diff --git a/.checkov.yml b/.checkov.yml new file mode 100644 index 00000000000..12f0d8b3841 --- /dev/null +++ b/.checkov.yml @@ -0,0 +1,6 @@ +--- +# You can see all available properties here: https://github.com/bridgecrewio/checkov#configuration-using-a-config-file +quiet: true +skip-check: + - CKV_DOCKER_2 + - CKV_GHA_7 diff --git a/.clang-format b/.clang-format index 14c0a235995..c5979d77ba1 100644 --- a/.clang-format +++ b/.clang-format @@ -24,6 +24,7 @@ ExperimentalAutoDetectBinPacking: false IndentCaseLabels: true IndentFunctionDeclarationAfterType: true IndentWidth: 2 +InsertNewlineAtEOF: true # It is broken on windows. Breaks all #include "header.h" --- Language: Cpp diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..30ad6d8f005 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +--- +# Dependabot configuration +# Reference: https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 00000000000..7d404c53f68 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,69 @@ +--- +alice3: + - changed-files: + - any-glob-to-any-file: ['ALICE3/**'] + +common: + - changed-files: + - any-glob-to-any-file: ['Common/**'] + +infrastructure: + - changed-files: + - any-glob-to-any-file: + - '.clang-format' + - '.clang-tidy' + - '.flake8' + - '.github/**' + - '.checkov.yml' + - '.mega-linter.yml' + - '.pre-commit-config.yaml' + - 'cmake/**' + - 'CODEOWNERS' + - 'CPPLINT.cfg' + - 'dependencies/**' + - 'packaging/**' + - 'pyproject.toml' + +datamodel: + - changed-files: + - any-glob-to-any-file: ['DataModel/**', '**/DataModel/**'] + +dpg: + - changed-files: + - any-glob-to-any-file: ['DPG/**'] + +pwgcf: + - changed-files: + - any-glob-to-any-file: ['PWGCF/**', '*/PWGCF/**'] + +pwgdq: + - changed-files: + - any-glob-to-any-file: ['PWGDQ/**', '*/PWGDQ/**'] + +pwgem: + - changed-files: + - any-glob-to-any-file: ['PWGEM/**', '*/PWGEM/**'] + +pwghf: + - changed-files: + - any-glob-to-any-file: ['PWGHF/**', '*/PWGHF/**'] + +pwgje: + - changed-files: + - any-glob-to-any-file: ['PWGJE/**', '*/PWGJE/**'] + +pwglf: + - changed-files: + - any-glob-to-any-file: ['PWGLF/**', '*/PWGLF/**', 'PWGMM/**', '*/PWGMM/**'] + +pwgud: + - changed-files: + - any-glob-to-any-file: ['PWGUD/**', '*/PWGUD/**'] + +trigger: + - changed-files: + - any-glob-to-any-file: ['EventFiltering/**'] + +tutorial: + - changed-files: + - any-glob-to-any-file: ['Tutorials/**'] diff --git a/.github/workflows/clean-test.yml b/.github/workflows/clean-test.yml new file mode 100644 index 00000000000..c6c9bc12067 --- /dev/null +++ b/.github/workflows/clean-test.yml @@ -0,0 +1,51 @@ +--- +name: Clean PR checks + +'on': + workflow_dispatch: + inputs: + pr: + description: PR number in this repo to be cleaned + type: string # can't use number here + required: true + message: + description: Human-readable message displayed on the new pending status + type: string + required: false + default: '' + + # Warning: GitHub limits the total number of inputs to 10, so a maximum of + # 8 checks is allowed here! + # Warning: the check_* keys are magic and must consist of the string + # "check_" followed by the applicable check name exactly. The + # "description" field is only the human-readable label for the input. + 'check_build/O2Physics/o2/macOS-arm': + description: build/O2Physics/o2/macOS-arm + type: boolean + default: true + + 'check_build/O2Physics/o2/macOS': + description: build/O2Physics/o2/macOS + type: boolean + default: true + + 'check_build/O2Physics/o2': + description: build/O2Physics/o2 + type: boolean + default: true + +permissions: {} + +jobs: + clean: + name: Clean PR checks + uses: alisw/ali-bot/.github/workflows/clean-pr-checks.yml@master + with: + owner: ${{ github.event.repository.owner.login }} + repo: ${{ github.event.repository.name }} + pr: ${{ github.event.inputs.pr }} + message: ${{ github.event.inputs.message }} + checks: ${{ toJSON(github.event.inputs) }} + permissions: + pull-requests: read # to get last commit for pr (octokit/graphql-action) + statuses: write # for set-github-status diff --git a/.github/workflows/codeowner-self-approval.yml b/.github/workflows/codeowner-self-approval.yml index bd4d3182682..149213effc5 100644 --- a/.github/workflows/codeowner-self-approval.yml +++ b/.github/workflows/codeowner-self-approval.yml @@ -13,7 +13,7 @@ permissions: jobs: approve: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 # Only run if the PR author enabled auto-merge, not someone else. # Also run if a new approval was created, as this affects whether we can # auto-approve. There is a risk of infinite loops here, though -- when we diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 00000000000..3f8fa9bc1b6 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,122 @@ +--- +name: "Pull Request Labeler" +'on': + pull_request_target: + types: [opened, synchronize, reopened, edited] +permissions: read-all + +jobs: + labeler: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + outputs: + labels: ${{ steps.labeler.outputs.all-labels }} + steps: + - name: Label the PR + id: labeler + uses: actions/labeler@v5 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + sync-labels: true + title-prefix-checker: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + needs: labeler + steps: + - name: Check the PR title prefix + id: check-prefix + env: + title: ${{ github.event.pull_request.title }} + labels: ${{ needs.labeler.outputs.labels }} + shell: python + run: | + import os + import re + import sys + title = os.environ['title'] + labels = os.environ['labels'] + tags = { + "infrastructure": "Infrastructure", + "common": "Common", + "alice3": "ALICE3", + "pwgcf": "PWGCF", + "pwgdq": "PWGDQ", + "pwgem": "PWGEM", + "pwghf": "PWGHF", + "pwgje": "PWGJE", + "pwglf": "PWGLF", + "pwgud": "PWGUD", + "dpg": "DPG", + "trigger": "Trigger", + "tutorial": "Tutorial", + } + print(f'PR title: "{title}"') + print(f'PR labels: "{labels}"') + tags_relevant = [tags[label] for label in tags if label in labels.split(",")] + print("Relevant title tags:", ",".join(tags_relevant)) + passed = True + prefix_good = ",".join(tags_relevant) + prefix_good = f"[{prefix_good}] " + print(f"Generated prefix: {prefix_good}") + replace_title = 0 + title_new = title + # If there is a prefix which contains a known tag, check it for correct tags, and reformat it if needed. + # If there is a prefix which does not contain any known tag, add the tag prefix. + # If there is no prefix, add the tag prefix. + if match := re.match(r"\[?(\w[\w, /\+-]+)[\]:]+ ", title): + prefix_title = match.group(1) + words_prefix_title = prefix_title.replace(",", " ").replace("/", " ").split() + title_stripped = title[len(match.group()) :] + print(f'PR title prefix: "{prefix_title}" -> tags: {words_prefix_title}') + print(f'Stripped PR title: "{title_stripped}"') + if any(tag in words_prefix_title for tag in tags.values()): + for tag in tags.values(): + if tag in tags_relevant and tag not in words_prefix_title: + print(f'::error::Relevant tag "{tag}" not found in the prefix of the PR title.') + passed = False + if tag not in tags_relevant and tag in words_prefix_title: + print(f'::error::Irrelevant tag "{tag}" found in the prefix of the PR title.') + passed = False + # Format a valid prefix. + if passed: + prefix_good = ",".join(w for w in prefix_title.replace(",", " ").split() if w) + prefix_good = f"[{prefix_good}] " + print(f"::notice::Reformatted prefix: {prefix_good}") + if match.group() != prefix_good: + replace_title = 1 + title_new = prefix_good + title_stripped + else: + print("::warning::No known tags found in the prefix.") + if tags_relevant: + replace_title = 1 + title_new = prefix_good + title + else: + print("::warning::No valid prefix found in the PR title.") + if tags_relevant: + replace_title = 1 + title_new = prefix_good + title + if not passed: + print("::error::Problems were found in the PR title prefix.") + print('::notice::Use the form "tags: title" or "[tags] title".') + sys.exit(1) + if replace_title: + print("::warning::The PR title prefix with tags needs to be added or adjusted.") + print(f'::warning::New title: "{title_new}".') + else: + print("::notice::The PR title prefix is fine.") + with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh: + print(f"replace={replace_title}", file=fh) + print(f"title={title_new}", file=fh) + - name: Fix the PR title prefix + if: ${{ steps.check-prefix.outputs.replace == 1 }} + uses: the-wright-jamie/Update-PR-Info-Action@v1.1.0 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" + base-branch-regex: master + error-on-fail: false + title-template: "${{ steps.check-prefix.outputs.title }}" + title-update-action: replace diff --git a/.github/workflows/mega-linter.yml b/.github/workflows/mega-linter.yml index e08d00c2cc2..68302e1f873 100644 --- a/.github/workflows/mega-linter.yml +++ b/.github/workflows/mega-linter.yml @@ -23,13 +23,12 @@ jobs: steps: # Git Checkout - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: # Checkout the HEAD of the PR instead of the merge commit. - # This may include unrelated files if the PR branch is not up to date with the upstream. - # ref: ${{ github.event.pull_request.head.sha }} - # Checkout the merge commit. - ref: refs/pull/${{ github.event.number }}/merge + ref: ${{ github.event.pull_request.head.sha }} + # Checkout the merge commit. (If a fixing PR is made, it will include also missing commits from upstream.) + # ref: refs/pull/${{ github.event.number }}/merge fetch-depth: 0 # So we can use secrets.ALIBUILD_GITHUB_TOKEN to push later. persist-credentials: false @@ -39,7 +38,7 @@ jobs: id: ml # You can override MegaLinter flavor used to have faster performances # More info at https://megalinter.io/flavors/ - uses: oxsecurity/megalinter@v7 + uses: oxsecurity/megalinter@v8.5.0 env: # All available variables are described in documentation: # https://megalinter.io/configuration/ @@ -48,6 +47,16 @@ jobs: VALIDATE_ALL_CODEBASE: false GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Upload MegaLinter artifacts + - name: Archive production artifacts + uses: actions/upload-artifact@v4 + if: success() || failure() + with: + name: MegaLinter reports + path: | + megalinter-reports + mega-linter.log + # Create or delete the cleanup branch - name: Update cleanup branch if: ${{ github.event.repository.owner.login == 'AliceO2Group' }} diff --git a/.github/workflows/o2-linter.yml b/.github/workflows/o2-linter.yml new file mode 100644 index 00000000000..099209da6e6 --- /dev/null +++ b/.github/workflows/o2-linter.yml @@ -0,0 +1,61 @@ +--- +# Find issues in O2 code +name: O2 linter + +"on": [pull_request_target, push] +permissions: {} +env: + BRANCH_MAIN: master + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +jobs: + o2-linter: + name: O2 linter + runs-on: ubuntu-24.04 + permissions: + pull-requests: write + steps: + - name: Set branches + run: | + if [[ "${{ github.event_name }}" == "push" ]]; then + branch_head="${{ github.ref }}" + branch_base="${{ env.BRANCH_MAIN }}" + else + branch_head="refs/pull/${{ github.event.pull_request.number }}/merge" + branch_base="${{ github.event.pull_request.base.ref }}" + fi + echo BRANCH_HEAD="$branch_head" >> "$GITHUB_ENV" + echo BRANCH_BASE="$branch_base" >> "$GITHUB_ENV" + - name: Checkout Code + uses: actions/checkout@v4 + with: + ref: ${{ env.BRANCH_HEAD }} + fetch-depth: 0 # needed to get the full history + - name: Run tests + id: linter + run: | + # Diff against the common ancestor of the source (head) branch and the target (base) branch. + echo "Diffing ${{ env.BRANCH_HEAD }} against ${{ env.BRANCH_BASE }}." + readarray -t files < <(git diff --diff-filter d --name-only origin/${{ env.BRANCH_BASE }}...) + if [ ${#files[@]} -eq 0 ]; then + echo "::notice::No files to lint." + echo "linter_ran=0" >> "$GITHUB_OUTPUT" + exit 0 + fi + echo "linter_ran=1" >> "$GITHUB_OUTPUT" + [[ "${{ github.event_name }}" == "pull_request_target" ]] && options="-g" + # shellcheck disable=SC2086 # Ignore unquoted options. + python3 Scripts/o2_linter.py $options "${files[@]}" + echo "Tip: If you allow actions in your fork repository, O2 linter will run when you push commits." + - name: Comment PR + if: (success() || failure()) && (github.event_name == 'pull_request_target' && steps.linter.outputs.linter_ran == 1) + uses: thollander/actions-comment-pull-request@v3 + with: + comment-tag: o2-linter + message: "**O2 linter results:** + ❌ ${{ steps.linter.outputs.n_issues }} errors, + ⚠️ ${{ steps.linter.outputs.n_tolerated }} warnings, + 🔕 ${{ steps.linter.outputs.n_disabled }} disabled" diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 8056a231e90..24b650f65b5 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -12,7 +12,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v1 + - uses: actions/stale@v9 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-pr-message: 'This PR has not been updated in the last 30 days. Is it still needed? Unless further action is taken, it will be closed in 5 days.' diff --git a/.mega-linter.yml b/.mega-linter.yml index 838c5454d14..e45919ac05a 100644 --- a/.mega-linter.yml +++ b/.mega-linter.yml @@ -15,7 +15,11 @@ DISABLE_LINTERS: - BASH_SHFMT - CPP_CLANG_FORMAT - JSON_PRETTIER + - PYTHON_BLACK + - PYTHON_FLAKE8 + - PYTHON_ISORT - REPOSITORY_DEVSKIM + - REPOSITORY_GITLEAKS - REPOSITORY_KICS - REPOSITORY_SECRETLINT - REPOSITORY_TRIVY @@ -35,3 +39,4 @@ PYTHON_PYRIGHT_CONFIG_FILE: pyproject.toml PYTHON_RUFF_CONFIG_FILE: pyproject.toml CPP_CPPLINT_FILE_EXTENSIONS: [".C", ".c", ".c++", ".cc", ".cl", ".cpp", ".cu", ".cuh", ".cxx", ".cxx.in", ".h", ".h++", ".hh", ".h.in", ".hpp", ".hxx", ".inc", ".inl", ".macro"] CPP_CLANG_FORMAT_FILE_EXTENSIONS: [".C", ".c", ".c++", ".cc", ".cl", ".cpp", ".cu", ".cuh", ".cxx", ".cxx.in", ".h", ".h++", ".hh", ".h.in", ".hpp", ".hxx", ".inc", ".inl", ".macro"] +REPOSITORY_GITLEAKS_PR_COMMITS_SCAN: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000000..dd9ef707b95 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,16 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - repo: https://github.com/pre-commit/mirrors-clang-format + rev: v18.1.3 # clang-format version + hooks: + - id: clang-format + - repo: https://github.com/cpplint/cpplint + rev: 2.0.0 + hooks: + - id: cpplint diff --git a/ALICE3/Core/CMakeLists.txt b/ALICE3/Core/CMakeLists.txt index 6db27c117d8..788711ac277 100644 --- a/ALICE3/Core/CMakeLists.txt +++ b/ALICE3/Core/CMakeLists.txt @@ -15,6 +15,14 @@ o2physics_add_library(ALICE3Core PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore) o2physics_target_root_dictionary(ALICE3Core - HEADERS TOFResoALICE3.h - DelphesO2TrackSmearer.h - LINKDEF ALICE3CoreLinkDef.h) + HEADERS TOFResoALICE3.h + DelphesO2TrackSmearer.h + LINKDEF ALICE3CoreLinkDef.h) + +o2physics_add_library(FastTracker + SOURCES FastTracker.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore) + +o2physics_target_root_dictionary(FastTracker + HEADERS FastTracker.h + LINKDEF FastTrackerLinkDef.h) diff --git a/ALICE3/Core/DetLayer.h b/ALICE3/Core/DetLayer.h new file mode 100644 index 00000000000..6b9fea14c06 --- /dev/null +++ b/ALICE3/Core/DetLayer.h @@ -0,0 +1,52 @@ +// 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 DetLayer.h +/// \author David Dobrigkeit Chinellato +/// \since 11/03/2021 +/// \brief Basic struct to hold information regarding a detector layer to be used in fast simulation +/// + +#ifndef ALICE3_CORE_DETLAYER_H_ +#define ALICE3_CORE_DETLAYER_H_ + +#include "TString.h" + +namespace o2::fastsim +{ + +struct DetLayer { + // TString for holding name + TString name; + + // position variables + float r; // radius in centimeters + float z; // z dimension in centimeters + + // material variables + float x0; // radiation length + float xrho; // density + + // resolution variables for active layers + float resRPhi; // RPhi resolution in centimeters + float resZ; // Z resolution in centimeters + + // efficiency + float eff; // detection efficiency + + // layer type + int type; // 0: undefined/inert, 1: silicon, 2: gas/tpc +}; + +} // namespace o2::fastsim + +#endif // ALICE3_CORE_DETLAYER_H_ diff --git a/ALICE3/Core/FastTracker.cxx b/ALICE3/Core/FastTracker.cxx new file mode 100644 index 00000000000..f41f5a8abf6 --- /dev/null +++ b/ALICE3/Core/FastTracker.cxx @@ -0,0 +1,596 @@ +// 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. + +#include +#include "TMath.h" +#include "TMatrixD.h" +#include "TRandom.h" +#include "TMatrixDSymEigen.h" +#include "FastTracker.h" + +namespace o2 +{ +namespace fastsim +{ + +// +-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+ + +FastTracker::FastTracker() +{ + // base constructor + magneticField = 20; // in kiloGauss + applyZacceptance = false; + applyMSCorrection = true; + applyMSCorrection = true; + applyElossCorrection = true; + applyEffCorrection = true; + covMatFactor = 0.99f; + verboseLevel = 0; + + // last fast-tracked track properties + covMatOK = 0; + covMatNotOK = 0; + nIntercepts = 0; + nSiliconPoints = 0; + nGasPoints = 0; + + maxRadiusSlowDet = 10; + integrationTime = 0.02; // ms + crossSectionMinB = 8; + dNdEtaCent = 2200; + dNdEtaMinB = 1; + avgRapidity = 0.45; + sigmaD = 6.0; + luminosity = 1.e27; + otherBackground = 0.0; // [0, 1] + upcBackgroundMultiplier = 1.0; +} + +void FastTracker::AddLayer(TString name, float r, float z, float x0, float xrho, float resRPhi, float resZ, float eff, int type) +{ + DetLayer newLayer{name.Data(), r, z, x0, xrho, resRPhi, resZ, eff, type}; + layers.push_back(newLayer); +} + +DetLayer FastTracker::GetLayer(int layer, bool ignoreBarrelLayers) +{ + int layerIdx = layer; + if (ignoreBarrelLayers) { + for (int il = 0, trackingLayerIdx = 0; trackingLayerIdx <= layer; il++) { + if (layers[il].type == 0) + continue; + trackingLayerIdx++; + layerIdx = il; + } + } + return layers[layerIdx]; +} + +void FastTracker::Print() +{ + // print out layer setup + LOG(info) << "+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+"; + LOG(info) << " Printing detector layout with " << layers.size() << " effective elements: "; + for (uint32_t il = 0; il < layers.size(); il++) { + LOG(info) << " Layer #" << il << "\t" << layers[il].name.Data() << "\tr = " << Form("%.2f", layers[il].r) << "cm\tz = " << layers[il].z << "\t" + << "x0 = " << layers[il].x0 << "\txrho = " << layers[il].xrho << "\tresRPhi = " << layers[il].resRPhi << "\tresZ = " << layers[il].resZ << "\teff = " << layers[il].eff; + } + LOG(info) << "+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+"; +} + +void FastTracker::AddSiliconALICE3v4(std::vector pixelResolution) +{ + LOG(info) << " ALICE 3: Adding v4 tracking layers"; + float x0IT = 0.001; // 0.1% + float x0OT = 0.005; // 0.5% + float xrhoIB = 1.1646e-02; // 50 mum Si + float xrhoOT = 1.1646e-01; // 500 mum Si + float eff = 1.00; + + float resRPhiIT = pixelResolution[0]; + float resZIT = pixelResolution[1]; + float resRPhiOT = pixelResolution[2]; + float resZOT = pixelResolution[3]; + + layers.push_back(DetLayer{"bpipe0", 0.48, 250, 0.00042, 2.772e-02, 0.0f, 0.0f, 0.0f, 0}); // 150 mum Be + layers.push_back(DetLayer{"ddd0", 0.5, 250, x0IT, xrhoIB, resRPhiIT, resZIT, eff, 1}); + layers.push_back(DetLayer{"ddd1", 1.2, 250, x0IT, xrhoIB, resRPhiIT, resZIT, eff, 1}); + layers.push_back(DetLayer{"ddd2", 2.5, 250, x0IT, xrhoIB, resRPhiIT, resZIT, eff, 1}); + layers.push_back(DetLayer{"bpipe1", 5.7, 250, 0.0014, 9.24e-02, 0.0f, 0.0f, 0.0f, 0}); // 500 mum Be + layers.push_back(DetLayer{"ddd3", 7., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1}); + layers.push_back(DetLayer{"ddd4", 10., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1}); + layers.push_back(DetLayer{"ddd5", 13., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1}); + layers.push_back(DetLayer{"ddd6", 16., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1}); + layers.push_back(DetLayer{"ddd7", 25., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1}); + layers.push_back(DetLayer{"ddd8", 40., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1}); + layers.push_back(DetLayer{"ddd9", 45., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1}); +} + +void FastTracker::AddSiliconALICE3v2(std::vector pixelResolution) +{ + LOG(info) << "ALICE 3: Adding v2 tracking layers;"; + float x0IT = 0.001; // 0.1% + float x0OT = 0.01; // 1.0% + float xrhoIB = 2.3292e-02; // 100 mum Si + float xrhoOT = 2.3292e-01; // 1000 mum Si + float eff = 1.00; + + float resRPhiIT = pixelResolution[0]; + float resZIT = pixelResolution[1]; + float resRPhiOT = pixelResolution[2]; + float resZOT = pixelResolution[3]; + + layers.push_back(DetLayer{"bpipe0", 0.48, 250, 0.00042, 2.772e-02, 0.0f, 0.0f, 0.0f, 0}); // 150 mum Be + layers.push_back(DetLayer{"B00", 0.5, 250, x0IT, xrhoIB, resRPhiIT, resZIT, eff, 1}); + layers.push_back(DetLayer{"B01", 1.2, 250, x0IT, xrhoIB, resRPhiIT, resZIT, eff, 1}); + layers.push_back(DetLayer{"B02", 2.5, 250, x0IT, xrhoIB, resRPhiIT, resZIT, eff, 1}); + layers.push_back(DetLayer{"bpipe1", 3.7, 250, 0.0014, 9.24e-02, 0.0f, 0.0f, 0.0f, 0}); // 500 mum Be + layers.push_back(DetLayer{"B03", 3.75, 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1}); + layers.push_back(DetLayer{"B04", 7., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1}); + layers.push_back(DetLayer{"B05", 12., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1}); + layers.push_back(DetLayer{"B06", 20., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1}); + layers.push_back(DetLayer{"B07", 30., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1}); + layers.push_back(DetLayer{"B08", 45., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1}); + layers.push_back(DetLayer{"B09", 60., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1}); + layers.push_back(DetLayer{"B10", 80., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1}); +} + +void FastTracker::AddTPC(float phiResMean, float zResMean) +{ + LOG(info) << " Adding standard time projection chamber"; + + // porting of DetectorK::AddTPC + // see here: + // https://github.com/AliceO2Group/DelphesO2/blob/master/src/DetectorK/DetectorK.cxx#L522 + // % Radiation Lengths ... Average per TPC row (i.e. total/159 ) + const int kNPassiveBound = 2; + const float radLBoundary[kNPassiveBound] = {1.692612e-01, 8.711904e-02}; + const float xrhoBoundary[kNPassiveBound] = {6.795774e+00, 3.111401e+00}; + const float rBoundary[kNPassiveBound] = {50, 70.0}; // cm + + float radLPerRow = 0.000036; + + float tpcInnerRadialPitch = 0.75; // cm + float tpcMiddleRadialPitch = 1.0; // cm + float tpcOuterRadialPitch = 1.5; // cm + float innerRows = 63; + float middleRows = 64; + float outerRows = 32; + float tpcRows = (innerRows + middleRows + outerRows); + float rowOneRadius = 85.2; // cm + float row64Radius = 135.1; // cm + float row128Radius = 199.2; // cm + + float zLength = 250.0f; // to be checked + + // add boundaries between ITS and TPC + for (int i = 0; i < kNPassiveBound; i++) { + AddLayer(Form("tpc_boundary%d", i), rBoundary[i], zLength, radLBoundary[i], xrhoBoundary[i], 0); // dummy errors + } + for (Int_t k = 0; k < tpcRows; k++) { + Float_t rowRadius = 0; + if (k < innerRows) + rowRadius = rowOneRadius + k * tpcInnerRadialPitch; + else if (k >= innerRows && k < (innerRows + middleRows)) + rowRadius = row64Radius + (k - innerRows + 1) * tpcMiddleRadialPitch; + else if (k >= (innerRows + middleRows) && k < tpcRows) + rowRadius = row128Radius + (k - innerRows - middleRows + 1) * tpcOuterRadialPitch; + + AddLayer(Form("tpc_%d", k), rowRadius, zLength, radLPerRow, 0, phiResMean, zResMean, 1.0f, 2); + } +} + +float FastTracker::Dist(float z, float r) +{ + // porting of DetektorK::Dist + // see here: + // https://github.com/AliceO2Group/DelphesO2/blob/master/src/DetectorK/DetectorK.cxx#L743 + int index = 1; + int nSteps = 301; + double dist = 0.0; + double dz0 = (4 * sigmaD - (-4) * sigmaD / (nSteps = 1)); + double z0 = 0.0; + for (int i = 0; i < nSteps; i++) { + if (i == nSteps - 1) + index = 1; + z0 = -4 * sigmaD + i * dz0; + dist += index * (dz0 / 3.) * (1 / o2::math_utils::sqrt(o2::constants::math::TwoPI) / sigmaD) * exp(-z0 * z0 / 2. / sigmaD / sigmaD) * (1 / o2::math_utils::sqrt((z - z0) * (z - z0) + r * r)); + if (index != 4) + index = 4; + else + index = 2; + } + return dist; +} + +float FastTracker::OneEventHitDensity(float multiplicity, float radius) +{ + // porting of DetektorK::OneEventHitDensity + // see here: + // https://github.com/AliceO2Group/DelphesO2/blob/master/src/DetectorK/DetectorK.cxx#L694 + float den = multiplicity / (o2::constants::math::TwoPI * radius * radius); + float tg = o2::math_utils::tan(2. * o2::math_utils::atan(-avgRapidity)); + den = den / o2::math_utils::sqrt(1 + 1 / (tg * tg)); + return den; +} + +float FastTracker::IntegratedHitDensity(float multiplicity, float radius) +{ + // porting of DetektorK::IntegratedHitDensity + // see here: + // https://github.com/AliceO2Group/DelphesO2/blob/master/src/DetectorK/DetectorK.cxx#L712 + float zdcHz = luminosity * 1.e24 * crossSectionMinB; + float den = zdcHz * integrationTime / 1000. * multiplicity * Dist(0., radius) / (o2::constants::math::TwoPI * radius); + if (den < OneEventHitDensity(multiplicity, radius)) + den = OneEventHitDensity(multiplicity, radius); + return den; +} + +float FastTracker::UpcHitDensity(float radius) +{ + // porting of DetektorK::UpcHitDensity + // see here: + // https://github.com/AliceO2Group/DelphesO2/blob/master/src/DetectorK/DetectorK.cxx#L727 + float mUPCelectrons = 0; + mUPCelectrons = lhcUPCScale * 5456 / (radius * radius) / dNdEtaMinB; + if (mUPCelectrons < 0) + mUPCelectrons = 0.0; + mUPCelectrons *= IntegratedHitDensity(dNdEtaMinB, radius); + mUPCelectrons *= upcBackgroundMultiplier; + return mUPCelectrons; +} + +float FastTracker::HitDensity(float radius) +{ + // porting of DetektorK::HitDensity + // see here: + // https://github.com/AliceO2Group/DelphesO2/blob/master/src/DetectorK/DetectorK.cxx#L663 + float arealDensity = 0.; + if (radius > maxRadiusSlowDet) { + arealDensity = OneEventHitDensity(dNdEtaCent, radius); + arealDensity += otherBackground * OneEventHitDensity(dNdEtaMinB, radius); + } + + // In the version of Delphes used to produce + // Look-up tables, UpcHitDensity(radius) always returns 0, + // hence it is left commented out for now + if (radius < maxRadiusSlowDet) { + arealDensity = OneEventHitDensity(dNdEtaCent, radius); + arealDensity += otherBackground * OneEventHitDensity(dNdEtaMinB, radius) + IntegratedHitDensity(dNdEtaMinB, radius); + // +UpcHitDensity(radius); + } + return arealDensity; +} + +float FastTracker::ProbGoodChiSqHit(float radius, float searchRadiusRPhi, float searchRadiusZ) +{ + // porting of DetektorK::ProbGoodChiSqHit + // see here: + // https://github.com/AliceO2Group/DelphesO2/blob/master/src/DetectorK/DetectorK.cxx#L629 + float sx, goodHit; + sx = o2::constants::math::TwoPI * searchRadiusRPhi * searchRadiusZ * HitDensity(radius); + goodHit = 1. / (1 + sx); + return goodHit; +} + +// function to provide a reconstructed track from a perfect input track +// returns number of intercepts (generic for now) +int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackParCov& outputTrack, float nch) +{ + hits.clear(); + nIntercepts = 0; + nSiliconPoints = 0; + nGasPoints = 0; + std::array posIni; // provision for != PV + inputTrack.getXYZGlo(posIni); + const float initialRadius = std::hypot(posIni[0], posIni[1]); + const float kTrackingMargin = 0.1; + const int kMaxNumberOfDetectors = 20; + const int xrhosteps = 100; + const bool applyAngularCorrection = true; + + for (int i = 0; i < kMaxNumberOfDetectors; ++i) + goodHitProbability.push_back(-1.); + goodHitProbability[0] = 1.; + + // +-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+ + // Outward pass to find intercepts + int firstLayerReached = -1; + int lastLayerReached = -1; + new (&outputTrack)(o2::track::TrackParCov)(inputTrack); + for (uint32_t il = 0; il < layers.size(); il++) { + // check if layer is doable + if (layers[il].r < initialRadius) + continue; // this layer should not be attempted, but go ahead + + // check if layer is reached + float targetX = 1e+3; + bool ok = true; + inputTrack.getXatLabR(layers[il].r, targetX, magneticField); + if (targetX > 999) + break; // failed to find intercept + + ok = inputTrack.propagateTo(targetX, magneticField); + if (ok && applyMSCorrection && layers[il].x0 > 0) { + ok = inputTrack.correctForMaterial(layers[il].x0, 0, applyAngularCorrection); + } + if (ok && applyElossCorrection && layers[il].xrho > 0) { // correct in small steps + for (int ise = xrhosteps; ise--;) { + ok = inputTrack.correctForMaterial(0, -layers[il].xrho / xrhosteps, applyAngularCorrection); + if (!ok) + break; + } + } + + // was there a problem on this layer? + if (!ok && il > 0) { // may fail to reach target layer due to the eloss + float rad2 = inputTrack.getX() * inputTrack.getX() + inputTrack.getY() * inputTrack.getY(); + float fMinRadTrack = 132.; + float maxR = layers[il - 1].r + kTrackingMargin * 2; + float minRad = (fMinRadTrack > 0 && fMinRadTrack < maxR) ? fMinRadTrack : maxR; + if (rad2 - minRad * minRad < kTrackingMargin * kTrackingMargin) { // check previously reached layer + return -5; // did not reach min requested layer + } else { + break; + } + } + if (std::abs(inputTrack.getZ()) > layers[il].z && applyZacceptance) { + break; // out of acceptance bounds + } + + if (layers[il].type == 0) + continue; // inert layer, skip + + // layer is reached + if (firstLayerReached < 0) + firstLayerReached = il; + lastLayerReached = il; + nIntercepts++; + } + + // +-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+ + // initialize track at outer point + o2::track::TrackParCov inwardTrack(inputTrack); + + // Enlarge covariance matrix + std::array trPars = {0.}; + for (int ip = 0; ip < 5; ip++) { + trPars[ip] = outputTrack.getParam(ip); + } + std::array largeCov = {0.}; + enum { kY, + kZ, + kSnp, + kTgl, + kPtI }; // track parameter aliases + enum { kY2, + kYZ, + kZ2, + kYSnp, + kZSnp, + kSnp2, + kYTgl, + kZTgl, + kSnpTgl, + kTgl2, + kYPtI, + kZPtI, + kSnpPtI, + kTglPtI, + kPtI2 }; // cov.matrix aliases + const double kLargeErr2Coord = 5 * 5; + const double kLargeErr2Dir = 0.7 * 0.7; + const double kLargeErr2PtI = 30.5 * 30.5; + for (int ic = 15; ic--;) + largeCov[ic] = 0.; + largeCov[kY2] = largeCov[kZ2] = kLargeErr2Coord; + largeCov[kSnp2] = largeCov[kTgl2] = kLargeErr2Dir; + largeCov[kPtI2] = kLargeErr2PtI * trPars[kPtI] * trPars[kPtI]; + + inwardTrack.setCov(largeCov); + inwardTrack.checkCovariance(); + + // +-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+ + // Inward pass to calculate covariances + for (int il = lastLayerReached; il >= firstLayerReached; il--) { + + float targetX = 1e+3; + inputTrack.getXatLabR(layers[il].r, targetX, magneticField); + if (targetX > 999) + continue; // failed to find intercept + + if (!inputTrack.propagateTo(targetX, magneticField)) { + continue; // failed to propagate + } + + if (std::abs(inputTrack.getZ()) > layers[il].z && applyZacceptance) { + continue; // out of acceptance bounds but continue inwards + } + + // get perfect data point position + std::array spacePoint; + inputTrack.getXYZGlo(spacePoint); + std::vector thisHit = {spacePoint[0], spacePoint[1], spacePoint[2]}; + + // towards adding cluster: move to track alpha + double alpha = inwardTrack.getAlpha(); + double xyz1[3]{ + TMath::Cos(alpha) * spacePoint[0] + TMath::Sin(alpha) * spacePoint[1], + -TMath::Sin(alpha) * spacePoint[0] + TMath::Cos(alpha) * spacePoint[1], + spacePoint[2]}; + if (!inwardTrack.propagateTo(xyz1[0], magneticField)) + continue; + + if (layers[il].type != 0) { // only update covm for tracker hits + const o2::track::TrackParametrization::dim2_t hitpoint = { + static_cast(xyz1[1]), + static_cast(xyz1[2])}; + const o2::track::TrackParametrization::dim3_t hitpointcov = {layers[il].resRPhi * layers[il].resRPhi, 0.f, layers[il].resZ * layers[il].resZ}; + + inwardTrack.update(hitpoint, hitpointcov); + inwardTrack.checkCovariance(); + } + + if (applyMSCorrection && layers[il].x0 > 0) { + if (!inputTrack.correctForMaterial(layers[il].x0, 0, applyAngularCorrection)) { + return -6; + } + if (!inwardTrack.correctForMaterial(layers[il].x0, 0, applyAngularCorrection)) { + return -6; + } + } + if (applyElossCorrection && layers[il].xrho > 0) { + for (int ise = xrhosteps; ise--;) { // correct in small steps + if (!inputTrack.correctForMaterial(0, layers[il].xrho / xrhosteps, applyAngularCorrection)) { + return -7; + } + if (!inwardTrack.correctForMaterial(0, layers[il].xrho / xrhosteps, applyAngularCorrection)) { + return -7; + } + } + } + + if (layers[il].type == 1) + nSiliconPoints++; // count silicon hits + if (layers[il].type == 2) + nGasPoints++; // count TPC/gas hits + + hits.push_back(thisHit); + + if (applyEffCorrection && layers[il].type != 0) { // good hit probability calculation + double sigYCmb = o2::math_utils::sqrt(inwardTrack.getSigmaY2() + layers[il].resRPhi * layers[il].resRPhi); + double sigZCmb = o2::math_utils::sqrt(inwardTrack.getSigmaZ2() + layers[il].resZ * layers[il].resZ); + goodHitProbability[il] = ProbGoodChiSqHit(layers[il].r * 100, sigYCmb * 100, sigZCmb * 100); + goodHitProbability[0] *= goodHitProbability[il]; + } + } + + // backpropagate to original radius + float finalX = 1e+3; + inwardTrack.getXatLabR(initialRadius, finalX, magneticField); + if (finalX > 999) + return -3; // failed to find intercept + + if (!inwardTrack.propagateTo(finalX, magneticField)) { + return -4; // failed to propagate + } + + // only attempt to continue if intercepts are at least four + if (nIntercepts < 4) + return nIntercepts; + + // generate efficiency + if (applyEffCorrection) { + dNdEtaCent = nch; + float eff = 1.; + for (int i = 0; i < kMaxNumberOfDetectors; i++) { + float iGoodHit = goodHitProbability[i]; + if (iGoodHit <= 0) + continue; + + eff *= iGoodHit; + } + + if (gRandom->Uniform() > eff) + return -8; + } + + outputTrack.setCov(inwardTrack.getCov()); + outputTrack.checkCovariance(); + + // Use covariance matrix based smearing + std::array covMat = {0.}; + for (int ii = 0; ii < 15; ii++) + covMat[ii] = outputTrack.getCov()[ii]; + TMatrixDSym m(5); + double fcovm[5][5]; + + for (int ii = 0, k = 0; ii < 5; ++ii) { + for (int j = 0; j < ii + 1; ++j, ++k) { + fcovm[ii][j] = covMat[k]; + fcovm[j][ii] = covMat[k]; + } + } + + // evaluate ruben's conditional, regularise + bool makePositiveDefinite = (covMatFactor > -1e-5); // apply fix + bool rubenConditional = false; + for (int ii = 0; ii < 5; ii++) { + for (int jj = 0; jj < 5; jj++) { + if (ii == jj) + continue; // don't evaluate diagonals + if (fcovm[ii][jj] * fcovm[ii][jj] > std::abs(fcovm[ii][ii] * fcovm[jj][jj])) { + rubenConditional = true; + if (makePositiveDefinite) { + fcovm[ii][jj] = TMath::Sign(1, fcovm[ii][jj]) * covMatFactor * sqrt(std::abs(fcovm[ii][ii] * fcovm[jj][jj])); + } + } + } + } + + // Should have a valid cov matrix now + m.SetMatrixArray(reinterpret_cast(fcovm)); + TMatrixDSymEigen eigen(m); + TMatrixD eigVec = eigen.GetEigenVectors(); + TVectorD eigVal = eigen.GetEigenValues(); + bool negEigVal = false; + for (int ii = 0; ii < 5; ii++) { + if (eigVal[ii] < 0.0f) + negEigVal = true; + } + + if (negEigVal && rubenConditional && makePositiveDefinite) { + if (verboseLevel > 0) { + LOG(info) << "WARNING: this diagonalization (at pt = " << inputTrack.getPt() << ") has negative eigenvalues despite Ruben's fix! Please be careful!"; + LOG(info) << "Printing info:"; + LOG(info) << "Kalman updates: " << nIntercepts; + LOG(info) << "Cov matrix: "; + m.Print(); + } + covMatNotOK++; + nIntercepts = -1; // mark as problematic so that it isn't used + return -1; + } + covMatOK++; + + // transform parameter vector and smear + double params_[5]; + for (int ii = 0; ii < 5; ++ii) { + double val = 0.; + for (int j = 0; j < 5; ++j) + val += eigVec[j][ii] * outputTrack.getParam(j); + // smear parameters according to eigenvalues + params_[ii] = gRandom->Gaus(val, sqrt(eigVal[ii])); + } + + // invert eigenvector matrix + eigVec.Invert(); + // transform back params vector + for (int ii = 0; ii < 5; ++ii) { + double val = 0.; + for (int j = 0; j < 5; ++j) + val += eigVec[j][ii] * params_[j]; + outputTrack.setParam(val, ii); + } + // should make a sanity check that par[2] sin(phi) is in [-1, 1] + if (fabs(outputTrack.getParam(2)) > 1.) { + LOG(info) << " --- smearTrack failed sin(phi) sanity check: " << outputTrack.getParam(2); + return -2; + } + + return nIntercepts; +} +// +-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+ + +} /* namespace fastsim */ +} /* namespace o2 */ + +ClassImp(o2::fastsim::FastTracker); diff --git a/ALICE3/Core/FastTracker.h b/ALICE3/Core/FastTracker.h new file mode 100644 index 00000000000..8508182fbf0 --- /dev/null +++ b/ALICE3/Core/FastTracker.h @@ -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. + +#ifndef ALICE3_CORE_FASTTRACKER_H_ +#define ALICE3_CORE_FASTTRACKER_H_ + +#include // not a system header but megalinter thinks so +#include +#include "DetLayer.h" +#include "ReconstructionDataFormats/Track.h" + +namespace o2 +{ +namespace fastsim +{ + +// +-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+ + +// this class implements a synthetic smearer that allows +// for on-demand smearing of TrackParCovs in a certain flexible t +// detector layout. +class FastTracker +{ + public: + // Constructor/destructor + FastTracker(); + virtual ~FastTracker() {} + + void AddLayer(TString name, float r, float z, float x0, float xrho, float resRPhi = 0.0f, float resZ = 0.0f, float eff = 0.0f, int type = 0); + DetLayer GetLayer(const int layer, bool ignoreBarrelLayers = true); + + void AddSiliconALICE3v4(std::vector pixelResolution); + void AddSiliconALICE3v2(std::vector pixelResolution); + void AddTPC(float phiResMean, float zResMean); + + void Print(); + int FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackParCov& outputTrack, float nch); + + // For efficiency calculation + float Dist(float z, float radius); + float OneEventHitDensity(float multiplicity, float radius); + float IntegratedHitDensity(float multiplicity, float radius); + float UpcHitDensity(float radius); + float HitDensity(float radius); + float ProbGoodChiSqHit(float radius, float searchRadiusRPhi, float searchRadiusZ); + + // Definition of detector layers + std::vector layers; + std::vector> hits; // bookkeep last added hits + + // operational + bool applyZacceptance; // check z acceptance or not + bool applyMSCorrection; // Apply correction for multiple scattering + bool applyElossCorrection; // Apply correction for eloss (requires MS correction) + bool applyEffCorrection; // Apply correction for hit efficiency + int verboseLevel; // 0: not verbose, >0 more verbose + int crossSectionMinB; + int dNdEtaCent; + int dNdEtaMinB; + float integrationTime; + float magneticField; // in kiloGauss (5 = 0.5T, etc) + float covMatFactor; // covmat off-diagonal factor to use for covmat fix (negative: no factor) + float sigmaD; + float luminosity; + float otherBackground; + float maxRadiusSlowDet; + float avgRapidity; + float lhcUPCScale; + float upcBackgroundMultiplier; + + uint64_t covMatOK; // cov mat has negative eigenvals + uint64_t covMatNotOK; // cov mat has negative eigenvals + + // last track information + int nIntercepts; // found in first outward propagation + int nSiliconPoints; // silicon-based space points added to track + int nGasPoints; // tpc-based space points added to track + std::vector goodHitProbability; + + ClassDef(FastTracker, 1); +}; + +// +-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+ + +} // namespace fastsim +} // namespace o2 + +#endif // ALICE3_CORE_FASTTRACKER_H_ diff --git a/ALICE3/Core/FastTrackerLinkDef.h b/ALICE3/Core/FastTrackerLinkDef.h new file mode 100644 index 00000000000..a69755b7e92 --- /dev/null +++ b/ALICE3/Core/FastTrackerLinkDef.h @@ -0,0 +1,21 @@ +// 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. + +#ifndef ALICE3_CORE_FASTTRACKERLINKDEF_H_ +#define ALICE3_CORE_FASTTRACKERLINKDEF_H_ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::fastsim::FastTracker + ; + +#endif // ALICE3_CORE_FASTTRACKERLINKDEF_H_ diff --git a/ALICE3/DataModel/A3DecayFinderTables.h b/ALICE3/DataModel/A3DecayFinderTables.h index cc7e8f3d3c7..05eb5ad9307 100644 --- a/ALICE3/DataModel/A3DecayFinderTables.h +++ b/ALICE3/DataModel/A3DecayFinderTables.h @@ -43,7 +43,10 @@ enum a3selectionBit : uint32_t { kDCAxy = 0, kTruePrPlusFromLc, kTruePiMinusFromLc, kTrueKaMinusFromLc, - kTruePrMinusFromLc }; + kTruePrMinusFromLc, + kTrueXiFromXiC, + kTruePiFromXiC, + kTruePiFromXiCC }; namespace o2::aod { @@ -51,7 +54,7 @@ namespace a3DecayMap { DECLARE_SOA_COLUMN(DecayMap, decayMap, uint32_t); //! simple map to process passing / not passing criteria } // namespace a3DecayMap -DECLARE_SOA_TABLE(Alice3DecayMaps, "AOD", "ALICE3DECAYMAP", +DECLARE_SOA_TABLE(Alice3DecayMaps, "AOD", "ALICE3DECAYMAPS", a3DecayMap::DecayMap); using Alice3DecayMap = Alice3DecayMaps::iterator; diff --git a/ALICE3/DataModel/OTFMcTrackExtra.h b/ALICE3/DataModel/OTFMcTrackExtra.h new file mode 100644 index 00000000000..bb75c86746c --- /dev/null +++ b/ALICE3/DataModel/OTFMcTrackExtra.h @@ -0,0 +1,42 @@ +// 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 OTFMcTrackExtra.h +/// \author Jesper Karlsson Gumprecht +/// \since 05/08/2024 +/// \brief Table to to hold MC information specifically for xi daughters created in the otf-tracker +/// + +#ifndef ALICE3_DATAMODEL_OTFMCTRACKEXTRA_H_ +#define ALICE3_DATAMODEL_OTFMCTRACKEXTRA_H_ + +// O2 includes +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace otf_mctrack_extra +{ +DECLARE_SOA_COLUMN(NewPdgCode, newPdgCode, int); //! PDG code (duplicate column but needed for particles created in the otf-tracker) +DECLARE_SOA_COLUMN(IsFromXi, isFromXi, bool); //! From Xi decayed in otf-tracker +DECLARE_SOA_COLUMN(IsFromL0, isFromL0, bool); //! From L0 decayed in otf-tracker +} // namespace otf_mctrack_extra +DECLARE_SOA_TABLE(OTFMcExtra, "AOD", "OTFMcExtra", + otf_mctrack_extra::NewPdgCode, + otf_mctrack_extra::IsFromXi, + otf_mctrack_extra::IsFromL0); + +using OTFMcTrackExtra = OTFMcExtra::iterator; + +} // namespace o2::aod + +#endif // ALICE3_DATAMODEL_OTFMCTRACKEXTRA_H_ diff --git a/ALICE3/DataModel/OTFMulticharm.h b/ALICE3/DataModel/OTFMulticharm.h new file mode 100644 index 00000000000..7dbde7bdc9a --- /dev/null +++ b/ALICE3/DataModel/OTFMulticharm.h @@ -0,0 +1,116 @@ +// 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 OTFStrangeness.h +/// \author David Dobrigkeit Chinellato +/// \since 05/08/2024 +/// \brief Set of tables for the ALICE3 strangeness information +/// + +#ifndef ALICE3_DATAMODEL_OTFMULTICHARM_H_ +#define ALICE3_DATAMODEL_OTFMULTICHARM_H_ + +// O2 includes +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace otfmulticharm +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Cascade, cascade, int, UpgradeCascades, "_Cascade"); +DECLARE_SOA_INDEX_COLUMN_FULL(XiCPion1, xiCPion1, int, Tracks, "_Pi1XiC"); +DECLARE_SOA_INDEX_COLUMN_FULL(XiCPion2, xiCPion2, int, Tracks, "_Pi2XiC"); +DECLARE_SOA_INDEX_COLUMN_FULL(XiCCPion, xiCCPion, int, Tracks, "_PiXiCC"); + +// topo vars +DECLARE_SOA_COLUMN(DCAXiCDaughters, dcaXiCDaughters, float); +DECLARE_SOA_COLUMN(DCAXiCCDaughters, dcaXiCCDaughters, float); + +DECLARE_SOA_COLUMN(MXiC, mXiC, float); +DECLARE_SOA_COLUMN(MXiCC, mXiCC, float); + +// kine vars +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); + +// tracking counters +DECLARE_SOA_COLUMN(NSiliconHitsXi, nSiliconHitsXi, int); +DECLARE_SOA_COLUMN(NSiliconHitsPiFromXi, nSiliconHitsPiFromXi, int); +DECLARE_SOA_COLUMN(NSiliconHitsPiFromLa, nSiliconHitsPiFromLa, int); +DECLARE_SOA_COLUMN(NSiliconHitsPrFromLa, nSiliconHitsPrFromLa, int); +DECLARE_SOA_COLUMN(NSiliconHitsPiC1, nSiliconHitsPiC1, int); +DECLARE_SOA_COLUMN(NSiliconHitsPiC2, nSiliconHitsPiC2, int); +DECLARE_SOA_COLUMN(NSiliconHitsPiCC, nSiliconHitsPiCC, int); + +DECLARE_SOA_COLUMN(NTPCHitsPiFromXi, nTPCHitsPiFromXi, int); +DECLARE_SOA_COLUMN(NTPCHitsPiFromLa, nTPCHitsPiFromLa, int); +DECLARE_SOA_COLUMN(NTPCHitsPrFromLa, nTPCHitsPrFromLa, int); +DECLARE_SOA_COLUMN(NTPCHitsPiC1, nTPCHitsPiC1, int); +DECLARE_SOA_COLUMN(NTPCHitsPiC2, nTPCHitsPiC2, int); +DECLARE_SOA_COLUMN(NTPCHitsPiCC, nTPCHitsPiCC, int); + +// DCA to PV variables +DECLARE_SOA_COLUMN(DCAToPVXi, dcaToPVXi, float); +DECLARE_SOA_COLUMN(DCAToPVXiC, dcaToPVXiC, float); +DECLARE_SOA_COLUMN(DCAToPVXiCC, dcaToPVXiCC, float); + +DECLARE_SOA_COLUMN(DCAToPVPiFromXi, dcaToPVPiFromXi, float); +DECLARE_SOA_COLUMN(DCAToPVPiFromLa, dcaToPVPiFromLa, float); +DECLARE_SOA_COLUMN(DCAToPVPrFromLa, dcaToPVPrFromLa, float); + +DECLARE_SOA_COLUMN(DCAToPVPiC1, dcaToPVPiC1, float); +DECLARE_SOA_COLUMN(DCAToPVPiC2, dcaToPVPiC2, float); +DECLARE_SOA_COLUMN(DCAToPVPiCC, dcaToPVPiCC, float); + +} // namespace otfmulticharm +DECLARE_SOA_TABLE(MCharmIndices, "AOD", "MCharmIndices", + o2::soa::Index<>, + otfmulticharm::CascadeId, + otfmulticharm::XiCPion1Id, + otfmulticharm::XiCPion2Id, + otfmulticharm::XiCCPionId); + +DECLARE_SOA_TABLE(MCharmCores, "AOD", "MCharmCores", + otfmulticharm::DCAXiCDaughters, + otfmulticharm::DCAXiCCDaughters, + otfmulticharm::MXiC, + otfmulticharm::MXiCC, + otfmulticharm::Pt, + otfmulticharm::Eta, + + otfmulticharm::NSiliconHitsXi, + otfmulticharm::NSiliconHitsPiFromXi, + otfmulticharm::NSiliconHitsPiFromLa, + otfmulticharm::NSiliconHitsPrFromLa, + otfmulticharm::NSiliconHitsPiC1, + otfmulticharm::NSiliconHitsPiC2, + otfmulticharm::NSiliconHitsPiCC, + otfmulticharm::NTPCHitsPiFromXi, + otfmulticharm::NTPCHitsPiFromLa, + otfmulticharm::NTPCHitsPrFromLa, + otfmulticharm::NTPCHitsPiC1, + otfmulticharm::NTPCHitsPiC2, + otfmulticharm::NTPCHitsPiCC, + + otfmulticharm::DCAToPVXi, + otfmulticharm::DCAToPVXiC, + otfmulticharm::DCAToPVXiCC, + otfmulticharm::DCAToPVPiFromXi, + otfmulticharm::DCAToPVPiFromLa, + otfmulticharm::DCAToPVPrFromLa, + otfmulticharm::DCAToPVPiC1, + otfmulticharm::DCAToPVPiC2, + otfmulticharm::DCAToPVPiCC); + +} // namespace o2::aod + +#endif // ALICE3_DATAMODEL_OTFMULTICHARM_H_ diff --git a/ALICE3/DataModel/OTFStrangeness.h b/ALICE3/DataModel/OTFStrangeness.h new file mode 100644 index 00000000000..861ec3a7af8 --- /dev/null +++ b/ALICE3/DataModel/OTFStrangeness.h @@ -0,0 +1,70 @@ +// 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 OTFStrangeness.h +/// \author David Dobrigkeit Chinellato +/// \since 05/08/2024 +/// \brief Set of tables for the ALICE3 strangeness information +/// + +#ifndef ALICE3_DATAMODEL_OTFSTRANGENESS_H_ +#define ALICE3_DATAMODEL_OTFSTRANGENESS_H_ + +// O2 includes +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace otfcascade +{ +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! +DECLARE_SOA_INDEX_COLUMN_FULL(CascadeTrack, cascadeTrack, int, Tracks, "_Cascade"); //! +DECLARE_SOA_INDEX_COLUMN_FULL(PosTrack, posTrack, int, Tracks, "_Pos"); //! +DECLARE_SOA_INDEX_COLUMN_FULL(NegTrack, negTrack, int, Tracks, "_Neg"); //! +DECLARE_SOA_INDEX_COLUMN_FULL(BachTrack, bachTrack, int, Tracks, "_Bach"); //! + +// topo vars +DECLARE_SOA_COLUMN(DCAV0Daughters, dcaV0Daughters, float); +DECLARE_SOA_COLUMN(DCACascadeDaughters, dcaCascadeDaughters, float); +DECLARE_SOA_COLUMN(V0Radius, v0Radius, float); +DECLARE_SOA_COLUMN(CascRadius, cascRadius, float); +DECLARE_SOA_COLUMN(CascRadiusMC, cascRadiusMC, float); +DECLARE_SOA_COLUMN(MLambda, mLambda, float); +DECLARE_SOA_COLUMN(MXi, mXi, float); + +// strangeness tracking +DECLARE_SOA_COLUMN(FindableClusters, findableClusters, int); +DECLARE_SOA_COLUMN(FoundClusters, foundClusters, int); + +} // namespace otfcascade +DECLARE_SOA_TABLE(UpgradeCascades, "AOD", "UPGRADECASCADES", + o2::soa::Index<>, + otfcascade::CollisionId, + otfcascade::CascadeTrackId, + otfcascade::PosTrackId, + otfcascade::NegTrackId, + otfcascade::BachTrackId, + otfcascade::DCAV0Daughters, + otfcascade::DCACascadeDaughters, + otfcascade::V0Radius, + otfcascade::CascRadius, + otfcascade::CascRadiusMC, + otfcascade::MLambda, + otfcascade::MXi, + otfcascade::FindableClusters, + otfcascade::FoundClusters); + +using UpgradeCascade = UpgradeCascades::iterator; + +} // namespace o2::aod + +#endif // ALICE3_DATAMODEL_OTFSTRANGENESS_H_ diff --git a/ALICE3/DataModel/tracksAlice3.h b/ALICE3/DataModel/tracksAlice3.h index c3a3e82a994..280c5ccb110 100644 --- a/ALICE3/DataModel/tracksAlice3.h +++ b/ALICE3/DataModel/tracksAlice3.h @@ -27,12 +27,18 @@ namespace o2::aod namespace track_alice3 { DECLARE_SOA_COLUMN(IsReconstructed, isReconstructed, bool); //! is reconstructed or not +DECLARE_SOA_COLUMN(NSiliconHits, nSiliconHits, int); //! number of silicon hits +DECLARE_SOA_COLUMN(NTPCHits, nTPCHits, int); //! number of tpc hits } // namespace track_alice3 DECLARE_SOA_TABLE(TracksAlice3, "AOD", "TRACKSALICE3", track_alice3::IsReconstructed); - using TrackAlice3 = TracksAlice3::iterator; +DECLARE_SOA_TABLE(TracksExtraA3, "AOD", "TracksExtraA3", + track_alice3::NSiliconHits, + track_alice3::NTPCHits); +using TrackExtraA3 = TracksExtraA3::iterator; + } // namespace o2::aod #endif // ALICE3_DATAMODEL_TRACKSALICE3_H_ diff --git a/ALICE3/TableProducer/CMakeLists.txt b/ALICE3/TableProducer/CMakeLists.txt index 52300bfc644..9c3d710d358 100644 --- a/ALICE3/TableProducer/CMakeLists.txt +++ b/ALICE3/TableProducer/CMakeLists.txt @@ -31,8 +31,17 @@ o2physics_add_dpl_workflow(alice3-centrality PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(alice3-decaypreselector + SOURCES alice3-decaypreselector.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(alice3-decayfinder SOURCES alice3-decayfinder.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(alice3-multicharm + SOURCES alice3-multicharm.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter + COMPONENT_NAME Analysis) diff --git a/ALICE3/TableProducer/OTF/CMakeLists.txt b/ALICE3/TableProducer/OTF/CMakeLists.txt index 305fcce4b66..d20b6c6ba5c 100644 --- a/ALICE3/TableProducer/OTF/CMakeLists.txt +++ b/ALICE3/TableProducer/OTF/CMakeLists.txt @@ -11,7 +11,7 @@ o2physics_add_dpl_workflow(onthefly-tracker SOURCES onTheFlyTracker.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsCommonDataFormats O2::DetectorsVertexing O2Physics::ALICE3Core + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsCommonDataFormats O2::DetectorsVertexing O2::DCAFitter O2Physics::ALICE3Core O2Physics::FastTracker COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(onthefly-tofpid diff --git a/ALICE3/TableProducer/OTF/onTheFlyTOFPID.cxx b/ALICE3/TableProducer/OTF/onTheFlyTOFPID.cxx index 39ace42c926..3a907d47342 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTOFPID.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTOFPID.cxx @@ -81,6 +81,8 @@ struct OnTheFlyTOFPID { Configurable nBinsTrackDeltaLength{"nBinsTrackDeltaLength", 100, "number of bins in delta track length"}; Configurable nBinsNsigmaCorrectSpecies{"nBinsNsigmaCorrectSpecies", 200, "number of bins in Nsigma plot (correct speies)"}; Configurable nBinsNsigmaWrongSpecies{"nBinsNsigmaWrongSpecies", 200, "number of bins in Nsigma plot (wrong species)"}; + Configurable minNsigmaRange{"minNsigmaRange", -10, "lower limit for the nsigma axis"}; + Configurable maxNsigmaRange{"maxNsigmaRange", +10, "upper limit for the nsigma axis"}; Configurable nBinsTimeRes{"nBinsTimeRes", 400, "number of bins plots time resolution"}; Configurable nBinsRelativeEtaPt{"nBinsRelativeEtaPt", 400, "number of bins plots pt and eta relative errors"}; Configurable nBinsEta{"nBinsEta", 400, "number of bins plot relative eta error"}; @@ -138,7 +140,7 @@ struct OnTheFlyTOFPID { } if (doQAplots) { - const AxisSpec axisMomentum{static_cast(nBinsP), 0.0f, +4.0f, "#it{p} (GeV/#it{c})"}; + const AxisSpec axisMomentum{static_cast(nBinsP), 0.0f, +10.0f, "#it{p} (GeV/#it{c})"}; const AxisSpec axisMomentumSmall{static_cast(nBinsP), 0.0f, +1.0f, "#it{p} (GeV/#it{c})"}; const AxisSpec axisVelocity{static_cast(nBinsBeta), 0.0f, +1.1f, "Measured #beta"}; const AxisSpec axisTrackLengthInner{static_cast(nBinsTrackLengthInner), 0.0f, 60.0f, "Track length (cm)"}; @@ -182,11 +184,11 @@ struct OnTheFlyTOFPID { std::string name_title_inner = "h2dInnerNsigmaTrue" + particle_names2[i_true] + "Vs" + particle_names2[i_hyp] + "Hypothesis"; std::string name_title_outer = "h2dOuterNsigmaTrue" + particle_names2[i_true] + "Vs" + particle_names2[i_hyp] + "Hypothesis"; if (i_true == i_hyp) { - const AxisSpec axisNsigmaCorrect{static_cast(nBinsNsigmaCorrectSpecies), -10.0f, +10.0f, "N#sigma - True " + particle_names1[i_true] + " vs " + particle_names1[i_hyp] + " hypothesis"}; + const AxisSpec axisNsigmaCorrect{static_cast(nBinsNsigmaCorrectSpecies), minNsigmaRange, maxNsigmaRange, "N#sigma - True " + particle_names1[i_true] + " vs " + particle_names1[i_hyp] + " hypothesis"}; histos.add(name_title_inner.c_str(), name_title_inner.c_str(), kTH2F, {axisMomentum, axisNsigmaCorrect}); histos.add(name_title_outer.c_str(), name_title_outer.c_str(), kTH2F, {axisMomentum, axisNsigmaCorrect}); } else { - const AxisSpec axisNsigmaWrong{static_cast(nBinsNsigmaWrongSpecies), -10.0f, +10.0f, "N#sigma - True " + particle_names1[i_true] + " vs " + particle_names1[i_hyp] + " hypothesis"}; + const AxisSpec axisNsigmaWrong{static_cast(nBinsNsigmaWrongSpecies), minNsigmaRange, maxNsigmaRange, "N#sigma - True " + particle_names1[i_true] + " vs " + particle_names1[i_hyp] + " hypothesis"}; histos.add(name_title_inner.c_str(), name_title_inner.c_str(), kTH2F, {axisMomentum, axisNsigmaWrong}); histos.add(name_title_outer.c_str(), name_title_outer.c_str(), kTH2F, {axisMomentum, axisNsigmaWrong}); } diff --git a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx index 163fc73058e..9fa7920d2ac 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx @@ -24,14 +24,23 @@ /// #include +#include +#include +#include +#include #include +#include +#include +#include #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" #include +#include "DCAFitter/DCAFitterN.h" +#include "Common/Core/RecoDecay.h" #include "Framework/O2DatabasePDGPlugin.h" #include "Common/DataModel/TrackSelectionTables.h" #include "ReconstructionDataFormats/DCA.h" @@ -42,12 +51,23 @@ #include "SimulationDataFormat/InteractionSampler.h" #include "Field/MagneticField.h" +#include "ITSMFTSimulation/Hit.h" +#include "ITStracking/Configuration.h" +#include "ITStracking/IOUtils.h" +#include "ITStracking/Tracker.h" +#include "ITStracking/Vertexer.h" +#include "ITStracking/VertexerTraits.h" + #include "ALICE3/Core/DelphesO2TrackSmearer.h" +#include "ALICE3/Core/FastTracker.h" +#include "ALICE3/Core/DetLayer.h" #include "ALICE3/DataModel/collisionAlice3.h" #include "ALICE3/DataModel/tracksAlice3.h" +#include "ALICE3/DataModel/OTFStrangeness.h" using namespace o2; using namespace o2::framework; +using std::array; struct OnTheFlyTracker { Produces collisions; @@ -58,25 +78,32 @@ struct OnTheFlyTracker { Produces tracksParCovExtension; Produces tracksLabels; Produces tracksDCA; + Produces tracksDCACov; Produces collisionsAlice3; Produces TracksAlice3; + Produces TracksExtraA3; + Produces upgradeCascades; // optionally produced, empty (to be tuned later) - Produces tracksExtra; // base table, extend later + Produces tracksExtra; // base table, extend later Produces trackSelection; Produces trackSelectionExtension; + Configurable seed{"seed", 0, "TGenPhaseSpace seed"}; Configurable magneticField{"magneticField", 20.0f, "magnetic field in kG"}; Configurable maxEta{"maxEta", 1.5, "maximum eta to consider viable"}; Configurable multEtaRange{"multEtaRange", 0.8, "eta range to compute the multiplicity"}; Configurable minPt{"minPt", 0.1, "minimum pt to consider viable"}; Configurable enableLUT{"enableLUT", false, "Enable track smearing"}; + Configurable enablePrimarySmearing{"enablePrimarySmearing", false, "Enable smearing of primary particles"}; + Configurable enableSecondarySmearing{"enableSecondarySmearing", false, "Enable smearing of weak decay daughters"}; Configurable enableNucleiSmearing{"enableNucleiSmearing", false, "Enable smearing of nuclei"}; Configurable enablePrimaryVertexing{"enablePrimaryVertexing", true, "Enable primary vertexing"}; Configurable interpolateLutEfficiencyVsNch{"interpolateLutEfficiencyVsNch", true, "interpolate LUT efficiency as f(Nch)"}; Configurable populateTracksDCA{"populateTracksDCA", true, "populate TracksDCA table"}; - Configurable populateTracksExtra{"populateTracksExtra", false, "populate TracksExtra table (legacy)"}; + Configurable populateTracksDCACov{"populateTracksDCACov", false, "populate TracksDCACov table"}; + Configurable populateTracksExtra{"populateTracksExtra", false, "populate TrackExtra table (legacy)"}; Configurable populateTrackSelection{"populateTrackSelection", false, "populate TrackSelection table (legacy)"}; Configurable processUnreconstructedTracks{"processUnreconstructedTracks", false, "process (smear) unreco-ed tracks"}; @@ -92,15 +119,54 @@ struct OnTheFlyTracker { Configurable lutTr{"lutTr", "lutCovm.tr.dat", "LUT for tritons"}; Configurable lutHe3{"lutHe3", "lutCovm.he3.dat", "LUT for Helium-3"}; - ConfigurableAxis axisMomentum{"axisMomentum", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "#it{p} (GeV/#it{c})"}; - ConfigurableAxis axisNVertices{"axisNVertices", {20, -0.5, 19.5}, "N_{vertices}"}; - ConfigurableAxis axisMultiplicity{"axisMultiplicity", {100, -0.5, 99.5}, "N_{contributors}"}; - ConfigurableAxis axisVertexZ{"axisVertexZ", {40, -20, 20}, "vertex Z (cm)"}; - ConfigurableAxis axisDCA{"axisDCA", {400, -200, 200}, "DCA (#mum)"}; - ConfigurableAxis axisX{"axisX", {250, -50, 200}, "track X (cm)"}; + struct : ConfigurableGroup { + ConfigurableAxis axisMomentum{"axisMomentum", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "#it{p} (GeV/#it{c})"}; + ConfigurableAxis axisNVertices{"axisNVertices", {20, -0.5, 19.5}, "N_{vertices}"}; + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {100, -0.5, 99.5}, "N_{contributors}"}; + ConfigurableAxis axisVertexZ{"axisVertexZ", {40, -20, 20}, "vertex Z (cm)"}; + ConfigurableAxis axisDCA{"axisDCA", {400, -200, 200}, "DCA (#mum)"}; + ConfigurableAxis axisX{"axisX", {250, -50, 200}, "track X (cm)"}; + ConfigurableAxis axisDecayRadius{"axisDecayRadius", {55, 0.01, 100}, "decay radius"}; + ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.101f, 1.131f}, ""}; + ConfigurableAxis axisXiMass{"axisXiMass", {200, 1.22f, 1.42f}, ""}; + + ConfigurableAxis axisDeltaPt{"axisDeltaPt", {200, -1.0f, +1.0f}, "#Delta p_{T}"}; + ConfigurableAxis axisDeltaEta{"axisDeltaEta", {200, -0.5f, +0.5f}, "#Delta #eta"}; + + ConfigurableAxis axisRadius{"axisRadius", {2500, 0.0f, +250.0f}, "R (cm)"}; + ConfigurableAxis axisZ{"axisZ", {100, -250.0f, +250.0f}, "Z (cm)"}; + } axes; + + // for topo var QA + struct : ConfigurableGroup { + std::string prefix = "fastTrackerSettings"; // JSON group name + Configurable minSiliconHits{"minSiliconHits", 6, "minimum number of silicon hits to accept track"}; + Configurable minSiliconHitsIfTPCUsed{"minSiliconHitsIfTPCUsed", 2, "minimum number of silicon hits to accept track in case TPC info is present"}; + Configurable minTPCClusters{"minTPCClusters", 70, "minimum number of TPC hits necessary to consider minSiliconHitsIfTPCUsed"}; + Configurable alice3detector{"alice3detector", 0, "0: ALICE 3 v1, 1: ALICE 3 v4"}; + Configurable applyZacceptance{"applyZacceptance", false, "apply z limits to detector layers or not"}; + Configurable applyMSCorrection{"applyMSCorrection", true, "apply ms corrections for secondaries or not"}; + Configurable applyElossCorrection{"applyElossCorrection", true, "apply eloss corrections for secondaries or not"}; + Configurable applyEffCorrection{"applyEffCorrection", true, "apply efficiency correction or not"}; + Configurable> pixelRes{"pixelRes", {0.00025, 0.00025, 0.001, 0.001}, "RPhiIT, ZIT, RPhiOT, ZOT"}; + } fastTrackerSettings; // allows for gap between peak and bg in case someone wants to + + struct : ConfigurableGroup { + std::string prefix = "cascadeDecaySettings"; // Cascade decay settings + Configurable decayXi{"decayXi", false, "Manually decay Xi and fill tables with daughters"}; + Configurable findXi{"findXi", false, "if decayXi on, find Xi and fill Tracks table also with Xi"}; + Configurable trackXi{"trackXi", false, "if findXi on, attempt to track Xi"}; + Configurable doXiQA{"doXiQA", false, "QA plots for when treating Xi"}; + } cascadeDecaySettings; using PVertex = o2::dataformats::PrimaryVertex; + // for secondary vertex finding + o2::vertexing::DCAFitterN<2> fitter; + + // FastTracker machinery + o2::fastsim::FastTracker fastTracker; + // Class to hold the track information for the O2 vertexing class TrackAlice3 : public o2::track::TrackParCov { @@ -110,12 +176,52 @@ struct OnTheFlyTracker { TrackAlice3() = default; ~TrackAlice3() = default; TrackAlice3(const TrackAlice3& src) = default; - TrackAlice3(const o2::track::TrackParCov& src, const int64_t label, const float t = 0, const float te = 1, bool decayDauInput = false) : o2::track::TrackParCov(src), mcLabel{label}, timeEst{t, te}, isDecayDau(decayDauInput) {} + TrackAlice3(const o2::track::TrackParCov& src, const int64_t label, + const float t = 0, + const float te = 1, + bool decayDauInput = false, + bool weakDecayDauInput = false, + int isUsedInCascadingInput = 0, + int nSiliconHitsInput = 0, + int nTPCHitsInput = 0) : o2::track::TrackParCov(src), + mcLabel{label}, + timeEst{t, te}, + isDecayDau(decayDauInput), + isWeakDecayDau(weakDecayDauInput), + isUsedInCascading(isUsedInCascadingInput), + nSiliconHits(nSiliconHitsInput), + nTPCHits(nTPCHitsInput) {} const TimeEst& getTimeMUS() const { return timeEst; } int64_t mcLabel; TimeEst timeEst; ///< time estimate in ns bool isDecayDau; + bool isWeakDecayDau; + int isUsedInCascading; // 0: not at all, 1: is a cascade, 2: is a bachelor, 3: is a pion, 4: is a proton + int nSiliconHits; + int nTPCHits; + }; + + // Helper struct to pass cascade information + struct cascadecandidate { + int cascadeTrackId; // track index in the Tracks table + int positiveId; // track index in the Tracks table + int negativeId; // track index in the Tracks table + int bachelorId; // track index in the Tracks table + + float dcaV0dau; + float dcacascdau; + float v0radius; + float cascradius; + float cascradiusMC; + + // for tracking + int findableClusters; + int foundClusters; + + float mLambda; + float mXi; }; + cascadecandidate thisCascade; // necessary for particle charges Service pdgDB; @@ -134,6 +240,10 @@ struct OnTheFlyTracker { std::vector bcData; o2::steer::InteractionSampler irSampler; o2::vertexing::PVertexer vertexer; + std::vector cascadesAlice3; + + // For TGenPhaseSpace seed + TRandom3 rand; void init(o2::framework::InitContext&) { @@ -178,31 +288,91 @@ struct OnTheFlyTracker { } // Basic QA - histos.add("hPtGenerated", "hPtGenerated", kTH1F, {axisMomentum}); - histos.add("hPtGeneratedEl", "hPtGeneratedEl", kTH1F, {axisMomentum}); - histos.add("hPtGeneratedPi", "hPtGeneratedPi", kTH1F, {axisMomentum}); - histos.add("hPtGeneratedKa", "hPtGeneratedKa", kTH1F, {axisMomentum}); - histos.add("hPtGeneratedPr", "hPtGeneratedPr", kTH1F, {axisMomentum}); - histos.add("hPtReconstructed", "hPtReconstructed", kTH1F, {axisMomentum}); - histos.add("hPtReconstructedEl", "hPtReconstructedEl", kTH1F, {axisMomentum}); - histos.add("hPtReconstructedPi", "hPtReconstructedPi", kTH1F, {axisMomentum}); - histos.add("hPtReconstructedKa", "hPtReconstructedKa", kTH1F, {axisMomentum}); - histos.add("hPtReconstructedPr", "hPtReconstructedPr", kTH1F, {axisMomentum}); + auto hNaN = histos.add("hNaNBookkeeping", "hNaNBookkeeping", kTH2F, {{10, -0.5f, 9.5f}, {10, -0.5f, 9.5f}}); + + hNaN->GetXaxis()->SetBinLabel(1, "Primary"); + hNaN->GetXaxis()->SetBinLabel(2, "Bachelor"); + hNaN->GetXaxis()->SetBinLabel(3, "Pi from La"); + hNaN->GetXaxis()->SetBinLabel(4, "Pr from La"); + + hNaN->GetYaxis()->SetBinLabel(1, "Smear NaN"); + hNaN->GetYaxis()->SetBinLabel(2, "Smear OK"); + + auto hCovMatOK = histos.add("hCovMatOK", "hCovMatOK", kTH1D, {{2, -0.5f, 1.5f}}); + hCovMatOK->GetXaxis()->SetBinLabel(1, "Not OK"); + hCovMatOK->GetXaxis()->SetBinLabel(2, "OK"); + + histos.add("hPtGenerated", "hPtGenerated", kTH1F, {axes.axisMomentum}); + histos.add("hPtGeneratedEl", "hPtGeneratedEl", kTH1F, {axes.axisMomentum}); + histos.add("hPtGeneratedPi", "hPtGeneratedPi", kTH1F, {axes.axisMomentum}); + histos.add("hPtGeneratedKa", "hPtGeneratedKa", kTH1F, {axes.axisMomentum}); + histos.add("hPtGeneratedPr", "hPtGeneratedPr", kTH1F, {axes.axisMomentum}); + histos.add("hPtReconstructed", "hPtReconstructed", kTH1F, {axes.axisMomentum}); + histos.add("hPtReconstructedEl", "hPtReconstructedEl", kTH1F, {axes.axisMomentum}); + histos.add("hPtReconstructedPi", "hPtReconstructedPi", kTH1F, {axes.axisMomentum}); + histos.add("hPtReconstructedKa", "hPtReconstructedKa", kTH1F, {axes.axisMomentum}); + histos.add("hPtReconstructedPr", "hPtReconstructedPr", kTH1F, {axes.axisMomentum}); // Collision QA - histos.add("hPVz", "hPVz", kTH1F, {axisVertexZ}); - histos.add("hLUTMultiplicity", "hLUTMultiplicity", kTH1F, {axisMultiplicity}); - histos.add("hSimMultiplicity", "hSimMultiplicity", kTH1F, {axisMultiplicity}); - histos.add("hRecoMultiplicity", "hRecoMultiplicity", kTH1F, {axisMultiplicity}); + histos.add("hPVz", "hPVz", kTH1F, {axes.axisVertexZ}); + histos.add("hLUTMultiplicity", "hLUTMultiplicity", kTH1F, {axes.axisMultiplicity}); + histos.add("hSimMultiplicity", "hSimMultiplicity", kTH1F, {axes.axisMultiplicity}); + histos.add("hRecoMultiplicity", "hRecoMultiplicity", kTH1F, {axes.axisMultiplicity}); if (doExtraQA) { - histos.add("h2dVerticesVsContributors", "h2dVerticesVsContributors", kTH2F, {axisMultiplicity, axisNVertices}); - histos.add("hRecoVsSimMultiplicity", "hRecoVsSimMultiplicity", kTH2F, {axisMultiplicity, axisMultiplicity}); - histos.add("h2dDCAxy", "h2dDCAxy", kTH2F, {axisMomentum, axisDCA}); + histos.add("h2dVerticesVsContributors", "h2dVerticesVsContributors", kTH2F, {axes.axisMultiplicity, axes.axisNVertices}); + histos.add("hRecoVsSimMultiplicity", "hRecoVsSimMultiplicity", kTH2F, {axes.axisMultiplicity, axes.axisMultiplicity}); + histos.add("h2dDCAxy", "h2dDCAxy", kTH2F, {axes.axisMomentum, axes.axisDCA}); + histos.add("h2dDCAz", "h2dDCAz", kTH2F, {axes.axisMomentum, axes.axisDCA}); + + histos.add("hSimTrackX", "hSimTrackX", kTH1F, {axes.axisX}); + histos.add("hRecoTrackX", "hRecoTrackX", kTH1F, {axes.axisX}); + histos.add("hTrackXatDCA", "hTrackXatDCA", kTH1F, {axes.axisX}); + } - histos.add("hSimTrackX", "hSimTrackX", kTH1F, {axisX}); - histos.add("hRecoTrackX", "hRecoTrackX", kTH1F, {axisX}); - histos.add("hTrackXatDCA", "hTrackXatDCA", kTH1F, {axisX}); + if (cascadeDecaySettings.doXiQA) { + histos.add("hXiBuilding", "hXiBuilding", kTH1F, {{10, -0.5f, 9.5f}}); + + histos.add("hGenXi", "hGenXi", kTH2F, {axes.axisDecayRadius, axes.axisMomentum}); + histos.add("hRecoXi", "hRecoXi", kTH2F, {axes.axisDecayRadius, axes.axisMomentum}); + + histos.add("hGenPiFromXi", "hGenPiFromXi", kTH2F, {axes.axisDecayRadius, axes.axisMomentum}); + histos.add("hGenPiFromLa", "hGenPiFromLa", kTH2F, {axes.axisDecayRadius, axes.axisMomentum}); + histos.add("hGenPrFromLa", "hGenPrFromLa", kTH2F, {axes.axisDecayRadius, axes.axisMomentum}); + histos.add("hRecoPiFromXi", "hRecoPiFromXi", kTH2F, {axes.axisDecayRadius, axes.axisMomentum}); + histos.add("hRecoPiFromLa", "hRecoPiFromLa", kTH2F, {axes.axisDecayRadius, axes.axisMomentum}); + histos.add("hRecoPrFromLa", "hRecoPrFromLa", kTH2F, {axes.axisDecayRadius, axes.axisMomentum}); + + // basic mass histograms to see if we're in business + histos.add("hMassLambda", "hMassLambda", kTH1F, {axes.axisLambdaMass}); + histos.add("hMassXi", "hMassXi", kTH1F, {axes.axisXiMass}); + + // OTF strangeness tracking QA + histos.add("hFoundVsFindable", "hFoundVsFindable", kTH2F, {{10, -0.5f, 9.5f}, {10, -0.5f, 9.5f}}); + + histos.add("h2dDCAxyCascade", "h2dDCAxyCascade", kTH2F, {axes.axisMomentum, axes.axisDCA}); + histos.add("h2dDCAxyCascadeBachelor", "h2dDCAxyCascadeBachelor", kTH2F, {axes.axisMomentum, axes.axisDCA}); + histos.add("h2dDCAxyCascadeNegative", "h2dDCAxyCascadeNegative", kTH2F, {axes.axisMomentum, axes.axisDCA}); + histos.add("h2dDCAxyCascadePositive", "h2dDCAxyCascadePositive", kTH2F, {axes.axisMomentum, axes.axisDCA}); + + histos.add("h2dDCAzCascade", "h2dDCAzCascade", kTH2F, {axes.axisMomentum, axes.axisDCA}); + histos.add("h2dDCAzCascadeBachelor", "h2dDCAzCascadeBachelor", kTH2F, {axes.axisMomentum, axes.axisDCA}); + histos.add("h2dDCAzCascadeNegative", "h2dDCAzCascadeNegative", kTH2F, {axes.axisMomentum, axes.axisDCA}); + histos.add("h2dDCAzCascadePositive", "h2dDCAzCascadePositive", kTH2F, {axes.axisMomentum, axes.axisDCA}); + + histos.add("h2dDeltaPtVsPt", "h2dDeltaPtVsPt", kTH2F, {axes.axisMomentum, axes.axisDeltaPt}); + histos.add("h2dDeltaEtaVsPt", "h2dDeltaEtaVsPt", kTH2F, {axes.axisMomentum, axes.axisDeltaEta}); + + histos.add("hFastTrackerHits", "hFastTrackerHits", kTH2F, {axes.axisZ, axes.axisRadius}); + auto hFastTrackerQA = histos.add("hFastTrackerQA", "hFastTrackerQA", kTH1D, {{8, -0.5f, 7.5f}}); + hFastTrackerQA->GetXaxis()->SetBinLabel(1, "Negative eigenvalue"); + hFastTrackerQA->GetXaxis()->SetBinLabel(2, "Failed sanity check"); + hFastTrackerQA->GetXaxis()->SetBinLabel(3, "intercept original radius"); + hFastTrackerQA->GetXaxis()->SetBinLabel(4, "propagate to original radius"); + hFastTrackerQA->GetXaxis()->SetBinLabel(5, "problematic layer"); + hFastTrackerQA->GetXaxis()->SetBinLabel(6, "multiple scattering"); + hFastTrackerQA->GetXaxis()->SetBinLabel(7, "energy loss"); + hFastTrackerQA->GetXaxis()->SetBinLabel(8, "efficiency"); } LOGF(info, "Initializing magnetic field to value: %.3f kG", static_cast(magneticField)); @@ -235,6 +405,119 @@ struct OnTheFlyTracker { vertexer.setValidateWithIR(kFALSE); vertexer.setBunchFilling(irSampler.getBunchFilling()); vertexer.init(); + + // initialize O2 2-prong fitter + fitter.setPropagateToPCA(true); + fitter.setMaxR(200.); + fitter.setMinParamChange(1e-3); + fitter.setMinRelChi2Change(0.9); + fitter.setMaxDZIni(1e9); + fitter.setMaxDXYIni(4); + fitter.setMaxChi2(1e9); + fitter.setUseAbsDCA(true); + fitter.setWeightedFinalPCA(false); + fitter.setMatCorrType(o2::base::Propagator::MatCorrType::USEMatCorrNONE); // such a light detector here + + // Set seed for TGenPhaseSpace + rand.SetSeed(seed); + + // configure FastTracker + fastTracker.magneticField = magneticField; + fastTracker.applyZacceptance = fastTrackerSettings.applyZacceptance; + fastTracker.applyMSCorrection = fastTrackerSettings.applyMSCorrection; + fastTracker.applyElossCorrection = fastTrackerSettings.applyElossCorrection; + + if (fastTrackerSettings.alice3detector == 0) { + fastTracker.AddSiliconALICE3v2(fastTrackerSettings.pixelRes); + } + if (fastTrackerSettings.alice3detector == 1) { + fastTracker.AddSiliconALICE3v4(fastTrackerSettings.pixelRes); + fastTracker.AddTPC(0.1, 0.1); + } + + // print fastTracker settings + fastTracker.Print(); + } + + /// Function to decay the xi + /// \param particle the particle to decay + /// \param track track of particle to decay + /// \param decayDaughters the address of resulting daughters + /// \param xiDecayVertex the address of the xi decay vertex + /// \param laDecayVertex the address of the la decay vertex + template + void decayParticle(McParticleType particle, o2::track::TrackParCov track, std::vector& decayDaughters, std::vector& xiDecayVertex, std::vector& laDecayVertex) + { + double u = rand.Uniform(0, 1); + double xi_mass = o2::constants::physics::MassXiMinus; + double la_mass = o2::constants::physics::MassLambda; + double pi_mass = o2::constants::physics::MassPionCharged; + double pr_mass = o2::constants::physics::MassProton; + + double xi_gamma = 1 / sqrt(1 + (particle.p() * particle.p()) / (xi_mass * xi_mass)); + double xi_ctau = 4.91 * xi_gamma; + double xi_rxyz = (-xi_ctau * log(1 - u)); + float sna, csa; + o2::math_utils::CircleXYf_t xi_circle; + track.getCircleParams(magneticField, xi_circle, sna, csa); + double xi_rxy = xi_rxyz / sqrt(1. + track.getTgl() * track.getTgl()); + double theta = xi_rxy / xi_circle.rC; + double newX = ((particle.vx() - xi_circle.xC) * std::cos(theta) - (particle.vy() - xi_circle.yC) * std::sin(theta)) + xi_circle.xC; + double newY = ((particle.vy() - xi_circle.yC) * std::cos(theta) + (particle.vx() - xi_circle.xC) * std::sin(theta)) + xi_circle.yC; + double newPx = particle.px() * std::cos(theta) - particle.py() * std::sin(theta); + double newPy = particle.py() * std::cos(theta) + particle.px() * std::sin(theta); + xiDecayVertex.push_back(newX); + xiDecayVertex.push_back(newY); + xiDecayVertex.push_back(particle.vz() + xi_rxyz * (particle.pz() / particle.p())); + + std::vector xiDaughters = {la_mass, pi_mass}; + TLorentzVector xi(newPx, newPy, particle.pz(), particle.e()); + TGenPhaseSpace xiDecay; + xiDecay.SetDecay(xi, 2, xiDaughters.data()); + xiDecay.Generate(); + decayDaughters.push_back(*xiDecay.GetDecay(1)); + TLorentzVector la = *xiDecay.GetDecay(0); + + double la_gamma = 1 / sqrt(1 + (la.P() * la.P()) / (la_mass * la_mass)); + double la_ctau = 7.89 * la_gamma; + std::vector laDaughters = {pi_mass, pr_mass}; + double la_rxyz = (-la_ctau * log(1 - u)); + laDecayVertex.push_back(xiDecayVertex[0] + la_rxyz * (xiDecay.GetDecay(0)->Px() / xiDecay.GetDecay(0)->P())); + laDecayVertex.push_back(xiDecayVertex[1] + la_rxyz * (xiDecay.GetDecay(0)->Py() / xiDecay.GetDecay(0)->P())); + laDecayVertex.push_back(xiDecayVertex[2] + la_rxyz * (xiDecay.GetDecay(0)->Pz() / xiDecay.GetDecay(0)->P())); + + TGenPhaseSpace laDecay; + laDecay.SetDecay(la, 2, laDaughters.data()); + laDecay.Generate(); + decayDaughters.push_back(*laDecay.GetDecay(0)); + decayDaughters.push_back(*laDecay.GetDecay(1)); + } + + /// Function to convert a TLorentzVector into a perfect Track + /// \param pdgCode particle pdg + /// \param particle the particle to convert (TLorentzVector) + /// \param productionVertex where the particle was produced + /// \param o2track the address of the resulting TrackParCov + void convertTLorentzVectorToO2Track(int pdgCode, TLorentzVector particle, std::vector productionVertex, o2::track::TrackParCov& o2track) + { + auto pdgInfo = pdgDB->GetParticle(pdgCode); + int charge = 0; + if (pdgInfo != nullptr) { + charge = pdgInfo->Charge() / 3; + } + std::array params; + std::array covm = {0.}; + float s, c, x; + o2::math_utils::sincos(static_cast(particle.Phi()), s, c); + o2::math_utils::rotateZInv(static_cast(productionVertex[0]), static_cast(productionVertex[1]), x, params[0], s, c); + params[1] = static_cast(productionVertex[2]); + params[2] = 0; + auto theta = 2. * std::atan(std::exp(-particle.PseudoRapidity())); + params[3] = 1. / std::tan(theta); + params[4] = charge / particle.Pt(); + + // Initialize TrackParCov in-place + new (&o2track)(o2::track::TrackParCov)(x, particle.Phi(), params, covm); } /// Function to convert a McParticle into a perfect Track @@ -266,9 +549,12 @@ struct OnTheFlyTracker { float dNdEta = 0.f; // Charged particle multiplicity to use in the efficiency evaluation void process(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) { + int lastTrackIndex = tracksParCov.lastIndex() + 1; // bookkeep the last added track + tracksAlice3.clear(); ghostTracksAlice3.clear(); bcData.clear(); + cascadesAlice3.clear(); o2::dataformats::DCA dcaInfo; o2::dataformats::VertexBase vtx; @@ -287,7 +573,11 @@ struct OnTheFlyTracker { } const auto pdg = std::abs(mcParticle.pdgCode()); if (pdg != kElectron && pdg != kMuonMinus && pdg != kPiPlus && pdg != kKPlus && pdg != kProton) { - continue; + if (!cascadeDecaySettings.decayXi) { + continue; + } else if (pdg != 3312) { + continue; + } } const auto& pdgInfo = pdgDB->GetParticle(mcParticle.pdgCode()); if (!pdgInfo) { @@ -303,14 +593,38 @@ struct OnTheFlyTracker { dNdEta /= (multEtaRange * 2.0f); uint32_t multiplicityCounter = 0; histos.fill(HIST("hLUTMultiplicity"), dNdEta); + gRandom->SetSeed(seed); for (const auto& mcParticle : mcParticles) { - if (!mcParticle.isPhysicalPrimary()) { - continue; + double xiDecayRadius2D = 0; + double laDecayRadius2D = 0; + std::vector decayProducts; + std::vector xiDecayVertex, laDecayVertex; + std::vector layers = {0.50, 1.20, 2.50, 3.75, 7.00, 12.0, 20.0}; + if (cascadeDecaySettings.decayXi) { + if (mcParticle.pdgCode() == 3312) { + o2::track::TrackParCov xiTrackParCov; + convertMCParticleToO2Track(mcParticle, xiTrackParCov); + decayParticle(mcParticle, xiTrackParCov, decayProducts, xiDecayVertex, laDecayVertex); + xiDecayRadius2D = sqrt(xiDecayVertex[0] * xiDecayVertex[0] + xiDecayVertex[1] * xiDecayVertex[1]); + laDecayRadius2D = sqrt(laDecayVertex[0] * laDecayVertex[0] + laDecayVertex[1] * laDecayVertex[1]); + } } + const auto pdg = std::abs(mcParticle.pdgCode()); + if (!mcParticle.isPhysicalPrimary()) { + if (!cascadeDecaySettings.decayXi) { + continue; + } else if (pdg != 3312) { + continue; + } + } if (pdg != kElectron && pdg != kMuonMinus && pdg != kPiPlus && pdg != kKPlus && pdg != kProton) { - continue; + if (!cascadeDecaySettings.decayXi) { + continue; + } else if (pdg != 3312) { + continue; + } } if (std::fabs(mcParticle.eta()) > maxEta) { continue; @@ -326,29 +640,298 @@ struct OnTheFlyTracker { if (TMath::Abs(mcParticle.pdgCode()) == 2212) histos.fill(HIST("hPtGeneratedPr"), mcParticle.pt()); + if (cascadeDecaySettings.doXiQA && mcParticle.pdgCode() == 3312) { + histos.fill(HIST("hGenXi"), xiDecayRadius2D, mcParticle.pt()); + histos.fill(HIST("hGenPiFromXi"), xiDecayRadius2D, decayProducts[0].Pt()); + histos.fill(HIST("hGenPiFromLa"), laDecayRadius2D, decayProducts[1].Pt()); + histos.fill(HIST("hGenPrFromLa"), laDecayRadius2D, decayProducts[2].Pt()); + } + if (mcParticle.pt() < minPt) { continue; } + o2::track::TrackParCov trackParCov; + convertMCParticleToO2Track(mcParticle, trackParCov); + bool isDecayDaughter = false; if (mcParticle.getProcess() == 4) isDecayDaughter = true; multiplicityCounter++; - o2::track::TrackParCov trackParCov; - convertMCParticleToO2Track(mcParticle, trackParCov); + const float t = (ir.timeInBCNS + gRandom->Gaus(0., 100.)) * 1e-3; + std::vector xiDaughterTrackParCovsPerfect(3); + std::vector xiDaughterTrackParCovsTracked(3); + std::vector isReco(3); + std::vector nHits(3); // total + std::vector nSiliconHits(3); // silicon type + std::vector nTPCHits(3); // TPC type + if (cascadeDecaySettings.decayXi && mcParticle.pdgCode() == 3312) { + if (cascadeDecaySettings.doXiQA) + histos.fill(HIST("hXiBuilding"), 0.0f); + if (xiDecayRadius2D > 20) { + continue; + } + + convertTLorentzVectorToO2Track(-211, decayProducts[0], xiDecayVertex, xiDaughterTrackParCovsPerfect[0]); + convertTLorentzVectorToO2Track(-211, decayProducts[1], laDecayVertex, xiDaughterTrackParCovsPerfect[1]); + convertTLorentzVectorToO2Track(2212, decayProducts[2], laDecayVertex, xiDaughterTrackParCovsPerfect[2]); + + for (int i = 0; i < 3; i++) { + isReco[i] = false; + nHits[i] = 0; + nSiliconHits[i] = 0; + nTPCHits[i] = 0; + if (enableSecondarySmearing) { + nHits[i] = fastTracker.FastTrack(xiDaughterTrackParCovsPerfect[i], xiDaughterTrackParCovsTracked[i], dNdEta); + nSiliconHits[i] = fastTracker.nSiliconPoints; + nTPCHits[i] = fastTracker.nGasPoints; + + if (nHits[i] < 0) { // QA + histos.fill(HIST("hFastTrackerQA"), o2::math_utils::abs(nHits[i])); + } + + if (nSiliconHits[i] >= fastTrackerSettings.minSiliconHits || (nSiliconHits[i] >= fastTrackerSettings.minSiliconHitsIfTPCUsed && nTPCHits[i] >= fastTrackerSettings.minTPCClusters)) { + isReco[i] = true; + } else { + continue; // extra sure + } + for (uint32_t ih = 0; ih < fastTracker.hits.size(); ih++) { + histos.fill(HIST("hFastTrackerHits"), fastTracker.hits[ih][2], std::hypot(fastTracker.hits[ih][0], fastTracker.hits[ih][1])); + } + } else { + isReco[i] = true; + xiDaughterTrackParCovsTracked[i] = xiDaughterTrackParCovsPerfect[i]; + } + + if (TMath::IsNaN(xiDaughterTrackParCovsTracked[i].getZ())) { + continue; + } else { + histos.fill(HIST("hNaNBookkeeping"), i + 1, 1.0f); + } + if (isReco[i]) { + tracksAlice3.push_back(TrackAlice3{xiDaughterTrackParCovsTracked[i], mcParticle.globalIndex(), t, 100.f * 1e-3, true, true, i + 2, nSiliconHits[i], nTPCHits[i]}); + } else { + ghostTracksAlice3.push_back(TrackAlice3{xiDaughterTrackParCovsTracked[i], mcParticle.globalIndex(), t, 100.f * 1e-3, true, true, i + 2}); + } + } + + if (cascadeDecaySettings.doXiQA && mcParticle.pdgCode() == 3312) { + if (isReco[0] && isReco[1] && isReco[2]) { + histos.fill(HIST("hXiBuilding"), 2.0f); + histos.fill(HIST("hRecoXi"), xiDecayRadius2D, mcParticle.pt()); + } + if (isReco[0]) + histos.fill(HIST("hRecoPiFromXi"), xiDecayRadius2D, decayProducts[0].Pt()); + if (isReco[1]) + histos.fill(HIST("hRecoPiFromLa"), laDecayRadius2D, decayProducts[1].Pt()); + if (isReco[2]) + histos.fill(HIST("hRecoPrFromLa"), laDecayRadius2D, decayProducts[2].Pt()); + } + + // +-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+ + // combine particles into actual Xi candidate + // cascade building starts here + if (cascadeDecaySettings.findXi && mcParticle.pdgCode() == 3312 && isReco[0] && isReco[1] && isReco[2]) { + if (cascadeDecaySettings.doXiQA) + histos.fill(HIST("hXiBuilding"), 3.0f); + // assign indices of the particles we've used + // they should be the last ones to be filled, in order: + // n-1: proton from lambda + // n-2: pion from lambda + // n-3: pion from xi + thisCascade.positiveId = lastTrackIndex + tracksAlice3.size() - 1; + thisCascade.negativeId = lastTrackIndex + tracksAlice3.size() - 2; + thisCascade.bachelorId = lastTrackIndex + tracksAlice3.size() - 3; + + // use DCA fitters + int nCand = 0; + bool dcaFitterOK_V0 = true; + try { + nCand = fitter.process(xiDaughterTrackParCovsTracked[1], xiDaughterTrackParCovsTracked[2]); + } catch (...) { + // LOG(error) << "Exception caught in DCA fitter process call!"; + dcaFitterOK_V0 = false; + } + if (nCand == 0) { + dcaFitterOK_V0 = false; + } + // V0 found successfully + if (dcaFitterOK_V0) { + if (cascadeDecaySettings.doXiQA) + histos.fill(HIST("hXiBuilding"), 4.0f); + std::array pos; + std::array posCascade; + std::array posP; + std::array negP; + std::array bachP; + + o2::track::TrackParCov pTrackAtPCA = fitter.getTrack(1); // proton (positive) + o2::track::TrackParCov nTrackAtPCA = fitter.getTrack(0); // pion (negative) + pTrackAtPCA.getPxPyPzGlo(posP); + nTrackAtPCA.getPxPyPzGlo(negP); + + // get decay vertex coordinates + const auto& vtx = fitter.getPCACandidate(); + for (int i = 0; i < 3; i++) { + pos[i] = vtx[i]; + } + + // calculate basic V0 properties here + // DCA to PV taken care of in daughter tracks already, not necessary + thisCascade.dcaV0dau = TMath::Sqrt(fitter.getChi2AtPCACandidate()); + thisCascade.v0radius = std::hypot(pos[0], pos[1]); + thisCascade.mLambda = RecoDecay::m(array{array{posP[0], posP[1], posP[2]}, array{negP[0], negP[1], negP[2]}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); + + // go for cascade: create V0 (pseudo)track from reconstructed V0 + std::array covV = {0.}; + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 6; i++) { + covV[MomInd[i]] = 1e-6; + covV[i] = 1e-6; + } + o2::track::TrackParCov v0Track = o2::track::TrackParCov( + {pos[0], pos[1], pos[2]}, + {posP[0] + negP[0], posP[1] + negP[1], posP[2] + negP[2]}, + covV, 0, true); + v0Track.setAbsCharge(0); + v0Track.setPID(o2::track::PID::Lambda); + + // dca fitter step + nCand = 0; + bool dcaFitterOK_Cascade = true; + try { + nCand = fitter.process(v0Track, xiDaughterTrackParCovsTracked[0]); + } catch (...) { + // LOG(error) << "Exception caught in DCA fitter process call!"; + dcaFitterOK_Cascade = false; + } + if (nCand == 0) { + dcaFitterOK_Cascade = false; + } + + // Cascade found successfully + if (dcaFitterOK_Cascade) { + if (cascadeDecaySettings.doXiQA) + histos.fill(HIST("hXiBuilding"), 5.0f); + o2::track::TrackParCov bachelorTrackAtPCA = fitter.getTrack(1); + + const auto& vtxCascade = fitter.getPCACandidate(); + for (int i = 0; i < 3; i++) { + posCascade[i] = vtxCascade[i]; + } + + // basic properties of the cascade + thisCascade.dcacascdau = TMath::Sqrt(fitter.getChi2AtPCACandidate()); + thisCascade.cascradius = std::hypot(posCascade[0], posCascade[1]); + bachelorTrackAtPCA.getPxPyPzGlo(bachP); + + thisCascade.mXi = RecoDecay::m(array{array{bachP[0], bachP[1], bachP[2]}, array{posP[0] + negP[0], posP[1] + negP[1], posP[2] + negP[2]}}, array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassLambda}); + + // initialize cascade track + o2::track::TrackParCov cascadeTrack = fitter.createParentTrackParCov(); + cascadeTrack.setAbsCharge(-1); // may require more adjustments + cascadeTrack.setPID(o2::track::PID::XiMinus); // FIXME: not OK for omegas + + thisCascade.cascradiusMC = xiDecayRadius2D; + thisCascade.findableClusters = 0; + thisCascade.foundClusters = 0; + + if (cascadeDecaySettings.trackXi) { + // optionally, add the points in the layers before the decay of the Xi + // will back-track the perfect MC cascade to relevant layers, find hit, smear and add to smeared cascade + for (int i = layers.size() - 1; i >= 0; i--) { + if (thisCascade.cascradiusMC > layers[i]) { + // will add this layer, since cascade decayed after the corresponding radius + thisCascade.findableClusters++; // add to findable + + // find perfect intercept XYZ + float targetX = 1e+3; + trackParCov.getXatLabR(layers[i], targetX, magneticField); + if (targetX > 999) + continue; // failed to find intercept + + if (!trackParCov.propagateTo(targetX, magneticField)) { + continue; // failed to propagate + } + + // get potential cluster position + std::array posClusterCandidate; + trackParCov.getXYZGlo(posClusterCandidate); + float r{std::hypot(posClusterCandidate[0], posClusterCandidate[1])}; + float phi{std::atan2(-posClusterCandidate[1], -posClusterCandidate[0]) + o2::its::constants::math::Pi}; + o2::fastsim::DetLayer currentTrackingLayer = fastTracker.GetLayer(i); + + if (currentTrackingLayer.resRPhi > 1e-8 && currentTrackingLayer.resZ > 1e-8) { // catch zero (though should not really happen...) + phi = gRandom->Gaus(phi, std::asin(currentTrackingLayer.resRPhi / r)); + posClusterCandidate[0] = r * std::cos(phi); + posClusterCandidate[1] = r * std::sin(phi); + posClusterCandidate[2] = gRandom->Gaus(posClusterCandidate[2], currentTrackingLayer.resZ); + } + + // towards adding cluster: move to track alpha + double alpha = cascadeTrack.getAlpha(); + double xyz1[3]{ + TMath::Cos(alpha) * posClusterCandidate[0] + TMath::Sin(alpha) * posClusterCandidate[1], + -TMath::Sin(alpha) * posClusterCandidate[0] + TMath::Cos(alpha) * posClusterCandidate[1], + posClusterCandidate[2]}; + + if (!(cascadeTrack.propagateTo(xyz1[0], magneticField))) + continue; + const o2::track::TrackParametrization::dim2_t hitpoint = { + static_cast(xyz1[1]), + static_cast(xyz1[2])}; + const o2::track::TrackParametrization::dim3_t hitpointcov = {currentTrackingLayer.resRPhi * currentTrackingLayer.resRPhi, 0.f, currentTrackingLayer.resZ * currentTrackingLayer.resZ}; + cascadeTrack.update(hitpoint, hitpointcov); + thisCascade.foundClusters++; // add to findable + } + } + } + + // add cascade track + + thisCascade.cascadeTrackId = lastTrackIndex + tracksAlice3.size(); // this is the next index to be filled -> should be it + + tracksAlice3.push_back(TrackAlice3{cascadeTrack, mcParticle.globalIndex(), t, 100.f * 1e-3, false, false, 1, thisCascade.foundClusters}); + + if (cascadeDecaySettings.doXiQA) { + histos.fill(HIST("hXiBuilding"), 6.0f); + histos.fill(HIST("h2dDeltaPtVsPt"), trackParCov.getPt(), cascadeTrack.getPt() - trackParCov.getPt()); + histos.fill(HIST("h2dDeltaEtaVsPt"), trackParCov.getPt(), cascadeTrack.getEta() - trackParCov.getEta()); + + histos.fill(HIST("hMassLambda"), thisCascade.mLambda); + histos.fill(HIST("hMassXi"), thisCascade.mXi); + histos.fill(HIST("hFoundVsFindable"), thisCascade.findableClusters, thisCascade.foundClusters); + } + + // add this cascade to vector (will fill cursor later with collision ID) + cascadesAlice3.push_back(thisCascade); + } + } + } // end cascade building + // +-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+ + + continue; // Not filling the tables with the xi itself + } if (doExtraQA) { histos.fill(HIST("hSimTrackX"), trackParCov.getX()); } - bool reconstructed = mSmearer.smearTrack(trackParCov, mcParticle.pdgCode(), dNdEta); + bool reconstructed = true; + if (enablePrimarySmearing) { + reconstructed = mSmearer.smearTrack(trackParCov, mcParticle.pdgCode(), dNdEta); + } + if (!reconstructed && !processUnreconstructedTracks) { continue; } if (TMath::IsNaN(trackParCov.getZ())) { // capture rare smearing mistakes / corrupted tracks + histos.fill(HIST("hNaNBookkeeping"), 0.0f, 0.0f); continue; + } else { + histos.fill(HIST("hNaNBookkeeping"), 0.0f, 1.0f); // ok! } // Base QA (note: reco pT here) @@ -367,7 +950,6 @@ struct OnTheFlyTracker { } // populate vector with track if we reco-ed it - const float t = (ir.timeInBCNS + gRandom->Gaus(0., 100.)) * 1e-3; if (reconstructed) { tracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), t, 100.f * 1e-3, isDecayDaughter}); } else { @@ -461,11 +1043,32 @@ struct OnTheFlyTracker { } if (doExtraQA && (!extraQAwithoutDecayDaughters || (extraQAwithoutDecayDaughters && !trackParCov.isDecayDau))) { histos.fill(HIST("h2dDCAxy"), trackParametrization.getPt(), dcaXY * 1e+4); // in microns, please + histos.fill(HIST("h2dDCAz"), trackParametrization.getPt(), dcaZ * 1e+4); // in microns, please histos.fill(HIST("hTrackXatDCA"), trackParametrization.getX()); } + if (cascadeDecaySettings.doXiQA) { + if (trackParCov.isUsedInCascading == 1) { + histos.fill(HIST("h2dDCAxyCascade"), trackParametrization.getPt(), dcaXY * 1e+4); // in microns, please + histos.fill(HIST("h2dDCAzCascade"), trackParametrization.getPt(), dcaZ * 1e+4); // in microns, please + } + if (trackParCov.isUsedInCascading == 2) { + histos.fill(HIST("h2dDCAxyCascadeBachelor"), trackParametrization.getPt(), dcaXY * 1e+4); // in microns, please + histos.fill(HIST("h2dDCAzCascadeBachelor"), trackParametrization.getPt(), dcaZ * 1e+4); // in microns, please + } + if (trackParCov.isUsedInCascading == 3) { + histos.fill(HIST("h2dDCAxyCascadeNegative"), trackParametrization.getPt(), dcaXY * 1e+4); // in microns, please + histos.fill(HIST("h2dDCAzCascadeNegative"), trackParametrization.getPt(), dcaZ * 1e+4); // in microns, please + } + if (trackParCov.isUsedInCascading == 4) { + histos.fill(HIST("h2dDCAxyCascadePositive"), trackParametrization.getPt(), dcaXY * 1e+4); // in microns, please + histos.fill(HIST("h2dDCAzCascadePositive"), trackParametrization.getPt(), dcaZ * 1e+4); // in microns, please + } + } tracksDCA(dcaXY, dcaZ); + if (populateTracksDCACov) { + tracksDCACov(dcaInfo.getSigmaY2(), dcaInfo.getSigmaZ2()); + } } - tracksPar(collisions.lastIndex(), trackType, trackParCov.getX(), trackParCov.getAlpha(), trackParCov.getY(), trackParCov.getZ(), trackParCov.getSnp(), trackParCov.getTgl(), trackParCov.getQ2Pt()); tracksParExtension(trackParCov.getPt(), trackParCov.getP(), trackParCov.getEta(), trackParCov.getPhi()); @@ -477,16 +1080,17 @@ struct OnTheFlyTracker { trackParCov.getSigmaTgl2(), trackParCov.getSigma1PtY(), trackParCov.getSigma1PtZ(), trackParCov.getSigma1PtSnp(), trackParCov.getSigma1PtTgl(), trackParCov.getSigma1Pt2()); tracksLabels(trackParCov.mcLabel, 0); + TracksExtraA3(trackParCov.nSiliconHits, trackParCov.nTPCHits); // populate extra tables if required to do so if (populateTracksExtra) { - tracksExtra(0.0f, (uint32_t)0, (uint8_t)0, (uint8_t)0, - (int8_t)0, (int8_t)0, (uint8_t)0, (uint8_t)0, + tracksExtra(0.0f, static_cast(0), static_cast(0), static_cast(0), static_cast(0), + static_cast(0), static_cast(0), static_cast(0), static_cast(0), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); } if (populateTrackSelection) { - trackSelection((uint8_t)0, false, false, false, false, false, false); + trackSelection(static_cast(0), false, false, false, false, false, false); trackSelectionExtension(false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false); } TracksAlice3(true); @@ -505,9 +1109,13 @@ struct OnTheFlyTracker { } if (doExtraQA && (!extraQAwithoutDecayDaughters || (extraQAwithoutDecayDaughters && !trackParCov.isDecayDau))) { histos.fill(HIST("h2dDCAxy"), trackParametrization.getPt(), dcaXY * 1e+4); // in microns, please + histos.fill(HIST("h2dDCAz"), trackParametrization.getPt(), dcaZ * 1e+4); // in microns, please histos.fill(HIST("hTrackXatDCA"), trackParametrization.getX()); } tracksDCA(dcaXY, dcaZ); + if (populateTracksDCACov) { + tracksDCACov(dcaInfo.getSigmaY2(), dcaInfo.getSigmaZ2()); + } } tracksPar(collisions.lastIndex(), trackType, trackParCov.getX(), trackParCov.getAlpha(), trackParCov.getY(), trackParCov.getZ(), trackParCov.getSnp(), trackParCov.getTgl(), trackParCov.getQ2Pt()); @@ -521,21 +1129,44 @@ struct OnTheFlyTracker { trackParCov.getSigmaTgl2(), trackParCov.getSigma1PtY(), trackParCov.getSigma1PtZ(), trackParCov.getSigma1PtSnp(), trackParCov.getSigma1PtTgl(), trackParCov.getSigma1Pt2()); tracksLabels(trackParCov.mcLabel, 0); + TracksExtraA3(trackParCov.nSiliconHits, trackParCov.nTPCHits); // populate extra tables if required to do so if (populateTracksExtra) { - tracksExtra(0.0f, (uint32_t)0, (uint8_t)0, (uint8_t)0, - (int8_t)0, (int8_t)0, (uint8_t)0, (uint8_t)0, + tracksExtra(0.0f, static_cast(0), static_cast(0), static_cast(0), static_cast(0), + static_cast(0), static_cast(0), static_cast(0), static_cast(0), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); } if (populateTrackSelection) { - trackSelection((uint8_t)0, false, false, false, false, false, false); + trackSelection(static_cast(0), false, false, false, false, false, false); trackSelectionExtension(false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false); } TracksAlice3(false); } - } + + for (const auto& cascade : cascadesAlice3) { + upgradeCascades( + collisions.lastIndex(), // now we know the collision index -> populate table + cascade.cascadeTrackId, + cascade.positiveId, + cascade.negativeId, + cascade.bachelorId, + cascade.dcaV0dau, + cascade.dcacascdau, + cascade.v0radius, + cascade.cascradius, + cascade.cascradiusMC, + cascade.mLambda, + cascade.mXi, + cascade.findableClusters, + cascade.foundClusters); + } + + // do bookkeeping of fastTracker tracking + histos.fill(HIST("hCovMatOK"), 0.0f, fastTracker.covMatNotOK); + histos.fill(HIST("hCovMatOK"), 1.0f, fastTracker.covMatOK); + } // end process }; /// Extends TracksExtra if necessary diff --git a/ALICE3/TableProducer/alice3-decayfinder.cxx b/ALICE3/TableProducer/alice3-decayfinder.cxx index 80b9de80238..ae0ea6b5e20 100644 --- a/ALICE3/TableProducer/alice3-decayfinder.cxx +++ b/ALICE3/TableProducer/alice3-decayfinder.cxx @@ -65,149 +65,6 @@ using tofTracks = soa::Join; using richTracks = soa::Join; using alice3tracks = soa::Join; -struct alice3decayPreselector { - Produces a3decayMaps; - - // Operation and minimisation criteria - Configurable nSigmaTOF{"nSigmaTOF", 4.0f, "Nsigma for TOF PID (if enabled)"}; - Configurable nSigmaRICH{"nSigmaRICH", 4.0f, "Nsigma for RICH PID (if enabled)"}; - - // Define o2 fitter, 2-prong, active memory (no need to redefine per event) - o2::vertexing::DCAFitterN<2> fitter; - - // for bit-packed maps - std::vector selectionMap; - - HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - /// function to check PDG + PDG mother - template - bool checkPDG(TTrack const& track, int pdgMother, int pdg) - { - bool returnValue = false; - // Association check - if (track.has_mcParticle()) { - auto mcParticle = track.template mcParticle_as(); - if (mcParticle.has_mothers()) { - for (auto& mcParticleMother : mcParticle.template mothers_as()) { - if (mcParticle.pdgCode() == pdg && mcParticleMother.pdgCode() == pdgMother) - returnValue = true; - } - } - } // end association check - return returnValue; - } - //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - - void init(InitContext&) - { - // future dev if needed - } - - // go declarative: use partitions instead of "if", then just toggle bits to allow for mask selection later - Partition pInnerTOFPi = nabs(aod::upgrade_tof::nSigmaPionInnerTOF) > nSigmaTOF; - Partition pInnerTOFKa = nabs(aod::upgrade_tof::nSigmaKaonInnerTOF) > nSigmaTOF; - Partition pInnerTOFPr = nabs(aod::upgrade_tof::nSigmaProtonInnerTOF) > nSigmaTOF; - Partition pOuterTOFPi = nabs(aod::upgrade_tof::nSigmaPionOuterTOF) > nSigmaTOF; - Partition pOuterTOFKa = nabs(aod::upgrade_tof::nSigmaKaonOuterTOF) > nSigmaTOF; - Partition pOuterTOFPr = nabs(aod::upgrade_tof::nSigmaProtonOuterTOF) > nSigmaTOF; - Partition pRICHPi = nabs(aod::alice3rich::richNsigmaPi) > nSigmaRICH; - Partition pRICHKa = nabs(aod::alice3rich::richNsigmaKa) > nSigmaRICH; - Partition pRICHPr = nabs(aod::alice3rich::richNsigmaPr) > nSigmaRICH; - - //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - /// Initialization of mask vectors if uninitialized - void initializeMasks(int size) - { - selectionMap.clear(); - selectionMap.resize(size, 0xFFFFFFFF); // all bits 1, please - } - //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - /// This process function ensures that all V0s are built. It will simply tag everything as true. - void processInitialize(aod::Tracks const& tracks) - { - initializeMasks(tracks.size()); - } - //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - void processFilterInnerTOF(tofTracks const&) - { - for (auto const& track : pInnerTOFPi) - bitoff(selectionMap[track.globalIndex()], kInnerTOFPion); - for (auto const& track : pInnerTOFKa) - bitoff(selectionMap[track.globalIndex()], kInnerTOFKaon); - for (auto const& track : pInnerTOFPr) - bitoff(selectionMap[track.globalIndex()], kInnerTOFProton); - } - //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - void processFilterOuterTOF(tofTracks const&) - { - for (auto const& track : pOuterTOFPi) - bitoff(selectionMap[track.globalIndex()], kOuterTOFPion); - for (auto const& track : pOuterTOFKa) - bitoff(selectionMap[track.globalIndex()], kOuterTOFKaon); - for (auto const& track : pOuterTOFPr) - bitoff(selectionMap[track.globalIndex()], kOuterTOFProton); - } - //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - void processFilterRICH(richTracks const&) - { - for (auto const& track : pRICHPi) - bitoff(selectionMap[track.globalIndex()], kRICHPion); - for (auto const& track : pRICHKa) - bitoff(selectionMap[track.globalIndex()], kRICHKaon); - for (auto const& track : pRICHPr) - bitoff(selectionMap[track.globalIndex()], kRICHProton); - } - //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - void processFilterOnMonteCarloTruth(labeledTracks const& tracks, aod::McParticles const&) - { - for (auto const& track : tracks) { - // D mesons - if (!checkPDG(track, 421, -321)) //+421 -> -321 +211 - bitoff(selectionMap[track.globalIndex()], kTrueKaMinusFromD); - if (!checkPDG(track, -421, +321)) //-421 -> +321 -211 - bitoff(selectionMap[track.globalIndex()], kTrueKaPlusFromD); - if (!checkPDG(track, 421, +211)) //+421 -> -321 +211 - bitoff(selectionMap[track.globalIndex()], kTruePiPlusFromD); - if (!checkPDG(track, -421, -211)) //-421 -> +321 -211 - bitoff(selectionMap[track.globalIndex()], kTruePiMinusFromD); - - // Lambdac baryons - if (!checkPDG(track, +4122, +2212)) //+4122 -> +2212 -321 +211 - bitoff(selectionMap[track.globalIndex()], kTruePrPlusFromLc); - if (!checkPDG(track, +4122, -321)) //+4122 -> +2212 -321 +211 - bitoff(selectionMap[track.globalIndex()], kTrueKaMinusFromLc); - if (!checkPDG(track, +4122, +211)) //+4122 -> +2212 -321 +211 - bitoff(selectionMap[track.globalIndex()], kTruePiPlusFromLc); - if (!checkPDG(track, -4122, -2212)) //-4122 -> -2212 +321 -211 - bitoff(selectionMap[track.globalIndex()], kTruePrMinusFromLc); - if (!checkPDG(track, -4122, +321)) //-4122 -> -2212 +321 -211 - bitoff(selectionMap[track.globalIndex()], kTrueKaPlusFromLc); - if (!checkPDG(track, -4122, -211)) //-4122 -> -2212 +321 -211 - bitoff(selectionMap[track.globalIndex()], kTruePiMinusFromLc); - } - } - //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - void processPublishDecision(aod::Tracks const& tracks) - { - for (uint32_t i = 0; i < tracks.size(); i++) { - a3decayMaps(selectionMap[i]); - } - selectionMap.clear(); - } - //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - - //*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<* - PROCESS_SWITCH(alice3decayPreselector, processInitialize, "Initialize (MUST be on)", true); - PROCESS_SWITCH(alice3decayPreselector, processFilterInnerTOF, "Switch to use inner TOF PID", false); - PROCESS_SWITCH(alice3decayPreselector, processFilterOuterTOF, "Switch to use outer TOF PID", false); - PROCESS_SWITCH(alice3decayPreselector, processFilterRICH, "Switch to use RICH", false); - PROCESS_SWITCH(alice3decayPreselector, processFilterOnMonteCarloTruth, "Switch to use MC truth", false); - PROCESS_SWITCH(alice3decayPreselector, processPublishDecision, "Fill decision mask table (MUST be on)", true); - //*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<* -}; - struct alice3decayFinder { SliceCache cache; @@ -223,6 +80,15 @@ struct alice3decayFinder { Configurable kaFromD_dcaXYconstant{"kaFromD_dcaXYconstant", -1.0f, "[0] in |DCAxy| > [0]+[1]/pT"}; Configurable kaFromD_dcaXYpTdep{"kaFromD_dcaXYpTdep", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; + Configurable DCosPA{"DCosPA", 0.99, " Cos of pointing angle: pt < 3 GeV"}; + Configurable DCosPAHighPt{"DCosPAHighPt", 0.995, " Cos of pointing angle: 3 GeV < pt"}; + Configurable DCosPAxy{"DCosPAxy", 0.99, " Cos of pointing angle xy: pt < 3 GeV"}; + Configurable DCosPAxyHighPt{"DCosPAxyHighPt", 0.995, " Cos of pointing angle xy: 3 GeV < pt"}; + Configurable DCosThetaStarLowPt{"DCosThetaStarLowPt", 0.8, "Cos theta; pt < 9"}; + Configurable DCosThetaStarHighPt{"DCosThetaStarHighPt", 0.9, "Cos theta; 9 < pt < 16"}; + Configurable DCosThetaStarVHighPt{"DCosThetaStarVHighPt", 1.0, "Cos theta; 16 < pt"}; + Configurable DDauDecayLength{"DDauDecayLength", 3, "|Normalized dau decay length| > [0]"}; + Configurable piFromLc_dcaXYconstant{"piFromLc_dcaXYconstant", -1.0f, "[0] in |DCAxy| > [0]+[1]/pT"}; Configurable piFromLc_dcaXYpTdep{"piFromLc_dcaXYpTdep", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; Configurable kaFromLc_dcaXYconstant{"kaFromLc_dcaXYconstant", -1.0f, "[0] in |DCAxy| > [0]+[1]/pT"}; @@ -233,6 +99,7 @@ struct alice3decayFinder { ConfigurableAxis axisEta{"axisEta", {8, -4.0f, +4.0f}, "#eta"}; ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for QA histograms"}; ConfigurableAxis axisDCA{"axisDCA", {200, -100, 100}, "DCA (#mum)"}; + ConfigurableAxis axisDCADaughters{"axisDCADaughters", {200, 0, 100}, "DCA (#mum)"}; ConfigurableAxis axisDMass{"axisDMass", {200, 1.765f, 1.965f}, "D Inv Mass (GeV/c^{2})"}; ConfigurableAxis axisLcMass{"axisLcMass", {200, 2.186f, 2.386f}, "#Lambda_{c} Inv Mass (GeV/c^{2})"}; @@ -262,7 +129,9 @@ struct alice3decayFinder { // partitions for D mesons Partition tracksPiPlusFromD = - ((aod::a3DecayMap::decayMap & trackSelectionPiPlusFromD) == trackSelectionPiPlusFromD) && aod::track::signed1Pt > 0.0f && nabs(aod::track::dcaXY) > piFromD_dcaXYconstant + piFromD_dcaXYpTdep* nabs(aod::track::signed1Pt); + ((aod::a3DecayMap::decayMap & trackSelectionPiPlusFromD) == trackSelectionPiPlusFromD) && + aod::track::signed1Pt > 0.0f && + nabs(aod::track::dcaXY) > piFromD_dcaXYconstant + piFromD_dcaXYpTdep* nabs(aod::track::signed1Pt); Partition tracksPiMinusFromD = ((aod::a3DecayMap::decayMap & trackSelectionPiMinusFromD) == trackSelectionPiMinusFromD) && aod::track::signed1Pt < 0.0f && nabs(aod::track::dcaXY) > piFromD_dcaXYconstant + piFromD_dcaXYpTdep* nabs(aod::track::signed1Pt); Partition tracksKaPlusFromD = @@ -287,12 +156,20 @@ struct alice3decayFinder { // Helper struct to pass candidate information struct { + float dcaDau; float mass; + std::array posSV; + std::array P; float pt; float eta; + float cosPA; + float cosPAxy; + float cosThetaStar; + float normalizedDecayLength; } dmeson; struct { + float dcaDau; float mass; float pt; float eta; @@ -323,15 +200,19 @@ struct alice3decayFinder { std::array negP; posTrack.getPxPyPzGlo(posP); negTrack.getPxPyPzGlo(negP); - - float dcaDau = TMath::Sqrt(fitter.getChi2AtPCACandidate()); - if (dcaDau > dcaDaughtersSelection) - return false; + dmeson.dcaDau = TMath::Sqrt(fitter.getChi2AtPCACandidate()); // return mass dmeson.mass = RecoDecay::m(array{array{posP[0], posP[1], posP[2]}, array{negP[0], negP[1], negP[2]}}, array{posMass, negMass}); dmeson.pt = std::hypot(posP[0] + negP[0], posP[1] + negP[1]); dmeson.eta = RecoDecay::eta(array{posP[0] + negP[0], posP[1] + negP[1], posP[2] + negP[2]}); + const auto posSV = fitter.getPCACandidate(); + dmeson.posSV[0] = posSV[0]; + dmeson.posSV[1] = posSV[1]; + dmeson.posSV[2] = posSV[2]; + o2::track::TrackParCov parentTrack = fitter.createParentTrackParCov(); + parentTrack.getPxPyPzGlo(dmeson.P); + dmeson.cosThetaStar = RecoDecay::cosThetaStar(std::array{std::array{posP[0], posP[1], posP[2]}, std::array{negP[0], negP[1], negP[2]}}, std::array{posMass, negMass}, dmeson.mass, 0); return true; } @@ -355,9 +236,9 @@ struct alice3decayFinder { } //}-{}-{}-{}-{}-{}-{}-{}-{}-{} - t0 = fitter.getTrack(0); - t1 = fitter.getTrack(1); - t2 = fitter.getTrack(2); + t0 = fitter3.getTrack(0); + t1 = fitter3.getTrack(1); + t2 = fitter3.getTrack(2); std::array P0; std::array P1; std::array P2; @@ -365,8 +246,8 @@ struct alice3decayFinder { t1.getPxPyPzGlo(P1); t2.getPxPyPzGlo(P2); - float dcaDau = TMath::Sqrt(fitter3.getChi2AtPCACandidate()); - if (dcaDau > dcaDaughtersSelection) + lcbaryon.dcaDau = TMath::Sqrt(fitter3.getChi2AtPCACandidate()); + if (lcbaryon.dcaDau > dcaDaughtersSelection) return false; // return mass @@ -433,7 +314,14 @@ struct alice3decayFinder { histos.add("hMassD", "hMassD", kTH1F, {axisDMass}); histos.add("hMassDbar", "hMassDbar", kTH1F, {axisDMass}); + histos.add("hDCosPA", "hDCosPA", kTH1F, {{200, 0, 1}}); + histos.add("hDCosPAxy", "hDCosPAxy", kTH1F, {{200, 0, 1}}); + histos.add("hDCosThetaStar", "hDCosThetaStar", kTH1F, {{200, -1, 1}}); + histos.add("hDDauDecayLength", "hDDauDecayLength", kTH1F, {{100, 0, 10}}); + if (doDCAplotsD) { + histos.add("hDCADDaughters", "hDCADDaughters", kTH1D, {axisDCADaughters}); + histos.add("hDCADbarDaughters", "hDCADbarDaughters", kTH1D, {axisDCA}); histos.add("h2dDCAxyVsPtPiPlusFromD", "h2dDCAxyVsPtPiPlusFromD", kTH2F, {axisPt, axisDCA}); histos.add("h2dDCAxyVsPtPiMinusFromD", "h2dDCAxyVsPtPiMinusFromD", kTH2F, {axisPt, axisDCA}); histos.add("h2dDCAxyVsPtKaPlusFromD", "h2dDCAxyVsPtKaPlusFromD", kTH2F, {axisPt, axisDCA}); @@ -450,6 +338,8 @@ struct alice3decayFinder { histos.add("hMassLcbar", "hMassLcbar", kTH1F, {axisLcMass}); if (doDCAplotsD) { + histos.add("hDCALcDaughters", "hDCALcDaughters", kTH1D, {axisDCADaughters}); + histos.add("hDCALcbarDaughters", "hDCALcbarDaughters", kTH1D, {axisDCA}); histos.add("h2dDCAxyVsPtPiPlusFromLc", "h2dDCAxyVsPtPiPlusFromLc", kTH2F, {axisPt, axisDCA}); histos.add("h2dDCAxyVsPtPiMinusFromLc", "h2dDCAxyVsPtPiMinusFromLc", kTH2F, {axisPt, axisDCA}); histos.add("h2dDCAxyVsPtKaPlusFromLc", "h2dDCAxyVsPtKaPlusFromLc", kTH2F, {axisPt, axisDCA}); @@ -505,6 +395,42 @@ struct alice3decayFinder { continue; if (!buildDecayCandidateTwoBody(posTrackRow, negTrackRow, o2::constants::physics::MassPionCharged, o2::constants::physics::MassKaonCharged)) continue; + + dmeson.cosPA = RecoDecay::cpa(std::array{collision.posX(), collision.posY(), collision.posZ()}, std::array{dmeson.posSV[0], dmeson.posSV[1], dmeson.posSV[2]}, std::array{dmeson.P[0], dmeson.P[1], dmeson.P[2]}); + dmeson.cosPAxy = RecoDecay::cpaXY(std::array{collision.posX(), collision.posY(), collision.posZ()}, std::array{dmeson.posSV[0], dmeson.posSV[1], dmeson.posSV[2]}, std::array{dmeson.P[0], dmeson.P[1], dmeson.P[2]}); + + const float dmesonCtau = 0.012301; + dmeson.normalizedDecayLength = ((dmeson.mass * std::fabs(std::hypot(collision.posX(), collision.posY(), collision.posZ()) - std::hypot(dmeson.posSV[0], dmeson.posSV[1], dmeson.posSV[2]))) / std::hypot(dmeson.P[0], dmeson.P[1], dmeson.P[2])) / dmesonCtau; + + histos.fill(HIST("hDCosPA"), dmeson.cosPA); + histos.fill(HIST("hDCosPAxy"), dmeson.cosPAxy); + histos.fill(HIST("hDCosThetaStar"), dmeson.cosThetaStar); + histos.fill(HIST("hDDauDecayLength"), dmeson.normalizedDecayLength); + + if (dmeson.dcaDau > dcaDaughtersSelection) + continue; + + if (dmeson.pt <= 3 && dmeson.cosPA < DCosPA) + continue; + else if (dmeson.pt > 3 && dmeson.cosPA < DCosPAHighPt) + continue; + + if (dmeson.pt <= 3 && dmeson.cosPAxy < DCosPAxy) + continue; + else if (dmeson.pt > 3 && dmeson.cosPAxy < DCosPAxyHighPt) + continue; + + if (dmeson.pt <= 9 && std::fabs(dmeson.cosThetaStar) > DCosThetaStarLowPt) + continue; + else if (dmeson.pt <= 16 && std::fabs(dmeson.cosThetaStar) > DCosThetaStarHighPt) + continue; + else if (dmeson.pt > 16 && std::fabs(dmeson.cosThetaStar) > DCosThetaStarVHighPt) + continue; + + if (dmeson.normalizedDecayLength > DDauDecayLength) + continue; + + histos.fill(HIST("hDCADDaughters"), dmeson.dcaDau * 1e+4); histos.fill(HIST("hMassD"), dmeson.mass); histos.fill(HIST("h3dRecD"), dmeson.pt, dmeson.eta, dmeson.mass); } @@ -516,6 +442,42 @@ struct alice3decayFinder { continue; if (!buildDecayCandidateTwoBody(posTrackRow, negTrackRow, o2::constants::physics::MassKaonCharged, o2::constants::physics::MassPionCharged)) continue; + + dmeson.cosPA = RecoDecay::cpa(std::array{collision.posX(), collision.posY(), collision.posZ()}, std::array{dmeson.posSV[0], dmeson.posSV[1], dmeson.posSV[2]}, std::array{dmeson.P[0], dmeson.P[1], dmeson.P[2]}); + dmeson.cosPAxy = RecoDecay::cpaXY(std::array{collision.posX(), collision.posY(), collision.posZ()}, std::array{dmeson.posSV[0], dmeson.posSV[1], dmeson.posSV[2]}, std::array{dmeson.P[0], dmeson.P[1], dmeson.P[2]}); + + const float dmesonCtau = 0.012301; + dmeson.normalizedDecayLength = ((dmeson.mass * std::fabs(std::hypot(collision.posX(), collision.posY(), collision.posZ()) - std::hypot(dmeson.posSV[0], dmeson.posSV[1], dmeson.posSV[2]))) / std::hypot(dmeson.P[0], dmeson.P[1], dmeson.P[2])) / dmesonCtau; + + histos.fill(HIST("hDCosPA"), dmeson.cosPA); + histos.fill(HIST("hDCosPAxy"), dmeson.cosPAxy); + histos.fill(HIST("hDCosThetaStar"), dmeson.cosThetaStar); + histos.fill(HIST("hDDauDecayLength"), dmeson.normalizedDecayLength); + + if (dmeson.dcaDau > dcaDaughtersSelection) + continue; + + if (dmeson.pt <= 3 && dmeson.cosPA < DCosPA) + continue; + else if (dmeson.pt > 3 && dmeson.cosPA < DCosPAHighPt) + continue; + + if (dmeson.pt <= 3 && dmeson.cosPAxy < DCosPAxy) + continue; + else if (dmeson.pt > 3 && dmeson.cosPAxy < DCosPAxyHighPt) + continue; + + if (dmeson.pt <= 9 && std::fabs(dmeson.cosThetaStar) > DCosThetaStarLowPt) + continue; + else if (dmeson.pt <= 16 && std::fabs(dmeson.cosThetaStar) > DCosThetaStarHighPt) + continue; + else if (dmeson.pt > 16 && std::fabs(dmeson.cosThetaStar) > DCosThetaStarVHighPt) + continue; + + if (dmeson.normalizedDecayLength > DDauDecayLength) + continue; + + histos.fill(HIST("hDCADbarDaughters"), dmeson.dcaDau * 1e+4); histos.fill(HIST("hMassDbar"), dmeson.mass); histos.fill(HIST("h3dRecDbar"), dmeson.pt, dmeson.eta, dmeson.mass); } @@ -560,6 +522,7 @@ struct alice3decayFinder { continue; if (!buildDecayCandidateThreeBody(proton, kaon, pion, o2::constants::physics::MassProton, o2::constants::physics::MassKaonCharged, o2::constants::physics::MassPionCharged)) continue; + histos.fill(HIST("hDCALcDaughters"), lcbaryon.dcaDau * 1e+4); histos.fill(HIST("hMassLc"), lcbaryon.mass); histos.fill(HIST("h3dRecLc"), lcbaryon.pt, lcbaryon.eta, lcbaryon.mass); } @@ -575,6 +538,7 @@ struct alice3decayFinder { continue; if (!buildDecayCandidateThreeBody(proton, kaon, pion, o2::constants::physics::MassProton, o2::constants::physics::MassKaonCharged, o2::constants::physics::MassPionCharged)) continue; + histos.fill(HIST("hDCALcbarDaughters"), lcbaryon.dcaDau * 1e+4); histos.fill(HIST("hMassLcbar"), lcbaryon.mass); histos.fill(HIST("h3dRecLcbar"), lcbaryon.pt, lcbaryon.eta, lcbaryon.mass); } @@ -593,6 +557,5 @@ struct alice3decayFinder { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc)}; } diff --git a/ALICE3/TableProducer/alice3-decaypreselector.cxx b/ALICE3/TableProducer/alice3-decaypreselector.cxx new file mode 100644 index 00000000000..e27e1e3ad94 --- /dev/null +++ b/ALICE3/TableProducer/alice3-decaypreselector.cxx @@ -0,0 +1,223 @@ +// 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. +// +// *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* +// Decay finder task for ALICE 3 +// *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* +// +// Uses specific ALICE 3 PID and performance for studying +// HF decays. Work in progress: use at your own risk! +// + +#include +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "DCAFitter/DCAFitterN.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "ALICE3/DataModel/OTFTOF.h" +#include "ALICE3/DataModel/OTFRICH.h" +#include "ALICE3/DataModel/A3DecayFinderTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +// simple checkers +// #define biton(var, nbit) ((var) |= (static_cast(1) << (nbit))) +#define bitoff(var, nbit) ((var) &= ~(static_cast(1) << (nbit))) //((a) &= ~(1ULL<<(b))) +// #define bitcheck(var, nbit) ((var) & (static_cast(1) << (nbit))) + +using FullTracksExt = soa::Join; + +// For MC association in pre-selection +using labeledTracks = soa::Join; +using tofTracks = soa::Join; +using richTracks = soa::Join; + +struct alice3decaypreselector { + Produces a3decayMaps; + + // Operation and minimisation criteria + Configurable nSigmaTOF{"nSigmaTOF", 4.0f, "Nsigma for TOF PID (if enabled)"}; + Configurable nSigmaRICH{"nSigmaRICH", 4.0f, "Nsigma for RICH PID (if enabled)"}; + + // Define o2 fitter, 2-prong, active memory (no need to redefine per event) + o2::vertexing::DCAFitterN<2> fitter; + + // for bit-packed maps + std::vector selectionMap; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + /// function to check PDG + PDG mother + template + bool checkPDG(TTrack const& track, int pdgMother, int pdg) + { + bool returnValue = false; + // Association check + if (track.has_mcParticle()) { + auto mcParticle = track.template mcParticle_as(); + if (mcParticle.has_mothers()) { + for (auto& mcParticleMother : mcParticle.template mothers_as()) { + if (mcParticle.pdgCode() == pdg && mcParticleMother.pdgCode() == pdgMother) + returnValue = true; + } + } + } // end association check + return returnValue; + } + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + + void init(InitContext&) + { + // future dev if needed + } + + // go declarative: use partitions instead of "if", then just toggle bits to allow for mask selection later + Partition pInnerTOFPi = nabs(aod::upgrade_tof::nSigmaPionInnerTOF) > nSigmaTOF; + Partition pInnerTOFKa = nabs(aod::upgrade_tof::nSigmaKaonInnerTOF) > nSigmaTOF; + Partition pInnerTOFPr = nabs(aod::upgrade_tof::nSigmaProtonInnerTOF) > nSigmaTOF; + Partition pOuterTOFPi = nabs(aod::upgrade_tof::nSigmaPionOuterTOF) > nSigmaTOF; + Partition pOuterTOFKa = nabs(aod::upgrade_tof::nSigmaKaonOuterTOF) > nSigmaTOF; + Partition pOuterTOFPr = nabs(aod::upgrade_tof::nSigmaProtonOuterTOF) > nSigmaTOF; + Partition pRICHPi = nabs(aod::upgrade_rich::nSigmaPionRich) > nSigmaRICH; + Partition pRICHKa = nabs(aod::upgrade_rich::nSigmaKaonRich) > nSigmaRICH; + Partition pRICHPr = nabs(aod::upgrade_rich::nSigmaProtonRich) > nSigmaRICH; + + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + /// Initialization of mask vectors if uninitialized + void initializeMasks(int size) + { + selectionMap.clear(); + selectionMap.resize(size, 0xFFFFFFFF); // all bits 1, please + } + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + /// This process function ensures that all V0s are built. It will simply tag everything as true. + void processInitialize(aod::Tracks const& tracks) + { + initializeMasks(tracks.size()); + } + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + void processFilterInnerTOF(tofTracks const&) + { + for (auto const& track : pInnerTOFPi) + bitoff(selectionMap[track.globalIndex()], kInnerTOFPion); + for (auto const& track : pInnerTOFKa) + bitoff(selectionMap[track.globalIndex()], kInnerTOFKaon); + for (auto const& track : pInnerTOFPr) + bitoff(selectionMap[track.globalIndex()], kInnerTOFProton); + } + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + void processFilterOuterTOF(tofTracks const&) + { + for (auto const& track : pOuterTOFPi) + bitoff(selectionMap[track.globalIndex()], kOuterTOFPion); + for (auto const& track : pOuterTOFKa) + bitoff(selectionMap[track.globalIndex()], kOuterTOFKaon); + for (auto const& track : pOuterTOFPr) + bitoff(selectionMap[track.globalIndex()], kOuterTOFProton); + } + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + void processFilterRICH(richTracks const&) + { + for (auto const& track : pRICHPi) + bitoff(selectionMap[track.globalIndex()], kRICHPion); + for (auto const& track : pRICHKa) + bitoff(selectionMap[track.globalIndex()], kRICHKaon); + for (auto const& track : pRICHPr) + bitoff(selectionMap[track.globalIndex()], kRICHProton); + } + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + void processFilterOnMonteCarloTruth(labeledTracks const& tracks, aod::McParticles const&) + { + for (auto const& track : tracks) { + // D mesons + if (!checkPDG(track, 421, -321)) //+421 -> -321 +211 + bitoff(selectionMap[track.globalIndex()], kTrueKaMinusFromD); + if (!checkPDG(track, -421, +321)) //-421 -> +321 -211 + bitoff(selectionMap[track.globalIndex()], kTrueKaPlusFromD); + if (!checkPDG(track, 421, +211)) //+421 -> -321 +211 + bitoff(selectionMap[track.globalIndex()], kTruePiPlusFromD); + if (!checkPDG(track, -421, -211)) //-421 -> +321 -211 + bitoff(selectionMap[track.globalIndex()], kTruePiMinusFromD); + + // Lambdac baryons + if (!checkPDG(track, +4122, +2212)) //+4122 -> +2212 -321 +211 + bitoff(selectionMap[track.globalIndex()], kTruePrPlusFromLc); + if (!checkPDG(track, +4122, -321)) //+4122 -> +2212 -321 +211 + bitoff(selectionMap[track.globalIndex()], kTrueKaMinusFromLc); + if (!checkPDG(track, +4122, +211)) //+4122 -> +2212 -321 +211 + bitoff(selectionMap[track.globalIndex()], kTruePiPlusFromLc); + if (!checkPDG(track, -4122, -2212)) //-4122 -> -2212 +321 -211 + bitoff(selectionMap[track.globalIndex()], kTruePrMinusFromLc); + if (!checkPDG(track, -4122, +321)) //-4122 -> -2212 +321 -211 + bitoff(selectionMap[track.globalIndex()], kTrueKaPlusFromLc); + if (!checkPDG(track, -4122, -211)) //-4122 -> -2212 +321 -211 + bitoff(selectionMap[track.globalIndex()], kTruePiMinusFromLc); + + // XiCC daughters + if (!checkPDG(track, 4422, 211)) // 4422 -> 4232 211, pi from xicc + bitoff(selectionMap[track.globalIndex()], kTruePiFromXiCC); + if (!checkPDG(track, 4232, 3312)) // 4232 -> 3312 211 211, xi from xic + bitoff(selectionMap[track.globalIndex()], kTrueXiFromXiC); + if (!checkPDG(track, 4232, 211)) // 4232 -> 3312 211 211, pi from xic + bitoff(selectionMap[track.globalIndex()], kTruePiFromXiC); + } + } + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + void processPublishDecision(aod::Tracks const& tracks) + { + for (uint32_t i = 0; i < tracks.size(); i++) { + a3decayMaps(selectionMap[i]); + } + selectionMap.clear(); + } + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + + //*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<* + PROCESS_SWITCH(alice3decaypreselector, processInitialize, "Initialize (MUST be on)", true); + PROCESS_SWITCH(alice3decaypreselector, processFilterInnerTOF, "Switch to use inner TOF PID", false); + PROCESS_SWITCH(alice3decaypreselector, processFilterOuterTOF, "Switch to use outer TOF PID", false); + PROCESS_SWITCH(alice3decaypreselector, processFilterRICH, "Switch to use RICH", false); + PROCESS_SWITCH(alice3decaypreselector, processFilterOnMonteCarloTruth, "Switch to use MC truth", false); + PROCESS_SWITCH(alice3decaypreselector, processPublishDecision, "Fill decision mask table (MUST be on)", true); + //*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<* +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/ALICE3/TableProducer/alice3-multicharm.cxx b/ALICE3/TableProducer/alice3-multicharm.cxx new file mode 100644 index 00000000000..d2ac55f8f11 --- /dev/null +++ b/ALICE3/TableProducer/alice3-multicharm.cxx @@ -0,0 +1,667 @@ +// 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. +// +// *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* +// Decay finder task for ALICE 3 +// *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* +// +// Uses specific ALICE 3 PID and performance for studying +// HF decays. Work in progress: use at your own risk! +// + +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "DCAFitter/DCAFitterN.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "ALICE3/DataModel/OTFTOF.h" +#include "ALICE3/DataModel/RICH.h" +#include "ALICE3/DataModel/A3DecayFinderTables.h" +#include "ALICE3/DataModel/OTFStrangeness.h" +#include "ALICE3/DataModel/OTFMulticharm.h" +#include "ALICE3/DataModel/tracksAlice3.h" +#include "DetectorsVertexing/PVertexer.h" +#include "DetectorsVertexing/PVertexerHelpers.h" +#include "CommonConstants/PhysicsConstants.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +// simple checkers +// #define biton(var, nbit) ((var) |= (static_cast(1) << (nbit))) +#define bitoff(var, nbit) ((var) &= ~(static_cast(1) << (nbit))) //((a) &= ~(1ULL<<(b))) +#define bitcheck(var, nbit) ((var) & (static_cast(1) << (nbit))) + +using FullTracksExt = soa::Join; + +// For MC association in pre-selection +using labeledTracks = soa::Join; +using tofTracks = soa::Join; +using richTracks = soa::Join; +using alice3tracks = soa::Join; + +struct alice3multicharm { + SliceCache cache; + + Produces multiCharmIdx; + Produces multiCharmCore; + + // Operation and minimisation criteria + Configurable fillDerivedTable{"fillDerivedTable", false, "fill MCharm[] tables (careful: memory)"}; + Configurable magneticField{"magneticField", 20.0f, "Magnetic field (in kilogauss)"}; + Configurable doDCAplots{"doDCAplots", true, "do daughter prong DCA plots for D mesons"}; + Configurable mcSameMotherCheck{"mcSameMotherCheck", true, "check if tracks come from the same MC mother"}; + Configurable dcaXiCDaughtersSelection{"dcaXiCDaughtersSelection", 0.002f, "DCA between XiC daughters (cm)"}; + Configurable dcaXiCCDaughtersSelection{"dcaXiCCDaughtersSelection", 0.002f, "DCA between XiCC daughters (cm)"}; + + Configurable piFromXiC_dcaXYconstant{"piFromXiC_dcaXYconstant", 0.001f, "[0] in |DCAxy| > [0]+[1]/pT"}; + Configurable piFromXiC_dcaZconstant{"piFromXiC_dcaZconstant", 0.001f, "[0] in |DCAxy| > [0]+[1]/pT"}; + Configurable piFromXiC_dcaXYpTdep{"piFromXiC_dcaXYpTdep", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; + Configurable piFromXiC_dcaZpTdep{"piFromXiC_dcaZpTdep", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; + Configurable piFromXiCC_dcaXYconstant{"piFromXiCC_dcaXYconstant", 0.001f, "[0] in |DCAxy| > [0]+[1]/pT"}; + Configurable piFromXiCC_dcaZconstant{"piFromXiCC_dcaZconstant", 0.001f, "[0] in |DCAxy| > [0]+[1]/pT"}; + Configurable piFromXiCC_dcaXYpTdep{"piFromXiCC_dcaXYpTdep", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; + Configurable piFromXiCC_dcaZpTdep{"piFromXiCC_dcaZpTdep", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; + Configurable xiFromXiC_dcaXYconstant{"xiFromXiC_dcaXYconstant", 0.001f, "[0] in |DCAxy| > [0]+[1]/pT"}; + Configurable xiFromXiC_dcaZconstant{"xiFromXiC_dcaZconstant", 0.001f, "[0] in |DCAxy| > [0]+[1]/pT"}; + Configurable xiFromXiC_dcaXYpTdep{"xiFromXiC_dcaXYpTdep", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; + Configurable xiFromXiC_dcaZpTdep{"xiFromXiC_dcaZpTdep", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; + + Configurable xiCFromXiCC_dcaXY{"xiCFromXiCC_dcaXY", 0.0015f, "maxDCA"}; + Configurable xiCFromXiCC_dcaZ{"xiCFromXiCC_dcaZ", 0.0015f, "maxDCA"}; + Configurable xiCC_dcaXY{"xiCC_dcaXY", 0.002f, "maxDCA"}; + Configurable xiCC_dcaZ{"xiCC_dcaZ", 0.002f, "maxDCA"}; + + Configurable minPiCPt{"minPiCPt", 0.15, "Minimum pT for XiC pions"}; + Configurable minPiCCPt{"minPiCCPt", 0.3, "Minimum pT for XiCC pions"}; + Configurable minNTracks{"minNTracks", -1, "Minimum number of tracks"}; + + Configurable minXiCRadius{"minXiCRadius", 0.001, "Minimum R2D for XiC decay (cm)"}; + Configurable minXiCCRadius{"minXiCCRadius", 0.005, "Minimum R2D for XiCC decay (cm)"}; + Configurable xicMinProperLength{"xicMinProperLength", 0.002, "Minimum proper length for XiC decay (cm)"}; + Configurable xicMaxProperLength{"xicMaxProperLength", 0.06, "Minimum proper length for XiC decay (cm)"}; + Configurable xiccMinProperLength{"xiccMinProperLength", 0.004, "Minimum proper length for XiCC decay (cm)"}; + Configurable xiccMaxProperLength{"xiccMaxProperLength", 999, "Minimum proper length for XiCC decay (cm)"}; + Configurable massWindowXi{"massWindowXi", 0.015, "Mass window around Xi peak"}; + Configurable massWindowXiC{"massWindowXiC", 0.015, "Mass window around XiC peak"}; + + ConfigurableAxis axisEta{"axisEta", {80, -4.0f, +4.0f}, "#eta"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for QA histograms"}; + ConfigurableAxis axisDCA2d{"axisDCA2d", {400, -200, 200}, "DCA2d (#mum)"}; + ConfigurableAxis axisDCA{"axisDCA", {200, 0, 200}, "DCA (#mum)"}; + ConfigurableAxis axisRadius{"axisRadius", {1000, 0, 1000}, "Decay radius (#mum)"}; + ConfigurableAxis axisDecayLength{"axisDecayLength", {2000, 0, 2000}, "Decay lenght (#mum)"}; + + ConfigurableAxis axisXiMass{"axisXiMass", {200, 1.221f, 1.421f}, "Xi Inv Mass (GeV/c^{2})"}; + ConfigurableAxis axisXiCMass{"axisXiCMass", {200, 2.368f, 2.568f}, "XiC Inv Mass (GeV/c^{2})"}; + ConfigurableAxis axisXiCCMass{"axisXiCCMass", {200, 3.521f, 3.721f}, "XiCC Inv Mass (GeV/c^{2})"}; + + ConfigurableAxis axisDCAXiCDaughters{"axisDCAXiCDaughters", {200, 0, 100}, "DCA (mum)"}; + ConfigurableAxis axisDCAXiCCDaughters{"axisDCAXiCCDaughters", {200, 0, 100}, "DCA (mum)"}; + + ConfigurableAxis axisNConsidered{"axisNConsidered", {200, -0.5f, 199.5f}, "Number of considered track combinations"}; + + o2::vertexing::DCAFitterN<2> fitter; + o2::vertexing::DCAFitterN<3> fitter3; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Partition trueXi = aod::mcparticle::pdgCode == 3312; + Partition trueXiC = aod::mcparticle::pdgCode == 4232; + Partition trueXiCC = aod::mcparticle::pdgCode == 4422; + + // filter expressions for D mesons + static constexpr uint32_t trackSelectionPiFromXiC = 1 << kInnerTOFPion | 1 << kOuterTOFPion | 1 << kRICHPion | 1 << kTruePiFromXiC; + static constexpr uint32_t trackSelectionPiFromXiCC = 1 << kInnerTOFPion | 1 << kOuterTOFPion | 1 << kRICHPion | 1 << kTruePiFromXiCC; + + // partitions for Xi daughters + Partition tracksPiFromXiC = + ((aod::a3DecayMap::decayMap & trackSelectionPiFromXiC) == trackSelectionPiFromXiC) && aod::track::signed1Pt > 0.0f && 1.0f / nabs(aod::track::signed1Pt) > minPiCPt&& nabs(aod::track::dcaXY) > piFromXiC_dcaXYconstant + piFromXiC_dcaXYpTdep* nabs(aod::track::signed1Pt) && nabs(aod::track::dcaZ) > piFromXiC_dcaZconstant + piFromXiC_dcaZpTdep* nabs(aod::track::signed1Pt); + + Partition tracksPiFromXiCC = ((aod::a3DecayMap::decayMap & trackSelectionPiFromXiCC) == trackSelectionPiFromXiCC) && aod::track::signed1Pt > 0.0f && 1.0f / nabs(aod::track::signed1Pt) > minPiCCPt&& nabs(aod::track::dcaXY) > piFromXiCC_dcaXYconstant + piFromXiCC_dcaXYpTdep* nabs(aod::track::signed1Pt); + + // Helper struct to pass candidate information + struct { + // decay properties + float dca; + float mass; + float pt; + float eta; + std::array xyz; + std::array prong0mom; + std::array prong1mom; + std::array prong2mom; + std::array parentTrackCovMatrix; + } thisXiCcandidate; + + struct { + float dca; + float mass; + float pt; + float eta; + std::array xyz; + std::array prong0mom; + std::array prong1mom; + std::array parentTrackCovMatrix; + + float etaPiCC; + + // charm daughters + int nSiliconHitsPiCC; + int nTPCHitsPiCC; + } thisXiCCcandidate; + + template + bool buildDecayCandidateTwoBody(TTrackType const& t0, TTrackType const& t1, float mass0, float mass1) + { + //}-{}-{}-{}-{}-{}-{}-{}-{}-{} + // Move close to minima + int nCand = 0; + try { + nCand = fitter.process(t0, t1); + } catch (...) { + return false; + } + if (nCand == 0) { + return false; + } + //}-{}-{}-{}-{}-{}-{}-{}-{}-{} + + o2::track::TrackParCov t0new = fitter.getTrack(0); + o2::track::TrackParCov t1new = fitter.getTrack(1); + t0new.getPxPyPzGlo(thisXiCCcandidate.prong0mom); + t1new.getPxPyPzGlo(thisXiCCcandidate.prong1mom); + + // get decay vertex coordinates + const auto& vtx = fitter.getPCACandidate(); + for (int i = 0; i < 3; i++) { + thisXiCCcandidate.xyz[i] = vtx[i]; + } + + // compute cov mat + for (int ii = 0; ii < 21; ii++) + thisXiCCcandidate.parentTrackCovMatrix[ii] = 0.0f; + + std::array covA = {0}; + std::array covB = {0}; + fitter.getTrack(0).getCovXYZPxPyPzGlo(covA); + fitter.getTrack(1).getCovXYZPxPyPzGlo(covB); + + const int momInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 6; i++) { + int j = momInd[i]; + thisXiCCcandidate.parentTrackCovMatrix[j] = covA[j] + covB[j]; + } + + auto covVtx = fitter.calcPCACovMatrix(); + thisXiCCcandidate.parentTrackCovMatrix[0] = covVtx(0, 0); + thisXiCCcandidate.parentTrackCovMatrix[1] = covVtx(1, 0); + thisXiCCcandidate.parentTrackCovMatrix[2] = covVtx(1, 1); + thisXiCCcandidate.parentTrackCovMatrix[3] = covVtx(2, 0); + thisXiCCcandidate.parentTrackCovMatrix[4] = covVtx(2, 1); + thisXiCCcandidate.parentTrackCovMatrix[5] = covVtx(2, 2); + + // set relevant values + thisXiCCcandidate.dca = TMath::Sqrt(fitter.getChi2AtPCACandidate()); + if (thisXiCCcandidate.dca > dcaXiCCDaughtersSelection) { + return false; + } + + thisXiCCcandidate.mass = RecoDecay::m(array{array{thisXiCCcandidate.prong0mom[0], thisXiCCcandidate.prong0mom[1], thisXiCCcandidate.prong0mom[2]}, array{thisXiCCcandidate.prong1mom[0], thisXiCCcandidate.prong1mom[1], thisXiCCcandidate.prong1mom[2]}}, array{mass0, mass1}); + thisXiCCcandidate.pt = std::hypot(thisXiCCcandidate.prong0mom[0] + thisXiCCcandidate.prong1mom[0], thisXiCCcandidate.prong0mom[1] + thisXiCCcandidate.prong1mom[1]); + thisXiCCcandidate.eta = RecoDecay::eta(array{thisXiCCcandidate.prong0mom[0] + thisXiCCcandidate.prong1mom[0], thisXiCCcandidate.prong0mom[1] + thisXiCCcandidate.prong1mom[1], thisXiCCcandidate.prong0mom[2] + thisXiCCcandidate.prong1mom[2]}); + return true; + } + + template + bool buildDecayCandidateThreeBody(TTrackType1 const& prong0, TTrackType2 const& prong1, TTrackType3 const& prong2, float p0mass, float p1mass, float p2mass) + { + o2::track::TrackParCov t0 = getTrackParCov(prong0); + o2::track::TrackParCov t1 = getTrackParCov(prong1); + o2::track::TrackParCov t2 = getTrackParCov(prong2); + + //}-{}-{}-{}-{}-{}-{}-{}-{}-{} + // Move close to minima + int nCand = 0; + try { + nCand = fitter3.process(t0, t1, t2); + } catch (...) { + return false; + } + if (nCand == 0) { + return false; + } + //}-{}-{}-{}-{}-{}-{}-{}-{}-{} + + t0 = fitter3.getTrack(0); + t1 = fitter3.getTrack(1); + t2 = fitter3.getTrack(2); + t0.getPxPyPzGlo(thisXiCcandidate.prong0mom); + t1.getPxPyPzGlo(thisXiCcandidate.prong1mom); + t2.getPxPyPzGlo(thisXiCcandidate.prong2mom); + + // get decay vertex coordinates + const auto& vtx = fitter3.getPCACandidate(); + for (int i = 0; i < 3; i++) { + thisXiCcandidate.xyz[i] = vtx[i]; + } + + // compute cov mat + for (int ii = 0; ii < 21; ii++) + thisXiCcandidate.parentTrackCovMatrix[ii] = 0.0f; + + std::array covA = {0}; + std::array covB = {0}; + std::array covC = {0}; + fitter3.getTrack(0).getCovXYZPxPyPzGlo(covA); + fitter3.getTrack(1).getCovXYZPxPyPzGlo(covB); + fitter3.getTrack(2).getCovXYZPxPyPzGlo(covC); + + const int momInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 6; i++) { + int j = momInd[i]; + thisXiCcandidate.parentTrackCovMatrix[j] = covA[j] + covB[j] + covC[j]; + } + + auto covVtx = fitter3.calcPCACovMatrix(); + thisXiCcandidate.parentTrackCovMatrix[0] = covVtx(0, 0); + thisXiCcandidate.parentTrackCovMatrix[1] = covVtx(1, 0); + thisXiCcandidate.parentTrackCovMatrix[2] = covVtx(1, 1); + thisXiCcandidate.parentTrackCovMatrix[3] = covVtx(2, 0); + thisXiCcandidate.parentTrackCovMatrix[4] = covVtx(2, 1); + thisXiCcandidate.parentTrackCovMatrix[5] = covVtx(2, 2); + + // set relevant values + thisXiCcandidate.dca = TMath::Sqrt(fitter3.getChi2AtPCACandidate()); + if (thisXiCcandidate.dca > dcaXiCDaughtersSelection) { + return false; + } + thisXiCcandidate.mass = RecoDecay::m(array{array{thisXiCcandidate.prong0mom[0], thisXiCcandidate.prong0mom[1], thisXiCcandidate.prong0mom[2]}, array{thisXiCcandidate.prong1mom[0], thisXiCcandidate.prong1mom[1], thisXiCcandidate.prong1mom[2]}, array{thisXiCcandidate.prong2mom[0], thisXiCcandidate.prong2mom[1], thisXiCcandidate.prong2mom[2]}}, array{p0mass, p1mass, p2mass}); + thisXiCcandidate.pt = std::hypot(thisXiCcandidate.prong0mom[0] + thisXiCcandidate.prong1mom[0] + thisXiCcandidate.prong2mom[0], thisXiCcandidate.prong0mom[1] + thisXiCcandidate.prong1mom[1] + thisXiCcandidate.prong2mom[1]); + thisXiCcandidate.eta = RecoDecay::eta(array{thisXiCcandidate.prong0mom[0] + thisXiCcandidate.prong1mom[0] + thisXiCcandidate.prong2mom[0], thisXiCcandidate.prong0mom[1] + thisXiCcandidate.prong1mom[1] + thisXiCcandidate.prong2mom[1], thisXiCcandidate.prong0mom[2] + thisXiCcandidate.prong1mom[2] + thisXiCcandidate.prong2mom[2]}); + return true; + } + + /// function to check if tracks have the same mother in MC + template + bool checkSameMother(TTrackType1 const& track1, TTrackType2 const& track2) + { + bool returnValue = false; + // Association check + // There might be smarter ways of doing this in the future + if (track1.has_mcParticle() && track2.has_mcParticle()) { + auto mcParticle1 = track1.template mcParticle_as(); + auto mcParticle2 = track2.template mcParticle_as(); + if (mcParticle1.has_mothers() && mcParticle2.has_mothers()) { + for (auto& mcParticleMother1 : mcParticle1.template mothers_as()) { + for (auto& mcParticleMother2 : mcParticle2.template mothers_as()) { + if (mcParticleMother1.globalIndex() == mcParticleMother2.globalIndex()) { + returnValue = true; + } + } + } + } + } // end association check + return returnValue; + } + + // Association check for the XiCC pion + template + bool checkSameMotherExtra(TTrackType1 const& track1, TTrackType2 const& track2) + { + bool returnValue = false; + // This might perhaps be a bit excessive + // Could be joined with `checkSameMother` but leaving as is for now + if (track1.has_mcParticle() && track2.has_mcParticle()) { + auto mcParticle1 = track1.template mcParticle_as(); + auto mcParticle2 = track2.template mcParticle_as(); + if (mcParticle1.has_mothers() && mcParticle2.has_mothers()) { + for (auto& mcParticleMother1 : mcParticle1.template mothers_as()) { + if (mcParticleMother1.has_mothers()) { + for (auto& mcParticleGrandMother1 : mcParticleMother1.template mothers_as()) { + for (auto& mcParticleMother2 : mcParticle2.template mothers_as()) { + if (mcParticleGrandMother1.globalIndex() == mcParticleMother2.globalIndex()) { + returnValue = true; + } + } + } + } + } + } + } // end association check + return returnValue; + } + + void init(InitContext&) + { + // initialize O2 2-prong fitter (only once) + fitter.setPropagateToPCA(true); + fitter.setMaxR(200.); + fitter.setMinParamChange(1e-3); + fitter.setMinRelChi2Change(0.9); + fitter.setMaxDZIni(1e9); + fitter.setMaxChi2(1e9); + fitter.setUseAbsDCA(true); + fitter.setWeightedFinalPCA(false); + fitter.setBz(magneticField); + fitter.setMatCorrType(o2::base::Propagator::MatCorrType::USEMatCorrNONE); + + fitter3.setPropagateToPCA(true); + fitter3.setMaxR(200.); + fitter3.setMinParamChange(1e-3); + fitter3.setMinRelChi2Change(0.9); + fitter3.setMaxDZIni(1e9); + fitter3.setMaxChi2(1e9); + fitter3.setUseAbsDCA(true); + fitter3.setWeightedFinalPCA(false); + fitter3.setBz(magneticField); + fitter3.setMatCorrType(o2::base::Propagator::MatCorrType::USEMatCorrNONE); + + // This histogram bookkeeps the attempts at DCA minimization and their eventual + // failure rates. + // --- 0: attempt XiC, 1: success XiC + // --- 2: attempt XiCC, 3: success XiCC + histos.add("hCharmBuilding", "hCharmBuilding", kTH1D, {{10, -0.5, 9.5f}}); + + histos.add("h2dGenXi", "h2dGenXi", kTH2D, {axisPt, axisEta}); + histos.add("h2dGenXiC", "h2dGenXiC", kTH2D, {axisPt, axisEta}); + histos.add("h2dGenXiCC", "h2dGenXiCC", kTH2D, {axisPt, axisEta}); + + histos.add("hMassXi", "hMassXi", kTH1D, {axisXiMass}); + histos.add("hMassXiC", "hMassXiC", kTH1D, {axisXiCMass}); + histos.add("hMassXiCC", "hMassXiCC", kTH1D, {axisXiCCMass}); + + histos.add("hEtaXiCC", "hEtaXiCC", kTH1D, {axisEta}); + histos.add("hPtXiCC", "hPtXiCC", kTH1D, {axisPt}); + histos.add("h3dMassXiCC", "h3dMassXiCC", kTH3D, {axisPt, axisEta, axisXiCCMass}); + + histos.add("hDCAXiCDaughters", "hDCAXiCDaughters", kTH1D, {axisDCAXiCDaughters}); + histos.add("hDCAXiCCDaughters", "hDCAXiCCDaughters", kTH1D, {axisDCAXiCCDaughters}); + histos.add("hDCAxyXi", "hDCAxyXi", kTH1D, {axisDCA}); + histos.add("hDCAzXi", "hDCAzXi", kTH1D, {axisDCA}); + + histos.add("hDCAxyXiC", "hDCAxyXiC", kTH1D, {axisDCA}); + histos.add("hDCAzXiC", "hDCAzXiC", kTH1D, {axisDCA}); + + histos.add("hDCAxyXiCC", "hDCAxyXiCC", kTH1D, {axisDCA}); + histos.add("hDCAzXiCC", "hDCAzXiCC", kTH1D, {axisDCA}); + + histos.add("hPi1cPt", "hPi1cPt", kTH1D, {axisPt}); + histos.add("hPi2cPt", "hPi2cPt", kTH1D, {axisPt}); + histos.add("hPiccPt", "hPiccPt", kTH1D, {axisPt}); + + histos.add("hMinXiCDecayRadius", "hMinXiCDecayRadius", kTH1D, {axisRadius}); + histos.add("hMinXiCCDecayRadius", "hMinXiCCDecayRadius", kTH1D, {axisRadius}); + + histos.add("hProperLengthXiC", "hProperLengthXiC", kTH1D, {axisDecayLength}); + histos.add("hProperLengthXiCC", "hProperLengthXiCC", kTH1D, {axisDecayLength}); + + // These histograms bookkeep the exact number of combinations attempted + // CombinationsXiC: triplets Xi-pi-pi considered per Xi + // CombinationsXiCC: doublets XiC-pi considered per XiC + histos.add("hCombinationsXiC", "hCombinationsXiC", kTH1D, {axisNConsidered}); + histos.add("hCombinationsXiCC", "hCombinationsXiCC", kTH1D, {axisNConsidered}); + histos.add("hNCollisions", "hNCollisions", kTH1D, {{2, 0.5, 2.5}}); + histos.add("hNTracks", "hNTracks", kTH1D, {{20000, 0, 20000}}); + + if (doDCAplots) { + histos.add("h2dDCAxyVsPtXiFromXiC", "h2dDCAxyVsPtXiFromXiC", kTH2D, {axisPt, axisDCA2d}); + histos.add("h2dDCAxyVsPtPiFromXiC", "h2dDCAxyVsPtPiFromXiC", kTH2D, {axisPt, axisDCA2d}); + histos.add("h2dDCAxyVsPtPiFromXiCC", "h2dDCAxyVsPtPiFromXiCC", kTH2D, {axisPt, axisDCA2d}); + } + } + + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + void processGenerated(aod::McParticles const&) + { + for (auto const& mcParticle : trueXi) + histos.fill(HIST("h2dGenXi"), mcParticle.pt(), mcParticle.eta()); + for (auto const& mcParticle : trueXiC) + histos.fill(HIST("h2dGenXiC"), mcParticle.pt(), mcParticle.eta()); + for (auto const& mcParticle : trueXiCC) { + histos.fill(HIST("h2dGenXiCC"), mcParticle.pt(), mcParticle.eta()); + } + } + + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + void processFindXiCC(aod::Collision const& collision, alice3tracks const& tracks, aod::McParticles const&, aod::UpgradeCascades const& cascades) + { + histos.fill(HIST("hNCollisions"), 1); + histos.fill(HIST("hNTracks"), tracks.size()); + + if (tracks.size() < minNTracks) + return; + + histos.fill(HIST("hNCollisions"), 2); + + // group with this collision + // n.b. cascades do not need to be grouped, being used directly in iterator-grouping + auto tracksPiFromXiCgrouped = tracksPiFromXiC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto tracksPiFromXiCCgrouped = tracksPiFromXiCC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + if (doDCAplots) { + for (auto const& cascade : cascades) { + if (cascade.has_cascadeTrack()) { + auto track = cascade.cascadeTrack_as(); // de-reference cascade track + histos.fill(HIST("h2dDCAxyVsPtXiFromXiC"), track.pt(), track.dcaXY() * 1e+4); + } else { + LOGF(info, "Damn, something is wrong"); + } + } + for (auto const& track : tracks) { + if (bitcheck(track.decayMap(), kTruePiFromXiC)) + histos.fill(HIST("h2dDCAxyVsPtPiFromXiC"), track.pt(), track.dcaXY() * 1e+4); + if (bitcheck(track.decayMap(), kTruePiFromXiCC)) + histos.fill(HIST("h2dDCAxyVsPtPiFromXiCC"), track.pt(), track.dcaXY() * 1e+4); + } + } + + for (auto const& xiCand : cascades) { + histos.fill(HIST("hMassXi"), xiCand.mXi()); + + if (std::fabs(xiCand.mXi() - o2::constants::physics::MassXiMinus) > massWindowXi) + continue; // out of mass region + + uint32_t nCombinationsC = 0; + auto xi = xiCand.cascadeTrack_as(); // de-reference cascade track + auto piFromXi = xiCand.bachTrack_as(); // de-reference bach track + auto piFromLa = xiCand.negTrack_as(); // de-reference neg track + auto prFromLa = xiCand.posTrack_as(); // de-reference pos track + + if (!bitcheck(xi.decayMap(), kTrueXiFromXiC)) + continue; + + if (std::fabs(xi.dcaXY()) < xiFromXiC_dcaXYconstant || std::fabs(xi.dcaZ()) < xiFromXiC_dcaZconstant) + continue; + + for (auto const& pi1c : tracksPiFromXiCgrouped) { + if (mcSameMotherCheck && !checkSameMother(xi, pi1c)) + continue; + if (xiCand.posTrackId() == pi1c.globalIndex() || xiCand.negTrackId() == pi1c.globalIndex() || xiCand.bachTrackId() == pi1c.globalIndex()) + continue; // avoid using any track that was already used + if (pi1c.pt() < minPiCPt) + continue; + + // second pion from XiC decay for starts here + for (auto const& pi2c : tracksPiFromXiCgrouped) { + + if (mcSameMotherCheck && !checkSameMother(xi, pi2c)) + continue; // keep only if same mother + if (pi1c.globalIndex() >= pi2c.globalIndex()) + continue; // avoid same-mother, avoid double-counting + if (xiCand.posTrackId() == pi2c.globalIndex() || xiCand.negTrackId() == pi2c.globalIndex() || xiCand.bachTrackId() == pi2c.globalIndex()) + continue; // avoid using any track that was already used + if (pi2c.pt() < minPiCPt) + continue; + + // if I am here, it means this is a triplet to be considered for XiC vertexing. + // will now attempt to build a three-body decay candidate with these three track rows. + + nCombinationsC++; + histos.fill(HIST("hCharmBuilding"), 0.0f); + if (!buildDecayCandidateThreeBody(xi, pi1c, pi2c, o2::constants::physics::MassXiMinus, o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged)) + continue; // failed at building candidate + + if (std::fabs(thisXiCcandidate.mass - o2::constants::physics::MassXiCPlus) > massWindowXiC) + continue; // out of mass region + histos.fill(HIST("hCharmBuilding"), 1.0f); + + const std::array momentumC = { + thisXiCcandidate.prong0mom[0] + thisXiCcandidate.prong1mom[0] + thisXiCcandidate.prong2mom[0], + thisXiCcandidate.prong0mom[1] + thisXiCcandidate.prong1mom[1] + thisXiCcandidate.prong2mom[1], + thisXiCcandidate.prong0mom[2] + thisXiCcandidate.prong1mom[2] + thisXiCcandidate.prong2mom[2]}; + + o2::track::TrackParCov xicTrack(thisXiCcandidate.xyz, momentumC, thisXiCcandidate.parentTrackCovMatrix, +1); + double xicDecayRadius2D = std::hypot(thisXiCcandidate.xyz[0], thisXiCcandidate.xyz[1]); + if (xicDecayRadius2D < minXiCRadius) + continue; // do not take if radius too small, likely a primary combination + + o2::dataformats::DCA dcaInfo; + float xicdcaXY = 1e+10, xicdcaZ = 1e+10; + ; + o2::track::TrackParCov xicTrackCopy(xicTrack); // paranoia + o2::vertexing::PVertex primaryVertex; + primaryVertex.setXYZ(collision.posX(), collision.posY(), collision.posZ()); + + if (xicTrackCopy.propagateToDCA(primaryVertex, magneticField, &dcaInfo)) { + xicdcaXY = dcaInfo.getY(); + xicdcaZ = dcaInfo.getZ(); + } + + if (std::fabs(xicdcaXY) < xiCFromXiCC_dcaXY || std::fabs(xicdcaZ) < xiCFromXiCC_dcaZ) + continue; + + histos.fill(HIST("hMassXiC"), thisXiCcandidate.mass); + + // attempt XiCC finding + uint32_t nCombinationsCC = 0; + for (auto const& picc : tracksPiFromXiCCgrouped) { + if (mcSameMotherCheck && !checkSameMotherExtra(xi, picc)) + continue; + if (xiCand.posTrackId() == picc.globalIndex() || xiCand.negTrackId() == picc.globalIndex() || xiCand.bachTrackId() == picc.globalIndex()) + continue; // avoid using any track that was already used + if (picc.pt() < minPiCCPt) + continue; + + o2::track::TrackParCov piccTrack = getTrackParCov(picc); + nCombinationsCC++; + histos.fill(HIST("hCharmBuilding"), 2.0f); + if (!buildDecayCandidateTwoBody(xicTrack, piccTrack, o2::constants::physics::MassXiCPlus, o2::constants::physics::MassPionCharged)) + continue; // failed at building candidate + + const std::array momentumCC = { + thisXiCCcandidate.prong0mom[0] + thisXiCCcandidate.prong1mom[0], + thisXiCCcandidate.prong0mom[1] + thisXiCCcandidate.prong1mom[1], + thisXiCCcandidate.prong0mom[2] + thisXiCCcandidate.prong1mom[2]}; + + o2::track::TrackParCov xiccTrack(thisXiCCcandidate.xyz, momentumCC, thisXiCCcandidate.parentTrackCovMatrix, +2); + double xiccDecayRadius2D = std::hypot(thisXiCCcandidate.xyz[0], thisXiCCcandidate.xyz[1]); + if (xiccDecayRadius2D < minXiCCRadius) + continue; // do not take if radius too small, likely a primary combination + + double totalMomentumC = std::hypot(momentumC[0], momentumC[1], momentumC[2]); + double xicProperLength = std::fabs(std::hypot(thisXiCcandidate.xyz[0], thisXiCcandidate.xyz[1], thisXiCcandidate.xyz[2]) - std::hypot(thisXiCCcandidate.xyz[0], thisXiCCcandidate.xyz[1], thisXiCCcandidate.xyz[2]) * totalMomentumC) / (std::fabs(totalMomentumC) * thisXiCcandidate.mass); + if (xicProperLength < xicMinProperLength || xicProperLength > xicMaxProperLength) + continue; + + double totalMomentumCC = std::hypot(momentumCC[0], momentumCC[1], momentumCC[2]); + double xiccProperLength = std::fabs(std::hypot(collision.posX(), collision.posY(), collision.posZ()) - std::hypot(thisXiCCcandidate.xyz[0], thisXiCCcandidate.xyz[1], thisXiCCcandidate.xyz[2]) * totalMomentumCC) / (std::fabs(totalMomentumCC) * thisXiCCcandidate.mass); + if (xiccProperLength < xiccMinProperLength || xiccProperLength > xicMaxProperLength) + continue; + + float xiccdcaXY = 1e+10, xiccdcaZ = 1e+10; + if (xiccTrack.propagateToDCA(primaryVertex, magneticField, &dcaInfo)) { + xiccdcaXY = dcaInfo.getY(); + xiccdcaZ = dcaInfo.getZ(); + } + + if (std::fabs(xiccdcaXY) > xiCC_dcaXY || std::fabs(xiccdcaZ) > xiCC_dcaZ) + continue; + + histos.fill(HIST("hDCAXiCDaughters"), thisXiCcandidate.dca * 1e+4); + histos.fill(HIST("hDCAXiCCDaughters"), thisXiCCcandidate.dca * 1e+4); + histos.fill(HIST("hProperLengthXiCC"), xiccProperLength * 1e+4); + histos.fill(HIST("hProperLengthXiC"), xicProperLength * 1e+4); + histos.fill(HIST("hMinXiCCDecayRadius"), xiccDecayRadius2D * 1e+4); + histos.fill(HIST("hMinXiCDecayRadius"), xicDecayRadius2D * 1e+4); + histos.fill(HIST("hPi2cPt"), pi2c.pt()); + histos.fill(HIST("hPi1cPt"), pi1c.pt()); + histos.fill(HIST("hPiccPt"), picc.pt()); + histos.fill(HIST("hDCAxyXi"), std::fabs(xi.dcaXY() * 1e+4)); + histos.fill(HIST("hDCAzXi"), std::fabs(xi.dcaZ() * 1e+4)); + histos.fill(HIST("hDCAxyXiC"), std::fabs(xicdcaXY * 1e+4)); + histos.fill(HIST("hDCAzXiC"), std::fabs(xicdcaZ * 1e+4)); + histos.fill(HIST("hDCAxyXiCC"), std::fabs(xiccdcaXY * 1e+4)); + histos.fill(HIST("hDCAzXiCC"), std::fabs(xiccdcaZ * 1e+4)); + histos.fill(HIST("hCharmBuilding"), 3.0f); + histos.fill(HIST("hMassXiCC"), thisXiCCcandidate.mass); + histos.fill(HIST("hPtXiCC"), thisXiCCcandidate.pt); + histos.fill(HIST("hEtaXiCC"), thisXiCCcandidate.eta); + histos.fill(HIST("h3dMassXiCC"), thisXiCCcandidate.pt, thisXiCCcandidate.eta, thisXiCCcandidate.mass); + + // produce multi-charm table for posterior analysis + if (fillDerivedTable) { + multiCharmCore( + thisXiCcandidate.dca, thisXiCCcandidate.dca, + thisXiCcandidate.mass, thisXiCCcandidate.mass, + thisXiCCcandidate.pt, thisXiCCcandidate.eta, + xi.nSiliconHits(), piFromXi.nSiliconHits(), + piFromLa.nSiliconHits(), prFromLa.nSiliconHits(), + pi1c.nSiliconHits(), pi2c.nSiliconHits(), picc.nSiliconHits(), + piFromXi.nTPCHits(), piFromLa.nTPCHits(), prFromLa.nTPCHits(), + pi1c.nTPCHits(), pi2c.nTPCHits(), picc.nTPCHits(), + xi.dcaXY(), xicdcaXY, xiccdcaXY, + piFromXi.dcaXY(), piFromLa.dcaXY(), prFromLa.dcaXY(), + pi1c.dcaXY(), pi2c.dcaXY(), picc.dcaXY()); + } + } + histos.fill(HIST("hCombinationsXiCC"), nCombinationsCC); + } + } + histos.fill(HIST("hCombinationsXiC"), nCombinationsC); + } + } + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + + //*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<* + PROCESS_SWITCH(alice3multicharm, processGenerated, "fill MC-only histograms", true); + PROCESS_SWITCH(alice3multicharm, processFindXiCC, "find XiCC baryons", true); + //*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<* +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/ALICE3/TableProducer/alice3-pidTOF.cxx b/ALICE3/TableProducer/alice3-pidTOF.cxx index 4ced165e00a..3e54b1f46dc 100644 --- a/ALICE3/TableProducer/alice3-pidTOF.cxx +++ b/ALICE3/TableProducer/alice3-pidTOF.cxx @@ -123,7 +123,7 @@ struct ALICE3pidTOFTask { if (!track.hasTOF()) { return -999.f; } - return ((track.trackTime() - track.collision().collisionTime()) * 1000.f - o2::pid::tof::ExpTimes::ComputeExpectedTime(track.tofExpMom() / o2::pid::tof::kCSPEED, + return ((track.trackTime() - track.collision().collisionTime()) * 1000.f - o2::pid::tof::ExpTimes::ComputeExpectedTime(track.tofExpMom() * o2::constants::physics::invLightSpeedCm2PS, track.length())) / sigma(track); } @@ -294,7 +294,7 @@ struct ALICE3pidTOFTaskQA { // // histos.fill(HIST("event/tofsignal"), t.p(), t.tofSignal()); histos.fill(HIST("event/tofsignal"), t.p(), tofSignal); - histos.fill(HIST("event/pexp"), t.p(), t.tofExpMom() / o2::pid::tof::kCSPEED); + histos.fill(HIST("event/pexp"), t.p(), t.tofExpMom() * o2::constants::physics::invLightSpeedCm2PS); histos.fill(HIST("event/eta"), t.eta()); histos.fill(HIST("event/length"), t.length()); histos.fill(HIST("event/pt"), t.pt()); diff --git a/ALICE3/Tasks/alice3-cdeuteron.cxx b/ALICE3/Tasks/alice3-cdeuteron.cxx index 3c0288f346e..de6b6738d02 100644 --- a/ALICE3/Tasks/alice3-cdeuteron.cxx +++ b/ALICE3/Tasks/alice3-cdeuteron.cxx @@ -172,15 +172,13 @@ struct Alice3CDeuteron { #undef MakeHistos } - Preslice perMcCollision = aod::mcparticle::mcCollisionId; + Preslice perMcCollision = aod::mcparticle::mcCollisionId; - void process(const soa::Join::iterator& coll, - const o2::aod::McCollisions&, - const soa::Join& tracks, - const aod::McParticles_000& mcParticles) + SliceCache cache; + template + void fillHistograms(const collType& coll, const trackType& tracks, const partType& mcParticles) { - const auto particlesInCollision = mcParticles.sliceBy(perMcCollision, coll.mcCollision().globalIndex()); + const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, coll.mcCollision().globalIndex(), cache); for (const auto& i : particlesInCollision) { histos.get(HIST("event/particlespdg"))->Fill(Form("%i", i.pdgCode()), 1); if (i.pdgCode() != 12345) { @@ -208,14 +206,21 @@ struct Alice3CDeuteron { // } int ntrks = 0; for (const auto& t : tracks) { - if (t.mcParticle_as().pdgCode() == 1000010020) { - histos.fill(HIST("event/trackspdg"), 1); - } else if (t.mcParticle_as().pdgCode() == -321) { - histos.fill(HIST("event/trackspdg"), 2); - } else if (t.mcParticle_as().pdgCode() == 211) { - histos.fill(HIST("event/trackspdg"), 3); - } else { - histos.fill(HIST("event/trackspdg"), 4); + if (!t.has_mcParticle()) { + continue; + } + switch (t.template mcParticle_as().pdgCode()) { + case 1000010020: + histos.fill(HIST("event/trackspdg"), 1); + break; + case -321: + histos.fill(HIST("event/trackspdg"), 2); + break; + case 211: + histos.fill(HIST("event/trackspdg"), 3); + break; + default: + histos.fill(HIST("event/trackspdg"), 4); } ntrks++; } @@ -225,17 +230,25 @@ struct Alice3CDeuteron { std::array dca2{1e10f, 1e10f}; std::array dca3{1e10f, 1e10f}; for (const auto& track1 : tracks) { + if (!track1.has_mcParticle()) { + continue; + } const auto index1 = track1.globalIndex(); int ncand = 0; - histos.fill(HIST("event/nsigmaDe"), track1.pt(), track1.tofNSigmaDe()); + if constexpr (usePID) { + histos.fill(HIST("event/nsigmaDe"), track1.pt(), track1.tofNSigmaDe()); + } if (usePdg) { - if (track1.mcParticle_as().pdgCode() != 1000010020) { + if (track1.template mcParticle_as().pdgCode() != 1000010020) { continue; } - } else if (abs(track1.tofNSigmaDe()) > maxNsigmaDe || track1.sign() < 0.f) { - continue; } - histos.fill(HIST("event/nsigmaDecut"), track1.pt(), track1.tofNSigmaDe()); + if constexpr (usePID) { + if (abs(track1.tofNSigmaDe()) > maxNsigmaDe || track1.sign() < 0.f) { + continue; + } + histos.fill(HIST("event/nsigmaDecut"), track1.pt(), track1.tofNSigmaDe()); + } if (!getTrackPar(track1).propagateParamToDCA(collPos, magField * 10.f, &dca1, 100.)) { continue; @@ -244,25 +257,37 @@ struct Alice3CDeuteron { histos.fill(HIST("event/track1dcaz"), dca1[1]); for (const auto& track2 : tracks) { + if (!track2.has_mcParticle()) { + continue; + } + const auto index2 = track2.globalIndex(); if (index1 == index2) { continue; } - histos.fill(HIST("event/nsigmaKa"), track2.pt(), track2.tofNSigmaKa()); + if constexpr (usePID) { + histos.fill(HIST("event/nsigmaKa"), track2.pt(), track2.tofNSigmaKa()); + } if (usePdg) { - if (track2.mcParticle_as().pdgCode() != -321) { + if (track2.template mcParticle_as().pdgCode() != -321) { continue; } - } else if (abs(track2.tofNSigmaKa()) > maxNsigmaKa || track2.sign() > 0.f) { - continue; } - histos.fill(HIST("event/nsigmaKacut"), track2.pt(), track2.tofNSigmaKa()); + if constexpr (usePID) { + if (abs(track2.tofNSigmaKa()) > maxNsigmaKa || track2.sign() > 0.f) { + continue; + } + histos.fill(HIST("event/nsigmaKacut"), track2.pt(), track2.tofNSigmaKa()); + } if (!getTrackPar(track2).propagateParamToDCA(collPos, magField * 10.f, &dca2, 100.)) { continue; } for (const auto& track3 : tracks) { + if (!track3.has_mcParticle()) { + continue; + } const auto index3 = track3.globalIndex(); if (index2 == index3) { @@ -271,15 +296,20 @@ struct Alice3CDeuteron { if (index1 == index3) { continue; } - histos.fill(HIST("event/nsigmaPi"), track3.pt(), track3.tofNSigmaPi()); + if constexpr (usePID) { + histos.fill(HIST("event/nsigmaPi"), track3.pt(), track3.tofNSigmaPi()); + } if (usePdg) { - if (track3.mcParticle_as().pdgCode() != 211) { + if (track3.template mcParticle_as().pdgCode() != 211) { continue; } - } else if (abs(track3.tofNSigmaPi()) > maxNsigmaPi || track3.sign() < 0.f) { - continue; } - histos.fill(HIST("event/nsigmaPicut"), track3.pt(), track3.tofNSigmaPi()); + if constexpr (usePID) { + if (abs(track3.tofNSigmaPi()) > maxNsigmaPi || track3.sign() < 0.f) { + continue; + } + histos.fill(HIST("event/nsigmaPicut"), track3.pt(), track3.tofNSigmaPi()); + } bool iscut = false; if (abs(dca1[0]) < minDca || abs(dca1[1]) < minDca) { iscut = true; @@ -318,9 +348,9 @@ struct Alice3CDeuteron { iscut = true; } - const auto mother1 = track1.mcParticle_as().mother0_as(); - const auto mother2 = track2.mcParticle_as().mother0_as(); - const auto mother3 = track3.mcParticle_as().mother0_as(); + const auto mother1 = track1.template mcParticle_as().template mothers_as()[0]; + const auto mother2 = track2.template mcParticle_as().template mothers_as()[0]; + const auto mother3 = track3.template mcParticle_as().template mothers_as()[0]; bool issig = true; if (mother1 != mother2) { issig = false; @@ -384,8 +414,8 @@ struct Alice3CDeuteron { const float vz = mother1.vz(); const float rmc = sqrt((secVtx[0] - vx) * (secVtx[0] - vx) + (secVtx[1] - vy) * (secVtx[1] - vy) + (secVtx[2] - vz) * (secVtx[2] - vz)); ncand++; - const float radius3xy = sqrt((track3.mcParticle_as().vx() - coll.mcCollision().posX()) * (track3.mcParticle_as().vx() - coll.mcCollision().posX()) + - (track3.mcParticle_as().vy() - coll.mcCollision().posY()) * (track3.mcParticle_as().vy() - coll.mcCollision().posY())); + const float radius3xy = sqrt((track3.template mcParticle_as().vx() - coll.mcCollision().posX()) * (track3.template mcParticle_as().vx() - coll.mcCollision().posX()) + + (track3.template mcParticle_as().vy() - coll.mcCollision().posY()) * (track3.template mcParticle_as().vy() - coll.mcCollision().posY())); #define FillHistos(tag) \ histos.fill(HIST(tag "/cpa"), CPA); \ @@ -442,6 +472,25 @@ struct Alice3CDeuteron { histos.fill(HIST("event/candperdeuteron"), ncand); } // End loop on deuterons } + + void processWithPid(const soa::Join::iterator& coll, + const o2::aod::McCollisions&, + const soa::Join& tracks, + const aod::McParticles& mcParticles) + { + fillHistograms(coll, tracks, mcParticles); + } + PROCESS_SWITCH(Alice3CDeuteron, processWithPid, "With detector PID info", true); + + void processNoPid(const soa::Join::iterator& coll, + const o2::aod::McCollisions&, + const soa::Join& tracks, + const aod::McParticles& mcParticles) + { + fillHistograms(coll, tracks, mcParticles); + } + PROCESS_SWITCH(Alice3CDeuteron, processNoPid, "With detector PID info", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/ALICE3/Tasks/alice3-qa-singleparticle.cxx b/ALICE3/Tasks/alice3-qa-singleparticle.cxx index 7e3939c61c9..1c8f0f19330 100644 --- a/ALICE3/Tasks/alice3-qa-singleparticle.cxx +++ b/ALICE3/Tasks/alice3-qa-singleparticle.cxx @@ -134,6 +134,8 @@ struct Alice3SingleParticle { histos.add("particle/primariesEta", "Particle Eta (primary) " + tit, kTH1D, {axisEta}); histos.add("particle/secondariesEta", "Particle Eta (secondary) " + tit, kTH1D, {axisEta}); histos.add("particle/Y", "Particle Y " + tit, kTH1D, {axisY}); + histos.add("particle/primariesY", "Particle Y (primary)" + tit, kTH1D, {axisY}); + histos.add("particle/secondariesY", "Particle Y (secondary)" + tit, kTH1D, {axisY}); histos.add("particle/EvsPz", "Particle E vs Pz " + tit, kTH2D, {axisE, axisPz}); histos.add("particle/YvzPz", "Particle Y vs Pz " + tit, kTH2D, {axisY, axisPz}); histos.add("particle/EtavzPz", "Particle Eta vs Pz " + tit, kTH2D, {axisEta, axisPz}); @@ -164,6 +166,16 @@ struct Alice3SingleParticle { histos.add("particle/mothers/prodVz", "Mothers Prod. Vertex Z " + tit, kTH1D, {axisProdz}); histos.add("particle/mothers/prodRadiusVsPt", "Mothers Prod. Vertex Radius " + tit, kTH2D, {axisPt, axisProdRadius}); histos.add("particle/mothers/prodRadius3DVsPt", "Mothers Prod. Vertex Radius XYZ " + tit, kTH2D, {axisPt, axisProdRadius}); + + histos.add("particle/mothers/mothers/PDGs", "Mothers mothers PDGs " + tit, kTH2D, {axisPDGs, axisCharge}); + histos.add("particle/mothers/mothers/PDGsPrimaries", "Mothers mothers PDGs Primaries of " + tit, kTH2D, {axisPDGs, axisCharge}); + histos.add("particle/mothers/mothers/PDGsSecondaries", "Mothers mothers PDGs Secondaries of " + tit, kTH2D, {axisPDGs, axisCharge}); + histos.add("particle/mothers/mothers/prodVx", "Mothers mothers Prod. Vertex X " + tit, kTH1D, {axisProdx}); + histos.add("particle/mothers/mothers/prodVy", "Mothers mothers Prod. Vertex Y " + tit, kTH1D, {axisPrody}); + histos.add("particle/mothers/mothers/prodVz", "Mothers mothers Prod. Vertex Z " + tit, kTH1D, {axisProdz}); + histos.add("particle/mothers/mothers/prodRadiusVsPt", "Mothers mothers Prod. Vertex Radius " + tit, kTH2D, {axisPt, axisProdRadius}); + histos.add("particle/mothers/mothers/prodRadius3DVsPt", "Mothers mothers Prod. Vertex Radius XYZ " + tit, kTH2D, {axisPt, axisProdRadius}); + if (doprocessParticleOnly) { return; } @@ -239,10 +251,12 @@ struct Alice3SingleParticle { histos.fill(HIST("particle/primariesPt"), mcParticle.pt()); histos.fill(HIST("particle/primariesP"), mcParticle.p()); histos.fill(HIST("particle/primariesEta"), mcParticle.eta()); + histos.fill(HIST("particle/primariesY"), mcParticle.y()); } else { histos.fill(HIST("particle/secondariesPt"), mcParticle.pt()); histos.fill(HIST("particle/secondariesP"), mcParticle.p()); histos.fill(HIST("particle/secondariesEta"), mcParticle.eta()); + histos.fill(HIST("particle/secondariesY"), mcParticle.y()); } histos.fill(HIST("particle/EvsPz"), mcParticle.e(), mcParticle.pz()); histos.fill(HIST("particle/Y"), mcParticle.y()); @@ -281,7 +295,7 @@ struct Alice3SingleParticle { } } if (mcParticle.has_mothers()) { - auto mothers = mcParticle.mothers_as(); + const auto& mothers = mcParticle.mothers_as(); for (const auto& mother : mothers) { const auto& pdgStringMot = getPdgCodeString(mother); const auto& pdgChargeMot = getCharge(mother); @@ -298,6 +312,26 @@ struct Alice3SingleParticle { histos.fill(HIST("particle/mothers/prodVz"), mother.vz()); histos.fill(HIST("particle/mothers/prodRadiusVsPt"), mother.pt(), std::sqrt(mother.vx() * mother.vx() + mother.vy() * mother.vy())); histos.fill(HIST("particle/mothers/prodRadius3DVsPt"), mother.pt(), std::sqrt(mother.vx() * mother.vx() + mother.vy() * mother.vy() + mother.vz() * mother.vz())); + if (mother.has_mothers()) { + const auto& mothers2 = mother.mothers_as(); + for (const auto& mother2 : mothers2) { + const auto& pdgStringMot2 = getPdgCodeString(mother2); + const auto& pdgChargeMot2 = getCharge(mother2); + + histos.get(HIST("particle/mothers/mothers/PDGs"))->Fill(pdgStringMot2, pdgChargeMot2, 1.f); + if (mcParticle.isPhysicalPrimary()) { + histos.get(HIST("particle/mothers/mothers/PDGsPrimaries"))->Fill(pdgStringMot2, pdgChargeMot2, 1.f); + } else { + histos.get(HIST("particle/mothers/mothers/PDGsSecondaries"))->Fill(pdgStringMot2, pdgChargeMot2, 1.f); + } + + histos.fill(HIST("particle/mothers/mothers/prodVx"), mother2.vx()); + histos.fill(HIST("particle/mothers/mothers/prodVy"), mother2.vy()); + histos.fill(HIST("particle/mothers/mothers/prodVz"), mother2.vz()); + histos.fill(HIST("particle/mothers/mothers/prodRadiusVsPt"), mother2.pt(), std::sqrt(mother2.vx() * mother2.vx() + mother2.vy() * mother2.vy())); + histos.fill(HIST("particle/mothers/mothers/prodRadius3DVsPt"), mother2.pt(), std::sqrt(mother2.vx() * mother2.vx() + mother2.vy() * mother2.vy() + mother2.vz() * mother2.vz())); + } + } } } @@ -331,7 +365,8 @@ struct Alice3SingleParticle { if (track.hasTOF()) { histos.get(HIST("track/tofPDGs"))->Fill(getPdgCodeString(mcParticle), getCharge(mcParticle), 1.f); } - if (!IsStable) { + if (IsStable.value == 0) { + LOG(info) << mcParticle.pdgCode() << " asked for " << PDG.value; if (!mcParticle.has_mothers()) { continue; } @@ -411,10 +446,12 @@ struct Alice3SingleParticle { histos.fill(HIST("particle/primariesPt"), mcParticle.pt()); histos.fill(HIST("particle/primariesP"), mcParticle.p()); histos.fill(HIST("particle/primariesEta"), mcParticle.eta()); + histos.fill(HIST("particle/primariesY"), mcParticle.y()); } else { histos.fill(HIST("particle/secondariesPt"), mcParticle.pt()); histos.fill(HIST("particle/secondariesP"), mcParticle.p()); histos.fill(HIST("particle/secondariesEta"), mcParticle.eta()); + histos.fill(HIST("particle/secondariesY"), mcParticle.y()); } histos.fill(HIST("particle/EvsPz"), mcParticle.e(), mcParticle.pz()); histos.fill(HIST("particle/Y"), mcParticle.y()); @@ -528,10 +565,12 @@ struct Alice3SingleParticle { histos.fill(HIST("particle/primariesPt"), mcParticle.pt()); histos.fill(HIST("particle/primariesP"), mcParticle.p()); histos.fill(HIST("particle/primariesEta"), mcParticle.eta()); + histos.fill(HIST("particle/primariesY"), mcParticle.y()); } else { histos.fill(HIST("particle/secondariesPt"), mcParticle.pt()); histos.fill(HIST("particle/secondariesP"), mcParticle.p()); histos.fill(HIST("particle/secondariesEta"), mcParticle.eta()); + histos.fill(HIST("particle/secondariesY"), mcParticle.y()); } histos.fill(HIST("particle/EvsPz"), mcParticle.e(), mcParticle.pz()); histos.fill(HIST("particle/Y"), mcParticle.y()); @@ -616,13 +655,12 @@ struct Alice3SingleParticle { if (track.hasTOF()) { histos.get(HIST("track/tofPDGs"))->Fill(getPdgCodeString(mcParticle), getCharge(mcParticle), 1.f); } - if (!IsStable) { + if (IsStable.value == 0) { if (!mcParticle.has_mothers()) { continue; } - // auto mothers = mcParticle.mothers(); - auto mothers = mcParticle.mothers_as(); - const auto ParticleIsInteresting = std::find(ParticlesOfInterest.begin(), ParticlesOfInterest.end(), mothers[0].globalIndex()) != ParticlesOfInterest.end(); + const auto& mothers = mcParticle.mothers_as(); + const auto& ParticleIsInteresting = std::find(ParticlesOfInterest.begin(), ParticlesOfInterest.end(), mothers[0].globalIndex()) != ParticlesOfInterest.end(); if (!ParticleIsInteresting) { continue; } diff --git a/CMakeLists.txt b/CMakeLists.txt index b9b20e4f797..af18a4a16f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,11 +16,13 @@ project(O2Physics LANGUAGES C CXX DESCRIPTION "Physics Analysis for O2") +cmake_policy(SET CMP0144 NEW) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) set_property(GLOBAL PROPERTY REPORT_UNDEFINED_PROPERTIES) cmake_host_system_information(RESULT _totalmem QUERY TOTAL_PHYSICAL_MEMORY) -math(EXPR _total_analysis_jobs "(${_totalmem}-2048)/4096") +math(EXPR _total_analysis_jobs "(${_totalmem}-2048)/2048") if(_total_analysis_jobs LESS_EQUAL 0) set(_total_analysis_jobs 1) endif() diff --git a/CODEOWNERS b/CODEOWNERS index dc6b9054dcc..ecd3c4c9aa7 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -15,42 +15,56 @@ /Common/CCDB @alibuild @jgrosseo @iarsene @ekryshen @ddobrigk /Common/Tools/Multiplicity @alibuild @ddobrigk @victor-gonzalez /ALICE3 @alibuild @njacazio @hscheid -/DPG @alibuild @chiarazampolli @noferini -/DPG/Tasks/AOTEvent @alibuild @ekryshen @strogolo -/DPG/Tasks/AOTTrack @alibuild @mfaggin @belikov @njacazio +/DPG @alibuild @chiarazampolli @alcaliva @catalinristea +/DPG/Tasks/AOTEvent @alibuild @ekryshen @strogolo @altsybee +/DPG/Tasks/AOTTrack @alibuild @mfaggin @iouribelikov @njacazio @lbariogl @f3sch /DPG/Tasks/TOF @alibuild @noferini @njacazio -/DPG/Tasks/FT0 @alibuild @afurs -/EventFiltering @alibuild @mpuccio @strogolo -/EventFiltering/PWGHF @alibuild @fgrosa @zhangbiao-phy @mpuccio @strogolo -/EventFiltering/PWGUD @alibuild @pbuehler @mpuccio @strogolo -/EventFiltering/PWGLF @alibuild @mpuccio @ercolessi @ChiaraDeMartin95 @strogolo -/EventFiltering/PWGCF @alibuild @lauraser @mpuccio @strogolo -/EventFiltering/PWGMM @alibuild @aortizve @mpuccio @strogolo -/EventFiltering/PWGJE @alibuild @fkrizek @nzardosh @mpuccio @strogolo -/PWGCF @alibuild @saganatt @victor-gonzalez @zchochul -/PWGCF/Core @alibuild @jgrosseo @saganatt @victor-gonzalez @zchochul -/PWGCF/DataModel @alibuild @jgrosseo @saganatt @victor-gonzalez @zchochul -/PWGCF/TableProducer @alibuild @jgrosseo @saganatt @victor-gonzalez @zchochul -/PWGCF/Tasks @alibuild @jgrosseo @saganatt @victor-gonzalez @zchochul +/DPG/Tasks/FT0 @alibuild @jotwinow @sahilupadhyaya92 @andreasmolander @afurs +/DPG/Tasks/FV0 @alibuild @jotwinow @sahilupadhyaya92 @andreasmolander @afurs +/DPG/Tasks/FDD @alibuild @jotwinow @sahilupadhyaya92 @andreasmolander @afurs +/EventFiltering @alibuild @mpuccio @lietava +/EventFiltering/PWGHF @alibuild @fgrosa @zhangbiao-phy @mpuccio @lietava +/EventFiltering/PWGUD @alibuild @pbuehler @mpuccio @lietava +/EventFiltering/PWGLF @alibuild @mpuccio @ercolessi @ChiaraDeMartin95 @lietava +/EventFiltering/PWGCF @alibuild @lauraser @mpuccio @lietava +/EventFiltering/PWGMM @alibuild @aortizve @mpuccio @lietava +/EventFiltering/PWGJE @alibuild @fkrizek @nzardosh @mpuccio @lietava +/PWGCF @alibuild @saganatt @victor-gonzalez @zchochul @lgraczykCern @prchakra @lauraser @ariedel-cern @EmilGorm @otonvd @shouqiye @glromane +/PWGCF/Core @alibuild @jgrosseo @saganatt @victor-gonzalez @zchochul @lgraczykCern @prchakra @lauraser @ariedel-cern @EmilGorm @otonvd @shouqiye @glromane +/PWGCF/DataModel @alibuild @jgrosseo @saganatt @victor-gonzalez @zchochul @lgraczykCern @prchakra @lauraser @ariedel-cern @EmilGorm @otonvd @shouqiye @glromane +/PWGCF/TableProducer @alibuild @jgrosseo @saganatt @victor-gonzalez @zchochul @lgraczykCern @prchakra @lauraser @ariedel-cern @EmilGorm @otonvd @shouqiye @glromane +/PWGCF/Tasks @alibuild @jgrosseo @saganatt @victor-gonzalez @zchochul @lgraczykCern @prchakra @lauraser @ariedel-cern @EmilGorm @otonvd @shouqiye @glromane /PWGDQ @alibuild @iarsene @dsekihat @feisenhu @lucamicheletti93 -/PWGEM @alibuild @mikesas @rbailhac @feisenhu +/PWGEM @alibuild @feisenhu @dsekihat @ivorobye /PWGEM/Dilepton @alibuild @mikesas @rbailhac @dsekihat @ivorobye @feisenhu /PWGEM/PhotonMeson @alibuild @mikesas @rbailhac @m-c-danisch @novitzky @mhemmer-cern @dsekihat -/PWGHF @alibuild @vkucera @fcolamar @fgrosa @fcatalan92 @mfaggin @mmazzilli @deepathoms @nzardosh @NicoleBastid @hahassan7 -/PWGLF @alibuild @ercolessi @fmazzasc @chiarapinto @BongHwi @smaff92 @mbombara @ChiaraDeMartin95 @njacazio @skundu692 -/PWGMM @alibuild @aalkin +/PWGHF @alibuild @vkucera @fcolamar @fgrosa @fcatalan92 @mfaggin @mmazzilli @deepathoms @NicoleBastid @hahassan7 @jpxrk @apalasciano @zhangbiao-phy +# PWG-LF +/PWGLF @alibuild @njacazio @skundu692 +/PWGLF/Tasks/GlobalEventProperties @alibuild @njacazio @skundu692 @gbencedi @omvazque +/PWGLF/TableProducer/GlobalEventProperties @alibuild @njacazio @skundu692 @gbencedi @omvazque +/PWGLF/Tasks/Nuspex @alibuild @njacazio @skundu692 @fmazzasc @chiarapinto @maciacco +/PWGLF/TableProducer/Nuspex @alibuild @njacazio @skundu692 @fmazzasc @chiarapinto @maciacco +/PWGLF/Tasks/Resonances @alibuild @njacazio @skundu692 @dmallick2 @smaff92 +/PWGLF/TableProducer/Resonances @alibuild @njacazio @skundu692 @dmallick2 @smaff92 +/PWGLF/Tasks/Strangeness @alibuild @njacazio @skundu692 @ercolessi @ChiaraDeMartin95 +/PWGLF/TableProducer/Strangeness @alibuild @njacazio @skundu692 @ercolessi @ChiaraDeMartin95 + +# PWG-MM +/PWGMM @alibuild @njacazio @skundu692 @aalkin +/PWGMM/Mult @alibuild @njacazio @skundu692 @aalkin @aortizve @ddobrigk @gbencedi /PWGMM/Lumi @alibuild @aalkin -/PWGMM/Mult @alibuild @aalkin @aortizve @ddobrigk -/PWGMM/UE @alibuild @aalkin @aortizve +/PWGMM/UE @alibuild @aalkin @aortizve + /PWGUD @alibuild @pbuehler @abylinkin @rolavick -/PWGJE @alibuild @lhavener @maoyx @nzardosh @ddobrigk @mfasDa +/PWGJE @alibuild @lhavener @maoyx @nzardosh @fjonasALICE @mfasDa @mhemmer-cern /Tools/PIDML @alibuild @saganatt /Tools/ML @alibuild @fcatalan92 @fmazzasc /Tutorials/PWGCF @alibuild @jgrosseo @saganatt @victor-gonzalez @zchochul /Tutorials/PWGDQ @alibuild @iarsene @dsekihat @feisenhu @lucamicheletti93 /Tutorials/PWGEM @alibuild @mikesas @rbailhac @dsekihat @ivorobye @feisenhu /Tutorials/PWGHF @alibuild @vkucera @fcolamar @fgrosa -/Tutorials/PWGJE @alibuild @lhavener @maoyx @nzardosh @ddobrigk @mfasDa +/Tutorials/PWGJE @alibuild @lhavener @maoyx @nzardosh @mfasDa @fjonasALICE /Tutorials/PWGLF @alibuild @alcaliva @lbariogl @chiarapinto @BongHwi @lbarnby @mbombara @iravasen @njacazio @ChiaraDeMartin95 @skundu692 /Tutorials/PWGMM @alibuild @aalkin @ddobrigk /Tutorials/PWGUD @alibuild @pbuehler diff --git a/CPPLINT.cfg b/CPPLINT.cfg index e050d1df67c..7f7d3c357c3 100644 --- a/CPPLINT.cfg +++ b/CPPLINT.cfg @@ -1 +1 @@ -filter=-build/c++11,-build/namespaces,-readability/fn_size,-readability/todo,-runtime/references,-whitespace/blank_line,-whitespace/braces,-whitespace/comments,-whitespace/line_length,-whitespace/semicolon,-whitespace/todo +filter=-build/c++11,-build/namespaces,-readability/fn_size,-readability/todo,-runtime/references,-whitespace/blank_line,-whitespace/braces,-whitespace/comments,-whitespace/indent_namespace,-whitespace/line_length,-whitespace/semicolon,-whitespace/todo diff --git a/Common/CCDB/AnalysisCCDBLinkDef.h b/Common/CCDB/AnalysisCCDBLinkDef.h index e87efaadcbf..bb2da231284 100644 --- a/Common/CCDB/AnalysisCCDBLinkDef.h +++ b/Common/CCDB/AnalysisCCDBLinkDef.h @@ -9,9 +9,20 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file AnalysisCCDBLinkDef.h +/// \brief Dictionary definitions +/// +/// \author Evgeny Kryshen + +#ifndef COMMON_CCDB_ANALYSISCCDBLINKDEF_H_ +#define COMMON_CCDB_ANALYSISCCDBLINKDEF_H_ + #pragma link off all globals; #pragma link off all classes; #pragma link off all functions; #pragma link C++ class EventSelectionParams + ; #pragma link C++ class TriggerAliases + ; +#pragma link C++ class std::map < uint64_t, uint32_t> + ; + +#endif // COMMON_CCDB_ANALYSISCCDBLINKDEF_H_ diff --git a/Common/CCDB/EventSelectionParams.cxx b/Common/CCDB/EventSelectionParams.cxx index 6e7e75d8d3b..74587314240 100644 --- a/Common/CCDB/EventSelectionParams.cxx +++ b/Common/CCDB/EventSelectionParams.cxx @@ -9,6 +9,13 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file EventSelectionParams.cxx +/// \brief Event selection parameters +/// +/// \author Evgeny Kryshen and Igor Altsybeev + +// o2-linter: disable=name/workflow-file + #include "EventSelectionParams.h" namespace o2::aod::evsel @@ -44,7 +51,7 @@ const char* selectionLabels[kNsel] = { "kNoV0C012vsTklBG", "kNoInconsistentVtx", "kNoPileupInMultBins", - "kNoPilupMV", + "kNoPileupMV", "kNoPileupTPC", "kIsTriggerTVX", "kIsINT1", @@ -54,7 +61,16 @@ const char* selectionLabels[kNsel] = { "kIsGoodZvtxFT0vsPV", "kIsVertexITSTPC", "kIsVertexTOFmatched", - "kIsVertexTRDmatched"}; + "kIsVertexTRDmatched", + "kNoCollInTimeRangeNarrow", + "kNoCollInTimeRangeStrict", + "kNoCollInTimeRangeStandard", + "kNoCollInRofStrict", + "kNoCollInRofStandard", + "kNoHighMultCollInPrevRof", + "kIsGoodITSLayer3", + "kIsGoodITSLayer0123", + "kIsGoodITSLayersAll"}; } // namespace o2::aod::evsel using namespace o2::aod::evsel; @@ -159,7 +175,7 @@ EventSelectionParams::EventSelectionParams(int system, int run) } } -void EventSelectionParams::DisableOutOfBunchPileupCuts() +void EventSelectionParams::disableOutOfBunchPileupCuts() { selectionBarrel[kNoV0MOnVsOfPileup] = 0; selectionBarrel[kNoSPDOnVsOfPileup] = 0; @@ -177,7 +193,7 @@ void EventSelectionParams::DisableOutOfBunchPileupCuts() selectionMuonWithoutPileupCuts[kNoV0PFPileup] = 0; } -void EventSelectionParams::SetOnVsOfParams(float newV0MOnVsOfA, float newV0MOnVsOfB, float newSPDOnVsOfA, float newSPDOnVsOfB) +void EventSelectionParams::setOnVsOfParams(float newV0MOnVsOfA, float newV0MOnVsOfB, float newSPDOnVsOfA, float newSPDOnVsOfB) { fV0MOnVsOfA = newV0MOnVsOfA; fV0MOnVsOfB = newV0MOnVsOfB; @@ -185,7 +201,7 @@ void EventSelectionParams::SetOnVsOfParams(float newV0MOnVsOfA, float newV0MOnVs fSPDOnVsOfB = newSPDOnVsOfB; } -bool* EventSelectionParams::GetSelection(int iSelection) +bool* EventSelectionParams::getSelection(int iSelection) { if (iSelection == 0) { return selectionBarrel; diff --git a/Common/CCDB/EventSelectionParams.h b/Common/CCDB/EventSelectionParams.h index af71bebb577..4633ff7aa73 100644 --- a/Common/CCDB/EventSelectionParams.h +++ b/Common/CCDB/EventSelectionParams.h @@ -9,6 +9,11 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file EventSelectionParams.h +/// \brief Event selection parameters +/// +/// \author Evgeny Kryshen and Igor Altsybeev + #ifndef COMMON_CCDB_EVENTSELECTIONPARAMS_H_ #define COMMON_CCDB_EVENTSELECTIONPARAMS_H_ @@ -19,48 +24,57 @@ namespace o2::aod::evsel { // Event selection criteria enum EventSelectionFlags { - kIsBBV0A = 0, // cell-averaged time in V0A in beam-beam window - kIsBBV0C, // cell-averaged time in V0C in beam-beam window (for Run 2 only) - kIsBBFDA, // cell-averaged time in FDA (or AD in Run2) in beam-beam window - kIsBBFDC, // cell-averaged time in FDC (or AD in Run2) in beam-beam window - kIsBBT0A, // cell-averaged time in T0A in beam-beam window - kIsBBT0C, // cell-averaged time in T0C in beam-beam window - kNoBGV0A, // cell-averaged time in V0A in beam-gas window - kNoBGV0C, // cell-averaged time in V0C in beam-gas window (for Run 2 only) - kNoBGFDA, // cell-averaged time in FDA (AD in Run2) in beam-gas window - kNoBGFDC, // cell-averaged time in FDC (AD in Run2) in beam-gas window - kNoBGT0A, // cell-averaged time in T0A in beam-gas window - kNoBGT0C, // cell-averaged time in T0C in beam-gas window - kIsBBZNA, // time in common ZNA channel in beam-beam window - kIsBBZNC, // time in common ZNC channel in beam-beam window - kIsBBZAC, // time in ZNA and ZNC in beam-beam window - circular cut in ZNA-ZNC plane - kNoBGZNA, // time in common ZNA channel is outside of beam-gas window - kNoBGZNC, // time in common ZNC channel is outside of beam-gas window - kNoV0MOnVsOfPileup, // no out-of-bunch pileup according to online-vs-offline VOM correlation - kNoSPDOnVsOfPileup, // no out-of-bunch pileup according to online-vs-offline SPD correlation - kNoV0Casymmetry, // no beam-gas according to correlation of V0C multiplicities in V0C3 and V0C012 - kIsGoodTimeRange, // good time range - kNoIncompleteDAQ, // complete event according to DAQ flags - kNoTPCLaserWarmUp, // no TPC laser warm-up event (used in Run 1) - kNoTPCHVdip, // no TPC HV dip - kNoPileupFromSPD, // no pileup according to SPD vertexer - kNoV0PFPileup, // no out-of-bunch pileup according to V0 past-future info - kNoSPDClsVsTklBG, // no beam-gas according to cluster-vs-tracklet correlation - kNoV0C012vsTklBG, // no beam-gas according to V0C012-vs-tracklet correlation - kNoInconsistentVtx, // no inconsistency in SPD and Track vertices - kNoPileupInMultBins, // no pileup according to multiplicity-differential pileup checks - kNoPileupMV, // no pileup according to multi-vertexer - kNoPileupTPC, // no pileup in TPC - kIsTriggerTVX, // FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level - kIsINT1, // SPDGFO >= 1 || V0A || V0C - kNoITSROFrameBorder, // bunch crossing is far from ITS RO Frame border - kNoTimeFrameBorder, // bunch crossing is far from Time Frame borders - kNoSameBunchPileup, // reject collisions in case of pileup with another collision in the same foundBC - kIsGoodZvtxFT0vsPV, // small difference between z-vertex from PV and from FT0 - kIsVertexITSTPC, // at least one ITS-TPC track (reject vertices built from ITS-only tracks) - kIsVertexTOFmatched, // at least one of vertex contributors is matched to TOF - kIsVertexTRDmatched, // at least one of vertex contributors is matched to TRD - kNsel // counter + kIsBBV0A = 0, // cell-averaged time in V0A in beam-beam window + kIsBBV0C, // cell-averaged time in V0C in beam-beam window (for Run 2 only) + kIsBBFDA, // cell-averaged time in FDA (or AD in Run2) in beam-beam window + kIsBBFDC, // cell-averaged time in FDC (or AD in Run2) in beam-beam window + kIsBBT0A, // cell-averaged time in T0A in beam-beam window + kIsBBT0C, // cell-averaged time in T0C in beam-beam window + kNoBGV0A, // cell-averaged time in V0A in beam-gas window + kNoBGV0C, // cell-averaged time in V0C in beam-gas window (for Run 2 only) + kNoBGFDA, // cell-averaged time in FDA (AD in Run2) in beam-gas window + kNoBGFDC, // cell-averaged time in FDC (AD in Run2) in beam-gas window + kNoBGT0A, // cell-averaged time in T0A in beam-gas window + kNoBGT0C, // cell-averaged time in T0C in beam-gas window + kIsBBZNA, // time in common ZNA channel in beam-beam window + kIsBBZNC, // time in common ZNC channel in beam-beam window + kIsBBZAC, // time in ZNA and ZNC in beam-beam window - circular cut in ZNA-ZNC plane + kNoBGZNA, // time in common ZNA channel is outside of beam-gas window + kNoBGZNC, // time in common ZNC channel is outside of beam-gas window + kNoV0MOnVsOfPileup, // no out-of-bunch pileup according to online-vs-offline VOM correlation + kNoSPDOnVsOfPileup, // no out-of-bunch pileup according to online-vs-offline SPD correlation + kNoV0Casymmetry, // no beam-gas according to correlation of V0C multiplicities in V0C3 and V0C012 + kIsGoodTimeRange, // good time range + kNoIncompleteDAQ, // complete event according to DAQ flags + kNoTPCLaserWarmUp, // no TPC laser warm-up event (used in Run 1) + kNoTPCHVdip, // no TPC HV dip + kNoPileupFromSPD, // no pileup according to SPD vertexer + kNoV0PFPileup, // no out-of-bunch pileup according to V0 past-future info + kNoSPDClsVsTklBG, // no beam-gas according to cluster-vs-tracklet correlation + kNoV0C012vsTklBG, // no beam-gas according to V0C012-vs-tracklet correlation + kNoInconsistentVtx, // no inconsistency in SPD and Track vertices + kNoPileupInMultBins, // no pileup according to multiplicity-differential pileup checks + kNoPileupMV, // no pileup according to multi-vertexer + kNoPileupTPC, // no pileup in TPC + kIsTriggerTVX, // FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level + kIsINT1, // SPDGFO >= 1 || V0A || V0C + kNoITSROFrameBorder, // bunch crossing is far from ITS RO Frame border + kNoTimeFrameBorder, // bunch crossing is far from Time Frame borders + kNoSameBunchPileup, // reject collisions in case of pileup with another collision in the same foundBC + kIsGoodZvtxFT0vsPV, // small difference between z-vertex from PV and from FT0 + kIsVertexITSTPC, // at least one ITS-TPC track (reject vertices built from ITS-only tracks) + kIsVertexTOFmatched, // at least one of vertex contributors is matched to TOF + kIsVertexTRDmatched, // at least one of vertex contributors is matched to TRD + kNoCollInTimeRangeNarrow, // no other collisions in specified time range (narrower than Strict) + kNoCollInTimeRangeStrict, // no other collisions in specified time range + kNoCollInTimeRangeStandard, // no other collisions in specified time range with per-collision multiplicity above threshold + kNoCollInRofStrict, // no other collisions in this Readout Frame + kNoCollInRofStandard, // no other collisions in this Readout Frame with per-collision multiplicity above threshold + kNoHighMultCollInPrevRof, // veto an event if FT0C amplitude in previous ITS ROF is above threshold + kIsGoodITSLayer3, // number of inactive chips on ITS layer 3 is below maximum allowed value + kIsGoodITSLayer0123, // numbers of inactive chips on ITS layers 0-3 are below maximum allowed values + kIsGoodITSLayersAll, // numbers of inactive chips on all ITS layers are below maximum allowed values + kNsel // counter }; extern const char* selectionLabels[kNsel]; @@ -70,10 +84,10 @@ extern const char* selectionLabels[kNsel]; class EventSelectionParams { public: - explicit EventSelectionParams(int system = 0, int run = 2); - void DisableOutOfBunchPileupCuts(); - void SetOnVsOfParams(float newV0MOnVsOfA, float newV0MOnVsOfB, float newSPDOnVsOfA, float newSPDOnVsOfB); - bool* GetSelection(int iSelection); + explicit EventSelectionParams(int system = 0, int run = 2); // o2-linter: disable=name/function-variable + void disableOutOfBunchPileupCuts(); + void setOnVsOfParams(float newV0MOnVsOfA, float newV0MOnVsOfB, float newSPDOnVsOfA, float newSPDOnVsOfB); + bool* getSelection(int iSelection); bool selectionBarrel[o2::aod::evsel::kNsel]; bool selectionMuonWithPileupCuts[o2::aod::evsel::kNsel]; @@ -147,7 +161,7 @@ class EventSelectionParams int fITSROFrameStartBorderMargin = 10; // number of bcs to cut in the beginning of ITS readout frame int fITSROFrameEndBorderMargin = 20; // number of bcs to cut in the end of ITS readout frame - ClassDefNV(EventSelectionParams, 5) + ClassDefNV(EventSelectionParams, 7) }; #endif // COMMON_CCDB_EVENTSELECTIONPARAMS_H_ diff --git a/Common/CCDB/RCTSelectionFlags.h b/Common/CCDB/RCTSelectionFlags.h new file mode 100644 index 00000000000..1f396751c25 --- /dev/null +++ b/Common/CCDB/RCTSelectionFlags.h @@ -0,0 +1,211 @@ +// 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 RCTSelectionFlags.h +/// \brief RCT selection flags +/// +/// \author Andrea Ferrero and Evgeny Kryshen + +#ifndef COMMON_CCDB_RCTSELECTIONFLAGS_H_ +#define COMMON_CCDB_RCTSELECTIONFLAGS_H_ + +#include +#include +#include + +#include +#include +#include +#include + +namespace o2::aod::rctsel +{ +/* + * Bit mapping used for populating the CCDB objects from the RCT flags + * From https://github.com/JianLIUhep/RCTutils/blob/main/CCDB/process_and_upload.C +std::map> detailedBitMapping = { + {"CPV", { {"Bad", 0}, {"Invalid", 0} }}, + {"EMC", { {"Bad", 1}, {"NoDetectorData", 1}, {"BadEMCalorimetry", 1}, {"LimitedAcceptanceMCReproducible", 2} }}, + {"FDD", { {"Bad", 3}, {"Invalid", 3}, {"NoDetectorData", 3} }}, + {"FT0", { {"Bad", 4}, {"UnknownQuality", 4}, {"Unknown", 4} }}, + {"FV0", { {"Bad", 5} }}, + {"HMP", { {"Bad", 6}, {"NoDetectorData", 6} }}, + {"ITS", { {"Bad", 7}, {"UnknownQuality", 7}, {"BadTracking", 7}, {"LimitedAcceptanceMCReproducible", 8} }}, + {"MCH", { {"Bad", 9}, {"NoDetectorData", 9}, {"Unknown", 9}, {"LimitedAcceptanceMCReproducible", 10} }}, + {"MFT", { {"Bad", 11}, {"BadTracking", 11}, {"LimitedAcceptanceMCReproducible", 12} }}, + {"MID", { {"Bad", 13}, {"BadTracking", 13}, {"LimitedAcceptanceMCReproducible", 14} }}, + {"PHS", { {"Bad", 15}, {"Invalid", 15} }}, + {"TOF", { {"Bad", 16}, {"NoDetectorData", 16}, {"BadPID", 16}, {"LimitedAcceptanceMCReproducible", 17} }}, + {"TPC", { {"Bad", 18}, {"BadTracking", 18}, {"BadPID", 19}, {"LimitedAcceptanceMCNotReproducible", 18}, {"LimitedAcceptanceMCReproducible", 20} }}, + {"TRD", { {"Bad", 21}, {"BadTracking", 21} }}, + {"ZDC", { {"Bad", 22}, {"UnknownQuality", 22}, {"Unknown", 22}, {"NoDetectorData", 22} }} +}; +*/ + +// RCT selection flags +enum RCTSelectionFlags { + kCPVBad = 0, + kEMCBad, + kEMCLimAccMCRepr, + kFDDBad, + kFT0Bad, + kFV0Bad, + kHMPBad, + kITSBad, + kITSLimAccMCRepr, + kMCHBad, + kMCHLimAccMCRepr, + kMFTBad, + kMFTLimAccMCRepr, + kMIDBad, + kMIDLimAccMCRepr, + kPHSBad, + kTOFBad, + kTOFLimAccMCRepr, + kTPCBadTracking, + kTPCBadPID, + kTPCLimAccMCRepr, + kTRDBad, + kZDCBad, + kNRCTSelectionFlags +}; + +template +concept HasRCTFlags = requires(T a, int bit) { + { a.rct_bit(bit) } -> std::convertible_to; + { a.rct_raw() } -> std::convertible_to; +}; + +class RCTFlagsChecker : public o2::utils::EnumFlags +{ + public: + RCTFlagsChecker() = default; + + // Construct the object from an initializer list, like this: + // RCTFlagsChecker qualityFlagsChecker{ kFT0Bad, kITSBad, kMFTBad, kMFTLimAccMCRepr }; + using o2::utils::EnumFlags::EnumFlags; + + // Construct the object from one of the pre-defined runlist selections. + // The label parameter can take the following values: + // - "CBT" + // - "CBT_hadronPID" + // - "CBT_electronPID" + // - "CCBT_calo" + // - "CBT_muon" + // - "CBT_muon_glo" + // The checkZDC boolean flag controls whether to iclude the ZDC quality in all the pre-defined selections (for Pb-Pb data) + // The treatLimitedAcceptanceAsBad boolean flag controls whether "LimitedAcceptanceMCReproducible" flags should be + // treated as Bad and the corresponding events excluded + explicit RCTFlagsChecker(const std::string& label, bool checkZDC = false, bool treatLimitedAcceptanceAsBad = false) + { + init(label, checkZDC, treatLimitedAcceptanceAsBad); + } + + // Initialize the object from an initializer list of RCTSelectionFlags values + void init(std::initializer_list flags) + { + reset(); + *this = RCTFlagsChecker(flags); + } + + // Initialize the object from one of the pre-defined runlist selections. + // The label parameter can take the following values: + // - "CBT" + // - "CBT_hadronPID" + // - "CBT_electronPID" + // - "CCBT_calo" + // - "CBT_muon" + // - "CBT_muon_glo" + // The checkZDC boolean flag controls whether to iclude the ZDC quality in all the pre-defined selections (for Pb-Pb data) + // The treatLimitedAcceptanceAsBad boolean flag controls whether "LimitedAcceptanceMCReproducible" flags should be + // treated as Bad and the corresponding events excluded + void init(const std::string& label, bool checkZDC = false, bool treatLimitedAcceptanceAsBad = false) + { + auto setFlags = [this](std::initializer_list flags) { + std::for_each(flags.begin(), + flags.end(), + [this](const RCTSelectionFlags f) noexcept { set(f); }); + }; + + reset(); + + if (label == "CBT") { + setFlags({kFT0Bad, kITSBad, kTPCBadTracking, kTPCBadPID}); + if (treatLimitedAcceptanceAsBad) { + setFlags({kITSLimAccMCRepr, kTPCLimAccMCRepr}); + } + } + + if (label == "CBT_hadronPID") { + setFlags({kFT0Bad, kITSBad, kTPCBadTracking, kTPCBadPID, kTOFBad}); + if (treatLimitedAcceptanceAsBad) { + setFlags({kITSLimAccMCRepr, kTPCLimAccMCRepr, kTOFLimAccMCRepr}); + } + } + + if (label == "CBT_electronPID") { + setFlags({kFT0Bad, kITSBad, kTPCBadTracking, kTPCBadPID, kTRDBad}); + if (treatLimitedAcceptanceAsBad) { + setFlags({kITSLimAccMCRepr, kTPCLimAccMCRepr}); + } + } + + if (label == "CBT_calo") { + setFlags({kFT0Bad, kITSBad, kTPCBadTracking, kTPCBadPID, kEMCBad}); + if (treatLimitedAcceptanceAsBad) { + setFlags({kITSLimAccMCRepr, kTPCLimAccMCRepr, kEMCLimAccMCRepr}); + } + } + + if (label == "CBT_muon") { + setFlags({kFT0Bad, kITSBad, kTPCBadTracking, kMCHBad, kMIDBad}); + if (treatLimitedAcceptanceAsBad) { + setFlags({kITSLimAccMCRepr, kTPCLimAccMCRepr, kMCHLimAccMCRepr, kMIDLimAccMCRepr}); + } + } + + if (label == "CBT_muon_glo") { + setFlags({kFT0Bad, kITSBad, kTPCBadTracking, kMCHBad, kMIDBad, kMFTBad}); + if (treatLimitedAcceptanceAsBad) { + setFlags({kITSLimAccMCRepr, kTPCLimAccMCRepr, kMCHLimAccMCRepr, kMIDLimAccMCRepr, kMFTLimAccMCRepr}); + } + } + + if (checkZDC) { + set(kZDCBad); + } + } + + // Check the RCT column of a given event selection table. + // The function returns true if none of the checked flags is set in the RCT column. + bool checkTable(const HasRCTFlags auto& table) + { + if (!any()) { + throw std::out_of_range("RCTFlagsCheckerAlt with empty RCTSelectionFlags bits mask"); + } + + // bitmask of the current table + uint64_t tableBits = table.rct_raw(); + // bitmask of flags to be checked + uint64_t flagsBits = value(); + + // return true if none of the checked bits is set in the table bitmask + return ((tableBits & flagsBits) == 0); + } + + bool operator()(const HasRCTFlags auto& table) + { + return checkTable(table); + } +}; + +} // namespace o2::aod::rctsel +#endif // COMMON_CCDB_RCTSELECTIONFLAGS_H_ diff --git a/Common/CCDB/ctpRateFetcher.cxx b/Common/CCDB/ctpRateFetcher.cxx index 83f03f8b7ab..e20fc41616c 100644 --- a/Common/CCDB/ctpRateFetcher.cxx +++ b/Common/CCDB/ctpRateFetcher.cxx @@ -22,7 +22,7 @@ namespace o2 { -double ctpRateFetcher::fetch(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStamp, int runNumber, std::string sourceName) +double ctpRateFetcher::fetch(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStamp, int runNumber, std::string sourceName, bool fCrashOnNull) { setupRun(runNumber, ccdb, timeStamp); if (sourceName.find("ZNC") != std::string::npos) { @@ -32,14 +32,22 @@ double ctpRateFetcher::fetch(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStam return fetchCTPratesClasses(ccdb, timeStamp, runNumber, "C1ZNC-B-NOPF-CRU", 6) / (sourceName.find("hadronic") != std::string::npos ? 28. : 1.); } } else if (sourceName == "T0CE") { - return fetchCTPratesClasses(ccdb, timeStamp, runNumber, "CMTVXTCE-B-NOPF-CRU"); + return fetchCTPratesClasses(ccdb, timeStamp, runNumber, "CMTVXTCE-B-NOPF"); } else if (sourceName == "T0SC") { - return fetchCTPratesClasses(ccdb, timeStamp, runNumber, "CMTVXTSC-B-NOPF-CRU"); + return fetchCTPratesClasses(ccdb, timeStamp, runNumber, "CMTVXTSC-B-NOPF"); } else if (sourceName == "T0VTX") { if (runNumber < 534202) { - return fetchCTPratesClasses(ccdb, timeStamp, runNumber, "minbias_TVX_L0"); // 2022 + return fetchCTPratesClasses(ccdb, timeStamp, runNumber, "minbias_TVX_L0", 3); // 2022 } else { - return fetchCTPratesClasses(ccdb, timeStamp, runNumber, "CMTVX-B-NOPF"); + double_t ret = fetchCTPratesClasses(ccdb, timeStamp, runNumber, "CMTVX-B-NOPF"); + if (ret < 0.) { + LOG(info) << "Trying different class"; + ret = fetchCTPratesClasses(ccdb, timeStamp, runNumber, "CMTVX-NONE"); + if ((ret < 0) && fCrashOnNull) { + LOG(fatal) << "None of the classes used for lumi found"; + } + } + return ret; } } LOG(error) << "CTP rate for " << sourceName << " not available"; @@ -52,17 +60,16 @@ double ctpRateFetcher::fetchCTPratesClasses(o2::ccdb::BasicCCDBManager* /*ccdb*/ std::vector clslist = mConfig->getTriggerClassList(); int classIndex = -1; for (size_t i = 0; i < clslist.size(); i++) { - if (ctpcls[i].name == className) { + if (ctpcls[i].name.find(className) != std::string::npos) { classIndex = i; break; } } if (classIndex == -1) { - LOG(fatal) << "Trigger class " << className << " not found in CTPConfiguration"; + LOG(warn) << "Trigger class " << className << " not found in CTPConfiguration"; + return -1.; } - auto rate{mScalers->getRateGivenT(timeStamp * 1.e-3, classIndex, inputType)}; - return pileUpCorrection(rate.second); } @@ -79,6 +86,9 @@ double ctpRateFetcher::fetchCTPratesInputs(o2::ccdb::BasicCCDBManager* /*ccdb*/, double ctpRateFetcher::pileUpCorrection(double triggerRate) { + if (mLHCIFdata == nullptr) { + LOG(fatal) << "No filling" << std::endl; + } auto bfilling = mLHCIFdata->getBunchFilling(); std::vector bcs = bfilling.getFilledBCs(); double nbc = bcs.size(); diff --git a/Common/CCDB/ctpRateFetcher.h b/Common/CCDB/ctpRateFetcher.h index 412c1e7a424..6aaf5e3ebaa 100644 --- a/Common/CCDB/ctpRateFetcher.h +++ b/Common/CCDB/ctpRateFetcher.h @@ -34,7 +34,7 @@ class ctpRateFetcher { public: ctpRateFetcher() = default; - double fetch(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStamp, int runNumber, std::string sourceName); + double fetch(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStamp, int runNumber, std::string sourceName, bool fCrashOnNull = true); void setManualCleanup(bool manualCleanup = true) { mManualCleanup = manualCleanup; } diff --git a/Common/CCDB/macros/ctpRateF.C b/Common/CCDB/macros/ctpRateF.C index 9f27007c761..32b93e4aa6b 100644 --- a/Common/CCDB/macros/ctpRateF.C +++ b/Common/CCDB/macros/ctpRateF.C @@ -37,6 +37,9 @@ struct ctpRateFetcher { double ctpRateFetcher::pileUpCorrection(double triggerRate) { + if (mLHCIFdata == nullptr) { + LOG(fatal) << "No filling" << std::endl; + } auto bfilling = mLHCIFdata->getBunchFilling(); std::vector bcs = bfilling.getFilledBCs(); double nbc = bcs.size(); @@ -97,22 +100,21 @@ double ctpRateFetcher::fetchCTPratesClasses(o2::ccdb::BasicCCDBManager* ccdb, ui { getCTPscalers(ccdb, timeStamp, runNumber); getCTPconfig(ccdb, timeStamp, runNumber); - std::vector ctpcls = mConfig->getCTPClasses(); std::vector clslist = mConfig->getTriggerClassList(); int classIndex = -1; for (size_t i = 0; i < clslist.size(); i++) { - if (ctpcls[i].name == className) { + if (ctpcls[i].name.find(className) != std::string::npos) { classIndex = i; break; } } if (classIndex == -1) { - LOG(fatal) << "Trigger class " << className << " not found in CTPConfiguration"; + LOG(warn) << "Trigger class " << className << " not found in CTPConfiguration"; + return -1; } - auto rate{mScalers->getRateGivenT(timeStamp * 1.e-3, classIndex, inputType)}; - + getLHCIFdata(ccdb, timeStamp, runNumber); return pileUpCorrection(rate.second); } double ctpRateFetcher::fetch(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStamp, int runNumber, std::string sourceName) @@ -124,26 +126,40 @@ double ctpRateFetcher::fetch(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStam return fetchCTPratesClasses(ccdb, timeStamp, runNumber, "C1ZNC-B-NOPF-CRU", 6) / (sourceName.find("hadronic") != std::string::npos ? 28. : 1.); } } else if (sourceName == "T0CE") { - return fetchCTPratesClasses(ccdb, timeStamp, runNumber, "CMTVXTCE-B-NOPF-CRU"); + return fetchCTPratesClasses(ccdb, timeStamp, runNumber, "CMTVXTCE-B-NOPF"); } else if (sourceName == "T0SC") { - return fetchCTPratesClasses(ccdb, timeStamp, runNumber, "CMTVXTSC-B-NOPF-CRU"); + return fetchCTPratesClasses(ccdb, timeStamp, runNumber, "CMTVXTSC-B-NOPF"); } else if (sourceName == "T0VTX") { if (runNumber < 534202) { - return fetchCTPratesClasses(ccdb, timeStamp, runNumber, "minbias_TVX_L0"); // 2022 + return fetchCTPratesClasses(ccdb, timeStamp, runNumber, "minbias_TVX_L0", 3); // 2022 } else { - return fetchCTPratesClasses(ccdb, timeStamp, runNumber, "CMTVX-B-NOPF-CRU"); + double_t ret = fetchCTPratesClasses(ccdb, timeStamp, runNumber, "CMTVX-B-NOPF"); + if (ret < 0.) { + LOG(info) << "Trying different class"; + ret = fetchCTPratesClasses(ccdb, timeStamp, runNumber, "CMTVX-NONE"); + if (ret < 0) { + LOG(fatal) << "None of the classes used for lumi found"; + } + } + return ret; } } LOG(error) << "CTP rate for " << sourceName << " not available"; return -1.; } -void ctpRateF(int runNumber = 0) +void ctpRateF(int runNumber = 0, bool cxx = 1) { auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance(); auto soreor = ccdbMgr.getRunDuration(runNumber); uint64_t timeStamp = (soreor.second - soreor.first) / 2 + soreor.first; std::cout << "Timestamp:" << timeStamp << std::endl; - ctpRateFetcher ctprate; - auto rate = ctprate.fetch(&ccdbMgr, timeStamp + 100, runNumber, "ZNChadronic"); - std::cout << "Rate:" << rate << std::endl; + if (cxx) { + o2::ctpRateFetcher ctprate; + auto rate = ctprate.fetch(&ccdbMgr, timeStamp + 100, runNumber, "T0VTX"); + std::cout << "Rate:" << rate << std::endl; + } else { + ctpRateFetcher ctprate; + auto rate = ctprate.fetch(&ccdbMgr, timeStamp + 100, runNumber, "T0VTX"); + std::cout << "Rate:" << rate << std::endl; + } } diff --git a/Common/CCDB/macros/upload_event_selection_params.C b/Common/CCDB/macros/upload_event_selection_params.C index aef73e3fa11..5d63cf49be8 100644 --- a/Common/CCDB/macros/upload_event_selection_params.C +++ b/Common/CCDB/macros/upload_event_selection_params.C @@ -10,6 +10,7 @@ // or submit itself to any jurisdiction. #include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" #include "TString.h" #include "map" #include "string" @@ -238,17 +239,16 @@ void upload_event_selection_params() runLast[n] = 297624; n++; - map metadata, metadataRCT, headersFirst, headersLast; + map metadata; for (int i = 0; i < n; i++) { printf("%s ", period[i].c_str()); if (!isNew[i]) { printf(" .... is not new, skipping\n"); continue; } - headersFirst = ccdb.retrieveHeaders(Form("RCT/Info/RunInformation/%i", runFirst[i]), metadataRCT, -1); - headersLast = ccdb.retrieveHeaders(Form("RCT/Info/RunInformation/%i", runLast[i]), metadataRCT, -1); - ULong64_t sor = atol(headersFirst["SOR"].c_str()); - ULong64_t eor = atol(headersLast["EOR"].c_str()); + auto sor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdb, runFirst[i]).first; + auto eor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdb, runLast[i]).second; + printf("sor=%llu eor=%llu\n", sor, eor); metadata["period"] = period[i]; metadata["run_first"] = Form("%d", runFirst[i]); diff --git a/Common/CCDB/macros/upload_trigger_aliases.C b/Common/CCDB/macros/upload_trigger_aliases.C index ac323fd403f..9fa91cd9b13 100644 --- a/Common/CCDB/macros/upload_trigger_aliases.C +++ b/Common/CCDB/macros/upload_trigger_aliases.C @@ -10,6 +10,7 @@ // or submit itself to any jurisdiction. #include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" #include "TObjArray.h" #include "TriggerAliases.h" #include "TTree.h" @@ -62,7 +63,7 @@ void upload_trigger_aliases() // ccdb.init("http://ccdb-test.cern.ch:8080"); // ccdb.truncate("EventSelection/TriggerAliases"); - map metadata, metadataRCT, header; + map metadata; // read list of runs from text file std::ifstream f("runs_run1.txt"); @@ -92,10 +93,11 @@ void upload_trigger_aliases() } } - // read SOR and EOR timestamps from RCT CCDB - header = ccdb.retrieveHeaders(Form("RCT/Info/RunInformation/%i", run), metadataRCT, -1); - ULong64_t sor = atol(header["SOR"].c_str()); - ULong64_t eor = atol(header["EOR"].c_str()); + // read SOR and EOR timestamps from RCT CCDB (via utility function) + auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdb, run); + ULong64_t sor = soreor.first; + ULong64_t eor = soreor.second; + // add safety margins to avoid edge effects due to SOR/EOR time differences in DCS and CTP sor -= 60000; eor += 300000; diff --git a/Common/CCDB/macros/upload_trigger_aliases_run3.C b/Common/CCDB/macros/upload_trigger_aliases_run3.C index 59048d2ce41..e946d9117d4 100644 --- a/Common/CCDB/macros/upload_trigger_aliases_run3.C +++ b/Common/CCDB/macros/upload_trigger_aliases_run3.C @@ -11,6 +11,7 @@ #include "DataFormatsCTP/Configuration.h" #include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" #include "TObjArray.h" #include "TriggerAliases.h" #include "TTree.h" @@ -45,8 +46,8 @@ void createPbPbAliases(map& mAliases) void upload_trigger_aliases_run3() { map mAliases; - // createDefaultAliases(mAliases); - createPbPbAliases(mAliases); + createDefaultAliases(mAliases); + // createPbPbAliases(mAliases); TObjArray* classNames[kNaliases]; for (auto& al : mAliases) { @@ -58,10 +59,10 @@ void upload_trigger_aliases_run3() // ccdb.init("http://ccdb-test.cern.ch:8080"); // ccdb.truncate("EventSelection/TriggerAliases"); - map metadata, metadataRCT, header; + map metadata; // read list of runs from text file - std::ifstream f("run3_pbpb2023.txt"); + std::ifstream f("runs.txt"); std::vector runs; int r = 0; while (f >> r) { @@ -93,11 +94,13 @@ void upload_trigger_aliases_run3() continue; // no CTP info if (run == 528543) continue; // no CTP info - // read SOR and EOR timestamps from RCT CCDB - header = ccdb.retrieveHeaders(Form("RCT/Info/RunInformation/%i", run), metadataRCT, -1); - ULong64_t sor = atol(header["SOR"].c_str()); - ULong64_t eor = atol(header["EOR"].c_str()); - ULong64_t ts = sor; + + // read SOR and EOR timestamps from RCT CCDB via utility function + auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdb, run); + auto eor = soreor.second; + auto sor = soreor.first; + auto ts = sor; + // read CTP config metadata["runNumber"] = Form("%d", run); auto ctpcfg = ccdb.retrieveFromTFileAny("CTP/Config/Config", metadata, ts); @@ -114,7 +117,7 @@ void upload_trigger_aliases_run3() TriggerAliases* aliases = new TriggerAliases(); for (auto& al : mAliases) { int aliasId = al.first; - LOGP(debug, "alias = {}", al.second); + LOGP(debug, "alias = {}", al.second.Data()); for (const auto& className : *(classNames[aliasId])) { TString sname = className->GetName(); LOGP(debug, " className = {}", sname.Data()); @@ -147,6 +150,6 @@ void upload_trigger_aliases_run3() } } aliases->Print(); - ccdb.storeAsTFileAny(aliases, "EventSelection/TriggerAliases", metadata, sor, eor + 10000); // adding tolerance of 10s to eor + ccdb.storeAsTFileAny(aliases, "EventSelection/TriggerAliases", metadata, sor - 1000, eor + 10000); // adding tolerance of 10s to eor } } diff --git a/Common/CMakeLists.txt b/Common/CMakeLists.txt index b81500cb1c9..f9458f6f409 100644 --- a/Common/CMakeLists.txt +++ b/Common/CMakeLists.txt @@ -15,3 +15,4 @@ add_subdirectory(CCDB) add_subdirectory(Tasks) add_subdirectory(TableProducer) add_subdirectory(Tools) +add_subdirectory(LegacyDataQA) diff --git a/Common/Core/AnalysisCoreLinkDef.h b/Common/Core/AnalysisCoreLinkDef.h index b376ccc7f10..ae4c91e9589 100644 --- a/Common/Core/AnalysisCoreLinkDef.h +++ b/Common/Core/AnalysisCoreLinkDef.h @@ -26,4 +26,6 @@ #pragma link C++ class OrbitRange + ; +#pragma link C++ class FFitWeights + ; + #endif // COMMON_CORE_ANALYSISCORELINKDEF_H_ diff --git a/Common/Core/CMakeLists.txt b/Common/Core/CMakeLists.txt index c826687e669..a5a771a2ca3 100644 --- a/Common/Core/CMakeLists.txt +++ b/Common/Core/CMakeLists.txt @@ -10,23 +10,34 @@ # or submit itself to any jurisdiction. o2physics_add_library(AnalysisCore - SOURCES TrackSelection.cxx - OrbitRange.cxx - PID/ParamBase.cxx - CollisionAssociation.cxx - TrackSelectionDefaults.cxx - EventPlaneHelper.cxx - TableHelper.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsParameters ROOT::EG O2::CCDB ROOT::Physics O2::FT0Base O2::FV0Base) + SOURCES TrackSelection.cxx + OrbitRange.cxx + PID/ParamBase.cxx + PID/PIDTOF.cxx + CollisionAssociation.cxx + TrackSelectionDefaults.cxx + EventPlaneHelper.cxx + TableHelper.cxx + MetadataHelper.cxx + CollisionTypeHelper.cxx + FFitWeights.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsParameters ROOT::EG O2::CCDB ROOT::Physics O2::FT0Base O2::FV0Base) o2physics_target_root_dictionary(AnalysisCore - HEADERS TrackSelection.h - TrackSelectionDefaults.h - OrbitRange.h - TableHelper.h - EventPlaneHelper.h - PID/ParamBase.h - PID/DetectorResponse.h - PID/PIDTOF.h - PID/TPCPIDResponse.h - LINKDEF AnalysisCoreLinkDef.h) + HEADERS TrackSelection.h + TrackSelectionDefaults.h + OrbitRange.h + TableHelper.h + MetadataHelper.h + EventPlaneHelper.h + PID/ParamBase.h + PID/DetectorResponse.h + PID/PIDTOF.h + PID/TPCPIDResponse.h + CollisionTypeHelper.h + FFitWeights.h + LINKDEF AnalysisCoreLinkDef.h) + +o2physics_add_header_only_library(TPCDriftManager + HEADERS TPCVDriftManager.h + INTERFACE_LINK_LIBRARIES O2::DataFormatsTPC) diff --git a/Common/Core/CollisionTypeHelper.cxx b/Common/Core/CollisionTypeHelper.cxx new file mode 100644 index 00000000000..c22510ec82e --- /dev/null +++ b/Common/Core/CollisionTypeHelper.cxx @@ -0,0 +1,58 @@ +// 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 CollisionTypeHelper.h +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Utility to handle the collision type from the GRP information +/// + +#include "Common/Core/CollisionTypeHelper.h" +#include +#include +#include "DataFormatsParameters/GRPLHCIFData.h" + +std::string CollisionSystemType::getCollisionSystemName(collType collSys) +{ + switch (collSys) { + case kCollSyspp: + return "pp"; + case kCollSysPbPb: + return "PbPb"; + case kCollSysXeXe: + return "XeXe"; + case kCollSyspPb: + return "pPb"; + default: + return "Undefined"; + } +} + +int CollisionSystemType::getCollisionTypeFromGrp(o2::parameters::GRPLHCIFData* grplhcif) +{ + const int ZBeamA = grplhcif->getBeamZ(o2::constants::lhc::BeamDirection::BeamA); + const int ZBeamC = grplhcif->getBeamZ(o2::constants::lhc::BeamDirection::BeamC); + LOG(debug) << "Collision system: " << ZBeamA << " * " << ZBeamC << " detected"; + switch (ZBeamA * ZBeamC) { + case 1: // pp 1*1 + return kCollSyspp; + case 6724: // Pb-Pb 82*82 + return kCollSysPbPb; + case 225: // Xe-Xe 54*54 + return kCollSysXeXe; + case 82: // p-Pb 82*1 + return kCollSyspPb; + default: + LOG(fatal) << "Undefined collision system in getCollisionTypeFromGrp with BeamA = " << ZBeamA << " and BeamC = " << ZBeamC; + return kCollSysUndef; + } + return kCollSysUndef; +} diff --git a/Common/Core/CollisionTypeHelper.h b/Common/Core/CollisionTypeHelper.h new file mode 100644 index 00000000000..0196fdc03bb --- /dev/null +++ b/Common/Core/CollisionTypeHelper.h @@ -0,0 +1,41 @@ +// 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 CollisionTypeHelper.h +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Utility to handle the collision type from the GRP information +/// + +#ifndef COMMON_CORE_COLLISIONTYPEHELPER_H_ +#define COMMON_CORE_COLLISIONTYPEHELPER_H_ + +#include +#include "DataFormatsParameters/GRPLHCIFData.h" + +// Container for the collision system type +struct CollisionSystemType { + // Enum type for the collision system + typedef int collType; + + static constexpr collType kCollSysUndef = -1; // Undefined collision system + static constexpr collType kCollSyspp = 0; // pp + static constexpr collType kCollSysPbPb = 1; // PbPb + static constexpr collType kCollSysXeXe = 2; // XeXe + static constexpr collType kCollSyspPb = 3; // pPb + static constexpr collType kNCollSys = 4; // Number of collision systems + + static std::string getCollisionSystemName(collType collSys); + + static int getCollisionTypeFromGrp(o2::parameters::GRPLHCIFData* grplhcif); +}; + +#endif // COMMON_CORE_COLLISIONTYPEHELPER_H_ diff --git a/Common/Core/FFitWeights.cxx b/Common/Core/FFitWeights.cxx new file mode 100644 index 00000000000..3a92114f48c --- /dev/null +++ b/Common/Core/FFitWeights.cxx @@ -0,0 +1,175 @@ +// 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 FFitWeights.cxx +/// \brief Implementation file for FFitWeights.h, see the header for more information +/// +/// \author Joachim C. K. B. Hansen + +#include "FFitWeights.h" + +#include +#include +#include + +#include + +ClassImp(FFitWeights) + + FFitWeights::FFitWeights() : TNamed("", ""), + fW_data{nullptr}, + CentBin{100}, + qAxis{nullptr}, + nResolution{3000}, + qnTYPE{0} +{ +} + +FFitWeights::FFitWeights(const char* name) : TNamed(name, name), + fW_data{nullptr}, + CentBin{100}, + qAxis{nullptr}, + nResolution{3000}, + qnTYPE{0} {} + +FFitWeights::~FFitWeights() +{ + delete fW_data; + if (qAxis) + delete qAxis; +}; + +void FFitWeights::init() +{ + fW_data = new TObjArray(); + fW_data->SetName("FFitWeights_Data"); + fW_data->SetOwner(kTRUE); + + if (!qAxis) + this->setBinAxis(500, 0, 25); + for (const auto& qn : qnTYPE) { + fW_data->Add(new TH2D(this->getQName(qn.first, qn.second.c_str()), this->getAxisName(qn.first, qn.second.c_str()), CentBin, 0, CentBin, qAxis->GetNbins(), qAxis->GetXmin(), qAxis->GetXmax())); + } +}; + +void FFitWeights::fillWeights(float centrality, float qn, int nh, const char* pf) +{ + TObjArray* tar{nullptr}; + + tar = fW_data; + if (!tar) + return; + + TH2D* th2 = reinterpret_cast(tar->FindObject(this->getQName(nh, pf))); + if (!th2) { + tar->Add(new TH2D(this->getQName(nh, pf), this->getAxisName(nh, pf), CentBin, 0, CentBin, qAxis->GetNbins(), qAxis->GetXmin(), qAxis->GetXmax())); + th2 = reinterpret_cast(tar->At(tar->GetEntries() - 1)); + } + th2->Fill(centrality, qn); +}; + +Long64_t FFitWeights::Merge(TCollection* collist) +{ + Long64_t nmerged = 0; + if (!fW_data) { + fW_data = new TObjArray(); + fW_data->SetName("FFitWeights_Data"); + fW_data->SetOwner(kTRUE); + } + FFitWeights* l_w = 0; + TIter all_w(collist); + while ((l_w = (reinterpret_cast(all_w())))) { + addArray(fW_data, l_w->getDataArray()); + nmerged++; + } + return nmerged; +}; +void FFitWeights::addArray(TObjArray* targ, TObjArray* sour) +{ + if (!sour) { + printf("Source array does not exist!\n"); + return; + } + for (int i = 0; i < sour->GetEntries(); i++) { + TH2D* sourh = reinterpret_cast(sour->At(i)); + TH2D* targh = reinterpret_cast(targ->FindObject(sourh->GetName())); + if (!targh) { + targh = reinterpret_cast(sourh->Clone(sourh->GetName())); + targh->SetDirectory(0); + targ->Add(targh); + } else { + targh->Add(sourh); + } + } +}; + +void FFitWeights::qSelection(std::vector nhv, std::vector stv) /* only execute OFFLINE */ +{ + TObjArray* tar{nullptr}; + + tar = fW_data; + if (!tar) + return; + + for (const auto& pf : stv) { + for (const auto& nh : nhv) { + TH2D* th2{reinterpret_cast(tar->FindObject(this->getQName(nh, pf.c_str())))}; + if (!th2) { + printf("qh not found!\n"); + return; + } + + TH1D* tmp{nullptr}; + TGraph* tmpgr{nullptr}; + // TSpline3* spline = nullptr; + for (int iSP{0}; iSP < 90; iSP++) { + tmp = th2->ProjectionY(Form("q%i_%i_%i", nh, iSP, iSP + 1), iSP + 1, iSP + 1); + std::vector xq(nResolution); + std::vector yq(nResolution); + for (int i{0}; i < nResolution; i++) + xq[i] = static_cast(i + 1) / static_cast(nResolution); + tmp->GetQuantiles(nResolution, yq.data(), xq.data()); + tmpgr = new TGraph(nResolution, yq.data(), xq.data()); + tmpgr->SetName(Form("sp_q%i%s_%i", nh, pf.c_str(), iSP)); + // spline = new TSpline3(Form("sp_q%i%s_%i", nh, pf.c_str(), iSP), tmpgr); + // spline->SetName(Form("sp_q%i%s_%i", nh, pf.c_str(), iSP)); + fW_data->Add(tmpgr); + } + } + } +}; + +float FFitWeights::eval(float centr, const float& dqn, const int nh, const char* pf) +{ + TObjArray* tar{nullptr}; + + tar = fW_data; + if (!tar) + return -1; + + int isp{static_cast(centr)}; + if (isp < 0 || isp > 90) { + return -1; + } + + TGraph* spline{nullptr}; + spline = reinterpret_cast(tar->FindObject(Form("sp_q%i%s_%i", nh, pf, isp))); + if (!spline) { + return -1; + } + + float qn_val{static_cast(100. * spline->Eval(dqn))}; + if (qn_val < 0 || qn_val > 100.05) { + return -1; + } + + return qn_val; +}; diff --git a/Common/Core/FFitWeights.h b/Common/Core/FFitWeights.h new file mode 100644 index 00000000000..c80165730f7 --- /dev/null +++ b/Common/Core/FFitWeights.h @@ -0,0 +1,83 @@ +// 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 FFitWeights.h +/// \brief Class for handling fit weights for ESE framework. Hold methods for loading and calculating all ESE splines. Supports FT0C, in the future it will support FT0A, FV0A and TPC. +/// +/// \author Joachim C. K. B. Hansen + +#ifndef COMMON_CORE_FFITWEIGHTS_H_ +#define COMMON_CORE_FFITWEIGHTS_H_ + +#include +#include +#include +#include +#include +#include + +#include "TNamed.h" +#include "TObjArray.h" +#include "TH3D.h" +#include "TH2D.h" +#include "TH1D.h" +#include "TFile.h" +#include "TCollection.h" +#include "TString.h" +#include "TMath.h" + +class FFitWeights : public TNamed +{ + public: + FFitWeights(); + explicit FFitWeights(const char* name); + ~FFitWeights(); + + void init(); + void fillWeights(float centrality, float qn, int nh, const char* pf = ""); + TObjArray* getDataArray() { return fW_data; } + + void setCentBin(int bin) { CentBin = bin; } + void setBinAxis(int bin, float min, float max) + { + qAxis = new TAxis(bin, min, max); + } + TAxis* getqVecAx() { return qAxis; } + + Long64_t Merge(TCollection* collist); + void qSelection(std::vector nhv, std::vector stv); + float eval(float centr, const float& dqn, const int nh, const char* pf = ""); + void setResolution(int res) { nResolution = res; } + int getResolution() const { return nResolution; } + void setQnType(std::vector> qninp) { qnTYPE = qninp; } + + private: + TObjArray* fW_data; + + int CentBin; + TAxis* qAxis; //! + int nResolution; + + std::vector> qnTYPE; + + const char* getQName(const int nh, const char* pf = "") + { + return Form("q%i%s", nh, pf); + }; + const char* getAxisName(const int nh, const char* pf = "") + { + return Form(";Centrality;q_{%i}^{%s}", nh, pf); + }; + void addArray(TObjArray* targ, TObjArray* sour); + + ClassDef(FFitWeights, 1); // calibration class +}; +#endif // COMMON_CORE_FFITWEIGHTS_H_ diff --git a/Common/Core/MetadataHelper.cxx b/Common/Core/MetadataHelper.cxx new file mode 100644 index 00000000000..bdcb7e2e8a4 --- /dev/null +++ b/Common/Core/MetadataHelper.cxx @@ -0,0 +1,117 @@ +// 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 MetadataHelper.cxx +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Base of utilities to build advanced tasks +/// + +#include "Common/Core/MetadataHelper.h" + +#include "Framework/InitContext.h" +#include "Framework/RunningWorkflowInfo.h" + +MetadataHelper::MetadataHelper() +{ + const std::array keyList = {"DataType", + "RecoPassName", + "Run", + "AnchorPassName", + "AnchorProduction"}; + for (const auto& key : keyList) { + mMetadata[key] = "undefined"; + } +} + +void MetadataHelper::initMetadata(o2::framework::ConfigContext const& cfgc) +{ + if (mIsInitialized) { + LOG(fatal) << "Metadata already initialized. Cannot reinitialize"; + } + for (const auto& key : mMetadata) { + const std::string cfgKey = "aod-metadata-" + key.first; + if (cfgc.options().hasOption(cfgKey.c_str())) { + mMetadata[key.first] = cfgc.options().get(cfgKey.c_str()); + LOG(info) << "Setting metadata " << key.first << " to '" << mMetadata[key.first] << "'"; + } + } + mIsInitialized = true; +} + +void MetadataHelper::print() const +{ + if (!mIsInitialized) { + LOG(fatal) << "Metadata not initialized"; + } + for (const auto& key : mMetadata) { + LOG(info) << "Metadata " << key.first << ": " << key.second; + } +} + +bool MetadataHelper::isKeyDefined(const std::string& key) const +{ + if (!mIsInitialized) { + LOG(fatal) << "Metadata not initialized"; + } + if (mMetadata.find(key) == mMetadata.end()) { + LOG(fatal) << "Key " << key << " not found in metadata"; + } + return mMetadata.at(key) != "undefined"; +} + +bool MetadataHelper::isFullyDefined() const +{ + if (!mIsInitialized) { + LOG(fatal) << "Metadata not initialized"; + } + for (const auto& key : mMetadata) { + if (!isKeyDefined(key.first)) { + return false; + } + } + return true; +} + +std::string MetadataHelper::get(std::string const& key) const +{ + if (!mIsInitialized) { + LOG(fatal) << "Metadata not initialized"; + } + if (mMetadata.find(key) == mMetadata.end()) { + LOG(fatal) << "Key " << key << " not found in metadata"; + } + return mMetadata.at(key); +} + +bool MetadataHelper::isRun3() const +{ + const bool b = (get("Run") == "3"); + LOG(info) << "From metadata this data is from " << (b ? "Run 3" : "Run 2"); + return b; +} + +bool MetadataHelper::isMC() const +{ + const bool b = (get("DataType") == "MC"); + LOG(info) << "From metadata this data is from " << (b ? "MC" : "Data"); + return b; +} + +bool MetadataHelper::isInitialized() const +{ + if (mIsInitialized) { + LOG(debug) << "Metadata is initialized"; + } else { + LOG(debug) << "Metadata is not initialized"; + } + return mIsInitialized; +} diff --git a/Common/Core/MetadataHelper.h b/Common/Core/MetadataHelper.h new file mode 100644 index 00000000000..8519c25bc88 --- /dev/null +++ b/Common/Core/MetadataHelper.h @@ -0,0 +1,67 @@ +// 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 TableHelper.h +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Utility to handle the metadata from the AOD +/// + +#ifndef COMMON_CORE_METADATAHELPER_H_ +#define COMMON_CORE_METADATAHELPER_H_ + +#include +#include +#include "Framework/ConfigContext.h" + +struct MetadataHelper { + /// @brief Constructor for the MetadataHelper. Defines the all the metadata keys that will be looked for and accessible + MetadataHelper(); + + /// @brief Function to initialize the metadata from the configuration context. + /// @param cfgc the configuration context + void initMetadata(o2::framework::ConfigContext const& cfgc); + + /// @brief Function to print the metadata + void print() const; + + /// Function to check if the metadata is fully defined + /// @return true if the metadata is fully defined, false otherwise + bool isFullyDefined() const; + + /// Function to check if the data is from Run 3 + /// @return 1 if the run is a run 3 run, 0 if it is not, -1 if it is not defined + bool isRun3() const; + + /// Function to check if the data is from MC + /// @return 1 if the data is from MC, 0 if it is not, -1 if it is not defined + bool isMC() const; + + /// @brief Function to check if the data has been correctly initialized + /// @return true if the data has been initialized, false otherwise + bool isInitialized() const; + + /// @brief Function to get the metadata value for a given key + /// @param key the key of the metadata + /// @return the value of the metadata. Throws an exception if the key is not found + std::string get(const std::string& key) const; + + /// @brief Function to check if a key is defined in the metadata + /// @param key the key to check + /// @return true if the key is defined, false otherwise. Throws an exception if the key is not found + bool isKeyDefined(const std::string& key) const; + + private: + std::map mMetadata; /// < The metadata map + bool mIsInitialized = false; /// < Flag to check if the metadata has been initialized +}; + +#endif // COMMON_CORE_METADATAHELPER_H_ diff --git a/Common/Core/PID/PIDTOF.cxx b/Common/Core/PID/PIDTOF.cxx new file mode 100644 index 00000000000..bec41fafc43 --- /dev/null +++ b/Common/Core/PID/PIDTOF.cxx @@ -0,0 +1,104 @@ +// 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 PIDTOF.cxx +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \since 02/07/2020 +/// \brief Implementation of the TOF detector response for PID +/// + +#include "PIDTOF.h" +#include + +namespace o2::pid::tof +{ + +void TOFResoParamsV3::setResolutionParametrizationRun2(std::unordered_map const& pars) +{ + std::array paramNames{"TrkRes.Pi.P0", "TrkRes.Pi.P1", "TrkRes.Pi.P2", "TrkRes.Pi.P3", "time_resolution", + "TrkRes.Ka.P0", "TrkRes.Ka.P1", "TrkRes.Ka.P2", "TrkRes.Ka.P3", + "TrkRes.Pr.P0", "TrkRes.Pr.P1", "TrkRes.Pr.P2", "TrkRes.Pr.P3"}; + // Now we override the parametrization to use the Run 2 one + for (int i = 0; i < 9; i++) { + if (mResolution[i]) { + delete mResolution[i]; + } + mResolution[i] = new TF2(Form("tofResTrack.%s_Run2", particleNames[i]), "-10", 0., 20, -1, 1.); // With negative values the old one is used + } + // Print the map + for (const auto& [key, value] : pars) { + LOG(info) << "Key: " << key << " Value: " << value; + } + for (int i = 0; i < 13; i++) { + setParameter(i, pars.at(paramNames[i])); + } +} + +// Time shift for post calibration to realign as a function of eta +void TOFResoParamsV3::setTimeShiftParameters(std::unordered_map const& pars, const bool positive) +{ + std::string baseOpt = positive ? "TimeShift.Pos." : "TimeShift.Neg."; + + if (pars.count(baseOpt + "GetN") == 0) { // If the map does not contain the number of eta bins, we assume that no correction has to be applied + return; + } + const int nPoints = static_cast(pars.at(baseOpt + "GetN")); + if (nPoints <= 0) { + LOG(fatal) << "TOFResoParamsV3 shift: time must be positive"; + } + TGraph graph; + for (int i = 0; i < nPoints; ++i) { + graph.AddPoint(pars.at(Form("TimeShift.eta%i", i)), pars.at(Form("TimeShift.cor%i", i))); + } + setTimeShiftParameters(&graph, positive); +} +void TOFResoParamsV3::setTimeShiftParameters(std::string const& filename, std::string const& objname, const bool positive) +{ + TFile f(filename.c_str(), "READ"); + if (f.IsOpen()) { + if (positive) { + f.GetObject(objname.c_str(), gPosEtaTimeCorr); + } else { + f.GetObject(objname.c_str(), gNegEtaTimeCorr); + } + f.Close(); + } + LOG(info) << "Set the Time Shift parameters from file " << filename << " and object " << objname << " for " << (positive ? "positive" : "negative"); +} +void TOFResoParamsV3::setTimeShiftParameters(TGraph* g, const bool positive) +{ + if (!g) { + LOG(info) << "No Time Shift parameter is passed for " << (positive ? "positive" : "negative"); + return; + } + if (positive) { + gPosEtaTimeCorr = g; + } else { + gNegEtaTimeCorr = g; + } + LOG(info) << "Set the Time Shift parameters from object " << g->GetName() << " " << g->GetTitle() << " for " << (positive ? "positive" : "negative"); +} +float TOFResoParamsV3::getTimeShift(float eta, int16_t sign) const +{ + if (sign > 0) { + if (!gPosEtaTimeCorr) { + return 0.f; + } + return gPosEtaTimeCorr->Eval(eta); + } + if (!gNegEtaTimeCorr) { + return 0.f; + } + return gNegEtaTimeCorr->Eval(eta); +} + +} // namespace o2::pid::tof diff --git a/Common/Core/PID/PIDTOF.h b/Common/Core/PID/PIDTOF.h index 2a54e28dfe6..ad16716916c 100644 --- a/Common/Core/PID/PIDTOF.h +++ b/Common/Core/PID/PIDTOF.h @@ -28,100 +28,20 @@ #include "TMath.h" #include "TGraph.h" #include "TFile.h" +#include "TF2.h" // O2 includes #include "DataFormatsTOF/ParameterContainers.h" #include "Framework/Logger.h" #include "ReconstructionDataFormats/PID.h" #include "Framework/DataTypes.h" +#include "CommonConstants/PhysicsConstants.h" namespace o2::pid::tof { // Utility values -static constexpr float kCSPEED = TMath::C() * 1.0e2f * 1.0e-12f; /// Speed of light in TOF units (cm/ps) -static constexpr float kCSPEDDInv = 1.f / kCSPEED; /// Inverse of the Speed of light in TOF units (ps/cm) -static constexpr float defaultReturnValue = -999.f; /// Default return value in case TOF measurement is not available - -/// \brief Class to handle the the TOF detector response for the TOF beta measurement -template -class Beta -{ - public: - Beta() = default; - ~Beta() = default; - - /// Computes the beta of a track given a length, a time measurement and an event time (in ps) - /// \param length Length in cm of the track - /// \param tofSignal TOF signal in ps for the track - /// \param collisionTime collision time in ps for the event of the track - static float GetBeta(const float length, const float tofSignal, const float collisionTime) { return length / (tofSignal - collisionTime) * kCSPEDDInv; } - - /// Gets the beta for the track of interest - /// \param track Track of interest - /// \param collisionTime Collision time - static float GetBeta(const TrackType& track, const float collisionTime) { return track.hasTOF() ? GetBeta(track.length(), track.tofSignal(), collisionTime) : defaultReturnValue; } - - /// Gets the beta for the track of interest - /// \param track Track of interest - static float GetBeta(const TrackType& track) { return GetBeta(track, track.tofEvTime()); } - - /// Computes the expected uncertainty on the beta measurement - /// \param length Length in cm of the track - /// \param tofSignal TOF signal in ps for the track - /// \param collisionTime collision time in ps for the event of the track - /// \param time_reso expected time resolution - static float GetExpectedSigma(const float length, const float tofSignal, const float collisionTime, const float expectedResolution) { return GetBeta(length, tofSignal, collisionTime) / (tofSignal - collisionTime) * expectedResolution; } - - /// Gets the expected uncertainty on the beta measurement of the track of interest - /// \param track Track of interest - float GetExpectedSigma(const TrackType& track) const { return GetExpectedSigma(track.length(), track.tofSignal(), track.tofEvTime(), mExpectedResolution); } - - /// Gets the expected beta for a given mass hypothesis (no energy loss taken into account) - /// \param momentum momentum in GeV/c of the track - /// \param mass mass in GeV/c2 of the particle of interest - static float GetExpectedBeta(const float momentum, const float mass) { return momentum > 0 ? momentum / std::sqrt(momentum * momentum + mass * mass) : 0.f; } - - /// Gets the expected beta given the particle index (no energy loss taken into account) of the track of interest - /// \param track Track of interest - template - float GetExpectedBeta(const TrackType& track) const - { - return GetExpectedBeta(track.p(), o2::track::PID::getMass2Z(id)); - } - - /// Gets the number of sigmas with respect the approximate beta (no energy loss taken into account) of the track of interest - /// \param track Track of interest - template - float GetSeparation(const TrackType& track) const - { - return (GetBeta(track) - GetExpectedBeta(track)) / GetExpectedSigma(track); - } - - float mExpectedResolution = 80; /// Expected time resolution -}; - -/// \brief Class to handle the the TOF detector response for the TOF mass measurement -template -class TOFMass -{ - public: - TOFMass() = default; - ~TOFMass() = default; - - /// Computes the TOF mass of a track given a momentum, a beta measurement - /// \param momentum momentum of the track - /// \param beta TOF beta measurement - static float GetTOFMass(const float momentum, const float beta) { return (momentum / beta) * std::sqrt(std::abs(1.f - beta * beta)); } - - /// Gets the TOF mass for the track of interest - /// \param track Track of interest - static float GetTOFMass(const TrackType& track, const float beta) { return track.hasTOF() ? GetTOFMass(track.p(), beta) : defaultReturnValue; } - - /// Gets the TOF mass for the track of interest - /// \param track Track of interest - static float GetTOFMass(const TrackType& track) { return track.hasTOF() ? GetTOFMass(track.p(), Beta::GetBeta(track)) : defaultReturnValue; } -}; +static constexpr float defaultReturnValue = -999.f; /// Default return value in case TOF measurement is not available /// \brief Next implementation class to store TOF response parameters for exp. times class TOFResoParamsV2 : public o2::tof::Parameters<13> @@ -139,7 +59,13 @@ class TOFResoParamsV2 : public o2::tof::Parameters<13> ~TOFResoParamsV2() = default; - void setShiftParameters(std::unordered_map const& pars) + template + float getResolution(const float, const float) const + { + return -1.f; + } + // Momentum shift for charge calibration + void setMomentumChargeShiftParameters(std::unordered_map const& pars) { if (pars.count("Shift.etaN") == 0) { // If the map does not contain the number of eta bins, we assume that no correction has to be applied mEtaN = 0; @@ -161,7 +87,13 @@ class TOFResoParamsV2 : public o2::tof::Parameters<13> mContent[i] = pars.at(Form("Shift.etaC%i", i)); } } - float getShift(float eta) const + // To remove + void setShiftParameters(std::unordered_map const& pars) + { + setMomentumChargeShiftParameters(pars); + } + + float getMomentumChargeShift(float eta) const { if (mEtaN == 0) { // No correction // LOG(info) << "TOFResoParamsV2 shift: no correction mEtaN is " << mEtaN; @@ -171,7 +103,13 @@ class TOFResoParamsV2 : public o2::tof::Parameters<13> // LOG(info) << "TOFResoParamsV2 shift: correction for eta " << eta << " is for index " << etaIndex << " = " << shift; return mContent.at(etaIndex); } - void printShiftParameters() const + // To remove + float getShift(float eta) const + { + return getMomentumChargeShift(eta); + } + + void printMomentumChargeShiftParameters() const { LOG(info) << "TOF momentum shift parameters"; LOG(info) << "etaN: " << mEtaN; @@ -182,29 +120,35 @@ class TOFResoParamsV2 : public o2::tof::Parameters<13> LOG(info) << "etaC" << i << ": " << mContent[i]; } } - void setTimeShiftParameters(std::string const& filename, std::string const& objname, bool pos) + // To remove + void printShiftParameters() const + { + printMomentumChargeShiftParameters(); + } + + void setTimeShiftParameters(std::string const& filename, std::string const& objname, bool positive) { TFile f(filename.c_str(), "READ"); if (f.IsOpen()) { - if (pos) { + if (positive) { f.GetObject(objname.c_str(), gPosEtaTimeCorr); } else { f.GetObject(objname.c_str(), gNegEtaTimeCorr); } f.Close(); } - LOG(info) << "Set the Time Shift parameters from file " << filename << " and object " << objname << " for " << (pos ? "positive" : "negative"); + LOG(info) << "Set the Time Shift parameters from file " << filename << " and object " << objname << " for " << (positive ? "positive" : "negative") << " example of shift at eta 0: " << getTimeShift(0, positive); } - void setTimeShiftParameters(TGraph* g, bool pos) + void setTimeShiftParameters(TGraph* g, bool positive) { - if (pos) { + if (positive) { gPosEtaTimeCorr = g; } else { gNegEtaTimeCorr = g; } - LOG(info) << "Set the Time Shift parameters from object " << g->GetName() << " " << g->GetTitle() << " for " << (pos ? "positive" : "negative"); + LOG(info) << "Set the Time Shift parameters from object " << g->GetName() << " " << g->GetTitle() << " for " << (positive ? "positive" : "negative"); } - float getTimeShift(float eta, short sign) const + float getTimeShift(float eta, int16_t sign) const { if (sign > 0) { if (!gPosEtaTimeCorr) { @@ -219,13 +163,274 @@ class TOFResoParamsV2 : public o2::tof::Parameters<13> } private: + // Charge calibration int mEtaN = 0; // Number of eta bins, 0 means no correction float mEtaStart = 0.f; float mEtaStop = 0.f; float mInvEtaWidth = 9999.f; std::vector mContent; - TGraph* gPosEtaTimeCorr = nullptr; - TGraph* gNegEtaTimeCorr = nullptr; + + // Time shift for post calibration + TGraph* gPosEtaTimeCorr = nullptr; /// Time shift correction for positive tracks + TGraph* gNegEtaTimeCorr = nullptr; /// Time shift correction for negative tracks +}; + +/// \brief Next implementation class to store TOF response parameters for exp. times +class TOFResoParamsV3 : public o2::tof::Parameters<13> +{ + public: + TOFResoParamsV3() : Parameters(std::array{"time_resolution", "time_resolution", "time_resolution", "time_resolution", "time_resolution", + "time_resolution", "time_resolution", "time_resolution", "time_resolution", + "time_resolution", "time_resolution", "time_resolution", "time_resolution"}, + "TOFResoParamsV3") + { + setParameters(std::array{60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0}); + } // Default constructor with default parameters + + ~TOFResoParamsV3() = default; + + // Momentum shift for charge calibration + void setMomentumChargeShiftParameters(std::unordered_map const& pars) + { + if (pars.count("Shift.etaN") == 0) { // If the map does not contain the number of eta bins, we assume that no correction has to be applied + mEtaN = 0; + return; + } + mEtaN = static_cast(pars.at("Shift.etaN")); + if (mEtaN <= 0) { + LOG(fatal) << "TOFResoParamsV3 shift: etaN must be positive"; + } + mEtaStart = pars.at("Shift.etaStart"); + mEtaStop = pars.at("Shift.etaStop"); + if (mEtaStart >= mEtaStop) { + LOG(fatal) << "TOFResoParamsV3 shift: etaStart must be smaller than etaStop"; + } + mInvEtaWidth = 1.f / ((mEtaStop - mEtaStart) / mEtaN); + mContent.clear(); + mContent.resize(mEtaN); + for (int i = 0; i < mEtaN; ++i) { + mContent[i] = pars.at(Form("Shift.etaC%i", i)); + } + } + + float getMomentumChargeShift(float eta) const + { + if (mEtaN == 0) { // No correction + // LOG(info) << "TOFResoParamsV3 shift: no correction mEtaN is " << mEtaN; + return 0.f; + } + const int& etaIndex = (eta <= mEtaStart) ? 0 : (eta >= mEtaStop ? (mEtaN - 1) : (eta - mEtaStart) * mInvEtaWidth); + // LOG(info) << "TOFResoParamsV3 shift: correction for eta " << eta << " is for index " << etaIndex << " = " << shift; + return mContent.at(etaIndex); + } + + void printMomentumChargeShiftParameters() const + { + LOG(info) << "TOF momentum shift parameters"; + LOG(info) << "etaN: " << mEtaN; + LOG(info) << "etaStart: " << mEtaStart; + LOG(info) << "etaStop: " << mEtaStop; + LOG(info) << "content size " << mContent.size(); + for (int i = 0; i < mEtaN; ++i) { + LOG(info) << "etaC" << i << ": " << mContent[i]; + } + } + + // Time shift for post calibration to realign as a function of eta + void setTimeShiftParameters(std::unordered_map const& pars, const bool positive); + void setTimeShiftParameters(std::string const& filename, std::string const& objname, const bool positive); + void setTimeShiftParameters(TGraph* g, const bool positive); + float getTimeShift(float eta, int16_t sign) const; + + void printTimeShiftParameters() const + { + if (gPosEtaTimeCorr) { + LOG(info) << "Using a time shift for Pos " << gPosEtaTimeCorr->GetName() << " " << gPosEtaTimeCorr->GetTitle() << " value at 0: " << gPosEtaTimeCorr->Eval(0) << " vs correction " << getTimeShift(0, 1); + } else { + LOG(info) << "Using no time shift for Pos vs correction " << getTimeShift(0, 1); + } + if (gNegEtaTimeCorr) { + LOG(info) << "Using a time shift for Neg " << gNegEtaTimeCorr->GetName() << " " << gNegEtaTimeCorr->GetTitle() << " value at 0: " << gNegEtaTimeCorr->Eval(0) << " vs correction " << getTimeShift(0, -1); + } else { + LOG(info) << "Using no time shift for Neg vs correction " << getTimeShift(0, -1); + } + } + + void setResolutionParametrization(std::unordered_map const& pars) + { + for (int i = 0; i < 9; i++) { + const std::string baseOpt = Form("tofResTrack.%s_", particleNames[i]); + // Check if a key begins with a string + for (const auto& [key, value] : pars) { + if (key.find(baseOpt) == 0) { + // Remove from the key the baseOpt + const std::string fun = key.substr(baseOpt.size()); + if (mResolution[i]) { + delete mResolution[i]; + } + mResolution[i] = new TF2(baseOpt.c_str(), fun.c_str(), 0., 20, -1, 1.); + LOG(info) << "Set the resolution function for " << particleNames[i] << " with formula " << mResolution[i]->GetFormula()->GetExpFormula(); + break; + } + } + } + // Print a summary + for (int i = 0; i < 9; i++) { + if (!mResolution[i]) { + LOG(info) << "Resolution function for " << particleNames[i] << " not provided, using default " << mDefaultResoParams[i]; + mResolution[i] = new TF2(Form("tofResTrack.%s_Default", particleNames[i]), mDefaultResoParams[i], 0., 20, -1, 1.); + } + LOG(info) << "Resolution function for " << particleNames[i] << " is " << mResolution[i]->GetName() << " with formula " << mResolution[i]->GetFormula()->GetExpFormula(); + } + } + + void setResolutionParametrizationRun2(std::unordered_map const& pars); + + template + float getResolution(const float p, const float eta) const + { + return mResolution[pid]->Eval(p, eta); + } + + void printResolution() const + { + // Print a summary + for (int i = 0; i < 9; i++) { + if (!mResolution[i]) { + LOG(info) << "Resolution function for " << particleNames[i] << " is not defined yet"; + continue; + } + LOG(info) << "Resolution function for " << particleNames[i] << " is " << mResolution[i]->GetName() << " with formula " << mResolution[i]->GetFormula()->GetExpFormula(); + } + } + void printFullConfig() const + { + print(); + printMomentumChargeShiftParameters(); + printTimeShiftParameters(); + printResolution(); + } + + private: + // Charge calibration + int mEtaN = 0; // Number of eta bins, 0 means no correction + float mEtaStart = 0.f; + float mEtaStop = 0.f; + float mInvEtaWidth = 9999.f; + std::vector mContent; + std::array mResolution{nullptr}; + static constexpr std::array mDefaultResoParams{"14.3*TMath::Power((TMath::Max(x-0.319,0.1))*(1-0.4235*y*y),-0.8467)", + "14.3*TMath::Power((TMath::Max(x-0.319,0.1))*(1-0.4235*y*y),-0.8467)", + "14.3*TMath::Power((TMath::Max(x-0.319,0.1))*(1-0.4235*y*y),-0.8467)", + "42.66*TMath::Power((TMath::Max(x-0.417,0.1))*(1-0.4235*y*y),-0.7145)", + "99.46*TMath::Power((TMath::Max(x-0.447,0.1))*(1-0.4235*y*y),-0.8094)", + "216*TMath::Power((TMath::Max(x-0.647,0.1))*(1-0.4235*y*y),-0.76)", + "315*TMath::Power((TMath::Max(x-0.811,0.1))*(1-0.4235*y*y),-0.783)", + "157*TMath::Power((TMath::Max(x-0.556,0.1))*(1-0.4235*y*y),-0.783)", + "216*TMath::Power((TMath::Max(x-0.647,0.1))*(1-0.4235*y*y),-0.76)"}; + static constexpr std::array particleNames = {"El", "Mu", "Pi", "Ka", "Pr", "De", "Tr", "He", "Al"}; + + // Time shift for post calibration + TGraph* gPosEtaTimeCorr = nullptr; /// Time shift correction for positive tracks + TGraph* gNegEtaTimeCorr = nullptr; /// Time shift correction for negative tracks +}; + +/// \brief Class to handle the the TOF detector response for the TOF beta measurement +class Beta +{ + public: + Beta() = default; + ~Beta() = default; + + /// Computes the beta of a track given a length, a time measurement and an event time (in ps) + /// \param length Length in cm of the track + /// \param tofSignal TOF signal in ps for the track + /// \param collisionTime collision time in ps for the event of the track + static float GetBeta(const float length, const float tofSignal, const float collisionTime) { return length / (tofSignal - collisionTime) * o2::constants::physics::invLightSpeedCm2PS; } + + /// Gets the beta for the track of interest + /// \param track Track of interest + /// \param collisionTime Collision time + template + static float GetBeta(const TrackType& track, const float collisionTime) + { + return track.hasTOF() ? GetBeta(track.length(), track.tofSignal(), collisionTime) : defaultReturnValue; + } + + /// Gets the beta for the track of interest + /// \param track Track of interest + template + static float GetBeta(const TrackType& track) + { + return GetBeta(track, track.tofEvTime()); + } + + /// Computes the expected uncertainty on the beta measurement + /// \param length Length in cm of the track + /// \param tofSignal TOF signal in ps for the track + /// \param collisionTime collision time in ps for the event of the track + /// \param time_reso expected time resolution + static float GetExpectedSigma(const float length, const float tofSignal, const float collisionTime, const float expectedResolution) { return GetBeta(length, tofSignal, collisionTime) / (tofSignal - collisionTime) * expectedResolution; } + + /// Gets the expected uncertainty on the beta measurement of the track of interest + /// \param track Track of interest + template + float GetExpectedSigma(const TrackType& track) const + { + return GetExpectedSigma(track.length(), track.tofSignal(), track.tofEvTime(), mExpectedResolution); + } + + /// Gets the expected beta for a given mass hypothesis (no energy loss taken into account) + /// \param momentum momentum in GeV/c of the track + /// \param mass mass in GeV/c2 of the particle of interest + static float GetExpectedBeta(const float momentum, const float mass) { return momentum > 0 ? momentum / std::sqrt(momentum * momentum + mass * mass) : 0.f; } + + /// Gets the expected beta given the particle index (no energy loss taken into account) of the track of interest + /// \param track Track of interest + template + float GetExpectedBeta(const TrackType& track) const + { + return GetExpectedBeta(track.p(), o2::track::PID::getMass2Z(id)); + } + + /// Gets the number of sigmas with respect the approximate beta (no energy loss taken into account) of the track of interest + /// \param track Track of interest + template + float GetSeparation(const TrackType& track) const + { + return (GetBeta(track) - GetExpectedBeta(track)) / GetExpectedSigma(track); + } + + float mExpectedResolution = 80; /// Expected time resolution +}; + +/// \brief Class to handle the the TOF detector response for the TOF mass measurement +class TOFMass +{ + public: + TOFMass() = default; + ~TOFMass() = default; + + /// Computes the TOF mass of a track given a momentum, a beta measurement + /// \param momentum momentum of the track + /// \param beta TOF beta measurement + static float GetTOFMass(const float momentum, const float beta) { return (momentum / beta) * std::sqrt(std::abs(1.f - beta * beta)); } + + /// Gets the TOF mass for the track of interest + /// \param track Track of interest + template + static float GetTOFMass(const TrackType& track, const float beta) + { + return track.hasTOF() ? GetTOFMass(track.p(), beta) : defaultReturnValue; + } + + /// Gets the TOF mass for the track of interest + /// \param track Track of interest + template + static float GetTOFMass(const TrackType& track) + { + return track.hasTOF() ? GetTOFMass(track.p(), Beta::GetBeta(track)) : defaultReturnValue; + } }; /// \brief Class to handle the the TOF detector response for the expected time @@ -239,7 +444,7 @@ class ExpTimes static constexpr float mMassZSqared = mMassZ * mMassZ; /// (M/z)^2 /// Computes the expected time of a track, given it TOF expected momentum - static float ComputeExpectedTime(const float tofExpMom, const float length) { return length * sqrt((mMassZSqared) + (tofExpMom * tofExpMom)) / (kCSPEED * tofExpMom); } + static float ComputeExpectedTime(const float tofExpMom, const float length) { return length * sqrt((mMassZSqared) + (tofExpMom * tofExpMom)) / (o2::constants::physics::LightSpeedCm2PS * tofExpMom); } /// Gets the expected signal of the track of interest under the PID assumption /// \param track Track of interest @@ -249,7 +454,7 @@ class ExpTimes return defaultReturnValue; } if (track.trackType() == o2::aod::track::Run2Track) { - return ComputeExpectedTime(track.tofExpMom() * kCSPEDDInv, track.length()); + return ComputeExpectedTime(track.tofExpMom() * o2::constants::physics::invLightSpeedCm2PS, track.length()); } return ComputeExpectedTime(track.tofExpMom(), track.length()); } @@ -257,16 +462,17 @@ class ExpTimes /// Gets the expected signal of the track of interest under the PID assumption corrected for shifts in expected momentum /// \param parameters Parameters to correct for the momentum shift /// \param track Track of interest - static float GetCorrectedExpectedSignal(const TOFResoParamsV2& parameters, const TrackType& track) + template + static float GetCorrectedExpectedSignal(const ParamType& parameters, const TrackType& track) { if (!track.hasTOF()) { return defaultReturnValue; } if (track.trackType() == o2::aod::track::Run2Track) { - return ComputeExpectedTime(track.tofExpMom() * kCSPEDDInv / (1.f + track.sign() * parameters.getShift(track.eta())), track.length()); + return ComputeExpectedTime(track.tofExpMom() * o2::constants::physics::invLightSpeedCm2PS / (1.f + track.sign() * parameters.getMomentumChargeShift(track.eta())), track.length()); } - LOG(debug) << "TOF exp. mom. " << track.tofExpMom() << " shifted = " << track.tofExpMom() / (1.f + track.sign() * parameters.getShift(track.eta())); - return ComputeExpectedTime(track.tofExpMom() / (1.f + track.sign() * parameters.getShift(track.eta())), track.length()) + parameters.getTimeShift(track.eta(), track.sign()); + LOG(debug) << "TOF exp. mom. " << track.tofExpMom() << " shifted = " << track.tofExpMom() / (1.f + track.sign() * parameters.getMomentumChargeShift(track.eta())); + return ComputeExpectedTime(track.tofExpMom() / (1.f + track.sign() * parameters.getMomentumChargeShift(track.eta())), track.length()) + parameters.getTimeShift(track.eta(), track.sign()); } /// Gets the expected resolution of the t-texp-t0 @@ -275,12 +481,18 @@ class ExpTimes /// \param track Track of interest /// \param tofSignal TOF signal of the track of interest /// \param collisionTimeRes Collision time resolution of the track of interest - static float GetExpectedSigma(const TOFResoParamsV2& parameters, const TrackType& track, const float tofSignal, const float collisionTimeRes) + template + static float GetExpectedSigma(const ParamType& parameters, const TrackType& track, const float tofSignal, const float collisionTimeRes) { const float& mom = track.p(); + const float& eta = track.eta(); if (mom <= 0) { return -999.f; } + const float reso = parameters.template getResolution(mom, eta); + if (reso > 0) { + return std::sqrt(reso * reso + parameters[4] * parameters[4] + collisionTimeRes * collisionTimeRes); + } if constexpr (id <= o2::track::PID::Pion) { LOG(debug) << "Using parameters for the pion hypothesis and ID " << id; const float dpp = parameters[0] + parameters[1] * mom + parameters[2] * mMassZ / mom; // mean relative pt resolution; @@ -301,29 +513,49 @@ class ExpTimes /// Gets the expected resolution of the t-texp-t0 /// \param parameters Detector response parameters /// \param track Track of interest - static float GetExpectedSigma(const TOFResoParamsV2& parameters, const TrackType& track) { return GetExpectedSigma(parameters, track, track.tofSignal(), track.tofEvTimeErr()); } + template + static float GetExpectedSigma(const ParamType& parameters, const TrackType& track) + { + return GetExpectedSigma(parameters, track, track.tofSignal(), track.tofEvTimeErr()); + } /// Gets the expected resolution of the time measurement, uses the expected time and no event time resolution /// \param parameters Parameters to use to compute the expected resolution /// \param track Track of interest - static float GetExpectedSigmaTracking(const TOFResoParamsV2& parameters, const TrackType& track) { return GetExpectedSigma(parameters, track, GetCorrectedExpectedSignal(parameters, track), 0.f); } + template + static float GetExpectedSigmaTracking(const ParamType& parameters, const TrackType& track) + { + return GetExpectedSigma(parameters, track, GetCorrectedExpectedSignal(parameters, track), 0.f); + } /// Gets the number of sigmas with respect the expected time /// \param parameters Detector response parameters /// \param track Track of interest /// \param collisionTime Collision time /// \param collisionTimeRes Collision time resolution of the track of interest - static float GetSeparation(const TOFResoParamsV2& parameters, const TrackType& track, const float collisionTime, const float resolution) { return track.hasTOF() ? (track.tofSignal() - collisionTime - GetCorrectedExpectedSignal(parameters, track)) / resolution : defaultReturnValue; } + template + static float GetSeparation(const ParamType& parameters, const TrackType& track, const float collisionTime, const float resolution) + { + return track.hasTOF() ? (track.tofSignal() - collisionTime - GetCorrectedExpectedSignal(parameters, track)) / resolution : defaultReturnValue; + } /// Gets the number of sigmas with respect the expected time /// \param parameters Detector response parameters /// \param track Track of interest - static float GetSeparation(const TOFResoParamsV2& parameters, const TrackType& track, const float resolution) { return GetSeparation(parameters, track, track.tofEvTime(), resolution); } + template + static float GetSeparation(const ParamType& parameters, const TrackType& track, const float resolution) + { + return GetSeparation(parameters, track, track.tofEvTime(), resolution); + } /// Gets the number of sigmas with respect the expected time /// \param parameters Detector response parameters /// \param track Track of interest - static float GetSeparation(const TOFResoParamsV2& parameters, const TrackType& track) { return GetSeparation(parameters, track, track.tofEvTime(), GetExpectedSigma(parameters, track)); } + template + static float GetSeparation(const ParamType& parameters, const TrackType& track) + { + return GetSeparation(parameters, track, track.tofEvTime(), GetExpectedSigma(parameters, track)); + } }; /// \brief Class to convert the trackTime to the tofSignal used for PID diff --git a/Common/Core/PID/ParamBase.h b/Common/Core/PID/ParamBase.h index 50c3f50132d..ec4b17083f4 100644 --- a/Common/Core/PID/ParamBase.h +++ b/Common/Core/PID/ParamBase.h @@ -17,8 +17,13 @@ /// These are the basic storage elements to be kept in the CCDB /// -#ifndef O2_FRAMEWORK_PARAMBASE_H_ -#define O2_FRAMEWORK_PARAMBASE_H_ +#ifndef COMMON_CORE_PID_PARAMBASE_H_ +#define COMMON_CORE_PID_PARAMBASE_H_ + +#include // std::copy +#include // std::map +#include // std::string +#include // std::vector // ROOT includes #include "TNamed.h" @@ -40,15 +45,15 @@ class Parameters : public TNamed /// Parametric constructor /// \param size Number of parameters in the container - Parameters(unsigned int size) : mPar(std::vector(size)){}; + explicit Parameters(unsigned int size) : mPar(std::vector(size)) {} /// Parametric constructor /// \param size Number of parameters in the container - Parameters(const TString name, unsigned int size) : TNamed(name, name), mPar(std::vector(size)){}; + Parameters(const TString name, unsigned int size) : TNamed(name, name), mPar(std::vector(size)) {} /// Parametric constructor /// \param params Parameters to initialize the container - Parameters(const TString name, const std::vector params) : TNamed(name, name), mPar{} { SetParameters(params); }; + Parameters(const TString name, const std::vector params) : TNamed(name, name), mPar{} { SetParameters(params); } /// Default destructor ~Parameters() override = default; @@ -68,11 +73,11 @@ class Parameters : public TNamed /// Setter for the parameter, using a parameter object /// \param params parameter object with parameters - void SetParameters(const Parameters params) { SetParameters(params.mPar); }; + void SetParameters(const Parameters params) { SetParameters(params.mPar); } /// Setter for the parameter, using a parameter pointer /// \param params pointer to parameter object with parameters - void SetParameters(const Parameters* params) { SetParameters(params->mPar); }; + void SetParameters(const Parameters* params) { SetParameters(params->mPar); } /// Printer of the parameter values void Print(Option_t* option = "") const override; @@ -108,7 +113,7 @@ class PidParameters : public TNamed { public: /// Default constructor - PidParameters(TString name = "DefaultParameters") : TNamed(name, name), mPar{} {}; + explicit PidParameters(TString name = "DefaultParameters") : TNamed(name, name), mPar{} {}; /// Default destructor ~PidParameters() override = default; @@ -133,11 +138,11 @@ class PidParameters : public TNamed /// Setter for the parameter, using a parameter object /// \param params parameter object with parameters - void SetParameters(const PidParameters params) { SetParameters(params.mPar); }; + void SetParameters(const PidParameters params) { SetParameters(params.mPar); } /// Setter for the parameter, using a parameter pointer /// \param params pointer to parameter object with parameters - void SetParameters(const PidParameters* params) { SetParameters(params->mPar); }; + void SetParameters(const PidParameters* params) { SetParameters(params->mPar); } /// Printer of the parameter values void Print(Option_t* /*option = ""*/) const override @@ -183,7 +188,7 @@ class PidParameters : public TNamed /// Getter for the parameters /// \return returns an array of parameters - const pidvar_t GetParameter(int i) const { return mPar[i]; } + pidvar_t GetParameter(int i) const { return mPar[i]; } /// Getter for the size of the parameter /// \return returns the size of the parameter array @@ -210,12 +215,12 @@ class Parametrization : public TNamed /// Parametric constructor /// \param name Name (and title) of the parametrization /// \param size Number of parameters of the parametrization - Parametrization(TString name, unsigned int size) : TNamed(name, name), mParameters(name + "Parameters", size){}; + Parametrization(TString name, unsigned int size) : TNamed(name, name), mParameters(name + "Parameters", size) {} /// Parametric constructor /// \param name Name (and title) of the parametrization /// \param params Parameters of the parametrization - Parametrization(TString name, const std::vector params) : TNamed(name, name), mParameters{name + "Parameters", params} {}; + Parametrization(TString name, const std::vector params) : TNamed(name, name), mParameters{name + "Parameters", params} {} /// Default destructor ~Parametrization() override = default; @@ -260,4 +265,4 @@ class Parametrization : public TNamed } // namespace o2::pid -#endif // O2_FRAMEWORK_PARAMBASE_H_ +#endif // COMMON_CORE_PID_PARAMBASE_H_ diff --git a/Common/Core/PID/TPCPIDResponse.h b/Common/Core/PID/TPCPIDResponse.h index 8008b22d082..f25e1acd69e 100644 --- a/Common/Core/PID/TPCPIDResponse.h +++ b/Common/Core/PID/TPCPIDResponse.h @@ -62,11 +62,11 @@ class Response const std::array GetBetheBlochParams() const { return mBetheBlochParams; } const std::array GetResolutionParamsDefault() const { return mResolutionParamsDefault; } const std::vector GetResolutionParams() const { return mResolutionParams; } - const float GetMIP() const { return mMIP; } - const float GetNClNormalization() const { return nClNorm; } - const float GetChargeFactor() const { return mChargeFactor; } - const float GetMultiplicityNormalization() const { return mMultNormalization; } - const bool GetUseDefaultResolutionParam() const { return mUseDefaultResolutionParam; } + float GetMIP() const { return mMIP; } + float GetNClNormalization() const { return nClNorm; } + float GetChargeFactor() const { return mChargeFactor; } + float GetMultiplicityNormalization() const { return mMultNormalization; } + bool GetUseDefaultResolutionParam() const { return mUseDefaultResolutionParam; } /// Gets the expected signal of the track template @@ -77,6 +77,9 @@ class Response /// Gets the number of sigmas with respect the expected value template float GetNumberOfSigma(const CollisionType& collision, const TrackType& trk, const o2::track::PID::ID id) const; + // Number of sigmas with respect to expected for MC, defining a tune-on-data signal value + template + float GetNumberOfSigmaMCTuned(const CollisionType& collision, const TrackType& trk, const o2::track::PID::ID id, float mcTunedTPCSignal) const; /// Gets the deviation to the expected signal template float GetSignalDelta(const TrackType& trk, const o2::track::PID::ID id) const; @@ -154,6 +157,21 @@ inline float Response::GetNumberOfSigma(const CollisionType& collision, const Tr return ((trk.tpcSignal() - GetExpectedSignal(trk, id)) / GetExpectedSigma(collision, trk, id)); } +template +inline float Response::GetNumberOfSigmaMCTuned(const CollisionType& collision, const TrackType& trk, const o2::track::PID::ID id, float mcTunedTPCSignal) const +{ + if (GetExpectedSigma(collision, trk, id) < 0.) { + return -999.f; + } + if (GetExpectedSignal(trk, id) < 0.) { + return -999.f; + } + if (!trk.hasTPC()) { + return -999.f; + } + return ((mcTunedTPCSignal - GetExpectedSignal(trk, id)) / GetExpectedSigma(collision, trk, id)); +} + /// Gets the deviation between the actual signal and the expected signal template inline float Response::GetSignalDelta(const TrackType& trk, const o2::track::PID::ID id) const diff --git a/Common/Core/RecoDecay.h b/Common/Core/RecoDecay.h index d8bf2201b2c..2bdf3b82b60 100644 --- a/Common/Core/RecoDecay.h +++ b/Common/Core/RecoDecay.h @@ -17,13 +17,19 @@ #ifndef COMMON_CORE_RECODECAY_H_ #define COMMON_CORE_RECODECAY_H_ +// C++ includes #include // std::find #include // std::array #include // std::abs, std::sqrt -#include // std::move -#include // std::vector +#include +#include // std::move +#include // std::vector -#include "TMCProcess.h" // for VMC Particle Production Process +// ROOT includes +#include // for VMC Particle Production Process +#include // for PDG codes + +// O2 includes #include "CommonConstants/MathConstants.h" /// Base class for calculating properties of reconstructed decays @@ -34,21 +40,13 @@ /// - calculation of topological properties of secondary vertices /// - Monte Carlo matching of decays at track and particle level -class RecoDecay -{ - public: - /// Default constructor - RecoDecay() = default; - - /// Default destructor - ~RecoDecay() = default; - +struct RecoDecay { // mapping of charm-hadron origin type enum OriginType { None = 0, Prompt, NonPrompt }; - static constexpr int8_t PdgStatusCodeAfterFlavourOscillation = 92; // decay products after B0(s) flavour oscillation + static constexpr int8_t StatusCodeAfterFlavourOscillation = 92; // decay products after B0(s) flavour oscillation // Auxiliary functions @@ -214,18 +212,23 @@ class RecoDecay /// Constrains angle to be within a range. /// \note Inspired by TVector2::Phi_0_2pi in ROOT. /// \param angle angle - /// \param min minimum of the range - /// \return value within [min, min + 2π). + /// \param minimum minimum of the range + /// \param harmonic harmonic number + /// \return value of angle within [minimum, minimum + 2π / harmonic). template - static T constrainAngle(T angle, U min = 0.) + static T constrainAngle(T angle, U minimum = 0.0F, unsigned int harmonic = 1U) { - while (angle < min) { - angle += o2::constants::math::TwoPI; + auto period = o2::constants::math::TwoPI; + if (harmonic != 1U) { + period /= harmonic; } - while (angle >= min + o2::constants::math::TwoPI) { - angle -= o2::constants::math::TwoPI; + while (angle < minimum) { + angle += period; } - return (T)angle; + while (angle >= minimum + period) { + angle -= period; + } + return angle; } /// Calculates cosine of pointing angle. @@ -426,7 +429,7 @@ class RecoDecay static double m2(const std::array, N>& arrMom, const std::array& arrMass) { std::array momTotal{0., 0., 0.}; // candidate momentum vector - double energyTot{0.}; // candidate energy + double energyTot{0.}; // candidate energy for (std::size_t iProng = 0; iProng < N; ++iProng) { for (std::size_t iMom = 0; iMom < 3; ++iMom) { momTotal[iMom] += arrMom[iProng][iMom]; @@ -520,20 +523,20 @@ class RecoDecay /// Finds the mother of an MC particle by looking for the expected PDG code in the mother chain. /// \param particlesMC table with MC particles /// \param particle MC particle - /// \param PDGMother expected mother PDG code + /// \param pdgMother expected mother PDG code /// \param acceptAntiParticles switch to accept the antiparticle of the expected mother - /// \param sign antiparticle indicator of the found mother w.r.t. PDGMother; 1 if particle, -1 if antiparticle, 0 if mother not found + /// \param sign antiparticle indicator of the found mother w.r.t. pdgMother; 1 if particle, -1 if antiparticle, 0 if mother not found /// \param depthMax maximum decay tree level to check; Mothers up to this level will be considered. If -1, all levels are considered. /// \return index of the mother particle if found, -1 otherwise template static int getMother(const T& particlesMC, const typename T::iterator& particle, - int PDGMother, + int pdgMother, bool acceptAntiParticles = false, int8_t* sign = nullptr, int8_t depthMax = -1) { - int8_t sgn = 0; // 1 if the expected mother is particle, -1 if antiparticle (w.r.t. PDGMother) + int8_t sgn = 0; // 1 if the expected mother is particle, -1 if antiparticle (w.r.t. pdgMother) int indexMother = -1; // index of the final matched mother, if found int stage = 0; // mother tree level (just for debugging) bool motherFound = false; // true when the desired mother particle is found in the kine tree @@ -549,7 +552,7 @@ class RecoDecay while (!motherFound && arrayIds[-stage].size() > 0 && (depthMax < 0 || -stage < depthMax)) { // vector of mother indices for the current stage std::vector arrayIdsStage{}; - for (auto& iPart : arrayIds[-stage]) { // check all the particles that were the mothers at the previous stage + for (auto iPart : arrayIds[-stage]) { // check all the particles that were the mothers at the previous stage, o2-linter: disable=const-ref-in-for-loop (int elements) auto particleMother = particlesMC.rawIteratorAt(iPart - particlesMC.offset()); if (particleMother.has_mothers()) { for (auto iMother = particleMother.mothersIds().front(); iMother <= particleMother.mothersIds().back(); ++iMother) { // loop over the mother particles of the analysed particle @@ -558,17 +561,17 @@ class RecoDecay } auto mother = particlesMC.rawIteratorAt(iMother - particlesMC.offset()); // Check mother's PDG code. - auto PDGParticleIMother = mother.pdgCode(); // PDG code of the mother + auto pdgParticleIMother = mother.pdgCode(); // PDG code of the mother // printf("getMother: "); // for (int i = stage; i < 0; i++) // Indent to make the tree look nice. // printf(" "); - // printf("Stage %d: Mother PDG: %d, Index: %d\n", stage, PDGParticleIMother, iMother); - if (PDGParticleIMother == PDGMother) { // exact PDG match + // printf("Stage %d: Mother PDG: %d, Index: %d\n", stage, pdgParticleIMother, iMother); + if (pdgParticleIMother == pdgMother) { // exact PDG match sgn = 1; indexMother = iMother; motherFound = true; break; - } else if (acceptAntiParticles && PDGParticleIMother == -PDGMother) { // antiparticle PDG match + } else if (acceptAntiParticles && pdgParticleIMother == -pdgMother) { // antiparticle PDG match sgn = -1; indexMother = iMother; motherFound = true; @@ -585,8 +588,8 @@ class RecoDecay } if (sign) { if constexpr (acceptFlavourOscillation) { - if (std::abs(particle.getGenStatusCode()) == PdgStatusCodeAfterFlavourOscillation) { // take possible flavour oscillation of B0(s) mother into account - sgn *= -1; // select the sign of the mother after oscillation (and not before) + if (std::abs(particle.getGenStatusCode()) == StatusCodeAfterFlavourOscillation) { // take possible flavour oscillation of B0(s) mother into account + sgn *= -1; // select the sign of the mother after oscillation (and not before) } } *sign = sgn; @@ -599,15 +602,15 @@ class RecoDecay /// \param checkProcess switch to accept only decay daughters by checking the production process of MC particles /// \param particle MC particle /// \param list vector where the indices of final-state daughters will be added - /// \param arrPDGFinal array of PDG codes of particles to be considered final if found + /// \param arrPdgFinal array of PDG codes of particles to be considered final if found /// \param depthMax maximum decay tree level; Daughters at this level (or beyond) will be considered final. If -1, all levels are considered. /// \param stage decay tree level; If different from 0, the particle itself will be added in the list in case it has no daughters. - /// \note Final state is defined as particles from arrPDGFinal plus final daughters of any other decay branch. - /// \note Antiparticles of particles in arrPDGFinal are accepted as well. + /// \note Final state is defined as particles from arrPdgFinal plus final daughters of any other decay branch. + /// \note Antiparticles of particles in arrPdgFinal are accepted as well. template static void getDaughters(const T& particle, std::vector* list, - const std::array& arrPDGFinal, + const std::array& arrPdgFinal, int8_t depthMax = -1, int8_t stage = 0) { @@ -636,12 +639,12 @@ class RecoDecay // If this is not the original particle, we are at the end of this branch and this particle is final. isFinal = true; } - auto PDGParticle = std::abs(particle.pdgCode()); + auto pdgParticle = std::abs(particle.pdgCode()); // If this is not the original particle, check its PDG code. if (!isFinal && stage > 0) { // If the particle has daughters but is considered to be final, we label it as final. - for (auto PDGi : arrPDGFinal) { - if (PDGParticle == std::abs(PDGi)) { // Accept antiparticles. + for (auto pdgI : arrPdgFinal) { // o2-linter: disable=const-ref-in-for-loop (int elements) + if (pdgParticle == std::abs(pdgI)) { // Accept antiparticles. isFinal = true; break; } @@ -652,7 +655,7 @@ class RecoDecay // printf("getDaughters: "); // for (int i = 0; i < stage; i++) // Indent to make the tree look nice. // printf(" "); - // printf("Stage %d: Adding %d (PDG %d) as final daughter.\n", stage, index, PDGParticle); + // printf("Stage %d: Adding %d (PDG %d) as final daughter.\n", stage, index, pdgParticle); list->push_back(particle.globalIndex()); return; } @@ -660,39 +663,52 @@ class RecoDecay // printf("getDaughters: "); // for (int i = 0; i < stage; i++) // Indent to make the tree look nice. // printf(" "); - // printf("Stage %d: %d (PDG %d) -> %d-%d\n", stage, index, PDGParticle, indexDaughterFirst, indexDaughterLast); + // printf("Stage %d: %d (PDG %d) -> %d-%d\n", stage, index, pdgParticle, indexDaughterFirst, indexDaughterLast); // Call itself to get daughters of daughters recursively. stage++; - for (auto& dau : particle.template daughters_as::parent_t>()) { - getDaughters(dau, list, arrPDGFinal, depthMax, stage); + for (const auto& dau : particle.template daughters_as::parent_t>()) { + getDaughters(dau, list, arrPdgFinal, depthMax, stage); } } /// Checks whether the reconstructed decay candidate is the expected decay. - /// \param checkProcess switch to accept only decay daughters by checking the production process of MC particles + /// \tparam acceptFlavourOscillation switch to accept flavour oscillastion (i.e. B0 -> B0bar -> D+pi-) + /// \tparam checkProcess switch to accept only decay daughters by checking the production process of MC particles + /// \tparam acceptIncompleteReco switch to accept candidates with only part of the daughters reconstructed + /// \tparam acceptTrackDecay switch to accept candidates with daughter tracks of pions and kaons which decayed + /// \tparam acceptTrackIntWithMaterial switch to accept candidates with final (i.e. p, K, pi) daughter tracks interacting with material /// \param particlesMC table with MC particles /// \param arrDaughters array of candidate daughters - /// \param PDGMother expected mother PDG code - /// \param arrPDGDaughters array of expected daughter PDG codes + /// \param pdgMother expected mother PDG code + /// \param arrPdgDaughters array of expected daughter PDG codes /// \param acceptAntiParticles switch to accept the antiparticle version of the expected decay - /// \param sign antiparticle indicator of the found mother w.r.t. PDGMother; 1 if particle, -1 if antiparticle, 0 if mother not found + /// \param sign antiparticle indicator of the found mother w.r.t. pdgMother; 1 if particle, -1 if antiparticle, 0 if mother not found /// \param depthMax maximum decay tree level to check; Daughters up to this level will be considered. If -1, all levels are considered. + /// \param nPiToMu number of pion prongs decayed to a muon + /// \param nKaToPi number of kaon prongs decayed to a pion + /// \param nInteractionsWithMaterial number of daughter particles that interacted with material /// \return index of the mother particle if the mother and daughters are correct, -1 otherwise - template + template static int getMatchedMCRec(const T& particlesMC, const std::array& arrDaughters, - int PDGMother, - std::array arrPDGDaughters, + int pdgMother, + std::array arrPdgDaughters, bool acceptAntiParticles = false, int8_t* sign = nullptr, - int depthMax = 1) - { - // Printf("MC Rec: Expected mother PDG: %d", PDGMother); - int8_t coefFlavourOscillation = 1; // 1 if no B0(s) flavour oscillation occured, -1 else - int8_t sgn = 0; // 1 if the expected mother is particle, -1 if antiparticle (w.r.t. PDGMother) - int indexMother = -1; // index of the mother particle - std::vector arrAllDaughtersIndex; // vector of indices of all daughters of the mother of the first provided daughter - std::array arrDaughtersIndex; // array of indices of provided daughters + int depthMax = 1, + int8_t* nPiToMu = nullptr, + int8_t* nKaToPi = nullptr, + int8_t* nInteractionsWithMaterial = nullptr) + { + // Printf("MC Rec: Expected mother PDG: %d", pdgMother); + int8_t coefFlavourOscillation = 1; // 1 if no B0(s) flavour oscillation occured, -1 else + int8_t sgn = 0; // 1 if the expected mother is particle, -1 if antiparticle (w.r.t. pdgMother) + int8_t nPiToMuLocal = 0; // number of pion prongs decayed to a muon + int8_t nKaToPiLocal = 0; // number of kaon prongs decayed to a pion + int8_t nInteractionsWithMaterialLocal = 0; // number of interactions with material + int indexMother = -1; // index of the mother particle + std::vector arrAllDaughtersIndex; // vector of indices of all daughters of the mother of the first provided daughter + std::array arrDaughtersIndex; // array of indices of provided daughters if (sign) { *sign = sgn; } @@ -702,9 +718,9 @@ class RecoDecay if (!arrDaughters[iProng].has_mcParticle()) { return -1; } - auto particleI = arrDaughters[iProng].mcParticle(); // ith daughter particle - if (std::abs(particleI.getGenStatusCode()) == PdgStatusCodeAfterFlavourOscillation) { // oscillation decay product spotted - coefFlavourOscillation = -1; // select the sign of the mother after oscillation (and not before) + auto particleI = arrDaughters[iProng].mcParticle(); // ith daughter particle + if (std::abs(particleI.getGenStatusCode()) == StatusCodeAfterFlavourOscillation) { // oscillation decay product spotted + coefFlavourOscillation = -1; // select the sign of the mother after oscillation (and not before) break; } } @@ -715,12 +731,49 @@ class RecoDecay return -1; } auto particleI = arrDaughters[iProng].mcParticle(); // ith daughter particle + if constexpr (acceptTrackDecay) { + // Replace the MC particle associated with the prong by its mother for π → μ and K → π. + auto motherI = particleI.template mothers_first_as(); + auto pdgI = std::abs(particleI.pdgCode()); + auto pdgMotherI = std::abs(motherI.pdgCode()); + if (pdgI == kMuonMinus && pdgMotherI == kPiPlus) { + // π → μ + nPiToMuLocal++; + particleI = motherI; + } else if (pdgI == kPiPlus && pdgMotherI == kKPlus) { + // K → π + nKaToPiLocal++; + particleI = motherI; + } + } + if constexpr (acceptTrackIntWithMaterial) { + // Replace the MC particle associated with the prong by its mother for part → part due to material interactions. + // It keeps looking at the mother iteratively, until it finds a particle from decay or primary + auto process = particleI.getProcess(); + auto pdgI = std::abs(particleI.pdgCode()); + auto pdgMotherI = std::abs(particleI.pdgCode()); + while (process != TMCProcess::kPDecay && process != TMCProcess::kPPrimary && pdgI == pdgMotherI) { + if (!particleI.has_mothers()) { + break; + } + auto motherI = particleI.template mothers_first_as(); + pdgI = std::abs(particleI.pdgCode()); + pdgMotherI = std::abs(motherI.pdgCode()); + if (pdgI == pdgMotherI) { + particleI = motherI; + process = particleI.getProcess(); + if (process == TMCProcess::kPDecay || process == TMCProcess::kPPrimary) { // we found the original daughter that interacted with material + nInteractionsWithMaterialLocal++; + } + } + } + } arrDaughtersIndex[iProng] = particleI.globalIndex(); // Get the list of daughter indices from the mother of the first prong. if (iProng == 0) { // Get the mother index and its sign. // PDG code of the first daughter's mother determines whether the expected mother is a particle or antiparticle. - indexMother = getMother(particlesMC, particleI, PDGMother, acceptAntiParticles, &sgn, depthMax); + indexMother = getMother(particlesMC, particleI, pdgMother, acceptAntiParticles, &sgn, depthMax); // Check whether mother was found. if (indexMother <= -1) { // Printf("MC Rec: Rejected: bad mother index or PDG"); @@ -734,21 +787,21 @@ class RecoDecay return -1; } // Check that the number of direct daughters is not larger than the number of expected final daughters. - if constexpr (!checkProcess) { + if constexpr (!acceptIncompleteReco && !checkProcess) { if (particleMother.daughtersIds().back() - particleMother.daughtersIds().front() + 1 > static_cast(N)) { // Printf("MC Rec: Rejected: too many direct daughters: %d (expected %ld final)", particleMother.daughtersIds().back() - particleMother.daughtersIds().front() + 1, N); return -1; } } // Get the list of actual final daughters. - getDaughters(particleMother, &arrAllDaughtersIndex, arrPDGDaughters, depthMax); + getDaughters(particleMother, &arrAllDaughtersIndex, arrPdgDaughters, depthMax); // printf("MC Rec: Mother %d has %d final daughters:", indexMother, arrAllDaughtersIndex.size()); // for (auto i : arrAllDaughtersIndex) { // printf(" %d", i); // } // printf("\n"); // Check whether the number of actual final daughters is equal to the number of expected final daughters (i.e. the number of provided prongs). - if (arrAllDaughtersIndex.size() != N) { + if (!acceptIncompleteReco && arrAllDaughtersIndex.size() != N) { // Printf("MC Rec: Rejected: incorrect number of final daughters: %ld (expected %ld)", arrAllDaughtersIndex.size(), N); return -1; } @@ -768,18 +821,18 @@ class RecoDecay return -1; } // Check daughter's PDG code. - auto PDGParticleI = particleI.pdgCode(); // PDG code of the ith daughter - // Printf("MC Rec: Daughter %d PDG: %d", iProng, PDGParticleI); - bool isPDGFound = false; // Is the PDG code of this daughter among the remaining expected PDG codes? + auto pdgParticleI = particleI.pdgCode(); // PDG code of the ith daughter + // Printf("MC Rec: Daughter %d PDG: %d", iProng, pdgParticleI); + bool isPdgFound = false; // Is the PDG code of this daughter among the remaining expected PDG codes? for (std::size_t iProngCp = 0; iProngCp < N; ++iProngCp) { - if (PDGParticleI == coefFlavourOscillation * sgn * arrPDGDaughters[iProngCp]) { - arrPDGDaughters[iProngCp] = 0; // Remove this PDG code from the array of expected ones. - isPDGFound = true; + if (pdgParticleI == coefFlavourOscillation * sgn * arrPdgDaughters[iProngCp]) { + arrPdgDaughters[iProngCp] = 0; // Remove this PDG code from the array of expected ones. + isPdgFound = true; break; } } - if (!isPDGFound) { - // Printf("MC Rec: Rejected: bad daughter PDG: %d", PDGParticleI); + if (!isPdgFound) { + // Printf("MC Rec: Rejected: bad daughter PDG: %d", pdgParticleI); return -1; } } @@ -787,6 +840,19 @@ class RecoDecay if (sign) { *sign = sgn; } + if constexpr (acceptTrackDecay) { + if (nPiToMu) { + *nPiToMu = nPiToMuLocal; + } + if (nKaToPi) { + *nKaToPi = nKaToPiLocal; + } + } + if constexpr (acceptTrackIntWithMaterial) { + if (nInteractionsWithMaterial) { + *nInteractionsWithMaterial = nInteractionsWithMaterialLocal; + } + } return indexMother; } @@ -794,57 +860,57 @@ class RecoDecay /// \param checkProcess switch to accept only decay daughters by checking the production process of MC particles /// \param particlesMC table with MC particles /// \param candidate candidate MC particle - /// \param PDGParticle expected particle PDG code + /// \param pdgParticle expected particle PDG code /// \param acceptAntiParticles switch to accept the antiparticle - /// \param sign antiparticle indicator of the candidate w.r.t. PDGParticle; 1 if particle, -1 if antiparticle, 0 if not matched + /// \param sign antiparticle indicator of the candidate w.r.t. pdgParticle; 1 if particle, -1 if antiparticle, 0 if not matched /// \return true if PDG code of the particle is correct, false otherwise template static int isMatchedMCGen(const T& particlesMC, const U& candidate, - int PDGParticle, + int pdgParticle, bool acceptAntiParticles = false, int8_t* sign = nullptr) { - std::array arrPDGDaughters; - return isMatchedMCGen(particlesMC, candidate, PDGParticle, std::move(arrPDGDaughters), acceptAntiParticles, sign); + std::array arrPdgDaughters; + return isMatchedMCGen(particlesMC, candidate, pdgParticle, std::move(arrPdgDaughters), acceptAntiParticles, sign); } /// Check whether the MC particle is the expected one and whether it decayed via the expected decay channel. /// \param checkProcess switch to accept only decay daughters by checking the production process of MC particles /// \param particlesMC table with MC particles /// \param candidate candidate MC particle - /// \param PDGParticle expected particle PDG code - /// \param arrPDGDaughters array of expected PDG codes of daughters + /// \param pdgParticle expected particle PDG code + /// \param arrPdgDaughters array of expected PDG codes of daughters /// \param acceptAntiParticles switch to accept the antiparticle - /// \param sign antiparticle indicator of the candidate w.r.t. PDGParticle; 1 if particle, -1 if antiparticle, 0 if not matched + /// \param sign antiparticle indicator of the candidate w.r.t. pdgParticle; 1 if particle, -1 if antiparticle, 0 if not matched /// \param depthMax maximum decay tree level to check; Daughters up to this level will be considered. If -1, all levels are considered. /// \param listIndexDaughters vector of indices of found daughter /// \return true if PDG codes of the particle and its daughters are correct, false otherwise template static bool isMatchedMCGen(const T& particlesMC, const U& candidate, - int PDGParticle, - std::array arrPDGDaughters, + int pdgParticle, + std::array arrPdgDaughters, bool acceptAntiParticles = false, int8_t* sign = nullptr, int depthMax = 1, std::vector* listIndexDaughters = nullptr) { - // Printf("MC Gen: Expected particle PDG: %d", PDGParticle); + // Printf("MC Gen: Expected particle PDG: %d", pdgParticle); int8_t coefFlavourOscillation = 1; // 1 if no B0(s) flavour oscillation occured, -1 else - int8_t sgn = 0; // 1 if the expected mother is particle, -1 if antiparticle (w.r.t. PDGParticle) + int8_t sgn = 0; // 1 if the expected mother is particle, -1 if antiparticle (w.r.t. pdgParticle) if (sign) { *sign = sgn; } // Check the PDG code of the particle. - auto PDGCandidate = candidate.pdgCode(); - // Printf("MC Gen: Candidate PDG: %d", PDGCandidate); - if (PDGCandidate == PDGParticle) { // exact PDG match + auto pdgCandidate = candidate.pdgCode(); + // Printf("MC Gen: Candidate PDG: %d", pdgCandidate); + if (pdgCandidate == pdgParticle) { // exact PDG match sgn = 1; - } else if (acceptAntiParticles && PDGCandidate == -PDGParticle) { // antiparticle PDG match + } else if (acceptAntiParticles && pdgCandidate == -pdgParticle) { // antiparticle PDG match sgn = -1; } else { - // Printf("MC Gen: Rejected: bad particle PDG: %s%d != %d", acceptAntiParticles ? "abs " : "", PDGCandidate, std::abs(PDGParticle)); + // Printf("MC Gen: Rejected: bad particle PDG: %s%d != %d", acceptAntiParticles ? "abs " : "", pdgCandidate, std::abs(pdgParticle)); return false; } // Check the PDG codes of the decay products. @@ -864,7 +930,7 @@ class RecoDecay } } // Get the list of actual final daughters. - getDaughters(candidate, &arrAllDaughtersIndex, arrPDGDaughters, depthMax); + getDaughters(candidate, &arrAllDaughtersIndex, arrPdgDaughters, depthMax); // printf("MC Gen: Mother %ld has %ld final daughters:", candidate.globalIndex(), arrAllDaughtersIndex.size()); // for (auto i : arrAllDaughtersIndex) { // printf(" %d", i); @@ -877,29 +943,29 @@ class RecoDecay } if constexpr (acceptFlavourOscillation) { // Loop over decay candidate prongs to spot possible oscillation decay product - for (auto indexDaughterI : arrAllDaughtersIndex) { - auto candidateDaughterI = particlesMC.rawIteratorAt(indexDaughterI - particlesMC.offset()); // ith daughter particle - if (std::abs(candidateDaughterI.getGenStatusCode()) == PdgStatusCodeAfterFlavourOscillation) { // oscillation decay product spotted - coefFlavourOscillation = -1; // select the sign of the mother after oscillation (and not before) + for (auto indexDaughterI : arrAllDaughtersIndex) { // o2-linter: disable=const-ref-in-for-loop (int elements) + auto candidateDaughterI = particlesMC.rawIteratorAt(indexDaughterI - particlesMC.offset()); // ith daughter particle + if (std::abs(candidateDaughterI.getGenStatusCode()) == StatusCodeAfterFlavourOscillation) { // oscillation decay product spotted + coefFlavourOscillation = -1; // select the sign of the mother after oscillation (and not before) break; } } } // Check daughters' PDG codes. - for (auto indexDaughterI : arrAllDaughtersIndex) { + for (auto indexDaughterI : arrAllDaughtersIndex) { // o2-linter: disable=const-ref-in-for-loop (int elements) auto candidateDaughterI = particlesMC.rawIteratorAt(indexDaughterI - particlesMC.offset()); // ith daughter particle - auto PDGCandidateDaughterI = candidateDaughterI.pdgCode(); // PDG code of the ith daughter - // Printf("MC Gen: Daughter %d PDG: %d", indexDaughterI, PDGCandidateDaughterI); - bool isPDGFound = false; // Is the PDG code of this daughter among the remaining expected PDG codes? + auto pdgCandidateDaughterI = candidateDaughterI.pdgCode(); // PDG code of the ith daughter + // Printf("MC Gen: Daughter %d PDG: %d", indexDaughterI, pdgCandidateDaughterI); + bool isPdgFound = false; // Is the PDG code of this daughter among the remaining expected PDG codes? for (std::size_t iProngCp = 0; iProngCp < N; ++iProngCp) { - if (PDGCandidateDaughterI == coefFlavourOscillation * sgn * arrPDGDaughters[iProngCp]) { - arrPDGDaughters[iProngCp] = 0; // Remove this PDG code from the array of expected ones. - isPDGFound = true; + if (pdgCandidateDaughterI == coefFlavourOscillation * sgn * arrPdgDaughters[iProngCp]) { + arrPdgDaughters[iProngCp] = 0; // Remove this PDG code from the array of expected ones. + isPdgFound = true; break; } } - if (!isPDGFound) { - // Printf("MC Gen: Rejected: bad daughter PDG: %d", PDGCandidateDaughterI); + if (!isPdgFound) { + // Printf("MC Gen: Rejected: bad daughter PDG: %d", pdgCandidateDaughterI); return false; } } @@ -918,11 +984,13 @@ class RecoDecay /// \param particlesMC table with MC particles /// \param particle MC particle /// \param searchUpToQuark if true tag origin based on charm/beauty quark otherwise on the presence of a b-hadron or c-hadron, with c-hadrons themselves marked as prompt + /// \param idxBhadMothers optional vector of b-hadron indices (might be more than one in case of searchUpToQuark in case of beauty resonances) /// \return an integer corresponding to the origin (0: none, 1: prompt, 2: nonprompt) as in OriginType template static int getCharmHadronOrigin(const T& particlesMC, const typename T::iterator& particle, - const bool searchUpToQuark = false) + const bool searchUpToQuark = false, + std::vector* idxBhadMothers = nullptr) { int stage = 0; // mother tree level (just for debugging) @@ -930,46 +998,66 @@ class RecoDecay std::vector> arrayIds{}; std::vector initVec{particle.globalIndex()}; arrayIds.push_back(initVec); // the first vector contains the index of the original particle - auto PDGParticle = std::abs(particle.pdgCode()); + auto pdgParticle = std::abs(particle.pdgCode()); bool couldBePrompt = false; - if (PDGParticle / 100 == 4 || PDGParticle / 1000 == 4) { + if (pdgParticle / 100 == kCharm || pdgParticle / 1000 == kCharm) { couldBePrompt = true; } while (arrayIds[-stage].size() > 0) { // vector of mother indices for the current stage std::vector arrayIdsStage{}; - for (auto& iPart : arrayIds[-stage]) { // check all the particles that were the mothers at the previous stage + for (auto iPart : arrayIds[-stage]) { // check all the particles that were the mothers at the previous stage, o2-linter: disable=const-ref-in-for-loop (int elements) auto particleMother = particlesMC.rawIteratorAt(iPart - particlesMC.offset()); if (particleMother.has_mothers()) { + + // we exit immediately if searchUpToQuark is false and the first mother is a parton (an hadron should never be the mother of a parton) + if (!searchUpToQuark) { + auto mother = particlesMC.rawIteratorAt(particleMother.mothersIds().front() - particlesMC.offset()); + auto pdgParticleIMother = std::abs(mother.pdgCode()); // PDG code of the mother + if (pdgParticleIMother < 9 || (pdgParticleIMother > 20 && pdgParticleIMother < 38)) { + return OriginType::Prompt; + } + } + for (auto iMother = particleMother.mothersIds().front(); iMother <= particleMother.mothersIds().back(); ++iMother) { // loop over the mother particles of the analysed particle if (std::find(arrayIdsStage.begin(), arrayIdsStage.end(), iMother) != arrayIdsStage.end()) { // if a mother is still present in the vector, do not check it again continue; } auto mother = particlesMC.rawIteratorAt(iMother - particlesMC.offset()); // Check mother's PDG code. - auto PDGParticleIMother = std::abs(mother.pdgCode()); // PDG code of the mother + auto pdgParticleIMother = std::abs(mother.pdgCode()); // PDG code of the mother // printf("getMother: "); // for (int i = stage; i < 0; i++) // Indent to make the tree look nice. // printf(" "); - // printf("Stage %d: Mother PDG: %d, Index: %d\n", stage, PDGParticleIMother, iMother); + // printf("Stage %d: Mother PDG: %d, Index: %d\n", stage, pdgParticleIMother, iMother); if (searchUpToQuark) { - if (PDGParticleIMother == 5) { // b quark + if (idxBhadMothers) { + if (pdgParticleIMother / 100 == kBottom || // b mesons + pdgParticleIMother / 1000 == kBottom) // b baryons + { + idxBhadMothers->push_back(iMother); + } + } + if (pdgParticleIMother == kBottom) { // b quark return OriginType::NonPrompt; } - if (PDGParticleIMother == 4) { // c quark + if (pdgParticleIMother == kCharm) { // c quark return OriginType::Prompt; } } else { if ( - (PDGParticleIMother / 100 == 5 || // b mesons - PDGParticleIMother / 1000 == 5) // b baryons + (pdgParticleIMother / 100 == kBottom || // b mesons + pdgParticleIMother / 1000 == kBottom) // b baryons ) { + if (idxBhadMothers) { + idxBhadMothers->push_back(iMother); + } return OriginType::NonPrompt; } if ( - (PDGParticleIMother / 100 == 4 || // c mesons - PDGParticleIMother / 1000 == 4) // c baryons + (pdgParticleIMother / 100 == kCharm || // c mesons + pdgParticleIMother / 1000 == kCharm) // c baryons ) { couldBePrompt = true; } @@ -988,6 +1076,365 @@ class RecoDecay } return OriginType::None; } + + /// based on getCharmHardronOrigin in order to extend general particle + /// Finding the origin (from charm hadronisation or beauty-hadron decay) of paritcle (b, c and others) + /// \param particlesMC table with MC particles + /// \param particle MC particle + /// \param searchUpToQuark if true tag origin based on charm/beauty quark otherwise on the presence of a b-hadron or c-hadron + /// \param idxBhadMothers optional vector of b-hadron indices (might be more than one in case of searchUpToQuark in case of beauty resonances) + /// \return an integer corresponding to the origin (0: none(others), 1: charm, 2: beauty) as in OriginType + template + static int getParticleOrigin(const T& particlesMC, + const typename T::iterator& particle, + const bool searchUpToQuark = false, + std::vector* idxBhadMothers = nullptr) + { + int stage = 0; // mother tree level (just for debugging) + + // vector of vectors with mother indices; each line corresponds to a "stage" + std::vector> arrayIds{}; + std::vector initVec{particle.globalIndex()}; + arrayIds.push_back(initVec); // the first vector contains the index of the original particle + auto pdgParticle = std::abs(particle.pdgCode()); + bool couldBeCharm = false; + if (pdgParticle / 100 == kCharm || pdgParticle / 1000 == kCharm) { + couldBeCharm = true; + } + while (arrayIds[-stage].size() > 0) { + // vector of mother indices for the current stage + std::vector arrayIdsStage{}; + for (auto iPart : arrayIds[-stage]) { // check all the particles that were the mothers at the previous stage, o2-linter: disable=const-ref-in-for-loop (int elements) + auto particleMother = particlesMC.rawIteratorAt(iPart - particlesMC.offset()); + if (particleMother.has_mothers()) { + + // we break immediately if searchUpToQuark is false and the first mother is a parton (an hadron should never be the mother of a parton) + if (!searchUpToQuark) { + auto mother = particlesMC.rawIteratorAt(particleMother.mothersIds().front() - particlesMC.offset()); + auto pdgParticleIMother = std::abs(mother.pdgCode()); // PDG code of the mother + if (pdgParticleIMother < 9 || (pdgParticleIMother > 20 && pdgParticleIMother < 38)) { + // auto PDGPaticle = std::abs(particleMother.pdgCode()); + if ( + (pdgParticle / 100 == kBottom || // b mesons + pdgParticle / 1000 == kBottom) // b baryons + ) { + return OriginType::NonPrompt; // beauty + } + if ( + (pdgParticle / 100 == kCharm || // c mesons + pdgParticle / 1000 == kCharm) // c baryons + ) { + return OriginType::Prompt; // charm + } + break; + } + } + + for (auto iMother = particleMother.mothersIds().front(); iMother <= particleMother.mothersIds().back(); ++iMother) { // loop over the mother particles of the analysed particle + if (std::find(arrayIdsStage.begin(), arrayIdsStage.end(), iMother) != arrayIdsStage.end()) { // if a mother is still present in the vector, do not check it again + continue; + } + auto mother = particlesMC.rawIteratorAt(iMother - particlesMC.offset()); + // Check status code + // auto motherStatusCode = std::abs(mother.getGenStatusCode()); + auto pdgParticleIMother = std::abs(mother.pdgCode()); // PDG code of the mother + // Check mother's PDG code. + // printf("getMother: "); + // for (int i = stage; i < 0; i++) // Indent to make the tree look nice. + // printf(" "); + // printf("Stage %d: Mother PDG: %d, status: %d, Index: %d\n", stage, pdgParticleIMother, motherStatusCode, iMother); + + if (searchUpToQuark) { + if (idxBhadMothers) { + if (pdgParticleIMother / 100 == kBottom || // b mesons + pdgParticleIMother / 1000 == kBottom) // b baryons + { + idxBhadMothers->push_back(iMother); + } + } + if (pdgParticleIMother == kBottom) { // b quark + return OriginType::NonPrompt; // beauty + } + if (pdgParticleIMother == kCharm) { // c quark + return OriginType::Prompt; // charm + } + } else { + if ( + (pdgParticleIMother / 100 == kBottom || // b mesons + pdgParticleIMother / 1000 == kBottom) // b baryons + ) { + if (idxBhadMothers) { + idxBhadMothers->push_back(iMother); + } + return OriginType::NonPrompt; // beauty + } + if ( + (pdgParticleIMother / 100 == kCharm || // c mesons + pdgParticleIMother / 1000 == kCharm) // c baryons + ) { + couldBeCharm = true; + } + } + // add mother index in the vector for the current stage + arrayIdsStage.push_back(iMother); + } + } + } + // add vector of mother indices for the current stage + arrayIds.push_back(arrayIdsStage); + stage--; + } + if (couldBeCharm) { + return OriginType::Prompt; // charm + } + return OriginType::None; + } +}; + +/// Calculations using (pT, η, φ) coordinates, aka (transverse momentum, pseudorapidity, azimuth) +/// \tparam indexPt index of pT element +/// \tparam indexEta index of η element +/// \tparam indexPhi index of φ element +/// \tparam indexM index of mass element (optional for (pT, η, φ, m) vectors) +template +struct RecoDecayPtEtaPhiBase { + // Variable-based calculations + + /// Sets a vector from pT, η, φ variables + /// \param vecTo vector to store pT, η, φ elements + /// \param ptFrom variable with pT + /// \param etaFrom variable with η + /// \param phiFrom variable with φ + template + static void setVectorFromVariables(TVec& vecTo, TPt ptFrom, TEta etaFrom, TPhi phiFrom) + { + vecTo[indexPt] = ptFrom; + vecTo[indexEta] = etaFrom; + vecTo[indexPhi] = phiFrom; + } + + /// px as a function of pT, φ + /// \param pt pT + /// \param phi φ + template + static auto px(TPt pt, TPhi phi) + { + return pt * std::cos(phi); + } + + /// py as a function of pT, φ + /// \param pt pT + /// \param phi φ + template + static auto py(TPt pt, TPhi phi) + { + return pt * std::sin(phi); + } + + /// pz as a function of pT, η + /// \param pt pT + /// \param eta η + template + static auto pz(TPt pt, TEta eta) + { + return pt * std::sinh(eta); + } + + /// p as a function of pT, η + /// \param pt pT + /// \param eta η + template + static auto p(TPt pt, TEta eta) + { + return pt * std::cosh(eta); + } + + /// Energy as a function of pT, η, mass + /// \param pt pT + /// \param eta η + /// \param m mass + template + static auto e(TPt pt, TEta eta, TM m) + { + return RecoDecay::e(p(pt, eta), m); + } + + /// Rapidity as a function of pT, η, mass + /// \param pt pT + /// \param eta η + /// \param m mass + template + static auto y(TPt pt, TEta eta, TM m) + { + // ln[(E + pz) / √(m^2 + pT^2)] + return std::log((e(pt, eta, m) + pz(pt, eta)) / RecoDecay::sqrtSumOfSquares(m, pt)); + } + + /// Momentum vector in (px, py, pz) coordinates from pT, η, φ variables + /// \param pt pT + /// \param eta η + /// \param phi φ + /// \return std::array with px, py, pz elements + template + static auto pVector(TPt pt, TEta eta, TPhi phi) + { + return std::array{px(pt, phi), py(pt, phi), pz(pt, eta)}; + } + + // Vector-based calculations + + /// pt + /// \param vec vector with pT, η, φ elements + template + static auto pt(const TVec& vec) + { + return vec[indexPt]; + } + + /// η + /// \param vec vector with pT, η, φ elements + template + static auto eta(const TVec& vec) + { + return vec[indexEta]; + } + + /// φ + /// \param vec vector with pT, η, φ elements + template + static auto phi(const TVec& vec) + { + return vec[indexPhi]; + } + + /// Sets pT, η, φ variables from a vector + /// \param vecFrom vector with pT, η, φ elements + /// \param ptTo variable to store pT + /// \param etaTo variable to store η + /// \param phiTo variable to store φ + template + static void setVariablesFromVector(const TVec& vecFrom, TPt& ptTo, TEta& etaTo, TPhi& phiTo) + { + ptTo = pt(vecFrom); + etaTo = eta(vecFrom); + phiTo = phi(vecFrom); + } + + /// px as a function of pT, φ + /// \param vec vector with pT, η, φ elements + template + static auto px(const TVec& vec) + { + return px(pt(vec), phi(vec)); + } + + /// py as a function of pT, φ + /// \param vec vector with pT, η, φ elements + template + static auto py(const TVec& vec) + { + return py(pt(vec), phi(vec)); + } + + /// pz as a function of pT, η + /// \param vec vector with pT, η, φ elements + template + static auto pz(const TVec& vec) + { + return pz(pt(vec), eta(vec)); + } + + /// p as a function of pT, η + /// \param vec vector with pT, η, φ elements + template + static auto p(const TVec& vec) + { + return p(pt(vec), eta(vec)); + } + + /// Energy as a function of pT, η, mass + /// \param vec vector with pT, η, φ elements + /// \param m mass + template + static auto e(const TVec& vec, TM m) + { + return e(pt(vec), eta(vec), m); + } + + /// Rapidity as a function of pT, η, mass + /// \param vec vector with pT, η, φ elements + /// \param m mass + template + static auto y(const TVec& vec, TM m) + { + return y(pt(vec), eta(vec), m); + } + + /// Momentum vector in (px, py, pz) coordinates from a (pT, η, φ) vector + /// \param vec vector with pT, η, φ elements + /// \return std::array with px, py, pz elements + template + static auto pVector(const TVec& vec) + { + return std::array{px(vec), py(vec), pz(vec)}; + } + + // Calculations for (pT, η, φ, m) vectors + + /// Energy as a function of pT, η, mass + /// \param vec vector with pT, η, φ, m elements + template + static auto e(const TVec& vec) + { + return e(vec, vec[indexM]); + } + + /// Rapidity as a function of pT, η, mass + /// \param vec vector with pT, η, φ, m elements + /// \param m mass + template + static auto y(const TVec& vec) + { + return y(vec, vec[indexM]); + } + + // /// Test consistency of calculations of kinematic quantities + // /// \param pxIn px + // /// \param pyIn py + // /// \param pzIn pz + // /// \param mIn mass + // template + // static void test(T pxIn, T pyIn, T pzIn, TM mIn) + // { + // std::array vecXYZ{pxIn, pyIn, pzIn}; + // std::array vecXYZ0{0, 0, 0}; + // std::array vecPtEtaPhi; + // std::array vecPtEtaPhiM; + // setVectorFromVariables(vecPtEtaPhi, RecoDecay::pt(vecXYZ), RecoDecay::eta(vecXYZ), RecoDecay::phi(vecXYZ)); + // setVectorFromVariables(vecPtEtaPhiM, RecoDecay::pt(vecXYZ), RecoDecay::eta(vecXYZ), RecoDecay::phi(vecXYZ)); + // vecPtEtaPhiM[3] = mIn; + // auto vecXYZFromVec = pVector(vecPtEtaPhi); + // auto vecXYZFromVars = pVector(pt(vecPtEtaPhi), eta(vecPtEtaPhi), phi(vecPtEtaPhi)); + // // Test px, py, pz, pt, p, eta, phi, e, y, m + // printf("RecoDecay test\n"); + // printf("px: In: %g, XYZ: %g, XYZ from vec: %g, XYZ from vars: %g, PtEtaPhi: %g, PtEtaPhiM: %g\n", pxIn, vecXYZ[0], vecXYZFromVec[0], vecXYZFromVars[0], px(vecPtEtaPhi), px(vecPtEtaPhiM)); + // printf("py: In: %g, XYZ: %g, XYZ from vec: %g, XYZ from vars: %g, PtEtaPhi: %g, PtEtaPhiM: %g\n", pyIn, vecXYZ[1], vecXYZFromVec[1], vecXYZFromVars[1], py(vecPtEtaPhi), py(vecPtEtaPhiM)); + // printf("pz: In: %g, XYZ: %g, XYZ from vec: %g, XYZ from vars: %g, PtEtaPhi: %g, PtEtaPhiM: %g\n", pzIn, vecXYZ[2], vecXYZFromVec[2], vecXYZFromVars[2], pz(vecPtEtaPhi), pz(vecPtEtaPhiM)); + // printf("pt: XYZ: %g, PtEtaPhi: %g, PtEtaPhiM: %g\n", RecoDecay::pt(vecXYZ), pt(vecPtEtaPhi), pt(vecPtEtaPhiM)); + // printf("p: XYZ: %g, PtEtaPhi: %g, PtEtaPhiM: %g\n", RecoDecay::p(vecXYZ), p(vecPtEtaPhi), p(vecPtEtaPhiM)); + // printf("eta: XYZ: %g, PtEtaPhi: %g, PtEtaPhiM: %g\n", RecoDecay::eta(vecXYZ), eta(vecPtEtaPhi), eta(vecPtEtaPhiM)); + // printf("phi: XYZ: %g, PtEtaPhi: %g, PtEtaPhiM: %g\n", RecoDecay::phi(vecXYZ), phi(vecPtEtaPhi), phi(vecPtEtaPhiM)); + // printf("e: XYZ: %g, PtEtaPhi: %g, PtEtaPhiM: %g\n", RecoDecay::e(vecXYZ, mIn), e(vecPtEtaPhi, mIn), e(vecPtEtaPhiM)); + // printf("y: XYZ: %g, PtEtaPhi: %g, PtEtaPhiM: %g\n", RecoDecay::y(vecXYZ, mIn), y(vecPtEtaPhi, mIn), y(vecPtEtaPhiM)); + // printf("m: In: %g, XYZ(p, E): %g, XYZ(pVec, E): %g, XYZ(arr): %g, PtEtaPhiM: %g\n", + // mIn, + // RecoDecay::m(RecoDecay::p(vecXYZ), RecoDecay::e(vecXYZ, mIn)), + // RecoDecay::m(vecXYZ, RecoDecay::e(vecXYZ, mIn)), + // RecoDecay::m(std::array{vecXYZ, vecXYZ0}, std::array{mIn, 0.}), + // vecPtEtaPhiM[indexM]); + // } }; +using RecoDecayPtEtaPhi = RecoDecayPtEtaPhiBase<>; // alias for instance with default parameters + #endif // COMMON_CORE_RECODECAY_H_ diff --git a/Common/Core/TPCVDriftManager.h b/Common/Core/TPCVDriftManager.h new file mode 100644 index 00000000000..5d35db5ea99 --- /dev/null +++ b/Common/Core/TPCVDriftManager.h @@ -0,0 +1,171 @@ +// 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. + +#ifndef COMMON_CORE_TPCVDRIFTMANAGER_H_ +#define COMMON_CORE_TPCVDRIFTMANAGER_H_ + +#include + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/Logger.h" +#include "Framework/DataTypes.h" +#include "DataFormatsTPC/VDriftCorrFact.h" +#include "CommonConstants/LHCConstants.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "ReconstructionDataFormats/Track.h" + +namespace o2::aod::common +{ + +// Thin wrapper for vdrift ccdb queries should partially mirror VDriftHelper class. +// Allows to move TPC standalone tracks under the assumption of a different +// collision than the track is associated to. +class TPCVDriftManager +{ + public: + void init(o2::ccdb::BasicCCDBManager* ccdb) noexcept + { + mCCDB = ccdb; + } + + void update(uint64_t timestamp) noexcept + { + // Check validity of already present obj, otherwise update + if (mVD != nullptr && (timestamp > static_cast(mVD->firstTime) || timestamp < static_cast(mVD->lastTime))) { + return; + } + + // Update Obj + mVD = mCCDB->getForTimeStamp("TPC/Calib/VDriftTgl", timestamp); + if (mVD == nullptr || mVD->firstTime < 0 || mVD->lastTime < 0) { + LOGP(error, "Got invalid VDriftCorrFact for {}", timestamp); + mValid = false; + return; + } + + // TODO account for laser calib + + // Update factors + mTPCVDriftNS = mVD->refVDrift * mVD->corrFact * 1e-3; + + mValid = true; + LOGP(info, "Updated VDrift for timestamp {} with vdrift={:.7f} (cm/ns)", mVD->creationTime, mTPCVDriftNS); + } + + template + [[nodiscard]] bool moveTPCTrack(const Collision& col, const TrackExtra& trackExtra, Track& track) noexcept + { + ++mCalls; + + // Check if there is a good object available otherwise pretend everything is fine + if (!mValid) { + if (mInvalid < mWarningLimit) { + LOGP(warn, "No VDrift object available, pretending track to be correct"); + if (mInvalid == mWarningLimit - 1) { + LOGP(warn, "Silencing further warnings!"); + } + } + ++mInvalid; + return true; + } + + // track is fine, or cannot be moved has information is not available + if (!(trackExtra.flags() & o2::aod::track::TrackFlags::TrackTimeAsym)) { + ++mNoFlag; + return true; + } + + // TPC time is given relative to the closest BC in ns + float tTB, tTBErr; + if (col.collisionTimeRes() < 0.f) { // use track data + ++mColResNeg; + tTB = trackExtra.trackTime(); + o2::aod::track::extensions::TPCTimeErrEncoding enc; + enc.encoding.timeErr = trackExtra.trackTimeRes(); + tTBErr = 0.5f * (enc.getDeltaTFwd() + enc.getDeltaTBwd()); + } else { + ++mColResPos; + // The TPC track can be associated to a different BC than the one the collision under assumption is; + // we need to calculate the difference and subtract this from the trackTime() + const auto trackBC = trackExtra.template collision_as().template foundBC_as().globalBC(); + const auto colBC = col.template foundBC_as().globalBC(); + float sign{1.f}; + uint64_t diffBC{0}; + if (colBC < trackBC) { + sign = -1.f; + diffBC = (trackBC - colBC); + } else { + diffBC = (colBC - trackBC); + } + float diffBCNS = sign * static_cast(diffBC) * static_cast(o2::constants::lhc::LHCBunchSpacingNS); + tTB = col.collisionTime() + diffBCNS; + tTBErr = col.collisionTimeRes(); + } + float dTime = tTB - trackExtra.trackTime(); + float dDrift = dTime * mTPCVDriftNS; + float dDriftErr = tTBErr * mTPCVDriftNS; + if (dDriftErr < 0.f || dDrift > 250.f) { // we cannot move a track outside the drift volume + if (mOutside < mWarningLimit) { + LOGP(warn, "Skipping correction outside of tpc volume with dDrift={} +- {}", dDrift, dDriftErr); + const auto trackBC = trackExtra.template collision_as().template foundBC_as().globalBC(); + const auto colBC = col.template foundBC_as().globalBC(); + int diffBC = colBC - trackBC; + LOGP(info, "ct={}; ctr={}; tTB={}; t0={}; dTime={}; dDrift={}; tgl={}: colBC={} trackBC={} diffBC={}", col.collisionTime(), col.collisionTimeRes(), tTB, trackExtra.trackTime(), dTime, dDrift, track.getTgl(), colBC, trackBC, diffBC); + if (mOutside == mWarningLimit - 1) { + LOGP(warn, "Silencing further warnings!"); + } + } + ++mOutside; + return false; + } + + // impose new Z coordinate + track.setZ(track.getZ() + ((track.getTgl() < 0.) ? -dDrift : dDrift)); + if constexpr (std::is_base_of_v) { + track.setCov(track.getSigmaZ2() + dDriftErr * dDriftErr, o2::track::kSigZ2); + } + + ++mMovedTrks; + + return true; + } + + void print() noexcept + { + LOGP(info, "TPC corrections called: {}; Moved Tracks: {}; Constrained Tracks={}; No Flag: {}; NULL: {}; Outside: {}; ColResPos {}; ColResNeg {};", mCalls, mMovedTrks, mConstrained, mNoFlag, mInvalid, mOutside, mColResPos, mColResNeg); + } + + private: + bool mValid{false}; + // Factors + float mTPCVDriftNS{0.f}; // drift velocity in cm/ns + + // CCDB + const o2::tpc::VDriftCorrFact* mVD{}; // reference to drift correction + o2::ccdb::BasicCCDBManager* mCCDB{}; // reference to initialized ccdb manager + + static constexpr unsigned int mWarningLimit{10}; + + // Counters + unsigned int mCalls{0}; // total number of calls + unsigned int mMovedTrks{0}; // number of moved tracks + unsigned int mInvalid{0}; // number of tracks where no drift object was available + unsigned int mColResNeg{0}; // number of collisions with negative resolution + unsigned int mColResPos{0}; // number of collisions with positive resolution + unsigned int mNoFlag{0}; // number of tracks without flag set + unsigned int mOutside{0}; // number of tracks moved but outside of sensible volume + unsigned int mConstrained{0}; // number of constrained tracks +}; + +} // namespace o2::aod::common + +#endif // COMMON_CORE_TPCVDRIFTMANAGER_H_ diff --git a/Common/Core/TrackSelection.cxx b/Common/Core/TrackSelection.cxx index 4cc355b57ce..717d7db77f5 100644 --- a/Common/Core/TrackSelection.cxx +++ b/Common/Core/TrackSelection.cxx @@ -30,7 +30,7 @@ bool TrackSelection::FulfillsITSHitRequirements(uint8_t itsClusterMap) const return true; } -const std::string TrackSelection::mCutNames[static_cast(TrackSelection::TrackCuts::kNCuts)] = {"TrackType", "PtRange", "EtaRange", "TPCNCls", "TPCCrossedRows", "TPCCrossedRowsOverNCls", "TPCChi2NDF", "TPCRefit", "ITSNCls", "ITSChi2NDF", "ITSRefit", "ITSHits", "GoldenChi2", "DCAxy", "DCAz"}; +const std::string TrackSelection::mCutNames[static_cast(TrackSelection::TrackCuts::kNCuts)] = {"TrackType", "PtRange", "EtaRange", "TPCNCls", "TPCCrossedRows", "TPCCrossedRowsOverNCls", "TPCChi2NDF", "TPCRefit", "ITSNCls", "ITSChi2NDF", "ITSRefit", "ITSHits", "GoldenChi2", "DCAxy", "DCAz", "TPCFracSharedCls"}; void TrackSelection::SetTrackType(o2::aod::track::TrackTypeEnum trackType) { @@ -79,6 +79,11 @@ void TrackSelection::SetMinNCrossedRowsOverFindableClustersTPC(float minNCrossed mMinNCrossedRowsOverFindableClustersTPC = minNCrossedRowsOverFindableClustersTPC; LOG(info) << "Track selection, set min N crossed rows over findable clusters TPC: " << mMinNCrossedRowsOverFindableClustersTPC; } +void TrackSelection::SetMaxTPCFractionSharedCls(float maxTPCFractionSharedCls) +{ + mMaxTPCFractionSharedCls = maxTPCFractionSharedCls; + LOG(info) << "Track selection, set max fraction of shared clusters TPC: " << mMaxTPCFractionSharedCls; +} void TrackSelection::SetMinNClustersITS(int minNClustersITS) { mMinNClustersITS = minNClustersITS; @@ -175,6 +180,9 @@ void TrackSelection::print() const case TrackCuts::kDCAz: LOG(info) << mCutNames[i] << " < " << mMaxDcaZ; break; + case TrackCuts::kTPCFracSharedCls: + LOG(info) << mCutNames[i] << " < " << mMaxTPCFractionSharedCls; + break; default: LOG(fatal) << "Cut unknown!"; } diff --git a/Common/Core/TrackSelection.h b/Common/Core/TrackSelection.h index b27ee30e8fd..19d77a198e1 100644 --- a/Common/Core/TrackSelection.h +++ b/Common/Core/TrackSelection.h @@ -45,6 +45,7 @@ class TrackSelection kGoldenChi2, kDCAxy, kDCAz, + kTPCFracSharedCls, kNCuts }; @@ -53,7 +54,8 @@ class TrackSelection Run3ITSibAny, Run3ITSallAny, Run3ITSall7Layers, - Run3ITSibTwo + Run3ITSibTwo, + Run3ITSibFirst }; // Flags for the selection of the DCAxy @@ -113,6 +115,9 @@ class TrackSelection if (!IsSelected(track, TrackCuts::kDCAz)) { return false; } + if (!IsSelected(track, TrackCuts::kTPCFracSharedCls)) { + return false; + } return true; } @@ -143,6 +148,7 @@ class TrackSelection setFlag(TrackCuts::kGoldenChi2); setFlag(TrackCuts::kDCAxy); setFlag(TrackCuts::kDCAz); + setFlag(TrackCuts::kTPCFracSharedCls); return flag; } @@ -194,10 +200,12 @@ class TrackSelection return (isRun2 && mRequireGoldenChi2) ? (track.flags() & o2::aod::track::GoldenChi2) : true; case TrackCuts::kDCAxy: - return abs(track.dcaXY()) <= ((mMaxDcaXYPtDep) ? mMaxDcaXYPtDep(track.pt()) : mMaxDcaXY); + return std::fabs(track.dcaXY()) <= ((mMaxDcaXYPtDep) ? mMaxDcaXYPtDep(track.pt()) : mMaxDcaXY); case TrackCuts::kDCAz: - return abs(track.dcaZ()) <= mMaxDcaZ; + return std::fabs(track.dcaZ()) <= mMaxDcaZ; + case TrackCuts::kTPCFracSharedCls: + return track.tpcFractionSharedCls() <= mMaxTPCFractionSharedCls; default: return false; @@ -224,6 +232,7 @@ class TrackSelection void SetRequireNoHitsInITSLayers(std::set excludedLayers); /// @brief Reset ITS requirements void ResetITSRequirements() { mRequiredITSHits.clear(); } + void SetMaxTPCFractionSharedCls(float maxTPCFractionSharedCls); /// @brief Print the track selection void print() const; @@ -249,6 +258,8 @@ class TrackSelection float mMaxDcaZ{1e10f}; // max dca in z direction std::function mMaxDcaXYPtDep{}; // max dca in xy plane as function of pT + float mMaxTPCFractionSharedCls{1e10f}; // max fraction of shared TPC clusters + bool mRequireITSRefit{false}; // require refit in ITS bool mRequireTPCRefit{false}; // require refit in TPC bool mRequireGoldenChi2{false}; // require golden chi2 cut (Run 2 only) diff --git a/Common/Core/TrackSelectionDefaults.cxx b/Common/Core/TrackSelectionDefaults.cxx index a5470e34745..2958718feba 100644 --- a/Common/Core/TrackSelectionDefaults.cxx +++ b/Common/Core/TrackSelectionDefaults.cxx @@ -58,6 +58,9 @@ TrackSelection getGlobalTrackSelectionRun3ITSMatch(int matching, int passFlag) case TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSall7Layers: selectedTracks.SetRequireHitsInITSLayers(7, {0, 1, 2, 3, 4, 5, 6}); break; + case TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibFirst: + selectedTracks.SetRequireHitsInITSLayers(1, {0}); + break; default: LOG(fatal) << "getGlobalTrackSelectionRun3ITSMatch with undefined ITS matching"; break; @@ -117,12 +120,27 @@ TrackSelection getGlobalTrackSelectionRun3HF() // Reduced default track selection for jet validation based on hybrid cuts for converted (based on ESD's from run 2) A02D's TrackSelection getJEGlobalTrackSelectionRun2() { - TrackSelection selectedTracks = getGlobalTrackSelection(); - selectedTracks.SetPtRange(0.15f, 1e15f); - selectedTracks.SetRequireGoldenChi2(false); - selectedTracks.SetMaxDcaXYPtDep([](float /*pt*/) { return 1e+10; }); + TrackSelection selectedTracks; + + // These track selections are the same as the global track selections as of Jan 2025. Implemented seperately to prevent future + // global track selection changes from affecting the Run 2 hybrid track selections. + selectedTracks.SetTrackType(o2::aod::track::Run2Track); // Run 2 track asked by default + selectedTracks.SetRequireITSRefit(true); + selectedTracks.SetRequireTPCRefit(true); + selectedTracks.SetRequireGoldenChi2(true); + selectedTracks.SetMinNCrossedRowsTPC(70); + selectedTracks.SetMinNCrossedRowsOverFindableClustersTPC(0.8f); + selectedTracks.SetMaxChi2PerClusterTPC(4.f); + selectedTracks.SetMaxChi2PerClusterITS(36.f); + + // These track selections are different to the global track selections as of Jan 2025. + selectedTracks.SetPtRange(0.15f, 1000.f); selectedTracks.SetEtaRange(-0.9f, 0.9f); + selectedTracks.SetMaxDcaXYPtDep([](float /*pt*/) { return 1e+10; }); selectedTracks.SetMaxDcaXY(2.4f); selectedTracks.SetMaxDcaZ(3.2f); + selectedTracks.SetRequireHitsInITSLayers(0, {0, 1}); // no minimum required number of hits in any SPD layer + selectedTracks.SetMaxTPCFractionSharedCls(0.4f); // This cut machinery was added since it's used in hybrid tracks Run 2 + return selectedTracks; } diff --git a/Common/Core/TrackSelectorPID.h b/Common/Core/TrackSelectorPID.h index e09969ba946..214627a2d72 100644 --- a/Common/Core/TrackSelectorPID.h +++ b/Common/Core/TrackSelectorPID.h @@ -103,9 +103,10 @@ class TrackSelectorPidBase /// Checks if track is compatible with given particle species hypothesis within given TPC nσ range. /// \param track track /// \param conditionalTof variable to store the result of selection with looser cuts for conditional accepting of track if combined with TOF + /// \param tpcNSigmaCustom custom TPC nσ value to be used for the selection, in case the desired value cannot be taken from the track table /// \return true if track satisfies TPC PID hypothesis for given TPC nσ range template - bool isSelectedByTpc(const T& track, bool& conditionalTof) + bool isSelectedByTpc(const T& track, bool& conditionalTof, float tpcNSigmaCustom = -999.f) { // Accept if selection is disabled via large values. if (mNSigmaTpcMin < -999. && mNSigmaTpcMax > 999.) { @@ -128,6 +129,11 @@ class TrackSelectorPidBase errorPdg(); } + /// use custom TPC nσ, if a valid value is provided + if (tpcNSigmaCustom > -999.f) { + nSigma = tpcNSigmaCustom; + } + if (mNSigmaTpcMinCondTof < -999. && mNSigmaTpcMaxCondTof > 999.) { conditionalTof = true; } else { @@ -140,13 +146,13 @@ class TrackSelectorPidBase /// \param track track /// \return TPC selection status (see TrackSelectorPID::Status) template - TrackSelectorPID::Status statusTpc(const T& track) + TrackSelectorPID::Status statusTpc(const T& track, float tpcNSigmaCustom = -999.f) { if (!isValidForTpc(track)) { return TrackSelectorPID::NotApplicable; } bool condTof = false; - if (isSelectedByTpc(track, condTof)) { + if (isSelectedByTpc(track, condTof, tpcNSigmaCustom)) { return TrackSelectorPID::Accepted; } else if (condTof) { return TrackSelectorPID::Conditional; // potential to be accepted if combined with TOF @@ -191,9 +197,10 @@ class TrackSelectorPidBase /// Checks if track is compatible with given particle species hypothesis within given TOF nσ range. /// \param track track /// \param conditionalTpc variable to store the result of selection with looser cuts for conditional accepting of track if combined with TPC + /// \param tofNSigmaCustom custom TOF nσ value to be used for the selection, in case the desired value cannot be taken from the track table /// \return true if track satisfies TOF PID hypothesis for given TOF nσ range template - bool isSelectedByTof(const T& track, bool& conditionalTpc) + bool isSelectedByTof(const T& track, bool& conditionalTpc, float tofNSigmaCustom = -999.f) { // Accept if selection is disabled via large values. if (mNSigmaTofMin < -999. && mNSigmaTofMax > 999.) { @@ -216,6 +223,11 @@ class TrackSelectorPidBase errorPdg(); } + /// use custom TOF nσ, if a valid value is provided + if (tofNSigmaCustom > -999.f) { + nSigma = tofNSigmaCustom; + } + if (mNSigmaTofMinCondTpc < -999. && mNSigmaTofMaxCondTpc > 999.) { conditionalTpc = true; } else { @@ -228,13 +240,13 @@ class TrackSelectorPidBase /// \param track track /// \return TOF selection status (see TrackSelectorPID::Status) template - TrackSelectorPID::Status statusTof(const T& track) + TrackSelectorPID::Status statusTof(const T& track, float tofNSigmaCustom = -999.f) { if (!isValidForTof(track)) { return TrackSelectorPID::NotApplicable; } bool condTpc = false; - if (isSelectedByTof(track, condTpc)) { + if (isSelectedByTof(track, condTpc, tofNSigmaCustom)) { return TrackSelectorPID::Accepted; } else if (condTpc) { return TrackSelectorPID::Conditional; // potential to be accepted if combined with TPC @@ -391,10 +403,10 @@ class TrackSelectorPidBase /// \param track track /// \return status of combined PID (TPC or TOF) (see TrackSelectorPID::Status) template - TrackSelectorPID::Status statusTpcOrTof(const T& track) + TrackSelectorPID::Status statusTpcOrTof(const T& track, float tpcNSigmaCustom = -999.f, float tofNSigmaCustom = -999.f) { - int pidTpc = statusTpc(track); - int pidTof = statusTof(track); + int pidTpc = statusTpc(track, tpcNSigmaCustom); + int pidTof = statusTof(track, tofNSigmaCustom); if (pidTpc == TrackSelectorPID::Accepted || pidTof == TrackSelectorPID::Accepted) { return TrackSelectorPID::Accepted; @@ -412,15 +424,15 @@ class TrackSelectorPidBase /// \param track track /// \return status of combined PID (TPC and TOF) (see TrackSelectorPID::Status) template - TrackSelectorPID::Status statusTpcAndTof(const T& track) + TrackSelectorPID::Status statusTpcAndTof(const T& track, float tpcNSigmaCustom = -999.f, float tofNSigmaCustom = -999.f) { int pidTpc = TrackSelectorPID::NotApplicable; if (track.hasTPC()) { - pidTpc = statusTpc(track); + pidTpc = statusTpc(track, tpcNSigmaCustom); } int pidTof = TrackSelectorPID::NotApplicable; if (track.hasTOF()) { - pidTof = statusTof(track); + pidTof = statusTof(track, tofNSigmaCustom); } if (pidTpc == TrackSelectorPID::Accepted && pidTof == TrackSelectorPID::Accepted) { diff --git a/Common/Core/fwdtrackUtilities.h b/Common/Core/fwdtrackUtilities.h new file mode 100644 index 00000000000..13fb27c5862 --- /dev/null +++ b/Common/Core/fwdtrackUtilities.h @@ -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. + +/// \file fwdtrackUtilities.h +/// \brief Utilities for manipulating parameters of fwdtracks +/// \author Maurice Coquet +/// \author Luca Micheletti +/// \author Daiki Sekihata + +#ifndef COMMON_CORE_FWDTRACKUTILITIES_H_ +#define COMMON_CORE_FWDTRACKUTILITIES_H_ + +#include +#include +#include "Math/SMatrix.h" +#include "TGeoGlobalMagField.h" + +namespace o2::aod +{ +namespace fwdtrackutils +{ +// Index used to set different options for muon propagation +enum class propagationPoint : int { + kToVertex = 0, + kToDCA = 1, + kToRabs = 2, +}; +using SMatrix55 = ROOT::Math::SMatrix>; +using SMatrix5 = ROOT::Math::SVector; + +/// propagate fwdtrack to a certain point. +template +o2::dataformats::GlobalFwdTrack propagateMuon(TFwdTrack const& muon, TCollision const& collision, const propagationPoint endPoint) +{ + double chi2 = muon.chi2(); + SMatrix5 tpars(muon.x(), muon.y(), muon.phi(), muon.tgl(), muon.signed1Pt()); + std::vector v1{muon.cXX(), muon.cXY(), muon.cYY(), muon.cPhiX(), muon.cPhiY(), + muon.cPhiPhi(), muon.cTglX(), muon.cTglY(), muon.cTglPhi(), muon.cTglTgl(), + muon.c1PtX(), muon.c1PtY(), muon.c1PtPhi(), muon.c1PtTgl(), muon.c1Pt21Pt2()}; + SMatrix55 tcovs(v1.begin(), v1.end()); + o2::track::TrackParCovFwd fwdtrack{muon.z(), tpars, tcovs, chi2}; + o2::dataformats::GlobalFwdTrack propmuon; + o2::globaltracking::MatchGlobalFwd mMatching; + + if (static_cast(muon.trackType()) > 2) { // MCH-MID or MCH standalone + o2::dataformats::GlobalFwdTrack track; + track.setParameters(tpars); + track.setZ(fwdtrack.getZ()); + track.setCovariances(tcovs); + auto mchTrack = mMatching.FwdtoMCH(track); + + if (endPoint == propagationPoint::kToVertex) { + o2::mch::TrackExtrap::extrapToVertex(mchTrack, collision.posX(), collision.posY(), collision.posZ(), collision.covXX(), collision.covYY()); + } else if (endPoint == propagationPoint::kToDCA) { + o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchTrack, collision.posZ()); + } else if (endPoint == propagationPoint::kToRabs) { + o2::mch::TrackExtrap::extrapToZ(mchTrack, -505.); + } + + auto proptrack = mMatching.MCHtoFwd(mchTrack); + propmuon.setParameters(proptrack.getParameters()); + propmuon.setZ(proptrack.getZ()); + propmuon.setCovariances(proptrack.getCovariances()); + } else if (static_cast(muon.trackType()) < 2) { // MFT-MCH-MID + const double centerMFT[3] = {0, 0, -61.4}; + o2::field::MagneticField* field = static_cast(TGeoGlobalMagField::Instance()->GetField()); + auto Bz = field->getBz(centerMFT); // Get field at centre of MFT + auto geoMan = o2::base::GeometryManager::meanMaterialBudget(muon.x(), muon.y(), muon.z(), collision.posX(), collision.posY(), collision.posZ()); + auto x2x0 = static_cast(geoMan.meanX2X0); + if (endPoint == propagationPoint::kToVertex) { + fwdtrack.propagateToVtxhelixWithMCS(collision.posZ(), {collision.posX(), collision.posY()}, {collision.covXX(), collision.covYY()}, Bz, x2x0); + } else if (endPoint == propagationPoint::kToDCA) { + fwdtrack.propagateToZhelix(collision.posZ(), Bz); + } + propmuon.setParameters(fwdtrack.getParameters()); + propmuon.setZ(fwdtrack.getZ()); + propmuon.setCovariances(fwdtrack.getCovariances()); + } + + v1.clear(); + v1.shrink_to_fit(); + + return propmuon; +} +} // namespace fwdtrackutils +} // namespace o2::aod + +#endif // COMMON_CORE_FWDTRACKUTILITIES_H_ diff --git a/Common/DataModel/CMakeLists.txt b/Common/DataModel/CMakeLists.txt index 312e9c15225..4891b1a95e9 100644 --- a/Common/DataModel/CMakeLists.txt +++ b/Common/DataModel/CMakeLists.txt @@ -20,4 +20,9 @@ o2physics_add_header_only_library(DataModel TrackSelectionTables.h McCollisionExtra.h Qvectors.h - MftmchMatchingML.h) + MatchMFTFT0.h + MftmchMatchingML.h + ZDCInterCalib.h + EseTable.h + FwdTrackReAlignTables.h + PropagatedFwdTrackTables.h) diff --git a/Common/DataModel/Centrality.h b/Common/DataModel/Centrality.h index f89e6b23e71..c3074a63c67 100644 --- a/Common/DataModel/Centrality.h +++ b/Common/DataModel/Centrality.h @@ -17,43 +17,82 @@ namespace o2::aod { namespace cent { -DECLARE_SOA_COLUMN(CentRun2V0M, centRun2V0M, float); //! Run2 Centrality percentile estimated from V0C+V0A multiplicities -DECLARE_SOA_COLUMN(CentRun2V0A, centRun2V0A, float); //! Run2 Centrality percentile estimated from V0A multiplicities -DECLARE_SOA_COLUMN(CentRun2SPDTracklets, centRun2SPDTracklets, float); //! Run2 centrality percentile estimated from SPD tracklets multiplicity -DECLARE_SOA_COLUMN(CentRun2SPDClusters, centRun2SPDClusters, float); //! Run2 centrality percentile estimated from SPD clusters multiplicity -DECLARE_SOA_COLUMN(CentRun2CL0, centRun2CL0, float); //! Run2 centrality percentile estimated from CL0 multiplicity -DECLARE_SOA_COLUMN(CentRun2CL1, centRun2CL1, float); //! Run2 centrality percentile estimated from CL1 multiplicity -DECLARE_SOA_COLUMN(CentFV0A, centFV0A, float); //! Run3 Centrality percentile estimated from FV0A multiplicities -DECLARE_SOA_COLUMN(CentFT0M, centFT0M, float); //! Run3 centrality percentile estimated from FT0A+FT0C multiplicities -DECLARE_SOA_COLUMN(CentFT0A, centFT0A, float); //! Run3 centrality percentile estimated from FT0A multiplicity -DECLARE_SOA_COLUMN(CentFT0C, centFT0C, float); //! Run3 centrality percentile estimated from FT0C multiplicity -DECLARE_SOA_COLUMN(CentFDDM, centFDDM, float); //! Run3 centrality percentile estimated from FDDA+FDDC multiplicity -DECLARE_SOA_COLUMN(CentNTPV, centNTPV, float); //! Run3 centrality percentile estimated from the number of tracks contributing to the PV +DECLARE_SOA_COLUMN(CentRun2V0M, centRun2V0M, float); //! Run 2 cent. from V0C+V0A multiplicities +DECLARE_SOA_COLUMN(CentRun2V0A, centRun2V0A, float); //! Run 2 cent. from V0A multiplicities +DECLARE_SOA_COLUMN(CentRun2SPDTracklets, centRun2SPDTracklets, float); //! Run 2 cent. from SPD tracklets multiplicity +DECLARE_SOA_COLUMN(CentRun2SPDClusters, centRun2SPDClusters, float); //! Run 2 cent. from SPD clusters multiplicity +DECLARE_SOA_COLUMN(CentRun2CL0, centRun2CL0, float); //! Run 2 cent. from CL0 multiplicity +DECLARE_SOA_COLUMN(CentRun2CL1, centRun2CL1, float); //! Run 2 cent. from CL1 multiplicity +DECLARE_SOA_COLUMN(CentRun2RefMult5, centRun2RefMult5, float); //! Run 2 cent. from ref. mult. estimator, eta 0.5 +DECLARE_SOA_COLUMN(CentRun2RefMult8, centRun2RefMult8, float); //! Run 2 cent. from ref. mult. estimator, eta 0.8 + +DECLARE_SOA_COLUMN(CentFV0A, centFV0A, float); //! Run 3 cent. from FV0A multiplicities +DECLARE_SOA_COLUMN(CentFT0M, centFT0M, float); //! Run 3 cent. from FT0A+FT0C multiplicities +DECLARE_SOA_COLUMN(CentFT0A, centFT0A, float); //! Run 3 cent. from FT0A multiplicity +DECLARE_SOA_COLUMN(CentFT0C, centFT0C, float); //! Run 3 cent. from FT0C multiplicity +DECLARE_SOA_COLUMN(CentFT0CVariant1, centFT0CVariant1, float); //! Run 3 cent. from FT0C multiplicity +DECLARE_SOA_COLUMN(CentFDDM, centFDDM, float); //! Run 3 cent. from FDDA+FDDC multiplicity +DECLARE_SOA_COLUMN(CentNTPV, centNTPV, float); //! Run 3 cent. from the number of tracks contributing to the +DECLARE_SOA_COLUMN(CentNGlobal, centNGlobal, float); //! Run 3 cent. from the number of tracks contributing to the PV +DECLARE_SOA_COLUMN(CentMFT, centMFT, float); //! Run 3 cent. from the number of tracks in the MFT } // namespace cent -DECLARE_SOA_TABLE(CentRun2V0Ms, "AOD", "CENTRUN2V0M", cent::CentRun2V0M); //! Run2 V0M estimated centrality table -DECLARE_SOA_TABLE(CentRun2V0As, "AOD", "CENTRUN2V0A", cent::CentRun2V0A); //! Run2 V0A estimated centrality table -DECLARE_SOA_TABLE(CentRun2SPDTrks, "AOD", "CENTRUN2SPDTRK", cent::CentRun2SPDTracklets); //! Run2 SPD tracklets estimated centrality table -DECLARE_SOA_TABLE(CentRun2SPDClss, "AOD", "CENTRUN2SPDCLS", cent::CentRun2SPDClusters); //! Run2 SPD clusters estimated centrality table -DECLARE_SOA_TABLE(CentRun2CL0s, "AOD", "CENTRUN2CL0", cent::CentRun2CL0); //! Run2 CL0 estimated centrality table -DECLARE_SOA_TABLE(CentRun2CL1s, "AOD", "CENTRUN2CL1", cent::CentRun2CL1); //! Run2 CL1 estimated centrality table -DECLARE_SOA_TABLE(CentFV0As, "AOD", "CENTFV0A", cent::CentFV0A); //! Run3 FV0A estimated centrality table -DECLARE_SOA_TABLE(CentFT0Ms, "AOD", "CENTFT0M", cent::CentFT0M); //! Run3 FT0M estimated centrality table -DECLARE_SOA_TABLE(CentFT0As, "AOD", "CENTFT0A", cent::CentFT0A); //! Run3 FT0A estimated centrality table -DECLARE_SOA_TABLE(CentFT0Cs, "AOD", "CENTFT0C", cent::CentFT0C); //! Run3 FT0C estimated centrality table -DECLARE_SOA_TABLE(CentFDDMs, "AOD", "CENTFDDM", cent::CentFDDM); //! Run3 FDDM estimated centrality table -DECLARE_SOA_TABLE(CentNTPVs, "AOD", "CENTNTPV", cent::CentNTPV); //! Run3 NTPV estimated centrality table + +// Run 2 tables +DECLARE_SOA_TABLE(CentRun2V0Ms, "AOD", "CENTRUN2V0M", cent::CentRun2V0M); //! Run 2 V0M centrality table +DECLARE_SOA_TABLE(CentRun2V0As, "AOD", "CENTRUN2V0A", cent::CentRun2V0A); //! Run 2 V0A centrality table +DECLARE_SOA_TABLE(CentRun2SPDTrks, "AOD", "CENTRUN2SPDTRK", cent::CentRun2SPDTracklets); //! Run 2 SPD tracklets centrality table +DECLARE_SOA_TABLE(CentRun2SPDClss, "AOD", "CENTRUN2SPDCLS", cent::CentRun2SPDClusters); //! Run 2 SPD clusters centrality table +DECLARE_SOA_TABLE(CentRun2CL0s, "AOD", "CENTRUN2CL0", cent::CentRun2CL0); //! Run 2 CL0 centrality table +DECLARE_SOA_TABLE(CentRun2CL1s, "AOD", "CENTRUN2CL1", cent::CentRun2CL1); //! Run 2 CL1 centrality table +DECLARE_SOA_TABLE(CentRun2RefMult5s, "AOD", "CENTRUN2REFMULT5", cent::CentRun2RefMult5); //! Run 2, ref mult |eta| < 0.5 +DECLARE_SOA_TABLE(CentRun2RefMult8s, "AOD", "CENTRUN2REFMULT8", cent::CentRun2RefMult8); //! Run 2, ref mult |eta| < 0.8 + +// Run 3 tables +DECLARE_SOA_TABLE(CentFV0As, "AOD", "CENTFV0A", cent::CentFV0A); //! Run 3 FV0A centrality table +DECLARE_SOA_TABLE(CentFT0Ms, "AOD", "CENTFT0M", cent::CentFT0M); //! Run 3 FT0M centrality table +DECLARE_SOA_TABLE(CentFT0As, "AOD", "CENTFT0A", cent::CentFT0A); //! Run 3 FT0A centrality table +DECLARE_SOA_TABLE(CentFT0Cs, "AOD", "CENTFT0C", cent::CentFT0C); //! Run 3 FT0C centrality table +DECLARE_SOA_TABLE(CentFDDMs, "AOD", "CENTFDDM", cent::CentFDDM); //! Run 3 FDDM centrality table +DECLARE_SOA_TABLE(CentNTPVs, "AOD", "CENTNTPV", cent::CentNTPV); //! Run 3 NTPV centrality table +DECLARE_SOA_TABLE(CentNGlobals, "AOD", "CENTNGLOBAL", cent::CentNGlobal); //! Run 3 NGlobal centrality table +DECLARE_SOA_TABLE(CentMFTs, "AOD", "CENTMFT", cent::CentMFT); //! Run 3 MFT tracks centrality table + +// Run 3 variant tables +DECLARE_SOA_TABLE(CentFT0CVariant1s, "AOD", "CENTFT0Cvar1", cent::CentFT0CVariant1); //! Run 3 FT0C variant 1 + using CentRun2V0M = CentRun2V0Ms::iterator; using CentRun2V0A = CentRun2V0As::iterator; using CentRun2SPDTrk = CentRun2SPDTrks::iterator; using CentRun2SPDCls = CentRun2SPDClss::iterator; using CentRun2CL0 = CentRun2CL0s::iterator; using CentRun2CL1 = CentRun2CL1s::iterator; +using CentRun2RefMult5 = CentRun2RefMult5s::iterator; +using CentRun2RefMult8 = CentRun2RefMult8s::iterator; using CentFV0A = CentFV0As::iterator; using CentFT0M = CentFT0Ms::iterator; using CentFT0A = CentFT0As::iterator; using CentFT0C = CentFT0Cs::iterator; using CentFDDM = CentFDDMs::iterator; using CentNTPV = CentNTPVs::iterator; +using CentNGlobal = CentNGlobals::iterator; +using CentMFT = CentMFTs::iterator; + +template +concept HasRun2Centrality = requires(T&& t) { + { t.centRun2V0M() }; + { t.centRun2CL0() }; + { t.centRun2CL1() }; +}; + +template +concept HasCentrality = requires(T&& t) { + { t.centFV0A() }; + { t.centFT0M() }; + { t.centFT0A() }; + { t.centFT0C() }; + { t.centNTPV() }; +}; + } // namespace o2::aod #endif // COMMON_DATAMODEL_CENTRALITY_H_ diff --git a/Common/DataModel/EseTable.h b/Common/DataModel/EseTable.h new file mode 100644 index 00000000000..68ffdff450a --- /dev/null +++ b/Common/DataModel/EseTable.h @@ -0,0 +1,52 @@ +// 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. + +// q vector framework with ESE (20/08/2024) +// +/// \author Joachim Hansen +// + +#ifndef COMMON_DATAMODEL_ESETABLE_H_ +#define COMMON_DATAMODEL_ESETABLE_H_ + +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" + +namespace o2::aod +{ +namespace q_vector +{ +DECLARE_SOA_COLUMN(QPERCFT0C, qPERCFT0C, std::vector); +DECLARE_SOA_COLUMN(QPERCFT0A, qPERCFT0A, std::vector); +DECLARE_SOA_COLUMN(QPERCFV0A, qPERCFV0A, std::vector); +DECLARE_SOA_COLUMN(QPERCTPCall, qPERCTPCall, std::vector); +DECLARE_SOA_COLUMN(QPERCTPCneg, qPERCTPCneg, std::vector); +DECLARE_SOA_COLUMN(QPERCTPCpos, qPERCTPCpos, std::vector); +} // namespace q_vector +DECLARE_SOA_TABLE(QPercentileFT0Cs, "AOD", "QPERCENTILEFT0C", q_vector::QPERCFT0C); +DECLARE_SOA_TABLE(QPercentileFT0As, "AOD", "QPERCENTILEFT0A", q_vector::QPERCFT0A); +DECLARE_SOA_TABLE(QPercentileFV0As, "AOD", "QPERCENTILEFV0A", q_vector::QPERCFV0A); +DECLARE_SOA_TABLE(QPercentileTPCalls, "AOD", "QPERCENTILETPCall", q_vector::QPERCTPCall); +DECLARE_SOA_TABLE(QPercentileTPCnegs, "AOD", "QPERCENTILETPCneg", q_vector::QPERCTPCneg); +DECLARE_SOA_TABLE(QPercentileTPCposs, "AOD", "QPERCENTILETPCpos", q_vector::QPERCTPCpos); + +using QPercentileFT0C = QPercentileFT0Cs::iterator; +using QPercentileFT0A = QPercentileFT0As::iterator; +using QPercentileFV0A = QPercentileFV0As::iterator; +using QPercentileTPCall = QPercentileTPCalls::iterator; +using QPercentileTPCneg = QPercentileTPCnegs::iterator; +using QPercentileTPCpos = QPercentileTPCposs::iterator; + +} // namespace o2::aod + +#endif // COMMON_DATAMODEL_ESETABLE_H_ diff --git a/Common/DataModel/EventSelection.h b/Common/DataModel/EventSelection.h index 4d81f0ee9da..77849d0d7cf 100644 --- a/Common/DataModel/EventSelection.h +++ b/Common/DataModel/EventSelection.h @@ -8,12 +8,19 @@ // 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 EventSelection.h +/// \brief Definitions of event selection tables +/// +/// \author Evgeny Kryshen and Igor Altsybeev + #ifndef COMMON_DATAMODEL_EVENTSELECTION_H_ #define COMMON_DATAMODEL_EVENTSELECTION_H_ #include "Framework/AnalysisDataModel.h" #include "Common/CCDB/TriggerAliases.h" #include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/RCTSelectionFlags.h" namespace o2::aod { @@ -47,6 +54,7 @@ namespace evsel { DECLARE_SOA_BITMAP_COLUMN(Alias, alias, 32); //! Bitmask of fired trigger aliases (see TriggerAliases.h for definitions) DECLARE_SOA_BITMAP_COLUMN(Selection, selection, 64); //! Bitmask of selection flags (see EventSelectionParams.h for definitions) +DECLARE_SOA_BITMAP_COLUMN(Rct, rct, 32); //! Bitmask of RCT flags DECLARE_SOA_COLUMN(Sel7, sel7, bool); //! Event selection decision based on V0A & V0C DECLARE_SOA_COLUMN(Sel8, sel8, bool); //! Event selection decision based on TVX DECLARE_SOA_INDEX_COLUMN_FULL(FoundBC, foundBC, int, BCs, "_foundBC"); //! BC entry index in BCs table (-1 if doesn't exist) @@ -54,16 +62,29 @@ DECLARE_SOA_INDEX_COLUMN_FULL(FoundFT0, foundFT0, int, FT0s, "_foundFT0"); //! DECLARE_SOA_INDEX_COLUMN_FULL(FoundFV0, foundFV0, int, FV0As, "_foundFV0"); //! FV0 entry index in FV0As table (-1 if doesn't exist) DECLARE_SOA_INDEX_COLUMN_FULL(FoundFDD, foundFDD, int, FDDs, "_foundFDD"); //! FDD entry index in FDDs table (-1 if doesn't exist) DECLARE_SOA_INDEX_COLUMN_FULL(FoundZDC, foundZDC, int, Zdcs, "_foundZDC"); //! ZDC entry index in ZDCs table (-1 if doesn't exist) +DECLARE_SOA_COLUMN(NumTracksInTimeRange, trackOccupancyInTimeRange, int); //! Occupancy in specified time interval by a number of tracks from nearby collisions // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(SumAmpFT0CInTimeRange, ft0cOccupancyInTimeRange, float); //! Occupancy in specified time interval by a sum of FT0C amplitudes from nearby collisions // o2-linter: disable=name/o2-column } // namespace evsel // bc-joinable event selection decisions DECLARE_SOA_TABLE(BcSels, "AOD", "BCSEL", //! - evsel::Alias, evsel::Selection, evsel::FoundFT0Id, evsel::FoundFV0Id, evsel::FoundFDDId, evsel::FoundZDCId); + evsel::Alias, evsel::Selection, evsel::Rct, evsel::FoundFT0Id, evsel::FoundFV0Id, evsel::FoundFDDId, evsel::FoundZDCId); using BcSel = BcSels::iterator; // collision-joinable event selection decisions DECLARE_SOA_TABLE(EvSels, "AOD", "EVSEL", //! - evsel::Alias, evsel::Selection, evsel::Sel7, evsel::Sel8, evsel::FoundBCId, evsel::FoundFT0Id, evsel::FoundFV0Id, evsel::FoundFDDId, evsel::FoundZDCId); + evsel::Alias, + evsel::Selection, + evsel::Rct, + evsel::Sel7, + evsel::Sel8, + evsel::FoundBCId, + evsel::FoundFT0Id, + evsel::FoundFV0Id, + evsel::FoundFDDId, + evsel::FoundZDCId, + evsel::NumTracksInTimeRange, + evsel::SumAmpFT0CInTimeRange); using EvSel = EvSels::iterator; } // namespace o2::aod diff --git a/Common/DataModel/FwdTrackReAlignTables.h b/Common/DataModel/FwdTrackReAlignTables.h new file mode 100644 index 00000000000..e8249e56608 --- /dev/null +++ b/Common/DataModel/FwdTrackReAlignTables.h @@ -0,0 +1,155 @@ +// 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 FwdTrackReAlignTables.h +/// \brief Table definitions for re-aligned forward tracks +/// \author Chi Zhang , CEA-Saclay + +#ifndef COMMON_DATAMODEL_FWDTRACKREALIGNTABLES_H_ +#define COMMON_DATAMODEL_FWDTRACKREALIGNTABLES_H_ + +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace fwdtrackrealign +{ +// FwdTracksRealign Columns definitions +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! +DECLARE_SOA_INDEX_COLUMN(FwdTrack, fwdtrack); //! FwdTrack index +DECLARE_SOA_COLUMN(TrackType, trackType, uint8_t); //! Type of track. See enum ForwardTrackTypeEnum +DECLARE_SOA_COLUMN(X, x, float); //! TrackParFwd parameter x +DECLARE_SOA_COLUMN(Y, y, float); //! TrackParFwd parameter y +DECLARE_SOA_COLUMN(Z, z, float); //! TrackParFwd propagation parameter z +DECLARE_SOA_COLUMN(Phi, phi, float); //! TrackParFwd parameter phi; (i.e. pt pointing direction) +DECLARE_SOA_COLUMN(Tgl, tgl, float); //! TrackParFwd parameter tan(\lamba); (\lambda = 90 - \theta_{polar}) +DECLARE_SOA_COLUMN(Signed1Pt, signed1Pt, float); //! TrackParFwd parameter: charged inverse transverse momentum; (q/pt) +DECLARE_SOA_COLUMN(IsRemovable, isRemovable, int); //! flag to validate the re-aligned track +DECLARE_SOA_COLUMN(Chi2, chi2, float); //! Track chi^2 + +// FwdTracksCovRealign columns definitions +DECLARE_SOA_COLUMN(SigmaX, sigmaX, float); //! Covariance matrix +DECLARE_SOA_COLUMN(SigmaY, sigmaY, float); //! Covariance matrix +DECLARE_SOA_COLUMN(SigmaPhi, sigmaPhi, float); //! Covariance matrix +DECLARE_SOA_COLUMN(SigmaTgl, sigmaTgl, float); //! Covariance matrix +DECLARE_SOA_COLUMN(Sigma1Pt, sigma1Pt, float); //! Covariance matrix +DECLARE_SOA_COLUMN(RhoXY, rhoXY, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(RhoPhiX, rhoPhiX, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(RhoPhiY, rhoPhiY, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(RhoTglX, rhoTglX, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(RhoTglY, rhoTglY, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(RhoTglPhi, rhoTglPhi, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(Rho1PtX, rho1PtX, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(Rho1PtY, rho1PtY, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(Rho1PtPhi, rho1PtPhi, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(Rho1PtTgl, rho1PtTgl, int8_t); //! Covariance matrix in compressed form + +// Dynamic and expression columns +DECLARE_SOA_DYNAMIC_COLUMN(Sign, sign, //! Sign of the track eletric charge + [](float signed1Pt) -> short { return (signed1Pt > 0) ? 1 : -1; }); +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! + [](float pt, float phi) -> float { + return pt * std::cos(phi); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, //! + [](float pt, float phi) -> float { + return pt * std::sin(phi); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! + [](float pt, float tgl) -> float { + return pt * tgl; + }); + +DECLARE_SOA_EXPRESSION_COLUMN(Eta, eta, float, //! + -1.f * nlog(ntan(o2::constants::math::PIQuarter - 0.5f * natan(aod::fwdtrackrealign::tgl)))); +DECLARE_SOA_EXPRESSION_COLUMN(Pt, pt, float, //! + ifnode(nabs(aod::fwdtrackrealign::signed1Pt) < o2::constants::math::Almost0, o2::constants::math::VeryBig, nabs(1.f / aod::fwdtrackrealign::signed1Pt))); +DECLARE_SOA_EXPRESSION_COLUMN(P, p, float, //! + ifnode((nabs(aod::fwdtrackrealign::signed1Pt) < o2::constants::math::Almost0) || (nabs(o2::constants::math::PIQuarter - 0.5f * natan(aod::fwdtrackrealign::tgl)) < o2::constants::math::Almost0), o2::constants::math::VeryBig, 0.5f * (ntan(o2::constants::math::PIQuarter - 0.5f * natan(aod::fwdtrackrealign::tgl)) + 1.f / ntan(o2::constants::math::PIQuarter - 0.5f * natan(aod::fwdtrackrealign::tgl))) / nabs(aod::fwdtrackrealign::signed1Pt))); +DECLARE_SOA_EXPRESSION_COLUMN(CXX, cXX, float, //! + aod::fwdtrackrealign::sigmaX* aod::fwdtrackrealign::sigmaX); +DECLARE_SOA_EXPRESSION_COLUMN(CXY, cXY, float, //! + (aod::fwdtrackrealign::rhoXY / 128.f) * (aod::fwdtrackrealign::sigmaX * aod::fwdtrackrealign::sigmaY)); +DECLARE_SOA_EXPRESSION_COLUMN(CYY, cYY, float, //! + aod::fwdtrackrealign::sigmaY* aod::fwdtrackrealign::sigmaY); +DECLARE_SOA_EXPRESSION_COLUMN(CPhiX, cPhiX, float, //! + (aod::fwdtrackrealign::rhoPhiX / 128.f) * (aod::fwdtrackrealign::sigmaPhi * aod::fwdtrackrealign::sigmaX)); +DECLARE_SOA_EXPRESSION_COLUMN(CPhiY, cPhiY, float, //! + (aod::fwdtrackrealign::rhoPhiY / 128.f) * (aod::fwdtrackrealign::sigmaPhi * aod::fwdtrackrealign::sigmaY)); +DECLARE_SOA_EXPRESSION_COLUMN(CPhiPhi, cPhiPhi, float, //! + aod::fwdtrackrealign::sigmaPhi* aod::fwdtrackrealign::sigmaPhi); +DECLARE_SOA_EXPRESSION_COLUMN(CTglX, cTglX, float, //! + (aod::fwdtrackrealign::rhoTglX / 128.f) * (aod::fwdtrackrealign::sigmaTgl * aod::fwdtrackrealign::sigmaX)); +DECLARE_SOA_EXPRESSION_COLUMN(CTglY, cTglY, float, //! + (aod::fwdtrackrealign::rhoTglY / 128.f) * (aod::fwdtrackrealign::sigmaTgl * aod::fwdtrackrealign::sigmaY)); +DECLARE_SOA_EXPRESSION_COLUMN(CTglPhi, cTglPhi, float, //! + (aod::fwdtrackrealign::rhoTglPhi / 128.f) * (aod::fwdtrackrealign::sigmaTgl * aod::fwdtrackrealign::sigmaPhi)); +DECLARE_SOA_EXPRESSION_COLUMN(CTglTgl, cTglTgl, float, //! + aod::fwdtrackrealign::sigmaTgl* aod::fwdtrackrealign::sigmaTgl); +DECLARE_SOA_EXPRESSION_COLUMN(C1PtY, c1PtY, float, //! + (aod::fwdtrackrealign::rho1PtY / 128.f) * (aod::fwdtrackrealign::sigma1Pt * aod::fwdtrackrealign::sigmaY)); +DECLARE_SOA_EXPRESSION_COLUMN(C1PtX, c1PtX, float, //! + (aod::fwdtrackrealign::rho1PtX / 128.f) * (aod::fwdtrackrealign::sigma1Pt * aod::fwdtrackrealign::sigmaX)); +DECLARE_SOA_EXPRESSION_COLUMN(C1PtPhi, c1PtPhi, float, //! + (aod::fwdtrackrealign::rho1PtPhi / 128.f) * (aod::fwdtrackrealign::sigma1Pt * aod::fwdtrackrealign::sigmaPhi)); +DECLARE_SOA_EXPRESSION_COLUMN(C1PtTgl, c1PtTgl, float, //! + (aod::fwdtrackrealign::rho1PtTgl / 128.f) * (aod::fwdtrackrealign::sigma1Pt * aod::fwdtrackrealign::sigmaTgl)); +DECLARE_SOA_EXPRESSION_COLUMN(C1Pt21Pt2, c1Pt21Pt2, float, //! + aod::fwdtrackrealign::sigma1Pt* aod::fwdtrackrealign::sigma1Pt); +} // namespace fwdtrackrealign + +// Tracks including MCH and/or MCH (plus optionally MFT) //! +DECLARE_SOA_TABLE_FULL(StoredFwdTracksReAlign, "FwdTracksReAlign", "AOD", "FWDTRACKREALIGN", + o2::soa::Index<>, fwdtrackrealign::CollisionId, fwdtrackrealign::FwdTrackId, fwdtrackrealign::TrackType, fwdtrackrealign::X, fwdtrackrealign::Y, fwdtrackrealign::Z, fwdtrackrealign::Phi, fwdtrackrealign::Tgl, + fwdtrackrealign::Signed1Pt, + fwdtrackrealign::Px, + fwdtrackrealign::Py, + fwdtrackrealign::Pz, + fwdtrackrealign::Sign, + fwdtrackrealign::Chi2, + fwdtrackrealign::IsRemovable); + +DECLARE_SOA_TABLE_FULL(StoredFwdTrksCovReAlign, "FwdCovsReAlign", "AOD", "FWDCOVREALIGN", //! + fwdtrackrealign::SigmaX, fwdtrackrealign::SigmaY, fwdtrackrealign::SigmaPhi, fwdtrackrealign::SigmaTgl, fwdtrackrealign::Sigma1Pt, + fwdtrackrealign::RhoXY, fwdtrackrealign::RhoPhiY, fwdtrackrealign::RhoPhiX, fwdtrackrealign::RhoTglX, fwdtrackrealign::RhoTglY, + fwdtrackrealign::RhoTglPhi, fwdtrackrealign::Rho1PtX, fwdtrackrealign::Rho1PtY, fwdtrackrealign::Rho1PtPhi, fwdtrackrealign::Rho1PtTgl); + +// extended table with expression columns that can be used as arguments of dynamic columns +DECLARE_SOA_EXTENDED_TABLE_USER(FwdTracksReAlign, StoredFwdTracksReAlign, "FWDTRKREALIGNEXT", //! + fwdtrackrealign::Pt, + fwdtrackrealign::Eta, + fwdtrackrealign::P); // the table name has here to be the one with EXT which is not nice and under study + +// extended table with expression columns that can be used as arguments of dynamic columns +DECLARE_SOA_EXTENDED_TABLE_USER(FwdTrksCovReAlign, StoredFwdTrksCovReAlign, "FWDCOVREALIGNEXT", //! + fwdtrackrealign::CXX, + fwdtrackrealign::CXY, + fwdtrackrealign::CYY, + fwdtrackrealign::CPhiX, + fwdtrackrealign::CPhiY, + fwdtrackrealign::CPhiPhi, + fwdtrackrealign::CTglX, + fwdtrackrealign::CTglY, + fwdtrackrealign::CTglPhi, + fwdtrackrealign::CTglTgl, + fwdtrackrealign::C1PtX, + fwdtrackrealign::C1PtY, + fwdtrackrealign::C1PtPhi, + fwdtrackrealign::C1PtTgl, + fwdtrackrealign::C1Pt21Pt2); // the table name has here to be the one with EXT which is not nice and under study + +using FwdTrackRealign = FwdTracksReAlign::iterator; +using FwdTrkCovRealign = FwdTrksCovReAlign::iterator; +using FullFwdTracksRealign = soa::Join; +using FullFwdTrackRealign = FullFwdTracksRealign::iterator; +} // namespace o2::aod + +#endif // COMMON_DATAMODEL_FWDTRACKREALIGNTABLES_H_ diff --git a/Common/DataModel/MatchMFTFT0.h b/Common/DataModel/MatchMFTFT0.h new file mode 100644 index 00000000000..21ee19b696f --- /dev/null +++ b/Common/DataModel/MatchMFTFT0.h @@ -0,0 +1,34 @@ +// 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 MatchMFTFT0.h +// \author Sarah Herrmann +// +// \brief Declaration of tables useful for the matching of MFT tracks to FT0-C signals +// \date 03/09/24 + +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace indices +{ // For bctoft0c +DECLARE_SOA_ARRAY_INDEX_COLUMN(FT0, ft0s); // has_ft0s works now, without it doesn't +DECLARE_SOA_ARRAY_INDEX_COLUMN(BC, bcs); // has_bcs works now, without it doesn't +} // namespace indices +namespace ambii +{ // for MA2T +DECLARE_SOA_INDEX_COLUMN(MFTTrack, track); +} // namespace ambii +DECLARE_SOA_TABLE(MatchedToFT0, "AOD", "MAFT", indices::BCId, indices::FT0Ids); + +DECLARE_SOA_TABLE(BCofMFT, "AOD", "BCOFMFT", ambii::MFTTrackId, indices::BCIds); +} // namespace o2::aod diff --git a/Common/DataModel/MatchMFTMuonData.h b/Common/DataModel/MatchMFTMuonData.h new file mode 100644 index 00000000000..d1b59dc168c --- /dev/null +++ b/Common/DataModel/MatchMFTMuonData.h @@ -0,0 +1,135 @@ +// 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. +#ifndef COMMON_DATAMODEL_MATCHMFTMUONDATA_H_ +#define COMMON_DATAMODEL_MATCHMFTMUONDATA_H_ +#include "Framework/AnalysisDataModel.h" +#endif // COMMON_DATAMODEL_MATCHMFTMUONDATA_H_ + +namespace o2::aod +{ +namespace matching_params +{ +// matching parameters +DECLARE_SOA_COLUMN(DeltaPt, mDeltaPt, float); +DECLARE_SOA_COLUMN(DeltaEta, mDeltaEta, float); +DECLARE_SOA_COLUMN(DeltaPhi, mDeltaPhi, float); +DECLARE_SOA_COLUMN(DeltaX, mDeltaX, float); +DECLARE_SOA_COLUMN(DeltaY, mDeltaY, float); +DECLARE_SOA_COLUMN(GMuonPt, mGMuonPt, float); +DECLARE_SOA_COLUMN(GMuonEta, mGMuonEta, float); +DECLARE_SOA_COLUMN(PairQ, mPairQ, int16_t); +DECLARE_SOA_COLUMN(IsCorrectMatch, mIsCorrectMatch, bool); +} // namespace matching_params + +DECLARE_SOA_TABLE(MatchParams, "AOD", "MATCHING", + matching_params::GMuonPt, + matching_params::GMuonEta, + matching_params::PairQ, + matching_params::DeltaPt, + matching_params::DeltaX, + matching_params::DeltaY, + matching_params::DeltaEta, + matching_params::DeltaPhi, + matching_params::IsCorrectMatch); + +namespace tag_matching_params +{ +// matching parameters +DECLARE_SOA_COLUMN(DeltaPt, mDeltaPt, float); +DECLARE_SOA_COLUMN(DeltaEta, mDeltaEta, float); +DECLARE_SOA_COLUMN(DeltaPhi, mDeltaPhi, float); +DECLARE_SOA_COLUMN(DeltaX, mDeltaX, float); +DECLARE_SOA_COLUMN(DeltaY, mDeltaY, float); +DECLARE_SOA_COLUMN(GMuonPt, mGMuonPt, float); +DECLARE_SOA_COLUMN(GMuonEta, mGMuonEta, float); +DECLARE_SOA_COLUMN(PairQ, mPairQ, int16_t); +DECLARE_SOA_COLUMN(IsCorrectMatch, mIsCorrectMatch, bool); +} // namespace tag_matching_params + +DECLARE_SOA_TABLE(TagMatchParams, "AOD", "TAGMATCHING", + tag_matching_params::GMuonPt, + tag_matching_params::GMuonEta, + tag_matching_params::PairQ, + tag_matching_params::DeltaPt, + tag_matching_params::DeltaX, + tag_matching_params::DeltaY, + tag_matching_params::DeltaEta, + tag_matching_params::DeltaPhi, + tag_matching_params::IsCorrectMatch); + +namespace probe_matching_params +{ +// matching parameters +DECLARE_SOA_COLUMN(DeltaPt, mDeltaPt, float); +DECLARE_SOA_COLUMN(DeltaEta, mDeltaEta, float); +DECLARE_SOA_COLUMN(DeltaPhi, mDeltaPhi, float); +DECLARE_SOA_COLUMN(DeltaX, mDeltaX, float); +DECLARE_SOA_COLUMN(DeltaY, mDeltaY, float); +DECLARE_SOA_COLUMN(TagGMuonPt, mTagGMuonPt, float); +DECLARE_SOA_COLUMN(GMuonPt, mGMuonPt, float); +DECLARE_SOA_COLUMN(GMuonEta, mGMuonEta, float); +DECLARE_SOA_COLUMN(PairQ, mPairQ, int16_t); +DECLARE_SOA_COLUMN(IsCorrectMatch, mIsCorrectMatch, bool); +} // namespace probe_matching_params + +DECLARE_SOA_TABLE(ProbeMatchParams, "AOD", "PROBEMATCHING", + probe_matching_params::TagGMuonPt, + probe_matching_params::GMuonPt, + probe_matching_params::GMuonEta, + probe_matching_params::PairQ, + probe_matching_params::DeltaPt, + probe_matching_params::DeltaX, + probe_matching_params::DeltaY, + probe_matching_params::DeltaEta, + probe_matching_params::DeltaPhi, + probe_matching_params::IsCorrectMatch); + +namespace mix_matching_params +{ +// matching parameters +DECLARE_SOA_COLUMN(DeltaPt, mDeltaPt, float); +DECLARE_SOA_COLUMN(DeltaEta, mDeltaEta, float); +DECLARE_SOA_COLUMN(DeltaPhi, mDeltaPhi, float); +DECLARE_SOA_COLUMN(DeltaX, mDeltaX, float); +DECLARE_SOA_COLUMN(DeltaY, mDeltaY, float); +DECLARE_SOA_COLUMN(GMuonPt, mGMuonPt, float); +DECLARE_SOA_COLUMN(GMuonEta, mGMuonEta, float); +DECLARE_SOA_COLUMN(PairQ, mPairQ, int16_t); +DECLARE_SOA_COLUMN(IsCorrectMatch, mIsCorrectMatch, bool); +} // namespace mix_matching_params + +DECLARE_SOA_TABLE(MixMatchParams, "AOD", "MIXMATCHING", + mix_matching_params::GMuonPt, + mix_matching_params::GMuonEta, + mix_matching_params::PairQ, + mix_matching_params::DeltaPt, + mix_matching_params::DeltaX, + mix_matching_params::DeltaY, + mix_matching_params::DeltaEta, + mix_matching_params::DeltaPhi, + mix_matching_params::IsCorrectMatch); + +namespace muon_pair +{ +// matching parameters +DECLARE_SOA_COLUMN(Mass, mMass, float); +DECLARE_SOA_COLUMN(Pt, mPt, float); +DECLARE_SOA_COLUMN(Rap, mRap, float); +DECLARE_SOA_COLUMN(PairQ, mPairQ, int16_t); +} // namespace muon_pair + +DECLARE_SOA_TABLE(MuonPair, "AOD", "MUONPAIR", + muon_pair::PairQ, + muon_pair::Mass, + muon_pair::Pt, + muon_pair::Rap); + +} // namespace o2::aod diff --git a/Common/DataModel/Multiplicity.h b/Common/DataModel/Multiplicity.h index 23e8e043af3..ce6aa4ba046 100644 --- a/Common/DataModel/Multiplicity.h +++ b/Common/DataModel/Multiplicity.h @@ -18,19 +18,20 @@ namespace o2::aod { namespace mult { -DECLARE_SOA_COLUMN(MultFV0A, multFV0A, float); //! -DECLARE_SOA_COLUMN(MultFV0C, multFV0C, float); //! -DECLARE_SOA_COLUMN(MultFT0A, multFT0A, float); //! -DECLARE_SOA_COLUMN(MultFT0C, multFT0C, float); //! -DECLARE_SOA_COLUMN(MultFDDA, multFDDA, float); //! -DECLARE_SOA_COLUMN(MultFDDC, multFDDC, float); //! -DECLARE_SOA_COLUMN(MultZNA, multZNA, float); //! -DECLARE_SOA_COLUMN(MultZNC, multZNC, float); //! -DECLARE_SOA_COLUMN(MultZEM1, multZEM1, float); //! -DECLARE_SOA_COLUMN(MultZEM2, multZEM2, float); //! -DECLARE_SOA_COLUMN(MultZPA, multZPA, float); //! -DECLARE_SOA_COLUMN(MultZPC, multZPC, float); //! -DECLARE_SOA_DYNAMIC_COLUMN(MultFV0M, multFV0M, //! +DECLARE_SOA_COLUMN(MultFV0A, multFV0A, float); //! +DECLARE_SOA_COLUMN(MultFV0AOuter, multFV0AOuter, float); //! +DECLARE_SOA_COLUMN(MultFV0C, multFV0C, float); //! +DECLARE_SOA_COLUMN(MultFT0A, multFT0A, float); //! +DECLARE_SOA_COLUMN(MultFT0C, multFT0C, float); //! +DECLARE_SOA_COLUMN(MultFDDA, multFDDA, float); //! +DECLARE_SOA_COLUMN(MultFDDC, multFDDC, float); //! +DECLARE_SOA_COLUMN(MultZNA, multZNA, float); //! +DECLARE_SOA_COLUMN(MultZNC, multZNC, float); //! +DECLARE_SOA_COLUMN(MultZEM1, multZEM1, float); //! +DECLARE_SOA_COLUMN(MultZEM2, multZEM2, float); //! +DECLARE_SOA_COLUMN(MultZPA, multZPA, float); //! +DECLARE_SOA_COLUMN(MultZPC, multZPC, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(MultFV0M, multFV0M, //! [](float multFV0A, float multFV0C) -> float { return multFV0A + multFV0C; }); DECLARE_SOA_DYNAMIC_COLUMN(MultFT0M, multFT0M, //! [](float multFT0A, float multFT0C) -> float { return multFT0A + multFT0C; }); @@ -45,20 +46,29 @@ DECLARE_SOA_DYNAMIC_COLUMN(IsInelGt0, isInelGt0, //! is INEL > 0 [](int multPveta1) -> bool { return multPveta1 > 0; }); DECLARE_SOA_DYNAMIC_COLUMN(IsInelGt1, isInelGt1, //! is INEL > 1 [](int multPveta1) -> bool { return multPveta1 > 1; }); + +// forward track counters +DECLARE_SOA_COLUMN(MFTNalltracks, mftNalltracks, int); //! overall counter, uses AO2D coll assoc +DECLARE_SOA_COLUMN(MFTNtracks, mftNtracks, int); //! reassigned, uses mult group software + // MC DECLARE_SOA_COLUMN(MultMCFT0A, multMCFT0A, int); //! DECLARE_SOA_COLUMN(MultMCFT0C, multMCFT0C, int); //! +DECLARE_SOA_COLUMN(MultMCFV0A, multMCFV0A, int); //! +DECLARE_SOA_COLUMN(MultMCFDDA, multMCFDDA, int); //! +DECLARE_SOA_COLUMN(MultMCFDDC, multMCFDDC, int); //! DECLARE_SOA_COLUMN(MultMCNParticlesEta10, multMCNParticlesEta10, int); //! DECLARE_SOA_COLUMN(MultMCNParticlesEta08, multMCNParticlesEta08, int); //! DECLARE_SOA_COLUMN(MultMCNParticlesEta05, multMCNParticlesEta05, int); //! +DECLARE_SOA_COLUMN(MultMCPVz, multMCPVz, float); //! // complementary / MultsExtra table -DECLARE_SOA_COLUMN(MultPVTotalContributors, multPVTotalContributors, int); //! -DECLARE_SOA_COLUMN(MultPVChi2, multPVChi2, float); //! -DECLARE_SOA_COLUMN(MultCollisionTimeRes, multCollisionTimeRes, float); //! -DECLARE_SOA_COLUMN(MultRunNumber, multRunNumber, int); //! -DECLARE_SOA_COLUMN(MultPVz, multPVz, float); //! -DECLARE_SOA_COLUMN(MultSel8, multSel8, bool); //! +DECLARE_SOA_COLUMN(MultPVTotalContributors, multPVTotalContributors, int); //! +DECLARE_SOA_COLUMN(MultPVChi2, multPVChi2, float); //! +DECLARE_SOA_COLUMN(MultCollisionTimeRes, multCollisionTimeRes, float); //! +DECLARE_SOA_COLUMN(MultRunNumber, multRunNumber, int); //! +DECLARE_SOA_COLUMN(MultPVz, multPVz, float); //! +DECLARE_SOA_COLUMN(MultSel8, multSel8, bool); //! DECLARE_SOA_COLUMN(MultNTracksHasITS, multNTracksHasITS, int); //! DECLARE_SOA_COLUMN(MultNTracksHasTPC, multNTracksHasTPC, int); //! @@ -66,19 +76,28 @@ DECLARE_SOA_COLUMN(MultNTracksHasTOF, multNTracksHasTOF, int); //! DECLARE_SOA_COLUMN(MultNTracksHasTRD, multNTracksHasTRD, int); //! // further QA -DECLARE_SOA_COLUMN(MultNTracksITSOnly, multNTracksITSOnly, int); //! -DECLARE_SOA_COLUMN(MultNTracksTPCOnly, multNTracksTPCOnly, int); //! -DECLARE_SOA_COLUMN(MultNTracksITSTPC, multNTracksITSTPC, int); //! +DECLARE_SOA_COLUMN(MultNTracksITSOnly, multNTracksITSOnly, int); //! +DECLARE_SOA_COLUMN(MultNTracksTPCOnly, multNTracksTPCOnly, int); //! +DECLARE_SOA_COLUMN(MultNTracksITSTPC, multNTracksITSTPC, int); //! DECLARE_SOA_COLUMN(MultAllTracksTPCOnly, multAllTracksTPCOnly, int); //! DECLARE_SOA_COLUMN(MultAllTracksITSTPC, multAllTracksITSTPC, int); //! DECLARE_SOA_COLUMN(MultNTracksGlobal, multNTracksGlobal, int); //! +DECLARE_SOA_COLUMN(MultNGlobalTracksPV, multNGlobalTracksPV, int); +DECLARE_SOA_COLUMN(MultNGlobalTracksPVeta1, multNGlobalTracksPVeta1, int); +DECLARE_SOA_COLUMN(MultNGlobalTracksPVetaHalf, multNGlobalTracksPVetaHalf, int); -DECLARE_SOA_COLUMN(BCNumber, bcNumber, int); //! +// even further QA: timing information for neighboring events +DECLARE_SOA_COLUMN(TimeToPrePrevious, timeToPrePrevious, float); //! +DECLARE_SOA_COLUMN(TimeToPrevious, timeToPrevious, float); //! +DECLARE_SOA_COLUMN(TimeToNext, timeToNext, float); //! +DECLARE_SOA_COLUMN(TimeToNeNext, timeToNeNext, float); //! } // namespace mult DECLARE_SOA_TABLE(FV0Mults, "AOD", "FV0MULT", //! Multiplicity with the FV0 detector mult::MultFV0A, mult::MultFV0C, mult::MultFV0M); +DECLARE_SOA_TABLE(FV0AOuterMults, "AOD", "FVOAOUTERMULT", //! FV0 without innermost ring + mult::MultFV0AOuter); DECLARE_SOA_TABLE(FT0Mults, "AOD", "FT0MULT", //! Multiplicity with the FT0 detector mult::MultFT0A, mult::MultFT0C, mult::MultFT0M); @@ -97,27 +116,86 @@ DECLARE_SOA_TABLE(PVMults, "AOD", "PVMULT", //! Multiplicity from the PV contrib mult::MultNTracksPVetaHalf, mult::IsInelGt0, mult::IsInelGt1); +DECLARE_SOA_TABLE(MFTMults, "AOD", "MFTMULT", //! Multiplicity with MFT + mult::MFTNalltracks, mult::MFTNtracks); using BarrelMults = soa::Join; using Mults = soa::Join; +using FT0Mult = FT0Mults::iterator; +using MFTMult = MFTMults::iterator; using Mult = Mults::iterator; -// for QA purposes -DECLARE_SOA_TABLE(MultsExtra, "AOD", "MULTEXTRA", //! +DECLARE_SOA_TABLE(MultsExtra_000, "AOD", "MULTEXTRA", //! mult::MultPVTotalContributors, mult::MultPVChi2, mult::MultCollisionTimeRes, mult::MultRunNumber, mult::MultPVz, mult::MultSel8, mult::MultNTracksHasITS, mult::MultNTracksHasTPC, mult::MultNTracksHasTOF, mult::MultNTracksHasTRD, mult::MultNTracksITSOnly, mult::MultNTracksTPCOnly, mult::MultNTracksITSTPC, mult::MultAllTracksTPCOnly, mult::MultAllTracksITSTPC, - mult::BCNumber); + evsel::NumTracksInTimeRange, + collision::Flags); + +DECLARE_SOA_TABLE_VERSIONED(MultsExtra_001, "AOD", "MULTEXTRA", 1, //! debug information + mult::MultPVTotalContributors, mult::MultPVChi2, mult::MultCollisionTimeRes, mult::MultRunNumber, mult::MultPVz, mult::MultSel8, + mult::MultNTracksHasITS, mult::MultNTracksHasTPC, mult::MultNTracksHasTOF, mult::MultNTracksHasTRD, + mult::MultNTracksITSOnly, mult::MultNTracksTPCOnly, mult::MultNTracksITSTPC, + mult::MultAllTracksTPCOnly, mult::MultAllTracksITSTPC, + evsel::NumTracksInTimeRange, + evsel::SumAmpFT0CInTimeRange, + collision::Flags); + +using MultsExtra = MultsExtra_001; + +DECLARE_SOA_TABLE(MultNeighs, "AOD", "MULTNEIGH", //! + mult::TimeToPrePrevious, mult::TimeToPrevious, + mult::TimeToNext, mult::TimeToNeNext); // for QA purposes DECLARE_SOA_TABLE(MultsGlobal, "AOD", "MULTGLOBAL", //! counters that use Track Selection (optional) - mult::MultNTracksGlobal); + mult::MultNTracksGlobal, + mult::MultNGlobalTracksPV, + mult::MultNGlobalTracksPVeta1, + mult::MultNGlobalTracksPVetaHalf); DECLARE_SOA_TABLE(MultSelections, "AOD", "MULTSELECTIONS", //! evsel::Selection); // for derived data / QA studies using MultExtra = MultsExtra::iterator; -DECLARE_SOA_TABLE(MultsExtraMC, "AOD", "MULTEXTRAMC", //! Table for the MC information - mult::MultMCFT0A, mult::MultMCFT0C, mult::MultMCNParticlesEta05, mult::MultMCNParticlesEta08, mult::MultMCNParticlesEta10, o2::soa::Marker<1>); -using MultExtraMC = MultsExtraMC::iterator; + +// mc collisions table - indexed to Mult +DECLARE_SOA_TABLE(MultMCExtras_000, "AOD", "MULTMCEXTRA", //! Table for MC information + mult::MultMCFT0A, + mult::MultMCFT0C, + mult::MultMCNParticlesEta05, + mult::MultMCNParticlesEta08, + mult::MultMCNParticlesEta10, + mult::MultMCPVz, + mult::IsInelGt0, + mult::IsInelGt1, + o2::soa::Marker<1>); + +// mc collisions table - indexed to Mult +DECLARE_SOA_TABLE_VERSIONED(MultMCExtras_001, "AOD", "MULTMCEXTRA", 1, //! Table for MC information + mult::MultMCFT0A, + mult::MultMCFT0C, + mult::MultMCFV0A, + mult::MultMCFDDA, + mult::MultMCFDDC, + mult::MultMCNParticlesEta05, + mult::MultMCNParticlesEta08, + mult::MultMCNParticlesEta10, + mult::MultMCPVz, + mult::IsInelGt0, + mult::IsInelGt1, + o2::soa::Marker<1>); + +using MultMCExtras = MultMCExtras_001; +using MultMCExtra = MultMCExtras::iterator; +using MultsExtraMC = MultMCExtras; // for backwards compatibility with previous naming scheme + +// crosslinks +namespace mult +{ +DECLARE_SOA_INDEX_COLUMN(MultMCExtra, multMCExtra); +} + +DECLARE_SOA_TABLE(Mult2MCExtras, "AOD", "Mult2MCEXTRA", //! Relate reco mult entry to MC extras entry + o2::soa::Index<>, mult::MultMCExtraId); namespace multZeq { @@ -139,49 +217,60 @@ DECLARE_SOA_TABLE(PVMultZeqs, "AOD", "PVMULTZEQ", //! Multiplicity equalized for using MultZeqs = soa::Join; using MultZeq = MultZeqs::iterator; +namespace mult +{ +// extra BC information +DECLARE_SOA_COLUMN(MultTVX, multTVX, bool); //! +DECLARE_SOA_COLUMN(MultFV0OrA, multFV0OrA, bool); //! +DECLARE_SOA_COLUMN(MultV0triggerBits, multV0triggerBits, uint8_t); //! +DECLARE_SOA_COLUMN(MultT0triggerBits, multT0triggerBits, uint8_t); //! +DECLARE_SOA_COLUMN(MultFDDtriggerBits, multFDDtriggerBits, uint8_t); //! +DECLARE_SOA_COLUMN(MultTriggerMask, multTriggerMask, uint64_t); //! CTP trigger mask +DECLARE_SOA_COLUMN(MultCollidingBC, multCollidingBC, bool); //! CTP trigger mask + +DECLARE_SOA_COLUMN(MultFT0PosZ, multFT0PosZ, float); //! Position along Z computed with the FT0 information within the BC +DECLARE_SOA_COLUMN(MultFT0PosZValid, multFT0PosZValid, bool); //! Validity of the position along Z computed with the FT0 information +} // namespace mult +DECLARE_SOA_TABLE(MultBCs, "AOD", "MULTBC", //! + mult::MultFT0A, + mult::MultFT0C, + mult::MultFT0PosZ, + mult::MultFT0PosZValid, + mult::MultFV0A, + mult::MultFDDA, + mult::MultFDDC, + mult::MultZNA, + mult::MultZNC, + mult::MultZEM1, + mult::MultZEM2, + mult::MultZPA, + mult::MultZPC, + mult::MultTVX, + mult::MultFV0OrA, + mult::MultV0triggerBits, + mult::MultT0triggerBits, + mult::MultFDDtriggerBits, + mult::MultTriggerMask, + mult::MultCollidingBC, + timestamp::Timestamp, + bc::Flags); +using MultBC = MultBCs::iterator; + +// crosslinks +namespace mult +{ +DECLARE_SOA_INDEX_COLUMN(MultBC, multBC); +} namespace multBC { -DECLARE_SOA_COLUMN(MultBCFT0A, multBCFT0A, float); //! -DECLARE_SOA_COLUMN(MultBCFT0C, multBCFT0C, float); //! -DECLARE_SOA_COLUMN(MultBCFV0A, multBCFV0A, float); //! -DECLARE_SOA_COLUMN(MultBCFDDA, multBCFDDA, float); //! -DECLARE_SOA_COLUMN(MultBCFDDC, multBCFDDC, float); //! - -DECLARE_SOA_COLUMN(MultBCFZNA, multBCFZNA, float); //! -DECLARE_SOA_COLUMN(MultBCFZNC, multBCFZNC, float); //! -DECLARE_SOA_COLUMN(MultBCFZEM1, multBCFZEM1, float); //! -DECLARE_SOA_COLUMN(MultBCFZEM2, multBCFZEM2, float); //! -DECLARE_SOA_COLUMN(MultBCFZPA, multBCFZPA, float); //! -DECLARE_SOA_COLUMN(MultBCFZPC, multBCFZPC, float); //! - -DECLARE_SOA_COLUMN(MultBCTVX, multBCTVX, bool); //! -DECLARE_SOA_COLUMN(MultBCFV0OrA, multBCFV0OrA, bool); //! -DECLARE_SOA_COLUMN(MultBCV0triggerBits, multBCV0triggerBits, uint8_t); //! -DECLARE_SOA_COLUMN(MultBCT0triggerBits, multBCT0triggerBits, uint8_t); //! -DECLARE_SOA_COLUMN(MultBCFDDtriggerBits, multBCFDDtriggerBits, uint8_t); //! -DECLARE_SOA_COLUMN(MultBCTriggerMask, multBCTriggerMask, uint64_t); //! CTP trigger mask -DECLARE_SOA_COLUMN(MultBCColliding, multBCColliding, bool); //! CTP trigger mask -} // namespace multBC -DECLARE_SOA_TABLE(MultsBC, "AOD", "MULTBC", //! - multBC::MultBCFT0A, - multBC::MultBCFT0C, - multBC::MultBCFV0A, - multBC::MultBCFDDA, - multBC::MultBCFDDC, - multBC::MultBCFZNA, - multBC::MultBCFZNC, - multBC::MultBCFZEM1, - multBC::MultBCFZEM2, - multBC::MultBCFZPA, - multBC::MultBCFZPC, - multBC::MultBCTVX, - multBC::MultBCFV0OrA, - multBC::MultBCV0triggerBits, - multBC::MultBCT0triggerBits, - multBC::MultBCFDDtriggerBits, - multBC::MultBCTriggerMask, - multBC::MultBCColliding); -using MultBC = MultsBC::iterator; +DECLARE_SOA_INDEX_COLUMN(FT0Mult, ft0Mult); +} + +// for QA purposes +DECLARE_SOA_TABLE(Mults2BC, "AOD", "MULTS2BC", //! Relate mult -> BC + o2::soa::Index<>, mult::MultBCId); +DECLARE_SOA_TABLE(BC2Mults, "AOD", "BC2MULTS", //! Relate BC -> mult + o2::soa::Index<>, multBC::FT0MultId); } // namespace o2::aod diff --git a/Common/DataModel/OccupancyTables.h b/Common/DataModel/OccupancyTables.h new file mode 100644 index 00000000000..e8f33b90990 --- /dev/null +++ b/Common/DataModel/OccupancyTables.h @@ -0,0 +1,345 @@ +// 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 OccupancyTables.h +/// \brief Occupancy Table Header : TPC PID - Calibration +/// +/// \author Rahul Verma (rahul.verma@iitb.ac.in) :: Marian I Ivanov (marian.ivanov@cern.ch) + +#include + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" + +#ifndef COMMON_DATAMODEL_OCCUPANCYTABLES_H_ +#define COMMON_DATAMODEL_OCCUPANCYTABLES_H_ + +namespace o2::aod +{ +namespace occp +{ +DECLARE_SOA_COLUMN(TfId, tfId, int64_t); +DECLARE_SOA_COLUMN(BcsInTFList, bcsInTFList, std::vector); + +DECLARE_SOA_COLUMN(OccPrimUnfm80, occPrimUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccFV0AUnfm80, occFV0AUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccFV0CUnfm80, occFV0CUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccFT0AUnfm80, occFT0AUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccFT0CUnfm80, occFT0CUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccFDDAUnfm80, occFDDAUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccFDDCUnfm80, occFDDCUnfm80, std::vector); + +DECLARE_SOA_COLUMN(OccNTrackITSUnfm80, occNTrackITSUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccNTrackTPCUnfm80, occNTrackTPCUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccNTrackTRDUnfm80, occNTrackTRDUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccNTrackTOFUnfm80, occNTrackTOFUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccNTrackSizeUnfm80, occNTrackSizeUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccNTrackTPCAUnfm80, occNTrackTPCAUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccNTrackTPCCUnfm80, occNTrackTPCCUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccNTrackITSTPCUnfm80, occNTrackITSTPCUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccNTrackITSTPCAUnfm80, occNTrackITSTPCAUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccNTrackITSTPCCUnfm80, occNTrackITSTPCCUnfm80, std::vector); + +DECLARE_SOA_COLUMN(OccMultNTracksHasITSUnfm80, occMultNTracksHasITSUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccMultNTracksHasTPCUnfm80, occMultNTracksHasTPCUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccMultNTracksHasTOFUnfm80, occMultNTracksHasTOFUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccMultNTracksHasTRDUnfm80, occMultNTracksHasTRDUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccMultNTracksITSOnlyUnfm80, occMultNTracksITSOnlyUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccMultNTracksTPCOnlyUnfm80, occMultNTracksTPCOnlyUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccMultNTracksITSTPCUnfm80, occMultNTracksITSTPCUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccMultAllTracksTPCOnlyUnfm80, occMultAllTracksTPCOnlyUnfm80, std::vector); + +DECLARE_SOA_COLUMN(OccRobustT0V0PrimUnfm80, occRobustT0V0PrimUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccRobustFDDT0V0PrimUnfm80, occRobustFDDT0V0PrimUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccRobustNtrackDetUnfm80, occRobustNtrackDetUnfm80, std::vector); +DECLARE_SOA_COLUMN(OccRobustMultExtraTableUnfm80, occRobustMultExtraTableUnfm80, std::vector); + +DECLARE_SOA_COLUMN(MeanOccPrimUnfm80, meanOccPrimUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccFV0AUnfm80, meanOccFV0AUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccFV0CUnfm80, meanOccFV0CUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccFT0AUnfm80, meanOccFT0AUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccFT0CUnfm80, meanOccFT0CUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccFDDAUnfm80, meanOccFDDAUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccFDDCUnfm80, meanOccFDDCUnfm80, float); + +DECLARE_SOA_COLUMN(MeanOccNTrackITSUnfm80, meanOccNTrackITSUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackTPCUnfm80, meanOccNTrackTPCUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackTRDUnfm80, meanOccNTrackTRDUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackTOFUnfm80, meanOccNTrackTOFUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackSizeUnfm80, meanOccNTrackSizeUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackTPCAUnfm80, meanOccNTrackTPCAUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackTPCCUnfm80, meanOccNTrackTPCCUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackITSTPCUnfm80, meanOccNTrackITSTPCUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackITSTPCAUnfm80, meanOccNTrackITSTPCAUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackITSTPCCUnfm80, meanOccNTrackITSTPCCUnfm80, float); + +DECLARE_SOA_COLUMN(MeanOccMultNTracksHasITSUnfm80, meanOccMultNTracksHasITSUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccMultNTracksHasTPCUnfm80, meanOccMultNTracksHasTPCUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccMultNTracksHasTOFUnfm80, meanOccMultNTracksHasTOFUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccMultNTracksHasTRDUnfm80, meanOccMultNTracksHasTRDUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccMultNTracksITSOnlyUnfm80, meanOccMultNTracksITSOnlyUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccMultNTracksTPCOnlyUnfm80, meanOccMultNTracksTPCOnlyUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccMultNTracksITSTPCUnfm80, meanOccMultNTracksITSTPCUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccMultAllTracksTPCOnlyUnfm80, meanOccMultAllTracksTPCOnlyUnfm80, float); + +DECLARE_SOA_COLUMN(MeanOccRobustT0V0PrimUnfm80, meanOccRobustT0V0PrimUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccRobustFDDT0V0PrimUnfm80, meanOccRobustFDDT0V0PrimUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccRobustNtrackDetUnfm80, meanOccRobustNtrackDetUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccRobustMultExtraTableUnfm80, meanOccRobustMultExtraTableUnfm80, float); +} // namespace occp + +DECLARE_SOA_TABLE(OccsBCsList, "AOD", "OCCSBCSLIST", o2::soa::Index<>, o2::aod::occp::TfId, o2::aod::occp::BcsInTFList); +DECLARE_SOA_TABLE(OccsDet, "AOD", "OCCSDET", o2::soa::Index<>, + o2::aod::occp::OccPrimUnfm80, + o2::aod::occp::OccFV0AUnfm80, + o2::aod::occp::OccFV0CUnfm80, + o2::aod::occp::OccFT0AUnfm80, + o2::aod::occp::OccFT0CUnfm80, + o2::aod::occp::OccFDDAUnfm80, + o2::aod::occp::OccFDDCUnfm80); + +DECLARE_SOA_TABLE(OccsTrackMult, "AOD", "OCCSTRACKMULT", o2::soa::Index<>, + o2::aod::occp::OccNTrackITSUnfm80, + o2::aod::occp::OccNTrackTPCUnfm80, + o2::aod::occp::OccNTrackTRDUnfm80, + o2::aod::occp::OccNTrackTOFUnfm80, + o2::aod::occp::OccNTrackSizeUnfm80, + o2::aod::occp::OccNTrackTPCAUnfm80, + o2::aod::occp::OccNTrackTPCCUnfm80, + o2::aod::occp::OccNTrackITSTPCUnfm80, + o2::aod::occp::OccNTrackITSTPCAUnfm80, + o2::aod::occp::OccNTrackITSTPCCUnfm80); + +DECLARE_SOA_TABLE(OccsMultExtra, "AOD", "OCCSMULTEXTRA", o2::soa::Index<>, + o2::aod::occp::OccMultNTracksHasITSUnfm80, + o2::aod::occp::OccMultNTracksHasTPCUnfm80, + o2::aod::occp::OccMultNTracksHasTOFUnfm80, + o2::aod::occp::OccMultNTracksHasTRDUnfm80, + o2::aod::occp::OccMultNTracksITSOnlyUnfm80, + o2::aod::occp::OccMultNTracksTPCOnlyUnfm80, + o2::aod::occp::OccMultNTracksITSTPCUnfm80, + o2::aod::occp::OccMultAllTracksTPCOnlyUnfm80); + +DECLARE_SOA_TABLE(OccsRobust, "AOD", "OCCSROBUST", o2::soa::Index<>, + o2::aod::occp::OccRobustT0V0PrimUnfm80, + o2::aod::occp::OccRobustFDDT0V0PrimUnfm80, + o2::aod::occp::OccRobustNtrackDetUnfm80, + o2::aod::occp::OccRobustMultExtraTableUnfm80); + +DECLARE_SOA_TABLE(OccsMeanDet, "AOD", "OCCSMEANDET", o2::soa::Index<>, + o2::aod::occp::MeanOccPrimUnfm80, + o2::aod::occp::MeanOccFV0AUnfm80, + o2::aod::occp::MeanOccFV0CUnfm80, + o2::aod::occp::MeanOccFT0AUnfm80, + o2::aod::occp::MeanOccFT0CUnfm80, + o2::aod::occp::MeanOccFDDAUnfm80, + o2::aod::occp::MeanOccFDDCUnfm80); + +DECLARE_SOA_TABLE(OccsMeanTrkMult, "AOD", "OCCSMEANTRKMULT", o2::soa::Index<>, + o2::aod::occp::MeanOccNTrackITSUnfm80, + o2::aod::occp::MeanOccNTrackTPCUnfm80, + o2::aod::occp::MeanOccNTrackTRDUnfm80, + o2::aod::occp::MeanOccNTrackTOFUnfm80, + o2::aod::occp::MeanOccNTrackSizeUnfm80, + o2::aod::occp::MeanOccNTrackTPCAUnfm80, + o2::aod::occp::MeanOccNTrackTPCCUnfm80, + o2::aod::occp::MeanOccNTrackITSTPCUnfm80, + o2::aod::occp::MeanOccNTrackITSTPCAUnfm80, + o2::aod::occp::MeanOccNTrackITSTPCCUnfm80); + +DECLARE_SOA_TABLE(OccsMnMultExtra, "AOD", "OCCSMNMULTEXTRA", o2::soa::Index<>, + o2::aod::occp::MeanOccMultNTracksHasITSUnfm80, + o2::aod::occp::MeanOccMultNTracksHasTPCUnfm80, + o2::aod::occp::MeanOccMultNTracksHasTOFUnfm80, + o2::aod::occp::MeanOccMultNTracksHasTRDUnfm80, + o2::aod::occp::MeanOccMultNTracksITSOnlyUnfm80, + o2::aod::occp::MeanOccMultNTracksTPCOnlyUnfm80, + o2::aod::occp::MeanOccMultNTracksITSTPCUnfm80, + o2::aod::occp::MeanOccMultAllTracksTPCOnlyUnfm80); + +DECLARE_SOA_TABLE(OccsMeanRobust, "AOD", "OCCSMEANROBUST", o2::soa::Index<>, + o2::aod::occp::MeanOccRobustT0V0PrimUnfm80, + o2::aod::occp::MeanOccRobustFDDT0V0PrimUnfm80, + o2::aod::occp::MeanOccRobustNtrackDetUnfm80, + o2::aod::occp::MeanOccRobustMultExtraTableUnfm80); + +using Occs = aod::OccsBCsList; +using Occ = Occs::iterator; + +namespace occidx +{ +DECLARE_SOA_INDEX_COLUMN(BC, bc); // Iterator is passed here in index column +DECLARE_SOA_INDEX_COLUMN(Occ, occ); +DECLARE_SOA_COLUMN(TfId, tfId, int); +DECLARE_SOA_COLUMN(BcInTF, bcInTF, int); +} // namespace occidx + +// DECLARE_SOA_TABLE(OccIndexTable, "AOD", "OCCINDEXTABLE", o2::soa::Index<>, +DECLARE_SOA_INDEX_TABLE_USER(OccIndexTable, Occs, "OCCINDEXTABLE", + o2::aod::occidx::BCId, + o2::aod::occidx::OccId); + +DECLARE_SOA_TABLE(BCTFinfoTable, "AOD", "BCTFINFOTABLE", o2::soa::Index<>, + o2::aod::occidx::TfId, + o2::aod::occidx::BcInTF); + +namespace trackmeanocc +{ +DECLARE_SOA_INDEX_COLUMN(Track, track); + +DECLARE_SOA_COLUMN(MeanOccPrimUnfm80, meanOccPrimUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccFV0AUnfm80, meanOccFV0AUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccFV0CUnfm80, meanOccFV0CUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccFT0AUnfm80, meanOccFT0AUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccFT0CUnfm80, meanOccFT0CUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccFDDAUnfm80, meanOccFDDAUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccFDDCUnfm80, meanOccFDDCUnfm80, float); + +DECLARE_SOA_COLUMN(MeanOccNTrackITSUnfm80, meanOccNTrackITSUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackTPCUnfm80, meanOccNTrackTPCUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackTRDUnfm80, meanOccNTrackTRDUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackTOFUnfm80, meanOccNTrackTOFUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackSizeUnfm80, meanOccNTrackSizeUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackTPCAUnfm80, meanOccNTrackTPCAUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackTPCCUnfm80, meanOccNTrackTPCCUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackITSTPCUnfm80, meanOccNTrackITSTPCUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackITSTPCAUnfm80, meanOccNTrackITSTPCAUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccNTrackITSTPCCUnfm80, meanOccNTrackITSTPCCUnfm80, float); + +DECLARE_SOA_COLUMN(MeanOccMultNTracksHasITSUnfm80, meanOccMultNTracksHasITSUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccMultNTracksHasTPCUnfm80, meanOccMultNTracksHasTPCUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccMultNTracksHasTOFUnfm80, meanOccMultNTracksHasTOFUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccMultNTracksHasTRDUnfm80, meanOccMultNTracksHasTRDUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccMultNTracksITSOnlyUnfm80, meanOccMultNTracksITSOnlyUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccMultNTracksTPCOnlyUnfm80, meanOccMultNTracksTPCOnlyUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccMultNTracksITSTPCUnfm80, meanOccMultNTracksITSTPCUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccMultAllTracksTPCOnlyUnfm80, meanOccMultAllTracksTPCOnlyUnfm80, float); + +DECLARE_SOA_COLUMN(MeanOccRobustT0V0PrimUnfm80, meanOccRobustT0V0PrimUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccRobustFDDT0V0PrimUnfm80, meanOccRobustFDDT0V0PrimUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccRobustNtrackDetUnfm80, meanOccRobustNtrackDetUnfm80, float); +DECLARE_SOA_COLUMN(MeanOccRobustMultExtraTableUnfm80, meanOccRobustMultExtraTableUnfm80, float); + +DECLARE_SOA_COLUMN(WeightMeanOccPrimUnfm80, weightMeanOccPrimUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccFV0AUnfm80, weightMeanOccFV0AUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccFV0CUnfm80, weightMeanOccFV0CUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccFT0AUnfm80, weightMeanOccFT0AUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccFT0CUnfm80, weightMeanOccFT0CUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccFDDAUnfm80, weightMeanOccFDDAUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccFDDCUnfm80, weightMeanOccFDDCUnfm80, float); + +DECLARE_SOA_COLUMN(WeightMeanOccNTrackITSUnfm80, weightMeanOccNTrackITSUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccNTrackTPCUnfm80, weightMeanOccNTrackTPCUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccNTrackTRDUnfm80, weightMeanOccNTrackTRDUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccNTrackTOFUnfm80, weightMeanOccNTrackTOFUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccNTrackSizeUnfm80, weightMeanOccNTrackSizeUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccNTrackTPCAUnfm80, weightMeanOccNTrackTPCAUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccNTrackTPCCUnfm80, weightMeanOccNTrackTPCCUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccNTrackITSTPCUnfm80, weightMeanOccNTrackITSTPCUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccNTrackITSTPCAUnfm80, weightMeanOccNTrackITSTPCAUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccNTrackITSTPCCUnfm80, weightMeanOccNTrackITSTPCCUnfm80, float); + +DECLARE_SOA_COLUMN(WeightMeanOccMultNTracksHasITSUnfm80, weightMeanOccMultNTracksHasITSUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccMultNTracksHasTPCUnfm80, weightMeanOccMultNTracksHasTPCUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccMultNTracksHasTOFUnfm80, weightMeanOccMultNTracksHasTOFUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccMultNTracksHasTRDUnfm80, weightMeanOccMultNTracksHasTRDUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccMultNTracksITSOnlyUnfm80, weightMeanOccMultNTracksITSOnlyUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccMultNTracksTPCOnlyUnfm80, weightMeanOccMultNTracksTPCOnlyUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccMultNTracksITSTPCUnfm80, weightMeanOccMultNTracksITSTPCUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccMultAllTracksTPCOnlyUnfm80, weightMeanOccMultAllTracksTPCOnlyUnfm80, float); + +DECLARE_SOA_COLUMN(WeightMeanOccRobustT0V0PrimUnfm80, weightMeanOccRobustT0V0PrimUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccRobustFDDT0V0PrimUnfm80, weightMeanOccRobustFDDT0V0PrimUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccRobustNtrackDetUnfm80, weightMeanOccRobustNtrackDetUnfm80, float); +DECLARE_SOA_COLUMN(WeightMeanOccRobustMultExtraTableUnfm80, weightMeanOccRobustMultExtraTableUnfm80, float); + +} // namespace trackmeanocc + +// Tracks +// using Tracks = aod::Tracks; +// DECLARE_SOA_INDEX_TABLE_USER(TrackMeanOccs0, Tracks, "TRACKMEANOCCS0", o2::aod::trackmeanocc::TrackId); +DECLARE_SOA_TABLE(TrackMeanOccs0, "AOD", "TRACKMEANOCCS0", o2::aod::trackmeanocc::TrackId); + +DECLARE_SOA_TABLE(TrackMeanOccs1, "AOD", "TRACKMEANOCCS1", o2::soa::Index<>, // TrackMeanOccDet + o2::aod::trackmeanocc::MeanOccPrimUnfm80, + o2::aod::trackmeanocc::MeanOccFV0AUnfm80, + o2::aod::trackmeanocc::MeanOccFV0CUnfm80, + o2::aod::trackmeanocc::MeanOccFT0AUnfm80, + o2::aod::trackmeanocc::MeanOccFT0CUnfm80, + o2::aod::trackmeanocc::MeanOccFDDAUnfm80, + o2::aod::trackmeanocc::MeanOccFDDCUnfm80); + +DECLARE_SOA_TABLE(TrackMeanOccs2, "AOD", "TRACKMEANOCCS2", o2::soa::Index<>, // TrackMeanOccTrackMult + o2::aod::trackmeanocc::MeanOccNTrackITSUnfm80, + o2::aod::trackmeanocc::MeanOccNTrackTPCUnfm80, + o2::aod::trackmeanocc::MeanOccNTrackTRDUnfm80, + o2::aod::trackmeanocc::MeanOccNTrackTOFUnfm80, + o2::aod::trackmeanocc::MeanOccNTrackSizeUnfm80, + o2::aod::trackmeanocc::MeanOccNTrackTPCAUnfm80, + o2::aod::trackmeanocc::MeanOccNTrackTPCCUnfm80, + o2::aod::trackmeanocc::MeanOccNTrackITSTPCUnfm80, + o2::aod::trackmeanocc::MeanOccNTrackITSTPCAUnfm80, + o2::aod::trackmeanocc::MeanOccNTrackITSTPCCUnfm80); + +DECLARE_SOA_TABLE(TrackMeanOccs3, "AOD", "TRACKMEANOCCS3", o2::soa::Index<>, // TrackMeanOccMultExtra + o2::aod::trackmeanocc::MeanOccMultNTracksHasITSUnfm80, + o2::aod::trackmeanocc::MeanOccMultNTracksHasTPCUnfm80, + o2::aod::trackmeanocc::MeanOccMultNTracksHasTOFUnfm80, + o2::aod::trackmeanocc::MeanOccMultNTracksHasTRDUnfm80, + o2::aod::trackmeanocc::MeanOccMultNTracksITSOnlyUnfm80, + o2::aod::trackmeanocc::MeanOccMultNTracksTPCOnlyUnfm80, + o2::aod::trackmeanocc::MeanOccMultNTracksITSTPCUnfm80, + o2::aod::trackmeanocc::MeanOccMultAllTracksTPCOnlyUnfm80); + +DECLARE_SOA_TABLE(TrackMeanOccs4, "AOD", "TRACKMEANOCCS4", o2::soa::Index<>, // TrackMeanOccRobus + o2::aod::trackmeanocc::MeanOccRobustT0V0PrimUnfm80, + o2::aod::trackmeanocc::MeanOccRobustFDDT0V0PrimUnfm80, + o2::aod::trackmeanocc::MeanOccRobustNtrackDetUnfm80, + o2::aod::trackmeanocc::MeanOccRobustMultExtraTableUnfm80); + +DECLARE_SOA_TABLE(TrackMeanOccs5, "AOD", "TRACKMEANOCCS5", o2::soa::Index<>, // TrackWieghtMeanOccDet + o2::aod::trackmeanocc::WeightMeanOccPrimUnfm80, + o2::aod::trackmeanocc::WeightMeanOccFV0AUnfm80, + o2::aod::trackmeanocc::WeightMeanOccFV0CUnfm80, + o2::aod::trackmeanocc::WeightMeanOccFT0AUnfm80, + o2::aod::trackmeanocc::WeightMeanOccFT0CUnfm80, + o2::aod::trackmeanocc::WeightMeanOccFDDAUnfm80, + o2::aod::trackmeanocc::WeightMeanOccFDDCUnfm80); + +DECLARE_SOA_TABLE(TrackMeanOccs6, "AOD", "TRACKMEANOCCS6", o2::soa::Index<>, // TrackWieghtMeanOccMult + o2::aod::trackmeanocc::WeightMeanOccNTrackITSUnfm80, + o2::aod::trackmeanocc::WeightMeanOccNTrackTPCUnfm80, + o2::aod::trackmeanocc::WeightMeanOccNTrackTRDUnfm80, + o2::aod::trackmeanocc::WeightMeanOccNTrackTOFUnfm80, + o2::aod::trackmeanocc::WeightMeanOccNTrackSizeUnfm80, + o2::aod::trackmeanocc::WeightMeanOccNTrackTPCAUnfm80, + o2::aod::trackmeanocc::WeightMeanOccNTrackTPCCUnfm80, + o2::aod::trackmeanocc::WeightMeanOccNTrackITSTPCUnfm80, + o2::aod::trackmeanocc::WeightMeanOccNTrackITSTPCAUnfm80, + o2::aod::trackmeanocc::WeightMeanOccNTrackITSTPCCUnfm80) + +DECLARE_SOA_TABLE(TrackMeanOccs7, "AOD", "TRACKMEANOCCS7", o2::soa::Index<>, // TrackWeightMeanOccMultExtra + o2::aod::trackmeanocc::WeightMeanOccMultNTracksHasITSUnfm80, + o2::aod::trackmeanocc::WeightMeanOccMultNTracksHasTPCUnfm80, + o2::aod::trackmeanocc::WeightMeanOccMultNTracksHasTOFUnfm80, + o2::aod::trackmeanocc::WeightMeanOccMultNTracksHasTRDUnfm80, + o2::aod::trackmeanocc::WeightMeanOccMultNTracksITSOnlyUnfm80, + o2::aod::trackmeanocc::WeightMeanOccMultNTracksTPCOnlyUnfm80, + o2::aod::trackmeanocc::WeightMeanOccMultNTracksITSTPCUnfm80, + o2::aod::trackmeanocc::WeightMeanOccMultAllTracksTPCOnlyUnfm80); + +DECLARE_SOA_TABLE(TrackMeanOccs8, "AOD", "TRACKMEANOCCS8", o2::soa::Index<>, // TrackWieghtMeanOccRboust + o2::aod::trackmeanocc::WeightMeanOccRobustT0V0PrimUnfm80, + o2::aod::trackmeanocc::WeightMeanOccRobustFDDT0V0PrimUnfm80, + o2::aod::trackmeanocc::WeightMeanOccRobustNtrackDetUnfm80, + o2::aod::trackmeanocc::WeightMeanOccRobustMultExtraTableUnfm80); +} // namespace o2::aod +#endif // COMMON_DATAMODEL_OCCUPANCYTABLES_H_ diff --git a/Common/DataModel/PIDResponse.h b/Common/DataModel/PIDResponse.h index 555e479eecd..90eb0e55112 100644 --- a/Common/DataModel/PIDResponse.h +++ b/Common/DataModel/PIDResponse.h @@ -94,9 +94,9 @@ template using hasTPCAl = decltype(std::declval().tpcNSigmaAl()); // PID index as template argument -#define perSpeciesWrapper(functionName) \ +#define PER_SPECIES_WRAPPER(functionName) \ template \ - const auto functionName(const TrackType& track) \ + auto functionName(const TrackType& track) \ { \ if constexpr (index == o2::track::PID::Electron) { \ return track.functionName##El(); \ @@ -119,10 +119,10 @@ using hasTPCAl = decltype(std::declval().tpcNSigmaAl()); } \ } -perSpeciesWrapper(tofNSigma); -perSpeciesWrapper(tofExpSigma); +PER_SPECIES_WRAPPER(tofNSigma); +PER_SPECIES_WRAPPER(tofExpSigma); template -const auto tofExpSignal(const TrackType& track) +auto tofExpSignal(const TrackType& track) { if constexpr (index == o2::track::PID::Electron) { return track.tofExpSignalEl(track.tofSignal()); @@ -144,12 +144,12 @@ const auto tofExpSignal(const TrackType& track) return track.tofExpSignalAl(track.tofSignal()); } } -perSpeciesWrapper(tofExpSignalDiff); +PER_SPECIES_WRAPPER(tofExpSignalDiff); -perSpeciesWrapper(tpcNSigma); -perSpeciesWrapper(tpcExpSigma); +PER_SPECIES_WRAPPER(tpcNSigma); +PER_SPECIES_WRAPPER(tpcExpSigma); template -const auto tpcExpSignal(const TrackType& track) +auto tpcExpSignal(const TrackType& track) { if constexpr (index == o2::track::PID::Electron) { return track.tpcExpSignalEl(track.tpcSignal()); @@ -171,14 +171,14 @@ const auto tpcExpSignal(const TrackType& track) return track.tpcExpSignalAl(track.tpcSignal()); } } -perSpeciesWrapper(tpcExpSignalDiff); +PER_SPECIES_WRAPPER(tpcExpSignalDiff); -#undef perSpeciesWrapper +#undef PER_SPECIES_WRAPPER // PID index as function argument for TOF -#define perSpeciesWrapper(functionName) \ +#define PER_SPECIES_WRAPPER(functionName) \ template \ - const auto functionName(const o2::track::PID::ID index, const TrackType& track) \ + auto functionName(const o2::track::PID::ID index, const TrackType& track) \ { \ switch (index) { \ case o2::track::PID::Electron: \ @@ -223,10 +223,10 @@ perSpeciesWrapper(tpcExpSignalDiff); } \ } -perSpeciesWrapper(tofNSigma); -perSpeciesWrapper(tofExpSigma); +PER_SPECIES_WRAPPER(tofNSigma); +PER_SPECIES_WRAPPER(tofExpSigma); template -const auto tofExpSignal(const o2::track::PID::ID index, const TrackType& track) +auto tofExpSignal(const o2::track::PID::ID index, const TrackType& track) { switch (index) { case o2::track::PID::Electron: @@ -270,14 +270,14 @@ const auto tofExpSignal(const o2::track::PID::ID index, const TrackType& track) return 0.f; } } -perSpeciesWrapper(tofExpSignalDiff); +PER_SPECIES_WRAPPER(tofExpSignalDiff); -#undef perSpeciesWrapper +#undef PER_SPECIES_WRAPPER // PID index as function argument for TPC -#define perSpeciesWrapper(functionName) \ +#define PER_SPECIES_WRAPPER(functionName) \ template \ - const auto functionName(const o2::track::PID::ID index, const TrackType& track) \ + auto functionName(const o2::track::PID::ID index, const TrackType& track) \ { \ switch (index) { \ case o2::track::PID::Electron: \ @@ -322,10 +322,10 @@ perSpeciesWrapper(tofExpSignalDiff); } \ } -perSpeciesWrapper(tpcNSigma); -perSpeciesWrapper(tpcExpSigma); +PER_SPECIES_WRAPPER(tpcNSigma); +PER_SPECIES_WRAPPER(tpcExpSigma); template -const auto tpcExpSignal(const o2::track::PID::ID index, const TrackType& track) +auto tpcExpSignal(const o2::track::PID::ID index, const TrackType& track) { switch (index) { case o2::track::PID::Electron: @@ -369,9 +369,9 @@ const auto tpcExpSignal(const o2::track::PID::ID index, const TrackType& track) return 0.f; } } -perSpeciesWrapper(tpcExpSignalDiff); +PER_SPECIES_WRAPPER(tpcExpSignalDiff); -#undef perSpeciesWrapper +#undef PER_SPECIES_WRAPPER } // namespace pidutils @@ -403,9 +403,18 @@ DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeTOFT0AC, isEvTimeTOFT0AC, //! True if the Eve namespace pidtofsignal { -DECLARE_SOA_COLUMN(TOFSignal, tofSignal, float); //! TOF signal from track time +DECLARE_SOA_COLUMN(TOFSignal, tofSignal, float); //! TOF signal from track time +DECLARE_SOA_DYNAMIC_COLUMN(EventCollisionTime, eventCollisionTime, //! Event collision time used for the track. Needs the TOF + [](float signal, float tMinusTexp, float texp) -> float { return texp + tMinusTexp - signal; }); + } // namespace pidtofsignal +namespace pidtofevtime +{ +DECLARE_SOA_COLUMN(TOFEvTime, tofEvTime, float); //! event time for TOF signal. Can be obtained via a combination of detectors e.g. TOF, FT0A, FT0C +DECLARE_SOA_COLUMN(TOFEvTimeErr, tofEvTimeErr, float); //! event time error for TOF. Can be obtained via a combination of detectors e.g. TOF, FT0A, FT0C +} // namespace pidtofevtime + namespace pidtofbeta { DECLARE_SOA_COLUMN(Beta, beta, float); //! TOF beta @@ -528,7 +537,12 @@ DEFINE_UNWRAP_NSIGMA_COLUMN(TOFNSigmaAl, tofNSigmaAl); //! Unwrapped (float) nsi } // namespace pidtof_tiny DECLARE_SOA_TABLE(TOFSignal, "AOD", "TOFSignal", //! Table of the TOF signal - pidtofsignal::TOFSignal); + pidtofsignal::TOFSignal, + pidtofsignal::EventCollisionTime); + +DECLARE_SOA_TABLE(TOFEvTime, "AOD", "TOFEvTime", //! Table of the TOF event time. One entry per track. + pidtofevtime::TOFEvTime, + pidtofevtime::TOFEvTimeErr); DECLARE_SOA_TABLE(pidTOFFlags, "AOD", "pidTOFFlags", //! Table of the flags for TOF signal quality on the track level pidflags::GoodTOFMatch); @@ -604,6 +618,14 @@ DECLARE_SOA_TABLE(pidTOFHe, "AOD", "pidTOFHe", //! Table of the TOF response wit DECLARE_SOA_TABLE(pidTOFAl, "AOD", "pidTOFAl", //! Table of the TOF response with binned Nsigma for alpha pidtof_tiny::TOFNSigmaStoreAl, pidtof_tiny::TOFNSigmaAl); +namespace mcpidtpc +{ +// Tuned MC on data +DECLARE_SOA_COLUMN(DeDxTunedMc, mcTunedTPCSignal, float); //! TPC signal after TuneOnData application for MC +} // namespace mcpidtpc + +DECLARE_SOA_TABLE(mcTPCTuneOnData, "AOD", "MCTPCTUNEONDATA", mcpidtpc::DeDxTunedMc); + namespace pidtpc { // Expected signals diff --git a/Common/DataModel/PIDResponseITS.h b/Common/DataModel/PIDResponseITS.h new file mode 100644 index 00000000000..4d582e54511 --- /dev/null +++ b/Common/DataModel/PIDResponseITS.h @@ -0,0 +1,196 @@ +// 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 PIDResponseITS.h +/// \since 2024-11-12 +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \author Francesco Mazzaschi francesco.mazzaschi@cern.ch +/// \author Giorgio Alberto Lucia giorgio.alberto.lucia@cern.ch +/// \brief Set of tables, tasks and utilities to provide the interface between +/// the analysis data model and the PID response of the ITS +/// + +#ifndef COMMON_DATAMODEL_PIDRESPONSEITS_H_ +#define COMMON_DATAMODEL_PIDRESPONSEITS_H_ + +// O2 includes +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "ReconstructionDataFormats/PID.h" +#include "Framework/Logger.h" + +namespace o2::aod +{ + +struct ITSResponse { + static float averageClusterSize(uint32_t itsClusterSizes) + { + float sum = 0; + int nclusters = 0; + int max = 0; + for (int layer = 0; layer < 7; layer++) { + int clsize = (itsClusterSizes >> (layer * 4)) & 0xf; + if (clsize > 0) { + nclusters++; + sum += clsize; + if (clsize > max) { + max = clsize; + } + } + } + if (nclusters == 0) { + return 0; + } + // truncated mean + return (sum - max) / (nclusters - 1); + }; + + template + static float expSignal(const float momentum) + { + static constexpr float inverseMass = 1. / o2::track::pid_constants::sMasses[id]; + // static constexpr float charge = static_cast(o2::track::pid_constants::sCharges[id]); + const float bg = momentum * inverseMass; + if (id == o2::track::PID::Helium3 || id == o2::track::PID::Alpha) { + return (mITSRespParamsZ2[0] / (std::pow(bg, mITSRespParamsZ2[1])) + mITSRespParamsZ2[2]); + } + return (mITSRespParams[0] / (std::pow(bg, mITSRespParams[1])) + mITSRespParams[2]); + } + + template + static float expResolution(const float momentum) + { + static constexpr float inverseMass = 1. / o2::track::pid_constants::sMasses[id]; + // static constexpr float charge = static_cast(o2::track::pid_constants::sCharges[id]); + const float bg = momentum * inverseMass; + if (id == o2::track::PID::Helium3 || id == o2::track::PID::Alpha) { + return mResolutionParamsZ2[0] * std::erf((bg - mResolutionParamsZ2[1]) / mResolutionParamsZ2[2]); + } + return mResolutionParams[0] * std::erf((bg - mResolutionParams[1]) / mResolutionParams[2]); + } + + template + static float nSigmaITS(uint32_t itsClusterSizes, float momentum, float eta) + { + const float exp = expSignal(momentum); + const float average = averageClusterSize(itsClusterSizes); + const float coslInv = 1. / std::cosh(eta); + const float resolution = expResolution(momentum) * exp; + return (average * coslInv - exp) / resolution; + }; + + template + static float nSigmaITS(const T& track) + { + return nSigmaITS(track.itsClusterSizes(), track.p(), track.eta()); + } + + static void setParameters(float p0, float p1, float p2, + float p0_Z2, float p1_Z2, float p2_Z2, + float p0_res, float p1_res, float p2_res, + float p0_res_Z2, float p1_res_Z2, float p2_res_Z2) + { + if (mIsInitialized) { + LOG(fatal) << "ITSResponse parameters already initialized"; + } + mIsInitialized = true; + mITSRespParams[0] = p0; + mITSRespParams[1] = p1; + mITSRespParams[2] = p2; + mITSRespParamsZ2[0] = p0_Z2; + mITSRespParamsZ2[1] = p1_Z2; + mITSRespParamsZ2[2] = p2_Z2; + mResolutionParams[0] = p0_res; + mResolutionParams[1] = p1_res; + mResolutionParams[2] = p2_res; + mResolutionParamsZ2[0] = p0_res_Z2; + mResolutionParamsZ2[1] = p1_res_Z2; + mResolutionParamsZ2[2] = p2_res_Z2; + } + + private: + static std::array mITSRespParams; + static std::array mITSRespParamsZ2; + static std::array mResolutionParams; + static std::array mResolutionParamsZ2; + static bool mIsInitialized; +}; + +std::array ITSResponse::mITSRespParams = {1.18941, 1.53792, 1.69961}; +std::array ITSResponse::mITSRespParamsZ2 = {2.35117, 1.80347, 5.14355}; +// relative resolution is modelled with an erf function: [0]*TMath::Erf((x-[1])/[2]) +std::array ITSResponse::mResolutionParams = {1.94669e-01, -2.08616e-01, 1.30753}; +std::array ITSResponse::mResolutionParamsZ2 = {8.74371e-02, -1.82804, 5.06449e-01}; +bool ITSResponse::mIsInitialized = false; + +namespace pidits +{ +DECLARE_SOA_DYNAMIC_COLUMN(ITSNSigmaElImp, itsNSigmaEl, //! Nsigma separation with the ITS detector for electrons + [](uint32_t itsClusterSizes, float momentum, float eta) -> float { + return ITSResponse::nSigmaITS(itsClusterSizes, momentum, eta); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(ITSNSigmaMuImp, itsNSigmaMu, //! Nsigma separation with the ITS detector for muons + [](uint32_t itsClusterSizes, float momentum, float eta) -> float { + return ITSResponse::nSigmaITS(itsClusterSizes, momentum, eta); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(ITSNSigmaPiImp, itsNSigmaPi, //! Nsigma separation with the ITS detector for pions + [](uint32_t itsClusterSizes, float momentum, float eta) -> float { + return ITSResponse::nSigmaITS(itsClusterSizes, momentum, eta); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(ITSNSigmaKaImp, itsNSigmaKa, //! Nsigma separation with the ITS detector for kaons + [](uint32_t itsClusterSizes, float momentum, float eta) -> float { + return ITSResponse::nSigmaITS(itsClusterSizes, momentum, eta); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(ITSNSigmaPrImp, itsNSigmaPr, //! Nsigma separation with the ITS detector for protons + [](uint32_t itsClusterSizes, float momentum, float eta) -> float { + return ITSResponse::nSigmaITS(itsClusterSizes, momentum, eta); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(ITSNSigmaDeImp, itsNSigmaDe, //! Nsigma separation with the ITS detector for deuterons + [](uint32_t itsClusterSizes, float momentum, float eta) -> float { + return ITSResponse::nSigmaITS(itsClusterSizes, momentum, eta); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(ITSNSigmaTrImp, itsNSigmaTr, //! Nsigma separation with the ITS detector for tritons + [](uint32_t itsClusterSizes, float momentum, float eta) -> float { + return ITSResponse::nSigmaITS(itsClusterSizes, momentum, eta); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(ITSNSigmaHeImp, itsNSigmaHe, //! Nsigma separation with the ITS detector for helium3 + [](uint32_t itsClusterSizes, float momentum, float eta) -> float { + return ITSResponse::nSigmaITS(itsClusterSizes, momentum, eta); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(ITSNSigmaAlImp, itsNSigmaAl, //! Nsigma separation with the ITS detector for alphas + [](uint32_t itsClusterSizes, float momentum, float eta) -> float { + return ITSResponse::nSigmaITS(itsClusterSizes, momentum, eta); + }); + +// Define user friendly names for the columns to join with the tracks +using ITSNSigmaEl = ITSNSigmaElImp; +using ITSNSigmaMu = ITSNSigmaMuImp; +using ITSNSigmaPi = ITSNSigmaPiImp; +using ITSNSigmaKa = ITSNSigmaKaImp; +using ITSNSigmaPr = ITSNSigmaPrImp; +using ITSNSigmaDe = ITSNSigmaDeImp; +using ITSNSigmaTr = ITSNSigmaTrImp; +using ITSNSigmaHe = ITSNSigmaHeImp; +using ITSNSigmaAl = ITSNSigmaAlImp; + +} // namespace pidits +} // namespace o2::aod + +#endif // COMMON_DATAMODEL_PIDRESPONSEITS_H_ diff --git a/Common/DataModel/PropagatedFwdTrackTables.h b/Common/DataModel/PropagatedFwdTrackTables.h new file mode 100644 index 00000000000..ab0b20b76cf --- /dev/null +++ b/Common/DataModel/PropagatedFwdTrackTables.h @@ -0,0 +1,85 @@ +// 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 PropagatedFwdTrackTables.h +/// \brief Table definitions for propagated forward tracks +/// \author Maurice Coquet +/// \author Luca Micheletti +/// \author Daiki Sekihata + +#ifndef COMMON_DATAMODEL_PROPAGATEDFWDTRACKTABLES_H_ +#define COMMON_DATAMODEL_PROPAGATEDFWDTRACKTABLES_H_ + +#include "Framework/AnalysisDataModel.h" +#include "TrackSelectionTables.h" + +namespace o2::aod +{ +namespace propfwdtrack +{ +DECLARE_SOA_INDEX_COLUMN(FwdTrack, fwdtrack); //! FwdTrack index +DECLARE_SOA_INDEX_COLUMN_FULL(MCHTrack, matchMCHTrack, int, FwdTracks, "_MatchMCHTrack"); //! Index of matched MCH track for GlobalMuonTracks and GlobalForwardTracks +DECLARE_SOA_COLUMN(CXXatDCA, cXXatDCA, float); //! DCAx resolution squared at DCA +DECLARE_SOA_COLUMN(CYYatDCA, cYYatDCA, float); //! DCAy resolution squared at DCA +DECLARE_SOA_COLUMN(CXYatDCA, cXYatDCA, float); //! correlation term of DCAx,y resolution at DCA +DECLARE_SOA_COLUMN(EtaMatchedMCHMID, etaMatchedMCHMID, float); //! eta of MCH-MID track in MFT-MCH-MID track at PV +DECLARE_SOA_COLUMN(PhiMatchedMCHMID, phiMatchedMCHMID, float); //! phi of MCH-MID track in MFT-MCH-MID track at PV +DECLARE_SOA_COLUMN(IsAssociatedToMPC, isAssociatedToMPC, bool); //! is assigned to the most probable collision (relevant to TTCA) +DECLARE_SOA_COLUMN(IsAmbiguous, isAmbiguous, bool); //! is ambiguous (relevant to TTCA) +} // namespace propfwdtrack + +DECLARE_SOA_TABLE_FULL(StoredPropagatedFwdTracks, "PropagatedFwdTracks", "AOD", "PROPFWDTRACK", + o2::soa::Index<>, fwdtrack::CollisionId, fwdtrack::TrackType, + fwdtrack::X, fwdtrack::Y, fwdtrack::Z, fwdtrack::Phi, fwdtrack::Tgl, + fwdtrack::Signed1Pt, fwdtrack::NClusters, fwdtrack::PDca, fwdtrack::RAtAbsorberEnd, + fwdtrack::Px, + fwdtrack::Py, + fwdtrack::Pz, + fwdtrack::Sign, + fwdtrack::Chi2, fwdtrack::Chi2MatchMCHMID, fwdtrack::Chi2MatchMCHMFT, + fwdtrack::MatchScoreMCHMFT, propfwdtrack::FwdTrackId, fwdtrack::MFTTrackId, propfwdtrack::MCHTrackId, + fwdtrack::MCHBitMap, fwdtrack::MIDBitMap, fwdtrack::MIDBoards, + fwdtrack::TrackTime, fwdtrack::TrackTimeRes, fwdtrack::FwdDcaX, fwdtrack::FwdDcaY, + propfwdtrack::CXXatDCA, propfwdtrack::CYYatDCA, propfwdtrack::CXYatDCA, + propfwdtrack::EtaMatchedMCHMID, propfwdtrack::PhiMatchedMCHMID, + propfwdtrack::IsAssociatedToMPC, propfwdtrack::IsAmbiguous, o2::soa::Marker<1>); + +DECLARE_SOA_TABLE_FULL(StoredPropagatedFwdTracksCov, "PropagatedFwdTracksCov", "AOD", "PROPFWDTRACKCOV", //! + fwdtrack::SigmaX, fwdtrack::SigmaY, fwdtrack::SigmaPhi, fwdtrack::SigmaTgl, fwdtrack::Sigma1Pt, + fwdtrack::RhoXY, fwdtrack::RhoPhiY, fwdtrack::RhoPhiX, fwdtrack::RhoTglX, fwdtrack::RhoTglY, + fwdtrack::RhoTglPhi, fwdtrack::Rho1PtX, fwdtrack::Rho1PtY, fwdtrack::Rho1PtPhi, fwdtrack::Rho1PtTgl, o2::soa::Marker<1>); + +// extended table with expression columns that can be used as arguments of dynamic columns +DECLARE_SOA_EXTENDED_TABLE_USER(PropagatedFwdTracks, StoredPropagatedFwdTracks, "PROPFWDTRACKEXT", //! + fwdtrack::Pt, + fwdtrack::Eta, + fwdtrack::P); + +// extended table with expression columns that can be used as arguments of dynamic columns +DECLARE_SOA_EXTENDED_TABLE_USER(PropagatedFwdTracksCov, StoredPropagatedFwdTracksCov, "PROPFWDTRACKCOVEXT", //! + fwdtrack::CXX, + fwdtrack::CXY, + fwdtrack::CYY, + fwdtrack::CPhiX, + fwdtrack::CPhiY, + fwdtrack::CPhiPhi, + fwdtrack::CTglX, + fwdtrack::CTglY, + fwdtrack::CTglPhi, + fwdtrack::CTglTgl, + fwdtrack::C1PtX, + fwdtrack::C1PtY, + fwdtrack::C1PtPhi, + fwdtrack::C1PtTgl, + fwdtrack::C1Pt21Pt2); +} // namespace o2::aod + +#endif // COMMON_DATAMODEL_PROPAGATEDFWDTRACKTABLES_H_ diff --git a/Common/DataModel/Qvectors.h b/Common/DataModel/Qvectors.h index 7302440ac7f..423c2648e89 100644 --- a/Common/DataModel/Qvectors.h +++ b/Common/DataModel/Qvectors.h @@ -29,12 +29,27 @@ namespace o2::aod namespace qvec { DECLARE_SOA_COLUMN(Cent, cent, float); -DECLARE_SOA_COLUMN(CentBin, centBin, int); +DECLARE_SOA_COLUMN(IsCalibrated, isCalibrated, bool); DECLARE_SOA_COLUMN(QvecRe, qvecRe, std::vector); DECLARE_SOA_COLUMN(QvecIm, qvecIm, std::vector); DECLARE_SOA_COLUMN(QvecAmp, qvecAmp, std::vector); +DECLARE_SOA_COLUMN(QvecFT0CReVec, qvecFT0CReVec, std::vector); +DECLARE_SOA_COLUMN(QvecFT0CImVec, qvecFT0CImVec, std::vector); +DECLARE_SOA_COLUMN(QvecFT0AReVec, qvecFT0AReVec, std::vector); +DECLARE_SOA_COLUMN(QvecFT0AImVec, qvecFT0AImVec, std::vector); +DECLARE_SOA_COLUMN(QvecFT0MReVec, qvecFT0MReVec, std::vector); +DECLARE_SOA_COLUMN(QvecFT0MImVec, qvecFT0MImVec, std::vector); +DECLARE_SOA_COLUMN(QvecFV0AReVec, qvecFV0AReVec, std::vector); +DECLARE_SOA_COLUMN(QvecFV0AImVec, qvecFV0AImVec, std::vector); +DECLARE_SOA_COLUMN(QvecTPCposReVec, qvecTPCposReVec, std::vector); +DECLARE_SOA_COLUMN(QvecTPCposImVec, qvecTPCposImVec, std::vector); +DECLARE_SOA_COLUMN(QvecTPCnegReVec, qvecTPCnegReVec, std::vector); +DECLARE_SOA_COLUMN(QvecTPCnegImVec, qvecTPCnegImVec, std::vector); +DECLARE_SOA_COLUMN(QvecTPCallReVec, qvecTPCallReVec, std::vector); +DECLARE_SOA_COLUMN(QvecTPCallImVec, qvecTPCallImVec, std::vector); + DECLARE_SOA_COLUMN(QvecFT0CRe, qvecFT0CRe, float); DECLARE_SOA_COLUMN(QvecFT0CIm, qvecFT0CIm, float); DECLARE_SOA_COLUMN(QvecFT0ARe, qvecFT0ARe, float); @@ -43,38 +58,101 @@ DECLARE_SOA_COLUMN(QvecFT0MRe, qvecFT0MRe, float); DECLARE_SOA_COLUMN(QvecFT0MIm, qvecFT0MIm, float); DECLARE_SOA_COLUMN(QvecFV0ARe, qvecFV0ARe, float); DECLARE_SOA_COLUMN(QvecFV0AIm, qvecFV0AIm, float); -DECLARE_SOA_COLUMN(QvecBPosRe, qvecBPosRe, float); -DECLARE_SOA_COLUMN(QvecBPosIm, qvecBPosIm, float); -DECLARE_SOA_COLUMN(QvecBNegRe, qvecBNegRe, float); -DECLARE_SOA_COLUMN(QvecBNegIm, qvecBNegIm, float); +DECLARE_SOA_COLUMN(QvecTPCposRe, qvecTPCposRe, float); +DECLARE_SOA_COLUMN(QvecTPCposIm, qvecTPCposIm, float); +DECLARE_SOA_COLUMN(QvecTPCnegRe, qvecTPCnegRe, float); +DECLARE_SOA_COLUMN(QvecTPCnegIm, qvecTPCnegIm, float); +DECLARE_SOA_COLUMN(QvecTPCallRe, qvecTPCallRe, float); +DECLARE_SOA_COLUMN(QvecTPCallIm, qvecTPCallIm, float); DECLARE_SOA_COLUMN(SumAmplFT0C, sumAmplFT0C, float); DECLARE_SOA_COLUMN(SumAmplFT0A, sumAmplFT0A, float); DECLARE_SOA_COLUMN(SumAmplFT0M, sumAmplFT0M, float); DECLARE_SOA_COLUMN(SumAmplFV0A, sumAmplFV0A, float); +DECLARE_SOA_COLUMN(NTrkTPCpos, nTrkTPCpos, int); +DECLARE_SOA_COLUMN(NTrkTPCneg, nTrkTPCneg, int); +DECLARE_SOA_COLUMN(NTrkTPCall, nTrkTPCall, int); +DECLARE_SOA_COLUMN(LabelsTPCpos, labelsTPCpos, std::vector); +DECLARE_SOA_COLUMN(LabelsTPCneg, labelsTPCneg, std::vector); +DECLARE_SOA_COLUMN(LabelsTPCall, labelsTPCall, std::vector); + +// Deprecated, will be removed in future after transition time // +DECLARE_SOA_COLUMN(QvecBPosReVec, qvecBPosReVec, std::vector); +DECLARE_SOA_COLUMN(QvecBPosImVec, qvecBPosImVec, std::vector); +DECLARE_SOA_COLUMN(QvecBNegReVec, qvecBNegReVec, std::vector); +DECLARE_SOA_COLUMN(QvecBNegImVec, qvecBNegImVec, std::vector); +DECLARE_SOA_COLUMN(QvecBTotReVec, qvecBTotReVec, std::vector); +DECLARE_SOA_COLUMN(QvecBTotImVec, qvecBTotImVec, std::vector); + +DECLARE_SOA_COLUMN(QvecBPosRe, qvecBPosRe, float); +DECLARE_SOA_COLUMN(QvecBPosIm, qvecBPosIm, float); +DECLARE_SOA_COLUMN(QvecBNegRe, qvecBNegRe, float); +DECLARE_SOA_COLUMN(QvecBNegIm, qvecBNegIm, float); +DECLARE_SOA_COLUMN(QvecBTotRe, qvecBTotRe, float); +DECLARE_SOA_COLUMN(QvecBTotIm, qvecBTotIm, float); + DECLARE_SOA_COLUMN(NTrkBPos, nTrkBPos, int); DECLARE_SOA_COLUMN(NTrkBNeg, nTrkBNeg, int); +DECLARE_SOA_COLUMN(NTrkBTot, nTrkBTot, int); DECLARE_SOA_COLUMN(LabelsBPos, labelsBPos, std::vector); DECLARE_SOA_COLUMN(LabelsBNeg, labelsBNeg, std::vector); +DECLARE_SOA_COLUMN(LabelsBTot, labelsBTot, std::vector); +///////////////////////////////////////////////////////////////// } // namespace qvec DECLARE_SOA_TABLE(Qvectors, "AOD", "QVECTORDEVS", //! Table with all Qvectors. - qvec::Cent, qvec::CentBin, qvec::QvecRe, qvec::QvecIm, qvec::QvecAmp); + qvec::Cent, qvec::IsCalibrated, qvec::QvecRe, qvec::QvecIm, qvec::QvecAmp); using Qvector = Qvectors::iterator; -DECLARE_SOA_TABLE(QvectorFT0Cs, "AOD", "QVECTORSFT0C", qvec::CentBin, qvec::QvecFT0CRe, qvec::QvecFT0CIm, qvec::SumAmplFT0C); -DECLARE_SOA_TABLE(QvectorFT0As, "AOD", "QVECTORSFT0A", qvec::CentBin, qvec::QvecFT0ARe, qvec::QvecFT0AIm, qvec::SumAmplFT0A); -DECLARE_SOA_TABLE(QvectorFT0Ms, "AOD", "QVECTORSFT0M", qvec::CentBin, qvec::QvecFT0MRe, qvec::QvecFT0MIm, qvec::SumAmplFT0M); -DECLARE_SOA_TABLE(QvectorFV0As, "AOD", "QVECTORSFV0A", qvec::CentBin, qvec::QvecFV0ARe, qvec::QvecFV0AIm, qvec::SumAmplFV0A); -DECLARE_SOA_TABLE(QvectorBPoss, "AOD", "QVECTORSBPOS", qvec::CentBin, qvec::QvecBPosRe, qvec::QvecBPosIm, qvec::NTrkBPos, qvec::LabelsBPos); -DECLARE_SOA_TABLE(QvectorBNegs, "AOD", "QVECTORSBNEG", qvec::CentBin, qvec::QvecBNegRe, qvec::QvecBNegIm, qvec::NTrkBNeg, qvec::LabelsBNeg); +DECLARE_SOA_TABLE(QvectorFT0Cs, "AOD", "QVECTORSFT0C", qvec::IsCalibrated, qvec::QvecFT0CRe, qvec::QvecFT0CIm, qvec::SumAmplFT0C); +DECLARE_SOA_TABLE(QvectorFT0As, "AOD", "QVECTORSFT0A", qvec::IsCalibrated, qvec::QvecFT0ARe, qvec::QvecFT0AIm, qvec::SumAmplFT0A); +DECLARE_SOA_TABLE(QvectorFT0Ms, "AOD", "QVECTORSFT0M", qvec::IsCalibrated, qvec::QvecFT0MRe, qvec::QvecFT0MIm, qvec::SumAmplFT0M); +DECLARE_SOA_TABLE(QvectorFV0As, "AOD", "QVECTORSFV0A", qvec::IsCalibrated, qvec::QvecFV0ARe, qvec::QvecFV0AIm, qvec::SumAmplFV0A); +DECLARE_SOA_TABLE(QvectorTPCposs, "AOD", "QVECTORSTPCPOS", qvec::IsCalibrated, qvec::QvecTPCposRe, qvec::QvecTPCposIm, qvec::NTrkTPCpos, qvec::LabelsTPCpos); +DECLARE_SOA_TABLE(QvectorTPCnegs, "AOD", "QVECTORSTPCNEG", qvec::IsCalibrated, qvec::QvecTPCnegRe, qvec::QvecTPCnegIm, qvec::NTrkTPCneg, qvec::LabelsTPCneg); +DECLARE_SOA_TABLE(QvectorTPCalls, "AOD", "QVECTORSTPCALL", qvec::IsCalibrated, qvec::QvecTPCallRe, qvec::QvecTPCallIm, qvec::NTrkTPCall, qvec::LabelsTPCall); + +DECLARE_SOA_TABLE(QvectorFT0CVecs, "AOD", "QVECTORSFT0CVEC", qvec::IsCalibrated, qvec::QvecFT0CReVec, qvec::QvecFT0CImVec, qvec::SumAmplFT0C); +DECLARE_SOA_TABLE(QvectorFT0AVecs, "AOD", "QVECTORSFT0AVEC", qvec::IsCalibrated, qvec::QvecFT0AReVec, qvec::QvecFT0AImVec, qvec::SumAmplFT0A); +DECLARE_SOA_TABLE(QvectorFT0MVecs, "AOD", "QVECTORSFT0MVEC", qvec::IsCalibrated, qvec::QvecFT0MReVec, qvec::QvecFT0MImVec, qvec::SumAmplFT0M); +DECLARE_SOA_TABLE(QvectorFV0AVecs, "AOD", "QVECTORSFV0AVEC", qvec::IsCalibrated, qvec::QvecFV0AReVec, qvec::QvecFV0AImVec, qvec::SumAmplFV0A); +DECLARE_SOA_TABLE(QvectorTPCposVecs, "AOD", "QVECTORSTPCPVEC", qvec::IsCalibrated, qvec::QvecTPCposReVec, qvec::QvecTPCposImVec, qvec::NTrkTPCpos, qvec::LabelsTPCpos); +DECLARE_SOA_TABLE(QvectorTPCnegVecs, "AOD", "QVECTORSTPCNVEC", qvec::IsCalibrated, qvec::QvecTPCnegReVec, qvec::QvecTPCnegImVec, qvec::NTrkTPCneg, qvec::LabelsTPCneg); +DECLARE_SOA_TABLE(QvectorTPCallVecs, "AOD", "QVECTORSTPCAVEC", qvec::IsCalibrated, qvec::QvecTPCallReVec, qvec::QvecTPCallImVec, qvec::NTrkTPCall, qvec::LabelsTPCall); using QvectorFT0C = QvectorFT0Cs::iterator; using QvectorFT0A = QvectorFT0As::iterator; using QvectorFT0M = QvectorFT0Ms::iterator; using QvectorFV0A = QvectorFV0As::iterator; +using QvectorTPCpos = QvectorTPCposs::iterator; +using QvectorTPCneg = QvectorTPCnegs::iterator; +using QvectorTPCall = QvectorTPCalls::iterator; + +using QvectorFT0CVec = QvectorFT0CVecs::iterator; +using QvectorFT0AVec = QvectorFT0AVecs::iterator; +using QvectorFT0MVec = QvectorFT0MVecs::iterator; +using QvectorFV0AVec = QvectorFV0AVecs::iterator; +using QvectorTPCposVec = QvectorTPCposVecs::iterator; +using QvectorTPCnegVec = QvectorTPCnegVecs::iterator; +using QvectorTPCallVec = QvectorTPCallVecs::iterator; + +// Deprecated, will be removed in future after transition time // +DECLARE_SOA_TABLE(QvectorBPoss, "AOD", "QVECTORSBPOS", qvec::IsCalibrated, qvec::QvecBPosRe, qvec::QvecBPosIm, qvec::NTrkBPos, qvec::LabelsBPos); +DECLARE_SOA_TABLE(QvectorBNegs, "AOD", "QVECTORSBNEG", qvec::IsCalibrated, qvec::QvecBNegRe, qvec::QvecBNegIm, qvec::NTrkBNeg, qvec::LabelsBNeg); +DECLARE_SOA_TABLE(QvectorBTots, "AOD", "QVECTORSBTOT", qvec::IsCalibrated, qvec::QvecBTotRe, qvec::QvecBTotIm, qvec::NTrkBTot, qvec::LabelsBTot); + +DECLARE_SOA_TABLE(QvectorBPosVecs, "AOD", "QVECTORSBPOSVEC", qvec::IsCalibrated, qvec::QvecBPosReVec, qvec::QvecBPosImVec, qvec::NTrkBPos, qvec::LabelsBPos); +DECLARE_SOA_TABLE(QvectorBNegVecs, "AOD", "QVECTORSBNEGVEC", qvec::IsCalibrated, qvec::QvecBNegReVec, qvec::QvecBNegImVec, qvec::NTrkBNeg, qvec::LabelsBNeg); +DECLARE_SOA_TABLE(QvectorBTotVecs, "AOD", "QVECTORSBTOTVEC", qvec::IsCalibrated, qvec::QvecBTotReVec, qvec::QvecBTotImVec, qvec::NTrkBTot, qvec::LabelsBTot); + using QvectorBPos = QvectorBPoss::iterator; using QvectorBNeg = QvectorBNegs::iterator; +using QvectorBTot = QvectorBTots::iterator; + +using QvectorBPosVec = QvectorBPosVecs::iterator; +using QvectorBNegVec = QvectorBNegVecs::iterator; +using QvectorBTotVec = QvectorBTotVecs::iterator; +///////////////////////////////////////////////////////////////// } // namespace o2::aod diff --git a/Common/DataModel/TrackSelectionTables.h b/Common/DataModel/TrackSelectionTables.h index cc27e06bfe7..46ebf03868f 100644 --- a/Common/DataModel/TrackSelectionTables.h +++ b/Common/DataModel/TrackSelectionTables.h @@ -60,6 +60,7 @@ struct TrackSelectionFlags { static constexpr flagtype kGlobalTrackWoTPCCluster = kQualityTracksWoTPCCluster | kPrimaryTracks | kInAcceptanceTracks; static constexpr flagtype kGlobalTrackWoPtEta = kQualityTracks | kPrimaryTracks; static constexpr flagtype kGlobalTrackWoDCA = kQualityTracks | kInAcceptanceTracks; + static constexpr flagtype kGlobalTrackWoDCAxy = kQualityTracks | kInAcceptanceTracks | kDCAz; static constexpr flagtype kGlobalTrackWoDCATPCCluster = kQualityTracksWoTPCCluster | kInAcceptanceTracks; /// @brief Function to check flag content diff --git a/Common/DataModel/ZDCInterCalib.h b/Common/DataModel/ZDCInterCalib.h new file mode 100644 index 00000000000..290a3ac61fe --- /dev/null +++ b/Common/DataModel/ZDCInterCalib.h @@ -0,0 +1,55 @@ +// 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 ZDCInterCalib.h +/// \brief ZDC tower intercalibration task +/// \author Chiara Oppedisano , INFN Torino + +#ifndef COMMON_DATAMODEL_ZDCINTERCALIB_H_ +#define COMMON_DATAMODEL_ZDCINTERCALIB_H_ + +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace znoutput +{ +DECLARE_SOA_COLUMN(ZNApmc, commonPMZNA, float); //! PMC ZNA // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(ZNApm1, ZNAPM1, float); //! PM1 ZNA // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(ZNApm2, ZNAPM2, float); //! PM2 ZNA // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(ZNApm3, ZNAPM3, float); //! PM3 ZNA // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(ZNApm4, ZNAPM4, float); //! PM4 ZNA // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(ZNAtdc, ZNATDC, float); //! TDC ZNA // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(ZNCpmc, commonPMZNC, float); //! PMC ZNC // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(ZNCpm1, ZNCPM1, float); //! PM1 ZNC // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(ZNCpm2, ZNCPM2, float); //! PM2 ZNC // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(ZNCpm3, ZNCPM3, float); //! PM3 ZNC // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(ZNCpm4, ZNCPM4, float); //! PM4 ZNC // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(ZNCtdc, ZNCTDC, float); //! TDC ZNC // o2-linter: disable=name/o2-column + +} // namespace znoutput + +DECLARE_SOA_TABLE(ZDCInterCalib, "AOD", "ZDCIC", o2::soa::Index<>, + znoutput::ZNApmc, + znoutput::ZNApm1, + znoutput::ZNApm2, + znoutput::ZNApm3, + znoutput::ZNApm4, + znoutput::ZNAtdc, + znoutput::ZNCpmc, + znoutput::ZNCpm1, + znoutput::ZNCpm2, + znoutput::ZNCpm3, + znoutput::ZNCpm4, + znoutput::ZNCtdc); +} // namespace o2::aod + +#endif // COMMON_DATAMODEL_ZDCINTERCALIB_H_ diff --git a/Common/LegacyDataQA/CMakeLists.txt b/Common/LegacyDataQA/CMakeLists.txt new file mode 100644 index 00000000000..c40882e2376 --- /dev/null +++ b/Common/LegacyDataQA/CMakeLists.txt @@ -0,0 +1,25 @@ +# 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(otfv0qa + SOURCES otfv0qa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(centqa + SOURCES centqa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(tpcpidqa + SOURCES tpcpidqa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) \ No newline at end of file diff --git a/Common/LegacyDataQA/centqa.cxx b/Common/LegacyDataQA/centqa.cxx new file mode 100644 index 00000000000..0d69be10754 --- /dev/null +++ b/Common/LegacyDataQA/centqa.cxx @@ -0,0 +1,92 @@ +// 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. +// +// This code calculates output histograms for centrality calibration +// as well as vertex-Z dependencies of raw variables (either for calibration +// of vtx-Z dependencies or for the calibration of those). +// +// This task is not strictly necessary in a typical analysis workflow, +// except for centrality calibration! The necessary task is the multiplicity +// tables. +// +// Comments, suggestions, questions? Please write to: +// - victor.gonzalez@cern.ch +// - david.dobrigkeit.chinellato@cern.ch +// + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "TH1F.h" +#include "TH2F.h" + +using namespace o2; +using namespace o2::framework; + +struct CentQA { + // Raw multiplicities + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext&) + { + const AxisSpec axisCentrality{205, 0, 205, "centrality"}; + + // Base histograms + histos.add("hV0M", "V0M centrality", kTH1F, {axisCentrality}); + histos.add("hV0A", "V0A centrality", kTH1F, {axisCentrality}); + histos.add("hCL0", "CL0 centrality", kTH1F, {axisCentrality}); + histos.add("hCL1", "CL1 centrality", kTH1F, {axisCentrality}); + histos.add("hRefMult5", "RefMult .5 centrality", kTH1F, {axisCentrality}); + histos.add("hRefMult8", "RefMult .8 centrality", kTH1F, {axisCentrality}); + } + + void processV0M(soa::Join::iterator const& col) + { + histos.fill(HIST("hV0M"), col.centRun2V0M()); + } + void processV0A(soa::Join::iterator const& col) + { + histos.fill(HIST("hV0A"), col.centRun2V0A()); + } + void processCL0(soa::Join::iterator const& col) + { + histos.fill(HIST("hCL0"), col.centRun2CL0()); + } + void processCL1(soa::Join::iterator const& col) + { + histos.fill(HIST("hCL1"), col.centRun2CL1()); + } + void processRefMult5(soa::Join::iterator const& col) + { + histos.fill(HIST("hRefMult5"), col.centRun2RefMult5()); + } + void processRefMult8(soa::Join::iterator const& col) + { + histos.fill(HIST("hRefMult8"), col.centRun2RefMult8()); + } + + PROCESS_SWITCH(CentQA, processV0M, "QA V0M centrality", true); + PROCESS_SWITCH(CentQA, processV0A, "QA V0A centrality", false); + PROCESS_SWITCH(CentQA, processCL0, "QA CL0 centrality", false); + PROCESS_SWITCH(CentQA, processCL1, "QA CL1 centrality", false); + PROCESS_SWITCH(CentQA, processRefMult5, "QA RefMult5 centrality", false); + PROCESS_SWITCH(CentQA, processRefMult8, "QA RefMult8 centrality", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Common/LegacyDataQA/otfv0qa.cxx b/Common/LegacyDataQA/otfv0qa.cxx new file mode 100644 index 00000000000..8dc446d9a01 --- /dev/null +++ b/Common/LegacyDataQA/otfv0qa.cxx @@ -0,0 +1,63 @@ +// 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. + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/EventSelection.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "TH1F.h" +#include "TH2F.h" + +using namespace o2; +using namespace o2::framework; + +struct OTFV0Qa { + // Raw multiplicities + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable maxGammaMassForXYplot{"maxGammaMassForXYplot", 0.1f, "Max photon mass for XY plot"}; + + ConfigurableAxis axisNCandidates{"axisNCandidates", {500, 0, 500}, "Number of OTF v0s"}; + ConfigurableAxis axisPosition{"axisPosition", {1000, -100, 100}, "position (cm)"}; + ConfigurableAxis axisMass{"axisMass", {100, 0.0f, 1.0f}, "Mass (GeV/c2)"}; + + void init(InitContext&) + { + const AxisSpec axisPVz{30, -15, 15, "Primary vertex Z (cm)"}; + + // Base histograms + histos.add("hPrimaryVertexZ", "Event counter", kTH1F, {axisPVz}); + histos.add("hCandidates", "Number of OTF V0s", kTH1F, {axisNCandidates}); + histos.add("hGammaMass", "mass distribution", kTH1F, {axisMass}); + histos.add("h2dPosition", "xy positions", kTH2F, {axisPosition, axisPosition}); + } + + void process(aod::Collision const& collision, aod::Run2OTFV0s const& v0s) + { + histos.fill(HIST("hPrimaryVertexZ"), collision.posZ()); + histos.fill(HIST("hCandidates"), v0s.size()); + for (auto const& v0 : v0s) { + histos.fill(HIST("hGammaMass"), v0.mass()); + if (v0.mass() < maxGammaMassForXYplot) { + histos.fill(HIST("h2dPosition"), v0.x(), v0.y()); + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Common/LegacyDataQA/tpcpidqa.cxx b/Common/LegacyDataQA/tpcpidqa.cxx new file mode 100644 index 00000000000..a67043fd342 --- /dev/null +++ b/Common/LegacyDataQA/tpcpidqa.cxx @@ -0,0 +1,119 @@ +// 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. +// +// This task converts tiny PID tables into full PID tables. +// It is meant to be used with Run 2 converted data to maintain +// full compatibility with any task that may subscribe to the Full +// tables (at the cost of some memory consumption). +// It is also able to produce very simple QA plots on the stored +// quantities (optionally disabled for simplicity) +// +// Warning: expected resolution is NOT provided. + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/PIDResponse.h" +#include "TableHelper.h" + +using namespace o2; +using namespace o2::framework; + +using tinyPidTracks = soa::Join; + +static constexpr int nParameters = 1; +static const std::vector tableNames{"Electron", // 0 + "Muon", // 1 + "Pion", // 2 + "Kaon", // 3 + "Proton", // 4 + "Deuteron", // 5 + "Triton", // 6 + "Helium", // 7 + "Alpha"}; // 8 +static const std::vector parameterNames{"enable"}; +static const int defaultParameters[9][nParameters]{{0}, {0}, {1}, {1}, {1}, {0}, {0}, {0}, {0}}; + +static constexpr int kPidEl = 0; +static constexpr int kPidMu = 1; +static constexpr int kPidPi = 2; +static constexpr int kPidKa = 3; +static constexpr int kPidPr = 4; +static constexpr int kPidDe = 5; +static constexpr int kPidTr = 6; +static constexpr int kPidHe = 7; +static constexpr int kPidAl = 8; +static constexpr int nTables = 9; + +struct TpcPidQa { + Configurable> enabledTables{"enabledTables", + {defaultParameters[0], nTables, nParameters, tableNames, parameterNames}, + "Produce QA for this species: 0 - no, 1 - yes"}; + std::vector mEnabledTables; // Vector of enabled tables + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + ConfigurableAxis axisMomentum{"axisMomentum", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "momentum"}; + + ConfigurableAxis axisNSigma{"axisNSigma", {48, -6.0f, 6.0f}, "axisNSigma"}; + + void init(InitContext&) + { + mEnabledTables.resize(9, 0); + + for (int i = 0; i < nTables; i++) { + int f = enabledTables->get(tableNames[i].c_str(), "enable"); + if (f == 1) { + mEnabledTables[i] = 1; + histos.add(fmt::format("hNSigmaVsPTot{}", tableNames[i]).c_str(), "", kTH2F, {axisMomentum, axisNSigma}); + } + } + } + + void process(tinyPidTracks const& tracks) + { + for (const auto& track : tracks) { + if (mEnabledTables[kPidEl]) { + histos.fill(HIST("hNSigmaVsPTotElectron"), track.p(), track.tpcNSigmaEl()); + } + if (mEnabledTables[kPidMu]) { + histos.fill(HIST("hNSigmaVsPTotMuon"), track.p(), track.tpcNSigmaMu()); + } + if (mEnabledTables[kPidPi]) { + histos.fill(HIST("hNSigmaVsPTotPion"), track.p(), track.tpcNSigmaPi()); + } + if (mEnabledTables[kPidKa]) { + histos.fill(HIST("hNSigmaVsPTotKaon"), track.p(), track.tpcNSigmaKa()); + } + if (mEnabledTables[kPidPr]) { + histos.fill(HIST("hNSigmaVsPTotProton"), track.p(), track.tpcNSigmaPr()); + } + if (mEnabledTables[kPidDe]) { + histos.fill(HIST("hNSigmaVsPTotDeuteron"), track.p(), track.tpcNSigmaDe()); + } + if (mEnabledTables[kPidTr]) { + histos.fill(HIST("hNSigmaVsPTotTriton"), track.p(), track.tpcNSigmaTr()); + } + if (mEnabledTables[kPidHe]) { + histos.fill(HIST("hNSigmaVsPTotHelium"), track.p(), track.tpcNSigmaHe()); + } + if (mEnabledTables[kPidAl]) { + histos.fill(HIST("hNSigmaVsPTotAlpha"), track.p(), track.tpcNSigmaAl()); + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Common/TableProducer/CMakeLists.txt b/Common/TableProducer/CMakeLists.txt index 7cd53628f18..27a5c14ceca 100644 --- a/Common/TableProducer/CMakeLists.txt +++ b/Common/TableProducer/CMakeLists.txt @@ -14,7 +14,7 @@ add_subdirectory(PID) o2physics_add_dpl_workflow(trackextension SOURCES trackextension.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(trackselection @@ -59,12 +59,12 @@ o2physics_add_dpl_workflow(ft0-corrected-table o2physics_add_dpl_workflow(track-propagation SOURCES trackPropagation.cxx - PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(track-propagation-tester SOURCES trackPropagationTester.cxx - PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2Physics::AnalysisCore O2Physics::trackSelectionRequest + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::trackSelectionRequest COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(calo-clusters @@ -92,7 +92,7 @@ o2physics_add_dpl_workflow(fwdtrack-to-collision-associator o2physics_add_dpl_workflow(mccollisionextra SOURCES mcCollsExtra.cxx - PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(qvector-table @@ -112,3 +112,46 @@ o2physics_add_dpl_workflow(mftmchmatchingml O2::CCDB O2Physics::MLCore O2::ReconstructionDataFormats COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(match-mft-ft0 + SOURCES match-mft-ft0.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + O2::ReconstructionDataFormats + O2::DetectorsBase O2::DetectorsCommonDataFormats + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(zdc-task-intercalib + SOURCES zdc-task-intercalib.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(ese-table-producer + SOURCES eseTableProducer.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(mftmch-matching-data + SOURCES match-mft-mch-data.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2Physics::AnalysisCCDB O2Physics::PWGDQCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(occ-table-producer + SOURCES occupancyTableProducer.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(mftmch-matching-data-mc + SOURCES match-mft-mch-data-mc.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2Physics::AnalysisCCDB O2Physics::PWGDQCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(muon-realignment + SOURCES muonRealignment.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2::DetectorsCommonDataFormats O2::MathUtils O2::MCHTracking O2::DataFormatsMCH O2::GlobalTracking O2::MCHBase O2::MCHGeometryTransformer O2::CommonUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(fwdtrack-propagation + SOURCES fwdtrackPropagation.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::GlobalTracking + COMPONENT_NAME Analysis) + diff --git a/Common/TableProducer/Converters/CMakeLists.txt b/Common/TableProducer/Converters/CMakeLists.txt index cbec8fc2d1e..13b1fbb38be 100644 --- a/Common/TableProducer/Converters/CMakeLists.txt +++ b/Common/TableProducer/Converters/CMakeLists.txt @@ -24,6 +24,11 @@ o2physics_add_dpl_workflow(tracks-extra-converter PUBLIC_LINK_LIBRARIES COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(tracks-extra-v002-converter + SOURCES tracksExtraV002Converter.cxx + PUBLIC_LINK_LIBRARIES + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(mft-tracks-converter SOURCES mftTracksConverter.cxx PUBLIC_LINK_LIBRARIES @@ -39,11 +44,21 @@ o2physics_add_dpl_workflow(collision-converter PUBLIC_LINK_LIBRARIES COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(mccollision-converter + SOURCES mcCollisionConverter.cxx + PUBLIC_LINK_LIBRARIES + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(bc-converter SOURCES bcConverter.cxx PUBLIC_LINK_LIBRARIES O2::Framework COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(bc-flags-creator + SOURCES bcFlagsCreator.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(calo-label-converter SOURCES caloLabelConverter.cxx PUBLIC_LINK_LIBRARIES @@ -59,3 +74,37 @@ o2physics_add_dpl_workflow(hmpid-converter PUBLIC_LINK_LIBRARIES COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(multsextra-converter + SOURCES multsExtraConverter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(multmcextras-converter + SOURCES multMCExtrasConverter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(trackqa-converter + SOURCES trackQAConverter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(trackqa-converter-002 + SOURCES trackQA002Converter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(run2bcinfos-converter + SOURCES run2bcinfosConverter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(run2-tracks-extra-converter + SOURCES run2tracksExtraConverter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(run2-tiny-to-full-pid + SOURCES run2TinyToFullPID.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/Common/TableProducer/Converters/bcFlagsCreator.cxx b/Common/TableProducer/Converters/bcFlagsCreator.cxx new file mode 100644 index 00000000000..972832716b5 --- /dev/null +++ b/Common/TableProducer/Converters/bcFlagsCreator.cxx @@ -0,0 +1,36 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" + +using namespace o2; +using namespace o2::framework; + +// Creates an empty BCFlags for data that doesn't have it to be used seamlessly +// n.b. this will overwrite existing BCFlags, to be discussed if data in mixed condition +struct bcFlagsCreator { + Produces bcFlags; + + void process(aod::BCs const& bcTable) + { + for (int64_t i = 0; i < bcTable.size(); ++i) { + bcFlags(0); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/Common/TableProducer/Converters/mcCollisionConverter.cxx b/Common/TableProducer/Converters/mcCollisionConverter.cxx new file mode 100644 index 00000000000..b965a092117 --- /dev/null +++ b/Common/TableProducer/Converters/mcCollisionConverter.cxx @@ -0,0 +1,42 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" + +using namespace o2; +using namespace o2::framework; + +struct mcCollisionConverter { + Produces mcCollisions_001; + + void process(aod::McCollisions_000 const& mcCollisionTable) + { + for (auto& mcCollision : mcCollisionTable) { + + // Repopulate new table + mcCollisions_001( + mcCollision.bcId(), + mcCollision.generatorsID(), + mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), + mcCollision.t(), mcCollision.weight(), + mcCollision.impactParameter(), + 0.0f); // dummy event plane, not available in _000 + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/Common/TableProducer/Converters/multMCExtrasConverter.cxx b/Common/TableProducer/Converters/multMCExtrasConverter.cxx new file mode 100644 index 00000000000..ac2c074ba1b --- /dev/null +++ b/Common/TableProducer/Converters/multMCExtrasConverter.cxx @@ -0,0 +1,38 @@ +// 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. + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/Multiplicity.h" + +using namespace o2; +using namespace o2::framework; + +struct MultMCExtrasConverter { + Produces multMCExtras_001; + void process(aod::MultMCExtras_000 const& multMCExtras_000) + { + for (const auto& r : multMCExtras_000) { + multMCExtras_001(r.multMCFT0A(), r.multMCFT0C(), 0, 0, 0, + r.multMCNParticlesEta05(), + r.multMCNParticlesEta08(), + r.multMCNParticlesEta10(), + r.multMCPVz()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Common/TableProducer/Converters/multsExtraConverter.cxx b/Common/TableProducer/Converters/multsExtraConverter.cxx new file mode 100644 index 00000000000..d62b34508b8 --- /dev/null +++ b/Common/TableProducer/Converters/multsExtraConverter.cxx @@ -0,0 +1,42 @@ +// 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. + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/Multiplicity.h" + +using namespace o2; +using namespace o2::framework; + +struct MultsExtraConverter { + Produces multsExtra_001; + void process(aod::MultsExtra_000 const& multsExtra_000) + { + for (const auto& r : multsExtra_000) { + multsExtra_001(r.multPVTotalContributors(), r.multPVChi2(), + r.multCollisionTimeRes(), r.multRunNumber(), r.multPVz(), r.multSel8(), + r.multNTracksHasITS(), r.multNTracksHasTPC(), r.multNTracksHasTOF(), + r.multNTracksHasTRD(), r.multNTracksITSOnly(), + r.multNTracksTPCOnly(), r.multNTracksITSTPC(), + r.multAllTracksTPCOnly(), r.multAllTracksITSTPC(), + r.trackOccupancyInTimeRange(), + 0.0f, + r.flags()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Common/TableProducer/Converters/run2TinyToFullPID.cxx b/Common/TableProducer/Converters/run2TinyToFullPID.cxx new file mode 100644 index 00000000000..23b6c5a8cbf --- /dev/null +++ b/Common/TableProducer/Converters/run2TinyToFullPID.cxx @@ -0,0 +1,166 @@ +// 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. +// +// This task converts tiny PID tables into full PID tables. +// It is meant to be used with Run 2 converted data to maintain +// full compatibility with any task that may subscribe to the Full +// tables (at the cost of some memory consumption). +// It is also able to produce very simple QA plots on the stored +// quantities (optionally disabled for simplicity) +// +// Warning: expected resolution is NOT provided. + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/PIDResponse.h" +#include "TableHelper.h" + +using namespace o2; +using namespace o2::framework; + +using tinyPidTracks = soa::Join; + +static constexpr int kPidEl = 0; +static constexpr int kPidMu = 1; +static constexpr int kPidPi = 2; +static constexpr int kPidKa = 3; +static constexpr int kPidPr = 4; +static constexpr int kPidDe = 5; +static constexpr int kPidTr = 6; +static constexpr int kPidHe = 7; +static constexpr int kPidAl = 8; +static constexpr int nTables = 9; + +static constexpr int nParameters = 1; +static const std::vector tableNames{"pidTPCFullEl", // 0 + "pidTPCFullMu", // 1 + "pidTPCFullPi", // 2 + "pidTPCFullKa", // 3 + "pidTPCFullPr", // 4 + "pidTPCFullDe", // 5 + "pidTPCFullTr", // 6 + "pidTPCFullHe", // 7 + "pidTPCFullAl"}; // 8 +static const std::vector parameterNames{"enable"}; +static const int defaultParameters[nTables][nParameters]{{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}}; + +struct Run2TinyToFullPID { + Produces pidTPCFullEl; + Produces pidTPCFullMu; + Produces pidTPCFullPi; + Produces pidTPCFullKa; + Produces pidTPCFullPr; + Produces pidTPCFullDe; + Produces pidTPCFullTr; + Produces pidTPCFullHe; + Produces pidTPCFullAl; + + Configurable> enabledTables{"enabledTables", + {defaultParameters[0], nTables, nParameters, tableNames, parameterNames}, + "Produce full PID tables depending on needs. Autodetect is -1, Force no is 0 and force yes is 1."}; + + std::vector mEnabledTables; // Vector of enabled tables + + void init(InitContext& context) + { + for (int i = 0; i < nTables; i++) { + LOGF(info, "test %i", i); + int f = enabledTables->get(tableNames[i].c_str(), "enable"); + enableFlagIfTableRequired(context, tableNames[i], f); + if (f == 1) { + mEnabledTables.push_back(i); + } + } + } + + void process(tinyPidTracks const& tracks) + { + // reserve memory + for (auto i : mEnabledTables) { + switch (i) { + case kPidEl: + pidTPCFullEl.reserve(tracks.size()); + break; + case kPidMu: + pidTPCFullMu.reserve(tracks.size()); + break; + case kPidPi: + pidTPCFullPi.reserve(tracks.size()); + break; + case kPidKa: + pidTPCFullKa.reserve(tracks.size()); + break; + case kPidPr: + pidTPCFullPr.reserve(tracks.size()); + break; + case kPidDe: + pidTPCFullDe.reserve(tracks.size()); + break; + case kPidTr: + pidTPCFullTr.reserve(tracks.size()); + break; + case kPidHe: + pidTPCFullHe.reserve(tracks.size()); + break; + case kPidAl: + pidTPCFullAl.reserve(tracks.size()); + break; + default: + LOG(fatal) << "Unknown table requested: " << i; + break; + } + } + + for (const auto& track : tracks) { + for (auto i : mEnabledTables) { + switch (i) { + case kPidEl: + pidTPCFullEl(0.0f, track.tpcNSigmaEl()); + break; + case kPidMu: + pidTPCFullMu(0.0f, track.tpcNSigmaMu()); + break; + case kPidPi: + pidTPCFullPi(0.0f, track.tpcNSigmaPi()); + break; + case kPidKa: + pidTPCFullKa(0.0f, track.tpcNSigmaKa()); + break; + case kPidPr: + pidTPCFullPr(0.0f, track.tpcNSigmaPr()); + break; + case kPidDe: + pidTPCFullDe(0.0f, track.tpcNSigmaDe()); + break; + case kPidTr: + pidTPCFullTr(0.0f, track.tpcNSigmaTr()); + break; + case kPidHe: + pidTPCFullHe(0.0f, track.tpcNSigmaHe()); + break; + case kPidAl: + pidTPCFullAl(0.0f, track.tpcNSigmaAl()); + break; + default: + LOG(fatal) << "Unknown table requested: " << i; + break; + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Common/TableProducer/Converters/run2bcinfosConverter.cxx b/Common/TableProducer/Converters/run2bcinfosConverter.cxx new file mode 100644 index 00000000000..6257d371824 --- /dev/null +++ b/Common/TableProducer/Converters/run2bcinfosConverter.cxx @@ -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. + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" + +using namespace o2; +using namespace o2::framework; + +struct Run2BCInfosConverter { + Produces Run2BCInfos_001; + void process(aod::Run2BCInfos_000 const& Run2BCInfos_000) + { + + for (const auto& entry : Run2BCInfos_000) { + Run2BCInfos_001(entry.eventCuts(), + entry.triggerMaskNext50(), entry.l0TriggerInputMask(), + entry.spdClustersL0(), entry.spdClustersL1(), + entry.spdFiredChipsL0(), entry.spdFiredChipsL1(), + entry.spdFiredFastOrL0(), entry.spdFiredFastOrL1(), + entry.v0TriggerChargeA(), entry.v0TriggerChargeC(), + 0, 0); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Common/TableProducer/Converters/run2tracksExtraConverter.cxx b/Common/TableProducer/Converters/run2tracksExtraConverter.cxx new file mode 100644 index 00000000000..28ae54c4367 --- /dev/null +++ b/Common/TableProducer/Converters/run2tracksExtraConverter.cxx @@ -0,0 +1,34 @@ +// 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. + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" + +using namespace o2; +using namespace o2::framework; + +struct Run2TracksExtraConverter { + Produces Run2TrackExtras_001; + void process(aod::Run2TrackExtras_000 const& Run2TrackExtras_000) + { + + for (const auto& track0 : Run2TrackExtras_000) { + Run2TrackExtras_001(track0.itsSignal(), 0); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Common/TableProducer/Converters/trackQA002Converter.cxx b/Common/TableProducer/Converters/trackQA002Converter.cxx new file mode 100644 index 00000000000..566c998e1bc --- /dev/null +++ b/Common/TableProducer/Converters/trackQA002Converter.cxx @@ -0,0 +1,97 @@ +// 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. +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" + +using namespace o2; +using namespace o2::framework; + +struct TrackQAConverter002 { + Produces tracksQA_002; + + void process000(aod::TracksQA_000 const& tracksQA_000) + { + for (const auto& trackQA : tracksQA_000) { + tracksQA_002( + trackQA.trackId(), + trackQA.tpcTime0(), + trackQA.tpcdcaR(), + trackQA.tpcdcaZ(), + trackQA.tpcClusterByteMask(), + trackQA.tpcdEdxMax0R(), + trackQA.tpcdEdxMax1R(), + trackQA.tpcdEdxMax2R(), + trackQA.tpcdEdxMax3R(), + trackQA.tpcdEdxTot0R(), + trackQA.tpcdEdxTot1R(), + trackQA.tpcdEdxTot2R(), + trackQA.tpcdEdxTot3R(), + // dummy values, not available in _000 + std::numeric_limits::min(), // deltaRefContParamY + std::numeric_limits::min(), // deltaRefContParamZ + std::numeric_limits::min(), // deltaRefContParamSnp + std::numeric_limits::min(), // deltaRefContParamTgl + std::numeric_limits::min(), // deltaRefContParamQ2Pt + std::numeric_limits::min(), // deltaRefGloParamY + std::numeric_limits::min(), // deltaRefGloParamZ + std::numeric_limits::min(), // deltaRefGloParamSnp + std::numeric_limits::min(), // deltaRefGloParamTgl + std::numeric_limits::min(), // deltaRefGloParamQ2Pt + std::numeric_limits::min(), // dTofdX + std::numeric_limits::min()); // dTofdY + } + } + PROCESS_SWITCH(TrackQAConverter002, process000, "process v000-to-v002 conversion", false); + + void process001(aod::TracksQA_001 const& tracksQA_001) + { + for (const auto& trackQA : tracksQA_001) { + tracksQA_002( + trackQA.trackId(), + trackQA.tpcTime0(), + trackQA.tpcdcaR(), + trackQA.tpcdcaZ(), + trackQA.tpcClusterByteMask(), + trackQA.tpcdEdxMax0R(), + trackQA.tpcdEdxMax1R(), + trackQA.tpcdEdxMax2R(), + trackQA.tpcdEdxMax3R(), + trackQA.tpcdEdxTot0R(), + trackQA.tpcdEdxTot1R(), + trackQA.tpcdEdxTot2R(), + trackQA.tpcdEdxTot3R(), + trackQA.deltaRefContParamY(), + trackQA.deltaRefITSParamZ(), + trackQA.deltaRefContParamSnp(), + trackQA.deltaRefContParamTgl(), + trackQA.deltaRefContParamQ2Pt(), + trackQA.deltaRefGloParamY(), + trackQA.deltaRefGloParamZ(), + trackQA.deltaRefGloParamSnp(), + trackQA.deltaRefGloParamTgl(), + trackQA.deltaRefGloParamQ2Pt(), + // dummy values, not available in _001 + std::numeric_limits::min(), // dTofdX + std::numeric_limits::min()); // dTofdY + } + } + PROCESS_SWITCH(TrackQAConverter002, process001, "process v001-to-v002 conversion", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/Common/TableProducer/Converters/trackQAConverter.cxx b/Common/TableProducer/Converters/trackQAConverter.cxx new file mode 100644 index 00000000000..bdfecbca8d0 --- /dev/null +++ b/Common/TableProducer/Converters/trackQAConverter.cxx @@ -0,0 +1,60 @@ +// 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. +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" + +using namespace o2; +using namespace o2::framework; + +struct trackQAConverter { + Produces tracksQA_001; + + void process(aod::TracksQA_000 const& tracksQA_000) + { + for (const auto& trackQA : tracksQA_000) { + tracksQA_001( + trackQA.trackId(), + trackQA.tpcTime0(), + trackQA.tpcdcaR(), + trackQA.tpcdcaZ(), + trackQA.tpcClusterByteMask(), + trackQA.tpcdEdxMax0R(), + trackQA.tpcdEdxMax1R(), + trackQA.tpcdEdxMax2R(), + trackQA.tpcdEdxMax3R(), + trackQA.tpcdEdxTot0R(), + trackQA.tpcdEdxTot1R(), + trackQA.tpcdEdxTot2R(), + trackQA.tpcdEdxTot3R(), + // dummy values, not available in _000 + std::numeric_limits::min(), // deltaRefContParamY + std::numeric_limits::min(), // deltaRefContParamZ + std::numeric_limits::min(), // deltaRefContParamSnp + std::numeric_limits::min(), // deltaRefContParamTgl + std::numeric_limits::min(), // deltaRefContParamQ2Pt + std::numeric_limits::min(), // deltaRefGloParamY + std::numeric_limits::min(), // deltaRefGloParamZ + std::numeric_limits::min(), // deltaRefGloParamSnp + std::numeric_limits::min(), // deltaRefGloParamTgl + std::numeric_limits::min()); // deltaRefGloParamQ2Pt + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/Common/TableProducer/Converters/tracksExtraV002Converter.cxx b/Common/TableProducer/Converters/tracksExtraV002Converter.cxx new file mode 100644 index 00000000000..a70ac8ea8a8 --- /dev/null +++ b/Common/TableProducer/Converters/tracksExtraV002Converter.cxx @@ -0,0 +1,115 @@ +// 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. + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" + +using namespace o2; +using namespace o2::framework; + +struct TracksExtraV002Converter { + Produces tracksExtra_002; + + void init(InitContext const&) + { + if (doprocessV000ToV002 == false && doprocessV001ToV002 == false) { + LOGF(fatal, "Neither processV000ToV002 nor processV001ToV002 is enabled. Please choose one!"); + } + if (doprocessV000ToV002 == true && doprocessV001ToV002 == true) { + LOGF(fatal, "Both processV000ToV002 and processV001ToV002 are enabled. Please choose only one!"); + } + } + + void processV000ToV002(aod::TracksExtra_000 const& tracksExtra_000) + { + + for (const auto& track0 : tracksExtra_000) { + + uint32_t itsClusterSizes = 0; + for (int layer = 0; layer < 7; layer++) { + if (track0.itsClusterMap() & (1 << layer)) { + itsClusterSizes |= (0xf << (layer * 4)); + } + } + + int8_t TPCNClsFindableMinusPID = 0; + + tracksExtra_002(track0.tpcInnerParam(), + track0.flags(), + itsClusterSizes, + track0.tpcNClsFindable(), + track0.tpcNClsFindableMinusFound(), + TPCNClsFindableMinusPID, + track0.tpcNClsFindableMinusCrossedRows(), + track0.tpcNClsShared(), + track0.trdPattern(), + track0.itsChi2NCl(), + track0.tpcChi2NCl(), + track0.trdChi2(), + track0.tofChi2(), + track0.tpcSignal(), + track0.trdSignal(), + track0.length(), + track0.tofExpMom(), + track0.trackEtaEmcal(), + track0.trackPhiEmcal(), + track0.trackTime(), + track0.trackTimeRes()); + } + } + PROCESS_SWITCH(TracksExtraV002Converter, processV000ToV002, "process v000-to-v002 conversion", false); + + void processV001ToV002(aod::TracksExtra_001 const& tracksExtra_001) + { + + for (const auto& track1 : tracksExtra_001) { + + int8_t TPCNClsFindableMinusPID = 0; + + tracksExtra_002(track1.tpcInnerParam(), + track1.flags(), + track1.itsClusterSizes(), + track1.tpcNClsFindable(), + track1.tpcNClsFindableMinusFound(), + TPCNClsFindableMinusPID, + track1.tpcNClsFindableMinusCrossedRows(), + track1.tpcNClsShared(), + track1.trdPattern(), + track1.itsChi2NCl(), + track1.tpcChi2NCl(), + track1.trdChi2(), + track1.tofChi2(), + track1.tpcSignal(), + track1.trdSignal(), + track1.length(), + track1.tofExpMom(), + track1.trackEtaEmcal(), + track1.trackPhiEmcal(), + track1.trackTime(), + track1.trackTimeRes()); + } + } + PROCESS_SWITCH(TracksExtraV002Converter, processV001ToV002, "process v001-to-v002 conversion", true); +}; + +/// Spawn the extended table for TracksExtra002 to avoid the call to the internal spawner and a consequent circular dependency +struct TracksExtraSpawner { + Spawns tracksExtra_002; +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + }; +} diff --git a/Common/TableProducer/PID/CMakeLists.txt b/Common/TableProducer/PID/CMakeLists.txt index 29491b7c8cd..d28a3268954 100644 --- a/Common/TableProducer/PID/CMakeLists.txt +++ b/Common/TableProducer/PID/CMakeLists.txt @@ -9,8 +9,13 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. -# TOF +# ITS +o2physics_add_dpl_workflow(pid-its + SOURCES pidITS.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) +# TOF o2physics_add_dpl_workflow(pid-tof-base SOURCES pidTOFBase.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::TOFBase @@ -21,6 +26,11 @@ o2physics_add_dpl_workflow(pid-tof PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::TOFWorkflowUtils COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(pid-tof-merge + SOURCES pidTOFMerge.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::TOFWorkflowUtils + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(pid-tof-beta SOURCES pidTOFbeta.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::TOFWorkflowUtils @@ -43,11 +53,6 @@ o2physics_add_dpl_workflow(pid-tpc PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(pid-tpc-full - SOURCES pidTPCFull.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore - COMPONENT_NAME Analysis) - # HMPID # BAYES diff --git a/Common/TableProducer/PID/pidITS.cxx b/Common/TableProducer/PID/pidITS.cxx new file mode 100644 index 00000000000..c3f437e6c8d --- /dev/null +++ b/Common/TableProducer/PID/pidITS.cxx @@ -0,0 +1,124 @@ +// 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 pidITS.cxx +/// \since 2024-11-12 +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \author Francesco Mazzaschi francesco.mazzaschi@cern.ch +/// \author Giorgio Alberto Lucia giorgio.alberto.lucia@cern.ch +/// \brief Task to produce PID tables for ITS split for each particle. +/// Only the tables for the mass hypotheses requested are filled, the others are sent empty. +/// + +#include +#include +#include + +// O2 includes +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "ReconstructionDataFormats/Track.h" +#include "CCDB/BasicCCDBManager.h" +#include "TOFBase/EventTimeMaker.h" + +// O2Physics includes +#include "Common/DataModel/PIDResponseITS.h" +#include "MetadataHelper.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::track; + +MetadataHelper metadataInfo; + +static constexpr int nCases = 2; +static constexpr int nParameters = 12; +static const std::vector casesNames{"Data", "MC"}; +static const std::vector parameterNames{"RespITSPar1", "RespITSPar2", "RespITSPar3", + "RespITSPar1_Z2", "RespITSPar2_Z2", "RespITSPar3_Z2", + "ResolutionPar1", "ResolutionPar2", "ResolutionPar3", + "ResolutionPar1_Z2", "ResolutionPar2_Z2", "ResolutionPar3_Z2"}; + +static constexpr float defaultParameters[nCases][nParameters] = { + {1.18941, 1.53792, 1.69961, 2.35117, 1.80347, 5.14355, 1.94669e-01, -2.08616e-01, 1.30753, 8.74371e-02, -1.82804, 5.06449e-01}, + {1.18941, 1.53792, 1.69961, 2.35117, 1.80347, 5.14355, 1.94669e-01, -2.08616e-01, 1.30753, 8.74371e-02, -1.82804, 5.06449e-01}}; + +/// Task to produce the ITS PID information for each particle species +/// The parametrization is: [p0/(bg)**p1 + p2] being bg = p/m. Different parametrizations are used for He3 and Alpha particles. +/// The resolution depends on the bg and is modelled with an erf function: p0*TMath::Erf((bg-p1)/p2) +struct itsPid { + + Configurable> itsParams{"itsParams", + {defaultParameters[0], nCases, nParameters, casesNames, parameterNames}, + "Response parameters"}; + Configurable getFromCCDB{"getFromCCDB", false, "Get the parameters from CCDB"}; + + Service ccdb; + Configurable paramfile{"param-file", "", "Path to the parametrization object, if empty the parametrization is not taken from file"}; + Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPath{"ccdbPath", "Analysis/PID/TPC/Response", "Path of the TPC parametrization on the CCDB"}; + Configurable recoPass{"recoPass", "", "Reconstruction pass name for CCDB query (automatically takes latest object for timestamp if blank)"}; + Configurable ccdbTimestamp{"ccdb-timestamp", 0, "timestamp of the object used to query in CCDB the detector response. Exceptions: -1 gets the latest object, 0 gets the run dependent timestamp"}; + + void init(o2::framework::InitContext&) + { + if (getFromCCDB) { + ccdb->setURL(url.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + LOG(fatal) << "Not implemented yet"; + } else { + const char* dataType = metadataInfo.isMC() ? "MC" : "Data"; + o2::aod::ITSResponse::setParameters(itsParams->get(dataType, "RespITSPar1"), + itsParams->get(dataType, "RespITSPar2"), + itsParams->get(dataType, "RespITSPar3"), + itsParams->get(dataType, "RespITSPar1_Z2"), + itsParams->get(dataType, "RespITSPar2_Z2"), + itsParams->get(dataType, "RespITSPar3_Z2"), + itsParams->get(dataType, "ResolutionPar1"), + itsParams->get(dataType, "ResolutionPar2"), + itsParams->get(dataType, "ResolutionPar3"), + itsParams->get(dataType, "ResolutionPar1_Z2"), + itsParams->get(dataType, "ResolutionPar2_Z2"), + itsParams->get(dataType, "ResolutionPar3_Z2")); + } + } + + /// Dummy process function for BCs, needed in case both Run2 and Run3 process functions are disabled + void process(aod::Timestamps const&) {} + + void processTest(o2::soa::Join const& tracks) + { + auto tracksWithPid = soa::Attach, + aod::pidits::ITSNSigmaEl, aod::pidits::ITSNSigmaMu, aod::pidits::ITSNSigmaPi, + aod::pidits::ITSNSigmaKa, aod::pidits::ITSNSigmaPr, aod::pidits::ITSNSigmaDe, + aod::pidits::ITSNSigmaTr, aod::pidits::ITSNSigmaHe, aod::pidits::ITSNSigmaAl>(tracks); + + for (const auto& track : tracksWithPid) { + LOG(info) << track.itsNSigmaEl(); + LOG(info) << track.itsNSigmaPi(); + LOG(info) << track.itsNSigmaPr(); + } + } + PROCESS_SWITCH(itsPid, processTest, "Produce a test", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // Parse the metadata + metadataInfo.initMetadata(cfgc); + auto workflow = WorkflowSpec{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/Common/TableProducer/PID/pidTOFBase.cxx b/Common/TableProducer/PID/pidTOFBase.cxx index 47047a82035..f0f9722fc6b 100644 --- a/Common/TableProducer/PID/pidTOFBase.cxx +++ b/Common/TableProducer/PID/pidTOFBase.cxx @@ -30,6 +30,8 @@ #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/FT0Corrected.h" #include "Common/DataModel/Multiplicity.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" #include "TableHelper.h" #include "pidTOFBase.h" @@ -39,36 +41,26 @@ using namespace o2::pid; using namespace o2::framework::expressions; using namespace o2::track; -void customize(std::vector& workflowOptions) -{ - std::vector options{{"add-qa", VariantType::Int, 0, {"Legacy. No effect."}}, - {"evtime", VariantType::Int, 1, {"Produce the table for the Event Time"}}}; - std::swap(workflowOptions, options); -} - -#include "Framework/runDataProcessing.h" - /// Selection criteria for tracks used for TOF event time float trackDistanceForGoodMatch = 999.f; float trackDistanceForGoodMatchLowMult = 999.f; int multiplicityThreshold = 0; using Run3Trks = o2::soa::Join; -using Run3Cols = o2::soa::Join; +using Run3Cols = aod::Collisions; bool isTrackGoodMatchForTOFPID(const Run3Trks::iterator& tr, const Run3Cols& /*ev*/) { if (!tr.hasTOF()) { return false; } - if (tr.has_collision() && tr.collision_as().multNTracksPVeta1() < multiplicityThreshold) { - return tr.tofChi2() < trackDistanceForGoodMatchLowMult; - } - return tr.tofChi2() < trackDistanceForGoodMatch; + return true; } /// Task to produce the TOF signal from the trackTime information struct tofSignal { o2::framework::Produces table; o2::framework::Produces tableFlags; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + bool enableTable = false; // Flag to check if the TOF signal table is requested or not bool enableTableFlags = false; // Flag to check if the TOF signal flags table is requested or not // CCDB configuration @@ -78,6 +70,7 @@ struct tofSignal { Configurable distanceForGoodMatch{"distanceForGoodMatch", 999.f, "Maximum distance to consider a good match"}; Configurable distanceForGoodMatchLowMult{"distanceForGoodMatchLowMult", 999.f, "Maximum distance to consider a good match for low multiplicity events"}; Configurable multThreshold{"multThreshold", 0, "Multiplicity threshold to consider a low multiplicity event"}; + Configurable enableQaHistograms{"enableQaHistograms", false, "Flag to enable the QA histograms"}; void init(o2::framework::InitContext& initContext) { @@ -101,6 +94,13 @@ struct tofSignal { trackDistanceForGoodMatchLowMult = distanceForGoodMatchLowMult; multiplicityThreshold = multThreshold; LOG(info) << "Configuring selections for good match: " << trackDistanceForGoodMatch << " low mult " << trackDistanceForGoodMatchLowMult << " mult. threshold " << multiplicityThreshold; + if (!enableQaHistograms) { + return; + } + histos.add("tofSignal", "tofSignal", kTH1D, {{1000, -1000, 1000000, "tofSignal (ps)"}}); + if (enableTableFlags) { + histos.add("goodForPIDFlags", "goodForPIDFlags", kTH1D, {{3, 0, 3, "flags"}}); + } } void processRun3(Run3Trks const& tracks, Run3Cols const& collisions) { @@ -112,11 +112,19 @@ struct tofSignal { tableFlags.reserve(tracks.size()); } for (auto& t : tracks) { - table(o2::pid::tof::TOFSignal::GetTOFSignal(t)); + const auto s = o2::pid::tof::TOFSignal::GetTOFSignal(t); + if (enableQaHistograms) { + histos.fill(HIST("tofSignal"), s); + } + table(s); if (!enableTableFlags) { continue; } - tableFlags(isTrackGoodMatchForTOFPID(t, collisions)); + const auto b = isTrackGoodMatchForTOFPID(t, collisions); + if (enableQaHistograms) { + histos.fill(HIST("goodForPIDFlags"), s); + } + tableFlags(b); } } PROCESS_SWITCH(tofSignal, processRun3, "Process Run3 data i.e. input is TrackIU", true); @@ -537,9 +545,6 @@ struct tofEventTime { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { auto workflow = WorkflowSpec{adaptAnalysisTask(cfgc)}; - if (!cfgc.options().get("evtime")) { - return workflow; - } workflow.push_back(adaptAnalysisTask(cfgc)); return workflow; } diff --git a/Common/TableProducer/PID/pidTOFBase.h b/Common/TableProducer/PID/pidTOFBase.h index d8556f95432..2861cf883ce 100644 --- a/Common/TableProducer/PID/pidTOFBase.h +++ b/Common/TableProducer/PID/pidTOFBase.h @@ -37,8 +37,6 @@ namespace o2::aod namespace pidtofevtime { -DECLARE_SOA_COLUMN(TOFEvTime, tofEvTime, float); //! event time for TOF signal. Can be obtained via a combination of detectors e.g. TOF, FT0A, FT0C -DECLARE_SOA_COLUMN(TOFEvTimeErr, tofEvTimeErr, float); //! event time error for TOF. Can be obtained via a combination of detectors e.g. TOF, FT0A, FT0C // TOF only columns DECLARE_SOA_COLUMN(UsedForTOFEvTime, usedForTOFEvTime, uint8_t); //! Flag to check if track was used in the TOF event time making DECLARE_SOA_COLUMN(EvTimeTOF, evTimeTOF, float); //! Event time computed with the TOF detector @@ -46,10 +44,6 @@ DECLARE_SOA_COLUMN(EvTimeTOFErr, evTimeTOFErr, float); //! Error of th DECLARE_SOA_COLUMN(EvTimeTOFMult, evTimeTOFMult, int); //! Event time multiplicity for TOF } // namespace pidtofevtime -DECLARE_SOA_TABLE(TOFEvTime, "AOD", "TOFEvTime", //! Table of the TOF event time. One entry per track. - pidtofevtime::TOFEvTime, - pidtofevtime::TOFEvTimeErr); - DECLARE_SOA_TABLE(EvTimeTOFOnly, "AOD", "EvTimeTOFOnly", //! Table for the TOF event time only with TOF. One entry per track. pidtofevtime::UsedForTOFEvTime, pidtofevtime::EvTimeTOF, diff --git a/Common/TableProducer/PID/pidTOFMerge.cxx b/Common/TableProducer/PID/pidTOFMerge.cxx new file mode 100644 index 00000000000..2d2fd282bfd --- /dev/null +++ b/Common/TableProducer/PID/pidTOFMerge.cxx @@ -0,0 +1,1544 @@ +// 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 pidTOFMerge.cxx +/// \brief Task to produce PID tables for TOF split for each particle. +/// Only the tables for the mass hypotheses requested are filled, the others are sent empty. +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// + +#include +#include +#include +#include +#include + +// O2 includes +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "ReconstructionDataFormats/Track.h" +#include "CCDB/BasicCCDBManager.h" +#include "TOFBase/EventTimeMaker.h" + +// O2Physics includes +#include "TableHelper.h" +#include "MetadataHelper.h" +#include "CollisionTypeHelper.h" +#include "pidTOFBase.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::pid; +using namespace o2::framework::expressions; +using namespace o2::track; + +MetadataHelper metadataInfo; + +// Input data types +using Run3Trks = o2::soa::Join; +using Run3Cols = aod::Collisions; +using Run3TrksWtof = soa::Join; +using Run3TrksWtofWevTime = soa::Join; + +using EvTimeCollisions = soa::Join; +using EvTimeCollisionsFT0 = soa::Join; + +using Run2Trks = o2::soa::Join; +using Run2TrksWtofWevTime = soa::Join; + +// Configuration common to all tasks +struct TOFCalibConfig { + template + void init(const CfgType& opt) + { + mUrl = opt.cfgUrl.value; + mPathGrpLhcIf = opt.cfgPathGrpLhcIf.value; + mTimestamp = opt.cfgTimestamp.value; + mTimeShiftCCDBPathPos = opt.cfgTimeShiftCCDBPathPos.value; + mTimeShiftCCDBPathNeg = opt.cfgTimeShiftCCDBPathNeg.value; + mTimeShiftCCDBPathPosMC = opt.cfgTimeShiftCCDBPathPosMC.value; + mTimeShiftCCDBPathNegMC = opt.cfgTimeShiftCCDBPathNegMC.value; + mParamFileName = opt.cfgParamFileName.value; + mParametrizationPath = opt.cfgParametrizationPath.value; + mReconstructionPass = opt.cfgReconstructionPass.value; + mReconstructionPassDefault = opt.cfgReconstructionPassDefault.value; + mFatalOnPassNotAvailable = opt.cfgFatalOnPassNotAvailable.value; + mEnableTimeDependentResponse = opt.cfgEnableTimeDependentResponse.value; + mCollisionSystem = opt.cfgCollisionSystem.value; + mAutoSetProcessFunctions = opt.cfgAutoSetProcessFunctions.value; + } + + template + void getCfg(o2::framework::InitContext& initContext, const std::string name, VType& v, const std::string task) + { + if (!getTaskOptionValue(initContext, task, name, v, false)) { + LOG(fatal) << "Could not get " << name << " from " << task << " task"; + } + } + + void inheritFromBaseTask(o2::framework::InitContext& initContext, const std::string task = "tof-signal") + { + mInitMode = 2; + getCfg(initContext, "ccdb-url", mUrl, task); + getCfg(initContext, "ccdb-path-grplhcif", mPathGrpLhcIf, task); + getCfg(initContext, "ccdb-timestamp", mTimestamp, task); + getCfg(initContext, "timeShiftCCDBPathPos", mTimeShiftCCDBPathPos, task); + getCfg(initContext, "timeShiftCCDBPathNeg", mTimeShiftCCDBPathNeg, task); + getCfg(initContext, "timeShiftCCDBPathPosMC", mTimeShiftCCDBPathPosMC, task); + getCfg(initContext, "timeShiftCCDBPathNegMC", mTimeShiftCCDBPathNegMC, task); + getCfg(initContext, "paramFileName", mParamFileName, task); + getCfg(initContext, "parametrizationPath", mParametrizationPath, task); + getCfg(initContext, "reconstructionPass", mReconstructionPass, task); + getCfg(initContext, "reconstructionPassDefault", mReconstructionPassDefault, task); + getCfg(initContext, "fatalOnPassNotAvailable", mFatalOnPassNotAvailable, task); + getCfg(initContext, "enableTimeDependentResponse", mEnableTimeDependentResponse, task); + getCfg(initContext, "collisionSystem", mCollisionSystem, task); + getCfg(initContext, "autoSetProcessFunctions", mAutoSetProcessFunctions, task); + } + // @brief Set up the configuration from the calibration object from the init function of the task + template + void initSetup(o2::pid::tof::TOFResoParamsV3& mRespParamsV3, + CCDBObject ccdb) + { + mInitMode = 1; + // First we set the CCDB manager + ccdb->setURL(mUrl); + ccdb->setTimestamp(mTimestamp); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + // Not later than now objects + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + + // Then the information about the metadata + if (mReconstructionPass == "metadata") { + LOG(info) << "Getting pass from metadata"; + if (metadataInfo.isMC()) { + mReconstructionPass = metadataInfo.get("AnchorPassName"); + } else { + mReconstructionPass = metadataInfo.get("RecoPassName"); + } + LOG(info) << "Passed autodetect mode for pass. Taking '" << mReconstructionPass << "'"; + } + LOG(info) << "Using parameter collection, starting from pass '" << mReconstructionPass << "'"; + + if (!mParamFileName.empty()) { // Loading the parametrization from file + LOG(info) << "Loading exp. sigma parametrization from file " << mParamFileName << ", using param: " << mParametrizationPath << " and pass " << mReconstructionPass; + o2::tof::ParameterCollection paramCollection; + paramCollection.loadParamFromFile(mParamFileName, mParametrizationPath); + LOG(info) << "+++ Loaded parameter collection from file +++"; + if (!paramCollection.retrieveParameters(mRespParamsV3, mReconstructionPass)) { + if (mFatalOnPassNotAvailable) { + LOG(fatal) << "Pass '" << mReconstructionPass << "' not available in the retrieved object from file"; + } else { + LOG(warning) << "Pass '" << mReconstructionPass << "' not available in the retrieved object from file, fetching '" << mReconstructionPassDefault << "'"; + if (!paramCollection.retrieveParameters(mRespParamsV3, mReconstructionPassDefault)) { + paramCollection.print(); + LOG(fatal) << "Cannot get default pass for calibration " << mReconstructionPassDefault; + } else { + if (metadataInfo.isRun3()) { + mRespParamsV3.setResolutionParametrization(paramCollection.getPars(mReconstructionPassDefault)); + } else { + mRespParamsV3.setResolutionParametrizationRun2(paramCollection.getPars(mReconstructionPassDefault)); + } + mRespParamsV3.setMomentumChargeShiftParameters(paramCollection.getPars(mReconstructionPassDefault)); + } + } + } else { // Pass is available, load non standard parameters + if (metadataInfo.isRun3()) { + mRespParamsV3.setResolutionParametrization(paramCollection.getPars(mReconstructionPass)); + } else { + mRespParamsV3.setResolutionParametrizationRun2(paramCollection.getPars(mReconstructionPass)); + } + mRespParamsV3.setMomentumChargeShiftParameters(paramCollection.getPars(mReconstructionPass)); + } + } else if (!mEnableTimeDependentResponse) { // Loading it from CCDB + LOG(info) << "Loading initial exp. sigma parametrization from CCDB, using path: " << mParametrizationPath << " for timestamp " << mTimestamp; + o2::tof::ParameterCollection* paramCollection = ccdb->template getSpecific(mParametrizationPath, mTimestamp); + if (!paramCollection->retrieveParameters(mRespParamsV3, mReconstructionPass)) { // Attempt at loading the parameters with the pass defined + if (mFatalOnPassNotAvailable) { + LOG(fatal) << "Pass '" << mReconstructionPass << "' not available in the retrieved CCDB object"; + } else { + LOG(warning) << "Pass '" << mReconstructionPass << "' not available in the retrieved CCDB object, fetching '" << mReconstructionPassDefault << "'"; + if (!paramCollection->retrieveParameters(mRespParamsV3, mReconstructionPassDefault)) { + paramCollection->print(); + LOG(fatal) << "Cannot get default pass for calibration " << mReconstructionPassDefault; + } else { + if (metadataInfo.isRun3()) { + mRespParamsV3.setResolutionParametrization(paramCollection->getPars(mReconstructionPassDefault)); + } else { + mRespParamsV3.setResolutionParametrizationRun2(paramCollection->getPars(mReconstructionPassDefault)); + } + mRespParamsV3.setMomentumChargeShiftParameters(paramCollection->getPars(mReconstructionPassDefault)); + } + } + } else { // Pass is available, load non standard parameters + if (metadataInfo.isRun3()) { + mRespParamsV3.setResolutionParametrization(paramCollection->getPars(mReconstructionPass)); + } else { + mRespParamsV3.setResolutionParametrizationRun2(paramCollection->getPars(mReconstructionPass)); + } + mRespParamsV3.setMomentumChargeShiftParameters(paramCollection->getPars(mReconstructionPass)); + } + } + + // Loading additional calibration objects + std::map metadata; + if (!mReconstructionPass.empty()) { + metadata["RecoPassName"] = mReconstructionPass; + } + + auto updateTimeShift = [&](const std::string& nameShift, bool isPositive) { + if (nameShift.empty()) { + return; + } + const bool isFromFile = nameShift.find(".root") != std::string::npos; + if (isFromFile) { + LOG(info) << "Initializing the time shift for " << (isPositive ? "positive" : "negative") << " from file '" << nameShift << "'"; + mRespParamsV3.setTimeShiftParameters(nameShift, "ccdb_object", isPositive); + } else if (!mEnableTimeDependentResponse) { // If the response is fixed fetch it at the init time + LOG(info) << "Initializing the time shift for " << (isPositive ? "positive" : "negative") + << " from ccdb '" << nameShift << "' and timestamp " << mTimestamp + << " and pass '" << mReconstructionPass << "'"; + ccdb->setFatalWhenNull(false); + mRespParamsV3.setTimeShiftParameters(ccdb->template getSpecific(nameShift, mTimestamp, metadata), isPositive); + ccdb->setFatalWhenNull(true); + } + LOG(info) << " test getTimeShift at 0 " << (isPositive ? "pos" : "neg") << ": " + << mRespParamsV3.getTimeShift(0, isPositive); + }; + + const std::string nameShiftPos = metadataInfo.isMC() ? mTimeShiftCCDBPathPosMC : mTimeShiftCCDBPathPos; + updateTimeShift(nameShiftPos, true); + const std::string nameShiftNeg = metadataInfo.isMC() ? mTimeShiftCCDBPathNegMC : mTimeShiftCCDBPathNeg; + updateTimeShift(nameShiftNeg, false); + + // Calibration object is defined + LOG(info) << "Parametrization at init time:"; + mRespParamsV3.printFullConfig(); + } + + template + void processSetup(o2::pid::tof::TOFResoParamsV3& mRespParamsV3, + CCDBObject ccdb, + const BcType& bc) + { + LOG(debug) << "Processing setup for run number " << bc.runNumber() << " from run " << mLastRunNumber; + // First we check if this run number was already processed + if (mLastRunNumber == bc.runNumber()) { + return; + } + LOG(info) << "Updating the parametrization from last run " << mLastRunNumber << " to " << bc.runNumber() << " and timestamp from " << mTimestamp << " " << bc.timestamp(); + mLastRunNumber = bc.runNumber(); + mTimestamp = bc.timestamp(); + + // Check the beam type + if (mCollisionSystem == -1) { + o2::parameters::GRPLHCIFData* grpo = ccdb->template getSpecific(mPathGrpLhcIf, + mTimestamp); + mCollisionSystem = CollisionSystemType::getCollisionTypeFromGrp(grpo); + } else { + LOG(debug) << "Not setting collisions system as already set to " << mCollisionSystem << " " << CollisionSystemType::getCollisionSystemName(mCollisionSystem); + } + + if (!mEnableTimeDependentResponse) { + return; + } + LOG(info) << "Updating parametrization from path '" << mParametrizationPath << "' and timestamp " << mTimestamp << " and reconstruction pass '" << mReconstructionPass << "' for run number " << bc.runNumber(); + if (mParamFileName.empty()) { // Not loading if parametrization was taken from file + LOG(info) << "Updating parametrization from ccdb"; + const o2::tof::ParameterCollection* paramCollection = ccdb->template getSpecific(mParametrizationPath, mTimestamp); + if (!paramCollection->retrieveParameters(mRespParamsV3, mReconstructionPass)) { + if (mFatalOnPassNotAvailable) { + LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", mReconstructionPass.data()); + } else { + LOGF(warning, "Pass '%s' not available in the retrieved CCDB object, fetching '%s'", mReconstructionPass.data(), mReconstructionPassDefault.data()); + if (!paramCollection->retrieveParameters(mRespParamsV3, mReconstructionPassDefault)) { + paramCollection->print(); + LOG(fatal) << "Cannot get default pass for calibration " << mReconstructionPassDefault; + } else { // Found the default case + if (metadataInfo.isRun3()) { + mRespParamsV3.setResolutionParametrization(paramCollection->getPars(mReconstructionPassDefault)); + } else { + mRespParamsV3.setResolutionParametrizationRun2(paramCollection->getPars(mReconstructionPassDefault)); + } + mRespParamsV3.setMomentumChargeShiftParameters(paramCollection->getPars(mReconstructionPassDefault)); + } + } + } else { // Found the non default case + if (metadataInfo.isRun3()) { + mRespParamsV3.setResolutionParametrization(paramCollection->getPars(mReconstructionPass)); + } else { + mRespParamsV3.setResolutionParametrizationRun2(paramCollection->getPars(mReconstructionPass)); + } + mRespParamsV3.setMomentumChargeShiftParameters(paramCollection->getPars(mReconstructionPass)); + } + } + + // Loading additional calibration objects + std::map metadata; + if (!mReconstructionPass.empty()) { + metadata["RecoPassName"] = mReconstructionPass; + } + + auto updateTimeShift = [&](const std::string& nameShift, bool isPositive) { + if (nameShift.empty()) { + return; + } + const bool isFromFile = nameShift.find(".root") != std::string::npos; + if (isFromFile) { + return; + } + LOG(info) << "Updating the time shift for " << (isPositive ? "positive" : "negative") + << " from ccdb '" << nameShift << "' and timestamp " << mTimestamp + << " and pass '" << mReconstructionPass << "'"; + ccdb->setFatalWhenNull(false); + mRespParamsV3.setTimeShiftParameters(ccdb->template getSpecific(nameShift, mTimestamp, metadata), isPositive); + ccdb->setFatalWhenNull(true); + LOG(info) << " test getTimeShift at 0 " << (isPositive ? "pos" : "neg") << ": " + << mRespParamsV3.getTimeShift(0, isPositive); + }; + + updateTimeShift(metadataInfo.isMC() ? mTimeShiftCCDBPathPosMC : mTimeShiftCCDBPathPos, true); + updateTimeShift(metadataInfo.isMC() ? mTimeShiftCCDBPathNegMC : mTimeShiftCCDBPathNeg, false); + + LOG(info) << "Parametrization at setup time:"; + mRespParamsV3.printFullConfig(); + } + + bool autoSetProcessFunctions() const { return mAutoSetProcessFunctions; } + int collisionSystem() const { return mCollisionSystem; } + + private: + int mLastRunNumber = -1; // Last run number for which the calibration was loaded + int mInitMode = 0; // 0: no init, 1: init, 2: inherit + + // Configurable options + std::string mUrl; + std::string mPathGrpLhcIf; + int64_t mTimestamp; + std::string mTimeShiftCCDBPathPos; + std::string mTimeShiftCCDBPathNeg; + std::string mTimeShiftCCDBPathPosMC; + std::string mTimeShiftCCDBPathNegMC; + std::string mParamFileName; + std::string mParametrizationPath; + std::string mReconstructionPass; + std::string mReconstructionPassDefault; + bool mFatalOnPassNotAvailable; + bool mEnableTimeDependentResponse; + int mCollisionSystem; + bool mAutoSetProcessFunctions; +}; + +// Part 1 TOF signal definition + +/// Selection criteria for tracks used for TOF event time +bool isTrackGoodMatchForTOFPID(const Run3Trks::iterator& tr) +{ + if (!tr.hasTOF()) { + return false; + } + return true; +} + +/// Task to produce the TOF signal from the trackTime information +struct tofSignal { + // Tables to produce + o2::framework::Produces table; + o2::framework::Produces tableFlags; + // Running flags + bool enableTableTOFSignal = false; // Flag to check if the TOF signal table is requested or not + bool enableTablepidTOFFlags = false; // Flag to check if the TOF signal flags table is requested or not + // Output histograms + Configurable enableQaHistograms{"enableQaHistograms", false, "Flag to enable the QA histograms"}; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + // Detector response and input parameters + o2::pid::tof::TOFResoParamsV3 mRespParamsV3; + Service ccdb; + struct : ConfigurableGroup { + Configurable cfgUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable cfgPathGrpLhcIf{"ccdb-path-grplhcif", "GLO/Config/GRPLHCIF", "Path on the CCDB for the GRPLHCIF object"}; + Configurable cfgTimestamp{"ccdb-timestamp", -1, "timestamp of the object"}; + Configurable cfgTimeShiftCCDBPathPos{"timeShiftCCDBPathPos", "", "Path of the TOF time shift vs eta for pos. tracks. If empty none is taken"}; + Configurable cfgTimeShiftCCDBPathNeg{"timeShiftCCDBPathNeg", "", "Path of the TOF time shift vs eta for neg. tracks. If empty none is taken"}; + Configurable cfgTimeShiftCCDBPathPosMC{"timeShiftCCDBPathPosMC", "", "Path of the TOF time shift for MC vs eta for pos. tracks. If empty none is taken"}; + Configurable cfgTimeShiftCCDBPathNegMC{"timeShiftCCDBPathNegMC", "", "Path of the TOF time shift for MC vs eta for neg. tracks. If empty none is taken"}; + Configurable cfgParamFileName{"paramFileName", "", "Path to the parametrization object. If empty the parametrization is not taken from file"}; + Configurable cfgParametrizationPath{"parametrizationPath", "TOF/Calib/Params", "Path of the TOF parametrization on the CCDB or in the file, if the paramFileName is not empty"}; + Configurable cfgReconstructionPass{"reconstructionPass", "", {"Apass to use when fetching the calibration tables. Empty (default) does not check for any pass. Use `metadata` to fetch it from the AO2D metadata. Otherwise it will override the metadata."}}; + Configurable cfgReconstructionPassDefault{"reconstructionPassDefault", "unanchored", {"Default pass to get if the standard one is not found"}}; + Configurable cfgFatalOnPassNotAvailable{"fatalOnPassNotAvailable", true, "Flag to throw a fatal if the pass is not available in the retrieved CCDB object"}; + Configurable cfgEnableTimeDependentResponse{"enableTimeDependentResponse", false, "Flag to use the collision timestamp to fetch the PID Response"}; + Configurable cfgCollisionSystem{"collisionSystem", -1, "Collision system: -1 (autoset), 0 (pp), 1 (PbPb), 2 (XeXe), 3 (pPb)"}; + Configurable cfgAutoSetProcessFunctions{"autoSetProcessFunctions", true, "Flag to autodetect the process functions to use"}; + } cfg; // Configurables (only defined here and inherited from other tasks) + + TOFCalibConfig mTOFCalibConfig; // TOF Calib configuration + + void init(o2::framework::InitContext& initContext) + { + mTOFCalibConfig.init(cfg); + // Checking that the table is requested in the workflow and enabling it + enableTableTOFSignal = isTableRequiredInWorkflow(initContext, "TOFSignal"); + if (enableTableTOFSignal) { + LOG(info) << "Table TOFSignal enabled!"; + } + enableTablepidTOFFlags = isTableRequiredInWorkflow(initContext, "pidTOFFlags"); + if (enableTablepidTOFFlags) { + LOG(info) << "Table pidTOFFlags enabled!"; + } + + // If the table is not requested, disable the task. Uless a process function is enabled from the workflow configuration + if (!enableTableTOFSignal && !enableTablepidTOFFlags && !doprocessRun2 && !doprocessRun3) { + LOG(info) << "No table or process is enabled. Disabling task"; + return; + } + if (mTOFCalibConfig.autoSetProcessFunctions()) { + LOG(info) << "Autodetecting process functions"; + if (metadataInfo.isFullyDefined() && !doprocessRun2 && !doprocessRun3) { // Check if the metadata is initialized (only if not forced from the workflow configuration) + if (metadataInfo.isRun3()) { + doprocessRun3.value = true; + } else { + doprocessRun2.value = false; + } + } + } + + // Last checks on the process functions + if (doprocessRun2 && doprocessRun3) { + LOG(fatal) << "Both processRun2 and processRun3 are enabled. Pick one of the two"; + } + if (!doprocessRun2 && !doprocessRun3) { + LOG(fatal) << "Neither processRun2 nor processRun3 are enabled. Pick one of the two"; + } + mTOFCalibConfig.initSetup(mRespParamsV3, ccdb); // Getting the parametrization parameters + if (!enableQaHistograms) { + return; + } + histos.add("tofSignal", "tofSignal", kTH1D, {{1000, -1000, 1000000, "tofSignal (ps)"}}); + if (enableTablepidTOFFlags) { + histos.add("goodForPIDFlags", "goodForPIDFlags", kTH1D, {{3, 0, 3, "flags"}}); + } + } + + /// Dummy process function for BCs, needed in case both Run2 and Run3 process functions are disabled + void process(aod::BCs const&) {} + + void processRun3(Run3Trks const& tracks) + { + if (!enableTableTOFSignal) { + return; + } + table.reserve(tracks.size()); + if (enableTablepidTOFFlags) { + tableFlags.reserve(tracks.size()); + } + for (const auto& trk : tracks) { + const float& sig = o2::pid::tof::TOFSignal::GetTOFSignal(trk); + if (enableQaHistograms) { + histos.fill(HIST("tofSignal"), sig); + } + table(sig); + if (!enableTablepidTOFFlags) { + continue; + } + const auto& b = isTrackGoodMatchForTOFPID(trk); + if (enableQaHistograms) { + histos.fill(HIST("goodForPIDFlags"), sig); + } + tableFlags(b); + } + } + PROCESS_SWITCH(tofSignal, processRun3, "Process Run3 data i.e. input is TrackIU. Set to false to autodetect from metadata.", false); + + void processRun2(Run2Trks const& tracks) + { + if (!enableTableTOFSignal) { + return; + } + table.reserve(tracks.size()); + if (enableTablepidTOFFlags) { + tableFlags.reserve(tracks.size()); + } + for (const auto& trk : tracks) { + table(o2::pid::tof::TOFSignal::GetTOFSignal(trk)); + if (!enableTablepidTOFFlags) { + continue; + } + tableFlags(true); + } + } + PROCESS_SWITCH(tofSignal, processRun2, "Process Run2 data i.e. input is Tracks. Set to false to autodetect from metadata.", false); +}; + +/// Selection criteria for tracks used for TOF event time +float trackSampleMinMomentum = 0.5f; +float trackSampleMaxMomentum = 2.f; +template +bool filterForTOFEventTime(const trackType& tr) +{ + return (tr.hasTOF() && + tr.p() > trackSampleMinMomentum && tr.p() < trackSampleMaxMomentum && + tr.hasITS() && + tr.hasTPC() && + (tr.trackType() == o2::aod::track::TrackTypeEnum::Track || tr.trackType() == o2::aod::track::TrackTypeEnum::TrackIU)); +} // accept all + +/// Specialization of TOF event time maker +template typename response, + typename trackTypeContainer, + typename responseParametersType> +o2::tof::eventTimeContainer evTimeMakerForTracks(const trackTypeContainer& tracks, + const responseParametersType& responseParameters, + const float& diamond = 6.0) +{ + return o2::tof::evTimeMakerFromParam(tracks, responseParameters, diamond); +} + +// Part 2 event time definition + +/// Task to produce the TOF event time table +struct tofEventTime { + // Tables to produce + Produces tableEvTime; + Produces tableEvTimeTOFOnly; + Produces tableFlags; + static constexpr bool kRemoveTOFEvTimeBias = true; // Flag to subtract the Ev. Time bias for low multiplicity events with TOF + static constexpr float kDiamond = 6.0; // Collision diamond used in the estimation of the TOF event time + static constexpr float kErrDiamond = kDiamond * 33.356409f; + static constexpr float kWeightDiamond = 1.f / (kErrDiamond * kErrDiamond); + + bool enableTableTOFEvTime = false; + bool enableTableEvTimeTOFOnly = false; + // Detector response and input parameters + o2::pid::tof::TOFResoParamsV3 mRespParamsV3; + Service ccdb; + TOFCalibConfig mTOFCalibConfig; // TOF Calib configuration + + // Event time configurations + Configurable minMomentum{"minMomentum", 0.5f, "Minimum momentum to select track sample for TOF event time"}; + Configurable maxMomentum{"maxMomentum", 2.0f, "Maximum momentum to select track sample for TOF event time"}; + Configurable maxEvTimeTOF{"maxEvTimeTOF", 100000.0f, "Maximum value of the TOF event time"}; + Configurable sel8TOFEvTime{"sel8TOFEvTime", false, "Flag to compute the ev. time only for events that pass the sel8 ev. selection"}; + Configurable mComputeEvTimeWithTOF{"computeEvTimeWithTOF", -1, "Compute ev. time with TOF. -1 (autoset), 0 no, 1 yes"}; + Configurable mComputeEvTimeWithFT0{"computeEvTimeWithFT0", -1, "Compute ev. time with FT0. -1 (autoset), 0 no, 1 yes"}; + Configurable maxNtracksInSet{"maxNtracksInSet", 10, "Size of the set to consider for the TOF ev. time computation"}; + + void init(o2::framework::InitContext& initContext) + { + mTOFCalibConfig.inheritFromBaseTask(initContext); + // Checking that the table is requested in the workflow and enabling it + enableTableTOFEvTime = isTableRequiredInWorkflow(initContext, "TOFEvTime"); + + if (!enableTableTOFEvTime) { + LOG(info) << "Table for TOF Event time (TOFEvTime) is not required, disabling it"; + } + LOG(info) << "Table TOFEvTime enabled!"; + + enableTableEvTimeTOFOnly = isTableRequiredInWorkflow(initContext, "EvTimeTOFOnly"); + if (enableTableEvTimeTOFOnly) { + LOG(info) << "Table EvTimeTOFOnly enabled!"; + } + + if (!enableTableTOFEvTime && !enableTableEvTimeTOFOnly) { + LOG(info) << "No table is enabled. Disabling task"; + return; + } + + if (mTOFCalibConfig.autoSetProcessFunctions()) { + LOG(info) << "Autodetecting process functions"; + if (metadataInfo.isFullyDefined()) { + if (metadataInfo.isRun3()) { + doprocessRun3.value = true; + } else { + doprocessRun2.value = true; + } + } + } + + if (metadataInfo.isFullyDefined()) { + if (metadataInfo.isRun3() && doprocessRun2) { + LOG(fatal) << "Run2 process function is enabled but the metadata says it is Run3"; + } + if (!metadataInfo.isRun3() && doprocessRun3) { + LOG(fatal) << "Run3 process function is enabled but the metadata says it is Run2"; + } + } + + trackSampleMinMomentum = minMomentum; + trackSampleMaxMomentum = maxMomentum; + LOG(info) << "Configuring track sample for TOF ev. time: " << trackSampleMinMomentum << " < p < " << trackSampleMaxMomentum; + // Check that both processes are not enabled + int nEnabled = 0; + if (doprocessRun2 == true) { + LOGF(info, "Enabling process function: processRun2"); + nEnabled++; + } + if (doprocessRun3 == true) { + LOGF(info, "Enabling process function: processRun3"); + nEnabled++; + } + if (nEnabled > 1) { + LOGF(fatal, "Cannot enable more process functions at the same time. Please choose one."); + } + + if (sel8TOFEvTime.value == true) { + LOG(info) << "TOF event time will be computed for collisions that pass the event selection only!"; + } + mTOFCalibConfig.initSetup(mRespParamsV3, ccdb); // Getting the parametrization parameters + + o2::tof::eventTimeContainer::setMaxNtracksInSet(maxNtracksInSet.value); + o2::tof::eventTimeContainer::printConfig(); + } + + void process(aod::BCs const&) {} + + /// + /// Process function to prepare the event for each track on Run 2 data + void processRun2(aod::Tracks const& tracks, + aod::Collisions const&) + { + if (!enableTableTOFEvTime) { + return; + } + + tableEvTime.reserve(tracks.size()); + tableFlags.reserve(tracks.size()); + + for (auto const& t : tracks) { // Loop on collisions + if (!t.has_collision()) { // Track was not assigned, cannot compute event time + tableFlags(0); + tableEvTime(0.f, 999.f); + continue; + } + tableFlags(1); + tableEvTime(t.collision().collisionTime() * 1000.f, t.collision().collisionTimeRes() * 1000.f); + } + } + PROCESS_SWITCH(tofEventTime, processRun2, "Process with Run2 data", true); + + /// + /// Process function to prepare the event for each track on Run 3 data without the FT0 + // Define slice per collision + Preslice perCollision = aod::track::collisionId; + template + using ResponseImplementationEvTime = o2::pid::tof::ExpTimes; + void processRun3(Run3TrksWtof const& tracks, + aod::FT0s const&, + EvTimeCollisionsFT0 const&, + aod::BCsWithTimestamps const& bcs) + { + if (!enableTableTOFEvTime) { + return; + } + LOG(debug) << "Processing Run3 data for TOF event time"; + + tableEvTime.reserve(tracks.size()); + tableFlags.reserve(tracks.size()); + if (enableTableEvTimeTOFOnly) { + tableEvTimeTOFOnly.reserve(tracks.size()); + } + + mTOFCalibConfig.processSetup(mRespParamsV3, ccdb, bcs.iteratorAt(0)); // Update the calibration parameters + + // Autoset the processing mode for the event time computation + if (mComputeEvTimeWithTOF == -1 || mComputeEvTimeWithFT0 == -1) { + switch (mTOFCalibConfig.collisionSystem()) { + case CollisionSystemType::kCollSyspp: // pp + mComputeEvTimeWithTOF.value = ((mComputeEvTimeWithTOF == -1) ? 0 : mComputeEvTimeWithTOF.value); + mComputeEvTimeWithFT0.value = ((mComputeEvTimeWithFT0 == -1) ? 1 : mComputeEvTimeWithFT0.value); + break; + case CollisionSystemType::kCollSysPbPb: // PbPb + mComputeEvTimeWithTOF.value = ((mComputeEvTimeWithTOF == -1) ? 1 : mComputeEvTimeWithTOF.value); + mComputeEvTimeWithFT0.value = ((mComputeEvTimeWithFT0 == -1) ? 0 : mComputeEvTimeWithFT0.value); + break; + default: + LOG(fatal) << "Collision system " << mTOFCalibConfig.collisionSystem() << " " << CollisionSystemType::getCollisionSystemName(mTOFCalibConfig.collisionSystem()) << " not supported for TOF event time computation"; + break; + } + } + LOG(debug) << "Running on " << CollisionSystemType::getCollisionSystemName(mTOFCalibConfig.collisionSystem()) << " mComputeEvTimeWithTOF " << mComputeEvTimeWithTOF.value << " mComputeEvTimeWithFT0 " << mComputeEvTimeWithFT0.value; + + if (mComputeEvTimeWithTOF == 1 && mComputeEvTimeWithFT0 == 1) { + int lastCollisionId = -1; // Last collision ID analysed + for (auto const& t : tracks) { // Loop on collisions + if (!t.has_collision() || ((sel8TOFEvTime.value == true) && !t.collision_as().sel8())) { // Track was not assigned, cannot compute event time or event did not pass the event selection + tableFlags(0); + tableEvTime(0.f, 999.f); + if (enableTableEvTimeTOFOnly) { + tableEvTimeTOFOnly((uint8_t)0, 0.f, 0.f, -1); + } + continue; + } + if (t.collisionId() == lastCollisionId) { // Event time from this collision is already in the table + continue; + } + /// Create new table for the tracks in a collision + lastCollisionId = t.collisionId(); /// Cache last collision ID + + const auto& tracksInCollision = tracks.sliceBy(perCollision, lastCollisionId); + const auto& collision = t.collision_as(); + + // Compute the TOF event time + const auto evTimeMakerTOF = evTimeMakerForTracks(tracksInCollision, mRespParamsV3, kDiamond); + + float t0AC[2] = {.0f, 999.f}; // Value and error of T0A or T0C or T0AC + float t0TOF[2] = {static_cast(evTimeMakerTOF.mEventTime), static_cast(evTimeMakerTOF.mEventTimeError)}; // Value and error of TOF + + uint8_t flags = 0; + int nGoodTracksForTOF = 0; + float eventTime = 0.f; + float sumOfWeights = 0.f; + float weight = 0.f; + + for (auto const& trk : tracksInCollision) { // Loop on Tracks + // Reset the flag + flags = 0; + // Reset the event time + eventTime = 0.f; + sumOfWeights = 0.f; + weight = 0.f; + // Remove the bias on TOF ev. time + if constexpr (kRemoveTOFEvTimeBias) { + evTimeMakerTOF.removeBias(trk, nGoodTracksForTOF, t0TOF[0], t0TOF[1], 2); + } + if (t0TOF[1] < kErrDiamond && (maxEvTimeTOF <= 0 || std::abs(t0TOF[0]) < maxEvTimeTOF)) { + flags |= o2::aod::pidflags::enums::PIDFlags::EvTimeTOF; + + weight = 1.f / (t0TOF[1] * t0TOF[1]); + eventTime += t0TOF[0] * weight; + sumOfWeights += weight; + } + + if (collision.has_foundFT0()) { // T0 measurement is available + // const auto& ft0 = collision.foundFT0(); + if (collision.t0ACValid()) { + t0AC[0] = collision.t0AC() * 1000.f; + t0AC[1] = collision.t0resolution() * 1000.f; + flags |= o2::aod::pidflags::enums::PIDFlags::EvTimeT0AC; + } + + weight = 1.f / (t0AC[1] * t0AC[1]); + eventTime += t0AC[0] * weight; + sumOfWeights += weight; + } + + if (sumOfWeights < kWeightDiamond) { // avoiding sumOfWeights = 0 or worse that kDiamond + eventTime = 0; + sumOfWeights = kWeightDiamond; + tableFlags(0); + } else { + tableFlags(flags); + } + tableEvTime(eventTime / sumOfWeights, std::sqrt(1. / sumOfWeights)); + if (enableTableEvTimeTOFOnly) { + tableEvTimeTOFOnly((uint8_t)filterForTOFEventTime(trk), t0TOF[0], t0TOF[1], evTimeMakerTOF.mEventTimeMultiplicity); + } + } + } + } else if (mComputeEvTimeWithTOF == 1 && mComputeEvTimeWithFT0 == 0) { + int lastCollisionId = -1; // Last collision ID analysed + for (auto const& t : tracks) { // Loop on collisions + if (!t.has_collision() || ((sel8TOFEvTime.value == true) && !t.collision_as().sel8())) { // Track was not assigned, cannot compute event time or event did not pass the event selection + tableFlags(0); + tableEvTime(0.f, 999.f); + if (enableTableEvTimeTOFOnly) { + tableEvTimeTOFOnly((uint8_t)0, 0.f, 0.f, -1); + } + continue; + } + if (t.collisionId() == lastCollisionId) { // Event time from this collision is already in the table + continue; + } + /// Create new table for the tracks in a collision + lastCollisionId = t.collisionId(); /// Cache last collision ID + + const auto& tracksInCollision = tracks.sliceBy(perCollision, lastCollisionId); + + // First make table for event time + const auto evTimeMakerTOF = evTimeMakerForTracks(tracksInCollision, mRespParamsV3, kDiamond); + int nGoodTracksForTOF = 0; + float et = evTimeMakerTOF.mEventTime; + float erret = evTimeMakerTOF.mEventTimeError; + + for (auto const& trk : tracksInCollision) { // Loop on Tracks + if constexpr (kRemoveTOFEvTimeBias) { + evTimeMakerTOF.removeBias(trk, nGoodTracksForTOF, et, erret, 2); + } + uint8_t flags = 0; + if (erret < kErrDiamond && (maxEvTimeTOF <= 0.f || std::abs(et) < maxEvTimeTOF)) { + flags |= o2::aod::pidflags::enums::PIDFlags::EvTimeTOF; + } else { + et = 0.f; + erret = kErrDiamond; + } + tableFlags(flags); + tableEvTime(et, erret); + if (enableTableEvTimeTOFOnly) { + tableEvTimeTOFOnly((uint8_t)filterForTOFEventTime(trk), et, erret, evTimeMakerTOF.mEventTimeMultiplicity); + } + } + } + } else if (mComputeEvTimeWithTOF == 0 && mComputeEvTimeWithFT0 == 1) { + for (auto const& t : tracks) { // Loop on collisions + if (enableTableEvTimeTOFOnly) { + tableEvTimeTOFOnly((uint8_t)0, 0.f, 0.f, -1); + } + if (!t.has_collision()) { // Track was not assigned, cannot compute event time + tableFlags(0); + tableEvTime(0.f, 999.f); + continue; + } + const auto& collision = t.collision_as(); + + if (collision.has_foundFT0()) { // T0 measurement is available + // const auto& ft0 = collision.foundFT0(); + if (collision.t0ACValid()) { + tableFlags(o2::aod::pidflags::enums::PIDFlags::EvTimeT0AC); + tableEvTime(collision.t0AC() * 1000.f, collision.t0resolution() * 1000.f); + continue; + } + } + tableFlags(0); + tableEvTime(0.f, 999.f); + } + } else { + LOG(fatal) << "Invalid configuration for TOF event time computation"; + } + } + PROCESS_SWITCH(tofEventTime, processRun3, "Process the Run3 data", true); +}; + +// Part 3 Nsigma computation + +static constexpr int kParEnabledN = 2; +static constexpr int kIdxEl = 0; +static constexpr int kIdxMu = 1; +static constexpr int kIdxPi = 2; +static constexpr int kIdxKa = 3; +static constexpr int kIdxPr = 4; +static constexpr int kIdxDe = 5; +static constexpr int kIdxTr = 6; +static constexpr int kIdxHe = 7; +static constexpr int kIdxAl = 8; + +static const std::vector kParEnabledNames{"Enable", "EnableFull"}; +static constexpr int kDefaultParEnabled[nSpecies][kParEnabledN]{{-1, -1}, + {-1, -1}, + {-1, -1}, + {-1, -1}, + {-1, -1}, + {-1, -1}, + {-1, -1}, + {-1, -1}, + {-1, -1}}; + +/// Task to produce the response table +struct tofPidMerge { + // Tables to produce + Produces tablePIDEl; + Produces tablePIDMu; + Produces tablePIDPi; + Produces tablePIDKa; + Produces tablePIDPr; + Produces tablePIDDe; + Produces tablePIDTr; + Produces tablePIDHe; + Produces tablePIDAl; + + // Tables to produce (full) + Produces tablePIDFullEl; + Produces tablePIDFullMu; + Produces tablePIDFullPi; + Produces tablePIDFullKa; + Produces tablePIDFullPr; + Produces tablePIDFullDe; + Produces tablePIDFullTr; + Produces tablePIDFullHe; + Produces tablePIDFullAl; + + // Beta tables + Produces tablePIDBeta; + Produces tablePIDTOFMass; + bool enableTableBeta = false; + bool enableTableMass = false; + + // Detector response parameters + o2::pid::tof::TOFResoParamsV3 mRespParamsV3; + Service ccdb; + TOFCalibConfig mTOFCalibConfig; // TOF Calib configuration + Configurable enableQaHistograms{"enableQaHistograms", false, "Flag to enable the QA histograms"}; + Configurable enableTOFParamsForBetaMass{"enableTOFParamsForBetaMass", false, "Flag to use TOF parameters for TOF Beta and Mass"}; + + // Configuration flags to include and exclude particle hypotheses + Configurable> enableParticle{"enableParticle", + {kDefaultParEnabled[0], nSpecies, kParEnabledN, particleNames, kParEnabledNames}, + "Produce PID information for the various mass hypotheses. Values different than -1 override the automatic setup: the corresponding table can be set off (0) or on (1)"}; + + // Histograms for QA + std::array, nSpecies> hnsigma; + std::array, nSpecies> hnsigmaFull; + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Running variables + std::vector mEnabledParticles; // Vector of enabled PID hypotheses to loop on when making tables + std::vector mEnabledParticlesFull; // Vector of enabled PID hypotheses to loop on when making full tables + void init(o2::framework::InitContext& initContext) + { + mTOFCalibConfig.inheritFromBaseTask(initContext); + // Checking the tables are requested in the workflow and enabling them + for (int i = 0; i < nSpecies; i++) { + // First checking tiny + int f = enableParticle->get(particleNames[i].c_str(), "Enable"); + enableFlagIfTableRequired(initContext, "pidTOF" + particleNames[i], f); + if (f == 1) { + mEnabledParticles.push_back(i); + } + + // Then checking full tables + f = enableParticle->get(particleNames[i].c_str(), "EnableFull"); + enableFlagIfTableRequired(initContext, "pidTOFFull" + particleNames[i], f); + if (f == 1) { + mEnabledParticlesFull.push_back(i); + } + } + if (mEnabledParticlesFull.size() == 0 && mEnabledParticles.size() == 0) { + LOG(info) << "No PID tables are required, disabling the task"; + doprocessRun3.value = false; + doprocessRun2.value = false; + } else { + if (mTOFCalibConfig.autoSetProcessFunctions()) { + LOG(info) << "Autodetecting process functions for mass and beta"; + if (metadataInfo.isFullyDefined()) { + if (metadataInfo.isRun3()) { + doprocessRun3.value = true; + doprocessRun2.value = false; + } else { + doprocessRun2.value = true; + doprocessRun3.value = false; + } + } + } + if (doprocessRun2 && doprocessRun3) { + LOG(fatal) << "Both processRun2 and processRun3 are enabled. Pick one of the two"; + } + if (!doprocessRun2 && !doprocessRun3) { + LOG(fatal) << "Neither processRun2 nor processRun3 are enabled. Pick one of the two"; + } + } + mTOFCalibConfig.initSetup(mRespParamsV3, ccdb); // Getting the parametrization parameters + + // Printing enabled tables and enabling QA histograms if needed + LOG(info) << "++ Enabled tables:"; + const AxisSpec pAxis{100, 0, 5, "#it{p} (GeV/#it{c})"}; + const AxisSpec nSigmaAxis{100, -10, 10, "N_{#sigma}^{TOF}"}; + for (const int& i : mEnabledParticles) { + LOG(info) << "++ pidTOF" << particleNames[i] << " is enabled"; + if (!enableQaHistograms) { + continue; + } + hnsigma[i] = histos.add(Form("nsigma/%s", particleNames[i].c_str()), Form("N_{#sigma}^{TOF}(%s)", particleNames[i].c_str()), kTH2F, {pAxis, nSigmaAxis}); + } + for (const int& i : mEnabledParticlesFull) { + LOG(info) << "++ pidTOFFull" << particleNames[i] << " is enabled"; + if (!enableQaHistograms) { + continue; + } + hnsigmaFull[i] = histos.add(Form("nsigmaFull/%s", particleNames[i].c_str()), Form("N_{#sigma}^{TOF}(%s)", particleNames[i].c_str()), kTH2F, {pAxis, nSigmaAxis}); + } + + // Checking the TOF mass and TOF beta tables + enableTableBeta = isTableRequiredInWorkflow(initContext, "pidTOFbeta"); + enableTableMass = isTableRequiredInWorkflow(initContext, "pidTOFmass"); + + if (!enableTableBeta && !enableTableMass) { + LOG(info) << "No table for TOF mass and beta is required. Disabling beta and mass tables"; + doprocessRun2BetaM.value = false; + doprocessRun3BetaM.value = false; + } else { + if (mTOFCalibConfig.autoSetProcessFunctions()) { + LOG(info) << "Autodetecting process functions for mass and beta"; + if (metadataInfo.isFullyDefined()) { + if (metadataInfo.isRun3()) { + doprocessRun3BetaM.value = true; + doprocessRun2BetaM.value = false; + } else { + doprocessRun2BetaM.value = true; + doprocessRun3BetaM.value = false; + } + } + } + if (doprocessRun2BetaM && doprocessRun3BetaM) { + LOG(fatal) << "Both processRun2BetaM and processRun3BetaM are enabled. Pick one of the two"; + } + if (!doprocessRun2BetaM && !doprocessRun3BetaM) { + LOG(fatal) << "Neither processRun2BetaM nor processRun3BetaM are enabled. Pick one of the two"; + } + } + } + + // Reserves an empty table for the given particle ID with size of the given track table + void reserveTable(const int id, const int64_t& size, const bool fullTable = false) + { + switch (id) { + case kIdxEl: { + if (fullTable) { + tablePIDFullEl.reserve(size); + } else { + tablePIDEl.reserve(size); + } + break; + } + case kIdxMu: { + if (fullTable) { + tablePIDFullMu.reserve(size); + } else { + tablePIDMu.reserve(size); + } + break; + } + case kIdxPi: { + if (fullTable) { + tablePIDFullPi.reserve(size); + } else { + tablePIDPi.reserve(size); + } + break; + } + case kIdxKa: { + if (fullTable) { + tablePIDFullKa.reserve(size); + } else { + tablePIDKa.reserve(size); + } + break; + } + case kIdxPr: { + if (fullTable) { + tablePIDFullPr.reserve(size); + } else { + tablePIDPr.reserve(size); + } + break; + } + case kIdxDe: { + if (fullTable) { + tablePIDFullDe.reserve(size); + } else { + tablePIDDe.reserve(size); + } + break; + } + case kIdxTr: { + if (fullTable) { + tablePIDFullTr.reserve(size); + } else { + tablePIDTr.reserve(size); + } + break; + } + case kIdxHe: { + if (fullTable) { + tablePIDFullHe.reserve(size); + } else { + tablePIDHe.reserve(size); + } + break; + } + case kIdxAl: { + if (fullTable) { + tablePIDFullAl.reserve(size); + } else { + tablePIDAl.reserve(size); + } + break; + } + default: + LOG(fatal) << "Wrong particle ID in reserveTable() for " << (fullTable ? "full" : "tiny") << " tables"; + break; + } + } + + // Makes the table empty for the given particle ID, filling it with dummy values + void makeTableEmpty(const int id, bool fullTable = false) + { + switch (id) { + case kIdxEl: + if (fullTable) { + tablePIDFullEl(-999.f, -999.f); + } else { + aod::pidutils::packInTable(-999.f, + tablePIDEl); + } + break; + case kIdxMu: + if (fullTable) { + tablePIDFullMu(-999.f, -999.f); + } else { + aod::pidutils::packInTable(-999.f, + tablePIDMu); + } + break; + case kIdxPi: + if (fullTable) { + tablePIDFullPi(-999.f, -999.f); + } else { + aod::pidutils::packInTable(-999.f, + tablePIDPi); + } + break; + case kIdxKa: + if (fullTable) { + tablePIDFullKa(-999.f, -999.f); + } else { + aod::pidutils::packInTable(-999.f, + tablePIDKa); + } + break; + case kIdxPr: + if (fullTable) { + tablePIDFullPr(-999.f, -999.f); + } else { + aod::pidutils::packInTable(-999.f, + tablePIDPr); + } + break; + case kIdxDe: + if (fullTable) { + tablePIDFullDe(-999.f, -999.f); + } else { + aod::pidutils::packInTable(-999.f, + tablePIDDe); + } + break; + case kIdxTr: + if (fullTable) { + tablePIDFullTr(-999.f, -999.f); + } else { + aod::pidutils::packInTable(-999.f, + tablePIDTr); + } + break; + case kIdxHe: + if (fullTable) { + tablePIDFullHe(-999.f, -999.f); + } else { + aod::pidutils::packInTable(-999.f, + tablePIDHe); + } + break; + case kIdxAl: + if (fullTable) { + tablePIDFullAl(-999.f, -999.f); + } else { + aod::pidutils::packInTable(-999.f, + tablePIDAl); + } + break; + default: + LOG(fatal) << "Wrong particle ID in makeTableEmpty() for " << (fullTable ? "full" : "tiny") << " tables"; + break; + } + } + + void process(aod::BCs const&) {} + + template + using ResponseImplementation = o2::pid::tof::ExpTimes; + void processRun3(Run3TrksWtofWevTime const& tracks, + Run3Cols const&, + aod::BCsWithTimestamps const& bcs) + { + constexpr auto responseEl = ResponseImplementation(); + constexpr auto responseMu = ResponseImplementation(); + constexpr auto responsePi = ResponseImplementation(); + constexpr auto responseKa = ResponseImplementation(); + constexpr auto responsePr = ResponseImplementation(); + constexpr auto responseDe = ResponseImplementation(); + constexpr auto responseTr = ResponseImplementation(); + constexpr auto responseHe = ResponseImplementation(); + constexpr auto responseAl = ResponseImplementation(); + + mTOFCalibConfig.processSetup(mRespParamsV3, ccdb, bcs.iteratorAt(0)); // Update the calibration parameters + + for (auto const& pidId : mEnabledParticles) { + reserveTable(pidId, tracks.size(), false); + } + + for (auto const& pidId : mEnabledParticlesFull) { + reserveTable(pidId, tracks.size(), true); + } + + float resolution = 1.f; // Last resolution assigned + float nsigma = 0; + for (auto const& trk : tracks) { // Loop on all tracks + if (!trk.has_collision()) { // Track was not assigned, cannot compute NSigma (no event time) -> filling with empty table + for (auto const& pidId : mEnabledParticles) { + makeTableEmpty(pidId, false); + } + for (auto const& pidId : mEnabledParticlesFull) { + makeTableEmpty(pidId, true); + } + continue; + } + + for (auto const& pidId : mEnabledParticles) { // Loop on enabled particle hypotheses + switch (pidId) { + case kIdxEl: { + nsigma = responseEl.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDEl); + break; + } + case kIdxMu: { + nsigma = responseMu.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDMu); + break; + } + case kIdxPi: { + nsigma = responsePi.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDPi); + break; + } + case kIdxKa: { + nsigma = responseKa.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDKa); + break; + } + case kIdxPr: { + nsigma = responsePr.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDPr); + break; + } + case kIdxDe: { + nsigma = responseDe.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDDe); + break; + } + case kIdxTr: { + nsigma = responseTr.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDTr); + break; + } + case kIdxHe: { + nsigma = responseHe.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDHe); + break; + } + case kIdxAl: { + nsigma = responseAl.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDAl); + break; + } + default: + LOG(fatal) << "Wrong particle ID for standard tables"; + break; + } + if (enableQaHistograms) { + hnsigma[pidId]->Fill(trk.p(), nsigma); + } + } + for (auto const& pidId : mEnabledParticlesFull) { // Loop on enabled particle hypotheses with full tables + switch (pidId) { + case kIdxEl: { + resolution = responseEl.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responseEl.GetSeparation(mRespParamsV3, trk, resolution); + tablePIDFullEl(resolution, nsigma); + break; + } + case kIdxMu: { + resolution = responseMu.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responseMu.GetSeparation(mRespParamsV3, trk, resolution); + tablePIDFullMu(resolution, nsigma); + break; + } + case kIdxPi: { + resolution = responsePi.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responsePi.GetSeparation(mRespParamsV3, trk); + tablePIDFullPi(resolution, nsigma); + break; + } + case kIdxKa: { + resolution = responseKa.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responseKa.GetSeparation(mRespParamsV3, trk, resolution); + tablePIDFullKa(resolution, nsigma); + break; + } + case kIdxPr: { + resolution = responsePr.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responsePr.GetSeparation(mRespParamsV3, trk, resolution); + tablePIDFullPr(resolution, nsigma); + break; + } + case kIdxDe: { + resolution = responseDe.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responseDe.GetSeparation(mRespParamsV3, trk, resolution); + tablePIDFullDe(resolution, nsigma); + break; + } + case kIdxTr: { + resolution = responseTr.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responseTr.GetSeparation(mRespParamsV3, trk, resolution); + tablePIDFullTr(resolution, nsigma); + break; + } + case kIdxHe: { + resolution = responseHe.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responseHe.GetSeparation(mRespParamsV3, trk, resolution); + tablePIDFullHe(resolution, nsigma); + break; + } + case kIdxAl: { + resolution = responseAl.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responseAl.GetSeparation(mRespParamsV3, trk, resolution); + tablePIDFullAl(resolution, nsigma); + break; + } + default: + LOG(fatal) << "Wrong particle ID for full tables"; + break; + } + if (enableQaHistograms) { + hnsigmaFull[pidId]->Fill(trk.p(), nsigma); + } + } + } + } + PROCESS_SWITCH(tofPidMerge, processRun3, "Produce Run 3 Nsigma table. Set to off if the tables are not required, or autoset is on", false); + + template + using ResponseImplementationRun2 = o2::pid::tof::ExpTimes; + void processRun2(Run2TrksWtofWevTime const& tracks, + Run3Cols const&, + aod::BCsWithTimestamps const& bcs) + { + constexpr auto responseEl = ResponseImplementationRun2(); + constexpr auto responseMu = ResponseImplementationRun2(); + constexpr auto responsePi = ResponseImplementationRun2(); + constexpr auto responseKa = ResponseImplementationRun2(); + constexpr auto responsePr = ResponseImplementationRun2(); + constexpr auto responseDe = ResponseImplementationRun2(); + constexpr auto responseTr = ResponseImplementationRun2(); + constexpr auto responseHe = ResponseImplementationRun2(); + constexpr auto responseAl = ResponseImplementationRun2(); + + mTOFCalibConfig.processSetup(mRespParamsV3, ccdb, bcs.iteratorAt(0)); // Update the calibration parameters + + for (auto const& pidId : mEnabledParticles) { + reserveTable(pidId, tracks.size(), false); + } + + for (auto const& pidId : mEnabledParticlesFull) { + reserveTable(pidId, tracks.size(), true); + } + + float resolution = 1.f; // Last resolution assigned + float nsigma = 0; + for (auto const& trk : tracks) { // Loop on all tracks + if (!trk.has_collision()) { // Track was not assigned, cannot compute NSigma (no event time) -> filling with empty table + for (auto const& pidId : mEnabledParticles) { + makeTableEmpty(pidId, false); + } + for (auto const& pidId : mEnabledParticlesFull) { + makeTableEmpty(pidId, true); + } + continue; + } + + for (auto const& pidId : mEnabledParticles) { // Loop on enabled particle hypotheses + switch (pidId) { + case kIdxEl: { + nsigma = responseEl.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDEl); + break; + } + case kIdxMu: { + nsigma = responseMu.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDMu); + break; + } + case kIdxPi: { + nsigma = responsePi.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDPi); + break; + } + case kIdxKa: { + nsigma = responseKa.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDKa); + break; + } + case kIdxPr: { + nsigma = responsePr.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDPr); + break; + } + case kIdxDe: { + nsigma = responseDe.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDDe); + break; + } + case kIdxTr: { + nsigma = responseTr.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDTr); + break; + } + case kIdxHe: { + nsigma = responseHe.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDHe); + break; + } + case kIdxAl: { + nsigma = responseAl.GetSeparation(mRespParamsV3, trk); + aod::pidutils::packInTable(nsigma, tablePIDAl); + break; + } + default: + LOG(fatal) << "Wrong particle ID for standard tables"; + break; + } + if (enableQaHistograms) { + hnsigma[pidId]->Fill(trk.p(), nsigma); + } + } + for (auto const& pidId : mEnabledParticlesFull) { // Loop on enabled particle hypotheses with full tables + switch (pidId) { + case kIdxEl: { + resolution = responseEl.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responseEl.GetSeparation(mRespParamsV3, trk, resolution); + tablePIDFullEl(resolution, nsigma); + break; + } + case kIdxMu: { + resolution = responseMu.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responseMu.GetSeparation(mRespParamsV3, trk, resolution); + tablePIDFullMu(resolution, nsigma); + break; + } + case kIdxPi: { + resolution = responsePi.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responsePi.GetSeparation(mRespParamsV3, trk); + tablePIDFullPi(resolution, nsigma); + break; + } + case kIdxKa: { + resolution = responseKa.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responseKa.GetSeparation(mRespParamsV3, trk, resolution); + tablePIDFullKa(resolution, nsigma); + break; + } + case kIdxPr: { + resolution = responsePr.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responsePr.GetSeparation(mRespParamsV3, trk, resolution); + tablePIDFullPr(resolution, nsigma); + break; + } + case kIdxDe: { + resolution = responseDe.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responseDe.GetSeparation(mRespParamsV3, trk, resolution); + tablePIDFullDe(resolution, nsigma); + break; + } + case kIdxTr: { + resolution = responseTr.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responseTr.GetSeparation(mRespParamsV3, trk, resolution); + tablePIDFullTr(resolution, nsigma); + break; + } + case kIdxHe: { + resolution = responseHe.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responseHe.GetSeparation(mRespParamsV3, trk, resolution); + tablePIDFullHe(resolution, nsigma); + break; + } + case kIdxAl: { + resolution = responseAl.GetExpectedSigma(mRespParamsV3, trk); + nsigma = responseAl.GetSeparation(mRespParamsV3, trk, resolution); + tablePIDFullAl(resolution, nsigma); + break; + } + default: + LOG(fatal) << "Wrong particle ID for full tables"; + break; + } + if (enableQaHistograms) { + hnsigmaFull[pidId]->Fill(trk.p(), nsigma); + } + } + } + } + PROCESS_SWITCH(tofPidMerge, processRun2, "Produce Run 2 Nsigma table. Set to off if the tables are not required, or autoset is on", false); + + o2::pid::tof::Beta responseBetaRun2; + void processRun2BetaM(Run2TrksWtofWevTime const& tracks) + { + if (!enableTableBeta && !enableTableMass) { + return; + } + float beta = 0.f; + tablePIDBeta.reserve(tracks.size()); + for (auto const& trk : tracks) { + beta = responseBetaRun2.GetBeta(trk); + if (enableTableBeta) { + tablePIDBeta(beta, responseBetaRun2.GetExpectedSigma(trk)); + } + if (enableTableMass) { + if (enableTOFParamsForBetaMass) { + tablePIDTOFMass(o2::pid::tof::TOFMass::GetTOFMass(trk.tofExpMom() / (1.f + trk.sign() * mRespParamsV3.getMomentumChargeShift(trk.eta())), beta)); + } else { + tablePIDTOFMass(o2::pid::tof::TOFMass::GetTOFMass(trk, beta)); + } + } + } + } + PROCESS_SWITCH(tofPidMerge, processRun2BetaM, "Produce Run 2 Beta and Mass table. Set to off if the tables are not required, or autoset is on", false); + + o2::pid::tof::Beta responseBeta; + void processRun3BetaM(Run3TrksWtofWevTime const& tracks) + { + if (!enableTableBeta && !enableTableMass) { + return; + } + float beta = 0.f; + tablePIDBeta.reserve(tracks.size()); + for (auto const& trk : tracks) { + beta = responseBeta.GetBeta(trk); + if (enableTableBeta) { + tablePIDBeta(beta, + responseBeta.GetExpectedSigma(trk)); + } + if (enableTableMass) { + if (enableTOFParamsForBetaMass) { + tablePIDTOFMass(o2::pid::tof::TOFMass::GetTOFMass(trk.tofExpMom() / (1.f + trk.sign() * mRespParamsV3.getMomentumChargeShift(trk.eta())), beta)); + } else { + tablePIDTOFMass(o2::pid::tof::TOFMass::GetTOFMass(trk, beta)); + } + } + } + } + PROCESS_SWITCH(tofPidMerge, processRun3BetaM, "Produce Run 3 Beta and Mass table. Set to off if the tables are not required, or autoset is on", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // Parse the metadata + metadataInfo.initMetadata(cfgc); + auto workflow = WorkflowSpec{adaptAnalysisTask(cfgc)}; + workflow.push_back(adaptAnalysisTask(cfgc)); + workflow.push_back(adaptAnalysisTask(cfgc)); + return workflow; +} diff --git a/Common/TableProducer/PID/pidTOFbeta.cxx b/Common/TableProducer/PID/pidTOFbeta.cxx index dc4888bce55..d76d631bc4d 100644 --- a/Common/TableProducer/PID/pidTOFbeta.cxx +++ b/Common/TableProducer/PID/pidTOFbeta.cxx @@ -124,7 +124,7 @@ struct tofPidBeta { } using Trks = soa::Join; - o2::pid::tof::Beta responseBeta; + o2::pid::tof::Beta responseBeta; template using ResponseImplementation = o2::pid::tof::ExpTimes; void process(Trks const& tracks) @@ -142,16 +142,13 @@ struct tofPidBeta { } if (enableTableMass) { if (enableTOFParams) { - tablePIDTOFMass(o2::pid::tof::TOFMass::GetTOFMass(trk.tofExpMom() / (1.f + trk.sign() * mRespParamsV2.getShift(trk.eta())), beta)); + tablePIDTOFMass(o2::pid::tof::TOFMass::GetTOFMass(trk.tofExpMom() / (1.f + trk.sign() * mRespParamsV2.getShift(trk.eta())), beta)); } else { - tablePIDTOFMass(o2::pid::tof::TOFMass::GetTOFMass(trk, beta)); + tablePIDTOFMass(o2::pid::tof::TOFMass::GetTOFMass(trk, beta)); } } } } }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/Common/TableProducer/PID/pidTPC.cxx b/Common/TableProducer/PID/pidTPC.cxx index d8eb27b1846..1fe071f2717 100644 --- a/Common/TableProducer/PID/pidTPC.cxx +++ b/Common/TableProducer/PID/pidTPC.cxx @@ -14,27 +14,36 @@ /// \author Nicolò Jacazio nicolo.jacazio@cern.ch /// \author Christian Sonnabend christian.sonnabend@cern.ch /// \author Annalena Kalteyer annalena.sophie.kalteyer@cern.ch -/// \brief Task to produce PID tables for TPC split for each particle with only the Nsigma information. -/// Only the tables for the mass hypotheses requested are filled, the others are sent empty. -/// QA histograms for the TPC PID can be produced by adding `--add-qa 1` to the workflow +/// \author Jeremy Wilkinson jeremy.wilkinson@cern.ch +/// \brief Task to produce PID tables for TPC split for each particle. +/// Only the tables for the mass hypotheses requested are filled, and only for the requested table size ("Full" or "Tiny"). The others are sent empty. /// - +#include +#include +#include +#include +#include // ROOT includes #include "TFile.h" +#include "TRandom.h" #include "TSystem.h" // O2 includes -#include +#include "CCDB/BasicCCDBManager.h" #include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/ASoAHelpers.h" #include "ReconstructionDataFormats/Track.h" #include "CCDB/CcdbApi.h" #include "Common/DataModel/PIDResponse.h" #include "Common/Core/PID/TPCPIDResponse.h" #include "Framework/AnalysisDataModel.h" #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/EventSelection.h" #include "TableHelper.h" #include "Tools/ML/model.h" #include "pidTPCBase.h" +#include "MetadataHelper.h" using namespace o2; using namespace o2::framework; @@ -44,29 +53,43 @@ using namespace o2::framework::expressions; using namespace o2::track; using namespace o2::ml; +MetadataHelper metadataInfo; // Metadata helper + void customize(std::vector& workflowOptions) { std::vector options{{"add-qa", VariantType::Int, 0, {"Legacy. No effect."}}}; std::swap(workflowOptions, options); } -#include "Framework/runDataProcessing.h" - /// Task to produce the response table struct tpcPid { using Trks = soa::Join; - using Coll = soa::Join; + using Coll = soa::Join; + + using TrksMC = soa::Join; + using CollMC = soa::Join; // Tables to produce - Produces tablePIDEl; - Produces tablePIDMu; - Produces tablePIDPi; - Produces tablePIDKa; - Produces tablePIDPr; - Produces tablePIDDe; - Produces tablePIDTr; - Produces tablePIDHe; - Produces tablePIDAl; + Produces tablePIDFullEl; + Produces tablePIDFullMu; + Produces tablePIDFullPi; + Produces tablePIDFullKa; + Produces tablePIDFullPr; + Produces tablePIDFullDe; + Produces tablePIDFullTr; + Produces tablePIDFullHe; + Produces tablePIDFullAl; + + Produces tablePIDTinyEl; + Produces tablePIDTinyMu; + Produces tablePIDTinyPi; + Produces tablePIDTinyKa; + Produces tablePIDTinyPr; + Produces tablePIDTinyDe; + Produces tablePIDTinyTr; + Produces tablePIDTinyHe; + Produces tablePIDTinyAl; + Produces tableTuneOnData; // TPC PID Response o2::pid::tpc::Response* response; @@ -75,7 +98,10 @@ struct tpcPid { OnnxModel network; o2::ccdb::CcdbApi ccdbApi; std::map metadata; + std::map nullmetadata; std::map headers; + std::vector speciesNetworkFlags = std::vector(9); + std::string networkVersion; // Input parameters Service ccdb; @@ -89,19 +115,29 @@ struct tpcPid { Configurable autofetchNetworks{"autofetchNetworks", 1, "(bool) Automatically fetches networks from CCDB for the correct run number"}; Configurable skipTPCOnly{"skipTPCOnly", false, "Flag to skip TPC only tracks (faster but affects the analyses that use TPC only tracks)"}; Configurable networkPathLocally{"networkPathLocally", "network.onnx", "(std::string) Path to the local .onnx file. If autofetching is enabled, then this is where the files will be downloaded"}; - Configurable enableNetworkOptimizations{"enableNetworkOptimizations", 1, "(bool) If the neural network correction is used, this enables GraphOptimizationLevel::ORT_ENABLE_EXTENDED in the ONNX session"}; Configurable networkPathCCDB{"networkPathCCDB", "Analysis/PID/TPC/ML", "Path on CCDB"}; + Configurable enableNetworkOptimizations{"enableNetworkOptimizations", 1, "(bool) If the neural network correction is used, this enables GraphOptimizationLevel::ORT_ENABLE_EXTENDED in the ONNX session"}; Configurable networkSetNumThreads{"networkSetNumThreads", 0, "Especially important for running on a SLURM cluster. Sets the number of threads used for execution."}; // Configuration flags to include and exclude particle hypotheses - Configurable pidEl{"pid-el", -1, {"Produce PID information for the Electron mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; - Configurable pidMu{"pid-mu", -1, {"Produce PID information for the Muon mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; - Configurable pidPi{"pid-pi", -1, {"Produce PID information for the Pion mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; - Configurable pidKa{"pid-ka", -1, {"Produce PID information for the Kaon mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; - Configurable pidPr{"pid-pr", -1, {"Produce PID information for the Proton mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; - Configurable pidDe{"pid-de", -1, {"Produce PID information for the Deuterons mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; - Configurable pidTr{"pid-tr", -1, {"Produce PID information for the Triton mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; - Configurable pidHe{"pid-he", -1, {"Produce PID information for the Helium3 mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; - Configurable pidAl{"pid-al", -1, {"Produce PID information for the Alpha mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidFullEl{"pid-full-el", -1, {"Produce PID information for the Electron mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidFullMu{"pid-full-mu", -1, {"Produce PID information for the Muon mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidFullPi{"pid-full-pi", -1, {"Produce PID information for the Pion mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidFullKa{"pid-full-ka", -1, {"Produce PID information for the Kaon mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidFullPr{"pid-full-pr", -1, {"Produce PID information for the Proton mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidFullDe{"pid-full-de", -1, {"Produce PID information for the Deuterons mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidFullTr{"pid-full-tr", -1, {"Produce PID information for the Triton mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidFullHe{"pid-full-he", -1, {"Produce PID information for the Helium3 mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidFullAl{"pid-full-al", -1, {"Produce PID information for the Alpha mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidTinyEl{"pid-tiny-el", -1, {"Produce PID information for the Electron mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidTinyMu{"pid-tiny-mu", -1, {"Produce PID information for the Muon mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidTinyPi{"pid-tiny-pi", -1, {"Produce PID information for the Pion mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidTinyKa{"pid-tiny-ka", -1, {"Produce PID information for the Kaon mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidTinyPr{"pid-tiny-pr", -1, {"Produce PID information for the Proton mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidTinyDe{"pid-tiny-de", -1, {"Produce PID information for the Deuterons mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidTinyTr{"pid-tiny-tr", -1, {"Produce PID information for the Triton mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidTinyHe{"pid-tiny-he", -1, {"Produce PID information for the Helium3 mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable pidTinyAl{"pid-tiny-al", -1, {"Produce PID information for the Alpha mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; + Configurable enableTuneOnDataTable{"enableTuneOnDataTable", -1, {"Produce tuned dE/dx signal table for MC to be used as raw signal in other tasks (default -1, 'only if needed'"}}; Configurable useNetworkEl{"useNetworkEl", 1, {"Switch for applying neural network on the electron mass hypothesis (if network enabled) (set to 0 to disable)"}}; Configurable useNetworkMu{"useNetworkMu", 1, {"Switch for applying neural network on the muon mass hypothesis (if network enabled) (set to 0 to disable)"}}; Configurable useNetworkPi{"useNetworkPi", 1, {"Switch for applying neural network on the pion mass hypothesis (if network enabled) (set to 0 to disable)"}}; @@ -113,31 +149,62 @@ struct tpcPid { Configurable useNetworkAl{"useNetworkAl", 1, {"Switch for applying neural network on the alpha mass hypothesis (if network enabled) (set to 0 to disable)"}}; Configurable networkBetaGammaCutoff{"networkBetaGammaCutoff", 0.45, {"Lower value of beta-gamma to override the NN application"}}; - // Paramatrization configuration + // Parametrization configuration bool useCCDBParam = false; void init(o2::framework::InitContext& initContext) { + // Protection for process flags + if ((doprocessStandard && doprocessMcTuneOnData) || (!doprocessStandard && !doprocessMcTuneOnData)) { + LOG(fatal) << "pid-tpc must have only one of the options 'processStandard' OR 'processMcTuneOnData' enabled. Please check your configuration."; + } response = new o2::pid::tpc::Response(); // Checking the tables are requested in the workflow and enabling them auto enableFlag = [&](const std::string particle, Configurable& flag) { enableFlagIfTableRequired(initContext, "pidTPC" + particle, flag); }; - enableFlag("El", pidEl); - enableFlag("Mu", pidMu); - enableFlag("Pi", pidPi); - enableFlag("Ka", pidKa); - enableFlag("Pr", pidPr); - enableFlag("De", pidDe); - enableFlag("Tr", pidTr); - enableFlag("He", pidHe); - enableFlag("Al", pidAl); - - // Initialise metadata object for CCDB calls + enableFlag("FullEl", pidFullEl); + enableFlag("FullMu", pidFullMu); + enableFlag("FullPi", pidFullPi); + enableFlag("FullKa", pidFullKa); + enableFlag("FullPr", pidFullPr); + enableFlag("FullDe", pidFullDe); + enableFlag("FullTr", pidFullTr); + enableFlag("FullHe", pidFullHe); + enableFlag("FullAl", pidFullAl); + + enableFlag("El", pidTinyEl); + enableFlag("Mu", pidTinyMu); + enableFlag("Pi", pidTinyPi); + enableFlag("Ka", pidTinyKa); + enableFlag("Pr", pidTinyPr); + enableFlag("De", pidTinyDe); + enableFlag("Tr", pidTinyTr); + enableFlag("He", pidTinyHe); + enableFlag("Al", pidTinyAl); + + if (doprocessMcTuneOnData) { + enableFlagIfTableRequired(initContext, "mcTPCTuneOnData", enableTuneOnDataTable); + } + + speciesNetworkFlags[0] = useNetworkEl; + speciesNetworkFlags[1] = useNetworkMu; + speciesNetworkFlags[2] = useNetworkPi; + speciesNetworkFlags[3] = useNetworkKa; + speciesNetworkFlags[4] = useNetworkPr; + speciesNetworkFlags[5] = useNetworkDe; + speciesNetworkFlags[6] = useNetworkTr; + speciesNetworkFlags[7] = useNetworkHe; + speciesNetworkFlags[8] = useNetworkAl; + + // Initialise metadata object for CCDB calls from AO2D metadata if (recoPass.value == "") { - LOGP(info, "Reco pass not specified; CCDB will take latest available object"); + if (metadataInfo.isFullyDefined()) { + metadata["RecoPassName"] = metadataInfo.get("RecoPassName"); + LOGP(info, "Automatically setting reco pass for TPC Response to {} from AO2D", metadata["RecoPassName"]); + } } else { - LOGP(info, "CCDB object will be requested for reconstruction pass {}", recoPass.value); + LOGP(info, "Setting reco pass for TPC response to user-defined name {}", recoPass.value); metadata["RecoPassName"] = recoPass.value; } @@ -161,17 +228,23 @@ struct tpcPid { ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + ccdbApi.init(url); if (time != 0) { LOGP(info, "Initialising TPC PID response for fixed timestamp {} and reco pass {}:", time, recoPass.value); ccdb->setTimestamp(time); response = ccdb->getSpecific(path, time, metadata); + headers = ccdbApi.retrieveHeaders(path, metadata, time); if (!response) { LOGF(warning, "Unable to find TPC parametrisation for specified pass name - falling back to latest object"); response = ccdb->getForTimeStamp(path, time); + headers = ccdbApi.retrieveHeaders(path, metadata, time); + networkVersion = headers["NN-Version"]; if (!response) { LOGF(fatal, "Unable to find any TPC object corresponding to timestamp {}!", time); } } + LOG(info) << "Successfully retrieved TPC PID object from CCDB for timestamp " << time << ", period " << headers["LPMProductionTag"] << ", recoPass " << headers["RecoPassName"]; + metadata["RecoPassName"] = headers["RecoPassName"]; // Force pass number for NN request to match retrieved BB response->PrintAll(); } } @@ -182,19 +255,21 @@ struct tpcPid { return; } else { /// CCDB and auto-fetching - ccdbApi.init(url); + if (!autofetchNetworks) { if (ccdbTimestamp > 0) { /// Fetching network for specific timestamp LOG(info) << "Fetching network for timestamp: " << ccdbTimestamp.value; bool retrieveSuccess = ccdbApi.retrieveBlob(networkPathCCDB.value, ".", metadata, ccdbTimestamp.value, false, networkPathLocally.value); headers = ccdbApi.retrieveHeaders(networkPathCCDB.value, metadata, ccdbTimestamp.value); + networkVersion = headers["NN-Version"]; if (retrieveSuccess) { network.initModel(networkPathLocally.value, enableNetworkOptimizations.value, networkSetNumThreads.value, strtoul(headers["Valid-From"].c_str(), NULL, 0), strtoul(headers["Valid-Until"].c_str(), NULL, 0)); std::vector dummyInput(network.getNumInputNodes(), 1.); network.evalModel(dummyInput); /// Init the model evaluations + LOGP(info, "Retrieved NN corrections for production tag {}, pass number {}, and NN-Version {}", headers["LPMProductionTag"], headers["RecoPassName"], headers["NN-Version"]); } else { - LOG(fatal) << "Error encountered while fetching/loading the network from CCDB! Maybe the network doesn't exist yet for this runnumber/timestamp?"; + LOG(fatal) << "No valid NN object found matching retrieved Bethe-Bloch parametrisation for pass " << metadata["RecoPassName"] << ". Please ensure that the requested pass has dedicated NN corrections available"; } } else { /// Taking the network from local file @@ -212,209 +287,396 @@ struct tpcPid { } } - Partition notTPCStandaloneTracks = (aod::track::tpcNClsFindable > (uint8_t)0) && ((aod::track::itsClusterSizes > (uint32_t)0) || (aod::track::trdPattern > (uint8_t)0) || (aod::track::tofExpMom > 0.f && aod::track::tofChi2 > 0.f)); // To count number of tracks for use in NN array + Partition notTPCStandaloneTracks = (aod::track::tpcNClsFindable > static_cast(0)) && ((aod::track::itsClusterSizes > static_cast(0)) || (aod::track::trdPattern > static_cast(0)) || (aod::track::tofExpMom > 0.f && aod::track::tofChi2 > 0.f)); // To count number of tracks for use in NN array Partition tracksWithTPC = (aod::track::tpcNClsFindable > (uint8_t)0); - void process(Coll const& collisions, Trks const& tracks, - aod::BCsWithTimestamps const& bcs) + template + std::vector createNetworkPrediction(C const& collisions, T const& tracks, B const& bcs, const size_t size) + { + + std::vector network_prediction; + + auto start_network_total = std::chrono::high_resolution_clock::now(); + if (autofetchNetworks) { + const auto& bc = bcs.begin(); + // Initialise correct TPC response object before NN setup (for NCl normalisation) + if (useCCDBParam && ccdbTimestamp.value == 0 && !ccdb->isCachedObjectValid(ccdbPath.value, bc.timestamp())) { // Updating parametrisation only if the initial timestamp is 0 + if (recoPass.value == "") { + LOGP(info, "Retrieving latest TPC response object for timestamp {}:", bc.timestamp()); + } else { + LOGP(info, "Retrieving TPC Response for timestamp {} and recoPass {}:", bc.timestamp(), recoPass.value); + } + response = ccdb->getSpecific(ccdbPath.value, bc.timestamp(), metadata); + headers = ccdbApi.retrieveHeaders(ccdbPath.value, metadata, bc.timestamp()); + networkVersion = headers["NN-Version"]; + if (!response) { + LOGP(warning, "!! Could not find a valid TPC response object for specific pass name {}! Falling back to latest uploaded object.", metadata["RecoPassName"]); + headers = ccdbApi.retrieveHeaders(ccdbPath.value, nullmetadata, bc.timestamp()); + response = ccdb->getForTimeStamp(ccdbPath.value, bc.timestamp()); + if (!response) { + LOGP(fatal, "Could not find ANY TPC response object for the timestamp {}!", bc.timestamp()); + } + } + LOG(info) << "Successfully retrieved TPC PID object from CCDB for timestamp " << bc.timestamp() << ", period " << headers["LPMProductionTag"] << ", recoPass " << headers["RecoPassName"]; + metadata["RecoPassName"] = headers["RecoPassName"]; // Force pass number for NN request to match retrieved BB + response->PrintAll(); + } + + if (bc.timestamp() < network.getValidityFrom() || bc.timestamp() > network.getValidityUntil()) { // fetches network only if the runnumbers change + LOG(info) << "Fetching network for timestamp: " << bc.timestamp(); + bool retrieveSuccess = ccdbApi.retrieveBlob(networkPathCCDB.value, ".", metadata, bc.timestamp(), false, networkPathLocally.value); + headers = ccdbApi.retrieveHeaders(networkPathCCDB.value, metadata, bc.timestamp()); + networkVersion = headers["NN-Version"]; + if (retrieveSuccess) { + network.initModel(networkPathLocally.value, enableNetworkOptimizations.value, networkSetNumThreads.value, strtoul(headers["Valid-From"].c_str(), NULL, 0), strtoul(headers["Valid-Until"].c_str(), NULL, 0)); + std::vector dummyInput(network.getNumInputNodes(), 1.); + network.evalModel(dummyInput); + LOGP(info, "Retrieved NN corrections for production tag {}, pass number {}, NN-Version number{}", headers["LPMProductionTag"], headers["RecoPassName"], headers["NN-Version"]); + } else { + LOG(fatal) << "No valid NN object found matching retrieved Bethe-Bloch parametrisation for pass " << metadata["RecoPassName"] << ". Please ensure that the requested pass has dedicated NN corrections available"; + } + } + } + + // Defining some network parameters + int input_dimensions = network.getNumInputNodes(); + int output_dimensions = network.getNumOutputNodes(); + const uint64_t track_prop_size = input_dimensions * size; + const uint64_t prediction_size = output_dimensions * size; + + network_prediction = std::vector(prediction_size * 9); // For each mass hypotheses + const float nNclNormalization = response->GetNClNormalization(); + float duration_network = 0; + + std::vector track_properties(track_prop_size); + uint64_t counter_track_props = 0; + int loop_counter = 0; + + // Filling a std::vector to be evaluated by the network + // Evaluation on single tracks brings huge overhead: Thus evaluation is done on one large vector + for (int i = 0; i < 9; i++) { // Loop over particle number for which network correction is used + for (auto const& trk : tracks) { + if (!trk.hasTPC()) { + continue; + } + if (skipTPCOnly) { + if (!trk.hasITS() && !trk.hasTRD() && !trk.hasTOF()) { + continue; + } + } + track_properties[counter_track_props] = trk.tpcInnerParam(); + track_properties[counter_track_props + 1] = trk.tgl(); + track_properties[counter_track_props + 2] = trk.signed1Pt(); + track_properties[counter_track_props + 3] = o2::track::pid_constants::sMasses[i]; + track_properties[counter_track_props + 4] = trk.has_collision() ? collisions.iteratorAt(trk.collisionId()).multTPC() / 11000. : 1.; + track_properties[counter_track_props + 5] = std::sqrt(nNclNormalization / trk.tpcNClsFound()); + if (input_dimensions == 7 && networkVersion == "2") { + track_properties[counter_track_props + 6] = trk.has_collision() ? collisions.iteratorAt(trk.collisionId()).ft0cOccupancyInTimeRange() / 60000. : 1.; + } + counter_track_props += input_dimensions; + } + + auto start_network_eval = std::chrono::high_resolution_clock::now(); + float* output_network = network.evalModel(track_properties); + auto stop_network_eval = std::chrono::high_resolution_clock::now(); + duration_network += std::chrono::duration>(stop_network_eval - start_network_eval).count(); + for (uint64_t i = 0; i < prediction_size; i += output_dimensions) { + for (int j = 0; j < output_dimensions; j++) { + network_prediction[i + j + prediction_size * loop_counter] = output_network[i + j]; + } + } + + counter_track_props = 0; + loop_counter += 1; + } + track_properties.clear(); + + auto stop_network_total = std::chrono::high_resolution_clock::now(); + LOG(debug) << "Neural Network for the TPC PID response correction: Time per track (eval ONNX): " << duration_network / (size * 9) << "ns ; Total time (eval ONNX): " << duration_network / 1000000000 << " s"; + LOG(debug) << "Neural Network for the TPC PID response correction: Time per track (eval + overhead): " << std::chrono::duration>(stop_network_total - start_network_total).count() / (size * 9) << "ns ; Total time (eval + overhead): " << std::chrono::duration>(stop_network_total - start_network_total).count() / 1000000000 << " s"; + + return network_prediction; + } + + template + void makePidTables(const int flagFull, NSF& tableFull, const int flagTiny, NST& tableTiny, const o2::track::PID::ID pid, const float tpcSignal, const T& trk, const C& collisions, const std::vector& network_prediction, const int& count_tracks, const int& tracksForNet_size) + { + if (flagFull != 1 && flagTiny != 1) { + return; + } + if (!trk.hasTPC() || tpcSignal < 0.f) { + if (flagFull) + tableFull(-999.f, -999.f); + if (flagTiny) + tableTiny(aod::pidtpc_tiny::binning::underflowBin); + return; + } + if (skipTPCOnly) { + if (!trk.hasITS() && !trk.hasTRD() && !trk.hasTOF()) { + if (flagFull) + tableFull(-999.f, -999.f); + if (flagTiny) + tableTiny(aod::pidtpc_tiny::binning::underflowBin); + return; + } + } + auto expSignal = response->GetExpectedSignal(trk, pid); + auto expSigma = trk.has_collision() ? response->GetExpectedSigma(collisions.iteratorAt(trk.collisionId()), trk, pid) : 0.07 * expSignal; // use default sigma value of 7% if no collision information to estimate resolution + if (expSignal < 0. || expSigma < 0.) { // skip if expected signal invalid + if (flagFull) + tableFull(-999.f, -999.f); + if (flagTiny) + tableTiny(aod::pidtpc_tiny::binning::underflowBin); + return; + } + + float nSigma = -999.f; + float bg = trk.tpcInnerParam() / o2::track::pid_constants::sMasses[pid]; // estimated beta-gamma for network cutoff + if (useNetworkCorrection && speciesNetworkFlags[pid] && trk.has_collision() && bg > networkBetaGammaCutoff) { + + // Here comes the application of the network. The output--dimensions of the network determine the application: 1: mean, 2: sigma, 3: sigma asymmetric + // For now only the option 2: sigma will be used. The other options are kept if there would be demand later on + if (network.getNumOutputNodes() == 1) { // Expected mean correction; no sigma correction + nSigma = (tpcSignal - network_prediction[count_tracks + tracksForNet_size * pid] * expSignal) / expSigma; + } else if (network.getNumOutputNodes() == 2) { // Symmetric sigma correction + expSigma = (network_prediction[2 * (count_tracks + tracksForNet_size * pid) + 1] - network_prediction[2 * (count_tracks + tracksForNet_size * pid)]) * expSignal; + nSigma = (tpcSignal / expSignal - network_prediction[2 * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[2 * (count_tracks + tracksForNet_size * pid) + 1] - network_prediction[2 * (count_tracks + tracksForNet_size * pid)]); + } else if (network.getNumOutputNodes() == 3) { // Asymmetric sigma corection + if (tpcSignal / expSignal >= network_prediction[3 * (count_tracks + tracksForNet_size * pid)]) { + expSigma = (network_prediction[3 * (count_tracks + tracksForNet_size * pid) + 1] - network_prediction[3 * (count_tracks + tracksForNet_size * pid)]) * expSignal; + nSigma = (tpcSignal / expSignal - network_prediction[3 * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[3 * (count_tracks + tracksForNet_size * pid) + 1] - network_prediction[3 * (count_tracks + tracksForNet_size * pid)]); + } else { + expSigma = (network_prediction[3 * (count_tracks + tracksForNet_size * pid)] - network_prediction[3 * (count_tracks + tracksForNet_size * pid) + 2]) * expSignal; + nSigma = (tpcSignal / expSignal - network_prediction[3 * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[3 * (count_tracks + tracksForNet_size * pid)] - network_prediction[3 * (count_tracks + tracksForNet_size * pid) + 2]); + } + } else { + LOGF(fatal, "Network output-dimensions incompatible!"); + } + } else { + nSigma = response->GetNumberOfSigmaMCTuned(collisions.iteratorAt(trk.collisionId()), trk, pid, tpcSignal); + } + if (flagFull) + tableFull(expSigma, nSigma); + if (flagTiny) + aod::pidutils::packInTable(nSigma, tableTiny); + }; + + void processStandard(Coll const& collisions, Trks const& tracks, aod::BCsWithTimestamps const& bcs) { const uint64_t outTable_size = tracks.size(); + auto reserveTable = [&outTable_size](const Configurable& flag, auto& table) { if (flag.value != 1) { return; } table.reserve(outTable_size); }; + // Prepare memory for enabled tables - reserveTable(pidEl, tablePIDEl); - reserveTable(pidMu, tablePIDMu); - reserveTable(pidPi, tablePIDPi); - reserveTable(pidKa, tablePIDKa); - reserveTable(pidPr, tablePIDPr); - reserveTable(pidDe, tablePIDDe); - reserveTable(pidTr, tablePIDTr); - reserveTable(pidHe, tablePIDHe); - reserveTable(pidAl, tablePIDAl); + reserveTable(pidFullEl, tablePIDFullEl); + reserveTable(pidFullMu, tablePIDFullMu); + reserveTable(pidFullPi, tablePIDFullPi); + reserveTable(pidFullKa, tablePIDFullKa); + reserveTable(pidFullPr, tablePIDFullPr); + reserveTable(pidFullDe, tablePIDFullDe); + reserveTable(pidFullTr, tablePIDFullTr); + reserveTable(pidFullHe, tablePIDFullHe); + reserveTable(pidFullAl, tablePIDFullAl); + + reserveTable(pidTinyEl, tablePIDTinyEl); + reserveTable(pidTinyMu, tablePIDTinyMu); + reserveTable(pidTinyPi, tablePIDTinyPi); + reserveTable(pidTinyKa, tablePIDTinyKa); + reserveTable(pidTinyPr, tablePIDTinyPr); + reserveTable(pidTinyDe, tablePIDTinyDe); + reserveTable(pidTinyTr, tablePIDTinyTr); + reserveTable(pidTinyHe, tablePIDTinyHe); + reserveTable(pidTinyAl, tablePIDTinyAl); - std::vector network_prediction; const uint64_t tracksForNet_size = (skipTPCOnly) ? notTPCStandaloneTracks.size() : tracksWithTPC.size(); + std::vector network_prediction; if (useNetworkCorrection) { - auto start_network_total = std::chrono::high_resolution_clock::now(); - if (autofetchNetworks) { - auto bc = bcs.begin(); - // Initialise correct TPC response object before NN setup (for NCl normalisation) - if (useCCDBParam && ccdbTimestamp.value == 0 && !ccdb->isCachedObjectValid(ccdbPath.value, bc.timestamp())) { // Updating parametrisation only if the initial timestamp is 0 - if (recoPass.value == "") { - LOGP(info, "Retrieving latest TPC response object for timestamp {}:", bc.timestamp()); - } else { - LOGP(info, "Retrieving TPC Response for timestamp {} and recoPass {}:", bc.timestamp(), recoPass.value); - } - response = ccdb->getSpecific(ccdbPath.value, bc.timestamp(), metadata); + network_prediction = createNetworkPrediction(collisions, tracks, bcs, tracksForNet_size); + } + + uint64_t count_tracks = 0; + + for (auto const& trk : tracks) { + // Loop on Tracks + + const auto& bc = trk.has_collision() ? collisions.iteratorAt(trk.collisionId()).bc_as() : bcs.begin(); + if (useCCDBParam && ccdbTimestamp.value == 0 && !ccdb->isCachedObjectValid(ccdbPath.value, bc.timestamp())) { // Updating parametrisation only if the initial timestamp is 0 + if (recoPass.value == "") { + LOGP(info, "Retrieving latest TPC response object for timestamp {}:", bc.timestamp()); + } else { + LOGP(info, "Retrieving TPC Response for timestamp {} and recoPass {}:", bc.timestamp(), recoPass.value); + } + response = ccdb->getSpecific(ccdbPath.value, bc.timestamp(), metadata); + headers = ccdbApi.retrieveHeaders(ccdbPath.value, metadata, bc.timestamp()); + if (!response) { + LOGP(warning, "!! Could not find a valid TPC response object for specific pass name {}! Falling back to latest uploaded object.", metadata["RecoPassName"]); + response = ccdb->getForTimeStamp(ccdbPath.value, bc.timestamp()); + headers = ccdbApi.retrieveHeaders(ccdbPath.value, nullmetadata, bc.timestamp()); if (!response) { - LOGP(warning, "!! Could not find a valid TPC response object for specific pass name {}! Falling back to latest uploaded object.", recoPass.value); - response = ccdb->getForTimeStamp(ccdbPath.value, bc.timestamp()); - if (!response) { - LOGP(fatal, "Could not find ANY TPC response object for the timestamp {}!", bc.timestamp()); - } + LOGP(fatal, "Could not find ANY TPC response object for the timestamp {}!", bc.timestamp()); } - response->PrintAll(); } + LOG(info) << "Successfully retrieved TPC PID object from CCDB for timestamp " << bc.timestamp() << ", period " << headers["LPMProductionTag"] << ", recoPass " << headers["RecoPassName"]; + response->PrintAll(); + } - if (bc.timestamp() < network.getValidityFrom() || bc.timestamp() > network.getValidityUntil()) { // fetches network only if the runnumbers change - LOG(info) << "Fetching network for timestamp: " << bc.timestamp(); - bool retrieveSuccess = ccdbApi.retrieveBlob(networkPathCCDB.value, ".", metadata, bc.timestamp(), false, networkPathLocally.value); - headers = ccdbApi.retrieveHeaders(networkPathCCDB.value, metadata, bc.timestamp()); - if (retrieveSuccess) { - network.initModel(networkPathLocally.value, enableNetworkOptimizations.value, networkSetNumThreads.value, strtoul(headers["Valid-From"].c_str(), NULL, 0), strtoul(headers["Valid-Until"].c_str(), NULL, 0)); + auto makePidTablesDefault = [&trk, &collisions, &network_prediction, &count_tracks, &tracksForNet_size, this](const int flagFull, auto& tableFull, const int flagTiny, auto& tableTiny, const o2::track::PID::ID pid) { + makePidTables(flagFull, tableFull, flagTiny, tableTiny, pid, trk.tpcSignal(), trk, collisions, network_prediction, count_tracks, tracksForNet_size); + }; - std::vector dummyInput(network.getNumInputNodes(), 1.); - network.evalModel(dummyInput); - } else { - LOG(fatal) << "Error encountered while fetching/loading the network from CCDB! Maybe the network doesn't exist yet for this runnumber/timestamp?"; - } - } + makePidTablesDefault(pidFullEl, tablePIDFullEl, pidTinyEl, tablePIDTinyEl, o2::track::PID::Electron); + makePidTablesDefault(pidFullMu, tablePIDFullMu, pidTinyMu, tablePIDTinyMu, o2::track::PID::Muon); + makePidTablesDefault(pidFullPi, tablePIDFullPi, pidTinyPi, tablePIDTinyPi, o2::track::PID::Pion); + makePidTablesDefault(pidFullKa, tablePIDFullKa, pidTinyKa, tablePIDTinyKa, o2::track::PID::Kaon); + makePidTablesDefault(pidFullPr, tablePIDFullPr, pidTinyPr, tablePIDTinyPr, o2::track::PID::Proton); + makePidTablesDefault(pidFullDe, tablePIDFullDe, pidTinyDe, tablePIDTinyDe, o2::track::PID::Deuteron); + makePidTablesDefault(pidFullTr, tablePIDFullTr, pidTinyTr, tablePIDTinyTr, o2::track::PID::Triton); + makePidTablesDefault(pidFullHe, tablePIDFullHe, pidTinyHe, tablePIDTinyHe, o2::track::PID::Helium3); + makePidTablesDefault(pidFullAl, tablePIDFullAl, pidTinyAl, tablePIDTinyAl, o2::track::PID::Alpha); + + if (trk.hasTPC() && (!skipTPCOnly || trk.hasITS() || trk.hasTRD() || trk.hasTOF())) { + count_tracks++; // Increment network track counter only if track has TPC, and (not skipping TPConly) or (is not TPConly) } + } + } - // Defining some network parameters - int input_dimensions = network.getNumInputNodes(); - int output_dimensions = network.getNumOutputNodes(); - const uint64_t track_prop_size = input_dimensions * tracksForNet_size; - const uint64_t prediction_size = output_dimensions * tracksForNet_size; - - network_prediction = std::vector(prediction_size * 9); // For each mass hypotheses - const float nNclNormalization = response->GetNClNormalization(); - float duration_network = 0; - - std::vector track_properties(track_prop_size); - uint64_t counter_track_props = 0; - int loop_counter = 0; - - // Filling a std::vector to be evaluated by the network - // Evaluation on single tracks brings huge overhead: Thus evaluation is done on one large vector - for (int i = 0; i < 9; i++) { // Loop over particle number for which network correction is used - for (auto const& trk : tracks) { - if (!trk.hasTPC()) { - continue; - } - if (skipTPCOnly) { - if (!trk.hasITS() && !trk.hasTRD() && !trk.hasTOF()) { - continue; - } - } - track_properties[counter_track_props] = trk.tpcInnerParam(); - track_properties[counter_track_props + 1] = trk.tgl(); - track_properties[counter_track_props + 2] = trk.signed1Pt(); - track_properties[counter_track_props + 3] = o2::track::pid_constants::sMasses[i]; - track_properties[counter_track_props + 4] = trk.has_collision() ? collisions.iteratorAt(trk.collisionId()).multTPC() / 11000. : 1.; // Dummy value in case no associated collision - track_properties[counter_track_props + 5] = std::sqrt(nNclNormalization / trk.tpcNClsFound()); - counter_track_props += input_dimensions; - } + PROCESS_SWITCH(tpcPid, processStandard, "Creating PID tables without MC TuneOnData", true); - auto start_network_eval = std::chrono::high_resolution_clock::now(); - float* output_network = network.evalModel(track_properties); - auto stop_network_eval = std::chrono::high_resolution_clock::now(); - duration_network += std::chrono::duration>(stop_network_eval - start_network_eval).count(); - for (uint64_t i = 0; i < prediction_size; i += output_dimensions) { - for (int j = 0; j < output_dimensions; j++) { - network_prediction[i + j + prediction_size * loop_counter] = output_network[i + j]; - } - } + Partition mcnotTPCStandaloneTracks = (aod::track::tpcNClsFindable > static_cast(0)) && ((aod::track::itsClusterSizes > static_cast(0)) || (aod::track::trdPattern > static_cast(0)) || (aod::track::tofExpMom > 0.f && aod::track::tofChi2 > 0.f)); // To count number of tracks for use in NN array + Partition mctracksWithTPC = (aod::track::tpcNClsFindable > (uint8_t)0); - counter_track_props = 0; - loop_counter += 1; + void processMcTuneOnData(CollMC const& collisionsMc, TrksMC const& tracksMc, aod::BCsWithTimestamps const& bcs, aod::McParticles const&) + { + gRandom->SetSeed(0); // Ensure unique seed from UUID for each process call + const uint64_t outTable_size = tracksMc.size(); + + auto reserveTable = [&outTable_size](const Configurable& flag, auto& table) { + if (flag.value != 1) { + return; } - track_properties.clear(); + table.reserve(outTable_size); + }; + + // Prepare memory for enabled tables + reserveTable(pidFullEl, tablePIDFullEl); + reserveTable(pidFullMu, tablePIDFullMu); + reserveTable(pidFullPi, tablePIDFullPi); + reserveTable(pidFullKa, tablePIDFullKa); + reserveTable(pidFullPr, tablePIDFullPr); + reserveTable(pidFullDe, tablePIDFullDe); + reserveTable(pidFullTr, tablePIDFullTr); + reserveTable(pidFullHe, tablePIDFullHe); + reserveTable(pidFullAl, tablePIDFullAl); + + reserveTable(pidTinyEl, tablePIDTinyEl); + reserveTable(pidTinyMu, tablePIDTinyMu); + reserveTable(pidTinyPi, tablePIDTinyPi); + reserveTable(pidTinyKa, tablePIDTinyKa); + reserveTable(pidTinyPr, tablePIDTinyPr); + reserveTable(pidTinyDe, tablePIDTinyDe); + reserveTable(pidTinyTr, tablePIDTinyTr); + reserveTable(pidTinyHe, tablePIDTinyHe); + reserveTable(pidTinyAl, tablePIDTinyAl); + + reserveTable(enableTuneOnDataTable, tableTuneOnData); // Only produce the table of tuned dE/dx if the signal is requested by another task + + const uint64_t tracksForNet_size = (skipTPCOnly) ? mcnotTPCStandaloneTracks.size() : mctracksWithTPC.size(); + std::vector network_prediction; - auto stop_network_total = std::chrono::high_resolution_clock::now(); - LOG(debug) << "Neural Network for the TPC PID response correction: Time per track (eval ONNX): " << duration_network / (tracksForNet_size * 9) << "ns ; Total time (eval ONNX): " << duration_network / 1000000000 << " s"; - LOG(debug) << "Neural Network for the TPC PID response correction: Time per track (eval + overhead): " << std::chrono::duration>(stop_network_total - start_network_total).count() / (tracksForNet_size * 9) << "ns ; Total time (eval + overhead): " << std::chrono::duration>(stop_network_total - start_network_total).count() / 1000000000 << " s"; + if (useNetworkCorrection) { + network_prediction = createNetworkPrediction(collisionsMc, tracksMc, bcs, tracksForNet_size); } uint64_t count_tracks = 0; - for (auto const& trk : tracks) { + for (auto const& trk : tracksMc) { // Loop on Tracks - if (trk.has_collision()) { - const auto& bc = collisions.iteratorAt(trk.collisionId()).bc_as(); - if (useCCDBParam && ccdbTimestamp.value == 0 && !ccdb->isCachedObjectValid(ccdbPath.value, bc.timestamp())) { // Updating parametrisation only if the initial timestamp is 0 - if (recoPass.value == "") { - LOGP(info, "Retrieving latest TPC response object for timestamp {}:", bc.timestamp()); - } else { - LOGP(info, "Retrieving TPC Response for timestamp {} and recoPass {}:", bc.timestamp(), recoPass.value); - } - response = ccdb->getSpecific(ccdbPath.value, bc.timestamp(), metadata); + const auto& bc = trk.has_collision() ? collisionsMc.iteratorAt(trk.collisionId()).bc_as() : bcs.begin(); + if (useCCDBParam && ccdbTimestamp.value == 0 && !ccdb->isCachedObjectValid(ccdbPath.value, bc.timestamp())) { // Updating parametrisation only if the initial timestamp is 0 + if (recoPass.value == "") { + LOGP(info, "Retrieving latest TPC response object for timestamp {}:", bc.timestamp()); + } else { + LOGP(info, "Retrieving TPC Response for timestamp {} and recoPass {}:", bc.timestamp(), recoPass.value); + } + response = ccdb->getSpecific(ccdbPath.value, bc.timestamp(), metadata); + if (!response) { + LOGP(warning, "!! Could not find a valid TPC response object for specific pass name {}! Falling back to latest uploaded object.", metadata["RecoPassName"]); + response = ccdb->getForTimeStamp(ccdbPath.value, bc.timestamp()); if (!response) { - LOGP(warning, "!! Could not find a valid TPC response object for specific pass name {}! Falling back to latest uploaded object.", recoPass.value); - response = ccdb->getForTimeStamp(ccdbPath.value, bc.timestamp()); - if (!response) { - LOGP(fatal, "Could not find ANY TPC response object for the timestamp {}!", bc.timestamp()); - } + LOGP(fatal, "Could not find ANY TPC response object for the timestamp {}!", bc.timestamp()); } - response->PrintAll(); } + response->PrintAll(); } - // Check and fill enabled tables - auto makeTable = [&trk, &collisions, &network_prediction, &count_tracks, &tracksForNet_size, this](const Configurable& flag, auto& table, const o2::track::PID::ID pid, bool speciesApplicationFlag) { - if (flag.value != 1) { - return; - } - if (!trk.hasTPC()) { - table(aod::pidtpc_tiny::binning::underflowBin); - return; - } + + // Perform TuneOnData sampling for MC dE/dx + float mcTunedTPCSignal = 0.; + if (!trk.hasTPC()) { + mcTunedTPCSignal = -999.f; + } else { if (skipTPCOnly) { if (!trk.hasITS() && !trk.hasTRD() && !trk.hasTOF()) { - table(aod::pidtpc_tiny::binning::underflowBin); - return; + mcTunedTPCSignal = -999.f; } } + int pid = getPIDIndex(trk.mcParticle().pdgCode()); + auto expSignal = response->GetExpectedSignal(trk, pid); - auto expSigma = trk.has_collision() ? response->GetExpectedSigma(collisions.iteratorAt(trk.collisionId()), trk, pid) : 0.07 * expSignal; // use default sigma value of 7% if no collision information to estimate resolution - if (expSignal < 0. || expSigma < 0.) { // skip if expected signal invalid - table(aod::pidtpc_tiny::binning::underflowBin); - return; + auto expSigma = response->GetExpectedSigma(collisionsMc.iteratorAt(trk.collisionId()), trk, pid); + if (expSignal < 0. || expSigma < 0.) { // if expectation invalid then give undefined signal + mcTunedTPCSignal = -999.f; } float bg = trk.tpcInnerParam() / o2::track::pid_constants::sMasses[pid]; // estimated beta-gamma for network cutoff - if (useNetworkCorrection && speciesApplicationFlag && trk.has_collision() && bg > networkBetaGammaCutoff) { - - // Here comes the application of the network. The output--dimensions of the network dtermine the application: 1: mean, 2: sigma, 3: sigma asymmetric - // For now only the option 2: sigma will be used. The other options are kept if there would be demand later on - if (network.getNumOutputNodes() == 1) { - aod::pidutils::packInTable((trk.tpcSignal() - network_prediction[count_tracks + tracksForNet_size * pid] * expSignal) / expSigma, table); - } else if (network.getNumOutputNodes() == 2) { - aod::pidutils::packInTable((trk.tpcSignal() / expSignal - network_prediction[2 * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[2 * (count_tracks + tracksForNet_size * pid) + 1] - network_prediction[2 * (count_tracks + tracksForNet_size * pid)]), table); - } else if (network.getNumOutputNodes() == 3) { - if (trk.tpcSignal() / expSignal >= network_prediction[3 * (count_tracks + tracksForNet_size * pid)]) { - aod::pidutils::packInTable((trk.tpcSignal() / expSignal - network_prediction[3 * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[3 * (count_tracks + tracksForNet_size * pid) + 1] - network_prediction[3 * (count_tracks + tracksForNet_size * pid)]), table); - } else { - aod::pidutils::packInTable((trk.tpcSignal() / expSignal - network_prediction[3 * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[3 * (count_tracks + tracksForNet_size * pid)] - network_prediction[3 * (count_tracks + tracksForNet_size * pid) + 2]), table); - } + if (useNetworkCorrection && speciesNetworkFlags[pid] && trk.has_collision() && bg > networkBetaGammaCutoff) { + auto mean = network_prediction[2 * (count_tracks + tracksForNet_size * pid)] * expSignal; // Absolute mean, i.e. the mean dE/dx value of the data in that slice, not the mean of the NSigma distribution + auto sigma = (network_prediction[2 * (count_tracks + tracksForNet_size * pid) + 1] - network_prediction[2 * (count_tracks + tracksForNet_size * pid)]) * expSignal; + if (mean < 0.f || sigma < 0.f) { + mcTunedTPCSignal = -999.f; } else { - LOGF(fatal, "Network output-dimensions incompatible!"); + mcTunedTPCSignal = gRandom->Gaus(mean, sigma); } } else { - aod::pidutils::packInTable(response->GetNumberOfSigma(collisions.iteratorAt(trk.collisionId()), trk, pid), table); + mcTunedTPCSignal = gRandom->Gaus(expSignal, expSigma); } + } + if (enableTuneOnDataTable) + tableTuneOnData(mcTunedTPCSignal); + + // Check and fill enabled nsigma tables + + auto makePidTablesMCTune = [&trk, &collisionsMc, &network_prediction, &count_tracks, &tracksForNet_size, &mcTunedTPCSignal, this](const int flagFull, auto& tableFull, const int flagTiny, auto& tableTiny, const o2::track::PID::ID pid) { + makePidTables(flagFull, tableFull, flagTiny, tableTiny, pid, mcTunedTPCSignal, trk, collisionsMc, network_prediction, count_tracks, tracksForNet_size); }; - makeTable(pidEl, tablePIDEl, o2::track::PID::Electron, useNetworkEl); - makeTable(pidMu, tablePIDMu, o2::track::PID::Muon, useNetworkMu); - makeTable(pidPi, tablePIDPi, o2::track::PID::Pion, useNetworkPi); - makeTable(pidKa, tablePIDKa, o2::track::PID::Kaon, useNetworkKa); - makeTable(pidPr, tablePIDPr, o2::track::PID::Proton, useNetworkPr); - makeTable(pidDe, tablePIDDe, o2::track::PID::Deuteron, useNetworkDe); - makeTable(pidTr, tablePIDTr, o2::track::PID::Triton, useNetworkTr); - makeTable(pidHe, tablePIDHe, o2::track::PID::Helium3, useNetworkHe); - makeTable(pidAl, tablePIDAl, o2::track::PID::Alpha, useNetworkAl); + makePidTablesMCTune(pidFullEl, tablePIDFullEl, pidTinyEl, tablePIDTinyEl, o2::track::PID::Electron); + makePidTablesMCTune(pidFullMu, tablePIDFullMu, pidTinyMu, tablePIDTinyMu, o2::track::PID::Muon); + makePidTablesMCTune(pidFullPi, tablePIDFullPi, pidTinyPi, tablePIDTinyPi, o2::track::PID::Pion); + makePidTablesMCTune(pidFullKa, tablePIDFullKa, pidTinyKa, tablePIDTinyKa, o2::track::PID::Kaon); + makePidTablesMCTune(pidFullPr, tablePIDFullPr, pidTinyPr, tablePIDTinyPr, o2::track::PID::Proton); + makePidTablesMCTune(pidFullDe, tablePIDFullDe, pidTinyDe, tablePIDTinyDe, o2::track::PID::Deuteron); + makePidTablesMCTune(pidFullTr, tablePIDFullTr, pidTinyTr, tablePIDTinyTr, o2::track::PID::Triton); + makePidTablesMCTune(pidFullHe, tablePIDFullHe, pidTinyHe, tablePIDTinyHe, o2::track::PID::Helium3); + makePidTablesMCTune(pidFullAl, tablePIDFullAl, pidTinyAl, tablePIDTinyAl, o2::track::PID::Alpha); if (trk.hasTPC() && (!skipTPCOnly || trk.hasITS() || trk.hasTRD() || trk.hasTOF())) { - count_tracks++; // Increment network track counter only if (not skipping TPConly) or (is not TPConly) + count_tracks++; // Increment network track counter only if track has TPC, and (not skipping TPConly) or (is not TPConly) } } } + + PROCESS_SWITCH(tpcPid, processMcTuneOnData, "Creating PID tables with MC TuneOnData", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + metadataInfo.initMetadata(cfgc); // Parse AO2D metadata + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/Common/TableProducer/PID/pidTPCBase.h b/Common/TableProducer/PID/pidTPCBase.h index d10d6acc30a..a882a598ef9 100644 --- a/Common/TableProducer/PID/pidTPCBase.h +++ b/Common/TableProducer/PID/pidTPCBase.h @@ -31,4 +31,30 @@ using PIDMult = PIDMults::iterator; } // namespace o2::aod +int getPIDIndex(const int pdgCode) // Get O2 PID index corresponding to MC PDG code +{ + switch (abs(pdgCode)) { + case 11: + return o2::track::PID::Electron; + case 13: + return o2::track::PID::Muon; + case 211: + return o2::track::PID::Pion; + case 321: + return o2::track::PID::Kaon; + case 2212: + return o2::track::PID::Proton; + case 1000010020: + return o2::track::PID::Deuteron; + case 1000010030: + return o2::track::PID::Triton; + case 1000020030: + return o2::track::PID::Helium3; + case 1000020040: + return o2::track::PID::Alpha; + default: // treat as pion if not any of the above + return o2::track::PID::Pion; + } +} + #endif // COMMON_TABLEPRODUCER_PID_PIDTPCBASE_H_ diff --git a/Common/TableProducer/PID/pidTPCFull.cxx b/Common/TableProducer/PID/pidTPCFull.cxx deleted file mode 100644 index 47f391f910f..00000000000 --- a/Common/TableProducer/PID/pidTPCFull.cxx +++ /dev/null @@ -1,426 +0,0 @@ -// 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 pidTPCFull.cxx -/// \author Nicolò Jacazio nicolo.jacazio@cern.ch -/// \author Christian Sonnabend christian.sonnabend@cern.ch -/// \author Annalena Kalteyer annalena.sophie.kalteyer@cern.ch -/// \brief Task to produce PID tables for TPC split for each particle. -/// Only the tables for the mass hypotheses requested are filled, the others are sent empty. -/// QA histograms for the TPC PID can be produced by adding `--add-qa 1` to the workflow -/// - -// ROOT includes -#include "TFile.h" -#include "TSystem.h" - -// O2 includes -#include -#include "Framework/AnalysisTask.h" -#include "ReconstructionDataFormats/Track.h" -#include "CCDB/CcdbApi.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/Core/PID/TPCPIDResponse.h" -#include "Framework/AnalysisDataModel.h" -#include "Common/DataModel/Multiplicity.h" -#include "TableHelper.h" -#include "Tools/ML/model.h" -#include "pidTPCBase.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::pid; -using namespace o2::pid::tpc; -using namespace o2::framework::expressions; -using namespace o2::track; -using namespace o2::ml; - -void customize(std::vector& workflowOptions) -{ - std::vector options{{"add-qa", VariantType::Int, 0, {"Legacy. No effect."}}}; - std::swap(workflowOptions, options); -} - -#include "Framework/runDataProcessing.h" - -/// Task to produce the response table -struct tpcPidFull { - using Trks = soa::Join; - using Coll = soa::Join; - - // Tables to produce - Produces tablePIDEl; - Produces tablePIDMu; - Produces tablePIDPi; - Produces tablePIDKa; - Produces tablePIDPr; - Produces tablePIDDe; - Produces tablePIDTr; - Produces tablePIDHe; - Produces tablePIDAl; - - // TPC PID Response - o2::pid::tpc::Response* response; - - // Network correction for TPC PID response - OnnxModel network; - o2::ccdb::CcdbApi ccdbApi; - std::map metadata; - std::map headers; - - // Input parameters - Service ccdb; - Configurable paramfile{"param-file", "", "Path to the parametrization object, if empty the parametrization is not taken from file"}; - Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable ccdbPath{"ccdbPath", "Analysis/PID/TPC/Response", "Path of the TPC parametrization on the CCDB"}; - Configurable recoPass{"recoPass", "", "Reconstruction pass name for CCDB query (automatically takes latest object for timestamp if blank)"}; - Configurable ccdbTimestamp{"ccdb-timestamp", 0, "timestamp of the object used to query in CCDB the detector response. Exceptions: -1 gets the latest object, 0 gets the run dependent timestamp"}; - // Parameters for loading network from a file / downloading the file - Configurable useNetworkCorrection{"useNetworkCorrection", 0, "(bool) Wether or not to use the network correction for the TPC dE/dx signal"}; - Configurable autofetchNetworks{"autofetchNetworks", 1, "(bool) Automatically fetches networks from CCDB for the correct run number"}; - Configurable skipTPCOnly{"skipTPCOnly", false, "Flag to skip TPC only tracks (faster but affects the analyses that use TPC only tracks)"}; - Configurable networkPathLocally{"networkPathLocally", "network.onnx", "(std::string) Path to the local .onnx file. If autofetching is enabled, then this is where the files will be downloaded"}; - Configurable networkPathCCDB{"networkPathCCDB", "Analysis/PID/TPC/ML", "Path on CCDB"}; - Configurable enableNetworkOptimizations{"enableNetworkOptimizations", 1, "(bool) If the neural network correction is used, this enables GraphOptimizationLevel::ORT_ENABLE_EXTENDED in the ONNX session"}; - Configurable networkSetNumThreads{"networkSetNumThreads", 0, "Especially important for running on a SLURM cluster. Sets the number of threads used for execution."}; - // Configuration flags to include and exclude particle hypotheses - Configurable pidEl{"pid-el", -1, {"Produce PID information for the Electron mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; - Configurable pidMu{"pid-mu", -1, {"Produce PID information for the Muon mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; - Configurable pidPi{"pid-pi", -1, {"Produce PID information for the Pion mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; - Configurable pidKa{"pid-ka", -1, {"Produce PID information for the Kaon mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; - Configurable pidPr{"pid-pr", -1, {"Produce PID information for the Proton mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; - Configurable pidDe{"pid-de", -1, {"Produce PID information for the Deuterons mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; - Configurable pidTr{"pid-tr", -1, {"Produce PID information for the Triton mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; - Configurable pidHe{"pid-he", -1, {"Produce PID information for the Helium3 mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; - Configurable pidAl{"pid-al", -1, {"Produce PID information for the Alpha mass hypothesis, overrides the automatic setup: the corresponding table can be set off (0) or on (1)"}}; - Configurable useNetworkEl{"useNetworkEl", 1, {"Switch for applying neural network on the electron mass hypothesis (if network enabled) (set to 0 to disable)"}}; - Configurable useNetworkMu{"useNetworkMu", 1, {"Switch for applying neural network on the muon mass hypothesis (if network enabled) (set to 0 to disable)"}}; - Configurable useNetworkPi{"useNetworkPi", 1, {"Switch for applying neural network on the pion mass hypothesis (if network enabled) (set to 0 to disable)"}}; - Configurable useNetworkKa{"useNetworkKa", 1, {"Switch for applying neural network on the kaon mass hypothesis (if network enabled) (set to 0 to disable)"}}; - Configurable useNetworkPr{"useNetworkPr", 1, {"Switch for applying neural network on the proton mass hypothesis (if network enabled) (set to 0 to disable)"}}; - Configurable useNetworkDe{"useNetworkDe", 1, {"Switch for applying neural network on the deuteron mass hypothesis (if network enabled) (set to 0 to disable)"}}; - Configurable useNetworkTr{"useNetworkTr", 1, {"Switch for applying neural network on the triton mass hypothesis (if network enabled) (set to 0 to disable)"}}; - Configurable useNetworkHe{"useNetworkHe", 1, {"Switch for applying neural network on the helium3 mass hypothesis (if network enabled) (set to 0 to disable)"}}; - Configurable useNetworkAl{"useNetworkAl", 1, {"Switch for applying neural network on the alpha mass hypothesis (if network enabled) (set to 0 to disable)"}}; - Configurable networkBetaGammaCutoff{"networkBetaGammaCutoff", 0.45, {"Lower value of beta-gamma to override the NN application"}}; - - // Paramatrization configuration - bool useCCDBParam = false; - - void init(o2::framework::InitContext& initContext) - { - response = new o2::pid::tpc::Response(); - // Checking the tables are requested in the workflow and enabling them - auto enableFlag = [&](const std::string particle, Configurable& flag) { - enableFlagIfTableRequired(initContext, "pidTPCFull" + particle, flag); - }; - enableFlag("El", pidEl); - enableFlag("Mu", pidMu); - enableFlag("Pi", pidPi); - enableFlag("Ka", pidKa); - enableFlag("Pr", pidPr); - enableFlag("De", pidDe); - enableFlag("Tr", pidTr); - enableFlag("He", pidHe); - enableFlag("Al", pidAl); - - // Initialise metadata object for CCDB calls - if (recoPass.value == "") { - LOGP(info, "Reco pass not specified; CCDB will take latest available object"); - } else { - LOGP(info, "CCDB object will be requested for reconstruction pass {}", recoPass.value); - metadata["RecoPassName"] = recoPass.value; - } - - /// TPC PID Response - const TString fname = paramfile.value; - if (fname != "") { // Loading the parametrization from file - LOGP(info, "Loading TPC response from file {}", fname.Data()); - try { - std::unique_ptr f(TFile::Open(fname, "READ")); - f->GetObject("Response", response); - } catch (...) { - LOGF(fatal, "Loading the TPC PID Response from file {} failed!", fname.Data()); - } - response->PrintAll(); - } else { - useCCDBParam = true; - const std::string path = ccdbPath.value; - const auto time = ccdbTimestamp.value; - ccdb->setURL(url.value); - ccdb->setFatalWhenNull(false); // manual fallback in case ccdb entry empty - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); - if (time != 0) { - LOGP(info, "Initialising TPC PID response for fixed timestamp {} and reco pass {}:", time, recoPass.value); - ccdb->setTimestamp(time); - response = ccdb->getSpecific(path, time, metadata); - if (!response) { - LOGF(warning, "Unable to find TPC parametrisation for specified pass name - falling back to latest object"); - response = ccdb->getForTimeStamp(path, time); - if (!response) { - LOGF(fatal, "Unable to find any TPC object corresponding to timestamp {}!", time); - } - } - response->PrintAll(); - } - } - - /// Neural network init for TPC PID - - if (!useNetworkCorrection) { - return; - } else { - - /// CCDB and auto-fetching - ccdbApi.init(url); - if (!autofetchNetworks) { - if (ccdbTimestamp > 0) { - /// Fetching network for specific timestamp - LOG(info) << "Fetching network for timestamp: " << ccdbTimestamp.value; - bool retrieveSuccess = ccdbApi.retrieveBlob(networkPathCCDB.value, ".", metadata, ccdbTimestamp.value, false, networkPathLocally.value); - headers = ccdbApi.retrieveHeaders(networkPathCCDB.value, metadata, ccdbTimestamp.value); - if (retrieveSuccess) { - network.initModel(networkPathLocally.value, enableNetworkOptimizations.value, networkSetNumThreads.value, strtoul(headers["Valid-From"].c_str(), NULL, 0), strtoul(headers["Valid-Until"].c_str(), NULL, 0)); - std::vector dummyInput(network.getNumInputNodes(), 1.); - network.evalModel(dummyInput); /// Init the model evaluations - } else { - LOG(fatal) << "Error encountered while fetching/loading the network from CCDB! Maybe the network doesn't exist yet for this runnumber/timestamp?"; - } - } else { - /// Taking the network from local file - if (networkPathLocally.value == "") { - LOG(fatal) << "Local path must be set (flag networkPathLocally)! Aborting..."; - } - LOG(info) << "Using local file [" << networkPathLocally.value << "] for the TPC PID response correction."; - network.initModel(networkPathLocally.value, enableNetworkOptimizations.value, networkSetNumThreads.value); - std::vector dummyInput(network.getNumInputNodes(), 1.); - network.evalModel(dummyInput); // This is an initialisation and might reduce the overhead of the model - } - } else { - return; - } - } - } - - Partition notTPCStandaloneTracks = (aod::track::tpcNClsFindable > (uint8_t)0) && ((aod::track::itsClusterSizes > (uint32_t)0) || (aod::track::trdPattern > (uint8_t)0) || (aod::track::tofExpMom > 0.f && aod::track::tofChi2 > 0.f)); // To count number of tracks for use in NN array - Partition tracksWithTPC = (aod::track::tpcNClsFindable > (uint8_t)0); - - void process(Coll const& collisions, Trks const& tracks, - aod::BCsWithTimestamps const& bcs) - { - - const uint64_t outTable_size = tracks.size(); - auto reserveTable = [&outTable_size](const Configurable& flag, auto& table) { - if (flag.value != 1) { - return; - } - table.reserve(outTable_size); - }; - // Prepare memory for enabled tables - reserveTable(pidEl, tablePIDEl); - reserveTable(pidMu, tablePIDMu); - reserveTable(pidPi, tablePIDPi); - reserveTable(pidKa, tablePIDKa); - reserveTable(pidPr, tablePIDPr); - reserveTable(pidDe, tablePIDDe); - reserveTable(pidTr, tablePIDTr); - reserveTable(pidHe, tablePIDHe); - reserveTable(pidAl, tablePIDAl); - - std::vector network_prediction; - const uint64_t tracksForNet_size = (skipTPCOnly) ? notTPCStandaloneTracks.size() : tracksWithTPC.size(); - - if (useNetworkCorrection) { - - auto start_network_total = std::chrono::high_resolution_clock::now(); - if (autofetchNetworks) { - auto bc = bcs.begin(); - // Initialise correct TPC response object before NN setup (for NCl normalisation) - if (useCCDBParam && ccdbTimestamp.value == 0 && !ccdb->isCachedObjectValid(ccdbPath.value, bc.timestamp())) { // Updating parametrisation only if the initial timestamp is 0 - if (recoPass.value == "") { - LOGP(info, "Retrieving latest TPC response object for timestamp {}:", bc.timestamp()); - } else { - LOGP(info, "Retrieving TPC Response for timestamp {} and recoPass {}:", bc.timestamp(), recoPass.value); - } - response = ccdb->getSpecific(ccdbPath.value, bc.timestamp(), metadata); - if (!response) { - LOGP(warning, "!! Could not find a valid TPC response object for specific pass name {}! Falling back to latest uploaded object.", recoPass.value); - response = ccdb->getForTimeStamp(ccdbPath.value, bc.timestamp()); - if (!response) { - LOGP(fatal, "Could not find ANY TPC response object for the timestamp {}!", bc.timestamp()); - } - } - response->PrintAll(); - } - - if (bc.timestamp() < network.getValidityFrom() || bc.timestamp() > network.getValidityUntil()) { // fetches network only if the runnumbers change - LOG(info) << "Fetching network for timestamp: " << bc.timestamp(); - bool retrieveSuccess = ccdbApi.retrieveBlob(networkPathCCDB.value, ".", metadata, bc.timestamp(), false, networkPathLocally.value); - headers = ccdbApi.retrieveHeaders(networkPathCCDB.value, metadata, bc.timestamp()); - if (retrieveSuccess) { - network.initModel(networkPathLocally.value, enableNetworkOptimizations.value, networkSetNumThreads.value, strtoul(headers["Valid-From"].c_str(), NULL, 0), strtoul(headers["Valid-Until"].c_str(), NULL, 0)); - std::vector dummyInput(network.getNumInputNodes(), 1.); - network.evalModel(dummyInput); - } else { - LOG(fatal) << "Error encountered while fetching/loading the network from CCDB! Maybe the network doesn't exist yet for this runnumber/timestamp?"; - } - } - } - - // Defining some network parameters - int input_dimensions = network.getNumInputNodes(); - int output_dimensions = network.getNumOutputNodes(); - const uint64_t track_prop_size = input_dimensions * tracksForNet_size; - const uint64_t prediction_size = output_dimensions * tracksForNet_size; - - network_prediction = std::vector(prediction_size * 9); // For each mass hypotheses - const float nNclNormalization = response->GetNClNormalization(); - float duration_network = 0; - - std::vector track_properties(track_prop_size); - uint64_t counter_track_props = 0; - int loop_counter = 0; - - // Filling a std::vector to be evaluated by the network - // Evaluation on single tracks brings huge overhead: Thus evaluation is done on one large vector - for (int i = 0; i < 9; i++) { // Loop over particle number for which network correction is used - for (auto const& trk : tracks) { - if (!trk.hasTPC()) { - continue; - } - if (skipTPCOnly) { - if (!trk.hasITS() && !trk.hasTRD() && !trk.hasTOF()) { - continue; - } - } - track_properties[counter_track_props] = trk.tpcInnerParam(); - track_properties[counter_track_props + 1] = trk.tgl(); - track_properties[counter_track_props + 2] = trk.signed1Pt(); - track_properties[counter_track_props + 3] = o2::track::pid_constants::sMasses[i]; - track_properties[counter_track_props + 4] = trk.has_collision() ? collisions.iteratorAt(trk.collisionId()).multTPC() / 11000. : 1.; // Dummy value in case no associated collision - track_properties[counter_track_props + 5] = std::sqrt(nNclNormalization / trk.tpcNClsFound()); - counter_track_props += input_dimensions; - } - - auto start_network_eval = std::chrono::high_resolution_clock::now(); - float* output_network = network.evalModel(track_properties); - auto stop_network_eval = std::chrono::high_resolution_clock::now(); - duration_network += std::chrono::duration>(stop_network_eval - start_network_eval).count(); - for (uint64_t i = 0; i < prediction_size; i += output_dimensions) { - for (int j = 0; j < output_dimensions; j++) { - network_prediction[i + j + prediction_size * loop_counter] = output_network[i + j]; - } - } - - counter_track_props = 0; - loop_counter += 1; - } - track_properties.clear(); - - auto stop_network_total = std::chrono::high_resolution_clock::now(); - LOG(debug) << "Neural Network for the TPC PID response correction: Time per track (eval ONNX): " << duration_network / (tracksForNet_size * 9) << "ns ; Total time (eval ONNX): " << duration_network / 1000000000 << " s"; - LOG(debug) << "Neural Network for the TPC PID response correction: Time per track (eval + overhead): " << std::chrono::duration>(stop_network_total - start_network_total).count() / (tracksForNet_size * 9) << "ns ; Total time (eval + overhead): " << std::chrono::duration>(stop_network_total - start_network_total).count() / 1000000000 << " s"; - } - - uint64_t count_tracks = 0; - - for (auto const& trk : tracks) { - // Loop on Tracks - if (trk.has_collision()) { - const auto& bc = collisions.iteratorAt(trk.collisionId()).bc_as(); - if (useCCDBParam && ccdbTimestamp.value == 0 && !ccdb->isCachedObjectValid(ccdbPath.value, bc.timestamp())) { // Updating parametrisation only if the initial timestamp is 0 - if (recoPass.value == "") { - LOGP(info, "Retrieving latest TPC response object for timestamp {}:", bc.timestamp()); - } else { - LOGP(info, "Retrieving TPC Response for timestamp {} and recoPass {}:", bc.timestamp(), recoPass.value); - } - response = ccdb->getSpecific(ccdbPath.value, bc.timestamp(), metadata); - if (!response) { - LOGP(warning, "!! Could not find a valid TPC response object for specific pass name {}! Falling back to latest uploaded object.", recoPass.value); - response = ccdb->getForTimeStamp(ccdbPath.value, bc.timestamp()); - if (!response) { - LOGP(fatal, "Could not find ANY TPC response object for the timestamp {}!", bc.timestamp()); - } - } - response->PrintAll(); - } - } - // Check and fill enabled tables - auto makeTable = [&trk, &collisions, &network_prediction, &count_tracks, &tracksForNet_size, this](const Configurable& flag, auto& table, const o2::track::PID::ID pid, bool speciesApplicationFlag) { - if (flag.value != 1) { - return; - } - if (!trk.hasTPC()) { - table(-999.f, -999.f); - return; - } - if (skipTPCOnly) { - if (!trk.hasITS() && !trk.hasTRD() && !trk.hasTOF()) { - table(-999.f, -999.f); - return; - } - } - auto expSignal = response->GetExpectedSignal(trk, pid); - auto expSigma = trk.has_collision() ? response->GetExpectedSigma(collisions.iteratorAt(trk.collisionId()), trk, pid) : 0.07 * expSignal; // use default sigma value of 7% if no collision information to estimate resolution - if (expSignal < 0. || expSigma < 0.) { // skip if expected signal invalid - table(-999.f, -999.f); - return; - } - float bg = trk.tpcInnerParam() / o2::track::pid_constants::sMasses[pid]; // estimated beta-gamma for network cutoff - - if (useNetworkCorrection && speciesApplicationFlag && trk.has_collision() && bg > networkBetaGammaCutoff) { - - // Here comes the application of the network. The output--dimensions of the network dtermine the application: 1: mean, 2: sigma, 3: sigma asymmetric - // For now only the option 2: sigma will be used. The other options are kept if there would be demand later on - if (network.getNumOutputNodes() == 1) { - table(expSigma, - (trk.tpcSignal() - network_prediction[count_tracks + tracksForNet_size * pid] * expSignal) / expSigma); - } else if (network.getNumOutputNodes() == 2) { - table((network_prediction[2 * (count_tracks + tracksForNet_size * pid) + 1] - network_prediction[2 * (count_tracks + tracksForNet_size * pid)]) * expSignal, - (trk.tpcSignal() / expSignal - network_prediction[2 * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[2 * (count_tracks + tracksForNet_size * pid) + 1] - network_prediction[2 * (count_tracks + tracksForNet_size * pid)])); - } else if (network.getNumOutputNodes() == 3) { - if (trk.tpcSignal() / expSignal >= network_prediction[3 * (count_tracks + tracksForNet_size * pid)]) { - table((network_prediction[3 * (count_tracks + tracksForNet_size * pid) + 1] - network_prediction[3 * (count_tracks + tracksForNet_size * pid)]) * expSignal, - (trk.tpcSignal() / expSignal - network_prediction[3 * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[3 * (count_tracks + tracksForNet_size * pid) + 1] - network_prediction[3 * (count_tracks + tracksForNet_size * pid)])); - } else { - table((network_prediction[3 * (count_tracks + tracksForNet_size * pid)] - network_prediction[3 * (count_tracks + tracksForNet_size * pid) + 2]) * expSignal, - (trk.tpcSignal() / expSignal - network_prediction[3 * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[3 * (count_tracks + tracksForNet_size * pid)] - network_prediction[3 * (count_tracks + tracksForNet_size * pid) + 2])); - } - } else { - LOGF(fatal, "Network output-dimensions incompatible!"); - } - } else { - table(expSigma, - response->GetNumberOfSigma(collisions.iteratorAt(trk.collisionId()), trk, pid)); - } - }; - - makeTable(pidEl, tablePIDEl, o2::track::PID::Electron, useNetworkEl); - makeTable(pidMu, tablePIDMu, o2::track::PID::Muon, useNetworkMu); - makeTable(pidPi, tablePIDPi, o2::track::PID::Pion, useNetworkPi); - makeTable(pidKa, tablePIDKa, o2::track::PID::Kaon, useNetworkKa); - makeTable(pidPr, tablePIDPr, o2::track::PID::Proton, useNetworkPr); - makeTable(pidDe, tablePIDDe, o2::track::PID::Deuteron, useNetworkDe); - makeTable(pidTr, tablePIDTr, o2::track::PID::Triton, useNetworkTr); - makeTable(pidHe, tablePIDHe, o2::track::PID::Helium3, useNetworkHe); - makeTable(pidAl, tablePIDAl, o2::track::PID::Alpha, useNetworkAl); - - if (trk.hasTPC() && (!skipTPCOnly || trk.hasITS() || trk.hasTRD() || trk.hasTOF())) { - count_tracks++; // Increment network track counter only if track has TPC, and (not skipping TPConly) or (is not TPConly) - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/Common/TableProducer/caloClusterProducer.cxx b/Common/TableProducer/caloClusterProducer.cxx index b569cf7a58f..086885beb4c 100644 --- a/Common/TableProducer/caloClusterProducer.cxx +++ b/Common/TableProducer/caloClusterProducer.cxx @@ -9,6 +9,17 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file caloClusterProducer.cxx +/// \brief Produces PHOS clusters from PHOS cells +/// +/// \author Dmitri Peresunko + +#include +#include +#include +#include +#include + #include "Framework/ConfigParamSpec.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -36,9 +47,9 @@ using namespace o2::framework; using namespace o2; -using mcCells = o2::soa::Join; +using McCells = o2::soa::Join; -struct caloClusterProducerTask { +struct CaloClusterProducer { Produces clucursor; Produces cluambcursor; Produces matchedTracks; @@ -46,13 +57,13 @@ struct caloClusterProducerTask { Produces cluambmccursor; Configurable isMC{"isMC", 0, "0 - data, 1 - MC"}; - Configurable useCoreE{"coreE", 0, "0 - full energy, 1 - core energy"}; + Configurable useCoreE{"useCoreE", 0, "0 - full energy, 1 - core energy"}; Configurable skipL1phase{"skipL1phase", false, "skip or apply L1phase time correction"}; - Configurable mNonlinType{"nonlinType", 1, "0:no corr, 1: default"}; - Configurable> cpvMinE{"cpvCluMinAmp", {20., 50., 50.}, "minimal CPV cluster amplitude per module"}; - Configurable mBadMapPath{"badmapPath", "PHS/Calib/BadMap", "path to BadMap snapshot"}; - Configurable mCalibPath{"calibPath", "PHS/Calib/CalibParams", "path to Calibration snapshot"}; - Configurable mL1PhasePath{"L1phasePath", "PHS/Calib/L1phase", "path to L1phase snapshot"}; + Configurable nonlinType{"nonlinType", 1, "0:no corr, 1: data, 2: MC"}; + Configurable> cpvMinE{"cpvMinE", {20., 50., 50.}, "minimal CPV cluster amplitude per module"}; + Configurable badMapPath{"badMapPath", "PHS/Calib/BadMap", "path to BadMap snapshot"}; + Configurable calibPath{"calibPath", "PHS/Calib/CalibParams", "path to Calibration snapshot"}; + Configurable l1phasePath{"l1phasePath", "PHS/Calib/L1phase", "path to L1phase snapshot"}; Service ccdb; @@ -71,15 +82,15 @@ struct caloClusterProducerTask { static constexpr int16_t kCpvX = 7; // grid 6 steps along z and 7 along phi as largest match ellips 20x20 cm static constexpr int16_t kCpvZ = 6; static constexpr int16_t kCpvCells = 4 * kCpvX * kCpvZ; // 4 modules - static constexpr float cpvMaxX = 73; // max CPV coordinate phi - static constexpr float cpvMaxZ = 63; // max CPV coordinate z + static constexpr float kCpvMaxX = 73; // max CPV coordinate phi + static constexpr float kCpvMaxZ = 63; // max CPV coordinate z - class trackMatch + class TrackMatch { public: - trackMatch() = default; - trackMatch(float x, float z, int i) : pX(x), pZ(z), indx(i) {} - ~trackMatch() = default; + TrackMatch() = default; + TrackMatch(float x, float z, int i) : pX(x), pZ(z), indx(i) {} + ~TrackMatch() = default; public: float pX = 9999.; // X (phi) track coordinate in PHOS plane @@ -87,11 +98,11 @@ struct caloClusterProducerTask { int indx = -1; // track global index }; - class trackTrigRec + class TrackTrigRec { public: - trackTrigRec() = default; - ~trackTrigRec() = default; + TrackTrigRec() = default; + ~TrackTrigRec() = default; public: int64_t mTR; // BC ref @@ -123,7 +134,7 @@ struct caloClusterProducerTask { } std::map bcMap; int bcId = 0; - for (auto bc : bcs) { + for (const auto& bc : bcs) { bcMap[bc.globalBC()] = bcId; bcId++; } @@ -131,7 +142,7 @@ struct caloClusterProducerTask { // If several collisions appear in BC, choose one with largers number of contributors std::map colMap; int colId = 0; - for (auto cl : colls) { + for (const auto& cl : colls) { auto colbc = colMap.find(cl.bc_as().globalBC()); if (colbc == colMap.end()) { // single collision per BC colMap[cl.bc_as().globalBC()] = colId; @@ -149,11 +160,11 @@ struct caloClusterProducerTask { // Fill output table // calibration may be updated by CCDB fetcher - const o2::phos::BadChannelsMap* badMap = ccdb->getForTimeStamp(mBadMapPath, timestamp); - const o2::phos::CalibParams* calibParams = ccdb->getForTimeStamp(mCalibPath, timestamp); + const o2::phos::BadChannelsMap* badMap = ccdb->getForTimeStamp(badMapPath, timestamp); + const o2::phos::CalibParams* calibParams = ccdb->getForTimeStamp(calibPath, timestamp); if (!isMC && !skipL1phase) { - const std::vector* vec = ccdb->getForTimeStamp>(mL1PhasePath, timestamp); + const std::vector* vec = ccdb->getForTimeStamp>(l1phasePath, timestamp); if (vec) { clusterizerPHOS->setL1phase((*vec)[0]); } else { @@ -182,7 +193,7 @@ struct caloClusterProducerTask { o2::InteractionRecord ir; const int kPHOS = 0; - for (auto& c : cells) { + for (const auto& c : cells) { if (c.caloType() != kPHOS) // PHOS continue; // Fix for bug in trigger digits @@ -216,7 +227,7 @@ struct caloClusterProducerTask { // Find CPV clusters corresponding to PHOS trigger records std::vector> cpvMatchPoints[kCpvCells]; // Number of entries in each cell per TrigRecord - std::vector cpvNMatchPoints; + std::vector cpvNMatchPoints; cpvNMatchPoints.reserve(outputPHOSClusterTrigRecs.size()); int64_t curBC = -1; if (cpvs.begin() != cpvs.end()) { @@ -245,7 +256,7 @@ struct caloClusterProducerTask { if (cpvclu.amplitude() < static_cast>(cpvMinE)[static_cast(cpvclu.moduleNumber()) - 2]) { continue; } - int index = CpvMatchIndex(cpvclu.moduleNumber(), cpvclu.posX(), cpvclu.posZ()); + int index = cpvMatchIndex(cpvclu.moduleNumber(), cpvclu.posX(), cpvclu.posZ()); cpvMatchPoints[index].emplace_back(cpvclu.posX(), cpvclu.posZ()); } if (cpvNMatchPoints.size() > 0) { @@ -255,7 +266,7 @@ struct caloClusterProducerTask { } // Fill output - for (auto& cluTR : outputPHOSClusterTrigRecs) { + for (const auto& cluTR : outputPHOSClusterTrigRecs) { int firstClusterInEvent = cluTR.getFirstEntry(); int lastClusterInEvent = firstClusterInEvent + cluTR.getNumberOfObjects(); @@ -293,7 +304,7 @@ struct caloClusterProducerTask { // Correction for the depth of the shower starting point (TDR p 127) const float para = 0.925; const float parb = 6.52; - float depth = para * TMath::Log(e) + parb; + float depth = para * std::log(e) + parb; posX -= posX * depth / 460.; posZ -= (posZ - vtx.Z()) * depth / 460.; @@ -306,51 +317,51 @@ struct caloClusterProducerTask { continue; } - e = Nonlinearity(e); + e = nonlinearity(e); mom.SetMag(e); float cpvdist = 99.; - const float cellSizeX = 2 * cpvMaxX / kCpvX; - const float cellSizeZ = 2 * cpvMaxZ / kCpvZ; + const float cellSizeX = 2 * kCpvMaxX / kCpvX; + const float cellSizeZ = 2 * kCpvMaxZ / kCpvZ; // look 9 CPV regions around PHOS cluster if (mod >= 2 && cpvExist) { // CPV exist in mods 2,3,4 - int phosIndex = CpvMatchIndex(mod, posX, posZ); + int phosIndex = cpvMatchIndex(mod, posX, posZ); std::vector regions; regions.push_back(phosIndex); - if (posX > -cpvMaxX + cellSizeX) { - if (posZ > -cpvMaxZ + cellSizeZ) { // bottom left + if (posX > -kCpvMaxX + cellSizeX) { + if (posZ > -kCpvMaxZ + cellSizeZ) { // bottom left regions.push_back(phosIndex - kCpvZ - 1); } regions.push_back(phosIndex - kCpvZ); - if (posZ < cpvMaxZ - cellSizeZ) { // top left + if (posZ < kCpvMaxZ - cellSizeZ) { // top left regions.push_back(phosIndex - kCpvZ + 1); } } - if (posZ > -cpvMaxZ + cellSizeZ) { // bottom + if (posZ > -kCpvMaxZ + cellSizeZ) { // bottom regions.push_back(phosIndex - 1); } - if (posZ < cpvMaxZ - cellSizeZ) { // top + if (posZ < kCpvMaxZ - cellSizeZ) { // top regions.push_back(phosIndex + 1); } - if (posX < cpvMaxX - cellSizeX) { - if (posZ > -cpvMaxZ + cellSizeZ) { // bottom right + if (posX < kCpvMaxX - cellSizeX) { + if (posZ > -kCpvMaxZ + cellSizeZ) { // bottom right regions.push_back(phosIndex + kCpvZ - 1); } regions.push_back(phosIndex + kCpvZ); - if (posZ < cpvMaxZ - cellSizeZ) { // top right + if (posZ < kCpvMaxZ - cellSizeZ) { // top right regions.push_back(phosIndex + kCpvZ + 1); } } - float sigmaX = 1. / TMath::Min(5.2, 1.111 + 0.56 * TMath::Exp(-0.031 * e * e) + 4.8 / TMath::Power(e + 0.61, 3)); // inverse sigma X - float sigmaZ = 1. / TMath::Min(3.3, 1.12 + 0.35 * TMath::Exp(-0.032 * e * e) + 0.75 / TMath::Power(e + 0.24, 3)); // inverse sigma Z + float sigmaX = 1. / std::min(5.2, 1.111 + 0.56 * std::exp(-0.031 * e * e) + 4.8 / std::pow(e + 0.61, 3)); // inverse sigma X + float sigmaZ = 1. / std::min(3.3, 1.12 + 0.35 * std::exp(-0.032 * e * e) + 0.75 / std::pow(e + 0.24, 3)); // inverse sigma Z - for (int indx : regions) { + for (const int& indx : regions) { if (indx >= 0 && indx < kCpvCells) { for (int ii = cpvPoints->mStart[indx]; ii < cpvPoints->mEnd[indx]; ii++) { auto p = cpvMatchPoints[indx][ii]; - float d = pow((p.first - posX) * sigmaX, 2) + pow((p.second - posZ) * sigmaZ, 2); + float d = std::pow((p.first - posX) * sigmaX, 2) + std::pow((p.second - posZ) * sigmaZ, 2); if (d < cpvdist) { cpvdist = d; } @@ -358,8 +369,8 @@ struct caloClusterProducerTask { } } } - if (cpvdist != 99.) { // was evaluated - cpvdist = sqrt(cpvdist); // was squared + if (cpvdist != 99.) { // was evaluated + cpvdist = std::sqrt(cpvdist); // was squared } int cpvindex = -2; // -2 no CPV in event if (cpvExist) { @@ -400,11 +411,11 @@ struct caloClusterProducerTask { } } - PROCESS_SWITCH(caloClusterProducerTask, processStandalone, "Process PHOS and CPV only", true); + PROCESS_SWITCH(CaloClusterProducer, processStandalone, "Process PHOS and CPV only", true); void processStandaloneMC(o2::aod::BCsWithTimestamps const& bcs, o2::aod::Collisions const& colls, - mcCells& cells, + McCells const& cells, o2::aod::CaloTriggers const&, o2::aod::CPVClusters const& cpvs) { @@ -417,7 +428,7 @@ struct caloClusterProducerTask { } std::map bcMap; int bcId = 0; - for (auto bc : bcs) { + for (auto const& bc : bcs) { bcMap[bc.globalBC()] = bcId; bcId++; } @@ -425,7 +436,7 @@ struct caloClusterProducerTask { // If several collisions appear in BC, choose one with largers number of contributors std::map colMap; int colId = 0; - for (auto cl : colls) { + for (auto const& cl : colls) { auto colbc = colMap.find(cl.bc_as().globalBC()); if (colbc == colMap.end()) { // single collision per BC colMap[cl.bc_as().globalBC()] = colId; @@ -443,11 +454,11 @@ struct caloClusterProducerTask { // Fill output table // calibration may be updated by CCDB fetcher - const o2::phos::BadChannelsMap* badMap = ccdb->getForTimeStamp(mBadMapPath, timestamp); - const o2::phos::CalibParams* calibParams = ccdb->getForTimeStamp(mCalibPath, timestamp); + const o2::phos::BadChannelsMap* badMap = ccdb->getForTimeStamp(badMapPath, timestamp); + const o2::phos::CalibParams* calibParams = ccdb->getForTimeStamp(calibPath, timestamp); if (!isMC && !skipL1phase) { - const std::vector* vec = ccdb->getForTimeStamp>(mL1PhasePath, timestamp); + const std::vector* vec = ccdb->getForTimeStamp>(l1phasePath, timestamp); if (vec) { clusterizerPHOS->setL1phase((*vec)[0]); } else { @@ -477,7 +488,7 @@ struct caloClusterProducerTask { o2::InteractionRecord ir; const int kPHOS = 0; o2::dataformats::MCTruthContainer cellTruth; - for (auto& c : cells) { + for (const auto& c : cells) { if (c.caloType() != kPHOS) // PHOS continue; // Fix for bug in trigger digits @@ -532,7 +543,7 @@ struct caloClusterProducerTask { // Find CPV clusters corresponding to PHOS trigger records std::vector> cpvMatchPoints[kCpvCells]; // Number of entries in each cell per TrigRecord - std::vector cpvNMatchPoints; + std::vector cpvNMatchPoints; cpvNMatchPoints.reserve(outputPHOSClusterTrigRecs.size()); int64_t curBC = -1; if (cpvs.begin() != cpvs.end()) { @@ -561,7 +572,7 @@ struct caloClusterProducerTask { if (cpvclu.amplitude() < static_cast>(cpvMinE)[static_cast(cpvclu.moduleNumber()) - 2]) { continue; } - int index = CpvMatchIndex(cpvclu.moduleNumber(), cpvclu.posX(), cpvclu.posZ()); + int index = cpvMatchIndex(cpvclu.moduleNumber(), cpvclu.posX(), cpvclu.posZ()); cpvMatchPoints[index].emplace_back(cpvclu.posX(), cpvclu.posZ()); } if (cpvNMatchPoints.size() > 0) { @@ -571,7 +582,7 @@ struct caloClusterProducerTask { } // Fill output - for (auto& cluTR : outputPHOSClusterTrigRecs) { + for (const auto& cluTR : outputPHOSClusterTrigRecs) { int firstClusterInEvent = cluTR.getFirstEntry(); int lastClusterInEvent = firstClusterInEvent + cluTR.getNumberOfObjects(); @@ -609,7 +620,7 @@ struct caloClusterProducerTask { // Correction for the depth of the shower starting point (TDR p 127) const float para = 0.925; const float parb = 6.52; - float depth = para * TMath::Log(e) + parb; + float depth = para * std::log(e) + parb; posX -= posX * depth / 460.; posZ -= (posZ - vtx.Z()) * depth / 460.; @@ -622,51 +633,51 @@ struct caloClusterProducerTask { continue; } - e = Nonlinearity(e); + e = nonlinearity(e); mom.SetMag(e); float cpvdist = 99.; - const float cellSizeX = 2 * cpvMaxX / kCpvX; - const float cellSizeZ = 2 * cpvMaxZ / kCpvZ; + const float cellSizeX = 2 * kCpvMaxX / kCpvX; + const float cellSizeZ = 2 * kCpvMaxZ / kCpvZ; // look 9 CPV regions around PHOS cluster if (mod >= 2 && cpvExist) { // CPV exist in mods 2,3,4 - int phosIndex = CpvMatchIndex(mod, posX, posZ); + int phosIndex = cpvMatchIndex(mod, posX, posZ); std::vector regions; regions.push_back(phosIndex); - if (posX > -cpvMaxX + cellSizeX) { - if (posZ > -cpvMaxZ + cellSizeZ) { // bottom left + if (posX > -kCpvMaxX + cellSizeX) { + if (posZ > -kCpvMaxZ + cellSizeZ) { // bottom left regions.push_back(phosIndex - kCpvZ - 1); } regions.push_back(phosIndex - kCpvZ); - if (posZ < cpvMaxZ - cellSizeZ) { // top left + if (posZ < kCpvMaxZ - cellSizeZ) { // top left regions.push_back(phosIndex - kCpvZ + 1); } } - if (posZ > -cpvMaxZ + cellSizeZ) { // bottom + if (posZ > -kCpvMaxZ + cellSizeZ) { // bottom regions.push_back(phosIndex - 1); } - if (posZ < cpvMaxZ - cellSizeZ) { // top + if (posZ < kCpvMaxZ - cellSizeZ) { // top regions.push_back(phosIndex + 1); } - if (posX < cpvMaxX - cellSizeX) { - if (posZ > -cpvMaxZ + cellSizeZ) { // bottom right + if (posX < kCpvMaxX - cellSizeX) { + if (posZ > -kCpvMaxZ + cellSizeZ) { // bottom right regions.push_back(phosIndex + kCpvZ - 1); } regions.push_back(phosIndex + kCpvZ); - if (posZ < cpvMaxZ - cellSizeZ) { // top right + if (posZ < kCpvMaxZ - cellSizeZ) { // top right regions.push_back(phosIndex + kCpvZ + 1); } } - float sigmaX = 1. / TMath::Min(5.2, 1.111 + 0.56 * TMath::Exp(-0.031 * e * e) + 4.8 / TMath::Power(e + 0.61, 3)); // inverse sigma X - float sigmaZ = 1. / TMath::Min(3.3, 1.12 + 0.35 * TMath::Exp(-0.032 * e * e) + 0.75 / TMath::Power(e + 0.24, 3)); // inverse sigma Z + float sigmaX = 1. / std::min(5.2, 1.111 + 0.56 * std::exp(-0.031 * e * e) + 4.8 / std::pow(e + 0.61, 3)); // inverse sigma X + float sigmaZ = 1. / std::min(3.3, 1.12 + 0.35 * std::exp(-0.032 * e * e) + 0.75 / std::pow(e + 0.24, 3)); // inverse sigma Z - for (int indx : regions) { + for (const int& indx : regions) { if (indx >= 0 && indx < kCpvCells) { for (int ii = cpvPoints->mStart[indx]; ii < cpvPoints->mEnd[indx]; ii++) { auto p = cpvMatchPoints[indx][ii]; - float d = pow((p.first - posX) * sigmaX, 2) + pow((p.second - posZ) * sigmaZ, 2); + float d = std::pow((p.first - posX) * sigmaX, 2) + std::pow((p.second - posZ) * sigmaZ, 2); if (d < cpvdist) { cpvdist = d; } @@ -674,8 +685,8 @@ struct caloClusterProducerTask { } } } - if (cpvdist != 99.) { // was evaluated - cpvdist = sqrt(cpvdist); // was squared + if (cpvdist != 99.) { // was evaluated + cpvdist = std::sqrt(cpvdist); // was squared } int cpvindex = -2; // -2 no CPV in event if (cpvExist) { @@ -689,7 +700,7 @@ struct caloClusterProducerTask { mclabels.clear(); mcamplitudes.clear(); gsl::span spDigList = outputTruthCont.getLabels(i); - for (auto cellLab : spDigList) { + for (const auto& cellLab : spDigList) { mclabels.push_back(cellLab.getTrackID()); // Track ID in current event? mcamplitudes.push_back(cellLab.getEdep()); } @@ -730,7 +741,7 @@ struct caloClusterProducerTask { } } - PROCESS_SWITCH(caloClusterProducerTask, processStandaloneMC, "Process MC, PHOS and CPV only", true); + PROCESS_SWITCH(CaloClusterProducer, processStandaloneMC, "Process MC, PHOS and CPV only", false); //------------------------------------------------------------ void processFull(o2::aod::BCsWithTimestamps const& bcs, @@ -760,7 +771,7 @@ struct caloClusterProducerTask { std::map bcMap; int bcId = 0; - for (auto bc : bcs) { + for (const auto& bc : bcs) { bcMap[bc.globalBC()] = bcId; bcId++; } @@ -768,7 +779,7 @@ struct caloClusterProducerTask { // If several collisions appear in BC, choose one with largers number of contributors std::map colMap; int colId = 0; - for (auto cl : colls) { + for (const auto& cl : colls) { auto colbc = colMap.find(cl.bc_as().globalBC()); if (colbc == colMap.end()) { // single collision per BC colMap[cl.bc_as().globalBC()] = colId; @@ -785,11 +796,11 @@ struct caloClusterProducerTask { // Fill output table // calibration may be updated by CCDB fetcher - const o2::phos::BadChannelsMap* badMap = ccdb->getForTimeStamp(mBadMapPath, timestamp); - const o2::phos::CalibParams* calibParams = ccdb->getForTimeStamp(mCalibPath, timestamp); + const o2::phos::BadChannelsMap* badMap = ccdb->getForTimeStamp(badMapPath, timestamp); + const o2::phos::CalibParams* calibParams = ccdb->getForTimeStamp(calibPath, timestamp); if (!isMC && !skipL1phase) { - const std::vector* vec = ccdb->getForTimeStamp>(mL1PhasePath, timestamp); + const std::vector* vec = ccdb->getForTimeStamp>(l1phasePath, timestamp); if (vec) { clusterizerPHOS->setL1phase((*vec)[0]); } else { @@ -818,7 +829,7 @@ struct caloClusterProducerTask { o2::InteractionRecord ir; const int kPHOS = 0; - for (auto& c : cells) { + for (const auto& c : cells) { if (c.caloType() != kPHOS) // PHOS continue; // Fix for bug in trigger digits @@ -852,7 +863,7 @@ struct caloClusterProducerTask { // Find CPV clusters corresponding to PHOS trigger records std::vector> cpvMatchPoints[kCpvCells]; // Number of entries in each cell per TrigRecord - std::vector cpvNMatchPoints; + std::vector cpvNMatchPoints; cpvNMatchPoints.reserve(outputPHOSClusterTrigRecs.size()); int64_t curBC = -1; @@ -881,7 +892,7 @@ struct caloClusterProducerTask { if (cpvclu.amplitude() < static_cast>(cpvMinE)[static_cast(cpvclu.moduleNumber()) - 2]) { continue; } - int index = CpvMatchIndex(cpvclu.moduleNumber(), cpvclu.posX(), cpvclu.posZ()); + int index = cpvMatchIndex(cpvclu.moduleNumber(), cpvclu.posX(), cpvclu.posZ()); cpvMatchPoints[index].emplace_back(cpvclu.posX(), cpvclu.posZ()); } if (cpvNMatchPoints.size()) { @@ -890,9 +901,9 @@ struct caloClusterProducerTask { } } // same for tracks - std::vector trackMatchPoints[kCpvCells]; // tracks hit in grid/cell in PHOS + std::vector trackMatchPoints[kCpvCells]; // tracks hit in grid/cell in PHOS // Number of entries in each cell per TrigRecord - std::vector trackNMatchPoints; + std::vector trackNMatchPoints; trackNMatchPoints.reserve(outputPHOSClusterTrigRecs.size()); curBC = 0; @@ -903,7 +914,7 @@ struct caloClusterProducerTask { } } bool keepBC = false; - for (auto& cluTR : outputPHOSClusterTrigRecs) { + for (const auto& cluTR : outputPHOSClusterTrigRecs) { if (cluTR.getBCData().toLong() == curBC) { keepBC = true; break; @@ -930,7 +941,7 @@ struct caloClusterProducerTask { curBC = track.collision().bc_as().globalBC(); } keepBC = false; - for (auto& cluTR : outputPHOSClusterTrigRecs) { + for (const auto& cluTR : outputPHOSClusterTrigRecs) { if (cluTR.getBCData().toLong() == curBC) { keepBC = true; break; @@ -954,7 +965,7 @@ struct caloClusterProducerTask { float trackX, trackZ; auto trackPar = getTrackPar(track); if (impactOnPHOS(trackPar, track.trackEtaEmcal(), track.trackPhiEmcal(), track.collision().posZ(), module, trackX, trackZ)) { - int index = CpvMatchIndex(module, trackX, trackZ); + int index = cpvMatchIndex(module, trackX, trackZ); trackMatchPoints[index].emplace_back(trackX, trackZ, track.globalIndex()); } } @@ -965,7 +976,7 @@ struct caloClusterProducerTask { } // Fill output tables - for (auto& cluTR : outputPHOSClusterTrigRecs) { + for (const auto& cluTR : outputPHOSClusterTrigRecs) { int firstClusterInEvent = cluTR.getFirstEntry(); int lastClusterInEvent = firstClusterInEvent + cluTR.getNumberOfObjects(); @@ -1012,7 +1023,7 @@ struct caloClusterProducerTask { // Correction for the depth of the shower starting point (TDR p 127) const float para = 0.925; const float parb = 6.52; - float depth = para * TMath::Log(e) + parb; + float depth = para * std::log(e) + parb; posX -= posX * depth / 460.; posZ -= (posZ - vtx.Z()) * depth / 460.; @@ -1025,53 +1036,53 @@ struct caloClusterProducerTask { continue; } - e = Nonlinearity(e); + e = nonlinearity(e); mom.SetMag(e); // CPV and track match - const float cellSizeX = 2 * cpvMaxX / kCpvX; - const float cellSizeZ = 2 * cpvMaxZ / kCpvZ; + const float cellSizeX = 2 * kCpvMaxX / kCpvX; + const float cellSizeZ = 2 * kCpvMaxZ / kCpvZ; // look 9 CPV regions around PHOS cluster - int phosIndex = CpvMatchIndex(mod, posX, posZ); + int phosIndex = cpvMatchIndex(mod, posX, posZ); std::vector regions; regions.push_back(phosIndex); - if (posX > -cpvMaxX + cellSizeX) { - if (posZ > -cpvMaxZ + cellSizeZ) { // bottom left + if (posX > -kCpvMaxX + cellSizeX) { + if (posZ > -kCpvMaxZ + cellSizeZ) { // bottom left regions.push_back(phosIndex - kCpvZ - 1); } regions.push_back(phosIndex - kCpvZ); - if (posZ < cpvMaxZ - cellSizeZ) { // top left + if (posZ < kCpvMaxZ - cellSizeZ) { // top left regions.push_back(phosIndex - kCpvZ + 1); } } - if (posZ > -cpvMaxZ + cellSizeZ) { // bottom + if (posZ > -kCpvMaxZ + cellSizeZ) { // bottom regions.push_back(phosIndex - 1); } - if (posZ < cpvMaxZ - cellSizeZ) { // top + if (posZ < kCpvMaxZ - cellSizeZ) { // top regions.push_back(phosIndex + 1); } - if (posX < cpvMaxX - cellSizeX) { - if (posZ > -cpvMaxZ + cellSizeZ) { // bottom right + if (posX < kCpvMaxX - cellSizeX) { + if (posZ > -kCpvMaxZ + cellSizeZ) { // bottom right regions.push_back(phosIndex + kCpvZ - 1); } regions.push_back(phosIndex + kCpvZ); - if (posZ < cpvMaxZ - cellSizeZ) { // top right + if (posZ < kCpvMaxZ - cellSizeZ) { // top right regions.push_back(phosIndex + kCpvZ + 1); } } - float sigmaX = 1. / TMath::Min(5.2, 1.111 + 0.56 * TMath::Exp(-0.031 * e * e) + 4.8 / TMath::Power(e + 0.61, 3)); // inverse sigma X - float sigmaZ = 1. / TMath::Min(3.3, 1.12 + 0.35 * TMath::Exp(-0.032 * e * e) + 0.75 / TMath::Power(e + 0.24, 3)); // inverse sigma Z + float sigmaX = 1. / std::min(5.2, 1.111 + 0.56 * std::exp(-0.031 * e * e) + 4.8 / std::pow(e + 0.61, 3)); // inverse sigma X + float sigmaZ = 1. / std::min(3.3, 1.12 + 0.35 * std::exp(-0.032 * e * e) + 0.75 / std::pow(e + 0.24, 3)); // inverse sigma Z float cpvdist = 99., trackdist = 99.; // float cpvDx = 0., cpvDz = 0.; float trackDx = 9999., trackDz = 9999.; int trackindex = -1; - for (int indx : regions) { + for (const int& indx : regions) { if (cpvPoints != cpvNMatchPoints.end()) { if (indx >= 0 && indx < kCpvCells) { for (int ii = cpvPoints->mStart[indx]; ii < cpvPoints->mEnd[indx]; ii++) { auto p = cpvMatchPoints[indx][ii]; - float d = pow((p.first - posX) * sigmaX, 2) + pow((p.second - posZ) * sigmaZ, 2); + float d = std::pow((p.first - posX) * sigmaX, 2) + std::pow((p.second - posZ) * sigmaZ, 2); if (d < cpvdist) { cpvdist = d; } @@ -1083,7 +1094,7 @@ struct caloClusterProducerTask { if (trackPoints != trackNMatchPoints.end()) { for (int ii = trackPoints->mStart[indx]; ii < trackPoints->mEnd[indx]; ii++) { auto pp = trackMatchPoints[indx][ii]; - float d = pow((pp.pX - posX) * sigmaX, 2) + pow((pp.pZ - posZ) * sigmaZ, 2); // TODO different sigma for tracks + float d = std::pow((pp.pX - posX) * sigmaX, 2) + std::pow((pp.pZ - posZ) * sigmaZ, 2); // TODO different sigma for tracks if (d < trackdist) { trackdist = d; trackDx = pp.pX - posX; @@ -1094,11 +1105,11 @@ struct caloClusterProducerTask { } } - if (cpvdist != 99.) { // was evaluated - cpvdist = sqrt(cpvdist); // was squared + if (cpvdist != 99.) { // was evaluated + cpvdist = std::sqrt(cpvdist); // was squared } - if (trackdist != 99.) { // was evaluated - trackdist = sqrt(trackdist); // was squared + if (trackdist != 99.) { // was evaluated + trackdist = std::sqrt(trackdist); // was squared } float lambdaShort = 0., lambdaLong = 0.; @@ -1140,12 +1151,12 @@ struct caloClusterProducerTask { } } - PROCESS_SWITCH(caloClusterProducerTask, processFull, "Process with track matching", false); + PROCESS_SWITCH(CaloClusterProducer, processFull, "Process with track matching", false); //------------------------------------------------------------ void processFullMC(o2::aod::BCsWithTimestamps const& bcs, o2::aod::Collisions const& colls, - mcCells& cells, + McCells const& cells, o2::aod::CaloTriggers const&, o2::aod::CPVClusters const& cpvs, o2::aod::FullTracks const& tracks) @@ -1169,7 +1180,7 @@ struct caloClusterProducerTask { std::map bcMap; int bcId = 0; - for (auto bc : bcs) { + for (const auto& bc : bcs) { bcMap[bc.globalBC()] = bcId; bcId++; } @@ -1177,7 +1188,7 @@ struct caloClusterProducerTask { // If several collisions appear in BC, choose one with largers number of contributors std::map colMap; int colId = 0; - for (auto cl : colls) { + for (const auto& cl : colls) { auto colbc = colMap.find(cl.bc_as().globalBC()); if (colbc == colMap.end()) { // single collision per BC colMap[cl.bc_as().globalBC()] = colId; @@ -1194,11 +1205,11 @@ struct caloClusterProducerTask { // Fill output table // calibration may be updated by CCDB fetcher - const o2::phos::BadChannelsMap* badMap = ccdb->getForTimeStamp(mBadMapPath, timestamp); - const o2::phos::CalibParams* calibParams = ccdb->getForTimeStamp(mCalibPath, timestamp); + const o2::phos::BadChannelsMap* badMap = ccdb->getForTimeStamp(badMapPath, timestamp); + const o2::phos::CalibParams* calibParams = ccdb->getForTimeStamp(calibPath, timestamp); if (!isMC && !skipL1phase) { - const std::vector* vec = ccdb->getForTimeStamp>(mL1PhasePath, timestamp); + const std::vector* vec = ccdb->getForTimeStamp>(l1phasePath, timestamp); if (vec) { clusterizerPHOS->setL1phase((*vec)[0]); } else { @@ -1228,7 +1239,7 @@ struct caloClusterProducerTask { o2::InteractionRecord ir; const int kPHOS = 0; - for (auto& c : cells) { + for (const auto& c : cells) { if (c.caloType() != kPHOS) // PHOS continue; // Fix for bug in trigger digits @@ -1283,7 +1294,7 @@ struct caloClusterProducerTask { // Find CPV clusters corresponding to PHOS trigger records std::vector> cpvMatchPoints[kCpvCells]; // Number of entries in each cell per TrigRecord - std::vector cpvNMatchPoints; + std::vector cpvNMatchPoints; cpvNMatchPoints.reserve(outputPHOSClusterTrigRecs.size()); int64_t curBC = -1; @@ -1312,7 +1323,7 @@ struct caloClusterProducerTask { if (cpvclu.amplitude() < static_cast>(cpvMinE)[static_cast(cpvclu.moduleNumber()) - 2]) { continue; } - int index = CpvMatchIndex(cpvclu.moduleNumber(), cpvclu.posX(), cpvclu.posZ()); + int index = cpvMatchIndex(cpvclu.moduleNumber(), cpvclu.posX(), cpvclu.posZ()); cpvMatchPoints[index].emplace_back(cpvclu.posX(), cpvclu.posZ()); } if (cpvNMatchPoints.size()) { @@ -1321,9 +1332,9 @@ struct caloClusterProducerTask { } } // same for tracks - std::vector trackMatchPoints[kCpvCells]; // tracks hit in grid/cell in PHOS + std::vector trackMatchPoints[kCpvCells]; // tracks hit in grid/cell in PHOS // Number of entries in each cell per TrigRecord - std::vector trackNMatchPoints; + std::vector trackNMatchPoints; trackNMatchPoints.reserve(outputPHOSClusterTrigRecs.size()); curBC = -1; @@ -1334,7 +1345,7 @@ struct caloClusterProducerTask { } } bool keepBC = false; - for (auto& cluTR : outputPHOSClusterTrigRecs) { + for (const auto& cluTR : outputPHOSClusterTrigRecs) { if (cluTR.getBCData().toLong() == curBC) { keepBC = true; break; @@ -1361,7 +1372,7 @@ struct caloClusterProducerTask { curBC = track.collision().bc_as().globalBC(); } keepBC = false; - for (auto& cluTR : outputPHOSClusterTrigRecs) { + for (const auto& cluTR : outputPHOSClusterTrigRecs) { if (cluTR.getBCData().toLong() == curBC) { keepBC = true; break; @@ -1385,7 +1396,7 @@ struct caloClusterProducerTask { float trackX, trackZ; auto trackPar = getTrackPar(track); if (impactOnPHOS(trackPar, track.trackEtaEmcal(), track.trackPhiEmcal(), track.collision().posZ(), module, trackX, trackZ)) { - int index = CpvMatchIndex(module, trackX, trackZ); + int index = cpvMatchIndex(module, trackX, trackZ); trackMatchPoints[index].emplace_back(trackX, trackZ, track.globalIndex()); } } @@ -1396,7 +1407,7 @@ struct caloClusterProducerTask { } // Fill output tables - for (auto& cluTR : outputPHOSClusterTrigRecs) { + for (const auto& cluTR : outputPHOSClusterTrigRecs) { int firstClusterInEvent = cluTR.getFirstEntry(); int lastClusterInEvent = firstClusterInEvent + cluTR.getNumberOfObjects(); @@ -1442,7 +1453,7 @@ struct caloClusterProducerTask { // Correction for the depth of the shower starting point (TDR p 127) const float para = 0.925; const float parb = 6.52; - float depth = para * TMath::Log(e) + parb; + float depth = para * std::log(e) + parb; posX -= posX * depth / 460.; posZ -= (posZ - vtx.Z()) * depth / 460.; @@ -1455,52 +1466,52 @@ struct caloClusterProducerTask { continue; } - e = Nonlinearity(e); + e = nonlinearity(e); mom.SetMag(e); // CPV and track match - const float cellSizeX = 2 * cpvMaxX / kCpvX; - const float cellSizeZ = 2 * cpvMaxZ / kCpvZ; + const float cellSizeX = 2 * kCpvMaxX / kCpvX; + const float cellSizeZ = 2 * kCpvMaxZ / kCpvZ; // look 9 CPV regions around PHOS cluster - int phosIndex = CpvMatchIndex(mod, posX, posZ); + int phosIndex = cpvMatchIndex(mod, posX, posZ); std::vector regions; regions.push_back(phosIndex); - if (posX > -cpvMaxX + cellSizeX) { - if (posZ > -cpvMaxZ + cellSizeZ) { // bottom left + if (posX > -kCpvMaxX + cellSizeX) { + if (posZ > -kCpvMaxZ + cellSizeZ) { // bottom left regions.push_back(phosIndex - kCpvZ - 1); } regions.push_back(phosIndex - kCpvZ); - if (posZ < cpvMaxZ - cellSizeZ) { // top left + if (posZ < kCpvMaxZ - cellSizeZ) { // top left regions.push_back(phosIndex - kCpvZ + 1); } } - if (posZ > -cpvMaxZ + cellSizeZ) { // bottom + if (posZ > -kCpvMaxZ + cellSizeZ) { // bottom regions.push_back(phosIndex - 1); } - if (posZ < cpvMaxZ - cellSizeZ) { // top + if (posZ < kCpvMaxZ - cellSizeZ) { // top regions.push_back(phosIndex + 1); } - if (posX < cpvMaxX - cellSizeX) { - if (posZ > -cpvMaxZ + cellSizeZ) { // bottom right + if (posX < kCpvMaxX - cellSizeX) { + if (posZ > -kCpvMaxZ + cellSizeZ) { // bottom right regions.push_back(phosIndex + kCpvZ - 1); } regions.push_back(phosIndex + kCpvZ); - if (posZ < cpvMaxZ - cellSizeZ) { // top right + if (posZ < kCpvMaxZ - cellSizeZ) { // top right regions.push_back(phosIndex + kCpvZ + 1); } } - float sigmaX = 1. / TMath::Min(5.2, 1.111 + 0.56 * TMath::Exp(-0.031 * e * e) + 4.8 / TMath::Power(e + 0.61, 3)); // inverse sigma X - float sigmaZ = 1. / TMath::Min(3.3, 1.12 + 0.35 * TMath::Exp(-0.032 * e * e) + 0.75 / TMath::Power(e + 0.24, 3)); // inverse sigma Z + float sigmaX = 1. / std::min(5.2, 1.111 + 0.56 * std::exp(-0.031 * e * e) + 4.8 / std::pow(e + 0.61, 3)); // inverse sigma X + float sigmaZ = 1. / std::min(3.3, 1.12 + 0.35 * std::exp(-0.032 * e * e) + 0.75 / std::pow(e + 0.24, 3)); // inverse sigma Z float cpvdist = 99., trackdist = 99.; // float cpvDx = 0., cpvDz = 0.; float trackDx = 9999., trackDz = 9999.; int trackindex = -1; - for (int indx : regions) { + for (const int& indx : regions) { if (cpvPoints != cpvNMatchPoints.end()) { if (indx >= 0 && indx < kCpvCells) { for (int ii = cpvPoints->mStart[indx]; ii < cpvPoints->mEnd[indx]; ii++) { auto p = cpvMatchPoints[indx][ii]; - float d = pow((p.first - posX) * sigmaX, 2) + pow((p.second - posZ) * sigmaZ, 2); + float d = std::pow((p.first - posX) * sigmaX, 2) + std::pow((p.second - posZ) * sigmaZ, 2); if (d < cpvdist) { cpvdist = d; } @@ -1511,7 +1522,7 @@ struct caloClusterProducerTask { if (trackPoints != trackNMatchPoints.end()) { for (int ii = trackPoints->mStart[indx]; ii < trackPoints->mEnd[indx]; ii++) { auto pp = trackMatchPoints[indx][ii]; - float d = pow((pp.pX - posX) * sigmaX, 2) + pow((pp.pZ - posZ) * sigmaZ, 2); // TODO different sigma for tracks + float d = std::pow((pp.pX - posX) * sigmaX, 2) + std::pow((pp.pZ - posZ) * sigmaZ, 2); // TODO different sigma for tracks if (d < trackdist) { trackdist = d; trackDx = pp.pX - posX; @@ -1522,11 +1533,11 @@ struct caloClusterProducerTask { } } - if (cpvdist != 99.) { // was evaluated - cpvdist = sqrt(cpvdist); // was squared + if (cpvdist != 99.) { // was evaluated + cpvdist = std::sqrt(cpvdist); // was squared } - if (trackdist != 99.) { // was evaluated - trackdist = sqrt(trackdist); // was squared + if (trackdist != 99.) { // was evaluated + trackdist = std::sqrt(trackdist); // was squared } float lambdaShort = 0., lambdaLong = 0.; @@ -1540,7 +1551,7 @@ struct caloClusterProducerTask { mclabels.clear(); mcamplitudes.clear(); gsl::span spDigList = outputTruthCont.getLabels(i); - for (auto cellLab : spDigList) { + for (const auto& cellLab : spDigList) { mclabels.push_back(cellLab.getTrackID()); // Track ID in current event? mcamplitudes.push_back(cellLab.getEdep()); } @@ -1581,17 +1592,17 @@ struct caloClusterProducerTask { } } - PROCESS_SWITCH(caloClusterProducerTask, processFullMC, "Process MC with track matching", false); + PROCESS_SWITCH(CaloClusterProducer, processFullMC, "Process MC with track matching", false); - int CpvMatchIndex(int16_t module, float x, float z) + int cpvMatchIndex(int16_t module, float x, float z) { // calculate cell index in grid over PHOS detector - const float cellSizeX = 2 * cpvMaxX / kCpvX; - const float cellSizeZ = 2 * cpvMaxZ / kCpvZ; + const float cellSizeX = 2 * kCpvMaxX / kCpvX; + const float cellSizeZ = 2 * kCpvMaxZ / kCpvZ; // in track matching tracks can be beyond CPV surface // assign these tracks to the closest cell - int ix = std::max(0, static_cast((x + cpvMaxX) / cellSizeX)); - int iz = std::max(0, static_cast((z + cpvMaxZ) / cellSizeZ)); + int ix = std::max(0, static_cast((x + kCpvMaxX) / cellSizeX)); + int iz = std::max(0, static_cast((z + kCpvMaxZ) / cellSizeZ)); if (ix >= kCpvX) { ix = kCpvX - 1; } @@ -1612,17 +1623,12 @@ struct caloClusterProducerTask { const float etaMax = 0.178266; double bz = o2::base::Propagator::Instance()->getNominalBz(); // magnetic field - if (trackPhi < phiMin || trackPhi > phiMax || abs(trackEta) > etaMax) { // do not match even approximately + trackPhi = RecoDecay::constrainAngle(trackPhi, 0., 1); // constrain angle to range 0,twoPi + if (trackPhi < phiMin || trackPhi > phiMax || std::abs(trackEta) > etaMax) { // do not match even approximately return false; } const float dphi = 20. * 0.017453293; - if (trackPhi < 0.) { - trackPhi += TMath::TwoPi(); - } - if (trackPhi > TMath::TwoPi()) { - trackPhi -= TMath::TwoPi(); - } module = 1 + static_cast((trackPhi - phiMin) / dphi); if (module < 1) { module = 1; @@ -1632,11 +1638,11 @@ struct caloClusterProducerTask { } // get PHOS radius - constexpr float shiftY = -1.26; // Depth-optimized + const double shiftY = -1.26; // Depth-optimized double posL[3] = {0., 0., shiftY}; // local position at the center of module double posG[3] = {0}; geomPHOS->getAlignmentMatrix(module)->LocalToMaster(posL, posG); - double rPHOS = sqrt(posG[0] * posG[0] + posG[1] * posG[1]); + double rPHOS = std::sqrt(posG[0] * posG[0] + posG[1] * posG[1]); double alpha = (230. + 20. * module) * 0.017453293; // During main reconstruction track was propagated to radius 460 cm with accounting material @@ -1661,7 +1667,7 @@ struct caloClusterProducerTask { return false; } alpha = trackPar.getAlpha(); - double ca = cos(alpha), sa = sin(alpha); + double ca = std::cos(alpha), sa = std::sin(alpha); posG[0] = trackPar.getX() * ca - trackPar.getY() * sa; posG[1] = trackPar.getY() * ca + trackPar.getX() * sa; posG[2] = trackPar.getZ(); @@ -1670,7 +1676,7 @@ struct caloClusterProducerTask { trackX = posL[0]; trackZ = posL[1]; // If trackX beyond the module, switch to the next one - if (abs(trackX) < xmax || (trackX < -xmax && module == 1) || (trackX > xmax && module == 4)) { + if (std::abs(trackX) < xmax || (trackX < -xmax && module == 1) || (trackX > xmax && module == 4)) { return true; } // re-do extrapolation to correct module @@ -1687,7 +1693,7 @@ struct caloClusterProducerTask { posL[1] = 0.; posL[2] = shiftY; // local position at the center of module geomPHOS->getAlignmentMatrix(module)->LocalToMaster(posL, posG); - rPHOS = sqrt(posG[0] * posG[0] + posG[1] * posG[1]); + rPHOS = std::sqrt(posG[0] * posG[0] + posG[1] * posG[1]); if (!trackPar.rotate(alpha) || !prop->PropagateToXBxByBz(trackPar, xtrg, 0.95, 10, o2::base::Propagator::MatCorrType::USEMatCorrNONE)) { @@ -1703,8 +1709,8 @@ struct caloClusterProducerTask { return false; } alpha = trackPar.getAlpha(); - ca = cos(alpha); - sa = sin(alpha); + ca = std::cos(alpha); + sa = std::sin(alpha); posG[0] = trackPar.getX() * ca - trackPar.getY() * sa; posG[1] = trackPar.getY() * ca + trackPar.getX() * sa; posG[2] = trackPar.getZ(); @@ -1715,13 +1721,38 @@ struct caloClusterProducerTask { return true; } - float Nonlinearity(float en) + float nonlinearity(float en) { // Correct for non-linearity - switch (mNonlinType) { + switch (nonlinType) { case 0: return en; - case 1: { + case 1: { // Data Run3 + const double a = 0.885621; + const double b = 0.003864; + const double c = 0.143948; + const double d = -0.034200; + const double f = -0.038992; + const double g = 0.436003; + const double h = 0.642263; + const double k = 0.000523; + double eMin = std::max(static_cast(0.25), en); // Parameterization valid down to 250 MeV + return en * (a + b * eMin + c / eMin + d / (eMin * eMin) + f / ((eMin - g) * (eMin - g) + h * h) + k / std::pow(eMin, 4)); + } + case 2: { // MC + const double a = 1.2428430; + const double b = -0.0001866; + const double c = -0.0299751; + const double d = -0.0003103; + const double f = 0.4053021; + const double g = -0.139670; + const double h = 1.909846; + const double k = 0.00028866050; + + double eMin = std::max(static_cast(0.25), en); // Parameterization valid down to 250 MeV + return en * (a + b * eMin + c / eMin + d / (eMin * eMin) + f / ((eMin - g) * (eMin - g) + h * h) + k / std::pow(eMin, 4)); + } + case 3: { // Obsolete data Run3 const double a = 9.34913e-01; const double b = 2.33e-03; const double c = -8.10e-05; @@ -1743,5 +1774,5 @@ struct caloClusterProducerTask { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/Common/TableProducer/centralityTable.cxx b/Common/TableProducer/centralityTable.cxx index 3631abe9fdf..48f1598afc5 100644 --- a/Common/TableProducer/centralityTable.cxx +++ b/Common/TableProducer/centralityTable.cxx @@ -8,9 +8,17 @@ // 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 centrality.cxx +// +/// \file centralityTable.cxx /// \brief Task to produce the centrality tables associated to each of the required centrality estimators +/// +/// \author ALICE +// + +#include +#include +#include +#include #include #include @@ -19,13 +27,19 @@ #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/RunningWorkflowInfo.h" +#include "Framework/HistogramRegistry.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "MetadataHelper.h" #include "TableHelper.h" +#include "TList.h" using namespace o2; using namespace o2::framework; +MetadataHelper metadataInfo; // Metadata helper + static constexpr int kCentRun2V0Ms = 0; static constexpr int kCentRun2V0As = 1; static constexpr int kCentRun2SPDTrks = 2; @@ -36,10 +50,13 @@ static constexpr int kCentFV0As = 6; static constexpr int kCentFT0Ms = 7; static constexpr int kCentFT0As = 8; static constexpr int kCentFT0Cs = 9; -static constexpr int kCentFDDMs = 10; -static constexpr int kCentNTPVs = 11; -static constexpr int nTables = 12; -static constexpr int nParameters = 1; +static constexpr int kCentFT0CVariant1s = 10; +static constexpr int kCentFDDMs = 11; +static constexpr int kCentNTPVs = 12; +static constexpr int kCentNGlobals = 13; +static constexpr int kCentMFTs = 14; +static constexpr int NTables = 15; +static constexpr int NParameters = 1; static const std::vector tableNames{"CentRun2V0Ms", "CentRun2V0As", "CentRun2SPDTrks", @@ -50,10 +67,13 @@ static const std::vector tableNames{"CentRun2V0Ms", "CentFT0Ms", "CentFT0As", "CentFT0Cs", + "CentFT0CVariant1s", "CentFDDMs", - "CentNTPVs"}; + "CentNTPVs", + "CentNGlobals", + "CentMFTs"}; static const std::vector parameterNames{"Enable"}; -static const int defaultParameters[nTables][nParameters]{{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}}; +static const int defaultParameters[NTables][NParameters]{{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}}; struct CentralityTable { Produces centRun2V0M; @@ -66,20 +86,29 @@ struct CentralityTable { Produces centFT0M; Produces centFT0A; Produces centFT0C; + Produces centFT0CVariant1; Produces centFDDM; Produces centNTPV; + Produces centNGlobals; + Produces centMFTs; Service ccdb; Configurable> enabledTables{"enabledTables", - {defaultParameters[0], nTables, nParameters, tableNames, parameterNames}, + {defaultParameters[0], NTables, NParameters, tableNames, parameterNames}, "Produce tables depending on needs. Values different than -1 override the automatic setup: the corresponding table can be set off (0) or on (1)"}; - Configurable ccdbUrl{"ccdburl", "http://alice-ccdb.cern.ch", "The CCDB endpoint url address"}; - Configurable ccdbPath{"ccdbpath", "Centrality/Estimators", "The CCDB path for centrality/multiplicity information"}; - Configurable genName{"genname", "", "Genearator name: HIJING, PYTHIA8, ... Default: \"\""}; - Configurable doNotCrashOnNull{"doNotCrashOnNull", false, {"Option to not crash on null and instead fill required tables with dummy info"}}; + struct : ConfigurableGroup { + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "The CCDB endpoint url address"}; + Configurable ccdbPath{"ccdbPath", "Centrality/Estimators", "The CCDB path for centrality/multiplicity information"}; + Configurable genName{"genName", "", "Genearator name: HIJING, PYTHIA8, ... Default: \"\""}; + Configurable doNotCrashOnNull{"doNotCrashOnNull", false, {"Option to not crash on null and instead fill required tables with dummy info"}}; + Configurable reconstructionPass{"reconstructionPass", "", {"Apass to use when fetching the calibration tables. Empty (default) does not check for any pass. Use `metadata` to fetch it from the AO2D metadata. Otherwise it will override the metadata."}}; + } ccdbConfig; + Configurable embedINELgtZEROselection{"embedINELgtZEROselection", false, {"Option to do percentile 100.5 if not INELgtZERO"}}; + Configurable produceHistograms{"produceHistograms", false, {"Option to produce debug histograms"}}; + ConfigurableAxis binsPercentile{"binsPercentile", {VARIABLE_WIDTH, 0, 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, 0.01, 0.011, 0.012, 0.013, 0.014, 0.015, 0.016, 0.017, 0.018, 0.019, 0.02, 0.021, 0.022, 0.023, 0.024, 0.025, 0.026, 0.027, 0.028, 0.029, 0.03, 0.031, 0.032, 0.033, 0.034, 0.035, 0.036, 0.037, 0.038, 0.039, 0.04, 0.041, 0.042, 0.043, 0.044, 0.045, 0.046, 0.047, 0.048, 0.049, 0.05, 0.051, 0.052, 0.053, 0.054, 0.055, 0.056, 0.057, 0.058, 0.059, 0.06, 0.061, 0.062, 0.063, 0.064, 0.065, 0.066, 0.067, 0.068, 0.069, 0.07, 0.071, 0.072, 0.073, 0.074, 0.075, 0.076, 0.077, 0.078, 0.079, 0.08, 0.081, 0.082, 0.083, 0.084, 0.085, 0.086, 0.087, 0.088, 0.089, 0.09, 0.091, 0.092, 0.093, 0.094, 0.095, 0.096, 0.097, 0.098, 0.099, 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.7, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.8, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.9, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 33.0, 34.0, 35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0, 47.0, 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0, 56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 72.0, 73.0, 74.0, 75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, 88.0, 89.0, 90.0, 91.0, 92.0, 93.0, 94.0, 95.0, 96.0, 97.0, 98.0, 99.0, 100.0}, "Binning of the percentile axis"}; int mRunNumber; - struct tagRun2V0MCalibration { + struct TagRun2V0MCalibration { bool mCalibrationStored = false; TFormula* mMCScale = nullptr; float mMCScalePars[6] = {0.0}; @@ -87,39 +116,39 @@ struct CentralityTable { TH1* mhVtxAmpCorrV0C = nullptr; TH1* mhMultSelCalib = nullptr; } Run2V0MInfo; - struct tagRun2V0ACalibration { + struct TagRun2V0ACalibration { bool mCalibrationStored = false; TH1* mhVtxAmpCorrV0A = nullptr; TH1* mhMultSelCalib = nullptr; } Run2V0AInfo; - struct tagRun2SPDTrackletsCalibration { + struct TagRun2SPDTrackletsCalibration { bool mCalibrationStored = false; TH1* mhVtxAmpCorr = nullptr; TH1* mhMultSelCalib = nullptr; } Run2SPDTksInfo; - struct tagRun2SPDClustersCalibration { + struct TagRun2SPDClustersCalibration { bool mCalibrationStored = false; TH1* mhVtxAmpCorrCL0 = nullptr; TH1* mhVtxAmpCorrCL1 = nullptr; TH1* mhMultSelCalib = nullptr; } Run2SPDClsInfo; - struct tagRun2CL0Calibration { + struct TagRun2CL0Calibration { bool mCalibrationStored = false; TH1* mhVtxAmpCorr = nullptr; TH1* mhMultSelCalib = nullptr; } Run2CL0Info; - struct tagRun2CL1Calibration { + struct TagRun2CL1Calibration { bool mCalibrationStored = false; TH1* mhVtxAmpCorr = nullptr; TH1* mhMultSelCalib = nullptr; } Run2CL1Info; - struct calibrationInfo { + struct CalibrationInfo { std::string name = ""; bool mCalibrationStored = false; TH1* mhMultSelCalib = nullptr; float mMCScalePars[6] = {0.0}; TFormula* mMCScale = nullptr; - explicit calibrationInfo(std::string name) + explicit CalibrationInfo(std::string name) : name(name), mCalibrationStored(false), mhMultSelCalib(nullptr), @@ -127,15 +156,38 @@ struct CentralityTable { mMCScale(nullptr) { } + bool isSane(bool fatalize = false) + { + if (!mhMultSelCalib) { + return true; + } + for (int i = 1; i < mhMultSelCalib->GetNbinsX() + 1; i++) { + if (mhMultSelCalib->GetXaxis()->GetBinLowEdge(i) > mhMultSelCalib->GetXaxis()->GetBinUpEdge(i)) { + if (fatalize) { + LOG(fatal) << "Centrality calibration table " << name << " has bins with low edge > up edge"; + } + LOG(warning) << "Centrality calibration table " << name << " has bins with low edge > up edge"; + return false; + } + } + return true; + } }; - calibrationInfo FV0AInfo = calibrationInfo("FV0"); - calibrationInfo FT0MInfo = calibrationInfo("FT0"); - calibrationInfo FT0AInfo = calibrationInfo("FT0A"); - calibrationInfo FT0CInfo = calibrationInfo("FT0C"); - calibrationInfo FDDMInfo = calibrationInfo("FDD"); - calibrationInfo NTPVInfo = calibrationInfo("NTracksPV"); + CalibrationInfo fv0aInfo = CalibrationInfo("FV0"); + CalibrationInfo ft0mInfo = CalibrationInfo("FT0"); + CalibrationInfo ft0aInfo = CalibrationInfo("FT0A"); + CalibrationInfo ft0cInfo = CalibrationInfo("FT0C"); + CalibrationInfo ft0cVariant1Info = CalibrationInfo("FT0Cvar1"); + CalibrationInfo fddmInfo = CalibrationInfo("FDD"); + CalibrationInfo ntpvInfo = CalibrationInfo("NTracksPV"); + CalibrationInfo nGlobalInfo = CalibrationInfo("NGlobal"); + CalibrationInfo mftInfo = CalibrationInfo("MFT"); std::vector mEnabledTables; // Vector of enabled tables - std::array isTableEnabled; + std::array isTableEnabled; + + // Debug output + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + OutputObj listCalib{"calib-list", OutputObjHandlingPolicy::QAObject}; void init(InitContext& context) { @@ -143,25 +195,25 @@ struct CentralityTable { if (doprocessRun3FT0 == true) { LOG(fatal) << "FT0 only mode is automatically enabled in Run3 mode. Please disable it and enable processRun3."; } - if (doprocessRun2 == false && doprocessRun3 == false) { - LOGF(fatal, "Neither processRun2 nor processRun3 enabled. Please choose one."); + if (doprocessRun2 == false && doprocessRun3 == false && doprocessRun3Complete == false) { + LOGF(fatal, "Neither processRun2 nor processRun3 nor processRun3Complete enabled. Please choose one."); } if (doprocessRun2 == true && doprocessRun3 == true) { LOGF(fatal, "Cannot enable processRun2 and processRun3 at the same time. Please choose one."); } /* Checking the tables which are requested in the workflow and enabling them */ - for (int i = 0; i < nTables; i++) { + for (int i = 0; i < NTables; i++) { int f = enabledTables->get(tableNames[i].c_str(), "Enable"); enableFlagIfTableRequired(context, tableNames[i], f); if (f == 1) { if (tableNames[i].find("Run2") != std::string::npos) { if (doprocessRun3) { - LOGF(fatal, "Cannot enable Run2 tables in Run3 mode. Please check and disable them."); + LOG(fatal) << "Cannot enable Run2 table `" << tableNames[i] << "` while running in Run3 mode. Please check and disable them."; } } else { if (doprocessRun2) { - LOGF(fatal, "Cannot enable Run3 tables in Run2 mode. Please check and disable them."); + LOG(fatal) << "Cannot enable Run3 table `" << tableNames[i] << "` while running in Run2 mode. Please check and disable them."; } } isTableEnabled[i] = true; @@ -172,18 +224,42 @@ struct CentralityTable { if (mEnabledTables.size() == 0) { LOGF(fatal, "No table enabled. Please enable at least one table."); } + std::sort(mEnabledTables.begin(), mEnabledTables.end()); + // Check if FT0 is the only centrality needed - if (mEnabledTables.size() == 1 && mEnabledTables[kCentFT0Ms] == true) { + if (mEnabledTables.size() == 1 && isTableEnabled[kCentFT0Ms] == true) { LOG(info) << "FT0 only mode is enabled"; doprocessRun3FT0.value = true; doprocessRun3.value = false; } - ccdb->setURL(ccdbUrl); + ccdb->setURL(ccdbConfig.ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); mRunNumber = 0; + listCalib.setObject(new TList); + if (!produceHistograms.value) { + return; + } + + histos.add("FT0M/percentile", "FT0M percentile.", HistType::kTH1D, {{binsPercentile, "FT0M percentile"}}); + histos.add("FT0M/percentilevsPV", "percentile vs PV mult.", HistType::kTH2D, {{binsPercentile, "FT0M percentile"}, {100, 0, 100, "PV mult."}}); + histos.add("FT0M/MultvsPV", "FT0M mult. vs PV mult.", HistType::kTH2D, {{1000, 0, 5000, "FT0M mult."}, {100, 0, 100, "PV mult."}}); + + histos.add("FT0A/percentile", "FT0A percentile.", HistType::kTH1D, {{binsPercentile, "FT0A percentile"}}); + histos.add("FT0A/percentilevsPV", "percentile vs PV mult.", HistType::kTH2D, {{binsPercentile, "FT0A percentile"}, {100, 0, 100, "PV mult."}}); + histos.add("FT0A/MultvsPV", "FT0A mult. vs PV mult.", HistType::kTH2D, {{1000, 0, 5000, "FT0A mult."}, {100, 0, 100, "PV mult."}}); + + histos.add("FT0C/percentile", "FT0C percentile.", HistType::kTH1D, {{binsPercentile, "FT0C percentile"}}); + histos.add("FT0C/percentilevsPV", "percentile vs PV mult.", HistType::kTH2D, {{binsPercentile, "FT0C percentile"}, {100, 0, 100, "PV mult."}}); + histos.add("FT0C/MultvsPV", "FT0C mult. vs PV mult.", HistType::kTH2D, {{1000, 0, 5000, "FT0C mult."}, {100, 0, 100, "PV mult."}}); + + histos.addClone("FT0M/", "sel8FT0M/"); + histos.addClone("FT0C/", "sel8FT0C/"); + histos.addClone("FT0A/", "sel8FT0A/"); + + histos.print(); } using BCsWithTimestampsAndRun2Infos = soa::Join; @@ -193,8 +269,22 @@ struct CentralityTable { /* check the previous run number */ auto bc = collision.bc_as(); if (bc.runNumber() != mRunNumber) { + mRunNumber = bc.runNumber(); // mark that this run has been attempted already regardless of outcome LOGF(debug, "timestamp=%llu", bc.timestamp()); - TList* callst = ccdb->getForTimeStamp(ccdbPath, bc.timestamp()); + TList* callst = nullptr; + if (ccdbConfig.reconstructionPass.value == "") { + callst = ccdb->getForRun(ccdbConfig.ccdbPath, bc.runNumber()); + } else if (ccdbConfig.reconstructionPass.value == "metadata") { + std::map metadata; + metadata["RecoPassName"] = metadataInfo.get("RecoPassName"); + LOGF(info, "Loading CCDB for reconstruction pass (from metadata): %s", metadataInfo.get("RecoPassName")); + callst = ccdb->getSpecificForRun(ccdbConfig.ccdbPath, bc.runNumber(), metadata); + } else { + std::map metadata; + metadata["RecoPassName"] = ccdbConfig.reconstructionPass.value; + LOGF(info, "Loading CCDB for reconstruction pass (from provided argument): %s", ccdbConfig.reconstructionPass.value); + callst = ccdb->getSpecificForRun(ccdbConfig.ccdbPath, bc.runNumber(), metadata); + } Run2V0MInfo.mCalibrationStored = false; Run2V0AInfo.mCalibrationStored = false; @@ -216,20 +306,28 @@ struct CentralityTable { Run2V0MInfo.mhVtxAmpCorrV0A = getccdb("hVtx_fAmplitude_V0A_Normalized"); Run2V0MInfo.mhVtxAmpCorrV0C = getccdb("hVtx_fAmplitude_V0C_Normalized"); Run2V0MInfo.mhMultSelCalib = getccdb("hMultSelCalib_V0M"); - Run2V0MInfo.mMCScale = getformulaccdb(TString::Format("%s-V0M", genName->c_str()).Data()); + Run2V0MInfo.mMCScale = getformulaccdb(TString::Format("%s-V0M", ccdbConfig.genName->c_str()).Data()); if ((Run2V0MInfo.mhVtxAmpCorrV0A != nullptr) && (Run2V0MInfo.mhVtxAmpCorrV0C != nullptr) && (Run2V0MInfo.mhMultSelCalib != nullptr)) { - if (genName->length() != 0) { + if (ccdbConfig.genName->length() != 0) { if (Run2V0MInfo.mMCScale != nullptr) { for (int ixpar = 0; ixpar < 6; ++ixpar) { Run2V0MInfo.mMCScalePars[ixpar] = Run2V0MInfo.mMCScale->GetParameter(ixpar); } } else { - LOGF(fatal, "MC Scale information from V0M for run %d not available", bc.runNumber()); + if (!ccdbConfig.doNotCrashOnNull) { // default behaviour: crash + LOGF(fatal, "MC Scale information from V0M for run %d not available", bc.runNumber()); + } else { // only if asked: continue filling with non-valid values (105) + LOGF(info, "MC Scale information from V0M for run %d not available", bc.runNumber()); + } } } Run2V0MInfo.mCalibrationStored = true; } else { - LOGF(fatal, "Calibration information from V0M for run %d corrupted", bc.runNumber()); + if (!ccdbConfig.doNotCrashOnNull) { // default behaviour: crash + LOGF(fatal, "Calibration information from V0M for run %d corrupted", bc.runNumber()); + } else { // only if asked: continue filling with non-valid values (105) + LOGF(info, "Calibration information from V0M for run %d corrupted, will fill V0M tables with dummy values", bc.runNumber()); + } } } if (isTableEnabled[kCentRun2V0As]) { @@ -239,7 +337,11 @@ struct CentralityTable { if ((Run2V0AInfo.mhVtxAmpCorrV0A != nullptr) && (Run2V0AInfo.mhMultSelCalib != nullptr)) { Run2V0AInfo.mCalibrationStored = true; } else { - LOGF(fatal, "Calibration information from V0A for run %d corrupted", bc.runNumber()); + if (!ccdbConfig.doNotCrashOnNull) { // default behaviour: crash + LOGF(fatal, "Calibration information from V0A for run %d corrupted", bc.runNumber()); + } else { // only if asked: continue filling with non-valid values (105) + LOGF(info, "Calibration information from V0A for run %d corrupted, will fill V0A tables with dummy values", bc.runNumber()); + } } } if (isTableEnabled[kCentRun2SPDTrks]) { @@ -249,7 +351,11 @@ struct CentralityTable { if ((Run2SPDTksInfo.mhVtxAmpCorr != nullptr) && (Run2SPDTksInfo.mhMultSelCalib != nullptr)) { Run2SPDTksInfo.mCalibrationStored = true; } else { - LOGF(fatal, "Calibration information from SPD tracklets for run %d corrupted", bc.runNumber()); + if (!ccdbConfig.doNotCrashOnNull) { // default behaviour: crash + LOGF(fatal, "Calibration information from SPD tracklets for run %d corrupted", bc.runNumber()); + } else { // only if asked: continue filling with non-valid values (105) + LOGF(info, "Calibration information from SPD tracklets for run %d corrupted, will fill SPD tracklets tables with dummy values", bc.runNumber()); + } } } if (isTableEnabled[kCentRun2SPDClss]) { @@ -260,7 +366,11 @@ struct CentralityTable { if ((Run2SPDClsInfo.mhVtxAmpCorrCL0 != nullptr) && (Run2SPDClsInfo.mhVtxAmpCorrCL1 != nullptr) && (Run2SPDClsInfo.mhMultSelCalib != nullptr)) { Run2SPDClsInfo.mCalibrationStored = true; } else { - LOGF(fatal, "Calibration information from SPD clusters for run %d corrupted", bc.runNumber()); + if (!ccdbConfig.doNotCrashOnNull) { // default behaviour: crash + LOGF(fatal, "Calibration information from SPD clusters for run %d corrupted", bc.runNumber()); + } else { // only if asked: continue filling with non-valid values (105) + LOGF(info, "Calibration information from SPD clusters for run %d corrupted, will fill SPD clusters tables with dummy values", bc.runNumber()); + } } } if (isTableEnabled[kCentRun2CL0s]) { @@ -270,7 +380,11 @@ struct CentralityTable { if ((Run2CL0Info.mhVtxAmpCorr != nullptr) && (Run2CL0Info.mhMultSelCalib != nullptr)) { Run2CL0Info.mCalibrationStored = true; } else { - LOGF(fatal, "Calibration information from CL0 multiplicity for run %d corrupted", bc.runNumber()); + if (!ccdbConfig.doNotCrashOnNull) { // default behaviour: crash + LOGF(fatal, "Calibration information from CL0 multiplicity for run %d corrupted", bc.runNumber()); + } else { // only if asked: continue filling with non-valid values (105) + LOGF(info, "Calibration information from CL0 multiplicity for run %d corrupted, will fill CL0 multiplicity tables with dummy values", bc.runNumber()); + } } } if (isTableEnabled[kCentRun2CL1s]) { @@ -280,24 +394,24 @@ struct CentralityTable { if ((Run2CL1Info.mhVtxAmpCorr != nullptr) && (Run2CL1Info.mhMultSelCalib != nullptr)) { Run2CL1Info.mCalibrationStored = true; } else { - LOGF(fatal, "Calibration information from CL1 multiplicity for run %d corrupted", bc.runNumber()); + if (!ccdbConfig.doNotCrashOnNull) { // default behaviour: crash + LOGF(fatal, "Calibration information from CL1 multiplicity for run %d corrupted", bc.runNumber()); + } else { // only if asked: continue filling with non-valid values (105) + LOGF(info, "Calibration information from CL1 multiplicity for run %d corrupted, will fill CL1 multiplicity tables with dummy values", bc.runNumber()); + } } } - if (Run2V0MInfo.mCalibrationStored || Run2V0AInfo.mCalibrationStored || Run2SPDTksInfo.mCalibrationStored || Run2SPDClsInfo.mCalibrationStored || Run2CL0Info.mCalibrationStored || Run2CL1Info.mCalibrationStored) { - mRunNumber = bc.runNumber(); - } } else { - if (!doNotCrashOnNull) { // default behaviour: crash + if (!ccdbConfig.doNotCrashOnNull) { // default behaviour: crash LOGF(fatal, "Centrality calibration is not available in CCDB for run=%d at timestamp=%llu", bc.runNumber(), bc.timestamp()); } else { // only if asked: continue filling with non-valid values (105) LOGF(info, "Centrality calibration is not available in CCDB for run=%d at timestamp=%llu, will fill tables with dummy values", bc.runNumber(), bc.timestamp()); - mRunNumber = bc.runNumber(); } } } auto scaleMC = [](float x, float pars[6]) { - return pow(((pars[0] + pars[1] * pow(x, pars[2])) - pars[3]) / pars[4], 1.0f / pars[5]); + return std::pow(((pars[0] + pars[1] * std::pow(x, pars[2])) - pars[3]) / pars[4], 1.0f / pars[5]); }; if (isTableEnabled[kCentRun2V0Ms]) { @@ -372,6 +486,8 @@ struct CentralityTable { bool enableCentFT0 = true, bool enableCentFDD = true, bool enableCentNTPV = true, + bool enableCentNGlobal = false, + bool enableCentMFT = false, typename CollisionType> void produceRun3Tables(CollisionType const& collisions) { @@ -390,12 +506,21 @@ struct CentralityTable { case kCentFT0Cs: centFT0C.reserve(collisions.size()); break; + case kCentFT0CVariant1s: + centFT0CVariant1.reserve(collisions.size()); + break; case kCentFDDMs: centFDDM.reserve(collisions.size()); break; case kCentNTPVs: centNTPV.reserve(collisions.size()); break; + case kCentNGlobals: + centNGlobals.reserve(collisions.size()); + break; + case kCentMFTs: + centMFTs.reserve(collisions.size()); + break; default: LOGF(fatal, "Table %d not supported in Run3", table); break; @@ -406,18 +531,48 @@ struct CentralityTable { /* check the previous run number */ auto bc = collision.template bc_as(); if (bc.runNumber() != mRunNumber) { + mRunNumber = bc.runNumber(); // mark that this run has been attempted already regardless of outcome LOGF(info, "timestamp=%llu, run number=%d", bc.timestamp(), bc.runNumber()); - TList* callst = ccdb->getForTimeStamp(ccdbPath, bc.timestamp()); - - FV0AInfo.mCalibrationStored = false; - FT0MInfo.mCalibrationStored = false; - FT0AInfo.mCalibrationStored = false; - FT0CInfo.mCalibrationStored = false; - FDDMInfo.mCalibrationStored = false; - NTPVInfo.mCalibrationStored = false; + TList* callst = nullptr; + // Check if the ccdb path is a root file + if (ccdbConfig.ccdbPath.value.find(".root") != std::string::npos) { + TFile f(ccdbConfig.ccdbPath.value.c_str(), "READ"); + f.GetObject(ccdbConfig.reconstructionPass.value.c_str(), callst); + if (!callst) { + f.ls(); + LOG(fatal) << "No calibration list " << ccdbConfig.reconstructionPass.value << " found in the file " << ccdbConfig.ccdbPath.value; + } + } else { + if (ccdbConfig.reconstructionPass.value == "") { + callst = ccdb->getForRun(ccdbConfig.ccdbPath, bc.runNumber()); + } else if (ccdbConfig.reconstructionPass.value == "metadata") { + std::map metadata; + metadata["RecoPassName"] = metadataInfo.get("RecoPassName"); + LOGF(info, "Loading CCDB for reconstruction pass (from metadata): %s", metadataInfo.get("RecoPassName")); + callst = ccdb->getSpecificForRun(ccdbConfig.ccdbPath, bc.runNumber(), metadata); + } else { + std::map metadata; + metadata["RecoPassName"] = ccdbConfig.reconstructionPass.value; + LOGF(info, "Loading CCDB for reconstruction pass (from provided argument): %s", ccdbConfig.reconstructionPass.value); + callst = ccdb->getSpecificForRun(ccdbConfig.ccdbPath, bc.runNumber(), metadata); + } + } + + fv0aInfo.mCalibrationStored = false; + ft0mInfo.mCalibrationStored = false; + ft0aInfo.mCalibrationStored = false; + ft0cInfo.mCalibrationStored = false; + ft0cVariant1Info.mCalibrationStored = false; + fddmInfo.mCalibrationStored = false; + ntpvInfo.mCalibrationStored = false; + nGlobalInfo.mCalibrationStored = false; + mftInfo.mCalibrationStored = false; if (callst != nullptr) { + if (produceHistograms) { + listCalib->Add(callst->Clone(Form("%i", bc.runNumber()))); + } LOGF(info, "Getting new histograms with %d run number for %d run number", mRunNumber, bc.runNumber()); - auto getccdb = [callst, bc](struct calibrationInfo& estimator, const Configurable generatorName) { // TODO: to consider the name inside the estimator structure + auto getccdb = [callst, bc](struct CalibrationInfo& estimator, const Configurable generatorName) { // TODO: to consider the name inside the estimator structure estimator.mhMultSelCalib = reinterpret_cast(callst->FindObject(TString::Format("hCalibZeq%s", estimator.name.c_str()).Data())); estimator.mMCScale = reinterpret_cast(callst->FindObject(TString::Format("%s-%s", generatorName->c_str(), estimator.name.c_str()).Data())); if (estimator.mhMultSelCalib != nullptr) { @@ -433,43 +588,51 @@ struct CentralityTable { } } estimator.mCalibrationStored = true; + estimator.isSane(); } else { - LOGF(error, "Calibration information from %s for run %d not available", estimator.name.c_str(), bc.runNumber()); + LOGF(info, "Calibration information from %s for run %d not available, will fill this estimator with invalid values and continue (no crash).", estimator.name.c_str(), bc.runNumber()); } }; for (auto const& table : mEnabledTables) { switch (table) { case kCentFV0As: - getccdb(FV0AInfo, genName); + getccdb(fv0aInfo, ccdbConfig.genName); break; case kCentFT0Ms: - getccdb(FT0MInfo, genName); + getccdb(ft0mInfo, ccdbConfig.genName); break; case kCentFT0As: - getccdb(FT0AInfo, genName); + getccdb(ft0aInfo, ccdbConfig.genName); break; case kCentFT0Cs: - getccdb(FT0CInfo, genName); + getccdb(ft0cInfo, ccdbConfig.genName); + break; + case kCentFT0CVariant1s: + getccdb(ft0cVariant1Info, ccdbConfig.genName); break; case kCentFDDMs: - getccdb(FDDMInfo, genName); + getccdb(fddmInfo, ccdbConfig.genName); break; case kCentNTPVs: - getccdb(NTPVInfo, genName); + getccdb(ntpvInfo, ccdbConfig.genName); + break; + case kCentNGlobals: + getccdb(nGlobalInfo, ccdbConfig.genName); + break; + case kCentMFTs: + getccdb(mftInfo, ccdbConfig.genName); break; default: LOGF(fatal, "Table %d not supported in Run3", table); break; } } - mRunNumber = bc.runNumber(); } else { - if (!doNotCrashOnNull) { // default behaviour: crash + if (!ccdbConfig.doNotCrashOnNull) { // default behaviour: crash LOGF(fatal, "Centrality calibration is not available in CCDB for run=%d at timestamp=%llu", bc.runNumber(), bc.timestamp()); } else { // only if asked: continue filling with non-valid values (105) LOGF(info, "Centrality calibration is not available in CCDB for run=%d at timestamp=%llu, will fill tables with dummy values", bc.runNumber(), bc.timestamp()); - mRunNumber = bc.runNumber(); } } } @@ -481,10 +644,11 @@ struct CentralityTable { * @param estimator The calibration information. * @param multiplicity The multiplicity value. */ - auto populateTable = [&](auto& table, struct calibrationInfo& estimator, float multiplicity) { + + auto populateTable = [&](auto& table, struct CalibrationInfo& estimator, float multiplicity) { const bool assignOutOfRange = embedINELgtZEROselection && !collision.isInelGt0(); auto scaleMC = [](float x, float pars[6]) { - return pow(((pars[0] + pars[1] * pow(x, pars[2])) - pars[3]) / pars[4], 1.0f / pars[5]); + return std::pow(((pars[0] + pars[1] * std::pow(x, pars[2])) - pars[3]) / pars[4], 1.0f / pars[5]); }; float percentile = 105.0f; @@ -500,38 +664,84 @@ struct CentralityTable { } LOGF(debug, "%s centrality/multiplicity percentile = %.0f for a zvtx eq %s value %.0f", estimator.name.c_str(), percentile, estimator.name.c_str(), scaledMultiplicity); table(percentile); + return percentile; }; for (auto const& table : mEnabledTables) { switch (table) { case kCentFV0As: if constexpr (enableCentFV0) { - populateTable(centFV0A, FV0AInfo, collision.multZeqFV0A()); + populateTable(centFV0A, fv0aInfo, collision.multZeqFV0A()); } break; case kCentFT0Ms: if constexpr (enableCentFT0) { - populateTable(centFT0M, FT0MInfo, collision.multZeqFT0A() + collision.multZeqFT0C()); + const float perC = populateTable(centFT0M, ft0mInfo, collision.multZeqFT0A() + collision.multZeqFT0C()); + if (produceHistograms.value) { + histos.fill(HIST("FT0M/percentile"), perC); + histos.fill(HIST("FT0M/percentilevsPV"), perC, collision.multNTracksPV()); + histos.fill(HIST("FT0M/MultvsPV"), collision.multZeqFT0A() + collision.multZeqFT0C(), collision.multNTracksPV()); + if (collision.sel8()) { + histos.fill(HIST("sel8FT0M/percentile"), perC); + histos.fill(HIST("sel8FT0M/percentilevsPV"), perC, collision.multNTracksPV()); + histos.fill(HIST("sel8FT0M/MultvsPV"), collision.multZeqFT0A() + collision.multZeqFT0C(), collision.multNTracksPV()); + } + } } break; case kCentFT0As: if constexpr (enableCentFT0) { - populateTable(centFT0A, FT0AInfo, collision.multZeqFT0A()); + const float perC = populateTable(centFT0A, ft0aInfo, collision.multZeqFT0A()); + if (produceHistograms.value) { + histos.fill(HIST("FT0A/percentile"), perC); + histos.fill(HIST("FT0A/percentilevsPV"), perC, collision.multNTracksPV()); + histos.fill(HIST("FT0A/MultvsPV"), collision.multZeqFT0A() + collision.multZeqFT0C(), collision.multNTracksPV()); + if (collision.sel8()) { + histos.fill(HIST("sel8FT0A/percentile"), perC); + histos.fill(HIST("sel8FT0A/percentilevsPV"), perC, collision.multNTracksPV()); + histos.fill(HIST("sel8FT0A/MultvsPV"), collision.multZeqFT0A() + collision.multZeqFT0C(), collision.multNTracksPV()); + } + } } break; case kCentFT0Cs: if constexpr (enableCentFT0) { - populateTable(centFT0C, FT0CInfo, collision.multZeqFT0C()); + const float perC = populateTable(centFT0C, ft0cInfo, collision.multZeqFT0C()); + if (produceHistograms.value) { + histos.fill(HIST("FT0C/percentile"), perC); + histos.fill(HIST("FT0C/percentilevsPV"), perC, collision.multNTracksPV()); + histos.fill(HIST("FT0C/MultvsPV"), collision.multZeqFT0A() + collision.multZeqFT0C(), collision.multNTracksPV()); + if (collision.sel8()) { + histos.fill(HIST("sel8FT0C/percentile"), perC); + histos.fill(HIST("sel8FT0C/percentilevsPV"), perC, collision.multNTracksPV()); + histos.fill(HIST("sel8FT0C/MultvsPV"), collision.multZeqFT0A() + collision.multZeqFT0C(), collision.multNTracksPV()); + } + } + } + break; + case kCentFT0CVariant1s: + if constexpr (enableCentFT0) { + populateTable(centFT0CVariant1, ft0cVariant1Info, collision.multZeqFT0C()); } break; case kCentFDDMs: if constexpr (enableCentFDD) { - populateTable(centFDDM, FDDMInfo, collision.multZeqFDDA() + collision.multZeqFDDC()); + populateTable(centFDDM, fddmInfo, collision.multZeqFDDA() + collision.multZeqFDDC()); } break; case kCentNTPVs: if constexpr (enableCentNTPV) { - populateTable(centNTPV, NTPVInfo, collision.multZeqNTracksPV()); + populateTable(centNTPV, ntpvInfo, collision.multZeqNTracksPV()); + } + break; + case kCentNGlobals: + if constexpr (enableCentNGlobal) { + populateTable(centNGlobals, nGlobalInfo, collision.multNTracksGlobal()); + } + break; + case kCentMFTs: + if constexpr (enableCentMFT) { + populateTable(centMFTs, mftInfo, collision.mftNtracks()); } break; default: @@ -542,12 +752,17 @@ struct CentralityTable { } } - void processRun3(soa::Join const& collisions, BCsWithTimestamps const&) + void processRun3Complete(soa::Join const& collisions, BCsWithTimestamps const&) + { + produceRun3Tables(collisions); + } + + void processRun3(soa::Join const& collisions, BCsWithTimestamps const&) { produceRun3Tables(collisions); } - void processRun3FT0(soa::Join const& collisions, BCsWithTimestamps const&) + void processRun3FT0(soa::Join const& collisions, BCsWithTimestamps const&) { produceRun3Tables(cfgc)}; } +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + metadataInfo.initMetadata(cfgc); + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/Common/TableProducer/eseTableProducer.cxx b/Common/TableProducer/eseTableProducer.cxx new file mode 100644 index 00000000000..098bfbe400f --- /dev/null +++ b/Common/TableProducer/eseTableProducer.cxx @@ -0,0 +1,258 @@ +// 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 eseTableProducer.cxx +/// \brief Producer for the ESE table +/// +/// \author Joachim C. K. B. Hansen + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/runDataProcessing.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" + +#include "Common/DataModel/EseTable.h" +#include "Common/DataModel/Qvectors.h" +#include "FFitWeights.h" + +using namespace o2; +using namespace o2::framework; + +using CollWithMults = soa::Join; + +struct EseTableProducer { + Produces qPercsFT0C; + Produces qPercsFT0A; + Produces qPercsFV0A; + Produces qPercsTPCall; + Produces qPercsTPCneg; + Produces qPercsTPCpos; + + OutputObj FFitObj{FFitWeights("weights")}; + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + Configurable cfgESE{"cfgESE", 1, "ese activation step: false = no ese, true = evaluate qSelection and fill table"}; + Configurable cfgEsePath{"cfgEsePath", "Users/j/joachiha/ESE/local/ffitsplines", "CCDB path for ese splines"}; + Configurable> cfgDetectors{"cfgDetectors", {"FT0C"}, "detectors to loop over: ['FT0C', 'FT0A', 'FV0A', 'TPCall', 'TPCneg', 'TPCpos']"}; + Configurable> cfgLoopHarmonics{"cfgLoopHarmonics", {2, 3}, "Harmonics to loop over when filling and evaluating q-Selection"}; + + Configurable> cfgaxisqn{"cfgaxisqn", {500, 0, 25}, "q_n amplitude range"}; + Configurable cfgnResolution{"cfgnResolution", 3000, "resolution of q-Selection"}; + + Configurable cfgnTotalSystem{"cfgnTotalSystem", 7, "total qvector number // look in Qvector table for this number"}; + Configurable cfgnCorrLevel{"cfgnCorrLevel", 3, "QVector step: 0 = no corr, 1 = rect, 2 = twist, 3 = full"}; + + int runNumber{-1}; + + enum class DetID { FT0C, + FT0A, + FT0M, + FV0A, + TPCpos, + TPCneg, + TPCall }; + + std::unordered_map detMap = { + {"FT0C", DetID::FT0C}, + {"FT0A", DetID::FT0A}, + {"FT0M", DetID::FT0M}, + {"FV0A", DetID::FV0A}, + {"TPCpos", DetID::TPCpos}, + {"TPCneg", DetID::TPCneg}, + {"TPCall", DetID::TPCall}}; + + FFitWeights* qSelection{nullptr}; + + Service ccdb; + + void init(o2::framework::InitContext&) + { + + LOGF(info, "ESETable::init()"); + + registry.add("hEventCounter", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + registry.add("hESEstat", "ese status;ese status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + int64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); + + std::vector> veccfg; + for (std::size_t i{0}; i < cfgLoopHarmonics->size(); i++) { + for (std::size_t j{0}; j < cfgDetectors->size(); j++) { + veccfg.push_back({cfgLoopHarmonics->at(i), cfgDetectors->at(j)}); + } + } + FFitObj->setBinAxis(cfgaxisqn->at(0), cfgaxisqn->at(1), cfgaxisqn->at(2)); + FFitObj->setResolution(cfgnResolution); + FFitObj->setQnType(veccfg); + FFitObj->init(); + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + + auto timestamp = bc.timestamp(); + + if (cfgESE) { + qSelection = ccdb->getForTimeStamp(cfgEsePath, timestamp); + if (!qSelection) + LOGF(fatal, "failed loading qSelection with ese flag"); + LOGF(info, "successfully loaded qSelection"); + } + } + + float Calcqn(const float& Qx, const float& Qy, const float& Mult) + { + float dqn{0.0f}; + float qn{0.0f}; + + dqn = Qx * Qx + Qy * Qy; + qn = TMath::Sqrt(dqn) / TMath::Sqrt(Mult); + return qn; + } + + constexpr int detIDN(const DetID id) + { + switch (id) { + case DetID::FT0C: + return 0; + case DetID::FT0A: + return 1; + case DetID::FT0M: + return 2; + case DetID::FV0A: + return 3; + case DetID::TPCpos: + return 4; + case DetID::TPCneg: + return 5; + case DetID::TPCall: + return 6; + } + return -1; + } + + void doSpline(float& splineVal, const float& centr, const float& nHarm, const char* pf, const auto& QX, const auto& QY, const auto& sumAmpl) + { + if (sumAmpl > 1e-8) { + float qnval = Calcqn(QX * sumAmpl, QY * sumAmpl, sumAmpl); + FFitObj->fillWeights(centr, qnval, nHarm, pf); + if (cfgESE) { + splineVal = qSelection->eval(centr, qnval, nHarm, pf); + } + } + } + + template + std::tuple getVectors(const C& col, const int& nHarm, const DetID& id) + { + const int detId = detIDN(id); + const int detInd{detId * 4 + cfgnTotalSystem * 4 * (nHarm - 2)}; + const auto Qx{col.qvecRe()[detInd + cfgnCorrLevel]}; + const auto Qy{col.qvecIm()[detInd + cfgnCorrLevel]}; + const auto sumAmpl{col.qvecAmp()[detId]}; + return {Qx, Qy, sumAmpl}; + } + + template + void calculateESE(T const& collision, + std::vector& qnpFT0C, + std::vector& qnpFT0A, + std::vector& qnpFV0A, + std::vector& qnpTPCall, + std::vector& qnpTPCneg, + std::vector& qnpTPCpos) + { + const float centrality = collision.centFT0C(); + float counter{0.5}; + registry.fill(HIST("hESEstat"), counter++); + + std::unordered_map*> vMap{ + {"FT0C", &qnpFT0C}, + {"FT0A", &qnpFT0A}, + {"FV0A", &qnpFV0A}, + {"TPCall", &qnpTPCall}, + {"TPCneg", &qnpTPCneg}, + {"TPCpos", &qnpTPCpos}}; + + for (std::size_t j{0}; j < cfgDetectors->size(); j++) { + const auto det{cfgDetectors->at(j)}; + const auto iter{detMap.find(det)}; + float splineVal{-1.0}; + + if (iter != detMap.end()) { + for (std::size_t i{0}; i < cfgLoopHarmonics->size(); i++) { + const int nHarm{cfgLoopHarmonics->at(i)}; + const auto [qxt, qyt, st] = getVectors(collision, nHarm, iter->second); + doSpline(splineVal, centrality, nHarm, det.c_str(), qxt, qyt, st); + if (i == 0) + registry.fill(HIST("hESEstat"), counter++); + + if (vMap.find(det) != vMap.end()) { + vMap[det]->push_back(splineVal); + } + } + } + } + }; + + void processESE(CollWithMults::iterator const& collision, aod::BCsWithTimestamps const&, aod::FV0As const&, aod::FT0s const&) + { + float counter{0.5}; + registry.fill(HIST("hEventCounter"), counter++); + + std::vector qnpFT0C{}; + std::vector qnpFT0A{}; + std::vector qnpFV0A{}; + std::vector qnpTPCall{}; + std::vector qnpTPCneg{}; + std::vector qnpTPCpos{}; + + auto bc{collision.bc_as()}; + int currentRun{bc.runNumber()}; + if (runNumber != currentRun) { + runNumber = currentRun; + initCCDB(bc); + } + registry.fill(HIST("hEventCounter"), counter++); + calculateESE(collision, qnpFT0C, qnpFT0A, qnpFV0A, qnpTPCall, qnpTPCneg, qnpTPCpos); + + qPercsFT0C(qnpFT0C); + qPercsFT0A(qnpFT0A); + qPercsFV0A(qnpFV0A); + qPercsTPCall(qnpTPCall); + qPercsTPCneg(qnpTPCneg); + qPercsTPCpos(qnpTPCpos); + registry.fill(HIST("hEventCounter"), counter++); + } + PROCESS_SWITCH(EseTableProducer, processESE, "proccess q vectors to calculate reduced q-vector", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/Common/TableProducer/eventSelection.cxx b/Common/TableProducer/eventSelection.cxx index d1f3cdb7187..1e55b6288a3 100644 --- a/Common/TableProducer/eventSelection.cxx +++ b/Common/TableProducer/eventSelection.cxx @@ -9,6 +9,15 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file eventSelection.cxx +/// \brief Event selection task +/// +/// \author Evgeny Kryshen and Igor Altsybeev + +#include +#include +#include + #include "Framework/ConfigParamSpec.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -23,6 +32,11 @@ #include "DataFormatsParameters/GRPLHCIFData.h" #include "DataFormatsParameters/GRPECSObject.h" #include "ITSMFTBase/DPLAlpideParam.h" +#include "MetadataHelper.h" +#include "DataFormatsParameters/AggregatedRunInfo.h" +#include "DataFormatsITSMFT/NoiseMap.h" // missing include in TimeDeadMap.h +#include "DataFormatsITSMFT/TimeDeadMap.h" +#include "ITSMFTReconstruction/ChipMappingITS.h" #include "TH1D.h" @@ -30,32 +44,63 @@ using namespace o2; using namespace o2::framework; using namespace o2::aod::evsel; +MetadataHelper metadataInfo; // Metadata helper + using BCsWithRun2InfosTimestampsAndMatches = soa::Join; using BCsWithRun3Matchings = soa::Join; using BCsWithBcSelsRun2 = soa::Join; -using BCsWithBcSelsRun3 = soa::Join; +using BCsWithBcSelsRun3 = soa::Join; +using FullTracks = soa::Join; using FullTracksIU = soa::Join; +static const double bcNS = o2::constants::lhc::LHCBunchSpacingNS; +static const int32_t nBCsPerOrbit = o2::constants::lhc::LHCMaxBunches; struct BcSelectionTask { Produces bcsel; Service ccdb; HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - Configurable confTriggerBcShift{"triggerBcShift", 999, "set to 294 for apass2/apass3 in LHC22o-t"}; - Configurable confITSROFrameStartBorderMargin{"ITSROFrameStartBorderMargin", -1, "Number of bcs at the start of ITS RO Frame border. Take from CCDB if -1"}; - Configurable confITSROFrameEndBorderMargin{"ITSROFrameEndBorderMargin", -1, "Number of bcs at the end of ITS RO Frame border. Take from CCDB if -1"}; - Configurable confTimeFrameStartBorderMargin{"TimeFrameStartBorderMargin", -1, "Number of bcs to cut at the start of the Time Frame. Take from CCDB if -1"}; - Configurable confTimeFrameEndBorderMargin{"TimeFrameEndBorderMargin", -1, "Number of bcs to cut at the end of the Time Frame. Take from CCDB if -1"}; - - int lastRunNumber = -1; - int64_t bcSOR = -1; // global bc of the start of the first orbit + Configurable confTriggerBcShift{"triggerBcShift", 0, "set either custom shift or 999 for apass2/apass3 in LHC22o-t"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confITSROFrameStartBorderMargin{"ITSROFrameStartBorderMargin", -1, "Number of bcs at the start of ITS RO Frame border. Take from CCDB if -1"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confITSROFrameEndBorderMargin{"ITSROFrameEndBorderMargin", -1, "Number of bcs at the end of ITS RO Frame border. Take from CCDB if -1"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confTimeFrameStartBorderMargin{"TimeFrameStartBorderMargin", -1, "Number of bcs to cut at the start of the Time Frame. Take from CCDB if -1"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confTimeFrameEndBorderMargin{"TimeFrameEndBorderMargin", -1, "Number of bcs to cut at the end of the Time Frame. Take from CCDB if -1"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confCheckRunDurationLimits{"checkRunDurationLimits", false, "Check if the BCs are within the run duration limits"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable> maxInactiveChipsPerLayer{"maxInactiveChipsPerLayer", {8, 8, 8, 111, 111, 195, 195}, "Maximum allowed number of inactive ITS chips per layer"}; + + int lastRun = -1; + int64_t lastTF = -1; + uint32_t lastRCT = 0; + uint64_t sorTimestamp = 0; // default SOR timestamp + uint64_t eorTimestamp = 1; // default EOR timestamp + int64_t bcSOR = -1; // global bc of the start of run int64_t nBCsPerTF = -1; // duration of TF in bcs, should be 128*3564 or 32*3564 + int rofOffset = -1; // ITS ROF offset, in bc + int rofLength = -1; // ITS ROF length, in bc int mITSROFrameStartBorderMargin = 10; // default value int mITSROFrameEndBorderMargin = 20; // default value int mTimeFrameStartBorderMargin = 300; // default value int mTimeFrameEndBorderMargin = 4000; // default value - + bool isPP = 1; // default value + TriggerAliases* aliases = nullptr; + EventSelectionParams* par = nullptr; + std::map* mapRCT = nullptr; + std::map> mapInactiveChips; // number of inactive chips vs orbit per layer + int64_t prevOrbitForInactiveChips = 0; // cached next stored orbit in the inactive chip map + int64_t nextOrbitForInactiveChips = 0; // cached previous stored orbit in the inactive chip map + bool isGoodITSLayer3 = true; // default value + bool isGoodITSLayer0123 = true; // default value + bool isGoodITSLayersAll = true; // default value void init(InitContext&) { + if (metadataInfo.isFullyDefined() && !doprocessRun2 && !doprocessRun3) { // Check if the metadata is initialized (only if not forced from the workflow configuration) + LOG(info) << "Autosetting the processing mode (Run2 or Run3) based on metadata"; + if (metadataInfo.isRun3()) { + doprocessRun3.value = true; + } else { + doprocessRun2.value = false; + } + } + // ccdb->setURL("http://ccdb-test.cern.ch:8080"); ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); @@ -69,6 +114,7 @@ struct BcSelectionTask { histos.add("hCounterTCEafterBCcuts", "", kTH1D, {{1, 0., 1.}}); histos.add("hCounterZEMafterBCcuts", "", kTH1D, {{1, 0., 1.}}); histos.add("hCounterZNCafterBCcuts", "", kTH1D, {{1, 0., 1.}}); + histos.add("hCounterInvalidBCTimestamp", "", kTH1D, {{1, 0., 1.}}); histos.add("hLumiTVX", ";;Luminosity, 1/#mub", kTH1D, {{1, 0., 1.}}); histos.add("hLumiTCE", ";;Luminosity, 1/#mub", kTH1D, {{1, 0., 1.}}); histos.add("hLumiZEM", ";;Luminosity, 1/#mub", kTH1D, {{1, 0., 1.}}); @@ -89,19 +135,19 @@ struct BcSelectionTask { { bcsel.reserve(bcs.size()); - for (auto& bc : bcs) { - EventSelectionParams* par = ccdb->getForTimeStamp("EventSelection/EventSelectionParams", bc.timestamp()); - TriggerAliases* aliases = ccdb->getForTimeStamp("EventSelection/TriggerAliases", bc.timestamp()); + for (const auto& bc : bcs) { + par = ccdb->getForTimeStamp("EventSelection/EventSelectionParams", bc.timestamp()); + aliases = ccdb->getForTimeStamp("EventSelection/TriggerAliases", bc.timestamp()); // fill fired aliases uint32_t alias{0}; uint64_t triggerMask = bc.triggerMask(); - for (auto& al : aliases->GetAliasToTriggerMaskMap()) { + for (const auto& al : aliases->GetAliasToTriggerMaskMap()) { if (triggerMask & al.second) { alias |= BIT(al.first); } } uint64_t triggerMaskNext50 = bc.triggerMaskNext50(); - for (auto& al : aliases->GetAliasToTriggerMaskNext50Map()) { + for (const auto& al : aliases->GetAliasToTriggerMaskNext50Map()) { if (triggerMaskNext50 & al.second) { alias |= BIT(al.first); } @@ -137,9 +183,9 @@ struct BcSelectionTask { selection |= (timeT0C > par->fT0CBBlower && timeT0C < par->fT0CBBupper) ? BIT(kIsBBT0C) : 0; selection |= (timeZNA > par->fZNABBlower && timeZNA < par->fZNABBupper) ? BIT(kIsBBZNA) : 0; selection |= (timeZNC > par->fZNCBBlower && timeZNC < par->fZNCBBupper) ? BIT(kIsBBZNC) : 0; - selection |= !(fabs(timeZNA) > par->fZNABGlower && fabs(timeZNA) < par->fZNABGupper) ? BIT(kNoBGZNA) : 0; - selection |= !(fabs(timeZNC) > par->fZNCBGlower && fabs(timeZNC) < par->fZNCBGupper) ? BIT(kNoBGZNC) : 0; - selection |= (pow((timeZNA + timeZNC - par->fZNSumMean) / par->fZNSumSigma, 2) + pow((timeZNA - timeZNC - par->fZNDifMean) / par->fZNDifSigma, 2) < 1) ? BIT(kIsBBZAC) : 0; + selection |= !(std::fabs(timeZNA) > par->fZNABGlower && std::fabs(timeZNA) < par->fZNABGupper) ? BIT(kNoBGZNA) : 0; + selection |= !(std::fabs(timeZNC) > par->fZNCBGlower && std::fabs(timeZNC) < par->fZNCBGupper) ? BIT(kNoBGZNC) : 0; + selection |= (std::pow((timeZNA + timeZNC - par->fZNSumMean) / par->fZNSumSigma, 2) + std::pow((timeZNA - timeZNC - par->fZNDifMean) / par->fZNDifSigma, 2) < 1) ? BIT(kIsBBZAC) : 0; // Calculate V0 multiplicity per ring float multRingV0A[5] = {0.}; @@ -199,8 +245,9 @@ struct BcSelectionTask { histos.get(HIST("hCounterTVX"))->Fill(Form("%d", bc.runNumber()), 1); } + uint32_t rct = 0; // Fill bc selection columns - bcsel(alias, selection, foundFT0, foundFV0, foundFDD, foundZDC); + bcsel(alias, selection, rct, foundFT0, foundFV0, foundFDD, foundZDC); } } PROCESS_SWITCH(BcSelectionTask, processRun2, "Process Run2 event selection", true); @@ -213,68 +260,108 @@ struct BcSelectionTask { { if (bcs.size() == 0) return; - bcsel.reserve(bcs.size()); - // extract ITS time frame parameters - int64_t ts = bcs.iteratorAt(0).timestamp(); - auto alppar = ccdb->getForTimeStamp>("ITS/Config/AlpideParam", ts); + int run = bcs.iteratorAt(0).runNumber(); + + if (run != lastRun) { + lastRun = run; + auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), run); + // first bc of the first orbit + bcSOR = runInfo.orbitSOR * nBCsPerOrbit; + // duration of TF in bcs + nBCsPerTF = runInfo.orbitsPerTF * nBCsPerOrbit; + // SOR and EOR timestamps + sorTimestamp = runInfo.sor; + eorTimestamp = runInfo.eor; + // timestamp of the middle of the run used to access run-wise CCDB entries + int64_t ts = runInfo.sor / 2 + runInfo.eor / 2; + // access ITSROF and TF border margins + par = ccdb->getForTimeStamp("EventSelection/EventSelectionParams", ts); + mITSROFrameStartBorderMargin = confITSROFrameStartBorderMargin < 0 ? par->fITSROFrameStartBorderMargin : confITSROFrameStartBorderMargin; + mITSROFrameEndBorderMargin = confITSROFrameEndBorderMargin < 0 ? par->fITSROFrameEndBorderMargin : confITSROFrameEndBorderMargin; + mTimeFrameStartBorderMargin = confTimeFrameStartBorderMargin < 0 ? par->fTimeFrameStartBorderMargin : confTimeFrameStartBorderMargin; + mTimeFrameEndBorderMargin = confTimeFrameEndBorderMargin < 0 ? par->fTimeFrameEndBorderMargin : confTimeFrameEndBorderMargin; + // ITSROF parameters + auto alppar = ccdb->getForTimeStamp>("ITS/Config/AlpideParam", ts); + rofOffset = alppar->roFrameBiasInBC; + rofLength = alppar->roFrameLengthInBC; + // Trigger aliases + aliases = ccdb->getForTimeStamp("EventSelection/TriggerAliases", ts); + // Collision system info + auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", ts); + int beamZ1 = grplhcif->getBeamZ(o2::constants::lhc::BeamA); + int beamZ2 = grplhcif->getBeamZ(o2::constants::lhc::BeamC); + isPP = beamZ1 == 1 && beamZ2 == 1; + // prepare map of inactive chips + auto itsDeadMap = ccdb->getForTimeStamp("ITS/Calib/TimeDeadMap", ts); + auto itsDeadMapOrbits = itsDeadMap->getEvolvingMapKeys(); // roughly every second, ~350 TFs = 350x32 orbits + std::vector vClosest; // temporary vector of inactive chip ids for the current orbit range + for (const auto& orbit : itsDeadMapOrbits) { + itsDeadMap->getMapAtOrbit(orbit, vClosest); + // insert initial (orbit,vector) pair for each layer + mapInactiveChips[orbit].resize(o2::itsmft::ChipMappingITS::NLayers, 0); + + // fill map of inactive chips + for (size_t iel = 0; iel < vClosest.size(); iel++) { + uint16_t w1 = vClosest[iel]; + bool isLastInSequence = (w1 & 0x8000) == 0; + uint16_t w2 = isLastInSequence ? w1 + 1 : vClosest[iel + 1]; + uint16_t chipId1 = w1 & 0x7FFF; + uint16_t chipId2 = w2 & 0x7FFF; + for (int chipId = chipId1; chipId < chipId2; chipId++) { + auto layer = o2::itsmft::ChipMappingITS::getLayer(chipId); + mapInactiveChips[orbit][layer]++; + } + } // loop over vector of inactive chip ids + } // loop over orbits + + // QC info + std::map metadata; + metadata["run"] = Form("%d", run); + ccdb->setFatalWhenNull(0); + mapRCT = ccdb->getSpecific>("Users/j/jian/RCT", ts, metadata); + ccdb->setFatalWhenNull(1); + if (mapRCT == nullptr) { + LOGP(info, "rct object missing... inserting dummy rct flags"); + mapRCT = new std::map; + mapRCT->insert(std::pair(sorTimestamp, 0)); + } + } // map from GlobalBC to BcId needed to find triggerBc std::map mapGlobalBCtoBcId; - for (auto& bc : bcs) { + for (const auto& bc : bcs) { mapGlobalBCtoBcId[bc.globalBC()] = bc.globalIndex(); } + int triggerBcShift = confTriggerBcShift; if (confTriggerBcShift == 999) { - int run = bcs.iteratorAt(0).runNumber(); triggerBcShift = (run <= 526766 || (run >= 526886 && run <= 527237) || (run >= 527259 && run <= 527518) || run == 527523 || run == 527734 || run >= 534091) ? 0 : 294; } - // extract run number and related information - int run = bcs.iteratorAt(0).runNumber(); - if (run != lastRunNumber) { - lastRunNumber = run; // do it only once - if (run >= 500000) { // access CCDB for data or anchored MC only - int64_t ts = bcs.iteratorAt(0).timestamp(); - // access orbitShift, ITSROF and TF border margins - EventSelectionParams* par = ccdb->getForTimeStamp("EventSelection/EventSelectionParams", ts); - mITSROFrameStartBorderMargin = confITSROFrameStartBorderMargin < 0 ? par->fITSROFrameStartBorderMargin : confITSROFrameStartBorderMargin; - mITSROFrameEndBorderMargin = confITSROFrameEndBorderMargin < 0 ? par->fITSROFrameEndBorderMargin : confITSROFrameEndBorderMargin; - mTimeFrameStartBorderMargin = confTimeFrameStartBorderMargin < 0 ? par->fTimeFrameStartBorderMargin : confTimeFrameStartBorderMargin; - mTimeFrameEndBorderMargin = confTimeFrameEndBorderMargin < 0 ? par->fTimeFrameEndBorderMargin : confTimeFrameEndBorderMargin; - // access orbit-reset timestamp - auto ctpx = ccdb->getForTimeStamp>("CTP/Calib/OrbitReset", ts); - int64_t tsOrbitReset = (*ctpx)[0]; // us - // access TF duration, start-of-run and end-of-run timestamps from ECS GRP - std::map metadata; - metadata["runNumber"] = Form("%d", run); - auto grpecs = ccdb->getSpecific("GLO/Config/GRPECS", ts, metadata); - uint32_t nOrbitsPerTF = grpecs->getNHBFPerTF(); // assuming 1 orbit = 1 HBF; nOrbitsPerTF=128 in 2022, 32 in 2023 - int64_t tsSOR = grpecs->getTimeStart(); // ms - // calculate SOR orbit - int64_t orbitSOR = (tsSOR * 1000 - tsOrbitReset) / o2::constants::lhc::LHCOrbitMUS; - // adjust to the nearest TF edge - orbitSOR = orbitSOR / nOrbitsPerTF * nOrbitsPerTF + par->fTimeFrameOrbitShift; - // first bc of the first orbit (should coincide with TF start) - bcSOR = orbitSOR * o2::constants::lhc::LHCMaxBunches; - // duration of TF in bcs - nBCsPerTF = nOrbitsPerTF * o2::constants::lhc::LHCMaxBunches; - LOGP(info, "tsOrbitReset={} us, SOR = {} ms, orbitSOR = {}, nBCsPerTF = {}", tsOrbitReset, tsSOR, orbitSOR, nBCsPerTF); + // bc loop + for (auto bc : bcs) { // o2-linter: disable=const-ref-in-for-loop (use bc as nonconst iterator) + // store rct flags + uint32_t rct = lastRCT; + int64_t thisTF = (bc.globalBC() - bcSOR) / nBCsPerTF; + if (mapRCT != nullptr && thisTF != lastTF) { // skip for unanchored runs; do it once per TF + auto itrct = mapRCT->upper_bound(bc.timestamp()); + if (itrct != mapRCT->begin()) + itrct--; + rct = itrct->second; + LOGP(debug, "sor={} eor={} ts={} rct={}", sorTimestamp, eorTimestamp, bc.timestamp(), rct); + lastRCT = rct; + lastTF = thisTF; } - } - // bc loop - for (auto bc : bcs) { - EventSelectionParams* par = ccdb->getForTimeStamp("EventSelection/EventSelectionParams", bc.timestamp()); - TriggerAliases* aliases = ccdb->getForTimeStamp("EventSelection/TriggerAliases", bc.timestamp()); uint32_t alias{0}; // workaround for pp2022 (trigger info is shifted by -294 bcs) int32_t triggerBcId = mapGlobalBCtoBcId[bc.globalBC() + triggerBcShift]; - if (triggerBcId) { + if (triggerBcId && aliases) { auto triggerBc = bcs.iteratorAt(triggerBcId); uint64_t triggerMask = triggerBc.triggerMask(); - for (auto& al : aliases->GetAliasToTriggerMaskMap()) { + for (const auto& al : aliases->GetAliasToTriggerMaskMap()) { if (triggerMask & al.second) { alias |= BIT(al.first); } @@ -333,22 +420,53 @@ struct BcSelectionTask { selection |= (timeT0C > par->fT0CBBlower && timeT0C < par->fT0CBBupper) ? BIT(kIsBBT0C) : 0; selection |= (timeZNA > par->fZNABBlower && timeZNA < par->fZNABBupper) ? BIT(kIsBBZNA) : 0; selection |= (timeZNC > par->fZNCBBlower && timeZNC < par->fZNCBBupper) ? BIT(kIsBBZNC) : 0; - selection |= (pow((timeZNA + timeZNC - par->fZNSumMean) / par->fZNSumSigma, 2) + pow((timeZNA - timeZNC - par->fZNDifMean) / par->fZNDifSigma, 2) < 1) ? BIT(kIsBBZAC) : 0; - selection |= !(fabs(timeZNA) > par->fZNABGlower && fabs(timeZNA) < par->fZNABGupper) ? BIT(kNoBGZNA) : 0; - selection |= !(fabs(timeZNC) > par->fZNCBGlower && fabs(timeZNC) < par->fZNCBGupper) ? BIT(kNoBGZNC) : 0; + selection |= (std::pow((timeZNA + timeZNC - par->fZNSumMean) / par->fZNSumSigma, 2) + std::pow((timeZNA - timeZNC - par->fZNDifMean) / par->fZNDifSigma, 2) < 1) ? BIT(kIsBBZAC) : 0; + selection |= !(std::fabs(timeZNA) > par->fZNABGlower && std::fabs(timeZNA) < par->fZNABGupper) ? BIT(kNoBGZNA) : 0; + selection |= !(std::fabs(timeZNC) > par->fZNCBGlower && std::fabs(timeZNC) < par->fZNCBGupper) ? BIT(kNoBGZNC) : 0; selection |= (bc.has_ft0() ? (bc.ft0().triggerMask() & BIT(o2::ft0::Triggers::bitVertex)) > 0 : 0) ? BIT(kIsTriggerTVX) : 0; - // check if bc is far (at least confITSROFrameBorderMargin) from the end of ITS RO Frame border - // 2bc margin is also introduced at ehe beginning of ITS RO Frame to account for the uncertainty of the roFrameBiasInBC - uint16_t bcInITSROF = (globalBC + 3564 - alppar->roFrameBiasInBC) % alppar->roFrameLengthInBC; + // check if bc is far from start and end of the ITS RO Frame border + uint16_t bcInITSROF = (globalBC + nBCsPerOrbit - rofOffset) % rofLength; LOGP(debug, "bcInITSROF={}", bcInITSROF); - selection |= bcInITSROF > mITSROFrameStartBorderMargin && bcInITSROF < alppar->roFrameLengthInBC - mITSROFrameEndBorderMargin ? BIT(kNoITSROFrameBorder) : 0; + selection |= bcInITSROF > mITSROFrameStartBorderMargin && bcInITSROF < rofLength - mITSROFrameEndBorderMargin ? BIT(kNoITSROFrameBorder) : 0; // check if bc is far from the Time Frame borders int64_t bcInTF = (globalBC - bcSOR) % nBCsPerTF; LOGP(debug, "bcInTF={}", bcInTF); selection |= bcInTF > mTimeFrameStartBorderMargin && bcInTF < nBCsPerTF - mTimeFrameEndBorderMargin ? BIT(kNoTimeFrameBorder) : 0; + // check number of inactive chips and set kIsGoodITSLayer3, kIsGoodITSLayer0123, kIsGoodITSLayersAll flags + int64_t orbit = globalBC / nBCsPerOrbit; + if (mapInactiveChips.size() > 0 && (orbit < prevOrbitForInactiveChips || orbit > nextOrbitForInactiveChips)) { + auto it = mapInactiveChips.upper_bound(orbit); + bool isEnd = (it == mapInactiveChips.end()); + if (isEnd) + it--; + nextOrbitForInactiveChips = isEnd ? orbit : it->first; // setting current orbit in case we reached the end of mapInactiveChips + auto vNextInactiveChips = it->second; + if (it != mapInactiveChips.begin() && !isEnd) + it--; + prevOrbitForInactiveChips = it->first; + auto vPrevInactiveChips = it->second; + LOGP(debug, "orbit: {}, previous orbit: {}, next orbit: {} ", orbit, prevOrbitForInactiveChips, nextOrbitForInactiveChips); + LOGP(debug, "next inactive chips: {} {} {} {} {} {} {}", vNextInactiveChips[0], vNextInactiveChips[1], vNextInactiveChips[2], vNextInactiveChips[3], vNextInactiveChips[4], vNextInactiveChips[5], vNextInactiveChips[6]); + LOGP(debug, "prev inactive chips: {} {} {} {} {} {} {}", vPrevInactiveChips[0], vPrevInactiveChips[1], vPrevInactiveChips[2], vPrevInactiveChips[3], vPrevInactiveChips[4], vPrevInactiveChips[5], vPrevInactiveChips[6]); + isGoodITSLayer3 = vPrevInactiveChips[3] <= maxInactiveChipsPerLayer->at(3) && vNextInactiveChips[3] <= maxInactiveChipsPerLayer->at(3); + isGoodITSLayer0123 = true; + for (int i = 0; i < 4; i++) { + isGoodITSLayer0123 &= vPrevInactiveChips[i] <= maxInactiveChipsPerLayer->at(i) && vNextInactiveChips[i] <= maxInactiveChipsPerLayer->at(i); + } + isGoodITSLayersAll = true; + for (int i = 0; i < o2::itsmft::ChipMappingITS::NLayers; i++) { + isGoodITSLayersAll &= vPrevInactiveChips[i] <= maxInactiveChipsPerLayer->at(i) && vNextInactiveChips[i] <= maxInactiveChipsPerLayer->at(i); + } + } + + selection |= isGoodITSLayer3 ? BIT(kIsGoodITSLayer3) : 0; + selection |= isGoodITSLayer0123 ? BIT(kIsGoodITSLayer0123) : 0; + selection |= isGoodITSLayersAll ? BIT(kIsGoodITSLayersAll) : 0; + + // fill found indices int32_t foundFT0 = bc.has_ft0() ? bc.ft0().globalIndex() : -1; int32_t foundFV0 = bc.has_fv0a() ? bc.fv0a().globalIndex() : -1; int32_t foundFDD = bc.has_fdd() ? bc.fdd().globalIndex() : -1; @@ -357,10 +475,7 @@ struct BcSelectionTask { // Temporary workaround to get visible cross section. TODO: store run-by-run visible cross sections in CCDB const char* srun = Form("%d", run); - auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", bc.timestamp()); - int beamZ1 = grplhcif->getBeamZ(o2::constants::lhc::BeamA); - int beamZ2 = grplhcif->getBeamZ(o2::constants::lhc::BeamC); - bool isPP = beamZ1 == 1 && beamZ2 == 1; + bool injectionEnergy = (run >= 500000 && run <= 520099) || (run >= 534133 && run <= 534468); // Cross sections in ub. Using dummy -1 if lumi estimator is not reliable float csTVX = isPP ? (injectionEnergy ? 0.0355e6 : 0.0594e6) : -1.; @@ -410,8 +525,17 @@ struct BcSelectionTask { } } + if (bc.timestamp() < sorTimestamp || bc.timestamp() > eorTimestamp) { + histos.get(HIST("hCounterInvalidBCTimestamp"))->Fill(srun, 1); + if (confCheckRunDurationLimits.value) { + LOGF(warn, "Invalid BC timestamp: %d, run: %d, sor: %d, eor: %d", bc.timestamp(), run, sorTimestamp, eorTimestamp); + alias = 0u; + selection = 0u; + } + } + // Fill bc selection columns - bcsel(alias, selection, foundFT0, foundFV0, foundFDD, foundZDC); + bcsel(alias, selection, rct, foundFT0, foundFV0, foundFDD, foundZDC); } } PROCESS_SWITCH(BcSelectionTask, processRun3, "Process Run3 event selection", false); @@ -420,17 +544,36 @@ struct BcSelectionTask { struct EventSelectionTask { SliceCache cache; Produces evsel; - Configurable syst{"syst", "PbPb", "pp, pPb, Pbp, PbPb, XeXe"}; // TODO determine from AOD metadata or from CCDB Configurable muonSelection{"muonSelection", 0, "0 - barrel, 1 - muon selection with pileup cuts, 2 - muon selection without pileup cuts"}; Configurable maxDiffZvtxFT0vsPV{"maxDiffZvtxFT0vsPV", 1., "maximum difference (in cm) between z-vertex from FT0 and PV"}; - Configurable isMC{"isMC", 0, "0 - data, 1 - MC"}; - Partition tracklets = (aod::track::trackType == static_cast(o2::aod::track::TrackTypeEnum::Run2Tracklet)); + Configurable isMC{"isMC", 0, "-1 - autoset, 0 - data, 1 - MC"}; + Configurable confSigmaBCforHighPtTracks{"confSigmaBCforHighPtTracks", 4, "Custom sigma (in bcs) for collisions with high-pt tracks"}; + + // configurables for occupancy-based event selection + Configurable confTimeIntervalForOccupancyCalculationMin{"TimeIntervalForOccupancyCalculationMin", -40, "Min time diff window for TPC occupancy calculation, us"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confTimeIntervalForOccupancyCalculationMax{"TimeIntervalForOccupancyCalculationMax", 100, "Max time diff window for TPC occupancy calculation, us"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confTimeRangeVetoOnCollStandard{"TimeRangeVetoOnCollStandard", 10.0, "Exclusion of a collision if there are other collisions nearby, +/- us"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confTimeRangeVetoOnCollNarrow{"TimeRangeVetoOnCollNarrow", 2.0, "Exclusion of a collision if there are other collisions nearby, +/- us"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confFT0CamplCutVetoOnCollInTimeRange{"FT0CamplPerCollCutVetoOnCollInTimeRange", 8000, "Max allowed FT0C amplitude for each nearby collision in +/- time range"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confFT0CamplCutVetoOnCollInROF{"FT0CamplPerCollCutVetoOnCollInROF", 5000, "Max allowed FT0C amplitude for each nearby collision inside this ITS ROF"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confEpsilonVzDiffVetoInROF{"EpsilonVzDiffVetoInROF", 0.3, "Minumum distance to nearby collisions along z inside this ITS ROF, cm"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confUseWeightsForOccupancyVariable{"UseWeightsForOccupancyEstimator", 1, "Use or not the delta-time weights for the occupancy estimator"}; // o2-linter: disable=name/configurable (temporary fix) + + Partition tracklets = (aod::track::trackType == static_cast(o2::aod::track::TrackTypeEnum::Run2Tracklet)); + + Preslice perCollision = aod::track::collisionId; + Preslice perCollisionIU = aod::track::collisionId; Service ccdb; HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - int lastRun = -1; // last run number (needed to access ccdb only if run!=lastRun) - std::bitset bcPatternB; // bc pattern of colliding bunches + int lastRun = -1; // last run number (needed to access ccdb only if run!=lastRun) + std::bitset bcPatternB; // bc pattern of colliding bunches + + int64_t bcSOR = -1; // global bc of the start of the first orbit + int64_t nBCsPerTF = -1; // duration of TF in bcs, should be 128*3564 or 32*3564 + int rofOffset = -1; // ITS ROF offset, in bc + int rofLength = -1; // ITS ROF length, in bc int32_t findClosest(int64_t globalBC, std::map& bcs) { @@ -446,9 +589,65 @@ struct EventSelectionTask { return (dbc1 <= dbc2) ? index1 : index2; } + // helper function to find median time in the vector of TOF or TRD-track times + float getMedian(std::vector v) + { + int medianIndex = v.size() / 2; + std::nth_element(v.begin(), v.begin() + medianIndex, v.end()); + return v[medianIndex]; + } + + // helper function to find closest TVX signal in time and in zVtx + int64_t findBestGlobalBC(int64_t meanBC, int64_t sigmaBC, int32_t nContrib, float zVtxCol, std::map& mapGlobalBcVtxZ) + { + // protection against + if (sigmaBC < 1) + sigmaBC = 1; + + int64_t minBC = meanBC - 3 * sigmaBC; + int64_t maxBC = meanBC + 3 * sigmaBC; + // TODO: use ITS ROF bounds to reduce the search range? + + float zVtxSigma = 2.7 * std::pow(nContrib, -0.466) + 0.024; + zVtxSigma += 1.0; // additional uncertainty due to imperfectections of FT0 time calibration + + auto itMin = mapGlobalBcVtxZ.lower_bound(minBC); + auto itMax = mapGlobalBcVtxZ.upper_bound(maxBC); + + float bestChi2 = 1e+10; + int64_t bestGlobalBC = 0; + for (std::map::iterator it = itMin; it != itMax; ++it) { + float chi2 = std::pow((it->second - zVtxCol) / zVtxSigma, 2) + std::pow(static_cast(it->first - meanBC) / sigmaBC, 2.); + if (chi2 < bestChi2) { + bestChi2 = chi2; + bestGlobalBC = it->first; + } + } + + return bestGlobalBC; + } + void init(InitContext&) { - // ccdb->setURL("http://ccdb-test.cern.ch:8080"); + if (metadataInfo.isFullyDefined()) { // Check if the metadata is initialized (only if not forced from the workflow configuration) + if (!doprocessRun2 && !doprocessRun3) { + LOG(info) << "Autosetting the processing mode (Run2 or Run3) based on metadata"; + if (metadataInfo.isRun3()) { + doprocessRun3.value = true; + } else { + doprocessRun2.value = false; + } + } + if (isMC == -1) { + LOG(info) << "Autosetting the MC mode based on metadata"; + if (metadataInfo.isMC()) { + isMC.value = 1; + } else { + isMC.value = 0; + } + } + } + ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); @@ -463,12 +662,12 @@ struct EventSelectionTask { evsel.reserve(collisions.size()); } - void processRun2(aod::Collision const& col, BCsWithBcSelsRun2 const&, aod::Tracks const&, aod::FV0Cs const&) + void processRun2(aod::Collision const& col, BCsWithBcSelsRun2 const&, FullTracks const&, aod::FV0Cs const&) { auto bc = col.bc_as(); EventSelectionParams* par = ccdb->getForTimeStamp("EventSelection/EventSelectionParams", bc.timestamp()); - bool* applySelection = par->GetSelection(muonSelection); - if (isMC) { + bool* applySelection = par->getSelection(muonSelection); + if (isMC == 1) { applySelection[kIsBBZAC] = 0; applySelection[kNoV0MOnVsOfPileup] = 0; applySelection[kNoSPDOnVsOfPileup] = 0; @@ -506,6 +705,9 @@ struct EventSelectionTask { selection |= (spdClusters < par->fSPDClsVsTklA + nTkl * par->fSPDClsVsTklB) ? BIT(kNoSPDClsVsTklBG) : 0; selection |= !(nTkl < 6 && multV0C012 > par->fV0C012vsTklA + nTkl * par->fV0C012vsTklB) ? BIT(kNoV0C012vsTklBG) : 0; + // copy rct flags from bcsel table + uint32_t rct = bc.rct_raw(); + // apply int7-like selections bool sel7 = 1; for (int i = 0; i < kNsel; i++) { @@ -524,134 +726,431 @@ struct EventSelectionTask { bool isINT1period = bc.runNumber() <= 136377 || (bc.runNumber() >= 144871 && bc.runNumber() <= 159582); // fill counters - if (isMC || (!isINT1period && bc.alias_bit(kINT7)) || (isINT1period && bc.alias_bit(kINT1))) { + if (isMC == 1 || (!isINT1period && bc.alias_bit(kINT7)) || (isINT1period && bc.alias_bit(kINT1))) { histos.get(HIST("hColCounterAll"))->Fill(Form("%d", bc.runNumber()), 1); if ((!isINT1period && sel7) || (isINT1period && sel1)) { histos.get(HIST("hColCounterAcc"))->Fill(Form("%d", bc.runNumber()), 1); } } - evsel(alias, selection, sel7, sel8, foundBC, foundFT0, foundFV0, foundFDD, foundZDC); + evsel(alias, selection, rct, sel7, sel8, foundBC, foundFT0, foundFV0, foundFDD, foundZDC, 0, 0); } PROCESS_SWITCH(EventSelectionTask, processRun2, "Process Run2 event selection", true); - Preslice perCollision = aod::track::collisionId; - void processRun3(aod::Collisions const& cols, FullTracksIU const& tracks, BCsWithBcSelsRun3 const& bcs, aod::FT0s const&) + Partition pvTracks = ((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)); + void processRun3(aod::Collisions const& cols, FullTracksIU const&, BCsWithBcSelsRun3 const& bcs, aod::FT0s const&) { int run = bcs.iteratorAt(0).runNumber(); // extract bc pattern from CCDB for data or anchored MC only if (run != lastRun && run >= 500000) { lastRun = run; + auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), run); + // first bc of the first orbit + bcSOR = runInfo.orbitSOR * nBCsPerOrbit; + // duration of TF in bcs + nBCsPerTF = runInfo.orbitsPerTF * nBCsPerOrbit; + // colliding bc pattern int64_t ts = bcs.iteratorAt(0).timestamp(); auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", ts); bcPatternB = grplhcif->getBunchFilling().getBCPattern(); - } - // create maps from globalBC to bc index for TVX or FT0-OR fired bcs - // to be used for closest TVX (FT0-OR) searches + // extract ITS ROF parameters + auto alppar = ccdb->getForTimeStamp>("ITS/Config/AlpideParam", ts); + rofOffset = alppar->roFrameBiasInBC; + rofLength = alppar->roFrameLengthInBC; + LOGP(debug, "ITS ROF Offset={} ITS ROF Length={}", rofOffset, rofLength); + } // if run != lastRun + + // create maps from globalBC to bc index for TVX-fired bcs + // to be used for closest TVX searches std::map mapGlobalBcWithTVX; - std::map mapGlobalBcWithTOR; - for (auto& bc : bcs) { + std::map mapGlobalBcVtxZ; + for (const auto& bc : bcs) { int64_t globalBC = bc.globalBC(); // skip non-colliding bcs for data and anchored runs - if (run >= 500000 && bcPatternB[globalBC % o2::constants::lhc::LHCMaxBunches] == 0) { + if (run >= 500000 && bcPatternB[globalBC % nBCsPerOrbit] == 0) { continue; } - if (bc.selection_bit(kIsBBT0A) || bc.selection_bit(kIsBBT0C)) { - mapGlobalBcWithTOR[globalBC] = bc.globalIndex(); - } if (bc.selection_bit(kIsTriggerTVX)) { mapGlobalBcWithTVX[globalBC] = bc.globalIndex(); + mapGlobalBcVtxZ[globalBC] = bc.has_ft0() ? bc.ft0().posZ() : 0; } } // protection against empty FT0 maps - if (mapGlobalBcWithTOR.size() == 0 || mapGlobalBcWithTVX.size() == 0) { + if (mapGlobalBcWithTVX.size() == 0) { LOGP(error, "FT0 table is empty or corrupted. Filling evsel table with dummy values"); - for (auto& col : cols) { + for (const auto& col : cols) { auto bc = col.bc_as(); int32_t foundBC = bc.globalIndex(); int32_t foundFT0 = bc.foundFT0Id(); int32_t foundFV0 = bc.foundFV0Id(); int32_t foundFDD = bc.foundFDDId(); int32_t foundZDC = bc.foundZDCId(); - evsel(bc.alias_raw(), bc.selection_raw(), kFALSE, kFALSE, foundBC, foundFT0, foundFV0, foundFDD, foundZDC); + uint32_t rct = 0; + evsel(bc.alias_raw(), bc.selection_raw(), rct, kFALSE, kFALSE, foundBC, foundFT0, foundFV0, foundFDD, foundZDC, -1, -1); } return; } - - std::vector vFoundBCindex(cols.size(), -1); // indices of found bcs - std::vector vIsVertexITSTPC(cols.size(), 0); // at least one of vertex contributors is ITS-TPC track - std::vector vIsVertexTOFmatched(cols.size(), 0); // at least one of vertex contributors is matched to TOF - std::vector vIsVertexTRDmatched(cols.size(), 0); // at least one of vertex contributors is matched to TRD - std::vector vCollisionsPerBc(bcs.size(), 0); // counter of collisions per found bc for pileup checks - // loop to find nearest bc with FT0 entry -> foundBC index - for (auto& col : cols) { + std::vector vTracksITS567perColl(cols.size(), 0); // counter of tracks per collision for occupancy studies + std::vector vAmpFT0CperColl(cols.size(), 0); // amplitude FT0C per collision + std::vector vCollVz(cols.size(), 0); // vector with vZ positions for each collision + std::vector vIsFullInfoForOccupancy(cols.size(), 0); // info for occupancy in +/- windows is available (i.e. a given coll is not too close to the TF borders) + const float timeWinOccupancyCalcMinNS = confTimeIntervalForOccupancyCalculationMin * 1e3; // ns + const float timeWinOccupancyCalcMaxNS = confTimeIntervalForOccupancyCalculationMax * 1e3; // ns + std::vector vIsVertexITSTPC(cols.size(), 0); // at least one of vertex contributors is ITS-TPC track + std::vector vIsVertexTOFmatched(cols.size(), 0); // at least one of vertex contributors is matched to TOF + std::vector vIsVertexTRDmatched(cols.size(), 0); // at least one of vertex contributors is matched to TRD + + std::vector vCollisionsPerBc(bcs.size(), 0); // counter of collisions per found bc for pileup checks + std::vector vFoundBCindex(cols.size(), -1); // indices of found bcs + std::vector vFoundGlobalBC(cols.size(), 0); // global BCs for collisions + + std::vector vIsVertexTOF(cols.size(), 0); + std::vector vIsVertexTRD(cols.size(), 0); + std::vector vIsVertexTPC(cols.size(), 0); + std::vector vIsVertexHighPtTPC(cols.size(), 0); + std::vector vNcontributors(cols.size(), 0); + std::vector vWeightedTimesTPCnoTOFnoTRD(cols.size(), 0); + std::vector vWeightedSigmaTPCnoTOFnoTRD(cols.size(), 0); + + // temporary vectors to find tracks with median time + std::vector vTrackTimesTOF; + std::vector vTrackTimesTRDnoTOF; + + // first loop to match collisions to TVX, also extract other per-collision information for further use + for (const auto& col : cols) { + int32_t colIndex = col.globalIndex(); auto bc = col.bc_as(); - int64_t meanBC = bc.globalBC(); - const double bcNS = o2::constants::lhc::LHCBunchSpacingNS; - int64_t deltaBC = std::ceil(col.collisionTimeRes() / bcNS * 4); - - // count tracks of different types - int nITSTPCtracks = 0; - int nTOFtracks = 0; - int nTRDtracks = 0; - int nTRDnotTOFtracks = 0; - double timeFromTOFtracks = 0; - double timeFromTRDtracks = 0; - auto tracksGrouped = tracks.sliceBy(perCollision, col.globalIndex()); - for (auto& track : tracksGrouped) { - if (!track.isPVContributor()) { - continue; - } - nITSTPCtracks += track.hasITS() && track.hasTPC(); - nTOFtracks += track.hasTOF(); - nTRDtracks += track.hasTRD(); - nTRDnotTOFtracks += track.hasTRD() && !track.hasTOF(); - // calculate average time using TOF and TRD tracks + + vCollVz[colIndex] = col.posZ(); + + int64_t globalBC = bc.globalBC(); + int bcInTF = (bc.globalBC() - bcSOR) % nBCsPerTF; + vIsFullInfoForOccupancy[colIndex] = ((bcInTF - 300) * bcNS > -timeWinOccupancyCalcMinNS) && ((nBCsPerTF - 4000 - bcInTF) * bcNS > timeWinOccupancyCalcMaxNS) ? true : false; + + const auto& colPvTracks = pvTracks.sliceByCached(aod::track::collisionId, col.globalIndex(), cache); + vTrackTimesTOF.clear(); + vTrackTimesTRDnoTOF.clear(); + int nPvTracksTPCnoTOFnoTRD = 0; + int nPvTracksHighPtTPCnoTOFnoTRD = 0; + float sumTime = 0, sumW = 0, sumHighPtTime = 0, sumHighPtW = 0; + for (const auto& track : colPvTracks) { + float trackTime = track.trackTime(); + if (track.itsNCls() >= 5) + vTracksITS567perColl[colIndex]++; + if (track.hasTRD()) + vIsVertexTRDmatched[colIndex] = 1; + if (track.hasTPC()) + vIsVertexITSTPC[colIndex] = 1; if (track.hasTOF()) { - timeFromTOFtracks += track.trackTime(); + vTrackTimesTOF.push_back(trackTime); + vIsVertexTOFmatched[colIndex] = 1; } else if (track.hasTRD()) { - timeFromTRDtracks += track.trackTime(); + vTrackTimesTRDnoTOF.push_back(trackTime); + } else if (track.hasTPC()) { + float trackTimeRes = track.trackTimeRes(); + float trackPt = track.pt(); + float w = 1. / (trackTimeRes * trackTimeRes); + sumTime += trackTime * w; + sumW += w; + nPvTracksTPCnoTOFnoTRD++; + if (trackPt > 1) { + sumHighPtTime += trackTime * w; + sumHighPtW += w; + nPvTracksHighPtTPCnoTOFnoTRD++; + } } } - LOGP(debug, "nContrib={} nITSTPCtracks={} nTOFtracks={} nTRDtracks={} nTRDnotTOFtracks={}", col.numContrib(), nITSTPCtracks, nTOFtracks, nTRDtracks, nTRDnotTOFtracks); - - if (nTRDnotTOFtracks > 0) { - meanBC += TMath::Nint(timeFromTRDtracks / nTRDnotTOFtracks / bcNS); // assign collision bc using TRD-matched tracks - deltaBC = 0; // use precise bc from TRD-matched tracks - } else if (nTOFtracks > 0) { - meanBC += TMath::FloorNint(timeFromTOFtracks / nTOFtracks / bcNS); // assign collision bc using TOF-matched tracks - deltaBC = 4; // use precise bc from TOF tracks with +/-4 bc margin - } else if (nITSTPCtracks > 0) { - deltaBC += 30; // extend deltaBC for collisions built with ITS-TPC tracks only - } - - int64_t minBC = meanBC - deltaBC; - int64_t maxBC = meanBC + deltaBC; - - int32_t indexClosestTVX = findClosest(meanBC, mapGlobalBcWithTVX); - int64_t tvxBC = bcs.iteratorAt(indexClosestTVX).globalBC(); - if (tvxBC >= minBC && tvxBC <= maxBC) { // closest TVX within search region - bc.setCursor(indexClosestTVX); - } else { // no TVX within search region, searching for TOR = T0A | T0C - int32_t indexClosestTOR = findClosest(meanBC, mapGlobalBcWithTOR); - int64_t torBC = bcs.iteratorAt(indexClosestTOR).globalBC(); - if (torBC >= minBC && torBC <= maxBC) { - bc.setCursor(indexClosestTOR); + vWeightedTimesTPCnoTOFnoTRD[colIndex] = sumW > 0 ? sumTime / sumW : 0; + vWeightedSigmaTPCnoTOFnoTRD[colIndex] = sumW > 0 ? std::sqrt(1. / sumW) : 0; + vNcontributors[colIndex] = colPvTracks.size(); + int nPvTracksTOF = vTrackTimesTOF.size(); + int nPvTracksTRDnoTOF = vTrackTimesTRDnoTOF.size(); + // collision type + vIsVertexTOF[colIndex] = nPvTracksTOF > 0; + vIsVertexTRD[colIndex] = nPvTracksTRDnoTOF > 0; + vIsVertexTPC[colIndex] = nPvTracksTPCnoTOFnoTRD > 0; + vIsVertexHighPtTPC[colIndex] = nPvTracksHighPtTPCnoTOFnoTRD > 0; + + int64_t foundGlobalBC = 0; + int32_t foundBCindex = -1; + + if (nPvTracksTOF > 0) { + // for collisions with TOF tracks: + // take bc corresponding to TOF track with median time + int64_t tofGlobalBC = globalBC + TMath::Nint(getMedian(vTrackTimesTOF) / bcNS); + std::map::iterator it = mapGlobalBcWithTVX.find(tofGlobalBC); + if (it != mapGlobalBcWithTVX.end()) { + foundGlobalBC = it->first; + foundBCindex = it->second; + } + } else if (nPvTracksTPCnoTOFnoTRD == 0 && nPvTracksTRDnoTOF > 0) { + // for collisions with TRD tracks but without TOF or ITSTPC-only tracks: + // take bc corresponding to TRD track with median time + int64_t trdGlobalBC = globalBC + TMath::Nint(getMedian(vTrackTimesTRDnoTOF) / bcNS); + std::map::iterator it = mapGlobalBcWithTVX.find(trdGlobalBC); + if (it != mapGlobalBcWithTVX.end()) { + foundGlobalBC = it->first; + foundBCindex = it->second; + } + } else if (nPvTracksHighPtTPCnoTOFnoTRD > 0) { + // for collisions with high-pt ITSTPC-nonTOF-nonTRD tracks + // search in 3*confSigmaBCforHighPtTracks range (3*4 bcs by default) + int64_t meanBC = globalBC + TMath::Nint(sumHighPtTime / sumHighPtW / bcNS); + int64_t bestGlobalBC = findBestGlobalBC(meanBC, confSigmaBCforHighPtTracks, vNcontributors[colIndex], col.posZ(), mapGlobalBcVtxZ); + if (bestGlobalBC > 0) { + foundGlobalBC = bestGlobalBC; + foundBCindex = mapGlobalBcWithTVX[bestGlobalBC]; } } - int32_t foundBC = bc.globalIndex(); + + // fill foundBC indices and global BCs + // keep current bc if TVX matching failed at this step + vFoundBCindex[colIndex] = foundBCindex >= 0 ? foundBCindex : bc.globalIndex(); + vFoundGlobalBC[colIndex] = foundGlobalBC > 0 ? foundGlobalBC : globalBC; + + // erase found global BC with TVX from the pool of bcs for the next loop over low-pt TPCnoTOFnoTRD collisions + if (foundBCindex >= 0) + mapGlobalBcVtxZ.erase(foundGlobalBC); + } + + // second loop to match remaining low-pt TPCnoTOFnoTRD collisions + for (const auto& col : cols) { int32_t colIndex = col.globalIndex(); - LOGP(debug, "foundBC = {} globalBC = {}", foundBC, bc.globalBC()); - vFoundBCindex[colIndex] = foundBC; - vIsVertexITSTPC[colIndex] = nITSTPCtracks > 0; - vIsVertexTOFmatched[colIndex] = nTOFtracks > 0; - vIsVertexTRDmatched[colIndex] = nTRDtracks > 0; - vCollisionsPerBc[foundBC]++; + if (vIsVertexTPC[colIndex] > 0 && vIsVertexTOF[colIndex] == 0 && vIsVertexHighPtTPC[colIndex] == 0) { + float weightedTime = vWeightedTimesTPCnoTOFnoTRD[colIndex]; + float weightedSigma = vWeightedSigmaTPCnoTOFnoTRD[colIndex]; + auto bc = col.bc_as(); + int64_t globalBC = bc.globalBC(); + int64_t meanBC = globalBC + TMath::Nint(weightedTime / bcNS); + int64_t sigmaBC = TMath::CeilNint(weightedSigma / bcNS); + int64_t bestGlobalBC = findBestGlobalBC(meanBC, sigmaBC, vNcontributors[colIndex], col.posZ(), mapGlobalBcVtxZ); + vFoundGlobalBC[colIndex] = bestGlobalBC > 0 ? bestGlobalBC : globalBC; + vFoundBCindex[colIndex] = bestGlobalBC > 0 ? mapGlobalBcWithTVX[bestGlobalBC] : bc.globalIndex(); + } + // fill pileup counter + vCollisionsPerBc[vFoundBCindex[colIndex]]++; } - for (auto& col : cols) { + // save indices of collisions for occupancy calculation (both in ROF and in time range) + std::vector> vCollsInSameITSROF; + std::vector> vCollsInPrevITSROF; + std::vector> vCollsInTimeWin; + std::vector> vTimeDeltaForColls; // delta time wrt a given collision + for (const auto& col : cols) { + int32_t colIndex = col.globalIndex(); + int64_t foundGlobalBC = vFoundGlobalBC[colIndex]; + auto bc = bcs.iteratorAt(vFoundBCindex[colIndex]); + if (bc.has_foundFT0()) + vAmpFT0CperColl[colIndex] = bc.foundFT0().sumAmpC(); + + int64_t tfId = (foundGlobalBC - bcSOR) / nBCsPerTF; + int64_t rofId = (foundGlobalBC + nBCsPerOrbit - rofOffset) / rofLength; + + // ### for in-ROF occupancy + std::vector vAssocCollInSameROF; + // find all collisions in the same ROF before a given collision + int32_t minColIndex = colIndex - 1; + while (minColIndex >= 0) { + int64_t thisBC = vFoundGlobalBC[minColIndex]; + // check if this is still the same TF + int64_t thisTFid = (thisBC - bcSOR) / nBCsPerTF; + if (thisTFid != tfId) + break; + // int thisRofIdInTF = (thisBC - rofOffset) / rofLength; + int64_t thisRofId = (thisBC + nBCsPerOrbit - rofOffset) / rofLength; + + // check if we are within the same ROF + if (thisRofId != rofId) + break; + vAssocCollInSameROF.push_back(minColIndex); + minColIndex--; + } + // find all collisions in the same ROF after the current one + int32_t maxColIndex = colIndex + 1; + while (maxColIndex < cols.size()) { + int64_t thisBC = vFoundGlobalBC[maxColIndex]; + int64_t thisTFid = (thisBC - bcSOR) / nBCsPerTF; + if (thisTFid != tfId) + break; + int64_t thisRofId = (thisBC + nBCsPerOrbit - rofOffset) / rofLength; + if (thisRofId != rofId) + break; + vAssocCollInSameROF.push_back(maxColIndex); + maxColIndex++; + } + vCollsInSameITSROF.push_back(vAssocCollInSameROF); + + // ### bookkeep collisions in previous ROF + std::vector vAssocCollInPrevROF; + minColIndex = colIndex - 1; + while (minColIndex >= 0) { + int64_t thisBC = vFoundGlobalBC[minColIndex]; + // check if this is still the same TF + int64_t thisTFid = (thisBC - bcSOR) / nBCsPerTF; + if (thisTFid != tfId) + break; + int64_t thisRofId = (thisBC + nBCsPerOrbit - rofOffset) / rofLength; + if (thisRofId == rofId - 1) + vAssocCollInPrevROF.push_back(minColIndex); + else if (thisRofId < rofId - 1) + break; + minColIndex--; + } + vCollsInPrevITSROF.push_back(vAssocCollInPrevROF); + + // ### for occupancy in time windows + std::vector vAssocToThisCol; + std::vector vCollsTimeDeltaWrtGivenColl; + // protection against the TF borders + if (!vIsFullInfoForOccupancy[colIndex]) { + vCollsInTimeWin.push_back(vAssocToThisCol); + vTimeDeltaForColls.push_back(vCollsTimeDeltaWrtGivenColl); + continue; + } + // find all collisions in time window before the current one + minColIndex = colIndex - 1; + while (minColIndex >= 0) { + int64_t thisBC = vFoundGlobalBC[minColIndex]; + // check if this is still the same TF + int64_t thisTFid = (thisBC - bcSOR) / nBCsPerTF; + if (thisTFid != tfId) + break; + float dt = (thisBC - foundGlobalBC) * bcNS; // ns + // check if we are within the chosen time range + if (dt < timeWinOccupancyCalcMinNS) + break; + vAssocToThisCol.push_back(minColIndex); + vCollsTimeDeltaWrtGivenColl.push_back(dt); + minColIndex--; + } + // find all collisions in time window after the current one + maxColIndex = colIndex + 1; + while (maxColIndex < cols.size()) { + int64_t thisBC = vFoundGlobalBC[maxColIndex]; + int64_t thisTFid = (thisBC - bcSOR) / nBCsPerTF; + if (thisTFid != tfId) + break; + float dt = (thisBC - foundGlobalBC) * bcNS; // ns + if (dt > timeWinOccupancyCalcMaxNS) + break; + vAssocToThisCol.push_back(maxColIndex); + vCollsTimeDeltaWrtGivenColl.push_back(dt); + maxColIndex++; + } + vCollsInTimeWin.push_back(vAssocToThisCol); + vTimeDeltaForColls.push_back(vCollsTimeDeltaWrtGivenColl); + } + + // perform the occupancy calculation per ITS ROF and also in the pre-defined time window + std::vector vNumTracksITS567inFullTimeWin(cols.size(), 0); // counter of tracks in full time window for occupancy studies (excluding given event) + std::vector vSumAmpFT0CinFullTimeWin(cols.size(), 0); // sum of FT0C of tracks in full time window for occupancy studies (excluding given event) + + std::vector vNoCollInTimeRangeStrict(cols.size(), 0); // no collisions in a specified time range + std::vector vNoCollInTimeRangeNarrow(cols.size(), 0); // no collisions in a specified time range (narrow) + std::vector vNoHighMultCollInTimeRange(cols.size(), 0); // no high-mult collisions in a specified time range + + std::vector vNoCollInSameRofStrict(cols.size(), 0); // to veto events with other collisions in the same ITS ROF + std::vector vNoCollInSameRofStandard(cols.size(), 0); // to veto events with other collisions in the same ITS ROF, with per-collision multiplicity above threshold + std::vector vNoCollInSameRofWithCloseVz(cols.size(), 0); // to veto events with nearby collisions with close vZ + std::vector vNoHighMultCollInPrevRof(cols.size(), 0); // veto events if FT0C amplitude in previous ITS ROF is above threshold + + for (const auto& col : cols) { + int32_t colIndex = col.globalIndex(); + float vZ = col.posZ(); + + // ### in-ROF occupancy + std::vector vAssocCollInSameROF = vCollsInSameITSROF[colIndex]; + int nITS567tracksForSameRofVetoStrict = 0; // to veto events with other collisions in the same ITS ROF + int nCollsInRofWithFT0CAboveVetoStandard = 0; // to veto events with other collisions in the same ITS ROF, with per-collision multiplicity above threshold + int nITS567tracksForRofVetoOnCloseVz = 0; // to veto events with nearby collisions with close vZ + for (uint32_t iCol = 0; iCol < vAssocCollInSameROF.size(); iCol++) { + int thisColIndex = vAssocCollInSameROF[iCol]; + nITS567tracksForSameRofVetoStrict += vTracksITS567perColl[thisColIndex]; + if (vAmpFT0CperColl[thisColIndex] > confFT0CamplCutVetoOnCollInROF) + nCollsInRofWithFT0CAboveVetoStandard++; + if (std::fabs(vCollVz[thisColIndex] - vZ) < confEpsilonVzDiffVetoInROF) + nITS567tracksForRofVetoOnCloseVz += vTracksITS567perColl[thisColIndex]; + } + // in-ROF occupancy flags + vNoCollInSameRofStrict[colIndex] = (nITS567tracksForSameRofVetoStrict == 0); + vNoCollInSameRofStandard[colIndex] = (nCollsInRofWithFT0CAboveVetoStandard == 0); + vNoCollInSameRofWithCloseVz[colIndex] = (nITS567tracksForRofVetoOnCloseVz == 0); + + // ### occupancy in previous ROF + std::vector vAssocCollInPrevROF = vCollsInPrevITSROF[colIndex]; + float totalFT0amplInPrevROF = 0; + for (uint32_t iCol = 0; iCol < vAssocCollInPrevROF.size(); iCol++) { + int thisColIndex = vAssocCollInPrevROF[iCol]; + totalFT0amplInPrevROF += vAmpFT0CperColl[thisColIndex]; + } + // veto events if FT0C amplitude in previous ITS ROF is above threshold + vNoHighMultCollInPrevRof[colIndex] = (totalFT0amplInPrevROF < confFT0CamplCutVetoOnCollInROF); + + // ### occupancy in time windows + // protection against TF borders + if (!vIsFullInfoForOccupancy[colIndex]) { // occupancy in undefined (too close to TF borders) + vNumTracksITS567inFullTimeWin[colIndex] = -1; + vSumAmpFT0CinFullTimeWin[colIndex] = -1; + continue; + } + std::vector vAssocToThisCol = vCollsInTimeWin[colIndex]; + std::vector vCollsTimeDeltaWrtGivenColl = vTimeDeltaForColls[colIndex]; + int nITS567tracksInFullTimeWindow = 0; + float sumAmpFT0CInFullTimeWindow = 0; + int nITS567tracksForVetoNarrow = 0; // to veto events with nearby collisions (narrower range) + int nITS567tracksForVetoStrict = 0; // to veto events with nearby collisions + int nCollsWithFT0CAboveVetoStandard = 0; // to veto events with per-collision multiplicity above threshold + for (uint32_t iCol = 0; iCol < vAssocToThisCol.size(); iCol++) { + int thisColIndex = vAssocToThisCol[iCol]; + float dt = vCollsTimeDeltaWrtGivenColl[iCol] / 1e3; // ns -> us + float wOccup = 1.; + if (confUseWeightsForOccupancyVariable) { + // weighted occupancy + wOccup = 0; + if (dt >= -40 && dt < -5) // collisions in the past + wOccup = 1. / 1225 * (dt + 40) * (dt + 40); + else if (dt >= -5 && dt < 15) // collisions near a given one + wOccup = 1; + // else if (dt >= 15 && dt < 100) // collisions from the future + // wOccup = -1. / 85 * dt + 20. / 17; + else if (dt >= 15 && dt < 40) // collisions from the future + wOccup = -0.4 / 25 * dt + 1.24; + else if (dt >= 40 && dt < 100) // collisions from the distant future + wOccup = -0.4 / 60 * dt + 0.6 + 0.8 / 3; + } + nITS567tracksInFullTimeWindow += wOccup * vTracksITS567perColl[thisColIndex]; + sumAmpFT0CInFullTimeWindow += wOccup * vAmpFT0CperColl[thisColIndex]; + + // counting tracks from other collisions in fixed time windows + if (std::fabs(dt) < confTimeRangeVetoOnCollNarrow) + nITS567tracksForVetoNarrow += vTracksITS567perColl[thisColIndex]; + if (std::fabs(dt) < confTimeRangeVetoOnCollStandard) + nITS567tracksForVetoStrict += vTracksITS567perColl[thisColIndex]; + + // standard cut on other collisions vs delta-times + const float driftV = 2.5; // drift velocity in cm/us, TPC drift_length / drift_time = 250 cm / 100 us + if (std::fabs(dt) < 2.0) { // us, complete veto on other collisions + nCollsWithFT0CAboveVetoStandard++; + } else if (dt > -4.0 && dt <= -2.0) { // us, strict veto to suppress fake ITS-TPC matches more + if (vAmpFT0CperColl[thisColIndex] > confFT0CamplCutVetoOnCollInTimeRange / 5) + nCollsWithFT0CAboveVetoStandard++; + } else if (std::fabs(dt) < 8 + std::fabs(vZ) / driftV) { // loose veto, 8 us corresponds to maximum possible |vZ|, which is ~20 cm + // counting number of other collisions with multiplicity above threshold + if (vAmpFT0CperColl[thisColIndex] > confFT0CamplCutVetoOnCollInTimeRange) + nCollsWithFT0CAboveVetoStandard++; + } + } + vNumTracksITS567inFullTimeWin[colIndex] = nITS567tracksInFullTimeWindow; // occupancy by a sum of number of ITS tracks (without a current collision) + vSumAmpFT0CinFullTimeWin[colIndex] = sumAmpFT0CInFullTimeWindow; // occupancy by a sum of FT0C amplitudes (without a current collision) + // occupancy flags based on nearby collisions + vNoCollInTimeRangeNarrow[colIndex] = (nITS567tracksForVetoNarrow == 0); + vNoCollInTimeRangeStrict[colIndex] = (nITS567tracksForVetoStrict == 0); + vNoHighMultCollInTimeRange[colIndex] = (nCollsWithFT0CAboveVetoStandard == 0); + } + + for (const auto& col : cols) { int32_t colIndex = col.globalIndex(); int32_t foundBC = vFoundBCindex[colIndex]; auto bc = bcs.iteratorAt(foundBC); @@ -661,7 +1160,7 @@ struct EventSelectionTask { int32_t foundZDC = bc.foundZDCId(); // compare zVtx from FT0 and from PV - bool isGoodZvtxFT0vsPV = bc.has_foundFT0() ? fabs(bc.foundFT0().posZ() - col.posZ()) < maxDiffZvtxFT0vsPV : 0; + bool isGoodZvtxFT0vsPV = bc.has_foundFT0() ? std::fabs(bc.foundFT0().posZ() - col.posZ()) < maxDiffZvtxFT0vsPV : 0; // copy alias decisions from bcsel table uint32_t alias = bc.alias_raw(); @@ -674,6 +1173,19 @@ struct EventSelectionTask { selection |= vIsVertexTRDmatched[colIndex] ? BIT(kIsVertexTRDmatched) : 0; selection |= isGoodZvtxFT0vsPV ? BIT(kIsGoodZvtxFT0vsPV) : 0; + // selection bits based on occupancy time pattern + selection |= vNoCollInTimeRangeNarrow[colIndex] ? BIT(kNoCollInTimeRangeNarrow) : 0; + selection |= vNoCollInTimeRangeStrict[colIndex] ? BIT(kNoCollInTimeRangeStrict) : 0; + selection |= vNoHighMultCollInTimeRange[colIndex] ? BIT(kNoCollInTimeRangeStandard) : 0; + + // selection bits based on ITS in-ROF occupancy + selection |= vNoCollInSameRofStrict[colIndex] ? BIT(kNoCollInRofStrict) : 0; + selection |= (vNoCollInSameRofStandard[colIndex] && vNoCollInSameRofWithCloseVz[colIndex]) ? BIT(kNoCollInRofStandard) : 0; + selection |= vNoHighMultCollInPrevRof[colIndex] ? BIT(kNoHighMultCollInPrevRof) : 0; + + // copy rct flags from bcsel table + uint32_t rct = bc.rct_raw(); + // apply int7-like selections bool sel7 = 0; @@ -691,14 +1203,19 @@ struct EventSelectionTask { histos.get(HIST("hColCounterAcc"))->Fill(Form("%d", bc.runNumber()), 1); } - evsel(alias, selection, sel7, sel8, foundBC, foundFT0, foundFV0, foundFDD, foundZDC); + evsel(alias, selection, rct, sel7, sel8, foundBC, foundFT0, foundFV0, foundFDD, foundZDC, + vNumTracksITS567inFullTimeWin[colIndex], vSumAmpFT0CinFullTimeWin[colIndex]); } } + PROCESS_SWITCH(EventSelectionTask, processRun3, "Process Run3 event selection", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { + // Parse the metadata + metadataInfo.initMetadata(cfgc); + return WorkflowSpec{ adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc)}; diff --git a/Common/TableProducer/ft0CorrectedTable.cxx b/Common/TableProducer/ft0CorrectedTable.cxx index 49e6e8bea1c..a8a2787aa5a 100644 --- a/Common/TableProducer/ft0CorrectedTable.cxx +++ b/Common/TableProducer/ft0CorrectedTable.cxx @@ -10,38 +10,96 @@ // or submit itself to any jurisdiction. #include -#include "Common/DataModel/FT0Corrected.h" +#include #include "Framework/ConfigParamSpec.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" -#include "Common/DataModel/EventSelection.h" #include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/EventSelection.h" #include "CommonConstants/LHCConstants.h" #include "CommonConstants/PhysicsConstants.h" #include "DataFormatsFT0/Digit.h" +#include "CCDB/BasicCCDBManager.h" +#include "CollisionTypeHelper.h" +#include "TRandom3.h" using namespace o2; using namespace o2::framework; - using namespace o2::aod; -struct FT0CorrectedTable { + +struct ft0CorrectedTable { + // Configurables + Configurable resoFT0A{"resoFT0A", 20.f, "FT0A resolution in ps for the MC override"}; + Configurable resoFT0C{"resoFT0C", 20.f, "FT0C resolution in ps for the MC override"}; + Configurable addHistograms{"addHistograms", false, "Add QA histograms"}; + Configurable cfgCollisionSystem{"collisionSystem", -2, "Collision system: -2 (use cfg values), -1 (autoset), 0 (pp), 1 (PbPb), 2 (XeXe), 3 (pPb)"}; + Configurable cfgUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable cfgPathGrpLhcIf{"ccdb-path-grplhcif", "GLO/Config/GRPLHCIF", "Path on the CCDB for the GRPLHCIF object"}; + Configurable cfgTimestamp{"ccdb-timestamp", -1, "timestamp of the object"}; + Service ccdb; + + // Producer Produces table; using BCsWithMatchings = soa::Join; using CollisionEvSel = soa::Join::iterator; + static constexpr float invLightSpeedCm2NS = 1.f / o2::constants::physics::LightSpeedCm2NS; + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + void init(o2::framework::InitContext&) + { + if (doprocessStandard && doprocessWithBypassFT0timeInMC) { + LOG(fatal) << "Both processStandard and processWithBypassFT0timeInMC are enabled. Pick one of the two"; + } + if (!doprocessStandard && !doprocessWithBypassFT0timeInMC) { + LOG(fatal) << "No process is enabled. Pick one"; + } + ccdb->setURL(cfgUrl); + ccdb->setTimestamp(cfgTimestamp); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + // Not later than now objects + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + + if (doprocessWithBypassFT0timeInMC) { + // From ps to ns + resoFT0A.value = resoFT0A.value / 1000.f; + resoFT0C.value = resoFT0C.value / 1000.f; + } + if (!addHistograms) { + return; + } + histos.add("t0A", "t0A", kTH1D, {{1000, -1, 1, "t0A (ns)"}}); + histos.add("t0C", "t0C", kTH1D, {{1000, -1, 1, "t0C (ns)"}}); + histos.add("t0AC", "t0AC", kTH1D, {{1000, -1000, 1000, "t0AC (ns)"}}); + histos.add("deltat0AC", "deltat0AC", kTH1D, {{1000, -1, 1, "#Deltat0AC (ns)"}}); + histos.add("deltat0ACps", "deltat0ACps", kTH1D, {{1000, -1000, 1000, "#Deltat0AC (ps)"}}); + if (doprocessWithBypassFT0timeInMC) { + histos.add("MC/deltat0A", "t0A", kTH1D, {{1000, -50, 50, "t0A (ps)"}}); + histos.add("MC/deltat0C", "t0C", kTH1D, {{1000, -50, 50, "t0C (ps)"}}); + histos.add("MC/deltat0AC", "t0AC", kTH1D, {{1000, -50, 50, "t0AC (ps)"}}); + } + } - void process(BCsWithMatchings const&, soa::Join const& collisions, aod::FT0s const&) + void processStandard(soa::Join const& collisions, + BCsWithMatchings const&, + aod::FT0s const&) { - for (auto& collision : collisions) { - float vertexPV = collision.posZ(); - float vertex_corr = vertexPV / o2::constants::physics::LightSpeedCm2NS; - float t0A = 1e10; - float t0C = 1e10; + table.reserve(collisions.size()); + float t0A = 1e10f; + float t0C = 1e10f; + for (const auto& collision : collisions) { + t0A = 1e10f; + t0C = 1e10f; + const float vertexPV = collision.posZ(); + const float vertex_corr = vertexPV * invLightSpeedCm2NS; constexpr float dummyTime = 30.; // Due to HW limitations time can be only within range (-25,25) ns, dummy time is around 32 ns if (collision.has_foundFT0()) { - auto ft0 = collision.foundFT0(); - std::bitset<8> triggers = ft0.triggerMask(); - bool ora = triggers[o2::ft0::Triggers::bitA]; - bool orc = triggers[o2::ft0::Triggers::bitC]; + const auto& ft0 = collision.foundFT0(); + const std::bitset<8>& triggers = ft0.triggerMask(); + const bool ora = triggers[o2::ft0::Triggers::bitA]; + const bool orc = triggers[o2::ft0::Triggers::bitC]; LOGF(debug, "triggers OrA %i OrC %i ", ora, orc); LOGF(debug, " T0A = %f, T0C %f, vertex_corr %f", ft0.timeA(), ft0.timeC(), vertex_corr); if (ora && ft0.timeA() < dummyTime) { @@ -52,11 +110,106 @@ struct FT0CorrectedTable { } } LOGF(debug, " T0 collision time T0A = %f, T0C = %f", t0A, t0C); + if (addHistograms) { + histos.fill(HIST("t0A"), t0A); + histos.fill(HIST("t0C"), t0C); + if (t0A < 1e10f && t0C < 1e10f) { + histos.fill(HIST("t0AC"), (t0A + t0C) * 0.5f); + histos.fill(HIST("deltat0AC"), (t0A - t0C) * 0.5f); + histos.fill(HIST("deltat0ACps"), (t0A - t0C) * 500.f); + } + } table(t0A, t0C); } } + PROCESS_SWITCH(ft0CorrectedTable, processStandard, "Process standard table (default)", true); + + void processWithBypassFT0timeInMC(soa::Join const& collisions, + soa::Join const& bcs, + aod::FT0s const&, + aod::McCollisions const&) + { + if (cfgCollisionSystem.value == -1) { + o2::parameters::GRPLHCIFData* grpo = ccdb->template getForTimeStamp(cfgPathGrpLhcIf, + bcs.iteratorAt(0).timestamp()); + cfgCollisionSystem.value = CollisionSystemType::getCollisionTypeFromGrp(grpo); + switch (cfgCollisionSystem.value) { + case CollisionSystemType::kCollSyspp: + resoFT0A.value = 24.f; + resoFT0C.value = 24.f; + break; + case CollisionSystemType::kCollSysPbPb: + resoFT0A.value = 5.65f; + resoFT0C.value = 5.65f; + break; + default: + break; + } + // Resolution is given in ps + resoFT0A.value = resoFT0A.value / 1000.f; + resoFT0C.value = resoFT0C.value / 1000.f; + } + table.reserve(collisions.size()); + float t0A = 1e10f; + float t0C = 1e10f; + float eventtimeMC = 1e10f; + float posZMC = 0; + bool hasMCcoll = false; + + for (const auto& collision : collisions) { + hasMCcoll = false; + eventtimeMC = 1e10f; + t0A = 1e10f; + t0C = 1e10f; + posZMC = 0; + const float vertexPV = collision.posZ(); + const float vertex_corr = vertexPV * invLightSpeedCm2NS; + constexpr float dummyTime = 30.; // Due to HW limitations time can be only within range (-25,25) ns, dummy time is around 32 ns + if (collision.has_mcCollision()) { + hasMCcoll = true; + const auto& collisionMC = collision.mcCollision(); + eventtimeMC = collisionMC.t(); + posZMC = collisionMC.posZ(); + } + if (collision.has_foundFT0()) { + const auto& ft0 = collision.foundFT0(); + const std::bitset<8>& triggers = ft0.triggerMask(); + const bool ora = triggers[o2::ft0::Triggers::bitA]; + const bool orc = triggers[o2::ft0::Triggers::bitC]; + + if (ora && ft0.timeA() < dummyTime) { + t0A = ft0.timeA(); + if (hasMCcoll) { + const float diff = eventtimeMC - posZMC * invLightSpeedCm2NS + gRandom->Gaus(0.f, resoFT0A); + t0A = diff; + } + t0A += vertex_corr; + } + if (orc && ft0.timeC() < dummyTime) { + t0C = ft0.timeC(); + if (hasMCcoll) { + const float diff = eventtimeMC + posZMC * invLightSpeedCm2NS + gRandom->Gaus(0.f, resoFT0C); + t0C = diff; + } + t0C -= vertex_corr; + } + } + LOGF(debug, " T0 collision time T0A = %f, T0C = %f", t0A, t0C); + if (addHistograms) { + histos.fill(HIST("t0A"), t0A); + histos.fill(HIST("t0C"), t0C); + histos.fill(HIST("t0AC"), (t0A + t0C) * 0.5f); + histos.fill(HIST("deltat0AC"), t0A - t0C); + if (hasMCcoll) { + histos.fill(HIST("MC/deltat0A"), (t0A - eventtimeMC) * 1000.f); + histos.fill(HIST("MC/deltat0C"), (t0C - eventtimeMC) * 1000.f); + histos.fill(HIST("MC/deltat0AC"), ((t0A + t0C) * 0.5f - eventtimeMC) * 1000.f); + } + } + table(t0A, t0C); + } + } + PROCESS_SWITCH(ft0CorrectedTable, processWithBypassFT0timeInMC, "Process MC with bypass of the AO2D information. Use with care!", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"ft0-corrected-table"})}; -} + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/Common/TableProducer/fwdtrackPropagation.cxx b/Common/TableProducer/fwdtrackPropagation.cxx new file mode 100644 index 00000000000..c7df8dd3ea5 --- /dev/null +++ b/Common/TableProducer/fwdtrackPropagation.cxx @@ -0,0 +1,422 @@ +// 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 fwdtrackPropagator.cxx +/// \brief Common task to produce propagated forward tracks +/// \author Maurice Coquet +/// \author Luca Micheletti +/// \author Daiki Sekihata + +#include +#include +#include + +#include "Framework/DataTypes.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "TableHelper.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "TGeoGlobalMagField.h" +#include "Field/MagneticField.h" + +#include "DetectorsBase/Propagator.h" +#include "GlobalTracking/MatchGlobalFwd.h" +#include "MCHTracking/TrackExtrap.h" +#include "MCHTracking/TrackParam.h" +#include "ReconstructionDataFormats/TrackFwd.h" + +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/PropagatedFwdTrackTables.h" +#include "Common/Core/fwdtrackUtilities.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::fwdtrackutils; + +struct FwdTrackPropagation { + using MyFwdTracks = soa::Join; + + Produces propfwdtracks; + Produces propfwdtrackscov; + + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable fillQAHistograms{"fillQAHistograms", true, "flag to fill QA histograms"}; + Configurable minPt{"minPt", 0.2, "min pt for muon"}; + Configurable maxPt{"maxPt", 1e+10, "max pt for muon"}; + Configurable minEtaSA{"minEtaSA", -4.0, "min. eta acceptance for MCH-MID"}; + Configurable maxEtaSA{"maxEtaSA", -2.5, "max. eta acceptance for MCH-MID"}; + Configurable minEtaGL{"minEtaGL", -3.6, "min. eta acceptance for MFT-MCH-MID"}; + Configurable maxEtaGL{"maxEtaGL", -2.5, "max. eta acceptance for MFT-MCH-MID"}; + Configurable minRabsGL{"minRabsGL", 27.6, "min. R at absorber end for global muon (min. eta = -3.6)"}; // std::tan(2.f * std::atan(std::exp(- -3.6)) ) * -505. + Configurable minRabs{"minRabs", 17.6, "min. R at absorber end"}; + Configurable midRabs{"midRabs", 26.5, "middle R at absorber end for pDCA cut"}; + Configurable maxRabs{"maxRabs", 89.5, "max. R at absorber end"}; + Configurable maxDCAxy{"maxDCAxy", 1e+10, "max. DCAxy for global muons"}; + Configurable maxPDCAforLargeR{"maxPDCAforLargeR", 324.f, "max. pDCA for large R at absorber end"}; + Configurable maxPDCAforSmallR{"maxPDCAforSmallR", 594.f, "max. pDCA for small R at absorber end"}; + Configurable maxMatchingChi2MCHMFT{"maxMatchingChi2MCHMFT", 50.f, "max. chi2 for MCH-MFT matching"}; + Configurable maxChi2SA{"maxChi2SA", 1e+6, "max. chi2 for standalone muon"}; + Configurable maxChi2GL{"maxChi2GL", 50.f, "max. chi2 for global muon"}; + Configurable refitGlobalMuon{"refitGlobalMuon", true, "flag to refit global muon"}; + + HistogramRegistry fRegistry{"fRegistry"}; + static constexpr std::string_view muon_types[5] = {"MFTMCHMID/", "MFTMCHMIDOtherMatch/", "MFTMCH/", "MCHMID/", "MCH/"}; + + void init(o2::framework::InitContext&) + { + if (doprocessWithoutFTTCA && doprocessWithFTTCA) { + LOGF(fatal, "Cannot enable doprocessWithoutFTTCA and doprocessWithFTTCA at the same time. Please choose one."); + } + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + ccdbApi.init(ccdburl); + + if (fillQAHistograms) { + addHistograms(); + } + } + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + int mRunNumber = -1; + + template + void initCCDB(TBC const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + LOGF(info, "mRunNumber = %d", mRunNumber); + std::map metadata; + auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, mRunNumber); + auto ts = soreor.first; + auto grpmag = ccdbApi.retrieveFromTFileAny(grpmagPath, metadata, ts); + o2::base::Propagator::initFieldFromGRP(grpmag); + if (!o2::base::GeometryManager::isGeometryLoaded()) { + ccdb->get(geoPath); + } + o2::mch::TrackExtrap::setField(); + } + + void addHistograms() + { + auto hMuonType = fRegistry.add("hMuonType", "muon type", kTH1F, {{5, -0.5f, 4.5f}}, false); + hMuonType->GetXaxis()->SetBinLabel(1, "MFT-MCH-MID (global muon)"); + hMuonType->GetXaxis()->SetBinLabel(2, "MFT-MCH-MID (global muon other match)"); + hMuonType->GetXaxis()->SetBinLabel(3, "MFT-MCH"); + hMuonType->GetXaxis()->SetBinLabel(4, "MCH-MID"); + hMuonType->GetXaxis()->SetBinLabel(5, "MCH standalone"); + + fRegistry.add("MFTMCHMID/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{100, 0.0f, 10}}, false); + fRegistry.add("MFTMCHMID/hRelDiffPt", "pT resolution;p_{T} (GeV/c);#Deltap_{T}/p_{T}", kTH2F, {{100, 0.0f, 10}, {200, 0, 0.2}}, false); + fRegistry.add("MFTMCHMID/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {60, -5.f, -2.f}}, false); + fRegistry.add("MFTMCHMID/hEtaPhi_MatchedMCHMID", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {60, -5.f, -2.f}}, false); + fRegistry.add("MFTMCHMID/hDiffCollId", "difference in collision index;collisionId_{TTCA} - collisionId_{MP}", kTH1F, {{41, -20.5, +20.5}}, false); + fRegistry.add("MFTMCHMID/hSign", "sign;sign", kTH1F, {{3, -1.5, +1.5}}, false); + fRegistry.add("MFTMCHMID/hNclusters", "Nclusters;Nclusters", kTH1F, {{21, -0.5f, 20.5}}, false); + fRegistry.add("MFTMCHMID/hNclustersMFT", "NclustersMFT;Nclusters MFT", kTH1F, {{11, -0.5f, 10.5}}, false); + fRegistry.add("MFTMCHMID/hRatAbsorberEnd", "R at absorber end;R at absorber end (cm)", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("MFTMCHMID/hPDCA_Rabs", "pDCA vs. Rabs;R at absorber end (cm);p #times DCA (GeV/c #upoint cm)", kTH2F, {{100, 0, 100}, {100, 0.0f, 1000}}, false); + fRegistry.add("MFTMCHMID/hChi2", "chi2;chi2", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("MFTMCHMID/hChi2MFT", "chi2 MFT;chi2 MFT", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("MFTMCHMID/hChi2MatchMCHMID", "chi2 match MCH-MID;chi2", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("MFTMCHMID/hChi2MatchMCHMFT", "chi2 match MCH-MFT;chi2", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("MFTMCHMID/hMatchScoreMCHMFT", "match score MCH-MFT;score", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("MFTMCHMID/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", kTH2F, {{200, -0.5, 0.5}, {200, -0.5, +0.5}}, false); + fRegistry.add("MFTMCHMID/hDCAxy2DinSigma", "DCA x vs. y in sigma;DCA_{x} (#sigma);DCA_{y} (#sigma)", kTH2F, {{200, -10, 10}, {200, -10, +10}}, false); + fRegistry.add("MFTMCHMID/hDCAxy", "DCAxy;DCA_{xy} (cm);", kTH1F, {{100, 0, 1}}, false); + fRegistry.add("MFTMCHMID/hDCAxyinSigma", "DCAxy in sigma;DCA_{xy} (#sigma);", kTH1F, {{100, 0, 10}}, false); + fRegistry.addClone("MFTMCHMID/", "MCHMID/"); + fRegistry.add("MFTMCHMID/hDCAxResolutionvsPt", "DCA_{x} vs. p_{T};p_{T} (GeV/c);DCA_{x} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 500}}, false); + fRegistry.add("MFTMCHMID/hDCAyResolutionvsPt", "DCA_{y} vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 500}}, false); + fRegistry.add("MCHMID/hDCAxResolutionvsPt", "DCA_{x} vs. p_{T};p_{T} (GeV/c);DCA_{x} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 5e+5}}, false); + fRegistry.add("MCHMID/hDCAyResolutionvsPt", "DCA_{y} vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 5e+5}}, false); + } + + bool isSelected(const float pt, const float eta, const float rAtAbsorberEnd, const float pDCA, const float chi2, const uint8_t trackType, const float dcaXY) + { + if (pt < minPt || maxPt < pt) { + return false; + } + if (rAtAbsorberEnd < minRabs || maxRabs < rAtAbsorberEnd) { + return false; + } + if (rAtAbsorberEnd < midRabs ? pDCA > maxPDCAforSmallR : pDCA > maxPDCAforLargeR) { + return false; + } + + if (trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + if (eta < minEtaGL || maxEtaGL < eta) { + return false; + } + if (maxDCAxy < dcaXY) { + return false; + } + if (chi2 < 0.f || maxChi2GL < chi2) { + return false; + } + if (rAtAbsorberEnd < minRabsGL || maxRabs < rAtAbsorberEnd) { + return false; + } + } else if (trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + if (eta < minEtaSA || maxEtaSA < eta) { + return false; + } + if (chi2 < 0.f || maxChi2SA < chi2) { + return false; + } + } else { + return false; + } + + return true; + } + + template + void fillFwdTrackTable(TCollision const& collision, TFwdTrack fwdtrack, TFwdTracks const&, TMFTTracks const&, const bool isAmbiguous) + { + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && (fwdtrack.chi2MatchMCHMFT() > maxMatchingChi2MCHMFT || fwdtrack.chi2() > maxChi2GL)) { + return; + } // Users have to decide the best match between MFT and MCH-MID at analysis level. The same global muon is repeatedly stored. + + if (fwdtrack.chi2MatchMCHMID() < 0.f) { // this should never happen. only for protection. + return; + } + + o2::dataformats::GlobalFwdTrack propmuonAtPV = propagateMuon(fwdtrack, collision, propagationPoint::kToVertex); + o2::dataformats::GlobalFwdTrack propmuonAtDCA = propagateMuon(fwdtrack, collision, propagationPoint::kToDCA); + + float pt = propmuonAtPV.getPt(); + float eta = propmuonAtPV.getEta(); + float phi = propmuonAtPV.getPhi(); + float tgl = propmuonAtPV.getTgl(); + o2::math_utils::bringTo02Pi(phi); + + float cXXatDCA = propmuonAtDCA.getSigma2X(); + float cYYatDCA = propmuonAtDCA.getSigma2Y(); + float cXYatDCA = propmuonAtDCA.getSigmaXY(); + + float dcaX = propmuonAtDCA.getX() - collision.posX(); + float dcaY = propmuonAtDCA.getY() - collision.posY(); + float rAtAbsorberEnd = fwdtrack.rAtAbsorberEnd(); // this works only for GlobalMuonTrack + float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); + + float dFdx = 2.f * dcaX / dcaXY; + float dFdy = 2.f * dcaY / dcaXY; + float sigma_dcaXY = std::sqrt(cXXatDCA * dFdx * dFdx + cYYatDCA * dFdy * dFdy + 2.f * cXYatDCA * dFdx * dFdy); + + float pDCA = fwdtrack.p() * dcaXY; + int nClustersMFT = 0; + float etaMatchedMCHMID = propmuonAtPV.getEta(); + float phiMatchedMCHMID = propmuonAtPV.getPhi(); + o2::math_utils::bringTo02Pi(phiMatchedMCHMID); + float x = fwdtrack.x(); + float y = fwdtrack.y(); + float z = fwdtrack.z(); + float chi2mft = 0.f; + + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + const auto& mchtrack = fwdtrack.template matchMCHTrack_as(); // MCH-MID + o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(mchtrack, collision, propagationPoint::kToVertex); + etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); + phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); + o2::math_utils::bringTo02Pi(phiMatchedMCHMID); + o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = propagateMuon(mchtrack, collision, propagationPoint::kToDCA); + float dcaX_Matched = propmuonAtDCA_Matched.getX() - collision.posX(); + float dcaY_Matched = propmuonAtDCA_Matched.getY() - collision.posY(); + float dcaXY_Matched = std::sqrt(dcaX_Matched * dcaX_Matched + dcaY_Matched * dcaY_Matched); + pDCA = mchtrack.p() * dcaXY_Matched; + + const auto& mfttrack = fwdtrack.template matchMFTTrack_as(); + nClustersMFT = mfttrack.nClusters(); + chi2mft = mfttrack.chi2(); + if (refitGlobalMuon) { + eta = mfttrack.eta(); + phi = mfttrack.phi(); + o2::math_utils::bringTo02Pi(phi); + pt = propmuonAtPV_Matched.getP() * std::sin(2.f * std::atan(std::exp(-eta))); + + x = mfttrack.x(); + y = mfttrack.y(); + z = mfttrack.z(); + tgl = mfttrack.tgl(); + } + } else if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + o2::dataformats::GlobalFwdTrack propmuonAtRabs = propagateMuon(fwdtrack, collision, propagationPoint::kToRabs); // this is necessary only for MuonStandaloneTrack + float xAbs = propmuonAtRabs.getX(); + float yAbs = propmuonAtRabs.getY(); + rAtAbsorberEnd = std::sqrt(xAbs * xAbs + yAbs * yAbs); // Redo propagation only for muon tracks // propagation of MFT tracks alredy done in reconstruction + } else { + return; + } + + if (!isSelected(pt, eta, rAtAbsorberEnd, pDCA, fwdtrack.chi2(), fwdtrack.trackType(), dcaXY)) { + return; + } + + const auto& fwdcov = propmuonAtPV.getCovariances(); // covatiant matrix at PV + const float sigX = std::sqrt(fwdcov(0, 0)); + const float sigY = std::sqrt(fwdcov(1, 1)); + const float sigPhi = std::sqrt(fwdcov(2, 2)); + const float sigTgl = std::sqrt(fwdcov(3, 3)); + const float sig1Pt = std::sqrt(fwdcov(4, 4)); + const float rhoXY = 128.f * fwdcov(0, 1) / (sigX * sigY); + const float rhoPhiX = 128.f * fwdcov(0, 2) / (sigPhi * sigX); + const float rhoPhiY = 128.f * fwdcov(1, 2) / (sigPhi * sigY); + const float rhoTglX = 128.f * fwdcov(0, 3) / (sigTgl * sigX); + const float rhoTglY = 128.f * fwdcov(1, 3) / (sigTgl * sigY); + const float rhoTglPhi = 128.f * fwdcov(2, 3) / (sigTgl * sigPhi); + const float rho1PtX = 128.f * fwdcov(0, 4) / (sig1Pt * sigX); + const float rho1PtY = 128.f * fwdcov(1, 4) / (sig1Pt * sigY); + const float rho1PtPhi = 128.f * fwdcov(2, 4) / (sig1Pt * sigPhi); + const float rho1PtTgl = 128.f * fwdcov(3, 4) / (sig1Pt * sigTgl); + + bool isAssociatedToMPC = fwdtrack.collisionId() == collision.globalIndex(); + // LOGF(info, "isAmbiguous = %d, isAssociatedToMPC = %d, fwdtrack.globalIndex() = %d, fwdtrack.collisionId() = %d, collision.globalIndex() = %d", isAmbiguous, isAssociatedToMPC, fwdtrack.globalIndex(), fwdtrack.collisionId(), collision.globalIndex()); + + propfwdtracks( + collision.globalIndex(), fwdtrack.trackType(), + x, y, z, phi, tgl, + fwdtrack.sign() / pt, fwdtrack.nClusters(), pDCA, rAtAbsorberEnd, + fwdtrack.chi2(), fwdtrack.chi2MatchMCHMID(), fwdtrack.chi2MatchMCHMFT(), + fwdtrack.matchScoreMCHMFT(), fwdtrack.globalIndex(), fwdtrack.matchMFTTrackId(), fwdtrack.matchMCHTrackId(), + fwdtrack.mchBitMap(), fwdtrack.midBitMap(), fwdtrack.midBoards(), fwdtrack.trackTime(), fwdtrack.trackTimeRes(), dcaX, dcaY, + cXXatDCA, cYYatDCA, cXYatDCA, etaMatchedMCHMID, phiMatchedMCHMID, isAssociatedToMPC, isAmbiguous); + + propfwdtrackscov( + sigX, sigY, sigPhi, sigTgl, sig1Pt, + rhoXY, rhoPhiX, rhoPhiY, rhoTglX, rhoTglY, + rhoTglPhi, rho1PtX, rho1PtY, rho1PtPhi, rho1PtTgl); + + if (fillQAHistograms) { + fRegistry.fill(HIST("hMuonType"), fwdtrack.trackType()); + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + fRegistry.fill(HIST("MFTMCHMID/hPt"), pt); + fRegistry.fill(HIST("MFTMCHMID/hRelDiffPt"), pt, sig1Pt * pt); + fRegistry.fill(HIST("MFTMCHMID/hEtaPhi"), phi, eta); + fRegistry.fill(HIST("MFTMCHMID/hEtaPhi_MatchedMCHMID"), phiMatchedMCHMID, etaMatchedMCHMID); + fRegistry.fill(HIST("MFTMCHMID/hDiffCollId"), collision.globalIndex() - fwdtrack.collisionId()); + fRegistry.fill(HIST("MFTMCHMID/hSign"), fwdtrack.sign()); + fRegistry.fill(HIST("MFTMCHMID/hNclusters"), fwdtrack.nClusters()); + fRegistry.fill(HIST("MFTMCHMID/hNclustersMFT"), nClustersMFT); + fRegistry.fill(HIST("MFTMCHMID/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); + fRegistry.fill(HIST("MFTMCHMID/hRatAbsorberEnd"), rAtAbsorberEnd); + fRegistry.fill(HIST("MFTMCHMID/hChi2"), fwdtrack.chi2()); + fRegistry.fill(HIST("MFTMCHMID/hChi2MFT"), chi2mft); + fRegistry.fill(HIST("MFTMCHMID/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); + fRegistry.fill(HIST("MFTMCHMID/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); + fRegistry.fill(HIST("MFTMCHMID/hMatchScoreMCHMFT"), fwdtrack.matchScoreMCHMFT()); + fRegistry.fill(HIST("MFTMCHMID/hDCAxy2D"), dcaX, dcaY); + fRegistry.fill(HIST("MFTMCHMID/hDCAxy2DinSigma"), dcaX / std::sqrt(cXXatDCA), dcaY / std::sqrt(cYYatDCA)); + fRegistry.fill(HIST("MFTMCHMID/hDCAxy"), dcaXY); + fRegistry.fill(HIST("MFTMCHMID/hDCAxyinSigma"), dcaXY / sigma_dcaXY); + fRegistry.fill(HIST("MFTMCHMID/hDCAxResolutionvsPt"), pt, std::sqrt(cXXatDCA) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/hDCAyResolutionvsPt"), pt, std::sqrt(cYYatDCA) * 1e+4); // convert cm to um + } else if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + fRegistry.fill(HIST("MCHMID/hPt"), pt); + fRegistry.fill(HIST("MCHMID/hRelDiffPt"), pt, sig1Pt * pt); + fRegistry.fill(HIST("MCHMID/hEtaPhi"), phi, eta); + fRegistry.fill(HIST("MCHMID/hEtaPhi_MatchedMCHMID"), phiMatchedMCHMID, etaMatchedMCHMID); + fRegistry.fill(HIST("MCHMID/hDiffCollId"), collision.globalIndex() - fwdtrack.collisionId()); + fRegistry.fill(HIST("MCHMID/hSign"), fwdtrack.sign()); + fRegistry.fill(HIST("MCHMID/hNclusters"), fwdtrack.nClusters()); + fRegistry.fill(HIST("MCHMID/hNclustersMFT"), nClustersMFT); + fRegistry.fill(HIST("MCHMID/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); + fRegistry.fill(HIST("MCHMID/hRatAbsorberEnd"), rAtAbsorberEnd); + fRegistry.fill(HIST("MCHMID/hChi2"), fwdtrack.chi2()); + fRegistry.fill(HIST("MCHMID/hChi2MFT"), chi2mft); + fRegistry.fill(HIST("MCHMID/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); + fRegistry.fill(HIST("MCHMID/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); + fRegistry.fill(HIST("MCHMID/hMatchScoreMCHMFT"), fwdtrack.matchScoreMCHMFT()); + fRegistry.fill(HIST("MCHMID/hDCAxy2D"), dcaX, dcaY); + fRegistry.fill(HIST("MCHMID/hDCAxy2DinSigma"), dcaX / std::sqrt(cXXatDCA), dcaY / std::sqrt(cYYatDCA)); + fRegistry.fill(HIST("MCHMID/hDCAxy"), dcaXY); + fRegistry.fill(HIST("MCHMID/hDCAxyinSigma"), dcaXY / sigma_dcaXY); + fRegistry.fill(HIST("MCHMID/hDCAxResolutionvsPt"), pt, std::sqrt(cXXatDCA) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MCHMID/hDCAyResolutionvsPt"), pt, std::sqrt(cYYatDCA) * 1e+4); // convert cm to um + } + } + } + + SliceCache cache; + PresliceUnsorted perMFTTrack = o2::aod::fwdtrack::matchMFTTrackId; + Preslice perCollision = o2::aod::fwdtrack::collisionId; + // Preslice perCollisionMFT = o2::aod::fwdtrack::collisionId; + Preslice fwdtrackIndicesPerCollision = aod::track_association::collisionId; + PresliceUnsorted fwdtrackIndicesPerFwdTrack = aod::track_association::fwdtrackId; + + void processWithoutFTTCA(aod::Collisions const& collisions, MyFwdTracks const& fwdtracks, aod::MFTTracks const& mfttracks, aod::BCsWithTimestamps const&) + { + for (const auto& collision : collisions) { + const auto& bc = collision.template bc_as(); + initCCDB(bc); + + const auto& fwdtracks_per_coll = fwdtracks.sliceBy(perCollision, collision.globalIndex()); + for (const auto& fwdtrack : fwdtracks_per_coll) { + if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + continue; + } + fillFwdTrackTable(collision, fwdtrack, fwdtracks, mfttracks, false); + } // end of fwdtrack loop + } // end of collision loop + } + PROCESS_SWITCH(FwdTrackPropagation, processWithoutFTTCA, "process without FTTCA", true); + + void processWithFTTCA(aod::Collisions const& collisions, MyFwdTracks const& fwdtracks, aod::MFTTracks const& mfttracks, aod::BCsWithTimestamps const&, aod::FwdTrackAssoc const& fwdtrackIndices) + { + std::unordered_map mapAmb; // fwdtrack.globalIndex() -> bool isAmb; + for (const auto& fwdtrack : fwdtracks) { + const auto& fwdtrackIdsPerFwdTrack = fwdtrackIndices.sliceBy(fwdtrackIndicesPerFwdTrack, fwdtrack.globalIndex()); + mapAmb[fwdtrack.globalIndex()] = fwdtrackIdsPerFwdTrack.size() > 1; + // LOGF(info, "fwdtrack.globalIndex() = %d, ntimes = %d, isAmbiguous = %d", fwdtrack.globalIndex(), fwdtrackIdsPerFwdTrack.size(), mapAmb[fwdtrack.globalIndex()]); + } // end of fwdtrack loop + + for (const auto& collision : collisions) { + const auto& bc = collision.template bc_as(); + initCCDB(bc); + + const auto& fwdtrackIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); + for (const auto& fwdtrackId : fwdtrackIdsThisCollision) { + const auto& fwdtrack = fwdtrackId.template fwdtrack_as(); + if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + continue; + } + fillFwdTrackTable(collision, fwdtrack, fwdtracks, mfttracks, mapAmb[fwdtrack.globalIndex()]); + } // end of fwdtrack loop + } // end of collision loop + mapAmb.clear(); + } + PROCESS_SWITCH(FwdTrackPropagation, processWithFTTCA, "process with FTTCA", false); +}; + +// Extends the PropagatedFwdTracks table for expression columns +struct PropagatedFwdTrackSpawner { + Spawns propFwdTracks; + Spawns propFwdTracksCov; + void init(InitContext const&) {} +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"fwdtrack-propagation"}), + adaptAnalysisTask(cfgc, TaskName{"propagated-fwdtrack-spawner"}), + }; +} diff --git a/Common/TableProducer/match-mft-ft0.cxx b/Common/TableProducer/match-mft-ft0.cxx new file mode 100644 index 00000000000..a4b208a03c9 --- /dev/null +++ b/Common/TableProducer/match-mft-ft0.cxx @@ -0,0 +1,545 @@ +// 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 match-mft-ft0.cxx +// \author Sarah Herrmann +// +// \brief This code loops over every MFT tracks (except orphan tracks) and propagates +// them to the FT0-C, matching the signals in some BC to reduce track ambiguity +// It produces a table containing for each MFT track a list of BCs with an FT0C match +// called aod::BCofMFT +// \date 03/09/24 + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" + +#include "MathUtils/Utils.h" +#include "CommonConstants/LHCConstants.h" +#include "Common/Core/trackUtilities.h" //for getTrackPar() +#include "ReconstructionDataFormats/TrackFwd.h" //for propagate +// https://github.com/AliceO2Group/AliceO2/blob/dev/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackFwd.h +#include "CommonConstants/LHCConstants.h" +#include "Math/MatrixFunctions.h" +#include "Math/SMatrix.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" + +#include "DataFormatsParameters/GRPMagField.h" +#include "DetectorsBase/GeometryManager.h" +#include "Field/MagneticField.h" +#include "TGeoGlobalMagField.h" + +#include "DataFormatsParameters/GRPMagField.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" + +#include "Common/DataModel/MatchMFTFT0.h" + +using SMatrix55 = ROOT::Math::SMatrix>; +using SMatrix5 = ROOT::Math::SVector; + +using namespace o2; +using namespace o2::framework; + +// Creating a table BC to FT0 and filling it +struct bctoft0c { + Produces mf; + struct { + std::vector ft0ids; + } filler; + void process(aod::BCs::iterator const& bc, soa::SmallGroups const& ft0s) + { + filler.ft0ids.clear(); + for (auto const& ft0 : ft0s) { + filler.ft0ids.emplace_back(ft0.globalIndex()); + } + mf(bc.globalIndex(), filler.ft0ids); + } +}; + +using ExtBCs = soa::Join; + +template +T getCompatibleBCs(aod::AmbiguousMFTTrack const& atrack, aod::Collision const& collOrig, T const& bcs, int deltaBC) +{ + // this method is unused for now, MFTtracks with no collisions (orphan tracks) are not considered for the matching with FT0C + auto compBCs = atrack.bc_as(); // BC + info on FT0 + auto bcIter = compBCs.begin(); // first element of compBC + uint64_t firstBC = bcIter.globalBC(); + + bcIter.moveToEnd(); // does it move to the end or the next one after the end ? + --bcIter; // to avoid a seg fault + uint64_t lastBC = bcIter.globalBC(); // gives the last COMPATIBLE BC in compBCs + + auto bcIt = collOrig.bc_as(); + + int64_t minBCId = bcIt.globalIndex(); + auto minGlobalBC = bcIt.globalBC(); + + if (bcIt.globalBC() < firstBC + deltaBC) { + while (bcIt != bcs.end() && bcIt.globalBC() < firstBC + deltaBC) { + minBCId = bcIt.globalIndex(); + minGlobalBC = bcIt.globalBC(); + + ++bcIt; + } + if (bcIt == bcs.end()) { + --bcIt; + minBCId = bcIt.globalIndex(); + minGlobalBC = bcIt.globalBC(); + } + } else { + // here bcIt.globalBC() >= firstBC + deltaBC + + while (bcIt != bcs.begin() && bcIt.globalBC() > firstBC + deltaBC) { + minBCId = bcIt.globalIndex(); + minGlobalBC = bcIt.globalBC(); + + --bcIt; + } + } + + int64_t maxBCId = bcIt.globalIndex(); + + while (bcIt != bcs.end() && bcIt.globalBC() < lastBC + deltaBC) { + maxBCId = bcIt.globalIndex(); + + ++bcIt; + } + + if (bcIt != bcs.end() && maxBCId >= minBCId) { + T slice{{bcs.asArrowTable()->Slice(minBCId, maxBCId - minBCId + 1)}, (uint64_t)minBCId}; + bcs.copyIndexBindings(slice); + return slice; + } else { + T slice{{bcs.asArrowTable()->Slice(minBCId, maxBCId - minBCId)}, (uint64_t)minBCId}; + bcs.copyIndexBindings(slice); + return slice; + } +} + +template +T getCompatibleBCs(aod::MFTTracks::iterator const& track, aod::Collision const& collOrig, T const& bcs, int deltaBC) +{ + + // define firstBC and lastBC (globalBC of beginning and end of the range, when no shift is applied) + + auto bcIt = collOrig.bc_as(); + // auto timstp = bcIt.timestamp(); + + int64_t firstBC = bcIt.globalBC() + (track.trackTime() - track.trackTimeRes()) / o2::constants::lhc::LHCBunchSpacingNS; + int64_t lastBC = firstBC + 2 * track.trackTimeRes() / o2::constants::lhc::LHCBunchSpacingNS + 1; // to have a delta = 198 BC + + // printf(">>>>>>>>>>>>>>>>>>>>>>>>>>> last-first %lld\n", lastBC-firstBC); + + // int collTimeResInBC = collOrig.collisionTimeRes()/o2::constants::lhc::LHCBunchSpacingNS; + + // int64_t collFirstBC = bcIt.globalBC() + (collOrig.collisionTime() - collOrig.collisionTimeRes())/o2::constants::lhc::LHCBunchSpacingNS; + // int64_t collLastBC = collFirstBC + 2*collOrig.collisionTimeRes()/o2::constants::lhc::LHCBunchSpacingNS +1; + + int64_t minBCId = bcIt.globalIndex(); + + if ((int64_t)bcIt.globalBC() < firstBC + deltaBC) { + while (bcIt != bcs.end() && (int64_t)bcIt.globalBC() < firstBC + deltaBC) { + minBCId = bcIt.globalIndex(); + + ++bcIt; + } + if (bcIt == bcs.end()) { + --bcIt; + // allows to avoid bcIt==bcs.end() in the following + } + // minGlobalBC needs to be >= to firstBC+deltaBC + minBCId = bcIt.globalIndex(); + + } else { + // here bcIt.globalBC() >= firstBC + deltaBC + + while (bcIt != bcs.begin() && (int64_t)bcIt.globalBC() >= (int64_t)firstBC + deltaBC) { + minBCId = bcIt.globalIndex(); + --bcIt; + } + if (bcIt == bcs.begin() && (int64_t)bcIt.globalBC() >= (int64_t)firstBC + deltaBC) { + minBCId = bcIt.globalIndex(); + } + ++bcIt; // retrieve the pointer which gave minBCId and minGlobalBC + if (bcIt == bcs.end()) { + --bcIt; // go back if we got to the end of the list + } + } + + int64_t maxBCId = bcIt.globalIndex(); + + if ((int64_t)bcIt.globalBC() > (int64_t)lastBC + deltaBC) { + // the previous minimum is actually bigger than the right boundary + + if (bcIt != bcs.begin()) { + --bcIt; // let's check the previous element in the BC list + if ((int64_t)bcIt.globalBC() < (int64_t)firstBC + deltaBC) // if this previous element is smaller than the left boundary + { + // means that the slice of compatible BCs is empty + + T slice{{bcs.asArrowTable()->Slice(0, 0)}, (uint64_t)0}; + // bcs.copyIndexBindings(slice); REMOVED IT BECAUSE I DON'T KNOW WHAT IT DOES HERE + return slice; // returns an empty slice + } + } + } + + if ((int64_t)bcIt.globalBC() < (int64_t)firstBC + deltaBC) { + // the previous minimum is actually smaller than the right boundary + ++bcIt; + + if (bcIt != bcs.end() && ((int64_t)bcIt.globalBC() > (int64_t)lastBC + deltaBC)) { + // check the following element + + T slice{{bcs.asArrowTable()->Slice(0, 0)}, (uint64_t)0}; + // bcs.copyIndexBindings(slice); REMOVED IT BECAUSE I DON'T KNOW WHAT IT DOES HERE + return slice; // returns an empty slice + } + } + + while (bcIt != bcs.end() && (int64_t)bcIt.globalBC() <= (int64_t)lastBC + deltaBC) { + maxBCId = bcIt.globalIndex(); + + ++bcIt; + } + + if (maxBCId < minBCId) { + if (bcIt == bcs.end()) { + printf("at the end of the bcs iterator %d\n", 1); + } + T slice{{bcs.asArrowTable()->Slice(0, 0)}, (uint64_t)0}; + // bcs.copyIndexBindings(slice); REMOVED IT BECAUSE I DON'T KNOW WHAT IT DOES HERE + return slice; // returns an empty slice + } + + T slice{{bcs.asArrowTable()->Slice(minBCId, maxBCId - minBCId + 1)}, (uint64_t)minBCId}; + bcs.copyIndexBindings(slice); + return slice; +} + +struct matchmftft0 { + Produces BcMft; + struct { + std::vector BCids; + } filler; + + Service ccdb; + + int runNumber = -1; + float Bz = 0; // Magnetic field for MFT + static constexpr double centerMFT[3] = {0, 0, -61.4}; // Field at center of MFT + int count = 0; + o2::parameters::GRPMagField* grpmag = nullptr; + + Configurable strictBCSel{"strictBCSel", false, "force the BC of the match to have FT0A&C signals"}; + Configurable shiftBC{"shiftBC", 0, "shift in BC wrt normal"}; // should be kept at zero except if the time-alignment MFT-FT0C must be redone + + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + + std::vector> channelCoord = {{103.2, 17.8, -813.1}, {76.9, 17.8, -815.9}, {103.1, 44.2, -812.1}, {76.8, 44.2, -814.9}, {103.2, 78.7, -810}, {76.8, 79, -812.9}, {103.2, 105, -807.1}, {76.8, 105.3, -810}, {43.2, 78.8, -815}, {43.2, 105.1, -812.1}, {16.8, 78.9, -815.9}, {16.8, 105.2, -813}, {-16.8, 105.2, -813}, {-16.8, 78.9, -815.9}, {-43.2, 105.1, -812.1}, {-43.2, 78.8, -815}, {-76.8, 105.3, -810}, {-76.8, 79, -812.9}, {-103.2, 105, -807.1}, {-103.2, 78.7, -810}, {-76.8, 44.2, -814.9}, {-103.1, 44.2, -812.1}, {-76.9, 17.8, -815.9}, {-103.2, 17.8, -813.1}, {-103.2, -17.8, -813.1}, {-76.9, -17.8, -815.9}, {-103.1, -44.2, -812.1}, {-76.8, -44.2, -814.9}, {-103.2, -78.7, -810}, {-76.8, -79, -812.9}, {-103.2, -105, -807.1}, {-76.8, -105.3, -810}, {-43.2, -78.8, -815}, {-43.2, -105.1, -812.1}, {-16.8, -78.9, -815.9}, {-16.8, -105.2, -813}, {16.8, -105.2, -813}, {16.8, -78.9, -815.9}, {43.2, -105.1, -812.1}, {43.2, -78.8, -815}, {76.8, -105.3, -810}, {76.8, -79, -812.9}, {103.2, -105, -807.1}, {103.2, -78.7, -810}, {76.8, -44.2, -814.9}, {103.1, -44.2, -812.1}, {76.9, -17.8, -815.9}, {103.2, -17.8, -813.1}, {163, 18.7, -804.1}, {137, 18.9, -808.9}, {163, 45.2, -803.1}, {137, 45.3, -807.9}, {163, 78.6, -800.1}, {137, 79.1, -804.9}, {163, 104.9, -797.2}, {137, 105.4, -801.9}, {103.4, 138, -802}, {102.9, 164, -797.2}, {77.1, 138, -804.9}, {76.6, 164, -800}, {43.3, 139, -807}, {43.2, 165, -802.1}, {16.9, 139, -807.9}, {16.7, 165, -803}, {-16.7, 165, -803}, {-16.9, 139, -807.9}, {-43.2, 165, -802.1}, {-43.3, 139, -807}, {-76.6, 164, -800}, {-77.1, 138, -804.9}, {-102.9, 164, -797.2}, {-103.4, 138, -802}, {-137, 105.4, -801.9}, {-163, 104.9, -797.2}, {-137, 79.1, -804.9}, {-163, 78.6, -800.1}, {-137, 45.3, -807.9}, {-163, 45.2, -803.1}, {-137, 18.9, -808.9}, {-163, 18.7, -804.1}, {-163, -18.7, -804.1}, {-137, -18.9, -808.9}, {-163, -45.2, -803.1}, {-137, -45.3, -807.9}, {-163, -78.6, -800.1}, {-137, -79.1, -804.9}, {-163, -104.9, -797.2}, {-137, -105.4, -801.9}, {-103.4, -138, -802}, {-102.9, -164, -797.2}, {-77.1, -138, -804.9}, {-76.6, -164, -800}, {-43.3, -139, -807}, {-43.2, -165, -802.1}, {-16.9, -139, -807.9}, {-16.7, -165, -803}, {16.7, -165, -803}, {16.9, -139, -807.9}, {43.2, -165, -802.1}, {43.3, -139, -807}, {76.6, -164, -800}, {77.1, -138, -804.9}, {102.9, -164, -797.2}, {103.4, -138, -802}, {137, -105.4, -801.9}, {163, -104.9, -797.2}, {137, -79.1, -804.9}, {163, -78.6, -800.1}, {137, -45.3, -807.9}, {163, -45.2, -803.1}, {137, -18.9, -808.9}, {163, -18.7, -804.1}}; + + HistogramRegistry registry{ + "registry", + {{"UnMatchedTracksXY", "; #it{x} (cm); #it{y} (cm);", {HistType::kTH2F, {{701, -35.05, 35.05}, {701, -35.05, 35.05}}}}, + {"MatchedTracksXY", "; #it{x} (cm); #it{y} (cm);", {HistType::kTH2F, {{701, -35.05, 35.05}, {701, -35.05, 35.05}}}}, + {"AllTracksXY", "; #it{x} (cm); #it{y} (cm);", {HistType::kTH2F, {{701, -35.05, 35.05}, {701, -35.05, 35.05}}}}, + {"DistChannelToProp", "; D (cm); #count", {HistType::kTH1D, {{101, 0, 100}}}}, + {"NchannelsPerBC", "; N_{channelC}; #count", {HistType::kTH1D, {{101, 0, 100}}}}, + {"NgoodBCperTrack", "; N_{goodBC}; #count", {HistType::kTH1D, {{11, 0, 10}}}}, + {"NgoodBCperTrackINDIV", "; N_{goodBC}; #count", {HistType::kTH1D, {{11, 0, 10}}}}, + {"NCompBCwFT0C", "; N_{compBC}; #count", {HistType::kTH1D, {{21, -0.5, 20.5}}}}, + {"NCompBCwFT0s", "; N_{compBC}; #count", {HistType::kTH1D, {{21, -0.5, 20.5}}}}, + {"DiffInBCINDIV", "; indivBC-firstBC (globalBC); #count", {HistType::kTH1I, {{199, 0, 199}}}}, + {"DiffInBC", "; goodBC-firstBC (globalBC); #count", {HistType::kTH1I, {{199, 0, 199}}}}}}; + + void init(InitContext const&) + { + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + } + + void initCCDB(ExtBCs::iterator const& bc) + { + + if (runNumber == bc.runNumber()) { + return; + } + grpmag = ccdb->getForTimeStamp(grpmagPath, bc.timestamp()); + LOG(info) << "Setting magnetic field to current " << grpmag->getL3Current() + << " A for run " << bc.runNumber() + << " from its GRPMagField CCDB object"; + o2::base::Propagator::initFieldFromGRP(grpmag); // for some reason this is necessary for the next next line + runNumber = bc.runNumber(); + + o2::field::MagneticField* field = static_cast(TGeoGlobalMagField::Instance()->GetField()); + + Bz = field->getBz(centerMFT); // gives error if the propagator is not initFielded + LOG(info) << "The field at the center of the MFT is Bz = " << Bz; + } + + bool isInFT0Acc(double x, double y) + { + // returns true if the propagated x and y positions are in an active zone of the FT0-C, false if they in a dead zone + + if ((abs(x) < 6.365) && (abs(y) < 6.555)) { + // track outside the FT0-C acceptance (in the central hole) + return false; + } + + if (((x > -12.75) && (x < -11.85)) || ((x > -6.55) && (x < -5.75)) || ((x > -0.35) && (x < 0.45)) || ((x > 5.75) && (x < 6.55)) || ((x > 11.85) && (x < 12.75))) { + // track outside the FT0-C acceptance (in the vertical line holes) + return false; + } + + if (((y > -12.95) && (y < -11.95)) || ((y > -6.65) && (y < -5.85)) || ((y > -0.55) && (y < 0.45)) || ((y > 5.75) && (y < 6.65)) || ((y > 11.95) && (y < 12.85))) { + // track outside the FT0-C acceptance (in the horizontal line holes) + return false; + } + + return true; + } + + void processMFT(aod::MFTTracks const& mfttracks, + aod::Collisions const&, ExtBCs const& bcs, + aod::FT0s const&) + { + initCCDB(bcs.begin()); + + int i = 0; // counts the number of channels having non-zero amplitude + // for a particular BC + double D = 0.0; // distance between (xe,ye,ze) and (xc,yc,zc) + double minD; + double globalMinD; + + for (auto& track : mfttracks) { + filler.BCids.clear(); + globalMinD = 999.; // minimum D for all BC + ExtBCs::iterator closestBC; // compatible BC with the D the smallest + // beware: there could be several BC with the same smallest D + // not a very useful variable + + if (!track.has_collision()) { + BcMft(track.globalIndex(), filler.BCids); // empty + continue; + } + auto collOrig = track.collision(); + + auto bcSlice = getCompatibleBCs(track, collOrig, bcs, shiftBC); + + // firstBC= global BC of the beginning of the ROF (shifted by shiftBC) + int64_t firstBC = collOrig.bc_as().globalBC() + (track.trackTime() - track.trackTimeRes()) / o2::constants::lhc::LHCBunchSpacingNS + shiftBC; + + bool rofHasBoth = false; // ROF with both FT0C and FT0A signal in the same BC + + std::vector v1; // Temporary null vector for the computation of the covariance matrix + SMatrix55 tcovs(v1.begin(), v1.end()); + SMatrix5 tpars(track.x(), track.y(), track.phi(), track.tgl(), track.signed1Pt()); + + o2::track::TrackParCovFwd trackPar{track.z(), tpars, tcovs, track.chi2()}; + + // we propagate the MFT track to the mean z position of FT0-C + // getTrackPar() doesn't work because mft tracks don't have alpha + trackPar.propagateToZhelix(-82.6, Bz); // z in cm + + if (!isInFT0Acc(trackPar.getX(), trackPar.getY())) { + // track outside the FT0-C acceptance + BcMft(track.globalIndex(), filler.BCids); // empty + continue; + } + + std::vector goodBC; // contains the BCs matched with the current MFT track + int nCompBCwft0C = 0; + int nCompBCwft0s = 0; // Number of compatible BCs with FT0A AND C signals + + bool hasft0A = false; + bool hasft0C = false; + for (auto& bc : bcSlice) { + hasft0C = false; + hasft0A = false; + // printf("----------bcId %lld\n", bc.globalIndex()); + if (!bc.has_ft0s()) { + continue; + } + + auto ft0s = bc.ft0s(); + i = 0; // reinitialise + D = 0.0; + minD = 999.9; + for (auto const& ft0 : ft0s) { + // printf("---------ft0.bcId %d\n", ft0.bcId()); + if (ft0.channelA().size() > 0) { + // BC with signals in FT0A + hasft0A = true; + } + + if (ft0.channelC().size() > 0) { + hasft0C = true; + } + for (auto channelId : ft0.channelC()) { + + std::vector Xc = channelCoord[channelId]; //(xc,yc,zc) coordinates + // D in cm + D = sqrt(pow(Xc[0] * 0.1 - trackPar.getX(), 2) + pow(Xc[1] * 0.1 - trackPar.getY(), 2) + pow(Xc[2] * 0.1 - 1.87 - trackPar.getZ(), 2)); + // printf("----channelId %u, D %f, n %d\n", channelId, D, n);//should be between 96 and 207 + if (D < minD) { + minD = D; + } + + registry.fill(HIST("DistChannelToProp"), D); + } + + i += ft0.channelC().size(); + } + + registry.fill(HIST("NchannelsPerBC"), i); + if (hasft0C) { + nCompBCwft0C++; // number of compatible BCs that have ft0-C signal + } + + //----------------------- BC selection here ------------------------ + // if strictBCSel true we are only considering BC with signals from both FT0A and FT0C + if (!(hasft0A && hasft0C) && strictBCSel) { + continue; + // we go to the next BC + } + nCompBCwft0s++; + if (hasft0A && hasft0C) { + rofHasBoth = true; + } + + //----------------------- end of BC selection ------------------------ + + if (minD < 2) // 20 mm + { + goodBC.push_back(bc); // goodBC is a vector of bc + filler.BCids.emplace_back(bc.globalIndex()); + } + if (minD < globalMinD) { + globalMinD = minD; + closestBC = bc; + } + } + + if (!rofHasBoth) { + // there isn't a coincidence of FT0A and C inside the considered MFT ROF + // MFT track is probably noise, we don't select it + filler.BCids.clear(); + BcMft(track.globalIndex(), filler.BCids); // empty + continue; + } + registry.fill(HIST("NgoodBCperTrack"), goodBC.size()); + if (goodBC.size() == 0) { + registry.fill(HIST("UnMatchedTracksXY"), trackPar.getX(), trackPar.getY()); + } + if (goodBC.size() > 0) { + registry.fill(HIST("MatchedTracksXY"), trackPar.getX(), trackPar.getY()); + int64_t diff = goodBC[0].globalBC() - firstBC; + registry.fill(HIST("DiffInBC"), diff); + } + registry.fill(HIST("AllTracksXY"), trackPar.getX(), trackPar.getY()); + registry.fill(HIST("NCompBCwFT0C"), nCompBCwft0C); + registry.fill(HIST("NCompBCwFT0s"), nCompBCwft0s); + + if (nCompBCwft0s == 1) { + registry.fill(HIST("NgoodBCperTrackINDIV"), goodBC.size()); + + // position of the goodBC in the ROF for isolated colliding BCs + if (goodBC.size() > 0) { + int64_t diff = goodBC[0].globalBC() - firstBC; + registry.fill(HIST("DiffInBCINDIV"), diff); + } + } + + BcMft(track.globalIndex(), filler.BCids); + } // loop of mfttracks + } + PROCESS_SWITCH(matchmftft0, processMFT, "Process MFT tracks with collisions", true); +}; + +struct checkmatchinmc { + // checks if the matching works as expected in MC + // only doprocessMFTMCcheck==true if you are analysing MC + + HistogramRegistry registryMC{ + "registryMC", + {}}; + + void init(InitContext const&) + { + if (doprocessMFTMCcheck) { + registryMC.add({"TrackIsMatched", "; isMFTTrackMatched; #count", {HistType::kTH1I, {{2, 0, 2}}}}); + registryMC.add({"DiffInBCTrue", "; goodBC-trueBC (globalBC); #count", {HistType::kTH1I, {{800, -400, 400}}}}); + registryMC.add({"TrueBCAmongMatched", "; isTrueBCAmongMatchedOnes; #count", {HistType::kTH1D, {{2, 0, 2}}}}); + } + } + + using MFTTracksLabeledWithFT0 = soa::Join; + + void processMFTMCcheck(MFTTracksLabeledWithFT0 const& mfttracks, + aod::McCollisions const&, ExtBCs const&, aod::McParticles const&) + { + + for (auto& mfttrack : mfttracks) { + + if (!mfttrack.has_bcs()) // mft tracks having a match in FT0-C + { + registryMC.fill(HIST("TrackIsMatched"), 0); + continue; + } + + registryMC.fill(HIST("TrackIsMatched"), 1); // around 50% of all MFT tracks are matched with FT0-C in data + // around 90% of MFT tracks falling in the active FT0-C regions are matched + if (!mfttrack.has_mcParticle()) { + continue; + } + + o2::aod::McParticle particle = mfttrack.mcParticle(); + int64_t trueMFTBC = particle.mcCollision().bc_as().globalBC(); + ; + bool isTrueBCAmongMatchedOnes = false; + + for (auto& bc : mfttrack.bcs_as()) { // + int64_t bcDiffTrue = bc.globalBC() - trueMFTBC; // difference between the muon's BC and the MFT track's BC + registryMC.fill(HIST("DiffInBCTrue"), bcDiffTrue); + if (bcDiffTrue == 0) { + isTrueBCAmongMatchedOnes = true; + } + } + if (isTrueBCAmongMatchedOnes) { + registryMC.fill(HIST("TrueBCAmongMatched"), 1); + } else { + registryMC.fill(HIST("TrueBCAmongMatched"), 0); + } + } + } + PROCESS_SWITCH(checkmatchinmc, processMFTMCcheck, "Process MFT tracks and check matching with MC information", false); + + void processDummy(aod::Collisions const&) + { + // do nothing + } + PROCESS_SWITCH(checkmatchinmc, processDummy, "Do nothing if not MC", true); +}; + +WorkflowSpec + defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/Common/TableProducer/match-mft-mch-data-mc.cxx b/Common/TableProducer/match-mft-mch-data-mc.cxx new file mode 100644 index 00000000000..4a03582489d --- /dev/null +++ b/Common/TableProducer/match-mft-mch-data-mc.cxx @@ -0,0 +1,881 @@ +// 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. +#include +#include +#include +#include +#include + +#include "CCDB/BasicCCDBManager.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/MftmchMatchingML.h" +#include "Common/DataModel/MatchMFTMuonData.h" +#include "Common/Core/trackUtilities.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/AnalysisCut.h" +#include "PWGDQ/Core/AnalysisCompositeCut.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/CutsLibrary.h" +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" +#include "DetectorsVertexing/VertexTrackMatcher.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "ReconstructionDataFormats/VtxTrackIndex.h" +#include "ReconstructionDataFormats/VtxTrackRef.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DetectorsVertexing/PVertexerParams.h" +#include "MathUtils/Primitive2D.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/MatchMFTFT0.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Field/MagneticField.h" +#include "TGeoGlobalMagField.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "EventFiltering/Zorro.h" +#include "ReconstructionDataFormats/TrackFwd.h" +#include "Math/MatrixFunctions.h" +#include "Math/SMatrix.h" +#include "MFTTracking/Tracker.h" +#include "MCHTracking/TrackParam.h" +#include "MCHTracking/TrackExtrap.h" +#include "GlobalTracking/MatchGlobalFwd.h" +#include +#include +#include "TDatabasePDG.h" + +using namespace std; + +using namespace o2; +using namespace o2::soa; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/DataTypes.h" +#include "Framework/runDataProcessing.h" + +using MyCollisions = aod::Collisions; +using MyBCs = soa::Join; +using MyMUONs = soa::Join; +using MyMFTs = soa::Join; + +using MyCollision = MyCollisions::iterator; +using MyBC = MyBCs::iterator; +using MyMUON = MyMUONs::iterator; +using MyMFT = MyMFTs::iterator; + +using SMatrix55 = ROOT::Math::SMatrix>; +using SMatrix5 = ROOT::Math::SVector; + +float mMu = TDatabasePDG::Instance()->GetParticle(13)->Mass(); +int mRunNumber; +/* + TLorentzVector muon1LV; + TLorentzVector muon2LV; + TLorentzVector dimuonLV; +*/ +unordered_map> map_mfttracks; +unordered_map> map_muontracks; +unordered_map map_collisions; +unordered_map map_has_mfttracks_collisions; +unordered_map map_has_muontracks_collisions; +unordered_map map_vtxz; +unordered_map map_nmfttrack; + +struct match_mft_mch_data_mc { + + //// Variables for matching method + Configurable fMatchingMethod{"cfgMatchingMethod", 0, ""}; + + //// Variables for selecting muon tracks + Configurable fEtaMchLow{"cfgEtaMchLow", -4.0f, ""}; + Configurable fEtaMchUp{"cfgEtaMchUp", -2.5f, ""}; + Configurable fRabsLow1{"cfgRabsLow1", 17.6f, ""}; + Configurable fRabsUp1{"cfgRabsUp1", 26.5f, ""}; + Configurable fRabsLow2{"cfgRabsLow2", 26.5f, ""}; + Configurable fRabsUp2{"cfgRabsUp2", 89.5f, ""}; + Configurable fPdcaUp1{"cfgPdcaUp1", 594.f, ""}; + Configurable fPdcaUp2{"cfgPdcaUp2", 324.f, ""}; + Configurable fTrackChi2MchUp{"cfgTrackChi2MchUp", 5.f, ""}; + Configurable fMatchingChi2MchMidUp{"cfgMatchingChi2MchMidUp", 999.f, ""}; + + //// Variables for selecting mft tracks + Configurable fEtaMftLow{"cfgEtaMftlow", -3.6f, ""}; + Configurable fEtaMftUp{"cfgEtaMftup", -2.5f, ""}; + Configurable fTrackNClustMftLow{"cfgTrackNClustMftLow", 7, ""}; + Configurable fTrackChi2MftUp{"cfgTrackChi2MftUp", 999.f, ""}; + + /// Variables to add preselection for the matching table + Configurable fPreselectMatchingX{"cfgPreselectMatchingX", 15.f, ""}; + Configurable fPreselectMatchingY{"cfgPreselectMatchingY", 15.f, ""}; + + /// Variables to event mixing criteria + Configurable fSaveMixedMatchingParamsRate{"cfgSaveMixedMatchingParamsRate", 0.002f, ""}; + Configurable fEventMaxDeltaNMFT{"cfgEventMaxDeltaNMFT", 1, ""}; + Configurable fEventMaxDeltaVtxZ{"cfgEventMaxDeltaVtxZ", 1.f, ""}; + + //// Variables for selecting tag muon + Configurable fTagMassWindowMin{"cfgTagMassWindowMin", 2.8f, ""}; + Configurable fTagMassWindowMax{"cfgTagMassWindowMax", 3.3f, ""}; + + //// Variables for ccdb + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + + //// Variables for Tag matching criteria + Configurable fSigmaXTagMuonCut{"cfgSigmaXTagMuonCut", 1.f, ""}; + Configurable fMeanXTagMuonCut{"cfgMeanXTagMuonCut", 0.f, ""}; + Configurable fSigmaYTagMuonCut{"cfgSigmaYTagMuonCut", 1.f, ""}; + Configurable fMeanYTagMuonCut{"cfgMeanYTagMuonCut", 1.f, ""}; + + Configurable fSigmaEtaTagMuonCut{"cfgSigmaEtaTagMuonCut", 0.2f, ""}; + Configurable fMeanEtaTagMuonCut{"cfgMeanEtaTagMuonCut", 0.f, ""}; + Configurable fSigmaPhiTagMuonCut{"cfgSigmaPhiTagMuonCut", 0.2f, ""}; + Configurable fMeanPhiTagMuonCut{"cfgMeanPhiTagMuonCut", 0.f, ""}; + + template + class FindTagAndProbe + { + private: + o2::dataformats::GlobalFwdTrack muontrack_at_pv[2]; + + TLorentzVector mDimuon; + MUON muontrack1; + MUON muontrack2; + Collision collision; + int tagIdx, probeIdx; + + int16_t mQ; + + inline void fillCovarianceArray(MUON const& muontrack, float cov[15]) const + { + cov[0] = muontrack.cXX(); + cov[1] = muontrack.cXY(); + cov[2] = muontrack.cYY(); + cov[3] = muontrack.cPhiX(); + cov[4] = muontrack.cPhiY(); + cov[5] = muontrack.cPhiPhi(); + cov[6] = muontrack.cTglX(); + cov[7] = muontrack.cTglY(); + cov[8] = muontrack.cTglPhi(); + cov[9] = muontrack.cTglTgl(); + cov[10] = muontrack.c1PtX(); + cov[11] = muontrack.c1PtY(); + cov[12] = muontrack.c1PtPhi(); + cov[13] = muontrack.c1PtTgl(); + cov[14] = muontrack.c1Pt21Pt2(); + } + + inline o2::dataformats::GlobalFwdTrack propagateMUONtoPV(MUON const& muontrack) const + { + const double mz = muontrack.z(); + const double mchi2 = muontrack.chi2(); + const float mx = muontrack.x(); + const float my = muontrack.y(); + const float mphi = muontrack.phi(); + const float mtgl = muontrack.tgl(); + const float m1pt = muontrack.signed1Pt(); + + float cov[15]; + fillCovarianceArray(muontrack, cov); + SMatrix5 tpars(mx, my, mphi, mtgl, m1pt); + SMatrix55 tcovs(cov, cov + 15); + + o2::track::TrackParCovFwd parcovmuontrack{mz, tpars, tcovs, mchi2}; + + o2::dataformats::GlobalFwdTrack gtrack; + gtrack.setParameters(tpars); + gtrack.setZ(parcovmuontrack.getZ()); + gtrack.setCovariances(tcovs); + + o2::globaltracking::MatchGlobalFwd mMatching; + auto mchtrack = mMatching.FwdtoMCH(gtrack); + + o2::mch::TrackExtrap::extrapToVertex(mchtrack, collision.posX(), collision.posY(), collision.posZ(), collision.covXX(), collision.covYY()); + + auto fwdtrack = mMatching.MCHtoFwd(mchtrack); + o2::dataformats::GlobalFwdTrack extrap_muontrack; + extrap_muontrack.setParameters(fwdtrack.getParameters()); + extrap_muontrack.setZ(fwdtrack.getZ()); + extrap_muontrack.setCovariances(fwdtrack.getCovariances()); + + return extrap_muontrack; + } + + inline void setTagAndProbe() + { + if (muontrack1.pt() > muontrack2.pt()) { + tagIdx = 0; + probeIdx = 1; + } else { + tagIdx = 1; + probeIdx = 0; + } + } + + public: + inline FindTagAndProbe(const MUON& muon1, const MUON& muon2, const Collision& coll) + : muontrack_at_pv(), mDimuon(), muontrack1(muon1), muontrack2(muon2), collision(coll), tagIdx(-1), probeIdx(-1), mQ(0) + { + mQ = muontrack1.sign() + muontrack2.sign(); + setTagAndProbe(); + } + + void calcMuonPairAtPV() + { + muontrack_at_pv[0] = propagateMUONtoPV(muontrack1); + muontrack_at_pv[1] = propagateMUONtoPV(muontrack2); + TLorentzVector vMuon1, vMuon2; + vMuon1.SetPtEtaPhiM(muontrack_at_pv[0].getPt(), muontrack_at_pv[0].getEta(), muontrack_at_pv[0].getPhi(), mMu); + vMuon2.SetPtEtaPhiM(muontrack_at_pv[1].getPt(), muontrack_at_pv[1].getEta(), muontrack_at_pv[1].getPhi(), mMu); + mDimuon = vMuon1 + vMuon2; + } + inline int getTagMuonIndex() const { return tagIdx; } + inline int getProbeMuonIndex() const { return probeIdx; } + inline float getMass() const { return mDimuon.M(); } + inline float getPt() const { return mDimuon.Pt(); } + inline float getRap() const { return mDimuon.Rapidity(); } + inline int16_t getCharge() const { return mQ; } + inline const o2::dataformats::GlobalFwdTrack& getMuonAtPV(int idx) const { return muontrack_at_pv[idx]; } + }; // end of class FindTagAndProbe + + template + class MatchingParamsML + { + private: + MUON muontrack; + MFT mfttrack; + Collision collision; + + float mDX, mDY, mDPt, mDPhi, mDEta; + float mGlobalMuonPtAtDCA, mGlobalMuonEtaAtDCA, mGlobalMuonPhiAtDCA, mGlobalMuonDCAx, mGlobalMuonDCAy, mGlobalMuonQ; + int mMatchingType; + + o2::field::MagneticField* fieldB; + o2::globaltracking::MatchGlobalFwd mMatching; + + inline o2::track::TrackParCovFwd propagateMFTtoMatchingPlane() + { + double covArr[15]{0.0}; + SMatrix55 tmftcovs(covArr, covArr + 15); + + SMatrix5 tmftpars(mfttrack.x(), mfttrack.y(), mfttrack.phi(), mfttrack.tgl(), mfttrack.signed1Pt()); + o2::track::TrackParCovFwd extrap_mfttrack{mfttrack.z(), tmftpars, tmftcovs, mfttrack.chi2()}; + + double propVec[3] = {0.}; + float zPlane = 0.f; + if (mMatchingType == MCH_FIRST_CLUSTER) { + propVec[0] = muontrack.x() - mfttrack.x(); + propVec[1] = muontrack.y() - mfttrack.y(); + propVec[2] = muontrack.z() - mfttrack.z(); + zPlane = muontrack.z(); + } else if (mMatchingType == END_OF_ABSORBER || mMatchingType == BEGINING_OF_ABSORBER) { + auto extrap_muontrack = propagateMUONtoMatchingPlane(); + propVec[0] = extrap_muontrack.getX() - mfttrack.x(); + propVec[1] = extrap_muontrack.getY() - mfttrack.y(); + propVec[2] = extrap_muontrack.getZ() - mfttrack.z(); + zPlane = (mMatchingType == END_OF_ABSORBER) ? -505.f : -90.f; + } else { + zPlane = mfttrack.z(); + } + + double centerZ[3] = {mfttrack.x() + propVec[0] / 2., mfttrack.y() + propVec[1] / 2., mfttrack.z() + propVec[2] / 2.}; + float Bz = fieldB->getBz(centerZ); + extrap_mfttrack.propagateToZ(zPlane, Bz); // z in cm + return extrap_mfttrack; + } + + inline o2::dataformats::GlobalFwdTrack propagateMUONtoMatchingPlane() + { + float cov[15] = { + muontrack.cXX(), muontrack.cXY(), muontrack.cYY(), + muontrack.cPhiX(), muontrack.cPhiY(), muontrack.cPhiPhi(), + muontrack.cTglX(), muontrack.cTglY(), muontrack.cTglPhi(), + muontrack.cTglTgl(), muontrack.c1PtX(), muontrack.c1PtY(), + muontrack.c1PtPhi(), muontrack.c1PtTgl(), muontrack.c1Pt21Pt2()}; + + SMatrix5 tpars(muontrack.x(), muontrack.y(), muontrack.phi(), muontrack.tgl(), muontrack.signed1Pt()); + SMatrix55 tcovs(cov, cov + 15); + double chi2 = muontrack.chi2(); + + o2::track::TrackParCovFwd parcovmuontrack{muontrack.z(), tpars, tcovs, chi2}; + + o2::dataformats::GlobalFwdTrack gtrack; + gtrack.setParameters(tpars); + gtrack.setZ(parcovmuontrack.getZ()); + gtrack.setCovariances(tcovs); + + auto mchtrack = mMatching.FwdtoMCH(gtrack); + + if (mMatchingType == MFT_LAST_CLUSTR) { + o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchtrack, mfttrack.z()); + } else if (mMatchingType == END_OF_ABSORBER) { + o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchtrack, -505.); + } else if (mMatchingType == BEGINING_OF_ABSORBER) { + o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchtrack, -90.); + } + + auto fwdtrack = mMatching.MCHtoFwd(mchtrack); + + o2::dataformats::GlobalFwdTrack extrap_muontrack; + extrap_muontrack.setParameters(fwdtrack.getParameters()); + extrap_muontrack.setZ(fwdtrack.getZ()); + extrap_muontrack.setCovariances(fwdtrack.getCovariances()); + return extrap_muontrack; + } + + inline o2::track::TrackParCovFwd propagateMFTtoDCA() + { + double covArr[15]{0.0}; + SMatrix55 tmftcovs(covArr, covArr + 15); + + SMatrix5 tmftpars(mfttrack.x(), mfttrack.y(), mfttrack.phi(), mfttrack.tgl(), mfttrack.signed1Pt()); + o2::track::TrackParCovFwd extrap_mfttrack{mfttrack.z(), tmftpars, tmftcovs, mfttrack.chi2()}; + + double propVec[3] = {}; + propVec[0] = collision.posX() - mfttrack.x(); + propVec[1] = collision.posY() - mfttrack.y(); + propVec[2] = collision.posZ() - mfttrack.z(); + + double centerZ[3] = {mfttrack.x() + propVec[0] / 2., mfttrack.y() + propVec[1] / 2., mfttrack.z() + propVec[2] / 2.}; + float Bz = fieldB->getBz(centerZ); + extrap_mfttrack.propagateToZ(collision.posZ(), Bz); // z in cm + return extrap_mfttrack; + } + + inline o2::dataformats::GlobalFwdTrack propagateMUONtoPV() + { + float cov[15] = { + muontrack.cXX(), muontrack.cXY(), muontrack.cYY(), + muontrack.cPhiX(), muontrack.cPhiY(), muontrack.cPhiPhi(), + muontrack.cTglX(), muontrack.cTglY(), muontrack.cTglPhi(), + muontrack.cTglTgl(), muontrack.c1PtX(), muontrack.c1PtY(), + muontrack.c1PtPhi(), muontrack.c1PtTgl(), muontrack.c1Pt21Pt2()}; + + SMatrix5 tpars(muontrack.x(), muontrack.y(), muontrack.phi(), muontrack.tgl(), muontrack.signed1Pt()); + SMatrix55 tcovs(cov, cov + 15); + double chi2 = muontrack.chi2(); + + o2::track::TrackParCovFwd parcovmuontrack{muontrack.z(), tpars, tcovs, chi2}; + + o2::dataformats::GlobalFwdTrack gtrack; + gtrack.setParameters(tpars); + gtrack.setZ(parcovmuontrack.getZ()); + gtrack.setCovariances(tcovs); + + auto mchtrack = mMatching.FwdtoMCH(gtrack); + o2::mch::TrackExtrap::extrapToVertex(mchtrack, collision.posX(), collision.posY(), collision.posZ(), collision.covXX(), collision.covYY()); + + auto fwdtrack = mMatching.MCHtoFwd(mchtrack); + o2::dataformats::GlobalFwdTrack extrap_muontrack; + extrap_muontrack.setParameters(fwdtrack.getParameters()); + extrap_muontrack.setZ(fwdtrack.getZ()); + extrap_muontrack.setCovariances(fwdtrack.getCovariances()); + + return extrap_muontrack; + } + + public: + enum MATCHING_TYPE { MCH_FIRST_CLUSTER, + MFT_LAST_CLUSTR, + END_OF_ABSORBER, + BEGINING_OF_ABSORBER }; + + MatchingParamsML(MUON const& muon, MFT const& mft, Collision const& coll, int MType, o2::field::MagneticField* field) : muontrack(muon), mfttrack(mft), collision(coll), mDX(0.f), mDY(0.f), mDPt(0.f), mDPhi(0.f), mDEta(0.f), mGlobalMuonPtAtDCA(0.f), mGlobalMuonEtaAtDCA(0.f), mGlobalMuonPhiAtDCA(0.f), mGlobalMuonDCAx(0.f), mGlobalMuonDCAy(0.f), mGlobalMuonQ(0.f), mMatchingType(MType), fieldB(field) {} + void calcMatchingParams() + { + auto mfttrack_on_matchingP = propagateMFTtoMatchingPlane(); + auto muontrack_on_matchingP = propagateMUONtoMatchingPlane(); + + float dphiRaw = mfttrack_on_matchingP.getPhi() - muontrack_on_matchingP.getPhi(); + float dphi = TVector2::Phi_mpi_pi(dphiRaw); + float deta = mfttrack_on_matchingP.getEta() - muontrack_on_matchingP.getEta(); + + mDX = mfttrack_on_matchingP.getX() - muontrack_on_matchingP.getX(); + mDY = mfttrack_on_matchingP.getY() - muontrack_on_matchingP.getY(); + mDPt = mfttrack_on_matchingP.getPt() - muontrack_on_matchingP.getPt(); + mDPhi = dphi; + mDEta = deta; + } + + void calcGlobalMuonParams() + { + auto mfttrack_at_dca = propagateMFTtoDCA(); + auto muontrack_at_pv = propagateMUONtoPV(); + + float momentum = muontrack_at_pv.getP(); + float theta = mfttrack_at_dca.getTheta(); + float phiTrack = mfttrack_at_dca.getPhi(); + float px = momentum * std::sin(theta) * std::cos(phiTrack); + float py = momentum * std::sin(theta) * std::sin(phiTrack); + + mGlobalMuonQ = muontrack.sign() + mfttrack.sign(); + mGlobalMuonPtAtDCA = std::sqrt(px * px + py * py); + mGlobalMuonEtaAtDCA = mfttrack_at_dca.getEta(); + mGlobalMuonPhiAtDCA = mfttrack_at_dca.getPhi(); + mGlobalMuonDCAx = mfttrack_at_dca.getX() - collision.posX(); + mGlobalMuonDCAy = mfttrack_at_dca.getY() - collision.posY(); + } + + inline float getDx() const { return mDX; } + inline float getDy() const { return mDY; } + inline float getDphi() const { return mDPhi; } + inline float getDeta() const { return mDEta; } + inline float getDpt() const { return mDPt; } + inline float getGMPtAtDCA() const { return mGlobalMuonPtAtDCA; } + inline float getGMEtaAtDCA() const { return mGlobalMuonEtaAtDCA; } + inline float getGMPhiAtDCA() const { return mGlobalMuonPhiAtDCA; } + inline float getGMDcaX() const { return mGlobalMuonDCAx; } + inline float getGMDcaY() const { return mGlobalMuonDCAy; } + inline float getGMDcaXY() const { return std::sqrt(mGlobalMuonDCAx * mGlobalMuonDCAx + mGlobalMuonDCAy * mGlobalMuonDCAy); } + inline int16_t getGMQ() const { return static_cast(mGlobalMuonQ); } + + }; // end of class MatchingParamsML + + template + o2::dataformats::GlobalFwdTrack propagateMUONtoPV(MUON const& muontrack, Collisions const& collisions) + { + auto collision = collisions.rawIteratorAt(muontrack.collisionId()); + o2::globaltracking::MatchGlobalFwd mMatching; + o2::dataformats::GlobalFwdTrack extrap_muontrack; + + SMatrix5 tpars(muontrack.x(), muontrack.y(), muontrack.phi(), muontrack.tgl(), muontrack.signed1Pt()); + std::vector v1{muontrack.cXX(), muontrack.cXY(), muontrack.cYY(), + muontrack.cPhiX(), muontrack.cPhiY(), muontrack.cPhiPhi(), + muontrack.cTglX(), muontrack.cTglY(), muontrack.cTglPhi(), + muontrack.cTglTgl(), muontrack.c1PtX(), muontrack.c1PtY(), + muontrack.c1PtPhi(), muontrack.c1PtTgl(), muontrack.c1Pt21Pt2()}; + SMatrix55 tcovs(v1.begin(), v1.end()); + double chi2 = muontrack.chi2(); + o2::track::TrackParCovFwd parcovmuontrack{muontrack.z(), tpars, tcovs, chi2}; + + o2::dataformats::GlobalFwdTrack gtrack; + gtrack.setParameters(tpars); + gtrack.setZ(parcovmuontrack.getZ()); + gtrack.setCovariances(tcovs); + auto mchtrack = mMatching.FwdtoMCH(gtrack); + + o2::mch::TrackExtrap::extrapToVertex(mchtrack, collision.posX(), collision.posY(), collision.posZ(), collision.covXX(), collision.covYY()); + + auto fwdtrack = mMatching.MCHtoFwd(mchtrack); + extrap_muontrack.setParameters(fwdtrack.getParameters()); + extrap_muontrack.setZ(fwdtrack.getZ()); + extrap_muontrack.setCovariances(fwdtrack.getCovariances()); + + return extrap_muontrack; + } + + inline bool isGoodTagDimuon(float M) + { + return !(M < fTagMassWindowMin || M > fTagMassWindowMax); + } + + inline bool isGoodTagMatching(float mDX, float mDY, float mDEta, float mDPhi) + { + float dxNorm = (mDX - fMeanXTagMuonCut) / (fSigmaXTagMuonCut * 3); + float dyNorm = (mDY - fMeanYTagMuonCut) / (fSigmaYTagMuonCut * 3); + float detaNorm = (mDEta - fMeanEtaTagMuonCut) / (fSigmaEtaTagMuonCut * 3); + float dphiNorm = (mDPhi - fMeanPhiTagMuonCut) / (fSigmaPhiTagMuonCut * 3); + + float rTagXY = dxNorm * dxNorm + dyNorm * dyNorm; + float rTagEtaPhi = detaNorm * detaNorm + dphiNorm * dphiNorm; + + return (rTagXY < 1.f && rTagEtaPhi > 0.f); + } + + template + bool isCorrectMatching(MUON const& muontrack, MFT const& mfttrack) + { + + int idmuon = muontrack.mcParticleId(); + int idmft = mfttrack.mcParticleId(); + + if (idmuon == -1 || idmft == -1) + return false; + if (idmuon != idmft) + return false; + else + return true; + }; + + template + bool isGoodMuonQuality(MUON muontrack) + { + if (!muontrack.has_collision()) + return false; + if (muontrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) + return false; + if (muontrack.chi2() > fTrackChi2MchUp) + return false; + if (fRabsLow1 > muontrack.rAtAbsorberEnd() || muontrack.rAtAbsorberEnd() > fRabsUp2) + return false; + if (muontrack.rAtAbsorberEnd() < fRabsUp1 && fPdcaUp1 < muontrack.pDca()) + return false; + if (muontrack.rAtAbsorberEnd() > fRabsLow2 && fPdcaUp2 < muontrack.pDca()) + return false; + return true; + } + + template + bool isGoodMuonKine(MUON muontrack) + { + if (fEtaMchLow > muontrack.getEta() || muontrack.getEta() > fEtaMchUp) + return false; + return true; + } + + template + bool isGoodMFTQuality(MFT mfttrack) + { + if (!mfttrack.has_collision()) + return false; + if (mfttrack.chi2() > fTrackChi2MftUp) + return false; + if (mfttrack.nClusters() < fTrackNClustMftLow) + return false; + return true; + } + + template + bool isGoodMFTKine(MFT mfttrack) + { + if (fEtaMftLow > mfttrack.getEta() || mfttrack.getEta() > fEtaMftUp) + return false; + return true; + } + + inline bool isPassMatchingPreselection(float Dx, float Dy) + { + return !(std::abs(Dx) > fPreselectMatchingX || std::abs(Dy) > fPreselectMatchingY); + } + + template + void setMUONs(MUONs const& muontracks, Collisions const& collisions) + { + for (auto muontrack : muontracks) { + if (!isGoodMuonQuality(muontrack)) + continue; + o2::dataformats::GlobalFwdTrack muontrack_at_pv = propagateMUONtoPV(muontrack, collisions); + if (!isGoodMuonKine(muontrack_at_pv)) + continue; + + auto collision = collisions.rawIteratorAt(muontrack.collisionId()); + + bool& has = map_has_muontracks_collisions[muontrack.collisionId()]; + has = true; + + vector& arr_muontracks = map_muontracks[collision.globalIndex()]; + arr_muontracks.push_back(muontrack.globalIndex()); + } + } + + template + o2::track::TrackParCovFwd PropagateMFTtoDCA(MFT const& mfttrack, Collisions const& collisions, o2::field::MagneticField* field) + { + auto collision = collisions.rawIteratorAt(mfttrack.collisionId()); + std::vector mftv1; + SMatrix55 mftcovs{mftv1.begin(), mftv1.end()}; + SMatrix5 mftpars = {mfttrack.x(), mfttrack.y(), mfttrack.phi(), mfttrack.tgl(), mfttrack.signed1Pt()}; + o2::track::TrackParCovFwd mftpartrack = {mfttrack.z(), mftpars, mftcovs, mfttrack.chi2()}; + double propVec[3] = {fabs(mfttrack.x() - collision.posX()), + fabs(mfttrack.y() - collision.posY()), + fabs(mfttrack.z() - collision.posZ())}; + double centerZ[3] = {mfttrack.x() - propVec[0] / 2., + mfttrack.y() - propVec[1] / 2., + mfttrack.z() - propVec[2] / 2.}; + float Bz = field->getBz(centerZ); + mftpartrack.propagateToZ(collision.posZ(), Bz); + return mftpartrack; + } + + template + void setMFTs(MFTs const& mfttracks, Collisions const& collisions, o2::field::MagneticField* field) + { + for (auto mfttrack : mfttracks) { + if (!isGoodMFTQuality(mfttrack)) + continue; + + o2::track::TrackParCovFwd mfttrack_at_dca = PropagateMFTtoDCA(mfttrack, collisions, field); + if (!isGoodMFTKine(mfttrack_at_dca)) + continue; + + auto collision = collisions.rawIteratorAt(mfttrack.collisionId()); + + map_vtxz[mfttrack.collisionId()] = collision.posZ(); + map_nmfttrack[mfttrack.collisionId()] += 1; + + bool& has = map_has_mfttracks_collisions[mfttrack.collisionId()]; + has = true; + + vector& arr_mfttracks = map_mfttracks[collision.globalIndex()]; + arr_mfttracks.push_back(mfttrack.globalIndex()); + } + } + + Produces tableMatchingParams; + Produces tableTagMatchingParams; + Produces tableProbeMatchingParams; + Produces tableMixMatchingParams; + Produces tableMuonPair; + + Service ccdbManager; + + o2::field::MagneticField* fieldB; + o2::ccdb::CcdbApi ccdbApi; + + template + void initCCDB(BC const& bc) + { + if (mRunNumber == bc.runNumber()) + return; + + mRunNumber = bc.runNumber(); + std::map metadata; + auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, mRunNumber); + auto ts = soreor.first; + auto grpmag = ccdbApi.retrieveFromTFileAny(grpmagPath, metadata, ts); + o2::base::Propagator::initFieldFromGRP(grpmag); + if (!o2::base::GeometryManager::isGeometryLoaded()) { + ccdbManager->get(geoPath); + } + o2::mch::TrackExtrap::setField(); + fieldB = static_cast(TGeoGlobalMagField::Instance()->GetField()); + } + + void init(o2::framework::InitContext&) + { + ccdbManager->setURL(ccdburl); + ccdbManager->setCaching(true); + ccdbManager->setLocalObjectValidityChecking(); + ccdbManager->setFatalWhenNull(false); + ccdbApi.init(ccdburl); + mRunNumber = 0; + } + + void process(MyCollisions const& collisions, + MyBCs const& bcs, + MyMUONs const& muontracks, + MyMFTs const& mfttracks) + { + LOG(info) << "Process() "; + map_muontracks.clear(); + map_mfttracks.clear(); + map_collisions.clear(); + map_has_muontracks_collisions.clear(); + map_has_mfttracks_collisions.clear(); + + initCCDB(bcs.begin()); + setMUONs(muontracks, collisions); + setMFTs(mfttracks, collisions, fieldB); + + for (auto map_has_muontracks_collision : map_has_muontracks_collisions) { + auto idmuontrack_collisions = map_has_muontracks_collision.first; + for (auto map_has_mfttracks_collision : map_has_mfttracks_collisions) { + auto idmfttrack_collisions = map_has_mfttracks_collision.first; + if (idmuontrack_collisions != idmfttrack_collisions) + continue; + map_collisions[idmfttrack_collisions] = true; + } + } + + for (auto const& map_collision : map_collisions) { + auto const& collision = collisions.rawIteratorAt(map_collision.first); + + for (auto const& imuontrack1 : map_muontracks[map_collision.first]) { + auto const& muontrack1 = muontracks.rawIteratorAt(imuontrack1); + + for (auto const& imfttrack1 : map_mfttracks[map_collision.first]) { + auto const& mfttrack1 = mfttracks.rawIteratorAt(imfttrack1); + + MatchingParamsML matching(muontrack1, mfttrack1, collision, fMatchingMethod, fieldB); + matching.calcMatchingParams(); + + if (!isPassMatchingPreselection(matching.getDx(), matching.getDy())) + continue; + + matching.calcGlobalMuonParams(); + + bool isTrue = isCorrectMatching(muontrack1, mfttrack1); + + tableMatchingParams(matching.getGMPtAtDCA(), + matching.getGMEtaAtDCA(), + static_cast(matching.getGMQ()), + matching.getDpt(), + matching.getDx(), + matching.getDy(), + matching.getDeta(), + matching.getDphi(), + isTrue); + } + + for (auto const& map_mfttrack : map_mfttracks) { + if (map_mfttrack.first == map_collision.first) + continue; + if (fabs(map_vtxz[map_mfttrack.first] - map_vtxz[map_collision.first]) > fEventMaxDeltaVtxZ) + continue; + if (fabs(map_nmfttrack[map_mfttrack.first] - map_nmfttrack[map_collision.first]) > fEventMaxDeltaNMFT) + continue; + + for (auto const& imfttrack1 : map_mfttrack.second) { + auto const& mfttrack1 = mfttracks.rawIteratorAt(imfttrack1); + MatchingParamsML matching(muontrack1, mfttrack1, collision, fMatchingMethod, fieldB); + matching.calcMatchingParams(); + if (!isPassMatchingPreselection(matching.getDx(), matching.getDy())) + continue; + matching.calcGlobalMuonParams(); + + bool isTrue = isCorrectMatching(muontrack1, mfttrack1); + + tableMixMatchingParams(matching.getGMPtAtDCA(), + matching.getGMEtaAtDCA(), + static_cast(matching.getGMQ()), + matching.getDpt(), + matching.getDx(), + matching.getDy(), + matching.getDeta(), + matching.getDphi(), + isTrue); + } + } + + for (auto const& imuontrack2 : map_muontracks[map_collision.first]) { + + if (imuontrack1 >= imuontrack2) + continue; + + auto const& muontrack2 = muontracks.rawIteratorAt(imuontrack2); + + FindTagAndProbe tagdimuon(muontrack1, muontrack2, collision); + tagdimuon.calcMuonPairAtPV(); + tableMuonPair(tagdimuon.getCharge(), tagdimuon.getMass(), tagdimuon.getPt(), tagdimuon.getRap()); + + if (!isGoodTagDimuon(tagdimuon.getMass())) + continue; + + auto tagmuontrack = muontrack1; + auto probemuontrack = muontrack2; + + if (tagdimuon.getTagMuonIndex() == 1) { + tagmuontrack = muontrack2; + probemuontrack = muontrack1; + } + + int nTagMFTCand = 0; + int nProbeMFTCand = 0; + + int IndexTagMFTCand = -1; + float tagGMPtAtDCA = 0; + // float tagGMEtaAtDCA = 0; + + float minimumR = 9999.; + int minimumIndexProbeMFTCand = -1; + + unordered_map> map_tagMatchingParams; + unordered_map> map_probeMatchingParams; + + for (auto const& imfttrack1 : map_mfttracks[map_collision.first]) { + auto const& mfttrack1 = mfttracks.rawIteratorAt(imfttrack1); + MatchingParamsML matchingTag(tagmuontrack, mfttrack1, collision, fMatchingMethod, fieldB); + matchingTag.calcMatchingParams(); + matchingTag.calcGlobalMuonParams(); + if (isGoodTagMatching(matchingTag.getDx(), matchingTag.getDy(), matchingTag.getDeta(), matchingTag.getDphi()) && + isPassMatchingPreselection(matchingTag.getDx(), matchingTag.getDy())) { + bool isTrue = isCorrectMatching(tagmuontrack, mfttrack1); + tableTagMatchingParams(matchingTag.getGMPtAtDCA(), + matchingTag.getGMEtaAtDCA(), + matchingTag.getGMQ(), + matchingTag.getDpt(), + matchingTag.getDx(), + matchingTag.getDy(), + matchingTag.getDeta(), + matchingTag.getDphi(), + isTrue); + IndexTagMFTCand = mfttrack1.globalIndex(); + tagGMPtAtDCA = matchingTag.getGMPtAtDCA(); + // tagGMEtaAtDCA = matchingTag.getGMEtaAtDCA(); + ++nTagMFTCand; + } + } // end of loop imfttrack1 + + if (nTagMFTCand != 1) + continue; + for (auto const& imfttrack1 : map_mfttracks[map_collision.first]) { + auto const& mfttrack1 = mfttracks.rawIteratorAt(imfttrack1); + if (mfttrack1.globalIndex() == IndexTagMFTCand) + continue; + MatchingParamsML matchingProbe(probemuontrack, mfttrack1, collision, fMatchingMethod, fieldB); + matchingProbe.calcMatchingParams(); + if (isPassMatchingPreselection(matchingProbe.getDx(), matchingProbe.getDy())) { + float R = sqrt(matchingProbe.getDx() * matchingProbe.getDx() + matchingProbe.getDy() * matchingProbe.getDy()); + bool isTrue = isCorrectMatching(probemuontrack, mfttrack1); + matchingProbe.calcGlobalMuonParams(); + vector& probeMatchingParams = map_probeMatchingParams[nProbeMFTCand]; + probeMatchingParams.push_back(tagGMPtAtDCA); + probeMatchingParams.push_back(matchingProbe.getGMPtAtDCA()); + probeMatchingParams.push_back(matchingProbe.getGMEtaAtDCA()); + probeMatchingParams.push_back(matchingProbe.getGMQ()); + probeMatchingParams.push_back(matchingProbe.getDpt()); + probeMatchingParams.push_back(matchingProbe.getDx()); + probeMatchingParams.push_back(matchingProbe.getDy()); + probeMatchingParams.push_back(matchingProbe.getDeta()); + probeMatchingParams.push_back(matchingProbe.getDphi()); + probeMatchingParams.push_back(isTrue); + if (R < minimumR) { + minimumIndexProbeMFTCand = nProbeMFTCand; + minimumR = R; + } + ++nProbeMFTCand; + } + } // end of loop imfttrack1 + + if (nProbeMFTCand < 1) + continue; + + if (minimumIndexProbeMFTCand > -1) { + vector& probeMatchingParams = map_probeMatchingParams[minimumIndexProbeMFTCand]; + tableProbeMatchingParams(probeMatchingParams[0], + probeMatchingParams[1], + probeMatchingParams[2], + static_cast(probeMatchingParams[3]), + probeMatchingParams[4], + probeMatchingParams[5], + probeMatchingParams[6], + probeMatchingParams[7], + probeMatchingParams[8], + static_cast(probeMatchingParams[9])); + } + + } // end of loop imuontrack2 + } // end of loop imuontrack1 + } // end of loop map_collision + + } // end of processMC +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/Common/TableProducer/match-mft-mch-data.cxx b/Common/TableProducer/match-mft-mch-data.cxx new file mode 100644 index 00000000000..b566d9531f8 --- /dev/null +++ b/Common/TableProducer/match-mft-mch-data.cxx @@ -0,0 +1,881 @@ +// 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. +#include +#include +#include +#include +#include + +#include "CCDB/BasicCCDBManager.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/MftmchMatchingML.h" +#include "Common/DataModel/MatchMFTMuonData.h" +#include "Common/Core/trackUtilities.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/AnalysisCut.h" +#include "PWGDQ/Core/AnalysisCompositeCut.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/CutsLibrary.h" +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" +#include "DetectorsVertexing/VertexTrackMatcher.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "ReconstructionDataFormats/VtxTrackIndex.h" +#include "ReconstructionDataFormats/VtxTrackRef.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DetectorsVertexing/PVertexerParams.h" +#include "MathUtils/Primitive2D.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/MatchMFTFT0.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Field/MagneticField.h" +#include "TGeoGlobalMagField.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "EventFiltering/Zorro.h" +#include "ReconstructionDataFormats/TrackFwd.h" +#include "Math/MatrixFunctions.h" +#include "Math/SMatrix.h" +#include "MFTTracking/Tracker.h" +#include "MCHTracking/TrackParam.h" +#include "MCHTracking/TrackExtrap.h" +#include "GlobalTracking/MatchGlobalFwd.h" +#include +#include +#include "TDatabasePDG.h" + +using namespace std; + +using namespace o2; +using namespace o2::soa; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/DataTypes.h" +#include "Framework/runDataProcessing.h" + +using MyCollisions = aod::Collisions; +using MyBCs = soa::Join; +using MyMUONs = soa::Join; +using MyMFTs = aod::MFTTracks; + +using MyCollision = MyCollisions::iterator; +using MyBC = MyBCs::iterator; +using MyMUON = MyMUONs::iterator; +using MyMFT = MyMFTs::iterator; + +using SMatrix55 = ROOT::Math::SMatrix>; +using SMatrix5 = ROOT::Math::SVector; + +float mMu = TDatabasePDG::Instance()->GetParticle(13)->Mass(); +int mRunNumber; +/* + TLorentzVector muon1LV; + TLorentzVector muon2LV; + TLorentzVector dimuonLV; +*/ +unordered_map> map_mfttracks; +unordered_map> map_muontracks; +unordered_map map_collisions; +unordered_map map_has_mfttracks_collisions; +unordered_map map_has_muontracks_collisions; +unordered_map map_vtxz; +unordered_map map_nmfttrack; + +struct match_mft_mch_data_mc { + + //// Variables for matching method + Configurable fMatchingMethod{"cfgMatchingMethod", 0, ""}; + + //// Variables for selecting muon tracks + Configurable fEtaMchLow{"cfgEtaMchLow", -4.0f, ""}; + Configurable fEtaMchUp{"cfgEtaMchUp", -2.5f, ""}; + Configurable fRabsLow1{"cfgRabsLow1", 17.6f, ""}; + Configurable fRabsUp1{"cfgRabsUp1", 26.5f, ""}; + Configurable fRabsLow2{"cfgRabsLow2", 26.5f, ""}; + Configurable fRabsUp2{"cfgRabsUp2", 89.5f, ""}; + Configurable fPdcaUp1{"cfgPdcaUp1", 594.f, ""}; + Configurable fPdcaUp2{"cfgPdcaUp2", 324.f, ""}; + Configurable fTrackChi2MchUp{"cfgTrackChi2MchUp", 5.f, ""}; + Configurable fMatchingChi2MchMidUp{"cfgMatchingChi2MchMidUp", 999.f, ""}; + + //// Variables for selecting mft tracks + Configurable fEtaMftLow{"cfgEtaMftlow", -3.6f, ""}; + Configurable fEtaMftUp{"cfgEtaMftup", -2.5f, ""}; + Configurable fTrackNClustMftLow{"cfgTrackNClustMftLow", 7, ""}; + Configurable fTrackChi2MftUp{"cfgTrackChi2MftUp", 999.f, ""}; + + /// Variables to add preselection for the matching table + Configurable fPreselectMatchingX{"cfgPreselectMatchingX", 15.f, ""}; + Configurable fPreselectMatchingY{"cfgPreselectMatchingY", 15.f, ""}; + + /// Variables to event mixing criteria + Configurable fSaveMixedMatchingParamsRate{"cfgSaveMixedMatchingParamsRate", 0.002f, ""}; + Configurable fEventMaxDeltaNMFT{"cfgEventMaxDeltaNMFT", 1, ""}; + Configurable fEventMaxDeltaVtxZ{"cfgEventMaxDeltaVtxZ", 1.f, ""}; + + //// Variables for selecting tag muon + Configurable fTagMassWindowMin{"cfgTagMassWindowMin", 2.8f, ""}; + Configurable fTagMassWindowMax{"cfgTagMassWindowMax", 3.3f, ""}; + + //// Variables for ccdb + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + + //// Variables for Tag matching criteria + Configurable fSigmaXTagMuonCut{"cfgSigmaXTagMuonCut", 1.f, ""}; + Configurable fMeanXTagMuonCut{"cfgMeanXTagMuonCut", 0.f, ""}; + Configurable fSigmaYTagMuonCut{"cfgSigmaYTagMuonCut", 1.f, ""}; + Configurable fMeanYTagMuonCut{"cfgMeanYTagMuonCut", 1.f, ""}; + + Configurable fSigmaEtaTagMuonCut{"cfgSigmaEtaTagMuonCut", 0.2f, ""}; + Configurable fMeanEtaTagMuonCut{"cfgMeanEtaTagMuonCut", 0.f, ""}; + Configurable fSigmaPhiTagMuonCut{"cfgSigmaPhiTagMuonCut", 0.2f, ""}; + Configurable fMeanPhiTagMuonCut{"cfgMeanPhiTagMuonCut", 0.f, ""}; + + template + class FindTagAndProbe + { + private: + o2::dataformats::GlobalFwdTrack muontrack_at_pv[2]; + + TLorentzVector mDimuon; + MUON muontrack1; + MUON muontrack2; + Collision collision; + int tagIdx, probeIdx; + + int16_t mQ; + + inline void fillCovarianceArray(MUON const& muontrack, float cov[15]) const + { + cov[0] = muontrack.cXX(); + cov[1] = muontrack.cXY(); + cov[2] = muontrack.cYY(); + cov[3] = muontrack.cPhiX(); + cov[4] = muontrack.cPhiY(); + cov[5] = muontrack.cPhiPhi(); + cov[6] = muontrack.cTglX(); + cov[7] = muontrack.cTglY(); + cov[8] = muontrack.cTglPhi(); + cov[9] = muontrack.cTglTgl(); + cov[10] = muontrack.c1PtX(); + cov[11] = muontrack.c1PtY(); + cov[12] = muontrack.c1PtPhi(); + cov[13] = muontrack.c1PtTgl(); + cov[14] = muontrack.c1Pt21Pt2(); + } + + inline o2::dataformats::GlobalFwdTrack propagateMUONtoPV(MUON const& muontrack) const + { + const double mz = muontrack.z(); + const double mchi2 = muontrack.chi2(); + const float mx = muontrack.x(); + const float my = muontrack.y(); + const float mphi = muontrack.phi(); + const float mtgl = muontrack.tgl(); + const float m1pt = muontrack.signed1Pt(); + + float cov[15]; + fillCovarianceArray(muontrack, cov); + SMatrix5 tpars(mx, my, mphi, mtgl, m1pt); + SMatrix55 tcovs(cov, cov + 15); + + o2::track::TrackParCovFwd parcovmuontrack{mz, tpars, tcovs, mchi2}; + + o2::dataformats::GlobalFwdTrack gtrack; + gtrack.setParameters(tpars); + gtrack.setZ(parcovmuontrack.getZ()); + gtrack.setCovariances(tcovs); + + o2::globaltracking::MatchGlobalFwd mMatching; + auto mchtrack = mMatching.FwdtoMCH(gtrack); + + o2::mch::TrackExtrap::extrapToVertex(mchtrack, collision.posX(), collision.posY(), collision.posZ(), collision.covXX(), collision.covYY()); + + auto fwdtrack = mMatching.MCHtoFwd(mchtrack); + o2::dataformats::GlobalFwdTrack extrap_muontrack; + extrap_muontrack.setParameters(fwdtrack.getParameters()); + extrap_muontrack.setZ(fwdtrack.getZ()); + extrap_muontrack.setCovariances(fwdtrack.getCovariances()); + + return extrap_muontrack; + } + + inline void setTagAndProbe() + { + if (muontrack1.pt() > muontrack2.pt()) { + tagIdx = 0; + probeIdx = 1; + } else { + tagIdx = 1; + probeIdx = 0; + } + } + + public: + inline FindTagAndProbe(const MUON& muon1, const MUON& muon2, const Collision& coll) + : muontrack_at_pv(), mDimuon(), muontrack1(muon1), muontrack2(muon2), collision(coll), tagIdx(-1), probeIdx(-1), mQ(0) + { + mQ = muontrack1.sign() + muontrack2.sign(); + setTagAndProbe(); + } + + void calcMuonPairAtPV() + { + muontrack_at_pv[0] = propagateMUONtoPV(muontrack1); + muontrack_at_pv[1] = propagateMUONtoPV(muontrack2); + TLorentzVector vMuon1, vMuon2; + vMuon1.SetPtEtaPhiM(muontrack_at_pv[0].getPt(), muontrack_at_pv[0].getEta(), muontrack_at_pv[0].getPhi(), mMu); + vMuon2.SetPtEtaPhiM(muontrack_at_pv[1].getPt(), muontrack_at_pv[1].getEta(), muontrack_at_pv[1].getPhi(), mMu); + mDimuon = vMuon1 + vMuon2; + } + inline int getTagMuonIndex() const { return tagIdx; } + inline int getProbeMuonIndex() const { return probeIdx; } + inline float getMass() const { return mDimuon.M(); } + inline float getPt() const { return mDimuon.Pt(); } + inline float getRap() const { return mDimuon.Rapidity(); } + inline int16_t getCharge() const { return mQ; } + inline const o2::dataformats::GlobalFwdTrack& getMuonAtPV(int idx) const { return muontrack_at_pv[idx]; } + }; // end of class FindTagAndProbe + + template + class MatchingParamsML + { + private: + MUON muontrack; + MFT mfttrack; + Collision collision; + + float mDX, mDY, mDPt, mDPhi, mDEta; + float mGlobalMuonPtAtDCA, mGlobalMuonEtaAtDCA, mGlobalMuonPhiAtDCA, mGlobalMuonDCAx, mGlobalMuonDCAy, mGlobalMuonQ; + int mMatchingType; + + o2::field::MagneticField* fieldB; + o2::globaltracking::MatchGlobalFwd mMatching; + + inline o2::track::TrackParCovFwd propagateMFTtoMatchingPlane() + { + double covArr[15]{0.0}; + SMatrix55 tmftcovs(covArr, covArr + 15); + + SMatrix5 tmftpars(mfttrack.x(), mfttrack.y(), mfttrack.phi(), mfttrack.tgl(), mfttrack.signed1Pt()); + o2::track::TrackParCovFwd extrap_mfttrack{mfttrack.z(), tmftpars, tmftcovs, mfttrack.chi2()}; + + double propVec[3] = {0.}; + float zPlane = 0.f; + if (mMatchingType == MCH_FIRST_CLUSTER) { + propVec[0] = muontrack.x() - mfttrack.x(); + propVec[1] = muontrack.y() - mfttrack.y(); + propVec[2] = muontrack.z() - mfttrack.z(); + zPlane = muontrack.z(); + } else if (mMatchingType == END_OF_ABSORBER || mMatchingType == BEGINING_OF_ABSORBER) { + auto extrap_muontrack = propagateMUONtoMatchingPlane(); + propVec[0] = extrap_muontrack.getX() - mfttrack.x(); + propVec[1] = extrap_muontrack.getY() - mfttrack.y(); + propVec[2] = extrap_muontrack.getZ() - mfttrack.z(); + zPlane = (mMatchingType == END_OF_ABSORBER) ? -505.f : -90.f; + } else { + zPlane = mfttrack.z(); + } + + double centerZ[3] = {mfttrack.x() + propVec[0] / 2., mfttrack.y() + propVec[1] / 2., mfttrack.z() + propVec[2] / 2.}; + float Bz = fieldB->getBz(centerZ); + extrap_mfttrack.propagateToZ(zPlane, Bz); // z in cm + return extrap_mfttrack; + } + + inline o2::dataformats::GlobalFwdTrack propagateMUONtoMatchingPlane() + { + float cov[15] = { + muontrack.cXX(), muontrack.cXY(), muontrack.cYY(), + muontrack.cPhiX(), muontrack.cPhiY(), muontrack.cPhiPhi(), + muontrack.cTglX(), muontrack.cTglY(), muontrack.cTglPhi(), + muontrack.cTglTgl(), muontrack.c1PtX(), muontrack.c1PtY(), + muontrack.c1PtPhi(), muontrack.c1PtTgl(), muontrack.c1Pt21Pt2()}; + + SMatrix5 tpars(muontrack.x(), muontrack.y(), muontrack.phi(), muontrack.tgl(), muontrack.signed1Pt()); + SMatrix55 tcovs(cov, cov + 15); + double chi2 = muontrack.chi2(); + + o2::track::TrackParCovFwd parcovmuontrack{muontrack.z(), tpars, tcovs, chi2}; + + o2::dataformats::GlobalFwdTrack gtrack; + gtrack.setParameters(tpars); + gtrack.setZ(parcovmuontrack.getZ()); + gtrack.setCovariances(tcovs); + + auto mchtrack = mMatching.FwdtoMCH(gtrack); + + if (mMatchingType == MFT_LAST_CLUSTR) { + o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchtrack, mfttrack.z()); + } else if (mMatchingType == END_OF_ABSORBER) { + o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchtrack, -505.); + } else if (mMatchingType == BEGINING_OF_ABSORBER) { + o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchtrack, -90.); + } + + auto fwdtrack = mMatching.MCHtoFwd(mchtrack); + + o2::dataformats::GlobalFwdTrack extrap_muontrack; + extrap_muontrack.setParameters(fwdtrack.getParameters()); + extrap_muontrack.setZ(fwdtrack.getZ()); + extrap_muontrack.setCovariances(fwdtrack.getCovariances()); + return extrap_muontrack; + } + + inline o2::track::TrackParCovFwd propagateMFTtoDCA() + { + double covArr[15]{0.0}; + SMatrix55 tmftcovs(covArr, covArr + 15); + + SMatrix5 tmftpars(mfttrack.x(), mfttrack.y(), mfttrack.phi(), mfttrack.tgl(), mfttrack.signed1Pt()); + o2::track::TrackParCovFwd extrap_mfttrack{mfttrack.z(), tmftpars, tmftcovs, mfttrack.chi2()}; + + double propVec[3] = {}; + propVec[0] = collision.posX() - mfttrack.x(); + propVec[1] = collision.posY() - mfttrack.y(); + propVec[2] = collision.posZ() - mfttrack.z(); + + double centerZ[3] = {mfttrack.x() + propVec[0] / 2., mfttrack.y() + propVec[1] / 2., mfttrack.z() + propVec[2] / 2.}; + float Bz = fieldB->getBz(centerZ); + extrap_mfttrack.propagateToZ(collision.posZ(), Bz); // z in cm + return extrap_mfttrack; + } + + inline o2::dataformats::GlobalFwdTrack propagateMUONtoPV() + { + float cov[15] = { + muontrack.cXX(), muontrack.cXY(), muontrack.cYY(), + muontrack.cPhiX(), muontrack.cPhiY(), muontrack.cPhiPhi(), + muontrack.cTglX(), muontrack.cTglY(), muontrack.cTglPhi(), + muontrack.cTglTgl(), muontrack.c1PtX(), muontrack.c1PtY(), + muontrack.c1PtPhi(), muontrack.c1PtTgl(), muontrack.c1Pt21Pt2()}; + + SMatrix5 tpars(muontrack.x(), muontrack.y(), muontrack.phi(), muontrack.tgl(), muontrack.signed1Pt()); + SMatrix55 tcovs(cov, cov + 15); + double chi2 = muontrack.chi2(); + + o2::track::TrackParCovFwd parcovmuontrack{muontrack.z(), tpars, tcovs, chi2}; + + o2::dataformats::GlobalFwdTrack gtrack; + gtrack.setParameters(tpars); + gtrack.setZ(parcovmuontrack.getZ()); + gtrack.setCovariances(tcovs); + + auto mchtrack = mMatching.FwdtoMCH(gtrack); + o2::mch::TrackExtrap::extrapToVertex(mchtrack, collision.posX(), collision.posY(), collision.posZ(), collision.covXX(), collision.covYY()); + + auto fwdtrack = mMatching.MCHtoFwd(mchtrack); + o2::dataformats::GlobalFwdTrack extrap_muontrack; + extrap_muontrack.setParameters(fwdtrack.getParameters()); + extrap_muontrack.setZ(fwdtrack.getZ()); + extrap_muontrack.setCovariances(fwdtrack.getCovariances()); + + return extrap_muontrack; + } + + public: + enum MATCHING_TYPE { MCH_FIRST_CLUSTER, + MFT_LAST_CLUSTR, + END_OF_ABSORBER, + BEGINING_OF_ABSORBER }; + + MatchingParamsML(MUON const& muon, MFT const& mft, Collision const& coll, int MType, o2::field::MagneticField* field) : muontrack(muon), mfttrack(mft), collision(coll), mDX(0.f), mDY(0.f), mDPt(0.f), mDPhi(0.f), mDEta(0.f), mGlobalMuonPtAtDCA(0.f), mGlobalMuonEtaAtDCA(0.f), mGlobalMuonPhiAtDCA(0.f), mGlobalMuonDCAx(0.f), mGlobalMuonDCAy(0.f), mGlobalMuonQ(0.f), mMatchingType(MType), fieldB(field) {} + void calcMatchingParams() + { + auto mfttrack_on_matchingP = propagateMFTtoMatchingPlane(); + auto muontrack_on_matchingP = propagateMUONtoMatchingPlane(); + + float dphiRaw = mfttrack_on_matchingP.getPhi() - muontrack_on_matchingP.getPhi(); + float dphi = TVector2::Phi_mpi_pi(dphiRaw); + float deta = mfttrack_on_matchingP.getEta() - muontrack_on_matchingP.getEta(); + + mDX = mfttrack_on_matchingP.getX() - muontrack_on_matchingP.getX(); + mDY = mfttrack_on_matchingP.getY() - muontrack_on_matchingP.getY(); + mDPt = mfttrack_on_matchingP.getPt() - muontrack_on_matchingP.getPt(); + mDPhi = dphi; + mDEta = deta; + } + + void calcGlobalMuonParams() + { + auto mfttrack_at_dca = propagateMFTtoDCA(); + auto muontrack_at_pv = propagateMUONtoPV(); + + float momentum = muontrack_at_pv.getP(); + float theta = mfttrack_at_dca.getTheta(); + float phiTrack = mfttrack_at_dca.getPhi(); + float px = momentum * std::sin(theta) * std::cos(phiTrack); + float py = momentum * std::sin(theta) * std::sin(phiTrack); + + mGlobalMuonQ = muontrack.sign() + mfttrack.sign(); + mGlobalMuonPtAtDCA = std::sqrt(px * px + py * py); + mGlobalMuonEtaAtDCA = mfttrack_at_dca.getEta(); + mGlobalMuonPhiAtDCA = mfttrack_at_dca.getPhi(); + mGlobalMuonDCAx = mfttrack_at_dca.getX() - collision.posX(); + mGlobalMuonDCAy = mfttrack_at_dca.getY() - collision.posY(); + } + + inline float getDx() const { return mDX; } + inline float getDy() const { return mDY; } + inline float getDphi() const { return mDPhi; } + inline float getDeta() const { return mDEta; } + inline float getDpt() const { return mDPt; } + inline float getGMPtAtDCA() const { return mGlobalMuonPtAtDCA; } + inline float getGMEtaAtDCA() const { return mGlobalMuonEtaAtDCA; } + inline float getGMPhiAtDCA() const { return mGlobalMuonPhiAtDCA; } + inline float getGMDcaX() const { return mGlobalMuonDCAx; } + inline float getGMDcaY() const { return mGlobalMuonDCAy; } + inline float getGMDcaXY() const { return std::sqrt(mGlobalMuonDCAx * mGlobalMuonDCAx + mGlobalMuonDCAy * mGlobalMuonDCAy); } + inline int16_t getGMQ() const { return static_cast(mGlobalMuonQ); } + + }; // end of class MatchingParamsML + + template + o2::dataformats::GlobalFwdTrack propagateMUONtoPV(MUON const& muontrack, Collisions const& collisions) + { + auto collision = collisions.rawIteratorAt(muontrack.collisionId()); + o2::globaltracking::MatchGlobalFwd mMatching; + o2::dataformats::GlobalFwdTrack extrap_muontrack; + + SMatrix5 tpars(muontrack.x(), muontrack.y(), muontrack.phi(), muontrack.tgl(), muontrack.signed1Pt()); + std::vector v1{muontrack.cXX(), muontrack.cXY(), muontrack.cYY(), + muontrack.cPhiX(), muontrack.cPhiY(), muontrack.cPhiPhi(), + muontrack.cTglX(), muontrack.cTglY(), muontrack.cTglPhi(), + muontrack.cTglTgl(), muontrack.c1PtX(), muontrack.c1PtY(), + muontrack.c1PtPhi(), muontrack.c1PtTgl(), muontrack.c1Pt21Pt2()}; + SMatrix55 tcovs(v1.begin(), v1.end()); + double chi2 = muontrack.chi2(); + o2::track::TrackParCovFwd parcovmuontrack{muontrack.z(), tpars, tcovs, chi2}; + + o2::dataformats::GlobalFwdTrack gtrack; + gtrack.setParameters(tpars); + gtrack.setZ(parcovmuontrack.getZ()); + gtrack.setCovariances(tcovs); + auto mchtrack = mMatching.FwdtoMCH(gtrack); + + o2::mch::TrackExtrap::extrapToVertex(mchtrack, collision.posX(), collision.posY(), collision.posZ(), collision.covXX(), collision.covYY()); + + auto fwdtrack = mMatching.MCHtoFwd(mchtrack); + extrap_muontrack.setParameters(fwdtrack.getParameters()); + extrap_muontrack.setZ(fwdtrack.getZ()); + extrap_muontrack.setCovariances(fwdtrack.getCovariances()); + + return extrap_muontrack; + } + + inline bool isGoodTagDimuon(float M) + { + return !(M < fTagMassWindowMin || M > fTagMassWindowMax); + } + + inline bool isGoodTagMatching(float mDX, float mDY, float mDEta, float mDPhi) + { + float dxNorm = (mDX - fMeanXTagMuonCut) / (fSigmaXTagMuonCut * 3); + float dyNorm = (mDY - fMeanYTagMuonCut) / (fSigmaYTagMuonCut * 3); + float detaNorm = (mDEta - fMeanEtaTagMuonCut) / (fSigmaEtaTagMuonCut * 3); + float dphiNorm = (mDPhi - fMeanPhiTagMuonCut) / (fSigmaPhiTagMuonCut * 3); + + float rTagXY = dxNorm * dxNorm + dyNorm * dyNorm; + float rTagEtaPhi = detaNorm * detaNorm + dphiNorm * dphiNorm; + + return (rTagXY < 1.f && rTagEtaPhi > 0.f); + } + + template + bool isCorrectMatching(MUON const& muontrack, MFT const& mfttrack) + { + + int idmuon = muontrack.mcParticleId(); + int idmft = mfttrack.mcParticleId(); + + if (idmuon == -1 || idmft == -1) + return false; + if (idmuon != idmft) + return false; + else + return true; + }; + + template + bool isGoodMuonQuality(MUON muontrack) + { + if (!muontrack.has_collision()) + return false; + if (muontrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) + return false; + if (muontrack.chi2() > fTrackChi2MchUp) + return false; + if (fRabsLow1 > muontrack.rAtAbsorberEnd() || muontrack.rAtAbsorberEnd() > fRabsUp2) + return false; + if (muontrack.rAtAbsorberEnd() < fRabsUp1 && fPdcaUp1 < muontrack.pDca()) + return false; + if (muontrack.rAtAbsorberEnd() > fRabsLow2 && fPdcaUp2 < muontrack.pDca()) + return false; + return true; + } + + template + bool isGoodMuonKine(MUON muontrack) + { + if (fEtaMchLow > muontrack.getEta() || muontrack.getEta() > fEtaMchUp) + return false; + return true; + } + + template + bool isGoodMFTQuality(MFT mfttrack) + { + if (!mfttrack.has_collision()) + return false; + if (mfttrack.chi2() > fTrackChi2MftUp) + return false; + if (mfttrack.nClusters() < fTrackNClustMftLow) + return false; + return true; + } + + template + bool isGoodMFTKine(MFT mfttrack) + { + if (fEtaMftLow > mfttrack.getEta() || mfttrack.getEta() > fEtaMftUp) + return false; + return true; + } + + inline bool isPassMatchingPreselection(float Dx, float Dy) + { + return !(std::abs(Dx) > fPreselectMatchingX || std::abs(Dy) > fPreselectMatchingY); + } + + template + void setMUONs(MUONs const& muontracks, Collisions const& collisions) + { + for (auto muontrack : muontracks) { + if (!isGoodMuonQuality(muontrack)) + continue; + o2::dataformats::GlobalFwdTrack muontrack_at_pv = propagateMUONtoPV(muontrack, collisions); + if (!isGoodMuonKine(muontrack_at_pv)) + continue; + + auto collision = collisions.rawIteratorAt(muontrack.collisionId()); + + bool& has = map_has_muontracks_collisions[muontrack.collisionId()]; + has = true; + + vector& arr_muontracks = map_muontracks[collision.globalIndex()]; + arr_muontracks.push_back(muontrack.globalIndex()); + } + } + + template + o2::track::TrackParCovFwd PropagateMFTtoDCA(MFT const& mfttrack, Collisions const& collisions, o2::field::MagneticField* field) + { + auto collision = collisions.rawIteratorAt(mfttrack.collisionId()); + std::vector mftv1; + SMatrix55 mftcovs{mftv1.begin(), mftv1.end()}; + SMatrix5 mftpars = {mfttrack.x(), mfttrack.y(), mfttrack.phi(), mfttrack.tgl(), mfttrack.signed1Pt()}; + o2::track::TrackParCovFwd mftpartrack = {mfttrack.z(), mftpars, mftcovs, mfttrack.chi2()}; + double propVec[3] = {fabs(mfttrack.x() - collision.posX()), + fabs(mfttrack.y() - collision.posY()), + fabs(mfttrack.z() - collision.posZ())}; + double centerZ[3] = {mfttrack.x() - propVec[0] / 2., + mfttrack.y() - propVec[1] / 2., + mfttrack.z() - propVec[2] / 2.}; + float Bz = field->getBz(centerZ); + mftpartrack.propagateToZ(collision.posZ(), Bz); + return mftpartrack; + } + + template + void setMFTs(MFTs const& mfttracks, Collisions const& collisions, o2::field::MagneticField* field) + { + for (auto mfttrack : mfttracks) { + if (!isGoodMFTQuality(mfttrack)) + continue; + + o2::track::TrackParCovFwd mfttrack_at_dca = PropagateMFTtoDCA(mfttrack, collisions, field); + if (!isGoodMFTKine(mfttrack_at_dca)) + continue; + + auto collision = collisions.rawIteratorAt(mfttrack.collisionId()); + + map_vtxz[mfttrack.collisionId()] = collision.posZ(); + map_nmfttrack[mfttrack.collisionId()] += 1; + + bool& has = map_has_mfttracks_collisions[mfttrack.collisionId()]; + has = true; + + vector& arr_mfttracks = map_mfttracks[collision.globalIndex()]; + arr_mfttracks.push_back(mfttrack.globalIndex()); + } + } + + Produces tableMatchingParams; + Produces tableTagMatchingParams; + Produces tableProbeMatchingParams; + Produces tableMixMatchingParams; + Produces tableMuonPair; + + Service ccdbManager; + + o2::field::MagneticField* fieldB; + o2::ccdb::CcdbApi ccdbApi; + + template + void initCCDB(BC const& bc) + { + if (mRunNumber == bc.runNumber()) + return; + + mRunNumber = bc.runNumber(); + std::map metadata; + auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, mRunNumber); + auto ts = soreor.first; + auto grpmag = ccdbApi.retrieveFromTFileAny(grpmagPath, metadata, ts); + o2::base::Propagator::initFieldFromGRP(grpmag); + if (!o2::base::GeometryManager::isGeometryLoaded()) { + ccdbManager->get(geoPath); + } + o2::mch::TrackExtrap::setField(); + fieldB = static_cast(TGeoGlobalMagField::Instance()->GetField()); + } + + void init(o2::framework::InitContext&) + { + ccdbManager->setURL(ccdburl); + ccdbManager->setCaching(true); + ccdbManager->setLocalObjectValidityChecking(); + ccdbManager->setFatalWhenNull(false); + ccdbApi.init(ccdburl); + mRunNumber = 0; + } + + void process(MyCollisions const& collisions, + MyBCs const& bcs, + MyMUONs const& muontracks, + MyMFTs const& mfttracks) + { + LOG(info) << "Process() "; + map_muontracks.clear(); + map_mfttracks.clear(); + map_collisions.clear(); + map_has_muontracks_collisions.clear(); + map_has_mfttracks_collisions.clear(); + + initCCDB(bcs.begin()); + setMUONs(muontracks, collisions); + setMFTs(mfttracks, collisions, fieldB); + + for (auto map_has_muontracks_collision : map_has_muontracks_collisions) { + auto idmuontrack_collisions = map_has_muontracks_collision.first; + for (auto map_has_mfttracks_collision : map_has_mfttracks_collisions) { + auto idmfttrack_collisions = map_has_mfttracks_collision.first; + if (idmuontrack_collisions != idmfttrack_collisions) + continue; + map_collisions[idmfttrack_collisions] = true; + } + } + + for (auto const& map_collision : map_collisions) { + auto const& collision = collisions.rawIteratorAt(map_collision.first); + + for (auto const& imuontrack1 : map_muontracks[map_collision.first]) { + auto const& muontrack1 = muontracks.rawIteratorAt(imuontrack1); + + for (auto const& imfttrack1 : map_mfttracks[map_collision.first]) { + auto const& mfttrack1 = mfttracks.rawIteratorAt(imfttrack1); + + MatchingParamsML matching(muontrack1, mfttrack1, collision, fMatchingMethod, fieldB); + matching.calcMatchingParams(); + + if (!isPassMatchingPreselection(matching.getDx(), matching.getDy())) + continue; + + matching.calcGlobalMuonParams(); + + bool isTrue = false; + + tableMatchingParams(matching.getGMPtAtDCA(), + matching.getGMEtaAtDCA(), + static_cast(matching.getGMQ()), + matching.getDpt(), + matching.getDx(), + matching.getDy(), + matching.getDeta(), + matching.getDphi(), + isTrue); + } + + for (auto const& map_mfttrack : map_mfttracks) { + if (map_mfttrack.first == map_collision.first) + continue; + if (fabs(map_vtxz[map_mfttrack.first] - map_vtxz[map_collision.first]) > fEventMaxDeltaVtxZ) + continue; + if (fabs(map_nmfttrack[map_mfttrack.first] - map_nmfttrack[map_collision.first]) > fEventMaxDeltaNMFT) + continue; + + for (auto const& imfttrack1 : map_mfttrack.second) { + auto const& mfttrack1 = mfttracks.rawIteratorAt(imfttrack1); + MatchingParamsML matching(muontrack1, mfttrack1, collision, fMatchingMethod, fieldB); + matching.calcMatchingParams(); + if (!isPassMatchingPreselection(matching.getDx(), matching.getDy())) + continue; + matching.calcGlobalMuonParams(); + + bool isTrue = false; + + tableMixMatchingParams(matching.getGMPtAtDCA(), + matching.getGMEtaAtDCA(), + static_cast(matching.getGMQ()), + matching.getDpt(), + matching.getDx(), + matching.getDy(), + matching.getDeta(), + matching.getDphi(), + isTrue); + } + } + + for (auto const& imuontrack2 : map_muontracks[map_collision.first]) { + + if (imuontrack1 >= imuontrack2) + continue; + + auto const& muontrack2 = muontracks.rawIteratorAt(imuontrack2); + + FindTagAndProbe tagdimuon(muontrack1, muontrack2, collision); + tagdimuon.calcMuonPairAtPV(); + tableMuonPair(tagdimuon.getCharge(), tagdimuon.getMass(), tagdimuon.getPt(), tagdimuon.getRap()); + + if (!isGoodTagDimuon(tagdimuon.getMass())) + continue; + + auto tagmuontrack = muontrack1; + auto probemuontrack = muontrack2; + + if (tagdimuon.getTagMuonIndex() == 1) { + tagmuontrack = muontrack2; + probemuontrack = muontrack1; + } + + int nTagMFTCand = 0; + int nProbeMFTCand = 0; + + int IndexTagMFTCand = -1; + float tagGMPtAtDCA = 0; + // float tagGMEtaAtDCA = 0; + + float minimumR = 9999.; + int minimumIndexProbeMFTCand = -1; + + unordered_map> map_tagMatchingParams; + unordered_map> map_probeMatchingParams; + + for (auto const& imfttrack1 : map_mfttracks[map_collision.first]) { + auto const& mfttrack1 = mfttracks.rawIteratorAt(imfttrack1); + MatchingParamsML matchingTag(tagmuontrack, mfttrack1, collision, fMatchingMethod, fieldB); + matchingTag.calcMatchingParams(); + matchingTag.calcGlobalMuonParams(); + if (isGoodTagMatching(matchingTag.getDx(), matchingTag.getDy(), matchingTag.getDeta(), matchingTag.getDphi()) && + isPassMatchingPreselection(matchingTag.getDx(), matchingTag.getDy())) { + bool isTrue = false; + tableTagMatchingParams(matchingTag.getGMPtAtDCA(), + matchingTag.getGMEtaAtDCA(), + matchingTag.getGMQ(), + matchingTag.getDpt(), + matchingTag.getDx(), + matchingTag.getDy(), + matchingTag.getDeta(), + matchingTag.getDphi(), + isTrue); + IndexTagMFTCand = mfttrack1.globalIndex(); + tagGMPtAtDCA = matchingTag.getGMPtAtDCA(); + // tagGMEtaAtDCA = matchingTag.getGMEtaAtDCA(); + ++nTagMFTCand; + } + } // end of loop imfttrack1 + + if (nTagMFTCand != 1) + continue; + for (auto const& imfttrack1 : map_mfttracks[map_collision.first]) { + auto const& mfttrack1 = mfttracks.rawIteratorAt(imfttrack1); + if (mfttrack1.globalIndex() == IndexTagMFTCand) + continue; + MatchingParamsML matchingProbe(probemuontrack, mfttrack1, collision, fMatchingMethod, fieldB); + matchingProbe.calcMatchingParams(); + if (isPassMatchingPreselection(matchingProbe.getDx(), matchingProbe.getDy())) { + float R = sqrt(matchingProbe.getDx() * matchingProbe.getDx() + matchingProbe.getDy() * matchingProbe.getDy()); + bool isTrue = false; + matchingProbe.calcGlobalMuonParams(); + vector& probeMatchingParams = map_probeMatchingParams[nProbeMFTCand]; + probeMatchingParams.push_back(tagGMPtAtDCA); + probeMatchingParams.push_back(matchingProbe.getGMPtAtDCA()); + probeMatchingParams.push_back(matchingProbe.getGMEtaAtDCA()); + probeMatchingParams.push_back(matchingProbe.getGMQ()); + probeMatchingParams.push_back(matchingProbe.getDpt()); + probeMatchingParams.push_back(matchingProbe.getDx()); + probeMatchingParams.push_back(matchingProbe.getDy()); + probeMatchingParams.push_back(matchingProbe.getDeta()); + probeMatchingParams.push_back(matchingProbe.getDphi()); + probeMatchingParams.push_back(isTrue); + if (R < minimumR) { + minimumIndexProbeMFTCand = nProbeMFTCand; + minimumR = R; + } + ++nProbeMFTCand; + } + } // end of loop imfttrack1 + + if (nProbeMFTCand < 1) + continue; + + if (minimumIndexProbeMFTCand > -1) { + vector& probeMatchingParams = map_probeMatchingParams[minimumIndexProbeMFTCand]; + tableProbeMatchingParams(probeMatchingParams[0], + probeMatchingParams[1], + probeMatchingParams[2], + static_cast(probeMatchingParams[3]), + probeMatchingParams[4], + probeMatchingParams[5], + probeMatchingParams[6], + probeMatchingParams[7], + probeMatchingParams[8], + static_cast(probeMatchingParams[9])); + } + + } // end of loop imuontrack2 + } // end of loop imuontrack1 + } // end of loop map_collision + + } // end of processMC +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/Common/TableProducer/mcCollsExtra.cxx b/Common/TableProducer/mcCollsExtra.cxx index 3c8b42a0267..c085969c5af 100644 --- a/Common/TableProducer/mcCollsExtra.cxx +++ b/Common/TableProducer/mcCollsExtra.cxx @@ -11,6 +11,20 @@ // // Quick and dirty task to correlate MC <-> data // + +#include +#include +#include +#include + +#include "Math/Vector4D.h" +#include +#include +#include +#include +#include +#include + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -32,18 +46,6 @@ #include "DataFormatsParameters/GRPMagField.h" #include "CCDB/BasicCCDBManager.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "Framework/ASoAHelpers.h" - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -133,9 +135,9 @@ struct mcCollisionExtra { auto mcCollision = collision.mcCollision(); auto iter = std::find(sortedIndices.begin(), sortedIndices.end(), mcCollision.index()); if (iter != sortedIndices.end()) { - int index = iter - sortedIndices.begin(); - for (int iMcColl = index + 1; iMcColl < index + 17; iMcColl++) { - if (iMcColl >= sortedIndices.size()) + auto index = std::distance(iter, sortedIndices.begin()); + for (auto iMcColl = index + 1; iMcColl < index + 17; iMcColl++) { + if (iMcColl >= std::ssize(sortedIndices)) continue; if (mcCollisionHasPoI[sortedIndices[iMcColl]]) bitset(forwardHistory, iMcColl - index - 1); diff --git a/Common/TableProducer/mftmchMatchingML.cxx b/Common/TableProducer/mftmchMatchingML.cxx index 314321e1d06..fba6c1464eb 100644 --- a/Common/TableProducer/mftmchMatchingML.cxx +++ b/Common/TableProducer/mftmchMatchingML.cxx @@ -10,7 +10,11 @@ // or submit itself to any jurisdiction. #include +#if __has_include() #include +#else +#include +#endif #include #include #include @@ -73,7 +77,11 @@ struct mftmchMatchingML { Ort::Env env{ORT_LOGGING_LEVEL_WARNING, "model-explorer"}; Ort::SessionOptions session_options; +#if __has_include() std::shared_ptr onnx_session = nullptr; +#else + std::shared_ptr onnx_session = nullptr; +#endif OnnxModel model; template @@ -150,10 +158,26 @@ struct mftmchMatchingML { std::vector output_names; std::vector> output_shapes; +#if __has_include() input_names = onnx_session->GetInputNames(); input_shapes = onnx_session->GetInputShapes(); output_names = onnx_session->GetOutputNames(); output_shapes = onnx_session->GetOutputShapes(); +#else + Ort::AllocatorWithDefaultOptions tmpAllocator; + for (size_t i = 0; i < onnx_session->GetInputCount(); ++i) { + input_names.push_back(onnx_session->GetInputNameAllocated(i, tmpAllocator).get()); + } + for (size_t i = 0; i < onnx_session->GetInputCount(); ++i) { + input_shapes.emplace_back(onnx_session->GetInputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape()); + } + for (size_t i = 0; i < onnx_session->GetOutputCount(); ++i) { + output_names.push_back(onnx_session->GetOutputNameAllocated(i, tmpAllocator).get()); + } + for (size_t i = 0; i < onnx_session->GetOutputCount(); ++i) { + output_shapes.emplace_back(onnx_session->GetOutputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape()); + } +#endif auto input_shape = input_shapes[0]; input_shape[0] = 1; @@ -163,9 +187,26 @@ struct mftmchMatchingML { if (input_tensor_values[8] < cfgXYWindow) { std::vector input_tensors; +#if __has_include() input_tensors.push_back(Ort::Experimental::Value::CreateTensor(input_tensor_values.data(), input_tensor_values.size(), input_shape)); std::vector output_tensors = onnx_session->Run(input_names, input_tensors, output_names); +#else + Ort::MemoryInfo mem_info = + Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault); + input_tensors.push_back(Ort::Value::CreateTensor(mem_info, input_tensor_values.data(), input_tensor_values.size(), input_shape.data(), input_shape.size())); + + Ort::RunOptions runOptions; + std::vector inputNamesChar(input_names.size(), nullptr); + std::transform(std::begin(input_names), std::end(input_names), std::begin(inputNamesChar), + [&](const std::string& str) { return str.c_str(); }); + + std::vector outputNamesChar(output_names.size(), nullptr); + std::transform(std::begin(output_names), std::end(output_names), std::begin(outputNamesChar), + [&](const std::string& str) { return str.c_str(); }); + + std::vector output_tensors = onnx_session->Run(runOptions, inputNamesChar.data(), input_tensors.data(), input_tensors.size(), outputNamesChar.data(), outputNamesChar.size()); +#endif const float* output_value = output_tensors[0].GetTensorData(); diff --git a/Common/TableProducer/multiplicityExtraTable.cxx b/Common/TableProducer/multiplicityExtraTable.cxx index b9d9bfc10a5..001e75e6adb 100644 --- a/Common/TableProducer/multiplicityExtraTable.cxx +++ b/Common/TableProducer/multiplicityExtraTable.cxx @@ -8,6 +8,8 @@ // 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. +#include // megalinter thinks this is a C header... +#include #include "Framework/ConfigParamSpec.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -16,13 +18,10 @@ #include "Common/DataModel/Multiplicity.h" #include "DataFormatsFIT/Triggers.h" #include "TableHelper.h" - #include "CCDB/CcdbApi.h" #include "CommonDataFormat/BunchFilling.h" -#include #include "DataFormatsParameters/GRPObject.h" #include "DataFormatsParameters/GRPLHCIFData.h" -#include using namespace o2; using namespace o2::framework; @@ -31,7 +30,28 @@ using BCPattern = std::bitset; const int nBCsPerOrbit = o2::constants::lhc::LHCMaxBunches; struct MultiplicityExtraTable { - Produces multBC; + Produces multBC; + Produces multNeigh; + + Produces mult2bc; + Produces bc2mult; + + // Allow for downscaling of BC table for less space use in derived data + Configurable bcDownscaleFactor{"bcDownscaleFactor", 2, "Downscale factor for BC table (0: save nothing, 1: save all)"}; + Configurable minFT0CforBCTable{"minFT0CforBCTable", 25.0f, "Minimum FT0C amplitude to fill BC table to reduce data"}; + Configurable saveOnlyBCsWithCollisions{"saveOnlyBCsWithCollisions", true, "save only BCs with collisions in them"}; + + Configurable bcTableFloatPrecision{"bcTableFloatPrecision", 0.1, "float precision in bc table for data reduction"}; + + float tru(float value) + { + if (bcTableFloatPrecision < 1e-4) + return value; // make sure nothing bad happens in case zero (best precision) + return bcTableFloatPrecision * std::round(value / bcTableFloatPrecision) + 0.5f * bcTableFloatPrecision; + }; + + // needed for downscale + unsigned int randomSeed = 0; o2::ccdb::CcdbApi ccdbApi; Service ccdb; @@ -42,6 +62,8 @@ struct MultiplicityExtraTable { void init(InitContext&) { + randomSeed = static_cast(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + ccdbApi.init("http://alice-ccdb.cern.ch"); ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); @@ -50,113 +72,214 @@ struct MultiplicityExtraTable { using BCsWithRun3Matchings = soa::Join; - void process(BCsWithRun3Matchings::iterator const& bc, aod::FV0As const&, aod::FT0s const&, aod::FDDs const&, aod::Zdcs const&) + void processBCs(soa::Join const& bcs, aod::FV0As const&, aod::FT0s const&, aod::FDDs const&, aod::Zdcs const&, soa::Join const& collisions) { - bool Tvx = false; - bool isFV0OrA = false; - float multFT0C = 0.f; - float multFT0A = 0.f; - float multFV0A = 0.f; - float multFDDA = 0.f; - float multFDDC = 0.f; - - // ZDC amplitudes - float multZEM1 = -1.f; - float multZEM2 = -1.f; - float multZNA = -1.f; - float multZNC = -1.f; - float multZPA = -1.f; - float multZPC = -1.f; - - uint8_t multFT0TriggerBits = 0; - uint8_t multFV0TriggerBits = 0; - uint8_t multFDDTriggerBits = 0; - uint64_t multBCTriggerMask = bc.triggerMask(); - - // initialize - from Arvind - newRunNumber = bc.runNumber(); - int localBC = bc.globalBC() % nBCsPerOrbit; - - if (newRunNumber != oldRunNumber) { - uint64_t ts{}; - std::map metadataRCT, headers; - headers = ccdbApi.retrieveHeaders(Form("RCT/Info/RunInformation/%i", newRunNumber), metadataRCT, -1); - ts = atol(headers["SOR"].c_str()); - - LOG(info) << " newRunNumber " << newRunNumber << " time stamp " << ts; - oldRunNumber = newRunNumber; - std::map mapMetadata; - std::map mapHeader; - auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", ts); - CollidingBunch = grplhcif->getBunchFilling().getBCPattern(); - } // new run number - - bool collidingBC = CollidingBunch.test(localBC); - - if (bc.has_ft0()) { - auto ft0 = bc.ft0(); - std::bitset<8> triggers = ft0.triggerMask(); - Tvx = triggers[o2::fit::Triggers::bitVertex]; - multFT0TriggerBits = static_cast(triggers.to_ulong()); - - // calculate T0 charge - for (auto amplitude : ft0.amplitudeA()) { - multFT0A += amplitude; + //+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+ + // determine saved BCs and corresponding new BC table index + std::vector bcHasCollision(bcs.size()); + std::vector newBCindex(bcs.size()); + std::vector bc2multArray(bcs.size()); + int atIndex = 0; + for (const auto& bc : bcs) { + bcHasCollision[bc.globalIndex()] = false; + newBCindex[bc.globalIndex()] = -1; + bc2multArray[bc.globalIndex()] = -1; + } + + //+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+ + // tag BCs that have a collision (from evsel foundBC) + for (const auto& collision : collisions) { + bcHasCollision[collision.foundBCId()] = true; + } + //+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+ + + for (const auto& bc : bcs) { + // downscale if requested to do so + if (bcDownscaleFactor < 1.f && (static_cast(rand_r(&randomSeed)) / static_cast(RAND_MAX)) > bcDownscaleFactor) { + continue; + } + + float multFT0C = 0.f; + if (bc.has_ft0()) { + auto ft0 = bc.ft0(); + for (auto amplitude : ft0.amplitudeC()) { + multFT0C += amplitude; + } + } else { + multFT0C = -999.0f; } - for (auto amplitude : ft0.amplitudeC()) { - multFT0C += amplitude; + + if (multFT0C < minFT0CforBCTable) { + continue; // skip this event } - } else { - multFT0A = -999.0f; - multFT0C = -999.0f; - } - if (bc.has_fv0a()) { - auto fv0 = bc.fv0a(); - std::bitset<8> fV0Triggers = fv0.triggerMask(); - multFV0TriggerBits = static_cast(fV0Triggers.to_ulong()); - for (auto amplitude : fv0.amplitude()) { - multFV0A += amplitude; + if (saveOnlyBCsWithCollisions && !bcHasCollision[bc.globalIndex()]) { + continue; // skip if no collision is assigned to this BC (from evSel assignment) } - isFV0OrA = fV0Triggers[o2::fit::Triggers::bitA]; - } else { - multFV0A = -999.0f; + + newBCindex[bc.globalIndex()] = atIndex++; } + //+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+ - if (bc.has_fdd()) { - auto fdd = bc.fdd(); - std::bitset<8> fFDDTriggers = fdd.triggerMask(); - multFDDTriggerBits = static_cast(fFDDTriggers.to_ulong()); + //+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+ + // interlink: collision -> valid BC, BC -> collision + for (const auto& collision : collisions) { + mult2bc(newBCindex[collision.foundBCId()]); + bc2multArray[collision.foundBCId()] = collision.globalIndex(); + } + //+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+ - for (auto amplitude : fdd.chargeA()) { - multFDDA += amplitude; + for (const auto& bc : bcs) { + if (newBCindex[bc.globalIndex()] < 0) { + continue; // don't keep if low mult or downsampled out } - for (auto amplitude : fdd.chargeC()) { - multFDDC += amplitude; + + bool Tvx = false; + bool isFV0OrA = false; + float multFT0C = 0.f; + float multFT0A = 0.f; + float multFV0A = 0.f; + float multFDDA = 0.f; + float multFDDC = 0.f; + + // ZDC amplitudes + float multZEM1 = -1.f; + float multZEM2 = -1.f; + float multZNA = -1.f; + float multZNC = -1.f; + float multZPA = -1.f; + float multZPC = -1.f; + + float posZFT0 = -1e+3; + bool posZFT0valid = false; + + uint8_t multFT0TriggerBits = 0; + uint8_t multFV0TriggerBits = 0; + uint8_t multFDDTriggerBits = 0; + uint64_t multBCTriggerMask = bc.triggerMask(); + + // initialize - from Arvind + newRunNumber = bc.runNumber(); + int localBC = bc.globalBC() % nBCsPerOrbit; + + if (newRunNumber != oldRunNumber) { + auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, newRunNumber); + auto ts = soreor.first; + + LOG(info) << " newRunNumber " << newRunNumber << " time stamp " << ts; + oldRunNumber = newRunNumber; + auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", ts); + CollidingBunch = grplhcif->getBunchFilling().getBCPattern(); + } // new run number + + bool collidingBC = CollidingBunch.test(localBC); + + if (bc.has_ft0()) { + const auto& ft0 = bc.ft0(); + std::bitset<8> triggers = ft0.triggerMask(); + Tvx = triggers[o2::fit::Triggers::bitVertex]; + multFT0TriggerBits = static_cast(triggers.to_ulong()); + + // calculate T0 charge + for (auto amplitude : ft0.amplitudeA()) { + multFT0A += amplitude; + } + for (auto amplitude : ft0.amplitudeC()) { + multFT0C += amplitude; + } + posZFT0 = ft0.posZ(); + posZFT0valid = ft0.isValidTime(); + } else { + multFT0A = -999.0f; + multFT0C = -999.0f; + } + if (bc.has_fv0a()) { + auto fv0 = bc.fv0a(); + std::bitset<8> fV0Triggers = fv0.triggerMask(); + multFV0TriggerBits = static_cast(fV0Triggers.to_ulong()); + + for (auto amplitude : fv0.amplitude()) { + multFV0A += amplitude; + } + isFV0OrA = fV0Triggers[o2::fit::Triggers::bitA]; + } else { + multFV0A = -999.0f; + } + + if (bc.has_fdd()) { + auto fdd = bc.fdd(); + std::bitset<8> fFDDTriggers = fdd.triggerMask(); + multFDDTriggerBits = static_cast(fFDDTriggers.to_ulong()); + + for (auto amplitude : fdd.chargeA()) { + multFDDA += amplitude; + } + for (auto amplitude : fdd.chargeC()) { + multFDDC += amplitude; + } + } else { + multFDDA = -999.0f; + multFDDC = -999.0f; + } + + if (bc.has_zdc()) { + multZNA = bc.zdc().amplitudeZNA(); + multZNC = bc.zdc().amplitudeZNC(); + multZEM1 = bc.zdc().amplitudeZEM1(); + multZEM2 = bc.zdc().amplitudeZEM2(); + multZPA = bc.zdc().amplitudeZPA(); + multZPC = bc.zdc().amplitudeZPC(); + } else { + multZNA = -999.f; + multZNC = -999.f; + multZEM1 = -999.f; + multZEM2 = -999.f; + multZPA = -999.f; + multZPC = -999.f; } - } else { - multFDDA = -999.0f; - multFDDC = -999.0f; + + bc2mult(bc2multArray[bc.globalIndex()]); + multBC( + tru(multFT0A), tru(multFT0C), + tru(posZFT0), posZFT0valid, tru(multFV0A), + tru(multFDDA), tru(multFDDC), tru(multZNA), tru(multZNC), tru(multZEM1), + tru(multZEM2), tru(multZPA), tru(multZPC), Tvx, isFV0OrA, + multFV0TriggerBits, multFT0TriggerBits, multFDDTriggerBits, multBCTriggerMask, collidingBC, + bc.timestamp(), + bc.flags()); } + } - if (bc.has_zdc()) { - multZNA = bc.zdc().amplitudeZNA(); - multZNC = bc.zdc().amplitudeZNC(); - multZEM1 = bc.zdc().amplitudeZEM1(); - multZEM2 = bc.zdc().amplitudeZEM2(); - multZPA = bc.zdc().amplitudeZPA(); - multZPC = bc.zdc().amplitudeZPC(); - } else { - multZNA = -999.f; - multZNC = -999.f; - multZEM1 = -999.f; - multZEM2 = -999.f; - multZPA = -999.f; - multZPC = -999.f; + void processCollisionNeighbors(aod::Collisions const& collisions) + { + std::vector timeArray; + timeArray.resize(collisions.size(), 1e+3); + + for (const auto& collision : collisions) { + timeArray[collision.globalIndex()] = collision.collisionTime(); } - multBC(multFT0A, multFT0C, multFV0A, multFDDA, multFDDC, multZNA, multZNC, multZEM1, multZEM2, multZPA, multZPC, Tvx, isFV0OrA, multFV0TriggerBits, multFT0TriggerBits, multFDDTriggerBits, multBCTriggerMask, collidingBC); + float deltaPrevious = 1e+6, deltaPrePrevious = 1e+6; + float deltaNext = 1e+6, deltaNeNext = 1e+6; + for (const auto& collision : collisions) { + int ii = collision.globalIndex(); + + if (ii - 1 >= 0) + deltaPrevious = timeArray[ii] - timeArray[ii - 1]; + if (ii - 2 >= 0) + deltaPrePrevious = timeArray[ii] - timeArray[ii - 2]; + if (ii + 1 < collisions.size()) + deltaNext = timeArray[ii + 1] - timeArray[ii]; + if (ii + 2 < collisions.size()) + deltaNeNext = timeArray[ii + 2] - timeArray[ii]; + + multNeigh(deltaPrePrevious, deltaPrevious, deltaNext, deltaNeNext); + } } + + // Process switches + PROCESS_SWITCH(MultiplicityExtraTable, processBCs, "Produce BC tables", true); + PROCESS_SWITCH(MultiplicityExtraTable, processCollisionNeighbors, "Produce neighbor timing tables", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/Common/TableProducer/multiplicityTable.cxx b/Common/TableProducer/multiplicityTable.cxx index bd455c8b4b1..6deb146daab 100644 --- a/Common/TableProducer/multiplicityTable.cxx +++ b/Common/TableProducer/multiplicityTable.cxx @@ -8,23 +8,40 @@ // 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 multiplicityTable.cxx +/// \brief Produces multiplicity tables +/// +/// \author ALICE +/// + +#include +#include +#include +#include + #include "Framework/ConfigParamSpec.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" -#include "CCDB/BasicCCDBManager.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Multiplicity.h" -#include "TableHelper.h" -#include "iostream" +#include "Framework/HistogramRegistry.h" #include "Framework/ASoAHelpers.h" #include "Framework/O2DatabasePDGPlugin.h" +#include "CCDB/BasicCCDBManager.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/TrackSelectionTables.h" +#include "TableHelper.h" +#include "MetadataHelper.h" +#include "TList.h" +#include "PWGMM/Mult/DataModel/bestCollisionTable.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +MetadataHelper metadataInfo; // Metadata helper + static constexpr int kFV0Mults = 0; static constexpr int kFT0Mults = 1; static constexpr int kFDDMults = 2; @@ -38,9 +55,16 @@ static constexpr int kFV0MultZeqs = 9; static constexpr int kFT0MultZeqs = 10; static constexpr int kFDDMultZeqs = 11; static constexpr int kPVMultZeqs = 12; -static constexpr int kMultsExtraMC = 13; -static constexpr int nTables = 14; -static constexpr int nParameters = 1; +static constexpr int kMultMCExtras = 13; +static constexpr int Ntables = 14; + +// Checking that the Zeq tables are after the normal ones +static_assert(kFV0Mults < kFV0MultZeqs); +static_assert(kFT0Mults < kFT0MultZeqs); +static_assert(kFDDMults < kFDDMultZeqs); +static_assert(kPVMults < kPVMultZeqs); + +static constexpr int Nparameters = 1; static const std::vector tableNames{"FV0Mults", // 0 "FT0Mults", // 1 "FDDMults", // 2 @@ -54,13 +78,14 @@ static const std::vector tableNames{"FV0Mults", // 0 "FT0MultZeqs", // 10 "FDDMultZeqs", // 11 "PVMultZeqs", // 12 - "MultsExtraMC"}; // 13 + "MultMCExtras"}; // 13 static const std::vector parameterNames{"Enable"}; -static const int defaultParameters[nTables][nParameters]{{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}}; +static const int defaultParameters[Ntables][Nparameters]{{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}}; struct MultiplicityTable { SliceCache cache; Produces tableFV0; // 0 + Produces tableFV0AOuter; // 0-bis (produced with FV0) Produces tableFT0; // 1 Produces tableFDD; // 2 Produces tableZDC; // 3 @@ -73,7 +98,9 @@ struct MultiplicityTable { Produces tableFT0Zeqs; // 10 Produces tableFDDZeqs; // 11 Produces tablePVZeqs; // 12 - Produces tableExtraMc; // 13 + Produces tableExtraMc; // 13 + Produces tableExtraMult2MCExtras; + Produces mftMults; // Not accounted for, produced using custom process function to avoid dependencies Produces multsGlobal; // Not accounted for, produced based on process function processGlobalTrackingCounters // For vertex-Z corrections in calibration @@ -83,10 +110,11 @@ struct MultiplicityTable { using Run2Tracks = soa::Join; Partition run2tracklets = (aod::track::trackType == static_cast(o2::aod::track::TrackTypeEnum::Run2Tracklet)); Partition tracksWithTPC = (aod::track::tpcNClsFindable > (uint8_t)0); - Partition pvContribTracks = (nabs(aod::track::eta) < 0.8f) && ((aod::track::flags & (uint32_t)o2::aod::track::PVContributor) == (uint32_t)o2::aod::track::PVContributor); - Partition pvContribTracksEta1 = (nabs(aod::track::eta) < 1.0f) && ((aod::track::flags & (uint32_t)o2::aod::track::PVContributor) == (uint32_t)o2::aod::track::PVContributor); + Partition pvContribTracks = (nabs(aod::track::eta) < 0.8f) && ((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)); + Partition pvContribTracksEta1 = (nabs(aod::track::eta) < 1.0f) && ((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)); Preslice perCol = aod::track::collisionId; Preslice perColIU = aod::track::collisionId; + Preslice perCollisionMFT = o2::aod::fwdtrack::collisionId; using BCsWithRun3Matchings = soa::Join; @@ -94,11 +122,17 @@ struct MultiplicityTable { Configurable doVertexZeq{"doVertexZeq", 1, "if 1: do vertex Z eq mult table"}; Configurable fractionOfEvents{"fractionOfEvents", 2.0, "Fractions of events to keep in case the QA is used"}; Configurable> enabledTables{"enabledTables", - {defaultParameters[0], nTables, nParameters, tableNames, parameterNames}, + {defaultParameters[0], Ntables, Nparameters, tableNames, parameterNames}, "Produce tables depending on needs. Values different than -1 override the automatic setup: the corresponding table can be set off (0) or on (1)"}; - Configurable ccdbUrl{"ccdburl", "http://alice-ccdb.cern.ch", "The CCDB endpoint url address"}; - Configurable ccdbPath{"ccdbpath", "Centrality/Calibration", "The CCDB path for centrality/multiplicity information"}; + struct : ConfigurableGroup { + Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "The CCDB endpoint url address"}; + Configurable ccdbPath{"ccdbPath", "Centrality/Calibration", "The CCDB path for centrality/multiplicity information"}; + Configurable reconstructionPass{"reconstructionPass", "", {"Apass to use when fetching the calibration tables. Empty (default) does not check for any pass. Use `metadata` to fetch it from the AO2D metadata. Otherwise it will override the metadata."}}; + } ccdbConfig; + + Configurable produceHistograms{"produceHistograms", false, {"Option to produce debug histograms"}}; + Configurable autoSetupFromMetadata{"autoSetupFromMetadata", true, {"Autosetup the Run 2 and Run 3 processing from the metadata"}}; int mRunNumber; bool lCalibLoaded; @@ -107,13 +141,30 @@ struct MultiplicityTable { TProfile* hVtxZFT0A; TProfile* hVtxZFT0C; TProfile* hVtxZFDDA; + TProfile* hVtxZFDDC; TProfile* hVtxZNTracks; std::vector mEnabledTables; // Vector of enabled tables + // Debug output + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::QAObject}; + OutputObj listCalib{"calib-list", OutputObjHandlingPolicy::QAObject}; + unsigned int randomSeed = 0; void init(InitContext& context) { + // If both Run 2 and Run 3 data process flags are enabled then we check the metadata + if (autoSetupFromMetadata && metadataInfo.isFullyDefined()) { + LOG(info) << "Autosetting the processing from the metadata"; + if (doprocessRun2 == true && doprocessRun3 == true) { + if (metadataInfo.isRun3()) { + doprocessRun2.value = false; + } else { + doprocessRun3.value = false; + } + } + } + randomSeed = static_cast(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); if (doprocessRun2 == false && doprocessRun3 == false) { LOGF(fatal, "Neither processRun2 nor processRun3 enabled. Please choose one."); @@ -121,8 +172,9 @@ struct MultiplicityTable { if (doprocessRun2 == true && doprocessRun3 == true) { LOGF(fatal, "Cannot enable processRun2 and processRun3 at the same time. Please choose one."); } - bool tEnabled[nTables] = {false}; - for (int i = 0; i < nTables; i++) { + + bool tEnabled[Ntables] = {false}; + for (int i = 0; i < Ntables; i++) { int f = enabledTables->get(tableNames[i].c_str(), "Enable"); enableFlagIfTableRequired(context, tableNames[i], f); if (f == 1) { @@ -133,6 +185,13 @@ struct MultiplicityTable { } } } + // Handle the custom cases. + if (tEnabled[kMultMCExtras]) { + if (enabledTables->get(tableNames[kMultMCExtras].c_str(), "Enable") == -1) { + doprocessMC.value = true; + LOG(info) << "Enabling MC processing due to " << tableNames[kMultMCExtras] << " table being enabled."; + } + } // Check that the tables are enabled consistenly if (tEnabled[kFV0MultZeqs] && !tEnabled[kFV0Mults]) { // FV0 @@ -151,6 +210,7 @@ struct MultiplicityTable { mEnabledTables.push_back(kPVMults); LOG(info) << "Cannot have the " << tableNames[kPVMultZeqs] << " table enabled and not the one on " << tableNames[kPVMults] << ". Enabling it."; } + std::sort(mEnabledTables.begin(), mEnabledTables.end()); mRunNumber = 0; lCalibLoaded = false; @@ -162,12 +222,24 @@ struct MultiplicityTable { hVtxZFDDC = nullptr; hVtxZNTracks = nullptr; - ccdb->setURL(ccdbUrl); + ccdb->setURL(ccdbConfig.ccdburl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); // don't fatal, please - exception is caught explicitly (as it should) + + listCalib.setObject(new TList); + if (!produceHistograms.value) { + return; + } + histos.add("FT0A", "FT0A vs FT0A eq.", HistType::kTH2D, {{1000, 0, 1000, "FT0A multiplicity"}, {1000, 0, 1000, "FT0A multiplicity eq."}}); + histos.add("FT0C", "FT0C vs FT0C eq.", HistType::kTH2D, {{1000, 0, 1000, "FT0C multiplicity"}, {1000, 0, 1000, "FT0C multiplicity eq."}}); + histos.add("FT0CMultvsPV", "FT0C vs mult.", HistType::kTH2D, {{1000, 0, 1000, "FT0C mult."}, {100, 0, 100, "PV mult."}}); + histos.add("FT0AMultvsPV", "FT0A vs mult.", HistType::kTH2D, {{1000, 0, 1000, "FT0A mult."}, {100, 0, 100, "PV mult."}}); } + /// Dummy process function for BCs, needed in case both Run2 and Run3 process functions are disabled + void process(aod::BCs const&) {} + void processRun2(aod::Run2MatchedSparse::iterator const& collision, Run2Tracks const&, aod::BCs const&, @@ -194,21 +266,21 @@ struct MultiplicityTable { int multNContribsEtaHalf = 0; if (collision.has_fv0a()) { - for (auto amplitude : collision.fv0a().amplitude()) { + for (const auto& amplitude : collision.fv0a().amplitude()) { multFV0A += amplitude; } } if (collision.has_fv0c()) { - for (auto amplitude : collision.fv0c().amplitude()) { + for (const auto& amplitude : collision.fv0c().amplitude()) { multFV0C += amplitude; } } if (collision.has_ft0()) { auto ft0 = collision.ft0(); - for (auto amplitude : ft0.amplitudeA()) { + for (const auto& amplitude : ft0.amplitudeA()) { multFT0A += amplitude; } - for (auto amplitude : ft0.amplitudeC()) { + for (const auto& amplitude : ft0.amplitudeC()) { multFT0C += amplitude; } } @@ -218,7 +290,20 @@ struct MultiplicityTable { multZNC = zdc.energyCommonZNC(); } - LOGF(debug, "multFV0A=%5.0f multFV0C=%5.0f multFT0A=%5.0f multFT0C=%5.0f multFDDA=%5.0f multFDDC=%5.0f multZNA=%6.0f multZNC=%6.0f multTracklets=%i multTPC=%i", multFV0A, multFV0C, multFT0A, multFT0C, multFDDA, multFDDC, multZNA, multZNC, multTracklets, multTPC); + // Try to do something Similar to https://github.com/alisw/AliPhysics/blob/22862a945004f719f8e9664c0264db46e7186a48/OADB/AliPPVsMultUtils.cxx#L541C26-L541C37 + for (const auto& tracklet : trackletsGrouped) { + if (std::abs(tracklet.eta()) < 1.0) { + multNContribsEta1++; + } + if (std::abs(tracklet.eta()) < 0.8) { + multNContribs++; + } + if (std::abs(tracklet.eta()) < 0.5) { + multNContribsEtaHalf++; + } + } + + LOGF(debug, "multFV0A=%5.0f multFV0C=%5.0f multFT0A=%5.0f multFT0C=%5.0f multFDDA=%5.0f multFDDC=%5.0f multZNA=%6.0f multZNC=%6.0f multTracklets=%i multTPC=%i multNContribsEta1=%i multNContribs=%i multNContribsEtaHalf=%i", multFV0A, multFV0C, multFT0A, multFT0C, multFDDA, multFDDC, multZNA, multZNC, multTracklets, multTPC, multNContribs, multNContribsEta1, multNContribsEtaHalf); tableFV0(multFV0A, multFV0C); tableFT0(multFT0A, multFT0C); tableFDD(multFDDA, multFDDC); @@ -228,14 +313,15 @@ struct MultiplicityTable { tablePv(multNContribs, multNContribsEta1, multNContribsEtaHalf); } - using Run3Tracks = soa::Join; - Partition tracksIUWithTPC = (aod::track::tpcNClsFindable > (uint8_t)0); - Partition pvAllContribTracksIU = ((aod::track::flags & (uint32_t)o2::aod::track::PVContributor) == (uint32_t)o2::aod::track::PVContributor); - Partition pvContribTracksIU = (nabs(aod::track::eta) < 0.8f) && ((aod::track::flags & (uint32_t)o2::aod::track::PVContributor) == (uint32_t)o2::aod::track::PVContributor); - Partition pvContribTracksIUEta1 = (nabs(aod::track::eta) < 1.0f) && ((aod::track::flags & (uint32_t)o2::aod::track::PVContributor) == (uint32_t)o2::aod::track::PVContributor); - Partition pvContribTracksIUEtaHalf = (nabs(aod::track::eta) < 0.5f) && ((aod::track::flags & (uint32_t)o2::aod::track::PVContributor) == (uint32_t)o2::aod::track::PVContributor); + using Run3TracksIU = soa::Join; + Partition tracksIUWithTPC = (aod::track::tpcNClsFindable > (uint8_t)0); + Partition pvAllContribTracksIU = ((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)); + Partition pvContribTracksIU = (nabs(aod::track::eta) < 0.8f) && ((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)); + Partition pvContribTracksIUEta1 = (nabs(aod::track::eta) < 1.0f) && ((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)); + Partition pvContribTracksIUEtaHalf = (nabs(aod::track::eta) < 0.5f) && ((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)); + void processRun3(soa::Join const& collisions, - Run3Tracks const&, + Run3TracksIU const&, BCsWithRun3Matchings const&, aod::Zdcs const&, aod::FV0As const&, @@ -243,10 +329,11 @@ struct MultiplicityTable { aod::FDDs const&) { // reserve memory - for (auto i : mEnabledTables) { + for (const auto& i : mEnabledTables) { switch (i) { case kFV0Mults: // FV0 tableFV0.reserve(collisions.size()); + tableFV0AOuter.reserve(collisions.size()); break; case kFT0Mults: // FT0 tableFT0.reserve(collisions.size()); @@ -284,8 +371,7 @@ struct MultiplicityTable { case kPVMultZeqs: // Equalized multiplicity for PV tablePVZeqs.reserve(collisions.size()); break; - case kMultsExtraMC: // MC extra information - tableExtraMc.reserve(collisions.size()); + case kMultMCExtras: // MC extra information (nothing to do in the data) break; default: LOG(fatal) << "Unknown table requested: " << i; @@ -295,6 +381,7 @@ struct MultiplicityTable { // Initializing multiplicity values float multFV0A = 0.f; + float multFV0AOuter = 0.f; float multFV0C = 0.f; float multFT0A = 0.f; float multFT0C = 0.f; @@ -327,8 +414,25 @@ struct MultiplicityTable { if (doVertexZeq > 0) { if (bc.runNumber() != mRunNumber) { mRunNumber = bc.runNumber(); // mark this run as at least tried - lCalibObjects = ccdb->getForTimeStamp(ccdbPath, bc.timestamp()); + if (ccdbConfig.reconstructionPass.value == "") { + lCalibObjects = ccdb->getForRun(ccdbConfig.ccdbPath, mRunNumber); + } else if (ccdbConfig.reconstructionPass.value == "metadata") { + std::map metadata; + metadata["RecoPassName"] = metadataInfo.get("RecoPassName"); + LOGF(info, "Loading CCDB for reconstruction pass (from metadata): %s", metadataInfo.get("RecoPassName")); + lCalibObjects = ccdb->getSpecificForRun(ccdbConfig.ccdbPath, mRunNumber, metadata); + } else { + std::map metadata; + metadata["RecoPassName"] = ccdbConfig.reconstructionPass.value; + LOGF(info, "Loading CCDB for reconstruction pass (from provided argument): %s", ccdbConfig.reconstructionPass.value); + lCalibObjects = ccdb->getSpecificForRun(ccdbConfig.ccdbPath, mRunNumber, metadata); + } + if (lCalibObjects) { + if (produceHistograms) { + listCalib->Add(lCalibObjects->Clone(Form("%i", bc.runNumber()))); + } + hVtxZFV0A = static_cast(lCalibObjects->FindObject("hVtxZFV0A")); hVtxZFT0A = static_cast(lCalibObjects->FindObject("hVtxZFT0A")); hVtxZFT0C = static_cast(lCalibObjects->FindObject("hVtxZFT0C")); @@ -348,23 +452,30 @@ struct MultiplicityTable { } } - for (auto i : mEnabledTables) { + for (const auto& i : mEnabledTables) { switch (i) { case kFV0Mults: // FV0 { multFV0A = 0.f; + multFV0AOuter = 0.f; multFV0C = 0.f; // using FV0 row index from event selection task if (collision.has_foundFV0()) { - auto fv0 = collision.foundFV0(); - for (auto amplitude : fv0.amplitude()) { + const auto& fv0 = collision.foundFV0(); + for (size_t ii = 0; ii < fv0.amplitude().size(); ii++) { + auto amplitude = fv0.amplitude()[ii]; + auto channel = fv0.channel()[ii]; multFV0A += amplitude; + if (channel > 7) { + multFV0AOuter += amplitude; + } } } else { multFV0A = -999.f; multFV0C = -999.f; } tableFV0(multFV0A, multFV0C); + tableFV0AOuter(multFV0AOuter); LOGF(debug, "multFV0A=%5.0f multFV0C=%5.0f", multFV0A, multFV0C); } break; case kFT0Mults: // FT0 @@ -374,10 +485,10 @@ struct MultiplicityTable { // using FT0 row index from event selection task if (collision.has_foundFT0()) { const auto& ft0 = collision.foundFT0(); - for (auto amplitude : ft0.amplitudeA()) { + for (const auto& amplitude : ft0.amplitudeA()) { multFT0A += amplitude; } - for (auto amplitude : ft0.amplitudeC()) { + for (const auto& amplitude : ft0.amplitudeC()) { multFT0C += amplitude; } } else { @@ -394,10 +505,10 @@ struct MultiplicityTable { // using FDD row index from event selection task if (collision.has_foundFDD()) { const auto& fdd = collision.foundFDD(); - for (auto amplitude : fdd.chargeA()) { + for (const auto& amplitude : fdd.chargeA()) { multFDDA += amplitude; } - for (auto amplitude : fdd.chargeC()) { + for (const auto& amplitude : fdd.chargeC()) { multFDDC += amplitude; } } else { @@ -449,12 +560,15 @@ struct MultiplicityTable { // use only one single grouping operation, then do loop const auto& tracksThisCollision = pvContribTracksIUEta1.sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); multNContribsEta1 = tracksThisCollision.size(); - for (auto track : tracksThisCollision) { - if (std::abs(track.eta()) < 0.8) + for (const auto& track : tracksThisCollision) { + if (std::abs(track.eta()) < 0.8) { multNContribs++; - if (std::abs(track.eta()) < 0.5) + } + if (std::abs(track.eta()) < 0.5) { multNContribsEtaHalf++; + } } + tablePv(multNContribs, multNContribsEta1, multNContribsEtaHalf); LOGF(debug, "multNContribs=%i, multNContribsEta1=%i, multNContribsEtaHalf=%i", multNContribs, multNContribsEta1, multNContribsEtaHalf); } break; @@ -465,7 +579,7 @@ struct MultiplicityTable { const auto& pvAllContribsGrouped = pvAllContribTracksIU->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); const auto& tpcTracksGrouped = tracksIUWithTPC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - for (auto track : pvAllContribsGrouped) { + for (const auto& track : pvAllContribsGrouped) { if (track.hasITS()) { nHasITS++; if (track.hasTPC()) @@ -486,7 +600,7 @@ struct MultiplicityTable { int nAllTracksTPCOnly = 0; int nAllTracksITSTPC = 0; - for (auto track : tpcTracksGrouped) { + for (const auto& track : tpcTracksGrouped) { if (track.hasITS()) { nAllTracksITSTPC++; } else { @@ -494,12 +608,13 @@ struct MultiplicityTable { } } - int bcNumber = bc.globalBC() % 3564; - tableExtra(collision.numContrib(), collision.chi2(), collision.collisionTimeRes(), mRunNumber, collision.posZ(), collision.sel8(), nHasITS, nHasTPC, nHasTOF, nHasTRD, nITSonly, nTPConly, nITSTPC, - nAllTracksTPCOnly, nAllTracksITSTPC, bcNumber); + nAllTracksTPCOnly, nAllTracksITSTPC, + collision.trackOccupancyInTimeRange(), + collision.ft0cOccupancyInTimeRange(), + collision.flags()); } break; case kMultSelections: // Multiplicity selections { @@ -507,22 +622,28 @@ struct MultiplicityTable { } break; case kFV0MultZeqs: // Z equalized FV0 { - if (fabs(collision.posZ()) < 15.0f && lCalibLoaded) { + if (std::fabs(collision.posZ()) < 15.0f && lCalibLoaded) { multZeqFV0A = hVtxZFV0A->Interpolate(0.0) * multFV0A / hVtxZFV0A->Interpolate(collision.posZ()); } tableFV0Zeqs(multZeqFV0A); } break; case kFT0MultZeqs: // Z equalized FT0 { - if (fabs(collision.posZ()) < 15.0f && lCalibLoaded) { + if (std::fabs(collision.posZ()) < 15.0f && lCalibLoaded) { multZeqFT0A = hVtxZFT0A->Interpolate(0.0) * multFT0A / hVtxZFT0A->Interpolate(collision.posZ()); multZeqFT0C = hVtxZFT0C->Interpolate(0.0) * multFT0C / hVtxZFT0C->Interpolate(collision.posZ()); } + if (produceHistograms.value) { + histos.fill(HIST("FT0A"), multFT0A, multZeqFT0A); + histos.fill(HIST("FT0C"), multFT0C, multZeqFT0C); + histos.fill(HIST("FT0AMultvsPV"), multZeqFT0A, multNContribs); + histos.fill(HIST("FT0CMultvsPV"), multZeqFT0C, multNContribs); + } tableFT0Zeqs(multZeqFT0A, multZeqFT0C); } break; case kFDDMultZeqs: // Z equalized FDD { - if (fabs(collision.posZ()) < 15.0f && lCalibLoaded) { + if (std::fabs(collision.posZ()) < 15.0f && lCalibLoaded) { multZeqFDDA = hVtxZFDDA->Interpolate(0.0) * multFDDA / hVtxZFDDA->Interpolate(collision.posZ()); multZeqFDDC = hVtxZFDDC->Interpolate(0.0) * multFDDC / hVtxZFDDC->Interpolate(collision.posZ()); } @@ -530,12 +651,12 @@ struct MultiplicityTable { } break; case kPVMultZeqs: // Z equalized PV { - if (fabs(collision.posZ()) < 15.0f && lCalibLoaded) { + if (std::fabs(collision.posZ()) < 15.0f && lCalibLoaded) { multZeqNContribs = hVtxZNTracks->Interpolate(0.0) * multNContribs / hVtxZNTracks->Interpolate(collision.posZ()); } tablePVZeqs(multZeqNContribs); } break; - case kMultsExtraMC: // MC only (nothing to do) + case kMultMCExtras: // MC only (nothing to do) { } break; default: // Default @@ -550,19 +671,23 @@ struct MultiplicityTable { // one loop better than multiple sliceby calls // FIT FT0C: -3.3 < η < -2.1 // FOT FT0A: 3.5 < η < 4.9 - Filter mcParticleFilter = (aod::mcparticle::eta < 4.9f) && (aod::mcparticle::eta > -3.3f); - using mcParticlesFiltered = soa::Filtered; + Filter mcParticleFilter = (aod::mcparticle::eta < 7.0f) && (aod::mcparticle::eta > -7.0f); + using McParticlesFiltered = soa::Filtered; - void processMC(aod::McCollision const&, mcParticlesFiltered const& mcParticles) + void processMC(aod::McCollision const& mcCollision, McParticlesFiltered const& mcParticles) { int multFT0A = 0; + int multFV0A = 0; int multFT0C = 0; + int multFDDA = 0; + int multFDDC = 0; int multBarrelEta05 = 0; int multBarrelEta08 = 0; int multBarrelEta10 = 0; for (auto const& mcPart : mcParticles) { - if (!mcPart.isPhysicalPrimary()) + if (!mcPart.isPhysicalPrimary()) { continue; + } auto charge = 0.; auto* p = pdg->GetParticle(mcPart.pdgCode()); @@ -586,31 +711,109 @@ struct MultiplicityTable { multFT0C++; if (3.5 < mcPart.eta() && mcPart.eta() < 4.9) multFT0A++; + if (2.2 < mcPart.eta() && mcPart.eta() < 5.0) + multFV0A++; + if (-6.9 < mcPart.eta() && mcPart.eta() < -4.9) + multFDDC++; + if (4.7 < mcPart.eta() && mcPart.eta() < 6.3) + multFDDA++; } - tableExtraMc(multFT0A, multFT0C, multBarrelEta05, multBarrelEta08, multBarrelEta10); + tableExtraMc(multFT0A, multFT0C, multFV0A, multFDDA, multFDDC, multBarrelEta05, multBarrelEta08, multBarrelEta10, mcCollision.posZ()); + } + + void processMC2Mults(soa::Join::iterator const& collision) + { + tableExtraMult2MCExtras(collision.mcCollisionId()); // interlink } - void processGlobalTrackingCounters(aod::Collision const&, - soa::Join const& tracks) + Configurable minPtGlobalTrack{"minPtGlobalTrack", 0.15, "min. pT for global tracks"}; + Configurable maxPtGlobalTrack{"maxPtGlobalTrack", 1e+10, "max. pT for global tracks"}; + Configurable minNclsITSGlobalTrack{"minNclsITSGlobalTrack", 5, "min. number of ITS clusters for global tracks"}; + Configurable minNclsITSibGlobalTrack{"minNclsITSibGlobalTrack", 1, "min. number of ITSib clusters for global tracks"}; + + using Run3Tracks = soa::Join; + Partition pvContribGlobalTracksEta1 = (minPtGlobalTrack < aod::track::pt && aod::track::pt < maxPtGlobalTrack) && (nabs(aod::track::eta) < 1.0f) && ((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)) && requireQualityTracksInFilter(); + + void processGlobalTrackingCounters(aod::Collision const& collision, soa::Join const& tracksIU, Run3Tracks const&) { // counter from Igor int nGlobalTracks = 0; - for (auto& track : tracks) { - if (fabs(track.eta()) < 0.8 && track.tpcNClsFound() >= 80 && track.tpcNClsCrossedRows() >= 100) { + int multNbrContribsEta05GlobalTrackWoDCA = 0; + int multNbrContribsEta08GlobalTrackWoDCA = 0; + int multNbrContribsEta10GlobalTrackWoDCA = 0; + + auto pvContribGlobalTracksEta1PerCollision = pvContribGlobalTracksEta1->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + for (const auto& track : pvContribGlobalTracksEta1PerCollision) { + if (track.itsNCls() < minNclsITSGlobalTrack || track.itsNClsInnerBarrel() < minNclsITSibGlobalTrack) { + continue; + } + multNbrContribsEta10GlobalTrackWoDCA++; + + if (std::abs(track.eta()) < 0.8) { + multNbrContribsEta08GlobalTrackWoDCA++; + } + if (std::abs(track.eta()) < 0.5) { + multNbrContribsEta05GlobalTrackWoDCA++; + } + } + + for (const auto& track : tracksIU) { + if (std::fabs(track.eta()) < 0.8 && track.tpcNClsFound() >= 80 && track.tpcNClsCrossedRows() >= 100) { if (track.isGlobalTrack()) { nGlobalTracks++; } } } - multsGlobal(nGlobalTracks); + + LOGF(debug, "nGlobalTracks = %d, multNbrContribsEta08GlobalTrackWoDCA = %d, multNbrContribsEta10GlobalTrackWoDCA = %d, multNbrContribsEta05GlobalTrackWoDCA = %d", nGlobalTracks, multNbrContribsEta08GlobalTrackWoDCA, multNbrContribsEta10GlobalTrackWoDCA, multNbrContribsEta05GlobalTrackWoDCA); + + multsGlobal(nGlobalTracks, multNbrContribsEta08GlobalTrackWoDCA, multNbrContribsEta10GlobalTrackWoDCA, multNbrContribsEta05GlobalTrackWoDCA); + } + + void processRun3MFT(soa::Join::iterator const&, + o2::aod::MFTTracks const& mftTracks, + soa::SmallGroups const& retracks) + { + int nAllTracks = 0; + int nTracks = 0; + + for (const auto& track : mftTracks) { + if (track.nClusters() >= 5) { // hardcoded for now + nAllTracks++; + } + } + + if (retracks.size() > 0) { + for (const auto& retrack : retracks) { + auto track = retrack.mfttrack(); + if (track.nClusters() < 5) { + continue; // min cluster requirement + } + if ((track.eta() > -2.0f) && (track.eta() < -3.9f)) { + continue; // too far to be of true interest + } + if (std::abs(retrack.bestDCAXY()) > 2.0f) { + continue; // does not point to PV properly + } + nTracks++; + } + } + mftMults(nAllTracks, nTracks); } // Process switches - PROCESS_SWITCH(MultiplicityTable, processRun2, "Produce Run 2 multiplicity tables", false); - PROCESS_SWITCH(MultiplicityTable, processRun3, "Produce Run 3 multiplicity tables", true); + PROCESS_SWITCH(MultiplicityTable, processRun2, "Produce Run 2 multiplicity tables. Autoset if both processRun2 and processRun3 are enabled", true); + PROCESS_SWITCH(MultiplicityTable, processRun3, "Produce Run 3 multiplicity tables. Autoset if both processRun2 and processRun3 are enabled", true); PROCESS_SWITCH(MultiplicityTable, processGlobalTrackingCounters, "Produce Run 3 global counters", false); PROCESS_SWITCH(MultiplicityTable, processMC, "Produce MC multiplicity tables", false); + PROCESS_SWITCH(MultiplicityTable, processMC2Mults, "Produce MC -> Mult map", false); + PROCESS_SWITCH(MultiplicityTable, processRun3MFT, "Produce MFT mult tables", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // Parse the metadata + metadataInfo.initMetadata(cfgc); + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/Common/TableProducer/muonRealignment.cxx b/Common/TableProducer/muonRealignment.cxx new file mode 100644 index 00000000000..9da3a27d97f --- /dev/null +++ b/Common/TableProducer/muonRealignment.cxx @@ -0,0 +1,410 @@ +// 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 muonRealignment.cxx +/// \brief Task for muon re-alignment at analysis level +/// \author Chi Zhang , CEA-Saclay + +#include +#include +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/ASoAHelpers.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "CommonUtils/NameConf.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DataFormatsMCH/Cluster.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include "DetectorsBase/Propagator.h" +#include "MathUtils/Cartesian.h" +#include "MCHGeometryTransformer/Transformations.h" +#include "MCHTracking/Track.h" +#include "MCHTracking/TrackExtrap.h" +#include "MCHTracking/TrackParam.h" +#include "MCHTracking/TrackFitter.h" +#include "MCHBase/TrackerParam.h" +#include "GlobalTracking/MatchGlobalFwd.h" +#include "ReconstructionDataFormats/TrackFwd.h" +#include "Common/DataModel/FwdTrackReAlignTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/CollisionAssociationTables.h" + +using namespace std; +using namespace o2; +using namespace o2::framework; +using namespace o2::mch; +using namespace o2::framework::expressions; + +const int fgNDetElemCh[10] = {4, 4, 4, 4, 18, 18, 26, 26, 26, 26}; +const int fgSNDetElemCh[11] = {0, 4, 8, 12, 16, 34, 52, 78, 104, 130, 156}; + +struct FwdTrkCovRealignInfo { + float sigX = 0.f; + float sigY = 0.f; + float sigPhi = 0.f; + float sigTgl = 0.f; + float sig1Pt = 0.f; + int8_t rhoXY = 0; + int8_t rhoPhiX = 0; + int8_t rhoPhiY = 0; + int8_t rhoTglX = 0; + int8_t rhoTglY = 0; + int8_t rhoTglPhi = 0; + int8_t rho1PtX = 0; + int8_t rho1PtY = 0; + int8_t rho1PtPhi = 0; + int8_t rho1PtTgl = 0; +}; + +struct MuonRealignment { + Produces realignFwdTrks; + Produces realignFwdTrksCov; + + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable geoRefPath{"geoRefPath", "GLO/Config/GeometryAligned", "Path of the reference geometry file"}; + Configurable geoNewPath{"geoNewPath", "GLO/Config/GeometryAligned", "Path of the new geometry file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable grpPathLocal{"grpPathLocal", "", "Local path of the GRP object if not using CCDB"}; + Configurable geoNewPathLocal{"geoNewPathLocal", "", "Local path of the GRP object if not using CCDB"}; + Configurable nolaterthanRef{"ccdb-no-later-than-ref", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object of reference basis"}; + Configurable nolaterthanNew{"ccdb-no-later-than-new", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object of new basis"}; + Configurable cfgChamberResolutionX{"cfgChamberResolutionX", 0.04, "Chamber resolution along X configuration for refit"}; // 0.4cm pp, 0.2cm PbPb + Configurable cfgChamberResolutionY{"cfgChamberResolutionY", 0.04, "Chamber resolution along Y configuration for refit"}; // 0.4cm pp, 0.2cm PbPb + Configurable cfgSigmaCutImprove{"cfgSigmaCutImprove", 6., "Sigma cut for track improvement"}; // 6 for pp, 4 for PbPb + Configurable fUseRemoteField{"cfgUseRemoteField", true, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; + Configurable fUseRemoteGeometry{"cfgUseRemoteGeometry", false, "Chose whether to fetch new geometry from ccdb or set it manually"}; + + parameters::GRPMagField* grpmag = nullptr; + base::MatLayerCylSet* lut = nullptr; + TrackFitter trackFitter; // Track fitter from MCH tracking library + geo::TransformationCreator transformation; + map transformRef; // reference geometry w.r.t track data + map transformNew; // new geometry + globaltracking::MatchGlobalFwd mMatching; + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + double mImproveCutChi2; // Chi2 cut for track improvement. + Service ccdb; + TGeoManager* geoNew = nullptr; + TGeoManager* geoRef = nullptr; + + Preslice perMuon = aod::fwdtrkcl::fwdtrackId; + Preslice fwdtrackIndicesPerCollision = aod::track_association::collisionId; + + int GetDetElemId(int iDetElemNumber) + { + // make sure detector number is valid + if (!(iDetElemNumber >= fgSNDetElemCh[0] && + iDetElemNumber < fgSNDetElemCh[10])) { + LOGF(fatal, "Invalid detector element number: %d", iDetElemNumber); + } + /// get det element number from ID + // get chamber and element number in chamber + int iCh = 0; + int iDet = 0; + for (int i = 1; i <= 10; i++) { + if (iDetElemNumber < fgSNDetElemCh[i]) { + iCh = i; + iDet = iDetElemNumber - fgSNDetElemCh[i - 1]; + break; + } + } + + // make sure detector index is valid + if (!(iCh > 0 && iCh <= 10 && iDet < fgNDetElemCh[iCh - 1])) { + LOGF(fatal, "Invalid detector element id: %d", 100 * iCh + iDet); + } + + // add number of detectors up to this chamber + return 100 * iCh + iDet; + } + + bool RemoveTrack(mch::Track& track) + { + // Refit track with re-aligned clusters + bool removeTrack = false; + try { + trackFitter.fit(track, false); + } catch (exception const& e) { + removeTrack = true; + return removeTrack; + } + + auto itStartingParam = std::prev(track.rend()); + + while (true) { + + try { + trackFitter.fit(track, true, false, (itStartingParam == track.rbegin()) ? nullptr : &itStartingParam); + } catch (exception const&) { + removeTrack = true; + break; + } + + double worstLocalChi2 = -1.0; + + track.tagRemovableClusters(0x1F, false); + + auto itWorstParam = track.end(); + + for (auto itParam = track.begin(); itParam != track.end(); ++itParam) { + if (itParam->getLocalChi2() > worstLocalChi2) { + worstLocalChi2 = itParam->getLocalChi2(); + itWorstParam = itParam; + } + } + + if (worstLocalChi2 < mImproveCutChi2) { + break; + } + + if (!itWorstParam->isRemovable()) { + removeTrack = true; + track.removable(); + break; + } + + auto itNextParam = track.removeParamAtCluster(itWorstParam); + auto itNextToNextParam = (itNextParam == track.end()) ? itNextParam : std::next(itNextParam); + itStartingParam = track.rbegin(); + + if (track.getNClusters() < 10) { + removeTrack = true; + break; + } else { + while (itNextToNextParam != track.end()) { + if (itNextToNextParam->getClusterPtr()->getChamberId() != itNextParam->getClusterPtr()->getChamberId()) { + itStartingParam = std::make_reverse_iterator(++itNextParam); + break; + } + ++itNextToNextParam; + } + } + } + + if (!removeTrack) { + for (auto& param : track) { + param.setParameters(param.getSmoothParameters()); + param.setCovariances(param.getSmoothCovariances()); + } + } + + return removeTrack; + } + + void init(InitContext const&) + { + fCurrentRun = 0; + + // Configuration for CCDB server + ccdb->setURL(ccdburl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + // Configuration for track fitter + const auto& trackerParam = TrackerParam::Instance(); + trackFitter.setBendingVertexDispersion(trackerParam.bendingVertexDispersion); + trackFitter.setChamberResolution(cfgChamberResolutionX.value, cfgChamberResolutionY.value); + trackFitter.smoothTracks(true); + trackFitter.useChamberResolution(); + mImproveCutChi2 = 2. * cfgSigmaCutImprove.value * cfgSigmaCutImprove.value; + } + + template + void runMuonRealignment(TEvent const& collision, aod::BCsWithTimestamps const&, TMuons const&, TMuonCls const& clusters, AssocMuons const& fwdtrackIndices) + { + auto bc = collision.template bc_as(); + if (fCurrentRun != bc.runNumber()) { + // Load magnetic field information from CCDB/local + if (fUseRemoteField) { + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + grpmag = ccdb->getForTimeStamp(grpmagPath, bc.timestamp()); + if (grpmag != nullptr) { + base::Propagator::initFieldFromGRP(grpmag); + TrackExtrap::setField(); + TrackExtrap::useExtrapV2(); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", bc.timestamp()); + } + } else { + if (std::filesystem::exists(grpPathLocal.value)) { + const auto grp = parameters::GRPObject::loadFrom(grpPathLocal.value); + base::Propagator::initFieldFromGRP(grp); + TrackExtrap::setField(); + TrackExtrap::useExtrapV2(); + } else { + LOGF(fatal, "GRP object is not available in local path: %s", grpPathLocal.value); + } + } + + // Load geometry information from CCDB/local + LOGF(info, "Loading reference aligned geometry from CCDB no later than %d", nolaterthanRef.value); + ccdb->setCreatedNotAfter(nolaterthanRef.value); // this timestamp has to be consistent with what has been used in reco + geoRef = ccdb->getForTimeStamp(geoRefPath, bc.timestamp()); + ccdb->clearCache(geoRefPath); + if (geoRef != nullptr) { + transformation = geo::transformationFromTGeoManager(*geoRef); + } else { + LOGF(fatal, "Reference aligned geometry object is not available in CCDB at timestamp=%llu", bc.timestamp()); + } + for (int i = 0; i < 156; i++) { + int iDEN = GetDetElemId(i); + transformRef[iDEN] = transformation(iDEN); + } + + if (fUseRemoteGeometry) { + LOGF(info, "Loading new aligned geometry from CCDB no later than %d", nolaterthanNew.value); + ccdb->setCreatedNotAfter(nolaterthanNew.value); // make sure this timestamp can be resolved regarding the reference one + geoNew = ccdb->getForTimeStamp(geoNewPath, bc.timestamp()); + ccdb->clearCache(geoNewPath); + if (geoNew != nullptr) { + transformation = geo::transformationFromTGeoManager(*geoNew); + } else { + LOGF(fatal, "New aligned geometry object is not available in CCDB at timestamp=%llu", bc.timestamp()); + } + for (int i = 0; i < 156; i++) { + int iDEN = GetDetElemId(i); + transformNew[iDEN] = transformation(iDEN); + } + } else { + LOGF(info, "Loading new aligned geometry from local path: %s", geoNewPathLocal.value); + if (std::filesystem::exists(geoNewPathLocal.value)) { + base::GeometryManager::loadGeometry(geoNewPathLocal.value); + transformation = geo::transformationFromTGeoManager(*gGeoManager); + for (int i = 0; i < 156; i++) { + int iDEN = GetDetElemId(i); + transformNew[iDEN] = transformation(iDEN); + } + } else { + LOGF(fatal, "New geometry file is not available in local path: %s", geoNewPathLocal.value); + } + } + + fCurrentRun = bc.runNumber(); + } + + // Reserve storage for output table + realignFwdTrks.reserve(fwdtrackIndices.size()); + realignFwdTrksCov.reserve(fwdtrackIndices.size()); + + // Loop over forward tracks using association indices + FwdTrkCovRealignInfo fwdTrkCovRealignInfo; + for (auto const& muonId : fwdtrackIndices) { + auto muon = muonId.template fwdtrack_as(); + int muonRealignId = muon.globalIndex(); + if ((muon.trackType() == aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) || (muon.trackType() == aod::fwdtrack::ForwardTrackTypeEnum::MCHStandaloneTrack)) { + + auto clustersSliced = clusters.sliceBy(perMuon, muon.globalIndex()); // Slice clusters by muon id + mch::Track convertedTrack = mch::Track(); // Temporary variable to store re-aligned clusters + int clIndex = -1; + // Get re-aligned clusters associated to current track + for (auto const& cluster : clustersSliced) { + clIndex += 1; + + mch::Cluster* clusterMCH = new mch::Cluster(); + + math_utils::Point3D local; + math_utils::Point3D master; + master.SetXYZ(cluster.x(), cluster.y(), cluster.z()); + + // Transformation from reference geometry frame to new geometry frame + transformRef[cluster.deId()].MasterToLocal(master, local); + transformNew[cluster.deId()].LocalToMaster(local, master); + + clusterMCH->x = master.x(); + clusterMCH->y = master.y(); + clusterMCH->z = master.z(); + + uint32_t ClUId = mch::Cluster::buildUniqueId(static_cast(cluster.deId() / 100) - 1, cluster.deId(), clIndex); + clusterMCH->uid = ClUId; + clusterMCH->ex = cluster.isGoodX() ? 0.2 : 10.0; + clusterMCH->ey = cluster.isGoodY() ? 0.2 : 10.0; + + // Add transformed cluster into temporary variable + convertedTrack.createParamAtCluster(*clusterMCH); + LOGF(debug, "Track %d, cluster DE%d: x:%g y:%g z:%g", muon.globalIndex(), cluster.deId(), cluster.x(), cluster.y(), cluster.z()); + LOGF(debug, "Track %d, re-aligned cluster DE%d: x:%g y:%g z:%g", muonRealignId, cluster.deId(), clusterMCH->getX(), clusterMCH->getY(), clusterMCH->getZ()); + } + + // Refit the re-aligned track + int removable = 0; + if (convertedTrack.getNClusters() != 0) { + removable = RemoveTrack(convertedTrack); + } else { + LOGF(fatal, "Muon track %d has no associated clusters.", muon.globalIndex()); + } + + // Get the re-aligned track parameter: track param at the first cluster + mch::TrackParam trackParam = mch::TrackParam(convertedTrack.first()); + + // Convert MCH track to FWD track and get new parameters + auto fwdtrack = mMatching.MCHtoFwd(trackParam); + fwdtrack.setTrackChi2(trackParam.getTrackChi2() / convertedTrack.getNDF()); + fwdTrkCovRealignInfo.sigX = TMath::Sqrt(fwdtrack.getCovariances()(0, 0)); + fwdTrkCovRealignInfo.sigY = TMath::Sqrt(fwdtrack.getCovariances()(1, 1)); + fwdTrkCovRealignInfo.sigPhi = TMath::Sqrt(fwdtrack.getCovariances()(2, 2)); + fwdTrkCovRealignInfo.sigTgl = TMath::Sqrt(fwdtrack.getCovariances()(3, 3)); + fwdTrkCovRealignInfo.sig1Pt = TMath::Sqrt(fwdtrack.getCovariances()(4, 4)); + fwdTrkCovRealignInfo.rhoXY = (Char_t)(128. * fwdtrack.getCovariances()(0, 1) / (fwdTrkCovRealignInfo.sigX * fwdTrkCovRealignInfo.sigY)); + fwdTrkCovRealignInfo.rhoPhiX = (Char_t)(128. * fwdtrack.getCovariances()(0, 2) / (fwdTrkCovRealignInfo.sigPhi * fwdTrkCovRealignInfo.sigX)); + fwdTrkCovRealignInfo.rhoPhiY = (Char_t)(128. * fwdtrack.getCovariances()(1, 2) / (fwdTrkCovRealignInfo.sigPhi * fwdTrkCovRealignInfo.sigY)); + fwdTrkCovRealignInfo.rhoTglX = (Char_t)(128. * fwdtrack.getCovariances()(0, 3) / (fwdTrkCovRealignInfo.sigTgl * fwdTrkCovRealignInfo.sigX)); + fwdTrkCovRealignInfo.rhoTglY = (Char_t)(128. * fwdtrack.getCovariances()(1, 3) / (fwdTrkCovRealignInfo.sigTgl * fwdTrkCovRealignInfo.sigY)); + fwdTrkCovRealignInfo.rhoTglPhi = (Char_t)(128. * fwdtrack.getCovariances()(2, 3) / (fwdTrkCovRealignInfo.sigTgl * fwdTrkCovRealignInfo.sigPhi)); + fwdTrkCovRealignInfo.rho1PtX = (Char_t)(128. * fwdtrack.getCovariances()(0, 4) / (fwdTrkCovRealignInfo.sig1Pt * fwdTrkCovRealignInfo.sigX)); + fwdTrkCovRealignInfo.rho1PtY = (Char_t)(128. * fwdtrack.getCovariances()(1, 4) / (fwdTrkCovRealignInfo.sig1Pt * fwdTrkCovRealignInfo.sigY)); + fwdTrkCovRealignInfo.rho1PtPhi = (Char_t)(128. * fwdtrack.getCovariances()(2, 4) / (fwdTrkCovRealignInfo.sig1Pt * fwdTrkCovRealignInfo.sigPhi)); + fwdTrkCovRealignInfo.rho1PtTgl = (Char_t)(128. * fwdtrack.getCovariances()(3, 4) / (fwdTrkCovRealignInfo.sig1Pt * fwdTrkCovRealignInfo.sigTgl)); + LOGF(debug, "TrackParm %d, x:%g y:%g z:%g phi:%g tgl:%g InvQPt:%g chi2:%g nClusters:%d", muon.globalIndex(), muon.x(), muon.y(), muon.z(), muon.phi(), muon.tgl(), muon.signed1Pt(), muon.chi2(), muon.nClusters()); + LOGF(debug, "Re-aligned trackParm %d, x:%g y:%g z:%g phi:%g tgl:%g InvQPt:%g chi2:%g nClusters:%d removable:%d", muonRealignId, fwdtrack.getX(), fwdtrack.getY(), fwdtrack.getZ(), fwdtrack.getPhi(), fwdtrack.getTgl(), fwdtrack.getInvQPt(), fwdtrack.getTrackChi2(), convertedTrack.getNClusters(), removable); + // Fill refitted track info + realignFwdTrks(muonId.collisionId(), muonId.fwdtrackId(), muon.trackType(), fwdtrack.getX(), fwdtrack.getY(), fwdtrack.getZ(), fwdtrack.getPhi(), fwdtrack.getTgl(), fwdtrack.getInvQPt(), fwdtrack.getTrackChi2(), removable); + realignFwdTrksCov(fwdTrkCovRealignInfo.sigX, fwdTrkCovRealignInfo.sigY, fwdTrkCovRealignInfo.sigPhi, + fwdTrkCovRealignInfo.sigTgl, fwdTrkCovRealignInfo.sig1Pt, fwdTrkCovRealignInfo.rhoXY, + fwdTrkCovRealignInfo.rhoPhiX, fwdTrkCovRealignInfo.rhoPhiY, fwdTrkCovRealignInfo.rhoTglX, + fwdTrkCovRealignInfo.rhoTglY, fwdTrkCovRealignInfo.rhoTglPhi, fwdTrkCovRealignInfo.rho1PtX, + fwdTrkCovRealignInfo.rho1PtY, fwdTrkCovRealignInfo.rho1PtPhi, fwdTrkCovRealignInfo.rho1PtTgl); + muonRealignId++; + } else { + // Fill nothing for global muons + realignFwdTrks(muonId.collisionId(), muonId.fwdtrackId(), muon.trackType(), 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, -1.0); + realignFwdTrksCov(0.f, 0.f, 0.f, 0.f, 0.f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + muonRealignId++; + } + } + } + + void processMuonReAlignmentWithAssoc(aod::Collisions const& collisions, aod::BCsWithTimestamps const& bcs, aod::FwdTracks const& tracks, aod::FwdTrkCls const& clusters, aod::FwdTrackAssoc const& fwdtrackIndices) + { + for (auto& collision : collisions) { + auto muonIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); + runMuonRealignment(collision, bcs, tracks, clusters, muonIdsThisCollision); + } + } + PROCESS_SWITCH(MuonRealignment, processMuonReAlignmentWithAssoc, "Process to produce realigned muons based on associated fwdtracks info", true); +}; + +// Extends the fwdtracksrealign table with expression columns +struct MuonRealignmentSpawner { + Spawns realignFwdTrksCov; + Spawns realignFwdTrks; + void init(InitContext const&) {} +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +} diff --git a/Common/TableProducer/occupancyTableProducer.cxx b/Common/TableProducer/occupancyTableProducer.cxx new file mode 100644 index 00000000000..ce56bfda149 --- /dev/null +++ b/Common/TableProducer/occupancyTableProducer.cxx @@ -0,0 +1,1681 @@ +// 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 occupancyTableProducer.cxx +/// \brief Occupancy Table Producer : TPC PID - Calibration +/// Occupancy calculater using tracks which have entry for collision and trackQA tables +/// Ambg tracks were not used +/// \author Rahul Verma (rahul.verma@iitb.ac.in) :: Marian I Ivanov (marian.ivanov@cern.ch) + +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" + +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" + +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/OccupancyTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsFT0/Digit.h" +#include "DataFormatsParameters/GRPLHCIFData.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +int32_t nBCsPerOrbit = o2::constants::lhc::LHCMaxBunches; +// const int nBCinTFgrp80 = 1425; +// nOrbitsPerTF = run < 534133 ? 128 : 32; +// for 128 => nBCsPerTF = 456192 , for 32 => nBCsPerTF = 114048 +const int nBCinTF = 114048; /// CCDB value // to be obtained from CCDB in future +const int nBCinDrift = 114048 / 32; /// to get from ccdb in future +const int arraySize = 10; // Max no timeframes that can be present in a dataframe + +struct OccupancyTableProducer { + + Service ccdb; + + // declare production of tables + Produces genOccIndexTable; + Produces genBCTFinfoTable; + Produces genOccsBCsList; + + Produces genOccsDet; + Produces genOccsTrackMult; + Produces genOccsMultExtra; + Produces genOccsRobust; + + Produces genOccsMeanDet; + Produces genOccsMeanTrkMult; + Produces genOccsMnMultExtra; + Produces genOccsMeanRobust; + + Configurable customOrbitOffset{"customOrbitOffset", 0, "customOrbitOffset for MC"}; + Configurable grouping{"grouping", 80, "grouping of BCs"}; + + Configurable buildOccIndexTable{"buildOccIndexTable", true, "builder of table OccIndexTable"}; + Configurable buildBCTFinfoTable{"buildBCTFinfoTable", true, "builder of table BCTFinfoTable"}; + Configurable buildOccsBCsList{"buildOccsBCsList", true, "builder of table OccsBCsList"}; + + Configurable buildOccsDet{"buildOccsDet", true, "builder of table OccsDet"}; + Configurable buildOccsTrackMult{"buildOccsTrackMult", true, "builder of table OccsTrackMult"}; + Configurable buildOccsMultExtra{"buildOccsMultExtra", true, "builder of table OccsMultExtra"}; + Configurable buildOccsRobust{"buildOccsRobust", true, "builder of table OccsRobust"}; + + Configurable buildOccsMeanDet{"buildOccsMeanDet", true, "builder of table OccsMeanDet"}; + Configurable buildOccsMeanTrkMult{"buildOccsMeanTrkMult", true, "builder of table OccsMeanTrkMult"}; + Configurable buildOccsMnMultExtra{"buildOccsMnMultExtra", true, "builder of table OccsMnMultExtra"}; + Configurable buildOccsMeanRobust{"buildOccsMeanRobust", true, "builder of table OccsMeanRobust"}; + + // Histogram registry; + HistogramRegistry recoEvent{"recoEvent", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry occupancyQA{"occupancyQA", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Data Structures for Occupancy estimation + std::array tfList; + std::array, arraySize> bcTFMap; + std::array, arraySize> occPrimUnfm80; + std::array, arraySize> occFV0AUnfm80; + std::array, arraySize> occFV0CUnfm80; + std::array, arraySize> occFT0AUnfm80; + std::array, arraySize> occFT0CUnfm80; + std::array, arraySize> occFDDAUnfm80; + std::array, arraySize> occFDDCUnfm80; + + std::array, arraySize> occNTrackITSUnfm80; + std::array, arraySize> occNTrackTPCUnfm80; + std::array, arraySize> occNTrackTRDUnfm80; + std::array, arraySize> occNTrackTOFUnfm80; + std::array, arraySize> occNTrackSizeUnfm80; + std::array, arraySize> occNTrackTPCAUnfm80; + std::array, arraySize> occNTrackTPCCUnfm80; + std::array, arraySize> occNTrackITSTPCUnfm80; + std::array, arraySize> occNTrackITSTPCAUnfm80; + std::array, arraySize> occNTrackITSTPCCUnfm80; + + std::array, arraySize> occMultNTracksHasITSUnfm80; + std::array, arraySize> occMultNTracksHasTPCUnfm80; + std::array, arraySize> occMultNTracksHasTOFUnfm80; + std::array, arraySize> occMultNTracksHasTRDUnfm80; + std::array, arraySize> occMultNTracksITSOnlyUnfm80; + std::array, arraySize> occMultNTracksTPCOnlyUnfm80; + std::array, arraySize> occMultNTracksITSTPCUnfm80; + std::array, arraySize> occMultAllTracksTPCOnlyUnfm80; + + std::vector vecRobustOccT0V0PrimUnfm80; + std::vector vecRobustOccFDDT0V0PrimUnfm80; + std::vector vecRobustOccNtrackDetUnfm80; + std::vector vecRobustOccmultTableUnfm80; + std::vector> vecRobustOccT0V0PrimUnfm80medianPosVec; // Median => one for odd and two for even entries + std::vector> vecRobustOccFDDT0V0PrimUnfm80medianPosVec; + std::vector> vecRobustOccNtrackDetUnfm80medianPosVec; + std::vector> vecRobustOccmultTableUnfm80medianPosVec; + + void init(InitContext const&) + { + // Set size of the vectors + for (int i = 0; i < arraySize; i++) { + bcTFMap[i].resize(nBCinTF / 80); + occPrimUnfm80[i].resize(nBCinTF / 80); + occFV0AUnfm80[i].resize(nBCinTF / 80); + occFV0CUnfm80[i].resize(nBCinTF / 80); + occFT0AUnfm80[i].resize(nBCinTF / 80); + occFT0CUnfm80[i].resize(nBCinTF / 80); + occFDDAUnfm80[i].resize(nBCinTF / 80); + occFDDCUnfm80[i].resize(nBCinTF / 80); + + occNTrackITSUnfm80[i].resize(nBCinTF / 80); + occNTrackTPCUnfm80[i].resize(nBCinTF / 80); + occNTrackTRDUnfm80[i].resize(nBCinTF / 80); + occNTrackTOFUnfm80[i].resize(nBCinTF / 80); + occNTrackSizeUnfm80[i].resize(nBCinTF / 80); + occNTrackTPCAUnfm80[i].resize(nBCinTF / 80); + occNTrackTPCCUnfm80[i].resize(nBCinTF / 80); + occNTrackITSTPCUnfm80[i].resize(nBCinTF / 80); + occNTrackITSTPCAUnfm80[i].resize(nBCinTF / 80); + occNTrackITSTPCCUnfm80[i].resize(nBCinTF / 80); + + occMultNTracksHasITSUnfm80[i].resize(nBCinTF / 80); + occMultNTracksHasTPCUnfm80[i].resize(nBCinTF / 80); + occMultNTracksHasTOFUnfm80[i].resize(nBCinTF / 80); + occMultNTracksHasTRDUnfm80[i].resize(nBCinTF / 80); + occMultNTracksITSOnlyUnfm80[i].resize(nBCinTF / 80); + occMultNTracksTPCOnlyUnfm80[i].resize(nBCinTF / 80); + occMultNTracksITSTPCUnfm80[i].resize(nBCinTF / 80); + occMultAllTracksTPCOnlyUnfm80[i].resize(nBCinTF / 80); + } + + vecRobustOccT0V0PrimUnfm80.resize(nBCinTF / 80); + vecRobustOccFDDT0V0PrimUnfm80.resize(nBCinTF / 80); + vecRobustOccNtrackDetUnfm80.resize(nBCinTF / 80); + vecRobustOccmultTableUnfm80.resize(nBCinTF / 80); + + vecRobustOccT0V0PrimUnfm80medianPosVec.resize(nBCinTF / 80); // Median => one for odd and two for even entries + vecRobustOccFDDT0V0PrimUnfm80medianPosVec.resize(nBCinTF / 80); + vecRobustOccNtrackDetUnfm80medianPosVec.resize(nBCinTF / 80); + vecRobustOccmultTableUnfm80medianPosVec.resize(nBCinTF / 80); + + // Getting Info from CCDB, to be implemented Later + recoEvent.add("h_nBCinTF", "h_nBCinTF(to check nBCinTF)", {HistType::kTH1F, {{100, 114040, 114060}}}); // 114048 + recoEvent.add("h_bcInTF", "h_bcInTF", {HistType::kTH1F, {{2000, 0, 200000}}}); + recoEvent.add("h_RO_T0V0PrimUnfm80", "h_RO_T0V0PrimUnfm80:median contributors", {HistType::kTH1F, {{12 * 2, -1, 11}}}); + recoEvent.add("h_RO_FDDT0V0PrimUnfm80", "h_RO_FDDT0V0PrimUnfm80:median contributors", {HistType::kTH1F, {{12 * 2, -1, 11}}}); + recoEvent.add("h_RO_NtrackDetUnfm80", "h_RO_NtrackDetITS/TPC/TRD/TOF_80:median contributors", {HistType::kTH1F, {{12 * 2, -1, 11}}}); + recoEvent.add("h_RO_multTableUnfm80", "h_RO_multTableExtra_80:median contributors", {HistType::kTH1F, {{12 * 2, -1, 11}}}); + + recoEvent.print(); + } + + void normalizeVector(std::vector& OriginalVec, const float& scaleFactor) + { + std::transform(OriginalVec.begin(), OriginalVec.end(), OriginalVec.begin(), [scaleFactor](float x) { return x * scaleFactor; }); + } + + template + void getMedianOccVect( + std::vector& medianVector, + std::vector>& medianPosVec, + const Vecs&... vectors) + { + const int n = sizeof...(Vecs); // Number of vectors + const int size = std::get<0>(std::tie(vectors...)).size(); // Size of the first vector + + for (int i = 0; i < size; i++) { + std::vector> data; // first element is entry, second is index + int iEntry = 0; + + // Lambda to iterate over all vectors + auto collect = [&](const auto& vec) { + data.push_back({vec[i], static_cast(iEntry)}); + iEntry++; + }; + (collect(vectors), ...); // Unpack variadic arguments and apply lambda + + // Sort the data + std::sort(data.begin(), data.end(), [](const std::array& a, const std::array& b) { + return a[0] < b[0]; + }); + + double median; + // Find the median + if (n % 2 == 0) { + median = (data[(n - 1) / 2][0] + data[(n - 1) / 2 + 1][0]) / 2; + medianPosVec[i][0] = static_cast(data[(n - 1) / 2][1] + 0.001); + medianPosVec[i][1] = static_cast(data[(n - 1) / 2 + 1][1] + 0.001); + } else { + median = data[n / 2][0]; + medianPosVec[i][0] = static_cast(data[n / 2][1] + 0.001); + medianPosVec[i][1] = -10; // For odd entries, only one value can be the median + } + medianVector[i] = median; + } + } + + void getRunInfo(const int& run, int& nBCsPerTF, int64_t& bcSOR) + { + auto runDuration = ccdb->getRunDuration(run, true); + int64_t tsSOR = runDuration.first; + auto ctpx = ccdb->getForTimeStamp>("CTP/Calib/OrbitReset", tsSOR); + int64_t tsOrbitReset = (*ctpx)[0]; + uint32_t nOrbitsPerTF = run < 534133 ? 128 : 32; + int64_t orbitSOR = (tsSOR * 1000 - tsOrbitReset) / o2::constants::lhc::LHCOrbitMUS; + orbitSOR = orbitSOR / nOrbitsPerTF * nOrbitsPerTF; + bcSOR = orbitSOR * nBCsPerOrbit + customOrbitOffset * nBCsPerOrbit; // customOrbitOffset is a configurable + nBCsPerTF = nOrbitsPerTF * nBCsPerOrbit; + } + + template + void getTimingInfo(const T& bc, int& lastRun, int32_t& nBCsPerTF, int64_t& bcSOR, uint64_t& time, int64_t& tfIdThis, int& bcInTF) + { + int run = bc.runNumber(); + if (run != lastRun) { // update run info + lastRun = run; + getRunInfo(run, nBCsPerTF, bcSOR); // update nBCsPerTF && bcSOR + } + // update the information + time = bc.timestamp(); + tfIdThis = (bc.globalBC() - bcSOR) / nBCsPerTF; + bcInTF = (bc.globalBC() - bcSOR) % nBCsPerTF; + } + + using MyCollisions = soa::Join; + using MyTracks = soa::Join; + + Preslice tracksPerCollisionPreslice = o2::aod::track::collisionId; + + int dfCount = 0; + int32_t nBCsPerTF = -999; + int64_t bcSOR = -999; + uint64_t time = -1; + int64_t tfIdThis = -1; + int bcInTF = -1; + uint tfCounted = 0; + int tfIDX = 0; + int lastRun = -999; + + // Process the Data + void process(o2::aod::BCsWithTimestamps const& BCs, MyCollisions const& collisions, MyTracks const& tracks) // aod::TracksQA const& tracksQA, o2::aod::Origins const& Origins //tables only used during debugging + { + // dfCount++;LOG(info) << "DEBUG 1 :: df_" << dfCount ;//<< " :: DF_" << Origins.begin().dataframeID() << " :: collisions.size() = " << collisions.size() << " :: tracks.size() = " << tracks.size() << " :: tracksQA.size() = " << tracksQA.size() << " :: BCs.size() = " << BCs.size(); + + if (collisions.size() == 0) { + for (const auto& BC : BCs) { // For BCs and OccIndexTable to have same size for joining + getTimingInfo(BC, lastRun, nBCsPerTF, bcSOR, time, tfIdThis, bcInTF); + genOccIndexTable(BC.globalIndex(), -999); // BCId, OccId + genBCTFinfoTable(tfIdThis, bcInTF); + } + return; + } + + // Initialisze the vectors components to zero + tfIDX = 0; + tfCounted = 0; + for (int i = 0; i < arraySize; i++) { + tfList[i] = -1; + bcTFMap[i].clear(); // list of BCs used in one time frame; + std::fill(occPrimUnfm80[i].begin(), occPrimUnfm80[i].end(), 0.); + std::fill(occFV0AUnfm80[i].begin(), occFV0AUnfm80[i].end(), 0.); + std::fill(occFV0CUnfm80[i].begin(), occFV0CUnfm80[i].end(), 0.); + std::fill(occFT0AUnfm80[i].begin(), occFT0AUnfm80[i].end(), 0.); + std::fill(occFT0CUnfm80[i].begin(), occFT0CUnfm80[i].end(), 0.); + std::fill(occFDDAUnfm80[i].begin(), occFDDAUnfm80[i].end(), 0.); + std::fill(occFDDCUnfm80[i].begin(), occFDDCUnfm80[i].end(), 0.); + + std::fill(occNTrackITSUnfm80[i].begin(), occNTrackITSUnfm80[i].end(), 0.); + std::fill(occNTrackTPCUnfm80[i].begin(), occNTrackTPCUnfm80[i].end(), 0.); + std::fill(occNTrackTRDUnfm80[i].begin(), occNTrackTRDUnfm80[i].end(), 0.); + std::fill(occNTrackTOFUnfm80[i].begin(), occNTrackTOFUnfm80[i].end(), 0.); + std::fill(occNTrackSizeUnfm80[i].begin(), occNTrackSizeUnfm80[i].end(), 0.); + std::fill(occNTrackTPCAUnfm80[i].begin(), occNTrackTPCAUnfm80[i].end(), 0.); + std::fill(occNTrackTPCCUnfm80[i].begin(), occNTrackTPCCUnfm80[i].end(), 0.); + std::fill(occNTrackITSTPCUnfm80[i].begin(), occNTrackITSTPCUnfm80[i].end(), 0.); + std::fill(occNTrackITSTPCAUnfm80[i].begin(), occNTrackITSTPCAUnfm80[i].end(), 0.); + std::fill(occNTrackITSTPCCUnfm80[i].begin(), occNTrackITSTPCCUnfm80[i].end(), 0.); + + std::fill(occMultNTracksHasITSUnfm80[i].begin(), occMultNTracksHasITSUnfm80[i].end(), 0.); + std::fill(occMultNTracksHasTPCUnfm80[i].begin(), occMultNTracksHasTPCUnfm80[i].end(), 0.); + std::fill(occMultNTracksHasTOFUnfm80[i].begin(), occMultNTracksHasTOFUnfm80[i].end(), 0.); + std::fill(occMultNTracksHasTRDUnfm80[i].begin(), occMultNTracksHasTRDUnfm80[i].end(), 0.); + std::fill(occMultNTracksITSOnlyUnfm80[i].begin(), occMultNTracksITSOnlyUnfm80[i].end(), 0.); + std::fill(occMultNTracksTPCOnlyUnfm80[i].begin(), occMultNTracksTPCOnlyUnfm80[i].end(), 0.); + std::fill(occMultNTracksITSTPCUnfm80[i].begin(), occMultNTracksITSTPCUnfm80[i].end(), 0.); + std::fill(occMultAllTracksTPCOnlyUnfm80[i].begin(), occMultAllTracksTPCOnlyUnfm80[i].end(), 0.); + } + + std::vector tfIDList; + for (const auto& collision : collisions) { + const auto& bc = collision.bc_as(); + getTimingInfo(bc, lastRun, nBCsPerTF, bcSOR, time, tfIdThis, bcInTF); + + recoEvent.fill(HIST("h_nBCinTF"), nBCsPerTF); + recoEvent.fill(HIST("h_bcInTF"), bcInTF); + + if (nBCsPerTF > nBCinTF) { + LOG(error) << "DEBUG :: FATAL ERROR :: nBCsPerTF > nBCinTF i.e " << nBCsPerTF << " > " << nBCinTF << " will cause crash in further process"; + return; + } + + const uint64_t collIdx = collision.globalIndex(); + const auto tracksTablePerColl = tracks.sliceBy(tracksPerCollisionPreslice, collIdx); + + int nTrackITS = 0; + int nTrackTPC = 0; + int nTrackTRD = 0; + int nTrackTOF = 0; + int nTrackTPCA = 0; + int nTrackTPCC = 0; + int nTrackITSTPCA = 0; + int nTrackITSTPCC = 0; + + for (const auto& track : tracksTablePerColl) { + if (track.hasITS()) { + nTrackITS++; + } // Flag to check if track has a ITS match + if (track.hasTPC()) { + nTrackTPC++; + if (track.eta() <= 0.0) { + nTrackTPCA++; // includes tracks at eta zero as well. + } else { + nTrackTPCC++; + } + } // Flag to check if track has a TPC match + if (track.hasTRD()) { + nTrackTRD++; + } // Flag to check if track has a TRD match + if (track.hasTOF()) { + nTrackTOF++; + } // Flag to check if track has a TOF measurement + if (track.hasITS() && track.hasTPC()) { + if (track.eta() <= 0.0) { + nTrackITSTPCA++; // includes tracks at eta zero as well. + } else { + nTrackITSTPCC++; + } + } + } // track loop + + // if (collision.multNTracksTPCOnly() != 0) { + // LOG(error) << "DEBUG :: ERROR = multNTracksTPCOnly != 0" << collision.multNTracksTPCOnly(); + // return; + // } + // if (collision.multAllTracksITSTPC() != nTrackITSTPC) { + // LOG(error) << "DEBUG :: ERROR :: 10 multAllTracksITSTPC :: " << collision.multAllTracksITSTPC() << " != " << nTrackITSTPC; + // return; + // } + + tfIDList.push_back(tfIdThis); + + if (tfList[tfIDX] != tfIdThis) { + if (tfCounted != 0) { + tfIDX++; + } // + tfList[tfIDX] = tfIdThis; + tfCounted++; + } + + bcTFMap[tfIDX].push_back(bc.globalIndex()); + auto& tfOccPrimUnfm80 = occPrimUnfm80[tfIDX]; + auto& tfOccFV0AUnfm80 = occFV0AUnfm80[tfIDX]; + auto& tfOccFV0CUnfm80 = occFV0CUnfm80[tfIDX]; + auto& tfOccFT0AUnfm80 = occFT0AUnfm80[tfIDX]; + auto& tfOccFT0CUnfm80 = occFT0CUnfm80[tfIDX]; + auto& tfOccFDDAUnfm80 = occFDDAUnfm80[tfIDX]; + auto& tfOccFDDCUnfm80 = occFDDCUnfm80[tfIDX]; + + auto& tfOccNTrackITSUnfm80 = occNTrackITSUnfm80[tfIDX]; + auto& tfOccNTrackTPCUnfm80 = occNTrackTPCUnfm80[tfIDX]; + auto& tfOccNTrackTRDUnfm80 = occNTrackTRDUnfm80[tfIDX]; + auto& tfOccNTrackTOFUnfm80 = occNTrackTOFUnfm80[tfIDX]; + auto& tfOccNTrackSizeUnfm80 = occNTrackSizeUnfm80[tfIDX]; + auto& tfOccNTrackTPCAUnfm80 = occNTrackTPCAUnfm80[tfIDX]; + auto& tfOccNTrackTPCCUnfm80 = occNTrackTPCCUnfm80[tfIDX]; + auto& tfOccNTrackITSTPCUnfm80 = occNTrackITSTPCUnfm80[tfIDX]; + auto& tfOccNTrackITSTPCAUnfm80 = occNTrackITSTPCAUnfm80[tfIDX]; + auto& tfOccNTrackITSTPCCUnfm80 = occNTrackITSTPCCUnfm80[tfIDX]; + + auto& tfOccMultNTracksHasITSUnfm80 = occMultNTracksHasITSUnfm80[tfIDX]; + auto& tfOccMultNTracksHasTPCUnfm80 = occMultNTracksHasTPCUnfm80[tfIDX]; + auto& tfOccMultNTracksHasTOFUnfm80 = occMultNTracksHasTOFUnfm80[tfIDX]; + auto& tfOccMultNTracksHasTRDUnfm80 = occMultNTracksHasTRDUnfm80[tfIDX]; + auto& tfOccMultNTracksITSOnlyUnfm80 = occMultNTracksITSOnlyUnfm80[tfIDX]; + auto& tfOccMultNTracksTPCOnlyUnfm80 = occMultNTracksTPCOnlyUnfm80[tfIDX]; + auto& tfOccMultNTracksITSTPCUnfm80 = occMultNTracksITSTPCUnfm80[tfIDX]; + auto& tfOccMultAllTracksTPCOnlyUnfm80 = occMultAllTracksTPCOnlyUnfm80[tfIDX]; + + // current collision bin in 80/160 grouping. + int bin80Zero = bcInTF / 80; + // int bin160_0=bcInTF/160; + + // float fbin80Zero =float(bcInTF)/80; + // float fbin160_0=float(bcInTF)/160; + + ushort fNumContrib = collision.numContrib(); + float fMultFV0A = collision.multFV0A(), fMultFV0C = collision.multFV0C(); + float fMultFT0A = collision.multFT0A(), fMultFT0C = collision.multFT0C(); + float fMultFDDA = collision.multFDDA(), fMultFDDC = collision.multFDDC(); + int fNTrackITS = nTrackITS; + int fNTrackTPC = nTrackTPC, fNTrackTRD = nTrackTRD; + int fNTrackTOF = nTrackTOF; + int fNTrackTPCA = nTrackTPCA, fNTrackTPCC = nTrackTPCC; + int fNTrackITSTPC = collision.multAllTracksITSTPC(), fNTrackSize = tracksTablePerColl.size(); + int fNTrackITSTPCA = nTrackITSTPCA, fNTrackITSTPCC = nTrackITSTPCC; + + // Processing for grouping of 80 BCs + for (int deltaBin = 0; deltaBin < nBCinDrift / 80; deltaBin++) { + tfOccPrimUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += fNumContrib * 1; + tfOccFV0AUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += fMultFV0A * 1; + tfOccFV0CUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += fMultFV0C * 1; + tfOccFT0AUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += fMultFT0A * 1; + tfOccFT0CUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += fMultFT0C * 1; + tfOccFDDAUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += fMultFDDA * 1; + tfOccFDDCUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += fMultFDDC * 1; + + tfOccNTrackITSUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += fNTrackITS * 1; + tfOccNTrackTPCUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += fNTrackTPC * 1; + tfOccNTrackTRDUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += fNTrackTRD * 1; + tfOccNTrackTOFUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += fNTrackTOF * 1; + tfOccNTrackSizeUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += fNTrackSize * 1; + tfOccNTrackTPCAUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += fNTrackTPCA * 1; + tfOccNTrackTPCCUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += fNTrackTPCC * 1; + tfOccNTrackITSTPCUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += fNTrackITSTPC * 1; + tfOccNTrackITSTPCAUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += fNTrackITSTPCA * 1; + tfOccNTrackITSTPCCUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += fNTrackITSTPCC * 1; + + tfOccMultNTracksHasITSUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += collision.multNTracksHasITS() * 1; + tfOccMultNTracksHasTPCUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += collision.multNTracksHasTPC() * 1; + tfOccMultNTracksHasTOFUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += collision.multNTracksHasTOF() * 1; + tfOccMultNTracksHasTRDUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += collision.multNTracksHasTRD() * 1; + tfOccMultNTracksITSOnlyUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += collision.multNTracksITSOnly() * 1; + tfOccMultNTracksTPCOnlyUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += collision.multNTracksTPCOnly() * 1; + tfOccMultNTracksITSTPCUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += collision.multNTracksITSTPC() * 1; + tfOccMultAllTracksTPCOnlyUnfm80[(bin80Zero + deltaBin) % (nBCinTF / 80)] += collision.multAllTracksTPCOnly() * 1; + } + } + // collision Loop is over + + std::vector sortedTfIDList = tfIDList; + std::sort(sortedTfIDList.begin(), sortedTfIDList.end()); + auto last = std::unique(sortedTfIDList.begin(), sortedTfIDList.end()); + sortedTfIDList.erase(last, sortedTfIDList.end()); + + if (tfCounted != sortedTfIDList.size()) { + LOG(error) << "DEBUG :: Number mismatch for tf counted and filled :: " << tfCounted << " != " << sortedTfIDList.size(); + } + + int totalBCcountSize = 0; + for (int i = 0; i < arraySize; i++) { + totalBCcountSize += bcTFMap[i].size(); + // check if the BCs are already sorted or not + if (!std::is_sorted(bcTFMap[i].begin(), bcTFMap[i].end())) { + LOG(debug) << "DEBUG :: ERROR :: BCs are not sorted"; + } + } + // + if (totalBCcountSize != collisions.size()) { + LOG(debug) << "DEBUG :: ERROR :: filled TF list and collision size mismatch :: filledTF_Size = " << totalBCcountSize << " != " << collisions.size() << " = collisions.size()"; + } + + // Fill the Producers + for (uint i = 0; i < tfCounted; i++) { + + auto& vecOccPrimUnfm80 = occPrimUnfm80[i]; + auto& vecOccFV0AUnfm80 = occFV0AUnfm80[i]; + auto& vecOccFV0CUnfm80 = occFV0CUnfm80[i]; + auto& vecOccFT0AUnfm80 = occFT0AUnfm80[i]; + auto& vecOccFT0CUnfm80 = occFT0CUnfm80[i]; + auto& vecOccFDDAUnfm80 = occFDDAUnfm80[i]; + auto& vecOccFDDCUnfm80 = occFDDCUnfm80[i]; + + auto& vecOccNTrackITSUnfm80 = occNTrackITSUnfm80[i]; + auto& vecOccNTrackTPCUnfm80 = occNTrackTPCUnfm80[i]; + auto& vecOccNTrackTRDUnfm80 = occNTrackTRDUnfm80[i]; + auto& vecOccNTrackTOFUnfm80 = occNTrackTOFUnfm80[i]; + auto& vecOccNTrackSizeUnfm80 = occNTrackSizeUnfm80[i]; + auto& vecOccNTrackTPCAUnfm80 = occNTrackTPCAUnfm80[i]; + auto& vecOccNTrackTPCCUnfm80 = occNTrackTPCCUnfm80[i]; + auto& vecOccNTrackITSTPCUnfm80 = occNTrackITSTPCUnfm80[i]; + auto& vecOccNTrackITSTPCAUnfm80 = occNTrackITSTPCAUnfm80[i]; + auto& vecOccNTrackITSTPCCUnfm80 = occNTrackITSTPCCUnfm80[i]; + + auto& vecOccMultNTracksHasITSUnfm80 = occMultNTracksHasITSUnfm80[i]; + auto& vecOccMultNTracksHasTPCUnfm80 = occMultNTracksHasTPCUnfm80[i]; + auto& vecOccMultNTracksHasTOFUnfm80 = occMultNTracksHasTOFUnfm80[i]; + auto& vecOccMultNTracksHasTRDUnfm80 = occMultNTracksHasTRDUnfm80[i]; + auto& vecOccMultNTracksITSOnlyUnfm80 = occMultNTracksITSOnlyUnfm80[i]; + auto& vecOccMultNTracksTPCOnlyUnfm80 = occMultNTracksTPCOnlyUnfm80[i]; + auto& vecOccMultNTracksITSTPCUnfm80 = occMultNTracksITSTPCUnfm80[i]; + auto& vecOccMultAllTracksTPCOnlyUnfm80 = occMultAllTracksTPCOnlyUnfm80[i]; + + float meanOccPrimUnfm80 = TMath::Mean(vecOccPrimUnfm80.size(), vecOccPrimUnfm80.data()); + float meanOccFV0AUnfm80 = TMath::Mean(vecOccFV0AUnfm80.size(), vecOccFV0AUnfm80.data()); + float meanOccFV0CUnfm80 = TMath::Mean(vecOccFV0CUnfm80.size(), vecOccFV0CUnfm80.data()); + float meanOccFT0AUnfm80 = TMath::Mean(vecOccFT0AUnfm80.size(), vecOccFT0AUnfm80.data()); + float meanOccFT0CUnfm80 = TMath::Mean(vecOccFT0CUnfm80.size(), vecOccFT0CUnfm80.data()); + float meanOccFDDAUnfm80 = TMath::Mean(vecOccFDDAUnfm80.size(), vecOccFDDAUnfm80.data()); + float meanOccFDDCUnfm80 = TMath::Mean(vecOccFDDCUnfm80.size(), vecOccFDDCUnfm80.data()); + + float meanOccNTrackITSUnfm80 = TMath::Mean(vecOccNTrackITSUnfm80.size(), vecOccNTrackITSUnfm80.data()); + float meanOccNTrackTPCUnfm80 = TMath::Mean(vecOccNTrackTPCUnfm80.size(), vecOccNTrackTPCUnfm80.data()); + float meanOccNTrackTRDUnfm80 = TMath::Mean(vecOccNTrackTRDUnfm80.size(), vecOccNTrackTRDUnfm80.data()); + float meanOccNTrackTOFUnfm80 = TMath::Mean(vecOccNTrackTOFUnfm80.size(), vecOccNTrackTOFUnfm80.data()); + float meanOccNTrackSizeUnfm80 = TMath::Mean(vecOccNTrackSizeUnfm80.size(), vecOccNTrackSizeUnfm80.data()); + float meanOccNTrackTPCAUnfm80 = TMath::Mean(vecOccNTrackTPCAUnfm80.size(), vecOccNTrackTPCAUnfm80.data()); + float meanOccNTrackTPCCUnfm80 = TMath::Mean(vecOccNTrackTPCCUnfm80.size(), vecOccNTrackTPCCUnfm80.data()); + float meanOccNTrackITSTPCUnfm80 = TMath::Mean(vecOccNTrackITSTPCUnfm80.size(), vecOccNTrackITSTPCUnfm80.data()); + float meanOccNTrackITSTPCAUnfm80 = TMath::Mean(vecOccNTrackITSTPCAUnfm80.size(), vecOccNTrackITSTPCAUnfm80.data()); + float meanOccNTrackITSTPCCUnfm80 = TMath::Mean(vecOccNTrackITSTPCCUnfm80.size(), vecOccNTrackITSTPCCUnfm80.data()); + + float meanOccMultNTracksHasITSUnfm80 = TMath::Mean(vecOccMultNTracksHasITSUnfm80.size(), vecOccMultNTracksHasITSUnfm80.data()); + float meanOccMultNTracksHasTPCUnfm80 = TMath::Mean(vecOccMultNTracksHasTPCUnfm80.size(), vecOccMultNTracksHasTPCUnfm80.data()); + float meanOccMultNTracksHasTOFUnfm80 = TMath::Mean(vecOccMultNTracksHasTOFUnfm80.size(), vecOccMultNTracksHasTOFUnfm80.data()); + float meanOccMultNTracksHasTRDUnfm80 = TMath::Mean(vecOccMultNTracksHasTRDUnfm80.size(), vecOccMultNTracksHasTRDUnfm80.data()); + float meanOccMultNTracksITSOnlyUnfm80 = TMath::Mean(vecOccMultNTracksITSOnlyUnfm80.size(), vecOccMultNTracksITSOnlyUnfm80.data()); + float meanOccMultNTracksTPCOnlyUnfm80 = TMath::Mean(vecOccMultNTracksTPCOnlyUnfm80.size(), vecOccMultNTracksTPCOnlyUnfm80.data()); + float meanOccMultNTracksITSTPCUnfm80 = TMath::Mean(vecOccMultNTracksITSTPCUnfm80.size(), vecOccMultNTracksITSTPCUnfm80.data()); + float meanOccMultAllTracksTPCOnlyUnfm80 = TMath::Mean(vecOccMultAllTracksTPCOnlyUnfm80.size(), vecOccMultAllTracksTPCOnlyUnfm80.data()); + + // Normalise the original vectors + normalizeVector(vecOccPrimUnfm80, meanOccPrimUnfm80 / meanOccPrimUnfm80); + normalizeVector(vecOccFV0AUnfm80, meanOccPrimUnfm80 / meanOccFV0AUnfm80); + normalizeVector(vecOccFV0CUnfm80, meanOccPrimUnfm80 / meanOccFV0CUnfm80); + normalizeVector(vecOccFT0AUnfm80, meanOccPrimUnfm80 / meanOccFT0AUnfm80); + normalizeVector(vecOccFT0CUnfm80, meanOccPrimUnfm80 / meanOccFT0CUnfm80); + normalizeVector(vecOccFDDAUnfm80, meanOccPrimUnfm80 / meanOccFDDAUnfm80); + normalizeVector(vecOccFDDCUnfm80, meanOccPrimUnfm80 / meanOccFDDCUnfm80); + + normalizeVector(vecOccNTrackITSUnfm80, meanOccPrimUnfm80 / meanOccNTrackITSUnfm80); + normalizeVector(vecOccNTrackTPCUnfm80, meanOccPrimUnfm80 / meanOccNTrackTPCUnfm80); + normalizeVector(vecOccNTrackTRDUnfm80, meanOccPrimUnfm80 / meanOccNTrackTRDUnfm80); + normalizeVector(vecOccNTrackTOFUnfm80, meanOccPrimUnfm80 / meanOccNTrackTOFUnfm80); + normalizeVector(vecOccNTrackSizeUnfm80, meanOccPrimUnfm80 / meanOccNTrackSizeUnfm80); + normalizeVector(vecOccNTrackTPCAUnfm80, meanOccPrimUnfm80 / meanOccNTrackTPCAUnfm80); + normalizeVector(vecOccNTrackTPCCUnfm80, meanOccPrimUnfm80 / meanOccNTrackTPCCUnfm80); + normalizeVector(vecOccNTrackITSTPCUnfm80, meanOccPrimUnfm80 / meanOccNTrackITSTPCUnfm80); + normalizeVector(vecOccNTrackITSTPCAUnfm80, meanOccPrimUnfm80 / meanOccNTrackITSTPCAUnfm80); + normalizeVector(vecOccNTrackITSTPCCUnfm80, meanOccPrimUnfm80 / meanOccNTrackITSTPCCUnfm80); + + normalizeVector(vecOccMultNTracksHasITSUnfm80, meanOccPrimUnfm80 / meanOccMultNTracksHasITSUnfm80); + normalizeVector(vecOccMultNTracksHasTPCUnfm80, meanOccPrimUnfm80 / meanOccMultNTracksHasTPCUnfm80); + normalizeVector(vecOccMultNTracksHasTOFUnfm80, meanOccPrimUnfm80 / meanOccMultNTracksHasTOFUnfm80); + normalizeVector(vecOccMultNTracksHasTRDUnfm80, meanOccPrimUnfm80 / meanOccMultNTracksHasTRDUnfm80); + normalizeVector(vecOccMultNTracksITSOnlyUnfm80, meanOccPrimUnfm80 / meanOccMultNTracksITSOnlyUnfm80); + normalizeVector(vecOccMultNTracksTPCOnlyUnfm80, meanOccPrimUnfm80 / meanOccMultNTracksTPCOnlyUnfm80); + normalizeVector(vecOccMultNTracksITSTPCUnfm80, meanOccPrimUnfm80 / meanOccMultNTracksITSTPCUnfm80); + normalizeVector(vecOccMultAllTracksTPCOnlyUnfm80, meanOccPrimUnfm80 / meanOccMultAllTracksTPCOnlyUnfm80); + + // Find Robust estimators + // T0A, T0C, V0A, Prim + getMedianOccVect(vecRobustOccT0V0PrimUnfm80, vecRobustOccT0V0PrimUnfm80medianPosVec, + vecOccPrimUnfm80, vecOccFV0AUnfm80, vecOccFT0AUnfm80, vecOccFT0CUnfm80); + + // T0A, T0C, V0A, FDD, Prim + getMedianOccVect(vecRobustOccFDDT0V0PrimUnfm80, vecRobustOccFDDT0V0PrimUnfm80medianPosVec, + vecOccPrimUnfm80, vecOccFV0AUnfm80, vecOccFT0AUnfm80, vecOccFT0CUnfm80, vecOccFDDAUnfm80, vecOccFDDCUnfm80); + + // NTrackDet + getMedianOccVect(vecRobustOccNtrackDetUnfm80, vecRobustOccNtrackDetUnfm80medianPosVec, + vecOccNTrackITSUnfm80, vecOccNTrackTPCUnfm80, vecOccNTrackTRDUnfm80, vecOccNTrackTOFUnfm80); + + // multExtraTable + getMedianOccVect(vecRobustOccmultTableUnfm80, vecRobustOccmultTableUnfm80medianPosVec, + vecOccPrimUnfm80, vecOccMultNTracksHasITSUnfm80, vecOccMultNTracksHasTPCUnfm80, + vecOccMultNTracksHasTOFUnfm80, vecOccMultNTracksHasTRDUnfm80, vecOccMultNTracksITSOnlyUnfm80, + vecOccMultNTracksTPCOnlyUnfm80, vecOccMultNTracksITSTPCUnfm80, vecOccMultAllTracksTPCOnlyUnfm80, + vecOccNTrackITSTPCUnfm80); + + for (const auto& vec : vecRobustOccT0V0PrimUnfm80medianPosVec) { + recoEvent.fill(HIST("h_RO_T0V0PrimUnfm80"), vec[0]); + recoEvent.fill(HIST("h_RO_T0V0PrimUnfm80"), vec[1]); + } + + for (const auto& vec : vecRobustOccFDDT0V0PrimUnfm80medianPosVec) { + recoEvent.fill(HIST("h_RO_FDDT0V0PrimUnfm80"), vec[0]); + recoEvent.fill(HIST("h_RO_FDDT0V0PrimUnfm80"), vec[1]); + } + + for (const auto& vec : vecRobustOccNtrackDetUnfm80medianPosVec) { + recoEvent.fill(HIST("h_RO_NtrackDetUnfm80"), vec[0]); + recoEvent.fill(HIST("h_RO_NtrackDetUnfm80"), vec[1]); + } + + for (const auto& vec : vecRobustOccmultTableUnfm80medianPosVec) { + recoEvent.fill(HIST("h_RO_multTableUnfm80"), vec[0]); + recoEvent.fill(HIST("h_RO_multTableUnfm80"), vec[1]); + } + + genOccsBCsList(tfList[i], bcTFMap[i]); + + if (buildOccsDet) { + genOccsDet(vecOccPrimUnfm80, + vecOccFV0AUnfm80, vecOccFV0CUnfm80, + vecOccFT0AUnfm80, vecOccFT0CUnfm80, + vecOccFDDAUnfm80, vecOccFDDCUnfm80); + } + if (buildOccsTrackMult) { + genOccsTrackMult(vecOccNTrackITSUnfm80, vecOccNTrackTPCUnfm80, + vecOccNTrackTRDUnfm80, vecOccNTrackTOFUnfm80, + vecOccNTrackSizeUnfm80, vecOccNTrackTPCAUnfm80, + vecOccNTrackTPCCUnfm80, vecOccNTrackITSTPCUnfm80, + vecOccNTrackITSTPCAUnfm80, vecOccNTrackITSTPCCUnfm80); + } + if (buildOccsMultExtra) { + genOccsMultExtra(vecOccMultNTracksHasITSUnfm80, vecOccMultNTracksHasTPCUnfm80, + vecOccMultNTracksHasTOFUnfm80, vecOccMultNTracksHasTRDUnfm80, + vecOccMultNTracksITSOnlyUnfm80, vecOccMultNTracksTPCOnlyUnfm80, + vecOccMultNTracksITSTPCUnfm80, vecOccMultAllTracksTPCOnlyUnfm80); + } + + if (buildOccsRobust) { + genOccsRobust(vecRobustOccT0V0PrimUnfm80, vecRobustOccFDDT0V0PrimUnfm80, vecRobustOccNtrackDetUnfm80, vecRobustOccmultTableUnfm80); + } + if (buildOccsMeanDet) { + genOccsMeanDet(meanOccPrimUnfm80, + meanOccFV0AUnfm80, meanOccFV0CUnfm80, + meanOccFT0AUnfm80, meanOccFT0CUnfm80, + meanOccFDDAUnfm80, meanOccFDDCUnfm80); + } + + if (buildOccsMeanTrkMult) { + genOccsMeanTrkMult(meanOccNTrackITSUnfm80, + meanOccNTrackTPCUnfm80, + meanOccNTrackTRDUnfm80, + meanOccNTrackTOFUnfm80, + meanOccNTrackSizeUnfm80, + meanOccNTrackTPCAUnfm80, + meanOccNTrackTPCCUnfm80, + meanOccNTrackITSTPCUnfm80, + meanOccNTrackITSTPCAUnfm80, + meanOccNTrackITSTPCCUnfm80); + } + + if (buildOccsMnMultExtra) { + genOccsMnMultExtra(meanOccMultNTracksHasITSUnfm80, meanOccMultNTracksHasTPCUnfm80, + meanOccMultNTracksHasTOFUnfm80, meanOccMultNTracksHasTRDUnfm80, + meanOccMultNTracksITSOnlyUnfm80, meanOccMultNTracksTPCOnlyUnfm80, + meanOccMultNTracksITSTPCUnfm80, meanOccMultAllTracksTPCOnlyUnfm80); + } + + if (buildOccsMeanRobust) { + genOccsMeanRobust( + TMath::Mean(vecRobustOccT0V0PrimUnfm80.size(), vecRobustOccT0V0PrimUnfm80.data()), + TMath::Mean(vecRobustOccFDDT0V0PrimUnfm80.size(), vecRobustOccFDDT0V0PrimUnfm80.data()), + TMath::Mean(vecRobustOccNtrackDetUnfm80.size(), vecRobustOccNtrackDetUnfm80.data()), + TMath::Mean(vecRobustOccmultTableUnfm80.size(), vecRobustOccmultTableUnfm80.data())); + } + } + + // Create a BC index table. + int64_t occIDX = -1; + int idx = -1; + for (auto const& bc : BCs) { + idx = -1; + getTimingInfo(bc, lastRun, nBCsPerTF, bcSOR, time, tfIdThis, bcInTF); + + auto idxIt = std::find(tfList.begin(), tfList.end(), tfIdThis); + if (idxIt != tfList.end()) { + idx = std::distance(tfList.begin(), idxIt); + } else { + LOG(error) << "DEBUG :: SEVERE :: BC Timeframe not in the list"; + } + + auto it = std::find(bcTFMap[idx].begin(), bcTFMap[idx].end(), bc.globalIndex()); // will find the iterator where object is placed. + if (it != bcTFMap[idx].end()) { + occIDX = idx; // Element is in the vector + } else { + occIDX = -1; // Element is not in the vector + } + + genOccIndexTable(bc.globalIndex(), occIDX); // BCId, OccId + genBCTFinfoTable(tfIdThis, bcInTF); + } + } // Process function ends +}; + +struct TrackMeanOccTableProducer { + Produces genTrackMeanOccs0; + Produces genTrackMeanOccs1; + Produces genTrackMeanOccs2; + Produces genTrackMeanOccs3; + Produces genTrackMeanOccs4; + Produces genTrackMeanOccs5; + Produces genTrackMeanOccs6; + Produces genTrackMeanOccs7; + Produces genTrackMeanOccs8; + + Service ccdb; + + HistogramRegistry occupancyQA{"occupancyQA", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Configurables + Configurable customOrbitOffset{"customOrbitOffset", 0, "customOrbitOffset for MC"}; + + Configurable buildTrackMeanOccs1{"buildTrackMeanOccs1", true, "builder TrackMeanOccs1"}; + Configurable buildTrackMeanOccs2{"buildTrackMeanOccs2", true, "builder TrackMeanOccs2"}; + Configurable buildTrackMeanOccs3{"buildTrackMeanOccs3", true, "builder TrackMeanOccs3"}; + Configurable buildTrackMeanOccs4{"buildTrackMeanOccs4", true, "builder TrackMeanOccs4"}; + Configurable buildTrackMeanOccs5{"buildTrackMeanOccs5", true, "builder TrackMeanOccs5"}; + Configurable buildTrackMeanOccs6{"buildTrackMeanOccs6", true, "builder TrackMeanOccs6"}; + Configurable buildTrackMeanOccs7{"buildTrackMeanOccs7", true, "builder TrackMeanOccs7"}; + Configurable buildTrackMeanOccs8{"buildTrackMeanOccs8", true, "builder TrackMeanOccs8"}; + + Configurable fillQA1{"fillQA1", false, "fill QA LOG Ratios"}; + Configurable fillQA2{"fillQA2", false, "fill QA condition dependent QAs"}; + + // vectors to be used for occupancy estimation + std::vector occPrimUnfm80; + std::vector occFV0AUnfm80; + std::vector occFV0CUnfm80; + std::vector occFT0AUnfm80; + std::vector occFT0CUnfm80; + std::vector occFDDAUnfm80; + std::vector occFDDCUnfm80; + + std::vector occNTrackITSUnfm80; + std::vector occNTrackTPCUnfm80; + std::vector occNTrackTRDUnfm80; + std::vector occNTrackTOFUnfm80; + std::vector occNTrackSizeUnfm80; + std::vector occNTrackTPCAUnfm80; + std::vector occNTrackTPCCUnfm80; + std::vector occNTrackITSTPCUnfm80; + std::vector occNTrackITSTPCAUnfm80; + std::vector occNTrackITSTPCCUnfm80; + + std::vector occMultNTracksHasITSUnfm80; + std::vector occMultNTracksHasTPCUnfm80; + std::vector occMultNTracksHasTOFUnfm80; + std::vector occMultNTracksHasTRDUnfm80; + std::vector occMultNTracksITSOnlyUnfm80; + std::vector occMultNTracksTPCOnlyUnfm80; + std::vector occMultNTracksITSTPCUnfm80; + std::vector occMultAllTracksTPCOnlyUnfm80; + + std::vector occRobustT0V0PrimUnfm80; + std::vector occRobustFDDT0V0PrimUnfm80; + std::vector occRobustNtrackDetUnfm80; + std::vector occRobustMultTableUnfm80; + + void init(InitContext const&) + { + // CCDB related part to be added later + occPrimUnfm80.resize(nBCinTF / 80); + occFV0AUnfm80.resize(nBCinTF / 80); + occFV0CUnfm80.resize(nBCinTF / 80); + occFT0AUnfm80.resize(nBCinTF / 80); + occFT0CUnfm80.resize(nBCinTF / 80); + occFDDAUnfm80.resize(nBCinTF / 80); + occFDDCUnfm80.resize(nBCinTF / 80); + + occNTrackITSUnfm80.resize(nBCinTF / 80); + occNTrackTPCUnfm80.resize(nBCinTF / 80); + occNTrackTRDUnfm80.resize(nBCinTF / 80); + occNTrackTOFUnfm80.resize(nBCinTF / 80); + occNTrackSizeUnfm80.resize(nBCinTF / 80); + occNTrackTPCAUnfm80.resize(nBCinTF / 80); + occNTrackTPCCUnfm80.resize(nBCinTF / 80); + occNTrackITSTPCUnfm80.resize(nBCinTF / 80); + occNTrackITSTPCAUnfm80.resize(nBCinTF / 80); + occNTrackITSTPCCUnfm80.resize(nBCinTF / 80); + + occMultNTracksHasITSUnfm80.resize(nBCinTF / 80); + occMultNTracksHasTPCUnfm80.resize(nBCinTF / 80); + occMultNTracksHasTOFUnfm80.resize(nBCinTF / 80); + occMultNTracksHasTRDUnfm80.resize(nBCinTF / 80); + occMultNTracksITSOnlyUnfm80.resize(nBCinTF / 80); + occMultNTracksTPCOnlyUnfm80.resize(nBCinTF / 80); + occMultNTracksITSTPCUnfm80.resize(nBCinTF / 80); + occMultAllTracksTPCOnlyUnfm80.resize(nBCinTF / 80); + + occRobustT0V0PrimUnfm80.resize(nBCinTF / 80); + occRobustFDDT0V0PrimUnfm80.resize(nBCinTF / 80); + occRobustNtrackDetUnfm80.resize(nBCinTF / 80); + occRobustMultTableUnfm80.resize(nBCinTF / 80); + + const AxisSpec axisQA1 = {500, 0, 50000}; + const AxisSpec axisQA2 = {200, -2, 2}; + const AxisSpec axisQA3 = {200, -20, 20}; + + occupancyQA.add("occTrackQA/Mean/OccPrimUnfm80", "OccPrimUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccFV0AUnfm80", "OccFV0AUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccFV0CUnfm80", "OccFV0CUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccFT0AUnfm80", "OccFT0AUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccFT0CUnfm80", "OccFT0CUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccFDDAUnfm80", "OccFDDAUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccFDDCUnfm80", "OccFDDCUnfm80", kTH1F, {axisQA1}); + + occupancyQA.add("occTrackQA/Mean/OccNTrackITSUnfm80", "OccNTrackITSUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccNTrackTPCUnfm80", "OccNTrackTPCUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccNTrackTRDUnfm80", "OccNTrackTRDUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccNTrackTOFUnfm80", "OccNTrackTOFUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccNTrackSizeUnfm80", "OccNTrackSizeUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccNTrackTPCAUnfm80", "OccNTrackTPCAUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccNTrackTPCCUnfm80", "OccNTrackTPCCUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccNTrackITSTPCUnfm80", "OccNTrackITSTPCUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccNTrackITSTPCAUnfm80", "OccNTrackITSTPCAUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccNTrackITSTPCCUnfm80", "OccNTrackITSTPCCUnfm80", kTH1F, {axisQA1}); + + occupancyQA.add("occTrackQA/Mean/OccMultNTracksHasITSUnfm80", "OccMultNTracksHasITSUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccMultNTracksHasTPCUnfm80", "OccMultNTracksHasTPCUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccMultNTracksHasTOFUnfm80", "OccMultNTracksHasTOFUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccMultNTracksHasTRDUnfm80", "OccMultNTracksHasTRDUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccMultNTracksITSOnlyUnfm80", "OccMultNTracksITSOnlyUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccMultNTracksTPCOnlyUnfm80", "OccMultNTracksTPCOnlyUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccMultNTracksITSTPCUnfm80", "OccMultNTracksITSTPCUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccMultAllTracksTPCOnlyUnfm80", "OccMultAllTracksTPCOnlyUnfm80", kTH1F, {axisQA1}); + + occupancyQA.add("occTrackQA/Mean/OccRobustT0V0PrimUnfm80", "OccRobustT0V0PrimUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccRobustFDDT0V0PrimUnfm80", "OccRobustFDDT0V0PrimUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccRobustNtrackDetUnfm80", "OccRobustNtrackDetUnfm80", kTH1F, {axisQA1}); + occupancyQA.add("occTrackQA/Mean/OccRobustMultExtraTableUnfm80", "OccRobustMultExtraTableUnfm80", kTH1F, {axisQA1}); + + occupancyQA.addClone("occTrackQA/Mean/", "occTrackQA/WeightMean/"); + + if (fillQA1) { + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccPrimUnfm80", "OccPrimUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccFV0AUnfm80", "OccFV0AUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccFV0CUnfm80", "OccFV0CUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccFT0AUnfm80", "OccFT0AUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccFT0CUnfm80", "OccFT0CUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccFDDAUnfm80", "OccFDDAUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccFDDCUnfm80", "OccFDDCUnfm80", kTH1F, {axisQA2}); + + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccNTrackITSUnfm80", "OccNTrackITSUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccNTrackTPCUnfm80", "OccNTrackTPCUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccNTrackTRDUnfm80", "OccNTrackTRDUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccNTrackTOFUnfm80", "OccNTrackTOFUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccNTrackSizeUnfm80", "OccNTrackSizeUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccNTrackTPCAUnfm80", "OccNTrackTPCAUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccNTrackTPCCUnfm80", "OccNTrackTPCCUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccNTrackITSTPCUnfm80", "OccNTrackITSTPCUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccNTrackITSTPCAUnfm80", "OccNTrackITSTPCAUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccNTrackITSTPCCUnfm80", "OccNTrackITSTPCCUnfm80", kTH1F, {axisQA2}); + + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccMultNTracksHasITSUnfm80", "OccMultNTracksHasITSUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccMultNTracksHasTPCUnfm80", "OccMultNTracksHasTPCUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccMultNTracksHasTOFUnfm80", "OccMultNTracksHasTOFUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccMultNTracksHasTRDUnfm80", "OccMultNTracksHasTRDUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccMultNTracksITSOnlyUnfm80", "OccMultNTracksITSOnlyUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccMultNTracksTPCOnlyUnfm80", "OccMultNTracksTPCOnlyUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccMultNTracksITSTPCUnfm80", "OccMultNTracksITSTPCUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccMultAllTracksTPCOnlyUnfm80", "OccMultAllTracksTPCOnlyUnfm80", kTH1F, {axisQA2}); + + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccRobustT0V0PrimUnfm80", "OccRobustT0V0PrimUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccRobustFDDT0V0PrimUnfm80", "OccRobustFDDT0V0PrimUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccRobustNtrackDetUnfm80", "OccRobustNtrackDetUnfm80", kTH1F, {axisQA2}); + occupancyQA.add("occTrackQA/LogRatio/RobustT0V0Prim/Mean/OccRobustMultExtraTableUnfm80", "OccRobustMultExtraTableUnfm80", kTH1F, {axisQA2}); + + occupancyQA.addClone("occTrackQA/LogRatio/RobustT0V0Prim/Mean/", "occTrackQA/LogRatio/RobustT0V0Prim/WeightMean/"); + occupancyQA.addClone("occTrackQA/LogRatio/RobustT0V0Prim/WeightMean/", "occTrackQA/LogRatio/weightRobustT0V0Prim/WeightMean/"); + } + + if (fillQA2) { + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccPrimUnfm80", "OccPrimUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccFV0AUnfm80", "OccFV0AUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccFV0CUnfm80", "OccFV0CUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccFT0AUnfm80", "OccFT0AUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccFT0CUnfm80", "OccFT0CUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccFDDAUnfm80", "OccFDDAUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccFDDCUnfm80", "OccFDDCUnfm80", kTH1F, {axisQA3}); + + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccNTrackITSUnfm80", "OccNTrackITSUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccNTrackTPCUnfm80", "OccNTrackTPCUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccNTrackTRDUnfm80", "OccNTrackTRDUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccNTrackTOFUnfm80", "OccNTrackTOFUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccNTrackSizeUnfm80", "OccNTrackSizeUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccNTrackTPCAUnfm80", "OccNTrackTPCAUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccNTrackTPCCUnfm80", "OccNTrackTPCCUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccNTrackITSTPCUnfm80", "OccNTrackITSTPCUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccNTrackITSTPCAUnfm80", "OccNTrackITSTPCAUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccNTrackITSTPCCUnfm80", "OccNTrackITSTPCCUnfm80", kTH1F, {axisQA3}); + + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccMultNTracksHasITSUnfm80", "OccMultNTracksHasITSUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccMultNTracksHasTPCUnfm80", "OccMultNTracksHasTPCUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccMultNTracksHasTOFUnfm80", "OccMultNTracksHasTOFUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccMultNTracksHasTRDUnfm80", "OccMultNTracksHasTRDUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccMultNTracksITSOnlyUnfm80", "OccMultNTracksITSOnlyUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccMultNTracksTPCOnlyUnfm80", "OccMultNTracksTPCOnlyUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccMultNTracksITSTPCUnfm80", "OccMultNTracksITSTPCUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccMultAllTracksTPCOnlyUnfm80", "OccMultAllTracksTPCOnlyUnfm80", kTH1F, {axisQA3}); + + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccRobustT0V0PrimUnfm80", "OccRobustT0V0PrimUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccRobustFDDT0V0PrimUnfm80", "OccRobustFDDT0V0PrimUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccRobustNtrackDetUnfm80", "OccRobustNtrackDetUnfm80", kTH1F, {axisQA3}); + occupancyQA.add("occTrackQA/Condition1/RobustT0V0Prim/Mean/OccRobustMultExtraTableUnfm80", "OccRobustMultExtraTableUnfm80", kTH1F, {axisQA3}); + + occupancyQA.addClone("occTrackQA/Condition1/RobustT0V0Prim/Mean/", "occTrackQA/Condition1/RobustT0V0Prim/WeightMean/"); + occupancyQA.addClone("occTrackQA/Condition1/RobustT0V0Prim/WeightMean/", "occTrackQA/Condition1/weightRobustT0V0Prim/WeightMean/"); + + occupancyQA.addClone("occTrackQA/Condition1/", "occTrackQA/Condition2/"); + occupancyQA.addClone("occTrackQA/Condition1/", "occTrackQA/Condition3/"); + occupancyQA.addClone("occTrackQA/Condition1/", "occTrackQA/Condition4/"); + } + occupancyQA.print(); + } + + enum OccNamesEnum { + kOccPrimUnfm80 = 0, + kOccFV0AUnfm80, + kOccFV0CUnfm80, + kOccFT0AUnfm80, + kOccFT0CUnfm80, + kOccFDDAUnfm80, + kOccFDDCUnfm80, + + kOccNTrackITSUnfm80, + kOccNTrackTPCUnfm80, + kOccNTrackTRDUnfm80, + kOccNTrackTOFUnfm80, + kOccNTrackSizeUnfm80, + kOccNTrackTPCAUnfm80, + kOccNTrackTPCCUnfm80, + kOccNTrackITSTPCUnfm80, + kOccNTrackITSTPCAUnfm80, + kOccNTrackITSTPCCUnfm80, + + kOccMultNTracksHasITSUnfm80, + kOccMultNTracksHasTPCUnfm80, + kOccMultNTracksHasTOFUnfm80, + kOccMultNTracksHasTRDUnfm80, + kOccMultNTracksITSOnlyUnfm80, + kOccMultNTracksTPCOnlyUnfm80, + kOccMultNTracksITSTPCUnfm80, + kOccMultAllTracksTPCOnlyUnfm80, + + kOccRobustT0V0PrimUnfm80, + kOccRobustFDDT0V0PrimUnfm80, + kOccRobustNtrackDetUnfm80, + kOccRobustMultTableUnfm80 + }; + + static constexpr std::string_view OccNames[]{ + "OccPrimUnfm80", + "OccFV0AUnfm80", + "OccFV0CUnfm80", + "OccFT0AUnfm80", + "OccFT0CUnfm80", + "OccFDDAUnfm80", + "OccFDDCUnfm80", + + "OccNTrackITSUnfm80", + "OccNTrackTPCUnfm80", + "OccNTrackTRDUnfm80", + "OccNTrackTOFUnfm80", + "OccNTrackSizeUnfm80", + "OccNTrackTPCAUnfm80", + "OccNTrackTPCCUnfm80", + "OccNTrackITSTPCUnfm80", + "OccNTrackITSTPCAUnfm80", + "OccNTrackITSTPCCUnfm80", + + "OccMultNTracksHasITSUnfm80", + "OccMultNTracksHasTPCUnfm80", + "OccMultNTracksHasTOFUnfm80", + "OccMultNTracksHasTRDUnfm80", + "OccMultNTracksITSOnlyUnfm80", + "OccMultNTracksTPCOnlyUnfm80", + "OccMultNTracksITSTPCUnfm80", + "OccMultAllTracksTPCOnlyUnfm80", + + "OccRobustT0V0PrimUnfm80", + "OccRobustFDDT0V0PrimUnfm80", + "OccRobustNtrackDetUnfm80", + "OccRobustMultExtraTableUnfm80"}; + + enum OccDirEnum { + kMean = 0, + kWeightMean, + kLogRatio, + kRobustT0V0Prim, + kWeightRobustT0V0Prim, + kCondition1, + kCondition2, + kCondition3, + kCondition4 + }; + + static constexpr std::string_view OccDire[] = { + "Mean/", + "WeightMean/", + "LogRatio/", + "RobustT0V0Prim/", + "weightRobustT0V0Prim/", + "Condition1/", + "Condition2/", + "Condition3/", + "Condition4/"}; + + void getRunInfo(const int& run, int& nBCsPerTF, int64_t& bcSOR) + { + auto runDuration = ccdb->getRunDuration(run, true); + int64_t tsSOR = runDuration.first; + auto ctpx = ccdb->getForTimeStamp>("CTP/Calib/OrbitReset", tsSOR); + int64_t tsOrbitReset = (*ctpx)[0]; + uint32_t nOrbitsPerTF = run < 534133 ? 128 : 32; + int64_t orbitSOR = (tsSOR * 1000 - tsOrbitReset) / o2::constants::lhc::LHCOrbitMUS; + orbitSOR = orbitSOR / nOrbitsPerTF * nOrbitsPerTF; + bcSOR = orbitSOR * nBCsPerOrbit + customOrbitOffset * nBCsPerOrbit; // customOrbitOffset is a configurable + nBCsPerTF = nOrbitsPerTF * nBCsPerOrbit; + } + + template + void getTimingInfo(const T& bc, int& lastRun, int32_t& nBCsPerTF, int64_t& bcSOR, uint64_t& time, int64_t& tfIdThis, int& bcInTF) + { + int run = bc.runNumber(); + if (run != lastRun) { // update run info + lastRun = run; + getRunInfo(run, nBCsPerTF, bcSOR); // update nBCsPerTF && bcSOR + } + // update the information + time = bc.timestamp(); + tfIdThis = (bc.globalBC() - bcSOR) / nBCsPerTF; + bcInTF = (bc.globalBC() - bcSOR) % nBCsPerTF; + } + + float getMeanOccupancy(int bcBegin, int bcEnd, const std::vector& OccVector) + { + float sumOfBins = 0; + int binStart, binEnd; + if (bcBegin <= bcEnd) { + binStart = bcBegin; + binEnd = bcEnd; + } else { + binStart = bcEnd; + binEnd = bcBegin; + } + for (int i = binStart; i <= binEnd; i++) { + sumOfBins += OccVector[i]; + } + float meanOccupancy = sumOfBins / static_cast(binEnd - binStart + 1); + return meanOccupancy; + } + + float getWeightedMeanOccupancy(int bcBegin, int bcEnd, const std::vector& OccVector) + { + float sumOfBins = 0; + int binStart, binEnd; + // Assuming linear dependence of R on bins + float m; // slope of the equation + float c; // some constant in linear + float x1, x2; //, y1 = 90., y2 = 245.; + + if (bcBegin <= bcEnd) { + binStart = bcBegin; + binEnd = bcEnd; + x1 = static_cast(binStart); + x2 = static_cast(binEnd); + } else { + binStart = bcEnd; + binEnd = bcBegin; + x1 = static_cast(binEnd); + x2 = static_cast(binStart); + } // + + if (x2 == x1) { + m = 0; + } else { + m = (245. - 90.) / (x2 - x1); + } + c = 245. - m * x2; + float weightSum = 0; + float wr = 0; + float r = 0; + for (int i = binStart; i <= binEnd; i++) { + r = m * i + c; + wr = 125. / r; + if (x2 == x1) { + wr = 1.0; + } + sumOfBins += OccVector[i] * wr; + weightSum += wr; + } + float meanOccupancy = sumOfBins / weightSum; + return meanOccupancy; + } + + template + void fillQAInfo(const float& occValue, const float& occRobustValue) + { + occupancyQA.fill(HIST("occTrackQA/") + HIST(OccDire[occMode]) + HIST(OccNames[occName]), occValue); + if (fillQA1) { + occupancyQA.fill(HIST("occTrackQA/LogRatio/") + HIST(OccDire[occRobustMode]) + HIST(OccDire[occMode]) + HIST(OccNames[occName]), std::log(std::abs(occValue / occRobustValue))); + if (fillQA2) { + if (std::abs(std::log(occValue / occRobustValue)) < 2) { // conditional filling start + occupancyQA.fill(HIST("occTrackQA/Condition1/") + HIST(OccDire[occRobustMode]) + HIST(OccDire[occMode]) + HIST(OccNames[occName]), (std::log(occValue / occRobustValue)) * std::sqrt(occValue + occRobustValue)); + if (std::abs(occRobustValue + occValue) > 200) { + occupancyQA.fill(HIST("occTrackQA/Condition4/") + HIST(OccDire[occRobustMode]) + HIST(OccDire[occMode]) + HIST(OccNames[occName]), (std::log(occValue / occRobustValue)) * std::sqrt(occValue + occRobustValue)); + occupancyQA.fill(HIST("occTrackQA/Condition3/") + HIST(OccDire[occRobustMode]) + HIST(OccDire[occMode]) + HIST(OccNames[occName]), (std::log(occValue / occRobustValue)) * std::sqrt(occValue + occRobustValue)); + occupancyQA.fill(HIST("occTrackQA/Condition2/") + HIST(OccDire[occRobustMode]) + HIST(OccDire[occMode]) + HIST(OccNames[occName]), (std::log(occValue / occRobustValue)) * std::sqrt(occValue + occRobustValue)); + } else if (std::abs(occRobustValue + occValue) > 50) { + occupancyQA.fill(HIST("occTrackQA/Condition3/") + HIST(OccDire[occRobustMode]) + HIST(OccDire[occMode]) + HIST(OccNames[occName]), (std::log(occValue / occRobustValue)) * std::sqrt(occValue + occRobustValue)); + occupancyQA.fill(HIST("occTrackQA/Condition2/") + HIST(OccDire[occRobustMode]) + HIST(OccDire[occMode]) + HIST(OccNames[occName]), (std::log(occValue / occRobustValue)) * std::sqrt(occValue + occRobustValue)); + } else if (std::abs(occRobustValue + occValue) > 20) { + occupancyQA.fill(HIST("occTrackQA/Condition2/") + HIST(OccDire[occRobustMode]) + HIST(OccDire[occMode]) + HIST(OccNames[occName]), (std::log(occValue / occRobustValue)) * std::sqrt(occValue + occRobustValue)); + } + } // conditional filling end + } + } + } + + using MyCollisions = soa::Join; + using MyTracks = soa::Join; + using MyTracksQA = aod::TracksQA_002; + using MyBCTable = soa::Join; + + using MyOccsDet = soa::Join; + using MyOccsTrackMult = soa::Join; + using MyOccsMultExtra = soa::Join; + using MyOccsRobust = soa::Join; + + // Process the Data + int dfCount = 0; + int32_t nBCsPerTF = -999; + int64_t bcSOR = -999; + int lastRun = -999; + + uint64_t time = -1; + int64_t tfIdThis = -1; + int bcInTF = -1; + + void process(MyBCTable const& BCs, MyCollisions const& collisions, MyTracks const& tracks, MyTracksQA const& tracksQA, + // o2::aod::AmbiguousTracks const& ambgTracks, o2::aod::Origins const& Origins, aod::OccsBCsList const& occsBCsList, //tables only used during debugging + MyOccsDet const& occsDet, MyOccsTrackMult const& occsTrackMult, + MyOccsMultExtra const& occsMultExtra, MyOccsRobust const& occsRobust) + { + // dfCount++;LOG(info) << "DEBUG 2 :: df_" << dfCount ;//<< " :: DF_" << Origins.begin().dataframeID() << " :: collisions.size() = " << collisions.size() << " :: tracks.size() = " << tracks.size() << " :: tracksQA.size() = " << tracksQA.size() + // << " :: MyBCTable.size() = " << BCs.size() + // << " :: occsBCsList.size() = " <(); + } + if (doAmbgUpdate) { + // to be updated later + // bc = collisions.iteratorAt(2).bc_as(); + // bc = ambgTracks.iteratorAt(0).bc_as(); + } + // LOG(info)<<" What happens in the case when the collision id is = -1 and it tries to obtain bc" + getTimingInfo(bc, lastRun, nBCsPerTF, bcSOR, time, tfIdThis, bcInTF); + } + + if (tfIdThis != oldTFid) { + oldTFid = tfIdThis; + // auto OccList = Occs.iteratorAt(bc.occId()); + if (buildTrackMeanOccs1 || buildTrackMeanOccs5) { + auto listOccsDet = occsDet.iteratorAt(bc.occId()); + std::copy(listOccsDet.occPrimUnfm80().begin(), listOccsDet.occPrimUnfm80().end(), occPrimUnfm80.begin()); + std::copy(listOccsDet.occFV0AUnfm80().begin(), listOccsDet.occFV0AUnfm80().end(), occFV0AUnfm80.begin()); + std::copy(listOccsDet.occFV0CUnfm80().begin(), listOccsDet.occFV0CUnfm80().end(), occFV0CUnfm80.begin()); + std::copy(listOccsDet.occFT0AUnfm80().begin(), listOccsDet.occFT0AUnfm80().end(), occFT0AUnfm80.begin()); + std::copy(listOccsDet.occFT0CUnfm80().begin(), listOccsDet.occFT0CUnfm80().end(), occFT0CUnfm80.begin()); + std::copy(listOccsDet.occFDDAUnfm80().begin(), listOccsDet.occFDDAUnfm80().end(), occFDDAUnfm80.begin()); + std::copy(listOccsDet.occFDDCUnfm80().begin(), listOccsDet.occFDDCUnfm80().end(), occFDDCUnfm80.begin()); + } + + if (buildTrackMeanOccs2 || buildTrackMeanOccs6) { + auto listOccsTrackMult = occsTrackMult.iteratorAt(bc.occId()); + ; + std::copy(listOccsTrackMult.occNTrackITSUnfm80().begin(), listOccsTrackMult.occNTrackITSUnfm80().end(), occNTrackITSUnfm80.begin()); + std::copy(listOccsTrackMult.occNTrackTPCUnfm80().begin(), listOccsTrackMult.occNTrackTPCUnfm80().end(), occNTrackTPCUnfm80.begin()); + std::copy(listOccsTrackMult.occNTrackTRDUnfm80().begin(), listOccsTrackMult.occNTrackTRDUnfm80().end(), occNTrackTRDUnfm80.begin()); + std::copy(listOccsTrackMult.occNTrackTOFUnfm80().begin(), listOccsTrackMult.occNTrackTOFUnfm80().end(), occNTrackTOFUnfm80.begin()); + std::copy(listOccsTrackMult.occNTrackSizeUnfm80().begin(), listOccsTrackMult.occNTrackSizeUnfm80().end(), occNTrackSizeUnfm80.begin()); + std::copy(listOccsTrackMult.occNTrackTPCAUnfm80().begin(), listOccsTrackMult.occNTrackTPCAUnfm80().end(), occNTrackTPCAUnfm80.begin()); + std::copy(listOccsTrackMult.occNTrackTPCCUnfm80().begin(), listOccsTrackMult.occNTrackTPCCUnfm80().end(), occNTrackTPCCUnfm80.begin()); + std::copy(listOccsTrackMult.occNTrackITSTPCUnfm80().begin(), listOccsTrackMult.occNTrackITSTPCUnfm80().end(), occNTrackITSTPCUnfm80.begin()); + std::copy(listOccsTrackMult.occNTrackITSTPCAUnfm80().begin(), listOccsTrackMult.occNTrackITSTPCAUnfm80().end(), occNTrackITSTPCAUnfm80.begin()); + std::copy(listOccsTrackMult.occNTrackITSTPCCUnfm80().begin(), listOccsTrackMult.occNTrackITSTPCCUnfm80().end(), occNTrackITSTPCCUnfm80.begin()); + } + + if (buildTrackMeanOccs3 || buildTrackMeanOccs7) { + auto listOccsMultExtra = occsMultExtra.iteratorAt(bc.occId()); + ; + std::copy(listOccsMultExtra.occMultNTracksHasITSUnfm80().begin(), listOccsMultExtra.occMultNTracksHasITSUnfm80().end(), occMultNTracksHasITSUnfm80.begin()); + std::copy(listOccsMultExtra.occMultNTracksHasTPCUnfm80().begin(), listOccsMultExtra.occMultNTracksHasTPCUnfm80().end(), occMultNTracksHasTPCUnfm80.begin()); + std::copy(listOccsMultExtra.occMultNTracksHasTOFUnfm80().begin(), listOccsMultExtra.occMultNTracksHasTOFUnfm80().end(), occMultNTracksHasTOFUnfm80.begin()); + std::copy(listOccsMultExtra.occMultNTracksHasTRDUnfm80().begin(), listOccsMultExtra.occMultNTracksHasTRDUnfm80().end(), occMultNTracksHasTRDUnfm80.begin()); + std::copy(listOccsMultExtra.occMultNTracksITSOnlyUnfm80().begin(), listOccsMultExtra.occMultNTracksITSOnlyUnfm80().end(), occMultNTracksITSOnlyUnfm80.begin()); + std::copy(listOccsMultExtra.occMultNTracksTPCOnlyUnfm80().begin(), listOccsMultExtra.occMultNTracksTPCOnlyUnfm80().end(), occMultNTracksTPCOnlyUnfm80.begin()); + std::copy(listOccsMultExtra.occMultNTracksITSTPCUnfm80().begin(), listOccsMultExtra.occMultNTracksITSTPCUnfm80().end(), occMultNTracksITSTPCUnfm80.begin()); + std::copy(listOccsMultExtra.occMultAllTracksTPCOnlyUnfm80().begin(), listOccsMultExtra.occMultAllTracksTPCOnlyUnfm80().end(), occMultAllTracksTPCOnlyUnfm80.begin()); + } + + auto listOccsRobust = occsRobust.iteratorAt(bc.occId()); + std::copy(listOccsRobust.occRobustT0V0PrimUnfm80().begin(), listOccsRobust.occRobustT0V0PrimUnfm80().end(), occRobustT0V0PrimUnfm80.begin()); + if (buildTrackMeanOccs4 || buildTrackMeanOccs8) { + std::copy(listOccsRobust.occRobustFDDT0V0PrimUnfm80().begin(), listOccsRobust.occRobustFDDT0V0PrimUnfm80().end(), occRobustFDDT0V0PrimUnfm80.begin()); + std::copy(listOccsRobust.occRobustNtrackDetUnfm80().begin(), listOccsRobust.occRobustNtrackDetUnfm80().end(), occRobustNtrackDetUnfm80.begin()); + std::copy(listOccsRobust.occRobustMultExtraTableUnfm80().begin(), listOccsRobust.occRobustMultExtraTableUnfm80().end(), occRobustMultTableUnfm80.begin()); + } + } + + // Timebc = TGlobalBC+ΔTdrift + // ΔTdrift=((250(cm)-abs(z))/vdrift) + // vdrift=2.64 cm/μs + // z=zv+tgl*Radius + + rBegin = 90., rEnd = 245.; // in cm + zBegin = collision.posZ() + track.tgl() * rBegin; // in cm + zEnd = collision.posZ() + track.tgl() * rEnd; // in cm + vdrift = 2.64; // cm/μs + + // clip the result at 250 + if (zBegin > 250) { + zBegin = 250; + } else if (zBegin < -250) { + zBegin = -250; + } + + if (zEnd > 250) { + zEnd = 250; + } else if (zEnd < -250) { + zEnd = -250; + } + + dTbegin = ((250. - std::abs(zBegin)) / vdrift) / 0.025; + dTend = ((250. - std::abs(zEnd)) / vdrift) / 0.025; + + bcBegin = bcInTF + dTbegin; + bcEnd = bcInTF + dTend; + + binBCbegin = bcBegin / 80; + binBCend = bcEnd / 80; + + genTrackMeanOccs0(track.globalIndex()); + + meanOccRobustT0V0PrimUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occRobustT0V0PrimUnfm80); + weightMeanOccRobustT0V0PrimUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occRobustT0V0PrimUnfm80); + + if (buildTrackMeanOccs1) { + meanOccPrimUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occPrimUnfm80); + meanOccFV0AUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occFV0AUnfm80); + meanOccFV0CUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occFV0CUnfm80); + meanOccFT0AUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occFT0AUnfm80); + meanOccFT0CUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occFT0CUnfm80); + meanOccFDDAUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occFDDAUnfm80); + meanOccFDDCUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occFDDCUnfm80); + + genTrackMeanOccs1(meanOccPrimUnfm80, + meanOccFV0AUnfm80, + meanOccFV0CUnfm80, + meanOccFT0AUnfm80, + meanOccFT0CUnfm80, + meanOccFDDAUnfm80, + meanOccFDDCUnfm80); + + fillQAInfo(meanOccPrimUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccFV0AUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccFV0CUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccFT0AUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccFT0CUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccFDDAUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccFDDCUnfm80, meanOccRobustT0V0PrimUnfm80); + } + if (buildTrackMeanOccs2) { + meanOccNTrackITSUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occNTrackITSUnfm80); + meanOccNTrackTPCUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occNTrackTPCUnfm80); + meanOccNTrackTRDUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occNTrackTRDUnfm80); + meanOccNTrackTOFUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occNTrackTOFUnfm80); + meanOccNTrackSizeUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occNTrackSizeUnfm80); + meanOccNTrackTPCAUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occNTrackTPCAUnfm80); + meanOccNTrackTPCCUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occNTrackTPCCUnfm80); + meanOccNTrackITSTPCUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occNTrackITSTPCUnfm80); + meanOccNTrackITSTPCAUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occNTrackITSTPCAUnfm80); + meanOccNTrackITSTPCCUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occNTrackITSTPCCUnfm80); + + genTrackMeanOccs2(meanOccNTrackITSUnfm80, + meanOccNTrackTPCUnfm80, + meanOccNTrackTRDUnfm80, + meanOccNTrackTOFUnfm80, + meanOccNTrackSizeUnfm80, + meanOccNTrackTPCAUnfm80, + meanOccNTrackTPCCUnfm80, + meanOccNTrackITSTPCUnfm80, + meanOccNTrackITSTPCAUnfm80, + meanOccNTrackITSTPCCUnfm80); + + fillQAInfo(meanOccNTrackITSUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccNTrackTPCUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccNTrackTRDUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccNTrackTOFUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccNTrackSizeUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccNTrackTPCAUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccNTrackTPCCUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccNTrackITSTPCUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccNTrackITSTPCAUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccNTrackITSTPCCUnfm80, meanOccRobustT0V0PrimUnfm80); + } + if (buildTrackMeanOccs3) { + meanOccMultNTracksHasITSUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occMultNTracksHasITSUnfm80); + meanOccMultNTracksHasTPCUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occMultNTracksHasTPCUnfm80); + meanOccMultNTracksHasTOFUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occMultNTracksHasTOFUnfm80); + meanOccMultNTracksHasTRDUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occMultNTracksHasTRDUnfm80); + meanOccMultNTracksITSOnlyUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occMultNTracksITSOnlyUnfm80); + meanOccMultNTracksTPCOnlyUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occMultNTracksTPCOnlyUnfm80); + meanOccMultNTracksITSTPCUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occMultNTracksITSTPCUnfm80); + meanOccMultAllTracksTPCOnlyUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occMultAllTracksTPCOnlyUnfm80); + + genTrackMeanOccs3(meanOccMultNTracksHasITSUnfm80, + meanOccMultNTracksHasTPCUnfm80, + meanOccMultNTracksHasTOFUnfm80, + meanOccMultNTracksHasTRDUnfm80, + meanOccMultNTracksITSOnlyUnfm80, + meanOccMultNTracksTPCOnlyUnfm80, + meanOccMultNTracksITSTPCUnfm80, + meanOccMultAllTracksTPCOnlyUnfm80); + + fillQAInfo(meanOccMultNTracksHasITSUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccMultNTracksHasTPCUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccMultNTracksHasTOFUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccMultNTracksHasTRDUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccMultNTracksITSOnlyUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccMultNTracksTPCOnlyUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccMultNTracksITSTPCUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccMultAllTracksTPCOnlyUnfm80, meanOccRobustT0V0PrimUnfm80); + } + if (buildTrackMeanOccs4) { + meanOccRobustFDDT0V0PrimUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occRobustFDDT0V0PrimUnfm80); + meanOccRobustNtrackDetUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occRobustNtrackDetUnfm80); + meanOccRobustMultTableUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occRobustMultTableUnfm80); + + genTrackMeanOccs4(meanOccRobustT0V0PrimUnfm80, + meanOccRobustFDDT0V0PrimUnfm80, + meanOccRobustNtrackDetUnfm80, + meanOccRobustMultTableUnfm80); + + fillQAInfo(meanOccRobustT0V0PrimUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccRobustFDDT0V0PrimUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccRobustNtrackDetUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccRobustMultTableUnfm80, meanOccRobustT0V0PrimUnfm80); + } + + if (buildTrackMeanOccs5) { + weightMeanOccPrimUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occPrimUnfm80); + weightMeanOccFV0AUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occFV0AUnfm80); + weightMeanOccFV0CUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occFV0CUnfm80); + weightMeanOccFT0AUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occFT0AUnfm80); + weightMeanOccFT0CUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occFT0CUnfm80); + weightMeanOccFDDAUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occFDDAUnfm80); + weightMeanOccFDDCUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occFDDCUnfm80); + + genTrackMeanOccs5(weightMeanOccPrimUnfm80, + weightMeanOccFV0AUnfm80, + weightMeanOccFV0CUnfm80, + weightMeanOccFT0AUnfm80, + weightMeanOccFT0CUnfm80, + weightMeanOccFDDAUnfm80, + weightMeanOccFDDCUnfm80); + + fillQAInfo(weightMeanOccPrimUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFV0AUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFV0CUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFT0AUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFT0CUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFDDAUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFDDCUnfm80, meanOccRobustT0V0PrimUnfm80); + + fillQAInfo(weightMeanOccPrimUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFV0AUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFV0CUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFT0AUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFT0CUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFDDAUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFDDCUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + } + + if (buildTrackMeanOccs6) { + weightMeanOccNTrackITSUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occNTrackITSUnfm80); + weightMeanOccNTrackTPCUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occNTrackTPCUnfm80); + weightMeanOccNTrackTRDUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occNTrackTRDUnfm80); + weightMeanOccNTrackTOFUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occNTrackTOFUnfm80); + weightMeanOccNTrackSizeUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occNTrackSizeUnfm80); + weightMeanOccNTrackTPCAUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occNTrackTPCAUnfm80); + weightMeanOccNTrackTPCCUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occNTrackTPCCUnfm80); + weightMeanOccNTrackITSTPCUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occNTrackITSTPCUnfm80); + weightMeanOccNTrackITSTPCAUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occNTrackITSTPCAUnfm80); + weightMeanOccNTrackITSTPCCUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occNTrackITSTPCCUnfm80); + + genTrackMeanOccs6(weightMeanOccNTrackITSUnfm80, + weightMeanOccNTrackTPCUnfm80, + weightMeanOccNTrackTRDUnfm80, + weightMeanOccNTrackTOFUnfm80, + weightMeanOccNTrackSizeUnfm80, + weightMeanOccNTrackTPCAUnfm80, + weightMeanOccNTrackTPCCUnfm80, + weightMeanOccNTrackITSTPCUnfm80, + weightMeanOccNTrackITSTPCAUnfm80, + weightMeanOccNTrackITSTPCCUnfm80); + + fillQAInfo(weightMeanOccNTrackITSUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackTPCUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackTRDUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackTOFUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackSizeUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackTPCAUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackTPCCUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackITSTPCUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackITSTPCAUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackITSTPCCUnfm80, meanOccRobustT0V0PrimUnfm80); + + fillQAInfo(weightMeanOccNTrackITSUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackTPCUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackTRDUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackTOFUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackSizeUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackTPCAUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackTPCCUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackITSTPCUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackITSTPCAUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccNTrackITSTPCCUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + } + + if (buildTrackMeanOccs7) { + weightMeanOccMultNTracksHasITSUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occMultNTracksHasITSUnfm80); + weightMeanOccMultNTracksHasTPCUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occMultNTracksHasTPCUnfm80); + weightMeanOccMultNTracksHasTOFUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occMultNTracksHasTOFUnfm80); + weightMeanOccMultNTracksHasTRDUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occMultNTracksHasTRDUnfm80); + weightMeanOccMultNTracksITSOnlyUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occMultNTracksITSOnlyUnfm80); + weightMeanOccMultNTracksTPCOnlyUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occMultNTracksTPCOnlyUnfm80); + weightMeanOccMultNTracksITSTPCUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occMultNTracksITSTPCUnfm80); + weightMeanOccMultAllTracksTPCOnlyUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occMultAllTracksTPCOnlyUnfm80); + + genTrackMeanOccs7(weightMeanOccMultNTracksHasITSUnfm80, + weightMeanOccMultNTracksHasTPCUnfm80, + weightMeanOccMultNTracksHasTOFUnfm80, + weightMeanOccMultNTracksHasTRDUnfm80, + weightMeanOccMultNTracksITSOnlyUnfm80, + weightMeanOccMultNTracksTPCOnlyUnfm80, + weightMeanOccMultNTracksITSTPCUnfm80, + weightMeanOccMultAllTracksTPCOnlyUnfm80); + + fillQAInfo(weightMeanOccMultNTracksHasITSUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccMultNTracksHasTPCUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccMultNTracksHasTOFUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccMultNTracksHasTRDUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccMultNTracksITSOnlyUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccMultNTracksTPCOnlyUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccMultNTracksITSTPCUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccMultAllTracksTPCOnlyUnfm80, meanOccRobustT0V0PrimUnfm80); + + fillQAInfo(weightMeanOccMultNTracksHasITSUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccMultNTracksHasTPCUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccMultNTracksHasTOFUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccMultNTracksHasTRDUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccMultNTracksITSOnlyUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccMultNTracksTPCOnlyUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccMultNTracksITSTPCUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccMultAllTracksTPCOnlyUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + } + + if (buildTrackMeanOccs8) { + weightMeanOccRobustFDDT0V0PrimUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occRobustFDDT0V0PrimUnfm80); + weightMeanOccRobustNtrackDetUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occRobustNtrackDetUnfm80); + weightMeanOccRobustMultTableUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occRobustMultTableUnfm80); + + genTrackMeanOccs8(weightMeanOccRobustT0V0PrimUnfm80, + weightMeanOccRobustFDDT0V0PrimUnfm80, + weightMeanOccRobustNtrackDetUnfm80, + weightMeanOccRobustMultTableUnfm80); + + fillQAInfo(weightMeanOccRobustT0V0PrimUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccRobustFDDT0V0PrimUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccRobustNtrackDetUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccRobustMultTableUnfm80, meanOccRobustT0V0PrimUnfm80); + + fillQAInfo(weightMeanOccRobustT0V0PrimUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccRobustFDDT0V0PrimUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccRobustNtrackDetUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccRobustMultTableUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + } + } // end of trackQA loop + } // Process function ends +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +} diff --git a/Common/TableProducer/qVectorsTable.cxx b/Common/TableProducer/qVectorsTable.cxx index a1ac0a8b7db..9de8faf028f 100644 --- a/Common/TableProducer/qVectorsTable.cxx +++ b/Common/TableProducer/qVectorsTable.cxx @@ -23,11 +23,13 @@ #include #include #include +#include // o2Physics includes. #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" #include "Common/Core/EventPlaneHelper.h" #include "Common/DataModel/EventSelection.h" @@ -57,8 +59,9 @@ struct qVectorsTable { kFT0A = 1, kFT0M, kFV0A, - kBPos, - kBNeg + kTPCpos, + kTPCneg, + kTPCall }; // Configurables. @@ -73,41 +76,44 @@ struct qVectorsTable { Configurable cfgCentEsti{"cfgCentEsti", 2, "Centrality estimator (Run3): 0 = FT0M, 1 = FT0A, 2 = FT0C, 3 = FV0A"}; - Configurable cfgCCDBConst{"cfgCCDBConst", 1, "Using constants in CCDB, 1 = CCDB, 2= Configurable"}; - Configurable cfgGainCor{"cfgGainCor", 2, "Gain equalization, 1 = CCDB, 2 = Configurable"}; - // LOKI: We have here all centrality estimators for Run 3 (except FDDM and NTPV), - // but the Q-vectors are calculated only for some of them. - // FIXME: 6 correction factors for each centrality and 8 centrality intervals are hard-coded. - // TODO: Constants from the CCDB - Configurable> cfgFT0CCorr{"cfgFT0CCorr", std::vector{0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.}, "Correction constants for FT0C"}; - Configurable> cfgFT0ACorr{"cfgFT0ACorr", std::vector{0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.}, "Correction constants for FT0A"}; - Configurable> cfgFT0MCorr{"cfgFT0MCorr", std::vector{0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.}, "Correction constants for FT0M"}; - Configurable> cfgFV0ACorr{"cfgFV0ACorr", std::vector{0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.}, "Correction constants for FV0A"}; - Configurable> cfgBPosCorr{"cfgBPosCorr", std::vector{0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.}, "Correction constants for positive TPC tracks"}; - Configurable> cfgBNegCorr{"cfgBNegCorr", std::vector{0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.}, "Correction constants for negative TPC tracks"}; - - Configurable> cfgFT0RelGain{"cfgFT0RelGain", std::vector{1.66815, 1.07726, 1.06665, 0.804114, 0.583846, 0.500518, 0.391628, 0.348394, 0.358615, 0.308253, 0.294405, 0.273764, 2.57031, 2.39421, 1.44468, 1.36256, 0.680442, 0.514505, 0.402177, 0.0768064, 0.724138, 0.69854, 0.45071, 0.468864, 2.39613, 1.29564, 1.32493, 0.966852, 0.847806, 0.676617, 0.560133, 0.445884, 0.449895, 0.361821, 0.361393, 0.352685, 3.34893, 3.14722, 1.77013, 1.6832, 0.880161, 0.671814, 0.574672, 0.500735, 0.911163, 0.869385, 0.568519, 0.575432, 2.6472, 1.48855, 1.54706, 1.14217, 0.787196, 0.598142, 0.53321, 0.44489, 0.490051, 0.385222, 0.41518, 0.366924, 2.9316, 2.8146, 1.52534, 1.61405, 0.899687, 0.701258, 0.54537, 0.506217, 0.823043, 0.904671, 0.548924, 0.54579, 2.42676, 1.45846, 1.48897, 1.02953, 0.827955, 0.640462, 0.572353, 0.46783, 0.488863, 0.369599, 0.415494, 0.362218, 3.17981, 3.01309, 1.79391, 1.65753, 0.922038, 0.747622, 0.585332, 0.516699, 1.04287, 1.00833, 0.673634, 0.647385, 1.28287, 0.982116, 0.952414, 0.812895, 0.696049, 0.643981, 0.561084, 0.545641, 0.627786, 0.556424, 0.580068, 0.563328, 1.55845, 1.35077, 1.08229, 0.932524, 0.721666, 0.673458, 0.544954, 0.57362, 0.633485, 0.627168, 0.545195, 0.614894, 1.71862, 1.4596, 1.13659, 1.0249, 0.941048, 0.69596, 0.621792, 0.609313, 0.727359, 0.618647, 0.651608, 0.668898, 1.8986, 1.74193, 1.33445, 1.08025, 0.823063, 0.773975, 0.665728, 0.661659, 0.71767, 0.682773, 0.678768, 0.703515, 2.09321, 1.70391, 1.31288, 1.13727, 0.842259, 0.782933, 0.691555, 0.66877, 0.729401, 0.657522, 0.677497, 0.652054, 1.6339, 1.73831, 1.58303, 1.17792, 0.888915, 0.833191, 0.693254, 0.689346, 0.80103, 0.751452, 0.741275, 0.757127, 2.32919, 1.93853, 1.46963, 1.27367, 0.957618, 1.07039, 0.737812, 0.759759, 0.827746, 0.724172, 0.782507, 0.803106, 2.80548, 0.99413, 1.73022, 1.50227, 0.921537, 0.869511, 1.03225, 1.07005, 1.57744, 1.30007, 1.23155, 1.06504, 1.70968, 1.25775, 1.24086, 1.07188, 1.7137, 1.36342, 1.30506, 1.12737, 1.82987, 1.39909, 1.14134, 1, 1, 1, 1, 1, 1}, "constants for relative FT0 gain equalization"}; - Configurable> cfgFV0RelGain{"cfgFV0RelGain", std::vector{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, "constants for relative FV0 gain equalization"}; - Configurable cfgMinPtOnTPC{"cfgMinPtOnTPC", 0.15, "minimum transverse momentum selection for TPC tracks participating in Q-vector reconstruction"}; Configurable cfgMaxPtOnTPC{"cfgMaxPtOnTPC", 5., "maximum transverse momentum selection for TPC tracks participating in Q-vector reconstruction"}; - Configurable cfgnMod{"cfgnMod", 2, "Modulation of interest"}; + Configurable cfgCorrLevel{"cfgCorrLevel", 4, "calibration step: 0 = no corr, 1 = gain corr, 2 = rectr, 3 = twist, 4 = full"}; + Configurable> cfgnMods{"cfgnMods", {2, 3}, "Modulation of interest"}; + Configurable cfgMaxCentrality{"cfgMaxCentrality", 100.f, "max. centrality for Q vector calibration"}; + Configurable useCorrectionForRun{"useCorrectionForRun", true, "Get Qvector corrections based on run number instead of timestamp"}; Configurable cfgGainEqPath{"cfgGainEqPath", "Users/j/junlee/Qvector/GainEq", "CCDB path for gain equalization constants"}; Configurable cfgQvecCalibPath{"cfgQvecCalibPath", "Analysis/EventPlane/QVecCorrections", "CCDB pasth for Q-vecteor calibration constants"}; ConfigurableAxis cfgaxisFITamp{"cfgaxisFITamp", {1000, 0, 5000}, ""}; + Configurable cfgUseFT0C{"cfgUseFT0C", false, "Initial value for using FT0C. By default obtained from DataModel."}; + Configurable cfgUseFT0A{"cfgUseFT0A", false, "Initial value for using FT0A. By default obtained from DataModel."}; + Configurable cfgUseFT0M{"cfgUseFT0M", false, "Initial value for using FT0M. By default obtained from DataModel."}; + Configurable cfgUseFV0A{"cfgUseFV0A", false, "Initial value for using FV0A. By default obtained from DataModel."}; + Configurable cfgUseTPCpos{"cfgUseTPCpos", false, "Initial value for using TPCpos. By default obtained from DataModel."}; + Configurable cfgUseTPCneg{"cfgUseTPCneg", false, "Initial value for using TPCneg. By default obtained from DataModel."}; + Configurable cfgUseTPCall{"cfgUseTPCall", false, "Initial value for using TPCall. By default obtained from DataModel."}; + // Table. Produces qVector; Produces qVectorFT0C; Produces qVectorFT0A; Produces qVectorFT0M; Produces qVectorFV0A; - Produces qVectorBPos; - Produces qVectorBNeg; + Produces qVectorTPCpos; + Produces qVectorTPCneg; + Produces qVectorTPCall; + + Produces qVectorFT0CVec; + Produces qVectorFT0AVec; + Produces qVectorFT0MVec; + Produces qVectorFV0AVec; + Produces qVectorTPCposVec; + Produces qVectorTPCnegVec; + Produces qVectorTPCallVec; - std::vector> cfgCorr{}; std::vector FT0RelGainConst{}; std::vector FV0RelGainConst{}; @@ -125,9 +131,61 @@ struct qVectorsTable { HistogramRegistry histosQA{"histosQA", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; int runNumber{-1}; + float cent; - void init(InitContext const&) + std::vector objQvec{}; + + // Deprecated, will be removed in future after transition time // + Configurable cfgUseBPos{"cfgUseBPos", false, "Initial value for using BPos. By default obtained from DataModel."}; + Configurable cfgUseBNeg{"cfgUseBNeg", false, "Initial value for using BNeg. By default obtained from DataModel."}; + Configurable cfgUseBTot{"cfgUseBTot", false, "Initial value for using BTot. By default obtained from DataModel."}; + + Produces qVectorBPos; + Produces qVectorBNeg; + Produces qVectorBTot; + + Produces qVectorBPosVec; + Produces qVectorBNegVec; + Produces qVectorBTotVec; + ///////////////////////////////////////////////////////////////// + + std::unordered_map useDetector = { + {"QvectorBTots", cfgUseBTot}, + {"QvectorBNegs", cfgUseBNeg}, + {"QvectorBPoss", cfgUseBPos}, + {"QvectorTPCalls", cfgUseTPCall}, + {"QvectorTPCnegs", cfgUseTPCneg}, + {"QvectorTPCposs", cfgUseTPCpos}, + {"QvectorFV0As", cfgUseFV0A}, + {"QvectorFT0Ms", cfgUseFT0M}, + {"QvectorFT0As", cfgUseFT0A}, + {"QvectorFT0Cs", cfgUseFT0C}}; + + void init(InitContext& initContext) { + // Check the sub-detector used + auto& workflows = initContext.services().get(); + for (DeviceSpec const& device : workflows.devices) { + for (auto const& input : device.inputs) { + if (input.matcher.binding == "Qvectors") { + for (auto det : useDetector) { + useDetector[det.first.data()] = true; + } + LOGF(info, "Using all detectors."); + goto allDetectorsInUse; // Added to break from nested loop if all detectors are in use. + } + for (auto det : useDetector) { + std::string table_name_with_vector = det.first; // for replacing s with Vecs at the end. + if (input.matcher.binding == det.first || input.matcher.binding == table_name_with_vector.replace(table_name_with_vector.size() - 1, 1, "Vecs")) { + useDetector[det.first.data()] = true; + LOGF(info, Form("Using detector: %s.", det.first.data())); + } + } + } + } + + // Exit point in case all detectors are being used. + allDetectorsInUse: // Setup the access to the CCDB objects of interest. ccdb->setURL(cfgCcdbParam.cfgURL); ccdb->setCaching(true); @@ -154,17 +212,18 @@ struct qVectorsTable { void initCCDB(aod::BCsWithTimestamps::iterator const& bc) { - cfgCorr.clear(); FT0RelGainConst.clear(); FV0RelGainConst.clear(); - cfgCorr = {}; FT0RelGainConst = {}; FV0RelGainConst = {}; + std::string fullPath; + auto timestamp = bc.timestamp(); + auto runnumber = bc.runNumber(); - auto offsetFT0 = ccdb->getForTimeStamp>("FT0/Calib/Align", timestamp); - auto offsetFV0 = ccdb->getForTimeStamp>("FV0/Calib/Align", timestamp); + auto offsetFT0 = getForTsOrRun>("FT0/Calib/Align", timestamp, runnumber); + auto offsetFV0 = getForTsOrRun>("FV0/Calib/Align", timestamp, runnumber); if (offsetFT0 != nullptr) { helperEP.SetOffsetFT0A((*offsetFT0)[0].getX(), (*offsetFT0)[0].getY()); @@ -180,145 +239,40 @@ struct qVectorsTable { LOGF(fatal, "Could not get the alignment parameters for FV0."); } - std::string fullPath; - if (cfgCCDBConst == 1) { + objQvec.clear(); + for (std::size_t i = 0; i < cfgnMods->size(); i++) { + int ind = cfgnMods->at(i); fullPath = cfgQvecCalibPath; - fullPath += "/FT0C"; - auto objft0c = ccdb->getForTimeStamp>(fullPath, timestamp); - if (!objft0c) { - if (cfgFT0CCorr->size() < 48) { - LOGF(fatal, "No proper correction factor assigned for FT0C"); - } else { - cfgCorr.push_back(cfgFT0CCorr); - } - } else { - cfgCorr.push_back(*(objft0c)); - } - - fullPath = cfgQvecCalibPath; - fullPath += "/FT0A"; - auto objft0a = ccdb->getForTimeStamp>(fullPath, timestamp); - if (!objft0a) { - if (cfgFT0ACorr->size() < 48) { - LOGF(fatal, "No proper correction factor assigned for FT0A"); - } else { - cfgCorr.push_back(cfgFT0ACorr); - } - } else { - cfgCorr.push_back(*(objft0a)); - } - - fullPath = cfgQvecCalibPath; - fullPath += "/FT0M"; - auto objft0m = ccdb->getForTimeStamp>(fullPath, timestamp); - if (!objft0m) { - if (cfgFT0MCorr->size() < 48) { - LOGF(fatal, "No proper correction factor assigned for FT0M"); - } else { - cfgCorr.push_back(cfgFT0MCorr); - } - } else { - cfgCorr.push_back(*(objft0m)); + fullPath += "/v"; + fullPath += std::to_string(ind); + auto objqvec = getForTsOrRun(fullPath, timestamp, runnumber); + if (!objqvec) { + fullPath = cfgQvecCalibPath; + fullPath += "/v2"; + objqvec = getForTsOrRun(fullPath, timestamp, runnumber); } - - fullPath = cfgQvecCalibPath; - fullPath += "/FV0A"; - auto objfv0a = ccdb->getForTimeStamp>(fullPath, timestamp); - if (!objfv0a) { - if (cfgFV0ACorr->size() < 48) { - LOGF(fatal, "No proper correction factor assigned for FV0A"); - } else { - cfgCorr.push_back(cfgFV0ACorr); - } - } else { - cfgCorr.push_back(*(objfv0a)); - } - - fullPath = cfgQvecCalibPath; - fullPath += "/BPos"; - auto objbpos = ccdb->getForTimeStamp>(fullPath, timestamp); - if (!objbpos) { - if (cfgBPosCorr->size() < 48) { - LOGF(fatal, "No proper correction factor assigned for BPos"); - } else { - cfgCorr.push_back(cfgBPosCorr); - } - } else { - cfgCorr.push_back(*(objbpos)); - } - - fullPath = cfgQvecCalibPath; - fullPath += "/BNeg"; - auto objbneg = ccdb->getForTimeStamp>(fullPath, timestamp); - if (!objbneg) { - if (cfgBNegCorr->size() < 48) { - LOGF(fatal, "No proper correction factor assigned for BNeg"); - } else { - cfgCorr.push_back(cfgBNegCorr); - } - } else { - cfgCorr.push_back(*(objbneg)); - } - } else if (cfgCCDBConst == 2) { - if (cfgFT0CCorr->size() < 48) { - LOGF(fatal, "No proper correction factor assigned for FT0C"); - } - if (cfgFT0ACorr->size() < 48) { - LOGF(fatal, "No proper correction factor assigned for FT0A"); - } - if (cfgFT0MCorr->size() < 48) { - LOGF(fatal, "No proper correction factor assigned for FT0M"); - } - if (cfgFV0ACorr->size() < 48) { - LOGF(fatal, "No proper correction factor assigned for FV0A"); - } - if (cfgBPosCorr->size() < 48) { - LOGF(fatal, "No proper correction factor assigned for positive TPC tracks"); - } - if (cfgBNegCorr->size() < 48) { - LOGF(fatal, "No proper correction factor assigned for negative TPC tracks"); - } // will be replaced with method that call constants from CCDB - - cfgCorr.push_back(cfgFT0CCorr); - cfgCorr.push_back(cfgFT0ACorr); - cfgCorr.push_back(cfgFT0MCorr); - cfgCorr.push_back(cfgFV0ACorr); - cfgCorr.push_back(cfgBPosCorr); - cfgCorr.push_back(cfgBNegCorr); + objQvec.push_back(objqvec); } - - if (cfgGainCor == 0) { - for (auto i{0u}; i < cfgFT0RelGain->size(); i++) { + fullPath = cfgGainEqPath; + fullPath += "/FT0"; + auto objft0Gain = getForTsOrRun>(fullPath, timestamp, runnumber); + if (!objft0Gain || cfgCorrLevel == 0) { + for (auto i{0u}; i < 208; i++) { FT0RelGainConst.push_back(1.); } - for (auto i{0u}; i < cfgFV0RelGain->size(); i++) { - FV0RelGainConst.push_back(1.); - } - } else if (cfgGainCor == 1) { - fullPath = cfgGainEqPath; - fullPath += "/FT0"; - auto objft0Gain = ccdb->getForTimeStamp>(fullPath, timestamp); - if (!objft0Gain) { - for (auto i{0u}; i < cfgFT0RelGain->size(); i++) { - FT0RelGainConst.push_back(1.); - } - } else { - FT0RelGainConst = *(objft0Gain); - } + } else { + FT0RelGainConst = *(objft0Gain); + } - fullPath = cfgGainEqPath; - fullPath += "/FV0"; - auto objfv0Gain = ccdb->getForTimeStamp>(fullPath, timestamp); - if (!objfv0Gain) { - for (auto i{0u}; i < cfgFV0RelGain->size(); i++) { - FV0RelGainConst.push_back(1.); - } - } else { - FV0RelGainConst = *(objfv0Gain); + fullPath = cfgGainEqPath; + fullPath += "/FV0"; + auto objfv0Gain = getForTsOrRun>(fullPath, timestamp, runnumber); + if (!objfv0Gain || cfgCorrLevel == 0) { + for (auto i{0u}; i < 48; i++) { + FV0RelGainConst.push_back(1.); } - } else if (cfgGainCor == 2) { - FT0RelGainConst = cfgFT0RelGain; - FV0RelGainConst = cfgFV0RelGain; + } else { + FV0RelGainConst = *(objfv0Gain); } } @@ -347,110 +301,90 @@ struct qVectorsTable { return true; } - void process(MyCollisions::iterator const& coll, aod::BCsWithTimestamps const&, aod::FT0s const&, aod::FV0As const&, MyTracks const& tracks) + /// Function to get corrections from CCDB eithr using the timestamp or the runnumber + /// \param fullPath is the path to correction in CCDB + /// \param timestamp is the collision timestamp + /// \param runNumber is the collision run number + /// \return CCDB correction + template + CorrectionType* getForTsOrRun(std::string const& fullPath, int64_t timestamp, int runNumber) { - - std::vector TrkBPosLabel{}; - std::vector TrkBNegLabel{}; - std::vector qvecRe{}; - std::vector qvecIm{}; - std::vector qvecAmp{}; - - auto bc = coll.bc_as(); - int currentRun = bc.runNumber(); - if (runNumber != currentRun) { - initCCDB(bc); - runNumber = currentRun; - } - - // Get the centrality value for all subscribed estimators and takes the one - // corresponding to cfgCentEsti. Reject also the events with invalid values. - // NOTE: centFDDM and centNTPV not implemented as it makes the compilation crashes... - float centAllEstim[4] = { - coll.centFT0M(), coll.centFT0A(), coll.centFT0C(), - coll.centFV0A()}; - float cent = centAllEstim[cfgCentEsti]; - if (cent < 0. || cent > 100.) { - cent = 110.; + if (useCorrectionForRun) { + return ccdb->getForRun(fullPath, runNumber); + } else { + return ccdb->getForTimeStamp(fullPath, timestamp); } + } - // Calculate the Q-vectors values for this event. - // TODO: Add here qVect for other detectors,... - float qVectFT0A[2] = {0.}; // Real and imaginary parts of the Q-vector in FT0A. - float qVectFT0C[2] = {0.}; // Real and imaginary parts of the Q-vector in FT0C. + template + void CalQvec(const Nmode nmode, const CollType& coll, const TrackType& track, std::vector& QvecRe, std::vector& QvecIm, std::vector& QvecAmp, std::vector& TrkTPCposLabel, std::vector& TrkTPCnegLabel, std::vector& TrkTPCallLabel) + { + float qVectFT0A[2] = {0.}; + float qVectFT0C[2] = {0.}; float qVectFT0M[2] = {0.}; - float qVectFV0A[2] = {0.}; // Real and imaginary parts of the Q-vector in FV0A. + float qVectFV0A[2] = {0.}; + float qVectTPCpos[2] = {0.}; + float qVectTPCneg[2] = {0.}; + float qVectTPCall[2] = {0.}; - float qVectBPos[2] = {0.}; - float qVectBNeg[2] = {0.}; - - TComplex QvecDet(0); // Complex value of the Q-vector for any detector. + TComplex QvecDet(0); TComplex QvecFT0M(0); - float sumAmplFT0A = 0.; // Sum of the amplitudes of all non-dead channels in any detector. + float sumAmplFT0A = 0.; float sumAmplFT0C = 0.; float sumAmplFT0M = 0.; float sumAmplFV0A = 0.; - /// First check if the collision has a found FT0. If yes, calculate the - /// Q-vectors for FT0A and FT0C (both real and imaginary parts). If no, - /// attribute dummy values to the corresponding qVect. - if (coll.has_foundFT0()) { + if (coll.has_foundFT0() && (useDetector["QvectorFT0As"] || useDetector["QvectorFT0Cs"] || useDetector["QvectorFT0Ms"])) { auto ft0 = coll.foundFT0(); - // Iterate over the non-dead channels for FT0-A to get the total Q-vector - // and sum of amplitudes. - for (std::size_t iChA = 0; iChA < ft0.channelA().size(); iChA++) { - // Get first the corresponding amplitude. - float ampl = ft0.amplitudeA()[iChA]; - int FT0AchId = ft0.channelA()[iChA]; - - histosQA.fill(HIST("FT0Amp"), ampl, FT0AchId); - histosQA.fill(HIST("FT0AmpCor"), ampl / FT0RelGainConst[FT0AchId], FT0AchId); - // Update the Q-vector and sum of amplitudes using the helper function. - // LOKI: Note this assumes nHarmo = 2!! Likely generalise in the future. - helperEP.SumQvectors(0, FT0AchId, ampl / FT0RelGainConst[FT0AchId], cfgnMod, QvecDet, sumAmplFT0A, ft0geom, fv0geom); - helperEP.SumQvectors(0, FT0AchId, ampl / FT0RelGainConst[FT0AchId], cfgnMod, QvecFT0M, sumAmplFT0M, ft0geom, fv0geom); - } // Go to the next channel iChA. - - // Set the Qvectors for FT0A with the normalised Q-vector values if the sum of - // amplitudes is non-zero. Otherwise, set it to a dummy 999. - if (sumAmplFT0A > 1e-8) { - QvecDet /= sumAmplFT0A; - qVectFT0A[0] = QvecDet.Re(); - qVectFT0A[1] = QvecDet.Im(); - // printf("qVectFT0A[0] = %.2f ; qVectFT0A[1] = %.2f \n", qVectFT0A[0], qVectFT0A[1]); // Debug printing. + if (useDetector["QvectorFT0As"]) { + for (std::size_t iChA = 0; iChA < ft0.channelA().size(); iChA++) { + float ampl = ft0.amplitudeA()[iChA]; + int FT0AchId = ft0.channelA()[iChA]; + + histosQA.fill(HIST("FT0Amp"), ampl, FT0AchId); + histosQA.fill(HIST("FT0AmpCor"), ampl / FT0RelGainConst[FT0AchId], FT0AchId); + + helperEP.SumQvectors(0, FT0AchId, ampl / FT0RelGainConst[FT0AchId], nmode, QvecDet, sumAmplFT0A, ft0geom, fv0geom); + helperEP.SumQvectors(0, FT0AchId, ampl / FT0RelGainConst[FT0AchId], nmode, QvecFT0M, sumAmplFT0M, ft0geom, fv0geom); + } + if (sumAmplFT0A > 1e-8) { + QvecDet /= sumAmplFT0A; + qVectFT0A[0] = QvecDet.Re(); + qVectFT0A[1] = QvecDet.Im(); + } } else { qVectFT0A[0] = 999.; qVectFT0A[1] = 999.; } - // Repeat the procedure with FT0-C for the found FT0. - // Start by resetting to zero the intermediate quantities. - QvecDet = TComplex(0., 0.); - for (std::size_t iChC = 0; iChC < ft0.channelC().size(); iChC++) { - // iChC ranging from 0 to max 112. We need to add 96 (= max channels in FT0-A) - // to ensure a proper channel number in FT0 as a whole. - float ampl = ft0.amplitudeC()[iChC]; - int FT0CchId = ft0.channelC()[iChC] + 96; + if (useDetector["QvectorFT0Cs"]) { + QvecDet = TComplex(0., 0.); + for (std::size_t iChC = 0; iChC < ft0.channelC().size(); iChC++) { + float ampl = ft0.amplitudeC()[iChC]; + int FT0CchId = ft0.channelC()[iChC] + 96; - histosQA.fill(HIST("FT0Amp"), ampl, FT0CchId); - histosQA.fill(HIST("FT0AmpCor"), ampl / FT0RelGainConst[FT0CchId], FT0CchId); + histosQA.fill(HIST("FT0Amp"), ampl, FT0CchId); + histosQA.fill(HIST("FT0AmpCor"), ampl / FT0RelGainConst[FT0CchId], FT0CchId); - helperEP.SumQvectors(0, FT0CchId, ampl / FT0RelGainConst[FT0CchId], cfgnMod, QvecDet, sumAmplFT0C, ft0geom, fv0geom); - helperEP.SumQvectors(0, FT0CchId, ampl / FT0RelGainConst[FT0CchId], cfgnMod, QvecFT0M, sumAmplFT0M, ft0geom, fv0geom); - } + helperEP.SumQvectors(0, FT0CchId, ampl / FT0RelGainConst[FT0CchId], nmode, QvecDet, sumAmplFT0C, ft0geom, fv0geom); + helperEP.SumQvectors(0, FT0CchId, ampl / FT0RelGainConst[FT0CchId], nmode, QvecFT0M, sumAmplFT0M, ft0geom, fv0geom); + } - if (sumAmplFT0C > 1e-8) { - QvecDet /= sumAmplFT0C; - qVectFT0C[0] = QvecDet.Re(); - qVectFT0C[1] = QvecDet.Im(); - // printf("qVectFT0C[0] = %.2f ; qVectFT0C[1] = %.2f \n", qVectFT0C[0], qVectFT0C[1]); // Debug printing. + if (sumAmplFT0C > 1e-8) { + QvecDet /= sumAmplFT0C; + qVectFT0C[0] = QvecDet.Re(); + qVectFT0C[1] = QvecDet.Im(); + } else { + qVectFT0C[0] = 999.; + qVectFT0C[1] = 999.; + } } else { - qVectFT0C[0] = 999.; - qVectFT0C[1] = 999.; + qVectFT0C[0] = -999.; + qVectFT0C[1] = -999.; } - if (sumAmplFT0M > 1e-8) { + if (sumAmplFT0M > 1e-8 && useDetector["QvectorFT0Ms"]) { QvecFT0M /= sumAmplFT0M; qVectFT0M[0] = QvecFT0M.Re(); qVectFT0M[1] = QvecFT0M.Im(); @@ -469,7 +403,7 @@ struct qVectorsTable { QvecDet = TComplex(0., 0.); sumAmplFV0A = 0; - if (coll.has_foundFV0()) { + if (coll.has_foundFV0() && useDetector["QvectorFV0As"]) { auto fv0 = coll.foundFV0(); for (std::size_t iCh = 0; iCh < fv0.channel().size(); iCh++) { @@ -478,14 +412,13 @@ struct qVectorsTable { histosQA.fill(HIST("FV0Amp"), ampl, FV0AchId); histosQA.fill(HIST("FV0AmpCor"), ampl / FV0RelGainConst[FV0AchId], FV0AchId); - helperEP.SumQvectors(1, FV0AchId, ampl / FV0RelGainConst[FV0AchId], cfgnMod, QvecDet, sumAmplFV0A, ft0geom, fv0geom); + helperEP.SumQvectors(1, FV0AchId, ampl / FV0RelGainConst[FV0AchId], nmode, QvecDet, sumAmplFV0A, ft0geom, fv0geom); } if (sumAmplFV0A > 1e-8) { QvecDet /= sumAmplFV0A; qVectFV0A[0] = QvecDet.Re(); qVectFV0A[1] = QvecDet.Im(); - // printf("qVectFV0[0] = %.2f ; qVectFV0[1] = %.2f \n", qVectFV0[0], qVectFV0[1]); // Debug printing. } else { qVectFV0A[0] = 999.; qVectFV0A[1] = 999.; @@ -495,101 +428,214 @@ struct qVectorsTable { qVectFV0A[1] = -999.; } - int nTrkBPos = 0; - int nTrkBNeg = 0; + int nTrkTPCpos = 0; + int nTrkTPCneg = 0; + int nTrkTPCall = 0; - for (auto& trk : tracks) { + for (auto& trk : track) { if (!SelTrack(trk)) { continue; } histosQA.fill(HIST("ChTracks"), trk.pt(), trk.eta(), trk.phi(), cent); - if (std::abs(trk.eta()) < 0.1 || std::abs(trk.eta()) > 0.8) { + if (std::abs(trk.eta()) > 0.8) { continue; } - if (trk.eta() > 0) { - qVectBPos[0] += trk.pt() * std::cos(trk.phi() * cfgnMod); - qVectBPos[1] += trk.pt() * std::sin(trk.phi() * cfgnMod); - TrkBPosLabel.push_back(trk.globalIndex()); - nTrkBPos++; - } else if (trk.eta() < 0) { - qVectBNeg[0] += trk.pt() * std::cos(trk.phi() * cfgnMod); - qVectBNeg[1] += trk.pt() * std::sin(trk.phi() * cfgnMod); - TrkBNegLabel.push_back(trk.globalIndex()); - nTrkBNeg++; + qVectTPCall[0] += trk.pt() * std::cos(trk.phi() * nmode); + qVectTPCall[1] += trk.pt() * std::sin(trk.phi() * nmode); + TrkTPCallLabel.push_back(trk.globalIndex()); + nTrkTPCall++; + if (std::abs(trk.eta()) < 0.1) { + continue; + } + if (trk.eta() > 0 && (useDetector["QvectorTPCposs"] || useDetector["QvectorBPoss"])) { + qVectTPCpos[0] += trk.pt() * std::cos(trk.phi() * nmode); + qVectTPCpos[1] += trk.pt() * std::sin(trk.phi() * nmode); + TrkTPCposLabel.push_back(trk.globalIndex()); + nTrkTPCpos++; + } else if (trk.eta() < 0 && (useDetector["QvectorTPCnegs"] || useDetector["QvectorBNegs"])) { + qVectTPCneg[0] += trk.pt() * std::cos(trk.phi() * nmode); + qVectTPCneg[1] += trk.pt() * std::sin(trk.phi() * nmode); + TrkTPCnegLabel.push_back(trk.globalIndex()); + nTrkTPCneg++; } } - - if (nTrkBPos > 0) { - qVectBPos[0] /= nTrkBPos; - qVectBPos[1] /= nTrkBPos; + if (nTrkTPCpos > 0) { + qVectTPCpos[0] /= nTrkTPCpos; + qVectTPCpos[1] /= nTrkTPCpos; } else { - qVectBPos[0] = 999.; - qVectBPos[1] = 999.; + qVectTPCpos[0] = 999.; + qVectTPCpos[1] = 999.; } - if (nTrkBNeg > 0) { - qVectBNeg[0] /= nTrkBNeg; - qVectBNeg[1] /= nTrkBNeg; + if (nTrkTPCneg > 0) { + qVectTPCneg[0] /= nTrkTPCneg; + qVectTPCneg[1] /= nTrkTPCneg; } else { - qVectBNeg[0] = 999.; - qVectBNeg[1] = 999.; + qVectTPCneg[0] = 999.; + qVectTPCneg[1] = 999.; } - int cBin = helperEP.GetCentBin(cent); + if (nTrkTPCall > 0) { + qVectTPCall[0] /= nTrkTPCall; + qVectTPCall[1] /= nTrkTPCall; + } else { + qVectTPCall[0] = 999.; + qVectTPCall[1] = 999.; + } for (auto i{0u}; i < 4; i++) { - qvecRe.push_back(qVectFT0C[0]); - qvecIm.push_back(qVectFT0C[1]); + QvecRe.push_back(qVectFT0C[0]); + QvecIm.push_back(qVectFT0C[1]); + } + for (auto i{0u}; i < 4; i++) { + QvecRe.push_back(qVectFT0A[0]); + QvecIm.push_back(qVectFT0A[1]); } for (auto i{0u}; i < 4; i++) { - qvecRe.push_back(qVectFT0A[0]); - qvecIm.push_back(qVectFT0A[1]); + QvecRe.push_back(qVectFT0M[0]); + QvecIm.push_back(qVectFT0M[1]); } for (auto i{0u}; i < 4; i++) { - qvecRe.push_back(qVectFT0M[0]); - qvecIm.push_back(qVectFT0M[1]); + QvecRe.push_back(qVectFV0A[0]); + QvecIm.push_back(qVectFV0A[1]); } for (auto i{0u}; i < 4; i++) { - qvecRe.push_back(qVectFV0A[0]); - qvecIm.push_back(qVectFV0A[1]); + QvecRe.push_back(qVectTPCpos[0]); + QvecIm.push_back(qVectTPCpos[1]); } for (auto i{0u}; i < 4; i++) { - qvecRe.push_back(qVectBPos[0]); - qvecIm.push_back(qVectBPos[1]); + QvecRe.push_back(qVectTPCneg[0]); + QvecIm.push_back(qVectTPCneg[1]); } for (auto i{0u}; i < 4; i++) { - qvecRe.push_back(qVectBNeg[0]); - qvecIm.push_back(qVectBNeg[1]); + QvecRe.push_back(qVectTPCall[0]); + QvecIm.push_back(qVectTPCall[1]); } - qvecAmp.push_back(sumAmplFT0C); - qvecAmp.push_back(sumAmplFT0A); - qvecAmp.push_back(sumAmplFT0M); - qvecAmp.push_back(sumAmplFV0A); - qvecAmp.push_back(static_cast(nTrkBPos)); - qvecAmp.push_back(static_cast(nTrkBNeg)); + QvecAmp.push_back(sumAmplFT0C); + QvecAmp.push_back(sumAmplFT0A); + QvecAmp.push_back(sumAmplFT0M); + QvecAmp.push_back(sumAmplFV0A); + QvecAmp.push_back(static_cast(nTrkTPCpos)); + QvecAmp.push_back(static_cast(nTrkTPCneg)); + QvecAmp.push_back(static_cast(nTrkTPCall)); + } + + void process(MyCollisions::iterator const& coll, aod::BCsWithTimestamps const&, aod::FT0s const&, aod::FV0As const&, MyTracks const& tracks) + { + std::vector TrkTPCposLabel{}; + std::vector TrkTPCnegLabel{}; + std::vector TrkTPCallLabel{}; + std::vector qvecRe{}; + std::vector qvecIm{}; + std::vector qvecAmp{}; - if (cBin != -1) { - for (auto i{0u}; i < 6; i++) { - helperEP.DoRecenter(qvecRe[i * 4 + 1], qvecIm[i * 4 + 1], cfgCorr[i][cBin * 6], cfgCorr[i][cBin * 6 + 1]); + std::vector qvecReFT0C{}; + std::vector qvecImFT0C{}; + std::vector qvecReFT0A{}; + std::vector qvecImFT0A{}; + std::vector qvecReFT0M{}; + std::vector qvecImFT0M{}; + std::vector qvecReFV0A{}; + std::vector qvecImFV0A{}; + std::vector qvecReTPCpos{}; + std::vector qvecImTPCpos{}; + std::vector qvecReTPCneg{}; + std::vector qvecImTPCneg{}; + std::vector qvecReTPCall{}; + std::vector qvecImTPCall{}; - helperEP.DoRecenter(qvecRe[i * 4 + 2], qvecIm[i * 4 + 2], cfgCorr[i][cBin * 6], cfgCorr[i][cBin * 6 + 1]); - helperEP.DoTwist(qvecRe[i * 4 + 2], qvecIm[i * 4 + 2], cfgCorr[i][cBin * 6 + 2], cfgCorr[i][cBin * 6 + 3]); + auto bc = coll.bc_as(); + int currentRun = bc.runNumber(); + if (runNumber != currentRun) { + initCCDB(bc); + runNumber = currentRun; + } - helperEP.DoRecenter(qvecRe[i * 4 + 3], qvecIm[i * 4 + 3], cfgCorr[i][cBin * 6], cfgCorr[i][cBin * 6 + 1]); - helperEP.DoTwist(qvecRe[i * 4 + 3], qvecIm[i * 4 + 3], cfgCorr[i][cBin * 6 + 2], cfgCorr[i][cBin * 6 + 3]); - helperEP.DoRescale(qvecRe[i * 4 + 3], qvecIm[i * 4 + 3], cfgCorr[i][cBin * 6 + 4], cfgCorr[i][cBin * 6 + 5]); + float centAllEstim[4] = { + coll.centFT0M(), coll.centFT0A(), coll.centFT0C(), + coll.centFV0A()}; + cent = centAllEstim[cfgCentEsti]; + bool IsCalibrated = true; + if (cent < 0. || cent > cfgMaxCentrality) { + cent = 110.; + IsCalibrated = false; + } + for (std::size_t id = 0; id < cfgnMods->size(); id++) { + int ind = cfgnMods->at(id); + CalQvec(ind, coll, tracks, qvecRe, qvecIm, qvecAmp, TrkTPCposLabel, TrkTPCnegLabel, TrkTPCallLabel); + if (cent < cfgMaxCentrality) { + for (auto i{0u}; i < kTPCall + 1; i++) { + helperEP.DoRecenter(qvecRe[(kTPCall + 1) * 4 * id + i * 4 + 1], qvecIm[(kTPCall + 1) * 4 * id + i * 4 + 1], + objQvec.at(id)->GetBinContent(static_cast(cent) + 1, 1, i + 1), objQvec.at(id)->GetBinContent(static_cast(cent) + 1, 2, i + 1)); + + helperEP.DoRecenter(qvecRe[(kTPCall + 1) * 4 * id + i * 4 + 2], qvecIm[(kTPCall + 1) * 4 * id + i * 4 + 2], + objQvec.at(id)->GetBinContent(static_cast(cent) + 1, 1, i + 1), objQvec.at(id)->GetBinContent(static_cast(cent) + 1, 2, i + 1)); + helperEP.DoTwist(qvecRe[(kTPCall + 1) * 4 * id + i * 4 + 2], qvecIm[(kTPCall + 1) * 4 * id + i * 4 + 2], + objQvec.at(id)->GetBinContent(static_cast(cent) + 1, 3, i + 1), objQvec.at(id)->GetBinContent(static_cast(cent) + 1, 4, i + 1)); + + helperEP.DoRecenter(qvecRe[(kTPCall + 1) * 4 * id + i * 4 + 3], qvecIm[(kTPCall + 1) * 4 * id + i * 4 + 3], + objQvec.at(id)->GetBinContent(static_cast(cent) + 1, 1, i + 1), objQvec.at(id)->GetBinContent(static_cast(cent) + 1, 2, i + 1)); + helperEP.DoTwist(qvecRe[(kTPCall + 1) * 4 * id + i * 4 + 3], qvecIm[(kTPCall + 1) * 4 * id + i * 4 + 3], + objQvec.at(id)->GetBinContent(static_cast(cent) + 1, 3, i + 1), objQvec.at(id)->GetBinContent(static_cast(cent) + 1, 4, i + 1)); + helperEP.DoRescale(qvecRe[(kTPCall + 1) * 4 * id + i * 4 + 3], qvecIm[(kTPCall + 1) * 4 * id + i * 4 + 3], + objQvec.at(id)->GetBinContent(static_cast(cent) + 1, 5, i + 1), objQvec.at(id)->GetBinContent(static_cast(cent) + 1, 6, i + 1)); + } } + int CorrLevel = cfgCorrLevel == 0 ? 0 : cfgCorrLevel - 1; + qvecReFT0C.push_back(qvecRe[(kTPCall + 1) * 4 * id + kFT0C * 4 + CorrLevel]); + qvecImFT0C.push_back(qvecIm[(kTPCall + 1) * 4 * id + kFT0C * 4 + CorrLevel]); + qvecReFT0A.push_back(qvecRe[(kTPCall + 1) * 4 * id + kFT0A * 4 + CorrLevel]); + qvecImFT0A.push_back(qvecIm[(kTPCall + 1) * 4 * id + kFT0A * 4 + CorrLevel]); + qvecReFT0M.push_back(qvecRe[(kTPCall + 1) * 4 * id + kFT0M * 4 + CorrLevel]); + qvecImFT0M.push_back(qvecIm[(kTPCall + 1) * 4 * id + kFT0M * 4 + CorrLevel]); + qvecReFV0A.push_back(qvecRe[(kTPCall + 1) * 4 * id + kFV0A * 4 + CorrLevel]); + qvecImFV0A.push_back(qvecIm[(kTPCall + 1) * 4 * id + kFV0A * 4 + CorrLevel]); + qvecReTPCpos.push_back(qvecRe[(kTPCall + 1) * 4 * id + kTPCpos * 4 + CorrLevel]); + qvecImTPCpos.push_back(qvecIm[(kTPCall + 1) * 4 * id + kTPCpos * 4 + CorrLevel]); + qvecReTPCneg.push_back(qvecRe[(kTPCall + 1) * 4 * id + kTPCneg * 4 + CorrLevel]); + qvecImTPCneg.push_back(qvecIm[(kTPCall + 1) * 4 * id + kTPCneg * 4 + CorrLevel]); + qvecReTPCall.push_back(qvecRe[(kTPCall + 1) * 4 * id + kTPCall * 4 + CorrLevel]); + qvecImTPCall.push_back(qvecIm[(kTPCall + 1) * 4 * id + kTPCall * 4 + CorrLevel]); } // Fill the columns of the Qvectors table. - qVector(cent, cBin, qvecRe, qvecIm, qvecAmp); - qVectorFT0C(cBin, qvecRe[kFT0C * 4 + 3], qvecIm[kFT0C * 4 + 3], sumAmplFT0C); - qVectorFT0A(cBin, qvecRe[kFT0A * 4 + 3], qvecIm[kFT0A * 4 + 3], sumAmplFT0A); - qVectorFT0M(cBin, qvecRe[kFT0M * 4 + 3], qvecIm[kFT0M * 4 + 3], sumAmplFT0M); - qVectorFV0A(cBin, qvecRe[kFV0A * 4 + 3], qvecIm[kFV0A * 4 + 3], sumAmplFV0A); - qVectorBPos(cBin, qvecRe[kBPos * 4 + 3], qvecIm[kBPos * 4 + 3], nTrkBPos, TrkBPosLabel); - qVectorBNeg(cBin, qvecRe[kBNeg * 4 + 3], qvecIm[kBNeg * 4 + 3], nTrkBNeg, TrkBNegLabel); + qVector(cent, IsCalibrated, qvecRe, qvecIm, qvecAmp); + if (useDetector["QvectorFT0Cs"]) + qVectorFT0C(IsCalibrated, qvecReFT0C.at(0), qvecImFT0C.at(0), qvecAmp[kFT0C]); + if (useDetector["QvectorFT0As"]) + qVectorFT0A(IsCalibrated, qvecReFT0A.at(0), qvecImFT0A.at(0), qvecAmp[kFT0A]); + if (useDetector["QvectorFT0Ms"]) + qVectorFT0M(IsCalibrated, qvecReFT0M.at(0), qvecImFT0M.at(0), qvecAmp[kFT0M]); + if (useDetector["QvectorFV0As"]) + qVectorFV0A(IsCalibrated, qvecReFV0A.at(0), qvecImFV0A.at(0), qvecAmp[kFV0A]); + if (useDetector["QvectorTPCposs"]) + qVectorTPCpos(IsCalibrated, qvecReTPCpos.at(0), qvecImTPCpos.at(0), qvecAmp[kTPCpos], TrkTPCposLabel); + if (useDetector["QvectorTPCnegs"]) + qVectorTPCneg(IsCalibrated, qvecReTPCneg.at(0), qvecImTPCneg.at(0), qvecAmp[kTPCneg], TrkTPCnegLabel); + if (useDetector["QvectorTPCalls"]) + qVectorTPCall(IsCalibrated, qvecReTPCall.at(0), qvecImTPCall.at(0), qvecAmp[kTPCall], TrkTPCallLabel); + + qVectorFT0CVec(IsCalibrated, qvecReFT0C, qvecImFT0C, qvecAmp[kFT0C]); + qVectorFT0AVec(IsCalibrated, qvecReFT0A, qvecImFT0A, qvecAmp[kFT0A]); + qVectorFT0MVec(IsCalibrated, qvecReFT0M, qvecImFT0M, qvecAmp[kFT0M]); + qVectorFV0AVec(IsCalibrated, qvecReFV0A, qvecImFV0A, qvecAmp[kFV0A]); + qVectorTPCposVec(IsCalibrated, qvecReTPCpos, qvecImTPCpos, qvecAmp[kTPCpos], TrkTPCposLabel); + qVectorTPCnegVec(IsCalibrated, qvecReTPCneg, qvecImTPCneg, qvecAmp[kTPCneg], TrkTPCnegLabel); + qVectorTPCallVec(IsCalibrated, qvecReTPCall, qvecImTPCall, qvecAmp[kTPCall], TrkTPCallLabel); + + // Deprecated, will be removed in future after transition time // + if (useDetector["QvectorBPoss"]) + qVectorBPos(IsCalibrated, qvecReTPCpos.at(0), qvecImTPCpos.at(0), qvecAmp[kTPCpos], TrkTPCposLabel); + if (useDetector["QvectorBNegs"]) + qVectorBNeg(IsCalibrated, qvecReTPCneg.at(0), qvecImTPCneg.at(0), qvecAmp[kTPCneg], TrkTPCnegLabel); + if (useDetector["QvectorBTots"]) + qVectorBTot(IsCalibrated, qvecReTPCall.at(0), qvecImTPCall.at(0), qvecAmp[kTPCall], TrkTPCallLabel); + + qVectorBPosVec(IsCalibrated, qvecReTPCpos, qvecImTPCpos, qvecAmp[kTPCpos], TrkTPCposLabel); + qVectorBNegVec(IsCalibrated, qvecReTPCneg, qvecImTPCneg, qvecAmp[kTPCneg], TrkTPCnegLabel); + qVectorBTotVec(IsCalibrated, qvecReTPCall, qvecImTPCall, qvecAmp[kTPCall], TrkTPCallLabel); + ///////////////////////////////////////////////////////////////// } // End process. }; diff --git a/Common/TableProducer/timestamp.cxx b/Common/TableProducer/timestamp.cxx index 98a6fb6bc15..e3d37f7129b 100644 --- a/Common/TableProducer/timestamp.cxx +++ b/Common/TableProducer/timestamp.cxx @@ -23,25 +23,31 @@ #include "CCDB/BasicCCDBManager.h" #include "CommonDataFormat/InteractionRecord.h" #include "DetectorsRaw/HBFUtils.h" +#include "MetadataHelper.h" using namespace o2::framework; using namespace o2::header; using namespace o2; +MetadataHelper metadataInfo; // Metadata helper + struct TimestampTask { Produces timestampTable; /// Table with SOR timestamps produced by the task Service ccdb; /// CCDB manager to access orbit-reset timestamp o2::ccdb::CcdbApi ccdb_api; /// API to access CCDB headers + Configurable fatalOnInvalidTimestamp{"fatalOnInvalidTimestamp", false, "Generate fatal error for invalid timestamps"}; std::map mapRunToOrbitReset; /// Cache of orbit reset timestamps + std::map> mapRunToRunDuration; /// Cache of run duration timestamps int lastRunNumber = 0; /// Last run number processed int64_t orbitResetTimestamp = 0; /// Orbit-reset timestamp in us + std::pair runDuration; /// Pair of SOR and EOR timestamps // Configurables Configurable verbose{"verbose", false, "verbose mode"}; Configurable rct_path{"rct-path", "RCT/Info/RunInformation", "path to the ccdb RCT objects for the SOR timestamps"}; Configurable orbit_reset_path{"orbit-reset-path", "CTP/Calib/OrbitReset", "path to the ccdb orbit-reset objects"}; Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "URL of the CCDB database"}; - Configurable isRun2MC{"isRun2MC", false, "Running mode: enable only for Run 2 MC. Timestamps are set to SOR timestamp"}; + Configurable isRun2MC{"isRun2MC", -1, "Running mode: enable only for Run 2 MC. Timestamps are set to SOR timestamp. Default: -1 (autoset from metadata) 0 (Standard) 1 (Run 2 MC)"}; void init(o2::framework::InitContext&) { @@ -51,6 +57,14 @@ struct TimestampTask { if (!ccdb_api.isHostReachable()) { LOGF(fatal, "CCDB host %s is not reacheable, cannot go forward", url.value.data()); } + if (isRun2MC.value == -1) { + if ((!metadataInfo.isRun3()) && metadataInfo.isMC()) { + isRun2MC.value = 1; + LOG(info) << "Autosetting the Run2 MC mode based on metadata"; + } else { + isRun2MC.value = 0; + } + } } void process(aod::BC const& bc) @@ -64,23 +78,15 @@ struct TimestampTask { } else if (mapRunToOrbitReset.count(runNumber)) { // The run number was already requested before: getting it from cache! LOGF(debug, "Getting orbit-reset timestamp from cache"); orbitResetTimestamp = mapRunToOrbitReset[runNumber]; + runDuration = mapRunToRunDuration[runNumber]; } else { // The run was not requested before: need to acccess CCDB! LOGF(debug, "Getting start-of-run and end-of-run timestamps from CCDB"); - std::map metadata, headers; - const std::string run_path = Form("%s/%i", rct_path.value.data(), runNumber); - headers = ccdb_api.retrieveHeaders(run_path, metadata, -1); - if (headers.count("SOR") == 0) { - LOGF(fatal, "Cannot find start-of-run timestamp for run number in path '%s'.", run_path.data()); - } - if (headers.count("EOR") == 0) { - LOGF(fatal, "Cannot find end-of-run timestamp for run number in path '%s'.", run_path.data()); - } + runDuration = ccdb->getRunDuration(runNumber, true); /// fatalise if timestamps are not found + int64_t sorTimestamp = runDuration.first; // timestamp of the SOR/SOX/STF in ms + int64_t eorTimestamp = runDuration.second; // timestamp of the EOR/EOX/ETF in ms - int64_t sorTimestamp = atol(headers["SOR"].c_str()); // timestamp of the SOR in ms - int64_t eorTimestamp = atol(headers["EOR"].c_str()); // timestamp of the EOR in ms - - bool isUnanchoredRun3MC = runNumber >= 300000 && runNumber < 500000; - if (isRun2MC || isUnanchoredRun3MC) { + const bool isUnanchoredRun3MC = runNumber >= 300000 && runNumber < 500000; + if (isRun2MC.value == 1 || isUnanchoredRun3MC) { // isRun2MC: bc/orbit distributions are not simulated in Run2 MC. All bcs are set to 0. // isUnanchoredRun3MC: assuming orbit-reset is done in the beginning of each run // Setting orbit-reset timestamp to start-of-run timestamp @@ -92,7 +98,7 @@ struct TimestampTask { } else { // sometimes orbit is reset after SOR. Using EOR timestamps for orbitReset query is more reliable LOGF(debug, "Getting orbit-reset timestamp using end-of-run timestamp from CCDB"); - auto ctp = ccdb->getForTimeStamp>(orbit_reset_path.value.data(), eorTimestamp); + auto ctp = ccdb->getForTimeStamp>(orbit_reset_path.value.data(), eorTimestamp / 2 + sorTimestamp / 2); orbitResetTimestamp = (*ctp)[0]; } @@ -102,18 +108,29 @@ struct TimestampTask { if (!check.second) { LOGF(fatal, "Run number %i already existed with a orbit-reset timestamp of %llu", runNumber, check.first->second); } - LOGF(info, "Add new run number %i with orbit-reset timestamp %llu to cache", runNumber, orbitResetTimestamp); + mapRunToRunDuration[runNumber] = runDuration; + LOGF(info, "Add new run number %i with orbit-reset timestamp %llu, SOR: %llu, EOR: %llu to cache", runNumber, orbitResetTimestamp, runDuration.first, runDuration.second); } if (verbose.value) { LOGF(info, "Orbit-reset timestamp for run number %i found: %llu us", runNumber, orbitResetTimestamp); } - - timestampTable((orbitResetTimestamp + int64_t(bc.globalBC() * o2::constants::lhc::LHCBunchSpacingNS * 1e-3)) / 1000); // us -> ms + int64_t timestamp{(orbitResetTimestamp + int64_t(bc.globalBC() * o2::constants::lhc::LHCBunchSpacingNS * 1e-3)) / 1000}; // us -> ms + if (timestamp < runDuration.first || timestamp > runDuration.second) { + if (fatalOnInvalidTimestamp.value) { + LOGF(fatal, "Timestamp %llu us is out of run duration [%llu, %llu] ms", timestamp, runDuration.first, runDuration.second); + } else { + LOGF(debug, "Timestamp %llu us is out of run duration [%llu, %llu] ms", timestamp, runDuration.first, runDuration.second); + } + } + timestampTable(timestamp); } }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { + // Parse the metadata + metadataInfo.initMetadata(cfgc); + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/Common/TableProducer/trackPropagation.cxx b/Common/TableProducer/trackPropagation.cxx index c20790016c1..073533a191c 100644 --- a/Common/TableProducer/trackPropagation.cxx +++ b/Common/TableProducer/trackPropagation.cxx @@ -38,6 +38,8 @@ struct TrackPropagation { Produces tracksDCA; Produces tracksDCACov; + Produces tunertable; + Service ccdb; bool fillTracksDCA = false; @@ -58,12 +60,20 @@ struct TrackPropagation { Configurable mVtxPath{"mVtxPath", "GLO/Calib/MeanVertex", "Path of the mean vertex file"}; Configurable minPropagationRadius{"minPropagationDistance", o2::constants::geom::XTPCInnerRef + 0.1, "Only tracks which are at a smaller radius will be propagated, defaults to TPC inner wall"}; // for TrackTuner only (MC smearing) - Configurable useTrackTuner{"useTrackTuner", false, "Apply Improver/DCA corrections to MC"}; - Configurable trackTunerParams{"trackTunerParams", "debugInfo=0|updateTrackCovMat=1|updateCurvature=0|updatePulls=0|isInputFileFromCCDB=1|pathInputFile=Users/m/mfaggin/test/inputsTrackTuner/PbPb2022|nameInputFile=trackTuner_DataLHC22sPass5_McLHC22l1b2_run529397.root|usePvRefitCorrections=0|oneOverPtCurrent=0|oneOverPtUpgr=0", "TrackTuner parameter initialization (format: =|=)"}; - OutputObj trackTunedTracks{TH1D("trackTunedTracks", "", 4, 0.5, 4.5), OutputObjHandlingPolicy::AnalysisObject}; + Configurable useTrackTuner{"useTrackTuner", false, "Apply track tuner corrections to MC"}; + Configurable fillTrackTunerTable{"fillTrackTunerTable", false, "flag to fill track tuner table"}; + Configurable trackTunerConfigSource{"trackTunerConfigSource", aod::track_tuner::InputString, "1: input string; 2: TrackTuner Configurables"}; + Configurable trackTunerParams{"trackTunerParams", "debugInfo=0|updateTrackDCAs=1|updateTrackCovMat=1|updateCurvature=0|updateCurvatureIU=0|updatePulls=0|isInputFileFromCCDB=1|pathInputFile=Users/m/mfaggin/test/inputsTrackTuner/PbPb2022|nameInputFile=trackTuner_DataLHC22sPass5_McLHC22l1b2_run529397.root|pathFileQoverPt=Users/h/hsharma/qOverPtGraphs|nameFileQoverPt=D0sigma_Data_removal_itstps_MC_LHC22b1b.root|usePvRefitCorrections=0|qOverPtMC=-1.|qOverPtData=-1.", "TrackTuner parameter initialization (format: =|=)"}; + ConfigurableAxis axisPtQA{"axisPtQA", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for QA histograms"}; + OutputObj trackTunedTracks{TH1D("trackTunedTracks", "", 1, 0.5, 1.5), OutputObjHandlingPolicy::AnalysisObject}; + + // OutputObj hDCAxyVsPtRec{TH2F("hDCAxyVsPtRec", ";DCAxy;PtRec", 600, -0.15, 0.15, axisPtQA)}; + // OutputObj hDCAxyVsPtMC{TH2F("hDCAxyVsPtMC", ";DCAxy;PtMC", 600, -0.15, 0.15, axisPtQA)}; using TracksIUWithMc = soa::Join; + HistogramRegistry registry{"registry"}; + void init(o2::framework::InitContext& initContext) { int nEnabledProcesses = 0; @@ -100,16 +110,32 @@ struct TrackPropagation { ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); + // Histograms for track tuner + AxisSpec axisBinsDCA = {600, -0.15f, 0.15f, "#it{dca}_{xy} (cm)"}; + registry.add("hDCAxyVsPtRec", "hDCAxyVsPtRec", kTH2F, {axisBinsDCA, axisPtQA}); + registry.add("hDCAxyVsPtMC", "hDCAxyVsPtMC", kTH2F, {axisBinsDCA, axisPtQA}); + registry.add("hDCAzVsPtRec", "hDCAzVsPtRec", kTH2F, {axisBinsDCA, axisPtQA}); + registry.add("hDCAzVsPtMC", "hDCAzVsPtMC", kTH2F, {axisBinsDCA, axisPtQA}); + /// TrackTuner initialization if (useTrackTuner) { - std::string outputStringParams = trackTunerObj.configParams(trackTunerParams); + std::string outputStringParams = ""; + switch (trackTunerConfigSource) { + case aod::track_tuner::InputString: + outputStringParams = trackTunerObj.configParams(trackTunerParams); + break; + case aod::track_tuner::Configurables: + outputStringParams = trackTunerObj.configParams(); + break; + + default: + LOG(fatal) << "TrackTuner configuration source not defined. Fix it! (Supported options: input string (1); Configurables (2))"; + break; + } + trackTunerObj.getDcaGraphs(); trackTunedTracks->SetTitle(outputStringParams.c_str()); trackTunedTracks->GetXaxis()->SetBinLabel(1, "all tracks"); - trackTunedTracks->GetXaxis()->SetBinLabel(2, "tracks tuned (no negative detXY)"); - trackTunedTracks->GetXaxis()->SetBinLabel(3, "untouched tracks due to negative detXY"); - trackTunedTracks->GetXaxis()->SetBinLabel(4, "original detXY<0"); } } @@ -118,6 +144,15 @@ struct TrackPropagation { if (runNumber == bc.runNumber()) { return; } + + // load matLUT for this timestamp + if (!lut) { + LOG(info) << "Loading material look-up table for timestamp: " << bc.timestamp(); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->getForTimeStamp(lutPath, bc.timestamp())); + } else { + LOG(info) << "Material look-up table already in place. Not reloading."; + } + grpmag = ccdb->getForTimeStamp(grpmagPath, bc.timestamp()); LOG(info) << "Setting magnetic field to current " << grpmag->getL3Current() << " A for run " << bc.runNumber() << " from its GRPMagField CCDB object"; o2::base::Propagator::initFieldFromGRP(grpmag); @@ -179,45 +214,65 @@ struct TrackPropagation { } // auto trackParCov = getTrackParCov(track); aod::track::TrackTypeEnum trackType = (aod::track::TrackTypeEnum)track.trackType(); + // std::array trackPxPyPz; + // std::array trackPxPyPzTuned = {0.0, 0.0, 0.0}; + double q2OverPtNew = -9999.; // Only propagate tracks which have passed the innermost wall of the TPC (e.g. skipping loopers etc). Others fill unpropagated. if (track.trackType() == aod::track::TrackIU && track.x() < minPropagationRadius) { - if constexpr (isMc && fillCovMat) { /// track tuner ok only if cov. matrix is used + if constexpr (isMc && fillCovMat) { // checking MC and fillCovMat block begins + // bool hasMcParticle = track.has_mcParticle(); if (useTrackTuner) { trackTunedTracks->Fill(1); // all tracks - // call track propagator - // this function reads many many things - // - reads track params bool hasMcParticle = track.has_mcParticle(); if (hasMcParticle) { - // LOG(info) << " MC particle exists... "; - // LOG(info) << "Inside trackPropagation: before calling tuneTrackParams trackParCov.getY(): " << trackParCov.getY(); auto mcParticle = track.mcParticle(); trackTunerObj.tuneTrackParams(mcParticle, mTrackParCov, matCorr, &mDcaInfoCov, trackTunedTracks); - // LOG(info) << "Inside trackPropagation: after calling tuneTrackParams trackParCov.getY(): " << trackParCov.getY(); - // trackTunedTracks->Fill(1); + q2OverPtNew = mTrackParCov.getQ2Pt(); } } - } + } // MC and fillCovMat block ends + bool isPropagationOK = true; + if (track.has_collision()) { auto const& collision = track.collision(); if constexpr (fillCovMat) { mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); - o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, mTrackParCov, 2.f, matCorr, &mDcaInfoCov); + isPropagationOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, mTrackParCov, 2.f, matCorr, &mDcaInfoCov); } else { - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, mTrackPar, 2.f, matCorr, &mDcaInfo); + isPropagationOK = o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, mTrackPar, 2.f, matCorr, &mDcaInfo); } } else { if constexpr (fillCovMat) { mVtx.setPos({mMeanVtx->getX(), mMeanVtx->getY(), mMeanVtx->getZ()}); mVtx.setCov(mMeanVtx->getSigmaX() * mMeanVtx->getSigmaX(), 0.0f, mMeanVtx->getSigmaY() * mMeanVtx->getSigmaY(), 0.0f, 0.0f, mMeanVtx->getSigmaZ() * mMeanVtx->getSigmaZ()); - o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, mTrackParCov, 2.f, matCorr, &mDcaInfoCov); + isPropagationOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, mTrackParCov, 2.f, matCorr, &mDcaInfoCov); } else { - o2::base::Propagator::Instance()->propagateToDCABxByBz({mMeanVtx->getX(), mMeanVtx->getY(), mMeanVtx->getZ()}, mTrackPar, 2.f, matCorr, &mDcaInfo); + isPropagationOK = o2::base::Propagator::Instance()->propagateToDCABxByBz({mMeanVtx->getX(), mMeanVtx->getY(), mMeanVtx->getZ()}, mTrackPar, 2.f, matCorr, &mDcaInfo); } } - trackType = aod::track::Track; + if (isPropagationOK) { + trackType = aod::track::Track; + } + // filling some QA histograms for track tuner test purpose + if constexpr (isMc && fillCovMat) { // checking MC and fillCovMat block begins + if (track.has_mcParticle() && isPropagationOK) { + auto mcParticle1 = track.mcParticle(); + // && abs(mcParticle1.pdgCode())==211 + if (mcParticle1.isPhysicalPrimary()) { + registry.fill(HIST("hDCAxyVsPtRec"), mDcaInfoCov.getY(), mTrackParCov.getPt()); + registry.fill(HIST("hDCAxyVsPtMC"), mDcaInfoCov.getY(), mcParticle1.pt()); + registry.fill(HIST("hDCAzVsPtRec"), mDcaInfoCov.getZ(), mTrackParCov.getPt()); + registry.fill(HIST("hDCAzVsPtMC"), mDcaInfoCov.getZ(), mcParticle1.pt()); + } + } + } // MC and fillCovMat block ends + } + // Filling modified Q/Pt values at IU/production point by track tuner in track tuner table + if (useTrackTuner && fillTrackTunerTable) { + tunertable(q2OverPtNew); } + // LOG(info) << " trackPropagation (this value filled in tuner table)--> " << q2OverPtNew; if constexpr (fillCovMat) { tracksParPropagated(track.collisionId(), trackType, mTrackParCov.getX(), mTrackParCov.getAlpha(), mTrackParCov.getY(), mTrackParCov.getZ(), mTrackParCov.getSnp(), mTrackParCov.getTgl(), mTrackParCov.getQ2Pt()); tracksParExtensionPropagated(mTrackParCov.getPt(), mTrackParCov.getP(), mTrackParCov.getEta(), mTrackParCov.getPhi()); @@ -259,6 +314,7 @@ struct TrackPropagation { // ----------------------- void processCovarianceMc(TracksIUWithMc const& tracks, aod::McParticles const& mcParticles, aod::Collisions const& collisions, aod::BCsWithTimestamps const& bcs) { + // auto table_extension = soa::Extend(tracks); fillTrackTables(tracks, mcParticles, collisions, bcs); } PROCESS_SWITCH(TrackPropagation, processCovarianceMc, "Process with covariance on MC", false); diff --git a/Common/TableProducer/trackselection.cxx b/Common/TableProducer/trackselection.cxx index 7ae8930de17..8ce5a88e0bd 100644 --- a/Common/TableProducer/trackselection.cxx +++ b/Common/TableProducer/trackselection.cxx @@ -41,7 +41,7 @@ struct TrackSelectionTask { Configurable produceTable{"produceTable", -1, "option to produce the standard table table with the track selection. -1 autosetup, 0 dislabled, 1 enabled"}; Configurable produceFBextendedTable{"produceFBextendedTable", -1, "option to produce table with FB selection information. -1 autosetup, 0 dislabled, 1 enabled"}; Configurable compatibilityIU{"compatibilityIU", false, "compatibility option to allow the processing of tracks before the introduction of IU tracks"}; - Configurable itsMatching{"itsMatching", 0, "condition for ITS matching (0: Run2 SPD kAny, 1: Run3ITSibAny, 2: Run3ITSallAny, 3: Run3ITSall7Layers)"}; + Configurable itsMatching{"itsMatching", 0, "condition for ITS matching (0: Run2 SPD kAny, 1: Run3ITSibAny, 2: Run3ITSallAny, 3: Run3ITSall7Layers, 4: Run3ITSibFirst)"}; Configurable dcaSetup{"dcaSetup", 0, "dca setup: (0: default, 1: ppPass3)"}; Configurable ptMin{"ptMin", 0.1f, "Lower cut on pt for the track selected"}; Configurable ptMax{"ptMax", 1e10f, "Upper cut on pt for the track selected"}; @@ -74,6 +74,7 @@ struct TrackSelectionTask { break; } LOG(warning) << "isRun3 == true and itsMatching == 0: not setting globalTracks = getGlobalTrackSelection();, but going to itsMatching == 1 and set getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny)"; + [[fallthrough]]; case 1: // Run 3 kAny on 3 IB layers of ITS if (isRun3) { @@ -81,6 +82,7 @@ struct TrackSelectionTask { globalTracks = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, dcaSetup.value); break; } + [[fallthrough]]; case 2: // Run 3 kAny on all 7 layers of ITS if (isRun3) { @@ -88,6 +90,7 @@ struct TrackSelectionTask { globalTracks = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSallAny, dcaSetup.value); break; } + [[fallthrough]]; case 3: // Run 3 kAll on all 7 layers of ITS if (isRun3) { @@ -95,6 +98,15 @@ struct TrackSelectionTask { globalTracks = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSall7Layers, dcaSetup.value); break; } + [[fallthrough]]; + case 4: + // Run 3 kFirst, i.e. 1 hit in first layer of ITS + if (isRun3) { + LOG(info) << "setting up getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibFirst, " << dcaSetup.value << ");"; + globalTracks = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibFirst, dcaSetup.value); + break; + } + [[fallthrough]]; default: LOG(fatal) << "TrackSelectionTask with undefined cuts. Fix it!"; break; diff --git a/Common/TableProducer/zdc-task-intercalib.cxx b/Common/TableProducer/zdc-task-intercalib.cxx new file mode 100644 index 00000000000..77b590bde57 --- /dev/null +++ b/Common/TableProducer/zdc-task-intercalib.cxx @@ -0,0 +1,155 @@ +// 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 zdc-task-intercalib.cxx +/// \brief Task for ZDC tower inter-calibration +/// \author chiara.oppedisano@cern.ch + +// o2-linter: disable=name/workflow-file +// o2-linter: disable=name/file-cpp +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/ZDCInterCalib.h" + +#include "TH1F.h" +#include "TH2F.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::evsel; + +using BCsRun3 = soa::Join; +using ColEvSels = soa::Join; + +struct ZDCCalibTower { + + Produces zTab; + + // Configurable parameters + // + Configurable nBins{"nBins", 400, "n bins"}; + Configurable maxZN{"maxZN", 399.5, "Max ZN signal"}; + Configurable tdcCut{"tdcCut", false, "Flag for TDC cut"}; + Configurable tdcZNmincut{"tdcZNmincut", -2.5, "Min ZN TDC cut"}; + Configurable tdcZNmaxcut{"tdcZNmaxcut", -2.5, "Max ZN TDC cut"}; + // + HistogramRegistry registry{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext const&) + { + registry.add("ZNApmc", "ZNApmc; ZNA PMC; Entries", {HistType::kTH1F, {{nBins, -0.5, maxZN}}}); + registry.add("ZNCpmc", "ZNCpmc; ZNC PMC; Entries", {HistType::kTH1F, {{nBins, -0.5, maxZN}}}); + registry.add("ZNApm1", "ZNApm1; ZNA PM1; Entries", {HistType::kTH1F, {{nBins, -0.5, maxZN}}}); + registry.add("ZNApm2", "ZNApm2; ZNA PM2; Entries", {HistType::kTH1F, {{nBins, -0.5, maxZN}}}); + registry.add("ZNApm3", "ZNApm3; ZNA PM3; Entries", {HistType::kTH1F, {{nBins, -0.5, maxZN}}}); + registry.add("ZNApm4", "ZNApm4; ZNA PM4; Entries", {HistType::kTH1F, {{nBins, -0.5, maxZN}}}); + registry.add("ZNCpm1", "ZNCpm1; ZNC PM1; Entries", {HistType::kTH1F, {{nBins, -0.5, maxZN}}}); + registry.add("ZNCpm2", "ZNCpm2; ZNC PM2; Entries", {HistType::kTH1F, {{nBins, -0.5, maxZN}}}); + registry.add("ZNCpm3", "ZNCpm3; ZNC PM3; Entries", {HistType::kTH1F, {{nBins, -0.5, maxZN}}}); + registry.add("ZNCpm4", "ZNCpm4; ZNC PM4; Entries", {HistType::kTH1F, {{nBins, -0.5, maxZN}}}); + registry.add("ZNAsumq", "ZNAsumq; ZNA uncalib. sum PMQ; Entries", {HistType::kTH1F, {{nBins, -0.5, maxZN}}}); + registry.add("ZNCsumq", "ZNCsumq; ZNC uncalib. sum PMQ; Entries", {HistType::kTH1F, {{nBins, -0.5, maxZN}}}); + } + + void process(ColEvSels const& cols, BCsRun3 const& /*bcs*/, aod::Zdcs const& /*zdcs*/) + { + // collision-based event selection + for (auto const& collision : cols) { + const auto& foundBC = collision.foundBC_as(); + if (foundBC.has_zdc()) { + const auto& zdc = foundBC.zdc(); + + // To assure that ZN have a genuine signal (tagged by the relative TDC) + // we can check that the amplitude is >0 or that ADC is NOT very negative (-inf) + + double pmcZNC = zdc.energyCommonZNC(); + double pmcZNA = zdc.energyCommonZNA(); + bool isZNChit = false, isZNAhit = false; + // + double tdcZNC = zdc.timeZNC(); + double tdcZNA = zdc.timeZNA(); + // OR we can select a narrow window in both ZN TDCs using the configurable parameters + if (tdcCut) { // a narrow TDC window is set + if ((tdcZNC >= tdcZNmincut) && (tdcZNC <= tdcZNmaxcut)) { + isZNChit = true; + } + if ((tdcZNA >= tdcZNmincut) && (tdcZNA <= tdcZNmaxcut)) { + isZNAhit = true; + } + } else { // if no window on TDC is set + if (pmcZNC > -1.) { + isZNChit = true; + } + if (pmcZNA > -1.) { + isZNAhit = true; + } + } + // + double sumZNC = 0; + double sumZNA = 0; + double pmqZNC[4] = { + 0, + 0, + 0, + 0, + }; + double pmqZNA[4] = { + 0, + 0, + 0, + 0, + }; + // + if (isZNChit) { + for (int it = 0; it < 4; it++) { + pmqZNC[it] = (zdc.energySectorZNC())[it]; + sumZNC += pmqZNC[it]; + } + registry.get(HIST("ZNCpmc"))->Fill(pmcZNC); + registry.get(HIST("ZNCpm1"))->Fill(pmqZNC[0]); + registry.get(HIST("ZNCpm2"))->Fill(pmqZNC[1]); + registry.get(HIST("ZNCpm3"))->Fill(pmqZNC[2]); + registry.get(HIST("ZNCpm4"))->Fill(pmqZNC[3]); + registry.get(HIST("ZNCsumq"))->Fill(sumZNC); + } + if (isZNAhit) { + for (int it = 0; it < 4; it++) { + pmqZNA[it] = (zdc.energySectorZNA())[it]; + sumZNA += pmqZNA[it]; + } + // + registry.get(HIST("ZNApmc"))->Fill(pmcZNA); + registry.get(HIST("ZNApm1"))->Fill(pmqZNA[0]); + registry.get(HIST("ZNApm2"))->Fill(pmqZNA[1]); + registry.get(HIST("ZNApm3"))->Fill(pmqZNA[2]); + registry.get(HIST("ZNApm4"))->Fill(pmqZNA[3]); + registry.get(HIST("ZNAsumq"))->Fill(sumZNA); + } + if (isZNAhit || isZNChit) + zTab(pmcZNA, pmqZNA[0], pmqZNA[1], pmqZNA[2], pmqZNA[3], tdcZNC, pmcZNC, pmqZNC[0], pmqZNC[1], pmqZNC[2], pmqZNC[3], tdcZNA); + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) // o2-linter: disable=name/file-cpp +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Common/Tasks/CMakeLists.txt b/Common/Tasks/CMakeLists.txt index 6c15bf176fa..2cbd4c34626 100644 --- a/Common/Tasks/CMakeLists.txt +++ b/Common/Tasks/CMakeLists.txt @@ -78,3 +78,18 @@ o2physics_add_dpl_workflow(qvectors-correction SOURCES qVectorsCorrection.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(centrality-study + SOURCES centralityStudy.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-test + SOURCES flowTest.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(muon-qa + SOURCES muonQa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::Field O2::DetectorsBase O2::DetectorsCommonDataFormats O2::MathUtils O2::MCHTracking O2::DataFormatsMCH O2::GlobalTracking O2::MCHBase O2::MCHGeometryTransformer O2::CommonUtils + COMPONENT_NAME Analysis) \ No newline at end of file diff --git a/Common/Tasks/centralityStudy.cxx b/Common/Tasks/centralityStudy.cxx new file mode 100644 index 00000000000..67a387fc903 --- /dev/null +++ b/Common/Tasks/centralityStudy.cxx @@ -0,0 +1,495 @@ +// 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. +// +// This task does dedicated centrality studies for understanding the +// Run 3 Pb-Pb centrality selections in 2023 data. It is compatible with +// derived data. + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "TH1F.h" +#include "TH2F.h" + +using namespace o2; +using namespace o2::framework; + +using BCsWithRun3Matchings = soa::Join; + +struct centralityStudy { + // Raw multiplicities + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Configurables + Configurable do2DPlots{"do2DPlots", true, "0 - no, 1 - yes"}; + Configurable doOccupancyStudyVsCentrality2d{"doOccupancyStudyVsCentrality2d", true, "0 - no, 1 - yes"}; + Configurable doOccupancyStudyVsRawValues2d{"doOccupancyStudyVsRawValues2d", true, "0 - no, 1 - yes"}; + Configurable doOccupancyStudyVsCentrality3d{"doOccupancyStudyVsCentrality3d", false, "0 - no, 1 - yes"}; + Configurable doOccupancyStudyVsRawValues3d{"doOccupancyStudyVsRawValues3d", false, "0 - no, 1 - yes"}; + Configurable doNGlobalTracksVsRawSignals{"doNGlobalTracksVsRawSignals", true, "0 - no, 1 - yes"}; + Configurable applySel8{"applySel8", true, "0 - no, 1 - yes"}; + Configurable applyVtxZ{"applyVtxZ", true, "0 - no, 1 - yes"}; + + // Apply extra event selections + Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border"}; + Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", true, "require events with at least one ITS-TPC track"}; + Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "require events with PV position along z consistent (within 1 cm) between PV reconstructed using tracks and PV using FT0 A-C time difference"}; + Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", true, "require events with at least one of vertex contributors matched to TOF"}; + Configurable requireIsVertexTRDmatched{"requireIsVertexTRDmatched", true, "require events with at least one of vertex contributors matched to TRD"}; + Configurable rejectSameBunchPileup{"rejectSameBunchPileup", true, "reject collisions in case of pileup with another collision in the same foundBC"}; + + Configurable rejectITSinROFpileupStandard{"rejectITSinROFpileupStandard", false, "reject collisions in case of in-ROF ITS pileup (standard)"}; + Configurable rejectITSinROFpileupStrict{"rejectITSinROFpileupStrict", false, "reject collisions in case of in-ROF ITS pileup (strict)"}; + Configurable rejectCollInTimeRangeNarrow{"rejectCollInTimeRangeNarrow", false, "reject if extra colls in time range (narrow)"}; + + Configurable selectUPCcollisions{"selectUPCcollisions", false, "select collisions tagged with UPC flag"}; + + Configurable selectCollidingBCs{"selectCollidingBCs", true, "BC analysis: select colliding BCs"}; + Configurable selectTVX{"selectTVX", true, "BC analysis: select TVX"}; + Configurable selectFV0OrA{"selectFV0OrA", true, "BC analysis: select FV0OrA"}; + Configurable vertexZwithT0{"vertexZwithT0", 1000.0f, "require a certain vertex-Z in BC analysis"}; + + Configurable minTimeDelta{"minTimeDelta", -1.0f, "reject collision if another collision is this close or less in time"}; + Configurable minFT0CforVertexZ{"minFT0CforVertexZ", 250, "minimum FT0C for vertex-Z profile calculation"}; + + Configurable scaleSignalFT0C{"scaleSignalFT0C", 1.00f, "scale FT0C signal for convenience"}; + Configurable scaleSignalFT0M{"scaleSignalFT0M", 1.00f, "scale FT0M signal for convenience"}; + Configurable scaleSignalFV0A{"scaleSignalFV0A", 1.00f, "scale FV0A signal for convenience"}; + + // _______________________________________ + // upc rejection criteria + // reject low zna/c + struct : ConfigurableGroup { + Configurable minZNACsignal{"minZNACsignal", -999999.0f, "min zna/c signal"}; + Configurable maxFT0CforZNACselection{"maxFT0CforZNACselection", -99999.0f, "max ft0c signal for minZNACsignal to work"}; + + Configurable minFV0Asignal{"minFV0Asignal", -999999.0f, "min fv0a signal"}; + Configurable maxFT0CforFV0Aselection{"maxFT0CforFV0Aselection", -99999.0f, "max ft0c signal for minFV0Asignal to work"}; + + Configurable minFDDAsignal{"minFDDAsignal", -999999.0f, "min fdda signal"}; + Configurable maxFT0CforFDDAselection{"maxFT0CforFDDAselection", -99999.0f, "max ft0c signal for minFDDAsignal to work"}; + } upcRejection; + + // Configurable Axes for 2d plots, etc + ConfigurableAxis axisMultFV0A{"axisMultFV0A", {1000, 0, 100000}, "FV0A amplitude"}; + ConfigurableAxis axisMultFT0A{"axisMultFT0A", {1000, 0, 100000}, "FT0A amplitude"}; + ConfigurableAxis axisMultFT0C{"axisMultFT0C", {1000, 0, 100000}, "FT0C amplitude"}; + ConfigurableAxis axisMultFT0M{"axisMultFT0M", {1000, 0, 100000}, "FT0M amplitude"}; + ConfigurableAxis axisMultFDDA{"axisMultFDDA", {1000, 0, 100000}, "FDDA amplitude"}; + ConfigurableAxis axisMultFDDC{"axisMultFDDC", {1000, 0, 100000}, "FDDC amplitude"}; + ConfigurableAxis axisMultPVContributors{"axisMultPVContributors", {200, 0, 6000}, "Number of PV Contributors"}; + ConfigurableAxis axisMultGlobalTracks{"axisMultGlobalTracks", {500, 0, 5000}, "Number of global tracks"}; + ConfigurableAxis axisMultMFTTracks{"axisMultMFTTracks", {500, 0, 5000}, "Number of MFT tracks"}; + + ConfigurableAxis axisTrackOccupancy{"axisTrackOccupancy", {50, 0, 5000}, "Track occupancy"}; + ConfigurableAxis axisFT0COccupancy{"axisFT0COccupancy", {50, 0, 80000}, "FT0C occupancy"}; + + // For one-dimensional plots, where binning is no issue + ConfigurableAxis axisMultUltraFineFV0A{"axisMultUltraFineFV0A", {60000, 0, 60000}, "FV0A amplitude"}; + ConfigurableAxis axisMultUltraFineFT0M{"axisMultUltraFineFT0M", {50000, 0, 200000}, "FT0M amplitude"}; + ConfigurableAxis axisMultUltraFineFT0C{"axisMultUltraFineFT0C", {60000, 0, 60000}, "FT0C amplitude"}; + ConfigurableAxis axisMultUltraFinePVContributors{"axisMultUltraFinePVContributors", {10000, 0, 10000}, "Number of PV Contributors"}; + ConfigurableAxis axisMultUltraFineGlobalTracks{"axisMultUltraFineGlobalTracks", {5000, 0, 5000}, "Number of global tracks"}; + ConfigurableAxis axisMultUltraFineMFTTracks{"axisMultUltraFineMFTTracks", {5000, 0, 5000}, "Number of MFT tracks"}; + + ConfigurableAxis axisMultITSOnly{"axisMultITSOnly", {200, 0, 6000}, "Number of ITS only tracks"}; + ConfigurableAxis axisMultITSTPC{"axisMultITSTPC", {200, 0, 6000}, "Number of ITSTPC matched tracks"}; + + // For centrality studies if requested + ConfigurableAxis axisCentrality{"axisCentrality", {100, 0, 100}, "FT0C percentile"}; + ConfigurableAxis axisPVChi2{"axisPVChi2", {300, 0, 30}, "FT0C percentile"}; + ConfigurableAxis axisDeltaTime{"axisDeltaTime", {300, 0, 300}, "#Delta time"}; + + // For profile Z + ConfigurableAxis axisPVz{"axisPVz", {400, -20.0f, +20.0f}, "PVz (cm)"}; + + ConfigurableAxis axisZN{"axisZN", {1100, -50.0f, +500.0f}, "ZN"}; + + void init(InitContext&) + { + if (doprocessCollisions || doprocessCollisionsWithCentrality) { + const AxisSpec axisCollisions{100, -0.5f, 99.5f, "Number of collisions"}; + histos.add("hCollisionSelection", "hCollisionSelection", kTH1D, {{20, -0.5f, +19.5f}}); + histos.get(HIST("hCollisionSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + histos.get(HIST("hCollisionSelection"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + histos.get(HIST("hCollisionSelection"))->GetXaxis()->SetBinLabel(3, "posZ cut"); + histos.get(HIST("hCollisionSelection"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + histos.get(HIST("hCollisionSelection"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + histos.get(HIST("hCollisionSelection"))->GetXaxis()->SetBinLabel(6, "kIsVertexITSTPC"); + histos.get(HIST("hCollisionSelection"))->GetXaxis()->SetBinLabel(7, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("hCollisionSelection"))->GetXaxis()->SetBinLabel(8, "kIsVertexTOFmatched"); + histos.get(HIST("hCollisionSelection"))->GetXaxis()->SetBinLabel(9, "kIsVertexTRDmatched"); + histos.get(HIST("hCollisionSelection"))->GetXaxis()->SetBinLabel(10, "kNoSameBunchPileup"); + histos.get(HIST("hCollisionSelection"))->GetXaxis()->SetBinLabel(11, "Neighbour rejection"); + histos.get(HIST("hCollisionSelection"))->GetXaxis()->SetBinLabel(12, "no ITS in-ROF pileup (standard)"); + histos.get(HIST("hCollisionSelection"))->GetXaxis()->SetBinLabel(13, "no ITS in-ROF pileup (strict)"); + + histos.add("hFT0C_Collisions", "hFT0C_Collisions", kTH1D, {axisMultUltraFineFT0C}); + histos.add("hFT0M_Collisions", "hFT0M_Collisions", kTH1D, {axisMultUltraFineFT0M}); + histos.add("hFV0A_Collisions", "hFV0A_Collisions", kTH1D, {axisMultUltraFineFV0A}); + histos.add("hNGlobalTracks", "hNGlobalTracks", kTH1D, {axisMultUltraFineGlobalTracks}); + histos.add("hNMFTTracks", "hNMFTTracks", kTH1D, {axisMultUltraFineMFTTracks}); + histos.add("hNPVContributors", "hNPVContributors", kTH1D, {axisMultUltraFinePVContributors}); + + histos.add("hFT0CvsPVz_Collisions_All", "hFT0CvsPVz_Collisions_All", kTProfile, {axisPVz}); + histos.add("hFT0CvsPVz_Collisions", "hFT0CvsPVz_Collisions", kTProfile, {axisPVz}); + histos.add("hFV0AvsPVz_Collisions", "hFV0AvsPVz_Collisions", kTProfile, {axisPVz}); + histos.add("hNGlobalTracksvsPVz_Collisions", "hNGlobalTracksvsPVz_Collisions", kTProfile, {axisPVz}); + histos.add("hNMFTTracksvsPVz_Collisions", "hNMFTTracksvsPVz_Collisions", kTProfile, {axisPVz}); + } + + if (doprocessBCs) { + histos.add("hBCSelection", "hBCSelection", kTH1D, {{20, -0.5, 19.5f}}); + histos.add("hFT0C_BCs", "hFT0C_BCs", kTH1D, {axisMultUltraFineFT0C}); + histos.add("hFT0M_BCs", "hFT0M_BCs", kTH1D, {axisMultUltraFineFT0M}); + histos.add("hFV0A_BCs", "hFV0A_BCs", kTH1D, {axisMultUltraFineFV0A}); + histos.add("hFT0CvsPVz_BCs_All", "hFT0CvsPVz_BCs_All", kTProfile, {axisPVz}); + histos.add("hFT0CvsPVz_BCs", "hFT0CvsPVz_BCs", kTProfile, {axisPVz}); + histos.add("hVertexZ_BCvsCO", "hVertexZ_BCvsCO", kTH2D, {axisPVz, axisPVz}); + histos.add("hZNAvsFT0C_BCs", "hZNAvsFT0C_BCs", kTH2D, {axisMultFT0C, axisZN}); + histos.add("hZNCvsFT0C_BCs", "hZNCvsFT0C_BCs", kTH2D, {axisMultFT0C, axisZN}); + } + + if (do2DPlots) { + histos.add("hNContribsVsFT0C", "hNContribsVsFT0C", kTH2F, {axisMultFT0C, axisMultPVContributors}); + histos.add("hNContribsVsFV0A", "hNContribsVsFV0A", kTH2F, {axisMultFV0A, axisMultPVContributors}); + histos.add("hMatchedVsITSOnly", "hMatchedVsITSOnly", kTH2F, {axisMultITSOnly, axisMultITSTPC}); + + // 2d correlation of fit signals + histos.add("hFT0AVsFT0C", "hFT0AVsFT0C", kTH2F, {axisMultFT0C, axisMultFT0A}); + histos.add("hFV0AVsFT0C", "hFV0AVsFT0C", kTH2F, {axisMultFT0C, axisMultFV0A}); + histos.add("hFDDAVsFT0C", "hFDDAVsFT0C", kTH2F, {axisMultFT0C, axisMultFDDA}); + histos.add("hFDDCVsFT0C", "hFDDCVsFT0C", kTH2F, {axisMultFT0C, axisMultFDDC}); + } + + if (doNGlobalTracksVsRawSignals) { + histos.add("hNGlobalTracksVsFT0A", "hNGlobalTracksVsFT0A", kTH2F, {axisMultFT0A, axisMultGlobalTracks}); + histos.add("hNGlobalTracksVsFT0C", "hNGlobalTracksVsFT0C", kTH2F, {axisMultFT0C, axisMultGlobalTracks}); + histos.add("hNGlobalTracksVsFT0M", "hNGlobalTracksVsFT0M", kTH2F, {axisMultFT0M, axisMultGlobalTracks}); + histos.add("hNGlobalTracksVsFV0A", "hNGlobalTracksVsFV0A", kTH2F, {axisMultFV0A, axisMultGlobalTracks}); + histos.add("hNGlobalTracksVsFDDA", "hNGlobalTracksVsFDDA", kTH2F, {axisMultFDDA, axisMultGlobalTracks}); + histos.add("hNGlobalTracksVsFDDC", "hNGlobalTracksVsFDDC", kTH2F, {axisMultFDDC, axisMultGlobalTracks}); + histos.add("hNGlobalTracksVsZNA", "hNGlobalTracksVsZNA", kTH2F, {axisZN, axisMultGlobalTracks}); + histos.add("hNGlobalTracksVsZNC", "hNGlobalTracksVsZNC", kTH2F, {axisZN, axisMultGlobalTracks}); + histos.add("hNGlobalTracksVsNMFTTracks", "hNGlobalTracksVsNMFTTracks", kTH2F, {axisMultMFTTracks, axisMultGlobalTracks}); + } + + if (doOccupancyStudyVsRawValues2d) { + histos.add("hNcontribsProfileVsTrackOccupancyVsFT0C", "hNcontribsProfileVsTrackOccupancyVsFT0C", kTProfile2D, {axisTrackOccupancy, axisMultFT0C}); + histos.add("hNGlobalTracksProfileVsTrackOccupancyVsFT0C", "hNGlobalTracksProfileVsTrackOccupancyVsFT0C", kTProfile2D, {axisTrackOccupancy, axisMultFT0C}); + histos.add("hNcontribsProfileVsFT0COccupancyVsFT0C", "hNcontribsProfileVsFT0COccupancyVsFT0C", kTProfile2D, {axisFT0COccupancy, axisMultFT0C}); + histos.add("hNGlobalTracksProfileVsFT0COccupancyVsFT0C", "hNGlobalTracksProfileVsFT0COccupancyVsFT0C", kTProfile2D, {axisFT0COccupancy, axisMultFT0C}); + } + + if (doOccupancyStudyVsRawValues3d) { + histos.add("hTrackOccupancyVsNContribsVsFT0C", "hTrackOccupancyVsNContribsVsFT0C", kTH3F, {axisTrackOccupancy, axisMultPVContributors, axisMultFT0C}); + histos.add("hTrackOccupancyVsNGlobalTracksVsFT0C", "hTrackOccupancyVsNGlobalTracksVsFT0C", kTH3F, {axisTrackOccupancy, axisMultGlobalTracks, axisMultFT0C}); + histos.add("hFT0COccupancyVsNContribsVsFT0C", "hFT0COccupancyVsNContribsVsFT0C", kTH3F, {axisFT0COccupancy, axisMultPVContributors, axisMultFT0C}); + histos.add("hFT0COccupancyVsNGlobalTracksVsFT0C", "hFT0COccupancyVsNGlobalTracksVsFT0C", kTH3F, {axisFT0COccupancy, axisMultGlobalTracks, axisMultFT0C}); + } + + if (doprocessCollisionsWithCentrality) { + // in case requested: do vs centrality debugging + histos.add("hCentrality", "hCentrality", kTH1F, {axisCentrality}); + histos.add("hNContribsVsCentrality", "hNContribsVsCentrality", kTH2F, {axisCentrality, axisMultPVContributors}); + histos.add("hNITSTPCTracksVsCentrality", "hNITSTPCTracksVsCentrality", kTH2F, {axisCentrality, axisMultPVContributors}); + histos.add("hNITSOnlyTracksVsCentrality", "hNITSOnlyTracksVsCentrality", kTH2F, {axisCentrality, axisMultPVContributors}); + histos.add("hNGlobalTracksVsCentrality", "hNGlobalTracksVsCentrality", kTH2F, {axisCentrality, axisMultPVContributors}); + histos.add("hNMFTTracksVsCentrality", "hNMFTTracksVsCentrality", kTH2F, {axisCentrality, axisMultMFTTracks}); + histos.add("hPVChi2VsCentrality", "hPVChi2VsCentrality", kTH2F, {axisCentrality, axisPVChi2}); + histos.add("hDeltaTimeVsCentrality", "hDeltaTimeVsCentrality", kTH2F, {axisCentrality, axisDeltaTime}); + + if (doOccupancyStudyVsCentrality2d) { + histos.add("hNcontribsProfileVsTrackOccupancyVsCentrality", "hNcontribsProfileVsTrackOccupancyVsCentrality", kTProfile2D, {axisTrackOccupancy, axisCentrality}); + histos.add("hNGlobalTracksProfileVsTrackOccupancyVsCentrality", "hNGlobalTracksProfileVsTrackOccupancyVsCentrality", kTProfile2D, {axisTrackOccupancy, axisCentrality}); + histos.add("hNcontribsProfileVsFT0COccupancyVsCentrality", "hNcontribsProfileVsFT0COccupancyVsCentrality", kTProfile2D, {axisFT0COccupancy, axisCentrality}); + histos.add("hNGlobalTracksProfileVsFT0COccupancyVsCentrality", "hNGlobalTracksProfileVsFT0COccupancyVsCentrality", kTProfile2D, {axisFT0COccupancy, axisCentrality}); + } + + if (doOccupancyStudyVsCentrality3d) { + histos.add("hTrackOccupancyVsNContribsVsCentrality", "hTrackOccupancyVsNContribsVsCentrality", kTH3F, {axisTrackOccupancy, axisMultPVContributors, axisCentrality}); + histos.add("hTrackOccupancyVsNGlobalTracksVsCentrality", "hTrackOccupancyVsNGlobalTracksVsCentrality", kTH3F, {axisTrackOccupancy, axisMultGlobalTracks, axisCentrality}); + histos.add("hFT0COccupancyVsNContribsVsCentrality", "hFT0COccupancyVsNContribsVsCentrality", kTH3F, {axisFT0COccupancy, axisMultPVContributors, axisCentrality}); + histos.add("hFT0COccupancyVsNGlobalTracksVsCentrality", "hFT0COccupancyVsNGlobalTracksVsCentrality", kTH3F, {axisFT0COccupancy, axisMultGlobalTracks, axisCentrality}); + } + } + } + + template + void genericProcessCollision(TCollision collision) + // process this collisions + { + + histos.fill(HIST("hCollisionSelection"), 0); // all collisions + if (applySel8 && !collision.multSel8()) + return; + histos.fill(HIST("hCollisionSelection"), 1); + if (applyVtxZ && TMath::Abs(collision.multPVz()) > 10) + return; + histos.fill(HIST("hCollisionSelection"), 2); + + // _______________________________________________________ + // Extra event selections start here + if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return; + } + histos.fill(HIST("hCollisionSelection"), 3 /* Not at ITS ROF border */); + + if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return; + } + histos.fill(HIST("hCollisionSelection"), 4 /* Not at TF border */); + + if (requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return; + } + histos.fill(HIST("hCollisionSelection"), 5 /* Contains at least one ITS-TPC track */); + + if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; + } + histos.fill(HIST("hCollisionSelection"), 6 /* PV position consistency check */); + + if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return; + } + histos.fill(HIST("hCollisionSelection"), 7 /* PV with at least one contributor matched with TOF */); + + if (requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + return; + } + histos.fill(HIST("hCollisionSelection"), 8 /* PV with at least one contributor matched with TRD */); + + if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return; + } + histos.fill(HIST("hCollisionSelection"), 9 /* Not at same bunch pile-up */); + + // do this only if information is available + if constexpr (requires { collision.timeToNext(); }) { + float timeToNeighbour = TMath::Min( + std::abs(collision.timeToNext()), + std::abs(collision.timeToPrevious())); + histos.fill(HIST("hDeltaTimeVsCentrality"), collision.centFT0C(), timeToNeighbour); + if (timeToNeighbour < minTimeDelta) { + return; + } + histos.fill(HIST("hCollisionSelection"), 10 /* has suspicious neighbour */); + } + + if (rejectITSinROFpileupStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return; + } + histos.fill(HIST("hCollisionSelection"), 11 /* Not ITS ROF pileup (standard) */); + + if (rejectITSinROFpileupStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return; + } + histos.fill(HIST("hCollisionSelection"), 12 /* Not ITS ROF pileup (strict) */); + + if (selectUPCcollisions && collision.flags() < 1) { // if zero then NOT upc, otherwise UPC + return; + } + histos.fill(HIST("hCollisionSelection"), 13 /* is UPC event */); + + if (rejectCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + return; + } + histos.fill(HIST("hCollisionSelection"), 14 /* Not ITS ROF pileup (strict) */); + + if (collision.multFT0C() < upcRejection.maxFT0CforZNACselection && + collision.multZNA() < upcRejection.minZNACsignal && + collision.multZNC() < upcRejection.minZNACsignal) { + return; + } + if (collision.multFT0C() < upcRejection.maxFT0CforFV0Aselection && + collision.multFV0A() < upcRejection.minFV0Asignal) { + return; + } + if (collision.multFT0C() < upcRejection.maxFT0CforFDDAselection && + collision.multFDDA() < upcRejection.minFDDAsignal) { + return; + } + histos.fill(HIST("hCollisionSelection"), 15 /* pass em/upc rejection */); + + // if we got here, we also finally fill the FT0C histogram, please + histos.fill(HIST("hNPVContributors"), collision.multPVTotalContributors()); + histos.fill(HIST("hFT0C_Collisions"), collision.multFT0C() * scaleSignalFT0C); + histos.fill(HIST("hFT0M_Collisions"), (collision.multFT0A() + collision.multFT0C()) * scaleSignalFT0M); + histos.fill(HIST("hFV0A_Collisions"), collision.multFV0A() * scaleSignalFV0A); + histos.fill(HIST("hNGlobalTracks"), collision.multNTracksGlobal()); + histos.fill(HIST("hNMFTTracks"), collision.mftNtracks()); + histos.fill(HIST("hFT0CvsPVz_Collisions_All"), collision.multPVz(), collision.multFT0C() * scaleSignalFT0C); + histos.fill(HIST("hFV0AvsPVz_Collisions"), collision.multPVz(), collision.multFV0A() * scaleSignalFV0A); + histos.fill(HIST("hNGlobalTracksvsPVz_Collisions"), collision.multPVz(), collision.multNTracksGlobal()); + histos.fill(HIST("hNMFTTracksvsPVz_Collisions"), collision.multPVz(), collision.mftNtracks()); + if (collision.multFT0C() > minFT0CforVertexZ) { + histos.fill(HIST("hFT0CvsPVz_Collisions"), collision.multPVz(), collision.multFT0C() * scaleSignalFT0C); + } + if (do2DPlots) { + histos.fill(HIST("hNContribsVsFT0C"), collision.multFT0C() * scaleSignalFT0C, collision.multPVTotalContributors()); + histos.fill(HIST("hNContribsVsFV0A"), collision.multFV0A() * scaleSignalFV0A, collision.multPVTotalContributors()); + histos.fill(HIST("hMatchedVsITSOnly"), collision.multNTracksITSOnly(), collision.multNTracksITSTPC()); + + // correlate also FIT detector signals + histos.fill(HIST("hFT0AVsFT0C"), collision.multFT0C() * scaleSignalFT0C, collision.multFT0A()); + histos.fill(HIST("hFV0AVsFT0C"), collision.multFT0C() * scaleSignalFT0C, collision.multFV0A()); + histos.fill(HIST("hFDDAVsFT0C"), collision.multFT0C() * scaleSignalFT0C, collision.multFDDA()); + histos.fill(HIST("hFDDCVsFT0C"), collision.multFT0C() * scaleSignalFT0C, collision.multFDDC()); + } + + if (doOccupancyStudyVsCentrality2d) { + histos.fill(HIST("hNcontribsProfileVsTrackOccupancyVsFT0C"), collision.trackOccupancyInTimeRange(), collision.multFT0C(), collision.multPVTotalContributors()); + histos.fill(HIST("hNGlobalTracksProfileVsTrackOccupancyVsFT0C"), collision.trackOccupancyInTimeRange(), collision.multFT0C(), collision.multNTracksGlobal()); + histos.fill(HIST("hNcontribsProfileVsFT0COccupancyVsFT0C"), collision.ft0cOccupancyInTimeRange(), collision.multFT0C(), collision.multPVTotalContributors()); + histos.fill(HIST("hNGlobalTracksProfileVsFT0COccupancyVsFT0C"), collision.ft0cOccupancyInTimeRange(), collision.multFT0C(), collision.multNTracksGlobal()); + } + + if (doOccupancyStudyVsRawValues3d) { + histos.fill(HIST("hTrackOccupancyVsNContribsVsFT0C"), collision.trackOccupancyInTimeRange(), collision.multPVTotalContributors(), collision.multFT0C()); + histos.fill(HIST("hTrackOccupancyVsNGlobalTracksVsFT0C"), collision.trackOccupancyInTimeRange(), collision.multNTracksGlobal(), collision.multFT0C()); + histos.fill(HIST("hFT0COccupancyVsNContribsVsFT0C"), collision.ft0cOccupancyInTimeRange(), collision.multPVTotalContributors(), collision.multFT0C()); + histos.fill(HIST("hFT0COccupancyVsNGlobalTracksVsFT0C"), collision.ft0cOccupancyInTimeRange(), collision.multNTracksGlobal(), collision.multFT0C()); + } + + if (doNGlobalTracksVsRawSignals) { + histos.fill(HIST("hNGlobalTracksVsFT0A"), collision.multFT0A(), collision.multNTracksGlobal()); + histos.fill(HIST("hNGlobalTracksVsFT0C"), collision.multFT0C(), collision.multNTracksGlobal()); + histos.fill(HIST("hNGlobalTracksVsFT0M"), collision.multFT0A() + collision.multFT0C(), collision.multNTracksGlobal()); + histos.fill(HIST("hNGlobalTracksVsFV0A"), collision.multFV0A(), collision.multNTracksGlobal()); + histos.fill(HIST("hNGlobalTracksVsFDDA"), collision.multFDDA(), collision.multNTracksGlobal()); + histos.fill(HIST("hNGlobalTracksVsFDDC"), collision.multFDDC(), collision.multNTracksGlobal()); + histos.fill(HIST("hNGlobalTracksVsZNA"), collision.multZNA(), collision.multNTracksGlobal()); + histos.fill(HIST("hNGlobalTracksVsZNC"), collision.multZNC(), collision.multNTracksGlobal()); + histos.fill(HIST("hNGlobalTracksVsNMFTTracks"), collision.mftNtracks(), collision.multNTracksGlobal()); + } + + // if the table has centrality information + if constexpr (requires { collision.centFT0C(); }) { + // process FT0C centrality plots + histos.fill(HIST("hCentrality"), collision.centFT0C()); + histos.fill(HIST("hNContribsVsCentrality"), collision.centFT0C(), collision.multPVTotalContributors()); + histos.fill(HIST("hNITSTPCTracksVsCentrality"), collision.centFT0C(), collision.multNTracksITSTPC()); + histos.fill(HIST("hNITSOnlyTracksVsCentrality"), collision.centFT0C(), collision.multNTracksITSOnly()); + histos.fill(HIST("hNGlobalTracksVsCentrality"), collision.centFT0C(), collision.multNTracksGlobal()); + histos.fill(HIST("hNMFTTracksVsCentrality"), collision.centFT0C(), collision.mftNtracks()); + histos.fill(HIST("hPVChi2VsCentrality"), collision.centFT0C(), collision.multPVChi2()); + + if (doOccupancyStudyVsCentrality2d) { + histos.fill(HIST("hNcontribsProfileVsTrackOccupancyVsCentrality"), collision.trackOccupancyInTimeRange(), collision.centFT0C(), collision.multPVTotalContributors()); + histos.fill(HIST("hNGlobalTracksProfileVsTrackOccupancyVsCentrality"), collision.trackOccupancyInTimeRange(), collision.centFT0C(), collision.multNTracksGlobal()); + histos.fill(HIST("hNcontribsProfileVsFT0COccupancyVsCentrality"), collision.ft0cOccupancyInTimeRange(), collision.centFT0C(), collision.multPVTotalContributors()); + histos.fill(HIST("hNGlobalTracksProfileVsFT0COccupancyVsCentrality"), collision.ft0cOccupancyInTimeRange(), collision.centFT0C(), collision.multNTracksGlobal()); + } + + if (doOccupancyStudyVsCentrality3d) { + histos.fill(HIST("hTrackOccupancyVsNContribsVsCentrality"), collision.trackOccupancyInTimeRange(), collision.multPVTotalContributors(), collision.centFT0C()); + histos.fill(HIST("hTrackOccupancyVsNGlobalTracksVsCentrality"), collision.trackOccupancyInTimeRange(), collision.multNTracksGlobal(), collision.centFT0C()); + histos.fill(HIST("hFT0COccupancyVsNContribsVsCentrality"), collision.ft0cOccupancyInTimeRange(), collision.multPVTotalContributors(), collision.centFT0C()); + histos.fill(HIST("hFT0COccupancyVsNGlobalTracksVsCentrality"), collision.ft0cOccupancyInTimeRange(), collision.multNTracksGlobal(), collision.centFT0C()); + } + } + } + + void processCollisions(soa::Join::iterator const& collision) + { + genericProcessCollision(collision); + } + + void processCollisionsWithCentrality(soa::Join::iterator const& collision) + { + genericProcessCollision(collision); + } + + void processCollisionsWithCentralityWithNeighbours(soa::Join::iterator const& collision) + { + genericProcessCollision(collision); + } + + void processBCs(soa::Join::iterator const& multbc, soa::Join const&) + { + // process BCs, calculate FT0C distribution + // conditionals suggested by FIT team (Jacek O. et al) + histos.fill(HIST("hBCSelection"), 0); // all BCs + if (selectCollidingBCs && !multbc.multCollidingBC()) + return; + histos.fill(HIST("hBCSelection"), 1); // colliding + if (selectTVX && !multbc.multTVX()) + return; + histos.fill(HIST("hBCSelection"), 2); // TVX + if (selectFV0OrA && !multbc.multFV0OrA()) + return; + histos.fill(HIST("hBCSelection"), 3); // FV0OrA + if (vertexZwithT0 < 100.0f) { + if (!multbc.multFT0PosZValid()) + return; + if (TMath::Abs(multbc.multFT0PosZ()) > vertexZwithT0) + return; + } + histos.fill(HIST("hBCSelection"), 4); // FV0OrA + + if (multbc.multFT0C() < upcRejection.maxFT0CforZNACselection && + multbc.multZNA() < upcRejection.minZNACsignal && + multbc.multZNC() < upcRejection.minZNACsignal) { + return; + } + if (multbc.multFT0C() < upcRejection.maxFT0CforFV0Aselection && + multbc.multFV0A() < upcRejection.minFV0Asignal) { + return; + } + if (multbc.multFT0C() < upcRejection.maxFT0CforFDDAselection && + multbc.multFDDA() < upcRejection.minFDDAsignal) { + return; + } + + histos.fill(HIST("hBCSelection"), 5); // znac + + // if we got here, we also finally fill the FT0C histogram, please + histos.fill(HIST("hFT0C_BCs"), multbc.multFT0C() * scaleSignalFT0C); + + // ZN signals + histos.fill(HIST("hZNAvsFT0C_BCs"), multbc.multFT0C() * scaleSignalFT0C, multbc.multZNA()); + histos.fill(HIST("hZNCvsFT0C_BCs"), multbc.multFT0C() * scaleSignalFT0C, multbc.multZNC()); + + histos.fill(HIST("hFT0M_BCs"), (multbc.multFT0A() + multbc.multFT0C()) * scaleSignalFT0M); + histos.fill(HIST("hFV0A_BCs"), multbc.multFV0A() * scaleSignalFV0A); + if (multbc.multFT0PosZValid()) { + histos.fill(HIST("hFT0CvsPVz_BCs_All"), multbc.multFT0PosZ(), multbc.multFT0C() * scaleSignalFT0C); + if (multbc.multFT0C() > minFT0CforVertexZ) { + histos.fill(HIST("hFT0CvsPVz_BCs"), multbc.multFT0PosZ(), multbc.multFT0C() * scaleSignalFT0C); + } + } + + if (multbc.has_ft0Mult()) { + auto multco = multbc.ft0Mult_as>(); + if (multbc.multFT0PosZValid()) { + histos.fill(HIST("hVertexZ_BCvsCO"), multco.multPVz(), multbc.multFT0PosZ()); + } + } + } + + PROCESS_SWITCH(centralityStudy, processCollisions, "per-collision analysis", false); + PROCESS_SWITCH(centralityStudy, processCollisionsWithCentrality, "per-collision analysis", true); + PROCESS_SWITCH(centralityStudy, processCollisionsWithCentralityWithNeighbours, "per-collision analysis", false); + PROCESS_SWITCH(centralityStudy, processBCs, "per-BC analysis", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Common/Tasks/flowTest.cxx b/Common/Tasks/flowTest.cxx new file mode 100644 index 00000000000..bb27c0cc504 --- /dev/null +++ b/Common/Tasks/flowTest.cxx @@ -0,0 +1,292 @@ +// 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. + +// flow test for QC of synthetic flow exercise +// cross-PWG effort in tracking studies +// includes basic tracking, V0s and Cascades + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/trackUtilities.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +#define bitcheck(var, nbit) ((var) & (1 << (nbit))) + +#include "Framework/runDataProcessing.h" + +struct flowTest { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable minB{"minB", 0.0f, "min impact parameter"}; + Configurable maxB{"maxB", 20.0f, "max impact parameter"}; + Configurable pdgSelection{"pdgSelection", 0, "pdg code selection for tracking study (0: no selection)"}; + + Configurable analysisMinimumITSClusters{"analysisMinimumITSClusters", 5, "minimum ITS clusters for analysis track category"}; + Configurable analysisMinimumTPCClusters{"analysisMinimumTPCClusters", 70, "minimum TPC clusters for analysis track category"}; + + ConfigurableAxis axisB{"axisB", {100, 0.0f, 20.0f}, ""}; + ConfigurableAxis axisPhi{"axisPhi", {100, 0.0f, 2.0f * TMath::Pi()}, ""}; + ConfigurableAxis axisNch{"axisNch", {300, 0.0f, 3000.0f}, "Nch in |eta|<0.8"}; + + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f}, "pt axis"}; + + void init(InitContext&) + { + // QA and detailed studies + histos.add("hImpactParameter", "hImpactParameter", HistType::kTH1D, {axisB}); + histos.add("hNchVsImpactParameter", "hNchVsImpactParameter", HistType::kTH2D, {axisB, axisNch}); + histos.add("hEventPlaneAngle", "hEventPlaneAngle", HistType::kTH1D, {axisPhi}); + histos.add("hTrackPhiVsEventPlaneAngle", "hTrackPhiVsEventPlaneAngle", HistType::kTH2D, {axisPhi, axisPhi}); + histos.add("hTrackDeltaPhiVsEventPlaneAngle", "hTrackDeltaPhiVsEventPlaneAngle", HistType::kTH2D, {axisPhi, axisPhi}); + + // analysis + histos.add("hPtVsPhiGenerated", "hPtVsPhiGenerated", HistType::kTH2D, {axisPhi, axisPt}); + histos.add("hPtVsPhiGlobal", "hPtVsPhiGlobal", HistType::kTH2D, {axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGenerated", "hBVsPtVsPhiGenerated", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGlobal", "hBVsPtVsPhiGlobal", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGlobalFake", "hBVsPtVsPhiGlobalFake", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiAnalysis", "hBVsPtVsPhiAnalysis", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiAnalysisFake", "hBVsPtVsPhiAnalysisFake", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiAny", "hBVsPtVsPhiAny", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiTPCTrack", "hBVsPtVsPhiTPCTrack", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiITSTrack", "hBVsPtVsPhiITSTrack", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiITSTrackFake", "hBVsPtVsPhiITSTrackFake", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiITSABTrack", "hBVsPtVsPhiITSABTrack", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiITSABTrackFake", "hBVsPtVsPhiITSABTrackFake", HistType::kTH3D, {axisB, axisPhi, axisPt}); + + histos.add("hBVsPtVsPhiGeneratedK0Short", "hBVsPtVsPhiGeneratedK0Short", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGlobalK0Short", "hBVsPtVsPhiGlobalK0Short", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGeneratedLambda", "hBVsPtVsPhiGeneratedLambda", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGlobalLambda", "hBVsPtVsPhiGlobalLambda", HistType::kTH3D, {axisB, axisPhi, axisPt}); + + histos.add("hBVsPtVsPhiGeneratedXi", "hBVsPtVsPhiGeneratedXi", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGlobalXi", "hBVsPtVsPhiGlobalXi", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGeneratedOmega", "hBVsPtVsPhiGeneratedOmega", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGlobalOmega", "hBVsPtVsPhiGlobalOmega", HistType::kTH3D, {axisB, axisPhi, axisPt}); + } + + using recoTracks = soa::Join; + using recoTracksWithLabels = soa::Join; + + void process(aod::McCollision const& mcCollision, soa::Join const& mcParticles, recoTracksWithLabels const&) + { + + float imp = mcCollision.impactParameter(); + float evPhi = mcCollision.eventPlaneAngle(); + if (evPhi < 0) + evPhi += 2. * TMath::Pi(); + + long nCh = 0; + + if (imp > minB && imp < maxB) { + // event within range + histos.fill(HIST("hImpactParameter"), imp); + histos.fill(HIST("hEventPlaneAngle"), evPhi); + + for (auto const& mcParticle : mcParticles) { + // focus on bulk: e, mu, pi, k, p + int pdgCode = TMath::Abs(mcParticle.pdgCode()); + if (pdgCode != 11 && pdgCode != 13 && pdgCode != 211 && pdgCode != 321 && pdgCode != 2212) + continue; + if ((pdgSelection.value != 0) && (pdgCode != pdgSelection.value)) + continue; // isn't of desired species and pdgSelection is requested + + if (!mcParticle.isPhysicalPrimary()) + continue; + if (TMath::Abs(mcParticle.eta()) > 0.8) // main acceptance + continue; + + float deltaPhi = mcParticle.phi() - mcCollision.eventPlaneAngle(); + if (deltaPhi < 0) + deltaPhi += 2. * TMath::Pi(); + if (deltaPhi > 2. * TMath::Pi()) + deltaPhi -= 2. * TMath::Pi(); + + histos.fill(HIST("hTrackDeltaPhiVsEventPlaneAngle"), evPhi, deltaPhi); + histos.fill(HIST("hTrackPhiVsEventPlaneAngle"), evPhi, mcParticle.phi()); + histos.fill(HIST("hPtVsPhiGenerated"), deltaPhi, mcParticle.pt()); + histos.fill(HIST("hBVsPtVsPhiGenerated"), imp, deltaPhi, mcParticle.pt()); + + nCh++; + + bool validGlobal = false; + bool validGlobalFake = false; + bool validTrack = false; + bool validTPCTrack = false; + bool validITSTrack = false; + bool validITSTrackFake = false; + bool validITSABTrack = false; + bool validITSABTrackFake = false; + bool validAnalysisTrack = false; + bool validAnalysisTrackFake = false; + if (mcParticle.has_tracks()) { + auto const& tracks = mcParticle.tracks_as(); + for (auto const& track : tracks) { + bool isITSFake = false; + if (bitcheck(track.mcMask(), 13)) { // should perhaps be done better at some point + isITSFake = true; + } + + if (track.tpcNClsFound() >= analysisMinimumTPCClusters && track.itsNCls() >= analysisMinimumITSClusters) { + validAnalysisTrack = true; + if (isITSFake) { + validAnalysisTrackFake = true; + } + } + if (track.hasTPC() && track.hasITS()) { + validGlobal = true; + if (isITSFake) { + validGlobalFake = true; + } + } + if (track.hasTPC() || track.hasITS()) { + validTrack = true; + } + if (track.hasTPC()) { + validTPCTrack = true; + } + if (track.hasITS() && track.itsChi2NCl() > -1e-6) { + validITSTrack = true; + if (isITSFake) { + validITSTrackFake = true; + } + } + if (track.hasITS() && track.itsChi2NCl() < -1e-6) { + validITSABTrack = true; + if (isITSFake) { + validITSABTrackFake = true; + } + } + } + } + + // if valid global, fill + if (validGlobal) { + histos.fill(HIST("hPtVsPhiGlobal"), deltaPhi, mcParticle.pt()); + histos.fill(HIST("hBVsPtVsPhiGlobal"), imp, deltaPhi, mcParticle.pt()); + } + if (validGlobalFake) { + histos.fill(HIST("hBVsPtVsPhiGlobalFake"), imp, deltaPhi, mcParticle.pt()); + } + if (validAnalysisTrack) { + histos.fill(HIST("hBVsPtVsPhiAnalysis"), imp, deltaPhi, mcParticle.pt()); + } + if (validAnalysisTrackFake) { + histos.fill(HIST("hBVsPtVsPhiAnalysisFake"), imp, deltaPhi, mcParticle.pt()); + } + // if any track present, fill + if (validTrack) + histos.fill(HIST("hBVsPtVsPhiAny"), imp, deltaPhi, mcParticle.pt()); + if (validTPCTrack) + histos.fill(HIST("hBVsPtVsPhiTPCTrack"), imp, deltaPhi, mcParticle.pt()); + if (validITSTrack) + histos.fill(HIST("hBVsPtVsPhiITSTrack"), imp, deltaPhi, mcParticle.pt()); + if (validITSTrackFake) + histos.fill(HIST("hBVsPtVsPhiITSTrackFake"), imp, deltaPhi, mcParticle.pt()); + if (validITSABTrack) + histos.fill(HIST("hBVsPtVsPhiITSABTrack"), imp, deltaPhi, mcParticle.pt()); + if (validITSABTrackFake) + histos.fill(HIST("hBVsPtVsPhiITSABTrackFake"), imp, deltaPhi, mcParticle.pt()); + } + } + histos.fill(HIST("hNchVsImpactParameter"), imp, nCh); + } + + using LabeledCascades = soa::Join; + + void processCascade(aod::McParticle const& mcParticle, soa::SmallGroups const& cascades, recoTracks const&, aod::McCollisions const&) + { + auto mcCollision = mcParticle.mcCollision(); + float imp = mcCollision.impactParameter(); + + int pdgCode = TMath::Abs(mcParticle.pdgCode()); + if (pdgCode != 3312 && pdgCode != 3334) + return; + + if (!mcParticle.isPhysicalPrimary()) + return; + if (TMath::Abs(mcParticle.eta()) > 0.8) + return; + + float deltaPhi = mcParticle.phi() - mcCollision.eventPlaneAngle(); + if (deltaPhi < 0) + deltaPhi += 2. * TMath::Pi(); + if (deltaPhi > 2. * TMath::Pi()) + deltaPhi -= 2. * TMath::Pi(); + if (pdgCode == 3312) + histos.fill(HIST("hBVsPtVsPhiGeneratedXi"), imp, deltaPhi, mcParticle.pt()); + if (pdgCode == 3334) + histos.fill(HIST("hBVsPtVsPhiGeneratedOmega"), imp, deltaPhi, mcParticle.pt()); + + if (cascades.size() > 0) { + if (pdgCode == 3312) + histos.fill(HIST("hBVsPtVsPhiGlobalXi"), imp, deltaPhi, mcParticle.pt()); + if (pdgCode == 3334) + histos.fill(HIST("hBVsPtVsPhiGlobalOmega"), imp, deltaPhi, mcParticle.pt()); + } + } + PROCESS_SWITCH(flowTest, processCascade, "Process cascades", true); + + using LabeledV0s = soa::Join; + + void processV0s(aod::McParticle const& mcParticle, soa::SmallGroups const& v0s, recoTracks const&, aod::McCollisions const&) + { + auto mcCollision = mcParticle.mcCollision(); + float imp = mcCollision.impactParameter(); + + int pdgCode = TMath::Abs(mcParticle.pdgCode()); + if (pdgCode != 310 && pdgCode != 3122) + return; + + if (!mcParticle.isPhysicalPrimary()) + return; + if (TMath::Abs(mcParticle.eta()) > 0.8) + return; + + float deltaPhi = mcParticle.phi() - mcCollision.eventPlaneAngle(); + if (deltaPhi < 0) + deltaPhi += 2. * TMath::Pi(); + if (deltaPhi > 2. * TMath::Pi()) + deltaPhi -= 2. * TMath::Pi(); + if (pdgCode == 310) + histos.fill(HIST("hBVsPtVsPhiGeneratedK0Short"), imp, deltaPhi, mcParticle.pt()); + if (pdgCode == 3122) + histos.fill(HIST("hBVsPtVsPhiGeneratedLambda"), imp, deltaPhi, mcParticle.pt()); + + if (v0s.size() > 0) { + if (pdgCode == 310) + histos.fill(HIST("hBVsPtVsPhiGlobalK0Short"), imp, deltaPhi, mcParticle.pt()); + if (pdgCode == 3122) + histos.fill(HIST("hBVsPtVsPhiGlobalLambda"), imp, deltaPhi, mcParticle.pt()); + } + } + PROCESS_SWITCH(flowTest, processV0s, "Process V0s", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Common/Tasks/integrationTest.cxx b/Common/Tasks/integrationTest.cxx index 41052506516..04e0ad4778e 100644 --- a/Common/Tasks/integrationTest.cxx +++ b/Common/Tasks/integrationTest.cxx @@ -13,6 +13,7 @@ // Integration tester for quick and dirty cross checks that // the framework is working reasonably // +// Includes further QA if option enabled #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" @@ -44,6 +45,13 @@ struct integrationTest { Configurable nBinsCollisions{"nBinsCollisions", 50, "number of bins in collision histo"}; Configurable do2DNTrackCorr{"do2DNTrackCorr", true, "Do 2D Ntrack correlation plots"}; + Configurable doBasicQA{"doBasicQA", true, "Do basic QA"}; + ConfigurableAxis axisHasDetector{"axisHasDetector", {16, -0.5f, 15.5f}, ""}; + ConfigurableAxis axisEta{"axisEta", {200, -2.0f, 2.0f}, ""}; + ConfigurableAxis axisPhi{"axisPhi", {200, 0.0f, +2 * TMath::Pi()}, ""}; + ConfigurableAxis axisNclu{"axisNclu", {10, -0.5f, 9.5f}, ""}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for analysis"}; + enum kTable { kBC = 0, kCollision, kTrack, @@ -120,25 +128,43 @@ struct integrationTest { hs->GetXaxis()->SetBinLabel(ii + 1, lTableNames[ii].Data()); // Histograms with related indices: per BC - histos.add("hCollisionsPerBC", "hCollisionsPerBC", HistType::kTH1F, {axisCollisions}); + histos.add("hCollisionsPerBC", "hCollisionsPerBC", HistType::kTH1D, {axisCollisions}); // Histograms with related indices: per collision - histos.add("hTracks", "hTracks", HistType::kTH1F, {axisTracks}); - histos.add("hTracksITS", "hTracksITS", HistType::kTH1F, {axisTracks}); - histos.add("hTracksTPC", "hTracksTPC", HistType::kTH1F, {axisTracks}); - histos.add("hTracksTRD", "hTracksTRD", HistType::kTH1F, {axisTracks}); - histos.add("hTracksTOF", "hTracksTOF", HistType::kTH1F, {axisTracks}); - histos.add("hMFTTracks", "hMFTTracks", HistType::kTH1F, {axisTracks}); - histos.add("hFWDTracks", "hFWDTracks", HistType::kTH1F, {axisTracks}); + histos.add("hTracks", "hTracks", HistType::kTH1D, {axisTracks}); + histos.add("hTracksITS", "hTracksITS", HistType::kTH1D, {axisTracks}); + histos.add("hTracksTPC", "hTracksTPC", HistType::kTH1D, {axisTracks}); + histos.add("hTracksNoTPCOnly", "hTracksNoTPCOnly", HistType::kTH1D, {axisTracks}); + histos.add("hTracksTRD", "hTracksTRD", HistType::kTH1D, {axisTracks}); + histos.add("hTracksTOF", "hTracksTOF", HistType::kTH1D, {axisTracks}); + histos.add("hMFTTracks", "hMFTTracks", HistType::kTH1D, {axisTracks}); + histos.add("hFWDTracks", "hFWDTracks", HistType::kTH1D, {axisTracks}); - histos.add("hV0s", "hV0s", HistType::kTH1F, {axisTracks}); - histos.add("hCascades", "hCascades", HistType::kTH1F, {axisTracks}); + histos.add("hV0s", "hV0s", HistType::kTH1D, {axisTracks}); + histos.add("hCascades", "hCascades", HistType::kTH1D, {axisTracks}); + histos.add("hHasDetector", "hHasDetector", HistType::kTH1D, {axisHasDetector}); if (do2DNTrackCorr) { - histos.add("hTOFvsTRD", "hTOFvsTRD", HistType::kTH2F, {axisTracks2Dtrd, axisTracks2Dtof}); - histos.add("hTOFvsTPC", "hTOFvsTPC", HistType::kTH2F, {axisTracks2Dtpc, axisTracks2Dtof}); - histos.add("hTRDvsTPC", "hTRDvsTPC", HistType::kTH2F, {axisTracks2Dtpc, axisTracks2Dtrd}); - histos.add("hITSvsTPC", "hITSvsTPC", HistType::kTH2F, {axisTracks2Dtpc, axisTracks2Dits}); + histos.add("hTOFvsTRD", "hTOFvsTRD", HistType::kTH2D, {axisTracks2Dtrd, axisTracks2Dtof}); + histos.add("hTOFvsTPC", "hTOFvsTPC", HistType::kTH2D, {axisTracks2Dtpc, axisTracks2Dtof}); + histos.add("hTRDvsTPC", "hTRDvsTPC", HistType::kTH2D, {axisTracks2Dtpc, axisTracks2Dtrd}); + histos.add("hITSvsTPC", "hITSvsTPC", HistType::kTH2D, {axisTracks2Dtpc, axisTracks2Dits}); + } + + // pT histograms + histos.add("hPt", "hPt", HistType::kTH1D, {axisPt}); + histos.add("hPtITS", "hPtITS", HistType::kTH1D, {axisPt}); + histos.add("hPtTPC", "hPtTPC", HistType::kTH1D, {axisPt}); + histos.add("hPtNoTPCOnly", "hPtNoTPCOnly", HistType::kTH1D, {axisPt}); + histos.add("hPtTOF", "hPtTOF", HistType::kTH1D, {axisPt}); + histos.add("hPtTRD", "hPtTRD", HistType::kTH1D, {axisPt}); + + if (doBasicQA) { + // general QA + histos.add("h2dPhiVsEtaAll", "h2dPhiVsEtaAll", HistType::kTH2D, {axisEta, axisPhi}); + histos.add("h2dPhiVsEtaNoTPCOnly", "h2dPhiVsEtaNoTPCOnly", HistType::kTH2D, {axisEta, axisPhi}); + histos.add("hNCluAll", "hNCluAll", HistType::kTH1D, {axisNclu}); + histos.add("hNCluNoTPCOnly", "hNCluNoTPCOnly", HistType::kTH1D, {axisNclu}); } } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* @@ -170,59 +196,87 @@ struct integrationTest { aod::McMFTTrackLabels const& mcmfttracklabels, aod::McFwdTrackLabels const& mcfwdtracklabels) { - histos.fill(HIST("hTableSizes"), (float)kBC + 0.5f, bcs.size()); - histos.fill(HIST("hTableSizes"), (float)kCollision + 0.5f, collisions.size()); - histos.fill(HIST("hTableSizes"), (float)kTrack + 0.5f, tracks.size()); - histos.fill(HIST("hTableSizes"), (float)kTrackCov + 0.5f, trackcovs.size()); - histos.fill(HIST("hTableSizes"), (float)kTrackExtra + 0.5f, trackextras.size()); - histos.fill(HIST("hTableSizes"), (float)kMftTrack + 0.5f, mfttracks.size()); - histos.fill(HIST("hTableSizes"), (float)kFwdTrack + 0.5f, fwdtracks.size()); - histos.fill(HIST("hTableSizes"), (float)kFwdTrackCov + 0.5f, fwdtrackcovs.size()); - histos.fill(HIST("hTableSizes"), (float)kAmbiguousTrack + 0.5f, ambitracks.size()); - histos.fill(HIST("hTableSizes"), (float)kAmbiguousMftTrack + 0.5f, ambimfttracks.size()); - histos.fill(HIST("hTableSizes"), (float)kAmbiguousFwdTrack + 0.5f, ambifwdtracks.size()); - histos.fill(HIST("hTableSizes"), (float)kV0 + 0.5f, v0s.size()); - histos.fill(HIST("hTableSizes"), (float)kCascade + 0.5f, cascades.size()); - histos.fill(HIST("hTableSizes"), (float)kCalo + 0.5f, calos.size()); - histos.fill(HIST("hTableSizes"), (float)kCaloTrigger + 0.5f, calotriggers.size()); - histos.fill(HIST("hTableSizes"), (float)kFDD + 0.5f, fdds.size()); - histos.fill(HIST("hTableSizes"), (float)kFT0 + 0.5f, ft0s.size()); - histos.fill(HIST("hTableSizes"), (float)kV0A + 0.5f, fv0as.size()); - histos.fill(HIST("hTableSizes"), (float)kZDC + 0.5f, zdcs.size()); - histos.fill(HIST("hTableSizes"), (float)kMcCollision + 0.5f, mccollisions.size()); - histos.fill(HIST("hTableSizes"), (float)kMcCollisionLabel + 0.5f, mccollisionlabels.size()); - histos.fill(HIST("hTableSizes"), (float)kMcParticle + 0.5f, mcparticles.size()); - histos.fill(HIST("hTableSizes"), (float)kMcTrackLabel + 0.5f, mctracklabels.size()); - histos.fill(HIST("hTableSizes"), (float)kMcMftTrackLabel + 0.5f, mcmfttracklabels.size()); - histos.fill(HIST("hTableSizes"), (float)kMcFwdTrackLabel + 0.5f, mcfwdtracklabels.size()); - histos.fill(HIST("hTableSizes"), (float)kFrameCounter + 0.5f); + histos.fill(HIST("hTableSizes"), static_cast(kBC) + 0.5f, bcs.size()); + histos.fill(HIST("hTableSizes"), static_cast(kCollision) + 0.5f, collisions.size()); + histos.fill(HIST("hTableSizes"), static_cast(kTrack) + 0.5f, tracks.size()); + histos.fill(HIST("hTableSizes"), static_cast(kTrackCov) + 0.5f, trackcovs.size()); + histos.fill(HIST("hTableSizes"), static_cast(kTrackExtra) + 0.5f, trackextras.size()); + histos.fill(HIST("hTableSizes"), static_cast(kMftTrack) + 0.5f, mfttracks.size()); + histos.fill(HIST("hTableSizes"), static_cast(kFwdTrack) + 0.5f, fwdtracks.size()); + histos.fill(HIST("hTableSizes"), static_cast(kFwdTrackCov) + 0.5f, fwdtrackcovs.size()); + histos.fill(HIST("hTableSizes"), static_cast(kAmbiguousTrack) + 0.5f, ambitracks.size()); + histos.fill(HIST("hTableSizes"), static_cast(kAmbiguousMftTrack) + 0.5f, ambimfttracks.size()); + histos.fill(HIST("hTableSizes"), static_cast(kAmbiguousFwdTrack) + 0.5f, ambifwdtracks.size()); + histos.fill(HIST("hTableSizes"), static_cast(kV0) + 0.5f, v0s.size()); + histos.fill(HIST("hTableSizes"), static_cast(kCascade) + 0.5f, cascades.size()); + histos.fill(HIST("hTableSizes"), static_cast(kCalo) + 0.5f, calos.size()); + histos.fill(HIST("hTableSizes"), static_cast(kCaloTrigger) + 0.5f, calotriggers.size()); + histos.fill(HIST("hTableSizes"), static_cast(kFDD) + 0.5f, fdds.size()); + histos.fill(HIST("hTableSizes"), static_cast(kFT0) + 0.5f, ft0s.size()); + histos.fill(HIST("hTableSizes"), static_cast(kV0A) + 0.5f, fv0as.size()); + histos.fill(HIST("hTableSizes"), static_cast(kZDC) + 0.5f, zdcs.size()); + histos.fill(HIST("hTableSizes"), static_cast(kMcCollision) + 0.5f, mccollisions.size()); + histos.fill(HIST("hTableSizes"), static_cast(kMcCollisionLabel) + 0.5f, mccollisionlabels.size()); + histos.fill(HIST("hTableSizes"), static_cast(kMcParticle) + 0.5f, mcparticles.size()); + histos.fill(HIST("hTableSizes"), static_cast(kMcTrackLabel) + 0.5f, mctracklabels.size()); + histos.fill(HIST("hTableSizes"), static_cast(kMcMftTrackLabel) + 0.5f, mcmfttracklabels.size()); + histos.fill(HIST("hTableSizes"), static_cast(kMcFwdTrackLabel) + 0.5f, mcfwdtracklabels.size()); + histos.fill(HIST("hTableSizes"), static_cast(kFrameCounter) + 0.5f); } PROCESS_SWITCH(integrationTest, processDataModel, "Check data model", true); void processBCs(aod::BC const&, aod::Collisions const& collisions) { - histos.fill(HIST("hCollisionsPerBC"), (float)collisions.size()); + histos.fill(HIST("hCollisionsPerBC"), static_cast(collisions.size())); } PROCESS_SWITCH(integrationTest, processBCs, "Check collisions per BC", true); void processCollisions(aod::Collision const&, FullTracksIU const& tracks, aod::V0s const& v0s, aod::Cascades const& cascades) { - Int_t lHasITS = 0, lHasTPC = 0, lHasTRD = 0, lHasTOF = 0; + Int_t lHasITS = 0, lHasTPC = 0, lHasTRD = 0, lHasTOF = 0, lNotTPCOnly = 0; for (auto& track : tracks) { - if (!track.isPVContributor()) - continue; - if (track.hasITS()) + // TPC only bool + bool isTPConly = track.hasTPC() && !track.hasTOF() && !track.hasTRD() && !track.hasITS(); + histos.fill(HIST("hPt"), track.pt()); + if (track.hasITS()) { lHasITS++; - if (track.hasTPC()) + histos.fill(HIST("hPtITS"), track.pt()); + } + if (track.hasTPC()) { lHasTPC++; - if (track.hasTRD()) + histos.fill(HIST("hPtTPC"), track.pt()); + } + if (!isTPConly) { + lNotTPCOnly++; + histos.fill(HIST("hPtNoTPCOnly"), track.pt()); + } + if (track.hasTRD()) { lHasTRD++; - if (track.hasTOF()) + histos.fill(HIST("hPtTRD"), track.pt()); + } + if (track.hasTOF()) { lHasTOF++; + histos.fill(HIST("hPtTOF"), track.pt()); + } + + if (doBasicQA) { + histos.fill(HIST("hNCluAll"), track.itsNCls()); + histos.fill(HIST("h2dPhiVsEtaAll"), track.eta(), track.phi()); + + if (!isTPConly) { + histos.fill(HIST("hNCluNoTPCOnly"), track.itsNCls()); + histos.fill(HIST("h2dPhiVsEtaNoTPCOnly"), track.eta(), track.phi()); + } + + // encode particle has??? properties here + uint8_t encodedHasInfo = (track.hasITS() << 0) | (track.hasTPC() << 1) | (track.hasTRD() << 2) | (track.hasTOF() << 3); + histos.fill(HIST("hHasDetector"), encodedHasInfo); + } } histos.fill(HIST("hTracks"), tracks.size()); histos.fill(HIST("hTracksITS"), lHasITS); histos.fill(HIST("hTracksTPC"), lHasTPC); + histos.fill(HIST("hTracksNoTPCOnly"), lNotTPCOnly); histos.fill(HIST("hTracksTRD"), lHasTRD); histos.fill(HIST("hTracksTOF"), lHasTOF); if (do2DNTrackCorr) { diff --git a/Common/Tasks/multiplicityQa.cxx b/Common/Tasks/multiplicityQa.cxx index 72fc827606a..3fc2374c2cc 100644 --- a/Common/Tasks/multiplicityQa.cxx +++ b/Common/Tasks/multiplicityQa.cxx @@ -402,12 +402,12 @@ struct MultiplicityQa { histos.fill(HIST("multiplicityQa/h2dFT0MVsNchT0M"), nchFT0, biggestFT0); } - void processFIT(aod::MultsBC const& multsdebug) + void processFIT(aod::MultBCs const& multsdebug) { for (auto& mult : multsdebug) { - histos.fill(HIST("multiplicityQa/hIsolatedFT0A"), mult.multBCFT0A()); - histos.fill(HIST("multiplicityQa/hIsolatedFT0C"), mult.multBCFT0C()); - histos.fill(HIST("multiplicityQa/hIsolatedFT0M"), mult.multBCFT0A() + mult.multBCFT0C()); + histos.fill(HIST("multiplicityQa/hIsolatedFT0A"), mult.multFT0A()); + histos.fill(HIST("multiplicityQa/hIsolatedFT0C"), mult.multFT0C()); + histos.fill(HIST("multiplicityQa/hIsolatedFT0M"), mult.multFT0A() + mult.multFT0C()); } } diff --git a/Common/Tasks/muonQa.cxx b/Common/Tasks/muonQa.cxx new file mode 100644 index 00000000000..a39dfa53295 --- /dev/null +++ b/Common/Tasks/muonQa.cxx @@ -0,0 +1,2514 @@ +// 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 The task for muon QA +/// \author Andrea Ferrero +/// \author Paul Veen +/// \author Chi Zhang + +#include + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/ASoAHelpers.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "CommonUtils/NameConf.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DataFormatsMCH/Cluster.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include "DetectorsBase/Propagator.h" +#include "Field/MagneticField.h" +#include "MathUtils/Cartesian.h" +#include "MCHGeometryTransformer/Transformations.h" +#include "MCHTracking/Track.h" +#include "MCHTracking/TrackExtrap.h" +#include "MCHTracking/TrackParam.h" +#include "MCHTracking/TrackFitter.h" +#include "MCHBase/TrackerParam.h" +#include "GlobalTracking/MatchGlobalFwd.h" +#include "ReconstructionDataFormats/TrackFwd.h" +#include "Common/DataModel/FwdTrackReAlignTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/CollisionAssociationTables.h" + +#include "TGeoGlobalMagField.h" +#include "Math/Vector4D.h" + +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::mch; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using MyEvents = soa::Join; +using MyMuonsWithCov = soa::Join; +using MyMFTs = aod::MFTTracks; + +using SMatrix55 = ROOT::Math::SMatrix>; +using SMatrix5 = ROOT::Math::SVector; + +using MuonPair = std::pair, std::pair>; +using GlobalMuonPair = std::pair>, std::pair>>; + +const int fgNCh = 10; +const int fgNDetElemCh[fgNCh] = {4, 4, 4, 4, 18, 18, 26, 26, 26, 26}; +const int fgSNDetElemCh[fgNCh + 1] = {0, 4, 8, 12, 16, 34, 52, 78, 104, 130, 156}; +const float zAtAbsEnd = -505.; + +constexpr double firstMFTPlaneZ = o2::mft::constants::mft::LayerZCoordinate()[0]; +constexpr double lastMFTPlaneZ = o2::mft::constants::mft::LayerZCoordinate()[9]; + +std::array zRefPlane{ + firstMFTPlaneZ, + lastMFTPlaneZ, + -90.0, + -300.0, + //-505.0, + -520.0}; + +std::vector> referencePlanes{ + {"MFT-begin", 10.0}, + {"MFT-end", 15.0}, + {"Absorber-begin", 20.0}, + {"Absorber-mid", 75.0}, + //{"Absorber-end", 100.0}, + {"MCH-begin", 100.0}}; + +enum MuonExtrapolation { + // Index used to set different options for muon propagation + kToVtx = 0, // propagtion to vertex by default + kToDCA, + kToAbsEnd, + kToZ +}; + +struct VarColl { + int64_t globalIndex = 0; + float x = 0.f; + float y = 0.f; + float z = 0.f; + float covXX = 0.f; + float covYY = 0.f; + int64_t bc = 0; + int multMFT = 0; +}; + +struct VarTrack { + int64_t collisionId = -1; + int64_t globalIndex = 0; + int nClusters = 0; // Only MCH + int sign = 0; + int64_t bc = 0; + int trackType = 0; + float trackTime = 0.f; + + // Basic kinematics + float x = 0.f; + float y = 0.f; + float z = 0.f; + float eta = 0.f; + float phi = 0.f; + float tgl = 0.f; + + float px = 0.f; + float py = 0.f; + float pz = 0.f; + float pT = 0.f; + float p = 0.f; + + // Propagation related infos + float dcaX = 0.f; + float dcaY = 0.f; + float pDca = 0.f; + float rabs = 0.f; + float chi2 = 0.f; + float chi2matching = 0.f; +}; + +struct VarClusters { + vector> posClusters; // (x,y,z) + vector> errorClusters; // (ex,ey) + vector DEIDs; +}; + +struct muonQa { + //// Variables for enabling QA options + struct : ConfigurableGroup { + Configurable fEnableQAMatching{"cfgEnableQAMatching", false, "Enable MCH-MFT matching QA checks"}; + Configurable fEnableQAResidual{"cfgEnableQAResidual", false, "Enable residual QA checks"}; + Configurable fEnableQADCA{"cfgEnableQADCA", false, "Enable DCA QA checks"}; + Configurable fEnableQADimuon{"cfgEnableQADimuon", false, "Enable dimuon QA checks"}; + } configQAs; + + //// Variables for selecting muon tracks + struct : ConfigurableGroup { + Configurable fPMchLow{"cfgPMchLow", 0.0f, ""}; + Configurable fPtMchLow{"cfgPtMchLow", 0.7f, ""}; + Configurable fEtaMchLow{"cfgEtaMchLow", -4.0f, ""}; + Configurable fEtaMchUp{"cfgEtaMchUp", -2.5f, ""}; + Configurable fRabsLow{"cfgRabsLow", 17.6f, ""}; + Configurable fRabsUp{"cfgRabsUp", 89.5f, ""}; + Configurable fSigmaPdcaUp{"cfgPdcaUp", 6.f, ""}; + Configurable fTrackChi2MchUp{"cfgTrackChi2MchUp", 5.f, ""}; + Configurable fMatchingChi2MchMidUp{"cfgMatchingChi2MchMidUp", 999.f, ""}; + } configMuons; + + //// Variables for selecting mft tracks + struct : ConfigurableGroup { + Configurable fEtaMftLow{"cfgEtaMftlow", -3.6f, ""}; + Configurable fEtaMftUp{"cfgEtaMftup", -2.5f, ""}; + Configurable fTrackNClustMftLow{"cfgTrackNClustMftLow", 7, ""}; + Configurable fTrackChi2MftUp{"cfgTrackChi2MftUp", 999.f, ""}; + } configMFTs; + + //// Variables for selecting global tracks + Configurable fMatchingChi2MftMchUp{"cfgMatchingChi2MftMchUp", 50.f, ""}; + + //// Variables for alignment corrections + Configurable fEnableMFTAlignmentCorrections{"cfgEnableMFTAlignmentCorrections", false, ""}; + + //// Variables for re-alignment setup + struct : ConfigurableGroup { + Configurable fDoRealign{"cfgDoRealign", false, "Switch to apply re-alignment"}; + Configurable fChamberResolutionX{"cfgChamberResolutionX", 0.4, "Chamber resolution along X configuration for refit"}; // 0.4cm pp, 0.2cm PbPb + Configurable fChamberResolutionY{"cfgChamberResolutionY", 0.4, "Chamber resolution along Y configuration for refit"}; // 0.4cm pp, 0.2cm PbPb + Configurable fSigmaCutImprove{"cfgSigmaCutImprove", 6., "Sigma cut for track improvement"}; + } configRealign; + + /// Variables to event mixing criteria + struct : ConfigurableGroup { + Configurable fEventMaxDeltaNMFT{"cfgEventMaxDeltaNMFT", 1, ""}; + Configurable fEventMaxDeltaVtxZ{"cfgEventMaxDeltaVtxZ", 1.f, ""}; + Configurable fEventMinDeltaBc{"cfgEventMinDeltaBc", 500, ""}; + } configMixing; + + //// Variables for ccdb + struct : ConfigurableGroup { + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable geoPathRealign{"geoPathRealign", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable nolaterthan{"ccdb-no-later-than-ref", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object of reference basis"}; + Configurable nolaterthanRealign{"ccdb-no-later-than-new", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object of new basis"}; + } configCCDB; + + //// Variables for histograms configuration + Configurable fNCandidatesMax{"nCandidatesMax", 5, ""}; + + parameters::GRPMagField* grpmag = nullptr; + TrackFitter trackFitter; // Track fitter from MCH tracking library + + globaltracking::MatchGlobalFwd mMatching; + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + double mImproveCutChi2; // Chi2 cut for track improvement. + Service ccdb; + o2::field::MagneticField* fieldB = nullptr; + double Bz; // Bz for MFT + + geo::TransformationCreator transformation; + map transformRef; // reference geometry w.r.t track data + map transformNew; // new geometry + TGeoManager* geoNew = nullptr; + TGeoManager* geoRef = nullptr; + + Preslice perMuon = aod::fwdtrkcl::fwdtrackId; + Preslice fwdtracksPerCollision = aod::fwdtrack::collisionId; + Preslice mftPerCollision = aod::fwdtrack::collisionId; + + HistogramRegistry registry{"registry", {}}; + HistogramRegistry registryDCA{"registryDCA", {}}; + HistogramRegistry registryResiduals{"registryResiduals", {}}; + HistogramRegistry registryResidualsMFT{"registryResidualsMFT", {}}; + HistogramRegistry registryResidualsMCH{"registryResidualsMCH", {}}; + HistogramRegistry registryDimuon{"registryDimuon", {}}; + + std::array quadrants = {"Q0", "Q1", "Q2", "Q3"}; + + std::array, 3>, 4>, 2> dcaHistos; + std::array, 3>, 4>, 2> dcaHistosMixedEvents; + + std::array, 4>, 6> trackResidualsHistos; + std::array, 4>, 6> trackResidualsHistosMixedEvents; + + std::array, 10>, 4> residualsHistos; + std::array, 10>, 4> residualsHistosMixedEvents; + + std::array, 10>, 2>, 2> residualsHistosPerDE; + std::array, 10>, 2>, 2> residualsHistosPerDEMixedEvents; + + std::array, 10>, 2>, 2> mchResidualsHistosPerDE; + std::array, 10>, 2>, 2> mchResidualsHistosPerDEMixedEvents; + + VarTrack fgValuesMCH; + VarTrack fgValuesMCHpv; + VarTrack fgValuesMFT; + VarTrack fgValuesGlobal; + vector fgValuesCandidates; + + void CreateBasicHistograms() + { + // ====================== + // Muons plots + // ====================== + + AxisSpec chi2Axis = {1000, 0, 1000, "chi2"}; + AxisSpec momentumAxis = {1000, 0, 1000, "p (GeV/c)"}; + AxisSpec transverseMomentumAxis = {1000, 0, 100, "p_{T} (GeV/c)"}; + AxisSpec etaAxis = {80, -5, -1, "#eta"}; + AxisSpec rAbsAxis = {100, 0., 100.0, "R_{abs} (cm)"}; + AxisSpec dcaAxis = {400, 0.0, 20.0, "DCA"}; + AxisSpec pdcaAxis = {5000, 0.0, 5000.0, "p #times DCA"}; + AxisSpec phiAxis = {360, -180.0, 180.0, "#phi (degrees)"}; + + registry.add("muons/TrackChi2", "MCH track #chi^{2}", {HistType::kTH1F, {chi2Axis}}); + registry.add("muons/TrackP", "MCH track momentum", {HistType::kTH1F, {momentumAxis}}); + registry.add("muons/TrackPt", "MCH track transverse momentum", {HistType::kTH1F, {transverseMomentumAxis}}); + registry.add("muons/TrackEta", "MCH track #eta", {HistType::kTH1F, {etaAxis}}); + registry.add("muons/TrackRabs", "MCH track R_{abs}", {HistType::kTH1F, {rAbsAxis}}); + registry.add("muons/TrackDCA", "MCH track DCA", {HistType::kTH1F, {dcaAxis}}); + registry.add("muons/TrackPDCA", "MCH track p #times DCA", {HistType::kTH1F, {pdcaAxis}}); + registry.add("muons/TrackPhi", "MCH track #phi", {HistType::kTH1F, {phiAxis}}); + + // ====================== + // Global muons plots + // ====================== + int nTrackTypes = static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MCHStandaloneTrack) + 1; + AxisSpec trackTypeAxis = {static_cast(nTrackTypes), 0.0, static_cast(nTrackTypes), "track type"}; + registry.add("global-muons/nTracksPerType", "Number of tracks per type", {HistType::kTH1F, {trackTypeAxis}}); + + AxisSpec nCandidatesAxis = {static_cast(fNCandidatesMax), 0.0, static_cast(fNCandidatesMax), "match candidate rank"}; + registry.add("global-muons/NCandidates", "Number of MFT-MCH match candidates", {HistType::kTH1F, {nCandidatesAxis}}); + registry.add("global-muons/MatchChi2", "MFT-MCH match chi2", {HistType::kTH2F, {chi2Axis, nCandidatesAxis}}); + + registry.add("global-muons/TrackChi2", "Muon track #chi^{2}", {HistType::kTH1F, {chi2Axis}}); + registry.add("global-muons/TrackP", "Muon track momentum", {HistType::kTH1F, {momentumAxis}}); + registry.add("global-muons/TrackPt", "Muon track transverse momentum", {HistType::kTH1F, {transverseMomentumAxis}}); + registry.add("global-muons/TrackEta", "Muon track #eta", {HistType::kTH1F, {etaAxis}}); + registry.add("global-muons/TrackRabs", "Muon track R_{abs}", {HistType::kTH1F, {rAbsAxis}}); + registry.add("global-muons/TrackDCA", "Muon track DCA", {HistType::kTH1F, {dcaAxis}}); + registry.add("global-muons/TrackPDCA", "Muon track p #times DCA", {HistType::kTH1F, {pdcaAxis}}); + registry.add("global-muons/TrackPhi", "Muon track #phi", {HistType::kTH1F, {phiAxis}}); + + // ====================== + // Global muon plots with matching cuts + // ====================== + + if (configQAs.fEnableQAMatching) { + AxisSpec dbcAxis = {1000, -500, 500, "#Delta_{BC}"}; + registry.add("global-matches/BCdifference", "MCH-MFT BC difference", {HistType::kTH1F, {dbcAxis}}); + + AxisSpec nClustersAxis = {20, 0, 20, "# of MFT clusters per track"}; + + registry.add("global-matches/MatchChi2", "MFT-MCH match chi2", {HistType::kTH1F, {chi2Axis}}); + + registry.add("global-matches/TrackChi2_MFT", "MFT track #chi^{2}", {HistType::kTH1F, {chi2Axis}}); + registry.add("global-matches/TrackNclusters_MFT", "MFT track Nclusters", {HistType::kTH1F, {nClustersAxis}}); + + registry.add("global-matches/TrackChi2", "Muon track #chi^{2}", {HistType::kTH1F, {chi2Axis}}); + registry.add("global-matches/TrackP", "Muon track momentum", {HistType::kTH1F, {momentumAxis}}); + registry.add("global-matches/TrackPt", "Muon track transverse momentum", {HistType::kTH1F, {transverseMomentumAxis}}); + registry.add("global-matches/TrackEta", "Muon track #eta", {HistType::kTH1F, {etaAxis}}); + registry.add("global-matches/TrackRabs", "Muon track R_{abs}", {HistType::kTH1F, {rAbsAxis}}); + registry.add("global-matches/TrackDCA", "Muon track DCA", {HistType::kTH1F, {dcaAxis}}); + registry.add("global-matches/TrackPDCA", "Muon track p #times DCA", {HistType::kTH1F, {pdcaAxis}}); + registry.add("global-matches/TrackPhi", "Muon track #phi", {HistType::kTH1F, {phiAxis}}); + + registry.add("global-matches/TrackP_glo", "Global muon track momentum", {HistType::kTH1F, {momentumAxis}}); + registry.add("global-matches/TrackPt_glo", "Global muon track transverse momentum", {HistType::kTH1F, {transverseMomentumAxis}}); + registry.add("global-matches/TrackEta_glo", "Global muon track #eta", {HistType::kTH1F, {etaAxis}}); + registry.add("global-matches/TrackDCA_glo", "Global muon track DCA", {HistType::kTH1F, {dcaAxis}}); + registry.add("global-matches/TrackPhi_glo", "Global muon track #phi", {HistType::kTH1F, {phiAxis}}); + } + + AxisSpec momentumCorrelationAxis = {100, 0, 100, "momentum (GeV/c)"}; + AxisSpec momentumDeltaAxis = {100, -1, 1, "#DeltaP (GeV/c)"}; + // Momentum correlations + registry.add("global-muons/MomentumCorrelation_Global_vs_Muon", + "P_{global} vs. P_{MCH}", + {HistType::kTH2F, {momentumCorrelationAxis, momentumCorrelationAxis}}); + registry.add("global-muons/MomentumDifference_Global_vs_Muon", + "(P_{global} - P_{MCH}) / P_{MCH} vs. P_{MCH}", + {HistType::kTH2F, {momentumCorrelationAxis, momentumDeltaAxis}}); + registry.add("global-muons/MomentumCorrelation_subleading_vs_leading", + "P_{subleading_match} vs. P_{leading_match}", + {HistType::kTH2F, {momentumCorrelationAxis, momentumCorrelationAxis}}); + registry.add("global-muons/MomentumDifference_subleading_vs_leading", + "(P_{subleading_match} - P_{leading_match}) / P_{leading_match} vs. P_{leading_match}", + {HistType::kTH2F, {momentumCorrelationAxis, momentumDeltaAxis}}); + + // AxisSpec etaAxis = {100, -5.0, -2.0, "#eta"}; + AxisSpec etaCorrelationAxis = {80, -5.0, -1.0, "#eta"}; + AxisSpec etaDeltaAxis = {100, -0.2, 0.2, "#Delta#eta"}; + // Eta correlations + registry.add("global-muons/EtaCorrelation_Global_vs_Muon", + "#eta_{global} vs. #eta_{MCH}", + {HistType::kTH2F, {etaCorrelationAxis, etaCorrelationAxis}}); + registry.add("global-muons/EtaDifference_Global_vs_Muon", + "(#eta_{global} - #eta_{MCH}) / #eta_{MCH} vs. #eta_{MCH}", + {HistType::kTH2F, {etaCorrelationAxis, etaDeltaAxis}}); + registry.add("global-muons/EtaCorrelation_subleading_vs_leading", + "#eta_{subleading_match} vs. #eta_{leading_match}", + {HistType::kTH2F, {etaCorrelationAxis, etaCorrelationAxis}}); + registry.add("global-muons/EtaDifference_subleading_vs_leading", + "(#eta_{subleading_match} - #eta_{leading_match}) / #eta_{leading_match} vs. #eta_{leading_match}", + {HistType::kTH2F, {etaCorrelationAxis, etaDeltaAxis}}); + } + + void CreateDetailedHistograms() + { + AxisSpec dcaxMFTAxis = {400, -0.5, 0.5, "DCA_{x} (cm)"}; + AxisSpec dcayMFTAxis = {400, -0.5, 0.5, "DCA_{y} (cm)"}; + AxisSpec dcaxMCHAxis = {400, -10.0, 10.0, "DCA_{x} (cm)"}; + AxisSpec dcayMCHAxis = {400, -10.0, 10.0, "DCA_{y} (cm)"}; + AxisSpec dcazAxis = {20, -10.0, 10.0, "DCA_{z} (cm)"}; + AxisSpec dxAxis = {600, -30.0, 30.0, "#Delta x (cm)"}; + AxisSpec dyAxis = {600, -30.0, 30.0, "#Delta y (cm)"}; + AxisSpec thetaxAxis = {10, 0.0, 20.0, "#theta_{x} (degrees)"}; + AxisSpec dThetaxAxis = {500, -5.0, 5.0, "#Delta#theta_{x} (degrees)"}; + AxisSpec thetayAxis = {10, 0.0, 20.0, "#theta_{y} (degrees)"}; + AxisSpec dThetayAxis = {500, -5.0, 5.0, "#Delta#theta_{y} (degrees)"}; + AxisSpec phiAxis = {360, -180.0, 180.0, "#phi (degrees)"}; + AxisSpec dPhiAxis = {200, -20.0, 20.0, "#Delta#phi (degrees)"}; + + if (configQAs.fEnableQAResidual) { + for (size_t i = 0; i < referencePlanes.size(); i++) { + const auto& refPLane = referencePlanes[i]; + AxisSpec xAxis = {10, 0, refPLane.second, "|x| (cm)"}; + AxisSpec yAxis = {10, 0, refPLane.second, "|y| (cm)"}; + for (size_t j = 0; j < quadrants.size(); j++) { + const auto& quadrant = quadrants[j]; + std::string histPath = std::string("Alignment/same-event/Residuals/ReferencePlanes/") + refPLane.first + "/" + quadrant + "/"; + trackResidualsHistos[i][j]["dx_vs_x"] = registry.add((histPath + "dx_vs_x").c_str(), std::format("#Delta x vs. |x| - {}", quadrant).c_str(), {HistType::kTH2F, {xAxis, dxAxis}}); + trackResidualsHistos[i][j]["dx_vs_y"] = registry.add((histPath + "dx_vs_y").c_str(), std::format("#Delta x vs. |y| - {}", quadrant).c_str(), {HistType::kTH2F, {yAxis, dxAxis}}); + trackResidualsHistos[i][j]["dy_vs_x"] = registry.add((histPath + "dy_vs_x").c_str(), std::format("#Delta y vs. |x| - {}", quadrant).c_str(), {HistType::kTH2F, {xAxis, dyAxis}}); + trackResidualsHistos[i][j]["dy_vs_y"] = registry.add((histPath + "dy_vs_y").c_str(), std::format("#Delta y vs. |y| - {}", quadrant).c_str(), {HistType::kTH2F, {yAxis, dyAxis}}); + + trackResidualsHistos[i][j]["dthetax_vs_x"] = registry.add((histPath + "dthetax_vs_x").c_str(), std::format("#Delta #theta_x vs. |x| - {}", quadrant).c_str(), {HistType::kTH2F, {xAxis, dThetaxAxis}}); + trackResidualsHistos[i][j]["dthetax_vs_y"] = registry.add((histPath + "dthetax_vs_y").c_str(), std::format("#Delta #theta_x vs. |y| - {}", quadrant).c_str(), {HistType::kTH2F, {yAxis, dThetaxAxis}}); + trackResidualsHistos[i][j]["dthetax_vs_thetax"] = registry.add((histPath + "dthetax_vs_thetax").c_str(), std::format("#Delta #theta_x vs. |#theta_x| - {}", quadrant).c_str(), {HistType::kTH2F, {thetaxAxis, dThetaxAxis}}); + + trackResidualsHistos[i][j]["dthetay_vs_x"] = registry.add((histPath + "dthetay_vs_x").c_str(), std::format("#Delta #theta_y vs. |x| - {}", quadrant).c_str(), {HistType::kTH2F, {xAxis, dThetayAxis}}); + trackResidualsHistos[i][j]["dthetay_vs_y"] = registry.add((histPath + "dthetay_vs_y").c_str(), std::format("#Delta #theta_y vs. |y| - {}", quadrant).c_str(), {HistType::kTH2F, {yAxis, dThetayAxis}}); + trackResidualsHistos[i][j]["dthetay_vs_thetay"] = registry.add((histPath + "dthetay_vs_thetay").c_str(), std::format("#Delta #theta_y vs. |#theta_y| - {}", quadrant).c_str(), {HistType::kTH2F, {thetayAxis, dThetayAxis}}); + + // mixed events + histPath = std::string("Alignment/mixed-event/Residuals/ReferencePlanes/") + refPLane.first + "/" + quadrant + "/"; + trackResidualsHistosMixedEvents[i][j]["dx_vs_x"] = registry.add((histPath + "dx_vs_x").c_str(), std::format("#Delta x vs. |x| - {}", quadrant).c_str(), {HistType::kTH2F, {xAxis, dxAxis}}); + trackResidualsHistosMixedEvents[i][j]["dx_vs_y"] = registry.add((histPath + "dx_vs_y").c_str(), std::format("#Delta x vs. |y| - {}", quadrant).c_str(), {HistType::kTH2F, {yAxis, dxAxis}}); + trackResidualsHistosMixedEvents[i][j]["dy_vs_x"] = registry.add((histPath + "dy_vs_x").c_str(), std::format("#Delta y vs. |x| - {}", quadrant).c_str(), {HistType::kTH2F, {xAxis, dyAxis}}); + trackResidualsHistosMixedEvents[i][j]["dy_vs_y"] = registry.add((histPath + "dy_vs_y").c_str(), std::format("#Delta y vs. |y| - {}", quadrant).c_str(), {HistType::kTH2F, {yAxis, dyAxis}}); + + trackResidualsHistosMixedEvents[i][j]["dthetax_vs_x"] = registry.add((histPath + "dthetax_vs_x").c_str(), std::format("#Delta #theta_x vs. |x| - {}", quadrant).c_str(), {HistType::kTH2F, {xAxis, dThetaxAxis}}); + trackResidualsHistosMixedEvents[i][j]["dthetax_vs_y"] = registry.add((histPath + "dthetax_vs_y").c_str(), std::format("#Delta #theta_x vs. |y| - {}", quadrant).c_str(), {HistType::kTH2F, {yAxis, dThetaxAxis}}); + trackResidualsHistosMixedEvents[i][j]["dthetax_vs_thetax"] = registry.add((histPath + "dthetax_vs_thetax").c_str(), std::format("#Delta #theta_x vs. |#theta_x| - {}", quadrant).c_str(), {HistType::kTH2F, {thetaxAxis, dThetaxAxis}}); + + trackResidualsHistosMixedEvents[i][j]["dthetay_vs_x"] = registry.add((histPath + "dthetay_vs_x").c_str(), std::format("#Delta #theta_y vs. |x| - {}", quadrant).c_str(), {HistType::kTH2F, {xAxis, dThetayAxis}}); + trackResidualsHistosMixedEvents[i][j]["dthetay_vs_y"] = registry.add((histPath + "dthetay_vs_y").c_str(), std::format("#Delta #theta_y vs. |y| - {}", quadrant).c_str(), {HistType::kTH2F, {yAxis, dThetayAxis}}); + trackResidualsHistosMixedEvents[i][j]["dthetay_vs_thetay"] = registry.add((histPath + "dthetay_vs_thetay").c_str(), std::format("#Delta #theta_y vs. |#theta_y| - {}", quadrant).c_str(), {HistType::kTH2F, {thetayAxis, dThetayAxis}}); + } + } + + for (size_t j = 0; j < quadrants.size(); j++) { + const auto& quadrant = quadrants[j]; + AxisSpec xAxis = {20, 0, 200, "|x| (cm)"}; + AxisSpec yAxis = {10, 0, 200, "|y| (cm)"}; + for (int chamber = 0; chamber < 10; chamber++) { + std::string histPath = std::string("Alignment/same-event/Residuals/MFT/") + quadrant + "/CH" + std::to_string(chamber + 1) + "/"; + // Delta x at cluster + residualsHistos[j][chamber]["dx_vs_x"] = registryResiduals.add((histPath + "dx_vs_x").c_str(), "Cluster x residual vs. x", {HistType::kTH2F, {xAxis, dxAxis}}); + residualsHistos[j][chamber]["dx_vs_y"] = registryResiduals.add((histPath + "dx_vs_y").c_str(), "Cluster x residual vs. y", {HistType::kTH2F, {yAxis, dxAxis}}); + residualsHistos[j][chamber]["dy_vs_x"] = registryResiduals.add((histPath + "dy_vs_x").c_str(), "Cluster y residual vs. x", {HistType::kTH2F, {xAxis, dyAxis}}); + residualsHistos[j][chamber]["dy_vs_y"] = registryResiduals.add((histPath + "dy_vs_y").c_str(), "Cluster y residual vs. y", {HistType::kTH2F, {yAxis, dyAxis}}); + + // mixed events + histPath = std::string("Alignment/mixed-event/Residuals/MFT/") + quadrant + "/CH" + std::to_string(chamber + 1) + "/"; + // Delta x at cluster + residualsHistosMixedEvents[j][chamber]["dx_vs_x"] = registryResiduals.add((histPath + "dx_vs_x").c_str(), "Cluster x residual vs. x", {HistType::kTH2F, {xAxis, dxAxis}}); + residualsHistosMixedEvents[j][chamber]["dx_vs_y"] = registryResiduals.add((histPath + "dx_vs_y").c_str(), "Cluster x residual vs. y", {HistType::kTH2F, {yAxis, dxAxis}}); + residualsHistosMixedEvents[j][chamber]["dy_vs_x"] = registryResiduals.add((histPath + "dy_vs_x").c_str(), "Cluster y residual vs. x", {HistType::kTH2F, {xAxis, dyAxis}}); + residualsHistosMixedEvents[j][chamber]["dy_vs_y"] = registryResiduals.add((histPath + "dy_vs_y").c_str(), "Cluster y residual vs. y", {HistType::kTH2F, {yAxis, dyAxis}}); + } + } + + for (size_t i = 0; i < 2; i++) { + std::string topBottom = (i == 0) ? "top" : "bottom"; + AxisSpec deAxis = {26, 0, 26, "DE index"}; + AxisSpec phiAxis = {16, -180, 180, "#phi (degrees)"}; + for (size_t j = 0; j < 2; j++) { + std::string sign = (j == 0) ? "positive" : "negative"; + for (int chamber = 0; chamber < 10; chamber++) { + std::string histPath = std::string("Alignment/same-event/Residuals/MFT/MFT_") + topBottom + "/" + sign + "/CH" + std::to_string(chamber + 1) + "/"; + // Delta x and y at cluster + residualsHistosPerDE[i][j][chamber]["dx_vs_de"] = registryResidualsMFT.add((histPath + "dx_vs_de").c_str(), "Cluster x residual vs. DE index", {HistType::kTH2F, {deAxis, dxAxis}}); + residualsHistosPerDE[i][j][chamber]["dy_vs_de"] = registryResidualsMFT.add((histPath + "dy_vs_de").c_str(), "Cluster y residual vs. DE index", {HistType::kTH2F, {deAxis, dxAxis}}); + + residualsHistosPerDE[i][j][chamber]["dx_vs_phi"] = registryResidualsMFT.add((histPath + "dx_vs_phi").c_str(), "Cluster x residual vs. cluster #phi", {HistType::kTH2F, {phiAxis, dxAxis}}); + residualsHistosPerDE[i][j][chamber]["dy_vs_phi"] = registryResidualsMFT.add((histPath + "dy_vs_phi").c_str(), "Cluster y residual vs. cluster #phi", {HistType::kTH2F, {phiAxis, dxAxis}}); + + // mixed events + histPath = std::string("Alignment/mixed-event/Residuals/MFT/MFT_") + topBottom + "/" + sign + "/CH" + std::to_string(chamber + 1) + "/"; + // Delta x and y at cluster + residualsHistosPerDEMixedEvents[i][j][chamber]["dx_vs_de"] = registryResidualsMFT.add((histPath + "dx_vs_de").c_str(), "Cluster x residual vs. DE index", {HistType::kTH2F, {deAxis, dxAxis}}); + residualsHistosPerDEMixedEvents[i][j][chamber]["dy_vs_de"] = registryResidualsMFT.add((histPath + "dy_vs_de").c_str(), "Cluster y residual vs. DE index", {HistType::kTH2F, {deAxis, dxAxis}}); + + residualsHistosPerDEMixedEvents[i][j][chamber]["dx_vs_phi"] = registryResidualsMFT.add((histPath + "dx_vs_phi").c_str(), "Cluster x residual vs. cluster #phi", {HistType::kTH2F, {phiAxis, dxAxis}}); + residualsHistosPerDEMixedEvents[i][j][chamber]["dy_vs_phi"] = registryResidualsMFT.add((histPath + "dy_vs_phi").c_str(), "Cluster y residual vs. cluster #phi", {HistType::kTH2F, {phiAxis, dxAxis}}); + } + } + } + + for (size_t i = 0; i < 2; i++) { + std::string topBottom = (i == 0) ? "top" : "bottom"; + AxisSpec deAxis = {26, 0, 26, "DE index"}; + for (size_t j = 0; j < 2; j++) { + std::string sign = (j == 0) ? "positive" : "negative"; + for (int chamber = 0; chamber < 10; chamber++) { + std::string histPath = std::string("Alignment/same-event/Residuals/MCH/MCH_") + topBottom + "/" + sign + "/CH" + std::to_string(chamber + 1) + "/"; + // Delta x and y at cluster + mchResidualsHistosPerDE[i][j][chamber]["dx_vs_de"] = registryResidualsMCH.add((histPath + "dx_vs_de").c_str(), "Cluster x residual vs. DE index", {HistType::kTH2F, {deAxis, dxAxis}}); + mchResidualsHistosPerDE[i][j][chamber]["dy_vs_de"] = registryResidualsMCH.add((histPath + "dy_vs_de").c_str(), "Cluster y residual vs. DE index", {HistType::kTH2F, {deAxis, dxAxis}}); + + // mixed events + histPath = std::string("Alignment/mixed-event/Residuals/MCH/MCH_") + topBottom + "/" + sign + "/CH" + std::to_string(chamber + 1) + "/"; + // Delta x and y at cluster + mchResidualsHistosPerDEMixedEvents[i][j][chamber]["dx_vs_de"] = registryResidualsMCH.add((histPath + "dx_vs_de").c_str(), "Cluster x residual vs. DE index", {HistType::kTH2F, {deAxis, dxAxis}}); + mchResidualsHistosPerDEMixedEvents[i][j][chamber]["dy_vs_de"] = registryResidualsMCH.add((histPath + "dy_vs_de").c_str(), "Cluster y residual vs. DE index", {HistType::kTH2F, {deAxis, dxAxis}}); + } + } + } + } + + if (configQAs.fEnableQADCA) { + for (size_t j = 0; j < quadrants.size(); j++) { + const auto& quadrant = quadrants[j]; + std::string histPath = std::string("Alignment/same-event/DCA/MFT/") + quadrant + "/"; + dcaHistos[0][j][0]["DCA_x"] = registryDCA.add((histPath + "DCA_x").c_str(), std::format("DCA(x) - {}", quadrant).c_str(), {HistType::kTH1F, {dcaxMFTAxis}}); + dcaHistos[0][j][1]["DCA_x"] = registryDCA.add((histPath + "DCA_x_pos").c_str(), std::format("DCA(x) - {} charge > 0", quadrant).c_str(), {HistType::kTH1F, {dcaxMFTAxis}}); + dcaHistos[0][j][2]["DCA_x"] = registryDCA.add((histPath + "DCA_x_neg").c_str(), std::format("DCA(x) - {} charge < 0", quadrant).c_str(), {HistType::kTH1F, {dcaxMFTAxis}}); + dcaHistos[0][j][0]["DCA_y"] = registryDCA.add((histPath + "DCA_y").c_str(), std::format("DCA(y) - {}", quadrant).c_str(), {HistType::kTH1F, {dcayMFTAxis}}); + dcaHistos[0][j][1]["DCA_y"] = registryDCA.add((histPath + "DCA_y_pos").c_str(), std::format("DCA(y) - {} charge > 0", quadrant).c_str(), {HistType::kTH1F, {dcayMFTAxis}}); + dcaHistos[0][j][2]["DCA_y"] = registryDCA.add((histPath + "DCA_y_neg").c_str(), std::format("DCA(y) - {} charge < 0", quadrant).c_str(), {HistType::kTH1F, {dcayMFTAxis}}); + dcaHistos[0][j][0]["DCA_x_vs_z"] = registryDCA.add((histPath + "DCA_x_vs_z").c_str(), std::format("DCA(x) vs. z - {}", quadrant).c_str(), {HistType::kTH2F, {dcazAxis, dcaxMFTAxis}}); + dcaHistos[0][j][0]["DCA_y_vs_z"] = registryDCA.add((histPath + "DCA_y_vs_z").c_str(), std::format("DCA(y) vs. z - {}", quadrant).c_str(), {HistType::kTH2F, {dcazAxis, dcayMFTAxis}}); + + histPath = std::string("Alignment/same-event/DCA/MCH/") + quadrant + "/"; + dcaHistos[1][j][0]["DCA_x"] = registryDCA.add((histPath + "DCA_x").c_str(), std::format("DCA(x) - {}", quadrant).c_str(), {HistType::kTH1F, {dcaxMCHAxis}}); + dcaHistos[1][j][1]["DCA_x"] = registryDCA.add((histPath + "DCA_x_pos").c_str(), std::format("DCA(x) - {} charge > 0", quadrant).c_str(), {HistType::kTH1F, {dcaxMCHAxis}}); + dcaHistos[1][j][2]["DCA_x"] = registryDCA.add((histPath + "DCA_x_neg").c_str(), std::format("DCA(x) - {} charge < 0", quadrant).c_str(), {HistType::kTH1F, {dcaxMCHAxis}}); + dcaHistos[1][j][0]["DCA_y"] = registryDCA.add((histPath + "DCA_y").c_str(), std::format("DCA(y) - {}", quadrant).c_str(), {HistType::kTH1F, {dcayMCHAxis}}); + dcaHistos[1][j][1]["DCA_y"] = registryDCA.add((histPath + "DCA_y_pos").c_str(), std::format("DCA(y) - {} charge > 0", quadrant).c_str(), {HistType::kTH1F, {dcayMCHAxis}}); + dcaHistos[1][j][2]["DCA_y"] = registryDCA.add((histPath + "DCA_y_neg").c_str(), std::format("DCA(y) - {} charge < 0", quadrant).c_str(), {HistType::kTH1F, {dcayMCHAxis}}); + + histPath = std::string("Alignment/mixed-event/DCA/MFT/") + quadrant + "/"; + dcaHistosMixedEvents[0][j][0]["DCA_x"] = registryDCA.add((histPath + "DCA_x").c_str(), std::format("DCA(x) - {}", quadrant).c_str(), {HistType::kTH1F, {dcaxMFTAxis}}); + dcaHistosMixedEvents[0][j][1]["DCA_x"] = registryDCA.add((histPath + "DCA_x_pos").c_str(), std::format("DCA(x) - {} charge > 0", quadrant).c_str(), {HistType::kTH1F, {dcaxMFTAxis}}); + dcaHistosMixedEvents[0][j][2]["DCA_x"] = registryDCA.add((histPath + "DCA_x_neg").c_str(), std::format("DCA(x) - {} charge < 0", quadrant).c_str(), {HistType::kTH1F, {dcaxMFTAxis}}); + dcaHistosMixedEvents[0][j][0]["DCA_y"] = registryDCA.add((histPath + "DCA_y").c_str(), std::format("DCA(y) - {}", quadrant).c_str(), {HistType::kTH1F, {dcayMFTAxis}}); + dcaHistosMixedEvents[0][j][1]["DCA_y"] = registryDCA.add((histPath + "DCA_y_pos").c_str(), std::format("DCA(y) - {} charge > 0", quadrant).c_str(), {HistType::kTH1F, {dcayMFTAxis}}); + dcaHistosMixedEvents[0][j][2]["DCA_y"] = registryDCA.add((histPath + "DCA_y_neg").c_str(), std::format("DCA(y) - {} charge < 0", quadrant).c_str(), {HistType::kTH1F, {dcayMFTAxis}}); + dcaHistosMixedEvents[0][j][0]["DCA_x_vs_z"] = registryDCA.add((histPath + "DCA_x_vs_z").c_str(), std::format("DCA(x) vs. z - {}", quadrant).c_str(), {HistType::kTH2F, {dcazAxis, dcaxMFTAxis}}); + dcaHistosMixedEvents[0][j][0]["DCA_y_vs_z"] = registryDCA.add((histPath + "DCA_y_vs_z").c_str(), std::format("DCA(y) vs. z - {}", quadrant).c_str(), {HistType::kTH2F, {dcazAxis, dcayMFTAxis}}); + + histPath = std::string("Alignment/mixed-event/DCA/MCH/") + quadrant + "/"; + dcaHistosMixedEvents[1][j][0]["DCA_x"] = registryDCA.add((histPath + "DCA_x").c_str(), std::format("DCA(x) - {}", quadrant).c_str(), {HistType::kTH1F, {dcaxMCHAxis}}); + dcaHistosMixedEvents[1][j][1]["DCA_x"] = registryDCA.add((histPath + "DCA_x_pos").c_str(), std::format("DCA(x) - {} charge > 0", quadrant).c_str(), {HistType::kTH1F, {dcaxMCHAxis}}); + dcaHistosMixedEvents[1][j][2]["DCA_x"] = registryDCA.add((histPath + "DCA_x_neg").c_str(), std::format("DCA(x) - {} charge < 0", quadrant).c_str(), {HistType::kTH1F, {dcaxMCHAxis}}); + dcaHistosMixedEvents[1][j][0]["DCA_y"] = registryDCA.add((histPath + "DCA_y").c_str(), std::format("DCA(y) - {}", quadrant).c_str(), {HistType::kTH1F, {dcayMCHAxis}}); + dcaHistosMixedEvents[1][j][1]["DCA_y"] = registryDCA.add((histPath + "DCA_y_pos").c_str(), std::format("DCA(y) - {} charge > 0", quadrant).c_str(), {HistType::kTH1F, {dcayMCHAxis}}); + dcaHistosMixedEvents[1][j][2]["DCA_y"] = registryDCA.add((histPath + "DCA_y_neg").c_str(), std::format("DCA(y) - {} charge < 0", quadrant).c_str(), {HistType::kTH1F, {dcayMCHAxis}}); + } + } + + if (configQAs.fEnableQADimuon) { + AxisSpec invMassAxis = {400, 1, 5, "M_{#mu^{+}#mu^{-}} (GeV/c^{2})"}; + AxisSpec invMassCorrelationAxis = {80, 0, 8, "M_{#mu^{+}#mu^{-}} (GeV/c^{2})"}; + AxisSpec invMassAxisFull = {5000, 0, 100, "M_{#mu^{+}#mu^{-}} (GeV/c^{2})"}; + // MCH-MID tracks with MCH acceptance cuts + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_MuonCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxisFull}}); + // MCH-MID tracks with MCH acceptance cuts and combinations from the top and bottom halfs of MCH + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_MuonCuts_TT", "#mu^{+}#mu^{-} invariant mass, top-top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_TT", "#mu^{+}#mu^{-} invariant mass, top-top", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_MuonCuts_TB", "#mu^{+}#mu^{-} invariant mass, top-bottom or bottom-top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_TB", "#mu^{+}#mu^{-} invariant mass, top-bottom or bottom-top", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_MuonCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom-bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom-bottom", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_TT", "#mu^{+}#mu^{-} invariant mass, top-top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_TT", "#mu^{+}#mu^{-} invariant mass, top-top", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_TB", "#mu^{+}#mu^{-} invariant mass, top-bottom or bottom-top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_TB", "#mu^{+}#mu^{-} invariant mass, top-bottom or bottom-top", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom-bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom-bottom", {HistType::kTH1F, {invMassAxisFull}}); + // MCH-MID tracks with MFT acceptance cuts + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxisFull}}); + // MCH-MID tracks with MFT acceptance cuts and combinations from the top and bottom halfs of MCH + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_TT", "#mu^{+}#mu^{-} invariant mass, top-top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_TT", "#mu^{+}#mu^{-} invariant mass, top-top", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_TB", "#mu^{+}#mu^{-} invariant mass, top-bottom or bottom-top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_TB", "#mu^{+}#mu^{-} invariant mass, top-bottom or bottom-top", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom-bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom-bottom", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_TT", "#mu^{+}#mu^{-} invariant mass, top-top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_TT", "#mu^{+}#mu^{-} invariant mass, top-top", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_TB", "#mu^{+}#mu^{-} invariant mass, top-bottom or bottom-top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_TB", "#mu^{+}#mu^{-} invariant mass, top-bottom or bottom-top", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom-bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom-bottom", {HistType::kTH1F, {invMassAxisFull}}); + // Good MFT-MCH-MID tracks with MCH parameters and MFT acceptance cuts + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_GlobalMatchesCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_GlobalMatchesCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_GlobalMatchesCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMatchesCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxisFull}}); + // Good MFT-MCH-MID tracks with global parameters MFT acceptance cuts + registryDimuon.add("dimuon/same-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_GlobalMuonKine_GlobalMatchesCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_GlobalMuonKine_GlobalMatchesCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxisFull}}); + // Good MFT-MCH-MID tracks with re-scaled MFT kinematics and MFT acceptance cuts + registryDimuon.add("dimuon/same-event/invariantMass_ScaledMftKine_GlobalMatchesCuts", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_ScaledMftKine_GlobalMatchesCuts", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_ScaledMftKine_GlobalMatchesCuts", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_ScaledMftKine_GlobalMatchesCuts", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum", {HistType::kTH1F, {invMassAxisFull}}); + // combinations of tracks from top and bottom halfs of MFT + registryDimuon.add("dimuon/same-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_TT", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum, top-top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_TB", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum, top-bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_BT", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum, bottom-top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_BB", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum, bottom-bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_TT", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum, top-top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_TB", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum, top-bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_BT", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum, bottom-top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_BB", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum, bottom-bottom", {HistType::kTH1F, {invMassAxis}}); + // combinations with sub-leading matches + registryDimuon.add("dimuon/same-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_leading_subleading", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_GlobalMuonKine_GlobalMatchesCuts_leading_subleading", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/same-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_subleading_leading", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_GlobalMuonKine_GlobalMatchesCuts_subleading_leading", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/same-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_subleading_subleading", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_GlobalMuonKine_GlobalMatchesCuts_subleading_subleading", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxisFull}}); + + // invariant mass correlations + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_vs_GlobalMuonKine", "M_{#mu^{+}#mu^{-}} - muon tracks vs. global tracks", {HistType::kTH2F, {invMassCorrelationAxis, invMassCorrelationAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_ScaledMftKine_vs_GlobalMuonKine", "M_{#mu^{+}#mu^{-}} - rescaled MFT tracks vs. global tracks", {HistType::kTH2F, {invMassCorrelationAxis, invMassCorrelationAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_GlobalMuonKine_subleading_vs_leading", "M_{#mu^{+}#mu^{-}} - subleading vs. leading matches", {HistType::kTH2F, {invMassCorrelationAxis, invMassCorrelationAxis}}); + } + } + + void doTransformMFT(o2::mch::TrackParam& track) + { + double zCH10 = -1437.6; + double z = track.getZ(); + // double dZ = zMCH - z; + double x = track.getNonBendingCoor(); + double y = track.getBendingCoor(); + double xSlope = track.getNonBendingSlope(); + double ySlope = track.getBendingSlope(); + + double xShiftMCH = (y > 0) ? 0.8541 : -1.5599; + double xCorrection = xShiftMCH * z / zCH10; + track.setNonBendingCoor(x + xCorrection); + double xSlopeCorrection = xShiftMCH / zCH10; + track.setNonBendingSlope(xSlope + xSlopeCorrection); + + double yShiftMCH = (y > 0) ? 3.0311 : 0.7588; + double yCorrection = yShiftMCH * z / zCH10; + track.setBendingCoor(y + yCorrection); + double ySlopeCorrection = yShiftMCH / zCH10; + track.setBendingSlope(ySlope + ySlopeCorrection); + } + + template + void TransformMFT(TTrack& track) + { + if constexpr (static_cast(GlobalFwdFillMap)) { + auto mchTrack = mMatching.FwdtoMCH(track); + doTransformMFT(mchTrack); + + auto transformedTrack = mMatching.MCHtoFwd(mchTrack); + track.setParameters(transformedTrack.getParameters()); + track.setZ(transformedTrack.getZ()); + track.setCovariances(transformedTrack.getCovariances()); + } else { + o2::dataformats::GlobalFwdTrack fwdtrack; + fwdtrack.setParameters(track.getParameters()); + fwdtrack.setZ(track.getZ()); + fwdtrack.setCovariances(track.getCovariances()); + auto mchTrack = mMatching.FwdtoMCH(fwdtrack); + doTransformMFT(mchTrack); + + auto transformedTrack = mMatching.MCHtoFwd(mchTrack); + track.setParameters(transformedTrack.getParameters()); + track.setZ(transformedTrack.getZ()); + track.setCovariances(transformedTrack.getCovariances()); + } + } + + int GetDetElemId(int iDetElemNumber) + { + // make sure detector number is valid + if (!(iDetElemNumber >= fgSNDetElemCh[0] && + iDetElemNumber < fgSNDetElemCh[10])) { + LOGF(fatal, "Invalid detector element number: %d", iDetElemNumber); + } + /// get det element number from ID + // get chamber and element number in chamber + int iCh = 0; + int iDet = 0; + for (int i = 1; i <= 10; i++) { + if (iDetElemNumber < fgSNDetElemCh[i]) { + iCh = i; + iDet = iDetElemNumber - fgSNDetElemCh[i - 1]; + break; + } + } + + // make sure detector index is valid + if (!(iCh > 0 && iCh <= 10 && iDet < fgNDetElemCh[iCh - 1])) { + LOGF(fatal, "Invalid detector element id: %d", 100 * iCh + iDet); + } + + // add number of detectors up to this chamber + return 100 * iCh + iDet; + } + + int GetQuadrantPhi(double phi) + { + if (phi >= 0 && phi < 90) { + return 0; + } + if (phi >= 90 && phi <= 180) { + return 1; + } + if (phi >= -180 && phi < -90) { + return 2; + } + if (phi >= -90 && phi < 0) { + return 3; + } + return -1; + } + + template + int GetQuadrantTrack(TTrack const& track) + { + double phi = static_cast(track.phi()) * 180 / TMath::Pi(); + return GetQuadrantPhi(phi); + } + + bool RemoveTrack(mch::Track& track) + { + // Refit track with re-aligned clusters + bool removeTrack = false; + try { + trackFitter.fit(track, false); + } catch (exception const& e) { + removeTrack = true; + return removeTrack; + } + + auto itStartingParam = std::prev(track.rend()); + + while (true) { + + try { + trackFitter.fit(track, true, false, (itStartingParam == track.rbegin()) ? nullptr : &itStartingParam); + } catch (exception const&) { + removeTrack = true; + break; + } + + double worstLocalChi2 = -1.0; + + track.tagRemovableClusters(0x1F, false); + + auto itWorstParam = track.end(); + + for (auto itParam = track.begin(); itParam != track.end(); ++itParam) { + if (itParam->getLocalChi2() > worstLocalChi2) { + worstLocalChi2 = itParam->getLocalChi2(); + itWorstParam = itParam; + } + } + + if (worstLocalChi2 < mImproveCutChi2) { + break; + } + + if (!itWorstParam->isRemovable()) { + removeTrack = true; + track.removable(); + break; + } + + auto itNextParam = track.removeParamAtCluster(itWorstParam); + auto itNextToNextParam = (itNextParam == track.end()) ? itNextParam : std::next(itNextParam); + itStartingParam = track.rbegin(); + + if (track.getNClusters() < 10) { + removeTrack = true; + break; + } else { + while (itNextToNextParam != track.end()) { + if (itNextToNextParam->getClusterPtr()->getChamberId() != itNextParam->getClusterPtr()->getChamberId()) { + itStartingParam = std::make_reverse_iterator(++itNextParam); + break; + } + ++itNextToNextParam; + } + } + } + + if (!removeTrack) { + for (auto& param : track) { + param.setParameters(param.getSmoothParameters()); + param.setCovariances(param.getSmoothCovariances()); + } + } + + return removeTrack; + } + + template + bool pDCACut(Var const& fgValues, Var const& fgValuesPV, double nSigmaPDCA) + { + static const double sigmaPDCA23 = 80.; + static const double sigmaPDCA310 = 54.; + static const double relPRes = 0.0004; + static const double slopeRes = 0.0005; + + double thetaAbs = TMath::ATan(fgValues.rabs / 505.) * TMath::RadToDeg(); + double p = fgValuesPV.p; + + double pDCA = fgValues.pDca; + double sigmaPDCA = (thetaAbs < 3) ? sigmaPDCA23 : sigmaPDCA310; + double nrp = nSigmaPDCA * relPRes * p; + double pResEffect = sigmaPDCA / (1. - nrp / (1. + nrp)); + double slopeResEffect = 535. * slopeRes * p; + double sigmaPDCAWithRes = TMath::Sqrt(pResEffect * pResEffect + slopeResEffect * slopeResEffect); + + if (pDCA > nSigmaPDCA * sigmaPDCAWithRes) { + return false; + } + + return true; + } + + template + bool IsMixedEvent(Var const& fgValues1, Var const& fgValues2) + { + if (fgValues1.bc == fgValues2.bc) { + return false; + } + + uint64_t bcDiff = (fgValues2.bc > fgValues1.bc) ? (fgValues2.bc - fgValues1.bc) : (fgValues1.bc - fgValues2.bc); + // in the event mixing case, we require a minimum BC gap between the collisions + if (bcDiff < configMixing.fEventMinDeltaBc) + return false; + + // we also require that the collisions have similar Z positions and multiplicity of MFT tracks + if (std::fabs(fgValues2.z - fgValues1.z) > configMixing.fEventMaxDeltaVtxZ) { + return false; + } + + if (std::abs(fgValues2.multMFT - fgValues1.multMFT) > configMixing.fEventMaxDeltaNMFT) { + return false; + } + + return true; + } + + template + bool IsGoodMuon(Var const& fgValues, Var const& fgValuesPV, float fTrackChi2MchUp, float fPMchLow, float fPtMchLow, float fEtaMchLow, float fEtaMchUp, float fRabsLow, float fRabsUp, float fSigmaPdcaUp) + { + // chi2 cut + if (fgValues.chi2 > fTrackChi2MchUp) + return false; + + // momentum cut + if (fgValues.p < fPMchLow) { + return false; // skip low-momentum tracks + } + + // transverse momentum cut + if (fgValues.pT < fPtMchLow) { + return false; // skip low-momentum tracks + } + + // Eta cut + if ((fgValues.eta < fEtaMchLow || fgValues.eta > fEtaMchUp)) { + return false; + } + + // RAbs cut + if ((fgValues.rabs < fRabsLow || fgValues.rabs > fRabsUp)) { + return false; + } + + // pDCA cut + if (!pDCACut(fgValues, fgValuesPV, fSigmaPdcaUp)) { + return false; + } + + return true; + } + + template + bool IsGoodMuon(Var const& fgValues, Var const& fgValuesPV) + { + return IsGoodMuon(fgValues, fgValuesPV, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, configMuons.fPtMchLow, configMuons.fEtaMchLow, configMuons.fEtaMchUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp); + } + + template + bool IsGoodGlobalMuon(Var const& fgValues, Var const& fgValuesPV) + { + return IsGoodMuon(fgValues, fgValuesPV, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, configMuons.fPtMchLow, configMFTs.fEtaMftLow, configMFTs.fEtaMftUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp); + } + + template + bool IsGoodMFT(Var const& fgValues, float fTrackChi2MftUp, int fTrackNClustMftLow) + { + // chi2 cut + if (fgValues.chi2 > fTrackChi2MftUp) { + return false; + } + + // number of clusters cut + if (fgValues.nClusters < fTrackNClustMftLow) { + return false; + } + + return true; + } + + template + bool IsGoodGlobalMatching(Var const& fgValues, float fTrackChi2MftUp, int fTrackNClustMftLow, float fMatchingChi2MftMchUp) + { + if (!IsGoodMFT(fgValues, fTrackChi2MftUp, fTrackNClustMftLow)) { + return false; + } + + if (fgValues.chi2matching > fMatchingChi2MftMchUp) { + return false; + } + + return true; + } + + template + bool IsGoodGlobalMatching(Var const& fgValues) + { + return IsGoodGlobalMatching(fgValues, configMFTs.fTrackChi2MftUp, configMFTs.fTrackNClustMftLow, fMatchingChi2MftMchUp); + } + + template + double GetMuMuInvariantMass(VarT const& track1, VarT const& track2) + { + ROOT::Math::PxPyPzMVector muon1{ + track1.px, + track1.py, + track1.pz, + o2::constants::physics::MassMuon}; + + ROOT::Math::PxPyPzMVector muon2{ + track2.px, + track2.py, + track2.pz, + o2::constants::physics::MassMuon}; + + auto dimuon = muon1 + muon2; + + return dimuon.M(); + } + + template + void GetMuonPairs(TMuons const& muons, TCandidates const& matchingCandidates, const std::map& collisionInfos, + std::vector& muonPairs, + std::vector& globalMuonPairs) + { + // muon tracks - outer loop over collisions + for (auto& [collisionIndex1, collisionInfo1] : collisionInfos) { + + // outer loop over muon tracks + auto muonCollision1 = muons.sliceBy(fwdtracksPerCollision, collisionInfo1.globalIndex); + for (auto muon1 : muonCollision1) { + + if (muon1.trackType() <= 2) { + continue; + } + auto mchIndex1 = muon1.globalIndex(); + + // inner loop over collisions + for (auto& [collisionIndex2, collisionInfo2] : collisionInfos) { + // avoid double-counting of collisions + if (collisionIndex2 < collisionIndex1) + continue; + + bool sameEvent = (collisionIndex1 == collisionIndex2); + bool mixedEvent = IsMixedEvent(collisionInfo1, collisionInfo2); + + if (!sameEvent && !mixedEvent) + continue; + + // inner loop over muon tracks + auto muonCollision2 = muons.sliceBy(fwdtracksPerCollision, collisionInfo2.globalIndex); + for (auto muon2 : muonCollision2) { + if (muon2.trackType() <= 2) { + continue; + } + auto mchIndex2 = muon2.globalIndex(); + + // avoid double-counting of muon pairs if we are not mixing events + if (sameEvent && mchIndex2 <= mchIndex1) + continue; + + MuonPair muonPair{{collisionIndex1, mchIndex1}, {collisionIndex2, mchIndex2}}; + muonPairs.emplace_back(muonPair); + } + } + } + } + + // global muon tracks - outer loop over collisions + for (auto& [collisionIndex1, collisionInfo1] : collisionInfos) { + + // outer loop over global muon tracks + auto muonCollision1 = muons.sliceBy(fwdtracksPerCollision, collisionInfo1.globalIndex); + for (auto muon1 : muonCollision1) { + + if (muon1.trackType() <= 2) { + continue; + } + auto mchIndex1 = muon1.globalIndex(); + auto matchingCandidateIt1 = matchingCandidates.find(mchIndex1); + if (matchingCandidateIt1 == matchingCandidates.end()) { + continue; + } + + // inner loop over collisions + for (auto& [collisionIndex2, collisionInfo2] : collisionInfos) { + // avoid double-counting of collisions + if (collisionIndex2 < collisionIndex1) + continue; + + bool sameEvent = (collisionIndex1 == collisionIndex2); + bool mixedEvent = IsMixedEvent(collisionInfo1, collisionInfo2); + + if (!sameEvent && !mixedEvent) + continue; + + // outer loop over global muon tracks + auto muonCollision2 = muons.sliceBy(fwdtracksPerCollision, collisionInfo2.globalIndex); + for (auto muon2 : muonCollision2) { + + if (muon2.trackType() <= 2) { + continue; + } + auto mchIndex2 = muon2.globalIndex(); + auto matchingCandidateIt2 = matchingCandidates.find(mchIndex2); + if (matchingCandidateIt2 == matchingCandidates.end()) { + continue; + } + + // avoid double-counting of muon pairs if we are not mixing events + if (sameEvent && mchIndex2 <= mchIndex1) + continue; + + GlobalMuonPair muonPair{{collisionIndex1, matchingCandidateIt1->second}, {collisionIndex2, matchingCandidateIt2->second}}; + globalMuonPairs.emplace_back(muonPair); + } + } + } + } + } + + template + void FillCollision(TEvent const& collision, Var& fgValues) + { + fgValues.globalIndex = collision.globalIndex(); + fgValues.x = collision.posX(); + fgValues.y = collision.posY(); + fgValues.z = collision.posZ(); + fgValues.covXX = collision.covXX(); + fgValues.covYY = collision.covYY(); + } + + template + void FillTrack(mch::Track const& muon, Var& fgValues) + { + mch::TrackParam trackParam = mch::TrackParam(muon.first()); + auto proptrack = mMatching.MCHtoFwd(trackParam); + + fgValues.pT = proptrack.getPt(); + fgValues.x = proptrack.getX(); + fgValues.y = proptrack.getY(); + fgValues.z = proptrack.getZ(); + fgValues.eta = proptrack.getEta(); + fgValues.tgl = proptrack.getTgl(); + fgValues.phi = proptrack.getPhi(); + + fgValues.p = proptrack.getP(); + fgValues.px = proptrack.getPx(); + fgValues.py = proptrack.getPy(); + fgValues.pz = proptrack.getPz(); + + fgValues.chi2 = trackParam.getTrackChi2(); + fgValues.nClusters = muon.getNClusters(); + fgValues.sign = trackParam.getCharge(); + } + + template + void FillTrack(TTrack const& muon, Var& fgValues) + { + fgValues.collisionId = muon.collisionId(); + fgValues.globalIndex = muon.globalIndex(); + fgValues.trackTime = muon.trackTime(); + + fgValues.pT = muon.pt(); + fgValues.x = muon.x(); + fgValues.y = muon.y(); + fgValues.z = muon.z(); + fgValues.eta = muon.eta(); + fgValues.tgl = muon.tgl(); + fgValues.phi = muon.phi(); + + fgValues.p = muon.p(); + fgValues.px = muon.px(); + fgValues.py = muon.py(); + fgValues.pz = muon.pz(); + + fgValues.chi2 = muon.chi2(); + fgValues.nClusters = muon.nClusters(); + fgValues.sign = muon.sign(); + + if constexpr (static_cast(MuonFillMap)) { + // Direct info from AO2D without re-propagation + fgValues.pDca = muon.pDca(); + fgValues.rabs = muon.rAtAbsorberEnd(); + fgValues.trackType = muon.trackType(); + } + } + + template + bool FillClusters(TMCHTrack const& muon, TFwdCls const& mchcls, Var& fgValues, mch::Track& convertedTrack) + { + int removable = 0; + auto clustersSliced = mchcls.sliceBy(perMuon, muon.globalIndex()); // Slice clusters by muon id + vector> posClusters; + + int clIndex = -1; + // Get re-aligned clusters associated to current track + for (auto const& cluster : clustersSliced) { + clIndex += 1; + + math_utils::Point3D local; + math_utils::Point3D master; + + mch::Cluster* clusterMCH = new mch::Cluster(); + master.SetXYZ(cluster.x(), cluster.y(), cluster.z()); + + if (configRealign.fDoRealign) { + // Transformation from reference geometry frame to new geometry frame + transformRef[cluster.deId()].MasterToLocal(master, local); + transformNew[cluster.deId()].LocalToMaster(local, master); + } + + clusterMCH->x = master.x(); + clusterMCH->y = master.y(); + clusterMCH->z = master.z(); + + uint32_t ClUId = mch::Cluster::buildUniqueId(static_cast(cluster.deId() / 100) - 1, cluster.deId(), clIndex); + clusterMCH->uid = ClUId; + clusterMCH->ex = cluster.isGoodX() ? 0.2 : 10.0; + clusterMCH->ey = cluster.isGoodY() ? 0.2 : 10.0; + + // Fill temporary values + vector posCls = {clusterMCH->x, clusterMCH->y, clusterMCH->z}; + vector eCls = {clusterMCH->ex, clusterMCH->ey}; + posClusters.emplace_back(posCls); + fgValues.errorClusters.emplace_back(eCls); + fgValues.DEIDs.emplace_back(cluster.deId()); + + // Add transformed cluster into temporary variable + convertedTrack.createParamAtCluster(*clusterMCH); + } + + if (configRealign.fDoRealign) { + // Refit the re-aligned track + if (convertedTrack.getNClusters() != 0) { + removable = RemoveTrack(convertedTrack); + } else { + LOGF(fatal, "Muon track %d has no associated clusters.", muon.globalIndex()); + } + + for (auto it = convertedTrack.begin(); it != convertedTrack.end(); it++) { + vector pos = {static_cast(it->getNonBendingCoor()), static_cast(it->getBendingCoor()), static_cast(it->getZ())}; + fgValues.posClusters.emplace_back(pos); + } + + } else { + fgValues.posClusters = posClusters; + } + + return !removable; + } + + template + void FillMatchingCandidates(TMuon const& muon, TMCH const& mchtrack, TMap& matchingCandidates) + { + uint64_t muonId = muon.globalIndex(); + uint64_t mchId = mchtrack.globalIndex(); + + //// Save matching candidates index pairs + auto matchingCandidateIt = matchingCandidates.find(mchId); + if (matchingCandidateIt != matchingCandidates.end()) { + matchingCandidateIt->second.push_back(muonId); + } else { + matchingCandidates[mchId].push_back(muonId); + } + } + + template + void FillPropagation(mch::Track const& muon, VarC const& collision, VarT& fgValues, int endPoint = kToVtx, int endZ = 0) + { + o2::dataformats::GlobalFwdTrack propmuon; + mch::TrackParam trackParam = mch::TrackParam(muon.first()); + fgValues.chi2 = trackParam.getTrackChi2(); + fgValues.nClusters = muon.getNClusters(); + fgValues.sign = trackParam.getCharge(); + + if (endPoint == kToVtx) { + o2::mch::TrackExtrap::extrapToVertex(trackParam, collision.x, collision.y, collision.z, collision.covXX, collision.covYY); + } + if (endPoint == kToDCA) { + o2::mch::TrackExtrap::extrapToVertexWithoutBranson(trackParam, collision.z); + } + if (endPoint == kToAbsEnd) { + o2::mch::TrackExtrap::extrapToZ(trackParam, zAtAbsEnd); + } + if (endPoint == kToZ) { + o2::mch::TrackExtrap::extrapToZ(trackParam, endZ); + } + + auto proptrack = mMatching.MCHtoFwd(trackParam); + propmuon.setParameters(proptrack.getParameters()); + propmuon.setZ(proptrack.getZ()); + propmuon.setCovariances(proptrack.getCovariances()); + + //// Fill propagation informations + if (endPoint == kToVtx || endPoint == kToZ) { + fgValues.pT = propmuon.getPt(); + fgValues.x = propmuon.getX(); + fgValues.y = propmuon.getY(); + fgValues.z = propmuon.getZ(); + fgValues.eta = propmuon.getEta(); + fgValues.tgl = propmuon.getTgl(); + fgValues.phi = propmuon.getPhi(); + + fgValues.p = propmuon.getP(); + fgValues.px = propmuon.getP() * sin(M_PI / 2 - atan(propmuon.getTgl())) * cos(propmuon.getPhi()); + fgValues.py = propmuon.getP() * sin(M_PI / 2 - atan(propmuon.getTgl())) * sin(propmuon.getPhi()); + fgValues.pz = propmuon.getP() * cos(M_PI / 2 - atan(propmuon.getTgl())); + } + + if (endPoint == kToDCA) { + fgValues.dcaX = (propmuon.getX() - collision.x); + fgValues.dcaY = (propmuon.getY() - collision.y); + float dcaXY = std::sqrt(fgValues.dcaX * fgValues.dcaX + fgValues.dcaY * fgValues.dcaY); + + mch::TrackParam trackParam = mch::TrackParam(muon.first()); + float p = trackParam.p(); + fgValues.pDca = p * dcaXY; + } + + if (endPoint == kToAbsEnd) { + double xAbs = propmuon.getX(); + double yAbs = propmuon.getY(); + fgValues.rabs = std::sqrt(xAbs * xAbs + yAbs * yAbs); + } + } + + template + void FillPropagation(TTrack const& muon, VarC const& collision, VarT const& fgValuesMCH, VarT& fgValues, int endPoint = kToVtx, int endZ = 0) + { + o2::dataformats::GlobalFwdTrack propmuon; + double chi2 = muon.chi2(); + fgValues.chi2 = chi2; + fgValues.nClusters = muon.nClusters(); + fgValues.sign = muon.sign(); + + if constexpr (static_cast(MuonFillMap)) { + o2::dataformats::GlobalFwdTrack track; + + SMatrix5 tpars(muon.x(), muon.y(), muon.phi(), muon.tgl(), muon.signed1Pt()); + std::vector v1{muon.cXX(), muon.cXY(), muon.cYY(), muon.cPhiX(), muon.cPhiY(), + muon.cPhiPhi(), muon.cTglX(), muon.cTglY(), muon.cTglPhi(), muon.cTglTgl(), + muon.c1PtX(), muon.c1PtY(), muon.c1PtPhi(), muon.c1PtTgl(), muon.c1Pt21Pt2()}; + SMatrix55 tcovs(v1.begin(), v1.end()); + o2::track::TrackParCovFwd fwdtrack{muon.z(), tpars, tcovs, chi2}; + + track.setParameters(tpars); + track.setZ(fwdtrack.getZ()); + track.setCovariances(tcovs); + auto mchTrack = mMatching.FwdtoMCH(track); + + if (endPoint == kToVtx) { + o2::mch::TrackExtrap::extrapToVertex(mchTrack, collision.x, collision.y, collision.z, collision.covXX, collision.covYY); + } + if (endPoint == kToDCA) { + o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchTrack, collision.z); + } + if (endPoint == kToAbsEnd) { + o2::mch::TrackExtrap::extrapToZ(mchTrack, zAtAbsEnd); + } + if (endPoint == kToZ) { + o2::mch::TrackExtrap::extrapToZ(mchTrack, endZ); + } + + auto proptrack = mMatching.MCHtoFwd(mchTrack); + propmuon.setParameters(proptrack.getParameters()); + propmuon.setZ(proptrack.getZ()); + propmuon.setCovariances(proptrack.getCovariances()); + + } else { + + o2::dataformats::GlobalFwdTrack track; + + if constexpr (static_cast(Scaled)) { + double pMCH = fgValuesMCH.p; + int sign = fgValuesMCH.sign; + + double px = pMCH * sin(M_PI / 2 - atan(muon.tgl())) * cos(muon.phi()); + double py = pMCH * sin(M_PI / 2 - atan(muon.tgl())) * sin(muon.phi()); + // double pz = pMCH * cos(M_PI / 2 - atan(mft.tgl())); + double pt = std::sqrt(std::pow(px, 2) + std::pow(py, 2)); + + double chi2 = muon.chi2(); + double signed1Pt = endPoint == kToDCA ? muon.signed1Pt() : sign / pt; + SMatrix5 tpars(muon.x(), muon.y(), muon.phi(), muon.tgl(), signed1Pt); + std::vector v1{0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}; + SMatrix55 tcovs(v1.begin(), v1.end()); + o2::track::TrackParCovFwd fwdtrack{muon.z(), tpars, tcovs, chi2}; + track.setParameters(tpars); + track.setZ(fwdtrack.getZ()); + track.setCovariances(tcovs); + } else { + SMatrix5 tpars(muon.x(), muon.y(), muon.phi(), muon.tgl(), muon.signed1Pt()); + std::vector v1{muon.cXX(), muon.cXY(), muon.cYY(), muon.cPhiX(), muon.cPhiY(), + muon.cPhiPhi(), muon.cTglX(), muon.cTglY(), muon.cTglPhi(), muon.cTglTgl(), + muon.c1PtX(), muon.c1PtY(), muon.c1PtPhi(), muon.c1PtTgl(), muon.c1Pt21Pt2()}; + SMatrix55 tcovs(v1.begin(), v1.end()); + o2::track::TrackParCovFwd fwdtrack{muon.z(), tpars, tcovs, chi2}; + track.setParameters(tpars); + track.setZ(fwdtrack.getZ()); + track.setCovariances(tcovs); + } + + if (endPoint == kToVtx) { + if (fEnableMFTAlignmentCorrections) { + TransformMFT<0>(track); + } + auto geoMan = o2::base::GeometryManager::meanMaterialBudget(muon.x(), muon.y(), muon.z(), collision.x, collision.y, collision.z); + auto x2x0 = static_cast(geoMan.meanX2X0); + track.propagateToVtxhelixWithMCS(collision.z, {collision.x, collision.y}, {collision.covXX, collision.covYY}, Bz, x2x0); + } + if (endPoint == kToDCA) { + if (fEnableMFTAlignmentCorrections) { + TransformMFT<0>(track); + } + track.propagateToZ(collision.z, Bz); + } + if (endPoint == kToZ) { + auto mchTrackExt = mMatching.FwdtoMCH(track); + if (fEnableMFTAlignmentCorrections) { + doTransformMFT(mchTrackExt); + } + o2::mch::TrackExtrap::extrapToZ(mchTrackExt, endZ); + track = mMatching.MCHtoFwd(mchTrackExt); + } + + propmuon.setParameters(track.getParameters()); + propmuon.setZ(track.getZ()); + propmuon.setCovariances(track.getCovariances()); + } + + //// Fill propagation informations + if (endPoint == kToVtx || endPoint == kToZ) { + fgValues.pT = propmuon.getPt(); + fgValues.x = propmuon.getX(); + fgValues.y = propmuon.getY(); + fgValues.z = propmuon.getZ(); + fgValues.eta = propmuon.getEta(); + fgValues.tgl = propmuon.getTgl(); + fgValues.phi = propmuon.getPhi(); + + fgValues.p = propmuon.getP(); + fgValues.px = propmuon.getP() * sin(M_PI / 2 - atan(propmuon.getTgl())) * cos(propmuon.getPhi()); + fgValues.py = propmuon.getP() * sin(M_PI / 2 - atan(propmuon.getTgl())) * sin(propmuon.getPhi()); + fgValues.pz = propmuon.getP() * cos(M_PI / 2 - atan(propmuon.getTgl())); + } + + if (endPoint == kToDCA) { + fgValues.dcaX = (propmuon.getX() - collision.x); + fgValues.dcaY = (propmuon.getY() - collision.y); + float dcaXY = std::sqrt(fgValues.dcaX * fgValues.dcaX + fgValues.dcaY * fgValues.dcaY); + + if constexpr (static_cast(MuonFillMap)) { + float p = muon.p(); + fgValues.pDca = p * dcaXY; + } + } + + if (endPoint == kToAbsEnd) { + double xAbs = propmuon.getX(); + double yAbs = propmuon.getY(); + fgValues.rabs = std::sqrt(xAbs * xAbs + yAbs * yAbs); + } + } + + template + void FillMatching(TTrack const& track, Var& fgValuesMCH, Var& fgValuesMFT) + { + fgValuesMCH.chi2matching = track.chi2MatchMCHMID(); + fgValuesMFT.chi2matching = track.chi2MatchMCHMFT(); + } + + template + void FillMuonHistograms(Var const& fgValuesMCH, Var const& fgValuesMCHpv, Var const& fgValuesMFT, Var const& fgValuesGlobal, VarVector const& fgValuesCandidates) + { + if constexpr (static_cast(MuonFillMap)) { + // Muon histograms + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, 1.E10, configMuons.fPMchLow, configMuons.fPtMchLow, configMuons.fEtaMchLow, configMuons.fEtaMchUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + registry.get(HIST("muons/TrackChi2"))->Fill(fgValuesMCH.chi2); + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, 0., configMuons.fPtMchLow, configMuons.fEtaMchLow, configMuons.fEtaMchUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + registry.get(HIST("muons/TrackP"))->Fill(fgValuesMCH.p); + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, 0., configMuons.fEtaMchLow, configMuons.fEtaMchUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + registry.get(HIST("muons/TrackPt"))->Fill(fgValuesMCH.pT); + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, configMuons.fPtMchLow, -1.E10, 1.E10, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + registry.get(HIST("muons/TrackEta"))->Fill(fgValuesMCH.eta); + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, configMuons.fPtMchLow, configMuons.fEtaMchLow, configMuons.fEtaMchUp, 0., 1.E10, configMuons.fSigmaPdcaUp)) { + registry.get(HIST("muons/TrackRabs"))->Fill(fgValuesMCH.rabs); + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, configMuons.fPtMchLow, configMuons.fEtaMchLow, configMuons.fEtaMchUp, configMuons.fRabsLow, configMuons.fRabsUp, 1.E10)) { + registry.get(HIST("muons/TrackPDCA"))->Fill(fgValuesMCH.pDca); + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, configMuons.fPtMchLow, configMuons.fEtaMchLow, configMuons.fEtaMchUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + registry.get(HIST("muons/TrackPhi"))->Fill(fgValuesMCH.phi * 180.0 / TMath::Pi()); + registry.get(HIST("muons/TrackDCA"))->Fill(std::sqrt(fgValuesMCH.dcaX * fgValuesMCH.dcaX + fgValuesMCH.dcaY * fgValuesMCH.dcaY)); + } + } + + if constexpr (static_cast(GlobalMuonFillMap)) { + // Global muon histograms + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, 1.E10, configMuons.fPMchLow, configMuons.fPtMchLow, configMFTs.fEtaMftLow, configMFTs.fEtaMftUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + registry.get(HIST("global-muons/TrackChi2"))->Fill(fgValuesMCH.chi2); + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, 0., configMuons.fPtMchLow, configMFTs.fEtaMftLow, configMFTs.fEtaMftUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + registry.get(HIST("global-muons/TrackP"))->Fill(fgValuesMCH.p); + + // Momentum correlations + registry.get(HIST("global-muons/MomentumCorrelation_Global_vs_Muon"))->Fill(fgValuesMCH.p, fgValuesGlobal.p); + if (fgValuesMCH.p != 0) { + registry.get(HIST("global-muons/MomentumDifference_Global_vs_Muon"))->Fill(fgValuesMCH.p, (fgValuesGlobal.p - fgValuesMCH.p) / fgValuesMCH.p); + } + + if (fgValuesCandidates.size() >= 2) { + registry.get(HIST("global-muons/MomentumCorrelation_subleading_vs_leading"))->Fill(fgValuesCandidates[0].p, fgValuesCandidates[1].p); + if (fgValuesCandidates[0].p != 0) { + registry.get(HIST("global-muons/MomentumDifference_subleading_vs_leading"))->Fill(fgValuesCandidates[0].p, (fgValuesCandidates[1].p - fgValuesCandidates[0].p) / fgValuesCandidates[0].p); + } + } + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, 0., configMFTs.fEtaMftLow, configMFTs.fEtaMftUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + registry.get(HIST("global-muons/TrackPt"))->Fill(fgValuesMCH.pT); + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, configMuons.fPtMchLow, -1.E10, 1.E10, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + registry.get(HIST("global-muons/TrackEta"))->Fill(fgValuesMCH.eta); + + // Eta correlations + registry.get(HIST("global-muons/EtaCorrelation_Global_vs_Muon"))->Fill(fgValuesMCH.eta, fgValuesGlobal.eta); + if (fgValuesMCH.eta != 0) { + registry.get(HIST("global-muons/EtaDifference_Global_vs_Muon"))->Fill(fgValuesMCH.eta, (fgValuesGlobal.eta - fgValuesMCH.eta) / fgValuesMCH.eta); + } + + if (fgValuesCandidates.size() >= 2) { + registry.get(HIST("global-muons/EtaCorrelation_subleading_vs_leading"))->Fill(fgValuesCandidates[0].eta, fgValuesCandidates[1].eta); + if (fgValuesCandidates[0].eta != 0) { + registry.get(HIST("global-muons/EtaDifference_subleading_vs_leading"))->Fill(fgValuesCandidates[0].eta, (fgValuesCandidates[1].eta - fgValuesCandidates[0].eta) / fgValuesCandidates[0].eta); + } + } + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, configMuons.fPtMchLow, configMFTs.fEtaMftLow, configMFTs.fEtaMftUp, 0., 1.E10, configMuons.fSigmaPdcaUp)) { + registry.get(HIST("global-muons/TrackRabs"))->Fill(fgValuesMCH.rabs); + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, configMuons.fPtMchLow, configMFTs.fEtaMftLow, configMFTs.fEtaMftUp, configMuons.fRabsLow, configMuons.fRabsUp, 1.E10)) { + registry.get(HIST("global-muons/TrackPDCA"))->Fill(fgValuesMCH.pDca); + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, configMuons.fPtMchLow, configMFTs.fEtaMftLow, configMFTs.fEtaMftUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + registry.get(HIST("global-muons/TrackPhi"))->Fill(fgValuesMCH.phi * 180.0 / TMath::Pi()); + registry.get(HIST("global-muons/TrackDCA"))->Fill(std::sqrt(fgValuesMCH.dcaX * fgValuesMCH.dcaX + fgValuesMCH.dcaY * fgValuesMCH.dcaY)); + } + } + + if constexpr (static_cast(GlobalMatchingFillMap)) { + // Global muon histograms + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, 1.E10, configMuons.fPMchLow, configMuons.fPtMchLow, configMFTs.fEtaMftLow, configMFTs.fEtaMftUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + if (IsGoodGlobalMatching(fgValuesMFT, configMFTs.fTrackChi2MftUp, configMFTs.fTrackNClustMftLow, fMatchingChi2MftMchUp)) { + registry.get(HIST("global-matches/TrackChi2"))->Fill(fgValuesMCH.chi2); + } + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, 0., configMuons.fPtMchLow, configMFTs.fEtaMftLow, configMFTs.fEtaMftUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + if (IsGoodGlobalMatching(fgValuesMFT, configMFTs.fTrackChi2MftUp, configMFTs.fTrackNClustMftLow, fMatchingChi2MftMchUp)) { + registry.get(HIST("global-matches/TrackP"))->Fill(fgValuesMCH.p); + } + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, 0., configMFTs.fEtaMftLow, configMFTs.fEtaMftUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + if (IsGoodGlobalMatching(fgValuesMFT, configMFTs.fTrackChi2MftUp, configMFTs.fTrackNClustMftLow, fMatchingChi2MftMchUp)) { + registry.get(HIST("global-matches/TrackPt"))->Fill(fgValuesMCH.pT); + } + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, configMuons.fPtMchLow, -1.E10, 1.E10, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + if (IsGoodGlobalMatching(fgValuesMFT, configMFTs.fTrackChi2MftUp, configMFTs.fTrackNClustMftLow, fMatchingChi2MftMchUp)) { + registry.get(HIST("global-matches/TrackEta"))->Fill(fgValuesMCH.eta); + } + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, configMuons.fPtMchLow, configMFTs.fEtaMftLow, configMFTs.fEtaMftUp, 0., 1.E10, configMuons.fSigmaPdcaUp)) { + if (IsGoodGlobalMatching(fgValuesMFT, configMFTs.fTrackChi2MftUp, configMFTs.fTrackNClustMftLow, fMatchingChi2MftMchUp)) { + registry.get(HIST("global-matches/TrackRabs"))->Fill(fgValuesMCH.rabs); + } + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, configMuons.fPtMchLow, configMFTs.fEtaMftLow, configMFTs.fEtaMftUp, configMuons.fRabsLow, configMuons.fRabsUp, 1.E10)) { + if (IsGoodGlobalMatching(fgValuesMFT, configMFTs.fTrackChi2MftUp, configMFTs.fTrackNClustMftLow, fMatchingChi2MftMchUp)) { + registry.get(HIST("global-matches/TrackPDCA"))->Fill(fgValuesMCH.pDca); + } + } + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, configMuons.fPtMchLow, configMFTs.fEtaMftLow, configMFTs.fEtaMftUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + if (IsGoodGlobalMatching(fgValuesMFT, configMFTs.fTrackChi2MftUp, configMFTs.fTrackNClustMftLow, fMatchingChi2MftMchUp)) { + registry.get(HIST("global-matches/TrackPhi"))->Fill(fgValuesMCH.phi * 180.0 / TMath::Pi()); + registry.get(HIST("global-matches/TrackDCA"))->Fill(std::sqrt(fgValuesMCH.dcaX * fgValuesMCH.dcaX + fgValuesMCH.dcaY * fgValuesMCH.dcaY)); + + registry.get(HIST("global-matches/TrackP_glo"))->Fill(fgValuesGlobal.p); + registry.get(HIST("global-matches/TrackPt_glo"))->Fill(fgValuesGlobal.pT); + registry.get(HIST("global-matches/TrackEta_glo"))->Fill(fgValuesGlobal.eta); + registry.get(HIST("global-matches/TrackPhi_glo"))->Fill(fgValuesGlobal.phi * 180.0 / TMath::Pi()); + registry.get(HIST("global-matches/TrackDCA_glo"))->Fill(std::sqrt(fgValuesGlobal.dcaX * fgValuesGlobal.dcaX + fgValuesGlobal.dcaY * fgValuesGlobal.dcaY)); + } + if (IsGoodGlobalMatching(fgValuesMFT, 1.E10, configMFTs.fTrackNClustMftLow, fMatchingChi2MftMchUp)) { + registry.get(HIST("global-matches/TrackChi2_MFT"))->Fill(fgValuesMFT.chi2); + } + if (IsGoodGlobalMatching(fgValuesMFT, configMFTs.fTrackChi2MftUp, 0, fMatchingChi2MftMchUp)) { + registry.get(HIST("global-matches/TrackNclusters_MFT"))->Fill(fgValuesMFT.nClusters); + } + if (IsGoodGlobalMatching(fgValuesMFT, configMFTs.fTrackChi2MftUp, configMFTs.fTrackNClustMftLow, 1.E10)) { + registry.get(HIST("global-matches/MatchChi2"))->Fill(fgValuesMFT.chi2matching); + } + } + } + } + + template + void FillTrackResidualHistograms(VarVector const& fgVectorsMCH, VarVector const& fgVectorsMFT, int quadrant, bool same, bool mixed) + { + std::vector> xPos; + std::vector> yPos; + std::vector> thetax; + std::vector> thetay; + for (int zi = 0; zi < int(zRefPlane.size()); zi++) { + xPos.emplace_back(std::array{fgVectorsMCH[zi].x, fgVectorsMFT[zi].x}); + yPos.emplace_back(std::array{fgVectorsMCH[zi].y, fgVectorsMFT[zi].y}); + thetax.emplace_back(std::array{ + std::atan2(fgVectorsMCH[zi].px, -1.0 * fgVectorsMCH[zi].pz) * 180 / TMath::Pi(), + std::atan2(fgVectorsMFT[zi].px, -1.0 * fgVectorsMFT[zi].pz) * 180 / TMath::Pi()}); + thetay.emplace_back(std::array{ + std::atan2(fgVectorsMCH[zi].py, -1.0 * fgVectorsMCH[zi].pz) * 180 / TMath::Pi(), + std::atan2(fgVectorsMFT[zi].py, -1.0 * fgVectorsMFT[zi].pz) * 180 / TMath::Pi()}); + } + + for (int i = 0; i < int(zRefPlane.size()); i++) { + if (same) { + std::get>(trackResidualsHistos[i][quadrant]["dx_vs_x"])->Fill(std::fabs(xPos[i][1]), xPos[i][0] - xPos[i][1]); + std::get>(trackResidualsHistos[i][quadrant]["dx_vs_y"])->Fill(std::fabs(yPos[i][1]), xPos[i][0] - xPos[i][1]); + std::get>(trackResidualsHistos[i][quadrant]["dy_vs_x"])->Fill(std::fabs(xPos[i][1]), yPos[i][0] - yPos[i][1]); + std::get>(trackResidualsHistos[i][quadrant]["dy_vs_y"])->Fill(std::fabs(yPos[i][1]), yPos[i][0] - yPos[i][1]); + + std::get>(trackResidualsHistos[i][quadrant]["dthetax_vs_x"])->Fill(std::fabs(xPos[i][1]), thetax[i][0] - thetax[i][1]); + std::get>(trackResidualsHistos[i][quadrant]["dthetax_vs_y"])->Fill(std::fabs(yPos[i][1]), thetax[i][0] - thetax[i][1]); + std::get>(trackResidualsHistos[i][quadrant]["dthetax_vs_thetax"])->Fill(std::fabs(thetax[i][1]), thetax[i][0] - thetax[i][1]); + std::get>(trackResidualsHistos[i][quadrant]["dthetay_vs_x"])->Fill(std::fabs(xPos[i][1]), thetay[i][0] - thetay[i][1]); + std::get>(trackResidualsHistos[i][quadrant]["dthetay_vs_y"])->Fill(std::fabs(yPos[i][1]), thetay[i][0] - thetay[i][1]); + std::get>(trackResidualsHistos[i][quadrant]["dthetay_vs_thetay"])->Fill(std::fabs(thetay[i][1]), thetay[i][0] - thetay[i][1]); + } + if (mixed) { + std::get>(trackResidualsHistosMixedEvents[i][quadrant]["dx_vs_x"])->Fill(std::fabs(xPos[i][1]), xPos[i][0] - xPos[i][1]); + std::get>(trackResidualsHistosMixedEvents[i][quadrant]["dx_vs_y"])->Fill(std::fabs(yPos[i][1]), xPos[i][0] - xPos[i][1]); + std::get>(trackResidualsHistosMixedEvents[i][quadrant]["dy_vs_x"])->Fill(std::fabs(xPos[i][1]), yPos[i][0] - yPos[i][1]); + std::get>(trackResidualsHistosMixedEvents[i][quadrant]["dy_vs_y"])->Fill(std::fabs(yPos[i][1]), yPos[i][0] - yPos[i][1]); + + std::get>(trackResidualsHistosMixedEvents[i][quadrant]["dthetax_vs_x"])->Fill(std::fabs(xPos[i][1]), thetax[i][0] - thetax[i][1]); + std::get>(trackResidualsHistosMixedEvents[i][quadrant]["dthetax_vs_y"])->Fill(std::fabs(yPos[i][1]), thetax[i][0] - thetax[i][1]); + std::get>(trackResidualsHistosMixedEvents[i][quadrant]["dthetax_vs_thetax"])->Fill(std::fabs(thetax[i][1]), thetax[i][0] - thetax[i][1]); + std::get>(trackResidualsHistosMixedEvents[i][quadrant]["dthetay_vs_x"])->Fill(std::fabs(xPos[i][1]), thetay[i][0] - thetay[i][1]); + std::get>(trackResidualsHistosMixedEvents[i][quadrant]["dthetay_vs_y"])->Fill(std::fabs(yPos[i][1]), thetay[i][0] - thetay[i][1]); + std::get>(trackResidualsHistosMixedEvents[i][quadrant]["dthetay_vs_thetay"])->Fill(std::fabs(thetay[i][1]), thetay[i][0] - thetay[i][1]); + } + } + } + + template + void FillDCAHistograms(VarT const& fgValues, VarC const& fgValuesColl, int sign, int quadrant, bool same, bool mixed) + { + if constexpr (static_cast(MuonFillMap)) { + if (same) { + std::get>(dcaHistos[1][quadrant][0]["DCA_x"])->Fill(fgValues.dcaX); + std::get>(dcaHistos[1][quadrant][0]["DCA_y"])->Fill(fgValues.dcaY); + std::get>(dcaHistos[1][quadrant][sign]["DCA_x"])->Fill(fgValues.dcaX); + std::get>(dcaHistos[1][quadrant][sign]["DCA_y"])->Fill(fgValues.dcaY); + } + if (mixed) { + std::get>(dcaHistosMixedEvents[1][quadrant][0]["DCA_x"])->Fill(fgValues.dcaX); + std::get>(dcaHistosMixedEvents[1][quadrant][0]["DCA_y"])->Fill(fgValues.dcaY); + std::get>(dcaHistosMixedEvents[1][quadrant][sign]["DCA_x"])->Fill(fgValues.dcaX); + std::get>(dcaHistosMixedEvents[1][quadrant][sign]["DCA_y"])->Fill(fgValues.dcaY); + } + } + + if constexpr (static_cast(GlobalMuonFillMap)) { + if (same) { + std::get>(dcaHistos[0][quadrant][0]["DCA_x"])->Fill(fgValues.dcaX); + std::get>(dcaHistos[0][quadrant][0]["DCA_y"])->Fill(fgValues.dcaY); + std::get>(dcaHistos[0][quadrant][sign]["DCA_x"])->Fill(fgValues.dcaX); + std::get>(dcaHistos[0][quadrant][sign]["DCA_y"])->Fill(fgValues.dcaY); + std::get>(dcaHistos[0][quadrant][0]["DCA_x_vs_z"])->Fill(fgValuesColl.z, fgValues.dcaX); + std::get>(dcaHistos[0][quadrant][0]["DCA_y_vs_z"])->Fill(fgValuesColl.z, fgValues.dcaY); + } + + if (mixed) { + std::get>(dcaHistosMixedEvents[0][quadrant][0]["DCA_x"])->Fill(fgValues.dcaX); + std::get>(dcaHistosMixedEvents[0][quadrant][0]["DCA_y"])->Fill(fgValues.dcaY); + std::get>(dcaHistosMixedEvents[0][quadrant][sign]["DCA_x"])->Fill(fgValues.dcaX); + std::get>(dcaHistosMixedEvents[0][quadrant][sign]["DCA_y"])->Fill(fgValues.dcaY); + std::get>(dcaHistosMixedEvents[0][quadrant][0]["DCA_x_vs_z"])->Fill(fgValuesColl.z, fgValues.dcaX); + std::get>(dcaHistosMixedEvents[0][quadrant][0]["DCA_y_vs_z"])->Fill(fgValuesColl.z, fgValues.dcaY); + } + } + } + + template + void FillResidualHistograms(Var const& fgValuesProp, Var const& fgValuesMCH, Var const& fgValuesMCHpv, Var const& fgValuesMFT, float xCls, float yCls, int topBottom, int posNeg, int quadrant, int chamber, int deIndex, bool same, bool mixed) + { + std::array xPos{xCls, fgValuesProp.x}; + std::array yPos{yCls, fgValuesProp.y}; + double phiClus = std::atan2(yCls, xCls) * 180 / TMath::Pi(); + + if constexpr (static_cast(MuonFillMap)) { + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, 20., configMuons.fPtMchLow, configMFTs.fEtaMftLow, configMFTs.fEtaMftUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + if (same) { + std::get>(mchResidualsHistosPerDE[topBottom][posNeg][chamber]["dx_vs_de"])->Fill(deIndex, xPos[0] - xPos[1]); + std::get>(mchResidualsHistosPerDE[topBottom][posNeg][chamber]["dy_vs_de"])->Fill(deIndex, yPos[0] - yPos[1]); + } + if (mixed) { + std::get>(mchResidualsHistosPerDEMixedEvents[topBottom][posNeg][chamber]["dx_vs_de"])->Fill(deIndex, xPos[0] - xPos[1]); + std::get>(mchResidualsHistosPerDEMixedEvents[topBottom][posNeg][chamber]["dy_vs_de"])->Fill(deIndex, yPos[0] - yPos[1]); + } + } + } + + if constexpr (static_cast(MFTFillMap)) { + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, 20., configMuons.fPtMchLow, configMFTs.fEtaMftLow, configMFTs.fEtaMftUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + if (IsGoodMFT(fgValuesMFT, configMFTs.fTrackChi2MftUp, configMFTs.fTrackNClustMftLow)) { + if (same) { + std::get>(residualsHistos[quadrant][chamber]["dx_vs_x"])->Fill(std::fabs(xPos[1]), xPos[0] - xPos[1]); + std::get>(residualsHistos[quadrant][chamber]["dx_vs_y"])->Fill(std::fabs(yPos[1]), xPos[0] - xPos[1]); + std::get>(residualsHistos[quadrant][chamber]["dy_vs_x"])->Fill(std::fabs(xPos[1]), yPos[0] - yPos[1]); + std::get>(residualsHistos[quadrant][chamber]["dy_vs_y"])->Fill(std::fabs(yPos[1]), yPos[0] - yPos[1]); + + // residuals vs. DE index + std::get>(residualsHistosPerDE[topBottom][posNeg][chamber]["dx_vs_de"])->Fill(deIndex, xPos[0] - xPos[1]); + std::get>(residualsHistosPerDE[topBottom][posNeg][chamber]["dy_vs_de"])->Fill(deIndex, yPos[0] - yPos[1]); + + // residuals vs. cluster phi + std::get>(residualsHistosPerDE[topBottom][posNeg][chamber]["dx_vs_phi"])->Fill(phiClus, xPos[0] - xPos[1]); + std::get>(residualsHistosPerDE[topBottom][posNeg][chamber]["dy_vs_phi"])->Fill(phiClus, yPos[0] - yPos[1]); + } + if (mixed) { + std::get>(residualsHistosMixedEvents[quadrant][chamber]["dx_vs_x"])->Fill(std::fabs(xPos[1]), xPos[0] - xPos[1]); + std::get>(residualsHistosMixedEvents[quadrant][chamber]["dx_vs_y"])->Fill(std::fabs(yPos[1]), xPos[0] - xPos[1]); + std::get>(residualsHistosMixedEvents[quadrant][chamber]["dy_vs_x"])->Fill(std::fabs(xPos[1]), yPos[0] - yPos[1]); + std::get>(residualsHistosMixedEvents[quadrant][chamber]["dy_vs_y"])->Fill(std::fabs(yPos[1]), yPos[0] - yPos[1]); + + // residuals vs. DE index + std::get>(residualsHistosPerDEMixedEvents[topBottom][posNeg][chamber]["dx_vs_de"])->Fill(deIndex, xPos[0] - xPos[1]); + std::get>(residualsHistosPerDEMixedEvents[topBottom][posNeg][chamber]["dy_vs_de"])->Fill(deIndex, yPos[0] - yPos[1]); + + // residuals vs. cluster phi + std::get>(residualsHistosPerDEMixedEvents[topBottom][posNeg][chamber]["dx_vs_phi"])->Fill(phiClus, xPos[0] - xPos[1]); + std::get>(residualsHistosPerDEMixedEvents[topBottom][posNeg][chamber]["dy_vs_phi"])->Fill(phiClus, yPos[0] - yPos[1]); + } + } + } + } + } + + template + void resetVar(Var& fgValues) + { + fgValues = {}; + } + + void initCCDB(aod::BCsWithTimestamps const& bcs) + { + // Update CCDB informations + if (bcs.size() > 0 && fCurrentRun != bcs.begin().runNumber()) { + // Load magnetic field information from CCDB/local + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + grpmag = ccdb->getForTimeStamp(configCCDB.grpmagPath, bcs.begin().timestamp()); + if (grpmag != nullptr) { + base::Propagator::initFieldFromGRP(grpmag); + TrackExtrap::setField(); + TrackExtrap::useExtrapV2(); + fieldB = static_cast(TGeoGlobalMagField::Instance()->GetField()); // for MFT + double centerMFT[3] = {0, 0, -61.4}; // or use middle point between Vtx and MFT? + Bz = fieldB->getBz(centerMFT); // Get field at centre of MFT + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", bcs.begin().timestamp()); + } + + // Load geometry information from CCDB/local + LOGF(info, "Loading reference aligned geometry from CCDB no later than %d", configCCDB.nolaterthan.value); + ccdb->setCreatedNotAfter(configCCDB.nolaterthan); // this timestamp has to be consistent with what has been used in reco + geoRef = ccdb->getForTimeStamp(configCCDB.geoPath, bcs.begin().timestamp()); + ccdb->clearCache(configCCDB.geoPath); + if (geoRef != nullptr) { + transformation = geo::transformationFromTGeoManager(*geoRef); + } else { + LOGF(fatal, "Reference aligned geometry object is not available in CCDB at timestamp=%llu", bcs.begin().timestamp()); + } + for (int i = 0; i < 156; i++) { + int iDEN = GetDetElemId(i); + transformRef[iDEN] = transformation(iDEN); + } + + if (configRealign.fDoRealign) { + LOGF(info, "Loading new aligned geometry from CCDB no later than %d", configCCDB.nolaterthanRealign.value); + ccdb->setCreatedNotAfter(configCCDB.nolaterthanRealign); // make sure this timestamp can be resolved regarding the reference one + geoNew = ccdb->getForTimeStamp(configCCDB.geoPathRealign, bcs.begin().timestamp()); + ccdb->clearCache(configCCDB.geoPathRealign); + if (geoNew != nullptr) { + transformation = geo::transformationFromTGeoManager(*geoNew); + } else { + LOGF(fatal, "New aligned geometry object is not available in CCDB at timestamp=%llu", bcs.begin().timestamp()); + } + for (int i = 0; i < 156; i++) { + int iDEN = GetDetElemId(i); + transformNew[iDEN] = transformation(iDEN); + } + } + + fCurrentRun = bcs.begin().runNumber(); + } + } + + void init(InitContext const&) + { + fCurrentRun = 0; + + // Configuration for CCDB server + ccdb->setURL(configCCDB.ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + // Configuration for track fitter + const auto& trackerParam = TrackerParam::Instance(); + trackFitter.setBendingVertexDispersion(trackerParam.bendingVertexDispersion); + trackFitter.setChamberResolution(configRealign.fChamberResolutionX, configRealign.fChamberResolutionY); + trackFitter.smoothTracks(true); + trackFitter.useChamberResolution(); + mImproveCutChi2 = 2. * configRealign.fSigmaCutImprove * configRealign.fSigmaCutImprove; + + CreateBasicHistograms(); + CreateDetailedHistograms(); + } + + template + void runDCA(TEventMap const& collisions, TBcs const& bcs, TMuons const& muons, TMFTTracks const& mfts, TTrack const& muon, mch::Track const& mchrealigned, VarC& fgValuesColl, VarT& fgValuesMCH, VarT& fgValuesMCHpv, VarT& fgValuesMFT) + { + if constexpr (static_cast(MuonFillMap)) { + + // track selection + if (!IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, 0., 30., configMFTs.fEtaMftLow, configMFTs.fEtaMftUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + return; + } + + // Loop over collisions + for (auto& [collisionId, fgValuesColltmp] : collisions) { + + bool sameEvent = (fgValuesColltmp.bc == fgValuesColl.bc); + bool mixedEvent = IsMixedEvent(fgValuesColltmp, fgValuesColl); + + if (!sameEvent && !mixedEvent) { + continue; + } + + // Fill propagation of MCH track to DCA + if (configRealign.fDoRealign) { + FillPropagation(mchrealigned, fgValuesColltmp, fgValuesMCH, kToDCA); + } else { + FillPropagation<1>(muon, fgValuesColltmp, VarTrack{}, fgValuesMCH, kToDCA); + } + + double phi = fgValuesMCH.phi * 180 / TMath::Pi(); + int quadrant = GetQuadrantPhi(phi); + int sign = (fgValuesMCH.sign > 0) ? 1 : 2; + + // Fill DCA QA histograms + FillDCAHistograms<1, 0>(fgValuesMCH, fgValuesColltmp, sign, quadrant, sameEvent, mixedEvent); + } + } + + if constexpr (static_cast(GlobalMuonFillMap)) { + auto mftsThisCollision = mfts.sliceBy(mftPerCollision, fgValuesColl.globalIndex); + for (auto const& mft : mftsThisCollision) { + + // Fill MFT track + VarTrack fgValuesMFTtmp; + FillTrack<0>(mft, fgValuesMFTtmp); + + if (fgValuesMFT.trackTime != fgValuesMFTtmp.trackTime) { + continue; // if not time compatible + } + + if (!IsGoodMFT(fgValuesMFTtmp, configMFTs.fTrackChi2MftUp, configMFTs.fTrackNClustMftLow)) { + continue; + } + + int quadrant = GetQuadrantTrack(mft); + if (quadrant < 0) { + continue; + } + + int sign = (fgValuesMFTtmp.sign > 0) ? 1 : 2; + + for (auto& [collisionId, fgValuesColltmp] : collisions) { + + bool sameEvent = (fgValuesColltmp.bc == fgValuesColl.bc); + bool mixedEvent = IsMixedEvent(fgValuesColltmp, fgValuesColl); + + if (!sameEvent && !mixedEvent) { + continue; + } + + // Propagate MFT track to DCA + FillPropagation<0, 1>(mft, fgValuesColltmp, VarTrack{}, fgValuesMFTtmp, kToDCA); + + // Fill DCA QA histograms + FillDCAHistograms<0, 1>(fgValuesMFTtmp, fgValuesColltmp, sign, quadrant, sameEvent, mixedEvent); + } + resetVar(fgValuesMFTtmp); + } + } + } + + template + void runResidual(TEventMap const& collisions, TBcs const& bcs, TMuons const& muons, TMFTTracks const& mfts, TMuonCls const& clusters, TMCHTrack const& mchtrack, mch::Track const& mchrealigned, TMFTTrack const& mfttrack, VarC const& fgValuesColl, VarT const& fgValuesMCH, VarT const& fgValuesMCHpv, VarT const& fgValuesMFT) + { + if (!IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, 20., configMuons.fPtMchLow, configMFTs.fEtaMftLow, configMFTs.fEtaMftUp, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + return; + } + + double phi = fgValuesMCH.phi * 180 / TMath::Pi(); + int quadrant = GetQuadrantPhi(phi); + + //// MCH-MFT track residuals + if (mfttrack.has_collision()) { + auto& fgValuesCollMatched = collisions.at(mfttrack.collisionId()); + + // Do extrapolation for muons to all reference planes + vector mchTrackExtrap; + for (double z : zRefPlane) { + VarTrack fgValues; + if (configRealign.fDoRealign) { + FillPropagation(mchrealigned, VarColl{}, fgValues, kToZ, z); + } else { + FillPropagation<1>(mchtrack, VarColl{}, VarTrack{}, fgValues, kToZ, z); + } + mchTrackExtrap.emplace_back(fgValues); + } + + // Loop over MFT tracks + for (auto const& mft : mfts) { + + if (!mft.has_collision()) { + continue; + } + + // Fill MFT track + VarTrack fgValuesMFTtmp; + FillTrack<0>(mft, fgValuesMFTtmp); + + // Track selection + if (!IsGoodMFT(fgValuesMFTtmp, configMFTs.fTrackChi2MftUp, configMFTs.fTrackNClustMftLow)) { + continue; + } + + auto& fgValuesCollMFT = collisions.at(mft.collisionId()); + + bool sameEvent = (fgValuesCollMFT.bc == fgValuesCollMatched.bc); + bool mixedEvent = IsMixedEvent(fgValuesCollMFT, fgValuesColl); + if (!sameEvent && !mixedEvent) { + continue; + } + + // Do extrapolation for MFTs to all reference planes + vector mftTrackExtrap; + for (double z : zRefPlane) { + VarTrack fgValues; + FillPropagation<0, 1>(mft, fgValuesCollMFT, mchTrackExtrap[1], fgValues, kToZ, z); + mftTrackExtrap.emplace_back(fgValues); + } + + //// Fill QA histograms for alignment checks + FillTrackResidualHistograms(mchTrackExtrap, mftTrackExtrap, quadrant, sameEvent, mixedEvent); + + resetVar(fgValuesMFTtmp); + } + } + + //// Track-Cluster residuals + for (auto const& muon : muons) { + if (static_cast(muon.trackType()) <= 2) { + continue; + } + if (!muon.has_collision()) { + continue; + } + auto& fgValuesCollMCH = collisions.at(muon.collisionId()); + + bool sameEvent = (fgValuesCollMCH.bc == fgValuesColl.bc); + bool mixedEvent = IsMixedEvent(fgValuesCollMCH, fgValuesColl); + if (!sameEvent && !mixedEvent) { + continue; + } + + //// Fill MCH clusters: do re-alignment if asked + mch::Track mchrealignedTmp; + VarClusters fgValuesClsTmp; + if (!FillClusters(muon, clusters, fgValuesClsTmp, mchrealignedTmp)) { + continue; // Refit is not valid + } + + // Loop over attached clusters + for (int iCls = 0; iCls < int(fgValuesClsTmp.posClusters.size()); iCls++) { + + double phiCls = std::atan2(fgValuesClsTmp.posClusters[iCls][1], fgValuesClsTmp.posClusters[iCls][0]) * 180 / TMath::Pi(); + int quadrantCls = GetQuadrantPhi(phiCls); + int DEId = fgValuesClsTmp.DEIDs[iCls]; + int chamber = DEId / 100 - 1; + int deIndex = DEId % 100; + + //// MCH residuals + //// Propagate MCH track to given cluster + VarTrack fgValuesMCHprop; + if (configRealign.fDoRealign) { + FillPropagation(mchrealigned, VarColl{}, fgValuesMCHprop, kToZ, fgValuesClsTmp.posClusters[iCls][2]); + } else { + FillPropagation<1>(mchtrack, VarColl{}, VarTrack{}, fgValuesMCHprop, kToZ, fgValuesClsTmp.posClusters[iCls][2]); + } + + //// Fill residual QA histograms + int topBottom = (fgValuesMCH.y >= 0) ? 0 : 1; + int posNeg = (fgValuesMCH.sign >= 0) ? 0 : 1; + FillResidualHistograms<1, 0>(fgValuesMCHprop, fgValuesMCH, fgValuesMCHpv, fgValuesMFT, fgValuesClsTmp.posClusters[iCls][0], fgValuesClsTmp.posClusters[iCls][1], topBottom, posNeg, quadrantCls, chamber, deIndex, sameEvent, mixedEvent); + resetVar(fgValuesMCHprop); + + //// MFT residuals + if (IsGoodMFT(fgValuesMFT, configMFTs.fTrackChi2MftUp, configMFTs.fTrackNClustMftLow)) { + //// Propagate MFT track to given cluster + VarTrack fgValuesMFTprop; + FillPropagation<0, 1>(mfttrack, VarColl{}, fgValuesMCH, fgValuesMFTprop, kToZ, fgValuesClsTmp.posClusters[iCls][2]); + + //// Fill residual QA histograms for MFT + topBottom = (mfttrack.y() >= 0) ? 0 : 1; + posNeg = (fgValuesMCH.sign >= 0) ? 0 : 1; + FillResidualHistograms<0, 1>(fgValuesMFTprop, fgValuesMCH, fgValuesMCHpv, fgValuesMFT, fgValuesClsTmp.posClusters[iCls][0], fgValuesClsTmp.posClusters[iCls][1], topBottom, posNeg, quadrantCls, chamber, deIndex, sameEvent, mixedEvent); + resetVar(fgValuesMFTprop); + } + } + } + } + + template + void runEventSelection(TEvents const& collisions, TBcs const& bcs, TFwdTracks const& muons, TMFTTracks const& mfts, TMap& collisionSel) + { + for (auto const& collision : collisions) { + + uint64_t collisionIndex = collision.globalIndex(); + auto muonsThisCollision = muons.sliceBy(fwdtracksPerCollision, collisionIndex); + auto mftsThisCollision = mfts.sliceBy(mftPerCollision, collisionIndex); + + if (muonsThisCollision.size() < 1 && mftsThisCollision.size() < 1) { + continue; + } + + auto& fgValuesColl = collisionSel[collisionIndex]; + FillCollision(collision, fgValuesColl); + fgValuesColl.bc = bcs.rawIteratorAt(collision.bcId()).globalBC(); + fgValuesColl.multMFT = mftsThisCollision.size(); + } + } + + template + void runMuonQA(TEventMap const& collisions, TCandidateMap& matchingCandidates, TBcs const& bcs, TFwdTracks const& muons, TMFTTracks const& mfts, TMuonCls const& clusters) + { + //// First loop over all muon tracks + for (auto const& muon : muons) { + + //// Get collision information if associated + VarColl fgValuesColl; + if (muon.has_collision()) { + fgValuesColl = collisions.at(muon.collisionId()); + } else { + continue; + } + + if (static_cast(muon.trackType()) <= 2) { // MFT-MCH-MID(0) or MFT-MCH(2) + + registry.get(HIST("global-muons/nTracksPerType"))->Fill(static_cast(muon.trackType())); + + auto mfttrack = muon.template matchMFTTrack_as(); + auto mchtrack = muon.template matchMCHTrack_as(); + + // Fill global matching candidates: global muons per MCH track + FillMatchingCandidates(muon, mchtrack, matchingCandidates); + + } else { // MCH-MID(3) or MCH(4) + + // Fill MCH tracks + FillTrack<1>(muon, fgValuesMCH); + + // Propagate MCH to PV + FillPropagation<1>(muon, fgValuesColl, fgValuesMCH, fgValuesMCHpv); // copied in a separate variable + + //// Fill MCH clusters: re-align clusters if required + mch::Track mchrealigned; + VarClusters fgValuesCls; + if (!FillClusters(muon, clusters, fgValuesCls, mchrealigned)) { + continue; // if refit was not passed + } + + //// Update MCH tracks kinematics if using realigned muons + if (configRealign.fDoRealign) { + + // Update track info + FillTrack(mchrealigned, fgValuesMCH); + + // Update propagate of MCH to PV + FillPropagation(mchrealigned, fgValuesColl, fgValuesMCHpv); + + // Update pDCA and Rabs values + FillPropagation(mchrealigned, fgValuesColl, fgValuesMCH, kToAbsEnd); + FillPropagation(mchrealigned, fgValuesColl, fgValuesMCH, kToDCA); + } + + //// Fill muon QA histograms + FillMuonHistograms<1, 0, 0>(fgValuesMCH, fgValuesMCHpv, fgValuesMFT, VarTrack{}, nullptr); + + //// Fill muon DCA QA checks + if (configQAs.fEnableQADCA) { + runDCA<1, 0>(collisions, bcs, muons, mfts, muon, mchrealigned, fgValuesColl, fgValuesMCH, fgValuesMCHpv, fgValuesMFT); + } + } + + resetVar(fgValuesMFT); + resetVar(fgValuesMCH); + resetVar(fgValuesMCHpv); + } + + //// Second loop over global muon tracks + for (auto& [mchIndex, globalMuonsVector] : matchingCandidates) { + + //// sort matching candidates in ascending order based on the matching chi2 + auto compareChi2 = [&muons](uint64_t trackIndex1, uint64_t trackIndex2) -> bool { + auto const& track1 = muons.rawIteratorAt(trackIndex1); + auto const& track2 = muons.rawIteratorAt(trackIndex2); + + return (track1.chi2MatchMCHMFT() < track2.chi2MatchMCHMFT()); + }; + std::sort(globalMuonsVector.begin(), globalMuonsVector.end(), compareChi2); + + //// Get tracks + auto muontrack = muons.rawIteratorAt(globalMuonsVector[0]); + auto mchtrack = muontrack.template matchMCHTrack_as(); + auto mfttrack = muontrack.template matchMFTTrack_as(); + + //// Fill matching chi2 + FillMatching(muontrack, fgValuesMCH, fgValuesMFT); + + //// Fill global informations + registry.get(HIST("global-muons/NCandidates"))->Fill(int(globalMuonsVector.size())); + for (size_t candidateIndex = 0; candidateIndex < globalMuonsVector.size(); candidateIndex++) { + auto const& muon = muons.rawIteratorAt(globalMuonsVector[candidateIndex]); + registry.get(HIST("global-muons/MatchChi2"))->Fill(muon.chi2MatchMCHMFT(), candidateIndex); + } + + //// Fill collision information if avalaible + auto& fgValuesCollGlo = collisions.at(muontrack.collisionId()); + VarColl fgValuesCollMCH; // in principal should be the same as global muon + if (mchtrack.has_collision()) { + fgValuesCollMCH = collisions.at(mchtrack.collisionId()); + } + + //// Fill MCH and MFT tracks: basic info copied from input tables + FillTrack<1>(mchtrack, fgValuesMCH); + FillTrack<0>(mfttrack, fgValuesMFT); + FillTrack<1>(muontrack, fgValuesGlobal); + + //// Propagate MCH to PV + FillPropagation<1>(mchtrack, fgValuesCollMCH, VarTrack{}, fgValuesMCHpv); // saved in separate variable fgValuesMCHpv + + //// Fill MCH clusters: re-align clusters if required + mch::Track mchrealigned; + VarClusters fgValuesCls; + if (!FillClusters(mchtrack, clusters, fgValuesCls, mchrealigned)) { + continue; // if refit was not passed + } + + //// Update MCH tracks kinematics if using realigned muons + if (configRealign.fDoRealign) { + // Update track info + FillTrack(mchrealigned, fgValuesMCH); + + // Update propagation of MCH to PV + FillPropagation(mchrealigned, fgValuesCollMCH, fgValuesMCHpv); + + // Update pDCA and Rabs values + FillPropagation(mchrealigned, fgValuesCollMCH, fgValuesMCH, kToAbsEnd); + FillPropagation(mchrealigned, fgValuesCollMCH, fgValuesMCH, kToDCA); + } + + //// Fill global muon candidates info + for (int i = 0; i < int(globalMuonsVector.size()); i++) { + VarTrack fgValuesTmp; + auto muonCandidate = muons.rawIteratorAt(globalMuonsVector[i]); + FillTrack<0>(muonCandidate, fgValuesTmp); + fgValuesCandidates.emplace_back(fgValuesTmp); + } + + //// Fill global muons QA : fill global matching QA if required + if (configQAs.fEnableQAMatching) { + + // Propagate global muon tracks to DCA: treat it as MFT using p from MCH? + FillPropagation<0, 1>(muontrack, fgValuesCollGlo, fgValuesMCH, fgValuesGlobal, kToDCA); + + // Fill bc difference of matched MCH and MFT + if (muontrack.has_collision() && mfttrack.has_collision()) { + fgValuesMCH.bc = collisions.at(muontrack.collisionId()).bc; + fgValuesMFT.bc = collisions.at(mfttrack.collisionId()).bc; + int64_t dbc = fgValuesMCH.bc - fgValuesMFT.bc; + registry.get(HIST("global-matches/BCdifference"))->Fill(dbc); + } + + // Fill QA histograms including global matching + FillMuonHistograms<0, 1, 1>(fgValuesMCH, fgValuesMCHpv, fgValuesMFT, fgValuesGlobal, fgValuesCandidates); + + } else { + // Fill QA histograms + FillMuonHistograms<0, 1, 0>(fgValuesMCH, fgValuesMCHpv, fgValuesMFT, fgValuesGlobal, fgValuesCandidates); + } + + //// Fill residual QA checks if requireds + if (configQAs.fEnableQAResidual) { + runResidual(collisions, bcs, muons, mfts, clusters, mchtrack, mchrealigned, mfttrack, fgValuesCollGlo, fgValuesMCH, fgValuesMCHpv, fgValuesMFT); + } + + //// Fill MFT DCA QA checks if required + if (configQAs.fEnableQADCA) { + runDCA<0, 1>(collisions, bcs, muons, mfts, nullptr, mch::Track(), fgValuesCollGlo, fgValuesMCH, fgValuesMCHpv, fgValuesMFT); + } + + fgValuesCandidates.clear(); + resetVar(fgValuesMFT); + resetVar(fgValuesMCH); + resetVar(fgValuesMCHpv); + resetVar(fgValuesGlobal); + } + } + + template + void runDimuonQA(TEventMap const& collisions, TCandidateMap const& matchingCandidates, TFwdTracks const& muonTracks, TMuonCls const& clusters) + { + std::vector muonPairs; + std::vector globalMuonPairs; + + GetMuonPairs(muonTracks, matchingCandidates, collisions, muonPairs, globalMuonPairs); + + for (auto& [muon1, muon2] : muonPairs) { + auto collisionIndex1 = muon1.first; + auto const& collision1 = collisions.at(collisionIndex1); + auto collisionIndex2 = muon2.first; + auto const& collision2 = collisions.at(collisionIndex2); + + auto mchIndex1 = muon1.second; + auto mchIndex2 = muon2.second; + auto const& muonTrack1 = muonTracks.rawIteratorAt(mchIndex1); + auto const& muonTrack2 = muonTracks.rawIteratorAt(mchIndex2); + + VarTrack fgValuesMuon1, fgValuesMuonPV1; + VarTrack fgValuesMuon2, fgValuesMuonPV2; + mch::Track mchrealigned1, mchrealigned2; + VarClusters fgValuesCls1, fgValuesCls2; + if (!FillClusters(muonTrack1, clusters, fgValuesCls1, mchrealigned1) || !FillClusters(muonTrack2, clusters, fgValuesCls2, mchrealigned2)) { + continue; // Refit is not valid + } + + if (configRealign.fDoRealign) { + + FillTrack(mchrealigned1, fgValuesMuon1); + FillTrack(mchrealigned2, fgValuesMuon2); + + // Propagate MCH to PV + FillPropagation(mchrealigned1, collision1, fgValuesMuonPV1); + FillPropagation(mchrealigned2, collision2, fgValuesMuonPV2); + + // Recalculate pDCA and Rabs values + FillPropagation(mchrealigned1, collision1, fgValuesMuon1, kToAbsEnd); + FillPropagation(mchrealigned1, collision1, fgValuesMuon1, kToDCA); + FillPropagation(mchrealigned2, collision2, fgValuesMuon2, kToAbsEnd); + FillPropagation(mchrealigned2, collision2, fgValuesMuon2, kToDCA); + } else { + FillTrack<1>(muonTrack1, fgValuesMuon1); + FillTrack<1>(muonTrack2, fgValuesMuon2); + + // Propagate MCH to PV + FillPropagation<1>(muonTrack1, collision1, fgValuesMuon1, fgValuesMuonPV1); + FillPropagation<1>(muonTrack2, collision2, fgValuesMuon1, fgValuesMuonPV2); + } + + int sign1 = muonTrack1.sign(); + int sign2 = muonTrack2.sign(); + + // only consider opposite-sign pairs + if ((sign1 * sign2) >= 0) + continue; + + int posQuadrant = (sign1 > 0) ? GetQuadrantPhi(muonTrack1.phi() * 180.0 / TMath::Pi()) + : GetQuadrantPhi(muonTrack2.phi() * 180.0 / TMath::Pi()); + int negQuadrant = (sign1 < 0) ? GetQuadrantPhi(muonTrack1.phi() * 180.0 / TMath::Pi()) + : GetQuadrantPhi(muonTrack2.phi() * 180.0 / TMath::Pi()); + int posTopBottom = (posQuadrant == 0 || posQuadrant == 1) ? 0 : 1; + int negTopBottom = (negQuadrant == 0 || negQuadrant == 1) ? 0 : 1; + + bool goodMuonTracks = (IsGoodMuon(fgValuesMuon1, fgValuesMuonPV1) && IsGoodMuon(fgValuesMuon2, fgValuesMuonPV2)); + bool goodGlobalMuonTracks = (IsGoodGlobalMuon(fgValuesMuon1, fgValuesMuonPV1) && IsGoodGlobalMuon(fgValuesMuon2, fgValuesMuonPV2)); + + bool sameEvent = (collisionIndex1 == collisionIndex2); + + double mass = GetMuMuInvariantMass(fgValuesMuonPV1, fgValuesMuonPV2); + if (goodMuonTracks) { + if (sameEvent) { + // same-event case + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_MuonCuts"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts"))->Fill(mass); + + if (posTopBottom == 0 && negTopBottom == 0) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_MuonCuts_TT"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_TT"))->Fill(mass); + } else if ((posTopBottom == 0 && negTopBottom == 1) || (posTopBottom == 1 && negTopBottom == 0)) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_MuonCuts_TB"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_TB"))->Fill(mass); + } else if (posTopBottom == 1 && negTopBottom == 1) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_MuonCuts_BB"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_BB"))->Fill(mass); + } + } else { + // event-mixing case + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts"))->Fill(mass); + + if (posTopBottom == 0 && negTopBottom == 0) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_TT"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_TT"))->Fill(mass); + } else if ((posTopBottom == 0 && negTopBottom == 1) || (posTopBottom == 1 && negTopBottom == 0)) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_TB"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_TB"))->Fill(mass); + } else if (posTopBottom == 1 && negTopBottom == 1) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_BB"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_BB"))->Fill(mass); + } + } + } + + if (goodGlobalMuonTracks) { + if (sameEvent) { + // same-event case + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts"))->Fill(mass); + + if (posTopBottom == 0 && negTopBottom == 0) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_TT"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_TT"))->Fill(mass); + } else if ((posTopBottom == 0 && negTopBottom == 1) || (posTopBottom == 1 && negTopBottom == 0)) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_TB"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_TB"))->Fill(mass); + } else if (posTopBottom == 1 && negTopBottom == 1) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_BB"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_BB"))->Fill(mass); + } + } else { + // event-mixing case + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts"))->Fill(mass); + + if (posTopBottom == 0 && negTopBottom == 0) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_TT"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_TT"))->Fill(mass); + } else if ((posTopBottom == 0 && negTopBottom == 1) || (posTopBottom == 1 && negTopBottom == 0)) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_TB"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_TB"))->Fill(mass); + } else if (posTopBottom == 1 && negTopBottom == 1) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_BB"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_BB"))->Fill(mass); + } + } + } + } + + for (auto& [muon1, muon2] : globalMuonPairs) { + auto collisionIndex1 = muon1.first; + auto collisionIndex2 = muon2.first; + auto& globalTracksVector1 = muon1.second; + auto& globalTracksVector2 = muon2.second; + + auto const& collision1 = collisions.at(collisionIndex1); + auto const& collision2 = collisions.at(collisionIndex2); + + auto const& muonTrack1 = muonTracks.rawIteratorAt(globalTracksVector1[0]); + auto const& muonTrack2 = muonTracks.rawIteratorAt(globalTracksVector2[0]); + auto const& mftTrack1 = muonTrack1.template matchMFTTrack_as(); + auto const& mftTrack2 = muonTrack2.template matchMFTTrack_as(); + auto const& mchTrack1 = muonTrack1.template matchMCHTrack_as(); + auto const& mchTrack2 = muonTrack2.template matchMCHTrack_as(); + + VarTrack fgValuesMuon1, fgValuesMuonPV1, fgValuesMCH1, fgValuesMCHpv1, fgValuesMFT1, fgValuesMFTpv1; + VarTrack fgValuesMuon2, fgValuesMuonPV2, fgValuesMCH2, fgValuesMCHpv2, fgValuesMFT2, fgValuesMFTpv2; + + // Fill MCH and MFT tracks + FillTrack<1>(mchTrack1, fgValuesMCH1); + FillTrack<0>(mftTrack1, fgValuesMFT1); + FillTrack<1>(muonTrack1, fgValuesMuon1); + FillTrack<1>(mchTrack2, fgValuesMCH2); + FillTrack<0>(mftTrack2, fgValuesMFT2); + FillTrack<1>(muonTrack2, fgValuesMuon2); + + //// Fill matching chi2 + FillMatching(muonTrack1, fgValuesMCH1, fgValuesMFT1); + FillMatching(muonTrack2, fgValuesMCH2, fgValuesMFT2); + + mch::Track mchrealigned1, mchrealigned2; + VarClusters fgValuesCls1, fgValuesCls2; + if (!FillClusters(muonTrack1, clusters, fgValuesCls1, mchrealigned1) || !FillClusters(muonTrack2, clusters, fgValuesCls2, mchrealigned2)) { + continue; // Refit is not valid + } + + if (configRealign.fDoRealign) { + + FillTrack(mchrealigned1, fgValuesMCH1); + FillTrack(mchrealigned2, fgValuesMCH2); + + // Propagate MCH to PV + FillPropagation(mchrealigned1, collision1, fgValuesMCHpv1); + FillPropagation(mchrealigned2, collision2, fgValuesMCHpv2); + + // Recalculate pDCA and Rabs values + FillPropagation(mchrealigned1, collision1, fgValuesMCH1, kToAbsEnd); + FillPropagation(mchrealigned1, collision1, fgValuesMCH1, kToDCA); + FillPropagation(mchrealigned2, collision2, fgValuesMCH2, kToAbsEnd); + FillPropagation(mchrealigned2, collision2, fgValuesMCH2, kToDCA); + + } else { + FillTrack<1>(mchTrack1, fgValuesMCH1); + FillTrack<1>(mchTrack2, fgValuesMCH2); + + // Propagate MCH to PV + FillPropagation<1>(mchTrack1, collision1, fgValuesMCH1, fgValuesMCHpv1); + FillPropagation<1>(mchTrack2, collision2, fgValuesMCH2, fgValuesMCHpv2); + } + + // Propagate global muon tracks to PV + FillPropagation<0>(muonTrack1, collision1, fgValuesMCH1, fgValuesMuonPV1); + FillPropagation<0>(muonTrack2, collision2, fgValuesMCH2, fgValuesMuonPV2); + + // Propagate MFT tracks to PV + FillPropagation<0, 1>(mftTrack1, collision1, fgValuesMCH1, fgValuesMFTpv1); + FillPropagation<0, 1>(mftTrack2, collision2, fgValuesMCH2, fgValuesMFTpv2); + + int sign1 = mchTrack1.sign(); + int sign2 = mchTrack2.sign(); + + // only consider opposite-sign pairs + if ((sign1 * sign2) >= 0) + continue; + + // indexes indicating whether the positive and negative tracks come from the top or bottom halves of MFT + int posTopBottom = (sign1 > 0) ? ((muonTrack1.y() >= 0) ? 0 : 1) : ((muonTrack2.y() >= 0) ? 0 : 1); + int negTopBottom = (sign1 < 0) ? ((muonTrack1.y() >= 0) ? 0 : 1) : ((muonTrack2.y() >= 0) ? 0 : 1); + + bool goodGlobalMuonTracks = (IsGoodGlobalMuon(fgValuesMCH1, fgValuesMCHpv1) && IsGoodGlobalMuon(fgValuesMCH2, fgValuesMCHpv2)); + bool goodGlobalMuonMatches = (IsGoodGlobalMatching(fgValuesMFT1) && IsGoodGlobalMatching(fgValuesMFT2)); + + bool sameEvent = (collisionIndex1 == collisionIndex2); + + if (goodGlobalMuonTracks && goodGlobalMuonMatches) { + + double massMCH = GetMuMuInvariantMass(fgValuesMCHpv1, fgValuesMCHpv2); + double mass = GetMuMuInvariantMass(fgValuesMuonPV1, fgValuesMuonPV2); + double massScaled = GetMuMuInvariantMass(fgValuesMFTpv1, fgValuesMFTpv2); + + if (sameEvent) { + // same-event case + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMatchesCuts"))->Fill(massMCH); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_GlobalMatchesCuts"))->Fill(massMCH); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_GlobalMuonKine_GlobalMatchesCuts"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_ScaledMftKine_GlobalMatchesCuts"))->Fill(massScaled); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_ScaledMftKine_GlobalMatchesCuts"))->Fill(massScaled); + + if (posTopBottom == 0 && negTopBottom == 0) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_TT"))->Fill(massScaled); + } else if (posTopBottom == 0 && negTopBottom == 1) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_TB"))->Fill(massScaled); + } else if (posTopBottom == 1 && negTopBottom == 0) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_BT"))->Fill(massScaled); + } else if (posTopBottom == 1 && negTopBottom == 1) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_BB"))->Fill(massScaled); + } + + // mass correlation + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_vs_GlobalMuonKine"))->Fill(mass, massMCH); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_ScaledMftKine_vs_GlobalMuonKine"))->Fill(mass, massScaled); + } else { + // event-mixing case + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMatchesCuts"))->Fill(massMCH); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMatchesCuts"))->Fill(massMCH); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_GlobalMuonKine_GlobalMatchesCuts"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_ScaledMftKine_GlobalMatchesCuts"))->Fill(massScaled); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_ScaledMftKine_GlobalMatchesCuts"))->Fill(massScaled); + + if (posTopBottom == 0 && negTopBottom == 0) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_TT"))->Fill(massScaled); + } else if (posTopBottom == 0 && negTopBottom == 1) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_TB"))->Fill(massScaled); + } else if (posTopBottom == 1 && negTopBottom == 0) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_BT"))->Fill(massScaled); + } else if (posTopBottom == 1 && negTopBottom == 1) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_BB"))->Fill(massScaled); + } + } + } + + // plots for sub-leading matches are only filled in the same-event case + if (sameEvent) { + if (globalTracksVector1.size() > 1) { + VarTrack fgValuesMuonb1, fgValuesMuonbpv1, fgValuesMFTb1; + auto const& muonTrack1b = muonTracks.rawIteratorAt(globalTracksVector1[1]); + FillTrack<1>(muonTrack1b, fgValuesMuonb1); + FillPropagation<0>(muonTrack1b, collision1, fgValuesMCH1, fgValuesMuonbpv1); + + goodGlobalMuonTracks = (IsGoodGlobalMuon(fgValuesMCH1, fgValuesMCHpv1) && IsGoodGlobalMuon(fgValuesMCH2, fgValuesMCHpv2)); + goodGlobalMuonMatches = (IsGoodGlobalMatching(fgValuesMFTb1) && IsGoodGlobalMatching(fgValuesMFT2)); + double mass = GetMuMuInvariantMass(fgValuesMuonbpv1, fgValuesMuonPV2); + if (goodGlobalMuonTracks && goodGlobalMuonMatches) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_subleading_leading"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_GlobalMuonKine_GlobalMatchesCuts_subleading_leading"))->Fill(mass); + } + } + + if (globalTracksVector2.size() > 1) { + VarTrack fgValuesMuonb2, fgValuesMuonbpv2, fgValuesMFTb2; + auto const& muonTrack2b = muonTracks.rawIteratorAt(globalTracksVector2[1]); + FillTrack<1>(muonTrack2b, fgValuesMuonb2); + FillPropagation<0>(muonTrack2b, collision2, fgValuesMCH2, fgValuesMuonbpv2); + + goodGlobalMuonTracks = (IsGoodGlobalMuon(fgValuesMCH1, fgValuesMCHpv1) && IsGoodGlobalMuon(fgValuesMCH2, fgValuesMCHpv2)); + goodGlobalMuonMatches = (IsGoodGlobalMatching(fgValuesMFTb2) && IsGoodGlobalMatching(fgValuesMFT1)); + double mass = GetMuMuInvariantMass(fgValuesMuonbpv2, fgValuesMuonPV1); + if (goodGlobalMuonTracks && goodGlobalMuonMatches) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_leading_subleading"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_GlobalMuonKine_GlobalMatchesCuts_leading_subleading"))->Fill(mass); + } + } + + if (globalTracksVector1.size() > 1 && globalTracksVector2.size() > 1) { + VarTrack fgValuesMuonb1, fgValuesMuonbpv1, fgValuesMFTb1; + VarTrack fgValuesMuonb2, fgValuesMuonbpv2, fgValuesMFTb2; + auto const& muonTrack1b = muonTracks.rawIteratorAt(globalTracksVector1[1]); + auto const& muonTrack2b = muonTracks.rawIteratorAt(globalTracksVector2[1]); + + FillTrack<1>(muonTrack1b, fgValuesMuonb1); + FillPropagation<0>(muonTrack1b, collision1, fgValuesMCH1, fgValuesMuonbpv1); + + FillTrack<1>(muonTrack2b, fgValuesMuonb2); + FillPropagation<0>(muonTrack2b, collision2, fgValuesMCH2, fgValuesMuonbpv2); + + goodGlobalMuonTracks = (IsGoodGlobalMuon(fgValuesMCH1, fgValuesMCHpv1) && IsGoodGlobalMuon(fgValuesMCH2, fgValuesMCHpv2)); + goodGlobalMuonMatches = (IsGoodGlobalMatching(fgValuesMFTb1) && IsGoodGlobalMatching(fgValuesMFTb2)); + double mass = GetMuMuInvariantMass(fgValuesMuonbpv1, fgValuesMuonbpv2); + double massLeading = GetMuMuInvariantMass(fgValuesMuonPV1, fgValuesMuonPV2); + if (goodGlobalMuonTracks && goodGlobalMuonMatches) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_subleading_subleading"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_GlobalMuonKine_GlobalMatchesCuts_subleading_subleading"))->Fill(mass); + + // mass correlation + registryDimuon.get(HIST("dimuon/same-event/invariantMass_GlobalMuonKine_subleading_vs_leading"))->Fill(massLeading, mass); + } + } + } + } + } + + void processMuonQa(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, MyMuonsWithCov const& muontracks, MyMFTs const& mfttracks, aod::FwdTrkCls const& muonclusters) + { + std::map collisionSel; + std::map> matchingCandidates; + + initCCDB(bcs); + + runEventSelection(collisions, bcs, muontracks, mfttracks, collisionSel); + + runMuonQA(collisionSel, matchingCandidates, bcs, muontracks, mfttracks, muonclusters); + + if (configQAs.fEnableQADimuon) { + runDimuonQA(collisionSel, matchingCandidates, muontracks, muonclusters); + } + } + PROCESS_SWITCH(muonQa, processMuonQa, "Process to run muon QA", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/Common/Tasks/qVectorsCorrection.cxx b/Common/Tasks/qVectorsCorrection.cxx index 73d4d992792..10e37a4c210 100644 --- a/Common/Tasks/qVectorsCorrection.cxx +++ b/Common/Tasks/qVectorsCorrection.cxx @@ -25,6 +25,7 @@ #include #include #include +#include // o2Physics includes. #include "Framework/AnalysisDataModel.h" @@ -36,13 +37,21 @@ #include "Framework/StaticFor.h" #include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "Common/Core/EventPlaneHelper.h" +#include "Common/Core/TrackSelection.h" + +#include "CommonConstants/PhysicsConstants.h" // o2 includes. using namespace o2; using namespace o2::framework; +using MyCollisions = soa::Join; +using MyTracks = soa::Join; + struct qVectorsCorrection { // No correction = recenter, recentered Qvectors = twist, twisted Qvectors = rescale. // NOTE: As of no, the twist gets both twist and rescale correction constants. @@ -52,15 +61,39 @@ struct qVectorsCorrection { // as TDirectoryFile. HistogramRegistry histosQA{"histosQA", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - Configurable cfgnMod{"cfgnMod", 2, "Modulation of interest"}; + Configurable> cfgnMods{"cfgnMods", {2, 3}, "Modulation of interest"}; Configurable cfgDetName{"cfgDetName", "FT0C", "The name of detector to be analyzed"}; - Configurable cfgRefAName{"cfgRefAName", "BPos", "The name of detector for reference A"}; - Configurable cfgRefBName{"cfgRefBName", "BNeg", "The name of detector for reference B"}; + Configurable cfgRefAName{"cfgRefAName", "TPCpos", "The name of detector for reference A"}; + Configurable cfgRefBName{"cfgRefBName", "TPCneg", "The name of detector for reference B"}; + Configurable cfgAddEvtSel{"cfgAddEvtSel", true, "event selection"}; + + Configurable cfgnTotalSystem{"cfgnTotalSystem", 7, "total qvector number"}; + Configurable cfgNbinsEP{"cfgNbinsEP", 360, "nbins for EP histograms"}; + + Configurable cfgQAAll{"cfgQAAll", false, "draw all q-vector steps"}; + Configurable cfgQAFinal{"cfgQAFinal", false, "draw final q-vector steps"}; + Configurable cfgQAFlowStudy{"cfgQAFlowStudy", false, "configurable for flow study"}; + Configurable cfgQAOccupancyStudy{"cfgQAOccupancyStudy", false, "configurable for occupancy study"}; + Configurable cfgAddEvtSelPileup{"cfgAddEvtSelPileup", false, "configurable for pileup selection"}; + + Configurable cfgMinPt{"cfgMinPt", 0.15, "Minimum transverse momentum for charged track"}; + Configurable cfgMaxEta{"cfgMaxEta", 0.8, "Maximum pseudorapidiy for charged track"}; + Configurable cfgMaxDCArToPVcut{"cfgMaxDCArToPVcut", 0.1, "Maximum transverse DCA"}; + Configurable cfgMaxDCAzToPVcut{"cfgMaxDCAzToPVcut", 1.0, "Maximum longitudinal DCA"}; - ConfigurableAxis cfgaxisQvecF{"cfgaxisQvecF", {100, -1, 1}, ""}; + Configurable cfgMaxOccupancy{"cfgMaxOccupancy", 999999, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable cfgMinOccupancy{"cfgMinOccupancy", 0, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + + ConfigurableAxis cfgaxisQvecF{"cfgaxisQvecF", {300, -1, 1}, ""}; ConfigurableAxis cfgaxisQvec{"cfgaxisQvec", {100, -3, 3}, ""}; - ConfigurableAxis cfgaxisCent{"cfgaxisCent", {90, 0, 90}, ""}; + ConfigurableAxis cfgaxisCent{"cfgaxisCent", {100, 0, 100}, ""}; + + ConfigurableAxis cfgaxiscos{"cfgaxiscos", {102, -1.02, 1.02}, ""}; + ConfigurableAxis cfgaxispt{"cfgaxispt", {100, 0, 10}, ""}; + ConfigurableAxis cfgaxisCentMerged{"cfgaxisCentMerged", {20, 0, 100}, ""}; + ConfigurableAxis cfgaxisAzimuth{"cfgaxisAzimuth", {72, 0, 2.0 * constants::math::PI}, ""}; + ConfigurableAxis cfgaxisOccupancy{"cfgaxisOccupancy", {VARIABLE_WIDTH, -1, 0, 100, 500, 1000, 2000, 3000, 4000, 5000, 10000, 99999}, ""}; // Helper variables. EventPlaneHelper helperEP; @@ -72,6 +105,9 @@ struct qVectorsCorrection { template int GetDetId(const T& name) { + if (name.value == "BPos" || name.value == "BNeg" || name.value == "BTot") { + LOGF(warning, "Using deprecated label: %s. Please use TPCpos, TPCneg, TPCall instead.", name.value); + } if (name.value == "FT0C") { return 0; } else if (name.value == "FT0A") { @@ -80,15 +116,40 @@ struct qVectorsCorrection { return 2; } else if (name.value == "FV0A") { return 3; - } else if (name.value == "BPos") { + } else if (name.value == "TPCpos" || name.value == "BPos") { return 4; - } else if (name.value == "BNeg") { + } else if (name.value == "TPCneg" || name.value == "BNeg") { return 5; + } else if (name.value == "TPCall" || name.value == "BTot") { + return 6; } else { return 0; } } + template + bool SelTrack(const TrackType track) + { + if (track.pt() < 0.15) + return false; + if (!track.passedITSNCls()) + return false; + if (!track.passedITSChi2NDF()) + return false; + if (!track.passedITSHits()) + return false; + if (!track.passedTPCCrossedRowsOverNCls()) + return false; + if (!track.passedTPCChi2NDF()) + return false; + if (!track.passedDCAxy()) + return false; + if (!track.passedDCAz()) + return false; + + return true; + } + void init(InitContext const&) { DetId = GetDetId(cfgDetName); @@ -96,7 +157,7 @@ struct qVectorsCorrection { RefBId = GetDetId(cfgRefBName); if (DetId == RefAId || DetId == RefBId || RefAId == RefBId) { - LOGF(info, "Wrong detector configuration \n The FT0C will be used to get Q-Vector \n The BPos and BNeg will be used as reference systems"); + LOGF(info, "Wrong detector configuration \n The FT0C will be used to get Q-Vector \n The TPCpos and TPCneg will be used as reference systems"); DetId = 0; RefAId = 4; RefBId = 5; @@ -106,98 +167,398 @@ struct qVectorsCorrection { AxisSpec axisCent{cfgaxisCent, "centrality"}; AxisSpec axisQvec{cfgaxisQvec, "Q"}; AxisSpec axisQvecF{cfgaxisQvecF, "Q"}; - AxisSpec axisEvtPl{360, -constants::math::PI, constants::math::PI}; + AxisSpec axisEvtPl{cfgNbinsEP, -constants::math::PI, constants::math::PI}; + + AxisSpec axisCos{cfgaxiscos, "angle function"}; + AxisSpec axisPt{cfgaxispt, "trasverse momentum"}; + AxisSpec axisCentMerged{cfgaxisCentMerged, "merged centrality"}; + AxisSpec axisAzimuth{cfgaxisAzimuth, "relative azimuthal angle"}; + AxisSpec axisOccupancy{cfgaxisOccupancy, "Occupancy"}; histosQA.add("histCentFull", "Centrality distribution for valid events", HistType::kTH1F, {axisCent}); - histosQA.add("histQvecUncor", "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); - histosQA.add("histQvecRectr", "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); - histosQA.add("histQvecTwist", "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); - histosQA.add("histQvecFinal", "", {HistType::kTH3F, {axisQvec, axisQvec, axisCent}}); + for (uint i = 0; i < cfgnMods->size(); i++) { + histosQA.add(Form("histQvecUncorV%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); + histosQA.add(Form("histQvecRefAUncorV%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); + histosQA.add(Form("histQvecRefBUncorV%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); - histosQA.add("histQvecRefAUncor", "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); - histosQA.add("histQvecRefARectr", "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); - histosQA.add("histQvecRefATwist", "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); - histosQA.add("histQvecRefAFinal", "", {HistType::kTH3F, {axisQvec, axisQvec, axisCent}}); + histosQA.add(Form("histEvtPlUncorV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("histEvtPlRefAUncorV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("histEvtPlRefBUncorV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); - histosQA.add("histQvecRefBUncor", "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); - histosQA.add("histQvecRefBRectr", "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); - histosQA.add("histQvecRefBTwist", "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); - histosQA.add("histQvecRefBFinal", "", {HistType::kTH3F, {axisQvec, axisQvec, axisCent}}); + if (cfgQAOccupancyStudy) { + histosQA.add(Form("histQvecOccUncorV%d", cfgnMods->at(i)), "", {HistType::kTHnSparseF, {axisQvecF, axisQvecF, axisCent, axisOccupancy}}); + histosQA.add(Form("histQvecRefAOccUncorV%d", cfgnMods->at(i)), "", {HistType::kTHnSparseF, {axisQvecF, axisQvecF, axisCent, axisOccupancy}}); + histosQA.add(Form("histQvecRefBOccUncorV%d", cfgnMods->at(i)), "", {HistType::kTHnSparseF, {axisQvecF, axisQvecF, axisCent, axisOccupancy}}); + } - histosQA.add("histEvtPlUncor", "", {HistType::kTH2F, {axisEvtPl, axisCent}}); - histosQA.add("histEvtPlRectr", "", {HistType::kTH2F, {axisEvtPl, axisCent}}); - histosQA.add("histEvtPlTwist", "", {HistType::kTH2F, {axisEvtPl, axisCent}}); - histosQA.add("histEvtPlFinal", "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + if (cfgQAFinal) { + histosQA.add(Form("histQvecFinalV%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisQvec, axisQvec, axisCent}}); + histosQA.add(Form("histQvecRefAFinalV%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisQvec, axisQvec, axisCent}}); + histosQA.add(Form("histQvecRefBFinalV%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisQvec, axisQvec, axisCent}}); - histosQA.add("histEvtPlRefAUncor", "", {HistType::kTH2F, {axisEvtPl, axisCent}}); - histosQA.add("histEvtPlRefARectr", "", {HistType::kTH2F, {axisEvtPl, axisCent}}); - histosQA.add("histEvtPlRefATwist", "", {HistType::kTH2F, {axisEvtPl, axisCent}}); - histosQA.add("histEvtPlRefAFinal", "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + if (cfgQAOccupancyStudy) { + histosQA.add(Form("histQvecOccFinalV%d", cfgnMods->at(i)), "", {HistType::kTHnSparseF, {axisQvecF, axisQvecF, axisCent, axisOccupancy}}); + histosQA.add(Form("histQvecRefAOccFinalV%d", cfgnMods->at(i)), "", {HistType::kTHnSparseF, {axisQvecF, axisQvecF, axisCent, axisOccupancy}}); + histosQA.add(Form("histQvecRefBOccFinalV%d", cfgnMods->at(i)), "", {HistType::kTHnSparseF, {axisQvecF, axisQvecF, axisCent, axisOccupancy}}); + } - histosQA.add("histEvtPlRefBUncor", "", {HistType::kTH2F, {axisEvtPl, axisCent}}); - histosQA.add("histEvtPlRefBRectr", "", {HistType::kTH2F, {axisEvtPl, axisCent}}); - histosQA.add("histEvtPlRefBTwist", "", {HistType::kTH2F, {axisEvtPl, axisCent}}); - histosQA.add("histEvtPlRefBFinal", "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("histQvecRes_SigRefAV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisQvecF, axisCent}}); + histosQA.add(Form("histQvecRes_SigRefBV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisQvecF, axisCent}}); + histosQA.add(Form("histQvecRes_RefARefBV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisQvecF, axisCent}}); - histosQA.add("histEvtPlRes_SigRefA", "", {HistType::kTH2F, {axisEvtPl, axisCent}}); - histosQA.add("histEvtPlRes_SigRefB", "", {HistType::kTH2F, {axisEvtPl, axisCent}}); - histosQA.add("histEvtPlRes_RefARefB", "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("histEvtPlFinalV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("histEvtPlRefAFinalV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("histEvtPlRefBFinalV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); - } // End void init(InitContext const&) + histosQA.add(Form("histEvtPlRes_SigRefAV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("histEvtPlRes_SigRefBV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("histEvtPlRes_RefARefBV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); - // Definition of all the needed template functions. - template - void fillHistosQvec(const T& vec) - { - if (vec.qvecAmp()[DetId] > 1e-8) { - histosQA.fill(HIST("histQvecUncor"), vec.qvecRe()[DetId * 4], vec.qvecIm()[DetId * 4], vec.cent()); - histosQA.fill(HIST("histQvecRectr"), vec.qvecRe()[DetId * 4 + 1], vec.qvecIm()[DetId * 4 + 1], vec.cent()); - histosQA.fill(HIST("histQvecTwist"), vec.qvecRe()[DetId * 4 + 2], vec.qvecIm()[DetId * 4 + 2], vec.cent()); - histosQA.fill(HIST("histQvecFinal"), vec.qvecRe()[DetId * 4 + 3], vec.qvecIm()[DetId * 4 + 3], vec.cent()); - - histosQA.fill(HIST("histEvtPlUncor"), helperEP.GetEventPlane(vec.qvecRe()[DetId * 4], vec.qvecIm()[DetId * 4], cfgnMod), vec.cent()); - histosQA.fill(HIST("histEvtPlRectr"), helperEP.GetEventPlane(vec.qvecRe()[DetId * 4 + 1], vec.qvecIm()[DetId * 4 + 1], cfgnMod), vec.cent()); - histosQA.fill(HIST("histEvtPlTwist"), helperEP.GetEventPlane(vec.qvecRe()[DetId * 4 + 2], vec.qvecIm()[DetId * 4 + 2], cfgnMod), vec.cent()); - histosQA.fill(HIST("histEvtPlFinal"), helperEP.GetEventPlane(vec.qvecRe()[DetId * 4 + 3], vec.qvecIm()[DetId * 4 + 3], cfgnMod), vec.cent()); - } + histosQA.add(Form("hist_EP_cos_Det_v%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisCos}}); + histosQA.add(Form("hist_EP_sin_Det_v%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisCos}}); + histosQA.add(Form("hist_EP_azimuth_Det_v%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisAzimuth}}); - if (vec.qvecAmp()[RefAId] > 1e-8) { - histosQA.fill(HIST("histQvecRefAUncor"), vec.qvecRe()[RefAId * 4], vec.qvecIm()[RefAId * 4], vec.cent()); - histosQA.fill(HIST("histQvecRefARectr"), vec.qvecRe()[RefAId * 4 + 1], vec.qvecIm()[RefAId * 4 + 1], vec.cent()); - histosQA.fill(HIST("histQvecRefATwist"), vec.qvecRe()[RefAId * 4 + 2], vec.qvecIm()[RefAId * 4 + 2], vec.cent()); - histosQA.fill(HIST("histQvecRefAFinal"), vec.qvecRe()[RefAId * 4 + 3], vec.qvecIm()[RefAId * 4 + 3], vec.cent()); + histosQA.add(Form("hist_EP_cos_RefA_v%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisCos}}); + histosQA.add(Form("hist_EP_sin_RefA_v%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisCos}}); + histosQA.add(Form("hist_EP_azimuth_RefA_v%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisAzimuth}}); - histosQA.fill(HIST("histEvtPlRefAUncor"), helperEP.GetEventPlane(vec.qvecRe()[RefAId * 4], vec.qvecIm()[RefAId * 4], cfgnMod), vec.cent()); - histosQA.fill(HIST("histEvtPlRefARectr"), helperEP.GetEventPlane(vec.qvecRe()[RefAId * 4 + 1], vec.qvecIm()[RefAId * 4 + 1], cfgnMod), vec.cent()); - histosQA.fill(HIST("histEvtPlRefATwist"), helperEP.GetEventPlane(vec.qvecRe()[RefAId * 4 + 2], vec.qvecIm()[RefAId * 4 + 2], cfgnMod), vec.cent()); - histosQA.fill(HIST("histEvtPlRefAFinal"), helperEP.GetEventPlane(vec.qvecRe()[RefAId * 4 + 3], vec.qvecIm()[RefAId * 4 + 3], cfgnMod), vec.cent()); - } + histosQA.add(Form("hist_EP_cos_RefB_v%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisCos}}); + histosQA.add(Form("hist_EP_sin_RefB_v%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisCos}}); + histosQA.add(Form("hist_EP_azimuth_RefB_v%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisAzimuth}}); - if (vec.qvecAmp()[RefBId] > 1e-8) { - histosQA.fill(HIST("histQvecRefBUncor"), vec.qvecRe()[RefBId * 4], vec.qvecIm()[RefBId * 4], vec.cent()); - histosQA.fill(HIST("histQvecRefBRectr"), vec.qvecRe()[RefBId * 4 + 1], vec.qvecIm()[RefBId * 4 + 1], vec.cent()); - histosQA.fill(HIST("histQvecRefBTwist"), vec.qvecRe()[RefBId * 4 + 2], vec.qvecIm()[RefBId * 4 + 2], vec.cent()); - histosQA.fill(HIST("histQvecRefBFinal"), vec.qvecRe()[RefBId * 4 + 3], vec.qvecIm()[RefBId * 4 + 3], vec.cent()); + if (cfgQAAll) { + histosQA.add(Form("histQvecRectrV%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); + histosQA.add(Form("histQvecTwistV%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); - histosQA.fill(HIST("histEvtPlRefBUncor"), helperEP.GetEventPlane(vec.qvecRe()[RefBId * 4], vec.qvecIm()[RefBId * 4], cfgnMod), vec.cent()); - histosQA.fill(HIST("histEvtPlRefBRectr"), helperEP.GetEventPlane(vec.qvecRe()[RefBId * 4 + 1], vec.qvecIm()[RefBId * 4 + 1], cfgnMod), vec.cent()); - histosQA.fill(HIST("histEvtPlRefBTwist"), helperEP.GetEventPlane(vec.qvecRe()[RefBId * 4 + 2], vec.qvecIm()[RefBId * 4 + 2], cfgnMod), vec.cent()); - histosQA.fill(HIST("histEvtPlRefBFinal"), helperEP.GetEventPlane(vec.qvecRe()[RefBId * 4 + 3], vec.qvecIm()[RefBId * 4 + 3], cfgnMod), vec.cent()); + histosQA.add(Form("histQvecRefARectrV%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); + histosQA.add(Form("histQvecRefATwistV%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); + + histosQA.add(Form("histQvecRefBRectrV%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); + histosQA.add(Form("histQvecRefBTwistV%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); + + histosQA.add(Form("histEvtPlRectrV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("histEvtPlTwistV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + + histosQA.add(Form("histEvtPlRefARectrV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("histEvtPlRefATwistV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + + histosQA.add(Form("histEvtPlRefBRectrV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("histEvtPlRefBTwistV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + } + } } + } // End void init(InitContext const&) - if (vec.qvecAmp()[DetId] > 1e-8 && vec.qvecAmp()[RefAId] > 1e-8 && vec.qvecAmp()[RefBId] > 1e-8) { - histosQA.fill(HIST("histEvtPlRes_SigRefA"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecRe()[DetId * 4 + 3], vec.qvecIm()[DetId * 4 + 3], cfgnMod), helperEP.GetEventPlane(vec.qvecRe()[RefAId * 4 + 3], vec.qvecIm()[RefAId * 4 + 3], cfgnMod), cfgnMod), vec.cent()); - histosQA.fill(HIST("histEvtPlRes_SigRefB"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecRe()[DetId * 4 + 3], vec.qvecIm()[DetId * 4 + 3], cfgnMod), helperEP.GetEventPlane(vec.qvecRe()[RefBId * 4 + 3], vec.qvecIm()[RefBId * 4 + 3], cfgnMod), cfgnMod), vec.cent()); - histosQA.fill(HIST("histEvtPlRes_RefARefB"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecRe()[RefAId * 4 + 3], vec.qvecIm()[RefAId * 4 + 3], cfgnMod), helperEP.GetEventPlane(vec.qvecRe()[RefBId * 4 + 3], vec.qvecIm()[RefBId * 4 + 3], cfgnMod), cfgnMod), vec.cent()); + template + void fillHistosFlow(const CollType& coll, const TrackType& track, int nmode) + { + if (coll.qvecAmp()[DetId] < 1e-8 || coll.qvecAmp()[RefAId] < 1e-8 || coll.qvecAmp()[RefBId] < 1e-8) { + return; + } + int DetInd = DetId * 4 + cfgnTotalSystem * 4 * (nmode - 2); + int RefAInd = RefAId * 4 + cfgnTotalSystem * 4 * (nmode - 2); + int RefBInd = RefBId * 4 + cfgnTotalSystem * 4 * (nmode - 2); + + for (auto& trk : track) { + if (!SelTrack(trk)) { + continue; + } + + if (std::abs(trk.eta()) > 0.8) { + continue; + } + + if (nmode == 2) { + histosQA.fill(HIST("hist_EP_cos_Det_v2"), coll.cent(), trk.pt(), std::cos(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[DetInd + 3], coll.qvecIm()[DetInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_sin_Det_v2"), coll.cent(), trk.pt(), std::sin(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[DetInd + 3], coll.qvecIm()[DetInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_Det_v2"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[DetInd + 3], coll.qvecIm()[DetInd + 3], nmode)))); + + histosQA.fill(HIST("hist_EP_cos_RefA_v2"), coll.cent(), trk.pt(), std::cos(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefAInd + 3], coll.qvecIm()[RefAInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_sin_RefA_v2"), coll.cent(), trk.pt(), std::sin(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefAInd + 3], coll.qvecIm()[RefAInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_RefA_v2"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefAInd + 3], coll.qvecIm()[RefAInd + 3], nmode)))); + + histosQA.fill(HIST("hist_EP_cos_RefB_v2"), coll.cent(), trk.pt(), std::cos(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefBInd + 3], coll.qvecIm()[RefBInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_sin_RefB_v2"), coll.cent(), trk.pt(), std::sin(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefBInd + 3], coll.qvecIm()[RefBInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_RefB_v2"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefBInd + 3], coll.qvecIm()[RefBInd + 3], nmode)))); + } else if (nmode == 3) { + histosQA.fill(HIST("hist_EP_cos_Det_v3"), coll.cent(), trk.pt(), std::cos(3.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[DetInd + 3], coll.qvecIm()[DetInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_sin_Det_v3"), coll.cent(), trk.pt(), std::sin(3.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[DetInd + 3], coll.qvecIm()[DetInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_Det_v3"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(3.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[DetInd + 3], coll.qvecIm()[DetInd + 3], nmode)))); + + histosQA.fill(HIST("hist_EP_cos_RefA_v3"), coll.cent(), trk.pt(), std::cos(3.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefAInd + 3], coll.qvecIm()[RefAInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_sin_RefA_v3"), coll.cent(), trk.pt(), std::sin(3.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefAInd + 3], coll.qvecIm()[RefAInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_RefA_v3"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(3.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefAInd + 3], coll.qvecIm()[RefAInd + 3], nmode)))); + + histosQA.fill(HIST("hist_EP_cos_RefB_v3"), coll.cent(), trk.pt(), std::cos(3.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefBInd + 3], coll.qvecIm()[RefBInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_sin_RefB_v3"), coll.cent(), trk.pt(), std::sin(3.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefBInd + 3], coll.qvecIm()[RefBInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_RefB_v3"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(3.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefBInd + 3], coll.qvecIm()[RefBInd + 3], nmode)))); + } else if (nmode == 4) { + histosQA.fill(HIST("hist_EP_cos_Det_v4"), coll.cent(), trk.pt(), std::cos(4.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[DetInd + 3], coll.qvecIm()[DetInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_sin_Det_v4"), coll.cent(), trk.pt(), std::sin(4.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[DetInd + 3], coll.qvecIm()[DetInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_Det_v4"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(4.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[DetInd + 3], coll.qvecIm()[DetInd + 3], nmode)))); + + histosQA.fill(HIST("hist_EP_cos_RefA_v4"), coll.cent(), trk.pt(), std::cos(4.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefAInd + 3], coll.qvecIm()[RefAInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_sin_RefA_v4"), coll.cent(), trk.pt(), std::sin(4.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefAInd + 3], coll.qvecIm()[RefAInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_RefA_v4"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(4.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefAInd + 3], coll.qvecIm()[RefAInd + 3], nmode)))); + + histosQA.fill(HIST("hist_EP_cos_RefB_v4"), coll.cent(), trk.pt(), std::cos(4.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefBInd + 3], coll.qvecIm()[RefBInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_sin_RefB_v4"), coll.cent(), trk.pt(), std::sin(4.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefBInd + 3], coll.qvecIm()[RefBInd + 3], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_RefB_v4"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(4.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[RefBInd + 3], coll.qvecIm()[RefBInd + 3], nmode)))); + } } } - void process(aod::Qvector const& qVec) + // Definition of all the needed template functions. + template + void fillHistosQvec(const T& vec, int nmode) + { + int DetInd = DetId * 4 + cfgnTotalSystem * 4 * (nmode - 2); + int RefAInd = RefAId * 4 + cfgnTotalSystem * 4 * (nmode - 2); + int RefBInd = RefBId * 4 + cfgnTotalSystem * 4 * (nmode - 2); + if (nmode == 2) { + if (vec.qvecAmp()[DetId] > 1e-8) { + histosQA.fill(HIST("histQvecUncorV2"), vec.qvecRe()[DetInd], vec.qvecIm()[DetInd], vec.cent()); + histosQA.fill(HIST("histEvtPlUncorV2"), helperEP.GetEventPlane(vec.qvecRe()[DetInd], vec.qvecIm()[DetInd], nmode), vec.cent()); + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecOccUncorV2"), vec.qvecRe()[DetInd], vec.qvecIm()[DetInd], vec.cent(), vec.trackOccupancyInTimeRange()); + } + if (cfgQAFinal) { + histosQA.fill(HIST("histQvecFinalV2"), vec.qvecRe()[DetInd + 3], vec.qvecIm()[DetInd + 3], vec.cent()); + histosQA.fill(HIST("histEvtPlFinalV2"), helperEP.GetEventPlane(vec.qvecRe()[DetInd + 3], vec.qvecIm()[DetInd + 3], nmode), vec.cent()); + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecOccFinalV2"), vec.qvecRe()[DetInd + 3], vec.qvecIm()[DetInd + 3], vec.cent(), vec.trackOccupancyInTimeRange()); + } + if (cfgQAAll) { + histosQA.fill(HIST("histQvecRectrV2"), vec.qvecRe()[DetInd + 1], vec.qvecIm()[DetInd + 1], vec.cent()); + histosQA.fill(HIST("histQvecTwistV2"), vec.qvecRe()[DetInd + 2], vec.qvecIm()[DetInd + 2], vec.cent()); + + histosQA.fill(HIST("histEvtPlRectrV2"), helperEP.GetEventPlane(vec.qvecRe()[DetInd + 1], vec.qvecIm()[DetInd + 1], nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlTwistV2"), helperEP.GetEventPlane(vec.qvecRe()[DetInd + 2], vec.qvecIm()[DetInd + 2], nmode), vec.cent()); + } + } + } + if (vec.qvecAmp()[RefAId] > 1e-8) { + histosQA.fill(HIST("histQvecRefAUncorV2"), vec.qvecRe()[RefAInd], vec.qvecIm()[RefAInd], vec.cent()); + histosQA.fill(HIST("histEvtPlRefAUncorV2"), helperEP.GetEventPlane(vec.qvecRe()[RefAInd], vec.qvecIm()[RefAInd], nmode), vec.cent()); + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecRefAOccUncorV2"), vec.qvecRe()[RefAInd], vec.qvecIm()[RefAInd], vec.cent(), vec.trackOccupancyInTimeRange()); + } + if (cfgQAFinal) { + histosQA.fill(HIST("histQvecRefAFinalV2"), vec.qvecRe()[RefAInd + 3], vec.qvecIm()[RefAInd + 3], vec.cent()); + histosQA.fill(HIST("histEvtPlRefAFinalV2"), helperEP.GetEventPlane(vec.qvecRe()[RefAInd + 3], vec.qvecIm()[RefAInd + 3], nmode), vec.cent()); + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecRefAOccFinalV2"), vec.qvecRe()[RefAInd + 3], vec.qvecIm()[RefAInd + 3], vec.cent(), vec.trackOccupancyInTimeRange()); + } + if (cfgQAAll) { + histosQA.fill(HIST("histQvecRefARectrV2"), vec.qvecRe()[RefAInd + 1], vec.qvecIm()[RefAInd + 1], vec.cent()); + histosQA.fill(HIST("histQvecRefATwistV2"), vec.qvecRe()[RefAInd + 2], vec.qvecIm()[RefAInd + 2], vec.cent()); + + histosQA.fill(HIST("histEvtPlRefARectrV2"), helperEP.GetEventPlane(vec.qvecRe()[RefAInd + 1], vec.qvecIm()[RefAInd + 1], nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRefATwistV2"), helperEP.GetEventPlane(vec.qvecRe()[RefAInd + 2], vec.qvecIm()[RefAInd + 2], nmode), vec.cent()); + } + } + } + if (vec.qvecAmp()[RefBId] > 1e-8) { + histosQA.fill(HIST("histQvecRefBUncorV2"), vec.qvecRe()[RefBInd], vec.qvecIm()[RefBInd], vec.cent()); + histosQA.fill(HIST("histEvtPlRefBUncorV2"), helperEP.GetEventPlane(vec.qvecRe()[RefBInd], vec.qvecIm()[RefBInd], nmode), vec.cent()); + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecRefBOccUncorV2"), vec.qvecRe()[RefBInd], vec.qvecIm()[RefBInd], vec.cent(), vec.trackOccupancyInTimeRange()); + } + if (cfgQAFinal) { + histosQA.fill(HIST("histQvecRefBFinalV2"), vec.qvecRe()[RefBInd + 3], vec.qvecIm()[RefBInd + 3], vec.cent()); + histosQA.fill(HIST("histEvtPlRefBFinalV2"), helperEP.GetEventPlane(vec.qvecRe()[RefBInd + 3], vec.qvecIm()[RefBInd + 3], nmode), vec.cent()); + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecRefBOccFinalV2"), vec.qvecRe()[RefBInd + 3], vec.qvecIm()[RefBInd + 3], vec.cent(), vec.trackOccupancyInTimeRange()); + } + if (cfgQAAll) { + histosQA.fill(HIST("histQvecRefBRectrV2"), vec.qvecRe()[RefBInd + 1], vec.qvecIm()[RefBInd + 1], vec.cent()); + histosQA.fill(HIST("histQvecRefBTwistV2"), vec.qvecRe()[RefBInd + 2], vec.qvecIm()[RefBInd + 2], vec.cent()); + + histosQA.fill(HIST("histEvtPlRefBRectrV2"), helperEP.GetEventPlane(vec.qvecRe()[RefBInd + 1], vec.qvecIm()[RefBInd + 1], nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRefBTwistV2"), helperEP.GetEventPlane(vec.qvecRe()[RefBInd + 2], vec.qvecIm()[RefBInd + 2], nmode), vec.cent()); + } + } + } + if (vec.qvecAmp()[DetId] > 1e-8 && vec.qvecAmp()[RefAId] > 1e-8 && vec.qvecAmp()[RefBId] > 1e-8 && cfgQAFinal) { + histosQA.fill(HIST("histQvecRes_SigRefAV2"), vec.qvecRe()[DetInd + 3] * vec.qvecRe()[RefAInd + 3] + vec.qvecIm()[DetInd + 3] * vec.qvecIm()[RefAInd + 3], vec.cent()); + histosQA.fill(HIST("histQvecRes_SigRefBV2"), vec.qvecRe()[DetInd + 3] * vec.qvecRe()[RefBInd + 3] + vec.qvecIm()[DetInd + 3] * vec.qvecIm()[RefBInd + 3], vec.cent()); + histosQA.fill(HIST("histQvecRes_RefARefBV2"), vec.qvecRe()[RefAInd + 3] * vec.qvecRe()[RefBInd + 3] + vec.qvecIm()[RefAInd + 3] * vec.qvecIm()[RefBInd + 3], vec.cent()); + + histosQA.fill(HIST("histEvtPlRes_SigRefAV2"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecRe()[DetInd + 3], vec.qvecIm()[DetInd + 3], nmode), helperEP.GetEventPlane(vec.qvecRe()[RefAInd + 3], vec.qvecIm()[RefAInd + 3], nmode), nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRes_SigRefBV2"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecRe()[DetInd + 3], vec.qvecIm()[DetInd + 3], nmode), helperEP.GetEventPlane(vec.qvecRe()[RefBInd + 3], vec.qvecIm()[RefBInd + 3], nmode), nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRes_RefARefBV2"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecRe()[RefAInd + 3], vec.qvecIm()[RefAInd + 3], nmode), helperEP.GetEventPlane(vec.qvecRe()[RefBInd + 3], vec.qvecIm()[RefBInd + 3], nmode), nmode), vec.cent()); + } + } else if (nmode == 3) { + if (vec.qvecAmp()[DetId] > 1e-8) { + histosQA.fill(HIST("histQvecUncorV3"), vec.qvecRe()[DetInd], vec.qvecIm()[DetInd], vec.cent()); + histosQA.fill(HIST("histEvtPlUncorV3"), helperEP.GetEventPlane(vec.qvecRe()[DetInd], vec.qvecIm()[DetInd], nmode), vec.cent()); + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecOccUncorV3"), vec.qvecRe()[DetInd], vec.qvecIm()[DetInd], vec.cent(), vec.trackOccupancyInTimeRange()); + } + if (cfgQAFinal) { + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecOccFinalV3"), vec.qvecRe()[DetInd + 3], vec.qvecIm()[DetInd + 3], vec.cent(), vec.trackOccupancyInTimeRange()); + } + histosQA.fill(HIST("histQvecFinalV3"), vec.qvecRe()[DetInd + 3], vec.qvecIm()[DetInd + 3], vec.cent()); + histosQA.fill(HIST("histEvtPlFinalV3"), helperEP.GetEventPlane(vec.qvecRe()[DetInd + 3], vec.qvecIm()[DetInd + 3], nmode), vec.cent()); + if (cfgQAAll) { + histosQA.fill(HIST("histQvecRectrV3"), vec.qvecRe()[DetInd + 1], vec.qvecIm()[DetInd + 1], vec.cent()); + histosQA.fill(HIST("histQvecTwistV3"), vec.qvecRe()[DetInd + 2], vec.qvecIm()[DetInd + 2], vec.cent()); + + histosQA.fill(HIST("histEvtPlRectrV3"), helperEP.GetEventPlane(vec.qvecRe()[DetInd + 1], vec.qvecIm()[DetInd + 1], nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlTwistV3"), helperEP.GetEventPlane(vec.qvecRe()[DetInd + 2], vec.qvecIm()[DetInd + 2], nmode), vec.cent()); + } + } + } + if (vec.qvecAmp()[RefAId] > 1e-8) { + histosQA.fill(HIST("histQvecRefAUncorV3"), vec.qvecRe()[RefAInd], vec.qvecIm()[RefAInd], vec.cent()); + histosQA.fill(HIST("histEvtPlRefAUncorV3"), helperEP.GetEventPlane(vec.qvecRe()[RefAInd], vec.qvecIm()[RefAInd], nmode), vec.cent()); + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecRefAOccUncorV3"), vec.qvecRe()[RefAInd], vec.qvecIm()[RefAInd], vec.cent(), vec.trackOccupancyInTimeRange()); + } + if (cfgQAFinal) { + histosQA.fill(HIST("histQvecRefAFinalV3"), vec.qvecRe()[RefAInd + 3], vec.qvecIm()[RefAInd + 3], vec.cent()); + histosQA.fill(HIST("histEvtPlRefAFinalV3"), helperEP.GetEventPlane(vec.qvecRe()[RefAInd + 3], vec.qvecIm()[RefAInd + 3], nmode), vec.cent()); + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecRefAOccFinalV3"), vec.qvecRe()[RefAInd + 3], vec.qvecIm()[RefAInd + 3], vec.cent(), vec.trackOccupancyInTimeRange()); + } + if (cfgQAAll) { + histosQA.fill(HIST("histQvecRefARectrV3"), vec.qvecRe()[RefAInd + 1], vec.qvecIm()[RefAInd + 1], vec.cent()); + histosQA.fill(HIST("histQvecRefATwistV3"), vec.qvecRe()[RefAInd + 2], vec.qvecIm()[RefAInd + 2], vec.cent()); + + histosQA.fill(HIST("histEvtPlRefARectrV3"), helperEP.GetEventPlane(vec.qvecRe()[RefAInd + 1], vec.qvecIm()[RefAInd + 1], nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRefATwistV3"), helperEP.GetEventPlane(vec.qvecRe()[RefAInd + 2], vec.qvecIm()[RefAInd + 2], nmode), vec.cent()); + } + } + } + if (vec.qvecAmp()[RefBId] > 1e-8) { + histosQA.fill(HIST("histQvecRefBUncorV3"), vec.qvecRe()[RefBInd], vec.qvecIm()[RefBInd], vec.cent()); + histosQA.fill(HIST("histEvtPlRefBUncorV3"), helperEP.GetEventPlane(vec.qvecRe()[RefBInd], vec.qvecIm()[RefBInd], nmode), vec.cent()); + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecRefBOccUncorV3"), vec.qvecRe()[RefBInd], vec.qvecIm()[RefBInd], vec.cent(), vec.trackOccupancyInTimeRange()); + } + if (cfgQAFinal) { + histosQA.fill(HIST("histQvecRefBFinalV3"), vec.qvecRe()[RefBInd + 3], vec.qvecIm()[RefBInd + 3], vec.cent()); + histosQA.fill(HIST("histEvtPlRefBFinalV3"), helperEP.GetEventPlane(vec.qvecRe()[RefBInd + 3], vec.qvecIm()[RefBInd + 3], nmode), vec.cent()); + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecRefBOccFinalV3"), vec.qvecRe()[RefBInd + 3], vec.qvecIm()[RefBInd + 3], vec.cent(), vec.trackOccupancyInTimeRange()); + } + if (cfgQAAll) { + histosQA.fill(HIST("histQvecRefBRectrV3"), vec.qvecRe()[RefBInd + 1], vec.qvecIm()[RefBInd + 1], vec.cent()); + histosQA.fill(HIST("histQvecRefBTwistV3"), vec.qvecRe()[RefBInd + 2], vec.qvecIm()[RefBInd + 2], vec.cent()); + + histosQA.fill(HIST("histEvtPlRefBRectrV3"), helperEP.GetEventPlane(vec.qvecRe()[RefBInd + 1], vec.qvecIm()[RefBInd + 1], nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRefBTwistV3"), helperEP.GetEventPlane(vec.qvecRe()[RefBInd + 2], vec.qvecIm()[RefBInd + 2], nmode), vec.cent()); + } + } + } + if (vec.qvecAmp()[DetId] > 1e-8 && vec.qvecAmp()[RefAId] > 1e-8 && vec.qvecAmp()[RefBId] > 1e-8 && cfgQAFinal) { + histosQA.fill(HIST("histQvecRes_SigRefAV3"), vec.qvecRe()[DetInd + 3] * vec.qvecRe()[RefAInd + 3] + vec.qvecIm()[DetInd + 3] * vec.qvecIm()[RefAInd + 3], vec.cent()); + histosQA.fill(HIST("histQvecRes_SigRefBV3"), vec.qvecRe()[DetInd + 3] * vec.qvecRe()[RefBInd + 3] + vec.qvecIm()[DetInd + 3] * vec.qvecIm()[RefBInd + 3], vec.cent()); + histosQA.fill(HIST("histQvecRes_RefARefBV3"), vec.qvecRe()[RefAInd + 3] * vec.qvecRe()[RefBInd + 3] + vec.qvecIm()[RefAInd + 3] * vec.qvecIm()[RefBInd + 3], vec.cent()); + + histosQA.fill(HIST("histEvtPlRes_SigRefAV3"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecRe()[DetInd + 3], vec.qvecIm()[DetInd + 3], nmode), helperEP.GetEventPlane(vec.qvecRe()[RefAInd + 3], vec.qvecIm()[RefAInd + 3], nmode), nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRes_SigRefBV3"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecRe()[DetInd + 3], vec.qvecIm()[DetInd + 3], nmode), helperEP.GetEventPlane(vec.qvecRe()[RefBInd + 3], vec.qvecIm()[RefBInd + 3], nmode), nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRes_RefARefBV3"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecRe()[RefAInd + 3], vec.qvecIm()[RefAInd + 3], nmode), helperEP.GetEventPlane(vec.qvecRe()[RefBInd + 3], vec.qvecIm()[RefBInd + 3], nmode), nmode), vec.cent()); + } + } else if (nmode == 4) { + if (vec.qvecAmp()[DetId] > 1e-8) { + histosQA.fill(HIST("histQvecUncorV4"), vec.qvecRe()[DetInd], vec.qvecIm()[DetInd], vec.cent()); + histosQA.fill(HIST("histEvtPlUncorV4"), helperEP.GetEventPlane(vec.qvecRe()[DetInd], vec.qvecIm()[DetInd], nmode), vec.cent()); + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecOccUncorV4"), vec.qvecRe()[DetInd], vec.qvecIm()[DetInd], vec.cent(), vec.trackOccupancyInTimeRange()); + } + if (cfgQAFinal) { + histosQA.fill(HIST("histQvecFinalV4"), vec.qvecRe()[DetInd + 3], vec.qvecIm()[DetInd + 3], vec.cent()); + histosQA.fill(HIST("histEvtPlFinalV4"), helperEP.GetEventPlane(vec.qvecRe()[DetInd + 3], vec.qvecIm()[DetInd + 3], nmode), vec.cent()); + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecOccFinalV4"), vec.qvecRe()[DetInd + 3], vec.qvecIm()[DetInd + 3], vec.cent(), vec.trackOccupancyInTimeRange()); + } + if (cfgQAAll) { + histosQA.fill(HIST("histQvecRectrV4"), vec.qvecRe()[DetInd + 1], vec.qvecIm()[DetInd + 1], vec.cent()); + histosQA.fill(HIST("histQvecTwistV4"), vec.qvecRe()[DetInd + 2], vec.qvecIm()[DetInd + 2], vec.cent()); + + histosQA.fill(HIST("histEvtPlRectrV4"), helperEP.GetEventPlane(vec.qvecRe()[DetInd + 1], vec.qvecIm()[DetInd + 1], nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlTwistV4"), helperEP.GetEventPlane(vec.qvecRe()[DetInd + 2], vec.qvecIm()[DetInd + 2], nmode), vec.cent()); + } + } + } + if (vec.qvecAmp()[RefAId] > 1e-8) { + histosQA.fill(HIST("histQvecRefAUncorV4"), vec.qvecRe()[RefAInd], vec.qvecIm()[RefAInd], vec.cent()); + histosQA.fill(HIST("histEvtPlRefAUncorV4"), helperEP.GetEventPlane(vec.qvecRe()[RefAInd], vec.qvecIm()[RefAInd], nmode), vec.cent()); + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecRefAOccUncorV4"), vec.qvecRe()[RefAInd], vec.qvecIm()[RefAInd], vec.cent(), vec.trackOccupancyInTimeRange()); + } + if (cfgQAFinal) { + histosQA.fill(HIST("histQvecRefAFinalV4"), vec.qvecRe()[RefAInd + 3], vec.qvecIm()[RefAInd + 3], vec.cent()); + histosQA.fill(HIST("histEvtPlRefAFinalV4"), helperEP.GetEventPlane(vec.qvecRe()[RefAInd + 3], vec.qvecIm()[RefAInd + 3], nmode), vec.cent()); + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecRefAOccFinalV4"), vec.qvecRe()[RefAInd + 3], vec.qvecIm()[RefAInd + 3], vec.cent(), vec.trackOccupancyInTimeRange()); + } + if (cfgQAAll) { + histosQA.fill(HIST("histQvecRefARectrV4"), vec.qvecRe()[RefAInd + 1], vec.qvecIm()[RefAInd + 1], vec.cent()); + histosQA.fill(HIST("histQvecRefATwistV4"), vec.qvecRe()[RefAInd + 2], vec.qvecIm()[RefAInd + 2], vec.cent()); + + histosQA.fill(HIST("histEvtPlRefARectrV4"), helperEP.GetEventPlane(vec.qvecRe()[RefAInd + 1], vec.qvecIm()[RefAInd + 1], nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRefATwistV4"), helperEP.GetEventPlane(vec.qvecRe()[RefAInd + 2], vec.qvecIm()[RefAInd + 2], nmode), vec.cent()); + } + } + } + if (vec.qvecAmp()[RefBId] > 1e-8) { + histosQA.fill(HIST("histQvecRefBUncorV4"), vec.qvecRe()[RefBInd], vec.qvecIm()[RefBInd], vec.cent()); + histosQA.fill(HIST("histEvtPlRefBUncorV4"), helperEP.GetEventPlane(vec.qvecRe()[RefBInd], vec.qvecIm()[RefBInd], nmode), vec.cent()); + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecRefBOccUncorV4"), vec.qvecRe()[RefBInd], vec.qvecIm()[RefBInd], vec.cent(), vec.trackOccupancyInTimeRange()); + } + if (cfgQAFinal) { + histosQA.fill(HIST("histQvecRefBFinalV4"), vec.qvecRe()[RefBInd + 3], vec.qvecIm()[RefBInd + 3], vec.cent()); + histosQA.fill(HIST("histEvtPlRefBFinalV4"), helperEP.GetEventPlane(vec.qvecRe()[RefBInd + 3], vec.qvecIm()[RefBInd + 3], nmode), vec.cent()); + if (cfgQAOccupancyStudy) { + histosQA.fill(HIST("histQvecRefBOccFinalV4"), vec.qvecRe()[RefBInd + 3], vec.qvecIm()[RefBInd + 3], vec.cent(), vec.trackOccupancyInTimeRange()); + } + if (cfgQAAll) { + histosQA.fill(HIST("histQvecRefBRectrV4"), vec.qvecRe()[RefBInd + 1], vec.qvecIm()[RefBInd + 1], vec.cent()); + histosQA.fill(HIST("histQvecRefBTwistV4"), vec.qvecRe()[RefBInd + 2], vec.qvecIm()[RefBInd + 2], vec.cent()); + + histosQA.fill(HIST("histEvtPlRefBRectrV4"), helperEP.GetEventPlane(vec.qvecRe()[RefBInd + 1], vec.qvecIm()[RefBInd + 1], nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRefBTwistV4"), helperEP.GetEventPlane(vec.qvecRe()[RefBInd + 2], vec.qvecIm()[RefBInd + 2], nmode), vec.cent()); + } + } + } + if (vec.qvecAmp()[DetId] > 1e-8 && vec.qvecAmp()[RefAId] > 1e-8 && vec.qvecAmp()[RefBId] > 1e-8 && cfgQAFinal) { + histosQA.fill(HIST("histQvecRes_SigRefAV4"), vec.qvecRe()[DetInd + 3] * vec.qvecRe()[RefAInd + 3] + vec.qvecIm()[DetInd + 3] * vec.qvecIm()[RefAInd + 3], vec.cent()); + histosQA.fill(HIST("histQvecRes_SigRefBV4"), vec.qvecRe()[DetInd + 3] * vec.qvecRe()[RefBInd + 3] + vec.qvecIm()[DetInd + 3] * vec.qvecIm()[RefBInd + 3], vec.cent()); + histosQA.fill(HIST("histQvecRes_RefARefBV4"), vec.qvecRe()[RefAInd + 3] * vec.qvecRe()[RefBInd + 3] + vec.qvecIm()[RefAInd + 3] * vec.qvecIm()[RefBInd + 3], vec.cent()); + + histosQA.fill(HIST("histEvtPlRes_SigRefAV4"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecRe()[DetInd + 3], vec.qvecIm()[DetInd + 3], nmode), helperEP.GetEventPlane(vec.qvecRe()[RefAInd + 3], vec.qvecIm()[RefAInd + 3], nmode), nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRes_SigRefBV4"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecRe()[DetInd + 3], vec.qvecIm()[DetInd + 3], nmode), helperEP.GetEventPlane(vec.qvecRe()[RefBInd + 3], vec.qvecIm()[RefBInd + 3], nmode), nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRes_RefARefBV4"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecRe()[RefAInd + 3], vec.qvecIm()[RefAInd + 3], nmode), helperEP.GetEventPlane(vec.qvecRe()[RefBInd + 3], vec.qvecIm()[RefBInd + 3], nmode), nmode), vec.cent()); + } + } + } + void process(MyCollisions::iterator const& qVec, MyTracks const& tracks) { histosQA.fill(HIST("histCentFull"), qVec.cent()); - fillHistosQvec(qVec); + if (cfgAddEvtSel && (!qVec.sel8() || + !qVec.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || + !qVec.selection_bit(aod::evsel::kNoSameBunchPileup))) { + return; + } + if (cfgAddEvtSel && (qVec.trackOccupancyInTimeRange() > cfgMaxOccupancy || qVec.trackOccupancyInTimeRange() < cfgMinOccupancy)) { + return; + } + if (cfgAddEvtSelPileup && !qVec.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return; + } + + for (uint i = 0; i < cfgnMods->size(); i++) { + fillHistosQvec(qVec, cfgnMods->at(i)); + if (cfgQAFinal && cfgQAFlowStudy) { + fillHistosFlow(qVec, tracks, cfgnMods->at(i)); + } + } } // End void process(...) }; diff --git a/Common/Tools/CMakeLists.txt b/Common/Tools/CMakeLists.txt index 768162d940e..29950466a85 100644 --- a/Common/Tools/CMakeLists.txt +++ b/Common/Tools/CMakeLists.txt @@ -10,21 +10,16 @@ # or submit itself to any jurisdiction. add_subdirectory(Multiplicity) +add_subdirectory(PID) -o2physics_add_executable(aod-data-model-graph - SOURCES aodDataModelGraph.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore - ) - -o2physics_add_executable(pidparam-tpc-response - SOURCES handleParamTPCResponse.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore - ) +#o2physics_add_executable(aod-data-model-graph +# SOURCES aodDataModelGraph.cxx +# PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore) o2physics_add_library(trackSelectionRequest - SOURCES trackSelectionRequest.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore) + SOURCES trackSelectionRequest.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore) o2physics_target_root_dictionary(trackSelectionRequest - HEADERS trackSelectionRequest.h - LINKDEF trackSelectionRequestLinkDef.h) \ No newline at end of file + HEADERS trackSelectionRequest.h + LINKDEF trackSelectionRequestLinkDef.h) diff --git a/Common/Tools/Multiplicity/multCalibrator.cxx b/Common/Tools/Multiplicity/multCalibrator.cxx index 51306f91160..e9931c0389f 100644 --- a/Common/Tools/Multiplicity/multCalibrator.cxx +++ b/Common/Tools/Multiplicity/multCalibrator.cxx @@ -40,7 +40,7 @@ multCalibrator::multCalibrator() : TNamed(), fInputFileName("AnalysisResults.root"), fOutputFileName("CCDB-objects.root"), fAnchorPointValue(-1), - fAnchorPointPercentage(90), + fAnchorPointPercentage(100), fCalibHists(0x0), fPrecisionHistogram(0x0) { diff --git a/Common/Tools/Multiplicity/multGlauberNBDFitter.cxx b/Common/Tools/Multiplicity/multGlauberNBDFitter.cxx index 112983de9ea..a765db72448 100644 --- a/Common/Tools/Multiplicity/multGlauberNBDFitter.cxx +++ b/Common/Tools/Multiplicity/multGlauberNBDFitter.cxx @@ -309,6 +309,7 @@ Bool_t multGlauberNBDFitter::DoFit() fk = fGlauberNBD->GetParameter(1); ff = fGlauberNBD->GetParameter(2); fnorm = fGlauberNBD->GetParameter(3); + fdMu = fGlauberNBD->GetParameter(4); return fitptr.Get()->IsValid(); } @@ -369,9 +370,25 @@ Double_t multGlauberNBDFitter::ContinuousNBD(Double_t n, Double_t mu, Double_t k return F; } -void multGlauberNBDFitter::CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCollProf) +void multGlauberNBDFitter::CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCollProf, TH2F* lNPart2DPlot, TH2F* lNColl2DPlot, TH1F* hPercentileMap, Double_t lLoRange, Double_t lHiRange) { cout << "Calculating , in centrality bins..." << endl; + cout << "Range to calculate: " << lLoRange << " to " << lHiRange << endl; + + cout << "Acquiring values from the fit function..." << endl; + + fMu = fGlauberNBD->GetParameter(0); + fk = fGlauberNBD->GetParameter(1); + ff = fGlauberNBD->GetParameter(2); + fnorm = fGlauberNBD->GetParameter(3); + fdMu = fGlauberNBD->GetParameter(4); + + cout << "Please inspect now: " << endl; + cout << "Glauber NBD mu ............: " << fMu << endl; + cout << "Glauber NBD k .............: " << fk << endl; + cout << "Glauber NBD f .............: " << ff << endl; + cout << "Glauber NBD norm ..........: " << fnorm << endl; + cout << "Glauber NBD dmu/dNanc .....: " << fdMu << endl; //2-fold nested loop: // + looping over all Nancestor combinations @@ -379,8 +396,10 @@ void multGlauberNBDFitter::CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCol // ^---> final product already multiplicity-binned //______________________________________________________ - Double_t lLoRange, lHiRange; - fGlauberNBD->GetRange(lLoRange, lHiRange); + if (lLoRange < -1 && lHiRange < -1) { + fGlauberNBD->GetRange(lLoRange, lHiRange); + } + // bypass to zero for (int ibin = 0; ibin < fNNpNcPairs; ibin++) { if (ibin % 2000 == 0) cout << "At NpNc pair #" << ibin << " of " << fNNpNcPairs << "..." << endl; @@ -403,8 +422,15 @@ void multGlauberNBDFitter::CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCol if (lMultValue > 1e-6) lMult = fAncestorMode != 2 ? fNBD->Eval(lMultValue) : ContinuousNBD(lMultValue, lThisMu, lThisk); Double_t lProbability = lNancestorCount * lMult; - lNPartProf->Fill(lMultValue, fNpart[ibin], lProbability); - lNCollProf->Fill(lMultValue, fNcoll[ibin], lProbability); + Double_t lMultValueToFill = lMultValue; + if (hPercentileMap) + lMultValueToFill = hPercentileMap->GetBinContent(hPercentileMap->FindBin(lMultValue)); + lNPartProf->Fill(lMultValueToFill, fNpart[ibin], lProbability); + lNCollProf->Fill(lMultValueToFill, fNcoll[ibin], lProbability); + if (lNPart2DPlot) + lNPart2DPlot->Fill(lMultValueToFill, fNpart[ibin], lProbability); + if (lNColl2DPlot) + lNColl2DPlot->Fill(lMultValueToFill, fNcoll[ibin], lProbability); } } } diff --git a/Common/Tools/Multiplicity/multGlauberNBDFitter.h b/Common/Tools/Multiplicity/multGlauberNBDFitter.h index ed93c49fc6b..42d5cab046f 100644 --- a/Common/Tools/Multiplicity/multGlauberNBDFitter.h +++ b/Common/Tools/Multiplicity/multGlauberNBDFitter.h @@ -75,7 +75,7 @@ class multGlauberNBDFitter : public TNamed Double_t ContinuousNBD(Double_t n, Double_t mu, Double_t k); //For estimating Npart, Ncoll in multiplicity bins - void CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCollProf); + void CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCollProf, TH2F* lNPart2DPlot, TH2F* lNColl2DPlot, TH1F* hPercentileMap, Double_t lLoRange = -1, Double_t lHiRange = -1); //void Print(Option_t *option="") const; diff --git a/Common/Tools/PID/CMakeLists.txt b/Common/Tools/PID/CMakeLists.txt new file mode 100644 index 00000000000..3d9bd387cfe --- /dev/null +++ b/Common/Tools/PID/CMakeLists.txt @@ -0,0 +1,18 @@ +# 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_executable(pidparam-tpc-response + SOURCES handleParamTPCResponse.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore) + +o2physics_add_executable(check-pid-packing + SOURCES checkPidPacking.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore) diff --git a/Common/Tools/PID/checkPidPacking.cxx b/Common/Tools/PID/checkPidPacking.cxx new file mode 100644 index 00000000000..c503ee1b288 --- /dev/null +++ b/Common/Tools/PID/checkPidPacking.cxx @@ -0,0 +1,100 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file checkPidPacking.cxx +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief exec to check the packing and depacking of PID signals (nsigmas) +/// \since 03/05/2024 +/// + +#include "Common/DataModel/PIDResponse.h" +#include "TH1F.h" +#include "TCanvas.h" +#include "TRandom.h" + +using namespace o2; + +template +bool process(std::string outputName, int nevents = 100000) +{ + class NsigmaContainer + { + public: + NsigmaContainer() {} + void operator()(const int8_t& packed) { mPacked = packed; } + int8_t mPacked = 0; + float unpack() { return aod::pidutils::unPackInTable(mPacked); } + } container; + + TH1F* hgaus = new TH1F("hgaus", "", 20 / T::bin_width, + -10 + T::bin_width * 0.5, + 10 + T::bin_width * 0.5); + LOG(info) << "Bin width = " << T::bin_width << " vs histo " << hgaus->GetXaxis()->GetBinWidth(1); + hgaus->SetLineColor(2); + hgaus->SetLineStyle(1); + TH1F* hgausPacked = static_cast(hgaus->Clone("hgausPacked")); + hgausPacked->SetLineColor(4); + hgausPacked->SetLineStyle(2); + + TH1F* huniform = static_cast(hgaus->Clone("huniform")); + huniform->SetLineColor(2); + huniform->SetLineStyle(1); + TH1F* huniformPacked = static_cast(hgaus->Clone("huniformPacked")); + huniformPacked->SetLineColor(4); + huniformPacked->SetLineStyle(2); + + for (int i = 0; i < nevents; i++) { + float nsigma = gRandom->Gaus(0, 1); + hgaus->Fill(nsigma); + aod::pidutils::packInTable(nsigma, container); + hgausPacked->Fill(container.unpack()); + + nsigma = gRandom->Uniform(-10, 10); + huniform->Fill(nsigma); + aod::pidutils::packInTable(nsigma, container); + huniformPacked->Fill(container.unpack()); + } + + TCanvas* can = new TCanvas("can"); + hgaus->Draw(); + hgausPacked->Draw("same"); + outputName = "/tmp/" + outputName + ".pdf"; + can->SaveAs(Form("%s[", outputName.c_str())); + can->SaveAs(outputName.c_str()); + + huniform->Draw(); + huniformPacked->Draw("same"); + can->SaveAs(outputName.c_str()); + can->SaveAs(Form("%s]", outputName.c_str())); + const bool gausOk = (hgaus->GetBinContent(hgaus->FindBin(0)) == hgausPacked->GetBinContent(hgausPacked->FindBin(0))); + const bool uniformOk = (huniform->GetBinContent(huniform->FindBin(0)) == huniformPacked->GetBinContent(huniformPacked->FindBin(0))); + return gausOk && uniformOk; +} + +int main(int /*argc*/, char* /*argv*/[]) +{ + + LOG(info) << "Checking the packing and unpacking of PID signals (nsigmas) in the TPC PID response."; + if (process("TPC", 100000)) { + LOG(info) << "Packing and unpacking of PID signals (nsigmas) in the TPC PID response is correct."; + } else { + LOG(fatal) << "Packing and unpacking of PID signals (nsigmas) in the TPC PID response is incorrect."; + } + + LOG(info) << "Checking the packing and unpacking of PID signals (nsigmas) in the TOF PID response."; + if (process("TOF", 100000)) { + LOG(info) << "Packing and unpacking of PID signals (nsigmas) in the TOF PID response is correct."; + } else { + LOG(fatal) << "Packing and unpacking of PID signals (nsigmas) in the TOF PID response is incorrect."; + } + +} // main diff --git a/Common/Tools/handleParamBase.h b/Common/Tools/PID/handleParamBase.h similarity index 83% rename from Common/Tools/handleParamBase.h rename to Common/Tools/PID/handleParamBase.h index cb28fc0d128..01c2a66ab8b 100644 --- a/Common/Tools/handleParamBase.h +++ b/Common/Tools/PID/handleParamBase.h @@ -16,8 +16,8 @@ /// \brief Header file with utilities for handling PID parametrization on CCDB /// -#ifndef COMMON_TOOLS_HANDLEPARAMBASE_H_ -#define COMMON_TOOLS_HANDLEPARAMBASE_H_ +#ifndef COMMON_TOOLS_PID_HANDLEPARAMBASE_H_ +#define COMMON_TOOLS_PID_HANDLEPARAMBASE_H_ #include #include @@ -145,26 +145,41 @@ void setupTimestamps(int64_t& timestamp, const std::string run_path = Form("%s/%i", rct_path.data(), runnumber); headers = api.retrieveHeaders(run_path, metadata, -1); - if (headers.count("SOR") == 0) { - LOGF(fatal, "Cannot find run-number SOR in path '%s'.", run_path.data()); + + if (headers.count("STF") == 0) { + LOGF(warning, "Cannot find STF for run %d in path '%s'. Using SOR as fallback", runnumber, run_path.data()); + if (headers.count("SOR") == 0) { + LOGF(fatal, "Cannot find SOR in path '%s'.", run_path.data()); + } + sor = atol(headers["SOR"].c_str()); + } else { + sor = atol(headers["STF"].c_str()); } - sor = atol(headers["SOR"].c_str()); - if (headers.count("EOR") == 0) { - LOGF(fatal, "Cannot find run-number EOR in path '%s'.", run_path.data()); + + if (headers.count("ETF") == 0) { + LOGF(warning, "Cannot find ETF for run %d in path '%s'. Using EOR as fallback", runnumber, run_path.data()); + if (headers.count("EOR") == 0) { + LOGF(fatal, "Cannot find EOR in path '%s'.", run_path.data()); + } + eor = atol(headers["EOR"].c_str()); + } else { + eor = atol(headers["ETF"].c_str()); } - eor = atol(headers["EOR"].c_str()); - LOG(info) << "Getting timestamp for run " << runnumber << " from CCDB in path " << run_path << " -> SOR " << sor << " (" << timeStampToHReadble(sor) << ")" - << ", EOR " << eor << " (" << timeStampToHReadble(eor) << ")"; + + LOG(info) << "Getting timestamp for run " << runnumber << " from CCDB in path " << run_path << " -> STF " << sor << " (" << timeStampToHReadble(sor) << ")" + << ", ETF " << eor << " (" << timeStampToHReadble(eor) << ")"; }; if (minRunNumber != 0) { int64_t SOR = 0, EOR = 0; getSOREOR(minRunNumber, SOR, EOR); timestamp = SOR; // timestamp of the SOR in ms - LOG(info) << "Setting timestamp of object from run number " << minRunNumber << ": " << validityStart << " -> " << timeStampToHReadble(validityStart); + LOG(info) << "Setting timestamp of object from run number " << minRunNumber << ": " << timestamp << " -> " << timeStampToHReadble(timestamp); if (validityStart == 0) { // Start of validity from first run number validityStart = SOR; LOG(info) << "Setting validityStart of object from run number " << minRunNumber << ": " << validityStart << " -> " << timeStampToHReadble(validityStart); + validityStart -= 120000; // add 2 minute margin before start of validity from RCT + LOG(info) << "Adding 2-minute margin to validityStart: " << validityStart << " -> " << timeStampToHReadble(validityStart); } if (validityStop == 0) { if (minRunNumber != maxRunNumber) { @@ -175,11 +190,13 @@ void setupTimestamps(int64_t& timestamp, validityStop = EOR; LOG(info) << "Setting validityStop of object from run number " << minRunNumber << ": " << validityStop << " -> " << timeStampToHReadble(validityStop); } + validityStop += 120000; // add 2 minute margin after end of validity from RCT + LOG(info) << "Adding 2-minute margin to validityStop: " << validityStop << " -> " << timeStampToHReadble(validityStop); } } - if (validityStop == 0) { //Default value for validityStop + if (validityStop == 0) { // Default value for validityStop validityStop = 4108971600000; } } -#endif // COMMON_TOOLS_HANDLEPARAMBASE_H_ +#endif // COMMON_TOOLS_PID_HANDLEPARAMBASE_H_ diff --git a/Common/Tools/handleParamTPCResponse.cxx b/Common/Tools/PID/handleParamTPCResponse.cxx similarity index 100% rename from Common/Tools/handleParamTPCResponse.cxx rename to Common/Tools/PID/handleParamTPCResponse.cxx diff --git a/Common/Tools/TrackTuner.h b/Common/Tools/TrackTuner.h index d3e5861962e..26937eb9131 100644 --- a/Common/Tools/TrackTuner.h +++ b/Common/Tools/TrackTuner.h @@ -23,6 +23,9 @@ #include #include #include +#include +#include +#include #include "CCDB/BasicCCDBManager.h" #include "CCDB/CcdbApi.h" @@ -36,60 +39,117 @@ #include "DetectorsBase/GeometryManager.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" #include "Framework/RunningWorkflowInfo.h" #include "ReconstructionDataFormats/DCA.h" #include "ReconstructionDataFormats/Track.h" - #include -struct TrackTuner { - +namespace o2::aod +{ +namespace track_tuner +{ +DECLARE_SOA_COLUMN(TunedQOverPt, tunedQOverPt, float); + +/// configuration source +enum configSource : int { InputString = 1, + Configurables }; +} // namespace track_tuner + +DECLARE_SOA_TABLE(TrackTunerTable, "AOD", "TRACKTUNERTABLE", //! + track_tuner::TunedQOverPt); +} // namespace o2::aod + +struct TrackTuner : o2::framework::ConfigurableGroup { + + std::string prefix = "trackTuner"; // JSON group name + o2::framework::Configurable cfgDebugInfo{"debugInfo", false, "Flag to switch on the debug printout"}; + o2::framework::Configurable cfgUpdateTrackDCAs{"updateTrackDCAs", false, "Flag to enable the DCA smearing"}; + o2::framework::Configurable cfgUpdateTrackCovMat{"updateTrackCovMat", false, "Flag to enable the DCA covariance-matrix smearing"}; + o2::framework::Configurable cfgUpdateCurvature{"updateCurvature", false, "Flag to enable the Q/Pt smearing after the propagation to the production point"}; + o2::framework::Configurable cfgUpdateCurvatureIU{"updateCurvatureIU", false, "Flag to enable the Q/Pt smearing before the propagation to the production point"}; + o2::framework::Configurable cfgUpdatePulls{"updatePulls", false, "Flag to enable the pulls smearing"}; + o2::framework::Configurable cfgIsInputFileFromCCDB{"isInputFileFromCCDB", false, "True: files from CCDB; False: fils from local path (debug)"}; + o2::framework::Configurable cfgPathInputFile{"pathInputFile", "", "Path to file containing DCAxy, DCAz graphs from data and MC"}; + o2::framework::Configurable cfgNameInputFile{"nameInputFile", "", "Name of the file containing DCAxy, DCAz graphs from data and MC"}; + o2::framework::Configurable cfgPathFileQoverPt{"pathFileQoverPt", "", "Path to file containing Q/Pt correction graphs from data and MC"}; + o2::framework::Configurable cfgNameFileQoverPt{"nameFileQoverPt", "", "Name of file containing Q/Pt correction graphs from data and MC"}; + o2::framework::Configurable cfgUsePvRefitCorrections{"usePvRefitCorrections", false, "Flag to establish whether to use corrections obtained with or w/o PV refit"}; + o2::framework::Configurable cfgQOverPtMC{"qOverPtMC", -1., "Scaling factor on q/pt of MC"}; + o2::framework::Configurable cfgQOverPtData{"qOverPtData", -1., "Scaling factor on q/pt of data"}; + o2::framework::Configurable cfgNPhiBins{"nPhiBins", 0, "Number of phi bins"}; /////////////////////////////// /// parameters to be configured bool debugInfo = false; + bool updateTrackDCAs = false; // To update the track DCAs; bool updateTrackCovMat = false; bool updateCurvature = false; + bool updateCurvatureIU = false; // To update the track parameter Q/Pt in trackIU table, particularly used for V0 mass width dependence on Q/Pt bool updatePulls = false; bool isInputFileFromCCDB = false; // query input file from CCDB or local folder - std::string pathInputFile = ""; // Path to file containing DCAxy, DCAz graphs from data (upgr) and MC (current) - std::string nameInputFile = ""; // Common Name of different files containing graphs, found in the above paths + std::string pathInputFile = ""; // Path to file containing DCAxy, DCAz graphs from data and MC + std::string nameInputFile = ""; // Name of the file containing DCAxy, DCAz graphs from data and MC + std::string pathFileQoverPt = ""; // Path to file containing Q/Pt correction graphs from data and MC (only one proxy provided, i.e. D0 sigma graphs from data and MC) + std::string nameFileQoverPt = ""; // file name containing Q/Pt correction graphs from data and MC bool usePvRefitCorrections = false; // establish whether to use corrections obtained with or w/o PV refit - float oneOverPtCurrent = 0.; // 1/pt old - float oneOverPtUpgr = 0.; // 1/pt new + float qOverPtMC = -1.; // 1/pt MC + float qOverPtData = -1.; // 1/pt data /////////////////////////////// + bool isConfigFromString = false; + bool isConfigFromConfigurables = false; + int nPhiBins = 1; o2::ccdb::CcdbApi ccdbApi; std::map metadata; - std::unique_ptr grDcaXYResVsPtPionCurrent; - std::unique_ptr grDcaXYResVsPtPionUpgr; + std::vector> grDcaXYResVsPtPionMC; + std::vector> grDcaXYResVsPtPionData; + + std::vector> grDcaZResVsPtPionMC; + std::vector> grDcaZResVsPtPionData; - std::unique_ptr grDcaZResVsPtPionCurrent; - std::unique_ptr grDcaZResVsPtPionUpgr; + std::vector> grDcaXYMeanVsPtPionMC; + std::vector> grDcaXYMeanVsPtPionData; - std::unique_ptr grDcaXYMeanVsPtPionCurrent; - std::unique_ptr grDcaXYMeanVsPtPionUpgr; + std::vector> grDcaZMeanVsPtPionMC; + std::vector> grDcaZMeanVsPtPionData; - std::unique_ptr grDcaZMeanVsPtPionCurrent; - std::unique_ptr grDcaZMeanVsPtPionUpgr; + std::unique_ptr grOneOverPtPionMC; // MC + std::unique_ptr grOneOverPtPionData; // Data - std::unique_ptr grOneOverPtPionCurrent; - std::unique_ptr grOneOverPtPionUpgr; + std::vector> grDcaXYPullVsPtPionMC; + std::vector> grDcaXYPullVsPtPionData; - std::unique_ptr grDcaXYPullVsPtPionCurrent; - std::unique_ptr grDcaXYPullVsPtPionUpgr; + std::vector> grDcaZPullVsPtPionMC; + std::vector> grDcaZPullVsPtPionData; - std::unique_ptr grDcaZPullVsPtPionCurrent; - std::unique_ptr grDcaZPullVsPtPionUpgr; + /// @brief Function doing a few sanity-checks on the configurations + void checkConfig() + { + /// check configuration source + if (isConfigFromString && isConfigFromConfigurables) { + LOG(fatal) << " [ isConfigFromString==kTRUE and isConfigFromConfigurables==kTRUE ] Configuration done both via string and via configurables -> Only one of them can be set to kTRUE at once! Please refer to the trackTuner documentation."; + } + /// check Q/pt update + if ((updateCurvatureIU) && (updateCurvature)) { + LOG(fatal) << " [ updateCurvatureIU==kTRUE and updateCurvature==kTRUE ] -> Only one of them can be set to kTRUE at once! Please refer to the trackTuner documentation."; + } + } - /// @brief Function to configure the TrackTuner parameters + /// @brief Function to configure the TrackTuner parameters with an input string /// @param inputString Input string with all parameter configuration. Format: =|= /// @return String with the values of all parameters after configurations are listed, to cross check that everything worked well std::string configParams(std::string inputString) { + LOG(info) << "[TrackTuner] /*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/"; + LOG(info) << "[TrackTuner] /*/*/ /*/*/"; + LOG(info) << "[TrackTuner] /*/*/ Configuring the TrackTuner via a string /*/*/"; + LOG(info) << "[TrackTuner] /*/*/ /*/*/"; + LOG(info) << "[TrackTuner] /*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/"; + std::string delimiter = "|"; std::string assignmentSymbol = "="; @@ -122,39 +182,54 @@ struct TrackTuner { /// +++ to be manually updated every time one adds a new parameter to the TrackTuner.h +++ enum Pars : uint8_t { DebugInfo = 0, UpdateTrackCovMat, + UpdateTrackDCAs, UpdateCurvature, + UpdateCurvatureIU, UpdatePulls, - PathInputFile, IsInputFileFromCCDB, + PathInputFile, NameInputFile, + PathFileQoverPt, + NameFileQoverPt, UsePvRefitCorrections, - OneOverPtCurrent, - OneOverPtUpgr, + QOverPtMC, + QOverPtData, + NPhiBins, NPars }; std::map mapParNames = { std::make_pair(DebugInfo, "debugInfo"), + std::make_pair(UpdateTrackDCAs, "updateTrackDCAs"), std::make_pair(UpdateTrackCovMat, "updateTrackCovMat"), std::make_pair(UpdateCurvature, "updateCurvature"), + std::make_pair(UpdateCurvatureIU, "updateCurvatureIU"), std::make_pair(UpdatePulls, "updatePulls"), std::make_pair(IsInputFileFromCCDB, "isInputFileFromCCDB"), std::make_pair(PathInputFile, "pathInputFile"), + std::make_pair(PathFileQoverPt, "pathFileQoverPt"), std::make_pair(NameInputFile, "nameInputFile"), + std::make_pair(NameFileQoverPt, "nameFileQoverPt"), std::make_pair(UsePvRefitCorrections, "usePvRefitCorrections"), - std::make_pair(OneOverPtCurrent, "oneOverPtCurrent"), - std::make_pair(OneOverPtUpgr, "oneOverPtUpgr")}; + std::make_pair(QOverPtMC, "qOverPtMC"), + std::make_pair(QOverPtData, "qOverPtData"), + std::make_pair(NPhiBins, "nPhiBins")}; /////////////////////////////////////////////////////////////////////////////////// LOG(info) << "[TrackTuner]"; LOG(info) << "[TrackTuner] >>> Parameters before the custom settings"; LOG(info) << "[TrackTuner] debugInfo = " << debugInfo; + LOG(info) << "[TrackTuner] updateTrackDCAs = " << updateTrackDCAs; LOG(info) << "[TrackTuner] updateTrackCovMat = " << updateTrackCovMat; LOG(info) << "[TrackTuner] updateCurvature = " << updateCurvature; + LOG(info) << "[TrackTuner] updateCurvatureIU = " << updateCurvatureIU; LOG(info) << "[TrackTuner] updatePulls = " << updatePulls; LOG(info) << "[TrackTuner] isInputFileFromCCDB = " << isInputFileFromCCDB; LOG(info) << "[TrackTuner] pathInputFile = " << pathInputFile; LOG(info) << "[TrackTuner] nameInputFile = " << nameInputFile; + LOG(info) << "[TrackTuner] pathFileQoverPt = " << pathFileQoverPt; + LOG(info) << "[TrackTuner] nameFileQoverPt = " << nameFileQoverPt; LOG(info) << "[TrackTuner] usePvRefitCorrections = " << usePvRefitCorrections; - LOG(info) << "[TrackTuner] oneOverPtCurrent = " << oneOverPtCurrent; - LOG(info) << "[TrackTuner] oneOverPtUpgr = " << oneOverPtUpgr; + LOG(info) << "[TrackTuner] qOverPtMC = " << qOverPtMC; + LOG(info) << "[TrackTuner] qOverPtData = " << qOverPtData; + LOG(info) << "[TrackTuner] nPhiBins = " << nPhiBins; // ############################################################################################## // ######## split the original string, separating substrings delimited by "|" symbol ######## @@ -176,7 +251,7 @@ struct TrackTuner { /// check if the number of input parameters is correct if (static_cast(slices.size()) != NPars) { - LOG(fatal) << "[TrackTuner] " << slices.size() << " parameters provided, while " << NPars << " are expected. Fix it!"; + LOG(fatal) << "[TrackTuner] " << slices.size() << " parameters provided, while " << static_cast(NPars) << " are expected. Fix it!"; } // ################################################################################################################### @@ -216,6 +291,10 @@ struct TrackTuner { setBoolFromString(debugInfo, getValueString(DebugInfo)); LOG(info) << "[TrackTuner] debugInfo = " << debugInfo; outputString += "debugInfo=" + std::to_string(debugInfo); + // Configure updateTrackDCAs + setBoolFromString(updateTrackDCAs, getValueString(UpdateTrackDCAs)); + LOG(info) << "[TrackTuner] updateTrackDCAs = " << updateTrackDCAs; + outputString += ", updateTrackDCAs=" + std::to_string(updateTrackDCAs); // Configure updateTrackCovMat setBoolFromString(updateTrackCovMat, getValueString(UpdateTrackCovMat)); LOG(info) << "[TrackTuner] updateTrackCovMat = " << updateTrackCovMat; @@ -224,6 +303,10 @@ struct TrackTuner { setBoolFromString(updateCurvature, getValueString(UpdateCurvature)); LOG(info) << "[TrackTuner] updateCurvature = " << updateCurvature; outputString += ", updateCurvature=" + std::to_string(updateCurvature); + // Configure updateCurvatureIU + setBoolFromString(updateCurvatureIU, getValueString(UpdateCurvatureIU)); + LOG(info) << "[TrackTuner] updateCurvatureIU = " << updateCurvatureIU; + outputString += ", updateCurvatureIU=" + std::to_string(updateCurvatureIU); // Configure updatePulls setBoolFromString(updatePulls, getValueString(UpdatePulls)); LOG(info) << "[TrackTuner] updatePulls = " << updatePulls; @@ -236,22 +319,127 @@ struct TrackTuner { pathInputFile = getValueString(PathInputFile); outputString += ", pathInputFile=" + pathInputFile; LOG(info) << "[TrackTuner] pathInputFile = " << pathInputFile; + // Configure pathInputFile + pathFileQoverPt = getValueString(PathFileQoverPt); + outputString += ", pathFileQoverPt=" + pathFileQoverPt; + LOG(info) << "[TrackTuner] pathFileQoverPt = " << pathFileQoverPt; // Configure nameInputFile nameInputFile = getValueString(NameInputFile); outputString += ", nameInputFile=" + nameInputFile; LOG(info) << "[TrackTuner] nameInputFile = " << nameInputFile; + // Configure nameFileQoverPt + nameFileQoverPt = getValueString(NameFileQoverPt); + outputString += ", nameFileQoverPt=" + nameFileQoverPt; + LOG(info) << "[TrackTuner] nameFileQoverPt = " << nameFileQoverPt; // Configure usePvRefitCorrections setBoolFromString(usePvRefitCorrections, getValueString(UsePvRefitCorrections)); - outputString += ", usePvRefitCorrections=" + usePvRefitCorrections; + outputString += ", usePvRefitCorrections=" + std::to_string(usePvRefitCorrections); + LOG(info) << "[TrackTuner] usePvRefitCorrections = " << usePvRefitCorrections; + // Configure qOverPtMC + qOverPtMC = std::stof(getValueString(QOverPtMC)); + outputString += ", qOverPtMC=" + std::to_string(qOverPtMC); + LOG(info) << "[TrackTuner] qOverPtMC = " << qOverPtMC; + // Configure qOverPtData + qOverPtData = std::stof(getValueString(QOverPtData)); + outputString += ", qOverPtData=" + std::to_string(qOverPtData); + LOG(info) << "[TrackTuner] qOverPtData = " << qOverPtData; + // Configure nPhiBins + nPhiBins = std::stoi(getValueString(NPhiBins)); + outputString += ", nPhiBins=" + std::to_string(nPhiBins); + if (nPhiBins < 0) + LOG(fatal) << "[TrackTuner] negative nPhiBins!" << nPhiBins; + LOG(info) << "[TrackTuner] nPhiBins = " << nPhiBins; + /// declare that the configuration is done via an input string + isConfigFromString = true; + + /// sanity-checks on the configurations + checkConfig(); + + return outputString; + } + + /// @brief Function to configure the TrackTuner parameters with an input string + /// @return String with the values of all parameters after configurations are listed, to cross check that everything worked well + std::string configParams() + { + + LOG(info) << "[TrackTuner] /=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#"; + LOG(info) << "[TrackTuner] /=/#/ /=/#/"; + LOG(info) << "[TrackTuner] /=/#/ Configuring the TrackTuner using the input Configurables /=/#/"; + LOG(info) << "[TrackTuner] /=/#/ /=/#/"; + LOG(info) << "[TrackTuner] /=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/"; + + std::string outputString = ""; + LOG(info) << "[TrackTuner] "; + LOG(info) << "[TrackTuner] >>> Parameters after the custom settings"; + // Configure debugInfo + debugInfo = cfgDebugInfo; + LOG(info) << "[TrackTuner] debugInfo = " << debugInfo; + outputString += "debugInfo=" + std::to_string(debugInfo); + // Configure updateTrackDCAs + updateTrackDCAs = cfgUpdateTrackDCAs; + LOG(info) << "[TrackTuner] updateTrackDCAs = " << updateTrackDCAs; + outputString += ", updateTrackDCAs=" + std::to_string(updateTrackDCAs); + // Configure updateTrackCovMat + updateTrackCovMat = cfgUpdateTrackCovMat; + LOG(info) << "[TrackTuner] updateTrackCovMat = " << updateTrackCovMat; + outputString += ", updateTrackCovMat=" + std::to_string(updateTrackCovMat); + // Configure updateCurvature + updateCurvature = cfgUpdateCurvature; + LOG(info) << "[TrackTuner] updateCurvature = " << updateCurvature; + outputString += ", updateCurvature=" + std::to_string(updateCurvature); + // Configure updateCurvatureIU + updateCurvatureIU = cfgUpdateCurvatureIU; + LOG(info) << "[TrackTuner] updateCurvatureIU = " << updateCurvatureIU; + outputString += ", updateCurvatureIU=" + std::to_string(updateCurvatureIU); + // Configure updatePulls + updatePulls = cfgUpdatePulls; + LOG(info) << "[TrackTuner] updatePulls = " << updatePulls; + outputString += ", updatePulls=" + std::to_string(updatePulls); + // Configure isInputFileFromCCDB + isInputFileFromCCDB = cfgIsInputFileFromCCDB; + LOG(info) << "[TrackTuner] isInputFileFromCCDB = " << isInputFileFromCCDB; + outputString += ", isInputFileFromCCDB=" + std::to_string(isInputFileFromCCDB); + // Configure pathInputFile + pathInputFile = cfgPathInputFile; + outputString += ", pathInputFile=" + pathInputFile; + LOG(info) << "[TrackTuner] pathInputFile = " << pathInputFile; + // Configure pathInputFile + pathFileQoverPt = cfgPathFileQoverPt; + outputString += ", pathFileQoverPt=" + pathFileQoverPt; + LOG(info) << "[TrackTuner] pathFileQoverPt = " << pathFileQoverPt; + // Configure nameInputFile + nameInputFile = cfgNameInputFile; + outputString += ", nameInputFile=" + nameInputFile; + LOG(info) << "[TrackTuner] nameInputFile = " << nameInputFile; + // Configure nameFileQoverPt + nameFileQoverPt = cfgNameFileQoverPt; + outputString += ", nameFileQoverPt=" + nameFileQoverPt; + LOG(info) << "[TrackTuner] nameFileQoverPt = " << nameFileQoverPt; + // Configure usePvRefitCorrections + usePvRefitCorrections = cfgUsePvRefitCorrections; + outputString += ", usePvRefitCorrections=" + std::to_string(usePvRefitCorrections); LOG(info) << "[TrackTuner] usePvRefitCorrections = " << usePvRefitCorrections; - // Configure oneOverPtCurr - oneOverPtCurrent = std::stof(getValueString(OneOverPtCurrent)); - outputString += ", oneOverPtCurrent=" + std::to_string(oneOverPtCurrent); - LOG(info) << "[TrackTuner] oneOverPtCurrent = " << oneOverPtCurrent; - // Configure oneOverPtUpgr - oneOverPtUpgr = std::stof(getValueString(OneOverPtUpgr)); - outputString += ", oneOverPtUpgr=" + std::to_string(oneOverPtUpgr); - LOG(info) << "[TrackTuner] oneOverPtUpgr = " << oneOverPtUpgr; + // Configure qOverPtMC + qOverPtMC = cfgQOverPtMC; + outputString += ", qOverPtMC=" + std::to_string(qOverPtMC); + LOG(info) << "[TrackTuner] qOverPtMC = " << qOverPtMC; + // Configure qOverPtData + qOverPtData = cfgQOverPtData; + outputString += ", qOverPtData=" + std::to_string(qOverPtData); + LOG(info) << "[TrackTuner] qOverPtData = " << qOverPtData; + // Configure nPhiBins + nPhiBins = cfgNPhiBins; + outputString += ", nPhiBins=" + std::to_string(nPhiBins); + if (nPhiBins < 0) + LOG(fatal) << "[TrackTuner] negative nPhiBins!" << nPhiBins; + LOG(info) << "[TrackTuner] nPhiBins = " << nPhiBins; + + /// declare that the configuration is done via the Configurables + isConfigFromConfigurables = true; + + /// sanity-checks on the configurations + checkConfig(); return outputString; } @@ -259,6 +447,7 @@ struct TrackTuner { void getDcaGraphs() { std::string fullNameInputFile = ""; + std::string fullNameFileQoverPt = ""; if (isInputFileFromCCDB) { /// use input correction file from CCDB @@ -267,23 +456,32 @@ struct TrackTuner { std::string tmpDir = "."; ccdbApi.init("http://alice-ccdb.cern.ch"); - // get the file from CCDB + // get the DCA correction file from CCDB if (!ccdbApi.retrieveBlob(pathInputFile.data(), tmpDir, metadata, 0, false, nameInputFile.data())) { - LOG(fatal) << "[TrackTuner] input file not found on CCDB, please check the pathInputFile and nameInputFile!"; + LOG(fatal) << "[TrackTuner] input file for DCA corrections not found on CCDB, please check the pathInputFile and nameInputFile!"; } + // get the Q/Pt correction file from CCDB + if (!ccdbApi.retrieveBlob(pathFileQoverPt.data(), tmpDir, metadata, 0, false, nameFileQoverPt.data())) { + LOG(fatal) << "[TrackTuner] input file for Q/Pt corrections not found on CCDB, please check the pathFileQoverPt and nameFileQoverPt!"; + } // point to the file in the tmp local folder fullNameInputFile = tmpDir + std::string("/") + nameInputFile; + fullNameFileQoverPt = tmpDir + std::string("/") + nameFileQoverPt; } else { /// use input correction file from local filesystem fullNameInputFile = pathInputFile + std::string("/") + nameInputFile; + fullNameFileQoverPt = pathFileQoverPt + std::string("/") + nameFileQoverPt; } - /// open the input correction file std::unique_ptr inputFile(TFile::Open(fullNameInputFile.c_str(), "READ")); if (!inputFile.get()) { LOG(fatal) << "Something wrong with the input file" << fullNameInputFile << " for dca correction. Fix it!"; } + std::unique_ptr inputFileQoverPt(TFile::Open(fullNameFileQoverPt.c_str(), "READ")); + if (!inputFileQoverPt.get() && (updateCurvature || updateCurvatureIU)) { + LOG(fatal) << "Something wrong with the Q/Pt input file" << fullNameFileQoverPt << " for Q/Pt correction. Fix it!"; + } // choose wheter to use corrections w/ PV refit or w/o it, and retrieve the proper TDirectory std::string dir = "woPvRefit"; @@ -295,330 +493,435 @@ struct TrackTuner { LOG(fatal) << "TDirectory " << td << " not found in input file" << inputFile->GetName() << ". Fix it!"; } - std::string grDcaXYResNameCurr = "resCurrentDcaXY"; - std::string grDcaXYMeanNameCurr = "meanCurrentDcaXY"; - std::string grDcaXYPullNameCurr = "pullsCurrentDcaXY"; - std::string grDcaXYResNameUpgr = "resUpgrDcaXY"; - std::string grDcaXYMeanNameUpgr = "meanUpgrDcaXY"; - std::string grDcaXYPullNameUpgr = "pullsUpgrDcaXY"; - - grDcaXYResVsPtPionCurrent.reset(dynamic_cast(td->Get(grDcaXYResNameCurr.c_str()))); - grDcaXYResVsPtPionUpgr.reset(dynamic_cast(td->Get(grDcaXYResNameUpgr.c_str()))); - grDcaXYMeanVsPtPionCurrent.reset(dynamic_cast(td->Get(grDcaXYMeanNameCurr.c_str()))); - grDcaXYMeanVsPtPionUpgr.reset(dynamic_cast(td->Get(grDcaXYMeanNameUpgr.c_str()))); - grDcaXYPullVsPtPionCurrent.reset(dynamic_cast(td->Get(grDcaXYPullNameCurr.c_str()))); - grDcaXYPullVsPtPionUpgr.reset(dynamic_cast(td->Get(grDcaXYPullNameUpgr.c_str()))); - if (!grDcaXYResVsPtPionCurrent.get() || !grDcaXYResVsPtPionUpgr.get() || !grDcaXYMeanVsPtPionCurrent.get() || !grDcaXYMeanVsPtPionUpgr.get() || !grDcaXYPullVsPtPionCurrent.get() || !grDcaXYPullVsPtPionUpgr.get()) { - LOG(fatal) << "Something wrong with the names of the correction graphs for dcaXY. Fix it!"; - } - - std::string grDcaZResNameCurr = "resCurrentDcaZ"; - std::string grDcaZMeanNameCurr = "meanCurrentDcaZ"; - std::string grDcaZPullNameCurr = "pullsCurrentDcaZ"; - std::string grDcaZResNameUpgr = "resUpgrDcaZ"; - std::string grDcaZMeanNameUpgr = "meanUpgrDcaZ"; - std::string grDcaZPullNameUpgr = "pullsUpgrDcaZ"; - - grDcaZResVsPtPionCurrent.reset(dynamic_cast(td->Get(grDcaZResNameCurr.c_str()))); - grDcaZResVsPtPionUpgr.reset(dynamic_cast(td->Get(grDcaZResNameUpgr.c_str()))); - grDcaZMeanVsPtPionCurrent.reset(dynamic_cast(td->Get(grDcaZMeanNameCurr.c_str()))); - grDcaZMeanVsPtPionUpgr.reset(dynamic_cast(td->Get(grDcaZMeanNameUpgr.c_str()))); - grDcaZPullVsPtPionCurrent.reset(dynamic_cast(td->Get(grDcaZPullNameCurr.c_str()))); - grDcaZPullVsPtPionUpgr.reset(dynamic_cast(td->Get(grDcaZPullNameUpgr.c_str()))); - if (!grDcaZResVsPtPionCurrent.get() || !grDcaZResVsPtPionUpgr.get() || !grDcaZMeanVsPtPionCurrent.get() || !grDcaZMeanVsPtPionUpgr.get() || !grDcaZPullVsPtPionCurrent.get() || !grDcaZPullVsPtPionUpgr.get()) { - LOG(fatal) << "Something wrong with the names of the correction graphs for dcaZ. Fix it!"; - } - } - - template - void tuneTrackParams(T1 const& mcparticle, T2& trackParCov, T3 const& matCorr, T4 dcaInfoCov, H hQA) - { - - double ptMC = mcparticle.pt(); - - double dcaXYResCurrent = 0.0; // sd0rpo=0.; - double dcaZResCurrent = 0.0; // sd0zo =0.; + int inputNphiBins = nPhiBins; + if (inputNphiBins == 0) + nPhiBins = 1; // old phi_independent settings - double dcaXYResUpgr = 0.0; // sd0rpn=0.; - double dcaZResUpgr = 0.0; // sd0zn =0.; + // reserve memory and initialize vector for needed number of graphs + grDcaXYResVsPtPionMC.resize(nPhiBins); + grDcaXYResVsPtPionData.resize(nPhiBins); - // double OneOverPtCurrent = 0.0; // spt1o =0.; - // double OneOverPtUpgr = 0.0; // spt1n =0.; + grDcaZResVsPtPionMC.resize(nPhiBins); + grDcaZResVsPtPionData.resize(nPhiBins); - double dcaXYMeanCurrent = 0.0; // sd0mrpo=0.; - double dcaXYMeanUpgr = 0.0; // sd0mrpn=0.; + grDcaXYMeanVsPtPionMC.resize(nPhiBins); + grDcaXYMeanVsPtPionData.resize(nPhiBins); - double dcaXYPullCurrent = 1.0; - double dcaXYPullUpgr = 1.0; + grDcaZMeanVsPtPionMC.resize(nPhiBins); + grDcaZMeanVsPtPionData.resize(nPhiBins); - double dcaZPullCurrent = 1.0; - double dcaZPullUpgr = 1.0; + grDcaXYPullVsPtPionMC.resize(nPhiBins); + grDcaXYPullVsPtPionData.resize(nPhiBins); - dcaXYResCurrent = evalGraph(ptMC, grDcaXYResVsPtPionCurrent.get()); - dcaXYResUpgr = evalGraph(ptMC, grDcaXYResVsPtPionUpgr.get()); + grDcaZPullVsPtPionMC.resize(nPhiBins); + grDcaZPullVsPtPionData.resize(nPhiBins); - // dcaXYResCurrent = 1.0; - // dcaXYResUpgr = 1.5; - - dcaZResCurrent = evalGraph(ptMC, grDcaZResVsPtPionCurrent.get()); - dcaZResUpgr = evalGraph(ptMC, grDcaZResVsPtPionUpgr.get()); - - // dcaZResCurrent = 1.0; - // dcaZResUpgr = 1.0; + /// Lambda expression to get the TGraphErrors from file + auto loadGraph = [&](int phiBin, const std::string& strBaseName) -> TGraphErrors* { + std::string strGraphName = inputNphiBins != 0 ? fmt::format("{}_{}", strBaseName, phiBin) : strBaseName; + TObject* obj = td->Get(strGraphName.c_str()); + if (!obj) { + LOG(fatal) << "[TrackTuner] TGraphErrors not found in the Input Root file: " << strGraphName; + td->ls(); + return nullptr; + } + return dynamic_cast(obj); + }; - // OneOverPtCurrent = evalGraph(ptMC, grOneOverPtPionCurrent.get() ); - // OneOverPtUpgr = evalGraph(ptMC, grOneOverPtPionUpgr.get() ); + if (inputNphiBins != 0) { + LOG(info) << "[TrackTuner] Loading phi-dependent XY TGraphErrors"; + } + for (int iPhiBin = 0; iPhiBin < nPhiBins; ++iPhiBin) { - // OneOverPtCurrent = 1.0; - // OneOverPtUpgr = 2.0; + grDcaXYResVsPtPionMC[iPhiBin].reset(loadGraph(iPhiBin, "resCurrentDcaXY")); + grDcaXYResVsPtPionData[iPhiBin].reset(loadGraph(iPhiBin, "resUpgrDcaXY")); + grDcaXYMeanVsPtPionMC[iPhiBin].reset(loadGraph(iPhiBin, "meanCurrentDcaXY")); + grDcaXYMeanVsPtPionData[iPhiBin].reset(loadGraph(iPhiBin, "meanUpgrDcaXY")); + grDcaXYPullVsPtPionMC[iPhiBin].reset(loadGraph(iPhiBin, "pullsCurrentDcaXY")); + grDcaXYPullVsPtPionData[iPhiBin].reset(loadGraph(iPhiBin, "pullsUpgrDcaXY")); - dcaXYMeanCurrent = evalGraph(ptMC, grDcaXYMeanVsPtPionCurrent.get()); - dcaXYMeanUpgr = evalGraph(ptMC, grDcaXYMeanVsPtPionUpgr.get()); + if (!grDcaXYResVsPtPionMC[iPhiBin].get() || !grDcaXYResVsPtPionData[iPhiBin].get() || !grDcaXYMeanVsPtPionMC[iPhiBin].get() || !grDcaXYMeanVsPtPionData[iPhiBin].get() || !grDcaXYPullVsPtPionMC[iPhiBin].get() || !grDcaXYPullVsPtPionData[iPhiBin].get()) { + LOG(fatal) << "[TrackTuner] Something wrong with the names of the correction graphs for dcaXY. Fix it! Problematic phi bin is" << iPhiBin; + } + } - // dcaXYMeanCurrent = 0.0; - // dcaXYMeanUpgr = 0.0; + if (inputNphiBins != 0) { + LOG(info) << "[TrackTuner] Loading phi-dependent Z TGraphErrors"; + } + for (int iPhiBin = 0; iPhiBin < nPhiBins; ++iPhiBin) { + grDcaZResVsPtPionMC[iPhiBin].reset(loadGraph(iPhiBin, "resCurrentDcaZ")); + grDcaZMeanVsPtPionMC[iPhiBin].reset(loadGraph(iPhiBin, "meanCurrentDcaZ")); + grDcaZPullVsPtPionMC[iPhiBin].reset(loadGraph(iPhiBin, "pullsCurrentDcaZ")); + grDcaZResVsPtPionData[iPhiBin].reset(loadGraph(iPhiBin, "resUpgrDcaZ")); + grDcaZMeanVsPtPionData[iPhiBin].reset(loadGraph(iPhiBin, "meanUpgrDcaZ")); + grDcaZPullVsPtPionData[iPhiBin].reset(loadGraph(iPhiBin, "pullsUpgrDcaZ")); + + if (!grDcaZResVsPtPionMC[iPhiBin].get() || !grDcaZResVsPtPionData[iPhiBin].get() || !grDcaZMeanVsPtPionMC[iPhiBin].get() || !grDcaZMeanVsPtPionData[iPhiBin].get() || !grDcaZPullVsPtPionMC[iPhiBin].get() || !grDcaZPullVsPtPionData[iPhiBin].get()) { + LOG(fatal) << "[TrackTuner] Something wrong with the names of the correction graphs for dcaZ. Fix it! Problematic phi bin is" << iPhiBin; + } + } - dcaXYPullCurrent = evalGraph(ptMC, grDcaXYPullVsPtPionCurrent.get()); - dcaXYPullUpgr = evalGraph(ptMC, grDcaXYPullVsPtPionUpgr.get()); + std::string grOneOverPtPionNameMC = "sigmaVsPtMc"; + std::string grOneOverPtPionNameData = "sigmaVsPtData"; - dcaZPullCurrent = evalGraph(ptMC, grDcaZPullVsPtPionCurrent.get()); - dcaZPullUpgr = evalGraph(ptMC, grDcaZPullVsPtPionUpgr.get()); + if (updateCurvature || updateCurvatureIU) { + grOneOverPtPionMC.reset(dynamic_cast(inputFileQoverPt->Get(grOneOverPtPionNameMC.c_str()))); + grOneOverPtPionData.reset(dynamic_cast(inputFileQoverPt->Get(grOneOverPtPionNameData.c_str()))); + } + } // getDcaGraphs() ends here + template + void tuneTrackParams(T1 const& mcparticle, T2& trackParCov, T3 const& matCorr, T4 dcaInfoCov, H hQA) + { + double ptMC = mcparticle.pt(); + double dcaXYResMC = 0.0; // sd0rpo=0.; + double dcaZResMC = 0.0; // sd0zo =0.; + + double dcaXYResData = 0.0; // sd0rpn=0.; + double dcaZResData = 0.0; // sd0zn =0.; + + double dcaXYMeanMC = 0.0; // sd0mrpo=0.; + double dcaXYMeanData = 0.0; // sd0mrpn=0.; + + double dcaXYPullMC = 1.0; + double dcaXYPullData = 1.0; + + double dcaZPullMC = 1.0; + double dcaZPullData = 1.0; + + // get phibin + double phiMC = mcparticle.phi(); + if (phiMC < 0.) + phiMC += o2::constants::math::TwoPI; // 2 * std::numbers::pi;// + int phiBin = phiMC / (o2::constants::math::TwoPI + 0.0000001) * nPhiBins; // 0.0000001 just a numerical protection + + dcaXYResMC = evalGraph(ptMC, grDcaXYResVsPtPionMC[phiBin].get()); + dcaXYResData = evalGraph(ptMC, grDcaXYResVsPtPionData[phiBin].get()); + + dcaZResMC = evalGraph(ptMC, grDcaZResVsPtPionMC[phiBin].get()); + dcaZResData = evalGraph(ptMC, grDcaZResVsPtPionData[phiBin].get()); + + // For Q/Pt corrections, files on CCDB will be used if both qOverPtMC and qOverPtData are null + if (updateCurvature || updateCurvatureIU) { + if ((qOverPtMC < 0) || (qOverPtData < 0)) { + if (debugInfo) { + LOG(info) << "### q/pt smearing: qOverPtMC=" << qOverPtMC << ", qOverPtData=" << qOverPtData << ". One of them is negative. Retrieving then values from graphs from input .root file"; + } + /// check that input graphs for q/pt smearing are correctly retrieved + if (!grOneOverPtPionData.get() || !grOneOverPtPionMC.get()) { + LOG(fatal) << "### q/pt smearing: input graphs not correctly retrieved. Aborting."; + } + qOverPtMC = std::max(0.0, evalGraph(ptMC, grOneOverPtPionMC.get())); + qOverPtData = std::max(0.0, evalGraph(ptMC, grOneOverPtPionData.get())); + } // qOverPtMC, qOverPtData block ends here + } // updateCurvature, updateCurvatureIU block ends here + + if (updateTrackDCAs) { + + dcaXYMeanMC = evalGraph(ptMC, grDcaXYMeanVsPtPionMC[phiBin].get()); + dcaXYMeanData = evalGraph(ptMC, grDcaXYMeanVsPtPionData[phiBin].get()); + + dcaXYPullMC = evalGraph(ptMC, grDcaXYPullVsPtPionMC[phiBin].get()); + dcaXYPullData = evalGraph(ptMC, grDcaXYPullVsPtPionData[phiBin].get()); + + dcaZPullMC = evalGraph(ptMC, grDcaZPullVsPtPionMC[phiBin].get()); + dcaZPullData = evalGraph(ptMC, grDcaZPullVsPtPionData[phiBin].get()); + } // Unit conversion, is it required ?? - dcaXYResCurrent *= 1.e-4; - dcaZResCurrent *= 1.e-4; + dcaXYResMC *= 1.e-4; + dcaZResMC *= 1.e-4; - dcaXYResUpgr *= 1.e-4; - dcaZResUpgr *= 1.e-4; + dcaXYResData *= 1.e-4; + dcaZResData *= 1.e-4; - dcaXYMeanCurrent *= 1.e-4; - dcaXYMeanUpgr *= 1.e-4; + dcaXYMeanMC *= 1.e-4; + dcaXYMeanData *= 1.e-4; // Apply the smearing // --------------------------------------------- // double pt1o =param [4]; - double trackParOneOverPtCurrent = trackParCov.getQ2Pt(); + double trackParQPtMCRec = trackParCov.getQ2Pt(); int sign = trackParCov.getQ2Pt() / std::abs(trackParCov.getQ2Pt()); // double pt1mc =parammc[4]; - double trackParOneOverPtMC = sign / mcparticle.pt(); + double trackParQPtMC = sign / mcparticle.pt(); o2::dataformats::VertexBase vtxMC; vtxMC.setPos({mcparticle.vx(), mcparticle.vy(), mcparticle.vz()}); vtxMC.setCov(0, 0, 0, 0, 0, 0); // ??? or All ZEROs // == 1 cm2? wrt prop point if (debugInfo) { - // LOG(info) << " sign " << sign; - // LOG(info) << " trackParCov.getQ2Pt() " << trackParOneOverPtCurrent << " " << trackParCov.getQ2Pt(); - // LOG(info) << " sign/mcparticle.pt() " << trackParOneOverPtMC; - // LOG(info) << " (curvReco-curvMC)/curvMC " << (trackParOneOverPtCurrent - trackParOneOverPtMC)/trackParOneOverPtMC * 100.0 << "%"; - // LOG(info) << " trackParCov.getPtInv() " << trackParCov.getPtInv() << std::endl; - // LOG(info) << " 1/trackParCov.getPtInv() " << 1./trackParCov.getPtInv() << " & mcparticle.pt() " << mcparticle.pt(); - LOG(info) << mcparticle.pt() << " " << 1 / trackParCov.getPtInv() << " " << (trackParOneOverPtCurrent - trackParOneOverPtMC) / trackParOneOverPtMC * 100.0; - // LOG(info) << "Before Propagation to Production Point -> alpha: " << trackParCov.getAlpha() << ", DCAxy: " << trackParCov.getY() << ", DCAz: " << trackParCov.getZ(); - } - // propagate to DCA with respect to the Production point - o2::base::Propagator::Instance()->propagateToDCABxByBz(vtxMC, trackParCov, 2.f, matCorr, dcaInfoCov); - if (debugInfo) { - // LOG(info) << "After Propagation to Production Point -> alpha: " << trackParCov.getAlpha() << ", DCAxy: " << trackParCov.getY() << ", DCAz: " << trackParCov.getZ(); - LOG(info) << "track.y(): " << trackParCov.getY(); + LOG(info) << mcparticle.pt() << " " << 1 / trackParCov.getPtInv() << " " << (trackParQPtMCRec - trackParQPtMC) / trackParQPtMC * 100.0; } - ////////////////////////////// DCAs modifications Start ///////////////////////////////// - - // double d0zo =param [1]; - double trackParDcaZCurrent = trackParCov.getZ(); - - // double d0rpo =param [0]; - double trackParDcaXYCurrent = trackParCov.getY(); + // for updating the Q/pT from the tracksIU. + // This is placed before track propagation to production point, so that Q/pT can be updated before propagation + // Q/Pt is modified and set before track propagation - float mcVxRotated = mcparticle.vx() * std::cos(trackParCov.getAlpha()) + mcparticle.vy() * std::sin(trackParCov.getAlpha()); // invert - float mcVyRotated = mcparticle.vy() * std::cos(trackParCov.getAlpha()) - mcparticle.vx() * std::sin(trackParCov.getAlpha()); + double deltaQpt = 0.0; + double deltaQptTuned = 0.0; + double trackParQPtTuned = 0.0; - if (debugInfo) { - // LOG(info) << "mcVy " << mcparticle.vy() << std::endl; - LOG(info) << "mcVxRotated " << mcVxRotated; - LOG(info) << "mcVyRotated " << mcVyRotated; - } + // variables for track cov matrix elements update + double sigmaY2 = 0.0; + double sigmaZY = 0.0; + double sigmaZ2 = 0.0; + double sigmaSnpY = 0.0; + double sigmaSnpZ = 0.0; + double sigmaTglY = 0.0; + double sigmaTglZ = 0.0; + double sigma1PtY = 0.0; + double sigma1PtZ = 0.0; + double sigma1PtSnp = 0.0; + double sigma1PtTgl = 0.0; + double sigma1Pt2 = 0.0; - // std::array arrayXYZ = { mcVxRotated, mcVyRotated , mcparticle.vz()}; - // std::array arrayPxPyPz = {mcparticle.px(), mcparticle.py(), mcparticle.pz()}; + double sigmaY2orig = trackParCov.getSigmaY2(); + double sigmaZYorig = trackParCov.getSigmaZY(); + double sigmaZ2orig = trackParCov.getSigmaZ2(); - // const int matSize = 21; - // std::array arrayCovMatMC = {0.,0.,0.,0.,0., 0.,0.,0.,0.,0., 0.,0.,0.,0.,0., 0.,0.,0.,0.,0.,0. }; - // o2::track::TrackParametrizationWithError trackParCovMC{arrayXYZ, arrayPxPyPz, arrayCovMatMC, trackParCov.getSign()}; + if (updateCurvatureIU) { + // double dpt1o =pt1o-pt1mc; + deltaQpt = trackParQPtMCRec - trackParQPtMC; + // double dpt1n =dpt1o *(spt1o >0. ? (spt1n /spt1o ) : 1.); + deltaQptTuned = deltaQpt * (qOverPtMC > 0. ? (qOverPtData / qOverPtMC) : 1.); + // double pt1n = pt1mc+dpt1n; + trackParQPtTuned = trackParQPtMC + deltaQptTuned; + trackParCov.setQ2Pt(trackParQPtTuned); - // double d0rpmc=parammc[0]; - // double trackParDcaXYMC = trackParCovMC.getY(); // here + // updating track cov matrix elements for 1/Pt at innermost update point + // if(sd0rpo>0. && spt1o>0.)covar[10]*=(sd0rpn/sd0rpo)*(spt1n/spt1o);//ypt + sigma1PtY = trackParCov.getSigma1PtY(); + if (dcaXYResMC > 0. && qOverPtMC > 0.) { + sigma1PtY *= ((dcaXYResData / dcaXYResMC) * (qOverPtData / qOverPtMC)); + trackParCov.setCov(sigma1PtY, 10); + } - double trackParDcaXYMC = mcVyRotated; // here - // LOG(info) << "trackParCovMC.getY() " << trackParCovMC.getY() << std::endl; + // if(sd0zo>0. && spt1o>0.) covar[11]*=(sd0zn/sd0zo)*(spt1n/spt1o);//zpt + sigma1PtZ = trackParCov.getSigma1PtZ(); + if (dcaZResMC > 0. && qOverPtMC > 0.) { + sigma1PtZ *= ((dcaZResData / dcaZResMC) * (qOverPtData / qOverPtMC)); + trackParCov.setCov(sigma1PtZ, 11); + } - // double d0zmc =parammc[1]; - double trackParDcaZMC = mcparticle.vz(); + // if(spt1o>0.) covar[12]*=(spt1n/spt1o);//sinPhipt + sigma1PtSnp = trackParCov.getSigma1PtSnp(); + if (qOverPtMC > 0.) { + sigma1PtSnp *= (qOverPtData / qOverPtMC); + trackParCov.setCov(sigma1PtSnp, 12); + } - // double dd0zo =d0zo-d0zmc; - double diffDcaZFromMCCurent = trackParDcaZCurrent - trackParDcaZMC; + // if(spt1o>0.) covar[13]*=(spt1n/spt1o);//tanTpt + sigma1PtTgl = trackParCov.getSigma1PtTgl(); + if (qOverPtMC > 0.) { + sigma1PtTgl *= (qOverPtData / qOverPtMC); + trackParCov.setCov(sigma1PtTgl, 13); + } - // double dd0zn =dd0zo *(sd0zo >0. ? (sd0zn /sd0zo ) : 1.); - double diffDcaZFromMCUpgr = diffDcaZFromMCCurent * (dcaZResCurrent > 0. ? (dcaZResUpgr / dcaZResCurrent) : 1.); + // if(spt1o>0.) covar[14]*=(spt1n/spt1o)*(spt1n/spt1o);//ptpt + sigma1Pt2 = trackParCov.getSigma1Pt2(); + if (qOverPtMC > 0.) { + sigma1Pt2 *= (qOverPtData / qOverPtMC); + trackParCov.setCov(sigma1Pt2, 14); + } + } // updateCurvatureIU block ends here + // propagate to DCA with respect to the Production point + // if (!updateCurvatureIU) { + // o2::base::Propagator::Instance()->propagateToDCABxByBz(vtxMC, trackParCov, 2.f, matCorr, dcaInfoCov); + // } - // double d0zn =d0zmc+dd0zn; - double trackParDcaZUpgr = trackParDcaZMC + diffDcaZFromMCUpgr; + double trackParDcaXYoriginal = trackParCov.getY(); + double trackParDcaZoriginal = trackParCov.getZ(); - // double dd0rpo=d0rpo-d0rpmc; - double diffDcaXYFromMCCurent = trackParDcaXYCurrent - trackParDcaXYMC; + if (updateTrackDCAs) { + // propagate to DCA with respect to the Production point + o2::base::Propagator::Instance()->propagateToDCABxByBz(vtxMC, trackParCov, 2.f, matCorr, dcaInfoCov); + if (debugInfo) { + LOG(info) << "phi MC" << mcparticle.phi(); + LOG(info) << "alpha track" << trackParCov.getAlpha(); + } + // double d0zo =param [1]; + double trackParDcaZRec = trackParCov.getZ(); + // double d0rpo =param [0]; + double trackParDcaXYRec = trackParCov.getY(); + float mcVxRotated = mcparticle.vx() * std::cos(trackParCov.getAlpha()) + mcparticle.vy() * std::sin(trackParCov.getAlpha()); // invert + float mcVyRotated = mcparticle.vy() * std::cos(trackParCov.getAlpha()) - mcparticle.vx() * std::sin(trackParCov.getAlpha()); - // double dd0rpn=dd0rpo*(sd0rpo>0. ? (sd0rpn/sd0rpo) : 1.); - double diffDcaXYFromMCUpgr = diffDcaXYFromMCCurent * (dcaXYResCurrent > 0. ? (dcaXYResUpgr / dcaXYResCurrent) : 1.); + if (debugInfo) { + // LOG(info) << "mcVy " << mcparticle.vy() << std::endl; + LOG(info) << "mcVxRotated " << mcVxRotated; + LOG(info) << "mcVyRotated " << mcVyRotated; + } + // std::array arrayXYZ = { mcVxRotated, mcVyRotated , mcparticle.vz()}; + // std::array arrayPxPyPz = {mcparticle.px(), mcparticle.py(), mcparticle.pz()}; - // double dd0mrpn=std::abs(sd0mrpn)-std::abs(sd0mrpo); - // double diffDcaXYMeanUpgMinusCur = std::abs(dcaXYMeanUpgr) - std::abs(dcaXYMeanCurrent) ; - double diffDcaXYMeanUpgMinusCur = dcaXYMeanUpgr - dcaXYMeanCurrent; + // const int matSize = 21; + // std::array arrayCovMatMC = {0.,0.,0.,0.,0., 0.,0.,0.,0.,0., 0.,0.,0.,0.,0., 0.,0.,0.,0.,0.,0. }; + // o2::track::TrackParametrizationWithError trackParCovMC{arrayXYZ, arrayPxPyPz, arrayCovMatMC, trackParCov.getSign()}; - // double d0rpn =d0rpmc+dd0rpn-dd0mrpn; - double trackParDcaXYUpgr = trackParDcaXYMC + diffDcaXYFromMCUpgr - diffDcaXYMeanUpgMinusCur; + // double d0rpmc=parammc[0]; + // double trackParDcaXYMC = trackParCovMC.getY(); // here - if (debugInfo) { - LOG(info) << dcaZResCurrent << ", " << dcaZResUpgr << ", diff(DcaZ - DcaZMC): " << diffDcaZFromMCCurent << ", diff upgraded: " << diffDcaZFromMCUpgr << ", DcaZ Upgr : " << trackParDcaZUpgr; - LOG(info) << dcaXYResCurrent << ", " << dcaXYResUpgr << ", diff(DcaY - DcaYMC): " << diffDcaXYFromMCCurent << ", diff upgraded: " << diffDcaXYFromMCUpgr << ", DcaY Upgr :" << trackParDcaXYUpgr; - } + double trackParDcaXYMC = mcVyRotated; // here - // option mimic data - // ---------------------- - // if(fMimicData){ - // // dd0mrpn=sd0mrpn-sd0mrpo; - // diffDcaXYMeanUpgMinusCur = dcaXYMeanUpgr - dcaXYMeanCurrent; - // // d0rpn = d0rpmc+dd0rpn+dd0mrpn; - // trackParDcaXYUpgr = diffDcaXYFromMCCurent + diffDcaXYFromMCUpgr + diffDcaXYMeanUpgMinusCur; - // } + // double d0zmc =parammc[1]; + double trackParDcaZMC = mcparticle.vz(); - // setting updated track parameters - // -------------------------------- - // param[0]=d0rpn; - // double oldDCAxyValue = trackParCov.getY(); - double trackParDcaXYoriginal = trackParCov.getY(); - trackParCov.setY(trackParDcaXYUpgr); - // trackParCov.setY(oldDCAxyValue); - // param[1]=d0zn ; - double trackParDcaZoriginal = trackParCov.getZ(); - trackParCov.setZ(trackParDcaZUpgr); + // double dd0zo =d0zo-d0zmc; + double deltaDcaZ = trackParDcaZRec - trackParDcaZMC; - if (updateCurvature) { - // -------------------------------------- - // double dpt1o =pt1o-pt1mc; - double diffOneOverPtFromMCCurent = trackParOneOverPtCurrent - trackParOneOverPtMC; + // double dd0zn =dd0zo *(sd0zo >0. ? (sd0zn /sd0zo ) : 1.); + double deltaDcaZTuned = deltaDcaZ * (dcaZResMC > 0. ? (dcaZResData / dcaZResMC) : 1.); - // double dpt1n =dpt1o *(spt1o >0. ? (spt1n /spt1o ) : 1.); - double diffOneOverPtFromMCUpgr = diffOneOverPtFromMCCurent * (oneOverPtCurrent > 0. ? (oneOverPtUpgr / oneOverPtCurrent) : 1.); + // double d0zn =d0zmc+dd0zn; + double trackParDcaZTuned = trackParDcaZMC + deltaDcaZTuned; - // double pt1n = pt1mc+dpt1n; - double trackParOneOverPtUpgr = trackParOneOverPtMC + diffOneOverPtFromMCUpgr; + // double dd0rpo=d0rpo-d0rpmc; + double deltaDcaXY = trackParDcaXYRec - trackParDcaXYMC - dcaXYMeanMC; - // param[4]=pt1n ; - trackParCov.setQ2Pt(trackParOneOverPtUpgr); - } - // if(debugInfo){ - // LOG(info) << "Inside tuneTrackParams() before modifying trackParCov.getY(): " << trackParCov.getY() << " trackParOneOverPtMC = " << trackParOneOverPtMC << " diffOneOverPtFromMCUpgr = " << diffOneOverPtFromMCUpgr << std::endl; - //} + // double dd0rpn=dd0rpo*(sd0rpo>0. ? (sd0rpn/sd0rpo) : 1.); + double deltaDcaXYTuned = deltaDcaXY * (dcaXYResMC > 0. ? (dcaXYResData / dcaXYResMC) : 1.); - // Updating Single Track Covariance matrices + // double dd0mrpn=std::abs(sd0mrpn)-std::abs(sd0mrpo); + // double deltaDcaXYmean = std::abs(dcaXYMeanData) - std::abs(dcaXYMeanMC) ; + double deltaDcaXYmean = dcaXYMeanData - dcaXYMeanMC; - double sigmaY2 = 0.0; - double sigmaZY = 0.0; - double sigmaZ2 = 0.0; - double sigmaSnpY = 0.0; - double sigmaSnpZ = 0.0; - double sigmaTglY = 0.0; - double sigmaTglZ = 0.0; - double sigma1PtY = 0.0; - double sigma1PtZ = 0.0; - double sigma1PtSnp = 0.0; - double sigma1PtTgl = 0.0; - double sigma1Pt2 = 0.0; + // double d0rpn =d0rpmc+dd0rpn-dd0mrpn; + double trackParDcaXYTuned = trackParDcaXYMC + deltaDcaXYTuned + deltaDcaXYmean; - double sigmaY2orig = trackParCov.getSigmaY2(); - double sigmaZYorig = trackParCov.getSigmaZY(); - double sigmaZ2orig = trackParCov.getSigmaZ2(); + if (debugInfo) { + LOG(info) << dcaZResMC << ", " << dcaZResData << ", diff(DcaZ - DcaZMC): " << deltaDcaZ << ", diff upgraded: " << deltaDcaZTuned << ", DcaZ Data : " << trackParDcaZTuned; + LOG(info) << dcaXYResMC << ", " << dcaXYResData << ", " << dcaXYMeanMC << ", diff(DcaY - DcaYMC - dcaXYMeanMC): " << deltaDcaXY << ", diff upgraded: " << deltaDcaXYTuned << ", DcaY Data :" << trackParDcaXYTuned; + } + // option mimic data + // ---------------------- + // if(fMimicData){ + // // dd0mrpn=sd0mrpn-sd0mrpo; + // deltaDcaXYmean = dcaXYMeanData - dcaXYMeanMC; + // // d0rpn = d0rpmc+dd0rpn+dd0mrpn; + // trackParDcaXYTuned = deltaDcaXY + deltaDcaXYTuned + deltaDcaXYmean; + // } + + // setting updated track parameters + // -------------------------------- + trackParDcaXYoriginal = trackParCov.getY(); + trackParCov.setY(trackParDcaXYTuned); + trackParDcaZoriginal = trackParCov.getZ(); + trackParCov.setZ(trackParDcaZTuned); + } // ----> updateTrackDCAs block ends here + + if ((updateCurvature) && (!updateCurvatureIU)) { // ...block begins here + if (!updateTrackDCAs) { + /// propagation to production point not done yet, doing it now + o2::base::Propagator::Instance()->propagateToDCABxByBz(vtxMC, trackParCov, 2.f, matCorr, dcaInfoCov); + } + deltaQpt = trackParQPtMCRec - trackParQPtMC; + // double dpt1n =dpt1o *(spt1o >0. ? (spt1n /spt1o ) : 1.); + deltaQptTuned = deltaQpt * (qOverPtMC > 0. ? (qOverPtData / qOverPtMC) : 1.); + // double pt1n = pt1mc+dpt1n; + trackParQPtTuned = trackParQPtMC + deltaQptTuned; + trackParCov.setQ2Pt(trackParQPtTuned); + } // ...block ends here if (updateTrackCovMat) { // if(sd0rpo>0.) covar[0]*=(sd0rpn/sd0rpo)*(sd0rpn/sd0rpo);//yy sigmaY2 = trackParCov.getSigmaY2(); - if (dcaXYResCurrent > 0.) - sigmaY2 *= ((dcaXYResUpgr / dcaXYResCurrent) * (dcaXYResUpgr / dcaXYResCurrent)); - trackParCov.setCov(sigmaY2, 0); + if (dcaXYResMC > 0.) { + sigmaY2 *= ((dcaXYResData / dcaXYResMC) * (dcaXYResData / dcaXYResMC)); + trackParCov.setCov(sigmaY2, 0); + } // if(sd0zo>0. && sd0rpo>0.)covar[1]*=(sd0rpn/sd0rpo)*(sd0zn/sd0zo);//yz sigmaZY = trackParCov.getSigmaZY(); - if (dcaZResCurrent > 0. && dcaXYResCurrent > 0.) - sigmaZY *= ((dcaXYResUpgr / dcaXYResCurrent) * (dcaZResUpgr / dcaZResCurrent)); - trackParCov.setCov(sigmaZY, 1); + if (dcaZResMC > 0. && dcaXYResMC > 0.) { + // sigmaZY *= ((dcaXYResData / dcaXYResMC) * (dcaZResData / dcaZResMC)); + sigmaZY *= ((dcaXYResData / dcaXYResMC) * (dcaZResData / dcaZResMC)); + trackParCov.setCov(sigmaZY, 1); + } // if(sd0zo>0.) covar[2]*=(sd0zn/sd0zo)*(sd0zn/sd0zo);//zz sigmaZ2 = trackParCov.getSigmaZ2(); - if (dcaZResCurrent > 0.) - sigmaZ2 *= ((dcaZResUpgr / dcaZResCurrent) * (dcaZResUpgr / dcaZResCurrent)); - trackParCov.setCov(sigmaZ2, 2); + if (dcaZResMC > 0.) { + sigmaZ2 *= ((dcaZResData / dcaZResMC) * (dcaZResData / dcaZResMC)); + trackParCov.setCov(sigmaZ2, 2); + } // if(sd0rpo>0.) covar[3]*=(sd0rpn/sd0rpo);//yl sigmaSnpY = trackParCov.getSigmaSnpY(); - if (dcaXYResCurrent > 0.) - sigmaSnpY *= ((dcaXYResUpgr / dcaXYResCurrent)); - trackParCov.setCov(sigmaSnpY, 3); + if (dcaXYResMC > 0.) { + sigmaSnpY *= ((dcaXYResData / dcaXYResMC)); + trackParCov.setCov(sigmaSnpY, 3); + } // if(sd0zo>0.) covar[4]*=(sd0zn/sd0zo);//zl sigmaSnpZ = trackParCov.getSigmaSnpZ(); - if (dcaZResCurrent > 0.) - sigmaSnpZ *= ((dcaZResUpgr / dcaZResCurrent)); - trackParCov.setCov(sigmaSnpZ, 4); + if (dcaZResMC > 0.) { + sigmaSnpZ *= ((dcaZResData / dcaZResMC)); + trackParCov.setCov(sigmaSnpZ, 4); + } // if(sd0rpo>0.) covar[6]*=(sd0rpn/sd0rpo);//ysenT sigmaTglY = trackParCov.getSigmaTglY(); - if (dcaXYResCurrent > 0.) - sigmaTglY *= ((dcaXYResUpgr / dcaXYResCurrent)); - trackParCov.setCov(sigmaTglY, 6); + if (dcaXYResMC > 0.) { + sigmaTglY *= ((dcaXYResData / dcaXYResMC)); + trackParCov.setCov(sigmaTglY, 6); + } // if(sd0zo>0.) covar[7]*=(sd0zn/sd0zo);//zsenT sigmaTglZ = trackParCov.getSigmaTglZ(); - if (dcaZResCurrent > 0.) - sigmaTglZ *= ((dcaZResUpgr / dcaZResCurrent)); - trackParCov.setCov(sigmaTglZ, 7); - - // if(sd0rpo>0. && spt1o>0.)covar[10]*=(sd0rpn/sd0rpo)*(spt1n/spt1o);//ypt - sigma1PtY = trackParCov.getSigma1PtY(); - if (dcaXYResCurrent > 0. && oneOverPtCurrent > 0.) - sigma1PtY *= ((dcaXYResUpgr / dcaXYResCurrent) * (oneOverPtUpgr / oneOverPtCurrent)); - trackParCov.setCov(sigma1PtY, 10); - - // if(sd0zo>0. && spt1o>0.) covar[11]*=(sd0zn/sd0zo)*(spt1n/spt1o);//zpt - sigma1PtZ = trackParCov.getSigma1PtZ(); - if (dcaZResCurrent > 0. && oneOverPtCurrent > 0.) - sigma1PtZ *= ((dcaZResUpgr / dcaZResCurrent) * (oneOverPtUpgr / oneOverPtCurrent)); - trackParCov.setCov(sigma1PtZ, 11); - - // if(spt1o>0.) covar[12]*=(spt1n/spt1o);//sinPhipt - sigma1PtSnp = trackParCov.getSigma1PtSnp(); - if (oneOverPtCurrent > 0.) - sigma1PtSnp *= (oneOverPtUpgr / oneOverPtCurrent); - trackParCov.setCov(sigma1PtSnp, 12); - - // if(spt1o>0.) covar[13]*=(spt1n/spt1o);//tanTpt - sigma1PtTgl = trackParCov.getSigma1PtTgl(); - if (oneOverPtCurrent > 0.) - sigma1PtTgl *= (oneOverPtUpgr / oneOverPtCurrent); - trackParCov.setCov(sigma1PtTgl, 13); + if (dcaZResMC > 0.) { + sigmaTglZ *= ((dcaZResData / dcaZResMC)); + trackParCov.setCov(sigmaTglZ, 7); + } - // if(spt1o>0.) covar[14]*=(spt1n/spt1o)*(spt1n/spt1o);//ptpt - sigma1Pt2 = trackParCov.getSigma1Pt2(); - if (oneOverPtCurrent > 0.) - sigma1Pt2 *= (oneOverPtUpgr / oneOverPtCurrent); - trackParCov.setCov(sigma1Pt2, 14); - } + // checking and updating track cov matrix elements for 1/Pt begins + if ((updateCurvature) && (!updateCurvatureIU)) { + // if(sd0rpo>0. && spt1o>0.)covar[10]*=(sd0rpn/sd0rpo)*(spt1n/spt1o);//ypt + sigma1PtY = trackParCov.getSigma1PtY(); + if (dcaXYResMC > 0. && qOverPtMC > 0.) { + sigma1PtY *= ((dcaXYResData / dcaXYResMC) * (qOverPtData / qOverPtMC)); + trackParCov.setCov(sigma1PtY, 10); + } + + // if(sd0zo>0. && spt1o>0.) covar[11]*=(sd0zn/sd0zo)*(spt1n/spt1o);//zpt + sigma1PtZ = trackParCov.getSigma1PtZ(); + if (dcaZResMC > 0. && qOverPtMC > 0.) { + sigma1PtZ *= ((dcaZResData / dcaZResMC) * (qOverPtData / qOverPtMC)); + trackParCov.setCov(sigma1PtZ, 11); + } + + // if(spt1o>0.) covar[12]*=(spt1n/spt1o);//sinPhipt + sigma1PtSnp = trackParCov.getSigma1PtSnp(); + if (qOverPtMC > 0.) { + sigma1PtSnp *= (qOverPtData / qOverPtMC); + trackParCov.setCov(sigma1PtSnp, 12); + } + + // if(spt1o>0.) covar[13]*=(spt1n/spt1o);//tanTpt + sigma1PtTgl = trackParCov.getSigma1PtTgl(); + if (qOverPtMC > 0.) { + sigma1PtTgl *= (qOverPtData / qOverPtMC); + trackParCov.setCov(sigma1PtTgl, 13); + } + + // if(spt1o>0.) covar[14]*=(spt1n/spt1o)*(spt1n/spt1o);//ptpt + sigma1Pt2 = trackParCov.getSigma1Pt2(); + if (qOverPtMC > 0.) { + sigma1Pt2 *= (qOverPtData / qOverPtMC); + trackParCov.setCov(sigma1Pt2, 14); + } + } // ---> track cov matrix elements for 1/Pt ends here + } // ---> updateTrackCovMat block ends here if (updatePulls) { - double ratioDCAxyPulls = dcaXYPullCurrent / dcaXYPullUpgr; - double ratioDCAzPulls = dcaZPullCurrent / dcaZPullUpgr; + double ratioDCAxyPulls = 1.0; + double ratioDCAzPulls = 1.0; + if (dcaZPullData > 0.0) { + ratioDCAzPulls = dcaZPullMC / dcaZPullData; + } + if (dcaXYPullData > 0.0) { + ratioDCAxyPulls = dcaXYPullMC / dcaXYPullData; + } // covar[0]*=pullcorr*pullcorr;//yy - sigmaY2 *= (ratioDCAxyPulls * ratioDCAxyPulls); trackParCov.setCov(sigmaY2, 0); @@ -649,7 +952,7 @@ struct TrackTuner { sigma1PtZ *= ratioDCAzPulls; trackParCov.setCov(sigma1PtZ, 11); - } + } // ---> updatePulls block ends here /// sanity check for track covariance matrix element /// see https://github.com/AliceO2Group/AliceO2/blob/66de30958153cd7badf522150e8554f9fcf975ff/Common/DCAFitter/include/DCAFitter/DCAFitterN.h#L38-L54 @@ -689,7 +992,7 @@ struct TrackTuner { } else { hQA->Fill(2); } - } + } // tuneTrackParams() ends here // to be declared // --------------- @@ -714,7 +1017,7 @@ struct TrackTuner { { if (!graph) { - printf("\tevalGraph fails !\n"); + LOG(fatal) << "\t evalGraph fails !\n"; return 0.; } int nPoints = graph->GetN(); diff --git a/Common/Tools/trackSelectionRequest.cxx b/Common/Tools/trackSelectionRequest.cxx index 088eafab508..ed82f1ff7bf 100644 --- a/Common/Tools/trackSelectionRequest.cxx +++ b/Common/Tools/trackSelectionRequest.cxx @@ -108,6 +108,14 @@ int trackSelectionRequest::getMinTPCCrossedRowsOverFindable() const { return minTPCcrossedrowsoverfindable; } +void trackSelectionRequest::setMaxTPCFractionSharedCls(float maxTPCFractionSharedCls_) +{ + maxTPCFractionSharedCls = maxTPCFractionSharedCls_; +} +int trackSelectionRequest::getMaxTPCFractionSharedCls() const +{ + return maxTPCFractionSharedCls; +} void trackSelectionRequest::setRequireITS(bool requireITS_) { requireITS = requireITS_; @@ -159,6 +167,8 @@ void trackSelectionRequest::CombineWithLogicalOR(trackSelectionRequest const& lT minTPCcrossedrows = lTraSelRe.getMinTPCCrossedRows(); if (lTraSelRe.getMinTPCCrossedRowsOverFindable() < minTPCcrossedrowsoverfindable) minTPCcrossedrowsoverfindable = lTraSelRe.getMinTPCCrossedRowsOverFindable(); + if (lTraSelRe.getMaxTPCFractionSharedCls() > maxTPCFractionSharedCls) + maxTPCFractionSharedCls = lTraSelRe.getMaxTPCFractionSharedCls(); if (lTraSelRe.getRequireITS() == false) requireITS = false; @@ -205,7 +215,9 @@ void trackSelectionRequest::PrintSelections() const LOGF(info, "Minimum TPC clusters ...................: %i", minTPCclusters); LOGF(info, "Minimum TPC crossed rows ...............: %i", minTPCcrossedrows); LOGF(info, "Minimum TPC crossed rows over findable .: %.3f", minTPCcrossedrowsoverfindable); + LOGF(info, "Max Fraction of TPC Shared Clusters ....: %.3f", maxTPCFractionSharedCls); + LOGF(info, "Require ITS ............................: %i", requireITS); LOGF(info, "Minimum ITS clusters ...................: %i", minITSclusters); LOGF(info, "Max ITS chi2/clu ......................: %.3f", maxITSChi2percluster); -} \ No newline at end of file +} diff --git a/Common/Tools/trackSelectionRequest.h b/Common/Tools/trackSelectionRequest.h index 00931491acf..123392611f0 100644 --- a/Common/Tools/trackSelectionRequest.h +++ b/Common/Tools/trackSelectionRequest.h @@ -60,6 +60,8 @@ class trackSelectionRequest int getMinTPCCrossedRows() const; void setMinTPCCrossedRowsOverFindable(float minTPCCrossedRowsOverFindable_); int getMinTPCCrossedRowsOverFindable() const; + void setMaxTPCFractionSharedCls(float maxTPCFractionSharedCls_); + int getMaxTPCFractionSharedCls() const; void setRequireITS(bool requireITS_); bool getRequireITS() const; @@ -97,6 +99,8 @@ class trackSelectionRequest return false; if (lTrack.tpcCrossedRowsOverFindableCls() < minTPCcrossedrowsoverfindable) return false; + if (lTrack.tpcFractionSharedCls() > maxTPCFractionSharedCls) + return false; if (lTrack.hasITS() == false && requireITS) return false; if (lTrack.itsNCls() < minITSclusters) @@ -117,6 +121,8 @@ class trackSelectionRequest return false; if (lTrack.tpcCrossedRowsOverFindableCls() < minTPCcrossedrowsoverfindable) return false; + if (lTrack.tpcFractionSharedCls() > maxTPCFractionSharedCls) + return false; if (lTrack.hasITS() == false && requireITS) return false; if (lTrack.itsNCls() < minITSclusters) @@ -146,6 +152,7 @@ class trackSelectionRequest int minTPCclusters; int minTPCcrossedrows; float minTPCcrossedrowsoverfindable; + float maxTPCFractionSharedCls; // ITS parameters (TracksExtra) bool requireITS; // in Run 3, equiv to hasITS int minITSclusters; diff --git a/DPG/Tasks/AOTEvent/CMakeLists.txt b/DPG/Tasks/AOTEvent/CMakeLists.txt index b536703d0e2..4cf8873a59f 100644 --- a/DPG/Tasks/AOTEvent/CMakeLists.txt +++ b/DPG/Tasks/AOTEvent/CMakeLists.txt @@ -19,7 +19,32 @@ o2physics_add_dpl_workflow(lumi-qa PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2::DetectorsBase COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(mshape-qa - SOURCES mshapeQa.cxx +o2physics_add_dpl_workflow(time-dependent-qa + SOURCES timeDependentQa.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2::DetectorsBase O2::TPCCalibration COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(detector-occupancy-qa + SOURCES detectorOccupancyQa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2::DetectorsBase + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(rof-border-qa + SOURCES rofBorderQa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2::DetectorsBase + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(matching-qa + SOURCES matchingQa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2::DetectorsBase + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(rof-occupancy-qa + SOURCES rofOccupancyQa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2::DetectorsBase + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(occupancy-vs-dedx-qa + SOURCES dEdxVsOccupancyWithTrackQAinfo.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2::DetectorsBase + COMPONENT_NAME Analysis) diff --git a/DPG/Tasks/AOTEvent/dEdxVsOccupancyWithTrackQAinfo.cxx b/DPG/Tasks/AOTEvent/dEdxVsOccupancyWithTrackQAinfo.cxx new file mode 100644 index 00000000000..36af0603ee8 --- /dev/null +++ b/DPG/Tasks/AOTEvent/dEdxVsOccupancyWithTrackQAinfo.cxx @@ -0,0 +1,471 @@ +// 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 dEdxVsOccupancyWithTrackQAinfo.cxx +/// \brief dE/dx vs occupancy QA task with more detailed checks +/// +/// \author Igor Altsybeev + +#include +#include "map" + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "CCDB/BasicCCDBManager.h" +#include "Framework/HistogramRegistry.h" +#include "CommonDataFormat/BunchFilling.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "DataFormatsParameters/AggregatedRunInfo.h" + +#include "TH1F.h" +#include "TH2F.h" +#include "TH3.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::aod::evsel; + +using BCsRun3 = soa::Join; +using ColEvSels = soa::Join; +// using ColEvSels = soa::Join; +using FullTracksIU = soa::Join; + +struct dEdxVsOccupancyWithTrackQAinfoTask { + // configurables for study of occupancy in time windows + // Configurable confAddBasicQAhistos{"AddBasicQAhistos", true, "0 - add basic histograms, 1 - skip"}; // o2-linter: disable=name/configurable (temporary fix) + // Configurable confTimeIntervalForOccupancyCalculation{"TimeIntervalForOccupancyCalculation", 100, "Time interval for TPC occupancy calculation, us"}; // o2-linter: disable=name/configurable (temporary fix) + // Configurable confFlagCentralityIsAvailable{"FlagCentralityIsAvailable", true, "Fill centrality-related historams"}; // o2-linter: disable=name/configurable (temporary fix) + // Configurable confFlagManyHeavyHistos{"FlagManyHeavyHistos", true, "Fill more TH2, TH3, THn historams"}; // o2-linter: disable=name/configurable (temporary fix) + + // event and track cuts for given event + Configurable confCutVertZMinThisEvent{"VzMinThisEvent", -10, "vZ cut for a current event"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confCutVertZMaxThisEvent{"VzMaxThisEvent", 10, "vZ cut for a current event"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confCutPtMinThisEvent{"PtMinThisEvent", 0.2, "pt cut for particles in a current event"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confCutPtMaxThisEvent{"PtMaxThisEvent", 100., "pt cut for particles in a current event"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confCutEtaMinTracksThisEvent{"EtaMinTracksThisEvent", -0.8, "eta cut for particles in a current event"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confCutEtaMaxTracksThisEvent{"EtaMaxTracksThisEvent", 0.8, "eta cut for particles in a current event"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confCutMinTPCcls{"MinNumTPCcls", 70, "min number of TPC clusters for a current event"}; // o2-linter: disable=name/configurable (temporary fix) + + uint64_t minGlobalBC = 0; + Service ccdb; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + bool* applySelection = NULL; + int nBCsPerOrbit = 3564; + int lastRunNumber = -1; + int nOrbits; + double minOrbit; + int64_t bcSOR = 0; // global bc of the start of the first orbit, setting 0 by default for unanchored MC + int64_t nBCsPerTF = 128 * nBCsPerOrbit; // duration of TF in bcs, should be 128*3564 or 32*3564, setting 128 orbits by default sfor unanchored MC + ctpRateFetcher mRateFetcher; + + // save time "slices" for several collisions for QA + bool flagFillQAtimeOccupHist = false; + int nCollisionsForTimeBinQA = 40; + int counterQAtimeOccupHistos = 0; + + void init(InitContext&) + { + // ccdb->setURL("http://ccdb-test.cern.ch:8080"); + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + // dE/dx + AxisSpec axisDeDx{800, 0.0, 800.0, "dE/dx (a. u.)"}; + histos.add("dEdx_vs_Momentum_CORRECTED", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + histos.add("dEdx_vs_Momentum", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + // histos.add("dEdx_vs_Momentum_occupBelow200", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + // histos.add("dEdx_vs_Momentum_occupBelow200_kNoCollStd", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + // histos.add("dEdx_vs_Momentum_occupAbove4000", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + // histos.add("dEdx_vs_Momentum_NegativeFractionNclsPID", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + // histos.add("dEdx_vs_Momentum_HighFractionNclsNonPID", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + AxisSpec axisBinsOccupStudydEdx{{0., 500, 1000, 2000, 4000, 6000, 8000, 15000}, "p_{T}"}; + // histos.add("dEdx_vs_Momentum_vs_occup", "dE/dx", kTH3F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx, axisBinsOccupStudydEdx}); + // if (confFlagManyHeavyHistos) { + // histos.add("dEdx_vs_Momentum_vs_occup_eta_02_04", "dE/dx", kTH3F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx, axisBinsOccupStudydEdx}); + // histos.add("dEdx_vs_Momentum_vs_occup_eta_04_02", "dE/dx", kTH3F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx, axisBinsOccupStudydEdx}); + // } + histos.add("dEdx_3OROC_tot_vs_Momentum_vs_occup_eta_02_04", "dE/dx", kTH3F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx, axisBinsOccupStudydEdx}); + histos.add("dEdx_3OROC_tot_vs_Momentum_vs_occup_eta_04_02", "dE/dx", kTH3F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx, axisBinsOccupStudydEdx}); + histos.add("dEdx_3OROC_max_vs_Momentum_vs_occup_eta_02_04", "dE/dx", kTH3F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx, axisBinsOccupStudydEdx}); + histos.add("dEdx_3OROC_max_vs_Momentum_vs_occup_eta_04_02", "dE/dx", kTH3F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx, axisBinsOccupStudydEdx}); + + // track QA info + histos.add("tpcdEdxMax0R_vs_Momentum", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + histos.add("tpcdEdxMax1R_vs_Momentum", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + histos.add("tpcdEdxMax2R_vs_Momentum", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + histos.add("tpcdEdxMax3R_vs_Momentum", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + + histos.add("tpcdEdxTot0R_vs_Momentum", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + histos.add("tpcdEdxTot1R_vs_Momentum", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + histos.add("tpcdEdxTot2R_vs_Momentum", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + histos.add("tpcdEdxTot3R_vs_Momentum", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + + histos.add("tpcdEdxTot3R_vs_dEdxFromTracks", "dE/dx", kTH2F, {axisDeDx, axisDeDx}); + histos.add("tpcdEdxTotSUM_vs_dEdxFromTracks", "dE/dx", kTH2F, {axisDeDx, axisDeDx}); + histos.add("tpcdEdxMaxSUM_vs_dEdxFromTracks", "dE/dx", kTH2F, {axisDeDx, axisDeDx}); + + histos.add("tpcdEdxAverageMax_vs_dEdxFromTracks", "dE/dx", kTH2F, {axisDeDx, axisDeDx}); + histos.add("tpcdEdxAverageTot_vs_dEdxFromTracks", "dE/dx", kTH2F, {axisDeDx, axisDeDx}); + + histos.add("tpcdEdxAverageMax_3OROC_vs_dEdxFromTracks", "dE/dx", kTH2F, {axisDeDx, axisDeDx}); + histos.add("tpcdEdxAverageTot_3OROC_vs_dEdxFromTracks", "dE/dx", kTH2F, {axisDeDx, axisDeDx}); + + histos.add("tpcdEdxCORRECTED_vs_dEdxFromTracks", "dE/dx", kTH2F, {axisDeDx, axisDeDx}); + + const AxisSpec axisDcaZ{1000, -5., 5., "DCA_{z}, cm"}; + histos.add("dcaXY_vs_dcaXYqa", "dE/dx", kTH2F, {axisDcaZ, {601, -300.5, 300.5, "DCA_{z}, cm"}}); + histos.add("dcaZ_vs_dcaZqa", "dE/dx", kTH2F, {axisDcaZ, {601, -300.5, 300.5, "DCA_{z}, cm"}}); + + AxisSpec axisOccupancyForDeDxStudies{60, 0, 15000, "occupancy"}; + histos.add("dEdx_vs_centr_vs_occup_narrow_p_win", "dE/dx", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisDeDx}); + // histos.add("dEdx_vs_centr_vs_occup_narrow_p_win_pos", "dE/dx", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisDeDx}); + // histos.add("dEdx_vs_centr_vs_occup_narrow_p_win_neg", "dE/dx", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisDeDx}); + // histos.add("dEdx_vs_centr_vs_occup_narrow_p_win_pos_FractionPIDclsInRange", "dE/dx", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisDeDx}); + // histos.add("dEdx_vs_centr_vs_occup_narrow_p_win_neg_FractionPIDclsInRange", "dE/dx", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisDeDx}); + + histos.add("dEdx_3OROC_max_vs_centr_vs_occup_narrow_p_win", "dE/dx", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisDeDx}); + histos.add("dEdx_3OROC_tot_vs_centr_vs_occup_narrow_p_win", "dE/dx", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisDeDx}); + + histos.add("dEdx_vs_centr_vs_occup_narrow_p_win_CORRECTED", "dE/dx", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisDeDx}); + + // AxisSpec axisFractionNclsFindableMinusPID{110, -1.1, 1.1, "TPC nClsFindableMinusPID / nClsFindable"}; + // histos.add("fraction_tpcNClsFindableMinusPID_vs_occup", "", kTH2D, {axisOccupancyForDeDxStudies, axisFractionNclsFindableMinusPID}); + // histos.add("fraction_tpcNClsFindableMinusPID_vs_occup_peripheralByV0A", "", kTH2D, {axisOccupancyForDeDxStudies, axisFractionNclsFindableMinusPID}); + // histos.add("fraction_tpcNClsFindableMinusPID_vs_occup_centralByV0A", "", kTH2D, {axisOccupancyForDeDxStudies, axisFractionNclsFindableMinusPID}); + // histos.add("fraction_tpcNClsFindableMinusPID_vs_occup_eta02", "", kTH2D, {axisOccupancyForDeDxStudies, axisFractionNclsFindableMinusPID}); + // histos.add("fraction_tpcNClsFindableMinusPID_vs_occup_pos", "", kTH2D, {axisOccupancyForDeDxStudies, axisFractionNclsFindableMinusPID}); + // histos.add("fraction_tpcNClsFindableMinusPID_vs_occup_neg", "", kTH2D, {axisOccupancyForDeDxStudies, axisFractionNclsFindableMinusPID}); + // histos.add("fraction_tpcNClsFindableMinusPID_vs_occup_lowPt", "", kTH2D, {axisOccupancyForDeDxStudies, axisFractionNclsFindableMinusPID}); + // histos.add("fraction_tpcNClsFindableMinusPID_vs_occup_highPt", "", kTH2D, {axisOccupancyForDeDxStudies, axisFractionNclsFindableMinusPID}); + + // QA dEdx correction coeff + histos.add("dEdx_CORRECTION_COEFF", "coeff", kTH1F, {{1000, -2.0, 2.0, "correction coeff"}}); + } + + Preslice perCollision = aod::track::collisionId; + + float fReal_fTPCSignalN(float mbb0R1, float a1pt, float atgl, float atglmbb0R1, float a1ptmbb0R1, float side, float a1pt2, float fTrackOccN, float fOccTPCN, float fTrackOccMeanN) + { + return ((0.017012 * mbb0R1) + (-0.0018469 * a1pt) + (-0.0052177 * atgl) + (-0.0035655 * atglmbb0R1) + (0.0017846 * a1ptmbb0R1) + (0.0019127 * side) + (-0.00012964 * a1pt2) + (0.013066)) * fTrackOccN + ((0.0055592 * mbb0R1) + (-0.0010618 * a1pt) + (-0.0016134 * atgl) + (-0.0059098 * atglmbb0R1) + (0.0013335 * a1ptmbb0R1) + (0.00052133 * side) + (3.1119e-05 * a1pt2) + (0.0049428)) * fOccTPCN + ((0.00077317 * mbb0R1) + (-0.0013827 * a1pt) + (0.003249 * atgl) + (-0.00063689 * atglmbb0R1) + (0.0016218 * a1ptmbb0R1) + (-0.00045215 * side) + (-1.5815e-05 * a1pt2) + (-0.004882)) * fTrackOccMeanN + ((-0.015053 * mbb0R1) + (0.0018912 * a1pt) + (-0.012305 * atgl) + (0.081387 * atglmbb0R1) + (0.003205 * a1ptmbb0R1) + (-0.0087404 * side) + (-0.0028608 * a1pt2) + (0.99091)); + }; + void processRun3( + ColEvSels const& cols, + FullTracksIU const& tracks, + BCsRun3 const& bcs, + aod::TracksQA_002 const& tracksQA, + aod::FT0s const&) + { + int runNumber = bcs.iteratorAt(0).runNumber(); + if (runNumber != lastRunNumber) { + lastRunNumber = runNumber; // do it only once + + if (runNumber >= 500000) { + auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), runNumber); + // first bc of the first orbit + bcSOR = runInfo.orbitSOR * o2::constants::lhc::LHCMaxBunches; + // duration of TF in bcs + nBCsPerTF = runInfo.orbitsPerTF * o2::constants::lhc::LHCMaxBunches; + + LOGP(info, "bcSOR = {}, nBCsPerTF = {}", bcSOR, nBCsPerTF); + } + } + + // track QA table + std::vector labelTrack2TrackQA; + labelTrack2TrackQA.clear(); + labelTrack2TrackQA.resize(tracks.size(), -1); + for (const auto& trackQA : tracksQA) { + int64_t trackId = trackQA.trackId(); + int64_t trackQAIndex = trackQA.globalIndex(); + labelTrack2TrackQA[trackId] = trackQAIndex; + } + + for (const auto& col : cols) { + if (!col.sel8()) + continue; + + // check hadronic rate + auto bc = col.foundBC_as(); + int64_t ts = bc.timestamp(); + double hadronicRate = mRateFetcher.fetch(ccdb.service, ts, runNumber, "ZNC hadronic") * 1.e-3; // kHz + const int multTPC = col.multTPC(); + + int occupancy = col.trackOccupancyInTimeRange(); + + auto tracksGrouped = tracks.sliceBy(perCollision, col.globalIndex()); + + // pre-calc nPV + int nPV = 0; + for (const auto& track : tracksGrouped) { + if (!track.isPVContributor()) + continue; + if (track.pt() < confCutPtMinThisEvent || track.pt() > confCutPtMaxThisEvent) + continue; + if (track.eta() < confCutEtaMinTracksThisEvent || track.eta() > confCutEtaMaxTracksThisEvent) + continue; + if (track.itsNCls() < 5) + continue; + nPV++; + } + + // main track loop + for (const auto& track : tracksGrouped) { + if (!track.isPVContributor()) + continue; + if (track.pt() < confCutPtMinThisEvent || track.pt() > confCutPtMaxThisEvent) + continue; + if (track.eta() < confCutEtaMinTracksThisEvent || track.eta() > confCutEtaMaxTracksThisEvent) + continue; + if (track.itsNCls() < 5) + continue; + if (!track.isGlobalTrack()) + continue; + if (track.tpcNClsFound() < confCutMinTPCcls) + continue; + + float signedP = track.sign() * track.tpcInnerParam(); + + aod::TracksQA_002::iterator trackQA; + // bool existPosTrkQA; + if (labelTrack2TrackQA[track.globalIndex()] != -1) { + trackQA = tracksQA.iteratorAt(labelTrack2TrackQA[track.globalIndex()]); + // existPosTrkQA = true; + + float signedP = track.sign() * track.tpcInnerParam(); + float dEdx = track.tpcSignal(); + + float tpcdEdxMax0Rabs = trackQA.tpcdEdxMax0R() * dEdx / 100; + float tpcdEdxMax1Rabs = trackQA.tpcdEdxMax1R() * dEdx / 100; + float tpcdEdxMax2Rabs = trackQA.tpcdEdxMax2R() * dEdx / 100; + float tpcdEdxMax3Rabs = trackQA.tpcdEdxMax3R() * dEdx / 100; + + float tpcdEdxTot0Rabs = trackQA.tpcdEdxTot0R() * dEdx / 100; + float tpcdEdxTot1Rabs = trackQA.tpcdEdxTot1R() * dEdx / 100; + float tpcdEdxTot2Rabs = trackQA.tpcdEdxTot2R() * dEdx / 100; + float tpcdEdxTot3Rabs = trackQA.tpcdEdxTot3R() * dEdx / 100; + + histos.fill(HIST("tpcdEdxMax0R_vs_Momentum"), signedP, tpcdEdxMax0Rabs); + histos.fill(HIST("tpcdEdxMax1R_vs_Momentum"), signedP, tpcdEdxMax1Rabs); + histos.fill(HIST("tpcdEdxMax2R_vs_Momentum"), signedP, tpcdEdxMax2Rabs); + histos.fill(HIST("tpcdEdxMax3R_vs_Momentum"), signedP, tpcdEdxMax3Rabs); + + histos.fill(HIST("tpcdEdxTot0R_vs_Momentum"), signedP, tpcdEdxTot0Rabs); + histos.fill(HIST("tpcdEdxTot1R_vs_Momentum"), signedP, tpcdEdxTot1Rabs); + histos.fill(HIST("tpcdEdxTot2R_vs_Momentum"), signedP, tpcdEdxTot2Rabs); + histos.fill(HIST("tpcdEdxTot3R_vs_Momentum"), signedP, tpcdEdxTot3Rabs); + + // FROM: https://github.com/AliceO2Group/AliceO2/blob/d4afff4276fae2d31f6c3c79d9ec4246deff95f8/Detectors/AOD/src/AODProducerWorkflowSpec.cxx#L2628C1-L2629C84 + // const float dEdxNorm = (tpcOrig.getdEdx().dEdxTotTPC > 0) ? 100. / tpcOrig.getdEdx().dEdxTotTPC : 0; + // trackQAHolder.tpcdEdxMax0R = uint8_t(tpcOrig.getdEdx().dEdxMaxIROC * dEdxNorm); + histos.fill(HIST("tpcdEdxTot3R_vs_dEdxFromTracks"), track.tpcSignal(), trackQA.tpcdEdxTot3R() * dEdx / 100); + histos.fill(HIST("tpcdEdxTotSUM_vs_dEdxFromTracks"), track.tpcSignal(), tpcdEdxTot0Rabs + tpcdEdxTot1Rabs + tpcdEdxTot2Rabs + tpcdEdxTot3Rabs); + histos.fill(HIST("tpcdEdxMaxSUM_vs_dEdxFromTracks"), track.tpcSignal(), tpcdEdxMax0Rabs + tpcdEdxMax1Rabs + tpcdEdxMax2Rabs + tpcdEdxMax3Rabs); + + // ### dEdx MAX + if (1) { + float sum_dEdx_max = 0; + int counter_has_dEdx_max = 0; + if (tpcdEdxMax1Rabs > 0) { + sum_dEdx_max += tpcdEdxMax1Rabs; + counter_has_dEdx_max++; + } + if (tpcdEdxMax2Rabs > 0) { + sum_dEdx_max += tpcdEdxMax2Rabs; + counter_has_dEdx_max++; + } + if (tpcdEdxMax3Rabs > 0) { + sum_dEdx_max += tpcdEdxMax3Rabs; + counter_has_dEdx_max++; + } + // only 3 OROC: + float sum_3OROC_dEdx_max = sum_dEdx_max; + int counter_3OROC_has_dEdx_max = counter_has_dEdx_max; + if (counter_3OROC_has_dEdx_max > 0) { + sum_3OROC_dEdx_max /= counter_3OROC_has_dEdx_max; + histos.fill(HIST("tpcdEdxAverageMax_3OROC_vs_dEdxFromTracks"), track.tpcSignal(), sum_3OROC_dEdx_max); + } + // now IROC: + if (tpcdEdxMax0Rabs > 0) { + sum_dEdx_max += tpcdEdxMax0Rabs; + counter_has_dEdx_max++; + } + // average and fill histos + if (counter_has_dEdx_max > 0) { + sum_dEdx_max /= counter_has_dEdx_max; + histos.fill(HIST("tpcdEdxAverageMax_vs_dEdxFromTracks"), track.tpcSignal(), sum_dEdx_max); + } + if (occupancy >= 0) { + if (std::fabs(signedP) > 0.38 && std::fabs(signedP) < 0.4) + histos.fill(HIST("dEdx_3OROC_max_vs_centr_vs_occup_narrow_p_win"), nPV, occupancy, sum_dEdx_max); + + if (track.eta() > 0.2 && track.eta() < 0.4) + histos.fill(HIST("dEdx_3OROC_max_vs_Momentum_vs_occup_eta_02_04"), signedP, sum_dEdx_max, occupancy); + if (track.eta() > -0.4 && track.eta() < -0.2) + histos.fill(HIST("dEdx_3OROC_max_vs_Momentum_vs_occup_eta_04_02"), signedP, sum_dEdx_max, occupancy); + } + } + // ### dEdx TOT + if (1) { + float sum_dEdx_tot = 0; + int counter_has_dEdx_tot = 0; + if (tpcdEdxTot1Rabs > 0) { + sum_dEdx_tot += tpcdEdxTot1Rabs; + counter_has_dEdx_tot++; + } + if (tpcdEdxTot2Rabs > 0) { + sum_dEdx_tot += tpcdEdxTot2Rabs; + counter_has_dEdx_tot++; + } + if (tpcdEdxTot3Rabs > 0) { + sum_dEdx_tot += tpcdEdxTot3Rabs; + counter_has_dEdx_tot++; + } + // only 3 OROC: + float sum_3OROC_dEdx_tot = sum_dEdx_tot; + int counter_3OROC_has_dEdx_tot = counter_has_dEdx_tot; + if (counter_3OROC_has_dEdx_tot > 0) { + sum_3OROC_dEdx_tot /= counter_3OROC_has_dEdx_tot; + histos.fill(HIST("tpcdEdxAverageTot_3OROC_vs_dEdxFromTracks"), track.tpcSignal(), sum_3OROC_dEdx_tot); + } + // now IROC: + if (tpcdEdxTot0Rabs > 0) { + sum_dEdx_tot += tpcdEdxTot0Rabs; + counter_has_dEdx_tot++; + } + // average and fill histos + if (counter_has_dEdx_tot > 0) { + sum_dEdx_tot /= counter_has_dEdx_tot; + histos.fill(HIST("tpcdEdxAverageTot_vs_dEdxFromTracks"), track.tpcSignal(), sum_dEdx_tot); + } + + if (occupancy >= 0) { + if (std::fabs(signedP) > 0.38 && std::fabs(signedP) < 0.4) + histos.fill(HIST("dEdx_3OROC_tot_vs_centr_vs_occup_narrow_p_win"), nPV, occupancy, sum_dEdx_tot); + + if (track.eta() > 0.2 && track.eta() < 0.4) + histos.fill(HIST("dEdx_3OROC_tot_vs_Momentum_vs_occup_eta_02_04"), signedP, sum_dEdx_tot, occupancy); + if (track.eta() > -0.4 && track.eta() < -0.2) + histos.fill(HIST("dEdx_3OROC_tot_vs_Momentum_vs_occup_eta_04_02"), signedP, sum_dEdx_tot, occupancy); + } + } + + histos.fill(HIST("dcaXY_vs_dcaXYqa"), track.dcaXY(), trackQA.tpcdcaR()); + histos.fill(HIST("dcaZ_vs_dcaZqa"), track.dcaZ(), trackQA.tpcdcaZ()); + } + // else { + // existPosTrkQA = false; + // } + + // ### dE/dx by Marian: + float fTPCSignal = track.tpcSignal(); + float fNormMultTPC = multTPC / 11000.; // IA: my guess: it's https://github.com/AliceO2Group/O2Physics/blob/f681d9cc71214c4eb5613a3f473cbea41e48a61f/DPG/Tasks/TPC/tpcSkimsTableCreator.cxx#L575C30-L575C47 + + // df["mdEdx"]=(50/df["fTPCSignal"]).clip(0.05,1.1) + // df["fTPCSignalN"]=(df["fTPCSignal"]/df["bb0"]/50.).clip(0.5,1.5) + // df["fTrackOccN"]=df.eval("fTrackOcc/1000.") + // df["mdEdxExp"]=df.eval("1./bb0") + // df["fFt0OccN"]=df["fFt0Occ"]*df.eval("fFt0Occ/fTrackOcc").median() + // df["mdEdxExpOcc"]=df.eval("mdEdxExp*fTrackOccN") + // df["fTrackOccMeanN"]=(df["fHadronicRate"]/5) # normalization 5 - 10 bins + // df["fTrackOccN2"]=df.eval("fTrackOccN*fTrackOccN") + // df["fOccTPCN"]=(df["fNormMultTPC"]*10).clip(0,12) # normalization 10 - 12 bins + // df["mdEdxOccTPCN"]=df.eval("mdEdx*fOccTPCN") + // df["mdEdxMeanOccTPCN"]=df.eval("mdEdx*fTrackOccMeanN") + + float fTrackOccN = occupancy / 1000.; + float fOccTPCN = fNormMultTPC * 10; //(fNormMultTPC*10).clip(0,12) + if (fOccTPCN > 12) + fOccTPCN = 12; + else if (fOccTPCN < 0) + fOccTPCN = 0; + + float fTrackOccMeanN = hadronicRate / 5; + + float side = track.tgl() > 0 ? 1 : 0; + float a1pt = std::abs(track.signed1Pt()); + float a1pt2 = a1pt * a1pt; + float atgl = std::abs(track.tgl()); + float mbb0R = 50 / fTPCSignal; + if (mbb0R > 1.05) + mbb0R = 1.05; + else if (mbb0R < 0.05) + mbb0R = 0.05; + // float mbb0R = max(0.05, min(50 / fTPCSignal, 1.05)); + float a1ptmbb0R = a1pt * mbb0R; + float atglmbb0R = atgl * mbb0R; + + // tree->SetAlias("side","fTgl>0"); + // tree->SetAlias("a1pt","abs(fSigned1Pt)"); + // tree->SetAlias("a1pt2","abs(fSigned1Pt**2)"); + // tree->SetAlias("atgl","abs(fTgl)"); + // tree->SetAlias("mbb0R","max(0.05,min(50/fTPCSignal,1.05))"); + // tree->SetAlias("a1ptmbb0R","a1pt*mbb0R"); + // tree->SetAlias("atglmbb0R","atgl*mbb0R"); + + // ### iteration 1 correction + // float fTPCSignalN_CBB = fReal_fTPCSignalN(mbb0,a1pt,atgl,atglmbb0,a1ptmbb0,side,a1pt2,fTrackOccN,fOccTPCN,fTrackOccMeanN+0); // atglmbb0 is != atglmbb0R!!! etc. + float fTPCSignalN_CR0 = fReal_fTPCSignalN(mbb0R, a1pt, atgl, atglmbb0R, a1ptmbb0R, side, a1pt2, fTrackOccN, fOccTPCN, fTrackOccMeanN + 0); + + // tree->SetAlias("fTPCSignalN_CBB","fReal_fTPCSignalN(mbb0,a1pt,atgl,atglmbb0,a1ptmbb0,side,a1pt2,fTrackOccN,fOccTPCN,fTrackOccMeanN+0)"); + // tree->SetAlias("fTPCSignalN_CR0","fReal_fTPCSignalN(mbb0R,a1pt,atgl,atglmbb0R,a1ptmbb0R,side,a1pt2,fTrackOccN,fOccTPCN,fTrackOccMeanN+0)"); + + float mbb0R1 = 50 / (fTPCSignal / fTPCSignalN_CR0); + if (mbb0R1 > 1.05) + mbb0R1 = 1.05; + else if (mbb0R1 < 0.05) + mbb0R1 = 0.05; + // float mbb0R1 = max(0.05, min(50 / (fTPCSignal / fTPCSignalN_CR0), 1.05 + 0)); + // tree->SetAlias("mbb0R1","max(0.05,min(50/(fTPCSignal/fTPCSignalN_CR0),1.05+0))"); + float fTPCSignalN_CR1 = fReal_fTPCSignalN(mbb0R1, a1pt, atgl, atgl * mbb0R1, a1pt * mbb0R1, side, a1pt2, fTrackOccN, fOccTPCN, fTrackOccMeanN + 0); + // tree->SetAlias("fTPCSignalN_CR1","fReal_fTPCSignalN(mbb0R1,a1pt,atgl,atgl*mbb0R1,a1pt*mbb0R1,side,a1pt2,fTrackOccN,fOccTPCN,fTrackOccMeanN+0)"); + // + // tree->SetAlias("fTPCSignalN_mad_BB","fReal_fTPCSignalN_mad(mbb0,a1pt,atgl,atglmbb0,a1ptmbb0,side,a1pt2,fTrackOccN,fOccTPCN,fTrackOccMeanN+0)"); + // tree->SetAlias("fTPCSignalN_mad_R0","fReal_fTPCSignalN_mad(mbb0R1,a1pt,atgl,atgl*mbb0R1,a1pt*mbb0R1,side,a1pt2,fTrackOccN,fOccTPCN,fTrackOccMeanN+0)"); + // + // tree->SetAlias("fTPCSignal_CorrR1","fTPCSignal/fTPCSignalN_CR1"); + // tree->SetAlias("fTPCSignal_CorrBB","fTPCSignal/fTPCSignalN_CBB"); + + histos.fill(HIST("dEdx_vs_Momentum"), signedP, fTPCSignal); + + float corrected_dEdx = fTPCSignal / fTPCSignalN_CR1; + histos.fill(HIST("dEdx_CORRECTION_COEFF"), fTPCSignalN_CR1); + histos.fill(HIST("dEdx_vs_Momentum_CORRECTED"), signedP, corrected_dEdx); + histos.fill(HIST("tpcdEdxCORRECTED_vs_dEdxFromTracks"), fTPCSignal, corrected_dEdx); + + if (occupancy >= 0) { + if (std::fabs(signedP) > 0.38 && std::fabs(signedP) < 0.4) { + histos.fill(HIST("dEdx_vs_centr_vs_occup_narrow_p_win"), nPV, occupancy, fTPCSignal); + histos.fill(HIST("dEdx_vs_centr_vs_occup_narrow_p_win_CORRECTED"), nPV, occupancy, corrected_dEdx); + } + } + + } // end of track loop + } // end of collision loop + } + PROCESS_SWITCH(dEdxVsOccupancyWithTrackQAinfoTask, processRun3, "Process Run3 tracking vs detector occupancy QA", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/DPG/Tasks/AOTEvent/detectorOccupancyQa.cxx b/DPG/Tasks/AOTEvent/detectorOccupancyQa.cxx new file mode 100644 index 00000000000..e3160ab87ac --- /dev/null +++ b/DPG/Tasks/AOTEvent/detectorOccupancyQa.cxx @@ -0,0 +1,1253 @@ +// 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 detectorOccupancyQa.cxx +/// \brief Occupancy QA task +/// +/// \author Igor Altsybeev + +#include +#include "map" + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "CCDB/BasicCCDBManager.h" +#include "Framework/HistogramRegistry.h" +#include "CommonDataFormat/BunchFilling.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "DataFormatsParameters/AggregatedRunInfo.h" + +#include "TH1F.h" +#include "TH2F.h" +#include "TH3.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::aod::evsel; + +// using BCsRun2 = soa::Join; +using BCsRun3 = soa::Join; +// using ColEvSels = soa::Join; +using ColEvSels = soa::Join; +// using FullTracksIU = soa::Join; +using FullTracksIU = soa::Join; + +struct DetectorOccupancyQaTask { + // configurables for study of occupancy in time windows + Configurable confAddBasicQAhistos{"AddBasicQAhistos", true, "0 - add basic histograms, 1 - skip"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confTimeIntervalForOccupancyCalculation{"TimeIntervalForOccupancyCalculation", 100, "Time interval for TPC occupancy calculation, us"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confOccupancyHistCoeffNtracksForOccupancy{"HistCoeffNtracksForOccupancy", 1., "Coefficient for max nTracks in occupancy histos"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confOccupancyHistCoeffNbins2D{"HistCoeffNbins2D", 1., "Coefficient for nBins in occupancy 2D histos"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confOccupancyHistCoeffNbins3D{"HistCoeffNbins3D", 1., "Coefficient for nBins in occupancy 3D histos"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confCoeffMaxNtracksThisEvent{"CoeffMaxNtracksThisEvent", 1., "Coefficient for max nTracks or FT0 ampl in histos in a given event"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confFlagApplyROFborderCut{"ApplyROFborderCut", true, "Use ROF border cut for a current event"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confFlagApplyTFborderCut{"ApplyTFborderCut", true, "Use TF border cut for a current event"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confFlagWhichTimeRange{"FlagWhichTimeRange", 0, "Whicn time range for occupancy calculation: 0 - symmetric, 1 - only past, 2 - only future"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confFlagUseGlobalTracks{"FlagUseGlobalTracks", false, "For small time bins, use global tracks counter instead of ITSTPC tracks"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confFlagUseNoCollInRofStrict{"FlagUseNoCollInRofStrict", false, "Suppress same-ROF events for occupancy historams"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confFlagUseNoHighMultCollInPrevRof{"FlagUseNoHighMultCollInPrevRof", false, "Suppress high-multiplicity prev-ROF events for occupancy historams"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confFlagCentralityIsAvailable{"FlagCentralityIsAvailable", true, "Fill centrality-related historams"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confFlagManyHeavyHistos{"FlagManyHeavyHistos", true, "Fill more TH2, TH3, THn historams"}; // o2-linter: disable=name/configurable (temporary fix) + + // configuration for small time binning + Configurable confTimeIntervalForSmallBins{"TimeIntervalForSmallBins", 100, "Time interval for TPC occupancy calculation in small bins, +/-, us"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confNumberOfSmallTimeBins{"nSmallTimeBins", 40, "Number of small time bins"}; // o2-linter: disable=name/configurable (temporary fix) + + // event and track cuts for given event + Configurable confCutVertZMinThisEvent{"VzMinThisEvent", -10, "vZ cut for a current event"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confCutVertZMaxThisEvent{"VzMaxThisEvent", 10, "vZ cut for a current event"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confCutPtMinThisEvent{"PtMinThisEvent", 0.2, "pt cut for particles in a current event"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confCutPtMaxThisEvent{"PtMaxThisEvent", 100., "pt cut for particles in a current event"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confCutEtaMinTracksThisEvent{"EtaMinTracksThisEvent", -0.8, "eta cut for particles in a current event"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confCutEtaMaxTracksThisEvent{"EtaMaxTracksThisEvent", 0.8, "eta cut for particles in a current event"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confCutMinTPCcls{"MinNumTPCcls", 70, "min number of TPC clusters for a current event"}; // o2-linter: disable=name/configurable (temporary fix) + + // config for QA histograms + Configurable confAddTracksVsFwdHistos{"AddTracksVsFwdHistos", true, "0 - add histograms, 1 - skip"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable nBinsTracks{"nBinsTracks", 400, "N bins in n tracks histo"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable nMaxTracks{"nMaxTracks", 8000, "N max in n tracks histo"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable nMaxGlobalTracks{"nMaxGlobalTracks", 3000, "N max in n tracks histo"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable nBinsMultFwd{"nBinsMultFwd", 400, "N bins in mult fwd histo"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable nMaxMultFwd{"nMaxMultFwd", 200000, "N max in mult fwd histo"}; // o2-linter: disable=name/configurable (temporary fix) + + Configurable nBinsOccupancy{"nBinsOccupancy", 150, "N bins for occupancy axis"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable nMaxOccupancy{"nMaxOccupancy", 15000, "N for max of the occupancy axis"}; // o2-linter: disable=name/configurable (temporary fix) + + Configurable nMaxBcInTFforAnalysis{"nMaxBcInTFforAnalysis", -1, "When to stop taking collisions in TF, if -1: take all collisions"}; // o2-linter: disable=name/configurable (temporary fix) + + uint64_t minGlobalBC = 0; + Service ccdb; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + bool* applySelection = NULL; + int nBCsPerOrbit = 3564; + int lastRunNumber = -1; + int nOrbits; + double minOrbit; + int64_t bcSOR = 0; // global bc of the start of the first orbit, setting 0 by default for unanchored MC + int64_t nBCsPerTF = 128 * nBCsPerOrbit; // duration of TF in bcs, should be 128*3564 or 32*3564, setting 128 orbits by default sfor unanchored MC + + // save time "slices" for several collisions for QA + bool flagFillQAtimeOccupHist = false; + int nCollisionsForTimeBinQA = 40; + int counterQAtimeOccupHistos = 0; + + void init(InitContext&) + { + // ccdb->setURL("http://ccdb-test.cern.ch:8080"); + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + const AxisSpec axisBCinTF{static_cast(nBCsPerTF), 0, static_cast(nBCsPerTF), "bc in TF"}; + histos.add("hNcolVsBcInTF", ";bc in TF; n collisions", kTH1F, {axisBCinTF}); + histos.add("hNcolVsBcInTFafterMaxBcCut", ";bc in TF; n collisions", kTH1F, {axisBCinTF}); + + // histograms for occupancy-in-time-window study + double kMaxOccup = confOccupancyHistCoeffNtracksForOccupancy; + double kMaxThisEv = confCoeffMaxNtracksThisEvent; + + // 1D, dE/dx, etc. + if (confAddBasicQAhistos) { + int nMax1D = kMaxThisEv * 8000; + histos.add("hNumITS567tracksPerCollision", ";n tracks;n events", kTH1D, {{nMax1D, -0.5, nMax1D - 0.5}}); + histos.add("hNumITS567tracksPerCollisionSel", ";n tracks;n events", kTH1D, {{nMax1D, -0.5, nMax1D - 0.5}}); + histos.add("hNumITSTPCtracksPerCollision", ";n tracks;n events", kTH1D, {{nMax1D, -0.5, nMax1D - 0.5}}); + histos.add("hNumITSTPCtracksPerCollisionSel", ";n tracks;n events", kTH1D, {{nMax1D, -0.5, nMax1D - 0.5}}); + + histos.add("hNumITS567tracksInTimeWindow", ";n tracks;n events", kTH1D, {{2500, -0.5, 25000.5}}); + histos.add("hNumITSTPCtracksInTimeWindow", ";n tracks;n events", kTH1D, {{2500, -0.5, 25000.5}}); + histos.add("hNumITS567tracksInTimeWindowSel", ";n tracks;n events", kTH1D, {{2500, -0.5, 25000.5}}); + histos.add("hNumITSTPCtracksInTimeWindowSel", ";n tracks;n events", kTH1D, {{2500, -0.5, 25000.5}}); + + histos.add("hNumCollInTimeWindow", ";n collisions;n events", kTH1D, {{201, -0.5, 200.5}}); + histos.add("hNumCollInTimeWindowSel", ";n collisions;n events", kTH1D, {{201, -0.5, 200.5}}); + histos.add("hNumCollInTimeWindowSelITSTPC", ";n collisions;n events", kTH1D, {{201, -0.5, 200.5}}); + histos.add("hNumCollInTimeWindowSelIfTOF", ";n collisions;n events", kTH1D, {{201, -0.5, 200.5}}); + histos.add("hNumCollInTimeWindowVsOrbit", ";orbit id;n collisions;n events", kTH2F, {{128, -0.5, 127.5}, {201, -0.5, 200.5}}); + + histos.add("hNumUniqueBCInTimeWindow", ";n collisions;n events", kTH1D, {{201, -0.5, 200.5}}); + + // track QA counters + histos.add("nTrackCounter_after_cuts_QA", "", kTH1D, {{12, -0.5, 11.5, "track QA"}}); + TAxis* axTrackCounters = reinterpret_cast(histos.get(HIST("nTrackCounter_after_cuts_QA"))->GetXaxis()); + axTrackCounters->SetBinLabel(1, "all"); + axTrackCounters->SetBinLabel(2, "PVcontrib"); + axTrackCounters->SetBinLabel(3, "ptCut"); + axTrackCounters->SetBinLabel(4, "etaCut"); + axTrackCounters->SetBinLabel(5, "itsNCls>=5"); + axTrackCounters->SetBinLabel(6, "isGlobal,nTPCcls>=70"); + axTrackCounters->SetBinLabel(7, "passedTPCRefit"); + axTrackCounters->SetBinLabel(8, "occupancy>=0"); + axTrackCounters->SetBinLabel(9, "fracton nClsNoPID (0,0.8)"); + axTrackCounters->SetBinLabel(10, "pos"); + axTrackCounters->SetBinLabel(11, "neg"); + + // dE/dx + AxisSpec axisDeDx{800, 0.0, 800.0, "dE/dx (a. u.)"}; + histos.add("dEdx_vs_Momentum", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + histos.add("dEdx_vs_Momentum_occupBelow200", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + histos.add("dEdx_vs_Momentum_occupBelow200_kNoCollStd", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + histos.add("dEdx_vs_Momentum_occupAbove4000", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + histos.add("dEdx_vs_Momentum_NegativeFractionNclsPID", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + histos.add("dEdx_vs_Momentum_HighFractionNclsNonPID", "dE/dx", kTH2F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx}); + AxisSpec axisBinsOccupStudydEdx{{0., 500, 1000, 2000, 4000, 6000, 8000, 15000}, "p_{T}"}; + histos.add("dEdx_vs_Momentum_vs_occup", "dE/dx", kTH3F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx, axisBinsOccupStudydEdx}); + if (confFlagManyHeavyHistos) { + histos.add("dEdx_vs_Momentum_vs_occup_eta_02_04", "dE/dx", kTH3F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx, axisBinsOccupStudydEdx}); + histos.add("dEdx_vs_Momentum_vs_occup_eta_04_02", "dE/dx", kTH3F, {{1000, -5.0, 5.0, "#it{p}/Z (GeV/c)"}, axisDeDx, axisBinsOccupStudydEdx}); + } + + AxisSpec axisOccupancyForDeDxStudies{60, 0, 15000, "occupancy"}; + histos.add("dEdx_vs_centr_vs_occup_narrow_p_win", "dE/dx", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisDeDx}); + histos.add("dEdx_vs_centr_vs_occup_narrow_p_win_pos", "dE/dx", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisDeDx}); + histos.add("dEdx_vs_centr_vs_occup_narrow_p_win_neg", "dE/dx", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisDeDx}); + histos.add("dEdx_vs_centr_vs_occup_narrow_p_win_pos_FractionPIDclsInRange", "dE/dx", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisDeDx}); + histos.add("dEdx_vs_centr_vs_occup_narrow_p_win_neg_FractionPIDclsInRange", "dE/dx", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisDeDx}); + + AxisSpec axisFractionNclsFindableMinusPID{110, -1.1, 1.1, "TPC nClsFindableMinusPID / nClsFindable"}; + histos.add("fraction_tpcNClsFindableMinusPID_vs_occup", "", kTH2D, {axisOccupancyForDeDxStudies, axisFractionNclsFindableMinusPID}); + histos.add("fraction_tpcNClsFindableMinusPID_vs_occup_peripheralByV0A", "", kTH2D, {axisOccupancyForDeDxStudies, axisFractionNclsFindableMinusPID}); + histos.add("fraction_tpcNClsFindableMinusPID_vs_occup_centralByV0A", "", kTH2D, {axisOccupancyForDeDxStudies, axisFractionNclsFindableMinusPID}); + histos.add("fraction_tpcNClsFindableMinusPID_vs_occup_eta02", "", kTH2D, {axisOccupancyForDeDxStudies, axisFractionNclsFindableMinusPID}); + histos.add("fraction_tpcNClsFindableMinusPID_vs_occup_pos", "", kTH2D, {axisOccupancyForDeDxStudies, axisFractionNclsFindableMinusPID}); + histos.add("fraction_tpcNClsFindableMinusPID_vs_occup_neg", "", kTH2D, {axisOccupancyForDeDxStudies, axisFractionNclsFindableMinusPID}); + histos.add("fraction_tpcNClsFindableMinusPID_vs_occup_lowPt", "", kTH2D, {axisOccupancyForDeDxStudies, axisFractionNclsFindableMinusPID}); + histos.add("fraction_tpcNClsFindableMinusPID_vs_occup_highPt", "", kTH2D, {axisOccupancyForDeDxStudies, axisFractionNclsFindableMinusPID}); + + // more QA for TPC cls counting + histos.add("tpcNClsFindable", "", kTH1D, {{601, -300.5, 300.5}}); + histos.add("tpcNClsFindableMinusFound", "", kTH1D, {{601, -300.5, 300.5}}); + histos.add("tpcNClsFindableMinusCrossedRows", "", kTH1D, {{601, -300.5, 300.5}}); + histos.add("tpcNClsShared", "", kTH1D, {{601, -300.5, 300.5}}); + histos.add("tpcNClsFindableMinusPID", "", kTH1D, {{601, -300.5, 300.5}}); + histos.add("tpcNClUsedForPID", "", kTH1D, {{601, -300.5, 300.5}}); + histos.add("tpcNClsFound", "", kTH1D, {{601, -300.5, 300.5}}); + histos.add("tpcNClsFoundAsDiffByHand", "", kTH1D, {{601, -300.5, 300.5}}); + histos.add("tpcNClsFindableMinusPID_CORRECTED", "", kTH1D, {{601, -300.5, 300.5}}); + histos.add("tpcNClsFoundMinusPID_BY_HAND", "", kTH1D, {{601, -300.5, 300.5}}); + + histos.add("tpcNClsUsedForPID_vs_Findable", ";tpcNClsFindable;tpcNClUsedForPID", kTH2D, {{601, -300.5, 300.5}, {601, -300.5, 300.5}}); + histos.add("tpcNClsUsedForPID_vs_Findable_CORRECTED", ";tpcNClsFindable;tpcNClUsedForPID", kTH2D, {{601, -300.5, 300.5}, {601, -300.5, 300.5}}); + histos.add("tpcNClsShared_vs_Findable", ";tpcNClsFindable;tpcNClsShared", kTH2D, {{601, -300.5, 300.5}, {601, -300.5, 300.5}}); + histos.add("tpcNClsFound_vs_Findable", ";tpcNClsFindable;tpcNClsFound", kTH2D, {{601, -300.5, 300.5}, {601, -300.5, 300.5}}); + histos.add("tpcNClsUsedForPID_vs_Shared", ";tpcNClsShared;tpcNClUsedForPID", kTH2D, {{601, -300.5, 300.5}, {601, -300.5, 300.5}}); + histos.add("tpcNClsUsedForPID_vs_Found", ";tpcNClsFound;tpcNClUsedForPID", kTH2D, {{601, -300.5, 300.5}, {601, -300.5, 300.5}}); + + // ### kinematic distributions for events with high occupancy at specified dt ranges + histos.add("track_distr_nITStrThisEv_10_200/hEventCount", ";delta-time bin id;n events", kTH1D, {{5, -0.5, 4.5}}); + histos.add("track_distr_nITStrThisEv_above_2000/hEventCount", ";delta-time bin id;n events", kTH1D, {{5, -0.5, 4.5}}); + + const int nEtaBins = 800; + histos.add("track_distr_nITStrThisEv_10_200/hEta_lowOccupInTPC", ";#eta;n tracks", kTH1D, {{nEtaBins, -1.0, 1.0}}); + histos.add("track_distr_nITStrThisEv_10_200/hEta_highOccupInRecentPast", ";#eta;n tracks", kTH1D, {{nEtaBins, -1.0, 1.0}}); + histos.add("track_distr_nITStrThisEv_10_200/hEta_highOccupInCloseFuture", ";#eta;n tracks", kTH1D, {{nEtaBins, -1.0, 1.0}}); + histos.add("track_distr_nITStrThisEv_10_200/hEta_highOccupInDistantFuture", ";#eta;n tracks", kTH1D, {{nEtaBins, -1.0, 1.0}}); + histos.add("track_distr_nITStrThisEv_10_200/hEta_highOccupInNeighbourEvents", ";#eta;n tracks", kTH1D, {{nEtaBins, -1.0, 1.0}}); + + histos.add("track_distr_nITStrThisEv_above_2000/hEta_lowOccupInTPC", ";#eta;n tracks", kTH1D, {{nEtaBins, -1.0, 1.0}}); + histos.add("track_distr_nITStrThisEv_above_2000/hEta_highOccupInRecentPast", ";#eta;n tracks", kTH1D, {{nEtaBins, -1.0, 1.0}}); + histos.add("track_distr_nITStrThisEv_above_2000/hEta_highOccupInCloseFuture", ";#eta;n tracks", kTH1D, {{nEtaBins, -1.0, 1.0}}); + histos.add("track_distr_nITStrThisEv_above_2000/hEta_highOccupInDistantFuture", ";#eta;n tracks", kTH1D, {{nEtaBins, -1.0, 1.0}}); + histos.add("track_distr_nITStrThisEv_above_2000/hEta_highOccupInNeighbourEvents", ";#eta;n tracks", kTH1D, {{nEtaBins, -1.0, 1.0}}); + + const int nPhiBins = 800; + AxisSpec axisPhi{nPhiBins, 0, TMath::TwoPi(), "#varphi"}; // o2-linter: disable=external-pi (temporary fix) + histos.add("track_distr_nITStrThisEv_10_200/hPhi_lowOccupInTPC", ";#varphi;n tracks", kTH1D, {axisPhi}); + histos.add("track_distr_nITStrThisEv_10_200/hPhi_highOccupInRecentPast", ";#varphi;n tracks", kTH1D, {axisPhi}); + histos.add("track_distr_nITStrThisEv_10_200/hPhi_highOccupInCloseFuture", ";#varphi;n tracks", kTH1D, {axisPhi}); + histos.add("track_distr_nITStrThisEv_10_200/hPhi_highOccupInDistantFuture", ";#varphi;n tracks", kTH1D, {axisPhi}); + histos.add("track_distr_nITStrThisEv_10_200/hPhi_highOccupInNeighbourEvents", ";#varphi;n tracks", kTH1D, {axisPhi}); + + histos.add("track_distr_nITStrThisEv_above_2000/hPhi_lowOccupInTPC", ";#varphi;n tracks", kTH1D, {axisPhi}); + histos.add("track_distr_nITStrThisEv_above_2000/hPhi_highOccupInRecentPast", ";#varphi;n tracks", kTH1D, {axisPhi}); + histos.add("track_distr_nITStrThisEv_above_2000/hPhi_highOccupInCloseFuture", ";#varphi;n tracks", kTH1D, {axisPhi}); + histos.add("track_distr_nITStrThisEv_above_2000/hPhi_highOccupInDistantFuture", ";#varphi;n tracks", kTH1D, {axisPhi}); + histos.add("track_distr_nITStrThisEv_above_2000/hPhi_highOccupInNeighbourEvents", ";#varphi;n tracks", kTH1D, {axisPhi}); + + // const int nPtBins = 800; + AxisSpec axisLogPt{200, 0.05, 40, "p_{T}"}; + axisLogPt.makeLogarithmic(); + histos.add("track_distr_nITStrThisEv_10_200/hPt_lowOccupInTPC", ";p_{T};n tracks", kTH1D, {axisLogPt}); + histos.add("track_distr_nITStrThisEv_10_200/hPt_highOccupInRecentPast", ";p_{T};n tracks", kTH1D, {axisLogPt}); + histos.add("track_distr_nITStrThisEv_10_200/hPt_highOccupInCloseFuture", ";p_{T};n tracks", kTH1D, {axisLogPt}); + histos.add("track_distr_nITStrThisEv_10_200/hPt_highOccupInDistantFuture", ";p_{T};n tracks", kTH1D, {axisLogPt}); + histos.add("track_distr_nITStrThisEv_10_200/hPt_highOccupInNeighbourEvents", ";p_{T};n tracks", kTH1D, {axisLogPt}); + + histos.add("track_distr_nITStrThisEv_above_2000/hPt_lowOccupInTPC", ";p_{T};n tracks", kTH1D, {axisLogPt}); + histos.add("track_distr_nITStrThisEv_above_2000/hPt_highOccupInRecentPast", ";p_{T};n tracks", kTH1D, {axisLogPt}); + histos.add("track_distr_nITStrThisEv_above_2000/hPt_highOccupInCloseFuture", ";p_{T};n tracks", kTH1D, {axisLogPt}); + histos.add("track_distr_nITStrThisEv_above_2000/hPt_highOccupInDistantFuture", ";p_{T};n tracks", kTH1D, {axisLogPt}); + histos.add("track_distr_nITStrThisEv_above_2000/hPt_highOccupInNeighbourEvents", ";p_{T};n tracks", kTH1D, {axisLogPt}); + + // 3D: pt vs centr vs occup + if (confFlagManyHeavyHistos) { + histos.add("ptGlobal_vs_centr_vs_occup", "", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisLogPt}); + histos.add("ptPV_vs_centr_vs_occup", "", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisLogPt}); + histos.add("ptGlobal_vs_centr_vs_occup_NoCollStd", "", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisLogPt}); + histos.add("ptPV_vs_centr_vs_occup_NoCollStd", "", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisLogPt}); + } + } + // 2D + int nBins3D = 80 * confOccupancyHistCoeffNbins3D; + int nBins3DoccupancyAxis = 100 * confOccupancyHistCoeffNbins3D; + + if (confAddBasicQAhistos) { + int nBins2D = 200 * confOccupancyHistCoeffNbins2D; + + histos.add("hNumITSTPCtracksInTimeWindow_vs_TracksPerColl", ";n tracks this collision;n tracks in time window", kTH2D, {{nBins2D, 0, kMaxThisEv * 8000}, {nBins2D, 0, kMaxOccup * 25000}}); + histos.add("hNumITSTPCtracksInTimeWindow_vs_TracksPerColl_withoutThisCol", ";n tracks this collision;n tracks in time window", kTH2D, {{nBins2D, 0, kMaxThisEv * 8000}, {nBins2D, 0, kMaxOccup * 25000}}); + histos.add("hNumITS567tracksInTimeWindow_vs_TracksPerColl", ";n tracks this collision;n tracks in time window", kTH2D, {{nBins2D, 0, kMaxThisEv * 8000}, {nBins2D, 0, kMaxOccup * 25000}}); + histos.add("hNumITS567tracksInTimeWindow_vs_TracksPerColl_withoutThisCol", ";n tracks this collision;n tracks in time window", kTH2D, {{nBins2D, 0, kMaxThisEv * 8000}, {nBins2D, 0, kMaxOccup * 25000}}); + + histos.add("hNumITS567tracksInTimeWindow_vs_FT0Campl", ";FT0C ampl. sum in time window;n ITS tracks with 5,6,7 hits in time window", kTH2D, {{nBins2D, 0, kMaxOccup * 250000}, {nBins2D, 0, kMaxOccup * 25000}}); + histos.add("hNumITSTPCtracksInTimeWindow_vs_FT0Campl", ";FT0C ampl. sum in time window;n ITS-TPC tracks in time window", kTH2D, {{nBins2D, 0, kMaxOccup * 250000}, {nBins2D, 0, kMaxOccup * 25000}}); + histos.add("hNumITSTPCtracksInTimeWindow_vs_ITS567tracks", ";n ITS tracks with 5,6,7 hits in time window;n ITS-TPC tracks in time window", kTH2D, {{nBins2D, 0, kMaxOccup * 25000}, {nBins2D, 0, kMaxOccup * 25000}}); + + histos.add("hNumITS567tracks_vs_FT0Campl_ThisEvent", ";FT0C ampl.;n ITS tracks with 5,6,7 hits", kTH2D, {{nBins2D, 0, kMaxThisEv * 100000}, {nBins2D, 0, kMaxThisEv * 8000}}); + histos.add("hNumITSTPCtracks_vs_FT0Campl_ThisEvent", ";FT0C ampl.;n ITS-TPC tracks", kTH2D, {{nBins2D, 0, kMaxThisEv * 100000}, {nBins2D, 0, kMaxThisEv * 8000}}); + histos.add("hNumITSTPCtracks_vs_ITS567tracks_ThisEvent", ";n ITS tracks with 5,6,7 hits;n ITS-TPC tracks", kTH2D, {{nBins2D, 0, kMaxThisEv * 8000}, {nBins2D, 0, kMaxThisEv * 8000}}); + + // 3D + histos.add("hNumITSTPC_vs_ITS567tracksThisCol_vs_ITS567tracksInTimeWindow_BEFORE_sel", ";n ITS tracks with 5,6,7 cls, this collision;n ITS-TPC tracks, this collision;ITS tracks with 5,6,7 cls in time window", kTH3D, {{nBins3D, 0, kMaxThisEv * 8000}, {nBins3D, 0, kMaxThisEv * 8000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 25000}}); + histos.add("hNumITSTPC_vs_ITS567tracksThisCol_vs_FT0CamplInTimeWindow_BEFORE_sel", ";n ITS tracks with 5,6,7 cls, this collision;n ITS-TPC tracks, this collision;FT0C ampl. sum in time window", kTH3D, {{nBins3D, 0, kMaxThisEv * 8000}, {nBins3D, 0, kMaxThisEv * 8000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 250000}}); + + histos.add("hNumITSTPC_vs_ITS567tracksThisCol_vs_ITS567tracksInTimeWindow", ";n ITS tracks with 5,6,7 cls, this collision;n ITS-TPC tracks, this collision;ITS tracks with 5,6,7 cls in time window", kTH3D, {{nBins3D, 0, kMaxThisEv * 8000}, {nBins3D, 0, kMaxThisEv * 8000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 25000}}); + histos.add("hNumITSTPC_vs_ITS567tracksThisCol_vs_FT0CamplInTimeWindow", ";n ITS tracks with 5,6,7 cls, this collision;n ITS-TPC tracks, this collision;FT0C ampl. sum in time window", kTH3D, {{nBins3D, 0, kMaxThisEv * 8000}, {nBins3D, 0, kMaxThisEv * 8000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 250000}}); + histos.add("hNumITSTPC_vs_ITS567tracksThisCol_vs_FT0CamplInTimeWindow_kNoCollInTimeRangeNarrow", ";n ITS tracks with 5,6,7 cls, this collision;n ITS-TPC tracks, this collision;FT0C ampl. sum in time window", kTH3D, {{nBins3D, 0, kMaxThisEv * 8000}, {nBins3D, 0, kMaxThisEv * 8000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 250000}}); + + histos.add("hNumITSTPC_vs_FT0CthisCol_vs_FT0CamplInTimeWindow_kNoCollInTimeRangeNarrow", ";FT0C this collision;n ITS-TPC tracks, this collision;FT0C ampl. sum in time window", kTH3D, {{nBins3D, 0, kMaxThisEv * 80000}, {nBins3D, 0, kMaxThisEv * 8000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 250000}}); + histos.add("hNumITS567_vs_FT0CthisCol_vs_FT0CamplInTimeWindow_kNoCollInTimeRangeNarrow", ";FT0C this collision;n ITS567cls tracks, this collision;FT0C ampl. sum in time window", kTH3D, {{nBins3D, 0, kMaxThisEv * 80000}, {nBins3D, 0, kMaxThisEv * 8000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 250000}}); + } + // nD, time bins to cover the range -confTimeIntervalForSmallBins... +confTimeIntervalForSmallBins (us) + double timeBinSize = 2 * confTimeIntervalForSmallBins / confNumberOfSmallTimeBins; + std::vector arrTimeBins; + for (int i = 0; i < confNumberOfSmallTimeBins + 1; i++) + arrTimeBins.push_back(-confTimeIntervalForSmallBins + i * timeBinSize); + const AxisSpec axisTimeBins{arrTimeBins, "#Delta t, #mus"}; + int nBinsX = 20; + int nBinsY = 40; + histos.add("occupancyInTimeBins", ";time bin (#mus);n ITS tracks with 5,6,7 cls, this collision;n ITS-TPC tracks, this collision;ITS tracks with 5,6,7 cls in time window", kTHnF, {axisTimeBins, {nBinsX, 0, kMaxThisEv * 4000}, {nBinsY, 0, kMaxThisEv * 4000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 10000}}); + histos.add("occupancyInTimeBins_vs_FT0thisCol_kNoCollInTimeRangeNarrow", ";time bin (#mus);FT0C this collision, this collision;n ITS-TPC tracks, this collision;ITS tracks with 5,6,7 cls in time window", kTHnF, {axisTimeBins, {nBins3D, 0, kMaxThisEv * 100000}, {nBinsY, 0, kMaxThisEv * 4000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 10000}}); + histos.add("occupancyInTimeBins_nITS567_vs_FT0thisCol_kNoCollInTimeRangeNarrow", ";time bin (#mus);FT0C this collision, this collision;n ITS567cls tracks, this collision;ITS tracks with 5,6,7 cls in time window", kTHnF, {axisTimeBins, {nBins3D, 0, kMaxThisEv * 100000}, {nBinsY, 0, kMaxThisEv * 4000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 10000}}); + + if (confFlagManyHeavyHistos) { + histos.add("occupancyInTimeBins_BEFORE_sel", ";time bin (#mus);n ITS tracks with 5,6,7 cls, this collision;n ITS-TPC tracks, this collision;ITS tracks with 5,6,7 cls in time window", kTHnF, {axisTimeBins, {nBinsX, 0, kMaxThisEv * 4000}, {nBinsY, 0, kMaxThisEv * 4000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 10000}}); + histos.add("occupancyInTimeBins_occupByFT0_BEFORE_sel", ";time bin (#mus);n ITS tracks with 5,6,7 cls, this collision;n ITS-TPC tracks, this collision;sum FT0 in time window", kTHnF, {axisTimeBins, {nBinsX, 0, kMaxThisEv * 4000}, {nBinsY, 0, kMaxThisEv * 4000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 100000}}); + + histos.add("occupancyInTimeBins_occupByFT0", ";time bin (#mus);n ITS tracks with 5,6,7 cls, this collision;n ITS-TPC tracks, this collision;sum FT0 in time window", kTHnF, {axisTimeBins, {nBinsX, 0, kMaxThisEv * 4000}, {nBinsY, 0, kMaxThisEv * 4000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 100000}}); + histos.add("occupancyInTimeBins_occupByFT0_kNoCollInTimeRangeNarrow", ";time bin (#mus);n ITS tracks with 5,6,7 cls, this collision;n ITS-TPC tracks, this collision;sum FT0 in time window", kTHnF, {axisTimeBins, {nBinsX, 0, kMaxThisEv * 4000}, {nBinsY, 0, kMaxThisEv * 4000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 100000}}); + + histos.add("occupancyInTimeBins_vs_FT0thisCol_occupByFT0_kNoCollInTimeRangeNarrow", ";time bin (#mus);FT0C this collision, this collision;n ITS-TPC tracks, this collision;sum FT0 in time window", kTHnF, {axisTimeBins, {nBins3D, 0, kMaxThisEv * 100000}, {nBinsY, 0, kMaxThisEv * 4000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 100000}}); + + histos.add("occupancyInTimeBins_nITS567_vs_FT0thisCol_occupByFT0_kNoCollInTimeRangeNarrow", ";time bin (#mus);FT0C this collision, this collision;n ITS567cls tracks, this collision;sum FT0 in time window", kTHnF, {axisTimeBins, {nBins3D, 0, kMaxThisEv * 100000}, {nBinsY, 0, kMaxThisEv * 4000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 100000}}); + histos.add("occupancyInTimeBins_nITS567_vs_FT0thisCol_occupByFT0_kNoCollInTimeRangeNarrow_NoCollInRofStrict", ";time bin (#mus);FT0C this collision, this collision;n ITS567cls tracks, this collision;sum FT0 in time window", kTHnF, {axisTimeBins, {nBins3D, 0, kMaxThisEv * 100000}, {nBinsY, 0, kMaxThisEv * 4000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 100000}}); + } + + histos.add("thisEventITStracksInTimeBins", ";time bin (#mus);n tracks", kTH1F, {axisTimeBins}); + histos.add("thisEventITSTPCtracksInTimeBins", ";time bin (#mus);n tracks", kTH1F, {axisTimeBins}); + histos.add("thisEventFT0CInTimeBins", ";time bin (#mus);n tracks", kTH1F, {axisTimeBins}); + + histos.add("qaForHighOccupITStracksInTimeBinPast", ";time bin (#mus);n tracks", kTH1F, {axisTimeBins}); + histos.add("qaForHighOccupITStracksInTimeBinFuture1", ";time bin (#mus);n tracks", kTH1F, {axisTimeBins}); + histos.add("qaForHighOccupITStracksInTimeBinFuture2", ";time bin (#mus);n tracks", kTH1F, {axisTimeBins}); + histos.add("qaForHighOccupITStracksForNeighbourEvents", ";time bin (#mus);n tracks", kTH1F, {axisTimeBins}); + + // save dt information for several first collisions for QA + histos.add("histOccupInTimeBinsQA", ";dt;this coll id", kTH2F, {axisTimeBins, {nCollisionsForTimeBinQA, -0.5, nCollisionsForTimeBinQA - 0.5}}); + + // QA of occupancy-based event selection + histos.add("hOccupancy", "", kTH1D, {{15002, -1.5, 15000.5}}); + histos.add("hOccupancyVsOrbit", ";orbit id;weighted occupancy;n events", kTH2F, {{128, -0.5, 127.5}, {600, 0, 15000}}); + + AxisSpec axisOccupancyTracks{nBinsOccupancy, 0., nMaxOccupancy, "occupancy (n ITS tracks weighted)"}; + if (confFlagCentralityIsAvailable) { + AxisSpec axisCentrality{100, 0, 100, "centrality, %"}; + histos.add("hCentrVsOccupancy", "hCentrVsOccupancy", kTH2F, {axisCentrality, axisOccupancyTracks}); + histos.add("hCentrVsOccupancyNoCollStd", "hCentrVsOccupancyNoCollStd", kTH2F, {axisCentrality, axisOccupancyTracks}); + } + + if (confAddTracksVsFwdHistos) { + AxisSpec axisNtracks{nBinsTracks, -0.5, nMaxTracks - 0.5, "n tracks"}; + AxisSpec axisNtracksGlobal{nBinsTracks, -0.5, nMaxGlobalTracks - 0.5, "n tracks"}; + AxisSpec axisMultV0A{nBinsMultFwd, 0., static_cast(nMaxMultFwd), "mult V0A"}; + AxisSpec axisMultFT0C{nBinsMultFwd, 0., static_cast(nMaxMultFwd * 0.4), "mult FT0C"}; + + histos.add("nTracksPV_vs_V0A_kNoCollInTimeRangeStandard", "nTracksPV_vs_V0A_kNoCollInTimeRangeStandard", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("nTracksPV_vs_V0A_kNoCollInTimeRangeNarrow", "nTracksPV_vs_V0A_kNoCollInTimeRangeNarrow", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("nTracksPV_vs_V0A_occup_0_250", "nTracksPV_vs_V0A_occup_0_250", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("nTracksPV_vs_V0A_occup_0_500", "nTracksPV_vs_V0A_occup_0_500", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("nTracksPV_vs_V0A_occup_0_750", "nTracksPV_vs_V0A_occup_0_750", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("nTracksPV_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard", "nTracksPV_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("nTracksPV_vs_V0A_occup_0_500_kNoCollInTimeRangeNarrow", "nTracksPV_vs_V0A_occup_0_500_kNoCollInTimeRangeNarrow", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("nTracksPV_vs_V0A_noOccupSel", "nTracksPV_vs_V0A_noOccupSel", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("nTracksPV_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard_extraCuts", "nTracksPV_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard_extraCuts", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("nTracksPV_vs_V0A_occup_ABOVE_750", "nTracksPV_vs_V0A_occup_ABOVE_750", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("nTracksPV_vs_V0A_occup_Minus1", "nTracksPV_vs_V0A_occup_Minus1", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("nTracksPV_vs_V0A_AntiNoCollInTimeRangeStandard", "nTracksPV_vs_V0A_AntiNoCollInTimeRangeStandard", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("nTracksPV_vs_V0A_AntiNoCollInTimeRangeNarrow", "nTracksPV_vs_V0A_AntiNoCollInTimeRangeNarrow", kTH2F, {axisMultV0A, axisNtracks}); + + histos.add("nTracksGlobal_vs_V0A_kNoCollInTimeRangeStandard", "nTracksGlobal_vs_V0A_kNoCollInTimeRangeStandard", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_V0A_kNoCollInTimeRangeNarrow", "nTracksGlobal_vs_V0A_kNoCollInTimeRangeNarrow", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_V0A_occup_0_250", "nTracksGlobal_vs_V0A_occup_0_250", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_V0A_occup_0_500", "nTracksGlobal_vs_V0A_occup_0_500", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_V0A_occup_0_750", "nTracksGlobal_vs_V0A_occup_0_750", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard", "nTracksGlobal_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_V0A_occup_0_500_kNoCollInTimeRangeNarrow", "nTracksGlobal_vs_V0A_occup_0_500_kNoCollInTimeRangeNarrow", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_V0A_noOccupSel", "nTracksGlobal_vs_V0A_noOccupSel", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard_extraCuts", "nTracksGlobal_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard_extraCuts", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_V0A_occup_ABOVE_750", "nTracksGlobal_vs_V0A_occup_ABOVE_750", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_V0A_occup_Minus1", "nTracksGlobal_vs_V0A_occup_Minus1", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_V0A_AntiNoCollInTimeRangeStandard", "nTracksGlobal_vs_V0A_AntiNoCollInTimeRangeStandard", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_V0A_AntiNoCollInTimeRangeNarrow", "nTracksGlobal_vs_V0A_AntiNoCollInTimeRangeNarrow", kTH2F, {axisMultV0A, axisNtracksGlobal}); + + histos.add("nTracksGlobal_vs_nPV_kNoCollInTimeRangeStandard", "nTracksGlobal_vs_nPV_kNoCollInTimeRangeStandard", kTH2F, {axisNtracks, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_nPV_kNoCollInTimeRangeNarrow", "nTracksGlobal_vs_nPV_kNoCollInTimeRangeNarrow", kTH2F, {axisNtracks, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_nPV_occup_0_250", "nTracksGlobal_vs_nPV_occup_0_250", kTH2F, {axisNtracks, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_nPV_occup_0_500", "nTracksGlobal_vs_nPV_occup_0_500", kTH2F, {axisNtracks, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_nPV_occup_0_750", "nTracksGlobal_vs_nPV_occup_0_750", kTH2F, {axisNtracks, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_nPV_occup_0_2000", "nTracksGlobal_vs_nPV_occup_0_2000", kTH2F, {axisNtracks, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_nPV_occup_0_500_kNoCollInTimeRangeStandard", "nTracksGlobal_vs_nPV_occup_0_500_kNoCollInTimeRangeStandard", kTH2F, {axisNtracks, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_nPV_occup_0_500_kNoCollInTimeRangeNarrow", "nTracksGlobal_vs_nPV_occup_0_500_kNoCollInTimeRangeNarrow", kTH2F, {axisNtracks, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_nPV_noOccupSel", "nTracksGlobal_vs_nPV_noOccupSel", kTH2F, {axisNtracks, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_nPV_occup_0_500_kNoCollInTimeRangeStandard_extraCuts", "nTracksGlobal_vs_nPV_occup_0_500_kNoCollInTimeRangeStandard_extraCuts", kTH2F, {axisNtracks, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_nPV_occup_0_2000_kNoCollInTimeRangeStandard_extraCuts", "nTracksGlobal_vs_nPV_occup_0_2000_kNoCollInTimeRangeStandard_extraCuts", kTH2F, {axisNtracks, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_nPV_occup_ABOVE_750", "nTracksGlobal_vs_nPV_occup_ABOVE_750", kTH2F, {axisNtracks, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_nPV_occup_Minus1", "nTracksGlobal_vs_nPV_occup_Minus1", kTH2F, {axisNtracks, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_nPV_AntiNoCollInTimeRangeStandard", "nTracksGlobal_vs_nPV_AntiNoCollInTimeRangeStandard", kTH2F, {axisNtracks, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_nPV_AntiNoCollInTimeRangeNarrow", "nTracksGlobal_vs_nPV_AntiNoCollInTimeRangeNarrow", kTH2F, {axisNtracks, axisNtracksGlobal}); + + histos.add("nTracksGlobal_vs_nPV_QA_onlyVzCut_noTFROFborderCuts", "nTracksGlobal_vs_nPV_QA_onlyVzCut_noTFROFborderCuts", kTH2F, {axisNtracks, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_nPV_QA_after_TFborderCut", "nTracksGlobal_vs_nPV_QA_after_TFborderCut", kTH2F, {axisNtracks, axisNtracksGlobal}); + + histos.add("nTracksGlobal_vs_nPV_occupByFT0C_0_2500", "nTracksGlobal_vs_nPV_occupByFT0C_0_2500", kTH2F, {axisNtracks, axisNtracksGlobal}); + histos.add("nTracksGlobal_vs_nPV_occupByFT0C_0_20000", "nTracksGlobal_vs_nPV_occupByFT0C_0_20000", kTH2F, {axisNtracks, axisNtracksGlobal}); + + // 3D histograms with occupancy axis + histos.add("nTracksGlobal_vs_nPV_vs_occup_pure", "nTracksGlobal_vs_nPV_vs_occup_pure", kTH3F, {axisNtracks, axisNtracksGlobal, axisOccupancyTracks}); + histos.add("nTracksGlobal_vs_nPV_vs_occup_kNoCollInTimeRangeStandard", "nTracksGlobal_vs_nPV_vs_occup_kNoCollInTimeRangeStandard", kTH3F, {axisNtracks, axisNtracksGlobal, axisOccupancyTracks}); + histos.add("nTracksGlobal_vs_nPV_vs_occup_kNoCollInTimeRangeNarrow", "nTracksGlobal_vs_nPV_vs_occup_kNoCollInTimeRangeNarrow", kTH3F, {axisNtracks, axisNtracksGlobal, axisOccupancyTracks}); + histos.add("nTracksGlobal_vs_nPV_vs_occup_kNoCollInTimeRangeStandard_extraCuts", "nTracksGlobal_vs_nPV_vs_occup_kNoCollInTimeRangeStandard_extraCuts", kTH3F, {axisNtracks, axisNtracksGlobal, axisOccupancyTracks}); + + // 3D histograms: nGlobalTracks with cls567 as y-axis, V0A as x-axis: + histos.add("nTracksGlobal_vs_V0A_vs_occup_pure", "", kTH3F, {axisMultV0A, axisNtracksGlobal, axisOccupancyTracks}); + histos.add("nTracksGlobal_vs_V0A_vs_occup_kNoCollInTimeRangeStandard_extraCuts", "", kTH3F, {axisMultV0A, axisNtracksGlobal, axisOccupancyTracks}); + // FT0C as x-axis: + histos.add("nTracksGlobal_vs_FT0C_vs_occup_pure", "", kTH3F, {axisMultFT0C, axisNtracksGlobal, axisOccupancyTracks}); + histos.add("nTracksGlobal_vs_FT0C_vs_occup_kNoCollInTimeRangeStandard_extraCuts", "", kTH3F, {axisMultFT0C, axisNtracksGlobal, axisOccupancyTracks}); + + // 3D histograms: now - nITStracks with cls567 as y-axis, V0A as x-axis: + histos.add("nPV_vs_V0A_vs_occup_pure", "", kTH3F, {axisMultV0A, axisNtracks, axisOccupancyTracks}); + histos.add("nPV_vs_V0A_vs_occup_kNoCollInTimeRangeStandard_extraCuts", "", kTH3F, {axisMultV0A, axisNtracks, axisOccupancyTracks}); + // FT0C as x-axis: + histos.add("nPV_vs_FT0C_vs_occup_pure", "", kTH3F, {axisMultFT0C, axisNtracks, axisOccupancyTracks}); + histos.add("nPV_vs_FT0C_vs_occup_kNoCollInTimeRangeStandard_extraCuts", "", kTH3F, {axisMultFT0C, axisNtracks, axisOccupancyTracks}); + } + } + + Preslice perCollision = aod::track::collisionId; + + void processRun3( + ColEvSels const& cols, + FullTracksIU const& tracks, + BCsRun3 const& bcs, + aod::FT0s const&) + { + int runNumber = bcs.iteratorAt(0).runNumber(); + if (runNumber != lastRunNumber) { + lastRunNumber = runNumber; // do it only once + + if (runNumber >= 500000) { + auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), runNumber); + // first bc of the first orbit + bcSOR = runInfo.orbitSOR * o2::constants::lhc::LHCMaxBunches; + // duration of TF in bcs + nBCsPerTF = runInfo.orbitsPerTF * o2::constants::lhc::LHCMaxBunches; + + LOGP(info, "bcSOR = {}, nBCsPerTF = {}", bcSOR, nBCsPerTF); + } + } + + // vectors with info for the occupancy study + std::vector vFoundBCindex(cols.size(), -1); // indices of found bcs + std::vector vFoundGlobalBC(cols.size(), 0); // global BCs for collisions + std::vector vIsVertexTOFmatched(cols.size(), 0); // at least one of vertex contributors is matched to TOF + std::vector vTracksITS567perColl(cols.size(), 0); // counter of tracks per found bc for occupancy studies + std::vector vTracksITS567perCollPtEtaCuts(cols.size(), 0); // counter of tracks per found bc for occupancy studies + std::vector vTracksGlobalPerCollPtEtaCuts(cols.size(), 0); // counter of tracks per found bc for occupancy studies + std::vector vTracksITSTPCperColl(cols.size(), 0); // counter of tracks per found bc for occupancy studies + std::vector vTracksITSTPCperCollPtEtaCuts(cols.size(), 0); // counter of tracks per found bc for occupancy studies + std::vector vAmpFT0CperColl(cols.size(), 0); // amplitude FT0C per collision + + std::vector vTFids(cols.size(), 0); + std::vector vIsFullInfoForOccupancy(cols.size(), 0); + std::vector vIsMarkedCollForAnalysis(cols.size(), 0); // cut on the max bcId in the time frame + + std::vector vFlagsForEtaQAvsOccupancyInDeltaTimeWins(cols.size(), 0); + + const double timeWinOccupancyCalcNS = confTimeIntervalForOccupancyCalculation * 1e3; // ns, to be compared with TPC drift time + const double bcNS = o2::constants::lhc::LHCBunchSpacingNS; + + for (const auto& col : cols) { + const auto& bc = col.foundBC_as(); + + // count tracks of different types + int nITS567cls = 0; + int nITS567clsPtEtaCuts = 0; + int nGlobalPtEtaCuts = 0; + int nITSTPCtracks = 0; + int nITSTPCtracksPtEtaCuts = 0; + int nTOFtracks = 0; + // int nTRDtracks = 0; + auto tracksGrouped = tracks.sliceBy(perCollision, col.globalIndex()); + for (const auto& track : tracksGrouped) { + if (!track.isPVContributor()) { + continue; + } + if (track.itsNCls() >= 5) + nITS567cls++; + nITSTPCtracks += track.hasITS() && track.hasTPC(); + nTOFtracks += track.hasTOF(); + // nTRDtracks += track.hasTRD(); + + if (track.pt() < confCutPtMinThisEvent || track.pt() > confCutPtMaxThisEvent) + continue; + if (track.eta() < confCutEtaMinTracksThisEvent || track.eta() > confCutEtaMaxTracksThisEvent) + continue; + + if (track.itsNCls() >= 5) + nITS567clsPtEtaCuts++; + + if (track.tpcNClsFound() < confCutMinTPCcls) + continue; + nITSTPCtracksPtEtaCuts += track.hasITS() && track.hasTPC(); + + if (track.itsNCls() >= 5) + nGlobalPtEtaCuts += track.isGlobalTrack(); + } + + int32_t foundBC = bc.globalIndex(); + int32_t colIndex = col.globalIndex(); + + vFoundBCindex[colIndex] = foundBC; + vFoundGlobalBC[colIndex] = bc.globalBC(); + + if (bc.has_foundFT0()) + vAmpFT0CperColl[colIndex] = bc.foundFT0().sumAmpC(); + + vIsVertexTOFmatched[colIndex] = nTOFtracks > 0; + + vTracksITS567perColl[colIndex] += nITS567cls; + vTracksITS567perCollPtEtaCuts[colIndex] += nITS567clsPtEtaCuts; + vTracksGlobalPerCollPtEtaCuts[colIndex] += nGlobalPtEtaCuts; + + vTracksITSTPCperColl[colIndex] += nITSTPCtracks; + vTracksITSTPCperCollPtEtaCuts[colIndex] += nITSTPCtracksPtEtaCuts; + + // TF ids within a given cols table + int tfId = (bc.globalBC() - bcSOR) / nBCsPerTF; + vTFids[colIndex] = tfId; + + // check that this collision has full information inside the time window (taking into account TF borders) + int64_t bcInTF = (bc.globalBC() - bcSOR) % nBCsPerTF; + vIsFullInfoForOccupancy[colIndex] = ((bcInTF - 300) * bcNS > timeWinOccupancyCalcNS) && ((nBCsPerTF - 4000 - bcInTF) * bcNS > timeWinOccupancyCalcNS) ? true : false; + + // cut on the max bc in the time frame + vIsMarkedCollForAnalysis[colIndex] = nMaxBcInTFforAnalysis == -1 ? 1 : (bcInTF >= 300 && bcInTF < nMaxBcInTFforAnalysis); + LOGP(debug, "### check bcInTF cut: colIndex={} bcInTF={} vIsFullInfoForOccupancy={}", colIndex, bcInTF, static_cast(vIsFullInfoForOccupancy[colIndex])); + } + + // find for each collision all collisions within the defined time window + std::vector> vCollsInTimeWin; + std::vector> vTimeDeltaForColls; // delta time wrt a given collision + for (const auto& col : cols) { + int32_t colIndex = col.globalIndex(); + std::vector vCollsAssocToGivenColl; + std::vector vCollsTimeDeltaWrtGivenColl; + + // protection against the TF borders + if (!vIsFullInfoForOccupancy[colIndex]) { + vCollsInTimeWin.push_back(vCollsAssocToGivenColl); + vTimeDeltaForColls.push_back(vCollsTimeDeltaWrtGivenColl); + continue; + } + + int64_t foundGlobalBC = vFoundGlobalBC[colIndex]; + int64_t tfId = (foundGlobalBC - bcSOR) / nBCsPerTF; + + // find all collisions in time window before the current one (start with the current collision) + int32_t minColIndex = colIndex; + while (minColIndex >= 0) { + int64_t thisBC = vFoundGlobalBC[minColIndex]; + + // check if this is still the same TF + int64_t thisTfId = (thisBC - bcSOR) / nBCsPerTF; + if (thisTfId != tfId) + break; + + float dt = (thisBC - foundGlobalBC) * bcNS; // ns + + if (confFlagWhichTimeRange == 2 && dt < 0) + break; + + // check if we are within the chosen time range + if (dt < -timeWinOccupancyCalcNS) + break; + vCollsAssocToGivenColl.push_back(minColIndex); + vCollsTimeDeltaWrtGivenColl.push_back(dt); + minColIndex--; + } + + // find all collisions in time window after the current one + int32_t maxColIndex = colIndex + 1; + while (maxColIndex < cols.size() && confFlagWhichTimeRange != 1) { + int64_t thisBC = vFoundGlobalBC[maxColIndex]; + int64_t thisTfId = (thisBC - bcSOR) / nBCsPerTF; + if (thisTfId != tfId) + break; + + float dt = (thisBC - foundGlobalBC) * bcNS; // ns + + if (dt > timeWinOccupancyCalcNS) + break; + vCollsAssocToGivenColl.push_back(maxColIndex); + vCollsTimeDeltaWrtGivenColl.push_back(dt); + maxColIndex++; + } + + vCollsInTimeWin.push_back(vCollsAssocToGivenColl); + vTimeDeltaForColls.push_back(vCollsTimeDeltaWrtGivenColl); + } + + // perform the occupancy calculation in the pre-defined time window + uint32_t orbitAtCollIndexZero = 0; + for (const auto& col : cols) { + int32_t colIndex = col.globalIndex(); + + // protection against the TF borders + if (!vIsFullInfoForOccupancy[colIndex]) + continue; + + // cut on the max bcId in the time frame (to avoid the artificial fade-out tail in the MC productions) + if (!vIsMarkedCollForAnalysis[colIndex]) + continue; + + // cut on vZ for a given collision + if (col.posZ() < confCutVertZMinThisEvent || col.posZ() > confCutVertZMaxThisEvent) + continue; + + // skip if collision is close to TF border + if (confFlagApplyTFborderCut && !col.selection_bit(kNoTimeFrameBorder)) + continue; + + // skip if collision is close to ROF border + if (confFlagApplyROFborderCut && !col.selection_bit(kNoITSROFrameBorder)) + continue; + + std::vector vCollsAssocToGivenColl = vCollsInTimeWin[colIndex]; + std::vector vCollsTimeDeltaWrtGivenColl = vTimeDeltaForColls[colIndex]; + + LOGP(debug, " >> vCollsAssocToGivenColl.size={}", vCollsAssocToGivenColl.size()); + + int64_t foundGlobalBC = vFoundGlobalBC[colIndex]; + uint32_t orbit = foundGlobalBC / o2::constants::lhc::LHCMaxBunches; + if (colIndex == 0) + orbitAtCollIndexZero = orbit; + + int nITS567tracksInTimeWindow = 0; + int nITSTPCtracksInTimeWindow = 0; + int nITS567tracksInTimeWindowSel = 0; + int nITSTPCtracksInTimeWindowSel = 0; + + int nCollInTimeWindow = 0; + int nCollInTimeWindowSel = 0; + int nCollInTimeWindowSelITSTPC = 0; + int nCollInTimeWindowSelIfTOF = 0; + double multFT0CmainCollision = 0.f; + double multFT0CInTimeWindow = 0.f; + map mUniqueBC; + + bool sel = col.selection_bit(kIsTriggerTVX); + + // loop over nearby collisions + for (unsigned int iCol = 0; iCol < vCollsAssocToGivenColl.size(); iCol++) { + int thisColIndex = vCollsAssocToGivenColl[iCol]; + int64_t thisGlobBC = vFoundGlobalBC[thisColIndex]; + float thisColTimeDiff = vCollsTimeDeltaWrtGivenColl[iCol] / 1e3; // ns -> us + + // fill this-event time bins + if (thisColIndex != colIndex && std::fabs(thisColTimeDiff) < confTimeIntervalForSmallBins) { + LOGP(debug, " iCol={}/{}, thisColIndex={}, colIndex={}, thisColTimeDiff={} nITS={}", iCol, vCollsAssocToGivenColl.size(), thisColIndex, colIndex, thisColTimeDiff, vTracksITS567perColl[thisColIndex]); + histos.fill(HIST("thisEventITStracksInTimeBins"), thisColTimeDiff, vTracksITS567perColl[thisColIndex]); + histos.fill(HIST("thisEventFT0CInTimeBins"), thisColTimeDiff, vAmpFT0CperColl[thisColIndex]); + // histos.fill(HIST("thisEventITSTPCtracksInTimeBins"), thisColTimeDiff, vTracksITSTPCperColl[thisColIndex]); + } + nCollInTimeWindow++; + nITS567tracksInTimeWindow += vTracksITS567perColl[thisColIndex]; + nITSTPCtracksInTimeWindow += vTracksITSTPCperColl[thisColIndex]; + + auto thisBC = bcs.iteratorAt(vFoundBCindex[thisColIndex]); + bool selThisBCsel = thisBC.selection_bit(kIsTriggerTVX); + + if (sel && selThisBCsel) { + nCollInTimeWindowSel++; + nITS567tracksInTimeWindowSel += vTracksITS567perColl[thisColIndex]; + nITSTPCtracksInTimeWindowSel += vTracksITSTPCperColl[thisColIndex]; + + mUniqueBC[thisGlobBC] = thisColIndex; + if (vTracksITSTPCperColl[thisColIndex] >= 2) + nCollInTimeWindowSelITSTPC++; + + if (vIsVertexTOFmatched[thisColIndex]) + nCollInTimeWindowSelIfTOF++; + } + + if (thisBC.has_foundFT0()) { + float multFT0C = thisBC.foundFT0().sumAmpC(); + if (iCol == 0) // the "middle" collision we study + multFT0CmainCollision = multFT0C; + multFT0CInTimeWindow += multFT0C; + } + LOGP(debug, "### Occupancy in time window study: colIndex={} thisColIndex={} thisGlobBC={} nTrThisCol={} nITSTPCtracksInTimeWindow={} timeDiff={} deltaBC={}", colIndex, thisColIndex, thisGlobBC, vTracksITSTPCperColl[thisColIndex], nITSTPCtracksInTimeWindow, (foundGlobalBC - thisGlobBC) * bcNS, foundGlobalBC - thisGlobBC); + } + + LOGP(debug, " --> ### summary: colIndex={}/{} BC={} orbit={} nCollInTimeWindow={} nCollInTimeWindowSel={} nITSTPCtracksInTimeWindow={} ", colIndex, cols.size(), foundGlobalBC, orbit - orbitAtCollIndexZero, nCollInTimeWindow, nCollInTimeWindowSel, nITSTPCtracksInTimeWindow); + + if (confAddBasicQAhistos) { + histos.fill(HIST("hNumITS567tracksInTimeWindow"), nITS567tracksInTimeWindow); + histos.fill(HIST("hNumITSTPCtracksInTimeWindow"), nITSTPCtracksInTimeWindow); + + histos.fill(HIST("hNumITSTPCtracksPerCollision"), vTracksITSTPCperColl[colIndex]); + histos.fill(HIST("hNumITS567tracksPerCollision"), vTracksITS567perColl[colIndex]); + + histos.fill(HIST("hNumITSTPCtracksInTimeWindow_vs_TracksPerColl"), vTracksITSTPCperColl[colIndex], nITSTPCtracksInTimeWindow); + histos.fill(HIST("hNumITSTPCtracksInTimeWindow_vs_TracksPerColl_withoutThisCol"), vTracksITSTPCperColl[colIndex], nITSTPCtracksInTimeWindow - vTracksITSTPCperColl[colIndex]); + + histos.fill(HIST("hNumITS567tracksInTimeWindow_vs_TracksPerColl"), vTracksITS567perColl[colIndex], nITS567tracksInTimeWindow); + histos.fill(HIST("hNumITS567tracksInTimeWindow_vs_TracksPerColl_withoutThisCol"), vTracksITS567perColl[colIndex], nITS567tracksInTimeWindow - vTracksITS567perColl[colIndex]); + + histos.fill(HIST("hNumCollInTimeWindow"), nCollInTimeWindow); + + int64_t bcInTF = (vFoundGlobalBC[colIndex] - bcSOR) % nBCsPerTF; + int orbitId = bcInTF / o2::constants::lhc::LHCMaxBunches; + histos.fill(HIST("hNumCollInTimeWindowVsOrbit"), orbitId, nCollInTimeWindow); + + histos.fill(HIST("hNumUniqueBCInTimeWindow"), mUniqueBC.size()); + + // 3D before ev quality cut: + histos.fill(HIST("hNumITSTPC_vs_ITS567tracksThisCol_vs_ITS567tracksInTimeWindow_BEFORE_sel"), vTracksITS567perCollPtEtaCuts[colIndex], vTracksITSTPCperCollPtEtaCuts[colIndex], nITS567tracksInTimeWindow - vTracksITS567perColl[colIndex]); + histos.fill(HIST("hNumITSTPC_vs_ITS567tracksThisCol_vs_FT0CamplInTimeWindow_BEFORE_sel"), vTracksITS567perCollPtEtaCuts[colIndex], vTracksITSTPCperCollPtEtaCuts[colIndex], multFT0CInTimeWindow - multFT0CmainCollision); + + if (sel && std::fabs(col.posZ()) < 10) { + histos.fill(HIST("hNumITS567tracksInTimeWindowSel"), nITS567tracksInTimeWindowSel); + histos.fill(HIST("hNumITSTPCtracksInTimeWindowSel"), nITSTPCtracksInTimeWindowSel); + + histos.fill(HIST("hNumITS567tracksPerCollisionSel"), vTracksITS567perColl[colIndex]); + histos.fill(HIST("hNumITSTPCtracksPerCollisionSel"), vTracksITSTPCperCollPtEtaCuts[colIndex]); + + histos.fill(HIST("hNumCollInTimeWindowSel"), nCollInTimeWindowSel); + histos.fill(HIST("hNumCollInTimeWindowSelITSTPC"), nCollInTimeWindowSelITSTPC); + histos.fill(HIST("hNumCollInTimeWindowSelIfTOF"), nCollInTimeWindowSelIfTOF); + + // 3D histograms: ITS vs ITSTPC in this event vs occupancy from other events + histos.fill(HIST("hNumITSTPC_vs_ITS567tracksThisCol_vs_ITS567tracksInTimeWindow"), vTracksITS567perCollPtEtaCuts[colIndex], vTracksITSTPCperCollPtEtaCuts[colIndex], nITS567tracksInTimeWindow - vTracksITS567perColl[colIndex]); + histos.fill(HIST("hNumITSTPC_vs_ITS567tracksThisCol_vs_FT0CamplInTimeWindow"), vTracksITS567perCollPtEtaCuts[colIndex], vTracksITSTPCperCollPtEtaCuts[colIndex], multFT0CInTimeWindow - multFT0CmainCollision); + if (col.selection_bit(kNoCollInTimeRangeNarrow)) { + histos.fill(HIST("hNumITSTPC_vs_ITS567tracksThisCol_vs_FT0CamplInTimeWindow_kNoCollInTimeRangeNarrow"), vTracksITS567perCollPtEtaCuts[colIndex], vTracksITSTPCperCollPtEtaCuts[colIndex], multFT0CInTimeWindow - multFT0CmainCollision); + + histos.fill(HIST("hNumITSTPC_vs_FT0CthisCol_vs_FT0CamplInTimeWindow_kNoCollInTimeRangeNarrow"), multFT0CmainCollision, vTracksITSTPCperCollPtEtaCuts[colIndex], multFT0CInTimeWindow - multFT0CmainCollision); + histos.fill(HIST("hNumITS567_vs_FT0CthisCol_vs_FT0CamplInTimeWindow_kNoCollInTimeRangeNarrow"), multFT0CmainCollision, vTracksITS567perCollPtEtaCuts[colIndex], multFT0CInTimeWindow - multFT0CmainCollision); + } + } + + // 2D histograms + histos.fill(HIST("hNumITS567tracksInTimeWindow_vs_FT0Campl"), multFT0CInTimeWindow, nITS567tracksInTimeWindow); + histos.fill(HIST("hNumITSTPCtracksInTimeWindow_vs_FT0Campl"), multFT0CInTimeWindow, nITSTPCtracksInTimeWindow); + histos.fill(HIST("hNumITSTPCtracksInTimeWindow_vs_ITS567tracks"), nITS567tracksInTimeWindow, nITSTPCtracksInTimeWindow); + + histos.fill(HIST("hNumITS567tracks_vs_FT0Campl_ThisEvent"), multFT0CmainCollision, vTracksITS567perCollPtEtaCuts[colIndex]); + histos.fill(HIST("hNumITSTPCtracks_vs_FT0Campl_ThisEvent"), multFT0CmainCollision, vTracksITSTPCperCollPtEtaCuts[colIndex]); + histos.fill(HIST("hNumITSTPCtracks_vs_ITS567tracks_ThisEvent"), vTracksITS567perCollPtEtaCuts[colIndex], vTracksITSTPCperCollPtEtaCuts[colIndex]); + } + + // counters of occupancy in specified delta-time ranges, to monitor eta, phi, pt distributions later + float integralFullDeltaTime = histos.get(HIST("thisEventITStracksInTimeBins"))->Integral(); + int binMin = histos.get(HIST("thisEventITStracksInTimeBins"))->FindBin(-39.5); // us + int binMax = histos.get(HIST("thisEventITStracksInTimeBins"))->FindBin(-10.5); + float integralPast = histos.get(HIST("thisEventITStracksInTimeBins"))->Integral(binMin, binMax); + binMin = histos.get(HIST("thisEventITStracksInTimeBins"))->FindBin(20.5); + binMax = histos.get(HIST("thisEventITStracksInTimeBins"))->FindBin(49.5); + float integralFuture1 = histos.get(HIST("thisEventITStracksInTimeBins"))->Integral(binMin, binMax); + binMin = histos.get(HIST("thisEventITStracksInTimeBins"))->FindBin(50.5); + binMax = histos.get(HIST("thisEventITStracksInTimeBins"))->FindBin(79.5); + float integralFuture2 = histos.get(HIST("thisEventITStracksInTimeBins"))->Integral(binMin, binMax); + binMin = histos.get(HIST("thisEventITStracksInTimeBins"))->FindBin(-9.5); + binMax = histos.get(HIST("thisEventITStracksInTimeBins"))->FindBin(19.5); + float integralNeighbourEvents = histos.get(HIST("thisEventITStracksInTimeBins"))->Integral(binMin, binMax); + + // recent past + if (integralFullDeltaTime < 150) // ~empty detector + vFlagsForEtaQAvsOccupancyInDeltaTimeWins[colIndex] = 1; + // recent past + if (integralPast > /*3000*/ 2500 && (integralFullDeltaTime - integralPast) < 120) // low occupancy outside the dt region of interest + vFlagsForEtaQAvsOccupancyInDeltaTimeWins[colIndex] = 2; + // close future + if (integralFuture1 > /*3000*/ 2500 && (integralFullDeltaTime - integralFuture1) < 120) + vFlagsForEtaQAvsOccupancyInDeltaTimeWins[colIndex] = 3; + // distant future + if (integralFuture2 > /*3000*/ 2500 && (integralFullDeltaTime - integralFuture2) < 120) + vFlagsForEtaQAvsOccupancyInDeltaTimeWins[colIndex] = 4; + // neighbour events + if (integralNeighbourEvents > /*3000*/ 2500 && (integralFullDeltaTime - integralNeighbourEvents) < 120) + vFlagsForEtaQAvsOccupancyInDeltaTimeWins[colIndex] = 5; + + // loop over time axis in nD histograms: + for (int iT = 0; iT < histos.get(HIST("thisEventITStracksInTimeBins"))->GetNbinsX(); iT++) { + int nITStrInTimeBin = histos.get(HIST("thisEventITStracksInTimeBins"))->GetBinContent(iT + 1); + if (nITStrInTimeBin == 0) // no collisions in this dt bin + continue; + // int nITSTPCtInTimeBin = histos.get(HIST("thisEventITSTPCtracksInTimeBins"))->GetBinContent(iT + 1); + + float dt = histos.get(HIST("thisEventITStracksInTimeBins"))->GetBinCenter(iT + 1); + + int nFT0CInTimeBin = histos.get(HIST("thisEventFT0CInTimeBins"))->GetBinContent(iT + 1); + + if (confFlagManyHeavyHistos) { + histos.fill(HIST("occupancyInTimeBins_BEFORE_sel"), dt, vTracksITS567perCollPtEtaCuts[colIndex], confFlagUseGlobalTracks ? vTracksGlobalPerCollPtEtaCuts[colIndex] : vTracksITSTPCperCollPtEtaCuts[colIndex], nITStrInTimeBin); + histos.fill(HIST("occupancyInTimeBins_occupByFT0_BEFORE_sel"), dt, vTracksITS567perCollPtEtaCuts[colIndex], confFlagUseGlobalTracks ? vTracksGlobalPerCollPtEtaCuts[colIndex] : vTracksITSTPCperCollPtEtaCuts[colIndex], nFT0CInTimeBin); + } + bool flagFillOccupVsDt = true; + if (confFlagUseNoCollInRofStrict && !col.selection_bit(kNoCollInRofStrict)) + flagFillOccupVsDt = false; + if (confFlagUseNoHighMultCollInPrevRof && !col.selection_bit(kNoHighMultCollInPrevRof)) + flagFillOccupVsDt = false; + + if (sel && std::fabs(col.posZ()) < 10 && flagFillOccupVsDt) { + histos.fill(HIST("occupancyInTimeBins"), dt, vTracksITS567perCollPtEtaCuts[colIndex], confFlagUseGlobalTracks ? vTracksGlobalPerCollPtEtaCuts[colIndex] : vTracksITSTPCperCollPtEtaCuts[colIndex], nITStrInTimeBin); + if (confFlagManyHeavyHistos) + histos.fill(HIST("occupancyInTimeBins_occupByFT0"), dt, vTracksITS567perCollPtEtaCuts[colIndex], confFlagUseGlobalTracks ? vTracksGlobalPerCollPtEtaCuts[colIndex] : vTracksITSTPCperCollPtEtaCuts[colIndex], nFT0CInTimeBin); + + if (col.selection_bit(kNoCollInTimeRangeNarrow)) { + histos.fill(HIST("occupancyInTimeBins_vs_FT0thisCol_kNoCollInTimeRangeNarrow"), dt, vAmpFT0CperColl[colIndex], confFlagUseGlobalTracks ? vTracksGlobalPerCollPtEtaCuts[colIndex] : vTracksITSTPCperCollPtEtaCuts[colIndex], nITStrInTimeBin); + histos.fill(HIST("occupancyInTimeBins_nITS567_vs_FT0thisCol_kNoCollInTimeRangeNarrow"), dt, vAmpFT0CperColl[colIndex], vTracksITS567perCollPtEtaCuts[colIndex], nITStrInTimeBin); + if (confFlagManyHeavyHistos) { + histos.fill(HIST("occupancyInTimeBins_occupByFT0_kNoCollInTimeRangeNarrow"), dt, vTracksITS567perCollPtEtaCuts[colIndex], confFlagUseGlobalTracks ? vTracksGlobalPerCollPtEtaCuts[colIndex] : vTracksITSTPCperCollPtEtaCuts[colIndex], nFT0CInTimeBin); + histos.fill(HIST("occupancyInTimeBins_vs_FT0thisCol_occupByFT0_kNoCollInTimeRangeNarrow"), dt, vAmpFT0CperColl[colIndex], confFlagUseGlobalTracks ? vTracksGlobalPerCollPtEtaCuts[colIndex] : vTracksITSTPCperCollPtEtaCuts[colIndex], nFT0CInTimeBin); + + histos.fill(HIST("occupancyInTimeBins_nITS567_vs_FT0thisCol_occupByFT0_kNoCollInTimeRangeNarrow"), dt, vAmpFT0CperColl[colIndex], vTracksITS567perCollPtEtaCuts[colIndex], nFT0CInTimeBin); + if (col.selection_bit(kNoCollInRofStrict)) + histos.fill(HIST("occupancyInTimeBins_nITS567_vs_FT0thisCol_occupByFT0_kNoCollInTimeRangeNarrow_NoCollInRofStrict"), dt, vAmpFT0CperColl[colIndex], vTracksITS567perCollPtEtaCuts[colIndex], nFT0CInTimeBin); + } + } + } + + // + + if (counterQAtimeOccupHistos < nCollisionsForTimeBinQA) + histos.fill(HIST("histOccupInTimeBinsQA"), dt, counterQAtimeOccupHistos + 1, nITStrInTimeBin); + + // QA for high occup in time bins + if (vFlagsForEtaQAvsOccupancyInDeltaTimeWins[colIndex] == 2) + histos.fill(HIST("qaForHighOccupITStracksInTimeBinPast"), dt, nITStrInTimeBin); + if (vFlagsForEtaQAvsOccupancyInDeltaTimeWins[colIndex] == 3) + histos.fill(HIST("qaForHighOccupITStracksInTimeBinFuture1"), dt, nITStrInTimeBin); + if (vFlagsForEtaQAvsOccupancyInDeltaTimeWins[colIndex] == 4) + histos.fill(HIST("qaForHighOccupITStracksInTimeBinFuture2"), dt, nITStrInTimeBin); + if (vFlagsForEtaQAvsOccupancyInDeltaTimeWins[colIndex] == 5) + histos.fill(HIST("qaForHighOccupITStracksForNeighbourEvents"), dt, nITStrInTimeBin); + } + + // reset delta time hist for this event + histos.get(HIST("thisEventITStracksInTimeBins"))->Reset(); + // histos.get(HIST("thisEventITSTPCtracksInTimeBins"))->Reset(); + histos.get(HIST("thisEventFT0CInTimeBins"))->Reset(); + counterQAtimeOccupHistos++; + } // end of occupancy calculation + + // ### occupancy event selection QA + for (const auto& col : cols) { + // if (!col.sel8()) { + // continue; + // } + if (!col.selection_bit(kIsTriggerTVX)) + continue; + // cut on vZ for a given collision + if (col.posZ() < confCutVertZMinThisEvent || col.posZ() > confCutVertZMaxThisEvent) + continue; + + int32_t colIndex = col.globalIndex(); + int64_t bcInTF = (vFoundGlobalBC[colIndex] - bcSOR) % nBCsPerTF; + histos.fill(HIST("hNcolVsBcInTF"), bcInTF); + + // cut on the max bcId in the time frame (to avoid the artificial fade-out tail in the MC productions) + if (!vIsMarkedCollForAnalysis[colIndex]) + continue; + + histos.fill(HIST("hNcolVsBcInTFafterMaxBcCut"), bcInTF); + + auto multV0A = col.multFV0A(); + // auto multT0A = col.multFT0A(); + auto multT0C = col.multFT0C(); + int nPV = 0; // col.multNTracksPV(); + int nGlobalTracks = 0; + + int occupancy = col.trackOccupancyInTimeRange(); + + auto tracksGrouped = tracks.sliceBy(perCollision, col.globalIndex()); + + // pre-calc nPV + for (const auto& track : tracksGrouped) { + if (!track.isPVContributor()) + continue; + if (track.pt() < confCutPtMinThisEvent || track.pt() > confCutPtMaxThisEvent) + continue; + if (track.eta() < confCutEtaMinTracksThisEvent || track.eta() > confCutEtaMaxTracksThisEvent) + continue; + if (track.itsNCls() < 5) + continue; + nPV++; + } + + // main loop for dE/dx + for (const auto& track : tracksGrouped) { + histos.fill(HIST("nTrackCounter_after_cuts_QA"), 0); + if (!track.isPVContributor()) + continue; + histos.fill(HIST("nTrackCounter_after_cuts_QA"), 1); + if (track.pt() < confCutPtMinThisEvent || track.pt() > confCutPtMaxThisEvent) + continue; + histos.fill(HIST("nTrackCounter_after_cuts_QA"), 2); + if (track.eta() < confCutEtaMinTracksThisEvent || track.eta() > confCutEtaMaxTracksThisEvent) + continue; + histos.fill(HIST("nTrackCounter_after_cuts_QA"), 3); + if (track.itsNCls() < 5) + continue; + histos.fill(HIST("nTrackCounter_after_cuts_QA"), 4); + // nPV++; + + if (track.isGlobalTrack() && track.tpcNClsFound() >= confCutMinTPCcls) { + nGlobalTracks++; + histos.fill(HIST("nTrackCounter_after_cuts_QA"), 5); + + if (track.passedTPCRefit()) { + histos.fill(HIST("nTrackCounter_after_cuts_QA"), 6); + + float signedP = track.sign() * track.tpcInnerParam(); + histos.fill(HIST("dEdx_vs_Momentum"), signedP, track.tpcSignal()); + if (occupancy >= 0 && occupancy < 200) { + histos.fill(HIST("dEdx_vs_Momentum_occupBelow200"), signedP, track.tpcSignal()); + if (col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) + histos.fill(HIST("dEdx_vs_Momentum_occupBelow200_kNoCollStd"), signedP, track.tpcSignal()); + } + if (occupancy > 4000) + histos.fill(HIST("dEdx_vs_Momentum_occupAbove4000"), signedP, track.tpcSignal()); + + if (occupancy >= 0) { + histos.fill(HIST("nTrackCounter_after_cuts_QA"), 7); + + histos.fill(HIST("dEdx_vs_Momentum_vs_occup"), signedP, track.tpcSignal(), occupancy); + + if (confFlagManyHeavyHistos) { + if (track.eta() > 0.2 && track.eta() < 0.4) + histos.fill(HIST("dEdx_vs_Momentum_vs_occup_eta_02_04"), signedP, track.tpcSignal(), occupancy); + if (track.eta() > -0.4 && track.eta() < -0.2) + histos.fill(HIST("dEdx_vs_Momentum_vs_occup_eta_04_02"), signedP, track.tpcSignal(), occupancy); + } + // more QA for TPC cls counting + histos.fill(HIST("tpcNClsFindable"), track.tpcNClsFindable()); + histos.fill(HIST("tpcNClsFindableMinusFound"), track.tpcNClsFindableMinusFound()); + histos.fill(HIST("tpcNClsFindableMinusCrossedRows"), track.tpcNClsFindableMinusCrossedRows()); + histos.fill(HIST("tpcNClsShared"), track.tpcNClsShared()); + histos.fill(HIST("tpcNClsFindableMinusPID"), track.tpcNClsFindableMinusPID()); + int tpcNClUsedForPID = track.tpcNClsFindable() - track.tpcNClsFindableMinusPID(); + histos.fill(HIST("tpcNClUsedForPID"), tpcNClUsedForPID); + + histos.fill(HIST("tpcNClsFound"), track.tpcNClsFound()); + histos.fill(HIST("tpcNClsFoundAsDiffByHand"), track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()); + + histos.fill(HIST("tpcNClsUsedForPID_vs_Findable"), track.tpcNClsFindable(), tpcNClUsedForPID); + histos.fill(HIST("tpcNClsShared_vs_Findable"), track.tpcNClsFindable(), track.tpcNClsShared()); + histos.fill(HIST("tpcNClsUsedForPID_vs_Shared"), track.tpcNClsShared(), tpcNClUsedForPID); + histos.fill(HIST("tpcNClsFound_vs_Findable"), track.tpcNClsFindable(), track.tpcNClsFound()); + histos.fill(HIST("tpcNClsUsedForPID_vs_Found"), track.tpcNClsFound(), tpcNClUsedForPID); + + int tpcNClsCorrectedFindableMinusPID = track.tpcNClsFindableMinusPID(); + // correct for a buggy behaviour due to int8 and uint8 difference: + if (tpcNClsCorrectedFindableMinusPID < -70) + tpcNClsCorrectedFindableMinusPID += 256; + histos.fill(HIST("tpcNClsFindableMinusPID_CORRECTED"), tpcNClsCorrectedFindableMinusPID); + histos.fill(HIST("tpcNClsUsedForPID_vs_Findable_CORRECTED"), track.tpcNClsFindable(), track.tpcNClsFindable() - tpcNClsCorrectedFindableMinusPID); + + histos.fill(HIST("tpcNClsFoundMinusPID_BY_HAND"), (track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) - (track.tpcNClsFindable() - tpcNClsCorrectedFindableMinusPID)); + + // check ratio tpcNClsFindableMinusPID / tpcNClsFindable + // https://github.com/AliceO2Group/AliceO2/blob/dev/Framework/Core/include/Framework/AnalysisDataModel.h#L242 + // https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/AOD/src/AODProducerWorkflowSpec.cxx#L2553C21-L2553C44 + float fractionTPCcls = (1.0 * tpcNClsCorrectedFindableMinusPID) / track.tpcNClsFindable(); + histos.fill(HIST("fraction_tpcNClsFindableMinusPID_vs_occup"), occupancy, fractionTPCcls); + if (fractionTPCcls >= 0 && fractionTPCcls < 0.8) + histos.fill(HIST("nTrackCounter_after_cuts_QA"), 8); + if (fractionTPCcls < 0) + histos.fill(HIST("dEdx_vs_Momentum_HighFractionNclsNonPID"), signedP, track.tpcSignal()); + if (fractionTPCcls > 0.8) + histos.fill(HIST("dEdx_vs_Momentum_NegativeFractionNclsPID"), signedP, track.tpcSignal()); + + if (multV0A < 6800) + histos.fill(HIST("fraction_tpcNClsFindableMinusPID_vs_occup_peripheralByV0A"), occupancy, fractionTPCcls); + else if (multV0A > 82850) + histos.fill(HIST("fraction_tpcNClsFindableMinusPID_vs_occup_centralByV0A"), occupancy, fractionTPCcls); + + if (std::fabs(track.eta()) < 0.2) + histos.fill(HIST("fraction_tpcNClsFindableMinusPID_vs_occup_eta02"), occupancy, fractionTPCcls); + + // vs charge + if (signedP > 0) { + histos.fill(HIST("nTrackCounter_after_cuts_QA"), 9); + histos.fill(HIST("fraction_tpcNClsFindableMinusPID_vs_occup_pos"), occupancy, fractionTPCcls); + } else { + histos.fill(HIST("nTrackCounter_after_cuts_QA"), 10); + histos.fill(HIST("fraction_tpcNClsFindableMinusPID_vs_occup_neg"), occupancy, fractionTPCcls); + } + // vs pt + if (track.pt() > 0.2 && track.pt() < 0.8) + histos.fill(HIST("fraction_tpcNClsFindableMinusPID_vs_occup_lowPt"), occupancy, fractionTPCcls); + if (track.pt() > 0.8 && track.pt() < 10) + histos.fill(HIST("fraction_tpcNClsFindableMinusPID_vs_occup_highPt"), occupancy, fractionTPCcls); + + // dE/dx in narrow mom bin vs centrality and occupancy + if (std::fabs(signedP) > 0.38 && std::fabs(signedP) < 0.4) + histos.fill(HIST("dEdx_vs_centr_vs_occup_narrow_p_win"), nPV, occupancy, track.tpcSignal()); + // vs charge + if (signedP > 0.38 && signedP < 0.4) { + histos.fill(HIST("dEdx_vs_centr_vs_occup_narrow_p_win_pos"), nPV, occupancy, track.tpcSignal()); + if (fractionTPCcls >= 0 && fractionTPCcls < 0.8) + histos.fill(HIST("dEdx_vs_centr_vs_occup_narrow_p_win_pos_FractionPIDclsInRange"), nPV, occupancy, track.tpcSignal()); + } else if (signedP > -0.4 && signedP < -0.38) { + histos.fill(HIST("dEdx_vs_centr_vs_occup_narrow_p_win_neg"), nPV, occupancy, track.tpcSignal()); + if (fractionTPCcls >= 0 && fractionTPCcls < 0.8) + histos.fill(HIST("dEdx_vs_centr_vs_occup_narrow_p_win_neg_FractionPIDclsInRange"), nPV, occupancy, track.tpcSignal()); + } + } + } + } + } // end of track loop + + if (confAddTracksVsFwdHistos) + histos.fill(HIST("nTracksGlobal_vs_nPV_QA_onlyVzCut_noTFROFborderCuts"), nPV, nGlobalTracks); + + // skip if collision is close to TF border + if (confFlagApplyTFborderCut && !col.selection_bit(kNoTimeFrameBorder)) + continue; + + if (confAddTracksVsFwdHistos) + histos.fill(HIST("nTracksGlobal_vs_nPV_QA_after_TFborderCut"), nPV, nGlobalTracks); + + // skip if collision is close to ROF border + if (confFlagApplyROFborderCut && !col.selection_bit(kNoITSROFrameBorder)) + continue; + + histos.fill(HIST("hOccupancy"), occupancy); + if (occupancy >= 0) { + int orbitId = bcInTF / o2::constants::lhc::LHCMaxBunches; + histos.fill(HIST("hOccupancyVsOrbit"), orbitId, occupancy); + } + + // another track loop to fill track-level histograms + if (confAddBasicQAhistos) { + int flagWhichDeltaTimeWin = vFlagsForEtaQAvsOccupancyInDeltaTimeWins[colIndex]; + bool flagNoCollNearby = col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard); + + if (occupancy >= 0) { + if (nPV >= 10 && nPV < 200) { + if (flagNoCollNearby && flagWhichDeltaTimeWin != 5) + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hEventCount"), flagWhichDeltaTimeWin); + if (flagWhichDeltaTimeWin == 5) // nearby collisions --> avoid checking the flagNoCollNearby flag + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hEventCount"), flagWhichDeltaTimeWin); + } + if (nPV >= 2000) { + if (flagNoCollNearby && flagWhichDeltaTimeWin != 5) + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hEventCount"), flagWhichDeltaTimeWin); + if (flagWhichDeltaTimeWin == 5) // nearby collisions --> avoid checking the flagNoCollNearby flag + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hEventCount"), flagWhichDeltaTimeWin); + } + } + + for (const auto& track : tracksGrouped) { + if (!track.isPVContributor()) + continue; + if (track.itsNCls() < 5) + continue; + if (!(track.isGlobalTrack() && track.tpcNClsFound() >= confCutMinTPCcls)) + continue; + + // pt vs centr vs occup + if (occupancy >= 0) { + if (confFlagManyHeavyHistos) { + histos.fill(HIST("ptGlobal_vs_centr_vs_occup"), nPV, occupancy, track.pt()); + histos.fill(HIST("ptPV_vs_centr_vs_occup"), nPV, occupancy, track.pt()); + if (col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + histos.fill(HIST("ptGlobal_vs_centr_vs_occup_NoCollStd"), nPV, occupancy, track.pt()); + histos.fill(HIST("ptPV_vs_centr_vs_occup_NoCollStd"), nPV, occupancy, track.pt()); + } + } + + if (nPV >= 10 && nPV < 200) { + if (flagWhichDeltaTimeWin == 1 && flagNoCollNearby) { + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hEta_lowOccupInTPC"), track.eta()); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_lowOccupInTPC"), track.phi()); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPt_lowOccupInTPC"), track.pt()); + } + if (flagWhichDeltaTimeWin == 2 && flagNoCollNearby) { + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hEta_highOccupInRecentPast"), track.eta()); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_highOccupInRecentPast"), track.phi()); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPt_highOccupInRecentPast"), track.pt()); + } + if (flagWhichDeltaTimeWin == 3 && flagNoCollNearby) { + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hEta_highOccupInCloseFuture"), track.eta()); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_highOccupInCloseFuture"), track.phi()); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPt_highOccupInCloseFuture"), track.pt()); + } + if (flagWhichDeltaTimeWin == 4 && flagNoCollNearby) { + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hEta_highOccupInDistantFuture"), track.eta()); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_highOccupInDistantFuture"), track.phi()); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPt_highOccupInDistantFuture"), track.pt()); + } + if (flagWhichDeltaTimeWin == 5) { + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hEta_highOccupInNeighbourEvents"), track.eta()); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_highOccupInNeighbourEvents"), track.phi()); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPt_highOccupInNeighbourEvents"), track.pt()); + } + } else if (nPV >= 2000) { + if (flagWhichDeltaTimeWin == 1 && flagNoCollNearby) { + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hEta_lowOccupInTPC"), track.eta()); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPhi_lowOccupInTPC"), track.phi()); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPt_lowOccupInTPC"), track.pt()); + } + if (flagWhichDeltaTimeWin == 2 && flagNoCollNearby) { + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hEta_highOccupInRecentPast"), track.eta()); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPhi_highOccupInRecentPast"), track.phi()); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPt_highOccupInRecentPast"), track.pt()); + } + if (flagWhichDeltaTimeWin == 3 && flagNoCollNearby) { + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hEta_highOccupInCloseFuture"), track.eta()); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPhi_highOccupInCloseFuture"), track.phi()); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPt_highOccupInCloseFuture"), track.pt()); + } + if (flagWhichDeltaTimeWin == 4 && flagNoCollNearby) { + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hEta_highOccupInDistantFuture"), track.eta()); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPhi_highOccupInDistantFuture"), track.phi()); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPt_highOccupInDistantFuture"), track.pt()); + } + if (flagWhichDeltaTimeWin == 5) { + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hEta_highOccupInNeighbourEvents"), track.eta()); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPhi_highOccupInNeighbourEvents"), track.phi()); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPt_highOccupInNeighbourEvents"), track.pt()); + } + } + } // end of if (occupancy >= 0) + } + } // end of spec track loop to fill track histograms + + // occupancy vs centrality + if (confFlagCentralityIsAvailable) { + auto t0cCentr = col.centFT0C(); + if (occupancy >= 0) { + histos.fill(HIST("hCentrVsOccupancy"), t0cCentr, occupancy); + if (col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) + histos.fill(HIST("hCentrVsOccupancyNoCollStd"), t0cCentr, occupancy); + } + } + + if (!confAddTracksVsFwdHistos) { + continue; + } + + // nPV tracks vs fwd amplitude + histos.fill(HIST("nTracksPV_vs_V0A_noOccupSel"), multV0A, nPV); + histos.fill(HIST("nTracksGlobal_vs_V0A_noOccupSel"), multV0A, nGlobalTracks); + histos.fill(HIST("nTracksGlobal_vs_nPV_noOccupSel"), nPV, nGlobalTracks); + + if (occupancy >= 0) { + histos.fill(HIST("nTracksGlobal_vs_nPV_vs_occup_pure"), nPV, nGlobalTracks, occupancy); + histos.fill(HIST("nTracksGlobal_vs_V0A_vs_occup_pure"), multV0A, nGlobalTracks, occupancy); + histos.fill(HIST("nTracksGlobal_vs_FT0C_vs_occup_pure"), multT0C, nGlobalTracks, occupancy); + + histos.fill(HIST("nPV_vs_V0A_vs_occup_pure"), multV0A, nPV, occupancy); + histos.fill(HIST("nPV_vs_FT0C_vs_occup_pure"), multT0C, nPV, occupancy); + } + + if (col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + histos.fill(HIST("nTracksPV_vs_V0A_kNoCollInTimeRangeStandard"), multV0A, nPV); + histos.fill(HIST("nTracksGlobal_vs_V0A_kNoCollInTimeRangeStandard"), multV0A, nGlobalTracks); + histos.fill(HIST("nTracksGlobal_vs_nPV_kNoCollInTimeRangeStandard"), nPV, nGlobalTracks); + if (occupancy >= 0) + histos.fill(HIST("nTracksGlobal_vs_nPV_vs_occup_kNoCollInTimeRangeStandard"), nPV, nGlobalTracks, occupancy); + if (occupancy >= 0 && col.selection_bit(kNoSameBunchPileup) && col.selection_bit(kIsGoodZvtxFT0vsPV)) { + histos.fill(HIST("nTracksGlobal_vs_nPV_vs_occup_kNoCollInTimeRangeStandard_extraCuts"), nPV, nGlobalTracks, occupancy); + histos.fill(HIST("nTracksGlobal_vs_V0A_vs_occup_kNoCollInTimeRangeStandard_extraCuts"), multV0A, nGlobalTracks, occupancy); + histos.fill(HIST("nTracksGlobal_vs_FT0C_vs_occup_kNoCollInTimeRangeStandard_extraCuts"), multT0C, nGlobalTracks, occupancy); + + histos.fill(HIST("nPV_vs_V0A_vs_occup_kNoCollInTimeRangeStandard_extraCuts"), multV0A, nPV, occupancy); + histos.fill(HIST("nPV_vs_FT0C_vs_occup_kNoCollInTimeRangeStandard_extraCuts"), multT0C, nPV, occupancy); + } + } + if (col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + histos.fill(HIST("nTracksPV_vs_V0A_kNoCollInTimeRangeNarrow"), multV0A, nPV); + histos.fill(HIST("nTracksGlobal_vs_V0A_kNoCollInTimeRangeNarrow"), multV0A, nGlobalTracks); + histos.fill(HIST("nTracksGlobal_vs_nPV_kNoCollInTimeRangeNarrow"), nPV, nGlobalTracks); + if (occupancy >= 0) + histos.fill(HIST("nTracksGlobal_vs_nPV_vs_occup_kNoCollInTimeRangeNarrow"), nPV, nGlobalTracks, occupancy); + } + if (occupancy >= 0 && occupancy < 250) { + histos.fill(HIST("nTracksPV_vs_V0A_occup_0_250"), multV0A, nPV); + histos.fill(HIST("nTracksGlobal_vs_V0A_occup_0_250"), multV0A, nGlobalTracks); + histos.fill(HIST("nTracksGlobal_vs_nPV_occup_0_250"), nPV, nGlobalTracks); + } + if (occupancy >= 0 && occupancy < 500) { + histos.fill(HIST("nTracksPV_vs_V0A_occup_0_500"), multV0A, nPV); + histos.fill(HIST("nTracksGlobal_vs_V0A_occup_0_500"), multV0A, nGlobalTracks); + histos.fill(HIST("nTracksGlobal_vs_nPV_occup_0_500"), nPV, nGlobalTracks); + } + if (occupancy >= 0 && occupancy < 750) { + histos.fill(HIST("nTracksPV_vs_V0A_occup_0_750"), multV0A, nPV); + histos.fill(HIST("nTracksGlobal_vs_V0A_occup_0_750"), multV0A, nGlobalTracks); + histos.fill(HIST("nTracksGlobal_vs_nPV_occup_0_750"), nPV, nGlobalTracks); + } + if (occupancy >= 0 && occupancy < 2000) { + histos.fill(HIST("nTracksGlobal_vs_nPV_occup_0_2000"), nPV, nGlobalTracks); + } + // ### now vs FT0C occupancy: + float occupByFT0C = col.ft0cOccupancyInTimeRange(); + if (occupByFT0C >= 0 && occupByFT0C < 2500) { + histos.fill(HIST("nTracksGlobal_vs_nPV_occupByFT0C_0_2500"), nPV, nGlobalTracks); + } + if (occupByFT0C >= 0 && occupByFT0C < 20000) { + histos.fill(HIST("nTracksGlobal_vs_nPV_occupByFT0C_0_20000"), nPV, nGlobalTracks); + } + // + if (occupancy >= 0 && occupancy < 500 && col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + histos.fill(HIST("nTracksPV_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard"), multV0A, nPV); + histos.fill(HIST("nTracksGlobal_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard"), multV0A, nGlobalTracks); + histos.fill(HIST("nTracksGlobal_vs_nPV_occup_0_500_kNoCollInTimeRangeStandard"), nPV, nGlobalTracks); + } + if (occupancy >= 0 && occupancy < 500 && col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + histos.fill(HIST("nTracksPV_vs_V0A_occup_0_500_kNoCollInTimeRangeNarrow"), multV0A, nPV); + histos.fill(HIST("nTracksGlobal_vs_V0A_occup_0_500_kNoCollInTimeRangeNarrow"), multV0A, nGlobalTracks); + histos.fill(HIST("nTracksGlobal_vs_nPV_occup_0_500_kNoCollInTimeRangeNarrow"), nPV, nGlobalTracks); + } + if (occupancy >= 0 && occupancy < 500 && col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) && col.selection_bit(kNoSameBunchPileup) && col.selection_bit(kIsGoodZvtxFT0vsPV)) { + histos.fill(HIST("nTracksPV_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard_extraCuts"), multV0A, nPV); + histos.fill(HIST("nTracksGlobal_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard_extraCuts"), multV0A, nGlobalTracks); + histos.fill(HIST("nTracksGlobal_vs_nPV_occup_0_500_kNoCollInTimeRangeStandard_extraCuts"), nPV, nGlobalTracks); + } + if (occupancy >= 0 && occupancy < 2000 && col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) && col.selection_bit(kNoSameBunchPileup) && col.selection_bit(kIsGoodZvtxFT0vsPV)) { + histos.fill(HIST("nTracksGlobal_vs_nPV_occup_0_2000_kNoCollInTimeRangeStandard_extraCuts"), nPV, nGlobalTracks); + } + + // more checks + if (occupancy >= 750) { + histos.fill(HIST("nTracksPV_vs_V0A_occup_ABOVE_750"), multV0A, nPV); + histos.fill(HIST("nTracksGlobal_vs_V0A_occup_ABOVE_750"), multV0A, nGlobalTracks); + histos.fill(HIST("nTracksGlobal_vs_nPV_occup_ABOVE_750"), nPV, nGlobalTracks); + } + if (occupancy == -1) { + histos.fill(HIST("nTracksPV_vs_V0A_occup_Minus1"), multV0A, nPV); + histos.fill(HIST("nTracksGlobal_vs_V0A_occup_Minus1"), multV0A, nGlobalTracks); + histos.fill(HIST("nTracksGlobal_vs_nPV_occup_Minus1"), nPV, nGlobalTracks); + } + if (!col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + histos.fill(HIST("nTracksPV_vs_V0A_AntiNoCollInTimeRangeStandard"), multV0A, nPV); + histos.fill(HIST("nTracksGlobal_vs_V0A_AntiNoCollInTimeRangeStandard"), multV0A, nGlobalTracks); + histos.fill(HIST("nTracksGlobal_vs_nPV_AntiNoCollInTimeRangeStandard"), nPV, nGlobalTracks); + } + if (!col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + histos.fill(HIST("nTracksPV_vs_V0A_AntiNoCollInTimeRangeNarrow"), multV0A, nPV); + histos.fill(HIST("nTracksGlobal_vs_V0A_AntiNoCollInTimeRangeNarrow"), multV0A, nGlobalTracks); + histos.fill(HIST("nTracksGlobal_vs_nPV_AntiNoCollInTimeRangeNarrow"), nPV, nGlobalTracks); + } + } + } + PROCESS_SWITCH(DetectorOccupancyQaTask, processRun3, "Process Run3 tracking vs detector occupancy QA", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/DPG/Tasks/AOTEvent/eventSelectionQa.cxx b/DPG/Tasks/AOTEvent/eventSelectionQa.cxx index 024ca6bbe63..854314837e8 100644 --- a/DPG/Tasks/AOTEvent/eventSelectionQa.cxx +++ b/DPG/Tasks/AOTEvent/eventSelectionQa.cxx @@ -9,7 +9,15 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "map" +/// \file eventSelectionQa.cxx +/// \brief Event selection QA task +/// +/// \author Evgeny Kryshen + +#include +#include +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -21,6 +29,13 @@ #include "CommonDataFormat/BunchFilling.h" #include "DataFormatsParameters/GRPLHCIFData.h" #include "DataFormatsParameters/GRPECSObject.h" +#include "DataFormatsParameters/AggregatedRunInfo.h" +#include "DataFormatsITSMFT/NoiseMap.h" // missing include in TimeDeadMap.h +#include "DataFormatsITSMFT/TimeDeadMap.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "ReconstructionDataFormats/Vertex.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "ITSMFTReconstruction/ChipMappingITS.h" #include "TH1F.h" #include "TH2F.h" @@ -32,30 +47,29 @@ using BCsRun2 = soa::Join; using ColEvSels = soa::Join; using FullTracksIU = soa::Join; +using FullTracksIUwithLabels = soa::Join; struct EventSelectionQaTask { Configurable isMC{"isMC", 0, "0 - data, 1 - MC"}; - Configurable nGlobalBCs{"nGlobalBCs", 100000, "number of global bcs"}; - Configurable minOrbitConf{"minOrbit", 0, "minimum orbit"}; - Configurable nOrbitsConf{"nOrbits", 10000, "number of orbits"}; + Configurable nGlobalBCs{"nGlobalBCs", 100000, "number of global bcs for detailed monitoring"}; Configurable isLowFlux{"isLowFlux", 1, "1 - low flux (pp, pPb), 0 - high flux (PbPb)"}; - uint64_t minGlobalBC = 0; Service ccdb; HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - bool* applySelection = NULL; - int nBCsPerOrbit = 3564; - int lastRunNumber = -1; - int nOrbits = nOrbitsConf; - double minOrbit = minOrbitConf; - int64_t bcSOR = 0; // global bc of the start of the first orbit, setting 0 by default for unanchored MC - int64_t nBCsPerTF = 128 * nBCsPerOrbit; // duration of TF in bcs, should be 128*3564 or 32*3564, setting 128 orbits by default sfor unanchored MC - std::bitset beamPatternA; - std::bitset beamPatternC; - std::bitset bcPatternA; - std::bitset bcPatternC; - std::bitset bcPatternB; + static const int32_t nBCsPerOrbit = o2::constants::lhc::LHCMaxBunches; + int32_t lastRun = -1; + int64_t nOrbits = 1; // number of orbits, setting 1 for unanchored MC + int64_t orbitSOR = 0; // first orbit, setting 0 for unanchored MC + int64_t bcSOR = 0; // global bc of the start of the first orbit, setting 0 for unanchored MC + int32_t nOrbitsPerTF = 128; // 128 in 2022, 32 in 2023, setting 128 for unanchored MC + int64_t nBCsPerTF = nOrbitsPerTF * nBCsPerOrbit; // duration of TF in bcs + int rofOffset = -1; // ITS ROF offset, in bc + int rofLength = -1; // ITS ROF length, in bc + + std::bitset bcPatternA; + std::bitset bcPatternC; + std::bitset bcPatternB; SliceCache cache; Partition tracklets = (aod::track::trackType == static_cast(o2::aod::track::TrackTypeEnum::Run2Tracklet)); @@ -75,9 +89,6 @@ struct EventSelectionQaTask { void init(InitContext&) { - minGlobalBC = uint64_t(minOrbit) * nBCsPerOrbit; - - // ccdb->setURL("http://ccdb-test.cern.ch:8080"); ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); @@ -276,17 +287,22 @@ struct EventSelectionQaTask { histos.add("hNcontribAccTRD", "", kTH1F, {axisNcontrib}); histos.add("hNcontribMisTOF", "", kTH1F, {axisNcontrib}); - histos.add("hMultT0MVsNcontribAcc", "", kTH2F, {axisMultT0M, axisNcontrib}); // before ITS RO Frame border cut - histos.add("hMultT0MVsNcontribCut", "", kTH2F, {axisMultT0M, axisNcontrib}); // after ITS RO Frame border cut + histos.add("hMultT0MVsNcontribTVX", "", kTH2F, {axisMultT0M, axisNcontrib}); // before ITS RO Frame border cut + histos.add("hMultT0MVsNcontribTVXTFcuts", "", kTH2F, {axisMultT0M, axisNcontrib}); // before ITS RO Frame border cut + histos.add("hMultT0MVsNcontribTVXROFcuts", "", kTH2F, {axisMultT0M, axisNcontrib}); // after ITS RO Frame border cut + histos.add("hMultT0MVsNcontribTVXTFROFcuts", "", kTH2F, {axisMultT0M, axisNcontrib}); // after ITS RO Frame border cut + // histos.add("hMultT0MVsNcontribAcc", "", kTH2F, {axisMultT0M, axisNcontrib}); // before ITS RO Frame border cut - histos.add("hMultV0AVsNcontribAcc", "", kTH2F, {axisMultV0A, axisNcontrib}); // before ITS RO Frame border cut - histos.add("hMultV0AVsNcontribCut", "", kTH2F, {axisMultV0A, axisNcontrib}); // after ITS RO Frame border cut - histos.add("hMultV0AVsNcontribAfterVertex", "", kTH2F, {axisMultV0A, axisNcontrib}); // after good vertex cut - histos.add("hMultV0AVsNcontribGood", "", kTH2F, {axisMultV0A, axisNcontrib}); // after pileup check + histos.add("hMultV0AVsNcontribTVX", "", kTH2F, {axisMultV0A, axisNcontrib}); // before ITS RO Frame border cut + histos.add("hMultV0AVsNcontribTVXTFcuts", "", kTH2F, {axisMultV0A, axisNcontrib}); // before ITS RO Frame border cut + histos.add("hMultV0AVsNcontribTVXROFcuts", "", kTH2F, {axisMultV0A, axisNcontrib}); // before ITS RO Frame border cut + histos.add("hMultV0AVsNcontribTVXTFROFcuts", "", kTH2F, {axisMultV0A, axisNcontrib}); // after ITS RO Frame border cut + histos.add("hMultV0AVsNcontribIsVertexITSTPC", "", kTH2F, {axisMultV0A, axisNcontrib}); // after good vertex cut + histos.add("hMultV0AVsNcontribGood", "", kTH2F, {axisMultV0A, axisNcontrib}); // after pileup check - histos.add("hBcForMultV0AVsNcontribAcc", "", kTH1F, {axisBCs}); // bc distribution for V0A-vs-Ncontrib accepted - histos.add("hBcForMultV0AVsNcontribOutliers", "", kTH1F, {axisBCs}); // bc distribution for V0A-vs-Ncontrib outliers - histos.add("hBcForMultV0AVsNcontribCut", "", kTH1F, {axisBCs}); // bc distribution for V0A-vs-Ncontrib after ITS-ROF border cut + // histos.add("hFoundBcForMultV0AVsNcontribAcc", "", kTH1F, {axisBCs}); // bc distribution for V0A-vs-Ncontrib accepted + histos.add("hFoundBcForMultV0AVsNcontribOutliers", "", kTH1F, {axisBCs}); // bc distribution for V0A-vs-Ncontrib outliers + histos.add("hFoundBcAfterROFborderCut", "", kTH1F, {axisBCs}); // bc distribution for V0A-vs-Ncontrib after ITS-ROF border cut histos.add("hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); // FT0-vertex vs z-vertex from collisions histos.add("hVtxFT0MinusVtxCol", "", kTH1F, {axisVtxZ}); // FT0-vertex minus z-vertex from collisions @@ -303,6 +319,11 @@ struct EventSelectionQaTask { histos.add("hVertexXMC", "", kTH1F, {axisVtxXY}); histos.add("hVertexYMC", "", kTH1F, {axisVtxXY}); histos.add("hVertexZMC", "", kTH1F, {axisVtxZ}); + histos.add("hNcontribColFromMC", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribAccFromMC", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribMisFromMC", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribColFromData", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribAccFromData", "", kTH1F, {axisNcontrib}); for (int i = 0; i < kNsel; i++) { histos.get(HIST("hSelCounter"))->GetXaxis()->SetBinLabel(i + 1, selectionLabels[i]); @@ -313,6 +334,31 @@ struct EventSelectionQaTask { histos.get(HIST("hColCounterAcc"))->GetXaxis()->SetBinLabel(i + 1, aliasLabels[i].data()); histos.get(HIST("hBcCounterAll"))->GetXaxis()->SetBinLabel(i + 1, aliasLabels[i].data()); } + + // ROF border QA + histos.add("ITSROFborderQA/hFoundBC_kTVX_counter_ITSTPCtracks", "", kTH1D, {axisBCs}); + histos.add("ITSROFborderQA/hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks", "", kTH1D, {axisBCs}); + + // occupancy QA + if (!isLowFlux) { + histos.add("occupancyQA/hOccupancyByTracks", "", kTH1D, {{15002, -1.5, 15000.5}}); + histos.add("occupancyQA/hOccupancyByFT0C", "", kTH1D, {{15002, -20, 150000}}); + histos.add("occupancyQA/hOccupancyByFT0CvsByTracks", "", kTH2D, {{150, 0, 15000}, {150, 0, 150000}}); + + // 3D histograms: nGlobalTracks with cls567 as y-axis, V0A as x-axis: + const AxisSpec axisNtracks{160, -0.5, 4000 - 0.5, "n tracks"}; + const AxisSpec axisNtracksGlobal{120, -0.5, 3000 - 0.5, "n tracks"}; + const AxisSpec axisMultV0AForOccup{20, 0., static_cast(200000), "mult V0A"}; + const AxisSpec axisOccupancyTracks{150, 0., 15000, "occupancy (n ITS tracks weighted)"}; + histos.add("occupancyQA/hNumTracksPV_vs_V0A_vs_occupancy", "", kTH3F, {axisMultV0AForOccup, axisNtracks, axisOccupancyTracks}); + histos.add("occupancyQA/hNumTracksPVTPC_vs_V0A_vs_occupancy", "", kTH3F, {axisMultV0AForOccup, axisNtracksGlobal, axisOccupancyTracks}); + + histos.add("occupancyQA/hITSTracks_ev1_vs_ev2_2coll_in_ROF", ";nITStracks event #1;nITStracks event #2", kTH2D, {{200, 0., 6000}, {200, 0., 6000}}); + histos.add("occupancyQA/hITSTracks_ev1_vs_ev2_2coll_in_ROF_UPC", ";nITStracks event #1;nITStracks event #2", kTH2D, {{41, -0.5, 40.5}, {41, -0.5, 40.5}}); + histos.add("occupancyQA/hITSTracks_ev1_vs_ev2_2coll_in_ROF_nonUPC", ";nITStracks event #1;nITStracks event #2", kTH2D, {{200, 0., 6000}, {200, 0., 6000}}); + + histos.add("occupancyQA/dEdx_vs_centr_vs_occup_narrow_p_win", "dE/dx", kTH3F, {{20, 0, 4000, "n PV tracks"}, {60, 0, 15000, "occupancy"}, {800, 0.0, 800.0, "dE/dx (a. u.)"}}); + } } void processRun2( @@ -325,25 +371,28 @@ struct EventSelectionQaTask { aod::FDDs const&) { bool isINT1period = 0; - if (!applySelection) { - auto first_bc = bcs.iteratorAt(0); - EventSelectionParams* par = ccdb->getForTimeStamp("EventSelection/EventSelectionParams", first_bc.timestamp()); - applySelection = par->GetSelection(0); + + int run = bcs.iteratorAt(0).runNumber(); + if (run != lastRun) { + lastRun = run; + auto firstBC = bcs.iteratorAt(0); + EventSelectionParams* par = ccdb->getForTimeStamp("EventSelection/EventSelectionParams", firstBC.timestamp()); + bool* applySelection = par->getSelection(0); for (int i = 0; i < kNsel; i++) { histos.get(HIST("hSelMask"))->SetBinContent(i + 1, applySelection[i]); } - isINT1period = first_bc.runNumber() <= 136377 || (first_bc.runNumber() >= 144871 && first_bc.runNumber() <= 159582); + isINT1period = run <= 136377 || (run >= 144871 && run <= 159582); } // bc-based event selection qa - for (auto& bc : bcs) { + for (const auto& bc : bcs) { for (int iAlias = 0; iAlias < kNaliases; iAlias++) { histos.fill(HIST("hBcCounterAll"), iAlias, bc.alias_bit(iAlias)); } } // collision-based event selection qa - for (auto& col : cols) { + for (const auto& col : cols) { bool sel1 = col.selection_bit(kIsINT1) && col.selection_bit(kNoBGV0A) && col.selection_bit(kNoBGV0C) && col.selection_bit(kNoTPCLaserWarmUp) && col.selection_bit(kNoTPCHVdip); for (int iAlias = 0; iAlias < kNaliases; iAlias++) { @@ -367,26 +416,26 @@ struct EventSelectionQaTask { histos.fill(HIST("hSelCounter"), i, col.selection_bit(i)); } - auto bc = col.bc_as(); + const auto& bc = col.bc_as(); uint64_t globalBC = bc.globalBC(); // uint64_t orbit = globalBC / nBCsPerOrbit; int localBC = globalBC % nBCsPerOrbit; - histos.fill(HIST("hGlobalBcAll"), globalBC - minGlobalBC); - // histos.fill(HIST("hOrbitAll"), orbit - minOrbit); + histos.fill(HIST("hGlobalBcAll"), globalBC - bcSOR); + // histos.fill(HIST("hOrbitAll"), orbit - orbitSOR); histos.fill(HIST("hBcAll"), localBC); if (col.selection_bit(kIsBBV0A) || col.selection_bit(kIsBBV0C)) { - histos.fill(HIST("hGlobalBcFV0"), globalBC - minGlobalBC); - // histos.fill(HIST("hOrbitFV0"), orbit - minOrbit); + histos.fill(HIST("hGlobalBcFV0"), globalBC - bcSOR); + // histos.fill(HIST("hOrbitFV0"), orbit - orbitSOR); histos.fill(HIST("hBcFV0"), localBC); } if (col.selection_bit(kIsBBT0A) || col.selection_bit(kIsBBT0C)) { - histos.fill(HIST("hGlobalBcFT0"), globalBC - minGlobalBC); - // histos.fill(HIST("hOrbitFT0"), orbit - minOrbit); + histos.fill(HIST("hGlobalBcFT0"), globalBC - bcSOR); + // histos.fill(HIST("hOrbitFT0"), orbit - orbitSOR); histos.fill(HIST("hBcFT0"), localBC); } if (col.selection_bit(kIsBBFDA) || col.selection_bit(kIsBBFDC)) { - histos.fill(HIST("hGlobalBcFDD"), globalBC - minGlobalBC); - // histos.fill(HIST("hOrbitFDD"), orbit - minOrbit); + histos.fill(HIST("hGlobalBcFDD"), globalBC - bcSOR); + // histos.fill(HIST("hOrbitFDD"), orbit - orbitSOR); histos.fill(HIST("hBcFDD"), localBC); } @@ -439,10 +488,11 @@ struct EventSelectionQaTask { float multT0C = bc.has_ft0() ? bc.ft0().sumAmpC() : -999.f; if (bc.has_fdd()) { - for (auto amplitude : bc.fdd().chargeA()) { + auto fdd = bc.fdd(); + for (const auto& amplitude : fdd.chargeA()) { multFDA += amplitude; } - for (auto amplitude : bc.fdd().chargeC()) { + for (const auto& amplitude : fdd.chargeC()) { multFDC += amplitude; } } @@ -523,65 +573,128 @@ struct EventSelectionQaTask { aod::FT0s const&, aod::FDDs const&) { - int runNumber = bcs.iteratorAt(0).runNumber(); - uint32_t nOrbitsPerTF = 128; // 128 in 2022, 32 in 2023 - if (runNumber != lastRunNumber) { - lastRunNumber = runNumber; // do it only once - int64_t tsSOR = 0; - int64_t tsEOR = 1; - - if (runNumber >= 500000) { // access CCDB for data or anchored MC only + int run = bcs.iteratorAt(0).runNumber(); + + if (run != lastRun) { + lastRun = run; + int64_t tsSOR = 0; // dummy start-of-run timestamp for unanchored MC + int64_t tsEOR = 1; // dummy end-of-run timestamp for unanchored MC + if (run >= 500000) { + auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), run); + // first bc of the first orbit + bcSOR = runInfo.orbitSOR * nBCsPerOrbit; + // duration of TF in bcs + nBCsPerTF = runInfo.orbitsPerTF * nBCsPerOrbit; + // number of orbits per TF + nOrbitsPerTF = runInfo.orbitsPerTF; + // first orbit + orbitSOR = runInfo.orbitSOR; + // total number of orbits + nOrbits = runInfo.orbitEOR - runInfo.orbitSOR; + // start-of-run timestamp + tsSOR = runInfo.sor; + // end-of-run timestamp + tsEOR = runInfo.eor; + + // extract ITS ROF parameters int64_t ts = bcs.iteratorAt(0).timestamp(); - - // access colliding and beam-gas bc patterns - auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", ts); - beamPatternA = grplhcif->getBunchFilling().getBeamPattern(0); - beamPatternC = grplhcif->getBunchFilling().getBeamPattern(1); + auto alppar = ccdb->getForTimeStamp>("ITS/Config/AlpideParam", ts); + rofOffset = alppar->roFrameBiasInBC; + rofLength = alppar->roFrameLengthInBC; + LOGP(debug, "rofOffset={} rofLength={}", rofOffset, rofLength); + + // bc patterns + auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", (tsSOR + tsEOR) / 2); + auto beamPatternA = grplhcif->getBunchFilling().getBeamPattern(0); + auto beamPatternC = grplhcif->getBunchFilling().getBeamPattern(1); bcPatternA = beamPatternA & ~beamPatternC; bcPatternC = ~beamPatternA & beamPatternC; bcPatternB = beamPatternA & beamPatternC; + // fill once for (int i = 0; i < nBCsPerOrbit; i++) { - if (bcPatternA[i]) { - histos.fill(HIST("hBcA"), i); + histos.fill(HIST("hBcA"), i, bcPatternA[i] ? 1. : 0.); + histos.fill(HIST("hBcB"), i, bcPatternB[i] ? 1. : 0.); + histos.fill(HIST("hBcC"), i, bcPatternC[i] ? 1. : 0.); + } + + // fill ITS dead maps + o2::itsmft::TimeDeadMap* itsDeadMap = ccdb->getForTimeStamp("ITS/Calib/TimeDeadMap", (tsSOR + tsEOR) / 2); + auto itsDeadMapOrbits = itsDeadMap->getEvolvingMapKeys(); // roughly every second, ~350 TFs = 350x32 orbits + if (itsDeadMapOrbits.size() > 0) { + std::vector itsDeadMapOrbitsDouble(itsDeadMapOrbits.begin(), itsDeadMapOrbits.end()); + const AxisSpec axisItsDeadMapOrbits{itsDeadMapOrbitsDouble}; + + for (int l = 0; l < o2::itsmft::ChipMappingITS::NLayers; l++) { + int nChips = o2::itsmft::ChipMappingITS::getNChipsOnLayer(l); + double idFirstChip = o2::itsmft::ChipMappingITS::getFirstChipsOnLayer(l); + // int nStaves = o2::itsmft::ChipMappingITS::getNStavesOnLr(l); + // double idFirstStave = o2::itsmft::ChipMappingITS::getFirstStavesOnLr(l); + histos.add(Form("hDeadChipsVsOrbitL%d", l), Form(";orbit; chip; Layer %d", l), kTH2C, {axisItsDeadMapOrbits, {nChips, idFirstChip, idFirstChip + nChips}}); + histos.add(Form("hNumberOfInactiveChipsVsOrbitL%d", l), Form(";orbit; Layer %d", l), kTH1I, {axisItsDeadMapOrbits}); } - if (bcPatternC[i]) { - histos.fill(HIST("hBcC"), i); + + std::vector vClosest; + std::bitset alwaysDeadChips; + std::bitset deadChips; + alwaysDeadChips.set(); + for (const auto& orbit : itsDeadMapOrbits) { + itsDeadMap->getMapAtOrbit(orbit, vClosest); + deadChips.reset(); + for (size_t iel = 0; iel < vClosest.size(); iel++) { + uint16_t w1 = vClosest[iel]; + bool isLastInSequence = (w1 & 0x8000) == 0; + uint16_t w2 = isLastInSequence ? w1 + 1 : vClosest[iel + 1]; + uint16_t chipId1 = w1 & 0x7FFF; + uint16_t chipId2 = w2 & 0x7FFF; + // dead chips are stored as ranges + // vClosest contains first and last chip ids in the range + // last chip id in the range is marked with 0x8000 bit set to 1 + for (int chipId = chipId1; chipId < chipId2; chipId++) { + histos.fill(HIST("hDeadChipsVsOrbitL0"), orbit, chipId, 1); + histos.fill(HIST("hDeadChipsVsOrbitL1"), orbit, chipId, 1); + histos.fill(HIST("hDeadChipsVsOrbitL2"), orbit, chipId, 1); + histos.fill(HIST("hDeadChipsVsOrbitL3"), orbit, chipId, 1); + histos.fill(HIST("hDeadChipsVsOrbitL4"), orbit, chipId, 1); + histos.fill(HIST("hDeadChipsVsOrbitL5"), orbit, chipId, 1); + histos.fill(HIST("hDeadChipsVsOrbitL6"), orbit, chipId, 1); + deadChips.set(chipId); + } + } + alwaysDeadChips &= deadChips; // chips active in the current orbit are set to 0 } - if (bcPatternB[i]) { - histos.fill(HIST("hBcB"), i); + // std::cout << alwaysDeadChips << std::endl; + + // filling histograms with number of inactive chips per layer vs orbit (ignoring always inactive) + for (const auto& orbit : itsDeadMapOrbits) { + itsDeadMap->getMapAtOrbit(orbit, vClosest); + std::vector nInactiveChips(o2::itsmft::ChipMappingITS::NLayers, 0); + for (size_t iel = 0; iel < vClosest.size(); iel++) { + uint16_t w1 = vClosest[iel]; + bool isLastInSequence = (w1 & 0x8000) == 0; + uint16_t w2 = isLastInSequence ? w1 + 1 : vClosest[iel + 1]; + uint16_t chipId1 = w1 & 0x7FFF; + uint16_t chipId2 = w2 & 0x7FFF; + for (int chipId = chipId1; chipId < chipId2; chipId++) { + if (alwaysDeadChips[chipId]) // skip always inactive chips + continue; + int32_t layer = o2::itsmft::ChipMappingITS::getLayer(chipId); + nInactiveChips[layer]++; + } + } + histos.fill(HIST("hNumberOfInactiveChipsVsOrbitL0"), orbit, nInactiveChips[0]); + histos.fill(HIST("hNumberOfInactiveChipsVsOrbitL1"), orbit, nInactiveChips[1]); + histos.fill(HIST("hNumberOfInactiveChipsVsOrbitL2"), orbit, nInactiveChips[2]); + histos.fill(HIST("hNumberOfInactiveChipsVsOrbitL3"), orbit, nInactiveChips[3]); + histos.fill(HIST("hNumberOfInactiveChipsVsOrbitL4"), orbit, nInactiveChips[4]); + histos.fill(HIST("hNumberOfInactiveChipsVsOrbitL5"), orbit, nInactiveChips[5]); + histos.fill(HIST("hNumberOfInactiveChipsVsOrbitL6"), orbit, nInactiveChips[6]); } } - - EventSelectionParams* par = ccdb->getForTimeStamp("EventSelection/EventSelectionParams", ts); - // access orbit-reset timestamp - auto ctpx = ccdb->getForTimeStamp>("CTP/Calib/OrbitReset", ts); - int64_t tsOrbitReset = (*ctpx)[0]; // us - // access TF duration, start-of-run and end-of-run timestamps from ECS GRP - std::map metadata; - metadata["runNumber"] = Form("%d", runNumber); - auto grpecs = ccdb->getSpecific("GLO/Config/GRPECS", ts, metadata); - nOrbitsPerTF = grpecs->getNHBFPerTF(); // assuming 1 orbit = 1 HBF; nOrbitsPerTF=128 in 2022, 32 in 2023 - tsSOR = grpecs->getTimeStart(); // ms - tsEOR = grpecs->getTimeEnd(); // ms - // calculate SOR and EOR orbits - int64_t orbitSOR = (tsSOR * 1000 - tsOrbitReset) / o2::constants::lhc::LHCOrbitMUS; - int64_t orbitEOR = (tsEOR * 1000 - tsOrbitReset) / o2::constants::lhc::LHCOrbitMUS; - // adjust to the nearest TF edge - orbitSOR = orbitSOR / nOrbitsPerTF * nOrbitsPerTF + par->fTimeFrameOrbitShift; - orbitEOR = orbitEOR / nOrbitsPerTF * nOrbitsPerTF + par->fTimeFrameOrbitShift; - // set nOrbits and minOrbit used for orbit-axis binning - nOrbits = orbitEOR - orbitSOR; - minOrbit = orbitSOR; - // first bc of the first orbit (should coincide with TF start) - bcSOR = orbitSOR * o2::constants::lhc::LHCMaxBunches; - // duration of TF in bcs - nBCsPerTF = nOrbitsPerTF * o2::constants::lhc::LHCMaxBunches; - LOGP(info, "tsOrbitReset={} us, SOR = {} ms, EOR = {} ms, orbitSOR = {}, nBCsPerTF = {}", tsOrbitReset, tsSOR, tsEOR, orbitSOR, nBCsPerTF); - } + } // run >= 500000 // create orbit-axis histograms on the fly with binning based on info from GRP if GRP is available - // otherwise default minOrbit and nOrbits will be used + // otherwise default orbitSOR and nOrbits will be used const AxisSpec axisOrbits{static_cast(nOrbits / nOrbitsPerTF), 0., static_cast(nOrbits), ""}; histos.add("hOrbitAll", "", kTH1F, {axisOrbits}); histos.add("hOrbitCol", "", kTH1F, {axisOrbits}); @@ -596,6 +709,10 @@ struct EventSelectionQaTask { const AxisSpec axisBCinTF{static_cast(nBCsPerTF), 0, static_cast(nBCsPerTF), "bc in TF"}; histos.add("hNcontribVsBcInTF", ";bc in TF; n vertex contributors", kTH1F, {axisBCinTF}); histos.add("hNcontribAfterCutsVsBcInTF", ";bc in TF; n vertex contributors", kTH1F, {axisBCinTF}); + histos.add("hNcolMCVsBcInTF", ";bc in TF; n MC collisions", kTH1F, {axisBCinTF}); + histos.add("hNcolVsBcInTF", ";bc in TF; n collisions", kTH1F, {axisBCinTF}); + histos.add("hNcolVsBcInTFafterTFborderCut", ";bc in TF; n collisions", kTH1F, {axisBCinTF}); + histos.add("hNtvxVsBcInTF", ";bc in TF; n TVX triggers", kTH1F, {axisBCinTF}); double minSec = floor(tsSOR / 1000.); double maxSec = ceil(tsEOR / 1000.); @@ -620,12 +737,12 @@ struct EventSelectionQaTask { break; } deltaIndex++; - const auto& bc_past = bcs.iteratorAt(bc.globalIndex() - deltaIndex); - deltaBC = globalBC - bc_past.globalBC(); + const auto& bcPast = bcs.iteratorAt(bc.globalIndex() - deltaIndex); + deltaBC = globalBC - bcPast.globalBC(); if (deltaBC < maxDeltaBC) { - pastActivityFT0 |= bc_past.has_ft0(); - pastActivityFV0 |= bc_past.has_fv0a(); - pastActivityFDD |= bc_past.has_fdd(); + pastActivityFT0 |= bcPast.has_ft0(); + pastActivityFV0 |= bcPast.has_fv0a(); + pastActivityFDD |= bcPast.has_fdd(); } } @@ -662,7 +779,7 @@ struct EventSelectionQaTask { std::vector vGlobalBCs(nBCs, 0); // bc-based event selection qa - for (auto& bc : bcs) { + for (const auto& bc : bcs) { if (!bc.has_ft0()) continue; float multT0A = bc.ft0().sumAmpA(); @@ -681,7 +798,7 @@ struct EventSelectionQaTask { } // bc-based event selection qa - for (auto& bc : bcs) { + for (const auto& bc : bcs) { for (int iAlias = 0; iAlias < kNaliases; iAlias++) { histos.fill(HIST("hBcCounterAll"), iAlias, bc.alias_bit(iAlias)); } @@ -712,22 +829,22 @@ struct EventSelectionQaTask { histos.fill(HIST("hTimeFDCref"), timeFDC); } - histos.fill(HIST("hGlobalBcAll"), globalBC - minGlobalBC); - histos.fill(HIST("hOrbitAll"), orbit - minOrbit); + histos.fill(HIST("hGlobalBcAll"), globalBC - bcSOR); + histos.fill(HIST("hOrbitAll"), orbit - orbitSOR); histos.fill(HIST("hBcAll"), localBC); if (bc.selection_bit(kIsTriggerTVX)) { - histos.fill(HIST("hOrbitTVX"), orbit - minOrbit); + histos.fill(HIST("hOrbitTVX"), orbit - orbitSOR); histos.fill(HIST("hBcTVX"), localBC); } // FV0 if (bc.has_fv0a()) { - histos.fill(HIST("hGlobalBcFV0"), globalBC - minGlobalBC); - histos.fill(HIST("hOrbitFV0"), orbit - minOrbit); + histos.fill(HIST("hGlobalBcFV0"), globalBC - bcSOR); + histos.fill(HIST("hOrbitFV0"), orbit - orbitSOR); histos.fill(HIST("hBcFV0"), localBC); float multV0A = 0; - for (auto amplitude : bc.fv0a().amplitude()) { + for (const auto& amplitude : bc.fv0a().amplitude()) { multV0A += amplitude; } histos.fill(HIST("hMultV0Aall"), multV0A); @@ -738,8 +855,8 @@ struct EventSelectionQaTask { // FT0 if (bc.has_ft0()) { - histos.fill(HIST("hGlobalBcFT0"), globalBC - minGlobalBC); - histos.fill(HIST("hOrbitFT0"), orbit - minOrbit); + histos.fill(HIST("hGlobalBcFT0"), globalBC - bcSOR); + histos.fill(HIST("hOrbitFT0"), orbit - orbitSOR); histos.fill(HIST("hBcFT0"), localBC); float multT0A = bc.ft0().sumAmpA(); float multT0C = bc.ft0().sumAmpC(); @@ -749,7 +866,10 @@ struct EventSelectionQaTask { histos.fill(HIST("hMultT0Aref"), multT0A); histos.fill(HIST("hMultT0Cref"), multT0C); } - + if (bc.selection_bit(kIsTriggerTVX)) { + int64_t bcInTF = (globalBC - bcSOR) % nBCsPerTF; + histos.fill(HIST("hNtvxVsBcInTF"), bcInTF); + } if (!bc.selection_bit(kNoBGFDA) && bc.selection_bit(kIsTriggerTVX)) { histos.fill(HIST("hMultT0Abga"), multT0A); histos.fill(HIST("hMultT0Cbga"), multT0C); @@ -762,15 +882,17 @@ struct EventSelectionQaTask { // FDD if (bc.has_fdd()) { - histos.fill(HIST("hGlobalBcFDD"), globalBC - minGlobalBC); - histos.fill(HIST("hOrbitFDD"), orbit - minOrbit); + histos.fill(HIST("hGlobalBcFDD"), globalBC - bcSOR); + histos.fill(HIST("hOrbitFDD"), orbit - orbitSOR); histos.fill(HIST("hBcFDD"), localBC); + + auto fdd = bc.fdd(); float multFDA = 0; - for (auto amplitude : bc.fdd().chargeA()) { + for (const auto& amplitude : fdd.chargeA()) { multFDA += amplitude; } float multFDC = 0; - for (auto amplitude : bc.fdd().chargeC()) { + for (const auto& amplitude : fdd.chargeC()) { multFDC += amplitude; } histos.fill(HIST("hMultFDAall"), multFDA); @@ -783,8 +905,8 @@ struct EventSelectionQaTask { // ZDC if (bc.has_zdc()) { - histos.fill(HIST("hGlobalBcZDC"), globalBC - minGlobalBC); - histos.fill(HIST("hOrbitZDC"), orbit - minOrbit); + histos.fill(HIST("hGlobalBcZDC"), globalBC - bcSOR); + histos.fill(HIST("hOrbitZDC"), orbit - orbitSOR); histos.fill(HIST("hBcZDC"), localBC); float multZNA = bc.zdc().energyCommonZNA(); float multZNC = bc.zdc().energyCommonZNC(); @@ -804,7 +926,7 @@ struct EventSelectionQaTask { // map for pileup checks std::vector vCollisionsPerBc(bcs.size(), 0); - for (auto& col : cols) { + for (const auto& col : cols) { if (col.foundBCId() < 0 || col.foundBCId() >= bcs.size()) continue; vCollisionsPerBc[col.foundBCId()]++; @@ -820,10 +942,10 @@ struct EventSelectionQaTask { // to be used for closest TVX (FT0-OR) searches std::map mapGlobalBcWithTVX; std::map mapGlobalBcWithTOR; - for (auto& bc : bcs) { + for (const auto& bc : bcs) { int64_t globalBC = bc.globalBC(); // skip non-colliding bcs for data and anchored runs - if (runNumber >= 500000 && bcPatternB[globalBC % o2::constants::lhc::LHCMaxBunches] == 0) { + if (run >= 500000 && bcPatternB[globalBC % nBCsPerOrbit] == 0) { continue; } if (bc.selection_bit(kIsBBT0A) || bc.selection_bit(kIsBBT0C)) { @@ -853,7 +975,11 @@ struct EventSelectionQaTask { } // collision-based event selection qa - for (auto& col : cols) { + std::vector vFoundGlobalBC(cols.size(), 0); // global BCs for collisions + std::vector vCollVz(cols.size(), 0); // vector with vZ positions for each collision + std::vector vIsSel8(cols.size(), 0); // vector with sel8 decisions + std::vector vTracksITS567perColl(cols.size(), 0); // counter of tracks per collision for occupancy studies + for (const auto& col : cols) { for (int iAlias = 0; iAlias < kNaliases; iAlias++) { if (!col.alias_bit(iAlias)) { continue; @@ -873,47 +999,30 @@ struct EventSelectionQaTask { uint64_t globalBC = bc.globalBC(); uint64_t orbit = globalBC / nBCsPerOrbit; int localBC = globalBC % nBCsPerOrbit; - histos.fill(HIST("hGlobalBcCol"), globalBC - minGlobalBC); - histos.fill(HIST("hOrbitCol"), orbit - minOrbit); + histos.fill(HIST("hGlobalBcCol"), globalBC - bcSOR); + histos.fill(HIST("hOrbitCol"), orbit - orbitSOR); histos.fill(HIST("hBcCol"), localBC); if (col.sel8()) { - histos.fill(HIST("hOrbitAcc"), orbit - minOrbit); + histos.fill(HIST("hOrbitAcc"), orbit - orbitSOR); } + int32_t colIndex = col.globalIndex(); + vFoundGlobalBC[colIndex] = globalBC; + vCollVz[colIndex] = col.posZ(); + vIsSel8[colIndex] = col.sel8(); + // search for nearest ft0a&ft0c entry int32_t indexClosestTVX = findClosest(globalBC, mapGlobalBcWithTVX); int bcDiff = static_cast(globalBC - vGlobalBCs[indexClosestTVX]); - // count tracks of different types - auto tracksGrouped = tracks.sliceBy(perCollision, col.globalIndex()); - int nContributorsAfterEtaTPCCuts = 0; - for (auto& track : tracksGrouped) { - int trackBcDiff = bcDiff + track.trackTime() / o2::constants::lhc::LHCBunchSpacingNS; - if (!track.isPVContributor()) - continue; - if (fabs(track.eta()) < 0.8 && track.tpcNClsFound() > 80 && track.tpcNClsCrossedRows() > 100) - nContributorsAfterEtaTPCCuts++; - if (!track.hasTPC()) - histos.fill(HIST("hITStrackBcDiff"), trackBcDiff); - if (track.hasTOF()) { - histos.fill(HIST("hBcTrackTOF"), (globalBC + TMath::FloorNint(track.trackTime() / o2::constants::lhc::LHCBunchSpacingNS)) % nBCsPerOrbit); - } else if (track.hasTRD()) { - histos.fill(HIST("hBcTrackTRD"), (globalBC + TMath::Nint(track.trackTime() / o2::constants::lhc::LHCBunchSpacingNS)) % nBCsPerOrbit); - } - if (track.hasTOF() || track.hasTRD() || !track.hasITS() || !track.hasTPC() || track.pt() < 1) - continue; - histos.fill(HIST("hTrackBcDiffVsEta"), track.eta(), trackBcDiff); - if (track.eta() < -0.2 || track.eta() > 0.2) - continue; - histos.fill(HIST("hSecondsTVXvsBcDif"), bc.timestamp() / 1000., trackBcDiff); - } - int nContributors = col.numContrib(); float timeRes = col.collisionTimeRes(); int64_t bcInTF = (globalBC - bcSOR) % nBCsPerTF; histos.fill(HIST("hNcontribCol"), nContributors); histos.fill(HIST("hNcontribVsBcInTF"), bcInTF, nContributors); - histos.fill(HIST("hNcontribAfterCutsVsBcInTF"), bcInTF, nContributorsAfterEtaTPCCuts); + histos.fill(HIST("hNcolVsBcInTF"), bcInTF); + if (col.selection_bit(kNoTimeFrameBorder)) + histos.fill(HIST("hNcolVsBcInTFafterTFborderCut"), bcInTF); histos.fill(HIST("hColBcDiffVsNcontrib"), nContributors, bcDiff); histos.fill(HIST("hColTimeResVsNcontrib"), nContributors, timeRes); if (!col.selection_bit(kIsVertexITSTPC)) { @@ -967,7 +1076,7 @@ struct EventSelectionQaTask { // FV0 float multV0A = 0; if (foundBC.has_fv0a()) { - for (auto amplitude : foundBC.fv0a().amplitude()) { + for (const auto& amplitude : foundBC.fv0a().amplitude()) { multV0A += amplitude; } } @@ -975,10 +1084,11 @@ struct EventSelectionQaTask { float multFDA = 0; float multFDC = 0; if (foundBC.has_fdd()) { - for (auto amplitude : foundBC.fdd().chargeA()) { + auto fdd = foundBC.fdd(); + for (const auto& amplitude : fdd.chargeA()) { multFDA += amplitude; } - for (auto amplitude : foundBC.fdd().chargeC()) { + for (const auto& amplitude : fdd.chargeC()) { multFDC += amplitude; } } @@ -995,10 +1105,77 @@ struct EventSelectionQaTask { histos.fill(HIST("hMultZNAcol"), multZNA); histos.fill(HIST("hMultZNCcol"), multZNC); + // count tracks of different types + auto tracksGrouped = tracks.sliceBy(perCollision, colIndex); + int nPV = 0; + int nContributorsAfterEtaTPCCuts = 0; + bool isTVX = col.selection_bit(kIsTriggerTVX); + for (const auto& track : tracksGrouped) { + int trackBcDiff = bcDiff + track.trackTime() / o2::constants::lhc::LHCBunchSpacingNS; + if (!track.isPVContributor()) + continue; + + if (track.itsNCls() >= 5) + vTracksITS567perColl[colIndex]++; + + // high-quality contributors for ROF border QA and occupancy study + if (isTVX && std::fabs(track.eta()) < 0.8 && track.pt() > 0.2 && track.itsNCls() >= 5) { + nPV++; + if (track.tpcNClsFound() > 70 && track.tpcNClsCrossedRows() > 80 && track.itsChi2NCl() < 36 && track.tpcChi2NCl() < 4) { + nContributorsAfterEtaTPCCuts++; + // ROF border QA + histos.fill(HIST("ITSROFborderQA/hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks"), localBC, track.itsNCls()); + histos.fill(HIST("ITSROFborderQA/hFoundBC_kTVX_counter_ITSTPCtracks"), localBC); + } + } + if (!track.hasTPC()) + histos.fill(HIST("hITStrackBcDiff"), trackBcDiff); + if (track.hasTOF()) { + histos.fill(HIST("hBcTrackTOF"), (globalBC + TMath::FloorNint(track.trackTime() / o2::constants::lhc::LHCBunchSpacingNS)) % nBCsPerOrbit); + } else if (track.hasTRD()) { + histos.fill(HIST("hBcTrackTRD"), (globalBC + TMath::Nint(track.trackTime() / o2::constants::lhc::LHCBunchSpacingNS)) % nBCsPerOrbit); + } + if (track.hasTOF() || track.hasTRD() || !track.hasITS() || !track.hasTPC() || track.pt() < 1) + continue; + histos.fill(HIST("hTrackBcDiffVsEta"), track.eta(), trackBcDiff); + if (track.eta() < -0.2 || track.eta() > 0.2) + continue; + histos.fill(HIST("hSecondsTVXvsBcDif"), bc.timestamp() / 1000., trackBcDiff); + } // end of track loop + + histos.fill(HIST("hNcontribAfterCutsVsBcInTF"), bcInTF, nContributorsAfterEtaTPCCuts); + + if (!isLowFlux && col.sel8()) { + int occupancyByTracks = col.trackOccupancyInTimeRange(); + histos.fill(HIST("occupancyQA/hOccupancyByTracks"), occupancyByTracks); + float occupancyByFT0C = col.ft0cOccupancyInTimeRange(); + histos.fill(HIST("occupancyQA/hOccupancyByFT0C"), occupancyByFT0C); + if (occupancyByTracks >= 0) { + histos.fill(HIST("occupancyQA/hOccupancyByFT0CvsByTracks"), occupancyByTracks, occupancyByFT0C); + histos.fill(HIST("occupancyQA/hNumTracksPV_vs_V0A_vs_occupancy"), multV0A, nPV, occupancyByTracks); + histos.fill(HIST("occupancyQA/hNumTracksPVTPC_vs_V0A_vs_occupancy"), multV0A, nContributorsAfterEtaTPCCuts, occupancyByTracks); + + // dE/dx QA for a narrow pT bin + for (const auto& track : tracksGrouped) { + if (!track.isPVContributor()) + continue; + if (std::fabs(track.eta()) < 0.8 && track.pt() > 0.2 && track.itsNCls() >= 5) { + float signedP = track.sign() * track.tpcInnerParam(); + if (std::fabs(signedP) > 0.38 && std::fabs(signedP) < 0.4 && track.tpcNClsFound() > 70 && track.tpcNClsCrossedRows() > 80 && track.itsChi2NCl() < 36 && track.tpcChi2NCl() < 4) { + float dEdx = track.tpcSignal(); + histos.fill(HIST("occupancyQA/dEdx_vs_centr_vs_occup_narrow_p_win"), nPV, occupancyByTracks, dEdx); + } + } + } + } + } + // filling plots for events passing basic TVX selection - if (!col.selection_bit(kIsTriggerTVX)) { + if (!isTVX) { continue; } + histos.fill(HIST("hMultT0MVsNcontribTVX"), multT0A + multT0C, nContributors); + histos.fill(HIST("hMultV0AVsNcontribTVX"), multV0A, nContributors); // z-vertex from FT0 vs PV if (foundBC.has_ft0()) { @@ -1009,9 +1186,16 @@ struct EventSelectionQaTask { int foundLocalBC = foundBC.globalBC() % nBCsPerOrbit; + if (col.selection_bit(kNoITSROFrameBorder)) { + histos.fill(HIST("hMultT0MVsNcontribTVXROFcuts"), multT0A + multT0C, nContributors); + histos.fill(HIST("hMultV0AVsNcontribTVXROFcuts"), multV0A, nContributors); + } + if (col.selection_bit(kNoTimeFrameBorder)) { - histos.fill(HIST("hMultV0AVsNcontribAcc"), multV0A, nContributors); - histos.fill(HIST("hBcForMultV0AVsNcontribAcc"), foundLocalBC); + histos.fill(HIST("hMultT0MVsNcontribTVXTFcuts"), multT0A + multT0C, nContributors); + histos.fill(HIST("hMultV0AVsNcontribTVXTFcuts"), multV0A, nContributors); + + // histos.fill(HIST("hFoundBcForMultV0AVsNcontribAcc"), foundLocalBC); histos.fill(HIST("hFoundBc"), foundLocalBC); histos.fill(HIST("hFoundBcNcontrib"), foundLocalBC, nContributors); if (col.selection_bit(kIsVertexTOFmatched)) { @@ -1019,16 +1203,14 @@ struct EventSelectionQaTask { histos.fill(HIST("hFoundBcNcontribTOF"), foundLocalBC, nContributors); } if (nContributors < 0.043 * multV0A - 860) { - histos.fill(HIST("hBcForMultV0AVsNcontribOutliers"), foundLocalBC); + histos.fill(HIST("hFoundBcForMultV0AVsNcontribOutliers"), foundLocalBC); } if (col.selection_bit(kNoITSROFrameBorder)) { - histos.fill(HIST("hMultV0AVsNcontribCut"), multV0A, nContributors); - histos.fill(HIST("hBcForMultV0AVsNcontribCut"), foundLocalBC); - } - } + histos.fill(HIST("hMultT0MVsNcontribTVXTFROFcuts"), multT0A + multT0C, nContributors); + histos.fill(HIST("hMultV0AVsNcontribTVXTFROFcuts"), multV0A, nContributors); - if (col.selection_bit(kNoITSROFrameBorder)) { - histos.fill(HIST("hMultT0MVsNcontribCut"), multT0A + multT0C, nContributors); + histos.fill(HIST("hFoundBcAfterROFborderCut"), foundLocalBC); + } } // filling plots for accepted events @@ -1037,7 +1219,7 @@ struct EventSelectionQaTask { } if (col.selection_bit(kIsVertexITSTPC)) { - histos.fill(HIST("hMultV0AVsNcontribAfterVertex"), multV0A, nContributors); + histos.fill(HIST("hMultV0AVsNcontribIsVertexITSTPC"), multV0A, nContributors); if (col.selection_bit(kNoSameBunchPileup)) { histos.fill(HIST("hMultV0AVsNcontribGood"), multV0A, nContributors); } @@ -1047,7 +1229,7 @@ struct EventSelectionQaTask { histos.fill(HIST("hMultT0Mpup"), multT0A + multT0C); } - histos.fill(HIST("hMultT0MVsNcontribAcc"), multT0A + multT0C, nContributors); + // histos.fill(HIST("hMultT0MVsNcontribAcc"), multT0A + multT0C, nContributors); histos.fill(HIST("hTimeV0Aacc"), timeV0A); histos.fill(HIST("hTimeZNAacc"), timeZNA); histos.fill(HIST("hTimeZNCacc"), timeZNC); @@ -1064,39 +1246,145 @@ struct EventSelectionQaTask { histos.fill(HIST("hMultZNAacc"), multZNA); histos.fill(HIST("hMultZNCacc"), multZNC); histos.fill(HIST("hNcontribAcc"), nContributors); - } // collisions + + // ### in-ROF occupancy QA + if (!isLowFlux) { + std::vector> vCollsInSameITSROF; + // save indices of collisions in same ROF + for (const auto& col : cols) { + int32_t colIndex = col.globalIndex(); + int64_t foundGlobalBC = vFoundGlobalBC[colIndex]; + int64_t tfId = (foundGlobalBC - bcSOR) / nBCsPerTF; + int64_t rofId = (foundGlobalBC + 3564 - rofOffset) / rofLength; + std::vector vAssocToSameROF; + // find all collisions in the same ROF before a given collision + int32_t minColIndex = colIndex - 1; + while (minColIndex >= 0) { + int64_t thisBC = vFoundGlobalBC[minColIndex]; + // check if this is still the same TF + int64_t thisTFid = (thisBC - bcSOR) / nBCsPerTF; + if (thisTFid != tfId) + break; + int64_t thisRofId = (thisBC + 3564 - rofOffset) / rofLength; + + // check if we are within the same ROF + if (thisRofId != rofId) + break; + vAssocToSameROF.push_back(minColIndex); + minColIndex--; + } + // find all collisions in the same ROF after the current one + int32_t maxColIndex = colIndex + 1; + while (maxColIndex < cols.size()) { + int64_t thisBC = vFoundGlobalBC[maxColIndex]; + int64_t thisTFid = (thisBC - bcSOR) / nBCsPerTF; + if (thisTFid != tfId) + break; + int64_t thisRofId = (thisBC + 3564 - rofOffset) / rofLength; + if (thisRofId != rofId) + break; + vAssocToSameROF.push_back(maxColIndex); + maxColIndex++; + } + vCollsInSameITSROF.push_back(vAssocToSameROF); + } // end of in-ROF occupancy 1st loop + + // nTrack correlations in ROFs with 2 collisions inside + for (const auto& col : cols) { + int32_t colIndex = col.globalIndex(); + if (!col.sel8() || !col.selection_bit(kNoSameBunchPileup)) + continue; + if (vCollsInSameITSROF[colIndex].size() != 1) // analyse only cases with 2 collisions in the same ROF + continue; + float vZ = col.posZ(); + float nPV = vTracksITS567perColl[colIndex]; + + ushort flags = col.flags(); + bool isVertexUPC = flags & dataformats::Vertex>::Flags::UPCMode; // is vertex with UPC settings + + // the second collision in ROF + std::vector vAssocToSameROF = vCollsInSameITSROF[colIndex]; + int thisColIndex = vAssocToSameROF[0]; + float vZassoc = vCollVz[thisColIndex]; // vZ of the second collision in the same ROF + float nPVassoc = vTracksITS567perColl[thisColIndex]; // n PV tracks of the second collision in the same ROF + if (std::fabs(vZ) < 10 && std::fabs(vZassoc) < 10 && thisColIndex > colIndex && vIsSel8[thisColIndex]) { + histos.fill(HIST("occupancyQA/hITSTracks_ev1_vs_ev2_2coll_in_ROF"), nPV, nPVassoc); + if (isVertexUPC) + histos.fill(HIST("occupancyQA/hITSTracks_ev1_vs_ev2_2coll_in_ROF_UPC"), nPV, nPVassoc); + else + histos.fill(HIST("occupancyQA/hITSTracks_ev1_vs_ev2_2coll_in_ROF_nonUPC"), nPV, nPVassoc); + } + } + } // end of in-ROF occupancy QA + + // TVX efficiency after TF and ITS ROF border cuts + for (const auto& col : cols) { + if (!col.selection_bit(kNoTimeFrameBorder) || !col.selection_bit(kNoITSROFrameBorder)) + continue; + + uint32_t nContrib = col.numContrib(); + histos.fill(HIST("hNcontribColFromData"), nContrib); + if (!col.selection_bit(kIsTriggerTVX)) + continue; + + histos.fill(HIST("hNcontribAccFromData"), nContrib); + } } PROCESS_SWITCH(EventSelectionQaTask, processRun3, "Process Run3 event selection QA", false); - void processMCRun3(aod::McCollisions const& mcCols, soa::Join const& cols, BCsRun3 const&, aod::FT0s const&) + Partition pvTracks = ((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)); + void processMCRun3(aod::McCollisions const& mcCols, soa::Join const& cols, FullTracksIUwithLabels const&, BCsRun3 const&, aod::FT0s const&, aod::McParticles const& mcParts) { - for (auto& mcCol : mcCols) { + for (const auto& mcCol : mcCols) { auto bc = mcCol.bc_as(); uint64_t globalBC = bc.globalBC(); uint64_t orbit = globalBC / nBCsPerOrbit; int localBC = globalBC % nBCsPerOrbit; - histos.fill(HIST("hGlobalBcColMC"), globalBC - minGlobalBC); - histos.fill(HIST("hOrbitColMC"), orbit - minOrbit); + int64_t bcInTF = (globalBC - bcSOR) % nBCsPerTF; + histos.fill(HIST("hGlobalBcColMC"), globalBC - bcSOR); + histos.fill(HIST("hOrbitColMC"), orbit - orbitSOR); histos.fill(HIST("hBcColMC"), localBC); histos.fill(HIST("hVertexXMC"), mcCol.posX()); histos.fill(HIST("hVertexYMC"), mcCol.posY()); histos.fill(HIST("hVertexZMC"), mcCol.posZ()); + histos.fill(HIST("hNcolMCVsBcInTF"), bcInTF); } - // check fraction of collisions matched to wrong bcs - for (auto& col : cols) { - if (!col.has_mcCollision()) { - continue; + for (const auto& col : cols) { + int32_t mcColIdFromCollision = col.mcCollisionId(); + // check if collision is built from tracks originating from different MC collisions + bool isCollisionAmbiguous = 0; + const auto& colPvTracks = pvTracks.sliceByCached(aod::track::collisionId, col.globalIndex(), cache); + for (const auto& track : colPvTracks) { + int32_t mcPartId = track.mcParticleId(); + int32_t mcColId = mcPartId >= 0 ? mcParts.iteratorAt(mcPartId).mcCollisionId() : -1; + if (mcColId < 0 || mcColIdFromCollision != mcColId) { + isCollisionAmbiguous = 1; + break; + } } - uint64_t mcBC = col.mcCollision().bc_as().globalBC(); - uint64_t rcBC = col.foundBC_as().globalBC(); + + // skip ambiguous collisions + if (isCollisionAmbiguous) + continue; + + // skip collisions at the borders of TF and ITS ROF + if (!col.selection_bit(kNoTimeFrameBorder) || !col.selection_bit(kNoITSROFrameBorder)) + continue; + + uint32_t nContrib = col.numContrib(); + histos.fill(HIST("hNcontribColFromMC"), nContrib); + if (!col.selection_bit(kIsTriggerTVX)) + continue; + + histos.fill(HIST("hNcontribAccFromMC"), nContrib); + + int64_t rcBC = col.foundBC_as().globalBC(); + int64_t mcBC = col.mcCollision().bc_as().globalBC(); + if (mcBC != rcBC) { - histos.fill(HIST("hNcontribMis"), col.numContrib()); - if (col.collisionTimeRes() < 12) { - // ~ wrong bcs for collisions with T0F-matched tracks - histos.fill(HIST("hNcontribMisTOF"), col.numContrib()); - } + histos.fill(HIST("hNcontribMisFromMC"), nContrib); } } } diff --git a/DPG/Tasks/AOTEvent/lumiQa.cxx b/DPG/Tasks/AOTEvent/lumiQa.cxx index 6e554fc1952..254e58f0b67 100644 --- a/DPG/Tasks/AOTEvent/lumiQa.cxx +++ b/DPG/Tasks/AOTEvent/lumiQa.cxx @@ -30,16 +30,32 @@ struct LumiQaTask { TH1* hCalibT0C = nullptr; static const int nBCsPerOrbit = o2::constants::lhc::LHCMaxBunches; std::bitset bcPatternB; + std::bitset bcPatternA; + std::bitset bcPatternC; + std::bitset beamPatternA; + std::bitset beamPatternC; void init(InitContext&) { ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); + const AxisSpec axisMultZNA{2000, 0., 400., "ZNA multiplicity"}; + const AxisSpec axisMultZNC{2000, 0., 400., "ZNC multiplicity"}; const AxisSpec axisMultT0M{1000, 0., 270000., "T0M multiplicity"}; const AxisSpec axisMultT0A{1000, 0., 200000., "T0A multiplicity"}; const AxisSpec axisMultT0C{1000, 0., 70000., "T0C multiplicity"}; const AxisSpec axisCentT0C{100, 0., 100., "T0C centrality"}; + const AxisSpec axisTime{700, -35., 35., "time (ns)"}; + const AxisSpec axisMultChannelT0A{5000, 0., 5000., "T0A channel multiplicity"}; + const AxisSpec axisMultChannelT0C{5000, 0., 5000., "T0C channel multiplicity"}; + int nChannelsT0A = 96; + int nChannelsT0C = 112; + const AxisSpec axisChannelsT0A{nChannelsT0A, 0, static_cast(nChannelsT0A)}; + const AxisSpec axisChannelsT0C{nChannelsT0C, 0, static_cast(nChannelsT0C)}; + + histos.add("hMultZNA", "", kTH1F, {axisMultZNA}); + histos.add("hMultZNC", "", kTH1F, {axisMultZNC}); histos.add("hMultT0M", "", kTH1F, {axisMultT0M}); histos.add("hMultT0A", "", kTH1F, {axisMultT0A}); histos.add("hMultT0C", "", kTH1F, {axisMultT0C}); @@ -53,43 +69,101 @@ struct LumiQaTask { histos.add("hMultT0CselTVXTCEB", "", kTH1F, {axisMultT0C}); histos.add("hCentT0CselTVXTCEB", "", kTH1F, {axisCentT0C}); + histos.add("hTimeZNA", "", kTH1F, {axisTime}); + histos.add("hTimeZNC", "", kTH1F, {axisTime}); + histos.add("hTimeZNAselTVX", "", kTH1F, {axisTime}); + histos.add("hTimeZNCselTVX", "", kTH1F, {axisTime}); + histos.add("hTimeZNAselB", "", kTH1F, {axisTime}); + histos.add("hTimeZNCselB", "", kTH1F, {axisTime}); + histos.add("hTimeZNAselA", "", kTH1F, {axisTime}); + histos.add("hTimeZNCselA", "", kTH1F, {axisTime}); + histos.add("hTimeZNAselC", "", kTH1F, {axisTime}); + histos.add("hTimeZNCselC", "", kTH1F, {axisTime}); + histos.add("hCounterTCE", "", kTH1D, {{1, 0., 1.}}); histos.add("hCounterZNA", "", kTH1D, {{1, 0., 1.}}); histos.add("hCounterZNC", "", kTH1D, {{1, 0., 1.}}); histos.add("hCounterZEM", "", kTH1D, {{1, 0., 1.}}); + histos.add("hMultT0AperChannel", "", kTH2D, {axisMultChannelT0A, axisChannelsT0A}); + histos.add("hMultT0CperChannel", "", kTH2D, {axisMultChannelT0C, axisChannelsT0C}); } void process(BCsRun3 const& bcs, aod::Zdcs const&, aod::FT0s const&) { int runNumber = bcs.iteratorAt(0).runNumber(); - LOGP(info, "runNumber={}", runNumber); const char* srun = Form("%d", runNumber); if (runNumber != lastRunNumber) { + LOGP(info, "runNumber={}", runNumber); lastRunNumber = runNumber; int64_t ts = bcs.iteratorAt(0).timestamp(); auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", ts); + beamPatternA = grplhcif->getBunchFilling().getBeamPattern(0); + beamPatternC = grplhcif->getBunchFilling().getBeamPattern(1); bcPatternB = grplhcif->getBunchFilling().getBCPattern(); + bcPatternA = beamPatternA & ~beamPatternC; + bcPatternC = ~beamPatternA & beamPatternC; TList* callst = ccdb->getForTimeStamp("Centrality/Estimators", ts); + if (callst == nullptr) { + LOGF(info, "Centrality calibration is not available in CCDB for run=%d at timestamp=%llu", runNumber, ts); + return; + } + hCalibT0C = reinterpret_cast(callst->FindObject("hCalibZeqFT0C")); - } - if (!hCalibT0C) { - return; + if (hCalibT0C == nullptr) { + LOGF(info, "hCalibZeqFT0C histogram is not available for run=%d at timestamp=%llu", runNumber, ts); + return; + } } for (const auto& bc : bcs) { if (bc.has_zdc()) { float timeZNA = bc.zdc().timeZNA(); float timeZNC = bc.zdc().timeZNC(); - if (fabs(timeZNA) < 2) { + float multZNA = bc.zdc().energyCommonZNA(); + float multZNC = bc.zdc().energyCommonZNC(); + + histos.fill(HIST("hMultZNA"), multZNA); + histos.fill(HIST("hMultZNC"), multZNC); + histos.fill(HIST("hTimeZNA"), timeZNA); + histos.fill(HIST("hTimeZNC"), timeZNC); + if (bc.has_ft0() && TESTBIT(bc.ft0().triggerMask(), o2::ft0::Triggers::bitVertex)) { // TVX + histos.fill(HIST("hTimeZNAselTVX"), timeZNA); + histos.fill(HIST("hTimeZNCselTVX"), timeZNC); + } + + if (bcPatternB[bc.globalBC() % nBCsPerOrbit]) { // B-mask + histos.fill(HIST("hTimeZNAselB"), timeZNA); + histos.fill(HIST("hTimeZNCselB"), timeZNC); + } + if (bcPatternA[bc.globalBC() % nBCsPerOrbit]) { // A-mask + histos.fill(HIST("hTimeZNAselA"), timeZNA); + histos.fill(HIST("hTimeZNCselA"), timeZNC); + } + if (bcPatternC[bc.globalBC() % nBCsPerOrbit]) { // C-mask + histos.fill(HIST("hTimeZNAselC"), timeZNA); + histos.fill(HIST("hTimeZNCselC"), timeZNC); + } + + double meanTimeZNA = 0; + double meanTimeZNC = 0; + if (runNumber == 544795) { + meanTimeZNA = 0.49; + meanTimeZNC = -5.19; + } else if (runNumber == 544911) { + meanTimeZNA = -1.44; + meanTimeZNC = -11.39; + } + + if (fabs(timeZNA - meanTimeZNA) < 2) { histos.get(HIST("hCounterZNA"))->Fill(srun, 1); } - if (fabs(timeZNC) < 2) { + if (fabs(timeZNC - meanTimeZNC) < 2) { histos.get(HIST("hCounterZNC"))->Fill(srun, 1); } - if (fabs(timeZNA) < 2 || fabs(timeZNC) < 2) { + if (fabs(timeZNA - meanTimeZNA) < 2 || fabs(timeZNC - meanTimeZNC) < 2) { histos.get(HIST("hCounterZEM"))->Fill(srun, 1); } } @@ -97,6 +171,13 @@ struct LumiQaTask { if (!bc.has_ft0()) { continue; } + for (unsigned int ic = 0; ic < bc.ft0().amplitudeA().size(); ic++) { + histos.fill(HIST("hMultT0AperChannel"), bc.ft0().amplitudeA()[ic], bc.ft0().channelA()[ic]); + } + for (unsigned int ic = 0; ic < bc.ft0().amplitudeC().size(); ic++) { + histos.fill(HIST("hMultT0CperChannel"), bc.ft0().amplitudeC()[ic], bc.ft0().channelC()[ic]); + } + float multT0A = bc.ft0().sumAmpA(); float multT0C = bc.ft0().sumAmpC(); float multT0M = multT0A + multT0C; diff --git a/DPG/Tasks/AOTEvent/matchingQa.cxx b/DPG/Tasks/AOTEvent/matchingQa.cxx new file mode 100644 index 00000000000..b59b8faba0c --- /dev/null +++ b/DPG/Tasks/AOTEvent/matchingQa.cxx @@ -0,0 +1,818 @@ +// 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. + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsFT0/Digit.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "MetadataHelper.h" + +using namespace o2; +using namespace o2::framework; + +using BCsRun3 = soa::Join; +using FullTracksIU = soa::Join; +using FullTracksIUwithLabels = soa::Join; +float bcNS = o2::constants::lhc::LHCBunchSpacingNS; +int32_t nBCsPerOrbit = o2::constants::lhc::LHCMaxBunches; + +MetadataHelper metadataInfo; // Metadata helper + +struct MatchingQaTask { + Service ccdb; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Preslice perCollision = aod::track::collisionId; + Configurable customOrbitOffset{"customOrbitOffset", 0, "customOrbitOffset for MC"}; + Configurable isLowFlux{"isLowFlux", 0, "1 - low flux (pp, pPb), 0 - high flux (PbPb)"}; + Configurable useTimeDiff{"useTimeDiff", 1, "use time difference for selection"}; + Configurable useVtxDiff{"useVtxDiff", 1, "use vertex difference for selection"}; + Configurable removeTOFmatches{"removeTOFmatches", 1, "remove TVX bcs matched to collisions with TOF tracks"}; + Configurable removeHighPtmatches{"removeHighPtmatches", 1, "remove TVX bcs matched to collisions with high-pt ITS-TPC tracks"}; + Configurable removeColsWithAmbiguousTOF{"removeColsWithAmbiguousTOF", 0, "remove collisions with ambiguous TOF signals"}; + Configurable removeNoncollidingBCs{"removeNoncollidingBCs", 1, "Remove TVX from non-colliding bcs"}; + Configurable useITSROFconstraint{"useITSROFconstraint", 1, "use ITS ROF constraints for ITS-TPC vertices"}; + Configurable additionalDeltaBC{"additionalDeltaBC", 0, "Additional BC margin added to deltaBC for ITS-TPC vertices"}; + Configurable deltaBCforTOFcollisions{"deltaBCforTOFcollisions", 1, "bc margin for TOF-matched collisions"}; + Configurable minimumDeltaBC{"minimumDeltaBC", -1, "minimum delta BC for ITS-TPC vertices"}; + Configurable deltaBCforHighPtTracks{"deltaBCforHighPtTracks", 10, "delta BC for high-pt ITS-TPC tracks"}; + + std::bitset bcPatternB; // bc pattern of colliding bunches + int lastRun = -1; + int64_t bcSOR = -1; // global bc of the start of the first orbit + int32_t nBCsPerTF = -1; // duration of TF in bcs, should be 128*3564 or 32*3564 + int32_t offsetITSROF = 64; + int32_t nBCsPerITSROF = 198; + std::vector vFoundBCindex; + std::vector vNumITStracks; + std::vector vNumTOFtracks; + std::vector vNumTRDtracks; + std::vector vNumTPCtracks; + std::vector vNumTPCtracksHighPt; + + bool isGoodBC(int64_t globalBC, bool fillHistos = 0) + { + // kNoTimeFrameBorder + int64_t bcInTF = (globalBC - bcSOR) % nBCsPerTF; + if (fillHistos) + histos.fill(HIST("hBcInTFall"), bcInTF); + if (bcInTF < 300 || bcInTF > nBCsPerTF - 4000) + return 0; + if (fillHistos) + histos.fill(HIST("hBcInTFcut"), bcInTF); + // kNoITSROFrameBorder + uint16_t bcInITSROF = (globalBC + nBCsPerOrbit - offsetITSROF) % nBCsPerITSROF; + if (fillHistos) + histos.fill(HIST("hBcInITSROFall"), bcInITSROF); + if (bcInITSROF < 10 || bcInITSROF > nBCsPerITSROF - 20) + return 0; + if (fillHistos) + histos.fill(HIST("hBcInITSROFcut"), bcInITSROF); + return 1; + } + + void init(InitContext&) + { + if (metadataInfo.isFullyDefined()) { + if (!metadataInfo.isMC()) { + doprocessMC.value = false; + } + } + + const AxisSpec axisNcontrib{isLowFlux ? 200 : 8000, 0., isLowFlux ? 200. : 8000., "n contributors"}; + const AxisSpec axisColTimeRes{1500, 0., 1500., "collision time resolution (ns)"}; + const AxisSpec axisFraction{1000, 0., 1., ""}; + const AxisSpec axisBcDiff{800, -400., 400., "bc diff"}; + const AxisSpec axisBcs{nBCsPerOrbit, 0., static_cast(nBCsPerOrbit), "bc"}; + const AxisSpec axisMultT0C{200, 0., isLowFlux ? 2000. : 60000., "Rec. mult. T0C"}; + const AxisSpec axisZvtxDiff{200, -20., 20., "Zvtx difference, cm"}; + const AxisSpec axisTime{600, -25., 35., "Time, ns"}; + const AxisSpec axisPt{100, 0., 10., "p_{T}, GeV"}; + + histos.add("hTimeT0AHighMultT0C", "", kTH1F, {axisTime}); + histos.add("hTimeT0CHighMultT0C", "", kTH1F, {axisTime}); + histos.add("hTimeV0AHighMultT0C", "", kTH1F, {axisTime}); + histos.add("hTimeFDAHighMultT0C", "", kTH1F, {axisTime}); + histos.add("hTimeFDCHighMultT0C", "", kTH1F, {axisTime}); + + histos.add("hRecMultT0C", "", kTH1D, {axisMultT0C}); + + histos.add("hRecMultT0CvsNcontrib", "", kTH2D, {axisMultT0C, axisNcontrib}); + histos.add("hRecMultT0CvsNcontribTPC", "", kTH2D, {axisMultT0C, axisNcontrib}); + histos.add("hRecMultT0CvsNcontribTOF", "", kTH2D, {axisMultT0C, axisNcontrib}); + histos.add("hRecMultT0CvsNcontribTRD", "", kTH2D, {axisMultT0C, axisNcontrib}); + histos.add("hRecMultT0CvsNcontribTPCHighPt", "", kTH2D, {axisMultT0C, axisNcontrib}); + + histos.add("hBCsITS", "", kTH1F, {axisBcs}); + + histos.add("hNcontribCandidatesHighPt", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribCountsHighPt", "", kTH1F, {axisNcontrib}); + + histos.add("hNcontribCandidates", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribCounts", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribSigma", "", kTH2F, {axisNcontrib, axisColTimeRes}); + + histos.add("hNcontribAll", "", kTH1F, {axisNcontrib}); + + histos.add("hNcontribCol", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribColTOF", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribColTRD", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribColTPC", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribColITS", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribColTPCHighPt", "", kTH1F, {axisNcontrib}); + + histos.add("hNcontribAcc", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribAccTOF", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribAccTRD", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribAccTPC", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribAccITS", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribAccTPCHighPt", "", kTH1F, {axisNcontrib}); + + histos.add("hTrackBcDiffVsPt", "", kTH2F, {axisPt, axisBcDiff}); + histos.add("hTrackBcResVsPt", "", kTH2F, {axisPt, axisBcDiff}); + + histos.add("hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("hColBcDiffVsNcontribTOF", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("hColBcDiffVsNcontribTRD", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("hColBcDiffVsNcontribTPC", "", kTH2F, {axisNcontrib, axisBcDiff}); + + histos.add("hZvtxDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisZvtxDiff}); + histos.add("hZvtxDiffVsNcontribTOF", "", kTH2F, {axisNcontrib, axisZvtxDiff}); + histos.add("hZvtxDiffVsNcontribTPC", "", kTH2F, {axisNcontrib, axisZvtxDiff}); + histos.add("hZvtxDiffVsNcontribTRD", "", kTH2F, {axisNcontrib, axisZvtxDiff}); + + histos.add("hNcontribUnambiguous", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribUnambiguousTOF", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribUnambiguousTRD", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribUnambiguousTPC", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribUnambiguousITS", "", kTH1F, {axisNcontrib}); + + histos.add("hNcontribMis", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribMisTOF", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribMisTRD", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribMisTPC", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribMisITS", "", kTH1F, {axisNcontrib}); + + histos.add("hNcontribColMostlyOk", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribColMostlyOkTOF", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribColMostlyOkTPC", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribColMostlyOkTRD", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribColMostlyOkITS", "", kTH1F, {axisNcontrib}); + + histos.add("hNcontribColMostlyOkMis", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribColMostlyOkMisTOF", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribColMostlyOkMisTPC", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribColMostlyOkMisTRD", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribColMostlyOkMisITS", "", kTH1F, {axisNcontrib}); + + histos.add("hNcontribAllContribAll", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribAllContribWrong", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribAllFractionWrong", "", kTH2F, {axisNcontrib, axisFraction}); + histos.add("hNcontribTvxMostlyOk", "", kTH1F, {axisNcontrib}); + } + + int32_t findClosest(int64_t globalBC, std::map& bcs) + { + auto it = bcs.lower_bound(globalBC); + int64_t bc1 = it->first; + int32_t index1 = it->second; + if (it != bcs.begin()) + --it; + int64_t bc2 = it->first; + int32_t index2 = it->second; + int64_t dbc1 = std::abs(bc1 - globalBC); + int64_t dbc2 = std::abs(bc2 - globalBC); + return (dbc1 <= dbc2) ? index1 : index2; + } + + void process(aod::Collisions const& cols, FullTracksIU const& tracks, BCsRun3 const& bcs, aod::FT0s const& ft0s, aod::FV0As const& /*fv0as*/, aod::FDDs const& /*FDDs*/) + { + int run = bcs.iteratorAt(0).runNumber(); + if (run != lastRun) { + lastRun = run; + auto runDuration = ccdb->getRunDuration(run, true); + int64_t tsSOR = runDuration.first; + auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", tsSOR); + bcPatternB = grplhcif->getBunchFilling().getBCPattern(); + + auto ctpx = ccdb->getForTimeStamp>("CTP/Calib/OrbitReset", tsSOR); + int64_t tsOrbitReset = (*ctpx)[0]; + uint32_t nOrbitsPerTF = run < 534133 ? 128 : 32; + int64_t orbitSOR = (tsSOR * 1000 - tsOrbitReset) / o2::constants::lhc::LHCOrbitMUS; + orbitSOR = orbitSOR / nOrbitsPerTF * nOrbitsPerTF; + bcSOR = orbitSOR * nBCsPerOrbit + customOrbitOffset * nBCsPerOrbit; + nBCsPerTF = nOrbitsPerTF * nBCsPerOrbit; + nBCsPerITSROF = (run >= 543437 && run <= 545367) ? 594 : 198; + const AxisSpec axisBcDiff{800, -400., 400., "bc diff"}; + const AxisSpec axisBcsInTF{nBCsPerTF, 0., static_cast(nBCsPerTF), "bc"}; + const AxisSpec axisBcsInITSROF{nBCsPerITSROF, 0., static_cast(nBCsPerITSROF), "bc"}; + histos.add("hBcInTFall", "", kTH1F, {axisBcsInTF}); + histos.add("hBcInTFcut", "", kTH1F, {axisBcsInTF}); + histos.add("hBcInITSROFall", "", kTH1F, {axisBcsInITSROF}); + histos.add("hBcInITSROFcut", "", kTH1F, {axisBcsInITSROF}); + + histos.add("hBcInTFITS", "", kTH1F, {axisBcsInTF}); + histos.add("hBcInTFTPC", "", kTH1F, {axisBcsInTF}); + + histos.add("hBcInITSROFITS", "", kTH1F, {axisBcsInITSROF}); + histos.add("hBcInITSROFTPC", "", kTH1F, {axisBcsInITSROF}); + + histos.add("hBcInITSROFTPCDiff", "", kTH2F, {axisBcsInITSROF, axisBcDiff}); + } + + int nCols = cols.size(); + vFoundBCindex.resize(nCols); + vNumITStracks.resize(nCols); + vNumTOFtracks.resize(nCols); + vNumTRDtracks.resize(nCols); + vNumTPCtracks.resize(nCols); + vNumTPCtracksHighPt.resize(nCols); + std::fill(vFoundBCindex.begin(), vFoundBCindex.end(), -1); + std::fill(vNumITStracks.begin(), vNumITStracks.end(), 0); + std::fill(vNumTOFtracks.begin(), vNumTOFtracks.end(), 0); + std::fill(vNumTRDtracks.begin(), vNumTRDtracks.end(), 0); + std::fill(vNumTPCtracks.begin(), vNumTPCtracks.end(), 0); + std::fill(vNumTPCtracksHighPt.begin(), vNumTPCtracksHighPt.end(), 0); + + std::vector> vTPCtracksPts(cols.size()); + std::vector> vTOFtracksTimes(cols.size()); + std::vector> vTPCtracksTimes(cols.size()); + std::vector> vITStracksTimes(cols.size()); + std::vector> vTPCtracksTimeRes(cols.size()); + + std::vector vTOFtracksSumWeightedTimes(cols.size(), 0); + std::vector vTRDtracksSumWeightedTimes(cols.size(), 0); + std::vector vTPCtracksSumWeightedTimes(cols.size(), 0); + std::vector vITStracksSumWeightedTimes(cols.size(), 0); + std::vector vTOFtracksSumWeights(cols.size(), 0); + std::vector vTRDtracksSumWeights(cols.size(), 0); + std::vector vTPCtracksSumWeights(cols.size(), 0); + std::vector vITStracksSumWeights(cols.size(), 0); + std::vector vMinTimeTOFtracks(cols.size(), 10000); + std::vector vMaxTimeTOFtracks(cols.size(), -10000); + std::vector vWeightedSigma(cols.size(), 0); + std::map mapGlobalBcWithT0B; + std::map mapGlobalBcWithTVX; + std::map mapGlobalBcVtxZ; + std::map mapGlobalBcMultT0C; + std::map mapGlobalBcVtxZ2; + + int nBCs = bcs.size(); + std::vector vGlobalBCs(nBCs, 0); + + for (auto& bc : bcs) { + vGlobalBCs[bc.globalIndex()] = bc.globalBC(); + } + + for (auto& ft0 : ft0s) { + auto bc = ft0.bc_as(); + int64_t globalBC = bc.globalBC(); + // remove noise from non-colliding bcs + if (removeNoncollidingBCs && bcPatternB[globalBC % o2::constants::lhc::LHCMaxBunches] == 0) + continue; + if (ft0.triggerMask() & BIT(o2::ft0::Triggers::bitVertex)) { + mapGlobalBcWithTVX[globalBC] = bc.globalIndex(); + mapGlobalBcVtxZ[globalBC] = ft0.posZ(); + mapGlobalBcVtxZ2[globalBC] = ft0.posZ(); + mapGlobalBcMultT0C[globalBC] = ft0.sumAmpC(); + } + if (fabs(ft0.timeA()) < 1 && fabs(ft0.timeC()) < 1) { + mapGlobalBcWithT0B[globalBC] = bc.globalIndex(); + } + } + + for (auto& track : tracks) { + // DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h + // Time for different track types: + // ITS-TPC-TRD-TOF: time from TOF +/- 10 ns + // ITS-TPC-TRD: time from TRD +/- 5 ns + // ITS-TPC: time from ITS-TPC matching + + // ITS and colId requirements are redundant for contributors + int32_t colId = track.collisionId(); + + if (!track.isPVContributor() || colId < 0 || !track.hasITS()) + continue; + + float trackPt = track.pt(); + float trackTime = track.trackTime(); + float trackTimeRes = track.trackTimeRes(); + float w = 1. / (trackTimeRes * trackTimeRes); + if (track.hasTOF()) { + vTOFtracksTimes[colId].push_back(trackTime); + vNumTOFtracks[colId]++; + vTOFtracksSumWeightedTimes[colId] += trackTime * w; + vTOFtracksSumWeights[colId] += w; + if (vMinTimeTOFtracks[colId] > trackTime) + vMinTimeTOFtracks[colId] = trackTime; + if (vMaxTimeTOFtracks[colId] < trackTime) + vMaxTimeTOFtracks[colId] = trackTime; + } else if (track.hasTRD()) { + vNumTRDtracks[colId]++; + vTRDtracksSumWeightedTimes[colId] += trackTime * w; + vTRDtracksSumWeights[colId] += w; + } else if (track.hasTPC()) { + vTPCtracksPts[colId].push_back(trackPt); + vTPCtracksTimes[colId].push_back(trackTime); + vTPCtracksTimeRes[colId].push_back(trackTimeRes); + vNumTPCtracks[colId]++; + if (trackPt > 1) + vNumTPCtracksHighPt[colId]++; + vTPCtracksSumWeightedTimes[colId] += trackTime * w; + vTPCtracksSumWeights[colId] += w; + } else { + vITStracksTimes[colId].push_back(trackTime); + vNumITStracks[colId]++; + vITStracksSumWeightedTimes[colId] += trackTime * w; + vITStracksSumWeights[colId] += w; + } + } + + for (auto& col : cols) { + int32_t colId = col.globalIndex(); + + if (vNumTOFtracks[colId] == 0) + continue; + auto bc = col.bc_as(); + int64_t globalBC = bc.globalBC(); + + // todo: bypass ambiguous collisions with TOF tracks pointing to different bcs + // float weightedTime = vTOFtracksSumWeightedTimes[colId] / vTOFtracksSumWeights[colId]; + + // TOF track time median calculation using std::nth_element + auto& vTOFtracks = vTOFtracksTimes[colId]; + int median = vTOFtracks.size() / 2; + std::nth_element(vTOFtracks.begin(), vTOFtracks.begin() + median, vTOFtracks.end()); + float medianTime = vTOFtracks[median]; + + // int64_t tofGlobalBC = globalBC + TMath::Nint(weightedTime / bcNS); + int64_t tofGlobalBC = globalBC + TMath::Nint(medianTime / bcNS); + + int32_t foundBC = findClosest(tofGlobalBC, mapGlobalBcWithTVX); + int64_t foundGlobalBC = bcs.iteratorAt(foundBC).globalBC(); + // todo: check what to do if foundBC is too far from tofGlobalBC + if (fabs(foundGlobalBC - tofGlobalBC) > deltaBCforTOFcollisions) { + foundBC = -1; + int32_t nContrib = col.numContrib(); + if (nContrib > 100) { + int32_t foundBCwithT0B = findClosest(tofGlobalBC, mapGlobalBcWithT0B); + int64_t foundGlobalBCwithT0B = bcs.iteratorAt(foundBCwithT0B).globalBC(); + + LOGP(info, "Total number of TOF tracks: {}", vTOFtracks.size()); + LOGP(info, "Median time: {}", medianTime); + LOGP(info, "globalBC: {}", globalBC % 3564); + LOGP(info, "TOF global BC: {}", tofGlobalBC % 3564); + LOGP(info, "Found global BC: {}", foundGlobalBC % 3564); + LOGP(info, "Found global BC with T0B: {}", foundGlobalBCwithT0B % 3564); + sort(vTOFtracks.begin(), vTOFtracks.end()); + for (float t : vTOFtracks) { + LOGP(info, " {}", t); + } + } + } + + vFoundBCindex[colId] = foundBC; + if (removeTOFmatches && foundBC >= 0) { + mapGlobalBcVtxZ.erase(foundGlobalBC); + } + } + + // second loop to match collisions with high-pt ITS-TPC tracks + for (auto& col : cols) { + int32_t colId = col.globalIndex(); + if (vNumTOFtracks[colId] > 0) + continue; + if (vNumTPCtracksHighPt[colId] == 0) + continue; + + auto bc = col.bc_as(); + int64_t globalBC = bc.globalBC(); + float sumTime = 0; + int nTracks = 0; + for (uint32_t i = 0; i < vTPCtracksTimes[colId].size(); ++i) { + if (vTPCtracksPts[colId][i] < 1.0) + continue; + sumTime += vTPCtracksTimes[colId][i]; + nTracks++; + } + if (nTracks == 0) { + LOGP(info, "Warning: nTracks = 0"); + continue; + } + + int64_t deltaBC = deltaBCforHighPtTracks; + int64_t tpcGlobalBC = globalBC + TMath::Nint(sumTime / nTracks / bcNS); + int64_t minBC = tpcGlobalBC - deltaBC; + int64_t maxBC = tpcGlobalBC + deltaBC; + int32_t nContrib = col.numContrib(); + float zVtxCol = col.posZ(); + float zVtxSigma = 2.7 * pow(nContrib, -0.466) + 0.024; + zVtxSigma += 1.0; // additional uncertainty due to imperfectections of FT0 time calibration + + // todo: check upper bound + auto itMin = mapGlobalBcVtxZ.lower_bound(minBC); + auto itMax = mapGlobalBcVtxZ.upper_bound(maxBC); + + float bestChi2 = 1e+10; + int64_t globalBcBest = 0; + + int nCandidates = 0; + for (std::map::iterator it = itMin; it != itMax; ++it) { + float zVtxFT0 = it->second; + float zVtxDiff = zVtxFT0 - zVtxCol; + float bcDiff = tpcGlobalBC - globalBC; + float chi2 = 0; + chi2 += useVtxDiff ? pow(zVtxDiff / zVtxSigma, 2) : 0.; + chi2 += useTimeDiff ? pow(bcDiff / (deltaBCforHighPtTracks / 3.), 2) : 0.; + + if (chi2 < bestChi2) { + bestChi2 = chi2; + globalBcBest = it->first; + } + nCandidates++; + } + histos.fill(HIST("hNcontribCandidatesHighPt"), nContrib, nCandidates); + histos.fill(HIST("hNcontribCountsHighPt"), nContrib); + + if (globalBcBest != 0) + vFoundBCindex[colId] = mapGlobalBcWithTVX[globalBcBest]; + + if (removeHighPtmatches && vFoundBCindex[colId] >= 0) + mapGlobalBcVtxZ.erase(globalBC); + } // second loop + + // third loop to match collisions with poor time resolution + for (auto& col : cols) { + int32_t colId = col.globalIndex(); + if (vNumTOFtracks[colId] > 0) + continue; + if (vNumTPCtracks[colId] == 0) + continue; + if (vFoundBCindex[colId] >= 0) // found in the previous step + continue; + + auto bc = col.bc_as(); + int64_t globalBC = bc.globalBC(); + + float weightedTime = vTPCtracksSumWeightedTimes[colId] / vTPCtracksSumWeights[colId]; + float weightedSigma = sqrt(1. / vTPCtracksSumWeights[colId]); + + int64_t minROF = 0; + int64_t maxROF = 0; + if (useITSROFconstraint) { + float medianTime = 0; + auto vTPCtracks = vTPCtracksTimes[colId]; + int median = vTPCtracks.size() / 2; + std::nth_element(vTPCtracks.begin(), vTPCtracks.begin() + median, vTPCtracks.end()); + medianTime = vTPCtracks[median]; + + int64_t itsGlobalBC = globalBC + TMath::Nint(medianTime / bcNS); + minROF = (itsGlobalBC - offsetITSROF) / nBCsPerITSROF * nBCsPerITSROF + offsetITSROF; + maxROF = minROF + nBCsPerITSROF; + LOGP(debug, "{} {}", minROF, maxROF); + float sumTime = 0; + float sumW = 0; + for (uint32_t i = 0; i < vTPCtracksTimes[colId].size(); ++i) { + float trackTime = vTPCtracksTimes[colId][i]; + int64_t trackGlobalBC = globalBC + TMath::Nint(trackTime / bcNS); + LOGP(debug, " {}", trackGlobalBC); + if (trackGlobalBC < minROF || trackGlobalBC > maxROF) + continue; + float r = vTPCtracksTimeRes[colId][i]; + float w = 1. / (r * r); + sumTime += trackTime * w; + sumW += w; + } + weightedTime = sumTime / sumW; + weightedSigma = sqrt(1. / sumW); + } + + int64_t deltaBC = std::ceil(weightedSigma / bcNS * 3); + int64_t tpcGlobalBC = globalBC + TMath::Nint(weightedTime / bcNS); + + LOGP(debug, "{} {}", tpcGlobalBC, deltaBC); + + deltaBC += additionalDeltaBC; + + if (minimumDeltaBC >= 0) { + deltaBC = deltaBC < minimumDeltaBC ? minimumDeltaBC : deltaBC; + } + + int64_t minBC = tpcGlobalBC - deltaBC; + int64_t maxBC = tpcGlobalBC + deltaBC; + + if (useITSROFconstraint) { + minBC = minBC < minROF ? minROF : minBC; + maxBC = maxBC > maxROF ? maxROF : maxBC; + if (minBC > maxBC) { + LOGP(debug, "{} {} {} {}", minBC, maxBC, minROF, maxROF); + continue; + } + } + + int32_t nContrib = col.numContrib(); + float zVtxCol = col.posZ(); + float zVtxSigma = 2.7 * pow(nContrib, -0.466) + 0.024; + zVtxSigma += 1.0; // additional uncertainty due to imperfectections of FT0 time calibration + + // QA + vWeightedSigma[colId] = weightedSigma; + + // todo: check upper bound + auto itMin = mapGlobalBcVtxZ.lower_bound(minBC); + auto itMax = mapGlobalBcVtxZ.upper_bound(maxBC); + + float bestChi2 = 1e+10; + int64_t globalBcBest = 0; + + int nCandidates = 0; + for (std::map::iterator it = itMin; it != itMax; ++it) { + float zVtxFT0 = it->second; + float zVtxDiff = zVtxFT0 - zVtxCol; + float timeDiff = bcNS * (tpcGlobalBC - globalBC); + float chi2 = 0; + chi2 += useVtxDiff ? pow(zVtxDiff / zVtxSigma, 2) : 0.; + chi2 += useTimeDiff ? pow(timeDiff / weightedSigma, 2) : 0.; + + if (chi2 < bestChi2) { + bestChi2 = chi2; + globalBcBest = it->first; + } + nCandidates++; + } + if (nCandidates > 100) + LOGP(info, "{} {}", minBC, maxBC); + + histos.fill(HIST("hNcontribCandidates"), nContrib, nCandidates); + histos.fill(HIST("hNcontribCounts"), nContrib); + + if (globalBcBest != 0) + vFoundBCindex[colId] = mapGlobalBcWithTVX[globalBcBest]; + + } // third loop + + // QA + for (auto& ft0 : ft0s) { + auto bc = ft0.bc_as(); + int64_t globalBC = bc.globalBC(); + // remove noise from non-colliding bcs + if (removeNoncollidingBCs && bcPatternB[globalBC % o2::constants::lhc::LHCMaxBunches] == 0) + continue; + if (!(ft0.triggerMask() & BIT(o2::ft0::Triggers::bitVertex))) + continue; + float multT0C = ft0.sumAmpC(); + histos.fill(HIST("hRecMultT0C"), ft0.sumAmpC()); + if (multT0C < 1800) + continue; + histos.fill(HIST("hTimeT0AHighMultT0C"), ft0.timeA()); + histos.fill(HIST("hTimeT0CHighMultT0C"), ft0.timeC()); + if (bc.has_fv0a()) { + auto fv0 = bc.fv0a(); + histos.fill(HIST("hTimeV0AHighMultT0C"), fv0.time()); + } + if (bc.has_fdd()) { + auto fdd = bc.fdd(); + histos.fill(HIST("hTimeFDAHighMultT0C"), fdd.timeA()); + histos.fill(HIST("hTimeFDCHighMultT0C"), fdd.timeC()); + } + } + + for (auto& col : cols) { + int64_t globalBC = col.bc_as().globalBC(); + if (!isGoodBC(globalBC, 1)) + continue; + + int32_t colId = col.globalIndex(); + int32_t nContrib = col.numContrib(); + // float timeRes = col.collisionTimeRes(); + int32_t foundBC = vFoundBCindex[colId]; + bool isGoodTOF = vMaxTimeTOFtracks[colId] - vMinTimeTOFtracks[colId] < 50; + bool isFoundTVX = foundBC >= 0; + + float zVtxDiff = 1e+10; + float multT0C = 0; + int64_t foundGlobalBC = 0; + + if (foundBC >= 0 && foundBC < bcs.size()) { + auto bc = bcs.iteratorAt(foundBC); + foundGlobalBC = bc.globalBC(); + // LOGP(info,"{}",bc.has_ft0()); + if (bc.has_ft0()) { + zVtxDiff = bc.ft0().posZ() - col.posZ(); + multT0C = bc.ft0().sumAmpC(); + } + } + + histos.fill(HIST("hNcontribAll"), nContrib); + if (removeColsWithAmbiguousTOF && !isGoodTOF) { + continue; + } + + histos.fill(HIST("hNcontribCol"), nContrib); + if (isFoundTVX) { + histos.fill(HIST("hNcontribAcc"), nContrib); + histos.fill(HIST("hRecMultT0CvsNcontrib"), multT0C, nContrib); + histos.fill(HIST("hZvtxDiffVsNcontrib"), nContrib, zVtxDiff); + } + + // search for nearest ft0a&ft0c entry + int32_t indexClosestTVX = findClosest(globalBC, mapGlobalBcWithTVX); + int bcDiff = static_cast(globalBC - vGlobalBCs[indexClosestTVX]); + histos.fill(HIST("hColBcDiffVsNcontrib"), nContrib, bcDiff); + + if (vNumTOFtracks[colId] > 0) { + histos.fill(HIST("hNcontribColTOF"), nContrib); + if (isFoundTVX) { + histos.fill(HIST("hNcontribAccTOF"), nContrib); + histos.fill(HIST("hRecMultT0CvsNcontribTOF"), multT0C, nContrib); + histos.fill(HIST("hZvtxDiffVsNcontribTOF"), nContrib, zVtxDiff); + } + histos.fill(HIST("hColBcDiffVsNcontribTOF"), nContrib, bcDiff); + + for (uint32_t i = 0; i < vTPCtracksTimes[colId].size(); i++) { + float pt = vTPCtracksPts[colId][i]; + auto t = vTPCtracksTimes[colId][i]; + int foundBCinITSROF = (foundGlobalBC + nBCsPerOrbit - offsetITSROF) % nBCsPerITSROF; + int64_t tpcTrackGlobalBC = globalBC + TMath::Nint(t / bcNS); + int64_t deltaBC = tpcTrackGlobalBC - foundGlobalBC; + histos.fill(HIST("hBcInITSROFTPCDiff"), foundBCinITSROF, deltaBC); + histos.fill(HIST("hTrackBcDiffVsPt"), pt, deltaBC); + histos.fill(HIST("hTrackBcResVsPt"), pt, vTPCtracksTimeRes[colId][i] / bcNS); + } + } else if (vNumTPCtracksHighPt[colId] > 0) { + histos.fill(HIST("hNcontribColTPCHighPt"), nContrib); + if (isFoundTVX) { + histos.fill(HIST("hNcontribAccTPCHighPt"), nContrib); + histos.fill(HIST("hRecMultT0CvsNcontribTPCHighPt"), multT0C, nContrib); + } + } else if (vNumTPCtracks[colId] > 0) { + histos.fill(HIST("hNcontribSigma"), nContrib, vWeightedSigma[colId]); + histos.fill(HIST("hNcontribColTPC"), nContrib); + histos.fill(HIST("hColBcDiffVsNcontribTPC"), nContrib, bcDiff); + if (nContrib > 180) { + histos.fill(HIST("hBcInTFTPC"), (globalBC - bcSOR) % nBCsPerTF); + histos.fill(HIST("hBcInITSROFTPC"), (globalBC + nBCsPerOrbit - offsetITSROF) % nBCsPerITSROF); + } + if (isFoundTVX) { + histos.fill(HIST("hNcontribAccTPC"), nContrib); + histos.fill(HIST("hRecMultT0CvsNcontribTPC"), multT0C, nContrib); + histos.fill(HIST("hZvtxDiffVsNcontribTPC"), nContrib, zVtxDiff); + } + } else if (vNumTRDtracks[colId] > 0) { + histos.fill(HIST("hNcontribColTRD"), nContrib); + if (isFoundTVX) { + histos.fill(HIST("hNcontribAccTRD"), nContrib); + histos.fill(HIST("hRecMultT0CvsNcontribTRD"), multT0C, nContrib); + histos.fill(HIST("hZvtxDiffVsNcontribTRD"), nContrib, zVtxDiff); + } + histos.fill(HIST("hColBcDiffVsNcontribTRD"), nContrib, bcDiff); + } else if (vNumITStracks[colId] > 0) { + histos.fill(HIST("hNcontribColITS"), nContrib); + if (nContrib > 180) { + histos.fill(HIST("hBcInTFITS"), (globalBC - bcSOR) % nBCsPerTF); + histos.fill(HIST("hBcInITSROFITS"), (globalBC + nBCsPerOrbit - offsetITSROF) % nBCsPerITSROF); + } + + if (isFoundTVX) + histos.fill(HIST("hNcontribAccITS"), nContrib); + } + } + } + + void processMC( + aod::McCollisions const& mcCols, + soa::Join const& cols, + FullTracksIUwithLabels const& tracks, + BCsRun3 const& /*bcs*/, + aod::FT0s const& /*ft0s*/, + aod::McParticles const& mcParts) + { + + std::vector vLabel(cols.size(), -1); + std::vector vIsAmbiguousLabel(cols.size(), 0); + std::vector vNumWrongContributors(cols.size(), 0); + + for (auto& track : tracks) { + if (!track.isPVContributor()) + continue; + int32_t colId = track.collisionId(); + auto col = cols.iteratorAt(colId); + int32_t mcColIdFromCollision = col.mcCollisionId(); + if (mcColIdFromCollision < 0) + continue; + int mcId = track.mcParticleId(); + if (mcId < 0 || mcId >= mcParts.size()) + continue; + auto mcPart = mcParts.iteratorAt(mcId); + int32_t mcColId = mcPart.mcCollisionId(); + if (mcColId < 0) + continue; + if (mcColIdFromCollision != mcColId) + vNumWrongContributors[colId]++; + + if (vLabel[colId] != -1 && vLabel[colId] != mcColId) { + vIsAmbiguousLabel[colId] = 1; + } + vLabel[colId] = mcColId; + } + + for (auto& col : cols) { + int64_t globalBC = col.bc_as().globalBC(); + if (!isGoodBC(globalBC)) + continue; + + int32_t colId = col.globalIndex(); + int32_t nContrib = col.numContrib(); + + histos.fill(HIST("hNcontribAllContribAll"), nContrib, nContrib); + histos.fill(HIST("hNcontribAllContribWrong"), nContrib, vNumWrongContributors[colId]); + histos.fill(HIST("hNcontribAllFractionWrong"), nContrib, static_cast(vNumWrongContributors[colId]) / nContrib); + + if (static_cast(vNumWrongContributors[colId]) / nContrib > 0.1) + continue; + + histos.fill(HIST("hNcontribColMostlyOk"), nContrib); + if (vNumTOFtracks[colId] > 0) { + histos.fill(HIST("hNcontribColMostlyOkTOF"), nContrib); + } else if (vNumTPCtracks[colId] > 0) { + histos.fill(HIST("hNcontribColMostlyOkTPC"), nContrib); + } else if (vNumTRDtracks[colId] > 0) { + histos.fill(HIST("hNcontribColMostlyOkTRD"), nContrib); + } else if (vNumITStracks[colId] > 0) { + histos.fill(HIST("hNcontribColMostlyOkITS"), nContrib); + } + + int32_t foundBC = vFoundBCindex[colId]; + int32_t mcColId = vLabel[colId]; + auto mcCol = mcCols.iteratorAt(mcColId); + auto mcBC = mcCol.bc_as(); + // int64_t mcGlobalBC = mcBC.globalBC(); + bool isMcTVX = mcBC.has_ft0() ? mcBC.ft0().triggerMask() & BIT(o2::ft0::Triggers::bitVertex) : 0; + if (isMcTVX) + histos.fill(HIST("hNcontribTvxMostlyOk"), nContrib); + + if (foundBC >= 0 && foundBC != mcBC.globalIndex()) { + // Analyse mismatches + histos.fill(HIST("hNcontribColMostlyOkMis"), nContrib); + if (vNumTOFtracks[colId] > 0) { + histos.fill(HIST("hNcontribColMostlyOkMisTOF"), nContrib); + } else if (vNumTPCtracks[colId] > 0) { + histos.fill(HIST("hNcontribColMostlyOkMisTPC"), nContrib); + } else if (vNumTRDtracks[colId] > 0) { + histos.fill(HIST("hNcontribColMostlyOkMisTRD"), nContrib); + } else if (vNumITStracks[colId] > 0) { + histos.fill(HIST("hNcontribColMostlyOkMisITS"), nContrib); + } + } + + if (vIsAmbiguousLabel[colId]) + continue; + + histos.fill(HIST("hNcontribUnambiguous"), nContrib); + if (vNumTOFtracks[colId] > 0) { + histos.fill(HIST("hNcontribUnambiguousTOF"), nContrib); + } else if (vNumTPCtracks[colId] > 0) { + histos.fill(HIST("hNcontribUnambiguousTPC"), nContrib); + } else if (vNumTRDtracks[colId] > 0) { + histos.fill(HIST("hNcontribUnambiguousTRD"), nContrib); + } else if (vNumITStracks[colId] > 0) { + histos.fill(HIST("hNcontribUnambiguousITS"), nContrib); + } + + if (foundBC >= 0 && foundBC != mcBC.globalIndex()) { + // Analyse mismatches + histos.fill(HIST("hNcontribMis"), nContrib); + if (vNumTOFtracks[colId] > 0) { + histos.fill(HIST("hNcontribMisTOF"), nContrib); + } else if (vNumTPCtracks[colId] > 0) { + histos.fill(HIST("hNcontribMisTPC"), nContrib); + } else if (vNumTRDtracks[colId] > 0) { + histos.fill(HIST("hNcontribMisTRD"), nContrib); + } else if (vNumITStracks[colId] > 0) { + histos.fill(HIST("hNcontribMisITS"), nContrib); + } + } + } + } + + PROCESS_SWITCH(MatchingQaTask, processMC, "", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // Parse the metadata + metadataInfo.initMetadata(cfgc); + + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/DPG/Tasks/AOTEvent/mshapeQa.cxx b/DPG/Tasks/AOTEvent/mshapeQa.cxx deleted file mode 100644 index 38f3910da21..00000000000 --- a/DPG/Tasks/AOTEvent/mshapeQa.cxx +++ /dev/null @@ -1,189 +0,0 @@ -// 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. - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "CCDB/BasicCCDBManager.h" -#include "Framework/HistogramRegistry.h" -#include "TPCCalibration/TPCMShapeCorrection.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "DataFormatsParameters/GRPECSObject.h" - -#include "TTree.h" - -using namespace o2; -using namespace o2::framework; -using BCsRun3 = soa::Join; -using BarrelTracks = soa::Join; -const AxisSpec axisQoverPt{100, -5., 5., "q/p_{T}, 1/GeV"}; -const AxisSpec axisDcaR{1000, -5., 5., "DCA_{r}, cm"}; -const AxisSpec axisDcaZ{1000, -5., 5., "DCA_{z}, cm"}; -const AxisSpec axisSparseQoverPt{20, -5., 5., "q/p_{T}, 1/GeV"}; -const AxisSpec axisSparseDcaR{100, -5., 5., "DCA_{r}, cm"}; -const AxisSpec axisSparseDcaZ{100, -5., 5., "DCA_{z}, cm"}; - -struct MshapeQaTask { - Configurable confTimeBinWidthInSec{"TimeBinWidthInSec", 0.1, "Width of time bins in seconds"}; - Service ccdb; - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - o2::tpc::TPCMShapeCorrection mshape; // object for simple access - int lastRunNumber = -1; - double maxSec = 1; - double minSec = 0; - void init(InitContext&) - { - ccdb->setURL("http://alice-ccdb.cern.ch"); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - histos.add("hQoverPt", "", kTH1F, {axisQoverPt}); - histos.add("hDcaR", "", kTH1F, {axisDcaR}); - histos.add("hDcaZ", "", kTH1F, {axisDcaZ}); - histos.add("hQoverPtDcaR", "", kTH2F, {axisSparseQoverPt, axisSparseDcaR}); - histos.add("hQoverPtDcaZ", "", kTH2F, {axisSparseQoverPt, axisSparseDcaZ}); - } - - void process(aod::Collision const& col, BCsRun3 const& bcs, BarrelTracks const& tracks) - { - int runNumber = bcs.iteratorAt(0).runNumber(); - if (runNumber != lastRunNumber) { - lastRunNumber = runNumber; - std::map metadata; - metadata["runNumber"] = Form("%d", runNumber); - auto grpecs = ccdb->getSpecific("GLO/Config/GRPECS", bcs.iteratorAt(0).timestamp(), metadata); - minSec = floor(grpecs->getTimeStart() / 1000.); - maxSec = ceil(grpecs->getTimeEnd() / 1000.); - int nTimeBins = static_cast((maxSec - minSec) / confTimeBinWidthInSec); - double timeInterval = nTimeBins * confTimeBinWidthInSec; - const AxisSpec axisSeconds{nTimeBins, 0, timeInterval, "seconds"}; - histos.add("hSecondsAsideQoverPtSumDcaR", "", kTH2F, {axisSeconds, axisSparseQoverPt}); - histos.add("hSecondsAsideQoverPtSumDcaZ", "", kTH2F, {axisSeconds, axisSparseQoverPt}); - histos.add("hSecondsCsideQoverPtSumDcaR", "", kTH2F, {axisSeconds, axisSparseQoverPt}); - histos.add("hSecondsCsideQoverPtSumDcaZ", "", kTH2F, {axisSeconds, axisSparseQoverPt}); - histos.add("hSecondsQoverPtSumDcaR", "", kTH2F, {axisSeconds, axisSparseQoverPt}); - histos.add("hSecondsQoverPtSumDcaZ", "", kTH2F, {axisSeconds, axisSparseQoverPt}); - - histos.add("hSecondsAsideSumDcaR", "", kTH1F, {axisSeconds}); - histos.add("hSecondsAsideSumDcaZ", "", kTH1F, {axisSeconds}); - histos.add("hSecondsCsideSumDcaR", "", kTH1F, {axisSeconds}); - histos.add("hSecondsCsideSumDcaZ", "", kTH1F, {axisSeconds}); - histos.add("hSecondsSumDcaR", "", kTH1F, {axisSeconds}); - histos.add("hSecondsSumDcaZ", "", kTH1F, {axisSeconds}); - histos.add("hSecondsTracks", "", kTH1F, {axisSeconds}); - histos.add("hSecondsTracksMshape", "", kTH1F, {axisSeconds}); - histos.add("hSecondsAsideITSTPCcontrib", "", kTH1F, {axisSeconds}); - histos.add("hSecondsCsideITSTPCcontrib", "", kTH1F, {axisSeconds}); - histos.add("hSecondsCollisions", "", kTH1F, {axisSeconds}); - - const AxisSpec axisPhi{64, 0, TMath::TwoPi(), "#varphi"}; - histos.add("hSecondsITSlayer0vsPhi", "", kTH2F, {axisSeconds, axisPhi}); - histos.add("hSecondsITSlayer1vsPhi", "", kTH2F, {axisSeconds, axisPhi}); - histos.add("hSecondsITSlayer2vsPhi", "", kTH2F, {axisSeconds, axisPhi}); - histos.add("hSecondsITSlayer3vsPhi", "", kTH2F, {axisSeconds, axisPhi}); - histos.add("hSecondsITSlayer4vsPhi", "", kTH2F, {axisSeconds, axisPhi}); - histos.add("hSecondsITSlayer5vsPhi", "", kTH2F, {axisSeconds, axisPhi}); - histos.add("hSecondsITSlayer6vsPhi", "", kTH2F, {axisSeconds, axisPhi}); - histos.add("hSecondsITS7clsVsPhi", "", kTH2F, {axisSeconds, axisPhi}); - histos.add("hSecondsITSglobalVsPhi", "", kTH2F, {axisSeconds, axisPhi}); - histos.add("hSecondsITSTRDVsPhi", "", kTH2F, {axisSeconds, axisPhi}); - histos.add("hSecondsITSTOFVsPhi", "", kTH2F, {axisSeconds, axisPhi}); - } - - int64_t ts = col.bc_as().timestamp(); - auto mShapeTree = ccdb->getForTimeStamp("TPC/Calib/MShapePotential", ts); - mshape.setFromTree(*mShapeTree); - bool isMshape = !mshape.getBoundaryPotential(ts).mPotential.empty(); - - double secFromSOR = ts / 1000. - minSec; - - int nAsideITSTPCContrib = 0; - int nCsideITSTPCContrib = 0; - for (const auto& track : tracks) { - if (!track.hasTPC() || !track.hasITS()) { - continue; - } - float qpt = track.signed1Pt(); - float dcaR = track.dcaXY(); - float dcaZ = track.dcaZ(); - LOGP(debug, "dcaR = {} dcaZ = {}", dcaR, dcaZ); - histos.fill(HIST("hQoverPt"), qpt); - histos.fill(HIST("hDcaR"), dcaR); - histos.fill(HIST("hDcaZ"), dcaZ); - histos.fill(HIST("hQoverPtDcaR"), qpt, dcaR); - histos.fill(HIST("hQoverPtDcaZ"), qpt, dcaZ); - histos.fill(HIST("hSecondsSumDcaR"), secFromSOR, dcaR); - histos.fill(HIST("hSecondsSumDcaZ"), secFromSOR, dcaZ); - histos.fill(HIST("hSecondsQoverPtSumDcaR"), secFromSOR, qpt, dcaR); - histos.fill(HIST("hSecondsQoverPtSumDcaZ"), secFromSOR, qpt, dcaZ); - histos.fill(HIST("hSecondsTracks"), secFromSOR); - if (track.tgl() > 0.) { - histos.fill(HIST("hSecondsAsideQoverPtSumDcaR"), secFromSOR, qpt, dcaR); - histos.fill(HIST("hSecondsAsideQoverPtSumDcaZ"), secFromSOR, qpt, dcaZ); - histos.fill(HIST("hSecondsAsideSumDcaR"), secFromSOR, dcaR); - histos.fill(HIST("hSecondsAsideSumDcaZ"), secFromSOR, dcaZ); - - } else { - histos.fill(HIST("hSecondsCsideQoverPtSumDcaR"), secFromSOR, qpt, dcaR); - histos.fill(HIST("hSecondsCsideQoverPtSumDcaZ"), secFromSOR, qpt, dcaZ); - histos.fill(HIST("hSecondsCsideSumDcaR"), secFromSOR, dcaR); - histos.fill(HIST("hSecondsCsideSumDcaZ"), secFromSOR, dcaZ); - } - if (isMshape) { - histos.fill(HIST("hSecondsTracksMshape"), secFromSOR); - } - if (track.isPVContributor()) { - if (track.tgl() > 0.) { - nAsideITSTPCContrib++; - } else { - nCsideITSTPCContrib++; - } - - // select straight tracks - if (track.pt() < 1) { - continue; - } - // study ITS cluster pattern vs sec - if (track.itsClusterMap() & (1 << 0)) - histos.fill(HIST("hSecondsITSlayer0vsPhi"), secFromSOR, track.phi()); - if (track.itsClusterMap() & (1 << 1)) - histos.fill(HIST("hSecondsITSlayer1vsPhi"), secFromSOR, track.phi()); - if (track.itsClusterMap() & (1 << 2)) - histos.fill(HIST("hSecondsITSlayer2vsPhi"), secFromSOR, track.phi()); - if (track.itsClusterMap() & (1 << 3)) - histos.fill(HIST("hSecondsITSlayer3vsPhi"), secFromSOR, track.phi()); - if (track.itsClusterMap() & (1 << 4)) - histos.fill(HIST("hSecondsITSlayer4vsPhi"), secFromSOR, track.phi()); - if (track.itsClusterMap() & (1 << 5)) - histos.fill(HIST("hSecondsITSlayer5vsPhi"), secFromSOR, track.phi()); - if (track.itsClusterMap() & (1 << 6)) - histos.fill(HIST("hSecondsITSlayer6vsPhi"), secFromSOR, track.phi()); - if (track.itsNCls() == 7) - histos.fill(HIST("hSecondsITS7clsVsPhi"), secFromSOR, track.phi()); - if (track.hasITS() && track.hasTPC()) - histos.fill(HIST("hSecondsITSglobalVsPhi"), secFromSOR, track.phi()); - if (track.hasTRD()) - histos.fill(HIST("hSecondsITSTRDVsPhi"), secFromSOR, track.phi()); - if (track.hasTOF()) - histos.fill(HIST("hSecondsITSTOFVsPhi"), secFromSOR, track.phi()); - } - } - histos.fill(HIST("hSecondsCollisions"), secFromSOR); - histos.fill(HIST("hSecondsAsideITSTPCcontrib"), secFromSOR, nAsideITSTPCContrib); - histos.fill(HIST("hSecondsCsideITSTPCcontrib"), secFromSOR, nCsideITSTPCContrib); - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/DPG/Tasks/AOTEvent/rofBorderQa.cxx b/DPG/Tasks/AOTEvent/rofBorderQa.cxx new file mode 100644 index 00000000000..83f704960b6 --- /dev/null +++ b/DPG/Tasks/AOTEvent/rofBorderQa.cxx @@ -0,0 +1,461 @@ +// 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 QA task to study ROF border effect for different event, track and particle selection parameters +/// \author Igor Altsybeev, Igor.Altsybeev@cern.ch + +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/CCDB/EventSelectionParams.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "DataFormatsParameters/GRPMagField.h" + +#include "Common/DataModel/FT0Corrected.h" +#include "DataFormatsFT0/Digit.h" + +using namespace std; +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// main class +struct RofBorderQaTask { + // for vertex vs time: + bool flagShowInfo = false; + int lastRunNumber = -1; + int nBCsPerOrbit = 3564; + + // bc position correlations + Service ccdb; + + int64_t bcSOR = -1; // global bc of the start of the first orbit + int64_t orbitSOR = -1; + int64_t nBCsPerTF = 1; // 128*3564; // duration of TF in bcs + uint32_t nOrbitsPerTF = 0; + + // Configurable flagPbPb{"flagPbPb", 0, "0 - pp, 1 - PbPb"}; + + // ##### hist registries + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + void init(InitContext const&) + { + AxisSpec axisBC{3601, -0.5, 3600.5, "bc"}; + + // ##### tracks for All collisions + histos.add("hFoundBC_nAllTracks", "hFoundBC_nAllTracks", kTH1D, {axisBC}); + histos.add("hFoundBC_nTracksPV", "hFoundBC_nTracksPV", kTH1D, {axisBC}); + histos.add("hFoundBC_nGlobalTracks", "hFoundBC_nGlobalTracks", kTH1D, {axisBC}); + histos.add("hFoundBC_nITStracks", "hFoundBC_nITStracks", kTH1D, {axisBC}); + histos.add("hFoundBC_nTPCtracks", "hFoundBC_nTPCtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_nTOFtracks", "hFoundBC_nTOFtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_nTRDtracks", "hFoundBC_nTRDtracks", kTH1D, {axisBC}); + + histos.add("hFoundBC_nTRDTOFtracks", "hFoundBC_nTRDTOFtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_nITSTPCTRDtracks", "hFoundBC_nITSTPCTRDtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_nITSTPCTOFtracks", "hFoundBC_nITSTPCTOFtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_nITSTPCTRDTOFtracks", "hFoundBC_nITSTPCTRDTOFtracks", kTH1D, {axisBC}); + + // ##### tracks for TVX collisions + histos.add("hFoundBC_kTVX_nAllTracks", "hFoundBC_kTVX_nAllTracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nTracksPV", "hFoundBC_kTVX_nTracksPV", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nGlobalTracks", "hFoundBC_kTVX_nGlobalTracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nITStracks", "hFoundBC_kTVX_nITStracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nTPCtracks", "hFoundBC_kTVX_nTPCtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nITSTPCtracks", "hFoundBC_kTVX_nITSTPCtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nTOFtracks", "hFoundBC_kTVX_nTOFtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nTRDtracks", "hFoundBC_kTVX_nTRDtracks", kTH1D, {axisBC}); + + histos.add("hFoundBC_kTVX_nTRDTOFtracks", "hFoundBC_kTVX_nTRDTOFtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nITSTPCTRDtracks", "hFoundBC_kTVX_nITSTPCTRDtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nITSTPCTOFtracks", "hFoundBC_kTVX_nITSTPCTOFtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nITSTPCTRDTOFtracks", "hFoundBC_kTVX_nITSTPCTRDTOFtracks", kTH1D, {axisBC}); + + histos.add("hFoundBC_kTVX_counter", "hFoundBC_kTVX_counter", kTH1D, {axisBC}); + + // n ITS layers per track in pt bins + AxisSpec axisPtBinsForROFstudy{{0.1, 0.2, 0.3, 0.4, 0.5, 0.8, 1.0, 1.5, 2.0, 3.0, 5.0}, "p_{T}"}; + histos.add("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_vs_pt", "hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_vs_pt", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histos.add("hFoundBC_kTVX_counter_nITSTPCtracks_vs_pt", "hFoundBC_kTVX_counter_nITSTPCtracks_vs_pt", kTH2D, {axisBC, axisPtBinsForROFstudy}); + + histos.add("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_vs_pt_pi", "hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_vs_pt_pi", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histos.add("hFoundBC_kTVX_counter_nITSTPCtracks_vs_pt_pi", "hFoundBC_kTVX_counter_nITSTPCtracks_vs_pt_pi", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histos.add("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_vs_pt_ka", "hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_vs_pt_ka", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histos.add("hFoundBC_kTVX_counter_nITSTPCtracks_vs_pt_ka", "hFoundBC_kTVX_counter_nITSTPCtracks_vs_pt_ka", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histos.add("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_vs_pt_pr", "hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_vs_pt_pr", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histos.add("hFoundBC_kTVX_counter_nITSTPCtracks_vs_pt_pr", "hFoundBC_kTVX_counter_nITSTPCtracks_vs_pt_pr", kTH2D, {axisBC, axisPtBinsForROFstudy}); + + // n ITS layers per track + histos.add("hBC_kTVX_nITSlayers_for_ITSTPCtracks", "hBC_kTVX_nITSlayers_for_ITSTPCtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks", "hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_kTVXinTRD", "hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_kTVXinTRD", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_pi", "hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_pi", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_ka", "hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_ka", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_pr", "hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_pr", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nITSlayers_for_GlobalTracks", "hFoundBC_kTVX_nITSlayers_for_GlobalTracks", kTH1D, {axisBC}); + + // counters + histos.add("hBC_kTVX_counter_ITSTPCtracks", "hBC_kTVX_counter_ITSTPCtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_counter_ITSTPCtracks", "hFoundBC_kTVX_counter_ITSTPCtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_counter_ITSTPCtracks_kTVXinTRD", "hFoundBC_kTVX_counter_ITSTPCtracks_kTVXinTRD", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_counter_ITSTPCtracks_pi", "hFoundBC_kTVX_counter_ITSTPCtracks_pi", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_counter_ITSTPCtracks_ka", "hFoundBC_kTVX_counter_ITSTPCtracks_ka", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_counter_ITSTPCtracks_pr", "hFoundBC_kTVX_counter_ITSTPCtracks_pr", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_counter_GlobalTracks", "hFoundBC_kTVX_counter_GlobalTracks", kTH1D, {axisBC}); + + // mult bins + AxisSpec axisMultBins{{ + -0.5, + 4.5, + 9.5, + 19.5, + 39.5, + 79.5, + 199.5, + }, + "n PV ITSTPC tracks"}; + histos.add("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_multBins", "hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_multBins", kTH2D, {axisBC, axisMultBins}); + histos.add("hFoundBC_kTVX_counter_ITSTPCtracks_multBins", "hFoundBC_kTVX_counter_ITSTPCtracks_multBins", kTH2D, {axisBC, axisMultBins}); + + AxisSpec axisClusterSizes{15, 0.5, 15.5, "cluster size #times cos(#Lambda)"}; + histos.add("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_clsSizeBins", "hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_clsSizeBins", kTH2D, {axisBC, axisClusterSizes}); + histos.add("hFoundBC_kTVX_counter_ITSTPCtracks_clsSizeBins", "hFoundBC_kTVX_counter_ITSTPCtracks_clsSizeBins", kTH2D, {axisBC, axisClusterSizes}); + + // ##### tracks for TVXinTRD collisions + histos.add("hFoundBC_kTVXinTRD_nAllTracks", "hFoundBC_kTVXinTRD_nAllTracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVXinTRD_nTracksPV", "hFoundBC_kTVXinTRD_nTracksPV", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVXinTRD_nGlobalTracks", "hFoundBC_kTVXinTRD_nGlobalTracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVXinTRD_nITStracks", "hFoundBC_kTVXinTRD_nITStracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVXinTRD_nTPCtracks", "hFoundBC_kTVXinTRD_nTPCtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVXinTRD_nTOFtracks", "hFoundBC_kTVXinTRD_nTOFtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVXinTRD_nTRDtracks", "hFoundBC_kTVXinTRD_nTRDtracks", kTH1D, {axisBC}); + + histos.add("hFoundBC_kTVXinTRD_nTRDTOFtracks", "hFoundBC_kTVXinTRD_nTRDTOFtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVXinTRD_nITSTPCTRDtracks", "hFoundBC_kTVXinTRD_nITSTPCTRDtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVXinTRD_nITSTPCTOFtracks", "hFoundBC_kTVXinTRD_nITSTPCTOFtracks", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVXinTRD_nITSTPCTRDTOFtracks", "hFoundBC_kTVXinTRD_nITSTPCTRDTOFtracks", kTH1D, {axisBC}); + + // to study ITS ROF dips vs multiplicity + histos.add("hFoundBC_kTVX_nITSTPCTRDtracks_mult_1_20", "hFoundBC_kTVX_nITSTPCTRDtracks_mult_1_20", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nITSTPCTRDtracks_mult_20_100", "hFoundBC_kTVX_nITSTPCTRDtracks_mult_20_100", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nITSTPCTRDtracks_mult_100_400", "hFoundBC_kTVX_nITSTPCTRDtracks_mult_100_400", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nITSTPCTRDtracks_mult_400_1000", "hFoundBC_kTVX_nITSTPCTRDtracks_mult_400_1000", kTH1D, {axisBC}); + histos.add("hFoundBC_kTVX_nITSTPCTRDtracks_mult_above_1000", "hFoundBC_kTVX_nITSTPCTRDtracks_mult_above_1000", kTH1D, {axisBC}); + + // to study ITS ROF dips vs pt + AxisSpec axisITSlayers{7, -0.5, 7 - 0.5, "layer id"}; + histos.add("hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta02", "hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta02", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histos.add("hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta02_04", "hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta02_04", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histos.add("hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta04_06", "hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta04_06", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histos.add("hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta06_08", "hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta06_08", kTH2D, {axisBC, axisPtBinsForROFstudy}); + + histos.add("hITSlayerCounts_vs_BC_pt02_05", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + histos.add("hITSlayerCounts_vs_BC_pt05_10", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + histos.add("hITSlayerCounts_vs_BC_pt10_50", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + + // pions + histos.add("hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta02", "hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta02", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histos.add("hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta02_04", "hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta02_04", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histos.add("hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta04_06", "hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta04_06", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histos.add("hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta06_08", "hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta06_08", kTH2D, {axisBC, axisPtBinsForROFstudy}); + + histos.add("hITSlayerCounts_vs_BC_pi_pt02_05", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + histos.add("hITSlayerCounts_vs_BC_pi_pt05_10", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + histos.add("hITSlayerCounts_vs_BC_pi_pt10_50", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + + // protons + histos.add("hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta02", "hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta02", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histos.add("hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta02_04", "hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta02_04", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histos.add("hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta04_06", "hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta04_06", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histos.add("hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta06_08", "hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta06_08", kTH2D, {axisBC, axisPtBinsForROFstudy}); + + histos.add("hITSlayerCounts_vs_BC_p_pt02_05", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + histos.add("hITSlayerCounts_vs_BC_p_pt05_10", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + histos.add("hITSlayerCounts_vs_BC_p_pt10_50", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + // histos.add("hITSlayerCounts_vs_BC_p_pt10_50", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + + // bcInTF + AxisSpec axisBCinTF32orbits{32 * 3564, -0.5, 32 * 3564, "bcInTF"}; + histos.add("hBCinTF_kTVX_nTracksPV", "hBCinTF_kTVX_nTracksPV;bc in TF; n tracks", kTH1D, {axisBCinTF32orbits}); + histos.add("hBCinTF_kTVX_nITSTPCTRDtracks", "hBCinTF_kTVX_nITSTPCTRDtracks;bc in TF; n tracks", kTH1D, {axisBCinTF32orbits}); + } + + using DaughterTracks = soa::Join; + // using Colls = soa::Join; + using Colls = soa::Join; + // using Colls = soa::Join; + using BCsRun3 = soa::Join; //, aod::Run3MatchedToBCSparse>; + + void processRun3( + Colls::iterator const& collision, + aod::FT0s const&, + BCsRun3 const& bcs, + aod::Origins const& /*origins*/, + soa::Join const& tracks) + // aod::V0Datas const& v0s, DaughterTracks const&) + { + auto bc = collision.bc_as(); + auto collBC = bc.globalBC() % 3564; + uint64_t globalFoundBC = 9999; + if (collision.has_foundBC()) { + auto bcFound = collision.foundBC_as(); + globalFoundBC = bcFound.globalBC() % 3564; + } else { + return; + } + // histosEvent.fill(HIST("hBC_Bef"), collBC); + + if (fabs(collision.posZ()) > 10) + return; + + // routine for each new run + int runNumber = bc.runNumber(); + + // #### begin of the code from qaPrimVtxVsTime.cxx + if (lastRunNumber != runNumber) { + /// execute the code in this scope only once, i.e. when the current run is considered for the first time in this DF + lastRunNumber = runNumber; + int64_t tsSOR = 0; + // int64_t tsEOR = 0; + + /// reject AO2Ds for which no CCDB access is possible + if (runNumber < 500000) { + LOG(warning) << ">>> run number " << runNumber << " < 500000. access to CCDB not possible. Exiting"; + return; + } + /// If we are here, the current run was never considered before. + + // ##### code to find TF borders, Feb 1, 2024 + int64_t ts = bcs.iteratorAt(0).timestamp(); + // access orbit-reset timestamp + auto ctpx = ccdb->getForTimeStamp>("CTP/Calib/OrbitReset", ts); + int64_t tsOrbitReset = (*ctpx)[0]; // us + + std::map metadata; + metadata["runNumber"] = Form("%d", runNumber); + auto grpecs = ccdb->getSpecific("GLO/Config/GRPECS", ts, metadata); + nOrbitsPerTF = grpecs->getNHBFPerTF(); // assuming 1 orbit = 1 HBF + tsSOR = grpecs->getTimeStart(); // ms + // tsEOR = grpecs->getTimeEnd(); // ms + + // duration of TF in bcs + nBCsPerTF = nOrbitsPerTF * nBCsPerOrbit; + + // IA - try without "-1" shift + orbitSOR = (tsSOR * 1000 - tsOrbitReset) / o2::constants::lhc::LHCOrbitMUS; + orbitSOR = orbitSOR / nOrbitsPerTF * nOrbitsPerTF; // - 1; + bcSOR = orbitSOR * nBCsPerOrbit; + } + + // bc in Time Frame: + int64_t bcInTF = (bc.globalBC() - bcSOR) % nBCsPerTF; + + // ### special sub-loop over tracks for numerator of tracks / T0ampl ratios + if (!collision.has_foundBC()) + return; + int nAllTracks = 0; + int nTracksPV = 0; + + int nITStracks = 0; + int nTPCtracks = 0; + int nITSTPCtracks = 0; + int nTOFtracks = 0; + int nTRDtracks = 0; + + int nTRDTOFtracks = 0; + int nITSTPCTRDtracks = 0; + int nITSTPCTOFtracks = 0; + int nITSTPCTRDTOFtracks = 0; + + int nGlobalTracks = 0; + + for (auto& track : tracks) { + nAllTracks++; + if (!track.isPVContributor()) { + continue; + } + nTracksPV++; + + if (track.isGlobalTrack()) + nGlobalTracks++; + + nITStracks += track.hasITS() && !track.hasTPC(); + nTPCtracks += track.hasTPC(); + nITSTPCtracks += track.hasITS() && track.hasTPC(); + nTOFtracks += track.hasTOF(); + nTRDtracks += track.hasTRD() && !track.hasTOF(); + + nTRDTOFtracks += track.hasTRD() && track.hasTOF(); + nITSTPCTRDtracks += track.hasITS() && track.hasTPC() && track.hasTRD(); + nITSTPCTOFtracks += track.hasITS() && track.hasTPC() && track.hasTOF(); + nITSTPCTRDTOFtracks += track.hasITS() && track.hasTPC() && track.hasTOF() && track.hasTRD(); + + float eta = track.eta(); + float pt = track.pt(); + + bool isPion = (TMath::Abs(track.tpcNSigmaPi()) < 3 && TMath::Abs(track.tpcNSigmaKa()) > 3 && TMath::Abs(track.tpcNSigmaPr()) > 3 && TMath::Abs(track.tpcNSigmaEl()) > 1) ? true : false; + bool isKaon = (TMath::Abs(track.tpcNSigmaKa()) < 3 && TMath::Abs(track.tpcNSigmaPi()) > 3 && TMath::Abs(track.tpcNSigmaPr()) > 3 && TMath::Abs(track.tpcNSigmaEl()) > 1) ? true : false; + bool isProton = (TMath::Abs(track.tpcNSigmaPr()) < 3 && TMath::Abs(track.tpcNSigmaKa()) > 3 && TMath::Abs(track.tpcNSigmaPi()) > 3 && TMath::Abs(track.tpcNSigmaEl()) > 1) ? true : false; + + if (track.hasITS() && track.hasTPC() && fabs(eta) < 0.8) { + histos.fill(HIST("hBC_kTVX_nITSlayers_for_ITSTPCtracks"), collBC, track.itsNCls()); + histos.fill(HIST("hBC_kTVX_counter_ITSTPCtracks"), collBC); + } + + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) && track.hasITS() && track.hasTPC() && fabs(eta) < 0.8) { + + histos.fill(HIST("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks"), globalFoundBC, track.itsNCls()); + histos.fill(HIST("hFoundBC_kTVX_counter_ITSTPCtracks"), globalFoundBC); + + // ### vs mult + histos.fill(HIST("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_multBins"), globalFoundBC, nTracksPV, track.itsNCls()); + histos.fill(HIST("hFoundBC_kTVX_counter_ITSTPCtracks_multBins"), globalFoundBC, nTracksPV); + + // ### vs pt + histos.fill(HIST("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_vs_pt"), globalFoundBC, pt, track.itsNCls()); + histos.fill(HIST("hFoundBC_kTVX_counter_nITSTPCtracks_vs_pt"), globalFoundBC, pt); + + if (collision.alias_bit(kTVXinTRD)) { + histos.fill(HIST("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_kTVXinTRD"), globalFoundBC, track.itsNCls()); + histos.fill(HIST("hFoundBC_kTVX_counter_ITSTPCtracks_kTVXinTRD"), globalFoundBC); + } + + // ### with pid selection + if (isPion) { + histos.fill(HIST("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_pi"), globalFoundBC, track.itsNCls()); + histos.fill(HIST("hFoundBC_kTVX_counter_ITSTPCtracks_pi"), globalFoundBC); + + histos.fill(HIST("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_vs_pt_pi"), globalFoundBC, pt, track.itsNCls()); + histos.fill(HIST("hFoundBC_kTVX_counter_nITSTPCtracks_vs_pt_pi"), globalFoundBC, pt); + } + if (isKaon) { + histos.fill(HIST("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_ka"), globalFoundBC, track.itsNCls()); + histos.fill(HIST("hFoundBC_kTVX_counter_ITSTPCtracks_ka"), globalFoundBC); + + histos.fill(HIST("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_vs_pt_ka"), globalFoundBC, pt, track.itsNCls()); + histos.fill(HIST("hFoundBC_kTVX_counter_nITSTPCtracks_vs_pt_ka"), globalFoundBC, pt); + } + if (isProton) { + histos.fill(HIST("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_pr"), globalFoundBC, track.itsNCls()); + histos.fill(HIST("hFoundBC_kTVX_counter_ITSTPCtracks_pr"), globalFoundBC); + + histos.fill(HIST("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_vs_pt_pr"), globalFoundBC, pt, track.itsNCls()); + histos.fill(HIST("hFoundBC_kTVX_counter_nITSTPCtracks_vs_pt_pr"), globalFoundBC, pt); + } + } + // ### global tracks + if (track.isGlobalTrack() && fabs(eta) < 0.8) { + histos.fill(HIST("hFoundBC_kTVX_nITSlayers_for_GlobalTracks"), globalFoundBC, track.itsNCls()); + histos.fill(HIST("hFoundBC_kTVX_counter_GlobalTracks"), globalFoundBC); + } + + // ### vs cluster size + if (track.itsNCls() >= 5) { + float averageClusterSize = 0.; + for (int i = 0; i < 7; i++) { // info stored in 4 bits + averageClusterSize += (((1 << 4) - 1) & (track.itsClusterSizes() >> 4 * i)); + } + averageClusterSize /= track.itsNCls(); + histos.fill(HIST("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_clsSizeBins"), globalFoundBC, averageClusterSize, track.itsNCls()); + histos.fill(HIST("hFoundBC_kTVX_counter_ITSTPCtracks_clsSizeBins"), globalFoundBC, averageClusterSize); + } + } + + // all collisions + histos.fill(HIST("hFoundBC_nAllTracks"), globalFoundBC, nAllTracks); + histos.fill(HIST("hFoundBC_nTracksPV"), globalFoundBC, nTracksPV); + histos.fill(HIST("hFoundBC_nGlobalTracks"), globalFoundBC, nGlobalTracks); + histos.fill(HIST("hFoundBC_nITStracks"), globalFoundBC, nITStracks); + histos.fill(HIST("hFoundBC_nTPCtracks"), globalFoundBC, nTPCtracks); + histos.fill(HIST("hFoundBC_nTOFtracks"), globalFoundBC, nTOFtracks); + histos.fill(HIST("hFoundBC_nTRDtracks"), globalFoundBC, nTRDtracks); + + histos.fill(HIST("hFoundBC_nTRDTOFtracks"), globalFoundBC, nTRDTOFtracks); + histos.fill(HIST("hFoundBC_nITSTPCTRDtracks"), globalFoundBC, nITSTPCTRDtracks); + histos.fill(HIST("hFoundBC_nITSTPCTOFtracks"), globalFoundBC, nITSTPCTOFtracks); + histos.fill(HIST("hFoundBC_nITSTPCTRDTOFtracks"), globalFoundBC, nITSTPCTRDTOFtracks); + + // TVX collisions + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + histos.fill(HIST("hFoundBC_kTVX_nAllTracks"), globalFoundBC, nAllTracks); + histos.fill(HIST("hFoundBC_kTVX_nTracksPV"), globalFoundBC, nTracksPV); + histos.fill(HIST("hFoundBC_kTVX_nGlobalTracks"), globalFoundBC, nGlobalTracks); + histos.fill(HIST("hFoundBC_kTVX_nITStracks"), globalFoundBC, nITStracks); + histos.fill(HIST("hFoundBC_kTVX_nTPCtracks"), globalFoundBC, nTPCtracks); + histos.fill(HIST("hFoundBC_kTVX_nITSTPCtracks"), globalFoundBC, nITSTPCtracks); + histos.fill(HIST("hFoundBC_kTVX_nTOFtracks"), globalFoundBC, nTOFtracks); + histos.fill(HIST("hFoundBC_kTVX_nTRDtracks"), globalFoundBC, nTRDtracks); + + histos.fill(HIST("hFoundBC_kTVX_nTRDTOFtracks"), globalFoundBC, nTRDTOFtracks); + histos.fill(HIST("hFoundBC_kTVX_nITSTPCTRDtracks"), globalFoundBC, nITSTPCTRDtracks); + histos.fill(HIST("hFoundBC_kTVX_nITSTPCTOFtracks"), globalFoundBC, nITSTPCTOFtracks); + histos.fill(HIST("hFoundBC_kTVX_nITSTPCTRDTOFtracks"), globalFoundBC, nITSTPCTRDTOFtracks); + + histos.fill(HIST("hFoundBC_kTVX_counter"), globalFoundBC); + + // to study ITS ROF dips vs multiplicity + if (nTracksPV >= 1 && nTracksPV < 20) + histos.fill(HIST("hFoundBC_kTVX_nITSTPCTRDtracks_mult_1_20"), globalFoundBC, nITSTPCTRDtracks); + else if (nTracksPV >= 20 && nTracksPV < 100) + histos.fill(HIST("hFoundBC_kTVX_nITSTPCTRDtracks_mult_20_100"), globalFoundBC, nITSTPCTRDtracks); + else if (nTracksPV >= 100 && nTracksPV < 400) + histos.fill(HIST("hFoundBC_kTVX_nITSTPCTRDtracks_mult_100_400"), globalFoundBC, nITSTPCTRDtracks); + else if (nTracksPV >= 400 && nTracksPV < 1000) + histos.fill(HIST("hFoundBC_kTVX_nITSTPCTRDtracks_mult_400_1000"), globalFoundBC, nITSTPCTRDtracks); + else if (nTracksPV >= 1000) + histos.fill(HIST("hFoundBC_kTVX_nITSTPCTRDtracks_mult_above_1000"), globalFoundBC, nITSTPCTRDtracks); + + // vs bcInTF: + histos.fill(HIST("hBCinTF_kTVX_nTracksPV"), bcInTF, nTracksPV); + histos.fill(HIST("hBCinTF_kTVX_nITSTPCTRDtracks"), bcInTF, nITSTPCTRDtracks); + } + + // TVXinTRD collisions + if (collision.alias_bit(kTVXinTRD)) { + histos.fill(HIST("hFoundBC_kTVXinTRD_nAllTracks"), globalFoundBC, nAllTracks); + histos.fill(HIST("hFoundBC_kTVXinTRD_nTracksPV"), globalFoundBC, nTracksPV); + histos.fill(HIST("hFoundBC_kTVXinTRD_nGlobalTracks"), globalFoundBC, nGlobalTracks); + histos.fill(HIST("hFoundBC_kTVXinTRD_nITStracks"), globalFoundBC, nITStracks); + histos.fill(HIST("hFoundBC_kTVXinTRD_nTPCtracks"), globalFoundBC, nTPCtracks); + histos.fill(HIST("hFoundBC_kTVXinTRD_nTOFtracks"), globalFoundBC, nTOFtracks); + histos.fill(HIST("hFoundBC_kTVXinTRD_nTRDtracks"), globalFoundBC, nTRDtracks); + + histos.fill(HIST("hFoundBC_kTVXinTRD_nTRDTOFtracks"), globalFoundBC, nTRDTOFtracks); + histos.fill(HIST("hFoundBC_kTVXinTRD_nITSTPCTRDtracks"), globalFoundBC, nITSTPCTRDtracks); + histos.fill(HIST("hFoundBC_kTVXinTRD_nITSTPCTOFtracks"), globalFoundBC, nITSTPCTOFtracks); + histos.fill(HIST("hFoundBC_kTVXinTRD_nITSTPCTRDTOFtracks"), globalFoundBC, nITSTPCTRDTOFtracks); + } + } + + PROCESS_SWITCH(RofBorderQaTask, processRun3, "Process RofBorderQaTask", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/DPG/Tasks/AOTEvent/rofOccupancyQa.cxx b/DPG/Tasks/AOTEvent/rofOccupancyQa.cxx new file mode 100644 index 00000000000..cbc8d7d56d1 --- /dev/null +++ b/DPG/Tasks/AOTEvent/rofOccupancyQa.cxx @@ -0,0 +1,1366 @@ +// 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 rofOccupancyQa.cxx +/// \brief ROF occupancy QA task +/// +/// \author Igor Altsybeev + +#include + +#include "Framework/ConfigParamSpec.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/LHCConstants.h" +#include "Framework/HistogramRegistry.h" +// #include "DataFormatsParameters/GRPLHCIFData.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsParameters/AggregatedRunInfo.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::aod::evsel; + +using BCsWithBcSelsRun3 = soa::Join; +using FullTracksIU = soa::Join; +const double bcNS = o2::constants::lhc::LHCBunchSpacingNS; + +struct RofOccupancyQaTask { + // configurables for occupancy-based event selection + Configurable confTimeIntervalForOccupancyCalculationMin{"TimeIntervalForOccupancyCalculationMin", -40, "Min time diff window for TPC occupancy calculation, us"}; // o2-linter: disable=name/configurable + Configurable confTimeIntervalForOccupancyCalculationMax{"TimeIntervalForOccupancyCalculationMax", 100, "Max time diff window for TPC occupancy calculation, us"}; // o2-linter: disable=name/configurable + Configurable confTimeRangeVetoOnCollStandard{"TimeRangeVetoOnCollStandard", 10.0, "Exclusion of a collision if there are other collisions nearby, +/- us"}; // o2-linter: disable=name/configurable + Configurable confTimeRangeVetoOnCollNarrow{"TimeRangeVetoOnCollNarrow", 2.0, "Exclusion of a collision if there are other collisions nearby, +/- us"}; // o2-linter: disable=name/configurable + Configurable confNtracksCutVetoOnCollInTimeRange{"NtracksCutVetoOnCollInTimeRange", 800, "Max allowed N tracks (PV contributors) for each nearby collision in +/- time range"}; // o2-linter: disable=name/configurable + Configurable confEpsilonDistanceForVzDependentVetoTPC{"EpsilonDistanceForVzDependentVetoTPC", 2.5, "Epsilon for vZ-dependent veto on drifting TPC tracks from nearby collisions, cm"}; // o2-linter: disable=name/configurable + Configurable confFT0CamplCutVetoOnCollInROF{"FT0CamplPerCollCutVetoOnCollInROF", 5000, "Max allowed FT0C amplitude for each nearby collision inside this ITS ROF"}; // o2-linter: disable=name/configurable + Configurable confEpsilonVzDiffVetoInROF{"EpsilonVzDiffVetoInROF", 0.3, "Minumum distance to nearby collisions along z inside this ITS ROF, cm"}; // o2-linter: disable=name/configurable + Configurable confUseWeightsForOccupancyVariable{"UseWeightsForOccupancyEstimator", 1, "Use or not the delta-time weights for the occupancy estimator"}; // o2-linter: disable=name/configurable + Configurable confFactorForHistRange{"kFactorForHistRange", 1.0, "To change axes b/n pp and Pb-Pb"}; // o2-linter: disable=name/configurable + + Service ccdb; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + int lastRun = -1; // last run number (needed to access ccdb only if run!=lastRun) + // std::bitset bcPatternB; // bc pattern of colliding bunches + + int64_t bcSOR = -1; // global bc of the start of the first orbit + int64_t nBCsPerTF = -1; // duration of TF in bcs, should be 128*3564 or 32*3564 + int rofOffset = -1; // ITS ROF offset, in bc + int rofLength = -1; // ITS ROF length, in bc + + void init(InitContext&) + { + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + float k = confFactorForHistRange; + histos.add("hDeltaTime", "", kTH1D, {{1500, -50, 100}}); + histos.add("hDeltaTimeAboveNtracksCut", "", kTH1D, {{1500, -50, 100}}); + histos.add("hDeltaTime_vZ10cm", "", kTH1D, {{1500, -50, 100}}); + histos.add("hDeltaTime_sel8", "", kTH1D, {{1500, -50, 100}}); + histos.add("hDeltaTime_sel8_vZ10cm", "", kTH1D, {{1500, -50, 100}}); + histos.add("hDeltaTimeAboveNtracksCut_sel8_vZ10cm", "", kTH1D, {{1500, -50, 100}}); + + histos.add("hOccupancyWeights", "", kTH1D, {{150, -50, 100}}); + histos.add("hOccupancyByTracks", "", kTH1D, {{250, 0., 25000 * k}}); + histos.add("hOccupancyByFT0C", "", kTH1D, {{250, 0., 2.5e5 * k}}); + histos.add("hOccupancyByTrInROF", "", kTH1D, {{250, 0., 25000 * k}}); + histos.add("hOccupancyByFT0C_vs_ByTracks", "", kTH2D, {{500, 0., 25000 * k}, {500, 0., 2.5e5 * k}}); + histos.add("hOccupancyByFT0C_vs_ByTracks_vZ_TF_ROF_border_cuts", "", kTH2D, {{500, 0., 25000 * k}, {500, 0., 2.5e5 * k}}); + histos.add("hOccupancyByFT0C_vs_ByTracks_afterNarrowDeltaTimeCut", "", kTH2D, {{500, 0., 25000 * k}, {500, 0., 2.5e5 * k}}); + histos.add("hOccupancyByFT0C_vs_ByTracks_afterStrictDeltaTimeCut", "", kTH2D, {{500, 0., 25000 * k}, {500, 0., 2.5e5 * k}}); + histos.add("hOccupancyByFT0C_vs_ByTracks_afterStandardDeltaTimeCut", "", kTH2D, {{500, 0., 25000 * k}, {500, 0., 2.5e5 * k}}); + histos.add("hOccupancyByFT0C_vs_ByTracks_afterVzDependentDeltaTimeCut", "", kTH2D, {{500, 0., 25000 * k}, {500, 0., 2.5e5 * k}}); + + histos.add("hOccupancyByTracks_CROSSCHECK", "", kTH1D, {{250, 0., 25000 * k}}); + histos.add("hOccupancyByFT0C_CROSSCHECK", "", kTH1D, {{250, 0., 2.5e5 * k}}); + + // this ev nITStr vs FT0C + histos.add("hThisEvITSTr_vs_ThisEvFT0C/all", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + histos.add("hThisEvITSTr_vs_ThisEvFT0C/vZ_TF_ROF_border_cuts", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + histos.add("hThisEvITSTr_vs_ThisEvFT0C/afterNarrowDeltaTimeCut", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + histos.add("hThisEvITSTr_vs_ThisEvFT0C/afterStrictDeltaTimeCut", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + histos.add("hThisEvITSTr_vs_ThisEvFT0C/afterStandardDeltaTimeCut", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + histos.add("hThisEvITSTr_vs_ThisEvFT0C/afterVzDependentDeltaTimeCut", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + + histos.add("hThisEvITSTr_vs_ThisEvFT0C/kNoCollInRofStrict", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + histos.add("hThisEvITSTr_vs_ThisEvFT0C/kNoCollInRofStandard", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + histos.add("hThisEvITSTr_vs_ThisEvFT0C/kNoCollInRofWithCloseVz", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + + histos.add("hThisEvITSTr_vs_ThisEvFT0C/NarrowDeltaCut_StdTimeAndRofCuts", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + + histos.add("hThisEvITSTr_vs_ThisEvFT0C/occupBelow2000", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + histos.add("hThisEvITSTr_vs_ThisEvFT0C/hThisEvITSTPCTr_vs_ThisEvFT0C_occupBelow2000", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + histos.add("hThisEvITSTr_vs_ThisEvFT0C/NarrowDeltaCut_StdTimeAndRofCuts_occupBelow2000", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + histos.add("hThisEvITSTr_vs_ThisEvFT0C/hThisEvITSTPCTr_vs_ThisEvFT0C_NarrowDeltaCut_StdTimeAndRofCuts_occupBelow2000", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + + // CROSS-CHECK SEL BITS: + histos.add("hThisEvITSTr_vs_ThisEvFT0C/CROSSCHECK_afterNarrowDeltaTimeCut", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + histos.add("hThisEvITSTr_vs_ThisEvFT0C/CROSSCHECK_afterStrictDeltaTimeCut", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + histos.add("hThisEvITSTr_vs_ThisEvFT0C/CROSSCHECK_afterStandardDeltaTimeCut", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + + histos.add("hThisEvITSTr_vs_ThisEvFT0C/CROSSCHECK_kNoCollInRofStrict", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + histos.add("hThisEvITSTr_vs_ThisEvFT0C/CROSSCHECK_kNoCollInRofStandard", "", kTH2D, {{250, 0., 1e5 * k}, {250, 0., 10000 * k}}); + // histos.add("hThisEvITSTr_vs_ThisEvFT0C/CROSSCHECK_kNoCollInRofWithCloseVz", "", kTH2D, {{250, 0., 1e5*k}, {250, 0., 10000*k}}); + + // this ev nITSTPCtr vs nITStr + histos.add("hThisEvITSTPCTr_vs_ThisEvITStr/all", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 5000 * k}}); + histos.add("hThisEvITSTPCTr_vs_ThisEvITStr/vZ_TF_ROF_border_cuts", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 5000 * k}}); + histos.add("hThisEvITSTPCTr_vs_ThisEvITStr/afterNarrowDeltaTimeCut", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 5000 * k}}); + histos.add("hThisEvITSTPCTr_vs_ThisEvITStr/afterStrictDeltaTimeCut", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 5000 * k}}); + histos.add("hThisEvITSTPCTr_vs_ThisEvITStr/afterStandardDeltaTimeCut", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 5000 * k}}); + histos.add("hThisEvITSTPCTr_vs_ThisEvITStr/afterVzDependentDeltaTimeCut", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 5000 * k}}); + + histos.add("hThisEvITSTPCTr_vs_ThisEvITStr/kNoCollInRofStrict", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 5000 * k}}); + histos.add("hThisEvITSTPCTr_vs_ThisEvITStr/kNoCollInRofStandard", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 5000 * k}}); + histos.add("hThisEvITSTPCTr_vs_ThisEvITStr/kNoCollInRofWithCloseVz", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 5000 * k}}); + + histos.add("hThisEvITSTPCTr_vs_ThisEvITStr/NarrowDeltaCut_StdTimeAndRofCuts", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 5000 * k}}); + + histos.add("hThisEvITSTPCTr_vs_ThisEvITStr/occupBelow2000", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 5000 * k}}); + histos.add("hThisEvITSTPCTr_vs_ThisEvITStr/occupBelow2000_NarrowDeltaCut_StdTimeAndRofCuts", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 5000 * k}}); + histos.add("hThisEvITSTPCTr_vs_ThisEvITStr/occupBelow2000_StrictDeltaTimeCutAndRofCuts", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 5000 * k}}); + + histos.add("hThisEvITStr_vs_vZcut", "", kTH2D, {{200, 0., 10.}, {200, 0., 8000 * k}}); + histos.add("hThisEvITSTPCtr_vs_vZcut", "", kTH2D, {{200, 0., 10.}, {200, 0., 5000 * k}}); + + histos.add("hThisEvITStr_vs_vZ", "", kTH2D, {{400, -20, 20.}, {200, 0., 8000 * k}}); + histos.add("hThisEvITSTPCtr_vs_vZ", "", kTH2D, {{400, -20, 20.}, {200, 0., 5000 * k}}); + + histos.add("hVz", "", kTH1D, {{1600, -40, 40.}}); + histos.add("hDeltaVz", "", kTH1D, {{1600, -40, 40.}}); + histos.add("hDeltaVzAfterCuts", "", kTH1D, {{1600, -40, 40.}}); + histos.add("hDeltaVzAfterTFandROFborderCuts", "", kTH1D, {{1600, -40, 40.}}); + histos.add("hDeltaVzGivenCollAbove100NearbyBelow100", "", kTH1D, {{1600, -40, 40.}}); + histos.add("hDeltaVzGivenCollBelow100NearbyAbove100", "", kTH1D, {{1600, -40, 40.}}); + histos.add("hDeltaVzAfterAllCuts", "", kTH1D, {{1600, -40, 40.}}); + + // + histos.add("hDeltaVzVsDeltaTime1", "", kTH2D, {{400, -25, 25}, {100, -20, 20}}); + histos.add("hDeltaVzVsDeltaTime2", "", kTH2D, {{400, -25, 25}, {100, -20, 20}}); + histos.add("hDeltaVzVsDeltaTime3", "", kTH2D, {{400, -25, 25}, {100, -20, 20}}); + histos.add("hDeltaVzVsDeltaTime4", "", kTH2D, {{400, -25, 25}, {100, -20, 20}}); + + histos.add("hEtaVz02", "", kTH1D, {{500, -2.5, 2.5}}); + histos.add("hEtaVzPlus10", "", kTH1D, {{500, -2.5, 2.5}}); + histos.add("hEtaVzMinus10", "", kTH1D, {{500, -2.5, 2.5}}); + histos.add("hEtaVzPlus15", "", kTH1D, {{500, -2.5, 2.5}}); + histos.add("hEtaVzMinus15", "", kTH1D, {{500, -2.5, 2.5}}); + histos.add("hEtaVsVz", "", kTH2D, {{250, -25, 25}, {250, -2.5, 2.5}}); + histos.add("hNPVcontribVsVz", "", kTH2D, {{250, -25, 25}, {500, 0., 8000}}); + histos.add("hNPVcontribVsVz_eta08", "", kTH2D, {{250, -25, 25}, {500, 0., 8000}}); + + // + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTPCTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTPCTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + histos.add("afterStrictDeltaTimeCut/hThisEvITSTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("afterStrictDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("afterStrictDeltaTimeCut/hThisEvITSTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + histos.add("afterStrictDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + histos.add("afterStandardDeltaTimeCut/hThisEvITSTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("afterStandardDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("afterStandardDeltaTimeCut/hThisEvITSTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + histos.add("afterStandardDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + histos.add("afterVzDependentDeltaTimeCut/hThisEvITSTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("afterVzDependentDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("afterVzDependentDeltaTimeCut/hThisEvITSTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + histos.add("afterVzDependentDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + histos.add("kNoCollInRofStrict/hThisEvITSTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("kNoCollInRofStrict/hThisEvITSTPCTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("kNoCollInRofStrict/hThisEvITSTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + histos.add("kNoCollInRofStrict/hThisEvITSTPCTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + histos.add("kNoCollInRofStandard/hThisEvITSTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("kNoCollInRofStandard/hThisEvITSTPCTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("kNoCollInRofStandard/hThisEvITSTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + histos.add("kNoCollInRofStandard/hThisEvITSTPCTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + histos.add("kNoCollInRofWithCloseVz/hThisEvITSTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("kNoCollInRofWithCloseVz/hThisEvITSTPCTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("kNoCollInRofWithCloseVz/hThisEvITSTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + histos.add("kNoCollInRofWithCloseVz/hThisEvITSTPCTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + histos.add("NarrowDeltaCut_StdTimeAndRofCuts/hThisEvITSTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("NarrowDeltaCut_StdTimeAndRofCuts/hThisEvITSTPCTr_vs_occupancyByTracks", "", kTH2D, {{250, 0., 25000 * k}, {250, 0., 8000}}); + histos.add("NarrowDeltaCut_StdTimeAndRofCuts/hThisEvITSTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + histos.add("NarrowDeltaCut_StdTimeAndRofCuts/hThisEvITSTPCTr_vs_occupancyByFT0C", "", kTH2D, {{250, 0., 2.5e5 * k}, {250, 0., 8000}}); + + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF", "", kTH2D, {{250, 0., 12000 * k}, {250, 0., 8000 * k}}); + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTPCTr_vs_occupancyInROF", "", kTH2D, {{250, 0., 12000 * k}, {250, 0., 8000 * k}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInROF", "", kTH2D, {{250, 0., 12000 * k}, {250, 0., 8000 * k}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyInROF", "", kTH2D, {{250, 0., 12000 * k}, {250, 0., 8000 * k}}); + + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF_HasNeighbours", "", kTH2D, {{250, 0., 12000 * k}, {250, 0., 8000 * k}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInROF_HasNeighbours", "", kTH2D, {{250, 0., 12000 * k}, {250, 0., 8000 * k}}); + histos.add("kNoCollInRofWithCloseVz/hThisEvITSTr_vs_occupancyInROF_HasNeighbours", "", kTH2D, {{250, 0., 12000 * k}, {250, 0., 8000 * k}}); + + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyFT0CInROF", "", kTH2D, {{250, 0., 100000 * k}, {250, 0., 8000 * k}}); + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTPCTr_vs_occupancyFT0CInROF", "", kTH2D, {{250, 0., 100000 * k}, {250, 0., 8000 * k}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyFT0CInROF", "", kTH2D, {{250, 0., 100000 * k}, {250, 0., 8000 * k}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyFT0CInROF", "", kTH2D, {{250, 0., 100000 * k}, {250, 0., 8000 * k}}); + + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyFT0CInROF_HasNeighbours", "", kTH2D, {{250, 0., 100000 * k}, {250, 0., 8000 * k}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyFT0CInROF_HasNeighbours", "", kTH2D, {{250, 0., 100000 * k}, {250, 0., 8000 * k}}); + histos.add("kNoCollInRofWithCloseVz/hThisEvITSTr_vs_occupancyFT0CInROF_HasNeighbours", "", kTH2D, {{250, 0., 100000 * k}, {250, 0., 8000 * k}}); + + histos.add("vZ_TF_ROF_border_cuts/hThisEvFT0C_vs_occupancyFT0CInROF_HasNeighbours", "", kTH2D, {{250, 0., 100000 * k}, {250, 0., 100000 * k}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvFT0C_vs_occupancyFT0CInROF_HasNeighbours", "", kTH2D, {{250, 0., 100000 * k}, {250, 0., 100000 * k}}); + histos.add("kNoCollInRofWithCloseVz/hThisEvFT0C_vs_occupancyFT0CInROF_HasNeighbours", "", kTH2D, {{250, 0., 100000 * k}, {250, 0., 100000 * k}}); + + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF_2coll", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInROF_2coll", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("kNoCollInRofWithCloseVz/hThisEvITSTr_vs_occupancyInROF_2coll", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + + histos.add("vZ_TF_ROF_border_cuts/hThisEvFT0C_vs_occupancyFT0CInROF_2coll", "", kTH2D, {{250, 0., 100000 * k}, {250, 0., 100000 * k}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvFT0C_vs_occupancyFT0CInROF_2coll", "", kTH2D, {{250, 0., 100000 * k}, {250, 0., 100000 * k}}); + histos.add("kNoCollInRofWithCloseVz/hThisEvFT0C_vs_occupancyFT0CInROF_2coll", "", kTH2D, {{250, 0., 100000 * k}, {250, 0., 100000 * k}}); + + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInAnotherEarlierROF_1collPerROF", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInAnotherEarlierROF_1collPerROF", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + // histos.add("kNoCollInRofWithCloseVz/hThisEvITSTr_vs_occupancyInAnotherEarlierROF_1collPerROF", "", kTH2D, {{250, 0., 8000*k}, {250, 0., 8000*k}}); + + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInPreviousROF_1collPerROF", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInPreviousROF_1collPerROF", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInPrevPrevROF_1collPerROF", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + + // coll on x axis always has more tracks: + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF_2coll_XaxisWins", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInROF_2coll_XaxisWins", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInPreviousROF_1collPerROF_XaxisWins", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInPreviousROF_1collPerROF_XaxisWins", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + + // 2,3,4 colls in ROF + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF_2coll_noVzCutOnOtherVertices", "", kTH2D, {{500, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF_3coll_noVzCutOnOtherVertices", "", kTH2D, {{500, 0., 20000 * k}, {250, 0., 8000 * k}}); + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF_4coll_noVzCutOnOtherVertices", "", kTH2D, {{500, 0., 20000 * k}, {250, 0., 8000 * k}}); + + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_1coll_in_ROF", "", kTH1D, {{250, 0., 8000 * k}}); + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_2coll_in_ROF", "", kTH1D, {{250, 0., 8000 * k}}); + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_3coll_in_ROF", "", kTH1D, {{250, 0., 8000 * k}}); + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_4coll_in_ROF", "", kTH1D, {{250, 0., 8000 * k}}); + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_5collOrMore_in_ROF", "", kTH1D, {{250, 0., 8000 * k}}); + + // 1D + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_allOccup_2coll_inROF", "", kTH1D, {{250, 0., 8000 * k}}); + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_lowOccup_2coll_inROF", "", kTH1D, {{250, 0., 8000 * k}}); + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_highOccup_2coll_inROF", "", kTH1D, {{250, 0., 8000 * k}}); + + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_allOccup_1collPerROF", "", kTH1D, {{250, 0., 8000 * k}}); + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_lowOccup_1collPerROF", "", kTH1D, {{250, 0., 8000 * k}}); + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_highOccup_1collPerROF", "", kTH1D, {{250, 0., 8000 * k}}); + + // now with the ratio on y-axis: + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF_2coll_XaxisWins_RatioV2toV1", "", kTH2D, {{250, 0., 8000 * k}, {220, 0., 1.1}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInROF_2coll_XaxisWins_RatioV2toV1", "", kTH2D, {{250, 0., 8000 * k}, {220, 0., 1.1}}); + + histos.add("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInPreviousROF_1collPerROF_XaxisWins_RatioV2toV1", "", kTH2D, {{250, 0., 8000 * k}, {220, 0., 1.1}}); + histos.add("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInPreviousROF_1collPerROF_XaxisWins_RatioV2toV1", "", kTH2D, {{250, 0., 8000 * k}, {220, 0., 1.1}}); + + histos.add("afterNarrowDeltaTimeCut/hSum_2coll_withFT0above4000_inROF", "", kTH1D, {{500, 0., 15000 * k}}); + histos.add("afterNarrowDeltaTimeCut/hSum_2coll_withFT0above4000_thisROFprevROF", "", kTH1D, {{500, 0., 15000 * k}}); + histos.add("afterNarrowDeltaTimeCut/hSum_2coll_withFT0above4000_thisROFprevPrevROF", "", kTH1D, {{500, 0., 15000 * k}}); + histos.add("afterNarrowDeltaTimeCut/hSum_2coll_withFT0above4000_thisROFearlierThanPrevPrevROF", "", kTH1D, {{500, 0., 15000 * k}}); + + // + histos.add("hNcollPerROF", "", kTH1D, {{16, -0.5, 15.5}}); + + // ROF-by-ROF study: + histos.add("ROFbyROF/nPV_vs_ROFid", "", kTH2D, {{800, 0., 8000 * k}, {10, -0.5, 9.5}}); + histos.add("ROFbyROF/nPV_vs_subROFid", "", kTH2D, {{800, 0., 8000 * k}, {20, -0.5, 19.5}}); + + histos.add("ROFbyROF/FT0C_vs_ROFid", "", kTH2D, {{800, 0., 80000 * k}, {10, -0.5, 9.5}}); + histos.add("ROFbyROF/FT0C_vs_subROFid", "", kTH2D, {{800, 0., 80000 * k}, {20, -0.5, 19.5}}); + + histos.add("ROFbyROF/nPV_00x00", "", kTH1D, {{250, 0., 8000 * k}}); + + histos.add("ROFbyROF/nPV_10x00", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_01x00", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_00x10", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_00x01", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + + histos.add("ROFbyROF/nPV_11x00", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_01x10", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_00x11", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + + histos.add("ROFbyROF/nPV_10x00_nearbyByFT0C", "", kTH2D, {{250, 0., 80000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_01x00_nearbyByFT0C", "", kTH2D, {{250, 0., 80000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_00x10_nearbyByFT0C", "", kTH2D, {{250, 0., 80000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_00x01_nearbyByFT0C", "", kTH2D, {{250, 0., 80000 * k}, {250, 0., 8000 * k}}); + + histos.add("ROFbyROF/nPV_10x00_thisFT0C", "", kTH2D, {{250, 0., 80000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_01x00_thisFT0C", "", kTH2D, {{250, 0., 80000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_00x10_thisFT0C", "", kTH2D, {{250, 0., 80000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_00x01_thisFT0C", "", kTH2D, {{250, 0., 80000 * k}, {250, 0., 8000 * k}}); + + // histos.add("ROFbyROF/nPV_11x11", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + + // ### sub-ROFs: + histos.add("ROFbyROF/nPV_0_x00_0", "", kTH1D, {{250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_0_0x0_0", "", kTH1D, {{250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_0_00x_0", "", kTH1D, {{250, 0., 8000 * k}}); + + // corr with prev subROFs: + histos.add("ROFbyROF/nPV_0_00x_y00_000", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_0_0x0_y00_000", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_0_x00_y00_000", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + + histos.add("ROFbyROF/nPV_0_00x_0y0_000", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_0_0x0_0y0_000", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_0_x00_0y0_000", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + + histos.add("ROFbyROF/nPV_0_00x_00y_000", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_0_0x0_00y_000", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_0_x00_00y_000", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + + // corr with next subROFs: + histos.add("ROFbyROF/nPV_000_y00_00x_0", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_000_y00_0x0_0", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_000_y00_x00_0", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + + histos.add("ROFbyROF/nPV_000_0y0_00x_0", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_000_0y0_0x0_0", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_000_0y0_x00_0", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + + histos.add("ROFbyROF/nPV_000_00y_00x_0", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_000_00y_0x0_0", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + histos.add("ROFbyROF/nPV_000_00y_x00_0", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + + // #### new occupancy studies + histos.add("nPV_vs_occupancyByTracks/sel8", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 25000 * k}}); + histos.add("nPV_vs_occupancyByTracks/NoCollInTimeRangeNarrow", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 25000 * k}}); + histos.add("nPV_vs_occupancyByTracks/NoCollInTimeRangeStrict", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 25000 * k}}); + histos.add("nPV_vs_occupancyByTracks/NoCollInTimeRangeStandard", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 25000 * k}}); + histos.add("nPV_vs_occupancyByTracks/NoCollInRofStrict", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 25000 * k}}); + histos.add("nPV_vs_occupancyByTracks/NoCollInRofStandard", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 25000 * k}}); + histos.add("nPV_vs_occupancyByTracks/NoCollInTimeAndRofStandard", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 25000 * k}}); + histos.add("nPV_vs_occupancyByTracks/NoCollInTimeAndRofStrict", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 25000 * k}}); + histos.add("nPV_vs_occupancyByTracks/NoCollInTimeAndRofStrict_vZ_5cm", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 25000 * k}}); + histos.add("nPV_vs_occupancyByTracks/kNoHighMultCollInPrevRof", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 25000 * k}}); + histos.add("nPV_vs_occupancyByTracks/kNoHighMultCollInPrevRofAndRofStrict", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 25000 * k}}); + + histos.add("nPV_vs_occupancyByFT0C/sel8", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 2.5e5 * k}}); + histos.add("nPV_vs_occupancyByFT0C/NoCollInTimeRangeNarrow", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 2.5e5 * k}}); + histos.add("nPV_vs_occupancyByFT0C/NoCollInTimeRangeStrict", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 2.5e5 * k}}); + histos.add("nPV_vs_occupancyByFT0C/NoCollInTimeRangeStandard", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 2.5e5 * k}}); + histos.add("nPV_vs_occupancyByFT0C/NoCollInRofStrict", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 2.5e5 * k}}); + histos.add("nPV_vs_occupancyByFT0C/NoCollInRofStandard", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 2.5e5 * k}}); + histos.add("nPV_vs_occupancyByFT0C/NoCollInTimeAndRofStandard", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 2.5e5 * k}}); + histos.add("nPV_vs_occupancyByFT0C/NoCollInTimeAndRofStrict", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 2.5e5 * k}}); + histos.add("nPV_vs_occupancyByFT0C/NoCollInTimeAndRofStrict_vZ_5cm", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 2.5e5 * k}}); + histos.add("nPV_vs_occupancyByFT0C/kNoHighMultCollInPrevRof", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 2.5e5 * k}}); + histos.add("nPV_vs_occupancyByFT0C/kNoHighMultCollInPrevRofAndRofStrict", "", kTH2D, {{125, 0., 8000 * k}, {100, 0., 2.5e5 * k}}); + } + + Partition pvTracks = ((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)); + // Partition pvTracks = ((aod::track::flags & (uint32_t)o2::aod::track::PVContributor) == (uint32_t)o2::aod::track::PVContributor); + Preslice perCollision = aod::track::collisionId; + + using ColEvSels = soa::Join; //, aod::Mults, aod::CentFT0Cs>; + void processRun3(ColEvSels const& cols, FullTracksIU const&, BCsWithBcSelsRun3 const& bcs, aod::FT0s const&) + { + int run = bcs.iteratorAt(0).runNumber(); + // extract bc pattern from CCDB for data or anchored MC only + if (run != lastRun && run >= 500000) { + lastRun = run; + auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), run); + // first bc of the first orbit + bcSOR = runInfo.orbitSOR * o2::constants::lhc::LHCMaxBunches; + // duration of TF in bcs + nBCsPerTF = runInfo.orbitsPerTF * o2::constants::lhc::LHCMaxBunches; + + // extract ITS ROF parameters + int64_t ts = bcs.iteratorAt(0).timestamp(); + auto alppar = ccdb->getForTimeStamp>("ITS/Config/AlpideParam", ts); + rofOffset = alppar->roFrameBiasInBC; + rofLength = alppar->roFrameLengthInBC; + LOGP(info, "rofOffset={} rofLength={}", rofOffset, rofLength); + } + + std::vector vTracksITS567perColl(cols.size(), 0); // counter of tracks per collision for occupancy studies + std::vector vTracksITSTPCperColl(cols.size(), 0); // counter of tracks per collision for occupancy studies + std::vector vTracksITS567eta08perColl(cols.size(), 0); // counter of tracks per collision for occupancy studies + std::vector vAmpFT0CperColl(cols.size(), 0); // amplitude FT0C per collision + std::vector vIsFullInfoForOccupancy(cols.size(), 0); // info for occupancy in +/- windows is available (i.e. a given coll is not too close to the TF borders) + const float timeWinOccupancyCalcMinNS = confTimeIntervalForOccupancyCalculationMin * 1e3; // ns + const float timeWinOccupancyCalcMaxNS = confTimeIntervalForOccupancyCalculationMax * 1e3; // ns + std::vector vIsVertexITSTPC(cols.size(), 0); // at least one of vertex contributors is ITS-TPC track + std::vector vIsVertexTOFmatched(cols.size(), 0); // at least one of vertex contributors is matched to TOF + std::vector vIsVertexTRDmatched(cols.size(), 0); // at least one of vertex contributors is matched to TRD + + // std::vector vCollisionsPerBc(bcs.size(), 0); // counter of collisions per found bc for pileup checks + std::vector vFoundBCindex(cols.size(), -1); // indices of found bcs + std::vector vFoundGlobalBC(cols.size(), 0); // global BCs for collisions + + std::vector vCollVz(cols.size(), 0); // vector with vZ positions for each collision + std::vector vIsSel8(cols.size(), 0); + std::vector vCombCond(cols.size(), 0); + + std::vector vCollRofId(cols.size(), 0); // rof Id for each collision + std::vector vCollRofIdPerOrbit(cols.size(), 0); // rof Id for each collision, per orbit + std::vector vCollRofSubId(cols.size(), 0); // rof sub-Id for each collision + std::vector vCollRofSubIdPerOrbit(cols.size(), 0); // rof sub-Id for each collision, per orbit + + // first loop over collisions - collecting info + for (const auto& col : cols) { + int32_t colIndex = col.globalIndex(); + // auto bc = col.bc_as(); + const auto& bc = col.foundBC_as(); + int64_t globalBC = bc.globalBC(); + + int32_t foundBC = bc.globalIndex(); + vFoundBCindex[colIndex] = foundBC; + vFoundGlobalBC[colIndex] = globalBC; // bc.globalBC(); + + if (bc.has_foundFT0()) + vAmpFT0CperColl[colIndex] = bc.foundFT0().sumAmpC(); + + vCollVz[colIndex] = col.posZ(); + vIsSel8[colIndex] = col.sel8(); + vCombCond[colIndex] = vIsSel8[colIndex] && (std::fabs(vCollVz[colIndex]) < 8) && (vAmpFT0CperColl[colIndex] > 500 /* a.u.*/); + + int bcInTF = (bc.globalBC() - bcSOR) % nBCsPerTF; + vIsFullInfoForOccupancy[colIndex] = ((bcInTF - 300) * bcNS > -timeWinOccupancyCalcMinNS) && ((nBCsPerTF - 4000 - bcInTF) * bcNS > timeWinOccupancyCalcMaxNS) ? true : false; + + // int64_t rofId = (globalBC + 3564 - rofOffset) / rofLength; + int rofId = (bcInTF - rofOffset) / rofLength; + vCollRofId[colIndex] = rofId; + + int rofIdPerOrbit = rofId % (3564 / rofLength); + vCollRofIdPerOrbit[colIndex] = rofIdPerOrbit; + + int bcInITSROF = (globalBC + 3564 - rofOffset) % rofLength; + int subRofId = bcInITSROF / (rofLength / 3); + vCollRofSubId[colIndex] = subRofId; + vCollRofSubIdPerOrbit[colIndex] = 3 * rofIdPerOrbit + subRofId; + // LOGP(info, ">> rofId={} rofIdPerOrbit={} subRofId={} vCollRofSubId={}", rofId, rofIdPerOrbit, subRofId, vCollRofSubId[colIndex]); + + auto colPvTracks = pvTracks.sliceBy(perCollision, col.globalIndex()); + + for (const auto& track : colPvTracks) { + if (track.itsNCls() >= 5) { + vTracksITS567perColl[colIndex]++; + if (std::fabs(track.eta()) < 0.8) + vTracksITS567eta08perColl[colIndex]++; + if (track.tpcNClsFound() > 70) + vTracksITSTPCperColl[colIndex]++; + if (std::fabs(col.posZ()) < 1) + histos.fill(HIST("hEtaVz02"), track.eta()); + else if (col.posZ() > 9.5 && col.posZ() < 10.5) + histos.fill(HIST("hEtaVzPlus10"), track.eta()); + else if (col.posZ() > -10.5 && col.posZ() < -9.5) + histos.fill(HIST("hEtaVzMinus10"), track.eta()); + else if (col.posZ() > 14.5 && col.posZ() < 15.5) + histos.fill(HIST("hEtaVzPlus15"), track.eta()); + else if (col.posZ() > -15.5 && col.posZ() < -14.5) + histos.fill(HIST("hEtaVzMinus15"), track.eta()); + + histos.fill(HIST("hEtaVsVz"), col.posZ(), track.eta()); + } + if (track.hasTRD()) + vIsVertexTRDmatched[colIndex] = 1; + if (track.hasTPC()) + vIsVertexITSTPC[colIndex] = 1; + if (track.hasTOF()) { + vIsVertexTOFmatched[colIndex] = 1; + } + } + + if (col.sel8()) { + histos.fill(HIST("hNPVcontribVsVz"), col.posZ(), vTracksITS567perColl[colIndex]); + histos.fill(HIST("hNPVcontribVsVz_eta08"), col.posZ(), vTracksITS567eta08perColl[colIndex]); + } + } + + // ROF-by-ROF study: + int nColls = vCombCond.size(); + for (const auto& col : cols) { + int32_t k = col.globalIndex(); + + if (k - 2 < 0 || k + 2 > nColls - 1) + continue; + + // the "purest case" + if (vCombCond[k]) { + if (vCollRofId[k - 1] < vCollRofId[k] - 2 && /* next coll is far */ vCollRofId[k + 1] > vCollRofId[k] + 2) // 00x00 + histos.fill(HIST("ROFbyROF/nPV_00x00"), vTracksITS567perColl[k]); + + if (vCollRofId[k - 1] < vCollRofId[k] - 1 && /* next coll is far */ vCollRofId[k + 1] > vCollRofId[k] + 1) // 0x0 + { + if (vCollRofSubId[k] == 0) + histos.fill(HIST("ROFbyROF/nPV_0_x00_0"), vTracksITS567perColl[k]); + if (vCollRofSubId[k] == 1) + histos.fill(HIST("ROFbyROF/nPV_0_0x0_0"), vTracksITS567perColl[k]); + if (vCollRofSubId[k] == 2) + histos.fill(HIST("ROFbyROF/nPV_0_00x_0"), vTracksITS567perColl[k]); + } + } + + // prev 1 coll + if (vCombCond[k] && vCombCond[k - 1]) { + if (vCollRofId[k - 2] < vCollRofId[k] - 2 && vCollRofId[k - 1] == vCollRofId[k] - 2 && /* next coll is far */ vCollRofId[k + 1] > vCollRofId[k] + 2) // 10x00 + { + histos.fill(HIST("ROFbyROF/nPV_10x00"), vTracksITS567perColl[k - 1], vTracksITS567perColl[k]); + histos.fill(HIST("ROFbyROF/nPV_10x00_nearbyByFT0C"), vAmpFT0CperColl[k - 1], vTracksITS567perColl[k]); + histos.fill(HIST("ROFbyROF/nPV_10x00_thisFT0C"), vAmpFT0CperColl[k], vTracksITS567perColl[k]); + } + if (vCollRofId[k - 2] < vCollRofId[k] - 2 && vCollRofId[k - 1] == vCollRofId[k] - 1 && /* next coll is far */ vCollRofId[k + 1] > vCollRofId[k] + 2) // 01x00 + { + histos.fill(HIST("ROFbyROF/nPV_01x00"), vTracksITS567perColl[k - 1], vTracksITS567perColl[k]); + histos.fill(HIST("ROFbyROF/nPV_01x00_nearbyByFT0C"), vAmpFT0CperColl[k - 1], vTracksITS567perColl[k]); + histos.fill(HIST("ROFbyROF/nPV_01x00_thisFT0C"), vAmpFT0CperColl[k], vTracksITS567perColl[k]); + } + + if (vCollRofId[k - 2] < vCollRofId[k] - 2 && vCollRofId[k - 1] == vCollRofId[k] - 1 && /* next coll is far */ vCollRofId[k + 1] > vCollRofId[k] + 1) // 01x0 + { + // sub-ROFs: + if (vCollRofSubId[k - 1] == 2 && vCollRofSubId[k] == 0) + histos.fill(HIST("ROFbyROF/nPV_0_00x_y00_000"), vTracksITS567perColl[k - 1], vTracksITS567perColl[k]); + if (vCollRofSubId[k - 1] == 1 && vCollRofSubId[k] == 0) + histos.fill(HIST("ROFbyROF/nPV_0_0x0_y00_000"), vTracksITS567perColl[k - 1], vTracksITS567perColl[k]); + if (vCollRofSubId[k - 1] == 0 && vCollRofSubId[k] == 0) + histos.fill(HIST("ROFbyROF/nPV_0_x00_y00_000"), vTracksITS567perColl[k - 1], vTracksITS567perColl[k]); + + if (vCollRofSubId[k - 1] == 2 && vCollRofSubId[k] == 1) + histos.fill(HIST("ROFbyROF/nPV_0_00x_0y0_000"), vTracksITS567perColl[k - 1], vTracksITS567perColl[k]); + if (vCollRofSubId[k - 1] == 1 && vCollRofSubId[k] == 1) + histos.fill(HIST("ROFbyROF/nPV_0_0x0_0y0_000"), vTracksITS567perColl[k - 1], vTracksITS567perColl[k]); + if (vCollRofSubId[k - 1] == 0 && vCollRofSubId[k] == 1) + histos.fill(HIST("ROFbyROF/nPV_0_x00_0y0_000"), vTracksITS567perColl[k - 1], vTracksITS567perColl[k]); + + if (vCollRofSubId[k - 1] == 2 && vCollRofSubId[k] == 2) + histos.fill(HIST("ROFbyROF/nPV_0_00x_00y_000"), vTracksITS567perColl[k - 1], vTracksITS567perColl[k]); + if (vCollRofSubId[k - 1] == 1 && vCollRofSubId[k] == 2) + histos.fill(HIST("ROFbyROF/nPV_0_0x0_00y_000"), vTracksITS567perColl[k - 1], vTracksITS567perColl[k]); + if (vCollRofSubId[k - 1] == 0 && vCollRofSubId[k] == 2) + histos.fill(HIST("ROFbyROF/nPV_0_x00_00y_000"), vTracksITS567perColl[k - 1], vTracksITS567perColl[k]); + } + } + // next 1 coll + if (vCombCond[k] && vCombCond[k + 1]) { + if (vCollRofId[k - 1] < vCollRofId[k] - 2 /* prev coll is far */ && vCollRofId[k + 1] == vCollRofId[k] + 1 && vCollRofId[k + 2] > vCollRofId[k] + 2) // 00x10 + { + histos.fill(HIST("ROFbyROF/nPV_00x10"), vTracksITS567perColl[k + 1], vTracksITS567perColl[k]); + histos.fill(HIST("ROFbyROF/nPV_00x10_nearbyByFT0C"), vAmpFT0CperColl[k + 1], vTracksITS567perColl[k]); + histos.fill(HIST("ROFbyROF/nPV_00x10_thisFT0C"), vAmpFT0CperColl[k], vTracksITS567perColl[k]); + } + + if (vCollRofId[k - 1] < vCollRofId[k] - 1 /* prev coll is far */ && vCollRofId[k + 1] == vCollRofId[k] + 1 && vCollRofId[k + 2] > vCollRofId[k] + 2) // 0x10 + { + // sub-ROFs: + if (vCollRofSubId[k + 1] == 2 && vCollRofSubId[k] == 0) + histos.fill(HIST("ROFbyROF/nPV_000_y00_00x_0"), vTracksITS567perColl[k + 1], vTracksITS567perColl[k]); + if (vCollRofSubId[k + 1] == 1 && vCollRofSubId[k] == 0) + histos.fill(HIST("ROFbyROF/nPV_000_y00_0x0_0"), vTracksITS567perColl[k + 1], vTracksITS567perColl[k]); + if (vCollRofSubId[k + 1] == 0 && vCollRofSubId[k] == 0) + histos.fill(HIST("ROFbyROF/nPV_000_y00_x00_0"), vTracksITS567perColl[k + 1], vTracksITS567perColl[k]); + + if (vCollRofSubId[k + 1] == 2 && vCollRofSubId[k] == 1) + histos.fill(HIST("ROFbyROF/nPV_000_0y0_00x_0"), vTracksITS567perColl[k + 1], vTracksITS567perColl[k]); + if (vCollRofSubId[k + 1] == 1 && vCollRofSubId[k] == 1) + histos.fill(HIST("ROFbyROF/nPV_000_0y0_0x0_0"), vTracksITS567perColl[k + 1], vTracksITS567perColl[k]); + if (vCollRofSubId[k + 1] == 0 && vCollRofSubId[k] == 1) + histos.fill(HIST("ROFbyROF/nPV_000_0y0_x00_0"), vTracksITS567perColl[k + 1], vTracksITS567perColl[k]); + + if (vCollRofSubId[k + 1] == 2 && vCollRofSubId[k] == 2) + histos.fill(HIST("ROFbyROF/nPV_000_00y_00x_0"), vTracksITS567perColl[k + 1], vTracksITS567perColl[k]); + if (vCollRofSubId[k + 1] == 1 && vCollRofSubId[k] == 2) + histos.fill(HIST("ROFbyROF/nPV_000_00y_0x0_0"), vTracksITS567perColl[k + 1], vTracksITS567perColl[k]); + if (vCollRofSubId[k + 1] == 0 && vCollRofSubId[k] == 2) + histos.fill(HIST("ROFbyROF/nPV_000_00y_x00_0"), vTracksITS567perColl[k + 1], vTracksITS567perColl[k]); + } + + if (vCollRofId[k - 1] < vCollRofId[k] - 2 /* prev coll is far */ && vCollRofId[k + 1] == vCollRofId[k] + 2 && vCollRofId[k + 2] > vCollRofId[k] + 2) // 00x01 + { + histos.fill(HIST("ROFbyROF/nPV_00x01"), vTracksITS567perColl[k + 1], vTracksITS567perColl[k]); + histos.fill(HIST("ROFbyROF/nPV_00x01_nearbyByFT0C"), vAmpFT0CperColl[k + 1], vTracksITS567perColl[k]); + histos.fill(HIST("ROFbyROF/nPV_00x01_thisFT0C"), vAmpFT0CperColl[k], vTracksITS567perColl[k]); + } + } + + // 2 colls + if (vCombCond[k] && vCombCond[k - 1] && vCombCond[k - 2]) { + if (vCollRofId[k - 2] == vCollRofId[k] - 2 && vCollRofId[k - 1] == vCollRofId[k] - 1 && vCollRofId[k + 1] > vCollRofId[k] + 2) // 11x00 + histos.fill(HIST("ROFbyROF/nPV_11x00"), vTracksITS567perColl[k - 1], vTracksITS567perColl[k]); + } + + if (vCombCond[k] && vCombCond[k - 1] && vCombCond[k + 1]) { + if (vCollRofId[k - 2] < vCollRofId[k] - 2 && vCollRofId[k - 1] == vCollRofId[k] - 1 && vCollRofId[k + 1] == vCollRofId[k] + 1 && vCollRofId[k + 2] > vCollRofId[k] + 2) // 01x10 + histos.fill(HIST("ROFbyROF/nPV_01x10"), vTracksITS567perColl[k - 1], vTracksITS567perColl[k]); + } + + if (vCombCond[k] && vCombCond[k + 1] && vCombCond[k + 2]) { + if (vCollRofId[k - 1] < vCollRofId[k] - 2 && vCollRofId[k + 1] == vCollRofId[k] + 1 && vCollRofId[k + 2] == vCollRofId[k] + 2) // 00x11 + histos.fill(HIST("ROFbyROF/nPV_00x11"), vTracksITS567perColl[k + 1], vTracksITS567perColl[k]); + } + + // many colls around + // histos.add("ROFbyROF/nPV_11x11", "", kTH2D, {{250, 0., 8000 * k}, {250, 0., 8000 * k}}); + } + + // save indices of collisions in time range for occupancy calculation + std::vector> vCollsInTimeWin; + std::vector> vCollsInSameITSROF; + std::vector> vTimeDeltaForColls; // delta time wrt a given collision + for (const auto& col : cols) { + int32_t colIndex = col.globalIndex(); + int64_t foundGlobalBC = vFoundGlobalBC[colIndex]; + + // int bcInTF = (foundGlobalBC - bcSOR) % nBCsPerTF; + // int bcInITSROF = (foundGlobalBC + 3564 - rofOffset) % rofLength; + int64_t tfId = (foundGlobalBC - bcSOR) / nBCsPerTF; + int64_t rofId = (foundGlobalBC + 3564 - rofOffset) / rofLength; + // int rofIdInTF = (bcInTF - rofOffset) / rofLength; + + // ### in-ROF occupancy + std::vector vAssocToSameROF; + // find all collisions in the same ROF before a given collision + int32_t minColIndex = colIndex - 1; + while (minColIndex >= 0) { + int64_t thisBC = vFoundGlobalBC[minColIndex]; + // check if this is still the same TF + int64_t thisTFid = (thisBC - bcSOR) / nBCsPerTF; + if (thisTFid != tfId) + break; + // int thisRofIdInTF = (thisBC - rofOffset) / rofLength; + int64_t thisRofId = (thisBC + 3564 - rofOffset) / rofLength; + + // check if we are within the same ROF + if (thisRofId != rofId) + break; + vAssocToSameROF.push_back(minColIndex); + minColIndex--; + } + // find all collisions in the same ROF after the current one + int32_t maxColIndex = colIndex + 1; + while (maxColIndex < cols.size()) { + int64_t thisBC = vFoundGlobalBC[maxColIndex]; + int64_t thisTFid = (thisBC - bcSOR) / nBCsPerTF; + if (thisTFid != tfId) + break; + // int thisRofIdInTF = (thisBC - rofOffset) / rofLength; + int64_t thisRofId = (thisBC + 3564 - rofOffset) / rofLength; + if (thisRofId != rofId) + break; + vAssocToSameROF.push_back(maxColIndex); + maxColIndex++; + } + vCollsInSameITSROF.push_back(vAssocToSameROF); + + // ### occupancy in time windows + std::vector vAssocToThisCol; + std::vector vCollsTimeDeltaWrtGivenColl; + // protection against the TF borders + if (!vIsFullInfoForOccupancy[colIndex]) { + vCollsInTimeWin.push_back(vAssocToThisCol); + vTimeDeltaForColls.push_back(vCollsTimeDeltaWrtGivenColl); + continue; + } + // find all collisions in time window before the current one + minColIndex = colIndex - 1; + while (minColIndex >= 0) { + int64_t thisBC = vFoundGlobalBC[minColIndex]; + // check if this is still the same TF + int64_t thisTFid = (thisBC - bcSOR) / nBCsPerTF; + if (thisTFid != tfId) + break; + float dt = (thisBC - foundGlobalBC) * bcNS; // ns + // check if we are within the chosen time range + if (dt < timeWinOccupancyCalcMinNS) + break; + vAssocToThisCol.push_back(minColIndex); + vCollsTimeDeltaWrtGivenColl.push_back(dt); + minColIndex--; + } + // find all collisions in time window after the current one + maxColIndex = colIndex + 1; + while (maxColIndex < cols.size()) { + int64_t thisBC = vFoundGlobalBC[maxColIndex]; + int64_t thisTFid = (thisBC - bcSOR) / nBCsPerTF; + if (thisTFid != tfId) + break; + float dt = (thisBC - foundGlobalBC) * bcNS; // ns + if (dt > timeWinOccupancyCalcMaxNS) + break; + vAssocToThisCol.push_back(maxColIndex); + vCollsTimeDeltaWrtGivenColl.push_back(dt); + maxColIndex++; + } + vCollsInTimeWin.push_back(vAssocToThisCol); + vTimeDeltaForColls.push_back(vCollsTimeDeltaWrtGivenColl); + } + + // perform the occupancy calculation per ITS ROF and also in the pre-defined time window + std::vector vNumTracksITS567inFullTimeWin(cols.size(), 0); // counter of tracks in full time window for occupancy studies (excluding given event) + std::vector vSumAmpFT0CinFullTimeWin(cols.size(), 0); // sum of FT0C of tracks in full time window for occupancy studies (excluding given event) + std::vector vNumTracksITS567inROF(cols.size(), 0); // counter of tracks in given ROF (excluding given event) + std::vector vSumAmpFT0CinROF(cols.size(), 0); // counter of tracks in given ROF (excluding given event) + std::vector vNumCollinROF(cols.size(), 0); // counter of tracks in given ROF (excluding given event) + std::vector vNumCollinROFinVz10(cols.size(), 0); // counter of tracks in given ROF (excluding given event) + std::vector vInROFcollIndex(cols.size(), 0); // counter of tracks in given ROF (excluding given event) + std::vector vROFidThisColl(cols.size(), 0); // counter of tracks in given ROF (excluding given event) + + std::vector vNoCollInTimeRangeStrict(cols.size(), 0); // no collisions in a specified time range + std::vector vNoCollInTimeRangeNarrow(cols.size(), 0); // no collisions in a specified time range (narrow) + std::vector vNoHighMultCollInTimeRange(cols.size(), 0); // no high-mult collisions in a specified time range + std::vector vNoCollInVzDependentTimeRange(cols.size(), 0); // no collisions in a vZ-dependent time range + + std::vector vNoCollInSameRofStrict(cols.size(), 0); // to veto events with other collisions in the same ITS ROF + std::vector vNoCollInSameRofStandard(cols.size(), 0); // to veto events with other collisions in the same ITS ROF, with per-collision multiplicity above threshold + std::vector vNoCollInSameRofWithCloseVz(cols.size(), 0); // to veto events with nearby collisions with close vZ + std::vector> vArrNoCollInSameRofWithCloseVz; //(cols.size(), 0); // to veto events with nearby collisions with close vZ + + for (const auto& col : cols) { + int32_t colIndex = col.globalIndex(); + float vZ = col.posZ(); + + // QA: + if (vAmpFT0CperColl[colIndex] > 5000) { + histos.fill(HIST("hThisEvITStr_vs_vZ"), vZ, vTracksITS567perColl[colIndex]); + histos.fill(HIST("hThisEvITSTPCtr_vs_vZ"), vZ, vTracksITSTPCperColl[colIndex]); + } + + // ### in-ROF occupancy + // int64_t rofId = (vFoundGlobalBC[colIndex] + 3564 - rofOffset) / rofLength; + // int bcInTF = (vFoundGlobalBC[colIndex] - bcSOR) % nBCsPerTF; + int bcInITSROF = (vFoundGlobalBC[colIndex] + 3564 - rofOffset) % rofLength; + int rofIdInTF = (vFoundGlobalBC[colIndex] + 3564 - rofOffset) / rofLength; + // auto bc = bcs.iteratorAt(vFoundBCindex[colIndex]); + // LOGP(info, "#### starting new coll: bc={} bcInTF={} bcInITSROF={} rofId={}; noROFborder={}; rofOffset={} rofLength={}", vFoundGlobalBC[colIndex], bcInTF, bcInITSROF, rofId, bc.selection_bit(kNoITSROFrameBorder), rofOffset, rofLength); + // LOGP(info, "#### starting new coll: bcInTF={} bcInITSROF={} rofIdInTF={}; noROFborder={}, vZ={} mult={}; rofOffset={} rofLength={}", bcInTF, bcInITSROF, rofIdInTF, bc.selection_bit(kNoITSROFrameBorder), vZ, vTracksITS567perColl[colIndex], rofOffset, rofLength); + + std::vector vAssocToSameROF = vCollsInSameITSROF[colIndex]; + int nITS567tracksForRofVetoStrict = 0; // to veto events with other collisions in the same ITS ROF + float nSumAmplFT0CforRofVetoStrict = 0; // to veto events with other collisions in the same ITS ROF + // int nITS567tracksForRofVetoStandard = 0; // to veto events with other collisions in the same ITS ROF, with per-collision multiplicity above threshold + int nCollsInRofWithFT0CAboveVetoStandard = 0; // to veto events with other collisions in the same ITS ROF, with per-collision multiplicity above threshold + int nITS567tracksForRofVetoOnCloseVz = 0; // to veto events with nearby collisions with close vZ + int nArrITS567tracksForRofVetoOnCloseVz[200] = {}; // to veto events with nearby collisions with close vZ + vNumCollinROF[colIndex] = 1; + vInROFcollIndex[colIndex] = 0; + vROFidThisColl[colIndex] = rofIdInTF; + + if (std::fabs(vZ) < 10) + vNumCollinROFinVz10[colIndex] = 1; + for (uint32_t iCol = 0; iCol < vAssocToSameROF.size(); iCol++) { + int thisColIndex = vAssocToSameROF[iCol]; + // int64_t thisRofId = (vFoundGlobalBC[thisColIndex] + 3564 - rofOffset) / rofLength; + // int thisBcInTF = (vFoundGlobalBC[thisColIndex] - bcSOR) % nBCsPerTF; + int thisBcInITSROF = (vFoundGlobalBC[thisColIndex] + 3564 - rofOffset) % rofLength; + // int thisRofIdInTF = (vFoundGlobalBC[thisColIndex] + 3564 - rofOffset) / rofLength; + // auto bcAssoc = bcs.iteratorAt(vFoundBCindex[thisColIndex]); + // LOGP(info, ">> assoc: bc={} bcInTF={} bcInITSROF={} rofId={} noROFborder={}", vFoundGlobalBC[thisColIndex], thisBcInTF, thisBcInITSROF, thisRofId, bcAssoc.selection_bit(kNoITSROFrameBorder)); + // LOGP(info, ">> assoc: bcInTF={} bcInITSROF={} rofIdInTF={} noROFborder={} vZ={} mult={}", thisBcInTF, thisBcInITSROF, thisRofIdInTF, bcAssoc.selection_bit(kNoITSROFrameBorder), vCollVz[thisColIndex], vTracksITS567perColl[thisColIndex]); + + // if (std::fabs(vTracksITS567perColl[thisColIndex]) > confNtracksCutVetoOnCollInROF) + nITS567tracksForRofVetoStrict += vTracksITS567perColl[thisColIndex]; + nSumAmplFT0CforRofVetoStrict += vAmpFT0CperColl[thisColIndex]; + vNumCollinROF[colIndex]++; + if (std::fabs(vCollVz[thisColIndex]) < 10) + vNumCollinROFinVz10[colIndex]++; + vInROFcollIndex[colIndex] = thisBcInITSROF > bcInITSROF ? 0 : 1; // if colIndex is for the first coll in ROF => inROFindex=0, otherwise =1 + + // if (vTracksITS567perColl[thisColIndex] > confNtracksCutVetoOnCollInROF) + // nITS567tracksForRofVetoStandard += vTracksITS567perColl[thisColIndex]; + + if (vAmpFT0CperColl[thisColIndex] > confFT0CamplCutVetoOnCollInROF) + nCollsInRofWithFT0CAboveVetoStandard++; + + if (std::fabs(vCollVz[thisColIndex] - vZ) < confEpsilonVzDiffVetoInROF) + nITS567tracksForRofVetoOnCloseVz += vTracksITS567perColl[thisColIndex]; + for (int i = 0; i < 200; i++) { + // if (std::fabs(vCollVz[thisColIndex] - vZ) < 0.05 * i && vTracksITS567perColl[thisColIndex] > 50) + // if (vTracksITS567perColl[colIndex]>100 && vTracksITS567perColl[colIndex]<1000 && + if (vAmpFT0CperColl[colIndex] > 4000 && vAmpFT0CperColl[colIndex] < 15000 && + (vCollVz[thisColIndex] - vZ) > 0.05 * i && std::fabs(vCollVz[thisColIndex] - vZ) < (0.1 + 0.05) * i && vTracksITS567perColl[thisColIndex] > 20) // 0.05 * (i + 1)) + // std::fabs(vCollVz[thisColIndex] - vZ) < 0.05 * i && vTracksITS567perColl[thisColIndex] > 30) // 0.05 * (i + 1)) + nArrITS567tracksForRofVetoOnCloseVz[i]++; + } + + if (std::fabs(vZ) < 10) { + histos.fill(HIST("hDeltaVz"), vCollVz[thisColIndex] - vZ); + if (vTracksITS567perColl[colIndex] >= 100 && vTracksITS567perColl[thisColIndex] < 100) + histos.fill(HIST("hDeltaVzGivenCollAbove100NearbyBelow100"), vCollVz[thisColIndex] - vZ); + if (vTracksITS567perColl[colIndex] <= 100 && vTracksITS567perColl[thisColIndex] > 100) + histos.fill(HIST("hDeltaVzGivenCollBelow100NearbyAbove100"), vCollVz[thisColIndex] - vZ); + if (vTracksITS567perColl[colIndex] > 20 && vTracksITS567perColl[thisColIndex] > 20) + histos.fill(HIST("hDeltaVzAfterCuts"), vCollVz[thisColIndex] - vZ); + if (col.sel8()) // bc.selection_bit(kIsTriggerTVX) && bc.selection_bit(kNoTimeFrameBorder) && bc.selection_bit(kNoITSROFrameBorder)) + histos.fill(HIST("hDeltaVzAfterTFandROFborderCuts"), vCollVz[thisColIndex] - vZ); + if (vTracksITS567perColl[colIndex] > 20 && vTracksITS567perColl[thisColIndex] > 20 && col.sel8()) // bc.selection_bit(kIsTriggerTVX) && bc.selection_bit(kNoTimeFrameBorder) && bc.selection_bit(kNoITSROFrameBorder)) + histos.fill(HIST("hDeltaVzAfterAllCuts"), vCollVz[thisColIndex] - vZ); + } + } + vNumTracksITS567inROF[colIndex] = nITS567tracksForRofVetoStrict; // occupancy in ROF (excluding a given collision) + vSumAmpFT0CinROF[colIndex] = nSumAmplFT0CforRofVetoStrict; // occupancy in ROF (excluding a given collision) + + // in-ROF occupancy flags + vNoCollInSameRofStrict[colIndex] = (nITS567tracksForRofVetoStrict == 0); + // vNoCollInSameRofStandard[colIndex] = (nITS567tracksForRofVetoStandard == 0); + vNoCollInSameRofStandard[colIndex] = (nCollsInRofWithFT0CAboveVetoStandard == 0); + vNoCollInSameRofWithCloseVz[colIndex] = (nITS567tracksForRofVetoOnCloseVz == 0); + + std::vector vVzCutThisColl; + + // ### occupancy in time windows + // protection against TF borders + if (!vIsFullInfoForOccupancy[colIndex]) { // occupancy in undefined (too close to TF borders) + vNumTracksITS567inFullTimeWin[colIndex] = -1; + vSumAmpFT0CinFullTimeWin[colIndex] = -1; + // vNumTracksITS567inROF[colIndex] = -1; + vArrNoCollInSameRofWithCloseVz.push_back(vVzCutThisColl); + continue; + } + std::vector vAssocToThisCol = vCollsInTimeWin[colIndex]; + std::vector vCollsTimeDeltaWrtGivenColl = vTimeDeltaForColls[colIndex]; + int nITS567tracksInFullTimeWindow = 0; + int sumAmpFT0CInFullTimeWindow = 0; + int nITS567tracksForVetoNarrow = 0; // to veto events with nearby collisions (narrower range) + int nITS567tracksForVetoStrict = 0; // to veto events with nearby collisions + int nITS567tracksForVetoStandard = 0; // to veto events with per-collision multiplicity above threshold + int nITS567tracksForVetoVzDependent = 0; // to veto events with nearby collisions, vZ-dependent time cut + for (uint32_t iCol = 0; iCol < vAssocToThisCol.size(); iCol++) { + int thisColIndex = vAssocToThisCol[iCol]; + float dt = vCollsTimeDeltaWrtGivenColl[iCol] / 1e3; // ns -> us + histos.fill(HIST("hDeltaTime"), dt); + if (vTracksITS567perColl[colIndex] > 50 && vTracksITS567perColl[thisColIndex] > 50) + histos.fill(HIST("hDeltaTimeAboveNtracksCut"), dt); + + if (std::fabs(vCollVz[colIndex]) < 10 && std::fabs(vCollVz[thisColIndex]) < 10) + histos.fill(HIST("hDeltaTime_vZ10cm"), dt); + + if (vIsSel8[colIndex] && vIsSel8[thisColIndex]) + histos.fill(HIST("hDeltaTime_sel8"), dt); + + if (std::fabs(vCollVz[colIndex]) < 10 && vIsSel8[colIndex] && std::fabs(vCollVz[thisColIndex]) < 10 && vIsSel8[thisColIndex]) { + histos.fill(HIST("hDeltaTime_sel8_vZ10cm"), dt); + if (vTracksITS567perColl[colIndex] > 50 && vTracksITS567perColl[thisColIndex] > 50) + histos.fill(HIST("hDeltaTimeAboveNtracksCut_sel8_vZ10cm"), dt); + } + + float wOccup = 1.; + if (confUseWeightsForOccupancyVariable) { + // weighted occupancy + wOccup = 0; + if (dt >= -40 && dt < -5) // collisions in the past + wOccup = 1. / 1225 * (dt + 40) * (dt + 40); + else if (dt >= -5 && dt < 15) // collisions near a given one + wOccup = 1; + // else if (dt >= 15 && dt < 100) // collisions from the future + // wOccup = -1. / 85 * dt + 20. / 17; + else if (dt >= 15 && dt < 40) // collisions from the future + wOccup = -0.4 / 25 * dt + 1.24; + else if (dt >= 40 && dt < 100) // collisions from the distant future + wOccup = -0.4 / 60 * dt + 0.6 + 0.8 / 3; + if (wOccup > 0) + histos.fill(HIST("hOccupancyWeights"), dt, wOccup); + } + nITS567tracksInFullTimeWindow += wOccup * vTracksITS567perColl[thisColIndex]; + sumAmpFT0CInFullTimeWindow += wOccup * vAmpFT0CperColl[thisColIndex]; + + // counting tracks from other collisions in fixed time windows + if (std::fabs(dt) < confTimeRangeVetoOnCollNarrow) + nITS567tracksForVetoNarrow += vTracksITS567perColl[thisColIndex]; + if (std::fabs(dt) < confTimeRangeVetoOnCollStandard) + nITS567tracksForVetoStrict += vTracksITS567perColl[thisColIndex]; + + // if (std::fabs(dt) < confTimeRangeVetoOnCollStandard + 0.5) { // add 0.5 us safety margin + // standard cut on other collisions vs delta-times + const float driftV = 2.5; // drift velocity in cm/us, TPC drift_length / drift_time = 250 cm / 100 us + if (std::fabs(dt) < 2.0) { // us, complete veto on other collisions + nITS567tracksForVetoStandard += vTracksITS567perColl[thisColIndex]; + } else if (dt > -4.0 && dt <= -2.0) { // us, strict veto to suppress fake ITS-TPC matches more + if (vTracksITS567perColl[thisColIndex] > confNtracksCutVetoOnCollInTimeRange / 5) + nITS567tracksForVetoStandard += vTracksITS567perColl[thisColIndex]; + } else if (std::fabs(dt) < 8 + std::fabs(vZ) / driftV) { // loose veto, 8 us corresponds to maximum possible |vZ|, which is ~20 cm + // counting number of other collisions with mult above threshold + if (vTracksITS567perColl[thisColIndex] > confNtracksCutVetoOnCollInTimeRange) + nITS567tracksForVetoStandard += vTracksITS567perColl[thisColIndex]; + } + // vZ-dependent time cut to avoid collinear tracks from other collisions (experimental) + if (std::fabs(dt) < 8 + std::fabs(vZ) / driftV) { + if (dt < 0) { + // check distance between given vZ and (moving in two directions) vZ of drifting tracks from past collisions + if ((std::fabs(vCollVz[thisColIndex] - std::fabs(dt) * driftV - vZ) < confEpsilonDistanceForVzDependentVetoTPC) || + (std::fabs(vCollVz[thisColIndex] + std::fabs(dt) * driftV - vZ) < confEpsilonDistanceForVzDependentVetoTPC)) + nITS567tracksForVetoVzDependent += vTracksITS567perColl[thisColIndex]; + + // FOR QA: + if (std::fabs(vCollVz[thisColIndex] - std::fabs(dt) * driftV - vZ) < confEpsilonDistanceForVzDependentVetoTPC) + histos.fill(HIST("hDeltaVzVsDeltaTime1"), vCollVz[thisColIndex] - std::fabs(dt) * driftV - vZ, dt); + if (std::fabs(vCollVz[thisColIndex] + std::fabs(dt) * driftV - vZ) < confEpsilonDistanceForVzDependentVetoTPC) + histos.fill(HIST("hDeltaVzVsDeltaTime2"), vCollVz[thisColIndex] + std::fabs(dt) * driftV - vZ, dt); + + } else { // dt>0 + // check distance between drifted vZ of given collision (in two directions) and vZ of future collisions + if ((std::fabs(vZ - dt * driftV - vCollVz[thisColIndex]) < confEpsilonDistanceForVzDependentVetoTPC) || + (std::fabs(vZ + dt * driftV - vCollVz[thisColIndex]) < confEpsilonDistanceForVzDependentVetoTPC)) + nITS567tracksForVetoVzDependent += vTracksITS567perColl[thisColIndex]; + + // FOR QA: + if (std::fabs(vZ - dt * driftV - vCollVz[thisColIndex]) < confEpsilonDistanceForVzDependentVetoTPC) + histos.fill(HIST("hDeltaVzVsDeltaTime3"), vZ - dt * driftV - vCollVz[thisColIndex], dt); + if (std::fabs(vZ + dt * driftV - vCollVz[thisColIndex]) < confEpsilonDistanceForVzDependentVetoTPC) + histos.fill(HIST("hDeltaVzVsDeltaTime4"), vZ + dt * driftV - vCollVz[thisColIndex], dt); + } + } + } + vNumTracksITS567inFullTimeWin[colIndex] = nITS567tracksInFullTimeWindow; // occupancy by ITS tracks (without a current collision) + vSumAmpFT0CinFullTimeWin[colIndex] = sumAmpFT0CInFullTimeWindow; // occupancy by FT0C (without a current collision) + // occupancy flags based on nearby collisions + vNoCollInTimeRangeNarrow[colIndex] = (nITS567tracksForVetoNarrow == 0); + vNoCollInTimeRangeStrict[colIndex] = (nITS567tracksForVetoStrict == 0); + vNoHighMultCollInTimeRange[colIndex] = (nITS567tracksForVetoStandard == 0); + vNoCollInVzDependentTimeRange[colIndex] = (nITS567tracksForVetoVzDependent == 0); + + for (int i = 0; i < 200; i++) + vVzCutThisColl.push_back(nArrITS567tracksForRofVetoOnCloseVz[i] == 0); + vArrNoCollInSameRofWithCloseVz.push_back(vVzCutThisColl); + } + + for (const auto& col : cols) { + int32_t colIndex = col.globalIndex(); + bool sel8 = col.sel8(); // bc.selection_bit(kIsTriggerTVX) && bc.selection_bit(kNoTimeFrameBorder) && bc.selection_bit(kNoITSROFrameBorder); + + float vZ = vCollVz[colIndex]; + int occTracks = col.trackOccupancyInTimeRange(); + float occFT0C = col.ft0cOccupancyInTimeRange(); + + if (sel8) { + // histos.fill(HIST("hColCounterAcc"),Form("%d", bc.runNumber()), 1); + if (vInROFcollIndex[colIndex] == 0) + histos.fill(HIST("hNcollPerROF"), vNumCollinROF[colIndex]); + + histos.fill(HIST("hVz"), vZ); + + int nPV = vTracksITS567perColl[colIndex]; + float ft0C = vAmpFT0CperColl[colIndex]; + + // ROF-by-ROF + if (std::fabs(vZ) < 8) { + histos.fill(HIST("ROFbyROF/nPV_vs_ROFid"), nPV, vCollRofIdPerOrbit[colIndex]); + histos.fill(HIST("ROFbyROF/nPV_vs_subROFid"), nPV, vCollRofSubIdPerOrbit[colIndex]); + + histos.fill(HIST("ROFbyROF/FT0C_vs_ROFid"), ft0C, vCollRofIdPerOrbit[colIndex]); + histos.fill(HIST("ROFbyROF/FT0C_vs_subROFid"), ft0C, vCollRofSubIdPerOrbit[colIndex]); + } + // vs occupancy + if (occTracks >= 0 && std::fabs(vZ) < 8) { + histos.fill(HIST("nPV_vs_occupancyByTracks/sel8"), nPV, occTracks); + if (col.selection_bit(kNoCollInTimeRangeNarrow)) + histos.fill(HIST("nPV_vs_occupancyByTracks/NoCollInTimeRangeNarrow"), nPV, occTracks); + if (col.selection_bit(kNoCollInTimeRangeStrict)) + histos.fill(HIST("nPV_vs_occupancyByTracks/NoCollInTimeRangeStrict"), nPV, occTracks); + if (col.selection_bit(kNoCollInTimeRangeStandard)) + histos.fill(HIST("nPV_vs_occupancyByTracks/NoCollInTimeRangeStandard"), nPV, occTracks); + if (col.selection_bit(kNoCollInRofStrict)) + histos.fill(HIST("nPV_vs_occupancyByTracks/NoCollInRofStrict"), nPV, occTracks); + if (col.selection_bit(kNoCollInRofStandard)) + histos.fill(HIST("nPV_vs_occupancyByTracks/NoCollInRofStandard"), nPV, occTracks); + if (col.selection_bit(kNoCollInTimeRangeStandard) && col.selection_bit(kNoCollInRofStandard)) + histos.fill(HIST("nPV_vs_occupancyByTracks/NoCollInTimeAndRofStandard"), nPV, occTracks); + if (col.selection_bit(kNoCollInTimeRangeStrict) && col.selection_bit(kNoCollInRofStrict)) + histos.fill(HIST("nPV_vs_occupancyByTracks/NoCollInTimeAndRofStrict"), nPV, occTracks); + if (col.selection_bit(kNoCollInTimeRangeStrict) && col.selection_bit(kNoCollInRofStrict) && std::fabs(vZ) < 5) + histos.fill(HIST("nPV_vs_occupancyByTracks/NoCollInTimeAndRofStrict_vZ_5cm"), nPV, occTracks); + if (col.selection_bit(kNoHighMultCollInPrevRof)) + histos.fill(HIST("nPV_vs_occupancyByTracks/kNoHighMultCollInPrevRof"), nPV, occTracks); + if (col.selection_bit(kNoHighMultCollInPrevRof) && col.selection_bit(kNoCollInRofStrict)) + histos.fill(HIST("nPV_vs_occupancyByTracks/kNoHighMultCollInPrevRofAndRofStrict"), nPV, occTracks); + } + if (occFT0C >= 0 && std::fabs(vZ) < 8) { + histos.fill(HIST("nPV_vs_occupancyByFT0C/sel8"), nPV, occFT0C); + if (col.selection_bit(kNoCollInTimeRangeNarrow)) + histos.fill(HIST("nPV_vs_occupancyByFT0C/NoCollInTimeRangeNarrow"), nPV, occFT0C); + if (col.selection_bit(kNoCollInTimeRangeStrict)) + histos.fill(HIST("nPV_vs_occupancyByFT0C/NoCollInTimeRangeStrict"), nPV, occFT0C); + if (col.selection_bit(kNoCollInTimeRangeStandard)) + histos.fill(HIST("nPV_vs_occupancyByFT0C/NoCollInTimeRangeStandard"), nPV, occFT0C); + if (col.selection_bit(kNoCollInRofStrict)) + histos.fill(HIST("nPV_vs_occupancyByFT0C/NoCollInRofStrict"), nPV, occFT0C); + if (col.selection_bit(kNoCollInRofStandard)) + histos.fill(HIST("nPV_vs_occupancyByFT0C/NoCollInRofStandard"), nPV, occFT0C); + if (col.selection_bit(kNoCollInTimeRangeStandard) && col.selection_bit(kNoCollInRofStandard)) + histos.fill(HIST("nPV_vs_occupancyByFT0C/NoCollInTimeAndRofStandard"), nPV, occFT0C); + if (col.selection_bit(kNoCollInTimeRangeStrict) && col.selection_bit(kNoCollInRofStrict)) + histos.fill(HIST("nPV_vs_occupancyByFT0C/NoCollInTimeAndRofStrict"), nPV, occFT0C); + if (col.selection_bit(kNoCollInTimeRangeStrict) && col.selection_bit(kNoCollInRofStrict) && std::fabs(vZ) < 5) + histos.fill(HIST("nPV_vs_occupancyByFT0C/NoCollInTimeAndRofStrict_vZ_5cm"), nPV, occFT0C); + if (col.selection_bit(kNoHighMultCollInPrevRof)) + histos.fill(HIST("nPV_vs_occupancyByFT0C/kNoHighMultCollInPrevRof"), nPV, occFT0C); + if (col.selection_bit(kNoHighMultCollInPrevRof) && col.selection_bit(kNoCollInRofStrict)) + histos.fill(HIST("nPV_vs_occupancyByFT0C/kNoHighMultCollInPrevRofAndRofStrict"), nPV, occFT0C); + } + } + + if (occTracks >= 0) + histos.fill(HIST("hOccupancyByTracks_CROSSCHECK"), occTracks); + if (occFT0C >= 0) + histos.fill(HIST("hOccupancyByFT0C_CROSSCHECK"), occFT0C); + + if (vNumTracksITS567inFullTimeWin[colIndex] >= 0) { + histos.fill(HIST("hOccupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex]); + histos.fill(HIST("hOccupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex]); + + histos.fill(HIST("hOccupancyByTrInROF"), vNumTracksITS567inROF[colIndex]); + histos.fill(HIST("hOccupancyByFT0C_vs_ByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vSumAmpFT0CinFullTimeWin[colIndex]); + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/all"), vAmpFT0CperColl[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("hThisEvITSTPCTr_vs_ThisEvITStr/all"), vTracksITS567perColl[colIndex], vTracksITSTPCperColl[colIndex]); + + if (sel8 && std::fabs(col.posZ()) < 8) { + histos.fill(HIST("hOccupancyByFT0C_vs_ByTracks_vZ_TF_ROF_border_cuts"), vNumTracksITS567inFullTimeWin[colIndex], vSumAmpFT0CinFullTimeWin[colIndex]); + + // if (vAmpFT0CperColl[colIndex] > 5000 && vAmpFT0CperColl[colIndex] < 10000) { + // if (vAmpFT0CperColl[colIndex] > 500) { + if (vAmpFT0CperColl[colIndex] > 0) { // 50) { + + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTPCTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTPCTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF"), vNumTracksITS567inROF[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTPCTr_vs_occupancyInROF"), vNumTracksITS567inROF[colIndex], vTracksITSTPCperColl[colIndex]); + + if (vNumTracksITS567inROF[colIndex] > 0) { + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF_HasNeighbours"), vNumTracksITS567inROF[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyFT0CInROF_HasNeighbours"), vSumAmpFT0CinROF[colIndex], vTracksITS567perColl[colIndex]); + + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvFT0C_vs_occupancyFT0CInROF_HasNeighbours"), vSumAmpFT0CinROF[colIndex], vAmpFT0CperColl[colIndex]); + } + + // two collisions in one ROF (both with |vZ|<10 cm) + if (vNumCollinROF[colIndex] == 2 && vNumCollinROFinVz10[colIndex] == 2 && vInROFcollIndex[colIndex] == 1) { + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF_2coll"), vNumTracksITS567inROF[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvFT0C_vs_occupancyFT0CInROF_2coll"), vSumAmpFT0CinROF[colIndex], vAmpFT0CperColl[colIndex]); + + if (vNumTracksITS567inROF[colIndex] > vTracksITS567perColl[colIndex]) { + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF_2coll_XaxisWins"), vNumTracksITS567inROF[colIndex], vTracksITS567perColl[colIndex]); + if (vNumTracksITS567inROF[colIndex] > 0) + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF_2coll_XaxisWins_RatioV2toV1"), vNumTracksITS567inROF[colIndex], 1.0 * vTracksITS567perColl[colIndex] / vNumTracksITS567inROF[colIndex]); + + } else { + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF_2coll_XaxisWins"), vTracksITS567perColl[colIndex], vNumTracksITS567inROF[colIndex]); + + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_allOccup_2coll_inROF"), vTracksITS567perColl[colIndex]); + if (occTracks < 500) + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_lowOccup_2coll_inROF"), vTracksITS567perColl[colIndex]); + else if (occTracks > 1000) + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_highOccup_2coll_inROF"), vTracksITS567perColl[colIndex]); + + if (vTracksITS567perColl[colIndex] > 0) + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF_2coll_XaxisWins_RatioV2toV1"), vTracksITS567perColl[colIndex], 1.0 * vNumTracksITS567inROF[colIndex] / vTracksITS567perColl[colIndex]); + } + } + + // 3 or 4 collisions in one ROF + if (vNumCollinROF[colIndex] == 2 && vInROFcollIndex[colIndex] == 1) + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF_2coll_noVzCutOnOtherVertices"), vNumTracksITS567inROF[colIndex], vTracksITS567perColl[colIndex]); + if (vNumCollinROF[colIndex] == 3 && vInROFcollIndex[colIndex] == 1) + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF_3coll_noVzCutOnOtherVertices"), vNumTracksITS567inROF[colIndex], vTracksITS567perColl[colIndex]); + if (vNumCollinROF[colIndex] == 4 && vInROFcollIndex[colIndex] == 1) + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInROF_4coll_noVzCutOnOtherVertices"), vNumTracksITS567inROF[colIndex], vTracksITS567perColl[colIndex]); + + // now 1D histograms vs nCollInROF + if (vNumCollinROF[colIndex] == 1) + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_1coll_in_ROF"), vTracksITS567perColl[colIndex]); + if (vNumCollinROF[colIndex] == 2) + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_2coll_in_ROF"), vTracksITS567perColl[colIndex]); + if (vNumCollinROF[colIndex] == 3) + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_3coll_in_ROF"), vTracksITS567perColl[colIndex]); + if (vNumCollinROF[colIndex] == 4) + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_4coll_in_ROF"), vTracksITS567perColl[colIndex]); + if (vNumCollinROF[colIndex] >= 5) + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_5collOrMore_in_ROF"), vTracksITS567perColl[colIndex]); + + // compare with previous ROF + if (colIndex - 1 >= 0) { + if (vNumCollinROF[colIndex] == 1 && vNumCollinROFinVz10[colIndex] == 1 && vInROFcollIndex[colIndex] == 0 && vNumCollinROF[colIndex - 1] == 1 && vNumCollinROFinVz10[colIndex - 1] == 1 && vInROFcollIndex[colIndex - 1] == 0) { + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInAnotherEarlierROF_1collPerROF"), vTracksITS567perColl[colIndex - 1], vTracksITS567perColl[colIndex]); + if (vROFidThisColl[colIndex] == vROFidThisColl[colIndex - 1] + 1) // one ROF right after the previous + { + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInPreviousROF_1collPerROF"), vTracksITS567perColl[colIndex - 1], vTracksITS567perColl[colIndex]); + if (vTracksITS567perColl[colIndex - 1] > vTracksITS567perColl[colIndex]) { + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInPreviousROF_1collPerROF_XaxisWins"), vTracksITS567perColl[colIndex - 1], vTracksITS567perColl[colIndex]); + if (vTracksITS567perColl[colIndex - 1] > 0) + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInPreviousROF_1collPerROF_XaxisWins_RatioV2toV1"), vTracksITS567perColl[colIndex - 1], 1.0 * vTracksITS567perColl[colIndex] / vTracksITS567perColl[colIndex - 1]); + } else { + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInPreviousROF_1collPerROF_XaxisWins"), vTracksITS567perColl[colIndex], vTracksITS567perColl[colIndex - 1]); + + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_allOccup_1collPerROF"), vTracksITS567perColl[colIndex]); + if (occTracks < 500) + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_lowOccup_1collPerROF"), vTracksITS567perColl[colIndex]); + else if (occTracks > 1000) + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_highOccup_1collPerROF"), vTracksITS567perColl[colIndex]); + + if (vTracksITS567perColl[colIndex] > 0) + histos.fill(HIST("vZ_TF_ROF_border_cuts/hThisEvITSTr_vs_occupancyInPreviousROF_1collPerROF_XaxisWins_RatioV2toV1"), vTracksITS567perColl[colIndex], 1.0 * vTracksITS567perColl[colIndex - 1] / vTracksITS567perColl[colIndex]); + } + } + } + } + } + + if (vNoCollInTimeRangeNarrow[colIndex]) + histos.fill(HIST("hOccupancyByFT0C_vs_ByTracks_afterNarrowDeltaTimeCut"), vNumTracksITS567inFullTimeWin[colIndex], vSumAmpFT0CinFullTimeWin[colIndex]); + if (vNoCollInTimeRangeStrict[colIndex]) + histos.fill(HIST("hOccupancyByFT0C_vs_ByTracks_afterStrictDeltaTimeCut"), vNumTracksITS567inFullTimeWin[colIndex], vSumAmpFT0CinFullTimeWin[colIndex]); + if (vNoHighMultCollInTimeRange[colIndex]) + histos.fill(HIST("hOccupancyByFT0C_vs_ByTracks_afterStandardDeltaTimeCut"), vNumTracksITS567inFullTimeWin[colIndex], vSumAmpFT0CinFullTimeWin[colIndex]); + if (vNoCollInVzDependentTimeRange[colIndex]) + histos.fill(HIST("hOccupancyByFT0C_vs_ByTracks_afterVzDependentDeltaTimeCut"), vNumTracksITS567inFullTimeWin[colIndex], vSumAmpFT0CinFullTimeWin[colIndex]); + + // same-event 2D correlations: + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/vZ_TF_ROF_border_cuts"), vAmpFT0CperColl[colIndex], vTracksITS567perColl[colIndex]); + + if (vNoCollInTimeRangeNarrow[colIndex]) + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/afterNarrowDeltaTimeCut"), vAmpFT0CperColl[colIndex], vTracksITS567perColl[colIndex]); + if (vNoCollInTimeRangeStrict[colIndex]) + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/afterStrictDeltaTimeCut"), vAmpFT0CperColl[colIndex], vTracksITS567perColl[colIndex]); + if (vNoHighMultCollInTimeRange[colIndex]) + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/afterStandardDeltaTimeCut"), vAmpFT0CperColl[colIndex], vTracksITS567perColl[colIndex]); + if (vNoCollInVzDependentTimeRange[colIndex]) + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/afterVzDependentDeltaTimeCut"), vAmpFT0CperColl[colIndex], vTracksITS567perColl[colIndex]); + + if (vNoCollInSameRofStrict[colIndex]) + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/kNoCollInRofStrict"), vAmpFT0CperColl[colIndex], vTracksITS567perColl[colIndex]); + if (vNoCollInSameRofStandard[colIndex]) + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/kNoCollInRofStandard"), vAmpFT0CperColl[colIndex], vTracksITS567perColl[colIndex]); + if (vNoCollInSameRofWithCloseVz[colIndex]) + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/kNoCollInRofWithCloseVz"), vAmpFT0CperColl[colIndex], vTracksITS567perColl[colIndex]); + + // CROSS CHECK WITH SEL BITS: + if (col.selection_bit(kNoCollInTimeRangeNarrow)) + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/CROSSCHECK_afterNarrowDeltaTimeCut"), vAmpFT0CperColl[colIndex], vTracksITS567perColl[colIndex]); + if (col.selection_bit(kNoCollInTimeRangeStrict)) + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/CROSSCHECK_afterStrictDeltaTimeCut"), vAmpFT0CperColl[colIndex], vTracksITS567perColl[colIndex]); + if (col.selection_bit(kNoCollInTimeRangeStandard)) + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/CROSSCHECK_afterStandardDeltaTimeCut"), vAmpFT0CperColl[colIndex], vTracksITS567perColl[colIndex]); + + if (col.selection_bit(kNoCollInRofStrict)) + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/CROSSCHECK_kNoCollInRofStrict"), vAmpFT0CperColl[colIndex], vTracksITS567perColl[colIndex]); + if (col.selection_bit(kNoCollInRofStandard)) + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/CROSSCHECK_kNoCollInRofStandard"), vAmpFT0CperColl[colIndex], vTracksITS567perColl[colIndex]); + + if (vNumTracksITS567inFullTimeWin[colIndex] < 2000) { + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/occupBelow2000"), vAmpFT0CperColl[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/hThisEvITSTPCTr_vs_ThisEvFT0C_occupBelow2000"), vAmpFT0CperColl[colIndex], vTracksITSTPCperColl[colIndex]); + } + + if (vNoCollInTimeRangeNarrow[colIndex] && vNoHighMultCollInTimeRange[colIndex] && vNoCollInSameRofStandard[colIndex] && vNoCollInSameRofWithCloseVz[colIndex]) { + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/NarrowDeltaCut_StdTimeAndRofCuts"), vAmpFT0CperColl[colIndex], vTracksITS567perColl[colIndex]); + + if (vNumTracksITS567inFullTimeWin[colIndex] < 2000) { + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/NarrowDeltaCut_StdTimeAndRofCuts_occupBelow2000"), vAmpFT0CperColl[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("hThisEvITSTr_vs_ThisEvFT0C/hThisEvITSTPCTr_vs_ThisEvFT0C_NarrowDeltaCut_StdTimeAndRofCuts_occupBelow2000"), vAmpFT0CperColl[colIndex], vTracksITSTPCperColl[colIndex]); + } + } + + // now ITSTPC vs ITS tr (this event) + histos.fill(HIST("hThisEvITSTPCTr_vs_ThisEvITStr/vZ_TF_ROF_border_cuts"), vTracksITS567perColl[colIndex], vTracksITSTPCperColl[colIndex]); + + if (vNoCollInTimeRangeNarrow[colIndex]) + histos.fill(HIST("hThisEvITSTPCTr_vs_ThisEvITStr/afterNarrowDeltaTimeCut"), vTracksITS567perColl[colIndex], vTracksITSTPCperColl[colIndex]); + if (vNoCollInTimeRangeStrict[colIndex]) + histos.fill(HIST("hThisEvITSTPCTr_vs_ThisEvITStr/afterStrictDeltaTimeCut"), vTracksITS567perColl[colIndex], vTracksITSTPCperColl[colIndex]); + if (vNoHighMultCollInTimeRange[colIndex]) + histos.fill(HIST("hThisEvITSTPCTr_vs_ThisEvITStr/afterStandardDeltaTimeCut"), vTracksITS567perColl[colIndex], vTracksITSTPCperColl[colIndex]); + if (vNoCollInVzDependentTimeRange[colIndex]) + histos.fill(HIST("hThisEvITSTPCTr_vs_ThisEvITStr/afterVzDependentDeltaTimeCut"), vTracksITS567perColl[colIndex], vTracksITSTPCperColl[colIndex]); + + if (vNoCollInSameRofStrict[colIndex]) + histos.fill(HIST("hThisEvITSTPCTr_vs_ThisEvITStr/kNoCollInRofStrict"), vTracksITS567perColl[colIndex], vTracksITSTPCperColl[colIndex]); + if (vNoCollInSameRofStandard[colIndex]) + histos.fill(HIST("hThisEvITSTPCTr_vs_ThisEvITStr/kNoCollInRofStandard"), vTracksITS567perColl[colIndex], vTracksITSTPCperColl[colIndex]); + if (vNoCollInSameRofWithCloseVz[colIndex]) + histos.fill(HIST("hThisEvITSTPCTr_vs_ThisEvITStr/kNoCollInRofWithCloseVz"), vTracksITS567perColl[colIndex], vTracksITSTPCperColl[colIndex]); + + if (vNumTracksITS567inFullTimeWin[colIndex] < 2000) + histos.fill(HIST("hThisEvITSTPCTr_vs_ThisEvITStr/occupBelow2000"), vTracksITS567perColl[colIndex], vTracksITSTPCperColl[colIndex]); + + if (vNoCollInTimeRangeNarrow[colIndex] && vNoHighMultCollInTimeRange[colIndex] && vNoCollInSameRofStandard[colIndex] && vNoCollInSameRofWithCloseVz[colIndex]) { + histos.fill(HIST("hThisEvITSTPCTr_vs_ThisEvITStr/NarrowDeltaCut_StdTimeAndRofCuts"), vTracksITS567perColl[colIndex], vTracksITSTPCperColl[colIndex]); + if (vNumTracksITS567inFullTimeWin[colIndex] < 2000) + histos.fill(HIST("hThisEvITSTPCTr_vs_ThisEvITStr/occupBelow2000_NarrowDeltaCut_StdTimeAndRofCuts"), vTracksITS567perColl[colIndex], vTracksITSTPCperColl[colIndex]); + } + + if (vNoCollInTimeRangeStrict[colIndex] && vNoCollInSameRofStrict[colIndex] && vNoCollInSameRofWithCloseVz[colIndex]) { + if (vNumTracksITS567inFullTimeWin[colIndex] < 2000) + histos.fill(HIST("hThisEvITSTPCTr_vs_ThisEvITStr/occupBelow2000_StrictDeltaTimeCutAndRofCuts"), vTracksITS567perColl[colIndex], vTracksITSTPCperColl[colIndex]); + } + + // vZ bins to tune vZthresh cut + if (vNoCollInTimeRangeNarrow[colIndex]) { + + for (int i = 0; i < 200; i++) { + if (std::fabs(col.posZ()) < 8 && !vArrNoCollInSameRofWithCloseVz[colIndex][i]) { + histos.fill(HIST("hThisEvITStr_vs_vZcut"), 0.025 + 0.05 * i, vTracksITS567perColl[colIndex]); + histos.fill(HIST("hThisEvITSTPCtr_vs_vZcut"), 0.025 + 0.05 * i, vTracksITSTPCperColl[colIndex]); + } + } + } + + // ### this event vs Occupancy 2D histos + // if (vAmpFT0CperColl[colIndex] > 5000 && vAmpFT0CperColl[colIndex] < 10000) { + // if (vAmpFT0CperColl[colIndex] > 500) { + if (vAmpFT0CperColl[colIndex] > 0) { // 100) { + + if (vNoCollInTimeRangeNarrow[colIndex]) { + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInROF"), vNumTracksITS567inROF[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyInROF"), vNumTracksITS567inROF[colIndex], vTracksITSTPCperColl[colIndex]); + + if (vNumTracksITS567inROF[colIndex] > 0) { + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInROF_HasNeighbours"), vNumTracksITS567inROF[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyFT0CInROF_HasNeighbours"), vSumAmpFT0CinROF[colIndex], vTracksITS567perColl[colIndex]); + + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvFT0C_vs_occupancyFT0CInROF_HasNeighbours"), vSumAmpFT0CinROF[colIndex], vAmpFT0CperColl[colIndex]); + } + + if (vNumCollinROF[colIndex] == 2 && vNumCollinROFinVz10[colIndex] == 2 && vInROFcollIndex[colIndex] == 1) { + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInROF_2coll"), vNumTracksITS567inROF[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvFT0C_vs_occupancyFT0CInROF_2coll"), vSumAmpFT0CinROF[colIndex], vAmpFT0CperColl[colIndex]); + + if (vNumTracksITS567inROF[colIndex] > vTracksITS567perColl[colIndex]) { + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInROF_2coll_XaxisWins"), vNumTracksITS567inROF[colIndex], vTracksITS567perColl[colIndex]); + if (vNumTracksITS567inROF[colIndex] > 0) + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInROF_2coll_XaxisWins_RatioV2toV1"), vNumTracksITS567inROF[colIndex], 1.0 * vTracksITS567perColl[colIndex] / vNumTracksITS567inROF[colIndex]); + } else { + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInROF_2coll_XaxisWins"), vTracksITS567perColl[colIndex], vNumTracksITS567inROF[colIndex]); + if (vTracksITS567perColl[colIndex] > 0) + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInROF_2coll_XaxisWins_RatioV2toV1"), vTracksITS567perColl[colIndex], 1.0 * vNumTracksITS567inROF[colIndex] / vTracksITS567perColl[colIndex]); + } + + // the sum of v1 and v2: + if (vSumAmpFT0CinROF[colIndex] > 4000 && vAmpFT0CperColl[colIndex] > 4000) + histos.fill(HIST("afterNarrowDeltaTimeCut/hSum_2coll_withFT0above4000_inROF"), vTracksITS567perColl[colIndex] + vNumTracksITS567inROF[colIndex]); + } + // compare with previous ROF + if (colIndex - 1 >= 0) { + if (vNumCollinROF[colIndex] == 1 && vNumCollinROFinVz10[colIndex] == 1 && vInROFcollIndex[colIndex] == 0 && vNumCollinROF[colIndex - 1] == 1 && vNumCollinROFinVz10[colIndex - 1] == 1 && vInROFcollIndex[colIndex - 1] == 0) { + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInAnotherEarlierROF_1collPerROF"), vTracksITS567perColl[colIndex - 1], vTracksITS567perColl[colIndex]); + if (vROFidThisColl[colIndex] == vROFidThisColl[colIndex - 1] + 1) // one ROF right after the previous + { + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInPreviousROF_1collPerROF"), vTracksITS567perColl[colIndex - 1], vTracksITS567perColl[colIndex]); + + if (vTracksITS567perColl[colIndex - 1] > vTracksITS567perColl[colIndex]) { + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInPreviousROF_1collPerROF_XaxisWins"), vTracksITS567perColl[colIndex - 1], vTracksITS567perColl[colIndex]); + if (vTracksITS567perColl[colIndex - 1] > 0) + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInPreviousROF_1collPerROF_XaxisWins_RatioV2toV1"), vTracksITS567perColl[colIndex - 1], 1.0 * vTracksITS567perColl[colIndex] / vTracksITS567perColl[colIndex - 1]); + } else { + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInPreviousROF_1collPerROF_XaxisWins"), vTracksITS567perColl[colIndex], vTracksITS567perColl[colIndex - 1]); + if (vTracksITS567perColl[colIndex] > 0) + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInPreviousROF_1collPerROF_XaxisWins_RatioV2toV1"), vTracksITS567perColl[colIndex], 1.0 * vTracksITS567perColl[colIndex - 1] / vTracksITS567perColl[colIndex]); + } + // the sum of v1 and v2: + if (vAmpFT0CperColl[colIndex] > 4000 && vAmpFT0CperColl[colIndex - 1] > 4000) + histos.fill(HIST("afterNarrowDeltaTimeCut/hSum_2coll_withFT0above4000_thisROFprevROF"), vTracksITS567perColl[colIndex] + vTracksITS567perColl[colIndex - 1]); + } else if (vROFidThisColl[colIndex] == vROFidThisColl[colIndex - 1] + 2) { + // ROF vs ROF-2 + histos.fill(HIST("afterNarrowDeltaTimeCut/hThisEvITSTr_vs_occupancyInPrevPrevROF_1collPerROF"), vTracksITS567perColl[colIndex - 1], vTracksITS567perColl[colIndex]); + if (vAmpFT0CperColl[colIndex] > 4000 && vAmpFT0CperColl[colIndex - 1] > 4000) + histos.fill(HIST("afterNarrowDeltaTimeCut/hSum_2coll_withFT0above4000_thisROFprevPrevROF"), vTracksITS567perColl[colIndex] + vTracksITS567perColl[colIndex - 1]); + } else { + // ROF is earlier than previous + // the sum of v1 and v2: + if (vAmpFT0CperColl[colIndex] > 4000 && vAmpFT0CperColl[colIndex - 1] > 4000) + histos.fill(HIST("afterNarrowDeltaTimeCut/hSum_2coll_withFT0above4000_thisROFearlierThanPrevPrevROF"), vTracksITS567perColl[colIndex] + vTracksITS567perColl[colIndex - 1]); + } + } + } + } + if (vNoCollInTimeRangeStrict[colIndex]) { + histos.fill(HIST("afterStrictDeltaTimeCut/hThisEvITSTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("afterStrictDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + histos.fill(HIST("afterStrictDeltaTimeCut/hThisEvITSTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("afterStrictDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + } + if (vNoHighMultCollInTimeRange[colIndex]) { + histos.fill(HIST("afterStandardDeltaTimeCut/hThisEvITSTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("afterStandardDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + histos.fill(HIST("afterStandardDeltaTimeCut/hThisEvITSTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("afterStandardDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + } + + if (vNoCollInVzDependentTimeRange[colIndex]) { + histos.fill(HIST("afterVzDependentDeltaTimeCut/hThisEvITSTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("afterVzDependentDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + histos.fill(HIST("afterVzDependentDeltaTimeCut/hThisEvITSTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("afterVzDependentDeltaTimeCut/hThisEvITSTPCTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + } + + if (vNoCollInSameRofStrict[colIndex]) { + histos.fill(HIST("kNoCollInRofStrict/hThisEvITSTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("kNoCollInRofStrict/hThisEvITSTPCTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + histos.fill(HIST("kNoCollInRofStrict/hThisEvITSTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("kNoCollInRofStrict/hThisEvITSTPCTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + } + + if (vNoCollInSameRofStandard[colIndex]) { + histos.fill(HIST("kNoCollInRofStandard/hThisEvITSTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("kNoCollInRofStandard/hThisEvITSTPCTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + histos.fill(HIST("kNoCollInRofStandard/hThisEvITSTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("kNoCollInRofStandard/hThisEvITSTPCTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + } + + if (vNoCollInSameRofWithCloseVz[colIndex]) { + histos.fill(HIST("kNoCollInRofWithCloseVz/hThisEvITSTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("kNoCollInRofWithCloseVz/hThisEvITSTPCTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + histos.fill(HIST("kNoCollInRofWithCloseVz/hThisEvITSTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("kNoCollInRofWithCloseVz/hThisEvITSTPCTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + + if (vNumTracksITS567inROF[colIndex] > 0) { + histos.fill(HIST("kNoCollInRofWithCloseVz/hThisEvITSTr_vs_occupancyInROF_HasNeighbours"), vNumTracksITS567inROF[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("kNoCollInRofWithCloseVz/hThisEvITSTr_vs_occupancyFT0CInROF_HasNeighbours"), vSumAmpFT0CinROF[colIndex], vTracksITS567perColl[colIndex]); + + histos.fill(HIST("kNoCollInRofWithCloseVz/hThisEvFT0C_vs_occupancyFT0CInROF_HasNeighbours"), vSumAmpFT0CinROF[colIndex], vAmpFT0CperColl[colIndex]); + } + + if (vNumCollinROF[colIndex] == 2 && vNumCollinROFinVz10[colIndex] == 2 && vInROFcollIndex[colIndex] == 1) { + histos.fill(HIST("kNoCollInRofWithCloseVz/hThisEvITSTr_vs_occupancyInROF_2coll"), vNumTracksITS567inROF[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("kNoCollInRofWithCloseVz/hThisEvFT0C_vs_occupancyFT0CInROF_2coll"), vSumAmpFT0CinROF[colIndex], vAmpFT0CperColl[colIndex]); + } + } + + if (vNoCollInTimeRangeNarrow[colIndex] && vNoHighMultCollInTimeRange[colIndex] && vNoCollInSameRofStandard[colIndex] && vNoCollInSameRofWithCloseVz[colIndex]) { + histos.fill(HIST("NarrowDeltaCut_StdTimeAndRofCuts/hThisEvITSTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("NarrowDeltaCut_StdTimeAndRofCuts/hThisEvITSTPCTr_vs_occupancyByFT0C"), vSumAmpFT0CinFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + histos.fill(HIST("NarrowDeltaCut_StdTimeAndRofCuts/hThisEvITSTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITS567perColl[colIndex]); + histos.fill(HIST("NarrowDeltaCut_StdTimeAndRofCuts/hThisEvITSTPCTr_vs_occupancyByTracks"), vNumTracksITS567inFullTimeWin[colIndex], vTracksITSTPCperColl[colIndex]); + } + } + } + } + } + } + + PROCESS_SWITCH(RofOccupancyQaTask, processRun3, "Process Run3 ROF occupancy QA", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/DPG/Tasks/AOTEvent/timeDependentQa.cxx b/DPG/Tasks/AOTEvent/timeDependentQa.cxx new file mode 100644 index 00000000000..e742ee040fd --- /dev/null +++ b/DPG/Tasks/AOTEvent/timeDependentQa.cxx @@ -0,0 +1,741 @@ +// 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 timeDependentQa.cxx +/// \brief Time-dependent QA for a number of observables +/// +/// \author Evgeny Kryshen and Igor Altsybeev + +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "CCDB/BasicCCDBManager.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/DataModel/Multiplicity.h" +#include "TPCCalibration/TPCMShapeCorrection.h" +#include "DataFormatsParameters/AggregatedRunInfo.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "ReconstructionDataFormats/Vertex.h" + +#include "TTree.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::aod::evsel; +using namespace o2::aod::rctsel; + +using ColEvSels = soa::Join; +using BCsRun3 = soa::Join; +using BarrelTracks = soa::Join; + +const AxisSpec axisQoverPt{100, -1., 1., "q/p_{T}, 1/GeV"}; +const AxisSpec axisDcaR{1000, -5., 5., "DCA_{r}, cm"}; +const AxisSpec axisDcaZ{1000, -5., 5., "DCA_{z}, cm"}; +const AxisSpec axisSparseQoverPt{20, -1., 1., "q/p_{T}, 1/GeV"}; +const AxisSpec axisSparseDcaR{100, -1., 1., "DCA_{r}, cm"}; +const AxisSpec axisSparseDcaZ{100, -1., 1., "DCA_{z}, cm"}; + +struct TimeDependentQaTask { + Configurable confTimeBinWidthInSec{"TimeBinWidthInSec", 0.5, "Width of time bins in seconds"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confTimeWiderBinFactor{"TimeWideBinFactor", 4, "Factor for wider time bins for some 2D histograms"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confTakeVerticesWithUPCsettings{"ConsiderVerticesWithUPCsettings", 0, "Take vertices: 0 - all , 1 - only without UPC settings, 2 - only with UPC settings"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confFlagFillPhiVsTimeHist{"FlagFillPhiVsTimeHist", 2, "0 - don't fill , 1 - fill only for global/7cls/TRD/TOF tracks, 2 - fill also layer-by-layer"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confFlagFillEtaPhiVsTimeHist{"FlagFillEtaPhiVsTimeHist", 0, "0 - don't fill , 1 - fill"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confCutOnNtpcClsForSharedFractAndDeDxCalc{"CutOnNtpcClsForSharedFractAndDeDxCalc", 70, ""}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confFlagCheckMshape{"FlagCheckMshape", 0, "0 - don't check , 1 - check"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confFlagCheckQoverPtHist{"FlagCheckQoverPtHist", 1, "0 - don't check , 1 - check"}; // o2-linter: disable=name/configurable (temporary fix) + + enum EvSelBitsToMonitor { + enCollisionsAll = 0, + enIsTriggerTVX, + enNoTimeFrameBorder, + enNoITSROFrameBorder, + enCollisionsSel8, + enNoSameBunchPileup, + enIsGoodZvtxFT0vsPV, + enIsVertexITSTPC, + enIsVertexTOFmatched, + enIsVertexTRDmatched, + enNoCollInTimeRangeNarrow, + enNoCollInTimeRangeStrict, + enNoCollInTimeRangeStandard, + enNoCollInRofStrict, + enNoCollInRofStandard, + enNoHighMultCollInPrevRof, + enIsGoodITSLayer3, + enIsGoodITSLayer0123, + enIsGoodITSLayersAll, + enIsLowOccupStd, + enIsLowOccupStdAlsoInPrevRof, + enIsLowOccupStdCut500, + enIsLowOccupStdCut2000, + enIsLowOccupStdCut4000, + enIsLowOccupStdAlsoInPrevRofCut2000noDeadStaves, + enNumEvSelBits, // counter + }; + + enum RctCombFlagsToMonitor { + enCBT = kNRCTSelectionFlags, + enCBT_hadronPID, + enCBT_electronPID, + enCBT_calo, + enCBT_muon, + enCBT_muon_glo, + enNumRctFlagsTotal, // counter + }; + + Service ccdb; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + o2::tpc::TPCMShapeCorrection mshape; // object for simple access + int lastRunNumber = -1; + double maxSec = 1; + double minSec = 0; + static const int32_t nBCsPerOrbit = o2::constants::lhc::LHCMaxBunches; + int64_t bcSOR = 0; // global bc of the start of the first orbit, setting 0 for unanchored MC + int64_t nBCsPerTF = -1; // duration of TF in bcs + ctpRateFetcher mRateFetcher; + + // RCT flag combinations: checkers (based on presentation https://indico.cern.ch/event/1513866/#18-how-to-use-the-rct-flags-at) + RCTFlagsChecker rctCheckerCBT{"CBT"}; // o2-linter: disable=name/function-variable (temporary fix) + RCTFlagsChecker rctCheckerCBT_hadronPID{"CBT_hadronPID"}; // o2-linter: disable=name/function-variable (temporary fix) + RCTFlagsChecker rctCheckerCBT_electronPID{"CBT_electronPID"}; // o2-linter: disable=name/function-variable (temporary fix) + RCTFlagsChecker rctCheckerCBT_calo{"CBT_calo"}; // o2-linter: disable=name/function-variable (temporary fix) + RCTFlagsChecker rctCheckerCBT_muon{"CBT_muon"}; // o2-linter: disable=name/function-variable (temporary fix) + RCTFlagsChecker rctCheckerCBT_muon_glo{"CBT_muon_glo"}; // o2-linter: disable=name/function-variable (temporary fix) + + TAxis* axRctFlags; + + void init(InitContext&) + { + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + histos.add("allTracks/hQoverPt", "", kTH1F, {axisQoverPt}); + if (confFlagCheckQoverPtHist) { + histos.add("allTracks/hQoverPtDcaR", "", kTH2F, {axisSparseQoverPt, axisSparseDcaR}); + histos.add("allTracks/hQoverPtDcaZ", "", kTH2F, {axisSparseQoverPt, axisSparseDcaZ}); + } + histos.add("allTracks/hDcaR", "", kTH1F, {axisDcaR}); + histos.add("allTracks/hDcaZ", "", kTH1F, {axisDcaZ}); + histos.add("allTracks/hDcaRafterCuts", "", kTH1F, {axisDcaR}); + histos.add("allTracks/hDcaZafterCuts", "", kTH1F, {axisDcaZ}); + + histos.add("PVcontrib/hDcaRafterCuts", "", kTH1F, {axisDcaR}); + histos.add("PVcontrib/hDcaZafterCuts", "", kTH1F, {axisDcaZ}); + + histos.add("A/global/hDcaRafterCuts", "", kTH1F, {axisDcaR}); + histos.add("A/global/hDcaZafterCuts", "", kTH1F, {axisDcaZ}); + histos.add("A/globalPV/hDcaRafterCuts", "", kTH1F, {axisDcaR}); + histos.add("A/globalPV/hDcaZafterCuts", "", kTH1F, {axisDcaZ}); + + histos.add("C/global/hDcaRafterCuts", "", kTH1F, {axisDcaR}); + histos.add("C/global/hDcaZafterCuts", "", kTH1F, {axisDcaZ}); + histos.add("C/globalPV/hDcaRafterCuts", "", kTH1F, {axisDcaR}); + histos.add("C/globalPV/hDcaZafterCuts", "", kTH1F, {axisDcaZ}); + } + + Preslice perCollision = aod::track::collisionId; + + void processRun3( + ColEvSels const& cols, + BarrelTracks const& tracks, + BCsRun3 const& bcs, + aod::FT0s const&) + { + int runNumber = bcs.iteratorAt(0).runNumber(); + if (runNumber != lastRunNumber) { + LOGP(debug, " >> QA: run number = {}", runNumber); + lastRunNumber = runNumber; + + int64_t tsSOR = 0; // dummy start-of-run timestamp + int64_t tsEOR = 1; // dummy end-of-run timestamp + if (runNumber >= 500000) { + auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), runNumber); + // first bc of the first orbit + bcSOR = runInfo.orbitSOR * nBCsPerOrbit; + // duration of TF in bcs + nBCsPerTF = runInfo.orbitsPerTF * nBCsPerOrbit; + // start-of-run timestamp + tsSOR = runInfo.sor; + // end-of-run timestamp + tsEOR = runInfo.eor; + } + + minSec = floor(tsSOR / 1000.); + maxSec = ceil(tsEOR / 1000.); + int nTimeBins = static_cast((maxSec - minSec) / confTimeBinWidthInSec); + int nTimeWideBins = static_cast((maxSec - minSec) / confTimeBinWidthInSec / confTimeWiderBinFactor); + double timeInterval = nTimeBins * confTimeBinWidthInSec; + + const AxisSpec axisSeconds{nTimeBins, 0, timeInterval, "seconds"}; + const AxisSpec axisSecondsWideBins{nTimeWideBins, 0, timeInterval, "seconds"}; + histos.add("hSecondsBCsTVX", "", kTH1D, {axisSeconds}); + histos.add("hSecondsBCsTVXandTFborderCuts", "", kTH1D, {axisSeconds}); + + histos.add("hSecondsCollisionsBeforeAllCuts", "", kTH1D, {axisSeconds}); + histos.add("hSecondsCollisionsTVXNoVzCut", "", kTH1D, {axisSeconds}); + histos.add("hSecondsCollisionsTFborderCutNoVzCut", "", kTH1D, {axisSeconds}); + histos.add("hSecondsCollisionsTVXTFborderCutNoVzCut", "", kTH1D, {axisSeconds}); + + histos.add("hSecondsCollisions", "", kTH1D, {axisSeconds}); + histos.add("hSecondsIR", "", kTH1D, {axisSeconds}); + histos.add("hSecondsVz", "", kTH1D, {axisSeconds}); + histos.add("hSecondsFT0Camlp", "", kTH1D, {axisSeconds}); + histos.add("hSecondsFT0CamlpByColMult", "", kTH1D, {axisSeconds}); + histos.add("hSecondsFT0AamlpByColMult", "", kTH1D, {axisSeconds}); + histos.add("hSecondsV0Aamlp", "", kTH1D, {axisSeconds}); + histos.add("hSecondsOccupancyByTracks", "", kTH1D, {axisSeconds}); + histos.add("hSecondsOccupancyByFT0C", "", kTH1D, {axisSeconds}); + + // QA for UPC settings + histos.add("hSecondsUPCverticesBeforeAllCuts", "", kTH2F, {axisSeconds, {2, -0.5, 1.5, "Is vertex with UPC settings"}}); + histos.add("hSecondsUPCverticesBeforeSel8", "", kTH2F, {axisSeconds, {2, -0.5, 1.5, "Is vertex with UPC settings after |vZ|<10 cut"}}); + histos.add("hSecondsUPCvertices", "", kTH2F, {axisSeconds, {2, -0.5, 1.5, "Is vertex with UPC settings after |vZ|<10 and sel8 cuts"}}); + + // ### QA event selection bits + int nEvSelBits = enNumEvSelBits; + histos.add("hSecondsEventSelBits", "", kTH2F, {axisSecondsWideBins, {nEvSelBits, -0.5, nEvSelBits - 0.5, "Monitoring of event selection bits"}}); + TAxis* axSelBits = reinterpret_cast(histos.get(HIST("hSecondsEventSelBits"))->GetYaxis()); + axSelBits->SetBinLabel(1 + enCollisionsAll, "collisionsAll"); + axSelBits->SetBinLabel(1 + enIsTriggerTVX, "IsTriggerTVX"); + axSelBits->SetBinLabel(1 + enNoTimeFrameBorder, "NoTimeFrameBorder"); + axSelBits->SetBinLabel(1 + enNoITSROFrameBorder, "NoITSROFrameBorder"); + + // bits after sel8 + axSelBits->SetBinLabel(1 + enCollisionsSel8, "collisionsSel8"); + axSelBits->SetBinLabel(1 + enNoSameBunchPileup, "NoSameBunchPileup"); + axSelBits->SetBinLabel(1 + enIsGoodZvtxFT0vsPV, "IsGoodZvtxFT0vsPV"); + axSelBits->SetBinLabel(1 + enIsVertexITSTPC, "IsVertexITSTPC"); + axSelBits->SetBinLabel(1 + enIsVertexTOFmatched, "IsVertexTOFmatched"); + axSelBits->SetBinLabel(1 + enIsVertexTRDmatched, "IsVertexTRDmatched"); + + axSelBits->SetBinLabel(1 + enNoCollInTimeRangeNarrow, "NoCollInTimeRangeNarrow"); + axSelBits->SetBinLabel(1 + enNoCollInTimeRangeStrict, "NoCollInTimeRangeStrict"); + axSelBits->SetBinLabel(1 + enNoCollInTimeRangeStandard, "NoCollInTimeRangeStandard"); + axSelBits->SetBinLabel(1 + enNoCollInRofStrict, "NoCollInRofStrict"); + axSelBits->SetBinLabel(1 + enNoCollInRofStandard, "NoCollInRofStandard"); + axSelBits->SetBinLabel(1 + enNoHighMultCollInPrevRof, "NoHighMultCollInPrevRof"); + + axSelBits->SetBinLabel(1 + enIsGoodITSLayer3, "IsGoodITSLayer3"); + axSelBits->SetBinLabel(1 + enIsGoodITSLayer0123, "IsGoodITSLayer0123"); + axSelBits->SetBinLabel(1 + enIsGoodITSLayersAll, "IsGoodITSLayersAll"); + + // combined conditions on occupancy + axSelBits->SetBinLabel(1 + enIsLowOccupStd, "isLowOccupStd"); + axSelBits->SetBinLabel(1 + enIsLowOccupStdAlsoInPrevRof, "isLowOccupStdAlsoInPrevRof"); + axSelBits->SetBinLabel(1 + enIsLowOccupStdCut500, "isLowOccupStdCut500"); + axSelBits->SetBinLabel(1 + enIsLowOccupStdCut2000, "isLowOccupStdCut2000"); + axSelBits->SetBinLabel(1 + enIsLowOccupStdCut4000, "isLowOccupStdCut4000"); + axSelBits->SetBinLabel(1 + enIsLowOccupStdAlsoInPrevRofCut2000noDeadStaves, "isLowOccupStdAlsoInPrevRofCut2000noDeadStaves"); + + // ### QA RCT flags + int nRctFlagsTotal = enNumRctFlagsTotal; + histos.add("hSecondsRCTflags", "", kTH2F, {axisSecondsWideBins, {nRctFlagsTotal + 1, -0.5, nRctFlagsTotal + 1 - 0.5, "Monitoring of RCT flags"}}); + axRctFlags = reinterpret_cast(histos.get(HIST("hSecondsRCTflags"))->GetYaxis()); + axRctFlags->SetBinLabel(1, "NcollisionsSel8"); + axRctFlags->SetBinLabel(2 + kCPVBad, "CPVBad"); + axRctFlags->SetBinLabel(2 + kEMCBad, "EMCBad"); + axRctFlags->SetBinLabel(2 + kEMCLimAccMCRepr, "EMCLimAccMCRepr"); + axRctFlags->SetBinLabel(2 + kFDDBad, "FDDBad"); + axRctFlags->SetBinLabel(2 + kFT0Bad, "FT0Bad"); + axRctFlags->SetBinLabel(2 + kFV0Bad, "FV0Bad"); + axRctFlags->SetBinLabel(2 + kHMPBad, "HMPBad"); + axRctFlags->SetBinLabel(2 + kITSBad, "ITSBad"); + axRctFlags->SetBinLabel(2 + kITSLimAccMCRepr, "ITSLimAccMCRepr"); + axRctFlags->SetBinLabel(2 + kMCHBad, "MCHBad"); + axRctFlags->SetBinLabel(2 + kMCHLimAccMCRepr, "MCHLimAccMCRepr"); + axRctFlags->SetBinLabel(2 + kMFTBad, "MFTBad"); + axRctFlags->SetBinLabel(2 + kMFTLimAccMCRepr, "MFTLimAccMCRepr"); + axRctFlags->SetBinLabel(2 + kMIDBad, "MIDBad"); + axRctFlags->SetBinLabel(2 + kMIDLimAccMCRepr, "MIDLimAccMCRepr"); + axRctFlags->SetBinLabel(2 + kPHSBad, "PHSBad"); + axRctFlags->SetBinLabel(2 + kTOFBad, "TOFBad"); + axRctFlags->SetBinLabel(2 + kTOFLimAccMCRepr, "TOFLimAccMCRepr"); + axRctFlags->SetBinLabel(2 + kTPCBadTracking, "TPCBadTracking"); + axRctFlags->SetBinLabel(2 + kTPCBadPID, "TPCBadPID"); + axRctFlags->SetBinLabel(2 + kTPCLimAccMCRepr, "TPCLimAccMCRepr"); + axRctFlags->SetBinLabel(2 + kTRDBad, "TRDBad"); + axRctFlags->SetBinLabel(2 + kZDCBad, "ZDCBad"); + // combined flags + axRctFlags->SetBinLabel(2 + enCBT, "CBT"); + axRctFlags->SetBinLabel(2 + enCBT_hadronPID, "CBT_hadronPID"); + axRctFlags->SetBinLabel(2 + enCBT_electronPID, "CBT_electronPID"); + axRctFlags->SetBinLabel(2 + enCBT_calo, "CBT_calo"); + axRctFlags->SetBinLabel(2 + enCBT_muon, "CBT_muon"); + axRctFlags->SetBinLabel(2 + enCBT_muon_glo, "CBT_muon_glo"); + + // QA for all tracks + // const AxisSpec axisChi2ITS{40, 0., 20., "chi2/ndof"}; + // const AxisSpec axisChi2TPC{40, 0., 20., "chi2/ndof"}; + const AxisSpec axisNclsITS{5, 3.5, 8.5, "n ITS cls"}; + const AxisSpec axisNclsTPC{40, -0.5, 159.5, "n TPC cls"}; + const AxisSpec axisFraction{20, 0, 1., "Fraction shared cls Tpc"}; + histos.add("allTracks/hSecondsTracks", "", kTH1D, {axisSeconds}); + if (confFlagCheckQoverPtHist) { + histos.add("allTracks/hSecondsQoverPtSumDcaR", "", kTH2D, {axisSecondsWideBins, axisSparseQoverPt}); + histos.add("allTracks/hSecondsQoverPtSumDcaZ", "", kTH2D, {axisSecondsWideBins, axisSparseQoverPt}); + } + histos.add("allTracks/hSecondsSumDcaR", "", kTH1D, {axisSeconds}); + histos.add("allTracks/hSecondsSumDcaZ", "", kTH1D, {axisSeconds}); + histos.add("allTracks/hSecondsSumPt", "", kTH1D, {axisSeconds}); + histos.add("allTracks/hSecondsNumClsIts", "", kTH1D, {axisSeconds}); + histos.add("allTracks/hSeconds2DNumClsIts", "", kTH2D, {axisSecondsWideBins, axisNclsITS}); + histos.add("allTracks/hSecondsChi2NClIts", "", kTH1D, {axisSeconds}); + if (confFlagCheckMshape) + histos.add("allTracks/hSecondsTracksMshape", "", kTH1D, {axisSeconds}); + + // QA for PV contributors + histos.add("PVcontrib/hSecondsTracks", "", kTH1D, {axisSeconds}); + histos.add("PVcontrib/hSecondsSumDcaR", "", kTH1D, {axisSeconds}); + histos.add("PVcontrib/hSecondsSumDcaZ", "", kTH1D, {axisSeconds}); + histos.add("PVcontrib/hSecondsSumPt", "", kTH1D, {axisSeconds}); + histos.add("PVcontrib/hSecondsNumClsIts", "", kTH1D, {axisSeconds}); + histos.add("PVcontrib/hSeconds2DNumClsIts", "", kTH2D, {axisSecondsWideBins, axisNclsITS}); + histos.add("PVcontrib/hSecondsChi2NClIts", "", kTH1D, {axisSeconds}); + + // QA for global tracks + // ### A side + // global tracks + histos.add("A/global/hSecondsNumTracks", "", kTH1D, {axisSeconds}); + if (confFlagCheckQoverPtHist) { + histos.add("A/global/hSecondsQoverPtSumDcaR", "", kTH2D, {axisSecondsWideBins, axisSparseQoverPt}); + histos.add("A/global/hSecondsQoverPtSumDcaZ", "", kTH2D, {axisSecondsWideBins, axisSparseQoverPt}); + } + histos.add("A/global/hSecondsSumDcaR", "", kTH1D, {axisSeconds}); + histos.add("A/global/hSecondsSumDcaZ", "", kTH1D, {axisSeconds}); + histos.add("A/global/hSecondsSumPt", "", kTH1D, {axisSeconds}); + histos.add("A/global/hSecondsNumClsIts", "", kTH1D, {axisSeconds}); + histos.add("A/global/hSeconds2DNumClsIts", "", kTH2D, {axisSecondsWideBins, axisNclsITS}); + histos.add("A/global/hSecondsChi2NClIts", "", kTH1D, {axisSeconds}); + histos.add("A/global/hSecondsNumClsTpc", "", kTH1D, {axisSeconds}); + histos.add("A/global/hSeconds2DNumClsTpc", "", kTH2D, {axisSecondsWideBins, axisNclsTPC}); + histos.add("A/global/hSecondsChi2NClTpc", "", kTH1D, {axisSeconds}); + histos.add("A/global/hSecondsTpcFractionSharedCls", "", kTH1D, {axisSeconds}); + histos.add("A/global/hSeconds2DTpcFractionSharedCls", "", kTH2D, {axisSecondsWideBins, axisFraction}); + histos.add("A/global/hSecondsDeDx", "", kTH1D, {axisSeconds}); + + // global && PV tracks + histos.add("A/globalPV/hSecondsNumPVcontributors", "", kTH1D, {axisSeconds}); + histos.add("A/globalPV/hSecondsSumDcaR", "", kTH1D, {axisSeconds}); + histos.add("A/globalPV/hSecondsSumDcaZ", "", kTH1D, {axisSeconds}); + histos.add("A/globalPV/hSecondsSumPt", "", kTH1D, {axisSeconds}); + histos.add("A/globalPV/hSecondsNumClsIts", "", kTH1D, {axisSeconds}); + histos.add("A/globalPV/hSeconds2DNumClsIts", "", kTH2D, {axisSecondsWideBins, axisNclsITS}); + histos.add("A/globalPV/hSecondsChi2NClIts", "", kTH1D, {axisSeconds}); + histos.add("A/globalPV/hSecondsNumClsTpc", "", kTH1D, {axisSeconds}); + histos.add("A/globalPV/hSeconds2DNumClsTpc", "", kTH2D, {axisSecondsWideBins, axisNclsTPC}); + histos.add("A/globalPV/hSecondsChi2NClTpc", "", kTH1D, {axisSeconds}); + histos.add("A/globalPV/hSecondsTpcFractionSharedCls", "", kTH1D, {axisSeconds}); + histos.add("A/globalPV/hSeconds2DTpcFractionSharedCls", "", kTH2D, {axisSecondsWideBins, axisFraction}); + histos.add("A/globalPV/hSecondsDeDx", "", kTH1D, {axisSeconds}); + + // ### C side + // global tracks + histos.add("C/global/hSecondsNumTracks", "", kTH1D, {axisSeconds}); + if (confFlagCheckQoverPtHist) { + histos.add("C/global/hSecondsQoverPtSumDcaR", "", kTH2D, {axisSecondsWideBins, axisSparseQoverPt}); + histos.add("C/global/hSecondsQoverPtSumDcaZ", "", kTH2D, {axisSecondsWideBins, axisSparseQoverPt}); + } + histos.add("C/global/hSecondsSumDcaR", "", kTH1D, {axisSeconds}); + histos.add("C/global/hSecondsSumDcaZ", "", kTH1D, {axisSeconds}); + histos.add("C/global/hSecondsSumPt", "", kTH1D, {axisSeconds}); + histos.add("C/global/hSecondsNumClsIts", "", kTH1D, {axisSeconds}); + histos.add("C/global/hSeconds2DNumClsIts", "", kTH2D, {axisSecondsWideBins, axisNclsITS}); + histos.add("C/global/hSecondsChi2NClIts", "", kTH1D, {axisSeconds}); + histos.add("C/global/hSecondsNumClsTpc", "", kTH1D, {axisSeconds}); + histos.add("C/global/hSeconds2DNumClsTpc", "", kTH2D, {axisSecondsWideBins, axisNclsTPC}); + histos.add("C/global/hSecondsChi2NClTpc", "", kTH1D, {axisSeconds}); + histos.add("C/global/hSecondsTpcFractionSharedCls", "", kTH1D, {axisSeconds}); + histos.add("C/global/hSeconds2DTpcFractionSharedCls", "", kTH2D, {axisSecondsWideBins, axisFraction}); + histos.add("C/global/hSecondsDeDx", "", kTH1D, {axisSeconds}); + + // global && PV tracks + histos.add("C/globalPV/hSecondsNumPVcontributors", "", kTH1D, {axisSeconds}); + histos.add("C/globalPV/hSecondsSumDcaR", "", kTH1D, {axisSeconds}); + histos.add("C/globalPV/hSecondsSumDcaZ", "", kTH1D, {axisSeconds}); + histos.add("C/globalPV/hSecondsSumPt", "", kTH1D, {axisSeconds}); + histos.add("C/globalPV/hSecondsNumClsIts", "", kTH1D, {axisSeconds}); + histos.add("C/globalPV/hSeconds2DNumClsIts", "", kTH2D, {axisSecondsWideBins, axisNclsITS}); + histos.add("C/globalPV/hSecondsChi2NClIts", "", kTH1D, {axisSeconds}); + histos.add("C/globalPV/hSecondsNumClsTpc", "", kTH1D, {axisSeconds}); + histos.add("C/globalPV/hSeconds2DNumClsTpc", "", kTH2D, {axisSecondsWideBins, axisNclsTPC}); + histos.add("C/globalPV/hSecondsChi2NClTpc", "", kTH1D, {axisSeconds}); + histos.add("C/globalPV/hSecondsTpcFractionSharedCls", "", kTH1D, {axisSeconds}); + histos.add("C/globalPV/hSeconds2DTpcFractionSharedCls", "", kTH2D, {axisSecondsWideBins, axisFraction}); + histos.add("C/globalPV/hSecondsDeDx", "", kTH1D, {axisSeconds}); + + // phi holes vs time + const AxisSpec axisPhi{64, 0, TMath::TwoPi(), "#varphi"}; // o2-linter: disable=external-pi (temporary fix) + const AxisSpec axisEta{10, -0.8, 0.8, "#eta"}; + if (confFlagFillPhiVsTimeHist == 2) { + histos.add("hSecondsITSlayer0vsPhi", "", kTH2F, {axisSeconds, axisPhi}); + histos.add("hSecondsITSlayer1vsPhi", "", kTH2F, {axisSeconds, axisPhi}); + histos.add("hSecondsITSlayer2vsPhi", "", kTH2F, {axisSeconds, axisPhi}); + histos.add("hSecondsITSlayer3vsPhi", "", kTH2F, {axisSeconds, axisPhi}); + histos.add("hSecondsITSlayer4vsPhi", "", kTH2F, {axisSeconds, axisPhi}); + histos.add("hSecondsITSlayer5vsPhi", "", kTH2F, {axisSeconds, axisPhi}); + histos.add("hSecondsITSlayer6vsPhi", "", kTH2F, {axisSeconds, axisPhi}); + } + if (confFlagFillPhiVsTimeHist > 0) { + histos.add("hSecondsITS7clsVsPhi", "", kTH2F, {axisSeconds, axisPhi}); + histos.add("hSecondsITSglobalVsPhi", "", kTH2F, {axisSeconds, axisPhi}); + histos.add("hSecondsITSTRDVsPhi", "", kTH2F, {axisSeconds, axisPhi}); + histos.add("hSecondsITSTOFVsPhi", "", kTH2F, {axisSeconds, axisPhi}); + } + if (confFlagFillEtaPhiVsTimeHist) + histos.add("hSecondsITSglobalVsEtaPhi", "", kTH3F, {axisSeconds, axisEta, axisPhi}); + } + + // count TVX triggers per DF + for (const auto& bc : bcs) { + // auto bc = col.foundBC_as(); + int64_t ts = bc.timestamp(); + double secFromSOR = ts / 1000. - minSec; + if (bc.selection_bit(kIsTriggerTVX)) { + histos.fill(HIST("hSecondsBCsTVX"), secFromSOR); + if (bc.selection_bit(kNoTimeFrameBorder)) { + histos.fill(HIST("hSecondsBCsTVXandTFborderCuts"), secFromSOR); + } + } + } + + // ### collision loop + for (const auto& col : cols) { + // check if a vertex is found in the UPC mode ITS ROF + // flags from: https://github.com/AliceO2Group/AliceO2/blob/dev/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h + ushort flags = col.flags(); + bool isVertexUPC = flags & dataformats::Vertex>::Flags::UPCMode; // is vertex with UPC settings + if (confTakeVerticesWithUPCsettings > 0) { // otherwise analyse all collisions + if (confTakeVerticesWithUPCsettings == 1 && isVertexUPC) // reject vertices with UPC settings + continue; + if (confTakeVerticesWithUPCsettings == 2 && !isVertexUPC) // we want to select vertices with UPC settings --> reject vertices reconstructed with "normal" settings + continue; + // LOGP(info, "flags={} nTracks = {}", flags, tracks.size()); + } + + auto bc = col.foundBC_as(); + int64_t ts = bc.timestamp(); + double secFromSOR = ts / 1000. - minSec; + + histos.fill(HIST("hSecondsCollisionsBeforeAllCuts"), secFromSOR); + if (col.selection_bit(kIsTriggerTVX)) + histos.fill(HIST("hSecondsCollisionsTVXNoVzCut"), secFromSOR); + if (col.selection_bit(kNoTimeFrameBorder)) + histos.fill(HIST("hSecondsCollisionsTFborderCutNoVzCut"), secFromSOR); + if (col.selection_bit(kIsTriggerTVX) && col.selection_bit(kNoTimeFrameBorder)) + histos.fill(HIST("hSecondsCollisionsTVXTFborderCutNoVzCut"), secFromSOR); + + histos.fill(HIST("hSecondsUPCverticesBeforeAllCuts"), secFromSOR, isVertexUPC ? 1 : 0); + + if (std::fabs(col.posZ()) > 10) + continue; + + histos.fill(HIST("hSecondsUPCverticesBeforeSel8"), secFromSOR, isVertexUPC ? 1 : 0); + + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enCollisionsAll); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enIsTriggerTVX, col.selection_bit(kIsTriggerTVX)); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enNoTimeFrameBorder, col.selection_bit(kNoTimeFrameBorder)); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enNoITSROFrameBorder, col.selection_bit(kNoITSROFrameBorder)); + + // sel8 selection: + if (!col.sel8()) + continue; + + histos.fill(HIST("hSecondsUPCvertices"), secFromSOR, isVertexUPC ? 1 : 0); + histos.fill(HIST("hSecondsCollisions"), secFromSOR); + histos.fill(HIST("hSecondsVz"), secFromSOR, col.posZ()); + histos.fill(HIST("hSecondsFT0Camlp"), secFromSOR, bc.foundFT0().sumAmpC()); + histos.fill(HIST("hSecondsFT0CamlpByColMult"), secFromSOR, col.multFT0C()); + histos.fill(HIST("hSecondsFT0AamlpByColMult"), secFromSOR, col.multFT0A()); + histos.fill(HIST("hSecondsV0Aamlp"), secFromSOR, col.multFV0A()); + + histos.fill(HIST("hSecondsOccupancyByTracks"), secFromSOR, col.trackOccupancyInTimeRange()); + histos.fill(HIST("hSecondsOccupancyByFT0C"), secFromSOR, col.ft0cOccupancyInTimeRange()); + + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enCollisionsSel8); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enNoSameBunchPileup, col.selection_bit(kNoSameBunchPileup)); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enIsGoodZvtxFT0vsPV, col.selection_bit(kIsGoodZvtxFT0vsPV)); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enIsVertexITSTPC, col.selection_bit(kIsVertexITSTPC)); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enIsVertexTOFmatched, col.selection_bit(kIsVertexTOFmatched)); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enIsVertexTRDmatched, col.selection_bit(kIsVertexTRDmatched)); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enNoCollInTimeRangeNarrow, col.selection_bit(kNoCollInTimeRangeNarrow)); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enNoCollInTimeRangeStrict, col.selection_bit(kNoCollInTimeRangeStrict)); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enNoCollInTimeRangeStandard, col.selection_bit(kNoCollInTimeRangeStandard)); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enNoCollInRofStrict, col.selection_bit(kNoCollInRofStrict)); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enNoCollInRofStandard, col.selection_bit(kNoCollInRofStandard)); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enNoHighMultCollInPrevRof, col.selection_bit(kNoHighMultCollInPrevRof)); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enIsGoodITSLayer3, col.selection_bit(kIsGoodITSLayer3)); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enIsGoodITSLayer0123, col.selection_bit(kIsGoodITSLayer0123)); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enIsGoodITSLayersAll, col.selection_bit(kIsGoodITSLayersAll)); + + // occupancy selection combinations + float occupByTracks = col.trackOccupancyInTimeRange(); + + bool isLowOccupStd = col.selection_bit(kNoCollInTimeRangeStandard) && col.selection_bit(kNoCollInRofStandard); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enIsLowOccupStd, isLowOccupStd); + + bool isLowOccupStdAlsoInPrevRof = isLowOccupStd && col.selection_bit(kNoHighMultCollInPrevRof); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enIsLowOccupStdAlsoInPrevRof, isLowOccupStdAlsoInPrevRof); + + bool isLowOccupStdCut500 = isLowOccupStd && occupByTracks >= 0 && occupByTracks < 500; + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enIsLowOccupStdCut500, isLowOccupStdCut500); + + bool isLowOccupStdCut2000 = isLowOccupStd && occupByTracks >= 0 && occupByTracks < 2000; + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enIsLowOccupStdCut2000, isLowOccupStdCut2000); + + bool isLowOccupStdCut4000 = isLowOccupStd && occupByTracks >= 0 && occupByTracks < 4000; + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enIsLowOccupStdCut4000, isLowOccupStdCut4000); + + bool isLowOccupStdAlsoInPrevRofCut2000noDeadStaves = isLowOccupStdCut2000 && col.selection_bit(kNoHighMultCollInPrevRof) && col.selection_bit(kIsGoodITSLayersAll); + histos.fill(HIST("hSecondsEventSelBits"), secFromSOR, enIsLowOccupStdAlsoInPrevRofCut2000noDeadStaves, isLowOccupStdAlsoInPrevRofCut2000noDeadStaves); + + // check RCT flags + histos.fill(HIST("hSecondsRCTflags"), secFromSOR, 0); // n collisions sel8 + for (int iFlag = 0; iFlag < kNRCTSelectionFlags; iFlag++) { + histos.fill(HIST("hSecondsRCTflags"), secFromSOR, 1 + iFlag, col.rct_bit(iFlag)); + LOGP(debug, "i = {}, bitValue = {}, binLabel={}, binCenter={}", iFlag, col.rct_bit(iFlag), axRctFlags->GetBinLabel(2 + iFlag), axRctFlags->GetBinCenter(2 + iFlag)); + } + LOGP(debug, "CBT_hadronPID = {}, kFT0Bad = {}, kITSBad = {}, kTPCBadTracking = {}, kTPCBadPID = {}, kTOFBad = {}, 1 + enCBT_hadronPID = {}, binLabel={}, binCenter={}", rctCheckerCBT_hadronPID(col), + col.rct_bit(kFT0Bad), col.rct_bit(kITSBad), col.rct_bit(kTPCBadTracking), col.rct_bit(kTPCBadPID), col.rct_bit(kTOFBad), 1 + enCBT_hadronPID, axRctFlags->GetBinLabel(2 + enCBT_hadronPID), axRctFlags->GetBinCenter(2 + enCBT_hadronPID)); + histos.fill(HIST("hSecondsRCTflags"), secFromSOR, 1 + enCBT, rctCheckerCBT(col)); + histos.fill(HIST("hSecondsRCTflags"), secFromSOR, 1 + enCBT_hadronPID, rctCheckerCBT_hadronPID(col)); + histos.fill(HIST("hSecondsRCTflags"), secFromSOR, 1 + enCBT_electronPID, rctCheckerCBT_electronPID(col)); + histos.fill(HIST("hSecondsRCTflags"), secFromSOR, 1 + enCBT_calo, rctCheckerCBT_calo(col)); + histos.fill(HIST("hSecondsRCTflags"), secFromSOR, 1 + enCBT_muon, rctCheckerCBT_muon(col)); + histos.fill(HIST("hSecondsRCTflags"), secFromSOR, 1 + enCBT_muon_glo, rctCheckerCBT_muon_glo(col)); + + // check hadronic rate + double hadronicRate = mRateFetcher.fetch(ccdb.service, ts, runNumber, "ZNC hadronic") * 1.e-3; // kHz + histos.fill(HIST("hSecondsIR"), secFromSOR, hadronicRate); + + // checking mShape flags in time: + bool isMshape = false; + if (confFlagCheckMshape) { + auto mShapeTree = ccdb->getForTimeStamp("TPC/Calib/MShapePotential", ts); + mshape.setFromTree(*mShapeTree); + isMshape = !mshape.getBoundaryPotential(ts).mPotential.empty(); + } + + // ##### track loop + auto tracksGrouped = tracks.sliceBy(perCollision, col.globalIndex()); + for (const auto& track : tracksGrouped) { + // if (!track.hasTPC() || !track.hasITS()) + // continue; + if (std::fabs(track.eta()) > 0.8 || std::fabs(track.pt()) < 0.2) + continue; + + double dcaR = track.dcaXY(); + double dcaZ = track.dcaZ(); + LOGP(debug, "dcaR = {} dcaZ = {}", dcaR, dcaZ); + histos.fill(HIST("allTracks/hDcaR"), dcaR); + histos.fill(HIST("allTracks/hDcaZ"), dcaZ); + + // now DCA cuts: + if (std::fabs(dcaR) > 1. || std::fabs(dcaZ) > 1.) + continue; + + histos.fill(HIST("allTracks/hSecondsTracks"), secFromSOR); + + histos.fill(HIST("allTracks/hDcaRafterCuts"), dcaR); + histos.fill(HIST("allTracks/hDcaZafterCuts"), dcaZ); + + double qpt = track.signed1Pt(); + histos.fill(HIST("allTracks/hQoverPt"), qpt); + if (confFlagCheckQoverPtHist) { + histos.fill(HIST("allTracks/hQoverPtDcaR"), qpt, dcaR); + histos.fill(HIST("allTracks/hQoverPtDcaZ"), qpt, dcaZ); + } + // now consider only abs values for DCAs: + double dcaRabs = std::fabs(dcaR); + double dcaZabs = std::fabs(dcaZ); + + histos.fill(HIST("allTracks/hSecondsSumDcaR"), secFromSOR, dcaRabs); + histos.fill(HIST("allTracks/hSecondsSumDcaZ"), secFromSOR, dcaZabs); + histos.fill(HIST("allTracks/hSecondsSumPt"), secFromSOR, track.pt()); + if (confFlagCheckQoverPtHist) { + histos.fill(HIST("allTracks/hSecondsQoverPtSumDcaR"), secFromSOR, qpt, dcaRabs); + histos.fill(HIST("allTracks/hSecondsQoverPtSumDcaZ"), secFromSOR, qpt, dcaZabs); + } + histos.fill(HIST("allTracks/hSecondsNumClsIts"), secFromSOR, track.itsNCls()); + histos.fill(HIST("allTracks/hSeconds2DNumClsIts"), secFromSOR, track.itsNCls()); + histos.fill(HIST("allTracks/hSecondsChi2NClIts"), secFromSOR, track.itsChi2NCl()); + if (confFlagCheckMshape && isMshape) { + histos.fill(HIST("allTracks/hSecondsTracksMshape"), secFromSOR); + } + + // ### PV contributors + if (track.isPVContributor()) { + histos.fill(HIST("PVcontrib/hDcaRafterCuts"), dcaR); + histos.fill(HIST("PVcontrib/hDcaZafterCuts"), dcaZ); + + histos.fill(HIST("PVcontrib/hSecondsTracks"), secFromSOR); + histos.fill(HIST("PVcontrib/hSecondsSumDcaR"), secFromSOR, dcaRabs); + histos.fill(HIST("PVcontrib/hSecondsSumDcaZ"), secFromSOR, dcaZabs); + histos.fill(HIST("PVcontrib/hSecondsSumPt"), secFromSOR, track.pt()); + // histos.fill(HIST("PVcontrib/hSecondsQoverPtSumDcaR"), secFromSOR, qpt, dcaRabs); + // histos.fill(HIST("PVcontrib/hSecondsQoverPtSumDcaZ"), secFromSOR, qpt, dcaZabs); + histos.fill(HIST("PVcontrib/hSecondsNumClsIts"), secFromSOR, track.itsNCls()); + histos.fill(HIST("PVcontrib/hSeconds2DNumClsIts"), secFromSOR, track.itsNCls()); + histos.fill(HIST("PVcontrib/hSecondsChi2NClIts"), secFromSOR, track.itsChi2NCl()); + } + + // ### global tracks + float dedx = track.tpcSignal(); + if (track.isGlobalTrack()) { // A side + if (track.tgl() > 0.) { + histos.fill(HIST("A/global/hDcaRafterCuts"), dcaR); + histos.fill(HIST("A/global/hDcaZafterCuts"), dcaZ); + + histos.fill(HIST("A/global/hSecondsNumTracks"), secFromSOR); + if (confFlagCheckQoverPtHist) { + histos.fill(HIST("A/global/hSecondsQoverPtSumDcaR"), secFromSOR, qpt, dcaRabs); + histos.fill(HIST("A/global/hSecondsQoverPtSumDcaZ"), secFromSOR, qpt, dcaZabs); + } + histos.fill(HIST("A/global/hSecondsSumDcaR"), secFromSOR, dcaRabs); + histos.fill(HIST("A/global/hSecondsSumDcaZ"), secFromSOR, dcaZabs); + histos.fill(HIST("A/global/hSecondsSumPt"), secFromSOR, track.pt()); + histos.fill(HIST("A/global/hSecondsNumClsIts"), secFromSOR, track.itsNCls()); + histos.fill(HIST("A/global/hSeconds2DNumClsIts"), secFromSOR, track.itsNCls()); + histos.fill(HIST("A/global/hSecondsChi2NClIts"), secFromSOR, track.itsChi2NCl()); + histos.fill(HIST("A/global/hSecondsNumClsTpc"), secFromSOR, track.tpcNClsFound()); + histos.fill(HIST("A/global/hSeconds2DNumClsTpc"), secFromSOR, track.tpcNClsFound()); + histos.fill(HIST("A/global/hSecondsChi2NClTpc"), secFromSOR, track.tpcChi2NCl()); + if (track.tpcNClsFound() >= confCutOnNtpcClsForSharedFractAndDeDxCalc) { + histos.fill(HIST("A/global/hSecondsTpcFractionSharedCls"), secFromSOR, track.tpcFractionSharedCls()); + histos.fill(HIST("A/global/hSeconds2DTpcFractionSharedCls"), secFromSOR, track.tpcFractionSharedCls()); + if (dedx < 1.e4) // protection from weird values + histos.fill(HIST("A/global/hSecondsDeDx"), secFromSOR, dedx); + } + + if (track.isPVContributor()) { + histos.fill(HIST("A/globalPV/hDcaRafterCuts"), dcaR); + histos.fill(HIST("A/globalPV/hDcaZafterCuts"), dcaZ); + + histos.fill(HIST("A/globalPV/hSecondsNumPVcontributors"), secFromSOR); + histos.fill(HIST("A/globalPV/hSecondsSumDcaR"), secFromSOR, dcaRabs); + histos.fill(HIST("A/globalPV/hSecondsSumDcaZ"), secFromSOR, dcaZabs); + histos.fill(HIST("A/globalPV/hSecondsSumPt"), secFromSOR, track.pt()); + histos.fill(HIST("A/globalPV/hSecondsNumClsIts"), secFromSOR, track.itsNCls()); + histos.fill(HIST("A/globalPV/hSeconds2DNumClsIts"), secFromSOR, track.itsNCls()); + histos.fill(HIST("A/globalPV/hSecondsChi2NClIts"), secFromSOR, track.itsChi2NCl()); + histos.fill(HIST("A/globalPV/hSecondsNumClsTpc"), secFromSOR, track.tpcNClsFound()); + histos.fill(HIST("A/globalPV/hSeconds2DNumClsTpc"), secFromSOR, track.tpcNClsFound()); + histos.fill(HIST("A/globalPV/hSecondsChi2NClTpc"), secFromSOR, track.tpcChi2NCl()); + if (track.tpcNClsFound() >= confCutOnNtpcClsForSharedFractAndDeDxCalc) { + histos.fill(HIST("A/globalPV/hSecondsTpcFractionSharedCls"), secFromSOR, track.tpcFractionSharedCls()); + histos.fill(HIST("A/globalPV/hSeconds2DTpcFractionSharedCls"), secFromSOR, track.tpcFractionSharedCls()); + if (dedx < 1.e4) // protection from weird values + histos.fill(HIST("A/globalPV/hSecondsDeDx"), secFromSOR, dedx); + } + } + } else { // C side + histos.fill(HIST("C/global/hDcaRafterCuts"), dcaR); + histos.fill(HIST("C/global/hDcaZafterCuts"), dcaZ); + + histos.fill(HIST("C/global/hSecondsNumTracks"), secFromSOR); + if (confFlagCheckQoverPtHist) { + histos.fill(HIST("C/global/hSecondsQoverPtSumDcaR"), secFromSOR, qpt, dcaRabs); + histos.fill(HIST("C/global/hSecondsQoverPtSumDcaZ"), secFromSOR, qpt, dcaZabs); + } + histos.fill(HIST("C/global/hSecondsSumDcaR"), secFromSOR, dcaRabs); + histos.fill(HIST("C/global/hSecondsSumDcaZ"), secFromSOR, dcaZabs); + histos.fill(HIST("C/global/hSecondsSumPt"), secFromSOR, track.pt()); + histos.fill(HIST("C/global/hSecondsNumClsIts"), secFromSOR, track.itsNCls()); + histos.fill(HIST("C/global/hSeconds2DNumClsIts"), secFromSOR, track.itsNCls()); + histos.fill(HIST("C/global/hSecondsChi2NClIts"), secFromSOR, track.itsChi2NCl()); + histos.fill(HIST("C/global/hSecondsNumClsTpc"), secFromSOR, track.tpcNClsFound()); + histos.fill(HIST("C/global/hSeconds2DNumClsTpc"), secFromSOR, track.tpcNClsFound()); + histos.fill(HIST("C/global/hSecondsChi2NClTpc"), secFromSOR, track.tpcChi2NCl()); + if (track.tpcNClsFound() >= confCutOnNtpcClsForSharedFractAndDeDxCalc) { + histos.fill(HIST("C/global/hSecondsTpcFractionSharedCls"), secFromSOR, track.tpcFractionSharedCls()); + histos.fill(HIST("C/global/hSeconds2DTpcFractionSharedCls"), secFromSOR, track.tpcFractionSharedCls()); + if (dedx < 1.e4) // protection from weird values + histos.fill(HIST("C/global/hSecondsDeDx"), secFromSOR, dedx); + } + + if (track.isPVContributor()) { + histos.fill(HIST("C/globalPV/hDcaRafterCuts"), dcaR); + histos.fill(HIST("C/globalPV/hDcaZafterCuts"), dcaZ); + + histos.fill(HIST("C/globalPV/hSecondsNumPVcontributors"), secFromSOR); + histos.fill(HIST("C/globalPV/hSecondsSumDcaR"), secFromSOR, dcaRabs); + histos.fill(HIST("C/globalPV/hSecondsSumDcaZ"), secFromSOR, dcaZabs); + histos.fill(HIST("C/globalPV/hSecondsSumPt"), secFromSOR, track.pt()); + histos.fill(HIST("C/globalPV/hSecondsNumClsIts"), secFromSOR, track.itsNCls()); + histos.fill(HIST("C/globalPV/hSeconds2DNumClsIts"), secFromSOR, track.itsNCls()); + histos.fill(HIST("C/globalPV/hSecondsChi2NClIts"), secFromSOR, track.itsChi2NCl()); + histos.fill(HIST("C/globalPV/hSecondsNumClsTpc"), secFromSOR, track.tpcNClsFound()); + histos.fill(HIST("C/globalPV/hSeconds2DNumClsTpc"), secFromSOR, track.tpcNClsFound()); + histos.fill(HIST("C/globalPV/hSecondsChi2NClTpc"), secFromSOR, track.tpcChi2NCl()); + if (track.tpcNClsFound() >= confCutOnNtpcClsForSharedFractAndDeDxCalc) { + histos.fill(HIST("C/globalPV/hSecondsTpcFractionSharedCls"), secFromSOR, track.tpcFractionSharedCls()); + histos.fill(HIST("C/globalPV/hSeconds2DTpcFractionSharedCls"), secFromSOR, track.tpcFractionSharedCls()); + if (dedx < 1.e4) // protection from weird values + histos.fill(HIST("C/globalPV/hSecondsDeDx"), secFromSOR, dedx); + } + } + } + } // end of global tracks + + // study ITS cluster pattern vs phi vs time (pt>1 GeV/c cut selects straight tracks) + if (track.isPVContributor() && track.pt() > 1) { + // layer-by-layer check + if (confFlagFillPhiVsTimeHist == 2) { + if (track.itsClusterMap() & (1 << 0)) + histos.fill(HIST("hSecondsITSlayer0vsPhi"), secFromSOR, track.phi()); + if (track.itsClusterMap() & (1 << 1)) + histos.fill(HIST("hSecondsITSlayer1vsPhi"), secFromSOR, track.phi()); + if (track.itsClusterMap() & (1 << 2)) + histos.fill(HIST("hSecondsITSlayer2vsPhi"), secFromSOR, track.phi()); + if (track.itsClusterMap() & (1 << 3)) + histos.fill(HIST("hSecondsITSlayer3vsPhi"), secFromSOR, track.phi()); + if (track.itsClusterMap() & (1 << 4)) + histos.fill(HIST("hSecondsITSlayer4vsPhi"), secFromSOR, track.phi()); + if (track.itsClusterMap() & (1 << 5)) + histos.fill(HIST("hSecondsITSlayer5vsPhi"), secFromSOR, track.phi()); + if (track.itsClusterMap() & (1 << 6)) + histos.fill(HIST("hSecondsITSlayer6vsPhi"), secFromSOR, track.phi()); + } + // tracks with conditions + if (confFlagFillPhiVsTimeHist > 0) { + if (track.itsNCls() == 7) + histos.fill(HIST("hSecondsITS7clsVsPhi"), secFromSOR, track.phi()); + if (track.isGlobalTrack()) + histos.fill(HIST("hSecondsITSglobalVsPhi"), secFromSOR, track.phi()); + if (track.hasTRD()) + histos.fill(HIST("hSecondsITSTRDVsPhi"), secFromSOR, track.phi()); + if (track.hasTOF()) + histos.fill(HIST("hSecondsITSTOFVsPhi"), secFromSOR, track.phi()); + } + // eta-phi histogram for global tracks + if (confFlagFillEtaPhiVsTimeHist && track.isGlobalTrack()) { + histos.fill(HIST("hSecondsITSglobalVsEtaPhi"), secFromSOR, track.eta(), track.phi()); + } + } + } + } + } // end of collision loop + PROCESS_SWITCH(TimeDependentQaTask, processRun3, "Process Run3 QA vs time", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/DPG/Tasks/AOTTrack/CMakeLists.txt b/DPG/Tasks/AOTTrack/CMakeLists.txt index 91e7ad91313..9974d3d6bc2 100644 --- a/DPG/Tasks/AOTTrack/CMakeLists.txt +++ b/DPG/Tasks/AOTTrack/CMakeLists.txt @@ -13,54 +13,75 @@ add_subdirectory(PID) add_subdirectory(V0Cascades) o2physics_add_dpl_workflow(qa-trackselection - SOURCES qaTrackSelection.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) + SOURCES qaTrackSelection.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(qa-event-track - SOURCES qaEventTrack.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::ReconstructionDataFormats - COMPONENT_NAME Analysis) + SOURCES qaEventTrack.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::ReconstructionDataFormats + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(qa-event-track-lite - SOURCES qaEventTrackLite.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::ReconstructionDataFormats - COMPONENT_NAME Analysis) + SOURCES qaEventTrackLite.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::ReconstructionDataFormats + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(qa-event-track-lite-producer - SOURCES qaEventTrackLiteProducer.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::ReconstructionDataFormats - COMPONENT_NAME Analysis) + SOURCES qaEventTrackLiteProducer.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::ReconstructionDataFormats + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(qa-fakehits + SOURCES qaFakeHits.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(qa-efficiency - SOURCES qaEfficiency.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) + SOURCES qaEfficiency.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(qa-dca-mc + SOURCES qaDcaMC.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(qa-sign-charge-mc + SOURCES qaSignChargeMC.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsVertexing + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(qa-match-eff - SOURCES qaMatchEff.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) + SOURCES qaMatchEff.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(qa-impact-parameter - SOURCES qaImpPar.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - O2::ReconstructionDataFormats - O2::DetectorsCommonDataFormats - O2::DetectorsVertexing - COMPONENT_NAME Analysis) + SOURCES qaImpPar.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + O2::ReconstructionDataFormats + O2::DetectorsCommonDataFormats + O2::DetectorsVertexing + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(monitorfilterbit - SOURCES MonitorFilterBit.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) + SOURCES MonitorFilterBit.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(qa-prim-vtx-vs-time - SOURCES qaPrimVtxVsTime.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) + SOURCES qaPrimVtxVsTime.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(qa-tracksplitting + SOURCES qaTrackSplitting.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(tag-and-probe-dmesons - SOURCES tagAndProbeDmesons.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsVertexing - COMPONENT_NAME Analysis) + SOURCES tagAndProbeDmesons.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsVertexing O2Physics::MLCore + COMPONENT_NAME Analysis) + diff --git a/DPG/Tasks/AOTTrack/PID/CMakeLists.txt b/DPG/Tasks/AOTTrack/PID/CMakeLists.txt index 3736b58695d..17f77acfa59 100644 --- a/DPG/Tasks/AOTTrack/PID/CMakeLists.txt +++ b/DPG/Tasks/AOTTrack/PID/CMakeLists.txt @@ -9,54 +9,8 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. -# PID QA - -## Combined -o2physics_add_dpl_workflow(pid-with-v0s-qa - SOURCES qaPIDWithV0s.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -## TOF -o2physics_add_dpl_workflow(pid-tof-qa - SOURCES qaPIDTOF.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(pid-tof-qa-beta - SOURCES qaPIDTOFBeta.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(pid-tof-qa-mc - SOURCES qaPIDTOFMC.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(pid-tof-qa-evtime - SOURCES qaPIDTOFEvTime.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -## TPC -o2physics_add_dpl_workflow(pid-tpc-qa - SOURCES qaPIDTPC.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(pid-tpc-qa-sig - SOURCES qaPIDTPCSignal.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(pid-tpc-qa-mc - SOURCES qaPIDTPCMC.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -## HMPID -o2physics_add_dpl_workflow(pid-hmpid-qa - SOURCES qaHMPID.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - +add_subdirectory(Combined) +add_subdirectory(TOF) +add_subdirectory(TPC) +add_subdirectory(ITS) +add_subdirectory(HMPID) diff --git a/DPG/Tasks/AOTTrack/PID/Combined/CMakeLists.txt b/DPG/Tasks/AOTTrack/PID/Combined/CMakeLists.txt new file mode 100644 index 00000000000..a07c4324557 --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/Combined/CMakeLists.txt @@ -0,0 +1,16 @@ +# 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. + +# Combined +o2physics_add_dpl_workflow(pid-with-v0s-qa + SOURCES qaPIDWithV0s.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/DPG/Tasks/AOTTrack/PID/qaPIDWithV0s.cxx b/DPG/Tasks/AOTTrack/PID/Combined/qaPIDWithV0s.cxx similarity index 100% rename from DPG/Tasks/AOTTrack/PID/qaPIDWithV0s.cxx rename to DPG/Tasks/AOTTrack/PID/Combined/qaPIDWithV0s.cxx diff --git a/DPG/Tasks/AOTTrack/PID/HMPID/CMakeLists.txt b/DPG/Tasks/AOTTrack/PID/HMPID/CMakeLists.txt new file mode 100644 index 00000000000..763c9105528 --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/HMPID/CMakeLists.txt @@ -0,0 +1,21 @@ +# 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. + +# HMPID +o2physics_add_dpl_workflow(pid-hmpid-qa + SOURCES qaHMPID.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pid-hmpid + SOURCES analysisHMPID.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/DPG/Tasks/AOTTrack/PID/HMPID/analysisHMPID.cxx b/DPG/Tasks/AOTTrack/PID/HMPID/analysisHMPID.cxx new file mode 100644 index 00000000000..c5a6b9d0597 --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/HMPID/analysisHMPID.cxx @@ -0,0 +1,137 @@ +// 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. + +// O2 includes +#include "ReconstructionDataFormats/Track.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "ReconstructionDataFormats/TrackParametrization.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/PID/PIDTOF.h" +#include "Common/TableProducer/PID/pidTOFBase.h" +#include "ReconstructionDataFormats/PID.h" +#include "Common/Core/trackUtilities.h" +#include "ReconstructionDataFormats/DCA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/ASoA.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace o2::aod +{ + +namespace variables_table // declaration of columns to create +{ +DECLARE_SOA_COLUMN(ChAngle, chAngle, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(MomentumHMPID, momentumHMPID, float); +DECLARE_SOA_COLUMN(MomentumTrack, momentumTrack, float); +DECLARE_SOA_COLUMN(Xtrack, xtrack, float); +DECLARE_SOA_COLUMN(Ytrack, ytrack, float); +DECLARE_SOA_COLUMN(Xmip, xmip, float); +DECLARE_SOA_COLUMN(Ymip, ymip, float); +DECLARE_SOA_COLUMN(Nphotons, nphotons, float); +DECLARE_SOA_COLUMN(ChargeMIP, chargeMIP, float); +DECLARE_SOA_COLUMN(ClusterSize, clustersize, float); +DECLARE_SOA_COLUMN(Chamber, chamber, float); +DECLARE_SOA_COLUMN(Photons_charge, photons_charge, float[10]); + +DECLARE_SOA_COLUMN(EtaTrack, etatrack, float); +DECLARE_SOA_COLUMN(PhiTrack, phitrack, float); + +DECLARE_SOA_COLUMN(ITSNcluster, itsNcluster, float); +DECLARE_SOA_COLUMN(TPCNcluster, tpcNcluster, float); +DECLARE_SOA_COLUMN(TPCNClsCrossedRows, tpcNClsCrossedRows, float); +DECLARE_SOA_COLUMN(TPCchi2, tpcChi2, float); +DECLARE_SOA_COLUMN(ITSchi2, itsChi2, float); + +DECLARE_SOA_COLUMN(DCAxy, dcaxy, float); +DECLARE_SOA_COLUMN(DCAz, dcaz, float); + +DECLARE_SOA_COLUMN(TPCNSigmaPi, tpcNsigmaPi, float); +DECLARE_SOA_COLUMN(TOFNSigmaPi, tofNsigmaPi, float); +DECLARE_SOA_COLUMN(TPCNSigmaKa, tpcNsigmaKa, float); +DECLARE_SOA_COLUMN(TOFNSigmaKa, tofNsigmaKa, float); +DECLARE_SOA_COLUMN(TPCNSigmaPr, tpcNsigmaPr, float); +DECLARE_SOA_COLUMN(TOFNSigmaPr, tofNsigmaPr, float); +DECLARE_SOA_COLUMN(TPCNSigmaDe, tpcNsigmaDe, float); +DECLARE_SOA_COLUMN(TOFNSigmaDe, tofNsigmaDe, float); + +} // namespace variables_table + +DECLARE_SOA_TABLE(HMPID_analysis, "AOD", "HMPIDANALYSIS", + variables_table::ChAngle, variables_table::Phi, variables_table::Eta, variables_table::MomentumHMPID, + variables_table::MomentumTrack, variables_table::Xtrack, variables_table::Ytrack, variables_table::Xmip, + variables_table::Ymip, variables_table::Nphotons, variables_table::ChargeMIP, variables_table::ClusterSize, + variables_table::Chamber, variables_table::Photons_charge, variables_table::EtaTrack, variables_table::PhiTrack, + variables_table::ITSNcluster, variables_table::TPCNcluster, variables_table::TPCNClsCrossedRows, + variables_table::TPCchi2, variables_table::ITSchi2, variables_table::DCAxy, variables_table::DCAz, + variables_table::TPCNSigmaPi, variables_table::TOFNSigmaPi, variables_table::TPCNSigmaKa, variables_table::TOFNSigmaKa, + variables_table::TPCNSigmaPr, variables_table::TOFNSigmaPr, variables_table::TPCNSigmaDe, variables_table::TOFNSigmaDe); +} // namespace o2::aod + +struct pidHmpidAnalysis { + + Produces HMPID_analysis; + + // using TrackCandidates = soa::Join; + + using CollisionCandidates = o2::soa::Join; + + using TrackCandidates = soa::Join; + + void process(const aod::HMPIDs& hmpids, + TrackCandidates const&, + CollisionCandidates const&) + { + + for (const auto& t : hmpids) { + if (t.track_as().isGlobalTrack() != (uint8_t) true) { + continue; + } + + const auto& track = t.track_as(); + + if (!track.hasITS() || !track.hasTPC() || !track.hasTOF()) { + continue; + } + + float hmpidPhotsCharge2[10]; + + for (int i = 0; i < 10; i++) { + hmpidPhotsCharge2[i] = t.hmpidPhotsCharge()[i]; + } + + /////FILL TABLE + HMPID_analysis(t.hmpidSignal(), t.track_as().phi(), t.track_as().eta(), t.hmpidMom(), + track.p(), t.hmpidXTrack(), t.hmpidYTrack(), t.hmpidXMip(), + t.hmpidYMip(), t.hmpidNPhotons(), t.hmpidQMip(), (t.hmpidClusSize() % 1000000) / 1000, t.hmpidClusSize() / 1000000, + hmpidPhotsCharge2, track.eta(), track.phi(), track.itsNCls(), track.tpcNClsFound(), track.tpcNClsCrossedRows(), + track.tpcChi2NCl(), track.itsChi2NCl(), track.dcaXY(), track.dcaZ(), + track.tpcNSigmaPi(), track.tofNSigmaPi(), track.tpcNSigmaKa(), track.tofNSigmaKa(), + track.tpcNSigmaPr(), track.tofNSigmaPr(), track.tpcNSigmaDe(), track.tofNSigmaDe()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfg) { return WorkflowSpec{adaptAnalysisTask(cfg)}; } diff --git a/DPG/Tasks/AOTTrack/PID/HMPID/qaHMPID.cxx b/DPG/Tasks/AOTTrack/PID/HMPID/qaHMPID.cxx new file mode 100644 index 00000000000..a4e01d6a980 --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/HMPID/qaHMPID.cxx @@ -0,0 +1,311 @@ +// 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. + +// O2 includes +#include "ReconstructionDataFormats/Track.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "ReconstructionDataFormats/TrackParametrization.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/PID/PIDTOF.h" +#include "Common/TableProducer/PID/pidTOFBase.h" +#include "ReconstructionDataFormats/PID.h" +#include "Common/Core/trackUtilities.h" +#include "ReconstructionDataFormats/DCA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/ASoA.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace o2::aod +{ + +namespace variables_table // declaration of columns to create +{ +DECLARE_SOA_COLUMN(ChAngle, chAngle, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(MomHMPID, momMPID, float); +DECLARE_SOA_COLUMN(MomTrackX, momTrackX, float); +DECLARE_SOA_COLUMN(MomTrackY, momTrackY, float); +DECLARE_SOA_COLUMN(MomTrackZ, momTrackZ, float); +DECLARE_SOA_COLUMN(Xtrack, xtrack, float); +DECLARE_SOA_COLUMN(Ytrack, ytrack, float); +DECLARE_SOA_COLUMN(Xmip, xmip, float); +DECLARE_SOA_COLUMN(Ymip, ymip, float); +DECLARE_SOA_COLUMN(Nphotons, nphotons, float); +DECLARE_SOA_COLUMN(ChargeMIP, chargeMIP, float); +DECLARE_SOA_COLUMN(ClusterSize, clustersize, float); +DECLARE_SOA_COLUMN(Chamber, chamber, float); +DECLARE_SOA_COLUMN(Photons_charge, photons_charge, float[10]); + +DECLARE_SOA_COLUMN(EtaTrack, etatrack, float); +DECLARE_SOA_COLUMN(PhiTrack, phitrack, float); + +DECLARE_SOA_COLUMN(ITSNcluster, itsNcluster, float); +DECLARE_SOA_COLUMN(TPCNcluster, tpcNcluster, float); +DECLARE_SOA_COLUMN(TPCNClsCrossedRows, tpcNClsCrossedRows, float); +DECLARE_SOA_COLUMN(TPCchi2, tpcChi2, float); +DECLARE_SOA_COLUMN(ITSchi2, itsChi2, float); + +DECLARE_SOA_COLUMN(DCAxy, dcaxy, float); +DECLARE_SOA_COLUMN(DCAz, dcaz, float); + +} // namespace variables_table + +DECLARE_SOA_TABLE(HMPID_analysis, "AOD", "HMPIDANALYSIS", + variables_table::ChAngle, variables_table::Phi, variables_table::Eta, variables_table::MomHMPID, + variables_table::MomTrackX, variables_table::MomTrackY, variables_table::MomTrackZ, + variables_table::Xtrack, variables_table::Ytrack, variables_table::Xmip, + variables_table::Ymip, variables_table::Nphotons, variables_table::ChargeMIP, variables_table::ClusterSize, + variables_table::Chamber, variables_table::Photons_charge, variables_table::EtaTrack, variables_table::PhiTrack, + variables_table::ITSNcluster, variables_table::TPCNcluster, variables_table::TPCNClsCrossedRows, + variables_table::TPCchi2, variables_table::ITSchi2, variables_table::DCAxy, variables_table::DCAz); +} // namespace o2::aod + +struct pidHmpidQa { + + Produces HMPID_analysis; + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Configurable nBinsP{"nBinsP", 500, "Number of momentum bins"}; + Configurable minP{"minP", 0.01f, "Minimum momentum plotted (GeV/c)"}; + Configurable maxP{"maxP", 10.f, "Maximum momentum plotted (GeV/c)"}; + Configurable maxDCA{"maxDCA", 3.f, "Maximum DCA xy use for the plot (cm)"}; + Configurable maxDistance{"maxDistance", 5.f, "Maximum HMPID distance between the track and the cluster (cm)"}; + Configurable minCharge{"minCharge", 120.f, "Minimum HMPID charge collected in the cluster"}; + + void init(o2::framework::InitContext&) + { + AxisSpec momAxis{nBinsP, minP, maxP}; + + histos.add("hmpidSignal", "hmpidSignal", kTH1F, {{1000, 0, 1}}); + histos.add("hmpidMomvsTrackMom", "hmpidMomvsTrackMom", kTH2F, {{1200, 0, 30, "Track #it{p} (GeV/#it{c})"}, {1200, 0, 30, "HMP #it{p} (GeV/#it{c})"}}); + histos.add("PhivsEta", "PhivsEta", kTH2F, {{550, -0.55, 0.55, "#eta"}, {550, 0, 1.1, "#phi (rad)"}}); + histos.add("hmpidCkovvsMom", "hmpidCkovvsMom", kTH2F, {{500, 0, 10, "#it{p} (GeV/#it{c})"}, {1000, 0, 1, "Cherenkov angle (rad)"}}); + histos.add("hmpidXTrack", "hmpidXTrack", kTH1F, {{280, 0, 140, "X track (cm)"}}); + histos.add("hmpidYTrack", "hmpidYTrack", kTH1F, {{280, 0, 140, "Y track (cm)"}}); + histos.add("hmpidXMip", "hmpidXMip", kTH1F, {{280, 0, 140, "X mip (cm)"}}); + histos.add("hmpidYMip", "hmpidYMip", kTH1F, {{280, 0, 140, "X mip (cm)"}}); + histos.add("hmpidXResiduals", "hmpidXResiduals", kTH1F, {{400, -20, 20, "X Residuals (cm)"}}); + histos.add("hmpidYResiduals", "hmpidYResiduals", kTH1F, {{400, -20, 20, "Y Residuals (cm)"}}); + histos.add("hmpidNPhotons", "hmpidNPhotons", kTH1F, {{50, 0, 50, "Number of photons"}}); + histos.add("hmpidQMip", "hmpidQMip", kTH1F, {{2000, 200, 2200, "Charge (ADCD)"}}); + histos.add("hmpidClusSize", "hmpidClusSize", kTH1F, {{15, 0, 15, "MIP Cluster size"}}); + histos.add("TrackMom", "TrackMom", kTH1F, {{1200, -30, 30, "#it{p} (GeV/#it{c})"}}); + histos.add("hmpidMom", "hmpidMom", kTH1F, {{1200, -30, 30, "#it{p} (GeV/#it{c})"}}); + histos.add("hmpidPhotsCharge", "hmpidPhotsCharge", kTH1F, {{300, 0, 300}}); + for (int iCh = 0; iCh < 7; iCh++) { + histos.add(Form("hmpidXTrack%i", iCh), Form("hmpidXTrack%i", iCh), kTH1F, {{280, 0, 140, "X track (cm)"}}); + histos.add(Form("hmpidYTrack%i", iCh), Form("hmpidYTrack%i", iCh), kTH1F, {{280, 0, 140, "Y track (cm)"}}); + histos.add(Form("hmpidXMip%i", iCh), Form("hmpidXMip%i", iCh), kTH1F, {{280, 0, 140, "X mip (cm)"}}); + histos.add(Form("hmpidYMip%i", iCh), Form("hmpidYMip%i", iCh), kTH1F, {{280, 0, 140, "X mip (cm)"}}); + histos.add(Form("hmpidXResiduals%i", iCh), Form("hmpidXResiduals%i", iCh), kTH1F, {{400, -20, 20, "X Residuals (cm)"}}); + histos.add(Form("hmpidYResiduals%i", iCh), Form("hmpidYResiduals%i", iCh), kTH1F, {{400, -20, 20, "Y Residuals (cm)"}}); + histos.add(Form("hmpidNPhotons%i", iCh), Form("hmpidNPhotons%i", iCh), kTH1F, {{50, 0, 50, "Number of photons"}}); + histos.add(Form("hmpidQMip%i", iCh), Form("hmpidQMip%i", iCh), kTH1F, {{2000, 200, 2200, "Charge (ADCD)"}}); + histos.add(Form("hmpidClusSize%i", iCh), Form("hmpidClusSize%i", iCh), kTH1F, {{15, 0, 15, "MIP Cluster size"}}); + histos.add(Form("TrackMom%i", iCh), Form("TrackMom%i", iCh), kTH1F, {{1200, -30, 30, "#it{p} (GeV/#it{c})"}}); + histos.add(Form("hmpidMom%i", iCh), Form("hmpidMom%i", iCh), kTH1F, {{1200, -30, 30, "#it{p} (GeV/#it{c})"}}); + histos.add(Form("hmpidPhotsCharge%i", iCh), Form("hmpidPhotsCharge%i", iCh), kTH1F, {{300, 0, 300}}); + } + } + + using TrackCandidates = soa::Join; + + void process(const aod::HMPIDs& hmpids, + const TrackCandidates& /*tracks*/, + const aod::Collisions& /*colls*/) + + { + + for (const auto& t : hmpids) { + if (t.track_as().isGlobalTrack() != (uint8_t) true) { + continue; + } + + const auto& track = t.track_as(); + + if (!track.hasITS() || !track.hasTPC() || !track.hasTOF()) { + continue; + } + + float hmpidPhotsCharge2[10]; + + for (int i = 0; i < 10; i++) { + hmpidPhotsCharge2[i] = t.hmpidPhotsCharge()[i]; + } + + HMPID_analysis(t.hmpidSignal(), t.track_as().phi(), t.track_as().eta(), t.hmpidMom(), + track.px(), track.py(), track.pz(), t.hmpidXTrack(), t.hmpidYTrack(), t.hmpidXMip(), + t.hmpidYMip(), t.hmpidNPhotons(), t.hmpidQMip(), (t.hmpidClusSize() % 1000000) / 1000, t.hmpidClusSize() / 1000000, + hmpidPhotsCharge2, track.eta(), track.phi(), track.itsNCls(), track.tpcNClsFound(), track.tpcNClsCrossedRows(), + track.tpcChi2NCl(), track.itsChi2NCl(), track.dcaXY(), track.dcaZ()); + + histos.fill(HIST("hmpidSignal"), t.hmpidSignal()); + histos.fill(HIST("PhivsEta"), t.track_as().eta(), t.track_as().phi()); + histos.fill(HIST("hmpidMomvsTrackMom"), t.track_as().p(), std::abs(t.hmpidMom())); + histos.fill(HIST("hmpidCkovvsMom"), std::abs(t.hmpidMom()), t.hmpidSignal()); + histos.fill(HIST("hmpidXTrack"), t.hmpidXTrack()); + histos.fill(HIST("hmpidYTrack"), t.hmpidYTrack()); + histos.fill(HIST("hmpidXMip"), t.hmpidXMip()); + histos.fill(HIST("hmpidYMip"), t.hmpidYMip()); + if (t.track_as().p() > 1.5) { + histos.fill(HIST("hmpidXResiduals"), t.hmpidXMip() - t.hmpidXTrack()); + histos.fill(HIST("hmpidYResiduals"), t.hmpidYMip() - t.hmpidYTrack()); + } + histos.fill(HIST("hmpidNPhotons"), t.hmpidNPhotons()); + histos.fill(HIST("hmpidQMip"), t.hmpidQMip()); + histos.fill(HIST("hmpidClusSize"), (t.hmpidClusSize() % 1000000) / 1000); + histos.fill(HIST("TrackMom"), t.track_as().p()); + histos.fill(HIST("hmpidMom"), std::abs(t.hmpidMom())); + for (int i = 0; i < 10; i++) { + if (t.hmpidPhotsCharge()[i] > 0) + histos.fill(HIST("hmpidPhotsCharge"), t.hmpidPhotsCharge()[i]); + } + + if (t.hmpidClusSize() / 1000000 == 0) { + histos.fill(HIST("hmpidXTrack0"), t.hmpidXTrack()); + histos.fill(HIST("hmpidYTrack0"), t.hmpidYTrack()); + histos.fill(HIST("hmpidXMip0"), t.hmpidXMip()); + histos.fill(HIST("hmpidYMip0"), t.hmpidYMip()); + histos.fill(HIST("hmpidXResiduals0"), t.hmpidXMip() - t.hmpidXTrack()); + histos.fill(HIST("hmpidYResiduals0"), t.hmpidYMip() - t.hmpidYTrack()); + histos.fill(HIST("hmpidNPhotons0"), t.hmpidNPhotons()); + histos.fill(HIST("hmpidQMip0"), t.hmpidQMip()); + histos.fill(HIST("hmpidClusSize0"), (t.hmpidClusSize() % 1000000) / 1000); + histos.fill(HIST("TrackMom0"), t.track_as().p()); + histos.fill(HIST("hmpidMom0"), std::abs(t.hmpidMom())); + for (int i = 0; i < 10; i++) { + if (t.hmpidPhotsCharge()[i] > 0) + histos.fill(HIST("hmpidPhotsCharge0"), t.hmpidPhotsCharge()[i]); + } + } + + if (t.hmpidClusSize() / 1000000 == 1) { + histos.fill(HIST("hmpidXTrack1"), t.hmpidXTrack()); + histos.fill(HIST("hmpidYTrack1"), t.hmpidYTrack()); + histos.fill(HIST("hmpidXMip1"), t.hmpidXMip()); + histos.fill(HIST("hmpidYMip1"), t.hmpidYMip()); + histos.fill(HIST("hmpidXResiduals1"), t.hmpidXMip() - t.hmpidXTrack()); + histos.fill(HIST("hmpidYResiduals1"), t.hmpidYMip() - t.hmpidYTrack()); + histos.fill(HIST("hmpidNPhotons1"), t.hmpidNPhotons()); + histos.fill(HIST("hmpidQMip1"), t.hmpidQMip()); + histos.fill(HIST("hmpidClusSize1"), (t.hmpidClusSize() % 1000000) / 1000); + histos.fill(HIST("TrackMom1"), t.track_as().p()); + histos.fill(HIST("hmpidMom1"), std::abs(t.hmpidMom())); + for (int i = 0; i < 10; i++) { + if (t.hmpidPhotsCharge()[i] > 0) + histos.fill(HIST("hmpidPhotsCharge1"), t.hmpidPhotsCharge()[i]); + } + } + + if (t.hmpidClusSize() / 1000000 == 2) { + histos.fill(HIST("hmpidXTrack2"), t.hmpidXTrack()); + histos.fill(HIST("hmpidYTrack2"), t.hmpidYTrack()); + histos.fill(HIST("hmpidXMip2"), t.hmpidXMip()); + histos.fill(HIST("hmpidYMip2"), t.hmpidYMip()); + histos.fill(HIST("hmpidXResiduals2"), t.hmpidXMip() - t.hmpidXTrack()); + histos.fill(HIST("hmpidYResiduals2"), t.hmpidYMip() - t.hmpidYTrack()); + histos.fill(HIST("hmpidNPhotons2"), t.hmpidNPhotons()); + histos.fill(HIST("hmpidQMip2"), t.hmpidQMip()); + histos.fill(HIST("hmpidClusSize2"), (t.hmpidClusSize() % 1000000) / 1000); + histos.fill(HIST("TrackMom2"), t.track_as().p()); + histos.fill(HIST("hmpidMom2"), std::abs(t.hmpidMom())); + for (int i = 0; i < 10; i++) { + if (t.hmpidPhotsCharge()[i] > 0) + histos.fill(HIST("hmpidPhotsCharge2"), t.hmpidPhotsCharge()[i]); + } + } + + if (t.hmpidClusSize() / 1000000 == 3) { + histos.fill(HIST("hmpidXTrack3"), t.hmpidXTrack()); + histos.fill(HIST("hmpidYTrack3"), t.hmpidYTrack()); + histos.fill(HIST("hmpidXMip3"), t.hmpidXMip()); + histos.fill(HIST("hmpidYMip3"), t.hmpidYMip()); + histos.fill(HIST("hmpidXResiduals3"), t.hmpidXMip() - t.hmpidXTrack()); + histos.fill(HIST("hmpidYResiduals3"), t.hmpidYMip() - t.hmpidYTrack()); + histos.fill(HIST("hmpidNPhotons3"), t.hmpidNPhotons()); + histos.fill(HIST("hmpidQMip3"), t.hmpidQMip()); + histos.fill(HIST("hmpidClusSize3"), (t.hmpidClusSize() % 1000000) / 1000); + histos.fill(HIST("TrackMom3"), t.track_as().p()); + histos.fill(HIST("hmpidMom3"), std::abs(t.hmpidMom())); + for (int i = 0; i < 10; i++) { + if (t.hmpidPhotsCharge()[i] > 0) + histos.fill(HIST("hmpidPhotsCharge3"), t.hmpidPhotsCharge()[i]); + } + } + + if (t.hmpidClusSize() / 1000000 == 4) { + histos.fill(HIST("hmpidXTrack4"), t.hmpidXTrack()); + histos.fill(HIST("hmpidYTrack4"), t.hmpidYTrack()); + histos.fill(HIST("hmpidXMip4"), t.hmpidXMip()); + histos.fill(HIST("hmpidYMip4"), t.hmpidYMip()); + histos.fill(HIST("hmpidXResiduals4"), t.hmpidXMip() - t.hmpidXTrack()); + histos.fill(HIST("hmpidYResiduals4"), t.hmpidYMip() - t.hmpidYTrack()); + histos.fill(HIST("hmpidNPhotons4"), t.hmpidNPhotons()); + histos.fill(HIST("hmpidQMip4"), t.hmpidQMip()); + histos.fill(HIST("hmpidClusSize4"), (t.hmpidClusSize() % 1000000) / 1000); + histos.fill(HIST("TrackMom4"), t.track_as().p()); + histos.fill(HIST("hmpidMom4"), std::abs(t.hmpidMom())); + for (int i = 0; i < 10; i++) { + if (t.hmpidPhotsCharge()[i] > 0) + histos.fill(HIST("hmpidPhotsCharge4"), t.hmpidPhotsCharge()[i]); + } + } + + if (t.hmpidClusSize() / 1000000 == 5) { + histos.fill(HIST("hmpidXTrack5"), t.hmpidXTrack()); + histos.fill(HIST("hmpidYTrack5"), t.hmpidYTrack()); + histos.fill(HIST("hmpidXMip5"), t.hmpidXMip()); + histos.fill(HIST("hmpidYMip5"), t.hmpidYMip()); + histos.fill(HIST("hmpidXResiduals5"), t.hmpidXMip() - t.hmpidXTrack()); + histos.fill(HIST("hmpidYResiduals5"), t.hmpidYMip() - t.hmpidYTrack()); + histos.fill(HIST("hmpidNPhotons5"), t.hmpidNPhotons()); + histos.fill(HIST("hmpidQMip5"), t.hmpidQMip()); + histos.fill(HIST("hmpidClusSize5"), (t.hmpidClusSize() % 1000000) / 1000); + histos.fill(HIST("TrackMom5"), t.track_as().p()); + histos.fill(HIST("hmpidMom5"), std::abs(t.hmpidMom())); + for (int i = 0; i < 10; i++) { + if (t.hmpidPhotsCharge()[i] > 0) + histos.fill(HIST("hmpidPhotsCharge5"), t.hmpidPhotsCharge()[i]); + } + } + + if (t.hmpidClusSize() / 1000000 == 6) { + histos.fill(HIST("hmpidXTrack6"), t.hmpidXTrack()); + histos.fill(HIST("hmpidYTrack6"), t.hmpidYTrack()); + histos.fill(HIST("hmpidXMip6"), t.hmpidXMip()); + histos.fill(HIST("hmpidYMip6"), t.hmpidYMip()); + histos.fill(HIST("hmpidXResiduals6"), t.hmpidXMip() - t.hmpidXTrack()); + histos.fill(HIST("hmpidYResiduals6"), t.hmpidYMip() - t.hmpidYTrack()); + histos.fill(HIST("hmpidNPhotons6"), t.hmpidNPhotons()); + histos.fill(HIST("hmpidQMip6"), t.hmpidQMip()); + histos.fill(HIST("hmpidClusSize6"), (t.hmpidClusSize() % 1000000) / 1000); + histos.fill(HIST("TrackMom6"), t.track_as().p()); + histos.fill(HIST("hmpidMom6"), std::abs(t.hmpidMom())); + for (int i = 0; i < 10; i++) { + if (t.hmpidPhotsCharge()[i] > 0) + histos.fill(HIST("hmpidPhotsCharge6"), t.hmpidPhotsCharge()[i]); + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfg) { return WorkflowSpec{adaptAnalysisTask(cfg)}; } diff --git a/DPG/Tasks/AOTTrack/PID/ITS/CMakeLists.txt b/DPG/Tasks/AOTTrack/PID/ITS/CMakeLists.txt new file mode 100644 index 00000000000..1550742c0f4 --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/ITS/CMakeLists.txt @@ -0,0 +1,16 @@ +# 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. + +# ITS +o2physics_add_dpl_workflow(pid-its-qa + SOURCES qaPIDITS.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/DPG/Tasks/AOTTrack/PID/ITS/qaPIDITS.cxx b/DPG/Tasks/AOTTrack/PID/ITS/qaPIDITS.cxx new file mode 100644 index 00000000000..c93d5980498 --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/ITS/qaPIDITS.cxx @@ -0,0 +1,349 @@ +// 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 qaPIDITS.cxx +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Implementation for QA tasks of the ITS PID quantities +/// + +#include +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StaticFor.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::track; + +static constexpr int nParameters = 1; +static const std::vector tableNames{"Electron", // 0 + "Muon", // 1 + "Pion", // 2 + "Kaon", // 3 + "Proton", // 4 + "Deuteron", // 5 + "Triton", // 6 + "Helium", // 7 + "Alpha"}; // 8 +static const std::vector parameterNames{"enable"}; +static const std::vector selectionNames{"selection"}; +static const int defaultParameters[9][nParameters]{{0}, {0}, {1}, {1}, {1}, {0}, {0}, {0}, {0}}; +static const float defaultPIDSelection[9][nParameters]{{-1.f}, {-1.f}, {-1.f}, {-1.f}, {-1.f}, {-1.f}, {-1.f}, {-1.f}, {-1.f}}; +static constexpr int Np = 9; +bool enableParticle[Np] = {false, false, false, + false, false, false, + false, false, false}; +std::array, Np> hNsigmaPos; +std::array, Np> hNsigmaNeg; + +template +float nsigmaITS(const TrackType& track, const o2::track::PID::ID id) +{ + switch (id) { + case o2::track::PID::Electron: + return track.itsNSigmaEl(); + case o2::track::PID::Muon: + return track.itsNSigmaMu(); + case o2::track::PID::Pion: + return track.itsNSigmaPi(); + case o2::track::PID::Kaon: + return track.itsNSigmaKa(); + case o2::track::PID::Proton: + return track.itsNSigmaPr(); + case o2::track::PID::Deuteron: + return track.itsNSigmaDe(); + case o2::track::PID::Triton: + return track.itsNSigmaTr(); + case o2::track::PID::Helium3: + return track.itsNSigmaHe(); + case o2::track::PID::Alpha: + return track.itsNSigmaAl(); + default: + LOG(fatal) << "PID not implemented"; + return 0.f; + } +} +template +float nsigmaTOF(const TrackType& track, const o2::track::PID::ID id) +{ + switch (id) { + case o2::track::PID::Electron: + return track.tofNSigmaEl(); + case o2::track::PID::Muon: + return track.tofNSigmaMu(); + case o2::track::PID::Pion: + return track.tofNSigmaPi(); + case o2::track::PID::Kaon: + return track.tofNSigmaKa(); + case o2::track::PID::Proton: + return track.tofNSigmaPr(); + case o2::track::PID::Deuteron: + return track.tofNSigmaDe(); + case o2::track::PID::Triton: + return track.tofNSigmaTr(); + case o2::track::PID::Helium3: + return track.tofNSigmaHe(); + case o2::track::PID::Alpha: + return track.tofNSigmaAl(); + default: + LOG(fatal) << "PID not implemented"; + return 0.f; + } +} +template +float nsigmaTPC(const TrackType& track, const o2::track::PID::ID id) +{ + switch (id) { + case o2::track::PID::Electron: + return track.tpcNSigmaEl(); + case o2::track::PID::Muon: + return track.tpcNSigmaMu(); + case o2::track::PID::Pion: + return track.tpcNSigmaPi(); + case o2::track::PID::Kaon: + return track.tpcNSigmaKa(); + case o2::track::PID::Proton: + return track.tpcNSigmaPr(); + case o2::track::PID::Deuteron: + return track.tpcNSigmaDe(); + case o2::track::PID::Triton: + return track.tpcNSigmaTr(); + case o2::track::PID::Helium3: + return track.tpcNSigmaHe(); + case o2::track::PID::Alpha: + return track.tpcNSigmaAl(); + default: + LOG(fatal) << "PID not implemented"; + return 0.f; + } +} + +float tpcSelValues[9]; +float tofSelValues[9]; + +/// Task to produce the ITS QA plots +struct itsPidQa { + static constexpr const char* pT[Np] = {"e", "#mu", "#pi", "K", "p", "d", "t", "^{3}He", "#alpha"}; + static constexpr const char* pN[Np] = {"El", "Mu", "Pi", "Ka", "Pr", "De", "Tr", "He", "Al"}; + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Configurable> enabledParticle{"enabledParticle", + {defaultParameters[0], 9, nParameters, tableNames, parameterNames}, + "Produce QA for this species: 0 - no, 1 - yes"}; + Configurable> tofSelection{"tofSelection", + {defaultPIDSelection[0], 9, nParameters, tableNames, selectionNames}, + "Selection on the TOF nsigma"}; + Configurable> tpcSelection{"tpcSelection", + {defaultPIDSelection[0], 9, nParameters, tableNames, selectionNames}, + "Selection on the TPC nsigma"}; + + Configurable logAxis{"logAxis", 1, "Flag to use a log momentum axis"}; + Configurable nBinsP{"nBinsP", 3000, "Number of bins for the momentum"}; + Configurable minP{"minP", 0.01, "Minimum momentum in range"}; + Configurable maxP{"maxP", 20, "Maximum momentum in range"}; + ConfigurableAxis etaBins{"etaBins", {100, -1.f, 1.f}, "Binning in eta"}; + ConfigurableAxis phiBins{"phiBins", {100, 0, TMath::TwoPi()}, "Binning in phi"}; + ConfigurableAxis trackLengthBins{"trackLengthBins", {100, 0, 1000.f}, "Binning in track length plot"}; + ConfigurableAxis deltaBins{"deltaBins", {200, -1000.f, 1000.f}, "Binning in Delta (dEdx - expected dEdx)"}; + ConfigurableAxis expSigmaBins{"expSigmaBins", {200, 0.f, 200.f}, "Binning in expected Sigma"}; + ConfigurableAxis nSigmaBins{"nSigmaBins", {401, -10.025f, 10.025f}, "Binning in NSigma"}; + ConfigurableAxis avClsBins{"avClsBins", {200, 0, 20}, "Binning in average cluster size"}; + Configurable trackSelection{"trackSelection", 1, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; + Configurable applyRapidityCut{"applyRapidityCut", false, "Flag to apply rapidity cut"}; + Configurable minTPCNcls{"minTPCNcls", 0, "Minimum number or TPC Clusters for tracks"}; + ConfigurableAxis tpcNclsBins{"tpcNclsBins", {16, 0, 160}, "Binning in number of clusters in TPC"}; + + template + float averageClusterSizeTrk(const TrackType& track) + { + return o2::aod::ITSResponse::averageClusterSize(track.itsClusterSizes()); + } + + float averageClusterSizePerCoslInv(uint32_t itsClusterSizes, float eta) { return o2::aod::ITSResponse::averageClusterSize(itsClusterSizes) * std::cosh(eta); } + + template + float averageClusterSizePerCoslInv(const TrackType& track) + { + return averageClusterSizePerCoslInv(track.itsClusterSizes(), track.eta()); + } + + void init(o2::framework::InitContext&) + { + const AxisSpec vtxZAxis{100, -20, 20, "Vtx_{z} (cm)"}; + const AxisSpec etaAxis{etaBins, "#it{#eta}"}; + const AxisSpec phiAxis{phiBins, "#it{#phi}"}; + const AxisSpec lAxis{trackLengthBins, "Track length (cm)"}; + AxisSpec ptAxis{nBinsP, minP, maxP, "#it{p}_{T}/|Z| (GeV/#it{c})"}; + AxisSpec pAxis{nBinsP, minP, maxP, "#it{p}/|Z| (GeV/#it{c})"}; + if (logAxis) { + ptAxis.makeLogarithmic(); + pAxis.makeLogarithmic(); + } + const AxisSpec avClsAxis{avClsBins, ""}; + const AxisSpec avClsEffAxis{avClsBins, " / cosh(#eta)"}; + + // Event properties + auto h = histos.add("event/evsel", "", kTH1D, {{10, 0.5, 10.5, "Ev. Sel."}}); + h->GetXaxis()->SetBinLabel(1, "Events read"); + h->GetXaxis()->SetBinLabel(2, "Passed ev. sel."); + h->GetXaxis()->SetBinLabel(3, "Passed vtx Z"); + + h = histos.add("event/trackselection", "", kTH1D, {{10, 0.5, 10.5, "Selection passed"}}); + h->GetXaxis()->SetBinLabel(1, "Tracks read"); + h->GetXaxis()->SetBinLabel(2, "isGlobalTrack"); + h->GetXaxis()->SetBinLabel(3, "hasITS"); + h->GetXaxis()->SetBinLabel(4, "hasTPC"); + h->GetXaxis()->SetBinLabel(5, Form("tpcNClsFound > %i", minTPCNcls.value)); + + histos.add("event/vertexz", "", kTH1D, {vtxZAxis}); + h = histos.add("event/particlehypo", "", kTH1D, {{10, 0, 10, "PID in tracking"}}); + for (int id = 0; id < 9; id++) { + h->GetXaxis()->SetBinLabel(id + 1, PID::getName(id)); + tpcSelValues[id] = tpcSelection->get(tableNames[id].c_str(), "selection"); + if (tpcSelValues[id] <= 0.f) { + tpcSelValues[id] = 999.f; + } + tofSelValues[id] = tofSelection->get(tableNames[id].c_str(), "selection"); + if (tofSelValues[id] <= 0.f) { + tofSelValues[id] = 999.f; + } + } + histos.add("event/eta", "", kTH1D, {etaAxis}); + histos.add("event/phi", "", kTH1D, {phiAxis}); + histos.add("event/etaphi", "", kTH2F, {etaAxis, phiAxis}); + histos.add("event/length", "", kTH1D, {lAxis}); + histos.add("event/pt", "", kTH1D, {ptAxis}); + histos.add("event/p", "", kTH1D, {pAxis}); + + for (int id = 0; id < 9; id++) { + const int f = enabledParticle->get(tableNames[id].c_str(), "enable"); + if (f != 1) { + continue; + } + // NSigma + const char* axisTitle = Form("N_{#sigma}^{ITS}(%s)", pT[id]); + const AxisSpec nSigmaAxis{nSigmaBins, axisTitle}; + enableParticle[id] = true; + hNsigmaPos[id] = histos.add(Form("nsigmaPos/%s", pN[id]), axisTitle, kTH2F, {pAxis, nSigmaAxis}); + hNsigmaNeg[id] = histos.add(Form("nsigmaNeg/%s", pN[id]), axisTitle, kTH2F, {pAxis, nSigmaAxis}); + } + histos.add("event/averageClusterSize", "", kTH2D, {pAxis, avClsAxis}); + histos.add("event/averageClusterSizePerCoslInv", "", kTH2D, {pAxis, avClsEffAxis}); + histos.add("event/SelectedAverageClusterSize", "", kTH2D, {pAxis, avClsAxis}); + histos.add("event/SelectedAverageClusterSizePerCoslInv", "", kTH2D, {pAxis, avClsEffAxis}); + LOG(info) << "QA PID ITS histograms:"; + histos.print(); + } + + Filter eventFilter = (o2::aod::evsel::sel8 == true && nabs(o2::aod::collision::posZ) < 10.f); + // Filter trackFilter = (requireGlobalTrackInFilter()); + using CollisionCandidate = soa::Filtered>::iterator; + using TrackCandidates = soa::Join; + void process(CollisionCandidate const& collision, + TrackCandidates const& tracks) + { + auto tracksWithPid = soa::Attach(tracks); + + if (tracks.size() != tracksWithPid.size()) { + LOG(fatal) << "Mismatch in track table size!" << tracks.size() << " vs " << tracksWithPid.size(); + } + histos.fill(HIST("event/evsel"), 1); + histos.fill(HIST("event/evsel"), 2); + histos.fill(HIST("event/evsel"), 3); + histos.fill(HIST("event/vertexz"), collision.posZ()); + + for (const auto& track : tracksWithPid) { + histos.fill(HIST("event/trackselection"), 1.f); + if (!track.isGlobalTrack()) { // Skipping non global tracks + continue; + } + histos.fill(HIST("event/trackselection"), 2.f); + if (!track.hasITS()) { // Skipping tracks without ITS + continue; + } + histos.fill(HIST("event/trackselection"), 3.f); + if (!track.hasTPC()) { // Skipping tracks without TPC + continue; + } + histos.fill(HIST("event/trackselection"), 4.f); + if (track.tpcNClsFound() < minTPCNcls) { // Skipping tracks without enough TPC clusters + continue; + } + + histos.fill(HIST("event/trackselection"), 5.f); + histos.fill(HIST("event/particlehypo"), track.pidForTracking()); + histos.fill(HIST("event/eta"), track.eta()); + histos.fill(HIST("event/phi"), track.phi()); + histos.fill(HIST("event/etaphi"), track.eta(), track.phi()); + histos.fill(HIST("event/length"), track.length()); + histos.fill(HIST("event/pt"), track.pt()); + histos.fill(HIST("event/p"), track.p()); + histos.fill(HIST("event/averageClusterSize"), track.p(), averageClusterSizeTrk(track)); + histos.fill(HIST("event/averageClusterSizePerCoslInv"), track.p(), averageClusterSizePerCoslInv(track)); + bool discard = false; + for (int id = 0; id < 9; id++) { + if (std::abs(nsigmaTPC(track, id)) > tpcSelValues[id]) { + LOG(debug) << "Discarding based on TPC hypothesis " << id << " " << std::abs(nsigmaTPC(track, id)) << ">" << tpcSelValues[id]; + discard = true; + break; + } + if (track.hasTOF()) { + if (std::abs(nsigmaTOF(track, id)) > tofSelValues[id]) { + LOG(debug) << "Discarding based on TOF hypothesis " << id << " " << std::abs(nsigmaTOF(track, id)) << ">" << tofSelValues[id]; + discard = true; + break; + } + } + } + if (discard) { + continue; + } + histos.fill(HIST("event/SelectedAverageClusterSize"), track.p(), averageClusterSizeTrk(track)); + histos.fill(HIST("event/SelectedAverageClusterSizePerCoslInv"), track.p(), averageClusterSizePerCoslInv(track)); + + for (o2::track::PID::ID id = 0; id <= o2::track::PID::Last; id++) { + if (!enableParticle[id]) { + continue; + } + if (applyRapidityCut) { + if (std::abs(track.rapidity(PID::getMass(id))) > 0.5) { + continue; + } + } + const float nsigma = nsigmaITS(track, id); + if (track.sign() > 0) { + hNsigmaPos[id]->Fill(track.pt(), nsigma); + } else { + hNsigmaNeg[id]->Fill(track.pt(), nsigma); + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/DPG/Tasks/AOTTrack/PID/TOF/CMakeLists.txt b/DPG/Tasks/AOTTrack/PID/TOF/CMakeLists.txt new file mode 100644 index 00000000000..f4f799d4f5b --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/TOF/CMakeLists.txt @@ -0,0 +1,31 @@ +# 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. + +# TOF +o2physics_add_dpl_workflow(pid-tof-qa + SOURCES qaPIDTOF.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pid-tof-qa-beta + SOURCES qaPIDTOFBeta.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pid-tof-qa-mc + SOURCES qaPIDTOFMC.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pid-tof-qa-evtime + SOURCES qaPIDTOFEvTime.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/DPG/Tasks/AOTTrack/PID/qaPIDTOF.cxx b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOF.cxx similarity index 96% rename from DPG/Tasks/AOTTrack/PID/qaPIDTOF.cxx rename to DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOF.cxx index 8c1aeca6483..24e5a09a21a 100644 --- a/DPG/Tasks/AOTTrack/PID/qaPIDTOF.cxx +++ b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOF.cxx @@ -137,6 +137,8 @@ struct tofPidQa { Configurable splitSignalPerCharge{"splitSignalPerCharge", true, "Split the signal per charge (reduces memory footprint if off)"}; Configurable enableVsMomentumHistograms{"enableVsMomentumHistograms", false, "Enables plots vs momentum instead of just pT (reduces memory footprint if off)"}; Configurable requireGoodMatchTracks{"requireGoodMatchTracks", false, "Require good match tracks"}; + Configurable pvContributorsMin{"pvContributorsMin", -10, "Minimum pvContributors"}; + Configurable pvContributorsMax{"pvContributorsMax", 10000, "Maximum pvContributors"}; template void initPerParticle(const AxisSpec& pAxis, @@ -260,6 +262,7 @@ struct tofPidQa { { const AxisSpec multAxis{100, 0, 100, "TOF multiplicity"}; const AxisSpec vtxZAxis{100, -20, 20, "Vtx_{z} (cm)"}; + const AxisSpec contributorsAxis{100, 0, 1000, "PV contributors"}; const AxisSpec etaAxis{etaBins, "#it{#eta}"}; const AxisSpec phiAxis{phiBins, "#it{#phi}"}; const AxisSpec colTimeAxis{100, -2000, 2000, "Collision time (ps)"}; @@ -282,6 +285,8 @@ struct tofPidQa { h->GetXaxis()->SetBinLabel(1, "Events read"); h->GetXaxis()->SetBinLabel(2, "Passed ev. sel."); h->GetXaxis()->SetBinLabel(3, "Passed vtx Z"); + h->GetXaxis()->SetBinLabel(4, Form("Passed pvContributorsMin %f", pvContributorsMin.value)); + h->GetXaxis()->SetBinLabel(5, Form("Passed pvContributorsMax %f", pvContributorsMax.value)); h = histos.add("event/trackselection", "", kTH1D, {{10, 0.5, 10.5, "Selection passed"}}); h->GetXaxis()->SetBinLabel(1, "Tracks read"); @@ -291,6 +296,7 @@ struct tofPidQa { h->GetXaxis()->SetBinLabel(5, "hasTOF"); h->GetXaxis()->SetBinLabel(6, "goodTOFMatch"); + histos.add("event/pvcontributors", "", kTH1D, {contributorsAxis}); histos.add("event/vertexz", "", kTH1D, {vtxZAxis}); h = histos.add("event/particlehypo", "", kTH1D, {{10, 0, 10, "PID in tracking"}}); for (int i = 0; i < 9; i++) { @@ -375,11 +381,31 @@ struct tofPidQa { } } } - if (abs(collision.posZ()) > 10.f) { + if (std::abs(collision.posZ()) > 10.f) { return false; } + // Count the number of contributors + int pvContributors = 0; + for (const auto& trk : tracks) { + if (trk.isPVContributor()) { + pvContributors++; + } + } + histos.fill(HIST("event/pvcontributors"), pvContributors); + if (pvContributors < pvContributorsMin) { + return false; + } + if constexpr (fillHistograms) { + histos.fill(HIST("event/evsel"), 4); + } + if (pvContributors > pvContributorsMax) { + return false; + } + if constexpr (fillHistograms) { + histos.fill(HIST("event/evsel"), 5); + } if constexpr (fillHistograms) { - histos.fill(HIST("event/evsel"), 3); + histos.fill(HIST("event/evsel"), 6); histos.fill(HIST("event/vertexz"), collision.posZ()); histos.fill(HIST("event/evtime/colltime"), collision.collisionTime() * 1000.f); @@ -505,7 +531,7 @@ struct tofPidQa { } if (applyRapidityCut) { - if (abs(t.rapidity(PID::getMass(id))) > 0.5) { + if (std::abs(t.rapidity(PID::getMass(id))) > 0.5) { continue; } } diff --git a/DPG/Tasks/AOTTrack/PID/qaPIDTOFBeta.cxx b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFBeta.cxx similarity index 84% rename from DPG/Tasks/AOTTrack/PID/qaPIDTOFBeta.cxx rename to DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFBeta.cxx index a550dfbd120..60ad0a9ab38 100644 --- a/DPG/Tasks/AOTTrack/PID/qaPIDTOFBeta.cxx +++ b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFBeta.cxx @@ -48,6 +48,8 @@ struct tofPidBetaQa { ConfigurableAxis tofBetaBins{"tofBetaBins", {4000, 0, 2.f}, "Binning in the TOF beta plot"}; ConfigurableAxis trackLengthBins{"trackLengthBins", {100, 0, 1000.f}, "Binning in track length plot"}; Configurable requireGoodMatchTracks{"requireGoodMatchTracks", false, "Require good match tracks"}; + Configurable mMaxTOFChi2{"maxTOFChi2", 3.f, "Maximum TOF Chi2"}; + Configurable mEtaWindow{"etaWindow", 0.8f, "Window in eta for tracks"}; void init(o2::framework::InitContext&) { @@ -61,7 +63,7 @@ struct tofPidBetaQa { const AxisSpec lAxis{trackLengthBins, "Track length (cm)"}; const AxisSpec tofChi2Axis{1000, 0, 20, "TOF residual (cm)"}; const AxisSpec ptResoAxis{100, 0, 0.1, "#sigma_{#it{p}_{T}}"}; - const AxisSpec pAxisPosNeg{2 * nBinsP, -maxP, maxP, "#it{p}/z (GeV/#it{c})"}; + const AxisSpec pAxisPosNeg{2 * nBinsP, -maxP, maxP, "signed #it{p} (GeV/#it{c})"}; AxisSpec ptAxis{nBinsP, minP, maxP, "#it{p}_{T} (GeV/#it{c})"}; AxisSpec pAxis{nBinsP, minP, maxP, "#it{p} (GeV/#it{c})"}; if (logAxis) { @@ -126,51 +128,51 @@ struct tofPidBetaQa { // TOF beta if (splitSignalPerCharge) { - histos.add("tofbeta/inclusive", "", HistType::kTH3F, {pAxisPosNeg, betaAxis, chargeAxis}); + histos.add("tofbeta/inclusive", "", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); if (splitSignalPerEvTime) { - histos.add("tofbeta/EvTimeTOF", "Ev. Time TOF", HistType::kTH3F, {pAxisPosNeg, betaAxis, chargeAxis}); - histos.add("tofbeta/EvTimeTOFOnly", "Ev. Time TOF Only", HistType::kTH3F, {pAxisPosNeg, betaAxis, chargeAxis}); - histos.add("tofbeta/EvTimeT0AC", "Ev. Time T0AC", HistType::kTH3F, {pAxisPosNeg, betaAxis, chargeAxis}); - histos.add("tofbeta/EvTimeT0ACOnly", "Ev. Time T0AC Only", HistType::kTH3F, {pAxisPosNeg, betaAxis, chargeAxis}); + histos.add("tofbeta/EvTimeTOF", "Ev. Time TOF", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/EvTimeTOFOnly", "Ev. Time TOF Only", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/EvTimeT0AC", "Ev. Time T0AC", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/EvTimeT0ACOnly", "Ev. Time T0AC Only", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); } if (splitTrdTracks) { - histos.add("tofbeta/trd/inclusive", "(hasTRD)", HistType::kTH3F, {pAxisPosNeg, betaAxis, chargeAxis}); + histos.add("tofbeta/trd/inclusive", "(hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); if (splitSignalPerEvTime) { - histos.add("tofbeta/trd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH3F, {pAxisPosNeg, betaAxis, chargeAxis}); - histos.add("tofbeta/trd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH3F, {pAxisPosNeg, betaAxis, chargeAxis}); - histos.add("tofbeta/trd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH3F, {pAxisPosNeg, betaAxis, chargeAxis}); - histos.add("tofbeta/trd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH3F, {pAxisPosNeg, betaAxis, chargeAxis}); + histos.add("tofbeta/trd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/trd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/trd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/trd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); } - histos.add("tofbeta/notrd/inclusive", "(hasTRD)", HistType::kTH3F, {pAxisPosNeg, betaAxis, chargeAxis}); + histos.add("tofbeta/notrd/inclusive", "(hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); if (splitSignalPerEvTime) { - histos.add("tofbeta/notrd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH3F, {pAxisPosNeg, betaAxis, chargeAxis}); - histos.add("tofbeta/notrd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH3F, {pAxisPosNeg, betaAxis, chargeAxis}); - histos.add("tofbeta/notrd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH3F, {pAxisPosNeg, betaAxis, chargeAxis}); - histos.add("tofbeta/notrd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH3F, {pAxisPosNeg, betaAxis, chargeAxis}); + histos.add("tofbeta/notrd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/notrd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/notrd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/notrd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); } } } else { - histos.add("tofbeta/inclusive", "", HistType::kTH2F, {pAxis, betaAxis}); + histos.add("tofbeta/inclusive", "", HistType::kTH2F, {pAxisPosNeg, betaAxis}); if (splitSignalPerEvTime) { - histos.add("tofbeta/EvTimeTOF", "Ev. Time TOF", HistType::kTH2F, {pAxis, betaAxis}); - histos.add("tofbeta/EvTimeTOFOnly", "Ev. Time TOF Only", HistType::kTH2F, {pAxis, betaAxis}); - histos.add("tofbeta/EvTimeT0AC", "Ev. Time T0AC", HistType::kTH2F, {pAxis, betaAxis}); - histos.add("tofbeta/EvTimeT0ACOnly", "Ev. Time T0AC Only", HistType::kTH2F, {pAxis, betaAxis}); + histos.add("tofbeta/EvTimeTOF", "Ev. Time TOF", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/EvTimeTOFOnly", "Ev. Time TOF Only", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/EvTimeT0AC", "Ev. Time T0AC", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/EvTimeT0ACOnly", "Ev. Time T0AC Only", HistType::kTH2F, {pAxisPosNeg, betaAxis}); } if (splitTrdTracks) { - histos.add("tofbeta/trd/inclusive", "(hasTRD)", HistType::kTH2F, {pAxis, betaAxis}); + histos.add("tofbeta/trd/inclusive", "(hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); if (splitSignalPerEvTime) { - histos.add("tofbeta/trd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH2F, {pAxis, betaAxis}); - histos.add("tofbeta/trd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH2F, {pAxis, betaAxis}); - histos.add("tofbeta/trd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH2F, {pAxis, betaAxis}); - histos.add("tofbeta/trd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH2F, {pAxis, betaAxis}); + histos.add("tofbeta/trd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/trd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/trd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/trd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); } - histos.add("tofbeta/notrd/inclusive", "(hasTRD)", HistType::kTH2F, {pAxis, betaAxis}); + histos.add("tofbeta/notrd/inclusive", "(hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); if (splitSignalPerEvTime) { - histos.add("tofbeta/notrd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH2F, {pAxis, betaAxis}); - histos.add("tofbeta/notrd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH2F, {pAxis, betaAxis}); - histos.add("tofbeta/notrd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH2F, {pAxis, betaAxis}); - histos.add("tofbeta/notrd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH2F, {pAxis, betaAxis}); + histos.add("tofbeta/notrd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/notrd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/notrd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/notrd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); } } } @@ -193,7 +195,7 @@ struct tofPidBetaQa { h->GetXaxis()->SetBinLabel(1, "Tracks read"); h->GetXaxis()->SetBinLabel(2, "hasTOF"); h->GetXaxis()->SetBinLabel(3, "isGlobalTrack"); - h->GetXaxis()->SetBinLabel(4, "goodTOFMatch"); + h->GetXaxis()->SetBinLabel(4, TString::Format("TOF chi2 < %.2f", mMaxTOFChi2.value)); } Filter eventFilter = (applyEvSel.node() == 0) || @@ -205,6 +207,7 @@ struct tofPidBetaQa { ((trackSelection.node() == 3) && requireGlobalTrackWoDCAInFilter()) || ((trackSelection.node() == 4) && requireQualityTracksInFilter()) || ((trackSelection.node() == 5) && requireInAcceptanceTracksInFilter()); + Filter etaFilter = (nabs(o2::aod::track::eta) < mEtaWindow); using CollisionCandidate = soa::Filtered>::iterator; using TrackCandidates = soa::Join 10.f) { + if (std::abs(collision.posZ()) > 10.f) { return; } @@ -244,7 +247,7 @@ struct tofPidBetaQa { continue; } histos.fill(HIST("event/trackselection"), 3.f); - if (requireGoodMatchTracks.value && !track.goodTOFMatch()) { // Skipping tracks without good match + if (track.tofChi2() > mMaxTOFChi2) { // Skipping tracks with large Chi2 continue; } histos.fill(HIST("event/trackselection"), 4.f); @@ -327,24 +330,25 @@ struct tofPidBetaQa { } } } else { - histos.fill(HIST("tofmass/notrd/inclusive"), track.p(), track.mass()); - histos.fill(HIST("tofbeta/notrd/inclusive"), track.p(), track.beta()); + const float signedp = track.p() * track.sign(); + histos.fill(HIST("tofmass/notrd/inclusive"), signedp, track.mass()); + histos.fill(HIST("tofbeta/notrd/inclusive"), signedp, track.beta()); if (splitSignalPerEvTime) { if (track.isEvTimeTOF()) { - histos.fill(HIST("tofmass/notrd/EvTimeTOF"), track.p(), track.mass()); - histos.fill(HIST("tofbeta/notrd/EvTimeTOF"), track.p(), track.beta()); + histos.fill(HIST("tofmass/notrd/EvTimeTOF"), signedp, track.mass()); + histos.fill(HIST("tofbeta/notrd/EvTimeTOF"), signedp, track.beta()); } if (track.isEvTimeTOF() && !track.isEvTimeT0AC()) { - histos.fill(HIST("tofmass/notrd/EvTimeTOFOnly"), track.p(), track.mass()); - histos.fill(HIST("tofbeta/notrd/EvTimeTOFOnly"), track.p(), track.beta()); + histos.fill(HIST("tofmass/notrd/EvTimeTOFOnly"), signedp, track.mass()); + histos.fill(HIST("tofbeta/notrd/EvTimeTOFOnly"), signedp, track.beta()); } if (track.isEvTimeT0AC()) { - histos.fill(HIST("tofmass/notrd/EvTimeT0AC"), track.p(), track.mass()); - histos.fill(HIST("tofbeta/notrd/EvTimeT0AC"), track.p(), track.beta()); + histos.fill(HIST("tofmass/notrd/EvTimeT0AC"), signedp, track.mass()); + histos.fill(HIST("tofbeta/notrd/EvTimeT0AC"), signedp, track.beta()); } if (track.isEvTimeT0AC() && !track.isEvTimeTOF()) { - histos.fill(HIST("tofmass/notrd/EvTimeT0ACOnly"), track.p(), track.mass()); - histos.fill(HIST("tofbeta/notrd/EvTimeT0ACOnly"), track.p(), track.beta()); + histos.fill(HIST("tofmass/notrd/EvTimeT0ACOnly"), signedp, track.mass()); + histos.fill(HIST("tofbeta/notrd/EvTimeT0ACOnly"), signedp, track.beta()); } } } @@ -384,24 +388,25 @@ struct tofPidBetaQa { } } } else { - histos.fill(HIST("tofmass/trd/inclusive"), track.p(), track.mass()); - histos.fill(HIST("tofbeta/trd/inclusive"), track.p(), track.beta()); + const float signedp = track.p() * track.sign(); + histos.fill(HIST("tofmass/trd/inclusive"), signedp, track.mass()); + histos.fill(HIST("tofbeta/trd/inclusive"), signedp, track.beta()); if (splitSignalPerEvTime) { if (track.isEvTimeTOF()) { - histos.fill(HIST("tofmass/trd/EvTimeTOF"), track.p(), track.mass()); - histos.fill(HIST("tofbeta/trd/EvTimeTOF"), track.p(), track.beta()); + histos.fill(HIST("tofmass/trd/EvTimeTOF"), signedp, track.mass()); + histos.fill(HIST("tofbeta/trd/EvTimeTOF"), signedp, track.beta()); } if (track.isEvTimeTOF() && !track.isEvTimeT0AC()) { - histos.fill(HIST("tofmass/trd/EvTimeTOFOnly"), track.p(), track.mass()); - histos.fill(HIST("tofbeta/trd/EvTimeTOFOnly"), track.p(), track.beta()); + histos.fill(HIST("tofmass/trd/EvTimeTOFOnly"), signedp, track.mass()); + histos.fill(HIST("tofbeta/trd/EvTimeTOFOnly"), signedp, track.beta()); } if (track.isEvTimeT0AC()) { - histos.fill(HIST("tofmass/trd/EvTimeT0AC"), track.p(), track.mass()); - histos.fill(HIST("tofbeta/trd/EvTimeT0AC"), track.p(), track.beta()); + histos.fill(HIST("tofmass/trd/EvTimeT0AC"), signedp, track.mass()); + histos.fill(HIST("tofbeta/trd/EvTimeT0AC"), signedp, track.beta()); } if (track.isEvTimeT0AC() && !track.isEvTimeTOF()) { - histos.fill(HIST("tofmass/trd/EvTimeT0ACOnly"), track.p(), track.mass()); - histos.fill(HIST("tofbeta/trd/EvTimeT0ACOnly"), track.p(), track.beta()); + histos.fill(HIST("tofmass/trd/EvTimeT0ACOnly"), signedp, track.mass()); + histos.fill(HIST("tofbeta/trd/EvTimeT0ACOnly"), signedp, track.beta()); } } } @@ -410,7 +415,4 @@ struct tofPidBetaQa { } }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFEvTime.cxx b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFEvTime.cxx new file mode 100644 index 00000000000..204bff837fb --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFEvTime.cxx @@ -0,0 +1,604 @@ +// 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 qaPIDTOFEvTime.cxx +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Tasks of the TOF PID quantities for the event times +/// + +#include "TEfficiency.h" +#include "THashList.h" + +#include "Framework/HistogramRegistry.h" +#include "Framework/StaticFor.h" +#include "Framework/AnalysisTask.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/TableProducer/PID/pidTOFBase.h" +#include "Framework/runDataProcessing.h" +#include "CommonConstants/LHCConstants.h" +#include "DataFormatsFT0/Digit.h" + +using namespace o2; +using namespace o2::framework; + +struct tofPidCollisionTimeQa { + ConfigurableAxis evTimeBins{"evTimeBins", {1000, -1000.f, 1000.f}, "Binning for the event time"}; + ConfigurableAxis evTimeDeltaBins{"evTimeDeltaBins", {1000, -1000.f, 1000.f}, "Binning for the delta between event times"}; + ConfigurableAxis evTimeResoBins{"evTimeResoBins", {1000, 0.f, 1000.f}, "Binning for the event time resolution"}; + ConfigurableAxis tofSignalBins{"tofSignalBins", {5000, 0.f, 100000.f}, "Binning for the TOF signal"}; + ConfigurableAxis pBins{"pBins", {200, 0.1f, 5.f}, "Binning for the momentum"}; + + Configurable nBinsMultiplicity{"nBinsMultiplicity", 1000, "Number of bins for the multiplicity"}; + Configurable rangeMultiplicity{"rangeMultiplicity", 1000.f, "Range for the multiplicity"}; + Configurable logAxis{"logAxis", 0, "Flag to use a log momentum axis"}; + Configurable minPReso{"minPReso", 1.4f, "Minimum momentum in range for the resolution plot"}; + Configurable maxPReso{"maxPReso", 1.5f, "Maximum momentum in range for the resolution plot"}; + Configurable enableDebug{"enableDebug", false, "Add debug plots"}; + + OutputObj listEfficiency{"Efficiency"}; + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + void init(o2::framework::InitContext&) + { + const AxisSpec evTimeAxis{evTimeBins, "Event time (ps)"}; + const AxisSpec evTimeDeltaAxis{evTimeDeltaBins, "Delta event time (ps)"}; + const AxisSpec multAxis{nBinsMultiplicity, 0, rangeMultiplicity, "Track multiplicity for TOF event time"}; + const AxisSpec evTimeResoAxis{evTimeResoBins, "Event time resolution (ps)"}; + const AxisSpec tofSignalAxis{tofSignalBins, "TOF signal (ps)"}; + AxisSpec pAxis{pBins, "#it{p} GeV/#it{c}"}; + AxisSpec ptAxis{pBins, "#it{p}_{T} GeV/#it{c}"}; + if (logAxis) { + pAxis.makeLogarithmic(); + ptAxis.makeLogarithmic(); + } + const AxisSpec collisionAxis{6000, -0.5f, 6000.f - .5f, "Collision index % 6000"}; + const AxisSpec massAxis{1000, 0, 3, "TOF mass (GeV/#it{c}^{2})"}; + const AxisSpec betaAxis{1000, 0, 1.5, "TOF #beta"}; + const AxisSpec deltaAxis{1000, -10000, 10000, "t-t_{ev}-t_{exp}(#pi) (ps)"}; + const AxisSpec lengthAxis{1000, 0, 600, "Track length (cm)"}; + + if (doprocessData) { + auto h = histos.add("eventSelection", "eventSelection", kTH1F, {{10, 0, 10, "Cut passed"}}); + h->GetXaxis()->SetBinLabel(1, "Events read"); + h->GetXaxis()->SetBinLabel(2, "Event selection"); + h->GetXaxis()->SetBinLabel(3, "#sigma_{Ev. time} < 200 ps"); + h->GetXaxis()->SetBinLabel(4, "#sigma_{Ev. time} > 200 ps"); + h = histos.add("trackSelection", "trackSelection", kTH1F, {{10, 0, 10, "Cut passed"}}); + h->GetXaxis()->SetBinLabel(1, "Tracks read"); + h->GetXaxis()->SetBinLabel(2, "Track selection"); + h->GetXaxis()->SetBinLabel(3, "hasITS"); + h->GetXaxis()->SetBinLabel(4, "hasTPC"); + h->GetXaxis()->SetBinLabel(5, "hasTOF"); + histos.add("deltaEvTimeTOFT0A", "deltaEvTimeTOFT0A", kTH1F, {evTimeDeltaAxis})->GetXaxis()->SetTitle("Ev. time_{TOF} - Ev. time_{T0A} (ps)"); + histos.add("deltaEvTimeTOFT0C", "deltaEvTimeTOFT0C", kTH1F, {evTimeDeltaAxis})->GetXaxis()->SetTitle("Ev. time_{TOF} - Ev. time_{T0C} (ps)"); + histos.add("deltaEvTimeTOFT0AC", "deltaEvTimeTOFT0AC", kTH1F, {evTimeDeltaAxis})->GetXaxis()->SetTitle("Ev. time_{TOF} - Ev. time_{T0AC} (ps)"); + auto h2 = histos.add("deltaEvTimeTOFT0AvsT0C", "deltaEvTimeTOFT0AvsT0C", kTH2F, {evTimeDeltaAxis, evTimeDeltaAxis}); + h2->GetXaxis()->SetTitle("Ev. time_{TOF} - Ev. time_{T0A} (ps)"); + h2->GetYaxis()->SetTitle("Ev. time_{TOF} - Ev. time_{T0C} (ps)"); + h2 = histos.add("deltaEvTimeTOFT0AvsTOF", "deltaEvTimeTOFT0AvsTOF", kTH2F, {evTimeAxis, evTimeDeltaAxis}); + h2->GetXaxis()->SetTitle("Ev. time_{TOF} (ps)"); + h2->GetYaxis()->SetTitle("Ev. time_{TOF} - Ev. time_{T0A} (ps)"); + h2 = histos.add("deltaEvTimeTOFT0CvsTOF", "deltaEvTimeTOFT0CvsTOF", kTH2F, {evTimeAxis, evTimeDeltaAxis}); + h2->GetXaxis()->SetTitle("Ev. time_{TOF} (ps)"); + h2->GetYaxis()->SetTitle("Ev. time_{TOF} - Ev. time_{T0C} (ps)"); + h2 = histos.add("deltaEvTimeTOFT0ACvsTOF", "deltaEvTimeTOFT0ACvsTOF", kTH2F, {evTimeAxis, evTimeDeltaAxis}); + h2->GetXaxis()->SetTitle("Ev. time_{TOF} (ps)"); + h2->GetYaxis()->SetTitle("Ev. time_{TOF} - Ev. time_{T0AC} (ps)"); + + histos.add("eventTime", "eventTime", kTH1F, {evTimeAxis}); + histos.add("eventTimeReso", "eventTimeReso", kTH1F, {evTimeResoAxis}); + histos.add("eventTimeVsMult", "eventTimeVsMult", kTH2F, {multAxis, evTimeAxis}); + histos.add("eventTimeResoVsMult", "eventTimeResoVsMult", kTH2F, {multAxis, evTimeResoAxis}); + + histos.add("eventTimeTOFMult", "eventTimeTOFMult", kTH1F, {multAxis}); + histos.add("eventTimeTOF", "eventTimeTOF", kTH1F, {evTimeAxis})->GetXaxis()->SetTitle("Ev. time_{TOF} (ps)"); + histos.add("eventTimeTOFReso", "eventTimeTOFReso", kTH1F, {evTimeResoAxis})->GetXaxis()->SetTitle("Ev. time_{TOF} resolution (ps)"); + histos.add("eventTimeTOFVsMult", "eventTimeTOFVsMult", kTH2F, {multAxis, evTimeAxis})->GetYaxis()->SetTitle("Ev. time_{TOF} (ps)"); + histos.add("eventTimeTOFResoVsMult", "eventTimeTOFResoVsMult", kTH2F, {multAxis, evTimeResoAxis})->GetYaxis()->SetTitle("Ev. time_{TOF} resolution (ps)"); + + histos.add("eventTimeT0A", "eventTimeT0A", kTH1F, {evTimeAxis})->GetXaxis()->SetTitle("T0A event time (ps)"); + histos.add("eventTimeT0C", "eventTimeT0C", kTH1F, {evTimeAxis})->GetXaxis()->SetTitle("T0C event time (ps)"); + histos.add("eventTimeT0AC", "eventTimeT0AC", kTH1F, {evTimeAxis})->GetXaxis()->SetTitle("T0AC event time (ps)"); + histos.add("eventTimeT0ACReso", "eventTimeT0ACReso", kTH1F, {evTimeResoAxis})->GetXaxis()->SetTitle("T0AC event time resolution (ps)"); + + histos.add("collisionTime", "collisionTime", kTH1F, {evTimeResoAxis})->GetXaxis()->SetTitle("Collision time (ps)"); + histos.add("collisionTimeRes", "collisionTimeRes", kTH1F, {evTimeResoAxis})->GetXaxis()->SetTitle("Collision time resolution (ps)"); + + histos.add("tracks/p", "p", kTH1F, {pAxis}); + histos.add("tracks/pt", "pt", kTH1F, {ptAxis}); + histos.add("tracks/length", "length", kTH1F, {lengthAxis}); + + histos.add("deltaVsMult/pi", Form("pi %.2f < #it{p} < %.2f", minPReso.value, maxPReso.value), kTH2F, {multAxis, deltaAxis}); + histos.add("deltaVsReso/pi", Form("pi %.2f < #it{p} < %.2f", minPReso.value, maxPReso.value), kTH2F, {evTimeResoAxis, deltaAxis}); + + histos.add("tofbeta/inclusive", "", HistType::kTH2F, {pAxis, betaAxis}); + histos.add("tofbeta/EvTimeTOF", "Ev. Time TOF", HistType::kTH2F, {pAxis, betaAxis}); + histos.add("tofbeta/EvTimeTOFOnly", "Ev. Time TOF Only", HistType::kTH2F, {pAxis, betaAxis}); + histos.add("tofbeta/EvTimeT0AC", "Ev. Time T0AC", HistType::kTH2F, {pAxis, betaAxis}); + histos.add("tofbeta/EvTimeT0AOnly", "Ev. Time T0A Only", HistType::kTH2F, {pAxis, betaAxis}); + histos.add("tofbeta/EvTimeT0COnly", "Ev. Time T0A Only", HistType::kTH2F, {pAxis, betaAxis}); + histos.add("tofbeta/EvTimeT0ACOnly", "Ev. Time T0AC Only", HistType::kTH2F, {pAxis, betaAxis}); + + histos.add("tofmass/inclusive", "", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/EvTimeTOF", "Ev. Time TOF", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/EvTimeTOFOnly", "Ev. Time TOF Only", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/EvTimeT0AC", "Ev. Time T0AC", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/EvTimeT0AOnly", "Ev. Time T0A Only", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/EvTimeT0COnly", "Ev. Time T0C Only", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/EvTimeT0ACOnly", "Ev. Time T0AC Only", HistType::kTH2F, {pAxis, massAxis}); + if (enableDebug) { + histos.add("withtof/p", "p", kTH1F, {pAxis}); + histos.add("withtof/pt", "pt", kTH1F, {ptAxis}); + histos.add("withtof/length", "length", kTH1F, {lengthAxis}); + histos.add("withtof/tofSignal", "tofSignal", kTH1F, {tofSignalAxis}); + histos.add("withtof/beta", "beta", kTH2F, {pAxis, betaAxis}); + histos.add("withtof/delta", "delta", kTH2F, {pAxis, deltaAxis}); + histos.add("withtof/expP", "expP", kTH2F, {pAxis, pAxis}); + histos.add("withtof/mass", "mass", kTH1F, {massAxis}); + histos.add("withtof/tofSignalPerCollision", "tofSignalPerCollision", kTH2S, {collisionAxis, tofSignalAxis}); + + histos.addClone("withtof/", "goodreso/"); + histos.addClone("withtof/", "badreso/"); + histos.addClone("withtof/", "goodforevtime/"); + histos.addClone("withtof/", "withqualitycuts/"); + } + + listEfficiency.setObject(new THashList); + auto makeEfficiency = [&](TString effname, TString efftitle) { + listEfficiency->Add(new TEfficiency(effname, efftitle + ";TOF multiplicity;Efficiency", nBinsMultiplicity, 0, rangeMultiplicity)); + }; + + makeEfficiency("effTOFEvTime", "Efficiency of the TOF Event Time"); + makeEfficiency("effT0ACEvTime", "Efficiency of the T0AC Event Time"); + makeEfficiency("effTOFT0ACEvTime", "Efficiency of the TOF+T0AC Event Time"); + makeEfficiency("effT0AEvTime", "Efficiency of the T0A Event Time"); + makeEfficiency("effT0CEvTime", "Efficiency of the T0C Event Time"); + } + + if (!doprocessMC) { + return; + } + const AxisSpec diffAxis{1000, -1000, 1000, "Difference"}; + histos.add("MC/diff/All", "All", HistType::kTH1F, {diffAxis})->GetXaxis()->SetTitle("t^{MC}_{ev}-t^{All}_{ev} (ps)"); + histos.add("MC/diff/FT0", "FT0", HistType::kTH1F, {diffAxis})->GetXaxis()->SetTitle("t^{MC}_{ev}-t_{FT0}_{ev} (ps)"); + histos.add("MC/diff/TOF", "TOF", HistType::kTH1F, {diffAxis})->GetXaxis()->SetTitle("t^{MC}_{ev}-t_{TOF}_{ev} (ps)"); + + histos.add("MC/diffvsZ/All", "All", HistType::kTH2F, {diffAxis, {100, -20, 20}})->GetXaxis()->SetTitle("t^{MC}_{ev}-t^{All}_{ev}_{ev} (ps)"); + histos.add("MC/diffvsZ/FT0", "FT0", HistType::kTH2F, {diffAxis, {100, -20, 20}})->GetXaxis()->SetTitle("t^{MC}_{ev}-t_{FT0}_{ev} (ps)"); + histos.add("MC/diffvsZ/TOF", "TOF", HistType::kTH2F, {diffAxis, {100, -20, 20}})->GetXaxis()->SetTitle("t^{MC}_{ev}-t_{TOF}_{ev} (ps)"); + + // pion + histos.add("MC/particle/pdg211/all/particleDiff", "particleDiff", HistType::kTH2F, {ptAxis, diffAxis})->GetYaxis()->SetTitle("t^{MC}_{ev}-t^{part}_{MC} (ps)"); + histos.add("MC/particle/pdg211/all/delta", "delta", HistType::kTH2F, {ptAxis, diffAxis})->GetYaxis()->SetTitle("t_{TOF}-t^{MC}_{ev}-t_{exp} (ps)"); + histos.add("MC/particle/pdg211/all/deltaTRD", "deltaTRD", HistType::kTH2F, {ptAxis, diffAxis})->GetYaxis()->SetTitle("t_{TOF}-t^{MC}_{ev}-t_{exp} (ps)"); + histos.add("MC/particle/pdg211/all/deltaNoTRD", "deltaNoTRD", HistType::kTH2F, {ptAxis, diffAxis})->GetYaxis()->SetTitle("t_{TOF}-t^{MC}_{ev}-t_{exp} (ps)"); + histos.addClone("MC/particle/pdg211/all/", "MC/particle/pdg211/prm/"); + + histos.addClone("MC/particle/pdg211/", "MC/particle/pdgNeg211/"); + + // kaon + histos.addClone("MC/particle/pdg211/", "MC/particle/pdg321/"); + histos.addClone("MC/particle/pdg211/", "MC/particle/pdgNeg321/"); + // proton + histos.addClone("MC/particle/pdg211/", "MC/particle/pdg2212/"); + histos.addClone("MC/particle/pdg211/", "MC/particle/pdgNeg2212/"); + + const AxisSpec mcTimeAxis{1000, -1000, 1000, "MC coll time (ps)"}; + + histos.add("MC/CollisionTime/eventtimeMC", "", HistType::kTH1F, {mcTimeAxis}); + histos.add("MC/CollisionTime/All", "", HistType::kTH1F, {mcTimeAxis})->GetXaxis()->SetTitle("All (ps)"); + histos.add("MC/CollisionTime/FT0", "", HistType::kTH1F, {mcTimeAxis})->GetXaxis()->SetTitle("FT0 (ps)"); + histos.add("MC/CollisionTime/TOF", "", HistType::kTH1F, {mcTimeAxis})->GetXaxis()->SetTitle("TOF (ps)"); + histos.add("MC/CollisionTime/eventtimeMCvsAll", "", HistType::kTH2F, {mcTimeAxis, mcTimeAxis})->GetYaxis()->SetTitle("All (ps)"); + histos.add("MC/CollisionTime/eventtimeMCvsFT0", "", HistType::kTH2F, {mcTimeAxis, mcTimeAxis})->GetYaxis()->SetTitle("FT0 (ps)"); + histos.add("MC/CollisionTime/eventtimeMCvsTOF", "", HistType::kTH2F, {mcTimeAxis, mcTimeAxis})->GetYaxis()->SetTitle("TOF (ps)"); + + const AxisSpec axisBCID{o2::constants::lhc::LHCMaxBunches, -0.5, -0.5 + o2::constants::lhc::LHCMaxBunches, "BC ID in orbit"}; + const AxisSpec axisBCIDMC{o2::constants::lhc::LHCMaxBunches, -0.5, -0.5 + o2::constants::lhc::LHCMaxBunches, "MC BC ID in orbit"}; + + histos.add("collisions/Reco/BCvsMCBC", "BC vs MC BC", kTH2D, {axisBCID, axisBCIDMC}); + histos.add("collisions/Reco/FoundBCvsMCBC", "Found BC vs MC BC", kTH2D, {axisBCID, axisBCIDMC})->GetXaxis()->SetTitle("Found BC ID in orbit"); + histos.add("collisions/Reco/FoundBCvsBC", "Found BC vs MC BC", kTH2D, {axisBCID, axisBCID})->GetXaxis()->SetTitle("Found BC ID in orbit"); + histos.add("collisions/Reco/bcMinusfoundBc", "bcMinusfoundBc", kTH1D, {{1600, -1000, 1000, "bc - foundBc (ns)"}}); + histos.add("collisions/Reco/bcMinusfoundBcRatio", "bcMinusfoundBcRatio", kTH1D, {{1600, -40, 40, "(bc - foundBc)/collisionTimeRes"}}); + histos.add("collisions/Reco/bcMinusMcBc", "bcMinusMcBc", kTH1D, {{1600, -1000, 1000, "bc - mcBc (ns)"}}); + histos.add("collisions/Reco/foundbcMinusMcBc", "foundbcMinusMcBc", kTH1D, {{1600, -1000, 1000, "foundBc - mcBc (ns)"}}); + histos.add("collisions/Reco/bcMinusMcBcRatio", "bcMinusMcBcRatio", kTH1D, {{1600, -40, 40, "(bc - mcBc)/collisionTimeRes"}}); + histos.add("collisions/Reco/foundbcMinusMcBcRatio", "foundbcMinusMcBcRatio", kTH1D, {{1600, -40, 40, "(foundBc-mcBc)/collisionTimeRes"}}); + + histos.add("ft0/FT0AMinusFT0ACorrected", "", kTH1D, {{1600, -1000, 1000, "FT0A - FT0A_{corr} (ps)"}}); + histos.add("ft0/FT0CMinusFT0CCorrected", "", kTH1D, {{1600, -1000, 1000, "FT0C - FT0C_{corr} (ps)"}}); + histos.add("ft0/FT0ACMinusFT0ACCorrected", "", kTH1D, {{1600, -1000, 1000, "FT0AC - FT0AC_{corr} (ps)"}}); + histos.add("ft0/diffPosZ", "", kTH1D, {{100, -10, 10, "z_{mc} - z_{FT0} (cm)"}}); + } + + using Trks = soa::Join; + using TrksData = soa::Join; + using EvTimeCollisions = soa::Join; + // Define slice per collision + Preslice perCollision = aod::track::collisionId; + void processData(TrksData const& tracks, EvTimeCollisions const&) + { + static int ncolls = 0; + int lastCollisionId = -1; // Last collision ID analysed + for (auto& t : tracks) { + if (!t.has_collision()) { // Track was not assigned to a collision + continue; + } else if (t.collisionId() == lastCollisionId) { // Event was already processed + continue; + } + lastCollisionId = t.collisionId(); /// Cache last collision ID + auto collision = t.collision_as(); + + histos.fill(HIST("eventSelection"), 0.5f); + histos.fill(HIST("eventSelection"), 1.5f); + if (t.tofEvTimeErr() > 199.f) { + histos.fill(HIST("eventSelection"), 2.5f); + } else { + histos.fill(HIST("eventSelection"), 3.5f); + } + histos.fill(HIST("eventTime"), t.tofEvTime()); + histos.fill(HIST("eventTimeReso"), t.tofEvTimeErr()); + histos.fill(HIST("eventTimeVsMult"), t.evTimeTOFMult(), t.tofEvTime()); + histos.fill(HIST("eventTimeResoVsMult"), t.evTimeTOFMult(), t.tofEvTimeErr()); + + if (t.isEvTimeTOF()) { + histos.fill(HIST("eventTimeTOF"), t.evTimeTOF()); + histos.fill(HIST("eventTimeTOFReso"), t.evTimeTOFErr()); + histos.fill(HIST("eventTimeTOFMult"), t.evTimeTOFMult()); + histos.fill(HIST("eventTimeTOFVsMult"), t.evTimeTOFMult(), t.evTimeTOF()); + histos.fill(HIST("eventTimeTOFResoVsMult"), t.evTimeTOFMult(), t.evTimeTOFErr()); + } + + if (collision.has_foundFT0()) { // T0 measurement is available + if (collision.t0ACorrectedValid()) { + histos.fill(HIST("eventTimeT0A"), collision.t0ACorrected() * 1000.f); + if (t.isEvTimeTOF()) { + histos.fill(HIST("deltaEvTimeTOFT0A"), t.evTimeTOF() - collision.t0ACorrected() * 1000.f); + histos.fill(HIST("deltaEvTimeTOFT0AvsTOF"), t.evTimeTOF(), t.evTimeTOF() - collision.t0ACorrected() * 1000.f); + } + } + if (collision.t0CCorrectedValid()) { + histos.fill(HIST("eventTimeT0C"), collision.t0CCorrected() * 1000.f); + if (t.isEvTimeTOF()) { + histos.fill(HIST("deltaEvTimeTOFT0C"), t.evTimeTOF() - collision.t0CCorrected() * 1000.f); + histos.fill(HIST("deltaEvTimeTOFT0CvsTOF"), t.evTimeTOF(), t.evTimeTOF() - collision.t0CCorrected() * 1000.f); + } + } + if (collision.t0ACValid()) { + histos.fill(HIST("eventTimeT0AC"), collision.t0AC() * 1000.f); + histos.fill(HIST("eventTimeT0ACReso"), collision.t0resolution() * 1000.f); + if (t.isEvTimeTOF()) { + histos.fill(HIST("deltaEvTimeTOFT0AC"), t.evTimeTOF() - collision.t0AC() * 1000.f); + histos.fill(HIST("deltaEvTimeTOFT0ACvsTOF"), t.evTimeTOF(), t.evTimeTOF() - collision.t0AC() * 1000.f); + } + } + if (collision.t0ACorrectedValid() && collision.t0CCorrectedValid() && t.isEvTimeTOF()) { + histos.fill(HIST("deltaEvTimeTOFT0AvsT0C"), t.evTimeTOF() - collision.t0ACorrected() * 1000.f, t.evTimeTOF() - collision.t0CCorrected() * 1000.f); + } + } + + histos.fill(HIST("collisionTime"), collision.collisionTime()); + histos.fill(HIST("collisionTimeRes"), collision.collisionTimeRes()); + ncolls++; + + const auto tracksInCollision = tracks.sliceBy(perCollision, lastCollisionId); + int nTracksWithTOF = 0; + for (auto const& trk : tracksInCollision) { // Loop on Tracks + histos.fill(HIST("trackSelection"), 0.5f); + + if (!trk.isGlobalTrack()) { + continue; + } + histos.fill(HIST("trackSelection"), 1.5f); + + if (!trk.hasITS()) { + continue; + } + histos.fill(HIST("trackSelection"), 2.5f); + if (!trk.hasTPC()) { + continue; + } + histos.fill(HIST("trackSelection"), 3.5f); + + histos.fill(HIST("tracks/p"), trk.p()); + histos.fill(HIST("tracks/pt"), trk.pt()); + histos.fill(HIST("tracks/length"), trk.length()); + + if (enableDebug) { + if (trk.tofEvTimeErr() > 199.f) { + histos.fill(HIST("badreso/ptden"), trk.pt()); + } else { + histos.fill(HIST("goodreso/ptden"), trk.pt()); + } + } + + if (!trk.hasTOF()) { + continue; + } + nTracksWithTOF++; + histos.fill(HIST("trackSelection"), 4.5f); + + // Recompute quantities with event times + const float& betaTOF = trk.evTimeTOFMult() > 1 ? o2::pid::tof::Beta::GetBeta(trk, trk.evTimeTOF()) : 999.f; + const float& betaT0A = collision.t0ACorrectedValid() ? o2::pid::tof::Beta::GetBeta(trk, collision.t0ACorrected() * 1000.f) : 999.f; + const float& betaT0C = collision.t0CCorrectedValid() ? o2::pid::tof::Beta::GetBeta(trk, collision.t0CCorrected() * 1000.f) : 999.f; + const float& betaT0AC = collision.t0ACValid() ? o2::pid::tof::Beta::GetBeta(trk, collision.t0AC() * 1000.f) : 999.f; + + const float& massTOF = trk.evTimeTOFMult() > 1 ? o2::pid::tof::TOFMass::GetTOFMass(trk, betaTOF) : 999.f; + const float& massT0A = collision.t0ACorrectedValid() ? o2::pid::tof::TOFMass::GetTOFMass(trk, betaT0A) : 999.f; + const float& massT0C = collision.t0CCorrectedValid() ? o2::pid::tof::TOFMass::GetTOFMass(trk, betaT0C) : 999.f; + const float& massT0AC = collision.t0ACValid() ? o2::pid::tof::TOFMass::GetTOFMass(trk, betaT0AC) : 999.f; + + const float& deltaPi = trk.tofSignal() - trk.tofEvTime() - trk.tofExpTimePi(); + + histos.fill(HIST("tofbeta/inclusive"), trk.p(), trk.beta()); + histos.fill(HIST("tofmass/inclusive"), trk.p(), trk.mass()); + if (trk.isEvTimeTOF()) { + histos.fill(HIST("tofbeta/EvTimeTOF"), trk.p(), trk.beta()); + histos.fill(HIST("tofmass/EvTimeTOF"), trk.p(), trk.mass()); + histos.fill(HIST("tofbeta/EvTimeTOFOnly"), trk.p(), betaTOF); + histos.fill(HIST("tofmass/EvTimeTOFOnly"), trk.p(), massTOF); + } + if (trk.isEvTimeT0AC()) { + histos.fill(HIST("tofbeta/EvTimeT0AC"), trk.p(), trk.beta()); + histos.fill(HIST("tofmass/EvTimeT0AC"), trk.p(), trk.mass()); + } + histos.fill(HIST("tofbeta/EvTimeT0AOnly"), trk.p(), betaT0A); + histos.fill(HIST("tofbeta/EvTimeT0COnly"), trk.p(), betaT0C); + histos.fill(HIST("tofbeta/EvTimeT0ACOnly"), trk.p(), betaT0AC); + + histos.fill(HIST("tofmass/EvTimeT0AOnly"), trk.p(), massT0A); + histos.fill(HIST("tofmass/EvTimeT0COnly"), trk.p(), massT0C); + histos.fill(HIST("tofmass/EvTimeT0ACOnly"), trk.p(), massT0AC); + + if (trk.p() > minPReso && trk.p() < maxPReso) { + histos.fill(HIST("deltaVsMult/pi"), trk.evTimeTOFMult(), deltaPi); + histos.fill(HIST("deltaVsReso/pi"), trk.evTimeTOFMult(), deltaPi); + } + if (enableDebug) { + + histos.fill(HIST("withtof/p"), trk.p()); + histos.fill(HIST("withtof/pt"), trk.pt()); + histos.fill(HIST("withtof/length"), trk.length()); + histos.fill(HIST("withtof/tofSignal"), trk.tofSignal()); + histos.fill(HIST("withtof/beta"), trk.p(), trk.beta()); + histos.fill(HIST("withtof/delta"), trk.p(), deltaPi); + + histos.fill(HIST("withtof/expP"), trk.p(), trk.tofExpMom()); + histos.fill(HIST("withtof/mass"), trk.mass()); + histos.fill(HIST("withtof/tofSignalPerCollision"), ncolls % 6000, trk.tofSignal()); + if (trk.pt() > 0.3 && trk.beta() > 0.3) { + histos.fill(HIST("withqualitycuts/p"), trk.p()); + histos.fill(HIST("withqualitycuts/pt"), trk.pt()); + histos.fill(HIST("withqualitycuts/length"), trk.length()); + histos.fill(HIST("withqualitycuts/mass"), trk.mass()); + } + + if (trk.tofEvTimeErr() > 199.f) { + histos.fill(HIST("badreso/p"), trk.p()); + histos.fill(HIST("badreso/pt"), trk.pt()); + histos.fill(HIST("badreso/length"), trk.length()); + histos.fill(HIST("badreso/tofSignal"), trk.tofSignal()); + histos.fill(HIST("badreso/beta"), trk.p(), trk.beta()); + histos.fill(HIST("badreso/delta"), trk.p(), deltaPi); + histos.fill(HIST("badreso/expP"), trk.p(), trk.tofExpMom()); + histos.fill(HIST("badreso/mass"), trk.mass()); + histos.fill(HIST("badreso/tofSignalPerCollision"), ncolls % 6000, trk.tofSignal()); + } else { + histos.fill(HIST("goodreso/p"), trk.p()); + histos.fill(HIST("goodreso/pt"), trk.pt()); + histos.fill(HIST("goodreso/length"), trk.length()); + histos.fill(HIST("goodreso/tofSignal"), trk.tofSignal()); + histos.fill(HIST("goodreso/beta"), trk.p(), trk.beta()); + histos.fill(HIST("goodreso/delta"), trk.p(), deltaPi); + histos.fill(HIST("goodreso/expP"), trk.p(), trk.tofExpMom()); + histos.fill(HIST("goodreso/mass"), trk.mass()); + histos.fill(HIST("goodreso/tofSignalPerCollision"), ncolls % 6000, trk.tofSignal()); + } + if (!trk.usedForTOFEvTime()) { + continue; + } + histos.fill(HIST("goodforevtime/p"), trk.p()); + histos.fill(HIST("goodforevtime/pt"), trk.pt()); + histos.fill(HIST("goodforevtime/length"), trk.length()); + histos.fill(HIST("goodforevtime/tofSignal"), trk.tofSignal()); + histos.fill(HIST("goodforevtime/beta"), trk.p(), trk.beta()); + histos.fill(HIST("goodforevtime/delta"), trk.p(), deltaPi); + histos.fill(HIST("goodforevtime/expP"), trk.p(), trk.tofExpMom()); + histos.fill(HIST("goodforevtime/mass"), trk.mass()); + histos.fill(HIST("goodforevtime/tofSignalPerCollision"), ncolls % 6000, trk.tofSignal()); + } + } + static_cast(listEfficiency->FindObject("effTOFEvTime"))->Fill(t.isEvTimeTOF(), nTracksWithTOF); + static_cast(listEfficiency->FindObject("effT0AEvTime"))->Fill(collision.has_foundFT0() && collision.t0ACorrectedValid(), nTracksWithTOF); + static_cast(listEfficiency->FindObject("effT0CEvTime"))->Fill(collision.has_foundFT0() && collision.t0CCorrectedValid(), nTracksWithTOF); + static_cast(listEfficiency->FindObject("effT0ACEvTime"))->Fill(collision.has_foundFT0() && collision.t0ACValid(), nTracksWithTOF); + static_cast(listEfficiency->FindObject("effTOFT0ACEvTime"))->Fill(t.isEvTimeTOF() && collision.has_foundFT0() && collision.t0ACorrectedValid(), nTracksWithTOF); + } + } + PROCESS_SWITCH(tofPidCollisionTimeQa, processData, "Process data", true); + + using TrksMC = soa::Join; + using EvTimeCollisionsMC = soa::Join; + void processMC(TrksMC const& tracks, + EvTimeCollisionsMC const&, + aod::McParticles const&, + aod::BCs const&, + aod::FT0s const&, + aod::McCollisions const&) + { + // static int ncolls = 0; + int lastCollisionId = -1; // Last collision ID analysed + + for (auto& trk : tracks) { + if (!trk.has_collision()) { // Track was not assigned to a collision + continue; + } + const auto& collision = trk.collision_as(); + if (!collision.has_mcCollision()) { + continue; + } + const auto& collisionMC = collision.mcCollision_as(); + const float eventtimeMC = collisionMC.t() * 1000.f; + + if (trk.has_mcParticle()) { + const auto& particle = trk.mcParticle(); + const auto& mcCollTimeMinusFormationTime = particle.vt() - collisionMC.t(); + const auto& mcTOFvalue = trk.tofSignal() - eventtimeMC - trk.tofExpTimePi(); + LOG(debug) << "Track " << particle.vt() << " vs " << eventtimeMC; + switch (particle.pdgCode()) { + case 211: + histos.fill(HIST("MC/particle/pdg211/all/particleDiff"), particle.pt(), mcCollTimeMinusFormationTime); + histos.fill(HIST("MC/particle/pdg211/all/delta"), particle.pt(), mcTOFvalue); + if (trk.hasTRD()) { + histos.fill(HIST("MC/particle/pdg211/all/deltaTRD"), particle.pt(), mcTOFvalue); + } else { + histos.fill(HIST("MC/particle/pdg211/all/deltaNoTRD"), particle.pt(), mcTOFvalue); + } + if (particle.isPhysicalPrimary()) { + histos.fill(HIST("MC/particle/pdg211/prm/particleDiff"), particle.pt(), mcCollTimeMinusFormationTime); + } + break; + case -211: + histos.fill(HIST("MC/particle/pdgNeg211/all/particleDiff"), particle.pt(), mcCollTimeMinusFormationTime); + histos.fill(HIST("MC/particle/pdgNeg211/all/delta"), particle.pt(), mcTOFvalue); + histos.fill(HIST("MC/particle/pdgNeg211/all/delta"), particle.pt(), mcTOFvalue); + if (trk.hasTRD()) { + histos.fill(HIST("MC/particle/pdgNeg211/all/deltaTRD"), particle.pt(), mcTOFvalue); + } else { + histos.fill(HIST("MC/particle/pdgNeg211/all/deltaNoTRD"), particle.pt(), mcTOFvalue); + } + if (particle.isPhysicalPrimary()) { + histos.fill(HIST("MC/particle/pdgNeg211/prm/particleDiff"), particle.pt(), mcCollTimeMinusFormationTime); + } + break; + case 321: + histos.fill(HIST("MC/particle/pdg321/all/particleDiff"), particle.pt(), mcCollTimeMinusFormationTime); + if (particle.isPhysicalPrimary()) { + histos.fill(HIST("MC/particle/pdg321/prm/particleDiff"), particle.pt(), mcCollTimeMinusFormationTime); + } + break; + case -321: + histos.fill(HIST("MC/particle/pdgNeg321/all/particleDiff"), particle.pt(), mcCollTimeMinusFormationTime); + if (particle.isPhysicalPrimary()) { + histos.fill(HIST("MC/particle/pdgNeg321/prm/particleDiff"), particle.pt(), mcCollTimeMinusFormationTime); + } + break; + case 2212: + histos.fill(HIST("MC/particle/pdg2212/all/particleDiff"), particle.pt(), mcCollTimeMinusFormationTime); + if (particle.isPhysicalPrimary()) { + histos.fill(HIST("MC/particle/pdg2212/prm/particleDiff"), particle.pt(), mcCollTimeMinusFormationTime); + } + break; + case -2212: + histos.fill(HIST("MC/particle/pdgNeg2212/all/particleDiff"), particle.pt(), mcCollTimeMinusFormationTime); + if (particle.isPhysicalPrimary()) { + histos.fill(HIST("MC/particle/pdgNeg2212/prm/particleDiff"), particle.pt(), mcCollTimeMinusFormationTime); + } + break; + default: + break; + } + } + + if (trk.collisionId() == lastCollisionId) { // Event was already processed + continue; + } + lastCollisionId = trk.collisionId(); /// Cache last collision ID + + float t0AC[2] = {0.f, 0.f}; + // const auto& ft0 = collision.foundFT0(); + if (collision.t0ACValid()) { + t0AC[0] = collision.t0AC() * 1000.f; + t0AC[1] = collision.t0resolution() * 1000.f; + } + + float t0A = 1e10; + float t0C = 1e10; + + constexpr float dummyTime = 30.; // Due to HW limitations time can be only within range (-25,25) ns, dummy time is around 32 ns + if (collision.has_foundFT0()) { // Get the non corrected FT0AC + const auto& ft0 = collision.foundFT0(); + const std::bitset<8>& triggers = ft0.triggerMask(); + const bool ora = triggers[o2::ft0::Triggers::bitA]; + const bool orc = triggers[o2::ft0::Triggers::bitC]; + if (ora && ft0.timeA() < dummyTime) { + t0A = ft0.timeA(); + } + if (orc && ft0.timeC() < dummyTime) { + t0C = ft0.timeC(); + } + if (ft0.isValidTime()) { + histos.fill(HIST("ft0/diffPosZ"), ft0.posZ() - collisionMC.posZ()); + } + } + if (collision.t0ACorrectedValid()) { + histos.fill(HIST("ft0/FT0AMinusFT0ACorrected"), (t0A - collision.t0ACorrected()) * 1000.f); + } + if (collision.t0CCorrectedValid()) { + histos.fill(HIST("ft0/FT0CMinusFT0CCorrected"), (t0C - collision.t0CCorrected()) * 1000.f); + } + if (collision.t0ACValid()) { + histos.fill(HIST("ft0/FT0ACMinusFT0ACCorrected"), (0.5 * (t0A + t0C) - collision.t0AC()) * 1000.f); + } + + const auto& recoBC = collision.bc(); + const auto& foundBC = collision.foundBC(); + const auto& mcBC = collisionMC.bc(); + + const auto& recoBCid = recoBC.globalBC() % o2::constants::lhc::LHCMaxBunches; + const auto& mcBCid = mcBC.globalBC() % o2::constants::lhc::LHCMaxBunches; + const auto& foundBCid = foundBC.globalBC() % o2::constants::lhc::LHCMaxBunches; + const int diffRecoFoundBC = foundBC.globalBC() - recoBC.globalBC(); + const int diffRecoMCBC = recoBC.globalBC() - mcBC.globalBC(); + const int diffFoundMCBC = foundBC.globalBC() - mcBC.globalBC(); + histos.fill(HIST("collisions/Reco/BCvsMCBC"), recoBCid, mcBCid); + histos.fill(HIST("collisions/Reco/FoundBCvsMCBC"), foundBCid, mcBCid); + histos.fill(HIST("collisions/Reco/FoundBCvsBC"), foundBCid, recoBCid); + histos.fill(HIST("collisions/Reco/bcMinusMcBc"), (diffRecoMCBC)*o2::constants::lhc::LHCBunchSpacingNS); + histos.fill(HIST("collisions/Reco/foundbcMinusMcBc"), (diffFoundMCBC)*o2::constants::lhc::LHCBunchSpacingNS); + histos.fill(HIST("collisions/Reco/bcMinusfoundBc"), (diffRecoFoundBC)*o2::constants::lhc::LHCBunchSpacingNS); + histos.fill(HIST("collisions/Reco/bcMinusfoundBcRatio"), (diffRecoFoundBC)*o2::constants::lhc::LHCBunchSpacingNS / collision.collisionTimeRes()); + histos.fill(HIST("collisions/Reco/foundbcMinusMcBcRatio"), (diffFoundMCBC)*o2::constants::lhc::LHCBunchSpacingNS / collision.collisionTimeRes()); + histos.fill(HIST("collisions/Reco/bcMinusMcBcRatio"), (diffRecoMCBC)*o2::constants::lhc::LHCBunchSpacingNS / collision.collisionTimeRes()); + + // timeInBCNS + bc2ns(); + // bc* o2::constants::lhc::LHCBunchSpacingNS + orbit* o2::constants::lhc::LHCOrbitNS; + // int64_t(mcBC.globalBC() * o2::constants::lhc::LHCBunchSpacingNS * 1e-3)) + + histos.fill(HIST("MC/CollisionTime/eventtimeMC"), eventtimeMC); + histos.fill(HIST("MC/CollisionTime/All"), trk.tofEvTime()); + histos.fill(HIST("MC/CollisionTime/FT0"), t0AC[0]); + histos.fill(HIST("MC/CollisionTime/TOF"), trk.evTimeTOF()); + histos.fill(HIST("MC/CollisionTime/eventtimeMCvsAll"), eventtimeMC, trk.tofEvTime()); + histos.fill(HIST("MC/CollisionTime/eventtimeMCvsFT0"), eventtimeMC, t0AC[0]); + histos.fill(HIST("MC/CollisionTime/eventtimeMCvsTOF"), eventtimeMC, trk.evTimeTOF()); + + histos.fill(HIST("MC/diff/All"), eventtimeMC - trk.tofEvTime()); + histos.fill(HIST("MC/diff/FT0"), eventtimeMC - t0AC[0]); + histos.fill(HIST("MC/diff/TOF"), eventtimeMC - trk.evTimeTOF()); + histos.fill(HIST("MC/diffvsZ/All"), eventtimeMC - trk.tofEvTime(), collisionMC.posZ()); + histos.fill(HIST("MC/diffvsZ/FT0"), eventtimeMC - t0AC[0], collisionMC.posZ()); + histos.fill(HIST("MC/diffvsZ/TOF"), eventtimeMC - trk.evTimeTOF(), collisionMC.posZ()); + } + } + PROCESS_SWITCH(tofPidCollisionTimeQa, processMC, "Process MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFMC.cxx b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFMC.cxx new file mode 100644 index 00000000000..73d1c72ad1e --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFMC.cxx @@ -0,0 +1,757 @@ +// 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 qaPIDTOFMC.cxx +/// \author Nicolò Jacazio +/// \brief Task to produce QA output of the PID with TOF running on the MC e.g. to compute purity. +/// + +// O2 includes +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StaticFor.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::track; + +static constexpr int Np = 9; +static constexpr int NpNp = Np * Np; + +std::array, Np> hParticlePt; +std::array, Np> hParticleP; +std::array, Np> hParticleEta; + +std::array, Np> hTrackPt; +std::array, Np> hTrackP; +std::array, Np> hTrackEta; +std::array, Np> hTrackLength; + +std::array, Np> hSignalMC; +std::array, Np> hSignalMCprm; +std::array, Np> hSignalMCstr; +std::array, Np> hSignalMCmat; + +std::array, Np> hNSigma; +std::array, Np> hNSigmaprm; +std::array, Np> hNSigmastr; +std::array, Np> hNSigmamat; + +std::array, NpNp> hNSigmaMC; +std::array, NpNp> hNSigmaMCprm; +std::array, NpNp> hNSigmaMCstr; +std::array, NpNp> hNSigmaMCmat; + +std::array, NpNp> hDeltaMCEvTime; +std::array, NpNp> hDeltaMCEvTimeTrueGoodEv; +std::array, NpNp> hDeltaMCEvTimeTrueBadEv; +std::array, NpNp> hDeltaMCEvTimeprm; +std::array, NpNp> hDeltaMCEvTimestr; +std::array, NpNp> hDeltaMCEvTimemat; + +std::array, NpNp> hDeltaMCEvTimeMC; +std::array, NpNp> hDeltaMCEvTimeMCprm; +std::array, NpNp> hDeltaMCEvTimeMCstr; +std::array, NpNp> hDeltaMCEvTimeMCmat; +std::array, NpNp> hDeltaMCEvTimeMCGoodMatch; +std::array, NpNp> hDeltaMCEvTimeMCBadMatch; + +std::array, NpNp> hDeltaExpTimeMC; + +template +double calculateTimeOfFlight(double momentum, double length) +{ + static constexpr float mass = pid_constants::sMasses[id]; + static constexpr float c = o2::constants::physics::LightSpeedCm2PS; + // Calculate the Lorentz factor gamma + const float gamma = std::sqrt(1 + std::pow(momentum / (mass * c), 2)); + + // Calculate velocity + double velocity = momentum / (gamma * mass); + + // Calculate time of flight + double timeOfFlight = length / velocity; + + return timeOfFlight; +} + +/// Task to produce the TOF QA plots +struct pidTofQaMc { + SliceCache cache; + static constexpr const char* pT[Np] = {"e", "#mu", "#pi", "K", "p", "d", "t", "^{3}He", "#alpha"}; + static constexpr const char* pName[Np] = {"El", "Mu", "Pi", "Ka", "Pr", "De", "Tr", "He", "Al"}; + static constexpr int PDGs[Np] = {11, 13, 211, 321, 2212, 1000010020, 1000010030, 1000020030}; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable checkPrimaries{"checkPrimaries", 1, + "Whether to check physical primary and secondaries particles for the resolution."}; + Configurable pdgSign{"pdgSign", 0, "Sign of the PDG, -1 0 or 1"}; + Configurable doEl{"doEl", 0, "Process electrons"}; + Configurable doMu{"doMu", 0, "Process muons"}; + Configurable doPi{"doPi", 0, "Process pions"}; + Configurable doKa{"doKa", 0, "Process kaons"}; + Configurable doPr{"doPr", 0, "Process protons"}; + Configurable doDe{"doDe", 0, "Process deuterons"}; + Configurable doTr{"doTr", 0, "Process tritons"}; + Configurable doHe{"doHe", 0, "Process helium3"}; + Configurable doAl{"doAl", 0, "Process alpha"}; + ConfigurableAxis binsPt{"binsPt", {2000, 0.f, 20.f}, "Binning of the pT axis"}; + ConfigurableAxis binsNsigma{"binsNsigma", {2000, -50.f, 50.f}, "Binning of the NSigma axis"}; + ConfigurableAxis binsDelta{"binsDelta", {2000, -500.f, 500.f}, "Binning of the Delta axis"}; + ConfigurableAxis binsSignal{"binsSignal", {6000, 0, 2000}, "Binning of the TPC signal axis"}; + ConfigurableAxis binsLength{"binsLength", {1000, 0, 3000}, "Binning of the Length axis"}; + ConfigurableAxis binsEta{"binsEta", {100, -4, 4}, "Binning of the Eta axis"}; + Configurable minEta{"minEta", -0.8, "Minimum eta in range"}; + Configurable maxEta{"maxEta", 0.8, "Maximum eta in range"}; + Configurable nMinNumberOfContributors{"nMinNumberOfContributors", 2, "Minimum required number of contributors to the vertex"}; + Configurable logAxis{"logAxis", 0, "Flag to use a logarithmic pT axis, in this case the pT limits are the expontents"}; // TODO: support log axis + + template + void addParticleHistos(const AxisSpec& ptAxis, const AxisSpec& pAxis, const AxisSpec& signalAxis) + { + switch (mcID) { + case 0: + if (!doEl) { + return; + } + break; + case 1: + if (!doMu) { + return; + } + break; + case 2: + if (!doPi) { + return; + } + break; + case 3: + if (!doKa) { + return; + } + break; + case 4: + if (!doPr) { + return; + } + break; + case 5: + if (!doDe) { + return; + } + break; + case 6: + if (!doTr) { + return; + } + break; + case 7: + if (!doHe) { + return; + } + break; + case 8: + if (!doAl) { + return; + } + break; + default: + LOG(fatal) << "Can't interpret index"; + } + + const AxisSpec lengthAxis{binsLength, "Track length (cm)"}; + const AxisSpec etaAxis{binsEta, "#it{#eta}"}; + const AxisSpec nSigmaAxis{binsNsigma, Form("N_{#sigma}^{TOF}(%s)", pT[mcID])}; + const AxisSpec deltaAxis{binsDelta, Form("#Delta^{TOF}(%s)", pT[mcID])}; + const AxisSpec deltaLengthAxis{binsDelta, Form("t_{exp}(%s)-t_{exp}^{*}(%s)", pT[mcID], pT[mcID])}; + + // Particle info + hParticlePt[mcID] = histos.add(Form("particlept/%s", pName[mcID]), pT[mcID], kTH1D, {ptAxis}); + hParticleP[mcID] = histos.add(Form("particlep/%s", pName[mcID]), pT[mcID], kTH1D, {pAxis}); + hParticleEta[mcID] = histos.add(Form("particleeta/%s", pName[mcID]), pT[mcID], kTH1D, {etaAxis}); + + // Track info + hTrackPt[mcID] = histos.add(Form("trackpt/%s", pName[mcID]), pT[mcID], kTH1D, {ptAxis}); + hTrackP[mcID] = histos.add(Form("trackp/%s", pName[mcID]), pT[mcID], kTH1D, {pAxis}); + hTrackEta[mcID] = histos.add(Form("tracketa/%s", pName[mcID]), pT[mcID], kTH1D, {etaAxis}); + hTrackLength[mcID] = histos.add(Form("tracklength/%s", pName[mcID]), pT[mcID], kTH1D, {lengthAxis}); + + // NSigma + hSignalMC[mcID] = histos.add(Form("signalMC/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {pAxis, signalAxis}); + hNSigma[mcID] = histos.add(Form("nsigma/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {ptAxis, nSigmaAxis}); + hDeltaMCEvTime[mcID] = histos.add(Form("deltamcevtime/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {ptAxis, deltaAxis}); + hDeltaMCEvTimeTrueGoodEv[mcID] = histos.add(Form("deltamcevtimegoodev/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {ptAxis, deltaAxis}); + hDeltaMCEvTimeTrueBadEv[mcID] = histos.add(Form("deltamcevtimebadev/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {ptAxis, deltaAxis}); + hDeltaMCEvTimeMC[mcID] = histos.add(Form("deltamcevtimeMC/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {ptAxis, deltaAxis}); + hDeltaMCEvTimeMCGoodMatch[mcID] = histos.add(Form("deltamcevtimeMCgm/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {ptAxis, deltaAxis}); + hDeltaMCEvTimeMCBadMatch[mcID] = histos.add(Form("deltamcevtimeMCbm/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {ptAxis, deltaAxis}); + + hDeltaExpTimeMC[mcID] = histos.add(Form("deltaexptimeMC/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {ptAxis, deltaLengthAxis}); + + if (!checkPrimaries) { + return; + } + hSignalMCprm[mcID] = histos.add(Form("signalMCprm/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {pAxis, signalAxis}); + hSignalMCstr[mcID] = histos.add(Form("signalMCstr/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {pAxis, signalAxis}); + hSignalMCmat[mcID] = histos.add(Form("signalMCmat/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {pAxis, signalAxis}); + + hNSigmaprm[mcID] = histos.add(Form("nsigmaprm/%s", pName[mcID]), Form("Primary %s", pT[mcID]), HistType::kTH2F, {ptAxis, nSigmaAxis}); + hNSigmastr[mcID] = histos.add(Form("nsigmastr/%s", pName[mcID]), Form("Secondary %s from decay", pT[mcID]), HistType::kTH2F, {ptAxis, nSigmaAxis}); + hNSigmamat[mcID] = histos.add(Form("nsigmamat/%s", pName[mcID]), Form("Secondary %s from material", pT[mcID]), HistType::kTH2F, {ptAxis, nSigmaAxis}); + + hDeltaMCEvTimeprm[mcID] = histos.add(Form("deltamcevtimeprm/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {ptAxis, deltaAxis}); + hDeltaMCEvTimestr[mcID] = histos.add(Form("deltamcevtimestr/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {ptAxis, deltaAxis}); + hDeltaMCEvTimemat[mcID] = histos.add(Form("deltamcevtimemat/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {ptAxis, deltaAxis}); + + hDeltaMCEvTimeMCprm[mcID] = histos.add(Form("deltamcevtimeMCprm/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {ptAxis, deltaAxis}); + hDeltaMCEvTimeMCstr[mcID] = histos.add(Form("deltamcevtimeMCstr/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {ptAxis, deltaAxis}); + hDeltaMCEvTimeMCmat[mcID] = histos.add(Form("deltamcevtimeMCmat/%s", pName[mcID]), pT[mcID], HistType::kTH2F, {ptAxis, deltaAxis}); + } + + template + void addParticleMCHistos(const AxisSpec& ptAxis, const AxisSpec&, const AxisSpec&) + { + switch (mcID) { + case 0: + if (!doEl) { + return; + } + break; + case 1: + if (!doMu) { + return; + } + break; + case 2: + if (!doPi) { + return; + } + break; + case 3: + if (!doKa) { + return; + } + break; + case 4: + if (!doPr) { + return; + } + break; + case 5: + if (!doDe) { + return; + } + break; + case 6: + if (!doTr) { + return; + } + break; + case 7: + if (!doHe) { + return; + } + break; + case 8: + if (!doAl) { + return; + } + break; + default: + LOG(fatal) << "Can't interpret index"; + } + + const AxisSpec nSigmaAxis{binsNsigma, Form("N_{#sigma}^{TOF}(%s)", pT[massID])}; + + hNSigmaMC[mcID * Np + massID] = histos.add(Form("nsigmaMC/%s/%s", pName[mcID], pName[massID]), pT[mcID], HistType::kTH2F, {ptAxis, nSigmaAxis}); + if (checkPrimaries) { + hNSigmaMCprm[mcID * Np + massID] = histos.add(Form("nsigmaMCprm/%s/%s", pName[mcID], pName[massID]), pT[mcID], HistType::kTH2F, {ptAxis, nSigmaAxis}); + hNSigmaMCstr[mcID * Np + massID] = histos.add(Form("nsigmaMCstr/%s/%s", pName[mcID], pName[massID]), pT[mcID], HistType::kTH2F, {ptAxis, nSigmaAxis}); + hNSigmaMCmat[mcID * Np + massID] = histos.add(Form("nsigmaMCmat/%s/%s", pName[mcID], pName[massID]), pT[mcID], HistType::kTH2F, {ptAxis, nSigmaAxis}); + } + } + + void init(o2::framework::InitContext&) + { + AxisSpec pAxis{binsPt, "#it{p} (GeV/#it{c})"}; + AxisSpec ptAxis{binsPt, "#it{p}_{T} (GeV/#it{c})"}; + if (logAxis) { + pAxis.makeLogarithmic(); + ptAxis.makeLogarithmic(); + } + const AxisSpec betaAxis{1000, 0, 1.2, "TOF #beta"}; + + histos.add("event/T0", ";Tracks with TOF;T0 (ps);Counts", HistType::kTH2F, {{1000, 0, 1000}, {1000, -1000, 1000}}); + + histos.add("event/vertexz", ";Vtx_{z} (cm);Entries", kTH1F, {{100, -20, 20}}); + histos.add("event/tofbadmatch", "", kTH1F, {ptAxis}); + histos.add("event/tofgoodmatch", "", kTH1F, {ptAxis}); + + static_for<0, 8>([&](auto i) { + static_for<0, 8>([&](auto j) { + addParticleMCHistos(ptAxis, pAxis, betaAxis); + }); + addParticleHistos(ptAxis, pAxis, betaAxis); + }); + + histos.add("event/tofbeta", "All", HistType::kTH2F, {pAxis, betaAxis}); + if (checkPrimaries) { + histos.add("event/tofbetaPrm", "Primaries", HistType::kTH2F, {pAxis, betaAxis}); + // histos.add("event/tofbetaSec", "Secondaries", HistType::kTH2F, {pAxis, betaAxis}); + histos.add("event/tofbetaStr", "Secondaries from weak decays", HistType::kTH2F, {pAxis, betaAxis}); + histos.add("event/tofbetaMat", "Secondaries from material", HistType::kTH2F, {pAxis, betaAxis}); + } + // Print output histograms statistics + LOG(info) << "Size of the histograms in qaPIDTOFMC"; + histos.print(); + } + + template + void fillParticleInfoForPdg(const T& particle) + { + switch (pdgSign.value) { + case 0: + if (std::abs(particle.pdgCode()) != PDGs[mcID]) { + return; + } + break; + case 1: + if (particle.pdgCode() != PDGs[mcID]) { + return; + } + break; + case 2: + if (particle.pdgCode() != -PDGs[mcID]) { + return; + } + break; + default: + LOG(fatal) << "Can't interpret pdgSign"; + } + switch (mcID) { + case 0: + if (!doEl) { + return; + } + break; + case 1: + if (!doMu) { + return; + } + break; + case 2: + if (!doPi) { + return; + } + break; + case 3: + if (!doKa) { + return; + } + break; + case 4: + if (!doPr) { + return; + } + break; + case 5: + if (!doDe) { + return; + } + break; + case 6: + if (!doTr) { + return; + } + break; + case 7: + if (!doHe) { + return; + } + break; + case 8: + if (!doAl) { + return; + } + break; + default: + LOG(fatal) << "Can't interpret index"; + } + + hParticlePt[mcID]->Fill(particle.pt()); + hParticleP[mcID]->Fill(particle.p()); + hParticleEta[mcID]->Fill(particle.p()); + } + + template + void fillTrackInfoForPdg(const T& track, const TT& particle) + { + switch (mcID) { + case 0: + if (!doEl) { + return; + } + break; + case 1: + if (!doMu) { + return; + } + break; + case 2: + if (!doPi) { + return; + } + break; + case 3: + if (!doKa) { + return; + } + break; + case 4: + if (!doPr) { + return; + } + break; + case 5: + if (!doDe) { + return; + } + break; + case 6: + if (!doTr) { + return; + } + break; + case 7: + if (!doHe) { + return; + } + break; + case 8: + if (!doAl) { + return; + } + break; + default: + LOG(fatal) << "Can't interpret index"; + } + + const float nsigma = o2::aod::pidutils::tofNSigma(track); + + // Fill for all + hNSigma[mcID]->Fill(track.pt(), nsigma); + float expTime = 0.f; + switch (mcID) { + case 0: + expTime = track.tofExpTimeEl(); + break; + case 1: + expTime = track.tofExpTimeMu(); + break; + case 2: + expTime = track.tofExpTimePi(); + break; + case 3: + expTime = track.tofExpTimeKa(); + break; + case 4: + expTime = track.tofExpTimePr(); + break; + case 5: + expTime = track.tofExpTimeDe(); + break; + case 6: + expTime = track.tofExpTimeTr(); + break; + case 7: + expTime = track.tofExpTimeHe(); + break; + case 8: + expTime = track.tofExpTimeAl(); + break; + default: + break; + } + const float delta = track.tofSignal() - expTime - particle.mcCollision().t() * 1000.f; + + hDeltaMCEvTime[mcID]->Fill(track.pt(), delta); + + if (checkPrimaries) { + if (!particle.isPhysicalPrimary()) { + if (particle.getProcess() == 4) { + hNSigmastr[mcID]->Fill(track.pt(), nsigma); + hDeltaMCEvTimestr[mcID]->Fill(track.pt(), delta); + } else { + hNSigmamat[mcID]->Fill(track.pt(), nsigma); + hDeltaMCEvTimemat[mcID]->Fill(track.pt(), delta); + } + } else { + hNSigmaprm[mcID]->Fill(track.pt(), nsigma); + hDeltaMCEvTimeprm[mcID]->Fill(track.pt(), delta); + } + } + + switch (pdgSign.value) { + case 0: + if (std::abs(particle.pdgCode()) != PDGs[mcID]) { + return; + } + break; + case 1: + if (particle.pdgCode() != PDGs[mcID]) { + return; + } + break; + case 2: + if (particle.pdgCode() != -PDGs[mcID]) { + return; + } + break; + default: + LOG(fatal) << "Can't interpret pdgSign"; + } + + // Track info + hTrackPt[mcID]->Fill(track.pt()); + hTrackP[mcID]->Fill(track.p()); + hTrackEta[mcID]->Fill(track.eta()); + hTrackLength[mcID]->Fill(track.length()); + + // PID info + const float beta = track.beta(); + // const float beta = track.tofBeta(); + hSignalMC[mcID]->Fill(track.p(), beta); + hDeltaMCEvTimeMC[mcID]->Fill(track.pt(), delta); + + if (track.mcMask() & (0x1 << 15) && track.mcMask() & (0x1 << 13)) { + hDeltaMCEvTimeMCBadMatch[mcID]->Fill(track.pt(), delta); + } else { + hDeltaMCEvTimeMCGoodMatch[mcID]->Fill(track.pt(), delta); + } + + // Check that the track collision and the particle collisions match + if (particle.isPhysicalPrimary()) { + if (track.template collision_as().mcCollision().globalIndex() != particle.mcCollision().globalIndex()) { + hDeltaMCEvTimeTrueBadEv[mcID]->Fill(track.pt(), delta); + } else { + hDeltaMCEvTimeTrueGoodEv[mcID]->Fill(track.pt(), delta); + } + } + + const float mcExpTime = calculateTimeOfFlight(track.tpcInnerParam(), track.length()); + // const float mcExpTime = calculateTimeOfFlight(particle.p(), track.length()); + hDeltaExpTimeMC[mcID]->Fill(track.pt(), expTime - mcExpTime); + + if (checkPrimaries) { + if (!particle.isPhysicalPrimary()) { + if (particle.getProcess() == 4) { + hSignalMCstr[mcID]->Fill(track.p(), beta); + hDeltaMCEvTimeMCstr[mcID]->Fill(track.pt(), delta); + } else { + hSignalMCmat[mcID]->Fill(track.p(), beta); + hDeltaMCEvTimeMCmat[mcID]->Fill(track.pt(), delta); + } + } else { + hSignalMCprm[mcID]->Fill(track.p(), beta); + hDeltaMCEvTimeMCprm[mcID]->Fill(track.pt(), delta); + } + } + } + + template + void fillPIDInfoForPdg(const T& track, const TT& particle) + { + switch (mcID) { + case 0: + if (!doEl) { + return; + } + break; + case 1: + if (!doMu) { + return; + } + break; + case 2: + if (!doPi) { + return; + } + break; + case 3: + if (!doKa) { + return; + } + break; + case 4: + if (!doPr) { + return; + } + break; + case 5: + if (!doDe) { + return; + } + break; + case 6: + if (!doTr) { + return; + } + break; + case 7: + if (!doHe) { + return; + } + break; + case 8: + if (!doAl) { + return; + } + break; + default: + LOG(fatal) << "Can't interpret index"; + } + + switch (pdgSign.value) { + case 0: + if (std::abs(particle.pdgCode()) != PDGs[mcID]) { + return; + } + break; + case 1: + if (particle.pdgCode() != PDGs[mcID]) { + return; + } + break; + case 2: + if (particle.pdgCode() != -PDGs[mcID]) { + return; + } + break; + default: + LOG(fatal) << "Can't interpret pdgSign"; + } + + const float nsigmaMassID = o2::aod::pidutils::tofNSigma(track); + + hNSigmaMC[mcID * Np + massID]->Fill(track.pt(), nsigmaMassID); + if (checkPrimaries) { + if (!particle.isPhysicalPrimary()) { + if (particle.getProcess() == 4) { + hNSigmaMCstr[mcID * Np + massID]->Fill(track.pt(), nsigmaMassID); + } else { + hNSigmaMCmat[mcID * Np + massID]->Fill(track.pt(), nsigmaMassID); + } + } else { + hNSigmaMCprm[mcID * Np + massID]->Fill(track.pt(), nsigmaMassID); + } + } + } + + using Trks = soa::Join; + using Colls = soa::Join; + Preslice perCol = aod::track::collisionId; + Preslice perMCCol = aod::mcparticle::mcCollisionId; + + void process(Colls const& collisions, + Trks& tracks, + aod::McParticles& mcParticles, + aod::McCollisions&) + { + for (const auto& collision : collisions) { + if (collision.numContrib() < nMinNumberOfContributors) { + return; + } + if (!collision.sel8()) { + continue; + } + if (!collision.has_mcCollision()) { + continue; + } + const auto particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, collision.mcCollision().globalIndex(), cache); + + for (const auto& p : particlesInCollision) { + static_for<0, 8>([&](auto i) { + fillParticleInfoForPdg(p); + }); + } + + const auto& tracksInCollision = tracks.sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + // tracksInCollision.bindExternalIndices(&mcParticles); + // const auto& tracksWithPid = soa::Attach(tracksInCollision); + // tracksInCollision.copyIndexBindings(tracksWithPid); + const float collisionTime_ps = collision.collisionTime() * 1000.f; + unsigned int nTracksWithTOF = 0; + for (const auto& track : tracksInCollision) { + // + if (!track.hasTOF()) { // Skipping tracks without TOF + continue; + } + if (track.eta() < minEta || track.eta() > maxEta) { + continue; + } + + nTracksWithTOF++; + + // Fill for all + // const float beta = track.tofBeta(); + const float beta = track.beta(); + histos.fill(HIST("event/tofbeta"), track.p(), beta); + if (!track.has_mcParticle()) { + continue; + } + + std::bitset<16> bits(track.mcMask()); + // LOG(info) << "Using bitset: " << bits; + if (bits[15]) { + histos.fill(HIST("event/tofbadmatch"), track.pt()); + } else { + histos.fill(HIST("event/tofgoodmatch"), track.pt()); + } + + const auto& particle = track.mcParticle(); + + if (checkPrimaries) { + if (!particle.isPhysicalPrimary()) { + // histos.fill(HIST("event/tofbetaSec"), track.p(), beta); + if (particle.getProcess() == 4) { + histos.fill(HIST("event/tofbetaStr"), track.tpcInnerParam(), track.tpcSignal()); + } else { + histos.fill(HIST("event/tofbetaMat"), track.tpcInnerParam(), track.tpcSignal()); + } + } else { + histos.fill(HIST("event/tofbetaPrm"), track.p(), beta); + } + } + + // Fill with PDG codes + static_for<0, 8>([&](auto i) { + static_for<0, 8>([&](auto j) { + fillPIDInfoForPdg(track, particle); + }); + fillTrackInfoForPdg(track, particle); + }); + } // track loop + histos.fill(HIST("event/T0"), nTracksWithTOF, collisionTime_ps); + histos.fill(HIST("event/vertexz"), collision.posZ()); + } // collision loop + } // process() +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/DPG/Tasks/AOTTrack/PID/TPC/CMakeLists.txt b/DPG/Tasks/AOTTrack/PID/TPC/CMakeLists.txt new file mode 100644 index 00000000000..01d69f64386 --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/TPC/CMakeLists.txt @@ -0,0 +1,26 @@ +# 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. + +# TPC +o2physics_add_dpl_workflow(pid-tpc-qa + SOURCES qaPIDTPC.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pid-tpc-qa-sig + SOURCES qaPIDTPCSignal.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pid-tpc-qa-mc + SOURCES qaPIDTPCMC.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/DPG/Tasks/AOTTrack/PID/qaPIDTPC.cxx b/DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPC.cxx similarity index 99% rename from DPG/Tasks/AOTTrack/PID/qaPIDTPC.cxx rename to DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPC.cxx index 40913b39b79..2794070498d 100644 --- a/DPG/Tasks/AOTTrack/PID/qaPIDTPC.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPC.cxx @@ -299,7 +299,7 @@ struct tpcPidQa { histos.fill(HIST("event/evsel"), 2); } - if (abs(collision.posZ()) > 10.f) { + if (std::abs(collision.posZ()) > 10.f) { return false; } if constexpr (fillHistograms) { @@ -396,7 +396,7 @@ struct tpcPidQa { } if (applyRapidityCut) { - if (abs(t.rapidity(PID::getMass(id))) > 0.5) { + if (std::abs(t.rapidity(PID::getMass(id))) > 0.5) { continue; } } diff --git a/DPG/Tasks/AOTTrack/PID/qaPIDTPCMC.cxx b/DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPCMC.cxx similarity index 99% rename from DPG/Tasks/AOTTrack/PID/qaPIDTPCMC.cxx rename to DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPCMC.cxx index e99f6a9116c..993c2f7b24c 100644 --- a/DPG/Tasks/AOTTrack/PID/qaPIDTPCMC.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPCMC.cxx @@ -303,6 +303,7 @@ struct pidTpcQaMc { histos.add(hnsigmaMCmat[mcID * Np + massID].data(), Form("True Secondary %s from material", pT[mcID]), HistType::kTH2F, {ptAxis, nSigmaAxis}); if constexpr (mcID == massID) { + histos.add(hsignalMC[mcID].data(), Form("%s", pT[mcID]), HistType::kTH2F, {pAxis, signalAxis}); histos.add(hsignalMCprm[mcID].data(), Form("Primary %s", pT[mcID]), HistType::kTH2F, {pAxis, signalAxis}); histos.add(hsignalMCstr[mcID].data(), Form("Secondary %s from decay", pT[mcID]), HistType::kTH2F, {pAxis, signalAxis}); histos.add(hsignalMCmat[mcID].data(), Form("Secondary %s from material", pT[mcID]), HistType::kTH2F, {pAxis, signalAxis}); diff --git a/DPG/Tasks/AOTTrack/PID/qaPIDTPCSignal.cxx b/DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPCSignal.cxx similarity index 52% rename from DPG/Tasks/AOTTrack/PID/qaPIDTPCSignal.cxx rename to DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPCSignal.cxx index 0c7183e86b6..bf8492b8036 100644 --- a/DPG/Tasks/AOTTrack/PID/qaPIDTPCSignal.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPCSignal.cxx @@ -30,29 +30,36 @@ using namespace o2::framework::expressions; /// Task to produce the TPC QA plots struct tpcPidQaSignal { HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + // Task configuration + Configurable runPerRunOutput{"runPerRunOutput", false, "Flag to produce run by run output for e.g. lite calibration purposes"}; + Configurable enabledEdxPerID{"enabledEdxPerID", false, "Flag to produce dE/dx per particle ID histograms"}; + Configurable enableITS{"enableITS", false, "Enable ITS plots"}; + // Histogram configuration Configurable logAxis{"logAxis", 1, "Flag to use a log momentum axis"}; Configurable nBinsP{"nBinsP", 3000, "Number of bins for the momentum"}; - Configurable runPerRunOutput{"runPerRunOutput", false, "Flag to produce run by run output for e.g. lite calibration purposes"}; - Configurable enabledEdxPerID{"enabledEdxPerID", false, "Flag to produce dE/dx per particle ID histograms"}; - Configurable trdSelection{"trdSelection", 0, "Flag for the TRD selection: -1 no TRD, 0 no selection, 1 TRD"}; - Configurable fractionOfEvents{"fractionOfEvents", 0.1f, "Downsampling factor for the events for derived data"}; Configurable minP{"minP", 0.01, "Minimum momentum in range"}; + Configurable maxP{"maxP", 20, "Maximum momentum in range"}; + ConfigurableAxis dEdxBins{"dEdxBins", {5000, 0.f, 5000.f}, "Binning in dE/dx"}; + + // Track selections + Configurable pidInTracking{"pidInTracking", -1, "PID in tracking"}; Configurable maxEta{"maxEta", 0.8, "Maximum eta in range"}; Configurable maxITSChi2{"maxITSChi2", 36, "Maximum chi2 in range"}; Configurable maxTPCChi2{"maxTPCChi2", 4, "Maximum chi2 in range"}; - Configurable maxP{"maxP", 20, "Maximum momentum in range"}; Configurable minITSCls{"minITSCls", 6, "Minimum number of ITS clusters"}; - Configurable pidInTracking{"pidInTracking", -1, "PID in tracking"}; - Configurable minTPCCls{"minTPCCls", 0, "Minimum number of TPC clusters"}; + Configurable trdSelection{"trdSelection", 0, "Flag for the TRD selection: -1 no TRD, 0 no selection, 1 TRD"}; + Configurable tofSelection{"tofSelection", 0, "Flag for the TOF selection: -1 no TOF, 0 no selection, 1 TOF"}; Configurable minTPCClsFindable{"minTPCClsFindable", 0, "Minimum number of TPC findable clusters"}; Configurable minCrossedRowsOverFindableCls{"minCrossedRowsOverFindableCls", 0.8f, "Minimum number of TPC found/findable clusters"}; - ConfigurableAxis dEdxBins{"dEdxBins", {5000, 0.f, 5000.f}, "Binning in dE/dx"}; Configurable minTPCNcls{"minTPCNcls", 0.f, "Minimum number or TPC Clusters for tracks"}; Configurable minNClsCrossedRows{"minNClsCrossedRows", 70.f, "Minimum number or TPC crossed rows for tracks"}; - std::shared_ptr hdedx; - std::array, 9> hdedx_perID; + // Task variables + std::array, 2> mHistoDedx; + std::array, 9>, 2> mHistoDedxPerID; + std::array, 2> mHistoDedxwITS; + std::array, 9>, 2> mHistoDedxPerIDwITS; int lastRun = -1; unsigned int randomSeed = 0; void init(o2::framework::InitContext&) @@ -64,40 +71,78 @@ struct tpcPidQaSignal { pAxis.makeLogarithmic(); } const AxisSpec dedxAxis{dEdxBins, "d#it{E}/d#it{x} Arb. units"}; - const AxisSpec chargeAxis{2, -2.f, 2.f, "Charge"}; // Event properties - auto h = histos.add("event/evsel", "", kTH1D, {{10, 0.5, 10.5, "Ev. Sel."}}); - h->GetXaxis()->SetBinLabel(1, "Events read"); - h->GetXaxis()->SetBinLabel(2, "Passed ev. sel."); - h->GetXaxis()->SetBinLabel(3, "Passed vtx Z"); + auto hevsel = histos.add("event/evsel", "", kTH1D, {{10, 0.5, 10.5, "Ev. Sel."}}); + hevsel->GetXaxis()->SetBinLabel(1, "Events read"); + hevsel->GetXaxis()->SetBinLabel(2, "Passed ev. sel."); + hevsel->GetXaxis()->SetBinLabel(3, "Passed vtx Z"); - // Event properties - h = histos.add("trksel", "", kTH1D, {{10, 0.5, 10.5, "Trk. Sel."}}); - h->GetXaxis()->SetBinLabel(1, "Tracks read"); - h->GetXaxis()->SetBinLabel(2, Form("Has > %i ITS clusters", minITSCls.value)); - h->GetXaxis()->SetBinLabel(3, Form("Has > %i TPC clusters findable", minTPCClsFindable.value)); - h->GetXaxis()->SetBinLabel(4, Form("Has > %f TPC clusters found", minTPCNcls.value)); - h->GetXaxis()->SetBinLabel(5, Form("Has > %f Found/Findable Ratio", minCrossedRowsOverFindableCls.value)); - h->GetXaxis()->SetBinLabel(6, Form("Has > %f Xrows", minNClsCrossedRows.value)); - h->GetXaxis()->SetBinLabel(7, "All PID in trk"); + // Track properties + auto htrksel = histos.add("trksel", "", kTH1D, {{10, 0.5, 10.5, "Trk. Sel."}}); + htrksel->GetXaxis()->SetBinLabel(1, "Tracks read"); + htrksel->GetXaxis()->SetBinLabel(2, Form("Has > %i ITS clusters", minITSCls.value)); + htrksel->GetXaxis()->SetBinLabel(3, Form("Has > %i TPC clusters findable", minTPCClsFindable.value)); + htrksel->GetXaxis()->SetBinLabel(4, Form("Has > %f TPC clusters found", minTPCNcls.value)); + htrksel->GetXaxis()->SetBinLabel(5, Form("Has > %f Found/Findable Ratio", minCrossedRowsOverFindableCls.value)); + htrksel->GetXaxis()->SetBinLabel(6, Form("Has > %f Xrows", minNClsCrossedRows.value)); + htrksel->GetXaxis()->SetBinLabel(7, "All PID in trk"); if (pidInTracking == -1) { - h->GetXaxis()->SetBinLabel(7, Form("PID in trk %i", pidInTracking.value)); + htrksel->GetXaxis()->SetBinLabel(7, Form("PID in trk %i", pidInTracking.value)); } - h->GetXaxis()->SetBinLabel(8, "no TRD sel."); - if (trdSelection == -1) { - h->GetXaxis()->SetBinLabel(8, "has no TRD"); - } else if (trdSelection == 1) { - h->GetXaxis()->SetBinLabel(8, "has TRD"); + htrksel->GetXaxis()->SetBinLabel(8, "no TRD sel."); + switch (trdSelection) { + case 0: + htrksel->GetXaxis()->SetBinLabel(8, "no TRD sel."); + break; + case -1: + htrksel->GetXaxis()->SetBinLabel(8, "has no TRD"); + break; + case 1: + htrksel->GetXaxis()->SetBinLabel(8, "has TRD"); + break; + default: + LOG(fatal) << "Invalid TRD selection " << trdSelection; + } + switch (tofSelection) { + case 0: + htrksel->GetXaxis()->SetBinLabel(9, "no TOF sel."); + break; + case -1: + htrksel->GetXaxis()->SetBinLabel(9, "has no TOF"); + break; + case 1: + htrksel->GetXaxis()->SetBinLabel(9, "has TOF"); + break; + default: + LOG(fatal) << "Invalid TRD selection " << trdSelection; } histos.add("event/vertexz", "", kTH1D, {vtxZAxis}); - hdedx = histos.add("event/tpcsignal", "", kTH3D, {pAxis, dedxAxis, chargeAxis}); - if (enabledEdxPerID) { - for (int i = 0; i < 9; i++) { - hdedx_perID[i] = histos.add(Form("event/tpcsignal_%i", i), "", kTH3D, {pAxis, dedxAxis, chargeAxis}); + + const AxisSpec itsAxis{20, -0.5, 19.5, ""}; + if (enableITS) { + if (enabledEdxPerID) { + for (int i = 0; i < 9; i++) { + mHistoDedxPerIDwITS[0][i] = histos.add(Form("event/tpcsignalPos_%i", i), "", kTH3F, {pAxis, dedxAxis, itsAxis}); + mHistoDedxPerIDwITS[1][i] = histos.add(Form("event/tpcsignalNeg_%i", i), "", kTH3F, {pAxis, dedxAxis, itsAxis}); + } + } else { + mHistoDedxwITS[0] = histos.add("event/tpcsignalPos", "", kTH3F, {pAxis, dedxAxis, itsAxis}); + mHistoDedxwITS[1] = histos.add("event/tpcsignalNeg", "", kTH3F, {pAxis, dedxAxis, itsAxis}); + } + } else { + if (enabledEdxPerID) { + for (int i = 0; i < 9; i++) { + mHistoDedxPerID[0][i] = histos.add(Form("event/tpcsignalPos_%i", i), "", kTH2D, {pAxis, dedxAxis}); + mHistoDedxPerID[1][i] = histos.add(Form("event/tpcsignalNeg_%i", i), "", kTH2D, {pAxis, dedxAxis}); + } + } else { + mHistoDedx[0] = histos.add("event/tpcsignalPos", "", kTH2D, {pAxis, dedxAxis}); + mHistoDedx[1] = histos.add("event/tpcsignalNeg", "", kTH2D, {pAxis, dedxAxis}); } } + LOG(info) << "QA PID TPC histograms:"; histos.print(); } @@ -126,7 +171,7 @@ struct tpcPidQaSignal { return false; } histos.fill(HIST("trksel"), 6); - if (pidInTracking != -1 && (track.pidForTracking() != std::abs(pidInTracking))) { + if (pidInTracking != -1 && (track.pidForTracking() != static_cast(std::abs(pidInTracking)))) { return false; } histos.fill(HIST("trksel"), 7); @@ -147,9 +192,68 @@ struct tpcPidQaSignal { LOG(fatal) << "Invalid TRD selection"; } histos.fill(HIST("trksel"), 8); + switch (tofSelection) { + case 0: + break; + case -1: + if (track.hasTOF()) { + return false; + } + break; + case 1: + if (!track.hasTOF()) { + return false; + } + break; + default: + LOG(fatal) << "Invalid TOF selection"; + } + histos.fill(HIST("trksel"), 9); return true; } + template + void processTracks(const T& tracks) + { + for (const auto& t : tracks) { + if (!t.has_collision()) { + continue; + } + if (std::abs(t.collision().posZ()) > 10.f) { + continue; + } + if (!isTrackSelected(t)) { + continue; + } + + const int signIdx = t.sign() > 0 ? 0 : 1; + if (enableITS) { + float average = 0; + int n = 0; + for (int i = 0; i < 7; i++) { + if (t.itsClsSizeInLayer(i) <= 0) { + continue; + } + average += t.itsClsSizeInLayer(i); + n++; + } + average = n > 0 ? average / n : 0; + average *= cos(atan(t.tgl())); + if (enabledEdxPerID) { + mHistoDedxPerIDwITS[signIdx][t.pidForTracking()]->Fill(t.tpcInnerParam(), t.tpcSignal(), average); + } else { + mHistoDedxwITS[signIdx]->Fill(t.tpcInnerParam(), t.tpcSignal(), average); + } + } else { + if (enabledEdxPerID) { + mHistoDedxPerID[signIdx][t.pidForTracking()]->Fill(t.tpcInnerParam(), t.tpcSignal()); + } else { + mHistoDedx[signIdx]->Fill(t.tpcInnerParam(), t.tpcSignal()); + } + } + } + } + Filter trackFilterEta = (nabs(aod::track::eta) < maxEta); Filter trackFilterITS = (aod::track::itsChi2NCl < maxITSChi2); Filter trackFilterTPC = ((aod::track::tpcChi2NCl < maxTPCChi2)); @@ -158,10 +262,6 @@ struct tpcPidQaSignal { soa::Filtered const& tracks, aod::BCs const&) { - if (fractionOfEvents < 1.f && (static_cast(rand_r(&randomSeed)) / static_cast(RAND_MAX)) > fractionOfEvents) { // Skip events that are not sampled - return; - } - histos.fill(HIST("event/evsel"), 1); if (!collision.sel8()) { return; @@ -169,76 +269,31 @@ struct tpcPidQaSignal { histos.fill(HIST("event/evsel"), 2); - if (abs(collision.posZ()) > 10.f) { + if (std::abs(collision.posZ()) > 10.f) { return; } histos.fill(HIST("event/evsel"), 3); histos.fill(HIST("event/vertexz"), collision.posZ()); - - for (const auto& t : tracks) { - if (!isTrackSelected(t)) { - continue; - } - switch (trdSelection) { - case 0: - break; - case -1: - if (t.hasTRD()) { - continue; - } - break; - case 1: - if (!t.hasTRD()) { - continue; - } - break; - default: - LOG(fatal) << "Invalid TRD selection"; - } - if (runPerRunOutput.value == true && lastRun != collision.bc().runNumber()) { - lastRun = collision.bc().runNumber(); - AxisSpec pAxis{nBinsP, minP, maxP, "#it{p}/|Z| (GeV/#it{c})"}; - if (logAxis) { - pAxis.makeLogarithmic(); - } - const AxisSpec dedxAxis{dEdxBins, "d#it{E}/d#it{x} Arb. units"}; - const AxisSpec chargeAxis{2, -2.f, 2.f, "Charge"}; - hdedx = histos.add(Form("Run%i/tpcsignal", lastRun), "", kTH3D, {pAxis, dedxAxis, chargeAxis}); - } - hdedx->Fill(t.tpcInnerParam(), t.tpcSignal(), t.sign()); - if (enabledEdxPerID) { - hdedx_perID[t.pidForTracking()]->Fill(t.tpcInnerParam(), t.tpcSignal(), t.sign()); - } - } + processTracks(tracks); } PROCESS_SWITCH(tpcPidQaSignal, processEvSel, "Process with event selection", false); void processNoEvSel(soa::Filtered const& tracks, aod::Collisions const& collisions) { - if (fractionOfEvents < 1.f && (static_cast(rand_r(&randomSeed)) / static_cast(RAND_MAX)) > fractionOfEvents) { // Skip events that are not sampled - return; - } - histos.fill(HIST("event/evsel"), 1, collisions.size()); - - for (const auto& t : tracks) { - if (!t.has_collision()) { - continue; - } - if (abs(t.collision().posZ()) > 10.f) { - continue; - } - if (!isTrackSelected(t)) { - continue; - } - - hdedx->Fill(t.tpcInnerParam(), t.tpcSignal(), t.sign()); - if (enabledEdxPerID) { - hdedx_perID[t.pidForTracking()]->Fill(t.tpcInnerParam(), t.tpcSignal(), t.sign()); - } - } + LOG(debug) << "Processing " << collisions.size() << " collisions with " << tracks.size() << " tracks"; + processTracks(tracks); } PROCESS_SWITCH(tpcPidQaSignal, processNoEvSel, "Process without event selection", true); + + Filter trackFilterTrksSel = requireGlobalTrackInFilter(); + void processMoreTrkSel(soa::Filtered> const& tracks, aod::Collisions const& collisions) + { + histos.fill(HIST("event/evsel"), 1, collisions.size()); + LOG(debug) << "Processing " << collisions.size() << " collisions with " << tracks.size() << " tracks"; + processTracks(tracks); + } + PROCESS_SWITCH(tpcPidQaSignal, processMoreTrkSel, "Process without event selection", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/DPG/Tasks/AOTTrack/PID/qaHMPID.cxx b/DPG/Tasks/AOTTrack/PID/qaHMPID.cxx deleted file mode 100644 index 0038bc59e3c..00000000000 --- a/DPG/Tasks/AOTTrack/PID/qaHMPID.cxx +++ /dev/null @@ -1,77 +0,0 @@ -// 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. - -// O2 includes -#include "ReconstructionDataFormats/Track.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Common/DataModel/TrackSelectionTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct pidHmpidQa { - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - Configurable nBinsP{"nBinsP", 500, "Number of momentum bins"}; - Configurable minP{"minP", 0.01f, "Minimum momentum plotted (GeV/c)"}; - Configurable maxP{"maxP", 10.f, "Maximum momentum plotted (GeV/c)"}; - Configurable maxDCA{"maxDCA", 3.f, "Maximum DCA xy use for the plot (cm)"}; - Configurable maxDistance{"maxDistance", 5.f, "Maximum HMPID distance between the track and the cluster (cm)"}; - Configurable minCharge{"minCharge", 120.f, "Minimum HMPID charge collected in the cluster"}; - - void init(o2::framework::InitContext&) - { - AxisSpec momAxis{nBinsP, minP, maxP}; - histos.add("hmpidSignal", "hmpidSignal", kTH1F, {{300, 0, 3000}}); - histos.add("hmpidXTrack", "hmpidXTrack", kTH1F, {{300, 0, 3000}}); - histos.add("hmpidYTrack", "hmpidYTrack", kTH1F, {{300, 0, 3000}}); - histos.add("hmpidXMip", "hmpidXMip", kTH1F, {{300, 0, 3000}}); - histos.add("hmpidYMip", "hmpidYMip", kTH1F, {{300, 0, 3000}}); - histos.add("hmpidNPhotons", "hmpidNPhotons", kTH1F, {{300, 0, 3000}}); - histos.add("hmpidQMip", "hmpidQMip", kTH1F, {{300, 200, 3200}}); - histos.add("hmpidClusSize", "hmpidClusSize", kTH1F, {{300, 0, 3000}}); - histos.add("hmpidMom", "hmpidMom", kTH1F, {{300, 0, 3000}}); - histos.add("hmpidPhotsCharge", "hmpidPhotsCharge", kTH2F, {{300, 0, 3000}, {300, 0, 3000}}); - } - - using TrackCandidates = soa::Join; - void process(const aod::HMPIDs& hmpids, - const TrackCandidates&, - const aod::Collisions&) - { - for (const auto& t : hmpids) { - if (t.track_as().isGlobalTrack() != (uint8_t) true) { - continue; - } - if (abs(t.track_as().dcaXY()) > maxDCA) { - continue; - } - - histos.fill(HIST("hmpidSignal"), t.hmpidSignal()); - histos.fill(HIST("hmpidXTrack"), t.hmpidXTrack()); - histos.fill(HIST("hmpidYTrack"), t.hmpidYTrack()); - histos.fill(HIST("hmpidXMip"), t.hmpidXMip()); - histos.fill(HIST("hmpidYMip"), t.hmpidYMip()); - histos.fill(HIST("hmpidNPhotons"), t.hmpidNPhotons()); - histos.fill(HIST("hmpidQMip"), t.hmpidQMip()); - histos.fill(HIST("hmpidClusSize"), t.hmpidClusSize()); - histos.fill(HIST("hmpidMom"), t.hmpidMom()); - for (int i = 0; i < 10; i++) { - histos.fill(HIST("hmpidPhotsCharge"), t.hmpidMom(), i); - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfg) { return WorkflowSpec{adaptAnalysisTask(cfg)}; } diff --git a/DPG/Tasks/AOTTrack/PID/qaPIDTOFEvTime.cxx b/DPG/Tasks/AOTTrack/PID/qaPIDTOFEvTime.cxx deleted file mode 100644 index 39e7f8aa57e..00000000000 --- a/DPG/Tasks/AOTTrack/PID/qaPIDTOFEvTime.cxx +++ /dev/null @@ -1,410 +0,0 @@ -// 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 qaPIDTOFEvTime.cxx -/// \author Nicolò Jacazio nicolo.jacazio@cern.ch -/// \brief Tasks of the TOF PID quantities for the event times -/// - -#include "TEfficiency.h" -#include "THashList.h" - -#include "Framework/HistogramRegistry.h" -#include "Framework/StaticFor.h" -#include "Framework/AnalysisTask.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/FT0Corrected.h" -#include "Common/TableProducer/PID/pidTOFBase.h" -#include "Framework/runDataProcessing.h" - -using namespace o2; -using namespace o2::framework; - -struct tofPidCollisionTimeQa { - ConfigurableAxis evTimeBins{"evTimeBins", {1000, -1000.f, 1000.f}, "Binning for the event time"}; - ConfigurableAxis evTimeDeltaBins{"evTimeDeltaBins", {1000, -1000.f, 1000.f}, "Binning for the delta between event times"}; - ConfigurableAxis evTimeResoBins{"evTimeResoBins", {1000, 0.f, 1000.f}, "Binning for the event time resolution"}; - ConfigurableAxis tofSignalBins{"tofSignalBins", {5000, 0.f, 100000.f}, "Binning for the TOF signal"}; - ConfigurableAxis pBins{"pBins", {200, 0.1f, 5.f}, "Binning for the momentum"}; - - Configurable nBinsMultiplicity{"nBinsMultiplicity", 1000, "Number of bins for the multiplicity"}; - Configurable rangeMultiplicity{"rangeMultiplicity", 1000.f, "Range for the multiplicity"}; - Configurable logAxis{"logAxis", 0, "Flag to use a log momentum axis"}; - Configurable minPReso{"minPReso", 1.4f, "Minimum momentum in range for the resolution plot"}; - Configurable maxPReso{"maxPReso", 1.5f, "Maximum momentum in range for the resolution plot"}; - Configurable enableDebug{"enableDebug", false, "Add debug plots"}; - - OutputObj listEfficiency{"Efficiency"}; - - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - void init(o2::framework::InitContext&) - { - const AxisSpec evTimeAxis{evTimeBins, "Event time (ps)"}; - const AxisSpec evTimeDeltaAxis{evTimeDeltaBins, "Delta event time (ps)"}; - const AxisSpec multAxis{nBinsMultiplicity, 0, rangeMultiplicity, "Track multiplicity for TOF event time"}; - const AxisSpec evTimeResoAxis{evTimeResoBins, "Event time resolution (ps)"}; - const AxisSpec tofSignalAxis{tofSignalBins, "TOF signal (ps)"}; - AxisSpec pAxis{pBins, "#it{p} GeV/#it{c}"}; - AxisSpec ptAxis{pBins, "#it{p}_{T} GeV/#it{c}"}; - if (logAxis) { - pAxis.makeLogarithmic(); - ptAxis.makeLogarithmic(); - } - const AxisSpec collisionAxis{6000, -0.5f, 6000.f - .5f, "Collision index % 6000"}; - const AxisSpec massAxis{1000, 0, 3, "TOF mass (GeV/#it{c}^{2})"}; - const AxisSpec betaAxis{1000, 0, 1.5, "TOF #beta"}; - const AxisSpec deltaAxis{1000, -10000, 10000, "t-t_{ev}-t_{exp}(#pi) (ps)"}; - const AxisSpec lengthAxis{1000, 0, 600, "Track length (cm)"}; - - auto h = histos.add("eventSelection", "eventSelection", kTH1F, {{10, 0, 10, "Cut passed"}}); - h->GetXaxis()->SetBinLabel(1, "Events read"); - h->GetXaxis()->SetBinLabel(2, "Event selection"); - h->GetXaxis()->SetBinLabel(3, "#sigma_{Ev. time} < 200 ps"); - h->GetXaxis()->SetBinLabel(4, "#sigma_{Ev. time} > 200 ps"); - h = histos.add("trackSelection", "trackSelection", kTH1F, {{10, 0, 10, "Cut passed"}}); - h->GetXaxis()->SetBinLabel(1, "Tracks read"); - h->GetXaxis()->SetBinLabel(2, "Track selection"); - h->GetXaxis()->SetBinLabel(3, "hasITS"); - h->GetXaxis()->SetBinLabel(4, "hasTPC"); - h->GetXaxis()->SetBinLabel(5, "hasTOF"); - histos.add("deltaEvTimeTOFT0A", "deltaEvTimeTOFT0A", kTH1F, {evTimeDeltaAxis})->GetXaxis()->SetTitle("Ev. time_{TOF} - Ev. time_{T0A} (ps)"); - histos.add("deltaEvTimeTOFT0C", "deltaEvTimeTOFT0C", kTH1F, {evTimeDeltaAxis})->GetXaxis()->SetTitle("Ev. time_{TOF} - Ev. time_{T0C} (ps)"); - histos.add("deltaEvTimeTOFT0AC", "deltaEvTimeTOFT0AC", kTH1F, {evTimeDeltaAxis})->GetXaxis()->SetTitle("Ev. time_{TOF} - Ev. time_{T0AC} (ps)"); - auto h2 = histos.add("deltaEvTimeTOFT0AvsT0C", "deltaEvTimeTOFT0AvsT0C", kTH2F, {evTimeDeltaAxis, evTimeDeltaAxis}); - h2->GetXaxis()->SetTitle("Ev. time_{TOF} - Ev. time_{T0A} (ps)"); - h2->GetYaxis()->SetTitle("Ev. time_{TOF} - Ev. time_{T0C} (ps)"); - h2 = histos.add("deltaEvTimeTOFT0AvsTOF", "deltaEvTimeTOFT0AvsTOF", kTH2F, {evTimeAxis, evTimeDeltaAxis}); - h2->GetXaxis()->SetTitle("Ev. time_{TOF} (ps)"); - h2->GetYaxis()->SetTitle("Ev. time_{TOF} - Ev. time_{T0A} (ps)"); - h2 = histos.add("deltaEvTimeTOFT0CvsTOF", "deltaEvTimeTOFT0CvsTOF", kTH2F, {evTimeAxis, evTimeDeltaAxis}); - h2->GetXaxis()->SetTitle("Ev. time_{TOF} (ps)"); - h2->GetYaxis()->SetTitle("Ev. time_{TOF} - Ev. time_{T0C} (ps)"); - h2 = histos.add("deltaEvTimeTOFT0ACvsTOF", "deltaEvTimeTOFT0ACvsTOF", kTH2F, {evTimeAxis, evTimeDeltaAxis}); - h2->GetXaxis()->SetTitle("Ev. time_{TOF} (ps)"); - h2->GetYaxis()->SetTitle("Ev. time_{TOF} - Ev. time_{T0AC} (ps)"); - - histos.add("eventTime", "eventTime", kTH1F, {evTimeAxis}); - histos.add("eventTimeReso", "eventTimeReso", kTH1F, {evTimeResoAxis}); - histos.add("eventTimeVsMult", "eventTimeVsMult", kTH2F, {multAxis, evTimeAxis}); - histos.add("eventTimeResoVsMult", "eventTimeResoVsMult", kTH2F, {multAxis, evTimeResoAxis}); - - histos.add("eventTimeTOFMult", "eventTimeTOFMult", kTH1F, {multAxis}); - histos.add("eventTimeTOF", "eventTimeTOF", kTH1F, {evTimeAxis})->GetXaxis()->SetTitle("Ev. time_{TOF} (ps)"); - histos.add("eventTimeTOFReso", "eventTimeTOFReso", kTH1F, {evTimeResoAxis})->GetXaxis()->SetTitle("Ev. time_{TOF} resolution (ps)"); - histos.add("eventTimeTOFVsMult", "eventTimeTOFVsMult", kTH2F, {multAxis, evTimeAxis})->GetYaxis()->SetTitle("Ev. time_{TOF} (ps)"); - histos.add("eventTimeTOFResoVsMult", "eventTimeTOFResoVsMult", kTH2F, {multAxis, evTimeResoAxis})->GetYaxis()->SetTitle("Ev. time_{TOF} resolution (ps)"); - - histos.add("eventTimeT0A", "eventTimeT0A", kTH1F, {evTimeAxis})->GetXaxis()->SetTitle("T0A event time (ps)"); - histos.add("eventTimeT0C", "eventTimeT0C", kTH1F, {evTimeAxis})->GetXaxis()->SetTitle("T0C event time (ps)"); - histos.add("eventTimeT0AC", "eventTimeT0AC", kTH1F, {evTimeAxis})->GetXaxis()->SetTitle("T0AC event time (ps)"); - histos.add("eventTimeT0ACReso", "eventTimeT0ACReso", kTH1F, {evTimeResoAxis})->GetXaxis()->SetTitle("T0AC event time resolution (ps)"); - - histos.add("collisionTime", "collisionTime", kTH1F, {evTimeResoAxis})->GetXaxis()->SetTitle("Collision time (ps)"); - histos.add("collisionTimeRes", "collisionTimeRes", kTH1F, {evTimeResoAxis})->GetXaxis()->SetTitle("Collision time resolution (ps)"); - - histos.add("tracks/p", "p", kTH1F, {pAxis}); - histos.add("tracks/pt", "pt", kTH1F, {ptAxis}); - histos.add("tracks/length", "length", kTH1F, {lengthAxis}); - - histos.add("deltaVsMult/pi", Form("pi %.2f < #it{p} < %.2f", minPReso.value, maxPReso.value), kTH2F, {multAxis, deltaAxis}); - histos.add("deltaVsReso/pi", Form("pi %.2f < #it{p} < %.2f", minPReso.value, maxPReso.value), kTH2F, {evTimeResoAxis, deltaAxis}); - - histos.add("tofbeta/inclusive", "", HistType::kTH2F, {pAxis, betaAxis}); - histos.add("tofbeta/EvTimeTOF", "Ev. Time TOF", HistType::kTH2F, {pAxis, betaAxis}); - histos.add("tofbeta/EvTimeTOFOnly", "Ev. Time TOF Only", HistType::kTH2F, {pAxis, betaAxis}); - histos.add("tofbeta/EvTimeT0AC", "Ev. Time T0AC", HistType::kTH2F, {pAxis, betaAxis}); - histos.add("tofbeta/EvTimeT0AOnly", "Ev. Time T0A Only", HistType::kTH2F, {pAxis, betaAxis}); - histos.add("tofbeta/EvTimeT0COnly", "Ev. Time T0A Only", HistType::kTH2F, {pAxis, betaAxis}); - histos.add("tofbeta/EvTimeT0ACOnly", "Ev. Time T0AC Only", HistType::kTH2F, {pAxis, betaAxis}); - - histos.add("tofmass/inclusive", "", HistType::kTH2F, {pAxis, massAxis}); - histos.add("tofmass/EvTimeTOF", "Ev. Time TOF", HistType::kTH2F, {pAxis, massAxis}); - histos.add("tofmass/EvTimeTOFOnly", "Ev. Time TOF Only", HistType::kTH2F, {pAxis, massAxis}); - histos.add("tofmass/EvTimeT0AC", "Ev. Time T0AC", HistType::kTH2F, {pAxis, massAxis}); - histos.add("tofmass/EvTimeT0AOnly", "Ev. Time T0A Only", HistType::kTH2F, {pAxis, massAxis}); - histos.add("tofmass/EvTimeT0COnly", "Ev. Time T0C Only", HistType::kTH2F, {pAxis, massAxis}); - histos.add("tofmass/EvTimeT0ACOnly", "Ev. Time T0AC Only", HistType::kTH2F, {pAxis, massAxis}); - - if (enableDebug) { - histos.add("withtof/p", "p", kTH1F, {pAxis}); - histos.add("withtof/pt", "pt", kTH1F, {ptAxis}); - histos.add("withtof/length", "length", kTH1F, {lengthAxis}); - histos.add("withtof/tofSignal", "tofSignal", kTH1F, {tofSignalAxis}); - histos.add("withtof/beta", "beta", kTH2F, {pAxis, betaAxis}); - histos.add("withtof/delta", "delta", kTH2F, {pAxis, deltaAxis}); - histos.add("withtof/expP", "expP", kTH2F, {pAxis, pAxis}); - histos.add("withtof/mass", "mass", kTH1F, {massAxis}); - histos.add("withtof/tofSignalPerCollision", "tofSignalPerCollision", kTH2S, {collisionAxis, tofSignalAxis}); - - histos.add("goodreso/p", "p", kTH1F, {pAxis}); - histos.add("goodreso/pt", "pt", kTH1F, {ptAxis}); - histos.add("goodreso/ptden", "ptden", kTH1F, {ptAxis}); - histos.add("goodreso/length", "length", kTH1F, {lengthAxis}); - histos.add("goodreso/tofSignal", "tofSignal", kTH1F, {tofSignalAxis}); - histos.add("goodreso/beta", "beta", kTH2F, {pAxis, betaAxis}); - histos.add("goodreso/delta", "delta", kTH2F, {pAxis, deltaAxis}); - histos.add("goodreso/expP", "expP", kTH2F, {pAxis, pAxis}); - histos.add("goodreso/mass", "mass", kTH1F, {massAxis}); - histos.add("goodreso/tofSignalPerCollision", "tofSignalPerCollision", kTH2S, {collisionAxis, tofSignalAxis}); - - histos.add("badreso/p", "p", kTH1F, {pAxis}); - histos.add("badreso/pt", "pt", kTH1F, {ptAxis}); - histos.add("badreso/ptden", "ptden", kTH1F, {ptAxis}); - histos.add("badreso/length", "length", kTH1F, {lengthAxis}); - histos.add("badreso/tofSignal", "tofSignal", kTH1F, {tofSignalAxis}); - histos.add("badreso/beta", "beta", kTH2F, {pAxis, betaAxis}); - histos.add("badreso/delta", "delta", kTH2F, {pAxis, deltaAxis}); - histos.add("badreso/expP", "expP", kTH2F, {pAxis, pAxis}); - histos.add("badreso/mass", "mass", kTH1F, {massAxis}); - histos.add("badreso/tofSignalPerCollision", "tofSignalPerCollision", kTH2S, {collisionAxis, tofSignalAxis}); - - histos.add("goodforevtime/tofSignal", "tofSignal", kTH1F, {tofSignalAxis}); - histos.add("goodforevtime/p", "p", kTH1F, {pAxis}); - histos.add("goodforevtime/pt", "pt", kTH1F, {ptAxis}); - histos.add("goodforevtime/length", "length", kTH1F, {lengthAxis}); - histos.add("goodforevtime/beta", "beta", kTH2F, {pAxis, betaAxis}); - histos.add("goodforevtime/delta", "delta", kTH2F, {pAxis, deltaAxis}); - histos.add("goodforevtime/expP", "expP", kTH2F, {pAxis, pAxis}); - histos.add("goodforevtime/mass", "mass", kTH1F, {massAxis}); - histos.add("goodforevtime/tofSignalPerCollision", "tofSignalPerCollision", kTH2S, {collisionAxis, tofSignalAxis}); - - histos.add("withqualitycuts/p", "p", kTH1F, {pAxis}); - histos.add("withqualitycuts/pt", "pt", kTH1F, {ptAxis}); - histos.add("withqualitycuts/length", "length", kTH1F, {lengthAxis}); - histos.add("withqualitycuts/mass", "mass", kTH1F, {massAxis}); - } - - listEfficiency.setObject(new THashList); - auto makeEfficiency = [&](TString effname, TString efftitle) { - listEfficiency->Add(new TEfficiency(effname, efftitle + ";TOF multiplicity;Efficiency", nBinsMultiplicity, 0, rangeMultiplicity)); - }; - - makeEfficiency("effTOFEvTime", "Efficiency of the TOF Event Time"); - makeEfficiency("effT0ACEvTime", "Efficiency of the T0AC Event Time"); - makeEfficiency("effTOFT0ACEvTime", "Efficiency of the TOF+T0AC Event Time"); - makeEfficiency("effT0AEvTime", "Efficiency of the T0A Event Time"); - makeEfficiency("effT0CEvTime", "Efficiency of the T0C Event Time"); - } - - using Trks = soa::Join; - using EvTimeCollisions = soa::Join; - // Define slice per collision - Preslice perCollision = aod::track::collisionId; - void process(Trks const& tracks, EvTimeCollisions const&) - { - static int ncolls = 0; - int lastCollisionId = -1; // Last collision ID analysed - for (auto& t : tracks) { - if (!t.has_collision()) { // Track was not assigned to a collision - continue; - } else if (t.collisionId() == lastCollisionId) { // Event was already processed - continue; - } - // Create new table for the tracks in a collision - lastCollisionId = t.collisionId(); /// Cache last collision ID - auto collision = t.collision_as(); - - histos.fill(HIST("eventSelection"), 0.5f); - histos.fill(HIST("eventSelection"), 1.5f); - if (t.tofEvTimeErr() > 199.f) { - histos.fill(HIST("eventSelection"), 2.5f); - } else { - histos.fill(HIST("eventSelection"), 3.5f); - } - histos.fill(HIST("eventTime"), t.tofEvTime()); - histos.fill(HIST("eventTimeReso"), t.tofEvTimeErr()); - histos.fill(HIST("eventTimeVsMult"), t.evTimeTOFMult(), t.tofEvTime()); - histos.fill(HIST("eventTimeResoVsMult"), t.evTimeTOFMult(), t.tofEvTimeErr()); - - if (t.isEvTimeTOF()) { - histos.fill(HIST("eventTimeTOF"), t.evTimeTOF()); - histos.fill(HIST("eventTimeTOFReso"), t.evTimeTOFErr()); - histos.fill(HIST("eventTimeTOFMult"), t.evTimeTOFMult()); - histos.fill(HIST("eventTimeTOFVsMult"), t.evTimeTOFMult(), t.evTimeTOF()); - histos.fill(HIST("eventTimeTOFResoVsMult"), t.evTimeTOFMult(), t.evTimeTOFErr()); - } - - if (collision.has_foundFT0()) { // T0 measurement is available - if (collision.t0ACorrectedValid()) { - histos.fill(HIST("eventTimeT0A"), collision.t0ACorrected() * 1000.f); - if (t.isEvTimeTOF()) { - histos.fill(HIST("deltaEvTimeTOFT0A"), t.evTimeTOF() - collision.t0ACorrected() * 1000.f); - histos.fill(HIST("deltaEvTimeTOFT0AvsTOF"), t.evTimeTOF(), t.evTimeTOF() - collision.t0ACorrected() * 1000.f); - } - } - if (collision.t0CCorrectedValid()) { - histos.fill(HIST("eventTimeT0C"), collision.t0CCorrected() * 1000.f); - if (t.isEvTimeTOF()) { - histos.fill(HIST("deltaEvTimeTOFT0C"), t.evTimeTOF() - collision.t0CCorrected() * 1000.f); - histos.fill(HIST("deltaEvTimeTOFT0CvsTOF"), t.evTimeTOF(), t.evTimeTOF() - collision.t0CCorrected() * 1000.f); - } - } - if (collision.t0ACValid()) { - histos.fill(HIST("eventTimeT0AC"), collision.t0AC() * 1000.f); - histos.fill(HIST("eventTimeT0ACReso"), collision.t0resolution() * 1000.f); - if (t.isEvTimeTOF()) { - histos.fill(HIST("deltaEvTimeTOFT0AC"), t.evTimeTOF() - collision.t0AC() * 1000.f); - histos.fill(HIST("deltaEvTimeTOFT0ACvsTOF"), t.evTimeTOF(), t.evTimeTOF() - collision.t0AC() * 1000.f); - } - } - if (collision.t0ACorrectedValid() && collision.t0CCorrectedValid() && t.isEvTimeTOF()) { - histos.fill(HIST("deltaEvTimeTOFT0AvsT0C"), t.evTimeTOF() - collision.t0ACorrected() * 1000.f, t.evTimeTOF() - collision.t0CCorrected() * 1000.f); - } - } - - histos.fill(HIST("collisionTime"), collision.collisionTime()); - histos.fill(HIST("collisionTimeRes"), collision.collisionTimeRes()); - ncolls++; - - const auto tracksInCollision = tracks.sliceBy(perCollision, lastCollisionId); - int nTracksWithTOF = 0; - for (auto const& trk : tracksInCollision) { // Loop on Tracks - histos.fill(HIST("trackSelection"), 0.5f); - - if (!trk.isGlobalTrack()) { - continue; - } - histos.fill(HIST("trackSelection"), 1.5f); - - if (!trk.hasITS()) { - continue; - } - histos.fill(HIST("trackSelection"), 2.5f); - if (!trk.hasTPC()) { - continue; - } - histos.fill(HIST("trackSelection"), 3.5f); - - histos.fill(HIST("tracks/p"), trk.p()); - histos.fill(HIST("tracks/pt"), trk.pt()); - histos.fill(HIST("tracks/length"), trk.length()); - - if (enableDebug) { - if (trk.tofEvTimeErr() > 199.f) { - histos.fill(HIST("badreso/ptden"), trk.pt()); - } else { - histos.fill(HIST("goodreso/ptden"), trk.pt()); - } - } - - if (!trk.hasTOF()) { - continue; - } - nTracksWithTOF++; - histos.fill(HIST("trackSelection"), 4.5f); - - // Recompute quantities with event times - const float& betaTOF = trk.evTimeTOFMult() > 1 ? o2::pid::tof::Beta::GetBeta(trk, trk.evTimeTOF()) : 999.f; - const float& betaT0A = collision.t0ACorrectedValid() ? o2::pid::tof::Beta::GetBeta(trk, collision.t0ACorrected() * 1000.f) : 999.f; - const float& betaT0C = collision.t0CCorrectedValid() ? o2::pid::tof::Beta::GetBeta(trk, collision.t0CCorrected() * 1000.f) : 999.f; - const float& betaT0AC = collision.t0ACValid() ? o2::pid::tof::Beta::GetBeta(trk, collision.t0AC() * 1000.f) : 999.f; - - const float& massTOF = trk.evTimeTOFMult() > 1 ? o2::pid::tof::TOFMass::GetTOFMass(trk, betaTOF) : 999.f; - const float& massT0A = collision.t0ACorrectedValid() ? o2::pid::tof::TOFMass::GetTOFMass(trk, betaT0A) : 999.f; - const float& massT0C = collision.t0CCorrectedValid() ? o2::pid::tof::TOFMass::GetTOFMass(trk, betaT0C) : 999.f; - const float& massT0AC = collision.t0ACValid() ? o2::pid::tof::TOFMass::GetTOFMass(trk, betaT0AC) : 999.f; - - const float& deltaPi = trk.tofSignal() - trk.tofEvTime() - o2::pid::tof::ExpTimes::GetExpectedSignal(trk); - - histos.fill(HIST("tofbeta/inclusive"), trk.p(), trk.beta()); - histos.fill(HIST("tofmass/inclusive"), trk.p(), trk.mass()); - if (trk.isEvTimeTOF()) { - histos.fill(HIST("tofbeta/EvTimeTOF"), trk.p(), trk.beta()); - histos.fill(HIST("tofmass/EvTimeTOF"), trk.p(), trk.mass()); - histos.fill(HIST("tofbeta/EvTimeTOFOnly"), trk.p(), betaTOF); - histos.fill(HIST("tofmass/EvTimeTOFOnly"), trk.p(), massTOF); - } - if (trk.isEvTimeT0AC()) { - histos.fill(HIST("tofbeta/EvTimeT0AC"), trk.p(), trk.beta()); - histos.fill(HIST("tofmass/EvTimeT0AC"), trk.p(), trk.mass()); - } - histos.fill(HIST("tofbeta/EvTimeT0AOnly"), trk.p(), betaT0A); - histos.fill(HIST("tofbeta/EvTimeT0COnly"), trk.p(), betaT0C); - histos.fill(HIST("tofbeta/EvTimeT0ACOnly"), trk.p(), betaT0AC); - - histos.fill(HIST("tofmass/EvTimeT0AOnly"), trk.p(), massT0A); - histos.fill(HIST("tofmass/EvTimeT0COnly"), trk.p(), massT0C); - histos.fill(HIST("tofmass/EvTimeT0ACOnly"), trk.p(), massT0AC); - - if (enableDebug) { - - histos.fill(HIST("withtof/p"), trk.p()); - histos.fill(HIST("withtof/pt"), trk.pt()); - histos.fill(HIST("withtof/length"), trk.length()); - histos.fill(HIST("withtof/tofSignal"), trk.tofSignal()); - histos.fill(HIST("withtof/beta"), trk.p(), trk.beta()); - histos.fill(HIST("withtof/delta"), trk.p(), deltaPi); - if (trk.p() > minPReso && trk.p() < maxPReso) { - histos.fill(HIST("deltaVsMult/pi"), trk.evTimeTOFMult(), deltaPi); - histos.fill(HIST("deltaVsReso/pi"), trk.evTimeTOFMult(), deltaPi); - } - - histos.fill(HIST("withtof/expP"), trk.p(), trk.tofExpMom()); - histos.fill(HIST("withtof/mass"), trk.mass()); - histos.fill(HIST("withtof/tofSignalPerCollision"), ncolls % 6000, trk.tofSignal()); - if (trk.pt() > 0.3 && trk.beta() > 0.3) { - histos.fill(HIST("withqualitycuts/p"), trk.p()); - histos.fill(HIST("withqualitycuts/pt"), trk.pt()); - histos.fill(HIST("withqualitycuts/length"), trk.length()); - histos.fill(HIST("withqualitycuts/mass"), trk.mass()); - } - - if (trk.tofEvTimeErr() > 199.f) { - histos.fill(HIST("badreso/p"), trk.p()); - histos.fill(HIST("badreso/pt"), trk.pt()); - histos.fill(HIST("badreso/length"), trk.length()); - histos.fill(HIST("badreso/tofSignal"), trk.tofSignal()); - histos.fill(HIST("badreso/beta"), trk.p(), trk.beta()); - histos.fill(HIST("badreso/delta"), trk.p(), deltaPi); - histos.fill(HIST("badreso/expP"), trk.p(), trk.tofExpMom()); - histos.fill(HIST("badreso/mass"), trk.mass()); - histos.fill(HIST("badreso/tofSignalPerCollision"), ncolls % 6000, trk.tofSignal()); - } else { - histos.fill(HIST("goodreso/p"), trk.p()); - histos.fill(HIST("goodreso/pt"), trk.pt()); - histos.fill(HIST("goodreso/length"), trk.length()); - histos.fill(HIST("goodreso/tofSignal"), trk.tofSignal()); - histos.fill(HIST("goodreso/beta"), trk.p(), trk.beta()); - histos.fill(HIST("goodreso/delta"), trk.p(), deltaPi); - histos.fill(HIST("goodreso/expP"), trk.p(), trk.tofExpMom()); - histos.fill(HIST("goodreso/mass"), trk.mass()); - histos.fill(HIST("goodreso/tofSignalPerCollision"), ncolls % 6000, trk.tofSignal()); - } - if (!trk.usedForTOFEvTime()) { - continue; - } - histos.fill(HIST("goodforevtime/p"), trk.p()); - histos.fill(HIST("goodforevtime/pt"), trk.pt()); - histos.fill(HIST("goodforevtime/length"), trk.length()); - histos.fill(HIST("goodforevtime/tofSignal"), trk.tofSignal()); - histos.fill(HIST("goodforevtime/beta"), trk.p(), trk.beta()); - histos.fill(HIST("goodforevtime/delta"), trk.p(), deltaPi); - histos.fill(HIST("goodforevtime/expP"), trk.p(), trk.tofExpMom()); - histos.fill(HIST("goodforevtime/mass"), trk.mass()); - histos.fill(HIST("goodforevtime/tofSignalPerCollision"), ncolls % 6000, trk.tofSignal()); - } - } - static_cast(listEfficiency->FindObject("effTOFEvTime"))->Fill(t.isEvTimeTOF(), nTracksWithTOF); - static_cast(listEfficiency->FindObject("effT0AEvTime"))->Fill(collision.has_foundFT0() && collision.t0ACorrectedValid(), nTracksWithTOF); - static_cast(listEfficiency->FindObject("effT0CEvTime"))->Fill(collision.has_foundFT0() && collision.t0CCorrectedValid(), nTracksWithTOF); - static_cast(listEfficiency->FindObject("effT0ACEvTime"))->Fill(collision.has_foundFT0() && collision.t0ACValid(), nTracksWithTOF); - static_cast(listEfficiency->FindObject("effTOFT0ACEvTime"))->Fill(t.isEvTimeTOF() && collision.has_foundFT0() && collision.t0ACorrectedValid(), nTracksWithTOF); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} diff --git a/DPG/Tasks/AOTTrack/PID/qaPIDTOFMC.cxx b/DPG/Tasks/AOTTrack/PID/qaPIDTOFMC.cxx deleted file mode 100644 index e841e057497..00000000000 --- a/DPG/Tasks/AOTTrack/PID/qaPIDTOFMC.cxx +++ /dev/null @@ -1,752 +0,0 @@ -// 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 qaPIDTOFMC.cxx -/// \author Nicolò Jacazio -/// \brief Task to produce QA output of the PID with TOF running on the MC. -/// - -// O2 includes -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/StaticFor.h" -#include "Common/DataModel/PIDResponse.h" -#include "Framework/runDataProcessing.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::track; - -/// Task to produce the TOF QA plots -struct pidTofQaMc { - SliceCache cache; - - static constexpr int Np = 9; - static constexpr int NpNp = Np * Np; - static constexpr std::string_view hparticlept[Np] = {"particlept/El", "particlept/Mu", "particlept/Pi", - "particlept/Ka", "particlept/Pr", "particlept/De", - "particlept/Tr", "particlept/He", "particlept/Al"}; - static constexpr std::string_view hparticlep[Np] = {"particlep/El", "particlep/Mu", "particlep/Pi", - "particlep/Ka", "particlep/Pr", "particlep/De", - "particlep/Tr", "particlep/He", "particlep/Al"}; - static constexpr std::string_view hparticleeta[Np] = {"particleeta/El", "particleeta/Mu", "particleeta/Pi", - "particleeta/Ka", "particleeta/Pr", "particleeta/De", - "particleeta/Tr", "particleeta/He", "particleeta/Al"}; - static constexpr std::string_view htrackpt[Np] = {"trackpt/El", "trackpt/Mu", "trackpt/Pi", - "trackpt/Ka", "trackpt/Pr", "trackpt/De", - "trackpt/Tr", "trackpt/He", "trackpt/Al"}; - static constexpr std::string_view htrackp[Np] = {"trackp/El", "trackp/Mu", "trackp/Pi", - "trackp/Ka", "trackp/Pr", "trackp/De", - "trackp/Tr", "trackp/He", "trackp/Al"}; - static constexpr std::string_view htracketa[Np] = {"tracketa/El", "tracketa/Mu", "tracketa/Pi", - "tracketa/Ka", "tracketa/Pr", "tracketa/De", - "tracketa/Tr", "tracketa/He", "tracketa/Al"}; - static constexpr std::string_view htracklength[Np] = {"tracklength/El", "tracklength/Mu", "tracklength/Pi", - "tracklength/Ka", "tracklength/Pr", "tracklength/De", - "tracklength/Tr", "tracklength/He", "tracklength/Al"}; - // Signal - static constexpr std::string_view hsignalMC[Np] = {"signalMC/El", "signalMC/Mu", "signalMC/Pi", - "signalMC/Ka", "signalMC/Pr", "signalMC/De", - "signalMC/Tr", "signalMC/He", "signalMC/Al"}; - static constexpr std::string_view hsignalMCprm[Np] = {"signalMCprm/El", "signalMCprm/Mu", "signalMCprm/Pi", - "signalMCprm/Ka", "signalMCprm/Pr", "signalMCprm/De", - "signalMCprm/Tr", "signalMCprm/He", "signalMCprm/Al"}; - static constexpr std::string_view hsignalMCstr[Np] = {"signalMCstr/El", "signalMCstr/Mu", "signalMCstr/Pi", - "signalMCstr/Ka", "signalMCstr/Pr", "signalMCstr/De", - "signalMCstr/Tr", "signalMCstr/He", "signalMCstr/Al"}; - static constexpr std::string_view hsignalMCmat[Np] = {"signalMCmat/El", "signalMCmat/Mu", "signalMCmat/Pi", - "signalMCmat/Ka", "signalMCmat/Pr", "signalMCmat/De", - "signalMCmat/Tr", "signalMCmat/He", "signalMCmat/Al"}; - // Nsigma - static constexpr std::string_view hnsigma[Np] = {"nsigma/El", "nsigma/Mu", "nsigma/Pi", - "nsigma/Ka", "nsigma/Pr", "nsigma/De", - "nsigma/Tr", "nsigma/He", "nsigma/Al"}; - static constexpr std::string_view hnsigmaprm[Np] = {"nsigmaprm/El", "nsigmaprm/Mu", "nsigmaprm/Pi", - "nsigmaprm/Ka", "nsigmaprm/Pr", "nsigmaprm/De", - "nsigmaprm/Tr", "nsigmaprm/He", "nsigmaprm/Al"}; - static constexpr std::string_view hnsigmastr[Np] = {"nsigmastr/El", "nsigmastr/Mu", "nsigmastr/Pi", - "nsigmastr/Ka", "nsigmastr/Pr", "nsigmastr/De", - "nsigmastr/Tr", "nsigmastr/He", "nsigmastr/Al"}; - static constexpr std::string_view hnsigmamat[Np] = {"nsigmamat/El", "nsigmamat/Mu", "nsigmamat/Pi", - "nsigmamat/Ka", "nsigmamat/Pr", "nsigmamat/De", - "nsigmamat/Tr", "nsigmamat/He", "nsigmamat/Al"}; - static constexpr std::string_view hnsigmaMC[NpNp] = {"nsigmaMC/El/El", "nsigmaMC/El/Mu", "nsigmaMC/El/Pi", - "nsigmaMC/El/Ka", "nsigmaMC/El/Pr", "nsigmaMC/El/De", - "nsigmaMC/El/Tr", "nsigmaMC/El/He", "nsigmaMC/El/Al", - "nsigmaMC/Mu/El", "nsigmaMC/Mu/Mu", "nsigmaMC/Mu/Pi", - "nsigmaMC/Mu/Ka", "nsigmaMC/Mu/Pr", "nsigmaMC/Mu/De", - "nsigmaMC/Mu/Tr", "nsigmaMC/Mu/He", "nsigmaMC/Mu/Al", - "nsigmaMC/Pi/El", "nsigmaMC/Pi/Mu", "nsigmaMC/Pi/Pi", - "nsigmaMC/Pi/Ka", "nsigmaMC/Pi/Pr", "nsigmaMC/Pi/De", - "nsigmaMC/Pi/Tr", "nsigmaMC/Pi/He", "nsigmaMC/Pi/Al", - "nsigmaMC/Ka/El", "nsigmaMC/Ka/Mu", "nsigmaMC/Ka/Pi", - "nsigmaMC/Ka/Ka", "nsigmaMC/Ka/Pr", "nsigmaMC/Ka/De", - "nsigmaMC/Ka/Tr", "nsigmaMC/Ka/He", "nsigmaMC/Ka/Al", - "nsigmaMC/Pr/El", "nsigmaMC/Pr/Mu", "nsigmaMC/Pr/Pi", - "nsigmaMC/Pr/Ka", "nsigmaMC/Pr/Pr", "nsigmaMC/Pr/De", - "nsigmaMC/Pr/Tr", "nsigmaMC/Pr/He", "nsigmaMC/Pr/Al", - "nsigmaMC/De/El", "nsigmaMC/De/Mu", "nsigmaMC/De/Pi", - "nsigmaMC/De/Ka", "nsigmaMC/De/Pr", "nsigmaMC/De/De", - "nsigmaMC/De/Tr", "nsigmaMC/De/He", "nsigmaMC/De/Al", - "nsigmaMC/Tr/El", "nsigmaMC/Tr/Mu", "nsigmaMC/Tr/Pi", - "nsigmaMC/Tr/Ka", "nsigmaMC/Tr/Pr", "nsigmaMC/Tr/De", - "nsigmaMC/Tr/Tr", "nsigmaMC/Tr/He", "nsigmaMC/Tr/Al", - "nsigmaMC/He/El", "nsigmaMC/He/Mu", "nsigmaMC/He/Pi", - "nsigmaMC/He/Ka", "nsigmaMC/He/Pr", "nsigmaMC/He/De", - "nsigmaMC/He/Tr", "nsigmaMC/He/He", "nsigmaMC/He/Al", - "nsigmaMC/Al/El", "nsigmaMC/Al/Mu", "nsigmaMC/Al/Pi", - "nsigmaMC/Al/Ka", "nsigmaMC/Al/Pr", "nsigmaMC/Al/De", - "nsigmaMC/Al/Tr", "nsigmaMC/Al/He", "nsigmaMC/Al/Al"}; - static constexpr std::string_view hnsigmaMCstr[NpNp] = {"nsigmaMCstr/El/El", "nsigmaMCstr/El/Mu", "nsigmaMCstr/El/Pi", - "nsigmaMCstr/El/Ka", "nsigmaMCstr/El/Pr", "nsigmaMCstr/El/De", - "nsigmaMCstr/El/Tr", "nsigmaMCstr/El/He", "nsigmaMCstr/El/Al", - "nsigmaMCstr/Mu/El", "nsigmaMCstr/Mu/Mu", "nsigmaMCstr/Mu/Pi", - "nsigmaMCstr/Mu/Ka", "nsigmaMCstr/Mu/Pr", "nsigmaMCstr/Mu/De", - "nsigmaMCstr/Mu/Tr", "nsigmaMCstr/Mu/He", "nsigmaMCstr/Mu/Al", - "nsigmaMCstr/Pi/El", "nsigmaMCstr/Pi/Mu", "nsigmaMCstr/Pi/Pi", - "nsigmaMCstr/Pi/Ka", "nsigmaMCstr/Pi/Pr", "nsigmaMCstr/Pi/De", - "nsigmaMCstr/Pi/Tr", "nsigmaMCstr/Pi/He", "nsigmaMCstr/Pi/Al", - "nsigmaMCstr/Ka/El", "nsigmaMCstr/Ka/Mu", "nsigmaMCstr/Ka/Pi", - "nsigmaMCstr/Ka/Ka", "nsigmaMCstr/Ka/Pr", "nsigmaMCstr/Ka/De", - "nsigmaMCstr/Ka/Tr", "nsigmaMCstr/Ka/He", "nsigmaMCstr/Ka/Al", - "nsigmaMCstr/Pr/El", "nsigmaMCstr/Pr/Mu", "nsigmaMCstr/Pr/Pi", - "nsigmaMCstr/Pr/Ka", "nsigmaMCstr/Pr/Pr", "nsigmaMCstr/Pr/De", - "nsigmaMCstr/Pr/Tr", "nsigmaMCstr/Pr/He", "nsigmaMCstr/Pr/Al", - "nsigmaMCstr/De/El", "nsigmaMCstr/De/Mu", "nsigmaMCstr/De/Pi", - "nsigmaMCstr/De/Ka", "nsigmaMCstr/De/Pr", "nsigmaMCstr/De/De", - "nsigmaMCstr/De/Tr", "nsigmaMCstr/De/He", "nsigmaMCstr/De/Al", - "nsigmaMCstr/Tr/El", "nsigmaMCstr/Tr/Mu", "nsigmaMCstr/Tr/Pi", - "nsigmaMCstr/Tr/Ka", "nsigmaMCstr/Tr/Pr", "nsigmaMCstr/Tr/De", - "nsigmaMCstr/Tr/Tr", "nsigmaMCstr/Tr/He", "nsigmaMCstr/Tr/Al", - "nsigmaMCstr/He/El", "nsigmaMCstr/He/Mu", "nsigmaMCstr/He/Pi", - "nsigmaMCstr/He/Ka", "nsigmaMCstr/He/Pr", "nsigmaMCstr/He/De", - "nsigmaMCstr/He/Tr", "nsigmaMCstr/He/He", "nsigmaMCstr/He/Al", - "nsigmaMCstr/Al/El", "nsigmaMCstr/Al/Mu", "nsigmaMCstr/Al/Pi", - "nsigmaMCstr/Al/Ka", "nsigmaMCstr/Al/Pr", "nsigmaMCstr/Al/De", - "nsigmaMCstr/Al/Tr", "nsigmaMCstr/Al/He", "nsigmaMCstr/Al/Al"}; - static constexpr std::string_view hnsigmaMCmat[NpNp] = {"nsigmaMCmat/El/El", "nsigmaMCmat/El/Mu", "nsigmaMCmat/El/Pi", - "nsigmaMCmat/El/Ka", "nsigmaMCmat/El/Pr", "nsigmaMCmat/El/De", - "nsigmaMCmat/El/Tr", "nsigmaMCmat/El/He", "nsigmaMCmat/El/Al", - "nsigmaMCmat/Mu/El", "nsigmaMCmat/Mu/Mu", "nsigmaMCmat/Mu/Pi", - "nsigmaMCmat/Mu/Ka", "nsigmaMCmat/Mu/Pr", "nsigmaMCmat/Mu/De", - "nsigmaMCmat/Mu/Tr", "nsigmaMCmat/Mu/He", "nsigmaMCmat/Mu/Al", - "nsigmaMCmat/Pi/El", "nsigmaMCmat/Pi/Mu", "nsigmaMCmat/Pi/Pi", - "nsigmaMCmat/Pi/Ka", "nsigmaMCmat/Pi/Pr", "nsigmaMCmat/Pi/De", - "nsigmaMCmat/Pi/Tr", "nsigmaMCmat/Pi/He", "nsigmaMCmat/Pi/Al", - "nsigmaMCmat/Ka/El", "nsigmaMCmat/Ka/Mu", "nsigmaMCmat/Ka/Pi", - "nsigmaMCmat/Ka/Ka", "nsigmaMCmat/Ka/Pr", "nsigmaMCmat/Ka/De", - "nsigmaMCmat/Ka/Tr", "nsigmaMCmat/Ka/He", "nsigmaMCmat/Ka/Al", - "nsigmaMCmat/Pr/El", "nsigmaMCmat/Pr/Mu", "nsigmaMCmat/Pr/Pi", - "nsigmaMCmat/Pr/Ka", "nsigmaMCmat/Pr/Pr", "nsigmaMCmat/Pr/De", - "nsigmaMCmat/Pr/Tr", "nsigmaMCmat/Pr/He", "nsigmaMCmat/Pr/Al", - "nsigmaMCmat/De/El", "nsigmaMCmat/De/Mu", "nsigmaMCmat/De/Pi", - "nsigmaMCmat/De/Ka", "nsigmaMCmat/De/Pr", "nsigmaMCmat/De/De", - "nsigmaMCmat/De/Tr", "nsigmaMCmat/De/He", "nsigmaMCmat/De/Al", - "nsigmaMCmat/Tr/El", "nsigmaMCmat/Tr/Mu", "nsigmaMCmat/Tr/Pi", - "nsigmaMCmat/Tr/Ka", "nsigmaMCmat/Tr/Pr", "nsigmaMCmat/Tr/De", - "nsigmaMCmat/Tr/Tr", "nsigmaMCmat/Tr/He", "nsigmaMCmat/Tr/Al", - "nsigmaMCmat/He/El", "nsigmaMCmat/He/Mu", "nsigmaMCmat/He/Pi", - "nsigmaMCmat/He/Ka", "nsigmaMCmat/He/Pr", "nsigmaMCmat/He/De", - "nsigmaMCmat/He/Tr", "nsigmaMCmat/He/He", "nsigmaMCmat/He/Al", - "nsigmaMCmat/Al/El", "nsigmaMCmat/Al/Mu", "nsigmaMCmat/Al/Pi", - "nsigmaMCmat/Al/Ka", "nsigmaMCmat/Al/Pr", "nsigmaMCmat/Al/De", - "nsigmaMCmat/Al/Tr", "nsigmaMCmat/Al/He", "nsigmaMCmat/Al/Al"}; - static constexpr std::string_view hnsigmaMCprm[NpNp] = {"nsigmaMCprm/El/El", "nsigmaMCprm/El/Mu", "nsigmaMCprm/El/Pi", - "nsigmaMCprm/El/Ka", "nsigmaMCprm/El/Pr", "nsigmaMCprm/El/De", - "nsigmaMCprm/El/Tr", "nsigmaMCprm/El/He", "nsigmaMCprm/El/Al", - "nsigmaMCprm/Mu/El", "nsigmaMCprm/Mu/Mu", "nsigmaMCprm/Mu/Pi", - "nsigmaMCprm/Mu/Ka", "nsigmaMCprm/Mu/Pr", "nsigmaMCprm/Mu/De", - "nsigmaMCprm/Mu/Tr", "nsigmaMCprm/Mu/He", "nsigmaMCprm/Mu/Al", - "nsigmaMCprm/Pi/El", "nsigmaMCprm/Pi/Mu", "nsigmaMCprm/Pi/Pi", - "nsigmaMCprm/Pi/Ka", "nsigmaMCprm/Pi/Pr", "nsigmaMCprm/Pi/De", - "nsigmaMCprm/Pi/Tr", "nsigmaMCprm/Pi/He", "nsigmaMCprm/Pi/Al", - "nsigmaMCprm/Ka/El", "nsigmaMCprm/Ka/Mu", "nsigmaMCprm/Ka/Pi", - "nsigmaMCprm/Ka/Ka", "nsigmaMCprm/Ka/Pr", "nsigmaMCprm/Ka/De", - "nsigmaMCprm/Ka/Tr", "nsigmaMCprm/Ka/He", "nsigmaMCprm/Ka/Al", - "nsigmaMCprm/Pr/El", "nsigmaMCprm/Pr/Mu", "nsigmaMCprm/Pr/Pi", - "nsigmaMCprm/Pr/Ka", "nsigmaMCprm/Pr/Pr", "nsigmaMCprm/Pr/De", - "nsigmaMCprm/Pr/Tr", "nsigmaMCprm/Pr/He", "nsigmaMCprm/Pr/Al", - "nsigmaMCprm/De/El", "nsigmaMCprm/De/Mu", "nsigmaMCprm/De/Pi", - "nsigmaMCprm/De/Ka", "nsigmaMCprm/De/Pr", "nsigmaMCprm/De/De", - "nsigmaMCprm/De/Tr", "nsigmaMCprm/De/He", "nsigmaMCprm/De/Al", - "nsigmaMCprm/Tr/El", "nsigmaMCprm/Tr/Mu", "nsigmaMCprm/Tr/Pi", - "nsigmaMCprm/Tr/Ka", "nsigmaMCprm/Tr/Pr", "nsigmaMCprm/Tr/De", - "nsigmaMCprm/Tr/Tr", "nsigmaMCprm/Tr/He", "nsigmaMCprm/Tr/Al", - "nsigmaMCprm/He/El", "nsigmaMCprm/He/Mu", "nsigmaMCprm/He/Pi", - "nsigmaMCprm/He/Ka", "nsigmaMCprm/He/Pr", "nsigmaMCprm/He/De", - "nsigmaMCprm/He/Tr", "nsigmaMCprm/He/He", "nsigmaMCprm/He/Al", - "nsigmaMCprm/Al/El", "nsigmaMCprm/Al/Mu", "nsigmaMCprm/Al/Pi", - "nsigmaMCprm/Al/Ka", "nsigmaMCprm/Al/Pr", "nsigmaMCprm/Al/De", - "nsigmaMCprm/Al/Tr", "nsigmaMCprm/Al/He", "nsigmaMCprm/Al/Al"}; - - static constexpr const char* pT[Np] = {"e", "#mu", "#pi", "K", "p", "d", "t", "^{3}He", "#alpha"}; - static constexpr int PDGs[Np] = {11, 13, 211, 321, 2212, 1000010020, 1000010030, 1000020030}; - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - Configurable checkPrimaries{"checkPrimaries", 1, - "Whether to check physical primary and secondaries particles for the resolution."}; - Configurable pdgSign{"pdgSign", 0, "Sign of the PDG, -1 0 or 1"}; - Configurable doEl{"doEl", 0, "Process electrons"}; - Configurable doMu{"doMu", 0, "Process muons"}; - Configurable doPi{"doPi", 0, "Process pions"}; - Configurable doKa{"doKa", 0, "Process kaons"}; - Configurable doPr{"doPr", 0, "Process protons"}; - Configurable doDe{"doDe", 0, "Process deuterons"}; - Configurable doTr{"doTr", 0, "Process tritons"}; - Configurable doHe{"doHe", 0, "Process helium3"}; - Configurable doAl{"doAl", 0, "Process alpha"}; - ConfigurableAxis binsPt{"binsPt", {2000, 0.f, 20.f}, "Binning of the pT axis"}; - ConfigurableAxis binsNsigma{"binsNsigma", {2000, -50.f, 50.f}, "Binning of the NSigma axis"}; - ConfigurableAxis binsSignal{"binsSignal", {6000, 0, 2000}, "Binning of the TPC signal axis"}; - ConfigurableAxis binsLength{"binsLength", {1000, 0, 3000}, "Binning of the Length axis"}; - ConfigurableAxis binsEta{"binsEta", {100, -4, 4}, "Binning of the Eta axis"}; - Configurable minEta{"minEta", -0.8, "Minimum eta in range"}; - Configurable maxEta{"maxEta", 0.8, "Maximum eta in range"}; - Configurable nMinNumberOfContributors{"nMinNumberOfContributors", 2, "Minimum required number of contributors to the vertex"}; - Configurable logAxis{"logAxis", 0, "Flag to use a logarithmic pT axis, in this case the pT limits are the expontents"}; // TODO: support log axis - - template - void addParticleHistos(const AxisSpec& ptAxis, const AxisSpec& pAxis, const AxisSpec& signalAxis) - { - switch (mcID) { - case 0: - if (!doEl) { - return; - } - break; - case 1: - if (!doMu) { - return; - } - break; - case 2: - if (!doPi) { - return; - } - break; - case 3: - if (!doKa) { - return; - } - break; - case 4: - if (!doPr) { - return; - } - break; - case 5: - if (!doDe) { - return; - } - break; - case 6: - if (!doTr) { - return; - } - break; - case 7: - if (!doHe) { - return; - } - break; - case 8: - if (!doAl) { - return; - } - break; - default: - LOG(fatal) << "Can't interpret index"; - } - - const AxisSpec lengthAxis{binsLength, "Track length (cm)"}; - const AxisSpec etaAxis{binsEta, "#it{#eta}"}; - const AxisSpec nSigmaAxis{binsNsigma, Form("N_{#sigma}^{TOF}(%s)", pT[mcID])}; - - // Particle info - histos.add(hparticlept[mcID].data(), "", kTH1F, {pAxis}); - histos.add(hparticlep[mcID].data(), "", kTH1F, {pAxis}); - histos.add(hparticleeta[mcID].data(), "", kTH1F, {pAxis}); - - // Track info - histos.add(htrackpt[mcID].data(), "", kTH1F, {pAxis}); - histos.add(htrackp[mcID].data(), "", kTH1F, {pAxis}); - histos.add(htracketa[mcID].data(), "", kTH1F, {pAxis}); - histos.add(htracklength[mcID].data(), "", kTH1F, {pAxis}); - - // NSigma - histos.add(hnsigma[mcID].data(), pT[mcID], HistType::kTH2F, {ptAxis, nSigmaAxis}); - histos.add(hsignalMC[mcID].data(), pT[mcID], HistType::kTH2F, {pAxis, signalAxis}); - - if (!checkPrimaries) { - return; - } - - histos.add(hnsigmaprm[mcID].data(), Form("Primary %s", pT[mcID]), HistType::kTH2F, {ptAxis, nSigmaAxis}); - histos.add(hnsigmastr[mcID].data(), Form("Secondary %s from decay", pT[mcID]), HistType::kTH2F, {ptAxis, nSigmaAxis}); - histos.add(hnsigmamat[mcID].data(), Form("Secondary %s from material", pT[mcID]), HistType::kTH2F, {ptAxis, nSigmaAxis}); - - histos.add(hsignalMCprm[mcID].data(), Form("Primary %s", pT[mcID]), HistType::kTH2F, {pAxis, signalAxis}); - histos.add(hsignalMCstr[mcID].data(), Form("Secondary %s from decay", pT[mcID]), HistType::kTH2F, {pAxis, signalAxis}); - histos.add(hsignalMCmat[mcID].data(), Form("Secondary %s from material", pT[mcID]), HistType::kTH2F, {pAxis, signalAxis}); - } - - template - void addParticleMCHistos(const AxisSpec& ptAxis, const AxisSpec&, const AxisSpec&) - { - switch (mcID) { - case 0: - if (!doEl) { - return; - } - break; - case 1: - if (!doMu) { - return; - } - break; - case 2: - if (!doPi) { - return; - } - break; - case 3: - if (!doKa) { - return; - } - break; - case 4: - if (!doPr) { - return; - } - break; - case 5: - if (!doDe) { - return; - } - break; - case 6: - if (!doTr) { - return; - } - break; - case 7: - if (!doHe) { - return; - } - break; - case 8: - if (!doAl) { - return; - } - break; - default: - LOG(fatal) << "Can't interpret index"; - } - - const AxisSpec nSigmaAxis{binsNsigma, Form("N_{#sigma}^{TOF}(%s)", pT[massID])}; - - histos.add(hnsigmaMC[mcID * Np + massID].data(), Form("True %s", pT[mcID]), HistType::kTH2F, {ptAxis, nSigmaAxis}); - if (checkPrimaries) { - histos.add(hnsigmaMCprm[mcID * Np + massID].data(), Form("True Primary %s", pT[mcID]), HistType::kTH2F, {ptAxis, nSigmaAxis}); - histos.add(hnsigmaMCstr[mcID * Np + massID].data(), Form("True Secondary %s from decay", pT[mcID]), HistType::kTH2F, {ptAxis, nSigmaAxis}); - histos.add(hnsigmaMCmat[mcID * Np + massID].data(), Form("True Secondary %s from material", pT[mcID]), HistType::kTH2F, {ptAxis, nSigmaAxis}); - } - } - - void init(o2::framework::InitContext&) - { - AxisSpec pAxis{binsPt, "#it{p} (GeV/#it{c})"}; - AxisSpec ptAxis{binsPt, "#it{p}_{T} (GeV/#it{c})"}; - if (logAxis) { - pAxis.makeLogarithmic(); - ptAxis.makeLogarithmic(); - } - const AxisSpec betaAxis{1000, 0, 1.2, "TOF #beta"}; - - histos.add("event/T0", ";Tracks with TOF;T0 (ps);Counts", HistType::kTH2F, {{1000, 0, 1000}, {1000, -1000, 1000}}); - - histos.add("event/vertexz", ";Vtx_{z} (cm);Entries", kTH1F, {{100, -20, 20}}); - - static_for<0, 8>([&](auto i) { - static_for<0, 8>([&](auto j) { - addParticleMCHistos(ptAxis, pAxis, betaAxis); - }); - addParticleHistos(ptAxis, pAxis, betaAxis); - }); - - histos.add("event/tofbeta", "All", HistType::kTH2F, {pAxis, betaAxis}); - if (checkPrimaries) { - histos.add("event/tofbetaPrm", "Primaries", HistType::kTH2F, {pAxis, betaAxis}); - // histos.add("event/tofbetaSec", "Secondaries", HistType::kTH2F, {pAxis, betaAxis}); - histos.add("event/tofbetaStr", "Secondaries from weak decays", HistType::kTH2F, {pAxis, betaAxis}); - histos.add("event/tofbetaMat", "Secondaries from material", HistType::kTH2F, {pAxis, betaAxis}); - } - // Print output histograms statistics - LOG(info) << "Size of the histograms in qaPIDTOFMC"; - histos.print(); - } - - template - void fillParticleInfoForPdg(const T& particle) - { - switch (pdgSign.value) { - case 0: - if (abs(particle.pdgCode()) != PDGs[mcID]) { - return; - } - break; - case 1: - if (particle.pdgCode() != PDGs[mcID]) { - return; - } - break; - case 2: - if (particle.pdgCode() != -PDGs[mcID]) { - return; - } - break; - default: - LOG(fatal) << "Can't interpret pdgSign"; - } - switch (mcID) { - case 0: - if (!doEl) { - return; - } - break; - case 1: - if (!doMu) { - return; - } - break; - case 2: - if (!doPi) { - return; - } - break; - case 3: - if (!doKa) { - return; - } - break; - case 4: - if (!doPr) { - return; - } - break; - case 5: - if (!doDe) { - return; - } - break; - case 6: - if (!doTr) { - return; - } - break; - case 7: - if (!doHe) { - return; - } - break; - case 8: - if (!doAl) { - return; - } - break; - default: - LOG(fatal) << "Can't interpret index"; - } - - histos.fill(HIST(hparticlep[mcID]), particle.p()); - histos.fill(HIST(hparticlept[mcID]), particle.pt()); - histos.fill(HIST(hparticleeta[mcID]), particle.eta()); - } - - template - void fillTrackInfoForPdg(const T& track, const TT& particle) - { - switch (mcID) { - case 0: - if (!doEl) { - return; - } - break; - case 1: - if (!doMu) { - return; - } - break; - case 2: - if (!doPi) { - return; - } - break; - case 3: - if (!doKa) { - return; - } - break; - case 4: - if (!doPr) { - return; - } - break; - case 5: - if (!doDe) { - return; - } - break; - case 6: - if (!doTr) { - return; - } - break; - case 7: - if (!doHe) { - return; - } - break; - case 8: - if (!doAl) { - return; - } - break; - default: - LOG(fatal) << "Can't interpret index"; - } - - const float nsigma = o2::aod::pidutils::tofNSigma(track); - - // Fill for all - histos.fill(HIST(hnsigma[mcID]), track.pt(), nsigma); - - if (checkPrimaries) { - if (!particle.isPhysicalPrimary()) { - if (particle.getProcess() == 4) { - histos.fill(HIST(hnsigmastr[mcID]), track.pt(), nsigma); - } else { - histos.fill(HIST(hnsigmamat[mcID]), track.pt(), nsigma); - } - } else { - histos.fill(HIST(hnsigmaprm[mcID]), track.pt(), nsigma); - } - } - - switch (pdgSign.value) { - case 0: - if (abs(particle.pdgCode()) != PDGs[mcID]) { - return; - } - break; - case 1: - if (particle.pdgCode() != PDGs[mcID]) { - return; - } - break; - case 2: - if (particle.pdgCode() != -PDGs[mcID]) { - return; - } - break; - default: - LOG(fatal) << "Can't interpret pdgSign"; - } - - // Track info - histos.fill(HIST(htrackp[mcID]), track.p()); - histos.fill(HIST(htrackpt[mcID]), track.pt()); - histos.fill(HIST(htracketa[mcID]), track.eta()); - histos.fill(HIST(htracklength[mcID]), track.length()); - - // PID info - histos.fill(HIST(hsignalMC[mcID]), track.p(), track.beta()); - if (checkPrimaries) { - if (!particle.isPhysicalPrimary()) { - if (particle.getProcess() == 4) { - histos.fill(HIST(hsignalMCstr[mcID]), track.p(), track.beta()); - } else { - histos.fill(HIST(hsignalMCmat[mcID]), track.p(), track.beta()); - } - } else { - histos.fill(HIST(hsignalMCprm[mcID]), track.p(), track.beta()); - } - } - } - - template - void fillPIDInfoForPdg(const T& track, const TT& particle) - { - switch (mcID) { - case 0: - if (!doEl) { - return; - } - break; - case 1: - if (!doMu) { - return; - } - break; - case 2: - if (!doPi) { - return; - } - break; - case 3: - if (!doKa) { - return; - } - break; - case 4: - if (!doPr) { - return; - } - break; - case 5: - if (!doDe) { - return; - } - break; - case 6: - if (!doTr) { - return; - } - break; - case 7: - if (!doHe) { - return; - } - break; - case 8: - if (!doAl) { - return; - } - break; - default: - LOG(fatal) << "Can't interpret index"; - } - - switch (pdgSign.value) { - case 0: - if (abs(particle.pdgCode()) != PDGs[mcID]) { - return; - } - break; - case 1: - if (particle.pdgCode() != PDGs[mcID]) { - return; - } - break; - case 2: - if (particle.pdgCode() != -PDGs[mcID]) { - return; - } - break; - default: - LOG(fatal) << "Can't interpret pdgSign"; - } - - const float nsigmaMassID = o2::aod::pidutils::tofNSigma(track); - - histos.fill(HIST(hnsigmaMC[mcID * Np + massID]), track.pt(), nsigmaMassID); - if (checkPrimaries) { - if (!particle.isPhysicalPrimary()) { - if (particle.getProcess() == 4) { - histos.fill(HIST(hnsigmaMCstr[mcID * Np + massID]), track.pt(), nsigmaMassID); - } else { - histos.fill(HIST(hnsigmaMCmat[mcID * Np + massID]), track.pt(), nsigmaMassID); - } - } else { - histos.fill(HIST(hnsigmaMCprm[mcID * Np + massID]), track.pt(), nsigmaMassID); - } - } - } - - Preslice perCol = aod::track::collisionId; - Preslice perMCCol = aod::mcparticle::mcCollisionId; - - void process(soa::Join const& collisions, - soa::Join& tracks, - aod::McParticles& mcParticles, - aod::McCollisions&) - { - for (const auto& collision : collisions) { - if (collision.numContrib() < nMinNumberOfContributors) { - return; - } - if (!collision.has_mcCollision()) { - continue; - } - const auto tracksInCollision = tracks.sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - const auto particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, collision.mcCollision().globalIndex(), cache); - - for (const auto& p : particlesInCollision) { - static_for<0, 8>([&](auto i) { - fillParticleInfoForPdg(p); - }); - } - - const float collisionTime_ps = collision.collisionTime() * 1000.f; - unsigned int nTracksWithTOF = 0; - for (const auto& t : tracksInCollision) { - // - if (!t.hasTOF()) { // Skipping tracks without TOF - continue; - } - if (t.eta() < minEta || t.eta() > maxEta) { - continue; - } - - nTracksWithTOF++; - - // Fill for all - histos.fill(HIST("event/tofbeta"), t.p(), t.beta()); - if (!t.has_mcParticle()) { - continue; - } - - const auto& particle = t.mcParticle(); - - if (checkPrimaries) { - if (!particle.isPhysicalPrimary()) { - // histos.fill(HIST("event/tofbetaSec"), t.p(), t.beta()); - if (particle.getProcess() == 4) { - histos.fill(HIST("event/tofbetaStr"), t.tpcInnerParam(), t.tpcSignal()); - } else { - histos.fill(HIST("event/tofbetaMat"), t.tpcInnerParam(), t.tpcSignal()); - } - } else { - histos.fill(HIST("event/tofbetaPrm"), t.p(), t.beta()); - } - } - - // Fill with PDG codes - static_for<0, 8>([&](auto i) { - static_for<0, 8>([&](auto j) { - fillPIDInfoForPdg(t, particle); - }); - fillTrackInfoForPdg(t, particle); - }); - } // track loop - histos.fill(HIST("event/T0"), nTracksWithTOF, collisionTime_ps); - histos.fill(HIST("event/vertexz"), collision.posZ()); - } // collision loop - } // process() -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx b/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx index 7fb981a271b..91effcc47b4 100644 --- a/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx +++ b/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx @@ -9,6 +9,8 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -57,7 +59,9 @@ struct perfK0sResolution { Configurable nV0lifetime{"nV0lifetime", 3., "n ctau"}; Configurable nMaxTPCNsigma{"nMaxTPCNsigma", 10., "Maximum TPC nsigma for pions"}; Configurable itsIbSelectionPos{"itsIbSelectionPos", 0, "Flag for the ITS IB selection on positive daughters: -1 no ITS IB, 0 no selection, 1 ITS IB"}; - Configurable itsIbSelectionNeg{"itsIbSelectionNeg", 0, "Flag for the ITS IB IB selection on negative daughters: -1 no ITS IB, 0 no selection, 1 ITS IB"}; + Configurable itsIbSelectionNeg{"itsIbSelectionNeg", 0, "Flag for the ITS IB selection on negative daughters: -1 no ITS IB, 0 no selection, 1 ITS IB"}; + Configurable itsAfterburnerPos{"itsAfterburnerPos", 0, "Flag for the ITS afterburner tracks on positive daughters: -1 no AB, 0 no selection, 1 AB"}; + Configurable itsAfterburnerNeg{"itsAfterburnerNeg", 0, "Flag for the ITS afterburner tracks on negative daughters: -1 no AB, 0 no selection, 1 AB"}; Configurable trdSelectionPos{"trdSelectionPos", 0, "Flag for the TRD selection on positive daughters: -1 no TRD, 0 no selection, 1 TRD"}; Configurable trdSelectionNeg{"trdSelectionNeg", 0, "Flag for the TRD selection on negative daughters: -1 no TRD, 0 no selection, 1 TRD"}; Configurable tofSelectionPos{"tofSelectionPos", 0, "Flag for the TOF selection on positive daughters: -1 no TOF, 0 no selection, 1 TOF"}; @@ -93,6 +97,8 @@ struct perfK0sResolution { Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable minOccupancyCut{"minOccupancyCut", 1, "Minimum occupancy cut. Enabled if min < max"}; + Configurable maxOccupancyCut{"maxOccupancyCut", -1, "Maximum occupancy cut. Enabled if min < max"}; int runNumber = -1; @@ -248,15 +254,49 @@ struct perfK0sResolution { LOG(fatal) << "Invalid ITS selection for negative daughter"; break; } + switch (itsAfterburnerPos) { + case -1: + if (ptrack.itsChi2NCl() >= 0) { + return false; + } + break; + case 0: + break; + case 1: + if (ptrack.itsChi2NCl() < 0) { + return false; + } + break; + default: + LOG(fatal) << "Invalid AB selection for positive daughter"; + break; + } + switch (itsAfterburnerNeg) { + case -1: + if (ntrack.itsChi2NCl() >= 0) { + return false; + } + break; + case 0: + break; + case 1: + if (ntrack.itsChi2NCl() < 0) { + return false; + } + break; + default: + LOG(fatal) << "Invalid AB selection for negative daughter"; + break; + } // TPC selection if (!ntrack.hasTPC() || !ptrack.hasTPC()) { return false; } - if (abs(ntrack.tpcNSigmaPi()) > nMaxTPCNsigma) { + if (std::abs(ntrack.tpcNSigmaPi()) > nMaxTPCNsigma) { return false; } - if (abs(ptrack.tpcNSigmaPi()) > nMaxTPCNsigma) { + if (std::abs(ptrack.tpcNSigmaPi()) > nMaxTPCNsigma) { return false; } if (ntrack.tpcNClsCrossedRows() < extraCutTPCClusters || ptrack.tpcNClsCrossedRows() < extraCutTPCClusters) { @@ -385,6 +425,13 @@ struct perfK0sResolution { soa::Filtered const& fullV0s, PIDTracks const&) { + const int occupancy = collision.trackOccupancyInTimeRange(); + if (minOccupancyCut < maxOccupancyCut) { + if (occupancy < minOccupancyCut || occupancy > maxOccupancyCut) { + return; + } + } + rK0sResolution.fill(HIST("h1_stats"), 0.5); for (auto& v0 : fullV0s) { rK0sResolution.fill(HIST("h1_stats"), 1.5); diff --git a/DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.cxx b/DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.cxx index 8470c52c591..9ee92d0a509 100644 --- a/DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.cxx +++ b/DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.cxx @@ -14,6 +14,8 @@ /// \author Carolina Reetz c.reetz@cern.ch /// \brief QA task to study momentum resolution of Lambda daughter tracks +#include + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -50,18 +52,24 @@ struct qaLamMomResolution { Configurable collSelection{"collSelection", true, "Apply collision selection"}; Configurable useTrackTuner{"useTrackTuner", false, "Apply pT/DCA corrections to MC"}; - Configurable trackTunerParams{"trackTunerParams", "debugInfo=0|updateTrackCovMat=0|updateCurvature=1|updatePulls=0|isInputFileFromCCDB=1|pathInputFile=Users/m/mfaggin/test/inputsTrackTuner/PbPb2022|nameInputFile=trackTuner_DataLHC22sPass5_McLHC22l1b2_run529397.root|usePvRefitCorrections=0|oneOverPtCurrent=1|oneOverPtUpgr=1.2", "TrackTuner parameter initialization (format: =|=)"}; + Configurable trackTunerParams{"trackTunerParams", "debugInfo=0|updateTrackDCAs=0|updateTrackCovMat=0|updateCurvature=0|updateCurvatureIU=0|updatePulls=0|isInputFileFromCCDB=1|pathInputFile=Users/m/mfaggin/test/inputsTrackTuner/PbPb2022|nameInputFile=trackTuner_DataLHC22sPass5_McLHC22l1b2_run529397.root|pathFileQoverPt=Users/h/hsharma/qOverPtGraphs|nameFileQoverPt=D0sigma_Data_removal_itstps_MC_LHC22b1b.root|usePvRefitCorrections=0|qOverPtMC=-1.|qOverPtData=-1.", "TrackTuner parameter initialization (format: =|=)"}; Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable itsAfterburnerPos{"itsAfterburnerPos", 0, "Flag for the ITS afterburner tracks on positive daughters: -1 no AB, 0 no selection, 1 AB"}; + Configurable itsAfterburnerNeg{"itsAfterburnerNeg", 0, "Flag for the ITS afterburner tracks on negative daughters: -1 no AB, 0 no selection, 1 AB"}; + HistogramRegistry hist{"Histograms"}; o2::dataformats::VertexBase mVtx; + o2::dataformats::VertexBase mPV; o2::dataformats::DCA mDcaInfoCovPos; o2::dataformats::DCA mDcaInfoCovNeg; - o2::track::TrackParametrizationWithError mTrackParCovPos; - o2::track::TrackParametrizationWithError mTrackParCovNeg; + o2::track::TrackParametrizationWithError mTrackParCovPosVtx; + o2::track::TrackParametrizationWithError mTrackParCovNegVtx; + o2::track::TrackParametrizationWithError mTrackParCovPosPV; + o2::track::TrackParametrizationWithError mTrackParCovNegPV; int runNumber = 0; @@ -76,6 +84,7 @@ struct qaLamMomResolution { float radiusLambda = -1.0f; float ptLambda = -1.0f; float etaProton = -1.0f, etaPion = -1.0f; + float phiProton = -1.0f, phiPion = -1.0f; int tpcNClsProton = 0, tpcNClsPion = 0; int chargeProton = 0, chargePion = 0; // daughter momenta @@ -88,11 +97,16 @@ struct qaLamMomResolution { std::array momProtonRecErr; std::array momPionRecErr; float sigma1PtProtonIU = -1.0f, sigma1PtPionIU = -1.0f; + // daughter IU position + std::array posProtonRecIU; + std::array posPionRecIU; + std::array posProtonRecIUErr; + std::array posPionRecIUErr; // daughter DCA - std::array DCAProtonRec; // 0: xy, 1: z - std::array DCAPionRec; // 0: xy, 1: z - std::array DCAProtonRecErr; // 0: xy, 1: z - std::array DCAPionRecErr; // 0: xy, 1: z + std::array DCAProtonRec; // 0: xy, 1: z // updated if tuner is used! + std::array DCAPionRec; // 0: xy, 1: z // updated if tuner is used! + std::array DCAProtonRecErr; // 0: xy, 1: z // updated if tuner is used! + std::array DCAPionRecErr; // 0: xy, 1: z // updated if tuner is used! // MC info std::array momProtonGen; std::array momPionGen; @@ -137,15 +151,58 @@ struct qaLamMomResolution { runNumber = bc.runNumber(); } - template + template + bool selectAfterburner(TTrack const& posTrack, TTrack const& negTrack) + { + switch (itsAfterburnerPos) { + case -1: + if (posTrack.itsChi2NCl() >= 0) { + return false; + } + break; + case 0: + break; + case 1: + if (posTrack.itsChi2NCl() < 0) { + return false; + } + break; + default: + LOG(fatal) << "Invalid AB selection for positive daughter"; + break; + } + switch (itsAfterburnerNeg) { + case -1: + if (negTrack.itsChi2NCl() >= 0) { + return false; + } + break; + case 0: + break; + case 1: + if (negTrack.itsChi2NCl() < 0) { + return false; + } + break; + default: + LOG(fatal) << "Invalid AB selection for negative daughter"; + break; + } + return true; + } + + template void tuneV0(TV0 const& v0, TV0Track const& posTrack, TV0Track const& negTrack, aod::McParticles const&, + TCollision const& collision, aod::BCsWithTimestamps const& bcs) { initCCDB(bcs.begin()); trackTunedTracks->Fill(1, 2); // tune 2 tracks + o2::track::TrackParametrizationWithError mTrackParCovPos; + o2::track::TrackParametrizationWithError mTrackParCovNeg; setTrackParCov(posTrack, mTrackParCovPos); setTrackParCov(negTrack, mTrackParCovNeg); mTrackParCovPos.setPID(posTrack.pidForTracking()); @@ -155,12 +212,25 @@ struct qaLamMomResolution { auto mcParticlePos = posTrack.mcParticle(); auto mcParticleNeg = negTrack.mcParticle(); + // tune parameters at IU trackTuner.tuneTrackParams(mcParticlePos, mTrackParCovPos, matCorr, &mDcaInfoCovPos, trackTunedTracks); trackTuner.tuneTrackParams(mcParticleNeg, mTrackParCovNeg, matCorr, &mDcaInfoCovNeg, trackTunedTracks); + // propagate tuned tracks to Lambda vertex + mTrackParCovPosVtx = mTrackParCovPos; + mTrackParCovNegVtx = mTrackParCovNeg; mVtx.setPos({v0.x(), v0.y(), v0.z()}); mVtx.setCov(v0.positionCovMat()[0], v0.positionCovMat()[1], v0.positionCovMat()[2], v0.positionCovMat()[3], v0.positionCovMat()[4], v0.positionCovMat()[5]); - o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, mTrackParCovPos, 2.f, matCorr, &mDcaInfoCovPos); - o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, mTrackParCovNeg, 2.f, matCorr, &mDcaInfoCovNeg); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, mTrackParCovPosVtx, 2.f, matCorr, &mDcaInfoCovPos); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, mTrackParCovNegVtx, 2.f, matCorr, &mDcaInfoCovNeg); + + // get DCAs to PV + // DCA with respect to collision associated to the V0 + mTrackParCovPosPV = mTrackParCovPos; + mTrackParCovNegPV = mTrackParCovNeg; + mPV.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mPV.setCov(collision.covXX(), collision.covXX(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, mTrackParCovPosPV, 2.f, matCorr, &mDcaInfoCovPos); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, mTrackParCovNegPV, 2.f, matCorr, &mDcaInfoCovNeg); } template @@ -170,6 +240,7 @@ struct qaLamMomResolution { massLambda, radiusLambda, ptLambda, chargeProton, chargePion, etaProton, etaPion, + phiProton, phiPion, tpcNClsProton, tpcNClsPion, momProtonRec[0], momProtonRec[1], momProtonRec[2], momProtonRecErr[0], momProtonRecErr[1], momProtonRecErr[2], @@ -182,6 +253,10 @@ struct qaLamMomResolution { momProtonGen[0], momProtonGen[1], momProtonGen[2], momPionGen[0], momPionGen[1], momPionGen[2], sigma1PtProtonIU, sigma1PtPionIU, + posProtonRecIU[0], posProtonRecIU[1], posProtonRecIU[2], + posProtonRecIUErr[0], posProtonRecIUErr[1], posProtonRecIUErr[2], + posPionRecIU[0], posPionRecIU[1], posPionRecIU[2], + posPionRecIUErr[0], posPionRecIUErr[1], posPionRecIUErr[2], DCAProtonRec[0], DCAProtonRec[1], DCAProtonRecErr[0], DCAProtonRecErr[1], DCAPionRec[0], DCAPionRec[1], @@ -215,7 +290,23 @@ struct qaLamMomResolution { momPionRecIUErr[2] = sqrt(pioncv[20]); sigma1PtPionIU = pionTrackIU.sigma1Pt(); - // daughter DCA + // daughter position at IU + // proton + posProtonRecIU[0] = protonTrackIU.x(); + posProtonRecIU[1] = protonTrackIU.y(); + posProtonRecIU[2] = protonTrackIU.z(); + posProtonRecIUErr[0] = sqrt(protoncv[0]); + posProtonRecIUErr[1] = sqrt(protoncv[2]); + posProtonRecIUErr[2] = sqrt(protoncv[5]); + // pion + posPionRecIU[0] = pionTrackIU.px(); + posPionRecIU[1] = pionTrackIU.py(); + posPionRecIU[2] = pionTrackIU.pz(); + posPionRecIUErr[0] = sqrt(pioncv[0]); + posPionRecIUErr[1] = sqrt(pioncv[2]); + posPionRecIUErr[2] = sqrt(pioncv[5]); + + // daughter DCA to PV DCAProtonRec[0] = protonTrackIU.dcaXY(); DCAProtonRec[1] = protonTrackIU.dcaZ(); DCAProtonRecErr[0] = sqrt(protonTrackIU.sigmaDcaXY2()); @@ -230,6 +321,8 @@ struct qaLamMomResolution { chargePion = pionTrackIU.sign(); etaProton = protonTrackIU.eta(); etaPion = pionTrackIU.eta(); + phiProton = protonTrackIU.phi(); + phiPion = pionTrackIU.phi(); tpcNClsProton = protonTrackIU.tpcNClsFound(); tpcNClsPion = pionTrackIU.tpcNClsFound(); } @@ -246,7 +339,7 @@ struct qaLamMomResolution { return; } hist.fill(HIST("hEventSelectionFlow"), 1.f); - if (collSelection && (abs(collision.posZ()) >= 10.)) { + if (collSelection && (std::abs(collision.posZ()) >= 10.)) { return; } hist.fill(HIST("hEventSelectionFlow"), 2.f); @@ -262,6 +355,10 @@ struct qaLamMomResolution { const auto& protonTrackIU = v0data.posTrack_as(); const auto& pionTrackIU = v0data.negTrack_as(); + // afterburner selection + if (!selectAfterburner(protonTrackIU, pionTrackIU)) + continue; + if (protonTrackIU.has_mcParticle() && pionTrackIU.has_mcParticle()) { const auto& MCproton = protonTrackIU.mcParticle_as(); @@ -301,15 +398,15 @@ struct qaLamMomResolution { // optionally use track tuner to tune daughter tracks' pT at decay vertex if (useTrackTuner) { // tune V0 - tuneV0(v0data, protonTrackIU, pionTrackIU, mcparticles, bcs); + tuneV0(v0data, protonTrackIU, pionTrackIU, mcparticles, collision, bcs); // get smeared parameters and cov matrix std::array pPos{0., 0., 0.}; std::array pNeg{0., 0., 0.}; std::array cPos, cNeg; - mTrackParCovPos.getPxPyPzGlo(pPos); - mTrackParCovNeg.getPxPyPzGlo(pNeg); - mTrackParCovPos.getCovXYZPxPyPzGlo(cPos); - mTrackParCovNeg.getCovXYZPxPyPzGlo(cNeg); + mTrackParCovPosVtx.getPxPyPzGlo(pPos); + mTrackParCovNegVtx.getPxPyPzGlo(pNeg); + mTrackParCovPosVtx.getCovXYZPxPyPzGlo(cPos); + mTrackParCovNegVtx.getCovXYZPxPyPzGlo(cNeg); // lambda massLambda = RecoDecay::m(std::array{std::array{pPos[0], pPos[1], pPos[2]}, std::array{pNeg[0], pNeg[1], pNeg[2]}}, @@ -329,6 +426,17 @@ struct qaLamMomResolution { momPionRecErr[0] = sqrt(cNeg[9]); momPionRecErr[1] = sqrt(cNeg[14]); momPionRecErr[2] = sqrt(cNeg[20]); + // smeared DCAs at PV + // proton + DCAProtonRec[0] = mDcaInfoCovPos.getY(); + DCAProtonRec[1] = mDcaInfoCovPos.getZ(); + DCAProtonRecErr[0] = sqrt(mDcaInfoCovPos.getSigmaY2()); + DCAProtonRecErr[1] = sqrt(mDcaInfoCovPos.getSigmaZ2()); + // pion + DCAPionRec[0] = mDcaInfoCovNeg.getY(); + DCAPionRec[1] = mDcaInfoCovNeg.getZ(); + DCAPionRecErr[0] = sqrt(mDcaInfoCovNeg.getSigmaY2()); + DCAPionRecErr[1] = sqrt(mDcaInfoCovNeg.getSigmaZ2()); } // fill table @@ -343,6 +451,10 @@ struct qaLamMomResolution { const auto& protonTrackIU = v0data.negTrack_as(); const auto& pionTrackIU = v0data.posTrack_as(); + // afterburner selection + if (!selectAfterburner(pionTrackIU, protonTrackIU)) + continue; + if (protonTrackIU.has_mcParticle() && pionTrackIU.has_mcParticle()) { const auto& MCproton = protonTrackIU.mcParticle_as(); @@ -382,15 +494,15 @@ struct qaLamMomResolution { // optionally use track tuner to tune daughter tracks' pT at decay vertex if (useTrackTuner) { // tune V0 - tuneV0(v0data, pionTrackIU, protonTrackIU, mcparticles, bcs); + tuneV0(v0data, pionTrackIU, protonTrackIU, mcparticles, collision, bcs); // get smeared parameters and cov matrix std::array pPos{0., 0., 0.}; std::array pNeg{0., 0., 0.}; std::array cPos, cNeg; - mTrackParCovPos.getPxPyPzGlo(pPos); - mTrackParCovNeg.getPxPyPzGlo(pNeg); - mTrackParCovPos.getCovXYZPxPyPzGlo(cPos); - mTrackParCovNeg.getCovXYZPxPyPzGlo(cNeg); + mTrackParCovPosVtx.getPxPyPzGlo(pPos); + mTrackParCovNegVtx.getPxPyPzGlo(pNeg); + mTrackParCovPosVtx.getCovXYZPxPyPzGlo(cPos); + mTrackParCovNegVtx.getCovXYZPxPyPzGlo(cNeg); // lambda massLambda = RecoDecay::m(std::array{std::array{pPos[0], pPos[1], pPos[2]}, std::array{pNeg[0], pNeg[1], pNeg[2]}}, @@ -410,6 +522,17 @@ struct qaLamMomResolution { momPionRecErr[0] = sqrt(cPos[9]); momPionRecErr[1] = sqrt(cPos[14]); momPionRecErr[2] = sqrt(cPos[20]); + // smeared DCAs at PV + // proton + DCAProtonRec[0] = mDcaInfoCovNeg.getY(); + DCAProtonRec[1] = mDcaInfoCovNeg.getZ(); + DCAProtonRecErr[0] = sqrt(mDcaInfoCovNeg.getSigmaY2()); + DCAProtonRecErr[1] = sqrt(mDcaInfoCovNeg.getSigmaZ2()); + // pion + DCAPionRec[0] = mDcaInfoCovPos.getY(); + DCAPionRec[1] = mDcaInfoCovPos.getZ(); + DCAPionRecErr[0] = sqrt(mDcaInfoCovPos.getSigmaY2()); + DCAPionRecErr[1] = sqrt(mDcaInfoCovPos.getSigmaZ2()); } // fill table diff --git a/DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.h b/DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.h index c605278bf9f..603195404d4 100644 --- a/DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.h +++ b/DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.h @@ -34,6 +34,9 @@ DECLARE_SOA_COLUMN(ChargePion, chargePion, int); // eta DECLARE_SOA_COLUMN(EtaProton, etaProton, float); DECLARE_SOA_COLUMN(EtaPion, etaPion, float); +// phi +DECLARE_SOA_COLUMN(PhiProton, phiProton, float); +DECLARE_SOA_COLUMN(PhiPion, phiPion, float); // nTPCclusters DECLARE_SOA_COLUMN(NTPCClusProton, nTPCclusProton, int); DECLARE_SOA_COLUMN(NTPCClusPion, nTPCclusPion, int); @@ -65,6 +68,20 @@ DECLARE_SOA_COLUMN(PyPionIUErr, pyPionIUErr, float); DECLARE_SOA_COLUMN(PzPionIUErr, pzPionIUErr, float); DECLARE_SOA_COLUMN(Sigma1PtProtonIU, sigma1ptProtonIU, float); DECLARE_SOA_COLUMN(Sigma1PtPionIU, sigma1ptPionIU, float); +// IU position +DECLARE_SOA_COLUMN(XProtonIU, xProtonIU, float); +DECLARE_SOA_COLUMN(YProtonIU, yProtonIU, float); +DECLARE_SOA_COLUMN(ZProtonIU, zProtonIU, float); +DECLARE_SOA_COLUMN(XPionIU, xPionIU, float); +DECLARE_SOA_COLUMN(YPionIU, yPionIU, float); +DECLARE_SOA_COLUMN(ZPionIU, zPionIU, float); +// IU position uncertainties +DECLARE_SOA_COLUMN(XProtonIUErr, xProtonIUErr, float); +DECLARE_SOA_COLUMN(YProtonIUErr, yProtonIUErr, float); +DECLARE_SOA_COLUMN(ZProtonIUErr, zProtonIUErr, float); +DECLARE_SOA_COLUMN(XPionIUErr, xPionIUErr, float); +DECLARE_SOA_COLUMN(YPionIUErr, yPionIUErr, float); +DECLARE_SOA_COLUMN(ZPionIUErr, zPionIUErr, float); // DCA DECLARE_SOA_COLUMN(DCAxyProton, dcaxyProton, float); DECLARE_SOA_COLUMN(DCAxyPion, dcaxyPion, float); @@ -93,6 +110,8 @@ DECLARE_SOA_TABLE(LamDaughters, "AOD", "LAMDAUGHTERS", qaLamMomResolution::ChargePion, qaLamMomResolution::EtaProton, qaLamMomResolution::EtaPion, + qaLamMomResolution::PhiProton, + qaLamMomResolution::PhiPion, qaLamMomResolution::NTPCClusProton, qaLamMomResolution::NTPCClusPion, qaLamMomResolution::PxProton, @@ -127,6 +146,18 @@ DECLARE_SOA_TABLE(LamDaughters, "AOD", "LAMDAUGHTERS", qaLamMomResolution::PzPionMC, qaLamMomResolution::Sigma1PtProtonIU, qaLamMomResolution::Sigma1PtPionIU, + qaLamMomResolution::XProtonIU, + qaLamMomResolution::YProtonIU, + qaLamMomResolution::ZProtonIU, + qaLamMomResolution::XProtonIUErr, + qaLamMomResolution::YProtonIUErr, + qaLamMomResolution::ZProtonIUErr, + qaLamMomResolution::XPionIU, + qaLamMomResolution::YPionIU, + qaLamMomResolution::ZPionIU, + qaLamMomResolution::XPionIUErr, + qaLamMomResolution::YPionIUErr, + qaLamMomResolution::ZPionIUErr, qaLamMomResolution::DCAxyProton, qaLamMomResolution::DCAzProton, qaLamMomResolution::DCAxyProtonErr, diff --git a/DPG/Tasks/AOTTrack/qaDcaMC.cxx b/DPG/Tasks/AOTTrack/qaDcaMC.cxx new file mode 100644 index 00000000000..4054c59b33a --- /dev/null +++ b/DPG/Tasks/AOTTrack/qaDcaMC.cxx @@ -0,0 +1,621 @@ +// 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 qaDcaMC.cxx +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Task to analyse the DCA distributions in the MC according to PDG code and status +/// + +// O2 includes +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StaticFor.h" +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" + +// ROOT includes +#include "TPDGCode.h" +#include "TEfficiency.h" +#include "THashList.h" + +using namespace o2::framework; + +// Indices for the track cut histogram +static constexpr int trkCutIdxTrkRead = 1; +static constexpr int trkCutIdxHasMcPart = 2; +static constexpr int trkCutIdxPassedPt = 3; +static constexpr int trkCutIdxPassedEta = 4; +static constexpr int trkCutIdxPassedPhi = 5; +static constexpr int trkCutIdxPassedY = 6; +static constexpr int trkCutIdxPassedFake = 7; +static constexpr int trkCutIdxHasCollision = 8; +static constexpr int trkCutIdxPassedTrkType = 9; +static constexpr int trkCutIdxPassedPtRange = 10; +static constexpr int trkCutIdxPassedEtaRange = 11; +static constexpr int trkCutIdxPassedDcaXYMax = 12; +static constexpr int trkCutIdxPassedDcaXYMin = 13; +static constexpr int trkCutIdxPassedDcaZMax = 14; +static constexpr int trkCutIdxPassedDcaZMin = 15; +static constexpr int trkCutIdxPassedGoldenChi2 = 16; +static constexpr int trkCutIdxPassedIsPvCont = 17; +static constexpr int trkCutIdxPassedITSPartial = 18; +static constexpr int trkCutIdxPassedTPCPartial = 19; +static constexpr int trkCutIdxPassedTOFPartial = 20; +static constexpr int trkCutIdxPassedGlobal = 21; +static constexpr int trkCutIdxN = 22; + +// Particle information +static constexpr int nSpecies = o2::track::PID::NIDs; // One per PDG +static constexpr int nCharges = 2; // Positive and negative +static constexpr const char* particleTitle[nSpecies] = {"e", "#mu", "#pi", "K", "p", "d", "t", "^{3}He", "#alpha"}; +static constexpr const char* particleNames[nSpecies] = {"el", "mu", "pi", "ka", "pr", "de", "tr", "he", "al"}; +static constexpr const char* chargeNames[nSpecies] = {"pos_pdg", "neg_pdg"}; +static constexpr int PDGs[nSpecies] = {kElectron, kMuonMinus, kPiPlus, kKPlus, kProton, 1000010020, 1000010030, 1000020030, 1000020040}; + +// Histograms +// Pt +std::array, nCharges>, nSpecies> hPtPrm; +std::array, nCharges>, nSpecies> hPtStr; +std::array, nCharges>, nSpecies> hPtMat; +std::array, nCharges>, nSpecies> hPtMatSM; +std::array, nCharges>, nSpecies> hPtMatSM1Dau; +std::array, nCharges>, nSpecies> hPtMotherOfPDG1; +std::array, nCharges>, nSpecies> hPtMotherOfPDG2; +std::array, nCharges>, nSpecies> hPtMotherOfPDG3; + +struct QaDcaMc { + // Track/particle selection + Configurable maxProdRadius{"maxProdRadius", 9999.f, "Maximum production radius of the particle under study"}; + Configurable motherPDG{"motherPDG", 0, "PDG code of the mother particle"}; + // Charge selection + Configurable doPositivePDG{"doPositivePDG", false, "Flag to fill histograms for positive PDG codes."}; + Configurable doNegativePDG{"doNegativePDG", false, "Flag to fill histograms for negative PDG codes."}; + // Particle only selection + Configurable doEl{"do-el", false, "Flag to run with the PDG code of electrons"}; + Configurable doMu{"do-mu", false, "Flag to run with the PDG code of muons"}; + Configurable doPi{"do-pi", false, "Flag to run with the PDG code of pions"}; + Configurable doKa{"do-ka", false, "Flag to run with the PDG code of kaons"}; + Configurable doPr{"do-pr", false, "Flag to run with the PDG code of protons"}; + Configurable doDe{"do-de", false, "Flag to run with the PDG code of deuterons"}; + Configurable doTr{"do-tr", false, "Flag to run with the PDG code of tritons"}; + Configurable doHe{"do-he", false, "Flag to run with the PDG code of helium 3"}; + Configurable doAl{"do-al", false, "Flag to run with the PDG code of helium 4"}; + // Track only selection, options to select only specific tracks + Configurable minNClustersITS{"minNClustersITS", -1, "Minimum required number of ITS clusters"}; + Configurable enableTrackSelection{"enableTrackSelection", true, "Enable the track selection"}; + + // Event selection + Configurable enableEventSelection{"enableEventSelection", true, "Enable the event selection"}; + Configurable nMinNumberOfContributors{"nMinNumberOfContributors", 2, "Minimum required number of contributors to the primary vertex"}; + Configurable vertexZMin{"vertex-z-min", -10.f, "Minimum position of the generated vertez in Z (cm)"}; + Configurable vertexZMax{"vertex-z-max", 10.f, "Maximum position of the generated vertez in Z (cm)"}; + // Histogram configuration + ConfigurableAxis ptBins{"ptBins", {200, 0.f, 5.f}, "Pt binning"}; + Configurable logPt{"log-pt", 0, "Flag to use a logarithmic pT axis"}; + ConfigurableAxis etaBins{"etaBins", {200, -3.f, 3.f}, "Eta binning"}; + ConfigurableAxis phiBins{"phiBins", {200, 0.f, 6.284f}, "Phi binning"}; + ConfigurableAxis yBins{"yBins", {200, -0.5f, 0.5f}, "Y binning"}; + ConfigurableAxis dcaBinsxy{"dcaBinsxy", {500, -1.f, 1.f}, "DCAxy binning"}; + ConfigurableAxis dcaBinsz{"dcaBinsz", {100, -0.1f, 0.1f}, "DCAz binning"}; + Configurable doPVContributorCut{"doPVContributorCut", false, "Select tracks used for primary vertex recostruction (isPVContributor)"}; + + // Histograms + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + static const char* particleName(int pdgSign, o2::track::PID::ID id) + { + return Form("%s %s", pdgSign == 0 ? "Positive PDG" : "Negative PDG", o2::track::PID::getName(id)); + } + + template + void makeMCHistograms(const bool doMakeHistograms) + { + if (!doMakeHistograms) { + return; + } + + if constexpr (pdgSign == 0) { + if (!doPositivePDG) { // Positive + return; + } + } else if constexpr (pdgSign == 1) { + if (!doNegativePDG) { // Negative + return; + } + } else { + LOG(fatal) << "Can't interpret pdgSign " << pdgSign; + } + + AxisSpec axisPt{ptBins, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisP{ptBins, "#it{p} (GeV/#it{c})"}; + if (logPt) { + axisPt.makeLogarithmic(); + axisP.makeLogarithmic(); + } + const AxisSpec axisEta{etaBins, "#it{#eta}"}; + const AxisSpec axisY{yBins, "#it{y}"}; + const AxisSpec axisPhi{phiBins, "#it{#varphi} (rad)"}; + const AxisSpec axisDCAxy{dcaBinsxy, "DCA_{xy} (cm)"}; + const AxisSpec axisDCAz{dcaBinsz, "DCA_{z} (cm)"}; + + const char* partName = particleName(pdgSign, id); + LOG(info) << "Preparing histograms for particle: " << partName << " pdgSign " << pdgSign; + + const TString tagPt = Form("%s #it{#eta} [%.2f,%.2f] #it{y} [%.2f,%.2f] #it{#varphi} [%.2f,%.2f]", + partName, + etaMin, etaMax, + yMin, yMax, + phiMin, phiMax); + + hPtPrm[id][pdgSign] = histos.add(Form("MC/%s/%s/dcaxyz/pt/prm", particleNames[id], chargeNames[pdgSign]), "DCA Prm. " + tagPt, kTH3F, {axisPt, axisDCAxy, axisDCAz}); + hPtStr[id][pdgSign] = histos.add(Form("MC/%s/%s/dcaxyz/pt/str", particleNames[id], chargeNames[pdgSign]), "DCA Str. " + tagPt, kTH3F, {axisPt, axisDCAxy, axisDCAz}); + hPtMat[id][pdgSign] = histos.add(Form("MC/%s/%s/dcaxyz/pt/mat", particleNames[id], chargeNames[pdgSign]), "DCA Mat. " + tagPt, kTH3F, {axisPt, axisDCAxy, axisDCAz}); + hPtMatSM[id][pdgSign] = histos.add(Form("MC/%s/%s/dcaxyz/pt/sm", particleNames[id], chargeNames[pdgSign]), "DCA Mat. SM " + tagPt, kTH3F, {axisPt, axisDCAxy, axisDCAz}); + hPtMatSM1Dau[id][pdgSign] = histos.add(Form("MC/%s/%s/dcaxyz/pt/sm1dau", particleNames[id], chargeNames[pdgSign]), "DCA Mat. SM 1 Dau " + tagPt, kTH3F, {axisPt, axisDCAxy, axisDCAz}); + if (motherPDG.value != 0) { + hPtMotherOfPDG1[id][pdgSign] = histos.add(Form("MC/%s/%s/dcaxyz/pt/motherpdg1", particleNames[id], chargeNames[pdgSign]), "DCA mother pdg " + tagPt, kTH3F, {axisPt, axisDCAxy, axisDCAz}); + hPtMotherOfPDG2[id][pdgSign] = histos.add(Form("MC/%s/%s/dcaxyz/pt/motherpdg2", particleNames[id], chargeNames[pdgSign]), "DCA mother pdg " + tagPt, kTH3F, {axisPt, axisDCAxy, axisDCAz}); + hPtMotherOfPDG3[id][pdgSign] = histos.add(Form("MC/%s/%s/dcaxyz/pt/motherpdg3", particleNames[id], chargeNames[pdgSign]), "DCA mother pdg " + tagPt, kTH3F, {axisPt, axisDCAxy, axisDCAz}); + } + + LOG(info) << "Done with making histograms for particle: " << partName; + } + + void initMC(const AxisSpec& axisSel) + { + auto h = histos.add("MC/trackSelection", "Track Selection", kTH1D, {axisSel}); + h->GetXaxis()->SetBinLabel(trkCutIdxTrkRead, "Tracks read"); + h->GetXaxis()->SetBinLabel(trkCutIdxHasMcPart, "Passed has MC part."); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedPt, "Passed #it{p}_{T}"); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedEta, "Passed #it{#eta}"); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedPhi, "Passed #it{#varphi}"); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedY, "Passed y"); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedFake, "Passed Fake"); + h->GetXaxis()->SetBinLabel(trkCutIdxHasCollision, "Passed has collision"); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedTrkType, "passedTrackType"); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedPtRange, "passedPtRange"); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedEtaRange, "passedEtaRange"); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedDcaXYMax, "passedDCAxy max."); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedDcaXYMin, "passedDCAxy min."); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedDcaZMax, "passedDCAz max."); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedDcaZMin, "passedDCAz min."); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedGoldenChi2, "passedGoldenChi2"); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedIsPvCont, "passed isPVContributor"); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedITSPartial, "passedITS (partial)"); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedTPCPartial, "passedTPC (partial)"); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedTOFPartial, "passedTOF (partial)"); + h->GetXaxis()->SetBinLabel(trkCutIdxPassedGlobal, "No extra selection"); + + for (int i = 0; i < nSpecies; i++) { + h->GetXaxis()->SetBinLabel(trkCutIdxN + i, Form("Passed PDG %i %s", PDGs[i], particleTitle[i])); + } + histos.add("MC/fakeTrackNoiseHits", "Fake tracks from noise hits", kTH1D, {{1, 0, 1}}); + + static_for<0, 1>([&](auto pdgSign) { + makeMCHistograms(doEl); + makeMCHistograms(doMu); + makeMCHistograms(doPi); + makeMCHistograms(doKa); + makeMCHistograms(doPr); + makeMCHistograms(doDe); + makeMCHistograms(doTr); + makeMCHistograms(doHe); + makeMCHistograms(doAl); + }); + + histos.print(); + } + + // Selection cuts defined from the binning + double ptMin, ptMax; + double etaMin, etaMax; + double phiMin, phiMax; + double yMin, yMax; + + void init(InitContext&) + { + + // Printing configuration + LOG(info) << "Printing configuration"; + LOG(info) << "Set doPositivePDG to: " << (doPositivePDG ? "true" : "false"); + LOG(info) << "Set doNegativePDG to: " << (doNegativePDG ? "true" : "false"); + LOG(info) << "Set doEl to: " << (doEl ? "true" : "false"); + LOG(info) << "Set doMu to: " << (doMu ? "true" : "false"); + LOG(info) << "Set doPi to: " << (doPi ? "true" : "false"); + LOG(info) << "Set doKa to: " << (doKa ? "true" : "false"); + LOG(info) << "Set doPr to: " << (doPr ? "true" : "false"); + LOG(info) << "Set doDe to: " << (doDe ? "true" : "false"); + LOG(info) << "Set doTr to: " << (doTr ? "true" : "false"); + LOG(info) << "Set doHe to: " << (doHe ? "true" : "false"); + LOG(info) << "Set doAl to: " << (doAl ? "true" : "false"); + + auto doLimits = [&](double& min, double& max, const ConfigurableAxis& binning) { + const AxisSpec a{binning, "dummy"}; + min = a.binEdges[0]; + max = a.binEdges[a.binEdges.size() - 1]; + LOG(info) << "Making limits from " << min << ", " << max << " size " << a.getNbins(); + }; + + doLimits(ptMin, ptMax, ptBins); + doLimits(etaMin, etaMax, etaBins); + doLimits(phiMin, phiMax, phiBins); + doLimits(yMin, yMax, yBins); + + histos.add("eventSelection", "Event Selection", kTH1D, {{10, 0.5, 10.5, "Selection"}}); + histos.get(HIST("eventSelection"))->GetXaxis()->SetBinLabel(1, "Events read"); + histos.get(HIST("eventSelection"))->GetXaxis()->SetBinLabel(2, "Passed Ev. Sel. (sel8)"); + histos.get(HIST("eventSelection"))->GetXaxis()->SetBinLabel(3, "Passed Contrib."); + histos.get(HIST("eventSelection"))->GetXaxis()->SetBinLabel(4, "Passed Position"); + + const AxisSpec axisSel{40, 0.5, 40.5, "Selection"}; + initMC(axisSel); + } + + template + bool isPdgSelected(const o2::aod::McParticles::iterator& mcParticle) + { + static_assert(pdgSign == 0 || pdgSign == 1); + static_assert(id > 0 || id < nSpecies); + + // Selecting a specific PDG + if constexpr (pdgSign == 0) { + return mcParticle.pdgCode() == PDGs[id]; + } else { + return mcParticle.pdgCode() == -PDGs[id]; + } + } + + bool isPhysicalPrimary(const o2::aod::McParticles::iterator& mcParticle) + { + if (maxProdRadius < 999.f) { + if ((mcParticle.vx() * mcParticle.vx() + mcParticle.vy() * mcParticle.vy()) > maxProdRadius * maxProdRadius) { + return false; + } + } + return mcParticle.isPhysicalPrimary(); + } + + template + void fillMCTrackHistograms(const trackType& track, const bool doMakeHistograms) + { + static_assert(pdgSign == 0 || pdgSign == 1); + if (!doMakeHistograms) { + return; + } + + if constexpr (pdgSign == 0) { + if (!doPositivePDG) { + return; + } + } else { + if (!doNegativePDG) { + return; + } + } + + const o2::aod::McParticles::iterator& mcParticle = track.mcParticle(); + + if (!isPdgSelected(mcParticle)) { // Selecting PDG code + return; + } + + histos.fill(HIST("MC/trackSelection"), trkCutIdxN + id); + + if (motherPDG.value != 0) { + int motherPdgCounter = 0; + if (mcParticle.has_mothers()) { + const auto& mothers = mcParticle.mothers_as(); + for (const auto& mother : mothers) { + if (!mother.has_mothers()) { + continue; + } + const auto& mothers2 = mother.mothers_as(); + for (const auto& mother2 : mothers2) { + if (abs(mother2.pdgCode()) == motherPDG.value) { + motherPdgCounter++; + } + } + } + } + if (motherPdgCounter == 1) { + hPtMotherOfPDG1[id][pdgSign]->Fill(mcParticle.pt(), track.dcaXY(), track.dcaZ()); + } else if (motherPdgCounter == 2) { + hPtMotherOfPDG2[id][pdgSign]->Fill(mcParticle.pt(), track.dcaXY(), track.dcaZ()); + } else if (motherPdgCounter > 0) { + hPtMotherOfPDG3[id][pdgSign]->Fill(mcParticle.pt(), track.dcaXY(), track.dcaZ()); + } + } + + if (isPhysicalPrimary(mcParticle)) { + hPtPrm[id][pdgSign]->Fill(mcParticle.pt(), track.dcaXY(), track.dcaZ()); + } else if (mcParticle.getProcess() == 4) { // Particle decay + hPtStr[id][pdgSign]->Fill(mcParticle.pt(), track.dcaXY(), track.dcaZ()); + } else { // Material + hPtMat[id][pdgSign]->Fill(mcParticle.pt(), track.dcaXY(), track.dcaZ()); + if (mcParticle.has_mothers()) { + if (mcParticle.mothers_as()[0].pdgCode() == mcParticle.pdgCode()) { + hPtMatSM[id][pdgSign]->Fill(mcParticle.pt(), track.dcaXY(), track.dcaZ()); + if (mcParticle.mothers_as().size() == 1) { + hPtMatSM1Dau[id][pdgSign]->Fill(mcParticle.pt(), track.dcaXY(), track.dcaZ()); + } + } + } + } + } + + template + bool isCollisionSelected(const CollType& collision) + { + if constexpr (doFillHistograms) { + histos.fill(HIST("eventSelection"), 1); + } + if (!enableEventSelection.value) { + return true; + } + if (!collision.sel8()) { + return false; + } + if constexpr (doFillHistograms) { + histos.fill(HIST("eventSelection"), 2); + } + if (collision.numContrib() < nMinNumberOfContributors) { + return false; + } + if constexpr (doFillHistograms) { + histos.fill(HIST("eventSelection"), 3); + } + if ((collision.posZ() < vertexZMin || collision.posZ() > vertexZMax)) { + return false; + } + if constexpr (doFillHistograms) { + histos.fill(HIST("eventSelection"), 4); + } + return true; + } + + // Global process + using TrackCandidates = o2::soa::Join; + void process(o2::soa::Join::iterator const& collision, + o2::soa::Join const& tracks, + o2::aod::McParticles const&) + { + if (!isCollisionSelected(collision)) { + return; + } + + // Track loop + for (const auto& track : tracks) { + if (!isTrackSelected(track, HIST("MC/trackSelection"))) { + continue; + } + // Filling variable histograms + static_for<0, 1>([&](auto pdgSign) { + fillMCTrackHistograms(track, doEl); + fillMCTrackHistograms(track, doMu); + fillMCTrackHistograms(track, doPi); + fillMCTrackHistograms(track, doKa); + fillMCTrackHistograms(track, doPr); + fillMCTrackHistograms(track, doDe); + fillMCTrackHistograms(track, doTr); + fillMCTrackHistograms(track, doHe); + fillMCTrackHistograms(track, doAl); + }); + } + } + + // Function to apply particle selection + template + bool isInAcceptance(const particleType& particle, const histoType& countingHisto = 0, const int offset = 0) + { + if (particle.pt() < ptMin || particle.pt() > ptMax) { // Check pt + return false; + } + if constexpr (doFillHisto) { + histos.fill(countingHisto, 1 + offset); + } + if (particle.eta() < etaMin || particle.eta() > etaMax) { // Check eta + return false; + } + if constexpr (doFillHisto) { + histos.fill(countingHisto, 2 + offset); + } + if (particle.phi() < phiMin || particle.phi() > phiMax) { // Check phi + return false; + } + if constexpr (doFillHisto) { + histos.fill(countingHisto, 3 + offset); + } + if constexpr (isMC) { + if (particle.y() < yMin || particle.y() > yMax) { // Check rapidity + return false; + } + if constexpr (doFillHisto) { + histos.fill(countingHisto, 4 + offset); + } + } + + return true; + } + + // Function to apply track selection + bool passedITS = false; + bool passedTPC = false; + bool passedTRD = false; + bool passedTOF = false; + template + bool isTrackSelected(trackType& track, const histoType& countingHisto = 0) + { + // Reset selections + passedITS = false; + passedTPC = false; + passedTRD = false; + passedTOF = false; + + if constexpr (doFillHisto) { + histos.fill(countingHisto, trkCutIdxTrkRead); // Read tracks + } + + if constexpr (isMC) { // MC only + if (!track.has_mcParticle()) { + histos.fill(HIST("MC/fakeTrackNoiseHits"), 0.5); + return false; + } + if (!enableTrackSelection.value) { + return true; + } + + if constexpr (doFillHisto) { + histos.fill(countingHisto, trkCutIdxHasMcPart); // Tracks with particles (i.e. no fakes) + } + const auto mcParticle = track.mcParticle(); + if (!isInAcceptance(mcParticle, countingHisto, trkCutIdxHasMcPart)) { + // 3: pt cut 4: eta cut 5: phi cut 6: y cut + return false; + } + + // if (noFakesHits) { // Selecting tracks with no fake hits + // for (int i = 0; i < 7; i++) { // ITS + // if (track.mcMismatchInITS(i)) { + // return false; + // } + // } + // for (int i = 7; i < 10; i++) { // TPC + // if (track.mcMismatchInTPC(i)) { + // return false; + // } + // } + // } + if constexpr (doFillHisto) { + histos.fill(countingHisto, trkCutIdxPassedFake); + } + } else { // Data only + if (!isInAcceptance(track, countingHisto, trkCutIdxHasMcPart)) { + // 3: pt cut 4: eta cut 5: phi cut 6: y cut + return false; + } + } + + if (!track.has_collision()) { + return false; + } + if constexpr (doFillHisto) { + histos.fill(countingHisto, trkCutIdxHasCollision); + } + + if (!track.passedTrackType()) { + return false; + } + if constexpr (doFillHisto) { + histos.fill(countingHisto, trkCutIdxPassedTrkType); + } + if (!track.passedPtRange()) { + return false; + } + if constexpr (doFillHisto) { + histos.fill(countingHisto, trkCutIdxPassedPtRange); + } + if (!track.passedEtaRange()) { + return false; + } + if constexpr (doFillHisto) { + histos.fill(countingHisto, trkCutIdxPassedEtaRange); + } + // if (!track.passedDCAxy()) { + // return false; + // } + if constexpr (doFillHisto) { + histos.fill(countingHisto, trkCutIdxPassedDcaXYMax); + } + // if (std::abs(track.dcaXY()) < minDcaXY) { + // return false; + // } + if (track.itsNCls() < minNClustersITS) { + return false; + } + if constexpr (doFillHisto) { + histos.fill(countingHisto, trkCutIdxPassedDcaXYMin); + } + if (!track.passedDCAz()) { + return false; + } + if constexpr (doFillHisto) { + histos.fill(countingHisto, trkCutIdxPassedDcaZMax); + } + // if (std::abs(track.dcaZ()) < minDcaZ) { + // return false; + // } + if constexpr (doFillHisto) { + histos.fill(countingHisto, trkCutIdxPassedDcaZMin); + } + if (!track.passedGoldenChi2()) { + return false; + } + if constexpr (doFillHisto) { + histos.fill(countingHisto, trkCutIdxPassedGoldenChi2); + } + if (doPVContributorCut && !track.isPVContributor()) { + return false; + } + if constexpr (doFillHisto) { + histos.fill(countingHisto, trkCutIdxPassedIsPvCont); + } + + passedITS = track.passedITSNCls() && + track.passedITSChi2NDF() && + track.passedITSRefit() && + track.passedITSHits() && + track.hasITS(); + + passedTPC = track.passedTPCNCls() && + track.passedTPCCrossedRows() && + track.passedTPCCrossedRowsOverNCls() && + track.passedTPCChi2NDF() && + track.passedTPCRefit() && + track.hasTPC(); + passedTRD = track.hasTRD(); + passedTOF = track.hasTOF(); + + if (passedITS) { // Partial + if constexpr (doFillHisto) { + histos.fill(countingHisto, trkCutIdxPassedITSPartial); + } + } + + if (passedTPC) { // Partial + if constexpr (doFillHisto) { + histos.fill(countingHisto, trkCutIdxPassedTPCPartial); + } + } + + if (passedTOF) { // Partial + if constexpr (doFillHisto) { + histos.fill(countingHisto, trkCutIdxPassedTOFPartial); + } + } + if (!track.isGlobalTrackWoDCA()) { + return false; + } + if constexpr (doFillHisto) { + histos.fill(countingHisto, trkCutIdxPassedGlobal); + } + + return true; + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/DPG/Tasks/AOTTrack/qaEfficiency.cxx b/DPG/Tasks/AOTTrack/qaEfficiency.cxx index e128cfb2e35..f308ccb8568 100644 --- a/DPG/Tasks/AOTTrack/qaEfficiency.cxx +++ b/DPG/Tasks/AOTTrack/qaEfficiency.cxx @@ -13,10 +13,13 @@ /// \file qaEfficiency.cxx /// \author Nicolò Jacazio nicolo.jacazio@cern.ch /// \brief Task to analyse both data and MC to produce efficiency vs pT, eta and phi. -/// In MC the efficiency for particles is computed according to the PDG code (sign included and not charge) +/// In MC the efficiency for particles is computed according to the PDG code (sign included and not charge). /// // O2 includes +#include +#include + #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" @@ -24,18 +27,22 @@ #include "ReconstructionDataFormats/DCA.h" #include "ReconstructionDataFormats/Track.h" #include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/Core/TrackSelectionDefaults.h" #include "Common/DataModel/TrackSelectionTables.h" #include "PWGLF/DataModel/LFParticleIdentification.h" +#include "Common/Core/RecoDecay.h" // ROOT includes #include "TPDGCode.h" #include "TEfficiency.h" #include "THashList.h" +using namespace o2; using namespace o2::framework; +// Indices for the track cut histogram static constexpr int trkCutIdxTrkRead = 1; static constexpr int trkCutIdxHasMcPart = 2; static constexpr int trkCutIdxPassedPt = 3; @@ -57,14 +64,128 @@ static constexpr int trkCutIdxPassedITSPartial = 18; static constexpr int trkCutIdxPassedTPCPartial = 19; static constexpr int trkCutIdxPassedTOFPartial = 20; static constexpr int trkCutIdxPassedGlobal = 21; -static constexpr int trkCutIdxN = 22; +static constexpr int trkCutSameColl = 22; +static constexpr int trkCutIdxN = 23; + +// Particle information +static constexpr int nSpecies = o2::track::PID::NIDs; // One per PDG +static constexpr int nCharges = 2; +static constexpr int nParticles = nSpecies * nCharges; +static constexpr const char* particleTitle[nParticles] = {"e^{-}", "#mu^{-}", "#pi^{+}", + "K^{+}", "p", "d", + "t", "^{3}He", "#alpha", + "e^{+}", "#mu^{+}", "#pi^{-}", + "K^{-}", "#bar{p}", "#bar{d}", + "#bar{t}", "^{3}#bar{He}", "#bar{#alpha}"}; +static constexpr int PDGs[nParticles] = {11, 13, 211, 321, 2212, 1000010020, 1000010030, 1000020030, 1000020040, + -11, -13, -211, -321, -2212, -1000010020, -1000010030, -1000020030, -1000020040}; + +// Pt +std::array, nParticles> hPtIts; +std::array, nParticles> hPtTpc; +std::array, nParticles> hPtItsTpc; +std::array, nParticles> hPtItsTof; +std::array, nParticles> hPtTpcTof; +std::array, nParticles> hPtItsTpcTof; +std::array, nParticles> hPtItsTpcTrdTof; +std::array, nParticles> hPtItsTpcTrd; +std::array, nParticles> hPtTrkItsTpc; +std::array, nParticles> hPtGenerated; +std::array, nParticles> hPtGeneratedRecoEv; + +// Pt for primaries +std::array, nParticles> hPtItsPrm; +std::array, nParticles> hPtItsTpcPrm; +std::array, nParticles> hPtTrkItsTpcPrm; +std::array, nParticles> hPtItsTpcTofPrm; +std::array, nParticles> hPtTrkItsTpcTofPrm; +std::array, nParticles> hPtGeneratedPrm; +std::array, nParticles> hPtGeneratedPrmRecoEv; + +// Pt for secondaries from weak decay +std::array, nParticles> hPtItsTpcStr; +std::array, nParticles> hPtTrkItsTpcStr; +std::array, nParticles> hPtItsTpcTofStr; +std::array, nParticles> hPtGeneratedStr; +std::array, nParticles> hPtmotherGenerated; // histogram to store pT of mother +std::array, nParticles> hdecaylengthmother; // histogram to store decaylength of mother + +// Pt for secondaries from material +std::array, nParticles> hPtItsTpcMat; +std::array, nParticles> hPtTrkItsTpcMat; +std::array, nParticles> hPtItsTpcTofMat; +std::array, nParticles> hPtGeneratedMat; + +// Pt for tertiaries from secondary weak decay +std::array, nParticles> hPtItsTpcTer; +std::array, nParticles> hPtTrkItsTpcTer; +std::array, nParticles> hPtItsTpcTofTer; +std::array, nParticles> hPtGeneratedTer; + +// P +std::array, nParticles> hPItsTpc; +std::array, nParticles> hPTrkItsTpc; +std::array, nParticles> hPItsTpcTof; +std::array, nParticles> hPGenerated; + +// Eta +std::array, nParticles> hEtaItsTpc; +std::array, nParticles> hEtaTrkItsTpc; +std::array, nParticles> hEtaItsTpcTof; +std::array, nParticles> hEtaGenerated; + +// Eta for primaries +std::array, nParticles> hEtaItsTpcPrm; +std::array, nParticles> hEtaTrkItsTpcPrm; +std::array, nParticles> hEtaItsTpcTofPrm; +std::array, nParticles> hEtaGeneratedPrm; + +// Y +std::array, nParticles> hYItsTpc; +std::array, nParticles> hYItsTpcTof; +std::array, nParticles> hYGenerated; + +// Phi +std::array, nParticles> hPhiItsTpc; +std::array, nParticles> hPhiTrkItsTpc; +std::array, nParticles> hPhiItsTpcTof; +std::array, nParticles> hPhiGenerated; + +// Phi for primaries +std::array, nParticles> hPhiItsTpcPrm; +std::array, nParticles> hPhiTrkItsTpcPrm; +std::array, nParticles> hPhiItsTpcTofPrm; +std::array, nParticles> hPhiGeneratedPrm; + +// 2D +std::array, nParticles> hPtEtaItsTpc; +std::array, nParticles> hPtEtaTrkItsTpc; +std::array, nParticles> hPtEtaItsTpcTof; +std::array, nParticles> hPtEtaGenerated; +// 2D Pt vs Radius +std::array, nParticles> hPtRadiusItsTpc; +std::array, nParticles> hPtRadiusTrkItsTpc; +std::array, nParticles> hPtRadiusItsTpcTof; +std::array, nParticles> hPtRadiusGenerated; + +std::array, nParticles> hPtRadiusItsTpcPrm; +std::array, nParticles> hPtRadiusTrkItsTpcPrm; +std::array, nParticles> hPtRadiusItsTpcTofPrm; +std::array, nParticles> hPtRadiusGeneratedPrm; + +std::array, nParticles> hPtRadiusItsTpcStr; +std::array, nParticles> hPtRadiusTrkItsTpcStr; +std::array, nParticles> hPtRadiusItsTpcTofStr; +std::array, nParticles> hPtRadiusGeneratedStr; + +std::array, nParticles> hPtRadiusItsTpcTer; +std::array, nParticles> hPtRadiusTrkItsTpcTer; +std::array, nParticles> hPtRadiusItsTpcTofTer; +std::array, nParticles> hPtRadiusGeneratedTer; struct QaEfficiency { - // Particle information - static constexpr int nSpecies = o2::track::PID::NIDs; // One per PDG - static constexpr const char* particleTitle[nSpecies] = {"e", "#mu", "#pi", "K", "p", "d", "t", "^{3}He", "#alpha"}; - static constexpr int PDGs[nSpecies] = {kElectron, kMuonMinus, kPiPlus, kKPlus, kProton, 1000010020, 1000010030, 1000020030, 1000020040}; // Track/particle selection + Configurable numSameCollision{"numSameCollision", false, "Flag to ask that the numerator is in the same collision as the denominator"}; Configurable noFakesHits{"noFakesHits", false, "Flag to reject tracks that have fake hits"}; Configurable skipEventsWithoutTPCTracks{"skipEventsWithoutTPCTracks", false, "Flag to reject events that have no tracks reconstructed in the TPC"}; Configurable maxProdRadius{"maxProdRadius", 9999.f, "Maximum production radius of the particle under study"}; @@ -82,380 +203,78 @@ struct QaEfficiency { Configurable doTr{"do-tr", false, "Flag to run with the PDG code of tritons"}; Configurable doHe{"do-he", false, "Flag to run with the PDG code of helium 3"}; Configurable doAl{"do-al", false, "Flag to run with the PDG code of helium 4"}; + // Selection on mothers + Configurable checkForMothers{"checkForMothers", false, "Flag to use the array of mothers to check if the particle of interest come from any of those particles"}; + Configurable> mothersPDGs{"mothersPDGs", std::vector{3312, -3312}, "PDGs of origin of the particle under study"}; + Configurable keepOnlyHfParticles{"keepOnlyHfParticles", false, "Flag to decide wheter to consider only HF particles"}; + Configurable eventGeneratorType{"eventGeneratorType", -1, "Flag to check specific event generator (for HF): -1 -> no check, 0 -> MB events, 4 -> charm triggered, 5 -> beauty triggered"}; // Track only selection, options to select only specific tracks Configurable trackSelection{"trackSelection", true, "Local track selection"}; Configurable globalTrackSelection{"globalTrackSelection", 0, "Global track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks, 6 -> custom track cuts via Configurable"}; // Event selection Configurable nMinNumberOfContributors{"nMinNumberOfContributors", 2, "Minimum required number of contributors to the primary vertex"}; - Configurable vertexZMin{"vertex-z-min", -10.f, "Minimum position of the generated vertez in Z (cm)"}; - Configurable vertexZMax{"vertex-z-max", 10.f, "Maximum position of the generated vertez in Z (cm)"}; + Configurable vertexZMin{"vertex-z-min", -10.f, "Minimum position of the primary vertez in Z (cm)"}; + Configurable vertexZMax{"vertex-z-max", 10.f, "Maximum position of the primary vertez in Z (cm)"}; + Configurable applyPvZCutGenColl{"applyPvZCutGenColl", false, "Flag to enable the cut on the generated vertex z coordinate"}; + Configurable applyPvZCutInProcessMcWoColl{"applyPvZCutInProcessMcWoColl", false, "Flag to enable the cut on the vertex z coordinate (reco. & gen.) also in processMCWithoutCollisions"}; // Histogram configuration ConfigurableAxis ptBins{"ptBins", {200, 0.f, 5.f}, "Pt binning"}; Configurable logPt{"log-pt", 0, "Flag to use a logarithmic pT axis"}; ConfigurableAxis etaBins{"etaBins", {200, -3.f, 3.f}, "Eta binning"}; ConfigurableAxis phiBins{"phiBins", {200, 0.f, 6.284f}, "Phi binning"}; ConfigurableAxis yBins{"yBins", {200, -0.5f, 0.5f}, "Y binning"}; + ConfigurableAxis occBins{"occBins", {100, 0.f, 14000.f}, "Occupancy binning"}; + ConfigurableAxis centBins{"centBins", {110, 0.f, 110.f}, "Centrality binning"}; + ConfigurableAxis radiusBins{"radiusBins", {200, 0.f, 100.f}, "Radius binning"}; // Task configuration Configurable makeEff{"make-eff", false, "Flag to produce the efficiency with TEfficiency"}; Configurable doPtEta{"doPtEta", false, "Flag to produce the efficiency vs pT and Eta"}; + Configurable doPtRadius{"doPtRadius", false, "Flag to produce the efficiency vs pT and Radius"}; Configurable applyEvSel{"applyEvSel", 0, "Flag to apply event selection: 0 -> no event selection, 1 -> Run 2 event selection, 2 -> Run 3 event selection"}; // Custom track cuts for debug purposes TrackSelection customTrackCuts; - Configurable itsPattern{"itsPattern", 0, "0 = Run3ITSibAny, 1 = Run3ITSallAny, 2 = Run3ITSall7Layers, 3 = Run3ITSibTwo"}; - Configurable requireITS{"requireITS", true, "Additional cut on the ITS requirement"}; - Configurable requireTPC{"requireTPC", true, "Additional cut on the TPC requirement"}; - Configurable requireGoldenChi2{"requireGoldenChi2", true, "Additional cut on the GoldenChi2"}; - Configurable minITScl{"minITScl", 4, "Additional cut on the ITS cluster"}; + struct : ConfigurableGroup { + Configurable tracksIU{"tracksIU", false, "Additional cut for IU tracks"}; + Configurable itsPattern{"itsPattern", 0, "0 = Run3ITSibAny, 1 = Run3ITSallAny, 2 = Run3ITSall7Layers, 3 = Run3ITSibTwo"}; + Configurable requireITS{"requireITS", true, "Additional cut on the ITS requirement"}; + Configurable requireTPC{"requireTPC", true, "Additional cut on the TPC requirement"}; + Configurable requireGoldenChi2{"requireGoldenChi2", true, "Additional cut on the GoldenChi2"}; + Configurable minITScl{"minITScl", 4, "Additional cut on the ITS cluster"}; + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 70.f, "Additional cut on the minimum number of crossed rows in the TPC"}; + Configurable minNCrossedRowsOverFindableClustersTPC{"minNCrossedRowsOverFindableClustersTPC", 0.8f, "Additional cut on the minimum value of the ratio between crossed rows and findable clusters in the TPC"}; + Configurable maxChi2PerClusterTPC{"maxChi2PerClusterTPC", 4.f, "Additional cut on the maximum value of the chi2 per cluster in the TPC"}; + Configurable maxChi2PerClusterITS{"maxChi2PerClusterITS", 36.f, "Additional cut on the maximum value of the chi2 per cluster in the ITS"}; + Configurable maxDcaXY{"maxDcaXY", 10000.f, "Additional cut on the maximum abs value of the DCA xy"}; + Configurable maxDcaZ{"maxDcaZ", 2.f, "Additional cut on the maximum abs value of the DCA z"}; + Configurable minTPCNClsFound{"minTPCNClsFound", 0.f, "Additional cut on the minimum value of the number of found clusters in the TPC"}; + } cfgCustomTrackCuts; + Configurable doPVContributorCut{"doPVContributorCut", false, "Select tracks used for primary vertex recostruction (isPVContributor)"}; - Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 70.f, "Additional cut on the minimum number of crossed rows in the TPC"}; - Configurable minNCrossedRowsOverFindableClustersTPC{"minNCrossedRowsOverFindableClustersTPC", 0.8f, "Additional cut on the minimum value of the ratio between crossed rows and findable clusters in the TPC"}; - Configurable maxChi2PerClusterTPC{"maxChi2PerClusterTPC", 4.f, "Additional cut on the maximum value of the chi2 per cluster in the TPC"}; - Configurable maxChi2PerClusterITS{"maxChi2PerClusterITS", 36.f, "Additional cut on the maximum value of the chi2 per cluster in the ITS"}; - Configurable maxDcaXYFactor{"maxDcaXYFactor", 1.f, "Additional cut on the maximum value of the DCA xy (multiplicative factor)"}; - Configurable minDcaXY{"minDcaXY", -1.f, "Additional cut on the minimum value of the DCA xy"}; - Configurable maxDcaZ{"maxDcaZ", 2.f, "Additional cut on the maximum value of the DCA z"}; - Configurable minDcaZ{"minDcaZ", -2.f, "Additional cut on the minimum value of the DCA z"}; - Configurable minTPCNClsFound{"minTPCNClsFound", 0.f, "Additional cut on the minimum value of the number of found clusters in the TPC"}; + Configurable minDcaZ{"minDcaZ", -2.f, "Additional cut on the minimum abs value of the DCA z"}; + Configurable minDcaXY{"minDcaXY", -1.f, "Additional cut on the minimum abs value of the DCA xy"}; + + Configurable doOccupancy{"doOccupancyStudy", false, "Flag to store Occupancy-related information"}; + Configurable useFT0OccEstimator{"useFT0OccEstimator", false, "Flag to adopt FT0c to estimate occupancy instead of ITS"}; + // Output objects for TEfficiency OutputObj listEfficiencyMC{"EfficiencyMC"}; OutputObj listEfficiencyData{"EfficiencyData"}; + + using CollisionCandidates = o2::soa::Join; + using CollisionCandidatesMC = o2::soa::Join; + using TrackCandidates = o2::soa::Join; + using TrackCandidatesMC = o2::soa::Join; + // Histograms HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry histosPosPdg{"HistosPosPdg", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry histosNegPdg{"HistosNegPdg", {}, OutputObjHandlingPolicy::AnalysisObject}; - static constexpr int nHistograms = nSpecies * 2; - - // Pt - static constexpr std::string_view hPtIts[nHistograms] = {"MC/el/pos_pdg/pt/its", "MC/mu/pos_pdg/pt/its", "MC/pi/pos_pdg/pt/its", - "MC/ka/pos_pdg/pt/its", "MC/pr/pos_pdg/pt/its", "MC/de/pos_pdg/pt/its", - "MC/tr/pos_pdg/pt/its", "MC/he/pos_pdg/pt/its", "MC/al/pos_pdg/pt/its", - "MC/el/neg_pdg/pt/its", "MC/mu/neg_pdg/pt/its", "MC/pi/neg_pdg/pt/its", - "MC/ka/neg_pdg/pt/its", "MC/pr/neg_pdg/pt/its", "MC/de/neg_pdg/pt/its", - "MC/tr/neg_pdg/pt/its", "MC/he/neg_pdg/pt/its", "MC/al/neg_pdg/pt/its"}; - static constexpr std::string_view hPtTpc[nHistograms] = {"MC/el/pos_pdg/pt/tpc", "MC/mu/pos_pdg/pt/tpc", "MC/pi/pos_pdg/pt/tpc", - "MC/ka/pos_pdg/pt/tpc", "MC/pr/pos_pdg/pt/tpc", "MC/de/pos_pdg/pt/tpc", - "MC/tr/pos_pdg/pt/tpc", "MC/he/pos_pdg/pt/tpc", "MC/al/pos_pdg/pt/tpc", - "MC/el/neg_pdg/pt/tpc", "MC/mu/neg_pdg/pt/tpc", "MC/pi/neg_pdg/pt/tpc", - "MC/ka/neg_pdg/pt/tpc", "MC/pr/neg_pdg/pt/tpc", "MC/de/neg_pdg/pt/tpc", - "MC/tr/neg_pdg/pt/tpc", "MC/he/neg_pdg/pt/tpc", "MC/al/neg_pdg/pt/tpc"}; - static constexpr std::string_view hPtItsTpc[nHistograms] = {"MC/el/pos_pdg/pt/its_tpc", "MC/mu/pos_pdg/pt/its_tpc", "MC/pi/pos_pdg/pt/its_tpc", - "MC/ka/pos_pdg/pt/its_tpc", "MC/pr/pos_pdg/pt/its_tpc", "MC/de/pos_pdg/pt/its_tpc", - "MC/tr/pos_pdg/pt/its_tpc", "MC/he/pos_pdg/pt/its_tpc", "MC/al/pos_pdg/pt/its_tpc", - "MC/el/neg_pdg/pt/its_tpc", "MC/mu/neg_pdg/pt/its_tpc", "MC/pi/neg_pdg/pt/its_tpc", - "MC/ka/neg_pdg/pt/its_tpc", "MC/pr/neg_pdg/pt/its_tpc", "MC/de/neg_pdg/pt/its_tpc", - "MC/tr/neg_pdg/pt/its_tpc", "MC/he/neg_pdg/pt/its_tpc", "MC/al/neg_pdg/pt/its_tpc"}; - static constexpr std::string_view hPtItsTof[nHistograms] = {"MC/el/pos_pdg/pt/its_tof", "MC/mu/pos_pdg/pt/its_tof", "MC/pi/pos_pdg/pt/its_tof", - "MC/ka/pos_pdg/pt/its_tof", "MC/pr/pos_pdg/pt/its_tof", "MC/de/pos_pdg/pt/its_tof", - "MC/tr/pos_pdg/pt/its_tof", "MC/he/pos_pdg/pt/its_tof", "MC/al/pos_pdg/pt/its_tof", - "MC/el/neg_pdg/pt/its_tof", "MC/mu/neg_pdg/pt/its_tof", "MC/pi/neg_pdg/pt/its_tof", - "MC/ka/neg_pdg/pt/its_tof", "MC/pr/neg_pdg/pt/its_tof", "MC/de/neg_pdg/pt/its_tof", - "MC/tr/neg_pdg/pt/its_tof", "MC/he/neg_pdg/pt/its_tof", "MC/al/neg_pdg/pt/its_tof"}; - static constexpr std::string_view hPtTpcTof[nHistograms] = {"MC/el/pos_pdg/pt/tpc_tof", "MC/mu/pos_pdg/pt/tpc_tof", "MC/pi/pos_pdg/pt/tpc_tof", - "MC/ka/pos_pdg/pt/tpc_tof", "MC/pr/pos_pdg/pt/tpc_tof", "MC/de/pos_pdg/pt/tpc_tof", - "MC/tr/pos_pdg/pt/tpc_tof", "MC/he/pos_pdg/pt/tpc_tof", "MC/al/pos_pdg/pt/tpc_tof", - "MC/el/neg_pdg/pt/tpc_tof", "MC/mu/neg_pdg/pt/tpc_tof", "MC/pi/neg_pdg/pt/tpc_tof", - "MC/ka/neg_pdg/pt/tpc_tof", "MC/pr/neg_pdg/pt/tpc_tof", "MC/de/neg_pdg/pt/tpc_tof", - "MC/tr/neg_pdg/pt/tpc_tof", "MC/he/neg_pdg/pt/tpc_tof", "MC/al/neg_pdg/pt/tpc_tof"}; - static constexpr std::string_view hPtItsTpcTof[nHistograms] = {"MC/el/pos_pdg/pt/its_tpc_tof", "MC/mu/pos_pdg/pt/its_tpc_tof", "MC/pi/pos_pdg/pt/its_tpc_tof", - "MC/ka/pos_pdg/pt/its_tpc_tof", "MC/pr/pos_pdg/pt/its_tpc_tof", "MC/de/pos_pdg/pt/its_tpc_tof", - "MC/tr/pos_pdg/pt/its_tpc_tof", "MC/he/pos_pdg/pt/its_tpc_tof", "MC/al/pos_pdg/pt/its_tpc_tof", - "MC/el/neg_pdg/pt/its_tpc_tof", "MC/mu/neg_pdg/pt/its_tpc_tof", "MC/pi/neg_pdg/pt/its_tpc_tof", - "MC/ka/neg_pdg/pt/its_tpc_tof", "MC/pr/neg_pdg/pt/its_tpc_tof", "MC/de/neg_pdg/pt/its_tpc_tof", - "MC/tr/neg_pdg/pt/its_tpc_tof", "MC/he/neg_pdg/pt/its_tpc_tof", "MC/al/neg_pdg/pt/its_tpc_tof"}; - static constexpr std::string_view hPtItsTpcTrdTof[nHistograms] = {"MC/el/pos_pdg/pt/its_tpc_trd_tof", "MC/mu/pos_pdg/pt/its_tpc_trd_tof", "MC/pi/pos_pdg/pt/its_tpc_trd_tof", - "MC/ka/pos_pdg/pt/its_tpc_trd_tof", "MC/pr/pos_pdg/pt/its_tpc_trd_tof", "MC/de/pos_pdg/pt/its_tpc_trd_tof", - "MC/tr/pos_pdg/pt/its_tpc_trd_tof", "MC/he/pos_pdg/pt/its_tpc_trd_tof", "MC/al/pos_pdg/pt/its_tpc_trd_tof", - "MC/el/neg_pdg/pt/its_tpc_trd_tof", "MC/mu/neg_pdg/pt/its_tpc_trd_tof", "MC/pi/neg_pdg/pt/its_tpc_trd_tof", - "MC/ka/neg_pdg/pt/its_tpc_trd_tof", "MC/pr/neg_pdg/pt/its_tpc_trd_tof", "MC/de/neg_pdg/pt/its_tpc_trd_tof", - "MC/tr/neg_pdg/pt/its_tpc_trd_tof", "MC/he/neg_pdg/pt/its_tpc_trd_tof", "MC/al/neg_pdg/pt/its_tpc_trd_tof"}; - static constexpr std::string_view hPtItsTpcTrd[nHistograms] = {"MC/el/pos_pdg/pt/its_tpc_trd", "MC/mu/pos_pdg/pt/its_tpc_trd", "MC/pi/pos_pdg/pt/its_tpc_trd", - "MC/ka/pos_pdg/pt/its_tpc_trd", "MC/pr/pos_pdg/pt/its_tpc_trd", "MC/de/pos_pdg/pt/its_tpc_trd", - "MC/tr/pos_pdg/pt/its_tpc_trd", "MC/he/pos_pdg/pt/its_tpc_trd", "MC/al/pos_pdg/pt/its_tpc_trd", - "MC/el/neg_pdg/pt/its_tpc_trd", "MC/mu/neg_pdg/pt/its_tpc_trd", "MC/pi/neg_pdg/pt/its_tpc_trd", - "MC/ka/neg_pdg/pt/its_tpc_trd", "MC/pr/neg_pdg/pt/its_tpc_trd", "MC/de/neg_pdg/pt/its_tpc_trd", - "MC/tr/neg_pdg/pt/its_tpc_trd", "MC/he/neg_pdg/pt/its_tpc_trd", "MC/al/neg_pdg/pt/its_tpc_trd"}; - static constexpr std::string_view hPtTrkItsTpc[nHistograms] = {"MC/el/pos_pdg/pt/trk/its_tpc", "MC/mu/pos_pdg/pt/trk/its_tpc", "MC/pi/pos_pdg/pt/trk/its_tpc", - "MC/ka/pos_pdg/pt/trk/its_tpc", "MC/pr/pos_pdg/pt/trk/its_tpc", "MC/de/pos_pdg/pt/trk/its_tpc", - "MC/tr/pos_pdg/pt/trk/its_tpc", "MC/he/pos_pdg/pt/trk/its_tpc", "MC/al/pos_pdg/pt/trk/its_tpc", - "MC/el/neg_pdg/pt/trk/its_tpc", "MC/mu/neg_pdg/pt/trk/its_tpc", "MC/pi/neg_pdg/pt/trk/its_tpc", - "MC/ka/neg_pdg/pt/trk/its_tpc", "MC/pr/neg_pdg/pt/trk/its_tpc", "MC/de/neg_pdg/pt/trk/its_tpc", - "MC/tr/neg_pdg/pt/trk/its_tpc", "MC/he/neg_pdg/pt/trk/its_tpc", "MC/al/neg_pdg/pt/trk/its_tpc"}; - static constexpr std::string_view hPtGenerated[nHistograms] = {"MC/el/pos_pdg/pt/generated", "MC/mu/pos_pdg/pt/generated", "MC/pi/pos_pdg/pt/generated", - "MC/ka/pos_pdg/pt/generated", "MC/pr/pos_pdg/pt/generated", "MC/de/pos_pdg/pt/generated", - "MC/tr/pos_pdg/pt/generated", "MC/he/pos_pdg/pt/generated", "MC/al/pos_pdg/pt/generated", - "MC/el/neg_pdg/pt/generated", "MC/mu/neg_pdg/pt/generated", "MC/pi/neg_pdg/pt/generated", - "MC/ka/neg_pdg/pt/generated", "MC/pr/neg_pdg/pt/generated", "MC/de/neg_pdg/pt/generated", - "MC/tr/neg_pdg/pt/generated", "MC/he/neg_pdg/pt/generated", "MC/al/neg_pdg/pt/generated"}; - - // Pt for primaries - static constexpr std::string_view hPtItsPrm[nHistograms] = {"MC/el/pos_pdg/pt/prm/its", "MC/mu/pos_pdg/pt/prm/its", "MC/pi/pos_pdg/pt/prm/its", - "MC/ka/pos_pdg/pt/prm/its", "MC/pr/pos_pdg/pt/prm/its", "MC/de/pos_pdg/pt/prm/its", - "MC/tr/pos_pdg/pt/prm/its", "MC/he/pos_pdg/pt/prm/its", "MC/al/pos_pdg/pt/prm/its", - "MC/el/neg_pdg/pt/prm/its", "MC/mu/neg_pdg/pt/prm/its", "MC/pi/neg_pdg/pt/prm/its", - "MC/ka/neg_pdg/pt/prm/its", "MC/pr/neg_pdg/pt/prm/its", "MC/de/neg_pdg/pt/prm/its", - "MC/tr/neg_pdg/pt/prm/its", "MC/he/neg_pdg/pt/prm/its", "MC/al/neg_pdg/pt/prm/its"}; - static constexpr std::string_view hPtItsTpcPrm[nHistograms] = {"MC/el/pos_pdg/pt/prm/its_tpc", "MC/mu/pos_pdg/pt/prm/its_tpc", "MC/pi/pos_pdg/pt/prm/its_tpc", - "MC/ka/pos_pdg/pt/prm/its_tpc", "MC/pr/pos_pdg/pt/prm/its_tpc", "MC/de/pos_pdg/pt/prm/its_tpc", - "MC/tr/pos_pdg/pt/prm/its_tpc", "MC/he/pos_pdg/pt/prm/its_tpc", "MC/al/pos_pdg/pt/prm/its_tpc", - "MC/el/neg_pdg/pt/prm/its_tpc", "MC/mu/neg_pdg/pt/prm/its_tpc", "MC/pi/neg_pdg/pt/prm/its_tpc", - "MC/ka/neg_pdg/pt/prm/its_tpc", "MC/pr/neg_pdg/pt/prm/its_tpc", "MC/de/neg_pdg/pt/prm/its_tpc", - "MC/tr/neg_pdg/pt/prm/its_tpc", "MC/he/neg_pdg/pt/prm/its_tpc", "MC/al/neg_pdg/pt/prm/its_tpc"}; - static constexpr std::string_view hPtTrkItsTpcPrm[nHistograms] = {"MC/el/pos_pdg/pt/prm/trk/its_tpc", "MC/mu/pos_pdg/pt/prm/trk/its_tpc", "MC/pi/pos_pdg/pt/prm/trk/its_tpc", - "MC/ka/pos_pdg/pt/prm/trk/its_tpc", "MC/pr/pos_pdg/pt/prm/trk/its_tpc", "MC/de/pos_pdg/pt/prm/trk/its_tpc", - "MC/tr/pos_pdg/pt/prm/trk/its_tpc", "MC/he/pos_pdg/pt/prm/trk/its_tpc", "MC/al/pos_pdg/pt/prm/trk/its_tpc", - "MC/el/neg_pdg/pt/prm/trk/its_tpc", "MC/mu/neg_pdg/pt/prm/trk/its_tpc", "MC/pi/neg_pdg/pt/prm/trk/its_tpc", - "MC/ka/neg_pdg/pt/prm/trk/its_tpc", "MC/pr/neg_pdg/pt/prm/trk/its_tpc", "MC/de/neg_pdg/pt/prm/trk/its_tpc", - "MC/tr/neg_pdg/pt/prm/trk/its_tpc", "MC/he/neg_pdg/pt/prm/trk/its_tpc", "MC/al/neg_pdg/pt/prm/trk/its_tpc"}; - static constexpr std::string_view hPtItsTpcTofPrm[nHistograms] = {"MC/el/pos_pdg/pt/prm/its_tpc_tof", "MC/mu/pos_pdg/pt/prm/its_tpc_tof", "MC/pi/pos_pdg/pt/prm/its_tpc_tof", - "MC/ka/pos_pdg/pt/prm/its_tpc_tof", "MC/pr/pos_pdg/pt/prm/its_tpc_tof", "MC/de/pos_pdg/pt/prm/its_tpc_tof", - "MC/tr/pos_pdg/pt/prm/its_tpc_tof", "MC/he/pos_pdg/pt/prm/its_tpc_tof", "MC/al/pos_pdg/pt/prm/its_tpc_tof", - "MC/el/neg_pdg/pt/prm/its_tpc_tof", "MC/mu/neg_pdg/pt/prm/its_tpc_tof", "MC/pi/neg_pdg/pt/prm/its_tpc_tof", - "MC/ka/neg_pdg/pt/prm/its_tpc_tof", "MC/pr/neg_pdg/pt/prm/its_tpc_tof", "MC/de/neg_pdg/pt/prm/its_tpc_tof", - "MC/tr/neg_pdg/pt/prm/its_tpc_tof", "MC/he/neg_pdg/pt/prm/its_tpc_tof", "MC/al/neg_pdg/pt/prm/its_tpc_tof"}; - static constexpr std::string_view hPtTrkItsTpcTofPrm[nHistograms] = {"MC/el/pos_pdg/pt/prm/trk/its_tpc_tof", "MC/mu/pos_pdg/pt/prm/trk/its_tpc_tof", "MC/pi/pos_pdg/pt/prm/trk/its_tpc_tof", - "MC/ka/pos_pdg/pt/prm/trk/its_tpc_tof", "MC/pr/pos_pdg/pt/prm/trk/its_tpc_tof", "MC/de/pos_pdg/pt/prm/trk/its_tpc_tof", - "MC/tr/pos_pdg/pt/prm/trk/its_tpc_tof", "MC/he/pos_pdg/pt/prm/trk/its_tpc_tof", "MC/al/pos_pdg/pt/prm/trk/its_tpc_tof", - "MC/el/neg_pdg/pt/prm/trk/its_tpc_tof", "MC/mu/neg_pdg/pt/prm/trk/its_tpc_tof", "MC/pi/neg_pdg/pt/prm/trk/its_tpc_tof", - "MC/ka/neg_pdg/pt/prm/trk/its_tpc_tof", "MC/pr/neg_pdg/pt/prm/trk/its_tpc_tof", "MC/de/neg_pdg/pt/prm/trk/its_tpc_tof", - "MC/tr/neg_pdg/pt/prm/trk/its_tpc_tof", "MC/he/neg_pdg/pt/prm/trk/its_tpc_tof", "MC/al/neg_pdg/pt/prm/trk/its_tpc_tof"}; - static constexpr std::string_view hPtGeneratedPrm[nHistograms] = {"MC/el/pos_pdg/pt/prm/generated", "MC/mu/pos_pdg/pt/prm/generated", "MC/pi/pos_pdg/pt/prm/generated", - "MC/ka/pos_pdg/pt/prm/generated", "MC/pr/pos_pdg/pt/prm/generated", "MC/de/pos_pdg/pt/prm/generated", - "MC/tr/pos_pdg/pt/prm/generated", "MC/he/pos_pdg/pt/prm/generated", "MC/al/pos_pdg/pt/prm/generated", - "MC/el/neg_pdg/pt/prm/generated", "MC/mu/neg_pdg/pt/prm/generated", "MC/pi/neg_pdg/pt/prm/generated", - "MC/ka/neg_pdg/pt/prm/generated", "MC/pr/neg_pdg/pt/prm/generated", "MC/de/neg_pdg/pt/prm/generated", - "MC/tr/neg_pdg/pt/prm/generated", "MC/he/neg_pdg/pt/prm/generated", "MC/al/neg_pdg/pt/prm/generated"}; - - // Pt for secondaries from weak decay - static constexpr std::string_view hPtItsTpcStr[nHistograms] = {"MC/el/pos_pdg/pt/str/its_tpc", "MC/mu/pos_pdg/pt/str/its_tpc", "MC/pi/pos_pdg/pt/str/its_tpc", - "MC/ka/pos_pdg/pt/str/its_tpc", "MC/pr/pos_pdg/pt/str/its_tpc", "MC/de/pos_pdg/pt/str/its_tpc", - "MC/tr/pos_pdg/pt/str/its_tpc", "MC/he/pos_pdg/pt/str/its_tpc", "MC/al/pos_pdg/pt/str/its_tpc", - "MC/el/neg_pdg/pt/str/its_tpc", "MC/mu/neg_pdg/pt/str/its_tpc", "MC/pi/neg_pdg/pt/str/its_tpc", - "MC/ka/neg_pdg/pt/str/its_tpc", "MC/pr/neg_pdg/pt/str/its_tpc", "MC/de/neg_pdg/pt/str/its_tpc", - "MC/tr/neg_pdg/pt/str/its_tpc", "MC/he/neg_pdg/pt/str/its_tpc", "MC/al/neg_pdg/pt/str/its_tpc"}; - static constexpr std::string_view hPtTrkItsTpcStr[nHistograms] = {"MC/el/pos_pdg/pt/str/trk/its_tpc", "MC/mu/pos_pdg/pt/str/trk/its_tpc", "MC/pi/pos_pdg/pt/str/trk/its_tpc", - "MC/ka/pos_pdg/pt/str/trk/its_tpc", "MC/pr/pos_pdg/pt/str/trk/its_tpc", "MC/de/pos_pdg/pt/str/trk/its_tpc", - "MC/tr/pos_pdg/pt/str/trk/its_tpc", "MC/he/pos_pdg/pt/str/trk/its_tpc", "MC/al/pos_pdg/pt/str/trk/its_tpc", - "MC/el/neg_pdg/pt/str/trk/its_tpc", "MC/mu/neg_pdg/pt/str/trk/its_tpc", "MC/pi/neg_pdg/pt/str/trk/its_tpc", - "MC/ka/neg_pdg/pt/str/trk/its_tpc", "MC/pr/neg_pdg/pt/str/trk/its_tpc", "MC/de/neg_pdg/pt/str/trk/its_tpc", - "MC/tr/neg_pdg/pt/str/trk/its_tpc", "MC/he/neg_pdg/pt/str/trk/its_tpc", "MC/al/neg_pdg/pt/str/trk/its_tpc"}; - static constexpr std::string_view hPtItsTpcTofStr[nHistograms] = {"MC/el/pos_pdg/pt/str/its_tpc_tof", "MC/mu/pos_pdg/pt/str/its_tpc_tof", "MC/pi/pos_pdg/pt/str/its_tpc_tof", - "MC/ka/pos_pdg/pt/str/its_tpc_tof", "MC/pr/pos_pdg/pt/str/its_tpc_tof", "MC/de/pos_pdg/pt/str/its_tpc_tof", - "MC/tr/pos_pdg/pt/str/its_tpc_tof", "MC/he/pos_pdg/pt/str/its_tpc_tof", "MC/al/pos_pdg/pt/str/its_tpc_tof", - "MC/el/neg_pdg/pt/str/its_tpc_tof", "MC/mu/neg_pdg/pt/str/its_tpc_tof", "MC/pi/neg_pdg/pt/str/its_tpc_tof", - "MC/ka/neg_pdg/pt/str/its_tpc_tof", "MC/pr/neg_pdg/pt/str/its_tpc_tof", "MC/de/neg_pdg/pt/str/its_tpc_tof", - "MC/tr/neg_pdg/pt/str/its_tpc_tof", "MC/he/neg_pdg/pt/str/its_tpc_tof", "MC/al/neg_pdg/pt/str/its_tpc_tof"}; - static constexpr std::string_view hPtGeneratedStr[nHistograms] = {"MC/el/pos_pdg/pt/str/generated", "MC/mu/pos_pdg/pt/str/generated", "MC/pi/pos_pdg/pt/str/generated", - "MC/ka/pos_pdg/pt/str/generated", "MC/pr/pos_pdg/pt/str/generated", "MC/de/pos_pdg/pt/str/generated", - "MC/tr/pos_pdg/pt/str/generated", "MC/he/pos_pdg/pt/str/generated", "MC/al/pos_pdg/pt/str/generated", - "MC/el/neg_pdg/pt/str/generated", "MC/mu/neg_pdg/pt/str/generated", "MC/pi/neg_pdg/pt/str/generated", - "MC/ka/neg_pdg/pt/str/generated", "MC/pr/neg_pdg/pt/str/generated", "MC/de/neg_pdg/pt/str/generated", - "MC/tr/neg_pdg/pt/str/generated", "MC/he/neg_pdg/pt/str/generated", "MC/al/neg_pdg/pt/str/generated"}; - - // Pt for secondaries from material - static constexpr std::string_view hPtItsTpcMat[nHistograms] = {"MC/el/pos_pdg/pt/mat/its_tpc", "MC/mu/pos_pdg/pt/mat/its_tpc", "MC/pi/pos_pdg/pt/mat/its_tpc", - "MC/ka/pos_pdg/pt/mat/its_tpc", "MC/pr/pos_pdg/pt/mat/its_tpc", "MC/de/pos_pdg/pt/mat/its_tpc", - "MC/tr/pos_pdg/pt/mat/its_tpc", "MC/he/pos_pdg/pt/mat/its_tpc", "MC/al/pos_pdg/pt/mat/its_tpc", - "MC/el/neg_pdg/pt/mat/its_tpc", "MC/mu/neg_pdg/pt/mat/its_tpc", "MC/pi/neg_pdg/pt/mat/its_tpc", - "MC/ka/neg_pdg/pt/mat/its_tpc", "MC/pr/neg_pdg/pt/mat/its_tpc", "MC/de/neg_pdg/pt/mat/its_tpc", - "MC/tr/neg_pdg/pt/mat/its_tpc", "MC/he/neg_pdg/pt/mat/its_tpc", "MC/al/neg_pdg/pt/mat/its_tpc"}; - static constexpr std::string_view hPtTrkItsTpcMat[nHistograms] = {"MC/el/pos_pdg/pt/mat/trk/its_tpc", "MC/mu/pos_pdg/pt/mat/trk/its_tpc", "MC/pi/pos_pdg/pt/mat/trk/its_tpc", - "MC/ka/pos_pdg/pt/mat/trk/its_tpc", "MC/pr/pos_pdg/pt/mat/trk/its_tpc", "MC/de/pos_pdg/pt/mat/trk/its_tpc", - "MC/tr/pos_pdg/pt/mat/trk/its_tpc", "MC/he/pos_pdg/pt/mat/trk/its_tpc", "MC/al/pos_pdg/pt/mat/trk/its_tpc", - "MC/el/neg_pdg/pt/mat/trk/its_tpc", "MC/mu/neg_pdg/pt/mat/trk/its_tpc", "MC/pi/neg_pdg/pt/mat/trk/its_tpc", - "MC/ka/neg_pdg/pt/mat/trk/its_tpc", "MC/pr/neg_pdg/pt/mat/trk/its_tpc", "MC/de/neg_pdg/pt/mat/trk/its_tpc", - "MC/tr/neg_pdg/pt/mat/trk/its_tpc", "MC/he/neg_pdg/pt/mat/trk/its_tpc", "MC/al/neg_pdg/pt/mat/trk/its_tpc"}; - static constexpr std::string_view hPtItsTpcTofMat[nHistograms] = {"MC/el/pos_pdg/pt/mat/its_tpc_tof", "MC/mu/pos_pdg/pt/mat/its_tpc_tof", "MC/pi/pos_pdg/pt/mat/its_tpc_tof", - "MC/ka/pos_pdg/pt/mat/its_tpc_tof", "MC/pr/pos_pdg/pt/mat/its_tpc_tof", "MC/de/pos_pdg/pt/mat/its_tpc_tof", - "MC/tr/pos_pdg/pt/mat/its_tpc_tof", "MC/he/pos_pdg/pt/mat/its_tpc_tof", "MC/al/pos_pdg/pt/mat/its_tpc_tof", - "MC/el/neg_pdg/pt/mat/its_tpc_tof", "MC/mu/neg_pdg/pt/mat/its_tpc_tof", "MC/pi/neg_pdg/pt/mat/its_tpc_tof", - "MC/ka/neg_pdg/pt/mat/its_tpc_tof", "MC/pr/neg_pdg/pt/mat/its_tpc_tof", "MC/de/neg_pdg/pt/mat/its_tpc_tof", - "MC/tr/neg_pdg/pt/mat/its_tpc_tof", "MC/he/neg_pdg/pt/mat/its_tpc_tof", "MC/al/neg_pdg/pt/mat/its_tpc_tof"}; - static constexpr std::string_view hPtGeneratedMat[nHistograms] = {"MC/el/pos_pdg/pt/mat/generated", "MC/mu/pos_pdg/pt/mat/generated", "MC/pi/pos_pdg/pt/mat/generated", - "MC/ka/pos_pdg/pt/mat/generated", "MC/pr/pos_pdg/pt/mat/generated", "MC/de/pos_pdg/pt/mat/generated", - "MC/tr/pos_pdg/pt/mat/generated", "MC/he/pos_pdg/pt/mat/generated", "MC/al/pos_pdg/pt/mat/generated", - "MC/el/neg_pdg/pt/mat/generated", "MC/mu/neg_pdg/pt/mat/generated", "MC/pi/neg_pdg/pt/mat/generated", - "MC/ka/neg_pdg/pt/mat/generated", "MC/pr/neg_pdg/pt/mat/generated", "MC/de/neg_pdg/pt/mat/generated", - "MC/tr/neg_pdg/pt/mat/generated", "MC/he/neg_pdg/pt/mat/generated", "MC/al/neg_pdg/pt/mat/generated"}; - - // P - static constexpr std::string_view hPItsTpc[nHistograms] = {"MC/el/pos_pdg/p/its_tpc", "MC/mu/pos_pdg/p/its_tpc", "MC/pi/pos_pdg/p/its_tpc", - "MC/ka/pos_pdg/p/its_tpc", "MC/pr/pos_pdg/p/its_tpc", "MC/de/pos_pdg/p/its_tpc", - "MC/tr/pos_pdg/p/its_tpc", "MC/he/pos_pdg/p/its_tpc", "MC/al/pos_pdg/p/its_tpc", - "MC/el/neg_pdg/p/its_tpc", "MC/mu/neg_pdg/p/its_tpc", "MC/pi/neg_pdg/p/its_tpc", - "MC/ka/neg_pdg/p/its_tpc", "MC/pr/neg_pdg/p/its_tpc", "MC/de/neg_pdg/p/its_tpc", - "MC/tr/neg_pdg/p/its_tpc", "MC/he/neg_pdg/p/its_tpc", "MC/al/neg_pdg/p/its_tpc"}; - static constexpr std::string_view hPTrkItsTpc[nHistograms] = {"MC/el/pos_pdg/p/trk/its_tpc", "MC/mu/pos_pdg/p/trk/its_tpc", "MC/pi/pos_pdg/p/trk/its_tpc", - "MC/ka/pos_pdg/p/trk/its_tpc", "MC/pr/pos_pdg/p/trk/its_tpc", "MC/de/pos_pdg/p/trk/its_tpc", - "MC/tr/pos_pdg/p/trk/its_tpc", "MC/he/pos_pdg/p/trk/its_tpc", "MC/al/pos_pdg/p/trk/its_tpc", - "MC/el/neg_pdg/p/trk/its_tpc", "MC/mu/neg_pdg/p/trk/its_tpc", "MC/pi/neg_pdg/p/trk/its_tpc", - "MC/ka/neg_pdg/p/trk/its_tpc", "MC/pr/neg_pdg/p/trk/its_tpc", "MC/de/neg_pdg/p/trk/its_tpc", - "MC/tr/neg_pdg/p/trk/its_tpc", "MC/he/neg_pdg/p/trk/its_tpc", "MC/al/neg_pdg/p/trk/its_tpc"}; - static constexpr std::string_view hPItsTpcTof[nHistograms] = {"MC/el/pos_pdg/p/its_tpc_tof", "MC/mu/pos_pdg/p/its_tpc_tof", "MC/pi/pos_pdg/p/its_tpc_tof", - "MC/ka/pos_pdg/p/its_tpc_tof", "MC/pr/pos_pdg/p/its_tpc_tof", "MC/de/pos_pdg/p/its_tpc_tof", - "MC/tr/pos_pdg/p/its_tpc_tof", "MC/he/pos_pdg/p/its_tpc_tof", "MC/al/pos_pdg/p/its_tpc_tof", - "MC/el/neg_pdg/p/its_tpc_tof", "MC/mu/neg_pdg/p/its_tpc_tof", "MC/pi/neg_pdg/p/its_tpc_tof", - "MC/ka/neg_pdg/p/its_tpc_tof", "MC/pr/neg_pdg/p/its_tpc_tof", "MC/de/neg_pdg/p/its_tpc_tof", - "MC/tr/neg_pdg/p/its_tpc_tof", "MC/he/neg_pdg/p/its_tpc_tof", "MC/al/neg_pdg/p/its_tpc_tof"}; - static constexpr std::string_view hPGenerated[nHistograms] = {"MC/el/pos_pdg/p/generated", "MC/mu/pos_pdg/p/generated", "MC/pi/pos_pdg/p/generated", - "MC/ka/pos_pdg/p/generated", "MC/pr/pos_pdg/p/generated", "MC/de/pos_pdg/p/generated", - "MC/tr/pos_pdg/p/generated", "MC/he/pos_pdg/p/generated", "MC/al/pos_pdg/p/generated", - "MC/el/neg_pdg/p/generated", "MC/mu/neg_pdg/p/generated", "MC/pi/neg_pdg/p/generated", - "MC/ka/neg_pdg/p/generated", "MC/pr/neg_pdg/p/generated", "MC/de/neg_pdg/p/generated", - "MC/tr/neg_pdg/p/generated", "MC/he/neg_pdg/p/generated", "MC/al/neg_pdg/p/generated"}; - - // Eta - static constexpr std::string_view hEtaItsTpc[nHistograms] = {"MC/el/pos_pdg/eta/its_tpc", "MC/mu/pos_pdg/eta/its_tpc", "MC/pi/pos_pdg/eta/its_tpc", - "MC/ka/pos_pdg/eta/its_tpc", "MC/pr/pos_pdg/eta/its_tpc", "MC/de/pos_pdg/eta/its_tpc", - "MC/tr/pos_pdg/eta/its_tpc", "MC/he/pos_pdg/eta/its_tpc", "MC/al/pos_pdg/eta/its_tpc", - "MC/el/neg_pdg/eta/its_tpc", "MC/mu/neg_pdg/eta/its_tpc", "MC/pi/neg_pdg/eta/its_tpc", - "MC/ka/neg_pdg/eta/its_tpc", "MC/pr/neg_pdg/eta/its_tpc", "MC/de/neg_pdg/eta/its_tpc", - "MC/tr/neg_pdg/eta/its_tpc", "MC/he/neg_pdg/eta/its_tpc", "MC/al/neg_pdg/eta/its_tpc"}; - static constexpr std::string_view hEtaTrkItsTpc[nHistograms] = {"MC/el/pos_pdg/eta/trk/its_tpc", "MC/mu/pos_pdg/eta/trk/its_tpc", "MC/pi/pos_pdg/eta/trk/its_tpc", - "MC/ka/pos_pdg/eta/trk/its_tpc", "MC/pr/pos_pdg/eta/trk/its_tpc", "MC/de/pos_pdg/eta/trk/its_tpc", - "MC/tr/pos_pdg/eta/trk/its_tpc", "MC/he/pos_pdg/eta/trk/its_tpc", "MC/al/pos_pdg/eta/trk/its_tpc", - "MC/el/neg_pdg/eta/trk/its_tpc", "MC/mu/neg_pdg/eta/trk/its_tpc", "MC/pi/neg_pdg/eta/trk/its_tpc", - "MC/ka/neg_pdg/eta/trk/its_tpc", "MC/pr/neg_pdg/eta/trk/its_tpc", "MC/de/neg_pdg/eta/trk/its_tpc", - "MC/tr/neg_pdg/eta/trk/its_tpc", "MC/he/neg_pdg/eta/trk/its_tpc", "MC/al/neg_pdg/eta/trk/its_tpc"}; - static constexpr std::string_view hEtaItsTpcTof[nHistograms] = {"MC/el/pos_pdg/eta/its_tpc_tof", "MC/mu/pos_pdg/eta/its_tpc_tof", "MC/pi/pos_pdg/eta/its_tpc_tof", - "MC/ka/pos_pdg/eta/its_tpc_tof", "MC/pr/pos_pdg/eta/its_tpc_tof", "MC/de/pos_pdg/eta/its_tpc_tof", - "MC/tr/pos_pdg/eta/its_tpc_tof", "MC/he/pos_pdg/eta/its_tpc_tof", "MC/al/pos_pdg/eta/its_tpc_tof", - "MC/el/neg_pdg/eta/its_tpc_tof", "MC/mu/neg_pdg/eta/its_tpc_tof", "MC/pi/neg_pdg/eta/its_tpc_tof", - "MC/ka/neg_pdg/eta/its_tpc_tof", "MC/pr/neg_pdg/eta/its_tpc_tof", "MC/de/neg_pdg/eta/its_tpc_tof", - "MC/tr/neg_pdg/eta/its_tpc_tof", "MC/he/neg_pdg/eta/its_tpc_tof", "MC/al/neg_pdg/eta/its_tpc_tof"}; - static constexpr std::string_view hEtaGenerated[nHistograms] = {"MC/el/pos_pdg/eta/generated", "MC/mu/pos_pdg/eta/generated", "MC/pi/pos_pdg/eta/generated", - "MC/ka/pos_pdg/eta/generated", "MC/pr/pos_pdg/eta/generated", "MC/de/pos_pdg/eta/generated", - "MC/tr/pos_pdg/eta/generated", "MC/he/pos_pdg/eta/generated", "MC/al/pos_pdg/eta/generated", - "MC/el/neg_pdg/eta/generated", "MC/mu/neg_pdg/eta/generated", "MC/pi/neg_pdg/eta/generated", - "MC/ka/neg_pdg/eta/generated", "MC/pr/neg_pdg/eta/generated", "MC/de/neg_pdg/eta/generated", - "MC/tr/neg_pdg/eta/generated", "MC/he/neg_pdg/eta/generated", "MC/al/neg_pdg/eta/generated"}; - - // Eta for primaries - static constexpr std::string_view hEtaItsTpcPrm[nHistograms] = {"MC/el/pos_pdg/eta/prm/its_tpc", "MC/mu/pos_pdg/eta/prm/its_tpc", "MC/pi/pos_pdg/eta/prm/its_tpc", - "MC/ka/pos_pdg/eta/prm/its_tpc", "MC/pr/pos_pdg/eta/prm/its_tpc", "MC/de/pos_pdg/eta/prm/its_tpc", - "MC/tr/pos_pdg/eta/prm/its_tpc", "MC/he/pos_pdg/eta/prm/its_tpc", "MC/al/pos_pdg/eta/prm/its_tpc", - "MC/el/neg_pdg/eta/prm/its_tpc", "MC/mu/neg_pdg/eta/prm/its_tpc", "MC/pi/neg_pdg/eta/prm/its_tpc", - "MC/ka/neg_pdg/eta/prm/its_tpc", "MC/pr/neg_pdg/eta/prm/its_tpc", "MC/de/neg_pdg/eta/prm/its_tpc", - "MC/tr/neg_pdg/eta/prm/its_tpc", "MC/he/neg_pdg/eta/prm/its_tpc", "MC/al/neg_pdg/eta/prm/its_tpc"}; - static constexpr std::string_view hEtaTrkItsTpcPrm[nHistograms] = {"MC/el/pos_pdg/eta/prm/trk/its_tpc", "MC/mu/pos_pdg/eta/prm/trk/its_tpc", "MC/pi/pos_pdg/eta/prm/trk/its_tpc", - "MC/ka/pos_pdg/eta/prm/trk/its_tpc", "MC/pr/pos_pdg/eta/prm/trk/its_tpc", "MC/de/pos_pdg/eta/prm/trk/its_tpc", - "MC/tr/pos_pdg/eta/prm/trk/its_tpc", "MC/he/pos_pdg/eta/prm/trk/its_tpc", "MC/al/pos_pdg/eta/prm/trk/its_tpc", - "MC/el/neg_pdg/eta/prm/trk/its_tpc", "MC/mu/neg_pdg/eta/prm/trk/its_tpc", "MC/pi/neg_pdg/eta/prm/trk/its_tpc", - "MC/ka/neg_pdg/eta/prm/trk/its_tpc", "MC/pr/neg_pdg/eta/prm/trk/its_tpc", "MC/de/neg_pdg/eta/prm/trk/its_tpc", - "MC/tr/neg_pdg/eta/prm/trk/its_tpc", "MC/he/neg_pdg/eta/prm/trk/its_tpc", "MC/al/neg_pdg/eta/prm/trk/its_tpc"}; - static constexpr std::string_view hEtaItsTpcTofPrm[nHistograms] = {"MC/el/pos_pdg/eta/prm/its_tpc_tof", "MC/mu/pos_pdg/eta/prm/its_tpc_tof", "MC/pi/pos_pdg/eta/prm/its_tpc_tof", - "MC/ka/pos_pdg/eta/prm/its_tpc_tof", "MC/pr/pos_pdg/eta/prm/its_tpc_tof", "MC/de/pos_pdg/eta/prm/its_tpc_tof", - "MC/tr/pos_pdg/eta/prm/its_tpc_tof", "MC/he/pos_pdg/eta/prm/its_tpc_tof", "MC/al/pos_pdg/eta/prm/its_tpc_tof", - "MC/el/neg_pdg/eta/prm/its_tpc_tof", "MC/mu/neg_pdg/eta/prm/its_tpc_tof", "MC/pi/neg_pdg/eta/prm/its_tpc_tof", - "MC/ka/neg_pdg/eta/prm/its_tpc_tof", "MC/pr/neg_pdg/eta/prm/its_tpc_tof", "MC/de/neg_pdg/eta/prm/its_tpc_tof", - "MC/tr/neg_pdg/eta/prm/its_tpc_tof", "MC/he/neg_pdg/eta/prm/its_tpc_tof", "MC/al/neg_pdg/eta/prm/its_tpc_tof"}; - static constexpr std::string_view hEtaGeneratedPrm[nHistograms] = {"MC/el/pos_pdg/eta/prm/generated", "MC/mu/pos_pdg/eta/prm/generated", "MC/pi/pos_pdg/eta/prm/generated", - "MC/ka/pos_pdg/eta/prm/generated", "MC/pr/pos_pdg/eta/prm/generated", "MC/de/pos_pdg/eta/prm/generated", - "MC/tr/pos_pdg/eta/prm/generated", "MC/he/pos_pdg/eta/prm/generated", "MC/al/pos_pdg/eta/prm/generated", - "MC/el/neg_pdg/eta/prm/generated", "MC/mu/neg_pdg/eta/prm/generated", "MC/pi/neg_pdg/eta/prm/generated", - "MC/ka/neg_pdg/eta/prm/generated", "MC/pr/neg_pdg/eta/prm/generated", "MC/de/neg_pdg/eta/prm/generated", - "MC/tr/neg_pdg/eta/prm/generated", "MC/he/neg_pdg/eta/prm/generated", "MC/al/neg_pdg/eta/prm/generated"}; - - // Y - static constexpr std::string_view hYItsTpc[nHistograms] = {"MC/el/pos_pdg/y/its_tpc", "MC/mu/pos_pdg/y/its_tpc", "MC/pi/pos_pdg/y/its_tpc", - "MC/ka/pos_pdg/y/its_tpc", "MC/pr/pos_pdg/y/its_tpc", "MC/de/pos_pdg/y/its_tpc", - "MC/tr/pos_pdg/y/its_tpc", "MC/he/pos_pdg/y/its_tpc", "MC/al/pos_pdg/y/its_tpc", - "MC/el/neg_pdg/y/its_tpc", "MC/mu/neg_pdg/y/its_tpc", "MC/pi/neg_pdg/y/its_tpc", - "MC/ka/neg_pdg/y/its_tpc", "MC/pr/neg_pdg/y/its_tpc", "MC/de/neg_pdg/y/its_tpc", - "MC/tr/neg_pdg/y/its_tpc", "MC/he/neg_pdg/y/its_tpc", "MC/al/neg_pdg/y/its_tpc"}; - static constexpr std::string_view hYItsTpcTof[nHistograms] = {"MC/el/pos_pdg/y/its_tpc_tof", "MC/mu/pos_pdg/y/its_tpc_tof", "MC/pi/pos_pdg/y/its_tpc_tof", - "MC/ka/pos_pdg/y/its_tpc_tof", "MC/pr/pos_pdg/y/its_tpc_tof", "MC/de/pos_pdg/y/its_tpc_tof", - "MC/tr/pos_pdg/y/its_tpc_tof", "MC/he/pos_pdg/y/its_tpc_tof", "MC/al/pos_pdg/y/its_tpc_tof", - "MC/el/neg_pdg/y/its_tpc_tof", "MC/mu/neg_pdg/y/its_tpc_tof", "MC/pi/neg_pdg/y/its_tpc_tof", - "MC/ka/neg_pdg/y/its_tpc_tof", "MC/pr/neg_pdg/y/its_tpc_tof", "MC/de/neg_pdg/y/its_tpc_tof", - "MC/tr/neg_pdg/y/its_tpc_tof", "MC/he/neg_pdg/y/its_tpc_tof", "MC/al/neg_pdg/y/its_tpc_tof"}; - static constexpr std::string_view hYGenerated[nHistograms] = {"MC/el/pos_pdg/y/generated", "MC/mu/pos_pdg/y/generated", "MC/pi/pos_pdg/y/generated", - "MC/ka/pos_pdg/y/generated", "MC/pr/pos_pdg/y/generated", "MC/de/pos_pdg/y/generated", - "MC/tr/pos_pdg/y/generated", "MC/he/pos_pdg/y/generated", "MC/al/pos_pdg/y/generated", - "MC/el/neg_pdg/y/generated", "MC/mu/neg_pdg/y/generated", "MC/pi/neg_pdg/y/generated", - "MC/ka/neg_pdg/y/generated", "MC/pr/neg_pdg/y/generated", "MC/de/neg_pdg/y/generated", - "MC/tr/neg_pdg/y/generated", "MC/he/neg_pdg/y/generated", "MC/al/neg_pdg/y/generated"}; - - // Phi - static constexpr std::string_view hPhiItsTpc[nHistograms] = {"MC/el/pos_pdg/phi/its_tpc", "MC/mu/pos_pdg/phi/its_tpc", "MC/pi/pos_pdg/phi/its_tpc", - "MC/ka/pos_pdg/phi/its_tpc", "MC/pr/pos_pdg/phi/its_tpc", "MC/de/pos_pdg/phi/its_tpc", - "MC/tr/pos_pdg/phi/its_tpc", "MC/he/pos_pdg/phi/its_tpc", "MC/al/pos_pdg/phi/its_tpc", - "MC/el/neg_pdg/phi/its_tpc", "MC/mu/neg_pdg/phi/its_tpc", "MC/pi/neg_pdg/phi/its_tpc", - "MC/ka/neg_pdg/phi/its_tpc", "MC/pr/neg_pdg/phi/its_tpc", "MC/de/neg_pdg/phi/its_tpc", - "MC/tr/neg_pdg/phi/its_tpc", "MC/he/neg_pdg/phi/its_tpc", "MC/al/neg_pdg/phi/its_tpc"}; - static constexpr std::string_view hPhiTrkItsTpc[nHistograms] = {"MC/el/pos_pdg/phi/trk/its_tpc", "MC/mu/pos_pdg/phi/trk/its_tpc", "MC/pi/pos_pdg/phi/trk/its_tpc", - "MC/ka/pos_pdg/phi/trk/its_tpc", "MC/pr/pos_pdg/phi/trk/its_tpc", "MC/de/pos_pdg/phi/trk/its_tpc", - "MC/tr/pos_pdg/phi/trk/its_tpc", "MC/he/pos_pdg/phi/trk/its_tpc", "MC/al/pos_pdg/phi/trk/its_tpc", - "MC/el/neg_pdg/phi/trk/its_tpc", "MC/mu/neg_pdg/phi/trk/its_tpc", "MC/pi/neg_pdg/phi/trk/its_tpc", - "MC/ka/neg_pdg/phi/trk/its_tpc", "MC/pr/neg_pdg/phi/trk/its_tpc", "MC/de/neg_pdg/phi/trk/its_tpc", - "MC/tr/neg_pdg/phi/trk/its_tpc", "MC/he/neg_pdg/phi/trk/its_tpc", "MC/al/neg_pdg/phi/trk/its_tpc"}; - static constexpr std::string_view hPhiItsTpcTof[nHistograms] = {"MC/el/pos_pdg/phi/its_tpc_tof", "MC/mu/pos_pdg/phi/its_tpc_tof", "MC/pi/pos_pdg/phi/its_tpc_tof", - "MC/ka/pos_pdg/phi/its_tpc_tof", "MC/pr/pos_pdg/phi/its_tpc_tof", "MC/de/pos_pdg/phi/its_tpc_tof", - "MC/tr/pos_pdg/phi/its_tpc_tof", "MC/he/pos_pdg/phi/its_tpc_tof", "MC/al/pos_pdg/phi/its_tpc_tof", - "MC/el/neg_pdg/phi/its_tpc_tof", "MC/mu/neg_pdg/phi/its_tpc_tof", "MC/pi/neg_pdg/phi/its_tpc_tof", - "MC/ka/neg_pdg/phi/its_tpc_tof", "MC/pr/neg_pdg/phi/its_tpc_tof", "MC/de/neg_pdg/phi/its_tpc_tof", - "MC/tr/neg_pdg/phi/its_tpc_tof", "MC/he/neg_pdg/phi/its_tpc_tof", "MC/al/neg_pdg/phi/its_tpc_tof"}; - static constexpr std::string_view hPhiGenerated[nHistograms] = {"MC/el/pos_pdg/phi/generated", "MC/mu/pos_pdg/phi/generated", "MC/pi/pos_pdg/phi/generated", - "MC/ka/pos_pdg/phi/generated", "MC/pr/pos_pdg/phi/generated", "MC/de/pos_pdg/phi/generated", - "MC/tr/pos_pdg/phi/generated", "MC/he/pos_pdg/phi/generated", "MC/al/pos_pdg/phi/generated", - "MC/el/neg_pdg/phi/generated", "MC/mu/neg_pdg/phi/generated", "MC/pi/neg_pdg/phi/generated", - "MC/ka/neg_pdg/phi/generated", "MC/pr/neg_pdg/phi/generated", "MC/de/neg_pdg/phi/generated", - "MC/tr/neg_pdg/phi/generated", "MC/he/neg_pdg/phi/generated", "MC/al/neg_pdg/phi/generated"}; - - // Phi for primaries - static constexpr std::string_view hPhiItsTpcPrm[nHistograms] = {"MC/el/pos_pdg/phi/prm/its_tpc", "MC/mu/pos_pdg/phi/prm/its_tpc", "MC/pi/pos_pdg/phi/prm/its_tpc", - "MC/ka/pos_pdg/phi/prm/its_tpc", "MC/pr/pos_pdg/phi/prm/its_tpc", "MC/de/pos_pdg/phi/prm/its_tpc", - "MC/tr/pos_pdg/phi/prm/its_tpc", "MC/he/pos_pdg/phi/prm/its_tpc", "MC/al/pos_pdg/phi/prm/its_tpc", - "MC/el/neg_pdg/phi/prm/its_tpc", "MC/mu/neg_pdg/phi/prm/its_tpc", "MC/pi/neg_pdg/phi/prm/its_tpc", - "MC/ka/neg_pdg/phi/prm/its_tpc", "MC/pr/neg_pdg/phi/prm/its_tpc", "MC/de/neg_pdg/phi/prm/its_tpc", - "MC/tr/neg_pdg/phi/prm/its_tpc", "MC/he/neg_pdg/phi/prm/its_tpc", "MC/al/neg_pdg/phi/prm/its_tpc"}; - static constexpr std::string_view hPhiTrkItsTpcPrm[nHistograms] = {"MC/el/pos_pdg/phi/prm/trk/its_tpc", "MC/mu/pos_pdg/phi/prm/trk/its_tpc", "MC/pi/pos_pdg/phi/prm/trk/its_tpc", - "MC/ka/pos_pdg/phi/prm/trk/its_tpc", "MC/pr/pos_pdg/phi/prm/trk/its_tpc", "MC/de/pos_pdg/phi/prm/trk/its_tpc", - "MC/tr/pos_pdg/phi/prm/trk/its_tpc", "MC/he/pos_pdg/phi/prm/trk/its_tpc", "MC/al/pos_pdg/phi/prm/trk/its_tpc", - "MC/el/neg_pdg/phi/prm/trk/its_tpc", "MC/mu/neg_pdg/phi/prm/trk/its_tpc", "MC/pi/neg_pdg/phi/prm/trk/its_tpc", - "MC/ka/neg_pdg/phi/prm/trk/its_tpc", "MC/pr/neg_pdg/phi/prm/trk/its_tpc", "MC/de/neg_pdg/phi/prm/trk/its_tpc", - "MC/tr/neg_pdg/phi/prm/trk/its_tpc", "MC/he/neg_pdg/phi/prm/trk/its_tpc", "MC/al/neg_pdg/phi/prm/trk/its_tpc"}; - static constexpr std::string_view hPhiItsTpcTofPrm[nHistograms] = {"MC/el/pos_pdg/phi/prm/its_tpc_tof", "MC/mu/pos_pdg/phi/prm/its_tpc_tof", "MC/pi/pos_pdg/phi/prm/its_tpc_tof", - "MC/ka/pos_pdg/phi/prm/its_tpc_tof", "MC/pr/pos_pdg/phi/prm/its_tpc_tof", "MC/de/pos_pdg/phi/prm/its_tpc_tof", - "MC/tr/pos_pdg/phi/prm/its_tpc_tof", "MC/he/pos_pdg/phi/prm/its_tpc_tof", "MC/al/pos_pdg/phi/prm/its_tpc_tof", - "MC/el/neg_pdg/phi/prm/its_tpc_tof", "MC/mu/neg_pdg/phi/prm/its_tpc_tof", "MC/pi/neg_pdg/phi/prm/its_tpc_tof", - "MC/ka/neg_pdg/phi/prm/its_tpc_tof", "MC/pr/neg_pdg/phi/prm/its_tpc_tof", "MC/de/neg_pdg/phi/prm/its_tpc_tof", - "MC/tr/neg_pdg/phi/prm/its_tpc_tof", "MC/he/neg_pdg/phi/prm/its_tpc_tof", "MC/al/neg_pdg/phi/prm/its_tpc_tof"}; - static constexpr std::string_view hPhiGeneratedPrm[nHistograms] = {"MC/el/pos_pdg/phi/prm/generated", "MC/mu/pos_pdg/phi/prm/generated", "MC/pi/pos_pdg/phi/prm/generated", - "MC/ka/pos_pdg/phi/prm/generated", "MC/pr/pos_pdg/phi/prm/generated", "MC/de/pos_pdg/phi/prm/generated", - "MC/tr/pos_pdg/phi/prm/generated", "MC/he/pos_pdg/phi/prm/generated", "MC/al/pos_pdg/phi/prm/generated", - "MC/el/neg_pdg/phi/prm/generated", "MC/mu/neg_pdg/phi/prm/generated", "MC/pi/neg_pdg/phi/prm/generated", - "MC/ka/neg_pdg/phi/prm/generated", "MC/pr/neg_pdg/phi/prm/generated", "MC/de/neg_pdg/phi/prm/generated", - "MC/tr/neg_pdg/phi/prm/generated", "MC/he/neg_pdg/phi/prm/generated", "MC/al/neg_pdg/phi/prm/generated"}; - - // Pt-Eta - static constexpr std::string_view hPtEtaItsTpc[nHistograms] = {"MC/el/pos_pdg/pteta/its_tpc", "MC/mu/pos_pdg/pteta/its_tpc", "MC/pi/pos_pdg/pteta/its_tpc", - "MC/ka/pos_pdg/pteta/its_tpc", "MC/pr/pos_pdg/pteta/its_tpc", "MC/de/pos_pdg/pteta/its_tpc", - "MC/tr/pos_pdg/pteta/its_tpc", "MC/he/pos_pdg/pteta/its_tpc", "MC/al/pos_pdg/pteta/its_tpc", - "MC/el/neg_pdg/pteta/its_tpc", "MC/mu/neg_pdg/pteta/its_tpc", "MC/pi/neg_pdg/pteta/its_tpc", - "MC/ka/neg_pdg/pteta/its_tpc", "MC/pr/neg_pdg/pteta/its_tpc", "MC/de/neg_pdg/pteta/its_tpc", - "MC/tr/neg_pdg/pteta/its_tpc", "MC/he/neg_pdg/pteta/its_tpc", "MC/al/neg_pdg/pteta/its_tpc"}; - static constexpr std::string_view hPtEtaTrkItsTpc[nHistograms] = {"MC/el/pos_pdg/pteta/trk/its_tpc", "MC/mu/pos_pdg/pteta/trk/its_tpc", "MC/pi/pos_pdg/pteta/trk/its_tpc", - "MC/ka/pos_pdg/pteta/trk/its_tpc", "MC/pr/pos_pdg/pteta/trk/its_tpc", "MC/de/pos_pdg/pteta/trk/its_tpc", - "MC/tr/pos_pdg/pteta/trk/its_tpc", "MC/he/pos_pdg/pteta/trk/its_tpc", "MC/al/pos_pdg/pteta/trk/its_tpc", - "MC/el/neg_pdg/pteta/trk/its_tpc", "MC/mu/neg_pdg/pteta/trk/its_tpc", "MC/pi/neg_pdg/pteta/trk/its_tpc", - "MC/ka/neg_pdg/pteta/trk/its_tpc", "MC/pr/neg_pdg/pteta/trk/its_tpc", "MC/de/neg_pdg/pteta/trk/its_tpc", - "MC/tr/neg_pdg/pteta/trk/its_tpc", "MC/he/neg_pdg/pteta/trk/its_tpc", "MC/al/neg_pdg/pteta/trk/its_tpc"}; - static constexpr std::string_view hPtEtaItsTpcTof[nHistograms] = {"MC/el/pos_pdg/pteta/its_tpc_tof", "MC/mu/pos_pdg/pteta/its_tpc_tof", "MC/pi/pos_pdg/pteta/its_tpc_tof", - "MC/ka/pos_pdg/pteta/its_tpc_tof", "MC/pr/pos_pdg/pteta/its_tpc_tof", "MC/de/pos_pdg/pteta/its_tpc_tof", - "MC/tr/pos_pdg/pteta/its_tpc_tof", "MC/he/pos_pdg/pteta/its_tpc_tof", "MC/al/pos_pdg/pteta/its_tpc_tof", - "MC/el/neg_pdg/pteta/its_tpc_tof", "MC/mu/neg_pdg/pteta/its_tpc_tof", "MC/pi/neg_pdg/pteta/its_tpc_tof", - "MC/ka/neg_pdg/pteta/its_tpc_tof", "MC/pr/neg_pdg/pteta/its_tpc_tof", "MC/de/neg_pdg/pteta/its_tpc_tof", - "MC/tr/neg_pdg/pteta/its_tpc_tof", "MC/he/neg_pdg/pteta/its_tpc_tof", "MC/al/neg_pdg/pteta/its_tpc_tof"}; - static constexpr std::string_view hPtEtaGenerated[nHistograms] = {"MC/el/pos_pdg/pteta/generated", "MC/mu/pos_pdg/pteta/generated", "MC/pi/pos_pdg/pteta/generated", - "MC/ka/pos_pdg/pteta/generated", "MC/pr/pos_pdg/pteta/generated", "MC/de/pos_pdg/pteta/generated", - "MC/tr/pos_pdg/pteta/generated", "MC/he/pos_pdg/pteta/generated", "MC/al/pos_pdg/pteta/generated", - "MC/el/neg_pdg/pteta/generated", "MC/mu/neg_pdg/pteta/generated", "MC/pi/neg_pdg/pteta/generated", - "MC/ka/neg_pdg/pteta/generated", "MC/pr/neg_pdg/pteta/generated", "MC/de/neg_pdg/pteta/generated", - "MC/tr/neg_pdg/pteta/generated", "MC/he/neg_pdg/pteta/generated", "MC/al/neg_pdg/pteta/generated"}; static const char* particleName(int pdgSign, o2::track::PID::ID id) { - return Form("%s %s", pdgSign == 0 ? "Positive PDG" : "Negative PDG", o2::track::PID::getName(id)); + if (pdgSign == 0) { // Positive PDG + return particleTitle[id]; + } + // Negative PDG + return particleTitle[id + o2::track::PID::NIDs]; } template @@ -477,6 +296,7 @@ struct QaEfficiency { LOG(fatal) << "Can't interpret pdgSign " << pdgSign; } + AxisSpec axisDecayLength{100, 0.0, 10.0, "Decay Length (cm)"}; AxisSpec axisPt{ptBins, "#it{p}_{T} (GeV/#it{c})"}; AxisSpec axisP{ptBins, "#it{p} (GeV/#it{c})"}; if (logPt) { @@ -486,6 +306,8 @@ struct QaEfficiency { const AxisSpec axisEta{etaBins, "#it{#eta}"}; const AxisSpec axisY{yBins, "#it{y}"}; const AxisSpec axisPhi{phiBins, "#it{#varphi} (rad)"}; + const AxisSpec axisRadius{radiusBins, "Radius (cm)"}; + const AxisSpec axisOcc{occBins, "Occupancy"}; const char* partName = particleName(pdgSign, id); LOG(info) << "Preparing histograms for particle: " << partName << " pdgSign " << pdgSign; @@ -518,78 +340,111 @@ struct QaEfficiency { partName, phiMin, phiMax, yMin, yMax); - const int histogramIndex = id + pdgSign * nSpecies; - HistogramRegistry* registry = &histosPosPdg; - if (pdgSign == 1) { - registry = &histosNegPdg; - } - - registry->add(hPtIts[histogramIndex].data(), "ITS tracks " + tagPt, kTH1F, {axisPt}); - registry->add(hPtTpc[histogramIndex].data(), "TPC tracks " + tagPt, kTH1F, {axisPt}); - registry->add(hPtItsTpc[histogramIndex].data(), "ITS-TPC tracks " + tagPt, kTH1F, {axisPt}); - registry->add(hPtItsTof[histogramIndex].data(), "ITS-TOF tracks " + tagPt, kTH1F, {axisPt}); - registry->add(hPtTpcTof[histogramIndex].data(), "TPC-TOF tracks " + tagPt, kTH1F, {axisPt}); - registry->add(hPtItsTpcTrd[histogramIndex].data(), "ITS-TPC-TRD tracks " + tagPt, kTH1F, {axisPt}); - registry->add(hPtItsTpcTof[histogramIndex].data(), "ITS-TPC-TOF tracks " + tagPt, kTH1F, {axisPt}); - registry->add(hPtItsTpcTrdTof[histogramIndex].data(), "ITS-TPC-TRD-TOF tracks " + tagPt, kTH1F, {axisPt}); - registry->add(hPtTrkItsTpc[histogramIndex].data(), "ITS-TPC track (reco) " + tagPt, kTH1F, {axisPt}); - registry->add(hPtGenerated[histogramIndex].data(), "Generated " + tagPt, kTH1F, {axisPt}); - - registry->add(hPtItsPrm[histogramIndex].data(), "ITS tracks (primaries) " + tagPt, kTH1F, {axisPt}); - registry->add(hPtItsTpcPrm[histogramIndex].data(), "ITS-TPC tracks (primaries) " + tagPt, kTH1F, {axisPt}); - registry->add(hPtTrkItsTpcPrm[histogramIndex].data(), "ITS-TPC tracks (reco primaries) " + tagPt, kTH1F, {axisPt}); - registry->add(hPtItsTpcTofPrm[histogramIndex].data(), "ITS-TPC-TOF tracks (primaries) " + tagPt, kTH1F, {axisPt}); - registry->add(hPtTrkItsTpcTofPrm[histogramIndex].data(), "ITS-TPC-TOF tracks (reco primaries) " + tagPt, kTH1F, {axisPt}); - registry->add(hPtGeneratedPrm[histogramIndex].data(), "Generated (primaries) " + tagPt, kTH1F, {axisPt}); - - registry->add(hPtItsTpcStr[histogramIndex].data(), "ITS-TPC tracks (from weak decays) " + tagPt, kTH1F, {axisPt}); - registry->add(hPtTrkItsTpcStr[histogramIndex].data(), "ITS-TPC tracks (reco from weak decays) " + tagPt, kTH1F, {axisPt}); - registry->add(hPtItsTpcTofStr[histogramIndex].data(), "ITS-TPC-TOF tracks (from weak decays) " + tagPt, kTH1F, {axisPt}); - registry->add(hPtGeneratedStr[histogramIndex].data(), "Generated (from weak decays) " + tagPt, kTH1F, {axisPt}); - - registry->add(hPtItsTpcMat[histogramIndex].data(), "ITS-TPC tracks (from material)" + tagPt, kTH1F, {axisPt}); - registry->add(hPtTrkItsTpcMat[histogramIndex].data(), "ITS-TPC tracks (reco from material) " + tagPt, kTH1F, {axisPt}); - registry->add(hPtItsTpcTofMat[histogramIndex].data(), "ITS-TPC-TOF tracks ( from material) " + tagPt, kTH1F, {axisPt}); - registry->add(hPtGeneratedMat[histogramIndex].data(), "Generated ( from material) " + tagPt, kTH1F, {axisPt}); - - registry->add(hPItsTpc[histogramIndex].data(), "ITS-TPC tracks " + tagPt, kTH1F, {axisP}); - registry->add(hPTrkItsTpc[histogramIndex].data(), "ITS-TPC tracks (reco) " + tagPt, kTH1F, {axisP}); - registry->add(hPItsTpcTof[histogramIndex].data(), "ITS-TPC-TOF tracks " + tagPt, kTH1F, {axisP}); - registry->add(hPGenerated[histogramIndex].data(), "Generated " + tagPt, kTH1F, {axisP}); - - registry->add(hEtaItsTpc[histogramIndex].data(), "ITS-TPC tracks " + tagEta, kTH1F, {axisEta}); - registry->add(hEtaTrkItsTpc[histogramIndex].data(), "ITS-TPC tracks (reco) " + tagEta, kTH1F, {axisEta}); - registry->add(hEtaItsTpcTof[histogramIndex].data(), "ITS-TPC-TOF tracks " + tagEta, kTH1F, {axisEta}); - registry->add(hEtaGenerated[histogramIndex].data(), "Generated " + tagEta, kTH1F, {axisEta}); - - registry->add(hEtaItsTpcPrm[histogramIndex].data(), "ITS-TPC tracks (primaries) " + tagEta, kTH1F, {axisEta}); - registry->add(hEtaTrkItsTpcPrm[histogramIndex].data(), "ITS-TPC tracks (reco primaries) " + tagEta, kTH1F, {axisEta}); - registry->add(hEtaItsTpcTofPrm[histogramIndex].data(), "ITS-TPC-TOF tracks (primaries) " + tagEta, kTH1F, {axisEta}); - registry->add(hEtaGeneratedPrm[histogramIndex].data(), "Generated (primaries) " + tagEta, kTH1F, {axisEta}); - - registry->add(hYItsTpc[histogramIndex].data(), "ITS-TPC tracks " + tagY, kTH1F, {axisY}); - registry->add(hYItsTpcTof[histogramIndex].data(), "ITS-TPC-TOF tracks " + tagY, kTH1F, {axisY}); - registry->add(hYGenerated[histogramIndex].data(), "Generated " + tagY, kTH1F, {axisY}); - - registry->add(hPhiItsTpc[histogramIndex].data(), "ITS-TPC tracks " + tagPhi, kTH1F, {axisPhi}); - registry->add(hPhiTrkItsTpc[histogramIndex].data(), "ITS-TPC tracks (reco) " + tagPhi, kTH1F, {axisPhi}); - registry->add(hPhiItsTpcTof[histogramIndex].data(), "ITS-TPC-TOF tracks " + tagPhi, kTH1F, {axisPhi}); - registry->add(hPhiGenerated[histogramIndex].data(), "Generated " + tagPhi, kTH1F, {axisPhi}); - - registry->add(hPhiItsTpcPrm[histogramIndex].data(), "ITS-TPC tracks (primaries) " + tagPhi, kTH1F, {axisPhi}); - registry->add(hPhiTrkItsTpcPrm[histogramIndex].data(), "ITS-TPC tracks (reco primaries) " + tagPhi, kTH1F, {axisPhi}); - registry->add(hPhiItsTpcTofPrm[histogramIndex].data(), "ITS-TPC-TOF tracks (primaries) " + tagPhi, kTH1F, {axisPhi}); - registry->add(hPhiGeneratedPrm[histogramIndex].data(), "Generated (primaries) " + tagPhi, kTH1F, {axisPhi}); + + // Pt + hPtIts[histogramIndex] = histos.add(Form("MC/pdg%i/pt/its", PDGs[histogramIndex]), "ITS tracks " + tagPt, kTH1D, {axisPt}); + hPtTpc[histogramIndex] = histos.add(Form("MC/pdg%i/pt/tpc", PDGs[histogramIndex]), "TPC tracks " + tagPt, kTH1D, {axisPt}); + hPtItsTpc[histogramIndex] = histos.add(Form("MC/pdg%i/pt/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks " + tagPt, kTH1D, {axisPt}); + hPtItsTof[histogramIndex] = histos.add(Form("MC/pdg%i/pt/its_tof", PDGs[histogramIndex]), "ITS-TOF tracks " + tagPt, kTH1D, {axisPt}); + hPtTpcTof[histogramIndex] = histos.add(Form("MC/pdg%i/pt/tpc_tof", PDGs[histogramIndex]), "TPC-TOF tracks " + tagPt, kTH1D, {axisPt}); + hPtItsTpcTof[histogramIndex] = histos.add(Form("MC/pdg%i/pt/its_tpc_tof", PDGs[histogramIndex]), "ITS-TPC-TOF tracks " + tagPt, kTH1D, {axisPt}); + hPtItsTpcTrdTof[histogramIndex] = histos.add(Form("MC/pdg%i/pt/its_tpc_trd_tof", PDGs[histogramIndex]), "ITS-TPC-TRD-TOF tracks " + tagPt, kTH1D, {axisPt}); + hPtItsTpcTrd[histogramIndex] = histos.add(Form("MC/pdg%i/pt/its_tpc_trd", PDGs[histogramIndex]), "ITS-TPC-TRD tracks " + tagPt, kTH1D, {axisPt}); + hPtTrkItsTpc[histogramIndex] = histos.add(Form("MC/pdg%i/pt/trk/its_tpc", PDGs[histogramIndex]), "ITS-TPC track (reco) " + tagPt, kTH1D, {axisPt}); + hPtGenerated[histogramIndex] = histos.add(Form("MC/pdg%i/pt/generated", PDGs[histogramIndex]), "Generated " + tagPt, kTH1D, {axisPt}); + hPtGeneratedRecoEv[histogramIndex] = histos.add(Form("MC/pdg%i/pt/generated_reco_ev", PDGs[histogramIndex]), "Generated Reco Ev. " + tagPt, kTH1D, {axisPt}); + + // Prm + hPtItsPrm[histogramIndex] = histos.add(Form("MC/pdg%i/pt/prm/its", PDGs[histogramIndex]), "ITS tracks (primaries) " + tagPt, kTH1D, {axisPt}); + hPtItsTpcPrm[histogramIndex] = histos.add(Form("MC/pdg%i/pt/prm/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks (primaries) " + tagPt, kTH1D, {axisPt}); + hPtTrkItsTpcPrm[histogramIndex] = histos.add(Form("MC/pdg%i/pt/prm/trk/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks (reco primaries) " + tagPt, kTH1D, {axisPt}); + hPtItsTpcTofPrm[histogramIndex] = histos.add(Form("MC/pdg%i/pt/prm/its_tpc_tof", PDGs[histogramIndex]), "ITS-TPC-TOF tracks (primaries) " + tagPt, kTH1D, {axisPt}); + hPtTrkItsTpcTofPrm[histogramIndex] = histos.add(Form("MC/pdg%i/pt/prm/trk/its_tpc_tof", PDGs[histogramIndex]), "ITS-TPC-TOF tracks (reco primaries) " + tagPt, kTH1D, {axisPt}); + hPtGeneratedPrm[histogramIndex] = histos.add(Form("MC/pdg%i/pt/prm/generated", PDGs[histogramIndex]), "Generated (primaries) " + tagPt, kTH1D, {axisPt}); + hPtGeneratedPrmRecoEv[histogramIndex] = histos.add(Form("MC/pdg%i/pt/prm/generated_reco_ev", PDGs[histogramIndex]), "Generated Reco Ev. " + tagPt, kTH1D, {axisPt}); + + // Str + hPtItsTpcStr[histogramIndex] = histos.add(Form("MC/pdg%i/pt/str/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks (from weak decays) " + tagPt, kTH1D, {axisPt}); + hPtTrkItsTpcStr[histogramIndex] = histos.add(Form("MC/pdg%i/pt/str/trk/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks (reco from weak decays) " + tagPt, kTH1D, {axisPt}); + hPtItsTpcTofStr[histogramIndex] = histos.add(Form("MC/pdg%i/pt/str/its_tpc_tof", PDGs[histogramIndex]), "ITS-TPC-TOF tracks (from weak decays) " + tagPt, kTH1D, {axisPt}); + hPtGeneratedStr[histogramIndex] = histos.add(Form("MC/pdg%i/pt/str/generated", PDGs[histogramIndex]), "Generated (from weak decays) " + tagPt, kTH1D, {axisPt}); + hPtmotherGenerated[histogramIndex] = histos.add(Form("MC/pdg%i/pt/str/generated_mother", PDGs[histogramIndex]), "Generated Mother " + tagPt, kTH1D, {axisPt}); + hdecaylengthmother[histogramIndex] = histos.add(Form("MC/pdg%i/pt/str/decayLength", PDGs[histogramIndex]), "Decay Length of mother particle" + tagPt, kTH1D, {axisDecayLength}); + + // Ter + hPtItsTpcTer[histogramIndex] = histos.add(Form("MC/pdg%i/pt/ter/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks (from secondary weak decays) " + tagPt, kTH1D, {axisPt}); + hPtTrkItsTpcTer[histogramIndex] = histos.add(Form("MC/pdg%i/pt/ter/trk/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks (reco from secondary weak decays) " + tagPt, kTH1D, {axisPt}); + hPtItsTpcTofTer[histogramIndex] = histos.add(Form("MC/pdg%i/pt/ter/its_tpc_tof", PDGs[histogramIndex]), "ITS-TPC-TOF tracks (from secondary weak decays) " + tagPt, kTH1D, {axisPt}); + hPtGeneratedTer[histogramIndex] = histos.add(Form("MC/pdg%i/pt/ter/generated", PDGs[histogramIndex]), "Generated (from secondary weak decays) " + tagPt, kTH1D, {axisPt}); + + // Mat + hPtItsTpcMat[histogramIndex] = histos.add(Form("MC/pdg%i/pt/mat/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks (from material)" + tagPt, kTH1D, {axisPt}); + hPtTrkItsTpcMat[histogramIndex] = histos.add(Form("MC/pdg%i/pt/mat/trk/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks (reco from material) " + tagPt, kTH1D, {axisPt}); + hPtItsTpcTofMat[histogramIndex] = histos.add(Form("MC/pdg%i/pt/mat/its_tpc_tof", PDGs[histogramIndex]), "ITS-TPC-TOF tracks (from material) " + tagPt, kTH1D, {axisPt}); + hPtGeneratedMat[histogramIndex] = histos.add(Form("MC/pdg%i/pt/mat/generated", PDGs[histogramIndex]), "Generated ( from material) " + tagPt, kTH1D, {axisPt}); + + // P + hPItsTpc[histogramIndex] = histos.add(Form("MC/pdg%i/p/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks " + tagPt, kTH1D, {axisP}); + hPTrkItsTpc[histogramIndex] = histos.add(Form("MC/pdg%i/p/trk/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks (reco) " + tagPt, kTH1D, {axisP}); + hPItsTpcTof[histogramIndex] = histos.add(Form("MC/pdg%i/p/its_tpc_tof", PDGs[histogramIndex]), "ITS-TPC-TOF tracks " + tagPt, kTH1D, {axisP}); + hPGenerated[histogramIndex] = histos.add(Form("MC/pdg%i/p/generated", PDGs[histogramIndex]), "Generated " + tagPt, kTH1D, {axisP}); + + // Eta + hEtaItsTpc[histogramIndex] = histos.add(Form("MC/pdg%i/eta/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks " + tagEta, kTH1D, {axisEta}); + hEtaTrkItsTpc[histogramIndex] = histos.add(Form("MC/pdg%i/eta/trk/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks (reco) " + tagEta, kTH1D, {axisEta}); + hEtaItsTpcTof[histogramIndex] = histos.add(Form("MC/pdg%i/eta/its_tpc_tof", PDGs[histogramIndex]), "ITS-TPC-TOF tracks " + tagEta, kTH1D, {axisEta}); + hEtaGenerated[histogramIndex] = histos.add(Form("MC/pdg%i/eta/generated", PDGs[histogramIndex]), "Generated " + tagEta, kTH1D, {axisEta}); + + // Prm + hEtaItsTpcPrm[histogramIndex] = histos.add(Form("MC/pdg%i/eta/prm/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks (primaries) " + tagEta, kTH1D, {axisEta}); + hEtaTrkItsTpcPrm[histogramIndex] = histos.add(Form("MC/pdg%i/eta/prm/trk/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks (reco primaries) " + tagEta, kTH1D, {axisEta}); + hEtaItsTpcTofPrm[histogramIndex] = histos.add(Form("MC/pdg%i/eta/prm/its_tpc_tof", PDGs[histogramIndex]), "ITS-TPC-TOF tracks (primaries) " + tagEta, kTH1D, {axisEta}); + hEtaGeneratedPrm[histogramIndex] = histos.add(Form("MC/pdg%i/eta/prm/generated", PDGs[histogramIndex]), "Generated (primaries) " + tagEta, kTH1D, {axisEta}); + + // Y + hYItsTpc[histogramIndex] = histos.add(Form("MC/pdg%i/y/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks " + tagY, kTH1D, {axisY}); + hYItsTpcTof[histogramIndex] = histos.add(Form("MC/pdg%i/y/its_tpc_tof", PDGs[histogramIndex]), "ITS-TPC-TOF tracks " + tagY, kTH1D, {axisY}); + hYGenerated[histogramIndex] = histos.add(Form("MC/pdg%i/y/generated", PDGs[histogramIndex]), "Generated " + tagY, kTH1D, {axisY}); + + // Phi + hPhiItsTpc[histogramIndex] = histos.add(Form("MC/pdg%i/phi/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks " + tagPhi, kTH1D, {axisPhi}); + hPhiTrkItsTpc[histogramIndex] = histos.add(Form("MC/pdg%i/phi/trk/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks (reco) " + tagPhi, kTH1D, {axisPhi}); + hPhiItsTpcTof[histogramIndex] = histos.add(Form("MC/pdg%i/phi/its_tpc_tof", PDGs[histogramIndex]), "ITS-TPC-TOF tracks " + tagPhi, kTH1D, {axisPhi}); + hPhiGenerated[histogramIndex] = histos.add(Form("MC/pdg%i/phi/generated", PDGs[histogramIndex]), "Generated " + tagPhi, kTH1D, {axisPhi}); + + // Phi prm + hPhiItsTpcPrm[histogramIndex] = histos.add(Form("MC/pdg%i/phi/prm/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks (primaries) " + tagPhi, kTH1D, {axisPhi}); + hPhiTrkItsTpcPrm[histogramIndex] = histos.add(Form("MC/pdg%i/phi/prm/trk/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks (reco primaries) " + tagPhi, kTH1D, {axisPhi}); + hPhiItsTpcTofPrm[histogramIndex] = histos.add(Form("MC/pdg%i/phi/prm/its_tpc_tof", PDGs[histogramIndex]), "ITS-TPC-TOF tracks (primaries) " + tagPhi, kTH1D, {axisPhi}); + hPhiGeneratedPrm[histogramIndex] = histos.add(Form("MC/pdg%i/phi/prm/generated", PDGs[histogramIndex]), "Generated (primaries) " + tagPhi, kTH1D, {axisPhi}); if (doPtEta) { - registry->add(hPtEtaItsTpc[histogramIndex].data(), "ITS-TPC tracks " + tagPtEta, kTH2D, {axisPt, axisEta}); - registry->add(hPtEtaTrkItsTpc[histogramIndex].data(), "ITS-TPC tracks (reco) " + tagPtEta, kTH2D, {axisPt, axisEta}); - registry->add(hPtEtaItsTpcTof[histogramIndex].data(), "ITS-TPC-TOF tracks " + tagPtEta, kTH2D, {axisPt, axisEta}); - registry->add(hPtEtaGenerated[histogramIndex].data(), "Generated " + tagPtEta, kTH2D, {axisPt, axisEta}); + hPtEtaItsTpc[histogramIndex] = histos.add(Form("MC/pdg%i/pt/asd", PDGs[histogramIndex]), "ITS-TPC tracks " + tagPtEta, kTH2D, {axisPt, axisEta}); + hPtEtaTrkItsTpc[histogramIndex] = histos.add(Form("MC/pdg%i/pt/asd", PDGs[histogramIndex]), "ITS-TPC tracks (reco) " + tagPtEta, kTH2D, {axisPt, axisEta}); + hPtEtaItsTpcTof[histogramIndex] = histos.add(Form("MC/pdg%i/pt/asd", PDGs[histogramIndex]), "ITS-TPC-TOF tracks " + tagPtEta, kTH2D, {axisPt, axisEta}); + hPtEtaGenerated[histogramIndex] = histos.add(Form("MC/pdg%i/pt/asd", PDGs[histogramIndex]), "Generated " + tagPtEta, kTH2D, {axisPt, axisEta}); } - LOG(info) << "Done with particle: " << partName; + if (doPtRadius) { + hPtRadiusItsTpc[histogramIndex] = histos.add(Form("MC/pdg%i/pt/radius/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks " + tagPt + " vs Radius", kTH2D, {axisPt, axisRadius}); + hPtRadiusItsTpcTof[histogramIndex] = histos.add(Form("MC/pdg%i/pt/radius/its_tpc_tof", PDGs[histogramIndex]), "ITS-TPC-TOF tracks " + tagPt + " vs Radius", kTH2D, {axisPt, axisRadius}); + hPtRadiusGenerated[histogramIndex] = histos.add(Form("MC/pdg%i/pt/radius/generated", PDGs[histogramIndex]), "Generated " + tagPt + " vs Radius", kTH2D, {axisPt, axisRadius}); + + hPtRadiusItsTpcPrm[histogramIndex] = histos.add(Form("MC/pdg%i/pt/prm/radius/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks " + tagPt + " vs Radius", kTH2D, {axisPt, axisRadius}); + hPtRadiusItsTpcTofPrm[histogramIndex] = histos.add(Form("MC/pdg%i/pt/prm/radius/its_tpc_tof", PDGs[histogramIndex]), "ITS-TPC-TOF tracks " + tagPt + " vs Radius", kTH2D, {axisPt, axisRadius}); + hPtRadiusGeneratedPrm[histogramIndex] = histos.add(Form("MC/pdg%i/pt/prm/radius/generated", PDGs[histogramIndex]), "Generated " + tagPt + " vs Radius", kTH2D, {axisPt, axisRadius}); + + hPtRadiusItsTpcStr[histogramIndex] = histos.add(Form("MC/pdg%i/pt/str/radius/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks " + tagPt + " vs Radius", kTH2D, {axisPt, axisRadius}); + hPtRadiusItsTpcTofStr[histogramIndex] = histos.add(Form("MC/pdg%i/pt/str/radius/its_tpc_tof", PDGs[histogramIndex]), "ITS-TPC-TOF tracks " + tagPt + " vs Radius", kTH2D, {axisPt, axisRadius}); + hPtRadiusGeneratedStr[histogramIndex] = histos.add(Form("MC/pdg%i/pt/str/radius/generated", PDGs[histogramIndex]), "Generated " + tagPt + " vs Radius", kTH2D, {axisPt, axisRadius}); + + hPtRadiusItsTpcTer[histogramIndex] = histos.add(Form("MC/pdg%i/pt/ter/radius/its_tpc", PDGs[histogramIndex]), "ITS-TPC tracks " + tagPt + " vs Radius", kTH2D, {axisPt, axisRadius}); + hPtRadiusItsTpcTofTer[histogramIndex] = histos.add(Form("MC/pdg%i/pt/ter/radius/its_tpc_tof", PDGs[histogramIndex]), "ITS-TPC-TOF tracks " + tagPt + " vs Radius", kTH2D, {axisPt, axisRadius}); + hPtRadiusGeneratedTer[histogramIndex] = histos.add(Form("MC/pdg%i/pt/ter/radius/generated", PDGs[histogramIndex]), "Generated " + tagPt + " vs Radius", kTH2D, {axisPt, axisRadius}); + } + + LOG(info) << "Done with making histograms for particle: " << partName; } template @@ -621,13 +476,7 @@ struct QaEfficiency { subList->SetName(partName); listEfficiencyMC->Add(subList); - HistogramRegistry* registry = &histosPosPdg; - if (pdgSign == 1) { - registry = &histosNegPdg; - } - - auto makeEfficiency = [&](const TString effname, auto templateHisto) { // 1D efficiencies - const auto h = registry->get(templateHisto); + auto makeEfficiency = [&](const TString effname, auto h) { // 1D efficiencies LOG(debug) << " Making 1D TEfficiency " << effname << " from " << h->GetName(); const TAxis* axis = h->GetXaxis(); TString efftitle = h->GetTitle(); @@ -642,50 +491,55 @@ struct QaEfficiency { const int histogramIndex = id + pdgSign * nSpecies; - makeEfficiency("ITS_vsPt", HIST(hPtIts[histogramIndex])); - makeEfficiency("TPC_vsPt", HIST(hPtTpc[histogramIndex])); - makeEfficiency("ITS-TPC_vsPt", HIST(hPtItsTpc[histogramIndex])); - makeEfficiency("ITS-TOF_vsPt", HIST(hPtItsTof[histogramIndex])); - makeEfficiency("TPC-TOF_vsPt", HIST(hPtTpcTof[histogramIndex])); - makeEfficiency("ITS-TPC-TRD_vsPt", HIST(hPtItsTpcTrd[histogramIndex])); - makeEfficiency("ITS-TPC-TOF_vsPt", HIST(hPtItsTpcTof[histogramIndex])); - makeEfficiency("ITS-TPC-TRD-TOF_vsPt", HIST(hPtItsTpcTrdTof[histogramIndex])); - makeEfficiency("ITS-TPC_vsPt_Trk", HIST(hPtTrkItsTpc[histogramIndex])); - - makeEfficiency("ITS_vsPt_Prm", HIST(hPtItsPrm[histogramIndex])); - makeEfficiency("ITS-TPC_vsPt_Prm", HIST(hPtItsTpcPrm[histogramIndex])); - makeEfficiency("ITS-TPC_vsPt_Prm_Trk", HIST(hPtTrkItsTpcPrm[histogramIndex])); - makeEfficiency("ITS-TPC-TOF_vsPt_Prm", HIST(hPtItsTpcTofPrm[histogramIndex])); - makeEfficiency("ITS-TPC-TOF_vsPt_Prm_Trk", HIST(hPtTrkItsTpcTofPrm[histogramIndex])); - - makeEfficiency("ITS-TPC_vsPt_Str", HIST(hPtItsTpcStr[histogramIndex])); - makeEfficiency("ITS-TPC_vsPt_Str_Trk", HIST(hPtTrkItsTpcStr[histogramIndex])); - makeEfficiency("ITS-TPC-TOF_vsPt_Str", HIST(hPtItsTpcTofStr[histogramIndex])); - - makeEfficiency("ITS-TPC_vsPt_Mat", HIST(hPtItsTpcMat[histogramIndex])); - makeEfficiency("ITS-TPC_vsPt_Mat_Trk", HIST(hPtTrkItsTpcMat[histogramIndex])); - makeEfficiency("ITS-TPC-TOF_vsPt_Mat", HIST(hPtItsTpcTofMat[histogramIndex])); - - makeEfficiency("ITS-TPC_vsP", HIST(hPItsTpc[histogramIndex])); - makeEfficiency("ITS-TPC_vsP_Trk", HIST(hPTrkItsTpc[histogramIndex])); - makeEfficiency("ITS-TPC-TOF_vsP", HIST(hPItsTpcTof[histogramIndex])); - makeEfficiency("ITS-TPC_vsEta", HIST(hEtaItsTpc[histogramIndex])); - makeEfficiency("ITS-TPC_vsEta_Trk", HIST(hEtaTrkItsTpc[histogramIndex])); - makeEfficiency("ITS-TPC-TOF_vsEta", HIST(hEtaItsTpcTof[histogramIndex])); - makeEfficiency("ITS-TPC_vsEta_Prm", HIST(hEtaItsTpcPrm[histogramIndex])); - makeEfficiency("ITS-TPC_vsEta_Prm_Trk", HIST(hEtaTrkItsTpcPrm[histogramIndex])); - makeEfficiency("ITS-TPC-TOF_vsEta_Prm", HIST(hEtaItsTpcTofPrm[histogramIndex])); - makeEfficiency("ITS-TPC_vsY", HIST(hYItsTpc[histogramIndex])); - makeEfficiency("ITS-TPC-TOF_vsY", HIST(hYItsTpcTof[histogramIndex])); - makeEfficiency("ITS-TPC_vsPhi", HIST(hPhiItsTpc[histogramIndex])); - makeEfficiency("ITS-TPC_vsPhi_Trk", HIST(hPhiTrkItsTpc[histogramIndex])); - makeEfficiency("ITS-TPC-TOF_vsPhi", HIST(hPhiItsTpcTof[histogramIndex])); - makeEfficiency("ITS-TPC_vsPhi_Prm", HIST(hPhiItsTpcPrm[histogramIndex])); - makeEfficiency("ITS-TPC_vsPhi_Prm_Trk", HIST(hPhiTrkItsTpcPrm[histogramIndex])); - makeEfficiency("ITS-TPC-TOF_vsPhi_Prm", HIST(hPhiItsTpcTofPrm[histogramIndex])); - - auto makeEfficiency2D = [&](const TString effname, auto templateHisto) { // 2D efficiencies - const auto h = registry->get(templateHisto); + makeEfficiency("ITS_vsPt", hPtIts[histogramIndex]); + makeEfficiency("TPC_vsPt", hPtTpc[histogramIndex]); + makeEfficiency("ITS-TPC_vsPt", hPtItsTpc[histogramIndex]); + makeEfficiency("ITS-TOF_vsPt", hPtItsTof[histogramIndex]); + makeEfficiency("TPC-TOF_vsPt", hPtTpcTof[histogramIndex]); + makeEfficiency("ITS-TPC-TRD_vsPt", hPtItsTpcTrd[histogramIndex]); + makeEfficiency("ITS-TPC-TOF_vsPt", hPtItsTpcTof[histogramIndex]); + makeEfficiency("ITS-TPC-TRD-TOF_vsPt", hPtItsTpcTrdTof[histogramIndex]); + makeEfficiency("ITS-TPC_vsPt_Trk", hPtTrkItsTpc[histogramIndex]); + + makeEfficiency("ITS-TPC_vsPt_RecoEv", hPtItsTpc[histogramIndex]); + + makeEfficiency("ITS_vsPt_Prm", hPtItsPrm[histogramIndex]); + makeEfficiency("ITS-TPC_vsPt_Prm", hPtItsTpcPrm[histogramIndex]); + makeEfficiency("ITS-TPC_vsPt_Prm_Trk", hPtTrkItsTpcPrm[histogramIndex]); + makeEfficiency("ITS-TPC-TOF_vsPt_Prm", hPtItsTpcTofPrm[histogramIndex]); + makeEfficiency("ITS-TPC-TOF_vsPt_Prm_Trk", hPtTrkItsTpcTofPrm[histogramIndex]); + makeEfficiency("ITS-TPC_vsPt_Prm_RecoEv", hPtItsTpcPrm[histogramIndex]); + + makeEfficiency("ITS-TPC_vsPt_Str", hPtItsTpcStr[histogramIndex]); + makeEfficiency("ITS-TPC_vsPt_Str_Trk", hPtTrkItsTpcStr[histogramIndex]); + makeEfficiency("ITS-TPC-TOF_vsPt_Str", hPtItsTpcTofStr[histogramIndex]); + makeEfficiency("ITS-TPC_vsPt_Mat", hPtItsTpcMat[histogramIndex]); + makeEfficiency("ITS-TPC_vsPt_Mat_Trk", hPtTrkItsTpcMat[histogramIndex]); + makeEfficiency("ITS-TPC-TOF_vsPt_Mat", hPtItsTpcTofMat[histogramIndex]); + + makeEfficiency("ITS-TPC_vsPt_Ter", hPtItsTpcTer[histogramIndex]); + makeEfficiency("ITS-TPC_vsPt_Ter_Trk", hPtTrkItsTpcTer[histogramIndex]); + makeEfficiency("ITS-TPC-TOF_vsPt_Ter", hPtItsTpcTofTer[histogramIndex]); + + makeEfficiency("ITS-TPC_vsP", hPItsTpc[histogramIndex]); + makeEfficiency("ITS-TPC_vsP_Trk", hPTrkItsTpc[histogramIndex]); + makeEfficiency("ITS-TPC-TOF_vsP", hPItsTpcTof[histogramIndex]); + makeEfficiency("ITS-TPC_vsEta", hEtaItsTpc[histogramIndex]); + makeEfficiency("ITS-TPC_vsEta_Trk", hEtaTrkItsTpc[histogramIndex]); + makeEfficiency("ITS-TPC-TOF_vsEta", hEtaItsTpcTof[histogramIndex]); + makeEfficiency("ITS-TPC_vsEta_Prm", hEtaItsTpcPrm[histogramIndex]); + makeEfficiency("ITS-TPC_vsEta_Prm_Trk", hEtaTrkItsTpcPrm[histogramIndex]); + makeEfficiency("ITS-TPC-TOF_vsEta_Prm", hEtaItsTpcTofPrm[histogramIndex]); + makeEfficiency("ITS-TPC_vsY", hYItsTpc[histogramIndex]); + makeEfficiency("ITS-TPC-TOF_vsY", hYItsTpcTof[histogramIndex]); + makeEfficiency("ITS-TPC_vsPhi", hPhiItsTpc[histogramIndex]); + makeEfficiency("ITS-TPC_vsPhi_Trk", hPhiTrkItsTpc[histogramIndex]); + makeEfficiency("ITS-TPC-TOF_vsPhi", hPhiItsTpcTof[histogramIndex]); + makeEfficiency("ITS-TPC_vsPhi_Prm", hPhiItsTpcPrm[histogramIndex]); + makeEfficiency("ITS-TPC_vsPhi_Prm_Trk", hPhiTrkItsTpcPrm[histogramIndex]); + makeEfficiency("ITS-TPC-TOF_vsPhi_Prm", hPhiItsTpcTofPrm[histogramIndex]); + + auto makeEfficiency2D = [&](const TString effname, auto h) { // 2D efficiencies LOG(debug) << " Making 2D TEfficiency " << effname << " from " << h->GetName(); const TAxis* axisX = h->GetXaxis(); const TAxis* axisY = h->GetYaxis(); @@ -700,12 +554,22 @@ struct QaEfficiency { }; if (doPtEta) { - makeEfficiency2D("ITS-TPC_vsPt_vsEta", HIST(hPtEtaItsTpc[histogramIndex])); - makeEfficiency2D("ITS-TPC_vsPt_vsEta_Trk", HIST(hPtEtaTrkItsTpc[histogramIndex])); - makeEfficiency2D("ITS-TPC-TOF_vsPt_vsEta", HIST(hPtEtaItsTpcTof[histogramIndex])); - } - - LOG(info) << "Done with particle: " << partName << " for efficiencies"; + makeEfficiency2D("ITS-TPC_vsPt_vsEta", hPtEtaItsTpc[histogramIndex]); + makeEfficiency2D("ITS-TPC_vsPt_vsEta_Trk", hPtEtaTrkItsTpc[histogramIndex]); + makeEfficiency2D("ITS-TPC-TOF_vsPt_vsEta", hPtEtaItsTpcTof[histogramIndex]); + } + if (doPtRadius) { + makeEfficiency2D("ITS-TPC_vsPt_vsRadius", hPtRadiusItsTpc[histogramIndex]); + makeEfficiency2D("ITS-TPC-TOF_vsPt_vsRadius", hPtRadiusItsTpcTof[histogramIndex]); + makeEfficiency2D("ITS-TPC_vsPt_vsRadius", hPtRadiusItsTpcPrm[histogramIndex]); + makeEfficiency2D("ITS-TPC-TOF_vsPt_vsRadius", hPtRadiusItsTpcTofPrm[histogramIndex]); + makeEfficiency2D("ITS-TPC_vsPt_vsRadius", hPtRadiusItsTpcStr[histogramIndex]); + makeEfficiency2D("ITS-TPC-TOF_vsPt_vsRadius", hPtRadiusItsTpcTofStr[histogramIndex]); + makeEfficiency2D("ITS-TPC_vsPt_vsRadius", hPtRadiusItsTpcTer[histogramIndex]); + makeEfficiency2D("ITS-TPC-TOF_vsPt_vsRadius", hPtRadiusItsTpcTofTer[histogramIndex]); + } + + LOG(info) << "Done with making histograms for particle: " << partName << " for efficiencies"; } void initMC(const AxisSpec& axisSel) @@ -717,7 +581,7 @@ struct QaEfficiency { LOG(fatal) << "Both processMC and processMCWithoutCollisions are set to true. Please set only one of them to true."; } - auto h = histos.add("MC/trackSelection", "Track Selection", kTH1F, {axisSel}); + auto h = histos.add("MC/trackSelection", "Track Selection", kTH1D, {axisSel}); h->GetXaxis()->SetBinLabel(trkCutIdxTrkRead, "Tracks read"); h->GetXaxis()->SetBinLabel(trkCutIdxHasMcPart, "Passed has MC part."); h->GetXaxis()->SetBinLabel(trkCutIdxPassedPt, "Passed #it{p}_{T}"); @@ -763,13 +627,14 @@ struct QaEfficiency { default: LOG(fatal) << "Can't interpret track asked selection " << globalTrackSelection; } + h->GetXaxis()->SetBinLabel(trkCutSameColl, "passedSameColl"); for (int i = 0; i < nSpecies; i++) { h->GetXaxis()->SetBinLabel(trkCutIdxN + i, Form("Passed PDG %i %s", PDGs[i], particleTitle[i])); } - histos.add("MC/fakeTrackNoiseHits", "Fake tracks from noise hits", kTH1F, {{1, 0, 1}}); + histos.add("MC/fakeTrackNoiseHits", "Fake tracks from noise hits", kTH1D, {{1, 0, 1}}); - h = histos.add("MC/particleSelection", "Particle Selection", kTH1F, {axisSel}); + h = histos.add("MC/particleSelection", "Particle Selection", kTH1D, {axisSel}); h->GetXaxis()->SetBinLabel(1, "Particles read"); h->GetXaxis()->SetBinLabel(2, "Passed #it{p}_{T}"); h->GetXaxis()->SetBinLabel(3, "Passed #it{#eta}"); @@ -778,12 +643,30 @@ struct QaEfficiency { for (int i = 0; i < nSpecies; i++) { h->GetXaxis()->SetBinLabel(6 + i, Form("Passed PDG %i %s", PDGs[i], particleTitle[i])); } - histos.add("MC/eventMultiplicity", "Event Selection", kTH1F, {{1000, 0, 5000}}); + histos.add("MC/eventMultiplicity", "Event Selection", kTH1D, {{1000, 0, 5000}}); - histos.add("MC/trackLength", "Track length;Track length (cm)", kTH1F, {{2000, -1000, 1000}}); + histos.add("MC/trackLength", "Track length;Track length (cm)", kTH1D, {{2000, -1000, 1000}}); listEfficiencyMC.setObject(new THashList); + if (doOccupancy) { + const AxisSpec axisPt{ptBins, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisOcc{occBins, "Occupancy"}; + const AxisSpec axisCent{centBins, "Centrality"}; + + histos.add("MC/occ_cent/gen/pos", "Generated Positive ", kTH3D, {axisOcc, axisCent, axisPt}); + histos.add("MC/occ_cent/gen/neg", "Generated Negative ", kTH3D, {axisOcc, axisCent, axisPt}); + + histos.add("MC/occ_cent/reco/pos/its_tpc_tof", "ITS-TPC-TOF Positive ", kTH3D, {axisOcc, axisCent, axisPt}); + histos.add("MC/occ_cent/reco/neg/its_tpc_tof", "ITS-TPC-TOF Negative ", kTH3D, {axisOcc, axisCent, axisPt}); + + histos.add("MC/occ_cent/reco/pos/its_tpc", "ITS-TPC Positive ", kTH3D, {axisOcc, axisCent, axisPt}); + histos.add("MC/occ_cent/reco/neg/its_tpc", "ITS-TPC Negative ", kTH3D, {axisOcc, axisCent, axisPt}); + + histos.add("MC/occ_cent/reco/pos/its", "ITS Positive ", kTH3D, {axisOcc, axisCent, axisPt}); + histos.add("MC/occ_cent/reco/neg/its", "ITS Negative ", kTH3D, {axisOcc, axisCent, axisPt}); + } + static_for<0, 1>([&](auto pdgSign) { makeMCHistograms(doEl); makeMCHistograms(doMu); @@ -829,7 +712,7 @@ struct QaEfficiency { LOG(fatal) << "Can't enable processData and doprocessDataWithPID in the same time, pick one!"; } - auto h = histos.add("Data/trackSelection", "Track Selection", kTH1F, {axisSel}); + auto h = histos.add("Data/trackSelection", "Track Selection", kTH1D, {axisSel}); h->GetXaxis()->SetBinLabel(trkCutIdxTrkRead, "Tracks read"); h->GetXaxis()->SetBinLabel(trkCutIdxHasMcPart, ""); h->GetXaxis()->SetBinLabel(trkCutIdxPassedPt, "Passed #it{p}_{T}"); @@ -888,6 +771,8 @@ struct QaEfficiency { ptMin, ptMax, phiMin, phiMax); const AxisSpec axisEta{etaBins, "#it{#eta}"}; + const AxisSpec axisOcc{occBins, "Occupancy"}; + const AxisSpec axisCent{centBins, "Centrality"}; const TString tagPhi = Form("#it{#eta} [%.2f,%.2f] #it{p}_{T} [%.2f,%.2f]", etaMin, etaMax, @@ -897,72 +782,86 @@ struct QaEfficiency { const TString tagEtaPhi = Form("#it{p}_{T} [%.2f,%.2f]", ptMin, ptMax); - histos.add("Data/trackLength", "Track length;Track length (cm)", kTH1F, {{2000, -1000, 1000}}); + histos.add("Data/trackLength", "Track length;Track length (cm)", kTH1D, {{2000, -1000, 1000}}); + + if (doOccupancy) { + histos.add("Data/occ_cent/pos/its_tpc_tof", "ITS-TPC-TOF Positive ", kTH3D, {axisOcc, axisCent, axisPt}); + histos.add("Data/occ_cent/neg/its_tpc_tof", "ITS-TPC-TOF Negative ", kTH3D, {axisOcc, axisCent, axisPt}); + + histos.add("Data/occ_cent/pos/its_tpc", "ITS-TPC Positive ", kTH3D, {axisOcc, axisCent, axisPt}); + histos.add("Data/occ_cent/neg/its_tpc", "ITS-TPC Negative ", kTH3D, {axisOcc, axisCent, axisPt}); + + histos.add("Data/occ_cent/pos/tpc", "TPC Positive ", kTH3D, {axisOcc, axisCent, axisPt}); + histos.add("Data/occ_cent/neg/tpc", "TPC Negative ", kTH3D, {axisOcc, axisCent, axisPt}); + + histos.add("Data/occ_cent/pos/its", "ITS Positive ", kTH3D, {axisOcc, axisCent, axisPt}); + histos.add("Data/occ_cent/neg/its", "ITS Negative ", kTH3D, {axisOcc, axisCent, axisPt}); + } // ITS-TPC-TOF - histos.add("Data/pos/pt/its_tpc_tof", "ITS-TPC-TOF Positive " + tagPt, kTH1F, {axisPt}); - histos.add("Data/neg/pt/its_tpc_tof", "ITS-TPC-TOF Negative " + tagPt, kTH1F, {axisPt}); + histos.add("Data/pos/pt/its_tpc_tof", "ITS-TPC-TOF Positive " + tagPt, kTH1D, {axisPt}); + histos.add("Data/neg/pt/its_tpc_tof", "ITS-TPC-TOF Negative " + tagPt, kTH1D, {axisPt}); - histos.add("Data/pos/eta/its_tpc_tof", "ITS-TPC-TOF Positive " + tagEta, kTH1F, {axisEta}); - histos.add("Data/neg/eta/its_tpc_tof", "ITS-TPC-TOF Negative " + tagEta, kTH1F, {axisEta}); + histos.add("Data/pos/eta/its_tpc_tof", "ITS-TPC-TOF Positive " + tagEta, kTH1D, {axisEta}); + histos.add("Data/neg/eta/its_tpc_tof", "ITS-TPC-TOF Negative " + tagEta, kTH1D, {axisEta}); - histos.add("Data/pos/phi/its_tpc_tof", "ITS-TPC-TOF Positive " + tagPhi, kTH1F, {axisPhi}); - histos.add("Data/neg/phi/its_tpc_tof", "ITS-TPC-TOF Negative " + tagPhi, kTH1F, {axisPhi}); + histos.add("Data/pos/phi/its_tpc_tof", "ITS-TPC-TOF Positive " + tagPhi, kTH1D, {axisPhi}); + histos.add("Data/neg/phi/its_tpc_tof", "ITS-TPC-TOF Negative " + tagPhi, kTH1D, {axisPhi}); histos.add("Data/pos/etaphi/its_tpc_tof", "ITS-TPC-TOF Positive " + tagEtaPhi, kTH2D, {axisEta, axisPhi}); histos.add("Data/neg/etaphi/its_tpc_tof", "ITS-TPC-TOF Negative " + tagEtaPhi, kTH2D, {axisEta, axisPhi}); // ITS-TPC - histos.add("Data/pos/pt/its_tpc", "ITS-TPC Positive " + tagPt, kTH1F, {axisPt}); - histos.add("Data/neg/pt/its_tpc", "ITS-TPC Negative " + tagPt, kTH1F, {axisPt}); + histos.add("Data/pos/pt/its_tpc", "ITS-TPC Positive " + tagPt, kTH1D, {axisPt}); + histos.add("Data/neg/pt/its_tpc", "ITS-TPC Negative " + tagPt, kTH1D, {axisPt}); - histos.add("Data/pos/eta/its_tpc", "ITS-TPC Positive " + tagEta, kTH1F, {axisEta}); - histos.add("Data/neg/eta/its_tpc", "ITS-TPC Negative " + tagEta, kTH1F, {axisEta}); + histos.add("Data/pos/eta/its_tpc", "ITS-TPC Positive " + tagEta, kTH1D, {axisEta}); + histos.add("Data/neg/eta/its_tpc", "ITS-TPC Negative " + tagEta, kTH1D, {axisEta}); - histos.add("Data/pos/phi/its_tpc", "ITS-TPC Positive " + tagPhi, kTH1F, {axisPhi}); - histos.add("Data/neg/phi/its_tpc", "ITS-TPC Negative " + tagPhi, kTH1F, {axisPhi}); + histos.add("Data/pos/phi/its_tpc", "ITS-TPC Positive " + tagPhi, kTH1D, {axisPhi}); + histos.add("Data/neg/phi/its_tpc", "ITS-TPC Negative " + tagPhi, kTH1D, {axisPhi}); histos.add("Data/pos/etaphi/its_tpc", "ITS-TPC Positive " + tagEtaPhi, kTH2D, {axisEta, axisPhi}); histos.add("Data/neg/etaphi/its_tpc", "ITS-TPC Negative " + tagEtaPhi, kTH2D, {axisEta, axisPhi}); // TPC - histos.add("Data/pos/pt/tpc", "TPC Positive " + tagPt, kTH1F, {axisPt}); - histos.add("Data/neg/pt/tpc", "TPC Negative " + tagPt, kTH1F, {axisPt}); + histos.add("Data/pos/pt/tpc", "TPC Positive " + tagPt, kTH1D, {axisPt}); + histos.add("Data/neg/pt/tpc", "TPC Negative " + tagPt, kTH1D, {axisPt}); - histos.add("Data/pos/eta/tpc", "TPC Positive " + tagEta, kTH1F, {axisEta}); - histos.add("Data/neg/eta/tpc", "TPC Negative " + tagEta, kTH1F, {axisEta}); + histos.add("Data/pos/eta/tpc", "TPC Positive " + tagEta, kTH1D, {axisEta}); + histos.add("Data/neg/eta/tpc", "TPC Negative " + tagEta, kTH1D, {axisEta}); - histos.add("Data/pos/phi/tpc", "TPC Positive " + tagPhi, kTH1F, {axisPhi}); - histos.add("Data/neg/phi/tpc", "TPC Negative " + tagPhi, kTH1F, {axisPhi}); + histos.add("Data/pos/phi/tpc", "TPC Positive " + tagPhi, kTH1D, {axisPhi}); + histos.add("Data/neg/phi/tpc", "TPC Negative " + tagPhi, kTH1D, {axisPhi}); histos.add("Data/pos/etaphi/tpc", "TPC Positive " + tagEtaPhi, kTH2D, {axisEta, axisPhi}); histos.add("Data/neg/etaphi/tpc", "TPC Negative " + tagEtaPhi, kTH2D, {axisEta, axisPhi}); // ITS - histos.add("Data/pos/pt/its", "ITS Positive " + tagPt, kTH1F, {axisPt}); - histos.add("Data/neg/pt/its", "ITS Negative " + tagPt, kTH1F, {axisPt}); + histos.add("Data/pos/pt/its", "ITS Positive " + tagPt, kTH1D, {axisPt}); + histos.add("Data/neg/pt/its", "ITS Negative " + tagPt, kTH1D, {axisPt}); - histos.add("Data/pos/eta/its", "ITS Positive " + tagEta, kTH1F, {axisEta}); - histos.add("Data/neg/eta/its", "ITS Negative " + tagEta, kTH1F, {axisEta}); + histos.add("Data/pos/eta/its", "ITS Positive " + tagEta, kTH1D, {axisEta}); + histos.add("Data/neg/eta/its", "ITS Negative " + tagEta, kTH1D, {axisEta}); - histos.add("Data/pos/phi/its", "ITS Positive " + tagPhi, kTH1F, {axisPhi}); - histos.add("Data/neg/phi/its", "ITS Negative " + tagPhi, kTH1F, {axisPhi}); + histos.add("Data/pos/phi/its", "ITS Positive " + tagPhi, kTH1D, {axisPhi}); + histos.add("Data/neg/phi/its", "ITS Negative " + tagPhi, kTH1D, {axisPhi}); histos.add("Data/pos/etaphi/its", "ITS Positive " + tagEtaPhi, kTH2D, {axisEta, axisPhi}); histos.add("Data/neg/etaphi/its", "ITS Negative " + tagEtaPhi, kTH2D, {axisEta, axisPhi}); // HMPID if (doprocessHmpid) { - histos.add("Data/pos/hmpidMomDiff", "HMPID Positive Momentum difference", kTH1F, {{100, -10, 10, "#it{p} - #it{p}_{HMPID} (GeV/#it{c})"}}); - histos.add("Data/neg/hmpidMomDiff", "HMPID Negative Momentum difference", kTH1F, {{100, -10, 10, "#it{p} - #it{p}_{HMPID} (GeV/#it{c})"}}); - histos.add("Data/pos/pt/hmpid", "HMPID Positive " + tagPt, kTH1F, {axisPt}); - histos.add("Data/neg/pt/hmpid", "HMPID Negative " + tagPt, kTH1F, {axisPt}); + histos.add("Data/pos/hmpidMomDiff", "HMPID Positive Momentum difference", kTH1D, {{100, -10, 10, "#it{p} - #it{p}_{HMPID} (GeV/#it{c})"}}); + histos.add("Data/neg/hmpidMomDiff", "HMPID Negative Momentum difference", kTH1D, {{100, -10, 10, "#it{p} - #it{p}_{HMPID} (GeV/#it{c})"}}); + histos.add("Data/pos/pt/hmpid", "HMPID Positive " + tagPt, kTH1D, {axisPt}); + histos.add("Data/neg/pt/hmpid", "HMPID Negative " + tagPt, kTH1D, {axisPt}); - histos.add("Data/pos/eta/hmpid", "HMPID Positive " + tagEta, kTH1F, {axisEta}); - histos.add("Data/neg/eta/hmpid", "HMPID Negative " + tagEta, kTH1F, {axisEta}); + histos.add("Data/pos/eta/hmpid", "HMPID Positive " + tagEta, kTH1D, {axisEta}); + histos.add("Data/neg/eta/hmpid", "HMPID Negative " + tagEta, kTH1D, {axisEta}); - histos.add("Data/pos/phi/hmpid", "HMPID Positive " + tagPhi, kTH1F, {axisPhi}); - histos.add("Data/neg/phi/hmpid", "HMPID Negative " + tagPhi, kTH1F, {axisPhi}); + histos.add("Data/pos/phi/hmpid", "HMPID Positive " + tagPhi, kTH1D, {axisPhi}); + histos.add("Data/neg/phi/hmpid", "HMPID Negative " + tagPhi, kTH1D, {axisPhi}); histos.add("Data/pos/etaphi/hmpid", "HMPID Positive " + tagEtaPhi, kTH2D, {axisEta, axisPhi}); histos.add("Data/neg/etaphi/hmpid", "HMPID Negative " + tagEtaPhi, kTH2D, {axisEta, axisPhi}); @@ -1089,19 +988,22 @@ struct QaEfficiency { // Custom track cuts if (globalTrackSelection.value == 6) { - customTrackCuts = getGlobalTrackSelectionRun3ITSMatch(itsPattern.value); + customTrackCuts = getGlobalTrackSelectionRun3ITSMatch(cfgCustomTrackCuts.itsPattern); LOG(info) << "Customizing track cuts:"; - customTrackCuts.SetRequireITSRefit(requireITS.value); - customTrackCuts.SetRequireTPCRefit(requireTPC.value); - customTrackCuts.SetRequireGoldenChi2(requireGoldenChi2.value); - customTrackCuts.SetRequireHitsInITSLayers(minITScl.value, {0, 1, 2, 3, 4, 5, 6}); - customTrackCuts.SetMaxChi2PerClusterTPC(maxChi2PerClusterTPC.value); - customTrackCuts.SetMaxChi2PerClusterITS(maxChi2PerClusterITS.value); - customTrackCuts.SetMinNCrossedRowsTPC(minNCrossedRowsTPC.value); - customTrackCuts.SetMinNClustersTPC(minTPCNClsFound.value); - customTrackCuts.SetMinNCrossedRowsOverFindableClustersTPC(minNCrossedRowsOverFindableClustersTPC.value); - customTrackCuts.SetMaxDcaXYPtDep([](float /*pt*/) { return 10000.f; }); // No DCAxy cut will be used, this is done via the member function of the task - customTrackCuts.SetMaxDcaZ(maxDcaZ.value); + if (cfgCustomTrackCuts.tracksIU.value) { + customTrackCuts.SetTrackType(o2::aod::track::TrackTypeEnum::TrackIU); + } + customTrackCuts.SetRequireITSRefit(cfgCustomTrackCuts.requireITS); + customTrackCuts.SetRequireTPCRefit(cfgCustomTrackCuts.requireTPC); + customTrackCuts.SetRequireGoldenChi2(cfgCustomTrackCuts.requireGoldenChi2); + customTrackCuts.SetRequireHitsInITSLayers(cfgCustomTrackCuts.minITScl.value, {0, 1, 2, 3, 4, 5, 6}); + customTrackCuts.SetMaxChi2PerClusterTPC(cfgCustomTrackCuts.maxChi2PerClusterTPC); + customTrackCuts.SetMaxChi2PerClusterITS(cfgCustomTrackCuts.maxChi2PerClusterITS); + customTrackCuts.SetMinNCrossedRowsTPC(cfgCustomTrackCuts.minNCrossedRowsTPC); + customTrackCuts.SetMinNClustersTPC(cfgCustomTrackCuts.minTPCNClsFound); + customTrackCuts.SetMinNCrossedRowsOverFindableClustersTPC(cfgCustomTrackCuts.minNCrossedRowsOverFindableClustersTPC); + customTrackCuts.SetMaxDcaXYPtDep([&](float /*pt*/) { return cfgCustomTrackCuts.maxDcaXY; }); // No DCAxy cut will be used, this is done via the member function of the task + customTrackCuts.SetMaxDcaZ(cfgCustomTrackCuts.maxDcaZ); customTrackCuts.print(); } } @@ -1111,17 +1013,33 @@ struct QaEfficiency { { static_assert(pdgSign == 0 || pdgSign == 1); static_assert(id > 0 || id < nSpecies); + constexpr int index = id + pdgSign * nSpecies; + return mcParticle.pdgCode() == PDGs[index]; + } - // Selecting a specific PDG - if constexpr (pdgSign == 0) { - return mcParticle.pdgCode() == PDGs[id]; - } else { - return mcParticle.pdgCode() == -PDGs[id]; + bool isPhysicalPrimary(const o2::aod::McParticles::iterator& mcParticle) + { + if (maxProdRadius < 999.f) { + if ((mcParticle.vx() * mcParticle.vx() + mcParticle.vy() * mcParticle.vy()) > maxProdRadius * maxProdRadius) { + return false; + } } + return mcParticle.isPhysicalPrimary(); } - - template - void fillMCTrackHistograms(const trackType& track, const bool doMakeHistograms) + bool isFinal(const o2::aod::McParticles::iterator& mcParticle) + { + if (!mcParticle.has_daughters() && !mcParticle.isPhysicalPrimary() && mcParticle.getProcess() == 4) { + auto mothers = mcParticle.mothers_as(); + for (const auto& mother : mothers) { + if (!mother.isPhysicalPrimary() && mother.getProcess() == 4) { + return true; + } + } + } + return false; // Otherwise, not considered a tertiary particle + } + template + void fillMCTrackHistograms(const TrackCandidatesMC::iterator& track, const bool doMakeHistograms) { static_assert(pdgSign == 0 || pdgSign == 1); if (!doMakeHistograms) { @@ -1137,15 +1055,20 @@ struct QaEfficiency { return; } } - - HistogramRegistry* h = &histosPosPdg; - if constexpr (pdgSign == 1) { - h = &histosNegPdg; - } - constexpr int histogramIndex = id + pdgSign * nSpecies; LOG(debug) << "fillMCTrackHistograms for pdgSign '" << pdgSign << "' and id '" << static_cast(id) << "' " << particleName(pdgSign, id) << " with index " << histogramIndex; - const auto mcParticle = track.mcParticle(); + const o2::aod::McParticles::iterator& mcParticle = track.mcParticle(); + const CollisionCandidatesMC::iterator& collision = track.collision_as(); + float radius = std::sqrt(mcParticle.vx() * mcParticle.vx() + mcParticle.vy() * mcParticle.vy()); + if (numSameCollision) { + if (!collision.has_mcCollision()) { + return; + } + if (mcParticle.mcCollision().globalIndex() != collision.mcCollision().globalIndex()) { + return; + } + } + histos.fill(HIST("MC/trackSelection"), trkCutSameColl); if (!isPdgSelected(mcParticle)) { // Selecting PDG code return; @@ -1154,97 +1077,142 @@ struct QaEfficiency { histos.fill(HIST("MC/trackSelection"), trkCutIdxN + id); if (passedITS) { - h->fill(HIST(hPtIts[histogramIndex]), mcParticle.pt()); + hPtIts[histogramIndex]->Fill(mcParticle.pt()); } if (passedTPC) { - h->fill(HIST(hPtTpc[histogramIndex]), mcParticle.pt()); + hPtTpc[histogramIndex]->Fill(mcParticle.pt()); } if (passedITS && passedTPC) { - h->fill(HIST(hPItsTpc[histogramIndex]), mcParticle.p()); - h->fill(HIST(hPtItsTpc[histogramIndex]), mcParticle.pt()); - h->fill(HIST(hEtaItsTpc[histogramIndex]), mcParticle.eta()); - h->fill(HIST(hYItsTpc[histogramIndex]), mcParticle.y()); - h->fill(HIST(hPhiItsTpc[histogramIndex]), mcParticle.phi()); + hPItsTpc[histogramIndex]->Fill(mcParticle.p()); + hPtItsTpc[histogramIndex]->Fill(mcParticle.pt()); + hEtaItsTpc[histogramIndex]->Fill(mcParticle.eta()); + hYItsTpc[histogramIndex]->Fill(mcParticle.y()); + hPhiItsTpc[histogramIndex]->Fill(mcParticle.phi()); - h->fill(HIST(hPTrkItsTpc[histogramIndex]), track.p()); - h->fill(HIST(hPtTrkItsTpc[histogramIndex]), track.pt()); - h->fill(HIST(hEtaTrkItsTpc[histogramIndex]), track.eta()); - h->fill(HIST(hPhiTrkItsTpc[histogramIndex]), track.phi()); + hPTrkItsTpc[histogramIndex]->Fill(track.p()); + hPtTrkItsTpc[histogramIndex]->Fill(track.pt()); + hEtaTrkItsTpc[histogramIndex]->Fill(track.eta()); + hPhiTrkItsTpc[histogramIndex]->Fill(track.phi()); if (doPtEta) { - h->fill(HIST(hPtEtaItsTpc[histogramIndex]), mcParticle.pt(), mcParticle.eta()); - h->fill(HIST(hPtEtaTrkItsTpc[histogramIndex]), track.pt(), track.eta()); + hPtEtaItsTpc[histogramIndex]->Fill(mcParticle.pt(), mcParticle.eta()); + hPtEtaTrkItsTpc[histogramIndex]->Fill(track.pt(), track.eta()); if (passedTOF) { - h->fill(HIST(hPtEtaItsTpcTof[histogramIndex]), mcParticle.pt(), mcParticle.eta()); + hPtEtaItsTpcTof[histogramIndex]->Fill(mcParticle.pt(), mcParticle.eta()); + } + } + if (doPtRadius) { + hPtRadiusItsTpc[histogramIndex]->Fill(mcParticle.pt(), radius); + if (passedTOF) { + hPtRadiusItsTpcTof[histogramIndex]->Fill(mcParticle.pt(), radius); } } } if (passedITS && passedTOF) { - h->fill(HIST(hPtItsTof[histogramIndex]), mcParticle.pt()); + hPtItsTof[histogramIndex]->Fill(mcParticle.pt()); } if (passedTPC && passedTOF) { - h->fill(HIST(hPtTpcTof[histogramIndex]), mcParticle.pt()); + hPtTpcTof[histogramIndex]->Fill(mcParticle.pt()); } if (passedITS && passedTPC && passedTRD) { - h->fill(HIST(hPtItsTpcTrd[histogramIndex]), mcParticle.p()); + hPtItsTpcTrd[histogramIndex]->Fill(mcParticle.p()); } if (passedITS && passedTPC && passedTOF) { - h->fill(HIST(hPItsTpcTof[histogramIndex]), mcParticle.p()); - h->fill(HIST(hPtItsTpcTof[histogramIndex]), mcParticle.pt()); - h->fill(HIST(hEtaItsTpcTof[histogramIndex]), mcParticle.eta()); - h->fill(HIST(hYItsTpcTof[histogramIndex]), mcParticle.y()); - h->fill(HIST(hPhiItsTpcTof[histogramIndex]), mcParticle.phi()); + hPItsTpcTof[histogramIndex]->Fill(mcParticle.p()); + hPtItsTpcTof[histogramIndex]->Fill(mcParticle.pt()); + hEtaItsTpcTof[histogramIndex]->Fill(mcParticle.eta()); + hYItsTpcTof[histogramIndex]->Fill(mcParticle.y()); + hPhiItsTpcTof[histogramIndex]->Fill(mcParticle.phi()); } if (passedITS && passedTPC && passedTRD && passedTOF) { - h->fill(HIST(hPtItsTpcTrdTof[histogramIndex]), mcParticle.p()); + hPtItsTpcTrdTof[histogramIndex]->Fill(mcParticle.p()); } - - bool isPhysicalPrimary = mcParticle.isPhysicalPrimary(); - if (maxProdRadius < 999.f) { - if ((mcParticle.vx() * mcParticle.vx() + mcParticle.vy() * mcParticle.vy()) > maxProdRadius * maxProdRadius) { - isPhysicalPrimary = false; - } - } - - if (isPhysicalPrimary) { + if (isPhysicalPrimary(mcParticle)) { if (passedITS) { - h->fill(HIST(hPtItsPrm[histogramIndex]), mcParticle.pt()); + hPtItsPrm[histogramIndex]->Fill(mcParticle.pt()); } if (passedITS && passedTPC) { - h->fill(HIST(hPtItsTpcPrm[histogramIndex]), mcParticle.pt()); - h->fill(HIST(hPtTrkItsTpcPrm[histogramIndex]), track.pt()); - h->fill(HIST(hEtaItsTpcPrm[histogramIndex]), mcParticle.eta()); - h->fill(HIST(hEtaTrkItsTpcPrm[histogramIndex]), track.eta()); - h->fill(HIST(hPhiItsTpcPrm[histogramIndex]), mcParticle.phi()); - h->fill(HIST(hPhiTrkItsTpcPrm[histogramIndex]), track.phi()); + hPtItsTpcPrm[histogramIndex]->Fill(mcParticle.pt()); + hPtTrkItsTpcPrm[histogramIndex]->Fill(track.pt()); + hEtaItsTpcPrm[histogramIndex]->Fill(mcParticle.eta()); + hEtaTrkItsTpcPrm[histogramIndex]->Fill(track.eta()); + hPhiItsTpcPrm[histogramIndex]->Fill(mcParticle.phi()); + hPhiTrkItsTpcPrm[histogramIndex]->Fill(track.phi()); if (passedTOF) { - h->fill(HIST(hPtItsTpcTofPrm[histogramIndex]), mcParticle.pt()); - h->fill(HIST(hPtTrkItsTpcTofPrm[histogramIndex]), track.pt()); - h->fill(HIST(hEtaItsTpcTofPrm[histogramIndex]), mcParticle.eta()); - h->fill(HIST(hPhiItsTpcTofPrm[histogramIndex]), mcParticle.phi()); + hPtItsTpcTofPrm[histogramIndex]->Fill(mcParticle.pt()); + hPtTrkItsTpcTofPrm[histogramIndex]->Fill(track.pt()); + hEtaItsTpcTofPrm[histogramIndex]->Fill(mcParticle.eta()); + hPhiItsTpcTofPrm[histogramIndex]->Fill(mcParticle.phi()); + } + if (doPtRadius) { + hPtRadiusItsTpcPrm[histogramIndex]->Fill(mcParticle.pt(), radius); + if (passedTOF) { + hPtRadiusItsTpcTofPrm[histogramIndex]->Fill(mcParticle.pt(), radius); + } } } } else if (mcParticle.getProcess() == 4) { // Particle decay - if (passedITS && passedTPC) { - h->fill(HIST(hPtItsTpcStr[histogramIndex]), mcParticle.pt()); - h->fill(HIST(hPtTrkItsTpcStr[histogramIndex]), track.pt()); + // Checking mothers + bool motherIsAccepted = true; + if (checkForMothers.value && mothersPDGs.value.size() > 0 && mcParticle.has_mothers()) { + motherIsAccepted = false; + auto mothers = mcParticle.mothers_as(); + for (const auto& mother : mothers) { + for (const auto& pdgToCheck : mothersPDGs.value) { + if (mother.pdgCode() == pdgToCheck) { + motherIsAccepted = true; + // Calculate the decay length + double decayLength = std::sqrt(std::pow(mother.vx() - mother.mcCollision().posX(), 2) + std::pow(mother.vy() - mother.mcCollision().posY(), 2) + std::pow(mother.vz() - mother.mcCollision().posZ(), 2)); + hdecaylengthmother[histogramIndex]->Fill(decayLength); + break; + } + if (motherIsAccepted) { + break; + } + } + } + } + if (passedITS && passedTPC && motherIsAccepted) { + hPtItsTpcStr[histogramIndex]->Fill(mcParticle.pt()); + hPtTrkItsTpcStr[histogramIndex]->Fill(track.pt()); if (passedTOF) { - h->fill(HIST(hPtItsTpcTofStr[histogramIndex]), mcParticle.pt()); + hPtItsTpcTofStr[histogramIndex]->Fill(mcParticle.pt()); + } + if (doPtRadius) { + hPtRadiusItsTpcStr[histogramIndex]->Fill(mcParticle.pt(), radius); + if (passedTOF) { + hPtRadiusItsTpcTofStr[histogramIndex]->Fill(mcParticle.pt(), radius); + } + } + } + if (isFinal(mcParticle)) { + if (passedITS && passedTPC && motherIsAccepted) { + hPtItsTpcTer[histogramIndex]->Fill(mcParticle.pt()); + hPtTrkItsTpcTer[histogramIndex]->Fill(track.pt()); + if (passedTOF) { + hPtItsTpcTofTer[histogramIndex]->Fill(mcParticle.pt()); + } + if (doPtRadius) { + hPtRadiusItsTpcTer[histogramIndex]->Fill(mcParticle.pt(), radius); + if (passedTOF) { + hPtRadiusItsTpcTofTer[histogramIndex]->Fill(mcParticle.pt(), radius); + } + } } } } else { // Material if (passedITS && passedTPC) { - h->fill(HIST(hPtItsTpcMat[histogramIndex]), mcParticle.pt()); - h->fill(HIST(hPtTrkItsTpcMat[histogramIndex]), track.pt()); + hPtItsTpcMat[histogramIndex]->Fill(mcParticle.pt()); + hPtTrkItsTpcMat[histogramIndex]->Fill(track.pt()); if (passedTOF) { - h->fill(HIST(hPtItsTpcTofMat[histogramIndex]), mcParticle.pt()); + hPtItsTpcTofMat[histogramIndex]->Fill(mcParticle.pt()); } } } } - template - void fillMCParticleHistograms(const particleType& mcParticle, const bool doMakeHistograms) + template + void fillMCParticleHistograms(const o2::aod::McParticles::iterator& mcParticle, const bool doMakeHistograms) { static_assert(pdgSign == 0 || pdgSign == 1); if (!doMakeHistograms) { @@ -1261,45 +1229,76 @@ struct QaEfficiency { } } - HistogramRegistry* h = &histosPosPdg; - if (pdgSign == 1) { - h = &histosNegPdg; - } - constexpr int histogramIndex = id + pdgSign * nSpecies; LOG(debug) << "fillMCParticleHistograms for pdgSign '" << pdgSign << "' and id '" << static_cast(id) << "' " << particleName(pdgSign, id) << " with index " << histogramIndex; + float radius = std::sqrt(mcParticle.vx() * mcParticle.vx() + mcParticle.vy() * mcParticle.vy()); if (!isPdgSelected(mcParticle)) { // Selecting PDG code return; } + if constexpr (recoEv) { + hPtGeneratedRecoEv[histogramIndex]->Fill(mcParticle.pt()); + if (isPhysicalPrimary(mcParticle)) { + hPtGeneratedPrmRecoEv[histogramIndex]->Fill(mcParticle.pt()); + } + return; + } histos.fill(HIST("MC/particleSelection"), 6 + id); - h->fill(HIST(hPGenerated[histogramIndex]), mcParticle.p()); - h->fill(HIST(hPtGenerated[histogramIndex]), mcParticle.pt()); + hPGenerated[histogramIndex]->Fill(mcParticle.p()); + hPtGenerated[histogramIndex]->Fill(mcParticle.pt()); - bool isPhysicalPrimary = mcParticle.isPhysicalPrimary(); - if (maxProdRadius < 999.f) { - if ((mcParticle.vx() * mcParticle.vx() + mcParticle.vy() * mcParticle.vy()) > maxProdRadius * maxProdRadius) { - isPhysicalPrimary = false; + if (isPhysicalPrimary(mcParticle)) { + hPtGeneratedPrm[histogramIndex]->Fill(mcParticle.pt()); + hEtaGeneratedPrm[histogramIndex]->Fill(mcParticle.eta()); + hPhiGeneratedPrm[histogramIndex]->Fill(mcParticle.phi()); + if (doPtRadius) { + hPtRadiusGeneratedPrm[histogramIndex]->Fill(mcParticle.pt(), radius); } - } - - if (isPhysicalPrimary) { - h->fill(HIST(hPtGeneratedPrm[histogramIndex]), mcParticle.pt()); - h->fill(HIST(hEtaGeneratedPrm[histogramIndex]), mcParticle.eta()); - h->fill(HIST(hPhiGeneratedPrm[histogramIndex]), mcParticle.phi()); } else { - if (mcParticle.getProcess() == 4) { // Particle deday - h->fill(HIST(hPtGeneratedStr[histogramIndex]), mcParticle.pt()); + if (mcParticle.getProcess() == 4) { // Particle decay + bool motherIsAccepted = true; + // Check for mothers if needed + if (checkForMothers.value && mothersPDGs.value.size() > 0 && mcParticle.has_mothers()) { + motherIsAccepted = false; + auto mothers = mcParticle.mothers_as(); + // Loop over mother particles + for (const auto& mother : mothers) { + for (const auto& pdgToCheck : mothersPDGs.value) { + if (mother.pdgCode() == pdgToCheck) { + motherIsAccepted = true; // Mother matches the list of specified PDGs + hPtmotherGenerated[histogramIndex]->Fill(mother.pt()); // Fill generated pT for mother + break; + } + if (motherIsAccepted) { + break; + } + } + } + } + if (motherIsAccepted) { + hPtGeneratedStr[histogramIndex]->Fill(mcParticle.pt()); + if (doPtRadius) { + hPtRadiusGeneratedStr[histogramIndex]->Fill(mcParticle.pt(), radius); + } + if (isFinal(mcParticle)) { + hPtGeneratedTer[histogramIndex]->Fill(mcParticle.pt()); + if (doPtRadius) { + hPtRadiusGeneratedTer[histogramIndex]->Fill(mcParticle.pt(), radius); + } + } + } } else { // Material - h->fill(HIST(hPtGeneratedMat[histogramIndex]), mcParticle.pt()); + hPtGeneratedMat[histogramIndex]->Fill(mcParticle.pt()); } } - - h->fill(HIST(hEtaGenerated[histogramIndex]), mcParticle.eta()); - h->fill(HIST(hYGenerated[histogramIndex]), mcParticle.y()); - h->fill(HIST(hPhiGenerated[histogramIndex]), mcParticle.phi()); + hEtaGenerated[histogramIndex]->Fill(mcParticle.eta()); + hYGenerated[histogramIndex]->Fill(mcParticle.y()); + hPhiGenerated[histogramIndex]->Fill(mcParticle.phi()); if (doPtEta) { - h->fill(HIST(hPtEtaGenerated[histogramIndex]), mcParticle.pt(), mcParticle.eta()); + hPtEtaGenerated[histogramIndex]->Fill(mcParticle.pt(), mcParticle.eta()); + } + if (doPtRadius) { + hPtRadiusGenerated[histogramIndex]->Fill(mcParticle.pt(), radius); } } @@ -1324,11 +1323,6 @@ struct QaEfficiency { return; } - HistogramRegistry* registry = &histosPosPdg; - if (pdgSign == 1) { - registry = &histosNegPdg; - } - constexpr int histogramIndex = id + pdgSign * nSpecies; const char* partName = particleName(pdgSign, id); @@ -1346,56 +1340,64 @@ struct QaEfficiency { LOG(warning) << "Cannot find TEfficiency " << effname; return; } - eff->SetTotalHistogram(*registry->get(den).get(), "f"); - eff->SetPassedHistogram(*registry->get(num).get(), "f"); + eff->SetTotalHistogram(*den, "f"); + eff->SetPassedHistogram(*num, "f"); }; - doFillEfficiency("ITS_vsPt", HIST(hPtIts[histogramIndex]), HIST(hPtGenerated[histogramIndex])); - doFillEfficiency("TPC_vsPt", HIST(hPtTpc[histogramIndex]), HIST(hPtGenerated[histogramIndex])); - doFillEfficiency("ITS-TPC_vsPt", HIST(hPtItsTpc[histogramIndex]), HIST(hPtGenerated[histogramIndex])); - doFillEfficiency("ITS-TOF_vsPt", HIST(hPtItsTof[histogramIndex]), HIST(hPtGenerated[histogramIndex])); - doFillEfficiency("TPC-TOF_vsPt", HIST(hPtTpcTof[histogramIndex]), HIST(hPtGenerated[histogramIndex])); - doFillEfficiency("ITS-TPC-TRD_vsPt", HIST(hPtItsTpcTrd[histogramIndex]), HIST(hPtGenerated[histogramIndex])); - doFillEfficiency("ITS-TPC-TOF_vsPt", HIST(hPtItsTpcTof[histogramIndex]), HIST(hPtGenerated[histogramIndex])); - doFillEfficiency("ITS-TPC-TRD-TOF_vsPt", HIST(hPtItsTpcTrdTof[histogramIndex]), HIST(hPtGenerated[histogramIndex])); - doFillEfficiency("ITS-TPC_vsPt_Trk", HIST(hPtTrkItsTpc[histogramIndex]), HIST(hPtGenerated[histogramIndex])); - - doFillEfficiency("ITS_vsPt_Prm", HIST(hPtItsPrm[histogramIndex]), HIST(hPtGeneratedPrm[histogramIndex])); - doFillEfficiency("ITS-TPC_vsPt_Prm", HIST(hPtItsTpcPrm[histogramIndex]), HIST(hPtGeneratedPrm[histogramIndex])); - doFillEfficiency("ITS-TPC_vsPt_Prm_Trk", HIST(hPtTrkItsTpcPrm[histogramIndex]), HIST(hPtGeneratedPrm[histogramIndex])); - doFillEfficiency("ITS-TPC-TOF_vsPt_Prm", HIST(hPtItsTpcTofPrm[histogramIndex]), HIST(hPtGeneratedPrm[histogramIndex])); - doFillEfficiency("ITS-TPC-TOF_vsPt_Prm_Trk", HIST(hPtTrkItsTpcTofPrm[histogramIndex]), HIST(hPtGeneratedPrm[histogramIndex])); - - doFillEfficiency("ITS-TPC_vsPt_Str", HIST(hPtItsTpcStr[histogramIndex]), HIST(hPtGeneratedStr[histogramIndex])); - doFillEfficiency("ITS-TPC_vsPt_Str_Trk", HIST(hPtTrkItsTpcStr[histogramIndex]), HIST(hPtGeneratedStr[histogramIndex])); - doFillEfficiency("ITS-TPC-TOF_vsPt_Str", HIST(hPtItsTpcTofStr[histogramIndex]), HIST(hPtGeneratedStr[histogramIndex])); - - doFillEfficiency("ITS-TPC_vsPt_Mat", HIST(hPtItsTpcMat[histogramIndex]), HIST(hPtGeneratedMat[histogramIndex])); - doFillEfficiency("ITS-TPC_vsPt_Mat_Trk", HIST(hPtTrkItsTpcMat[histogramIndex]), HIST(hPtGeneratedMat[histogramIndex])); - doFillEfficiency("ITS-TPC-TOF_vsPt_Mat", HIST(hPtItsTpcTofMat[histogramIndex]), HIST(hPtGeneratedMat[histogramIndex])); - - doFillEfficiency("ITS-TPC_vsP", HIST(hPItsTpc[histogramIndex]), HIST(hPGenerated[histogramIndex])); - doFillEfficiency("ITS-TPC_vsP_Trk", HIST(hPTrkItsTpc[histogramIndex]), HIST(hPGenerated[histogramIndex])); - doFillEfficiency("ITS-TPC-TOF_vsP", HIST(hPItsTpcTof[histogramIndex]), HIST(hPGenerated[histogramIndex])); - - doFillEfficiency("ITS-TPC_vsEta", HIST(hEtaItsTpc[histogramIndex]), HIST(hEtaGenerated[histogramIndex])); - doFillEfficiency("ITS-TPC_vsEta_Trk", HIST(hEtaTrkItsTpc[histogramIndex]), HIST(hEtaGenerated[histogramIndex])); - doFillEfficiency("ITS-TPC-TOF_vsEta", HIST(hEtaItsTpcTof[histogramIndex]), HIST(hEtaGenerated[histogramIndex])); - - doFillEfficiency("ITS-TPC_vsEta_Prm", HIST(hEtaItsTpcPrm[histogramIndex]), HIST(hEtaGeneratedPrm[histogramIndex])); - doFillEfficiency("ITS-TPC_vsEta_Prm_Trk", HIST(hEtaTrkItsTpcPrm[histogramIndex]), HIST(hEtaGeneratedPrm[histogramIndex])); - doFillEfficiency("ITS-TPC-TOF_vsEta_Prm", HIST(hEtaItsTpcTofPrm[histogramIndex]), HIST(hEtaGeneratedPrm[histogramIndex])); - - doFillEfficiency("ITS-TPC_vsPhi_Prm", HIST(hPhiItsTpcPrm[histogramIndex]), HIST(hPhiGeneratedPrm[histogramIndex])); - doFillEfficiency("ITS-TPC_vsPhi_Prm_Trk", HIST(hPhiTrkItsTpcPrm[histogramIndex]), HIST(hPhiGeneratedPrm[histogramIndex])); - doFillEfficiency("ITS-TPC-TOF_vsPhi_Prm", HIST(hPhiItsTpcTofPrm[histogramIndex]), HIST(hPhiGeneratedPrm[histogramIndex])); - - doFillEfficiency("ITS-TPC_vsY", HIST(hYItsTpc[histogramIndex]), HIST(hYGenerated[histogramIndex])); - doFillEfficiency("ITS-TPC-TOF_vsY", HIST(hYItsTpcTof[histogramIndex]), HIST(hYGenerated[histogramIndex])); - - doFillEfficiency("ITS-TPC_vsPhi", HIST(hPhiItsTpc[histogramIndex]), HIST(hPhiGenerated[histogramIndex])); - doFillEfficiency("ITS-TPC_vsPhi_Trk", HIST(hPhiTrkItsTpc[histogramIndex]), HIST(hPhiGenerated[histogramIndex])); - doFillEfficiency("ITS-TPC-TOF_vsPhi", HIST(hPhiItsTpcTof[histogramIndex]), HIST(hPhiGenerated[histogramIndex])); + doFillEfficiency("ITS_vsPt", hPtIts[histogramIndex], hPtGenerated[histogramIndex]); + doFillEfficiency("TPC_vsPt", hPtTpc[histogramIndex], hPtGenerated[histogramIndex]); + doFillEfficiency("ITS-TPC_vsPt", hPtItsTpc[histogramIndex], hPtGenerated[histogramIndex]); + doFillEfficiency("ITS-TOF_vsPt", hPtItsTof[histogramIndex], hPtGenerated[histogramIndex]); + doFillEfficiency("TPC-TOF_vsPt", hPtTpcTof[histogramIndex], hPtGenerated[histogramIndex]); + doFillEfficiency("ITS-TPC-TRD_vsPt", hPtItsTpcTrd[histogramIndex], hPtGenerated[histogramIndex]); + doFillEfficiency("ITS-TPC-TOF_vsPt", hPtItsTpcTof[histogramIndex], hPtGenerated[histogramIndex]); + doFillEfficiency("ITS-TPC-TRD-TOF_vsPt", hPtItsTpcTrdTof[histogramIndex], hPtGenerated[histogramIndex]); + doFillEfficiency("ITS-TPC_vsPt_Trk", hPtTrkItsTpc[histogramIndex], hPtGenerated[histogramIndex]); + + doFillEfficiency("ITS-TPC_vsPt_RecoEv", hPtItsTpcPrm[histogramIndex], hPtGeneratedRecoEv[histogramIndex]); + + doFillEfficiency("ITS_vsPt_Prm", hPtItsPrm[histogramIndex], hPtGeneratedPrm[histogramIndex]); + doFillEfficiency("ITS-TPC_vsPt_Prm", hPtItsTpcPrm[histogramIndex], hPtGeneratedPrm[histogramIndex]); + doFillEfficiency("ITS-TPC_vsPt_Prm_Trk", hPtTrkItsTpcPrm[histogramIndex], hPtGeneratedPrm[histogramIndex]); + doFillEfficiency("ITS-TPC-TOF_vsPt_Prm", hPtItsTpcTofPrm[histogramIndex], hPtGeneratedPrm[histogramIndex]); + doFillEfficiency("ITS-TPC-TOF_vsPt_Prm_Trk", hPtTrkItsTpcTofPrm[histogramIndex], hPtGeneratedPrm[histogramIndex]); + + doFillEfficiency("ITS-TPC_vsPt_Prm_RecoEv", hPtItsTpcPrm[histogramIndex], hPtGeneratedPrmRecoEv[histogramIndex]); + + doFillEfficiency("ITS-TPC_vsPt_Str", hPtItsTpcStr[histogramIndex], hPtGeneratedStr[histogramIndex]); + doFillEfficiency("ITS-TPC_vsPt_Str_Trk", hPtTrkItsTpcStr[histogramIndex], hPtGeneratedStr[histogramIndex]); + doFillEfficiency("ITS-TPC-TOF_vsPt_Str", hPtItsTpcTofStr[histogramIndex], hPtGeneratedStr[histogramIndex]); + + doFillEfficiency("ITS-TPC_vsPt_Mat", hPtItsTpcMat[histogramIndex], hPtGeneratedMat[histogramIndex]); + doFillEfficiency("ITS-TPC_vsPt_Mat_Trk", hPtTrkItsTpcMat[histogramIndex], hPtGeneratedMat[histogramIndex]); + doFillEfficiency("ITS-TPC-TOF_vsPt_Mat", hPtItsTpcTofMat[histogramIndex], hPtGeneratedMat[histogramIndex]); + + doFillEfficiency("ITS-TPC_vsPt_Ter", hPtItsTpcTer[histogramIndex], hPtGeneratedTer[histogramIndex]); + doFillEfficiency("ITS-TPC_vsPt_Ter_Trk", hPtTrkItsTpcTer[histogramIndex], hPtGeneratedTer[histogramIndex]); + doFillEfficiency("ITS-TPC-TOF_vsPt_Ter", hPtItsTpcTofTer[histogramIndex], hPtGeneratedTer[histogramIndex]); + + doFillEfficiency("ITS-TPC_vsP", hPItsTpc[histogramIndex], hPGenerated[histogramIndex]); + doFillEfficiency("ITS-TPC_vsP_Trk", hPTrkItsTpc[histogramIndex], hPGenerated[histogramIndex]); + doFillEfficiency("ITS-TPC-TOF_vsP", hPItsTpcTof[histogramIndex], hPGenerated[histogramIndex]); + + doFillEfficiency("ITS-TPC_vsEta", hEtaItsTpc[histogramIndex], hEtaGenerated[histogramIndex]); + doFillEfficiency("ITS-TPC_vsEta_Trk", hEtaTrkItsTpc[histogramIndex], hEtaGenerated[histogramIndex]); + doFillEfficiency("ITS-TPC-TOF_vsEta", hEtaItsTpcTof[histogramIndex], hEtaGenerated[histogramIndex]); + + doFillEfficiency("ITS-TPC_vsEta_Prm", hEtaItsTpcPrm[histogramIndex], hEtaGeneratedPrm[histogramIndex]); + doFillEfficiency("ITS-TPC_vsEta_Prm_Trk", hEtaTrkItsTpcPrm[histogramIndex], hEtaGeneratedPrm[histogramIndex]); + doFillEfficiency("ITS-TPC-TOF_vsEta_Prm", hEtaItsTpcTofPrm[histogramIndex], hEtaGeneratedPrm[histogramIndex]); + + doFillEfficiency("ITS-TPC_vsPhi_Prm", hPhiItsTpcPrm[histogramIndex], hPhiGeneratedPrm[histogramIndex]); + doFillEfficiency("ITS-TPC_vsPhi_Prm_Trk", hPhiTrkItsTpcPrm[histogramIndex], hPhiGeneratedPrm[histogramIndex]); + doFillEfficiency("ITS-TPC-TOF_vsPhi_Prm", hPhiItsTpcTofPrm[histogramIndex], hPhiGeneratedPrm[histogramIndex]); + + doFillEfficiency("ITS-TPC_vsY", hYItsTpc[histogramIndex], hYGenerated[histogramIndex]); + doFillEfficiency("ITS-TPC-TOF_vsY", hYItsTpcTof[histogramIndex], hYGenerated[histogramIndex]); + + doFillEfficiency("ITS-TPC_vsPhi", hPhiItsTpc[histogramIndex], hPhiGenerated[histogramIndex]); + doFillEfficiency("ITS-TPC_vsPhi_Trk", hPhiTrkItsTpc[histogramIndex], hPhiGenerated[histogramIndex]); + doFillEfficiency("ITS-TPC-TOF_vsPhi", hPhiItsTpcTof[histogramIndex], hPhiGenerated[histogramIndex]); if (!doPtEta) { return; @@ -1408,14 +1410,24 @@ struct QaEfficiency { LOG(warning) << "Cannot find TEfficiency " << effname; return; } - eff->SetTotalHistogram(*registry->get(den).get(), "f"); - eff->SetPassedHistogram(*registry->get(num).get(), "f"); + eff->SetTotalHistogram(*den, "f"); + eff->SetPassedHistogram(*num, "f"); }; - fillEfficiency2D("ITS-TPC_vsPt_vsEta", HIST(hPtEtaItsTpc[histogramIndex]), HIST(hPtEtaGenerated[histogramIndex])); - fillEfficiency2D("ITS-TPC_vsPt_vsEta_Trk", HIST(hPtEtaTrkItsTpc[histogramIndex]), HIST(hPtEtaGenerated[histogramIndex])); - fillEfficiency2D("ITS-TPC-TOF_vsPt_vsEta", HIST(hPtEtaItsTpcTof[histogramIndex]), HIST(hPtEtaGenerated[histogramIndex])); + fillEfficiency2D("ITS-TPC_vsPt_vsEta", hPtEtaItsTpc[histogramIndex], hPtEtaGenerated[histogramIndex]); + fillEfficiency2D("ITS-TPC_vsPt_vsEta_Trk", hPtEtaTrkItsTpc[histogramIndex], hPtEtaGenerated[histogramIndex]); + fillEfficiency2D("ITS-TPC-TOF_vsPt_vsEta", hPtEtaItsTpcTof[histogramIndex], hPtEtaGenerated[histogramIndex]); + if (!doPtRadius) { + return; + } + fillEfficiency2D("ITS-TPC_vsPt_vsRadius", hPtRadiusItsTpc[histogramIndex], hPtRadiusGenerated[histogramIndex]); + fillEfficiency2D("ITS-TPC-TOF_vsPt_vsRadius", hPtRadiusItsTpcTof[histogramIndex], hPtRadiusGenerated[histogramIndex]); + fillEfficiency2D("ITS-TPC_vsPt_vsRadius", hPtRadiusItsTpcPrm[histogramIndex], hPtRadiusGeneratedPrm[histogramIndex]); + fillEfficiency2D("ITS-TPC-TOF_vsPt_vsRadius", hPtRadiusItsTpcTofPrm[histogramIndex], hPtRadiusGeneratedPrm[histogramIndex]); + fillEfficiency2D("ITS-TPC_vsPt_vsRadius", hPtRadiusItsTpcStr[histogramIndex], hPtRadiusGeneratedStr[histogramIndex]); + fillEfficiency2D("ITS-TPC-TOF_vsPt_vsRadius", hPtRadiusItsTpcTofStr[histogramIndex], hPtRadiusGeneratedStr[histogramIndex]); + fillEfficiency2D("ITS-TPC_vsPt_vsRadius", hPtRadiusItsTpcTer[histogramIndex], hPtRadiusGeneratedTer[histogramIndex]); + fillEfficiency2D("ITS-TPC-TOF_vsPt_vsRadius", hPtRadiusItsTpcTofTer[histogramIndex], hPtRadiusGeneratedTer[histogramIndex]); } - template bool isCollisionSelected(const CollType& collision) { @@ -1446,11 +1458,7 @@ struct QaEfficiency { } // Global process - using TrackCandidates = o2::soa::Join; - void process(o2::soa::Join::iterator const& collision) - { - isCollisionSelected(collision); - } + void process(CollisionCandidates::iterator const& collision) { isCollisionSelected(collision); } // Function to apply particle selection template @@ -1677,115 +1685,321 @@ struct QaEfficiency { return true; } + /// \brief Function to get MC collision occupancy + /// \param collSlice collection of reconstructed collisions + /// \return collision occupancy + template + int getOccupancyColl(CCs const& collSlice) + { + float multiplicity{0.f}; + int occupancy = 0; + for (const auto& collision : collSlice) { + float collMult{0.f}; + collMult = collision.numContrib(); + + if (collMult > multiplicity) { + if (useFT0OccEstimator) { + /// occupancy estimator (FT0c signal amplitudes in +-10us from current collision) + occupancy = collision.ft0cOccupancyInTimeRange(); + } else { + /// occupancy estimator (ITS tracks with at least 5 clusters in +-10us from current collision) + occupancy = static_cast(collision.trackOccupancyInTimeRange()); + } + multiplicity = collMult; + } + } // end loop over collisions + + return occupancy; + } + + /// \brief Function to get MC collision centrality + /// \param collSlice collection of reconstructed collisions + /// \return collision centrality + template + int getCentralityColl(CCs const& collSlice) + { + float multiplicity{0.f}; + int centrality = 0; + for (const auto& collision : collSlice) { + float collMult{0.f}; + collMult = collision.numContrib(); + + if (collMult > multiplicity) { + centrality = collision.centFT0C(); + multiplicity = collMult; + } + } // end loop over collisions + + return centrality; + } + // MC process + // Single-track efficiency calculated only for MC collisions with at least 1 reco. collision + SliceCache cache; Preslice perCollision = o2::aod::track::collisionId; - void processMC(o2::aod::McCollision const&, - o2::soa::SmallGroups> const& collisions, - o2::soa::Join const& tracks, + Preslice perCollisionMc = o2::aod::mcparticle::mcCollisionId; + PresliceUnsorted collPerCollMc = o2::aod::mccollisionlabel::mcCollisionId; + void processMC(o2::aod::McCollisions const& mcCollisions, + // o2::soa::SmallGroups const& collisions, + CollisionCandidatesMC const& collisions, + TrackCandidatesMC const& tracks, o2::aod::McParticles const& mcParticles) { - histos.fill(HIST("MC/generatedCollisions"), 1); - if (collisions.size() < 1) { // Skipping MC events that have no reconstructed collisions - return; - } - histos.fill(HIST("MC/generatedCollisions"), 2); - if (skipEventsWithoutTPCTracks) { - int nTPCTracks = 0; - for (const auto& collision : collisions) { - const auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex()); - for (const auto& track : groupedTracks) { - if (track.hasTPC()) { - nTPCTracks++; - break; + /// loop over generated collisions + for (const auto& mcCollision : mcCollisions) { + histos.fill(HIST("MC/generatedCollisions"), 1); + + const auto groupedCollisions = collisions.sliceBy(collPerCollMc, mcCollision.globalIndex()); + const auto groupedMcParticles = mcParticles.sliceBy(perCollisionMc, mcCollision.globalIndex()); + + // LOG(info) << "groupedCollisions.size() " << groupedCollisions.size(); + + if (groupedCollisions.size() < 1) { // Skipping MC events that have no reconstructed collisions + continue; + } + float centrality = -1.; + float occupancy = -1.; + if (doOccupancy) { + centrality = getCentralityColl(groupedCollisions); + occupancy = getOccupancyColl(groupedCollisions); + } + histos.fill(HIST("MC/generatedCollisions"), 2); + if (skipEventsWithoutTPCTracks) { + int nTPCTracks = 0; + for (const auto& collision : groupedCollisions) { + const auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex()); + for (const auto& track : groupedTracks) { + if (track.hasTPC()) { + nTPCTracks++; + break; + } } } + if (nTPCTracks == 0) { + LOG(info) << "Skipping event with no TPC tracks"; + continue; + } } - if (nTPCTracks == 0) { - LOG(info) << "Skipping event with no TPC tracks"; - return; - } - } - histos.fill(HIST("MC/generatedCollisions"), 3); + histos.fill(HIST("MC/generatedCollisions"), 3); - for (const auto& collision : collisions) { - histos.fill(HIST("MC/generatedCollisions"), 4); - if (!isCollisionSelected(collision)) { + if (eventGeneratorType >= 0 && mcCollision.getSubGeneratorId() != eventGeneratorType) { + LOG(debug) << "Skipping event with different type of generator than the one requested"; continue; } - histos.fill(HIST("MC/generatedCollisions"), 5); - const auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex()); + /// loop over reconstructed collisions + for (const auto& collision : groupedCollisions) { + histos.fill(HIST("MC/generatedCollisions"), 4); + if (!isCollisionSelected(collision)) { + continue; + } + histos.fill(HIST("MC/generatedCollisions"), 5); + if (useFT0OccEstimator) { + /// occupancy estimator (FT0c signal amplitudes in +-10us from current collision) + occupancy = collision.ft0cOccupancyInTimeRange(); + } else { + /// occupancy estimator (ITS tracks with at least 5 clusters in +-10us from current collision) + occupancy = static_cast(collision.trackOccupancyInTimeRange()); + } + centrality = collision.centFT0C(); + + const auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex()); + + // Track loop + for (const auto& track : groupedTracks) { + if (!isTrackSelected(track, HIST("MC/trackSelection"))) { + continue; + } + + // search for particles from HF decays + // no need to check if track.has_mcParticle() == true, this is done already in isTrackSelected + const auto& particle = track.mcParticle(); + if (keepOnlyHfParticles && !RecoDecay::getCharmHadronOrigin(mcParticles, particle, /*searchUpToQuark*/ true)) { + continue; + } - // Track loop - for (const auto& track : groupedTracks) { - if (!isTrackSelected(track, HIST("MC/trackSelection"))) { + if (doOccupancy) { + float trackPt = track.pt(); + float trackSign = track.sign(); + if (trackSign > 0) { + if (passedTOF && passedTPC && passedITS) { + histos.fill(HIST("MC/occ_cent/reco/pos/its_tpc_tof"), occupancy, centrality, trackPt); + } + if (passedTPC && passedITS) { + histos.fill(HIST("MC/occ_cent/reco/pos/its_tpc"), occupancy, centrality, trackPt); + } + if (passedITS) { + histos.fill(HIST("MC/occ_cent/reco/pos/its"), occupancy, centrality, trackPt); + } + } + if (trackSign < 0) { + if (passedTOF && passedTPC && passedITS) { + histos.fill(HIST("MC/occ_cent/reco/neg/its_tpc_tof"), occupancy, centrality, trackPt); + } + if (passedTPC && passedITS) { + histos.fill(HIST("MC/occ_cent/reco/neg/its_tpc"), occupancy, centrality, trackPt); + } + if (passedITS) { + histos.fill(HIST("MC/occ_cent/reco/neg/its"), occupancy, centrality, trackPt); + } + } + } + + // Filling variable histograms + histos.fill(HIST("MC/trackLength"), track.length()); + static_for<0, 1>([&](auto pdgSign) { + fillMCTrackHistograms(track, doEl); + fillMCTrackHistograms(track, doMu); + fillMCTrackHistograms(track, doPi); + fillMCTrackHistograms(track, doKa); + fillMCTrackHistograms(track, doPr); + fillMCTrackHistograms(track, doDe); + fillMCTrackHistograms(track, doTr); + fillMCTrackHistograms(track, doHe); + fillMCTrackHistograms(track, doAl); + }); + } + + // Skipping collisions without the generated collisions + // Actually this should never happen, since we group per MC collision + if (!collision.has_mcCollision()) { continue; + } else { + // skip generated collisions outside the allowed vtx-z range + // putting this condition here avoids the particle loop a few lines below + if (applyPvZCutGenColl) { + const float genPvZ = mcCollision.posZ(); + if (genPvZ < vertexZMin || genPvZ > vertexZMax) { + continue; + } + } } - // Filling variable histograms - histos.fill(HIST("MC/trackLength"), track.length()); - static_for<0, 1>([&](auto pdgSign) { - fillMCTrackHistograms(track, doEl); - fillMCTrackHistograms(track, doMu); - fillMCTrackHistograms(track, doPi); - fillMCTrackHistograms(track, doKa); - fillMCTrackHistograms(track, doPr); - fillMCTrackHistograms(track, doDe); - fillMCTrackHistograms(track, doTr); - fillMCTrackHistograms(track, doHe); - fillMCTrackHistograms(track, doAl); - }); - } - } - // Loop on particles to fill the denominator - float dNdEta = 0; // Multiplicity - for (const auto& mcParticle : mcParticles) { - if (TMath::Abs(mcParticle.eta()) <= 2.f && !mcParticle.has_daughters()) { - dNdEta += 1.f; + /// only to fill denominator of ITS-TPC matched primary tracks only in MC events with at least 1 reco. vtx + for (const auto& particle : groupedMcParticles) { // Particle loop + + /// require generated particle in acceptance + if (!isInAcceptance(particle, nullptr)) { + continue; + } + + // search for particles from HF decays + if (keepOnlyHfParticles && !RecoDecay::getCharmHadronOrigin(mcParticles, particle, /*searchUpToQuark*/ true)) { + continue; + } + + if (doOccupancy) { + float partSign = particle.pdgCode(); + float mcPartPt = particle.pt(); + if (partSign > 0) { + histos.fill(HIST("MC/occ_cent/gen/pos"), occupancy, centrality, mcPartPt); + } + if (partSign < 0) { + histos.fill(HIST("MC/occ_cent/gen/neg"), occupancy, centrality, mcPartPt); + } + } + + static_for<0, 1>([&](auto pdgSign) { + fillMCParticleHistograms(particle, doEl); + fillMCParticleHistograms(particle, doMu); + fillMCParticleHistograms(particle, doPi); + fillMCParticleHistograms(particle, doKa); + fillMCParticleHistograms(particle, doPr); + fillMCParticleHistograms(particle, doDe); + fillMCParticleHistograms(particle, doTr); + fillMCParticleHistograms(particle, doHe); + fillMCParticleHistograms(particle, doAl); + }); + } + } /// end loop over reconstructed collisions + + // skip generated collisions outside the allowed vtx-z range + // putting this condition here avoids the particle loop a few lines below + if (applyPvZCutGenColl) { + const float genPvZ = mcCollision.posZ(); + if (genPvZ < vertexZMin || genPvZ > vertexZMax) { + continue; + } } - if (!isInAcceptance(mcParticle, HIST("MC/particleSelection"))) { - continue; + + // Loop on particles to fill the denominator + float dNdEta = 0; // Multiplicity + for (const auto& mcParticle : groupedMcParticles) { + if (TMath::Abs(mcParticle.eta()) <= 2.f && !mcParticle.has_daughters()) { + dNdEta += 1.f; + } + if (!isInAcceptance(mcParticle, HIST("MC/particleSelection"))) { + continue; + } + + // search for particles from HF decays + if (keepOnlyHfParticles && !RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, /*searchUpToQuark*/ true)) { + continue; + } + + static_for<0, 1>([&](auto pdgSign) { + fillMCParticleHistograms(mcParticle, doEl); + fillMCParticleHistograms(mcParticle, doMu); + fillMCParticleHistograms(mcParticle, doPi); + fillMCParticleHistograms(mcParticle, doKa); + fillMCParticleHistograms(mcParticle, doPr); + fillMCParticleHistograms(mcParticle, doDe); + fillMCParticleHistograms(mcParticle, doTr); + fillMCParticleHistograms(mcParticle, doHe); + fillMCParticleHistograms(mcParticle, doAl); + }); } + histos.fill(HIST("MC/eventMultiplicity"), dNdEta * 0.5f / 2.f); + // Fill TEfficiencies static_for<0, 1>([&](auto pdgSign) { - fillMCParticleHistograms(mcParticle, doEl); - fillMCParticleHistograms(mcParticle, doMu); - fillMCParticleHistograms(mcParticle, doPi); - fillMCParticleHistograms(mcParticle, doKa); - fillMCParticleHistograms(mcParticle, doPr); - fillMCParticleHistograms(mcParticle, doDe); - fillMCParticleHistograms(mcParticle, doTr); - fillMCParticleHistograms(mcParticle, doHe); - fillMCParticleHistograms(mcParticle, doAl); + fillMCEfficiency(doEl); + fillMCEfficiency(doMu); + fillMCEfficiency(doPi); + fillMCEfficiency(doKa); + fillMCEfficiency(doPr); + fillMCEfficiency(doDe); + fillMCEfficiency(doTr); + fillMCEfficiency(doHe); + fillMCEfficiency(doAl); }); - } - histos.fill(HIST("MC/eventMultiplicity"), dNdEta * 0.5f / 2.f); - - // Fill TEfficiencies - static_for<0, 1>([&](auto pdgSign) { - fillMCEfficiency(doEl); - fillMCEfficiency(doMu); - fillMCEfficiency(doPi); - fillMCEfficiency(doKa); - fillMCEfficiency(doPr); - fillMCEfficiency(doDe); - fillMCEfficiency(doTr); - fillMCEfficiency(doHe); - fillMCEfficiency(doAl); - }); + } /// end loop over generated collisions } PROCESS_SWITCH(QaEfficiency, processMC, "process MC", false); // MC process without the collision association - void processMCWithoutCollisions(o2::soa::Join const& tracks, - o2::aod::McParticles const& mcParticles) + // Single-track efficiency calculated: + // - considering also MC collisions without any reco. collision + // - considering also tracks not associated to any collision + // - ignoring the track-to-collision association + void processMCWithoutCollisions(TrackCandidatesMC const& tracks, + o2::aod::Collisions const&, + o2::aod::McParticles const& mcParticles, + o2::aod::McCollisions const&) { // Track loop for (const auto& track : tracks) { if (!isTrackSelected(track, HIST("MC/trackSelection"))) { continue; } + + /// checking the PV z coordinate, if the track has been assigned to any collision + if (applyPvZCutInProcessMcWoColl && track.has_collision()) { + const auto collision = track.collision(); + const float posZ = collision.posZ(); + if (posZ < vertexZMin || posZ > vertexZMax) { + continue; + } + } + + // search for particles from HF decays + // no need to check if track.has_mcParticle() == true, this is done already in isTrackSelected + const auto& particle = track.mcParticle(); + if (keepOnlyHfParticles && !RecoDecay::getCharmHadronOrigin(mcParticles, particle, /*searchUpToQuark*/ true)) { + continue; + } + // Filling variable histograms histos.fill(HIST("MC/trackLength"), track.length()); static_for<0, 1>([&](auto pdgSign) { @@ -1806,6 +2020,20 @@ struct QaEfficiency { continue; } + /// checking the PV z coordinate for the generated collision + if (applyPvZCutInProcessMcWoColl && applyPvZCutGenColl) { + const auto mcCollision = mcParticle.mcCollision(); + const float posZ = mcCollision.posZ(); + if (posZ < vertexZMin || posZ > vertexZMax) { + continue; + } + } + + // search for particles from HF decays + if (keepOnlyHfParticles && !RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, /*searchUpToQuark*/ true)) { + continue; + } + static_for<0, 1>([&](auto pdgSign) { fillMCParticleHistograms(mcParticle, doEl); fillMCParticleHistograms(mcParticle, doMu); @@ -1834,7 +2062,7 @@ struct QaEfficiency { } PROCESS_SWITCH(QaEfficiency, processMCWithoutCollisions, "process MC without the collision association", false); - void processData(o2::soa::Join::iterator const& collision, + void processData(CollisionCandidates::iterator const& collision, TrackCandidates const& tracks) { @@ -1849,83 +2077,131 @@ struct QaEfficiency { histos.fill(HIST("Data/trackLength"), track.length()); + float trackPt = track.pt(); + float trackEta = track.eta(); + float trackPhi = track.phi(); + float trackSign = track.sign(); + float occupancy{}; + float centrality{}; + if (doOccupancy) { + centrality = collision.centFT0C(); + if (useFT0OccEstimator) { + /// occupancy estimator (FT0c signal amplitudes in +-10us from current collision) + occupancy = collision.ft0cOccupancyInTimeRange(); + } else { + /// occupancy estimator (ITS tracks with at least 5 clusters in +-10us from current collision) + occupancy = static_cast(collision.trackOccupancyInTimeRange()); + } + } if (passedITS) { - if (track.sign() > 0) { - histos.fill(HIST("Data/pos/pt/its"), track.pt()); - histos.fill(HIST("Data/pos/eta/its"), track.eta()); - histos.fill(HIST("Data/pos/phi/its"), track.phi()); - histos.fill(HIST("Data/pos/etaphi/its"), track.eta(), track.phi()); + if (trackSign > 0) { + histos.fill(HIST("Data/pos/pt/its"), trackPt); + histos.fill(HIST("Data/pos/eta/its"), trackEta); + histos.fill(HIST("Data/pos/phi/its"), trackPhi); + histos.fill(HIST("Data/pos/etaphi/its"), trackEta, trackPhi); + + if (doOccupancy) { + histos.fill(HIST("Data/occ_cent/pos/its"), occupancy, centrality, trackPt); + } } else { - histos.fill(HIST("Data/neg/pt/its"), track.pt()); - histos.fill(HIST("Data/neg/eta/its"), track.eta()); - histos.fill(HIST("Data/neg/phi/its"), track.phi()); - histos.fill(HIST("Data/neg/etaphi/its"), track.eta(), track.phi()); + histos.fill(HIST("Data/neg/pt/its"), trackPt); + histos.fill(HIST("Data/neg/eta/its"), trackEta); + histos.fill(HIST("Data/neg/phi/its"), trackPhi); + histos.fill(HIST("Data/neg/etaphi/its"), trackEta, trackPhi); + + if (doOccupancy) { + histos.fill(HIST("Data/occ_cent/neg/its"), occupancy, centrality, trackPt); + } } } if (passedTPC) { - if (track.sign() > 0) { - histos.fill(HIST("Data/pos/pt/tpc"), track.pt()); - histos.fill(HIST("Data/pos/eta/tpc"), track.eta()); - histos.fill(HIST("Data/pos/phi/tpc"), track.phi()); - histos.fill(HIST("Data/pos/etaphi/tpc"), track.eta(), track.phi()); + if (trackSign > 0) { + histos.fill(HIST("Data/pos/pt/tpc"), trackPt); + histos.fill(HIST("Data/pos/eta/tpc"), trackEta); + histos.fill(HIST("Data/pos/phi/tpc"), trackPhi); + histos.fill(HIST("Data/pos/etaphi/tpc"), trackEta, trackPhi); + + if (doOccupancy) { + histos.fill(HIST("Data/occ_cent/pos/tpc"), occupancy, centrality, trackPt); + } } else { - histos.fill(HIST("Data/neg/pt/tpc"), track.pt()); - histos.fill(HIST("Data/neg/eta/tpc"), track.eta()); - histos.fill(HIST("Data/neg/phi/tpc"), track.phi()); - histos.fill(HIST("Data/neg/etaphi/tpc"), track.eta(), track.phi()); + histos.fill(HIST("Data/neg/pt/tpc"), trackPt); + histos.fill(HIST("Data/neg/eta/tpc"), trackEta); + histos.fill(HIST("Data/neg/phi/tpc"), trackPhi); + histos.fill(HIST("Data/neg/etaphi/tpc"), trackEta, trackPhi); + + if (doOccupancy) { + histos.fill(HIST("Data/occ_cent/neg/tpc"), occupancy, centrality, trackPt); + } } } if (passedITS && passedTPC) { - if (track.sign() > 0) { - histos.fill(HIST("Data/pos/pt/its_tpc"), track.pt()); - histos.fill(HIST("Data/pos/eta/its_tpc"), track.eta()); - histos.fill(HIST("Data/pos/phi/its_tpc"), track.phi()); - histos.fill(HIST("Data/pos/etaphi/its_tpc"), track.eta(), track.phi()); + if (trackSign > 0) { + histos.fill(HIST("Data/pos/pt/its_tpc"), trackPt); + histos.fill(HIST("Data/pos/eta/its_tpc"), trackEta); + histos.fill(HIST("Data/pos/phi/its_tpc"), trackPhi); + histos.fill(HIST("Data/pos/etaphi/its_tpc"), trackEta, trackPhi); + + if (doOccupancy) { + histos.fill(HIST("Data/occ_cent/pos/its_tpc"), occupancy, centrality, trackPt); + } } else { - histos.fill(HIST("Data/neg/pt/its_tpc"), track.pt()); - histos.fill(HIST("Data/neg/eta/its_tpc"), track.eta()); - histos.fill(HIST("Data/neg/phi/its_tpc"), track.phi()); - histos.fill(HIST("Data/neg/etaphi/its_tpc"), track.eta(), track.phi()); + histos.fill(HIST("Data/neg/pt/its_tpc"), trackPt); + histos.fill(HIST("Data/neg/eta/its_tpc"), trackEta); + histos.fill(HIST("Data/neg/phi/its_tpc"), trackPhi); + histos.fill(HIST("Data/neg/etaphi/its_tpc"), trackEta, trackPhi); + + if (doOccupancy) { + histos.fill(HIST("Data/occ_cent/neg/its_tpc"), occupancy, centrality, trackPt); + } } } if (passedITS && passedTPC && passedTOF) { - if (track.sign() > 0) { - histos.fill(HIST("Data/pos/pt/its_tpc_tof"), track.pt()); - histos.fill(HIST("Data/pos/eta/its_tpc_tof"), track.eta()); - histos.fill(HIST("Data/pos/phi/its_tpc_tof"), track.phi()); - histos.fill(HIST("Data/pos/etaphi/its_tpc_tof"), track.eta(), track.phi()); + if (trackSign > 0) { + histos.fill(HIST("Data/pos/pt/its_tpc_tof"), trackPt); + histos.fill(HIST("Data/pos/eta/its_tpc_tof"), trackEta); + histos.fill(HIST("Data/pos/phi/its_tpc_tof"), trackPhi); + histos.fill(HIST("Data/pos/etaphi/its_tpc_tof"), trackEta, trackPhi); + + if (doOccupancy) { + histos.fill(HIST("Data/occ_cent/pos/its_tpc_tof"), occupancy, centrality, trackPt); + } } else { - histos.fill(HIST("Data/neg/pt/its_tpc_tof"), track.pt()); - histos.fill(HIST("Data/neg/eta/its_tpc_tof"), track.eta()); - histos.fill(HIST("Data/neg/phi/its_tpc_tof"), track.phi()); - histos.fill(HIST("Data/neg/etaphi/its_tpc_tof"), track.eta(), track.phi()); + histos.fill(HIST("Data/neg/pt/its_tpc_tof"), trackPt); + histos.fill(HIST("Data/neg/eta/its_tpc_tof"), trackEta); + histos.fill(HIST("Data/neg/phi/its_tpc_tof"), trackPhi); + histos.fill(HIST("Data/neg/etaphi/its_tpc_tof"), trackEta, trackPhi); + + if (doOccupancy) { + histos.fill(HIST("Data/occ_cent/neg/its"), occupancy, centrality, trackPt); + } } } if (makeEff) { if (passedITS) { - effITSTPCMatchingVsPt->Fill(passedTPC, track.pt()); + effITSTPCMatchingVsPt->Fill(passedTPC, trackPt); } if (passedTPC) { - effTPCITSMatchingVsPt->Fill(passedITS, track.pt()); + effTPCITSMatchingVsPt->Fill(passedITS, trackPt); } if (passedITS && passedTPC) { - effTPCTOFMatchingVsPt->Fill(passedTOF, track.pt()); + effTPCTOFMatchingVsPt->Fill(passedTOF, trackPt); effTPCTOFMatchingVsP->Fill(passedTOF, track.p()); - effTPCTOFMatchingVsEta->Fill(passedTOF, track.eta()); - effTPCTOFMatchingVsPhi->Fill(passedTOF, track.phi()); - effTPCTOFMatchingVsPtVsEta->Fill(passedTOF, track.pt(), track.eta()); - effTPCTOFMatchingVsPtVsPhi->Fill(passedTOF, track.pt(), track.phi()); + effTPCTOFMatchingVsEta->Fill(passedTOF, trackEta); + effTPCTOFMatchingVsPhi->Fill(passedTOF, trackPhi); + effTPCTOFMatchingVsPtVsEta->Fill(passedTOF, trackPt, trackEta); + effTPCTOFMatchingVsPtVsPhi->Fill(passedTOF, trackPt, trackPhi); } } } } PROCESS_SWITCH(QaEfficiency, processData, "process data", true); - void processDataWithPID(o2::soa::Join::iterator const& collision, + void processDataWithPID(CollisionCandidates::iterator const& collision, o2::soa::Join const& tracks) { @@ -1937,7 +2213,7 @@ struct QaEfficiency { if (!isTrackSelected(track, HIST("Data/trackSelection"))) { continue; } - if (abs(track.tpcNSigmaDe()) > nsigmaTPCDe) { + if (std::abs(track.tpcNSigmaDe()) > nsigmaTPCDe) { continue; } histos.fill(HIST("Data/trackLength"), track.length()); @@ -2018,8 +2294,7 @@ struct QaEfficiency { } PROCESS_SWITCH(QaEfficiency, processDataWithPID, "process data with PID", false); - void processHmpid(o2::soa::Join::iterator const& collision, - TrackCandidates const&, + void processHmpid(CollisionCandidates::iterator const& collision, TrackCandidates const&, o2::aod::HMPIDs const& hmpids) { @@ -2051,7 +2326,4 @@ struct QaEfficiency { PROCESS_SWITCH(QaEfficiency, processHmpid, "process HMPID matching", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/DPG/Tasks/AOTTrack/qaEventTrack.cxx b/DPG/Tasks/AOTTrack/qaEventTrack.cxx index 52ad175aab9..ffb64e1f9c2 100644 --- a/DPG/Tasks/AOTTrack/qaEventTrack.cxx +++ b/DPG/Tasks/AOTTrack/qaEventTrack.cxx @@ -27,6 +27,7 @@ #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisDataModel.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "ReconstructionDataFormats/DCA.h" #include "Common/Core/trackUtilities.h" #include "Common/DataModel/EventSelection.h" @@ -53,6 +54,9 @@ using namespace o2::dataformats; struct qaEventTrack { SliceCache cache; + // for particle charges + Service pdgDB; + // general steering settings Configurable isRun3{"isRun3", true, "Is Run3 dataset"}; // TODO: derive this from metadata once possible to get rid of the flag Configurable overwriteAxisRangeForPbPb{"overwriteAxisRangeForPbPb", false, "Global switch to easily set the most relaxed default axis ranges of multiplicity and PVcontribs for PbPb"}; @@ -76,19 +80,32 @@ struct qaEventTrack { Configurable maxEta{"maxEta", 2.0f, "Maximum eta of accepted tracks"}; Configurable minPhi{"minPhi", -1.f, "Minimum phi of accepted tracks"}; Configurable maxPhi{"maxPhi", 10.f, "Maximum phi of accepted tracks"}; + Configurable minTPCcrossedRows{"minTPCcrossedRows", 70, "Minimum number of TPC crossed rows of accepted tracks"}; - // option to check PID for tracking before filling resolution histogras + // option to check PID for tracking before filling resolution histograms Configurable checkPIDforTracking{"checkPIDforTracking", false, "check for PID in tracking"}; Configurable PartIdentifier{"PartIdentifier", 2, "Particle identifier for selected particle; 0: electron, 1: muon, 2: pion, 3: kaon, 4: proton, 5: deuteron, 6: triton, 7: helium3, 8: alpha"}; Configurable doExtraPIDqa{"doExtraPIDqa", false, "do extra QA for tracks with wrong PID in tracking"}; + // option to check for fake matches before filling resolution histograms + Configurable checkFakeMatches{"checkFakeMatches", false, "flag to check for fake matched tracks (and exclude them)"}; + // options to check the track variables only for PV contributors Configurable checkOnlyPVContributor{"checkOnlyPVContributor", false, "check the track variables only for primary vertex contributors"}; + // options to force or not the presence of TRD (debug) + struct : ConfigurableGroup { + Configurable activateChecksTRD{"activateChecksTRD", false, "Activate the checks wityh TRD - force the track to have or not have TRD"}; + Configurable forceTRD{"forceTRD", false, "Force the track to have TRD"}; + Configurable forceNotTRD{"forceNotTRD", false, "Force the track not to have TRD"}; + } checksTRD; + // configurable binning of histograms ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 2.0, 5.0, 10.0, 20.0, 50.0}, ""}; ConfigurableAxis binsInvPt{"binsInvPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 2.0, 5.0, 10.0, 20.0, 50.0}, ""}; + ConfigurableAxis binsSigned1Pt{"binsSigned1Pt", {300, -5., 5.}, ""}; ConfigurableAxis binsDeltaPt{"binsDeltaPt", {100, -0.495, 0.505}, ""}; + ConfigurableAxis binsDeltaSigned1Pt{"binsDeltaSigned1Pt", {100, -0.495, 0.505}, ""}; ConfigurableAxis binsVertexPosZ{"binsVertexPosZ", {100, -20., 20.}, ""}; // TODO: do we need this to be configurable? ConfigurableAxis binsVertexPosXY{"binsVertexPosXY", {500, -1., 1.}, ""}; // TODO: do we need this to be configurable? @@ -105,7 +122,7 @@ struct qaEventTrack { ((trackSelection.node() == 6) && requireGlobalTrackWoTPCClusterInFilter()) || ((trackSelection.node() == 7) && requireGlobalTrackWoDCATPCClusterInFilter()); - using TrackIUTable = soa::Join; + using TrackIUTable = soa::Join; Partition tracksIUFiltered = (trackSelection.node() == 0) || ((trackSelection.node() == 1) && requireGlobalTrackInFilter()) || ((trackSelection.node() == 2) && requireGlobalTrackWoPtEtaInFilter()) || @@ -142,6 +159,13 @@ struct qaEventTrack { return; } + if (checksTRD.activateChecksTRD) { + std::array casesTRD = {checksTRD.forceTRD, checksTRD.forceNotTRD}; + if (std::accumulate(casesTRD.begin(), casesTRD.end(), 0) != 1) { + LOGP(fatal, "One and only one case between forceTRD and forceNotTRD can be true at a time. Fix it!"); + } + } + // // Next section setups overwrite of configurableAxis if overwriteAxisRangeForPbPb is used. // @@ -179,6 +203,7 @@ struct qaEventTrack { const AxisSpec axisPt{binsPt, "#it{p}_{T} [GeV/c]"}; const AxisSpec axisInvPt{binsInvPt, "1/#it{p}_{T, gen} [GeV/c]^{-1}"}; + const AxisSpec axisSigned1Pt{binsSigned1Pt, "Q/#it{p}_{T, gen} [GeV/c]^{-1}"}; const AxisSpec axisEta{180, -0.9, 0.9, "#it{#eta}"}; const AxisSpec axisPhi{180, 0., 2 * M_PI, "#it{#varphi} [rad]"}; const AxisSpec axisVertexNumContrib{(overwriteAxisRangeForPbPb ? vecBinsVertexNumContribDefaultPbPb : vecBinsVertexNumContrib), "Number Of contributors to the PV"}; @@ -192,13 +217,16 @@ struct qaEventTrack { const AxisSpec axisParY{200, -0.5, 0.5, "#it{y} [cm]"}; const AxisSpec axisParZ{200, -11., 11., "#it{z} [cm]"}; const AxisSpec axisParAlpha{36, -M_PI, M_PI, "#alpha [rad]"}; - const AxisSpec axisParSigned1Pt{200, -8, 8, "#it{q}/#it{p}_{T}"}; + const AxisSpec axisParSigned1Pt{500, -8, 8, "#it{q}/#it{p}_{T}"}; const AxisSpec axisParSnp{11, -0.1, 0.1, "snp"}; const AxisSpec axisParTgl{200, -1., 1., "tgl"}; + const AxisSpec axisSign{2, -2., 2., "sign"}; const AxisSpec axisDeltaPt{binsDeltaPt, "#it{p}_{T, rec} - #it{p}_{T, gen} [GeV/c]"}; const AxisSpec axisDeltaPtScaled{binsDeltaPt, "(#it{p}_{T, rec} - #it{p}_{T, gen}) / #it{p}_{T, gen}"}; const AxisSpec axisDeltaInvPt{binsDeltaPt, "1/#it{p}_{T, rec} - 1/#it{p}_{T, gen} [GeV/c]^{-1}"}; + const AxisSpec axisDeltaSigned1Pt{binsDeltaSigned1Pt, "Q/#it{p}_{T, rec} - Q/#it{p}_{T, gen} [GeV/c]^{-1}"}; + const AxisSpec axisDeltaSigned1PtScaled{binsDeltaSigned1Pt, "(Q/#it{p}_{T, rec} - Q/#it{p}_{T, gen}) / Q/#it{p}_{T, gen}"}; const AxisSpec axisPullInvPt{100, -4., 4., "(1/#it{p}_{T, rec} - 1/#it{p}_{T, gen})/#sigma_{1/#it{p}_{T}}"}; const AxisSpec axisDeltaEta{100, -0.1, 0.1, "#eta_{rec} - #eta_{gen}"}; const AxisSpec axisDeltaPhi{100, -0.1, 0.1, "#varphi_{rec} - #varphi_{gen}"}; @@ -254,31 +282,39 @@ struct qaEventTrack { histos.add("Tracks/Kine/etavspt", "#eta vs #it{p}_{T}", kTH2F, {axisPt, axisEta}); histos.add("Tracks/Kine/phivspt", "#varphi vs #it{p}_{T}", kTH2F, {axisPt, axisPhi}); if (doprocessMC || doprocessRun2ConvertedMC) { - histos.add("Tracks/Kine/resoPt", "", kTH2D, {axisDeltaPt, axisPt}); + // pT resolution + histos.add("Tracks/Kine/resoPt", "", kTH3D, {axisDeltaPt, axisPt, axisSign}); histos.add("Tracks/Kine/resoPtEtaPlus", "", kTH2D, {axisDeltaPt, axisPt}); histos.add("Tracks/Kine/resoPtEtaMinus", "", kTH2D, {axisDeltaPt, axisPt}); - histos.add("Tracks/Kine/resoPtVsptmc", "", kTH2D, {axisDeltaPt, axisPt})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); + histos.add("Tracks/Kine/resoPtVsptmc", "", kTH3D, {axisDeltaPt, axisPt, axisSign})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); histos.add("Tracks/Kine/resoPtVsptmcEtaPlus", "", kTH2D, {axisDeltaPt, axisPt})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); histos.add("Tracks/Kine/resoPtVsptmcEtaMinus", "", kTH2D, {axisDeltaPt, axisPt})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); - histos.add("Tracks/Kine/resoPtVsptmcScaled", "", kTH2D, {axisDeltaPtScaled, axisPt})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); + histos.add("Tracks/Kine/resoPtVsptmcScaled", "", kTH3D, {axisDeltaPtScaled, axisPt, axisSign})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); histos.add("Tracks/Kine/resoPtVsptmcScaledEtaPlus", "", kTH2D, {axisDeltaPtScaled, axisPt})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); histos.add("Tracks/Kine/resoPtVsptmcScaledEtaMinus", "", kTH2D, {axisDeltaPtScaled, axisPt})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); - histos.add("Tracks/Kine/pullInvPtVsInvPtmc", "", kTH2D, {axisPullInvPt, axisInvPt}); + histos.add("Tracks/Kine/ptVsptmc", "", kTH2D, {axisPt, axisPt})->GetXaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); + // 1/pT resolution + histos.add("Tracks/Kine/resoInvPt", "", kTH3D, {axisDeltaInvPt, axisInvPt, axisSign}); + histos.add("Tracks/Kine/resoInvPtEtaPlus", "", kTH2D, {axisDeltaInvPt, axisInvPt}); + histos.add("Tracks/Kine/resoInvPtEtaMinus", "", kTH2D, {axisDeltaInvPt, axisInvPt}); + histos.add("Tracks/Kine/resoInvPtVsPt", "", kTH3D, {axisDeltaInvPt, axisPt, axisSign})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); + histos.add("Tracks/Kine/resoInvPtVsPtEtaPlus", "", kTH2D, {axisDeltaInvPt, axisPt})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); + histos.add("Tracks/Kine/resoInvPtVsPtEtaMinus", "", kTH2D, {axisDeltaInvPt, axisPt})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); + histos.add("Tracks/Kine/resoInvPtVsPtScaled", "", kTH3D, {axisDeltaInvPt, axisPt, axisSign})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); + // signed 1/pT resolution + histos.add("Tracks/Kine/resoSigned1Pt", "", kTH3D, {axisDeltaSigned1Pt, axisSigned1Pt, axisSign}); + histos.add("Tracks/Kine/resoSigned1PtVsPt", "", kTH3D, {axisDeltaSigned1Pt, axisPt, axisSign})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); + histos.add("Tracks/Kine/resoSigned1PtScaled", "", kTH3D, {axisDeltaSigned1PtScaled, axisSigned1Pt, axisSign}); + histos.add("Tracks/Kine/resoSigned1PtVsPtScaled", "", kTH3D, {axisDeltaSigned1PtScaled, axisPt, axisSign})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); + histos.add("Tracks/Kine/Signed1PtVsSigned1Ptmc", "", kTH2D, {axisSigned1Pt, axisSigned1Pt})->GetYaxis()->SetTitle("Q/#it{p}_{T, rec} [GeV/c]^{-1}"); + // 1/pT pull + histos.add("Tracks/Kine/pullInvPtVsInvPtmc", "", kTH3D, {axisPullInvPt, axisInvPt, axisSign}); histos.add("Tracks/Kine/pullInvPtVsInvPtmcEtaPlus", "", kTH2D, {axisPullInvPt, axisInvPt}); histos.add("Tracks/Kine/pullInvPtVsInvPtmcEtaMinus", "", kTH2D, {axisPullInvPt, axisInvPt}); - histos.add("Tracks/Kine/pullInvPtVsPtmc", "", kTH2D, {axisPullInvPt, axisPt})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); + histos.add("Tracks/Kine/pullInvPtVsPtmc", "", kTH3D, {axisPullInvPt, axisPt, axisSign})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); histos.add("Tracks/Kine/pullInvPtVsPtmcEtaPlus", "", kTH2D, {axisPullInvPt, axisPt})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); histos.add("Tracks/Kine/pullInvPtVsPtmcEtaMinus", "", kTH2D, {axisPullInvPt, axisPt})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); - histos.add("Tracks/Kine/resoInvPtVsPt", "", kTH2D, {axisDeltaInvPt, axisPt})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); - histos.add("Tracks/Kine/resoInvPtVsPtEtaPlus", "", kTH2D, {axisDeltaInvPt, axisPt})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); - histos.add("Tracks/Kine/resoInvPtVsPtEtaMinus", "", kTH2D, {axisDeltaInvPt, axisPt})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); - histos.add("Tracks/Kine/resoInvPt", "", kTH2D, {axisDeltaInvPt, axisInvPt}); - histos.add("Tracks/Kine/resoInvPtEtaPlus", "", kTH2D, {axisDeltaInvPt, axisInvPt}); - histos.add("Tracks/Kine/resoInvPtEtaMinus", "", kTH2D, {axisDeltaInvPt, axisInvPt}); - histos.add("Tracks/Kine/ptVsptmc", "", kTH2D, {axisPt, axisPt})->GetXaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); - histos.add("Tracks/Kine/resoEta", "", kTH2D, {axisDeltaEta, axisEta})->GetYaxis()->SetTitle("#eta_{rec}"); - histos.add("Tracks/Kine/resoPhi", "", kTH2D, {axisDeltaPhi, axisPhi})->GetYaxis()->SetTitle("#varphi_{rec}"); - + // wrong PID hypthesis histos.add("Tracks/Kine/resoPtVsptmcWrongPIDinTrk", "", kTH2D, {axisDeltaPt, axisPt})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); histos.add("Tracks/Kine/resoPtVsptmcEtaPlusWrongPIDinTrk", "", kTH2D, {axisDeltaPt, axisPt})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); histos.add("Tracks/Kine/resoPtVsptmcEtaMinusWrongPIDinTrk", "", kTH2D, {axisDeltaPt, axisPt})->GetYaxis()->SetTitle("#it{p}_{T, gen} [GeV/c]"); @@ -297,6 +333,9 @@ struct qaEventTrack { histos.add("Tracks/Kine/resoInvPtWrongPIDinTrk", "", kTH2D, {axisDeltaInvPt, axisInvPt}); histos.add("Tracks/Kine/resoInvPtEtaPlusWrongPIDinTrk", "", kTH2D, {axisDeltaInvPt, axisInvPt}); histos.add("Tracks/Kine/resoInvPtEtaMinusWrongPIDinTrk", "", kTH2D, {axisDeltaInvPt, axisInvPt}); + // eta, phi + histos.add("Tracks/Kine/resoEta", "", kTH2D, {axisDeltaEta, axisEta})->GetYaxis()->SetTitle("#eta_{rec}"); + histos.add("Tracks/Kine/resoPhi", "", kTH2D, {axisDeltaPhi, axisPhi})->GetYaxis()->SetTitle("#varphi_{rec}"); } histos.add("Tracks/Kine/relativeResoPt", "relative #it{p}_{T} resolution; #it{p}_{T}; #sigma(#it{p}_{T})/#it{p}_{T}", kTH2D, {{axisPt, {100, 0., 0.3}}}); histos.add("Tracks/Kine/relativeResoPtEtaPlus", "relative #it{p}_{T} resolution positive #eta; #it{p}_{T}; #sigma(#it{p}_{T})/#it{p}_{T} (#eta>0)", kTH2D, {{axisPt, {100, 0., 0.3}}}); @@ -443,6 +482,9 @@ struct qaEventTrack { histos.add("Tracks/TPC/tpcCrossedRowsOverFindableCls", "crossed TPC rows over findable clusters;crossed rows / findable clusters TPC", kTH1D, {{60, 0.7, 1.3}}); histos.add("Tracks/TPC/tpcChi2NCl", "chi2 per cluster in TPC;chi2 / cluster TPC", kTH1D, {{100, 0, 10}}); histos.add("Tracks/TPC/hasTPC", "pt distribution of tracks crossing TPC", kTH1D, {axisPt}); + auto h6 = histos.add("Tracks/TPC/tpcdEdxVsTPCmom", "Energy loss", kTH2D, {axisParSigned1Pt, {500, 0., 1000.}}); + h6->GetXaxis()->SetTitle("#it{p}_{TPC}/z (GeV/#it{c})"); + h6->GetYaxis()->SetTitle("dE/dx"); // tracks vs tracks @ IU if (doprocessDataIU) { @@ -622,6 +664,9 @@ struct qaEventTrack { if (track.phi() < minPhi || track.phi() > maxPhi) { // Extra Phi selection return false; } + if (track.tpcNClsCrossedRows() < minTPCcrossedRows) { // Extra TPC crossed rows selection + return false; + } if (selectCharge && (selectCharge != track.sign())) { return false; } @@ -1467,6 +1512,17 @@ void qaEventTrack::fillRecoHistogramsGroupedTracks(const C& collision, const T& if (!isSelectedTrack(track)) { continue; } + // TRD checks (debug) + if (checksTRD.activateChecksTRD) { + if (checksTRD.forceTRD && !track.hasTRD()) { + /// We want only tracks that match TRD, but the current one does not match it. Let's skip it. + continue; + } + if (checksTRD.forceNotTRD && track.hasTRD()) { + /// We want only tracks that do not match TRD, but the current one matches it. Let's skip it. + continue; + } + } // fill kinematic variables histos.fill(HIST("Tracks/Kine/pt"), track.pt()); if (track.sign() > 0) { @@ -1556,8 +1612,13 @@ void qaEventTrack::fillRecoHistogramsGroupedTracks(const C& collision, const T& if constexpr (IS_MC) { if (track.has_mcParticle()) { auto particle = track.mcParticle(); + auto pdgInfo = pdgDB->GetParticle(particle.pdgCode()); + int sign = 0; + if (pdgInfo != nullptr) { + sign = pdgInfo->Charge() / abs(pdgInfo->Charge()); + } // resolution plots - if (doExtraPIDqa && track.pidForTracking() != std::abs(PartIdentifier)) { + if (doExtraPIDqa && track.pidForTracking() != static_cast(std::abs(PartIdentifier))) { // full eta range histos.fill(HIST("Tracks/Kine/resoPtVsptmcWrongPIDinTrk"), track.pt() - particle.pt(), particle.pt()); histos.fill(HIST("Tracks/Kine/resoPtVsptmcScaledWrongPIDinTrk"), (track.pt() - particle.pt()) / particle.pt(), particle.pt()); @@ -1589,24 +1650,50 @@ void qaEventTrack::fillRecoHistogramsGroupedTracks(const C& collision, const T& } } - // optionally check for PID in tracking - if (checkPIDforTracking && track.pidForTracking() != std::abs(PartIdentifier)) { + // optionally check for PID in tracking: select tracks with correct PID in tracking + if (checkPIDforTracking && track.pidForTracking() != static_cast(std::abs(PartIdentifier))) { continue; } + // optionally check for fake matches: select tracks with no fake hits + if (checkFakeMatches) { // Selecting tracks with no fake hits + bool hasFakeHit = false; + for (int i = 0; i < 10; i++) { // From ITS to TPC + if (track.mcMask() & 1 << i) { + hasFakeHit = true; + break; + } + } + if (hasFakeHit) { + continue; + } + } + + // TPC energy loss + histos.fill(HIST("Tracks/TPC/tpcdEdxVsTPCmom"), track.tpcInnerParam() / track.sign(), track.tpcSignal()); + + // Kine plots // full eta range - histos.fill(HIST("Tracks/Kine/resoPt"), track.pt() - particle.pt(), track.pt()); - histos.fill(HIST("Tracks/Kine/resoPtVsptmc"), track.pt() - particle.pt(), particle.pt()); - histos.fill(HIST("Tracks/Kine/resoPtVsptmcScaled"), (track.pt() - particle.pt()) / particle.pt(), particle.pt()); - histos.fill(HIST("Tracks/Kine/pullInvPtVsInvPtmc"), (std::abs(track.signed1Pt()) - 1.f / particle.pt()) / std::sqrt(track.c1Pt21Pt2()), 1.f / particle.pt()); - histos.fill(HIST("Tracks/Kine/pullInvPtVsPtmc"), (std::abs(track.signed1Pt()) - 1.f / particle.pt()) / std::sqrt(track.c1Pt21Pt2()), particle.pt()); + histos.fill(HIST("Tracks/Kine/resoPt"), track.pt() - particle.pt(), track.pt(), track.sign()); + histos.fill(HIST("Tracks/Kine/resoPtVsptmc"), track.pt() - particle.pt(), particle.pt(), track.sign()); + histos.fill(HIST("Tracks/Kine/resoPtVsptmcScaled"), (track.pt() - particle.pt()) / particle.pt(), particle.pt(), track.sign()); if (particle.pt() > 0.f) { - histos.fill(HIST("Tracks/Kine/resoInvPt"), std::abs(track.signed1Pt()) - 1.f / particle.pt(), 1.f / particle.pt()); + histos.fill(HIST("Tracks/Kine/resoInvPt"), std::abs(track.signed1Pt()) - 1.f / particle.pt(), 1.f / particle.pt(), track.sign()); + histos.fill(HIST("Tracks/Kine/resoInvPtVsPt"), std::abs(track.signed1Pt()) - 1.f / particle.pt(), particle.pt(), track.sign()); + histos.fill(HIST("Tracks/Kine/resoInvPtVsPtScaled"), (std::abs(track.signed1Pt()) - 1.f / particle.pt()) / (1.f / particle.pt()), particle.pt(), track.sign()); + histos.fill(HIST("Tracks/Kine/resoSigned1Pt"), track.signed1Pt() - sign / particle.pt(), sign / particle.pt(), track.sign()); + histos.fill(HIST("Tracks/Kine/resoSigned1PtVsPt"), track.signed1Pt() - sign / particle.pt(), particle.pt(), track.sign()); + histos.fill(HIST("Tracks/Kine/resoSigned1PtScaled"), (track.signed1Pt() - sign / particle.pt()) / (sign / particle.pt()), sign / particle.pt(), track.sign()); + histos.fill(HIST("Tracks/Kine/resoSigned1PtVsPtScaled"), (track.signed1Pt() - sign / particle.pt()) / (sign / particle.pt()), particle.pt(), track.sign()); } - histos.fill(HIST("Tracks/Kine/resoInvPtVsPt"), track.signed1Pt() - 1.f / particle.pt(), particle.pt()); + histos.fill(HIST("Tracks/Kine/pullInvPtVsInvPtmc"), (std::abs(track.signed1Pt()) - 1.f / particle.pt()) / std::sqrt(track.c1Pt21Pt2()), 1.f / particle.pt(), track.sign()); + histos.fill(HIST("Tracks/Kine/pullInvPtVsPtmc"), (std::abs(track.signed1Pt()) - 1.f / particle.pt()) / std::sqrt(track.c1Pt21Pt2()), particle.pt(), track.sign()); + histos.fill(HIST("Tracks/Kine/ptVsptmc"), particle.pt(), track.pt()); + histos.fill(HIST("Tracks/Kine/Signed1PtVsSigned1Ptmc"), sign / particle.pt(), track.signed1Pt()); histos.fill(HIST("Tracks/Kine/resoEta"), track.eta() - particle.eta(), track.eta()); histos.fill(HIST("Tracks/Kine/resoPhi"), track.phi() - particle.phi(), track.phi()); + // split eta range if (eta > 0) { // positive eta histos.fill(HIST("Tracks/Kine/resoPtEtaPlus"), track.pt() - particle.pt(), track.pt()); diff --git a/DPG/Tasks/AOTTrack/qaEventTrackLiteProducer.cxx b/DPG/Tasks/AOTTrack/qaEventTrackLiteProducer.cxx index e3d0f3f1ec6..0184d5b39f0 100644 --- a/DPG/Tasks/AOTTrack/qaEventTrackLiteProducer.cxx +++ b/DPG/Tasks/AOTTrack/qaEventTrackLiteProducer.cxx @@ -19,6 +19,9 @@ #include "qaEventTrack.h" +#include + +#include "TRandom.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" @@ -38,7 +41,7 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::dataformats; -struct qaEventTrackLiteProducer { +struct QaEventTrackLiteProducer { // Tables to produce Produces tableCollisions; Produces tableCollsBig; @@ -178,7 +181,7 @@ struct qaEventTrackLiteProducer { { fillDerivedTable(collision, tracks, 0, bcs); } - PROCESS_SWITCH(qaEventTrackLiteProducer, processTableData, "Process data for table producing", true); + PROCESS_SWITCH(QaEventTrackLiteProducer, processTableData, "Process data for table producing", true); void processTableMC(CollisionTableMC::iterator const& collision, soa::Filtered> const& tracks, @@ -188,7 +191,7 @@ struct qaEventTrackLiteProducer { { fillDerivedTable(collision, tracks, mcParticles, bcs); } - PROCESS_SWITCH(qaEventTrackLiteProducer, processTableMC, "Process MC for table producing", false); + PROCESS_SWITCH(QaEventTrackLiteProducer, processTableMC, "Process MC for table producing", false); //************************************************************************************************** /** @@ -202,10 +205,10 @@ struct qaEventTrackLiteProducer { if (!isSelectedCollision(collision)) { return; } - if (abs(collision.posZ()) > selectMaxVtxZ) { + if (std::abs(collision.posZ()) > selectMaxVtxZ) { return; } - if (fractionOfSampledEvents < 1.f && (static_cast(rand()) / static_cast(RAND_MAX)) > fractionOfSampledEvents) { // Skip events that are not sampled + if (fractionOfSampledEvents < 1.f && (gRandom->Uniform()) > fractionOfSampledEvents) { // Skip events that are not sampled return; } if (nTableEventCounter > targetNumberOfEvents) { // Skip events if target is reached @@ -310,9 +313,9 @@ struct qaEventTrackLiteProducer { if (nTableEventCounter > targetNumberOfEvents) { // Skip events if target is reached return; } - for (auto& collision : collisions) { + for (const auto& collision : collisions) { - if (fractionOfSampledEvents < 1.f && (static_cast(rand()) / static_cast(RAND_MAX)) > fractionOfSampledEvents) { // Skip events that are not sampled + if (fractionOfSampledEvents < 1.f && (gRandom->Uniform()) > fractionOfSampledEvents) { // Skip events that are not sampled return; } nTableEventCounter++; @@ -407,7 +410,7 @@ struct qaEventTrackLiteProducer { /// Let's update the DF counter counterDF++; } - PROCESS_SWITCH(qaEventTrackLiteProducer, processTableDataCollsBig, "Process data for big collision table producing", false); + PROCESS_SWITCH(QaEventTrackLiteProducer, processTableDataCollsBig, "Process data for big collision table producing", false); /// Processing MC void processTableMCCollsBig(CollsBigTableMC const& collisions, @@ -423,10 +426,10 @@ struct qaEventTrackLiteProducer { /// Let's update the DF counter counterDF++; } - PROCESS_SWITCH(qaEventTrackLiteProducer, processTableMCCollsBig, "Process MC for big collision table producing", false); + PROCESS_SWITCH(QaEventTrackLiteProducer, processTableMCCollsBig, "Process MC for big collision table producing", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/DPG/Tasks/AOTTrack/qaFakeHits.cxx b/DPG/Tasks/AOTTrack/qaFakeHits.cxx new file mode 100644 index 00000000000..1da3a6a6674 --- /dev/null +++ b/DPG/Tasks/AOTTrack/qaFakeHits.cxx @@ -0,0 +1,254 @@ +// 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 qaFakeHits.cxx +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \since 2024-04-08 +/// \brief Task to analyze the fraction of the true and fake hits depending on where the fake hits are picked +/// + +// O2 includes +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StaticFor.h" +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" + +using namespace o2::framework; +// Particle information +static constexpr int nSpecies = o2::track::PID::NIDs; // One per PDG +static constexpr int nCharges = 2; +static constexpr int nParticles = nSpecies * nCharges; +static constexpr const char* particleTitle[nParticles] = {"e", "#mu", "#pi", "K", "p", "d", "t", "^{3}He", "#alpha", + "e", "#mu", "#pi", "K", "p", "d", "t", "^{3}He", "#alpha"}; +static constexpr int PDGs[nParticles] = {11, 13, 211, 321, 2212, 1000010020, 1000010030, 1000020030, 1000020040, + -11, -13, -211, -321, -2212, -1000010020, -1000010030, -1000020030, -1000020040}; +std::array, nParticles> hPtAll; +std::array, nParticles> hPtITS; +std::array, nParticles> hPtTPC; +std::array, nParticles> hPtTRD; +std::array, nParticles> hPtTOF; +std::array, nParticles> hPtOverall; + +struct QaFakeHits { + // Charge selection + Configurable doPositivePDG{"doPositivePDG", false, "Flag to fill histograms for positive PDG codes."}; + Configurable doNegativePDG{"doNegativePDG", false, "Flag to fill histograms for negative PDG codes."}; + // Particle only selection + Configurable doEl{"do-el", false, "Flag to run with the PDG code of electrons"}; + Configurable doMu{"do-mu", false, "Flag to run with the PDG code of muons"}; + Configurable doPi{"do-pi", false, "Flag to run with the PDG code of pions"}; + Configurable doKa{"do-ka", false, "Flag to run with the PDG code of kaons"}; + Configurable doPr{"do-pr", false, "Flag to run with the PDG code of protons"}; + Configurable doDe{"do-de", false, "Flag to run with the PDG code of deuterons"}; + Configurable doTr{"do-tr", false, "Flag to run with the PDG code of tritons"}; + Configurable doHe{"do-he", false, "Flag to run with the PDG code of helium 3"}; + Configurable doAl{"do-al", false, "Flag to run with the PDG code of helium 4"}; + // Track only selection, options to select only specific tracks + Configurable trackSelection{"trackSelection", true, "Local track selection"}; + Configurable globalTrackSelection{"globalTrackSelection", 0, "Global track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks, 6 -> custom track cuts via Configurable"}; + // Event selection + Configurable nMinNumberOfContributors{"nMinNumberOfContributors", 2, "Minimum required number of contributors to the primary vertex"}; + Configurable vertexZMin{"vertex-z-min", -10.f, "Minimum position of the generated vertez in Z (cm)"}; + Configurable vertexZMax{"vertex-z-max", 10.f, "Maximum position of the generated vertez in Z (cm)"}; + // Histogram configuration + ConfigurableAxis ptBins{"ptBins", {200, 0.f, 5.f}, "Pt binning"}; + // Histograms + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + static const char* particleName(int pdgSign, o2::track::PID::ID id) + { + if (pdgSign == 0) { // Positive PDG + return particleTitle[id]; + } + // Negative PDG + return particleTitle[id + o2::track::PID::NIDs]; + } + + void makeMCHistograms(const bool doMakeHistograms, + const int pdgSign, + o2::track::PID::ID id) + { + if (!doMakeHistograms) { + return; + } + + switch (pdgSign) { + case 0: // Positive + if (!doPositivePDG) { + return; + } + break; + case 1: // Negative + if (!doNegativePDG) { + return; + } + break; + default: + LOG(fatal) << "Can't interpret pdgSign " << pdgSign; + } + + const AxisSpec axisPt{ptBins, "#it{p}_{T} (GeV/#it{c})"}; + // const AxisSpec axisP{ptBins, "#it{p} (GeV/#it{c})"}; + // const AxisSpec axisEta{etaBins, "#it{#eta}"}; + // const AxisSpec axisY{yBins, "#it{y}"}; + // const AxisSpec axisPhi{phiBins, "#it{#varphi} (rad)"}; + + const char* partName = particleName(pdgSign, id); + LOG(info) << "Preparing histograms for particle: " << partName << " pdgSign " << pdgSign; + const int histogramIndex = id + pdgSign * nSpecies; + + const TString tagPt = Form("%s ", partName); + hPtAll[histogramIndex] = histos.add(Form("MC/pdg%i/pt/all", PDGs[histogramIndex]), "All tracks " + tagPt, kTH1D, {axisPt}); + hPtITS[histogramIndex] = histos.add(Form("MC/pdg%i/pt/mismatched/its", PDGs[histogramIndex]), "ITS mismatch " + tagPt, kTH1D, {axisPt}); + hPtTPC[histogramIndex] = histos.add(Form("MC/pdg%i/pt/mismatched/tpc", PDGs[histogramIndex]), "TPC mismatch " + tagPt, kTH1D, {axisPt}); + hPtTRD[histogramIndex] = histos.add(Form("MC/pdg%i/pt/mismatched/trd", PDGs[histogramIndex]), "TRD mismatch " + tagPt, kTH1D, {axisPt}); + hPtTOF[histogramIndex] = histos.add(Form("MC/pdg%i/pt/mismatched/tof", PDGs[histogramIndex]), "TOF mismatch " + tagPt, kTH1D, {axisPt}); + hPtOverall[histogramIndex] = histos.add(Form("MC/pdg%i/pt/mismatched/overall", PDGs[histogramIndex]), "Overall mismatch " + tagPt, kTH1D, {axisPt}); + + LOG(info) << "Done with particle: " << partName; + } + + void init(InitContext&) + { + for (int pdgSign = 0; pdgSign < 2; pdgSign++) { + makeMCHistograms(doEl, pdgSign, o2::track::PID::Electron); + makeMCHistograms(doMu, pdgSign, o2::track::PID::Muon); + makeMCHistograms(doPi, pdgSign, o2::track::PID::Pion); + makeMCHistograms(doKa, pdgSign, o2::track::PID::Kaon); + makeMCHistograms(doPr, pdgSign, o2::track::PID::Proton); + makeMCHistograms(doDe, pdgSign, o2::track::PID::Deuteron); + makeMCHistograms(doTr, pdgSign, o2::track::PID::Triton); + makeMCHistograms(doHe, pdgSign, o2::track::PID::Helium3); + makeMCHistograms(doAl, pdgSign, o2::track::PID::Alpha); + } + } + + template + bool isPdgSelected(const particleType& mcParticle) + { + static_assert(pdgSign == 0 || pdgSign == 1); + static_assert(id > 0 || id < nSpecies); + constexpr int index = id + pdgSign * nSpecies; + return mcParticle.pdgCode() == PDGs[index]; + } + + template + bool isMismatched(TrackType const& track, int layer) + { + return (track.mcMask() & 1 << layer); + } + + template + void fillMCTrackHistograms(const trackType& track, const bool doMakeHistograms) + { + static_assert(pdgSign == 0 || pdgSign == 1); + if (!doMakeHistograms) { + return; + } + + if constexpr (pdgSign == 0) { + if (!doPositivePDG) { + return; + } + } else { + if (!doNegativePDG) { + return; + } + } + + constexpr int histogramIndex = id + pdgSign * nSpecies; + LOG(debug) << "fillMCTrackHistograms for pdgSign '" << pdgSign << "' and id '" << static_cast(id) << "' " << particleName(pdgSign, id) << " with index " << histogramIndex; + if (!track.has_mcParticle()) { + return; + } + const auto& mcParticle = track.mcParticle(); + + if (!isPdgSelected(mcParticle)) { // Selecting PDG code + return; + } + if (!track.isGlobalTrack()) { + return; + } + hPtAll[histogramIndex]->Fill(mcParticle.pt()); + bool mismatchInITS = false; + for (int i = 0; i < 7; i++) { + if (isMismatched(track, i)) { + mismatchInITS = true; + break; + } + } + + bool mismatchInTPC = false; + for (int i = 7; i < 10; i++) { + if (isMismatched(track, i)) { + mismatchInTPC = true; + break; + } + } + const bool mismatchInTRD = isMismatched(track, 10); + const bool mismatchInTOF = isMismatched(track, 11); + const bool overallMismatch = isMismatched(track, 15); + + if (mismatchInITS) { + hPtITS[histogramIndex]->Fill(mcParticle.pt()); + } + if (mismatchInTPC) { + hPtTPC[histogramIndex]->Fill(mcParticle.pt()); + } + if (mismatchInTRD) { + hPtTRD[histogramIndex]->Fill(mcParticle.pt()); + } + if (mismatchInTOF) { + hPtTOF[histogramIndex]->Fill(mcParticle.pt()); + } + if (overallMismatch) { + hPtOverall[histogramIndex]->Fill(mcParticle.pt()); + } + } + + using TrackCandidates = o2::soa::Join; + using TrackCandidatesMC = o2::soa::Join; + + // MC process + void process(o2::aod::Collision const& /*collision*/, + o2::soa::Join const& tracks, + o2::aod::McCollisions const&, + o2::aod::McParticles const&) + { + // Track loop + for (const auto& track : tracks) { + static_for<0, 1>([&](auto pdgSign) { + fillMCTrackHistograms(track, doEl); + fillMCTrackHistograms(track, doMu); + fillMCTrackHistograms(track, doPi); + fillMCTrackHistograms(track, doKa); + fillMCTrackHistograms(track, doPr); + fillMCTrackHistograms(track, doDe); + fillMCTrackHistograms(track, doTr); + fillMCTrackHistograms(track, doHe); + fillMCTrackHistograms(track, doAl); + }); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/DPG/Tasks/AOTTrack/qaImpPar.cxx b/DPG/Tasks/AOTTrack/qaImpPar.cxx index 452e6448d70..8e93081727a 100644 --- a/DPG/Tasks/AOTTrack/qaImpPar.cxx +++ b/DPG/Tasks/AOTTrack/qaImpPar.cxx @@ -65,12 +65,17 @@ struct QaImpactPar { ConfigurableAxis binningPhi{"binningPhi", {24, 0.f, TMath::TwoPi()}, "Phi binning"}; ConfigurableAxis binningPDG{"binningPDG", {5, -1.5f, 3.5f}, "PDG species binning (-1: not matched, 0: unknown, 1: pi, 2: K, 3: p)"}; ConfigurableAxis binningCharge{"binningCharge", {2, -2.f, 2.f}, "charge binning (-1: negative; +1: positive)"}; + ConfigurableAxis binningIuPosX{"binningIuPosX", {100, -10.f, 10.f}, "Track IU x position"}; + ConfigurableAxis binningIuPosY{"binningIuPosY", {100, -10.f, 10.f}, "Track IU y position"}; + ConfigurableAxis binningIuPosZ{"binningIuPosZ", {100, -10.f, 10.f}, "Track IU z position"}; + ConfigurableAxis binningClusterSize{"binningClusterSize", {16, -0.5, 15.5}, "Cluster size, four bits per a layer"}; ConfigurableAxis binsNumPvContrib{"binsNumPvContrib", {200, 0, 200}, "Number of original PV contributors"}; Configurable keepOnlyPhysPrimary{"keepOnlyPhysPrimary", false, "Consider only phys. primary particles (MC)"}; Configurable keepOnlyPvContrib{"keepOnlyPvContrib", false, "Consider only PV contributor tracks"}; // Configurable numberContributorsMin{"numberContributorsMin", 0, "Minimum number of contributors for the primary vertex"}; Configurable useTriggerkINT7{"useTriggerkINT7", false, "Use kINT7 trigger"}; Configurable usesel8{"usesel8", true, "Use or not the sel8() (T0A & T0C) event selection"}; + Configurable addTrackIUinfo{"addTrackIUinfo", false, "Add track parameters at inner most update"}; Configurable trackSelection{"trackSelection", 1, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; Configurable zVtxMax{"zVtxMax", 10.f, "Maximum value for |z_vtx|"}; // Configurable keepOnlyGlobalTracks{"keepOnlyGlobalTracks", 1, "Keep only global tracks or not"}; @@ -108,6 +113,7 @@ struct QaImpactPar { Configurable keepAllTracksPVrefit{"keepAllTracksPVrefit", false, "Keep all tracks for PV refit (for debug)"}; Configurable use_customITSHitMap{"use_customITSHitMap", false, "Use custom ITS hitmap selection"}; Configurable customITShitmap{"customITShitmap", 0, "Custom ITS hitmap (consider the binary representation)"}; + Configurable customITShitmap_exclude{"customITShitmap_exclude", 0, "Custom ITS hitmap of layers to be excluded (consider the binary representation)"}; Configurable n_customMinITShits{"n_customMinITShits", 0, "Minimum number of layers crossed by a track among those in \"customITShitmap\""}; Configurable custom_forceITSTPCmatching{"custom_forceITSTPCmatching", false, "Consider or not only ITS-TPC macthed tracks when using custom ITS hitmap"}; @@ -125,15 +131,16 @@ struct QaImpactPar { ((trackSelection.node() == 2) && requireGlobalTrackWoPtEtaInFilter()) || ((trackSelection.node() == 3) && requireGlobalTrackWoDCAInFilter()) || ((trackSelection.node() == 4) && requireQualityTracksInFilter()) || - ((trackSelection.node() == 5) && requireTrackCutInFilter(TrackSelectionFlags::kInAcceptanceTracks)); + ((trackSelection.node() == 5) && requireTrackCutInFilter(TrackSelectionFlags::kInAcceptanceTracks)) || + ((trackSelection.node() == 6) && requireTrackCutInFilter(TrackSelectionFlags::kGlobalTrackWoDCAxy)); // Pt selection Filter ptMinFilter = o2::aod::track::pt > ptMin; /// Histogram registry (from o2::framework) HistogramRegistry histograms{"HistogramsImpParQA"}; - bool isPIDPionApplied = ((nSigmaTPCPionMin > -10.001 && nSigmaTPCPionMax < 10.001) || (nSigmaTOFPionMin > -10.001 && nSigmaTOFPionMax < 10.001)); - bool isPIDKaonApplied = ((nSigmaTPCKaonMin > -10.001 && nSigmaTPCKaonMax < 10.001) || (nSigmaTOFKaonMin > -10.001 && nSigmaTOFKaonMax < 10.001)); - bool isPIDProtonApplied = ((nSigmaTPCProtonMin > -10.001 && nSigmaTPCProtonMax < 10.001) || (nSigmaTOFProtonMin > -10.001 && nSigmaTOFProtonMax < 10.001)); + bool isPIDPionApplied; + bool isPIDKaonApplied; + bool isPIDProtonApplied; // Needed for PV refitting Service ccdb; @@ -151,14 +158,16 @@ struct QaImpactPar { using trackFullTable = o2::soa::Join; + using trackTableIU = o2::soa::Join; void processData(o2::soa::Filtered::iterator& collision, const trackTable& tracksUnfiltered, const o2::soa::Filtered& tracks, + const trackTableIU& tracksIU, o2::aod::BCsWithTimestamps const&) { /// here call the template processReco function auto bc = collision.bc_as(); - processReco(collision, tracksUnfiltered, tracks, 0, bc); + processReco(collision, tracksUnfiltered, tracks, tracksIU, 0, bc); } PROCESS_SWITCH(QaImpactPar, processData, "process data", true); @@ -168,13 +177,14 @@ struct QaImpactPar { void processMC(o2::soa::Filtered::iterator& collision, trackTable const& tracksUnfiltered, o2::soa::Filtered const& tracks, + const trackTableIU& tracksIU, const o2::aod::McParticles& mcParticles, const o2::aod::McCollisions&, o2::aod::BCsWithTimestamps const&) { /// here call the template processReco function auto bc = collision.bc_as(); - processReco(collision, tracksUnfiltered, tracks, mcParticles, bc); + processReco(collision, tracksUnfiltered, tracks, tracksIU, mcParticles, bc); } PROCESS_SWITCH(QaImpactPar, processMC, "process MC", false); @@ -232,7 +242,7 @@ struct QaImpactPar { // } mRunNumber = -1; - /// Custom cut selection objects + /// Custom cut selection objects - ITS layers that must be present std::set set_customITShitmap; // = {}; if (use_customITSHitMap) { for (int index_ITSlayer = 0; index_ITSlayer < 7; index_ITSlayer++) { @@ -251,11 +261,34 @@ struct QaImpactPar { selector_ITShitmap.SetRequireHitsInITSLayers(n_customMinITShits, set_customITShitmap); } + /// Custom cut selection objects - ITS layers that must be absent + std::set set_customITShitmap_exclude; // = {}; + if (use_customITSHitMap) { + for (int index_ITSlayer = 0; index_ITSlayer < 7; index_ITSlayer++) { + if ((customITShitmap_exclude & (1 << index_ITSlayer)) > 0) { + set_customITShitmap_exclude.insert(static_cast(index_ITSlayer)); + } + } + LOG(info) << "### customITShitmap_exclude: " << customITShitmap_exclude; + LOG(info) << "### set_customITShitmap_exclude.size(): " << set_customITShitmap_exclude.size(); + LOG(info) << "### ITS layers to be excluded: "; + for (std::set::iterator it = set_customITShitmap_exclude.begin(); it != set_customITShitmap_exclude.end(); it++) { + LOG(info) << "Layer " << static_cast(*it) << " "; + } + LOG(info) << "############"; + + selector_ITShitmap.SetRequireNoHitsInITSLayers(set_customITShitmap_exclude); + } // tracks const AxisSpec trackPtAxis{binningPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec trackPaxis{binningPt, "#it{p} (GeV/#it{c})"}; const AxisSpec trackEtaAxis{binningEta, "#it{#eta}"}; const AxisSpec trackPhiAxis{binningPhi, "#varphi"}; + const AxisSpec trackIUposXaxis{binningIuPosX, "x (cm)"}; + const AxisSpec trackIUposYaxis{binningIuPosY, "y (cm)"}; + const AxisSpec trackIUposZaxis{binningIuPosZ, "z (cm)"}; + const AxisSpec trackIUclusterSize{binningClusterSize, "cluster size"}; const AxisSpec trackImpParRPhiAxis{binningImpPar, "#it{d}_{r#it{#varphi}} (#mum)"}; const AxisSpec trackImpParZAxis{binningImpPar, "#it{d}_{z} (#mum)"}; const AxisSpec trackImpParRPhiPullsAxis{binningPulls, "#it{d}_{r#it{#varphi}} / #sigma(#it{d}_{r#it{#varphi}})"}; @@ -281,6 +314,11 @@ struct QaImpactPar { histograms.get(HIST("Reco/refitRun3"))->GetXaxis()->SetBinLabel(5, "hasTPC && hasITS"); histograms.add("Reco/h4ImpPar", "", kTHnSparseD, {trackPtAxis, trackImpParRPhiAxis, trackEtaAxis, trackPhiAxis, trackPDGAxis, trackChargeAxis, axisVertexNumContrib, trackIsPvContrib}); histograms.add("Reco/h4ImpParZ", "", kTHnSparseD, {trackPtAxis, trackImpParZAxis, trackEtaAxis, trackPhiAxis, trackPDGAxis, trackChargeAxis, axisVertexNumContrib, trackIsPvContrib}); + if (addTrackIUinfo) { + histograms.add("Reco/h4ClusterSizeIU", "", kTHnSparseD, {trackPaxis, trackImpParRPhiAxis, trackIUposXaxis, trackIUposYaxis, trackIUposZaxis, trackIUclusterSize}); + // histograms.add("Reco/h4ImpParIU", "", kTHnSparseD, {trackPaxis, trackImpParRPhiAxis, trackIUposXaxis, trackIUposYaxis, trackIUposZaxis}); + histograms.add("Reco/h4ImpParZIU", "", kTHnSparseD, {trackPaxis, trackImpParZAxis, trackIUposXaxis, trackIUposYaxis, trackIUposZaxis}); + } // if(fEnablePulls && !doPVrefit) { // LOGF(fatal, ">>> dca errors not stored after track propagation at the moment. Use fEnablePulls only if doPVrefit!"); // } @@ -288,15 +326,27 @@ struct QaImpactPar { histograms.add("Reco/h4ImpParPulls", "", kTHnSparseD, {trackPtAxis, trackImpParRPhiPullsAxis, trackEtaAxis, trackPhiAxis, trackPDGAxis, trackChargeAxis, axisVertexNumContrib, trackIsPvContrib}); histograms.add("Reco/h4ImpParZPulls", "", kTHnSparseD, {trackPtAxis, trackImpParZPullsAxis, trackEtaAxis, trackPhiAxis, trackPDGAxis, trackChargeAxis, axisVertexNumContrib, trackIsPvContrib}); } + isPIDPionApplied = ((nSigmaTPCPionMin > -10.001 && nSigmaTPCPionMax < 10.001) || (nSigmaTOFPionMin > -10.001 && nSigmaTOFPionMax < 10.001)); if (isPIDPionApplied) { + if (addTrackIUinfo) { + histograms.add("Reco/h4ClusterSizeIU_Pion", "", kTHnSparseD, {trackPaxis, trackImpParRPhiAxis, trackIUposXaxis, trackIUposYaxis, trackIUposZaxis, trackIUclusterSize}); + } histograms.add("Reco/h4ImpPar_Pion", "", kTHnSparseD, {trackPtAxis, trackImpParRPhiAxis, trackEtaAxis, trackPhiAxis, trackPDGAxis, trackChargeAxis, axisVertexNumContrib, trackIsPvContrib}); histograms.add("Reco/h4ImpParZ_Pion", "", kTHnSparseD, {trackPtAxis, trackImpParZAxis, trackEtaAxis, trackPhiAxis, trackPDGAxis, trackChargeAxis, axisVertexNumContrib, trackIsPvContrib}); } + isPIDKaonApplied = ((nSigmaTPCKaonMin > -10.001 && nSigmaTPCKaonMax < 10.001) || (nSigmaTOFKaonMin > -10.001 && nSigmaTOFKaonMax < 10.001)); if (isPIDKaonApplied) { + if (addTrackIUinfo) { + histograms.add("Reco/h4ClusterSizeIU_Kaon", "", kTHnSparseD, {trackPaxis, trackImpParRPhiAxis, trackIUposXaxis, trackIUposYaxis, trackIUposZaxis, trackIUclusterSize}); + } histograms.add("Reco/h4ImpPar_Kaon", "", kTHnSparseD, {trackPtAxis, trackImpParRPhiAxis, trackEtaAxis, trackPhiAxis, trackPDGAxis, trackChargeAxis, axisVertexNumContrib, trackIsPvContrib}); histograms.add("Reco/h4ImpParZ_Kaon", "", kTHnSparseD, {trackPtAxis, trackImpParZAxis, trackEtaAxis, trackPhiAxis, trackPDGAxis, trackChargeAxis, axisVertexNumContrib, trackIsPvContrib}); } + isPIDProtonApplied = ((nSigmaTPCProtonMin > -10.001 && nSigmaTPCProtonMax < 10.001) || (nSigmaTOFProtonMin > -10.001 && nSigmaTOFProtonMax < 10.001)); if (isPIDProtonApplied) { + if (addTrackIUinfo) { + histograms.add("Reco/h4ClusterSizeIU_Proton", "", kTHnSparseD, {trackPaxis, trackImpParRPhiAxis, trackIUposXaxis, trackIUposYaxis, trackIUposZaxis, trackIUclusterSize}); + } histograms.add("Reco/h4ImpPar_Proton", "", kTHnSparseD, {trackPtAxis, trackImpParRPhiAxis, trackEtaAxis, trackPhiAxis, trackPDGAxis, trackChargeAxis, axisVertexNumContrib, trackIsPvContrib}); histograms.add("Reco/h4ImpParZ_Proton", "", kTHnSparseD, {trackPtAxis, trackImpParZAxis, trackEtaAxis, trackPhiAxis, trackPDGAxis, trackChargeAxis, axisVertexNumContrib, trackIsPvContrib}); } @@ -320,7 +370,7 @@ struct QaImpactPar { /// core template process function template void processReco(const C& collision, const trackTable& unfilteredTracks, const T& tracks, - const T_MC& /*mcParticles*/, + const trackTableIU& tracksIU, const T_MC& /*mcParticles*/, o2::aod::BCsWithTimestamps::iterator const& bc) { constexpr float toMicrometers = 10000.f; // Conversion from [cm] to [mum] @@ -441,6 +491,7 @@ struct QaImpactPar { /// loop over tracks float pt = -999.f; + float p = -999.f; float impParRPhi = -999.f; float impParZ = -999.f; float impParRPhiSigma = 999.f; @@ -451,6 +502,11 @@ struct QaImpactPar { float tofNSigmaPion = -999.f; float tofNSigmaKaon = -999.f; float tofNSigmaProton = -999.f; + float trackIuPosX = -999.f; + float trackIuPosY = -999.f; + float trackIuPosZ = -999.f; + std::array posXYZ = {-999.f, -999.f, -999.f}; + int clusterSizeInLayer0 = -1; int ntr = tracks.size(); int cnt = 0; for (const auto& track : tracks) { @@ -534,6 +590,7 @@ struct QaImpactPar { } pt = track.pt(); + p = track.p(); tpcNSigmaPion = track.tpcNSigmaPi(); tpcNSigmaKaon = track.tpcNSigmaKa(); tpcNSigmaProton = track.tpcNSigmaPr(); @@ -638,9 +695,28 @@ struct QaImpactPar { } } + /// retrive track position at inner most update + if (addTrackIUinfo) { + for (const auto& trackIU : tracksIU) { + if (trackIU.globalIndex() == track.globalIndex()) { + o2::track::TrackParCov trackIuParCov = getTrackParCov(trackIU); + trackIuParCov.getXYZGlo(posXYZ); + trackIuPosX = posXYZ[0]; + trackIuPosY = posXYZ[1]; + trackIuPosZ = posXYZ[2]; + clusterSizeInLayer0 = trackIU.itsClsSizeInLayer(0); + } + } + } + /// all tracks histograms.fill(HIST("Reco/h4ImpPar"), pt, impParRPhi, track.eta(), track.phi(), pdgIndex, track.sign(), collision.numContrib(), track.isPVContributor()); histograms.fill(HIST("Reco/h4ImpParZ"), pt, impParZ, track.eta(), track.phi(), pdgIndex, track.sign(), collision.numContrib(), track.isPVContributor()); + if (addTrackIUinfo) { + histograms.fill(HIST("Reco/h4ClusterSizeIU"), p, impParRPhi, trackIuPosX, trackIuPosY, trackIuPosZ, clusterSizeInLayer0); + // histograms.fill(HIST("Reco/h4ImpParIU"), p, impParRPhi, trackIuPosX, trackIuPosY, trackIuPosZ); + histograms.fill(HIST("Reco/h4ImpParZIU"), p, impParZ, trackIuPosX, trackIuPosY, trackIuPosZ); + } if (fEnablePulls) { histograms.fill(HIST("Reco/h4ImpParPulls"), pt, impParRPhi / impParRPhiSigma, track.eta(), track.phi(), pdgIndex, track.sign(), collision.numContrib(), track.isPVContributor()); histograms.fill(HIST("Reco/h4ImpParZPulls"), pt, impParZ / impParZSigma, track.eta(), track.phi(), pdgIndex, track.sign(), collision.numContrib(), track.isPVContributor()); @@ -648,6 +724,9 @@ struct QaImpactPar { if (isPIDPionApplied && nSigmaTPCPionMin < tpcNSigmaPion && tpcNSigmaPion < nSigmaTPCPionMax && nSigmaTOFPionMin < tofNSigmaPion && tofNSigmaPion < nSigmaTOFPionMax) { /// PID selected pions + if (addTrackIUinfo) { + histograms.fill(HIST("Reco/h4ClusterSizeIU_Pion"), p, impParRPhi, trackIuPosX, trackIuPosY, trackIuPosZ, clusterSizeInLayer0); + } histograms.fill(HIST("Reco/h4ImpPar_Pion"), pt, impParRPhi, track.eta(), track.phi(), pdgIndex, track.sign(), collision.numContrib(), track.isPVContributor()); histograms.fill(HIST("Reco/h4ImpParZ_Pion"), pt, impParZ, track.eta(), track.phi(), pdgIndex, track.sign(), collision.numContrib(), track.isPVContributor()); histograms.fill(HIST("Reco/hNSigmaTPCPion_afterPID"), pt, tpcNSigmaPion); @@ -655,6 +734,9 @@ struct QaImpactPar { } if (isPIDKaonApplied && nSigmaTPCKaonMin < tpcNSigmaKaon && tpcNSigmaKaon < nSigmaTPCKaonMax && nSigmaTOFKaonMin < tofNSigmaKaon && tofNSigmaKaon < nSigmaTOFKaonMax) { /// PID selected kaons + if (addTrackIUinfo) { + histograms.fill(HIST("Reco/h4ClusterSizeIU_Kaon"), p, impParRPhi, trackIuPosX, trackIuPosY, trackIuPosZ, clusterSizeInLayer0); + } histograms.fill(HIST("Reco/h4ImpPar_Kaon"), pt, impParRPhi, track.eta(), track.phi(), pdgIndex, track.sign(), collision.numContrib(), track.isPVContributor()); histograms.fill(HIST("Reco/h4ImpParZ_Kaon"), pt, impParZ, track.eta(), track.phi(), pdgIndex, track.sign(), collision.numContrib(), track.isPVContributor()); histograms.fill(HIST("Reco/hNSigmaTPCKaon_afterPID"), pt, tpcNSigmaKaon); @@ -662,6 +744,9 @@ struct QaImpactPar { } if (isPIDProtonApplied && nSigmaTPCProtonMin < tpcNSigmaProton && tpcNSigmaProton < nSigmaTPCProtonMax && nSigmaTOFProtonMin < tofNSigmaProton && tofNSigmaProton < nSigmaTOFProtonMax) { /// PID selected Protons + if (addTrackIUinfo) { + histograms.fill(HIST("Reco/h4ClusterSizeIU_Proton"), p, impParRPhi, trackIuPosX, trackIuPosY, trackIuPosZ, clusterSizeInLayer0); + } histograms.fill(HIST("Reco/h4ImpPar_Proton"), pt, impParRPhi, track.eta(), track.phi(), pdgIndex, track.sign(), collision.numContrib(), track.isPVContributor()); histograms.fill(HIST("Reco/h4ImpParZ_Proton"), pt, impParZ, track.eta(), track.phi(), pdgIndex, track.sign(), collision.numContrib(), track.isPVContributor()); histograms.fill(HIST("Reco/hNSigmaTPCProton_afterPID"), pt, tpcNSigmaProton); diff --git a/DPG/Tasks/AOTTrack/qaMatchEff.cxx b/DPG/Tasks/AOTTrack/qaMatchEff.cxx index 3b02fdf65a9..ddcdf65766e 100644 --- a/DPG/Tasks/AOTTrack/qaMatchEff.cxx +++ b/DPG/Tasks/AOTTrack/qaMatchEff.cxx @@ -14,14 +14,16 @@ /// /// \author Rosario Turrisi , INFN-PD /// \author Mattia Faggin , UniTs & INFN-TS +/// \author Chunzheng Wang < chunzheng.wang@m.fudan.edu.cn>, Fudan Univ. // // Internal version number: 6.3 // -#include "Common/DataModel/EventSelection.h" #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/PIDResponse.h" #include "CommonConstants/MathConstants.h" #include "CCDB/BasicCCDBManager.h" @@ -29,7 +31,10 @@ #include "Framework/AnalysisTask.h" #include "Framework/RunningWorkflowInfo.h" #include "Framework/runDataProcessing.h" - +// +#include "string" +#include "vector" +#include "set" // namespace extConfPar { @@ -56,6 +61,17 @@ using std::array; using namespace extConfPar; using o2::constants::math::PI; using o2::constants::math::TwoPI; + +using CollisionsEvSel = soa::Filtered>; +using CollisionsMCEvSel = soa::Filtered>; +using CollisionsEvSelFT0C = soa::Filtered>; +using CollisionsMCEvSelFT0C = soa::Filtered>; + +using TracksPID = soa::Join; +using TracksIUPID = soa::Join; +using MCTracks = soa::Join; +using MCTracksIU = soa::Join; + // struct qaMatchEff { int lastRunNumber = -1; @@ -63,6 +79,9 @@ struct qaMatchEff { Service ccdb; using BCsWithTimeStamp = soa::Join; + Configurable makethn{"makethn", false, "choose if produce thnsparse"}; + Configurable makehistos{"makehistos", true, "choose if produce histos"}; + Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable enableMonitorVsTime{"enableMonitorVsTime", false, "Enable the storage of ITS-TPC matching efficiency vs. time"}; Configurable enableTHnSparseMonitorVsTime{"enableTHnSparseMonitorVsTime", false, "Enable the storage of ITS-TPC matching efficiency vs. time"}; @@ -70,16 +89,44 @@ struct qaMatchEff { // histogram registry HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; // + // Event selections + Configurable isPbPb{"isPbPb", false, "Boolean to tag if the data is PbPb collisions. If false, it is pp"}; + Configurable isEnableEventSelection{"isEnableEventSelection", true, "Boolean to switch the event selection on/off."}; + Configurable isCentralityRequired{"isCentralityRequired", false, "Boolean to switch the centrality selection on/off."}; + Configurable isRejectNearByEvent{"isRejectNearByEvent", false, "Boolean to switch the rejection of near by events on/off."}; + Configurable isEnableOccupancyCut{"isEnableOccupancyCut", false, "Boolean to switch the occupancy cut on/off."}; + struct : ConfigurableGroup { + Configurable centralityMinCut{"centralityMinCut", 0.0f, "Minimum centrality"}; + Configurable centralityMaxCut{"centralityMaxCut", 100.0f, "Maximum centrality"}; + } centralityCuts; + struct : ConfigurableGroup { + Configurable minTracksInTimeRange{"minTracksInTimeRange", 0, "Minimum number of tracks in the time range"}; + Configurable maxTracksInTimeRange{"maxTracksInTimeRange", 999999, "Maximum number of tracks in the time range"}; + } occupancyCuts; + // // Track selections + Configurable isUseTPCinnerWallPt{"isUseTPCinnerWallPt", false, "Boolean to switch the usage of pt calculated at the inner wall of TPC on/off."}; Configurable isUseTrackSelections{"isUseTrackSelections", false, "Boolean to switch the track selections on/off."}; Configurable isUseAnalysisTrackSelections{"isUseAnalysisTrackSelections", false, "Boolean to switch if the analysis track selections are used. If true, all the Explicit track cuts are ignored."}; - // kinematics - Configurable ptMinCutInnerWallTPC{"ptMinCutInnerWallTPC", 0.1f, "Minimum transverse momentum calculated at the inner wall of TPC (GeV/c)"}; - Configurable ptMinCut{"ptMinCut", 0.1f, "Minimum transverse momentum (GeV/c)"}; - Configurable ptMaxCut{"ptMaxCut", 100.f, "Maximum transverse momentum (GeV/c)"}; - Configurable etaMinCut{"etaMinCut", -2.0f, "Minimum pseudorapidity"}; - Configurable etaMaxCut{"etaMaxCut", 2.0f, "Maximum pseudorapidity"}; - Configurable isUseTPCinnerWallPt{"isUseTPCinnerWallPt", false, "Boolean to switch the usage of pt calculated at the inner wall of TPC on/off."}; + // analysis track selections changes + struct : ConfigurableGroup { + Configurable isChangeAnalysisCutEta{"isChangeAnalysisCutEta", false, "Boolean to switch if the analysis eta cut is changed."}; + Configurable isChangeAnalysisCutDcaZ{"isChangeAnalysisCutDcaZ", false, "Boolean to switch if the analysis DcaZ cut is changed."}; + Configurable isChangeAnalysisCutDcaXY{"isChangeAnalysisCutDcaXY", false, "Boolean to switch if the analysis DcaXY cut is changed."}; + Configurable isChangeAnalysisCutNClustersTPC{"isChangeAnalysisCutNClustersTPC", false, "Boolean to switch if the analysis NClustersTPC cut is changed."}; + Configurable isChangeAnalysisITSHitmap{"isChangeAnalysisITSHitmap", false, "Boolean to switch if the analysis ITSHitmap is changed."}; + } customAnaTrkSel; + // + // Kinematics + struct : ConfigurableGroup { + Configurable ptMinCutInnerWallTPC{"ptMinCutInnerWallTPC", 0.1f, "Minimum transverse momentum calculated at the inner wall of TPC (GeV/c)"}; + Configurable ptMinCut{"ptMinCut", 0.1f, "Minimum transverse momentum (GeV/c)"}; + Configurable ptMaxCut{"ptMaxCut", 100.f, "Maximum transverse momentum (GeV/c)"}; + Configurable etaMinCut{"etaMinCut", -2.0f, "Minimum pseudorapidity"}; + Configurable etaMaxCut{"etaMaxCut", 2.0f, "Maximum pseudorapidity"}; + } kineCuts; + // + // // DCA and PID cuts Configurable> dcaMaxCut{"dcaMaxCut", {parTableDCA[0], nParDCA, nParVaDCA, parClassDCA, parNameDCA}, "Track DCA cuts"}; Configurable> nSigmaPID{"nSigmaPID", {parTablePID[0], nParPID, nParVaPID, parClassPID, parNamePID}, "PID nSigma cuts TPC and TOF"}; @@ -95,16 +142,12 @@ struct qaMatchEff { // Other track settings // TRD presence Configurable isTRDThere{"isTRDThere", 2, "Integer to turn the presence of TRD off, on, don't care (0,1,anything else)"}; + Configurable isTOFThere{"isTOFThere", 2, "Integer to turn the presence of TOF off, on, don't care (0,1,anything else)"}; // Configurable isitMC{"isitMC", false, "Reading MC files, data if false"}; Configurable doDebug{"doDebug", false, "Flag of debug information"}; // Histogram configuration // - // histos axes limits - Configurable etaMin{"eta-min", -2.0f, "Lower limit in eta"}; - Configurable etaMax{"eta-max", 2.0f, "Upper limit in eta"}; - Configurable phiMin{"phi-min", 0.0f, "Lower limit in phi"}; - Configurable phiMax{"phi-max", 1.0f * TwoPI, "Upper limit in phi"}; // histos bins Configurable etaBins{"eta-bins", 40, "Number of eta bins"}; Configurable phiBins{"phi-bins", 18, "Number of phi bins"}; @@ -124,49 +167,9 @@ struct qaMatchEff { ConfigurableAxis posZBinsVsTime{"posZBinsVsTime", {2, -100, 100}, "posZ primary vertex binning for monitoring vs time"}; ConfigurableAxis tpcClstBinsVsTime{"tpcClstBinsVsTime", {40, 0, 160}, "TPC cluster binning for monitoring vs time"}; ConfigurableAxis itsClstBinsVsTime{"itsClstBinsVsTime", {9, 0, 9}, "ITS cluster binning for monitoring vs time"}; - // - AxisSpec axisPDG{pdgBins, 0, pdgBins + 1.000, "pdgclass"}; - // - AxisSpec axisPt{ptBins, "#it{p}_{T} (GeV/#it{c})"}; - // - AxisSpec axisX{XBins, "track x (cm)"}; - // - AxisSpec axisZ{ZBins, "track z (cm)"}; - // - AxisSpec axisQoPt{qoptBins, -20, 20, "#Q/it{p}_{T} (GeV/#it{c})^{-1}"}; - // - AxisSpec axisEta{etaBins, etaMin, etaMax, "#eta"}; - AxisSpec axisPhi{phiBins, phiMin, phiMax, "#it{#varphi} (rad)"}; - AxisSpec axisDEta{etaBins, etaMin, etaMax, "D#eta"}; - AxisSpec axisDPh{phiBins, -PI, PI, "D#it{#varphi} (rad)"}; - // // pdg codes vector std::vector pdgChoice = {211, 213, 215, 217, 219, 221, 223, 321, 411, 521, 2212, 1114, 2214}; - // - // configuration for THnSparse's - // - Configurable makethn{"makethn", false, "choose if produce thnsparse"}; - ConfigurableAxis thnd0{"thnd0", {150, -3.0f, 3.0f}, "impact parameter in xy [cm]"}; - ConfigurableAxis thndz{"thndz", {150, -10.0f, 10.0f}, "impact parameter in z [cm]"}; - ConfigurableAxis thnPt{"thnPt", {80, 0.0f, 20.0f}, "pt [GeV/c]"}; - ConfigurableAxis thnPhi{"thnPhi", {180, 0.0f, TMath::TwoPi()}, "phi"}; - ConfigurableAxis thnEta{"thnEta", {20, -2.0f, 2.0f}, "eta"}; - ConfigurableAxis thnType{"thnType", {3, -0.5f, 2.5f}, "0: primary, 1: physical secondary, 2: sec. from material"}; - ConfigurableAxis thnLabelSign{"thnLabelSign", {3, -1.5f, 1.5f}, "MC -1/+1 antip./particle"}; - ConfigurableAxis thnSpec{"thnSpec", {19, -9.5f, 9.5f}, "signed particle ID"}; - ConfigurableAxis thnITSclumap{"thnITSclumap", {128, -0.5f, 127.5f}, "ITS cluster map"}; - ConfigurableAxis thnTPCclu{"thnTPCclu", {81, -0.5f, 160.5f}, "TPC nclust found"}; - ConfigurableAxis thnHasDet{"thnHasDet", {9, -0.5f, 8.5f}, "presence of ITS, TPC, TOF"}; - AxisSpec thnd0Axis{thnd0, "#it{d}_{r#it{#varphi}} [cm]"}; - AxisSpec thndzAxis{thndz, "#it{d}_{z} [cm]"}; - AxisSpec thnPtAxis{thnPt, "#it{p}_{T}^{reco} [GeV/#it{c}]"}; - AxisSpec thnPhiAxis{thnPhi, "#it{#phi}"}; - AxisSpec thnEtaAxis{thnEta, "#it{#eta}"}; - AxisSpec thnTypeAxis{thnType, "0:prim-1:sec-2:matsec"}; - AxisSpec thnSpecAxis{thnSpec, "signed particle ID"}; - AxisSpec thnITSclumapAxis{thnITSclumap, "ITS cluster map"}; - AxisSpec thnTPCcluAxis{thnTPCclu, "TPC nclust found"}; - AxisSpec thnHasDetAxis{thnHasDet, "presence of ITS, TPC, TOF"}; + // // Tracks selection object TrackSelection cutObject; @@ -182,6 +185,20 @@ struct qaMatchEff { // limit for z position of primary vertex Configurable zPrimVtxMax{"zPrimVtxax", 999.f, "Maximum asbolute value of z of primary vertex"}; // + // configuration for THnSparse's + // + ConfigurableAxis thnd0{"thnd0", {150, -3.0f, 3.0f}, "impact parameter in xy [cm]"}; + ConfigurableAxis thndz{"thndz", {150, -10.0f, 10.0f}, "impact parameter in z [cm]"}; + ConfigurableAxis thnPt{"thnPt", {80, 0.0f, 20.0f}, "pt [GeV/c]"}; + ConfigurableAxis thnPhi{"thnPhi", {180, 0.0f, TwoPI}, "phi"}; + ConfigurableAxis thnEta{"thnEta", {20, -2.0f, 2.0f}, "eta"}; + ConfigurableAxis thnType{"thnType", {3, -0.5f, 2.5f}, "0: primary, 1: physical secondary, 2: sec. from material"}; + ConfigurableAxis thnSpec{"thnSpec", {11, -0.5f, 10.5f}, "particle ID"}; + ConfigurableAxis thnSign{"thnSign", {3, -1.5f, 1.5f}, "sign of track"}; + // ConfigurableAxis thnITSclumap{"thnITSclumap", {128, -0.5f, 127.5f}, "ITS cluster map"}; + // ConfigurableAxis thnTPCclu{"thnTPCclu", {81, -0.5f, 160.5f}, "TPC nclust found"}; + ConfigurableAxis thnHasDet{"thnHasDet", {12, -0.5f, 11.5f}, "presence of ITS, TPC, TOF, TRD"}; + // // // ****** BE VERY CAREFUL! -- FILTERS !!! ***** // @@ -196,6 +213,8 @@ struct qaMatchEff { if (doDebug) LOG(info) << "===========================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> is it MC? = " << isitMC; // + // + // // let's know if it's MC or data if (isitMC) initMC(); @@ -216,8 +235,8 @@ struct qaMatchEff { /// initialize the track selections if (isUseTrackSelections) { // kinematics - cutObject.SetEtaRange(etaMinCut, etaMaxCut); - cutObject.SetPtRange(ptMinCut, ptMaxCut); + cutObject.SetEtaRange(kineCuts.etaMinCut, kineCuts.etaMaxCut); + cutObject.SetPtRange(kineCuts.ptMinCut, kineCuts.ptMaxCut); cutObject.SetMaxDcaXY(dcaMaxCut->get("TrVtx", "dcaXY")); /// max for dca implementend by hand in isTrackSelectedKineCuts cutObject.SetMaxDcaZ(dcaMaxCut->get("TrVtx", "dcaZ")); /// max for dca implementend by hand in isTrackSelectedKineCuts // TPC @@ -243,11 +262,38 @@ struct qaMatchEff { } LOG(info) << "############"; cutObject.SetRequireHitsInITSLayers(customMinITShits, set_customITShitmap); + } - if (isUseAnalysisTrackSelections) { - LOG(info) << "### Using analysis track selections"; - cutObject = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, 0); - LOG(info) << "### Analysis track selections set"; + if (isUseAnalysisTrackSelections) { + LOG(info) << "### Using analysis track selections"; + cutObject = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, 0); + LOG(info) << "### Analysis track selections set"; + // change the cuts get from the track selection default if requested + if (customAnaTrkSel.isChangeAnalysisCutEta) { + cutObject.SetEtaRange(kineCuts.etaMinCut, kineCuts.etaMaxCut); + LOG(info) << "### Changing analysis eta cut to " << kineCuts.etaMinCut << " - " << kineCuts.etaMaxCut; + } + if (customAnaTrkSel.isChangeAnalysisCutDcaZ) { + cutObject.SetMaxDcaZ(dcaMaxCut->get("TrVtx", "dcaZ")); + LOG(info) << "### Changing analysis DCAZ cut to " << dcaMaxCut->get("TrVtx", "dcaZ"); + } + if (customAnaTrkSel.isChangeAnalysisCutDcaXY) { + cutObject.SetMaxDcaXYPtDep([this](float /*pt*/) { return dcaMaxCut->get("TrVtx", "dcaXY"); }); + LOG(info) << "### Changing analysis DcaXY cut to " << dcaMaxCut->get("TrVtx", "dcaXY"); + } + if (customAnaTrkSel.isChangeAnalysisCutNClustersTPC) { + cutObject.SetMinNClustersTPC(tpcNClusterMin); + LOG(info) << "### Changing analysis NClustersTPC cut to " << tpcNClusterMin; + } + if (customAnaTrkSel.isChangeAnalysisITSHitmap) { + std::set set_customITShitmap; // = {}; + for (int index_ITSlayer = 0; index_ITSlayer < 7; index_ITSlayer++) { + if ((customITShitmap & (1 << index_ITSlayer)) > 0) { + set_customITShitmap.insert(static_cast(index_ITSlayer)); + } + } + cutObject.SetRequireHitsInITSLayers(customMinITShits, set_customITShitmap); + LOG(info) << "### Changing analysis ITSHitmap cut to " << customMinITShits; } } } @@ -259,60 +305,110 @@ struct qaMatchEff { { if (doDebug) LOGF(info, "*********************************************************** DATA ***************************************************"); + + // + const AxisSpec axisPDG{pdgBins, 0, pdgBins + 1.000, "pdgclass"}; + const AxisSpec axisPt{ptBins, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisX{XBins, "track x (cm)"}; + const AxisSpec axisZ{ZBins, "track z (cm)"}; + const AxisSpec axisQoPt{qoptBins, -20, 20, "#Q/it{p}_{T} (GeV/#it{c})^{-1}"}; + const AxisSpec axisEta{etaBins, kineCuts.etaMinCut, kineCuts.etaMaxCut, "#eta"}; + const AxisSpec axisPhi{phiBins, 0.f, TwoPI, "#it{#varphi} (rad)"}; + const AxisSpec axisDEta{etaBins, kineCuts.etaMinCut, kineCuts.etaMaxCut, "D#eta"}; + const AxisSpec axisDPh{phiBins, -PI, PI, "D#it{#varphi} (rad)"}; + // + // configuration for THnSparse's + // + const AxisSpec thnd0Axis{thnd0, "#it{d}_{r#it{#varphi}} [cm]"}; + const AxisSpec thndzAxis{thndz, "#it{d}_{z} [cm]"}; + const AxisSpec thnPtAxis{thnPt, "#it{p}_{T}^{reco} [GeV/#it{c}]"}; + const AxisSpec thnPhiAxis{thnPhi, "#it{#phi}"}; + const AxisSpec thnEtaAxis{thnEta, "#it{#eta}"}; + const AxisSpec thnTypeAxis{thnType, "0:prim-1:sec-2:matsec"}; + const AxisSpec thnSpecAxis{thnSpec, "particle ID"}; + const AxisSpec thnSignAxis{thnSign, "track sign"}; + const AxisSpec thnHasDetAxis{thnHasDet, "presence of ITS, TPC, TOF, TRD"}; + // const AxisSpec thnITSclumapAxis{thnITSclumap, "ITS cluster map"}; + // const AxisSpec thnTPCcluAxis{thnTPCclu, "TPC nclust found"}; + // // // data histos // // thnsparse for fractions - only if selected if (makethn) histos.add("data/sparse/thnsforfrac", "Sparse histo for imp. par. fraction analysis - data", kTHnSparseF, - {thnd0Axis, thndzAxis, thnPtAxis, thnEtaAxis, thnTypeAxis, thnPhiAxis, thnSpecAxis, thnITSclumapAxis, thnTPCcluAxis, thnHasDetAxis}); + {thnd0Axis, thndzAxis, thnPtAxis, thnEtaAxis, thnTypeAxis, thnPhiAxis, thnSpecAxis, thnSignAxis, thnHasDetAxis}); /// control plots - histos.add("data/control/itsHitsMatched", "No. of hits vs ITS layer for ITS-TPC matched tracks;layer ITS", kTH2D, {{8, -1.5, 6.5}, {8, -0.5, 7.5, "No. of hits"}}); + // histos.add("data/control/itsHitsMatched", "No. of hits vs ITS layer for ITS-TPC matched tracks;layer ITS", kTH2D, {{8, -1.5, 6.5}, {8, -0.5, 7.5, "No. of hits"}}); histos.add("data/control/zPrimary", "Position of primary vertex along beam axis;z position [cm]", kTH1D, {{200, -20.0, 20.0}}, true); histos.add("data/control/yPrimary", "Position of primary vertex along y axis;y position [cm]", kTH1D, {{200, -0.1, 0.1}}, true); histos.add("data/control/xPrimary", "Position of primary vertex along x axis;x position [cm]", kTH1D, {{200, -0.1, 0.1}}, true); histos.add("data/control/chi2Prim", "#chi^2 of primary vertex fit;#chi^2", kTH1D, {{200, 0., 100.0}}, true); - histos.add("data/control/zDCA_tpc", "DCA along z TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("data/control/xyDCA_tpc", "DCA in x-y plane TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("data/control/zDCA_tpcits", "DCA along z TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("data/control/xyDCA_tpcits", "DCA in x-y plane TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/control/zDCA_tpc", "DCA along z TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/control/xyDCA_tpc", "DCA in x-y plane TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/control/zDCA_tpcits", "DCA along z TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/control/xyDCA_tpcits", "DCA in x-y plane TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + histos.add("data/control/centrality", "Centrality distribution;centrality [%]", kTH1D, {{100, 0.0, 100.0}}, true); + histos.add("data/control/occupancy", "Number of tracks in time range;N_{tracks}", kTH1D, {{5000, 0.0, 50000.0}}, true); + // + // + if (!makehistos) + return; + // + // histos.add("data/control/itsCMnoTPC", "ITS cluster map when no TPC", kTH1D, {thnITSclumapAxis}, true); + // histos.add("data/control/itsCMwTPC", "ITS cluster map w/TPC", kTH1D, {thnITSclumapAxis}, true); + // histos.add("data/control/itsCMnoTPCwTOFnoTRD", "ITS cluster map when no TPC w/TOF no TRD", kTH1D, {thnITSclumapAxis}, true); + // histos.add("data/control/itsCMnoTPCnoTOFwTRD", "ITS cluster map when no TPC w/TRD no TOF", kTH1D, {thnITSclumapAxis}, true); + // histos.add("data/control/itsCMnoTPCwTRDwTOF", "ITS cluster map when no TPC w/TRD w/TOF", kTH1D, {thnITSclumapAxis}, true); + // histos.add("data/control/itsCMwTPCwTRDnoTOF", "ITS cluster map when TPC w/TRD no TOF", kTH1D, {thnITSclumapAxis}, true); + // histos.add("data/control/itsCMwTPCwTOFnoTRD", "ITS cluster map when TPC w/TOF no TRD", kTH1D, {thnITSclumapAxis}, true); + // histos.add("data/control/itsCMwTPCwTOFwTRD", "ITS cluster map when TPC w/TOF w/TRD", kTH1D, {thnITSclumapAxis}, true); + + // histos.add("data/control/SitsCMnoTPC", "ITS cluster map when no TPC", kTH1D, {thnITSclumapAxis}, true); + // histos.add("data/control/SitsCMwTPC", "ITS cluster map w/TPC", kTH1D, {thnITSclumapAxis}, true); + // histos.add("data/control/SitsCMnoTPCwTOFnoTRD", "ITS cluster map when no TPC w/TOF no TRD", kTH1D, {thnITSclumapAxis}, true); + // histos.add("data/control/SitsCMnoTPCnoTOFwTRD", "ITS cluster map when no TPC w/TRD no TOF", kTH1D, {thnITSclumapAxis}, true); + // histos.add("data/control/SitsCMnoTPCwTRDwTOF", "ITS cluster map when no TPC w/TRD w/TOF", kTH1D, {thnITSclumapAxis}, true); + // histos.add("data/control/SitsCMwTPCwTRDnoTOF", "ITS cluster map when TPC w/TRD no TOF", kTH1D, {thnITSclumapAxis}, true); + // histos.add("data/control/SitsCMwTPCwTOFnoTRD", "ITS cluster map when TPC w/TOF no TRD", kTH1D, {thnITSclumapAxis}, true); + // histos.add("data/control/SitsCMwTPCwTOFwTRD", "ITS cluster map when TPC w/TOF w/TRD", kTH1D, {thnITSclumapAxis}, true); // TPC found/findable clusters and crossed rows distributions - no conditions histos.add("data/TPCclust/tpcNClsFound", "Number of TPC found clusters", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable", "Number of TPC findable clusters", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows", "Number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows", "Number of TPC findable clusters minus crossed rows", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFindable", "Number of TPC findable clusters", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows", "Number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows", "Number of TPC findable clusters minus crossed rows", kTH1F, {{200, -200.0, 200.0}}, true); histos.add("data/TPCclust/tpcNClsFound_tpc", "Number of TPC found clusters - TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_tpc", "Number of TPC findable clusters - TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_tpc", "Number of TPC crossed rows - TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_tpc", "Number of TPC findable clusters minus crossed rows - TPC tag", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_tpc", "Number of TPC findable clusters - TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_tpc", "Number of TPC crossed rows - TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_tpc", "Number of TPC findable clusters minus crossed rows - TPC tag", kTH1F, {{200, -200.0, 200.0}}, true); histos.add("data/TPCclust/tpcNClsFound_tpcits", "Number of TPC found clusters - TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_tpcits", "Number of TPC findable clusters - TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_tpcits", "Number of TPC crossed rows - TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_tpcits", "Number of TPC findable clusters minus crossed rows - TPC+ITS tag", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_tpcits", "Number of TPC findable clusters - TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_tpcits", "Number of TPC crossed rows - TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_tpcits", "Number of TPC findable clusters minus crossed rows - TPC+ITS tag", kTH1F, {{200, -200.0, 200.0}}, true); // // in [1,2] GeV pt interval - histos.add("data/TPCclust/tpcNClsFound_tpc_1g", "Number of TPC found clusters - TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_tpc_1g", "Number of TPC findable clusters - TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_tpc_1g", "Number of TPC crossed rows - TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_tpc_1g", "Number of TPC findable clusters minus crossed rows - TPC tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFound_tpc_1g", "Number of TPC found clusters - TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_tpc_1g", "Number of TPC findable clusters - TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_tpc_1g", "Number of TPC crossed rows - TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_tpc_1g", "Number of TPC findable clusters minus crossed rows - TPC tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); - histos.add("data/TPCclust/tpcNClsFound_tpcits_1g", "Number of TPC found clusters - TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_tpcits_1g", "Number of TPC findable clusters - TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_tpcits_1g", "Number of TPC crossed rows - TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_tpcits_1g", "Number of TPC findable clusters minus crossed rows - TPC+ITS tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFound_tpcits_1g", "Number of TPC found clusters - TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_tpcits_1g", "Number of TPC findable clusters - TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_tpcits_1g", "Number of TPC crossed rows - TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_tpcits_1g", "Number of TPC findable clusters minus crossed rows - TPC+ITS tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); /// compare pt's (tracking and innerParamTPC) - if (makept2d) { - histos.add("data/control/ptptconfTPCall", "Tracking pt vs TPC inner wall pt - TPC tag", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); - histos.add("data/control/ptptconfITSall", "Tracking pt vs TPC inner wall pt - ITS tag", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); - histos.add("data/control/ptptconfTPCITS", "Tracking pt vs TPC inner wall pt - TPC & ITS tag", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); - histos.add("data/control/ptptconfITSo", "Tracking pt vs TPC inner wall pt - ITS-only tracks", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); - histos.add("data/control/ptptconfTPCo", "Tracking pt vs TPC inner wall pt - TPC-only tracks", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); - } + // if (makept2d) { + // histos.add("data/control/ptptconfTPCall", "Tracking pt vs TPC inner wall pt - TPC tag", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); + // histos.add("data/control/ptptconfITSall", "Tracking pt vs TPC inner wall pt - ITS tag", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); + // histos.add("data/control/ptptconfTPCITS", "Tracking pt vs TPC inner wall pt - TPC & ITS tag", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); + // histos.add("data/control/ptptconfITSo", "Tracking pt vs TPC inner wall pt - ITS-only tracks", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); + // histos.add("data/control/ptptconfTPCo", "Tracking pt vs TPC inner wall pt - TPC-only tracks", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); + // } // // tpc, its and tpc+its request for all, positive and negative charges vs @@ -331,10 +427,10 @@ struct qaMatchEff { // // local X,Z of track - histos.add("data/control/trackXhist_tpcONLY", "x distribution - data TPC ONLY tag", kTH1D, {axisX}, true); - histos.add("data/control/trackXhist_tpcits", "x distribution - data TPC+ITS tag", kTH1D, {axisX}, true); - histos.add("data/control/trackZhist_tpcONLY", "z distribution - data TPC ONLY tag", kTH1D, {axisZ}, true); - histos.add("data/control/trackZhist_tpcits", "z distribution - data TPC+ITS tag", kTH1D, {axisZ}, true); + // histos.add("data/control/trackXhist_tpcONLY", "x distribution - data TPC ONLY tag", kTH1D, {axisX}, true); + // histos.add("data/control/trackXhist_tpcits", "x distribution - data TPC+ITS tag", kTH1D, {axisX}, true); + // histos.add("data/control/trackZhist_tpcONLY", "z distribution - data TPC ONLY tag", kTH1D, {axisZ}, true); + // histos.add("data/control/trackZhist_tpcits", "z distribution - data TPC+ITS tag", kTH1D, {axisZ}, true); // pt, phi, eta TOF tagged histos.add("data/pthist_toftpc", "#it{p}_{T} distribution - data TOF+TPC tag", kTH1D, {axisPt}, true); @@ -347,10 +443,10 @@ struct qaMatchEff { // // if you want just pions if (isPIDPionRequired) { - histos.add("data/PID/zDCA_tpc_pi", "DCA along z - pions TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("data/PID/xyDCA_tpc_pi", "DCA in x-y plane - pions TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("data/PID/zDCA_tpcits_pi", "DCA along z - pions TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("data/PID/xyDCA_tpcits_pi", "DCA in x-y plane - pions TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/PID/zDCA_tpc_pi", "DCA along z - pions TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/PID/xyDCA_tpc_pi", "DCA in x-y plane - pions TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/PID/zDCA_tpcits_pi", "DCA along z - pions TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/PID/xyDCA_tpcits_pi", "DCA in x-y plane - pions TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); histos.add("data/PID/pthist_tpc_pi", "#it{p}_{T} distribution - data TPC tag - pions", kTH1D, {axisPt}, true); histos.add("data/PID/etahist_tpc_pi", "#eta distribution - data TPC tag - pions", kTH1D, {axisEta}, true); @@ -404,31 +500,31 @@ struct qaMatchEff { // TPC found clusters distribution histos.add("data/TPCclust/tpcNClsFound_pi", "Number of TPC found clusters - pions", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_pi", "Number of TPC findable clusters - pions", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_pi", "Number of TPC crossed rows - pions", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pi", "Number of TPC findable clusters minus crossed rows - pions", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_pi", "Number of TPC findable clusters - pions", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_pi", "Number of TPC crossed rows - pions", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pi", "Number of TPC findable clusters minus crossed rows - pions", kTH1F, {{200, -200.0, 200.0}}, true); histos.add("data/TPCclust/tpcNClsFound_pi_tpc", "Number of TPC found clusters - TPC tag - pions", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_pi_tpc", "Number of TPC findable clusters - TPC tag - pions", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_pi_tpc", "Number of TPC crossed rows - TPC tag - pions", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pi_tpc", "Number of TPC findable clusters minus crossed rows - TPC tag - pions", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_pi_tpc", "Number of TPC findable clusters - TPC tag - pions", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_pi_tpc", "Number of TPC crossed rows - TPC tag - pions", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pi_tpc", "Number of TPC findable clusters minus crossed rows - TPC tag - pions", kTH1F, {{200, -200.0, 200.0}}, true); histos.add("data/TPCclust/tpcNClsFound_pi_tpcits", "Number of TPC found clusters - TPC+ITS tag - pions", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_pi_tpcits", "Number of TPC findable clusters - TPC+ITS tag - pions", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_pi_tpcits", "Number of TPC crossed rows - TPC+ITS tag - pions", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pi_tpcits", "Number of TPC findable clusters minus crossed rows - TPC+ITS tag - pions", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_pi_tpcits", "Number of TPC findable clusters - TPC+ITS tag - pions", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_pi_tpcits", "Number of TPC crossed rows - TPC+ITS tag - pions", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pi_tpcits", "Number of TPC findable clusters minus crossed rows - TPC+ITS tag - pions", kTH1F, {{200, -200.0, 200.0}}, true); // // in [1,2] GeV pt interval - histos.add("data/TPCclust/tpcNClsFound_pi_tpc_1g", "Number of TPC found clusters pions TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_pi_tpc_1g", "Number of TPC findable clusters pions TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_pi_tpc_1g", "Number of TPC crossed rows pions TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pi_tpc_1g", "Number of TPC findable clusters minus crossed rows pions TPC tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFound_pi_tpc_1g", "Number of TPC found clusters pions TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_pi_tpc_1g", "Number of TPC findable clusters pions TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_pi_tpc_1g", "Number of TPC crossed rows pions TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pi_tpc_1g", "Number of TPC findable clusters minus crossed rows pions TPC tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); - histos.add("data/TPCclust/tpcNClsFound_pi_tpcits_1g", "Number of TPC found clusters pions TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_pi_tpcits_1g", "Number of TPC findable clusters pions TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_pi_tpcits_1g", "Number of TPC crossed rows pions TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pi_tpcits_1g", "Number of TPC findable clusters minus crossed rows pions TPC+ITS tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFound_pi_tpcits_1g", "Number of TPC found clusters pions TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_pi_tpcits_1g", "Number of TPC findable clusters pions TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_pi_tpcits_1g", "Number of TPC crossed rows pions TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pi_tpcits_1g", "Number of TPC findable clusters minus crossed rows pions TPC+ITS tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); // plus histos.add("data/PID/pthist_tpc_piplus", "#it{p}_{T} distribution - data TPC tag - pos. pions", kTH1D, {axisPt}, true); @@ -452,36 +548,36 @@ struct qaMatchEff { if (isPIDKaonRequired) { // // in [1,2] GeV pt interval - histos.add("data/TPCclust/tpcNClsFound_ka_tpc_1g", "Number of TPC found clusters kaons TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_ka_tpc_1g", "Number of TPC findable clusters kaons TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_ka_tpc_1g", "Number of TPC crossed rows kaons TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_ka_tpc_1g", "Number of TPC findable clusters minus crossed rows kaons TPC tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFound_ka_tpc_1g", "Number of TPC found clusters kaons TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_ka_tpc_1g", "Number of TPC findable clusters kaons TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_ka_tpc_1g", "Number of TPC crossed rows kaons TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_ka_tpc_1g", "Number of TPC findable clusters minus crossed rows kaons TPC tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); histos.add("data/TPCclust/tpcNClsFound_ka_tpcits_1g", "Number of TPC found clusters kaons TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_ka_tpcits_1g", "Number of TPC findable clusters kaons TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_ka_tpcits_1g", "Number of TPC crossed rows kaons TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_ka_tpcits_1g", "Number of TPC findable clusters minus crossed rows kaons TPC+ITS tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_ka_tpcits_1g", "Number of TPC findable clusters kaons TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_ka_tpcits_1g", "Number of TPC crossed rows kaons TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_ka_tpcits_1g", "Number of TPC findable clusters minus crossed rows kaons TPC+ITS tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); // TPC found clusters distribution histos.add("data/TPCclust/tpcNClsFound_ka", "Number of TPC found clusters - kaons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_ka", "Number of TPC findable clusters - kaons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_ka", "Number of TPC crossed rows - kaons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_ka", "Number of TPC findable clusters minus crossed rows - kaons", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_ka", "Number of TPC findable clusters - kaons", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_ka", "Number of TPC crossed rows - kaons", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_ka", "Number of TPC findable clusters minus crossed rows - kaons", kTH1F, {{200, -200.0, 200.0}}, true); histos.add("data/TPCclust/tpcNClsFound_ka_tpc", "Number of TPC found clusters - TPC tag - kaons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_ka_tpc", "Number of TPC findable clusters - TPC tag - kaons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_ka_tpc", "Number of TPC crossed rows - TPC tag - kaons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_ka_tpc", "Number of TPC findable clusters minus crossed rows - TPC tag - kaons", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_ka_tpc", "Number of TPC findable clusters - TPC tag - kaons", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_ka_tpc", "Number of TPC crossed rows - TPC tag - kaons", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_ka_tpc", "Number of TPC findable clusters minus crossed rows - TPC tag - kaons", kTH1F, {{200, -200.0, 200.0}}, true); histos.add("data/TPCclust/tpcNClsFound_ka_tpcits", "Number of TPC found clusters - TPC+ITS tag - kaons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_ka_tpcits", "Number of TPC findable clusters - TPC+ITS tag - kaons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_ka_tpcits", "Number of TPC crossed rows - TPC+ITS tag - kaons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_ka_tpcits", "Number of TPC findable clusters minus crossed rows - TPC+ITS tag - kaons", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_ka_tpcits", "Number of TPC findable clusters - TPC+ITS tag - kaons", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_ka_tpcits", "Number of TPC crossed rows - TPC+ITS tag - kaons", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_ka_tpcits", "Number of TPC findable clusters minus crossed rows - TPC+ITS tag - kaons", kTH1F, {{200, -200.0, 200.0}}, true); - histos.add("data/PID/zDCA_tpc_ka", "DCA along z - kaons TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("data/PID/xyDCA_tpc_ka", "DCA in x-y plane - kaons TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("data/PID/zDCA_tpcits_ka", "DCA along z - kaons TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("data/PID/xyDCA_tpcits_ka", "DCA in x-y plane - kaons TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/PID/zDCA_tpc_ka", "DCA along z - kaons TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/PID/xyDCA_tpc_ka", "DCA in x-y plane - kaons TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/PID/zDCA_tpcits_ka", "DCA along z - kaons TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/PID/xyDCA_tpcits_ka", "DCA in x-y plane - kaons TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); histos.add("data/PID/pthist_tpc_ka", "#it{p}_{T} distribution - data TPC tag - kaons", kTH1D, {axisPt}, true); histos.add("data/PID/etahist_tpc_ka", "#eta distribution - data TPC tag - kaons", kTH1D, {axisEta}, true); @@ -555,37 +651,37 @@ struct qaMatchEff { if (isPIDProtonRequired) { // // in [1,2] GeV pt interval - histos.add("data/TPCclust/tpcNClsFound_pr_tpc_1g", "Number of TPC found clusters protons TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_pr_tpc_1g", "Number of TPC findable clusters protons TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_pr_tpc_1g", "Number of TPC crossed rows protons TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pr_tpc_1g", "Number of TPC findable clusters minus crossed rows protons TPC tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFound_pr_tpc_1g", "Number of TPC found clusters protons TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_pr_tpc_1g", "Number of TPC findable clusters protons TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_pr_tpc_1g", "Number of TPC crossed rows protons TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pr_tpc_1g", "Number of TPC findable clusters minus crossed rows protons TPC tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); - histos.add("data/TPCclust/tpcNClsFound_pr_tpcits_1g", "Number of TPC found clusters protons TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_pr_tpcits_1g", "Number of TPC findable clusters protons TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_pr_tpcits_1g", "Number of TPC crossed rows protons TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pr_tpcits_1g", "Number of TPC findable clusters minus crossed rows protons TPC+ITS tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFound_pr_tpcits_1g", "Number of TPC found clusters protons TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_pr_tpcits_1g", "Number of TPC findable clusters protons TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_pr_tpcits_1g", "Number of TPC crossed rows protons TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pr_tpcits_1g", "Number of TPC findable clusters minus crossed rows protons TPC+ITS tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); // // TPC found clusters distribution histos.add("data/TPCclust/tpcNClsFound_pr", "Number of TPC found clusters - protons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_pr", "Number of TPC findable clusters - protons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_pr", "Number of TPC crossed rows - protons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pr", "Number of TPC findable clusters minus crossed rows - protons", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_pr", "Number of TPC findable clusters - protons", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_pr", "Number of TPC crossed rows - protons", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pr", "Number of TPC findable clusters minus crossed rows - protons", kTH1F, {{200, -200.0, 200.0}}, true); histos.add("data/TPCclust/tpcNClsFound_pr_tpc", "Number of TPC found clusters - TPC tag - protons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_pr_tpc", "Number of TPC findable clusters - TPC tag - protons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_pr_tpc", "Number of TPC crossed rows - TPC tag - protons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pr_tpc", "Number of TPC findable clusters minus crossed rows - TPC tag - protons", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_pr_tpc", "Number of TPC findable clusters - TPC tag - protons", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_pr_tpc", "Number of TPC crossed rows - TPC tag - protons", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pr_tpc", "Number of TPC findable clusters minus crossed rows - TPC tag - protons", kTH1F, {{200, -200.0, 200.0}}, true); histos.add("data/TPCclust/tpcNClsFound_pr_tpcits", "Number of TPC found clusters - TPC+ITS tag - protons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcNClsFindable_pr_tpcits", "Number of TPC findable clusters - TPC+ITS tag - protons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcCrossedRows_pr_tpcits", "Number of TPC crossed rows - TPC+ITS tag - protons", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pr_tpcits", "Number of TPC findable clusters minus crossed rows - TPC+ITS tag - protons", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("data/TPCclust/tpcNClsFindable_pr_tpcits", "Number of TPC findable clusters - TPC+ITS tag - protons", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcCrossedRows_pr_tpcits", "Number of TPC crossed rows - TPC+ITS tag - protons", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("data/TPCclust/tpcsFindableMinusCrossedRows_pr_tpcits", "Number of TPC findable clusters minus crossed rows - TPC+ITS tag - protons", kTH1F, {{200, -200.0, 200.0}}, true); - histos.add("data/PID/zDCA_tpc_pr", "DCA along z - protons TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("data/PID/xyDCA_tpc_pr", "DCA in x-y plane - protons TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("data/PID/zDCA_tpcits_pr", "DCA along z - protons TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("data/PID/xyDCA_tpcits_pr", "DCA in x-y plane - protons TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/PID/zDCA_tpc_pr", "DCA along z - protons TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/PID/xyDCA_tpc_pr", "DCA in x-y plane - protons TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/PID/zDCA_tpcits_pr", "DCA along z - protons TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/PID/xyDCA_tpcits_pr", "DCA in x-y plane - protons TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); histos.add("data/PID/pthist_tpc_pr", "#it{p}_{T} distribution - data TPC tag - protons", kTH1D, {axisPt}, true); histos.add("data/PID/etahist_tpc_pr", "#eta distribution - data TPC tag - protons", kTH1D, {axisEta}, true); @@ -681,10 +777,10 @@ struct qaMatchEff { histos.add("data/PID/etahist_tpcits_noidminus", "#eta distribution - data TPC+ITS tag - neg. no ident.", kTH1D, {axisEta}, true); histos.add("data/PID/phihist_tpcits_noidminus", "#phi distribution - data TPC+ITS tag - neg. no ident. ", kTH1D, {axisPhi}, true); // - histos.add("data/PID/zDCA_tpc_noid", "DCA along z - no pi/K/P TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("data/PID/xyDCA_tpc_noid", "DCA in x-y plane - no pi/K/P TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("data/PID/zDCA_tpcits_noid", "DCA along z - no pi/K/P TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("data/PID/xyDCA_tpcits_noid", "DCA in x-y plane - no pi/K/P TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/PID/zDCA_tpc_noid", "DCA along z - no pi/K/P TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/PID/xyDCA_tpc_noid", "DCA in x-y plane - no pi/K/P TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/PID/zDCA_tpcits_noid", "DCA along z - no pi/K/P TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("data/PID/xyDCA_tpcits_noid", "DCA in x-y plane - no pi/K/P TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); } // @@ -705,13 +801,13 @@ struct qaMatchEff { histos.add("data/phihist_tpcits_neg", "#phi distribution - data q<0 TPC+ITS tag", kTH1D, {axisPhi}, true); // // pt>0.5 GeV/c threshold - histos.add("data/pthist_tpc_05", "#it{p}_{T} distribution - data TPC tag, #it{p}_{T}>0.5", kTH1D, {axisPt}, true); - histos.add("data/etahist_tpc_05", "#eta distribution - data TPC tag, #it{p}_{T}>0.5", kTH1D, {axisEta}, true); - histos.add("data/phihist_tpc_05", "#phi distribution - data TPC tag, #it{p}_{T}>0.5", kTH1D, {axisPhi}, true); + // histos.add("data/pthist_tpc_05", "#it{p}_{T} distribution - data TPC tag, #it{p}_{T}>0.5", kTH1D, {axisPt}, true); + // histos.add("data/etahist_tpc_05", "#eta distribution - data TPC tag, #it{p}_{T}>0.5", kTH1D, {axisEta}, true); + // histos.add("data/phihist_tpc_05", "#phi distribution - data TPC tag, #it{p}_{T}>0.5", kTH1D, {axisPhi}, true); - histos.add("data/pthist_tpcits_05", "#it{p}_{T} distribution - data TPC+ITS tag #it{p}_{T}>0.5", kTH1D, {axisPt}, true); - histos.add("data/etahist_tpcits_05", "#eta distribution - data TPC+ITS tag #it{p}_{T}>0.5", kTH1D, {axisEta}, true); - histos.add("data/phihist_tpcits_05", "#phi distribution - data TPC+ITS tag #it{p}_{T}>0.5", kTH1D, {axisPhi}, true); + // histos.add("data/pthist_tpcits_05", "#it{p}_{T} distribution - data TPC+ITS tag #it{p}_{T}>0.5", kTH1D, {axisPt}, true); + // histos.add("data/etahist_tpcits_05", "#eta distribution - data TPC+ITS tag #it{p}_{T}>0.5", kTH1D, {axisEta}, true); + // histos.add("data/phihist_tpcits_05", "#phi distribution - data TPC+ITS tag #it{p}_{T}>0.5", kTH1D, {axisPhi}, true); } // // Init MC function @@ -719,6 +815,31 @@ struct qaMatchEff { { if (doDebug) LOGF(info, " +++++++++++++++++++++++ MC ++++++++++++++++++++++++"); + // + const AxisSpec axisPDG{pdgBins, 0, pdgBins + 1.000, "pdgclass"}; + const AxisSpec axisPt{ptBins, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisX{XBins, "track x (cm)"}; + const AxisSpec axisZ{ZBins, "track z (cm)"}; + const AxisSpec axisQoPt{qoptBins, -20, 20, "#Q/it{p}_{T} (GeV/#it{c})^{-1}"}; + const AxisSpec axisEta{etaBins, kineCuts.etaMinCut, kineCuts.etaMaxCut, "#eta"}; + const AxisSpec axisPhi{phiBins, 0.f, TwoPI, "#it{#varphi} (rad)"}; + const AxisSpec axisDEta{etaBins, kineCuts.etaMinCut, kineCuts.etaMaxCut, "D#eta"}; + const AxisSpec axisDPh{phiBins, -PI, PI, "D#it{#varphi} (rad)"}; + // + // + // configuration for THnSparse's + // + const AxisSpec thnd0Axis{thnd0, "#it{d}_{r#it{#varphi}} [cm]"}; + const AxisSpec thndzAxis{thndz, "#it{d}_{z} [cm]"}; + const AxisSpec thnPtAxis{thnPt, "#it{p}_{T}^{reco} [GeV/#it{c}]"}; + const AxisSpec thnPhiAxis{thnPhi, "#it{#phi}"}; + const AxisSpec thnEtaAxis{thnEta, "#it{#eta}"}; + const AxisSpec thnTypeAxis{thnType, "0:prim-1:sec-2:matsec"}; + const AxisSpec thnSpecAxis{thnSpec, "particle ID"}; + const AxisSpec thnSignAxis{thnSign, "track sign"}; + // const AxisSpec thnITSclumapAxis{thnITSclumap, "ITS cluster map"}; + // const AxisSpec thnTPCcluAxis{thnTPCclu, "TPC nclust found"}; + const AxisSpec thnHasDetAxis{thnHasDet, "presence of ITS, TPC, TOF, TRD"}; // // adding histos to the registry @@ -731,60 +852,84 @@ struct qaMatchEff { // thnsparse for fractions if (makethn) histos.add("MC/sparse/thnsforfrac", "Sparse histo for imp. par. fraction analysis - MC", kTHnSparseF, - {thnd0Axis, thndzAxis, thnPtAxis, thnEtaAxis, thnTypeAxis, thnPhiAxis, thnSpecAxis, thnITSclumapAxis, thnTPCcluAxis, thnHasDetAxis}); + {thnd0Axis, thndzAxis, thnPtAxis, thnEtaAxis, thnTypeAxis, thnPhiAxis, thnSpecAxis, thnSignAxis, thnHasDetAxis}); /// control plots - histos.add("MC/control/itsHitsMatched", "No. of hits vs ITS layer for ITS-TPC matched tracks;layer ITS", kTH2D, {{8, -1.5, 6.5}, {8, -0.5, 7.5, "No. of hits"}}); + // histos.add("MC/control/itsHitsMatched", "No. of hits vs ITS layer for ITS-TPC matched tracks;layer ITS", kTH2D, {{8, -1.5, 6.5}, {8, -0.5, 7.5, "No. of hits"}}); histos.add("MC/control/zPrimary", "Position of primary vertex along beam axis;z position [cm]", kTH1D, {{200, -20.0, 20.0}}, true); histos.add("MC/control/yPrimary", "Position of primary vertex along y axis;y position [cm]", kTH1D, {{200, -0.1, 0.1}}, true); histos.add("MC/control/xPrimary", "Position of primary vertex along x axis;x position [cm]", kTH1D, {{200, -0.1, 0.1}}, true); histos.add("MC/control/chi2Prim", "#chi^2 of primary vertex fit;#chi^2", kTH1D, {{200, 0., 100.0}}, true); - histos.add("MC/control/zDCA_tpc", "DCA along z TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/control/xyDCA_tpc", "DCA in x-y plane TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/control/zDCA_tpcits", "DCA along z TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/control/xyDCA_tpcits", "DCA in x-y plane TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/control/zDCA_tpc", "DCA along z TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/control/xyDCA_tpc", "DCA in x-y plane TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/control/zDCA_tpcits", "DCA along z TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/control/xyDCA_tpcits", "DCA in x-y plane TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + histos.add("MC/control/centrality", "Centrality distribution;centrality [%]", kTH1D, {{100, 0.0, 100.0}}, true); + + if (!makehistos) + return; + // + // control plots + // histos.add("MC/control/itsCMnoTPC", "ITS cluster map when no TPC", kTH1D, {thnITSclumapAxis}, true); + // histos.add("MC/control/itsCMwTPC", "ITS cluster map w/TPC", kTH1D, {thnITSclumapAxis}, true); + // histos.add("MC/control/itsCMnoTPCwTOFnoTRD", "ITS cluster map when no TPC w/TOF no TRD", kTH1D, {thnITSclumapAxis}, true); + // histos.add("MC/control/itsCMnoTPCnoTOFwTRD", "ITS cluster map when no TPC w/TRD no TOF", kTH1D, {thnITSclumapAxis}, true); + // histos.add("MC/control/itsCMnoTPCwTRDwTOF", "ITS cluster map when no TPC w/TRD w/TOF", kTH1D, {thnITSclumapAxis}, true); + // histos.add("MC/control/itsCMwTPCwTRDnoTOF", "ITS cluster map when TPC w/TRD no TOF", kTH1D, {thnITSclumapAxis}, true); + // histos.add("MC/control/itsCMwTPCwTOFnoTRD", "ITS cluster map when TPC w/TOF no TRD", kTH1D, {thnITSclumapAxis}, true); + // histos.add("MC/control/itsCMwTPCwTOFwTRD", "ITS cluster map when TPC w/TOF w/TRD", kTH1D, {thnITSclumapAxis}, true); + + // histos.add("MC/control/SitsCMnoTPC", "ITS cluster map when no TPC", kTH1D, {thnITSclumapAxis}, true); + // histos.add("MC/control/SitsCMwTPC", "ITS cluster map w/TPC", kTH1D, {thnITSclumapAxis}, true); + // histos.add("MC/control/SitsCMnoTPCwTOFnoTRD", "ITS cluster map when no TPC w/TOF no TRD", kTH1D, {thnITSclumapAxis}, true); + // histos.add("MC/control/SitsCMnoTPCnoTOFwTRD", "ITS cluster map when no TPC w/TRD no TOF", kTH1D, {thnITSclumapAxis}, true); + // histos.add("MC/control/SitsCMnoTPCwTRDwTOF", "ITS cluster map when no TPC w/TRD w/TOF", kTH1D, {thnITSclumapAxis}, true); + // histos.add("MC/control/SitsCMwTPCwTRDnoTOF", "ITS cluster map when TPC w/TRD no TOF", kTH1D, {thnITSclumapAxis}, true); + // histos.add("MC/control/SitsCMwTPCwTOFnoTRD", "ITS cluster map when TPC w/TOF no TRD", kTH1D, {thnITSclumapAxis}, true); + // histos.add("MC/control/SitsCMwTPCwTOFwTRD", "ITS cluster map when TPC w/TOF w/TRD", kTH1D, {thnITSclumapAxis}, true); + // // local X,Z of track - histos.add("MC/control/trackXhist_tpcONLY", "x distribution - data TPC ONLY tag", kTH1D, {axisX}, true); - histos.add("MC/control/trackXhist_tpcits", "x distribution - data TPC+ITS tag", kTH1D, {axisX}, true); - histos.add("MC/control/trackZhist_tpcONLY", "z distribution - data TPC ONLY tag", kTH1D, {axisZ}, true); - histos.add("MC/control/trackZhist_tpcits", "z distribution - data TPC+ITS tag", kTH1D, {axisZ}, true); + // histos.add("MC/control/trackXhist_tpcONLY", "x distribution - data TPC ONLY tag", kTH1D, {axisX}, true); + // histos.add("MC/control/trackXhist_tpcits", "x distribution - data TPC+ITS tag", kTH1D, {axisX}, true); + // histos.add("MC/control/trackZhist_tpcONLY", "z distribution - data TPC ONLY tag", kTH1D, {axisZ}, true); + // histos.add("MC/control/trackZhist_tpcits", "z distribution - data TPC+ITS tag", kTH1D, {axisZ}, true); // TPC found/findable clusters and crossed rows distributions - no conditions histos.add("MC/TPCclust/tpcNClsFound", "Number of TPC found clusters", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable", "Number of TPC findable clusters", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows", "Number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows", "Number of TPC findable clusters minus crossed rows", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable", "Number of TPC findable clusters", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows", "Number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows", "Number of TPC findable clusters minus crossed rows", kTH1F, {{200, -200.0, 200.0}}, true); histos.add("MC/TPCclust/tpcNClsFound_tpc", "Number of TPC found clusters - TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_tpc", "Number of TPC findable clusters - TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_tpc", "Number of TPC crossed rows - TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_tpc", "Number of TPC findable clusters minus crossed rows - TPC tag", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_tpc", "Number of TPC findable clusters - TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_tpc", "Number of TPC crossed rows - TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_tpc", "Number of TPC findable clusters minus crossed rows - TPC tag", kTH1F, {{200, -200.0, 200.0}}, true); histos.add("MC/TPCclust/tpcNClsFound_tpcits", "Number of TPC found clusters - TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_tpcits", "Number of TPC findable clusters - TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_tpcits", "Number of TPC crossed rows - TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_tpcits", "Number of TPC findable clusters minus crossed rows - TPC+ITS tag", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_tpcits", "Number of TPC findable clusters - TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_tpcits", "Number of TPC crossed rows - TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_tpcits", "Number of TPC findable clusters minus crossed rows - TPC+ITS tag", kTH1F, {{200, -200.0, 200.0}}, true); // // pt in [1,2] GeV - histos.add("MC/TPCclust/tpcNClsFound_tpc_1g", "Number of TPC found clusters - TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_tpc_1g", "Number of TPC findable clusters - TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_tpc_1g", "Number of TPC crossed rows - TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_tpc_1g", "Number of TPC findable clusters minus crossed rows - TPC tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFound_tpc_1g", "Number of TPC found clusters - TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_tpc_1g", "Number of TPC findable clusters - TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_tpc_1g", "Number of TPC crossed rows - TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_tpc_1g", "Number of TPC findable clusters minus crossed rows - TPC tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); - histos.add("MC/TPCclust/tpcNClsFound_tpcits_1g", "Number of TPC found clusters - TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_tpcits_1g", "Number of TPC findable clusters - TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_tpcits_1g", "Number of TPC crossed rows - TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_tpcits_1g", "Number of TPC findable clusters minus crossed rows - TPC+ITS tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFound_tpcits_1g", "Number of TPC found clusters - TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_tpcits_1g", "Number of TPC findable clusters - TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_tpcits_1g", "Number of TPC crossed rows - TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_tpcits_1g", "Number of TPC findable clusters minus crossed rows - TPC+ITS tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); /// compare pt's (tracking and innerParamTPC) - if (makept2d) { - histos.add("MC/control/ptptconfTPCall", "Tracking pt vs TPC inner wall pt - TPC tag", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); - histos.add("MC/control/ptptconfITSall", "Tracking pt vs TPC inner wall pt - ITS tag", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); - histos.add("MC/control/ptptconfTPCITS", "Tracking pt vs TPC inner wall pt - TPC & ITS tag", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); - histos.add("MC/control/ptptconfITSo", "Tracking pt vs TPC inner wall pt - ITS-only tracks", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); - histos.add("MC/control/ptptconfTPCo", "Tracking pt vs TPC inner wall pt - TPC-only tracks", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); - } + // if (makept2d) { + // histos.add("MC/control/ptptconfTPCall", "Tracking pt vs TPC inner wall pt - TPC tag", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); + // histos.add("MC/control/ptptconfITSall", "Tracking pt vs TPC inner wall pt - ITS tag", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); + // histos.add("MC/control/ptptconfTPCITS", "Tracking pt vs TPC inner wall pt - TPC & ITS tag", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); + // histos.add("MC/control/ptptconfITSo", "Tracking pt vs TPC inner wall pt - ITS-only tracks", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); + // histos.add("MC/control/ptptconfTPCo", "Tracking pt vs TPC inner wall pt - TPC-only tracks", kTH2D, {{100, 0.0, 10.0, "tracking #it{p}_{T}"}, {100, 0.0, 10.0, "TPC #it{p}_{T}"}}); + // } // // all, positive, negative @@ -833,11 +978,11 @@ struct qaMatchEff { histos.add("MC/primsec/qopthist_tpc_prim", "Q/#it{p}_{T} distribution - MC prim TPC tag", kTH1D, {axisQoPt}, true); histos.add("MC/primsec/qopthist_tpcits_prim", "Q/#it{p}_{T} distribution - MC prim TPC+ITS tag", kTH1D, {axisQoPt}, true); - histos.add("MC/primsec/zDCA_tpc_prim", "DCA along z TPC tag - primaries;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/primsec/zDCA_tpcits_prim", "DCA along z TPC+ITS tag - primaries;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/primsec/zDCA_tpc_prim", "DCA along z TPC tag - primaries;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/primsec/zDCA_tpcits_prim", "DCA along z TPC+ITS tag - primaries;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/primsec/xyDCA_tpc_prim", "DCA in x-y plane TPC tag - primaries;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/primsec/xyDCA_tpcits_prim", "DCA in x-y plane TPC+ITS tag - primaries;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/primsec/xyDCA_tpc_prim", "DCA in x-y plane TPC tag - primaries;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/primsec/xyDCA_tpcits_prim", "DCA in x-y plane TPC+ITS tag - primaries;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); histos.add("MC/primsec/pthist_tpc_prim", "#it{p}_{T} distribution - MC prim TPC tag", kTH1D, {axisPt}, true); histos.add("MC/primsec/etahist_tpc_prim", "#eta distribution - MC prim TPC tag", kTH1D, {axisEta}, true); @@ -851,11 +996,11 @@ struct qaMatchEff { histos.add("MC/primsec/qopthist_tpc_secd", "Q/#it{p}_{T} distribution - MC dec. sec. TPC tag", kTH1D, {axisQoPt}, true); histos.add("MC/primsec/qopthist_tpcits_secd", "Q/#it{p}_{T} distribution - MC dec. sec. TPC+ITS tag", kTH1D, {axisQoPt}, true); - histos.add("MC/primsec/zDCA_tpc_secd", "DCA along z TPC tag - secd;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/primsec/zDCA_tpcits_secd", "DCA along z TPC+ITS tag - secd;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/primsec/zDCA_tpc_secd", "DCA along z TPC tag - secd;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/primsec/zDCA_tpcits_secd", "DCA along z TPC+ITS tag - secd;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/primsec/xyDCA_tpc_secd", "DCA in x-y plane TPC tag - secd;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/primsec/xyDCA_tpcits_secd", "DCA in x-y plane TPC+ITS tag - secd;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/primsec/xyDCA_tpc_secd", "DCA in x-y plane TPC tag - secd;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/primsec/xyDCA_tpcits_secd", "DCA in x-y plane TPC+ITS tag - secd;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); histos.add("MC/primsec/pthist_tpc_secd", "#it{p}_{T} distribution - MC dec. sec. TPC tag", kTH1D, {axisPt}, true); histos.add("MC/primsec/etahist_tpc_secd", "#eta distribution - MC dec. sec. TPC tag", kTH1D, {axisEta}, true); @@ -869,11 +1014,11 @@ struct qaMatchEff { histos.add("MC/primsec/qopthist_tpc_secm", "Q/#it{p}_{T} distribution - MC mat. sec. TPC tag", kTH1D, {axisQoPt}, true); histos.add("MC/primsec/qopthist_tpcits_secm", "Q/#it{p}_{T} distribution - MC mat. sec. TPC+ITS tag", kTH1D, {axisQoPt}, true); - histos.add("MC/primsec/zDCA_tpc_secm", "DCA along z TPC tag - secm;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/primsec/zDCA_tpcits_secm", "DCA along z TPC+ITS tag - secm;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/primsec/zDCA_tpc_secm", "DCA along z TPC tag - secm;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/primsec/zDCA_tpcits_secm", "DCA along z TPC+ITS tag - secm;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/primsec/xyDCA_tpc_secm", "DCA in x-y plane TPC tag - secm;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/primsec/xyDCA_tpcits_secm", "DCA in x-y plane TPC+ITS tag - secm;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/primsec/xyDCA_tpc_secm", "DCA in x-y plane TPC tag - secm;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/primsec/xyDCA_tpcits_secm", "DCA in x-y plane TPC+ITS tag - secm;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); histos.add("MC/primsec/pthist_tpc_secm", "#it{p}_{T} distribution - MC mat. sec. TPC tag", kTH1D, {axisPt}, true); histos.add("MC/primsec/etahist_tpc_secm", "#eta distribution - MC mat. sec. TPC tag", kTH1D, {axisEta}, true); @@ -887,20 +1032,20 @@ struct qaMatchEff { // DCA of identified // - histos.add("MC/PID/zDCA_tpc_pi", "DCA along z - pions TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/PID/xyDCA_tpc_pi", "DCA in x-y plane - pions TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/PID/zDCA_tpcits_pi", "DCA along z - pions TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/PID/xyDCA_tpcits_pi", "DCA in x-y plane - pions TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/PID/zDCA_tpc_pi", "DCA along z - pions TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/PID/xyDCA_tpc_pi", "DCA in x-y plane - pions TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/PID/zDCA_tpcits_pi", "DCA along z - pions TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/PID/xyDCA_tpcits_pi", "DCA in x-y plane - pions TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/PID/zDCA_tpc_ka", "DCA along z - kaons TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/PID/xyDCA_tpc_ka", "DCA in x-y plane - kaons TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/PID/zDCA_tpcits_ka", "DCA along z - kaons TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/PID/xyDCA_tpcits_ka", "DCA in x-y plane - kaons TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/PID/zDCA_tpc_ka", "DCA along z - kaons TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/PID/xyDCA_tpc_ka", "DCA in x-y plane - kaons TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/PID/zDCA_tpcits_ka", "DCA along z - kaons TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/PID/xyDCA_tpcits_ka", "DCA in x-y plane - kaons TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/PID/zDCA_tpc_pr", "DCA along z - protons TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/PID/xyDCA_tpc_pr", "DCA in x-y plane - protons TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/PID/zDCA_tpcits_pr", "DCA along z - protons TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); - histos.add("MC/PID/xyDCA_tpcits_pr", "DCA in x-y plane - protons TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/PID/zDCA_tpc_pr", "DCA along z - protons TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/PID/xyDCA_tpc_pr", "DCA in x-y plane - protons TPC tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/PID/zDCA_tpcits_pr", "DCA along z - protons TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); + // histos.add("MC/PID/xyDCA_tpcits_pr", "DCA in x-y plane - protons TPC+ITS tag;dca [cm]", kTH1D, {{200, -20.0, 20.0}}, true); // // pions only @@ -938,33 +1083,33 @@ struct qaMatchEff { // for "MC truth" pions // histos.add("MC/TPCclust/tpcNClsFound_piMC", "Number of TPC found clusters - #pi_{MC}", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_piMC", "Number of TPC findable clusters - #pi_{MC}", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_piMC", "Number of TPC crossed rows - #pi_{MC}", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC", "Number of TPC findable clusters minus crossed rows - #pi_{MC}", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_piMC", "Number of TPC findable clusters - #pi_{MC}", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_piMC", "Number of TPC crossed rows - #pi_{MC}", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC", "Number of TPC findable clusters minus crossed rows - #pi_{MC}", kTH1F, {{200, -200.0, 200.0}}, true); // // // TPC found clusters distribution histos.add("MC/TPCclust/tpcNClsFound_piMC_tpc", "TPC found clusters - #pi_{MC} TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_piMC_tpc", "TPC findable clusters - #pi_{MC} TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_piMC_tpc", "TPC crossed rows - #pi_{MC} TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC_tpc", "TPC findable clusters minus crossed rows - #pi_{MC} TPC tag", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_piMC_tpc", "TPC findable clusters - #pi_{MC} TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_piMC_tpc", "TPC crossed rows - #pi_{MC} TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC_tpc", "TPC findable clusters minus crossed rows - #pi_{MC} TPC tag", kTH1F, {{200, -200.0, 200.0}}, true); histos.add("MC/TPCclust/tpcNClsFound_piMC_tpcits", "TPC found clusters - #pi_{MC} TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_piMC_tpcits", "TPC findable clusters - #pi_{MC} TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_piMC_tpcits", "TPC crossed rows - #pi_{MC} TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC_tpcits", "TPC findable clusters minus crossed rows - #pi_{MC} TPC+ITS tag", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_piMC_tpcits", "TPC findable clusters - #pi_{MC} TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_piMC_tpcits", "TPC crossed rows - #pi_{MC} TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC_tpcits", "TPC findable clusters minus crossed rows - #pi_{MC} TPC+ITS tag", kTH1F, {{200, -200.0, 200.0}}, true); // // pt in [1,2] GeV - histos.add("MC/TPCclust/tpcNClsFound_piMC_tpc_1g", "Number of TPC found clusters - #pi_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_piMC_tpc_1g", "Number of TPC findable clusters - #pi_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_piMC_tpc_1g", "Number of TPC crossed rows - #pi_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC_tpc_1g", "Number of TPC findable clusters minus crossed rows - #pi_{MC} TPC tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); - - histos.add("MC/TPCclust/tpcNClsFound_piMC_tpcits_1g", "Number of TPC found clusters - #pi_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_piMC_tpcits_1g", "Number of TPC findable clusters - #pi_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_piMC_tpcits_1g", "Number of TPC crossed rows - #pi_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC_tpcits_1g", "Number of TPC findable clusters minus crossed rows - #pi_{MC} TPC+ITS tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFound_piMC_tpc_1g", "Number of TPC found clusters - #pi_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_piMC_tpc_1g", "Number of TPC findable clusters - #pi_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_piMC_tpc_1g", "Number of TPC crossed rows - #pi_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC_tpc_1g", "Number of TPC findable clusters minus crossed rows - #pi_{MC} TPC tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); + + // histos.add("MC/TPCclust/tpcNClsFound_piMC_tpcits_1g", "Number of TPC found clusters - #pi_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_piMC_tpcits_1g", "Number of TPC findable clusters - #pi_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_piMC_tpcits_1g", "Number of TPC crossed rows - #pi_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC_tpcits_1g", "Number of TPC findable clusters minus crossed rows - #pi_{MC} TPC+ITS tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); // // @@ -1056,30 +1201,30 @@ struct qaMatchEff { // // TPC found clusters distribution histos.add("MC/TPCclust/tpcNClsFound_prMC", "Number of TPC found clusters - protons_{MC}", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_prMC", "Number of TPC findable clusters - protons_{MC}", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_prMC", "Number of TPC crossed rows - protons_{MC}", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC", "Number of TPC findable clusters minus crossed rows - protons_{MC}", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_prMC", "Number of TPC findable clusters - protons_{MC}", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_prMC", "Number of TPC crossed rows - protons_{MC}", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC", "Number of TPC findable clusters minus crossed rows - protons_{MC}", kTH1F, {{200, -200.0, 200.0}}, true); histos.add("MC/TPCclust/tpcNClsFound_prMC_tpc", "Number of TPC found clusters - protons_{MC} TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_prMC_tpc", "Number of TPC findable clusters - protons_{MC} TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_prMC_tpc", "Number of TPC crossed rows - protons_{MC} TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC_tpc", "Number of TPC findable clusters minus crossed rows - protons_{MC} TPC tag", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_prMC_tpc", "Number of TPC findable clusters - protons_{MC} TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_prMC_tpc", "Number of TPC crossed rows - protons_{MC} TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC_tpc", "Number of TPC findable clusters minus crossed rows - protons_{MC} TPC tag", kTH1F, {{200, -200.0, 200.0}}, true); histos.add("MC/TPCclust/tpcNClsFound_prMC_tpcits", "Number of TPC found clusters - protons_{MC} TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_prMC_tpcits", "Number of TPC findable clusters - protons_{MC} TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_prMC_tpcits", "Number of TPC crossed rows - protons_{MC} TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC_tpcits", "Number of TPC findable clusters minus crossed rows - protons_{MC} TPC+ITS tag", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_prMC_tpcits", "Number of TPC findable clusters - protons_{MC} TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_prMC_tpcits", "Number of TPC crossed rows - protons_{MC} TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC_tpcits", "Number of TPC findable clusters minus crossed rows - protons_{MC} TPC+ITS tag", kTH1F, {{200, -200.0, 200.0}}, true); // // pt in [1,2] GeV - histos.add("MC/TPCclust/tpcNClsFound_prMC_tpc_1g", "Number of TPC found clusters - protons_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_prMC_tpc_1g", "Number of TPC findable clusters - protons_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_prMC_tpc_1g", "Number of TPC crossed rows - protons_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC_tpc_1g", "Number of TPC findable clusters minus crossed rows - protons_{MC} TPC tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFound_prMC_tpc_1g", "Number of TPC found clusters - protons_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_prMC_tpc_1g", "Number of TPC findable clusters - protons_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_prMC_tpc_1g", "Number of TPC crossed rows - protons_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC_tpc_1g", "Number of TPC findable clusters minus crossed rows - protons_{MC} TPC tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); - histos.add("MC/TPCclust/tpcNClsFound_prMC_tpcits_1g", "Number of TPC found clusters - protons_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_prMC_tpcits_1g", "Number of TPC findable clusters - protons_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_prMC_tpcits_1g", "Number of TPC crossed rows - protons_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC_tpcits_1g", "Number of TPC findable clusters minus crossed rows - protons_{MC} TPC+ITS tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFound_prMC_tpcits_1g", "Number of TPC found clusters - protons_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_prMC_tpcits_1g", "Number of TPC findable clusters - protons_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_prMC_tpcits_1g", "Number of TPC crossed rows - protons_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC_tpcits_1g", "Number of TPC findable clusters minus crossed rows - protons_{MC} TPC+ITS tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); // // @@ -1143,31 +1288,31 @@ struct qaMatchEff { // // TPC found clusters distribution histos.add("MC/TPCclust/tpcNClsFound_kaMC", "Number of TPC found clusters - kaons_{MC}", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_kaMC", "Number of TPC findable clusters - kaons_{MC} ", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_kaMC", "Number of TPC crossed rows - kaons_{MC} ", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC", "Number of TPC findable clusters minus crossed rows - kaons_{MC} ", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_kaMC", "Number of TPC findable clusters - kaons_{MC} ", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_kaMC", "Number of TPC crossed rows - kaons_{MC} ", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC", "Number of TPC findable clusters minus crossed rows - kaons_{MC} ", kTH1F, {{200, -200.0, 200.0}}, true); histos.add("MC/TPCclust/tpcNClsFound_kaMC_tpc", "Number of TPC found clusters - kaons_{MC} TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_kaMC_tpc", "Number of TPC findable clusters - kaons_{MC} TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_kaMC_tpc", "Number of TPC crossed rows - kaons_{MC} TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC_tpc", "Number of TPC findable clusters minus crossed rows - kaons_{MC} TPC tag", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_kaMC_tpc", "Number of TPC findable clusters - kaons_{MC} TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_kaMC_tpc", "Number of TPC crossed rows - kaons_{MC} TPC tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC_tpc", "Number of TPC findable clusters minus crossed rows - kaons_{MC} TPC tag", kTH1F, {{200, -200.0, 200.0}}, true); histos.add("MC/TPCclust/tpcNClsFound_kaMC_tpcits", "Number of TPC found clusters - kaons_{MC} TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_kaMC_tpcits", "Number of TPC findable clusters - kaons_{MC} TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_kaMC_tpcits", "Number of TPC crossed rows - kaons_{MC} TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC_tpcits", "Number of TPC findable clusters minus crossed rows - kaons_{MC} TPC+ITS tag", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_kaMC_tpcits", "Number of TPC findable clusters - kaons_{MC} TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_kaMC_tpcits", "Number of TPC crossed rows - kaons_{MC} TPC+ITS tag", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC_tpcits", "Number of TPC findable clusters minus crossed rows - kaons_{MC} TPC+ITS tag", kTH1F, {{200, -200.0, 200.0}}, true); // // pt in [1,2] GeV - histos.add("MC/TPCclust/tpcNClsFound_kaMC_tpc_1g", "Number of TPC found clusters - kaons_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_kaMC_tpc_1g", "Number of TPC findable clusters - kaons_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_kaMC_tpc_1g", "Number of TPC crossed rows - kaons_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC_tpc_1g", "Number of TPC findable clusters minus crossed rows - kaons_{MC} TPC tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFound_kaMC_tpc_1g", "Number of TPC found clusters - kaons_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_kaMC_tpc_1g", "Number of TPC findable clusters - kaons_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_kaMC_tpc_1g", "Number of TPC crossed rows - kaons_{MC} TPC tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC_tpc_1g", "Number of TPC findable clusters minus crossed rows - kaons_{MC} TPC tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); - histos.add("MC/TPCclust/tpcNClsFound_kaMC_tpcits_1g", "Number of TPC found clusters - kaons_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcNClsFindable_kaMC_tpcits_1g", "Number of TPC findable clusters - kaons_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcCrossedRows_kaMC_tpcits_1g", "Number of TPC crossed rows - kaons_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); - histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC_tpcits_1g", "Number of TPC findable clusters minus crossed rows - kaons_{MC} TPC+ITS tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); + // histos.add("MC/TPCclust/tpcNClsFound_kaMC_tpcits_1g", "Number of TPC found clusters - kaons_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcNClsFindable_kaMC_tpcits_1g", "Number of TPC findable clusters - kaons_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcCrossedRows_kaMC_tpcits_1g", "Number of TPC crossed rows - kaons_{MC} TPC+ITS tag pt1-2", kTH1F, {{161, -0.5, 160.5}}, true); + // histos.add("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC_tpcits_1g", "Number of TPC findable clusters minus crossed rows - kaons_{MC} TPC+ITS tag pt1-2", kTH1F, {{200, -200.0, 200.0}}, true); // // @@ -1208,13 +1353,13 @@ struct qaMatchEff { histos.add("MC/PID/phihist_tpcits_piK", "#phi distribution - #pi+kaons MC TPC+ITS tag", kTH1D, {axisPhi}, true); // pt>0.5 GeV/c threshold - histos.add("MC/pthist_tpc_05", "#it{p}_{T} distribution - MC TPC tag, #it{p}_{T}>0.5", kTH1D, {axisPt}, true); - histos.add("MC/etahist_tpc_05", "#eta distribution - MC TPC tag, #it{p}_{T}>0.5", kTH1D, {axisEta}, true); - histos.add("MC/phihist_tpc_05", "#phi distribution - MC TPC tag, #it{p}_{T}>0.5", kTH1D, {axisPhi}, true); + // histos.add("MC/pthist_tpc_05", "#it{p}_{T} distribution - MC TPC tag, #it{p}_{T}>0.5", kTH1D, {axisPt}, true); + // histos.add("MC/etahist_tpc_05", "#eta distribution - MC TPC tag, #it{p}_{T}>0.5", kTH1D, {axisEta}, true); + // histos.add("MC/phihist_tpc_05", "#phi distribution - MC TPC tag, #it{p}_{T}>0.5", kTH1D, {axisPhi}, true); - histos.add("MC/pthist_tpcits_05", "#it{p}_{T} distribution - MC TPC+ITS tag, #it{p}_{T}>0.5", kTH1D, {axisPt}, true); - histos.add("MC/etahist_tpcits_05", "#eta distribution - MC TPC+ITS tag, #it{p}_{T}>0.5", kTH1D, {axisEta}, true); - histos.add("MC/phihist_tpcits_05", "#phi distribution - MC TPC+ITS tag, #it{p}_{T}>0.5", kTH1D, {axisPhi}, true); + // histos.add("MC/pthist_tpcits_05", "#it{p}_{T} distribution - MC TPC+ITS tag, #it{p}_{T}>0.5", kTH1D, {axisPt}, true); + // histos.add("MC/etahist_tpcits_05", "#eta distribution - MC TPC+ITS tag, #it{p}_{T}>0.5", kTH1D, {axisEta}, true); + // histos.add("MC/phihist_tpcits_05", "#phi distribution - MC TPC+ITS tag, #it{p}_{T}>0.5", kTH1D, {axisPhi}, true); // // all but primary/secondary pions @@ -1255,15 +1400,14 @@ struct qaMatchEff { return true; // no track selections applied if (!cutObject.IsSelected(track, TrackSelection::TrackCuts::kPtRange)) return false; - if (isUseTPCinnerWallPt && computePtInParamTPC(track) < ptMinCutInnerWallTPC) { + if (isUseTPCinnerWallPt && computePtInParamTPC(track) < kineCuts.ptMinCutInnerWallTPC) { return false; // pt selection active only if the required pt is that calculated at the inner wall of TPC } if (!cutObject.IsSelected(track, TrackSelection::TrackCuts::kEtaRange)) return false; if (!cutObject.IsSelected(track, TrackSelection::TrackCuts::kDCAxy)) return false; - // dcaZ selection to simulate the dca cut in QC () - if (abs(track.dcaZ()) > dcaMaxCut->get("TrVtx", "dcaZ")) + if (!cutObject.IsSelected(track, TrackSelection::TrackCuts::kDCAz)) return false; return true; } @@ -1307,11 +1451,20 @@ struct qaMatchEff { histos.fill(HIST("MC/control/yPrimary"), coll.posY()); histos.fill(HIST("MC/control/xPrimary"), coll.posX()); histos.fill(HIST("MC/control/chi2Prim"), coll.chi2()); + if constexpr (requires { coll.centFT0C(); }) { + histos.fill(HIST("MC/control/centrality"), coll.centFT0C()); + } } else { histos.fill(HIST("data/control/zPrimary"), coll.posZ()); histos.fill(HIST("data/control/yPrimary"), coll.posY()); histos.fill(HIST("data/control/xPrimary"), coll.posX()); histos.fill(HIST("data/control/chi2Prim"), coll.chi2()); + if constexpr (requires { coll.centFT0C(); }) { + histos.fill(HIST("data/control/centrality"), coll.centFT0C()); + } + if constexpr (requires { coll.trackOccupancyInTimeRange(); }) { + histos.fill(HIST("data/control/occupancy"), coll.trackOccupancyInTimeRange()); + } } return; } @@ -1355,6 +1508,11 @@ struct qaMatchEff { continue; if ((isTRDThere == 0) && track.hasTRD()) continue; + // choose if we keep the track according to the TOF presence requirement + if ((isTOFThere == 1) && !track.hasTOF()) + continue; + if ((isTOFThere == 0) && track.hasTOF()) + continue; // kinematic track seletions for all tracks if (!isTrackSelectedKineCuts(track)) @@ -1386,9 +1544,9 @@ struct qaMatchEff { // here n of clusters of TPC assigned to float for histos (and to hack it if needed) :) // Float_t clustpc = (Float_t)track.tpcNClsFound(); - Float_t findcltpc = (Float_t)track.tpcNClsFindable(); - Float_t crowstpc = (Float_t)track.tpcNClsCrossedRows(); - Float_t finclusmincrotpc = (Float_t)track.tpcNClsFindableMinusCrossedRows(); + // Float_t findcltpc = (Float_t)track.tpcNClsFindable(); + // Float_t crowstpc = (Float_t)track.tpcNClsCrossedRows(); + // Float_t finclusmincrotpc = (Float_t)track.tpcNClsFindableMinusCrossedRows(); // // special case for ITS tracks // Using pt calculated at the inner wall of TPC @@ -1401,10 +1559,8 @@ struct qaMatchEff { countData++; // - // keep sign of track as boolean - bool positiveTrack = false; - if (track.signed1Pt() > 0) - positiveTrack = true; + // keep sign of track + Int_t signOfTrack = track.signed1Pt() > 0 ? 1 : -1; // // PID sigmas if constexpr (!IS_MC) { @@ -1415,6 +1571,7 @@ struct qaMatchEff { tofNSigmaKaon = track.tofNSigmaKa(); tofNSigmaProton = track.tofNSigmaPr(); } + const bool trkWTRD = track.hasTRD(); const bool trkWTOF = track.hasTOF(); const bool trkWTPC = track.hasTPC(); const bool trkWITS = track.hasITS(); @@ -1443,7 +1600,7 @@ struct qaMatchEff { siPDGCode = mcpart.pdgCode(); tpPDGCode = TMath::Abs(siPDGCode); if (mcpart.isPhysicalPrimary()) { - histos.get(HIST("MC/control/etahist_diff"))->Fill(mcpart.eta() - track.eta()); + // histos.get(HIST("MC/control/etahist_diff"))->Fill(mcpart.eta() - track.eta()); auto delta = mcpart.phi() - track.phi(); if (delta > PI) { delta -= TwoPI; @@ -1451,7 +1608,7 @@ struct qaMatchEff { if (delta < -PI) { delta += TwoPI; } - histos.get(HIST("MC/control/phihist_diff"))->Fill(delta); + // histos.get(HIST("MC/control/phihist_diff"))->Fill(delta); } /// MC info for THnSparse filling @@ -1476,188 +1633,231 @@ struct qaMatchEff { case 2212: specind = 4; break; - case -11: - specind = -1; - break; - case -211: - specind = -2; - break; - case -321: - specind = -3; - break; - case -2212: - specind = -4; - break; + // case -11: + // specind = -1; + // break; + // case -211: + // specind = -2; + // break; + // case -321: + // specind = -3; + // break; + // case -2212: + // specind = -4; + // break; default: specind = 0; } } else { - // PID info for ThNSparse filling - // - // WARNING !!! MIND the order of lines below, pions are preferred over kaons which are preferred over protons specind = -9999; - if (isProton && !(isKaon || isPion)) { - if (positiveTrack) { - specind = 4; - } else { - specind = -4; // protons ONLY - } - } - if (isKaon && !(isPion || isProton)) { - if (positiveTrack) { - specind = 3; - } else { - specind = -3; // kaons ONLY - } - } - if (isPion && !(isKaon || isProton)) { // pions ONLY - if (positiveTrack) { - specind = 2; - } else { - specind = -2; - } - } - if (isPion && isKaon && !isProton) { // maybe pion, maybe kaon - if (positiveTrack) { - specind = 5; - } else { - specind = -5; - } - } - if (isPion && isProton && !isKaon) { // maybe pion, maybe proton - if (positiveTrack) { - specind = 6; - } else { - specind = -6; - } - } - if (isKaon && isProton && !isPion) { // maybe proton, maybe kaon - if (positiveTrack) { - specind = 7; - } else { - specind = -7; - } - } - if (isPion && isKaon && isProton) { // maybe pion, maybe kaon, maybe proton - if (positiveTrack) { - specind = 9; - } else { - specind = -9; - } - } - if (!isPion && !isKaon && !isProton) { // PID is NOT pion or kaon or proton - if (positiveTrack) { - specind = 1; - } else { - specind = -1; - } - } + if (isProton && !(isKaon || isPion)) + specind = 4; // protons ONLY + if (isKaon && !(isPion || isProton)) + specind = 3; // kaons ONLY + if (isPion && !(isKaon || isProton)) + specind = 2; // pions ONLY + if (isPion && isKaon && !isProton) + specind = 5; // maybe pion, maybe kaon + if (isPion && isProton && !isKaon) + specind = 6; // maybe pion, maybe proton + if (isKaon && isProton && !isPion) + specind = 7; // maybe proton, maybe kaon + if (isPion && isKaon && isProton) + specind = 8; // maybe pion, maybe kaon, maybe proton + if (!isPion && !isKaon && !isProton) + specind = 9; // PID is NOT pion or kaon or proton } + // PID info for ThNSparse filling + // + // WARNING !!! MIND the order of lines below, pions are preferred over kaons which are preferred over protons // //*************************************************************************************************************************************************************************** // MIND!!!! THESE SETS OVERLAP!!! ___M__U__S__T___ select one of the conditions in the analysis hasdet = 0; - if (trkWITS && isTrackSelectedITSCuts(track)) { + if (trkWITS && isTrackSelectedITSCuts(track)) { // ITS at least hasdet = 1; // // // fill thnsparse for fraction analysis if (makethn) { if constexpr (IS_MC) { - histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, track.itsClusterMap(), clustpc, hasdet); + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (siPDGCode == 211 || siPDGCode == 321) // pions and kaons together + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); } else { - histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, track.itsClusterMap(), clustpc, hasdet); + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (specind == 2 || specind == 3 || specind == 5) // pions and kaons together + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); } } } - if (trkWTPC && isTrackSelectedTPCCuts(track)) { + if (trkWTPC && isTrackSelectedTPCCuts(track)) { // TPC at least hasdet = 2; // // // fill thnsparse for fraction analysis if (makethn) { if constexpr (IS_MC) { - histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, track.itsClusterMap(), clustpc, hasdet); + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (siPDGCode == 211 || siPDGCode == 321) // pions and kaons together + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); } else { - histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, track.itsClusterMap(), clustpc, hasdet); + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (specind == 2 || specind == 3 || specind == 5) // pions and kaons together + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); } } } - if (trkWITS && trkWTPC && isTrackSelectedTPCCuts(track) && isTrackSelectedITSCuts(track)) { + if (trkWITS && trkWTPC && isTrackSelectedTPCCuts(track) && isTrackSelectedITSCuts(track)) { // ITS + TPC at least hasdet = 3; // // // fill thnsparse for fraction analysis if (makethn) { if constexpr (IS_MC) { - histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, track.itsClusterMap(), clustpc, hasdet); + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (siPDGCode == 211 || siPDGCode == 321) // pions and kaons together + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); } else { - histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, track.itsClusterMap(), clustpc, hasdet); + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (specind == 2 || specind == 3 || specind == 5) // pions and kaons together + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); } } } - if (trkWTOF && trkWTPC && isTrackSelectedTPCCuts(track)) { + if (trkWTOF && trkWTPC && isTrackSelectedTPCCuts(track)) { // TOF + TPC at least hasdet = 4; // // // fill thnsparse for fraction analysis if (makethn) { if constexpr (IS_MC) { - histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, track.itsClusterMap(), clustpc, hasdet); + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (siPDGCode == 211 || siPDGCode == 321) // pions and kaons together + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); } else { - histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, track.itsClusterMap(), clustpc, hasdet); + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (specind == 2 || specind == 3 || specind == 5) // pions and kaons together + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); } } } - if (trkWITS && isTrackSelectedITSCuts(track) && trkWTOF) { + if (trkWITS && isTrackSelectedITSCuts(track) && trkWTOF) { // TOF + ITS at least hasdet = 5; // // // fill thnsparse for fraction analysis if (makethn) { if constexpr (IS_MC) { - histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, track.itsClusterMap(), clustpc, hasdet); + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (siPDGCode == 211 || siPDGCode == 321) // pions and kaons together + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); } else { - histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, track.itsClusterMap(), clustpc, hasdet); + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (specind == 2 || specind == 3 || specind == 5) // pions and kaons together + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); } } } - if (trkWITS && trkWTOF && trkWTPC && isTrackSelectedTPCCuts(track) && isTrackSelectedITSCuts(track)) { + if (trkWITS && trkWTOF && trkWTPC && isTrackSelectedTPCCuts(track) && isTrackSelectedITSCuts(track)) { // TOF + TPC +ITS at least hasdet = 6; // // // fill thnsparse for fraction analysis if (makethn) { if constexpr (IS_MC) { - histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, track.itsClusterMap(), clustpc, hasdet); + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (siPDGCode == 211 || siPDGCode == 321) // pions and kaons together + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); } else { - histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, track.itsClusterMap(), clustpc, hasdet); + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (specind == 2 || specind == 3 || specind == 5) // pions and kaons together + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); } } } - if (trkWITS && isTrackSelectedITSCuts(track) && !trkWTPC) { + if (trkWITS && isTrackSelectedITSCuts(track) && !trkWTPC) { // ITS at least, NO TPC hasdet = 7; // // // fill thnsparse for fraction analysis if (makethn) { if constexpr (IS_MC) { - histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, track.itsClusterMap(), clustpc, hasdet); + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (siPDGCode == 211 || siPDGCode == 321) // pions and kaons together + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); } else { - histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, track.itsClusterMap(), clustpc, hasdet); + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (specind == 2 || specind == 3 || specind == 5) // pions and kaons together + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); } } } - if (trkWTPC && isTrackSelectedTPCCuts(track) && !trkWITS) { + if (trkWTPC && isTrackSelectedTPCCuts(track) && !trkWITS) { // TPC at least, NO ITS hasdet = 8; // // // fill thnsparse for fraction analysis if (makethn) { if constexpr (IS_MC) { - histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, track.itsClusterMap(), clustpc, hasdet); + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (siPDGCode == 211 || siPDGCode == 321) // pions and kaons together + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); } else { - histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, track.itsClusterMap(), clustpc, hasdet); + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (specind == 2 || specind == 3 || specind == 5) // pions and kaons together + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); + } + } + } + if (trkWITS && isTrackSelectedITSCuts(track) && trkWTRD) { // ITS + TRD at least + hasdet = 9; + // + // + // fill thnsparse for fraction analysis + if (makethn) { + if constexpr (IS_MC) { + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (siPDGCode == 211 || siPDGCode == 321) // pions and kaons together + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); + } else { + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (specind == 2 || specind == 3 || specind == 5) // pions and kaons together + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); + } + } + } + if (trkWITS && isTrackSelectedITSCuts(track) && trkWTRD && trkWTOF) { // ITS + TRD + TOF at least + hasdet = 10; + // + // + // fill thnsparse for fraction analysis + if (makethn) { + if constexpr (IS_MC) { + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (siPDGCode == 211 || siPDGCode == 321) // pions and kaons together + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); + } else { + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (specind == 2 || specind == 3 || specind == 5) // pions and kaons together + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); + } + } + } + if (trkWITS && isTrackSelectedITSCuts(track) && !trkWTRD && !trkWTOF && !trkWTPC) { // ITS ONLY! + hasdet = 11; + // + // + // fill thnsparse for fraction analysis + if (makethn) { + if constexpr (IS_MC) { + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (siPDGCode == 211 || siPDGCode == 321) // pions and kaons together + histos.fill(HIST("MC/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); + } else { + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), specind, signOfTrack, hasdet); + if (specind == 2 || specind == 3 || specind == 5) // pions and kaons together + histos.fill(HIST("data/sparse/thnsforfrac"), track.dcaXY(), track.dcaZ(), trackPt, track.eta(), sayPrim, track.phi(), 10, signOfTrack, hasdet); } } } @@ -1666,55 +1866,59 @@ struct qaMatchEff { // // all tracks, no conditions // - + // + if (!makehistos) + return; + // + // // TPC clusters - all particles all dets // if constexpr (IS_MC) { //////////////////////// MC histos.get(HIST("MC/TPCclust/tpcNClsFound"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows"))->Fill(crowstpc); } else { histos.get(HIST("data/TPCclust/tpcNClsFound"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows"))->Fill(finclusmincrotpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows"))->Fill(finclusmincrotpc); } // TPC clusters all pions MC truth // if (tpPDGCode == 211) { histos.get(HIST("MC/TPCclust/tpcNClsFound_piMC"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_piMC"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_piMC"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_piMC"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_piMC"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC"))->Fill(crowstpc); } if (tpPDGCode == 321) { histos.get(HIST("MC/TPCclust/tpcNClsFound_kaMC"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_kaMC"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_kaMC"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_kaMC"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_kaMC"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC"))->Fill(crowstpc); } if (tpPDGCode == 2212) { histos.get(HIST("MC/TPCclust/tpcNClsFound_prMC"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_prMC"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_prMC"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_prMC"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_prMC"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC"))->Fill(crowstpc); } // TPC clusters all pions // if (isPion) { // if constexpr (IS_MC) { //////////////////////// MC // histos.get(HIST("MC/TPCclust/tpcNClsFound_pi"))->Fill(clustpc); - // histos.get(HIST("MC/TPCclust/tpcNClsFindable_pi"))->Fill(findcltpc); - // histos.get(HIST("MC/TPCclust/tpcCrossedRows_pi"))->Fill(crowstpc); - // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_pi"))->Fill(crowstpc); + // // histos.get(HIST("MC/TPCclust/tpcNClsFindable_pi"))->Fill(findcltpc); + // // histos.get(HIST("MC/TPCclust/tpcCrossedRows_pi"))->Fill(crowstpc); + // // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_pi"))->Fill(crowstpc); // } else { - if constexpr (!IS_MC) { // DATA + if constexpr (!IS_MC) { //////////////////////// data histos.get(HIST("data/TPCclust/tpcNClsFound_pi"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_pi"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_pi"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pi"))->Fill(finclusmincrotpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_pi"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_pi"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pi"))->Fill(finclusmincrotpc); } } // TPC clusters all kaons @@ -1722,15 +1926,15 @@ struct qaMatchEff { if (isKaon) { // if constexpr (IS_MC) { //////////////////////// MC // histos.get(HIST("MC/TPCclust/tpcNClsFound_ka"))->Fill(clustpc); - // histos.get(HIST("MC/TPCclust/tpcNClsFindable_ka"))->Fill(findcltpc); - // histos.get(HIST("MC/TPCclust/tpcCrossedRows_ka"))->Fill(crowstpc); - // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_ka"))->Fill(crowstpc); + // // histos.get(HIST("MC/TPCclust/tpcNClsFindable_ka"))->Fill(findcltpc); + // // histos.get(HIST("MC/TPCclust/tpcCrossedRows_ka"))->Fill(crowstpc); + // // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_ka"))->Fill(crowstpc); // } else { - if constexpr (!IS_MC) { // DATA + if constexpr (!IS_MC) { //////////////////////// data histos.get(HIST("data/TPCclust/tpcNClsFound_ka"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_ka"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_ka"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_ka"))->Fill(finclusmincrotpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_ka"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_ka"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_ka"))->Fill(finclusmincrotpc); } } // TPC clusters all protons @@ -1738,15 +1942,15 @@ struct qaMatchEff { if (isProton) { // if constexpr (IS_MC) { //////////////////////// MC // histos.get(HIST("MC/TPCclust/tpcNClsFound_pr"))->Fill(clustpc); - // histos.get(HIST("MC/TPCclust/tpcNClsFindable_pr"))->Fill(findcltpc); - // histos.get(HIST("MC/TPCclust/tpcCrossedRows_pr"))->Fill(crowstpc); - // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_pr"))->Fill(crowstpc); + // // histos.get(HIST("MC/TPCclust/tpcNClsFindable_pr"))->Fill(findcltpc); + // // histos.get(HIST("MC/TPCclust/tpcCrossedRows_pr"))->Fill(crowstpc); + // // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_pr"))->Fill(crowstpc); // } else { - if constexpr (!IS_MC) { // DATA + if constexpr (!IS_MC) { //////////////////////// data histos.get(HIST("data/TPCclust/tpcNClsFound_pr"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_pr"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_pr"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pr"))->Fill(finclusmincrotpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_pr"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_pr"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pr"))->Fill(finclusmincrotpc); } } // @@ -1758,30 +1962,30 @@ struct qaMatchEff { // // TPC clusters histos.get(HIST("MC/TPCclust/tpcNClsFound_tpc"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_tpc"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_tpc"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_tpc"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_tpc"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_tpc"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_tpc"))->Fill(crowstpc); // // pt 1-2 - if (trackPt <= 2 && trackPt > 1) { - histos.get(HIST("MC/TPCclust/tpcNClsFound_tpc_1g"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_tpc_1g"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_tpc_1g"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_tpc_1g"))->Fill(crowstpc); - } + // if (trackPt <= 2 && trackPt > 1) { + // histos.get(HIST("MC/TPCclust/tpcNClsFound_tpc_1g"))->Fill(clustpc); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_tpc_1g"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_tpc_1g"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_tpc_1g"))->Fill(crowstpc); + // } // - histos.fill(HIST("MC/control/zDCA_tpc"), track.dcaZ()); - histos.fill(HIST("MC/control/xyDCA_tpc"), track.dcaXY()); + // histos.fill(HIST("MC/control/zDCA_tpc"), track.dcaZ()); + // histos.fill(HIST("MC/control/xyDCA_tpc"), track.dcaXY()); // - if (makept2d) { - histos.fill(HIST("MC/control/ptptconfTPCall"), reco_pt, tpcinner_pt); - if (!trkWITS) - histos.fill(HIST("MC/control/ptptconfTPCo"), reco_pt, tpcinner_pt); - } - if (!trkWITS) { - histos.get(HIST("MC/control/trackXhist_tpcONLY"))->Fill(track.x()); - histos.get(HIST("MC/control/trackZhist_tpcONLY"))->Fill(track.z()); - } + // if (makept2d) { + // histos.fill(HIST("MC/control/ptptconfTPCall"), reco_pt, tpcinner_pt); + // if (!trkWITS) + // histos.fill(HIST("MC/control/ptptconfTPCo"), reco_pt, tpcinner_pt); + // } + // if (!trkWITS) { + // histos.get(HIST("MC/control/trackXhist_tpcONLY"))->Fill(track.x()); + // histos.get(HIST("MC/control/trackZhist_tpcONLY"))->Fill(track.z()); + // } histos.get(HIST("MC/qopthist_tpc"))->Fill(track.signed1Pt()); histos.get(HIST("MC/pthist_tpc"))->Fill(trackPt); histos.get(HIST("MC/phihist_tpc"))->Fill(track.phi()); @@ -1895,29 +2099,29 @@ struct qaMatchEff { // // TPC clusters histos.get(HIST("data/TPCclust/tpcNClsFound_tpc"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_tpc"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_tpc"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_tpc"))->Fill(crowstpc); - // pt 1-2 - if (trackPt <= 2 && trackPt > 1) { - histos.get(HIST("data/TPCclust/tpcNClsFound_tpc_1g"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_tpc_1g"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_tpc_1g"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_tpc_1g"))->Fill(crowstpc); - } + // histos.get(HIST("data/TPCclust/tpcNClsFindable_tpc"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_tpc"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_tpc"))->Fill(crowstpc); + // // pt 1-2 + // if (trackPt <= 2 && trackPt > 1) { + // histos.get(HIST("data/TPCclust/tpcNClsFound_tpc_1g"))->Fill(clustpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_tpc_1g"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_tpc_1g"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_tpc_1g"))->Fill(crowstpc); + // } // - histos.fill(HIST("data/control/zDCA_tpc"), track.dcaZ()); - histos.fill(HIST("data/control/xyDCA_tpc"), track.dcaXY()); + // histos.fill(HIST("data/control/zDCA_tpc"), track.dcaZ()); + // histos.fill(HIST("data/control/xyDCA_tpc"), track.dcaXY()); // - if (makept2d) { - histos.fill(HIST("data/control/ptptconfTPCall"), reco_pt, tpcinner_pt); - if (!trkWITS) - histos.fill(HIST("data/control/ptptconfTPCo"), reco_pt, tpcinner_pt); - } - if (!trkWITS) { - histos.get(HIST("data/control/trackXhist_tpcONLY"))->Fill(track.x()); - histos.get(HIST("data/control/trackZhist_tpcONLY"))->Fill(track.z()); - } + // if (makept2d) { + // histos.fill(HIST("data/control/ptptconfTPCall"), reco_pt, tpcinner_pt); + // if (!trkWITS) + // histos.fill(HIST("data/control/ptptconfTPCo"), reco_pt, tpcinner_pt); + // } + // if (!trkWITS) { + // histos.get(HIST("data/control/trackXhist_tpcONLY"))->Fill(track.x()); + // histos.get(HIST("data/control/trackZhist_tpcONLY"))->Fill(track.z()); + // } histos.get(HIST("data/qopthist_tpc"))->Fill(track.signed1Pt()); histos.get(HIST("data/pthist_tpc"))->Fill(trackPt); histos.get(HIST("data/phihist_tpc"))->Fill(track.phi()); @@ -1929,7 +2133,7 @@ struct qaMatchEff { const auto timestamp = track.collision().template bc_as().timestamp(); /// NB: in ms histos.get(HIST("data/hTrkTPCvsTime"))->Fill(timestamp); if (enableTHnSparseMonitorVsTime) { - histos.get(HIST("data/hTrkTPCvsTimePtEtaPosZ"))->Fill(timestamp, trackPt, track.eta(), track.collision().posZ(), 1. / trackPt, positiveTrack ? 0.5 : -0.5, track.tpcNClsFound(), track.itsNCls()); + histos.get(HIST("data/hTrkTPCvsTimePtEtaPosZ"))->Fill(timestamp, trackPt, track.eta(), track.collision().posZ(), 1. / trackPt, signOfTrack * 0.5, track.tpcNClsFound(), track.itsNCls()); } } } @@ -1946,25 +2150,25 @@ struct qaMatchEff { // // TPC clusters histos.get(HIST("data/TPCclust/tpcNClsFound_pi_tpc"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_pi_tpc"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_pi_tpc"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pi_tpc"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_pi_tpc"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_pi_tpc"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pi_tpc"))->Fill(crowstpc); // // pt 1-2 - if (trackPt <= 2 && trackPt > 1) { - histos.get(HIST("data/TPCclust/tpcNClsFound_pi_tpc_1g"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_pi_tpc_1g"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_pi_tpc_1g"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pi_tpc_1g"))->Fill(crowstpc); - } - // - histos.get(HIST("data/PID/zDCA_tpc_pi"))->Fill(track.dcaZ()); - histos.get(HIST("data/PID/xyDCA_tpc_pi"))->Fill(track.dcaXY()); + // if (trackPt <= 2 && trackPt > 1) { + // histos.get(HIST("data/TPCclust/tpcNClsFound_pi_tpc_1g"))->Fill(clustpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_pi_tpc_1g"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_pi_tpc_1g"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pi_tpc_1g"))->Fill(crowstpc); + // } + // // + // histos.get(HIST("data/PID/zDCA_tpc_pi"))->Fill(track.dcaZ()); + // histos.get(HIST("data/PID/xyDCA_tpc_pi"))->Fill(track.dcaXY()); // histos.get(HIST("data/PID/pthist_tpc_pi"))->Fill(trackPt); histos.get(HIST("data/PID/phihist_tpc_pi"))->Fill(track.phi()); histos.get(HIST("data/PID/etahist_tpc_pi"))->Fill(track.eta()); - if (positiveTrack) { + if (signOfTrack > 0) { histos.get(HIST("data/PID/pthist_tpc_piplus"))->Fill(trackPt); histos.get(HIST("data/PID/phihist_tpc_piplus"))->Fill(track.phi()); histos.get(HIST("data/PID/etahist_tpc_piplus"))->Fill(track.eta()); @@ -1977,13 +2181,13 @@ struct qaMatchEff { if (isPIDPionRequired) { if (pionPIDwithTPC) { histos.get(HIST("data/PID/pthist_tpc_pi_PIDTPC"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpc_piplus_PIDTPC"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpc_piminus_PIDTPC"))->Fill(trackPt); if (!trkWTOF || !pionPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpc_pi_PIDTPC_O"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpc_piplus_PIDTPC_O"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpc_piminus_PIDTPC_O"))->Fill(trackPt); @@ -1991,13 +2195,13 @@ struct qaMatchEff { } if (trkWTOF && pionPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpc_pi_PIDTOF"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpc_piplus_PIDTOF"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpc_piminus_PIDTOF"))->Fill(trackPt); if (!pionPIDwithTPC) { histos.get(HIST("data/PID/pthist_tpc_pi_PIDTOF_O"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpc_piplus_PIDTOF_O"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpc_piminus_PIDTOF_O"))->Fill(trackPt); @@ -2005,7 +2209,7 @@ struct qaMatchEff { } if (pionPIDwithTPC && trkWTOF && pionPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpc_pi_PIDTPCTOF"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpc_piplus_PIDTPCTOF"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpc_piminus_PIDTPCTOF"))->Fill(trackPt); @@ -2016,25 +2220,25 @@ struct qaMatchEff { // // TPC clusters histos.get(HIST("data/TPCclust/tpcNClsFound_ka_tpc"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_ka_tpc"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_ka_tpc"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_ka_tpc"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_ka_tpc"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_ka_tpc"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_ka_tpc"))->Fill(crowstpc); // // pt 1-2 - if (trackPt <= 2 && trackPt > 1) { - histos.get(HIST("data/TPCclust/tpcNClsFound_ka_tpc_1g"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_ka_tpc_1g"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_ka_tpc_1g"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_ka_tpc_1g"))->Fill(crowstpc); - } + // if (trackPt <= 2 && trackPt > 1) { + // histos.get(HIST("data/TPCclust/tpcNClsFound_ka_tpc_1g"))->Fill(clustpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_ka_tpc_1g"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_ka_tpc_1g"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_ka_tpc_1g"))->Fill(crowstpc); + // } // - histos.get(HIST("data/PID/zDCA_tpc_ka"))->Fill(track.dcaZ()); - histos.get(HIST("data/PID/xyDCA_tpc_ka"))->Fill(track.dcaXY()); + // histos.get(HIST("data/PID/zDCA_tpc_ka"))->Fill(track.dcaZ()); + // histos.get(HIST("data/PID/xyDCA_tpc_ka"))->Fill(track.dcaXY()); // histos.get(HIST("data/PID/pthist_tpc_ka"))->Fill(trackPt); histos.get(HIST("data/PID/phihist_tpc_ka"))->Fill(track.phi()); histos.get(HIST("data/PID/etahist_tpc_ka"))->Fill(track.eta()); - if (positiveTrack) { + if (signOfTrack > 0) { histos.get(HIST("data/PID/pthist_tpc_kaplus"))->Fill(trackPt); histos.get(HIST("data/PID/phihist_tpc_kaplus"))->Fill(track.phi()); histos.get(HIST("data/PID/etahist_tpc_kaplus"))->Fill(track.eta()); @@ -2047,13 +2251,13 @@ struct qaMatchEff { if (isPIDKaonRequired) { if (kaonPIDwithTPC) { histos.get(HIST("data/PID/pthist_tpc_ka_PIDTPC"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpc_kaplus_PIDTPC"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpc_kaminus_PIDTPC"))->Fill(trackPt); if (!trkWTOF || !kaonPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpc_ka_PIDTPC_O"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpc_kaplus_PIDTPC_O"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpc_kaminus_PIDTPC_O"))->Fill(trackPt); @@ -2061,13 +2265,13 @@ struct qaMatchEff { } if (trkWTOF && kaonPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpc_ka_PIDTOF"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpc_kaplus_PIDTOF"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpc_kaminus_PIDTOF"))->Fill(trackPt); if (!kaonPIDwithTPC) { histos.get(HIST("data/PID/pthist_tpc_ka_PIDTOF_O"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpc_kaplus_PIDTOF_O"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpc_kaminus_PIDTOF_O"))->Fill(trackPt); @@ -2075,7 +2279,7 @@ struct qaMatchEff { } if (kaonPIDwithTPC && trkWTOF && kaonPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpc_ka_PIDTPCTOF"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpc_kaplus_PIDTPCTOF"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpc_kaminus_PIDTPCTOF"))->Fill(trackPt); @@ -2086,25 +2290,25 @@ struct qaMatchEff { // // TPC clusters histos.get(HIST("data/TPCclust/tpcNClsFound_pr_tpc"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_pr_tpc"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_pr_tpc"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pr_tpc"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_pr_tpc"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_pr_tpc"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pr_tpc"))->Fill(crowstpc); // // pt 1-2 - if (trackPt <= 2 && trackPt > 1) { - histos.get(HIST("data/TPCclust/tpcNClsFound_pr_tpc_1g"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_pr_tpc_1g"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_pr_tpc_1g"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pr_tpc_1g"))->Fill(crowstpc); - } - // - histos.get(HIST("data/PID/zDCA_tpc_pr"))->Fill(track.dcaZ()); - histos.get(HIST("data/PID/xyDCA_tpc_pr"))->Fill(track.dcaXY()); + // if (trackPt <= 2 && trackPt > 1) { + // histos.get(HIST("data/TPCclust/tpcNClsFound_pr_tpc_1g"))->Fill(clustpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_pr_tpc_1g"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_pr_tpc_1g"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pr_tpc_1g"))->Fill(crowstpc); + // } + // // + // histos.get(HIST("data/PID/zDCA_tpc_pr"))->Fill(track.dcaZ()); + // histos.get(HIST("data/PID/xyDCA_tpc_pr"))->Fill(track.dcaXY()); // histos.get(HIST("data/PID/pthist_tpc_pr"))->Fill(trackPt); histos.get(HIST("data/PID/phihist_tpc_pr"))->Fill(track.phi()); histos.get(HIST("data/PID/etahist_tpc_pr"))->Fill(track.eta()); - if (positiveTrack) { + if (signOfTrack > 0) { histos.get(HIST("data/PID/pthist_tpc_prplus"))->Fill(trackPt); histos.get(HIST("data/PID/phihist_tpc_prplus"))->Fill(track.phi()); histos.get(HIST("data/PID/etahist_tpc_prplus"))->Fill(track.eta()); @@ -2117,13 +2321,13 @@ struct qaMatchEff { if (isPIDProtonRequired) { if (protonPIDwithTPC) { histos.get(HIST("data/PID/pthist_tpc_pr_PIDTPC"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpc_prplus_PIDTPC"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpc_prminus_PIDTPC"))->Fill(trackPt); if (!trkWTOF || !protonPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpc_pr_PIDTPC_O"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpc_prplus_PIDTPC_O"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpc_prminus_PIDTPC_O"))->Fill(trackPt); @@ -2131,13 +2335,13 @@ struct qaMatchEff { } if (trkWTOF && protonPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpc_pr_PIDTOF"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpc_prplus_PIDTOF"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpc_prminus_PIDTOF"))->Fill(trackPt); if (!protonPIDwithTPC) { histos.get(HIST("data/PID/pthist_tpc_pr_PIDTOF_O"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpc_prplus_PIDTOF_O"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpc_prminus_PIDTOF_O"))->Fill(trackPt); @@ -2145,7 +2349,7 @@ struct qaMatchEff { } if (protonPIDwithTPC && trkWTOF && protonPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpc_pr_PIDTPCTOF"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpc_prplus_PIDTPCTOF"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpc_prminus_PIDTPCTOF"))->Fill(trackPt); @@ -2153,12 +2357,12 @@ struct qaMatchEff { } // end protons if (!isPion && !isKaon && !isProton && (isPIDPionRequired || isPIDKaonRequired || isPIDProtonRequired)) { - histos.get(HIST("data/PID/zDCA_tpc_noid"))->Fill(track.dcaZ()); - histos.get(HIST("data/PID/xyDCA_tpc_noid"))->Fill(track.dcaXY()); + // histos.get(HIST("data/PID/zDCA_tpc_noid"))->Fill(track.dcaZ()); + // histos.get(HIST("data/PID/xyDCA_tpc_noid"))->Fill(track.dcaXY()); histos.get(HIST("data/PID/pthist_tpc_noid"))->Fill(trackPt); histos.get(HIST("data/PID/phihist_tpc_noid"))->Fill(track.phi()); histos.get(HIST("data/PID/etahist_tpc_noid"))->Fill(track.eta()); - if (positiveTrack) { + if (signOfTrack > 0) { histos.get(HIST("data/PID/pthist_tpc_noidplus"))->Fill(trackPt); histos.get(HIST("data/PID/phihist_tpc_noidplus"))->Fill(track.phi()); histos.get(HIST("data/PID/etahist_tpc_noidplus"))->Fill(track.eta()); @@ -2168,37 +2372,37 @@ struct qaMatchEff { histos.get(HIST("data/PID/etahist_tpc_noidminus"))->Fill(track.eta()); } } // not pions, nor kaons, nor protons - } // end if DATA + } // end if DATA // if (trkWITS && isTrackSelectedITSCuts(track)) { //////////////////////////////////////////// ITS tag inside TPC tagged if constexpr (IS_MC) { //////////////////////// MC // // TPC clusters histos.get(HIST("MC/TPCclust/tpcNClsFound_tpcits"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_tpcits"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_tpcits"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_tpcits"))->Fill(crowstpc); - // - // pt 1-2 - if (trackPt <= 2 && trackPt > 1) { - histos.get(HIST("MC/TPCclust/tpcNClsFound_tpcits_1g"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_tpcits_1g"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_tpcits_1g"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_tpcits_1g"))->Fill(crowstpc); - } - // - histos.get(HIST("MC/control/zDCA_tpcits"))->Fill(track.dcaZ()); - histos.get(HIST("MC/control/xyDCA_tpcits"))->Fill(track.dcaXY()); - if (makept2d) - histos.fill(HIST("MC/control/ptptconfTPCITS"), reco_pt, tpcinner_pt); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_tpcits"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_tpcits"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_tpcits"))->Fill(crowstpc); + // // + // // pt 1-2 + // if (trackPt <= 2 && trackPt > 1) { + // histos.get(HIST("MC/TPCclust/tpcNClsFound_tpcits_1g"))->Fill(clustpc); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_tpcits_1g"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_tpcits_1g"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_tpcits_1g"))->Fill(crowstpc); + // } + // // + // histos.get(HIST("MC/control/zDCA_tpcits"))->Fill(track.dcaZ()); + // histos.get(HIST("MC/control/xyDCA_tpcits"))->Fill(track.dcaXY()); + // if (makept2d) + // histos.fill(HIST("MC/control/ptptconfTPCITS"), reco_pt, tpcinner_pt); histos.get(HIST("MC/qopthist_tpcits"))->Fill(track.signed1Pt()); histos.get(HIST("MC/pthist_tpcits"))->Fill(trackPt); // histos.get(HIST("MC/phihist_tpcits"))->Fill(track.phi()); histos.get(HIST("MC/etahist_tpcits"))->Fill(track.eta()); // - histos.get(HIST("MC/control/trackXhist_tpcits"))->Fill(track.x()); - histos.get(HIST("MC/control/trackZhist_tpcits"))->Fill(track.z()); + // histos.get(HIST("MC/control/trackXhist_tpcits"))->Fill(track.x()); + // histos.get(HIST("MC/control/trackZhist_tpcits"))->Fill(track.z()); if (trkWTOF) { histos.get(HIST("MC/pthist_toftpcits"))->Fill(trackPt); @@ -2209,51 +2413,52 @@ struct qaMatchEff { // // TPC clusters histos.get(HIST("data/TPCclust/tpcNClsFound_tpcits"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_tpcits"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_tpcits"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_tpcits"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_tpcits"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_tpcits"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_tpcits"))->Fill(crowstpc); // // pt 1-2 - if (trackPt <= 2 && trackPt > 1) { - histos.get(HIST("data/TPCclust/tpcNClsFound_tpcits_1g"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_tpcits_1g"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_tpcits_1g"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_tpcits_1g"))->Fill(crowstpc); - } + // if (trackPt <= 2 && trackPt > 1) { + // histos.get(HIST("data/TPCclust/tpcNClsFound_tpcits_1g"))->Fill(clustpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_tpcits_1g"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_tpcits_1g"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_tpcits_1g"))->Fill(crowstpc); + // } + // // + // histos.get(HIST("data/control/zDCA_tpcits"))->Fill(track.dcaZ()); + // histos.get(HIST("data/control/xyDCA_tpcits"))->Fill(track.dcaXY()); + // if (makept2d) + // histos.fill(HIST("data/control/ptptconfTPCITS"), reco_pt, tpcinner_pt); // - histos.get(HIST("data/control/zDCA_tpcits"))->Fill(track.dcaZ()); - histos.get(HIST("data/control/xyDCA_tpcits"))->Fill(track.dcaXY()); - if (makept2d) - histos.fill(HIST("data/control/ptptconfTPCITS"), reco_pt, tpcinner_pt); histos.get(HIST("data/qopthist_tpcits"))->Fill(track.signed1Pt()); // - histos.get(HIST("data/control/trackXhist_tpcits"))->Fill(track.x()); - histos.get(HIST("data/control/trackZhist_tpcits"))->Fill(track.z()); + // histos.get(HIST("data/control/trackXhist_tpcits"))->Fill(track.x()); + // histos.get(HIST("data/control/trackZhist_tpcits"))->Fill(track.z()); // // PID is applied if (isPion) { // // TPC clusters histos.get(HIST("data/TPCclust/tpcNClsFound_pi_tpcits"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_pi_tpcits"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_pi_tpcits"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pi_tpcits"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_pi_tpcits"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_pi_tpcits"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pi_tpcits"))->Fill(crowstpc); // // pt 1-2 - if (trackPt <= 2 && trackPt > 1) { - histos.get(HIST("data/TPCclust/tpcNClsFound_pi_tpcits_1g"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_pi_tpcits_1g"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_pi_tpcits_1g"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pi_tpcits_1g"))->Fill(crowstpc); - } - // - histos.get(HIST("data/PID/zDCA_tpcits_pi"))->Fill(track.dcaZ()); - histos.get(HIST("data/PID/xyDCA_tpcits_pi"))->Fill(track.dcaXY()); + // if (trackPt <= 2 && trackPt > 1) { + // histos.get(HIST("data/TPCclust/tpcNClsFound_pi_tpcits_1g"))->Fill(clustpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_pi_tpcits_1g"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_pi_tpcits_1g"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pi_tpcits_1g"))->Fill(crowstpc); + // } + // // + // histos.get(HIST("data/PID/zDCA_tpcits_pi"))->Fill(track.dcaZ()); + // histos.get(HIST("data/PID/xyDCA_tpcits_pi"))->Fill(track.dcaXY()); // histos.get(HIST("data/PID/pthist_tpcits_pi"))->Fill(trackPt); histos.get(HIST("data/PID/phihist_tpcits_pi"))->Fill(track.phi()); histos.get(HIST("data/PID/etahist_tpcits_pi"))->Fill(track.eta()); - if (positiveTrack) { + if (signOfTrack > 0) { histos.get(HIST("data/PID/pthist_tpcits_piplus"))->Fill(trackPt); histos.get(HIST("data/PID/phihist_tpcits_piplus"))->Fill(track.phi()); histos.get(HIST("data/PID/etahist_tpcits_piplus"))->Fill(track.eta()); @@ -2266,13 +2471,13 @@ struct qaMatchEff { if (isPIDPionRequired) { if (pionPIDwithTPC) { histos.get(HIST("data/PID/pthist_tpcits_pi_PIDTPC"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpcits_piplus_PIDTPC"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpcits_piminus_PIDTPC"))->Fill(trackPt); if (!trkWTOF || !pionPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpcits_pi_PIDTPC_O"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpcits_piplus_PIDTPC_O"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpcits_piminus_PIDTPC_O"))->Fill(trackPt); @@ -2280,13 +2485,13 @@ struct qaMatchEff { } if (trkWTOF && pionPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpcits_pi_PIDTOF"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpcits_piplus_PIDTOF"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpcits_piminus_PIDTOF"))->Fill(trackPt); if (!pionPIDwithTPC) { histos.get(HIST("data/PID/pthist_tpcits_pi_PIDTOF_O"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpcits_piplus_PIDTOF_O"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpcits_piminus_PIDTOF_O"))->Fill(trackPt); @@ -2294,7 +2499,7 @@ struct qaMatchEff { } if (pionPIDwithTPC && trkWTOF && pionPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpcits_pi_PIDTPCTOF"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpcits_piplus_PIDTPCTOF"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpcits_piminus_PIDTPCTOF"))->Fill(trackPt); @@ -2305,25 +2510,25 @@ struct qaMatchEff { // // TPC clusters histos.get(HIST("data/TPCclust/tpcNClsFound_ka_tpcits"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_ka_tpcits"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_ka_tpcits"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_ka_tpcits"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_ka_tpcits"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_ka_tpcits"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_ka_tpcits"))->Fill(crowstpc); // // pt 1-2 - if (trackPt <= 2 && trackPt > 1) { - histos.get(HIST("data/TPCclust/tpcNClsFound_ka_tpcits_1g"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_ka_tpcits_1g"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_ka_tpcits_1g"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_ka_tpcits_1g"))->Fill(crowstpc); - } + // if (trackPt <= 2 && trackPt > 1) { + // histos.get(HIST("data/TPCclust/tpcNClsFound_ka_tpcits_1g"))->Fill(clustpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_ka_tpcits_1g"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_ka_tpcits_1g"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_ka_tpcits_1g"))->Fill(crowstpc); + // } // - histos.get(HIST("data/PID/zDCA_tpcits_ka"))->Fill(track.dcaZ()); - histos.get(HIST("data/PID/xyDCA_tpcits_ka"))->Fill(track.dcaXY()); + // histos.get(HIST("data/PID/zDCA_tpcits_ka"))->Fill(track.dcaZ()); + // histos.get(HIST("data/PID/xyDCA_tpcits_ka"))->Fill(track.dcaXY()); // histos.get(HIST("data/PID/pthist_tpcits_ka"))->Fill(trackPt); histos.get(HIST("data/PID/phihist_tpcits_ka"))->Fill(track.phi()); histos.get(HIST("data/PID/etahist_tpcits_ka"))->Fill(track.eta()); - if (positiveTrack) { + if (signOfTrack > 0) { histos.get(HIST("data/PID/pthist_tpcits_kaplus"))->Fill(trackPt); histos.get(HIST("data/PID/phihist_tpcits_kaplus"))->Fill(track.phi()); histos.get(HIST("data/PID/etahist_tpcits_kaplus"))->Fill(track.eta()); @@ -2336,13 +2541,13 @@ struct qaMatchEff { if (isPIDKaonRequired) { if (kaonPIDwithTPC) { histos.get(HIST("data/PID/pthist_tpcits_ka_PIDTPC"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpcits_kaplus_PIDTPC"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpcits_kaminus_PIDTPC"))->Fill(trackPt); if (!trkWTOF || !kaonPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpcits_ka_PIDTPC_O"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpcits_kaplus_PIDTPC_O"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpcits_kaminus_PIDTPC_O"))->Fill(trackPt); @@ -2350,13 +2555,13 @@ struct qaMatchEff { } if (trkWTOF && kaonPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpcits_ka_PIDTOF"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpcits_kaplus_PIDTOF"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpcits_kaminus_PIDTOF"))->Fill(trackPt); if (!kaonPIDwithTPC) { histos.get(HIST("data/PID/pthist_tpcits_ka_PIDTOF_O"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpcits_kaplus_PIDTOF_O"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpcits_kaminus_PIDTOF_O"))->Fill(trackPt); @@ -2364,7 +2569,7 @@ struct qaMatchEff { } if (kaonPIDwithTPC && trkWTOF && kaonPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpcits_ka_PIDTPCTOF"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpcits_kaplus_PIDTPCTOF"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpcits_kaminus_PIDTPCTOF"))->Fill(trackPt); @@ -2375,25 +2580,25 @@ struct qaMatchEff { // // TPC clusters histos.get(HIST("data/TPCclust/tpcNClsFound_pr_tpcits"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_pr_tpcits"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_pr_tpcits"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pr_tpcits"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_pr_tpcits"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_pr_tpcits"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pr_tpcits"))->Fill(crowstpc); // // pt 1-2 - if (trackPt <= 2 && trackPt > 1) { - histos.get(HIST("data/TPCclust/tpcNClsFound_pr_tpcits_1g"))->Fill(clustpc); - histos.get(HIST("data/TPCclust/tpcNClsFindable_pr_tpcits_1g"))->Fill(findcltpc); - histos.get(HIST("data/TPCclust/tpcCrossedRows_pr_tpcits_1g"))->Fill(crowstpc); - histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pr_tpcits_1g"))->Fill(crowstpc); - } + // if (trackPt <= 2 && trackPt > 1) { + // histos.get(HIST("data/TPCclust/tpcNClsFound_pr_tpcits_1g"))->Fill(clustpc); + // histos.get(HIST("data/TPCclust/tpcNClsFindable_pr_tpcits_1g"))->Fill(findcltpc); + // histos.get(HIST("data/TPCclust/tpcCrossedRows_pr_tpcits_1g"))->Fill(crowstpc); + // histos.get(HIST("data/TPCclust/tpcsFindableMinusCrossedRows_pr_tpcits_1g"))->Fill(crowstpc); + // } // - histos.get(HIST("data/PID/zDCA_tpcits_pr"))->Fill(track.dcaZ()); - histos.get(HIST("data/PID/xyDCA_tpcits_pr"))->Fill(track.dcaXY()); + // histos.get(HIST("data/PID/zDCA_tpcits_pr"))->Fill(track.dcaZ()); + // histos.get(HIST("data/PID/xyDCA_tpcits_pr"))->Fill(track.dcaXY()); // histos.get(HIST("data/PID/pthist_tpcits_pr"))->Fill(trackPt); histos.get(HIST("data/PID/phihist_tpcits_pr"))->Fill(track.phi()); histos.get(HIST("data/PID/etahist_tpcits_pr"))->Fill(track.eta()); - if (positiveTrack) { + if (signOfTrack > 0) { histos.get(HIST("data/PID/pthist_tpcits_prplus"))->Fill(trackPt); histos.get(HIST("data/PID/phihist_tpcits_prplus"))->Fill(track.phi()); histos.get(HIST("data/PID/etahist_tpcits_prplus"))->Fill(track.eta()); @@ -2406,13 +2611,13 @@ struct qaMatchEff { if (isPIDProtonRequired) { if (protonPIDwithTPC) { histos.get(HIST("data/PID/pthist_tpcits_pr_PIDTPC"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpcits_prplus_PIDTPC"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpcits_prminus_PIDTPC"))->Fill(trackPt); if (!trkWTOF || !protonPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpcits_pr_PIDTPC_O"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpcits_prplus_PIDTPC_O"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpcits_prminus_PIDTPC_O"))->Fill(trackPt); @@ -2420,13 +2625,13 @@ struct qaMatchEff { } if (trkWTOF && protonPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpcits_pr_PIDTOF"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpcits_prplus_PIDTOF"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpcits_prminus_PIDTOF"))->Fill(trackPt); if (!protonPIDwithTPC) { histos.get(HIST("data/PID/pthist_tpcits_pr_PIDTOF_O"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpcits_prplus_PIDTOF_O"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpcits_prminus_PIDTOF_O"))->Fill(trackPt); @@ -2434,7 +2639,7 @@ struct qaMatchEff { } if (protonPIDwithTPC && trkWTOF && protonPIDwithTOF) { histos.get(HIST("data/PID/pthist_tpcits_pr_PIDTPCTOF"))->Fill(trackPt); - if (positiveTrack) + if (signOfTrack > 0) histos.get(HIST("data/PID/pthist_tpcits_prplus_PIDTPCTOF"))->Fill(trackPt); else histos.get(HIST("data/PID/pthist_tpcits_prminus_PIDTPCTOF"))->Fill(trackPt); @@ -2451,19 +2656,19 @@ struct qaMatchEff { const auto timestamp = track.collision().template bc_as().timestamp(); /// NB: in ms histos.get(HIST("data/hTrkITSTPCvsTime"))->Fill(timestamp); if (enableTHnSparseMonitorVsTime) { - histos.get(HIST("data/hTrkITSTPCvsTimePtEtaPosZ"))->Fill(timestamp, trackPt, track.eta(), track.collision().posZ(), 1. / trackPt, positiveTrack ? 0.5 : -0.5, track.tpcNClsFound(), track.itsNCls()); + histos.get(HIST("data/hTrkITSTPCvsTimePtEtaPosZ"))->Fill(timestamp, trackPt, track.eta(), track.collision().posZ(), 1. / trackPt, signOfTrack * 0.5, track.tpcNClsFound(), track.itsNCls()); } } } // // not identified if (!isPion && !isKaon && !isProton && (isPIDPionRequired || isPIDKaonRequired || isPIDProtonRequired)) { - histos.get(HIST("data/PID/zDCA_tpcits_noid"))->Fill(track.dcaZ()); - histos.get(HIST("data/PID/xyDCA_tpcits_noid"))->Fill(track.dcaXY()); + // histos.get(HIST("data/PID/zDCA_tpcits_noid"))->Fill(track.dcaZ()); + // histos.get(HIST("data/PID/xyDCA_tpcits_noid"))->Fill(track.dcaXY()); histos.get(HIST("data/PID/pthist_tpcits_noid"))->Fill(trackPt); histos.get(HIST("data/PID/phihist_tpcits_noid"))->Fill(track.phi()); histos.get(HIST("data/PID/etahist_tpcits_noid"))->Fill(track.eta()); - if (positiveTrack) { + if (signOfTrack > 0) { histos.get(HIST("data/PID/pthist_tpcits_noidplus"))->Fill(trackPt); histos.get(HIST("data/PID/phihist_tpcits_noidplus"))->Fill(track.phi()); histos.get(HIST("data/PID/etahist_tpcits_noidplus"))->Fill(track.eta()); @@ -2482,58 +2687,134 @@ struct qaMatchEff { } } /// control plot: correlation # ITS its vs ITS layer - int itsNhits = 0; - for (unsigned int i = 0; i < 7; i++) { - if (track.itsClusterMap() & (1 << i)) { - itsNhits += 1; - } - } + // int itsNhits = 0; + // for (unsigned int i = 0; i < 7; i++) { + // if (track.itsClusterMap() & (1 << i)) { + // itsNhits += 1; + // } + // } bool trkHasITS = false; for (unsigned int i = 0; i < 7; i++) { if (track.itsClusterMap() & (1 << i)) { trkHasITS = true; - if (IS_MC) { //////////////////////// MC - histos.fill(HIST("MC/control/itsHitsMatched"), i, itsNhits); - } else { //////////////////////// DATA - histos.fill(HIST("data/control/itsHitsMatched"), i, itsNhits); - } + // if (IS_MC) { //////////////////////// MC + // histos.fill(HIST("MC/control/itsHitsMatched"), i, itsNhits); + // } else { //////////////////////// DATA + // histos.fill(HIST("data/control/itsHitsMatched"), i, itsNhits); + // } } } if (!trkHasITS) { - if (IS_MC) { //////////////////////// MC - histos.fill(HIST("MC/control/itsHitsMatched"), -1, itsNhits); - } else { //////////////////////// DATA - histos.fill(HIST("data/control/itsHitsMatched"), -1, itsNhits); - } + // if (IS_MC) { //////////////////////// MC + // histos.fill(HIST("MC/control/itsHitsMatched"), -1, itsNhits); + // } else { //////////////////////// DATA + // histos.fill(HIST("data/control/itsHitsMatched"), -1, itsNhits); + // } } } // end if ITS - } // end if TPC + } // end if TPC + // + // + // if (trkWITS) { + // if (IS_MC) { //////////////////////// MC + // if (!trkWTPC) + // histos.get(HIST("MC/control/itsCMnoTPC"))->Fill(track.itsClusterMap()); + // if (!trkWTPC && !trkWTRD && trkWTOF) + // histos.get(HIST("MC/control/itsCMnoTPCwTOFnoTRD"))->Fill(track.itsClusterMap()); + // if (!trkWTPC && trkWTRD && !trkWTOF) + // histos.get(HIST("MC/control/itsCMnoTPCnoTOFwTRD"))->Fill(track.itsClusterMap()); + // if (!trkWTPC && trkWTRD && trkWTOF) + // histos.get(HIST("MC/control/itsCMnoTPCwTRDwTOF"))->Fill(track.itsClusterMap()); + // if (trkWTPC) + // histos.get(HIST("MC/control/itsCMwTPC"))->Fill(track.itsClusterMap()); + // if (trkWTPC && trkWTRD && !trkWTOF) + // histos.get(HIST("MC/control/itsCMwTPCwTRDnoTOF"))->Fill(track.itsClusterMap()); + // if (trkWTPC && !trkWTRD && trkWTOF) + // histos.get(HIST("MC/control/itsCMwTPCwTOFnoTRD"))->Fill(track.itsClusterMap()); + // if (trkWTPC && trkWTRD && trkWTOF) + // histos.get(HIST("MC/control/itsCMwTPCwTOFwTRD"))->Fill(track.itsClusterMap()); + // } else { //////////////////////// DATA + // if (!trkWTPC) + // histos.get(HIST("data/control/itsCMnoTPC"))->Fill(track.itsClusterMap()); + // if (!trkWTPC && !trkWTRD && trkWTOF) + // histos.get(HIST("data/control/itsCMnoTPCwTOFnoTRD"))->Fill(track.itsClusterMap()); + // if (!trkWTPC && trkWTRD && !trkWTOF) + // histos.get(HIST("data/control/itsCMnoTPCnoTOFwTRD"))->Fill(track.itsClusterMap()); + // if (!trkWTPC && trkWTRD && trkWTOF) + // histos.get(HIST("data/control/itsCMnoTPCwTRDwTOF"))->Fill(track.itsClusterMap()); + // if (trkWTPC) + // histos.get(HIST("data/control/itsCMwTPC"))->Fill(track.itsClusterMap()); + // if (trkWTPC && trkWTRD && !trkWTOF) + // histos.get(HIST("data/control/itsCMwTPCwTRDnoTOF"))->Fill(track.itsClusterMap()); + // if (trkWTPC && !trkWTRD && trkWTOF) + // histos.get(HIST("data/control/itsCMwTPCwTOFnoTRD"))->Fill(track.itsClusterMap()); + // if (trkWTPC && trkWTRD && trkWTOF) + // histos.get(HIST("data/control/itsCMwTPCwTOFwTRD"))->Fill(track.itsClusterMap()); + // } + // if (isTrackSelectedITSCuts(track)) { + // if (IS_MC) { //////////////////////// MC + // if (!trkWTPC) + // histos.get(HIST("MC/control/SitsCMnoTPC"))->Fill(track.itsClusterMap()); + // if (!trkWTPC && !trkWTRD && trkWTOF) + // histos.get(HIST("MC/control/SitsCMnoTPCwTOFnoTRD"))->Fill(track.itsClusterMap()); + // if (!trkWTPC && trkWTRD && !trkWTOF) + // histos.get(HIST("MC/control/SitsCMnoTPCnoTOFwTRD"))->Fill(track.itsClusterMap()); + // if (!trkWTPC && trkWTRD && trkWTOF) + // histos.get(HIST("MC/control/SitsCMnoTPCwTRDwTOF"))->Fill(track.itsClusterMap()); + // if (trkWTPC) + // histos.get(HIST("MC/control/SitsCMwTPC"))->Fill(track.itsClusterMap()); + // if (trkWTPC && trkWTRD && !trkWTOF) + // histos.get(HIST("MC/control/SitsCMwTPCwTRDnoTOF"))->Fill(track.itsClusterMap()); + // if (trkWTPC && !trkWTRD && trkWTOF) + // histos.get(HIST("MC/control/SitsCMwTPCwTOFnoTRD"))->Fill(track.itsClusterMap()); + // if (trkWTPC && trkWTRD && trkWTOF) + // histos.get(HIST("MC/control/SitsCMwTPCwTOFwTRD"))->Fill(track.itsClusterMap()); + // } else { //////////////////////// DATA + // if (!trkWTPC) + // histos.get(HIST("data/control/SitsCMnoTPC"))->Fill(track.itsClusterMap()); + // if (!trkWTPC && !trkWTRD && trkWTOF) + // histos.get(HIST("data/control/SitsCMnoTPCwTOFnoTRD"))->Fill(track.itsClusterMap()); + // if (!trkWTPC && trkWTRD && !trkWTOF) + // histos.get(HIST("data/control/SitsCMnoTPCnoTOFwTRD"))->Fill(track.itsClusterMap()); + // if (!trkWTPC && trkWTRD && trkWTOF) + // histos.get(HIST("data/control/SitsCMnoTPCwTRDwTOF"))->Fill(track.itsClusterMap()); + // if (trkWTPC) + // histos.get(HIST("data/control/SitsCMwTPC"))->Fill(track.itsClusterMap()); + // if (trkWTPC && trkWTRD && !trkWTOF) + // histos.get(HIST("data/control/SitsCMwTPCwTRDnoTOF"))->Fill(track.itsClusterMap()); + // if (trkWTPC && !trkWTRD && trkWTOF) + // histos.get(HIST("data/control/SitsCMwTPCwTOFnoTRD"))->Fill(track.itsClusterMap()); + // if (trkWTPC && trkWTRD && trkWTOF) + // histos.get(HIST("data/control/SitsCMwTPCwTOFwTRD"))->Fill(track.itsClusterMap()); + // } + // } + // } // // all tracks with pt>0.5 - if (trackPt > 0.5) { - if (trkWTPC && isTrackSelectedTPCCuts(track)) { - if constexpr (IS_MC) { //////////////////////// MC - histos.get(HIST("MC/pthist_tpc_05"))->Fill(trackPt); - histos.get(HIST("MC/phihist_tpc_05"))->Fill(track.phi()); - histos.get(HIST("MC/etahist_tpc_05"))->Fill(track.eta()); - } else { //////////////////////// DATA - histos.get(HIST("data/pthist_tpc_05"))->Fill(trackPt); - histos.get(HIST("data/phihist_tpc_05"))->Fill(track.phi()); - histos.get(HIST("data/etahist_tpc_05"))->Fill(track.eta()); - } - if (trkWITS && isTrackSelectedITSCuts(track)) { - if constexpr (IS_MC) { - histos.get(HIST("MC/pthist_tpcits_05"))->Fill(trackPt); - histos.get(HIST("MC/phihist_tpcits_05"))->Fill(track.phi()); - histos.get(HIST("MC/etahist_tpcits_05"))->Fill(track.eta()); - } else { - histos.get(HIST("data/pthist_tpcits_05"))->Fill(trackPt); - histos.get(HIST("data/phihist_tpcits_05"))->Fill(track.phi()); - histos.get(HIST("data/etahist_tpcits_05"))->Fill(track.eta()); - } - } // end if ITS - } // end if TPC - } // end if pt > 0.5 + // if (trackPt > 0.5) { + // if (trkWTPC && isTrackSelectedTPCCuts(track)) { + // if constexpr (IS_MC) { //////////////////////// MC + // histos.get(HIST("MC/pthist_tpc_05"))->Fill(trackPt); + // histos.get(HIST("MC/phihist_tpc_05"))->Fill(track.phi()); + // histos.get(HIST("MC/etahist_tpc_05"))->Fill(track.eta()); + // } else { //////////////////////// DATA + // histos.get(HIST("data/pthist_tpc_05"))->Fill(trackPt); + // histos.get(HIST("data/phihist_tpc_05"))->Fill(track.phi()); + // histos.get(HIST("data/etahist_tpc_05"))->Fill(track.eta()); + // } + // if (trkWITS && isTrackSelectedITSCuts(track)) { + // if constexpr (IS_MC) { + // histos.get(HIST("MC/pthist_tpcits_05"))->Fill(trackPt); + // histos.get(HIST("MC/phihist_tpcits_05"))->Fill(track.phi()); + // histos.get(HIST("MC/etahist_tpcits_05"))->Fill(track.eta()); + // } else { + // histos.get(HIST("data/pthist_tpcits_05"))->Fill(trackPt); + // histos.get(HIST("data/phihist_tpcits_05"))->Fill(track.phi()); + // histos.get(HIST("data/etahist_tpcits_05"))->Fill(track.eta()); + // } + // } // end if ITS + // } // end if TPC + // } // end if pt > 0.5 // // positive only if (track.signed1Pt() > 0) { @@ -2558,9 +2839,9 @@ struct qaMatchEff { histos.get(HIST("data/etahist_tpcits_pos"))->Fill(track.eta()); } } // end if ITS - } // end if TPC - // - } // end positive + } // end if TPC + // + } // end positive // // negative only if (track.signed1Pt() < 0) { @@ -2585,9 +2866,9 @@ struct qaMatchEff { histos.get(HIST("data/etahist_tpcits_neg"))->Fill(track.eta()); } } // end if ITS - } // end if TPC - // - } // end negative + } // end if TPC + // + } // end negative if constexpr (IS_MC) { // MC auto mcpart = track.mcParticle(); @@ -2595,68 +2876,68 @@ struct qaMatchEff { // only primaries if (mcpart.isPhysicalPrimary()) { if (trkWTPC && isTrackSelectedTPCCuts(track)) { - histos.get(HIST("MC/primsec/zDCA_tpc_prim"))->Fill(track.dcaZ()); - histos.get(HIST("MC/primsec/xyDCA_tpc_prim"))->Fill(track.dcaXY()); + // histos.get(HIST("MC/primsec/zDCA_tpc_prim"))->Fill(track.dcaZ()); + // histos.get(HIST("MC/primsec/xyDCA_tpc_prim"))->Fill(track.dcaXY()); // histos.get(HIST("MC/primsec/qopthist_tpc_prim"))->Fill(track.signed1Pt()); histos.get(HIST("MC/primsec/pthist_tpc_prim"))->Fill(trackPt); histos.get(HIST("MC/primsec/phihist_tpc_prim"))->Fill(track.phi()); histos.get(HIST("MC/primsec/etahist_tpc_prim"))->Fill(track.eta()); if (trkWITS && isTrackSelectedITSCuts(track)) { - histos.get(HIST("MC/primsec/zDCA_tpcits_prim"))->Fill(track.dcaZ()); - histos.get(HIST("MC/primsec/xyDCA_tpcits_prim"))->Fill(track.dcaXY()); + // histos.get(HIST("MC/primsec/zDCA_tpcits_prim"))->Fill(track.dcaZ()); + // histos.get(HIST("MC/primsec/xyDCA_tpcits_prim"))->Fill(track.dcaXY()); // histos.get(HIST("MC/primsec/qopthist_tpcits_prim"))->Fill(track.signed1Pt()); histos.get(HIST("MC/primsec/pthist_tpcits_prim"))->Fill(trackPt); histos.get(HIST("MC/primsec/phihist_tpcits_prim"))->Fill(track.phi()); histos.get(HIST("MC/primsec/etahist_tpcits_prim"))->Fill(track.eta()); } // end if ITS - } // end if TPC + } // end if TPC // end if primaries } else if (mcpart.getProcess() == 4) { // // only secondaries from decay if (trkWTPC && isTrackSelectedTPCCuts(track)) { - histos.get(HIST("MC/primsec/zDCA_tpc_secd"))->Fill(track.dcaZ()); - histos.get(HIST("MC/primsec/xyDCA_tpc_secd"))->Fill(track.dcaXY()); + // histos.get(HIST("MC/primsec/zDCA_tpc_secd"))->Fill(track.dcaZ()); + // histos.get(HIST("MC/primsec/xyDCA_tpc_secd"))->Fill(track.dcaXY()); // histos.get(HIST("MC/primsec/qopthist_tpc_secd"))->Fill(track.signed1Pt()); histos.get(HIST("MC/primsec/pthist_tpc_secd"))->Fill(trackPt); histos.get(HIST("MC/primsec/phihist_tpc_secd"))->Fill(track.phi()); histos.get(HIST("MC/primsec/etahist_tpc_secd"))->Fill(track.eta()); if (trkWITS && isTrackSelectedITSCuts(track)) { - histos.get(HIST("MC/primsec/zDCA_tpcits_secd"))->Fill(track.dcaZ()); - histos.get(HIST("MC/primsec/xyDCA_tpcits_secd"))->Fill(track.dcaXY()); + // histos.get(HIST("MC/primsec/zDCA_tpcits_secd"))->Fill(track.dcaZ()); + // histos.get(HIST("MC/primsec/xyDCA_tpcits_secd"))->Fill(track.dcaXY()); // histos.get(HIST("MC/primsec/qopthist_tpcits_secd"))->Fill(track.signed1Pt()); histos.get(HIST("MC/primsec/pthist_tpcits_secd"))->Fill(trackPt); histos.get(HIST("MC/primsec/phihist_tpcits_secd"))->Fill(track.phi()); histos.get(HIST("MC/primsec/etahist_tpcits_secd"))->Fill(track.eta()); } // end if ITS - } // end if TPC + } // end if TPC // end if secondaries from decay } else { // // only secondaries from material if (trkWTPC && isTrackSelectedTPCCuts(track)) { - histos.get(HIST("MC/primsec/zDCA_tpc_secm"))->Fill(track.dcaZ()); - histos.get(HIST("MC/primsec/xyDCA_tpc_secm"))->Fill(track.dcaXY()); + // histos.get(HIST("MC/primsec/zDCA_tpc_secm"))->Fill(track.dcaZ()); + // histos.get(HIST("MC/primsec/xyDCA_tpc_secm"))->Fill(track.dcaXY()); // histos.get(HIST("MC/primsec/qopthist_tpc_secm"))->Fill(track.signed1Pt()); histos.get(HIST("MC/primsec/pthist_tpc_secm"))->Fill(trackPt); histos.get(HIST("MC/primsec/phihist_tpc_secm"))->Fill(track.phi()); histos.get(HIST("MC/primsec/etahist_tpc_secm"))->Fill(track.eta()); if (trkWITS && isTrackSelectedITSCuts(track)) { - histos.get(HIST("MC/primsec/zDCA_tpcits_secm"))->Fill(track.dcaZ()); - histos.get(HIST("MC/primsec/xyDCA_tpcits_secm"))->Fill(track.dcaXY()); + // histos.get(HIST("MC/primsec/zDCA_tpcits_secm"))->Fill(track.dcaZ()); + // histos.get(HIST("MC/primsec/xyDCA_tpcits_secm"))->Fill(track.dcaXY()); // histos.get(HIST("MC/primsec/qopthist_tpcits_secm"))->Fill(track.signed1Pt()); histos.get(HIST("MC/primsec/pthist_tpcits_secm"))->Fill(trackPt); histos.get(HIST("MC/primsec/phihist_tpcits_secm"))->Fill(track.phi()); histos.get(HIST("MC/primsec/etahist_tpcits_secm"))->Fill(track.eta()); } // end if ITS - } // end if TPC - } // end if secondaries from material + } // end if TPC + } // end if secondaries from material // // protons only if (tpPDGCode == 2212) { @@ -2664,25 +2945,25 @@ struct qaMatchEff { // // TPC clusters histos.get(HIST("MC/TPCclust/tpcNClsFound_prMC_tpc"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_prMC_tpc"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_prMC_tpc"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC_tpc"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_prMC_tpc"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_prMC_tpc"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC_tpc"))->Fill(crowstpc); // // pt 1-2 - if (trackPt <= 2 && trackPt > 1) { - histos.get(HIST("MC/TPCclust/tpcNClsFound_prMC_tpc_1g"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_prMC_tpc_1g"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_prMC_tpc_1g"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC_tpc_1g"))->Fill(crowstpc); - } + // if (trackPt <= 2 && trackPt > 1) { + // histos.get(HIST("MC/TPCclust/tpcNClsFound_prMC_tpc_1g"))->Fill(clustpc); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_prMC_tpc_1g"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_prMC_tpc_1g"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC_tpc_1g"))->Fill(crowstpc); + // } // - histos.get(HIST("MC/PID/zDCA_tpc_pr"))->Fill(track.dcaZ()); - histos.get(HIST("MC/PID/xyDCA_tpc_pr"))->Fill(track.dcaXY()); + // histos.get(HIST("MC/PID/zDCA_tpc_pr"))->Fill(track.dcaZ()); + // histos.get(HIST("MC/PID/xyDCA_tpc_pr"))->Fill(track.dcaXY()); // histos.get(HIST("MC/PID/pthist_tpc_pr"))->Fill(trackPt); histos.get(HIST("MC/PID/phihist_tpc_pr"))->Fill(track.phi()); histos.get(HIST("MC/PID/etahist_tpc_pr"))->Fill(track.eta()); - if (positiveTrack) { + if (signOfTrack > 0) { histos.get(HIST("MC/PID/pthist_tpc_prplus"))->Fill(trackPt); histos.get(HIST("MC/PID/phihist_tpc_prplus"))->Fill(track.phi()); histos.get(HIST("MC/PID/etahist_tpc_prplus"))->Fill(track.eta()); @@ -2695,25 +2976,25 @@ struct qaMatchEff { // // TPC clusters histos.get(HIST("MC/TPCclust/tpcNClsFound_prMC_tpcits"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_prMC_tpcits"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_prMC_tpcits"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC_tpcits"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_prMC_tpcits"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_prMC_tpcits"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC_tpcits"))->Fill(crowstpc); // // pt 1-2 - if (trackPt <= 2 && trackPt > 1) { - histos.get(HIST("MC/TPCclust/tpcNClsFound_prMC_tpcits_1g"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_prMC_tpcits_1g"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_prMC_tpcits_1g"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC_tpcits_1g"))->Fill(crowstpc); - } - // - histos.get(HIST("MC/PID/zDCA_tpcits_pr"))->Fill(track.dcaZ()); - histos.get(HIST("MC/PID/xyDCA_tpcits_pr"))->Fill(track.dcaXY()); + // if (trackPt <= 2 && trackPt > 1) { + // histos.get(HIST("MC/TPCclust/tpcNClsFound_prMC_tpcits_1g"))->Fill(clustpc); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_prMC_tpcits_1g"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_prMC_tpcits_1g"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_prMC_tpcits_1g"))->Fill(crowstpc); + // } + // // + // histos.get(HIST("MC/PID/zDCA_tpcits_pr"))->Fill(track.dcaZ()); + // histos.get(HIST("MC/PID/xyDCA_tpcits_pr"))->Fill(track.dcaXY()); // histos.get(HIST("MC/PID/pthist_tpcits_pr"))->Fill(trackPt); histos.get(HIST("MC/PID/phihist_tpcits_pr"))->Fill(track.phi()); histos.get(HIST("MC/PID/etahist_tpcits_pr"))->Fill(track.eta()); - if (positiveTrack) { + if (signOfTrack > 0) { histos.get(HIST("MC/PID/pthist_tpcits_prplus"))->Fill(trackPt); histos.get(HIST("MC/PID/phihist_tpcits_prplus"))->Fill(track.phi()); histos.get(HIST("MC/PID/etahist_tpcits_prplus"))->Fill(track.eta()); @@ -2723,7 +3004,7 @@ struct qaMatchEff { histos.get(HIST("MC/PID/etahist_tpcits_prminus"))->Fill(track.eta()); } } // end if ITS - } // end if TPC + } // end if TPC } // // pions only @@ -2732,25 +3013,25 @@ struct qaMatchEff { // // TPC clusters histos.get(HIST("MC/TPCclust/tpcNClsFound_piMC_tpc"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_piMC_tpc"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_piMC_tpc"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC_tpc"))->Fill(crowstpc); - // - // pt 1-2 - if (trackPt <= 2 && trackPt > 1) { - histos.get(HIST("MC/TPCclust/tpcNClsFound_piMC_tpc_1g"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_piMC_tpc_1g"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_piMC_tpc_1g"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC_tpc_1g"))->Fill(crowstpc); - } - // - histos.get(HIST("MC/PID/zDCA_tpc_pi"))->Fill(track.dcaZ()); - histos.get(HIST("MC/PID/xyDCA_tpc_pi"))->Fill(track.dcaXY()); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_piMC_tpc"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_piMC_tpc"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC_tpc"))->Fill(crowstpc); + // // + // // pt 1-2 + // if (trackPt <= 2 && trackPt > 1) { + // histos.get(HIST("MC/TPCclust/tpcNClsFound_piMC_tpc_1g"))->Fill(clustpc); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_piMC_tpc_1g"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_piMC_tpc_1g"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC_tpc_1g"))->Fill(crowstpc); + // } + // // + // histos.get(HIST("MC/PID/zDCA_tpc_pi"))->Fill(track.dcaZ()); + // histos.get(HIST("MC/PID/xyDCA_tpc_pi"))->Fill(track.dcaXY()); // histos.get(HIST("MC/PID/pthist_tpc_pi"))->Fill(trackPt); histos.get(HIST("MC/PID/phihist_tpc_pi"))->Fill(track.phi()); histos.get(HIST("MC/PID/etahist_tpc_pi"))->Fill(track.eta()); - if (positiveTrack) { + if (signOfTrack > 0) { histos.get(HIST("MC/PID/pthist_tpc_piplus"))->Fill(trackPt); histos.get(HIST("MC/PID/phihist_tpc_piplus"))->Fill(track.phi()); histos.get(HIST("MC/PID/etahist_tpc_piplus"))->Fill(track.eta()); @@ -2763,25 +3044,25 @@ struct qaMatchEff { // // TPC clusters histos.get(HIST("MC/TPCclust/tpcNClsFound_piMC_tpcits"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_piMC_tpcits"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_piMC_tpcits"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC_tpcits"))->Fill(crowstpc); - // - // pt 1-2 - if (trackPt <= 2 && trackPt > 1) { - histos.get(HIST("MC/TPCclust/tpcNClsFound_piMC_tpcits_1g"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_piMC_tpcits_1g"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_piMC_tpcits_1g"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC_tpcits_1g"))->Fill(crowstpc); - } - // - histos.get(HIST("MC/PID/zDCA_tpcits_pi"))->Fill(track.dcaZ()); - histos.get(HIST("MC/PID/xyDCA_tpcits_pi"))->Fill(track.dcaXY()); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_piMC_tpcits"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_piMC_tpcits"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC_tpcits"))->Fill(crowstpc); + // // + // // pt 1-2 + // if (trackPt <= 2 && trackPt > 1) { + // histos.get(HIST("MC/TPCclust/tpcNClsFound_piMC_tpcits_1g"))->Fill(clustpc); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_piMC_tpcits_1g"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_piMC_tpcits_1g"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_piMC_tpcits_1g"))->Fill(crowstpc); + // } + // // + // histos.get(HIST("MC/PID/zDCA_tpcits_pi"))->Fill(track.dcaZ()); + // histos.get(HIST("MC/PID/xyDCA_tpcits_pi"))->Fill(track.dcaXY()); // histos.get(HIST("MC/PID/pthist_tpcits_pi"))->Fill(trackPt); histos.get(HIST("MC/PID/phihist_tpcits_pi"))->Fill(track.phi()); histos.get(HIST("MC/PID/etahist_tpcits_pi"))->Fill(track.eta()); - if (positiveTrack) { + if (signOfTrack > 0) { histos.get(HIST("MC/PID/pthist_tpcits_piplus"))->Fill(trackPt); histos.get(HIST("MC/PID/phihist_tpcits_piplus"))->Fill(track.phi()); histos.get(HIST("MC/PID/etahist_tpcits_piplus"))->Fill(track.eta()); @@ -2791,7 +3072,7 @@ struct qaMatchEff { histos.get(HIST("MC/PID/etahist_tpcits_piminus"))->Fill(track.eta()); } } // end if ITS - } // end if TPC + } // end if TPC // // only primary pions if (mcpart.isPhysicalPrimary()) { @@ -2804,7 +3085,7 @@ struct qaMatchEff { histos.get(HIST("MC/PID/phihist_tpcits_pi_prim"))->Fill(track.phi()); histos.get(HIST("MC/PID/etahist_tpcits_pi_prim"))->Fill(track.eta()); } // end if ITS - } // end if TPC + } // end if TPC // end if primaries } else if (mcpart.getProcess() == 4) { // @@ -2818,7 +3099,7 @@ struct qaMatchEff { histos.get(HIST("MC/PID/phihist_tpcits_pi_secd"))->Fill(track.phi()); histos.get(HIST("MC/PID/etahist_tpcits_pi_secd"))->Fill(track.eta()); } // end if ITS - } // end if TPC + } // end if TPC // end if secondaries from decay } else { // @@ -2832,9 +3113,9 @@ struct qaMatchEff { histos.get(HIST("MC/PID/phihist_tpcits_pi_secm"))->Fill(track.phi()); histos.get(HIST("MC/PID/etahist_tpcits_pi_secm"))->Fill(track.eta()); } // end if ITS - } // end if TPC - } // end if secondaries from material // - } // end pions only + } // end if TPC + } // end if secondaries from material // + } // end pions only // // no primary/sec-d pions if (!((tpPDGCode == 211) && (mcpart.isPhysicalPrimary()))) { @@ -2858,8 +3139,8 @@ struct qaMatchEff { histos.get(HIST("MC/PID/etahist_tpcits_nopi"))->Fill(track.eta()); histos.get(HIST("MC/PID/pdghist_num"))->Fill(pdg_fill); } // end if ITS - } // end if TPC - } // end if not prim/sec-d pi + } // end if TPC + } // end if not prim/sec-d pi // // kaons only if (tpPDGCode == 321) { @@ -2867,25 +3148,25 @@ struct qaMatchEff { // // TPC clusters histos.get(HIST("MC/TPCclust/tpcNClsFound_kaMC_tpc"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_kaMC_tpc"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_kaMC_tpc"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC_tpc"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_kaMC_tpc"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_kaMC_tpc"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC_tpc"))->Fill(crowstpc); // // pt 1-2 - if (trackPt <= 2 && trackPt > 1) { - histos.get(HIST("MC/TPCclust/tpcNClsFound_kaMC_tpc_1g"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_kaMC_tpc_1g"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_kaMC_tpc_1g"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC_tpc_1g"))->Fill(crowstpc); - } + // if (trackPt <= 2 && trackPt > 1) { + // histos.get(HIST("MC/TPCclust/tpcNClsFound_kaMC_tpc_1g"))->Fill(clustpc); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_kaMC_tpc_1g"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_kaMC_tpc_1g"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC_tpc_1g"))->Fill(crowstpc); + // } // - histos.get(HIST("MC/PID/zDCA_tpc_ka"))->Fill(track.dcaZ()); - histos.get(HIST("MC/PID/xyDCA_tpc_ka"))->Fill(track.dcaXY()); + // histos.get(HIST("MC/PID/zDCA_tpc_ka"))->Fill(track.dcaZ()); + // histos.get(HIST("MC/PID/xyDCA_tpc_ka"))->Fill(track.dcaXY()); // histos.get(HIST("MC/PID/pthist_tpc_ka"))->Fill(trackPt); histos.get(HIST("MC/PID/phihist_tpc_ka"))->Fill(track.phi()); histos.get(HIST("MC/PID/etahist_tpc_ka"))->Fill(track.eta()); - if (positiveTrack) { + if (signOfTrack > 0) { histos.get(HIST("MC/PID/pthist_tpc_kaplus"))->Fill(trackPt); histos.get(HIST("MC/PID/phihist_tpc_kaplus"))->Fill(track.phi()); histos.get(HIST("MC/PID/etahist_tpc_kaplus"))->Fill(track.eta()); @@ -2898,25 +3179,25 @@ struct qaMatchEff { // // TPC clusters histos.get(HIST("MC/TPCclust/tpcNClsFound_kaMC_tpcits"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_kaMC_tpcits"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_kaMC_tpcits"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC_tpcits"))->Fill(crowstpc); - // - // pt 1-2 - if (trackPt <= 2 && trackPt > 1) { - histos.get(HIST("MC/TPCclust/tpcNClsFound_kaMC_tpcits_1g"))->Fill(clustpc); - histos.get(HIST("MC/TPCclust/tpcNClsFindable_kaMC_tpcits_1g"))->Fill(findcltpc); - histos.get(HIST("MC/TPCclust/tpcCrossedRows_kaMC_tpcits_1g"))->Fill(crowstpc); - histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC_tpcits_1g"))->Fill(crowstpc); - } - // - histos.get(HIST("MC/PID/zDCA_tpcits_ka"))->Fill(track.dcaZ()); - histos.get(HIST("MC/PID/xyDCA_tpcits_ka"))->Fill(track.dcaXY()); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_kaMC_tpcits"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_kaMC_tpcits"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC_tpcits"))->Fill(crowstpc); + // // + // // pt 1-2 + // if (trackPt <= 2 && trackPt > 1) { + // histos.get(HIST("MC/TPCclust/tpcNClsFound_kaMC_tpcits_1g"))->Fill(clustpc); + // histos.get(HIST("MC/TPCclust/tpcNClsFindable_kaMC_tpcits_1g"))->Fill(findcltpc); + // histos.get(HIST("MC/TPCclust/tpcCrossedRows_kaMC_tpcits_1g"))->Fill(crowstpc); + // histos.get(HIST("MC/TPCclust/tpcsFindableMinusCrossedRows_kaMC_tpcits_1g"))->Fill(crowstpc); + // } + // // + // histos.get(HIST("MC/PID/zDCA_tpcits_ka"))->Fill(track.dcaZ()); + // histos.get(HIST("MC/PID/xyDCA_tpcits_ka"))->Fill(track.dcaXY()); // histos.get(HIST("MC/PID/pthist_tpcits_ka"))->Fill(trackPt); histos.get(HIST("MC/PID/phihist_tpcits_ka"))->Fill(track.phi()); histos.get(HIST("MC/PID/etahist_tpcits_ka"))->Fill(track.eta()); - if (positiveTrack) { + if (signOfTrack > 0) { histos.get(HIST("MC/PID/pthist_tpcits_kaplus"))->Fill(trackPt); histos.get(HIST("MC/PID/phihist_tpcits_kaplus"))->Fill(track.phi()); histos.get(HIST("MC/PID/etahist_tpcits_kaplus"))->Fill(track.eta()); @@ -2926,7 +3207,7 @@ struct qaMatchEff { histos.get(HIST("MC/PID/etahist_tpcits_kaminus"))->Fill(track.eta()); } } // end if ITS - } // end if TPC + } // end if TPC } // // pions and kaons together @@ -2940,7 +3221,7 @@ struct qaMatchEff { histos.get(HIST("MC/PID/phihist_tpcits_piK"))->Fill(track.phi()); histos.get(HIST("MC/PID/etahist_tpcits_piK"))->Fill(track.eta()); } // end if ITS - } // end if TPC + } // end if TPC } } // @@ -2974,12 +3255,13 @@ struct qaMatchEff { /// If we are here, the current run was never considered before. /// Let's add the TH2 that we need for the monitoring /// Let's define the x-axis according to the start-of-run (SOR) and end-of-run (EOR) times + o2::ccdb::CcdbApi ccdb_api; ccdb_api.init(ccdburl); - std::map metadataRCT, headers; - headers = ccdb_api.retrieveHeaders(Form("RCT/Info/RunInformation/%i", runNumber), metadataRCT, -1); - tsSOR = atol(headers["SOR"].c_str()); - tsEOR = atol(headers["EOR"].c_str()); + auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdb_api, runNumber); + tsSOR = soreor.first; + tsEOR = soreor.second; + double minMilliSec = floor(tsSOR); /// round tsSOR to the highest integer lower than tsSOR double maxMilliSec = ceil(tsEOR); /// round tsEOR to the lowest integer higher than tsEOR const AxisSpec axisSeconds{static_cast((maxMilliSec - minMilliSec) * 1. / 10.), minMilliSec, maxMilliSec, "time from January 1st, 1970 at UTC (unit: 10 ms)"}; @@ -3011,18 +3293,56 @@ struct qaMatchEff { ////////////////////////////////////////////// /// Process MC with collision grouping /// ////////////////////////////////////////////// - void processMC(soa::Filtered::iterator const& collision, soa::Join const& tracks, aod::McParticles const& mcParticles) + void processMC(CollisionsEvSel::iterator const& collision, soa::Join const& tracks, aod::McParticles const& mcParticles) { + if (isEnableEventSelection && !collision.sel8()) { + if (doDebug) + LOGF(info, "Event selection not passed, skipping..."); + return; + } fillHistograms(tracks, mcParticles, mcParticles); /// 3rd argument non-sense in this case fillGeneralHistos(collision); } PROCESS_SWITCH(qaMatchEff, processMC, "process MC", false); + ///////////////////////////////////////////////////////////////////////////////// + /// Process data with collision grouping and centraliy information joined /// + ///////////////////////////////////////////////////////////////////////////////// + void processMCPbPbCent(CollisionsMCEvSelFT0C::iterator const& collision, MCTracks const& tracks, aod::McParticles const& mcParticles) + { + if (!isPbPb) { + if (doDebug) + LOGF(warning, "Centrality not defined for pp collision type, return..."); + return; + } + if (isEnableEventSelection && !collision.sel8()) { + if (doDebug) + LOGF(info, "Event selection not passed, skipping..."); + return; + } + float centrality = collision.centFT0C(); + if (isCentralityRequired) { + if (centrality < centralityCuts.centralityMinCut || centrality > centralityCuts.centralityMaxCut) { + if (doDebug) + LOGF(info, "Centrality not in the range, skipping..."); + return; + } + } + fillHistograms(tracks, mcParticles, mcParticles); /// 3rd argument non-sense in this case + fillGeneralHistos(collision); + } + PROCESS_SWITCH(qaMatchEff, processMCPbPbCent, "process MC with centrality info", false); + //////////////////////////////////////////////////////////// /// Process MC with collision grouping and IU tracks /// //////////////////////////////////////////////////////////// - void processTrkIUMC(soa::Filtered::iterator const& collision, soa::Join const& tracks, aod::McParticles const& mcParticles) + void processTrkIUMC(CollisionsMCEvSel::iterator const& collision, MCTracksIU const& tracks, aod::McParticles const& mcParticles) { + if (isEnableEventSelection && !collision.sel8()) { + if (doDebug) + LOGF(info, "Event selection not passed, skipping..."); + return; + } fillHistograms(tracks, mcParticles, mcParticles); /// 3rd argument non-sense in this case fillGeneralHistos(collision); } @@ -3031,7 +3351,7 @@ struct qaMatchEff { ///////////////////////////////////////////// /// Process MC w/o collision grouping /// ///////////////////////////////////////////// - void processMCNoColl(soa::Join const& tracks, aod::McParticles const& mcParticles) + void processMCNoColl(MCTracks const& tracks, aod::McParticles const& mcParticles) { fillHistograms(tracks, mcParticles, mcParticles); /// 3rd argument non-sense in this case } @@ -3040,22 +3360,78 @@ struct qaMatchEff { //////////////////////////////////////////////// /// Process data with collision grouping /// //////////////////////////////////////////////// - void processData(soa::Filtered::iterator const& collision, soa::Join const& tracks, BCsWithTimeStamp const& bcs) + void processData(CollisionsEvSel::iterator const& collision, TracksPID const& tracks, BCsWithTimeStamp const& bcs) { if (enableMonitorVsTime) { // tracks.rawIteratorAt(0).collision().bc_as().timestamp(); /// NB: in ms setUpTimeMonitoring(bcs); } + if (isEnableEventSelection && !collision.sel8()) { + if (doDebug) + LOGF(info, "Event selection not passed, skipping..."); + return; + } fillHistograms(tracks, tracks, bcs); // 2nd argument not used in this case fillGeneralHistos(collision); } PROCESS_SWITCH(qaMatchEff, processData, "process data", true); + ///////////////////////////////////////////////////////////////////////////////// + /// Process data with collision grouping and centraliy information joined /// + ///////////////////////////////////////////////////////////////////////////////// + void processDataPbPbCent(CollisionsEvSelFT0C::iterator const& collision, TracksPID const& tracks, BCsWithTimeStamp const& bcs) + { + if (!isPbPb) { + if (doDebug) + LOGF(warning, "Centrality not defined for pp collision type, return..."); + return; + } + if (enableMonitorVsTime) { + setUpTimeMonitoring(bcs); + } + if (isEnableEventSelection && !collision.sel8()) { + if (doDebug) + LOGF(info, "Event selection not passed, skipping..."); + return; + } + const float centrality = collision.centFT0C(); + const int occupancy = collision.trackOccupancyInTimeRange(); + if (isCentralityRequired) { + if (centrality < centralityCuts.centralityMinCut || centrality > centralityCuts.centralityMaxCut) { + if (doDebug) + LOGF(info, "Centrality not in the range, skipping..."); + return; + } + } + if (isRejectNearByEvent) { + if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + if (doDebug) + LOGF(info, "Nearby event found, skipping..."); + return; + } + } + if (isEnableOccupancyCut) { + if (occupancy < occupancyCuts.minTracksInTimeRange || occupancy > occupancyCuts.maxTracksInTimeRange) { + if (doDebug) + LOGF(info, "Occupancy not in the range, skipping..."); + return; + } + } + fillHistograms(tracks, tracks, bcs); // 2nd argument not used in this case + fillGeneralHistos(collision); + } + PROCESS_SWITCH(qaMatchEff, processDataPbPbCent, "process data with centrality info", false); + ///////////////////////////////////////////////////////////// /// Process data with collision grouping and IU tracks /// ///////////////////////////////////////////////////////////// - void processTrkIUData(soa::Filtered::iterator const& collision, soa::Join const& tracks) + void processTrkIUData(CollisionsEvSel::iterator const& collision, TracksIUPID const& tracks) { + if (isEnableEventSelection && !collision.sel8()) { + if (doDebug) + LOGF(info, "Event selection not passed, skipping..."); + return; + } fillHistograms(tracks, tracks, tracks); // 2nd and 3rd arguments not used in this case fillGeneralHistos(collision); } @@ -3064,15 +3440,14 @@ struct qaMatchEff { /////////////////////////////////////////////// /// Process data w/o collision grouping /// /////////////////////////////////////////////// - void processDataNoColl(soa::Join const& tracks, BCsWithTimeStamp const& bcs) + void processDataNoColl(TracksPID const& tracks, BCsWithTimeStamp const& bcs) { if (enableMonitorVsTime) { setUpTimeMonitoring(bcs); } fillHistograms(tracks, tracks, bcs); // 2nd argument not used in this case } - PROCESS_SWITCH(qaMatchEff, processDataNoColl, "process data - no collision grouping", true); - + PROCESS_SWITCH(qaMatchEff, processDataNoColl, "process data - no collision grouping", false); }; // end of structure WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/DPG/Tasks/AOTTrack/qaPrimVtxVsTime.cxx b/DPG/Tasks/AOTTrack/qaPrimVtxVsTime.cxx index 6ffd533d67b..dd66692a4e2 100644 --- a/DPG/Tasks/AOTTrack/qaPrimVtxVsTime.cxx +++ b/DPG/Tasks/AOTTrack/qaPrimVtxVsTime.cxx @@ -68,10 +68,11 @@ struct QaPrimVtxVsTime { /// Let's define the x-axis according to the start-of-run (SOR) and end-of-run (EOR) times o2::ccdb::CcdbApi ccdb_api; ccdb_api.init(ccdburl); - std::map metadataRCT, headers; - headers = ccdb_api.retrieveHeaders(Form("RCT/Info/RunInformation/%i", runNumber), metadataRCT, -1); - tsSOR = atol(headers["SOR"].c_str()); - tsEOR = atol(headers["EOR"].c_str()); + + auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdb_api, runNumber); + tsSOR = soreor.first; + tsEOR = soreor.second; + double minSec = floor(tsSOR / 1000.); /// round tsSOR to the highest integer lower than tsSOR double maxSec = ceil(tsEOR / 1000.); /// round tsEOR to the lowest integer higher than tsEOR const AxisSpec axisSeconds{static_cast(maxSec - minSec), minSec, maxSec, "seconds (from January 1st, 1970 at UTC)"}; @@ -96,4 +97,4 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ adaptAnalysisTask(cfgc)}; -} \ No newline at end of file +} diff --git a/DPG/Tasks/AOTTrack/qaSignChargeMC.cxx b/DPG/Tasks/AOTTrack/qaSignChargeMC.cxx new file mode 100644 index 00000000000..e40dd0e76e9 --- /dev/null +++ b/DPG/Tasks/AOTTrack/qaSignChargeMC.cxx @@ -0,0 +1,140 @@ +// 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 qaSignChargeMC.cxx +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Task to analyse the sign and charge of MC particles +/// \since 08/05/2024 +/// + +// O2 includes +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" + +using namespace o2::framework; + +struct QaSignChargeMC { + // Histograms + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Configurable PDG{"PDG", 2212, "PDG code of the particle of interest"}; + Configurable absPDG{"absPDG", true, "Check the PDG code in abs. value"}; + Configurable noFakeHits{"noFakeHits", true, "Check the PDG code in abs. value"}; + Configurable selPrimaries{"selPrimaries", true, "Select primaries"}; + Configurable trdSel{"trdSel", 0, "TRD selection: -1 = no TRD, 0 = all, 1 = TRD only"}; + Configurable tofSel{"tofSel", 0, "TOF selection: -1 = no TOF, 0 = all, 1 = TOF only"}; + + Service pdg; + + void init(InitContext&) + { + const AxisSpec axisReco{5, -2.5f, 2.5f, "Track sign"}; + const AxisSpec axisCharge{61, -60.5f, 60.5f, "Particle charge"}; + const AxisSpec axisPt{100, 0.f, 5.f, "#it{p}_{T} (GeV/#it{c})"}; + histos.add("sign_charge", "sign_charge", HistType::kTH2F, {axisReco, axisCharge}); + histos.add("sign_charge_pt", "sign_charge_pt", HistType::kTH3F, {axisReco, axisCharge, axisPt}); + } + + template + double getCharge(ParticleType const& particle) + { + auto pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (!pdgParticle) { + LOG(warning) << "PDG code not found: " << particle.pdgCode() << " returning 0.f as default charge."; + return 0.f; + } + return pdgParticle->Charge(); + } + + void process(o2::soa::Join const& tracks, + o2::aod::McParticles const&) + { + for (auto const& track : tracks) { + if (std::abs(track.eta()) > 0.8) { + continue; + } + if (!track.hasITS()) { + continue; + } + if (!track.hasTPC()) { + continue; + } + if (!track.has_mcParticle()) { + continue; + } + if (absPDG) { + if (std::abs(track.mcParticle().pdgCode()) != PDG) { + continue; + } + } else { + if (track.mcParticle().pdgCode() != PDG) { + continue; + } + } + if (selPrimaries && !track.mcParticle().isPhysicalPrimary()) { + continue; + } + switch (trdSel) { + case 0: + break; + case -1: + if (track.hasTRD()) { + continue; + } + break; + case 1: + if (!track.hasTRD()) { + continue; + } + break; + default: + LOG(fatal) << "Invalid TRD selection: " << trdSel.value; + break; + } + switch (tofSel) { + case 0: + break; + case -1: + if (track.hasTOF()) { + continue; + } + break; + case 1: + if (!track.hasTOF()) { + continue; + } + break; + default: + LOG(fatal) << "Invalid TOF selection: " << tofSel.value; + break; + } + + if (noFakeHits) { // Selecting tracks with no fake hits + bool hasFakeHit = false; + for (int i = 0; i < 10; i++) { // From ITS to TPC + if (track.mcMask() & 1 << i) { + hasFakeHit = true; + break; + } + } + if (hasFakeHit) { + continue; + } + } + histos.fill(HIST("sign_charge"), track.sign(), getCharge(track.mcParticle())); + histos.fill(HIST("sign_charge_pt"), track.sign(), getCharge(track.mcParticle()), track.pt()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/DPG/Tasks/AOTTrack/qaTrackSelection.cxx b/DPG/Tasks/AOTTrack/qaTrackSelection.cxx index 895db111497..f7ea3dd2f53 100644 --- a/DPG/Tasks/AOTTrack/qaTrackSelection.cxx +++ b/DPG/Tasks/AOTTrack/qaTrackSelection.cxx @@ -125,7 +125,7 @@ struct QaTrackCuts { customTrackCuts.SetRequireGoldenChi2(requireGoldenChi2.value); customTrackCuts.SetMaxChi2PerClusterTPC(maxChi2PerClusterTPC.value); customTrackCuts.SetMaxChi2PerClusterITS(maxChi2PerClusterITS.value); - if (abs(maxDcaXYFactor.value - 1.f) > 1e-6) { // No DCAxy cut will be used, this is done via the member function of the task + if (std::abs(maxDcaXYFactor.value - 1.f) > 1e-6) { // No DCAxy cut will be used, this is done via the member function of the task customTrackCuts.SetMaxDcaXYPtDep([](float /*pt*/) { return 10000.f; }); } customTrackCuts.SetMaxDcaZ(maxDcaZ.value); diff --git a/DPG/Tasks/AOTTrack/qaTrackSplitting.cxx b/DPG/Tasks/AOTTrack/qaTrackSplitting.cxx new file mode 100644 index 00000000000..3125f1e7c03 --- /dev/null +++ b/DPG/Tasks/AOTTrack/qaTrackSplitting.cxx @@ -0,0 +1,170 @@ +// 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 qaTrackSplitting.cxx +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Task to analyse the numbers of particles reconstructed more than once +/// + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/TrackSelectionTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct qaTrackSplitting { + Configurable pdg{"pdg", 2212, "PDG code of the particle to be analysed"}; + struct : ConfigurableGroup { + Configurable enableTrackCuts{"enableTrackCuts", false, "Enable the custom track cuts"}; + Configurable itsPattern{"itsPattern", 0, "0 = Run3ITSibAny, 1 = Run3ITSallAny, 2 = Run3ITSall7Layers, 3 = Run3ITSibTwo"}; + Configurable requireITS{"requireITS", true, "Additional cut on the ITS requirement"}; + Configurable requireTPC{"requireTPC", true, "Additional cut on the TPC requirement"}; + Configurable requireGoldenChi2{"requireGoldenChi2", true, "Additional cut on the GoldenChi2"}; + Configurable minITScl{"minITScl", 4, "Additional cut on the ITS cluster"}; + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 70.f, "Additional cut on the minimum number of crossed rows in the TPC"}; + Configurable minNCrossedRowsOverFindableClustersTPC{"minNCrossedRowsOverFindableClustersTPC", 0.8f, "Additional cut on the minimum value of the ratio between crossed rows and findable clusters in the TPC"}; + Configurable maxChi2PerClusterTPC{"maxChi2PerClusterTPC", 4.f, "Additional cut on the maximum value of the chi2 per cluster in the TPC"}; + Configurable maxChi2PerClusterITS{"maxChi2PerClusterITS", 36.f, "Additional cut on the maximum value of the chi2 per cluster in the ITS"}; + Configurable maxDcaXY{"maxDcaXY", 10000.f, "Additional cut on the maximum abs value of the DCA xy"}; + Configurable maxDcaZ{"maxDcaZ", 2.f, "Additional cut on the maximum abs value of the DCA z"}; + Configurable minTPCNClsFound{"minTPCNClsFound", 0.f, "Additional cut on the minimum value of the number of found clusters in the TPC"}; + + Configurable windowEta{"windowEta", 0.f, "Position in eta of the window"}; + Configurable windowEtaWidth{"windowEtaWidth", 0.1f, "Width of the eta window"}; + Configurable windowPhi{"windowPhi", 0.785f, "Position in phi of the window"}; + Configurable windowPhiWidth{"windowPhiWidth", 0.1f, "Width of the phi window"}; + Configurable windowPt{"windowPt", 1.f, "Position in pt of the window"}; + Configurable windowPtWidth{"windowPtWidth", 0.1f, "Width of the pt window"}; + + } cfgCustomTrackCuts; + + // Histograms + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + TrackSelection customTrackCuts; + + void init(InitContext&) + { + histos.add("tracks", "tracsk", kTH1D, {{10, -0.5, 9.5, "Track selection"}}); + histos.add("numberOfRecoed", "recoed", kTH1D, {{10, -0.5, 9.5, "Number of tracks associated to a particle"}}); + histos.add("map", "map", kTH3D, {{100, -1, 1, "#Delta #eta"}, {100, -1, 1, "#Delta #varphi"}, {100, -1, 1, "#Delta #it{p}_{T}"}}); + histos.add("deltaPt", "deltaPt", kTH2D, {{100, 0, 5, "#it{p}_{T}"}, {100, -1, 1, "#Delta #it{p}_{T}"}}); + histos.add("mapMC", "mapMC", kTH3D, {{100, -1, 1, "#Delta #eta"}, {100, -1, 1, "#Delta #varphi"}, {100, -1, 1, "#Delta #it{p}_{T}"}}); + + customTrackCuts = getGlobalTrackSelectionRun3ITSMatch(cfgCustomTrackCuts.itsPattern); + LOG(info) << "Customizing track cuts:"; + customTrackCuts.SetRequireITSRefit(cfgCustomTrackCuts.requireITS); + customTrackCuts.SetRequireTPCRefit(cfgCustomTrackCuts.requireTPC); + customTrackCuts.SetRequireGoldenChi2(cfgCustomTrackCuts.requireGoldenChi2); + customTrackCuts.SetRequireHitsInITSLayers(cfgCustomTrackCuts.minITScl.value, {0, 1, 2, 3, 4, 5, 6}); + customTrackCuts.SetMaxChi2PerClusterTPC(cfgCustomTrackCuts.maxChi2PerClusterTPC); + customTrackCuts.SetMaxChi2PerClusterITS(cfgCustomTrackCuts.maxChi2PerClusterITS); + customTrackCuts.SetMinNCrossedRowsTPC(cfgCustomTrackCuts.minNCrossedRowsTPC); + customTrackCuts.SetMinNClustersTPC(cfgCustomTrackCuts.minTPCNClsFound); + customTrackCuts.SetMinNCrossedRowsOverFindableClustersTPC(cfgCustomTrackCuts.minNCrossedRowsOverFindableClustersTPC); + customTrackCuts.SetMaxDcaXYPtDep([&](float /*pt*/) { return cfgCustomTrackCuts.maxDcaXY; }); // No DCAxy cut will be used, this is done via the member function of the task + customTrackCuts.SetMaxDcaZ(cfgCustomTrackCuts.maxDcaZ); + customTrackCuts.print(); + } + + using CollisionCandidates = o2::soa::Join; + using TrackCandidates = o2::soa::Join; + Filter trackFilterEta = nabs(aod::track::eta - cfgCustomTrackCuts.windowEta) < cfgCustomTrackCuts.windowEtaWidth; + Filter trackFilterPhi = nabs(aod::track::phi - cfgCustomTrackCuts.windowPhi) < cfgCustomTrackCuts.windowPhiWidth; + Filter trackFilterITS = (aod::track::itsClusterSizes > (uint32_t)0); + Filter trackFilterTPC = (aod::track::tpcNClsFindable > (uint8_t)0); + // Filter trackFilterType = (aod::track::TrackType == aod::track::Track); + // Filter filterPt = nabs(aod::track::pt - cfgCustomTrackCuts.windowPt) < cfgCustomTrackCuts.windowPtWidth; + void processData(CollisionCandidates const& collisions, + soa::Filtered const& filteredTracks) + { + for (const auto& coll1 : collisions) { + for (const auto& coll2 : collisions) { + if (coll1.globalIndex() == coll2.globalIndex()) { + continue; + } + for (const auto& track2 : filteredTracks) { + // Compute the delta in pT + for (const auto& track1 : filteredTracks) { + if (track1.globalIndex() == track2.globalIndex()) { + continue; + } + histos.fill(HIST("deltaPt"), track1.pt(), track1.pt() - track2.pt()); + } + } + } + } + } + PROCESS_SWITCH(qaTrackSplitting, processData, "Process Data", true); + + using CollisionCandidatesMC = soa::Join; + using TrackCandidatesMC = o2::soa::Join; + void processMC(CollisionCandidatesMC::iterator const& collision, + TrackCandidatesMC const& tracks, + o2::aod::McParticles const&) + { + if (!collision.sel8()) { + return; + } + typedef std::shared_ptr trkType; + + std::map> particleUsageCounter; + for (auto track : tracks) { + histos.fill(HIST("tracks"), 0); + if (!track.has_mcParticle()) { + continue; + } + histos.fill(HIST("tracks"), 1); + const auto& mcParticle = track.mcParticle(); + if (mcParticle.pdgCode() != pdg) { + continue; + } + histos.fill(HIST("tracks"), 2); + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + histos.fill(HIST("tracks"), 3); + if (cfgCustomTrackCuts.enableTrackCuts.value && !customTrackCuts.IsSelected(track)) { + continue; + } + histos.fill(HIST("tracks"), 4); + particleUsageCounter[track.mcParticleId()].push_back(std::make_shared(track)); + } + for (const auto& [mcId, tracksMatched] : particleUsageCounter) { + histos.fill(HIST("numberOfRecoed"), tracksMatched.size()); + if (tracksMatched.size() > 1) { + bool isFirst = true; + for (const auto& track : tracksMatched) { + if (isFirst) { + isFirst = false; + histos.fill(HIST("mapMC"), + track->eta() - track->mcParticle().eta(), + track->phi() - track->mcParticle().phi(), + track->pt() - track->mcParticle().pt()); + continue; + } + histos.fill(HIST("map"), + track->eta() - tracksMatched[0]->eta(), + track->phi() - tracksMatched[0]->phi(), + track->pt() - tracksMatched[0]->pt()); + } + } + } + } + PROCESS_SWITCH(qaTrackSplitting, processMC, "Process MC", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/DPG/Tasks/AOTTrack/tagAndProbeDmesons.cxx b/DPG/Tasks/AOTTrack/tagAndProbeDmesons.cxx index 1dea5ebebe1..2d236ee0230 100644 --- a/DPG/Tasks/AOTTrack/tagAndProbeDmesons.cxx +++ b/DPG/Tasks/AOTTrack/tagAndProbeDmesons.cxx @@ -15,19 +15,22 @@ /// \author Fabrizio Grosa , CERN #include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" #include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" #include "Common/Core/trackUtilities.h" +#include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "CommonConstants/PhysicsConstants.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" #include "DCAFitter/DCAFitterN.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/CollisionAssociationTables.h" -#include "Common/Core/TrackSelection.h" +#include "PWGHF/Utils/utilsAnalysis.h" +#include "Tools/ML/MlResponse.h" +#include using namespace o2; using namespace o2::framework; @@ -58,42 +61,42 @@ enum SignalFlags : uint8_t { Bkg = 0, Prompt, NonPrompt, - Resonant + Resonant, + BkgFromNoHf }; static constexpr int nBinsPt = 7; -static constexpr int nCutVars = 6; -static constexpr int nCutVarsDzero = 9; -constexpr float binsPt[nBinsPt + 1] = {0., 1., 2., 4., 6., 10., 20., 1000.}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +static constexpr int nCutVars = 9; +constexpr double binsPt[nBinsPt + 1] = {0., 1., 2., 4., 6., 10., 20., 1000.}; +auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; // default values for the cuts -constexpr float cuts[nBinsPt][nCutVars] = {{0.1f, 1.5f, 0.01f, 0.01f, 2.f, 2.f}, - {0.1f, 1.5f, 0.01f, 0.01f, 2.f, 2.f}, - {0.1f, 1.5f, 0.02f, 0.02f, 2.f, 2.f}, - {0.1f, 1.5f, 0.02f, 0.02f, 2.f, 2.f}, - {0.1f, 1.5f, 0.04f, 0.04f, 2.f, 2.f}, - {0.1f, 1.5f, 0.04f, 0.04f, 2.f, 2.f}, - {0.1f, 1.5f, 0.06f, 0.06f, 2.f, 2.f}}; - -constexpr float cutsDzero[nBinsPt][nCutVarsDzero] = {{1.815f, 1.915f, 0.01f, 0.01f, 2.f, 2.f, 0.f, 0.90f, 0.90f}, - {1.815f, 1.915f, 0.01f, 0.01f, 2.f, 2.f, 0.f, 0.90f, 0.90f}, - {1.815f, 1.915f, 0.02f, 0.02f, 2.f, 2.f, 0.f, 0.90f, 0.90f}, - {1.815f, 1.915f, 0.02f, 0.02f, 2.f, 2.f, 0.f, 0.90f, 0.90f}, - {1.815f, 1.915f, 0.04f, 0.04f, 2.f, 2.f, 0.f, 0.95f, 0.95f}, - {1.815f, 1.915f, 0.04f, 0.04f, 2.f, 2.f, 0.f, 0.95f, 0.95f}, - {1.815f, 1.915f, 0.06f, 0.06f, 2.f, 2.f, 0.f, 0.95f, 0.95f}}; - -static const std::vector labelsPt{}; -static const std::vector labelsCutVar = {"minMass", "maxMass", "decayLength", "decayLengthXY", "normDecayLength", "normDecayLengthXY"}; -static const std::vector labelsCutVarDzero = {"minMass", "maxMass", "decayLength", "decayLengthXY", "normDecayLength", "normDecayLengthXY", "impParProd", "cosPointing", "cosPointingXY"}; +constexpr double cuts[nBinsPt][nCutVars] = {{1.815f, 1.915f, 0.01f, 0.01f, 2.f, 2.f, 0.f, 0.90f, 0.90f}, + {1.815f, 1.915f, 0.01f, 0.01f, 2.f, 2.f, 0.f, 0.90f, 0.90f}, + {1.815f, 1.915f, 0.02f, 0.02f, 2.f, 2.f, 0.f, 0.90f, 0.90f}, + {1.815f, 1.915f, 0.02f, 0.02f, 2.f, 2.f, 0.f, 0.90f, 0.90f}, + {1.815f, 1.915f, 0.04f, 0.04f, 2.f, 2.f, 0.f, 0.95f, 0.95f}, + {1.815f, 1.915f, 0.04f, 0.04f, 2.f, 2.f, 0.f, 0.95f, 0.95f}, + {1.815f, 1.915f, 0.06f, 0.06f, 2.f, 2.f, 0.f, 0.95f, 0.95f}}; + +constexpr double mlCuts[nBinsPt][3] = {{0.f, 0.f, 0.f}, + {0.f, 0.f, 0.f}, + {0.f, 0.f, 0.f}, + {0.f, 0.f, 0.f}, + {0.f, 0.f, 0.f}, + {0.f, 0.f, 0.f}, + {0.f, 0.f, 0.f}}; + +static const std::vector labelsEmpty{}; +static const std::vector labelsCutVar = {"min mass", "max mass", "min decayLength", "min decayLengthXY", "min normDecayLength", "min normDecayLengthXY", "max impParProd", "min cosPointing", "min cosPointingXY"}; +static const std::vector labelsMlScores = {"max bkg score", "min prompt score", "min non-prompt score"}; DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! Collision index DECLARE_SOA_INDEX_COLUMN_FULL(Track0, track0, int, Tracks, "_0"); //! Index to first track DECLARE_SOA_INDEX_COLUMN_FULL(Track1, track1, int, Tracks, "_1"); //! Index to second track // Topological variables DECLARE_SOA_COLUMN(TagPt, tagPt, float); //! Tag's pT -DECLARE_SOA_COLUMN(TagInvMass, tagInvMass2, float); //! Tag's invMass +DECLARE_SOA_COLUMN(TagInvMass, tagInvMass, float); //! Tag's invMass DECLARE_SOA_COLUMN(DecayLength, decayLength, float); //! Decay length of the tag (cm) DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); //! Transverse decay length of the tag (cm) DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); //! Normalised decay length of the tag @@ -103,32 +106,55 @@ DECLARE_SOA_COLUMN(TrackDcaXY1, trackDcaXY1, float); //! DECLARE_SOA_COLUMN(ProductTrackDcaXY, productTrackDcaXY, float); //! Product of DCAxy of the two tag tracks DECLARE_SOA_COLUMN(Cpa, cpa, float); //! Cosine pointing angle of the tag DECLARE_SOA_COLUMN(CpaXY, cpaXY, float); //! Cosine of the pointing angle in XY of the tag -DECLARE_SOA_COLUMN(IsSignal, isSignal, uint8_t); //! Flag for a signal DECLARE_SOA_COLUMN(DecChannel, decChannel, uint8_t); //! Flag the selected decay channel +// MC info +DECLARE_SOA_COLUMN(IsSignal, isSignal, uint8_t); //! Flag for a signal +DECLARE_SOA_INDEX_COLUMN_FULL(Mother, mother, int, McParticles, ""); //! Index to MC particle mother of the tag tracks +// ML scores +DECLARE_SOA_COLUMN(MlScores, mlScores, std::vector); //! ML scores (bkg, prompt, non-prompt) } // namespace tagandprobe DECLARE_SOA_TABLE(PiPiFromDpTags, "AOD", "PIPIFROMDPTAG", //! Table for same sign 2-pion vertices used as tags soa::Index<>, aod::tagandprobe::CollisionId, aod::tagandprobe::Track0Id, - aod::tagandprobe::Track1Id); + aod::tagandprobe::Track1Id, + aod::tagandprobe::MlScores); +DECLARE_SOA_TABLE(PiPiFromDpMcTags, "AOD", "PIPIFROMDPMCTAG", //! Table with MC truth for same sign 2-pion vertices used as tags + aod::tagandprobe::IsSignal, + aod::tagandprobe::MotherId); DECLARE_SOA_TABLE(KaKaFromDspTags, "AOD", "KAKAFROMDSPTAG", //! Table for opposite sign 2-kaon vertices used as tags soa::Index<>, aod::tagandprobe::CollisionId, aod::tagandprobe::Track0Id, aod::tagandprobe::Track1Id, + aod::tagandprobe::MlScores, + soa::Marker<1>); +DECLARE_SOA_TABLE(KaKaFromDsMcTags, "AOD", "KAKAFROMDSMCTAG", //! Table with MC truth for opposite sign 2-kaon vertices used as tags + aod::tagandprobe::IsSignal, + aod::tagandprobe::MotherId, soa::Marker<1>); DECLARE_SOA_TABLE(PiKaFromDzTags, "AOD", "PIKAFROMDZTAG", //! Table for opposite sign pion(+)-kaon(-) vertices used as tags soa::Index<>, aod::tagandprobe::CollisionId, aod::tagandprobe::Track0Id, aod::tagandprobe::Track1Id, + aod::tagandprobe::MlScores, + soa::Marker<2>); +DECLARE_SOA_TABLE(PiKaFromDzMcTags, "AOD", "PIKAFROMDZMCTAG", //! Table with MC truth for opposite sign pion(+)-kaon(-) vertices used as tags + aod::tagandprobe::IsSignal, + aod::tagandprobe::MotherId, soa::Marker<2>); DECLARE_SOA_TABLE(KaPiFromDzTags, "AOD", "KAPIFROMDZTAG", //! Table for opposite sign kaon(+)-pion(-) vertices used as tags soa::Index<>, aod::tagandprobe::CollisionId, aod::tagandprobe::Track0Id, aod::tagandprobe::Track1Id, + aod::tagandprobe::MlScores, + soa::Marker<3>); +DECLARE_SOA_TABLE(KaPiFromDzMcTags, "AOD", "KAPIFROMDZMCTAG", //! Table with MC truth for opposite sign kaon(+)-pion(-) vertices used as tags + aod::tagandprobe::IsSignal, + aod::tagandprobe::MotherId, soa::Marker<3>); DECLARE_SOA_TABLE(TagTopoVariables, "AOD", "TAGTOPOVARIABLE", //! Table for the Tags' Topological variables aod::tagandprobe::TagPt, @@ -153,12 +179,19 @@ DECLARE_SOA_TABLE(TagTopoVariables, "AOD", "TAGTOPOVARIABLE", //! Table for the struct TagTwoProngDisplacedVertices { Produces tagPiPiTable; + Produces tagPiPiMcTable; Produces tagKaKaTable; + Produces tagKaKaMcTable; Produces tagKaPiTable; + Produces tagKaPiMcTable; Produces tagPiKaTable; + Produces tagPiKaMcTable; Produces tagVarsTable; + SliceCache cache; - Configurable fillTagTable{"fillTagTable", 0, "flag to fill tag table with topological variables (0 -> disabled, 1 -> signal only, 2 -> bkg only, 3 -> both)"}; + Configurable fillTopoVarsTable{"fillTopoVarsTable", 0, "flag to fill tag table with topological variables (0 -> disabled, 1 -> signal only, 2 -> bkg only, 3 -> bkg from no HF only, 4 -> all)"}; + Configurable downsamplingForTopoVarTable{"downsamplingForTopoVarTable", 1.1, "fraction of tag candidates to downscale in filling table with topological variables"}; + Configurable ptTagMaxForDownsampling{"ptTagMaxForDownsampling", 5., "maximum pT for downscaling of tag candidates in filling table with topological variables"}; Configurable applyTofPid{"applyTofPid", true, "flag to enable TOF PID selection"}; Configurable studyDzeroReflections{"studyDzeroReflections", false, "flag to study Dzero reflections"}; Configurable trackNumSigmaTof{"trackNumSigmaTof", 3.f, "number of sigma for TOF PID compatibility"}; @@ -166,15 +199,42 @@ struct TagTwoProngDisplacedVertices { Configurable trackDcaXyMin{"trackDcaXyMin", 0.002f, "minimum DCAxy for tracks with pT < 2 GeV/c"}; Configurable trackPtMin{"trackPtMin", 0.4f, "minimum track pT"}; - Configurable> binsPtPiPiFromDplus{"binsPtPiPiFromDplus", std::vector{aod::tagandprobe::vecBinsPt}, "pT bin limits for pipi pairs from D+ decays"}; - Configurable> binsKaKaFromDsOrDplus{"binsKaKaFromDsOrDplus", std::vector{aod::tagandprobe::vecBinsPt}, "pT bin limits for KK pairs from Ds or D+ decays"}; - Configurable> binsPtDzeroFromDstar{"binsPtDzeroFromDstar", std::vector{aod::tagandprobe::vecBinsPt}, "pT bin limits for Kpi pairs from D0 <- D*+ decays"}; - Configurable> binsPtDzeroKaKaFromDstar{"binsPtDzeroKaKaFromDstar", std::vector{aod::tagandprobe::vecBinsPt}, "pT bin limits for KK pairs from D0 <- D*+ decays"}; - - Configurable> cutsPiPiFromDplus{"cutsPiPiFromDplus", {aod::tagandprobe::cuts[0], aod::tagandprobe::nBinsPt, aod::tagandprobe::nCutVars, aod::tagandprobe::labelsPt, aod::tagandprobe::labelsCutVar}, "Selections for pipi pairs from D+ decays"}; - Configurable> cutsKaKaFromDsOrDplus{"cutsKaKaFromDsOrDplus", {aod::tagandprobe::cuts[0], aod::tagandprobe::nBinsPt, aod::tagandprobe::nCutVars, aod::tagandprobe::labelsPt, aod::tagandprobe::labelsCutVar}, "Selections for KK pairs from Ds or D+ decays"}; - Configurable> cutsDzeroFromDstar{"cutsDzeroFromDstar", {aod::tagandprobe::cutsDzero[0], aod::tagandprobe::nBinsPt, aod::tagandprobe::nCutVarsDzero, aod::tagandprobe::labelsPt, aod::tagandprobe::labelsCutVarDzero}, "Selections for Kpi pairs from D0 <- D*+ decays"}; - Configurable> cutsDzeroKaKaFromDstar{"cutsDzeroKaKaFromDstar", {aod::tagandprobe::cutsDzero[0], aod::tagandprobe::nBinsPt, aod::tagandprobe::nCutVarsDzero, aod::tagandprobe::labelsPt, aod::tagandprobe::labelsCutVarDzero}, "Selections for Kpi pairs from D0 <- D*+ decays"}; + Configurable> binsPtPiPiFromDplus{"binsPtPiPiFromDplus", std::vector{aod::tagandprobe::vecBinsPt}, "pT bin limits for pipi pairs from D+ decays"}; + Configurable> binsPtKaKaFromDsOrDplus{"binsPtKaKaFromDsOrDplus", std::vector{aod::tagandprobe::vecBinsPt}, "pT bin limits for KK pairs from Ds or D+ decays"}; + Configurable> binsPtDzeroFromDstar{"binsPtDzeroFromDstar", std::vector{aod::tagandprobe::vecBinsPt}, "pT bin limits for Kpi pairs from D0 <- D*+ decays"}; + Configurable> binsPtDzeroKaKaFromDstar{"binsPtDzeroKaKaFromDstar", std::vector{aod::tagandprobe::vecBinsPt}, "pT bin limits for KK pairs from D0 <- D*+ decays"}; + + Configurable> cutsPiPiFromDplus{"cutsPiPiFromDplus", {aod::tagandprobe::cuts[0], aod::tagandprobe::nBinsPt, aod::tagandprobe::nCutVars, aod::tagandprobe::labelsEmpty, aod::tagandprobe::labelsCutVar}, "Selections for pipi pairs from D+ decays"}; + Configurable> cutsKaKaFromDsOrDplus{"cutsKaKaFromDsOrDplus", {aod::tagandprobe::cuts[0], aod::tagandprobe::nBinsPt, aod::tagandprobe::nCutVars, aod::tagandprobe::labelsEmpty, aod::tagandprobe::labelsCutVar}, "Selections for KK pairs from Ds or D+ decays"}; + Configurable> cutsDzeroFromDstar{"cutsDzeroFromDstar", {aod::tagandprobe::cuts[0], aod::tagandprobe::nBinsPt, aod::tagandprobe::nCutVars, aod::tagandprobe::labelsEmpty, aod::tagandprobe::labelsCutVar}, "Selections for Kpi pairs from D0 <- D*+ decays"}; + Configurable> cutsDzeroKaKaFromDstar{"cutsDzeroKaKaFromDstar", {aod::tagandprobe::cuts[0], aod::tagandprobe::nBinsPt, aod::tagandprobe::nCutVars, aod::tagandprobe::labelsEmpty, aod::tagandprobe::labelsCutVar}, "Selections for KK pairs from D0 <- D*+ decays"}; + + // ML models for triggers + struct : ConfigurableGroup { + std::string prefix = "ML"; + Configurable applyMlPiPiFromDplus{"applyMlPiPiFromDplus", false, "Flag to enable ML application for pipi pairs from D+ decays"}; + Configurable applyMlKaKaFromDsOrDplus{"applyMlKaKaFromDsOrDplus", false, "Flag to enable ML application for KK pairs from Ds or D+ decays"}; + Configurable applyMlDzeroFromDstar{"applyMlDzeroFromDstar", false, "Flag to enable ML application for Kpi pairs from D0 <- D*+ decays"}; + Configurable applyMlDzeroKaKaFromDstar{"applyMlDzeroKaKaFromDstar", false, "Flag to enable ML application for KK pairs from D0 <- D*+ decays"}; + Configurable timestampCcdbForMlModels{"timestampCcdbForMlModels", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; + Configurable loadMlModelsFromCcdb{"loadMlModelsFromCcdb", true, "Flag to enable or disable the loading of ML models from CCDB"}; + // ML models (one per pT bin) + Configurable> modelPathsCcdbPiPiFromDplus{"modelPathsCcdbPiPiFromDplus", std::vector{"/Users/f/fgrosa/TagAndProbe/DplusPt2to3"}, "Paths of models on CCDB for pipi pairs from D+ decays"}; + Configurable> modelPathsCcdbKaKaFromDsOrDplus{"modelPathsCcdbKaKaFromDsOrDplus", std::vector{"/Users/f/fgrosa/TagAndProbe/DsPt2to3"}, "Paths of models on CCDB for KK pairs from Ds or D+ decays"}; + Configurable> modelPathsCcdbDzeroFromDstar{"modelPathsCcdbDzeroFromDstar", std::vector{"/Users/f/fgrosa/TagAndProbe/DzeroPt2to3"}, "Paths of models on CCDB for Kpi pairs from D0 <- D*+ decays"}; + Configurable> modelPathsCcdbDzeroKaKaFromDstar{"modelPathsCcdbDzeroKaKaFromDstar", std::vector{"/Users/f/fgrosa/TagAndProbe/DzeroToKKPt2to3"}, "Paths of models on CCDB for KK pairs from D0 <- D*+ decays"}; + Configurable> onnxFileNamesPiPiFromDplus{"onnxFileNamesPiPiFromDplus", std::vector{"ModelHandler_onnx_DplusToKPiPi.onnx"}, "ONNX file names for pipi pairs from D+ decays"}; + Configurable> onnxFileNamesKaKaFromDsOrDplus{"onnxFileNamesKaKaFromDsOrDplus", std::vector{"ModelHandler_onnx_DsToKKPi.onnx"}, "ONNX file names for KK pairs from Ds or D+ decays"}; + Configurable> onnxFileNamesDzeroFromDstar{"onnxFileNamesDzeroFromDstar", std::vector{"ModelHandler_onnx_DzeroToKPi.onnx"}, "ONNX file names for Kpi pairs from D0 <- D*+ decays"}; + Configurable> onnxFileNamesDzeroKaKaFromDstar{"onnxFileNamesDzeroKaKaFromDstar", std::vector{"ModelHandler_onnx_DzeroToKK.onnx"}, "ONNX file names for KK pairs from D0 <- D*+ decays"}; + // ML cuts + Configurable numMlClasses{"numMlClasses", 3, "Number of classes for the ML models"}; + Configurable> cutDirMl{"cutDirMl", std::vector{o2::cuts_ml::CutDirection::CutGreater, o2::cuts_ml::CutDirection::CutSmaller, o2::cuts_ml::CutDirection::CutSmaller}, "Whether to reject score values greater or smaller than the threshold"}; + Configurable> mlCutsPiPiFromDplus{"mlCutsPiPiFromDplus", {aod::tagandprobe::mlCuts[0], aod::tagandprobe::nBinsPt, 3, aod::tagandprobe::labelsEmpty, aod::tagandprobe::labelsMlScores}, "ML Selections for pipi pairs from D+ decays"}; + Configurable> mlCutsKaKaFromDsOrDplus{"mlCutsKaKaFromDsOrDplus", {aod::tagandprobe::mlCuts[0], aod::tagandprobe::nBinsPt, 3, aod::tagandprobe::labelsEmpty, aod::tagandprobe::labelsMlScores}, "ML Selections for KK pairs from Ds or D+ decays"}; + Configurable> mlCutsDzeroFromDstar{"mlCutsDzeroFromDstar", {aod::tagandprobe::mlCuts[0], aod::tagandprobe::nBinsPt, 3, aod::tagandprobe::labelsEmpty, aod::tagandprobe::labelsMlScores}, "ML Selections for Kpi pairs from D0 <- D*+ decays"}; + Configurable> mlCutsDzeroKaKaFromDstar{"mlCutsDzeroKaKaFromDstar", {aod::tagandprobe::mlCuts[0], aod::tagandprobe::nBinsPt, 3, aod::tagandprobe::labelsEmpty, aod::tagandprobe::labelsMlScores}, "ML Selections for KK pairs from D0 <- D*+ decays"}; + } mlConfig; using TracksWithSelAndDca = soa::Join; using TracksWithSelAndDcaMc = soa::Join; @@ -198,6 +258,8 @@ struct TagTwoProngDisplacedVertices { Partition positiveKaonsMc = aod::track::signed1Pt > 0.f && nabs(aod::pidtpc::tpcNSigmaKa) < trackNumSigmaTpc; Partition negativeKaonsMc = aod::track::signed1Pt < 0.f && nabs(aod::pidtpc::tpcNSigmaKa) < trackNumSigmaTpc; + std::array, aod::tagandprobe::TagChannels::NTagChannels> mlResponse{}; + std::array applyMl{}; ccdb::CcdbApi ccdbApi; Service ccdb; vertexing::DCAFitterN<2> vertexer; @@ -209,13 +271,21 @@ struct TagTwoProngDisplacedVertices { std::array{constants::physics::MassKaonCharged, constants::physics::MassPionCharged}, std::array{constants::physics::MassKaonCharged, constants::physics::MassKaonCharged}}; - std::array, aod::tagandprobe::TagChannels::NTagChannels> topologicalCuts{}; - std::array, aod::tagandprobe::TagChannels::NTagChannels> ptBinsForTopologicalCuts{}; + std::array, aod::tagandprobe::TagChannels::NTagChannels> topologicalCuts{}; + std::array, aod::tagandprobe::TagChannels::NTagChannels> ptBinsForTopologicalCuts{}; + std::vector> hBkgMlScore{}; + std::vector> hPromptMlScore{}; + std::vector> hNonPromptMlScore{}; + std::vector> hDataMlScore{}; HistogramRegistry registry{"registry"}; void init(InitContext&) { + if ((doprocessPiPiFromDplus && doprocessPiPiFromDplusMc) || (doprocessKaKaFromDsOrDplus && doprocessKaKaFromDsOrDplusMc) || (doprocessKaPiFromDstar && doprocessKaPiFromDstarMc)) { + LOGP(fatal, "The process functions for the same channel with and without MC truth cannot be enabled at the same time! Please check your configuration"); + } + std::string ccdbUrl = "http://alice-ccdb.cern.ch"; ccdb->setURL(ccdbUrl.data()); ccdb->setCaching(true); @@ -232,7 +302,7 @@ struct TagTwoProngDisplacedVertices { vertexer.setUseAbsDCA(false); topologicalCuts = {cutsPiPiFromDplus, cutsKaKaFromDsOrDplus, cutsDzeroFromDstar, cutsDzeroFromDstar, cutsDzeroKaKaFromDstar}; - ptBinsForTopologicalCuts = {binsPtPiPiFromDplus, binsKaKaFromDsOrDplus, binsPtDzeroFromDstar, binsPtDzeroFromDstar, binsPtDzeroKaKaFromDstar}; + ptBinsForTopologicalCuts = {binsPtPiPiFromDplus, binsPtKaKaFromDsOrDplus, binsPtDzeroFromDstar, binsPtDzeroFromDstar, binsPtDzeroKaKaFromDstar}; const AxisSpec axisPt{250, 0.f, 50.f}; const AxisSpec axisPtDzeroRefl{{0.f, 0.5f, 0.75f, 1.0f, 1.25f, 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 10.0f, 12.0f, 14.0f, 16.0f, 18.0f, 20.0f, 24.0f, 30.0f, 40.0f}}; @@ -240,14 +310,15 @@ struct TagTwoProngDisplacedVertices { const AxisSpec axisReflFlag{3, 0.5f, 3.5f}; const AxisSpec axisMassKaKa{200, constants::physics::MassPhi - 0.05f, constants::physics::MassPhi + 0.05f}; const AxisSpec axisMassKaPi{400, constants::physics::MassD0 - 0.2f, constants::physics::MassD0 + 0.2f}; + const AxisSpec axisMlScore{1000, 0.f, 1.f}; - if (doprocessPiPiFromDplus) { + if (doprocessPiPiFromDplus || doprocessPiPiFromDplusMc) { registry.add("hMassPiPiVsPt", ";#it{p}_{T}(#pi#pi) (GeV/#it{c}); #it{M}(#pi#pi) (GeV/#it{c}^{2})", HistType::kTH2D, {axisPt, axisMassPiPi}); } - if (doprocessKaKaFromDsOrDplus) { + if (doprocessKaKaFromDsOrDplus || doprocessKaKaFromDsOrDplusMc) { registry.add("hMassKaKaVsPt", ";#it{p}_{T}(KK) (GeV/#it{c}); #it{M}(KK) (GeV/#it{c}^{2})", HistType::kTH2D, {axisPt, axisMassKaKa}); } - if (doprocessKaPiFromDstar) { + if (doprocessKaPiFromDstar || doprocessKaPiFromDstarMc) { if (!studyDzeroReflections) { registry.add("hMassKaPiVsPt", ";#it{p}_{T}(K#pi) (GeV/#it{c}); #it{M}(K#pi) (GeV/#it{c}^{2})", HistType::kTH2D, {axisPt, axisMassKaPi}); } else { @@ -257,26 +328,41 @@ struct TagTwoProngDisplacedVertices { if (doprocessKaKaFromDzero) { registry.add("hMassDzeroKaKaVsPt", ";#it{p}_{T}(K#pi) (GeV/#it{c}); #it{M}(K#pi) (GeV/#it{c}^{2})", HistType::kTH2D, {axisPt, axisMassKaPi}); } - } - /// Finds pT bin in an array. - /// \param bins array of pT bins - /// \param value pT - /// \return index of the pT bin - template - int findBin(T1 const& binsPt, T2 value) - { - if (value < binsPt->front()) { - return -1; + if (mlConfig.applyMlPiPiFromDplus || mlConfig.applyMlDzeroFromDstar || mlConfig.applyMlKaKaFromDsOrDplus || mlConfig.applyMlDzeroKaKaFromDstar) { + if (doprocessPiPiFromDplusMc || doprocessKaKaFromDsOrDplusMc || doprocessKaPiFromDstarMc) { + for (int iScore{0}; iScore < mlConfig.numMlClasses; ++iScore) { + hBkgMlScore.push_back(registry.add(Form("hBkgMlScore%d", iScore), Form(";#it{p}_{T}(tag) (GeV/#it{c});ML score %d; counts", iScore), HistType::kTH2D, {axisPt, axisMlScore})); + hPromptMlScore.push_back(registry.add(Form("hPromptMlScore%d", iScore), Form(";#it{p}_{T}(tag) (GeV/#it{c});ML score %d; counts", iScore), HistType::kTH2D, {axisPt, axisMlScore})); + hNonPromptMlScore.push_back(registry.add(Form("hNonPromptMlScore%d", iScore), Form(";#it{p}_{T}(tag) (GeV/#it{c});ML score %d; counts", iScore), HistType::kTH2D, {axisPt, axisMlScore})); + } + } else { + for (int iScore{0}; iScore < mlConfig.numMlClasses; ++iScore) { + hDataMlScore.push_back(registry.add(Form("hMlScore%d", iScore), Form(";#it{p}_{T}(tag) (GeV/#it{c});ML score %d; counts", iScore), HistType::kTH2D, {axisPt, axisMlScore})); + } + } } - if (value >= binsPt->back()) { - return -1; + + const std::array, aod::tagandprobe::TagChannels::NTagChannels> mlCuts = {mlConfig.mlCutsPiPiFromDplus, mlConfig.mlCutsKaKaFromDsOrDplus, mlConfig.mlCutsDzeroFromDstar, mlConfig.mlCutsDzeroFromDstar, mlConfig.mlCutsDzeroKaKaFromDstar}; + const std::array, aod::tagandprobe::TagChannels::NTagChannels> onnxFileNames = {mlConfig.onnxFileNamesPiPiFromDplus, mlConfig.onnxFileNamesKaKaFromDsOrDplus, mlConfig.onnxFileNamesDzeroFromDstar, mlConfig.onnxFileNamesDzeroFromDstar, mlConfig.onnxFileNamesDzeroKaKaFromDstar}; + const std::array, aod::tagandprobe::TagChannels::NTagChannels> modelPathsCcdb = {mlConfig.modelPathsCcdbPiPiFromDplus, mlConfig.modelPathsCcdbKaKaFromDsOrDplus, mlConfig.modelPathsCcdbDzeroFromDstar, mlConfig.modelPathsCcdbDzeroFromDstar, mlConfig.modelPathsCcdbDzeroKaKaFromDstar}; + applyMl = {mlConfig.applyMlPiPiFromDplus, mlConfig.applyMlKaKaFromDsOrDplus, mlConfig.applyMlDzeroFromDstar, mlConfig.applyMlDzeroFromDstar, mlConfig.applyMlDzeroKaKaFromDstar}; + for (auto iChannel{0u}; iChannel < aod::tagandprobe::TagChannels::NTagChannels; ++iChannel) { + if (applyMl[iChannel]) { + mlResponse[iChannel].configure(ptBinsForTopologicalCuts[iChannel], mlCuts[iChannel], mlConfig.cutDirMl, mlConfig.numMlClasses); + if (mlConfig.loadMlModelsFromCcdb) { + mlResponse[iChannel].setModelPathsCCDB(onnxFileNames[iChannel], ccdbApi, modelPathsCcdb[iChannel], mlConfig.timestampCcdbForMlModels); + } else { + mlResponse[iChannel].setModelPathsLocal(onnxFileNames[iChannel]); + } + mlResponse[iChannel].init(); + } } - return std::distance(binsPt->begin(), std::upper_bound(binsPt->begin(), binsPt->end(), value)) - 1; } /// Fill a vector with the Mothers pdg codes - /// \param pdgMother vector with the pdg codes + /// \param pdgDecayMothers vector pdg codes of possible mothers + /// \param pdgResonances vector pdg codes of possible resonanced in the decays /// \param channel decay channel void pdgMothersDecayChannel(std::vector& pdgDecayMothers, std::vector& pdgResonances, const uint8_t channel) { @@ -302,16 +388,20 @@ struct TagTwoProngDisplacedVertices { /// Check if the given tag tracks belong to a D meson /// \param firstTrack candidate /// \param SecondTrack candidate - /// \param particlesMc McParticles table + /// \param mcParticles McParticles table /// \param channel decay channel + /// \param pdgDecayMothers vector pdg codes of possible mothers + /// \param pdgResonances vector pdg codes of possible resonanced in the decays + /// \param motherIdx particle mother index /// \return a flag that contains the information of MC truth (see aod::tagandprobe::SignalFlags) template uint8_t getTagOrigin(TTrack const& firsTrack, TTrack const& secondTrack, - PParticles const& particlesMc, + PParticles const& mcParticles, const uint8_t channel, std::vector& pdgDecayMothers, - std::vector& pdgResonances) + std::vector& pdgResonances, + int& motherIdx) { int pdgTagMother{0}; int pdgProbeParticle{-1}; @@ -329,20 +419,22 @@ struct TagTwoProngDisplacedVertices { } if (!firsTrack.has_mcParticle() || !secondTrack.has_mcParticle()) { - return BIT(aod::tagandprobe::SignalFlags::Bkg); + SETBIT(signalFlag, aod::tagandprobe::SignalFlags::Bkg); + SETBIT(signalFlag, aod::tagandprobe::SignalFlags::BkgFromNoHf); + return signalFlag; } else { auto firstMcTrack = firsTrack.template mcParticle_as(); auto secondMcTrack = secondTrack.template mcParticle_as(); - auto firstTrackMotherId = RecoDecay::getMother(particlesMc, firstMcTrack, pdgTagMother, true); - auto secondTrackMotherId = RecoDecay::getMother(particlesMc, secondMcTrack, pdgTagMother, true); + auto firstTrackMotherId = RecoDecay::getMother(mcParticles, firstMcTrack, pdgTagMother, true); + auto secondTrackMotherId = RecoDecay::getMother(mcParticles, secondMcTrack, pdgTagMother, true); bool isTaggedAsSignal{false}, isResonant{false}; if ((firstTrackMotherId == secondTrackMotherId) && (firstTrackMotherId != -1)) { - auto particleMother = particlesMc.rawIteratorAt(firstTrackMotherId); + auto particleMother = mcParticles.rawIteratorAt(firstTrackMotherId); /// π±π± for D± → K∓π±π± decays if (channel == aod::tagandprobe::TagChannels::DplusToKPiPi) { - auto particleMother = particlesMc.rawIteratorAt(firstTrackMotherId); + auto particleMother = mcParticles.rawIteratorAt(firstTrackMotherId); auto daughters = particleMother.template daughters_as(); // Check if the probe is within the mother's particle daughters @@ -350,6 +442,7 @@ struct TagTwoProngDisplacedVertices { for (auto& daughter : daughters) { if (std::abs(daughter.pdgCode()) == pdgProbeParticle) { isTaggedAsSignal = true; + motherIdx = firstTrackMotherId; break; } } @@ -359,6 +452,7 @@ struct TagTwoProngDisplacedVertices { if (std::find(pdgResonances.begin(), pdgResonances.end(), absPdg) != pdgResonances.end()) { isTaggedAsSignal = true; isResonant = true; + motherIdx = firstTrackMotherId; break; } } @@ -367,15 +461,16 @@ struct TagTwoProngDisplacedVertices { /// K∓K± for φ from Ds± or D± → φπ± decays /// K∓π± for D0 from D±* → D0π± decays for (auto pdgGrandMother : pdgDecayMothers) { - auto grandMotherId = RecoDecay::getMother(particlesMc, particleMother, pdgGrandMother, true); + auto grandMotherId = RecoDecay::getMother(mcParticles, particleMother, pdgGrandMother, true); if (grandMotherId != -1) { - auto particleGrandMother = particlesMc.rawIteratorAt(grandMotherId); + auto particleGrandMother = mcParticles.rawIteratorAt(grandMotherId); auto daughters = particleGrandMother.template daughters_as(); // Check if the probe is within the GrandMother's particle daughters if (daughters.size() == 2) { // exclude undesired decays, such as Ds± → φπ±π±π∓ for (auto& daughter : daughters) { if (std::abs(daughter.pdgCode()) == pdgProbeParticle) { isTaggedAsSignal = true; + motherIdx = grandMotherId; break; } } @@ -387,7 +482,7 @@ struct TagTwoProngDisplacedVertices { // check if it is non-prompt from beauty if (isTaggedAsSignal) { - if (RecoDecay::getCharmHadronOrigin(particlesMc, particlesMc.rawIteratorAt(firstTrackMotherId)) == RecoDecay::OriginType::NonPrompt) { + if (RecoDecay::getCharmHadronOrigin(mcParticles, mcParticles.rawIteratorAt(firstTrackMotherId)) == RecoDecay::OriginType::NonPrompt) { SETBIT(signalFlag, aod::tagandprobe::SignalFlags::NonPrompt); } else { SETBIT(signalFlag, aod::tagandprobe::SignalFlags::Prompt); @@ -398,7 +493,16 @@ struct TagTwoProngDisplacedVertices { return signalFlag; } - return BIT(aod::tagandprobe::SignalFlags::Bkg); + // if not signal, it must be background + SETBIT(signalFlag, aod::tagandprobe::SignalFlags::Bkg); + + auto originFirstTrack = RecoDecay::getCharmHadronOrigin(mcParticles, firstMcTrack, true); + auto originSecondTrack = RecoDecay::getCharmHadronOrigin(mcParticles, secondMcTrack, true); + if (originFirstTrack == RecoDecay::OriginType::None && originSecondTrack == RecoDecay::OriginType::None) { + SETBIT(signalFlag, aod::tagandprobe::SignalFlags::BkgFromNoHf); + } + + return signalFlag; } } @@ -420,61 +524,6 @@ struct TagTwoProngDisplacedVertices { return true; } - /// Calculate all the topology variables and store them in the Topology table - /// \param doMc 1 for the Mc and 0 for the data - /// \param primVtx primary vertex - /// \param secVtx secondary vertex - /// \param trackDcaXy array with the Tags' TrackDCAXY - /// \param channel decay channel - /// \param firstTrack candidate - /// \param SecondTrack candidate - /// \param particlesMc McParticle table - template - void getTagInfo(const PV& primVtx, - const SV& secVtx, - const CovMatSV& covMatrixSecVtx, - const PVec& pVec, - std::array& trackDcaXy, - const uint8_t channel, - const TTrack& firstTrack, - const TTrack& secondTrack, - float& invMass2, - std::vector& pdgDecayMothers, - std::vector& pdgResonances, - const PParticles& particlesMc) - { - auto covMatrixPV = primVtx.getCov(); - float phi, theta; - std::array pvCoord = {primVtx.getX(), primVtx.getY(), primVtx.getZ()}; - getPointDirection(pvCoord, secVtx, phi, theta); - - auto decLen = RecoDecay::distance(pvCoord, secVtx); - auto errorDecLen = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixSecVtx, phi, theta)); - auto errorDecLenXy = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.f) + getRotatedCovMatrixXX(covMatrixSecVtx, phi, 0.f)); - auto decLenXy = RecoDecay::distanceXY(pvCoord, secVtx); - auto cpa = RecoDecay::cpa(pvCoord, secVtx, pVec); - auto cpaXy = RecoDecay::cpaXY(pvCoord, secVtx, pVec); - auto normDecLen = decLen / errorDecLen; - auto normDecLenXy = decLenXy / errorDecLenXy; - auto tagsPt = RecoDecay::pt(pVec); - auto invMass = std::sqrt(invMass2); - - uint8_t isSignal = 0; // default value for data (no bkg, no signal) - - bool fillTable{true}; - if constexpr (doMc) { - isSignal = getTagOrigin(firstTrack, secondTrack, particlesMc, channel, pdgDecayMothers, pdgResonances); - if (fillTagTable == 1 && !(TESTBIT(isSignal, aod::tagandprobe::SignalFlags::Prompt) || TESTBIT(isSignal, aod::tagandprobe::SignalFlags::NonPrompt))) { // only signal - fillTable = false; - } else if (fillTagTable == 2 && !TESTBIT(isSignal, aod::tagandprobe::SignalFlags::Bkg)) { // only background - fillTable = false; - } - } - if (fillTable) { - tagVarsTable(tagsPt, invMass, decLen, decLenXy, normDecLen, normDecLenXy, trackDcaXy[0], trackDcaXy[1], trackDcaXy[0] * trackDcaXy[1], cpa, cpaXy, isSignal, channel); - } - } - template bool isSelectedPidTof(const TTrack& track, const uint8_t channel) @@ -525,13 +574,16 @@ struct TagTwoProngDisplacedVertices { const PVec& pVec, std::array& trackDcaXy, const uint8_t channel, - const int& ptBin) + const int& ptBin, + std::vector& topoVars) { + topoVars.clear(); std::array pvCoord = {primVtx.getX(), primVtx.getY(), primVtx.getZ()}; auto decLen = RecoDecay::distance(pvCoord, secVtx); if (decLen < topologicalCuts[channel].get(ptBin, 2u)) { return false; } + topoVars.push_back(decLen); auto covMatrixPV = primVtx.getCov(); @@ -539,6 +591,7 @@ struct TagTwoProngDisplacedVertices { if (decLenXy < topologicalCuts[channel].get(ptBin, 3u)) { return false; } + topoVars.push_back(decLenXy); float phi, theta; getPointDirection(pvCoord, secVtx, phi, theta); @@ -546,26 +599,32 @@ struct TagTwoProngDisplacedVertices { if (decLen / errorDecLen < topologicalCuts[channel].get(ptBin, 4u)) { return false; } + topoVars.push_back(decLen / errorDecLen); auto errorDecLenXy = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.f) + getRotatedCovMatrixXX(covMatrixSecVtx, phi, 0.f)); if (decLenXy / errorDecLenXy < topologicalCuts[channel].get(ptBin, 5u)) { return false; } + topoVars.push_back(decLenXy / errorDecLenXy); - // only for D0 meson - if (channel == aod::tagandprobe::TagChannels::DstarPlusToDzeroPi || channel == aod::tagandprobe::TagChannels::DstarMinusToDzeroBarPi || channel == aod::tagandprobe::TagChannels::DstarToDzeroToKK) { - if (trackDcaXy[0] * trackDcaXy[1] > topologicalCuts[channel].get(ptBin, 6u)) { - return false; - } - auto cpa = RecoDecay::cpa(pvCoord, secVtx, pVec); - if (cpa < topologicalCuts[channel].get(ptBin, 7u)) { - return false; - } - auto cpaXy = RecoDecay::cpaXY(pvCoord, secVtx, pVec); - if (cpaXy < topologicalCuts[channel].get(ptBin, 8u)) { - return false; - } + if (trackDcaXy[0] * trackDcaXy[1] > topologicalCuts[channel].get(ptBin, 6u)) { + return false; } + topoVars.push_back(trackDcaXy[0]); + topoVars.push_back(trackDcaXy[1]); + topoVars.push_back(trackDcaXy[0] * trackDcaXy[1]); + + auto cpa = RecoDecay::cpa(pvCoord, secVtx, pVec); + if (cpa < topologicalCuts[channel].get(ptBin, 7u)) { + return false; + } + topoVars.push_back(cpa); + + auto cpaXy = RecoDecay::cpaXY(pvCoord, secVtx, pVec); + if (cpaXy < topologicalCuts[channel].get(ptBin, 8u)) { + return false; + } + topoVars.push_back(cpaXy); return true; } @@ -577,7 +636,7 @@ struct TagTwoProngDisplacedVertices { float& /*bz*/, std::vector& pdgDecayMothers, std::vector& pdgResonances, - PParticles const& particlesMc) + PParticles const& mcParticles) { for (auto trackFirst = tracks.begin(); trackFirst != tracks.end(); ++trackFirst) { @@ -596,7 +655,8 @@ struct TagTwoProngDisplacedVertices { std::array pVecTrackSecond{trackSecond.px(), trackSecond.py(), trackSecond.pz()}; auto pVec = RecoDecay::pVec(pVecTrackFirst, pVecTrackSecond); - auto ptBin = findBin(&ptBinsForTopologicalCuts[channel], RecoDecay::pt(pVec)); + auto ptTag = RecoDecay::pt(pVec); + auto ptBin = o2::analysis::findBin(&ptBinsForTopologicalCuts[channel], ptTag); if (ptBin == -1) { continue; } @@ -623,14 +683,69 @@ struct TagTwoProngDisplacedVertices { const auto& secVtx = vertexer.getPCACandidate(); const auto& covMatrixPCA = vertexer.calcPCACovMatrixFlat(); std::array trackDcaXy{trackFirst.dcaXY(), trackSecond.dcaXY()}; - if (fillTagTable) { - getTagInfo(primVtx, secVtx, covMatrixPCA, pVec, trackDcaXy, channel, trackFirst, trackSecond, invMass2, pdgDecayMothers, pdgResonances, particlesMc); - } else { - if (!isSelectedTopology(primVtx, secVtx, covMatrixPCA, pVec, trackDcaXy, channel, ptBin)) { + std::vector topoVars{}; + if (!isSelectedTopology(primVtx, secVtx, covMatrixPCA, pVec, trackDcaXy, channel, ptBin, topoVars)) { + continue; + } + + uint8_t isSignal{0u}; + int motherIdx{-1}; + if constexpr (doMc) { + isSignal = getTagOrigin(trackFirst, trackSecond, mcParticles, channel, pdgDecayMothers, pdgResonances, motherIdx); + } + + std::vector mlScoresTag{}; + if (applyMl[channel]) { + bool isMlSelected = mlResponse[channel].isSelectedMl(topoVars, ptTag, mlScoresTag); + // we fill control histograms + if constexpr (doMc) { + if (TESTBIT(isSignal, aod::tagandprobe::SignalFlags::Bkg)) { + for (int iScore{0}; iScore < mlConfig.numMlClasses; ++iScore) { + hBkgMlScore.at(iScore)->Fill(ptTag, mlScoresTag.at(iScore)); + } + } else if (TESTBIT(isSignal, aod::tagandprobe::SignalFlags::Prompt)) { + for (int iScore{0}; iScore < mlConfig.numMlClasses; ++iScore) { + hPromptMlScore.at(iScore)->Fill(ptTag, mlScoresTag.at(iScore)); + } + } else if (TESTBIT(isSignal, aod::tagandprobe::SignalFlags::NonPrompt)) { + for (int iScore{0}; iScore < mlConfig.numMlClasses; ++iScore) { + hNonPromptMlScore.at(iScore)->Fill(ptTag, mlScoresTag.at(iScore)); + } + } + } else { + for (int iScore{0}; iScore < mlConfig.numMlClasses; ++iScore) { + hDataMlScore.at(iScore)->Fill(ptTag, mlScoresTag.at(iScore)); + } + } + if (!isMlSelected) { // for the time being all the topological variables used for all channels (decLen, decLenXy, normDecLen, normDecLenXy, cosp, cospXy, dcaXyTrack0, dcaXyTrack1, dcaProd) continue; } - registry.fill(HIST("hMassPiPiVsPt"), RecoDecay::pt(pVec), std::sqrt(invMass2)); // only channel with same sign tracks for the moment - tagPiPiTable(trackFirst.collisionId(), trackFirst.globalIndex(), trackSecond.globalIndex()); + } + + float invMass{std::sqrt(invMass2)}; + registry.fill(HIST("hMassPiPiVsPt"), ptTag, invMass); // only channel with same sign tracks for the moment + + if (fillTopoVarsTable) { + bool fillTable{true}; + if (fillTopoVarsTable == 1 && !(TESTBIT(isSignal, aod::tagandprobe::SignalFlags::Prompt) || TESTBIT(isSignal, aod::tagandprobe::SignalFlags::NonPrompt))) { // only signal + fillTable = false; + } else if (fillTopoVarsTable == 2 && !TESTBIT(isSignal, aod::tagandprobe::SignalFlags::Bkg)) { // only background + fillTable = false; + } else if (fillTopoVarsTable == 3 && !TESTBIT(isSignal, aod::tagandprobe::SignalFlags::BkgFromNoHf)) { // only background excluding tracks from other HF decays + fillTable = false; + } + float pseudoRndm = trackFirst.pt() * 1000. - (int64_t)(trackFirst.pt() * 1000); + if (ptTag < ptTagMaxForDownsampling && pseudoRndm >= downsamplingForTopoVarTable) { + fillTable = false; + } + if (fillTable) { + tagVarsTable(ptTag, invMass, topoVars[0], topoVars[1], topoVars[2], topoVars[3], trackDcaXy[0], trackDcaXy[1], topoVars[6], topoVars[7], topoVars[8], isSignal, channel); + } + } else { + tagPiPiTable(trackFirst.collisionId(), trackFirst.globalIndex(), trackSecond.globalIndex(), mlScoresTag); + if constexpr (doMc) { + tagPiPiMcTable(isSignal, motherIdx); + } } } } @@ -644,7 +759,7 @@ struct TagTwoProngDisplacedVertices { float& /*bz*/, std::vector& pdgDecayMothers, std::vector& pdgResonances, - PParticles const& particlesMc) + PParticles const& mcParticles) { for (const auto& trackPos : tracksPos) { @@ -663,7 +778,8 @@ struct TagTwoProngDisplacedVertices { std::array pVecTrackNeg{trackNeg.px(), trackNeg.py(), trackNeg.pz()}; auto pVec = RecoDecay::pVec(pVecTrackPos, pVecTrackNeg); - auto ptBin = findBin(&ptBinsForTopologicalCuts[channel], RecoDecay::pt(pVec)); + auto ptTag = RecoDecay::pt(pVec); + auto ptBin = o2::analysis::findBin(&ptBinsForTopologicalCuts[channel], ptTag); if (ptBin == -1) { continue; } @@ -690,57 +806,122 @@ struct TagTwoProngDisplacedVertices { const auto& secVtx = vertexer.getPCACandidate(); const auto& covMatrixPCA = vertexer.calcPCACovMatrixFlat(); std::array trackDcaXy{trackPos.dcaXY(), trackNeg.dcaXY()}; - if (fillTagTable) { - getTagInfo(primVtx, secVtx, covMatrixPCA, pVec, trackDcaXy, channel, trackPos, trackNeg, invMass2, pdgDecayMothers, pdgResonances, particlesMc); - } else { - if (!isSelectedTopology(primVtx, secVtx, covMatrixPCA, pVec, trackDcaXy, channel, ptBin)) { + std::vector topoVars{}; + if (!isSelectedTopology(primVtx, secVtx, covMatrixPCA, pVec, trackDcaXy, channel, ptBin, topoVars)) { + continue; + } + + uint8_t isSignal{0u}; + int motherIdx{-1}; + if constexpr (doMc) { + isSignal = getTagOrigin(trackPos, trackNeg, mcParticles, channel, pdgDecayMothers, pdgResonances, motherIdx); + } + + std::vector mlScoresTag{}; + if (applyMl[channel]) { + bool isMlSelected = mlResponse[channel].isSelectedMl(topoVars, ptTag, mlScoresTag); + // we fill control histograms + if constexpr (doMc) { + if (TESTBIT(isSignal, aod::tagandprobe::SignalFlags::Bkg)) { + for (int iScore{0}; iScore < mlConfig.numMlClasses; ++iScore) { + hBkgMlScore.at(iScore)->Fill(ptTag, mlScoresTag.at(iScore)); + } + } else if (TESTBIT(isSignal, aod::tagandprobe::SignalFlags::Prompt)) { + for (int iScore{0}; iScore < mlConfig.numMlClasses; ++iScore) { + hPromptMlScore.at(iScore)->Fill(ptTag, mlScoresTag.at(iScore)); + } + } else if (TESTBIT(isSignal, aod::tagandprobe::SignalFlags::NonPrompt)) { + for (int iScore{0}; iScore < mlConfig.numMlClasses; ++iScore) { + hNonPromptMlScore.at(iScore)->Fill(ptTag, mlScoresTag.at(iScore)); + } + } + } else { + for (int iScore{0}; iScore < mlConfig.numMlClasses; ++iScore) { + hDataMlScore.at(iScore)->Fill(ptTag, mlScoresTag.at(iScore)); + } + } + if (!isMlSelected) { // for the time being all the topological variables used for all channels (decLen, decLenXy, normDecLen, normDecLenXy, cosp, cospXy, dcaXyTrack0, dcaXyTrack1, dcaProd) continue; } - if (channel == aod::tagandprobe::TagChannels::DsOrDplusToKKPi) { - registry.fill(HIST("hMassKaKaVsPt"), RecoDecay::pt(pVec), std::sqrt(invMass2)); - tagKaKaTable(trackPos.collisionId(), trackPos.globalIndex(), trackNeg.globalIndex()); - } else if (channel == aod::tagandprobe::TagChannels::DstarPlusToDzeroPi) { - if (!studyDzeroReflections) { - registry.fill(HIST("hMassKaPiVsPt"), RecoDecay::pt(pVec), std::sqrt(invMass2)); - } else { - float invMassrefl{0.f}; - int isDzero = 1; - if (std::abs(trackPos.tpcNSigmaKa()) < trackNumSigmaTpc && (std::abs(trackNeg.tpcNSigmaPi()) < trackNumSigmaTpc)) { - isDzero = 3; - if (applyTofPid) { - if (!isSelectedPidTof(trackNeg, aod::tagandprobe::TagChannels::DstarMinusToDzeroBarPi) || !isSelectedPidTof(trackPos, aod::tagandprobe::TagChannels::DstarMinusToDzeroBarPi)) - isDzero = 1; - } + } + + float invMass{std::sqrt(invMass2)}; + if (channel == aod::tagandprobe::TagChannels::DsOrDplusToKKPi) { + registry.fill(HIST("hMassKaKaVsPt"), ptTag, invMass); + } else if (channel == aod::tagandprobe::TagChannels::DstarPlusToDzeroPi) { + if (!studyDzeroReflections) { + registry.fill(HIST("hMassKaPiVsPt"), ptTag, invMass); + } else { + float invMassRefl{0.f}; + int isDzero = 1; + if (std::abs(trackPos.tpcNSigmaKa()) < trackNumSigmaTpc && (std::abs(trackNeg.tpcNSigmaPi()) < trackNumSigmaTpc)) { + isDzero = 3; + if (applyTofPid) { + if (!isSelectedPidTof(trackNeg, aod::tagandprobe::TagChannels::DstarMinusToDzeroBarPi) || !isSelectedPidTof(trackPos, aod::tagandprobe::TagChannels::DstarMinusToDzeroBarPi)) + isDzero = 1; } - if (isDzero == 3) { - auto arrMomentum = std::array{pVecTrackNeg, pVecTrackPos}; - invMassrefl = std::sqrt(RecoDecay::m2(arrMomentum, masses[channel])); + } + if (isDzero == 3) { + auto arrMomentum = std::array{pVecTrackNeg, pVecTrackPos}; + invMassRefl = std::sqrt(RecoDecay::m2(arrMomentum, masses[channel])); + } + registry.fill(HIST("hMassKaPiVsPt"), ptTag, invMass, invMassRefl, isDzero); + } + } else if (channel == aod::tagandprobe::TagChannels::DstarMinusToDzeroBarPi) { + if (!studyDzeroReflections) { + registry.fill(HIST("hMassKaPiVsPt"), ptTag, invMass); + } else { + float invMassRefl{0.f}; + int isDzero = 2; + if (std::abs(trackNeg.tpcNSigmaKa()) < trackNumSigmaTpc && (std::abs(trackPos.tpcNSigmaPi()) < trackNumSigmaTpc)) { + isDzero = 3; + if (applyTofPid) { + if (!isSelectedPidTof(trackNeg, aod::tagandprobe::TagChannels::DstarPlusToDzeroPi) || !isSelectedPidTof(trackPos, aod::tagandprobe::TagChannels::DstarPlusToDzeroPi)) + isDzero = 2; } - registry.fill(HIST("hMassKaPiVsPt"), RecoDecay::pt(pVec), std::sqrt(invMass2), invMassrefl, isDzero); } - tagPiKaTable(trackPos.collisionId(), trackPos.globalIndex(), trackNeg.globalIndex()); + if (isDzero == 3) { + auto arrMomentum = std::array{pVecTrackNeg, pVecTrackPos}; + invMassRefl = std::sqrt(RecoDecay::m2(arrMomentum, masses[channel])); + } + registry.fill(HIST("hMassKaPiVsPt"), ptTag, invMass, invMassRefl, isDzero); + } + } else if (channel == aod::tagandprobe::TagChannels::DstarToDzeroToKK) { + registry.fill(HIST("hMassDzeroKaKaVsPt"), ptTag, invMass); + } + + if (fillTopoVarsTable) { + bool fillTable{true}; + if (fillTopoVarsTable == 1 && !(TESTBIT(isSignal, aod::tagandprobe::SignalFlags::Prompt) || TESTBIT(isSignal, aod::tagandprobe::SignalFlags::NonPrompt))) { // only signal + fillTable = false; + } else if (fillTopoVarsTable == 2 && !TESTBIT(isSignal, aod::tagandprobe::SignalFlags::Bkg)) { // only background + fillTable = false; + } else if (fillTopoVarsTable == 3 && !TESTBIT(isSignal, aod::tagandprobe::SignalFlags::BkgFromNoHf)) { // only background excluding tracks from other HF decays + fillTable = false; + } + float pseudoRndm = trackPos.pt() * 1000. - (int64_t)(trackPos.pt() * 1000); + if (ptTag < ptTagMaxForDownsampling && pseudoRndm >= downsamplingForTopoVarTable) { + fillTable = false; + } + if (fillTable) { + tagVarsTable(ptTag, invMass, topoVars[0], topoVars[1], topoVars[2], topoVars[3], trackDcaXy[0], trackDcaXy[1], topoVars[6], topoVars[7], topoVars[8], isSignal, channel); + } + } else { + if (channel == aod::tagandprobe::TagChannels::DsOrDplusToKKPi) { + tagKaKaTable(trackPos.collisionId(), trackPos.globalIndex(), trackNeg.globalIndex(), mlScoresTag); + if constexpr (doMc) { + tagKaKaMcTable(isSignal, motherIdx); + } + } else if (channel == aod::tagandprobe::TagChannels::DstarPlusToDzeroPi) { + tagPiKaTable(trackPos.collisionId(), trackPos.globalIndex(), trackNeg.globalIndex(), mlScoresTag); + if constexpr (doMc) { + tagPiKaMcTable(isSignal, motherIdx); + } } else if (channel == aod::tagandprobe::TagChannels::DstarMinusToDzeroBarPi) { - if (!studyDzeroReflections) { - registry.fill(HIST("hMassKaPiVsPt"), RecoDecay::pt(pVec), std::sqrt(invMass2)); - } else { - float invMassrefl{0.f}; - int isDzero = 2; - if (std::abs(trackNeg.tpcNSigmaKa()) < trackNumSigmaTpc && (std::abs(trackPos.tpcNSigmaPi()) < trackNumSigmaTpc)) { - isDzero = 3; - if (applyTofPid) { - if (!isSelectedPidTof(trackNeg, aod::tagandprobe::TagChannels::DstarPlusToDzeroPi) || !isSelectedPidTof(trackPos, aod::tagandprobe::TagChannels::DstarPlusToDzeroPi)) - isDzero = 2; - } - } - if (isDzero == 3) { - auto arrMomentum = std::array{pVecTrackNeg, pVecTrackPos}; - invMassrefl = std::sqrt(RecoDecay::m2(arrMomentum, masses[channel])); - } - registry.fill(HIST("hMassKaPiVsPt"), RecoDecay::pt(pVec), std::sqrt(invMass2), invMassrefl, isDzero); + tagKaPiTable(trackPos.collisionId(), trackPos.globalIndex(), trackNeg.globalIndex(), mlScoresTag); + if constexpr (doMc) { + tagKaPiMcTable(isSignal, motherIdx); } - tagKaPiTable(trackPos.collisionId(), trackPos.globalIndex(), trackNeg.globalIndex()); - } else if (channel == aod::tagandprobe::TagChannels::DstarToDzeroToKK) { - registry.fill(HIST("hMassDzeroKaKaVsPt"), RecoDecay::pt(pVec), std::sqrt(invMass2)); } } } @@ -750,7 +931,7 @@ struct TagTwoProngDisplacedVertices { void processPiPiFromDplusMc(CollisionsFiltered::iterator const& collision, TracksWithSelAndDcaMcFiltered const&, aod::BCsWithTimestamps const&, - aod::McParticles const& particlesMc) + aod::McParticles const& mcParticles) { auto bc = collision.bc_as(); float bz{0}; @@ -770,10 +951,10 @@ struct TagTwoProngDisplacedVertices { pdgMothersDecayChannel(pdgDecayMothers, pdgResonances, aod::tagandprobe::TagChannels::DplusToKPiPi); auto groupPositive = positivePionsMc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - computeCombinatorialSameCharge(collision, groupPositive, aod::tagandprobe::TagChannels::DplusToKPiPi, bz, pdgDecayMothers, pdgResonances, particlesMc); + computeCombinatorialSameCharge(collision, groupPositive, aod::tagandprobe::TagChannels::DplusToKPiPi, bz, pdgDecayMothers, pdgResonances, mcParticles); auto groupNegative = negativePionsMc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - computeCombinatorialSameCharge(collision, groupNegative, aod::tagandprobe::TagChannels::DplusToKPiPi, bz, pdgDecayMothers, pdgResonances, particlesMc); + computeCombinatorialSameCharge(collision, groupNegative, aod::tagandprobe::TagChannels::DplusToKPiPi, bz, pdgDecayMothers, pdgResonances, mcParticles); } PROCESS_SWITCH(TagTwoProngDisplacedVertices, processPiPiFromDplusMc, "Process pipi combinatorial to tag pion pairs from D+ decays Mc", false); @@ -809,7 +990,7 @@ struct TagTwoProngDisplacedVertices { void processKaKaFromDsOrDplusMc(CollisionsFiltered::iterator const& collision, TracksWithSelAndDcaMcFiltered const&, aod::BCsWithTimestamps const&, - aod::McParticles const& particlesMc) + aod::McParticles const& mcParticles) { auto bc = collision.bc_as(); float bz{0}; @@ -830,7 +1011,7 @@ struct TagTwoProngDisplacedVertices { auto groupPositive = positiveKaonsMc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto groupNegative = negativeKaonsMc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - computeCombinatorialOppositeCharge(collision, groupPositive, groupNegative, aod::tagandprobe::TagChannels::DsOrDplusToKKPi, bz, pdgDecayMothers, pdgResonances, particlesMc); + computeCombinatorialOppositeCharge(collision, groupPositive, groupNegative, aod::tagandprobe::TagChannels::DsOrDplusToKKPi, bz, pdgDecayMothers, pdgResonances, mcParticles); } PROCESS_SWITCH(TagTwoProngDisplacedVertices, processKaKaFromDsOrDplusMc, "Process KK combinatorial to tag kaon pairs from Ds+/D+ decays Mc", false); @@ -921,7 +1102,7 @@ struct TagTwoProngDisplacedVertices { void processKaPiFromDstarMc(CollisionsFiltered::iterator const& collision, TracksWithSelAndDcaMcFiltered const&, aod::BCsWithTimestamps const&, - aod::McParticles const& particlesMc) + aod::McParticles const& mcParticles) { auto bc = collision.bc_as(); float bz{0}; @@ -944,8 +1125,8 @@ struct TagTwoProngDisplacedVertices { auto groupPionNegative = negativePionsMc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto groupKaonPositive = positiveKaonsMc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto groupKaonNegative = negativeKaonsMc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - computeCombinatorialOppositeCharge(collision, groupPionPositive, groupKaonNegative, aod::tagandprobe::TagChannels::DstarPlusToDzeroPi, bz, pdgDecayMothers, pdgResonances, particlesMc); - computeCombinatorialOppositeCharge(collision, groupKaonPositive, groupPionNegative, aod::tagandprobe::TagChannels::DstarMinusToDzeroBarPi, bz, pdgDecayMothers, pdgResonances, particlesMc); + computeCombinatorialOppositeCharge(collision, groupPionPositive, groupKaonNegative, aod::tagandprobe::TagChannels::DstarPlusToDzeroPi, bz, pdgDecayMothers, pdgResonances, mcParticles); + computeCombinatorialOppositeCharge(collision, groupKaonPositive, groupPionNegative, aod::tagandprobe::TagChannels::DstarMinusToDzeroBarPi, bz, pdgDecayMothers, pdgResonances, mcParticles); } PROCESS_SWITCH(TagTwoProngDisplacedVertices, processKaPiFromDstarMc, "Process Kpi combinatorial to tag D0 from D*+ decays", false); }; @@ -953,12 +1134,51 @@ struct TagTwoProngDisplacedVertices { /// Probe third track reconstruction efficiency with different selections struct ProbeThirdTrack { + // ML models for triggers + struct : ConfigurableGroup { + std::string prefix = "ML"; + Configurable applyMlPiPiFromDplus{"applyMlPiPiFromDplus", false, "Flag to enable ML application for pipi pairs from D+ decays"}; + Configurable applyMlKaKaFromDsOrDplus{"applyMlKaKaFromDsOrDplus", false, "Flag to enable ML application for KK pairs from Ds or D+ decays"}; + Configurable applyMlDzeroFromDstar{"applyMlDzeroFromDstar", false, "Flag to enable ML application for Kpi pairs from D0 <- D*+ decays"}; + // pt bins + Configurable> binsPtPiPiFromDplus{"binsPtPiPiFromDplus", std::vector{aod::tagandprobe::vecBinsPt}, "pT bin limits for pipi pairs from D+ decays"}; + Configurable> binsPtKaKaFromDsOrDplus{"binsPtKaKaFromDsOrDplus", std::vector{aod::tagandprobe::vecBinsPt}, "pT bin limits for KK pairs from Ds or D+ decays"}; + Configurable> binsPtDzeroFromDstar{"binsPtDzeroFromDstar", std::vector{aod::tagandprobe::vecBinsPt}, "pT bin limits for Kpi pairs from D0 <- D*+ decays"}; + // ML cuts + Configurable> mlCutsPiPiFromDplus{"mlCutsPiPiFromDplus", {aod::tagandprobe::mlCuts[0], aod::tagandprobe::nBinsPt, 3, aod::tagandprobe::labelsEmpty, aod::tagandprobe::labelsMlScores}, "ML Selections for pipi pairs from D+ decays"}; + Configurable> mlCutsKaKaFromDsOrDplus{"mlCutsKaKaFromDsOrDplus", {aod::tagandprobe::mlCuts[0], aod::tagandprobe::nBinsPt, 3, aod::tagandprobe::labelsEmpty, aod::tagandprobe::labelsMlScores}, "ML Selections for KK pairs from Ds or D+ decays"}; + Configurable> mlCutsDzeroFromDstar{"mlCutsDzeroFromDstar", {aod::tagandprobe::mlCuts[0], aod::tagandprobe::nBinsPt, 3, aod::tagandprobe::labelsEmpty, aod::tagandprobe::labelsMlScores}, "ML Selections for Kpi pairs from D0 <- D*+ decays"}; + } mlConfig; + Configurable ptCandMin{"ptCandMin", 0.f, "Minimum candidate pt for THnSparse filling"}; + + ConfigurableAxis axisPtProbe{"axisPtProbe", {VARIABLE_WIDTH, 0.05f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.2f, 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.f, 12.f, 15.f, 20.f, 25.f, 30.f}, "Axis for pt Probe"}; + ConfigurableAxis axisPtTag{"axisPtTag", {VARIABLE_WIDTH, 0.05f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.2f, 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.f, 12.f, 15.f, 20.f, 25.f, 30.f}, "Axis for pt Tag"}; + ConfigurableAxis axisPtD{"axisPtD", {VARIABLE_WIDTH, 0.f, 0.5f, 1.f, 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f, 5.5f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 8.5f, 9.0f, 9.5f, 10.f, 11.f, 12.f, 14.f, 16.f, 20.f, 24.f, 36.f, 50.f}, "Axis for pt D"}; + ConfigurableAxis axisYD{"axisYD", {20, -1.f, 1.f}, "Axis for YD"}; + ConfigurableAxis axisEtaProbe{"axisEtaProbe", {20, -1.f, 1.f}, "Axis for Eta Probe"}; + ConfigurableAxis axisNumCrossRowTpc{"axisNumCrossRowTpc", {51, 49.5f, 100.5f}, "Axis for Number of CrossRowTpc"}; + ConfigurableAxis axisTpcChi2PerClus{"axisTpcChi2PerClus", {8, 2.f, 10.f}, "Axis for TpcChi2 Per Cluster"}; + ConfigurableAxis axisNumCluIts{"axisNumCluIts", {5, 2.5f, 7.5f}, "Axis for Number of Cluster ITS"}; + ConfigurableAxis axisPtMinTagdaught{"axisPtMinTagdaught", {10, 0.f, 1.f}, "Axis for Pt Min of Tag daughter"}; + ConfigurableAxis axisAbsEtaMaxTagdaught{"axisAbsEtaMaxTagdaught", {10, 0.f, 1.f}, "Axis for AbsEtaMax for Tag daughter"}; + + Filter tagMcFilter = aod::tagandprobe::isSignal > static_cast(0); + using TracksWithDca = soa::Join; + using TracksWithDcaMc = soa::Join; + using FilteredPiPiFromDpMcTags = soa::Filtered>; + using FilteredKaKaFromDspMcTags = soa::Filtered>; + using FilteredPiKaFromDzMcTags = soa::Filtered>; + using FilteredKaPiFromDzMcTags = soa::Filtered>; Preslice tagsPiPiPerCollision = aod::tagandprobe::collisionId; Preslice tagsKaKaPerCollision = aod::tagandprobe::collisionId; Preslice tagsPiKaPerCollision = aod::tagandprobe::collisionId; Preslice tagsKaPiPerCollision = aod::tagandprobe::collisionId; + Preslice tagsPiPiMcPerCollision = aod::tagandprobe::collisionId; + Preslice tagsKaKaMcPerCollision = aod::tagandprobe::collisionId; + Preslice tagsPiKaMcPerCollision = aod::tagandprobe::collisionId; + Preslice tagsKaPiMcPerCollision = aod::tagandprobe::collisionId; Preslice trackIndicesPerCollision = aod::track_association::collisionId; std::array, aod::tagandprobe::TagChannels::NTagChannels> masses = {std::array{constants::physics::MassPionCharged, constants::physics::MassPionCharged, constants::physics::MassKaonCharged}, @@ -968,12 +1188,20 @@ struct ProbeThirdTrack { std::array{constants::physics::MassKaonCharged, constants::physics::MassKaonCharged, constants::physics::MassPionCharged}}; std::array trackSelector{}; // define the track selectors + std::array applyMl{}; + std::array minInvMass{}; + std::array maxInvMass{}; std::array, aod::tagandprobe::TrackTypes::NTrackTypes>, aod::tagandprobe::TagChannels::NTagChannels> histos{}; + std::array, aod::tagandprobe::TagChannels::NTagChannels> histosGen{}; HistogramRegistry registry{"registry"}; void init(InitContext&) { + if ((doprocessCombinatorialDplusToKaPiPi && doprocessCombinatorialDplusToKaPiPiMc) || (doprocessCombinatorialDsToPhiPi && doprocessCombinatorialDsToPhiPiMc) || (doprocessCombinatorialDstarToDzeroPi && doprocessCombinatorialDstarToDzeroPiMc)) { + LOGP(fatal, "The process functions for the same channel with and without MC truth cannot be enabled at the same time! Please check your configuration"); + } + // ITS-TPC tracks (global tracks) trackSelector[aod::tagandprobe::TrackTypes::GlobalWoDca].SetTrackType(o2::aod::track::TrackTypeEnum::Track); trackSelector[aod::tagandprobe::TrackTypes::GlobalWoDca].SetPtRange(0.05f, 1e10f); @@ -1014,13 +1242,6 @@ struct ProbeThirdTrack { trackSelector[aod::tagandprobe::TrackTypes::GlobalWoDcaWoTpc].SetMaxChi2PerClusterITS(36.f); trackSelector[aod::tagandprobe::TrackTypes::GlobalWoDcaWoTpc].SetMaxDcaZ(2.f); - const AxisSpec axisPtProbe{{0.05f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.2f, 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.f, 12.f, 15.f, 20.f, 25.f, 30.f}}; - const AxisSpec axisPtTag{{0.05f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.2f, 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.f, 12.f, 15.f, 20.f, 25.f, 30.f}}; - const AxisSpec axisPtD{{0.f, 0.5f, 1.f, 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f, 5.5f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 8.5f, 9.0f, 9.5f, 10.f, 11.f, 12.f, 14.f, 16.f, 20.f, 24.f, 36.f, 50.f}}; - const AxisSpec axisEtaProbe{20, -1.f, 1.f}; - const AxisSpec axisNumCrossRowTpc{51, 49.5f, 100.5f}; - const AxisSpec axisTpcChi2PerClus{8, 2.f, 10.f}; - const AxisSpec axisNumCluIts{5, 2.5f, 7.5f}; std::array axisMass = {AxisSpec{225, 1.65f, 2.10f}, AxisSpec{225, 1.65f, 2.10f}, AxisSpec{350, 0.135f, 0.17f}, AxisSpec{350, 0.135f, 0.17f}, AxisSpec{350, 0.135f, 0.17f}}; std::array axisMassTag = {AxisSpec{125, 0.f, 2.5f}, AxisSpec{100, constants::physics::MassPhi - 0.05f, constants::physics::MassPhi + 0.05f}, AxisSpec{200, constants::physics::MassD0 - 0.2f, constants::physics::MassD0 + 0.2f}, AxisSpec{200, constants::physics::MassD0 - 0.2f, constants::physics::MassD0 + 0.2f}, AxisSpec{200, constants::physics::MassD0 - 0.2f, constants::physics::MassD0 + 0.2f}}; @@ -1032,8 +1253,15 @@ struct ProbeThirdTrack { histos[iChannel][iTrackType] = registry.add(Form("h%sVsPtProbeTag_%s", tagChannels[iChannel].data(), trackTypes[iTrackType].data()), "; #it{p}_{T}(D) (GeV/#it{c}); #it{p}_{T}(tag) (GeV/#it{c}); #it{p}_{T}(probe) (GeV/#it{c}); #it{p}_{T}^{TPC in}(probe) (GeV/#it{c}); #it{M}(D) (GeV/#it{c}^{2}); #it{M}(tag) (GeV/#it{c}^{2}); #it{#eta}(probe); #it{N}_{cross rows}^{TPC}(probe); #chi^{2}/#it{N}_{clusters}^{TPC}(probe); #it{N}_{clusters}^{ITS}(probe);", HistType::kTHnSparseF, {axisPtD, axisPtTag, axisPtProbe, axisPtProbe, axisMass[iChannel], axisMassTag[iChannel], axisEtaProbe, axisNumCrossRowTpc, axisTpcChi2PerClus, axisNumCluIts}); + auto invMassBins = axisMass[iChannel].binEdges; + minInvMass[iChannel] = invMassBins.front(); + maxInvMass[iChannel] = invMassBins.back(); } } + for (int iChannel{0}; iChannel < aod::tagandprobe::TagChannels::NTagChannels; ++iChannel) { + histosGen[iChannel] = registry.add(Form("hGen%s", tagChannels[iChannel].data()), ";#it{p}_{T}(D_{parent}) (GeV/#it{c}); #it{y}(D_{parent});#it{p}_{T}(tag) (GeV/#it{c}); #it{y}(tag);#it{p}_{T}(probe) (GeV/#it{c}); #it{#eta}(probe);#it{p}_{T}^{min}(tag daughters);#it{#eta}_{max}(tag daughters)", HistType::kTHnSparseF, {axisPtD, axisYD, axisPtTag, axisYD, axisPtProbe, axisEtaProbe, axisPtMinTagdaught, axisAbsEtaMaxTagdaught}); + } + applyMl = {mlConfig.applyMlPiPiFromDplus, mlConfig.applyMlKaKaFromDsOrDplus, mlConfig.applyMlDzeroFromDstar}; } template @@ -1055,22 +1283,52 @@ struct ProbeThirdTrack { } } - template - void loopOverThirdTrack(TTrackIndices const& groupedTrackThirdIndices, TTracks const& /*tracks*/, TTrack const& trackFirst, TTrack const& trackSecond, const uint8_t channel) + template + void loopOverThirdTrack(TTrackIndices const& groupedTrackThirdIndices, TTracks const& /*tracks*/, TTrack const& trackFirst, TTrack const& trackSecond, PParticles const mcParticles, const int motherIdxTag) { for (const auto& trackIndex : groupedTrackThirdIndices) { auto trackThird = trackIndex.template track_as(); - if (trackThird.globalIndex() == trackFirst.globalIndex() || trackThird.globalIndex() == trackSecond.globalIndex()) { - continue; - } - if (channel == aod::tagandprobe::TagChannels::DplusToKPiPi && trackThird.signed1Pt() * trackFirst.signed1Pt() > 0.) { // must be opposite sign - continue; + if constexpr (doMc) { + if (!trackThird.has_mcParticle()) { + continue; + } + int motherIdxProbe{-1}; + int pdgMotherFirst{0}, pdgMotherSecond{0}; + if constexpr (channel == aod::tagandprobe::TagChannels::DplusToKPiPi) { + pdgMotherFirst = constants::physics::Pdg::kDPlus; + } else if constexpr (channel == aod::tagandprobe::TagChannels::DsOrDplusToKKPi) { + pdgMotherFirst = constants::physics::Pdg::kDS; + pdgMotherSecond = constants::physics::Pdg::kDPlus; + } else if constexpr (channel == aod::tagandprobe::TagChannels::DstarPlusToDzeroPi || channel == aod::tagandprobe::TagChannels::DstarMinusToDzeroBarPi) { + pdgMotherFirst = constants::physics::Pdg::kDStar; + } + auto particleProbe = trackThird.template mcParticle_as(); + motherIdxProbe = RecoDecay::getMother(mcParticles, particleProbe, pdgMotherFirst, true); + if constexpr (channel == aod::tagandprobe::TagChannels::DsOrDplusToKKPi) { + if (motherIdxProbe < 0) { + motherIdxProbe = RecoDecay::getMother(mcParticles, particleProbe, pdgMotherSecond, true); + } + } + if (motherIdxProbe < 0 || motherIdxTag != motherIdxProbe) { + continue; + } } - if (channel == aod::tagandprobe::TagChannels::DstarPlusToDzeroPi && trackThird.signed1Pt() < 0.) { // must be positive + + if (trackThird.globalIndex() == trackFirst.globalIndex() || trackThird.globalIndex() == trackSecond.globalIndex()) { continue; } - if (channel == aod::tagandprobe::TagChannels::DstarMinusToDzeroBarPi && trackThird.signed1Pt() > 0.) { // must be negative - continue; + if constexpr (channel == aod::tagandprobe::TagChannels::DplusToKPiPi) { // must be opposite sign + if (trackThird.signed1Pt() * trackFirst.signed1Pt() > 0.) { + continue; + } + } else if constexpr (channel == aod::tagandprobe::TagChannels::DstarPlusToDzeroPi) { // must be positive + if (trackThird.signed1Pt() < 0.) { + continue; + } + } else if constexpr (channel == aod::tagandprobe::TagChannels::DstarMinusToDzeroBarPi) { // must be negative + if (trackThird.signed1Pt() > 0.) { + continue; + } } auto ptTrackThird = trackThird.pt(); auto ptTpcInnerTrackThird = trackThird.tpcInnerParam() / std::sqrt(1.f + trackThird.tgl() * trackThird.tgl()); @@ -1080,9 +1338,11 @@ struct ProbeThirdTrack { auto numItsCluTrackThird = trackThird.itsNCls(); float invMass{-1.f}, invMassTag{-1.f}, ptTag{-1.f}, ptD{-1.f}; computeInvariantMass(trackFirst, trackSecond, trackThird, channel, ptTag, invMassTag, ptD, invMass); - if ((channel == aod::tagandprobe::TagChannels::DstarPlusToDzeroPi || channel == aod::tagandprobe::TagChannels::DstarMinusToDzeroBarPi) && invMass > 0.17f) { + if (invMass < minInvMass[channel] || invMass > maxInvMass[channel]) { continue; - } else if ((channel == aod::tagandprobe::TagChannels::DplusToKPiPi || channel == aod::tagandprobe::TagChannels::DsOrDplusToKKPi) && (invMass < 1.65f || invMass > 2.10f)) { + } + if (ptD < ptCandMin) { + /// candidate pt lower than the minimum allowed value, let's skip it continue; } for (int iTrackType{0}; iTrackType < aod::tagandprobe::TrackTypes::NTrackTypes; ++iTrackType) { @@ -1093,6 +1353,32 @@ struct ProbeThirdTrack { } } + template + void runCombinatorialThirdTrack(TTags const& groupedTags, + TTrackIndices const& groupedTrackIndices, + TTracks const& tracks, + PParticles const& mcParticles) + { + for (const auto& tag : groupedTags) { + auto trackFirst = tag.template track0_as(); + auto trackSecond = tag.template track1_as(); + if (applyMl[channel] && tag.mlScores().size() == 3) { + std::array pVecTrackFirst{trackFirst.px(), trackFirst.py(), trackFirst.pz()}; + std::array pVecTrackSecond{trackSecond.px(), trackSecond.py(), trackSecond.pz()}; + auto ptTag = RecoDecay::pt(RecoDecay::pVec(pVecTrackFirst, pVecTrackSecond)); + auto ptBin = o2::analysis::findBin(&mlConfig.binsPtPiPiFromDplus.value, ptTag); + if (tag.mlScores()[0] > mlConfig.mlCutsPiPiFromDplus->get(ptBin, 0u) || tag.mlScores()[1] < mlConfig.mlCutsPiPiFromDplus->get(ptBin, 1u) || tag.mlScores()[2] < mlConfig.mlCutsPiPiFromDplus->get(ptBin, 2u)) { + continue; + } + } + int motherIdxTag{-1}; + if constexpr (doMc) { + motherIdxTag = tag.motherId(); + } + loopOverThirdTrack(groupedTrackIndices, tracks, trackFirst, trackSecond, mcParticles, motherIdxTag); + } + } + void processCombinatorialDplusToKaPiPi(aod::Collisions const& collisions, aod::PiPiFromDpTags const& tagsPiPi, aod::TrackAssoc const& trackIndices, @@ -1103,15 +1389,27 @@ struct ProbeThirdTrack { auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); // D+ -> pi+pi+K- and c.c. auto groupedTagsPiPi = tagsPiPi.sliceBy(tagsPiPiPerCollision, thisCollId); - for (const auto& tagPiPi : groupedTagsPiPi) { - auto trackFirst = tagPiPi.track0_as(); - auto trackSecond = tagPiPi.track1_as(); - loopOverThirdTrack(groupedTrackIndices, tracks, trackFirst, trackSecond, aod::tagandprobe::TagChannels::DplusToKPiPi); - } + runCombinatorialThirdTrack(groupedTagsPiPi, groupedTrackIndices, tracks, tracks); } } PROCESS_SWITCH(ProbeThirdTrack, processCombinatorialDplusToKaPiPi, "Process combinatorial of tagged 2-pion vertices with additional track", true); + void processCombinatorialDplusToKaPiPiMc(aod::Collisions const& collisions, + FilteredPiPiFromDpMcTags const& tagsPiPi, + aod::TrackAssoc const& trackIndices, + TracksWithDcaMc const& tracks, + aod::McParticles const& mcParticles) + { + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + // D+ -> pi+pi+K- and c.c. + auto groupedTagsPiPi = tagsPiPi.sliceBy(tagsPiPiMcPerCollision, thisCollId); + runCombinatorialThirdTrack(groupedTagsPiPi, groupedTrackIndices, tracks, mcParticles); + } + } + PROCESS_SWITCH(ProbeThirdTrack, processCombinatorialDplusToKaPiPiMc, "Process combinatorial of tagged 2-pion vertices with additional track using MC truth", false); + void processCombinatorialDsToPhiPi(aod::Collisions const& collisions, aod::KaKaFromDspTags const& tagsKaKa, aod::TrackAssoc const& trackIndices, @@ -1122,15 +1420,27 @@ struct ProbeThirdTrack { auto thisCollId = collision.globalIndex(); auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); auto groupedTagsKaKa = tagsKaKa.sliceBy(tagsKaKaPerCollision, thisCollId); - for (const auto& tagKaKa : groupedTagsKaKa) { - auto trackFirst = tagKaKa.track0_as(); - auto trackSecond = tagKaKa.track1_as(); - loopOverThirdTrack(groupedTrackIndices, tracks, trackFirst, trackSecond, aod::tagandprobe::TagChannels::DsOrDplusToKKPi); - } + runCombinatorialThirdTrack(groupedTagsKaKa, groupedTrackIndices, tracks, tracks); } } PROCESS_SWITCH(ProbeThirdTrack, processCombinatorialDsToPhiPi, "Process combinatorial of tagged 2-kaon (phi) vertices with additional track", true); + void processCombinatorialDsToPhiPiMc(aod::Collisions const& collisions, + FilteredKaKaFromDspMcTags const& tagsKaKa, + aod::TrackAssoc const& trackIndices, + TracksWithDcaMc const& tracks, + aod::McParticles const& mcParticles) + { + for (const auto& collision : collisions) { + // Ds+/D+ -> phi(->K+K-)pi+ and c.c. + auto thisCollId = collision.globalIndex(); + auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + auto groupedTagsKaKa = tagsKaKa.sliceBy(tagsKaKaMcPerCollision, thisCollId); + runCombinatorialThirdTrack(groupedTagsKaKa, groupedTrackIndices, tracks, mcParticles); + } + } + PROCESS_SWITCH(ProbeThirdTrack, processCombinatorialDsToPhiPiMc, "Process combinatorial of tagged 2-kaon (phi) vertices with additional track using MC truth", false); + void processCombinatorialDstarToDzeroPi(aod::Collisions const& collisions, aod::PiKaFromDzTags const& tagsPiKa, aod::KaPiFromDzTags const& tagsKaPi, @@ -1142,24 +1452,89 @@ struct ProbeThirdTrack { auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); // D*+ -> D0(->pi+K-)pi+ auto groupedTagsPiKa = tagsPiKa.sliceBy(tagsPiKaPerCollision, thisCollId); - for (const auto& tagPiKa : groupedTagsPiKa) { - auto trackFirst = tagPiKa.track0_as(); // positive --> pion - auto trackSecond = tagPiKa.track1_as(); // negative --> kaon - loopOverThirdTrack(groupedTrackIndices, tracks, trackFirst, trackSecond, aod::tagandprobe::TagChannels::DstarPlusToDzeroPi); - } + runCombinatorialThirdTrack(groupedTagsPiKa, groupedTrackIndices, tracks, tracks); // D*- -> D0bar(->K+pi-)pi- auto groupedTagsKaPi = tagsKaPi.sliceBy(tagsKaPiPerCollision, thisCollId); - for (const auto& tagKaPi : groupedTagsKaPi) { - auto trackFirst = tagKaPi.track0_as(); // positive --> kaon - auto trackSecond = tagKaPi.track1_as(); // negative --> pion - loopOverThirdTrack(groupedTrackIndices, tracks, trackFirst, trackSecond, aod::tagandprobe::TagChannels::DstarMinusToDzeroBarPi); - } + runCombinatorialThirdTrack(groupedTagsKaPi, groupedTrackIndices, tracks, tracks); } } PROCESS_SWITCH(ProbeThirdTrack, processCombinatorialDstarToDzeroPi, "Process combinatorial of tagged pion-kaon (D0) vertices with additional track", true); + void processCombinatorialDstarToDzeroPiMc(aod::Collisions const& collisions, + FilteredPiKaFromDzMcTags const& tagsPiKa, + FilteredKaPiFromDzMcTags const& tagsKaPi, + aod::TrackAssoc const& trackIndices, + TracksWithDcaMc const& tracks, + aod::McParticles const& mcParticles) + { + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + // D*+ -> D0(->pi+K-)pi+ + auto groupedTagsPiKa = tagsPiKa.sliceBy(tagsPiKaMcPerCollision, thisCollId); + runCombinatorialThirdTrack(groupedTagsPiKa, groupedTrackIndices, tracks, mcParticles); + // D*- -> D0bar(->K+pi-)pi- + auto groupedTagsKaPi = tagsKaPi.sliceBy(tagsKaPiMcPerCollision, thisCollId); + runCombinatorialThirdTrack(groupedTagsKaPi, groupedTrackIndices, tracks, mcParticles); + } + } + PROCESS_SWITCH(ProbeThirdTrack, processCombinatorialDstarToDzeroPiMc, "Process combinatorial of tagged pion-kaon (D0) vertices with additional track using MC truth", false); + void processDummy(aod::Collisions const&) {} PROCESS_SWITCH(ProbeThirdTrack, processDummy, "Dummy process function that does nothing", false); + + void processGeneratedDstarToDzeroPi(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) + { + + if (std::abs(mcCollision.posZ()) > 10.) + return; + std::array arrDstar = {kPiPlus, kKMinus, kPiPlus}; + int8_t* sign = nullptr; + std::vector listIndexDaughters; + float ptDzero = -1, yDzero = -999, ptSoftPion = -1, etaSoftPion = -999, ptminTagDaughers = 9999., etamaxTagDaugthers = 0.; + int indexProbe; + for (auto const& mcPart : mcParticles) { + // LOGP(info, "particle id: {}", mcPart.pdgCode()); + if (RecoDecay::isMatchedMCGen(mcParticles, mcPart, constants::physics::Pdg::kDStar, arrDstar, true, sign, 2, &listIndexDaughters)) { + // LOGP(info, "Selected particle id: {}", mcPart.pdgCode()); + ptDzero = -1; + yDzero = -999; + ptSoftPion = -1; + etaSoftPion = -999; + ptminTagDaughers = 9999.; + etamaxTagDaugthers = 0.; + indexProbe = -1; + for (auto const& iDaughtIndex : mcPart.daughtersIds()) { + // Printf("mcpart.daugthersIds, index: %d",idaughtindex); + auto mcPartDstarDaught = mcParticles.rawIteratorAt(iDaughtIndex - mcParticles.offset()); + if (std::abs(mcPartDstarDaught.pdgCode()) == constants::physics::Pdg::kD0) { + ptDzero = mcPartDstarDaught.pt(); + yDzero = mcPartDstarDaught.y(); + } else if (std::abs(mcPartDstarDaught.pdgCode()) == kPiPlus) { + ptSoftPion = mcPartDstarDaught.pt(); + etaSoftPion = mcPartDstarDaught.eta(); + indexProbe = iDaughtIndex; + } + } + for (auto const& idx : listIndexDaughters) { + // LOGP(info, "listIndexDaughters, index: {}", idx); + if (idx == indexProbe) { + continue; + } + auto mcPartDaught = mcParticles.rawIteratorAt(idx - mcParticles.offset()); + ptminTagDaughers = std::min(mcPartDaught.pt(), ptminTagDaughers); + etamaxTagDaugthers = std::max(std::abs(mcPartDaught.eta()), etamaxTagDaugthers); + } + // registry.fill(HIST(Form("hGen%s",tagChannels[aod::tagandprobe::DstarPlusToDzeroPi].data())), + if (mcPart.pdgCode() > 0) { + histosGen[aod::tagandprobe::DstarPlusToDzeroPi]->Fill(mcPart.pt(), mcPart.y(), ptDzero, yDzero, ptSoftPion, etaSoftPion, ptminTagDaughers, etamaxTagDaugthers); + } else { + histosGen[aod::tagandprobe::DstarMinusToDzeroBarPi]->Fill(mcPart.pt(), mcPart.y(), ptDzero, yDzero, ptSoftPion, etaSoftPion, ptminTagDaughers, etamaxTagDaugthers); + } + } + } + } + PROCESS_SWITCH(ProbeThirdTrack, processGeneratedDstarToDzeroPi, "Count generated particles", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/DPG/Tasks/FDD/qaFDD.cxx b/DPG/Tasks/FDD/qaFDD.cxx index eb8beb04413..c985d7dbb9d 100644 --- a/DPG/Tasks/FDD/qaFDD.cxx +++ b/DPG/Tasks/FDD/qaFDD.cxx @@ -366,14 +366,13 @@ struct fddQA { int localBC = globalBC % nBCsPerOrbit; if (newRunNumber != oldRunNumber) { - std::map metadataRCT, headers; - headers = ccdbApi.retrieveHeaders(Form("RCT/Info/RunInformation/%i", newRunNumber), metadataRCT, -1); - ts = atol(headers["SOR"].c_str()); + auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, newRunNumber); + ts = soreor.first; LOG(info) << " newRunNumber " << newRunNumber << " time stamp " << ts; oldRunNumber = newRunNumber; - std::map mapMetadata; - std::map mapHeader; + // std::map mapMetadata; + // std::map mapHeader; auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", ts); CollidingBunch = grplhcif->getBunchFilling().getBCPattern(); for (int i = 0; i < static_cast(CollidingBunch.size()); i++) { @@ -491,15 +490,14 @@ struct fddQA { newRunNumber = bc.runNumber(); if (newRunNumber != oldRunNumber) { - uint64_t ts{}; - std::map metadataRCT, headers; - headers = ccdbApi.retrieveHeaders(Form("RCT/Info/RunInformation/%i", newRunNumber), metadataRCT, -1); - ts = atol(headers["SOR"].c_str()); + // uint64_t ts{}; + // std::map metadataRCT, headers; + auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, newRunNumber); + // headers = ccdbApi.retrieveHeaders(Form("RCT/Info/RunInformation/%i", newRunNumber), metadataRCT, -1); + auto ts = soreor.first; // atol(headers["SOR"].c_str()); LOG(info) << " newRunNumber " << newRunNumber << " time stamp " << ts; oldRunNumber = newRunNumber; - std::map mapMetadata; - std::map mapHeader; auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", ts); CollidingBunch = grplhcif->getBunchFilling().getBCPattern(); for (int i = 0; i < static_cast(CollidingBunch.size()); i++) { diff --git a/DPG/Tasks/FV0/qaFV0.cxx b/DPG/Tasks/FV0/qaFV0.cxx index 29a5b763211..295f981b0b7 100644 --- a/DPG/Tasks/FV0/qaFV0.cxx +++ b/DPG/Tasks/FV0/qaFV0.cxx @@ -394,7 +394,7 @@ struct fv0Qa { FillConditionHistograms("FV0BC", localCollisionBCFV0); - for (int i = 0; i < fv0.amplitude().size(); i++) { + for (std::size_t i = 0; i < fv0.amplitude().size(); i++) { FillConditionHistograms("FV0ChannelAmplitude", fv0.amplitude()[i]); FillConditionHistograms("FV0AmplitudePerChannel", fv0.channel()[i], fv0.amplitude()[i]); sum(totalAmplitudes, fv0.amplitude()[i]); diff --git a/DPG/Tasks/TPC/CMakeLists.txt b/DPG/Tasks/TPC/CMakeLists.txt index 65482991a4b..b8c68ba36fc 100644 --- a/DPG/Tasks/TPC/CMakeLists.txt +++ b/DPG/Tasks/TPC/CMakeLists.txt @@ -11,7 +11,7 @@ o2physics_add_dpl_workflow(pid-tpc-skimscreation SOURCES tpcSkimsTableCreator.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(pid-tpc-tree-creator-light diff --git a/DPG/Tasks/TPC/tpcSkimsTableCreator.cxx b/DPG/Tasks/TPC/tpcSkimsTableCreator.cxx index 6dd7f5ab79b..77b563c5567 100644 --- a/DPG/Tasks/TPC/tpcSkimsTableCreator.cxx +++ b/DPG/Tasks/TPC/tpcSkimsTableCreator.cxx @@ -19,20 +19,26 @@ #include "tpcSkimsTableCreator.h" #include #include +#include /// ROOT #include "TRandom3.h" /// O2 #include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" /// O2Physics #include "Common/Core/trackUtilities.h" #include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" #include "Common/DataModel/TrackSelectionTables.h" #include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGDQ/DataModel/ReducedInfoTables.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/EventSelection.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/DataModel/OccupancyTables.h" using namespace o2; using namespace o2::framework; @@ -42,14 +48,18 @@ using namespace o2::dataformats; struct TreeWriterTpcV0 { + Service ccdb; + using Trks = soa::Join; - using Coll = soa::Join; + using Colls = soa::Join; + using MyBCTable = soa::Join; /// Tables to be produced Produces rowTPCTree; + Produces rowTPCTreeWithTrkQA; /// Configurables - Configurable nSigmaTOFdautrack{"nSigmaTOFdautrack", 5., "n-sigma TOF cut on the daughter tracks. Set 0 to switch it off."}; + Configurable nSigmaTOFdautrack{"nSigmaTOFdautrack", 999., "n-sigma TOF cut on the proton daughter tracks. Set 999 to switch it off."}; Configurable nClNorm{"nClNorm", 152., "Number of cluster normalization. Run 2: 159, Run 3 152"}; Configurable applyEvSel{"applyEvSel", 2, "Flag to apply rapidity cut: 0 -> no event selection, 1 -> Run 2 event selection, 2 -> Run 3 event selection"}; Configurable trackSelection{"trackSelection", 1, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; @@ -61,6 +71,9 @@ struct TreeWriterTpcV0 { Configurable downsamplingTsalisPions{"downsamplingTsalisPions", -1., "Downsampling factor to reduce the number of pions"}; Configurable downsamplingTsalisProtons{"downsamplingTsalisProtons", -1., "Downsampling factor to reduce the number of protons"}; Configurable downsamplingTsalisElectrons{"downsamplingTsalisElectrons", -1., "Downsampling factor to reduce the number of electrons"}; + Configurable maxPt4dwnsmplTsalisPions{"maxPt4dwnsmplTsalisPions", 100., "Maximum Pt for applying downsampling factor of pions"}; + Configurable maxPt4dwnsmplTsalisProtons{"maxPt4dwnsmplTsalisProtons", 100., "Maximum Pt for applying downsampling factor of protons"}; + Configurable maxPt4dwnsmplTsalisElectrons{"maxPt4dwnsmplTsalisElectrons", 100., "Maximum Pt for applying downsampling factor of electrons"}; Filter trackFilter = (trackSelection.node() == 0) || ((trackSelection.node() == 1) && requireGlobalTrackInFilter()) || @@ -69,9 +82,11 @@ struct TreeWriterTpcV0 { ((trackSelection.node() == 4) && requireQualityTracksInFilter()) || ((trackSelection.node() == 5) && requireTrackCutInFilter(TrackSelectionFlags::kInAcceptanceTracks)); + ctpRateFetcher mRateFetcher; + /// Funktion to fill skimmed tables template - void fillSkimmedV0Table(V0 const& v0, T const& track, C const& collision, const float nSigmaTPC, const float nSigmaTOF, const float dEdxExp, const o2::track::PID::ID id, int runnumber, double dwnSmplFactor) + void fillSkimmedV0Table(V0 const& v0, T const& track, C const& collision, const float nSigmaTPC, const float nSigmaTOF, const float dEdxExp, const o2::track::PID::ID id, int runnumber, double dwnSmplFactor, float hadronicRate) { const double ncl = track.tpcNClsFound(); @@ -79,6 +94,8 @@ struct TreeWriterTpcV0 { const double mass = o2::track::pid_constants::sMasses[id]; const double bg = p / mass; const int multTPC = collision.multTPC(); + auto trackocc = collision.trackOccupancyInTimeRange(); + auto ft0occ = collision.ft0cOccupancyInTimeRange(); const float alpha = v0.alpha(); const float qt = v0.qtarm(); @@ -87,7 +104,7 @@ struct TreeWriterTpcV0 { const float v0radius = v0.v0radius(); const float gammapsipair = v0.psipair(); - const double pseudoRndm = track.pt() * 1000. - (int64_t)(track.pt() * 1000); + const double pseudoRndm = track.pt() * 1000. - static_cast(track.pt() * 1000); if (pseudoRndm < dwnSmplFactor) { rowTPCTree(track.tpcSignal(), 1. / dEdxExp, @@ -110,7 +127,72 @@ struct TreeWriterTpcV0 { pT, v0radius, gammapsipair, - runnumber); + runnumber, + trackocc, + ft0occ, + hadronicRate); + } + }; + + /// Function to fill skimmed tables + template + void fillSkimmedV0TableWithTrQA(V0 const& v0, T const& track, TQA const& trackQA, bool existTrkQA, C const& collision, const float nSigmaTPC, const float nSigmaTOF, const float dEdxExp, const o2::track::PID::ID id, int runnumber, double dwnSmplFactor, float hadronicRate, int bcGlobalIndex, int bcTimeFrameId, int bcBcInTimeFrame) + { + + const double ncl = track.tpcNClsFound(); + const double p = track.tpcInnerParam(); + const double mass = o2::track::pid_constants::sMasses[id]; + const double bg = p / mass; + const int multTPC = collision.multTPC(); + auto trackocc = collision.trackOccupancyInTimeRange(); + auto ft0occ = collision.ft0cOccupancyInTimeRange(); + + const float alpha = v0.alpha(); + const float qt = v0.qtarm(); + const float cosPA = v0.v0cosPA(); + const float pT = v0.pt(); + const float v0radius = v0.v0radius(); + const float gammapsipair = v0.psipair(); + + const double pseudoRndm = track.pt() * 1000. - static_cast(track.pt() * 1000); + if (pseudoRndm < dwnSmplFactor) { + rowTPCTreeWithTrkQA(track.tpcSignal(), + 1. / dEdxExp, + track.tpcInnerParam(), + track.tgl(), + track.signed1Pt(), + track.eta(), + track.phi(), + track.y(), + mass, + bg, + multTPC / 11000., + std::sqrt(nClNorm / ncl), + id, + nSigmaTPC, + nSigmaTOF, + alpha, + qt, + cosPA, + pT, + v0radius, + gammapsipair, + runnumber, + trackocc, + ft0occ, + hadronicRate, + bcGlobalIndex, + bcTimeFrameId, + bcBcInTimeFrame, + existTrkQA ? trackQA.tpcClusterByteMask() : -999, + existTrkQA ? trackQA.tpcdEdxMax0R() : -999, + existTrkQA ? trackQA.tpcdEdxMax1R() : -999, + existTrkQA ? trackQA.tpcdEdxMax2R() : -999, + existTrkQA ? trackQA.tpcdEdxMax3R() : -999, + existTrkQA ? trackQA.tpcdEdxTot0R() : -999, + existTrkQA ? trackQA.tpcdEdxTot1R() : -999, + existTrkQA ? trackQA.tpcdEdxTot2R() : -999, + existTrkQA ? trackQA.tpcdEdxTot3R() : -999); } }; @@ -129,11 +211,14 @@ struct TreeWriterTpcV0 { /// Random downsampling trigger function using Tsalis/Hagedorn spectra fit (sqrt(s) = 62.4 GeV to 13 TeV) /// as in https://iopscience.iop.org/article/10.1088/2399-6528/aab00f/pdf TRandom3* fRndm = new TRandom3(0); - bool downsampleTsalisCharged(double pt, double factor1Pt, double sqrts, double mass) + bool downsampleTsalisCharged(double pt, double factor1Pt, double sqrts, double mass, double maxPt) { if (factor1Pt < 0.) { return true; } + if (pt > maxPt) { + return true; + } const double prob = tsalisCharged(pt, mass, sqrts) * pt; const double probNorm = tsalisCharged(1., mass, sqrts); if ((fRndm->Rndm() * ((prob / probNorm) * pt * pt)) > factor1Pt) { @@ -161,10 +246,13 @@ struct TreeWriterTpcV0 { void init(o2::framework::InitContext&) { + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); } /// Apply a track quality selection with a filter! - void process(Coll::iterator const& collision, soa::Filtered const& tracks, aod::V0Datas const& v0s, aod::BCsWithTimestamps const&) + void processStandard(Colls::iterator const& collision, soa::Filtered const& tracks, aod::V0Datas const& v0s, aod::BCsWithTimestamps const&) { /// Check event slection if (!isEventSelected(collision, tracks)) { @@ -172,59 +260,172 @@ struct TreeWriterTpcV0 { } auto bc = collision.bc_as(); const int runnumber = bc.runNumber(); + float hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), runnumber, "ZNC hadronic") * 1.e-3; rowTPCTree.reserve(tracks.size()); /// Loop over v0 candidates - for (auto v0 : v0s) { + for (const auto& v0 : v0s) { auto posTrack = v0.posTrack_as>(); auto negTrack = v0.negTrack_as>(); // gamma if (static_cast(posTrack.pidbit() & (1 << 0)) && static_cast(negTrack.pidbit() & (1 << 0))) { - if (downsampleTsalisCharged(posTrack.pt(), downsamplingTsalisElectrons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Electron])) { - fillSkimmedV0Table(v0, posTrack, collision, posTrack.tpcNSigmaEl(), posTrack.tofNSigmaEl(), posTrack.tpcExpSignalEl(posTrack.tpcSignal()), o2::track::PID::Electron, runnumber, dwnSmplFactor_El); + if (downsampleTsalisCharged(posTrack.pt(), downsamplingTsalisElectrons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Electron], maxPt4dwnsmplTsalisElectrons)) { + fillSkimmedV0Table(v0, posTrack, collision, posTrack.tpcNSigmaEl(), posTrack.tofNSigmaEl(), posTrack.tpcExpSignalEl(posTrack.tpcSignal()), o2::track::PID::Electron, runnumber, dwnSmplFactor_El, hadronicRate); } - if (downsampleTsalisCharged(negTrack.pt(), downsamplingTsalisElectrons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Electron])) { - fillSkimmedV0Table(v0, negTrack, collision, negTrack.tpcNSigmaEl(), negTrack.tofNSigmaEl(), negTrack.tpcExpSignalEl(negTrack.tpcSignal()), o2::track::PID::Electron, runnumber, dwnSmplFactor_El); + if (downsampleTsalisCharged(negTrack.pt(), downsamplingTsalisElectrons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Electron], maxPt4dwnsmplTsalisElectrons)) { + fillSkimmedV0Table(v0, negTrack, collision, negTrack.tpcNSigmaEl(), negTrack.tofNSigmaEl(), negTrack.tpcExpSignalEl(negTrack.tpcSignal()), o2::track::PID::Electron, runnumber, dwnSmplFactor_El, hadronicRate); } } // Ks0 if (static_cast(posTrack.pidbit() & (1 << 1)) && static_cast(negTrack.pidbit() & (1 << 1))) { - if (downsampleTsalisCharged(posTrack.pt(), downsamplingTsalisPions, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Pion])) { - fillSkimmedV0Table(v0, posTrack, collision, posTrack.tpcNSigmaPi(), posTrack.tofNSigmaPi(), posTrack.tpcExpSignalPi(posTrack.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi); + if (downsampleTsalisCharged(posTrack.pt(), downsamplingTsalisPions, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Pion], maxPt4dwnsmplTsalisPions)) { + fillSkimmedV0Table(v0, posTrack, collision, posTrack.tpcNSigmaPi(), posTrack.tofNSigmaPi(), posTrack.tpcExpSignalPi(posTrack.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi, hadronicRate); } - if (downsampleTsalisCharged(negTrack.pt(), downsamplingTsalisPions, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Pion])) { - fillSkimmedV0Table(v0, negTrack, collision, negTrack.tpcNSigmaPi(), negTrack.tofNSigmaPi(), negTrack.tpcExpSignalPi(negTrack.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi); + if (downsampleTsalisCharged(negTrack.pt(), downsamplingTsalisPions, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Pion], maxPt4dwnsmplTsalisPions)) { + fillSkimmedV0Table(v0, negTrack, collision, negTrack.tpcNSigmaPi(), negTrack.tofNSigmaPi(), negTrack.tpcExpSignalPi(negTrack.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi, hadronicRate); } } // Lambda if (static_cast(posTrack.pidbit() & (1 << 2)) && static_cast(negTrack.pidbit() & (1 << 2))) { - if (downsampleTsalisCharged(posTrack.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Proton])) { - fillSkimmedV0Table(v0, posTrack, collision, posTrack.tpcNSigmaPr(), posTrack.tofNSigmaPr(), posTrack.tpcExpSignalPr(posTrack.tpcSignal()), o2::track::PID::Proton, runnumber, dwnSmplFactor_Pr); + if (downsampleTsalisCharged(posTrack.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Proton], maxPt4dwnsmplTsalisProtons)) { + if (std::abs(posTrack.tofNSigmaPr()) <= nSigmaTOFdautrack) { + fillSkimmedV0Table(v0, posTrack, collision, posTrack.tpcNSigmaPr(), posTrack.tofNSigmaPr(), posTrack.tpcExpSignalPr(posTrack.tpcSignal()), o2::track::PID::Proton, runnumber, dwnSmplFactor_Pr, hadronicRate); + } } - if (downsampleTsalisCharged(negTrack.pt(), downsamplingTsalisPions, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Pion])) { - fillSkimmedV0Table(v0, negTrack, collision, negTrack.tpcNSigmaPi(), negTrack.tofNSigmaPi(), negTrack.tpcExpSignalPi(negTrack.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi); + if (downsampleTsalisCharged(negTrack.pt(), downsamplingTsalisPions, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Pion], maxPt4dwnsmplTsalisPions)) { + fillSkimmedV0Table(v0, negTrack, collision, negTrack.tpcNSigmaPi(), negTrack.tofNSigmaPi(), negTrack.tpcExpSignalPi(negTrack.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi, hadronicRate); } } // Antilambda if (static_cast(posTrack.pidbit() & (1 << 3)) && static_cast(negTrack.pidbit() & (1 << 3))) { - if (downsampleTsalisCharged(posTrack.pt(), downsamplingTsalisPions, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Pion])) { - fillSkimmedV0Table(v0, posTrack, collision, posTrack.tpcNSigmaPi(), posTrack.tofNSigmaPi(), posTrack.tpcExpSignalPi(posTrack.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi); + if (downsampleTsalisCharged(posTrack.pt(), downsamplingTsalisPions, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Pion], maxPt4dwnsmplTsalisPions)) { + fillSkimmedV0Table(v0, posTrack, collision, posTrack.tpcNSigmaPi(), posTrack.tofNSigmaPi(), posTrack.tpcExpSignalPi(posTrack.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi, hadronicRate); } - if (downsampleTsalisCharged(negTrack.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Proton])) { - fillSkimmedV0Table(v0, negTrack, collision, negTrack.tpcNSigmaPr(), negTrack.tofNSigmaPr(), negTrack.tpcExpSignalPr(negTrack.tpcSignal()), o2::track::PID::Proton, runnumber, dwnSmplFactor_Pr); + if (downsampleTsalisCharged(negTrack.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Proton], maxPt4dwnsmplTsalisProtons)) { + if (std::abs(negTrack.tofNSigmaPr()) <= nSigmaTOFdautrack) { + fillSkimmedV0Table(v0, negTrack, collision, negTrack.tpcNSigmaPr(), negTrack.tofNSigmaPr(), negTrack.tpcExpSignalPr(negTrack.tpcSignal()), o2::track::PID::Proton, runnumber, dwnSmplFactor_Pr, hadronicRate); + } } } } - } /// process + } /// process Standard + PROCESS_SWITCH(TreeWriterTpcV0, processStandard, "Standard V0 Samples for PID", true); + + Preslice perCollisionTracks = aod::track::collisionId; + Preslice perCollisionV0s = aod::v0data::collisionId; + void processWithTrQA(Colls const& collisions, Trks const& myTracks, aod::V0Datas const& myV0s, MyBCTable const&, aod::TracksQA_002 const& tracksQA) + { + std::vector labelTrack2TrackQA; + labelTrack2TrackQA.clear(); + labelTrack2TrackQA.resize(myTracks.size(), -1); + for (const auto& trackQA : tracksQA) { + int64_t trackId = trackQA.trackId(); + int64_t trackQAIndex = trackQA.globalIndex(); + labelTrack2TrackQA[trackId] = trackQAIndex; + } + for (const auto& collision : collisions) { + auto tracks = myTracks.sliceBy(perCollisionTracks, collision.globalIndex()); + auto v0s = myV0s.sliceBy(perCollisionV0s, collision.globalIndex()); + /// Check event slection + if (!isEventSelected(collision, tracks)) { + continue; + } + auto bc = collision.bc_as(); + const int runnumber = bc.runNumber(); + float hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), runnumber, "ZNC hadronic") * 1.e-3; + const int bcGlobalIndex = bc.globalIndex(); + const int bcTimeFrameId = bc.tfId(); + const int bcBcInTimeFrame = bc.bcInTF(); + rowTPCTreeWithTrkQA.reserve(tracks.size()); + /// Loop over v0 candidates + for (const auto& v0 : v0s) { + auto posTrack = v0.posTrack_as(); + auto negTrack = v0.negTrack_as(); + aod::TracksQA_002::iterator posTrackQA; + aod::TracksQA_002::iterator negTrackQA; + bool existPosTrkQA; + bool existNegTrkQA; + if (labelTrack2TrackQA[posTrack.globalIndex()] != -1) { + posTrackQA = tracksQA.iteratorAt(labelTrack2TrackQA[posTrack.globalIndex()]); + existPosTrkQA = true; + } else { + posTrackQA = tracksQA.iteratorAt(0); + existPosTrkQA = false; + } + if (labelTrack2TrackQA[negTrack.globalIndex()] != -1) { + negTrackQA = tracksQA.iteratorAt(labelTrack2TrackQA[negTrack.globalIndex()]); + existNegTrkQA = true; + } else { + negTrackQA = tracksQA.iteratorAt(0); + existNegTrkQA = false; + } + + // gamma + if (static_cast(posTrack.pidbit() & (1 << 0)) && static_cast(negTrack.pidbit() & (1 << 0))) { + if (downsampleTsalisCharged(posTrack.pt(), downsamplingTsalisElectrons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Electron], maxPt4dwnsmplTsalisElectrons)) { + fillSkimmedV0TableWithTrQA(v0, posTrack, posTrackQA, existPosTrkQA, collision, posTrack.tpcNSigmaEl(), posTrack.tofNSigmaEl(), posTrack.tpcExpSignalEl(posTrack.tpcSignal()), o2::track::PID::Electron, runnumber, dwnSmplFactor_El, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } + if (downsampleTsalisCharged(negTrack.pt(), downsamplingTsalisElectrons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Electron], maxPt4dwnsmplTsalisElectrons)) { + fillSkimmedV0TableWithTrQA(v0, negTrack, negTrackQA, existNegTrkQA, collision, negTrack.tpcNSigmaEl(), negTrack.tofNSigmaEl(), negTrack.tpcExpSignalEl(negTrack.tpcSignal()), o2::track::PID::Electron, runnumber, dwnSmplFactor_El, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } + } + // Ks0 + if (static_cast(posTrack.pidbit() & (1 << 1)) && static_cast(negTrack.pidbit() & (1 << 1))) { + if (downsampleTsalisCharged(posTrack.pt(), downsamplingTsalisPions, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Pion], maxPt4dwnsmplTsalisPions)) { + fillSkimmedV0TableWithTrQA(v0, posTrack, posTrackQA, existPosTrkQA, collision, posTrack.tpcNSigmaPi(), posTrack.tofNSigmaPi(), posTrack.tpcExpSignalPi(posTrack.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } + if (downsampleTsalisCharged(negTrack.pt(), downsamplingTsalisPions, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Pion], maxPt4dwnsmplTsalisPions)) { + fillSkimmedV0TableWithTrQA(v0, negTrack, negTrackQA, existNegTrkQA, collision, negTrack.tpcNSigmaPi(), negTrack.tofNSigmaPi(), negTrack.tpcExpSignalPi(negTrack.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } + } + // Lambda + if (static_cast(posTrack.pidbit() & (1 << 2)) && static_cast(negTrack.pidbit() & (1 << 2))) { + if (downsampleTsalisCharged(posTrack.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Proton], maxPt4dwnsmplTsalisProtons)) { + if (std::abs(posTrack.tofNSigmaPr()) <= nSigmaTOFdautrack) { + fillSkimmedV0TableWithTrQA(v0, posTrack, posTrackQA, existPosTrkQA, collision, posTrack.tpcNSigmaPr(), posTrack.tofNSigmaPr(), posTrack.tpcExpSignalPr(posTrack.tpcSignal()), o2::track::PID::Proton, runnumber, dwnSmplFactor_Pr, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } + } + if (downsampleTsalisCharged(negTrack.pt(), downsamplingTsalisPions, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Pion], maxPt4dwnsmplTsalisPions)) { + fillSkimmedV0TableWithTrQA(v0, negTrack, negTrackQA, existNegTrkQA, collision, negTrack.tpcNSigmaPi(), negTrack.tofNSigmaPi(), negTrack.tpcExpSignalPi(negTrack.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } + } + // Antilambda + if (static_cast(posTrack.pidbit() & (1 << 3)) && static_cast(negTrack.pidbit() & (1 << 3))) { + if (downsampleTsalisCharged(posTrack.pt(), downsamplingTsalisPions, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Pion], maxPt4dwnsmplTsalisPions)) { + fillSkimmedV0TableWithTrQA(v0, posTrack, posTrackQA, existPosTrkQA, collision, posTrack.tpcNSigmaPi(), posTrack.tofNSigmaPi(), posTrack.tpcExpSignalPi(posTrack.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } + if (downsampleTsalisCharged(negTrack.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Proton], maxPt4dwnsmplTsalisProtons)) { + if (std::abs(negTrack.tofNSigmaPr()) <= nSigmaTOFdautrack) { + fillSkimmedV0TableWithTrQA(v0, negTrack, negTrackQA, existNegTrkQA, collision, negTrack.tpcNSigmaPr(), negTrack.tofNSigmaPr(), negTrack.tpcExpSignalPr(negTrack.tpcSignal()), o2::track::PID::Proton, runnumber, dwnSmplFactor_Pr, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } + } + } + } + } + } /// process with TrackQA + PROCESS_SWITCH(TreeWriterTpcV0, processWithTrQA, "Standard V0 Samples with Track QA for PID", false); + void processDummy(Colls const&) {} + PROCESS_SWITCH(TreeWriterTpcV0, processDummy, "Dummy function", false); + }; /// struct TreeWriterTpcV0 struct TreeWriterTPCTOF { - using Trks = soa::Join; - using Coll = soa::Join; + + Service ccdb; + + using Trks = soa::Join; + using Colls = soa::Join; + using MyBCTable = soa::Join; /// Tables to be produced Produces rowTPCTOFTree; + Produces rowTPCTOFTreeWithTrkQA; /// Configurables Configurable nClNorm{"nClNorm", 152., "Number of cluster normalization. Run 2: 159, Run 3 152"}; @@ -279,6 +480,8 @@ struct TreeWriterTPCTOF { ((trackSelection.node() == 4) && requireQualityTracksInFilter()) || ((trackSelection.node() == 5) && requireTrackCutInFilter(TrackSelectionFlags::kInAcceptanceTracks)); + ctpRateFetcher mRateFetcher; + double tsalisCharged(double pt, double mass, double sqrts) { const double a = 6.81, b = 59.24; @@ -287,7 +490,7 @@ struct TreeWriterTPCTOF { double n = a + b / sqrts; double T = c + d / sqrts; double p0 = n * T; - double result = pow((1. + mt / p0), -n); + double result = std::pow((1. + mt / p0), -n); return result; }; @@ -310,7 +513,7 @@ struct TreeWriterTPCTOF { /// Function to fill trees template - void fillSkimmedTPCTOFTable(T const& track, C const& collision, const float nSigmaTPC, const float nSigmaTOF, const float dEdxExp, const o2::track::PID::ID id, int runnumber, double dwnSmplFactor) + void fillSkimmedTPCTOFTable(T const& track, C const& collision, const float nSigmaTPC, const float nSigmaTOF, const float dEdxExp, const o2::track::PID::ID id, int runnumber, double dwnSmplFactor, double hadronicRate) { const double ncl = track.tpcNClsFound(); @@ -318,8 +521,10 @@ struct TreeWriterTPCTOF { const double mass = o2::track::pid_constants::sMasses[id]; const double bg = p / mass; const int multTPC = collision.multTPC(); + auto trackocc = collision.trackOccupancyInTimeRange(); + auto ft0occ = collision.ft0cOccupancyInTimeRange(); - const double pseudoRndm = track.pt() * 1000. - (int64_t)(track.pt() * 1000); + const double pseudoRndm = track.pt() * 1000. - static_cast(track.pt() * 1000); if (pseudoRndm < dwnSmplFactor) { rowTPCTOFTree(track.tpcSignal(), 1. / dEdxExp, @@ -336,7 +541,59 @@ struct TreeWriterTPCTOF { id, nSigmaTPC, nSigmaTOF, - runnumber); + runnumber, + trackocc, + ft0occ, + hadronicRate); + } + }; + /// Function to fill trees + template + void fillSkimmedTPCTOFTableWithTrkQA(T const& track, TQA const& trackQA, bool existTrkQA, C const& collision, const float nSigmaTPC, const float nSigmaTOF, const float nSigmaITS, const float dEdxExp, const o2::track::PID::ID id, int runnumber, double dwnSmplFactor, double hadronicRate, int bcGlobalIndex, int bcTimeFrameId, int bcBcInTimeFrame) + { + + const double ncl = track.tpcNClsFound(); + const double p = track.tpcInnerParam(); + const double mass = o2::track::pid_constants::sMasses[id]; + const double bg = p / mass; + const int multTPC = collision.multTPC(); + auto trackocc = collision.trackOccupancyInTimeRange(); + auto ft0occ = collision.ft0cOccupancyInTimeRange(); + + const double pseudoRndm = track.pt() * 1000. - static_cast(track.pt() * 1000); + if (pseudoRndm < dwnSmplFactor) { + rowTPCTOFTreeWithTrkQA(track.tpcSignal(), + 1. / dEdxExp, + track.tpcInnerParam(), + track.tgl(), + track.signed1Pt(), + track.eta(), + track.phi(), + track.y(), + mass, + bg, + multTPC / 11000., + std::sqrt(nClNorm / ncl), + id, + nSigmaTPC, + nSigmaTOF, + nSigmaITS, + runnumber, + trackocc, + ft0occ, + hadronicRate, + bcGlobalIndex, + bcTimeFrameId, + bcBcInTimeFrame, + existTrkQA ? trackQA.tpcClusterByteMask() : -999, + existTrkQA ? trackQA.tpcdEdxMax0R() : -999, + existTrkQA ? trackQA.tpcdEdxMax1R() : -999, + existTrkQA ? trackQA.tpcdEdxMax2R() : -999, + existTrkQA ? trackQA.tpcdEdxMax3R() : -999, + existTrkQA ? trackQA.tpcdEdxTot0R() : -999, + existTrkQA ? trackQA.tpcdEdxTot1R() : -999, + existTrkQA ? trackQA.tpcdEdxTot2R() : -999, + existTrkQA ? trackQA.tpcdEdxTot3R() : -999); } }; @@ -358,53 +615,141 @@ struct TreeWriterTPCTOF { void init(o2::framework::InitContext&) { + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); } - void process(Coll::iterator const& collision, soa::Filtered const& tracks, aod::BCsWithTimestamps const&) + void processStandard(Colls::iterator const& collision, soa::Filtered const& tracks, aod::BCsWithTimestamps const&) { /// Check event selection if (!isEventSelected(collision, tracks)) { return; } - auto bc = collision.bc_as(); const int runnumber = bc.runNumber(); + float hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), runnumber, "ZNC hadronic") * 1.e-3; + rowTPCTOFTree.reserve(tracks.size()); for (auto const& trk : tracks) { /// Fill tree for tritons if (trk.tpcInnerParam() < maxMomHardCutOnlyTr && trk.tpcInnerParam() <= maxMomTPCOnlyTr && std::abs(trk.tpcNSigmaTr()) < nSigmaTPCOnlyTr && downsampleTsalisCharged(trk.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Triton])) { - fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaTr(), trk.tofNSigmaTr(), trk.tpcExpSignalTr(trk.tpcSignal()), o2::track::PID::Triton, runnumber, dwnSmplFactor_Tr); + fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaTr(), trk.tofNSigmaTr(), trk.tpcExpSignalTr(trk.tpcSignal()), o2::track::PID::Triton, runnumber, dwnSmplFactor_Tr, hadronicRate); } else if (trk.tpcInnerParam() < maxMomHardCutOnlyTr && trk.tpcInnerParam() > maxMomTPCOnlyTr && std::abs(trk.tofNSigmaTr()) < nSigmaTOF_TPCTOF_Tr && std::abs(trk.tpcNSigmaTr()) < nSigmaTPC_TPCTOF_Tr && downsampleTsalisCharged(trk.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Triton])) { - fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaTr(), trk.tofNSigmaTr(), trk.tpcExpSignalTr(trk.tpcSignal()), o2::track::PID::Triton, runnumber, dwnSmplFactor_Tr); + fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaTr(), trk.tofNSigmaTr(), trk.tpcExpSignalTr(trk.tpcSignal()), o2::track::PID::Triton, runnumber, dwnSmplFactor_Tr, hadronicRate); } /// Fill tree for deuterons if (trk.tpcInnerParam() < maxMomHardCutOnlyDe && trk.tpcInnerParam() <= maxMomTPCOnlyDe && std::abs(trk.tpcNSigmaDe()) < nSigmaTPCOnlyDe && downsampleTsalisCharged(trk.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Deuteron])) { - fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaDe(), trk.tofNSigmaDe(), trk.tpcExpSignalDe(trk.tpcSignal()), o2::track::PID::Deuteron, runnumber, dwnSmplFactor_De); + fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaDe(), trk.tofNSigmaDe(), trk.tpcExpSignalDe(trk.tpcSignal()), o2::track::PID::Deuteron, runnumber, dwnSmplFactor_De, hadronicRate); } else if (trk.tpcInnerParam() < maxMomHardCutOnlyDe && trk.tpcInnerParam() > maxMomTPCOnlyDe && std::abs(trk.tofNSigmaDe()) < nSigmaTOF_TPCTOF_De && std::abs(trk.tpcNSigmaDe()) < nSigmaTPC_TPCTOF_De && downsampleTsalisCharged(trk.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Deuteron])) { - fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaDe(), trk.tofNSigmaDe(), trk.tpcExpSignalDe(trk.tpcSignal()), o2::track::PID::Deuteron, runnumber, dwnSmplFactor_De); + fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaDe(), trk.tofNSigmaDe(), trk.tpcExpSignalDe(trk.tpcSignal()), o2::track::PID::Deuteron, runnumber, dwnSmplFactor_De, hadronicRate); } /// Fill tree for protons if (trk.tpcInnerParam() <= maxMomTPCOnlyPr && std::abs(trk.tpcNSigmaPr()) < nSigmaTPCOnlyPr && downsampleTsalisCharged(trk.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Proton])) { - fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaPr(), trk.tofNSigmaPr(), trk.tpcExpSignalPr(trk.tpcSignal()), o2::track::PID::Proton, runnumber, dwnSmplFactor_Pr); + fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaPr(), trk.tofNSigmaPr(), trk.tpcExpSignalPr(trk.tpcSignal()), o2::track::PID::Proton, runnumber, dwnSmplFactor_Pr, hadronicRate); } else if (trk.tpcInnerParam() > maxMomTPCOnlyPr && std::abs(trk.tofNSigmaPr()) < nSigmaTOF_TPCTOF_Pr && std::abs(trk.tpcNSigmaPr()) < nSigmaTPC_TPCTOF_Pr && downsampleTsalisCharged(trk.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Proton])) { - fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaPr(), trk.tofNSigmaPr(), trk.tpcExpSignalPr(trk.tpcSignal()), o2::track::PID::Proton, runnumber, dwnSmplFactor_Pr); + fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaPr(), trk.tofNSigmaPr(), trk.tpcExpSignalPr(trk.tpcSignal()), o2::track::PID::Proton, runnumber, dwnSmplFactor_Pr, hadronicRate); } /// Fill tree for kaons if (trk.tpcInnerParam() < maxMomHardCutOnlyKa && trk.tpcInnerParam() <= maxMomTPCOnlyKa && std::abs(trk.tpcNSigmaKa()) < nSigmaTPCOnlyKa && downsampleTsalisCharged(trk.pt(), downsamplingTsalisKaons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Kaon])) { - fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaKa(), trk.tofNSigmaKa(), trk.tpcExpSignalKa(trk.tpcSignal()), o2::track::PID::Kaon, runnumber, dwnSmplFactor_Ka); + fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaKa(), trk.tofNSigmaKa(), trk.tpcExpSignalKa(trk.tpcSignal()), o2::track::PID::Kaon, runnumber, dwnSmplFactor_Ka, hadronicRate); } else if (trk.tpcInnerParam() < maxMomHardCutOnlyKa && trk.tpcInnerParam() > maxMomTPCOnlyKa && std::abs(trk.tofNSigmaKa()) < nSigmaTOF_TPCTOF_Ka && std::abs(trk.tpcNSigmaKa()) < nSigmaTPC_TPCTOF_Ka && downsampleTsalisCharged(trk.pt(), downsamplingTsalisKaons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Kaon])) { - fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaKa(), trk.tofNSigmaKa(), trk.tpcExpSignalKa(trk.tpcSignal()), o2::track::PID::Kaon, runnumber, dwnSmplFactor_Ka); + fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaKa(), trk.tofNSigmaKa(), trk.tpcExpSignalKa(trk.tpcSignal()), o2::track::PID::Kaon, runnumber, dwnSmplFactor_Ka, hadronicRate); } /// Fill tree pions if (trk.tpcInnerParam() <= maxMomTPCOnlyPi && std::abs(trk.tpcNSigmaPi()) < nSigmaTPCOnlyPi && downsampleTsalisCharged(trk.pt(), downsamplingTsalisPions, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Pion])) { - fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaPi(), trk.tofNSigmaPi(), trk.tpcExpSignalPi(trk.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi); + fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaPi(), trk.tofNSigmaPi(), trk.tpcExpSignalPi(trk.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi, hadronicRate); } else if (trk.tpcInnerParam() > maxMomTPCOnlyPi && std::abs(trk.tofNSigmaPi()) < nSigmaTOF_TPCTOF_Pi && std::abs(trk.tpcNSigmaPi()) < nSigmaTPC_TPCTOF_Pi && downsampleTsalisCharged(trk.pt(), downsamplingTsalisPions, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Pion])) { - fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaPi(), trk.tofNSigmaPi(), trk.tpcExpSignalPi(trk.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi); + fillSkimmedTPCTOFTable(trk, collision, trk.tpcNSigmaPi(), trk.tofNSigmaPi(), trk.tpcExpSignalPi(trk.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi, hadronicRate); } } /// Loop tracks } /// process -}; /// struct TreeWriterTPCTOF + PROCESS_SWITCH(TreeWriterTPCTOF, processStandard, "Standard Samples for PID", true); + Preslice perCollisionTracks = aod::track::collisionId; + void processWithTrQA(Colls const& collisions, Trks const& myTracks, MyBCTable const&, aod::TracksQA_002 const& tracksQA) + { + std::vector labelTrack2TrackQA; + labelTrack2TrackQA.clear(); + labelTrack2TrackQA.resize(myTracks.size(), -1); + for (const auto& trackQA : tracksQA) { + int64_t trackId = trackQA.trackId(); + int64_t trackQAIndex = trackQA.globalIndex(); + labelTrack2TrackQA[trackId] = trackQAIndex; + } + for (const auto& collision : collisions) { + auto tracks = myTracks.sliceBy(perCollisionTracks, collision.globalIndex()); + auto tracksWithITSPid = soa::Attach(tracks); + /// Check event selection + if (!isEventSelected(collision, tracks)) { + continue; + } + auto bc = collision.bc_as(); + const int runnumber = bc.runNumber(); + float hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), runnumber, "ZNC hadronic") * 1.e-3; + const int bcGlobalIndex = bc.globalIndex(); + const int bcTimeFrameId = bc.tfId(); + const int bcBcInTimeFrame = bc.bcInTF(); + rowTPCTOFTreeWithTrkQA.reserve(tracks.size()); + for (auto const& trk : tracksWithITSPid) { + if (!((trackSelection == 0) || + ((trackSelection == 1) && trk.isGlobalTrack()) || + ((trackSelection == 2) && trk.isGlobalTrackWoPtEta()) || + ((trackSelection == 3) && trk.isGlobalTrackWoDCA()) || + ((trackSelection == 4) && trk.isQualityTrack()) || + ((trackSelection == 5) && trk.isInAcceptanceTrack()))) { + continue; + } + // get the corresponding trackQA using labelTracks2TracKQA and get variables of interest + aod::TracksQA_002::iterator trackQA; + bool existTrkQA; + if (labelTrack2TrackQA[trk.globalIndex()] != -1) { + trackQA = tracksQA.iteratorAt(labelTrack2TrackQA[trk.globalIndex()]); + existTrkQA = true; + } else { + trackQA = tracksQA.iteratorAt(0); + existTrkQA = false; + } + /// Fill tree for tritons + if (trk.tpcInnerParam() < maxMomHardCutOnlyTr && trk.tpcInnerParam() <= maxMomTPCOnlyTr && std::abs(trk.tpcNSigmaTr()) < nSigmaTPCOnlyTr && downsampleTsalisCharged(trk.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Triton])) { + fillSkimmedTPCTOFTableWithTrkQA(trk, trackQA, existTrkQA, collision, trk.tpcNSigmaTr(), trk.tofNSigmaTr(), trk.itsNSigmaTr(), trk.tpcExpSignalTr(trk.tpcSignal()), o2::track::PID::Triton, runnumber, dwnSmplFactor_Tr, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } else if (trk.tpcInnerParam() < maxMomHardCutOnlyTr && trk.tpcInnerParam() > maxMomTPCOnlyTr && std::abs(trk.tofNSigmaTr()) < nSigmaTOF_TPCTOF_Tr && std::abs(trk.tpcNSigmaTr()) < nSigmaTPC_TPCTOF_Tr && downsampleTsalisCharged(trk.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Triton])) { + fillSkimmedTPCTOFTableWithTrkQA(trk, trackQA, existTrkQA, collision, trk.tpcNSigmaTr(), trk.tofNSigmaTr(), trk.itsNSigmaTr(), trk.tpcExpSignalTr(trk.tpcSignal()), o2::track::PID::Triton, runnumber, dwnSmplFactor_Tr, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } + /// Fill tree for deuterons + if (trk.tpcInnerParam() < maxMomHardCutOnlyDe && trk.tpcInnerParam() <= maxMomTPCOnlyDe && std::abs(trk.tpcNSigmaDe()) < nSigmaTPCOnlyDe && downsampleTsalisCharged(trk.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Deuteron])) { + fillSkimmedTPCTOFTableWithTrkQA(trk, trackQA, existTrkQA, collision, trk.tpcNSigmaDe(), trk.tofNSigmaDe(), trk.itsNSigmaDe(), trk.tpcExpSignalDe(trk.tpcSignal()), o2::track::PID::Deuteron, runnumber, dwnSmplFactor_De, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } else if (trk.tpcInnerParam() < maxMomHardCutOnlyDe && trk.tpcInnerParam() > maxMomTPCOnlyDe && std::abs(trk.tofNSigmaDe()) < nSigmaTOF_TPCTOF_De && std::abs(trk.tpcNSigmaDe()) < nSigmaTPC_TPCTOF_De && downsampleTsalisCharged(trk.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Deuteron])) { + fillSkimmedTPCTOFTableWithTrkQA(trk, trackQA, existTrkQA, collision, trk.tpcNSigmaDe(), trk.tofNSigmaDe(), trk.itsNSigmaDe(), trk.tpcExpSignalDe(trk.tpcSignal()), o2::track::PID::Deuteron, runnumber, dwnSmplFactor_De, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } + /// Fill tree for protons + if (trk.tpcInnerParam() <= maxMomTPCOnlyPr && std::abs(trk.tpcNSigmaPr()) < nSigmaTPCOnlyPr && downsampleTsalisCharged(trk.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Proton])) { + fillSkimmedTPCTOFTableWithTrkQA(trk, trackQA, existTrkQA, collision, trk.tpcNSigmaPr(), trk.tofNSigmaPr(), trk.itsNSigmaPr(), trk.tpcExpSignalPr(trk.tpcSignal()), o2::track::PID::Proton, runnumber, dwnSmplFactor_Pr, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } else if (trk.tpcInnerParam() > maxMomTPCOnlyPr && std::abs(trk.tofNSigmaPr()) < nSigmaTOF_TPCTOF_Pr && std::abs(trk.tpcNSigmaPr()) < nSigmaTPC_TPCTOF_Pr && downsampleTsalisCharged(trk.pt(), downsamplingTsalisProtons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Proton])) { + fillSkimmedTPCTOFTableWithTrkQA(trk, trackQA, existTrkQA, collision, trk.tpcNSigmaPr(), trk.tofNSigmaPr(), trk.itsNSigmaPr(), trk.tpcExpSignalPr(trk.tpcSignal()), o2::track::PID::Proton, runnumber, dwnSmplFactor_Pr, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } + /// Fill tree for kaons + if (trk.tpcInnerParam() < maxMomHardCutOnlyKa && trk.tpcInnerParam() <= maxMomTPCOnlyKa && std::abs(trk.tpcNSigmaKa()) < nSigmaTPCOnlyKa && downsampleTsalisCharged(trk.pt(), downsamplingTsalisKaons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Kaon])) { + fillSkimmedTPCTOFTableWithTrkQA(trk, trackQA, existTrkQA, collision, trk.tpcNSigmaKa(), trk.tofNSigmaKa(), trk.itsNSigmaKa(), trk.tpcExpSignalKa(trk.tpcSignal()), o2::track::PID::Kaon, runnumber, dwnSmplFactor_Ka, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } else if (trk.tpcInnerParam() < maxMomHardCutOnlyKa && trk.tpcInnerParam() > maxMomTPCOnlyKa && std::abs(trk.tofNSigmaKa()) < nSigmaTOF_TPCTOF_Ka && std::abs(trk.tpcNSigmaKa()) < nSigmaTPC_TPCTOF_Ka && downsampleTsalisCharged(trk.pt(), downsamplingTsalisKaons, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Kaon])) { + fillSkimmedTPCTOFTableWithTrkQA(trk, trackQA, existTrkQA, collision, trk.tpcNSigmaKa(), trk.tofNSigmaKa(), trk.itsNSigmaKa(), trk.tpcExpSignalKa(trk.tpcSignal()), o2::track::PID::Kaon, runnumber, dwnSmplFactor_Ka, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } + /// Fill tree pions + if (trk.tpcInnerParam() <= maxMomTPCOnlyPi && std::abs(trk.tpcNSigmaPi()) < nSigmaTPCOnlyPi && downsampleTsalisCharged(trk.pt(), downsamplingTsalisPions, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Pion])) { + fillSkimmedTPCTOFTableWithTrkQA(trk, trackQA, existTrkQA, collision, trk.tpcNSigmaPi(), trk.tofNSigmaPi(), trk.itsNSigmaPi(), trk.tpcExpSignalPi(trk.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } else if (trk.tpcInnerParam() > maxMomTPCOnlyPi && std::abs(trk.tofNSigmaPi()) < nSigmaTOF_TPCTOF_Pi && std::abs(trk.tpcNSigmaPi()) < nSigmaTPC_TPCTOF_Pi && downsampleTsalisCharged(trk.pt(), downsamplingTsalisPions, sqrtSNN, o2::track::pid_constants::sMasses[o2::track::PID::Pion])) { + fillSkimmedTPCTOFTableWithTrkQA(trk, trackQA, existTrkQA, collision, trk.tpcNSigmaPi(), trk.tofNSigmaPi(), trk.itsNSigmaPi(), trk.tpcExpSignalPi(trk.tpcSignal()), o2::track::PID::Pion, runnumber, dwnSmplFactor_Pi, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } + } /// Loop tracks + } + } /// process + PROCESS_SWITCH(TreeWriterTPCTOF, processWithTrQA, "Samples for PID with TrackQA info", false); + void processDummy(Colls const&) {} + PROCESS_SWITCH(TreeWriterTPCTOF, processDummy, "Dummy function", false); +}; /// struct TreeWriterTPCTOF WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { auto workflow = WorkflowSpec{adaptAnalysisTask(cfgc)}; diff --git a/DPG/Tasks/TPC/tpcSkimsTableCreator.h b/DPG/Tasks/TPC/tpcSkimsTableCreator.h index c8cce4750de..0f7e2264a25 100644 --- a/DPG/Tasks/TPC/tpcSkimsTableCreator.h +++ b/DPG/Tasks/TPC/tpcSkimsTableCreator.h @@ -13,6 +13,8 @@ /// \author Annalena Kalteyer /// \author Christian Sonnabend /// \author Jeremy Wilkinson +/// \author Ana Marin +/// \brief Creates clean samples of particles for PID fits #ifndef DPG_TASKS_TPC_TPCSKIMSTABLECREATOR_H_ #define DPG_TASKS_TPC_TPCSKIMSTABLECREATOR_H_ @@ -34,6 +36,7 @@ DECLARE_SOA_COLUMN(NormNClustersTPC, normNClustersTPC, float); DECLARE_SOA_COLUMN(PidIndex, pidIndexTPC, uint8_t); DECLARE_SOA_COLUMN(NSigTPC, nsigTPC, float); DECLARE_SOA_COLUMN(NSigTOF, nsigTOF, float); +DECLARE_SOA_COLUMN(NSigITS, nsigITS, float); DECLARE_SOA_COLUMN(AlphaV0, alphaV0, float); DECLARE_SOA_COLUMN(QtV0, qtV0, float); DECLARE_SOA_COLUMN(CosPAV0, cosPAV0, float); @@ -41,6 +44,12 @@ DECLARE_SOA_COLUMN(PtV0, ptV0, float); DECLARE_SOA_COLUMN(RadiusV0, radiusV0, float); DECLARE_SOA_COLUMN(GammaPsiPair, gammaPsiPair, float); DECLARE_SOA_COLUMN(RunNumber, runNumber, int); +DECLARE_SOA_COLUMN(TrackOcc, trackOcc, float); +DECLARE_SOA_COLUMN(Ft0Occ, ft0Occ, float); +DECLARE_SOA_COLUMN(HadronicRate, hadronicRate, float); +DECLARE_SOA_COLUMN(BcGlobalIndex, bcGlobalIndex, int); +DECLARE_SOA_COLUMN(BcTimeFrameId, bcTimeFrameId, int); +DECLARE_SOA_COLUMN(BcBcInTimeFrame, bcBcInTimeFrame, int); } // namespace tpcskims DECLARE_SOA_TABLE(SkimmedTPCV0Tree, "AOD", "TPCSKIMV0TREE", o2::aod::track::TPCSignal, @@ -64,7 +73,48 @@ DECLARE_SOA_TABLE(SkimmedTPCV0Tree, "AOD", "TPCSKIMV0TREE", tpcskims::PtV0, tpcskims::RadiusV0, tpcskims::GammaPsiPair, - tpcskims::RunNumber); + tpcskims::RunNumber, + tpcskims::TrackOcc, + tpcskims::Ft0Occ, + tpcskims::HadronicRate); +DECLARE_SOA_TABLE(SkimmedTPCV0TreeWithTrkQA, "AOD", "TPCSKIMV0WQA", + o2::aod::track::TPCSignal, + tpcskims::InvDeDxExpTPC, + o2::aod::track::TPCInnerParam, + o2::aod::track::Tgl, + o2::aod::track::Signed1Pt, + o2::aod::track::Eta, + o2::aod::track::Phi, + o2::aod::track::Y, + tpcskims::Mass, + tpcskims::BetaGamma, + tpcskims::NormMultTPC, + tpcskims::NormNClustersTPC, + tpcskims::PidIndex, + tpcskims::NSigTPC, + tpcskims::NSigTOF, + tpcskims::AlphaV0, + tpcskims::QtV0, + tpcskims::CosPAV0, + tpcskims::PtV0, + tpcskims::RadiusV0, + tpcskims::GammaPsiPair, + tpcskims::RunNumber, + tpcskims::TrackOcc, + tpcskims::Ft0Occ, + tpcskims::HadronicRate, + tpcskims::BcGlobalIndex, + tpcskims::BcTimeFrameId, + tpcskims::BcBcInTimeFrame, + o2::aod::trackqa::TPCClusterByteMask, + o2::aod::trackqa::TPCdEdxMax0R, + o2::aod::trackqa::TPCdEdxMax1R, + o2::aod::trackqa::TPCdEdxMax2R, + o2::aod::trackqa::TPCdEdxMax3R, + o2::aod::trackqa::TPCdEdxTot0R, + o2::aod::trackqa::TPCdEdxTot1R, + o2::aod::trackqa::TPCdEdxTot2R, + o2::aod::trackqa::TPCdEdxTot3R); DECLARE_SOA_TABLE(SkimmedTPCTOFTree, "AOD", "TPCTOFSKIMTREE", o2::aod::track::TPCSignal, @@ -82,6 +132,43 @@ DECLARE_SOA_TABLE(SkimmedTPCTOFTree, "AOD", "TPCTOFSKIMTREE", tpcskims::PidIndex, tpcskims::NSigTPC, tpcskims::NSigTOF, - tpcskims::RunNumber); + tpcskims::RunNumber, + tpcskims::TrackOcc, + tpcskims::Ft0Occ, + tpcskims::HadronicRate); + +DECLARE_SOA_TABLE(SkimmedTPCTOFTreeWithTrkQA, "AOD", "TPCTOFSKIMWQA", + o2::aod::track::TPCSignal, + tpcskims::InvDeDxExpTPC, + o2::aod::track::TPCInnerParam, + o2::aod::track::Tgl, + o2::aod::track::Signed1Pt, + o2::aod::track::Eta, + o2::aod::track::Phi, + o2::aod::track::Y, + tpcskims::Mass, + tpcskims::BetaGamma, + tpcskims::NormMultTPC, + tpcskims::NormNClustersTPC, + tpcskims::PidIndex, + tpcskims::NSigTPC, + tpcskims::NSigTOF, + tpcskims::NSigITS, + tpcskims::RunNumber, + tpcskims::TrackOcc, + tpcskims::Ft0Occ, + tpcskims::HadronicRate, + tpcskims::BcGlobalIndex, + tpcskims::BcTimeFrameId, + tpcskims::BcBcInTimeFrame, + o2::aod::trackqa::TPCClusterByteMask, + o2::aod::trackqa::TPCdEdxMax0R, + o2::aod::trackqa::TPCdEdxMax1R, + o2::aod::trackqa::TPCdEdxMax2R, + o2::aod::trackqa::TPCdEdxMax3R, + o2::aod::trackqa::TPCdEdxTot0R, + o2::aod::trackqa::TPCdEdxTot1R, + o2::aod::trackqa::TPCdEdxTot2R, + o2::aod::trackqa::TPCdEdxTot3R); } // namespace o2::aod #endif // DPG_TASKS_TPC_TPCSKIMSTABLECREATOR_H_ diff --git a/EventFiltering/CMakeLists.txt b/EventFiltering/CMakeLists.txt index 8ad0d0c4061..a6001817596 100644 --- a/EventFiltering/CMakeLists.txt +++ b/EventFiltering/CMakeLists.txt @@ -21,7 +21,7 @@ o2physics_add_dpl_workflow(selected-bc-range-task o2physics_add_dpl_workflow(nuclei-filter SOURCES PWGLF/nucleiFilter.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::TOFBase COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(diffraction-filter @@ -54,7 +54,7 @@ o2physics_add_dpl_workflow(hf-filter-prepare-ml-samples o2physics_add_dpl_workflow(cf-filter SOURCES PWGCF/CFFilterAll.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore KFParticle::KFParticle O2::ReconstructionDataFormats O2::DetectorsBase COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(cf-filter-qa @@ -62,6 +62,11 @@ o2physics_add_dpl_workflow(cf-filter-qa PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(cf-filter-ppphi + SOURCES PWGCF/CFFilterPPPhi.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(je-filter SOURCES PWGJE/jetFilter.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet FastJet::Contrib @@ -79,7 +84,7 @@ o2physics_add_dpl_workflow(fje-filter o2physics_add_dpl_workflow(lf-strangeness-filter SOURCES PWGLF/strangenessFilter.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsBase + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore KFParticle::KFParticle O2::ReconstructionDataFormats O2::DetectorsBase COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(mult-filter @@ -97,7 +102,26 @@ o2physics_add_dpl_workflow(em-photon-filter-qc PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase O2Physics::PWGEMPhotonMesonCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(heavy-neutral-meson-filter + SOURCES PWGEM/HeavyNeutralMesonFilter.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(lf-f1proton-filter SOURCES PWGLF/filterf1proton.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase COMPONENT_NAME Analysis) + + o2physics_add_dpl_workflow(lf-doublephi-filter + SOURCES PWGLF/filterdoublephi.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase + COMPONENT_NAME Analysis) + +o2physics_add_library(EventFilteringUtils + SOURCES Zorro.cxx ZorroSummary.cxx + INSTALL_HEADERS ZorroHelper.h ZorroSummary.h + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore Arrow::arrow_shared) + +o2physics_target_root_dictionary(EventFilteringUtils + HEADERS ZorroHelper.h ZorroSummary.h + LINKDEF EventFilteringUtilsLinkDef.h) diff --git a/EventFiltering/EventFilteringUtilsLinkDef.h b/EventFiltering/EventFilteringUtilsLinkDef.h new file mode 100644 index 00000000000..3f029b8aa9a --- /dev/null +++ b/EventFiltering/EventFilteringUtilsLinkDef.h @@ -0,0 +1,18 @@ +// 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. + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class ZorroHelper + ; +#pragma link C++ class ZorroSummary + ; +#pragma link C++ class std::vector < ZorroHelper> + ; diff --git a/EventFiltering/PWGCF/CFFilterAll.cxx b/EventFiltering/PWGCF/CFFilterAll.cxx index ca7b90fc0ca..6d272e825cf 100644 --- a/EventFiltering/PWGCF/CFFilterAll.cxx +++ b/EventFiltering/PWGCF/CFFilterAll.cxx @@ -12,1169 +12,1035 @@ /// \file CFFilterAll.cxx /// \brief Selection of events with triplets and pairs for femtoscopic studies /// -/// \author Laura Serksnyte, TU München, laura.serksnyte@cern.ch; Anton Riedel, TU München, anton.riedel@cern.ch - -#include -#include -#include -#include -#include -#include -#include -#include +/// \author Laura Serksnyte, TU München, laura.serksnyte@cern.ch; Anton Riedel, TU München, anton.riedel@cern.ch; Maximilian Korwieser, TU Munich, maximilian.korwieser@cern.ch + #include +#include #include "../filterTables.h" -#include "Framework/ASoAHelpers.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DCAFitter/DCAFitterN.h" +#include "DetectorsBase/Propagator.h" + +#include "fairlogger/Logger.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/RecoDecay.h" + #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" -#include "CommonConstants/MathConstants.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponse.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "DataFormatsTPC/BetheBlochAleph.h" -#include "CCDB/BasicCCDBManager.h" -#include "CCDB/CcdbApi.h" + +#include "PWGLF/Utils/strangenessBuilderHelper.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector4D.h" +#include "TMath.h" using namespace o2; +using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; -namespace CFTrigger +namespace cf_trigger { // enums -enum CFThreeBodyTriggers { kPPP, - kPPL, - kPLL, - kLLL, - kNThreeBodyTriggers }; -enum CFTwoBodyTriggers { kPD, - kLD, - kNTwoBodyTriggers -}; -enum ParticleSpecies { - kProton, - kDeuteron, - kLambda, - kNParticleSpecies +enum CFTriggers { + kPPP, + kPPL, + kPLL, + kLLL, + kPPPhi, + kPPRho, + kPD, + kLD, + kRhoD, + kPhiD, + kNTriggers }; -enum V0Daughters { - kDaughPion, - kDaughProton, - kNV0Daughters + +// variables for track selection +const std::vector trackNames{"Pion", "Kaon", "Proton", "Deuteron"}; +const uint32_t nTrackNames = 4; + +const std::vector trackSelectionNames{"AbsEtaMax", "TpcClusterMin", "TpcRowMin", "TpcCrossedOverFoundMin", "TpcSharedMax", "TpcFracSharedMax", "ItsClusterMin", "ItsIbClusterMin", "AbsDcaXyMax", "AbsDcaZMax", "Chi2TpcMax", "Chi2ItsMax"}; +const uint32_t nTrackSelectionNames = 12; + +const float trackSelectionTable[nTrackNames][nTrackSelectionNames] = { + {0.85, 90, 80, 0.83, 160, 1, 1, 0, 0.15, 0.15, 99, 99}, // Pion + {0.85, 90, 80, 0.83, 160, 1, 1, 0, 0.15, 0.15, 99, 99}, // Kaon + {0.85, 90, 80, 0.83, 160, 1, 1, 0, 0.15, 0.15, 99, 99}, // Proton + {0.85, 90, 80, 0.83, 160, 1, 1, 0, 0.15, 0.15, 99, 99}, // Deuteron }; -enum ParticleRejection { kRejProton, - kRejPion, - kRejElectron, - kNParticleRejection + +const std::vector pidSelectionNames{"ItsMin", "ItsMax", "TpcMin", "TpcMax", "TpcTofMax"}; +const uint32_t nPidSelectionNames = 5; + +const float pidSelectionTable[nTrackNames][nPidSelectionNames] = { + {-99, 99, -4, 4, 4}, // Pion + {-99, 99, -4, 4, 4}, // Kaon + {-99, 99, -4, 4, 4}, // Proton + {-3.5, 3.5, -3.5, 3.5, 3.5}, // Deuteron }; -enum PIDLimits { kTPCMin, - kTPCMax, - kTOFMin, - kTOFMax, - kTPCTOF, - kNPIDLimits + +const std::vector momentumSelectionNames{"PtMin", "PtMax", "PThres", "UseInnerParam"}; +const uint32_t nMomentumSelectionNames = 4; + +const float momentumSelectionTable[nTrackNames][nMomentumSelectionNames] = { + {0, 6, 0.4, -1}, // Pion + {0, 6, 0.5, -1}, // Kaon + {0.3, 6, 0.75, -1}, // Proton + {0.4, 2, 1.2, -1}, // Deuteron }; -// For configurable tables -static const std::vector CFTriggerNamesALL{"ppp", "ppL", "pLL", "LLL", "pd", "Ld"}; -static const std::vector SpeciesNameAll{"Proton", "Deuteron", "Lambda"}; -static const std::vector SpeciesName{"Proton", "Deuteron"}; -static const std::vector SpeciesNameAnti{"AntiProton", "AntiDeuteron"}; -static const std::vector SpeciesV0DaughterName{"Pion", "Proton"}; -static const std::vector SpeciesRejectionName{"Proton", "Pion", "Electron"}; -static const std::vector TPCCutName{"TPC min", "TPC max"}; -static const std::vector SpeciesMinTPCClustersName{"Proton", "Deuteron"}; -static const std::vector SpeciesAvgTPCTOFName{"Proton", "AntiProton", "Deuteron", "AntiDeuteron"}; -static const std::vector TPCTOFAvgName{"TPC Avg", "TOF Avg"}; -static const std::vector PidCutsName{"TPC min", "TPC max", "TOF min", "TOF max", "TPCTOF max"}; -static const std::vector PtCutsName{"Pt min (particle)", "Pt max (particle)", "Pt min (antiparticle)", "Pt max (antiparticle)", "P thres"}; -static const std::vector MomCorCutsName{"Momemtum Correlation min", "Momemtum Correlation max"}; -static const std::vector PIDForTrackingName{"Switch", "Momemtum Threshold"}; -static const std::vector ThreeBodyFilterNames{"PPP", "PPL", "PLL", "LLL"}; -static const std::vector TwoBodyFilterNames{"PD", "LD"}; -static const std::vector ParticleNames{"PPP", "aPaPaP", "PPL", "aPaPaL", "PLL", "aPaLaL", "LLL", "aLaLaL", "PD", "aPaD", "LD", "aLaD"}; - -static const int nPidRejection = 2; -static const int nTracks = 2; -static const int nPidAvg = 4; -static const int nPidCutsDaughers = 2; -static const int nPtCuts = 5; -static const int nAllTriggers = 6; -static const int nTriggerAllNames = 12; -static const int nMomCorCuts = 2; - -static const float pidcutsTable[nTracks][kNPIDLimits]{ - {-6.f, 6.f, -6.f, 6.f, 6.f}, - {-6.f, 6.f, -99.f, 99.f, 99.f}}; -static const float pidcutsTableAnti[nTracks][kNPIDLimits]{ - {-6.f, 6.f, -6.f, 6.f, 6.f}, - {-6.f, 6.f, -99.f, 99.f, 99.f}}; -static const float pidRejectionTable[kNParticleRejection][nPidRejection]{ - {-2.f, 2.f}, - {-2.f, 2.f}}; -static const double pidTPCTOFAvgTable[nPidAvg][nTracks]{ - {0.f, 0.f}, - {0.f, 0.f}, - {0.f, 0.f}, - {0.f, 0.f}}; -static const float pidcutsV0DaughterTable[kNV0Daughters][nPidCutsDaughers]{ - {-6.f, 6.f}, - {-6.f, 6.f}}; -static const float ptcutsTable[kNParticleRejection][nPtCuts]{ - {0.35f, 6.f, 0.35f, 6.0f, 0.75f}, - {0.35f, 1.6f, 0.35f, 1.6f, 99.f}, - {0.f, 6.f, 0.f, 6.f, 99.f}}; -static const float NClustersMin[1][nTracks]{ - {60.0f, 60.0f}}; -static const float MomCorLimits[2][nMomCorCuts] = - {{-99, 99}, - {-99, 99}}; -static const float PIDForTrackingTable[2][nTracks]{ - {-1, 0.75}, - {-1, 1.2}}; -static const float ITSCutsTable[1][nTracks] = { - {1, 1}}; - -static const float triggerSwitches[1][nAllTriggers]{ - {1, 1, 1, 1, 1, 1}}; - -static const float Q3Limits[1][kNThreeBodyTriggers]{ - {0.6f, 0.6f, 0.6f, 0.6f}}; - -static const float KstarLimits[1][kNTwoBodyTriggers]{ - {1.2f, 1.2f}}; - -static const float Downsample[2][nTriggerAllNames]{ - {-1., -1., -1., -1., -1., -1., -1., -1., -1., -1., -1., -1}, - {1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.}}; - -} // namespace CFTrigger - -namespace o2::aod -{ -using FemtoFullCollision = - soa::Join::iterator; +// variables for triggers +const std::vector filterNames{"PPP", "PPL", "PLL", "LLL", "PPPhi", "PPRho", "PD", "LD", "PhiD", "RhoD"}; +const uint32_t nFilterNames = 10; -using FemtoFullTracks = - soa::Join; -} // namespace o2::aod +const std::vector switches{"Switch"}; +const uint32_t nSwitches = 1; -struct CFFilter { +const float filterTable[nSwitches][nFilterNames]{ + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}; - Produces tags; +const std::vector limitNames{"Tight Limit", "Loose Limit"}; +const uint32_t nLimitNames = 2; - Service ccdb; - o2::ccdb::CcdbApi ccdbApi; +const float limitTable[nLimitNames][nFilterNames]{ + {0.6f, 0.6f, 0.6f, 0.6f, 0.6f, 0.6f, 0.5f, 0.5f, 0.5f, 0.5f}, + {1.2f, 1.2f, 1.2f, 1.2f, 1.2f, 1.2f, 1.0f, 1.0f, 1.0f, 1.0f}}; + +using FullCollisions = soa::Join; +using FullCollision = FullCollisions::iterator; - Configurable ConfRngSeed{"ConfRngSeed", 69, "Seed for downsampling"}; - TRandom3* rng; +using FullTracks = soa::Join; + +} // namespace cf_trigger + +struct CFFilterAll { + + Produces tags; // Configs for events - Configurable ConfIsRun3{ - "ConfIsRun3", - true, - "Is Run3"}; - - Configurable ConfEvtSelectZvtx{ - "ConfEvtSelectZvtx", - true, - "Event selection includes max. z-Vertex"}; - Configurable ConfEvtZvtx{"ConfEvtZvtx", - 10.f, - "Evt sel: Max. z-Vertex (cm)"}; - Configurable ConfEvtOfflineCheck{ - "ConfEvtOfflineCheck", - false, - "Evt sel: check for offline selection"}; - Configurable ConfEvtTimeFrameBorderCheck{ - "ConfEvtTimeFrameBorderCheck", - true, - "Evt sel: check for offline selection"}; - Configurable ConfAutocorRejection{ - "ConfAutocorRejection", - true, - "Rejection autocorrelation pL pairs"}; + struct : ConfigurableGroup { + std::string prefix = "EventSel"; + Configurable zvtx{"zvtx", 12.f, "Max. z-Vertex (cm)"}; + Configurable eventSel{"eventSel", true, "Use sel8"}; + } EventSelection; // Configs for tracks - Configurable ConfDeuteronThPVMom{ - "ConfDeuteronThPVMom", - false, - "True: use momentum at PV instead of TPCinnerparameter for threshold"}; - - Configurable ConfUseManualPIDproton{ - "ConfUseManualPIDproton", - false, - "True: use home-made PID solution for proton "}; - Configurable ConfPIDBBProton{ - "ConfPIDBBProton", - "Users/l/lserksny/PIDProton", - "Path to the CCDB ocject for proton BB param"}; - Configurable ConfPIDBBAntiProton{ - "ConfPIDBBAntiProton", - "Users/l/lserksny/PIDAntiProton", - "Path to the CCDB ocject for antiproton BB param"}; - - Configurable ConfUseManualPIDdeuteron{ - "ConfUseManualPIDdeuteron", - false, - "True: use home-made PID solution for deuteron "}; - Configurable ConfPIDBBDeuteron{ - "ConfPIDBBDeuteron", - "Users/l/lserksny/PIDDeuteron", - "Path to the CCDB ocject for Deuteron BB param"}; - Configurable ConfPIDBBAntiDeuteron{ - "ConfPIDBBAntiDeuteron", - "Users/l/lserksny/PIDAntiDeuteron", - "Path to the CCDB ocject for antiDeuteron BB param"}; - - Configurable ConfUseManualPIDpion{ - "ConfUseManualPIDpion", - false, - "True: use home-made PID solution for pions"}; - Configurable ConfPIDBBPion{ - "ConfPIDBBPion", - "Users/l/lserksny/PIDPion", - "Path to the CCDB ocject for Pion BB param"}; - Configurable ConfPIDBBAntiPion{ - "ConfPIDBBAntiPion", - "Users/l/lserksny/PIDAntiPion", - "Path to the CCDB ocject for antiPion BB param"}; - - Configurable ConfUseManualPIDel{ - "ConfUseManualPIDel", - false, - "True: use home-made PID solution for electron"}; - Configurable ConfPIDBBElectron{ - "ConfPIDBBElectron", - "Users/l/lserksny/PIDElectron", - "Path to the CCDB ocject for Electron BB param"}; - Configurable ConfPIDBBAntiElectron{ - "ConfPIDBBAntiElectron", - "Users/l/lserksny/PIDAntiElectron", - "Path to the CCDB ocject for antiElectron BB param"}; - - Configurable ConfUseManualPIDdaughterPion{ - "ConfUseManualPIDdaughterPion", - false, - "True: use home-made PID solution for pion from V0"}; - Configurable ConfUseManualPIDdaughterProton{ - "ConfUseManualPIDdaughterProton", - false, - "True: use home-made PID solution for proton from V0"}; - - Configurable ConfUseAvgFromCCDB{ - "ConfUseAvgFromCCDB", - false, - "True: use TOF and TPC averages from CCDB"}; - Configurable ConfAvgPath{ - "ConfAvgPath", - "Users/l/lserksny/TPCTOFAvg", - "Path to the CCDB ocject for TOF and TPC averages"}; - - Configurable ConfRejectNotPropagatedTracks{ - "ConfRejectNotPropagatedTracks", - false, - "True: reject not propagated tracks"}; - Configurable ConfTrkEta{ - "ConfTrkEta", - 0.85, - "Eta"}; - Configurable> ConfTPCNClustersMin{ - "ConfTPCNClustersMin", - {CFTrigger::NClustersMin[0], 1, CFTrigger::nTracks, std::vector{"TPCNClusMin"}, CFTrigger::SpeciesMinTPCClustersName}, - "kstar limit for two body trigger"}; - Configurable ConfTrkTPCfCls{ - "ConfTrkTPCfCls", - 0.83, - "Minimum fraction of crossed rows over findable clusters"}; - Configurable ConfTrkTPCcRowsMin{ - "ConfTrkTPCcRowsMin", - 70, - "Minimum number of crossed TPC rows"}; - Configurable ConfTrkTPCsClsMax{ - "ConfTrkTPCsClsMax", - 160, - "Maximum number of shared TPC clusters"}; - Configurable> ConfTrkITSnclsMin{ - "ConfTrkITSnclsMin", - {CFTrigger::ITSCutsTable[0], 1, CFTrigger::nTracks, std::vector{"Cut"}, CFTrigger::SpeciesName}, - "Minimum number of ITS clusters"}; - Configurable> ConfTrkITSnclsIBMin{ - "ConfTrkITSnclsIBMin", - {CFTrigger::ITSCutsTable[0], 1, CFTrigger::nTracks, std::vector{"Cut"}, CFTrigger::SpeciesName}, - "Minimum number of ITS clusters in the inner barrel"}; - Configurable ConfTrkDCAxyMax{ - "ConfTrkDCAxyMax", - 0.15, - "Maximum DCA_xy"}; - Configurable ConfTrkDCAzMax{ - "ConfTrkDCAzMax", - 0.3, - "Maximum DCA_z"}; - // Checks taken from global track definition - Configurable ConfTrkRequireChi2MaxTPC{ - "ConfTrkRequireChi2MaxTPC", false, - "True: require max chi2 per TPC cluster"}; - Configurable ConfTrkRequireChi2MaxITS{ - "ConfTrkRequireChi2MaxITS", false, - "True: require max chi2 per ITS cluster"}; - Configurable - ConfTrkMaxChi2PerClusterTPC{ - "ConfTrkMaxChi2PerClusterTPC", - 4.0f, - "Minimal track selection: max allowed chi2 per TPC cluster"}; // 4.0 is default of - // global tracks - // on 20.01.2023 - Configurable - ConfTrkMaxChi2PerClusterITS{ - "ConfTrkMaxChi2PerClusterITS", - 36.0f, - "Minimal track selection: max allowed chi2 per ITS cluster"}; // 36.0 is default of - // global tracks - // on 20.01.2023 - Configurable ConfTrkTPCRefit{ - "ConfTrkTPCRefit", - false, - "True: require TPC refit"}; - Configurable ConfTrkITSRefit{ - "ConfTrkITSRefit", - false, - "True: require ITS refit"}; - - // PID selections - Configurable> ConfPIDCuts{ - "ConfPIDCuts", - {CFTrigger::pidcutsTable[0], CFTrigger::nTracks, CFTrigger::kNPIDLimits, CFTrigger::SpeciesName, CFTrigger::PidCutsName}, - "Particle PID selections"}; - Configurable> ConfPIDCutsAnti{ - "ConfPIDCutsAnti", - {CFTrigger::pidcutsTableAnti[0], CFTrigger::nTracks, CFTrigger::kNPIDLimits, CFTrigger::SpeciesNameAnti, CFTrigger::PidCutsName}, - "Particle PID selections for antiparticles; perfect case scenario identical to particles"}; - Configurable ConfRejectNOTDeuteron{ - "ConfRejectNOTDeuteron", - false, - "Reject deuteron candidates if they are compatible with electron, pion, proton"}; - Configurable> ConfPIDRejection{ - "ConfPIDRejection", - {CFTrigger::pidRejectionTable[0], CFTrigger::kNParticleRejection, CFTrigger::nPidRejection, CFTrigger::SpeciesRejectionName, CFTrigger::TPCCutName}, - "Particle PID Rejection selections (Deuteron candidates only)"}; - Configurable> ConfPIDTPCTOFAvg{ - "ConfPIDTPCTOFAvg", - {CFTrigger::pidTPCTOFAvgTable[0], CFTrigger::nPidAvg, CFTrigger::nTracks, CFTrigger::SpeciesAvgTPCTOFName, CFTrigger::TPCTOFAvgName}, - "Average expected nSigma of TPC and TOF, which is substracted in calculation of combined TPC and TOF nSigma"}; - - // Momentum selections - Configurable> ConfMomCorDifCut{ - "ConfMomCorDifCuts", - {CFTrigger::MomCorLimits[0], CFTrigger::nTracks, CFTrigger::nMomCorCuts, CFTrigger::SpeciesName, CFTrigger::MomCorCutsName}, - "ratio on momentum correlation difference (particle)"}; - Configurable> ConfMomCorDifCutAnti{ - "ConfMomCorDifCutsAnti", - {CFTrigger::MomCorLimits[0], CFTrigger::nTracks, CFTrigger::nMomCorCuts, CFTrigger::SpeciesNameAnti, CFTrigger::MomCorCutsName}, - "Cut on momentum correlation difference (antipartilce)"}; - Configurable ConfMomCorDifCutFlag{"ConfMomCorDifFlag", false, "Flag for cut on momentum correlation difference"}; - - Configurable> ConfMomCorRatioCut{ - "ConfMomCorRatioCuts", - {CFTrigger::MomCorLimits[0], CFTrigger::nTracks, CFTrigger::nMomCorCuts, CFTrigger::SpeciesName, CFTrigger::MomCorCutsName}, - "Cut on momentum correlation ratio (particle)"}; - Configurable> ConfMomCorRatioCutAnti{ - "ConfMomCorRatioCutsAnti", - {CFTrigger::MomCorLimits[0], CFTrigger::nTracks, CFTrigger::nMomCorCuts, CFTrigger::SpeciesNameAnti, CFTrigger::MomCorCutsName}, - "Cut on momentum correlation ratio (antipartilce)"}; - Configurable ConfMomCorRatioCutFlag{"ConfMomCorRatioFlag", false, "Flag for cut on momentum correlation ratio"}; - - Configurable> ConfPIDForTracking{ - "ConfPIDForTracking", - {CFTrigger::PIDForTrackingTable[0], CFTrigger::nTracks, 2, CFTrigger::SpeciesName, CFTrigger::PIDForTrackingName}, - "Use PID used in tracking up to momentum threshold"}; - - Configurable> ConfPtCuts{ - "ConfPtCuts", - {CFTrigger::ptcutsTable[0], CFTrigger::kNParticleSpecies, CFTrigger::nPtCuts, CFTrigger::SpeciesNameAll, CFTrigger::PtCutsName}, - "Particle Momentum selections"}; + struct : ConfigurableGroup { + std::string prefix = "TrackSel"; + Configurable> trackProperties{"trackProperties", + {cf_trigger::trackSelectionTable[0], + cf_trigger::nTrackNames, + cf_trigger::nTrackSelectionNames, + cf_trigger::trackNames, + cf_trigger::trackSelectionNames}, + "Track Selections"}; + + Configurable> momentum{"momentum", + {cf_trigger::momentumSelectionTable[0], + cf_trigger::nTrackNames, + cf_trigger::nMomentumSelectionNames, + cf_trigger::trackNames, + cf_trigger::momentumSelectionNames}, + "Momentum Selections"}; + + Configurable> pid{"pid", + {cf_trigger::pidSelectionTable[0], + cf_trigger::nTrackNames, + cf_trigger::nPidSelectionNames, + cf_trigger::trackNames, + cf_trigger::pidSelectionNames}, + "PID Selections"}; + } TrackSelections; // Configs for V0 - Configurable ConfV0PtMin{ - "ConfV0PtMin", - 0.f, - "Minimum transverse momentum of V0"}; - Configurable ConfV0DCADaughMax{ - "ConfV0DCADaughMax", - 1.8f, - "Maximum DCA between the V0 daughters"}; - Configurable ConfV0CPAMin{ - "ConfV0CPAMin", - 0.985f, - "Minimum CPA of V0"}; - Configurable ConfV0TranRadV0Min{ - "ConfV0TranRadV0Min", - 0.2f, - "Minimum transverse radius"}; - Configurable ConfV0TranRadV0Max{ - "ConfV0TranRadV0Max", - 100.f, - "Maximum transverse radius"}; - Configurable ConfV0DecVtxMax{"ConfV0DecVtxMax", - 100.f, - "Maximum distance from primary vertex"}; - Configurable ConfV0InvMassLowLimit{ - "ConfV0InvMassLowLimit", - 1.05, - "Lower limit of the V0 invariant mass"}; - Configurable ConfV0InvMassUpLimit{ - "ConfV0InvMassUpLimit", - 1.18, - "Upper limit of the V0 invariant mass"}; - - Configurable ConfV0RejectKaons{"ConfV0RejectKaons", - true, - "Switch to reject kaons"}; - Configurable ConfV0InvKaonMassLowLimit{ - "ConfV0InvKaonMassLowLimit", - 0.49, - "Lower limit of the V0 invariant mass for Kaon rejection"}; - Configurable ConfV0InvKaonMassUpLimit{ - "ConfV0InvKaonMassUpLimit", - 0.505, - "Upper limit of the V0 invariant mass for Kaon rejection"}; - - // config for V0 daughters - Configurable ConfDaughEta{ - "ConfDaughEta", - 0.85f, - "V0 Daugh sel: max eta"}; - Configurable ConfDaughTPCnclsMin{ - "ConfDaughTPCnclsMin", - 60.f, - "V0 Daugh sel: Min. nCls TPC"}; - Configurable ConfDaughDCAMin{ - "ConfDaughDCAMin", - 0.04f, - "V0 Daugh sel: Max. DCA Daugh to PV (cm)"}; - Configurable> ConfDaughPIDCuts{ - "ConfDaughPIDCuts", - {CFTrigger::pidcutsV0DaughterTable[0], CFTrigger::kNV0Daughters, CFTrigger::nPidCutsDaughers, CFTrigger::SpeciesV0DaughterName, CFTrigger::TPCCutName}, - "PID selections for Lambda daughters"}; + struct : ConfigurableGroup { + std::string prefix = "V0BuilderOpts"; + Configurable minCrossedRows{"minCrossedRows", 70, "minimum TPC crossed rows for daughter tracks"}; + Configurable dcanegtopv{"dcanegtopv", 0.04, "DCA Neg To PV"}; + Configurable dcapostopv{"dcapostopv", 0.04, "DCA Pos To PV"}; + Configurable v0cospa{"v0cospa", 0.95, "V0 CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0) + Configurable dcav0dau{"dcav0dau", 2.0, "DCA V0 Daughters"}; + Configurable v0radius{"v0radius", 0, "v0radius"}; + Configurable maxDaughterEta{"maxDaughterEta", 5, "Maximum daughter eta (in abs value)"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + } V0BuilderOpts; + + struct : ConfigurableGroup { + std::string prefix = "FitterOpts"; + Configurable propagateToPCA{"propagateToPCA", true, "Create tracks version propagated to PCA"}; + Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; + Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iteraterions if chi2/chi2old > this"}; + Configurable maxDzIni{"maxDzIni", 1.e9, "reject (if>0) PCA candicate if tracks DZ exceeds threshold"}; + Configurable maxDxyIni{"maxDxyIni", 4., "Same as above for DXY"}; + Configurable maxChi2{"maxChi2", 1.e9, "Maximum chi2"}; + Configurable useAbsDCA{"useAbsDCA", true, "Minimise abs. distance rather than chi2"}; + Configurable weightedFinalPCA{"weightedFinalPCA", false, "Weight final PCA"}; + } FitterOpts; + + struct : ConfigurableGroup { + std::string prefix = "LambdaSel"; + Configurable ptMin{"ptMin", 0.f, "Minimum transverse momentum of V0"}; + Configurable dcaDaughMax{"dcaDaughMax", 2.f, "Maximum DCA between the V0 daughters"}; + Configurable cpaMin{"cpaMin", 0.95f, "Minimum CPA of V0"}; + Configurable tranRadMin{"tranRadMin", 0.f, "Minimum transverse radius"}; + Configurable tranRadMax{"tranRadMax", 100.f, "Maximum transverse radius"}; + Configurable decVtxMax{"decVtxMax", 100.f, "Maximum distance from primary vertex"}; + Configurable invMassLow{"invMassLow", 1.05, "Lower limit of the V0 invariant mass"}; + Configurable invMassUp{"invMassUp", 1.18, "Upper limit of the V0 invariant mass"}; + Configurable rejectKaons{"rejectKaons", true, "Switch to reject kaons"}; + Configurable invKaonMassLow{"invKaonMassLow", 0.49, "Lower limit of the V0 invariant mass for Kaon rejection"}; + Configurable invKaonMassUp{"invKaonMassUp", 0.505, "Upper limit of the V0 invariant mass for Kaon rejection"}; + } LambdaSelections; + + struct : ConfigurableGroup { + std::string prefix = "LambdaDaughterSel"; + Configurable absEtaMax{"absEtaMax", 0.85f, "V0 Daugh sel: max eta"}; + Configurable tpcClusterMin{"tpcClusterMin", 70.f, "V0 Daugh sel: Min. nCls TPC"}; + Configurable dcaMin{"dcaMin", 0.04f, "V0 Daugh sel: Max. DCA Daugh to PV (cm)"}; + Configurable tpcMax{"tpcMax", 5, "PID selections for Lambda daughters"}; + } LambdaDaughterSelections; + + struct : ConfigurableGroup { + std::string prefix = "PhiSel"; + Configurable invMassLow{"invMassLow", 1.011461, "Lower limit of Phi invariant mass"}; + Configurable invMassUp{"invMassUp", 1.027461, "Upper limit of Phi invariant mass"}; + Configurable tightInvMassLow{"tightInvMassLow", 1.011461, "Lower tight limit of Phi invariant mass"}; + Configurable tightInvMassUp{"tightInvMassUp", 1.027461, "Upper tight limit of Phi invariant mass"}; + } PhiSelections; + + struct : ConfigurableGroup { + std::string prefix = "RhoSel"; + Configurable invMassLow{"invMassLow", 0.7, "Lower limit of Rho invariant mass"}; + Configurable invMassUp{"invMassUp", 0.85, "Upper limit of Rho invariant mass"}; + Configurable ptLow{"ptLow", 3, "Lower pt limit for rho"}; + Configurable tightInvMassLow{"tightInvMassLow", 0.73, "Lower tight limit of Rho invariant mass"}; + Configurable tightInvMassUp{"tightInvMassUp", 0.82, "Upper tight limit of Rho invariant mass"}; + } RhoSelections; // Trigger selections - Configurable> ConfTriggerSwitches{ - "ConfTriggerSwitches", - {CFTrigger::triggerSwitches[0], 1, CFTrigger::nAllTriggers, std::vector{"Switch"}, CFTrigger::CFTriggerNamesALL}, - "Turn on specific trigger"}; - - Configurable> ConfQ3Limits{ - "ConfQ3Limits", - {CFTrigger::Q3Limits[0], 1, CFTrigger::kNThreeBodyTriggers, std::vector{"Limit"}, CFTrigger::ThreeBodyFilterNames}, - "Q3 limits for three body trigger"}; - - Configurable> ConfKstarLimits{ - "ConfKstarLimits", - {CFTrigger::KstarLimits[0], 1, CFTrigger::kNTwoBodyTriggers, std::vector{"Limit"}, CFTrigger::TwoBodyFilterNames}, - "kstar limit for two body trigger"}; - - Configurable> ConfDownsample{ - "ConfDownsample", - {CFTrigger::Downsample[0], 2, CFTrigger::nTriggerAllNames, std::vector{"Switch", "Factor"}, CFTrigger::ParticleNames}, - "Downsample individual particle species (Switch has to be larger than 0, Factor has to smaller than 1)"}; + struct : ConfigurableGroup { + std::string prefix = "Triggers"; + Configurable> filterSwitches{"filterSwitches", + {cf_trigger::filterTable[0], + cf_trigger::nSwitches, + cf_trigger::nFilterNames, + cf_trigger::switches, + cf_trigger::filterNames}, + "Switch for triggers"}; + Configurable> limits{"limits", + {cf_trigger::limitTable[0], + cf_trigger::nLimitNames, + cf_trigger::nFilterNames, + cf_trigger::limitNames, + cf_trigger::filterNames}, + "Limits for trigger. Tight limit without downsampling and loose with downsampling"}; + } TriggerSelections; + + struct : ConfigurableGroup { + std::string prefix = "Binning"; + ConfigurableAxis multiplicity{"multiplicity", {200, 0, 200}, "Binning Multiplicity"}; + ConfigurableAxis zvtx{"zvtx", {30, -15, 15}, "Binning Zvertex"}; + + ConfigurableAxis momentum{"momentum", {600, 0, 6}, "Binning Momentum"}; + ConfigurableAxis eta{"eta", {200, -1, 1}, "Binning eta"}; + ConfigurableAxis phi{"phi", {720, 0, o2::constants::math::TwoPI}, "Binning phi"}; + ConfigurableAxis dca{"dca", {100, -0.2, 0.2}, "Binning Dca"}; + + ConfigurableAxis nsigma{"nsigma", {500, -5, 5}, "Binning nsigma"}; + ConfigurableAxis nsigmaComb{"nsigmaComb", {500, 0, 5}, "Binning nsigma comb"}; + ConfigurableAxis tpcSignal{"tpcSignal", {500, 0, 500}, "Binning Tpc Signal"}; + ConfigurableAxis itsSignal{"itsSignal", {150, 0, 15}, "Binning Its Signal"}; + ConfigurableAxis tofSignal{"tofSignal", {120, 0, 1.2}, "Binning Tof Signal"}; + ConfigurableAxis tpcCluster{"tpcCluster", {153, 0, 153}, "Binning Tpc Clusters"}; + ConfigurableAxis tpcChi2{"tpcChi2", {100, 0, 5}, "Binning TPC chi2"}; + ConfigurableAxis itsCluster{"itsCluster", {8, -0.5, 7.5}, "Binning Its Clusters"}; + ConfigurableAxis itsIbCluster{"itsIbCluster", {4, -0.5, 3.5}, "Binning Its Inner Barrel Clusters"}; + ConfigurableAxis itsChi2{"itsChi2", {100, 0, 50}, "Binning ITS chi2"}; + + ConfigurableAxis momCor{"momCor", {100, -1, 1}, "Binning Ratios"}; + ConfigurableAxis ratio{"ratio", {200, 0, 2}, "Binning Ratios"}; + + ConfigurableAxis invMassLambda{"invMassLambda", {200, 1, 1.2}, "Binning Invariant Mass Lambda"}; + ConfigurableAxis invMassK0short{"invMassK0short", {100, 0.48, 0.52}, "Binning Invariant Mass K0short"}; + + ConfigurableAxis dcaDaugh{"dcaDaugh", {200, 0, 2}, "Binning daughter DCA at decay vertex"}; + ConfigurableAxis cpa{"cpa", {100, 0.9, 1}, "Binning CPA"}; + ConfigurableAxis transRad{"transRad", {100, 0, 100}, "Binning Transverse Radius"}; + ConfigurableAxis decayVtx{"decayVtx", {100, 0, 100}, "Binning Decay Vertex"}; + + ConfigurableAxis invMassPhi{"invMassPhi", {700, 0.8, 1.5}, "Binning Invariant Mass Phi"}; + + ConfigurableAxis invMassRho{"invMassRho", {600, 0.6, 1.2}, "Binning Invariant Mass Rho"}; + + ConfigurableAxis q3{"q3", {300, 0, 3}, "Binning Decay Q3"}; + ConfigurableAxis kstar{"kstar", {300, 0, 3}, "Binning Decay Kstar"}; + + } Binning; HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; - // HistogramRegistry registryQA{"registryQA", {}, OutputObjHandlingPolicy::AnalysisObject}; - std::vector BBProton, BBAntiproton, BBDeuteron, BBAntideuteron, BBPion, BBAntipion, BBElectron, BBAntielectron, TPCTOFAvg; + // helper object flor building lambdas + o2::pwglf::strangenessBuilderHelper mStraHelper; + Service ccdb; + int mRunNumber = 0; + float mBz = 0.; + + // 4vectors for all particles + std::vector vecProton, vecAntiProton, vecDeuteron, vecAntiDeuteron, vecLambda, vecAntiLambda, vecKaon, vecAntiKaon, vecPhi, vecPion, vecAntiPion, vecRho; + // indices for all particles + std::vector idxProton, idxAntiProton, idxDeuteron, idxAntiDeuteron, idxKaon, idxAntiKaon, idxPion, idxAntiPion; + // indices for lambda daughters + std::vector idxLambdaDaughProton, idxLambdaDaughPion, idxAntiLambdaDaughProton, idxAntiLambdaDaughPion, idxPhiDaughPos, idxPhiDaughNeg, idxRhoDaughPos, idxRhoDaughNeg; + + // arrays to store found pairs/tripplets and trigger decisions + std::array keepEventTightLimit; + std::array keepEventLooseLimit; + std::array signalTightLimit; + std::array signalLooseLimit; + void init(o2::framework::InitContext&) { - rng = new TRandom3(ConfRngSeed.value); - - // init the ccdb - ccdb->setURL("http://alice-ccdb.cern.ch"); - ccdbApi.init("http://alice-ccdb.cern.ch"); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - - // Set avg if not taking from ccdb - if (!ConfUseAvgFromCCDB) { - TPCTOFAvg = {ConfPIDTPCTOFAvg->get("Proton", "TPC Avg"), - ConfPIDTPCTOFAvg->get("Proton", "TOF Avg"), - ConfPIDTPCTOFAvg->get("AntiProton", "TPC Avg"), - ConfPIDTPCTOFAvg->get("AntiProton", "TOF Avg"), - ConfPIDTPCTOFAvg->get("Deuteron", "TPC Avg"), - ConfPIDTPCTOFAvg->get("Deuteron", "TOF Avg"), - ConfPIDTPCTOFAvg->get("AntiDeuteron", "TPC Avg"), - ConfPIDTPCTOFAvg->get("AntiDeuteron", "TOF Avg")}; - } - - // global histograms - registry.add("fProcessedEvents", "CF - event filtered;;Events", HistType::kTH1F, {{8, -0.5, 7.5}}); - std::vector eventTitles = {"all", "rejected", "ppp", "ppL", "pLL", "LLL", "pD", "LD"}; - for (size_t iBin = 0; iBin < eventTitles.size(); iBin++) { - registry.get(HIST("fProcessedEvents"))->GetXaxis()->SetBinLabel(iBin + 1, eventTitles[iBin].data()); + // setup strangeness builder + mStraHelper.v0selections.minCrossedRows = V0BuilderOpts.minCrossedRows.value; + mStraHelper.v0selections.dcanegtopv = V0BuilderOpts.dcanegtopv.value; + mStraHelper.v0selections.dcapostopv = V0BuilderOpts.dcapostopv.value; + mStraHelper.v0selections.v0cospa = V0BuilderOpts.v0cospa.value; + mStraHelper.v0selections.dcav0dau = V0BuilderOpts.dcav0dau.value; + mStraHelper.v0selections.v0radius = V0BuilderOpts.v0radius.value; + mStraHelper.v0selections.maxDaughterEta = V0BuilderOpts.maxDaughterEta.value; + + mStraHelper.fitter.setPropagateToPCA(FitterOpts.propagateToPCA.value); + mStraHelper.fitter.setMaxR(FitterOpts.maxR.value); + mStraHelper.fitter.setMinParamChange(FitterOpts.minParamChange.value); + mStraHelper.fitter.setMinRelChi2Change(FitterOpts.minRelChi2Change.value); + mStraHelper.fitter.setMaxDZIni(FitterOpts.maxDzIni.value); + mStraHelper.fitter.setMaxDXYIni(FitterOpts.maxDxyIni.value); + mStraHelper.fitter.setMaxChi2(FitterOpts.maxChi2.value); + mStraHelper.fitter.setUseAbsDCA(FitterOpts.useAbsDCA.value); + mStraHelper.fitter.setWeightedFinalPCA(FitterOpts.weightedFinalPCA.value); + + // setup histograms + int allTriggers = 2 * cf_trigger::nFilterNames; + int prossedEventsBins = 3 + allTriggers; + std::vector triggerTitles = {"ppp_LooseQ3", "ppp_TightQ3", + "ppL_LooseQ3", "ppL_TightQ3", + "pLL_LooseQ3", "pLL_TightQ3", + "LLL_LooseQ3", "LLL_TightQ3", + "ppPhi_LooseQ3", "ppPhi_TightQ3", + "ppRho_LooseQ3", "ppRho_TightQ3", + "pD_LooseKstar", "pD_TightKstar", + "LD_LooseKstar", "LD_TightKstar", + "PhiD_LooseKstar", "PhiD_TightKstar", + "RhoD_LooseKstar", "RhoD_TightKstar"}; + + registry.add("fProcessedEvents", "CF - event filtered;;Events", HistType::kTH1F, {{prossedEventsBins, -0.5, prossedEventsBins - 0.5}}); + registry.get(HIST("fProcessedEvents"))->GetXaxis()->SetBinLabel(1, "all"); + registry.get(HIST("fProcessedEvents"))->GetXaxis()->SetBinLabel(2, "accepted_loose"); + registry.get(HIST("fProcessedEvents"))->GetXaxis()->SetBinLabel(3, "accepted_tight"); + + registry.add("fTriggerCorrelations", "CF - Trigger correlations", HistType::kTH2F, {{allTriggers, -0.5, allTriggers - 0.5}, {allTriggers, -0.5, allTriggers - 0.5}}); + + for (size_t iBin = 0; iBin < triggerTitles.size(); iBin++) { + registry.get(HIST("fProcessedEvents"))->GetXaxis()->SetBinLabel(iBin + 4, triggerTitles[iBin].data()); // start triggers from 4th bin + registry.get(HIST("fTriggerCorrelations"))->GetXaxis()->SetBinLabel(iBin + 1, triggerTitles[iBin].data()); + registry.get(HIST("fTriggerCorrelations"))->GetYaxis()->SetBinLabel(iBin + 1, triggerTitles[iBin].data()); } // event cuts - registry.add("EventCuts/fMultiplicityBefore", "Multiplicity of all processed events;Mult;Entries", HistType::kTH1F, {{1000, 0, 1000}}); - registry.add("EventCuts/fMultiplicityAfter", "Multiplicity after event cuts;Mult;Entries", HistType::kTH1F, {{1000, 0, 1000}}); - registry.add("EventCuts/fZvtxBefore", "Zvtx of all processed events;Z_{vtx};Entries", HistType::kTH1F, {{1000, -15, 15}}); - registry.add("EventCuts/fZvtxAfter", "Zvtx after event cuts;Z_{vtx};Entries", HistType::kTH1F, {{1000, -15, 15}}); - - // mom correlations p vs pTPC - registry.add("TrackCuts/TracksBefore/fMomCorrelationPos", "fMomCorrelation;p (GeV/c);p_{TPC} (GeV/c)", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 20.0f}}}); - registry.add("TrackCuts/TracksBefore/fMomCorrelationAfterCutsPos", "fMomCorrelationAfterCuts;p (GeV/c);p_{TPC} (GeV/c)", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 20.0f}}}); - registry.add("TrackCuts/TracksBefore/fMomCorrelationNeg", "fMomCorrelation;p (GeV/c);p_{TPC} (GeV/c)", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 20.0f}}}); - registry.add("TrackCuts/TracksBefore/fMomCorrelationAfterCutsNeg", "fMomCorrelationAfterCuts;p (GeV/c);p_{TPC} (GeV/c)", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 20.0f}}}); - - registry.add("TrackCuts/TracksBefore/fMomCorrelationAfterCutsProton", "fMomCorrelation;p (GeV/c);p_{TPC} (GeV/c)", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 20.0f}}}); - registry.add("TrackCuts/TracksBefore/fMomCorrelationAfterCutsAntiProton", "fMomCorrelation;p (GeV/c);p_{TPC} (GeV/c)", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 20.0f}}}); - registry.add("TrackCuts/TracksBefore/fMomCorrelationAfterCutsDeuteron", "fMomCorrelation;p (GeV/c);p_{TPC} (GeV/c)", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 20.0f}}}); - registry.add("TrackCuts/TracksBefore/fMomCorrelationAfterCutsAntiDeuteron", "fMomCorrelation;p (GeV/c);p_{TPC} (GeV/c)", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 20.0f}}}); - - // all tracks - registry.add("TrackCuts/TracksBefore/fPtTrackBefore", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); - registry.add("TrackCuts/TracksBefore/fEtaTrackBefore", "Pseudorapidity of all processed tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); - registry.add("TrackCuts/TracksBefore/fPhiTrackBefore", "Azimuthal angle of all processed tracks;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); + registry.add("EventQA/Before/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registry.add("EventQA/Before/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + + registry.add("EventQA/After/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registry.add("EventQA/After/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + + // all tracks before cuts + registry.add("TrackQA/Before/Particle/fPt", "Transverse;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/Before/Particle/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("TrackQA/Before/Particle/fPhi", "Azimuthal;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registry.add("TrackQA/Before/Particle/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registry.add("TrackQA/Before/Particle/fItsSignal", "ITSSignal;p_{TPC} (GeV/c);ITS Signal", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registry.add("TrackQA/Before/Particle/fTpcSignal", "TPCSignal;p_{TPC} (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registry.add("TrackQA/Before/Particle/fTofSignal", "TOFSignal;p_{TPC} (GeV/c);TOF Signal", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registry.add("TrackQA/Before/AntiParticle/fPt", "Transverse momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/Before/AntiParticle/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("TrackQA/Before/AntiParticle/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registry.add("TrackQA/Before/AntiParticle/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registry.add("TrackQA/Before/AntiParticle/fItsSignal", "ITSSignal;p_{TPC} (GeV/c);ITS Signal", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registry.add("TrackQA/Before/AntiParticle/fTpcSignal", "TPCSignal;p_{TPC} (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registry.add("TrackQA/Before/AntiParticle/fTofSignal", "TOFSignal;p_{TPC} (GeV/c);TOF Signal", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); // PID vs momentum before cuts - registry.add("TrackCuts/NSigmaBefore/fNsigmaTPCvsPProtonBefore", "NSigmaTPC Proton Before;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/NSigmaBefore/fNsigmaTOFvsPProtonBefore", "NSigmaTOF Proton Before;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/NSigmaBefore/fNsigmaTPCTOFvsPProtonBefore", "NSigmaTPCTOF Proton Before;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); - registry.add("TrackCuts/NSigmaBefore/fNsigmaTPCvsPAntiProtonBefore", "NSigmaTPC AntiProton Before;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/NSigmaBefore/fNsigmaTOFvsPAntiProtonBefore", "NSigmaTOF AntiProton Before;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/NSigmaBefore/fNsigmaTPCTOFvsPAntiProtonBefore", "NSigmaTPCTOF AntiProton Before;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); - registry.add("TrackCuts/NSigmaBefore/fNsigmaTPCvsPDeuteronBefore", "NSigmaTPC Deuteron Before;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/NSigmaBefore/fNsigmaTOFvsPDeuteronBefore", "NSigmaTOF Deuteron Before;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/NSigmaBefore/fNsigmaTPCTOFvsPDeuteronBefore", "NSigmaTPCTOF Deuteron Before;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); - - registry.add("TrackCuts/NSigmaBefore/fNsigmaTPCvsPAntiDeuteronBefore", "NSigmaTPC AntiDeuteron Before;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/NSigmaBefore/fNsigmaTOFvsPAntiDeuteronBefore", "NSigmaTOF AntiDeuteron Before;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/NSigmaBefore/fNsigmaTPCTOFvsPAntiDeuteronBefore", "NSigmaTPCTOF AntiDeuteron Before;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); - - registry.add("TrackCuts/NSigmaBefore/fNsigmaTPCvsPDeuteronBeforeP", "NSigmaTPC Deuteron BeforeP;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/NSigmaBefore/fNsigmaTPCvsPAntiDeuteronBeforeP", "NSigmaTPC AntiDeuteron BeforeP;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - - // TPC signal - registry.add("TrackCuts/TPCSignal/fTPCSignal", "TPCSignal;p_{TPC} (GeV/c);dE/dx", {HistType::kTH2F, {{1000, 0.0f, 6.0f}, {2000, -100.f, 1000.f}}}); - registry.add("TrackCuts/TPCSignal/fTPCSignalP", "TPCSignalP;p (GeV/c);dE/dx", {HistType::kTH2F, {{1000, 0.0f, 6.0f}, {2000, -100.f, 1000.f}}}); - registry.add("TrackCuts/TPCSignal/fTPCSignalALLCUTS", "TPCSignalALLCUTS;p_{TPC} (GeV/c);dE/dx", {HistType::kTH2F, {{1000, 0.0f, 6.0f}, {2000, -100.f, 1000.f}}}); - registry.add("TrackCuts/TPCSignal/fTPCSignalALLCUTSP", "TPCSignalALLCUTSP;p (GeV/c);dE/dx", {HistType::kTH2F, {{1000, 0.0f, 6.0f}, {2000, -100.f, 1000.f}}}); - - // TPC signal anti - registry.add("TrackCuts/TPCSignal/fTPCSignalAnti", "TPCSignal;p_{TPC} (GeV/c);dE/dx", {HistType::kTH2F, {{1000, 0.0f, 6.0f}, {2000, -100.f, 1000.f}}}); - registry.add("TrackCuts/TPCSignal/fTPCSignalAntiP", "TPCSignalP;p (GeV/c);dE/dx", {HistType::kTH2F, {{1000, 0.0f, 6.0f}, {2000, -100.f, 1000.f}}}); - registry.add("TrackCuts/TPCSignal/fTPCSignalAntiALLCUTS", "TPCSignalALLCUTS;p_{TPC} (GeV/c);dE/dx", {HistType::kTH2F, {{1000, 0.0f, 6.0f}, {2000, -100.f, 1000.f}}}); - registry.add("TrackCuts/TPCSignal/fTPCSignalAntiALLCUTSP", "TPCSignalALLCUTSP;p(GeV/c);dE/dx", {HistType::kTH2F, {{1000, 0.0f, 6.0f}, {2000, -100.f, 1000.f}}}); - - // TPC signal particles - registry.add("TrackCuts/TPCSignal/fTPCSignalProton", "fTPCSignalProton;p_{TPC} (GeV/c);dE/dx", {HistType::kTH2F, {{1000, 0.0f, 6.0f}, {20000, -100.f, 1000.f}}}); - registry.add("TrackCuts/TPCSignal/fTPCSignalAntiProton", "fTPCSignalAntiProton;p_{TPC} (GeV/c);dE/dx", {HistType::kTH2F, {{1000, 0.0f, 6.0f}, {20000, -100.f, 1000.f}}}); - registry.add("TrackCuts/TPCSignal/fTPCSignalDeuteron", "fTPCSignalDeuteron;p_{TPC} (GeV/c);dE/dx", {HistType::kTH2F, {{1000, 0.0f, 6.0f}, {20000, -100.f, 1000.f}}}); - registry.add("TrackCuts/TPCSignal/fTPCSignalAntiDeuteron", "fTPCSignalAntiDeuteron;p_{TPC} (GeV/c);dE/dx", {HistType::kTH2F, {{1000, 0.0f, 6.0f}, {20000, -100.f, 1000.f}}}); - registry.add("TrackCuts/TPCSignal/fTPCSignalPionMinusV0Daughter", "fTPCSignalPionMinusV0Daughter;p_{TPC} (GeV/c);dE/dx", {HistType::kTH2F, {{1000, 0.0f, 6.0f}, {20000, -100.f, 1000.f}}}); - registry.add("TrackCuts/TPCSignal/fTPCSignalPionPlusV0Daughter", "fTPCSignalPionPlusV0Daughter;p_{TPC} (GeV/c);dE/dx", {HistType::kTH2F, {{1000, 0.0f, 6.0f}, {20000, -100.f, 1000.f}}}); - registry.add("TrackCuts/TPCSignal/fTPCSignalProtonMinusV0Daughter", "fTPCSignalProtonMinusV0Daughter;p_{TPC} (GeV/c);dE/dx", {HistType::kTH2F, {{1000, 0.0f, 6.0f}, {20000, -100.f, 1000.f}}}); - registry.add("TrackCuts/TPCSignal/fTPCSignalProtonPlusV0Daughter", "fTPCSignalProtonPlusV0Daughter;p_{TPC} (GeV/c);dE/dx", {HistType::kTH2F, {{1000, 0.0f, 6.0f}, {20000, -100.f, 1000.f}}}); - - // PID vs momentum before cuts daughters - registry.add("TrackCuts/NSigmaBefore/fNsigmaTPCvsPProtonV0DaughBefore", "NSigmaTPC Proton V0Daught Before;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/NSigmaBefore/fNsigmaTPCvsPPionMinusV0DaughBefore", "NSigmaTPC AntiPion V0Daught Before;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/NSigmaBefore/fNsigmaTPCvsPAntiProtonAntiV0DaughBefore", "NSigmaTPC AntiProton antiV0Daught Before;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/NSigmaBefore/fNsigmaTPCvsPPionPlusAntiV0DaughBefore", "NSigmaTPC Pion antiV0Daught Before;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + registry.add("TrackQA/Before/Pion/fNsigmaITS", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/Pion/fNsigmaTPC", "NSigmaTPC;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/Pion/fNsigmaTOF", "NSigmaTOF;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/Pion/fNsigmaTPCTOF", "NsigmaTPCTOF;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registry.add("TrackQA/Before/AntiPion/fNsigmaITS", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/AntiPion/fNsigmaTPC", "NSigmaTPC;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/AntiPion/fNsigmaTOF", "NSigmaTOF;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/AntiPion/fNsigmaTPCTOF", "NsigmaTPCTOF;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registry.add("TrackQA/Before/Kaon/fNsigmaITS", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/Kaon/fNsigmaTPC", "NSigmaTPC;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/Kaon/fNsigmaTOF", "NSigmaTOF;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/Kaon/fNsigmaTPCTOF", "NsigmaTPCTOF;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registry.add("TrackQA/Before/AntiKaon/fNsigmaITS", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/AntiKaon/fNsigmaTPC", "NSigmaTPC;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/AntiKaon/fNsigmaTOF", "NSigmaTOF;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/AntiKaon/fNsigmaTPCTOF", "NsigmaTPCTOF;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registry.add("TrackQA/Before/Proton/fNsigmaITS", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/Proton/fNsigmaTPC", "NSigmaTPC;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/Proton/fNsigmaTOF", "NSigmaTOF;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/Proton/fNsigmaTPCTOF", "NsigmaTPCTOF;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registry.add("TrackQA/Before/AntiProton/fNsigmaITS", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/AntiProton/fNsigmaTPC", "NSigmaTPC;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/AntiProton/fNsigmaTOF", "NSigmaTOF;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/AntiProton/fNsigmaTPCTOF", "NsigmaTPCTOF;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registry.add("TrackQA/Before/Deuteron/fNsigmaITS", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/Deuteron/fNsigmaTPC", "NSigmaTPC;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/Deuteron/fNsigmaTOF", "NSigmaTOF;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/Deuteron/fNsigmaTPCTOF", "NsigmaTPCTOF;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registry.add("TrackQA/Before/AntiDeuteron/fNsigmaITS", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/AntiDeuteron/fNsigmaTPC", "NSigmaTPC;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/AntiDeuteron/fNsigmaTOF", "NSigmaTOF;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/Before/AntiDeuteron/fNsigmaTPCTOF", "NsigmaTPCTOF;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + // Pion + registry.add("TrackQA/After/Pion/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/After/Pion/fPTpc", "Momentum at TPC inner wall;p_{TPC} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/After/Pion/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registry.add("TrackQA/After/Pion/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("TrackQA/After/Pion/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + registry.add("TrackQA/After/Pion/fNsigmaIts", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/Pion/fNsigmaTpc", "NSigmaTPC;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/Pion/fNsigmaTof", "NSigmaTOF;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/Pion/fNsigmaTpcTof", "NSigmaTPCTOF;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registry.add("TrackQA/After/Pion/fItsSignal", "ITS Signal;p (GeV/c); (cm)", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registry.add("TrackQA/After/Pion/fTpcSignal", "TPC Signal;p (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registry.add("TrackQA/After/Pion/fTofBeta", "TOF #beta;p (GeV/c);#beta_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registry.add("TrackQA/After/Pion/fDcaXy", "DCA_{xy};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registry.add("TrackQA/After/Pion/fDcaZ", "DCA_{z};p_{T} (GeV/c); DCA_{Z};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + + registry.add("TrackQA/After/Pion/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/Pion/fTpcCrossedRows", "TPC Crossed Rows;TPC Crossed Rows;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/Pion/fTpcSharedClusters", "TPC Shared Clusters;TPC Shared Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/Pion/fTpcSharedClusterOverClusterss", "TPC Shared Clusters/Clusters;TPC Shared Clusters/Clusters;Entries", HistType::kTH1F, {Binning.ratio}); + registry.add("TrackQA/After/Pion/fTpcFindableOverRows", "TPC Findabled/Crossed Rows;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {Binning.ratio}); + registry.add("TrackQA/After/Pion/fTpcChi2OverCluster", "TPC #chi^{2}/Cluster;TPC #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.tpcChi2}); + + registry.add("TrackQA/After/Pion/fItsClusters", "ITS Clusters;ITS Clusters;Entries", HistType::kTH1F, {Binning.itsCluster}); + registry.add("TrackQA/After/Pion/fItsIbClusters", "ITS Inner Barrel Clusters;ITS Inner Barrel Clusters;Entries", HistType::kTH1F, {Binning.itsIbCluster}); + registry.add("TrackQA/After/Pion/fItsChi2OverCluster", "ITS #chi^{2}/Cluster;ITS #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.itsChi2}); + + // antiPion + registry.add("TrackQA/After/AntiPion/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/After/AntiPion/fPTpc", "Momentum at TPC inner wall;p_{TPC} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/After/AntiPion/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registry.add("TrackQA/After/AntiPion/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("TrackQA/After/AntiPion/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + registry.add("TrackQA/After/AntiPion/fNsigmaIts", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/AntiPion/fNsigmaTpc", "NSigmaTPC;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/AntiPion/fNsigmaTof", "NSigmaTOF;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/AntiPion/fNsigmaTpcTof", "NSigmaTPCTOF;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registry.add("TrackQA/After/AntiPion/fItsSignal", "ITS Signal;p (GeV/c); (cm)", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registry.add("TrackQA/After/AntiPion/fTpcSignal", "TPC Signal;p (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registry.add("TrackQA/After/AntiPion/fTofBeta", "TOF #beta;p (GeV/c);#beta_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registry.add("TrackQA/After/AntiPion/fDcaXy", "DCA_{xy};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registry.add("TrackQA/After/AntiPion/fDcaZ", "DCA_{z};p_{T} (GeV/c); DCA_{Z};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + + registry.add("TrackQA/After/AntiPion/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/AntiPion/fTpcCrossedRows", "TPC Crossed Rows;TPC Crossed Rows;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/AntiPion/fTpcSharedClusters", "TPC Shared Clusters;TPC Shared Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/AntiPion/fTpcSharedClusterOverClusterss", "TPC Shared Clusters/Clusters;TPC Shared Clusters/Clusters;Entries", HistType::kTH1F, {Binning.ratio}); + registry.add("TrackQA/After/AntiPion/fTpcFindableOverRows", "TPC Findabled/Crossed Rows;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {Binning.ratio}); + registry.add("TrackQA/After/AntiPion/fTpcChi2OverCluster", "TPC #chi^{2}/Cluster;TPC #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.tpcChi2}); + + registry.add("TrackQA/After/AntiPion/fItsClusters", "ITS Clusters;ITS Clusters;Entries", HistType::kTH1F, {Binning.itsCluster}); + registry.add("TrackQA/After/AntiPion/fItsIbClusters", "ITS Inner Barrel Clusters;ITS Inner Barrel Clusters;Entries", HistType::kTH1F, {Binning.itsIbCluster}); + registry.add("TrackQA/After/AntiPion/fItsChi2OverCluster", "ITS #chi^{2}/Cluster;ITS #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.itsChi2}); + + // Kaon + registry.add("TrackQA/After/Kaon/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/After/Kaon/fPTpc", "Momentum at TPC inner wall;p_{TPC} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/After/Kaon/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registry.add("TrackQA/After/Kaon/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("TrackQA/After/Kaon/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + registry.add("TrackQA/After/Kaon/fNsigmaIts", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/Kaon/fNsigmaTpc", "NSigmaTPC;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/Kaon/fNsigmaTof", "NSigmaTOF;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/Kaon/fNsigmaTpcTof", "NSigmaTPCTOF;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registry.add("TrackQA/After/Kaon/fItsSignal", "ITS Signal;p (GeV/c); (cm)", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registry.add("TrackQA/After/Kaon/fTpcSignal", "TPC Signal;p (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registry.add("TrackQA/After/Kaon/fTofBeta", "TOF #beta;p (GeV/c);#beta_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registry.add("TrackQA/After/Kaon/fDcaXy", "DCA_{xy};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registry.add("TrackQA/After/Kaon/fDcaZ", "DCA_{z};p_{T} (GeV/c); DCA_{Z};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + + registry.add("TrackQA/After/Kaon/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/Kaon/fTpcCrossedRows", "TPC Crossed Rows;TPC Crossed Rows;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/Kaon/fTpcSharedClusters", "TPC Shared Clusters;TPC Shared Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/Kaon/fTpcSharedClusterOverClusterss", "TPC Shared Clusters/Clusters;TPC Shared Clusters/Clusters;Entries", HistType::kTH1F, {Binning.ratio}); + registry.add("TrackQA/After/Kaon/fTpcFindableOverRows", "TPC Findabled/Crossed Rows;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {Binning.ratio}); + registry.add("TrackQA/After/Kaon/fTpcChi2OverCluster", "TPC #chi^{2}/Cluster;TPC #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.tpcChi2}); + + registry.add("TrackQA/After/Kaon/fItsClusters", "ITS Clusters;ITS Clusters;Entries", HistType::kTH1F, {Binning.itsCluster}); + registry.add("TrackQA/After/Kaon/fItsIbClusters", "ITS Inner Barrel Clusters;ITS Inner Barrel Clusters;Entries", HistType::kTH1F, {Binning.itsIbCluster}); + registry.add("TrackQA/After/Kaon/fItsChi2OverCluster", "ITS #chi^{2}/Cluster;ITS #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.itsChi2}); + + // antiKaon + registry.add("TrackQA/After/AntiKaon/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/After/AntiKaon/fPTpc", "Momentum at TPC inner wall;p_{TPC} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/After/AntiKaon/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registry.add("TrackQA/After/AntiKaon/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("TrackQA/After/AntiKaon/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + registry.add("TrackQA/After/AntiKaon/fNsigmaIts", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/AntiKaon/fNsigmaTpc", "NSigmaTPC;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/AntiKaon/fNsigmaTof", "NSigmaTOF;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/AntiKaon/fNsigmaTpcTof", "NSigmaTPCTOF;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registry.add("TrackQA/After/AntiKaon/fItsSignal", "ITS Signal;p (GeV/c); (cm)", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registry.add("TrackQA/After/AntiKaon/fTpcSignal", "TPC Signal;p (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registry.add("TrackQA/After/AntiKaon/fTofBeta", "TOF #beta;p (GeV/c);#beta_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registry.add("TrackQA/After/AntiKaon/fDcaXy", "DCA_{xy};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registry.add("TrackQA/After/AntiKaon/fDcaZ", "DCA_{z};p_{T} (GeV/c); DCA_{Z};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + + registry.add("TrackQA/After/AntiKaon/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/AntiKaon/fTpcCrossedRows", "TPC Crossed Rows;TPC Crossed Rows;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/AntiKaon/fTpcSharedClusters", "TPC Shared Clusters;TPC Shared Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/AntiKaon/fTpcSharedClusterOverClusterss", "TPC Shared Clusters/Clusters;TPC Shared Clusters/Clusters;Entries", HistType::kTH1F, {Binning.ratio}); + registry.add("TrackQA/After/AntiKaon/fTpcFindableOverRows", "TPC Findabled/Crossed Rows;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {Binning.ratio}); + registry.add("TrackQA/After/AntiKaon/fTpcChi2OverCluster", "TPC #chi^{2}/Cluster;TPC #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.tpcChi2}); + + registry.add("TrackQA/After/AntiKaon/fItsClusters", "ITS Clusters;ITS Clusters;Entries", HistType::kTH1F, {Binning.itsCluster}); + registry.add("TrackQA/After/AntiKaon/fItsIbClusters", "ITS Inner Barrel Clusters;ITS Inner Barrel Clusters;Entries", HistType::kTH1F, {Binning.itsIbCluster}); + registry.add("TrackQA/After/AntiKaon/fItsChi2OverCluster", "ITS #chi^{2}/Cluster;ITS #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.itsChi2}); // proton - // TEST P TPC - registry.add("TrackCuts/Proton/fPProton", "Momentum of protons at PV;p (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); - registry.add("TrackCuts/Proton/fPTPCProton", "Momentum of protons at TPC inner wall;p_{TPC} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); - registry.add("TrackCuts/Proton/fPtProton", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); - registry.add("TrackCuts/Proton/fMomCorProtonDif", "Momentum correlation;p_{reco} (GeV/c); (p_{TPC} - p_{reco}) (GeV/c)", {HistType::kTH2F, {{500, 0, 10}, {600, -3, 3}}}); - registry.add("TrackCuts/Proton/fMomCorProtonRatio", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {{500, 0, 10}, {200, -1, 1}}}); - registry.add("TrackCuts/Proton/fEtaProton", "Pseudorapidity of all processed tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); - registry.add("TrackCuts/Proton/fPhiProton", "Azimuthal angle of all processed tracks;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); - registry.add("TrackCuts/Proton/fNsigmaTPCvsPProton", "NSigmaTPC Proton;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/Proton/fNsigmaTOFvsPProton", "NSigmaTOF Proton;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/Proton/fNsigmaTPCTOFvsPProton", "NSigmaTPCTOF Proton;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); - - registry.add("TrackCuts/Proton/fNsigmaTPCvsPProtonP", "NSigmaTPC Proton P;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/Proton/fNsigmaTOFvsPProtonP", "NSigmaTOF Proton P;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/Proton/fNsigmaTPCTOFvsPProtonP", "NSigmaTPCTOF Proton P;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); - - registry.add("TrackCuts/Proton/fDCAxyProton", "fDCAxy Proton;DCA_{XY};Entries", HistType::kTH1F, {{500, -0.5f, 0.5f}}); - registry.add("TrackCuts/Proton/fDCAzProton", "fDCAz Proton;DCA_{Z};Entries", HistType::kTH1F, {{500, -0.5f, 0.5f}}); - registry.add("TrackCuts/Proton/fTPCsClsProton", "fTPCsCls Proton;TPC Shared Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); - registry.add("TrackCuts/Proton/fTPCcRowsProton", "fTPCcRows Proton;TPC Crossed Rows;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); - registry.add("TrackCuts/Proton/fTrkTPCfClsProton", "fTrkTPCfCls Proton;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {{500, 0.0f, 3.0f}}); - registry.add("TrackCuts/Proton/fTPCnclsProton", "fTPCncls Proton;TPC Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); + registry.add("TrackQA/After/Proton/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/After/Proton/fPTpc", "Momentum at TPC inner wall;p_{TPC} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/After/Proton/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registry.add("TrackQA/After/Proton/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("TrackQA/After/Proton/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + registry.add("TrackQA/After/Proton/fNsigmaIts", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/Proton/fNsigmaTpc", "NSigmaTPC;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/Proton/fNsigmaTof", "NSigmaTOF;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/Proton/fNsigmaTpcTof", "NSigmaTPCTOF;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registry.add("TrackQA/After/Proton/fItsSignal", "ITS Signal;p (GeV/c); (cm)", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registry.add("TrackQA/After/Proton/fTpcSignal", "TPC Signal;p (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registry.add("TrackQA/After/Proton/fTofBeta", "TOF #beta;p (GeV/c);#beta_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registry.add("TrackQA/After/Proton/fDcaXy", "DCA_{xy};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registry.add("TrackQA/After/Proton/fDcaZ", "DCA_{z};p_{T} (GeV/c); DCA_{Z};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + + registry.add("TrackQA/After/Proton/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/Proton/fTpcCrossedRows", "TPC Crossed Rows;TPC Crossed Rows;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/Proton/fTpcSharedClusters", "TPC Shared Clusters;TPC Shared Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/Proton/fTpcSharedClusterOverClusterss", "TPC Shared Clusters/Clusters;TPC Shared Clusters/Clusters;Entries", HistType::kTH1F, {Binning.ratio}); + registry.add("TrackQA/After/Proton/fTpcFindableOverRows", "TPC Findabled/Crossed Rows;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {Binning.ratio}); + registry.add("TrackQA/After/Proton/fTpcChi2OverCluster", "TPC #chi^{2}/Cluster;TPC #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.tpcChi2}); + + registry.add("TrackQA/After/Proton/fItsClusters", "ITS Clusters;ITS Clusters;Entries", HistType::kTH1F, {Binning.itsCluster}); + registry.add("TrackQA/After/Proton/fItsIbClusters", "ITS Inner Barrel Clusters;ITS Inner Barrel Clusters;Entries", HistType::kTH1F, {Binning.itsIbCluster}); + registry.add("TrackQA/After/Proton/fItsChi2OverCluster", "ITS #chi^{2}/Cluster;ITS #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.itsChi2}); // antiproton - registry.add("TrackCuts/AntiProton/fPtAntiProton", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); - registry.add("TrackCuts/AntiProton/fMomCorAntiProtonDif", "Momentum correlation;p_{reco} (GeV/c); (p_{TPC} - p_{reco}) (GeV/c)", {HistType::kTH2F, {{500, 0, 10}, {600, -3, 3}}}); - registry.add("TrackCuts/AntiProton/fMomCorAntiProtonRatio", "Momentum correlation;p_{reco} (GeV/c); |p_{TPC} - p_{reco}| (GeV/c)", {HistType::kTH2F, {{500, 0, 10}, {200, -1, 1}}}); - registry.add("TrackCuts/AntiProton/fEtaAntiProton", "Pseudorapidity of all processed tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); - registry.add("TrackCuts/AntiProton/fPhiAntiProton", "Azimuthal angle of all processed tracks;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); - registry.add("TrackCuts/AntiProton/fNsigmaTPCvsPAntiProton", "NSigmaTPC AntiProton;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/AntiProton/fNsigmaTOFvsPAntiProton", "NSigmaTOF AntiProton;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/AntiProton/fNsigmaTPCTOFvsPAntiProton", "NSigmaTPCTOF AntiProton;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); - - registry.add("TrackCuts/AntiProton/fNsigmaTPCvsPAntiProtonP", "NSigmaTPC AntiProton P;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/AntiProton/fNsigmaTOFvsPAntiProtonP", "NSigmaTOF AntiProton P;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/AntiProton/fNsigmaTPCTOFvsPAntiProtonP", "NSigmaTPCTOF AntiProton P;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); - - registry.add("TrackCuts/AntiProton/fDCAxyAntiProton", "fDCAxy AntiProton;DCA_{XY};Entries", HistType::kTH1F, {{500, -0.5f, 0.5f}}); - registry.add("TrackCuts/AntiProton/fDCAzAntiProton", "fDCAz AntiProton;DCA_{Z};Entries", HistType::kTH1F, {{500, -0.5f, 0.5f}}); - registry.add("TrackCuts/AntiProton/fTPCsClsAntiProton", "fTPCsCls AntiProton;TPC Shared Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); - registry.add("TrackCuts/AntiProton/fTPCcRowsAntiProton", "fTPCcRows AntiProton;TPC Crossed Rows;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); - registry.add("TrackCuts/AntiProton/fTrkTPCfClsAntiProton", "fTrkTPCfCls AntiProton;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {{500, 0.0f, 3.0f}}); - registry.add("TrackCuts/AntiProton/fTPCnclsAntiProton", "fTPCncls AntiProton;TPC Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); - - // deuteron - registry.add("TrackCuts/Deuteron/fPtDeuteron", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); - registry.add("TrackCuts/Deuteron/fMomCorDeuteronDif", "Momentum correlation;p_{reco} (GeV/c); (p_{TPC} - p_{reco}) (GeV/c)", {HistType::kTH2F, {{500, 0, 10}, {600, -3, 3}}}); - registry.add("TrackCuts/Deuteron/fMomCorDeuteronRatio", "Momentum correlation;p_{reco} (GeV/c); |p_{TPC} - p_{reco}| (GeV/c)", {HistType::kTH2F, {{500, 0, 10}, {200, -1, 1}}}); - registry.add("TrackCuts/Deuteron/fEtaDeuteron", "Pseudorapidity of all processed tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); - registry.add("TrackCuts/Deuteron/fPhiDeuteron", "Azimuthal angle of all processed tracks;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); - registry.add("TrackCuts/Deuteron/fNsigmaTPCvsPDeuteron", "NSigmaTPC Deuteron;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/Deuteron/fNsigmaTOFvsPDeuteron", "NSigmaTOF Deuteron;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/Deuteron/fNsigmaTPCTOFvsPDeuteron", "NSigmaTPCTOF Deuteron;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); - - registry.add("TrackCuts/Deuteron/fNsigmaTPCvsPDeuteronP", "NSigmaTPC Deuteron vd P;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/Deuteron/fNsigmaTOFvsPDeuteronP", "NSigmaTOF Deuteron P;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/Deuteron/fNsigmaTPCTOFvsPDeuteronP", "NSigmaTPCTOF Deuteron P;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); - - registry.add("TrackCuts/Deuteron/fDCAxyDeuteron", "fDCAxy Deuteron;DCA_{XY};Entries", HistType::kTH1F, {{500, -0.5f, 0.5f}}); - registry.add("TrackCuts/Deuteron/fDCAzDeuteron", "fDCAz Deuteron;DCA_{Z};Entries", HistType::kTH1F, {{500, -0.5f, 0.5f}}); - registry.add("TrackCuts/Deuteron/fTPCsClsDeuteron", "fTPCsCls Deuteron;TPC Shared Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); - registry.add("TrackCuts/Deuteron/fTPCcRowsDeuteron", "fTPCcRows Deuteron;TPC Crossed Rows;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); - registry.add("TrackCuts/Deuteron/fTrkTPCfClsDeuteron", "fTrkTPCfCls Deuteron;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {{500, 0.0f, 3.0f}}); - registry.add("TrackCuts/Deuteron/fTPCnclsDeuteron", "fTPCncls Deuteron;TPC Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); - - // antideuteron - registry.add("TrackCuts/AntiDeuteron/fPtAntiDeuteron", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); - registry.add("TrackCuts/AntiDeuteron/fMomCorAntiDeuteronDif", "Momentum correlation;p_{reco} (GeV/c); (p_{TPC} - p_{reco}) (GeV/c)", {HistType::kTH2F, {{500, 0, 10}, {600, -3, 3}}}); - registry.add("TrackCuts/AntiDeuteron/fMomCorAntiDeuteronRatio", "Momentum correlation;p_{reco} (GeV/c); (p_{TPC} - p_{reco}) (GeV/c)", {HistType::kTH2F, {{500, 0, 10}, {200, -1, 1}}}); - registry.add("TrackCuts/AntiDeuteron/fEtaAntiDeuteron", "Pseudorapidity of all processed tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); - registry.add("TrackCuts/AntiDeuteron/fPhiAntiDeuteron", "Azimuthal angle of all processed tracks;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); - registry.add("TrackCuts/AntiDeuteron/fNsigmaTPCvsPAntiDeuteron", "NSigmaTPC AntiDeuteron;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/AntiDeuteron/fNsigmaTOFvsPAntiDeuteron", "NSigmaTOF AntiDeuteron;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/AntiDeuteron/fNsigmaTPCTOFvsPAntiDeuteron", "NSigmaTPCTOF AntiDeuteron;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); - - registry.add("TrackCuts/AntiDeuteron/fNsigmaTPCvsPAntiDeuteronP", "NSigmaTPC AntiDeuteron vd P;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/AntiDeuteron/fNsigmaTOFvsPAntiDeuteronP", "NSigmaTOF AntiDeuteron P;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/AntiDeuteron/fNsigmaTPCTOFvsPAntiDeuteronP", "NSigmaTPCTOF AntiDeuteron P;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); - - registry.add("TrackCuts/AntiDeuteron/fDCAxyAntiDeuteron", "fDCAxy AntiDeuteron;DCA_{XY};Entries", HistType::kTH1F, {{500, -0.5f, 0.5f}}); - registry.add("TrackCuts/AntiDeuteron/fDCAzAntiDeuteron", "fDCAz AntiDeuteron;DCA_{Z};Entries", HistType::kTH1F, {{500, -0.5f, 0.5f}}); - registry.add("TrackCuts/AntiDeuteron/fTPCsClsAntiDeuteron", "fTPCsCls AntiDeuteron;TPC Shared Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); - registry.add("TrackCuts/AntiDeuteron/fTPCcRowsAntiDeuteron", "fTPCcRows AntiDeuteron;TPC Crossed Rows;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); - registry.add("TrackCuts/AntiDeuteron/fTrkTPCfClsAntiDeuteron", "fTrkTPCfCls AntiDeuteron;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {{500, 0.0f, 3.0f}}); - registry.add("TrackCuts/AntiDeuteron/fTPCnclsAntiDeuteron", "fTPCncls AntiDeuteron;TPC Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); - - // lambda before selections - registry.add("TrackCuts/V0Before/fInvMassLambdavsAntiLambda", "Invariant mass of Lambda vs AntiLambda;M_{#pi p};Entries", HistType::kTH2F, {{1000, 1.03, 1.5}, {1000, 1.03, 1.5}}); - registry.add("TrackCuts/V0Before/fPtLambdaBefore", "Transverse momentum of all processed V0s before cuts;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); - registry.add("TrackCuts/V0Before/fInvMassLambdaBefore", "Invariant mass of all processed V0s (Lambda) before cuts;M_{#pi p};Entries", HistType::kTH1F, {{1000, 1.03, 1.5}}); - registry.add("TrackCuts/V0Before/fInvMassAntiLambdaBefore", "Invariant mass of all processed V0s (antiLambda) before cuts;M_{#pi p};Entries", HistType::kTH1F, {{1000, 1.03, 1.5}}); - registry.add("TrackCuts/V0Before/fInvMassV0BeforeKaonvsV0Before", "Invariant mass of rejected K0 vs V0s (V0Before);M_{#pi p};;M_{#pi #pi}", HistType::kTH2F, {{1000, 1.03, 1.5}, {1000, 0.3, 0.6}}); - registry.add("TrackCuts/V0Before/fV0DCADaugh", "V0DCADaugh;DCA_{daugh};Entries", HistType::kTH1F, {{1000, -4, 4}}); - registry.add("TrackCuts/V0Before/fV0CPA", "V0 CPA;CPA;Entries", HistType::kTH1F, {{1000, 0.7, 1}}); - registry.add("TrackCuts/V0Before/fV0TranRad", "V0 TranRad;TranRad;Entries", HistType::kTH1F, {{1000, 0, 150}}); - registry.add("TrackCuts/V0Before/f0DecVtxX", "V0 DecVtxX;DecVtX;Entries", HistType::kTH1F, {{1000, 0, 150}}); - registry.add("TrackCuts/V0Before/f0DecVtxY", "V0 DecVtxY;DecVtY;Entries", HistType::kTH1F, {{1000, 0, 150}}); - registry.add("TrackCuts/V0Before/f0DecVtxZ", "V0 DecVtxZ;DecVtz;Entries", HistType::kTH1F, {{1000, 0, 150}}); - - registry.add("TrackCuts/V0Before/PosDaughter/Eta", "V0Before Pos Daugh Eta;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); - registry.add("TrackCuts/V0Before/PosDaughter/DCAXY", "V0Before Pos Daugh DCAXY;DCA_{XY};Entries", HistType::kTH1F, {{1000, -2.5f, 2.5f}}); - registry.add("TrackCuts/V0Before/PosDaughter/fTPCncls", "V0Before Pos Daugh TPCncls;TPC Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); - registry.add("TrackCuts/V0Before/NegDaughter/Eta", "V0Before Neg Daugh Eta;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); - registry.add("TrackCuts/V0Before/NegDaughter/DCAXY", "V0Before Neg Daugh DCAXY;DCA_{XY};Entries", HistType::kTH1F, {{1000, -2.5f, 2.5f}}); - registry.add("TrackCuts/V0Before/NegDaughter/fTPCncls", "V0Before Neg Daugh TPCncls;TPC Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); - registry.add("TrackCuts/V0Before/PosDaughter/fNsigmaTPCvsPProtonV0Daugh", "NSigmaTPC Proton V0Daught;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/V0Before/NegDaughter/fNsigmaTPCvsPPionMinusV0Daugh", "NSigmaTPC AntiPion V0Daught;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/V0Before/NegDaughter/fNsigmaTPCvsPAntiProtonV0Daugh", "NSigmaTPC Proton V0Daught;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/V0Before/PosDaughter/fNsigmaTPCvsPPionPlusV0Daugh", "NSigmaTPC AntiPion V0Daught;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - - // lambda - registry.add("TrackCuts/Lambda/fPtLambda", "Transverse momentum V0s;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); - registry.add("TrackCuts/Lambda/fInvMassLambda", "Invariant mass V0s (Lambda);M_{#pi p};Entries", HistType::kTH1F, {{1000, 1.03, 1.5}}); - registry.add("TrackCuts/Lambda/fInvMassLambdaKaonvsLambda", "Invariant mass of rejected K0 vs V0s (Lambda);M_{#pi p};M_{#pi #pi}", HistType::kTH2F, {{1000, 1.03, 1.5}, {1000, 0.3, 0.6}}); - registry.add("TrackCuts/Lambda/fV0DCADaugh", "V0DCADaugh;DCA_{daugh};Entries", HistType::kTH1F, {{1000, -4, 4}}); - registry.add("TrackCuts/Lambda/fV0CPA", "V0 CPA;CPA;Entries", HistType::kTH1F, {{1000, 0.7, 1}}); - registry.add("TrackCuts/Lambda/fV0TranRad", "V0 TranRad;TranRad;Entries", HistType::kTH1F, {{1000, 0, 150}}); - registry.add("TrackCuts/Lambda/f0DecVtxX", "V0 DecVtxX;DecVtX;Entries", HistType::kTH1F, {{1000, 0, 150}}); - registry.add("TrackCuts/Lambda/f0DecVtxY", "V0 DecVtxY;DecVtY;Entries", HistType::kTH1F, {{1000, 0, 150}}); - registry.add("TrackCuts/Lambda/f0DecVtxZ", "V0 DecVtxZ;DecVtZ;Entries", HistType::kTH1F, {{1000, 0, 150}}); - - // Lambda daughter - registry.add("TrackCuts/Lambda/PosDaughter/Eta", "Lambda Pos Daugh Eta;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); - registry.add("TrackCuts/Lambda/PosDaughter/DCAXY", "Lambda Pos Daugh DCAXY;DCA_{XY};Entries", HistType::kTH1F, {{1000, -2.5f, 2.5f}}); - registry.add("TrackCuts/Lambda/PosDaughter/fTPCncls", "Lambda Pos Daugh TPCncls;TPC Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); - registry.add("TrackCuts/Lambda/NegDaughter/Eta", "Lambda Neg Daugh Eta;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); - registry.add("TrackCuts/Lambda/NegDaughter/DCAXY", "Lambda Neg Daugh DCAXY;DCA_{XY};Entries", HistType::kTH1F, {{1000, -2.5f, 2.5f}}); - registry.add("TrackCuts/Lambda/NegDaughter/fTPCncls", "Lambda Neg Daugh TPCncls;TPC Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); - registry.add("TrackCuts/Lambda/PosDaughter/fNsigmaTPCvsPProtonV0Daugh", "NSigmaTPC Proton V0Daught;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/Lambda/NegDaughter/fNsigmaTPCvsPPionMinusV0Daugh", "NSigmaTPC AntiPion V0Daught;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - - // antilambda - registry.add("TrackCuts/AntiLambda/fPtAntiLambda", "Transverse momentum V0s;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); - registry.add("TrackCuts/AntiLambda/fInvMassAntiLambda", "Invariant mass V0s (Lambda);M_{#pi p};Entries", HistType::kTH1F, {{1000, 1.03, 1.5}}); - registry.add("TrackCuts/AntiLambda/fInvMassAntiLambdaKaonvsAntiLambda", "Invariant mass of rejected K0 vs V0s (Lambda);M_{#pi p};M_{#pi #pi}", HistType::kTH2F, {{1000, 1.03, 1.5}, {1000, 0.3, 0.6}}); - registry.add("TrackCuts/AntiLambda/fV0DCADaugh", "V0DCADaugh;DCA_{daugh};Entries", HistType::kTH1F, {{1000, -4, 4}}); - registry.add("TrackCuts/AntiLambda/fV0CPA", "V0 CPA;CPA;Entries", HistType::kTH1F, {{1000, 0.7, 1}}); - registry.add("TrackCuts/AntiLambda/fV0TranRad", "V0 TranRad;TranRad;Entries", HistType::kTH1F, {{1000, 0, 150}}); - registry.add("TrackCuts/AntiLambda/f0DecVtxX", "V0 DecVtxX;DecVtX;Entries", HistType::kTH1F, {{1000, 0, 150}}); - registry.add("TrackCuts/AntiLambda/f0DecVtxY", "V0 DecVtxY;DecVtY;Entries", HistType::kTH1F, {{1000, 0, 150}}); - registry.add("TrackCuts/AntiLambda/f0DecVtxZ", "V0 DecVtxZ;DecVtZ;Entries", HistType::kTH1F, {{1000, 0, 150}}); - - // AntiLambda daughter - registry.add("TrackCuts/AntiLambda/PosDaughter/Eta", "AntiLambda Pos Daugh Eta;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); - registry.add("TrackCuts/AntiLambda/PosDaughter/DCAXY", "AntiLambda Pos Daugh DCAXY;DCA_{XY};Entries", HistType::kTH1F, {{1000, -2.5f, 2.5f}}); - registry.add("TrackCuts/AntiLambda/PosDaughter/fTPCncls", "AntiLambda Pos Daugh TPCncls;TPC Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); - registry.add("TrackCuts/AntiLambda/NegDaughter/Eta", "AntiLambda Neg Daugh Eta;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); - registry.add("TrackCuts/AntiLambda/NegDaughter/DCAXY", "AntiLambda Neg Daugh DCAXY;DCA_{XY};Entries", HistType::kTH1F, {{1000, -2.5f, 2.5f}}); - registry.add("TrackCuts/AntiLambda/NegDaughter/fTPCncls", "AntiLambda Neg Daugh TPCncls;TPC Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); - registry.add("TrackCuts/AntiLambda/NegDaughter/fNsigmaTPCvsPAntiProtonAntiV0Daugh", "NSigmaTPC AntiProton antiV0Daught;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/AntiLambda/PosDaughter/fNsigmaTPCvsPPionPlusAntiV0Daugh", "NSigmaTPC Pion antiV0Daught;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + registry.add("TrackQA/After/AntiProton/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/After/AntiProton/fPTpc", "Momentum at TPC inner wall;p_{TPC} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/After/AntiProton/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registry.add("TrackQA/After/AntiProton/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("TrackQA/After/AntiProton/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + registry.add("TrackQA/After/AntiProton/fNsigmaIts", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/AntiProton/fNsigmaTpc", "NSigmaTPC;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/AntiProton/fNsigmaTof", "NSigmaTOF;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/AntiProton/fNsigmaTpcTof", "NSigmaTPCTOF;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registry.add("TrackQA/After/AntiProton/fItsSignal", "ITS Signal;p (GeV/c); (cm)", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registry.add("TrackQA/After/AntiProton/fTpcSignal", "TPC Signal;p (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registry.add("TrackQA/After/AntiProton/fTofBeta", "TOF #beta;p (GeV/c);#beta_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registry.add("TrackQA/After/AntiProton/fDcaXy", "DCA_{xy};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registry.add("TrackQA/After/AntiProton/fDcaZ", "DCA_{z};p_{T} (GeV/c); DCA_{Z};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + + registry.add("TrackQA/After/AntiProton/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/AntiProton/fTpcCrossedRows", "TPC Crossed Rows;TPC Crossed Rows;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/AntiProton/fTpcSharedClusters", "TPC Shared Clusters;TPC Shared Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/AntiProton/fTpcSharedClusterOverClusterss", "TPC Shared Clusters/Clusters;TPC Shared Clusters/Clusters;Entries", HistType::kTH1F, {Binning.ratio}); + registry.add("TrackQA/After/AntiProton/fTpcFindableOverRows", "TPC Findabled/Crossed Rows;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {Binning.ratio}); + registry.add("TrackQA/After/AntiProton/fTpcChi2OverCluster", "TPC #chi^{2}/Cluster;TPC #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.tpcChi2}); + + registry.add("TrackQA/After/AntiProton/fItsClusters", "ITS Clusters;ITS Clusters;Entries", HistType::kTH1F, {Binning.itsCluster}); + registry.add("TrackQA/After/AntiProton/fItsIbClusters", "ITS Inner Barrel Clusters;ITS Inner Barrel Clusters;Entries", HistType::kTH1F, {Binning.itsIbCluster}); + registry.add("TrackQA/After/AntiProton/fItsChi2OverCluster", "ITS #chi^{2}/Cluster;ITS #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.itsChi2}); + + // Deuteron + registry.add("TrackQA/After/Deuteron/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/After/Deuteron/fPTpc", "Momentum at TPC inner wall;p_{TPC} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/After/Deuteron/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registry.add("TrackQA/After/Deuteron/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("TrackQA/After/Deuteron/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + registry.add("TrackQA/After/Deuteron/fNsigmaIts", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/Deuteron/fNsigmaTpc", "NSigmaTPC;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/Deuteron/fNsigmaTof", "NSigmaTOF;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/Deuteron/fNsigmaTpcTof", "NSigmaTPCTOF;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registry.add("TrackQA/After/Deuteron/fItsSignal", "ITS Signal;p (GeV/c); (cm)", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registry.add("TrackQA/After/Deuteron/fTpcSignal", "TPC Signal;p (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registry.add("TrackQA/After/Deuteron/fTofBeta", "TOF #beta;p (GeV/c);#beta_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registry.add("TrackQA/After/Deuteron/fDcaXy", "DCA_{xy};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registry.add("TrackQA/After/Deuteron/fDcaZ", "DCA_{z};p_{T} (GeV/c); DCA_{Z};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + + registry.add("TrackQA/After/Deuteron/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/Deuteron/fTpcCrossedRows", "TPC Crossed Rows;TPC Crossed Rows;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/Deuteron/fTpcSharedClusters", "TPC Shared Clusters;TPC Shared Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/Deuteron/fTpcSharedClusterOverClusterss", "TPC Shared Clusters/Clusters;TPC Shared Clusters/Clusters;Entries", HistType::kTH1F, {Binning.ratio}); + registry.add("TrackQA/After/Deuteron/fTpcFindableOverRows", "TPC Findabled/Crossed Rows;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {Binning.ratio}); + registry.add("TrackQA/After/Deuteron/fTpcChi2OverCluster", "TPC #chi^{2}/Cluster;TPC #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.tpcChi2}); + + registry.add("TrackQA/After/Deuteron/fItsClusters", "ITS Clusters;ITS Clusters;Entries", HistType::kTH1F, {Binning.itsCluster}); + registry.add("TrackQA/After/Deuteron/fItsIbClusters", "ITS Inner Barrel Clusters;ITS Inner Barrel Clusters;Entries", HistType::kTH1F, {Binning.itsIbCluster}); + registry.add("TrackQA/After/Deuteron/fItsChi2OverCluster", "ITS #chi^{2}/Cluster;ITS #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.itsChi2}); + + // AntiDeuteron + registry.add("TrackQA/After/AntiDeuteron/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/After/AntiDeuteron/fPTpc", "Momentum at TPC inner wall;p_{TPC} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("TrackQA/After/AntiDeuteron/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registry.add("TrackQA/After/AntiDeuteron/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("TrackQA/After/AntiDeuteron/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + registry.add("TrackQA/After/AntiDeuteron/fNsigmaIts", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/AntiDeuteron/fNsigmaTpc", "NSigmaTPC;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/AntiDeuteron/fNsigmaTof", "NSigmaTOF;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("TrackQA/After/AntiDeuteron/fNsigmaTpcTof", "NSigmaTPCTOF;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + + registry.add("TrackQA/After/AntiDeuteron/fItsSignal", "ITS Signal;p (GeV/c); (cm)", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registry.add("TrackQA/After/AntiDeuteron/fTpcSignal", "TPC Signal;p (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registry.add("TrackQA/After/AntiDeuteron/fTofBeta", "TOF #beta;p (GeV/c);#beta_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registry.add("TrackQA/After/AntiDeuteron/fDcaXy", "DCA_{xy};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registry.add("TrackQA/After/AntiDeuteron/fDcaZ", "DCA_{z};p_{T} (GeV/c); DCA_{Z};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + + registry.add("TrackQA/After/AntiDeuteron/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/AntiDeuteron/fTpcCrossedRows", "TPC Crossed Rows;TPC Crossed Rows;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/AntiDeuteron/fTpcSharedClusters", "TPC Shared Clusters;TPC Shared Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("TrackQA/After/AntiDeuteron/fTpcSharedClusterOverClusterss", "TPC Shared Clusters/Clusters;TPC Shared Clusters/Clusters;Entries", HistType::kTH1F, {Binning.ratio}); + registry.add("TrackQA/After/AntiDeuteron/fTpcFindableOverRows", "TPC Findabled/Crossed Rows;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {Binning.ratio}); + registry.add("TrackQA/After/AntiDeuteron/fTpcChi2OverCluster", "TPC #chi^{2}/Cluster;TPC #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.tpcChi2}); + + registry.add("TrackQA/After/AntiDeuteron/fItsClusters", "ITS Clusters;ITS Clusters;Entries", HistType::kTH1F, {Binning.itsCluster}); + registry.add("TrackQA/After/AntiDeuteron/fItsIbClusters", "ITS Inner Barrel Clusters;ITS Inner Barrel Clusters;Entries", HistType::kTH1F, {Binning.itsIbCluster}); + registry.add("TrackQA/After/AntiDeuteron/fItsChi2OverCluster", "ITS #chi^{2}/Cluster;ITS #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.itsChi2}); + + // Lambda before + registry.add("LambdaQA/Before/fPt", "Transverse momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("LambdaQA/Before/fEta", "Psedurapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("LambdaQA/Before/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registry.add("LambdaQA/Before/fInvMassLambda", "Invariant mass Lambda;M_{#pi p};Entries", HistType::kTH1F, {Binning.invMassLambda}); + registry.add("LambdaQA/Before/fInvMassAntiLambda", "Invariant mass AntiLambda;M_{#pi p};Entries", HistType::kTH1F, {Binning.invMassLambda}); + registry.add("LambdaQA/Before/fInvMassLambdaVsAntiLambda", "Invariant mass of Lambda vs AntiLambda;M_{#pi p};Entries", HistType::kTH2F, {Binning.invMassLambda, Binning.invMassLambda}); + registry.add("LambdaQA/Before/fInvMassLambdaVsKaon", "Invariant mass of Lambda vs K0;M_{#pi p};;M_{#pi #pi}", HistType::kTH2F, {Binning.invMassLambda, Binning.invMassK0short}); + registry.add("LambdaQA/Before/fInvMassAntiLambdaVsKaon", "Invariant mass of AntiLambda vs K0;M_{#pi p};;M_{#pi #pi}", HistType::kTH2F, {Binning.invMassLambda, Binning.invMassK0short}); + registry.add("LambdaQA/Before/fDcaDaugh", "DCA_{Daugh};DCA_{daugh};Entries", HistType::kTH1F, {Binning.dcaDaugh}); + registry.add("LambdaQA/Before/fCpa", "Cosine of pointing angle;CPA;Entries", HistType::kTH1F, {Binning.cpa}); + registry.add("LambdaQA/Before/fTranRad", "Transverse Radisu;TranRad;Entries", HistType::kTH1F, {Binning.transRad}); + registry.add("LambdaQA/Before/fDecVtx", "Decay vertex displacement;DecVtx;Entries", HistType::kTH1F, {Binning.decayVtx}); + registry.add("LambdaQA/Before/PosDaughter/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("LambdaQA/Before/PosDaughter/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("LambdaQA/Before/PosDaughter/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registry.add("LambdaQA/Before/PosDaughter/fDcaXy", "DCA_{XY};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registry.add("LambdaQA/Before/PosDaughter/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("LambdaQA/Before/PosDaughter/fNsigmaTpcProton", "NSigmaTPC Proton;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("LambdaQA/Before/PosDaughter/fNsigmaTpcPion", "NSigmaTPC Pion;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("LambdaQA/Before/NegDaughter/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("LambdaQA/Before/NegDaughter/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("LambdaQA/Before/NegDaughter/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registry.add("LambdaQA/Before/NegDaughter/fDcaXy", "DCA_{XY};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registry.add("LambdaQA/Before/NegDaughter/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("LambdaQA/Before/NegDaughter/fNsigmaTpcProton", "NSigmaTPC AnitProton;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("LambdaQA/Before/NegDaughter/fNsigmaTpcPion", "NSigmaTPC AntiPion;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + + // Lambda after + registry.add("LambdaQA/After/Lambda/fPt", "Transverse momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("LambdaQA/After/Lambda/fEta", "Psedurapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("LambdaQA/After/Lambda/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registry.add("LambdaQA/After/Lambda/fInvMass", "Invariant mass;M_{#pi p};Entries", HistType::kTH1F, {Binning.invMassLambda}); + registry.add("LambdaQA/After/Lambda/fInvMassLambdaVsAntiLambda", "Invariant mass of Lambda vs AntiLambda;M_{#pi p};Entries", HistType::kTH2F, {Binning.invMassLambda, Binning.invMassLambda}); + registry.add("LambdaQA/After/Lambda/fInvMassLambdaVsKaon", "Invariant mass of rejected K0 vs V0s;M_{#pi p};;M_{#pi #pi}", HistType::kTH2F, {Binning.invMassLambda, Binning.invMassK0short}); + registry.add("LambdaQA/After/Lambda/fDcaDaugh", "DCA_{Daugh};DCA_{daugh};Entries", HistType::kTH1F, {Binning.dcaDaugh}); + registry.add("LambdaQA/After/Lambda/fCpa", "Cosine of pointing angle;CPA;Entries", HistType::kTH1F, {Binning.cpa}); + registry.add("LambdaQA/After/Lambda/fTranRad", "Transverse Radisu;TranRad;Entries", HistType::kTH1F, {Binning.transRad}); + registry.add("LambdaQA/After/Lambda/fDecVtx", "Decay vertex displacement;DecVtx;Entries", HistType::kTH1F, {Binning.decayVtx}); + registry.add("LambdaQA/After/Lambda/PosDaughter/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("LambdaQA/After/Lambda/PosDaughter/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("LambdaQA/After/Lambda/PosDaughter/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registry.add("LambdaQA/After/Lambda/PosDaughter/fDcaXy", "DCA_{XY};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registry.add("LambdaQA/After/Lambda/PosDaughter/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("LambdaQA/After/Lambda/PosDaughter/fNsigmaTpc", "NSigmaTPC Proton;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("LambdaQA/After/Lambda/NegDaughter/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("LambdaQA/After/Lambda/NegDaughter/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("LambdaQA/After/Lambda/NegDaughter/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registry.add("LambdaQA/After/Lambda/NegDaughter/fDcaXy", "DCA_{XY};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registry.add("LambdaQA/After/Lambda/NegDaughter/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("LambdaQA/After/Lambda/NegDaughter/fNsigmaTpc", "NSigmaTPC AntiPion;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + + // AntiLambda after + registry.add("LambdaQA/After/AntiLambda/fPt", "Transverse momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("LambdaQA/After/AntiLambda/fEta", "Psedurapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("LambdaQA/After/AntiLambda/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registry.add("LambdaQA/After/AntiLambda/fInvMass", "Invariant mass;M_{#pi p};Entries", HistType::kTH1F, {Binning.invMassLambda}); + registry.add("LambdaQA/After/AntiLambda/fInvMassAntiLambdaVsLambda", "Invariant mass of Lambda vs AntiLambda;M_{#pi p};Entries", HistType::kTH2F, {Binning.invMassLambda, Binning.invMassLambda}); + registry.add("LambdaQA/After/AntiLambda/fInvMassAntiLambdaVsKaon", "Invariant mass of rejected K0 vs V0s;M_{#pi p};;M_{#pi #pi}", HistType::kTH2F, {Binning.invMassLambda, Binning.invMassK0short}); + registry.add("LambdaQA/After/AntiLambda/fDcaDaugh", "DCA_{Daugh};DCA_{daugh};Entries", HistType::kTH1F, {Binning.dcaDaugh}); + registry.add("LambdaQA/After/AntiLambda/fCpa", "Cosine of pointing angle;CPA;Entries", HistType::kTH1F, {Binning.cpa}); + registry.add("LambdaQA/After/AntiLambda/fTranRad", "Transverse Radisu;TranRad;Entries", HistType::kTH1F, {Binning.transRad}); + registry.add("LambdaQA/After/AntiLambda/fDecVtx", "Decay vertex displacement;DecVtx;Entries", HistType::kTH1F, {Binning.decayVtx}); + registry.add("LambdaQA/After/AntiLambda/PosDaughter/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("LambdaQA/After/AntiLambda/PosDaughter/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("LambdaQA/After/AntiLambda/PosDaughter/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registry.add("LambdaQA/After/AntiLambda/PosDaughter/fDcaXy", "DCA_{XY};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registry.add("LambdaQA/After/AntiLambda/PosDaughter/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("LambdaQA/After/AntiLambda/PosDaughter/fNsigmaTpc", "NSigmaTPC Proton;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registry.add("LambdaQA/After/AntiLambda/NegDaughter/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("LambdaQA/After/AntiLambda/NegDaughter/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("LambdaQA/After/AntiLambda/NegDaughter/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registry.add("LambdaQA/After/AntiLambda/NegDaughter/fDcaXy", "DCA_{XY};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registry.add("LambdaQA/After/AntiLambda/NegDaughter/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registry.add("LambdaQA/After/AntiLambda/NegDaughter/fNsigmaTpc", "NSigmaTPC AntiPion;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + + // Phi before + registry.add("PhiQA/Before/fInvMass", "Invariant mass #phi;M_{KK};Entries", HistType::kTH1F, {Binning.invMassPhi}); + registry.add("PhiQA/Before/fPt", "Transverse momentum #phi;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("PhiQA/Before/fEta", "Pseudorapidity of V0;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("PhiQA/Before/fPhi", "Azimuthal angle of #phi;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + // Phi after + registry.add("PhiQA/After/fInvMass", "Invariant mass #phi;M_{KK};Entries", HistType::kTH1F, {Binning.invMassPhi}); + registry.add("PhiQA/After/fPt", "Transverse momentum #phi;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("PhiQA/After/fEta", "Pseudorapidity of #phi;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("PhiQA/After/fPhi", "Azimuthal angle of #Phi;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + // Rho before + registry.add("RhoQA/Before/fInvMass", "Invariant mass #rho;M_{#pi#pi};Entries", HistType::kTH1F, {Binning.invMassRho}); + registry.add("RhoQA/Before/fPt", "Transverse momentum #rho;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("RhoQA/Before/fEta", "Pseudorapidity of #rho;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("RhoQA/Before/fPhi", "Azimuthal angle of #rho;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + // Rho after + registry.add("RhoQA/After/fInvMass", "Invariant mass #rho;M_{#pi#pi};Entries", HistType::kTH1F, {Binning.invMassRho}); + registry.add("RhoQA/After/fPt", "Transverse momentum #rho;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registry.add("RhoQA/After/fEta", "Pseudorapidity of #rho;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registry.add("RhoQA/After/fPhi", "Azimuthal angle of #rho;#phi;Entries", HistType::kTH1F, {Binning.phi}); // for ppp - registry.add("ppp/fMultiplicity", "Multiplicity of all processed events;Mult;Entries", HistType::kTH1F, {{1000, 0, 1000}}); - registry.add("ppp/fZvtx", "Zvtx of all processed events;Z_{vtx};Entries", HistType::kTH1F, {{1000, -15, 15}}); - registry.add("ppp/fSE_particle", "Same Event distribution", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("ppp/fSE_particle_downsample", "Same Event distribution (downsampled)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("ppp/fSE_antiparticle", "Same Event distribution", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("ppp/fSE_antiparticle_downsample", "Same Event distribution (downsampled)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("ppp/fProtonPtVsQ3", "pT (proton) vs Q_{3};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); - registry.add("ppp/fAntiProtonPtVsQ3", "pT (antiproton) vs Q_{3};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); + registry.add("PPP/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registry.add("PPP/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registry.add("PPP/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registry.add("PPP/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registry.add("PPP/fProtonPtVsQ3", "Proton p_{T} vs Q_{3};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.q3}}); + registry.add("PPP/fAntiProtonPtVsQ3", "AntiProton p_{T} vs Q_{3};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.q3}}); // for ppl - registry.add("ppl/fMultiplicity", "Multiplicity of all processed events;Mult;Entries", HistType::kTH1F, {{1000, 0, 1000}}); - registry.add("ppl/fZvtx", "Zvtx of all processed events;Z_{vtx};Entries", HistType::kTH1F, {{1000, -15, 15}}); - registry.add("ppl/fSE_particle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("ppl/fSE_particle_downsample", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("ppl/fSE_antiparticle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("ppl/fSE_antiparticle_downsample", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("ppl/fProtonPtVsQ3", "pT (proton) vs Q_{3};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); - registry.add("ppl/fAntiProtonPtVsQ3", "pT (proton) vs Q_{3};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); - registry.add("ppl/fLambdaPtVsQ3", "pT (lambda) vs Q_{3};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); - registry.add("ppl/fAntiLambdaPtVsQ3", "pT (antilambda) vs Q_{3};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); + registry.add("PPL/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registry.add("PPL/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registry.add("PPL/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registry.add("PPL/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registry.add("PPL/fProtonPtVsQ3", "Proton p_{T} vs Q_{3};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.q3}}); + registry.add("PPL/fAntiProtonPtVsQ3", "AntiProton p_{T} vs Q_{3};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.q3}}); + registry.add("PPL/fLambdaPtVsQ3", "Lambda p_{T} vs Q_{3};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.q3}}); + registry.add("PPL/fAntiLambdaPtVsQ3", "AntiLambda p_{T} vs Q_{3};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.q3}}); // for pll - registry.add("pll/fMultiplicity", "Multiplicity of all processed events;Mult;Entries", HistType::kTH1F, {{1000, 0, 1000}}); - registry.add("pll/fZvtx", "Zvtx of all processed events;Z_{vtx};Entries", HistType::kTH1F, {{1000, -15, 15}}); - registry.add("pll/fSE_particle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("pll/fSE_particle_downsample", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("pll/fSE_antiparticle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("pll/fSE_antiparticle_downsample", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("pll/fProtonPtVsQ3", "Q3 vs pT (proton)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); - registry.add("pll/fAntiProtonPtVsQ3", "Q3 vs pT (antiproton)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); - registry.add("pll/fLambdaPtVsQ3", "Q3 vs pT (lambda)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); - registry.add("pll/fAntiLambdaPtVsQ3", "Q3 vs pT (antilambda)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); + registry.add("PLL/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registry.add("PLL/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registry.add("PLL/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);SE", HistType::kTH1F, {Binning.q3}); + registry.add("PLL/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);SE", HistType::kTH1F, {Binning.q3}); + registry.add("PLL/fProtonPtVsQ3", "Proton p_{T}Q3 vs pT", {HistType::kTH2F, {Binning.momentum, Binning.q3}}); + registry.add("PLL/fAntiProtonPtVsQ3", "AntiProton p_{T} vs Q3", {HistType::kTH2F, {Binning.momentum, Binning.q3}}); + registry.add("PLL/fLambdaPtVsQ3", "Lambda p_{T} vs Q3", {HistType::kTH2F, {Binning.momentum, Binning.q3}}); + registry.add("PLL/fAntiLambdaPtVsQ3", "AntiLambda p_{T} vs Q3", {HistType::kTH2F, {Binning.momentum, Binning.q3}}); // for lll - registry.add("lll/fMultiplicity", "Multiplicity of all processed events;Mult;Entries", HistType::kTH1F, {{1000, 0, 1000}}); - registry.add("lll/fZvtx", "Zvtx of all processed events;Z_{vtx};Entries", HistType::kTH1F, {{1000, -15, 15}}); - registry.add("lll/fSE_particle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("lll/fSE_particle_downsample", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("lll/fSE_antiparticle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("lll/fSE_antiparticle_downsample", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("lll/fLambdaPtVsQ3", "Q3 vs pT (lambda)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); - registry.add("lll/fAntiLambdaPtVsQ3", "Q3 vs pT (antilambda)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); + registry.add("LLL/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registry.add("LLL/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registry.add("LLL/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registry.add("LLL/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registry.add("LLL/fLambdaPtVsQ3", "Lambda p_{T} vs Q3", {HistType::kTH2F, {Binning.momentum, Binning.q3}}); + registry.add("LLL/fAntiLambdaPtVsQ3", "AntiLambda p_{T} vs Q3", {HistType::kTH2F, {Binning.momentum, Binning.q3}}); + + // for ppPhi + registry.add("PPPhi/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registry.add("PPPhi/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registry.add("PPPhi/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registry.add("PPPhi/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registry.add("PPPhi/fProtonPtVsQ3", "Proton p_{T} vs Q_{3}", HistType::kTH2F, {Binning.momentum, Binning.q3}); + registry.add("PPPhi/fAntiProtonPtVsQ3", "AntiLambda p_{T} vs Q3", HistType::kTH2F, {Binning.momentum, Binning.q3}); + registry.add("PPPhi/fPhiPtVsQ3", "#phi p_{T} vs Q_{3};p_{T} (GeV/c); Q_{3} (GeV/c)", HistType::kTH2F, {Binning.momentum, Binning.q3}); + registry.add("PPPhi/fPhiInvMassVsQ3", "#phi mass vs Q_{3};M_{K^{+}K^{-}} (GeV/c^{2});Q_{3} (GeV/c)", HistType::kTH2F, {Binning.invMassPhi, Binning.q3}); + + // for ppRho + registry.add("PPRho/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registry.add("PPRho/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registry.add("PPRho/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);SE", HistType::kTH1F, {Binning.q3}); + registry.add("PPRho/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);SE", HistType::kTH1F, {Binning.q3}); + registry.add("PPRho/fProtonPtVsQ3", "Proton p_{T} vs Q3", HistType::kTH2F, {Binning.momentum, Binning.q3}); + registry.add("PPRho/fAntiProtonPtVsQ3", "AntiProton p_{T} vs Q3", HistType::kTH2F, {Binning.momentum, Binning.q3}); + registry.add("PPRho/fRhoPtVsQ3", "#rho p_{T} vs Q3;Q_{3} (GeV/c);SE", HistType::kTH2F, {Binning.momentum, Binning.q3}); + registry.add("PPRho/fRhoInvMassVsQ3", "#rho mass vs Q_{3};M_{#pi^{+}#pi^{-}} (GeV/c^{2});Q_{3} (GeV/c)", HistType::kTH2F, {Binning.invMassRho, Binning.q3}); // for pd - registry.add("pd/fMultiplicity", "Multiplicity of all processed events;Mult;Entries", HistType::kTH1F, {{1000, 0, 1000}}); - registry.add("pd/fZvtx", "Zvtx of all processed events;Z_{vtx};Entries", HistType::kTH1F, {{1000, -15, 15}}); - registry.add("pd/fSE_particle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("pd/fSE_particle_downsample", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("pd/fSE_antiparticle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("pd/fSE_antiparticle_downsample", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("pd/fProtonPtVskstar", "pT (proton) vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); - registry.add("pd/fAntiProtonPtVskstar", "pT (antiproton) vs k^{*};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); - registry.add("pd/fDeuteronPtVskstar", "pT (deuteron) vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); - registry.add("pd/fAntiDeuteronPtVskstar", "pT (antideuteron) vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); + registry.add("PD/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registry.add("PD/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registry.add("PD/fSE_particle", "Same Event distribution;k^{*} (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registry.add("PD/fSE_antiparticle", "Same Event distribution;k^{*} (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registry.add("PD/fProtonPtVskstar", "Proton p_{T} vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.kstar}}); + registry.add("PD/fAntiProtonPtVskstar", "AntiProton p_{T} vs k^{*};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.kstar}}); + registry.add("PD/fDeuteronPtVskstar", "Deuteron p_{T} vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.kstar}}); + registry.add("PD/fAntiDeuteronPtVskstar", "AntiDeuteron p_{T} vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.kstar}}); // for ld - registry.add("ld/fMultiplicity", "Multiplicity of all processed events", HistType::kTH1F, {{1000, 0, 1000}}); - registry.add("ld/fZvtx", "Zvtx of all processed events;Z_{vtx};Entries", HistType::kTH1F, {{1000, -15, 15}}); - registry.add("ld/fSE_particle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("ld/fSE_particle_downsample", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("ld/fSE_antiparticle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("ld/fSE_antiparticle_downsample", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("ld/fDeuteronPtVskstar", "pT (deuteron) vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); - registry.add("ld/fAntiDeuteronPtVskstar", "pT (antideuteron) vs k^{*};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); - registry.add("ld/fLambdaPtVskstar", "pT (lambda) vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); - registry.add("ld/fAntiLambdaPtVskstar", "pT (antilambda) vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {{150, 0, 1.5}, {500, 0, 10}}}); + registry.add("LD/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registry.add("LD/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registry.add("LD/fSE_particle", "Same Event distribution;k^{*} (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registry.add("LD/fSE_antiparticle", "Same Event distribution;k^{*} (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registry.add("LD/fDeuteronPtVskstar", "Deuteron p_{T} vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.kstar}}); + registry.add("LD/fAntiDeuteronPtVskstar", "AntiDeuteron p_{T} vs k^{*};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.kstar}}); + registry.add("LD/fLambdaPtVskstar", "Lambda p_{T} vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.kstar}}); + registry.add("LD/fAntiLambdaPtVskstar", "AntiLambda p_{T} vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.kstar}}); + + // for phid + registry.add("PhiD/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registry.add("PhiD/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registry.add("PhiD/fSE_particle", "Same Event distribution;k^{*} (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registry.add("PhiD/fSE_antiparticle", "Same Event distribution;k^{*} (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registry.add("PhiD/fPhiPtVskstar", "Phi p_{T} vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.kstar}}); + registry.add("PhiD/fDeuteronPtVskstar", "Deuteron p_{T} vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.kstar}}); + registry.add("PhiD/fAntiDeuteronPtVskstar", "AntiDeuteron p_{T} vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.kstar}}); + registry.add("PhiD/fPhiInvMassVskstar", "#phi mass vs k^{*};M_{K^{+}K^{-}} (GeV/c^{2});k^{*} (GeV/c)", HistType::kTH2F, {Binning.invMassRho, Binning.kstar}); + + // for rhod + registry.add("RhoD/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registry.add("RhoD/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registry.add("RhoD/fSE_particle", "Same Event distribution;k^{*} (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registry.add("RhoD/fSE_antiparticle", "Same Event distribution;k^{*} (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registry.add("RhoD/fRhoPtVskstar", "Rho p_{T} vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.kstar}}); + registry.add("RhoD/fDeuteronPtVskstar", "Deuteron p_{T} vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.kstar}}); + registry.add("RhoD/fAntiDeuteronPtVskstar", "AntiDeuteron p_{T} vs k^{*};k^{*} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.momentum, Binning.kstar}}); + registry.add("RhoD/fRhoInvMassVskstar", "#rho mass vs k^{*};M_{#pi^{+}#pi^{-}} (GeV/c^{2});k^{*} (GeV/c)", HistType::kTH2F, {Binning.invMassRho, Binning.kstar}); } - float mMassElectron = o2::constants::physics::MassElectron; - float mMassPion = o2::constants::physics::MassPionCharged; - float mMassProton = o2::constants::physics::MassProton; - float mMassLambda = o2::constants::physics::MassLambda; - float mMassDeuteron = o2::constants::physics::MassDeuteron; - int currentRunNumber = -999; - int lastRunNumber = -999; + void initCCDB(int run) + { + if (run != mRunNumber) { + mRunNumber = run; + o2::parameters::GRPMagField* grpmag = ccdb->getForRun("GLO/Config/GRPMagField", run); + o2::base::Propagator::initFieldFromGRP(grpmag); + mBz = static_cast(grpmag->getNominalL3Field()); + + mStraHelper.fitter.setBz(mBz); + } + if (!mStraHelper.lut) { /// done only once + ccdb->setURL(V0BuilderOpts.ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(true); + auto* lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get("GLO/Param/MatLUT")); + o2::base::Propagator::Instance()->setMatLUT(lut); + mStraHelper.lut = lut; + } + } template - bool isSelectedEvent(T const& col) + bool checkEvent(T const& col) { - if (ConfEvtSelectZvtx && std::abs(col.posZ()) > ConfEvtZvtx) { + if (std::abs(col.posZ()) > EventSelection.zvtx.value) { return false; } - if (ConfEvtOfflineCheck && !col.sel8()) { + if (EventSelection.eventSel.value && !col.sel8()) { return false; } - // if event is close to the timeframe border, return false - if (ConfEvtTimeFrameBorderCheck && !col.selection_bit(aod::evsel::kNoTimeFrameBorder)) { - return false; - } - return true; } template - bool isSelectedTrack(T const& track, CFTrigger::ParticleSpecies partSpecies) + bool checkTrack(T const& track, std::string trackName) { - const auto charge = track.sign(); - const auto pT = track.pt(); - float momCorDif = track.tpcInnerParam() - track.p(); - float momCorRatio = momCorDif / track.p(); - const auto eta = track.eta(); - const auto tpcNClsF = track.tpcNClsFound(); - const auto tpcRClsC = track.tpcCrossedRowsOverFindableCls(); - const auto tpcNClsC = track.tpcNClsCrossedRows(); - const auto tpcNClsS = track.tpcNClsShared(); - const auto itsNCls = track.itsNCls(); - const auto itsNClsIB = track.itsNClsInnerBarrel(); - const auto dcaXY = track.dcaXY(); - const auto dcaZ = track.dcaZ(); - - if (charge > 0) { - if (pT < ConfPtCuts->get(partSpecies, "Pt min (particle)")) { - return false; - } - if (pT > ConfPtCuts->get(partSpecies, "Pt max (particle)")) { - return false; - } - if (ConfMomCorDifCutFlag.value && momCorDif < ConfMomCorDifCut->get(partSpecies, "Momemtum Correlation min")) { - return false; - } - if (ConfMomCorDifCutFlag.value && momCorDif > ConfMomCorDifCut->get(partSpecies, "Momemtum Correlation max")) { - return false; - } - if (ConfMomCorRatioCutFlag.value && momCorRatio < ConfMomCorRatioCut->get(partSpecies, "Momemtum Correlation min")) { - return false; - } - if (ConfMomCorRatioCutFlag.value && momCorRatio > ConfMomCorRatioCut->get(partSpecies, "Momemtum Correlation max")) { - return false; - } - } - if (charge < 0) { - if (pT < ConfPtCuts->get(partSpecies, "Pt min (antiparticle)")) { - return false; - } - if (pT > ConfPtCuts->get(partSpecies, "Pt max (antiparticle)")) { - return false; - } - if (ConfMomCorDifCutFlag.value && momCorDif < ConfMomCorDifCutAnti->get(partSpecies, "Momemtum Correlation min")) { - return false; - } - if (ConfMomCorDifCutFlag.value && momCorDif > ConfMomCorDifCutAnti->get(partSpecies, "Momemtum Correlation max")) { - return false; - } - if (ConfMomCorRatioCutFlag.value && momCorRatio < ConfMomCorRatioCutAnti->get(partSpecies, "Momemtum Correlation min")) { - return false; - } - if (ConfMomCorRatioCutFlag.value && momCorRatio > ConfMomCorRatioCutAnti->get(partSpecies, "Momemtum Correlation max")) { - return false; - } - } - - if (std::abs(eta) > ConfTrkEta) { - return false; - } - if (tpcNClsF < ConfTPCNClustersMin->get("TPCNClusMin", partSpecies)) { - return false; - } - if (tpcRClsC < ConfTrkTPCfCls) { + if (std::abs(track.eta()) > TrackSelections.trackProperties->get(trackName.c_str(), "AbsEtaMax")) { return false; } - if (tpcNClsC < ConfTrkTPCcRowsMin) { + if (track.tpcNClsFound() < TrackSelections.trackProperties->get(trackName.c_str(), "TpcClusterMin")) { return false; } - if (tpcNClsS > ConfTrkTPCsClsMax) { + if (track.tpcNClsCrossedRows() < TrackSelections.trackProperties->get(trackName.c_str(), "TpcRowMin")) { return false; } - if (itsNCls < ConfTrkITSnclsMin->get(static_cast(0), partSpecies)) { + if (track.tpcCrossedRowsOverFindableCls() < TrackSelections.trackProperties->get(trackName.c_str(), "TpcCrossedOverFoundMin")) { return false; } - if (itsNClsIB < ConfTrkITSnclsIBMin->get(static_cast(0), partSpecies)) { + if (track.tpcNClsShared() > TrackSelections.trackProperties->get(trackName.c_str(), "TpcSharedMax")) { return false; } - if (std::abs(dcaXY) > ConfTrkDCAxyMax) { + if (track.tpcFractionSharedCls() > TrackSelections.trackProperties->get(trackName.c_str(), "TpcFracSharedMax")) { return false; } - if (std::abs(dcaZ) > ConfTrkDCAzMax) { + if (track.itsNCls() < TrackSelections.trackProperties->get(trackName.c_str(), "ItsClusterMin")) { return false; } - // TODO: which dca, put dcaxy for now - if (ConfRejectNotPropagatedTracks && std::abs(dcaXY) > 1e3) { + if (track.itsNClsInnerBarrel() < TrackSelections.trackProperties->get(trackName.c_str(), "ItsIbClusterMin")) { return false; } - if (ConfTrkRequireChi2MaxTPC && track.tpcChi2NCl() >= ConfTrkMaxChi2PerClusterTPC) { + if (std::abs(track.dcaXY()) > TrackSelections.trackProperties->get(trackName.c_str(), "AbsDcaXyMax")) { return false; } - if (ConfTrkRequireChi2MaxITS && track.itsChi2NCl() >= ConfTrkMaxChi2PerClusterITS) { + if (std::abs(track.dcaZ()) > TrackSelections.trackProperties->get(trackName.c_str(), "AbsDcaZMax")) { return false; } - if (ConfTrkTPCRefit && !track.hasTPC()) { + if (track.tpcChi2NCl() > TrackSelections.trackProperties->get(trackName.c_str(), "Chi2TpcMax")) { return false; } - if (ConfTrkITSRefit && !track.hasITS()) { + if (track.itsChi2NCl() > TrackSelections.trackProperties->get(trackName.c_str(), "Chi2ItsMax")) { return false; } return true; } - template - bool isSelectedV0Daughter(T const& track, V const& v0, float charge, CFTrigger::V0Daughters species, double nSigmaTPCDaug[2]) + template + bool checkTrackPid(T const& track, std::string trackName) { - const auto tpcNClsF = track.tpcNClsFound(); - float eta = -1; - float dca = -1; - if (charge > 0) { - eta = v0.positiveeta(); - dca = v0.dcapostopv(); - } else if (charge < 0) { - eta = v0.negativeeta(); - dca = v0.dcanegtopv(); - } - const auto sign = track.sign(); - double nSigmaTPC = -999.f; - - if (charge < 0 && sign > 0) { - return false; - } - if (charge > 0 && sign < 0) { - return false; - } - if (std::abs(eta) > ConfDaughEta) { - return false; - } - if (tpcNClsF < ConfDaughTPCnclsMin) { - return false; - } - if (std::abs(dca) < ConfDaughDCAMin) { - return false; - } + float momentum = -99; - switch (species) { - case CFTrigger::kDaughPion: - nSigmaTPC = nSigmaTPCDaug[1]; - break; - case CFTrigger::kDaughProton: - nSigmaTPC = nSigmaTPCDaug[0]; - break; - default: - LOG(fatal) << "Particle species for V0 daughters not found"; + if (TrackSelections.momentum->get(trackName.c_str(), "UseInnerParam") < 0) { + momentum = track.p(); + } else { + momentum = track.tpcInnerParam(); } - if (nSigmaTPC < ConfDaughPIDCuts->get(species, "TPC min") || - nSigmaTPC > ConfDaughPIDCuts->get(species, "TPC max")) { - return false; - } - return true; - } - - template - bool isSelectedTrackPID(T const& track, CFTrigger::ParticleSpecies partSpecies, bool Rejection, double nSigmaTPC[2], int charge) - { - // nSigma should have entries [proton, deuteron] - bool isSelected = false; - bool pThres = true; - float nSigma = -999.; - - // check tracking PID - uint8_t SpeciesForTracking = 0; - if (partSpecies == CFTrigger::kProton) { - SpeciesForTracking = o2::track::PID::Proton; - } else if (partSpecies == CFTrigger::kDeuteron) { - SpeciesForTracking = o2::track::PID::Deuteron; + float nsigmaITS = -99; + float nsigmaTPC = -99; + float nsigmaTPCTOF = -99; + + if (trackName == std::string("Pion")) { + nsigmaITS = track.itsNSigmaPi(); + nsigmaTPC = track.tpcNSigmaPi(); + nsigmaTPCTOF = RecoDecay::sqrtSumOfSquares(track.tpcNSigmaPi(), track.tofNSigmaPi()); + } else if (trackName == std::string("Kaon")) { + nsigmaITS = track.itsNSigmaKa(); + nsigmaTPC = track.tpcNSigmaKa(); + nsigmaTPCTOF = RecoDecay::sqrtSumOfSquares(track.tpcNSigmaKa(), track.tofNSigmaKa()); + } else if (trackName == std::string("Proton")) { + nsigmaITS = track.itsNSigmaPr(); + nsigmaTPC = track.tpcNSigmaPr(); + nsigmaTPCTOF = RecoDecay::sqrtSumOfSquares(track.tpcNSigmaPr(), track.tofNSigmaPr()); + } else if (trackName == std::string("Deuteron")) { + nsigmaITS = track.itsNSigmaDe(); + nsigmaTPC = track.tpcNSigmaDe(); + nsigmaTPCTOF = RecoDecay::sqrtSumOfSquares(track.tpcNSigmaDe(), track.tofNSigmaDe()); } else { - LOG(warn) << "Unknown PID for tracking encountered"; + LOG(fatal) << "Unsupported track type"; } - if (ConfPIDForTracking->get(partSpecies, "Switch") > 0 && track.tpcInnerParam() < ConfPIDForTracking->get(partSpecies, "Momemtum Threshold")) { - if (track.pidForTracking() != SpeciesForTracking) { + if (momentum < TrackSelections.momentum->get(trackName.c_str(), "PThres")) { + if (nsigmaITS < TrackSelections.pid->get(trackName.c_str(), "ItsMin") || nsigmaITS > TrackSelections.pid->get(trackName.c_str(), "ItsMax")) { return false; } - } - - // check momentum threshold - if (track.tpcInnerParam() <= ConfPtCuts->get(partSpecies, "P thres")) { - pThres = true; - } else { - pThres = false; - } - if (CFTrigger::kDeuteron == partSpecies && ConfDeuteronThPVMom) { - if (track.p() <= ConfPtCuts->get(partSpecies, "P thres")) { - pThres = true; - } else { - pThres = false; - } - } - // compute nsigma - switch (partSpecies) { - case CFTrigger::kProton: - if (pThres) { - nSigma = nSigmaTPC[0]; - } else { - if (charge > 0) { - nSigma = std::sqrt(std::pow(nSigmaTPC[0] - TPCTOFAvg[0], 2) + std::pow(track.tofNSigmaPr() - TPCTOFAvg[1], 2)); - } else { - nSigma = std::sqrt(std::pow(nSigmaTPC[0] - TPCTOFAvg[2], 2) + std::pow(track.tofNSigmaPr() - TPCTOFAvg[3], 2)); - } - } - break; - case CFTrigger::kDeuteron: - if (pThres) { - nSigma = nSigmaTPC[1]; - } else { - if (charge > 0) { - nSigma = std::sqrt(std::pow(nSigmaTPC[1] - TPCTOFAvg[4], 2) + std::pow(track.tofNSigmaDe() - TPCTOFAvg[5], 2)); - } else { - nSigma = std::sqrt(std::pow(nSigmaTPC[1] - TPCTOFAvg[6], 2) + std::pow(track.tofNSigmaDe() - TPCTOFAvg[7], 2)); - } - } - break; - case CFTrigger::kLambda: - LOG(fatal) << "No PID selection for Lambdas"; - break; - default: - LOG(fatal) << "Particle species not known"; - } - // check if track is selected - - auto TPCmin = (charge > 0) ? ConfPIDCuts->get(partSpecies, CFTrigger::kTPCMin) - : ConfPIDCutsAnti->get(partSpecies, CFTrigger::kTPCMin); - - auto TPCmax = (charge > 0) ? ConfPIDCuts->get(partSpecies, CFTrigger::kTPCMax) - : ConfPIDCutsAnti->get(partSpecies, CFTrigger::kTPCMax); - - auto TPCTOFmax = (charge > 0) ? ConfPIDCuts->get(partSpecies, CFTrigger::kTPCTOF) - : ConfPIDCutsAnti->get(partSpecies, CFTrigger::kTPCTOF); - - if (pThres) { - if (nSigma > TPCmin && - nSigma < TPCmax) { - isSelected = true; + if (nsigmaTPC < TrackSelections.pid->get(trackName.c_str(), "TpcMin") || nsigmaTPC > TrackSelections.pid->get(trackName.c_str(), "TpcMax")) { + return false; } } else { - if (nSigma < TPCTOFmax) { - isSelected = true; - } - } - // for deuterons normally, we want to reject tracks that have a high - // probablilty of being another particle - if (Rejection) { - double nSigmaPi = track.tpcNSigmaPi(); - double nSigmaEl = track.tpcNSigmaEl(); - if (ConfUseManualPIDpion) { - auto bgScalingPion = 1 / mMassPion; // momentum scaling? - if (BBPion.size() == 6 && charge > 0) - nSigmaPi = updatePID(track, bgScalingPion, BBPion); - if (BBAntipion.size() == 6 && charge < 0) - nSigmaPi = updatePID(track, bgScalingPion, BBAntipion); - } - if (ConfUseManualPIDel) { - auto bgScalingElectron = 1 / mMassElectron; // momentum scaling? - if (BBElectron.size() == 6 && charge < 0) - nSigmaEl = updatePID(track, bgScalingElectron, BBElectron); - if (BBAntielectron.size() == 6 && charge > 0) - nSigmaEl = updatePID(track, bgScalingElectron, BBAntielectron); - } - if ((ConfPIDRejection->get(CFTrigger::kRejProton, CFTrigger::kTPCMin) < nSigmaTPC[0] && - ConfPIDRejection->get(CFTrigger::kRejProton, CFTrigger::kTPCMax) > nSigmaTPC[0]) || - (ConfPIDRejection->get(CFTrigger::kRejPion, CFTrigger::kTPCMin) < nSigmaPi && - ConfPIDRejection->get(CFTrigger::kRejPion, CFTrigger::kTPCMax) > nSigmaPi) || - (ConfPIDRejection->get(CFTrigger::kRejElectron, CFTrigger::kTPCMin) < nSigmaEl && - ConfPIDRejection->get(CFTrigger::kRejElectron, CFTrigger::kTPCMax) > nSigmaEl)) { + if (nsigmaTPCTOF > TrackSelections.pid->get(trackName.c_str(), "TpcTofMax")) { return false; } } - return isSelected; + return true; } - template - bool isSelectedMinimalV0(C const& /*col*/, V const& v0, T const& posTrack, - T const& negTrack, float charge, double nSigmaTPCPos[2], double nSigmaTPCNeg[2]) + bool checkLambda(float lambdaPt, float lambdaDauDca, float lambdaCpa, float lambdaRadius, float lambdaPos, float kaonMass, float lambdaMass) { - const auto signPos = posTrack.sign(); - const auto signNeg = negTrack.sign(); - if (signPos < 0 || signNeg > 0) { - LOG(info) << "Something wrong in isSelectedMinimal"; - LOG(info) << "ERROR - Wrong sign for V0 daughters"; + if (lambdaPt < LambdaSelections.ptMin) { + return false; } - const float pT = v0.pt(); - const std::vector decVtx = {v0.x(), v0.y(), v0.z()}; - const float tranRad = v0.v0radius(); - const float dcaDaughv0 = v0.dcaV0daughters(); - const float cpav0 = v0.v0cosPA(); - - const float invMassLambda = v0.mLambda(); - const float invMassAntiLambda = v0.mAntiLambda(); - - if (charge > 0 && (invMassLambda < ConfV0InvMassLowLimit || invMassLambda > ConfV0InvMassUpLimit)) { + if (lambdaDauDca > LambdaSelections.dcaDaughMax) { return false; } - if (charge < 0 && (invMassAntiLambda < ConfV0InvMassLowLimit || invMassAntiLambda > ConfV0InvMassUpLimit)) { + if (lambdaCpa < LambdaSelections.cpaMin) { return false; } - if (ConfV0RejectKaons) { - const float invMassKaon = v0.mK0Short(); - if (invMassKaon > ConfV0InvKaonMassLowLimit && invMassKaon < ConfV0InvKaonMassUpLimit) { - return false; - } + if (lambdaRadius < LambdaSelections.tranRadMin) { + return false; } - if (pT < ConfV0PtMin) { + if (lambdaRadius > LambdaSelections.tranRadMax) { return false; } - if (dcaDaughv0 > ConfV0DCADaughMax) { + if (lambdaPos > LambdaSelections.decVtxMax) { return false; } - if (cpav0 < ConfV0CPAMin) { + if (LambdaSelections.rejectKaons) { + if (kaonMass > LambdaSelections.invKaonMassLow && kaonMass < LambdaSelections.invKaonMassUp) { + return false; + } + } + if (lambdaMass < LambdaSelections.invMassLow) { return false; } - if (tranRad < ConfV0TranRadV0Min) { + if (lambdaMass > LambdaSelections.invMassUp) { return false; } - if (tranRad > ConfV0TranRadV0Max) { + return true; + } + + template + bool checkLambdaDaughter(T const& track, float eta, float dca, float nSigmaTPC) + { + if (std::abs(eta) > LambdaDaughterSelections.absEtaMax.value) { return false; } - for (size_t i = 0; i < decVtx.size(); i++) { - if (decVtx.at(i) > ConfV0DecVtxMax) { - return false; - } + if (std::abs(dca) < LambdaDaughterSelections.dcaMin.value) { + return false; } - if (charge > 0) { - if (!isSelectedV0Daughter(posTrack, v0, 1, CFTrigger::kDaughProton, nSigmaTPCPos)) { - return false; - } - if (!isSelectedV0Daughter(negTrack, v0, -1, CFTrigger::kDaughPion, nSigmaTPCNeg)) { - return false; - } + if (track.tpcNClsFound() < LambdaDaughterSelections.tpcClusterMin.value) { + return false; } - if (charge < 0) { - if (!isSelectedV0Daughter(posTrack, v0, 1, CFTrigger::kDaughPion, nSigmaTPCPos)) { - return false; - } - if (!isSelectedV0Daughter(negTrack, v0, -1, CFTrigger::kDaughProton, nSigmaTPCNeg)) { - return false; - } + if (std::abs(nSigmaTPC) > LambdaDaughterSelections.tpcMax.value) { + return false; } return true; } @@ -1189,18 +1055,18 @@ struct CFFilter { const float betay = beta * std::sin(trackSum.Phi()) * std::sin(trackSum.Theta()); const float betaz = beta * std::cos(trackSum.Theta()); - ROOT::Math::PxPyPzMVector PartOneCMS(part1); - ROOT::Math::PxPyPzMVector PartTwoCMS(part2); + ROOT::Math::PxPyPzMVector partOneCMS(part1); + ROOT::Math::PxPyPzMVector partTwoCMS(part2); const ROOT::Math::Boost boostPRF = ROOT::Math::Boost(-betax, -betay, -betaz); - PartOneCMS = boostPRF(PartOneCMS); - PartTwoCMS = boostPRF(PartTwoCMS); - const ROOT::Math::PxPyPzMVector trackRelK = PartOneCMS - PartTwoCMS; + partOneCMS = boostPRF(partOneCMS); + partTwoCMS = boostPRF(partTwoCMS); + const ROOT::Math::PxPyPzMVector trackRelK = partOneCMS - partTwoCMS; return 0.5 * trackRelK.P(); } - ROOT::Math::PxPyPzEVector getqij(const ROOT::Math::PtEtaPhiMVector parti, - const ROOT::Math::PtEtaPhiMVector partj) + ROOT::Math::PxPyPzEVector + getqij(const ROOT::Math::PtEtaPhiMVector parti, const ROOT::Math::PtEtaPhiMVector partj) { ROOT::Math::PxPyPzEVector vecparti(parti); ROOT::Math::PxPyPzEVector vecpartj(partj); @@ -1209,825 +1075,1120 @@ struct CFFilter { float scaling = trackDifference.Dot(trackSum) / trackSum.Dot(trackSum); return trackDifference - scaling * trackSum; } - float getQ3(const ROOT::Math::PtEtaPhiMVector part1, - const ROOT::Math::PtEtaPhiMVector part2, - const ROOT::Math::PtEtaPhiMVector part3) + float getQ3(const ROOT::Math::PtEtaPhiMVector part1, const ROOT::Math::PtEtaPhiMVector part2, const ROOT::Math::PtEtaPhiMVector part3) { ROOT::Math::PxPyPzEVector q12 = getqij(part1, part2); ROOT::Math::PxPyPzEVector q23 = getqij(part2, part3); ROOT::Math::PxPyPzEVector q31 = getqij(part3, part1); - float Q32 = q12.M2() + q23.M2() + q31.M2(); - return sqrt(-Q32); + float q32 = q12.M2() + q23.M2() + q31.M2(); + return std::sqrt(-q32); } - std::vector setValuesBB(aod::BCsWithTimestamps::iterator const& bunchCrossing, const std::string ccdbPath) + template + float itsSignal(T const& track) { - map metadata; - auto h = ccdbApi.retrieveFromTFileAny(ccdbPath, metadata, bunchCrossing.timestamp()); - // auto h = ccdb->getForTimeStamp(ccdbPath, bunchCrossing.timestamp()); //check if possible to use this without getting fatal - if (!h) { - std::vector dummy; - LOG(info) << "File from CCDB in path " << ccdbPath << " was not found for run " << bunchCrossing.runNumber() << ". Will use default PID task values!"; - return dummy; - } - LOG(info) << "File from CCDB in path " << ccdbPath << " was found for run " << bunchCrossing.runNumber() << "!"; - - TAxis* axis = h->GetXaxis(); - std::vector v{static_cast(h->GetBinContent(axis->FindBin("bb1"))), - static_cast(h->GetBinContent(axis->FindBin("bb2"))), - static_cast(h->GetBinContent(axis->FindBin("bb3"))), - static_cast(h->GetBinContent(axis->FindBin("bb4"))), - static_cast(h->GetBinContent(axis->FindBin("bb5"))), - static_cast(h->GetBinContent(axis->FindBin("Resolution")))}; - return v; - } - - std::vector setValuesAvg(aod::BCsWithTimestamps::iterator const& bunchCrossing, const std::string ccdbPath) + uint32_t clsizeflag = track.itsClusterSizes(); + auto clSizeLayer0 = (clsizeflag >> (0 * 4)) & 0xf; + auto clSizeLayer1 = (clsizeflag >> (1 * 4)) & 0xf; + auto clSizeLayer2 = (clsizeflag >> (2 * 4)) & 0xf; + auto clSizeLayer3 = (clsizeflag >> (3 * 4)) & 0xf; + auto clSizeLayer4 = (clsizeflag >> (4 * 4)) & 0xf; + auto clSizeLayer5 = (clsizeflag >> (5 * 4)) & 0xf; + auto clSizeLayer6 = (clsizeflag >> (6 * 4)) & 0xf; + int numLayers = 7; + int sumClusterSizes = clSizeLayer1 + clSizeLayer2 + clSizeLayer3 + clSizeLayer4 + clSizeLayer5 + clSizeLayer6 + clSizeLayer0; + float cosLamnda = 1. / std::cosh(track.eta()); + return (static_cast(sumClusterSizes) / numLayers) * cosLamnda; + }; + + void process(cf_trigger::FullCollision const& col, aod::BCs const&, cf_trigger::FullTracks const& tracks, o2::aod::V0s const& v0s) { - map metadata; - auto h = ccdbApi.retrieveFromTFileAny(ccdbPath, metadata, bunchCrossing.timestamp()); - // auto h = ccdb->getForTimeStamp(ccdbPath, bunchCrossing.timestamp()); //check if possible to use this without getting fatal - if (!h) { - std::vector dummy{ConfPIDTPCTOFAvg->get("Proton", "TPC Avg"), - ConfPIDTPCTOFAvg->get("Proton", "TOF Avg"), - ConfPIDTPCTOFAvg->get("AntiProton", "TPC Avg"), - ConfPIDTPCTOFAvg->get("AntiProton", "TOF Avg"), - ConfPIDTPCTOFAvg->get("Deuteron", "TPC Avg"), - ConfPIDTPCTOFAvg->get("Deuteron", "TOF Avg"), - ConfPIDTPCTOFAvg->get("AntiDeuteron", "TPC Avg"), - ConfPIDTPCTOFAvg->get("AntiDeuteron", "TOF Avg")}; - LOG(info) << "File from CCDB in path " << ccdbPath << " was not found for run " << bunchCrossing.runNumber() << ". Will use constant values from ConfPIDTPCTOFAvg!"; - return dummy; - } - LOG(info) << "File from CCDB in path " << ccdbPath << " was found for run " << bunchCrossing.runNumber() << "!"; - - TAxis* axis = h->GetXaxis(); - std::vector v{static_cast(h->GetBinContent(axis->FindBin("TPCProton"))), - static_cast(h->GetBinContent(axis->FindBin("TOFProton"))), - static_cast(h->GetBinContent(axis->FindBin("TPCAntiproton"))), - static_cast(h->GetBinContent(axis->FindBin("TOFAntiproton"))), - static_cast(h->GetBinContent(axis->FindBin("TPCDeuteron"))), - static_cast(h->GetBinContent(axis->FindBin("TOFDeuteron"))), - static_cast(h->GetBinContent(axis->FindBin("TPCAntideuteron"))), - static_cast(h->GetBinContent(axis->FindBin("TOFAntideuteron")))}; - return v; - } - template - double updatePID(T const& track, double bgScaling, std::vector BB) - { - double expBethe = tpc::BetheBlochAleph(static_cast(track.tpcInnerParam() * bgScaling), BB[0], BB[1], BB[2], BB[3], BB[4]); - double expSigma = expBethe * BB[5]; - return static_cast((track.tpcSignal() - expBethe) / expSigma); - } + auto tracksWithItsPid = soa::Attach(tracks); - void process(aod::FemtoFullCollision const& col, aod::BCsWithTimestamps const&, aod::FemtoFullTracks const& tracks, o2::aod::V0Datas const& fullV0s) - { + registry.fill(HIST("fProcessedEvents"), 0); + registry.fill(HIST("EventQA/Before/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("EventQA/Before/fZvtx"), col.posZ()); - if (!ConfIsRun3) { - LOG(fatal) << "Run 2 processing is not implemented!"; + if (!checkEvent(col)) { + return; } - if (ConfUseManualPIDproton || ConfUseManualPIDdeuteron || ConfUseAvgFromCCDB) { - currentRunNumber = col.bc_as().runNumber(); - if (currentRunNumber != lastRunNumber) { - auto bc = col.bc_as(); - if (ConfUseManualPIDproton || ConfUseManualPIDdaughterProton) { - BBProton = setValuesBB(bc, ConfPIDBBProton); - BBAntiproton = setValuesBB(bc, ConfPIDBBAntiProton); + registry.fill(HIST("EventQA/After/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("EventQA/After/fZvtx"), col.posZ()); + + initCCDB(col.bc().runNumber()); + + // clear particle vectors + vecProton.clear(); + vecAntiProton.clear(); + vecDeuteron.clear(); + vecAntiDeuteron.clear(); + vecLambda.clear(); + vecAntiLambda.clear(); + vecKaon.clear(); + vecAntiKaon.clear(); + vecPhi.clear(); + vecPion.clear(); + vecAntiPion.clear(); + vecRho.clear(); + // clear index vectors for all particles + idxProton.clear(); + idxAntiProton.clear(); + idxDeuteron.clear(); + idxAntiDeuteron.clear(); + idxKaon.clear(); + idxAntiKaon.clear(); + idxPion.clear(); + idxAntiPion.clear(); + // clear index vectors for daughters + idxLambdaDaughProton.clear(); + idxLambdaDaughPion.clear(); + idxAntiLambdaDaughProton.clear(); + idxAntiLambdaDaughPion.clear(); + idxPhiDaughPos.clear(); + idxPhiDaughNeg.clear(); + idxRhoDaughPos.clear(); + idxRhoDaughNeg.clear(); + + for (auto const& track : tracksWithItsPid) { + + // get paritcles + if (track.sign() > 0) { + registry.fill(HIST("TrackQA/Before/Particle/fPt"), track.pt()); + registry.fill(HIST("TrackQA/Before/Particle/fEta"), track.eta()); + registry.fill(HIST("TrackQA/Before/Particle/fPhi"), track.phi()); + registry.fill(HIST("TrackQA/Before/Particle/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registry.fill(HIST("TrackQA/Before/Particle/fItsSignal"), track.p(), itsSignal(track)); + registry.fill(HIST("TrackQA/Before/Particle/fTpcSignal"), track.p(), track.tpcSignal()); + registry.fill(HIST("TrackQA/Before/Particle/fTofSignal"), track.p(), track.beta()); + + registry.fill(HIST("TrackQA/Before/Pion/fNsigmaITS"), track.p(), track.itsNSigmaPi()); + registry.fill(HIST("TrackQA/Before/Pion/fNsigmaTPC"), track.p(), track.tpcNSigmaPi()); + registry.fill(HIST("TrackQA/Before/Pion/fNsigmaTOF"), track.p(), track.tofNSigmaPi()); + registry.fill(HIST("TrackQA/Before/Pion/fNsigmaTPCTOF"), track.p(), RecoDecay::sqrtSumOfSquares(track.tpcNSigmaPi(), track.tofNSigmaPi())); + + registry.fill(HIST("TrackQA/Before/Kaon/fNsigmaITS"), track.p(), track.itsNSigmaKa()); + registry.fill(HIST("TrackQA/Before/Kaon/fNsigmaTPC"), track.p(), track.tpcNSigmaKa()); + registry.fill(HIST("TrackQA/Before/Kaon/fNsigmaTOF"), track.p(), track.tofNSigmaKa()); + registry.fill(HIST("TrackQA/Before/Kaon/fNsigmaTPCTOF"), track.p(), RecoDecay::sqrtSumOfSquares(track.tpcNSigmaKa(), track.tofNSigmaKa())); + + registry.fill(HIST("TrackQA/Before/Proton/fNsigmaITS"), track.p(), track.itsNSigmaPr()); + registry.fill(HIST("TrackQA/Before/Proton/fNsigmaTPC"), track.p(), track.tpcNSigmaPr()); + registry.fill(HIST("TrackQA/Before/Proton/fNsigmaTOF"), track.p(), track.tofNSigmaPr()); + registry.fill(HIST("TrackQA/Before/Proton/fNsigmaTPCTOF"), track.p(), RecoDecay::sqrtSumOfSquares(track.tpcNSigmaPr(), track.tofNSigmaPr())); + + registry.fill(HIST("TrackQA/Before/Deuteron/fNsigmaITS"), track.p(), track.itsNSigmaDe()); + registry.fill(HIST("TrackQA/Before/Deuteron/fNsigmaTPC"), track.p(), track.tpcNSigmaDe()); + registry.fill(HIST("TrackQA/Before/Deuteron/fNsigmaTOF"), track.p(), track.tofNSigmaDe()); + registry.fill(HIST("TrackQA/Before/Deuteron/fNsigmaTPCTOF"), track.p(), RecoDecay::sqrtSumOfSquares(track.tpcNSigmaDe(), track.tofNSigmaDe())); + + if (checkTrack(track, std::string("Pion")) && checkTrackPid(track, std::string("Pion"))) { + vecPion.emplace_back(track.pt(), track.eta(), track.phi(), o2::constants::physics::MassPionCharged); + idxPion.push_back(track.globalIndex()); + + registry.fill(HIST("TrackQA/After/Pion/fPt"), track.pt()); + registry.fill(HIST("TrackQA/After/Pion/fPTpc"), track.tpcInnerParam()); + registry.fill(HIST("TrackQA/After/Pion/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registry.fill(HIST("TrackQA/After/Pion/fEta"), track.eta()); + registry.fill(HIST("TrackQA/After/Pion/fPhi"), track.phi()); + + registry.fill(HIST("TrackQA/After/Pion/fNsigmaIts"), track.p(), track.itsNSigmaPi()); + registry.fill(HIST("TrackQA/After/Pion/fNsigmaTpc"), track.p(), track.tpcNSigmaPi()); + registry.fill(HIST("TrackQA/After/Pion/fNsigmaTof"), track.p(), track.tofNSigmaPi()); + registry.fill(HIST("TrackQA/After/Pion/fNsigmaTpcTof"), track.p(), RecoDecay::sqrtSumOfSquares(track.tpcNSigmaPi(), track.tofNSigmaPi())); + + registry.fill(HIST("TrackQA/After/Pion/fItsSignal"), track.p(), itsSignal(track)); + registry.fill(HIST("TrackQA/After/Pion/fTpcSignal"), track.p(), track.tpcSignal()); + registry.fill(HIST("TrackQA/After/Pion/fTofBeta"), track.p(), track.beta()); + + registry.fill(HIST("TrackQA/After/Pion/fDcaXy"), track.pt(), track.dcaXY()); + registry.fill(HIST("TrackQA/After/Pion/fDcaZ"), track.pt(), track.dcaZ()); + + registry.fill(HIST("TrackQA/After/Pion/fTpcClusters"), track.tpcNClsFound()); + registry.fill(HIST("TrackQA/After/Pion/fTpcCrossedRows"), track.tpcNClsCrossedRows()); + registry.fill(HIST("TrackQA/After/Pion/fTpcSharedClusters"), track.tpcNClsShared()); + registry.fill(HIST("TrackQA/After/Pion/fTpcSharedClusterOverClusterss"), track.tpcFractionSharedCls()); + registry.fill(HIST("TrackQA/After/Pion/fTpcFindableOverRows"), track.tpcCrossedRowsOverFindableCls()); + registry.fill(HIST("TrackQA/After/Pion/fTpcChi2OverCluster"), track.tpcChi2NCl()); + + registry.fill(HIST("TrackQA/After/Pion/fItsClusters"), track.itsNCls()); + registry.fill(HIST("TrackQA/After/Pion/fItsIbClusters"), track.itsNClsInnerBarrel()); + registry.fill(HIST("TrackQA/After/Pion/fItsChi2OverCluster"), track.itsChi2NCl()); } - if (ConfUseManualPIDdeuteron) { - BBDeuteron = setValuesBB(bc, ConfPIDBBDeuteron); - BBAntideuteron = setValuesBB(bc, ConfPIDBBAntiDeuteron); - } - if (ConfUseManualPIDpion || ConfUseManualPIDdaughterPion) { - BBPion = setValuesBB(bc, ConfPIDBBPion); - BBAntipion = setValuesBB(bc, ConfPIDBBAntiPion); + + if (checkTrack(track, std::string("Kaon")) && checkTrackPid(track, std::string("Kaon"))) { + vecKaon.emplace_back(track.pt(), track.eta(), track.phi(), o2::constants::physics::MassKaonCharged); + idxKaon.push_back(track.globalIndex()); + + registry.fill(HIST("TrackQA/After/Kaon/fPt"), track.pt()); + registry.fill(HIST("TrackQA/After/Kaon/fPTpc"), track.tpcInnerParam()); + registry.fill(HIST("TrackQA/After/Kaon/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registry.fill(HIST("TrackQA/After/Kaon/fEta"), track.eta()); + registry.fill(HIST("TrackQA/After/Kaon/fPhi"), track.phi()); + + registry.fill(HIST("TrackQA/After/Kaon/fNsigmaIts"), track.p(), track.itsNSigmaKa()); + registry.fill(HIST("TrackQA/After/Kaon/fNsigmaTpc"), track.p(), track.tpcNSigmaKa()); + registry.fill(HIST("TrackQA/After/Kaon/fNsigmaTof"), track.p(), track.tofNSigmaKa()); + registry.fill(HIST("TrackQA/After/Kaon/fNsigmaTpcTof"), track.p(), RecoDecay::sqrtSumOfSquares(track.tpcNSigmaKa(), track.tofNSigmaKa())); + + registry.fill(HIST("TrackQA/After/Kaon/fItsSignal"), track.p(), itsSignal(track)); + registry.fill(HIST("TrackQA/After/Kaon/fTpcSignal"), track.p(), track.tpcSignal()); + registry.fill(HIST("TrackQA/After/Kaon/fTofBeta"), track.p(), track.beta()); + + registry.fill(HIST("TrackQA/After/Kaon/fDcaXy"), track.pt(), track.dcaXY()); + registry.fill(HIST("TrackQA/After/Kaon/fDcaZ"), track.pt(), track.dcaZ()); + + registry.fill(HIST("TrackQA/After/Kaon/fTpcClusters"), track.tpcNClsFound()); + registry.fill(HIST("TrackQA/After/Kaon/fTpcCrossedRows"), track.tpcNClsCrossedRows()); + registry.fill(HIST("TrackQA/After/Kaon/fTpcSharedClusters"), track.tpcNClsShared()); + registry.fill(HIST("TrackQA/After/Kaon/fTpcSharedClusterOverClusterss"), track.tpcFractionSharedCls()); + registry.fill(HIST("TrackQA/After/Kaon/fTpcFindableOverRows"), track.tpcCrossedRowsOverFindableCls()); + registry.fill(HIST("TrackQA/After/Kaon/fTpcChi2OverCluster"), track.tpcChi2NCl()); + + registry.fill(HIST("TrackQA/After/Kaon/fItsClusters"), track.itsNCls()); + registry.fill(HIST("TrackQA/After/Kaon/fItsIbClusters"), track.itsNClsInnerBarrel()); + registry.fill(HIST("TrackQA/After/Kaon/fItsChi2OverCluster"), track.itsChi2NCl()); } - if (ConfUseManualPIDpion) { - BBElectron = setValuesBB(bc, ConfPIDBBElectron); - BBAntielectron = setValuesBB(bc, ConfPIDBBAntiElectron); + + if (checkTrack(track, std::string("Proton")) && checkTrackPid(track, std::string("Proton"))) { + vecProton.emplace_back(track.pt(), track.eta(), track.phi(), o2::constants::physics::MassProton); + idxProton.push_back(track.globalIndex()); + + registry.fill(HIST("TrackQA/After/Proton/fPt"), track.pt()); + registry.fill(HIST("TrackQA/After/Proton/fPTpc"), track.tpcInnerParam()); + registry.fill(HIST("TrackQA/After/Proton/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registry.fill(HIST("TrackQA/After/Proton/fEta"), track.eta()); + registry.fill(HIST("TrackQA/After/Proton/fPhi"), track.phi()); + + registry.fill(HIST("TrackQA/After/Proton/fNsigmaIts"), track.p(), track.itsNSigmaPr()); + registry.fill(HIST("TrackQA/After/Proton/fNsigmaTpc"), track.p(), track.tpcNSigmaPr()); + registry.fill(HIST("TrackQA/After/Proton/fNsigmaTof"), track.p(), track.tofNSigmaPr()); + registry.fill(HIST("TrackQA/After/Proton/fNsigmaTpcTof"), track.p(), RecoDecay::sqrtSumOfSquares(track.tpcNSigmaPr(), track.tofNSigmaPr())); + + registry.fill(HIST("TrackQA/After/Proton/fItsSignal"), track.p(), itsSignal(track)); + registry.fill(HIST("TrackQA/After/Proton/fTpcSignal"), track.p(), track.tpcSignal()); + registry.fill(HIST("TrackQA/After/Proton/fTofBeta"), track.p(), track.beta()); + + registry.fill(HIST("TrackQA/After/Proton/fDcaXy"), track.pt(), track.dcaXY()); + registry.fill(HIST("TrackQA/After/Proton/fDcaZ"), track.pt(), track.dcaZ()); + + registry.fill(HIST("TrackQA/After/Proton/fTpcClusters"), track.tpcNClsFound()); + registry.fill(HIST("TrackQA/After/Proton/fTpcCrossedRows"), track.tpcNClsCrossedRows()); + registry.fill(HIST("TrackQA/After/Proton/fTpcSharedClusters"), track.tpcNClsShared()); + registry.fill(HIST("TrackQA/After/Proton/fTpcSharedClusterOverClusterss"), track.tpcFractionSharedCls()); + registry.fill(HIST("TrackQA/After/Proton/fTpcFindableOverRows"), track.tpcCrossedRowsOverFindableCls()); + registry.fill(HIST("TrackQA/After/Proton/fTpcChi2OverCluster"), track.tpcChi2NCl()); + + registry.fill(HIST("TrackQA/After/Proton/fItsClusters"), track.itsNCls()); + registry.fill(HIST("TrackQA/After/Proton/fItsIbClusters"), track.itsNClsInnerBarrel()); + registry.fill(HIST("TrackQA/After/Proton/fItsChi2OverCluster"), track.itsChi2NCl()); } - if (ConfUseAvgFromCCDB) { - TPCTOFAvg = setValuesAvg(bc, ConfAvgPath); + + if (checkTrack(track, std::string("Deuteron")) && checkTrackPid(track, std::string("Deuteron"))) { + vecDeuteron.emplace_back(track.pt(), track.eta(), track.phi(), o2::constants::physics::MassDeuteron); + idxDeuteron.push_back(track.globalIndex()); + + registry.fill(HIST("TrackQA/After/Deuteron/fPt"), track.pt()); + registry.fill(HIST("TrackQA/After/Deuteron/fPTpc"), track.tpcInnerParam()); + registry.fill(HIST("TrackQA/After/Deuteron/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registry.fill(HIST("TrackQA/After/Deuteron/fEta"), track.eta()); + registry.fill(HIST("TrackQA/After/Deuteron/fPhi"), track.phi()); + + registry.fill(HIST("TrackQA/After/Deuteron/fNsigmaIts"), track.p(), track.itsNSigmaDe()); + registry.fill(HIST("TrackQA/After/Deuteron/fNsigmaTpc"), track.p(), track.tpcNSigmaDe()); + registry.fill(HIST("TrackQA/After/Deuteron/fNsigmaTof"), track.p(), track.tofNSigmaDe()); + registry.fill(HIST("TrackQA/After/Deuteron/fNsigmaTpcTof"), track.p(), RecoDecay::sqrtSumOfSquares(track.tpcNSigmaDe(), track.tofNSigmaDe())); + + registry.fill(HIST("TrackQA/After/Deuteron/fItsSignal"), track.p(), itsSignal(track)); + registry.fill(HIST("TrackQA/After/Deuteron/fTpcSignal"), track.p(), track.tpcSignal()); + registry.fill(HIST("TrackQA/After/Deuteron/fTofBeta"), track.p(), track.beta()); + + registry.fill(HIST("TrackQA/After/Deuteron/fDcaXy"), track.pt(), track.dcaXY()); + registry.fill(HIST("TrackQA/After/Deuteron/fDcaZ"), track.pt(), track.dcaZ()); + + registry.fill(HIST("TrackQA/After/Deuteron/fTpcClusters"), track.tpcNClsFound()); + registry.fill(HIST("TrackQA/After/Deuteron/fTpcCrossedRows"), track.tpcNClsCrossedRows()); + registry.fill(HIST("TrackQA/After/Deuteron/fTpcSharedClusters"), track.tpcNClsShared()); + registry.fill(HIST("TrackQA/After/Deuteron/fTpcSharedClusterOverClusterss"), track.tpcFractionSharedCls()); + registry.fill(HIST("TrackQA/After/Deuteron/fTpcFindableOverRows"), track.tpcCrossedRowsOverFindableCls()); + registry.fill(HIST("TrackQA/After/Deuteron/fTpcChi2OverCluster"), track.tpcChi2NCl()); + + registry.fill(HIST("TrackQA/After/Deuteron/fItsClusters"), track.itsNCls()); + registry.fill(HIST("TrackQA/After/Deuteron/fItsIbClusters"), track.itsNClsInnerBarrel()); + registry.fill(HIST("TrackQA/After/Deuteron/fItsChi2OverCluster"), track.itsChi2NCl()); } - lastRunNumber = currentRunNumber; } - } - registry.fill(HIST("fProcessedEvents"), 0); - registry.fill(HIST("EventCuts/fMultiplicityBefore"), col.multNTracksPV()); - registry.fill(HIST("EventCuts/fZvtxBefore"), col.posZ()); + if (track.sign() < 0) { + registry.fill(HIST("TrackQA/Before/AntiParticle/fPt"), track.pt()); + registry.fill(HIST("TrackQA/Before/AntiParticle/fEta"), track.eta()); + registry.fill(HIST("TrackQA/Before/AntiParticle/fPhi"), track.phi()); + registry.fill(HIST("TrackQA/Before/AntiParticle/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registry.fill(HIST("TrackQA/Before/AntiParticle/fItsSignal"), track.p(), itsSignal(track)); + registry.fill(HIST("TrackQA/Before/AntiParticle/fTpcSignal"), track.p(), track.tpcSignal()); + registry.fill(HIST("TrackQA/Before/AntiParticle/fTofSignal"), track.p(), track.beta()); + + registry.fill(HIST("TrackQA/Before/AntiPion/fNsigmaITS"), track.p(), track.itsNSigmaPi()); + registry.fill(HIST("TrackQA/Before/AntiPion/fNsigmaTPC"), track.p(), track.tpcNSigmaPi()); + registry.fill(HIST("TrackQA/Before/AntiPion/fNsigmaTOF"), track.p(), track.tofNSigmaPi()); + registry.fill(HIST("TrackQA/Before/AntiPion/fNsigmaTPCTOF"), track.p(), RecoDecay::sqrtSumOfSquares(track.tpcNSigmaPi(), track.tofNSigmaPi())); + + registry.fill(HIST("TrackQA/Before/AntiKaon/fNsigmaITS"), track.p(), track.itsNSigmaKa()); + registry.fill(HIST("TrackQA/Before/AntiKaon/fNsigmaTPC"), track.p(), track.tpcNSigmaKa()); + registry.fill(HIST("TrackQA/Before/AntiKaon/fNsigmaTOF"), track.p(), track.tofNSigmaKa()); + registry.fill(HIST("TrackQA/Before/AntiKaon/fNsigmaTPCTOF"), track.p(), RecoDecay::sqrtSumOfSquares(track.tpcNSigmaKa(), track.tofNSigmaKa())); + + registry.fill(HIST("TrackQA/Before/AntiProton/fNsigmaITS"), track.p(), track.itsNSigmaPr()); + registry.fill(HIST("TrackQA/Before/AntiProton/fNsigmaTPC"), track.p(), track.tpcNSigmaPr()); + registry.fill(HIST("TrackQA/Before/AntiProton/fNsigmaTOF"), track.p(), track.tofNSigmaPr()); + registry.fill(HIST("TrackQA/Before/AntiProton/fNsigmaTPCTOF"), track.p(), RecoDecay::sqrtSumOfSquares(track.tpcNSigmaPr(), track.tofNSigmaPr())); + + registry.fill(HIST("TrackQA/Before/AntiDeuteron/fNsigmaITS"), track.p(), track.itsNSigmaDe()); + registry.fill(HIST("TrackQA/Before/AntiDeuteron/fNsigmaTPC"), track.p(), track.tpcNSigmaDe()); + registry.fill(HIST("TrackQA/Before/AntiDeuteron/fNsigmaTOF"), track.p(), track.tofNSigmaDe()); + registry.fill(HIST("TrackQA/Before/AntiDeuteron/fNsigmaTPCTOF"), track.p(), RecoDecay::sqrtSumOfSquares(track.tpcNSigmaDe(), track.tofNSigmaDe())); + + if (checkTrack(track, std::string("Pion")) && checkTrackPid(track, std::string("Pion"))) { + vecAntiPion.emplace_back(track.pt(), track.eta(), track.phi(), o2::constants::physics::MassPionCharged); + idxAntiPion.push_back(track.globalIndex()); + + registry.fill(HIST("TrackQA/After/AntiPion/fPt"), track.pt()); + registry.fill(HIST("TrackQA/After/AntiPion/fPTpc"), track.tpcInnerParam()); + registry.fill(HIST("TrackQA/After/AntiPion/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registry.fill(HIST("TrackQA/After/AntiPion/fEta"), track.eta()); + registry.fill(HIST("TrackQA/After/AntiPion/fPhi"), track.phi()); + + registry.fill(HIST("TrackQA/After/AntiPion/fNsigmaIts"), track.p(), track.itsNSigmaPi()); + registry.fill(HIST("TrackQA/After/AntiPion/fNsigmaTpc"), track.p(), track.tpcNSigmaPi()); + registry.fill(HIST("TrackQA/After/AntiPion/fNsigmaTof"), track.p(), track.tofNSigmaPi()); + registry.fill(HIST("TrackQA/After/AntiPion/fNsigmaTpcTof"), track.p(), RecoDecay::sqrtSumOfSquares(track.tpcNSigmaPi(), track.tofNSigmaPi())); + + registry.fill(HIST("TrackQA/After/AntiPion/fItsSignal"), track.p(), itsSignal(track)); + registry.fill(HIST("TrackQA/After/AntiPion/fTpcSignal"), track.p(), track.tpcSignal()); + registry.fill(HIST("TrackQA/After/AntiPion/fTofBeta"), track.p(), track.beta()); + + registry.fill(HIST("TrackQA/After/AntiPion/fDcaXy"), track.pt(), track.dcaXY()); + registry.fill(HIST("TrackQA/After/AntiPion/fDcaZ"), track.pt(), track.dcaZ()); + + registry.fill(HIST("TrackQA/After/AntiPion/fTpcClusters"), track.tpcNClsFound()); + registry.fill(HIST("TrackQA/After/AntiPion/fTpcCrossedRows"), track.tpcNClsCrossedRows()); + registry.fill(HIST("TrackQA/After/AntiPion/fTpcSharedClusters"), track.tpcNClsShared()); + registry.fill(HIST("TrackQA/After/AntiPion/fTpcSharedClusterOverClusterss"), track.tpcFractionSharedCls()); + registry.fill(HIST("TrackQA/After/AntiPion/fTpcFindableOverRows"), track.tpcCrossedRowsOverFindableCls()); + registry.fill(HIST("TrackQA/After/AntiPion/fTpcChi2OverCluster"), track.tpcChi2NCl()); + + registry.fill(HIST("TrackQA/After/AntiPion/fItsClusters"), track.itsNCls()); + registry.fill(HIST("TrackQA/After/AntiPion/fItsIbClusters"), track.itsNClsInnerBarrel()); + registry.fill(HIST("TrackQA/After/AntiPion/fItsChi2OverCluster"), track.itsChi2NCl()); + } - bool keepEvent3N[CFTrigger::kNThreeBodyTriggers] = {false, false, false, false}; - int lowQ3Triplets[CFTrigger::kNThreeBodyTriggers] = {0, 0, 0, 0}; + if (checkTrack(track, std::string("Kaon")) && checkTrackPid(track, std::string("Kaon"))) { + vecAntiKaon.emplace_back(track.pt(), track.eta(), track.phi(), o2::constants::physics::MassKaonCharged); + idxAntiKaon.push_back(track.globalIndex()); + + registry.fill(HIST("TrackQA/After/AntiKaon/fPt"), track.pt()); + registry.fill(HIST("TrackQA/After/AntiKaon/fPTpc"), track.tpcInnerParam()); + registry.fill(HIST("TrackQA/After/AntiKaon/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registry.fill(HIST("TrackQA/After/AntiKaon/fEta"), track.eta()); + registry.fill(HIST("TrackQA/After/AntiKaon/fPhi"), track.phi()); + + registry.fill(HIST("TrackQA/After/AntiKaon/fNsigmaIts"), track.p(), track.itsNSigmaKa()); + registry.fill(HIST("TrackQA/After/AntiKaon/fNsigmaTpc"), track.p(), track.tpcNSigmaKa()); + registry.fill(HIST("TrackQA/After/AntiKaon/fNsigmaTof"), track.p(), track.tofNSigmaKa()); + registry.fill(HIST("TrackQA/After/AntiKaon/fNsigmaTpcTof"), track.p(), RecoDecay::sqrtSumOfSquares(track.tpcNSigmaKa(), track.tofNSigmaKa())); + + registry.fill(HIST("TrackQA/After/AntiKaon/fItsSignal"), track.p(), itsSignal(track)); + registry.fill(HIST("TrackQA/After/AntiKaon/fTpcSignal"), track.p(), track.tpcSignal()); + registry.fill(HIST("TrackQA/After/AntiKaon/fTofBeta"), track.p(), track.beta()); + + registry.fill(HIST("TrackQA/After/AntiKaon/fDcaXy"), track.pt(), track.dcaXY()); + registry.fill(HIST("TrackQA/After/AntiKaon/fDcaZ"), track.pt(), track.dcaZ()); + + registry.fill(HIST("TrackQA/After/AntiKaon/fTpcClusters"), track.tpcNClsFound()); + registry.fill(HIST("TrackQA/After/AntiKaon/fTpcCrossedRows"), track.tpcNClsCrossedRows()); + registry.fill(HIST("TrackQA/After/AntiKaon/fTpcSharedClusters"), track.tpcNClsShared()); + registry.fill(HIST("TrackQA/After/AntiKaon/fTpcSharedClusterOverClusterss"), track.tpcFractionSharedCls()); + registry.fill(HIST("TrackQA/After/AntiKaon/fTpcFindableOverRows"), track.tpcCrossedRowsOverFindableCls()); + registry.fill(HIST("TrackQA/After/AntiKaon/fTpcChi2OverCluster"), track.tpcChi2NCl()); + + registry.fill(HIST("TrackQA/After/AntiKaon/fItsClusters"), track.itsNCls()); + registry.fill(HIST("TrackQA/After/AntiKaon/fItsIbClusters"), track.itsNClsInnerBarrel()); + registry.fill(HIST("TrackQA/After/AntiKaon/fItsChi2OverCluster"), track.itsChi2NCl()); + } - bool keepEvent2N[CFTrigger::kNTwoBodyTriggers] = {false, false}; - int lowKstarPairs[CFTrigger::kNTwoBodyTriggers] = {0, 0}; + if (checkTrack(track, std::string("Proton")) && checkTrackPid(track, std::string("Proton"))) { + vecAntiProton.emplace_back(track.pt(), track.eta(), track.phi(), o2::constants::physics::MassProton); + idxAntiProton.push_back(track.globalIndex()); + + registry.fill(HIST("TrackQA/After/AntiProton/fPt"), track.pt()); + registry.fill(HIST("TrackQA/After/AntiProton/fPTpc"), track.tpcInnerParam()); + registry.fill(HIST("TrackQA/After/AntiProton/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registry.fill(HIST("TrackQA/After/AntiProton/fEta"), track.eta()); + registry.fill(HIST("TrackQA/After/AntiProton/fPhi"), track.phi()); + + registry.fill(HIST("TrackQA/After/AntiProton/fNsigmaIts"), track.p(), track.itsNSigmaPr()); + registry.fill(HIST("TrackQA/After/AntiProton/fNsigmaTpc"), track.p(), track.tpcNSigmaPr()); + registry.fill(HIST("TrackQA/After/AntiProton/fNsigmaTof"), track.p(), track.tofNSigmaPr()); + registry.fill(HIST("TrackQA/After/AntiProton/fNsigmaTpcTof"), track.p(), RecoDecay::sqrtSumOfSquares(track.tpcNSigmaPr(), track.tofNSigmaPr())); + + registry.fill(HIST("TrackQA/After/AntiProton/fItsSignal"), track.p(), itsSignal(track)); + registry.fill(HIST("TrackQA/After/AntiProton/fTpcSignal"), track.p(), track.tpcSignal()); + registry.fill(HIST("TrackQA/After/AntiProton/fTofBeta"), track.p(), track.beta()); + + registry.fill(HIST("TrackQA/After/AntiProton/fDcaXy"), track.pt(), track.dcaXY()); + registry.fill(HIST("TrackQA/After/AntiProton/fDcaZ"), track.pt(), track.dcaZ()); + + registry.fill(HIST("TrackQA/After/AntiProton/fTpcClusters"), track.tpcNClsFound()); + registry.fill(HIST("TrackQA/After/AntiProton/fTpcCrossedRows"), track.tpcNClsCrossedRows()); + registry.fill(HIST("TrackQA/After/AntiProton/fTpcSharedClusters"), track.tpcNClsShared()); + registry.fill(HIST("TrackQA/After/AntiProton/fTpcSharedClusterOverClusterss"), track.tpcFractionSharedCls()); + registry.fill(HIST("TrackQA/After/AntiProton/fTpcFindableOverRows"), track.tpcCrossedRowsOverFindableCls()); + registry.fill(HIST("TrackQA/After/AntiProton/fTpcChi2OverCluster"), track.tpcChi2NCl()); + + registry.fill(HIST("TrackQA/After/AntiProton/fItsClusters"), track.itsNCls()); + registry.fill(HIST("TrackQA/After/AntiProton/fItsIbClusters"), track.itsNClsInnerBarrel()); + registry.fill(HIST("TrackQA/After/AntiProton/fItsChi2OverCluster"), track.itsChi2NCl()); + } - if (isSelectedEvent(col)) { + if (checkTrack(track, std::string("Deuteron")) && checkTrackPid(track, std::string("Deuteron"))) { + vecAntiDeuteron.emplace_back(track.pt(), track.eta(), track.phi(), o2::constants::physics::MassDeuteron); + idxAntiDeuteron.push_back(track.globalIndex()); + + registry.fill(HIST("TrackQA/After/AntiDeuteron/fPt"), track.pt()); + registry.fill(HIST("TrackQA/After/AntiDeuteron/fPTpc"), track.tpcInnerParam()); + registry.fill(HIST("TrackQA/After/AntiDeuteron/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registry.fill(HIST("TrackQA/After/AntiDeuteron/fEta"), track.eta()); + registry.fill(HIST("TrackQA/After/AntiDeuteron/fPhi"), track.phi()); + + registry.fill(HIST("TrackQA/After/AntiDeuteron/fNsigmaIts"), track.p(), track.itsNSigmaDe()); + registry.fill(HIST("TrackQA/After/AntiDeuteron/fNsigmaTpc"), track.p(), track.tpcNSigmaDe()); + registry.fill(HIST("TrackQA/After/AntiDeuteron/fNsigmaTof"), track.p(), track.tofNSigmaDe()); + registry.fill(HIST("TrackQA/After/AntiDeuteron/fNsigmaTpcTof"), track.p(), RecoDecay::sqrtSumOfSquares(track.tpcNSigmaDe(), track.tofNSigmaDe())); + + registry.fill(HIST("TrackQA/After/AntiDeuteron/fItsSignal"), track.p(), itsSignal(track)); + registry.fill(HIST("TrackQA/After/AntiDeuteron/fTpcSignal"), track.p(), track.tpcSignal()); + registry.fill(HIST("TrackQA/After/AntiDeuteron/fTofBeta"), track.p(), track.beta()); + + registry.fill(HIST("TrackQA/After/AntiDeuteron/fDcaXy"), track.pt(), track.dcaXY()); + registry.fill(HIST("TrackQA/After/AntiDeuteron/fDcaZ"), track.pt(), track.dcaZ()); + + registry.fill(HIST("TrackQA/After/AntiDeuteron/fTpcClusters"), track.tpcNClsFound()); + registry.fill(HIST("TrackQA/After/AntiDeuteron/fTpcCrossedRows"), track.tpcNClsCrossedRows()); + registry.fill(HIST("TrackQA/After/AntiDeuteron/fTpcSharedClusters"), track.tpcNClsShared()); + registry.fill(HIST("TrackQA/After/AntiDeuteron/fTpcSharedClusterOverClusterss"), track.tpcFractionSharedCls()); + registry.fill(HIST("TrackQA/After/AntiDeuteron/fTpcFindableOverRows"), track.tpcCrossedRowsOverFindableCls()); + registry.fill(HIST("TrackQA/After/AntiDeuteron/fTpcChi2OverCluster"), track.tpcChi2NCl()); + + registry.fill(HIST("TrackQA/After/AntiDeuteron/fItsClusters"), track.itsNCls()); + registry.fill(HIST("TrackQA/After/AntiDeuteron/fItsIbClusters"), track.itsNClsInnerBarrel()); + registry.fill(HIST("TrackQA/After/AntiDeuteron/fItsChi2OverCluster"), track.itsChi2NCl()); + } + } + } - registry.fill(HIST("EventCuts/fMultiplicityAfter"), col.multNTracksPV()); - registry.fill(HIST("EventCuts/fZvtxAfter"), col.posZ()); + // loop over and build v0s + for (auto const& v0 : v0s) { - // keep track of proton indices - std::vector ProtonIndex = {}; - std::vector AntiProtonIndex = {}; + auto posTrack = v0.posTrack_as(); + auto negTrack = v0.negTrack_as(); - // Prepare vectors for different species - std::vector protons, antiprotons, deuterons, antideuterons, lambdas, antilambdas; + auto posTrackPar = getTrackParCov(posTrack); + auto negTrackPar = getTrackParCov(negTrack); - // create deuteron and proton vectors (and corresponding antiparticles) for pair and triplet creation - for (auto& track : tracks) { + if (!mStraHelper.buildV0Candidate(v0.collisionId(), col.posX(), col.posY(), col.posZ(), posTrack, negTrack, posTrackPar, negTrackPar, false, false, false)) { + continue; + } - double nTPCSigmaP[2]{track.tpcNSigmaPr(), track.tpcNSigmaDe()}; - double nTPCSigmaN[2]{track.tpcNSigmaPr(), track.tpcNSigmaDe()}; + float lambdaPt = RecoDecay::sqrtSumOfSquares(mStraHelper.v0.momentum[0], mStraHelper.v0.momentum[1]); + float lambdaPos = std::hypot(mStraHelper.v0.position[0] - col.posX(), mStraHelper.v0.position[1] - col.posY(), mStraHelper.v0.position[2] - col.posZ()); + float lambdaRadius = std::hypot(mStraHelper.v0.position[0], mStraHelper.v0.position[1]); + float lambdaEta = RecoDecay::eta(std::array{mStraHelper.v0.momentum[0], mStraHelper.v0.momentum[1], mStraHelper.v0.momentum[2]}); + float lambdaPhi = RecoDecay::phi(mStraHelper.v0.momentum[0], mStraHelper.v0.momentum[1]); + float lambdaCpa = std::cos(mStraHelper.v0.pointingAngle); + float lambdaDauDca = mStraHelper.v0.daughterDCA; + float lambdaMass = mStraHelper.v0.massLambda; + float antiLambdaMass = mStraHelper.v0.massAntiLambda; + float kaonMass = mStraHelper.v0.massK0Short; + + float posTrackEta = RecoDecay::eta(std::array{mStraHelper.v0.positiveMomentum[0], mStraHelper.v0.positiveMomentum[1], mStraHelper.v0.positiveMomentum[2]}); + float posTrackDca = mStraHelper.v0.positiveDCAxy; + float negTrackEta = RecoDecay::eta(std::array{mStraHelper.v0.negativeMomentum[0], mStraHelper.v0.negativeMomentum[1], mStraHelper.v0.negativeMomentum[2]}); + float negTrackDca = mStraHelper.v0.negativeDCAxy; + + registry.fill(HIST("LambdaQA/Before/fPt"), lambdaPt); + registry.fill(HIST("LambdaQA/Before/fEta"), lambdaEta); + registry.fill(HIST("LambdaQA/Before/fPhi"), lambdaPhi); + registry.fill(HIST("LambdaQA/Before/fInvMassLambda"), lambdaMass); + registry.fill(HIST("LambdaQA/Before/fInvMassAntiLambda"), antiLambdaMass); + registry.fill(HIST("LambdaQA/Before/fInvMassLambdaVsAntiLambda"), lambdaMass, antiLambdaMass); + registry.fill(HIST("LambdaQA/Before/fInvMassLambdaVsKaon"), lambdaMass, kaonMass); + registry.fill(HIST("LambdaQA/Before/fInvMassAntiLambdaVsKaon"), antiLambdaMass, kaonMass); + registry.fill(HIST("LambdaQA/Before/fDcaDaugh"), lambdaDauDca); + registry.fill(HIST("LambdaQA/Before/fCpa"), lambdaCpa); + registry.fill(HIST("LambdaQA/Before/fTranRad"), lambdaRadius); + registry.fill(HIST("LambdaQA/Before/fDecVtx"), lambdaPos); + + registry.fill(HIST("LambdaQA/Before/PosDaughter/fPt"), posTrack.pt()); + registry.fill(HIST("LambdaQA/Before/PosDaughter/fEta"), posTrackEta); + registry.fill(HIST("LambdaQA/Before/PosDaughter/fPhi"), posTrack.phi()); + registry.fill(HIST("LambdaQA/Before/PosDaughter/fDcaXy"), posTrack.pt(), posTrackDca); + registry.fill(HIST("LambdaQA/Before/PosDaughter/fTpcClusters"), posTrack.tpcNClsFound()); + registry.fill(HIST("LambdaQA/Before/PosDaughter/fNsigmaTpcProton"), posTrack.p(), posTrack.tpcNSigmaPr()); + registry.fill(HIST("LambdaQA/Before/PosDaughter/fNsigmaTpcPion"), posTrack.p(), posTrack.tpcNSigmaPi()); + + registry.fill(HIST("LambdaQA/Before/NegDaughter/fPt"), negTrack.pt()); + registry.fill(HIST("LambdaQA/Before/NegDaughter/fEta"), negTrackEta); + registry.fill(HIST("LambdaQA/Before/NegDaughter/fPhi"), negTrack.phi()); + registry.fill(HIST("LambdaQA/Before/NegDaughter/fDcaXy"), negTrack.pt(), negTrackDca); + registry.fill(HIST("LambdaQA/Before/NegDaughter/fTpcClusters"), negTrack.tpcNClsFound()); + registry.fill(HIST("LambdaQA/Before/NegDaughter/fNsigmaTpcProton"), negTrack.p(), negTrack.tpcNSigmaPr()); + registry.fill(HIST("LambdaQA/Before/NegDaughter/fNsigmaTpcPion"), negTrack.p(), negTrack.tpcNSigmaPi()); + + if (checkLambda(lambdaPt, lambdaDauDca, lambdaCpa, lambdaRadius, lambdaPos, kaonMass, lambdaMass) && checkLambdaDaughter(posTrack, posTrackEta, posTrackDca, posTrack.tpcNSigmaPr()) && checkLambdaDaughter(negTrack, negTrackEta, negTrackDca, negTrack.tpcNSigmaPi())) { + vecLambda.emplace_back(lambdaPt, lambdaEta, lambdaPhi, o2::constants::physics::MassLambda0); + idxLambdaDaughProton.push_back(posTrack.globalIndex()); + idxLambdaDaughPion.push_back(negTrack.globalIndex()); + + registry.fill(HIST("LambdaQA/After/Lambda/fPt"), lambdaPt); + registry.fill(HIST("LambdaQA/After/Lambda/fEta"), lambdaEta); + registry.fill(HIST("LambdaQA/After/Lambda/fPhi"), lambdaPhi); + registry.fill(HIST("LambdaQA/After/Lambda/fInvMass"), lambdaMass); + registry.fill(HIST("LambdaQA/After/Lambda/fInvMassLambdaVsAntiLambda"), lambdaMass, antiLambdaMass); + registry.fill(HIST("LambdaQA/After/Lambda/fInvMassLambdaVsKaon"), lambdaMass, kaonMass); + registry.fill(HIST("LambdaQA/After/Lambda/fDcaDaugh"), lambdaDauDca); + registry.fill(HIST("LambdaQA/After/Lambda/fCpa"), lambdaCpa); + registry.fill(HIST("LambdaQA/After/Lambda/fTranRad"), lambdaRadius); + registry.fill(HIST("LambdaQA/After/Lambda/fDecVtx"), lambdaPos); + + registry.fill(HIST("LambdaQA/After/Lambda/PosDaughter/fPt"), posTrack.pt()); + registry.fill(HIST("LambdaQA/After/Lambda/PosDaughter/fEta"), posTrackEta); + registry.fill(HIST("LambdaQA/After/Lambda/PosDaughter/fPhi"), posTrack.phi()); + registry.fill(HIST("LambdaQA/After/Lambda/PosDaughter/fDcaXy"), posTrack.pt(), posTrackDca); + registry.fill(HIST("LambdaQA/After/Lambda/PosDaughter/fTpcClusters"), posTrack.tpcNClsFound()); + registry.fill(HIST("LambdaQA/After/Lambda/PosDaughter/fNsigmaTpc"), posTrack.p(), posTrack.tpcNSigmaPr()); + + registry.fill(HIST("LambdaQA/After/Lambda/NegDaughter/fPt"), negTrack.pt()); + registry.fill(HIST("LambdaQA/After/Lambda/NegDaughter/fEta"), negTrackEta); + registry.fill(HIST("LambdaQA/After/Lambda/NegDaughter/fPhi"), negTrack.phi()); + registry.fill(HIST("LambdaQA/After/Lambda/NegDaughter/fDcaXy"), negTrack.pt(), negTrackDca); + registry.fill(HIST("LambdaQA/After/Lambda/NegDaughter/fTpcClusters"), negTrack.tpcNClsFound()); + registry.fill(HIST("LambdaQA/After/Lambda/NegDaughter/fNsigmaTpc"), negTrack.p(), negTrack.tpcNSigmaPi()); + } - if (ConfUseManualPIDproton) { - auto bgScalingProton = 1 / mMassProton; // momentum scaling? - if (BBProton.size() == 6) - nTPCSigmaP[0] = updatePID(track, bgScalingProton, BBProton); - if (BBAntiproton.size() == 6) - nTPCSigmaN[0] = updatePID(track, bgScalingProton, BBAntiproton); - } - if (ConfUseManualPIDdeuteron) { - auto bgScalingDeuteron = 1 / mMassDeuteron; // momentum scaling? - if (BBDeuteron.size() == 6) - nTPCSigmaP[1] = updatePID(track, bgScalingDeuteron, BBDeuteron); - if (BBAntideuteron.size() == 6) - nTPCSigmaN[1] = updatePID(track, bgScalingDeuteron, BBAntideuteron); - } + if (checkLambda(lambdaPt, lambdaDauDca, lambdaCpa, lambdaRadius, lambdaPos, kaonMass, antiLambdaMass) && checkLambdaDaughter(posTrack, posTrackEta, posTrackDca, posTrack.tpcNSigmaPi()) && checkLambdaDaughter(negTrack, negTrackEta, negTrackDca, negTrack.tpcNSigmaPr())) { + vecAntiLambda.emplace_back(lambdaPt, lambdaEta, lambdaPhi, o2::constants::physics::MassLambda0); + + idxAntiLambdaDaughProton.push_back(negTrack.globalIndex()); + idxAntiLambdaDaughPion.push_back(posTrack.globalIndex()); + + registry.fill(HIST("LambdaQA/After/AntiLambda/fPt"), lambdaPt); + registry.fill(HIST("LambdaQA/After/AntiLambda/fEta"), lambdaEta); + registry.fill(HIST("LambdaQA/After/AntiLambda/fPhi"), lambdaPhi); + registry.fill(HIST("LambdaQA/After/AntiLambda/fInvMass"), antiLambdaMass); + registry.fill(HIST("LambdaQA/After/AntiLambda/fInvMassAntiLambdaVsLambda"), antiLambdaMass, lambdaMass); + registry.fill(HIST("LambdaQA/After/AntiLambda/fInvMassAntiLambdaVsKaon"), antiLambdaMass, kaonMass); + registry.fill(HIST("LambdaQA/After/AntiLambda/fDcaDaugh"), lambdaDauDca); + registry.fill(HIST("LambdaQA/After/AntiLambda/fCpa"), lambdaCpa); + registry.fill(HIST("LambdaQA/After/AntiLambda/fTranRad"), lambdaRadius); + registry.fill(HIST("LambdaQA/After/AntiLambda/fDecVtx"), lambdaPos); + + registry.fill(HIST("LambdaQA/After/AntiLambda/PosDaughter/fPt"), posTrack.pt()); + registry.fill(HIST("LambdaQA/After/AntiLambda/PosDaughter/fEta"), posTrackEta); + registry.fill(HIST("LambdaQA/After/AntiLambda/PosDaughter/fPhi"), posTrack.phi()); + registry.fill(HIST("LambdaQA/After/AntiLambda/PosDaughter/fDcaXy"), posTrack.pt(), posTrackDca); + registry.fill(HIST("LambdaQA/After/AntiLambda/PosDaughter/fTpcClusters"), posTrack.tpcNClsFound()); + registry.fill(HIST("LambdaQA/After/AntiLambda/PosDaughter/fNsigmaTpc"), posTrack.p(), posTrack.tpcNSigmaPr()); + + registry.fill(HIST("LambdaQA/After/AntiLambda/NegDaughter/fPt"), negTrack.pt()); + registry.fill(HIST("LambdaQA/After/AntiLambda/NegDaughter/fEta"), negTrackEta); + registry.fill(HIST("LambdaQA/After/AntiLambda/NegDaughter/fPhi"), negTrack.phi()); + registry.fill(HIST("LambdaQA/After/AntiLambda/NegDaughter/fDcaXy"), negTrack.pt(), negTrackDca); + registry.fill(HIST("LambdaQA/After/AntiLambda/NegDaughter/fTpcClusters"), negTrack.tpcNClsFound()); + registry.fill(HIST("LambdaQA/After/AntiLambda/NegDaughter/fNsigmaTpc"), negTrack.p(), negTrack.tpcNSigmaPi()); + } + } - registry.fill(HIST("TrackCuts/TracksBefore/fPtTrackBefore"), track.pt()); - registry.fill(HIST("TrackCuts/TracksBefore/fEtaTrackBefore"), track.eta()); - registry.fill(HIST("TrackCuts/TracksBefore/fPhiTrackBefore"), track.phi()); - - if (track.sign() > 0) { - // Fill PID info - registry.fill(HIST("TrackCuts/TPCSignal/fTPCSignal"), track.tpcInnerParam(), track.tpcSignal()); - registry.fill(HIST("TrackCuts/TPCSignal/fTPCSignalP"), track.p(), track.tpcSignal()); - if (isSelectedTrack(track, CFTrigger::kProton)) { - registry.fill(HIST("TrackCuts/TPCSignal/fTPCSignalALLCUTS"), track.tpcInnerParam(), track.tpcSignal()); - registry.fill(HIST("TrackCuts/TPCSignal/fTPCSignalALLCUTSP"), track.p(), track.tpcSignal()); - registry.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationAfterCutsPos"), track.p(), track.tpcInnerParam()); - } - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTPCvsPProtonBefore"), track.tpcInnerParam(), nTPCSigmaP[0]); - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTOFvsPProtonBefore"), track.tpcInnerParam(), track.tofNSigmaPr()); - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTPCTOFvsPProtonBefore"), track.tpcInnerParam(), std::sqrt(std::pow(nTPCSigmaP[0] - TPCTOFAvg[0], 2) + std::pow(track.tofNSigmaPr() - TPCTOFAvg[1], 2))); - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTPCvsPDeuteronBefore"), track.tpcInnerParam(), nTPCSigmaP[1]); - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTOFvsPDeuteronBefore"), track.tpcInnerParam(), track.tofNSigmaDe()); - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTPCTOFvsPDeuteronBefore"), track.tpcInnerParam(), std::sqrt(std::pow(nTPCSigmaP[1] - TPCTOFAvg[4], 2) + std::pow(track.tofNSigmaDe() - TPCTOFAvg[5], 2))); - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTPCvsPDeuteronBeforeP"), track.p(), nTPCSigmaP[1]); - registry.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationPos"), track.p(), track.tpcInnerParam()); + // build phi candidates + for (size_t k1 = 0; k1 < vecKaon.size(); k1++) { + for (size_t k2 = 0; k2 < vecAntiKaon.size(); k2++) { + ROOT::Math::PtEtaPhiMVector phi = vecKaon.at(k1) + vecAntiKaon.at(k2); + + registry.fill(HIST("PhiQA/Before/fInvMass"), phi.M()); + registry.fill(HIST("PhiQA/Before/fPt"), phi.Pt()); + registry.fill(HIST("PhiQA/Before/fEta"), phi.Eta()); + registry.fill(HIST("PhiQA/Before/fPhi"), RecoDecay::constrainAngle(phi.Phi())); + + if ((phi.M() >= PhiSelections.invMassLow.value) && + (phi.M() <= PhiSelections.invMassUp.value)) { + vecPhi.push_back(phi); + idxPhiDaughPos.push_back(idxKaon.at(k1)); + idxPhiDaughNeg.push_back(idxAntiKaon.at(k2)); + + registry.fill(HIST("PhiQA/After/fInvMass"), phi.M()); + registry.fill(HIST("PhiQA/After/fPt"), phi.Pt()); + registry.fill(HIST("PhiQA/After/fEta"), phi.Eta()); + registry.fill(HIST("PhiQA/After/fPhi"), RecoDecay::constrainAngle(phi.Phi())); } - if (track.sign() < 0) { - - registry.fill(HIST("TrackCuts/TPCSignal/fTPCSignalAnti"), track.tpcInnerParam(), track.tpcSignal()); - registry.fill(HIST("TrackCuts/TPCSignal/fTPCSignalAntiP"), track.p(), track.tpcSignal()); - if (isSelectedTrack(track, CFTrigger::kProton)) { - registry.fill(HIST("TrackCuts/TPCSignal/fTPCSignalAntiALLCUTS"), track.tpcInnerParam(), track.tpcSignal()); - registry.fill(HIST("TrackCuts/TPCSignal/fTPCSignalAntiALLCUTSP"), track.p(), track.tpcSignal()); - registry.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationAfterCutsNeg"), track.p(), track.tpcInnerParam()); - } + } + } - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTPCvsPAntiProtonBefore"), track.tpcInnerParam(), nTPCSigmaN[0]); - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTOFvsPAntiProtonBefore"), track.tpcInnerParam(), track.tofNSigmaPr()); - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTPCTOFvsPAntiProtonBefore"), track.tpcInnerParam(), std::sqrt(std::pow(nTPCSigmaN[0] - TPCTOFAvg[2], 2) + std::pow(track.tofNSigmaPr() - TPCTOFAvg[3], 2))); - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTPCvsPAntiDeuteronBefore"), track.tpcInnerParam(), nTPCSigmaN[1]); - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTOFvsPAntiDeuteronBefore"), track.tpcInnerParam(), track.tofNSigmaDe()); - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTPCTOFvsPAntiDeuteronBefore"), track.tpcInnerParam(), std::sqrt(std::pow(nTPCSigmaN[1] - TPCTOFAvg[6], 2) + std::pow(track.tofNSigmaDe() - TPCTOFAvg[7], 2))); - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTPCvsPAntiDeuteronBeforeP"), track.p(), nTPCSigmaN[1]); - registry.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationNeg"), track.p(), track.tpcInnerParam()); + // build rho candidates + for (size_t p1 = 0; p1 < vecPion.size(); p1++) { + for (size_t p2 = 0; p2 < vecAntiPion.size(); p2++) { + ROOT::Math::PtEtaPhiMVector rho = vecPion.at(p1) + vecAntiPion.at(p2); + + registry.fill(HIST("RhoQA/Before/fInvMass"), rho.M()); + registry.fill(HIST("RhoQA/Before/fPt"), rho.Pt()); + registry.fill(HIST("RhoQA/Before/fEta"), rho.Eta()); + registry.fill(HIST("RhoQA/Before/fPhi"), RecoDecay::constrainAngle(rho.Phi())); + + if (((rho.M() >= RhoSelections.invMassLow.value) && (rho.M() <= RhoSelections.invMassUp.value)) && (rho.Pt() >= RhoSelections.ptLow)) { + vecRho.push_back(rho); + idxRhoDaughPos.push_back(idxPion.at(p1)); + idxRhoDaughNeg.push_back(idxAntiPion.at(p2)); + + registry.fill(HIST("RhoQA/After/fInvMass"), rho.M()); + registry.fill(HIST("RhoQA/After/fPt"), rho.Pt()); + registry.fill(HIST("RhoQA/After/fEta"), rho.Eta()); + registry.fill(HIST("RhoQA/After/fPhi"), RecoDecay::constrainAngle(rho.Phi())); } + } + } - // get protons - if (isSelectedTrack(track, CFTrigger::kProton)) { - ROOT::Math::PtEtaPhiMVector temp(track.pt(), track.eta(), track.phi(), mMassProton); - if (track.sign() > 0 && isSelectedTrackPID(track, CFTrigger::kProton, false, nTPCSigmaP, 1)) { - protons.push_back(temp); - ProtonIndex.push_back(track.globalIndex()); - - registry.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationAfterCutsProton"), track.p(), track.tpcInnerParam()); - - registry.fill(HIST("TrackCuts/TPCSignal/fTPCSignalProton"), track.tpcInnerParam(), track.tpcSignal()); - registry.fill(HIST("TrackCuts/Proton/fPProton"), track.p()); - registry.fill(HIST("TrackCuts/Proton/fPTPCProton"), track.tpcInnerParam()); - registry.fill(HIST("TrackCuts/Proton/fPtProton"), track.pt()); - registry.fill(HIST("TrackCuts/Proton/fMomCorProtonDif"), track.p(), track.tpcInnerParam() - track.p()); - registry.fill(HIST("TrackCuts/Proton/fMomCorProtonRatio"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); - registry.fill(HIST("TrackCuts/Proton/fEtaProton"), track.eta()); - registry.fill(HIST("TrackCuts/Proton/fPhiProton"), track.phi()); - registry.fill(HIST("TrackCuts/Proton/fNsigmaTPCvsPProton"), track.tpcInnerParam(), nTPCSigmaP[0]); - registry.fill(HIST("TrackCuts/Proton/fNsigmaTOFvsPProton"), track.tpcInnerParam(), track.tofNSigmaPr()); - registry.fill(HIST("TrackCuts/Proton/fNsigmaTPCTOFvsPProton"), track.tpcInnerParam(), std::sqrt(std::pow(nTPCSigmaP[0] - TPCTOFAvg[0], 2) + std::pow(track.tofNSigmaPr() - TPCTOFAvg[1], 2))); - - registry.fill(HIST("TrackCuts/Proton/fNsigmaTPCvsPProtonP"), track.p(), nTPCSigmaP[0]); - registry.fill(HIST("TrackCuts/Proton/fNsigmaTOFvsPProtonP"), track.p(), track.tofNSigmaPr()); - registry.fill(HIST("TrackCuts/Proton/fNsigmaTPCTOFvsPProtonP"), track.p(), std::sqrt(std::pow(nTPCSigmaP[0] - TPCTOFAvg[0], 2) + std::pow(track.tofNSigmaPr() - TPCTOFAvg[1], 2))); - - registry.fill(HIST("TrackCuts/Proton/fDCAxyProton"), track.dcaXY()); - registry.fill(HIST("TrackCuts/Proton/fDCAzProton"), track.dcaZ()); - registry.fill(HIST("TrackCuts/Proton/fTPCsClsProton"), track.tpcNClsShared()); - registry.fill(HIST("TrackCuts/Proton/fTPCcRowsProton"), track.tpcNClsCrossedRows()); - registry.fill(HIST("TrackCuts/Proton/fTrkTPCfClsProton"), track.tpcCrossedRowsOverFindableCls()); - registry.fill(HIST("TrackCuts/Proton/fTPCnclsProton"), track.tpcNClsFound()); - } - if (track.sign() < 0 && isSelectedTrackPID(track, CFTrigger::kProton, false, nTPCSigmaN, -1)) { - antiprotons.push_back(temp); - AntiProtonIndex.push_back(track.globalIndex()); - - registry.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationAfterCutsAntiProton"), track.p(), track.tpcInnerParam()); - - registry.fill(HIST("TrackCuts/TPCSignal/fTPCSignalAntiProton"), track.tpcInnerParam(), track.tpcSignal()); - registry.fill(HIST("TrackCuts/AntiProton/fPtAntiProton"), track.pt()); - registry.fill(HIST("TrackCuts/AntiProton/fMomCorAntiProtonDif"), track.p(), track.tpcInnerParam() - track.p()); - registry.fill(HIST("TrackCuts/AntiProton/fMomCorAntiProtonRatio"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); - registry.fill(HIST("TrackCuts/AntiProton/fEtaAntiProton"), track.eta()); - registry.fill(HIST("TrackCuts/AntiProton/fPhiAntiProton"), track.phi()); - registry.fill(HIST("TrackCuts/AntiProton/fNsigmaTPCvsPAntiProton"), track.tpcInnerParam(), nTPCSigmaN[0]); - registry.fill(HIST("TrackCuts/AntiProton/fNsigmaTOFvsPAntiProton"), track.tpcInnerParam(), track.tofNSigmaPr()); - registry.fill(HIST("TrackCuts/AntiProton/fNsigmaTPCTOFvsPAntiProton"), track.tpcInnerParam(), std::sqrt(std::pow(nTPCSigmaN[0] - TPCTOFAvg[2], 2) + std::pow(track.tofNSigmaPr() - TPCTOFAvg[3], 2))); - - registry.fill(HIST("TrackCuts/AntiProton/fNsigmaTPCvsPAntiProtonP"), track.p(), nTPCSigmaN[0]); - registry.fill(HIST("TrackCuts/AntiProton/fNsigmaTOFvsPAntiProtonP"), track.p(), track.tofNSigmaPr()); - registry.fill(HIST("TrackCuts/AntiProton/fNsigmaTPCTOFvsPAntiProtonP"), track.p(), std::sqrt(std::pow(nTPCSigmaN[0] - TPCTOFAvg[2], 2) + std::pow(track.tofNSigmaPr() - TPCTOFAvg[3], 2))); - - registry.fill(HIST("TrackCuts/AntiProton/fDCAxyAntiProton"), track.dcaXY()); - registry.fill(HIST("TrackCuts/AntiProton/fDCAzAntiProton"), track.dcaZ()); - registry.fill(HIST("TrackCuts/AntiProton/fTPCsClsAntiProton"), track.tpcNClsShared()); - registry.fill(HIST("TrackCuts/AntiProton/fTPCcRowsAntiProton"), track.tpcNClsCrossedRows()); - registry.fill(HIST("TrackCuts/AntiProton/fTrkTPCfClsAntiProton"), track.tpcCrossedRowsOverFindableCls()); - registry.fill(HIST("TrackCuts/AntiProton/fTPCnclsAntiProton"), track.tpcNClsFound()); - } - } - // get deuterons - if (isSelectedTrack(track, CFTrigger::kDeuteron)) { - ROOT::Math::PtEtaPhiMVector temp(track.pt(), track.eta(), track.phi(), mMassDeuteron); - if (track.sign() > 0 && isSelectedTrackPID(track, CFTrigger::kDeuteron, ConfRejectNOTDeuteron.value, nTPCSigmaP, 1)) { - deuterons.push_back(temp); - - registry.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationAfterCutsDeuteron"), track.p(), track.tpcInnerParam()); - - registry.fill(HIST("TrackCuts/TPCSignal/fTPCSignalDeuteron"), track.tpcInnerParam(), track.tpcSignal()); - registry.fill(HIST("TrackCuts/Deuteron/fPtDeuteron"), track.pt()); - registry.fill(HIST("TrackCuts/Deuteron/fMomCorDeuteronDif"), track.p(), track.tpcInnerParam() - track.p()); - registry.fill(HIST("TrackCuts/Deuteron/fMomCorDeuteronRatio"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); - registry.fill(HIST("TrackCuts/Deuteron/fEtaDeuteron"), track.eta()); - registry.fill(HIST("TrackCuts/Deuteron/fPhiDeuteron"), track.phi()); - registry.fill(HIST("TrackCuts/Deuteron/fNsigmaTPCvsPDeuteron"), track.tpcInnerParam(), nTPCSigmaP[1]); - registry.fill(HIST("TrackCuts/Deuteron/fNsigmaTOFvsPDeuteron"), track.tpcInnerParam(), track.tofNSigmaDe()); - registry.fill(HIST("TrackCuts/Deuteron/fNsigmaTPCTOFvsPDeuteron"), track.tpcInnerParam(), std::sqrt(std::pow(nTPCSigmaP[1] - TPCTOFAvg[4], 2) + std::pow(track.tofNSigmaDe() - TPCTOFAvg[5], 2))); - - registry.fill(HIST("TrackCuts/Deuteron/fNsigmaTPCvsPDeuteronP"), track.p(), nTPCSigmaP[1]); - registry.fill(HIST("TrackCuts/Deuteron/fNsigmaTOFvsPDeuteronP"), track.p(), track.tofNSigmaDe()); - registry.fill(HIST("TrackCuts/Deuteron/fNsigmaTPCTOFvsPDeuteronP"), track.p(), std::sqrt(std::pow(nTPCSigmaP[1] - TPCTOFAvg[4], 2) + std::pow(track.tofNSigmaDe() - TPCTOFAvg[5], 2))); - - registry.fill(HIST("TrackCuts/Deuteron/fDCAxyDeuteron"), track.dcaXY()); - registry.fill(HIST("TrackCuts/Deuteron/fDCAzDeuteron"), track.dcaZ()); - registry.fill(HIST("TrackCuts/Deuteron/fTPCsClsDeuteron"), track.tpcNClsShared()); - registry.fill(HIST("TrackCuts/Deuteron/fTPCcRowsDeuteron"), track.tpcNClsCrossedRows()); - registry.fill(HIST("TrackCuts/Deuteron/fTrkTPCfClsDeuteron"), track.tpcCrossedRowsOverFindableCls()); - registry.fill(HIST("TrackCuts/Deuteron/fTPCnclsDeuteron"), track.tpcNClsFound()); - } - if (track.sign() < 0 && isSelectedTrackPID(track, CFTrigger::kDeuteron, ConfRejectNOTDeuteron.value, nTPCSigmaN, -1)) { - antideuterons.push_back(temp); - - registry.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationAfterCutsAntiDeuteron"), track.p(), track.tpcInnerParam()); - - registry.fill(HIST("TrackCuts/TPCSignal/fTPCSignalAntiDeuteron"), track.tpcInnerParam(), track.tpcSignal()); - registry.fill(HIST("TrackCuts/AntiDeuteron/fPtAntiDeuteron"), track.pt()); - registry.fill(HIST("TrackCuts/AntiDeuteron/fMomCorAntiDeuteronDif"), track.p(), track.tpcInnerParam() - track.p()); - registry.fill(HIST("TrackCuts/AntiDeuteron/fMomCorAntiDeuteronRatio"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); - registry.fill(HIST("TrackCuts/AntiDeuteron/fEtaAntiDeuteron"), track.eta()); - registry.fill(HIST("TrackCuts/AntiDeuteron/fPhiAntiDeuteron"), track.phi()); - registry.fill(HIST("TrackCuts/AntiDeuteron/fNsigmaTPCvsPAntiDeuteron"), track.tpcInnerParam(), nTPCSigmaN[1]); - registry.fill(HIST("TrackCuts/AntiDeuteron/fNsigmaTOFvsPAntiDeuteron"), track.tpcInnerParam(), track.tofNSigmaDe()); - registry.fill(HIST("TrackCuts/AntiDeuteron/fNsigmaTPCTOFvsPAntiDeuteron"), track.tpcInnerParam(), std::sqrt(std::pow(nTPCSigmaN[1] - TPCTOFAvg[6], 2) + std::pow(track.tofNSigmaDe() - TPCTOFAvg[7], 2))); - - registry.fill(HIST("TrackCuts/AntiDeuteron/fNsigmaTPCvsPAntiDeuteronP"), track.p(), nTPCSigmaN[1]); - registry.fill(HIST("TrackCuts/AntiDeuteron/fNsigmaTOFvsPAntiDeuteronP"), track.p(), track.tofNSigmaDe()); - registry.fill(HIST("TrackCuts/AntiDeuteron/fNsigmaTPCTOFvsPAntiDeuteronP"), track.p(), std::sqrt(std::pow(nTPCSigmaN[1] - TPCTOFAvg[6], 2) + std::pow(track.tofNSigmaDe() - TPCTOFAvg[7], 2))); - - registry.fill(HIST("TrackCuts/AntiDeuteron/fDCAxyAntiDeuteron"), track.dcaXY()); - registry.fill(HIST("TrackCuts/AntiDeuteron/fDCAzAntiDeuteron"), track.dcaZ()); - registry.fill(HIST("TrackCuts/AntiDeuteron/fTPCsClsAntiDeuteron"), track.tpcNClsShared()); - registry.fill(HIST("TrackCuts/AntiDeuteron/fTPCcRowsAntiDeuteron"), track.tpcNClsCrossedRows()); - registry.fill(HIST("TrackCuts/AntiDeuteron/fTrkTPCfClsAntiDeuteron"), track.tpcCrossedRowsOverFindableCls()); - registry.fill(HIST("TrackCuts/AntiDeuteron/fTPCnclsAntiDeuteron"), track.tpcNClsFound()); + // reset all arrays + keepEventTightLimit.fill(false); + keepEventLooseLimit.fill(false); + signalTightLimit.fill(0); + signalLooseLimit.fill(0); + + float q3 = 999.f, kstar = 999.f; + + // PPP + if (TriggerSelections.filterSwitches->get("Switch", "PPP") > 0) { + for (size_t p1 = 0; p1 < vecProton.size(); p1++) { + for (size_t p2 = p1 + 1; p2 < vecProton.size(); p2++) { + for (size_t p3 = p2 + 1; p3 < vecProton.size(); p3++) { + q3 = getQ3(vecProton.at(p1), vecProton.at(p2), vecProton.at(p3)); + registry.fill(HIST("PPP/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("PPP/fZvtx"), col.posZ()); + registry.fill(HIST("PPP/fSE_particle"), q3); + registry.fill(HIST("PPP/fProtonPtVsQ3"), vecProton.at(p1).Pt(), q3); + registry.fill(HIST("PPP/fProtonPtVsQ3"), vecProton.at(p2).Pt(), q3); + registry.fill(HIST("PPP/fProtonPtVsQ3"), vecProton.at(p3).Pt(), q3); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PPP")) { + signalLooseLimit[cf_trigger::kPPP] += 1; + if (q3 < TriggerSelections.limits->get("Tight Limit", "PPP")) { + signalTightLimit[cf_trigger::kPPP] += 1; + } + } } } } - - // keep track of daugher indices to avoid selfcorrelations - std::vector LambdaPosDaughIndex = {}; - std::vector LambdaNegDaughIndex = {}; - std::vector AntiLambdaPosDaughIndex = {}; - std::vector AntiLambdaNegDaughIndex = {}; - - for (auto& v0 : fullV0s) { - - auto postrack = v0.template posTrack_as(); - auto negtrack = v0.template negTrack_as(); - double nTPCSigmaPos[2]{postrack.tpcNSigmaPr(), postrack.tpcNSigmaPi()}; - double nTPCSigmaNeg[2]{negtrack.tpcNSigmaPr(), negtrack.tpcNSigmaPi()}; - if (ConfUseManualPIDdaughterPion) { - auto bgScalingPion = 1 / mMassPion; // momentum scaling? - if (BBPion.size() == 6) - nTPCSigmaPos[1] = updatePID(postrack, bgScalingPion, BBPion); - if (BBAntipion.size() == 6) - nTPCSigmaNeg[1] = updatePID(negtrack, bgScalingPion, BBAntipion); - } - if (ConfUseManualPIDdaughterProton) { - auto bgScalingProton = 1 / mMassProton; // momentum scaling? - if (BBProton.size() == 6) - nTPCSigmaPos[0] = updatePID(postrack, bgScalingProton, BBProton); - if (BBAntiproton.size() == 6) - nTPCSigmaNeg[0] = updatePID(negtrack, bgScalingProton, BBAntiproton); - } - registry.fill(HIST("TrackCuts/V0Before/fPtLambdaBefore"), v0.pt()); - registry.fill(HIST("TrackCuts/V0Before/fInvMassLambdaBefore"), v0.mLambda()); - registry.fill(HIST("TrackCuts/V0Before/fInvMassAntiLambdaBefore"), v0.mAntiLambda()); - registry.fill(HIST("TrackCuts/V0Before/fInvMassLambdavsAntiLambda"), v0.mLambda(), v0.mAntiLambda()); - registry.fill(HIST("TrackCuts/V0Before/fInvMassV0BeforeKaonvsV0Before"), v0.mK0Short(), v0.mLambda()); - registry.fill(HIST("TrackCuts/V0Before/fV0DCADaugh"), v0.dcaV0daughters()); - registry.fill(HIST("TrackCuts/V0Before/fV0CPA"), v0.v0cosPA()); - registry.fill(HIST("TrackCuts/V0Before/fV0TranRad"), v0.v0radius()); - registry.fill(HIST("TrackCuts/V0Before/f0DecVtxX"), v0.x()); - registry.fill(HIST("TrackCuts/V0Before/f0DecVtxY"), v0.y()); - registry.fill(HIST("TrackCuts/V0Before/f0DecVtxZ"), v0.z()); - - registry.fill(HIST("TrackCuts/V0Before/PosDaughter/Eta"), postrack.eta()); - registry.fill(HIST("TrackCuts/V0Before/PosDaughter/DCAXY"), postrack.dcaXY()); - registry.fill(HIST("TrackCuts/V0Before/PosDaughter/fTPCncls"), postrack.tpcNClsFound()); - registry.fill(HIST("TrackCuts/V0Before/NegDaughter/Eta"), negtrack.eta()); - registry.fill(HIST("TrackCuts/V0Before/NegDaughter/DCAXY"), negtrack.dcaXY()); - registry.fill(HIST("TrackCuts/V0Before/NegDaughter/fTPCncls"), negtrack.tpcNClsFound()); - registry.fill(HIST("TrackCuts/V0Before/PosDaughter/fNsigmaTPCvsPProtonV0Daugh"), postrack.tpcInnerParam(), nTPCSigmaPos[0]); - registry.fill(HIST("TrackCuts/V0Before/NegDaughter/fNsigmaTPCvsPPionMinusV0Daugh"), negtrack.tpcInnerParam(), nTPCSigmaNeg[1]); - registry.fill(HIST("TrackCuts/V0Before/NegDaughter/fNsigmaTPCvsPAntiProtonV0Daugh"), negtrack.tpcInnerParam(), nTPCSigmaNeg[0]); - registry.fill(HIST("TrackCuts/V0Before/PosDaughter/fNsigmaTPCvsPPionPlusV0Daugh"), postrack.tpcInnerParam(), nTPCSigmaPos[1]); - - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTPCvsPProtonV0DaughBefore"), postrack.tpcInnerParam(), nTPCSigmaPos[0]); - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTPCvsPPionPlusAntiV0DaughBefore"), postrack.tpcInnerParam(), nTPCSigmaNeg[1]); - - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTPCvsPPionMinusV0DaughBefore"), negtrack.tpcInnerParam(), nTPCSigmaNeg[1]); - registry.fill(HIST("TrackCuts/NSigmaBefore/fNsigmaTPCvsPAntiProtonAntiV0DaughBefore"), negtrack.tpcInnerParam(), nTPCSigmaNeg[0]); - - if (isSelectedMinimalV0(col, v0, postrack, negtrack, 1, nTPCSigmaPos, nTPCSigmaNeg)) { - ROOT::Math::PtEtaPhiMVector temp(v0.pt(), v0.eta(), v0.phi(), mMassLambda); - lambdas.push_back(temp); - LambdaPosDaughIndex.push_back(postrack.globalIndex()); - LambdaNegDaughIndex.push_back(negtrack.globalIndex()); - registry.fill(HIST("TrackCuts/TPCSignal/fTPCSignalProtonPlusV0Daughter"), postrack.tpcInnerParam(), postrack.tpcSignal()); - registry.fill(HIST("TrackCuts/TPCSignal/fTPCSignalPionMinusV0Daughter"), negtrack.tpcInnerParam(), negtrack.tpcSignal()); - registry.fill(HIST("TrackCuts/Lambda/fPtLambda"), v0.pt()); - registry.fill(HIST("TrackCuts/Lambda/fInvMassLambda"), v0.mLambda()); - registry.fill(HIST("TrackCuts/Lambda/fInvMassLambdaKaonvsLambda"), v0.mK0Short(), v0.mLambda()); - registry.fill(HIST("TrackCuts/Lambda/fV0DCADaugh"), v0.dcaV0daughters()); - registry.fill(HIST("TrackCuts/Lambda/fV0CPA"), v0.v0cosPA()); - registry.fill(HIST("TrackCuts/Lambda/fV0TranRad"), v0.v0radius()); - registry.fill(HIST("TrackCuts/Lambda/f0DecVtxX"), v0.x()); - registry.fill(HIST("TrackCuts/Lambda/f0DecVtxY"), v0.y()); - registry.fill(HIST("TrackCuts/Lambda/f0DecVtxZ"), v0.z()); - - registry.fill(HIST("TrackCuts/Lambda/PosDaughter/Eta"), postrack.eta()); - registry.fill(HIST("TrackCuts/Lambda/PosDaughter/DCAXY"), postrack.dcaXY()); - registry.fill(HIST("TrackCuts/Lambda/PosDaughter/fTPCncls"), postrack.tpcNClsFound()); - registry.fill(HIST("TrackCuts/Lambda/NegDaughter/Eta"), negtrack.eta()); - registry.fill(HIST("TrackCuts/Lambda/NegDaughter/DCAXY"), negtrack.dcaXY()); - registry.fill(HIST("TrackCuts/Lambda/NegDaughter/fTPCncls"), negtrack.tpcNClsFound()); - registry.fill(HIST("TrackCuts/Lambda/PosDaughter/fNsigmaTPCvsPProtonV0Daugh"), postrack.tpcInnerParam(), nTPCSigmaPos[0]); - registry.fill(HIST("TrackCuts/Lambda/NegDaughter/fNsigmaTPCvsPPionMinusV0Daugh"), negtrack.tpcInnerParam(), nTPCSigmaNeg[1]); - } - if (isSelectedMinimalV0(col, v0, postrack, negtrack, -1, nTPCSigmaPos, nTPCSigmaNeg)) { - ROOT::Math::PtEtaPhiMVector temp(v0.pt(), v0.eta(), v0.phi(), mMassLambda); - antilambdas.push_back(temp); - AntiLambdaPosDaughIndex.push_back(postrack.globalIndex()); - AntiLambdaNegDaughIndex.push_back(negtrack.globalIndex()); - registry.fill(HIST("TrackCuts/TPCSignal/fTPCSignalPionPlusV0Daughter"), postrack.tpcInnerParam(), postrack.tpcSignal()); - registry.fill(HIST("TrackCuts/TPCSignal/fTPCSignalProtonMinusV0Daughter"), negtrack.tpcInnerParam(), negtrack.tpcSignal()); - registry.fill(HIST("TrackCuts/AntiLambda/fPtAntiLambda"), v0.pt()); - registry.fill(HIST("TrackCuts/AntiLambda/fInvMassAntiLambda"), v0.mAntiLambda()); - registry.fill(HIST("TrackCuts/AntiLambda/fInvMassAntiLambdaKaonvsAntiLambda"), v0.mK0Short(), v0.mAntiLambda()); - registry.fill(HIST("TrackCuts/AntiLambda/fV0DCADaugh"), v0.dcaV0daughters()); - registry.fill(HIST("TrackCuts/AntiLambda/fV0CPA"), v0.v0cosPA()); - registry.fill(HIST("TrackCuts/AntiLambda/fV0TranRad"), v0.v0radius()); - registry.fill(HIST("TrackCuts/AntiLambda/f0DecVtxX"), v0.x()); - registry.fill(HIST("TrackCuts/AntiLambda/f0DecVtxY"), v0.y()); - registry.fill(HIST("TrackCuts/AntiLambda/f0DecVtxZ"), v0.z()); - - registry.fill(HIST("TrackCuts/AntiLambda/PosDaughter/Eta"), postrack.eta()); - registry.fill(HIST("TrackCuts/AntiLambda/PosDaughter/DCAXY"), postrack.dcaXY()); - registry.fill(HIST("TrackCuts/AntiLambda/PosDaughter/fTPCncls"), postrack.tpcNClsFound()); - registry.fill(HIST("TrackCuts/AntiLambda/NegDaughter/Eta"), negtrack.eta()); - registry.fill(HIST("TrackCuts/AntiLambda/NegDaughter/DCAXY"), negtrack.dcaXY()); - registry.fill(HIST("TrackCuts/AntiLambda/NegDaughter/fTPCncls"), negtrack.tpcNClsFound()); - registry.fill(HIST("TrackCuts/AntiLambda/NegDaughter/fNsigmaTPCvsPAntiProtonAntiV0Daugh"), negtrack.tpcInnerParam(), nTPCSigmaNeg[0]); - registry.fill(HIST("TrackCuts/AntiLambda/PosDaughter/fNsigmaTPCvsPPionPlusAntiV0Daugh"), postrack.tpcInnerParam(), nTPCSigmaPos[1]); + for (size_t p1 = 0; p1 < vecAntiProton.size(); p1++) { + for (size_t p2 = p1 + 1; p2 < vecAntiProton.size(); p2++) { + for (size_t p3 = p2 + 1; p3 < vecAntiProton.size(); p3++) { + q3 = getQ3(vecAntiProton.at(p1), vecAntiProton.at(p2), vecAntiProton.at(p3)); + registry.fill(HIST("PPP/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("PPP/fZvtx"), col.posZ()); + registry.fill(HIST("PPP/fSE_antiparticle"), q3); + registry.fill(HIST("PPP/fAntiProtonPtVsQ3"), vecAntiProton.at(p1).Pt(), q3); + registry.fill(HIST("PPP/fAntiProtonPtVsQ3"), vecAntiProton.at(p2).Pt(), q3); + registry.fill(HIST("PPP/fAntiProtonPtVsQ3"), vecAntiProton.at(p3).Pt(), q3); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PPP")) { + signalLooseLimit[cf_trigger::kPPP] += 1; + if (q3 < TriggerSelections.limits->get("Tight Limit", "PPP")) { + signalTightLimit[cf_trigger::kPPP] += 1; + } + } + } } } - - float Q3 = 999.f, kstar = 999.f; - if (ConfTriggerSwitches->get("Switch", "ppp") > 0.) { - // ppp trigger - for (auto iProton1 = protons.begin(); iProton1 != protons.end(); ++iProton1) { - auto iProton2 = iProton1 + 1; - for (; iProton2 != protons.end(); ++iProton2) { - auto iProton3 = iProton2 + 1; - for (; iProton3 != protons.end(); ++iProton3) { - Q3 = getQ3(*iProton1, *iProton2, *iProton3); - registry.fill(HIST("ppp/fSE_particle"), Q3); - registry.fill(HIST("ppp/fProtonPtVsQ3"), Q3, (*iProton1).Pt()); - registry.fill(HIST("ppp/fProtonPtVsQ3"), Q3, (*iProton2).Pt()); - registry.fill(HIST("ppp/fProtonPtVsQ3"), Q3, (*iProton3).Pt()); - if (Q3 < ConfQ3Limits->get(static_cast(0), CFTrigger::kPPP)) { - if (ConfDownsample->get("Switch", "PPP") > 0) { - if (rng->Uniform(0., 1.) < ConfDownsample->get("Factor", "PPP")) { - registry.fill(HIST("ppp/fSE_particle_downsample"), Q3); - lowQ3Triplets[CFTrigger::kPPP] += 1; - } - } else { - lowQ3Triplets[CFTrigger::kPPP] += 1; - } + } + // PPL + if (TriggerSelections.filterSwitches->get("Switch", "PPL") > 0) { + for (size_t p1 = 0; p1 < vecProton.size(); p1++) { + for (size_t p2 = p1 + 1; p2 < vecProton.size(); p2++) { + for (size_t l1 = 0; l1 < vecLambda.size(); l1++) { + if (idxProton.at(p1) == idxLambdaDaughProton.at(l1) || idxProton.at(p2) == idxLambdaDaughProton.at(l1)) { + continue; + } + q3 = getQ3(vecProton.at(p1), vecProton.at(p2), vecLambda.at(l1)); + registry.fill(HIST("PPL/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("PPL/fZvtx"), col.posZ()); + registry.fill(HIST("PPL/fSE_particle"), q3); + registry.fill(HIST("PPL/fProtonPtVsQ3"), vecProton.at(p1).Pt(), q3); + registry.fill(HIST("PPL/fProtonPtVsQ3"), vecProton.at(p2).Pt(), q3); + registry.fill(HIST("PPL/fLambdaPtVsQ3"), vecLambda.at(l1).Pt(), q3); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PPL")) { + signalLooseLimit[cf_trigger::kPPL] += 1; + if (q3 < TriggerSelections.limits->get("Tight Limit", "PPL")) { + signalTightLimit[cf_trigger::kPPL] += 1; } } } } - for (auto iAntiProton1 = antiprotons.begin(); iAntiProton1 != antiprotons.end(); ++iAntiProton1) { - auto iAntiProton2 = iAntiProton1 + 1; - for (; iAntiProton2 != antiprotons.end(); ++iAntiProton2) { - auto iAntiProton3 = iAntiProton2 + 1; - for (; iAntiProton3 != antiprotons.end(); ++iAntiProton3) { - Q3 = getQ3(*iAntiProton1, *iAntiProton2, *iAntiProton3); - registry.fill(HIST("ppp/fSE_antiparticle"), Q3); - registry.fill(HIST("ppp/fAntiProtonPtVsQ3"), Q3, (*iAntiProton1).Pt()); - registry.fill(HIST("ppp/fAntiProtonPtVsQ3"), Q3, (*iAntiProton2).Pt()); - registry.fill(HIST("ppp/fAntiProtonPtVsQ3"), Q3, (*iAntiProton3).Pt()); - if (Q3 < ConfQ3Limits->get(static_cast(0), CFTrigger::kPPP)) { - if (ConfDownsample->get("Switch", "aPaPaP") > 0) { - if (rng->Uniform(0., 1.) < ConfDownsample->get("Factor", "aPaPaP")) { - registry.fill(HIST("ppp/fSE_antiparticle_downsample"), Q3); - lowQ3Triplets[CFTrigger::kPPP] += 1; - } - } else { - lowQ3Triplets[CFTrigger::kPPP] += 1; - } + } + for (size_t p1 = 0; p1 < vecAntiProton.size(); p1++) { + for (size_t p2 = p1 + 1; p2 < vecAntiProton.size(); p2++) { + for (size_t l1 = 0; l1 < vecAntiLambda.size(); l1++) { + if (idxAntiProton.at(p1) == idxAntiLambdaDaughProton.at(l1) || idxAntiProton.at(p2) == idxAntiLambdaDaughProton.at(l1)) { + continue; + } + q3 = getQ3(vecAntiProton.at(p1), vecAntiProton.at(p2), vecAntiLambda.at(l1)); + registry.fill(HIST("PPL/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("PPL/fZvtx"), col.posZ()); + registry.fill(HIST("PPL/fSE_particle"), q3); + registry.fill(HIST("PPL/fAntiProtonPtVsQ3"), vecAntiProton.at(p1).Pt(), q3); + registry.fill(HIST("PPL/fAntiProtonPtVsQ3"), vecAntiProton.at(p2).Pt(), q3); + registry.fill(HIST("PPL/fAntiLambdaPtVsQ3"), vecAntiLambda.at(l1).Pt(), q3); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PPL")) { + signalLooseLimit[cf_trigger::kPPL] += 1; + if (q3 < TriggerSelections.limits->get("Tight Limit", "PPL")) { + signalTightLimit[cf_trigger::kPPL] += 1; } } } } } - if (ConfTriggerSwitches->get("Switch", "ppL") > 0.) { - // ppl trigger - for (auto iProton1 = protons.begin(); iProton1 != protons.end(); ++iProton1) { - auto iProton2 = iProton1 + 1; - auto i1 = std::distance(protons.begin(), iProton1); - for (; iProton2 != protons.end(); ++iProton2) { - auto i2 = std::distance(protons.begin(), iProton2); - for (auto iLambda1 = lambdas.begin(); iLambda1 != lambdas.end(); ++iLambda1) { - auto i3 = std::distance(lambdas.begin(), iLambda1); - if (ConfAutocorRejection.value && - (ProtonIndex.at(i1) == LambdaPosDaughIndex.at(i3) || - ProtonIndex.at(i2) == LambdaPosDaughIndex.at(i3))) { - continue; - } - Q3 = getQ3(*iProton1, *iProton2, *iLambda1); - registry.fill(HIST("ppl/fSE_particle"), Q3); - registry.fill(HIST("ppl/fProtonPtVsQ3"), Q3, (*iProton1).Pt()); - registry.fill(HIST("ppl/fProtonPtVsQ3"), Q3, (*iProton2).Pt()); - registry.fill(HIST("ppl/fLambdaPtVsQ3"), Q3, (*iLambda1).Pt()); - if (Q3 < ConfQ3Limits->get(static_cast(0), CFTrigger::kPPL)) { - if (ConfDownsample->get("Switch", "PPL") > 0) { - if (rng->Uniform(0., 1.) < ConfDownsample->get("Factor", "PPL")) { - registry.fill(HIST("ppl/fSE_particle_downsample"), Q3); - lowQ3Triplets[CFTrigger::kPPL] += 1; - } - } else { - lowQ3Triplets[CFTrigger::kPPL] += 1; - } + } + // PLL + if (TriggerSelections.filterSwitches->get("Switch", "PLL") > 0) { + for (size_t l1 = 0; l1 < vecLambda.size(); l1++) { + for (size_t l2 = l1 + 1; l2 < vecLambda.size(); l2++) { + for (size_t p1 = 0; p1 < vecProton.size(); p1++) { + if (idxProton.at(p1) == idxLambdaDaughProton.at(l1) || idxProton.at(p1) == idxLambdaDaughProton.at(l2)) { + continue; + } + if (idxLambdaDaughProton.at(l1) == idxLambdaDaughProton.at(l2) || idxLambdaDaughPion.at(l1) == idxLambdaDaughPion.at(l2)) { + continue; + } + q3 = getQ3(vecLambda.at(l1), vecLambda.at(l2), vecProton.at(p1)); + registry.fill(HIST("PLL/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("PLL/fZvtx"), col.posZ()); + registry.fill(HIST("PLL/fSE_particle"), q3); + registry.fill(HIST("PLL/fLambdaPtVsQ3"), vecLambda.at(l1).Pt(), q3); + registry.fill(HIST("PLL/fLambdaPtVsQ3"), vecLambda.at(l2).Pt(), q3); + registry.fill(HIST("PLL/fProtonPtVsQ3"), vecProton.at(p1).Pt(), q3); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PLL")) { + signalLooseLimit[cf_trigger::kPLL] += 1; + if (q3 < TriggerSelections.limits->get("Tight Limit", "PLL")) { + signalTightLimit[cf_trigger::kPLL] += 1; } } } } - for (auto iAntiProton1 = antiprotons.begin(); iAntiProton1 != antiprotons.end(); ++iAntiProton1) { - auto iAntiProton2 = iAntiProton1 + 1; - auto i1 = std::distance(antiprotons.begin(), iAntiProton1); - for (; iAntiProton2 != antiprotons.end(); ++iAntiProton2) { - auto i2 = std::distance(antiprotons.begin(), iAntiProton2); - for (auto iAntiLambda1 = antilambdas.begin(); iAntiLambda1 != antilambdas.end(); ++iAntiLambda1) { - auto i3 = std::distance(antilambdas.begin(), iAntiLambda1); - if (ConfAutocorRejection.value && - (AntiProtonIndex.at(i1) == AntiLambdaNegDaughIndex.at(i3) || - AntiProtonIndex.at(i2) == AntiLambdaNegDaughIndex.at(i3))) { - continue; - } - Q3 = getQ3(*iAntiProton1, *iAntiProton2, *iAntiLambda1); - registry.fill(HIST("ppl/fSE_antiparticle"), Q3); - registry.fill(HIST("ppl/fAntiProtonPtVsQ3"), Q3, (*iAntiProton1).Pt()); - registry.fill(HIST("ppl/fAntiProtonPtVsQ3"), Q3, (*iAntiProton2).Pt()); - registry.fill(HIST("ppl/fAntiLambdaPtVsQ3"), Q3, (*iAntiLambda1).Pt()); - if (Q3 < ConfQ3Limits->get(static_cast(0), CFTrigger::kPPL)) { - if (ConfDownsample->get("Switch", "aPaPaL") > 0) { - if (rng->Uniform(0., 1.) < ConfDownsample->get("Factor", "aPaPaL")) { - registry.fill(HIST("ppl/fSE_antiparticle_downsample"), Q3); - lowQ3Triplets[CFTrigger::kPPL] += 1; - } - } else { - lowQ3Triplets[CFTrigger::kPPL] += 1; - } + } + for (size_t l1 = 0; l1 < vecAntiLambda.size(); l1++) { + for (size_t l2 = l1 + 1; l2 < vecAntiLambda.size(); l2++) { + for (size_t p1 = 0; p1 < vecAntiProton.size(); p1++) { + if (idxAntiProton.at(p1) == idxAntiLambdaDaughProton.at(l1) || idxAntiProton.at(p1) == idxAntiLambdaDaughProton.at(l2)) { + continue; + } + if (idxAntiLambdaDaughProton.at(l1) == idxAntiLambdaDaughProton.at(l2) || idxAntiLambdaDaughPion.at(l1) == idxAntiLambdaDaughPion.at(l2)) { + continue; + } + q3 = getQ3(vecAntiLambda.at(l1), vecAntiLambda.at(l2), vecAntiProton.at(p1)); + registry.fill(HIST("PLL/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("PLL/fZvtx"), col.posZ()); + registry.fill(HIST("PLL/fSE_antiparticle"), q3); + registry.fill(HIST("PLL/fAntiLambdaPtVsQ3"), vecAntiLambda.at(l1).Pt(), q3); + registry.fill(HIST("PLL/fAntiLambdaPtVsQ3"), vecAntiLambda.at(l2).Pt(), q3); + registry.fill(HIST("PLL/fAntiProtonPtVsQ3"), vecAntiProton.at(p1).Pt(), q3); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PLL")) { + signalLooseLimit[cf_trigger::kPLL] += 1; + if (q3 < TriggerSelections.limits->get("Tight Limit", "PLL")) { + signalTightLimit[cf_trigger::kPLL] += 1; } } } } } - if (ConfTriggerSwitches->get("Switch", "pLL") > 0.) { - // pll trigger - for (auto iLambda1 = lambdas.begin(); iLambda1 != lambdas.end(); ++iLambda1) { - auto iLambda2 = iLambda1 + 1; - auto i1 = std::distance(lambdas.begin(), iLambda1); - for (; iLambda2 != lambdas.end(); ++iLambda2) { - auto i2 = std::distance(lambdas.begin(), iLambda2); - if (ConfAutocorRejection.value && - (LambdaPosDaughIndex.at(i1) == LambdaPosDaughIndex.at(i2) || - LambdaNegDaughIndex.at(i1) == LambdaNegDaughIndex.at(i2))) { + } + // LLL + if (TriggerSelections.filterSwitches->get("Switch", "LLL") > 0) { + for (size_t l1 = 0; l1 < vecLambda.size(); l1++) { + for (size_t l2 = l1 + 1; l2 < vecLambda.size(); l2++) { + for (size_t l3 = l2 + 1; l3 < vecLambda.size(); l3++) { + if (idxLambdaDaughProton.at(l1) == idxLambdaDaughProton.at(l2) || idxLambdaDaughPion.at(l1) == idxLambdaDaughPion.at(l2) || + idxLambdaDaughProton.at(l2) == idxLambdaDaughProton.at(l3) || idxLambdaDaughPion.at(l2) == idxLambdaDaughPion.at(l3) || + idxLambdaDaughProton.at(l3) == idxLambdaDaughProton.at(l1) || idxLambdaDaughPion.at(l3) == idxLambdaDaughPion.at(l1)) { continue; } - for (auto iProton1 = protons.begin(); iProton1 != protons.end(); ++iProton1) { - auto i3 = std::distance(protons.begin(), iProton1); - if (ConfAutocorRejection.value && - (LambdaPosDaughIndex.at(i1) == ProtonIndex.at(i3) || - LambdaPosDaughIndex.at(i2) == ProtonIndex.at(i3))) { - continue; - } - Q3 = getQ3(*iLambda1, *iLambda2, *iProton1); - registry.fill(HIST("pll/fSE_particle"), Q3); - registry.fill(HIST("pll/fProtonPtVsQ3"), Q3, (*iProton1).Pt()); - registry.fill(HIST("pll/fLambdaPtVsQ3"), Q3, (*iLambda1).Pt()); - registry.fill(HIST("pll/fLambdaPtVsQ3"), Q3, (*iLambda2).Pt()); - if (Q3 < ConfQ3Limits->get(static_cast(0), CFTrigger::kPLL)) { - if (ConfDownsample->get("Switch", "PLL") > 0) { - if (rng->Uniform(0., 1.) < ConfDownsample->get("Factor", "PLL")) { - registry.fill(HIST("pll/fSE_particle_downsample"), Q3); - lowQ3Triplets[CFTrigger::kPLL] += 1; - } - } else { - lowQ3Triplets[CFTrigger::kPLL] += 1; - } + q3 = getQ3(vecLambda.at(l1), vecLambda.at(l2), vecLambda.at(l3)); + registry.fill(HIST("PLL/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("PLL/fZvtx"), col.posZ()); + registry.fill(HIST("PLL/fSE_particle"), q3); + registry.fill(HIST("PLL/fLambdaPtVsQ3"), vecLambda.at(l1).Pt(), q3); + registry.fill(HIST("PLL/fLambdaPtVsQ3"), vecLambda.at(l2).Pt(), q3); + registry.fill(HIST("PLL/fLambdaPtVsQ3"), vecLambda.at(l3).Pt(), q3); + if (q3 < TriggerSelections.limits->get("Loose Limit", "LLL")) { + signalLooseLimit[cf_trigger::kLLL] += 1; + if (q3 < TriggerSelections.limits->get("Tight Limit", "LLL")) { + signalTightLimit[cf_trigger::kLLL] += 1; } } } } - for (auto iAntiLambda1 = antilambdas.begin(); iAntiLambda1 != antilambdas.end(); ++iAntiLambda1) { - auto iAntiLambda2 = iAntiLambda1 + 1; - auto i1 = std::distance(antilambdas.begin(), iAntiLambda1); - for (; iAntiLambda2 != antilambdas.end(); ++iAntiLambda2) { - auto i2 = std::distance(antilambdas.begin(), iAntiLambda2); - if (ConfAutocorRejection.value && - (AntiLambdaPosDaughIndex.at(i1) == AntiLambdaPosDaughIndex.at(i2) || - AntiLambdaNegDaughIndex.at(i1) == AntiLambdaNegDaughIndex.at(i2))) { + } + for (size_t l1 = 0; l1 < vecAntiLambda.size(); l1++) { + for (size_t l2 = l1 + 1; l2 < vecAntiLambda.size(); l2++) { + for (size_t l3 = l2 + 1; l3 < vecAntiLambda.size(); l3++) { + if (idxAntiLambdaDaughProton.at(l1) == idxAntiLambdaDaughProton.at(l2) || idxAntiLambdaDaughPion.at(l1) == idxAntiLambdaDaughPion.at(l2) || + idxAntiLambdaDaughProton.at(l2) == idxAntiLambdaDaughProton.at(l3) || idxAntiLambdaDaughPion.at(l2) == idxAntiLambdaDaughPion.at(l3) || + idxAntiLambdaDaughProton.at(l3) == idxAntiLambdaDaughProton.at(l1) || idxAntiLambdaDaughPion.at(l3) == idxAntiLambdaDaughPion.at(l1)) { continue; } - for (auto iAntiProton1 = antiprotons.begin(); iAntiProton1 != antiprotons.end(); ++iAntiProton1) { - auto i3 = std::distance(antiprotons.begin(), iAntiProton1); - if (ConfAutocorRejection.value && - (AntiLambdaNegDaughIndex.at(i1) == AntiProtonIndex.at(i3) || - AntiLambdaNegDaughIndex.at(i2) == AntiProtonIndex.at(i3))) { - continue; - } - Q3 = getQ3(*iAntiLambda1, *iAntiLambda2, *iAntiProton1); - registry.fill(HIST("pll/fSE_antiparticle"), Q3); - registry.fill(HIST("pll/fAntiProtonPtVsQ3"), Q3, (*iAntiProton1).Pt()); - registry.fill(HIST("pll/fAntiLambdaPtVsQ3"), Q3, (*iAntiLambda1).Pt()); - registry.fill(HIST("pll/fAntiLambdaPtVsQ3"), Q3, (*iAntiLambda2).Pt()); - if (Q3 < ConfQ3Limits->get(static_cast(0), CFTrigger::kPLL)) { - if (ConfDownsample->get("Switch", "aPaLaL") > 0) { - if (rng->Uniform(0., 1.) < ConfDownsample->get("Factor", "aPaLaL")) { - registry.fill(HIST("pll/fSE_antiparticle_downsample"), Q3); - lowQ3Triplets[CFTrigger::kPLL] += 1; - } - } else { - lowQ3Triplets[CFTrigger::kPLL] += 1; - } + q3 = getQ3(vecAntiLambda.at(l1), vecAntiLambda.at(l2), vecAntiLambda.at(l3)); + registry.fill(HIST("PLL/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("PLL/fZvtx"), col.posZ()); + registry.fill(HIST("PLL/fSE_particle"), q3); + registry.fill(HIST("PLL/fLambdaPtVsQ3"), vecAntiLambda.at(l1).Pt(), q3); + registry.fill(HIST("PLL/fLambdaPtVsQ3"), vecAntiLambda.at(l2).Pt(), q3); + registry.fill(HIST("PLL/fLambdaPtVsQ3"), vecAntiLambda.at(l3).Pt(), q3); + if (q3 < TriggerSelections.limits->get("Loose Limit", "LLL")) { + signalLooseLimit[cf_trigger::kLLL] += 1; + if (q3 < TriggerSelections.limits->get("Tight Limit", "LLL")) { + signalTightLimit[cf_trigger::kLLL] += 1; } } } } } - if (ConfTriggerSwitches->get("Switch", "LLL") > 0.) { - // lll trigger - for (auto iLambda1 = lambdas.begin(); iLambda1 != lambdas.end(); ++iLambda1) { - auto iLambda2 = iLambda1 + 1; - auto i1 = std::distance(lambdas.begin(), iLambda1); - for (; iLambda2 != lambdas.end(); ++iLambda2) { - auto i2 = std::distance(lambdas.begin(), iLambda2); - if (ConfAutocorRejection.value && - (LambdaPosDaughIndex.at(i1) == LambdaPosDaughIndex.at(i2) || - LambdaNegDaughIndex.at(i1) == LambdaNegDaughIndex.at(i2))) { + } + // PPPhi + if (TriggerSelections.filterSwitches->get("Switch", "PPPhi") > 0) { + for (size_t p1 = 0; p1 < vecProton.size(); p1++) { + for (size_t p2 = p1 + 1; p2 < vecProton.size(); p2++) { + for (size_t phi1 = 0; phi1 < vecPhi.size(); phi1++) { + if (idxProton.at(p1) == idxPhiDaughPos.at(phi1) || idxProton.at(p2) == idxPhiDaughPos.at(phi1)) { continue; } - auto iLambda3 = iLambda2 + 1; - for (; iLambda3 != lambdas.end(); ++iLambda3) { - auto i3 = std::distance(lambdas.begin(), iLambda3); - if (ConfAutocorRejection.value && - (LambdaPosDaughIndex.at(i1) == LambdaPosDaughIndex.at(i3) || - LambdaNegDaughIndex.at(i1) == LambdaNegDaughIndex.at(i3) || - LambdaPosDaughIndex.at(i2) == LambdaPosDaughIndex.at(i3) || - LambdaNegDaughIndex.at(i2) == LambdaNegDaughIndex.at(i3))) { - continue; - } - Q3 = getQ3(*iLambda1, *iLambda2, *iLambda3); - registry.fill(HIST("lll/fSE_particle"), Q3); - registry.fill(HIST("lll/fLambdaPtVsQ3"), Q3, (*iLambda1).Pt()); - registry.fill(HIST("lll/fLambdaPtVsQ3"), Q3, (*iLambda2).Pt()); - registry.fill(HIST("lll/fLambdaPtVsQ3"), Q3, (*iLambda3).Pt()); - if (Q3 < ConfQ3Limits->get(static_cast(0), CFTrigger::kLLL)) { - if (ConfDownsample->get("Switch", "LLL") > 0) { - if (rng->Uniform(0., 1.) < ConfDownsample->get("Factor", "LLL")) { - registry.fill(HIST("lll/fSE_particle_downsample"), Q3); - lowQ3Triplets[CFTrigger::kLLL] += 1; - } - } else { - lowQ3Triplets[CFTrigger::kLLL] += 1; - } + q3 = getQ3(vecProton.at(p1), vecProton.at(p2), vecPhi.at(phi1)); + registry.fill(HIST("PPPhi/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("PPPhi/fZvtx"), col.posZ()); + registry.fill(HIST("PPPhi/fSE_particle"), q3); + registry.fill(HIST("PPPhi/fProtonPtVsQ3"), vecProton.at(p1).Pt(), q3); + registry.fill(HIST("PPPhi/fProtonPtVsQ3"), vecProton.at(p2).Pt(), q3); + registry.fill(HIST("PPPhi/fPhiPtVsQ3"), vecPhi.at(phi1).Pt(), q3); + registry.fill(HIST("PPPhi/fPhiInvMassVsQ3"), vecPhi.at(phi1).M(), q3); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PPPhi")) { + if (q3 < TriggerSelections.limits->get("Tight Limit", "PPPhi") && + vecPhi.at(phi1).M() > PhiSelections.tightInvMassLow.value && vecPhi.at(phi1).M() < PhiSelections.tightInvMassUp.value) { + signalTightLimit[cf_trigger::kPPPhi] += 1; } } } } - for (auto iAntiLambda1 = antilambdas.begin(); iAntiLambda1 != antilambdas.end(); ++iAntiLambda1) { - auto iAntiLambda2 = iAntiLambda1 + 1; - auto i1 = std::distance(antilambdas.begin(), iAntiLambda1); - for (; iAntiLambda2 != antilambdas.end(); ++iAntiLambda2) { - auto i2 = std::distance(antilambdas.begin(), iAntiLambda2); - if (ConfAutocorRejection.value && - (AntiLambdaPosDaughIndex.at(i1) == AntiLambdaPosDaughIndex.at(i2) || - AntiLambdaNegDaughIndex.at(i1) == AntiLambdaNegDaughIndex.at(i2))) { + } + for (size_t p1 = 0; p1 < vecAntiProton.size(); p1++) { + for (size_t p2 = p1 + 1; p2 < vecAntiProton.size(); p2++) { + for (size_t phi1 = 0; phi1 < vecPhi.size(); phi1++) { + if (idxAntiProton.at(p1) == idxPhiDaughNeg.at(phi1) || idxAntiProton.at(p2) == idxPhiDaughNeg.at(phi1)) { continue; } - auto iAntiLambda3 = iAntiLambda2 + 1; - for (; iAntiLambda3 != antilambdas.end(); ++iAntiLambda3) { - auto i3 = std::distance(antilambdas.begin(), iAntiLambda3); - if (ConfAutocorRejection.value && - (AntiLambdaPosDaughIndex.at(i1) == AntiLambdaPosDaughIndex.at(i3) || - AntiLambdaNegDaughIndex.at(i1) == AntiLambdaNegDaughIndex.at(i3) || - AntiLambdaPosDaughIndex.at(i2) == AntiLambdaPosDaughIndex.at(i3) || - AntiLambdaNegDaughIndex.at(i2) == AntiLambdaNegDaughIndex.at(i3))) { - continue; - } - Q3 = getQ3(*iAntiLambda1, *iAntiLambda2, *iAntiLambda3); - registry.fill(HIST("lll/fSE_antiparticle"), Q3); - registry.fill(HIST("lll/fAntiLambdaPtVsQ3"), Q3, (*iAntiLambda1).Pt()); - registry.fill(HIST("lll/fAntiLambdaPtVsQ3"), Q3, (*iAntiLambda2).Pt()); - registry.fill(HIST("lll/fAntiLambdaPtVsQ3"), Q3, (*iAntiLambda3).Pt()); - if (Q3 < ConfQ3Limits->get(static_cast(0), CFTrigger::kLLL)) { - if (ConfDownsample->get("Switch", "aLaLaL") > 0) { - if (rng->Uniform(0., 1.) < ConfDownsample->get("Factor", "aLaLaL")) { - registry.fill(HIST("lll/fSE_antiparticle_downsample"), Q3); - lowQ3Triplets[CFTrigger::kLLL] += 1; - } - } else { - lowQ3Triplets[CFTrigger::kLLL] += 1; - } + q3 = getQ3(vecAntiProton.at(p1), vecAntiProton.at(p2), vecPhi.at(phi1)); + registry.fill(HIST("PPPhi/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("PPPhi/fZvtx"), col.posZ()); + registry.fill(HIST("PPPhi/fSE_particle"), q3); + registry.fill(HIST("PPPhi/fAntiProtonPtVsQ3"), vecAntiProton.at(p1).Pt(), q3); + registry.fill(HIST("PPPhi/fAntiProtonPtVsQ3"), vecAntiProton.at(p2).Pt(), q3); + registry.fill(HIST("PPPhi/fPhiPtVsQ3"), vecPhi.at(phi1).Pt(), q3); + registry.fill(HIST("PPPhi/fPhiInvMassVsQ3"), vecPhi.at(phi1).M(), q3); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PPPhi")) { + if (q3 < TriggerSelections.limits->get("Tight Limit", "PPPhi") && + vecPhi.at(phi1).M() > PhiSelections.tightInvMassLow.value && vecPhi.at(phi1).M() < PhiSelections.tightInvMassUp.value) { + signalTightLimit[cf_trigger::kPPPhi] += 1; } } } } } - if (ConfTriggerSwitches->get("Switch", "pd") > 0.) { - // pd trigger - for (auto iProton = protons.begin(); iProton != protons.end(); ++iProton) { - for (auto iDeuteron = deuterons.begin(); iDeuteron != deuterons.end(); ++iDeuteron) { - kstar = getkstar(*iProton, *iDeuteron); - registry.fill(HIST("pd/fSE_particle"), kstar); - registry.fill(HIST("pd/fProtonPtVskstar"), kstar, (*iProton).Pt()); - registry.fill(HIST("pd/fDeuteronPtVskstar"), kstar, (*iDeuteron).Pt()); - if (kstar < ConfKstarLimits->get(static_cast(0), CFTrigger::kPD)) { - if (ConfDownsample->get("Switch", "PD") > 0) { - if (rng->Uniform(0., 1.) < ConfDownsample->get("Factor", "PD")) { - registry.fill(HIST("pd/fSE_particle_downsample"), kstar); - lowKstarPairs[CFTrigger::kPD] += 1; - } - } else { - lowKstarPairs[CFTrigger::kPD] += 1; + } + // PPRho + if (TriggerSelections.filterSwitches->get("Switch", "PPRho") > 0) { + for (size_t p1 = 0; p1 < vecProton.size(); p1++) { + for (size_t p2 = p1 + 1; p2 < vecProton.size(); p2++) { + for (size_t r1 = 0; r1 < vecRho.size(); r1++) { + if (idxProton.at(p1) == idxRhoDaughPos.at(r1) || idxProton.at(p2) == idxRhoDaughPos.at(r1)) { + continue; + } + q3 = getQ3(vecProton.at(p1), vecProton.at(p2), vecRho.at(r1)); + registry.fill(HIST("PPRho/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("PPRho/fZvtx"), col.posZ()); + registry.fill(HIST("PPRho/fSE_particle"), q3); + registry.fill(HIST("PPRho/fProtonPtVsQ3"), vecProton.at(p1).Pt(), q3); + registry.fill(HIST("PPRho/fProtonPtVsQ3"), vecProton.at(p2).Pt(), q3); + registry.fill(HIST("PPRho/fRhoPtVsQ3"), vecRho.at(r1).Pt(), q3); + registry.fill(HIST("PPRho/fRhoInvMassVsQ3"), vecRho.at(r1).M(), q3); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PPRho")) { + if (q3 < TriggerSelections.limits->get("Tight Limit", "PPRho") && + vecRho.at(r1).M() > RhoSelections.tightInvMassLow.value && vecRho.at(r1).M() < RhoSelections.tightInvMassUp.value) { + signalTightLimit[cf_trigger::kPPRho] += 1; } } } } - - for (auto iAntiProton = antiprotons.begin(); iAntiProton != antiprotons.end(); ++iAntiProton) { - for (auto iAntiDeuteron = antideuterons.begin(); iAntiDeuteron != antideuterons.end(); ++iAntiDeuteron) { - kstar = getkstar(*iAntiProton, *iAntiDeuteron); - registry.fill(HIST("pd/fSE_antiparticle"), kstar); - registry.fill(HIST("pd/fAntiProtonPtVskstar"), kstar, (*iAntiProton).Pt()); - registry.fill(HIST("pd/fAntiDeuteronPtVskstar"), kstar, (*iAntiDeuteron).Pt()); - if (kstar < ConfKstarLimits->get(static_cast(0), CFTrigger::kPD)) { - if (ConfDownsample->get("Switch", "aPaD") > 0) { - if (rng->Uniform(0., 1.) < ConfDownsample->get("Factor", "aPaD")) { - registry.fill(HIST("pd/fSE_antiparticle_downsample"), kstar); - lowKstarPairs[CFTrigger::kPD] += 1; - } - } else { - lowKstarPairs[CFTrigger::kPD] += 1; + } + for (size_t p1 = 0; p1 < vecAntiProton.size(); p1++) { + for (size_t p2 = p1 + 1; p2 < vecAntiProton.size(); p2++) { + for (size_t r1 = 0; r1 < vecRho.size(); r1++) { + if (idxAntiProton.at(p1) == idxRhoDaughNeg.at(r1) || idxAntiProton.at(p2) == idxRhoDaughNeg.at(r1)) { + continue; + } + q3 = getQ3(vecAntiProton.at(p1), vecAntiProton.at(p2), vecRho.at(r1)); + registry.fill(HIST("PPRho/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("PPRho/fZvtx"), col.posZ()); + registry.fill(HIST("PPRho/fSE_antiparticle"), q3); + registry.fill(HIST("PPRho/fAntiProtonPtVsQ3"), vecAntiProton.at(p1).Pt(), q3); + registry.fill(HIST("PPRho/fAntiProtonPtVsQ3"), vecAntiProton.at(p2).Pt(), q3); + registry.fill(HIST("PPRho/fRhoPtVsQ3"), vecRho.at(r1).Pt(), q3); + registry.fill(HIST("PPRho/fRhoInvMassVsQ3"), vecRho.at(r1).M(), q3); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PPRho")) { + if (q3 < TriggerSelections.limits->get("Tight Limit", "PPRho") && + vecRho.at(r1).M() > RhoSelections.tightInvMassLow.value && vecRho.at(r1).M() < RhoSelections.tightInvMassUp.value) { + signalTightLimit[cf_trigger::kPPRho] += 1; } } } } } - if (ConfTriggerSwitches->get("Switch", "Ld") > 0.) { - // ld trigger - for (auto iDeuteron = deuterons.begin(); iDeuteron != deuterons.end(); ++iDeuteron) { - for (auto iLambda = lambdas.begin(); iLambda != lambdas.end(); ++iLambda) { - kstar = getkstar(*iDeuteron, *iLambda); - registry.fill(HIST("ld/fSE_particle"), kstar); - registry.fill(HIST("ld/fDeuteronPtVskstar"), kstar, (*iDeuteron).Pt()); - registry.fill(HIST("ld/fLambdaPtVskstar"), kstar, (*iLambda).Pt()); - if (kstar < ConfKstarLimits->get(static_cast(0), CFTrigger::kLD)) { - if (ConfDownsample->get("Switch", "LD") > 0) { - if (rng->Uniform(0., 1.) < ConfDownsample->get("Factor", "LD")) { - registry.fill(HIST("ld/fSE_particle_downsample"), kstar); - lowKstarPairs[CFTrigger::kLD] += 1; - } - } else { - lowKstarPairs[CFTrigger::kLD] += 1; - } + } + // PD + if (TriggerSelections.filterSwitches->get("Switch", "PD") > 0) { + for (size_t p1 = 0; p1 < vecProton.size(); p1++) { + for (size_t d1 = 0; d1 < vecDeuteron.size(); d1++) { + if (idxProton.at(p1) == idxDeuteron.at(d1)) { + continue; + } + kstar = getkstar(vecProton.at(p1), vecDeuteron.at(d1)); + registry.fill(HIST("PD/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("PD/fZvtx"), col.posZ()); + registry.fill(HIST("PD/fSE_particle"), kstar); + registry.fill(HIST("PD/fProtonPtVskstar"), vecProton.at(p1).Pt(), kstar); + registry.fill(HIST("PD/fDeuteronPtVskstar"), vecDeuteron.at(d1).Pt(), kstar); + if (kstar < TriggerSelections.limits->get("Loose Limit", "PD")) { + signalLooseLimit[cf_trigger::kPD] += 1; + if (kstar < TriggerSelections.limits->get("Tight Limit", "PD")) { + signalTightLimit[cf_trigger::kPD] += 1; } } } - for (auto iAntiDeuteron = antideuterons.begin(); iAntiDeuteron != antideuterons.end(); ++iAntiDeuteron) { - for (auto iAntiLambda = antilambdas.begin(); iAntiLambda != antilambdas.end(); ++iAntiLambda) { - kstar = getkstar(*iAntiDeuteron, *iAntiLambda); - registry.fill(HIST("ld/fSE_antiparticle"), kstar); - registry.fill(HIST("ld/fAntiDeuteronPtVskstar"), kstar, (*iAntiDeuteron).Pt()); - registry.fill(HIST("ld/fAntiLambdaPtVskstar"), kstar, (*iAntiLambda).Pt()); - if (kstar < ConfKstarLimits->get(static_cast(0), CFTrigger::kLD)) { - if (ConfDownsample->get("Switch", "aLaD") > 0) { - if (rng->Uniform(0., 1.) < ConfDownsample->get("Factor", "aLaD")) { - registry.fill(HIST("ld/fSE_antiparticle_downsample"), kstar); - lowKstarPairs[CFTrigger::kLD] += 1; - } - } else { - lowKstarPairs[CFTrigger::kLD] += 1; - } + } + for (size_t p1 = 0; p1 < vecAntiProton.size(); p1++) { + for (size_t d1 = 0; d1 < vecAntiDeuteron.size(); d1++) { + if (idxAntiProton.at(p1) == idxAntiDeuteron.at(d1)) { + continue; + } + kstar = getkstar(vecAntiProton.at(p1), vecAntiDeuteron.at(d1)); + registry.fill(HIST("PD/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("PD/fZvtx"), col.posZ()); + registry.fill(HIST("PD/fSE_antiparticle"), kstar); + registry.fill(HIST("PD/fAntiProtonPtVskstar"), vecAntiProton.at(p1).Pt(), kstar); + registry.fill(HIST("PD/fAntiDeuteronPtVskstar"), vecAntiDeuteron.at(d1).Pt(), kstar); + if (kstar < TriggerSelections.limits->get("Loose Limit", "PD")) { + signalLooseLimit[cf_trigger::kPD] += 1; + if (kstar < TriggerSelections.limits->get("Tight Limit", "PD")) { + signalTightLimit[cf_trigger::kPD] += 1; } } } } - } // if(isSelectedEvent) - - // create tags for three body triggers - if (lowQ3Triplets[CFTrigger::kPPP] > 0) { - keepEvent3N[CFTrigger::kPPP] = true; - registry.fill(HIST("fProcessedEvents"), 2); - registry.fill(HIST("ppp/fMultiplicity"), col.multNTracksPV()); - registry.fill(HIST("ppp/fZvtx"), col.posZ()); } - if (lowQ3Triplets[CFTrigger::kPPL] > 0) { - keepEvent3N[CFTrigger::kPPL] = true; - registry.fill(HIST("fProcessedEvents"), 3); - registry.fill(HIST("ppl/fMultiplicity"), col.multNTracksPV()); - registry.fill(HIST("ppl/fZvtx"), col.posZ()); + // LD + if (TriggerSelections.filterSwitches->get("Switch", "LD") > 0) { + for (size_t l1 = 0; l1 < vecLambda.size(); l1++) { + for (size_t d1 = 0; d1 < vecDeuteron.size(); d1++) { + if (idxLambdaDaughProton.at(l1) == idxDeuteron.at(d1)) { + continue; + } + kstar = getkstar(vecLambda.at(l1), vecDeuteron.at(d1)); + registry.fill(HIST("LD/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("LD/fZvtx"), col.posZ()); + registry.fill(HIST("LD/fSE_particle"), kstar); + registry.fill(HIST("LD/fLambdaPtVskstar"), vecLambda.at(l1).Pt(), kstar); + registry.fill(HIST("LD/fDeuteronPtVskstar"), vecDeuteron.at(d1).Pt(), kstar); + if (kstar < TriggerSelections.limits->get("Loose Limit", "LD")) { + signalLooseLimit[cf_trigger::kLD] += 1; + if (kstar < TriggerSelections.limits->get("Tight Limit", "LD")) { + signalTightLimit[cf_trigger::kLD] += 1; + } + } + } + } + for (size_t l1 = 0; l1 < vecAntiLambda.size(); l1++) { + for (size_t d1 = 0; d1 < vecAntiDeuteron.size(); d1++) { + if (idxAntiLambdaDaughProton.at(l1) == idxAntiDeuteron.at(d1)) { + continue; + } + kstar = getkstar(vecAntiLambda.at(l1), vecAntiDeuteron.at(d1)); + registry.fill(HIST("LD/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("LD/fZvtx"), col.posZ()); + registry.fill(HIST("LD/fSE_antiparticle"), kstar); + registry.fill(HIST("LD/fAntiLambdaPtVskstar"), vecAntiLambda.at(l1).Pt(), kstar); + registry.fill(HIST("LD/fAntiDeuteronPtVskstar"), vecAntiDeuteron.at(d1).Pt(), kstar); + if (kstar < TriggerSelections.limits->get("Loose Limit", "LD")) { + signalLooseLimit[cf_trigger::kLD] += 1; + if (kstar < TriggerSelections.limits->get("Tight Limit", "LD")) { + signalTightLimit[cf_trigger::kLD] += 1; + } + } + } + } } - if (lowQ3Triplets[CFTrigger::kPLL] > 0) { - keepEvent3N[CFTrigger::kPLL] = true; - registry.fill(HIST("fProcessedEvents"), 4); - registry.fill(HIST("pll/fMultiplicity"), col.multNTracksPV()); - registry.fill(HIST("pll/fZvtx"), col.posZ()); + // PhiD + if (TriggerSelections.filterSwitches->get("Switch", "PhiD") > 0) { + for (size_t phi1 = 0; phi1 < vecPhi.size(); phi1++) { + for (size_t d1 = 0; d1 < vecDeuteron.size(); d1++) { + if (idxPhiDaughPos.at(phi1) == idxDeuteron.at(d1)) { + continue; + } + kstar = getkstar(vecPhi.at(phi1), vecDeuteron.at(d1)); + registry.fill(HIST("PhiD/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("PhiD/fZvtx"), col.posZ()); + registry.fill(HIST("PhiD/fSE_particle"), kstar); + registry.fill(HIST("PhiD/fPhiPtVskstar"), vecPhi.at(phi1).Pt(), kstar); + registry.fill(HIST("PhiD/fDeuteronPtVskstar"), vecDeuteron.at(d1).Pt(), kstar); + registry.fill(HIST("PhiD/fPhiInvMassVskstar"), vecPhi.at(phi1).M(), kstar); + if (kstar < TriggerSelections.limits->get("Loose Limit", "PhiD")) { + signalLooseLimit[cf_trigger::kPhiD] += 1; + if (kstar < TriggerSelections.limits->get("Tight Limit", "PhiD") && + vecPhi.at(phi1).M() > PhiSelections.tightInvMassLow.value && vecPhi.at(phi1).M() < PhiSelections.tightInvMassUp.value) { + signalTightLimit[cf_trigger::kPhiD] += 1; + } + } + } + } + for (size_t phi1 = 0; phi1 < vecPhi.size(); phi1++) { + for (size_t d1 = 0; d1 < vecAntiDeuteron.size(); d1++) { + if (idxPhiDaughNeg.at(phi1) == idxAntiDeuteron.at(d1)) { + continue; + } + kstar = getkstar(vecPhi.at(phi1), vecAntiDeuteron.at(d1)); + registry.fill(HIST("PhiD/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("PhiD/fZvtx"), col.posZ()); + registry.fill(HIST("PhiD/fSE_antiparticle"), kstar); + registry.fill(HIST("PhiD/fPhiPtVskstar"), vecPhi.at(phi1).Pt(), kstar); + registry.fill(HIST("PhiD/fAntiDeuteronPtVskstar"), vecAntiDeuteron.at(d1).Pt(), kstar); + registry.fill(HIST("PhiD/fPhiInvMassVskstar"), vecPhi.at(phi1).M(), kstar); + if (kstar < TriggerSelections.limits->get("Loose Limit", "PhiD")) { + signalLooseLimit[cf_trigger::kPhiD] += 1; + if (kstar < TriggerSelections.limits->get("Tight Limit", "PhiD") && + vecPhi.at(phi1).M() > PhiSelections.tightInvMassLow.value && vecPhi.at(phi1).M() < PhiSelections.tightInvMassUp.value) { + signalTightLimit[cf_trigger::kPhiD] += 1; + } + } + } + } } - if (lowQ3Triplets[CFTrigger::kLLL] > 0) { - keepEvent3N[CFTrigger::kLLL] = true; - registry.fill(HIST("fProcessedEvents"), 5); - registry.fill(HIST("lll/fMultiplicity"), col.multNTracksPV()); - registry.fill(HIST("lll/fZvtx"), col.posZ()); + // RhoD + if (TriggerSelections.filterSwitches->get("Switch", "RhoD") > 0) { + for (size_t r1 = 0; r1 < vecRho.size(); r1++) { + for (size_t d1 = 0; d1 < vecDeuteron.size(); d1++) { + if (idxRhoDaughPos.at(r1) == idxDeuteron.at(d1)) { + continue; + } + kstar = getkstar(vecRho.at(r1), vecDeuteron.at(d1)); + registry.fill(HIST("RhoD/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("RhoD/fZvtx"), col.posZ()); + registry.fill(HIST("RhoD/fSE_particle"), kstar); + registry.fill(HIST("RhoD/fRhoPtVskstar"), vecRho.at(r1).Pt(), kstar); + registry.fill(HIST("RhoD/fDeuteronPtVskstar"), vecDeuteron.at(d1).Pt(), kstar); + registry.fill(HIST("RhoD/fRhoInvMassVskstar"), vecRho.at(r1).M(), kstar); + if (kstar < TriggerSelections.limits->get("Loose Limit", "RhoD")) { + signalLooseLimit[cf_trigger::kRhoD] += 1; + if (kstar < TriggerSelections.limits->get("Tight Limit", "RhoD") && + vecRho.at(r1).M() > RhoSelections.tightInvMassLow.value && vecRho.at(r1).M() < RhoSelections.tightInvMassUp.value) { + signalTightLimit[cf_trigger::kRhoD] += 1; + } + } + } + } + for (size_t r1 = 0; r1 < vecRho.size(); r1++) { + for (size_t d1 = 0; d1 < vecAntiDeuteron.size(); d1++) { + if (idxRhoDaughNeg.at(r1) == idxAntiDeuteron.at(d1)) { + continue; + } + kstar = getkstar(vecRho.at(r1), vecAntiDeuteron.at(d1)); + registry.fill(HIST("RhoD/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("RhoD/fZvtx"), col.posZ()); + registry.fill(HIST("RhoD/fSE_antiparticle"), kstar); + registry.fill(HIST("RhoD/fRhoPtVskstar"), vecRho.at(r1).Pt(), kstar); + registry.fill(HIST("RhoD/fAntiDeuteronPtVskstar"), vecAntiDeuteron.at(d1).Pt(), kstar); + registry.fill(HIST("RhoD/fRhoInvMassVskstar"), vecRho.at(r1).M(), kstar); + if (kstar < TriggerSelections.limits->get("Loose Limit", "RhoD")) { + signalLooseLimit[cf_trigger::kRhoD] += 1; + if (kstar < TriggerSelections.limits->get("Tight Limit", "RhoD") && + vecRho.at(r1).M() > RhoSelections.tightInvMassLow.value && vecRho.at(r1).M() < RhoSelections.tightInvMassUp.value) { + signalTightLimit[cf_trigger::kRhoD] += 1; + } + } + } + } } - // create tags for two body triggers - if (lowKstarPairs[CFTrigger::kPD] > 0) { - keepEvent2N[CFTrigger::kPD] = true; - registry.fill(HIST("fProcessedEvents"), 6); - registry.fill(HIST("pd/fMultiplicity"), col.multNTracksPV()); - registry.fill(HIST("pd/fZvtx"), col.posZ()); - } - if (lowKstarPairs[CFTrigger::kLD] > 0) { - keepEvent2N[CFTrigger::kLD] = true; - registry.fill(HIST("fProcessedEvents"), 7); - registry.fill(HIST("ld/fMultiplicity"), col.multNTracksPV()); - registry.fill(HIST("ld/fZvtx"), col.posZ()); + for (int i = 0; i < cf_trigger::kNTriggers; i++) { + if (signalLooseLimit[i] > 0) { + registry.fill(HIST("fProcessedEvents"), 3 + 2 * i); // need offset for filling + keepEventLooseLimit[i] = true; + } + if (signalTightLimit[i] > 0) { + registry.fill(HIST("fProcessedEvents"), 3 + 2 * i + 1); // need offset for filling + keepEventTightLimit[i] = true; + } + for (int j = i; j < cf_trigger::kNTriggers; j++) { + if (signalLooseLimit[i] > 0 && signalLooseLimit[j]) { + registry.fill(HIST("fTriggerCorrelations"), 2 * i, 2 * j); + } + if (signalLooseLimit[i] > 0 && signalTightLimit[j]) { // only one combination needed, fill only entries above diagonal + registry.fill(HIST("fTriggerCorrelations"), 2 * i, 2 * j + 1); + } + if (signalTightLimit[i] > 0 && signalTightLimit[j]) { + registry.fill(HIST("fTriggerCorrelations"), 2 * i + 1, 2 * j + 1); + } + } } - tags(keepEvent3N[CFTrigger::kPPP], - keepEvent3N[CFTrigger::kPPL], - keepEvent3N[CFTrigger::kPLL], - keepEvent3N[CFTrigger::kLLL], - keepEvent2N[CFTrigger::kPD], - keepEvent2N[CFTrigger::kLD]); - - if (!keepEvent3N[CFTrigger::kPPP] && !keepEvent3N[CFTrigger::kPPL] && !keepEvent3N[CFTrigger::kPLL] && !keepEvent3N[CFTrigger::kLLL] && - !keepEvent2N[CFTrigger::kPD] && !keepEvent2N[CFTrigger::kLD]) { + if (keepEventLooseLimit[cf_trigger::kPPP] || + keepEventLooseLimit[cf_trigger::kPPL] || + keepEventLooseLimit[cf_trigger::kPLL] || + keepEventLooseLimit[cf_trigger::kLLL] || + keepEventLooseLimit[cf_trigger::kPPPhi] || + keepEventLooseLimit[cf_trigger::kPPRho] || + keepEventLooseLimit[cf_trigger::kPD] || + keepEventLooseLimit[cf_trigger::kLD] || + keepEventLooseLimit[cf_trigger::kPhiD] || + keepEventLooseLimit[cf_trigger::kRhoD]) { registry.fill(HIST("fProcessedEvents"), 1); } - } + + if (keepEventTightLimit[cf_trigger::kPPP] || + keepEventTightLimit[cf_trigger::kPPL] || + keepEventTightLimit[cf_trigger::kPLL] || + keepEventTightLimit[cf_trigger::kLLL] || + keepEventTightLimit[cf_trigger::kPPPhi] || + keepEventTightLimit[cf_trigger::kPPRho] || + keepEventTightLimit[cf_trigger::kPD] || + keepEventTightLimit[cf_trigger::kLD] || + keepEventTightLimit[cf_trigger::kPhiD] || + keepEventTightLimit[cf_trigger::kRhoD]) { + registry.fill(HIST("fProcessedEvents"), 2); + } + + tags(keepEventTightLimit[cf_trigger::kPPP], keepEventLooseLimit[cf_trigger::kPPP], + keepEventTightLimit[cf_trigger::kPPL], keepEventLooseLimit[cf_trigger::kPPL], + keepEventTightLimit[cf_trigger::kPLL], keepEventLooseLimit[cf_trigger::kPLL], + keepEventTightLimit[cf_trigger::kLLL], keepEventLooseLimit[cf_trigger::kLLL], + keepEventTightLimit[cf_trigger::kPPPhi], keepEventLooseLimit[cf_trigger::kPPPhi], + keepEventTightLimit[cf_trigger::kPPRho], keepEventLooseLimit[cf_trigger::kPPRho], + keepEventTightLimit[cf_trigger::kPD], keepEventLooseLimit[cf_trigger::kPD], + keepEventTightLimit[cf_trigger::kLD], keepEventLooseLimit[cf_trigger::kLD], + keepEventTightLimit[cf_trigger::kPhiD], keepEventLooseLimit[cf_trigger::kPhiD], + keepEventTightLimit[cf_trigger::kRhoD], keepEventLooseLimit[cf_trigger::kRhoD]); + }; }; WorkflowSpec defineDataProcessing(ConfigContext const& cfg) { - return WorkflowSpec{adaptAnalysisTask(cfg)}; + return WorkflowSpec{adaptAnalysisTask(cfg)}; } diff --git a/EventFiltering/PWGCF/CFFilterPPPhi.cxx b/EventFiltering/PWGCF/CFFilterPPPhi.cxx new file mode 100644 index 00000000000..623b5cb9086 --- /dev/null +++ b/EventFiltering/PWGCF/CFFilterPPPhi.cxx @@ -0,0 +1,543 @@ +// 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 CFFilterAll.cxx +/// \brief Selection of events with triplets and pairs for femtoscopic studies +/// +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#include +#include +#include +#include +#include +#include + +#include "../filterTables.h" + +#include "Framework/Configurable.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "fairlogger/Logger.h" +#include "CommonConstants/MathConstants.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "DataFormatsTPC/BetheBlochAleph.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace o2::aod +{ +using FemtoFullCollision = + soa::Join::iterator; + +using FemtoFullTracks = + soa::Join; +} // namespace o2::aod + +struct CFFillterPPPhi { + + // Table for storing filter decisions + // Leave commented for now + /*Produces tags;*/ + + /*event selection*/ + Configurable ConfEvtSelectZvtx{ + "ConfEvtSelectZvtx", + true, + "Event selection includes max. z-Vertex"}; + + Configurable ConfEvtZvtx{"ConfEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; + + Configurable ConfEvtOfflineCheck{ + "ConfEvtOfflineCheck", + false, + "Evt sel: check for offline selection"}; + + Configurable ConfResoInvMassLowLimit{"ConfResoInvMassLowLimit", 1.011461, "Lower limit of the Reso invariant mass"}; + Configurable ConfResoInvMassUpLimit{"ConfResoInvMassUpLimit", 1.027461, "Upper limit of the Reso invariant mass"}; + + Configurable Q3Max{"Q3Max", 1.f, "Max Q3"}; + + /*track selection*/ + + Configurable ConfTrkEtaPr{"ConfTrkEtaPr", 0.85, "Et protona"}; // 0.8 + Configurable ConfTrkDCAxyPr{"ConfTrkDCAxyPr", 0.15, "DCAxy proton"}; // 0.1 + Configurable ConfTrkDCAzPr{"ConfTrkDCAzPr", 0.3, "DCAz proton"}; // 0.2 + Configurable ConfNClusPr{"ConfNClusPr", 70, "NClusters proton"}; // 0.2 + Configurable ConfNCrossedPr{"ConfNCrossedPr", 65, "NCrossedRows proton"}; // 0.2 + Configurable ConfTrkTPCfClsPr{"ConfTrkTPCfClsPr", 0.83, "Minimum fraction of crossed rows over findable clusters proton"}; // 0.2 + + Configurable ConfTrkPtPrUp{"ConfTrkPtPrUp", 6.0, "Pt_up proton"}; // 2.0 + Configurable ConfTrkPtPrDown{"ConfTrkPtPrDown", 0.35, "Pt_down proton"}; // 0.5 + Configurable ConfTrkPTPCPrThr{"ConfTrkPTPCPrThr", 0.8, "p_TPC,Thr proton"}; // 0.75 + Configurable ConfTrkPrSigmaPID{"ConfTrkPrSigmaPID", 3.50, "n_sigma proton"}; // 3.0 + + Configurable ConfTrkEtaKa{"ConfTrkEtaKa", 0.85, "Eta kaon"}; // 0.8 + Configurable ConfTrkDCAxyKa{"ConfTrkDCAxyKa", 0.15, "DCAxy kaon"}; // 0.1 + Configurable ConfTrkDCAzKa{"ConfTrkDCAzKa", 0.3, "DCAz kaon"}; // 0.2 + Configurable ConfNClusKa{"ConfNClusKa", 70, "NClusters kaon"}; // 0.2 + Configurable ConfNCrossedKa{"ConfNCrossedKa", 65, "NCrossedRows kaon"}; // 0.2 + Configurable ConfTrkTPCfClsKa{"ConfTrkTPCfClsKa", 0.80, "Minimum fraction of crossed rows over findable clusters kaon"}; // 0.2 + + Configurable ConfTrkPtKaUp{"ConfTrkPtKaUp", 6.0, "Pt_up kaon"}; // 2.0 + Configurable ConfTrkPtKaDown{"ConfTrkPtKaDown", 0.05, "Pt_down kaon"}; // 0.15 + Configurable ConfTrkPTPCKaThr{"ConfTrkPTPCKaThr", 0.40, "p_TPC,Thr kaon"}; // 0.4 + Configurable ConfTrkKaSigmaPID{"ConfTrkKaSigmaPID", 3.50, "n_sigma kaon"}; // 3.0 + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + + // histograms + registry.add("fProcessedEvents", "CF - event filtered;;Events", HistType::kTH1F, {{3, -0.5, 2.5}}); + std::vector eventTitles = {"all", "rejected", "ppphi"}; + for (size_t iBin = 0; iBin < eventTitles.size(); iBin++) { + registry.get(HIST("fProcessedEvents"))->GetXaxis()->SetBinLabel(iBin + 1, eventTitles[iBin].data()); + } + + // event cuts + registry.add("EventCuts/fMultiplicityBefore", "Multiplicity of all processed events;Mult;Entries", HistType::kTH1F, {{1000, 0, 1000}}); + registry.add("EventCuts/fMultiplicityAfter", "Multiplicity after event cuts;Mult;Entries", HistType::kTH1F, {{1000, 0, 1000}}); + registry.add("EventCuts/fZvtxBefore", "Zvtx of all processed events;Z_{vtx};Entries", HistType::kTH1F, {{1000, -15, 15}}); + registry.add("EventCuts/fZvtxAfter", "Zvtx after event cuts;Z_{vtx};Entries", HistType::kTH1F, {{1000, -15, 15}}); + + registry.add("TrackCuts/fPtBefore", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + registry.add("TrackCuts/fEtaBefore", "Pseudorapidity of all processed tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); + registry.add("TrackCuts/fPhiBefore", "Azimuthal angle of all processed tracks;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); + + // proton cuts + registry.add("TrackCuts/Proton/fPProton", "Momentum of protons at PV;p (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + registry.add("TrackCuts/Proton/fPTPCProton", "Momentum of protons at PV;p (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + registry.add("TrackCuts/Proton/fPtProton", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + registry.add("TrackCuts/Proton/fMomCorProtonDif", "Momentum correlation;p_{reco} (GeV/c); (p_{TPC} - p_{reco}) (GeV/c)", {HistType::kTH2F, {{500, 0, 10}, {600, -3, 3}}}); + registry.add("TrackCuts/Proton/fMomCorProtonRatio", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {{500, 0, 10}, {200, -1, 1}}}); + registry.add("TrackCuts/Proton/fEtaProton", "Pseudorapidity of all processed tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); + registry.add("TrackCuts/Proton/fPhiProton", "Azimuthal angle of all processed tracks;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); + registry.add("TrackCuts/Proton/fDCAxyProton", "fDCAxy Proton;DCA_{XY};Entries", HistType::kTH1F, {{500, -0.5f, 0.5f}}); + registry.add("TrackCuts/Proton/fDCAzProton", "fDCAz Proton;DCA_{Z};Entries", HistType::kTH1F, {{500, -0.5f, 0.5f}}); + registry.add("TrackCuts/Proton/fNsigmaTPCvsPProton", "NSigmaTPC Proton;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + registry.add("TrackCuts/Proton/fNsigmaTOFvsPProton", "NSigmaTOF Proton;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + registry.add("TrackCuts/Proton/fNsigmaTPCTOFvsPProton", "NSigmaTPCTOF Proton;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); + + registry.add("TrackCuts/Proton/fTPCsClsProton", "fTPCsCls Proton;TPC Shared Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); + registry.add("TrackCuts/Proton/fTPCcRowsProton", "fTPCcRows Proton;TPC Crossed Rows;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); + registry.add("TrackCuts/Proton/fTrkTPCfClsProton", "fTrkTPCfCls Proton;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {{500, 0.0f, 3.0f}}); + registry.add("TrackCuts/Proton/fTPCnclsProton", "fTPCncls Proton;TPC Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); + + registry.add("TrackCuts/AntiProton/fPAntiProton", "Momentum of antiprotons at PV;p (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + registry.add("TrackCuts/AntiProton/fPTPCAntiProton", "Momentum of protons at PV;p (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + registry.add("TrackCuts/AntiProton/fPtAntiProton", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + registry.add("TrackCuts/AntiProton/fMomCorAntiProtonDif", "Momentum correlation;p_{reco} (GeV/c); (p_{TPC} - p_{reco}) (GeV/c)", {HistType::kTH2F, {{500, 0, 10}, {600, -3, 3}}}); + registry.add("TrackCuts/AntiProton/fMomCorAntiProtonRatio", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {{500, 0, 10}, {200, -1, 1}}}); + registry.add("TrackCuts/AntiProton/fEtaAntiProton", "Pseudorapidity of all processed tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); + registry.add("TrackCuts/AntiProton/fPhiAntiProton", "Azimuthal angle of all processed tracks;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); + registry.add("TrackCuts/AntiProton/fDCAxyAntiProton", "fDCAxy AntiProton;DCA_{XY};Entries", HistType::kTH1F, {{500, -0.5f, 0.5f}}); + registry.add("TrackCuts/AntiProton/fDCAzAntiProton", "fDCAz AntiProton;DCA_{Z};Entries", HistType::kTH1F, {{500, -0.5f, 0.5f}}); + registry.add("TrackCuts/AntiProton/fNsigmaTPCvsPAntiProton", "NSigmaTPC AntiProton;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + registry.add("TrackCuts/AntiProton/fNsigmaTOFvsPAntiProton", "NSigmaTOF AntiProton;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + registry.add("TrackCuts/AntiProton/fNsigmaTPCTOFvsPAntiProton", "NSigmaTPCTOF AntiProton;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); + + registry.add("TrackCuts/AntiProton/fTPCsClsAntiProton", "fTPCsCls AntiProton;TPC Shared Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); + registry.add("TrackCuts/AntiProton/fTPCcRowsAntiProton", "fTPCcRows AntiProton;TPC Crossed Rows;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); + registry.add("TrackCuts/AntiProton/fTrkTPCfClsAntiProton", "fTrkTPCfCls AntiProton;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {{500, 0.0f, 3.0f}}); + registry.add("TrackCuts/AntiProton/fTPCnclsAntiProton", "fTPCncls AntiProton;TPC Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); + + // kaon cuts + registry.add("TrackCuts/Kaon/fPKaon", "Momentum of kaons at PV;p (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + registry.add("TrackCuts/Kaon/fPTPCKaon", "Momentum of protons at PV;p (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + registry.add("TrackCuts/Kaon/fPtKaon", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + registry.add("TrackCuts/Kaon/fMomCorKaonDif", "Momentum correlation;p_{reco} (GeV/c); (p_{TPC} - p_{reco}) (GeV/c)", {HistType::kTH2F, {{500, 0, 10}, {600, -3, 3}}}); + registry.add("TrackCuts/Kaon/fMomCorKaonRatio", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {{500, 0, 10}, {200, -1, 1}}}); + registry.add("TrackCuts/Kaon/fEtaKaon", "Pseudorapidity of all processed tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); + registry.add("TrackCuts/Kaon/fPhiKaon", "Azimuthal angle of all processed tracks;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); + registry.add("TrackCuts/Kaon/fDCAxyKaon", "fDCAxy Kaon;DCA_{XY};Entries", HistType::kTH1F, {{500, -0.5f, 0.5f}}); + registry.add("TrackCuts/Kaon/fDCAzKaon", "fDCAz Kaon;DCA_{Z};Entries", HistType::kTH1F, {{500, -0.5f, 0.5f}}); + registry.add("TrackCuts/Kaon/fNsigmaTPCvsPKaon", "NSigmaTPC Kaon;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + registry.add("TrackCuts/Kaon/fNsigmaTOFvsPKaon", "NSigmaTOF Kaon;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + registry.add("TrackCuts/Kaon/fNsigmaTPCTOFvsPKaon", "NSigmaTPCTOF Kaon;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); + + registry.add("TrackCuts/Kaon/fTPCsClsKaon", "fTPCsCls Kaon;TPC Shared Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); + registry.add("TrackCuts/Kaon/fTPCcRowsKaon", "fTPCcRows Kaon;TPC Crossed Rows;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); + registry.add("TrackCuts/Kaon/fTrkTPCfClsKaon", "fTrkTPCfCls Kaon;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {{500, 0.0f, 3.0f}}); + registry.add("TrackCuts/Kaon/fTPCnclsKaon", "fTPCncls Kaon;TPC Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); + + registry.add("TrackCuts/AntiKaon/fPAntiKaon", "Momentum of antikaons at PV;p (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + registry.add("TrackCuts/AntiKaon/fPTPCAntiKaon", "Momentum of protons at PV;p (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + registry.add("TrackCuts/AntiKaon/fPtAntiKaon", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + registry.add("TrackCuts/AntiKaon/fMomCorAntiKaonDif", "Momentum correlation;p_{reco} (GeV/c); (p_{TPC} - p_{reco}) (GeV/c)", {HistType::kTH2F, {{500, 0, 10}, {600, -3, 3}}}); + registry.add("TrackCuts/AntiKaon/fMomCorAntiKaonRatio", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {{500, 0, 10}, {200, -1, 1}}}); + registry.add("TrackCuts/AntiKaon/fEtaAntiKaon", "Pseudorapidity of all processed tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); + registry.add("TrackCuts/AntiKaon/fPhiAntiKaon", "Azimuthal angle of all processed tracks;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); + registry.add("TrackCuts/AntiKaon/fDCAxyAntiKaon", "fDCAxy AntiKaon;DCA_{XY};Entries", HistType::kTH1F, {{500, -0.5f, 0.5f}}); + registry.add("TrackCuts/AntiKaon/fDCAzAntiKaon", "fDCAz AntiKaon;DCA_{Z};Entries", HistType::kTH1F, {{500, -0.5f, 0.5f}}); + registry.add("TrackCuts/AntiKaon/fNsigmaTPCvsPAntiKaon", "NSigmaTPC AntiKaon;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + registry.add("TrackCuts/AntiKaon/fNsigmaTOFvsPAntiKaon", "NSigmaTOF AntiKaon;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + registry.add("TrackCuts/AntiKaon/fNsigmaTPCTOFvsPAntiKaon", "NSigmaTPCTOF AntiKaon;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); + + registry.add("TrackCuts/AntiKaon/fTPCsClsAntiKaon", "fTPCsCls AntiKaon;TPC Shared Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); + registry.add("TrackCuts/AntiKaon/fTPCcRowsAntiKaon", "fTPCcRows AntiKaon;TPC Crossed Rows;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); + registry.add("TrackCuts/AntiKaon/fTrkTPCfClsAntiKaon", "fTrkTPCfCls AntiKaon;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {{500, 0.0f, 3.0f}}); + registry.add("TrackCuts/AntiKaon/fTPCnclsAntiKaon", "fTPCncls AntiKaon;TPC Clusters;Entries", HistType::kTH1F, {{163, -1.0f, 162.0f}}); + + // phi cuts + registry.add("TrackCuts/Phi/fPtPhiBefore", "Transverse momentum V0s;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + registry.add("TrackCuts/Phi/fInvMassPhiBefore", "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {{7000, 0.8, 1.5}}); + + registry.add("TrackCuts/Phi/fEtaPhiBefore", "Pseudorapidity of V0;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); + registry.add("TrackCuts/Phi/fPhiPhiBefore", "Azimuthal angle of V0;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); + + registry.add("TrackCuts/Phi/fPtPhi", "Transverse momentum V0s;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + registry.add("TrackCuts/Phi/fInvMassPhi", "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {{7000, 0.8, 1.5}}); + registry.add("TrackCuts/Phi/fEtaPhi", "Pseudorapidity of V0;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); + registry.add("TrackCuts/Phi/fPhiPhi", "Azimuthal angle of V0;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); + + // phi daughter + registry.add("TrackCuts/Phi/PosDaughter/Pt", "Transverse momentum Pos Daugh tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + registry.add("TrackCuts/Phi/PosDaughter/Eta", "Phi Pos Daugh Eta;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); + registry.add("TrackCuts/Phi/PosDaughter/Phi", "Azimuthal angle of Pos Daugh tracks;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); + + registry.add("TrackCuts/Phi/NegDaughter/Pt", "Transverse momentum Neg Daugh tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + registry.add("TrackCuts/Phi/NegDaughter/Eta", "Phi Neg Daugh Eta;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); + registry.add("TrackCuts/Phi/NegDaughter/Phi", "Azimuthal angle of Neg Daugh tracks;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); + + // triggers + registry.add("ppphi/fMultiplicity", "Multiplicity of all triggered events;Mult;Entries", HistType::kTH1F, {{1000, 0, 1000}}); + registry.add("ppphi/fZvtx", "Zvtx of all triggered events;Z_{vtx};Entries", HistType::kTH1F, {{1000, -15, 15}}); + registry.add("ppphi/fSE_particle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); + registry.add("ppphi/fSE_antiparticle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); + registry.add("ppphi/fProtonPtVsQ3", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); + registry.add("ppphi/fPhiPtVsQ3", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); + registry.add("ppphi/fAntiProtonPtVsQ3", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); + registry.add("ppphi/fAntiPhiPtVsQ3", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); + } + + template + bool isSelectedEvent(T const& col) + { + if (ConfEvtSelectZvtx && std::abs(col.posZ()) > ConfEvtZvtx) { + return false; + } + if (ConfEvtOfflineCheck && !col.sel8()) { + return false; + } + return true; + } + + template + bool isSelectedTrackProton(T const& track) + { + bool isSelected = false; + if (track.pt() <= ConfTrkPtPrUp.value && track.pt() >= ConfTrkPtPrDown.value && std::abs(track.eta()) <= ConfTrkEtaPr.value && std::abs(track.dcaXY()) <= ConfTrkDCAxyPr.value && std::abs(track.dcaZ()) <= ConfTrkDCAzPr.value && track.tpcNClsCrossedRows() >= ConfNCrossedPr.value && track.tpcNClsFound() >= ConfNClusPr.value && track.tpcCrossedRowsOverFindableCls() >= ConfTrkTPCfClsPr.value) { + if (track.tpcInnerParam() < ConfTrkPTPCPrThr.value && std::abs(track.tpcNSigmaPr()) <= ConfTrkPrSigmaPID.value) { + isSelected = true; + } + if (track.tpcInnerParam() >= ConfTrkPTPCPrThr.value && std::abs(std::sqrt(track.tpcNSigmaPr() * track.tpcNSigmaPr() + track.tofNSigmaPr() * track.tofNSigmaPr())) <= ConfTrkPrSigmaPID.value) { + isSelected = true; + } + } + return isSelected; + } + + template + bool isSelectedTrackKaon(T const& track) + { + bool isSelected = false; + if (track.pt() <= ConfTrkPtKaUp.value && track.pt() >= ConfTrkPtKaDown.value && std::abs(track.eta()) <= ConfTrkEtaKa.value && std::abs(track.dcaXY()) <= ConfTrkDCAxyKa.value && std::abs(track.dcaZ()) <= ConfTrkDCAzKa.value && track.tpcNClsCrossedRows() >= ConfNCrossedKa.value && track.tpcNClsFound() >= ConfNClusKa.value && track.tpcCrossedRowsOverFindableCls() >= ConfTrkTPCfClsKa.value) { + if (track.tpcInnerParam() < ConfTrkPTPCKaThr.value && std::abs(track.tpcNSigmaKa()) <= ConfTrkKaSigmaPID.value) { + isSelected = true; + } + if (track.tpcInnerParam() >= ConfTrkPTPCKaThr.value && std::abs(std::sqrt(track.tpcNSigmaKa() * track.tpcNSigmaKa() + track.tofNSigmaKa() * track.tofNSigmaKa())) <= ConfTrkKaSigmaPID.value) { + isSelected = true; + } + } + return isSelected; + } + + float mMassProton = o2::constants::physics::MassProton; + float mMassKaonPlus = o2::constants::physics::MassKPlus; + float mMassKaonMinus = o2::constants::physics::MassKMinus; + + float mMassPhi = o2::constants::physics::MassPhi; + + float getkstar(const ROOT::Math::PtEtaPhiMVector part1, + const ROOT::Math::PtEtaPhiMVector part2) + { + const ROOT::Math::PtEtaPhiMVector trackSum = part1 + part2; + const float beta = trackSum.Beta(); + const float betax = + beta * std::cos(trackSum.Phi()) * std::sin(trackSum.Theta()); + const float betay = + beta * std::sin(trackSum.Phi()) * std::sin(trackSum.Theta()); + const float betaz = beta * std::cos(trackSum.Theta()); + ROOT::Math::PxPyPzMVector PartOneCMS(part1); + ROOT::Math::PxPyPzMVector PartTwoCMS(part2); + const ROOT::Math::Boost boostPRF = + ROOT::Math::Boost(-betax, -betay, -betaz); + PartOneCMS = boostPRF(PartOneCMS); + PartTwoCMS = boostPRF(PartTwoCMS); + const ROOT::Math::PxPyPzMVector trackRelK = PartOneCMS - PartTwoCMS; + return 0.5 * trackRelK.P(); + } + + ROOT::Math::PxPyPzEVector getqij(const ROOT::Math::PtEtaPhiMVector parti, + const ROOT::Math::PtEtaPhiMVector partj) + { + ROOT::Math::PxPyPzEVector vecparti(parti); + ROOT::Math::PxPyPzEVector vecpartj(partj); + ROOT::Math::PxPyPzEVector trackSum = vecparti + vecpartj; + ROOT::Math::PxPyPzEVector trackDifference = vecparti - vecpartj; + float scaling = trackDifference.Dot(trackSum) / trackSum.Dot(trackSum); + return trackDifference - scaling * trackSum; + } + float getQ3(const ROOT::Math::PtEtaPhiMVector part1, + const ROOT::Math::PtEtaPhiMVector part2, + const ROOT::Math::PtEtaPhiMVector part3) + { + ROOT::Math::PxPyPzEVector q12 = getqij(part1, part2); + ROOT::Math::PxPyPzEVector q23 = getqij(part2, part3); + ROOT::Math::PxPyPzEVector q31 = getqij(part3, part1); + float Q32 = q12.M2() + q23.M2() + q31.M2(); + return sqrt(-Q32); + } + + void process(aod::FemtoFullCollision const& col, aod::BCsWithTimestamps const&, aod::FemtoFullTracks const& tracks) + { + registry.fill(HIST("fProcessedEvents"), 0); + registry.fill(HIST("EventCuts/fMultiplicityBefore"), col.multNTracksPV()); + registry.fill(HIST("EventCuts/fZvtxBefore"), col.posZ()); + + int lowQ3Triplets = 0; + + if (isSelectedEvent(col)) { + + registry.fill(HIST("EventCuts/fMultiplicityAfter"), col.multNTracksPV()); + registry.fill(HIST("EventCuts/fZvtxAfter"), col.posZ()); + + std::vector protons, antiprotons, kaons, antikaons, phi; + + // keep track of proton indices + std::vector ProtonIndex = {}; + std::vector AntiProtonIndex = {}; + std::vector KaonIndex = {}; + std::vector AntiKaonIndex = {}; + + for (auto& track : tracks) { + registry.fill(HIST("TrackCuts/fPtBefore"), track.pt()); + registry.fill(HIST("TrackCuts/fEtaBefore"), track.eta()); + registry.fill(HIST("TrackCuts/fPhiBefore"), track.phi()); + + if (isSelectedTrackProton(track)) { + ROOT::Math::PtEtaPhiMVector temp(track.pt(), track.eta(), track.phi(), mMassProton); + if (track.sign() > 0) { + protons.push_back(temp); + + registry.fill(HIST("TrackCuts/Proton/fPProton"), track.p()); + registry.fill(HIST("TrackCuts/Proton/fPTPCProton"), track.tpcInnerParam()); + registry.fill(HIST("TrackCuts/Proton/fPtProton"), track.pt()); + registry.fill(HIST("TrackCuts/Proton/fMomCorProtonDif"), track.p(), track.tpcInnerParam() - track.p()); + registry.fill(HIST("TrackCuts/Proton/fMomCorProtonRatio"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registry.fill(HIST("TrackCuts/Proton/fEtaProton"), track.eta()); + registry.fill(HIST("TrackCuts/Proton/fPhiProton"), track.phi()); + registry.fill(HIST("TrackCuts/Proton/fNsigmaTPCvsPProton"), track.tpcInnerParam(), track.tpcNSigmaPr()); + registry.fill(HIST("TrackCuts/Proton/fNsigmaTOFvsPProton"), track.tpcInnerParam(), track.tofNSigmaPr()); + registry.fill(HIST("TrackCuts/Proton/fNsigmaTPCTOFvsPProton"), track.tpcInnerParam(), std::abs(std::sqrt(track.tpcNSigmaPr() * track.tpcNSigmaPr() + track.tofNSigmaPr() * track.tofNSigmaPr()))); + + registry.fill(HIST("TrackCuts/Proton/fDCAxyProton"), track.dcaXY()); + registry.fill(HIST("TrackCuts/Proton/fDCAzProton"), track.dcaZ()); + registry.fill(HIST("TrackCuts/Proton/fTPCsClsProton"), track.tpcNClsShared()); + registry.fill(HIST("TrackCuts/Proton/fTPCcRowsProton"), track.tpcNClsCrossedRows()); + registry.fill(HIST("TrackCuts/Proton/fTrkTPCfClsProton"), track.tpcCrossedRowsOverFindableCls()); + registry.fill(HIST("TrackCuts/Proton/fTPCnclsProton"), track.tpcNClsFound()); + // ProtonIndex.push_back(track.globalIndex()); + } + if (track.sign() < 0) { + antiprotons.push_back(temp); + + registry.fill(HIST("TrackCuts/AntiProton/fPAntiProton"), track.p()); + registry.fill(HIST("TrackCuts/AntiProton/fPTPCAntiProton"), track.tpcInnerParam()); + registry.fill(HIST("TrackCuts/AntiProton/fPtAntiProton"), track.pt()); + registry.fill(HIST("TrackCuts/AntiProton/fMomCorAntiProtonDif"), track.p(), track.tpcInnerParam() - track.p()); + registry.fill(HIST("TrackCuts/AntiProton/fMomCorAntiProtonRatio"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registry.fill(HIST("TrackCuts/AntiProton/fEtaAntiProton"), track.eta()); + registry.fill(HIST("TrackCuts/AntiProton/fPhiAntiProton"), track.phi()); + registry.fill(HIST("TrackCuts/AntiProton/fNsigmaTPCvsPAntiProton"), track.tpcInnerParam(), track.tpcNSigmaPr()); + registry.fill(HIST("TrackCuts/AntiProton/fNsigmaTOFvsPAntiProton"), track.tpcInnerParam(), track.tofNSigmaPr()); + registry.fill(HIST("TrackCuts/AntiProton/fNsigmaTPCTOFvsPAntiProton"), track.tpcInnerParam(), std::abs(std::sqrt(track.tpcNSigmaPr() * track.tpcNSigmaPr() + track.tofNSigmaPr() * track.tofNSigmaPr()))); + + registry.fill(HIST("TrackCuts/AntiProton/fDCAxyAntiProton"), track.dcaXY()); + registry.fill(HIST("TrackCuts/AntiProton/fDCAzAntiProton"), track.dcaZ()); + registry.fill(HIST("TrackCuts/AntiProton/fTPCsClsAntiProton"), track.tpcNClsShared()); + registry.fill(HIST("TrackCuts/AntiProton/fTPCcRowsAntiProton"), track.tpcNClsCrossedRows()); + registry.fill(HIST("TrackCuts/AntiProton/fTrkTPCfClsAntiProton"), track.tpcCrossedRowsOverFindableCls()); + registry.fill(HIST("TrackCuts/AntiProton/fTPCnclsAntiProton"), track.tpcNClsFound()); + // AntiProtonIndex.push_back(track.globalIndex()); + } + } + + if (isSelectedTrackKaon(track)) { + ROOT::Math::PtEtaPhiMVector temp(track.pt(), track.eta(), track.phi(), mMassKaonPlus); + if (track.sign() > 0) { + temp.SetM(mMassKaonPlus); + kaons.push_back(temp); + registry.fill(HIST("TrackCuts/Kaon/fPKaon"), track.p()); + registry.fill(HIST("TrackCuts/Kaon/fPTPCKaon"), track.tpcInnerParam()); + registry.fill(HIST("TrackCuts/Kaon/fPtKaon"), track.pt()); + registry.fill(HIST("TrackCuts/Kaon/fMomCorKaonDif"), track.p(), track.tpcInnerParam() - track.p()); + registry.fill(HIST("TrackCuts/Kaon/fMomCorKaonRatio"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registry.fill(HIST("TrackCuts/Kaon/fEtaKaon"), track.eta()); + registry.fill(HIST("TrackCuts/Kaon/fPhiKaon"), track.phi()); + registry.fill(HIST("TrackCuts/Kaon/fNsigmaTPCvsPKaon"), track.tpcInnerParam(), track.tpcNSigmaKa()); + registry.fill(HIST("TrackCuts/Kaon/fNsigmaTOFvsPKaon"), track.tpcInnerParam(), track.tofNSigmaKa()); + registry.fill(HIST("TrackCuts/Kaon/fNsigmaTPCTOFvsPKaon"), track.tpcInnerParam(), std::abs(std::sqrt(track.tpcNSigmaKa() * track.tpcNSigmaKa() + track.tofNSigmaKa() * track.tofNSigmaKa()))); + + registry.fill(HIST("TrackCuts/Kaon/fDCAxyKaon"), track.dcaXY()); + registry.fill(HIST("TrackCuts/Kaon/fDCAzKaon"), track.dcaZ()); + + registry.fill(HIST("TrackCuts/Kaon/fTPCsClsKaon"), track.tpcNClsShared()); + registry.fill(HIST("TrackCuts/Kaon/fTPCcRowsKaon"), track.tpcNClsCrossedRows()); + registry.fill(HIST("TrackCuts/Kaon/fTrkTPCfClsKaon"), track.tpcCrossedRowsOverFindableCls()); + registry.fill(HIST("TrackCuts/Kaon/fTPCnclsKaon"), track.tpcNClsFound()); + // KaonIndex.push_back(track.globalIndex()); + } + if (track.sign() < 0) { + temp.SetM(mMassKaonMinus); + + antikaons.push_back(temp); + registry.fill(HIST("TrackCuts/AntiKaon/fPAntiKaon"), track.p()); + registry.fill(HIST("TrackCuts/AntiKaon/fPTPCAntiKaon"), track.tpcInnerParam()); + registry.fill(HIST("TrackCuts/AntiKaon/fPtAntiKaon"), track.pt()); + registry.fill(HIST("TrackCuts/AntiKaon/fMomCorAntiKaonDif"), track.p(), track.tpcInnerParam() - track.p()); + registry.fill(HIST("TrackCuts/AntiKaon/fMomCorAntiKaonRatio"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registry.fill(HIST("TrackCuts/AntiKaon/fEtaAntiKaon"), track.eta()); + registry.fill(HIST("TrackCuts/AntiKaon/fPhiAntiKaon"), track.phi()); + registry.fill(HIST("TrackCuts/AntiKaon/fNsigmaTPCvsPAntiKaon"), track.tpcInnerParam(), track.tpcNSigmaKa()); + registry.fill(HIST("TrackCuts/AntiKaon/fNsigmaTOFvsPAntiKaon"), track.tpcInnerParam(), track.tofNSigmaKa()); + registry.fill(HIST("TrackCuts/AntiKaon/fNsigmaTPCTOFvsPAntiKaon"), track.tpcInnerParam(), std::abs(std::sqrt(track.tpcNSigmaKa() * track.tpcNSigmaKa() + track.tofNSigmaKa() * track.tofNSigmaKa()))); + + registry.fill(HIST("TrackCuts/AntiKaon/fDCAxyAntiKaon"), track.dcaXY()); + registry.fill(HIST("TrackCuts/AntiKaon/fDCAzAntiKaon"), track.dcaZ()); + registry.fill(HIST("TrackCuts/AntiKaon/fTPCsClsAntiKaon"), track.tpcNClsShared()); + registry.fill(HIST("TrackCuts/AntiKaon/fTPCcRowsAntiKaon"), track.tpcNClsCrossedRows()); + registry.fill(HIST("TrackCuts/AntiKaon/fTrkTPCfClsAntiKaon"), track.tpcCrossedRowsOverFindableCls()); + registry.fill(HIST("TrackCuts/AntiKaon/fTPCnclsAntiKaon"), track.tpcNClsFound()); + // AntiKaonIndex.push_back(track.globalIndex()); + } + } + + // end track + } + + for (const auto& postrack : kaons) { + for (const auto& negtrack : antikaons) { + + ROOT::Math::PtEtaPhiMVector temp = postrack + negtrack; + // temp.SetM(mMassPhi); + registry.fill(HIST("TrackCuts/Phi/fInvMassPhiBefore"), temp.M()); + + registry.fill(HIST("TrackCuts/Phi/fPtPhiBefore"), temp.pt()); + registry.fill(HIST("TrackCuts/Phi/fEtaPhiBefore"), temp.eta()); + registry.fill(HIST("TrackCuts/Phi/fPhiPhiBefore"), temp.phi()); + + if ((temp.M() >= ConfResoInvMassLowLimit.value) && (temp.M() <= ConfResoInvMassUpLimit.value)) { + // ROOT::Math::PtEtaPhiMVector temp = postrack + negtrack; + phi.push_back(temp); + + registry.fill(HIST("TrackCuts/Phi/fPtPhi"), temp.pt()); + registry.fill(HIST("TrackCuts/Phi/fEtaPhi"), temp.eta()); + registry.fill(HIST("TrackCuts/Phi/fPhiPhi"), temp.phi()); + registry.fill(HIST("TrackCuts/Phi/fInvMassPhi"), temp.M()); + + registry.fill(HIST("TrackCuts/Phi/PosDaughter/Pt"), postrack.pt()); + registry.fill(HIST("TrackCuts/Phi/PosDaughter/Eta"), postrack.eta()); + registry.fill(HIST("TrackCuts/Phi/PosDaughter/Phi"), postrack.phi()); + + registry.fill(HIST("TrackCuts/Phi/NegDaughter/Pt"), negtrack.pt()); + registry.fill(HIST("TrackCuts/Phi/NegDaughter/Eta"), negtrack.eta()); + registry.fill(HIST("TrackCuts/Phi/NegDaughter/Phi"), negtrack.phi()); + } + } + } + + // ppphi trigger + float Q3 = 999.f; + + for (auto iProton1 = protons.begin(); iProton1 != protons.end(); ++iProton1) { + auto iProton2 = iProton1 + 1; + // auto i1 = std::distance(protons.begin(), iProton1); + for (; iProton2 != protons.end(); ++iProton2) { + // auto i2 = std::distance(protons.begin(), iProton2); + for (auto iPhi1 = phi.begin(); iPhi1 != phi.end(); ++iPhi1) { + // auto i3 = std::distance(phi.begin(), iPhi1); + + Q3 = getQ3(*iProton1, *iProton2, *iPhi1); + registry.fill(HIST("ppphi/fSE_particle"), Q3); + registry.fill(HIST("ppphi/fProtonPtVsQ3"), Q3, (*iProton1).Pt()); + registry.fill(HIST("ppphi/fProtonPtVsQ3"), Q3, (*iProton2).Pt()); + registry.fill(HIST("ppphi/fPhiPtVsQ3"), Q3, (*iPhi1).Pt()); + if (Q3 < Q3Max.value) { + lowQ3Triplets += 1; + } + } + } + } + + // apapphi trigger + + for (auto iAntiProton1 = antiprotons.begin(); iAntiProton1 != antiprotons.end(); ++iAntiProton1) { + auto iAntiProton2 = iAntiProton1 + 1; + // auto i1 = std::distance(antiprotons.begin(), iAntiProton1); + for (; iAntiProton2 != antiprotons.end(); ++iAntiProton2) { + // auto i2 = std::distance(antiprotons.begin(), iAntiProton2); + for (auto iPhi1 = phi.begin(); iPhi1 != phi.end(); ++iPhi1) { + // auto i3 = std::distance(phi.begin(), iPhi1); + + Q3 = getQ3(*iAntiProton1, *iAntiProton2, *iPhi1); + registry.fill(HIST("ppphi/fSE_antiparticle"), Q3); + registry.fill(HIST("ppphi/fAntiProtonPtVsQ3"), Q3, (*iAntiProton1).Pt()); + registry.fill(HIST("ppphi/fAntiProtonPtVsQ3"), Q3, (*iAntiProton2).Pt()); + registry.fill(HIST("ppphi/fAntiPhiPtVsQ3"), Q3, (*iPhi1).Pt()); + if (Q3 < Q3Max.value) { + lowQ3Triplets += 1; + } + } + } + } + + // end event + } + + // create tags for three body triggers + if (lowQ3Triplets > 0) { + registry.fill(HIST("fProcessedEvents"), 2); + registry.fill(HIST("ppphi/fMultiplicity"), col.multNTracksPV()); + registry.fill(HIST("ppphi/fZvtx"), col.posZ()); + } else { + registry.fill(HIST("fProcessedEvents"), 1); + } + }; +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfg) +{ + return WorkflowSpec{adaptAnalysisTask(cfg)}; +} diff --git a/EventFiltering/PWGEM/EMPhotonFilter.cxx b/EventFiltering/PWGEM/EMPhotonFilter.cxx index 5740bba1b91..a254c7245a1 100644 --- a/EventFiltering/PWGEM/EMPhotonFilter.cxx +++ b/EventFiltering/PWGEM/EMPhotonFilter.cxx @@ -32,7 +32,7 @@ using namespace o2::framework::expressions; using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; -using MyPrimaryElectrons = soa::Join; +using MyPrimaryElectrons = soa::Join; using MyPrimaryElectron = MyPrimaryElectrons::iterator; struct EMPhotonFilter { diff --git a/EventFiltering/PWGEM/HeavyNeutralMesonFilter.cxx b/EventFiltering/PWGEM/HeavyNeutralMesonFilter.cxx new file mode 100644 index 00000000000..5d8fd72ba39 --- /dev/null +++ b/EventFiltering/PWGEM/HeavyNeutralMesonFilter.cxx @@ -0,0 +1,1260 @@ +// 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 HeavyNeutralMesonFilter.cxx +/// +/// \brief This code loops over collisions to filter events contaning heavy neutral mesons (omega or eta') using EMCal clusters and V0s (PCM) +/// +/// \author Nicolas Strangmann (nicolas.strangmann@cern.ch) - Goethe University Frankfurt; Maximilian Korwieser (maximilian.korwieser@cern.ch) - Technical University Munich +/// + +#include +#include +#include + +#include "Math/GenVector/Boost.h" +#include "Math/Vector4D.h" +#include "TMath.h" +#include "TRandom3.h" + +#include "PWGEM/PhotonMeson/Utils/HNMUtilities.h" +#include "PWGJE/DataModel/EMCALMatchedCollisions.h" + +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "fairlogger/Logger.h" +#include "Framework/Configurable.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "CommonConstants/MathConstants.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::pwgem::photonmeson; + +namespace o2::aod +{ +using MyBCs = soa::Join; +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; +using SelectedTracks = soa::Join; +} // namespace o2::aod + +namespace hnmtrigger +{ +enum FemtoTriggers { + kPPOmega, + kPPEtaPrime, + kOmegaD, + kEtaPrimeD, + kOmegaP, + kEtaPrimeP, + kNFemtoTriggers +}; + +enum TracksPID { + kProton, + kDeuteron, + kPion, + kNFemtoPartners +}; + +enum PIDLimits { kTPCMin, + kTPCMax, + kTPCTOF, + kITSmin, + kITSmax, + kNPIDLimits +}; +const std::vector speciesName{"proton", "Deuteron", "pion"}; +const std::vector pTCutsName{"Pt min", "Pt max", "P TOF thres"}; +const std::vector pidCutsName{"TPC min", "TPC max", "TPCTOF max", "ITS min", "ITS max"}; +const std::vector femtoFilterNames{"PPOmega", "PPEtaPrime", "Omegad", "EtaPrimed", "OmegaP", "EtaPrimeP"}; + +// configs for tracks +const float pidcutsTable[kNFemtoPartners][kNPIDLimits]{ + {-4.f, 4.f, 4.f, -99.f, 99.f}, + {-4.f, 4.f, 4.f, -6.f, 6.f}, + {-4.f, 4.f, 4.f, -99.f, 99.f}}; + +const float ptcutsTable[kNFemtoPartners][3]{ + {0.35f, 6.f, 0.75f}, + {0.55f, 2.f, 1.2f}, + {0.35f, 6.f, 0.75f}}; + +const float nClusterMinTPC[1][kNFemtoPartners]{{80.0f, 80.0f, 80.0f}}; +const float nClusterMinITS[1][kNFemtoPartners]{{4, 4, 4}}; + +static const float triggerSwitches[1][kNFemtoTriggers]{{1, 1, 1, 1, 1, 1}}; +const float triggerLimits[1][kNFemtoTriggers]{{1.f, 1.f, 1.f, 1.f, 1.f, 1.f}}; +} // namespace hnmtrigger + +struct HeavyNeutralMesonFilter { + Produces tags; + + // --------------------------------> Configurables <------------------------------------ + // - Event selection cuts + // - Track selection cuts + // - Cluster shifts + // - HNM mass selection windows + // - HNM min pTs / k*'s + // ------------------------------------------------------------------------------------- + // ---> Event selection + Configurable confEvtSelectZvtx{"confEvtSelectZvtx", true, "Event selection includes max. z-Vertex"}; + Configurable confEvtZvtx{"confEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; + Configurable confEvtRequireSel8{"confEvtRequireSel8", false, "Evt sel: check for offline selection (sel8)"}; + + // ---> Track selection + Configurable> cfgPtCuts{"cfgPtCuts", {hnmtrigger::ptcutsTable[0], hnmtrigger::kNFemtoPartners, 3, hnmtrigger::speciesName, hnmtrigger::pTCutsName}, "Track pT selections"}; + Configurable cfgTrkEta{"cfgTrkEta", 0.9, "Eta"}; + Configurable> cfgTPCNClustersMin{"cfgTPCNClustersMin", {hnmtrigger::nClusterMinTPC[0], 1, hnmtrigger::kNFemtoPartners, std::vector{"TPCNClusMin"}, hnmtrigger::speciesName}, "Mininum of TPC Clusters"}; + Configurable cfgTrkTPCfCls{"cfgTrkTPCfCls", 0.83, "Minimum fraction of crossed rows over findable clusters"}; + Configurable cfgTrkTPCcRowsMin{"cfgTrkTPCcRowsMin", 70, "Minimum number of crossed TPC rows"}; + Configurable cfgTrkTPCsClsSharedFrac{"cfgTrkTPCsClsSharedFrac", 1.f, "Fraction of shared TPC clusters"}; + Configurable> cfgTrkITSnclsMin{"cfgTrkITSnclsMin", {hnmtrigger::nClusterMinITS[0], 1, hnmtrigger::kNFemtoPartners, std::vector{"Cut"}, hnmtrigger::speciesName}, "Minimum number of ITS clusters"}; + Configurable cfgTrkDCAxyMax{"cfgTrkDCAxyMax", 0.15, "Maximum DCA_xy"}; + Configurable cfgTrkDCAzMax{"cfgTrkDCAzMax", 0.3, "Maximum DCA_z"}; + Configurable cfgTrkMaxChi2PerClusterTPC{"cfgTrkMaxChi2PerClusterTPC", 4.0f, "Minimal track selection: max allowed chi2 per TPC cluster"}; // 4.0 is default of global tracks on 20.01.2023 + Configurable cfgTrkMaxChi2PerClusterITS{"cfgTrkMaxChi2PerClusterITS", 36.0f, "Minimal track selection: max allowed chi2 per ITS cluster"}; // 36.0 is default of global tracks on 20.01.2023 + + Configurable> cfgPIDCuts{"cfgPIDCuts", {hnmtrigger::pidcutsTable[0], hnmtrigger::kNFemtoPartners, hnmtrigger::kNPIDLimits, hnmtrigger::speciesName, hnmtrigger::pidCutsName}, "Femtopartner PID nsigma selections"}; // PID selections + + // ---> Configurables to allow for a shift in eta/phi of EMCal clusters to better align with extrapolated TPC tracks + Configurable cfgDoEMCShift{"cfgDoEMCShift", false, "Apply SM-wise shift in eta and phi to EMCal clusters to align with TPC tracks"}; + Configurable> cfgEMCEtaShift{"cfgEMCEtaShift", {0.f}, "values for SM-wise shift in eta to be added to EMCal clusters to align with TPC tracks"}; + Configurable> cfgEMCPhiShift{"cfgEMCPhiShift", {0.f}, "values for SM-wise shift in phi to be added to EMCal clusters to align with TPC tracks"}; + static const int nSMs = 20; + std::array emcEtaShift = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + std::array emcPhiShift = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + // ---> Shift the omega/eta' mass based on the difference of the reconstructed mass of the pi0/eta to its PDG mass to reduce smearing caused by EMCal/PCM in photon measurement + Configurable cfgHNMMassCorrection{"cfgHNMMassCorrection", 1, "Use GG PDG mass to correct HNM mass (0 = off, 1 = subDeltaPi0, 2 = subLambda)"}; + + // ---> Mass windows for the selection of heavy neutral mesons (also based on mass of their light neutral meson decay daughter) + static constexpr float DefaultMassWindows[2][4] = {{0., 0.4, 0.6, 1.}, {0.4, 0.8, 0.8, 1.2}}; + Configurable> cfgMassWindowOmega{"cfgMassWindowOmega", {DefaultMassWindows[0], 4, {"pi0_min", "pi0_max", "omega_min", "omega_max"}}, "Mass window for selected omegas and their decay pi0"}; + Configurable> cfgMassWindowEtaPrime{"cfgMassWindowEtaPrime", {DefaultMassWindows[1], 4, {"eta_min", "eta_max", "etaprime_min", "etaprime_max"}}, "Mass window for selected eta' and their decay eta"}; + + // ---> Minimum pT values for the trigger decisions of the spectra and femto trigger. The femto triggers additionally require a given k*/Q3 + static constexpr float DefaultSpectraMinPts[4] = {1.8, 1.8, 2.6, 2.6}; + static constexpr float DefaultFemtoMinPts[4] = {1.8, 1.8, 2.6, 2.6}; + Configurable> cfgMinHNMPtsSpectrumTrigger{"cfgMinHNMPtsSpectrumTrigger", {DefaultSpectraMinPts, 4, {"PCM_omega", "PCM_etaprime", "EMC_omega", "EMC_etaprime"}}, "Minimum pT values for the spetra trigger decisions (GeV/c)"}; + Configurable> cfgMinHNMPtsFemtoTrigger{"cfgMinHNMPtsFemtoTrigger", {DefaultFemtoMinPts, 4, {"PCM_omega", "PCM_etaprime", "EMC_omega", "EMC_etaprime"}}, "Minimum pT values for the femto trigger decisions (GeV/c)"}; + Configurable> cfgKinematicLimits{"cfgKinematicLimits", {hnmtrigger::triggerLimits[0], 1, hnmtrigger::kNFemtoTriggers, std::vector{"Limit"}, hnmtrigger::femtoFilterNames}, "Maximum K* (Q_3) for two (three) body femto trigger"}; + + Configurable> cfgTriggerSwitches{"cfgTriggerSwitches", {hnmtrigger::triggerSwitches[0], 1, hnmtrigger::kNFemtoTriggers, std::vector{"Switch"}, hnmtrigger::femtoFilterNames}, "Turn on specific trigger"}; + + HistogramRegistry mHistManager{"HeavyNeutralMesonFilterHistograms", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Prepare vectors for different species + std::vector vGGs; + std::vector vHNMs; + std::vector etaPrimeEMC, etaPrimePCM, omegaEMC, omegaPCM, proton, antiproton, deuteron, antideuteron, pion, antipion; + float mMassProton = constants::physics::MassProton; + float mMassDeuteron = constants::physics::MassDeuteron; + float mMassOmega = 0.782; + float mMassEtaPrime = 0.957; + float mMassPionCharged = constants::physics::MassPionCharged; + + Preslice perCollisionPCM = aod::v0photonkf::collisionId; + Preslice perCollisionEMC = aod::skimmedcluster::collisionId; + + bool colContainsPCMOmega, colContainsEMCOmega, colContainsPCMEtaPrime, colContainsEMCEtaPrime = false; + + template + bool isSelectedTrack(T const& track, hnmtrigger::TracksPID partSpecies) + { + if (track.pt() < cfgPtCuts->get(partSpecies, "Pt min")) + return false; + if (track.pt() > cfgPtCuts->get(partSpecies, "Pt max")) + return false; + if (std::abs(track.eta()) > cfgTrkEta) + return false; + if (track.tpcNClsFound() < cfgTPCNClustersMin->get("TPCNClusMin", partSpecies)) + return false; + if (track.tpcCrossedRowsOverFindableCls() < cfgTrkTPCfCls) + return false; + if (track.tpcNClsCrossedRows() < cfgTrkTPCcRowsMin) + return false; + if (track.tpcFractionSharedCls() > cfgTrkTPCsClsSharedFrac) + return false; + if (track.itsNCls() < cfgTrkITSnclsMin->get(static_cast(0), partSpecies)) + return false; + if (std::abs(track.dcaXY()) > cfgTrkDCAxyMax) + return false; + if (std::abs(track.dcaZ()) > cfgTrkDCAzMax) + return false; + if (track.tpcChi2NCl() > cfgTrkMaxChi2PerClusterTPC) + return false; + if (track.itsChi2NCl() > cfgTrkMaxChi2PerClusterITS) + return false; + return true; + } + + template + bool isSelectedTrackPID(T const& track, hnmtrigger::TracksPID partSpecies) + { + // nSigma should have entries [proton, deuteron, pion] + bool isSelected = false; + + float nSigmaTrackTPC = -999.f; + float nSigmaTrackTOF = -999.f; + float nSigmaTrackITS = -999.f; + + switch (partSpecies) { + case hnmtrigger::kProton: + nSigmaTrackTPC = track.tpcNSigmaPr(); + nSigmaTrackTOF = track.tofNSigmaPr(); + nSigmaTrackITS = track.itsNSigmaPr(); + break; + case hnmtrigger::kDeuteron: + nSigmaTrackTPC = track.tpcNSigmaDe(); + nSigmaTrackTOF = track.tofNSigmaDe(); + nSigmaTrackITS = track.itsNSigmaDe(); + break; + case hnmtrigger::kPion: + nSigmaTrackTPC = track.tpcNSigmaPi(); + nSigmaTrackTOF = track.tofNSigmaPi(); + nSigmaTrackITS = track.itsNSigmaPi(); + break; + default: + LOG(fatal) << "Particle species not known"; + } + + float nSigmaTrackTPCTOF = std::sqrt(std::pow(nSigmaTrackTPC, 2) + std::pow(nSigmaTrackTOF, 2)); + + if (track.p() <= cfgPtCuts->get(partSpecies, "P TOF thres")) { + if (nSigmaTrackTPC > cfgPIDCuts->get(partSpecies, hnmtrigger::kTPCMin) && + nSigmaTrackTPC < cfgPIDCuts->get(partSpecies, hnmtrigger::kTPCMax) && + nSigmaTrackITS > cfgPIDCuts->get(partSpecies, hnmtrigger::kITSmin) && + nSigmaTrackITS < cfgPIDCuts->get(partSpecies, hnmtrigger::kITSmax)) { + isSelected = true; + } + } else { + if (nSigmaTrackTPCTOF < cfgPIDCuts->get(partSpecies, hnmtrigger::kTPCTOF)) { + isSelected = true; + } + } + return isSelected; + } + + template + bool isSelectedEvent(T const& col) + { + if (confEvtSelectZvtx && std::abs(col.posZ()) > confEvtZvtx) + return false; + if (confEvtRequireSel8 && !col.sel8()) + return false; + return true; + } + + float getkstar(const ROOT::Math::PtEtaPhiMVector part1, + const ROOT::Math::PtEtaPhiMVector part2) + { + const ROOT::Math::PtEtaPhiMVector trackSum = part1 + part2; + const float beta = trackSum.Beta(); + const float betax = beta * std::cos(trackSum.Phi()) * std::sin(trackSum.Theta()); + const float betay = beta * std::sin(trackSum.Phi()) * std::sin(trackSum.Theta()); + const float betaz = beta * std::cos(trackSum.Theta()); + ROOT::Math::PxPyPzMVector partOneCMS(part1); + ROOT::Math::PxPyPzMVector partTwoCMS(part2); + const ROOT::Math::Boost boostPRF = ROOT::Math::Boost(-betax, -betay, -betaz); + partOneCMS = boostPRF(partOneCMS); + partTwoCMS = boostPRF(partTwoCMS); + const ROOT::Math::PxPyPzMVector trackRelK = partOneCMS - partTwoCMS; + return 0.5 * trackRelK.P(); + } + + ROOT::Math::PxPyPzEVector getqij(const ROOT::Math::PtEtaPhiMVector parti, + const ROOT::Math::PtEtaPhiMVector partj) + { + ROOT::Math::PxPyPzEVector vecparti(parti); + ROOT::Math::PxPyPzEVector vecpartj(partj); + ROOT::Math::PxPyPzEVector trackSum = vecparti + vecpartj; + ROOT::Math::PxPyPzEVector trackDifference = vecparti - vecpartj; + float scaling = trackDifference.Dot(trackSum) / trackSum.Dot(trackSum); + return trackDifference - scaling * trackSum; + } + float getQ3(const ROOT::Math::PtEtaPhiMVector part1, + const ROOT::Math::PtEtaPhiMVector part2, + const ROOT::Math::PtEtaPhiMVector part3) + { + ROOT::Math::PxPyPzEVector q12 = getqij(part1, part2); + ROOT::Math::PxPyPzEVector q23 = getqij(part2, part3); + ROOT::Math::PxPyPzEVector q31 = getqij(part3, part1); + float q32 = q12.M2() + q23.M2() + q31.M2(); + return std::sqrt(-q32); + } + + void init(InitContext const&) + { + mHistManager.add("Event/nGGs", "Number of (selected) #gamma#gamma paris;#bf{#it{N}^{#gamma#gamma}};#bf{#it{N}_{selected}^{#gamma#gamma}}", HistType::kTH2F, {{51, -0.5, 50.5}, {51, -0.5, 50.5}}); + mHistManager.add("Event/nHeavyNeutralMesons", "Number of (selected) HNM candidates;#bf{#it{N}^{HNM}};#bf{#it{N}_{selected}^{HNM}}", HistType::kTH2F, {{51, -0.5, 50.5}, {51, -0.5, 50.5}}); + mHistManager.add("Event/nClustersVsV0s", "Number of clusters and V0s in the collision;#bf{#it{N}^{clusters}};#bf{#it{N}^{V0s}}", HistType::kTH2F, {{26, -0.5, 25.5}, {26, -0.5, 25.5}}); + mHistManager.add("Event/nEMCalEvents", "Number of collisions with a certain combination of EMCal triggers;;#bf{#it{N}_{collisions}}", HistType::kTH1F, {{5, -0.5, 4.5}}); + std::vector nEventTitles = {"Cells & kTVXinEMC", "Cells & L0", "Cells & !kTVXinEMC & !L0", "!Cells & kTVXinEMC", "!Cells & L0"}; + for (size_t iBin = 0; iBin < nEventTitles.size(); iBin++) + mHistManager.get(HIST("Event/nEMCalEvents"))->GetXaxis()->SetBinLabel(iBin + 1, nEventTitles[iBin].data()); + mHistManager.add("Event/fMultiplicityBefore", "Multiplicity of all processed events;#bf{#it{N}_{tracks}};#bf{#it{N}_{collisions}}", HistType::kTH1F, {{500, 0, 500}}); + mHistManager.add("Event/fMultiplicityAfter", "Multiplicity after event cuts;#bf{#it{N}_{tracks}};#bf{#it{N}_{collisions}}", HistType::kTH1F, {{500, 0, 500}}); + mHistManager.add("Event/fZvtxBefore", "Zvtx of all processed events;#bf{z_{vtx} (cm)};#bf{#it{N}_{collisions}}", HistType::kTH1F, {{500, -15, 15}}); + mHistManager.add("Event/fZvtxAfter", "Zvtx after event cuts;#bf{z_{vtx} (cm)};#bf{#it{N}_{collisions}}", HistType::kTH1F, {{500, -15, 15}}); + mHistManager.add("fProcessedEvents", "CF - event filtered;;Events", HistType::kTH1F, {{12, -0.5, 11.5}}); + std::vector pEventTitles = {"all", "rejected", "PCM #omega", "EMC #omega", "PCM #eta'", "EMC #eta'", "PPOmega", "PPEtaPrime", "Omegad", "EtaPrimed", "OmegaP", "EtaPrimeP"}; + for (size_t iBin = 0; iBin < pEventTitles.size(); iBin++) + mHistManager.get(HIST("fProcessedEvents"))->GetXaxis()->SetBinLabel(iBin + 1, pEventTitles[iBin].data()); + + mHistManager.add("GG/invMassVsPt_PCM", "Invariant mass and pT of gg candidates;#bf{#it{M}^{#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#gamma#gamma} (GeV/#it{c})}", HistType::kTH2F, {{400, 0., 0.8}, {250, 0., 25.}}); + mHistManager.add("GG/invMassVsPt_PCMEMC", "Invariant mass and pT of gg candidates;#bf{#it{M}^{#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#gamma#gamma} (GeV/#it{c})}", HistType::kTH2F, {{400, 0., 0.8}, {250, 0., 25.}}); + mHistManager.add("GG/invMassVsPt_EMC", "Invariant mass and pT of gg candidates;#bf{#it{M}^{#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#gamma#gamma} (GeV/#it{c})}", HistType::kTH2F, {{400, 0., 0.8}, {250, 0., 25.}}); + + // Momentum correlations p vs p_TPC + mHistManager.add("TrackCuts/TracksBefore/fMomCorrelationPos", "fMomCorrelation;#bf{#it{p} (GeV/#it{c})};#bf{#it{p}_{TPC} (GeV/#it{c})}", {HistType::kTH2F, {{500, 0.0f, 20.0f}, {500, 0.0f, 20.0f}}}); + mHistManager.add("TrackCuts/TracksBefore/fMomCorrelationNeg", "fMomCorrelation;#bf{#it{p} (GeV/#it{c})};#bf{#it{p}_{TPC} (GeV/#it{c})}", {HistType::kTH2F, {{500, 0.0f, 20.0f}, {500, 0.0f, 20.0f}}}); + + // All tracks + mHistManager.add("TrackCuts/TracksBefore/fPtTrackBefore", "Transverse momentum of all processed tracks;#bf{#it{p}_{T} (GeV/#it{c})};#bf{#it{N}_{tracks}}", HistType::kTH1F, {{500, 0, 10}}); + mHistManager.add("TrackCuts/TracksBefore/fEtaTrackBefore", "Pseudorapidity of all processed tracks;#eta;#bf{#it{N}_{tracks}}", HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add("TrackCuts/TracksBefore/fPhiTrackBefore", "Azimuthal angle of all processed tracks;#phi;#bf{#it{N}_{tracks}}", HistType::kTH1F, {{720, 0, constants::math::TwoPI}}); + + // TPC signal + mHistManager.add("TrackCuts/TPCSignal/fTPCSignalTPCP", "TPCSignal;#bf{#it{p}_{TPC} (GeV/#it{c})};#bf{TPC d#it{E}/d#it{x}}", {HistType::kTH2F, {{500, 0.0f, 6.0f}, {2000, -100.f, 500.f}}}); + mHistManager.add("TrackCuts/TPCSignal/fTPCSignal", "TPCSignalP;#bf{#it{p} (GeV/#it{c})};#bf{TPC d#it{E}/d#it{x}}", {HistType::kTH2F, {{500, 0.0f, 6.0f}, {2000, -100.f, 500.f}}}); + // TPC signal antiparticles (negative charge) + mHistManager.add("TrackCuts/TPCSignal/fTPCSignalAntiTPCP", "TPCSignal;#bf{#it{p}_{TPC} (GeV/#it{c})};#bf{TPC d#it{E}/d#it{x}}", {HistType::kTH2F, {{500, 0.0f, 6.0f}, {2000, -100.f, 500.f}}}); + mHistManager.add("TrackCuts/TPCSignal/fTPCSignalAnti", "TPCSignalP;#bf{#it{p} (GeV/#it{c})};#bf{TPC d#it{E}/d#it{x}}", {HistType::kTH2F, {{500, 0.0f, 6.0f}, {2000, -100.f, 500.f}}}); + + const int nTrackSpecies = 2 * hnmtrigger::kNFemtoPartners; // x2 because of anti particles + const char* particleSpecies[nTrackSpecies] = {"Proton", "AntiProton", "Deuteron", "AntiDeuteron", "Pion", "AntiPion"}; + const char* particleSpeciesLatex[nTrackSpecies] = {"p", "#bar{p}", "d", "#bar{d}", "#pi^{+}", "#pi^{-}"}; + + for (int iParticle = 0; iParticle < nTrackSpecies; iParticle++) { + mHistManager.add(Form("TrackCuts/TracksBefore/fMomCorrelationAfterCuts%s", particleSpecies[iParticle]), Form("%s momentum correlation;#bf{#it{p} (GeV/#it{c})};#bf{#it{p}_{TPC} (GeV/#it{c})}", particleSpecies[iParticle]), {HistType::kTH2F, {{500, 0.0f, 20.0f}, {500, 0.0f, 20.0f}}}); + mHistManager.add(Form("TrackCuts/TPCSignal/fTPCSignal%s", particleSpecies[iParticle]), Form("%s TPC energy loss;#bf{#it{p}_{TPC}^{%s} (GeV/#it{c})};#bf{TPC d#it{E}/d#it{x}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{500, 0.0f, 6.0f}, {10000, -100.f, 500.f}}}); + + mHistManager.add(Form("TrackCuts/%s/fP", particleSpecies[iParticle]), Form("%s momentum at PV;#bf{#it{p}^{%s} (GeV/#it{c})};#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{500, 0, 10}}); + mHistManager.add(Form("TrackCuts/%s/fPt", particleSpecies[iParticle]), Form("%s transverse momentum;#bf{#it{p}_{T}^{%s} (GeV/#it{c})};#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{500, 0, 10}}); + mHistManager.add(Form("TrackCuts/%s/fMomCorDif", particleSpecies[iParticle]), Form("Momentum correlation;#bf{#it{p}^{%s} (GeV/#it{c})};#bf{#it{p}_{TPC}^{%s} - #it{p}^{%s} (GeV/#it{c})}", particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{500, 0, 10}, {600, -3, 3}}}); + mHistManager.add(Form("TrackCuts/%s/fMomCorRatio", particleSpecies[iParticle]), Form("Relative momentum correlation;#bf{#it{p}^{%s} (GeV/#it{c})};#bf{#it{p}_{TPC}^{%s} - #it{p}^{%s} / #it{p}^{%s}}", particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{500, 0, 10}, {200, -1, 1}}}); + mHistManager.add(Form("TrackCuts/%s/fEta", particleSpecies[iParticle]), Form("%s pseudorapidity distribution;#eta;#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add(Form("TrackCuts/%s/fPhi", particleSpecies[iParticle]), Form("%s azimuthal angle distribution;#phi;#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{720, 0, constants::math::TwoPI}}); + + mHistManager.add(Form("TrackCuts/%s/fNsigmaTPCvsTPCP", particleSpecies[iParticle]), Form("NSigmaTPC %s;#bf{#it{p}_{TPC}^{%s} (GeV/#it{c})};#bf{n#sigma_{TPC}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + mHistManager.add(Form("TrackCuts/%s/fNsigmaTOFvsTPCP", particleSpecies[iParticle]), Form("NSigmaTOF %s;#bf{#it{p}_{TPC}^{%s} (GeV/#it{c})};#bf{n#sigma_{TOF}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + mHistManager.add(Form("TrackCuts/%s/fNsigmaTPCTOFvsTPCP", particleSpecies[iParticle]), Form("NSigmaTPCTOF %s;#bf{#it{p}_{TPC}^{%s} (GeV/#it{c})};n#sigma_{comb}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); + mHistManager.add(Form("TrackCuts/%s/fNsigmaITSvsP", particleSpecies[iParticle]), Form("NSigmaITS %s;#bf{#it{p}^{%s} (GeV/#it{c})};#bf{n#sigma_{ITS}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + mHistManager.add(Form("TrackCuts/%s/fNsigmaTPCvsP", particleSpecies[iParticle]), Form("NSigmaTPC %s P;#bf{#it{p}^{%s} (GeV/#it{c})};#bf{n#sigma_{TPC}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + mHistManager.add(Form("TrackCuts/%s/fNsigmaTOFvsP", particleSpecies[iParticle]), Form("NSigmaTOF %s P;#bf{#it{p}^{%s} (GeV/#it{c})};#bf{n#sigma_{TOF}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + mHistManager.add(Form("TrackCuts/%s/fNsigmaTPCTOFvsP", particleSpecies[iParticle]), Form("NSigmaTPCTOF %s P;#bf{#it{p}^{%s} (GeV/#it{c})};#bf{n#sigma_{comb}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); + + mHistManager.add(Form("TrackCuts/%s/fDCAxy", particleSpecies[iParticle]), Form("fDCAxy %s;#bf{DCA_{xy}};#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{500, -0.5f, 0.5f}}); + mHistManager.add(Form("TrackCuts/%s/fDCAz", particleSpecies[iParticle]), Form("fDCAz %s;#bf{DCA_{z}};#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{500, -0.5f, 0.5f}}); + mHistManager.add(Form("TrackCuts/%s/fTPCsCls", particleSpecies[iParticle]), Form("fTPCsCls %s;#bf{TPC Shared Clusters};#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{163, -1.0f, 162.0f}}); + mHistManager.add(Form("TrackCuts/%s/fTPCcRows", particleSpecies[iParticle]), Form("fTPCcRows %s;#bf{TPC Crossed Rows};#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{163, -1.0f, 162.0f}}); + mHistManager.add(Form("TrackCuts/%s/fTrkTPCfCls", particleSpecies[iParticle]), Form("fTrkTPCfCls %s;#bf{TPC Findable/CrossedRows};#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{500, 0.0f, 3.0f}}); + mHistManager.add(Form("TrackCuts/%s/fTPCncls", particleSpecies[iParticle]), Form("fTPCncls %s;#bf{TPC Clusters};#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{163, -1.0f, 162.0f}}); + } + + // --> HNM QA + // pi+ daughter + mHistManager.add("HNM/Before/PosDaughter/fInvMass", "Invariant mass HMN Pos Daugh;#bf{#it{M}^{#pi^{+}} (GeV/#it{c}^{2})};#bf{#it{N}^{#pi^{+}}}", HistType::kTH1F, {{200, 0, 0.2}}); + mHistManager.add("HNM/Before/PosDaughter/fPt", "Transverse momentum HMN Pos Daugh tracks;#bf{#it{p}_{T} (GeV/#it{c})};#bf{#it{N}^{#pi^{+}}}", HistType::kTH1F, {{500, 0, 10}}); + mHistManager.add("HNM/Before/PosDaughter/fEta", "HMN Pos Daugh Eta;#eta;#bf{#it{N}^{#pi^{+}}}", HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add("HNM/Before/PosDaughter/fPhi", "Azimuthal angle of HMN Pos Daugh tracks;#phi;#bf{#it{N}^{#pi^{+}}}", HistType::kTH1F, {{720, 0, constants::math::TwoPI}}); + // pi- daughter + mHistManager.add("HNM/Before/NegDaughter/fInvMass", "Invariant mass HMN Neg Daugh;#bf{#it{M}^{#pi^{-}} (GeV/#it{c}^{2})};#bf{#it{N}^{#pi^{-}}}", HistType::kTH1F, {{200, 0, 0.2}}); + mHistManager.add("HNM/Before/NegDaughter/fPt", "Transverse momentum HMN Neg Daugh tracks;#bf{#it{p}_{T} (GeV/#it{c})};#bf{#it{N}^{#pi^{-}}}", HistType::kTH1F, {{500, 0, 10}}); + mHistManager.add("HNM/Before/NegDaughter/fEta", "HMN Neg Daugh Eta;#eta;#bf{#it{N}^{#pi^{-}}}", HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add("HNM/Before/NegDaughter/fPhi", "Azimuthal angle of HMN Neg Daugh tracks;#phi;#bf{#it{N}^{#pi^{-}}}", HistType::kTH1F, {{720, 0, constants::math::TwoPI}}); + // Properties of the pi+pi- pair + mHistManager.add("HNM/Before/PiPlPiMi/fInvMassVsPt", "Invariant mass and pT of #pi^+pi^- pairs;#bf{#it{M}^{#pi^{+}#pi^{-}} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#pi^{+}#pi^{-}} (GeV/#it{c})}", HistType::kTH2F, {{400, 0.2, 1.}, {250, 0., 25.}}); + mHistManager.add("HNM/Before/PiPlPiMi/fEta", "Pseudorapidity of HMNCand;#eta;#bf{#it{N}^{#pi^{+}#pi^{-}}}", HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add("HNM/Before/PiPlPiMi/fPhi", "Azimuthal angle of HMNCand;#phi;#bf{#it{N}^{#pi^{+}#pi^{-}}}", HistType::kTH1F, {{720, 0, constants::math::TwoPI}}); + + for (const auto& BeforeAfterString : {"Before", "After"}) { + for (const auto& iHNM : {"Omega", "EtaPrime"}) { + for (const auto& MethodString : {"PCM", "EMC"}) { + mHistManager.add(Form("HNM/%s/%s/%s/fInvMassVsPt", BeforeAfterString, iHNM, MethodString), "Invariant mass and pT of heavy neutral meson candidates;#bf{#it{M}^{#pi^{+}#pi^{-}#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#pi^{+}#pi^{-}#gamma#gamma} (GeV/#it{c})}", HistType::kTH2F, {{600, 0.6, 1.2}, {250, 0., 25.}}); + mHistManager.add(Form("HNM/%s/%s/%s/fEta", BeforeAfterString, iHNM, MethodString), "Pseudorapidity of HNM candidate;#eta;#bf{#it{N}^{#pi^{+}#pi^{-}#gamma#gamma}}", HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add(Form("HNM/%s/%s/%s/fPhi", BeforeAfterString, iHNM, MethodString), "Azimuthal angle of HNM candidate;#phi;#bf{#it{N}^{#pi^{+}#pi^{-}#gamma#gamma}}", HistType::kTH1F, {{720, 0, constants::math::TwoPI}}); + } + } + } + mHistManager.add("HNM/Before/Omega/PCMEMC/fInvMassVsPt", "Invariant mass and pT of omega meson candidates;#bf{#it{M}^{#pi^{+}#pi^{-}#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#pi^{+}#pi^{-}#gamma#gamma} (GeV/#it{c})}", HistType::kTH2F, {{600, 0.6, 1.2}, {250, 0., 25.}}); + mHistManager.add("HNM/Before/Omega/PCMEMC/fEta", "Pseudorapidity of HMNCand;#eta;#bf{#it{N}^{#pi^{+}#pi^{-}#gamma#gamma}}", HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add("HNM/Before/Omega/PCMEMC/fPhi", "Azimuthal angle of HMNCand;#phi;#bf{#it{N}^{#pi^{+}#pi^{-}#gamma#gamma}}", HistType::kTH1F, {{720, 0, constants::math::TwoPI}}); + mHistManager.add("HNM/Before/EtaPrime/PCMEMC/fInvMassVsPt", "Invariant mass and pT of eta' meson candidates;#bf{#it{M}^{#pi^{+}#pi^{-}#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#pi^{+}#pi^{-}#gamma#gamma} (GeV/#it{c})}", HistType::kTH2F, {{600, 0.8, 1.2}, {250, 0., 25.}}); + mHistManager.add("HNM/Before/EtaPrime/PCMEMC/fEta", "Pseudorapidity of HMNCand;#eta;#bf{#it{N}^{#pi^{+}#pi^{-}#gamma#gamma}}", HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add("HNM/Before/EtaPrime/PCMEMC/fPhi", "Azimuthal angle of HMNCand;#phi;#bf{#it{N}^{#pi^{+}#pi^{-}#gamma#gamma}}", HistType::kTH1F, {{720, 0, constants::math::TwoPI}}); + + // --> Two body femto histograms + for (const auto& iFemtoPartner : {"p", "d"}) { + for (const auto& iHNM : {"omega", "etaprime"}) { + mHistManager.add(Form("%s%s/fMultiplicity", iHNM, iFemtoPartner), "Multiplicity of all processed events;#bf{#it{N}_{tracks}};#bf{#it{N}_{collisions}}", HistType::kTH1F, {{500, 0, 500}}); + mHistManager.add(Form("%s%s/fZvtx", iHNM, iFemtoPartner), "Zvtx of all processed events;#bf{z_{vtx} (cm)};#bf{#it{N}_{collisions}}", HistType::kTH1F, {{500, -15, 15}}); + for (const auto& iEMCPCM : {"PCM", "EMC"}) { + mHistManager.add(Form("%s%s/fSE_particle_%s", iHNM, iFemtoPartner, iEMCPCM), Form("Same Event distribution;#bf{#it{K}^{*} (GeV/#it{c})};#bf{#it{N}^{%s}}", iFemtoPartner), HistType::kTH1F, {{8000, 0, 8}}); + mHistManager.add(Form("%s%s/fSE_Antiparticle_%s", iHNM, iFemtoPartner, iEMCPCM), Form("Same Event distribution;#bf{#it{K}^{*} (GeV/#it{c})};#bf{#it{N}^{#bar{%s}}}", iFemtoPartner), HistType::kTH1F, {{8000, 0, 8}}); + mHistManager.add(Form("%s%s/f%sPtVskstar_%s", iHNM, iFemtoPartner, iHNM, iEMCPCM), Form("K* vs %s pt;#bf{#it{K}^{*} (GeV/#it{c})};#bf{#it{p}_{T}^{%s} (GeV/#it{c})}", iHNM, iHNM), HistType::kTH2F, {{{150, 0, 1.5}, {500, 0, 10}}}); + mHistManager.add(Form("%s%s/f%sPtVskstar_%s", iHNM, iFemtoPartner, iFemtoPartner, iEMCPCM), Form("K* vs %s pt;#bf{#it{K}^{*} (GeV/#it{c})};#bf{#it{p}_{T}^{%s} (GeV/#it{c})}", iFemtoPartner, iFemtoPartner), HistType::kTH2F, {{{150, 0, 1.5}, {500, 0, 10}}}); + mHistManager.add(Form("%s%s/fAnti%sPtVskstar_%s", iHNM, iFemtoPartner, iFemtoPartner, iEMCPCM), Form("K* vs #bar{%s} pt;#bf{#it{K}^{*} (GeV/#it{c})};#bf{#it{p}_{T}^{#bar{%s}} (GeV/#it{c})}", iFemtoPartner, iFemtoPartner), HistType::kTH2F, {{{150, 0, 1.5}, {500, 0, 10}}}); + } + } + } + + // --> Three body femto histograms + for (const auto& iHNM : {"omega", "etaprime"}) { + mHistManager.add(Form("pp%s/fMultiplicity", iHNM), "Multiplicity of all processed events;#bf{#it{N}_{tracks}};#bf{#it{N}_{collisions}}", HistType::kTH1F, {{500, 0, 500}}); + mHistManager.add(Form("pp%s/fZvtx", iHNM), "Zvtx of all processed events;#bf{z_{vtx} (cm)};#bf{#it{N}_{collisions}}", HistType::kTH1F, {{500, -15, 15}}); + for (const auto& iEMCPCM : {"PCM", "EMC"}) { + mHistManager.add(Form("pp%s/fSE_particle_%s", iHNM, iEMCPCM), "Same Event distribution;#bf{#it{Q}_{3} (GeV/#it{c})};#bf{#it{N}^{pp}}", HistType::kTH1F, {{8000, 0, 8}}); + mHistManager.add(Form("pp%s/fSE_Antiparticle_%s", iHNM, iEMCPCM), "Same Event distribution;#bf{#it{Q}_{3} (GeV/#it{c})};#bf{#it{N}^{#bar{p}#bar{p}}}", HistType::kTH1F, {{8000, 0, 8}}); + mHistManager.add(Form("pp%s/fProtonPtVsQ3_%s", iHNM, iEMCPCM), "pT (proton) vs Q_{3};#bf{#it{Q}_{3} (GeV/#it{c})};#bf{#it{p}_{T}^{p} (GeV/#it{c})}", HistType::kTH2F, {{{150, 0, 1.5}, {500, 0, 10}}}); + mHistManager.add(Form("pp%s/f%sCandPtVsQ3_%s", iHNM, iHNM, iEMCPCM), Form("pT (%s) vs Q_{3};#bf{#it{Q}_{3} (GeV/#it{c})};#bf{#it{p}_{T}^{%s} (GeV/#it{c})}", iHNM, iHNM), HistType::kTH2F, {{{150, 0, 1.5}, {500, 0, 10}}}); + mHistManager.add(Form("pp%s/fAntiProtonPtVsQ3_%s", iHNM, iEMCPCM), "pT (antiproton) vs Q_{3};#bf{#it{Q}_{3} (GeV/#it{c})};#bf{#it{p}_{T}^{#bar{p}} (GeV/#it{c})}", HistType::kTH2F, {{{150, 0, 1.5}, {500, 0, 10}}}); + } + } + + if (cfgDoEMCShift.value) { + for (int iSM = 0; iSM < nSMs; iSM++) { + emcEtaShift[iSM] = cfgEMCEtaShift.value[iSM]; + emcPhiShift[iSM] = cfgEMCPhiShift.value[iSM]; + LOG(info) << "SM-wise shift in eta/phi for SM " << iSM << ": " << emcEtaShift[iSM] << " / " << emcPhiShift[iSM]; + } + } + } + + void process(aod::MyCollision const& collision, aod::MyBCs const&, aod::SkimEMCClusters const& clusters, aod::V0PhotonsKF const& v0s, aod::SelectedTracks const& tracks) + { + // inlcude ITS PID information + auto tracksWithItsPid = soa::Attach(tracks); + + // QA all evts + mHistManager.fill(HIST("fProcessedEvents"), 0); + mHistManager.fill(HIST("Event/fMultiplicityBefore"), collision.multNTracksPV()); + mHistManager.fill(HIST("Event/fZvtxBefore"), collision.posZ()); + + // Ensure evts are consistent with Sel8 and Vtx-z selection + if (!isSelectedEvent(collision)) + return; + + // QA accepted evts + mHistManager.fill(HIST("Event/fMultiplicityAfter"), collision.multNTracksPV()); + mHistManager.fill(HIST("Event/fZvtxAfter"), collision.posZ()); + + colContainsPCMOmega = colContainsEMCOmega = colContainsPCMEtaPrime = colContainsEMCEtaPrime = false; // Used by spectrum trigger to flag events with high-pT omega/eta' candidates + int lowMomentumMultiplets[hnmtrigger::kNFemtoTriggers] = {0, 0, 0, 0, 0, 0}; // Number of found femto pairs/triplets for each femto trigger + bool keepFemtoEvent[hnmtrigger::kNFemtoTriggers] = {false, false, false, false, false, false}; // Set based on number of found pairs (see above) - used to flag femto events + + // clean vecs + // HNM candidates + etaPrimeEMC.clear(); + etaPrimePCM.clear(); + omegaEMC.clear(); + omegaPCM.clear(); + // Femto partners + proton.clear(); + antiproton.clear(); + deuteron.clear(); + antideuteron.clear(); + // Pions for HNM + pion.clear(); + antipion.clear(); + vHNMs.clear(); + // vGGs vector is cleared in reconstructGGs. + + // ---------------------------------> EMCal event QA <---------------------------------- + // - Fill Event/nEMCalEvents histogram for EMCal event QA + // ------------------------------------------------------------------------------------- + bool bcHasEMCCells = collision.isemcreadout(); + bool iskTVXinEMC = collision.foundBC_as().alias_bit(kTVXinEMC); + bool isL0Triggered = collision.foundBC_as().alias_bit(kEMC7) || collision.foundBC_as().alias_bit(kEG1) || collision.foundBC_as().alias_bit(kEG2); + + if (bcHasEMCCells && iskTVXinEMC) + mHistManager.fill(HIST("Event/nEMCalEvents"), 0); + if (bcHasEMCCells && isL0Triggered) + mHistManager.fill(HIST("Event/nEMCalEvents"), 1); + if (bcHasEMCCells && !iskTVXinEMC && !isL0Triggered) + mHistManager.fill(HIST("Event/nEMCalEvents"), 2); + if (!bcHasEMCCells && iskTVXinEMC) + mHistManager.fill(HIST("Event/nEMCalEvents"), 3); + if (!bcHasEMCCells && isL0Triggered) + mHistManager.fill(HIST("Event/nEMCalEvents"), 4); + + // --------------------------------> Process Photons <---------------------------------- + // - Slice clusters and V0s by collision ID to get the ones in this collision + // - Store the clusters and V0s in the vGammas vector + // - Reconstruct gamma-gamma pairs + // ------------------------------------------------------------------------------------- + auto v0sInThisCollision = v0s.sliceBy(perCollisionPCM, collision.globalIndex()); + auto clustersInThisCollision = clusters.sliceBy(perCollisionEMC, collision.globalIndex()); + mHistManager.fill(HIST("Event/nClustersVsV0s"), clustersInThisCollision.size(), v0sInThisCollision.size()); + + std::vector vGammas; + hnmutilities::storeGammasInVector(clustersInThisCollision, v0sInThisCollision, vGammas, emcEtaShift, emcPhiShift); + hnmutilities::reconstructGGs(vGammas, vGGs); + vGammas.clear(); + processGGs(vGGs); + + // ------------------------------> Loop over all tracks <------------------------------- + // - Sort them into vectors based on PID ((anti)protons, (anti)deuterons, (anti)pions) + // - Fill QA histograms for all tracks and per particle species + // ------------------------------------------------------------------------------------- + for (const auto& track : tracksWithItsPid) { + mHistManager.fill(HIST("TrackCuts/TracksBefore/fPtTrackBefore"), track.pt()); + mHistManager.fill(HIST("TrackCuts/TracksBefore/fEtaTrackBefore"), track.eta()); + mHistManager.fill(HIST("TrackCuts/TracksBefore/fPhiTrackBefore"), track.phi()); + if (track.sign() > 0) { // All particles (positive electric charge) + mHistManager.fill(HIST("TrackCuts/TPCSignal/fTPCSignalTPCP"), track.tpcInnerParam(), track.tpcSignal()); + mHistManager.fill(HIST("TrackCuts/TPCSignal/fTPCSignal"), track.p(), track.tpcSignal()); + mHistManager.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationPos"), track.p(), track.tpcInnerParam()); + } + if (track.sign() < 0) { // All anti-particles (negative electric charge) + mHistManager.fill(HIST("TrackCuts/TPCSignal/fTPCSignalAntiTPCP"), track.tpcInnerParam(), track.tpcSignal()); + mHistManager.fill(HIST("TrackCuts/TPCSignal/fTPCSignalAnti"), track.p(), track.tpcSignal()); + mHistManager.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationNeg"), track.p(), track.tpcInnerParam()); + } + + // For each track, check if it fulfills track and PID criteria to be identified as a proton, deuteron or pion + bool isProton = (isSelectedTrackPID(track, hnmtrigger::kProton) && isSelectedTrack(track, hnmtrigger::kProton)); + bool isDeuteron = (isSelectedTrackPID(track, hnmtrigger::kDeuteron) && isSelectedTrack(track, hnmtrigger::kDeuteron)); + bool isPion = (isSelectedTrackPID(track, hnmtrigger::kPion) && isSelectedTrack(track, hnmtrigger::kPion)); + + if (track.sign() > 0) { // Positive charge -> Particles + if (isProton) { + proton.emplace_back(track.pt(), track.eta(), track.phi(), mMassProton); + mHistManager.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationAfterCutsProton"), track.p(), track.tpcInnerParam()); + mHistManager.fill(HIST("TrackCuts/TPCSignal/fTPCSignalProton"), track.tpcInnerParam(), track.tpcSignal()); + + mHistManager.fill(HIST("TrackCuts/Proton/fP"), track.p()); + mHistManager.fill(HIST("TrackCuts/Proton/fPt"), track.pt()); + mHistManager.fill(HIST("TrackCuts/Proton/fMomCorDif"), track.p(), track.tpcInnerParam() - track.p()); + mHistManager.fill(HIST("TrackCuts/Proton/fMomCorRatio"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + mHistManager.fill(HIST("TrackCuts/Proton/fEta"), track.eta()); + mHistManager.fill(HIST("TrackCuts/Proton/fPhi"), track.phi()); + + mHistManager.fill(HIST("TrackCuts/Proton/fNsigmaTPCvsTPCP"), track.tpcInnerParam(), track.tpcNSigmaPr()); + mHistManager.fill(HIST("TrackCuts/Proton/fNsigmaTOFvsTPCP"), track.tpcInnerParam(), track.tofNSigmaPr()); + auto nSigmaTrackTPCTOF = std::sqrt(std::pow(track.tpcNSigmaPr(), 2) + std::pow(track.tofNSigmaPr(), 2)); + mHistManager.fill(HIST("TrackCuts/Proton/fNsigmaTPCTOFvsTPCP"), track.tpcInnerParam(), std::sqrt(std::pow(track.tpcNSigmaPr() - nSigmaTrackTPCTOF, 2) + std::pow(track.tofNSigmaPr() - nSigmaTrackTPCTOF, 2))); + mHistManager.fill(HIST("TrackCuts/Proton/fNsigmaITSvsP"), track.p(), track.itsNSigmaPr()); + mHistManager.fill(HIST("TrackCuts/Proton/fNsigmaTPCvsP"), track.p(), track.tpcNSigmaPr()); + mHistManager.fill(HIST("TrackCuts/Proton/fNsigmaTOFvsP"), track.p(), track.tofNSigmaPr()); + mHistManager.fill(HIST("TrackCuts/Proton/fNsigmaTPCTOFvsP"), track.p(), std::sqrt(std::pow(track.tpcNSigmaPr() - nSigmaTrackTPCTOF, 2) + std::pow(track.tofNSigmaPr() - nSigmaTrackTPCTOF, 2))); + + mHistManager.fill(HIST("TrackCuts/Proton/fDCAxy"), track.dcaXY()); + mHistManager.fill(HIST("TrackCuts/Proton/fDCAz"), track.dcaZ()); + mHistManager.fill(HIST("TrackCuts/Proton/fTPCsCls"), track.tpcNClsShared()); + mHistManager.fill(HIST("TrackCuts/Proton/fTPCcRows"), track.tpcNClsCrossedRows()); + mHistManager.fill(HIST("TrackCuts/Proton/fTrkTPCfCls"), track.tpcCrossedRowsOverFindableCls()); + mHistManager.fill(HIST("TrackCuts/Proton/fTPCncls"), track.tpcNClsFound()); + } + if (isDeuteron) { + deuteron.emplace_back(track.pt(), track.eta(), track.phi(), mMassDeuteron); + mHistManager.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationAfterCutsDeuteron"), track.p(), track.tpcInnerParam()); + mHistManager.fill(HIST("TrackCuts/TPCSignal/fTPCSignalDeuteron"), track.tpcInnerParam(), track.tpcSignal()); + + mHistManager.fill(HIST("TrackCuts/Deuteron/fP"), track.p()); + mHistManager.fill(HIST("TrackCuts/Deuteron/fPt"), track.pt()); + mHistManager.fill(HIST("TrackCuts/Deuteron/fMomCorDif"), track.p(), track.tpcInnerParam() - track.p()); + mHistManager.fill(HIST("TrackCuts/Deuteron/fMomCorRatio"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + mHistManager.fill(HIST("TrackCuts/Deuteron/fEta"), track.eta()); + mHistManager.fill(HIST("TrackCuts/Deuteron/fPhi"), track.phi()); + + mHistManager.fill(HIST("TrackCuts/Deuteron/fNsigmaTPCvsTPCP"), track.tpcInnerParam(), track.tpcNSigmaDe()); + mHistManager.fill(HIST("TrackCuts/Deuteron/fNsigmaTOFvsTPCP"), track.tpcInnerParam(), track.tofNSigmaDe()); + auto nSigmaTrackTPCTOF = std::sqrt(std::pow(track.tpcNSigmaDe(), 2) + std::pow(track.tofNSigmaDe(), 2)); + mHistManager.fill(HIST("TrackCuts/Deuteron/fNsigmaTPCTOFvsTPCP"), track.tpcInnerParam(), std::sqrt(std::pow(track.tpcNSigmaDe() - nSigmaTrackTPCTOF, 2) + std::pow(track.tofNSigmaDe() - nSigmaTrackTPCTOF, 2))); + mHistManager.fill(HIST("TrackCuts/Deuteron/fNsigmaITSvsP"), track.p(), track.itsNSigmaDe()); + mHistManager.fill(HIST("TrackCuts/Deuteron/fNsigmaTPCvsP"), track.p(), track.tpcNSigmaDe()); + mHistManager.fill(HIST("TrackCuts/Deuteron/fNsigmaTOFvsP"), track.p(), track.tofNSigmaDe()); + mHistManager.fill(HIST("TrackCuts/Deuteron/fNsigmaTPCTOFvsP"), track.p(), std::sqrt(std::pow(track.tpcNSigmaDe() - nSigmaTrackTPCTOF, 2) + std::pow(track.tofNSigmaDe() - nSigmaTrackTPCTOF, 2))); + + mHistManager.fill(HIST("TrackCuts/Deuteron/fDCAxy"), track.dcaXY()); + mHistManager.fill(HIST("TrackCuts/Deuteron/fDCAz"), track.dcaZ()); + mHistManager.fill(HIST("TrackCuts/Deuteron/fTPCsCls"), track.tpcNClsShared()); + mHistManager.fill(HIST("TrackCuts/Deuteron/fTPCcRows"), track.tpcNClsCrossedRows()); + mHistManager.fill(HIST("TrackCuts/Deuteron/fTrkTPCfCls"), track.tpcCrossedRowsOverFindableCls()); + mHistManager.fill(HIST("TrackCuts/Deuteron/fTPCncls"), track.tpcNClsFound()); + } + if (isPion) { + pion.emplace_back(track.pt(), track.eta(), track.phi(), mMassPionCharged); + mHistManager.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationAfterCutsPion"), track.p(), track.tpcInnerParam()); + mHistManager.fill(HIST("TrackCuts/TPCSignal/fTPCSignalPion"), track.tpcInnerParam(), track.tpcSignal()); + + mHistManager.fill(HIST("TrackCuts/Pion/fP"), track.p()); + mHistManager.fill(HIST("TrackCuts/Pion/fPt"), track.pt()); + mHistManager.fill(HIST("TrackCuts/Pion/fMomCorDif"), track.p(), track.tpcInnerParam() - track.p()); + mHistManager.fill(HIST("TrackCuts/Pion/fMomCorRatio"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + mHistManager.fill(HIST("TrackCuts/Pion/fEta"), track.eta()); + mHistManager.fill(HIST("TrackCuts/Pion/fPhi"), track.phi()); + + mHistManager.fill(HIST("TrackCuts/Pion/fNsigmaTPCvsTPCP"), track.tpcInnerParam(), track.tpcNSigmaPi()); + mHistManager.fill(HIST("TrackCuts/Pion/fNsigmaTOFvsTPCP"), track.tpcInnerParam(), track.tofNSigmaPi()); + auto nSigmaTrackTPCTOF = std::sqrt(std::pow(track.tpcNSigmaPi(), 2) + std::pow(track.tofNSigmaPi(), 2)); + mHistManager.fill(HIST("TrackCuts/Pion/fNsigmaTPCTOFvsTPCP"), track.tpcInnerParam(), std::sqrt(std::pow(track.tpcNSigmaPi() - nSigmaTrackTPCTOF, 2) + std::pow(track.tofNSigmaPi() - nSigmaTrackTPCTOF, 2))); + mHistManager.fill(HIST("TrackCuts/Pion/fNsigmaITSvsP"), track.p(), track.itsNSigmaPi()); + mHistManager.fill(HIST("TrackCuts/Pion/fNsigmaTPCvsP"), track.p(), track.tpcNSigmaPi()); + mHistManager.fill(HIST("TrackCuts/Pion/fNsigmaTOFvsP"), track.p(), track.tofNSigmaPi()); + mHistManager.fill(HIST("TrackCuts/Pion/fNsigmaTPCTOFvsP"), track.p(), std::sqrt(std::pow(track.tpcNSigmaPi() - nSigmaTrackTPCTOF, 2) + std::pow(track.tofNSigmaPi() - nSigmaTrackTPCTOF, 2))); + + mHistManager.fill(HIST("TrackCuts/Pion/fDCAxy"), track.dcaXY()); + mHistManager.fill(HIST("TrackCuts/Pion/fDCAz"), track.dcaZ()); + mHistManager.fill(HIST("TrackCuts/Pion/fTPCsCls"), track.tpcNClsShared()); + mHistManager.fill(HIST("TrackCuts/Pion/fTPCcRows"), track.tpcNClsCrossedRows()); + mHistManager.fill(HIST("TrackCuts/Pion/fTrkTPCfCls"), track.tpcCrossedRowsOverFindableCls()); + mHistManager.fill(HIST("TrackCuts/Pion/fTPCncls"), track.tpcNClsFound()); + } + } else { // Negative charge -> Anti-particles + if (isProton) { + antiproton.emplace_back(track.pt(), track.eta(), track.phi(), mMassProton); + mHistManager.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationAfterCutsAntiProton"), track.p(), track.tpcInnerParam()); + mHistManager.fill(HIST("TrackCuts/TPCSignal/fTPCSignalAntiProton"), track.tpcInnerParam(), track.tpcSignal()); + + mHistManager.fill(HIST("TrackCuts/AntiProton/fP"), track.p()); + mHistManager.fill(HIST("TrackCuts/AntiProton/fPt"), track.pt()); + mHistManager.fill(HIST("TrackCuts/AntiProton/fMomCorDif"), track.p(), track.tpcInnerParam() - track.p()); + mHistManager.fill(HIST("TrackCuts/AntiProton/fMomCorRatio"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + mHistManager.fill(HIST("TrackCuts/AntiProton/fEta"), track.eta()); + mHistManager.fill(HIST("TrackCuts/AntiProton/fPhi"), track.phi()); + + mHistManager.fill(HIST("TrackCuts/AntiProton/fNsigmaTPCvsTPCP"), track.tpcInnerParam(), track.tpcNSigmaPr()); + mHistManager.fill(HIST("TrackCuts/AntiProton/fNsigmaTOFvsTPCP"), track.tpcInnerParam(), track.tofNSigmaPr()); + auto nSigmaTrackTPCTOF = std::sqrt(std::pow(track.tpcNSigmaPr(), 2) + std::pow(track.tofNSigmaPr(), 2)); + mHistManager.fill(HIST("TrackCuts/AntiProton/fNsigmaTPCTOFvsTPCP"), track.tpcInnerParam(), std::sqrt(std::pow(track.tpcNSigmaPr() - nSigmaTrackTPCTOF, 2) + std::pow(track.tofNSigmaPr() - nSigmaTrackTPCTOF, 2))); + mHistManager.fill(HIST("TrackCuts/AntiProton/fNsigmaITSvsP"), track.p(), track.itsNSigmaPr()); + mHistManager.fill(HIST("TrackCuts/AntiProton/fNsigmaTPCvsP"), track.p(), track.tpcNSigmaPr()); + mHistManager.fill(HIST("TrackCuts/AntiProton/fNsigmaTOFvsP"), track.p(), track.tofNSigmaPr()); + mHistManager.fill(HIST("TrackCuts/AntiProton/fNsigmaTPCTOFvsP"), track.p(), std::sqrt(std::pow(track.tpcNSigmaPr() - nSigmaTrackTPCTOF, 2) + std::pow(track.tofNSigmaPr() - nSigmaTrackTPCTOF, 2))); + + mHistManager.fill(HIST("TrackCuts/AntiProton/fDCAxy"), track.dcaXY()); + mHistManager.fill(HIST("TrackCuts/AntiProton/fDCAz"), track.dcaZ()); + mHistManager.fill(HIST("TrackCuts/AntiProton/fTPCsCls"), track.tpcNClsShared()); + mHistManager.fill(HIST("TrackCuts/AntiProton/fTPCcRows"), track.tpcNClsCrossedRows()); + mHistManager.fill(HIST("TrackCuts/AntiProton/fTrkTPCfCls"), track.tpcCrossedRowsOverFindableCls()); + mHistManager.fill(HIST("TrackCuts/AntiProton/fTPCncls"), track.tpcNClsFound()); + } + if (isDeuteron) { + antideuteron.emplace_back(track.pt(), track.eta(), track.phi(), mMassDeuteron); + mHistManager.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationAfterCutsAntiDeuteron"), track.p(), track.tpcInnerParam()); + mHistManager.fill(HIST("TrackCuts/TPCSignal/fTPCSignalAntiDeuteron"), track.tpcInnerParam(), track.tpcSignal()); + + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fP"), track.p()); + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fPt"), track.pt()); + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fMomCorDif"), track.p(), track.tpcInnerParam() - track.p()); + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fMomCorRatio"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fEta"), track.eta()); + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fPhi"), track.phi()); + + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fNsigmaTPCvsTPCP"), track.tpcInnerParam(), track.tpcNSigmaDe()); + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fNsigmaTOFvsTPCP"), track.tpcInnerParam(), track.tofNSigmaDe()); + auto nSigmaTrackTPCTOF = std::sqrt(std::pow(track.tpcNSigmaDe(), 2) + std::pow(track.tofNSigmaDe(), 2)); + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fNsigmaTPCTOFvsTPCP"), track.tpcInnerParam(), std::sqrt(std::pow(track.tpcNSigmaDe() - nSigmaTrackTPCTOF, 2) + std::pow(track.tofNSigmaDe() - nSigmaTrackTPCTOF, 2))); + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fNsigmaITSvsP"), track.p(), track.itsNSigmaDe()); + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fNsigmaTPCvsP"), track.p(), track.tpcNSigmaDe()); + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fNsigmaTOFvsP"), track.p(), track.tofNSigmaDe()); + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fNsigmaTPCTOFvsP"), track.p(), std::sqrt(std::pow(track.tpcNSigmaDe() - nSigmaTrackTPCTOF, 2) + std::pow(track.tofNSigmaDe() - nSigmaTrackTPCTOF, 2))); + + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fDCAxy"), track.dcaXY()); + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fDCAz"), track.dcaZ()); + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fTPCsCls"), track.tpcNClsShared()); + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fTPCcRows"), track.tpcNClsCrossedRows()); + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fTrkTPCfCls"), track.tpcCrossedRowsOverFindableCls()); + mHistManager.fill(HIST("TrackCuts/AntiDeuteron/fTPCncls"), track.tpcNClsFound()); + } + if (isPion) { + antipion.emplace_back(track.pt(), track.eta(), track.phi(), mMassPionCharged); + mHistManager.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationAfterCutsAntiPion"), track.p(), track.tpcInnerParam()); + mHistManager.fill(HIST("TrackCuts/TPCSignal/fTPCSignalAntiPion"), track.tpcInnerParam(), track.tpcSignal()); + + mHistManager.fill(HIST("TrackCuts/AntiPion/fP"), track.p()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fPt"), track.pt()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fMomCorDif"), track.p(), track.tpcInnerParam() - track.p()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fMomCorRatio"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fEta"), track.eta()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fPhi"), track.phi()); + + mHistManager.fill(HIST("TrackCuts/AntiPion/fNsigmaTPCvsTPCP"), track.tpcInnerParam(), track.tpcNSigmaPi()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fNsigmaTOFvsTPCP"), track.tpcInnerParam(), track.tofNSigmaPi()); + auto nSigmaTrackTPCTOF = std::sqrt(std::pow(track.tpcNSigmaPi(), 2) + std::pow(track.tofNSigmaPi(), 2)); + mHistManager.fill(HIST("TrackCuts/AntiPion/fNsigmaTPCTOFvsTPCP"), track.tpcInnerParam(), std::sqrt(std::pow(track.tpcNSigmaPi() - nSigmaTrackTPCTOF, 2) + std::pow(track.tofNSigmaPi() - nSigmaTrackTPCTOF, 2))); + mHistManager.fill(HIST("TrackCuts/AntiPion/fNsigmaITSvsP"), track.p(), track.itsNSigmaPi()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fNsigmaTPCvsP"), track.p(), track.tpcNSigmaPi()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fNsigmaTOFvsP"), track.p(), track.tofNSigmaPi()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fNsigmaTPCTOFvsP"), track.p(), std::sqrt(std::pow(track.tpcNSigmaPi() - nSigmaTrackTPCTOF, 2) + std::pow(track.tofNSigmaPi() - nSigmaTrackTPCTOF, 2))); + + mHistManager.fill(HIST("TrackCuts/AntiPion/fDCAxy"), track.dcaXY()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fDCAz"), track.dcaZ()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fTPCsCls"), track.tpcNClsShared()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fTPCcRows"), track.tpcNClsCrossedRows()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fTrkTPCfCls"), track.tpcCrossedRowsOverFindableCls()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fTPCncls"), track.tpcNClsFound()); + } + } + } + + // -------------------------> Reconstruct HNM candidates <------------------------------ + // - Based on the previously filled (anti)pion vectors + // - Fill QA histograms for kinematics of the pions and their combinations + // ------------------------------------------------------------------------------------- + for (const auto& posPion : pion) { + for (const auto& negPion : antipion) { + ROOT::Math::PtEtaPhiMVector vecPiPlPiMi = posPion + negPion; + hnmutilities::reconstructHeavyNeutralMesons(vecPiPlPiMi, vGGs, vHNMs); + + mHistManager.fill(HIST("HNM/Before/PiPlPiMi/fInvMassVsPt"), vecPiPlPiMi.M(), vecPiPlPiMi.pt()); + mHistManager.fill(HIST("HNM/Before/PiPlPiMi/fEta"), vecPiPlPiMi.eta()); + mHistManager.fill(HIST("HNM/Before/PiPlPiMi/fPhi"), RecoDecay::constrainAngle(vecPiPlPiMi.phi())); + + mHistManager.fill(HIST("HNM/Before/PosDaughter/fInvMass"), posPion.M()); + mHistManager.fill(HIST("HNM/Before/PosDaughter/fPt"), posPion.pt()); + mHistManager.fill(HIST("HNM/Before/PosDaughter/fEta"), posPion.eta()); + mHistManager.fill(HIST("HNM/Before/PosDaughter/fPhi"), RecoDecay::constrainAngle(posPion.phi())); + + mHistManager.fill(HIST("HNM/Before/NegDaughter/fInvMass"), negPion.M()); + mHistManager.fill(HIST("HNM/Before/NegDaughter/fPt"), negPion.pt()); + mHistManager.fill(HIST("HNM/Before/NegDaughter/fEta"), negPion.eta()); + mHistManager.fill(HIST("HNM/Before/NegDaughter/fPhi"), RecoDecay::constrainAngle(negPion.phi())); + } + } + + // ---------------------------> Process HNM candidates <-------------------------------- + // - Fill invMassVsPt histograms separated into HNM types (based on GG mass) and gamma reco method + // - Set colContains* flags for each HNM type to be used in the high-pt spectrum trigger + // - Fill femto HNM vectors (omegaPCM, etaPrimePCM, omegaEMC, etaPrimeEMC) + // ------------------------------------------------------------------------------------- + processHNMs(vHNMs); + + // ------------------------------> Build triplets <------------------------------------- + // - Calculate Q3 for each triplet (p-p-omega, p-p-eta', anti-p-anti-p-omega, anti-p-anti-p-eta') + // - Fill QA histograms for Q3 and pT of the triplet and its daughters + // - Increment lowMomentumMultiplets for each triplet with Q3 < kinematic limit (used in femto trigger) + // ------------------------------------------------------------------------------------- + if (cfgTriggerSwitches->get("Switch", "PPOmega") > 0.) { // -----> p-p-omega femtoscopy + for (size_t i = 0; i < proton.size(); ++i) { + for (size_t j = i + 1; j < proton.size(); ++j) { + const auto& proton1 = proton[i]; + const auto& proton2 = proton[j]; + for (const auto& omegaParticles : omegaPCM) { // ---> PCM + + float q3 = getQ3(proton1, proton2, omegaParticles); + + mHistManager.fill(HIST("ppomega/fSE_particle_PCM"), q3); + mHistManager.fill(HIST("ppomega/fProtonPtVsQ3_PCM"), q3, proton1.Pt()); + mHistManager.fill(HIST("ppomega/fProtonPtVsQ3_PCM"), q3, proton2.Pt()); + mHistManager.fill(HIST("ppomega/fomegaCandPtVsQ3_PCM"), q3, omegaParticles.Pt()); + + if (q3 < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kPPOmega)) + lowMomentumMultiplets[hnmtrigger::kPPOmega] += 1; + } + for (const auto& omegaParticles : omegaEMC) { // ---> EMC + + float q3 = getQ3(proton1, proton2, omegaParticles); + + mHistManager.fill(HIST("ppomega/fSE_particle_EMC"), q3); + mHistManager.fill(HIST("ppomega/fProtonPtVsQ3_EMC"), q3, proton1.Pt()); + mHistManager.fill(HIST("ppomega/fProtonPtVsQ3_EMC"), q3, proton2.Pt()); + mHistManager.fill(HIST("ppomega/fomegaCandPtVsQ3_EMC"), q3, omegaParticles.Pt()); + + if (q3 < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kPPOmega)) + lowMomentumMultiplets[hnmtrigger::kPPOmega] += 1; + } + } + } + for (size_t i = 0; i < antiproton.size(); ++i) { // -----> antip-antip-omega femtoscopy + for (size_t j = i + 1; j < antiproton.size(); ++j) { + const auto& antiProton1 = antiproton[i]; + const auto& antiProton2 = antiproton[j]; + for (const auto& omegaParticles : omegaPCM) { // ---> PCM + + float q3 = getQ3(antiProton1, antiProton2, omegaParticles); + + mHistManager.fill(HIST("ppomega/fSE_Antiparticle_PCM"), q3); + mHistManager.fill(HIST("ppomega/fAntiProtonPtVsQ3_PCM"), q3, antiProton1.Pt()); + mHistManager.fill(HIST("ppomega/fAntiProtonPtVsQ3_PCM"), q3, antiProton2.Pt()); + mHistManager.fill(HIST("ppomega/fomegaCandPtVsQ3_PCM"), q3, omegaParticles.Pt()); + + if (q3 < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kPPOmega)) + lowMomentumMultiplets[hnmtrigger::kPPOmega] += 1; + } + for (const auto& omegaParticles : omegaEMC) { // ---> EMC + + float q3 = getQ3(antiProton1, antiProton2, omegaParticles); + + mHistManager.fill(HIST("ppomega/fSE_Antiparticle_EMC"), q3); + mHistManager.fill(HIST("ppomega/fAntiProtonPtVsQ3_EMC"), q3, antiProton1.Pt()); + mHistManager.fill(HIST("ppomega/fAntiProtonPtVsQ3_EMC"), q3, antiProton2.Pt()); + mHistManager.fill(HIST("ppomega/fomegaCandPtVsQ3_EMC"), q3, omegaParticles.Pt()); + + if (q3 < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kPPOmega)) + lowMomentumMultiplets[hnmtrigger::kPPOmega] += 1; + } + } + } + } + if (cfgTriggerSwitches->get("Switch", "PPEtaPrime") > 0.) { // -----> p-p-eta' femtoscopy + for (size_t i = 0; i < proton.size(); ++i) { + for (size_t j = i + 1; j < proton.size(); ++j) { + const auto& proton1 = proton[i]; + const auto& proton2 = proton[j]; + for (const auto& etaParticles : etaPrimePCM) { // ---> PCM + + float q3 = getQ3(proton1, proton2, etaParticles); + + mHistManager.fill(HIST("ppetaprime/fSE_particle_PCM"), q3); + mHistManager.fill(HIST("ppetaprime/fProtonPtVsQ3_PCM"), q3, proton1.Pt()); + mHistManager.fill(HIST("ppetaprime/fProtonPtVsQ3_PCM"), q3, proton2.Pt()); + mHistManager.fill(HIST("ppetaprime/fetaprimeCandPtVsQ3_PCM"), q3, etaParticles.Pt()); + + if (q3 < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kPPEtaPrime)) + lowMomentumMultiplets[hnmtrigger::kPPEtaPrime] += 1; + } + for (const auto& etaParticles : etaPrimeEMC) { // ---> EMC + + float q3 = getQ3(proton1, proton2, etaParticles); + + mHistManager.fill(HIST("ppetaprime/fSE_particle_EMC"), q3); + mHistManager.fill(HIST("ppetaprime/fProtonPtVsQ3_EMC"), q3, proton1.Pt()); + mHistManager.fill(HIST("ppetaprime/fProtonPtVsQ3_EMC"), q3, proton2.Pt()); + mHistManager.fill(HIST("ppetaprime/fetaprimeCandPtVsQ3_EMC"), q3, etaParticles.Pt()); + + if (q3 < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kPPEtaPrime)) + lowMomentumMultiplets[hnmtrigger::kPPEtaPrime] += 1; + } + } + } + for (size_t i = 0; i < antiproton.size(); ++i) { // -----> antip-antip-eta' femtoscopy + for (size_t j = i + 1; j < antiproton.size(); ++j) { + const auto& antiProton1 = antiproton[i]; + const auto& antiProton2 = antiproton[j]; + for (const auto& etaParticles : etaPrimePCM) { // ---> PCM + + float q3 = getQ3(antiProton1, antiProton2, etaParticles); + + mHistManager.fill(HIST("ppetaprime/fSE_Antiparticle_PCM"), q3); + mHistManager.fill(HIST("ppetaprime/fAntiProtonPtVsQ3_PCM"), q3, antiProton1.Pt()); + mHistManager.fill(HIST("ppetaprime/fAntiProtonPtVsQ3_PCM"), q3, antiProton2.Pt()); + mHistManager.fill(HIST("ppetaprime/fetaprimeCandPtVsQ3_PCM"), q3, etaParticles.Pt()); + + if (q3 < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kPPEtaPrime)) + lowMomentumMultiplets[hnmtrigger::kPPEtaPrime] += 1; + } + for (const auto& etaParticles : etaPrimeEMC) { // ---> EMC + + float q3 = getQ3(antiProton1, antiProton2, etaParticles); + + mHistManager.fill(HIST("ppetaprime/fSE_Antiparticle_EMC"), q3); + mHistManager.fill(HIST("ppetaprime/fAntiProtonPtVsQ3_EMC"), q3, antiProton1.Pt()); + mHistManager.fill(HIST("ppetaprime/fAntiProtonPtVsQ3_EMC"), q3, antiProton2.Pt()); + mHistManager.fill(HIST("ppetaprime/fetaprimeCandPtVsQ3_EMC"), q3, etaParticles.Pt()); + + if (q3 < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kPPEtaPrime)) + lowMomentumMultiplets[hnmtrigger::kPPEtaPrime] += 1; + } + } + } + } + + // --------------------------------> Build Pairs <-------------------------------------- + // - Calculate k* for each pair ((anti)d-omega, (anti)d-eta', (anti)p-omega, (anti)p-eta') + // - Fill QA histograms for k* and pT of the pairs + // - Increment lowMomentumMultiplets for each triplet with k* < kinematic limit (used in femto trigger) + // ------------------------------------------------------------------------------------- + if (cfgTriggerSwitches->get("Switch", "Omegad") > 0.) { + for (auto iomega = omegaPCM.begin(); iomega != omegaPCM.end(); ++iomega) { // -----> PCM + for (auto iDeuteron = deuteron.begin(); iDeuteron != deuteron.end(); ++iDeuteron) { // ---> d-omega femtoscopy + + float kstar = getkstar(*iomega, *iDeuteron); + + mHistManager.fill(HIST("omegad/fSE_particle_PCM"), kstar); + mHistManager.fill(HIST("omegad/fomegaPtVskstar_PCM"), kstar, (*iomega).Pt()); + mHistManager.fill(HIST("omegad/fdPtVskstar_PCM"), kstar, (*iDeuteron).Pt()); + + if (kstar < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kOmegaD)) + lowMomentumMultiplets[hnmtrigger::kOmegaD] += 1; + } + for (auto iAntiDeuteron = antideuteron.begin(); iAntiDeuteron != antideuteron.end(); ++iAntiDeuteron) { // ---> antid-omega femtoscopy + + float kstar = getkstar(*iomega, *iAntiDeuteron); + + mHistManager.fill(HIST("omegad/fSE_Antiparticle_PCM"), kstar); + mHistManager.fill(HIST("omegad/fomegaPtVskstar_PCM"), kstar, (*iomega).Pt()); + mHistManager.fill(HIST("omegad/fAntidPtVskstar_PCM"), kstar, (*iAntiDeuteron).Pt()); + + if (kstar < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kOmegaD)) + lowMomentumMultiplets[hnmtrigger::kOmegaD] += 1; + } + } + for (auto iomega = omegaEMC.begin(); iomega != omegaEMC.end(); ++iomega) { // -----> EMC + for (auto iDeuteron = deuteron.begin(); iDeuteron != deuteron.end(); ++iDeuteron) { // ---> d-omega femtoscopy + + float kstar = getkstar(*iomega, *iDeuteron); + + mHistManager.fill(HIST("omegad/fSE_particle_EMC"), kstar); + mHistManager.fill(HIST("omegad/fomegaPtVskstar_EMC"), kstar, (*iomega).Pt()); + mHistManager.fill(HIST("omegad/fdPtVskstar_EMC"), kstar, (*iDeuteron).Pt()); + + if (kstar < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kOmegaD)) + lowMomentumMultiplets[hnmtrigger::kOmegaD] += 1; + } + for (auto iAntiDeuteron = antideuteron.begin(); iAntiDeuteron != antideuteron.end(); ++iAntiDeuteron) { // ---> antid-omega femtoscopy + + float kstar = getkstar(*iomega, *iAntiDeuteron); + + mHistManager.fill(HIST("omegad/fSE_Antiparticle_EMC"), kstar); + mHistManager.fill(HIST("omegad/fomegaPtVskstar_EMC"), kstar, (*iomega).Pt()); + mHistManager.fill(HIST("omegad/fAntidPtVskstar_EMC"), kstar, (*iAntiDeuteron).Pt()); + + if (kstar < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kOmegaD)) + lowMomentumMultiplets[hnmtrigger::kOmegaD] += 1; + } + } + } + if (cfgTriggerSwitches->get("Switch", "EtaPrimed") > 0.) { + for (auto ietaprime = etaPrimePCM.begin(); ietaprime != etaPrimePCM.end(); ++ietaprime) { // -----> PCM + for (auto iDeuteron = deuteron.begin(); iDeuteron != deuteron.end(); ++iDeuteron) { // ---> d-eta' femtoscopy + + float kstar = getkstar(*ietaprime, *iDeuteron); + + mHistManager.fill(HIST("etaprimed/fSE_particle_PCM"), kstar); + mHistManager.fill(HIST("etaprimed/fetaprimePtVskstar_PCM"), kstar, (*ietaprime).Pt()); + mHistManager.fill(HIST("etaprimed/fdPtVskstar_PCM"), kstar, (*iDeuteron).Pt()); + + if (kstar < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kEtaPrimeD)) + lowMomentumMultiplets[hnmtrigger::kEtaPrimeD] += 1; + } + for (auto iAntiDeuteron = antideuteron.begin(); iAntiDeuteron != antideuteron.end(); ++iAntiDeuteron) { // ---> antid-eta' femtoscopy + + float kstar = getkstar(*ietaprime, *iAntiDeuteron); + + mHistManager.fill(HIST("etaprimed/fSE_Antiparticle_PCM"), kstar); + mHistManager.fill(HIST("etaprimed/fetaprimePtVskstar_PCM"), kstar, (*ietaprime).Pt()); + mHistManager.fill(HIST("etaprimed/fAntidPtVskstar_PCM"), kstar, (*iAntiDeuteron).Pt()); + + if (kstar < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kEtaPrimeD)) + lowMomentumMultiplets[hnmtrigger::kEtaPrimeD] += 1; + } + } + for (auto ietaprime = etaPrimeEMC.begin(); ietaprime != etaPrimeEMC.end(); ++ietaprime) { // -----> EMC + for (auto iDeuteron = deuteron.begin(); iDeuteron != deuteron.end(); ++iDeuteron) { // ---> d-eta' femtoscopy + + float kstar = getkstar(*ietaprime, *iDeuteron); + + mHistManager.fill(HIST("etaprimed/fSE_particle_EMC"), kstar); + mHistManager.fill(HIST("etaprimed/fetaprimePtVskstar_EMC"), kstar, (*ietaprime).Pt()); + mHistManager.fill(HIST("etaprimed/fdPtVskstar_EMC"), kstar, (*iDeuteron).Pt()); + + if (kstar < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kEtaPrimeD)) + lowMomentumMultiplets[hnmtrigger::kEtaPrimeD] += 1; + } + for (auto iAntiDeuteron = antideuteron.begin(); iAntiDeuteron != antideuteron.end(); ++iAntiDeuteron) { // ---> antid-eta' femtoscopy + + float kstar = getkstar(*ietaprime, *iAntiDeuteron); + + mHistManager.fill(HIST("etaprimed/fSE_Antiparticle_EMC"), kstar); + mHistManager.fill(HIST("etaprimed/fetaprimePtVskstar_EMC"), kstar, (*ietaprime).Pt()); + mHistManager.fill(HIST("etaprimed/fAntidPtVskstar_EMC"), kstar, (*iAntiDeuteron).Pt()); + + if (kstar < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kEtaPrimeD)) + lowMomentumMultiplets[hnmtrigger::kEtaPrimeD] += 1; + } + } + } + if (cfgTriggerSwitches->get("Switch", "OmegaP") > 0.) { + for (auto iomega = omegaPCM.begin(); iomega != omegaPCM.end(); ++iomega) { // -----> PCM + for (auto iProton = proton.begin(); iProton != proton.end(); ++iProton) { // ---> p-omega femtoscopy + + float kstar = getkstar(*iomega, *iProton); + + mHistManager.fill(HIST("omegap/fSE_particle_PCM"), kstar); + mHistManager.fill(HIST("omegap/fomegaPtVskstar_PCM"), kstar, (*iomega).Pt()); + mHistManager.fill(HIST("omegap/fpPtVskstar_PCM"), kstar, (*iProton).Pt()); + + if (kstar < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kOmegaP)) + lowMomentumMultiplets[hnmtrigger::kOmegaP] += 1; + } + for (auto iAntiProton = antiproton.begin(); iAntiProton != antiproton.end(); ++iAntiProton) { // ---> antip-omega femtoscopy + + float kstar = getkstar(*iomega, *iAntiProton); + + mHistManager.fill(HIST("omegap/fSE_Antiparticle_PCM"), kstar); + mHistManager.fill(HIST("omegap/fomegaPtVskstar_PCM"), kstar, (*iomega).Pt()); + mHistManager.fill(HIST("omegap/fAntipPtVskstar_PCM"), kstar, (*iAntiProton).Pt()); + + if (kstar < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kOmegaP)) + lowMomentumMultiplets[hnmtrigger::kOmegaP] += 1; + } + } + for (auto iomega = omegaEMC.begin(); iomega != omegaEMC.end(); ++iomega) { // -----> EMC + for (auto iProton = proton.begin(); iProton != proton.end(); ++iProton) { // ---> p-omega femtoscopy + + float kstar = getkstar(*iomega, *iProton); + + mHistManager.fill(HIST("omegap/fSE_particle_EMC"), kstar); + mHistManager.fill(HIST("omegap/fomegaPtVskstar_EMC"), kstar, (*iomega).Pt()); + mHistManager.fill(HIST("omegap/fpPtVskstar_EMC"), kstar, (*iProton).Pt()); + + if (kstar < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kOmegaP)) + lowMomentumMultiplets[hnmtrigger::kOmegaP] += 1; + } + for (auto iAntiProton = antiproton.begin(); iAntiProton != antiproton.end(); ++iAntiProton) { // ---> antip-omega femtoscopy + + float kstar = getkstar(*iomega, *iAntiProton); + + mHistManager.fill(HIST("omegap/fSE_Antiparticle_EMC"), kstar); + mHistManager.fill(HIST("omegap/fomegaPtVskstar_EMC"), kstar, (*iomega).Pt()); + mHistManager.fill(HIST("omegap/fAntipPtVskstar_EMC"), kstar, (*iAntiProton).Pt()); + + if (kstar < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kOmegaP)) + lowMomentumMultiplets[hnmtrigger::kOmegaP] += 1; + } + } + } + if (cfgTriggerSwitches->get("Switch", "EtaPrimeP") > 0.) { + for (auto ietaprime = etaPrimePCM.begin(); ietaprime != etaPrimePCM.end(); ++ietaprime) { // -----> PCM + for (auto iProton = proton.begin(); iProton != proton.end(); ++iProton) { // ---> p-eta' femtoscopy + + float kstar = getkstar(*ietaprime, *iProton); + + mHistManager.fill(HIST("etaprimep/fSE_particle_PCM"), kstar); + mHistManager.fill(HIST("etaprimep/fetaprimePtVskstar_PCM"), kstar, (*ietaprime).Pt()); + mHistManager.fill(HIST("etaprimep/fpPtVskstar_PCM"), kstar, (*iProton).Pt()); + + if (kstar < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kEtaPrimeP)) + lowMomentumMultiplets[hnmtrigger::kEtaPrimeP] += 1; + } + for (auto iAntiProton = antiproton.begin(); iAntiProton != antiproton.end(); ++iAntiProton) { // ---> antip-eta' femtoscopy + + float kstar = getkstar(*ietaprime, *iAntiProton); + + mHistManager.fill(HIST("etaprimep/fSE_Antiparticle_PCM"), kstar); + mHistManager.fill(HIST("etaprimep/fetaprimePtVskstar_PCM"), kstar, (*ietaprime).Pt()); + mHistManager.fill(HIST("etaprimep/fAntipPtVskstar_PCM"), kstar, (*iAntiProton).Pt()); + + if (kstar < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kEtaPrimeP)) + lowMomentumMultiplets[hnmtrigger::kEtaPrimeP] += 1; + } + } + for (auto ietaprime = etaPrimeEMC.begin(); ietaprime != etaPrimeEMC.end(); ++ietaprime) { // -----> EMC + for (auto iProton = proton.begin(); iProton != proton.end(); ++iProton) { // ---> p-eta' femtoscopy + + float kstar = getkstar(*ietaprime, *iProton); + + mHistManager.fill(HIST("etaprimep/fSE_particle_EMC"), kstar); + mHistManager.fill(HIST("etaprimep/fetaprimePtVskstar_EMC"), kstar, (*ietaprime).Pt()); + mHistManager.fill(HIST("etaprimep/fpPtVskstar_EMC"), kstar, (*iProton).Pt()); + + if (kstar < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kEtaPrimeP)) + lowMomentumMultiplets[hnmtrigger::kEtaPrimeP] += 1; + } + for (auto iAntiProton = antiproton.begin(); iAntiProton != antiproton.end(); ++iAntiProton) { // ---> antip-eta' femtoscopy + + float kstar = getkstar(*ietaprime, *iAntiProton); + + mHistManager.fill(HIST("etaprimep/fSE_Antiparticle_EMC"), kstar); + mHistManager.fill(HIST("etaprimep/fetaprimePtVskstar_EMC"), kstar, (*ietaprime).Pt()); + mHistManager.fill(HIST("etaprimep/fAntipPtVskstar_EMC"), kstar, (*iAntiProton).Pt()); + + if (kstar < cfgKinematicLimits->get(static_cast(0), hnmtrigger::kEtaPrimeP)) + lowMomentumMultiplets[hnmtrigger::kEtaPrimeP] += 1; + } + } + } + + // -----------------------------> Create femto tags <----------------------------------- + // - Set keepFemtoEvent flags for each HNM type based on the lowMomentumMultiplets + // - Fill histograms for the multiplicity and z-vertex of femto-accepted events + // ------------------------------------------------------------------------------------- + if (lowMomentumMultiplets[hnmtrigger::kPPOmega] > 0) { + keepFemtoEvent[hnmtrigger::kPPOmega] = true; + mHistManager.fill(HIST("fProcessedEvents"), 6); + mHistManager.fill(HIST("ppomega/fMultiplicity"), collision.multNTracksPV()); + mHistManager.fill(HIST("ppomega/fZvtx"), collision.posZ()); + } + if (lowMomentumMultiplets[hnmtrigger::kPPEtaPrime] > 0) { + keepFemtoEvent[hnmtrigger::kPPEtaPrime] = true; + mHistManager.fill(HIST("fProcessedEvents"), 7); + mHistManager.fill(HIST("ppetaprime/fMultiplicity"), collision.multNTracksPV()); + mHistManager.fill(HIST("ppetaprime/fZvtx"), collision.posZ()); + } + if (lowMomentumMultiplets[hnmtrigger::kOmegaD] > 0) { + keepFemtoEvent[hnmtrigger::kOmegaD] = true; + mHistManager.fill(HIST("fProcessedEvents"), 8); + mHistManager.fill(HIST("omegad/fMultiplicity"), collision.multNTracksPV()); + mHistManager.fill(HIST("omegad/fZvtx"), collision.posZ()); + } + if (lowMomentumMultiplets[hnmtrigger::kEtaPrimeD] > 0) { + keepFemtoEvent[hnmtrigger::kEtaPrimeD] = true; + mHistManager.fill(HIST("fProcessedEvents"), 9); + mHistManager.fill(HIST("etaprimed/fMultiplicity"), collision.multNTracksPV()); + mHistManager.fill(HIST("etaprimed/fZvtx"), collision.posZ()); + } + if (lowMomentumMultiplets[hnmtrigger::kOmegaP] > 0) { + keepFemtoEvent[hnmtrigger::kOmegaP] = true; + mHistManager.fill(HIST("fProcessedEvents"), 10); + mHistManager.fill(HIST("omegap/fMultiplicity"), collision.multNTracksPV()); + mHistManager.fill(HIST("omegap/fZvtx"), collision.posZ()); + } + if (lowMomentumMultiplets[hnmtrigger::kEtaPrimeP] > 0) { + keepFemtoEvent[hnmtrigger::kEtaPrimeP] = true; + mHistManager.fill(HIST("fProcessedEvents"), 11); + mHistManager.fill(HIST("etaprimep/fMultiplicity"), collision.multNTracksPV()); + mHistManager.fill(HIST("etaprimep/fZvtx"), collision.posZ()); + } + + // -----------------------------> Set trigger flags <----------------------------------- + // - 4 high pT spectrum trigger flags (PCM & EMC * omega & eta') + // - 4 femto trigger flags (p-omega, p-eta', d-omega || pp-omega, d-eta' || pp-eta') + // ------------------------------------------------------------------------------------- + tags(colContainsPCMOmega, colContainsEMCOmega, colContainsPCMEtaPrime, colContainsEMCEtaPrime, keepFemtoEvent[hnmtrigger::kOmegaP], keepFemtoEvent[hnmtrigger::kEtaPrimeP], + keepFemtoEvent[hnmtrigger::kPPOmega] || keepFemtoEvent[hnmtrigger::kOmegaD], keepFemtoEvent[hnmtrigger::kPPEtaPrime] || keepFemtoEvent[hnmtrigger::kEtaPrimeD]); + + if (!colContainsPCMOmega && !colContainsEMCOmega && !colContainsPCMEtaPrime && !colContainsEMCEtaPrime && !keepFemtoEvent[hnmtrigger::kPPOmega] && !keepFemtoEvent[hnmtrigger::kOmegaP] && !keepFemtoEvent[hnmtrigger::kPPEtaPrime] && !keepFemtoEvent[hnmtrigger::kEtaPrimeP] && !keepFemtoEvent[hnmtrigger::kOmegaD] && !keepFemtoEvent[hnmtrigger::kEtaPrimeD]) + mHistManager.fill(HIST("fProcessedEvents"), 1); // Fill "rejected", if no trigger selected the event + } + + /// \brief Loop over the GG candidates, fill the mass/pt histograms and set the isPi0/isEta flags based on the reconstructed mass + void processGGs(std::vector& vGGs) + { + int nGGsBeforeMassCuts = vGGs.size(); + for (unsigned int iGG = 0; iGG < vGGs.size(); iGG++) { + auto lightMeson = &vGGs.at(iGG); + + if (lightMeson->reconstructionType == photonpair::kPCMPCM) { + mHistManager.fill(HIST("GG/invMassVsPt_PCM"), lightMeson->m(), lightMeson->pT()); + } else if (lightMeson->reconstructionType == photonpair::kEMCEMC) { + mHistManager.fill(HIST("GG/invMassVsPt_EMC"), lightMeson->m(), lightMeson->pT()); + } else { + mHistManager.fill(HIST("GG/invMassVsPt_PCMEMC"), lightMeson->m(), lightMeson->pT()); + } + + if (lightMeson->m() > cfgMassWindowOmega->get("pi0_min") && lightMeson->m() < cfgMassWindowOmega->get("pi0_max")) { + lightMeson->isPi0 = true; + } else if (lightMeson->m() > cfgMassWindowEtaPrime->get("eta_min") && lightMeson->m() < cfgMassWindowEtaPrime->get("eta_max")) { + lightMeson->isEta = true; + } else { + vGGs.erase(vGGs.begin() + iGG); + iGG--; + } + } + mHistManager.fill(HIST("Event/nGGs"), nGGsBeforeMassCuts, vGGs.size()); + } + + /// \brief Loop over the heavy neutral meson candidates, fill the mass/pt histograms and set the trigger flags based on the reconstructed mass + void processHNMs(std::vector& vHNMs) + { + int nHNMsBeforeMassCuts = vHNMs.size(); + + for (unsigned int iHNM = 0; iHNM < vHNMs.size(); iHNM++) { + auto heavyNeutralMeson = vHNMs.at(iHNM); + float massHNM = heavyNeutralMeson.m(cfgHNMMassCorrection); + + if (heavyNeutralMeson.gg->reconstructionType == photonpair::kPCMPCM) { + if (heavyNeutralMeson.gg->isPi0) { + mHistManager.fill(HIST("HNM/Before/Omega/PCM/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/Before/Omega/PCM/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/Before/Omega/PCM/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } else if (heavyNeutralMeson.gg->isEta) { + mHistManager.fill(HIST("HNM/Before/EtaPrime/PCM/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/Before/EtaPrime/PCM/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/Before/EtaPrime/PCM/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } + } else if (heavyNeutralMeson.gg->reconstructionType == photonpair::kEMCEMC) { + if (heavyNeutralMeson.gg->isPi0) { + mHistManager.fill(HIST("HNM/Before/Omega/EMC/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/Before/Omega/EMC/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/Before/Omega/EMC/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } else if (heavyNeutralMeson.gg->isEta) { + mHistManager.fill(HIST("HNM/Before/EtaPrime/EMC/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/Before/EtaPrime/EMC/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/Before/EtaPrime/EMC/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } + } else { + if (heavyNeutralMeson.gg->isPi0) { + mHistManager.fill(HIST("HNM/Before/Omega/PCMEMC/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/Before/Omega/PCMEMC/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/Before/Omega/PCMEMC/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } else if (heavyNeutralMeson.gg->isEta) { + mHistManager.fill(HIST("HNM/Before/EtaPrime/PCMEMC/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/Before/EtaPrime/PCMEMC/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/Before/EtaPrime/PCMEMC/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } + } + + if (heavyNeutralMeson.gg->isPi0 && massHNM > cfgMassWindowOmega->get("omega_min") && massHNM < cfgMassWindowOmega->get("omega_max")) { + if (heavyNeutralMeson.gg->reconstructionType == photonpair::kPCMPCM) { + if (heavyNeutralMeson.pT() > cfgMinHNMPtsFemtoTrigger->get("PCM_omega")) { + omegaPCM.emplace_back(heavyNeutralMeson.pT(), heavyNeutralMeson.eta(), RecoDecay::constrainAngle(heavyNeutralMeson.phi()), mMassOmega); + mHistManager.fill(HIST("HNM/After/Omega/PCM/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/After/Omega/PCM/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/After/Omega/PCM/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } + if (heavyNeutralMeson.pT() > cfgMinHNMPtsSpectrumTrigger->get("PCM_omega")) + colContainsPCMOmega = true; + } else if (heavyNeutralMeson.gg->reconstructionType == photonpair::kEMCEMC) { + if (heavyNeutralMeson.pT() > cfgMinHNMPtsFemtoTrigger->get("EMC_omega")) { + omegaEMC.emplace_back(heavyNeutralMeson.pT(), heavyNeutralMeson.eta(), RecoDecay::constrainAngle(heavyNeutralMeson.phi()), mMassOmega); + mHistManager.fill(HIST("HNM/After/Omega/EMC/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/After/Omega/EMC/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/After/Omega/EMC/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } + if (heavyNeutralMeson.pT() > cfgMinHNMPtsSpectrumTrigger->get("EMC_omega")) + colContainsEMCOmega = true; + } + } else if (heavyNeutralMeson.gg->isEta && massHNM > cfgMassWindowEtaPrime->get("etaprime_min") && massHNM < cfgMassWindowEtaPrime->get("etaprime_max")) { + if (heavyNeutralMeson.gg->reconstructionType == photonpair::kPCMPCM) { + if (heavyNeutralMeson.pT() > cfgMinHNMPtsFemtoTrigger->get("PCM_etaprime")) { + etaPrimePCM.emplace_back(heavyNeutralMeson.pT(), heavyNeutralMeson.eta(), RecoDecay::constrainAngle(heavyNeutralMeson.phi()), mMassEtaPrime); + mHistManager.fill(HIST("HNM/After/EtaPrime/PCM/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/After/EtaPrime/PCM/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/After/EtaPrime/PCM/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } + if (heavyNeutralMeson.pT() > cfgMinHNMPtsSpectrumTrigger->get("PCM_etaprime")) + colContainsPCMEtaPrime = true; + } else if (heavyNeutralMeson.gg->reconstructionType == photonpair::kEMCEMC) { + if (heavyNeutralMeson.pT() > cfgMinHNMPtsFemtoTrigger->get("EMC_etaprime")) { + etaPrimeEMC.emplace_back(heavyNeutralMeson.pT(), heavyNeutralMeson.eta(), RecoDecay::constrainAngle(heavyNeutralMeson.phi()), mMassEtaPrime); + mHistManager.fill(HIST("HNM/After/EtaPrime/EMC/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/After/EtaPrime/EMC/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/After/EtaPrime/EMC/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } + if (heavyNeutralMeson.pT() > cfgMinHNMPtsSpectrumTrigger->get("EMC_etaprime")) + colContainsEMCEtaPrime = true; + } + } else { + vHNMs.erase(vHNMs.begin() + iHNM); + iHNM--; + } + } + mHistManager.fill(HIST("Event/nHeavyNeutralMesons"), nHNMsBeforeMassCuts, vHNMs.size()); + + if (colContainsPCMOmega) + mHistManager.fill(HIST("fProcessedEvents"), 2); + if (colContainsEMCOmega) + mHistManager.fill(HIST("fProcessedEvents"), 3); + if (colContainsPCMEtaPrime) + mHistManager.fill(HIST("fProcessedEvents"), 4); + if (colContainsEMCEtaPrime) + mHistManager.fill(HIST("fProcessedEvents"), 5); + } +}; + +WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/EventFiltering/PWGHF/HFFilter.cxx b/EventFiltering/PWGHF/HFFilter.cxx index 38167b92b06..14390515f56 100644 --- a/EventFiltering/PWGHF/HFFilter.cxx +++ b/EventFiltering/PWGHF/HFFilter.cxx @@ -18,29 +18,43 @@ /// \author Alexandre Bigot , Strasbourg University /// \author Biao Zhang , CCNU /// \author Federica Zanone , Heidelberg University +/// \author Antonio Palasciano , INFN Bari + +#include +#include +#include +#include + +#include "TRandom3.h" #include "CommonConstants/PhysicsConstants.h" #include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" +#include "DCAFitter/DCAFitterN.h" #include "DetectorsBase/Propagator.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/ASoAHelpers.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/DCA.h" +#include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseITS.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "EventFiltering/filterTables.h" #include "EventFiltering/PWGHF/HFFilterHelpers.h" +#include "PWGHF/Utils/utilsTrkCandHf.h" using namespace o2; +using namespace o2::soa; using namespace o2::analysis; using namespace o2::aod::hffilters; using namespace o2::framework; @@ -55,55 +69,68 @@ struct HfFilter { // Main struct for HF triggers Produces optimisationTreeCollisions; Configurable activateQA{"activateQA", 0, "flag to enable QA histos (0 no QA, 1 basic QA, 2 extended QA, 3 very extended QA)"}; - Configurable applyEventSelection{"applyEventSelection", true, "flag to enable event selection (sel8 + Zvt and possibly time-frame border cut)"}; - Configurable applyTimeFrameBorderCut{"applyTimeFrameBorderCut", true, "flag to enable time-frame border cut"}; + Configurable activateSecVtxForB{"activateSecVtxForB", false, "flag to enable 2nd vertex fitting - only beauty hadrons"}; // parameters for all triggers // nsigma PID (except for V0 and cascades) - Configurable> nSigmaPidCuts{"nSigmaPidCuts", {cutsNsigma[0], 3, 6, labelsRowsNsigma, labelsColumnsNsigma}, "Nsigma cuts for TPC/TOF PID (except for V0 and cascades)"}; + Configurable> nSigmaPidCuts{"nSigmaPidCuts", {cutsNsigma[0], 4, 8, labelsRowsNsigma, labelsColumnsNsigma}, "Nsigma cuts for ITS/TPC/TOF PID (except for V0 and cascades)"}; // min and max pts for tracks and bachelors (except for V0 and cascades) - Configurable> ptCuts{"ptCuts", {cutsPt[0], 2, 6, labelsRowsCutsPt, labelsColumnsCutsPt}, "minimum and maximum pT for bachelor tracks (except for V0 and cascades)"}; + Configurable> ptCuts{"ptCuts", {cutsPt[0], 2, 10, labelsRowsCutsPt, labelsColumnsCutsPt}, "minimum and maximum pT for bachelor tracks (except for V0 and cascades)"}; // parameters for high-pT triggers Configurable> ptThresholds{"ptThresholds", {cutsHighPtThresholds[0], 1, 2, labelsEmpty, labelsColumnsHighPtThresholds}, "pT treshold for high pT charm hadron candidates for kHighPt triggers in GeV/c"}; // parameters for beauty triggers - Configurable> deltaMassBeauty{"deltaMassBeauty", {cutsDeltaMassB[0], 1, kNBeautyParticles, labelsEmpty, labelsColumnsDeltaMassB}, "invariant-mass delta with respect to the b-hadron masses in GeV/c2"}; Configurable> pTBinsTrack{"pTBinsTrack", std::vector{hf_cuts_single_track::vecBinsPtTrack}, "track pT bin limits for DCAXY pT-dependent cut"}; - Configurable> cutsTrackBeauty3Prong{"cutsTrackBeauty3Prong", {hf_cuts_single_track::cutsTrack[0], hf_cuts_single_track::nBinsPtTrack, hf_cuts_single_track::nCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for 3-prong beauty candidates"}; - Configurable> cutsTrackBeauty4Prong{"cutsTrackBeauty4Prong", {hf_cuts_single_track::cutsTrack[0], hf_cuts_single_track::nBinsPtTrack, hf_cuts_single_track::nCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for 4-prong beauty candidates"}; + Configurable> cutsTrackBeauty3Prong{"cutsTrackBeauty3Prong", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for 3-prong beauty candidates"}; + Configurable> cutsTrackBeauty4Prong{"cutsTrackBeauty4Prong", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for 4-prong beauty candidates"}; + Configurable> cutsTrackBeautyToJPsi{"cutsTrackBeautyToJPsi", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for beauty->JPsi candidates (not muons)"}; Configurable paramCharmMassShape{"paramCharmMassShape", "2023_pass3", "Parametrisation of charm-hadron mass shape (options: 2023_pass3)"}; Configurable numSigmaDeltaMassCharmHad{"numSigmaDeltaMassCharmHad", 2.5, "Number of sigma for charm-hadron delta mass cut in B and D resonance triggers"}; - + Configurable> pTBinsBHadron{"pTBinsBHadron", std::vector{hf_trigger_cuts_presel_beauty::vecBinsPt}, "pT bin limits for beauty hadrons preselections"}; + + struct : o2::framework::ConfigurableGroup { + Configurable> cutsBplus{"cutsBplus", {hf_trigger_cuts_presel_beauty::cuts[0], hf_trigger_cuts_presel_beauty::nBinsPt, hf_trigger_cuts_presel_beauty::nCutVars, hf_trigger_cuts_presel_beauty::labelsPt, hf_trigger_cuts_presel_beauty::labelsColumnsTopolBeauty}, "B+ candidate selection per pT bin"}; + Configurable> cutsBzeroToDstar{"cutsBzeroToDstar", {hf_trigger_cuts_presel_beauty::cuts[0], hf_trigger_cuts_presel_beauty::nBinsPt, hf_trigger_cuts_presel_beauty::nCutVars, hf_trigger_cuts_presel_beauty::labelsPt, hf_trigger_cuts_presel_beauty::labelsColumnsTopolBeauty}, "B0 -> D*+ candidate selection per pT bin"}; + Configurable> cutsBzero{"cutsBzero", {hf_trigger_cuts_presel_beauty::cuts[0], hf_trigger_cuts_presel_beauty::nBinsPt, hf_trigger_cuts_presel_beauty::nCutVars, hf_trigger_cuts_presel_beauty::labelsPt, hf_trigger_cuts_presel_beauty::labelsColumnsTopolBeauty}, "B0 candidate selection per pT bin"}; + Configurable> cutsBs{"cutsBs", {hf_trigger_cuts_presel_beauty::cuts[0], hf_trigger_cuts_presel_beauty::nBinsPt, hf_trigger_cuts_presel_beauty::nCutVars, hf_trigger_cuts_presel_beauty::labelsPt, hf_trigger_cuts_presel_beauty::labelsColumnsTopolBeauty}, "Bs candidate selection per pT bin"}; + Configurable> cutsBc{"cutsBc", {hf_trigger_cuts_presel_beauty::cuts[0], hf_trigger_cuts_presel_beauty::nBinsPt, hf_trigger_cuts_presel_beauty::nCutVars, hf_trigger_cuts_presel_beauty::labelsPt, hf_trigger_cuts_presel_beauty::labelsColumnsTopolBeauty}, "Bc candidate selection per pT bin"}; + Configurable> cutsLb{"cutsLb", {hf_trigger_cuts_presel_beauty::cuts[0], hf_trigger_cuts_presel_beauty::nBinsPt, hf_trigger_cuts_presel_beauty::nCutVars, hf_trigger_cuts_presel_beauty::labelsPt, hf_trigger_cuts_presel_beauty::labelsColumnsTopolBeauty}, "Lb candidate selection per pT bin"}; + Configurable> cutsXib{"cutsXib", {hf_trigger_cuts_presel_beauty::cuts[0], hf_trigger_cuts_presel_beauty::nBinsPt, hf_trigger_cuts_presel_beauty::nCutVars, hf_trigger_cuts_presel_beauty::labelsPt, hf_trigger_cuts_presel_beauty::labelsColumnsTopolBeauty}, "Xib candidate selection per pT bin"}; + Configurable> cutsBtoJPsiX{"cutsBtoJPsiX", {hf_trigger_cuts_presel_beauty::cutsBtoJPsi[0], hf_trigger_cuts_presel_beauty::nBinsPt, hf_trigger_cuts_presel_beauty::nCutVarsBtoJPsi, hf_trigger_cuts_presel_beauty::labelsPt, hf_trigger_cuts_presel_beauty::labelsColumnsCutsBeautyToJPsi}, "B->JPsiX candidate selection"}; + } cutsBtoHadrons; // parameters for femto triggers Configurable femtoMaxRelativeMomentum{"femtoMaxRelativeMomentum", 2., "Maximal allowed value for relative momentum between charm-proton pairs in GeV/c"}; - Configurable> enableFemtoChannels{"enableFemtoChannels", {activeFemtoChannels[0], 1, 5, labelsEmpty, labelsColumnsFemtoChannels}, "Flags to enable/disable femto channels"}; - Configurable requireCharmMassForFemto{"requireCharmMassForFemto", false, "Flags to enable/disable cut on charm-hadron invariant-mass window for femto"}; - Configurable ptThresholdForFemtoPid{"ptThresholdForFemtoPid", 8., "pT threshold for changing strategy of proton PID in femto triggers"}; - Configurable forceTofPidForFemto{"forceTofPidForFemto", true, "force TOF PID for proton in femto triggers"}; + Configurable> enableFemtoChannels{"enableFemtoChannels", {activeFemtoChannels[0], 2, 5, labelsRowsFemtoChannels, labelsColumnsFemtoChannels}, "Flags to enable/disable femto channels"}; + Configurable> ptThresholdsForFemto{"ptThresholdsForFemto", {cutsPtThresholdsForFemto[0], 1, 2, labelsEmpty, labelsColumnsPtThresholdsForFemto}, "pT treshold for proton or deuteron for kFemto triggers in GeV/c"}; + Configurable forceTofProtonForFemto{"forceTofProtonForFemto", true, "flag to force TOF PID for protons"}; + Configurable forceTofDeuteronForFemto{"forceTofDeuteronForFemto", false, "flag to force TOF PID for deuterons"}; // double charm - Configurable> enableDoubleCharmChannels{"enableDoubleCharmChannels", {activeDoubleCharmChannels[0], 1, 3, labelsEmpty, labelsColumnsDoubleCharmChannels}, "Flags to enable/disable double charm channels"}; + Configurable> enableDoubleCharmChannels{"enableDoubleCharmChannels", {activeDoubleCharmChannels[0], 2, 3, labelsRowsDoubleCharmChannels, labelsColumnsDoubleCharmChannels}, "Flags to enable/disable double charm channels"}; Configurable keepOnlyDplusForDouble3Prongs{"keepOnlyDplusForDouble3Prongs", false, "Flag to enable/disable to keep only D+ in double charm 3-prongs trigger"}; // parameters for resonance triggers Configurable> cutsGammaK0sLambda{"cutsGammaK0sLambda", {cutsV0s[0], 1, 6, labelsEmpty, labelsColumnsV0s}, "Selections for V0s (gamma, K0s, Lambda) for D+V0 triggers"}; - Configurable> cutsPtDeltaMassCharmReso{"cutsPtDeltaMassCharmReso", {cutsCharmReso[0], 3, 11, labelsRowsDeltaMassCharmReso, labelsColumnsDeltaMassCharmReso}, "pt (GeV/c) and invariant-mass delta (GeV/c2) for charm hadron resonances"}; + Configurable> cutsPtDeltaMassCharmReso{"cutsPtDeltaMassCharmReso", {cutsCharmReso[0], 4, 13, labelsRowsDeltaMassCharmReso, labelsColumnsDeltaMassCharmReso}, "pt (GeV/c) and invariant-mass delta (GeV/c2) for charm hadron resonances"}; Configurable keepAlsoWrongDmesLambdaPairs{"keepAlsoWrongDmesLambdaPairs", true, "flat go keep also wrong sign D+Lambda pairs"}; + Configurable keepAlsoWrongDmesProtonPairs{"keepAlsoWrongDmesProtonPairs", true, "flat go keep also wrong sign D0p pairs"}; + Configurable keepAlsoWrongDstarMesProtonPairs{"keepAlsoWrongDstarMesProtonPairs", true, "flat go keep also wrong sign D*0p pairs"}; // parameters for charm baryons to Xi bachelor Configurable> cutsXiCascades{"cutsXiCascades", {cutsCascades[0], 1, 8, labelsEmpty, labelsColumnsCascades}, "Selections for cascades (Xi) for Xi+bachelor triggers"}; - Configurable> cutsXiBachelor{"cutsXiBachelor", {cutsCharmBaryons[0], 1, 4, labelsEmpty, labelsColumnsCharmBaryons}, "Selections for charm baryons (Xi+Pi and Xi+Ka)"}; - Configurable> cutsTrackCharmBaryonBachelor{"cutsTrackCharmBaryonBachelor", {hf_cuts_single_track::cutsTrack[0], hf_cuts_single_track::nBinsPtTrack, hf_cuts_single_track::nCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for charm-baryon bachelor candidates"}; + Configurable> cutsXiBachelor{"cutsXiBachelor", {cutsCharmBaryons[0], 1, 11, labelsEmpty, labelsColumnsCharmBarCuts}, "Selections for charm baryons (Xi+Pi, Xi+Ka, Xi+Pi+Pi)"}; + Configurable> cutsTrackCharmBaryonBachelor{"cutsTrackCharmBaryonBachelor", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for charm-baryon bachelor candidates"}; + Configurable> requireStrangenessTracking{"requireStrangenessTracking", {requireStrangenessTrackedXi[0], 1, 2, labelsEmpty, labelsColumnsCharmBaryons}, "Flags to require strangeness tracking for channels with Xi"}; // parameters for ML application Configurable> pTBinsBDT{"pTBinsBDT", std::vector{hf_cuts_bdt_multiclass::vecBinsPt}, "track pT bin limits for BDT cut"}; - Configurable> thresholdBDTScoreD0ToKPi{"thresholdBDTScoreD0ToKPi", {hf_cuts_bdt_multiclass::cuts[0], hf_cuts_bdt_multiclass::nBinsPt, hf_cuts_bdt_multiclass::nCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of D0 candidates"}; - Configurable> thresholdBDTScoreDPlusToPiKPi{"thresholdBDTScoreDPlusToPiKPi", {hf_cuts_bdt_multiclass::cuts[0], hf_cuts_bdt_multiclass::nBinsPt, hf_cuts_bdt_multiclass::nCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of D+ candidates"}; - Configurable> thresholdBDTScoreDSToPiKK{"thresholdBDTScoreDSToPiKK", {hf_cuts_bdt_multiclass::cuts[0], hf_cuts_bdt_multiclass::nBinsPt, hf_cuts_bdt_multiclass::nCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Ds+ candidates"}; - Configurable> thresholdBDTScoreLcToPiKP{"thresholdBDTScoreLcToPiKP", {hf_cuts_bdt_multiclass::cuts[0], hf_cuts_bdt_multiclass::nBinsPt, hf_cuts_bdt_multiclass::nCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Lc+ candidates"}; - Configurable> thresholdBDTScoreXicToPiKP{"thresholdBDTScoreXicToPiKP", {hf_cuts_bdt_multiclass::cuts[0], hf_cuts_bdt_multiclass::nBinsPt, hf_cuts_bdt_multiclass::nCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Xic+ candidates"}; + Configurable> thresholdBDTScoreD0ToKPi{"thresholdBDTScoreD0ToKPi", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of D0 candidates"}; + Configurable> thresholdBDTScoreDPlusToPiKPi{"thresholdBDTScoreDPlusToPiKPi", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of D+ candidates"}; + Configurable> thresholdBDTScoreDSToPiKK{"thresholdBDTScoreDSToPiKK", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Ds+ candidates"}; + Configurable> thresholdBDTScoreLcToPiKP{"thresholdBDTScoreLcToPiKP", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Lc+ candidates"}; + Configurable> thresholdBDTScoreXicToPiKP{"thresholdBDTScoreXicToPiKP", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Xic+ candidates"}; Configurable acceptBdtBkgOnly{"acceptBdtBkgOnly", true, "Enable / disable selection based on BDT bkg score only"}; @@ -126,9 +153,20 @@ struct HfFilter { // Main struct for HF triggers // parameter for Optimisation Tree Configurable applyOptimisation{"applyOptimisation", false, "Flag to enable or disable optimisation"}; + // manual downscale factors + Configurable applyDownscale{"applyDownscale", false, "Flag to enable or disable the application of downscale factors"}; + Configurable> downscaleFactors{"downscaleFactors", {defDownscaleFactors[0], kNtriggersHF, 1, hfTriggerNames, labelsDownscaleFactor}, "Downscale factors for each trigger (from 0 to 1)"}; + // array of BDT thresholds std::array, kNCharmParticles> thresholdBDTScores; + o2::vertexing::DCAFitterN<2> df2; // fitter for Charm Hadron vertex (2-prong vertex fitter) + o2::vertexing::DCAFitterN<3> df3; // fitter for Charm/Beauty Hadron vertex (3-prong vertex fitter) + o2::vertexing::DCAFitterN<4> df4; // fitter for Beauty Hadron vertex (4-prong vertex fitter) + o2::vertexing::DCAFitterN<2> dfB; // fitter for Beauty Hadron vertex (2-prong vertex fitter) + o2::vertexing::DCAFitterN<3> dfBtoDstar; // fitter for Beauty Hadron to D* vertex (3-prong vertex fitter) + o2::vertexing::DCAFitterN<2> dfStrangeness; // fitter for V0s and cascades (2-prong vertex fitter) + HistogramRegistry registry{"registry"}; std::shared_ptr hProcessedEvents; @@ -136,15 +174,19 @@ struct HfFilter { // Main struct for HF triggers std::shared_ptr hN2ProngCharmCand, hN3ProngCharmCand; std::array, kNCharmParticles> hCharmHighPt{}; std::array, kNCharmParticles> hCharmProtonKstarDistr{}; - std::array, kNBeautyParticles> hMassVsPtB{}; - std::array, kNCharmParticles + 17> hMassVsPtC{}; // +9 for resonances (D*+, D*0, Ds*+, Ds1+, Ds2*+, Xic+* right sign, Xic+* wrong sign, Xic0* right sign, Xic0* wrong sign) +2 for SigmaC (SigmaC++, SigmaC0) +2 for SigmaCK pairs (SigmaC++K-, SigmaC0K0s) +2 for charm baryons (Xi+Pi, Xi+Ka) - std::shared_ptr hProtonTPCPID, hProtonTOFPID; + std::array, kNCharmParticles> hCharmDeuteronKstarDistr{}; + std::array, nTotBeautyParts> hMassVsPtB{}; + std::array, kNCharmParticles + 23> hMassVsPtC{}; // +9 for resonances (D*+, D*0, Ds*+, Ds1+, Ds2*+, Xic+* right sign, Xic+* wrong sign, Xic0* right sign, Xic0* wrong sign) +2 for SigmaC (SigmaC++, SigmaC0) +2 for SigmaCK pairs (SigmaC++K-, SigmaC0K0s) +3 for charm baryons (Xi+Pi, Xi+Ka, Xi+Pi+Pi) + JPsi + 4 for charm baryons (D0+p, D0+pWrongSign, D*0p, D*0+pWrongSign) + std::array, 4> hPrDePID; // proton TPC, proton TOF, deuteron TPC, deuteron TOF std::array, kNCharmParticles> hBDTScoreBkg{}; std::array, kNCharmParticles> hBDTScorePrompt{}; std::array, kNCharmParticles> hBDTScoreNonPrompt{}; std::array, kNV0> hArmPod{}; std::shared_ptr hV0Selected; - std::shared_ptr hMassXi; + std::array, 2> hMassXi{}; // not tracked and tracked + std::array, kNBeautyParticles> hCpaVsPtB{}; + std::array, kNBeautyParticles> hDecayLengthVsPtB{}; + std::array, kNBeautyParticles> hImpactParamProductVsPtB{}; // material correction for track propagation o2::base::MatLayerCylSet* lut; @@ -157,20 +199,30 @@ struct HfFilter { // Main struct for HF triggers void init(InitContext&) { helper.setHighPtTriggerThresholds(ptThresholds->get(0u, 0u), ptThresholds->get(0u, 1u)); + helper.setPtTriggerThresholdsForFemto(ptThresholdsForFemto->get(0u, 0u), ptThresholdsForFemto->get(0u, 1u)); helper.setPtBinsSingleTracks(pTBinsTrack); - helper.setPtLimitsBeautyBachelor(ptCuts->get(0u, 0u), ptCuts->get(1u, 0u)); + helper.setPtBinsBeautyHadrons(pTBinsBHadron); + helper.setPtLimitsBeautyBachelor(ptCuts->get(0u, 0u), ptCuts->get(1u, 0u), ptCuts->get(0u, 7u), ptCuts->get(1u, 7u)); helper.setPtLimitsDstarSoftPion(ptCuts->get(0u, 1u), ptCuts->get(1u, 1u)); helper.setPtLimitsProtonForFemto(ptCuts->get(0u, 2u), ptCuts->get(1u, 2u)); + helper.setPtLimitsDeuteronForFemto(ptCuts->get(0u, 6u), ptCuts->get(1u, 6u)); helper.setPtLimitsCharmBaryonBachelor(ptCuts->get(0u, 3u), ptCuts->get(1u, 3u)); - helper.setCutsSingleTrackBeauty(cutsTrackBeauty3Prong, cutsTrackBeauty4Prong); + helper.setPtLimitsLcResonanceBachelor(ptCuts->get(0u, 8u), ptCuts->get(1u, 8u)); + helper.setPtLimitsThetaCBachelor(ptCuts->get(0u, 9u), ptCuts->get(1u, 9u)); + helper.setCutsSingleTrackBeauty(cutsTrackBeauty3Prong, cutsTrackBeauty4Prong, cutsTrackBeauty4Prong); helper.setCutsSingleTrackCharmBaryonBachelor(cutsTrackCharmBaryonBachelor); - helper.setPtThresholdPidStrategyForFemto(ptThresholdForFemtoPid); - helper.setNsigmaProtonCutsForFemto(std::array{nSigmaPidCuts->get(0u, 3u), nSigmaPidCuts->get(1u, 3u), nSigmaPidCuts->get(2u, 3u)}); + helper.setCutsBhadrons(cutsBtoHadrons.cutsBplus, cutsBtoHadrons.cutsBzeroToDstar, cutsBtoHadrons.cutsBc, cutsBtoHadrons.cutsBzero, cutsBtoHadrons.cutsBs, cutsBtoHadrons.cutsLb, cutsBtoHadrons.cutsXib); + helper.setCutsBtoJPsi(cutsBtoHadrons.cutsBtoJPsiX); + helper.setNsigmaProtonCutsForFemto(std::array{nSigmaPidCuts->get(0u, 3u), nSigmaPidCuts->get(1u, 3u), nSigmaPidCuts->get(2u, 3u), nSigmaPidCuts->get(3u, 3u)}); + helper.setNsigmaDeuteronCutsForFemto(std::array{nSigmaPidCuts->get(0u, 6u), nSigmaPidCuts->get(1u, 6u), nSigmaPidCuts->get(2u, 6u), nSigmaPidCuts->get(3u, 6u)}); helper.setNsigmaProtonCutsForCharmBaryons(nSigmaPidCuts->get(0u, 0u), nSigmaPidCuts->get(1u, 0u)); helper.setNsigmaPionKaonCutsForDzero(nSigmaPidCuts->get(0u, 1u), nSigmaPidCuts->get(1u, 1u)); helper.setNsigmaKaonCutsFor3Prongs(nSigmaPidCuts->get(0u, 2u), nSigmaPidCuts->get(1u, 2u)); + helper.setNsigmaKaonProtonCutsForBeautyToJPsi(nSigmaPidCuts->get(0u, 7u), nSigmaPidCuts->get(1u, 7u)); + helper.setForceTofForFemto(forceTofProtonForFemto, forceTofDeuteronForFemto); helper.setV0Selections(cutsGammaK0sLambda->get(0u, 0u), cutsGammaK0sLambda->get(0u, 1u), cutsGammaK0sLambda->get(0u, 2u), cutsGammaK0sLambda->get(0u, 3u), cutsGammaK0sLambda->get(0u, 4u), cutsGammaK0sLambda->get(0u, 5u)); helper.setXiSelections(cutsXiCascades->get(0u, 0u), cutsXiCascades->get(0u, 1u), cutsXiCascades->get(0u, 2u), cutsXiCascades->get(0u, 3u), cutsXiCascades->get(0u, 4u), cutsXiCascades->get(0u, 5u), cutsXiCascades->get(0u, 6u), cutsXiCascades->get(0u, 7u)); + helper.setXiBachelorSelections(cutsXiBachelor->get(0u, 0u), cutsXiBachelor->get(0u, 1u), cutsXiBachelor->get(0u, 2u), cutsXiBachelor->get(0u, 3u), cutsXiBachelor->get(0u, 4u), cutsXiBachelor->get(0u, 5u), cutsXiBachelor->get(0u, 6u), cutsXiBachelor->get(0u, 7u), cutsXiBachelor->get(0u, 8u), cutsXiBachelor->get(0u, 9u), cutsXiBachelor->get(0u, 10u)); helper.setNsigmaPiCutsForCharmBaryonBachelor(nSigmaPidCuts->get(0u, 4u), nSigmaPidCuts->get(1u, 4u)); helper.setTpcPidCalibrationOption(setTPCCalib); helper.setMassResolParametrisation(paramCharmMassShape); @@ -178,8 +230,17 @@ struct HfFilter { // Main struct for HF triggers helper.setPtRangeSoftPiSigmaC(ptCuts->get(0u, 4u), ptCuts->get(1u, 4u)); helper.setPtDeltaMassRangeSigmaC(cutsPtDeltaMassCharmReso->get(0u, 6u), cutsPtDeltaMassCharmReso->get(1u, 6u), cutsPtDeltaMassCharmReso->get(0u, 7u), cutsPtDeltaMassCharmReso->get(1u, 7u), cutsPtDeltaMassCharmReso->get(0u, 8u), cutsPtDeltaMassCharmReso->get(1u, 8u), cutsPtDeltaMassCharmReso->get(0u, 9u), cutsPtDeltaMassCharmReso->get(1u, 9u), cutsPtDeltaMassCharmReso->get(2u, 6u), cutsPtDeltaMassCharmReso->get(2u, 7u), cutsPtDeltaMassCharmReso->get(2u, 8u), cutsPtDeltaMassCharmReso->get(2u, 9u)); helper.setPtRangeSoftKaonXicResoToSigmaC(ptCuts->get(0u, 5u), ptCuts->get(1u, 5u)); + helper.setVtxConfiguration(dfStrangeness, true); // (DCAFitterN, useAbsDCA) + dfStrangeness.setMatCorrType(matCorr); + helper.setVtxConfiguration(df2, false); // (DCAFitterN, useAbsDCA) + helper.setVtxConfiguration(df3, false); + helper.setVtxConfiguration(df4, false); + if (activateSecVtxForB) { + helper.setVtxConfiguration(dfB, true); + helper.setVtxConfiguration(dfBtoDstar, true); + } - hProcessedEvents = registry.add("fProcessedEvents", "HF - event filtered;;counts", HistType::kTH1F, {{kNtriggersHF + 2, -0.5, +kNtriggersHF + 1.5}}); + hProcessedEvents = registry.add("fProcessedEvents", "HF - event filtered;;counts", HistType::kTH1D, {{kNtriggersHF + 2, -0.5, +kNtriggersHF + 1.5}}); for (auto iBin = 0; iBin < kNtriggersHF + 2; ++iBin) { if (iBin < 2) hProcessedEvents->GetXaxis()->SetBinLabel(iBin + 1, eventTitles[iBin].data()); @@ -188,52 +249,88 @@ struct HfFilter { // Main struct for HF triggers } if (activateQA) { - hN2ProngCharmCand = registry.add("fN2ProngCharmCand", "Number of 2-prong charm candidates per event;#it{N}_{candidates};counts", HistType::kTH1F, {{50, -0.5, 49.5}}); - hN3ProngCharmCand = registry.add("fN3ProngCharmCand", "Number of 3-prong charm candidates per event;#it{N}_{candidates};counts", HistType::kTH1F, {{50, -0.5, 49.5}}); + hN2ProngCharmCand = registry.add("fN2ProngCharmCand", "Number of 2-prong charm candidates per event;#it{N}_{candidates};counts", HistType::kTH1D, {{50, -0.5, 49.5}}); + hN3ProngCharmCand = registry.add("fN3ProngCharmCand", "Number of 3-prong charm candidates per event;#it{N}_{candidates};counts", HistType::kTH1D, {{50, -0.5, 49.5}}); for (int iCharmPart{0}; iCharmPart < kNCharmParticles; ++iCharmPart) { - hCharmHighPt[iCharmPart] = registry.add(Form("f%sHighPt", charmParticleNames[iCharmPart].data()), Form("#it{p}_{T} distribution of triggered high-#it{p}_{T} %s candidates;#it{p}_{T} (GeV/#it{c});counts", charmParticleNames[iCharmPart].data()), HistType::kTH1F, {ptAxis}); - hCharmProtonKstarDistr[iCharmPart] = registry.add(Form("f%sProtonKstarDistr", charmParticleNames[iCharmPart].data()), Form("#it{k}* distribution of triggered p#minus%s pairs;#it{k}* (GeV/#it{c});counts", charmParticleNames[iCharmPart].data()), HistType::kTH1F, {kstarAxis}); - hMassVsPtC[iCharmPart] = registry.add(Form("fMassVsPt%s", charmParticleNames[iCharmPart].data()), Form("#it{M} vs. #it{p}_{T} distribution of triggered %s candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", charmParticleNames[iCharmPart].data()), HistType::kTH2F, {ptAxis, massAxisC[iCharmPart]}); + hCharmHighPt[iCharmPart] = registry.add(Form("f%sHighPt", charmParticleNames[iCharmPart].data()), Form("#it{p}_{T} distribution of triggered high-#it{p}_{T} %s candidates;#it{p}_{T} (GeV/#it{c});counts", charmParticleNames[iCharmPart].data()), HistType::kTH1D, {ptAxis}); + hCharmProtonKstarDistr[iCharmPart] = registry.add(Form("f%sProtonKstarDistr", charmParticleNames[iCharmPart].data()), Form("#it{k}* distribution of triggered p#minus%s pairs;#it{k}* (GeV/#it{c});counts", charmParticleNames[iCharmPart].data()), HistType::kTH1D, {kstarAxis}); + hCharmDeuteronKstarDistr[iCharmPart] = registry.add(Form("f%sDeuteronKstarDistr", charmParticleNames[iCharmPart].data()), Form("#it{k}* distribution of triggered de%s pairs;#it{k}* (GeV/#it{c});counts", charmParticleNames[iCharmPart].data()), HistType::kTH1D, {kstarAxis}); + hMassVsPtC[iCharmPart] = registry.add(Form("fMassVsPt%s", charmParticleNames[iCharmPart].data()), Form("#it{M} vs. #it{p}_{T} distribution of triggered %s candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", charmParticleNames[iCharmPart].data()), HistType::kTH2D, {ptAxis, massAxisC[iCharmPart]}); if (activateQA > 1) { - hBDTScoreBkg[iCharmPart] = registry.add(Form("f%sBDTScoreBkgDistr", charmParticleNames[iCharmPart].data()), Form("BDT background score distribution for %s;BDT background score;counts", charmParticleNames[iCharmPart].data()), HistType::kTH1F, {bdtAxis}); - hBDTScorePrompt[iCharmPart] = registry.add(Form("f%sBDTScorePromptDistr", charmParticleNames[iCharmPart].data()), Form("BDT prompt score distribution for %s;BDT prompt score;counts", charmParticleNames[iCharmPart].data()), HistType::kTH1F, {bdtAxis}); - hBDTScoreNonPrompt[iCharmPart] = registry.add(Form("f%sBDTScoreNonPromptDistr", charmParticleNames[iCharmPart].data()), Form("BDT nonprompt score distribution for %s;BDT nonprompt score;counts", charmParticleNames[iCharmPart].data()), HistType::kTH1F, {bdtAxis}); + hBDTScoreBkg[iCharmPart] = registry.add(Form("f%sBDTScoreBkgDistr", charmParticleNames[iCharmPart].data()), Form("BDT background score distribution for %s;BDT background score;counts", charmParticleNames[iCharmPart].data()), HistType::kTH1D, {bdtAxis}); + hBDTScorePrompt[iCharmPart] = registry.add(Form("f%sBDTScorePromptDistr", charmParticleNames[iCharmPart].data()), Form("BDT prompt score distribution for %s;BDT prompt score;counts", charmParticleNames[iCharmPart].data()), HistType::kTH1D, {bdtAxis}); + hBDTScoreNonPrompt[iCharmPart] = registry.add(Form("f%sBDTScoreNonPromptDistr", charmParticleNames[iCharmPart].data()), Form("BDT nonprompt score distribution for %s;BDT nonprompt score;counts", charmParticleNames[iCharmPart].data()), HistType::kTH1D, {bdtAxis}); } } // charm resonances - hMassVsPtC[kNCharmParticles] = registry.add("fMassVsPtDStarPlus", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered DStarPlus candidates;#it{p}_{T} (GeV/#it{c});#Delta#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2F, {ptAxis, massAxisC[kNCharmParticles]}); - hMassVsPtC[kNCharmParticles + 1] = registry.add("fMassVsPtDStarZero", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered DStarZero candidates;#it{p}_{T} (GeV/#it{c});#Delta#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2F, {ptAxis, massAxisC[kNCharmParticles + 1]}); - hMassVsPtC[kNCharmParticles + 2] = registry.add("fMassVsPtDStarS", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered DStarS candidates;#it{p}_{T} (GeV/#it{c});#Delta#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2F, {ptAxis, massAxisC[kNCharmParticles + 2]}); - hMassVsPtC[kNCharmParticles + 3] = registry.add("fMassVsPtDs1Plus", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered Ds1Plus candidates;#it{p}_{T} (GeV/#it{c});#Delta#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2F, {ptAxis, massAxisC[kNCharmParticles + 3]}); - hMassVsPtC[kNCharmParticles + 4] = registry.add("fMassVsPtDs2StarPlus", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered Ds2StarPlus candidates;#it{p}_{T} (GeV/#Delta#it{c});#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2F, {ptAxis, massAxisC[kNCharmParticles + 4]}); - hMassVsPtC[kNCharmParticles + 5] = registry.add("fMassVsPtXicStarToDplusLambda", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered XicStar -> Dplus Lambda candidates;#it{p}_{T} (GeV/#it{c});#Delta#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2F, {ptAxis, massAxisC[kNCharmParticles + 5]}); - hMassVsPtC[kNCharmParticles + 6] = registry.add("fMassVsPtXicStarToDplusLambdaWrongSign", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered opposite-sign XicStar -> Dplus Lambda candidates;#it{p}_{T} (GeV/#it{c});#Delta#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2F, {ptAxis, massAxisC[kNCharmParticles + 6]}); - hMassVsPtC[kNCharmParticles + 7] = registry.add("fMassVsPtXicStarToD0Lambda", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered XicStar -> D0 Lambda candidates;#it{p}_{T} (GeV/#it{c});#Delta#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2F, {ptAxis, massAxisC[kNCharmParticles + 7]}); - hMassVsPtC[kNCharmParticles + 8] = registry.add("fMassVsPtXicStarToD0LambdaWrongSign", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered opposite-sign XicStar -> D0 Lambda candidates;#it{p}_{T} (GeV/#it{c});#Delta#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2F, {ptAxis, massAxisC[kNCharmParticles + 8]}); + hMassVsPtC[kNCharmParticles] = registry.add("fMassVsPtDStarPlus", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered DStarPlus candidates;#it{p}_{T} (GeV/#it{c});#Delta#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles]}); + hMassVsPtC[kNCharmParticles + 1] = registry.add("fMassVsPtDStarZero", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered DStarZero candidates;#it{p}_{T} (GeV/#it{c});#Delta#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 1]}); + hMassVsPtC[kNCharmParticles + 2] = registry.add("fMassVsPtDStarS", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered DStarS candidates;#it{p}_{T} (GeV/#it{c});#Delta#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 2]}); + hMassVsPtC[kNCharmParticles + 3] = registry.add("fMassVsPtDs1Plus", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered Ds1Plus candidates;#it{p}_{T} (GeV/#it{c});#Delta#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 3]}); + hMassVsPtC[kNCharmParticles + 4] = registry.add("fMassVsPtDs2StarPlus", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered Ds2StarPlus candidates;#it{p}_{T} (GeV/#Delta#it{c});#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 4]}); + hMassVsPtC[kNCharmParticles + 5] = registry.add("fMassVsPtXicStarToDplusLambda", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered XicStar -> Dplus Lambda candidates;#it{p}_{T} (GeV/#it{c});#Delta#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 5]}); + hMassVsPtC[kNCharmParticles + 6] = registry.add("fMassVsPtXicStarToDplusLambdaWrongSign", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered opposite-sign XicStar -> Dplus Lambda candidates;#it{p}_{T} (GeV/#it{c});#Delta#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 6]}); + hMassVsPtC[kNCharmParticles + 7] = registry.add("fMassVsPtXicStarToD0Lambda", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered XicStar -> D0 Lambda candidates;#it{p}_{T} (GeV/#it{c});#Delta#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 7]}); + hMassVsPtC[kNCharmParticles + 8] = registry.add("fMassVsPtXicStarToD0LambdaWrongSign", "#Delta#it{M} vs. #it{p}_{T} distribution of triggered opposite-sign XicStar -> D0 Lambda candidates;#it{p}_{T} (GeV/#it{c});#Delta#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 8]}); // SigmaC0,++ - hMassVsPtC[kNCharmParticles + 9] = registry.add("fMassVsPtSigmaCPlusPlus", "#it{M}(pK#pi#pi)-M(pK#pi) vs. #it{p}_{T} distribution of #Sigma_{c}^{++} candidates for triggers;#it{p}_{T}(#Sigma_{c}^{++}) (GeV/#it{c});#it{M}(pK#pi#pi)-M(pK#pi);counts", HistType::kTH2F, {ptAxis, massAxisC[kNCharmParticles + 9]}); - hMassVsPtC[kNCharmParticles + 10] = registry.add("fMassVsPtSigmaC0", "#it{M}(pK#pi#pi)-M(pK#pi) vs. #it{p}_{T} distribution of #Sigma_{c}^{0} candidates for triggers;#it{p}_{T}(#Sigma_{c}^{0}) (GeV/#it{c});#it{M}(pK#pi#pi)-M(pK#pi);counts", HistType::kTH2F, {ptAxis, massAxisC[kNCharmParticles + 10]}); + hMassVsPtC[kNCharmParticles + 9] = registry.add("fMassVsPtSigmaCPlusPlus", "#it{M}(pK#pi#pi)-M(pK#pi) vs. #it{p}_{T} distribution of #Sigma_{c}^{++} candidates for triggers;#it{p}_{T}(#Sigma_{c}^{++}) (GeV/#it{c});#it{M}(pK#pi#pi)-M(pK#pi);counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 9]}); + hMassVsPtC[kNCharmParticles + 10] = registry.add("fMassVsPtSigmaC0", "#it{M}(pK#pi#pi)-M(pK#pi) vs. #it{p}_{T} distribution of #Sigma_{c}^{0} candidates for triggers;#it{p}_{T}(#Sigma_{c}^{0}) (GeV/#it{c});#it{M}(pK#pi#pi)-M(pK#pi);counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 10]}); // SigmaCKaon pairs - hMassVsPtC[kNCharmParticles + 11] = registry.add("fMassVsPtSigmaC2455PlusPlusKaMinus", "#it{M}(#Sigma_{c}^{++}K^{-}(2455)) vs. #it{p}_{T} distribution of of triggered #Sigma_{c}^{++}K^{-} pairs;#it{p}_{T} (GeV/#it{c});#it{M}(#Sigma_{c}^{++}K^{-});counts", HistType::kTH2F, {ptAxis, massAxisC[kNCharmParticles + 11]}); - hMassVsPtC[kNCharmParticles + 12] = registry.add("fMassVsPtSigmaC2520PlusPlusKaMinus", "#it{M}(#Sigma_{c}^{++}K^{-}(2520)) vs. #it{p}_{T} distribution of of triggered #Sigma_{c}^{++}K^{-} pairs;#it{p}_{T} (GeV/#it{c});#it{M}(#Sigma_{c}^{++}K^{-});counts", HistType::kTH2F, {ptAxis, massAxisC[kNCharmParticles + 12]}); - hMassVsPtC[kNCharmParticles + 13] = registry.add("fMassVsPtSigmaC02455Ka0s", "#it{M}(#Sigma_{c}^{0}K^{0}_{s}(2455)) vs. #it{p}_{T} distribution of of triggered #Sigma_{c}^{0}K^{0}_{s} pairs;#it{p}_{T} (GeV/#it{c});#it{M}(#Sigma_{c}^{++}K^{-});counts", HistType::kTH2F, {ptAxis, massAxisC[kNCharmParticles + 13]}); - hMassVsPtC[kNCharmParticles + 14] = registry.add("fMassVsPtSigmaC02520Ka0s", "#it{M}(#Sigma_{c}^{0}K^{0}_{s}(2520)) vs. #it{p}_{T} distribution of of triggered #Sigma_{c}^{0}K^{0}_{s} pairs;#it{p}_{T} (GeV/#it{c});#it{M}(#Sigma_{c}^{++}K^{-});counts", HistType::kTH2F, {ptAxis, massAxisC[kNCharmParticles + 14]}); + hMassVsPtC[kNCharmParticles + 11] = registry.add("fMassVsPtSigmaC2455PlusPlusKaMinus", "#it{M}(#Sigma_{c}^{++}K^{-}(2455)) vs. #it{p}_{T} distribution of of triggered #Sigma_{c}^{++}K^{-} pairs;#it{p}_{T} (GeV/#it{c});#it{M}(#Sigma_{c}^{++}K^{-});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 11]}); + hMassVsPtC[kNCharmParticles + 12] = registry.add("fMassVsPtSigmaC2520PlusPlusKaMinus", "#it{M}(#Sigma_{c}^{++}K^{-}(2520)) vs. #it{p}_{T} distribution of of triggered #Sigma_{c}^{++}K^{-} pairs;#it{p}_{T} (GeV/#it{c});#it{M}(#Sigma_{c}^{++}K^{-});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 12]}); + hMassVsPtC[kNCharmParticles + 13] = registry.add("fMassVsPtSigmaC02455Ka0s", "#it{M}(#Sigma_{c}^{0}K^{0}_{s}(2455)) vs. #it{p}_{T} distribution of of triggered #Sigma_{c}^{0}K^{0}_{s} pairs;#it{p}_{T} (GeV/#it{c});#it{M}(#Sigma_{c}^{++}K^{-});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 13]}); + hMassVsPtC[kNCharmParticles + 14] = registry.add("fMassVsPtSigmaC02520Ka0s", "#it{M}(#Sigma_{c}^{0}K^{0}_{s}(2520)) vs. #it{p}_{T} distribution of of triggered #Sigma_{c}^{0}K^{0}_{s} pairs;#it{p}_{T} (GeV/#it{c});#it{M}(#Sigma_{c}^{++}K^{-});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 14]}); // charm baryons to LF cascades - hMassVsPtC[kNCharmParticles + 15] = registry.add("fMassVsPtCharmBaryonToXiPi", "#it{M} vs. #it{p}_{T} distribution of triggered #Xi+#pi candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2F, {ptAxis, massAxisC[kNCharmParticles + 15]}); - hMassVsPtC[kNCharmParticles + 16] = registry.add("fMassVsPtCharmBaryonToXiKa", "#it{M} vs. #it{p}_{T} distribution of triggered #Xi+K candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2F, {ptAxis, massAxisC[kNCharmParticles + 16]}); + hMassVsPtC[kNCharmParticles + 15] = registry.add("fMassVsPtCharmBaryonToXiPi", "#it{M} vs. #it{p}_{T} distribution of triggered #Xi+#pi candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 15]}); + hMassVsPtC[kNCharmParticles + 16] = registry.add("fMassVsPtCharmBaryonToXiKa", "#it{M} vs. #it{p}_{T} distribution of triggered #Xi+K candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 16]}); + hMassVsPtC[kNCharmParticles + 17] = registry.add("fMassVsPtCharmBaryonToXiPiPi", "#it{M} vs. #it{p}_{T} distribution of triggered #Xi+#pi+#pi candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 17]}); + // JPsi + hMassVsPtC[kNCharmParticles + 18] = registry.add("fMassVsPtJPsiToMuMu", "#it{M} vs. #it{p}_{T} distribution of triggered J/#psi to #mu#mu candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 18]}); + // Lc resonances + hMassVsPtC[kNCharmParticles + 19] = registry.add("fMassVsPtCharmBaryonToD0P", "#it{M} vs. #it{p}_{T} distribution of triggered D^{0}#p candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 19]}); + hMassVsPtC[kNCharmParticles + 20] = registry.add("fMassVsPtCharmBaryonToD0PWrongSign", "#it{M} vs. #it{p}_{T} distribution of triggered D^{0}#p wrong sign candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 20]}); + // ThetaC + hMassVsPtC[kNCharmParticles + 21] = registry.add("fMassVsPtCharmBaryonToDstarP", "#it{M} vs. #it{p}_{T} distribution of triggered D^{*0}#p candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 21]}); + hMassVsPtC[kNCharmParticles + 22] = registry.add("fMassVsPtCharmBaryonToDstarPWrongSign", "#it{M} vs. #it{p}_{T} distribution of triggered D^{*0}#p wrong sign candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", HistType::kTH2D, {ptAxis, massAxisC[kNCharmParticles + 22]}); for (int iBeautyPart{0}; iBeautyPart < kNBeautyParticles; ++iBeautyPart) { - hMassVsPtB[iBeautyPart] = registry.add(Form("fMassVsPt%s", beautyParticleNames[iBeautyPart].data()), Form("#it{M} vs. #it{p}_{T} distribution of triggered %s candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", beautyParticleNames[iBeautyPart].data()), HistType::kTH2F, {ptAxis, massAxisB[iBeautyPart]}); + hMassVsPtB[iBeautyPart] = registry.add(Form("fMassVsPt%s", beautyParticleNames[iBeautyPart].data()), Form("#it{M} vs. #it{p}_{T} distribution of triggered %s candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", beautyParticleNames[iBeautyPart].data()), HistType::kTH2D, {ptAxis, massAxisB[iBeautyPart]}); + hCpaVsPtB[iBeautyPart] = registry.add(Form("fCpaVsPt%s", beautyParticleNames[iBeautyPart].data()), Form("CPA vs. #it{p}_{T} distribution of triggered %s candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", beautyParticleNames[iBeautyPart].data()), HistType::kTH2D, {ptAxis, {500, 0., 1}}); + hDecayLengthVsPtB[iBeautyPart] = registry.add(Form("fDecayLengthVsPt%s", beautyParticleNames[iBeautyPart].data()), Form("DecayLength vs. #it{p}_{T} distribution of triggered %s candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", beautyParticleNames[iBeautyPart].data()), HistType::kTH2D, {ptAxis, {500, 0, 0.5}}); + if (iBeautyPart != kB0toDStar) { + hImpactParamProductVsPtB[iBeautyPart] = registry.add(Form("fImpactParamProductVsPt%s", beautyParticleNames[iBeautyPart].data()), Form("ImpactParamProduct vs. #it{p}_{T} distribution of triggered %s candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", beautyParticleNames[iBeautyPart].data()), HistType::kTH2D, {ptAxis, {500, -2.5e-3, +2.5e-3}}); + } + } + for (int iBeautyPart{kNBeautyParticles}; iBeautyPart < nTotBeautyParts; ++iBeautyPart) { + hMassVsPtB[iBeautyPart] = registry.add(Form("fMassVsPt%s", beautyParticleNames[iBeautyPart].data()), Form("#it{M} vs. #it{p}_{T} distribution of triggered %s candidates;#it{p}_{T} (GeV/#it{c});#it{M} (GeV/#it{c}^{2});counts", beautyParticleNames[iBeautyPart].data()), HistType::kTH2D, {ptAxis, massAxisB[iBeautyPart]}); } + constexpr int kNBinsHfVtxStages = kNHfVtxStage; + std::string labels[kNBinsHfVtxStages]; + labels[HfVtxStage::Skimmed] = "Skimm CharmHad-Pi pairs"; + labels[HfVtxStage::BeautyVertex] = "vertex CharmHad-Pi pairs"; + labels[HfVtxStage::CharmHadPiSelected] = "selected CharmHad-Pi pairs"; + static const AxisSpec axisHfVtxStages = {kNBinsHfVtxStages, 0.5, kNBinsHfVtxStages + 0.5, ""}; + registry.add("fHfVtxStages", "HfVtxStages;;entries", HistType::kTH2D, {axisHfVtxStages, {kNBeautyParticles, -0.5, +kNBeautyParticles - 0.5}}); + for (int iBin = 0; iBin < kNBinsHfVtxStages; iBin++) { + registry.get(HIST("fHfVtxStages"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); + } + for (int iBin = 0; iBin < kNBeautyParticles; iBin++) { + registry.get(HIST("fHfVtxStages"))->GetYaxis()->SetBinLabel(iBin + 1, beautyParticleNames[iBin].data()); + } + for (int iV0{kPhoton}; iV0 < kNV0; ++iV0) { - hArmPod[iV0] = registry.add(Form("fArmPod%s", v0Names[iV0].data()), Form("Armenteros Podolanski plot for selected %s;#it{#alpha};#it{q}_{T} (GeV/#it{c})", v0Labels[iV0].data()), HistType::kTH2F, {alphaAxis, qtAxis}); + hArmPod[iV0] = registry.add(Form("fArmPod%s", v0Names[iV0].data()), Form("Armenteros Podolanski plot for selected %s;#it{#alpha};#it{q}_{T} (GeV/#it{c})", v0Labels[iV0].data()), HistType::kTH2D, {alphaAxis, qtAxis}); } - hMassXi = registry.add("fMassXi", "#it{M} distribution of #Xi candidates;#it{M} (GeV/#it{c}^{2});counts", HistType::kTH1F, {{100, 1.28f, 1.36f}}); + hMassXi[0] = registry.add("fMassXi", "#it{M} distribution of #Xi candidates;#it{M} (GeV/#it{c}^{2});counts", HistType::kTH1D, {{100, 1.28f, 1.36f}}); + hMassXi[1] = registry.add("fMassTrackedXi", "#it{M} distribution of #Xi candidates;#it{M} (GeV/#it{c}^{2});counts", HistType::kTH1D, {{100, 1.28f, 1.36f}}); if (activateQA > 1) { - hProtonTPCPID = registry.add("fProtonTPCPID", "#it{N}_{#sigma}^{TPC} vs. #it{p} for selected protons;#it{p} (GeV/#it{c});#it{N}_{#sigma}^{TPC}", HistType::kTH2F, {pAxis, nSigmaAxis}); - hProtonTOFPID = registry.add("fProtonTOFPID", "#it{N}_{#sigma}^{TOF} vs. #it{p} for selected protons;#it{p} (GeV/#it{c});#it{N}_{#sigma}^{TOF}", HistType::kTH2F, {pAxis, nSigmaAxis}); - hV0Selected = registry.add("fV0Selected", "Selections for V0s;;counts", HistType::kTH2F, {{9, -0.5, 8.5}, {kNV0, -0.5, +kNV0 - 0.5}}); + hPrDePID[0] = registry.add("fProtonTPCPID", "#it{N}_{#sigma}^{TPC} vs. #it{p} for selected protons;#it{p} (GeV/#it{c});#it{N}_{#sigma}^{TPC}", HistType::kTH2D, {pAxis, nSigmaAxis}); + hPrDePID[1] = registry.add("fProtonTOFPID", "#it{N}_{#sigma}^{TOF} vs. #it{p} for selected protons;#it{p} (GeV/#it{c});#it{N}_{#sigma}^{TOF}", HistType::kTH2D, {pAxis, nSigmaAxis}); + hPrDePID[2] = registry.add("fDeuteronTPCPID", "#it{N}_{#sigma}^{TPC} vs. #it{p} for selected deuterons;#it{p} (GeV/#it{c});#it{N}_{#sigma}^{TPC}", HistType::kTH2D, {pAxis, nSigmaAxis}); + hPrDePID[3] = registry.add("fDeuteronTOFPID", "#it{N}_{#sigma}^{TOF} vs. #it{p} for selected deuterons;#it{p} (GeV/#it{c});#it{N}_{#sigma}^{TOF}", HistType::kTH2D, {pAxis, nSigmaAxis}); + + hV0Selected = registry.add("fV0Selected", "Selections for V0s;;counts", HistType::kTH2D, {{9, -0.5, 8.5}, {kNV0, -0.5, +kNV0 - 0.5}}); for (int iV0{kPhoton}; iV0 < kNV0; ++iV0) { hV0Selected->GetYaxis()->SetBinLabel(iV0 + 1, v0Labels[iV0].data()); @@ -260,37 +357,40 @@ struct HfFilter { // Main struct for HF triggers thresholdBDTScores = {thresholdBDTScoreD0ToKPi, thresholdBDTScoreDPlusToPiKPi, thresholdBDTScoreDSToPiKK, thresholdBDTScoreLcToPiKP, thresholdBDTScoreXicToPiKP}; } - using BigTracksMCPID = soa::Join; - using BigTracksPID = soa::Join; + using BigTracksMCPID = soa::Join; + using BigTracksPID = soa::Join; + using TracksIUPID = soa::Join; using CollsWithEvSel = soa::Join; using Hf2ProngsWithMl = soa::Join; using Hf3ProngsWithMl = soa::Join; Preslice trackIndicesPerCollision = aod::track_association::collisionId; - Preslice v0sPerCollision = aod::v0data::collisionId; + Preslice v0sPerCollision = aod::v0::collisionId; Preslice hf2ProngPerCollision = aod::track_association::collisionId; Preslice hf3ProngPerCollision = aod::track_association::collisionId; - Preslice cascPerCollision = aod::cascdata::collisionId; + Preslice cascPerCollision = aod::cascade::collisionId; Preslice photonsPerCollision = aod::v0photonkf::collisionId; + PresliceUnsorted trackedCascadesPerCollision = aod::track::collisionId; void process(CollsWithEvSel const& collisions, aod::BCsWithTimestamps const&, - aod::V0Datas const& v0s, - aod::CascDatas const& cascades, + aod::V0s const& v0s, + aod::Cascades const& cascades, + aod::AssignedTrackedCascades const& trackedCasc, Hf2ProngsWithMl const& cand2Prongs, Hf3ProngsWithMl const& cand3Prongs, aod::TrackAssoc const& trackIndices, - BigTracksPID const&, + BigTracksPID const& tracks, + TracksIUPID const& tracksIU, aod::V0PhotonsKF const& photons, aod::V0Legs const&) { for (const auto& collision : collisions) { bool keepEvent[kNtriggersHF]{false}; - if (applyEventSelection && (!collision.sel8() || std::fabs(collision.posZ()) > 11.f || (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) && applyTimeFrameBorderCut))) { // safety margin for Zvtx - - tags(keepEvent[kHighPt2P], keepEvent[kHighPt3P], keepEvent[kBeauty3P], keepEvent[kBeauty4P], keepEvent[kFemto2P], keepEvent[kFemto3P], keepEvent[kDoubleCharm2P], keepEvent[kDoubleCharm3P], keepEvent[kDoubleCharmMix], keepEvent[kV0Charm2P], keepEvent[kV0Charm3P], keepEvent[kCharmBarToXiBach], keepEvent[kSigmaCPPK], keepEvent[kSigmaC0K0], keepEvent[kPhotonCharm2P], keepEvent[kPhotonCharm3P]); + if (!collision.sel8() || std::fabs(collision.posZ()) > 11.f) { // safety margin for Zvtx + tags(keepEvent[kHighPt2P], keepEvent[kHighPt3P], keepEvent[kBeauty3P], keepEvent[kBeauty4P], keepEvent[kFemto2P], keepEvent[kFemto3P], keepEvent[kDoubleCharm2P], keepEvent[kDoubleCharm3P], keepEvent[kDoubleCharmMix], keepEvent[kV0Charm2P], keepEvent[kV0Charm3P], keepEvent[kCharmBarToXiBach], keepEvent[kSigmaCPPK], keepEvent[kSigmaC0K0], keepEvent[kPhotonCharm2P], keepEvent[kPhotonCharm3P], keepEvent[kSingleCharm2P], keepEvent[kSingleCharm3P], keepEvent[kSingleNonPromptCharm2P], keepEvent[kSingleNonPromptCharm3P], keepEvent[kCharmBarToXi2Bach], keepEvent[kPrCharm2P], keepEvent[kBtoJPsiKa], keepEvent[kBtoJPsiKstar], keepEvent[kBtoJPsiPhi], keepEvent[kBtoJPsiPrKa], keepEvent[kBtoJPsiPi]); continue; } @@ -313,7 +413,16 @@ struct HfFilter { // Main struct for HF triggers if (setTPCCalib == 1) { helper.setTpcRecalibMaps(ccdb, bc, ccdbPathTPC); } else if (setTPCCalib > 1) { - helper.setValuesBB(ccdbApi, bc, std::array{ccdbBBPion.value, ccdbBBAntiPion.value, ccdbBBKaon.value, ccdbBBAntiKaon.value, ccdbBBProton.value, ccdbBBAntiProton.value}); + helper.setValuesBB(ccdbApi, bc, std::array{ccdbBBPion.value, ccdbBBAntiPion.value, ccdbBBKaon.value, ccdbBBAntiKaon.value, ccdbBBProton.value, ccdbBBAntiProton.value, ccdbBBProton.value, ccdbBBAntiProton.value}); // dummy for deuteron + } + + auto bz = o2::base::Propagator::Instance()->getNominalBz(); + dfStrangeness.setBz(bz); + df2.setBz(bz); + df3.setBz(bz); + if (activateSecVtxForB) { + dfB.setBz(bz); + dfBtoDstar.setBz(bz); } currentRun = bc.runNumber(); @@ -321,24 +430,26 @@ struct HfFilter { // Main struct for HF triggers hProcessedEvents->Fill(0); - std::vector> indicesDau2Prong{}; + std::vector> indicesDau2Prong{}, indicesDau2ProngPrompt{}; auto cand2ProngsThisColl = cand2Prongs.sliceBy(hf2ProngPerCollision, thisCollId); - for (const auto& cand2Prong : cand2ProngsThisColl) { // start loop over 2 prongs - if (!TESTBIT(cand2Prong.hfflag(), o2::aod::hf_cand_2prong::DecayType::D0ToPiK)) { // check if it's a D0 + for (const auto& cand2Prong : cand2ProngsThisColl) { // start loop over 2 prongs + + int8_t preselD0 = TESTBIT(cand2Prong.hfflag(), o2::aod::hf_cand_2prong::DecayType::D0ToPiK); // check if it's a D0 + int8_t preselJPsiToMuMu = TESTBIT(cand2Prong.hfflag(), o2::aod::hf_cand_2prong::DecayType::JpsiToMuMu); // check if it's a JPsi + if (preselD0 == 0 && preselJPsiToMuMu == 0) { continue; } - auto trackPos = cand2Prong.prong0_as(); // positive daughter - auto trackNeg = cand2Prong.prong1_as(); // negative daughter + auto trackPos = tracks.rawIteratorAt(cand2Prong.prong0Id()); // positive daughter + auto trackNeg = tracks.rawIteratorAt(cand2Prong.prong1Id()); // negative daughter - auto preselD0 = helper.isDzeroPreselected(trackPos, trackNeg); - if (!preselD0) { - continue; + if (preselD0) { + preselD0 = helper.isDzeroPreselected(trackPos, trackNeg); } - auto trackParPos = getTrackPar(trackPos); - auto trackParNeg = getTrackPar(trackNeg); + auto trackParPos = getTrackParCov(trackPos); + auto trackParNeg = getTrackParCov(trackNeg); o2::gpu::gpustd::array dcaPos{trackPos.dcaXY(), trackPos.dcaZ()}; o2::gpu::gpustd::array dcaNeg{trackNeg.dcaXY(), trackNeg.dcaZ()}; std::array pVecPos{trackPos.pVector()}; @@ -352,63 +463,88 @@ struct HfFilter { // Main struct for HF triggers getPxPyPz(trackParNeg, pVecNeg); } - // apply ML models + // apply ML models for D0 + bool isD0CharmTagged{false}, isD0BeautyTagged{false}, isD0SignalTagged{false}; std::vector scores{}; - scores.insert(scores.end(), cand2Prong.mlProbSkimD0ToKPi().begin(), cand2Prong.mlProbSkimD0ToKPi().end()); - if (scores.size() != 3) { - scores.resize(3); - scores[0] = 2.; - scores[1] = -1.; - scores[2] = -1.; - } - auto tagBDT = helper.isBDTSelected(scores, thresholdBDTScores[kD0]); - bool isCharmTagged = TESTBIT(tagBDT, RecoDecay::OriginType::Prompt); - bool isBeautyTagged = TESTBIT(tagBDT, RecoDecay::OriginType::NonPrompt); - bool isSignalTagged = acceptBdtBkgOnly ? TESTBIT(tagBDT, RecoDecay::OriginType::None) : (isCharmTagged || isBeautyTagged); - - if (activateQA > 1) { - hBDTScoreBkg[kD0]->Fill(scores[0]); - hBDTScorePrompt[kD0]->Fill(scores[1]); - hBDTScoreNonPrompt[kD0]->Fill(scores[2]); - } + if (preselD0) { + scores.insert(scores.end(), cand2Prong.mlProbSkimD0ToKPi().begin(), cand2Prong.mlProbSkimD0ToKPi().end()); + if (scores.size() != 3) { + scores.resize(3); + scores[0] = 2.; + scores[1] = -1.; + scores[2] = -1.; + } + auto tagBDT = helper.isBDTSelected(scores, thresholdBDTScores[kD0]); + isD0CharmTagged = TESTBIT(tagBDT, RecoDecay::OriginType::Prompt); + isD0BeautyTagged = TESTBIT(tagBDT, RecoDecay::OriginType::NonPrompt); + isD0SignalTagged = acceptBdtBkgOnly ? TESTBIT(tagBDT, RecoDecay::OriginType::None) : (isD0CharmTagged || isD0BeautyTagged); - if (!isSignalTagged) { - continue; + if (activateQA > 1) { + hBDTScoreBkg[kD0]->Fill(scores[0]); + hBDTScorePrompt[kD0]->Fill(scores[1]); + hBDTScoreNonPrompt[kD0]->Fill(scores[2]); + } } auto pVec2Prong = RecoDecay::pVec(pVecPos, pVecNeg); auto pt2Prong = RecoDecay::pt(pVec2Prong); - if (applyOptimisation) { - optimisationTreeCharm(thisCollId, o2::constants::physics::Pdg::kD0, pt2Prong, scores[0], scores[1], scores[2]); + if (preselJPsiToMuMu) { + float ptMuonMin = cutsBtoHadrons.cutsBtoJPsiX->get(0u, 0u); // assuming that the cut is looser in the first pT bin + auto ptPos = RecoDecay::pt(pVecPos); + auto ptNeg = RecoDecay::pt(pVecNeg); + if (ptPos < ptMuonMin || ptNeg < ptMuonMin) { + preselJPsiToMuMu = 0u; + } else { + auto massJPsiCand = RecoDecay::m(std::array{pVecPos, pVecNeg}, std::array{massMu, massMu}); + hMassVsPtC[kNCharmParticles + 18]->Fill(pt2Prong, massJPsiCand); + } } - auto selD0 = helper.isSelectedD0InMassRange(pVecPos, pVecNeg, pt2Prong, preselD0, activateQA, hMassVsPtC[kD0]); + if (!isD0SignalTagged && !preselJPsiToMuMu) { + continue; + } - if (helper.isSelectedHighPt2Prong(pt2Prong)) { - keepEvent[kHighPt2P] = true; - if (activateQA) { - hCharmHighPt[kD0]->Fill(pt2Prong); + int8_t selD0InMass{0}; + double massD0Cand{-1.}, massD0BarCand{-1.}; + if (isD0SignalTagged) { + // single D0 + keepEvent[kSingleCharm2P] = true; + if (isD0BeautyTagged) { + keepEvent[kSingleNonPromptCharm2P] = true; } - } // end high-pT selection - - if (isCharmTagged) { + // single D0 at high pT + if (helper.isSelectedHighPt2Prong(pt2Prong)) { + keepEvent[kHighPt2P] = true; + if (activateQA) { + hCharmHighPt[kD0]->Fill(pt2Prong); + } + } + // multi-charm selection indicesDau2Prong.push_back(std::vector{trackPos.globalIndex(), trackNeg.globalIndex()}); - } // end multi-charm selection + if (isD0CharmTagged) { + indicesDau2ProngPrompt.push_back(std::vector{trackPos.globalIndex(), trackNeg.globalIndex()}); + } - // compute masses already here, needed both for B0 --> D* (--> D0 Pi) Pi and Ds1 --> D* (--> D0 Pi) K0S - auto massD0Cand = RecoDecay::m(std::array{pVecPos, pVecNeg}, std::array{massPi, massKa}); - auto massD0BarCand = RecoDecay::m(std::array{pVecPos, pVecNeg}, std::array{massKa, massPi}); + if (applyOptimisation) { + optimisationTreeCharm(thisCollId, o2::constants::physics::Pdg::kD0, pt2Prong, scores[0], scores[1], scores[2]); + } + selD0InMass = helper.isSelectedD0InMassRange(pVecPos, pVecNeg, pt2Prong, preselD0, activateQA, hMassVsPtC[kD0]); + // compute masses already here, needed both for B0 --> D* (--> D0 Pi) Pi and Ds1 --> D* (--> D0 Pi) K0S + massD0Cand = RecoDecay::m(std::array{pVecPos, pVecNeg}, std::array{massPi, massKa}); + massD0BarCand = RecoDecay::m(std::array{pVecPos, pVecNeg}, std::array{massKa, massPi}); + } auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + auto tracksWithItsPid = soa::Attach(tracks); for (const auto& trackId : trackIdsThisCollision) { // start loop over tracks - auto track = trackId.track_as(); + auto track = tracksWithItsPid.rawIteratorAt(trackId.trackId()); if (track.globalIndex() == trackPos.globalIndex() || track.globalIndex() == trackNeg.globalIndex()) { continue; } - auto trackParThird = getTrackPar(track); + auto trackParThird = getTrackParCov(track); o2::gpu::gpustd::array dcaThird{track.dcaXY(), track.dcaZ()}; std::array pVecThird = track.pVector(); if (track.collisionId() != thisCollId) { @@ -416,62 +552,167 @@ struct HfFilter { // Main struct for HF triggers getPxPyPz(trackParThird, pVecThird); } - if (!keepEvent[kBeauty3P] && isBeautyTagged) { - auto isTrackSelected = helper.isSelectedTrackForSoftPionOrBeauty(track, trackParThird, dcaThird, kBeauty3P); - if (isTrackSelected && ((TESTBIT(selD0, 0) && track.sign() < 0) || (TESTBIT(selD0, 1) && track.sign() > 0))) { - auto massCand = RecoDecay::m(std::array{pVec2Prong, pVecThird}, std::array{massD0, massPi}); + // Beauty with D0 + if (!keepEvent[kBeauty3P] && isD0BeautyTagged) { + int16_t isTrackSelected = helper.isSelectedTrackForSoftPionOrBeauty(track, trackParThird, dcaThird); + if (TESTBIT(isTrackSelected, kForBeauty) && ((TESTBIT(selD0InMass, 0) && track.sign() < 0) || (TESTBIT(selD0InMass, 1) && track.sign() > 0))) { // D0 pi-/K- and D0bar pi+/K+ + auto massCandD0Pi = RecoDecay::m(std::array{pVec2Prong, pVecThird}, std::array{massD0, massPi}); + auto massCandD0K = RecoDecay::m(std::array{pVec2Prong, pVecThird}, std::array{massD0, massKa}); auto pVecBeauty3Prong = RecoDecay::pVec(pVec2Prong, pVecThird); auto ptCand = RecoDecay::pt(pVecBeauty3Prong); - if (TESTBIT(isTrackSelected, kForBeauty) && std::fabs(massCand - massBPlus) <= deltaMassBeauty->get(0u, 0u)) { - keepEvent[kBeauty3P] = true; - // fill optimisation tree for D0 - if (applyOptimisation) { - optimisationTreeBeauty(thisCollId, o2::constants::physics::Pdg::kD0, pt2Prong, scores[0], scores[1], scores[2], dcaThird[0]); - } + bool isBplusInMass = helper.isSelectedBhadronInMassRange(ptCand, massCandD0Pi, kBplus); + bool isBcInMass = helper.isSelectedBhadronInMassRange(ptCand, massCandD0K, kBc); + + if (TESTBIT(isTrackSelected, kForBeauty) && (isBplusInMass || isBcInMass)) { if (activateQA) { - hMassVsPtB[kBplus]->Fill(ptCand, massCand); - } - } else if (TESTBIT(isTrackSelected, kSoftPionForBeauty)) { - std::array massDausD0{massPi, massKa}; - auto massD0dau = massD0Cand; - if (track.sign() < 0) { - massDausD0[0] = massKa; - massDausD0[1] = massPi; - massD0dau = massD0BarCand; + if (isBplusInMass) + registry.fill(HIST("fHfVtxStages"), 1 + HfVtxStage::Skimmed, kBplus); + if (isBcInMass) + registry.fill(HIST("fHfVtxStages"), 1 + HfVtxStage::Skimmed, kBc); } - auto massDstarCand = RecoDecay::m(std::array{pVecPos, pVecNeg, pVecThird}, std::array{massDausD0[0], massDausD0[1], massPi}); - auto massDiffDstar = massDstarCand - massD0dau; - if (cutsPtDeltaMassCharmReso->get(0u, 0u) <= massDiffDstar && massDiffDstar <= cutsPtDeltaMassCharmReso->get(1u, 0u) && ptCand > cutsPtDeltaMassCharmReso->get(2u, 0u)) { // additional check for B0->D*pi polarization studies + if (!activateSecVtxForB) { + keepEvent[kBeauty3P] = true; + // fill optimisation tree for D0 + if (applyOptimisation) { + optimisationTreeBeauty(thisCollId, o2::constants::physics::Pdg::kD0, pt2Prong, scores[0], scores[1], scores[2], dcaThird[0]); + } if (activateQA) { - hMassVsPtC[kNCharmParticles]->Fill(ptCand, massDiffDstar); + if (isBplusInMass) + hMassVsPtB[kBplus]->Fill(ptCand, massCandD0Pi); + if (isBcInMass) + hMassVsPtB[kBc]->Fill(ptCand, massCandD0K); } - for (const auto& trackIdB : trackIdsThisCollision) { // start loop over tracks - auto trackB = trackIdB.track_as(); - if (track.globalIndex() == trackB.globalIndex()) { - continue; + } else { + df2.process(trackParPos, trackParNeg); + df2.propagateTracksToVertex(); + std::array pVecPosVtx{}, pVecNegVtx{}; + df2.getTrack(0).getPxPyPzGlo(pVecPosVtx); + df2.getTrack(1).getPxPyPzGlo(pVecNegVtx); + auto trackParD = df2.createParentTrackParCov(); + trackParD.setAbsCharge(0); // to be sure + auto pVec2ProngVtx = RecoDecay::pVec(pVecPosVtx, pVecNegVtx); + if (dfB.process(trackParD, trackParThird) != 0) { + if (activateQA) { + registry.fill(HIST("fHfVtxStages"), 1 + HfVtxStage::BeautyVertex, kBplus); } - auto trackParFourth = getTrackPar(trackB); - o2::gpu::gpustd::array dcaFourth{trackB.dcaXY(), trackB.dcaZ()}; - std::array pVecFourth = trackB.pVector(); - if (trackB.collisionId() != thisCollId) { - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParFourth, 2.f, noMatCorr, &dcaFourth); - getPxPyPz(trackParFourth, pVecFourth); + dfB.propagateTracksToVertex(); + const auto& secondaryVertexBtoD0h = dfB.getPCACandidate(); + std::array pVecThirdVtx{}; + dfB.getTrack(0).getPxPyPzGlo(pVec2ProngVtx); + dfB.getTrack(1).getPxPyPzGlo(pVecThirdVtx); + o2::gpu::gpustd::array dca2Prong; //{trackParD.dcaXY(), trackParD.dcaZ()}; + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParD, 2.f, noMatCorr, &dca2Prong); + bool isBplus = helper.isSelectedBhadron(pVec2ProngVtx, pVecThirdVtx, dca2Prong, dcaThird, std::array{static_cast(collision.posX()), static_cast(collision.posY()), static_cast(collision.posZ())}, std::array{secondaryVertexBtoD0h[0], secondaryVertexBtoD0h[1], secondaryVertexBtoD0h[2]}, kBplus); + bool isBc = helper.isSelectedBhadron(pVec2ProngVtx, pVecThirdVtx, dca2Prong, dcaThird, std::array{static_cast(collision.posX()), static_cast(collision.posY()), static_cast(collision.posZ())}, std::array{secondaryVertexBtoD0h[0], secondaryVertexBtoD0h[1], secondaryVertexBtoD0h[2]}, kBc); + + if (isBplus || isBc) { + keepEvent[kBeauty3P] = true; + // fill optimisation tree for D0 + if (applyOptimisation) { + optimisationTreeBeauty(thisCollId, o2::constants::physics::Pdg::kD0, pt2Prong, scores[0], scores[1], scores[2], dcaThird[0]); + } + if (activateQA) { + if (isBplus) { + registry.fill(HIST("fHfVtxStages"), 1 + HfVtxStage::CharmHadPiSelected, kBplus); + hCpaVsPtB[kBplus]->Fill(ptCand, RecoDecay::cpa(std::array{static_cast(collision.posX()), static_cast(collision.posY()), static_cast(collision.posZ())}, std::array{secondaryVertexBtoD0h[0], secondaryVertexBtoD0h[1], secondaryVertexBtoD0h[2]}, RecoDecay::pVec(pVec2ProngVtx, pVecThirdVtx))); + hDecayLengthVsPtB[kBplus]->Fill(ptCand, RecoDecay::distance(std::array{static_cast(collision.posX()), static_cast(collision.posY()), static_cast(collision.posZ())}, std::array{secondaryVertexBtoD0h[0], secondaryVertexBtoD0h[1], secondaryVertexBtoD0h[2]})); + hImpactParamProductVsPtB[kBplus]->Fill(ptCand, dca2Prong[0] * dcaThird[0]); + hMassVsPtB[kBplus]->Fill(ptCand, massCandD0Pi); + } + if (isBc) { + registry.fill(HIST("fHfVtxStages"), 1 + HfVtxStage::CharmHadPiSelected, kBc); + hCpaVsPtB[kBc]->Fill(ptCand, RecoDecay::cpa(std::array{static_cast(collision.posX()), static_cast(collision.posY()), static_cast(collision.posZ())}, std::array{secondaryVertexBtoD0h[0], secondaryVertexBtoD0h[1], secondaryVertexBtoD0h[2]}, RecoDecay::pVec(pVec2ProngVtx, pVecThirdVtx))); + hDecayLengthVsPtB[kBc]->Fill(ptCand, RecoDecay::distance(std::array{static_cast(collision.posX()), static_cast(collision.posY()), static_cast(collision.posZ())}, std::array{secondaryVertexBtoD0h[0], secondaryVertexBtoD0h[1], secondaryVertexBtoD0h[2]})); + hImpactParamProductVsPtB[kBc]->Fill(ptCand, dca2Prong[0] * dcaThird[0]); + hMassVsPtB[kBc]->Fill(ptCand, massCandD0K); + } + } } + } + } + } + } + if (!keepEvent[kBeauty3P] && TESTBIT(isTrackSelected, kSoftPionForBeauty) && ((TESTBIT(selD0InMass, 0) && track.sign() > 0) || (TESTBIT(selD0InMass, 1) && track.sign() < 0))) { // D0 pi+ and D0bar pi- + auto pVecBeauty3Prong = RecoDecay::pVec(pVec2Prong, pVecThird); + auto ptCand = RecoDecay::pt(pVecBeauty3Prong); + std::array massDausD0{massPi, massKa}; + auto massD0dau = massD0Cand; + if (track.sign() < 0) { + massDausD0[0] = massKa; + massDausD0[1] = massPi; + massD0dau = massD0BarCand; + } + auto massDstarCand = RecoDecay::m(std::array{pVecPos, pVecNeg, pVecThird}, std::array{massDausD0[0], massDausD0[1], massPi}); + auto massDiffDstar = massDstarCand - massD0dau; + if (cutsPtDeltaMassCharmReso->get(0u, 0u) <= massDiffDstar && massDiffDstar <= cutsPtDeltaMassCharmReso->get(1u, 0u) && ptCand > cutsPtDeltaMassCharmReso->get(2u, 0u)) { // additional check for B0->D*pi polarization studies + if (activateQA) { + hMassVsPtC[kNCharmParticles]->Fill(ptCand, massDiffDstar); + } + for (const auto& trackIdB : trackIdsThisCollision) { // start loop over tracks + auto trackB = tracks.rawIteratorAt(trackIdB.trackId()); + if (track.globalIndex() == trackB.globalIndex()) { + continue; + } + auto trackParFourth = getTrackParCov(trackB); + o2::gpu::gpustd::array dcaFourth{trackB.dcaXY(), trackB.dcaZ()}; + std::array pVecFourth = trackB.pVector(); + if (trackB.collisionId() != thisCollId) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParFourth, 2.f, noMatCorr, &dcaFourth); + getPxPyPz(trackParFourth, pVecFourth); + } - auto isTrackFourthSelected = helper.isSelectedTrackForSoftPionOrBeauty(trackB, trackParFourth, dcaFourth, kBeauty3P); - if (track.sign() * trackB.sign() < 0 && TESTBIT(isTrackFourthSelected, kForBeauty)) { - auto massCandB0 = RecoDecay::m(std::array{pVecBeauty3Prong, pVecFourth}, std::array{massDStar, massPi}); - if (std::fabs(massCandB0 - massB0) <= deltaMassBeauty->get(0u, 2u)) { + auto isTrackFourthSelected = helper.isSelectedTrackForSoftPionOrBeauty(trackB, trackParFourth, dcaFourth); + if (track.sign() * trackB.sign() < 0 && TESTBIT(isTrackFourthSelected, kForBeauty)) { + auto massCandB0 = RecoDecay::m(std::array{pVecBeauty3Prong, pVecFourth}, std::array{massDStar, massPi}); + auto pVecBeauty4Prong = RecoDecay::pVec(pVec2Prong, pVecThird, pVecFourth); + auto ptCandBeauty4Prong = RecoDecay::pt(pVecBeauty4Prong); + if (helper.isSelectedBhadronInMassRange(ptCandBeauty4Prong, massCandB0, kB0toDStar)) { + if (activateQA) { + registry.fill(HIST("fHfVtxStages"), 1 + HfVtxStage::Skimmed, kB0toDStar); + } + if (!activateSecVtxForB) { keepEvent[kBeauty3P] = true; - // fill optimisation tree for D0 + // fill optimisation tree for D* if (applyOptimisation) { optimisationTreeBeauty(thisCollId, 413, pt2Prong, scores[0], scores[1], scores[2], dcaFourth[0]); // pdgCode of D*(2010)+: 413 } if (activateQA) { - auto pVecBeauty4Prong = RecoDecay::pVec(pVec2Prong, pVecThird, pVecFourth); - auto ptCandBeauty4Prong = RecoDecay::pt(pVecBeauty4Prong); hMassVsPtB[kB0toDStar]->Fill(ptCandBeauty4Prong, massCandB0); } + } else { + df2.process(trackParPos, trackParNeg); + df2.propagateTracksToVertex(); + std::array pVecPosVtx{}, pVecNegVtx{}; + df2.getTrack(0).getPxPyPzGlo(pVecPosVtx); + df2.getTrack(1).getPxPyPzGlo(pVecNegVtx); + auto trackParD = df2.createParentTrackParCov(); + trackParD.setAbsCharge(0); // to be sure + auto pVec2ProngVtx = RecoDecay::pVec(pVecPosVtx, pVecNegVtx); + if (dfBtoDstar.process(trackParD, trackParThird, trackParFourth) != 0) { + if (activateQA) { + registry.fill(HIST("fHfVtxStages"), 1 + HfVtxStage::BeautyVertex, kB0toDStar); + } + dfBtoDstar.propagateTracksToVertex(); + const auto& secondaryVertexBzero = dfBtoDstar.getPCACandidate(); + std::array pVecThirdVtx{}, pVecFourthVtx{}; + dfBtoDstar.getTrack(0).getPxPyPzGlo(pVec2ProngVtx); + dfBtoDstar.getTrack(1).getPxPyPzGlo(pVecThirdVtx); + dfBtoDstar.getTrack(2).getPxPyPzGlo(pVecFourthVtx); + bool isBzero = helper.isSelectedBzeroToDstar(pVec2ProngVtx, pVecThirdVtx, pVecFourthVtx, std::array{static_cast(collision.posX()), static_cast(collision.posY()), static_cast(collision.posZ())}, std::array{secondaryVertexBzero[0], secondaryVertexBzero[1], secondaryVertexBzero[2]}); + if (isBzero) { + keepEvent[kBeauty3P] = true; + // fill optimisation tree for D0 + if (applyOptimisation) { + optimisationTreeBeauty(thisCollId, 413, pt2Prong, scores[0], scores[1], scores[2], dcaFourth[0]); // pdgCode of D*(2010)+: 413 + } + if (activateQA) { + registry.fill(HIST("fHfVtxStages"), 1 + HfVtxStage::CharmHadPiSelected, kB0toDStar); + hCpaVsPtB[kB0toDStar]->Fill(ptCandBeauty4Prong, RecoDecay::cpa(std::array{static_cast(collision.posX()), static_cast(collision.posY()), static_cast(collision.posZ())}, std::array{secondaryVertexBzero[0], secondaryVertexBzero[1], secondaryVertexBzero[2]}, RecoDecay::pVec(pVec2ProngVtx, pVecThirdVtx, pVecFourthVtx))); + hDecayLengthVsPtB[kB0toDStar]->Fill(ptCandBeauty4Prong, RecoDecay::distance(std::array{static_cast(collision.posX()), static_cast(collision.posY()), static_cast(collision.posZ())}, std::array{secondaryVertexBzero[0], secondaryVertexBzero[1], secondaryVertexBzero[2]})); + hMassVsPtB[kB0toDStar]->Fill(ptCandBeauty4Prong, massCandB0); + } + } + } } } } @@ -481,12 +722,12 @@ struct HfFilter { // Main struct for HF triggers } // end beauty selection // 2-prong femto - if (!keepEvent[kFemto2P] && enableFemtoChannels->get(0u, 0u) && isCharmTagged && track.collisionId() == thisCollId && (TESTBIT(selD0, 0) || TESTBIT(selD0, 1) || !requireCharmMassForFemto)) { - bool isProton = helper.isSelectedProton4Femto(track, trackParThird, activateQA, hProtonTPCPID, hProtonTOFPID, forceTofPidForFemto); + if (!keepEvent[kFemto2P] && enableFemtoChannels->get(0u, 0u) && isD0CharmTagged && track.collisionId() == thisCollId) { + bool isProton = helper.isSelectedTrack4Femto(track, trackParThird, activateQA, hPrDePID[0], hPrDePID[1], kProtonForFemto); if (isProton) { float relativeMomentum = helper.computeRelativeMomentum(pVecThird, pVec2Prong, massD0); if (applyOptimisation) { - optimisationTreeFemto(thisCollId, o2::constants::physics::Pdg::kD0, pt2Prong, scores[0], scores[1], scores[2], relativeMomentum, track.tpcNSigmaPr(), track.tofNSigmaPr()); + optimisationTreeFemto(thisCollId, o2::constants::physics::Pdg::kD0, pt2Prong, scores[0], scores[1], scores[2], relativeMomentum, track.tpcNSigmaPr(), track.tofNSigmaPr(), track.tpcNSigmaDe(), track.tofNSigmaDe()); } if (relativeMomentum < femtoMaxRelativeMomentum) { keepEvent[kFemto2P] = true; @@ -497,10 +738,74 @@ struct HfFilter { // Main struct for HF triggers } } // end femto selection + // Beauty with JPsi + if (preselJPsiToMuMu) { + if (!TESTBIT(helper.isSelectedTrackForSoftPionOrBeauty(track, trackParThird, dcaThird), kForBeauty)) { // same for all channels + continue; + } + std::array pVecPosVtx{}, pVecNegVtx{}, pVecThirdVtx{}, pVecFourthVtx{}; + // 3-prong vertices + if (!keepEvent[kBtoJPsiKa] || !keepEvent[kBtoJPsiPi]) { + if (df3.process(trackParPos, trackParNeg, trackParThird) != 0) { + df3.propagateTracksToVertex(); + const auto& secondaryVertexBto3tracks = df3.getPCACandidate(); + df3.getTrack(0).getPxPyPzGlo(pVecPosVtx); + df3.getTrack(1).getPxPyPzGlo(pVecNegVtx); + df3.getTrack(2).getPxPyPzGlo(pVecThirdVtx); + auto isBhadSel = helper.isSelectedBhadronToJPsi<3>(std::array{pVecPosVtx, pVecNegVtx, pVecThirdVtx}, std::array{track}, std::array{static_cast(collision.posX()), static_cast(collision.posY()), static_cast(collision.posZ())}, std::array{secondaryVertexBto3tracks[0], secondaryVertexBto3tracks[1], secondaryVertexBto3tracks[2]}, activateQA, hMassVsPtB); + if (TESTBIT(isBhadSel, kBplusToJPsi)) { + keepEvent[kBtoJPsiKa] = true; + } + if (TESTBIT(isBhadSel, kBcToJPsi)) { + keepEvent[kBtoJPsiPi] = true; + } + } + } + // 4-prong vertices + if (!keepEvent[kBtoJPsiKstar] || !keepEvent[kBtoJPsiPhi] || !keepEvent[kBtoJPsiPrKa]) { + for (const auto& trackIdB : trackIdsThisCollision) { // start loop over tracks + if (keepEvent[kBtoJPsiKstar] && keepEvent[kBtoJPsiPhi] && keepEvent[kBtoJPsiPrKa]) { + break; + } + auto trackFourth = tracksWithItsPid.rawIteratorAt(trackIdB.trackId()); + if (trackFourth.globalIndex() == track.globalIndex() || trackFourth.globalIndex() == trackPos.globalIndex() || trackFourth.globalIndex() == trackNeg.globalIndex() || trackFourth.sign() * track.sign() > 0) { + continue; + } + auto trackParFourth = getTrackParCov(trackFourth); + o2::gpu::gpustd::array dcaFourth{trackFourth.dcaXY(), trackFourth.dcaZ()}; + std::array pVecFourth = trackFourth.pVector(); + if (trackFourth.collisionId() != thisCollId) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParFourth, 2.f, noMatCorr, &dcaFourth); + getPxPyPz(trackParFourth, pVecFourth); + } + if (!TESTBIT(helper.isSelectedTrackForSoftPionOrBeauty(trackFourth, trackParFourth, dcaFourth), kForBeauty)) { // same for all channels + continue; + } + if (df4.process(trackParPos, trackParNeg, trackParThird, trackParFourth) != 0) { + df4.propagateTracksToVertex(); + const auto& secondaryVertexBto4tracks = df4.getPCACandidate(); + df4.getTrack(0).getPxPyPzGlo(pVecPosVtx); + df4.getTrack(1).getPxPyPzGlo(pVecNegVtx); + df4.getTrack(2).getPxPyPzGlo(pVecThirdVtx); + df4.getTrack(3).getPxPyPzGlo(pVecFourthVtx); + auto isBhadSel = helper.isSelectedBhadronToJPsi<4>(std::array{pVecPosVtx, pVecNegVtx, pVecThirdVtx, pVecFourthVtx}, std::array{track, trackFourth}, std::array{static_cast(collision.posX()), static_cast(collision.posY()), static_cast(collision.posZ())}, std::array{secondaryVertexBto4tracks[0], secondaryVertexBto4tracks[1], secondaryVertexBto4tracks[2]}, activateQA, hMassVsPtB); + if (TESTBIT(isBhadSel, kB0ToJPsi)) { + keepEvent[kBtoJPsiKstar] = true; + } + if (TESTBIT(isBhadSel, kBsToJPsi)) { + keepEvent[kBtoJPsiPhi] = true; + } + if (TESTBIT(isBhadSel, kLbToJPsi)) { + keepEvent[kBtoJPsiPrKa] = true; + } + } + } + } + } } // end loop over tracks // 2-prong with Gamma (conversion photon) - if (!keepEvent[kPhotonCharm2P] && isSignalTagged && (TESTBIT(selD0, 0) || TESTBIT(selD0, 1))) { + if (!keepEvent[kPhotonCharm2P] && isD0SignalTagged && (TESTBIT(selD0InMass, 0) || TESTBIT(selD0InMass, 1))) { auto photonsThisCollision = photons.sliceBy(photonsPerCollision, thisCollId); for (const auto& photon : photonsThisCollision) { auto posTrack = photon.posTrack_as(); @@ -521,11 +826,11 @@ struct HfFilter { // Main struct for HF triggers auto pVecReso2Prong = RecoDecay::pVec(pVec2Prong, pVecPhoton); auto ptCand = RecoDecay::pt(pVecReso2Prong); if (ptCand > cutsPtDeltaMassCharmReso->get(2u, 1u)) { - if (TESTBIT(selD0, 0)) { + if (TESTBIT(selD0InMass, 0)) { massDStarCand = RecoDecay::m(std::array{pVecPos, pVecNeg, pVecPhoton}, std::array{massPi, massKa, massGamma}); massDiffDstar = massDStarCand - massD0Cand; } - if (TESTBIT(selD0, 1)) { + if (TESTBIT(selD0InMass, 1)) { massDStarBarCand = RecoDecay::m(std::array{pVecPos, pVecNeg, pVecPhoton}, std::array{massKa, massPi, massGamma}); massDiffDstarBar = massDStarBarCand - massD0BarCand; } @@ -549,33 +854,24 @@ struct HfFilter { // Main struct for HF triggers } // 2-prong with K0S or Lambda - if (!keepEvent[kV0Charm2P] && isSignalTagged && (TESTBIT(selD0, 0) || TESTBIT(selD0, 1))) { + if (!keepEvent[kV0Charm2P] && isD0SignalTagged && (TESTBIT(selD0InMass, 0) || TESTBIT(selD0InMass, 1))) { auto v0sThisCollision = v0s.sliceBy(v0sPerCollision, thisCollId); for (const auto& v0 : v0sThisCollision) { - auto posTrack = v0.posTrack_as(); - auto negTrack = v0.negTrack_as(); - auto selV0 = helper.isSelectedV0(v0, std::array{posTrack, negTrack}, collision, activateQA, hV0Selected, hArmPod); + V0Cand v0Cand; + if (!helper.buildV0(v0, tracksIU, collision, dfStrangeness, std::vector{cand2Prong.prong0Id(), cand2Prong.prong1Id()}, v0Cand)) { + continue; + } + auto selV0 = helper.isSelectedV0(v0Cand, activateQA, hV0Selected, hArmPod); if (!selV0) { continue; } - // propagate to PV - gpu::gpustd::array dcaInfo; - std::array pVecV0 = {v0.px(), v0.py(), v0.pz()}; - std::array pVecV0Orig = {v0.px(), v0.py(), v0.pz()}; - std::array posVecV0 = {v0.x(), v0.y(), v0.z()}; if (!keepEvent[kV0Charm2P] && TESTBIT(selV0, kK0S)) { - auto trackParK0 = o2::track::TrackPar(posVecV0, pVecV0Orig, 0, true); - trackParK0.setPID(o2::track::PID::K0); - trackParK0.setAbsCharge(0); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParK0, 2.f, matCorr, &dcaInfo); - getPxPyPz(trackParK0, pVecV0); - // we first look for a D*+ for (const auto& trackBachelorId : trackIdsThisCollision) { // start loop over tracks - auto trackBachelor = trackBachelorId.track_as(); - if (trackBachelor.globalIndex() == trackPos.globalIndex() || trackBachelor.globalIndex() == trackNeg.globalIndex()) { + auto trackBachelor = tracks.rawIteratorAt(trackBachelorId.trackId()); + if (trackBachelor.globalIndex() == trackPos.globalIndex() || trackBachelor.globalIndex() == trackNeg.globalIndex() || trackBachelor.globalIndex() == v0.posTrackId() || trackBachelor.globalIndex() == v0.negTrackId()) { continue; } @@ -587,8 +883,8 @@ struct HfFilter { // Main struct for HF triggers getPxPyPz(trackParBachelor, pVecBachelor); } - int isTrackSelected = helper.isSelectedTrackForSoftPionOrBeauty(trackBachelor, trackParBachelor, dcaBachelor, -1); - if (TESTBIT(isTrackSelected, kSoftPion) && ((TESTBIT(selD0, 0) && trackBachelor.sign() < 0) || (TESTBIT(selD0, 1) && trackBachelor.sign() > 0))) { + auto isTrackSelected = helper.isSelectedTrackForSoftPionOrBeauty(trackBachelor, trackParBachelor, dcaBachelor); + if (TESTBIT(isTrackSelected, kSoftPion) && ((TESTBIT(selD0InMass, 0) && trackBachelor.sign() > 0) || (TESTBIT(selD0InMass, 1) && trackBachelor.sign() < 0))) { std::array massDausD0{massPi, massKa}; auto massD0dau = massD0Cand; if (trackBachelor.sign() < 0) { @@ -606,10 +902,10 @@ struct HfFilter { // Main struct for HF triggers if (activateQA) { hMassVsPtC[kNCharmParticles]->Fill(ptDStarCand, massDiffDstar); } - auto pVecReso2Prong = RecoDecay::pVec(pVecDStarCand, pVecV0); + auto pVecReso2Prong = RecoDecay::pVec(pVecDStarCand, v0Cand.mom); auto ptCand = RecoDecay::pt(pVecReso2Prong); if (ptCand > cutsPtDeltaMassCharmReso->get(2u, 3u)) { - auto massDStarK0S = RecoDecay::m(std::array{pVecPos, pVecNeg, pVecBachelor, pVecV0}, std::array{massDausD0[0], massDausD0[1], massPi, massK0S}); + auto massDStarK0S = RecoDecay::m(std::array{pVecPos, pVecNeg, pVecBachelor, v0Cand.mom}, std::array{massDausD0[0], massDausD0[1], massPi, massK0S}); auto massDiffDsReso = massDStarK0S - massDStarCand; if (cutsPtDeltaMassCharmReso->get(0u, 3u) < massDiffDsReso && massDiffDsReso < cutsPtDeltaMassCharmReso->get(1u, 3u)) { if (activateQA) { @@ -625,24 +921,19 @@ struct HfFilter { // Main struct for HF triggers } } if (!keepEvent[kV0Charm2P] && (TESTBIT(selV0, kLambda) || TESTBIT(selV0, kAntiLambda))) { // Xic(3055) and Xic(3080) --> since it occupies only a small bandwidth, we might want to keep also wrong sign pairs - auto trackParLambda = o2::track::TrackPar(posVecV0, pVecV0Orig, 0, true); - trackParLambda.setAbsCharge(0); - trackParLambda.setPID(o2::track::PID::Lambda); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParLambda, 2.f, matCorr, &dcaInfo); - getPxPyPz(trackParLambda, pVecV0); float massXicStarCand{-999.}, massXicStarBarCand{-999.}; float massDiffXicStarCand{-999.}, massDiffXicStarBarCand{-999.}; bool isRightSignXicStar{false}, isRightSignXicStarBar{false}; - auto pVecReso2Prong = RecoDecay::pVec(pVec2Prong, pVecV0); + auto pVecReso2Prong = RecoDecay::pVec(pVec2Prong, v0Cand.mom); auto ptCand = RecoDecay::pt(pVecReso2Prong); if (ptCand > cutsPtDeltaMassCharmReso->get(2u, 5u)) { - if (TESTBIT(selD0, 0)) { - massXicStarCand = RecoDecay::m(std::array{pVecPos, pVecNeg, pVecV0}, std::array{massPi, massKa, massLambda}); + if (TESTBIT(selD0InMass, 0)) { + massXicStarCand = RecoDecay::m(std::array{pVecPos, pVecNeg, v0Cand.mom}, std::array{massPi, massKa, massLambda}); massDiffXicStarCand = massXicStarCand - massD0Cand; isRightSignXicStar = TESTBIT(selV0, kLambda); // right sign if Lambda } - if (TESTBIT(selD0, 1)) { - massXicStarBarCand = RecoDecay::m(std::array{pVecPos, pVecNeg, pVecV0}, std::array{massKa, massPi, massLambda}); + if (TESTBIT(selD0InMass, 1)) { + massXicStarBarCand = RecoDecay::m(std::array{pVecPos, pVecNeg, v0Cand.mom}, std::array{massKa, massPi, massLambda}); massDiffXicStarBarCand = massXicStarBarCand - massD0BarCand; isRightSignXicStarBar = TESTBIT(selV0, kAntiLambda); // right sign if AntiLambda } @@ -674,9 +965,160 @@ struct HfFilter { // Main struct for HF triggers } } // end V0 selection + // 2-prong (D0 or D*) with proton for Lc resonances and ThetaC (3100) + if (!keepEvent[kPrCharm2P] && isD0SignalTagged && (TESTBIT(selD0InMass, 0) || TESTBIT(selD0InMass, 1))) { + for (const auto& trackProtonId : trackIdsThisCollision) { // start loop over tracks selecting only protons + auto trackProton = tracks.rawIteratorAt(trackProtonId.trackId()); + auto trackParBachelorProton = getTrackPar(trackProton); + if (trackProton.globalIndex() == trackPos.globalIndex() || trackProton.globalIndex() == trackNeg.globalIndex()) { + continue; + } + gpu::gpustd::array dcaInfoBachProton; + if (trackProton.collisionId() != thisCollId) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParBachelorProton, 2.f, noMatCorr, &dcaInfoBachProton); + } + std::array pVecProton = trackProton.pVector(); + bool isSelPIDProton = helper.isSelectedProton4CharmOrBeautyBaryons(trackProton); + if (isSelPIDProton) { + if (!keepEvent[kPrCharm2P]) { + // we first look for a D*+ + for (const auto& trackBachelorId : trackIdsThisCollision) { // start loop over tracks to find bachelor pion + if (!helper.isSelectedProtonFromLcResoOrThetaC(trackProton)) { + continue; + } // stop here if proton below pT threshold for thetaC to avoid computational losses + auto trackBachelor = tracks.rawIteratorAt(trackBachelorId.trackId()); + if (trackBachelor.globalIndex() == trackPos.globalIndex() || trackBachelor.globalIndex() == trackNeg.globalIndex() || trackBachelor.globalIndex() == trackProton.globalIndex()) { + continue; + } + auto trackParBachelor = getTrackPar(trackBachelor); + o2::gpu::gpustd::array dcaBachelor{trackBachelor.dcaXY(), trackBachelor.dcaZ()}; + std::array pVecBachelor = trackBachelor.pVector(); + if (trackBachelor.collisionId() != thisCollId) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParBachelor, 2.f, noMatCorr, &dcaBachelor); + getPxPyPz(trackParBachelor, pVecBachelor); + } + auto isTrackSelected = helper.isSelectedTrackForSoftPionOrBeauty(trackBachelor, trackParBachelor, dcaBachelor); + if (TESTBIT(isTrackSelected, kSoftPion) && ((TESTBIT(selD0InMass, 0) && trackBachelor.sign() > 0) || (TESTBIT(selD0InMass, 1) && trackBachelor.sign() < 0))) { + if (pt2Prong < cutsPtDeltaMassCharmReso->get(3u, 12u)) { + continue; + } + std::array massDausD0{massPi, massKa}; + auto massD0dau = massD0Cand; + if (trackBachelor.sign() < 0) { + massDausD0[0] = massKa; + massDausD0[1] = massPi; + massD0dau = massD0BarCand; + } + auto pVecDStarCand = RecoDecay::pVec(pVec2Prong, pVecBachelor); + auto ptDStarCand = RecoDecay::pt(pVecDStarCand); + double massDStarCand{-999.}, massDiffDstar{-999.}; + if (ptDStarCand > cutsPtDeltaMassCharmReso->get(2u, 0u)) { + massDStarCand = RecoDecay::m(std::array{pVecPos, pVecNeg, pVecBachelor}, std::array{massDausD0[0], massDausD0[1], massPi}); + massDiffDstar = massDStarCand - massD0dau; + if (cutsPtDeltaMassCharmReso->get(0u, 0u) <= massDiffDstar && massDiffDstar <= cutsPtDeltaMassCharmReso->get(1u, 0u)) { + if (activateQA) { // probably this is not needed, since already performed for the Xic (duplicate) + hMassVsPtC[kNCharmParticles]->Fill(ptDStarCand, massDiffDstar); + } + auto pVecReso2Prong = RecoDecay::pVec(pVecDStarCand, pVecProton); + auto ptCand = RecoDecay::pt(pVecReso2Prong); + if (ptCand > cutsPtDeltaMassCharmReso->get(2u, 12u)) { + // build D*0p candidate with the possibility of storing also the other sign hyp. + float massThetacCand{-999.}, massThetacBarCand{-999.}; + float massDiffThetacCand{-999.}, massDiffThetacBarCand{-999.}; + bool isRightSignThetaC{false}, isRightSignThetaCBar{false}; + if (TESTBIT(selD0InMass, 1)) { // Correct hyp: ThetaC -> pD*- -> D0bar\pi- (Equivalent to trackBachelor.sign() < 0) + massThetacCand = RecoDecay::m(std::array{pVecPos, pVecNeg, pVecBachelor, pVecProton}, std::array{massDausD0[0], massDausD0[1], massPi, massProton}); + massDiffThetacCand = massThetacCand - massDStarCand; + isRightSignThetaC = trackProton.sign() > 0; // right sign if proton + } + if (TESTBIT(selD0InMass, 0)) { // Correct hyp: ThetaCbar -> pD*+ -> pD0\pi+ (Equivalent to trackBachelor.sign() > 0) + massThetacBarCand = RecoDecay::m(std::array{pVecPos, pVecNeg, pVecBachelor, pVecProton}, std::array{massDausD0[0], massDausD0[1], massPi, massProton}); + massDiffThetacBarCand = massThetacBarCand - massDStarCand; + isRightSignThetaCBar = trackProton.sign() < 0; // right sign if antiproton + } + bool isGoodThetac = (cutsPtDeltaMassCharmReso->get(0u, 12u) < massDiffThetacCand && massDiffThetacCand < cutsPtDeltaMassCharmReso->get(1u, 12u)); + bool isGoodThetacBar = (cutsPtDeltaMassCharmReso->get(0u, 12u) < massDiffThetacBarCand && massDiffThetacBarCand < cutsPtDeltaMassCharmReso->get(1u, 12u)); + + if (activateQA) { + if (isGoodThetac) { + if (isRightSignThetaC) { + hMassVsPtC[kNCharmParticles + 21]->Fill(ptCand, massDiffThetacCand); + } else if (!isRightSignThetaC && keepAlsoWrongDmesProtonPairs) { + hMassVsPtC[kNCharmParticles + 22]->Fill(ptCand, massDiffThetacBarCand); + } + } + if (isGoodThetacBar) { + if (isRightSignThetaCBar) { + hMassVsPtC[kNCharmParticles + 21]->Fill(ptCand, massDiffThetacCand); + } else if (!isRightSignThetaCBar && keepAlsoWrongDmesProtonPairs) { + hMassVsPtC[kNCharmParticles + 22]->Fill(ptCand, massDiffThetacBarCand); + } + } + } + if ((isGoodThetac && (isRightSignThetaC || keepAlsoWrongDstarMesProtonPairs)) || (isGoodThetacBar && (isRightSignThetaCBar || keepAlsoWrongDstarMesProtonPairs))) { + keepEvent[kPrCharm2P] = true; + break; + } + } + } + } + } + } // end bachelor pion for D*p pairs + // build D0p candidate with the possibility of storing also the other sign hyp. + if (pt2Prong < cutsPtDeltaMassCharmReso->get(3u, 11u)) { + continue; + } + if (!helper.isSelectedProtonFromLcResoOrThetaC(trackProton)) { + continue; + } + float massLcStarCand{-999.}, massLcStarBarCand{-999.}; + float massDiffLcStarCand{-999.}, massDiffLcStarBarCand{-999.}; + bool isRightSignLcStar{false}, isRightSignLcStarBar{false}; + auto pVecReso2Prong = RecoDecay::pVec(pVec2Prong, pVecProton); + auto ptCand = RecoDecay::pt(pVecReso2Prong); + if (ptCand > cutsPtDeltaMassCharmReso->get(2u, 11u)) { + if (TESTBIT(selD0InMass, 0)) { + massLcStarCand = RecoDecay::m(std::array{pVecPos, pVecNeg, pVecProton}, std::array{massPi, massKa, massProton}); + massDiffLcStarCand = massLcStarCand - massD0Cand; + isRightSignLcStar = trackProton.sign() > 0; // right sign if proton + } + if (TESTBIT(selD0InMass, 1)) { + massLcStarBarCand = RecoDecay::m(std::array{pVecPos, pVecNeg, pVecProton}, std::array{massKa, massPi, massProton}); + massDiffLcStarBarCand = massLcStarBarCand - massD0BarCand; + isRightSignLcStarBar = trackProton.sign() < 0; // right sign if antiproton + } + bool isGoodLcStar = (cutsPtDeltaMassCharmReso->get(0u, 11u) < massDiffLcStarCand && massDiffLcStarCand < cutsPtDeltaMassCharmReso->get(1u, 11u)); + bool isGoodLcStarBar = (cutsPtDeltaMassCharmReso->get(0u, 11u) < massDiffLcStarBarCand && massDiffLcStarBarCand < cutsPtDeltaMassCharmReso->get(1u, 11u)); + + if (activateQA) { + if (isGoodLcStar) { + if (isRightSignLcStar) { + hMassVsPtC[kNCharmParticles + 19]->Fill(ptCand, massDiffLcStarCand); + } else if (!isRightSignLcStar && keepAlsoWrongDmesProtonPairs) { + hMassVsPtC[kNCharmParticles + 20]->Fill(ptCand, massDiffLcStarBarCand); + } + } + if (isGoodLcStarBar) { + if (isRightSignLcStarBar) { + hMassVsPtC[kNCharmParticles + 19]->Fill(ptCand, massDiffLcStarCand); + } else if (!isRightSignLcStarBar && keepAlsoWrongDmesProtonPairs) { + hMassVsPtC[kNCharmParticles + 20]->Fill(ptCand, massDiffLcStarBarCand); + } + } + } + if ((isGoodLcStar && (isRightSignLcStar || keepAlsoWrongDmesProtonPairs)) || (isGoodLcStarBar && (isRightSignLcStarBar || keepAlsoWrongDmesProtonPairs))) { + keepEvent[kPrCharm2P] = true; + break; + } + } + } + } // end proton loop + } + } // end Lc resonances via D0-proton decays + } // end loop over 2-prong candidates - std::vector> indicesDau3Prong{}; + std::vector> indicesDau3Prong{}, indicesDau3ProngPrompt{}; auto cand3ProngsThisColl = cand3Prongs.sliceBy(hf3ProngPerCollision, thisCollId); for (const auto& cand3Prong : cand3ProngsThisColl) { // start loop over 3 prongs std::array is3Prong = { @@ -688,13 +1130,13 @@ struct HfFilter { // Main struct for HF triggers continue; } - auto trackFirst = cand3Prong.prong0_as(); - auto trackSecond = cand3Prong.prong1_as(); - auto trackThird = cand3Prong.prong2_as(); + auto trackFirst = tracks.rawIteratorAt(cand3Prong.prong0Id()); + auto trackSecond = tracks.rawIteratorAt(cand3Prong.prong1Id()); + auto trackThird = tracks.rawIteratorAt(cand3Prong.prong2Id()); - auto trackParFirst = getTrackPar(trackFirst); - auto trackParSecond = getTrackPar(trackSecond); - auto trackParThird = getTrackPar(trackThird); + auto trackParFirst = getTrackParCov(trackFirst); + auto trackParSecond = getTrackParCov(trackSecond); + auto trackParThird = getTrackParCov(trackThird); o2::gpu::gpustd::array dcaFirst{trackFirst.dcaXY(), trackFirst.dcaZ()}; o2::gpu::gpustd::array dcaSecond{trackSecond.dcaXY(), trackSecond.dcaZ()}; o2::gpu::gpustd::array dcaThird{trackThird.dcaXY(), trackThird.dcaZ()}; @@ -768,8 +1210,23 @@ struct HfFilter { // Main struct for HF triggers continue; } - if ((!keepOnlyDplusForDouble3Prongs && std::accumulate(isCharmTagged.begin(), isCharmTagged.end(), 0)) || (keepOnlyDplusForDouble3Prongs && isCharmTagged[kDplus - 1])) { + keepEvent[kSingleCharm3P] = true; + if (std::accumulate(isBeautyTagged.begin(), isBeautyTagged.end(), 0)) { + keepEvent[kSingleNonPromptCharm3P] = true; + } + + if (!keepOnlyDplusForDouble3Prongs) { indicesDau3Prong.push_back(std::vector{trackFirst.globalIndex(), trackSecond.globalIndex(), trackThird.globalIndex()}); + if (std::accumulate(isCharmTagged.begin(), isCharmTagged.end(), 0)) { + indicesDau3ProngPrompt.push_back(std::vector{trackFirst.globalIndex(), trackSecond.globalIndex(), trackThird.globalIndex()}); + } + } else { + if (isSignalTagged[kDplus - 1]) { + indicesDau3Prong.push_back(std::vector{trackFirst.globalIndex(), trackSecond.globalIndex(), trackThird.globalIndex()}); + if (isCharmTagged[kDplus - 1]) { + indicesDau3ProngPrompt.push_back(std::vector{trackFirst.globalIndex(), trackSecond.globalIndex(), trackThird.globalIndex()}); + } + } } // end multiple 3-prong selection auto pVec3Prong = RecoDecay::pVec(pVecFirst, pVecSecond, pVecThird); @@ -814,14 +1271,15 @@ struct HfFilter { // Main struct for HF triggers } // end high-pT selection auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + auto tracksWithItsPid = soa::Attach(tracks); for (const auto& trackId : trackIdsThisCollision) { // start loop over track indices as associated to this collision in HF code - auto track = trackId.track_as(); + auto track = tracksWithItsPid.rawIteratorAt(trackId.trackId()); if (track.globalIndex() == trackFirst.globalIndex() || track.globalIndex() == trackSecond.globalIndex() || track.globalIndex() == trackThird.globalIndex()) { continue; } - auto trackParFourth = getTrackPar(track); + auto trackParFourth = getTrackParCov(track); o2::gpu::gpustd::array dcaFourth{track.dcaXY(), track.dcaZ()}; std::array pVecFourth = track.pVector(); if (track.collisionId() != thisCollId) { @@ -829,25 +1287,65 @@ struct HfFilter { // Main struct for HF triggers getPxPyPz(trackParFourth, pVecFourth); } - int charmParticleID[kNBeautyParticles - 2] = {o2::constants::physics::Pdg::kDPlus, o2::constants::physics::Pdg::kDS, o2::constants::physics::Pdg::kLambdaCPlus, o2::constants::physics::Pdg::kXiCPlus}; + int charmParticleID[kNBeautyParticles - 3] = {o2::constants::physics::Pdg::kDPlus, o2::constants::physics::Pdg::kDS, o2::constants::physics::Pdg::kLambdaCPlus, o2::constants::physics::Pdg::kXiCPlus}; - float massCharmHypos[kNBeautyParticles - 2] = {massDPlus, massDs, massLc, massXic}; - float massBeautyHypos[kNBeautyParticles - 2] = {massB0, massBs, massLb, massXib}; - float deltaMassHypos[kNBeautyParticles - 2] = {deltaMassBeauty->get(0u, 1u), deltaMassBeauty->get(0u, 3u), deltaMassBeauty->get(0u, 4u), deltaMassBeauty->get(0u, 5u)}; - auto isTrackSelected = helper.isSelectedTrackForSoftPionOrBeauty(track, trackParFourth, dcaFourth, kBeauty4P); + float massCharmHypos[kNBeautyParticles - 3] = {massDPlus, massDs, massLc, massXic}; + auto isTrackSelected = helper.isSelectedTrackForSoftPionOrBeauty(track, trackParFourth, dcaFourth); if (track.sign() * sign3Prong < 0 && TESTBIT(isTrackSelected, kForBeauty)) { - for (int iHypo{0}; iHypo < kNBeautyParticles - 2 && !keepEvent[kBeauty4P]; ++iHypo) { + for (int iHypo{0}; iHypo < kNBeautyParticles - 3 && !keepEvent[kBeauty4P]; ++iHypo) { if (isBeautyTagged[iHypo] && (TESTBIT(is3ProngInMass[iHypo], 0) || TESTBIT(is3ProngInMass[iHypo], 1))) { auto massCandB = RecoDecay::m(std::array{pVec3Prong, pVecFourth}, std::array{massCharmHypos[iHypo], massPi}); - if (std::fabs(massCandB - massBeautyHypos[iHypo]) <= deltaMassHypos[iHypo]) { - keepEvent[kBeauty4P] = true; - if (applyOptimisation) { - optimisationTreeBeauty(thisCollId, charmParticleID[iHypo], pt3Prong, scores[iHypo][0], scores[iHypo][1], scores[iHypo][2], dcaFourth[0]); - } + auto pVecBeauty4Prong = RecoDecay::pVec(pVec3Prong, pVecFourth); + auto ptCandBeauty4Prong = RecoDecay::pt(pVecBeauty4Prong); + if (helper.isSelectedBhadronInMassRange(ptCandBeauty4Prong, massCandB, iHypo + 3)) { // + 3 to account for B+ and B0->D*+ and Bc if (activateQA) { - auto pVecBeauty4Prong = RecoDecay::pVec(pVec3Prong, pVecFourth); - auto ptCandBeauty4Prong = RecoDecay::pt(pVecBeauty4Prong); - hMassVsPtB[iHypo + 2]->Fill(ptCandBeauty4Prong, massCandB); + registry.fill(HIST("fHfVtxStages"), 1 + HfVtxStage::Skimmed, iHypo + 3); + } + if (!activateSecVtxForB) { + keepEvent[kBeauty4P] = true; + if (applyOptimisation) { + optimisationTreeBeauty(thisCollId, charmParticleID[iHypo], pt3Prong, scores[iHypo][0], scores[iHypo][1], scores[iHypo][2], dcaFourth[0]); + } + if (activateQA) { + hMassVsPtB[iHypo + 3]->Fill(ptCandBeauty4Prong, massCandB); + } + } else { + df3.process(trackParFirst, trackParSecond, trackParThird); + df3.propagateTracksToVertex(); + std::array pVecFirstVtx{}, pVecSecondVtx{}, pVecThirdVtx{}; + df3.getTrack(0).getPxPyPzGlo(pVecFirstVtx); + df3.getTrack(1).getPxPyPzGlo(pVecSecondVtx); + df3.getTrack(1).getPxPyPzGlo(pVecThirdVtx); + auto trackParD = df3.createParentTrackParCov(); + trackParD.setAbsCharge(sign3Prong); // to be sure + auto pVec3ProngVtx = RecoDecay::pVec(pVecFirstVtx, pVecSecondVtx, pVecThirdVtx); + if (dfB.process(trackParD, trackParFourth) != 0) { + if (activateQA) { + registry.fill(HIST("fHfVtxStages"), 1 + HfVtxStage::BeautyVertex, iHypo + 3); + } + dfB.propagateTracksToVertex(); + const auto& secondaryVertexB = dfB.getPCACandidate(); + std::array pVecFourtVtx{}; + dfB.getTrack(0).getPxPyPzGlo(pVec3ProngVtx); + dfB.getTrack(1).getPxPyPzGlo(pVecFourtVtx); + o2::gpu::gpustd::array dca3Prong; //{trackParD.dcaXY(), trackParD.dcaZ()}; + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParD, 2.f, noMatCorr, &dca3Prong); + bool isBhad = helper.isSelectedBhadron(pVec3ProngVtx, pVecFourtVtx, dca3Prong, dcaFourth, std::array{static_cast(collision.posX()), static_cast(collision.posY()), static_cast(collision.posZ())}, std::array{secondaryVertexB[0], secondaryVertexB[1], secondaryVertexB[2]}, iHypo + 3); + if (isBhad) { + keepEvent[kBeauty4P] = true; + // fill optimisation tree + if (applyOptimisation) { + optimisationTreeBeauty(thisCollId, charmParticleID[iHypo], pt3Prong, scores[iHypo][0], scores[iHypo][1], scores[iHypo][2], dcaFourth[0]); + } + if (activateQA) { + registry.fill(HIST("fHfVtxStages"), 1 + HfVtxStage::CharmHadPiSelected, iHypo + 3); + hCpaVsPtB[iHypo + 3]->Fill(ptCandBeauty4Prong, RecoDecay::cpa(std::array{static_cast(collision.posX()), static_cast(collision.posY()), static_cast(collision.posZ())}, std::array{secondaryVertexB[0], secondaryVertexB[1], secondaryVertexB[2]}, RecoDecay::pVec(pVec3ProngVtx, pVecFourtVtx))); + hDecayLengthVsPtB[iHypo + 3]->Fill(ptCandBeauty4Prong, RecoDecay::distance(std::array{static_cast(collision.posX()), static_cast(collision.posY()), static_cast(collision.posZ())}, std::array{secondaryVertexB[0], secondaryVertexB[1], secondaryVertexB[2]})); + hImpactParamProductVsPtB[iHypo + 3]->Fill(ptCandBeauty4Prong, dca3Prong[0] * dcaFourth[0]); + hMassVsPtB[iHypo + 3]->Fill(ptCandBeauty4Prong, massCandB); + } + } + } } } } @@ -855,13 +1353,15 @@ struct HfFilter { // Main struct for HF triggers } // end beauty selection // 3-prong femto - bool isProton = helper.isSelectedProton4Femto(track, trackParFourth, activateQA, hProtonTPCPID, hProtonTOFPID, forceTofPidForFemto); + bool isProton = helper.isSelectedTrack4Femto(track, trackParFourth, activateQA, hPrDePID[0], hPrDePID[1], kProtonForFemto); + bool isDeuteron = helper.isSelectedTrack4Femto(track, trackParFourth, activateQA, hPrDePID[2], hPrDePID[3], kDeuteronForFemto); + if (isProton && track.collisionId() == thisCollId) { for (int iHypo{0}; iHypo < kNCharmParticles - 1 && !keepEvent[kFemto3P]; ++iHypo) { - if (isCharmTagged[iHypo] && enableFemtoChannels->get(0u, iHypo + 1) && (TESTBIT(is3ProngInMass[iHypo], 0) || TESTBIT(is3ProngInMass[iHypo], 1) || !requireCharmMassForFemto)) { + if (isCharmTagged[iHypo] && enableFemtoChannels->get(0u, iHypo + 1)) { float relativeMomentum = helper.computeRelativeMomentum(pVecFourth, pVec3Prong, massCharmHypos[iHypo]); if (applyOptimisation) { - optimisationTreeFemto(thisCollId, charmParticleID[iHypo], pt3Prong, scores[iHypo][0], scores[iHypo][1], scores[iHypo][2], relativeMomentum, track.tpcNSigmaPr(), track.tofNSigmaPr()); + optimisationTreeFemto(thisCollId, charmParticleID[iHypo], pt3Prong, scores[iHypo][0], scores[iHypo][1], scores[iHypo][2], relativeMomentum, track.tpcNSigmaPr(), track.tofNSigmaPr(), track.tpcNSigmaDe(), track.tofNSigmaDe()); } if (relativeMomentum < femtoMaxRelativeMomentum) { keepEvent[kFemto3P] = true; @@ -871,6 +1371,22 @@ struct HfFilter { // Main struct for HF triggers } } } + } + if (isDeuteron && track.collisionId() == thisCollId) { + for (int iHypo{0}; iHypo < kNCharmParticles - 1 && !keepEvent[kFemto3P]; ++iHypo) { + if (isCharmTagged[iHypo] && enableFemtoChannels->get(1u, iHypo + 1)) { + float relativeMomentum = helper.computeRelativeMomentum(pVecFourth, pVec3Prong, massCharmHypos[iHypo]); + if (applyOptimisation) { + optimisationTreeFemto(thisCollId, charmParticleID[iHypo], pt3Prong, scores[iHypo][0], scores[iHypo][1], scores[iHypo][2], relativeMomentum, track.tpcNSigmaPr(), track.tofNSigmaPr(), track.tpcNSigmaDe(), track.tofNSigmaDe()); + } + if (relativeMomentum < femtoMaxRelativeMomentum) { + keepEvent[kFemto3P] = true; + if (activateQA) { + hCharmDeuteronKstarDistr[iHypo + 1]->Fill(relativeMomentum); + } + } + } + } } // end femto selection // SigmaC++ K- trigger @@ -881,7 +1397,7 @@ struct HfFilter { // Main struct for HF triggers for (const auto& trackSoftPiId : trackIdsThisCollision) { // start loop over tracks (soft pi) // soft pion candidates - auto trackSoftPi = trackSoftPiId.track_as(); + auto trackSoftPi = tracks.rawIteratorAt(trackSoftPiId.trackId()); auto globalIndexSoftPi = trackSoftPi.globalIndex(); // exclude tracks already used to build the 3-prong candidate @@ -912,7 +1428,7 @@ struct HfFilter { // Main struct for HF triggers o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParSoftPi, 2.f, noMatCorr, &dcaSoftPi); getPxPyPz(trackParSoftPi, pVecSoftPi); } - int8_t isSoftPionSelected = helper.isSelectedTrackForSoftPionOrBeauty(trackSoftPi, trackParSoftPi, dcaSoftPi, kSigmaCPPK); + int16_t isSoftPionSelected = helper.isSelectedTrackForSoftPionOrBeauty(trackSoftPi, trackParSoftPi, dcaSoftPi); if (TESTBIT(isSoftPionSelected, kSoftPionForSigmaC) /*&& (TESTBIT(is3Prong[2], 0) || TESTBIT(is3Prong[2], 1))*/) { // check the mass of the SigmaC++ candidate @@ -972,9 +1488,9 @@ struct HfFilter { // Main struct for HF triggers } } } // end SigmaC++ candidate - } // end loop over tracks (soft pi) - } // end candidate Lc->pKpi - } // end loop over tracks + } // end loop over tracks (soft pi) + } // end candidate Lc->pKpi + } // end loop over tracks // Ds with photon bool isGoodDsToKKPi = (isSignalTagged[kDs - 1]) && TESTBIT(is3ProngInMass[kDs - 1], 0); @@ -1010,9 +1526,9 @@ struct HfFilter { // Main struct for HF triggers auto pVecReso3Prong = RecoDecay::pVec(pVec3Prong, pVecPhoton); auto ptCand = RecoDecay::pt(pVecReso3Prong); - if (ptCand > cutsPtDeltaMassCharmReso->get(2u, 1u)) { - bool isGoodDsStarToKKPi = (cutsPtDeltaMassCharmReso->get(0u, 1u) < massDiffDsStarToKKPi && massDiffDsStarToKKPi < cutsPtDeltaMassCharmReso->get(1u, 1u)); - bool isGoodDsStarToPiKK = (cutsPtDeltaMassCharmReso->get(0u, 1u) < massDiffDsStarToPiKK && massDiffDsStarToPiKK < cutsPtDeltaMassCharmReso->get(1u, 1u)); + if (ptCand > cutsPtDeltaMassCharmReso->get(2u, 2u)) { + bool isGoodDsStarToKKPi = (cutsPtDeltaMassCharmReso->get(0u, 2u) < massDiffDsStarToKKPi && massDiffDsStarToKKPi < cutsPtDeltaMassCharmReso->get(1u, 2u)); + bool isGoodDsStarToPiKK = (cutsPtDeltaMassCharmReso->get(0u, 2u) < massDiffDsStarToPiKK && massDiffDsStarToPiKK < cutsPtDeltaMassCharmReso->get(1u, 2u)); if (isGoodDsStarToKKPi || isGoodDsStarToPiKK) { if (activateQA) { if (isGoodDsStarToKKPi) { @@ -1038,28 +1554,21 @@ struct HfFilter { // Main struct for HF triggers if ((!keepEvent[kV0Charm3P] && isGoodDPlus) || (!keepEvent[kSigmaC0K0] && (isGoodLcToPKPi || isGoodLcToPiKP))) { for (const auto& v0 : v0sThisCollision) { - auto posTrack = v0.posTrack_as(); - auto negTrack = v0.negTrack_as(); - auto selV0 = helper.isSelectedV0(v0, std::array{posTrack, negTrack}, collision, activateQA, hV0Selected, hArmPod); + V0Cand v0Cand; + if (!helper.buildV0(v0, tracksIU, collision, dfStrangeness, std::vector{cand3Prong.prong0Id(), cand3Prong.prong1Id(), cand3Prong.prong2Id()}, v0Cand)) { + continue; + } + auto selV0 = helper.isSelectedV0(v0Cand, activateQA, hV0Selected, hArmPod); if (!selV0) { continue; } - gpu::gpustd::array dcaInfo; - std::array pVecV0Orig = {v0.px(), v0.py(), v0.pz()}; - std::array pVecV0 = {v0.px(), v0.py(), v0.pz()}; - std::array posVecV0 = {v0.x(), v0.y(), v0.z()}; // we pair D+ with V0 if (!keepEvent[kV0Charm3P] && isGoodDPlus) { if (!keepEvent[kV0Charm3P] && TESTBIT(selV0, kK0S)) { // Ds2* - auto trackParK0S = o2::track::TrackPar(posVecV0, pVecV0Orig, 0, true); - trackParK0S.setAbsCharge(0); - trackParK0S.setPID(o2::track::PID::K0); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParK0S, 2.f, matCorr, &dcaInfo); - getPxPyPz(trackParK0S, pVecV0); - auto massDsStarCand = RecoDecay::m(std::array{pVecFirst, pVecSecond, pVecThird, pVecV0}, std::array{massPi, massKa, massPi, massK0S}); + auto massDsStarCand = RecoDecay::m(std::array{pVecFirst, pVecSecond, pVecThird, v0Cand.mom}, std::array{massPi, massKa, massPi, massK0S}); auto massDiffDsStar = massDsStarCand - massDPlusCand; - auto pVecReso3Prong = RecoDecay::pVec(pVec3Prong, pVecV0); + auto pVecReso3Prong = RecoDecay::pVec(pVec3Prong, v0Cand.mom); auto ptCand = RecoDecay::pt(pVecReso3Prong); if (ptCand > cutsPtDeltaMassCharmReso->get(2u, 4u)) { if (cutsPtDeltaMassCharmReso->get(0u, 4u) < massDiffDsStar && massDiffDsStar < cutsPtDeltaMassCharmReso->get(1u, 4u)) { @@ -1071,15 +1580,10 @@ struct HfFilter { // Main struct for HF triggers } } if (!keepEvent[kV0Charm3P] && (TESTBIT(selV0, kLambda) || TESTBIT(selV0, kAntiLambda))) { // Xic(3055) and Xic(3080) --> since it occupies only a small bandwidth, we might want to keep also wrong sign pairs - auto trackParLambda = o2::track::TrackPar(posVecV0, pVecV0Orig, 0, true); - trackParLambda.setAbsCharge(0); - trackParLambda.setPID(o2::track::PID::Lambda); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParLambda, 2.f, matCorr, &dcaInfo); - getPxPyPz(trackParLambda, pVecV0); - auto pVecReso3Prong = RecoDecay::pVec(pVec3Prong, pVecV0); + auto pVecReso3Prong = RecoDecay::pVec(pVec3Prong, v0Cand.mom); auto ptCand = RecoDecay::pt(pVecReso3Prong); if (ptCand > cutsPtDeltaMassCharmReso->get(2u, 5u)) { - auto massXicStarCand = RecoDecay::m(std::array{pVecFirst, pVecSecond, pVecThird, pVecV0}, std::array{massPi, massKa, massPi, massLambda}); + auto massXicStarCand = RecoDecay::m(std::array{pVecFirst, pVecSecond, pVecThird, v0Cand.mom}, std::array{massPi, massKa, massPi, massLambda}); auto massDiffXicStar = massXicStarCand - massDPlusCand; bool isRightSign = ((TESTBIT(selV0, kLambda) && sign3Prong > 0) || (TESTBIT(selV0, kAntiLambda) && sign3Prong < 0)); if (cutsPtDeltaMassCharmReso->get(0u, 5u) < massDiffXicStar && massDiffXicStar < cutsPtDeltaMassCharmReso->get(1u, 5u)) { @@ -1104,12 +1608,12 @@ struct HfFilter { // Main struct for HF triggers for (const auto& trackSoftPiId : trackIdsThisCollision) { // start loop over tracks (soft pi) // soft pion candidates - auto trackSoftPi = trackSoftPiId.track_as(); + auto trackSoftPi = tracks.rawIteratorAt(trackSoftPiId.trackId()); auto globalIndexSoftPi = trackSoftPi.globalIndex(); // exclude tracks already used to build the 3-prong candidate - if (globalIndexSoftPi == trackFirst.globalIndex() || globalIndexSoftPi == trackSecond.globalIndex() || globalIndexSoftPi == trackThird.globalIndex()) { - // do not consider as candidate soft pion a track already used to build the current 3-prong candidate + if (globalIndexSoftPi == trackFirst.globalIndex() || globalIndexSoftPi == trackSecond.globalIndex() || globalIndexSoftPi == trackThird.globalIndex() || globalIndexSoftPi == v0.posTrackId() || globalIndexSoftPi == v0.negTrackId()) { + // do not consider as candidate soft pion a track already used to build the current 3-prong candidate / V0 candidate continue; } @@ -1130,7 +1634,7 @@ struct HfFilter { // Main struct for HF triggers o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParSoftPi, 2.f, noMatCorr, &dcaSoftPi); getPxPyPz(trackParSoftPi, pVecSoftPi); } - int8_t isSoftPionSelected = helper.isSelectedTrackForSoftPionOrBeauty(trackSoftPi, trackParSoftPi, dcaSoftPi, kSigmaC0K0); + int16_t isSoftPionSelected = helper.isSelectedTrackForSoftPionOrBeauty(trackSoftPi, trackParSoftPi, dcaSoftPi); if (TESTBIT(isSoftPionSelected, kSoftPionForSigmaC) /*&& (TESTBIT(is3Prong[2], 0) || TESTBIT(is3Prong[2], 1))*/) { // check the mass of the SigmaC0 candidate @@ -1142,17 +1646,15 @@ struct HfFilter { // Main struct for HF triggers /// and keep it only if it is in the correct mass range float massSigmaCPKPi{-999.}, massSigmaCPiKP{-999.}, deltaMassXicResoPKPi{-999.}, deltaMassXicResoPiKP{-999.}; - std::array pVecPiPosK0s = posTrack.pVector(); - std::array pVecPiNegK0s = negTrack.pVector(); - float ptSigmaCKaon = RecoDecay::pt(pVecSigmaC, pVecPiPosK0s, pVecPiNegK0s); + float ptSigmaCKaon = RecoDecay::pt(pVecSigmaC, v0Cand.mom); if (ptSigmaCKaon > cutsPtDeltaMassCharmReso->get(2u, 10u)) { if (TESTBIT(whichSigmaC, 0)) { massSigmaCPKPi = RecoDecay::m(std::array{pVecFirst, pVecSecond, pVecThird, pVecSoftPi}, std::array{massProton, massKa, massPi, massPi}); - deltaMassXicResoPKPi = RecoDecay::m(std::array{pVecFirst, pVecSecond, pVecThird, pVecSoftPi, pVecPiPosK0s, pVecPiNegK0s}, std::array{massProton, massKa, massPi, massPi, massPi, massPi}) - massSigmaCPKPi; + deltaMassXicResoPKPi = RecoDecay::m(std::array{pVecFirst, pVecSecond, pVecThird, pVecSoftPi, v0Cand.mom}, std::array{massProton, massKa, massPi, massPi, massK0S}) - massSigmaCPKPi; } if (TESTBIT(whichSigmaC, 1)) { massSigmaCPiKP = RecoDecay::m(std::array{pVecFirst, pVecSecond, pVecThird, pVecSoftPi}, std::array{massPi, massKa, massProton, massPi}); - deltaMassXicResoPiKP = RecoDecay::m(std::array{pVecFirst, pVecSecond, pVecThird, pVecSoftPi, pVecPiPosK0s, pVecPiNegK0s}, std::array{massPi, massKa, massProton, massPi, massPi, massPi}) - massSigmaCPiKP; + deltaMassXicResoPiKP = RecoDecay::m(std::array{pVecFirst, pVecSecond, pVecThird, pVecSoftPi, v0Cand.mom}, std::array{massPi, massKa, massProton, massPi, massK0S}) - massSigmaCPiKP; } bool isPKPiOk = (cutsPtDeltaMassCharmReso->get(0u, 10u) < deltaMassXicResoPKPi && deltaMassXicResoPKPi < cutsPtDeltaMassCharmReso->get(1u, 10u)); @@ -1190,71 +1692,138 @@ struct HfFilter { // Main struct for HF triggers } } // end loop over 3-prong candidates - if (!keepEvent[kCharmBarToXiBach]) { + if (!keepEvent[kCharmBarToXiBach] || !keepEvent[kCharmBarToXi2Bach]) { auto cascThisColl = cascades.sliceBy(cascPerCollision, thisCollId); for (const auto& casc : cascThisColl) { - auto bachelorCasc = casc.bachelor_as(); - auto v0DauPos = casc.posTrack_as(); - auto v0DauNeg = casc.negTrack_as(); - if (!helper.isSelectedCascade(casc, std::array{bachelorCasc, v0DauPos, v0DauNeg}, collision)) { + bool hasStrangeTrack{false}; + + TracksIUPID::iterator cascTrack; + int requireStrangenessTrackingAny = requireStrangenessTracking->get(0u, 0u) + requireStrangenessTracking->get(0u, 1u); + if (requireStrangenessTrackingAny > 0) { // enabled for at least one of the two + auto trackedCascIdThisColl = trackedCasc.sliceBy(trackedCascadesPerCollision, thisCollId); + for (const auto& trackedCascId : trackedCascIdThisColl) { + if (trackedCascId.cascadeId() == casc.globalIndex()) { + hasStrangeTrack = true; + cascTrack = trackedCascId.track_as(); + break; + } + } + } + + CascCand cascCand; + if (!helper.buildCascade(casc, v0s, tracksIU, collision, dfStrangeness, {}, cascCand)) { continue; } + + if (!helper.isSelectedCascade(cascCand)) { + continue; + } + if (activateQA) { - hMassXi->Fill(casc.mXi()); + hMassXi[0]->Fill(cascCand.mXi); + if (hasStrangeTrack) { + hMassXi[1]->Fill(cascCand.mXi); + } } - auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - for (const auto& trackId : trackIdsThisCollision) { // start loop over tracks - auto track = trackId.track_as(); + auto bachelorCascId = casc.bachelorId(); + auto v0 = v0s.rawIteratorAt(casc.v0Id()); + auto v0DauPosId = v0.posTrackId(); + auto v0DauNegId = v0.negTrackId(); + + // propagate to PV + gpu::gpustd::array dcaInfo; + o2::track::TrackParCov trackParCasc; + o2::track::TrackParCov trackParCascTrack; + if (requireStrangenessTrackingAny < 2) { // needed for at least one of the two + trackParCasc = o2::track::TrackParCov(cascCand.vtx, cascCand.mom, cascCand.cov, cascCand.sign, true); + trackParCasc.setPID(o2::track::PID::XiMinus); + trackParCasc.setAbsCharge(1); // to be sure + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParCasc, 2.f, matCorr, &dcaInfo); + } + if (requireStrangenessTrackingAny > 0 && hasStrangeTrack) { // needed for at least one of the two + trackParCascTrack = getTrackParCov(cascTrack); + trackParCascTrack.setPID(o2::track::PID::XiMinus); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParCascTrack, 2.f, matCorr, &dcaInfo); + } - // ask for opposite sign daughters (omegac daughters) - if (track.sign() * bachelorCasc.sign() >= 0) { - continue; - } + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + for (const auto& trackId : trackIdsThisCollision) { // start loop over tracks (first bachelor) + auto track = tracks.rawIteratorAt(trackId.trackId()); // check if track is one of the Xi daughters - if (track.globalIndex() == bachelorCasc.globalIndex() || track.globalIndex() == v0DauPos.globalIndex() || track.globalIndex() == v0DauNeg.globalIndex()) { + if (track.globalIndex() == bachelorCascId || track.globalIndex() == v0DauPosId || track.globalIndex() == v0DauNegId) { continue; } - // propagate to PV - gpu::gpustd::array dcaInfo; - std::array pVecCascade = {casc.px(), casc.py(), casc.pz()}; - auto trackParCasc = o2::track::TrackPar(std::array{casc.x(), casc.y(), casc.z()}, pVecCascade, bachelorCasc.sign(), true); - trackParCasc.setPID(o2::track::PID::XiMinus); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParCasc, 2.f, matCorr, &dcaInfo); - getPxPyPz(trackParCasc, pVecCascade); - - auto trackParBachelor = getTrackPar(track); - std::array pVecBachelor = track.pVector(); + auto trackParBachelor = getTrackParCov(track); + gpu::gpustd::array dcaInfoBach; if (track.collisionId() != thisCollId) { - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParBachelor, 2.f, noMatCorr, &dcaInfo); - getPxPyPz(trackParBachelor, pVecBachelor); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParBachelor, 2.f, noMatCorr, &dcaInfoBach); } - auto isSelBachelor = helper.isSelectedBachelorForCharmBaryon(track, dcaInfo); + auto isSelBachelor = helper.isSelectedBachelorForCharmBaryon(track, dcaInfoBach); if (isSelBachelor == kRejected) { continue; } - auto ptCharmBaryon = RecoDecay::pt(RecoDecay::pVec(pVecCascade, pVecBachelor)); + if (!keepEvent[kCharmBarToXiBach] && track.sign() * cascCand.sign < 0) { // XiPi and XiKa - if (!keepEvent[kCharmBarToXiBach] && TESTBIT(isSelBachelor, kPionForCharmBaryon)) { - auto massXiPi = RecoDecay::m(std::array{pVecCascade, pVecBachelor}, std::array{massXi, massPi}); - if (ptCharmBaryon > cutsXiBachelor->get(0u, 0u) && massXiPi >= cutsXiBachelor->get(0u, 2u) && massXiPi <= 2.8f) { - keepEvent[kCharmBarToXiBach] = true; - if (activateQA) { - hMassVsPtC[kNCharmParticles + 15]->Fill(ptCharmBaryon, massXiPi); + bool isSelXiBach{false}; + if (requireStrangenessTracking->get(0u, 0u) > 0) { + if (hasStrangeTrack) { + isSelXiBach = helper.isSelectedXiBach(trackParCascTrack, trackParBachelor, isSelBachelor, collision, df2, activateQA, hMassVsPtC[kNCharmParticles + 15], hMassVsPtC[kNCharmParticles + 16]); } + } else { + isSelXiBach = helper.isSelectedXiBach(trackParCasc, trackParBachelor, isSelBachelor, collision, dfStrangeness, activateQA, hMassVsPtC[kNCharmParticles + 15], hMassVsPtC[kNCharmParticles + 16]); } - } - if (!keepEvent[kCharmBarToXiBach] && TESTBIT(isSelBachelor, kKaonForCharmBaryon)) { - auto massXiKa = RecoDecay::m(std::array{pVecCascade, pVecBachelor}, std::array{massXi, massKa}); - if (ptCharmBaryon > cutsXiBachelor->get(0u, 1u) && massXiKa >= cutsXiBachelor->get(0u, 3u) && massXiKa <= 2.8f) { + if (isSelXiBach) { keepEvent[kCharmBarToXiBach] = true; - if (activateQA) { - hMassVsPtC[kNCharmParticles + 16]->Fill(ptCharmBaryon, massXiKa); + } + } + + // only pions needed below + if (!TESTBIT(isSelBachelor, kPionForCharmBaryon)) { + continue; + } + + if (!keepEvent[kCharmBarToXi2Bach]) { + for (const auto& trackIdSecond : trackIdsThisCollision) { // start loop over tracks (second bachelor) + auto trackSecond = tracks.rawIteratorAt(trackIdSecond.trackId()); + + // check if track is one of the Xi daughters + if (trackSecond.globalIndex() == track.globalIndex() || trackSecond.globalIndex() == bachelorCascId || trackSecond.globalIndex() == v0DauPosId || trackSecond.globalIndex() == v0DauNegId) { + continue; + } + + if (track.sign() * trackSecond.sign() < 0 || track.sign() * cascCand.sign > 0) { // we want same sign pions, opposite to the xi + continue; + } + + auto trackParBachelorSecond = getTrackParCov(trackSecond); + gpu::gpustd::array dcaInfoBachSecond; + if (trackSecond.collisionId() != thisCollId) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParBachelorSecond, 2.f, noMatCorr, &dcaInfoBachSecond); + } + + auto isSelBachelorSecond = helper.isSelectedBachelorForCharmBaryon(trackSecond, dcaInfoBachSecond); + if (!TESTBIT(isSelBachelorSecond, kPionForCharmBaryon)) { + continue; + } + if (!keepEvent[kCharmBarToXi2Bach]) { // XiPiPi + + bool isSelXiBachBach{false}; + if (requireStrangenessTracking->get(0u, 1u) > 0) { + if (hasStrangeTrack) { + isSelXiBachBach = helper.isSelectedXiBachBach<3>(trackParCascTrack, {trackParBachelor, trackParBachelorSecond}, collision, df3, activateQA, hMassVsPtC[kNCharmParticles + 17]); + } + } else { // vertex with only the two bachelors + isSelXiBachBach = helper.isSelectedXiBachBach<2>(trackParCasc, {trackParBachelor, trackParBachelorSecond}, collision, df2, activateQA, hMassVsPtC[kNCharmParticles + 17]); + } + if (isSelXiBachBach) { + keepEvent[kCharmBarToXi2Bach] = true; + } } } } @@ -1263,9 +1832,13 @@ struct HfFilter { // Main struct for HF triggers } auto n2Prongs = helper.computeNumberOfCandidates(indicesDau2Prong); + auto n2ProngsPrompt = helper.computeNumberOfCandidates(indicesDau2ProngPrompt); auto n3Prongs = helper.computeNumberOfCandidates(indicesDau3Prong); + auto n3ProngsPrompt = helper.computeNumberOfCandidates(indicesDau3ProngPrompt); indicesDau2Prong.insert(indicesDau2Prong.end(), indicesDau3Prong.begin(), indicesDau3Prong.end()); auto n23Prongs = helper.computeNumberOfCandidates(indicesDau2Prong); + indicesDau2ProngPrompt.insert(indicesDau2ProngPrompt.end(), indicesDau3ProngPrompt.begin(), indicesDau3ProngPrompt.end()); + auto n23ProngsPrompt = helper.computeNumberOfCandidates(indicesDau2ProngPrompt); if (activateQA) { hN2ProngCharmCand->Fill(n2Prongs); @@ -1273,16 +1846,44 @@ struct HfFilter { // Main struct for HF triggers } if (n2Prongs > 1 && enableDoubleCharmChannels->get(0u, 0u)) { - keepEvent[kDoubleCharm2P] = true; + if (enableDoubleCharmChannels->get(1u, 0u)) { + keepEvent[kDoubleCharm2P] = true; + } else { + if (n2ProngsPrompt > 1) { + keepEvent[kDoubleCharm2P] = true; + } + } } if (n3Prongs > 1 && enableDoubleCharmChannels->get(0u, 1u)) { - keepEvent[kDoubleCharm3P] = true; + if (enableDoubleCharmChannels->get(1u, 1u)) { + keepEvent[kDoubleCharm3P] = true; + } else { + if (n3ProngsPrompt > 1) { + keepEvent[kDoubleCharm3P] = true; + } + } } if (n23Prongs > 1 && enableDoubleCharmChannels->get(0u, 2u)) { - keepEvent[kDoubleCharmMix] = true; + if (enableDoubleCharmChannels->get(1u, 2u)) { + keepEvent[kDoubleCharmMix] = true; + } else { + if (n23ProngsPrompt > 1) { + keepEvent[kDoubleCharmMix] = true; + } + } + } + + // apply downscale factors, if required + if (applyDownscale) { + auto rndValue = gRandom->Rndm(); + for (int iTrigger{0}; iTrigger < kNtriggersHF; ++iTrigger) { + if (rndValue > downscaleFactors->get(iTrigger, 0u)) { + keepEvent[iTrigger] = false; + } + } } - tags(keepEvent[kHighPt2P], keepEvent[kHighPt3P], keepEvent[kBeauty3P], keepEvent[kBeauty4P], keepEvent[kFemto2P], keepEvent[kFemto3P], keepEvent[kDoubleCharm2P], keepEvent[kDoubleCharm3P], keepEvent[kDoubleCharmMix], keepEvent[kV0Charm2P], keepEvent[kV0Charm3P], keepEvent[kCharmBarToXiBach], keepEvent[kSigmaCPPK], keepEvent[kSigmaC0K0], keepEvent[kPhotonCharm2P], keepEvent[kPhotonCharm3P]); + tags(keepEvent[kHighPt2P], keepEvent[kHighPt3P], keepEvent[kBeauty3P], keepEvent[kBeauty4P], keepEvent[kFemto2P], keepEvent[kFemto3P], keepEvent[kDoubleCharm2P], keepEvent[kDoubleCharm3P], keepEvent[kDoubleCharmMix], keepEvent[kV0Charm2P], keepEvent[kV0Charm3P], keepEvent[kCharmBarToXiBach], keepEvent[kSigmaCPPK], keepEvent[kSigmaC0K0], keepEvent[kPhotonCharm2P], keepEvent[kPhotonCharm3P], keepEvent[kSingleCharm2P], keepEvent[kSingleCharm3P], keepEvent[kSingleNonPromptCharm2P], keepEvent[kSingleNonPromptCharm3P], keepEvent[kCharmBarToXi2Bach], keepEvent[kPrCharm2P], keepEvent[kBtoJPsiKa], keepEvent[kBtoJPsiKstar], keepEvent[kBtoJPsiPhi], keepEvent[kBtoJPsiPrKa], keepEvent[kBtoJPsiPi]); if (!std::accumulate(keepEvent, keepEvent + kNtriggersHF, 0)) { hProcessedEvents->Fill(1); diff --git a/EventFiltering/PWGHF/HFFilterCharmHadronSignals.cxx b/EventFiltering/PWGHF/HFFilterCharmHadronSignals.cxx index 11796fc9d21..6ed8498e838 100644 --- a/EventFiltering/PWGHF/HFFilterCharmHadronSignals.cxx +++ b/EventFiltering/PWGHF/HFFilterCharmHadronSignals.cxx @@ -15,6 +15,9 @@ /// /// \author Fabrizio Grosa , CERN +#include +#include + #include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" @@ -49,11 +52,11 @@ struct HfFilterCharmHadronSignals { // Main struct for HF triggers // parameters for ML application Configurable> pTBinsBDT{"pTBinsBDT", std::vector{hf_cuts_bdt_multiclass::vecBinsPt}, "track pT bin limits for BDT cut"}; - Configurable> thresholdBDTScoreD0ToKPi{"thresholdBDTScoreD0ToKPi", {hf_cuts_bdt_multiclass::cuts[0], hf_cuts_bdt_multiclass::nBinsPt, hf_cuts_bdt_multiclass::nCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of D0 candidates"}; - Configurable> thresholdBDTScoreDPlusToPiKPi{"thresholdBDTScoreDPlusToPiKPi", {hf_cuts_bdt_multiclass::cuts[0], hf_cuts_bdt_multiclass::nBinsPt, hf_cuts_bdt_multiclass::nCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of D+ candidates"}; - Configurable> thresholdBDTScoreDSToPiKK{"thresholdBDTScoreDSToPiKK", {hf_cuts_bdt_multiclass::cuts[0], hf_cuts_bdt_multiclass::nBinsPt, hf_cuts_bdt_multiclass::nCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Ds+ candidates"}; - Configurable> thresholdBDTScoreLcToPiKP{"thresholdBDTScoreLcToPiKP", {hf_cuts_bdt_multiclass::cuts[0], hf_cuts_bdt_multiclass::nBinsPt, hf_cuts_bdt_multiclass::nCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Lc+ candidates"}; - Configurable> thresholdBDTScoreXicToPiKP{"thresholdBDTScoreXicToPiKP", {hf_cuts_bdt_multiclass::cuts[0], hf_cuts_bdt_multiclass::nBinsPt, hf_cuts_bdt_multiclass::nCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Xic+ candidates"}; + Configurable> thresholdBDTScoreD0ToKPi{"thresholdBDTScoreD0ToKPi", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of D0 candidates"}; + Configurable> thresholdBDTScoreDPlusToPiKPi{"thresholdBDTScoreDPlusToPiKPi", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of D+ candidates"}; + Configurable> thresholdBDTScoreDSToPiKK{"thresholdBDTScoreDSToPiKK", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Ds+ candidates"}; + Configurable> thresholdBDTScoreLcToPiKP{"thresholdBDTScoreLcToPiKP", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Lc+ candidates"}; + Configurable> thresholdBDTScoreXicToPiKP{"thresholdBDTScoreXicToPiKP", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Xic+ candidates"}; Configurable paramCharmMassShape{"paramCharmMassShape", "2023_pass3", "Parametrisation of charm-hadron mass shape (options: 2023_pass3)"}; Configurable numSigmaDeltaMassCharmHad{"numSigmaDeltaMassCharmHad", 2.5, "Number of sigma for charm-hadron delta mass cut in B and D resonance triggers"}; @@ -63,7 +66,7 @@ struct HfFilterCharmHadronSignals { // Main struct for HF triggers Configurable minDeltaMassDstar{"minDeltaMassDstar", static_cast(cutsCharmReso[0][0]), "minimum invariant-mass delta for D*+ in GeV/c2"}; Configurable maxDeltaMassDstar{"maxDeltaMassDstar", static_cast(cutsCharmReso[1][0]), "maximum invariant-mass delta for D*+ in GeV/c2"}; Configurable> pTBinsTrack{"pTBinsTrack", std::vector{hf_cuts_single_track::vecBinsPtTrack}, "track pT bin limits for DCAXY pT-dependent cut (D* from beauty)"}; - Configurable> cutsTrackBeauty3Prong{"cutsTrackBeauty3Prong", {hf_cuts_single_track::cutsTrack[0], hf_cuts_single_track::nBinsPtTrack, hf_cuts_single_track::nCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for 3-prong beauty candidates"}; + Configurable> cutsTrackBeauty3Prong{"cutsTrackBeauty3Prong", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for 3-prong beauty candidates"}; // CCDB configuration Service ccdb; @@ -97,7 +100,7 @@ struct HfFilterCharmHadronSignals { // Main struct for HF triggers { helper.setPtLimitsDstarSoftPion(minPtSoftPion, maxPtSoftPion); helper.setPtBinsSingleTracks(pTBinsTrack); - helper.setCutsSingleTrackBeauty(cutsTrackBeauty3Prong, cutsTrackBeauty3Prong); + helper.setCutsSingleTrackBeauty(cutsTrackBeauty3Prong, cutsTrackBeauty3Prong, cutsTrackBeauty3Prong); helper.setMassResolParametrisation(paramCharmMassShape); helper.setNumSigmaForDeltaMassCharmHadCut(numSigmaDeltaMassCharmHad); @@ -221,7 +224,7 @@ struct HfFilterCharmHadronSignals { // Main struct for HF triggers o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParThird, 2.f, noMatCorr, &dcaThird); getPxPyPz(trackParThird, pVecThird); } - auto isTrackSelected = helper.isSelectedTrackForSoftPionOrBeauty(track, trackParThird, dcaThird, kBeauty3P); + auto isTrackSelected = helper.isSelectedTrackForSoftPionOrBeauty(track, trackParThird, dcaThird); if (TESTBIT(isTrackSelected, kSoftPion)) { std::array massDausD0{massPi, massKa}; auto invMassD0dau = invMassD0; diff --git a/EventFiltering/PWGHF/HFFilterHelpers.h b/EventFiltering/PWGHF/HFFilterHelpers.h index e0dd03f3b75..798a96b1ec7 100644 --- a/EventFiltering/PWGHF/HFFilterHelpers.h +++ b/EventFiltering/PWGHF/HFFilterHelpers.h @@ -18,6 +18,7 @@ /// \author Alexandre Bigot , Strasbourg University /// \author Biao Zhang , CCNU /// \author Federica Zanone , Heidelberg University +/// \author Antonio Palasciano , INFN Bari #ifndef EVENTFILTERING_PWGHF_HFFILTERHELPERS_H_ #define EVENTFILTERING_PWGHF_HFFILTERHELPERS_H_ @@ -39,6 +40,8 @@ #include "CommonConstants/MathConstants.h" #include "CommonConstants/PhysicsConstants.h" #include "DataFormatsTPC/BetheBlochAleph.h" +#include "DCAFitter/DCAFitterN.h" +#include "DetectorsBase/Propagator.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/DataTypes.h" @@ -75,6 +78,17 @@ enum HfTriggers { kSigmaC0K0, kPhotonCharm2P, kPhotonCharm3P, + kSingleCharm2P, + kSingleCharm3P, + kSingleNonPromptCharm2P, + kSingleNonPromptCharm3P, + kCharmBarToXi2Bach, + kPrCharm2P, + kBtoJPsiKa, + kBtoJPsiKstar, + kBtoJPsiPhi, + kBtoJPsiPrKa, + kBtoJPsiPi, kNtriggersHF }; @@ -90,6 +104,7 @@ enum charmParticles { enum beautyParticles { kBplus = 0, kB0toDStar, + kBc, kB0, kBs, kLb, @@ -97,6 +112,15 @@ enum beautyParticles { kNBeautyParticles }; +enum beautyToJPsiParticles { + kBplusToJPsi = 0, + kB0ToJPsi, + kBsToJPsi, + kLbToJPsi, + kBcToJPsi, + kNBeautyParticlesToJPsi +}; + enum bachelorTrackSelection { kRejected = 0, kSoftPion, @@ -104,6 +128,7 @@ enum bachelorTrackSelection { kSoftPionForBeauty, kPionForCharmBaryon, kKaonForCharmBaryon, + kProtonForCharmBaryon, kSoftPionForSigmaC }; @@ -114,7 +139,14 @@ enum PIDSpecies { kKa, kAntiKa, kPr, - kAntiPr + kAntiPr, + kDe, + kAntiDe +}; + +enum trackSpecies { + kProtonForFemto, + kDeuteronForFemto }; enum V0Species { @@ -125,11 +157,87 @@ enum V0Species { kNV0 }; +enum HfVtxStage : uint8_t { + Skimmed = 0, + BeautyVertex, + CharmHadPiSelected, + kNHfVtxStage +}; + +// Helper struct to pass V0 informations +struct V0Cand { + std::array mom; + std::array vtx; + std::array cov; + float etaPos; + float etaNeg; + float ptPos; + float ptNeg; + float pinTpcPos; + float pinTpcNeg; + float nClsFoundTpcPos; + float nClsFoundTpcNeg; + float nClsCrossedRowsTpcPos; + float nClsCrossedRowsTpcNeg; + float crossedRowsOverFindableClsTpcPos; + float crossedRowsOverFindableClsTpcNeg; + float signalTpcPos; + float signalTpcNeg; + float v0cosPA; + float dcav0topv; + float dcaV0daughters; + float dcapostopv; + float dcanegtopv; + float alpha; + float qtarm; + float v0radius; + float mK0Short; + float mLambda; + float mAntiLambda; + float nSigmaPrTpcPos; + float nSigmaPrTofPos; + float nSigmaPrTpcNeg; + float nSigmaPrTofNeg; + float nSigmaPiTpcPos; + float nSigmaPiTofPos; + float nSigmaPiTpcNeg; + float nSigmaPiTofNeg; + bool hasTofPos; + bool hasTofNeg; +}; + +// Helper struct to pass Cascade informations +struct CascCand { + std::array mom; + std::array vtx; + std::array cov; + V0Cand v0; + float ptBach; + float etaBach; + float pinTpcBach; + float nClsFoundTpcBach; + float nClsCrossedRowsTpcBach; + float crossedRowsOverFindableClsTpcBach; + float signalTpcBach; + float pt; + float casccosPA; + float cascradius; + float dcaXYCascToPV; + float dcacascdaughters; + float mXi; + float mOmega; + float nSigmaPiTpcBach; + float nSigmaPiTofBach; + bool hasTofBach; + int sign; +}; + static const std::array charmParticleNames{"D0", "Dplus", "Ds", "Lc", "Xic"}; -static const std::array beautyParticleNames{"Bplus", "B0toDStar", "B0", "Bs", "Lb", "Xib"}; +static const int nTotBeautyParts = static_cast(kNBeautyParticles) + static_cast(kNBeautyParticlesToJPsi); +static const std::array beautyParticleNames{"Bplus", "B0toDStar", "Bc", "B0", "Bs", "Lb", "Xib", "BplusToJPsi", "B0ToJPsi", "BsToJPsi", "LbToJPsi", "BcToJPsi"}; static const std::array pdgCodesCharm{421, 411, 431, 4122, 4232}; static const std::array eventTitles = {"all", "rejected"}; -static const std::array hfTriggerNames{filtering::HfHighPt2P::columnLabel(), filtering::HfHighPt3P::columnLabel(), filtering::HfBeauty3P::columnLabel(), filtering::HfBeauty4P::columnLabel(), filtering::HfFemto2P::columnLabel(), filtering::HfFemto3P::columnLabel(), filtering::HfDoubleCharm2P::columnLabel(), filtering::HfDoubleCharm3P::columnLabel(), filtering::HfDoubleCharmMix::columnLabel(), filtering::HfV0Charm2P::columnLabel(), filtering::HfV0Charm3P::columnLabel(), filtering::HfCharmBarToXiBach::columnLabel(), filtering::HfSigmaCPPK::columnLabel(), filtering::HfSigmaC0K0::columnLabel(), filtering::HfPhotonCharm2P::columnLabel(), filtering::HfPhotonCharm3P::columnLabel()}; +static const std::vector hfTriggerNames{filtering::HfHighPt2P::columnLabel(), filtering::HfHighPt3P::columnLabel(), filtering::HfBeauty3P::columnLabel(), filtering::HfBeauty4P::columnLabel(), filtering::HfFemto2P::columnLabel(), filtering::HfFemto3P::columnLabel(), filtering::HfDoubleCharm2P::columnLabel(), filtering::HfDoubleCharm3P::columnLabel(), filtering::HfDoubleCharmMix::columnLabel(), filtering::HfV0Charm2P::columnLabel(), filtering::HfV0Charm3P::columnLabel(), filtering::HfCharmBarToXiBach::columnLabel(), filtering::HfSigmaCPPK::columnLabel(), filtering::HfSigmaC0K0::columnLabel(), filtering::HfPhotonCharm2P::columnLabel(), filtering::HfPhotonCharm3P::columnLabel(), filtering::HfSingleCharm2P::columnLabel(), filtering::HfSingleCharm3P::columnLabel(), filtering::HfSingleNonPromptCharm2P::columnLabel(), filtering::HfSingleNonPromptCharm3P::columnLabel(), filtering::HfCharmBarToXi2Bach::columnLabel(), filtering::HfPrCharm2P::columnLabel(), filtering::HfBtoJPsiKa::columnLabel(), filtering::HfBtoJPsiKstar::columnLabel(), filtering::HfBtoJPsiPhi::columnLabel(), filtering::HfBtoJPsiPrKa::columnLabel(), filtering::HfBtoJPsiPi::columnLabel()}; static const std::array v0Labels{"#gamma", "K_{S}^{0}", "#Lambda", "#bar{#Lambda}"}; static const std::array v0Names{"Photon", "K0S", "Lambda", "AntiLambda"}; @@ -144,6 +252,8 @@ static const std::tuple pdgCharmDaughters{ constexpr float massPi = o2::constants::physics::MassPiPlus; constexpr float massKa = o2::constants::physics::MassKPlus; constexpr float massProton = o2::constants::physics::MassProton; +constexpr float massMu = o2::constants::physics::MassMuon; +constexpr float massDeuteron = o2::constants::physics::MassDeuteron; constexpr float massGamma = o2::constants::physics::MassGamma; constexpr float massK0S = o2::constants::physics::MassK0Short; constexpr float massLambda = o2::constants::physics::MassLambda0; @@ -160,8 +270,11 @@ constexpr float massB0 = o2::constants::physics::MassB0; constexpr float massBs = o2::constants::physics::MassBS; constexpr float massLb = o2::constants::physics::MassLambdaB0; constexpr float massXib = o2::constants::physics::MassXiB0; +constexpr float massBc = 6.2744700f; // TODO add Bc mass to o2::constants::physics constexpr float massSigmaCPlusPlus = o2::constants::physics::MassSigmaCPlusPlus; constexpr float massSigmaC0 = o2::constants::physics::MassSigmaC0; +constexpr float massK0Star892 = o2::constants::physics::MassK0Star892; +constexpr float massJPsi = o2::constants::physics::MassJPsi; static const o2::framework::AxisSpec ptAxis{50, 0.f, 50.f}; static const o2::framework::AxisSpec pAxis{50, 0.f, 10.f}; @@ -172,45 +285,77 @@ static const o2::framework::AxisSpec alphaAxis{100, -1.f, 1.f}; static const o2::framework::AxisSpec qtAxis{100, 0.f, 0.25f}; static const o2::framework::AxisSpec bdtAxis{100, 0.f, 1.f}; static const o2::framework::AxisSpec phiAxis{36, 0., o2::constants::math::TwoPI}; -static const std::array massAxisC = {o2::framework::AxisSpec{100, 1.65f, 2.05f}, o2::framework::AxisSpec{100, 1.65f, 2.05f}, o2::framework::AxisSpec{100, 1.75f, 2.15f}, o2::framework::AxisSpec{100, 2.05f, 2.45f}, o2::framework::AxisSpec{100, 2.25f, 2.65f}, o2::framework::AxisSpec{100, 0.139f, 0.159f}, o2::framework::AxisSpec{100, 0.f, 0.25f}, o2::framework::AxisSpec{100, 0.f, 0.25f}, o2::framework::AxisSpec{200, 0.48f, 0.88f}, o2::framework::AxisSpec{200, 0.48f, 0.88f}, o2::framework::AxisSpec{100, 1.1f, 1.4f}, o2::framework::AxisSpec{100, 1.1f, 1.4f}, o2::framework::AxisSpec{100, 1.1f, 1.4f}, o2::framework::AxisSpec{100, 1.1f, 1.4f}, o2::framework::AxisSpec{170, 0.13f, 0.3f}, o2::framework::AxisSpec{170, 0.13f, 0.3f}, o2::framework::AxisSpec{200, 0.4f, 0.8f}, o2::framework::AxisSpec{200, 0.4f, 0.8f}, o2::framework::AxisSpec{200, 0.4f, 0.8f}, o2::framework::AxisSpec{200, 0.4f, 0.8f}, o2::framework::AxisSpec{100, 2.3f, 2.9f}, o2::framework::AxisSpec{100, 2.3f, 2.9f}}; -static const std::array massAxisB = {o2::framework::AxisSpec{240, 4.8f, 6.0f}, o2::framework::AxisSpec{240, 4.8f, 6.0f}, o2::framework::AxisSpec{240, 4.8f, 6.0f}, o2::framework::AxisSpec{240, 4.8f, 6.0f}, o2::framework::AxisSpec{240, 5.0f, 6.2f}, o2::framework::AxisSpec{240, 5.0f, 6.2f}}; +static const std::array massAxisC = {o2::framework::AxisSpec{250, 1.65f, 2.15f}, o2::framework::AxisSpec{250, 1.65f, 2.15f}, o2::framework::AxisSpec{250, 1.75f, 2.25f}, o2::framework::AxisSpec{250, 2.05f, 2.55f}, o2::framework::AxisSpec{250, 2.25f, 2.75f}, o2::framework::AxisSpec{200, 0.139f, 0.159f}, o2::framework::AxisSpec{250, 0.f, 0.25f}, o2::framework::AxisSpec{250, 0.f, 0.25f}, o2::framework::AxisSpec{200, 0.48f, 0.88f}, o2::framework::AxisSpec{200, 0.48f, 0.88f}, o2::framework::AxisSpec{200, 1.1f, 1.4f}, o2::framework::AxisSpec{200, 1.1f, 1.4f}, o2::framework::AxisSpec{200, 1.1f, 1.4f}, o2::framework::AxisSpec{200, 1.1f, 1.4f}, o2::framework::AxisSpec{170, 0.13f, 0.3f}, o2::framework::AxisSpec{170, 0.13f, 0.3f}, o2::framework::AxisSpec{200, 0.4f, 0.8f}, o2::framework::AxisSpec{200, 0.4f, 0.8f}, o2::framework::AxisSpec{200, 0.4f, 0.8f}, o2::framework::AxisSpec{200, 0.4f, 0.8f}, o2::framework::AxisSpec{350, 2.3f, 3.0f}, o2::framework::AxisSpec{350, 2.3f, 3.0f}, o2::framework::AxisSpec{350, 2.3f, 3.0f}, o2::framework::AxisSpec{240, 2.4f, 3.6f}, o2::framework::AxisSpec{300, 0.7f, 1.3f}, o2::framework::AxisSpec{300, 0.7f, 1.3f}, o2::framework::AxisSpec{300, 0.7f, 1.3f}, o2::framework::AxisSpec{300, 0.7f, 1.3f}}; +static const std::array massAxisB = {o2::framework::AxisSpec{500, 4.2f, 6.2f}, o2::framework::AxisSpec{500, 4.2f, 6.2f}, o2::framework::AxisSpec{500, 5.4f, 7.4f}, o2::framework::AxisSpec{500, 4.2f, 6.2f}, o2::framework::AxisSpec{500, 4.4f, 6.4f}, o2::framework::AxisSpec{400, 5.0f, 6.6f}, o2::framework::AxisSpec{500, 4.2f, 6.2f}, o2::framework::AxisSpec{500, 4.2f, 6.2f}, o2::framework::AxisSpec{500, 4.2f, 6.2f}, o2::framework::AxisSpec{500, 4.2f, 6.2f}, o2::framework::AxisSpec{400, 5.0f, 6.6f}, o2::framework::AxisSpec{240, 5.8f, 7.0f}}; // default values for configurables // channels to trigger on for femto -constexpr int activeFemtoChannels[1][5] = {{1, 1, 1, 1, 0}}; // pD0, pD+, pDs, pLc, pXic -static const std::vector labelsColumnsFemtoChannels = {"protonDZero", "protonDPlus", "protonDs", "protonLc", "protonXic"}; +constexpr int activeFemtoChannels[2][5] = {{1, 1, 1, 1, 0}, // pD0, pD+, pDs, pLc, pXic + {0, 0, 0, 1, 0}}; // only for deLc +static const std::vector labelsColumnsFemtoChannels = {"DZero", "DPlus", "Ds", "Lc", "Xic"}; +static const std::vector labelsRowsFemtoChannels = {"protonCharmFemto", "deuteronCharmFemto"}; +constexpr float cutsPtThresholdsForFemto[1][2] = {{8., 1.4}}; // proton, deuteron +static const std::vector labelsColumnsPtThresholdsForFemto = {"Proton", "Deuteron"}; // min and max pT for all tracks combined (except for V0 and cascades) -constexpr float cutsPt[2][6] = {{1., 0.1, 0.8, 0.5, 0.1, 0.2}, - {100000., 100000., 5., 100000., 100000., 100000.}}; // beauty, D*, femto, SigmaC, Xic*+ -> SigmaC++K- -static const std::vector labelsColumnsCutsPt = {"Beauty", "DstarPlus", "Femto", "CharmBaryon", "SoftPiSigmaC", "SoftKaonXicResoToSigmaC"}; +constexpr float cutsPt[2][10] = {{1., 0.1, 0.8, 0.5, 0.1, 0.2, 0.4, 0.5, 0.3, 0.3}, + {100000., 100000., 5., 100000., 100000., 100000., 100000., 100000., 100000., 100000.}}; // beauty, D*, femto, SigmaC, Xic*+ -> SigmaC++K-, beauty to JPsi, Lc*->D0p +static const std::vector labelsColumnsCutsPt = {"Beauty", "DstarPlus", "PrForFemto", "CharmBaryon", "SoftPiSigmaC", "SoftKaonXicResoToSigmaC", "DeForFemto", "BeautyToJPsi", "PrForLcReso", "PrForThetaC"}; static const std::vector labelsRowsCutsPt = {"Minimum", "Maximum"}; // PID cuts -constexpr float cutsNsigma[3][6] = {{3., 3., 3., 5., 3., 3.}, // TPC proton from Lc, pi/K from D0, K from 3-prong, femto, pi/K from Xic/Omegac, K from Xic*->SigmaC-Kaon - {3., 3., 3., 2.5, 3., 3.}, // TOF proton from Lc, pi/K from D0, K from 3-prong, femto, pi/K from Xic/Omegac, K from Xic*->SigmaC-Kaon - {999., 999., 999., 2.5, 999., 999.}}; // Sum in quadrature of TPC and TOF (used only for femto for pT < 4 GeV/c) -static const std::vector labelsColumnsNsigma = {"PrFromLc", "PiKaFromDZero", "KaFrom3Prong", "Femto", "PiKaFromCharmBaryon", "SoftKaonFromXicResoToSigmaC"}; -static const std::vector labelsRowsNsigma = {"TPC", "TOF", "Comb"}; +constexpr float cutsNsigma[4][8] = { + {3., 3., 3., 5., 3., 3., 5., 3.}, // TPC proton from Lc, pi/K from D0, K from 3-prong, femto selected proton, pi/K from Xic/Omegac, K from Xic*->SigmaC-Kaon, femto selected deuteron, K/p from beauty->JPsiX + {3., 3., 3., 2.5, 3., 3., 5., 3.}, // TOF proton from Lc, pi/K from D0, K from 3-prong, femto selected proton, pi/K from Xic/Omegac, K from Xic*->SigmaC-Kaon, femto selected deuteron, K/p from beauty->JPsiX + {999., 999., 999., 2.5, 999., 999., 5., 999.}, // Sum in quadrature of TPC and TOF (used only for femto selected proton and deuteron for pT < 4 GeV/c) + {999., 999., 999., 999., 999., 999., -4., 999.} // ITS used only for femto selected deuteron for less than pt threshold +}; +static const std::vector labelsColumnsNsigma = {"PrFromLc", "PiKaFromDZero", "KaFrom3Prong", "PrForFemto", "PiKaFromCharmBaryon", "SoftKaonFromXicResoToSigmaC", "DeForFemto", "KaPrFromBeautyToJPsi"}; +static const std::vector labelsRowsNsigma = {"TPC", "TOF", "Comb", "ITS"}; // high pt constexpr float cutsHighPtThresholds[1][2] = {{8., 8.}}; // 2-prongs, 3-prongs static const std::vector labelsColumnsHighPtThresholds = {"2Prongs", "3Prongs"}; -// beauty -constexpr float cutsDeltaMassB[1][kNBeautyParticles] = {{0.4, 0.4, 0.4, 0.4, 0.4, 0.4}}; // B+, B0, B0toDstar, Bs, Lb, Xib -static const std::vector labelsColumnsDeltaMassB = {"Bplus", "BZero", "BZeroToDstar", "Bs", "Lb", "Xib"}; +namespace hf_trigger_cuts_presel_beauty +{ +static constexpr int nBinsPt = 2; +static constexpr int nCutVars = 4; +static constexpr int nCutVarsBtoJPsi = 6; +// default values for the pT bin edges (can be used to configure histogram axis) +// common for any beauty candidate +constexpr double binsPt[nBinsPt + 1] = { + 0., + 5., + 1000.0}; +auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +// default values for the cuts +constexpr double cuts[nBinsPt][nCutVars] = {{0.4, -1, -1, 10.}, /* 0 < pt < 5 */ + {0.4, -1, -1, 10.}}; /* 5 < pt < 1000 */ + +constexpr double cutsBtoJPsi[nBinsPt][nCutVarsBtoJPsi] = {{1., 0.6, 0.9, 0.02, 0.02, 0.1}, /* 0 < pt < 5 */ + {1., 0.8, 0.9, 0.02, 0.02, 0.1}}; /* 5 < pt < 1000 */ + +// row labels +static const std::vector labelsPt{}; +// column labels +static const std::vector labelsColumnsTopolBeauty = {"DeltaMassB", "minCPA", "minDecayLength", "maxImpParProd"}; +static const std::vector labelsColumnsCutsBeautyToJPsi = {"minPtMuon", "DeltaMassB", "minCPA", "minDecayLength", "DeltaMassKK", "DeltaMassKPi"}; + +} // namespace hf_trigger_cuts_presel_beauty // double charm -constexpr int activeDoubleCharmChannels[1][3] = {{1, 1, 1}}; // kDoubleCharm2P, kDoubleCharm3P, kDoubleCharmMix +constexpr int activeDoubleCharmChannels[2][3] = {{1, 1, 1}, {1, 1, 0}}; // kDoubleCharm2P, kDoubleCharm3P, kDoubleCharmMix (second column to keep non-prompt) static const std::vector labelsColumnsDoubleCharmChannels = {"DoubleCharm2Prong", "DoubleCharm3Prong", "DoubleCharmMix"}; +static const std::vector labelsRowsDoubleCharmChannels = {"", "KeepNonprompt"}; // charm resonances -constexpr float cutsCharmReso[3][11] = {{0.0, 0.0, 0.0, 0.0, 0.4, 0., 0.0, 0.00, 0.21, 0.21, 0.0}, - {0.155, 0.3, 0.3, 0.88, 0.88, 1.35, 0.18, 0.18, 0.25, 0.25, 0.8}, - {0.0, 0.0, 0.0, 0.0, 5.0, 0.0, 0.0, 6.0, 0.0, 6.0, 0.0}}; // D*+, D*0, Ds*0, Ds1+, Ds2*+, Xic*->D, SigmaC0, SigmaC++, SigmaC(2520)0, SigmaC(2520)++, Xic*->SigmaC -static const std::vector labelsColumnsDeltaMassCharmReso = {"DstarPlus", "DstarZero", "DsStarZero", "Ds1Plus", "Ds2StarPlus", "XicResoToD", "SigmaC0", "SigmaCPlusPlus", "SigmaC02520", "SigmaCPlusPlus2520", "XicResoToSigmaC"}; -static const std::vector labelsRowsDeltaMassCharmReso = {"deltaMassMin", "deltaMassMax", "ptMin"}; +constexpr float cutsCharmReso[4][13] = {{0.0, 0.0, 0.0, 0.0, 0.4, 0., 0.0, 0.00, 0.21, 0.21, 0.0, 0.7, 0.7}, + {0.155, 0.3, 0.3, 0.88, 0.88, 1.35, 0.18, 0.18, 0.25, 0.25, 0.8, 1.3, 1.3}, + {0.0, 0.0, 0.0, 0.0, 5.0, 0.0, 0.0, 6.0, 0.0, 6.0, 0.0, 0.0, 0.0}, + {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}; // D*+, D*0, Ds*0, Ds1+, Ds2*+, Xic*->D, SigmaC0, SigmaC++, SigmaC(2520)0, SigmaC(2520)++, Xic*->SigmaC, Lc*->D0P, Lc*->D*+P +static const std::vector labelsColumnsDeltaMassCharmReso = {"DstarPlus", "DstarZero", "DsStarZero", "Ds1Plus", "Ds2StarPlus", "XicResoToD", "SigmaC0", "SigmaCPlusPlus", "SigmaC02520", "SigmaCPlusPlus2520", "XicResoToSigmaC", "LcResoToD0Pr", "ThetaC"}; +static const std::vector labelsRowsDeltaMassCharmReso = {"deltaMassMin", "deltaMassMax", "ptMin", "ptMinCharmDaugh"}; // V0s for charm resonances constexpr float cutsV0s[1][6] = {{0.85, 0.97, 0.5, 4., 0.02, 0.01}}; // cosPaGamma, cosPaK0sLambda, radiusK0sLambda, nSigmaPrLambda, deltaMassK0S, deltaMassLambda static const std::vector labelsColumnsV0s = {"CosPaGamma", "CosPaK0sLambda", "RadiusK0sLambda", "NSigmaPrLambda", "DeltaMassK0s", "DeltaMassLambda"}; @@ -218,13 +363,20 @@ static const std::vector labelsColumnsV0s = {"CosPaGamma", "CosPaK0 // cascades for Xi + bachelor triggers constexpr float cutsCascades[1][8] = {{0.2, 1., 0.01, 0.01, 0.99, 0.99, 0.3, 3.}}; // ptXiBachelor, deltaMassXi, deltaMassLambda, cosPaXi, cosPaLambda, DCAxyXi, nSigmaPid static const std::vector labelsColumnsCascades = {"PtBachelor", "PtXi", "DeltaMassXi", "DeltaMassLambda", "CosPAXi", "CosPaLambda", "DCAxyXi", "NsigmaPid"}; -constexpr float cutsCharmBaryons[1][4] = {{3., 3., 2.35, 2.60}}; // MinPtXiPi, MinPtXiKa, MinMassXiPi, MinMassXiKa -static const std::vector labelsColumnsCharmBaryons = {"MinPtXiPi", "MinPtXiKa", "MinMassXiPi", "MinMassXiKa"}; +constexpr float cutsCharmBaryons[1][11] = {{5., 5., 1000., 2.35, 2.60, 2.35, 3., 3., 2.7, -2., -2.}}; // MinPtXiPi, MinPtXiKa, MinPtXiPiPi, MinMassXiPi, MinMassXiKa, MinMassXiPiPi, MaxMassXiPi, MaxMassXiKa, MaxMassXiPiPi, CosPaXiBach, CosPaXiBachBach +static const std::vector labelsColumnsCharmBarCuts = {"MinPtXiPi", "MinPtXiKa", "MinPtXiPiPi", "MinMassXiPi", "MinMassXiKa", "MinMassXiPiPi", "MaxMassXiPi", "MaxMassXiKa", "MaxMassXiPiPi", "CosPaXiBach", "CosPaXiBachBach"}; + +constexpr int requireStrangenessTrackedXi[1][2] = {{1, 0}}; +static const std::vector labelsColumnsCharmBaryons = {"CharmBarToXiBach", "CharmBarToXiBachBach"}; // dummy array static const std::vector labelsEmpty{}; -static constexpr double cutsTrackDummy[o2::analysis::hf_cuts_single_track::nBinsPtTrack][o2::analysis::hf_cuts_single_track::nCutVarsTrack] = {{0., 10.}, {0., 10.}, {0., 10.}, {0., 10.}, {0., 10.}, {0., 10.}}; -o2::framework::LabeledArray cutsSingleTrackDummy{cutsTrackDummy[0], o2::analysis::hf_cuts_single_track::nBinsPtTrack, o2::analysis::hf_cuts_single_track::nCutVarsTrack, o2::analysis::hf_cuts_single_track::labelsPtTrack, o2::analysis::hf_cuts_single_track::labelsCutVarTrack}; +static constexpr double cutsTrackDummy[o2::analysis::hf_cuts_single_track::NBinsPtTrack][o2::analysis::hf_cuts_single_track::NCutVarsTrack] = {{0., 10.}, {0., 10.}, {0., 10.}, {0., 10.}, {0., 10.}, {0., 10.}}; +o2::framework::LabeledArray cutsSingleTrackDummy{cutsTrackDummy[0], o2::analysis::hf_cuts_single_track::NBinsPtTrack, o2::analysis::hf_cuts_single_track::NCutVarsTrack, o2::analysis::hf_cuts_single_track::labelsPtTrack, o2::analysis::hf_cuts_single_track::labelsCutVarTrack}; + +// manual downscale factors for tests +constexpr double defDownscaleFactors[kNtriggersHF][1] = {{1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}, {1.1}}; // one for each trigger +static const std::vector labelsDownscaleFactor = {"Downscale factor"}; // Main helper class @@ -240,21 +392,54 @@ class HfFilterHelper mPtThresholdHighPt2Prongs = threshold2Prongs; mPtThresholdHighPt3Prongs = threshold3Prongs; } + void setPtTriggerThresholdsForFemto(float thresholdProtons, float thresholdDeuterons) + { + mPtThresholdProtonForFemto = thresholdProtons; + mPtThresholdDeuteronForFemto = thresholdDeuterons; + } + void setForceTofForFemto(bool forceTofProtons, bool forceTofDeuterons) + { + mForceTofProtonForFemto = forceTofProtons; + mForceTofDeuteronForFemto = forceTofDeuterons; + } void setPtBinsSingleTracks(std::vector ptBins) { mPtBinsTracks = ptBins; } - void setCutsSingleTrackBeauty(o2::framework::LabeledArray cutsSingleTrack3P, o2::framework::LabeledArray cutsSingleTrack4P) + void setPtBinsBeautyHadrons(std::vector ptBins) { mPtBinsBeautyHadrons = ptBins; } + void setCutsSingleTrackBeauty(o2::framework::LabeledArray cutsSingleTrack3P, o2::framework::LabeledArray cutsSingleTrack4P, o2::framework::LabeledArray cutsSingleToJPsi) { mCutsSingleTrackBeauty3Prong = cutsSingleTrack3P; mCutsSingleTrackBeauty4Prong = cutsSingleTrack4P; + mCutsSingleTrackBeautyToJPsi = cutsSingleToJPsi; + } + void setCutsBhadrons(o2::framework::LabeledArray cutsBplus, o2::framework::LabeledArray cutsB0toDstar, o2::framework::LabeledArray cutsBc, o2::framework::LabeledArray cutsB0, o2::framework::LabeledArray cutsBs, o2::framework::LabeledArray cutsLb, o2::framework::LabeledArray cutsXib) + { + mCutsBhad[kBplus] = cutsBplus; + mCutsBhad[kB0toDStar] = cutsB0toDstar; + mCutsBhad[kBc] = cutsBc; + mCutsBhad[kB0] = cutsB0; + mCutsBhad[kBs] = cutsBs; + mCutsBhad[kLb] = cutsLb; + mCutsBhad[kXib] = cutsXib; + } + void setCutsBtoJPsi(o2::framework::LabeledArray cuts) + { + mCutsBhadToJPsi = cuts; } void setPtLimitsProtonForFemto(float minPt, float maxPt) { mPtMinProtonForFemto = minPt; mPtMaxProtonForFemto = maxPt; } - void setPtLimitsBeautyBachelor(float minPt, float maxPt) + void setPtLimitsDeuteronForFemto(float minPt, float maxPt) + { + mPtMinDeuteronForFemto = minPt; + mPtMaxDeuteronForFemto = maxPt; + } + void setPtLimitsBeautyBachelor(float minPt, float maxPt, float minPtBtoJPsiBach, float maxPtBtoJPsiBach) { mPtMinBeautyBachelor = minPt; mPtMaxBeautyBachelor = maxPt; + mPtMinBeautyToJPsiBachelor = minPtBtoJPsiBach; + mPtMaxBeautyToJPsiBachelor = maxPtBtoJPsiBach; } void setPtLimitsDstarSoftPion(float minPt, float maxPt) { @@ -291,9 +476,19 @@ class HfFilterHelper mPtMinCharmBaryonBachelor = minPt; mPtMaxCharmBaryonBachelor = maxPt; } + void setPtLimitsLcResonanceBachelor(float minPt, float maxPt) + { + mPtMinLcResonanceBachelor = minPt; + mPtMaxLcResonanceBachelor = maxPt; + } + void setPtLimitsThetaCBachelor(float minPt, float maxPt) + { + mPtMinThetaCBachelor = minPt; + mPtMaxThetaCBachelor = maxPt; + } - void setPtThresholdPidStrategyForFemto(float ptThreshold) { mPtThresholdPidStrategyForFemto = ptThreshold; } - void setNsigmaProtonCutsForFemto(std::array nSigmaCuts) { mNSigmaPrCutsForFemto = nSigmaCuts; } + void setNsigmaProtonCutsForFemto(std::array nSigmaCuts) { mNSigmaPrCutsForFemto = nSigmaCuts; } + void setNsigmaDeuteronCutsForFemto(std::array nSigmaCuts) { mNSigmaDeCutsForFemto = nSigmaCuts; } void setNsigmaProtonCutsForCharmBaryons(float nSigmaTpc, float nSigmaTof) { mNSigmaTpcPrCutForCharmBaryons = nSigmaTpc; @@ -309,6 +504,11 @@ class HfFilterHelper mNSigmaTpcPiKaCutForDzero = nSigmaTpc; mNSigmaTofPiKaCutForDzero = nSigmaTof; } + void setNsigmaKaonProtonCutsForBeautyToJPsi(float nSigmaTpc, float nSigmaTof) + { + mNSigmaTpcPrKaCutForBeautyToJPsi = nSigmaTpc; + mNSigmaTofPrKaCutForBeautyToJPsi = nSigmaTof; + } void setV0Selections(float minGammaCosPa, float minK0sLambdaCosPa, float minK0sLambdaRadius, float nSigmaPrFromLambda, float deltaMassK0s, float deltaMassLambda) { mMinGammaCosinePa = minGammaCosPa; @@ -341,6 +541,21 @@ class HfFilterHelper mNSigmaTofKaonFromXicResoToSigmaC = nSigmaTof; } + void setXiBachelorSelections(float ptMinXiPi, float ptMinXiKa, float ptMinXiPiPi, float massMinXiPi, float massMinXiKa, float massMinXiPiPi, float massMaxXiPi, float massMaxXiKa, float massMaxXiPiPi, float cosPaMinXiBach, float cosPaMinXiBachBach) + { + mPtMinXiBach[0] = ptMinXiPi; + mPtMinXiBach[1] = ptMinXiKa; + mPtMinXiBach[2] = ptMinXiPiPi; + mMassMinXiBach[0] = massMinXiPi; + mMassMinXiBach[1] = massMinXiKa; + mMassMinXiBach[2] = massMinXiPiPi; + mMassMaxXiBach[0] = massMaxXiPi; + mMassMaxXiBach[1] = massMaxXiKa; + mMassMaxXiBach[2] = massMaxXiPiPi; + mCosPaMinXiBach[0] = cosPaMinXiBach; + mCosPaMinXiBach[1] = cosPaMinXiBachBach; + } + void setTpcPidCalibrationOption(int opt) { mTpcPidCalibrationOption = opt; } void setMassResolParametrisation(std::string recoPass) @@ -366,10 +581,10 @@ class HfFilterHelper bool isSelectedHighPt2Prong(const T& pt); template bool isSelectedHighPt3Prong(const T& pt); - template - int8_t isSelectedTrackForSoftPionOrBeauty(const T& track, const T1& trackPar, const T2& dca, const int& whichTrigger); + template + int16_t isSelectedTrackForSoftPionOrBeauty(const T& track, const T1& trackPar, const T2& dca); template - bool isSelectedProton4Femto(const T1& track, const T2& trackPar, const int& activateQA, H2 hProtonTPCPID, H2 hProtonTOFPID, bool forceTof); + bool isSelectedTrack4Femto(const T1& track, const T2& trackPar, const int& activateQA, H2 hTPCPID, H2 hTOFPID, const int& trackSpecies); template int8_t isDzeroPreselected(const T& trackPos, const T& trackNeg); template @@ -390,113 +605,160 @@ class HfFilterHelper int8_t isSelectedSigmaCInDeltaMassRange(const T& pTrackSameChargeFirst, const T& pTrackSameChargeSecond, const T& pTrackOppositeCharge, const T& pTrackSoftPi, const float ptSigmaC, const int8_t isSelectedLc, H2 hMassVsPt, const int& activateQA); template int8_t isSelectedXicInMassRange(const T& pTrackSameChargeFirst, const T& pTrackSameChargeSecond, const T& pTrackOppositeCharge, const float& ptXic, const int8_t isSelected, const int& activateQA, H2 hMassVsPt); - template - int8_t isSelectedV0(const V0& v0, const std::array& dauTracks, const Coll& collision, const int& activateQA, H2 hV0Selected, std::array& hArmPod); + template + int8_t isSelectedV0(const V0& v0, const int& activateQA, H2 hV0Selected, std::array& hArmPod); template - inline bool isSelectedPhoton(const Photon& photon, const std::array& dauTracks, const int& activateQA, H2 hV0Selected, std::array& hArmPod); - template - bool isSelectedCascade(const Casc& casc, const std::array& dauTracks, const Coll& collision); + bool isSelectedPhoton(const Photon& photon, const std::array& dauTracks, const int& activateQA, H2 hV0Selected, std::array& hArmPod); + template + bool isSelectedCascade(const Casc& casc); template - int8_t isSelectedBachelorForCharmBaryon(const T& track, const T2& dca); + int16_t isSelectedBachelorForCharmBaryon(const T& track, const T2& dca); + template + bool isSelectedProton4CharmOrBeautyBaryons(const T& track); template int8_t isBDTSelected(const T& scores, const U& thresholdBDTScores); template bool isSelectedKaonFromXicResoToSigmaC(const T& track); - + template + bool isSelectedBhadron(T1 const& pVecTrack0, T1 const& pVecTrack1, T2 const& dcaTrack0, T2 const& dcaTrack1, const T3& primVtx, const T4& secVtx, const int whichB); + template + bool isSelectedBhadronInMassRange(T1 const& ptCand, T2 const& massCand, const int whichB); + template + bool isSelectedBzeroToDstar(T1 const& pVecTrack0, T1 const& pVecTrack1, T1 const& pVecTrack2, const T2& primVtx, const T3& secVtx); + template + int8_t isSelectedBhadronToJPsi(std::array pVecDauTracks, std::array tracksDauNoMu, const T3& primVtx, const T4& secVtx, const int& activateQA, std::array& hMassVsPt); + template + bool isCharmHadronMassInSbRegions(T1 const& massHypo1, T1 const& massHypo2, const float& lowLimitSB, const float& upLimitSB); + template + bool isSelectedXiBach(T const& trackParCasc, T const& trackParBachelor, int8_t isSelBachelor, C const& collision, o2::vertexing::DCAFitterN<2>& dcaFitter, const int& activateQA, H2 hMassVsPtXiPi, H2 hMassVsPtXiKa); + template + bool isSelectedXiBachBach(T const& trackParCasc, std::array const& trackParBachelor, C const& collision, o2::vertexing::DCAFitterN& dcaFitter, const int& activateQA, H2 hMassVsPtXiPiPi); + template + bool isSelectedProtonFromLcResoOrThetaC(const T& track); // helpers template T computeRelativeMomentum(const std::array& pTrack, const std::array& CharmCandMomentum, const T& CharmMass); template int computeNumberOfCandidates(std::vector> indices); + template + int setVtxConfiguration(T1 vertexer, bool useAbsDCA); + template + bool buildV0(V const& v0Indices, T const& tracks, C const& collision, o2::vertexing::DCAFitterN<2>& dcaFitter, const std::vector& vetoedTrackIds, V0Cand& v0Cand); + template + bool buildCascade(Casc const& cascIndices, V const& v0Indices, T const& tracks, C const& collision, o2::vertexing::DCAFitterN<2>& dcaFitter, const std::vector& vetoedTrackIds, CascCand& cascCand); // PID - void setValuesBB(o2::ccdb::CcdbApi& ccdbApi, aod::BCsWithTimestamps::iterator const& bunchCrossing, const std::array& ccdbPaths); + void setValuesBB(o2::ccdb::CcdbApi& ccdbApi, aod::BCsWithTimestamps::iterator const& bunchCrossing, const std::array& ccdbPaths); void setTpcRecalibMaps(o2::framework::Service const& ccdb, aod::BCsWithTimestamps::iterator const& bunchCrossing, const std::string& ccdbPath); private: // selections - template - bool isSelectedKaon4Charm3Prong(const T& track); - template - bool isSelectedProton4CharmBaryons(const T& track); + template + bool isSelectedKaon4Charm3ProngOrBeautyToJPsi(const T& track); // PID + float getTPCSplineCalib(const float tpcPin, const float dEdx, const int& pidSpecies); template - double getTPCSplineCalib(const T& track, const int& pidSpecies); + float getTPCSplineCalib(const T& track, const int& pidSpecies); + float getTPCPostCalib(const float tpcPin, const float tpcNCls, const float eta, const float tpcNSigma, const int& pidSpecies); template float getTPCPostCalib(const T& track, const int& pidSpecies); // helpers template int findBin(T1 const& binsPt, T2 value); + template + std::array alphaAndQtAP(std::array const& momPos, std::array const& momNeg); // selections - std::vector mPtBinsTracks{}; // vector of pT bins for single track cuts - o2::framework::LabeledArray mCutsSingleTrackBeauty3Prong{}; // dca selections for the 3-prong b-hadron pion daughter - o2::framework::LabeledArray mCutsSingleTrackBeauty4Prong{}; // dca selections for the 4-prong b-hadron pion daughter - float mPtMinSoftPionForDstar{0.1}; // minimum pt for the D*+ soft pion - float mPtMinSoftPionForSigmaC{0.1}; // minimum pt for the Σ0,++ soft pion - float mPtMaxSoftPionForSigmaC{10000.f}; // maximum pt for the Σ0,++ soft pion - float mPtMinSoftKaonForXicResoToSigmaC{0.1}; // minimum pt for the soft kaon of Xic* to SigmaC-Kaon - float mPtMaxSoftKaonForXicResoToSigmaC{10000.f}; // maximum pt for the soft kaon of Xic* to SigmaC-Kaon - float mPtMinBeautyBachelor{0.5}; // minimum pt for the b-hadron pion daughter - float mPtMinProtonForFemto{0.8}; // minimum pt for the proton for femto - float mPtMinCharmBaryonBachelor{0.5}; // minimum pt for the bachelor pion from Xic/Omegac decays - float mPtMaxSoftPionForDstar{2.}; // maximum pt for the D*+ soft pion - float mPtMaxBeautyBachelor{100000.}; // maximum pt for the b-hadron pion daughter - float mPtMaxProtonForFemto{5.0}; // maximum pt for the proton for femto - float mPtMaxCharmBaryonBachelor{100000.}; // maximum pt for the bachelor pion from Xic/Omegac decays - float mPtThresholdPidStrategyForFemto{8.}; // pt threshold to change strategy for proton PID for femto - float mPtMinSigmaCZero{0.f}; // pt min SigmaC0 candidate - float mPtMinSigmaC2520Zero{0.f}; // pt min SigmaC(2520)0 candidate - float mPtMinSigmaCPlusPlus{0.f}; // pt min SigmaC++ candidate - float mPtMinSigmaC2520PlusPlus{0.f}; // pt min SigmaC(2520)++ candidate - std::array mNSigmaPrCutsForFemto{3., 3., 3.}; // cut values for Nsigma TPC, TOF, combined for femto protons - float mNSigmaTpcPrCutForCharmBaryons{3.}; // maximum Nsigma TPC for protons in Lc and Xic decays - float mNSigmaTofPrCutForCharmBaryons{3.}; // maximum Nsigma TOF for protons in Lc and Xic decays - float mNSigmaTpcKaCutFor3Prongs{3.}; // maximum Nsigma TPC for kaons in 3-prong decays - float mNSigmaTofKaCutFor3Prongs{3.}; // maximum Nsigma TOF for kaons in 3-prong decays - float mNSigmaTpcPiKaCutForDzero{3.}; // maximum Nsigma TPC for pions/kaons in D0 decays - float mNSigmaTofPiKaCutForDzero{3.}; // maximum Nsigma TOF for pions/kaons in D0 decays - float mDeltaMassMinSigmaCZero{0.155}; // minimum delta mass M(pKpipi)-M(pKpi) of SigmaC0 candidates - float mDeltaMassMaxSigmaCZero{0.18}; // maximum delta mass M(pKpipi)-M(pKpi) of SigmaC0 candidates - float mDeltaMassMinSigmaC2520Zero{0.2}; // minimum delta mass M(pKpipi)-M(pKpi) of SigmaC(2520)0 candidates - float mDeltaMassMaxSigmaC2520Zero{0.26}; // maximum delta mass M(pKpipi)-M(pKpi) of SigmaC(2520)0 candidates - float mDeltaMassMinSigmaCPlusPlus{0.155}; // minimum delta mass M(pKpipi)-M(pKpi) of SigmaC++ candidates - float mDeltaMassMaxSigmaCPlusPlus{0.18}; // maximum delta mass M(pKpipi)-M(pKpi) of SigmaC++ candidates - float mDeltaMassMinSigmaC2520PlusPlus{0.2}; // minimum delta mass M(pKpipi)-M(pKpi) of SigmaC(2520)++ candidates - float mDeltaMassMaxSigmaC2520PlusPlus{0.26}; // maximum delta mass M(pKpipi)-M(pKpi) of SigmaC(2520)++ candidates - float mMinGammaCosinePa{0.85}; // minimum cosp for gammas - float mMinK0sLambdaCosinePa{0.97}; // minimum cosp for K0S and Lambda in charm excited decays - float mMinK0sLambdaRadius{0.5}; // minimum radius for K0S and Lambda in charm excited decays - float mMaxNsigmaPrForLambda{4.}; // maximum Nsigma TPC and TOF for protons in Lambda decays - float mDeltaMassK0s{0.02}; // delta mass cut for K0S in charm excited decays - float mDeltaMassLambda{0.01}; // delta mass cut for Lambda in charm excited decays - float mMinPtXiBachelor{0.1}; // minimum pt for Xi bachelor in Xic/Omegac decays - float mMinPtXi{1.}; // minimum pt for Xi in Xic/Omegac decays - float mDeltaMassXi{0.01}; // delta mass cut for Xi in Xic/Omegac decays - float mDeltaMassLambdaFromXi{0.01}; // delta mass cut for Lambda <- Xi in Xic/Omegac decays - float mCosPaXi{0.99}; // minimum cosp for Xi in Xic/Omegac decays - float mCosPaLambdaFromXi{0.99}; // minimum cosp for Xi in Xic/Omegac decays - float mMaxDcaXyXi{0.3}; // maximum dca for Xi in Xic/Omegac decays - float mMaxNsigmaXiDau{3.}; // maximum Nsigma TPC and TOF for Xi daughter tracks - o2::framework::LabeledArray mCutsSingleTrackCharmBaryonBachelor{}; // dca selections for the bachelor pion from Xic/Omegac decays - float mNSigmaTpcPiCharmBaryonBachelor{3.}; // maximum Nsigma TPC for pions in Xic/Omegac decays - float mNSigmaTofPiCharmBaryonBachelor{3.}; // maximum Nsigma TOF for pions in Xic/Omegac decays - float mNumSigmaDeltaMassCharmHad{2.5}; // number of sigmas for delta mass cut for charm hadrons in B and charm excited decays - std::array mSigmaPars2Prongs{}; // parameters (intercept, slope) for parametrisation of mass sigma vs pT for 2-prongs - std::array mDeltaMassPars2Prongs{}; // parameters (intercept, slope) for parametrisation of mass delta wrt PDG vs pT for 2-prongs - std::array mSigmaPars3Prongs{}; // parameters (intercept, slope) for parametrisation of mass sigma vs pT for 3-prongs - std::array mDeltaMassPars3Prongs{}; // parameters (intercept, slope) for parametrisation of mass delta wrt PDG vs pT for 3-prongs - float mPtThresholdHighPt2Prongs{8.}; // threshold for high pT triggers for 2-prongs - float mPtThresholdHighPt3Prongs{8.}; // threshold for high pT triggers for 3-prongs - float mNSigmaTpcKaonFromXicResoToSigmaC{3.}; // maximum Nsigma TPC for kaons in Xic*->SigmaC-Kaon - float mNSigmaTofKaonFromXicResoToSigmaC{3.}; // maximum Nsigma TOF for kaons in Xic*->SigmaC-Kaon + std::vector mPtBinsTracks{}; // vector of pT bins for single track cuts + std::vector mPtBinsBeautyHadrons{}; // vector of pT bins for beauty hadron candidates + o2::framework::LabeledArray mCutsSingleTrackBeauty3Prong{}; // dca selections for the 3-prong b-hadron pion daughter + o2::framework::LabeledArray mCutsSingleTrackBeauty4Prong{}; // dca selections for the 4-prong b-hadron pion daughter + o2::framework::LabeledArray mCutsSingleTrackBeautyToJPsi{}; // dca selections for the b-hadron -> JPsi X daughters (not the muons) + float mPtMinSoftPionForDstar{0.1}; // minimum pt for the D*+ soft pion + float mPtMinSoftPionForSigmaC{0.1}; // minimum pt for the Σ0,++ soft pion + float mPtMaxSoftPionForSigmaC{10000.f}; // maximum pt for the Σ0,++ soft pion + float mPtMinSoftKaonForXicResoToSigmaC{0.1}; // minimum pt for the soft kaon of Xic* to SigmaC-Kaon + float mPtMaxSoftKaonForXicResoToSigmaC{10000.f}; // maximum pt for the soft kaon of Xic* to SigmaC-Kaon + float mPtMinBeautyBachelor{0.5}; // minimum pt for the b-hadron pion daughter + float mPtMinBeautyToJPsiBachelor{0.5}; // minimum pt for the b-hadron -> JPsi X daughters (not the muons) + float mPtMinProtonForFemto{0.8}; // minimum pt for the proton for femto + float mPtMinDeuteronForFemto{0.8}; // minimum pt for the deuteron for femto + float mPtMinCharmBaryonBachelor{0.5}; // minimum pt for the bachelor pion from Xic/Omegac decays + float mPtMinLcResonanceBachelor{0.3}; // minimum pt for the bachelor proton from Lc resonance decays + float mPtMinThetaCBachelor{0.3}; // minimum pt for the bachelor proton from ThetaC decays + float mPtMaxSoftPionForDstar{2.}; // maximum pt for the D*+ soft pion + float mPtMaxBeautyBachelor{100000.}; // maximum pt for the b-hadron pion daughter + float mPtMaxBeautyToJPsiBachelor{100000.}; // maximum pt for the b-hadron -> JPsi X daughters (not the muons) + float mPtMaxProtonForFemto{5.0}; // maximum pt for the proton for femto + float mPtMaxDeuteronForFemto{5.0}; // maximum pt for the deuteron for femto + float mPtMaxCharmBaryonBachelor{100000.}; // maximum pt for the bachelor pion from Xic/Omegac decays + float mPtMaxLcResonanceBachelor{100000.}; // maximum pt for the bachelor proton from Lc resonance decays + float mPtMaxThetaCBachelor{100000.}; // maximum pt for the bachelor proton from ThetaC decays + float mPtThresholdProtonForFemto{8.}; // pt threshold to change strategy for proton PID for femto + float mPtThresholdDeuteronForFemto{1.4}; // pt threshold to change strategy for deuteron PID for femto + float mPtMinSigmaCZero{0.f}; // pt min SigmaC0 candidate + float mPtMinSigmaC2520Zero{0.f}; // pt min SigmaC(2520)0 candidate + float mPtMinSigmaCPlusPlus{0.f}; // pt min SigmaC++ candidate + float mPtMinSigmaC2520PlusPlus{0.f}; // pt min SigmaC(2520)++ candidate + std::array mNSigmaPrCutsForFemto{3., 3., 3., -4.}; // cut values for Nsigma TPC, TOF, combined, ITS for femto protons + std::array mNSigmaDeCutsForFemto{3., 3., 3., -4.}; // cut values for Nsigma TPC, TOF, combined, ITS for femto deuterons + float mNSigmaTpcPrCutForCharmBaryons{3.}; // maximum Nsigma TPC for protons in Lc and Xic decays + float mNSigmaTofPrCutForCharmBaryons{3.}; // maximum Nsigma TOF for protons in Lc and Xic decays + float mNSigmaTpcKaCutFor3Prongs{3.}; // maximum Nsigma TPC for kaons in 3-prong decays + float mNSigmaTofKaCutFor3Prongs{3.}; // maximum Nsigma TOF for kaons in 3-prong decays + float mNSigmaTpcPiKaCutForDzero{3.}; // maximum Nsigma TPC for pions/kaons in D0 decays + float mNSigmaTofPiKaCutForDzero{3.}; // maximum Nsigma TOF for pions/kaons in D0 decays + float mNSigmaTpcPrKaCutForBeautyToJPsi{3.}; // maximum Nsigma TPC for kaons and protons in B->JPsiX decays + float mNSigmaTofPrKaCutForBeautyToJPsi{3.}; // maximum Nsigma TPC for kaons and protons in B->JPsiX decays + float mDeltaMassMinSigmaCZero{0.155}; // minimum delta mass M(pKpipi)-M(pKpi) of SigmaC0 candidates + float mDeltaMassMaxSigmaCZero{0.18}; // maximum delta mass M(pKpipi)-M(pKpi) of SigmaC0 candidates + float mDeltaMassMinSigmaC2520Zero{0.2}; // minimum delta mass M(pKpipi)-M(pKpi) of SigmaC(2520)0 candidates + float mDeltaMassMaxSigmaC2520Zero{0.26}; // maximum delta mass M(pKpipi)-M(pKpi) of SigmaC(2520)0 candidates + float mDeltaMassMinSigmaCPlusPlus{0.155}; // minimum delta mass M(pKpipi)-M(pKpi) of SigmaC++ candidates + float mDeltaMassMaxSigmaCPlusPlus{0.18}; // maximum delta mass M(pKpipi)-M(pKpi) of SigmaC++ candidates + float mDeltaMassMinSigmaC2520PlusPlus{0.2}; // minimum delta mass M(pKpipi)-M(pKpi) of SigmaC(2520)++ candidates + float mDeltaMassMaxSigmaC2520PlusPlus{0.26}; // maximum delta mass M(pKpipi)-M(pKpi) of SigmaC(2520)++ candidates + float mMinGammaCosinePa{0.85}; // minimum cosp for gammas + float mMinK0sLambdaCosinePa{0.97}; // minimum cosp for K0S and Lambda in charm excited decays + float mMinK0sLambdaRadius{0.5}; // minimum radius for K0S and Lambda in charm excited decays + float mMaxNsigmaPrForLambda{4.}; // maximum Nsigma TPC and TOF for protons in Lambda decays + float mDeltaMassK0s{0.02}; // delta mass cut for K0S in charm excited decays + float mDeltaMassLambda{0.01}; // delta mass cut for Lambda in charm excited decays + float mMinPtXiBachelor{0.1}; // minimum pt for Xi bachelor in Xic/Omegac decays + float mMinPtXi{1.}; // minimum pt for Xi in Xic/Omegac decays + float mDeltaMassXi{0.01}; // delta mass cut for Xi in Xic/Omegac decays + float mDeltaMassLambdaFromXi{0.01}; // delta mass cut for Lambda <- Xi in Xic/Omegac decays + float mCosPaXi{0.99}; // minimum cosp for Xi in Xic/Omegac decays + float mCosPaLambdaFromXi{0.99}; // minimum cosp for Xi in Xic/Omegac decays + float mMaxDcaXyXi{0.3}; // maximum dca for Xi in Xic/Omegac decays + float mMaxNsigmaXiDau{3.}; // maximum Nsigma TPC and TOF for Xi daughter tracks + o2::framework::LabeledArray mCutsSingleTrackCharmBaryonBachelor{}; // dca selections for the bachelor pion from Xic/Omegac decays + float mNSigmaTpcPiCharmBaryonBachelor{3.}; // maximum Nsigma TPC for pions in Xic/Omegac decays + float mNSigmaTofPiCharmBaryonBachelor{3.}; // maximum Nsigma TOF for pions in Xic/Omegac decays + float mNumSigmaDeltaMassCharmHad{2.5}; // number of sigmas for delta mass cut for charm hadrons in B and charm excited decays + std::array mSigmaPars2Prongs{}; // parameters (intercept, slope) for parametrisation of mass sigma vs pT for 2-prongs + std::array mDeltaMassPars2Prongs{}; // parameters (intercept, slope) for parametrisation of mass delta wrt PDG vs pT for 2-prongs + std::array mSigmaPars3Prongs{}; // parameters (intercept, slope) for parametrisation of mass sigma vs pT for 3-prongs + std::array mDeltaMassPars3Prongs{}; // parameters (intercept, slope) for parametrisation of mass delta wrt PDG vs pT for 3-prongs + float mPtThresholdHighPt2Prongs{8.}; // threshold for high pT triggers for 2-prongs + float mPtThresholdHighPt3Prongs{8.}; // threshold for high pT triggers for 3-prongs + float mNSigmaTpcKaonFromXicResoToSigmaC{3.}; // maximum Nsigma TPC for kaons in Xic*->SigmaC-Kaon + float mNSigmaTofKaonFromXicResoToSigmaC{3.}; // maximum Nsigma TOF for kaons in Xic*->SigmaC-Kaon + bool mForceTofProtonForFemto = true; // flag to force TOF PID for protons + bool mForceTofDeuteronForFemto = false; // flag to force TOF PID for deuterons + std::array mPtMinXiBach{5., 5., 5.}; // minimum pT for XiBachelor candidates + std::array mMassMinXiBach{2.35, 2.6, 2.35}; // minimum invariant-mass for XiBachelor candidates + std::array mMassMaxXiBach{3.0, 3.0, 2.7}; // maximum invariant-mass for XiBachelor candidates + std::array mCosPaMinXiBach{-2.f, -2.f}; // minimum cosine of pointing angle for XiBachelor candidates + std::array, kNBeautyParticles> mCutsBhad{}; // selections for B-hadron candidates (DeltaMass, CPA, DecayLength, ImpactParameterProduct) + o2::framework::LabeledArray mCutsBhadToJPsi{}; // selections for B->JPsi candidates (PtMinMu, DeltaMass, CPA, DecayLength) // PID recalibrations - int mTpcPidCalibrationOption{0}; // Option for TPC PID calibration (0 -> AO2D, 1 -> postcalibrations, 2 -> alternative bethe bloch parametrisation) - std::array mHistMapPiPrKa{}; // Map for TPC PID postcalibrations for pions, kaon and protons - std::array, 6> mBetheBlochPiKaPr{}; // Bethe-Bloch parametrisations for pions, antipions, kaons, antikaons, protons, antiprotons in TPC + int mTpcPidCalibrationOption{0}; // Option for TPC PID calibration (0 -> AO2D, 1 -> postcalibrations, 2 -> alternative bethe bloch parametrisation) + std::array mHistMapPiPrKaDe{}; // Map for TPC PID postcalibrations for pions, kaon, protons and deuterons + std::array, 8> mBetheBlochPiKaPrDe{}; // Bethe-Bloch parametrisations for pions, antipions, kaons, antikaons, protons, antiprotons, deuterons, antideuterons in TPC }; /// Selection of high-pt 2-prong candidates @@ -526,11 +788,11 @@ inline bool HfFilterHelper::isSelectedHighPt3Prong(const T& pt) /// \param trackPar is a track parameter /// \param dca is the 2d array with dcaXY and dcaZ of the track /// \return a flag that encodes the selection for soft pions BIT(kSoftPion), tracks for beauty BIT(kForBeauty), or soft pions for beauty BIT(kSoftPionForBeauty) -template -inline int8_t HfFilterHelper::isSelectedTrackForSoftPionOrBeauty(const T& track, const T1& trackPar, const T2& dca, const int& whichTrigger) +template +inline int16_t HfFilterHelper::isSelectedTrackForSoftPionOrBeauty(const T& track, const T1& trackPar, const T2& dca) { - int8_t retValue{BIT(kSoftPion) | BIT(kForBeauty) | BIT(kSoftPionForBeauty) | BIT(kSoftPionForSigmaC)}; + int16_t retValue{BIT(kSoftPion) | BIT(kForBeauty) | BIT(kSoftPionForBeauty) | BIT(kSoftPionForSigmaC)}; if (!track.isGlobalTrackWoDCA()) { return kRejected; @@ -556,7 +818,7 @@ inline int8_t HfFilterHelper::isSelectedTrackForSoftPionOrBeauty(const T& track, return kRejected; } - if (whichTrigger == kSigmaCPPK || whichTrigger == kSigmaC0K0) { + if constexpr (whichTrigger == kSigmaCPPK || whichTrigger == kSigmaC0K0) { // SigmaC0,++ soft pion pt cut if (pT < mPtMinSoftPionForSigmaC || pT > mPtMaxSoftPionForSigmaC) { @@ -574,18 +836,29 @@ inline int8_t HfFilterHelper::isSelectedTrackForSoftPionOrBeauty(const T& track, } // below only regular beauty tracks, not required for soft pions - if (pT < mPtMinBeautyBachelor || pT > mPtMaxBeautyBachelor) { + float ptMin{-1.f}, ptMax{1000.f}; + if constexpr (whichTrigger == kBeauty3P || whichTrigger == kBeauty4P) { + ptMin = mPtMinBeautyBachelor; + ptMax = mPtMaxBeautyBachelor; + } else if constexpr (whichTrigger == kBtoJPsiKa || whichTrigger == kBtoJPsiPi || whichTrigger == kBtoJPsiKstar || whichTrigger == kBtoJPsiPhi || whichTrigger == kBtoJPsiPrKa) { + ptMin = mPtMinBeautyToJPsiBachelor; + ptMax = mPtMaxBeautyToJPsiBachelor; + } + + if (pT < ptMin || pT > ptMax) { CLRBIT(retValue, kForBeauty); } - float minDca = 1000.f; - float maxDca = 0.f; - if (whichTrigger == kBeauty3P) { + float minDca{1000.f}, maxDca{0.f}; + if constexpr (whichTrigger == kBeauty3P) { minDca = mCutsSingleTrackBeauty3Prong.get(pTBinTrack, 0u); maxDca = mCutsSingleTrackBeauty3Prong.get(pTBinTrack, 1u); - } else if (whichTrigger == kBeauty4P) { + } else if constexpr (whichTrigger == kBeauty4P) { minDca = mCutsSingleTrackBeauty4Prong.get(pTBinTrack, 0u); maxDca = mCutsSingleTrackBeauty4Prong.get(pTBinTrack, 1u); + } else if constexpr (whichTrigger == kBtoJPsiKa || whichTrigger == kBtoJPsiPi || whichTrigger == kBtoJPsiKstar || whichTrigger == kBtoJPsiPhi || whichTrigger == kBtoJPsiPrKa) { + minDca = mCutsSingleTrackBeautyToJPsi.get(pTBinTrack, 0u); + maxDca = mCutsSingleTrackBeautyToJPsi.get(pTBinTrack, 1u); } if (std::fabs(dca[0]) < minDca) { // minimum DCAxy @@ -600,19 +873,44 @@ inline int8_t HfFilterHelper::isSelectedTrackForSoftPionOrBeauty(const T& track, return retValue; } -/// Basic selection of proton candidates +/// Basic selection of proton or deuteron candidates /// \param track is a track /// \param trackPar is a track parameter /// \param activateQA flag to activate the filling of QA histos /// \param hProtonTPCPID histo with NsigmaTPC vs. p /// \param hProtonTOFPID histo with NsigmaTOF vs. p -/// \param forceTof flag to force TOF PID +/// \param trackSpecies flag to choose proton or deuteron /// \return true if track passes all cuts template -inline bool HfFilterHelper::isSelectedProton4Femto(const T1& track, const T2& trackPar, const int& activateQA, H2 hProtonTPCPID, H2 hProtonTOFPID, bool forceTof) +inline bool HfFilterHelper::isSelectedTrack4Femto(const T1& track, const T2& trackPar, const int& activateQA, H2 hTPCPID, H2 hTOFPID, const int& trackSpecies) { float pt = trackPar.getPt(); - if (pt < mPtMinProtonForFemto || pt > mPtMaxProtonForFemto) { + float ptMin, ptMax, ptThresholdPidStrategy; + std::array nSigmaCuts; + bool forceTof = false; // flag to force TOF PID + + // Assign particle-specific parameters + switch (trackSpecies) { + case kProtonForFemto: + ptMin = mPtMinProtonForFemto; + ptMax = mPtMaxProtonForFemto; + nSigmaCuts = mNSigmaPrCutsForFemto; + forceTof = mForceTofProtonForFemto; + ptThresholdPidStrategy = mPtThresholdProtonForFemto; + break; + case kDeuteronForFemto: + ptMin = mPtMinDeuteronForFemto; + ptMax = mPtMaxDeuteronForFemto; + nSigmaCuts = mNSigmaDeCutsForFemto; + forceTof = mForceTofDeuteronForFemto; + ptThresholdPidStrategy = mPtThresholdDeuteronForFemto; + break; + default: + return false; // Unknown particle type + } + + // Common selection criteria + if (pt < ptMin || pt > ptMax) { return false; } @@ -623,39 +921,60 @@ inline bool HfFilterHelper::isSelectedProton4Femto(const T1& track, const T2& tr if (!track.isGlobalTrack()) { return false; // use only global tracks } - - float NSigmaTPC = track.tpcNSigmaPr(); - float NSigmaTOF = track.tofNSigmaPr(); + // PID evaluation + float NSigmaITS = (trackSpecies == kProtonForFemto) ? track.itsNSigmaPr() : track.itsNSigmaDe(); // only used for deuteron + float NSigmaTPC = (trackSpecies == kProtonForFemto) ? track.tpcNSigmaPr() : track.tpcNSigmaDe(); + float NSigmaTOF = (trackSpecies == kProtonForFemto) ? track.tofNSigmaPr() : track.tofNSigmaDe(); if (!forceTof && !track.hasTOF()) { NSigmaTOF = 0.; // always accepted } + // Apply TPC PID post-calibration(only available for proton, dummy for deuteron) if (mTpcPidCalibrationOption == 1) { - NSigmaTPC = getTPCPostCalib(track, kPr); + NSigmaTPC = getTPCPostCalib(track, trackSpecies == kProtonForFemto ? kPr : kDe); } else if (mTpcPidCalibrationOption == 2) { if (track.sign() > 0) { - NSigmaTPC = getTPCSplineCalib(track, kPr); + NSigmaTPC = getTPCSplineCalib(track, trackSpecies == kProtonForFemto ? kPr : kDe); } else { - NSigmaTPC = getTPCSplineCalib(track, kAntiPr); + NSigmaTPC = getTPCSplineCalib(track, trackSpecies == kProtonForFemto ? kAntiPr : kAntiDe); } } float NSigma = std::sqrt(NSigmaTPC * NSigmaTPC + NSigmaTOF * NSigmaTOF); - if (trackPar.getPt() <= mPtThresholdPidStrategyForFemto) { - if (NSigma > mNSigmaPrCutsForFemto[2]) { - return false; + if (trackSpecies == kProtonForFemto) { + if (pt <= ptThresholdPidStrategy) { + if (NSigma > nSigmaCuts[2]) { + return false; + } + } else { + if (std::fabs(NSigmaTPC) > nSigmaCuts[0] || std::fabs(NSigmaTOF) > nSigmaCuts[1]) { + return false; + } } - } else { - if (std::fabs(NSigmaTPC) > mNSigmaPrCutsForFemto[0] || std::fabs(NSigmaTOF) > mNSigmaPrCutsForFemto[1]) { - return false; + } + // For deuterons: Determine whether to apply TOF based on pt threshold + if (trackSpecies == kDeuteronForFemto) { + // Apply different PID strategy in different pt range + // one side selection only + if (pt <= ptThresholdPidStrategy) { + if (NSigmaTPC < -nSigmaCuts[0] || NSigmaITS < -nSigmaCuts[3]) { // Use TPC and ITS below the threshold, NSigmaITS for deuteron with a lower limit + return false; + } + } else { + if (NSigmaTOF < -nSigmaCuts[1] || NSigmaTPC < -nSigmaCuts[0]) { // Use combined TPC and TOF above the threshold + return false; + } } } if (activateQA > 1) { - hProtonTPCPID->Fill(track.p(), NSigmaTPC); - if (forceTof || track.hasTOF()) { - hProtonTOFPID->Fill(track.p(), NSigmaTOF); + hTPCPID->Fill(track.p(), NSigmaTPC); + if ((forceTof || track.hasTOF())) { + if (trackSpecies == kProtonForFemto) + hTOFPID->Fill(track.p(), NSigmaTOF); + else if (trackSpecies == kDeuteronForFemto && pt > ptThresholdPidStrategy) + hTOFPID->Fill(track.p(), NSigmaTOF); } } @@ -673,7 +992,7 @@ inline int8_t HfFilterHelper::isDplusPreselected(const T& trackOppositeCharge) int8_t retValue = 0; // check PID of opposite charge track - if (!isSelectedKaon4Charm3Prong(trackOppositeCharge)) { + if (!isSelectedKaon4Charm3ProngOrBeautyToJPsi(trackOppositeCharge)) { return retValue; } @@ -693,7 +1012,7 @@ inline int8_t HfFilterHelper::isDsPreselected(const P& pTrackSameChargeFirst, co int8_t retValue = 0; // check PID of opposite charge track - if (!isSelectedKaon4Charm3Prong(trackOppositeCharge)) { + if (!isSelectedKaon4Charm3ProngOrBeautyToJPsi(trackOppositeCharge)) { return retValue; } @@ -721,13 +1040,13 @@ inline int8_t HfFilterHelper::isCharmBaryonPreselected(const T& trackSameChargeF { int8_t retValue = 0; // check PID of opposite charge track - if (!isSelectedKaon4Charm3Prong(trackOppositeCharge)) { + if (!isSelectedKaon4Charm3ProngOrBeautyToJPsi(trackOppositeCharge)) { return retValue; } - if (isSelectedProton4CharmBaryons(trackSameChargeFirst)) { + if (isSelectedProton4CharmOrBeautyBaryons(trackSameChargeFirst)) { retValue |= BIT(0); } - if (isSelectedProton4CharmBaryons(trackSameChargeSecond)) { + if (isSelectedProton4CharmOrBeautyBaryons(trackSameChargeSecond)) { retValue |= BIT(1); } @@ -982,7 +1301,7 @@ inline int8_t HfFilterHelper::isSelectedSigmaCInDeltaMassRange(const T& pTrackSa return retValue; } -/// Mass selection of Xic candidates to build Lb candidates +/// Mass selection of Xic candidates to build Xib candidates /// \param pTrackSameChargeFirst is the first same-charge track momentum /// \param pTrackSameChargeSecond is the second same-charge track momentum /// \param pTrackOppositeCharge is the opposite charge track momentum @@ -1022,14 +1341,12 @@ inline int8_t HfFilterHelper::isSelectedXicInMassRange(const T& pTrackSameCharge /// Basic selection of V0 candidates /// \param v0 is the v0 candidate -/// \param dauTracks is a 2-element array with positive and negative V0 daughter tracks -/// \param collision is the current collision /// \param activateQA flag to fill QA histos /// \param hV0Selected is the pointer to the QA histo for selected V0S /// \param hArmPod is the pointer to an array of QA histo AP plot after selection /// \return an integer passes all cuts -template -inline int8_t HfFilterHelper::isSelectedV0(const V0& v0, const std::array& dauTracks, const Coll& /*collision*/, const int& activateQA, H2 hV0Selected, std::array& hArmPod) +template +inline int8_t HfFilterHelper::isSelectedV0(const V0& v0, const int& activateQA, H2 hV0Selected, std::array& hArmPod) { int8_t isSelected{BIT(kK0S) | BIT(kLambda) | BIT(kAntiLambda)}; @@ -1040,7 +1357,7 @@ inline int8_t HfFilterHelper::isSelectedV0(const V0& v0, const std::array& } // eta of daughters - if (std::fabs(dauTracks[0].eta()) > 1. || std::fabs(dauTracks[1].eta()) > 1.) { // cut all V0 daughters with |eta| > 1. + if (std::fabs(v0.etaPos) > 1. || std::fabs(v0.etaNeg) > 1.) { // cut all V0 daughters with |eta| > 1. if (activateQA > 1) { for (int iV0{kK0S}; iV0 < kNV0; ++iV0) { hV0Selected->Fill(1., iV0); @@ -1050,7 +1367,7 @@ inline int8_t HfFilterHelper::isSelectedV0(const V0& v0, const std::array& } // V0 radius - if (v0.v0radius() < mMinK0sLambdaRadius) { + if (v0.v0radius < mMinK0sLambdaRadius) { for (int iV0{kK0S}; iV0 < kNV0; ++iV0) { CLRBIT(isSelected, iV0); if (activateQA > 1) { @@ -1059,9 +1376,8 @@ inline int8_t HfFilterHelper::isSelectedV0(const V0& v0, const std::array& } } - auto v0CosinePa = v0.v0cosPA(); for (int iV0{kK0S}; iV0 < kNV0; ++iV0) { - if (TESTBIT(isSelected, iV0) && v0CosinePa < mMinK0sLambdaCosinePa) { + if (TESTBIT(isSelected, iV0) && v0.v0cosPA < mMinK0sLambdaCosinePa) { CLRBIT(isSelected, iV0); if (activateQA > 1) { hV0Selected->Fill(3., iV0); @@ -1070,19 +1386,19 @@ inline int8_t HfFilterHelper::isSelectedV0(const V0& v0, const std::array& } // armenteros-podolanski / mass - if (TESTBIT(isSelected, kK0S) && std::fabs(v0.mK0Short() - massK0S) > mDeltaMassK0s) { + if (TESTBIT(isSelected, kK0S) && std::fabs(v0.mK0Short - massK0S) > mDeltaMassK0s) { CLRBIT(isSelected, kK0S); if (activateQA > 1) { hV0Selected->Fill(4., kK0S); } } - if (TESTBIT(isSelected, kLambda) && std::fabs(v0.mLambda() - massLambda) > mDeltaMassLambda) { + if (TESTBIT(isSelected, kLambda) && std::fabs(v0.mLambda - massLambda) > mDeltaMassLambda) { CLRBIT(isSelected, kLambda); if (activateQA > 1) { hV0Selected->Fill(4., kLambda); } } - if (TESTBIT(isSelected, kAntiLambda) && std::fabs(v0.mAntiLambda() - massLambda) > mDeltaMassLambda) { + if (TESTBIT(isSelected, kAntiLambda) && std::fabs(v0.mAntiLambda - massLambda) > mDeltaMassLambda) { CLRBIT(isSelected, kAntiLambda); if (activateQA > 1) { hV0Selected->Fill(4., kAntiLambda); @@ -1091,13 +1407,13 @@ inline int8_t HfFilterHelper::isSelectedV0(const V0& v0, const std::array& // DCA V0 and V0 daughters for (int iV0{kK0S}; iV0 < kNV0; ++iV0) { - if (TESTBIT(isSelected, iV0) && v0.dcav0topv() > 0.1f) { // we want only primary V0s + if (TESTBIT(isSelected, iV0) && v0.dcav0topv > 0.1f) { // we want only primary V0s CLRBIT(isSelected, iV0); if (activateQA > 1) { hV0Selected->Fill(5., iV0); } } - if (TESTBIT(isSelected, iV0) && (v0.dcaV0daughters() > 1.f || std::fabs(v0.dcapostopv()) < 0.05f || std::fabs(v0.dcanegtopv()) < 0.05f)) { + if (TESTBIT(isSelected, iV0) && (v0.dcaV0daughters > 1.f || std::fabs(v0.dcapostopv) < 0.05f || std::fabs(v0.dcanegtopv) < 0.05f)) { CLRBIT(isSelected, iV0); if (activateQA > 1) { hV0Selected->Fill(6., iV0); @@ -1106,25 +1422,29 @@ inline int8_t HfFilterHelper::isSelectedV0(const V0& v0, const std::array& } // PID (Lambda/AntiLambda only) - float nSigmaPrTpc[2] = {dauTracks[0].tpcNSigmaPr(), dauTracks[1].tpcNSigmaPr()}; - float nSigmaPrTof[2] = {dauTracks[0].tofNSigmaPr(), dauTracks[1].tofNSigmaPr()}; + float nSigmaPrTpc[2] = {v0.nSigmaPrTpcPos, v0.nSigmaPrTpcNeg}; + float nSigmaPrTof[2] = {v0.nSigmaPrTofPos, v0.nSigmaPrTofNeg}; + float pInTpc[2] = {v0.pinTpcPos, v0.pinTpcNeg}; + float nClsTpc[2] = {v0.nClsFoundTpcPos, v0.nClsFoundTpcNeg}; + float etaDaus[2] = {v0.etaPos, v0.etaNeg}; + float signalTpc[2] = {v0.signalTpcPos, v0.signalTpcNeg}; if (mTpcPidCalibrationOption == 1) { for (int iDau{0}; iDau < 2; ++iDau) { - nSigmaPrTpc[iDau] = getTPCPostCalib(dauTracks[iDau], kPr); + nSigmaPrTpc[iDau] = getTPCPostCalib(pInTpc[iDau], nClsTpc[iDau], etaDaus[iDau], nSigmaPrTpc[iDau], kPr); } } else if (mTpcPidCalibrationOption == 2) { for (int iDau{0}; iDau < 2; ++iDau) { - nSigmaPrTpc[iDau] = getTPCSplineCalib(dauTracks[iDau], (iDau == 0) ? kPr : kAntiPr); + nSigmaPrTpc[iDau] = getTPCSplineCalib(pInTpc[iDau], signalTpc[iDau], (iDau == 0) ? kPr : kAntiPr); } } - if (TESTBIT(isSelected, kLambda) && ((dauTracks[0].hasTPC() && std::fabs(nSigmaPrTpc[0]) > mMaxNsigmaPrForLambda) || (dauTracks[0].hasTOF() && std::fabs(nSigmaPrTof[0]) > mMaxNsigmaPrForLambda))) { + if (TESTBIT(isSelected, kLambda) && (std::fabs(nSigmaPrTpc[0]) > mMaxNsigmaPrForLambda || (v0.hasTofPos && std::fabs(nSigmaPrTof[0]) > mMaxNsigmaPrForLambda))) { CLRBIT(isSelected, kLambda); if (activateQA > 1) { hV0Selected->Fill(7., kLambda); } } - if (TESTBIT(isSelected, kAntiLambda) && ((dauTracks[1].hasTPC() && std::fabs(nSigmaPrTpc[1]) > mMaxNsigmaPrForLambda) || (dauTracks[1].hasTOF() && std::fabs(nSigmaPrTof[1]) > mMaxNsigmaPrForLambda))) { + if (TESTBIT(isSelected, kAntiLambda) && (std::fabs(nSigmaPrTpc[1]) > mMaxNsigmaPrForLambda || (v0.hasTofNeg && std::fabs(nSigmaPrTof[1]) > mMaxNsigmaPrForLambda))) { CLRBIT(isSelected, kAntiLambda); if (activateQA > 1) { hV0Selected->Fill(7., kAntiLambda); @@ -1134,7 +1454,7 @@ inline int8_t HfFilterHelper::isSelectedV0(const V0& v0, const std::array& if (activateQA) { for (int iV0{kK0S}; iV0 < kNV0; ++iV0) { if (TESTBIT(isSelected, iV0)) { - hArmPod[iV0]->Fill(v0.alpha(), v0.qtarm()); + hArmPod[iV0]->Fill(v0.alpha, v0.qtarm); if (activateQA > 1) { hV0Selected->Fill(8., iV0); } @@ -1196,123 +1516,127 @@ inline bool HfFilterHelper::isSelectedPhoton(const Photon& photon, const std::ar /// Basic selection of cascade candidates /// \param casc is the cascade candidate -/// \param dauTracks is a 3-element array with bachelor, positive and negative V0 daughter tracks -/// \param collision is the collision /// \return true if cascade passes all cuts -template -inline bool HfFilterHelper::isSelectedCascade(const Casc& casc, const std::array& dauTracks, const Coll& collision) +template +inline bool HfFilterHelper::isSelectedCascade(const Casc& casc) { // Xi min pT - if (casc.pt() < mMinPtXi) { + if (casc.pt < mMinPtXi) { return false; } // eta of daughters - if (std::fabs(dauTracks[0].eta()) > 1. || std::fabs(dauTracks[1].eta()) > 1. || std::fabs(dauTracks[2].eta()) > 1.) { // cut all V0 daughters with |eta| > 1. + if (std::fabs(casc.v0.etaPos) > 1. || std::fabs(casc.v0.etaNeg) > 1. || std::fabs(casc.etaBach) > 1.) { // cut all V0 daughters with |eta| > 1. return false; } // V0 radius - if (casc.v0radius() < 1.2) { + if (casc.v0.v0radius < 1.2) { return false; } // cascade radius - if (casc.cascradius() < 0.6) { + if (casc.cascradius < 0.6) { return false; } // V0 cosp - if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < mCosPaLambdaFromXi) { + if (casc.v0.v0cosPA < mCosPaLambdaFromXi) { return false; } // cascade cosp - if (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < mCosPaXi) { + if (casc.casccosPA < mCosPaXi) { return false; } // cascade DCAxy to PV - if (std::fabs(casc.dcaXYCascToPV()) > mMaxDcaXyXi) { + if (std::fabs(casc.dcaXYCascToPV) > mMaxDcaXyXi) { return false; } // Xi bachelor min pT - if (dauTracks[0].pt() < mMinPtXiBachelor) { + if (casc.ptBach < mMinPtXiBachelor) { return false; } // dau dca - if (std::fabs(casc.dcaV0daughters()) > 1.f || std::fabs(casc.dcacascdaughters()) > 1.f) { + if (std::fabs(casc.v0.dcaV0daughters) > 1.f || std::fabs(casc.dcacascdaughters) > 1.f) { return false; } // cascade mass - if (std::fabs(casc.mXi() - massXi) > mDeltaMassXi) { + if (std::fabs(casc.mXi - massXi) > mDeltaMassXi) { return false; } // V0 mass - if (std::fabs(casc.mLambda() - massLambda) > mDeltaMassLambdaFromXi) { + if (std::fabs(casc.v0.mLambda - massLambda) > mDeltaMassLambdaFromXi) { return false; } // PID - float nSigmaPrTpc[3] = {-999., dauTracks[1].tpcNSigmaPr(), dauTracks[2].tpcNSigmaPr()}; - float nSigmaPrTof[3] = {-999., dauTracks[1].tofNSigmaPr(), dauTracks[2].tofNSigmaPr()}; - float nSigmaPiTpc[3] = {dauTracks[0].tpcNSigmaPi(), dauTracks[1].tpcNSigmaPi(), dauTracks[2].tpcNSigmaPi()}; - float nSigmaPiTof[3] = {dauTracks[0].tofNSigmaPi(), dauTracks[1].tofNSigmaPi(), dauTracks[2].tofNSigmaPi()}; + float nSigmaPrTpc[3] = {-999, casc.v0.nSigmaPrTpcPos, casc.v0.nSigmaPrTpcNeg}; + float nSigmaPrTof[3] = {-999., casc.v0.nSigmaPrTofPos, casc.v0.nSigmaPrTofNeg}; + float nSigmaPiTpc[3] = {casc.nSigmaPiTpcBach, casc.v0.nSigmaPiTpcPos, casc.v0.nSigmaPiTpcNeg}; + float nSigmaPiTof[3] = {casc.nSigmaPiTofBach, casc.v0.nSigmaPiTofPos, casc.v0.nSigmaPiTofNeg}; + float pInTpc[3] = {casc.pinTpcBach, casc.v0.pinTpcPos, casc.v0.pinTpcNeg}; + float nClsTpc[3] = {casc.nClsFoundTpcBach, casc.v0.nClsFoundTpcPos, casc.v0.nClsFoundTpcNeg}; + float nCrossedRowsTpc[3] = {casc.nClsCrossedRowsTpcBach, casc.v0.nClsCrossedRowsTpcPos, casc.v0.nClsCrossedRowsTpcNeg}; + float crossedRowsOverFindableClsTpc[3] = {casc.crossedRowsOverFindableClsTpcBach, casc.v0.crossedRowsOverFindableClsTpcPos, casc.v0.crossedRowsOverFindableClsTpcNeg}; + float etaDaus[3] = {casc.etaBach, casc.v0.etaPos, casc.v0.etaNeg}; + float signalTpc[3] = {casc.signalTpcBach, casc.v0.signalTpcPos, casc.v0.signalTpcNeg}; if (mTpcPidCalibrationOption == 1) { for (int iDau{0}; iDau < 3; ++iDau) { - nSigmaPiTpc[iDau] = getTPCPostCalib(dauTracks[iDau], kPi); + nSigmaPiTpc[iDau] = getTPCPostCalib(pInTpc[iDau], nClsTpc[iDau], etaDaus[iDau], nSigmaPrTpc[iDau], kPi); if (iDau == 0) { continue; } - nSigmaPrTpc[iDau] = getTPCPostCalib(dauTracks[iDau], kPr); + nSigmaPrTpc[iDau] = getTPCPostCalib(pInTpc[iDau], nClsTpc[iDau], etaDaus[iDau], nSigmaPrTpc[iDau], kPr); } } else if (mTpcPidCalibrationOption == 2) { for (int iDau{0}; iDau < 3; ++iDau) { - nSigmaPiTpc[iDau] = getTPCSplineCalib(dauTracks[iDau], (dauTracks[iDau].sign() > 0) ? kPi : kAntiPi); + nSigmaPiTpc[iDau] = getTPCSplineCalib(pInTpc[iDau], signalTpc[iDau], (iDau == 0) ? kPi : kAntiPi); if (iDau == 0) { continue; } - nSigmaPrTpc[iDau] = getTPCSplineCalib(dauTracks[iDau], (dauTracks[iDau].sign() > 0) ? kPr : kAntiPr); + nSigmaPrTpc[iDau] = getTPCSplineCalib(pInTpc[iDau], signalTpc[iDau], (iDau == 0) ? kPr : kAntiPr); } } // PID to V0 tracks - if (dauTracks[0].sign() < 0) { // Xi- - if ((dauTracks[1].hasTPC() && std::fabs(nSigmaPrTpc[1]) > mMaxNsigmaXiDau) && (dauTracks[1].hasTOF() && std::fabs(nSigmaPrTof[1]) > mMaxNsigmaXiDau)) { + if (casc.sign < 0) { // Xi- + if (std::fabs(nSigmaPrTpc[1]) > mMaxNsigmaXiDau && (casc.v0.hasTofPos && std::fabs(nSigmaPrTof[1]) > mMaxNsigmaXiDau)) { return false; } - if ((dauTracks[2].hasTPC() && std::fabs(nSigmaPiTpc[2]) > mMaxNsigmaXiDau) && (dauTracks[2].hasTOF() && std::fabs(nSigmaPiTof[2]) > mMaxNsigmaXiDau)) { + if (std::fabs(nSigmaPiTpc[2]) > mMaxNsigmaXiDau && (casc.v0.hasTofNeg && std::fabs(nSigmaPiTof[2]) > mMaxNsigmaXiDau)) { return false; } - } else if (dauTracks[0].sign() > 0) { // Xi+ - if ((dauTracks[2].hasTPC() && std::fabs(nSigmaPrTpc[2]) > mMaxNsigmaXiDau) && (dauTracks[2].hasTOF() && std::fabs(nSigmaPrTof[2]) > mMaxNsigmaXiDau)) { + } else if (casc.sign > 0) { // Xi+ + if (std::fabs(nSigmaPrTpc[2]) > mMaxNsigmaXiDau && (casc.v0.hasTofNeg && std::fabs(nSigmaPrTof[2]) > mMaxNsigmaXiDau)) { return false; } - if ((dauTracks[1].hasTPC() && std::fabs(nSigmaPiTpc[1]) > mMaxNsigmaXiDau) && (dauTracks[1].hasTOF() && std::fabs(nSigmaPiTof[1]) > mMaxNsigmaXiDau)) { + if (std::fabs(nSigmaPiTpc[1]) > mMaxNsigmaXiDau && (casc.v0.hasTofPos && std::fabs(nSigmaPiTof[1]) > mMaxNsigmaXiDau)) { return false; } } // bachelor PID - if ((dauTracks[0].hasTPC() && std::fabs(nSigmaPiTpc[0]) > mMaxNsigmaXiDau) && (dauTracks[0].hasTOF() && std::fabs(nSigmaPiTof[0]) > mMaxNsigmaXiDau)) { + if (std::fabs(nSigmaPiTpc[0]) > mMaxNsigmaXiDau && (casc.hasTofBach && std::fabs(nSigmaPiTof[0]) > mMaxNsigmaXiDau)) { return false; } // additional track cuts - for (const auto& dauTrack : dauTracks) { + for (int iTrack{0}; iTrack < 3; ++iTrack) { // TPC clusters selections - if (dauTrack.tpcNClsFound() < 70) { // TODO: put me as a configurable please + if (nClsTpc[iTrack] < 70) { // TODO: put me as a configurable please return false; } - if (dauTrack.tpcNClsCrossedRows() < 70) { + if (nCrossedRowsTpc[iTrack] < 70) { return false; } - if (dauTrack.tpcCrossedRowsOverFindableCls() < 0.8) { + if (crossedRowsOverFindableClsTpc[iTrack] < 0.8) { return false; } } @@ -1325,9 +1649,9 @@ inline bool HfFilterHelper::isSelectedCascade(const Casc& casc, const std::array /// \param dca is the 2d array with dcaXY and dcaZ of the track /// \return 0 if rejected, or a bitmap that contains the information whether it is selected as pion and/or kaon template -inline int8_t HfFilterHelper::isSelectedBachelorForCharmBaryon(const T& track, const T2& dca) +inline int16_t HfFilterHelper::isSelectedBachelorForCharmBaryon(const T& track, const T2& dca) { - int8_t retValue{BIT(kPionForCharmBaryon) | BIT(kKaonForCharmBaryon)}; + int16_t retValue{BIT(kPionForCharmBaryon) | BIT(kKaonForCharmBaryon)}; if (!track.isGlobalTrackWoDCA()) { return kRejected; @@ -1479,9 +1803,9 @@ inline int HfFilterHelper::computeNumberOfCandidates(std::vector> /// \param ccdbApi is Api for CCDB /// \param bunchCrossing is the timestamp of bunchcrossing for the run number /// \param ccdbPaths are the paths on CCDB for pions, antipions, kaons, antikaons, protons, antiprotons -inline void HfFilterHelper::setValuesBB(o2::ccdb::CcdbApi& ccdbApi, aod::BCsWithTimestamps::iterator const& bunchCrossing, const std::array& ccdbPaths) +inline void HfFilterHelper::setValuesBB(o2::ccdb::CcdbApi& ccdbApi, aod::BCsWithTimestamps::iterator const& bunchCrossing, const std::array& ccdbPaths) { - for (int iSpecie{0u}; iSpecie < 6; ++iSpecie) { + for (int iSpecie{0u}; iSpecie < 8; ++iSpecie) { std::map metadata; auto hSpline = ccdbApi.retrieveFromTFileAny(ccdbPaths[iSpecie], metadata, bunchCrossing.timestamp()); @@ -1490,12 +1814,12 @@ inline void HfFilterHelper::setValuesBB(o2::ccdb::CcdbApi& ccdbApi, aod::BCsWith } TAxis* axis = hSpline->GetXaxis(); - mBetheBlochPiKaPr[iSpecie] = {static_cast(hSpline->GetBinContent(axis->FindBin("bb1"))), - static_cast(hSpline->GetBinContent(axis->FindBin("bb2"))), - static_cast(hSpline->GetBinContent(axis->FindBin("bb3"))), - static_cast(hSpline->GetBinContent(axis->FindBin("bb4"))), - static_cast(hSpline->GetBinContent(axis->FindBin("bb5"))), - static_cast(hSpline->GetBinContent(axis->FindBin("Resolution")))}; + mBetheBlochPiKaPrDe[iSpecie] = {static_cast(hSpline->GetBinContent(axis->FindBin("bb1"))), + static_cast(hSpline->GetBinContent(axis->FindBin("bb2"))), + static_cast(hSpline->GetBinContent(axis->FindBin("bb3"))), + static_cast(hSpline->GetBinContent(axis->FindBin("bb4"))), + static_cast(hSpline->GetBinContent(axis->FindBin("bb5"))), + static_cast(hSpline->GetBinContent(axis->FindBin("Resolution")))}; } } @@ -1509,16 +1833,16 @@ inline void HfFilterHelper::setTpcRecalibMaps(o2::framework::Service mapNames = {"mean_map_pion", "sigma_map_pion", "mean_map_kaon", "sigma_map_kaon", "mean_map_proton", "sigma_map_proton"}; + std::array mapNames = {"mean_map_pion", "sigma_map_pion", "mean_map_kaon", "sigma_map_kaon", "mean_map_proton", "sigma_map_proton", "mean_map_deuteron", "sigma_map_deuteron"}; for (size_t iMap = 0; iMap < mapNames.size(); iMap++) { - mHistMapPiPrKa[iMap] = nullptr; + mHistMapPiPrKaDe[iMap] = nullptr; } for (size_t iMap = 0; iMap < mapNames.size(); iMap++) { - mHistMapPiPrKa[iMap] = reinterpret_cast(calibList->FindObject(mapNames[iMap].data())); - if (!mHistMapPiPrKa[iMap]) { + mHistMapPiPrKaDe[iMap] = reinterpret_cast(calibList->FindObject(mapNames[iMap].data())); + if (!mHistMapPiPrKaDe[iMap]) { LOG(fatal) << "Cannot find histogram: " << mapNames[iMap].data(); return; } @@ -1530,8 +1854,8 @@ inline void HfFilterHelper::setTpcRecalibMaps(o2::framework::Service -inline bool HfFilterHelper::isSelectedProton4CharmBaryons(const T& track) +template +inline bool HfFilterHelper::isSelectedProton4CharmOrBeautyBaryons(const T& track) { float NSigmaTPC = track.tpcNSigmaPr(); float NSigmaTOF = track.tofNSigmaPr(); @@ -1546,11 +1870,20 @@ inline bool HfFilterHelper::isSelectedProton4CharmBaryons(const T& track) } } - if (std::fabs(NSigmaTPC) > mNSigmaTpcPrCutForCharmBaryons) { - return false; - } - if (track.hasTOF() && std::fabs(NSigmaTOF) > mNSigmaTofPrCutForCharmBaryons) { - return false; + if constexpr (is4beauty) { + if (std::fabs(NSigmaTPC) > mNSigmaTpcPrKaCutForBeautyToJPsi) { + return false; + } + if (track.hasTOF() && std::fabs(NSigmaTOF) > mNSigmaTofPrKaCutForBeautyToJPsi) { + return false; + } + } else { + if (std::fabs(NSigmaTPC) > mNSigmaTpcPrCutForCharmBaryons) { + return false; + } + if (track.hasTOF() && std::fabs(NSigmaTOF) > mNSigmaTofPrCutForCharmBaryons) { + return false; + } } return true; @@ -1572,7 +1905,7 @@ inline bool HfFilterHelper::isSelectedKaonFromXicResoToSigmaC(const T& track) if constexpr (isKaonTrack) { /// if the kaon is a track, and not a K0s (V0), check the PID as well - return isSelectedKaon4Charm3Prong(track); + return isSelectedKaon4Charm3ProngOrBeautyToJPsi(track); } return true; @@ -1581,8 +1914,8 @@ inline bool HfFilterHelper::isSelectedKaonFromXicResoToSigmaC(const T& track) /// Basic selection of kaon candidates for charm candidates /// \param track is a track /// \return true if track passes all cuts -template -inline bool HfFilterHelper::isSelectedKaon4Charm3Prong(const T& track) +template +inline bool HfFilterHelper::isSelectedKaon4Charm3ProngOrBeautyToJPsi(const T& track) { float NSigmaTPC = track.tpcNSigmaKa(); float NSigmaTOF = track.tofNSigmaKa(); @@ -1597,22 +1930,496 @@ inline bool HfFilterHelper::isSelectedKaon4Charm3Prong(const T& track) } } - if (std::fabs(NSigmaTPC) > mNSigmaTpcKaCutFor3Prongs) { + if constexpr (is4beauty) { + if (std::fabs(NSigmaTPC) > mNSigmaTpcPrKaCutForBeautyToJPsi) { + return false; + } + if (track.hasTOF() && std::fabs(NSigmaTOF) > mNSigmaTofPrKaCutForBeautyToJPsi) { + return false; + } + } else { + if (std::fabs(NSigmaTPC) > mNSigmaTpcKaCutFor3Prongs) { + return false; + } + if (track.hasTOF() && std::fabs(NSigmaTOF) > mNSigmaTofKaCutFor3Prongs) { + return false; + } + } + + return true; +} + +/// Basic selection of proton candidates forLc and ThetaC decays +/// \param track is a track +/// \return true if track passes all cuts +template +inline bool HfFilterHelper::isSelectedProtonFromLcResoOrThetaC(const T& track) +{ + + // pt selections + float pt = track.pt(); + if constexpr (is4ThetaC) { + if (pt < mPtMinThetaCBachelor || pt > mPtMaxThetaCBachelor) { + return false; + } + } else { + if (pt < mPtMinLcResonanceBachelor || pt > mPtMaxLcResonanceBachelor) { + return false; + } + } + + return true; +} + +/// Method to perform selections for B+ candidates after vertex reconstruction +/// \param pVecTrack0 is the array for the candidate D daughter momentum after reconstruction of secondary vertex +/// \param pVecTrack1 is the array for the candidate bachelor pion momentum after reconstruction of secondary vertex +/// \param dcaTrack0 is the dca of the D daughter track +/// \param dcaTrack1 is the dca of the pion daughter track +/// \param primVtx is the primary vertex +/// \param secVtx is the secondary vertex +/// \param whichB is the B-hadron species +/// \return true if the beauty candidate passes all cuts +template +inline bool HfFilterHelper::isSelectedBhadron(T1 const& pVecTrack0, T1 const& pVecTrack1, T2 const& dcaTrack0, T2 const& dcaTrack1, const T3& primVtx, const T4& secVtx, const int whichB) +{ + if (whichB == kB0toDStar) { + LOGP(fatal, "Wrong function used for selection of B0 -> D*pi, please use isSelectedBzeroToDstar"); + } + + auto pVecB = RecoDecay::pVec(pVecTrack0, pVecTrack1); + auto pTB = RecoDecay::pt(pVecB); + auto binPtB = findBin(mPtBinsBeautyHadrons, pTB); + if (binPtB == -1) { return false; } - if (track.hasTOF() && std::fabs(NSigmaTOF) > mNSigmaTofKaCutFor3Prongs) { + auto cpa = RecoDecay::cpa(primVtx, secVtx, pVecB); + auto decayLength = RecoDecay::distance(primVtx, secVtx); + auto impactParameterProduct = dcaTrack0[0] * dcaTrack1[0]; + + if (cpa < mCutsBhad[whichB].get(binPtB, 1u)) { + return false; + } + if (decayLength < mCutsBhad[whichB].get(binPtB, 2u)) { + return false; + } + if (impactParameterProduct > mCutsBhad[whichB].get(binPtB, 3u)) { return false; } return true; } -/// Update the TPC PID baesd on the spline of particles +/// Method to perform selections for B+ candidates after vertex reconstruction +/// \param pVecTrack0 is the array for the candidate D daughter momentum after reconstruction of secondary vertex +/// \param pVecTrack1 is the array for the soft pion momentum after reconstruction of secondary vertex +/// \param pVecTrack2 is the array for the candidate bachelor pion momentum after reconstruction of secondary vertex +/// \param primVtx is the primary vertex +/// \param secVtx is the secondary vertex +/// \return true if the beauty candidate passes all cuts +template +inline bool HfFilterHelper::isSelectedBzeroToDstar(T1 const& pVecTrack0, T1 const& pVecTrack1, T1 const& pVecTrack2, const T2& primVtx, const T3& secVtx) +{ + auto pVecB = RecoDecay::pVec(pVecTrack0, pVecTrack1, pVecTrack2); + auto pTB = RecoDecay::pt(pVecB); + auto binPtB = findBin(mPtBinsBeautyHadrons, pTB); + if (binPtB == -1) { + return false; + } + auto cpa = RecoDecay::cpa(primVtx, secVtx, pVecB); + auto decayLength = RecoDecay::distance(primVtx, secVtx); + + if (cpa < mCutsBhad[kB0toDStar].get(binPtB, 1u)) { + return false; + } + if (decayLength < mCutsBhad[kB0toDStar].get(binPtB, 2u)) { + return false; + } + + return true; +} + +/// Method to perform selections for B+ candidates after vertex reconstruction +/// \param ptCand is the pT of the beauty candidate +/// \param massCand is the mass of the beauty candidate +/// \param whichB is the B-hadron species +/// \return true if the beauty candidate passes all cuts +template +inline bool HfFilterHelper::isSelectedBhadronInMassRange(T1 const& ptCand, T2 const& massCand, const int whichB) +{ + auto binPtB = findBin(mPtBinsBeautyHadrons, ptCand); + if (binPtB == -1) { + return false; + } + + float massBhad{-1}; + switch (whichB) { + case kBplus: { + massBhad = massBPlus; + break; + } + case kB0toDStar: { + massBhad = massB0; + break; + } + case kB0: { + massBhad = massB0; + break; + } + case kBs: { + massBhad = massBs; + break; + } + case kBc: { + massBhad = massBc; + break; + } + case kLb: { + massBhad = massLb; + break; + } + case kXib: { + massBhad = massXib; + break; + } + } + + if (std::fabs(massCand - massBhad) > mCutsBhad[whichB].get(binPtB, 0u)) { + return false; + } + + return true; +} + +/// Method to perform selections for B -> JPsiX candidates after vertex reconstruction +/// \param pVecDauTracks is the array of momentum vectors of all daughter tracks +/// \param tracksDauNoMu is the array of tracks for the daughters that are no muons +/// \param primVtx is the primary vertex +/// \param secVtx is the secondary vertex +/// \param activateQA is the flag to enable the +/// \param hMassVsPt is the array of histograms for QA +/// \return true if the beauty candidate passes all cuts +template +inline int8_t HfFilterHelper::isSelectedBhadronToJPsi(std::array pVecDauTracks, std::array tracksDauNoMu, const T3& primVtx, const T4& secVtx, const int& activateQA, std::array& hMassVsPt) +{ + int8_t isSelected{0}; + + auto pVecJPsi = RecoDecay::pVec(pVecDauTracks[0], pVecDauTracks[1]); + const int offset = static_cast(kNBeautyParticles); + + if constexpr (Nprongs == 3) { + auto pVecBhad = RecoDecay::pVec(pVecDauTracks[0], pVecDauTracks[1], pVecDauTracks[2]); + auto ptBhad = RecoDecay::pt(pVecBhad); + auto binPtB = findBin(mPtBinsBeautyHadrons, ptBhad); + if (binPtB == -1) { + return isSelected; + } + auto ptMu1 = RecoDecay::pt(pVecDauTracks[0]); + auto ptMu2 = RecoDecay::pt(pVecDauTracks[1]); + if (ptMu1 < mCutsBhadToJPsi.get(binPtB, 0u) || ptMu2 < mCutsBhadToJPsi.get(binPtB, 0u)) { + return isSelected; + } + + if (RecoDecay::cpa(primVtx, secVtx, pVecBhad) < mCutsBhadToJPsi.get(binPtB, 2u)) { + return isSelected; + } + + if (RecoDecay::distance(primVtx, secVtx) < mCutsBhadToJPsi.get(binPtB, 3u)) { + return isSelected; + } + + if (isSelectedKaon4Charm3ProngOrBeautyToJPsi(tracksDauNoMu[0])) { + auto massJPsiKa = RecoDecay::m(std::array{pVecJPsi, pVecDauTracks[2]}, std::array{massJPsi, massKa}); + if (std::fabs(massJPsiKa - massBPlus) < mCutsBhadToJPsi.get(binPtB, 1u)) { + SETBIT(isSelected, kBplusToJPsi); + if (activateQA) { + hMassVsPt[offset + kBplusToJPsi]->Fill(ptBhad, massJPsiKa); + } + } + } + auto massJPsiPi = RecoDecay::m(std::array{pVecJPsi, pVecDauTracks[2]}, std::array{massJPsi, massPi}); + if (std::fabs(massJPsiPi - massBc) < mCutsBhadToJPsi.get(binPtB, 1u)) { + SETBIT(isSelected, kBcToJPsi); + if (activateQA) { + hMassVsPt[offset + kBcToJPsi]->Fill(ptBhad, massJPsiPi); + } + } + } else if constexpr (Nprongs == 4) { + auto pVecBhad = RecoDecay::pVec(pVecDauTracks[0], pVecDauTracks[1], pVecDauTracks[2], pVecDauTracks[3]); + auto ptBhad = RecoDecay::pt(pVecBhad); + auto binPtB = findBin(mPtBinsBeautyHadrons, ptBhad); + if (binPtB == -1) { + return isSelected; + } + auto ptMu1 = RecoDecay::pt(pVecDauTracks[0]); + auto ptMu2 = RecoDecay::pt(pVecDauTracks[1]); + if (ptMu1 < mCutsBhadToJPsi.get(binPtB, 0u) || ptMu2 < mCutsBhadToJPsi.get(binPtB, 0u)) { + return isSelected; + } + + if (RecoDecay::cpa(primVtx, secVtx, pVecBhad) < mCutsBhadToJPsi.get(binPtB, 2u)) { + return isSelected; + } + + if (RecoDecay::distance(primVtx, secVtx) < mCutsBhadToJPsi.get(binPtB, 3u)) { + return isSelected; + } + + bool isFirstKaon = isSelectedKaon4Charm3ProngOrBeautyToJPsi(tracksDauNoMu[0]); + bool isSeconKaon = isSelectedKaon4Charm3ProngOrBeautyToJPsi(tracksDauNoMu[1]); + bool isFirstProton = isSelectedProton4CharmOrBeautyBaryons(tracksDauNoMu[0]); + bool isSecondProton = isSelectedProton4CharmOrBeautyBaryons(tracksDauNoMu[1]); + auto massKaKa = RecoDecay::m(std::array{pVecDauTracks[2], pVecDauTracks[3]}, std::array{massKa, massKa}); + if (isFirstKaon && isSeconKaon) { + if (std::fabs(massKaKa - massPhi) < mCutsBhadToJPsi.get(binPtB, 4u)) { + auto massJPsiKaKa = RecoDecay::m(std::array{pVecJPsi, pVecDauTracks[2], pVecDauTracks[3]}, std::array{massJPsi, massKa, massKa}); + if (std::fabs(massJPsiKaKa - massBs) < mCutsBhadToJPsi.get(binPtB, 1u)) { + SETBIT(isSelected, kBsToJPsi); + if (activateQA) { + hMassVsPt[offset + kBsToJPsi]->Fill(ptBhad, massJPsiKaKa); + } + } + } + } + if (isFirstKaon) { + auto massKaPi = RecoDecay::m(std::array{pVecDauTracks[2], pVecDauTracks[3]}, std::array{massKa, massPi}); + if (std::fabs(massKaPi - massK0Star892) < mCutsBhadToJPsi.get(binPtB, 5u)) { + auto massJPsiKaPi = RecoDecay::m(std::array{pVecJPsi, pVecDauTracks[2], pVecDauTracks[3]}, std::array{massJPsi, massKa, massPi}); + if (std::fabs(massJPsiKaPi - massB0) < mCutsBhadToJPsi.get(binPtB, 1u)) { + SETBIT(isSelected, kB0ToJPsi); + if (activateQA) { + hMassVsPt[offset + kB0ToJPsi]->Fill(ptBhad, massJPsiKaPi); + } + } + } + } + if (isSeconKaon) { + auto massPiKa = RecoDecay::m(std::array{pVecDauTracks[2], pVecDauTracks[3]}, std::array{massPi, massKa}); + if (std::fabs(massPiKa - massK0Star892) < mCutsBhadToJPsi.get(binPtB, 5u)) { + auto massJPsiPiKa = RecoDecay::m(std::array{pVecJPsi, pVecDauTracks[2], pVecDauTracks[3]}, std::array{massJPsi, massPi, massKa}); + if (std::fabs(massJPsiPiKa - massB0) < mCutsBhadToJPsi.get(binPtB, 1u)) { + SETBIT(isSelected, kB0ToJPsi); + if (activateQA) { + hMassVsPt[offset + kB0ToJPsi]->Fill(ptBhad, massJPsiPiKa); + } + } + } + } + if (isFirstProton && isSeconKaon) { + auto massLbToJPsiPrKa = RecoDecay::m(std::array{pVecDauTracks[0], pVecDauTracks[1], pVecDauTracks[2], pVecDauTracks[3]}, std::array{massMu, massMu, massProton, massKa}); + if (std::fabs(massLbToJPsiPrKa - massLb) < mCutsBhadToJPsi.get(binPtB, 1u)) { + SETBIT(isSelected, kLbToJPsi); + if (activateQA) { + hMassVsPt[offset + kLbToJPsi]->Fill(ptBhad, massLbToJPsiPrKa); + } + } + } + if (isFirstKaon && isSecondProton) { + auto massLbToJPsiKaPr = RecoDecay::m(std::array{pVecDauTracks[0], pVecDauTracks[1], pVecDauTracks[2], pVecDauTracks[3]}, std::array{massMu, massMu, massKa, massProton}); + if (std::fabs(massLbToJPsiKaPr - massLb) < mCutsBhadToJPsi.get(binPtB, 1u)) { + SETBIT(isSelected, kLbToJPsi); + if (activateQA) { + hMassVsPt[offset + kLbToJPsi]->Fill(ptBhad, massLbToJPsiKaPr); + } + } + } + } + + return isSelected; +} + +/// Method to check if charm candidates has mass between sideband limits +/// \param massHypo1 is the array for the candidate D daughter momentum after reconstruction of secondary vertex +/// \param massHypo2 is the array for the candidate bachelor pion momentum after reconstruction of secondary vertex +/// \param lowLimitSB is the dca of the D daughter track +/// \param upLimitSB is the dca of the pion daughter track +/// \return true if the candidate passes the mass selection. +template +inline bool HfFilterHelper::isCharmHadronMassInSbRegions(T1 const& massHypo1, T1 const& massHypo2, const float& lowLimitSB, const float& upLimitSB) +{ + + if ((massHypo1 < lowLimitSB || massHypo1 > upLimitSB) && (massHypo2 < lowLimitSB || massHypo2 > upLimitSB)) { + return false; + } + + return true; +} + +/// Method to check if charm candidates has mass between sideband limits +/// \param trackParCasc is the cascade track parametrisation +/// \param trackParBachelor is the bachelor track parametrisation +/// \param isSelBachelor flag for bachelor selection (Pi/Ka) +/// \param collision is the collision containing the candidate +/// \param dcaFitter is the DCAFitter +/// \param activateQA is the flag to activate the QA +/// \param hMassVsPtXiPi is the 2D histogram with pT vs mass(XiPi) +/// \param hMassVsPtXiKa is the 2D histogram with pT vs mass(XiKa) +template +inline bool HfFilterHelper::isSelectedXiBach(T const& trackParCasc, T const& trackParBachelor, int8_t isSelBachelor, C const& collision, o2::vertexing::DCAFitterN<2>& dcaFitter, const int& activateQA, H2 hMassVsPtXiPi, H2 hMassVsPtXiKa) +{ + bool isSelectedXiPi{false}, isSelectedXiKa{false}; + + // compute pT + std::array pVecBachelor{}, pVecCascade{}; + getPxPyPz(trackParBachelor, pVecBachelor); + getPxPyPz(trackParCasc, pVecCascade); + auto ptXiBach = RecoDecay::pt(RecoDecay::pVec(pVecCascade, pVecBachelor)); + + // compute first mass hypo + float massXiPi{0.f}; + if (TESTBIT(isSelBachelor, kPionForCharmBaryon)) { + massXiPi = RecoDecay::m(std::array{pVecCascade, pVecBachelor}, std::array{massXi, massPi}); + if (ptXiBach >= mPtMinXiBach[0] && massXiPi >= mMassMinXiBach[0] && massXiPi <= mMassMaxXiBach[0]) { + isSelectedXiPi = true; + } + } + + // compute second mass hypo + float massXiKa{0.f}; + if (TESTBIT(isSelBachelor, kKaonForCharmBaryon)) { + massXiKa = RecoDecay::m(std::array{pVecCascade, pVecBachelor}, std::array{massXi, massKa}); + if (ptXiBach >= mPtMinXiBach[1] && massXiKa >= mMassMinXiBach[1] && massXiKa <= mMassMaxXiBach[1]) { + isSelectedXiKa = true; + } + } + + bool isSelected = isSelectedXiPi || isSelectedXiKa; + + if (isSelected && mCosPaMinXiBach[0] > -1.f) { // if selected by pT and mass, check topology if applicable + int nCand = 0; + try { + nCand = dcaFitter.process(trackParCasc, trackParBachelor); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call for Xi + bachelor!"; + return false; + } + if (nCand == 0) { + return false; + } + + const auto& vtx = dcaFitter.getPCACandidate(); + dcaFitter.propagateTracksToVertex(); + const auto& trackCascProp = dcaFitter.getTrack(0); + const auto& trackBachProp = dcaFitter.getTrack(1); + std::array momCasc{}, momBach{}; + trackCascProp.getPxPyPzGlo(momCasc); + trackBachProp.getPxPyPzGlo(momBach); + auto momXiBach = RecoDecay::pVec(momCasc, momBach); + + std::array primVtx = {collision.posX(), collision.posY(), collision.posZ()}; + if (RecoDecay::cpa(primVtx, std::array{vtx[0], vtx[1], vtx[2]}, momXiBach) < mCosPaMinXiBach[0]) { + return false; + } + + if (activateQA) { + if (isSelectedXiPi) { + hMassVsPtXiPi->Fill(ptXiBach, massXiPi); + } + if (isSelectedXiKa) { + hMassVsPtXiKa->Fill(ptXiBach, massXiKa); + } + } + } + + return isSelected; +} + +/// Method to check if charm candidates has mass between sideband limits +/// \param trackParCasc is the cascade track parametrisation +/// \param trackParBachelor is the array with two bachelor track parametrisations +/// \param collision is the collision containing the candidate +/// \param dcaFitter is the DCAFitter +/// \param activateQA is the flag to activate the QA +/// \param hMassVsPtXiPiPi is the 2D histogram with pT vs mass(XiPiPi) +template +inline bool HfFilterHelper::isSelectedXiBachBach(T const& trackParCasc, std::array const& trackParBachelor, C const& collision, o2::vertexing::DCAFitterN& dcaFitter, const int& activateQA, H2 hMassVsPtXiPiPi) +{ + // compute pT + std::array pVecBachelorFirst{}, pVecBachelorSecond{}, pVecCascade{}; + getPxPyPz(trackParBachelor[0], pVecBachelorFirst); + getPxPyPz(trackParBachelor[1], pVecBachelorSecond); + getPxPyPz(trackParCasc, pVecCascade); + auto ptXiBachBach = RecoDecay::pt(RecoDecay::pVec(pVecCascade, pVecBachelorFirst, pVecBachelorSecond)); + if (ptXiBachBach < mPtMinXiBach[2]) { + return false; + } + + // compute mass + float massXiPiPi = RecoDecay::m(std::array{pVecCascade, pVecBachelorFirst, pVecBachelorSecond}, std::array{massXi, massPi, massPi}); + if (massXiPiPi < mMassMinXiBach[2] || massXiPiPi > mMassMaxXiBach[2]) { + return false; + } + + if (mCosPaMinXiBach[1] > -1.f) { // check topology if applicable + int nCand = 0; + if constexpr (Nprongs == 3) { + try { + nCand = dcaFitter.process(trackParBachelor[0], trackParBachelor[1], trackParCasc); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call for Xi + bachelor + bachelor!"; + return false; + } + if (nCand == 0) { + return false; + } + } else if constexpr (Nprongs == 2) { + try { + nCand = dcaFitter.process(trackParBachelor[0], trackParBachelor[1]); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call for Xi + bachelor + bachelor!"; + return false; + } + if (nCand == 0) { + return false; + } + } + + const auto& vtx = dcaFitter.getPCACandidate(); + + std::array momCasc{pVecCascade}, momBachFirst{}, momBachSecond{}; + dcaFitter.propagateTracksToVertex(); + const auto& trackBachFirstProp = dcaFitter.getTrack(0); + const auto& trackBachSecondProp = dcaFitter.getTrack(1); + trackBachFirstProp.getPxPyPzGlo(momBachFirst); + trackBachSecondProp.getPxPyPzGlo(momBachSecond); + if constexpr (Nprongs == 3) { + const auto& trackCascProp = dcaFitter.getTrack(2); + trackCascProp.getPxPyPzGlo(momCasc); + } + auto momXiBachBach = RecoDecay::pVec(momCasc, momBachFirst, momBachSecond); + + std::array primVtx = {collision.posX(), collision.posY(), collision.posZ()}; + if (RecoDecay::cpa(primVtx, std::array{vtx[0], vtx[1], vtx[2]}, momXiBachBach) < mCosPaMinXiBach[1]) { + return false; + } + + if (activateQA) { + hMassVsPtXiPiPi->Fill(ptXiBachBach, massXiPiPi); + } + } + + return true; +} + +/// Update the TPC PID based on the spline of particles /// \param track is a track parameter /// \param pidSpecies is the particle species to be considered /// \return updated nsigma value for TPC PID template -inline double HfFilterHelper::getTPCSplineCalib(const T& track, const int& pidSpecies) +inline float HfFilterHelper::getTPCSplineCalib(const T& track, const int& pidSpecies) +{ + float tpcPin = track.tpcInnerParam(); + float dEdx = track.tpcSignal(); + + return getTPCSplineCalib(tpcPin, dEdx, pidSpecies); +} + +/// Update the TPC PID baesd on the spline of particles +/// \param tpcPin is the TPC momentum at innermost update +/// \param dEdx is the TPC dEdx +/// \param pidSpecies is the particle species to be considered +/// \return updated nsigma value for TPC PID +inline float HfFilterHelper::getTPCSplineCalib(const float tpcPin, const float dEdx, const int& pidSpecies) { float mMassPar{0.}; if (pidSpecies == kPi || pidSpecies == kAntiPi) { @@ -1621,64 +2428,84 @@ inline double HfFilterHelper::getTPCSplineCalib(const T& track, const int& pidSp mMassPar = massKa; } else if (pidSpecies == kPr || pidSpecies == kAntiPr) { mMassPar = massProton; + } else if (pidSpecies == kDe || pidSpecies == kAntiDe) { + mMassPar = massDeuteron; } else { LOGP(fatal, "TPC recalibrated Nsigma requested for unknown particle species, return 999"); return 999.; } auto bgScaling = 1 / mMassPar; - double expBethe = tpc::BetheBlochAleph(static_cast(track.tpcInnerParam() * bgScaling), mBetheBlochPiKaPr[pidSpecies][0], mBetheBlochPiKaPr[pidSpecies][1], mBetheBlochPiKaPr[pidSpecies][2], mBetheBlochPiKaPr[pidSpecies][3], mBetheBlochPiKaPr[pidSpecies][4]); - double expSigma = expBethe * mBetheBlochPiKaPr[pidSpecies][5]; - return static_cast((track.tpcSignal() - expBethe) / expSigma); + double expBethe = tpc::BetheBlochAleph(static_cast(tpcPin * bgScaling), mBetheBlochPiKaPrDe[pidSpecies][0], mBetheBlochPiKaPrDe[pidSpecies][1], mBetheBlochPiKaPrDe[pidSpecies][2], mBetheBlochPiKaPrDe[pidSpecies][3], mBetheBlochPiKaPrDe[pidSpecies][4]); + double expSigma = expBethe * mBetheBlochPiKaPrDe[pidSpecies][5]; + return static_cast((dEdx - expBethe) / expSigma); } /// compute TPC postcalibrated nsigma based on calibration histograms from CCDB -/// \param hCalibMean calibration histograms of mean from CCDB -/// \param hCalibSigma calibration histograms of sigma from CCDB -/// \param track is the track +/// \param tpcPin is the TPC momentum at innermost update +/// \param tpcNCls is the number of found TPC clusters +/// \param eta is the pseudorapidity +/// \param tpcNSigma is the original Nsigma /// \param pidSpecies is the PID species /// \return the corrected Nsigma value for the PID species -template -inline float HfFilterHelper::getTPCPostCalib(const T& track, const int& pidSpecies) +inline float HfFilterHelper::getTPCPostCalib(const float tpcPin, const float tpcNCls, const float eta, const float tpcNSigma, const int& pidSpecies) { - float tpcNCls = track.tpcNClsFound(); - float tpcPin = track.tpcInnerParam(); - float eta = track.eta(); - float tpcNSigma{0.}; int iHist{0}; - if (pidSpecies == kPi) { - tpcNSigma = track.tpcNSigmaPi(); iHist = 0; } else if (pidSpecies == kKa) { - tpcNSigma = track.tpcNSigmaKa(); iHist = 2; } else if (pidSpecies == kPr) { - tpcNSigma = track.tpcNSigmaPr(); iHist = 4; } else { LOG(fatal) << "Wrong PID Species be selected, please check!"; } - if (!mHistMapPiPrKa[iHist] || !mHistMapPiPrKa[iHist + 1]) { + + if (!mHistMapPiPrKaDe[iHist] || !mHistMapPiPrKaDe[iHist + 1]) { LOGP(warn, "Postcalibration TPC PID histograms not set. Use default Nsigma values."); } - auto binTPCNCls = mHistMapPiPrKa[iHist]->GetXaxis()->FindBin(tpcNCls); + auto binTPCNCls = mHistMapPiPrKaDe[iHist]->GetXaxis()->FindBin(tpcNCls); binTPCNCls = (binTPCNCls == 0 ? 1 : binTPCNCls); - binTPCNCls = std::min(mHistMapPiPrKa[iHist]->GetXaxis()->GetNbins(), binTPCNCls); - auto binPin = mHistMapPiPrKa[iHist]->GetYaxis()->FindBin(tpcPin); + binTPCNCls = std::min(mHistMapPiPrKaDe[iHist]->GetXaxis()->GetNbins(), binTPCNCls); + auto binPin = mHistMapPiPrKaDe[iHist]->GetYaxis()->FindBin(tpcPin); binPin = (binPin == 0 ? 1 : binPin); - binPin = std::min(mHistMapPiPrKa[iHist]->GetYaxis()->GetNbins(), binPin); - auto binEta = mHistMapPiPrKa[iHist]->GetZaxis()->FindBin(eta); + binPin = std::min(mHistMapPiPrKaDe[iHist]->GetYaxis()->GetNbins(), binPin); + auto binEta = mHistMapPiPrKaDe[iHist]->GetZaxis()->FindBin(eta); binEta = (binEta == 0 ? 1 : binEta); - binEta = std::min(mHistMapPiPrKa[iHist]->GetZaxis()->GetNbins(), binEta); + binEta = std::min(mHistMapPiPrKaDe[iHist]->GetZaxis()->GetNbins(), binEta); - auto mean = mHistMapPiPrKa[iHist]->GetBinContent(binTPCNCls, binPin, binEta); - auto width = mHistMapPiPrKa[iHist + 1]->GetBinContent(binTPCNCls, binPin, binEta); + auto mean = mHistMapPiPrKaDe[iHist]->GetBinContent(binTPCNCls, binPin, binEta); + auto width = mHistMapPiPrKaDe[iHist + 1]->GetBinContent(binTPCNCls, binPin, binEta); return (tpcNSigma - mean) / width; } +/// compute TPC postcalibrated nsigma based on calibration histograms from CCDB +/// \param track is the track +/// \param pidSpecies is the PID species +/// \return the corrected Nsigma value for the PID species +template +inline float HfFilterHelper::getTPCPostCalib(const T& track, const int& pidSpecies) +{ + float tpcNCls = track.tpcNClsFound(); + float tpcPin = track.tpcInnerParam(); + float eta = track.eta(); + float tpcNSigma{-999.}; + + if (pidSpecies == kPi) { + tpcNSigma = track.tpcNSigmaPi(); + } else if (pidSpecies == kKa) { + tpcNSigma = track.tpcNSigmaKa(); + } else if (pidSpecies == kPr) { + tpcNSigma = track.tpcNSigmaPr(); + } else { + LOG(fatal) << "Wrong PID Species be selected, please check!"; + } + + return getTPCPostCalib(tpcPin, tpcNCls, eta, tpcNSigma, pidSpecies); +} + /// Finds pT bin in an array. /// \param bins array of pT bins /// \param value pT @@ -1696,6 +2523,278 @@ inline int HfFilterHelper::findBin(T1 const& binsPt, T2 value) return std::distance(binsPt.begin(), std::upper_bound(binsPt.begin(), binsPt.end(), value)) - 1; } +/// Set vertxing configuration +/// \param vertexer o2::vertexing::DCAFitterN object +template +inline int HfFilterHelper::setVtxConfiguration(T1 vertexer, bool useAbsDCA) +{ + // Fitter initialisation + vertexer.setPropagateToPCA(true); + vertexer.setMaxR(200.); + vertexer.setMaxDZIni(1.e9); + vertexer.setMaxDXYIni(4.); + vertexer.setMinParamChange(1.e-3); + vertexer.setMinRelChi2Change(0.9); + vertexer.setMaxChi2(0.9); + vertexer.setUseAbsDCA(useAbsDCA); + vertexer.setWeightedFinalPCA(false); + return 1; +} + +/// Utility to compute AP alpha and qt +/// \param momPos momentum array of positive daughter +/// \param momNeg momentum array of negative daughter +template +inline std::array HfFilterHelper::alphaAndQtAP(std::array const& momPos, std::array const& momNeg) +{ + float momTot = RecoDecay::p(momPos[0] + momNeg[0], momPos[1] + momNeg[1], momPos[2] + momNeg[2]); + float lQlNeg = RecoDecay::dotProd(momNeg, std::array{momPos[0] + momNeg[0], momPos[1] + momNeg[1], momPos[2] + momNeg[2]}) / momTot; + float lQlPos = RecoDecay::dotProd(momPos, std::array{momPos[0] + momNeg[0], momPos[1] + momNeg[1], momPos[2] + momNeg[2]}) / momTot; + float alpha = (lQlPos - lQlNeg) / (lQlPos + lQlNeg); + float qtarm = std::sqrt(RecoDecay::p2(momNeg) - lQlNeg * lQlNeg); + + std::array alphaAndQt = {alpha, qtarm}; + return alphaAndQt; +} + +/// build V0 candidate from table with track indices +/// \param v0Indices V0 candidate from AO2D table (track indices) +/// \param tracks track table +/// \param collision collision +/// \param dcaFitter DCA fitter to be used +/// \param vetoedTrackIds vector with forbidden track indices, if any +template +inline bool HfFilterHelper::buildV0(V const& v0Indices, T const& tracks, C const& collision, o2::vertexing::DCAFitterN<2>& dcaFitter, const std::vector& vetoedTrackIds, V0Cand& v0Cand) +{ + auto trackPos = tracks.rawIteratorAt(v0Indices.posTrackId()); + auto trackNeg = tracks.rawIteratorAt(v0Indices.negTrackId()); + + // minimal track cuts + if (!trackPos.hasTPC() || !trackNeg.hasTPC()) { + return false; + } + + if (trackPos.tpcNClsCrossedRows() < 50 || trackNeg.tpcNClsCrossedRows() < 50) { + return false; + } + + if (std::find(vetoedTrackIds.begin(), vetoedTrackIds.end(), trackPos.globalIndex()) != vetoedTrackIds.end() || std::find(vetoedTrackIds.begin(), vetoedTrackIds.end(), trackNeg.globalIndex()) != vetoedTrackIds.end()) { + return false; + } + + auto trackParCovPos = getTrackParCov(trackPos); + auto trackParCovNeg = getTrackParCov(trackNeg); + std::array primVtx = {collision.posX(), collision.posY(), collision.posZ()}; + gpu::gpustd::array dcaInfoPos, dcaInfoNeg; + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParCovPos, 2.f, dcaFitter.getMatCorrType(), &dcaInfoPos); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParCovNeg, 2.f, dcaFitter.getMatCorrType(), &dcaInfoNeg); + + // reconstruct vertex + int nCand = 0; + try { + nCand = dcaFitter.process(trackParCovPos, trackParCovNeg); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call in V0!"; + return false; + } + if (nCand == 0) { + return false; + } + + // compute candidate momentum from tracks propagated to decay vertex + dcaFitter.propagateTracksToVertex(); + auto& trackPosProp = dcaFitter.getTrack(0); + auto& trackNegProp = dcaFitter.getTrack(1); + std::array momPos{}, momNeg{}; + trackPosProp.getPxPyPzGlo(momPos); + trackNegProp.getPxPyPzGlo(momNeg); + v0Cand.mom = RecoDecay::pVec(momPos, momNeg); + + // fill V0 quantities + v0Cand.dcapostopv = dcaInfoPos[0]; + v0Cand.dcanegtopv = dcaInfoNeg[0]; + v0Cand.ptPos = RecoDecay::pt(momPos); + v0Cand.ptNeg = RecoDecay::pt(momNeg); + v0Cand.pinTpcPos = trackPos.tpcInnerParam(); + v0Cand.pinTpcNeg = trackNeg.tpcInnerParam(); + v0Cand.nClsFoundTpcPos = trackPos.tpcNClsFound(); + v0Cand.nClsFoundTpcNeg = trackNeg.tpcNClsFound(); + v0Cand.nClsCrossedRowsTpcPos = trackPos.tpcNClsCrossedRows(); + v0Cand.nClsCrossedRowsTpcNeg = trackNeg.tpcNClsCrossedRows(); + v0Cand.crossedRowsOverFindableClsTpcPos = trackPos.tpcCrossedRowsOverFindableCls(); + v0Cand.crossedRowsOverFindableClsTpcNeg = trackNeg.tpcCrossedRowsOverFindableCls(); + v0Cand.signalTpcPos = trackPos.tpcSignal(); + v0Cand.signalTpcNeg = trackNeg.tpcSignal(); + v0Cand.etaPos = RecoDecay::eta(momPos); + v0Cand.etaNeg = RecoDecay::eta(momNeg); + v0Cand.dcaV0daughters = std::sqrt(dcaFitter.getChi2AtPCACandidate()); + + const auto& vtx = dcaFitter.getPCACandidate(); + for (int iCoord{0}; iCoord < 3; ++iCoord) { + v0Cand.vtx[iCoord] = vtx[iCoord]; + } + auto covVtxV = dcaFitter.calcPCACovMatrix(0); + v0Cand.cov = {}; + v0Cand.cov[0] = covVtxV(0, 0); + v0Cand.cov[1] = covVtxV(1, 0); + v0Cand.cov[2] = covVtxV(1, 1); + v0Cand.cov[3] = covVtxV(2, 0); + v0Cand.cov[4] = covVtxV(2, 1); + v0Cand.cov[5] = covVtxV(2, 2); + std::array covTpositive = {0.}; + std::array covTnegative = {0.}; + trackPosProp.getCovXYZPxPyPzGlo(covTpositive); + trackNegProp.getCovXYZPxPyPzGlo(covTnegative); + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int iCoord{0}; iCoord < 6; ++iCoord) { + v0Cand.cov[MomInd[iCoord]] = covTpositive[MomInd[iCoord]] + covTnegative[MomInd[iCoord]]; + } + v0Cand.v0radius = std::hypot(vtx[0], vtx[1]); + v0Cand.v0cosPA = RecoDecay::cpa(primVtx, vtx, v0Cand.mom); + + auto trackParV0 = dcaFitter.createParentTrackParCov(); + trackParV0.setAbsCharge(0); + trackParV0.setPID(o2::track::PID::K0); + gpu::gpustd::array dcaInfoV0; + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParV0, 2.f, dcaFitter.getMatCorrType(), &dcaInfoV0); + v0Cand.dcav0topv = dcaInfoV0[0]; + + v0Cand.mK0Short = RecoDecay::m(std::array{momPos, momNeg}, std::array{massPi, massPi}); + v0Cand.mLambda = RecoDecay::m(std::array{momPos, momNeg}, std::array{massProton, massPi}); + v0Cand.mAntiLambda = RecoDecay::m(std::array{momPos, momNeg}, std::array{massPi, massProton}); + + auto alphaAndQt = alphaAndQtAP(momPos, momNeg); + v0Cand.alpha = alphaAndQt[0]; + v0Cand.qtarm = alphaAndQt[1]; + + v0Cand.hasTofPos = trackPos.hasTOF(); + v0Cand.hasTofNeg = trackNeg.hasTOF(); + v0Cand.nSigmaPrTpcPos = trackPos.tpcNSigmaPr(); + v0Cand.nSigmaPrTofPos = trackPos.tofNSigmaPr(); + v0Cand.nSigmaPrTpcNeg = trackNeg.tpcNSigmaPr(); + v0Cand.nSigmaPrTofNeg = trackNeg.tofNSigmaPr(); + v0Cand.nSigmaPiTpcPos = trackPos.tpcNSigmaPi(); + v0Cand.nSigmaPiTofPos = trackPos.tofNSigmaPi(); + v0Cand.nSigmaPiTpcNeg = trackNeg.tpcNSigmaPi(); + v0Cand.nSigmaPiTofNeg = trackNeg.tofNSigmaPi(); + + return true; +} + +/// build cascade candidate from table with track indices +/// \param cascIndices cascade candidate from AO2D table (track indices) +/// \param v0Indices V0 candidate from AO2D table (track indices) +/// \param tracks track table +/// \param collision collision +/// \param dcaFitter DCA fitter to be used +/// \param vetoedTrackIds vector with forbidden track indices, if any +template +inline bool HfFilterHelper::buildCascade(Casc const& cascIndices, V const& v0Indices, T const& tracks, C const& collision, o2::vertexing::DCAFitterN<2>& dcaFitter, const std::vector& vetoedTrackIds, CascCand& cascCand) +{ + auto v0 = v0Indices.rawIteratorAt(cascIndices.v0Id()); + auto trackBachelor = tracks.rawIteratorAt(cascIndices.bachelorId()); + + // minimal track cuts + if (!trackBachelor.hasTPC()) { + return false; + } + + if (trackBachelor.tpcNClsCrossedRows() < 50) { + return false; + } + + if (std::find(vetoedTrackIds.begin(), vetoedTrackIds.end(), trackBachelor.globalIndex()) != vetoedTrackIds.end()) { + return false; + } + + gpu::gpustd::array dcaInfoBach; + auto bachTrackParCov = getTrackParCov(trackBachelor); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, bachTrackParCov, 2.f, dcaFitter.getMatCorrType(), &dcaInfoBach); + + // first we build V0 candidate + V0Cand v0Cand; + if (!buildV0(v0, tracks, collision, dcaFitter, vetoedTrackIds, v0Cand)) { + return false; + } + + // Set up covariance matrices (should in fact be optional) + auto v0TrackParCov = o2::track::TrackParCov({v0Cand.vtx[0], v0Cand.vtx[1], v0Cand.vtx[2]}, {v0Cand.mom[0], v0Cand.mom[1], v0Cand.mom[2]}, v0Cand.cov, 0, true); + v0TrackParCov.setAbsCharge(0); + v0TrackParCov.setPID(o2::track::PID::Lambda); + + int nCand = 0; + try { + nCand = dcaFitter.process(v0TrackParCov, bachTrackParCov); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call in Xi!"; + return false; + } + if (nCand == 0) { + return false; + } + + // compute candidate momentum from tracks propagated to decay vertex + dcaFitter.propagateTracksToVertex(); + auto& trackV0Prop = dcaFitter.getTrack(0); + auto& trackBachProp = dcaFitter.getTrack(1); + std::array momV0{}, momBach{}; + trackV0Prop.getPxPyPzGlo(momV0); + trackBachProp.getPxPyPzGlo(momBach); + cascCand.mom = RecoDecay::pVec(momV0, momBach); + cascCand.sign = trackBachelor.sign(); + + cascCand.v0 = v0Cand; + cascCand.ptBach = RecoDecay::pt(momBach); + cascCand.etaBach = RecoDecay::eta(momBach); + cascCand.pinTpcBach = trackBachelor.tpcInnerParam(); + cascCand.nClsFoundTpcBach = trackBachelor.tpcNClsFound(); + cascCand.nClsCrossedRowsTpcBach = trackBachelor.tpcNClsCrossedRows(); + cascCand.crossedRowsOverFindableClsTpcBach = trackBachelor.tpcCrossedRowsOverFindableCls(); + cascCand.signalTpcBach = trackBachelor.tpcSignal(); + cascCand.pt = RecoDecay::pt(cascCand.mom); + + std::array primVtx = {collision.posX(), collision.posY(), collision.posZ()}; + const auto& vtx = dcaFitter.getPCACandidate(); + for (int iCoord{0}; iCoord < 3; ++iCoord) { + cascCand.vtx[iCoord] = vtx[iCoord]; + } + auto covVtxV = dcaFitter.calcPCACovMatrix(0); + cascCand.cov = {}; + cascCand.cov[0] = covVtxV(0, 0); + cascCand.cov[1] = covVtxV(1, 0); + cascCand.cov[2] = covVtxV(1, 1); + cascCand.cov[3] = covVtxV(2, 0); + cascCand.cov[4] = covVtxV(2, 1); + cascCand.cov[5] = covVtxV(2, 2); + std::array covTv0 = {0.}; + std::array covTbachelor = {0.}; + trackV0Prop.getCovXYZPxPyPzGlo(covTv0); + trackBachProp.getCovXYZPxPyPzGlo(covTbachelor); + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int iCoord{0}; iCoord < 6; ++iCoord) { + cascCand.cov[MomInd[iCoord]] = covTv0[MomInd[iCoord]] + covTbachelor[MomInd[iCoord]]; + } + + cascCand.cascradius = std::hypot(vtx[0], vtx[1]); + cascCand.casccosPA = RecoDecay::cpa(primVtx, vtx, cascCand.mom); + + auto trackParCasc = dcaFitter.createParentTrackParCov(); + trackParCasc.setAbsCharge(1); + trackParCasc.setPID(o2::track::PID::XiMinus); + gpu::gpustd::array dcaInfoCasc; + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParCasc, 2.f, dcaFitter.getMatCorrType(), &dcaInfoCasc); + cascCand.dcaXYCascToPV = dcaInfoCasc[0]; + cascCand.dcacascdaughters = std::sqrt(dcaFitter.getChi2AtPCACandidate()); + cascCand.mXi = RecoDecay::m(std::array{momBach, momV0}, std::array{massPi, massLambda}); + cascCand.mOmega = RecoDecay::m(std::array{momBach, momV0}, std::array{massKa, massLambda}); + + cascCand.hasTofBach = trackBachelor.hasTOF(); + cascCand.nSigmaPiTpcBach = trackBachelor.tpcNSigmaPi(); + cascCand.nSigmaPiTofBach = trackBachelor.tofNSigmaPi(); + + return true; +} + } // namespace hffilters /// definition of tables @@ -1822,6 +2921,8 @@ DECLARE_SOA_COLUMN(DCAXY, dcaXY, float); //! DECLARE_SOA_COLUMN(KStar, kStar, float); //! DECLARE_SOA_COLUMN(NsigmaPrTPC, nsigmaPrTPC, float); //! DECLARE_SOA_COLUMN(NsigmaPrTOF, nsigmaPrTOF, float); //! +DECLARE_SOA_COLUMN(NsigmaDeTPC, nsigmaDeTPC, float); //! +DECLARE_SOA_COLUMN(NsigmaDeTOF, nsigmaDeTOF, float); //! } // namespace hfoptimisationTree DECLARE_SOA_TABLE(HFOptimisationTreeBeauty, "AOD", "HFOPTIMTREEB", //! @@ -1848,7 +2949,9 @@ DECLARE_SOA_TABLE(HFOptimisationTreeFemto, "AOD", "HFOPTIMTREEF", //! hfoptimisationTree::NonpromptBDT, hfoptimisationTree::KStar, hfoptimisationTree::NsigmaPrTPC, - hfoptimisationTree::NsigmaPrTOF); + hfoptimisationTree::NsigmaPrTOF, + hfoptimisationTree::NsigmaDeTPC, + hfoptimisationTree::NsigmaDeTOF); DECLARE_SOA_TABLE(HFOptimisationTreeCollisions, "AOD", "HFOPTIMTREECOLL", //! hfoptimisationTree::CollisionIndex) } // namespace o2::aod diff --git a/EventFiltering/PWGHF/HFFilterPrepareMLSamples.cxx b/EventFiltering/PWGHF/HFFilterPrepareMLSamples.cxx index 4a37a8b63b9..fd4cf6dba7e 100644 --- a/EventFiltering/PWGHF/HFFilterPrepareMLSamples.cxx +++ b/EventFiltering/PWGHF/HFFilterPrepareMLSamples.cxx @@ -17,8 +17,14 @@ /// \author Marcel Lesch , TUM /// \author Alexandre Bigot , Strasbourg University /// \author Biao Zhang , CCNU +/// \author Antonio Palasciano , INFN Bari +#include +#if __has_include() #include // needed for HFFilterHelpers, to be fixed +#else +#include +#endif #include "CommonConstants/PhysicsConstants.h" #include "CCDB/BasicCCDBManager.h" @@ -49,9 +55,13 @@ struct HfFilterPrepareMlSamples { // Main struct Produces train3P; // parameters for production of training samples - Configurable fillSignal{"fillSignal", true, "Flag to fill derived tables with signal for ML trainings"}; - Configurable fillBackground{"fillBackground", true, "Flag to fill derived tables with background for ML trainings"}; + Configurable fillOnlySignal{"fillOnlySignal", true, "Flag to fill derived tables with signal for ML trainings"}; + Configurable fillOnlyBackground{"fillOnlyBackground", true, "Flag to fill derived tables with background for ML trainings"}; Configurable downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of background candidates to keep for ML trainings"}; + Configurable massSbLeftMin{"massSbLeftMin", 1.72, "Left Sideband Lower Minv limit 2 Prong"}; + Configurable massSbLeftMax{"massSbLeftMax", 1.78, "Left Sideband Upper Minv limit 2 Prong"}; + Configurable massSbRightMin{"massSbRightMin", 1.94, "Right Sideband Lower Minv limit 2 Prong"}; + Configurable massSbRightMax{"massSbRightMax", 1.98, "Right Sideband Upper Minv limit 2 Prong"}; // CCDB configuration o2::ccdb::CcdbApi ccdbApi; @@ -63,8 +73,15 @@ struct HfFilterPrepareMlSamples { // Main struct o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; int currentRun = 0; // needed to detect if the run changed and trigger update of calibrations etc. + // helper object + HfFilterHelper helper; + void init(InitContext&) { + if (fillOnlySignal && fillOnlyBackground) { + LOGP(fatal, "fillOnlySignal and fillOnlyBackground cannot be activated simultaneously, exit"); + } + ccdb->setURL(url.value); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); @@ -72,14 +89,147 @@ struct HfFilterPrepareMlSamples { // Main struct ccdbApi.init(url); } + using BigTracksPID = soa::Join; using BigTracksMCPID = soa::Join; - void process(aod::Hf2Prongs const& cand2Prongs, - aod::Hf3Prongs const& cand3Prongs, - aod::McParticles const& mcParticles, - soa::Join const& collisions, - BigTracksMCPID const&, - aod::BCsWithTimestamps const&) + void processData2Prong(aod::Hf2Prongs const& cand2Prongs, + aod::Collisions const& collisions, + BigTracksPID const&, + aod::BCsWithTimestamps const&) + { + for (const auto& cand2Prong : cand2Prongs) { // start loop over 2 prongs + + auto thisCollId = cand2Prong.collisionId(); + auto collision = collisions.rawIteratorAt(thisCollId); + auto bc = collision.bc_as(); + + if (currentRun != bc.runNumber()) { + o2::parameters::GRPMagField* grpo = ccdb->getForTimeStamp(ccdbPathGrpMag, bc.timestamp()); + o2::base::Propagator::initFieldFromGRP(grpo); + currentRun = bc.runNumber(); + } + + auto trackPos = cand2Prong.prong0_as(); // positive daughter + auto trackNeg = cand2Prong.prong1_as(); // negative daughter + + auto trackParPos = getTrackPar(trackPos); + auto trackParNeg = getTrackPar(trackNeg); + o2::gpu::gpustd::array dcaPos{trackPos.dcaXY(), trackPos.dcaZ()}; + o2::gpu::gpustd::array dcaNeg{trackNeg.dcaXY(), trackNeg.dcaZ()}; + std::array pVecPos{trackPos.pVector()}; + std::array pVecNeg{trackNeg.pVector()}; + if (trackPos.collisionId() != thisCollId) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParPos, 2.f, noMatCorr, &dcaPos); + getPxPyPz(trackParPos, pVecPos); + } + if (trackNeg.collisionId() != thisCollId) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParNeg, 2.f, noMatCorr, &dcaNeg); + getPxPyPz(trackParNeg, pVecNeg); + } + + auto pVec2Prong = RecoDecay::pVec(pVecPos, pVecNeg); + auto pt2Prong = RecoDecay::pt(pVec2Prong); + + auto invMassD0 = RecoDecay::m(std::array{pVecPos, pVecNeg}, std::array{massPi, massKa}); + auto invMassD0bar = RecoDecay::m(std::array{pVecPos, pVecNeg}, std::array{massKa, massPi}); + + auto flag = RecoDecay::OriginType::None; + + if (fillOnlyBackground && !(helper.isCharmHadronMassInSbRegions(invMassD0, invMassD0bar, massSbLeftMin, massSbLeftMax) || (helper.isCharmHadronMassInSbRegions(invMassD0, invMassD0bar, massSbRightMin, massSbRightMax)))) + continue; + float pseudoRndm = trackPos.pt() * 1000. - static_cast(trackPos.pt() * 1000); + if (pseudoRndm < downSampleBkgFactor) { + train2P(invMassD0, invMassD0bar, pt2Prong, trackParPos.getPt(), dcaPos[0], dcaPos[1], trackPos.tpcNSigmaPi(), trackPos.tpcNSigmaKa(), trackPos.tofNSigmaPi(), trackPos.tofNSigmaKa(), + trackParNeg.getPt(), dcaNeg[0], dcaNeg[1], trackNeg.tpcNSigmaPi(), trackNeg.tpcNSigmaKa(), trackNeg.tofNSigmaPi(), trackNeg.tofNSigmaKa(), flag, true); + } + } // end loop over 2-prong candidates + } + PROCESS_SWITCH(HfFilterPrepareMlSamples, processData2Prong, "Store 2prong(D0) data tables", true); + + void processData3Prong(aod::Hf3Prongs const& cand3Prongs, + aod::Collisions const& collisions, + BigTracksPID const&, + aod::BCsWithTimestamps const&) + { + for (const auto& cand3Prong : cand3Prongs) { // start loop over 2 prongs + + auto thisCollId = cand3Prong.collisionId(); + auto collision = collisions.rawIteratorAt(thisCollId); + auto bc = collision.bc_as(); + + if (currentRun != bc.runNumber()) { + o2::parameters::GRPMagField* grpo = ccdb->getForTimeStamp(ccdbPathGrpMag, bc.timestamp()); + o2::base::Propagator::initFieldFromGRP(grpo); + currentRun = bc.runNumber(); + } + + auto trackFirst = cand3Prong.prong0_as(); // first daughter + auto trackSecond = cand3Prong.prong1_as(); // second daughter + auto trackThird = cand3Prong.prong2_as(); // third daughter + // auto arrayDaughters = std::array{trackFirst, trackSecond, trackThird}; + + auto trackParFirst = getTrackPar(trackFirst); + auto trackParSecond = getTrackPar(trackSecond); + auto trackParThird = getTrackPar(trackThird); + o2::gpu::gpustd::array dcaFirst{trackFirst.dcaXY(), trackFirst.dcaZ()}; + o2::gpu::gpustd::array dcaSecond{trackSecond.dcaXY(), trackSecond.dcaZ()}; + o2::gpu::gpustd::array dcaThird{trackThird.dcaXY(), trackThird.dcaZ()}; + std::array pVecFirst{trackFirst.pVector()}; + std::array pVecSecond{trackSecond.pVector()}; + std::array pVecThird{trackThird.pVector()}; + if (trackFirst.collisionId() != thisCollId) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParFirst, 2.f, noMatCorr, &dcaFirst); + getPxPyPz(trackParFirst, pVecFirst); + } + if (trackSecond.collisionId() != thisCollId) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParSecond, 2.f, noMatCorr, &dcaSecond); + getPxPyPz(trackParSecond, pVecSecond); + } + if (trackThird.collisionId() != thisCollId) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParThird, 2.f, noMatCorr, &dcaThird); + getPxPyPz(trackParThird, pVecThird); + } + + auto pVec3Prong = RecoDecay::pVec(pVecFirst, pVecSecond, pVecThird); + auto pt3Prong = RecoDecay::pt(pVec3Prong); + + auto invMassDplus = RecoDecay::m(std::array{pVecFirst, pVecSecond, pVecThird}, std::array{massPi, massKa, massPi}); + + auto invMassDsToKKPi = RecoDecay::m(std::array{pVecFirst, pVecSecond, pVecThird}, std::array{massKa, massKa, massPi}); + auto invMassDsToPiKK = RecoDecay::m(std::array{pVecFirst, pVecSecond, pVecThird}, std::array{massPi, massKa, massKa}); + + auto invMassLcToPKPi = RecoDecay::m(std::array{pVecFirst, pVecSecond, pVecThird}, std::array{massProton, massKa, massPi}); + auto invMassLcToPiKP = RecoDecay::m(std::array{pVecFirst, pVecSecond, pVecThird}, std::array{massPi, massKa, massProton}); + + auto invMassXicToPKPi = RecoDecay::m(std::array{pVecFirst, pVecSecond, pVecThird}, std::array{massProton, massKa, massPi}); + auto invMassXicToPiKP = RecoDecay::m(std::array{pVecFirst, pVecSecond, pVecThird}, std::array{massPi, massKa, massProton}); + + float deltaMassKKFirst = -1.f; + float deltaMassKKSecond = -1.f; + if (TESTBIT(cand3Prong.hfflag(), o2::aod::hf_cand_3prong::DecayType::DsToKKPi)) { + deltaMassKKFirst = std::abs(RecoDecay::m(std::array{pVecFirst, pVecSecond}, std::array{massKa, massKa}) - massPhi); + deltaMassKKSecond = std::abs(RecoDecay::m(std::array{pVecThird, pVecSecond}, std::array{massKa, massKa}) - massPhi); + } + // int8_t sign = 0; + auto flag = RecoDecay::OriginType::None; + + float pseudoRndm = trackFirst.pt() * 1000. - static_cast(trackFirst.pt() * 1000); + if (pseudoRndm < downSampleBkgFactor) { + train3P(invMassDplus, invMassDsToKKPi, invMassDsToPiKK, invMassLcToPKPi, invMassLcToPiKP, invMassXicToPKPi, invMassXicToPiKP, pt3Prong, deltaMassKKFirst, deltaMassKKSecond, + trackParFirst.getPt(), dcaFirst[0], dcaFirst[1], trackFirst.tpcNSigmaPi(), trackFirst.tpcNSigmaKa(), trackFirst.tpcNSigmaPr(), trackFirst.tofNSigmaPi(), trackFirst.tofNSigmaKa(), trackFirst.tofNSigmaPr(), + trackParSecond.getPt(), dcaSecond[0], dcaSecond[1], trackSecond.tpcNSigmaPi(), trackSecond.tpcNSigmaKa(), trackSecond.tpcNSigmaPr(), trackSecond.tofNSigmaPi(), trackSecond.tofNSigmaKa(), trackSecond.tofNSigmaPr(), + trackParThird.getPt(), dcaThird[0], dcaThird[1], trackThird.tpcNSigmaPi(), trackThird.tpcNSigmaKa(), trackThird.tpcNSigmaPr(), trackThird.tofNSigmaPi(), trackThird.tofNSigmaKa(), trackThird.tofNSigmaPr(), + flag, 0, cand3Prong.hfflag(), 0); + } + } // end loop over 3-prong candidates + } + PROCESS_SWITCH(HfFilterPrepareMlSamples, processData3Prong, "Store 3prong(D0)-data tables", true); + + void processMC2Prong(aod::Hf2Prongs const& cand2Prongs, + aod::McParticles const& mcParticles, + soa::Join const& collisions, + BigTracksMCPID const&, + aod::BCsWithTimestamps const&) { for (const auto& cand2Prong : cand2Prongs) { // start loop over 2 prongs @@ -122,7 +272,15 @@ struct HfFilterPrepareMlSamples { // Main struct // D0(bar) → π± K∓ bool isInCorrectColl{false}; - auto indexRec = RecoDecay::getMatchedMCRec(mcParticles, std::array{trackPos, trackNeg}, o2::constants::physics::Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign); + auto indexRec = RecoDecay::getMatchedMCRec(mcParticles, std::array{trackPos, trackNeg}, o2::constants::physics::Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign); + + if (fillOnlySignal && indexRec < 0) { + continue; + } + if (fillOnlyBackground && indexRec >= 0) { + continue; + } + if (indexRec > -1) { auto particle = mcParticles.rawIteratorAt(indexRec); flag = RecoDecay::getCharmHadronOrigin(mcParticles, particle); @@ -132,13 +290,19 @@ struct HfFilterPrepareMlSamples { // Main struct } } - float pseudoRndm = trackPos.pt() * 1000. - (int64_t)(trackPos.pt() * 1000); - if ((fillSignal && indexRec > -1) || (fillBackground && indexRec < 0 && pseudoRndm < downSampleBkgFactor)) { - train2P(invMassD0, invMassD0bar, pt2Prong, trackParPos.getPt(), dcaPos[0], dcaPos[1], trackPos.tpcNSigmaPi(), trackPos.tpcNSigmaKa(), trackPos.tofNSigmaPi(), trackPos.tofNSigmaKa(), - trackParNeg.getPt(), dcaNeg[0], dcaNeg[1], trackNeg.tpcNSigmaPi(), trackNeg.tpcNSigmaKa(), trackNeg.tofNSigmaPi(), trackNeg.tofNSigmaKa(), flag, isInCorrectColl); - } + train2P(invMassD0, invMassD0bar, pt2Prong, trackParPos.getPt(), dcaPos[0], dcaPos[1], trackPos.tpcNSigmaPi(), trackPos.tpcNSigmaKa(), trackPos.tofNSigmaPi(), trackPos.tofNSigmaKa(), + trackParNeg.getPt(), dcaNeg[0], dcaNeg[1], trackNeg.tpcNSigmaPi(), trackNeg.tpcNSigmaKa(), trackNeg.tofNSigmaPi(), trackNeg.tofNSigmaKa(), flag, isInCorrectColl); + } // end loop over 2-prong candidates + } + PROCESS_SWITCH(HfFilterPrepareMlSamples, processMC2Prong, "Store 2 prong(D0) MC tables", false); + void processMC3Prong(aod::Hf3Prongs const& cand3Prongs, + aod::McParticles const& mcParticles, + soa::Join const& collisions, + BigTracksMCPID const&, + aod::BCsWithTimestamps const&) + { for (const auto& cand3Prong : cand3Prongs) { // start loop over 3 prongs auto thisCollId = cand3Prong.collisionId(); @@ -203,32 +367,39 @@ struct HfFilterPrepareMlSamples { // Main struct int8_t channel = -1; // D± → π± K∓ π± - auto indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, o2::constants::physics::Pdg::kDPlus, std::array{+kPiPlus, -kKPlus, +kPiPlus}, true, &sign, 2); + auto indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, o2::constants::physics::Pdg::kDPlus, std::array{+kPiPlus, -kKPlus, +kPiPlus}, true, &sign, 2); if (indexRec >= 0) { channel = kDplus; } if (indexRec < 0) { // Ds± → K± K∓ π± - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, o2::constants::physics::Pdg::kDS, std::array{+kKPlus, -kKPlus, +kPiPlus}, true, &sign, 2); + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, o2::constants::physics::Pdg::kDS, std::array{+kKPlus, -kKPlus, +kPiPlus}, true, &sign, 2); if (indexRec >= 0) { channel = kDs; } } if (indexRec < 0) { // Λc± → p± K∓ π± - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, o2::constants::physics::Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, o2::constants::physics::Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); if (indexRec >= 0) { channel = kLc; } } if (indexRec < 0) { // Ξc± → p± K∓ π± - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, o2::constants::physics::Pdg::kXiCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, o2::constants::physics::Pdg::kXiCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); if (indexRec >= 0) { channel = kXic; } } + if (fillOnlySignal && indexRec < 0) { + continue; + } + if (fillOnlyBackground && indexRec >= 0) { + continue; + } + bool isInCorrectColl{false}; if (indexRec > -1) { auto particle = mcParticles.rawIteratorAt(indexRec); @@ -239,16 +410,15 @@ struct HfFilterPrepareMlSamples { // Main struct } } - float pseudoRndm = trackFirst.pt() * 1000. - (int64_t)(trackFirst.pt() * 1000); - if ((fillSignal && indexRec > -1) || (fillBackground && indexRec < 0 && pseudoRndm < downSampleBkgFactor)) { - train3P(invMassDplus, invMassDsToKKPi, invMassDsToPiKK, invMassLcToPKPi, invMassLcToPiKP, invMassXicToPKPi, invMassXicToPiKP, pt3Prong, deltaMassKKFirst, deltaMassKKSecond, - trackParFirst.getPt(), dcaFirst[0], dcaFirst[1], trackFirst.tpcNSigmaPi(), trackFirst.tpcNSigmaKa(), trackFirst.tpcNSigmaPr(), trackFirst.tofNSigmaPi(), trackFirst.tofNSigmaKa(), trackFirst.tofNSigmaPr(), - trackParSecond.getPt(), dcaSecond[0], dcaSecond[1], trackSecond.tpcNSigmaPi(), trackSecond.tpcNSigmaKa(), trackSecond.tpcNSigmaPr(), trackSecond.tofNSigmaPi(), trackSecond.tofNSigmaKa(), trackSecond.tofNSigmaPr(), - trackParThird.getPt(), dcaThird[0], dcaThird[1], trackThird.tpcNSigmaPi(), trackThird.tpcNSigmaKa(), trackThird.tpcNSigmaPr(), trackThird.tofNSigmaPi(), trackThird.tofNSigmaKa(), trackThird.tofNSigmaPr(), - flag, channel, cand3Prong.hfflag(), isInCorrectColl); - } + train3P(invMassDplus, invMassDsToKKPi, invMassDsToPiKK, invMassLcToPKPi, invMassLcToPiKP, invMassXicToPKPi, invMassXicToPiKP, pt3Prong, deltaMassKKFirst, deltaMassKKSecond, + trackParFirst.getPt(), dcaFirst[0], dcaFirst[1], trackFirst.tpcNSigmaPi(), trackFirst.tpcNSigmaKa(), trackFirst.tpcNSigmaPr(), trackFirst.tofNSigmaPi(), trackFirst.tofNSigmaKa(), trackFirst.tofNSigmaPr(), + trackParSecond.getPt(), dcaSecond[0], dcaSecond[1], trackSecond.tpcNSigmaPi(), trackSecond.tpcNSigmaKa(), trackSecond.tpcNSigmaPr(), trackSecond.tofNSigmaPi(), trackSecond.tofNSigmaKa(), trackSecond.tofNSigmaPr(), + trackParThird.getPt(), dcaThird[0], dcaThird[1], trackThird.tpcNSigmaPi(), trackThird.tpcNSigmaKa(), trackThird.tpcNSigmaPr(), trackThird.tofNSigmaPi(), trackThird.tofNSigmaKa(), trackThird.tofNSigmaPr(), + flag, channel, cand3Prong.hfflag(), isInCorrectColl); + } // end loop over 3-prong candidates } + PROCESS_SWITCH(HfFilterPrepareMlSamples, processMC3Prong, "Store 3 prong MC tables", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfg) diff --git a/EventFiltering/PWGJE/jetFilter.cxx b/EventFiltering/PWGJE/jetFilter.cxx index 60e67d39073..277f749d22b 100644 --- a/EventFiltering/PWGJE/jetFilter.cxx +++ b/EventFiltering/PWGJE/jetFilter.cxx @@ -14,6 +14,7 @@ #include #include #include +#include #include "Framework/ASoA.h" #include "Framework/ASoAHelpers.h" @@ -94,13 +95,13 @@ struct jetFilter { Filter trackFilter = (nabs(aod::jtrack::eta) < static_cast(cfgEtaTPC)) && (aod::jtrack::pt > trackPtMin); int trackSelection = -1; - int eventSelection = -1; + std::vector eventSelectionBits; void init(o2::framework::InitContext&) { triggerJetR = TMath::Nint(cfgJetR * 100.0f); trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(evSel)); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(evSel)); spectra.add("fCollZpos", "collision z position", HistType::kTH1F, {{200, -20., +20., "#it{z}_{vtx} position (cm)"}}); @@ -196,7 +197,7 @@ struct jetFilter { spectra.fill(HIST("fCollZpos"), collision.posZ()); hProcessedEvents->Fill(static_cast(kBinAllEvents) + 0.1f); // all minimum bias events - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { tags(keepEvent[kJetChLowPt], keepEvent[kJetChHighPt], keepEvent[kTrackLowPt], keepEvent[kTrackHighPt]); return; } @@ -286,13 +287,13 @@ struct jetFilter { tags(keepEvent[kJetChLowPt], keepEvent[kJetChHighPt], keepEvent[kTrackLowPt], keepEvent[kTrackHighPt]); } - void processWithoutRho(soa::Join::iterator const& collision, o2::aod::ChargedJets const& jets, soa::Filtered const& tracks) + void processWithoutRho(soa::Join::iterator const& collision, o2::aod::ChargedJets const& jets, soa::Filtered const& tracks) { doTriggering(collision, jets, tracks); } PROCESS_SWITCH(jetFilter, processWithoutRho, "Do charged jet triggering without background estimation for filling histograms", true); - void processWithRho(soa::Join::iterator const& collision, o2::aod::ChargedJets const& jets, soa::Filtered const& tracks) + void processWithRho(soa::Join::iterator const& collision, o2::aod::ChargedJets const& jets, soa::Filtered const& tracks) { doTriggering(collision, jets, tracks); } diff --git a/EventFiltering/PWGJE/jetHFFilter.cxx b/EventFiltering/PWGJE/jetHFFilter.cxx index ab6539372b8..6657e785751 100644 --- a/EventFiltering/PWGJE/jetHFFilter.cxx +++ b/EventFiltering/PWGJE/jetHFFilter.cxx @@ -75,7 +75,7 @@ struct JetHFFilterTask { registry.add("h_collisions", "Collision ;entries", {HistType::kTH1F, {{5, 0.0, 5.0}}}); } - void processJets(soa::Join::iterator const& /*collision*/, soa::Join const& d0Jets, CandidatesD0Data const& /*d0Candidates*/, soa::Join const& lcJets, CandidatesLcData const& /*lcCandidates*/, JetTracks const& /*tracks*/) + void processJets(soa::Join::iterator const& /*collision*/, soa::Join const& d0Jets, aod::CandidatesD0Data const& /*d0Candidates*/, soa::Join const& lcJets, aod::CandidatesLcData const& /*lcCandidates*/, aod::JetTracks const& /*tracks*/) { registry.fill(HIST("h_collisions"), 0.5); bool keepEvent[kAllObjects]{false}; diff --git a/EventFiltering/PWGLF/filterdoublephi.cxx b/EventFiltering/PWGLF/filterdoublephi.cxx new file mode 100644 index 00000000000..241a70aef9e --- /dev/null +++ b/EventFiltering/PWGLF/filterdoublephi.cxx @@ -0,0 +1,279 @@ +// 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 filterdoublephi.cxx +/// \brief Selection of events with triplets and pairs for femtoscopic studies +/// +/// \author Sourav Kundu, sourav.kundu@cern.ch + +#include +#include +#include +#include +#include +#include // FIXME +#include // FIXME + +#include +#include +#include +#include + +#include "../filterTables.h" +#include "PWGLF/DataModel/ReducedDoublePhiTables.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "CommonConstants/MathConstants.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "Common/DataModel/PIDResponseITS.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct filterdoublephi { + + // Produce derived tables + Produces tags; + + // events + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + // Configurable cfgCutCentralityMax{"cfgCutCentralityMax", 0.0f, "Accepted maximum Centrality"}; + // Configurable cfgCutCentralityMin{"cfgCutCentralityMin", 100.0f, "Accepted minimum Centrality"}; + // track + Configurable isPtdepPID1{"isPtdepPID1", false, "use pt dep PID kplus"}; + Configurable isPtdepPID2{"isPtdepPID2", false, "use pt dep PID kminus"}; + Configurable useGlobalTrack{"useGlobalTrack", true, "use Global track"}; + Configurable cfgCutTOFBeta{"cfgCutTOFBeta", 0.0, "cut TOF beta"}; + Configurable cfgCutCharge{"cfgCutCharge", 0.0, "cut on Charge"}; + Configurable cfgCutPT{"cfgCutPT", 0.2, "PT cut on daughter track"}; + Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; + Configurable cfgCutDCAxy{"cfgCutDCAxy", 2.0f, "DCAxy range for tracks"}; + Configurable cfgCutDCAz{"cfgCutDCAz", 2.0f, "DCAz range for tracks"}; + Configurable nsigmaCutTPC{"nsigmacutTPC", -2.0, "Value of the TPC Nsigma cut"}; + Configurable nsigmaCutTPCPreSel{"nsigmacutTPCPreSel", 3.0, "Value of the TPC Nsigma cut Pre selection"}; + Configurable nsigmaCutTOF{"nsigmaCutTOF", 3.0, "Value of the TOF Nsigma cut"}; + Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; + Configurable isDeepAngle{"isDeepAngle", true, "Deep Angle cut"}; + Configurable cfgDeepAngle{"cfgDeepAngle", 0.04, "Deep Angle cut value"}; + ConfigurableAxis configThnAxisInvMass{"configThnAxisInvMass", {120, 0.98, 1.1}, "#it{M} (GeV/#it{c}^{2})"}; + ConfigurableAxis configThnAxisPt{"configThnAxisPt", {100, 0.0, 10.}, "#it{p}_{T} (GeV/#it{c})"}; + Configurable minPhiMass{"minPhiMass", 1.01, "Minimum phi mass"}; + Configurable maxPhiMass{"maxPhiMass", 1.03, "Maximum phi mass"}; + Configurable MinPhiPairPt{"MinPhiPairPt", 2.0, "Minimum phi pair Pt"}; + Configurable MinPhiPairMass{"MinPhiPairMass", 2.5, "Minimum phi pair mass"}; + Configurable MaxPhiPairMass{"MaxPhiPairMass", 3.0, "Max phi pair mass"}; + + // Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + // Filter centralityFilter = (nabs(aod::cent::centFT0C) < cfgCutCentralityMax && nabs(aod::cent::centFT0C) > cfgCutCentralityMin); + Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPT); + Filter DCAcutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); + Filter PIDcutFilter = nabs(aod::pidtpc::tpcNSigmaKa) < nsigmaCutTPCPreSel; + + // using EventCandidates = soa::Filtered>; + using EventCandidates = soa::Join; + using TrackCandidates = soa::Filtered>; + + SliceCache cache; + Partition posTracks = aod::track::signed1Pt > cfgCutCharge; + Partition negTracks = aod::track::signed1Pt < cfgCutCharge; + + // Histogram + OutputObj hProcessedEvents{TH1D("hProcessedEvents", ";; Number of events", 3, 0.0f, 3.0f)}; + HistogramRegistry qaRegistry{"QAHistos", { + {"hInvMassPhi", "hInvMassPhi", {HistType::kTH2F, {{40, 1.0f, 1.04f}, {100, 0.0f, 10.0f}}}}, + {"hInvMassDoublePhi", "hInvMassDoublePhi", {HistType::kTH2F, {{1000, 2.0f, 3.0f}, {100, 0.0f, 10.0f}}}}, + {"hNsigmaPtkaonTPC", "hNsigmaPtkaonTPC", {HistType::kTH2F, {{200, -10.0f, 10.0f}, {100, 0.0f, 10.0f}}}}, + {"hNsigmaPtkaonTOF", "hNsigmaPtkaonTOF", {HistType::kTH2F, {{200, -10.0f, 10.0f}, {100, 0.0f, 10.0f}}}}, + }, + OutputObjHandlingPolicy::AnalysisObject}; + + double massKa = o2::constants::physics::MassKPlus; + + void init(o2::framework::InitContext&) + { + hProcessedEvents->GetXaxis()->SetBinLabel(1, "All events"); + hProcessedEvents->GetXaxis()->SetBinLabel(2, "Events with double Phi without sel."); + hProcessedEvents->GetXaxis()->SetBinLabel(3, aod::filtering::TriggerEventDoublePhi::columnLabel()); + } + + template + bool selectionTrack(const T& candidate) + { + if (useGlobalTrack && !(candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsCrossedRows() > cfgTPCcluster)) { + return false; + } + return true; + } + template + bool selectionPID(const T& candidate) + { + if (candidate.pt() < 0.5 && candidate.tpcNSigmaKa() > nsigmaCutTPC && candidate.tpcNSigmaKa() < 3.0) { + return true; + } + if (candidate.pt() >= 0.5) { + if (!candidate.hasTOF() && candidate.tpcNSigmaKa() > nsigmaCutTPC && candidate.tpcNSigmaKa() < 3.0) { + return true; + } + if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && candidate.tpcNSigmaKa() > nsigmaCutTPC && candidate.tpcNSigmaKa() < 3.0 && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF) { + return true; + } + } + return false; + } + template + bool selectionPID2(const T& candidate) + { + if (candidate.pt() < 0.5 && candidate.tpcNSigmaKa() > nsigmaCutTPC && candidate.tpcNSigmaKa() < 3.0) { + return true; + } + if (candidate.pt() >= 0.5) { + if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && candidate.tpcNSigmaKa() > nsigmaCutTPC && candidate.tpcNSigmaKa() < 3.0 && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF) { + return true; + } + } + return false; + } + // deep angle cut on pair to remove photon conversion + template + bool selectionPair(const T1& candidate1, const T2& candidate2) + { + double pt1, pt2, pz1, pz2, p1, p2, angle; + pt1 = candidate1.pt(); + pt2 = candidate2.pt(); + pz1 = candidate1.pz(); + pz2 = candidate2.pz(); + p1 = candidate1.p(); + p2 = candidate2.p(); + angle = TMath::ACos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); + if (isDeepAngle && angle < cfgDeepAngle) { + return false; + } + return true; + } + + ROOT::Math::PxPyPzMVector KaonPlus, KaonMinus, PhiMesonMother, PhiVectorDummy, PhiVectorDummy2, PhiPair; + void processPhiReducedTable(EventCandidates::iterator const& collision, TrackCandidates const&, aod::BCsWithTimestamps const&) + { + bool keepEventDoublePhi = false; + int numberPhi = 0; + o2::aod::ITSResponse itsResponse; + std::vector Phid1Index = {}; + std::vector Phid2Index = {}; + std::vector phiresonance, phiresonanced1, phiresonanced2; + int Npostrack = 0; + int Nnegtrack = 0; + hProcessedEvents->Fill(0.5); + if (collision.sel8()) { + auto posThisColl = posTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negThisColl = negTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + for (auto track1 : posThisColl) { + // track selection + if (!selectionTrack(track1)) { + continue; + } + // PID check + if (isPtdepPID1 && !selectionPID2(track1)) { + continue; + } + if (!isPtdepPID1 && !selectionPID(track1)) { + continue; + } + if (track1.pt() > 0.4 && track1.pt() < 1.0 && !(itsResponse.nSigmaITS(track1) > -2.0 && itsResponse.nSigmaITS(track1) < 3.0)) { + continue; + } + Npostrack = Npostrack + 1; + qaRegistry.fill(HIST("hNsigmaPtkaonTPC"), track1.tpcNSigmaKa(), track1.pt()); + if (track1.hasTOF()) { + qaRegistry.fill(HIST("hNsigmaPtkaonTOF"), track1.tofNSigmaKa(), track1.pt()); + } + auto track1ID = track1.globalIndex(); + for (auto track2 : negThisColl) { + // track selection + if (!selectionTrack(track2)) { + continue; + } + // PID check + if (isPtdepPID2 && !selectionPID2(track2)) { + continue; + } + if (!isPtdepPID2 && !selectionPID(track2)) { + continue; + } + if (track2.pt() > 0.4 && track2.pt() < 1.0 && !(itsResponse.nSigmaITS(track2) > -2.0 && itsResponse.nSigmaITS(track2) < 3.0)) { + continue; + } + if (Npostrack == 1) { + Nnegtrack = Nnegtrack + 1; + } + auto track2ID = track2.globalIndex(); + if (track2ID == track1ID) { + continue; + } + if (!selectionPair(track1, track2)) { + continue; + } + KaonPlus = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + KaonMinus = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + PhiMesonMother = KaonPlus + KaonMinus; + if (PhiMesonMother.M() > minPhiMass && PhiMesonMother.M() < maxPhiMass) { + numberPhi = numberPhi + 1; + ROOT::Math::PtEtaPhiMVector temp1(track1.pt(), track1.eta(), track1.phi(), massKa); + ROOT::Math::PtEtaPhiMVector temp2(track2.pt(), track2.eta(), track2.phi(), massKa); + ROOT::Math::PtEtaPhiMVector temp3(PhiMesonMother.pt(), PhiMesonMother.eta(), PhiMesonMother.phi(), PhiMesonMother.M()); + phiresonanced1.push_back(temp1); + phiresonanced2.push_back(temp2); + phiresonance.push_back(temp3); + Phid1Index.push_back(track1.globalIndex()); + Phid2Index.push_back(track2.globalIndex()); + qaRegistry.fill(HIST("hInvMassPhi"), PhiMesonMother.M(), PhiMesonMother.Pt()); + } + } + } + } // select collision + if (numberPhi > 1 && Npostrack > 1 && Nnegtrack > 1 && (phiresonance.size() == phiresonanced1.size()) && (phiresonance.size() == phiresonanced2.size())) { + hProcessedEvents->Fill(1.5); + for (auto if1 = phiresonance.begin(); if1 != phiresonance.end(); ++if1) { + auto i5 = std::distance(phiresonance.begin(), if1); + PhiVectorDummy = phiresonance.at(i5); + for (auto if2 = if1 + 1; if2 != phiresonance.end(); ++if2) { + auto i6 = std::distance(phiresonance.begin(), if2); + PhiVectorDummy2 = phiresonance.at(i6); + PhiPair = PhiVectorDummy + PhiVectorDummy2; + if (!(Phid1Index.at(i5) == Phid1Index.at(i6) && Phid2Index.at(i5) == Phid2Index.at(i6)) && PhiPair.M() > MinPhiPairMass && PhiPair.M() < MaxPhiPairMass && PhiPair.Pt() > MinPhiPairPt) { + qaRegistry.fill(HIST("hInvMassDoublePhi"), PhiPair.M(), PhiPair.Pt()); + keepEventDoublePhi = true; + } + } + } + } + if (keepEventDoublePhi) { + hProcessedEvents->Fill(2.5); + } + tags(keepEventDoublePhi); + } // process + PROCESS_SWITCH(filterdoublephi, processPhiReducedTable, "Process table creation for double phi", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfg) +{ + return WorkflowSpec{adaptAnalysisTask(cfg, TaskName{"lf-doublephi-filter"})}; +} diff --git a/EventFiltering/PWGLF/nucleiFilter.cxx b/EventFiltering/PWGLF/nucleiFilter.cxx index ee3ec9a1683..4b22c95c3b1 100644 --- a/EventFiltering/PWGLF/nucleiFilter.cxx +++ b/EventFiltering/PWGLF/nucleiFilter.cxx @@ -13,6 +13,8 @@ #include #include +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -27,6 +29,19 @@ #include "PWGLF/DataModel/Vtx3BodyTables.h" #include "../filterTables.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/trackUtilities.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsTOF/ParameterContainers.h" +#include "CCDB/BasicCCDBManager.h" +#include "DCAFitter/DCAFitterN.h" +#include "PWGLF/DataModel/pidTOFGeneric.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Common/Core/PID/PIDTOF.h" + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -35,7 +50,6 @@ namespace { static constexpr int nNuclei{3}; -static constexpr int nHyperNuclei{1}; static constexpr int nCutsPID{5}; static constexpr std::array masses{ constants::physics::MassDeuteron, constants::physics::MassTriton, @@ -44,7 +58,7 @@ static constexpr std::array charges{1, 1, 2}; static const std::vector matterOrNot{"Matter", "Antimatter"}; static const std::vector nucleiNames{"H2", "H3", "Helium"}; static const std::vector hypernucleiNames{"H3L"}; // 3-body decay case -static const std::vector columnsNames{"fH2", "fH3", o2::aod::filtering::He::columnLabel(), o2::aod::filtering::H3L3Body::columnLabel()}; +static const std::vector columnsNames{o2::aod::filtering::H2::columnLabel(), o2::aod::filtering::He::columnLabel(), o2::aod::filtering::HeV0::columnLabel(), o2::aod::filtering::TritonFemto::columnLabel(), o2::aod::filtering::H3L3Body::columnLabel(), o2::aod::filtering::Tracked3Body::columnLabel(), o2::aod::filtering::ITSmildIonisation::columnLabel(), o2::aod::filtering::ITSextremeIonisation::columnLabel()}; static const std::vector cutsNames{ "TPCnSigmaMin", "TPCnSigmaMax", "TOFnSigmaMin", "TOFnSigmaMax", "TOFpidStartPt"}; constexpr double betheBlochDefault[nNuclei][6]{ @@ -52,16 +66,16 @@ constexpr double betheBlochDefault[nNuclei][6]{ {-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}, {-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}}; static constexpr float cutsPID[nNuclei][nCutsPID]{ - {-3.f, +3.f, -4.f, +4.f, 1.0f}, /*H2*/ - {-3.f, +3.f, -4.f, +4.f, 1.6f}, /*H3*/ - {-5.f, +5.f, -4.f, +4.f, 14000.f}, /*He3*/ + {-3.f, +400.f, -4.f, +400.f, 1.0f}, /*H2*/ + {-3.f, +3.f, -4.f, +4.f, 1.6f}, /*H3*/ + {-5.f, +400.f, -4.f, +4.f, 14000.f}, /*He3*/ }; constexpr double bbMomScalingDefault[nNuclei][2]{ {1., 1.}, {1., 1.}, {1., 1.}}; constexpr double minTPCmom[nNuclei][2]{ - {0., 0.}, + {0.8, 0.}, {0., 0.}, {0.8, 0.}}; static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; @@ -80,42 +94,79 @@ struct nucleiFilter { Configurable cfgCutEta{"cfgCutEta", 1.f, "Eta range for tracks"}; Configurable cfgCutNclusITS{"cfgCutNclusITS", 2, "Minimum number of ITS clusters"}; + Configurable cfgCutNclusExtremeIonisationITS{"cfgCutNclusExtremeIonisationITS", 5, "Minimum number of ITS clusters for the extreme ionisation trigger"}; + Configurable cfgMomentumCutExtremeIonisation{"cfgMomentumCutExtremeIonisation", 1.2, "Minimum momentum for the extreme ionisation trigger"}; + Configurable cfgCutClsSizeExtremeIonisation{"cfgCutClsSizeExtremeIonisation", 8, "Minimum average size of ITS clusters for the extreme ionisation trigger"}; + Configurable cfgCutClsSizeMildIonisation{"cfgCutClsSizeMildIonisation", 5, "Minimum average size of ITS clusters for the mild ionisation trigger"}; Configurable cfgCutNclusTPC{"cfgCutNclusTPC", 80, "Minimum number of TPC clusters"}; Configurable cfgCutDCAxy{"cfgCutDCAxy", 3, "Max DCAxy"}; Configurable cfgCutDCAz{"cfgCutDCAz", 10, "Max DCAz"}; + Configurable cfgCutKstar{"cfgCutKstar", 1.f, "Kstar cut for triton femto trigger"}; + Configurable cfgCutCosPAheV0{"cfgCutCosPAheV0", 0.99, "CosPA cut for HeV0"}; Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {betheBlochDefault[0], nNuclei, 6, nucleiNames, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for light nuclei"}; Configurable> cfgMomentumScalingBetheBloch{"cfgMomentumScalingBetheBloch", {bbMomScalingDefault[0], nNuclei, 2, nucleiNames, matterOrNot}, "TPC Bethe-Bloch momentum scaling for light nuclei"}; Configurable> cfgMinTPCmom{"cfgMinTPCmom", {minTPCmom[0], nNuclei, 2, nucleiNames, matterOrNot}, "Minimum TPC p/Z for nuclei PID"}; Configurable> cfgCutsPID{"nucleiCutsPID", {cutsPID[0], nNuclei, nCutsPID, nucleiNames, cutsNames}, "Nuclei PID selections"}; - + Configurable cfgFixTPCinnerParam{"cfgFixTPCinnerParam", false, "Fix TPC inner param"}; + + // variable/tool for hypertriton 3body decay + int mRunNumber; + float mBz; + Service ccdb; + using TrackCandidates = soa::Join; // FIXME: positio has been changed + o2::aod::pidtofgeneric::TofPidNewCollision bachelorTOFPID; + o2::base::MatLayerCylSet* lut = nullptr; + o2::vertexing::DCAFitterN<2> fitter2body; + o2::vertexing::DCAFitterN<3> fitter3body; + o2::pid::tof::TOFResoParamsV2 mRespParamsV2; // configurable for hypertriton 3body decay - Configurable minCosPA3body{"minCosPA3body", 0.99, "minCosPA3body"}; - Configurable dcavtxdau{"dcavtxdau", 1.0, "DCA Vtx Daughters"}; - Configurable dcapiontopv{"dcapiontopv", 0.05, "DCA Pion To PV"}; - Configurable TofPidNsigmaMin{"TofPidNsigmaMin", -5, "TofPidNsigmaMin"}; - Configurable TofPidNsigmaMax{"TofPidNsigmaMax", 5, "TofPidNsigmaMax"}; - Configurable TpcPidNsigmaCut{"TpcPidNsigmaCut", 5, "TpcPidNsigmaCut"}; - Configurable lifetimecut{"lifetimecut", 40., "lifetimecut"}; // ct - Configurable minProtonPt{"minProtonPt", 0.3, "minProtonPt"}; - Configurable maxProtonPt{"maxProtonPt", 5, "maxProtonPt"}; - Configurable minPionPt{"minPionPt", 0.1, "minPionPt"}; - Configurable maxPionPt{"maxPionPt", 1.2, "maxPionPt"}; - Configurable minDeuteronPt{"minDeuteronPt", 0.6, "minDeuteronPt"}; - Configurable maxDeuteronPt{"maxDeuteronPt", 10, "maxDeuteronPt"}; - Configurable minDeuteronPUseTOF{"minDeuteronPUseTOF", 1, "minDeuteronPt Enable TOF PID"}; - Configurable h3LMassLowerlimit{"h3LMassLowerlimit", 2.96, "Hypertriton mass lower limit"}; - Configurable h3LMassUpperlimit{"h3LMassUpperlimit", 3.04, "Hypertriton mass upper limit"}; - Configurable mintpcNClsproton{"mintpcNClsproton", 90, "min tpc Nclusters for proton"}; - Configurable mintpcNClspion{"mintpcNClspion", 70, "min tpc Nclusters for pion"}; - Configurable mintpcNClsdeuteron{"mintpcNClsdeuteron", 100, "min tpc Nclusters for deuteron"}; - Configurable fixTPCinnerParam{"fixTPCinnerParam", false, "Fix TPC inner param"}; + struct : ConfigurableGroup { + Configurable bFieldInput{"trgH3L3Body.mBz", -999, "bz field, -999 is automatic"}; + Configurable minCosPA3body{"trgH3L3Body.minCosPA3body", 0.9995, "minCosPA3body"}; + Configurable dcavtxdau{"trgH3L3Body.dcavtxdau", 0.02, "meen DCA among Daughters"}; + Configurable dcapiontopv{"trgH3L3Body.dcapiontopv", 0.05, "DCA Pion To PV"}; + Configurable tofPIDNSigmaMin{"trgH3L3Body.tofPIDNSigmaMin", -5, "tofPIDNSigmaMin"}; + Configurable tofPIDNSigmaMax{"trgH3L3Body.tofPIDNSigmaMax", 5, "tofPIDNSigmaMax"}; + Configurable tpcPIDNSigmaCut{"trgH3L3Body.tpcPIDNSigmaCut", 5, "tpcPIDNSigmaCut"}; + Configurable lifetimecut{"trgH3L3Body.lifetimecut", 40., "lifetimecut"}; + Configurable minDaughtersEta{"trgH3L3Body.minDaughtersEta", 1.f, "minDaughtersEta"}; + Configurable minProtonPt{"trgH3L3Body.minProtonPt", 0.3, "minProtonPt"}; + Configurable maxProtonPt{"trgH3L3Body.maxProtonPt", 5, "maxProtonPt"}; + Configurable minPionPt{"trgH3L3Body.minPionPt", 0.1, "minPionPt"}; + Configurable maxPionPt{"trgH3L3Body.maxPionPt", 1.2, "maxPionPt"}; + Configurable minDeuteronPt{"trgH3L3Body.minDeuteronPt", 0.6, "minDeuteronPt"}; + Configurable maxDeuteronPt{"trgH3L3Body.maxDeuteronPt", 10, "maxDeuteronPt"}; + Configurable minDeuteronPUseTOF{"trgH3L3Body.minDeuteronPUseTOF", 1, "minDeuteronPt Enable TOF PID"}; + Configurable h3LMassLowerlimit{"trgH3L3Body.h3LMassLowerlimit", 2.96, "Hypertriton mass lower limit"}; + Configurable h3LMassUpperlimit{"trgH3L3Body.h3LMassUpperlimit", 3.04, "Hypertriton mass upper limit"}; + Configurable minP3Body{"trgH3L3Body.minP3Body", 1.5, "min P3Body"}; + Configurable mintpcNClsproton{"trgH3L3Body.mintpcNClsproton", 90, "min tpc Nclusters for proton"}; + Configurable mintpcNClspion{"trgH3L3Body.mintpcNClspion", 70, "min tpc Nclusters for pion"}; + Configurable mintpcNClsdeuteron{"trgH3L3Body.mintpcNClsdeuteron", 100, "min tpc Nclusters for deuteron"}; + + Configurable useMatCorrType{"trgH3L3Body.useMatCorrType", 0, "0: none, 1: TGeo, 2: LUT"}; + // CCDB options + Configurable ccdburl{"trgH3L3Body.ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"trgH3L3Body.grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"trgH3L3Body.grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"trgH3L3Body.lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"trgH3L3Body.geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + // CCDB TOF PID paras + Configurable timestamp{"trgH3L3Body.ccdb-timestamp", -1, "timestamp of the object"}; + Configurable paramFileName{"trgH3L3Body.paramFileName", "", "Path to the parametrization object. If empty the parametrization is not taken from file"}; + Configurable parametrizationPath{"trgH3L3Body.parametrizationPath", "TOF/Calib/Params", "Path of the TOF parametrization on the CCDB or in the file, if the paramFileName is not empty"}; + Configurable passName{"trgH3L3Body.passName", "", "Name of the pass inside of the CCDB parameter collection. If empty, the automatically deceted from metadata (to be implemented!!!)"}; + Configurable timeShiftCCDBPath{"trgH3L3Body.timeShiftCCDBPath", "", "Path of the TOF time shift vs eta. If empty none is taken"}; + Configurable loadResponseFromCCDB{"trgH3L3Body.loadResponseFromCCDB", false, "Flag to load the response from the CCDB"}; + Configurable fatalOnPassNotAvailable{"trgH3L3Body.fatalOnPassNotAvailable", false, "Flag to throw a fatal if the pass is not available in the retrieved CCDB object"}; + } trgH3L3Body; HistogramRegistry qaHists{"qaHists", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - OutputObj hProcessedEvents{TH1D("hProcessedEvents", ";;Number of filtered events", nNuclei + nHyperNuclei + 1, -0.5, nNuclei + nHyperNuclei + 0.5)}; + OutputObj hProcessedEvents{TH1D("hProcessedEvents", ";;Number of filtered events", kNtriggers + 1, -0.5, static_cast(kNtriggers) + 0.5)}; - void init(o2::framework::InitContext&) + void init(InitContext&) { std::vector ptBinning = {0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4., 5.}; @@ -125,7 +176,11 @@ struct nucleiFilter { qaHists.add("fTPCsignalAll", "Specific energy loss (before filter)", HistType::kTH2F, {{1200, -6, 6, "#it{p} (GeV/#it{c})"}, {1400, 0, 1400, "d#it{E} / d#it{X} (a. u.)"}}); qaHists.add("fTPCsignal", "Specific energy loss", HistType::kTH2F, {{1200, -6, 6, "#it{p} (GeV/#it{c})"}, {1400, 0, 1400, "d#it{E} / d#it{X} (a. u.)"}}); qaHists.add("fDeuTOFNsigma", "Deuteron TOF Nsigma distribution", HistType::kTH2F, {{1200, -6, 6, "#it{p} (GeV/#it{c})"}, {2000, -100, 100, "TOF n#sigma"}}); + qaHists.add("fBachDeuTOFNsigma", "Bachelor Deuteron TOF Nsigma distribution", HistType::kTH2F, {{1200, -6, 6, "#it{p} (GeV/#it{c})"}, {2000, -100, 100, "TOF n#sigma"}}); qaHists.add("fH3LMassVsPt", "Hypertrion mass Vs pT", HistType::kTH2F, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {80, 2.96, 3.04, "Inv. Mass (GeV/c^{2})"}}); + qaHists.add("fH3LDcaVsPt", "DCA vs pT", HistType::kTH2F, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {100, 0, 0.05, "DCA (cm)"}}); + qaHists.add("fH3LCosPAVsPt", "CosPA vs pT", HistType::kTH2F, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {100, 0.999, 1.0, "CosPA"}}); + qaHists.add("fExtremeIonisationITS", "ITS clusters for extreme ionisation trigger", HistType::kTH3F, {{4, 3.5, 7.5, "Number of ITS clusters"}, {150, 0, 15, "Average cluster size in ITS x cos#lambda"}, {100, 0.1, 10, "#it{p} (GeV/#it{c})"}}); for (int iN{0}; iN < nNuclei; ++iN) { h2TPCsignal[iN] = qaHists.add(Form("fTPCsignal_%s", nucleiNames[iN].data()), "Specific energy loss", HistType::kTH2F, {{1200, -6, 6., "#it{p}/Z (GeV/#it{c})"}, {1400, 0, 1400, "d#it{E} / d#it{X} (a. u.)"}}); @@ -136,30 +191,195 @@ struct nucleiFilter { for (uint32_t iS{0}; iS < columnsNames.size(); ++iS) { hProcessedEvents->GetXaxis()->SetBinLabel(iS + 2, columnsNames[iS].data()); } + + // for fH3L3Body + bachelorTOFPID.SetPidType(o2::track::PID::Deuteron); + fitter3body.setPropagateToPCA(true); + fitter3body.setMaxR(200.); + fitter3body.setMinParamChange(1e-3); + fitter3body.setMinRelChi2Change(0.9); + fitter3body.setMaxDZIni(1e9); + fitter3body.setMaxChi2(1e9); + fitter3body.setUseAbsDCA(true); + + fitter2body.setPropagateToPCA(true); + fitter2body.setMaxR(200.); + fitter2body.setMinParamChange(1e-3); + fitter2body.setMinRelChi2Change(0.9); + fitter2body.setMaxDZIni(1e9); + fitter2body.setMaxChi2(1e9); + fitter2body.setUseAbsDCA(true); + + ccdb->setURL(trgH3L3Body.ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); } - // Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta); - // using TrackCandidates = soa::Filtered>; - using TrackCandidates = soa::Join; - void process(soa::Join::iterator const& collision, aod::Vtx3BodyDatas const& vtx3bodydatas, TrackCandidates const& tracks) + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (trgH3L3Body.bFieldInput > -990) { + mBz = trgH3L3Body.bFieldInput; + o2::parameters::GRPMagField grpmag; + if (std::fabs(mBz) > 1e-5) { + grpmag.setL3Current(30000.f / (mBz / 5.0f)); + } + o2::base::Propagator::initFieldFromGRP(&grpmag); + mRunNumber = bc.runNumber(); + return; + } + + auto run3grp_timestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(trgH3L3Body.grpPath, run3grp_timestamp); + o2::parameters::GRPMagField* grpmag = 0x0; + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + // Fetch magnetic field from ccdb for current collision + mBz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << mBz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(trgH3L3Body.grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << trgH3L3Body.grpmagPath << " of object GRPMagField and " << trgH3L3Body.grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + // Fetch magnetic field from ccdb for current collision + // mBz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + mBz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << mBz << " kZG"; + } + mRunNumber = bc.runNumber(); + // Set magnetic field value once known + fitter2body.setBz(mBz); + fitter3body.setBz(mBz); + + if (trgH3L3Body.useMatCorrType == 2) { + // setMatLUT only after magfield has been initalized + // (setMatLUT has implicit and problematic init field call if not) + o2::base::Propagator::Instance()->setMatLUT(lut); + } + + // Initial TOF PID Paras, copied from pidTOF.cxx + trgH3L3Body.timestamp.value = bc.timestamp(); + ccdb->setTimestamp(trgH3L3Body.timestamp.value); + // Not later than now objects + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + // TODO: implement the automatic pass name detection from metadata + if (trgH3L3Body.passName.value == "") { + trgH3L3Body.passName.value = "unanchored"; // temporary default + LOG(warning) << "Passed autodetect mode for pass, not implemented yet, waiting for metadata. Taking '" << trgH3L3Body.passName.value << "'"; + } + LOG(info) << "Using parameter collection, starting from pass '" << trgH3L3Body.passName.value << "'"; + + const std::string fname = trgH3L3Body.paramFileName.value; + if (!fname.empty()) { // Loading the parametrization from file + LOG(info) << "Loading exp. sigma parametrization from file " << fname << ", using param: " << trgH3L3Body.parametrizationPath.value; + if (1) { + o2::tof::ParameterCollection paramCollection; + paramCollection.loadParamFromFile(fname, trgH3L3Body.parametrizationPath.value); + LOG(info) << "+++ Loaded parameter collection from file +++"; + if (!paramCollection.retrieveParameters(mRespParamsV2, trgH3L3Body.passName.value)) { + if (trgH3L3Body.fatalOnPassNotAvailable) { + LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", trgH3L3Body.passName.value.data()); + } else { + LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", trgH3L3Body.passName.value.data()); + } + } else { + mRespParamsV2.setShiftParameters(paramCollection.getPars(trgH3L3Body.passName.value)); + mRespParamsV2.printShiftParameters(); + } + } else { + mRespParamsV2.loadParamFromFile(fname.data(), trgH3L3Body.parametrizationPath.value); + } + } else if (trgH3L3Body.loadResponseFromCCDB) { // Loading it from CCDB + LOG(info) << "Loading exp. sigma parametrization from CCDB, using path: " << trgH3L3Body.parametrizationPath.value << " for timestamp " << trgH3L3Body.timestamp.value; + o2::tof::ParameterCollection* paramCollection = ccdb->getForTimeStamp(trgH3L3Body.parametrizationPath.value, trgH3L3Body.timestamp.value); + paramCollection->print(); + if (!paramCollection->retrieveParameters(mRespParamsV2, trgH3L3Body.passName.value)) { // Attempt at loading the parameters with the pass defined + if (trgH3L3Body.fatalOnPassNotAvailable) { + LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", trgH3L3Body.passName.value.data()); + } else { + LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", trgH3L3Body.passName.value.data()); + } + } else { // Pass is available, load non standard parameters + mRespParamsV2.setShiftParameters(paramCollection->getPars(trgH3L3Body.passName.value)); + mRespParamsV2.printShiftParameters(); + } + } + mRespParamsV2.print(); + if (trgH3L3Body.timeShiftCCDBPath.value != "") { + if (trgH3L3Body.timeShiftCCDBPath.value.find(".root") != std::string::npos) { + mRespParamsV2.setTimeShiftParameters(trgH3L3Body.timeShiftCCDBPath.value, "gmean_Pos", true); + mRespParamsV2.setTimeShiftParameters(trgH3L3Body.timeShiftCCDBPath.value, "gmean_Neg", false); + } else { + mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/pos", trgH3L3Body.timeShiftCCDBPath.value.c_str()), trgH3L3Body.timestamp.value), true); + mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/neg", trgH3L3Body.timeShiftCCDBPath.value.c_str()), trgH3L3Body.timestamp.value), false); + } + } + + bachelorTOFPID.SetParams(mRespParamsV2); + } + + enum { + kH2 = 0, + kHe, + kHeV0, + kTritonFemto, + kH3L3Body, + kTracked3Body, + kITSmildIonisation, + kITSextremeIonisation, + kNtriggers + } TriggerType; + // void process(soa::Join::iterator const& collision, aod::Vtx3BodyDatas const& vtx3bodydatas, TrackCandidates const& tracks) + using ColWithEvTime = soa::Join; + void process(ColWithEvTime::iterator const& collision, aod::Decay3Bodys const& decay3bodys, TrackCandidates const& tracks, aod::AssignedTracked3Bodys const& tracked3Bodys, aod::V0s const& v0s, aod::BCsWithTimestamps const&) { // collision process loop - bool keepEvent[nNuclei + nHyperNuclei]{false}; + std::array keepEvent{false}; // qaHists.fill(HIST("fCollZpos"), collision.posZ()); hProcessedEvents->Fill(0); // if (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { - tags(keepEvent[2], keepEvent[3]); + tags(keepEvent[kH2], keepEvent[kHe], keepEvent[kHeV0], keepEvent[kTritonFemto], keepEvent[kH3L3Body], keepEvent[kTracked3Body], keepEvent[kITSmildIonisation], keepEvent[kITSextremeIonisation]); return; } + // const double bgScalings[nNuclei][2]{ {charges[0] * cfgMomentumScalingBetheBloch->get(0u, 0u) / masses[0], charges[0] * cfgMomentumScalingBetheBloch->get(0u, 1u) / masses[0]}, {charges[1] * cfgMomentumScalingBetheBloch->get(1u, 0u) / masses[1], charges[1] * cfgMomentumScalingBetheBloch->get(1u, 1u) / masses[1]}, {charges[2] * cfgMomentumScalingBetheBloch->get(2u, 0u) / masses[2], charges[2] * cfgMomentumScalingBetheBloch->get(2u, 1u) / masses[2]}}; - for (auto& track : tracks) { // start loop over tracks + constexpr int nucleusIndex[nNuclei]{kH2, -1, kHe}; /// remap for nuclei triggers + std::vector h3indices; + std::vector h3vectors; + + auto getNsigma = [&](const auto& track, int iN, int iC) { + float fixTPCrigidity{(cfgFixTPCinnerParam && (track.pidForTracking() == track::PID::Helium3 || track.pidForTracking() == track::PID::Alpha)) ? 0.5f : 1.f}; + double expBethe{tpc::BetheBlochAleph(static_cast(track.tpcInnerParam() * fixTPCrigidity * bgScalings[iN][iC]), cfgBetheBlochParams->get(iN, 0u), cfgBetheBlochParams->get(iN, 1u), cfgBetheBlochParams->get(iN, 2u), cfgBetheBlochParams->get(iN, 3u), cfgBetheBlochParams->get(iN, 4u))}; + double expSigma{expBethe * cfgBetheBlochParams->get(iN, 5u)}; + return static_cast((track.tpcSignal() - expBethe) / expSigma); + }; + + for (const auto& track : tracks) { // start loop over tracks + if (track.itsNCls() >= cfgCutNclusExtremeIonisationITS) { + double avgClsSize{0.}; + double cosL{std::sqrt(1. / (1. + track.tgl() * track.tgl()))}; + for (int iC{0}; iC < 7; ++iC) { + avgClsSize += track.itsClsSizeInLayer(iC); + } + avgClsSize = avgClsSize * cosL / track.itsNCls(); + qaHists.fill(HIST("fExtremeIonisationITS"), track.itsNCls(), avgClsSize, track.p()); + keepEvent[kITSmildIonisation] = track.p() > cfgMomentumCutExtremeIonisation && avgClsSize > cfgCutClsSizeMildIonisation; + keepEvent[kITSextremeIonisation] = track.p() > cfgMomentumCutExtremeIonisation && avgClsSize > cfgCutClsSizeExtremeIonisation; + } if (track.itsNCls() < cfgCutNclusITS || track.tpcNClsFound() < cfgCutNclusTPC) { continue; @@ -169,10 +389,8 @@ struct nucleiFilter { qaHists.fill(HIST("fDeuTOFNsigma"), track.p() * track.sign(), track.tofNSigmaDe()); } - if (track.sign() > 0 && (std::abs(track.dcaXY()) > cfgCutDCAxy || - std::abs(track.dcaZ()) > cfgCutDCAz)) { - continue; - } + bool passesDCAselection{(track.sign() < 0 || (std::abs(track.dcaXY()) < cfgCutDCAxy && + std::abs(track.dcaZ()) < cfgCutDCAz))}; float nSigmaTPC[nNuclei]{ track.tpcNSigmaDe(), track.tpcNSigmaTr(), track.tpcNSigmaHe()}; @@ -180,7 +398,7 @@ struct nucleiFilter { track.tofNSigmaDe(), track.tofNSigmaTr(), track.tofNSigmaHe()}; const int iC{track.sign() < 0}; - float fixTPCrigidity{(fixTPCinnerParam && (track.pidForTracking() == track::PID::Helium3 || track.pidForTracking() == track::PID::Alpha)) ? 0.5f : 1.f}; + float fixTPCrigidity{(cfgFixTPCinnerParam && (track.pidForTracking() == track::PID::Helium3 || track.pidForTracking() == track::PID::Alpha)) ? 0.5f : 1.f}; // fill QA hist: dEdx for all charged tracks qaHists.fill(HIST("fTPCsignalAll"), track.sign() * track.tpcInnerParam() * fixTPCrigidity, track.tpcSignal()); @@ -192,9 +410,7 @@ struct nucleiFilter { } if (cfgBetheBlochParams->get(iN, 5u) > 0.f) { - double expBethe{tpc::BetheBlochAleph(static_cast(track.tpcInnerParam() * fixTPCrigidity * bgScalings[iN][iC]), cfgBetheBlochParams->get(iN, 0u), cfgBetheBlochParams->get(iN, 1u), cfgBetheBlochParams->get(iN, 2u), cfgBetheBlochParams->get(iN, 3u), cfgBetheBlochParams->get(iN, 4u))}; - double expSigma{expBethe * cfgBetheBlochParams->get(iN, 5u)}; - nSigmaTPC[iN] = static_cast((track.tpcSignal() - expBethe) / expSigma); + nSigmaTPC[iN] = getNsigma(track, iN, iC); } h2TPCnSigma[iN]->Fill(track.sign() * track.tpcInnerParam() * fixTPCrigidity, nSigmaTPC[iN]); if (nSigmaTPC[iN] < cfgCutsPID->get(iN, 0u) || nSigmaTPC[iN] > cfgCutsPID->get(iN, 1u)) { @@ -203,12 +419,79 @@ struct nucleiFilter { if (track.p() > cfgCutsPID->get(iN, 4u) && (nSigmaTOF[iN] < cfgCutsPID->get(iN, 2u) || nSigmaTOF[iN] > cfgCutsPID->get(iN, 3u))) { continue; } - keepEvent[iN] = true; - if (keepEvent[iN]) { + if (iN == 1 && passesDCAselection) { + h3indices.push_back(track.globalIndex()); + h3vectors.emplace_back(track.pt(), track.eta(), track.phi(), masses[iN]); + } + if (nucleusIndex[iN] < 0) { + continue; + } + keepEvent[nucleusIndex[iN]] = passesDCAselection; + if (keepEvent[nucleusIndex[iN]]) { h2TPCsignal[iN]->Fill(track.sign() * track.tpcInnerParam() * fixTPCrigidity, track.tpcSignal()); } } + for (const auto& track : tracks) { + if (track.itsNCls() < cfgCutNclusITS || + track.tpcNClsFound() < cfgCutNclusTPC || + std::abs(track.dcaXY()) > cfgCutDCAxy || + std::abs(track.dcaZ()) > cfgCutDCAz || + std::abs(track.eta()) > cfgCutEta) { + continue; + } + const ROOT::Math::PtEtaPhiMVector trackVector(track.pt(), track.eta(), track.phi(), constants::physics::MassPiMinus); + for (size_t iH3{0}; iH3 < h3vectors.size(); ++iH3) { + if (h3indices[iH3] == track.globalIndex()) { + continue; + } + const auto& h3vector = h3vectors[iH3]; + auto pivector = trackVector; + auto cm = h3vector + trackVector; + const ROOT::Math::Boost boost(cm.BoostToCM()); + boost(pivector); + if (pivector.P() < cfgCutKstar) { + keepEvent[kTritonFemto] = true; + break; + } + } + } + + for (const auto& v0 : v0s) { + const auto& posTrack = v0.posTrack_as(); + const auto& negTrack = v0.negTrack_as(); + if ((posTrack.itsNCls() < cfgCutNclusITS || posTrack.tpcNClsFound() < cfgCutNclusTPC) && + (negTrack.itsNCls() < cfgCutNclusITS || negTrack.tpcNClsFound() < cfgCutNclusTPC)) { + continue; + } + float nSigmas[2]{ + cfgBetheBlochParams->get(2, 5u) > 0.f ? getNsigma(posTrack, 2, 0) : posTrack.tpcNSigmaHe(), + cfgBetheBlochParams->get(2, 5u) > 0.f ? getNsigma(negTrack, 2, 1) : negTrack.tpcNSigmaHe()}; + if ((nSigmas[0] < cfgCutsPID->get(2, 0u) || nSigmas[0] > cfgCutsPID->get(2, 1u)) && + (nSigmas[1] < cfgCutsPID->get(2, 0u) || nSigmas[1] > cfgCutsPID->get(2, 1u))) { + continue; + } + int n2bodyVtx = fitter2body.process(getTrackParCov(posTrack), getTrackParCov(negTrack)); + if (n2bodyVtx == 0) { + continue; + } + auto vtxXYZ = fitter2body.getPCACandidate(); + o2::gpu::gpustd::array mom = {0.}; + vtxXYZ[0] -= collision.posX(); + vtxXYZ[1] -= collision.posY(); + vtxXYZ[2] -= collision.posZ(); + auto momTrackParCov = fitter2body.createParentTrackPar(); + momTrackParCov.getPxPyPzGlo(mom); + double cosPA = (vtxXYZ[0] * mom[0] + vtxXYZ[1] * mom[1] + vtxXYZ[2] * mom[2]) / + std::sqrt((vtxXYZ[0] * vtxXYZ[0] + vtxXYZ[1] * vtxXYZ[1] + vtxXYZ[2] * vtxXYZ[2]) * + (mom[0] * mom[0] + mom[1] * mom[1] + mom[2] * mom[2])); + if (cosPA < cfgCutCosPAheV0) { + continue; + } + keepEvent[kHeV0] = true; + break; + } + // // fill QA histograms // @@ -216,50 +499,160 @@ struct nucleiFilter { } // end loop over tracks - // hypertriton 3body loop - for (auto& vtx : vtx3bodydatas) { + // fH3L3Body trigger + auto bc = collision.bc_as(); + initCCDB(bc); - auto track0 = vtx.track0_as(); - auto track1 = vtx.track1_as(); - auto track2 = vtx.track2_as(); + for (const auto& decay3body : decay3bodys) { + auto track0 = decay3body.track0_as(); + auto track1 = decay3body.track1_as(); + auto track2 = decay3body.track2_as(); - if (vtx.vtxcosPA(collision.posX(), collision.posY(), collision.posZ()) < minCosPA3body) { + // track selection + // keep like-sign triplets, do not check sign of deuteron, use same cut for p and pi + if (track0.tpcNClsFound() < trgH3L3Body.mintpcNClspion || track1.tpcNClsFound() < trgH3L3Body.mintpcNClspion || track2.tpcNClsFound() < trgH3L3Body.mintpcNClsdeuteron) { continue; } - float ct = vtx.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassHyperTriton; - if (ct > lifetimecut) { + + if (std::abs(track0.eta()) > trgH3L3Body.minDaughtersEta || std::abs(track1.eta()) > trgH3L3Body.minDaughtersEta || std::abs(track2.eta()) > trgH3L3Body.minDaughtersEta) { continue; } - if (vtx.dcaVtxdaughters() > dcavtxdau) { + + bool isProton = false, isPion = false, isAntiProton = false, isAntiPion = false; + if (std::abs(track0.tpcNSigmaPr()) < std::abs(track0.tpcNSigmaPi())) { + if (track0.p() >= trgH3L3Body.minProtonPt && track0.p() <= trgH3L3Body.maxProtonPt) { + if (track0.tpcNClsFound() >= trgH3L3Body.mintpcNClsproton) { + isProton = true; + } + } + } + if (std::abs(track0.tpcNSigmaPi()) < std::abs(track0.tpcNSigmaPr())) { + if (track0.p() >= trgH3L3Body.minPionPt && track0.p() <= trgH3L3Body.maxPionPt) { + isPion = true; + } + } + if (std::abs(track1.tpcNSigmaPr()) < std::abs(track1.tpcNSigmaPi())) { + if (track1.p() >= trgH3L3Body.minProtonPt && track1.p() <= trgH3L3Body.maxProtonPt) { + if (track1.tpcNClsFound() >= trgH3L3Body.mintpcNClsproton) { + isAntiProton = true; + } + } + } + if (std::abs(track1.tpcNSigmaPi()) < std::abs(track1.tpcNSigmaPr())) { + if (track1.p() >= trgH3L3Body.minPionPt && track1.p() <= trgH3L3Body.maxPionPt) { + isAntiPion = true; + } + } + + if (!(isProton && isAntiPion) && !(isAntiProton && isPion)) { continue; } - if ((track2.tofNSigmaDe() < TofPidNsigmaMin || track2.tofNSigmaDe() > TofPidNsigmaMax) && track2.p() > minDeuteronPUseTOF) { + + if (std::abs(track2.tpcNSigmaDe()) > trgH3L3Body.tpcPIDNSigmaCut || track2.p() < trgH3L3Body.minDeuteronPt || track2.p() > trgH3L3Body.maxDeuteronPt) { continue; } - if (std::abs(track0.tpcNSigmaPr()) < TpcPidNsigmaCut && std::abs(track1.tpcNSigmaPi()) < TpcPidNsigmaCut && std::abs(track2.tpcNSigmaDe()) < TpcPidNsigmaCut && vtx.mHypertriton() > h3LMassLowerlimit && vtx.mHypertriton() < h3LMassUpperlimit) { - if (track0.tpcNClsFound() >= mintpcNClsproton && track1.tpcNClsFound() >= mintpcNClspion && track2.tpcNClsFound() >= mintpcNClsdeuteron) { - if (std::abs(vtx.dcatrack1topv()) > dcapiontopv) { - keepEvent[3] = true; - qaHists.fill(HIST("fH3LMassVsPt"), vtx.pt(), vtx.mHypertriton()); - } + + float tofNSigmaDeuteron = -999; + if (track2.has_collision() && track2.hasTOF()) { + auto originalcol = track2.collision_as(); + tofNSigmaDeuteron = bachelorTOFPID.GetTOFNSigma(track2, originalcol, collision); + } + if (track2.p() > trgH3L3Body.minDeuteronPUseTOF && (tofNSigmaDeuteron < trgH3L3Body.tofPIDNSigmaMin || tofNSigmaDeuteron > trgH3L3Body.tofPIDNSigmaMax)) { + continue; + } + + // reconstruct the secondary vertex + auto Track0 = getTrackParCov(track0); + auto Track1 = getTrackParCov(track1); + auto Track2 = getTrackParCov(track2); + int n3bodyVtx = fitter3body.process(Track0, Track1, Track2); + if (n3bodyVtx == 0) { // discard this pair + continue; + } + + std::array pos = {0.}; + const auto& vtxXYZ = fitter3body.getPCACandidate(); + for (int i = 0; i < 3; i++) { + pos[i] = vtxXYZ[i]; + } + + // Calculate DCA with respect to the collision associated to the SV, not individual tracks + gpu::gpustd::array dcaInfo; + + auto track0Par = getTrackPar(track0); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, track0Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); + auto track0dcaXY = dcaInfo[0]; + auto track0dca = std::sqrt(track0dcaXY * track0dcaXY + dcaInfo[1] * dcaInfo[1]); + + auto track1Par = getTrackPar(track1); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, track1Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); + auto track1dcaXY = dcaInfo[0]; + auto track1dca = std::sqrt(track1dcaXY * track1dcaXY + dcaInfo[1] * dcaInfo[1]); + + std::array p0 = {0.}, p1 = {0.}, p2{0.}; + const auto& propagatedTrack0 = fitter3body.getTrack(0); + const auto& propagatedTrack1 = fitter3body.getTrack(1); + const auto& propagatedTrack2 = fitter3body.getTrack(2); + propagatedTrack0.getPxPyPzGlo(p0); + propagatedTrack1.getPxPyPzGlo(p1); + propagatedTrack2.getPxPyPzGlo(p2); + std::array p3BXYZ = {p0[0] + p1[0] + p2[0], p0[1] + p1[1] + p2[1], p0[2] + p1[2] + p2[2]}; + float sqpt3B = p3BXYZ[0] * p3BXYZ[0] + p3BXYZ[1] * p3BXYZ[1]; + float sqp3B = sqpt3B + p3BXYZ[2] * p3BXYZ[2]; + float pt3B = std::sqrt(sqpt3B), p3B = std::sqrt(sqp3B); + + if (p3B < trgH3L3Body.minP3Body) { + continue; + } + + float dcaDaughters = fitter3body.getChi2AtPCACandidate(); + if (dcaDaughters > trgH3L3Body.dcavtxdau) { + continue; + } + + float vtxCosPA = RecoDecay::cpa(std::array{collision.posX(), collision.posY(), collision.posZ()}, std::array{pos[0], pos[1], pos[2]}, std::array{p3BXYZ[0], p3BXYZ[1], p3BXYZ[2]}); + if (vtxCosPA < trgH3L3Body.minCosPA3body) { + continue; + } + float ct = std::sqrt(std::pow(pos[0] - collision.posX(), 2) + std::pow(pos[1] - collision.posY(), 2) + std::pow(pos[2] - collision.posZ(), 2)) / (p3B + 1E-10) * constants::physics::MassHyperTriton; + if (ct > trgH3L3Body.lifetimecut) { + continue; + } + + float invmassH3L = RecoDecay::m(std::array{std::array{p0[0], p0[1], p0[2]}, std::array{p1[0], p1[1], p1[2]}, std::array{p2[0], p2[1], p2[2]}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); + float invmassAntiH3L = RecoDecay::m(std::array{std::array{p0[0], p0[1], p0[2]}, std::array{p1[0], p1[1], p1[2]}, std::array{p2[0], p2[1], p2[2]}}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}); + + if (invmassH3L >= trgH3L3Body.h3LMassLowerlimit && invmassH3L <= trgH3L3Body.h3LMassUpperlimit) { + // Hypertriton hypothesis + if (isProton && isAntiPion && std::abs(track1dca) >= trgH3L3Body.dcapiontopv) { + qaHists.fill(HIST("fH3LMassVsPt"), pt3B, invmassH3L); + qaHists.fill(HIST("fBachDeuTOFNsigma"), track2.p() * track2.sign(), tofNSigmaDeuteron); + qaHists.fill(HIST("fH3LDcaVsPt"), pt3B, dcaDaughters); + qaHists.fill(HIST("fH3LCosPAVsPt"), pt3B, vtxCosPA); + keepEvent[kH3L3Body] = true; } } - if (std::abs(track0.tpcNSigmaPi()) < TpcPidNsigmaCut && std::abs(track1.tpcNSigmaPr()) < TpcPidNsigmaCut && std::abs(track2.tpcNSigmaDe()) < TpcPidNsigmaCut && vtx.mAntiHypertriton() > h3LMassLowerlimit && vtx.mAntiHypertriton() < h3LMassUpperlimit) { - if (track0.tpcNClsFound() >= mintpcNClspion && track1.tpcNClsFound() >= mintpcNClsproton && track2.tpcNClsFound() >= mintpcNClsdeuteron) { - if (std::abs(vtx.dcatrack0topv()) > dcapiontopv) { - keepEvent[3] = true; - qaHists.fill(HIST("fH3LMassVsPt"), vtx.pt(), vtx.mAntiHypertriton()); - } + if (invmassAntiH3L >= trgH3L3Body.h3LMassLowerlimit && invmassAntiH3L <= trgH3L3Body.h3LMassUpperlimit) { + // Anti-Hypertriton hypothesis + if (isAntiProton && isPion && std::abs(track0dca) >= trgH3L3Body.dcapiontopv) { + qaHists.fill(HIST("fH3LMassVsPt"), pt3B, invmassAntiH3L); + qaHists.fill(HIST("fBachDeuTOFNsigma"), track2.p() * track2.sign(), tofNSigmaDeuteron); + qaHists.fill(HIST("fH3LDcaVsPt"), pt3B, dcaDaughters); + qaHists.fill(HIST("fH3LCosPAVsPt"), pt3B, vtxCosPA); + keepEvent[kH3L3Body] = true; } } - } // end loop over hypertriton 3body decay candidates + } - for (int iDecision{0}; iDecision < nNuclei + nHyperNuclei; ++iDecision) { + keepEvent[kTracked3Body] = tracked3Bodys.size() > 0; + + for (int iDecision{0}; iDecision < kNtriggers; ++iDecision) { if (keepEvent[iDecision]) { hProcessedEvents->Fill(iDecision + 1); } } - tags(keepEvent[2], keepEvent[3]); + + tags(keepEvent[kH2], keepEvent[kHe], keepEvent[kHeV0], keepEvent[kTritonFemto], keepEvent[kH3L3Body], keepEvent[kTracked3Body], keepEvent[kITSmildIonisation], keepEvent[kITSextremeIonisation]); } }; diff --git a/EventFiltering/PWGLF/strangenessFilter.cxx b/EventFiltering/PWGLF/strangenessFilter.cxx index 1e97b05d272..fea1290cc0c 100644 --- a/EventFiltering/PWGLF/strangenessFilter.cxx +++ b/EventFiltering/PWGLF/strangenessFilter.cxx @@ -15,6 +15,7 @@ /// \since June 1, 2021 #include +#include "TVector3.h" #include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" @@ -25,6 +26,7 @@ #include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" #include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/TrackParametrization.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" #include "PWGLF/DataModel/LFStrangenessTables.h" @@ -37,6 +39,7 @@ #include "Common/DataModel/Multiplicity.h" #include "CommonConstants/PhysicsConstants.h" #include "../filterTables.h" +#include "PWGLF/Utils/strangenessBuilderHelper.h" using namespace o2; using namespace o2::framework; @@ -56,11 +59,15 @@ static const std::vector massSigmaParameterNames{"p0", "p1", "p2", static const std::vector speciesNames{"Xi", "Omega"}; } // namespace stfilter +float CalculateDCAStraightToPV(float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) +{ + return std::hypot((pvY - Y) * Pz - (pvZ - Z) * Py, (pvX - X) * Pz - (pvZ - Z) * Px, (pvX - X) * Py - (pvY - Y) * Px) / std::sqrt(Px * Px + Py * Py + Pz * Pz); +} + struct strangenessFilter { // Recall the output table Produces strgtable; - TrackSelection mTrackSelector; // Define a histograms and registries HistogramRegistry QAHistos{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; @@ -68,14 +75,43 @@ struct strangenessFilter { HistogramRegistry QAHistosTriggerParticles{"QAHistosTriggerParticles", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; HistogramRegistry QAHistosStrangenessTracking{"QAHistosStrangenessTracking", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; HistogramRegistry EventsvsMultiplicity{"EventsvsMultiplicity", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - OutputObj hProcessedEvents{TH1D("hProcessedEvents", "Strangeness - event filtered;; Number of events", 14, -1., 13.)}; + OutputObj hProcessedEvents{TH1D("hProcessedEvents", "Strangeness - event filtered;; Number of events", 17, -1., 16.)}; OutputObj hCandidate{TH1F("hCandidate", "; Candidate pass selection; Number of events", 30, 0., 30.)}; OutputObj hEvtvshMinPt{TH1F("hEvtvshMinPt", " Number of h-Omega events with pT_h higher than thrd; min p_{T, trigg} (GeV/c); Number of events", 11, 0., 11.)}; - OutputObj hhXiPairsvsPt{TH1F("hhXiPairsvsPt", "pt distributions of Xi in events with a trigger particle; #it{p}_{T} (GeV/c); Number of Xi", 100, 0., 10.)}; + + // Dedicated selection criteria for lambda-lambda + struct : ConfigurableGroup { + Configurable cfgv0radiusMin{"cfgv0radiusMin", 1.2, "minimum decay radius"}; + Configurable cfgDCAPosToPVMin{"cfgDCAPosToPVMin", 0.05, "minimum DCA to PV for positive track"}; + Configurable cfgDCANegToPVMin{"cfgDCANegToPVMin", 0.2, "minimum DCA to PV for negative track"}; + Configurable cfgv0CosPA{"cfgv0CosPA", 0.995, "minimum v0 cosine"}; + Configurable cfgDCAV0Dau{"cfgDCAV0Dau", 1.0, "maximum DCA between daughters"}; + Configurable cfgV0PtMin{"cfgV0PtMin", 0, "minimum pT for lambda"}; + Configurable cfgV0RapMin{"cfgV0RapMin", -0.5, "maximum rapidity"}; + Configurable cfgV0RapMax{"cfgV0RapMax", 0.5, "maximum rapidity"}; + Configurable cfgV0LifeTime{"cfgV0LifeTime", 30., "maximum lambda lifetime"}; + Configurable cfgDaughTPCnclsMin{"cfgDaughTPCnclsMin", 70, "minimum fired crossed rows"}; + Configurable cfgITSNclus{"cfgITSNclus", 1, "minimum its cluster"}; + Configurable cfgRCrossedFindable{"cfgRCrossedFindable", 0.0, "minimum ratio of crossed rows over findable clusters"}; + Configurable cfgDaughPIDCutsTPCPr{"cfgDaughPIDCutsTPCPr", 5, "proton nsigma for TPC"}; + Configurable cfgDaughPIDCutsTPCPi{"cfgDaughPIDCutsTPCPi", 5, "pion nsigma for TPC"}; + Configurable cfgDaughEtaMin{"cfgDaughEtaMin", -0.8, "minimum daughter eta"}; + Configurable cfgDaughEtaMax{"cfgDaughEtaMax", 0.8, "maximum daughter eta"}; + Configurable cfgDaughPrPt{"cfgDaughPrPt", 0.5, "minimum daughter proton pt"}; + Configurable cfgDaughPiPt{"cfgDaughPiPt", 0.5, "minimum daughter pion pt"}; + Configurable cfgLambdaMassWindow{"cfgLambdaMassWindow", 0.01, "window for lambda mass selection"}; + Configurable cfgCompV0Rej{"cfgCompV0Rej", 0.01, "competing V0 rejection"}; + Configurable cfgMinCPAV0V0{"cfgMinCPAV0V0", 0.8, "minimum CPA of v0v0"}; + Configurable cfgMaxRadiusV0V0{"cfgMaxRadiusV0V0", 10.0, "maximum radius of v0v0"}; + Configurable cfgMaxDistanceV0V0{"cfgMaxDistanceV0V0", 5.0, "maximum distance of v0v0"}; + Configurable cfgMaxDCAV0V0{"cfgMaxDCAV0V0", 5.0, "maximum DCA of v0v0"}; + } cfgLLCuts; // Selection criteria for cascades + Configurable useCascadeMomentumAtPrimVtx{"useCascadeMomentumAtPrimVtx", false, "use cascade momentum at PV"}; Configurable doextraQA{"doextraQA", 1, "do extra QA"}; Configurable cutzvertex{"cutzvertex", 100.0f, "Accepted z-vertex range"}; + Configurable tpcmincrossedrows{"tpcmincrossedrows", 50, "Min number of crossed TPC rows"}; Configurable v0cospa{"v0cospa", 0.95, "V0 CosPA"}; Configurable casccospaxi{"casccospaxi", 0.95, "Casc CosPA"}; Configurable casccospaomega{"casccospaomega", 0.95, "Casc CosPA"}; @@ -105,10 +141,12 @@ struct strangenessFilter { Configurable nsigmatpcpr{"nsigmatpcpr", 6, "N Sigmas TPC pr"}; Configurable hastof{"hastof", 1, "Has TOF (OOB condition)"}; Configurable ptthrtof{"ptthrtof", 1.0, "Pt threshold to apply TOF condition"}; - Configurable kint7{"kint7", 0, "Apply kINT7 event selection"}; - Configurable sel7{"sel7", 0, "Apply sel7 event selection"}; Configurable sel8{"sel8", 0, "Apply sel8 event selection"}; Configurable LowLimitFT0MMult{"LowLimitFT0MMult", 3100, "FT0M selection for omega + high multiplicity trigger"}; + Configurable LowLimitFT0MMultNorm{"LowLimitFT0MMultNorm", 70, "FT0M selection for omega + high multiplicity trigger with Normalised FT0M"}; + Configurable useNormalisedMult{"useNormalisedMult", 1, "Use avarage multiplicity for HM omega like in multFilter.cxx"}; + Configurable avPyT0C{"avPyT0C", 8.83, "nch from pythia T0C"}; + Configurable avPyT0A{"avPyT0A", 8.16, "nch from pythia T0A"}; Configurable isTimeFrameBorderCut{"isTimeFrameBorderCut", 1, "Apply timeframe border cut"}; Configurable useSigmaBasedMassCutXi{"useSigmaBasedMassCutXi", true, "Mass window based on n*sigma instead of fixed"}; Configurable useSigmaBasedMassCutOmega{"useSigmaBasedMassCutOmega", true, "Mass window based on n*sigma instead of fixed"}; @@ -122,16 +160,12 @@ struct strangenessFilter { // Settings for strangeness tracking filter Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpMagPath{"grpMagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; - Configurable matLutPath{"matLutPath", "GLO/Param/MatLUT", "Path of the material LUT"}; Configurable propToDCA{"propToDCA", true, "create tracks version propagated to PCA"}; Configurable useAbsDCA{"useAbsDCA", true, "Minimise abs. distance rather than chi2"}; Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations if chi2/chi2old > this"}; - Configurable materialCorrectionType{"materialCorrectionType", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrLUT), "Type of material correction"}; Configurable minNoClsTrackedCascade{"minNoClsTrackedCascade", 70, "Minimum number of clusters required for daughters of tracked cascades"}; Configurable minPtTrackedCascade{"minPtTrackedCascade", 0., "Min. pt for tracked cascades"}; Configurable useNsigmaCutTrackedXi{"useNsigmaCutTrackedXi", true, "Mass window based on n*sigma instead of fixed"}; @@ -148,38 +182,135 @@ struct strangenessFilter { Configurable maxNSigmaBachelorTrackedOmega{"maxNSigmaBachelorTrackedOmega", 4., "Max Nsigma for bachelor of tracked Xi (Ka)"}; Configurable maxNSigmaV0PrTrackedCascade{"maxNSigmaV0PrTrackedCascade", 4., "Max Nsigma for proton from V0 fromtracked Xi"}; Configurable maxNSigmaV0PiTrackedCascade{"maxNSigmaV0PiTrackedCascade", 4., "Max Nsigma for pion from V0 fromtracked Xi"}; - Configurable minDcaTrackedXi{"minDcaTrackedXi", 0., "Minimum DCA for tracked cascades"}; + Configurable minDcaTrackedXi{"minDcaTrackedXi", -1., "Minimum DCA for tracked cascades"}; Configurable maxCpaTrackedXi{"maxCpaTrackedXi", 1., "Maximum CPA for tracked cascades"}; - Configurable minDcaTrackedOmega{"minDcaTrackedOmega", 0., "Minimum DCA for tracked cascades (ST)"}; + Configurable minDcaTrackedOmega{"minDcaTrackedOmega", -1., "Minimum DCA for tracked cascades (ST)"}; Configurable maxCpaTrackedOmega{"maxCpaTrackedOmega", 1., "Maximum CPA for tracked cascades (ST)"}; Configurable> parSigmaMass{ "parSigmaMass", {stfilter::massSigmaParameters[0], 4, 2, stfilter::massSigmaParameterNames, stfilter::speciesNames}, "Mass resolution parameters: [0]*exp([1]*x)+[2]*exp([3]*x)"}; - float bz = 0.; + + // helper object + o2::pwglf::strangenessBuilderHelper mStraHelper; + o2::vertexing::DCAFitterN<2> mDCAFitter; + + /// CCDB and info/objects to be fetched from it + Service ccdb; + int mRunNumber = 0; + float mBz = 0.; + std::vector* mMeanMultT0C; + std::vector* mMeanMultT0A; + + bool selectTrack(const auto& track) + { + return track.pt() > hMinPt && std::abs(track.eta()) < hEta && track.tpcNClsCrossedRows() >= tpcmincrossedrows && track.tpcCrossedRowsOverFindableCls() >= 0.8f && track.tpcChi2NCl() <= 4.f && track.itsChi2NCl() <= 36.f && (track.itsClusterMap() & 0x7) != 0; + } + + float getV0V0DCA(TVector3 v01pos, TVector3 v01mom, TVector3 v02pos, TVector3 v02mom) + { + TVector3 posdiff = v02pos - v01pos; + TVector3 cross = v01mom.Cross(v02mom); + TVector3 dcaVec = (posdiff.Dot(cross) / cross.Mag2()) * cross; + return dcaVec.Mag(); + } + float getV0V0CPA(TVector3 v01mom, TVector3 v02mom) + { + return v01mom.Dot(v02mom) / (v01mom.Mag() * v02mom.Mag()); + } + float getV0V0Distance(TVector3 v01pos, TVector3 v02pos) + { + TVector3 posdiff = v02pos - v01pos; + return posdiff.Mag(); + } + float getV0V0Radius(TVector3 v01pos, TVector3 v01mom, TVector3 v02pos, TVector3 v02mom) + { + TVector3 posdiff = v02pos - v01pos; + v01mom *= 1. / v01mom.Mag(); + v02mom *= 1. / v02mom.Mag(); + float dd = 1. - TMath::Power(v01mom.Dot(v02mom), 2); + if (dd < 1e-5) + return 999; + float tt = posdiff.Dot(v01mom - v01mom.Dot(v02mom) * v02mom) / dd; + float ss = -posdiff.Dot(v02mom - v01mom.Dot(v02mom) * v01mom) / dd; + TVector3 radVec = v01pos + v02pos + tt * v01mom + ss * v02mom; + radVec *= 0.5; + return radVec.Mag(); + } + bool isSelectedV0V0(TVector3 v01pos, TVector3 v01mom, TVector3 v02pos, TVector3 v02mom) + { + if (getV0V0DCA(v01pos, v01mom, v02pos, v02mom) > cfgLLCuts.cfgMaxDCAV0V0) + return false; + if (getV0V0CPA(v01mom, v02mom) < cfgLLCuts.cfgMinCPAV0V0) + return false; + if (getV0V0Distance(v01pos, v02pos) > cfgLLCuts.cfgMaxDistanceV0V0) + return false; + if (getV0V0Radius(v01pos, v01mom, v02pos, v02mom) > cfgLLCuts.cfgMaxRadiusV0V0) + return false; + + return true; + } + + template + bool isSelectedV0Daughter(T const& track) + { + if (track.tpcNClsCrossedRows() < cfgLLCuts.cfgDaughTPCnclsMin) + return false; + if (track.tpcCrossedRowsOverFindableCls() < cfgLLCuts.cfgRCrossedFindable) + return false; + if (track.itsNCls() < cfgLLCuts.cfgITSNclus) + return false; + if (track.eta() > cfgLLCuts.cfgDaughEtaMax) + return false; + if (track.eta() < cfgLLCuts.cfgDaughEtaMin) + return false; + + return true; + } + template + bool isSelectedV0DaughterPID(T const& track, int pid) // pid 0: proton, pid 1: pion + { + if (pid == 0 && std::abs(track.tpcNSigmaPr()) > cfgLLCuts.cfgDaughPIDCutsTPCPr) + return false; + if (pid == 1 && std::abs(track.tpcNSigmaPi()) > cfgLLCuts.cfgDaughPIDCutsTPCPi) + return false; + if (pid == 0 && track.pt() < cfgLLCuts.cfgDaughPrPt) + return false; + if (pid == 1 && track.pt() < cfgLLCuts.cfgDaughPiPt) + return false; + + return true; + } void init(o2::framework::InitContext&) { - ccdb->setURL(ccdbUrl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - - mTrackSelector.SetTrackType(o2::aod::track::TrackTypeEnum::Track); - mTrackSelector.SetPtRange(hMinPt, 1e10f); - mTrackSelector.SetEtaRange(-hEta, hEta); - mTrackSelector.SetRequireITSRefit(true); - mTrackSelector.SetRequireTPCRefit(true); - mTrackSelector.SetRequireGoldenChi2(false); - mTrackSelector.SetMinNCrossedRowsTPC(70); - mTrackSelector.SetMinNCrossedRowsOverFindableClustersTPC(0.8f); - mTrackSelector.SetMaxChi2PerClusterTPC(4.f); - mTrackSelector.SetRequireHitsInITSLayers(1, {0, 1, 2}); // one hit in any of the first three layers of IB - mTrackSelector.SetMaxChi2PerClusterITS(36.f); - // mTrackSelector.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f / pow(pt, 1.1f); }); - mTrackSelector.SetMaxDcaXY(1.f); - mTrackSelector.SetMaxDcaZ(2.f); + // set V0 parameters in the helper + mStraHelper.v0selections.minCrossedRows = tpcmincrossedrows; + if (dcamesontopv <= dcabaryontopv) + mStraHelper.v0selections.dcanegtopv = dcamesontopv; + else + mStraHelper.v0selections.dcanegtopv = dcabaryontopv; // get the minimum one + if (dcamesontopv <= dcabaryontopv) + mStraHelper.v0selections.dcapostopv = dcamesontopv; + else + mStraHelper.v0selections.dcapostopv = dcabaryontopv; // get the minimum one + mStraHelper.v0selections.v0cospa = v0cospa; + mStraHelper.v0selections.dcav0dau = dcav0dau; + mStraHelper.v0selections.v0radius = v0radius; + mStraHelper.v0selections.maxDaughterEta = etadau; + + // set cascade parameters in the helper + mStraHelper.cascadeselections.minCrossedRows = tpcmincrossedrows; + mStraHelper.cascadeselections.dcabachtopv = dcabachtopv; + mStraHelper.cascadeselections.cascradius = cascradius; + if (casccospaxi <= casccospaomega) + mStraHelper.cascadeselections.casccospa = casccospaxi; + else + mStraHelper.cascadeselections.casccospa = casccospaomega; // get the minimum one + mStraHelper.cascadeselections.dcacascdau = dcacascdau; + mStraHelper.cascadeselections.lambdaMassWindow = masslambdalimit; + mStraHelper.cascadeselections.maxDaughterEta = etadau; hProcessedEvents->GetXaxis()->SetBinLabel(1, "Events processed"); hProcessedEvents->GetXaxis()->SetBinLabel(2, "Event selection"); @@ -195,9 +326,12 @@ struct strangenessFilter { hProcessedEvents->GetXaxis()->SetBinLabel(12, aod::filtering::TrackedXi::columnLabel()); hProcessedEvents->GetXaxis()->SetBinLabel(13, aod::filtering::TrackedOmega::columnLabel()); hProcessedEvents->GetXaxis()->SetBinLabel(14, aod::filtering::OmegaHighMult::columnLabel()); + hProcessedEvents->GetXaxis()->SetBinLabel(15, aod::filtering::DoubleOmega::columnLabel()); + hProcessedEvents->GetXaxis()->SetBinLabel(16, aod::filtering::OmegaXi::columnLabel()); + hProcessedEvents->GetXaxis()->SetBinLabel(17, "LL"); hCandidate->GetXaxis()->SetBinLabel(1, "All"); - hCandidate->GetXaxis()->SetBinLabel(2, "Has_V0"); + hCandidate->GetXaxis()->SetBinLabel(2, "PassBuilderSel"); hCandidate->GetXaxis()->SetBinLabel(3, "DCA_meson"); hCandidate->GetXaxis()->SetBinLabel(4, "DCA_baryon"); hCandidate->GetXaxis()->SetBinLabel(5, "TPCNsigma_pion"); @@ -215,10 +349,12 @@ struct strangenessFilter { hCandidate->GetXaxis()->SetBinLabel(17, "CascCosPA"); hCandidate->GetXaxis()->SetBinLabel(18, "DCAV0ToPV"); hCandidate->GetXaxis()->SetBinLabel(19, "ProperLifeTime"); + hCandidate->GetXaxis()->SetBinLabel(20, "Rapidity"); std::vector centBinning = {0., 1., 5., 10., 20., 30., 40., 50., 70., 100.}; AxisSpec multAxisNTPV = {100, 0.0f, 100.0f, "N. tracks PV estimator"}; AxisSpec multAxisT0M = {600, 0.0f, 6000.0f, "T0M multiplicity estimator"}; + AxisSpec multAxisT0MNorm = {150, 0.0f, 150.0f, "Normalised T0M multiplicity estimator"}; AxisSpec multAxisV0A = {500, 0.0f, 25000.0f, "V0A multiplicity estimator"}; AxisSpec ximassAxis = {200, 1.28f, 1.36f}; AxisSpec omegamassAxis = {200, 1.59f, 1.75f}; @@ -275,11 +411,13 @@ struct strangenessFilter { QAHistosTriggerParticles.add("hPtTriggerSelEv", "hPtTriggerSelEv", HistType::kTH1F, {{300, 0, 30, "Pt of trigger particles after selections"}}); QAHistosTriggerParticles.add("hEtaTriggerAllEv", "hEtaTriggerAllEv", HistType::kTH2F, {{180, -1.4, 1.4, "Eta of trigger particles"}, {ptTriggAxis}}); QAHistosTriggerParticles.add("hPhiTriggerAllEv", "hPhiTriggerAllEv", HistType::kTH2F, {{100, 0, 2 * TMath::Pi(), "Phi of trigger particles"}, {ptTriggAxis}}); - QAHistosTriggerParticles.add("hDCAxyTriggerAllEv", "hDCAxyTriggerAllEv", HistType::kTH2F, {{400, -0.2, 0.2, "DCAxy of trigger particles"}, {ptTriggAxis}}); - QAHistosTriggerParticles.add("hDCAzTriggerAllEv", "hDCAzTriggerAllEv", HistType::kTH2F, {{400, -0.2, 0.2, "DCAz of trigger particles"}, {ptTriggAxis}}); EventsvsMultiplicity.add("AllEventsvsMultiplicityFT0M", "T0M distribution of all events", HistType::kTH1F, {multAxisT0M}); EventsvsMultiplicity.add("AllEventsvsMultiplicityFT0MwOmega", "T0M distribution of events w/ Omega candidate", HistType::kTH1F, {multAxisT0M}); + EventsvsMultiplicity.add("AllEventsvsMultiplicityFT0MNorm", "T0M Normalised of all events", HistType::kTH1F, {multAxisT0MNorm}); + EventsvsMultiplicity.add("AllEventsvsMultiplicityFT0MwOmegaNorm", "T0M distribution of events w/ Omega candidate - Normalised FT0M", HistType::kTH1F, {multAxisT0MNorm}); + EventsvsMultiplicity.add("AllEventsvsMultiplicityFT0MNoFT0", "T0M distribution of events without FT0", HistType::kTH1F, {multAxisT0M}); + if (doextraQA) { EventsvsMultiplicity.add("AllEventsvsMultiplicityZeqV0A", "ZeqV0A distribution of all events", HistType::kTH1F, {multAxisV0A}); EventsvsMultiplicity.add("hadEventsvsMultiplicityZeqV0A", "ZeqV0A distribution of events with hight pT hadron", HistType::kTH1F, {multAxisV0A}); @@ -313,12 +451,6 @@ struct strangenessFilter { QAHistos.add("hRapXi", "Rap Xi", HistType::kTH1F, {{100, -1, 1}}); QAHistos.add("hRapOmega", "Rap Omega", HistType::kTH1F, {{100, -1, 1}}); - // strangeness tracking - if (static_cast(materialCorrectionType.value) == o2::base::Propagator::MatCorrType::USEMatCorrLUT) { - auto* lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get("GLO/Param/MatLUT")); - o2::base::Propagator::Instance(true)->setMatLUT(lut); - } - QAHistosStrangenessTracking.add("hStRVsPtTrkCasc", "Tracked cascades;p_{T} (GeV/#it{c});R (cm)", HistType::kTH2D, {{200, 0., 10.}, {200, 0., 50}}); QAHistosStrangenessTracking.add("hMassOmegaTrkCasc", "Tracked cascades;m_{#Omega} (GeV/#it{c}^{2})", HistType::kTH1D, {{1000, 1., 3.}}); QAHistosStrangenessTracking.add("hMassXiTrkCasc", "Tracked cascades;m_{#Xi} (GeV/#it{c}^{2})", HistType::kTH1D, {{1000, 1., 3.}}); @@ -377,19 +509,39 @@ struct strangenessFilter { } } - // Filters - Filter trackFilter = (nabs(aod::track::eta) < hEta) && (aod::track::pt > hMinPt); + void initCCDB(int run) + { + if (run != mRunNumber) { + mRunNumber = run; + o2::parameters::GRPMagField* grpmag = ccdb->getForRun("GLO/Config/GRPMagField", run); + o2::base::Propagator::initFieldFromGRP(grpmag); + mBz = static_cast(grpmag->getNominalL3Field()); + mMeanMultT0C = ccdb->getForRun>("Users/e/ekryshen/meanT0C", run); + mMeanMultT0A = ccdb->getForRun>("Users/e/ekryshen/meanT0A", run); + + mDCAFitter.setBz(mBz); + mDCAFitter.setPropagateToPCA(propToDCA); + mDCAFitter.setMaxR(maxR); + mDCAFitter.setMaxDZIni(maxDZIni); + mDCAFitter.setMinParamChange(minParamChange); + mDCAFitter.setMinRelChi2Change(minRelChi2Change); + mDCAFitter.setUseAbsDCA(useAbsDCA); + mStraHelper.fitter.setBz(mBz); + } + if (!mStraHelper.lut) { /// done only once + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(true); + auto* lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get("GLO/Param/MatLUT")); + o2::base::Propagator::Instance()->setMatLUT(lut); + mStraHelper.lut = lut; + } + } // Tables - using CollisionCandidates = soa::Join::iterator; - // using CollisionCandidatesRun3 = soa::Join::iterator; - using CollisionCandidatesRun3 = soa::Join::iterator; - using TrackCandidates = soa::Filtered>; - using DaughterTracks = soa::Join; - using Cascades = aod::CascDataExt; - - Service ccdb; - int runNumber; + using CollisionCandidates = soa::Join::iterator; + using TrackCandidates = soa::Join; float getMassWindow(const stfilter::species s, const float pt, const float nsigma = 6) { @@ -398,42 +550,114 @@ struct strangenessFilter { } //////////////////////////////////////////////////////// - ////////// Strangeness Filter - Run 2 conv ///////////// + ////////// Strangeness Filter ////////////////////////// //////////////////////////////////////////////////////// void fillTriggerTable(bool keepEvent[]) { - strgtable(keepEvent[0], keepEvent[1], keepEvent[2], keepEvent[3], keepEvent[4], keepEvent[5], keepEvent[6], keepEvent[7], keepEvent[8], keepEvent[9]); + strgtable(keepEvent[0], keepEvent[1], keepEvent[2], keepEvent[3], keepEvent[4], keepEvent[5], keepEvent[6], keepEvent[7], keepEvent[8], keepEvent[9], keepEvent[10], keepEvent[11], keepEvent[12]); } - void processRun2(CollisionCandidates const& collision, TrackCandidates const& tracks, Cascades const& fullCasc, DaughterTracks& /*dtracks*/) + void process(CollisionCandidates const& collision, TrackCandidates const& tracks, aod::Cascades const& cascadesBase, aod::AssignedTrackedCascades const& trackedCascades, aod::AssignedTrackedV0s const& /*trackedV0s*/, aod::AssignedTracked3Bodys const& /*tracked3Bodys*/, aod::V0s const& v0Base, aod::BCs const&, aod::FT0s const& /*ft0s*/) { - // Is event good? [0] = Omega, [1] = high-pT hadron + Xi, [2] = 2Xi, [3] = 3Xi, [4] = 4Xi, [5] single-Xi, [6] Omega with high radius - // [7] tracked Xi, [8] tracked Omega, [9] tracked V0, [10] tracked 3Body - bool keepEvent[9]{}; // explicitly zero-initialised + // Is event good? [0] = Omega, [1] = high-pT hadron + Omega, [2] = 2Xi, [3] = 3Xi, [4] = 4Xi, [5] single-Xi, [6] Omega with high radius + // [7] tracked Xi, [8] tracked Omega, [9] Omega + high mult event + bool keepEvent[13]{}; // explicitly zero-initialised + std::vector> v0sFromOmegaID; + std::vector> v0sFromXiID; + + initCCDB(collision.bc().runNumber()); - if (kint7 && !collision.alias_bit(kINT7)) { + if (sel8 && !collision.sel8()) { fillTriggerTable(keepEvent); return; } - if (sel7 && !collision.sel7()) { + hProcessedEvents->Fill(-0.5); + + if (isTimeFrameBorderCut && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { fillTriggerTable(keepEvent); return; } - if (sel8 && !collision.sel8()) { + // all processed events after event selection + hProcessedEvents->Fill(0.5); + + if (std::fabs(collision.posZ()) > cutzvertex) { fillTriggerTable(keepEvent); return; } - if (TMath::Abs(collision.posZ()) > cutzvertex) { - fillTriggerTable(keepEvent); - return; + QAHistos.fill(HIST("hVtxZ"), collision.posZ()); + if (doextraQA) { + EventsvsMultiplicity.fill(HIST("AllEventsvsMultiplicityZeqV0A"), collision.multZeqFV0A()); + EventsvsMultiplicity.fill(HIST("AllEventsvsMultiplicityZeqT0M"), collision.multZeqFT0A() + collision.multZeqFT0C()); + EventsvsMultiplicity.fill(HIST("AllEventsvsMultiplicityZeqNTracksPV"), collision.multZeqNTracksPV()); } - if (doextraQA) { - EventsvsMultiplicity.fill(HIST("AllEventsvsMultiplicity"), collision.centRun2V0M()); - QAHistos.fill(HIST("hCentrality"), collision.centRun2V0M()); + Bool_t isHighMultEvent = 0; + float multFT0MNorm = 0.f; + EventsvsMultiplicity.fill(HIST("AllEventsvsMultiplicityFT0M"), collision.multFT0M()); + if (!useNormalisedMult) { + if (collision.multFT0M() > LowLimitFT0MMult) { + isHighMultEvent = 1; + } + } else { + float meanMultT0C = 0.f; + float fac_FT0C_ebe = 1.; + meanMultT0C = (*mMeanMultT0C)[0]; + if (meanMultT0C > 0) { + fac_FT0C_ebe = avPyT0C / meanMultT0C; + } + float meanMultT0A = 0.f; + meanMultT0A = (*mMeanMultT0A)[0]; + float fac_FT0A_ebe = 1.; + if (meanMultT0A > 0) { + fac_FT0A_ebe = avPyT0A / meanMultT0A; + } + LOG(debug) << "Mean mults t0:" << fac_FT0A_ebe << " " << fac_FT0C_ebe; + if (collision.has_foundFT0()) { + static int ampneg = 0; + auto ft0 = collision.foundFT0(); + float sumAmpFT0C = 0.f; + for (std::size_t i_c = 0; i_c < ft0.amplitudeC().size(); i_c++) { + float amplitude = ft0.amplitudeC()[i_c]; + sumAmpFT0C += amplitude; + } + float sumAmpFT0A = 0.f; + for (std::size_t i_a = 0; i_a < ft0.amplitudeA().size(); i_a++) { + float amplitude = ft0.amplitudeA()[i_a]; + sumAmpFT0A += amplitude; + } + const int nEta5 = 2; // FT0C + FT0A + float weigthsEta5[nEta5] = {0.0490638, 0.010958415}; + if (sumAmpFT0C >= 0 || sumAmpFT0A >= 0) { + if (meanMultT0A > 0 && meanMultT0C > 0) { + multFT0MNorm = sumAmpFT0C * fac_FT0C_ebe + sumAmpFT0A * fac_FT0A_ebe; + } else { + multFT0MNorm = sumAmpFT0C * weigthsEta5[0] + sumAmpFT0A * weigthsEta5[1]; + } + LOG(debug) << "meanMult:" << multFT0MNorm << " multFT0M:" << collision.multFT0M(); + if (sumAmpFT0A < 0 || sumAmpFT0C < 0) { + // LOG(info) << "ampa: " << sumAmpFT0A << " ampc:" << sumAmpFT0C; + ampneg++; + } + EventsvsMultiplicity.fill(HIST("AllEventsvsMultiplicityFT0MNorm"), multFT0MNorm); + if (multFT0MNorm > LowLimitFT0MMultNorm) { + isHighMultEvent = 1; + LOG(debug) << "Found FT0 using norm mult"; + } + } else { + LOG(warn) << "Found FT0 but, bith amplitudes are <=0 "; + EventsvsMultiplicity.fill(HIST("AllEventsvsMultiplicityFT0MNorm"), 148); + EventsvsMultiplicity.fill(HIST("AllEventsvsMultiplicityFT0MNoFT0"), collision.multFT0M()); + } + if (ampneg) { + LOG(warn) << "# of negative amplitudes:" << ampneg; + } + } else { + LOG(debug) << "FT0 not Found, using FT0M"; + EventsvsMultiplicity.fill(HIST("AllEventsvsMultiplicityFT0MNorm"), 149); + EventsvsMultiplicity.fill(HIST("AllEventsvsMultiplicityFT0MNoFT0"), collision.multFT0M()); + } } - hProcessedEvents->Fill(0.5); // constants const float ctauxi = 4.91; // from PDG @@ -448,280 +672,121 @@ struct strangenessFilter { int xicounterYN = 0; int omegacounter = 0; int omegalargeRcounter = 0; - int triggcounterForEstimates = 0; - // int triggcounter = 0; + const std::array pvPos{collision.posX(), collision.posY(), collision.posZ()}; + float pvX = 0.0f, pvY = 0.0f, pvZ = 0.0f; - for (auto& casc : fullCasc) { // loop over cascades - triggcounterForEstimates = 0; - auto bachelor = casc.bachelor_as(); - auto posdau = casc.posTrack_as(); - auto negdau = casc.negTrack_as(); - - bool isXi = false; - bool isXiYN = false; - bool isOmega = false; - bool isOmegalargeR = false; + // strangeness tracking selection + const auto primaryVertex = getPrimaryVertex(collision); + o2::dataformats::DCA impactParameterTrk; - // Position - xipos = std::hypot(casc.x() - collision.posX(), casc.y() - collision.posY(), casc.z() - collision.posZ()); - // Total momentum - xiptotmom = std::hypot(casc.px(), casc.py(), casc.pz()); - // Proper lifetime - xiproperlifetime = o2::constants::physics::MassXiMinus * xipos / (xiptotmom + 1e-13); - omegaproperlifetime = o2::constants::physics::MassOmegaMinus * xipos / (xiptotmom + 1e-13); + std::vector> v0sSelTuple; + for (auto& v00 : v0Base) { // loop over v0 for pre selection + hCandidate->Fill(0.5); // All candidates - if (casc.sign() == 1) { - if (TMath::Abs(casc.dcapostopv()) < dcamesontopv) { - continue; - } - if (TMath::Abs(casc.dcanegtopv()) < dcabaryontopv) { - continue; - } - if (TMath::Abs(posdau.tpcNSigmaPi()) > nsigmatpcpi) { - continue; - } - if (TMath::Abs(negdau.tpcNSigmaPr()) > nsigmatpcpr) { - continue; - } - } else { - if (TMath::Abs(casc.dcanegtopv()) < dcamesontopv) { - continue; - } - if (TMath::Abs(casc.dcapostopv()) < dcabaryontopv) { - continue; - } - if (TMath::Abs(posdau.tpcNSigmaPr()) > nsigmatpcpr) { - continue; - } - if (TMath::Abs(negdau.tpcNSigmaPi()) > nsigmatpcpi) { - continue; - } + if (v00.v0Type() != 1) { + continue; } - // these selection differ for Xi and Omegas: - if (TMath::Abs(posdau.eta()) > etadau) { + + const auto posTrack0 = v00.posTrack_as(); + const auto negTrack0 = v00.negTrack_as(); + + if (!isSelectedV0Daughter(posTrack0) || !isSelectedV0Daughter(negTrack0)) { continue; } - if (TMath::Abs(negdau.eta()) > etadau) { + + auto trackParPos0 = getTrackParCov(posTrack0); + auto trackParNeg0 = getTrackParCov(negTrack0); + + if (!mStraHelper.buildV0Candidate(v00.collisionId(), pvPos[0], pvPos[1], pvPos[2], posTrack0, negTrack0, trackParPos0, trackParNeg0)) { continue; } - if (TMath::Abs(bachelor.eta()) > etadau) { + + if (std::hypot(mStraHelper.v0.position[0], mStraHelper.v0.position[1]) < cfgLLCuts.cfgv0radiusMin) { continue; } - if (TMath::Abs(casc.dcabachtopv()) < dcabachtopv) { + if (std::fabs(mStraHelper.v0.positiveDCAxy) < cfgLLCuts.cfgDCAPosToPVMin) { continue; } - if (casc.v0radius() < v0radius) { + if (std::fabs(mStraHelper.v0.negativeDCAxy) < cfgLLCuts.cfgDCANegToPVMin) { continue; } - if (casc.cascradius() < cascradius) { + if (TMath::Cos(mStraHelper.v0.pointingAngle) < cfgLLCuts.cfgv0CosPA) { continue; } - if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < v0cospa) { + if (std::fabs(mStraHelper.v0.daughterDCA) > cfgLLCuts.cfgDCAV0Dau) { continue; } - if (casc.dcaV0daughters() > dcav0dau) { + if (std::hypot(mStraHelper.v0.momentum[0], mStraHelper.v0.momentum[1]) < cfgLLCuts.cfgV0PtMin) { continue; } - if (casc.dcacascdaughters() > dcacascdau) { + double yLambda = RecoDecay::y(array{mStraHelper.v0.momentum[0], mStraHelper.v0.momentum[1], mStraHelper.v0.momentum[2]}, o2::constants::physics::MassLambda0); + if (yLambda < cfgLLCuts.cfgV0RapMin) { continue; } - if (TMath::Abs(casc.mLambda() - constants::physics::MassLambda) > masslambdalimit) { + if (yLambda > cfgLLCuts.cfgV0RapMax) { continue; } - if (TMath::Abs(casc.eta()) > eta) { + double distovertotmom = std::hypot(mStraHelper.v0.position[0] - collision.posX(), mStraHelper.v0.position[1] - collision.posY(), mStraHelper.v0.position[2] - collision.posZ()) / (std::hypot(mStraHelper.v0.momentum[0], mStraHelper.v0.momentum[1], mStraHelper.v0.momentum[2]) + 1e-13); + if (distovertotmom * o2::constants::physics::MassLambda0 > cfgLLCuts.cfgV0LifeTime) { continue; } - isXi = (TMath::Abs(bachelor.tpcNSigmaPi()) < nsigmatpcpi) && - (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) > casccospaxi) && - (casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()) > dcav0topv) && - (TMath::Abs(casc.mXi() - o2::constants::physics::MassXiMinus) < ximasswindow) && - (TMath::Abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > omegarej) && - (xiproperlifetime < properlifetimefactor * ctauxi) && - (TMath::Abs(casc.yXi()) < rapidity); // add PID on bachelor - isXiYN = (TMath::Abs(bachelor.tpcNSigmaPi()) < nsigmatpcpi) && - (casc.cascradius() > lowerradiusXiYN) && - (TMath::Abs(casc.mXi() - o2::constants::physics::MassXiMinus) < ximasswindow) && - (TMath::Abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > omegarej) && - (xiproperlifetime < properlifetimefactor * ctauxi) && - (TMath::Abs(casc.yXi()) < rapidity); // add PID on bachelor - isOmega = (TMath::Abs(bachelor.tpcNSigmaKa()) < nsigmatpcka) && - (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) > casccospaomega) && - (casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()) > dcav0topv) && - (casc.cascradius() < upperradiusOmega) && - (TMath::Abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) < omegamasswindow) && - (TMath::Abs(casc.mXi() - o2::constants::physics::MassXiMinus) > xirej) && - (omegaproperlifetime < properlifetimefactor * ctauomega) && - (TMath::Abs(casc.yOmega()) < rapidity); // add PID on bachelor - isOmegalargeR = (TMath::Abs(bachelor.tpcNSigmaKa()) < nsigmatpcka) && - (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) > casccospaomega) && - (casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()) > dcav0topv) && - (casc.cascradius() > lowerradiusOmega) && - (TMath::Abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) < omegamasswindow) && - (TMath::Abs(casc.mXi() - o2::constants::physics::MassXiMinus) > xirej) && - (omegaproperlifetime < properlifetimefactor * ctauomega) && - (TMath::Abs(casc.yOmega()) < rapidity); // add PID on bachelor - - if (isXi) { - // Count number of Xi candidates - xicounter++; - - // Plot for estimates - if (tracks.size() > 0) - triggcounterForEstimates = 1; - if (triggcounterForEstimates && (TMath::Abs(casc.mXi() - o2::constants::physics::MassXiMinus) < 0.01)) - hhXiPairsvsPt->Fill(casc.pt()); // Fill the histogram with all the Xis produced in events with a trigger particle - // End plot for estimates - } - if (isXiYN) { - // Xis for YN interactions - xicounterYN++; - } - if (isOmega) { - // Count number of Omega candidates - omegacounter++; - } - if (isOmegalargeR) { - // Count number of Omega candidates with high radius - omegalargeRcounter++; + int Tag = 0; + if (isSelectedV0DaughterPID(posTrack0, 0) && isSelectedV0DaughterPID(negTrack0, 1)) { + if (cfgLLCuts.cfgLambdaMassWindow > std::fabs(mStraHelper.v0.massLambda - o2::constants::physics::MassLambda0)) { + if (cfgLLCuts.cfgCompV0Rej < std::fabs(mStraHelper.v0.massK0Short - o2::constants::physics::MassLambda0)) { + Tag++; + } + } + } // lambda + if (isSelectedV0DaughterPID(posTrack0, 1) && isSelectedV0DaughterPID(negTrack0, 0)) { + if (cfgLLCuts.cfgLambdaMassWindow > std::fabs(mStraHelper.v0.massAntiLambda - o2::constants::physics::MassLambda0)) { + if (cfgLLCuts.cfgCompV0Rej < std::fabs(mStraHelper.v0.massK0Short - o2::constants::physics::MassLambda0)) { + Tag++; + } + } + } // anti lambda + if (Tag != 1) { // Select when only one hypothesis is satisfied + continue; } - } // end loop over cascades - // Omega trigger definition - if (omegacounter > 0) { - keepEvent[0] = true; + TVector3 v0pos(mStraHelper.v0.position[0], mStraHelper.v0.position[1], mStraHelper.v0.position[2]); + TVector3 v0mom(mStraHelper.v0.momentum[0], mStraHelper.v0.momentum[1], mStraHelper.v0.momentum[2]); + + v0sSelTuple.emplace_back(posTrack0.globalIndex(), negTrack0.globalIndex(), v0pos, v0mom); } - // High-pT hadron + Xi trigger definition - if (xicounter > 0) { - for (auto track : tracks) { // start loop over tracks - if (isTrackFilter && !mTrackSelector.IsSelected(track)) { + for (size_t i = 0; i < v0sSelTuple.size(); ++i) { + for (size_t j = i + 1; j < v0sSelTuple.size(); ++j) { + auto d00 = std::get<0>(v0sSelTuple[i]); + auto d01 = std::get<1>(v0sSelTuple[i]); + auto d10 = std::get<0>(v0sSelTuple[j]); + auto d11 = std::get<1>(v0sSelTuple[j]); + if (d00 == d10 || d00 == d11 || d01 == d10 || d01 == d11) { continue; } - // triggcounter++; - keepEvent[1] = true; - } // end loop over tracks - } - - // 2Xi trigger definition - if (xicounter > 1) { - keepEvent[2] = true; - } - - // 3Xi trigger definition - if (xicounter > 2) { - keepEvent[3] = true; - } - - // 4Xi trigger definition - if (xicounter > 3) { - keepEvent[4] = true; - } - - // Single-Xi (YN) trigger definition - if (xicounterYN > 0) { - keepEvent[5] = true; - } - - // Omega with high radius trigger definition - if (omegalargeRcounter > 0) { - keepEvent[6] = true; - } - - // Fill centrality dependent histos - if (keepEvent[0]) { - hProcessedEvents->Fill(2.5); - } - if (keepEvent[1]) { - hProcessedEvents->Fill(3.5); - } - if (keepEvent[2]) { - hProcessedEvents->Fill(4.5); - } - if (keepEvent[3]) { - hProcessedEvents->Fill(5.5); - } - if (keepEvent[4]) { - hProcessedEvents->Fill(6.5); - } - if (keepEvent[5]) { - hProcessedEvents->Fill(7.5); - } - if (keepEvent[6]) { - hProcessedEvents->Fill(8.5); - } - - // Filling the table - fillTriggerTable(keepEvent); - } - // - PROCESS_SWITCH(strangenessFilter, processRun2, "Process data Run2", true); - - ////////////////////////////////////////////////////// - ////////// Strangeness Filter - Run 3 MC ///////////// - ////////////////////////////////////////////////////// - - void processRun3(CollisionCandidatesRun3 const& collision, TrackCandidates const& tracks, Cascades const& fullCasc, DaughterTracks& /*dtracks*/, - aod::AssignedTrackedCascades const& trackedCascades, aod::Cascades const& /*cascades*/, aod::AssignedTrackedV0s const& /*trackedV0s*/, aod::AssignedTracked3Bodys const& /*tracked3Bodys*/, aod::V0s const&, aod::BCsWithTimestamps const&) - { - // Is event good? [0] = Omega, [1] = high-pT hadron + Omega, [2] = 2Xi, [3] = 3Xi, [4] = 4Xi, [5] single-Xi, [6] Omega with high radius - // [7] tracked Xi, [8] tracked Omega, [9] Omega + high mult event - bool keepEvent[10]{}; // explicitly zero-initialised - - if (sel8 && !collision.sel8()) { - fillTriggerTable(keepEvent); - return; - } - hProcessedEvents->Fill(-0.5); - - if (isTimeFrameBorderCut && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { - fillTriggerTable(keepEvent); - return; - } - // all processed events after event selection - hProcessedEvents->Fill(0.5); - - if (TMath::Abs(collision.posZ()) > cutzvertex) { - fillTriggerTable(keepEvent); - return; - } - QAHistos.fill(HIST("hVtxZ"), collision.posZ()); - if (doextraQA) { - EventsvsMultiplicity.fill(HIST("AllEventsvsMultiplicityZeqV0A"), collision.multZeqFV0A()); - EventsvsMultiplicity.fill(HIST("AllEventsvsMultiplicityZeqT0M"), collision.multZeqFT0A() + collision.multZeqFT0C()); - EventsvsMultiplicity.fill(HIST("AllEventsvsMultiplicityZeqNTracksPV"), collision.multZeqNTracksPV()); + auto v00pos = std::get<2>(v0sSelTuple[i]); + auto v00mom = std::get<3>(v0sSelTuple[i]); + auto v01pos = std::get<2>(v0sSelTuple[j]); + auto v01mom = std::get<3>(v0sSelTuple[j]); + if (isSelectedV0V0(v00pos, v00mom, v01pos, v01mom)) { + keepEvent[12] = true; + } + } } - Bool_t isHighMultEvent = 0; - EventsvsMultiplicity.fill(HIST("AllEventsvsMultiplicityFT0M"), collision.multFT0M()); - if (collision.multFT0M() > LowLimitFT0MMult) - isHighMultEvent = 1; - - // constants - const float ctauxi = 4.91; // from PDG - const float ctauomega = 2.461; // from PDG - - // variables - float xipos = -1.; - float xiproperlifetime = -1.; - float omegaproperlifetime = -1.; - float xiptotmom = -1.; - int xicounter = 0; - int xicounterYN = 0; - int omegacounter = 0; - int omegalargeRcounter = 0; - int triggcounter = 0; - int triggcounterAllEv = 0; - int triggcounterForEstimates = 0; + for (auto& casc : cascadesBase) { // loop over cascades + hCandidate->Fill(0.5); // All candidates - for (auto& casc : fullCasc) { // loop over cascades - triggcounterForEstimates = 0; + const auto bachTrack = casc.bachelor_as(); + const auto v0Dau = casc.v0_as(); + const auto negTrack = v0Dau.negTrack_as(); + const auto posTrack = v0Dau.posTrack_as(); - hCandidate->Fill(0.5); // All candidates - hCandidate->Fill(1.5); // V0 exists - deprecated - auto bachelor = casc.bachelor_as(); - auto posdau = casc.posTrack_as(); - auto negdau = casc.negTrack_as(); + if (!mStraHelper.buildCascadeCandidate(casc.collisionId(), pvPos[0], pvPos[1], pvPos[2], posTrack, negTrack, bachTrack, -1, useCascadeMomentumAtPrimVtx, -1)) { + continue; + } + hCandidate->Fill(1.5); // Built and selected candidates in StraBuilder bool isXi = false; bool isXiYN = false; @@ -729,280 +794,291 @@ struct strangenessFilter { bool isOmegalargeR = false; // QA - QAHistos.fill(HIST("hMassXiBefSelvsPt"), casc.mXi(), casc.pt()); - QAHistos.fill(HIST("hMassOmegaBefSelvsPt"), casc.mOmega(), casc.pt()); - + double massXi = mStraHelper.cascade.massXi; + double massOmega = mStraHelper.cascade.massOmega; + double ptCasc = RecoDecay::sqrtSumOfSquares(mStraHelper.cascade.cascadeMomentum[0], mStraHelper.cascade.cascadeMomentum[1]); + QAHistos.fill(HIST("hMassXiBefSelvsPt"), massXi, ptCasc); + QAHistos.fill(HIST("hMassOmegaBefSelvsPt"), massOmega, ptCasc); // Position - xipos = std::hypot(casc.x() - collision.posX(), casc.y() - collision.posY(), casc.z() - collision.posZ()); + xipos = std::hypot(mStraHelper.cascade.cascadePosition[0] - collision.posX(), mStraHelper.cascade.cascadePosition[1] - collision.posY(), mStraHelper.cascade.cascadePosition[2] - collision.posZ()); // Total momentum - xiptotmom = std::hypot(casc.px(), casc.py(), casc.pz()); + xiptotmom = std::hypot(mStraHelper.cascade.cascadeMomentum[0], mStraHelper.cascade.cascadeMomentum[1], mStraHelper.cascade.cascadeMomentum[2]); // Proper lifetime xiproperlifetime = o2::constants::physics::MassXiMinus * xipos / (xiptotmom + 1e-13); omegaproperlifetime = o2::constants::physics::MassOmegaMinus * xipos / (xiptotmom + 1e-13); + // Radii + double Cascv0radius = std::hypot(mStraHelper.cascade.v0Position[0], mStraHelper.cascade.v0Position[1]); + double Casccascradius = std::hypot(mStraHelper.cascade.cascadePosition[0], mStraHelper.cascade.cascadePosition[1]); + // Rapidity + double etaCasc = RecoDecay::eta(std::array{mStraHelper.cascade.cascadeMomentum[0], mStraHelper.cascade.cascadeMomentum[1], mStraHelper.cascade.cascadeMomentum[2]}); + // pointing angle + double v0DauCPA = RecoDecay::cpa(pvPos, array{mStraHelper.cascade.v0Position[0], mStraHelper.cascade.v0Position[1], mStraHelper.cascade.v0Position[2]}, array{mStraHelper.cascade.positiveMomentum[0] + mStraHelper.cascade.negativeMomentum[0], mStraHelper.cascade.positiveMomentum[1] + mStraHelper.cascade.negativeMomentum[1], mStraHelper.cascade.positiveMomentum[2] + mStraHelper.cascade.negativeMomentum[2]}); + double cascCPA = RecoDecay::cpa( + pvPos, + array{mStraHelper.cascade.cascadePosition[0], mStraHelper.cascade.cascadePosition[1], mStraHelper.cascade.cascadePosition[2]}, + array{mStraHelper.cascade.positiveMomentum[0] + mStraHelper.cascade.negativeMomentum[0] + mStraHelper.cascade.bachelorMomentum[0], mStraHelper.cascade.positiveMomentum[1] + mStraHelper.cascade.negativeMomentum[1] + mStraHelper.cascade.bachelorMomentum[1], mStraHelper.cascade.positiveMomentum[2] + mStraHelper.cascade.negativeMomentum[2] + mStraHelper.cascade.bachelorMomentum[2]}); + // dca V0 to PV + double DCAV0ToPV = CalculateDCAStraightToPV( + mStraHelper.cascade.v0Position[0], mStraHelper.cascade.v0Position[1], mStraHelper.cascade.v0Position[2], + mStraHelper.cascade.positiveMomentum[0] + mStraHelper.cascade.negativeMomentum[0], + mStraHelper.cascade.positiveMomentum[1] + mStraHelper.cascade.negativeMomentum[1], + mStraHelper.cascade.positiveMomentum[2] + mStraHelper.cascade.negativeMomentum[2], + pvX, pvY, pvZ); + // massLambda + double LambdaMass = 0; + if (mStraHelper.cascade.charge < 0) { + LambdaMass = RecoDecay::m(array{array{mStraHelper.cascade.positiveMomentum[0], mStraHelper.cascade.positiveMomentum[1], mStraHelper.cascade.positiveMomentum[2]}, array{mStraHelper.cascade.negativeMomentum[0], mStraHelper.cascade.negativeMomentum[1], mStraHelper.cascade.negativeMomentum[2]}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); + } else { + LambdaMass = RecoDecay::m(array{array{mStraHelper.cascade.positiveMomentum[0], mStraHelper.cascade.positiveMomentum[1], mStraHelper.cascade.positiveMomentum[2]}, array{mStraHelper.cascade.negativeMomentum[0], mStraHelper.cascade.negativeMomentum[1], mStraHelper.cascade.negativeMomentum[2]}}, array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton}); + } + + // rapidity + double yXi = RecoDecay::y(array{mStraHelper.cascade.bachelorMomentum[0] + mStraHelper.cascade.positiveMomentum[0] + mStraHelper.cascade.negativeMomentum[0], mStraHelper.cascade.bachelorMomentum[1] + mStraHelper.cascade.positiveMomentum[1] + mStraHelper.cascade.negativeMomentum[1], mStraHelper.cascade.bachelorMomentum[2] + mStraHelper.cascade.positiveMomentum[2] + mStraHelper.cascade.negativeMomentum[2]}, o2::constants::physics::MassXiMinus); + double yOmega = RecoDecay::y(array{mStraHelper.cascade.bachelorMomentum[0] + mStraHelper.cascade.positiveMomentum[0] + mStraHelper.cascade.negativeMomentum[0], mStraHelper.cascade.bachelorMomentum[1] + mStraHelper.cascade.positiveMomentum[1] + mStraHelper.cascade.negativeMomentum[1], mStraHelper.cascade.bachelorMomentum[2] + mStraHelper.cascade.positiveMomentum[2] + mStraHelper.cascade.negativeMomentum[2]}, o2::constants::physics::MassOmegaMinus); - if (casc.sign() > 0) { - if (TMath::Abs(casc.dcapostopv()) < dcamesontopv) { + if (mStraHelper.cascade.charge > 0) { + if (std::fabs(mStraHelper.cascade.positiveDCAxy) < dcamesontopv) { continue; } hCandidate->Fill(2.5); - if (TMath::Abs(casc.dcanegtopv()) < dcabaryontopv) { + if (std::fabs(mStraHelper.cascade.negativeDCAxy) < dcabaryontopv) { continue; } hCandidate->Fill(3.5); - if (TMath::Abs(posdau.tpcNSigmaPi()) > nsigmatpcpi) { + if (std::fabs(posTrack.tpcNSigmaPi()) > nsigmatpcpi) { continue; } hCandidate->Fill(4.5); - if (TMath::Abs(negdau.tpcNSigmaPr()) > nsigmatpcpr) { + if (std::fabs(negTrack.tpcNSigmaPr()) > nsigmatpcpr) { continue; } hCandidate->Fill(5.5); - } else if (casc.sign() < 0) { - if (TMath::Abs(casc.dcanegtopv()) < dcamesontopv) { + } else if (mStraHelper.cascade.charge < 0) { + if (std::fabs(mStraHelper.cascade.negativeDCAxy) < dcamesontopv) { continue; } hCandidate->Fill(2.5); - if (TMath::Abs(casc.dcapostopv()) < dcabaryontopv) { + if (std::fabs(mStraHelper.cascade.positiveDCAxy) < dcabaryontopv) { continue; } hCandidate->Fill(3.5); - if (TMath::Abs(negdau.tpcNSigmaPi()) > nsigmatpcpi) { + if (std::fabs(negTrack.tpcNSigmaPi()) > nsigmatpcpi) { continue; } hCandidate->Fill(4.5); - if (TMath::Abs(posdau.tpcNSigmaPr()) > nsigmatpcpr) { + if (std::fabs(posTrack.tpcNSigmaPr()) > nsigmatpcpr) { continue; } hCandidate->Fill(5.5); } - if (TMath::Abs(posdau.eta()) > etadau) { - continue; - } - if (TMath::Abs(negdau.eta()) > etadau) { - continue; - } - if (TMath::Abs(bachelor.eta()) > etadau) { - continue; - } - hCandidate->Fill(6.5); - if (TMath::Abs(casc.dcabachtopv()) < dcabachtopv) { - continue; - } - hCandidate->Fill(7.5); - if (casc.v0radius() < v0radius) { + hCandidate->Fill(6.5); // OLD: eta dau (selection now applied in strangeness helper) + hCandidate->Fill(7.5); // OLD: bachtopv (selection now applied in strangeness helper) + + // not striclty needed as selection are applied beforehand - just as QA (no change in number expected) + if (Cascv0radius < v0radius) { continue; } hCandidate->Fill(8.5); - if (casc.cascradius() < cascradius) { + if (Casccascradius < cascradius) { continue; } hCandidate->Fill(9.5); - if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < v0cospa) { + if (v0DauCPA < v0cospa) { continue; } hCandidate->Fill(10.5); - if (casc.dcaV0daughters() > dcav0dau) { + if (mStraHelper.cascade.v0DaughterDCA > dcav0dau) { continue; } hCandidate->Fill(11.5); - if (casc.dcacascdaughters() > dcacascdau) { + if (mStraHelper.cascade.cascadeDaughterDCA > dcacascdau) { continue; } hCandidate->Fill(12.5); - if (TMath::Abs(casc.mLambda() - constants::physics::MassLambda) > masslambdalimit) { + if (std::fabs(LambdaMass - constants::physics::MassLambda) > masslambdalimit) { continue; } hCandidate->Fill(13.5); - if (TMath::Abs(casc.eta()) > eta) { + if (std::fabs(etaCasc) > eta) { continue; } hCandidate->Fill(14.5); if (hastof && - (!posdau.hasTOF() && posdau.pt() > ptthrtof) && - (!negdau.hasTOF() && negdau.pt() > ptthrtof) && - (!bachelor.hasTOF() && bachelor.pt() > ptthrtof)) { + (!posTrack.hasTOF() && posTrack.pt() > ptthrtof) && + (!negTrack.hasTOF() && negTrack.pt() > ptthrtof) && + (!bachTrack.hasTOF() && bachTrack.pt() > ptthrtof)) { continue; } hCandidate->Fill(15.5); - // Fill selections QA for XiMinus - if (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) > casccospaxi) { + // Fill selections QA for Xi + if (cascCPA > casccospaxi) { hCandidate->Fill(16.5); - if (casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()) > dcav0topv) { + if (cascCPA > dcav0topv) { hCandidate->Fill(17.5); if (xiproperlifetime < properlifetimefactor * ctauxi) { hCandidate->Fill(18.5); - if (TMath::Abs(casc.yXi()) < rapidity) { + if (std::fabs(yXi) < rapidity) { hCandidate->Fill(19.5); } } } } - const auto deltaMassXi = useSigmaBasedMassCutXi ? getMassWindow(stfilter::species::Xi, casc.pt()) : ximasswindow; - const auto deltaMassOmega = useSigmaBasedMassCutOmega ? getMassWindow(stfilter::species::Omega, casc.pt()) : omegamasswindow; - isXi = (TMath::Abs(bachelor.tpcNSigmaPi()) < nsigmatpcpi) && - (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) > casccospaxi) && - (casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()) > dcav0topv) && - (TMath::Abs(casc.mXi() - o2::constants::physics::MassXiMinus) < deltaMassXi) && - (TMath::Abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > omegarej) && + const auto deltaMassXi = useSigmaBasedMassCutXi ? getMassWindow(stfilter::species::Xi, ptCasc) : ximasswindow; + const auto deltaMassOmega = useSigmaBasedMassCutOmega ? getMassWindow(stfilter::species::Omega, ptCasc) : omegamasswindow; + + isXi = (std::fabs(bachTrack.tpcNSigmaPi()) < nsigmatpcpi) && + (cascCPA > casccospaxi) && + (DCAV0ToPV > dcav0topv) && + (std::fabs(massXi - o2::constants::physics::MassXiMinus) < deltaMassXi) && + (std::fabs(massOmega - o2::constants::physics::MassOmegaMinus) > omegarej) && (xiproperlifetime < properlifetimefactor * ctauxi) && - (TMath::Abs(casc.yXi()) < rapidity); - isXiYN = (TMath::Abs(bachelor.tpcNSigmaPi()) < nsigmatpcpi) && - (casc.cascradius() > lowerradiusXiYN) && - (TMath::Abs(casc.mXi() - o2::constants::physics::MassXiMinus) < deltaMassXi) && - (TMath::Abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > omegarej) && + (std::fabs(yXi) < rapidity); + isXiYN = (std::fabs(bachTrack.tpcNSigmaPi()) < nsigmatpcpi) && + (Casccascradius > lowerradiusXiYN) && + (std::fabs(massXi - o2::constants::physics::MassXiMinus) < deltaMassXi) && + (std::fabs(massOmega - o2::constants::physics::MassOmegaMinus) > omegarej) && (xiproperlifetime < properlifetimefactor * ctauxi) && - (TMath::Abs(casc.yXi()) < rapidity); - isOmega = (TMath::Abs(bachelor.tpcNSigmaKa()) < nsigmatpcka) && - (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) > casccospaomega) && - (casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()) > dcav0topv) && - (TMath::Abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) < deltaMassOmega) && - (TMath::Abs(casc.mXi() - o2::constants::physics::MassXiMinus) > xirej) && - (casc.cascradius() < upperradiusOmega) && + (std::fabs(yXi) < rapidity); + isOmega = (std::fabs(bachTrack.tpcNSigmaKa()) < nsigmatpcka) && + (cascCPA > casccospaomega) && + (DCAV0ToPV > dcav0topv) && + (std::fabs(massOmega - o2::constants::physics::MassOmegaMinus) < deltaMassOmega) && + (std::fabs(massXi - o2::constants::physics::MassXiMinus) > xirej) && + (Casccascradius < upperradiusOmega) && (omegaproperlifetime < properlifetimefactor * ctauomega) && - (TMath::Abs(casc.yOmega()) < rapidity); - isOmegalargeR = (TMath::Abs(bachelor.tpcNSigmaKa()) < nsigmatpcka) && - (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) > casccospaomega) && - (casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()) > dcav0topv) && - (casc.cascradius() > lowerradiusOmega) && - (TMath::Abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) < deltaMassOmega) && - (TMath::Abs(casc.mXi() - o2::constants::physics::MassXiMinus) > xirej) && + (std::fabs(yOmega) < rapidity); + isOmegalargeR = (std::fabs(bachTrack.tpcNSigmaKa()) < nsigmatpcka) && + (cascCPA > casccospaomega) && + (DCAV0ToPV > dcav0topv) && + (Casccascradius > lowerradiusOmega) && + (std::fabs(massOmega - o2::constants::physics::MassOmegaMinus) < deltaMassOmega) && + (std::fabs(massXi - o2::constants::physics::MassXiMinus) > xirej) && (omegaproperlifetime < properlifetimefactor * ctauomega) && - (TMath::Abs(casc.yOmega()) < rapidity); + (std::fabs(yOmega) < rapidity); if (isXi) { - QAHistos.fill(HIST("hMassXiAfterSelvsPt"), casc.mXi(), casc.pt()); - QAHistos.fill(HIST("hPtXi"), casc.pt()); - QAHistos.fill(HIST("hEtaXi"), casc.eta()); + QAHistos.fill(HIST("hMassXiAfterSelvsPt"), massXi, ptCasc); + QAHistos.fill(HIST("hPtXi"), ptCasc); + QAHistos.fill(HIST("hEtaXi"), etaCasc); QAHistosTopologicalVariables.fill(HIST("hProperLifetimeXi"), xiproperlifetime); - QAHistosTopologicalVariables.fill(HIST("hCascCosPAXi"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); - QAHistosTopologicalVariables.fill(HIST("hV0CosPAXi"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); - QAHistosTopologicalVariables.fill(HIST("hCascRadiusXi"), casc.cascradius()); - QAHistosTopologicalVariables.fill(HIST("hV0RadiusXi"), casc.v0radius()); - QAHistosTopologicalVariables.fill(HIST("hDCAV0ToPVXi"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); - QAHistosTopologicalVariables.fill(HIST("hDCAV0DaughtersXi"), casc.dcaV0daughters()); - QAHistosTopologicalVariables.fill(HIST("hDCACascDaughtersXi"), casc.dcacascdaughters()); - QAHistosTopologicalVariables.fill(HIST("hDCABachToPVXi"), TMath::Abs(casc.dcabachtopv())); - QAHistosTopologicalVariables.fill(HIST("hDCAPosToPVXi"), TMath::Abs(casc.dcapostopv())); - QAHistosTopologicalVariables.fill(HIST("hDCANegToPVXi"), TMath::Abs(casc.dcanegtopv())); - QAHistosTopologicalVariables.fill(HIST("hInvMassLambdaXi"), casc.mLambda()); + QAHistosTopologicalVariables.fill(HIST("hCascCosPAXi"), cascCPA); + QAHistosTopologicalVariables.fill(HIST("hV0CosPAXi"), v0DauCPA); + QAHistosTopologicalVariables.fill(HIST("hCascRadiusXi"), Casccascradius); + QAHistosTopologicalVariables.fill(HIST("hV0RadiusXi"), Cascv0radius); + QAHistosTopologicalVariables.fill(HIST("hDCAV0ToPVXi"), DCAV0ToPV); + QAHistosTopologicalVariables.fill(HIST("hDCAV0DaughtersXi"), mStraHelper.cascade.v0DaughterDCA); + QAHistosTopologicalVariables.fill(HIST("hDCACascDaughtersXi"), mStraHelper.cascade.cascadeDaughterDCA); + QAHistosTopologicalVariables.fill(HIST("hDCABachToPVXi"), std::fabs(mStraHelper.cascade.bachelorDCAxy)); + QAHistosTopologicalVariables.fill(HIST("hDCAPosToPVXi"), std::fabs(mStraHelper.cascade.positiveDCAxy)); + QAHistosTopologicalVariables.fill(HIST("hDCANegToPVXi"), std::fabs(mStraHelper.cascade.negativeDCAxy)); + QAHistosTopologicalVariables.fill(HIST("hInvMassLambdaXi"), LambdaMass); if (doextraQA) { - - QAHistos.fill(HIST("hHasTOFBachPi"), bachelor.hasTOF(), bachelor.pt()); + QAHistos.fill(HIST("hHasTOFBachPi"), bachTrack.hasTOF(), bachTrack.pt()); // QA PID - if (casc.sign() > 0) { - QAHistos.fill(HIST("hTPCNsigmaXiBachPiPlus"), bachelor.tpcNSigmaPi(), bachelor.tpcInnerParam()); - QAHistos.fill(HIST("hTPCNsigmaXiV0PiPlus"), posdau.tpcNSigmaPi(), posdau.tpcInnerParam()); - QAHistos.fill(HIST("hTPCNsigmaXiV0AntiProton"), negdau.tpcNSigmaPr(), negdau.tpcInnerParam()); - QAHistos.fill(HIST("hHasTOFPi"), posdau.hasTOF(), posdau.pt()); - QAHistos.fill(HIST("hHasTOFPr"), negdau.hasTOF(), negdau.pt()); + if (mStraHelper.cascade.charge > 0) { + QAHistos.fill(HIST("hTPCNsigmaXiBachPiPlus"), bachTrack.tpcNSigmaPi(), bachTrack.tpcInnerParam()); + QAHistos.fill(HIST("hTPCNsigmaXiV0PiPlus"), posTrack.tpcNSigmaPi(), posTrack.tpcInnerParam()); + QAHistos.fill(HIST("hTPCNsigmaXiV0AntiProton"), negTrack.tpcNSigmaPr(), negTrack.tpcInnerParam()); + QAHistos.fill(HIST("hHasTOFPi"), posTrack.hasTOF(), posTrack.pt()); + QAHistos.fill(HIST("hHasTOFPr"), negTrack.hasTOF(), negTrack.pt()); } else { - QAHistos.fill(HIST("hTPCNsigmaXiBachPiMinus"), bachelor.tpcNSigmaPi(), bachelor.tpcInnerParam()); - QAHistos.fill(HIST("hTPCNsigmaXiV0Proton"), posdau.tpcNSigmaPr(), posdau.tpcInnerParam()); - QAHistos.fill(HIST("hTPCNsigmaXiV0PiMinus"), negdau.tpcNSigmaPi(), negdau.tpcInnerParam()); - QAHistos.fill(HIST("hHasTOFPr"), posdau.hasTOF(), posdau.pt()); - QAHistos.fill(HIST("hHasTOFPi"), negdau.hasTOF(), negdau.pt()); + QAHistos.fill(HIST("hTPCNsigmaXiBachPiMinus"), bachTrack.tpcNSigmaPi(), bachTrack.tpcInnerParam()); + QAHistos.fill(HIST("hTPCNsigmaXiV0Proton"), posTrack.tpcNSigmaPr(), posTrack.tpcInnerParam()); + QAHistos.fill(HIST("hTPCNsigmaXiV0PiMinus"), negTrack.tpcNSigmaPi(), negTrack.tpcInnerParam()); + QAHistos.fill(HIST("hHasTOFPr"), posTrack.hasTOF(), posTrack.pt()); + QAHistos.fill(HIST("hHasTOFPi"), negTrack.hasTOF(), negTrack.pt()); } - QAHistos.fill(HIST("hRapXi"), casc.yXi()); + QAHistos.fill(HIST("hRapXi"), yXi); } // Count number of Xi candidates xicounter++; - - // Plot for estimates - for (auto track : tracks) { // start loop over tracks - if (isTrackFilter && !mTrackSelector.IsSelected(track)) { - continue; - } - triggcounterForEstimates++; - if (triggcounterForEstimates > 0) - break; - } - if (triggcounterForEstimates && (TMath::Abs(casc.mXi() - o2::constants::physics::MassXiMinus) < 0.01)) - hhXiPairsvsPt->Fill(casc.pt()); // Fill the histogram with all the Xis produced in events with a trigger particle - // End plot for estimates + // v0sFromXiID.push_back({casc.posTrackId(), casc.negTrackId()}); + v0sFromXiID.push_back({posTrack.globalIndex(), negTrack.globalIndex()}); } + if (isXiYN) { // Xis for YN interactions xicounterYN++; - QAHistosTopologicalVariables.fill(HIST("hCascRadiusXiYN"), casc.cascradius()); + QAHistosTopologicalVariables.fill(HIST("hCascRadiusXiYN"), Casccascradius); } if (isOmega) { - QAHistos.fill(HIST("hMassOmegaAfterSelvsPt"), casc.mOmega(), casc.pt()); - QAHistos.fill(HIST("hPtOmega"), casc.pt()); - QAHistos.fill(HIST("hEtaOmega"), casc.eta()); + QAHistos.fill(HIST("hMassOmegaAfterSelvsPt"), massOmega, ptCasc); + QAHistos.fill(HIST("hPtOmega"), ptCasc); + QAHistos.fill(HIST("hEtaOmega"), etaCasc); QAHistosTopologicalVariables.fill(HIST("hProperLifetimeOmega"), omegaproperlifetime); - QAHistosTopologicalVariables.fill(HIST("hCascCosPAOmega"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); - QAHistosTopologicalVariables.fill(HIST("hV0CosPAOmega"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); - QAHistosTopologicalVariables.fill(HIST("hCascRadiusOmega"), casc.cascradius()); - QAHistosTopologicalVariables.fill(HIST("hV0RadiusOmega"), casc.v0radius()); - QAHistosTopologicalVariables.fill(HIST("hDCAV0ToPVOmega"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); - QAHistosTopologicalVariables.fill(HIST("hDCAV0DaughtersOmega"), casc.dcaV0daughters()); - QAHistosTopologicalVariables.fill(HIST("hDCACascDaughtersOmega"), casc.dcacascdaughters()); - QAHistosTopologicalVariables.fill(HIST("hDCABachToPVOmega"), TMath::Abs(casc.dcabachtopv())); - QAHistosTopologicalVariables.fill(HIST("hDCAPosToPVOmega"), TMath::Abs(casc.dcapostopv())); - QAHistosTopologicalVariables.fill(HIST("hDCANegToPVOmega"), TMath::Abs(casc.dcanegtopv())); - QAHistosTopologicalVariables.fill(HIST("hInvMassLambdaOmega"), casc.mLambda()); + QAHistosTopologicalVariables.fill(HIST("hCascCosPAOmega"), cascCPA); + QAHistosTopologicalVariables.fill(HIST("hV0CosPAOmega"), v0DauCPA); + QAHistosTopologicalVariables.fill(HIST("hCascRadiusOmega"), Casccascradius); + QAHistosTopologicalVariables.fill(HIST("hV0RadiusOmega"), Cascv0radius); + QAHistosTopologicalVariables.fill(HIST("hDCAV0ToPVOmega"), DCAV0ToPV); + QAHistosTopologicalVariables.fill(HIST("hDCAV0DaughtersOmega"), mStraHelper.cascade.v0DaughterDCA); + QAHistosTopologicalVariables.fill(HIST("hDCACascDaughtersOmega"), mStraHelper.cascade.cascadeDaughterDCA); + QAHistosTopologicalVariables.fill(HIST("hDCABachToPVOmega"), std::fabs(mStraHelper.cascade.bachelorDCAxy)); + QAHistosTopologicalVariables.fill(HIST("hDCAPosToPVOmega"), std::fabs(mStraHelper.cascade.positiveDCAxy)); + QAHistosTopologicalVariables.fill(HIST("hDCANegToPVOmega"), std::fabs(mStraHelper.cascade.negativeDCAxy)); + QAHistosTopologicalVariables.fill(HIST("hInvMassLambdaOmega"), LambdaMass); if (doextraQA) { // QA PID - if (casc.sign() > 0) { - QAHistos.fill(HIST("hTPCNsigmaOmegaBachKaPlus"), bachelor.tpcNSigmaKa(), bachelor.tpcInnerParam()); - QAHistos.fill(HIST("hTPCNsigmaOmegaV0PiPlus"), posdau.tpcNSigmaPi(), posdau.tpcInnerParam()); - QAHistos.fill(HIST("hTPCNsigmaOmegaV0AntiProton"), negdau.tpcNSigmaPr(), negdau.tpcInnerParam()); - QAHistos.fill(HIST("hHasTOFPi"), posdau.hasTOF(), posdau.pt()); - QAHistos.fill(HIST("hHasTOFPr"), negdau.hasTOF(), negdau.pt()); + if (mStraHelper.cascade.charge > 0) { + QAHistos.fill(HIST("hTPCNsigmaOmegaBachKaPlus"), bachTrack.tpcNSigmaKa(), bachTrack.tpcInnerParam()); + QAHistos.fill(HIST("hTPCNsigmaOmegaV0PiPlus"), posTrack.tpcNSigmaPi(), posTrack.tpcInnerParam()); + QAHistos.fill(HIST("hTPCNsigmaOmegaV0AntiProton"), negTrack.tpcNSigmaPr(), negTrack.tpcInnerParam()); + QAHistos.fill(HIST("hHasTOFPi"), posTrack.hasTOF(), posTrack.pt()); + QAHistos.fill(HIST("hHasTOFPr"), negTrack.hasTOF(), negTrack.pt()); } else { - QAHistos.fill(HIST("hTPCNsigmaOmegaBachKaMinus"), bachelor.tpcNSigmaKa(), bachelor.tpcInnerParam()); - QAHistos.fill(HIST("hTPCNsigmaOmegaV0Proton"), posdau.tpcNSigmaPr(), posdau.tpcInnerParam()); - QAHistos.fill(HIST("hTPCNsigmaOmegaV0PiMinus"), negdau.tpcNSigmaPi(), negdau.tpcInnerParam()); - QAHistos.fill(HIST("hHasTOFPr"), posdau.hasTOF(), posdau.pt()); - QAHistos.fill(HIST("hHasTOFPi"), negdau.hasTOF(), negdau.pt()); + QAHistos.fill(HIST("hTPCNsigmaOmegaBachKaMinus"), bachTrack.tpcNSigmaKa(), bachTrack.tpcInnerParam()); + QAHistos.fill(HIST("hTPCNsigmaOmegaV0Proton"), posTrack.tpcNSigmaPr(), posTrack.tpcInnerParam()); + QAHistos.fill(HIST("hTPCNsigmaOmegaV0PiMinus"), negTrack.tpcNSigmaPi(), negTrack.tpcInnerParam()); + QAHistos.fill(HIST("hHasTOFPr"), posTrack.hasTOF(), posTrack.pt()); + QAHistos.fill(HIST("hHasTOFPi"), negTrack.hasTOF(), negTrack.pt()); } - QAHistos.fill(HIST("hHasTOFBachKa"), bachelor.hasTOF(), bachelor.pt()); - QAHistos.fill(HIST("hRapOmega"), casc.yOmega()); + QAHistos.fill(HIST("hHasTOFBachKa"), bachTrack.hasTOF(), bachTrack.pt()); + QAHistos.fill(HIST("hRapOmega"), yOmega); } // Count number of Omega candidates omegacounter++; + v0sFromOmegaID.push_back({posTrack.globalIndex(), negTrack.globalIndex()}); } + if (isOmegalargeR) { omegalargeRcounter++; - QAHistosTopologicalVariables.fill(HIST("hCascRadiusOmegaLargeR"), casc.cascradius()); + QAHistosTopologicalVariables.fill(HIST("hCascRadiusOmegaLargeR"), Casccascradius); } } // end loop over cascades - // Omega trigger definition - if (omegacounter > 0) { - keepEvent[0] = true; - } + keepEvent[0] = omegacounter > 0; - bool EvtwhMinPt[11]; - bool EvtwhMinPtCasc[11]; - float ThrdPt[11]; + std::array EvtwhMinPt{false}; + std::array ThrdPt; for (int i = 0; i < 11; i++) { - EvtwhMinPt[i] = 0.; - EvtwhMinPtCasc[i] = 0.; ThrdPt[i] = static_cast(i); } // QA tracks + int triggcounterAllEv = 0; for (auto track : tracks) { // start loop over tracks - if (isTrackFilter && !mTrackSelector.IsSelected(track)) { + if (isTrackFilter && !selectTrack(track)) { continue; } triggcounterAllEv++; QAHistosTriggerParticles.fill(HIST("hPtTriggerAllEv"), track.pt()); QAHistosTriggerParticles.fill(HIST("hPhiTriggerAllEv"), track.phi(), track.pt()); QAHistosTriggerParticles.fill(HIST("hEtaTriggerAllEv"), track.eta(), track.pt()); - QAHistosTriggerParticles.fill(HIST("hDCAxyTriggerAllEv"), track.dcaXY(), track.pt()); - QAHistosTriggerParticles.fill(HIST("hDCAzTriggerAllEv"), track.dcaZ(), track.pt()); - for (int i = 0; i < 11; i++) { - if (track.pt() > ThrdPt[i]) - EvtwhMinPt[i] = 1; + for (size_t i = 0; i < ThrdPt.size(); i++) { + EvtwhMinPt[i] = track.pt() > ThrdPt[i]; + } + + // High-pT hadron + Omega trigger definition + if (omegacounter > 0) { + keepEvent[1] = true; + QAHistosTriggerParticles.fill(HIST("hPtTriggerSelEv"), track.pt()); } } // end loop over tracks for (int i = 0; i < 11; i++) { @@ -1021,42 +1097,52 @@ struct strangenessFilter { } } QAHistosTriggerParticles.fill(HIST("hTriggeredParticlesAllEv"), triggcounterAllEv); - - // High-pT hadron + Omega trigger definition - if (omegacounter > 0) { - for (auto track : tracks) { // start loop over tracks - if (isTrackFilter && !mTrackSelector.IsSelected(track)) { - continue; - } - triggcounter++; - QAHistosTriggerParticles.fill(HIST("hPtTriggerSelEv"), track.pt()); - for (int i = 0; i < 11; i++) { - if (track.pt() > ThrdPt[i]) - EvtwhMinPtCasc[i] = 1; + if (keepEvent[1]) { + QAHistosTriggerParticles.fill(HIST("hTriggeredParticlesSelEv"), triggcounterAllEv); + for (size_t i = 0; i < EvtwhMinPt.size(); i++) { + if (EvtwhMinPt[i]) { + hEvtvshMinPt->Fill(i + 0.5); } - keepEvent[1] = true; - } // end loop over tracks - QAHistosTriggerParticles.fill(HIST("hTriggeredParticlesSelEv"), triggcounter); - } - - for (int i = 0; i < 11; i++) { - if (EvtwhMinPtCasc[i]) - hEvtvshMinPt->Fill(i + 0.5); + } } - // 2Xi trigger definition - if (xicounter > 1) { - keepEvent[2] = true; + // Double/triple/quad Xi trigger definition + if (v0sFromXiID.size() > 0) { + std::set> uniqueXis = {v0sFromXiID.begin(), v0sFromXiID.end()}; + if (uniqueXis.size() > 1) { + keepEvent[2] = true; + } + if (uniqueXis.size() > 2) { + keepEvent[3] = true; + } + if (uniqueXis.size() > 3) { + keepEvent[4] = true; + } } - // 3Xi trigger definition - if (xicounter > 2) { - keepEvent[3] = true; + // Double Omega trigger definition + if (v0sFromOmegaID.size() > 0) { + std::set> uniqueOmegas = {v0sFromOmegaID.begin(), v0sFromOmegaID.end()}; + if (uniqueOmegas.size() > 1) { + keepEvent[10] = true; + } } - // 4Xi trigger definition - if (xicounter > 3) { - keepEvent[4] = true; + // Omega + Xi trigger definition + if (v0sFromOmegaID.size() > 0 && v0sFromXiID.size() > 0) { + std::set> uniqueOmegas = {v0sFromOmegaID.begin(), v0sFromOmegaID.end()}; + std::set> uniqueXis = {v0sFromXiID.begin(), v0sFromXiID.end()}; + if (uniqueOmegas.size() > 1 || uniqueXis.size() > 1) { + keepEvent[11] = true; + } else { + // keep only if there is at least one non-overlapping v0 + for (auto v0Omega : uniqueOmegas) { + if (uniqueXis.find(v0Omega) == uniqueXis.end()) { + keepEvent[11] = true; + break; + } + } + } } // Single-Xi (YN) trigger definition @@ -1070,54 +1156,22 @@ struct strangenessFilter { } // Omega in high multiplicity events - if (omegacounter > 0) + if (omegacounter > 0) { EventsvsMultiplicity.fill(HIST("AllEventsvsMultiplicityFT0MwOmega"), collision.multFT0M()); + EventsvsMultiplicity.fill(HIST("AllEventsvsMultiplicityFT0MwOmegaNorm"), multFT0MNorm); + } if (omegacounter > 0 && isHighMultEvent) { keepEvent[9] = true; } - // strangeness tracking selection - const auto bc = collision.bc_as(); - if (runNumber != bc.runNumber()) { - runNumber = bc.runNumber(); - auto timestamp = bc.timestamp(); - - if (o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, timestamp)) { - o2::base::Propagator::initFieldFromGRP(grpo); - bz = grpo->getNominalL3Field(); - } else if (o2::parameters::GRPMagField* grpmag = ccdb->getForTimeStamp(grpMagPath, timestamp)) { - o2::base::Propagator::initFieldFromGRP(grpmag); - bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); - } else { - LOG(fatal) << "Got nullptr from CCDB for path " << grpMagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << timestamp; - } - } - - const auto primaryVertex = getPrimaryVertex(collision); - o2::dataformats::DCA impactParameterTrk; - - for (const auto& casc : fullCasc) { - QAHistosStrangenessTracking.fill(HIST("hPtCascCand"), casc.pt()); - } - - const auto matCorr = static_cast(materialCorrectionType.value); - o2::vertexing::DCAFitterN<2> df2; - df2.setBz(bz); - df2.setPropagateToPCA(propToDCA); - df2.setMaxR(maxR); - df2.setMaxDZIni(maxDZIni); - df2.setMinParamChange(minParamChange); - df2.setMinRelChi2Change(minRelChi2Change); - df2.setUseAbsDCA(useAbsDCA); - for (const auto& trackedCascade : trackedCascades) { - const auto trackCasc = trackedCascade.track_as(); + const auto trackCasc = trackedCascade.track_as(); QAHistosStrangenessTracking.fill(HIST("hPtCascTracked"), trackCasc.pt()); QAHistosStrangenessTracking.fill(HIST("hStRVsPtTrkCasc"), trackCasc.pt(), RecoDecay::sqrtSumOfSquares(trackCasc.x(), trackCasc.y())); QAHistosStrangenessTracking.fill(HIST("hMatchChi2TrkCasc"), trackedCascade.matchingChi2()); auto trackParCovTrk = getTrackParCov(trackCasc); - o2::base::Propagator::Instance()->propagateToDCA(primaryVertex, trackParCovTrk, bz, 2.f, matCorr, &impactParameterTrk); + o2::base::Propagator::Instance()->propagateToDCA(primaryVertex, trackParCovTrk, mBz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrLUT, &impactParameterTrk); QAHistosStrangenessTracking.fill(HIST("hDcaXY"), impactParameterTrk.getY()); QAHistosStrangenessTracking.fill(HIST("hDcaXYVsPt"), trackParCovTrk.getPt(), impactParameterTrk.getY()); @@ -1130,10 +1184,10 @@ struct strangenessFilter { // const auto itsTrack = trackedCascade.itsTrack(); const auto cascade = trackedCascade.cascade(); - const auto bachelor = cascade.bachelor_as(); + const auto bachelor = cascade.bachelor_as(); const auto v0 = cascade.v0_as(); - const auto negTrack = v0.negTrack_as(); - const auto posTrack = v0.posTrack_as(); + const auto negTrack = v0.negTrack_as(); + const auto posTrack = v0.posTrack_as(); if (!posTrack.hasTPC() || !negTrack.hasTPC() || !bachelor.hasTPC() || posTrack.tpcNClsFindable() < minNoClsTrackedCascade || @@ -1171,17 +1225,16 @@ struct strangenessFilter { o2::track::TrackPar trackParV0; o2::track::TrackPar trackParBachelor; float cpa = -1; - if (df2.process(getTrackParCov(negTrack), getTrackParCov(posTrack))) { - trackParCovV0 = df2.createParentTrackParCov(0); - if (df2.process(trackParCovV0, getTrackParCov(bachelor))) { - trackParV0 = df2.getTrackParamAtPCA(0); - trackParBachelor = df2.getTrackParamAtPCA(1); + if (mDCAFitter.process(getTrackParCov(negTrack), getTrackParCov(posTrack))) { + trackParCovV0 = mDCAFitter.createParentTrackParCov(0); + if (mDCAFitter.process(trackParCovV0, getTrackParCov(bachelor))) { + trackParV0 = mDCAFitter.getTrackParamAtPCA(0); + trackParBachelor = mDCAFitter.getTrackParamAtPCA(1); trackParV0.getPxPyPzGlo(momenta[0]); trackParBachelor.getPxPyPzGlo(momenta[1]); std::array pVec; - df2.createParentTrackParCov().getPxPyPzGlo(pVec); - std::array pvPos = {primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}; - cpa = RecoDecay::cpa(pvPos, df2.getPCACandidate(), pVec); + mDCAFitter.createParentTrackParCov().getPxPyPzGlo(pVec); + cpa = RecoDecay::cpa(pvPos, mDCAFitter.getPCACandidate(), pVec); QAHistosStrangenessTracking.fill(HIST("hCpa"), cpa); } else { continue; @@ -1217,7 +1270,7 @@ struct strangenessFilter { // Xi const auto deltaMassTrackedXi = useNsigmaCutTrackedXi ? getMassWindow(stfilter::species::Xi, trackCasc.pt(), massWindowTrackedXiNsigma) : massWindowTrackedXi; if ((std::abs(massXi - o2::constants::physics::MassXiMinus) < deltaMassTrackedXi) && - (impactParameterTrk.getY() >= minDcaTrackedXi) && + (std::abs(impactParameterTrk.getY()) >= minDcaTrackedXi) && (cpa <= maxCpaTrackedOmega) && (std::abs(bachelor.tpcNSigmaPi()) < maxNSigmaBachelorTrackedXi)) { keepEvent[7] = true; @@ -1238,7 +1291,7 @@ struct strangenessFilter { const auto deltaMassTrackedOmega = useNsigmaCutTrackedOmega ? getMassWindow(stfilter::species::Omega, trackCasc.pt(), massWindowTrackedOmegaNsigma) : massWindowTrackedOmega; if ((std::abs(massOmega - o2::constants::physics::MassOmegaMinus) < deltaMassTrackedOmega) && (std::abs(massXi - o2::constants::physics::MassXiMinus) >= massWindowXiExclTrackedOmega) && - (impactParameterTrk.getY() >= minDcaTrackedOmega) && + (std::abs(impactParameterTrk.getY()) >= minDcaTrackedOmega) && (cpa <= maxCpaTrackedOmega) && (std::abs(bachelor.tpcNSigmaKa()) < maxNSigmaBachelorTrackedOmega)) { keepEvent[8] = true; @@ -1292,12 +1345,18 @@ struct strangenessFilter { if (keepEvent[9]) { hProcessedEvents->Fill(12.5); } - + if (keepEvent[10]) { + hProcessedEvents->Fill(13.5); + } + if (keepEvent[11]) { + hProcessedEvents->Fill(14.5); + } + if (keepEvent[12]) { + hProcessedEvents->Fill(15.5); + } // Filling the table fillTriggerTable(keepEvent); } - // - PROCESS_SWITCH(strangenessFilter, processRun3, "Process Run3", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/EventFiltering/PWGUD/diffractionFilter.cxx b/EventFiltering/PWGUD/diffractionFilter.cxx index a9528252b27..c5adfcf90c5 100644 --- a/EventFiltering/PWGUD/diffractionFilter.cxx +++ b/EventFiltering/PWGUD/diffractionFilter.cxx @@ -132,11 +132,16 @@ struct DGFilterRun3 { // using MFs = aod::MFTTracks; using FWs = aod::FwdTracks; + // filter for global tracks + Filter globalTrackFilter = requireGlobalTrackInFilter(); + using globalTracks = soa::Filtered; + void process(CC const& collision, BCs const& bcs, TCs& tracks, // MFs& mfttracks, FWs& fwdtracks, + globalTracks& goodTracks, aod::Zdcs& /*zdcs*/, aod::FT0s& /*ft0s*/, aod::FV0As& /*fv0as*/, @@ -144,12 +149,14 @@ struct DGFilterRun3 { { // initialize LOGF(debug, "=4) + if (collision.numContrib() < 4) { + isDGSmall = true; + } else { + isDGLarge = true; + } + } + filterTable(isDGSmall, isDGLarge); // log output to check consistency of selections on original and skimmed data auto bc2 = collision.foundBC_as(); @@ -190,7 +206,7 @@ struct DGFilterRun3 { registry.fill(HIST("FIT/FDDCtime"), bc2.foundFDD().timeC()); } - auto FITlims = std::vector(5, 1000000.); + auto FITlims = std::vector(5, -1.); bool isDGcandidate = true; for (int nMinBC = 0; nMinBC <= 20; nMinBC++) { auto bcSlice = udhelpers::compatibleBCs(collision, 0, bcs, nMinBC); @@ -216,14 +232,15 @@ struct DGFilterRun3 { // collisions registry.fill(HIST("collisions/tracksAll"), tracks.size()); registry.fill(HIST("collisions/PVTracksAll"), collision.numContrib()); - Partition goodTracks = requireGlobalTrackInFilter(); - goodTracks.bindTable(tracks); + // Partition goodTracks = requireGlobalTrackInFilter(); + // goodTracks.bindTable(tracks); + // LOGF(info, "# good tracks %d", goodTracks.size()); registry.get(HIST("collisions/globalTracksAll"))->Fill(goodTracks.size()); auto netCharge = udhelpers::netCharge(tracks); registry.fill(HIST("collisions/netChargeAll"), collision.numContrib(), netCharge); registry.fill(HIST("collisions/dtcvsrPVtrwTOFAll"), collision.collisionTimeRes(), rgtrwTOF); registry.fill(HIST("collisions/rPVtrwTOFAll"), collision.numContrib(), rgtrwTOF); - if (ccs) { + if (isDG) { registry.fill(HIST("collisions/tracksDG"), tracks.size()); registry.fill(HIST("collisions/PVTracksDG"), collision.numContrib()); registry.get(HIST("collisions/globalTracksDG"))->Fill(goodTracks.size()); @@ -236,7 +253,7 @@ struct DGFilterRun3 { for (auto const& track : tracks) { if (track.isPVContributor()) { registry.fill(HIST("tracks/etavsptAll"), track.eta(), track.pt()); - if (ccs) { + if (isDG) { if (track.hasTOF()) { registry.fill(HIST("tracks/etavsptDGwT"), track.eta(), track.pt()); } else { @@ -254,7 +271,7 @@ struct DGFilterRun3 { } for (auto ii = 0; ii < 5; ii++) { registry.fill(HIST("collisions/forwardTracksAll"), ii, nforwardTracks[ii]); - if (ccs) { + if (isDG) { registry.fill(HIST("collisions/forwardTracksDG"), ii, nforwardTracks[ii]); } } diff --git a/EventFiltering/Zorro.cxx b/EventFiltering/Zorro.cxx new file mode 100644 index 00000000000..8b47d0c2d3f --- /dev/null +++ b/EventFiltering/Zorro.cxx @@ -0,0 +1,313 @@ +// 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. +// + +#include "Zorro.h" + +#include +#include + +#include + +#include "CCDB/BasicCCDBManager.h" +#include "CommonDataFormat/InteractionRecord.h" + +using o2::InteractionRecord; + +namespace +{ +int findBin(TH1* hist, const std::string& label) +{ // Find bin by label, avoiding the axis extention from the native ROOT implementation + for (int iBin{1}; iBin <= hist->GetNbinsX(); ++iBin) { + if (label == hist->GetXaxis()->GetBinLabel(iBin)) { + return iBin; + } + } + return -1; +} +} // namespace + +void Zorro::populateHistRegistry(o2::framework::HistogramRegistry& histRegistry, int runNumber, std::string folderName) +{ + int runId{-1}; + for (size_t i{0}; i < mRunNumberHistos.size(); ++i) { + if (mRunNumberHistos[i] == runNumber) { + runId = i; + break; + } + } + if (runId > -1) { + /// Support jobs running on non-continuous run numbers + mAnalysedTriggers = mAnalysedTriggersList[runId]; + mAnalysedTriggersOfInterest = mAnalysedTriggersOfInterestList[runId]; + return; + } + if (mSelections) { + mAnalysedTriggers = histRegistry.add((folderName + "/" + std::to_string(runNumber) + "/" + "AnalysedTriggers").data(), "", o2::framework::HistType::kTH1D, {{mSelections->GetNbinsX() - 2, -0.5, mSelections->GetNbinsX() - 2.5}}).get(); + for (int iBin{2}; iBin < mSelections->GetNbinsX(); ++iBin) { // Exclude first and last bins as they are total number of analysed and selected events, respectively + mAnalysedTriggers->GetXaxis()->SetBinLabel(iBin - 1, mSelections->GetXaxis()->GetBinLabel(iBin)); + } + std::shared_ptr selections = histRegistry.add((folderName + "/" + std::to_string(runNumber) + "/" + "Selections").data(), "", o2::framework::HistType::kTH1D, {{mSelections->GetNbinsX(), -0.5, static_cast(mSelections->GetNbinsX() - 0.5)}}); + selections->SetBit(TH1::kIsAverage); + for (int iBin{1}; iBin <= mSelections->GetNbinsX(); ++iBin) { + selections->GetXaxis()->SetBinLabel(iBin, mSelections->GetXaxis()->GetBinLabel(iBin)); + selections->SetBinContent(iBin, mSelections->GetBinContent(iBin)); + selections->SetBinError(iBin, mSelections->GetBinError(iBin)); + } + } + if (mScalers) { + std::shared_ptr scalers = histRegistry.add((folderName + "/" + std::to_string(runNumber) + "/" + "Scalers").data(), "", o2::framework::HistType::kTH1D, {{mScalers->GetNbinsX(), -0.5, static_cast(mScalers->GetNbinsX() - 0.5)}}); + scalers->SetBit(TH1::kIsAverage); + for (int iBin{1}; iBin <= mScalers->GetNbinsX(); ++iBin) { + scalers->GetXaxis()->SetBinLabel(iBin, mScalers->GetXaxis()->GetBinLabel(iBin)); + scalers->SetBinContent(iBin, mScalers->GetBinContent(iBin)); + scalers->SetBinError(iBin, mScalers->GetBinError(iBin)); + } + } + if (mInspectedTVX) { + std::shared_ptr inspectedTVX = histRegistry.add((folderName + "/" + std::to_string(runNumber) + "/" + "InspectedTVX").data(), "", o2::framework::HistType::kTH1D, {{mInspectedTVX->GetNbinsX(), -0.5, static_cast(mInspectedTVX->GetNbinsX() - 0.5)}}); + inspectedTVX->SetBit(TH1::kIsAverage); + for (int iBin{1}; iBin <= mInspectedTVX->GetNbinsX(); ++iBin) { + inspectedTVX->GetXaxis()->SetBinLabel(iBin, mInspectedTVX->GetXaxis()->GetBinLabel(iBin)); + inspectedTVX->SetBinContent(iBin, mInspectedTVX->GetBinContent(iBin)); + inspectedTVX->SetBinError(iBin, mInspectedTVX->GetBinError(iBin)); + } + } + if (mTOIs.size()) { + mAnalysedTriggersOfInterest = histRegistry.add((folderName + "/" + std::to_string(runNumber) + "/" + "AnalysedTriggersOfInterest").data(), "", o2::framework::HistType::kTH1D, {{static_cast(mTOIs.size()), -0.5, static_cast(mTOIs.size() - 0.5)}}).get(); + for (size_t i{0}; i < mTOIs.size(); ++i) { + mAnalysedTriggersOfInterest->GetXaxis()->SetBinLabel(i + 1, mTOIs[i].data()); + } + } + mAnalysedTriggersList.push_back(mAnalysedTriggers); + mAnalysedTriggersOfInterestList.push_back(mAnalysedTriggersOfInterest); + mRunNumberHistos.push_back(runNumber); +} + +void Zorro::populateExternalHists(int runNumber, TH2* ZorroHisto, TH2* ToiHisto) +{ + // x-axis is run number, y-axis is same as ZorroSummary + int runId{-1}; + for (size_t i{0}; i < mRunNumberHistos.size(); ++i) { + if (mRunNumberHistos[i] == runNumber) { + runId = i; + break; + } + } + if (runId > -1) { + return; + } + // if the summary histogram is not set, create a new one + if (!ZorroHisto) { + LOGF(info, "Summary histogram not set, creating a new one"); + ZorroHisto = new TH2D("Zorro", "Zorro", 1, -0.5, 0.5, 1 + mTOIs.size() * 2, -0.5, mTOIs.size() * 2 - 0.5); + ZorroHisto->SetBit(TH1::kIsAverage); + } + if (!ToiHisto) { + LOGF(info, "TOI histogram not set, creating a new one"); + ToiHisto = new TH2D("TOI", "TOI", 1, -0.5, 0.5, mTOIs.size() * 2, -0.5, mTOIs.size() * 2 - 0.5); + } + // if it is the first run, initialize the histogram + if (mRunNumberHistos.size() == 0) { + ZorroHisto->SetBins(1, -0.5, 0.5, 1 + mTOIs.size() * 2, -0.5, mTOIs.size() * 2 - 0.5); + ZorroHisto->SetBit(TH1::kIsAverage); + ZorroHisto->GetXaxis()->SetBinLabel(1, Form("%d", runNumber)); + ZorroHisto->GetYaxis()->SetBinLabel(1, "inspected TVX"); + for (size_t i{0}; i < mTOIs.size(); ++i) { + ZorroHisto->GetYaxis()->SetBinLabel(i + 2, Form("%s selections", mTOIs[i].data())); + ZorroHisto->GetYaxis()->SetBinLabel(i + 2 + mTOIs.size(), Form("%s scalers", mTOIs[i].data())); + } + // TOI histogram + ToiHisto->SetBins(1, -0.5, 0.5, mTOIs.size() * 2, -0.5, mTOIs.size() * 2 - 0.5); + ToiHisto->GetXaxis()->SetBinLabel(1, Form("%d", runNumber)); + for (size_t i{0}; i < mTOIs.size(); ++i) { + ToiHisto->GetYaxis()->SetBinLabel(i * 2 + 1, mTOIs[i].data()); + ToiHisto->GetYaxis()->SetBinLabel(i * 2 + 2, Form("%s AnalysedTriggers", mTOIs[i].data())); + } + } + if (mInspectedTVX) { + ZorroHisto->Fill(Form("%d", runNumber), "inspected TVX", mInspectedTVX->GetBinContent(1)); + ZorroHisto->SetBinError(mRunNumberHistos.size() + 1, 1, mInspectedTVX->GetBinError(1)); + } + if (mSelections) { + mAnalysedTriggers = new TH1D("AnalysedTriggers", "", mSelections->GetNbinsX() - 2, -0.5, mSelections->GetNbinsX() - 2.5); + for (int iBin{2}; iBin < mSelections->GetNbinsX(); ++iBin) { // Exclude first and last bins as they are total number of analysed and selected events, respectively + mAnalysedTriggers->GetXaxis()->SetBinLabel(iBin - 1, mSelections->GetXaxis()->GetBinLabel(iBin)); + } + for (size_t i{0}; i < mTOIs.size(); ++i) { + int bin = findBin(mSelections, mTOIs[i]); + ZorroHisto->Fill(Form("%d", runNumber), Form("%s selections", mTOIs[i].data()), mSelections->GetBinContent(bin)); + ZorroHisto->SetBinError(mRunNumberHistos.size() + 1, i + 2, mSelections->GetBinError(bin)); + } + } + if (mScalers) { + for (size_t i{0}; i < mTOIs.size(); ++i) { + int bin = findBin(mScalers, mTOIs[i]); + ZorroHisto->Fill(Form("%d", runNumber), Form("%s scalers", mTOIs[i].data()), mScalers->GetBinContent(bin)); + ZorroHisto->SetBinError(mRunNumberHistos.size() + 1, i + 2 + mTOIs.size(), mScalers->GetBinError(bin)); + } + } + + mRunNumberHistos.push_back(runNumber); +} + +std::vector Zorro::initCCDB(o2::ccdb::BasicCCDBManager* ccdb, int runNumber, uint64_t timestamp, std::string tois, int bcRange) +{ + if (mRunNumber == runNumber) { + return mTOIidx; + } + mCCDB = ccdb; + mRunNumber = runNumber; + mBCtolerance = bcRange; + std::map metadata; + metadata["runNumber"] = std::to_string(runNumber); + mRunDuration = mCCDB->getRunDuration(runNumber, true); + int64_t runTs = (mRunDuration.first / 2 + mRunDuration.second / 2); + auto ctp = ccdb->getForTimeStamp>("CTP/Calib/OrbitReset", runTs); + mOrbitResetTimestamp = (*ctp)[0]; + mScalers = mCCDB->getSpecific(mBaseCCDBPath + "FilterCounters", runTs, metadata); + mSelections = mCCDB->getSpecific(mBaseCCDBPath + "SelectionCounters", runTs, metadata); + mInspectedTVX = mCCDB->getSpecific(mBaseCCDBPath + "InspectedTVX", runTs, metadata); + setupHelpers(timestamp); + mLastBCglobalId = 0; + mLastSelectedIdx = 0; + mTOIs.clear(); + mTOIidx.clear(); + while (!tois.empty()) { + size_t pos = tois.find(","); + pos = (pos == std::string::npos) ? tois.size() : pos; + std::string token = tois.substr(0, pos); + // Trim leading and trailing whitespaces from the token + token.erase(0, token.find_first_not_of(" ")); + token.erase(token.find_last_not_of(" ") + 1); + int bin = findBin(mSelections, token) - 2; + mTOIs.push_back(token); + mTOIidx.push_back(bin); + tois = tois.erase(0, pos + 1); + } + mTOIcounts.resize(mTOIs.size(), 0); + LOGF(info, "Zorro initialized for run %d, triggers of interest:", runNumber); + for (size_t i{0}; i < mTOIs.size(); ++i) { + LOGF(info, ">>> %s : %i", mTOIs[i].data(), mTOIidx[i]); + } + mZorroSummary.setupTOIs(mTOIs.size(), tois); + std::vector toiCounters(mTOIs.size(), 0.); + for (size_t i{0}; i < mTOIs.size(); ++i) { + toiCounters[i] = mSelections->GetBinContent(mTOIidx[i] + 2); + } + mZorroSummary.setupRun(runNumber, mInspectedTVX->GetBinContent(1), toiCounters); + + return mTOIidx; +} + +std::bitset<128> Zorro::fetch(uint64_t bcGlobalId, uint64_t tolerance) +{ + mLastResult.reset(); + if (bcGlobalId < mBCranges.front().getMin().toLong() - tolerance || bcGlobalId > mBCranges.back().getMax().toLong() + tolerance) { + setupHelpers((mOrbitResetTimestamp + int64_t(bcGlobalId * o2::constants::lhc::LHCBunchSpacingNS * 1e-3)) / 1000); + } + + o2::dataformats::IRFrame bcFrame{InteractionRecord::long2IR(bcGlobalId) - tolerance, InteractionRecord::long2IR(bcGlobalId) + tolerance}; + if (bcGlobalId < mLastBCglobalId) { /// Handle the possible discontinuity in the BC processed by the analyses + mLastSelectedIdx = 0; + } + uint64_t lastSelectedIdx = mLastSelectedIdx; + mLastBCglobalId = bcGlobalId; + for (size_t i = mLastSelectedIdx; i < mBCranges.size(); i++) { + if (!mBCranges[i].isOutside(bcFrame)) { + for (int iMask{0}; iMask < 2; ++iMask) { + for (int iTOI{0}; iTOI < 64; ++iTOI) { + if (mZorroHelpers->at(i).selMask[iMask] & (1ull << iTOI)) { + mLastResult.set(iMask * 64 + iTOI, 1); + if (mAnalysedTriggers && !mAccountedBCranges[i]) { + mAnalysedTriggers->Fill(iMask * 64 + iTOI); + } + } + } + } + mAccountedBCranges[i] = true; + mLastSelectedIdx = mLastSelectedIdx == lastSelectedIdx-- ? i : mLastSelectedIdx; /// Decrease lastSelectedIdx to make sure this check is valid only in its first instance + } else if (mBCranges[i].getMax() < bcFrame.getMin()) { + mLastSelectedIdx = i; + } else if (mBCranges[i].getMin() > bcFrame.getMax()) { + break; + } + } + return mLastResult; +} + +bool Zorro::isSelected(uint64_t bcGlobalId, uint64_t tolerance, TH2* ToiHisto) +{ + uint64_t lastSelectedIdx = mLastSelectedIdx; + fetch(bcGlobalId, tolerance); + bool retVal{false}; + for (size_t i{0}; i < mTOIidx.size(); ++i) { + if (mTOIidx[i] < 0) { + continue; + } else if (mLastResult.test(mTOIidx[i])) { + if (ToiHisto && mAnalysedTriggers) { + int binX = ToiHisto->GetXaxis()->FindBin(Form("%d", mRunNumber)); + int binY = ToiHisto->GetYaxis()->FindBin(Form("%s AnalysedTriggers", mTOIs[i].data())); + ToiHisto->SetBinContent(binX, binY, mAnalysedTriggers->GetBinContent(mAnalysedTriggers->GetXaxis()->FindBin(mTOIs[i].data()))); + } + mTOIcounts[i] += (lastSelectedIdx != mLastSelectedIdx); /// Avoid double counting + if (mAnalysedTriggersOfInterest && lastSelectedIdx != mLastSelectedIdx) { + mAnalysedTriggersOfInterest->Fill(i); + mZorroSummary.increaseTOIcounter(mRunNumber, i); + } + if (ToiHisto && lastSelectedIdx != mLastSelectedIdx) { + ToiHisto->Fill(Form("%d", mRunNumber), Form("%s", mTOIs[i].data()), 1); + } + retVal = true; + } + } + return retVal; +} + +std::vector Zorro::getTriggerOfInterestResults(uint64_t bcGlobalId, uint64_t tolerance) +{ + fetch(bcGlobalId, tolerance); + return getTriggerOfInterestResults(); +} + +std::vector Zorro::getTriggerOfInterestResults() const +{ + std::vector results(mTOIidx.size(), false); + for (size_t i{0}; i < mTOIidx.size(); ++i) { + if (mTOIidx[i] < 0) { + continue; + } else if (mLastResult.test(mTOIidx[i])) { + results[i] = true; + } + } + return results; +} + +bool Zorro::isNotSelectedByAny(uint64_t bcGlobalId, uint64_t tolerance) +{ + fetch(bcGlobalId, tolerance); + return mLastResult.none(); +} + +void Zorro::setupHelpers(int64_t timestamp) +{ + if (mCCDB->isCachedObjectValid(mBaseCCDBPath + "ZorroHelpers", timestamp)) { + return; + } + mZorroHelpers = mCCDB->getSpecific>(mBaseCCDBPath + "ZorroHelpers", timestamp, {{"runNumber", std::to_string(mRunNumber)}}); + std::sort(mZorroHelpers->begin(), mZorroHelpers->end(), [](const auto& a, const auto& b) { return std::min(a.bcAOD, a.bcEvSel) < std::min(b.bcAOD, b.bcEvSel); }); + mBCranges.clear(); + mAccountedBCranges.clear(); + for (auto helper : *mZorroHelpers) { + mBCranges.emplace_back(InteractionRecord::long2IR(std::min(helper.bcAOD, helper.bcEvSel)), InteractionRecord::long2IR(std::max(helper.bcAOD, helper.bcEvSel))); + } + mAccountedBCranges.resize(mBCranges.size(), false); +} diff --git a/EventFiltering/Zorro.h b/EventFiltering/Zorro.h new file mode 100644 index 00000000000..c818e45ce48 --- /dev/null +++ b/EventFiltering/Zorro.h @@ -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. +// +// Zero Obstacles Results Retriever for Offline trigger selections + +#ifndef EVENTFILTERING_ZORRO_H_ +#define EVENTFILTERING_ZORRO_H_ + +#include +#include +#include +#include +#include + +#include "TH1D.h" +#include "TH2D.h" +#include "CommonDataFormat/IRFrame.h" +#include "Framework/HistogramRegistry.h" +#include "ZorroHelper.h" +#include "ZorroSummary.h" + +namespace o2 +{ +namespace ccdb +{ +class BasicCCDBManager; +}; +}; // namespace o2 + +class Zorro +{ + public: + Zorro() = default; + std::vector initCCDB(o2::ccdb::BasicCCDBManager* ccdb, int runNumber, uint64_t timestamp, std::string tois, int bcTolerance = 500); + std::bitset<128> fetch(uint64_t bcGlobalId, uint64_t tolerance = 100); + bool isSelected(uint64_t bcGlobalId, uint64_t tolerance = 100, TH2* toiHisto = nullptr); + bool isNotSelectedByAny(uint64_t bcGlobalId, uint64_t tolerance = 100); + + void populateHistRegistry(o2::framework::HistogramRegistry& histRegistry, int runNumber, std::string folderName = "Zorro"); + void populateExternalHists(int runNumber, TH2* zorroHisto = nullptr, TH2* toiHisto = nullptr); + + TH1D* getScalers() const { return mScalers; } + TH1D* getSelections() const { return mSelections; } + TH1D* getInspectedTVX() const { return mInspectedTVX; } + std::bitset<128> getLastResult() const { return mLastResult; } + std::vector getTOIcounters() const { return mTOIcounts; } + std::vector getTriggerOfInterestResults(uint64_t bcGlobalId, uint64_t tolerance = 100); + std::vector getTriggerOfInterestResults() const; + + void setCCDBpath(std::string path) { mBaseCCDBPath = path; } + void setBaseCCDBPath(std::string path) { mBaseCCDBPath = path; } + void setBCtolerance(int tolerance) { mBCtolerance = tolerance; } + + ZorroSummary* getZorroSummary() { return &mZorroSummary; } + + private: + void setupHelpers(int64_t timestamp); + + ZorroSummary mZorroSummary{"ZorroSummary", "ZorroSummary"}; + + std::string mBaseCCDBPath = "Users/m/mpuccio/EventFiltering/OTS/Chunked/"; + int mRunNumber = 0; + std::pair mRunDuration; + int64_t mOrbitResetTimestamp = 0; + TH1* mAnalysedTriggers; /// Accounting for all triggers in the current run + TH1* mAnalysedTriggersOfInterest; /// Accounting for triggers of interest in the current run + + std::vector mRunNumberHistos; + std::vector mAnalysedTriggersList; /// Per run histograms + std::vector mAnalysedTriggersOfInterestList; /// Per run histograms + + int mBCtolerance = 100; + uint64_t mLastBCglobalId = 0; + uint64_t mLastSelectedIdx = 0; + TH1D* mScalers = nullptr; + TH1D* mSelections = nullptr; + TH1D* mInspectedTVX = nullptr; + std::bitset<128> mLastResult; + std::vector mAccountedBCranges; /// Avoid double accounting of inspected BC ranges + std::vector mBCranges; + std::vector* mZorroHelpers = nullptr; + std::vector mTOIs; + std::vector mTOIidx; + std::vector mTOIcounts; + o2::ccdb::BasicCCDBManager* mCCDB = nullptr; +}; + +#endif // EVENTFILTERING_ZORRO_H_ diff --git a/EventFiltering/ZorroHelper.h b/EventFiltering/ZorroHelper.h new file mode 100644 index 00000000000..8bcc6240bc0 --- /dev/null +++ b/EventFiltering/ZorroHelper.h @@ -0,0 +1,23 @@ +// 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. +// + +#ifndef EVENTFILTERING_ZORROHELPER_H_ +#define EVENTFILTERING_ZORROHELPER_H_ + +#include "Rtypes.h" + +struct ZorroHelper { + ULong64_t bcAOD, bcEvSel, trigMask[2], selMask[2]; + ClassDefNV(ZorroHelper, 1); +}; + +#endif // EVENTFILTERING_ZORROHELPER_H_ diff --git a/EventFiltering/ZorroSummary.cxx b/EventFiltering/ZorroSummary.cxx new file mode 100644 index 00000000000..ee241f49108 --- /dev/null +++ b/EventFiltering/ZorroSummary.cxx @@ -0,0 +1,69 @@ +// 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. + +#include "ZorroSummary.h" + +#include "TCollection.h" + +void ZorroSummary::Copy(TObject& c) const +{ + static_cast(c) = *this; +} + +Long64_t ZorroSummary::Merge(TCollection* list) +{ + if (!list) { + return 0; + } + int n = 1; + if (list->IsEmpty()) { + return n; + } + + for (auto* obj : *list) { + auto* entry = dynamic_cast(obj); + if (!entry || entry->getTOInames() != mTOInames) { + continue; + } + n++; + auto& analysedToiCounters = entry->getAnalysedTOIcounters(); + for (const auto& [runNumber, currentAnalysedToiCounters] : analysedToiCounters) { + if (mAnalysedTOIcounters.find(runNumber) == mAnalysedTOIcounters.end()) { + mAnalysedTOIcounters[runNumber] = currentAnalysedToiCounters; + mTVXcounters[runNumber] = entry->getTVXcounters().at(runNumber); + mTOIcounters[runNumber] = entry->getTOIcounters().at(runNumber); + } else { + auto& thisCounters = mAnalysedTOIcounters[runNumber]; + for (size_t i = 0; i < thisCounters.size(); ++i) { + thisCounters[i] += currentAnalysedToiCounters[i]; + } + } + } + } + return n; +} + +double ZorroSummary::getNormalisationFactor(int toiId) const +{ + double totalTOI{0.}, totalTVX{0.}; + ULong64_t totalAnalysedTOI{0}; + for (const auto& [runNumber, toiCounters] : mTOIcounters) { + totalTOI += toiCounters.at(toiId); + } + for (const auto& [runNumber, tvxCounters] : mTVXcounters) { + totalTVX += tvxCounters; + } + for (const auto& [runNumber, analysedTOIcounters] : mAnalysedTOIcounters) { + totalAnalysedTOI += analysedTOIcounters.at(toiId); + } + + return totalTVX * totalAnalysedTOI / totalTOI; +} \ No newline at end of file diff --git a/EventFiltering/ZorroSummary.h b/EventFiltering/ZorroSummary.h new file mode 100644 index 00000000000..b4d401adba4 --- /dev/null +++ b/EventFiltering/ZorroSummary.h @@ -0,0 +1,76 @@ +// 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. +// + +#ifndef EVENTFILTERING_ZORROSUMMARY_H_ +#define EVENTFILTERING_ZORROSUMMARY_H_ + +#include + +#include +#include +#include + +class ZorroSummary : public TNamed +{ + public: + ZorroSummary() = default; + ZorroSummary(const char* name, const char* objTitle) : TNamed(name, objTitle) {} + virtual ~ZorroSummary() = default; // NOLINT: Making this override breaks compilation for unknown reason + virtual void Copy(TObject& c) const; // NOLINT: Making this override breaks compilation for unknown reason + virtual Long64_t Merge(TCollection* list); + + void setupTOIs(int ntois, const std::string& toinames) + { + mNtois = ntois; + mTOInames = toinames; + } + void setupRun(int runNumber, double tvxCountes, const std::vector& toiCounters) + { + if (mRunNumber == runNumber) { + return; + } + mRunNumber = runNumber; + mTVXcounters[runNumber] = tvxCountes; + mTOIcounters[runNumber] = toiCounters; + if (mAnalysedTOIcounters.find(runNumber) == mAnalysedTOIcounters.end()) { + mAnalysedTOIcounters[runNumber] = std::vector(mNtois, 0ull); + } + mCurrentAnalysedTOIcounters = &mAnalysedTOIcounters[runNumber]; + } + double getNormalisationFactor(int toiId) const; + void increaseTOIcounter(int runNumber, int toiId) + { + if (runNumber != mRunNumber) { + return; + } + mCurrentAnalysedTOIcounters->at(toiId)++; + } + + std::string getTOInames() const { return mTOInames; } + const auto& getTOIcounters() const { return mTOIcounters; } + const auto& getTVXcounters() const { return mTVXcounters; } + const auto& getAnalysedTOIcounters() const { return mAnalysedTOIcounters; } + + private: + int mRunNumber = 0; //! Run currently being analysed + std::vector* mCurrentAnalysedTOIcounters = nullptr; //! Analysed TOI counters for the current run + + int mNtois = 0; + std::string mTOInames; + std::unordered_map> mAnalysedTOIcounters; + std::unordered_map> mTOIcounters; + std::unordered_map mTVXcounters; + + ClassDef(ZorroSummary, 1); +}; + +#endif // EVENTFILTERING_ZORROSUMMARY_H_ \ No newline at end of file diff --git a/EventFiltering/cefpTask.cxx b/EventFiltering/cefpTask.cxx index d1596622d52..64cf4435b85 100644 --- a/EventFiltering/cefpTask.cxx +++ b/EventFiltering/cefpTask.cxx @@ -14,12 +14,13 @@ #include #include -#include #include #include #include #include #include +#include +#include #include "filterTables.h" @@ -200,12 +201,11 @@ static const float defaultDownscaling[128][1]{ {1.f}, {1.f}}; /// Max number of columns for triggers is 128 (extendible) -#define FILTER_CONFIGURABLE(_TYPE_) \ - Configurable> cfg##_TYPE_ \ - { \ -#_TYPE_, {defaultDownscaling[0], NumberOfColumns(typename _TYPE_::table_t::columns{}), 1, ColumnsNames(typename _TYPE_::table_t::columns{}), downscalingName }, #_TYPE_ " downscalings" \ +#define FILTER_CONFIGURABLE(_TYPE_) \ + Configurable> cfg##_TYPE_ \ + { \ + #_TYPE_, {defaultDownscaling[0], NumberOfColumns(typename _TYPE_::table_t::persistent_columns_t{}), 1, ColumnsNames(typename _TYPE_::table_t::persistent_columns_t{}), downscalingName}, #_TYPE_ " downscalings" \ } - } // namespace struct centralEventFilterTask { @@ -213,7 +213,11 @@ struct centralEventFilterTask { HistogramRegistry scalers{"scalers", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; Produces tags; + Configurable cfgDisableDownscalings{"cfgDisableDownscalings", false, "Disable downscalings"}; + Configurable cfgSkipUntriggeredEvents{"cfgSkipUntriggeredEvents", false, "Skip untriggered events"}; + FILTER_CONFIGURABLE(F1ProtonFilters); + FILTER_CONFIGURABLE(DoublePhiFilters); FILTER_CONFIGURABLE(NucleiFilters); FILTER_CONFIGURABLE(DiffractionFilters); FILTER_CONFIGURABLE(DqFilters); @@ -224,6 +228,7 @@ struct centralEventFilterTask { FILTER_CONFIGURABLE(MultFilters); FILTER_CONFIGURABLE(FullJetFilters); FILTER_CONFIGURABLE(PhotonFilters); + FILTER_CONFIGURABLE(HeavyNeutralMesonFilters); void init(o2::framework::InitContext& initc) { @@ -261,17 +266,20 @@ struct centralEventFilterTask { col.second = filterOpt.get(col.first.data(), 0u); } } + if (cfgDisableDownscalings.value) { + LOG(info) << "Downscalings are disabled for all channels."; + } } void run(ProcessingContext& pc) { // Filling output table - auto bcTabConsumer = pc.inputs().get(aod::MetadataTrait>::metadata::tableLabel()); + auto bcTabConsumer = pc.inputs().get(o2::soa::getTableLabel()); auto bcTabPtr{bcTabConsumer->asArrowTable()}; - auto collTabConsumer = pc.inputs().get(aod::MetadataTrait>::metadata::tableLabel()); + auto collTabConsumer = pc.inputs().get(o2::soa::getTableLabel()); auto collTabPtr{collTabConsumer->asArrowTable()}; - auto evSelConsumer = pc.inputs().get(aod::MetadataTrait>::metadata::tableLabel()); + auto evSelConsumer = pc.inputs().get(o2::soa::getTableLabel()); auto evSelTabPtr{evSelConsumer->asArrowTable()}; auto columnGloBCId{bcTabPtr->GetColumnByName(aod::BC::GlobalBC::mLabel)}; @@ -327,7 +335,7 @@ struct centralEventFilterTask { uint64_t decisionBin{(bin - 2) / 64}; uint64_t triggerBit{BIT((bin - 2) % 64)}; auto column{tablePtr->GetColumnByName(colName.first)}; - double downscaling{colName.second}; + double downscaling{cfgDisableDownscalings.value ? 1. : colName.second}; if (column) { int entry = 0; for (int64_t iC{0}; iC < column->num_chunks(); ++iC) { @@ -352,25 +360,31 @@ struct centralEventFilterTask { mFiltered->SetBinContent(1, mFiltered->GetBinContent(1) + nEvents - startCollision); for (uint64_t iE{0}; iE < outTrigger.size(); ++iE) { - for (uint64_t iD{0}; iD < outTrigger[0].size(); ++iD) { + const auto& triggerWord{outTrigger[iE]}; + bool triggered{false}, selected{false}; + for (uint64_t iD{0}; iD < triggerWord.size(); ++iD) { for (int iB{0}; iB < 64; ++iB) { - if (!(outTrigger[iE][iD] & BIT(iB))) { + if (!(triggerWord[iD] & BIT(iB))) { continue; } - for (int jD{0}; jD < outTrigger[0].size(); ++jD) { - for (int iC{iB}; iC < 64; ++iC) { - if (outTrigger[iE][iD] & BIT(iC)) { - mCovariance->Fill(iD * 64 + iB, jD * 64 + iC); + uint64_t xIndex{iD * 64 + iB}; + for (uint64_t jD{0}; jD < triggerWord.size(); ++jD) { + for (int jB{0}; jB < 64; ++jB) { + uint64_t yIndex{jD * 64 + jB}; + if (xIndex <= yIndex && triggerWord[jD] & BIT(jB)) { + mCovariance->Fill(iD * 64 + iB, jD * 64 + jB); } } } } - if (outTrigger[iE][iD]) { - mScalers->Fill(mScalers->GetNbinsX() - 1); - } - if (outDecision[iE][iD]) { - mFiltered->Fill(mFiltered->GetNbinsX() - 1); - } + triggered = triggered || triggerWord[iD]; + selected = selected || outDecision[iE][iD]; + } + if (triggered) { + mScalers->Fill(mScalers->GetNbinsX() - 1); + } + if (selected) { + mFiltered->Fill(mFiltered->GetNbinsX() - 1); } } @@ -382,6 +396,9 @@ struct centralEventFilterTask { } for (uint64_t iD{0}; iD < outDecision.size(); ++iD) { uint64_t foundBC = FoundBCArray->Value(iD) >= 0 && FoundBCArray->Value(iD) < GloBCArray->length() ? GloBCArray->Value(FoundBCArray->Value(iD)) : -1; + if (cfgSkipUntriggeredEvents.value && !outDecision[iD][0] && !outDecision[iD][1]) { + continue; + } tags(CollBCIdArray->Value(iD), GloBCArray->Value(CollBCIdArray->Value(iD)), foundBC, CollTimeArray->Value(iD), CollTimeResArray->Value(iD), outTrigger[iD][0], outTrigger[iD][1], outDecision[iD][0], outDecision[iD][1]); } } diff --git a/EventFiltering/filterTables.h b/EventFiltering/filterTables.h index 1f3a887939e..363a7176165 100644 --- a/EventFiltering/filterTables.h +++ b/EventFiltering/filterTables.h @@ -15,17 +15,48 @@ #include #include #include -#include "Framework/AnalysisDataModel.h" +#include + +namespace o2::aod +{ +template +struct Hash; +} + +#include "Framework/ASoA.h" + +namespace o2::soa +{ +template + requires(!std::same_as>::metadata, void>) +const char* getTableLabel() +{ + return o2::aod::MetadataTrait>::metadata::tableLabel(); +} + +template + requires requires { T::ref.label_hash; } +const char* getTableLabel() +{ + return o2::aod::Hash::str; +} +} // namespace o2::soa namespace o2::aod { namespace filtering { -DECLARE_SOA_COLUMN(He, hasHe, bool); //! -DECLARE_SOA_COLUMN(H3L3Body, hasH3L3Body, bool); //! hypertriton 3body +DECLARE_SOA_COLUMN(H2, hasH2, bool); //! deuteron trigger for the helium normalisation (to be downscaled) +DECLARE_SOA_COLUMN(He, hasHe, bool); //! helium +DECLARE_SOA_COLUMN(HeV0, hasHeV0, bool); //! V0 containing a V0 +DECLARE_SOA_COLUMN(TritonFemto, hasTritonFemto, bool); //! Triton hadron femtoscopy +DECLARE_SOA_COLUMN(H3L3Body, hasH3L3Body, bool); //! hypertriton 3body +DECLARE_SOA_COLUMN(ITSextremeIonisation, hasITSextremeIonisation, bool); //! ITS extreme ionisation +DECLARE_SOA_COLUMN(ITSmildIonisation, hasITSmildIonisation, bool); //! ITS mild ionisation (normalisation of the extreme ionisation), to be downscaled // diffraction -DECLARE_SOA_COLUMN(UDdiff, hasDiff, bool); //! Double Gap events, DG +DECLARE_SOA_COLUMN(UDdiffSmall, hasDiffSmall, bool); //! Double Gap events, <= 3 prongs +DECLARE_SOA_COLUMN(UDdiffLarge, hasDiffLarge, bool); //! Double Gap events, >= 4 prongs DECLARE_SOA_COLUMN(UDdiffBC, hasDiffBC, bool); //! diffractive BC @@ -38,34 +69,61 @@ DECLARE_SOA_COLUMN(DiMuon, hasDiMuon, bool); //! dimuon trigger with // EM dielectrons DECLARE_SOA_COLUMN(LMeeIMR, hasLMeeIMR, bool); //! dielectron trigger for intermediate mass region DECLARE_SOA_COLUMN(LMeeHMR, hasLMeeHMR, bool); //! dielectron trigger for high mass region +// Electron-muon pair +DECLARE_SOA_COLUMN(ElectronMuon, hasElectronMuon, bool); //! dimuon trigger with low pT on muons // heavy flavours -DECLARE_SOA_COLUMN(HfHighPt2P, hasHfHighPt2P, bool); //! high-pT 2-prong charm hadron -DECLARE_SOA_COLUMN(HfHighPt3P, hasHfHighPt3P, bool); //! high-pT 3-prong charm hadron -DECLARE_SOA_COLUMN(HfBeauty3P, hasHfBeauty3P, bool); //! 3-prong beauty hadron -DECLARE_SOA_COLUMN(HfBeauty4P, hasHfBeauty4P, bool); //! 4-prong beauty hadron -DECLARE_SOA_COLUMN(HfFemto2P, hasHfFemto2P, bool); //! 2-prong charm-hadron - N pair -DECLARE_SOA_COLUMN(HfFemto3P, hasHfFemto3P, bool); //! 3-prong charm-hadron - N pair -DECLARE_SOA_COLUMN(HfDoubleCharm2P, hasHfDoubleCharm2P, bool); //! at least two 2-prong charm-hadron candidates -DECLARE_SOA_COLUMN(HfDoubleCharm3P, hasHfDoubleCharm3P, bool); //! at least two 3-prong charm-hadron candidates -DECLARE_SOA_COLUMN(HfDoubleCharmMix, hasHfDoubleCharmMix, bool); //! at least one 2-prong and one 3-prong charm-hadron candidates -DECLARE_SOA_COLUMN(HfV0Charm2P, hasHfV0Charm2P, bool); //! V0 with 2-prong charm hadron -DECLARE_SOA_COLUMN(HfV0Charm3P, hasHfV0Charm3P, bool); //! V0 with 3-prong charm hadron -DECLARE_SOA_COLUMN(HfCharmBarToXiBach, hasHfCharmBarToXiBach, bool); //! Charm baryon to Xi + bachelor -DECLARE_SOA_COLUMN(HfSigmaCPPK, hasHfSigmaCPPK, bool); //! SigmaC(2455)++K- and SigmaC(2520)++K- + c.c. -DECLARE_SOA_COLUMN(HfSigmaC0K0, hasHfSigmaC0K0, bool); //! SigmaC(2455)0KS0 and SigmaC(2520)0KS0 -DECLARE_SOA_COLUMN(HfPhotonCharm2P, hasHfPhotonCharm2P, bool); //! photon with 2-prong charm hadron -DECLARE_SOA_COLUMN(HfPhotonCharm3P, hasHfPhotonCharm3P, bool); //! photon with 3-prong charm hadron +DECLARE_SOA_COLUMN(HfHighPt2P, hasHfHighPt2P, bool); //! high-pT 2-prong charm hadron +DECLARE_SOA_COLUMN(HfHighPt3P, hasHfHighPt3P, bool); //! high-pT 3-prong charm hadron +DECLARE_SOA_COLUMN(HfBeauty3P, hasHfBeauty3P, bool); //! 3-prong beauty hadron +DECLARE_SOA_COLUMN(HfBeauty4P, hasHfBeauty4P, bool); //! 4-prong beauty hadron +DECLARE_SOA_COLUMN(HfFemto2P, hasHfFemto2P, bool); //! 2-prong charm-hadron - N pair +DECLARE_SOA_COLUMN(HfFemto3P, hasHfFemto3P, bool); //! 3-prong charm-hadron - N pair +DECLARE_SOA_COLUMN(HfDoubleCharm2P, hasHfDoubleCharm2P, bool); //! at least two 2-prong charm-hadron candidates +DECLARE_SOA_COLUMN(HfDoubleCharm3P, hasHfDoubleCharm3P, bool); //! at least two 3-prong charm-hadron candidates +DECLARE_SOA_COLUMN(HfDoubleCharmMix, hasHfDoubleCharmMix, bool); //! at least one 2-prong and one 3-prong charm-hadron candidates +DECLARE_SOA_COLUMN(HfV0Charm2P, hasHfV0Charm2P, bool); //! V0 with 2-prong charm hadron +DECLARE_SOA_COLUMN(HfV0Charm3P, hasHfV0Charm3P, bool); //! V0 with 3-prong charm hadron +DECLARE_SOA_COLUMN(HfCharmBarToXiBach, hasHfCharmBarToXiBach, bool); //! Charm baryon to Xi + bachelor +DECLARE_SOA_COLUMN(HfCharmBarToXi2Bach, hasHfCharmBarToXi2Bach, bool); //! Charm baryon to Xi + 2 bachelors +DECLARE_SOA_COLUMN(HfPrCharm2P, hasHfPrCharm2P, bool); //! Charm baryon to 2-prong + bachelors +DECLARE_SOA_COLUMN(HfSigmaCPPK, hasHfSigmaCPPK, bool); //! SigmaC(2455)++K- and SigmaC(2520)++K- + c.c. +DECLARE_SOA_COLUMN(HfSigmaC0K0, hasHfSigmaC0K0, bool); //! SigmaC(2455)0KS0 and SigmaC(2520)0KS0 +DECLARE_SOA_COLUMN(HfPhotonCharm2P, hasHfPhotonCharm2P, bool); //! photon with 2-prong charm hadron +DECLARE_SOA_COLUMN(HfPhotonCharm3P, hasHfPhotonCharm3P, bool); //! photon with 3-prong charm hadron +DECLARE_SOA_COLUMN(HfSingleCharm2P, hasHfSingleCharm2P, bool); //! 2-prong charm hadron (for efficiency studies) +DECLARE_SOA_COLUMN(HfSingleCharm3P, hasHfSingleCharm3P, bool); //! 3-prong charm hadron (for efficiency studies) +DECLARE_SOA_COLUMN(HfSingleNonPromptCharm2P, hasHfSingleNonPromptCharm2P, bool); //! 2-prong charm hadron (for efficiency studies) +DECLARE_SOA_COLUMN(HfSingleNonPromptCharm3P, hasHfSingleNonPromptCharm3P, bool); //! 3-prong charm hadron (for efficiency studies) +DECLARE_SOA_COLUMN(HfBtoJPsiKa, hasHfBtoJPsiKa, bool); //! B+ -> JPsi(->mumu)K+ +DECLARE_SOA_COLUMN(HfBtoJPsiKstar, hasHfBtoJPsiKstar, bool); //! B0 -> JPsi(->mumu)K*+(->Kpi) +DECLARE_SOA_COLUMN(HfBtoJPsiPhi, hasHfBtoJPsiPhi, bool); //! B0s -> JPsi(->mumu)phi(->KK) +DECLARE_SOA_COLUMN(HfBtoJPsiPrKa, hasHfBtoJPsiPrKa, bool); //! Lb -> JPsi(->mumu)pK+ +DECLARE_SOA_COLUMN(HfBtoJPsiPi, hasHfBtoJPsiPi, bool); //! Bc -> JPsi(->mumu)pi+ // CF two body triggers -DECLARE_SOA_COLUMN(PD, hasPD, bool); //! has d-p pair -DECLARE_SOA_COLUMN(LD, hasLD, bool); //! has l-d pair +DECLARE_SOA_COLUMN(PD_TightKstar, hasPD_TightKstar, bool); //! has d-p pair with tight kstar limit +DECLARE_SOA_COLUMN(PD_LooseKstar, hasPD_LooseKstar, bool); //! has d-p pair with loose kstar limit +DECLARE_SOA_COLUMN(LD_TightKstar, hasLD_TightKstar, bool); //! has l-d pair with tight kstar limit +DECLARE_SOA_COLUMN(LD_LooseKstar, hasLD_LooseKstar, bool); //! has l-d pair with loose kstar limit +DECLARE_SOA_COLUMN(PHID_TightKstar, hasPHID_TightKstar, bool); //! has phi-d pair with tight kstar limit +DECLARE_SOA_COLUMN(PHID_LooseKstar, hasPHID_LooseKstar, bool); //! has phi-d pair with loose kstar limit +DECLARE_SOA_COLUMN(RHOD_TightKstar, hasRHOD_TightKstar, bool); //! has rho-d pair with tight kstar limit +DECLARE_SOA_COLUMN(RHOD_LooseKstar, hasRHOD_LooseKstar, bool); //! has rho-d pair with loose kstar limit // CF three body triggers -DECLARE_SOA_COLUMN(PPP, hasPPP, bool); //! has p-p-p triplet -DECLARE_SOA_COLUMN(PPL, hasPPL, bool); //! has p-p-L triplet -DECLARE_SOA_COLUMN(PLL, hasPLL, bool); //! has p-L-L triplet -DECLARE_SOA_COLUMN(LLL, hasLLL, bool); //! has L-L-L tripletD +DECLARE_SOA_COLUMN(PPP_TightQ3, hasPPP_TightQ3, bool); //! has p-p-p triplet with tight Q3 limit +DECLARE_SOA_COLUMN(PPP_LooseQ3, hasPPP_LooseQ3, bool); //! has p-p-p triplet with loose Q3 limit +DECLARE_SOA_COLUMN(PPL_TightQ3, hasPPL_TightQ3, bool); //! has p-p-L triplet with tight Q3 limit +DECLARE_SOA_COLUMN(PPL_LooseQ3, hasPPL_LooseQ3, bool); //! has p-p-L triplet with loose Q3 limit +DECLARE_SOA_COLUMN(PLL_TightQ3, hasPLL_TightQ3, bool); //! has p-L-L triplet with tight Q3 limit +DECLARE_SOA_COLUMN(PLL_LooseQ3, hasPLL_LooseQ3, bool); //! has p-L-L triplet with loose Q3 limit +DECLARE_SOA_COLUMN(LLL_TightQ3, hasLLL_TightQ3, bool); //! has L-L-L tripletD with tight Q3 limit +DECLARE_SOA_COLUMN(LLL_LooseQ3, hasLLL_LooseQ3, bool); //! has L-L-L tripletD with loose Q3 limit +DECLARE_SOA_COLUMN(PPPHI_TightQ3, hasPPPHI_TightQ3, bool); //! has P-P-PHI triplet with tight Q3 limit +DECLARE_SOA_COLUMN(PPPHI_LooseQ3, hasPPPHI_LooseQ3, bool); //! has P-P-PHI triplet with loose Q3 limit +DECLARE_SOA_COLUMN(PPRHO_TightQ3, hasPPRHO_TightQ3, bool); //! has P-P-RHO triplet with tight Q3 limit +DECLARE_SOA_COLUMN(PPRHO_LooseQ3, hasPPRHO_highQ3, bool); //! has P-P-RHO triplet with loose Q3 limit // jets DECLARE_SOA_COLUMN(JetChLowPt, hasJetChLowPt, bool); //! low-pT charged jet @@ -100,6 +158,8 @@ DECLARE_SOA_COLUMN(hadronOmega, hashadronOmega, bool); //! at least 1 DECLARE_SOA_COLUMN(DoubleXi, hasDoubleXi, bool); //! at least 2 Xi DECLARE_SOA_COLUMN(TripleXi, hasTripleXi, bool); //! at least 3 Xi DECLARE_SOA_COLUMN(QuadrupleXi, hasQuadrupleXi, bool); //! at least 4 Xi +DECLARE_SOA_COLUMN(DoubleOmega, hasDoubleOmega, bool); //! at least 2 Omega +DECLARE_SOA_COLUMN(OmegaXi, hasOmegaXi, bool); //! at least 1 Omega + 1 Xi DECLARE_SOA_COLUMN(SingleXiYN, hasSingleXiYN, bool); //! at least 1 Xi with high radius (YN interactions) DECLARE_SOA_COLUMN(OmegaLargeRadius, hasOmegaLargeRadius, bool); //! at least 1 Omega with high radius DECLARE_SOA_COLUMN(TrackedCascade, hasTrackedCascade, bool); //! at least 1 tracked cascade @@ -107,10 +167,14 @@ DECLARE_SOA_COLUMN(TrackedXi, hasTrackedXi, bool); //! at least 1 DECLARE_SOA_COLUMN(TrackedOmega, hasTrackedOmega, bool); //! at least 1 tracked Omega DECLARE_SOA_COLUMN(Tracked3Body, hasTracked3Body, bool); //! at least 1 tracked 3Body DECLARE_SOA_COLUMN(OmegaHighMult, hasOmegaHighMult, bool); //! at least 1 Omega + high-mult event +DECLARE_SOA_COLUMN(LambdaLambda, lambdaLambda, bool); //! at least 2 lambda satisfying selection // F1-proton DECLARE_SOA_COLUMN(TriggerEventF1Proton, triggereventf1proton, bool); //! F1 - proton femto trigger event +// Double Phi +DECLARE_SOA_COLUMN(TriggerEventDoublePhi, triggereventdoublephi, bool); //! Double Phi trigger event + // multiplicity DECLARE_SOA_COLUMN(HighTrackMult, hasHighTrackMult, bool); //! high trk muliplicity DECLARE_SOA_COLUMN(HighMultFv0, hasHighMultFv0, bool); //! high FV0 muliplicity @@ -130,6 +194,17 @@ DECLARE_SOA_COLUMN(PCMHighPtPhoton, hasPCMHighPtPhoton, bool); //! PCM high pT p // DECLARE_SOA_COLUMN(PCMEtaDalitz, hasPCMEtaDalitz, bool); //! PCM eta -> ee gamma // DECLARE_SOA_COLUMN(PCMEtaGG, hasPCMEtaGG, bool); //! PCM eta -> ee gamma DECLARE_SOA_COLUMN(PCMandEE, hasPCMandEE, bool); //! PCM and ee + +// heavy meson filters +DECLARE_SOA_COLUMN(PCMOmegaMeson, hasPCMOmegaMeson, bool); //! Omega meson candidate (3pi) in the collision +DECLARE_SOA_COLUMN(EMCOmegaMeson, hasEMCOmegaMeson, bool); //! Omega meson candidate (3pi) in the collision +DECLARE_SOA_COLUMN(PCMEtaPrimeMeson, hasPCMEtaPrimeMeson, bool); //! Eta' meson candidate (3pi) in the collision +DECLARE_SOA_COLUMN(EMCEtaPrimeMeson, hasEMCEtaPrimeMeson, bool); //! Eta' meson candidate (3pi) in the collision +DECLARE_SOA_COLUMN(POmega, hasPPOmega, bool); //! Pomega meson candidate (3pi) in the collision +DECLARE_SOA_COLUMN(PEtaPrime, hasPEtaPrime, bool); //! PPEta' meson candidate (3pi) in the collision +DECLARE_SOA_COLUMN(OmegadOrPP, hasOmegadOrPP, bool); //! Omegad' meson candidate (3pi) in the collision +DECLARE_SOA_COLUMN(EtaPrimedOrPP, hasEtaPrimedOrPP, bool); //! Eta'd meson candidate (3pi) in the collision + } // namespace filtering namespace decision @@ -156,12 +231,13 @@ DECLARE_SOA_COLUMN(BCend, hasBCend, uint64_t); //! CEFP bcrange // nuclei DECLARE_SOA_TABLE(NucleiFilters, "AOD", "NucleiFilters", //! - filtering::He, filtering::H3L3Body); + filtering::H2, filtering::He, filtering::HeV0, filtering::TritonFemto, filtering::H3L3Body, filtering::Tracked3Body, filtering::ITSmildIonisation, + filtering::ITSextremeIonisation); using NucleiFilter = NucleiFilters::iterator; // diffraction DECLARE_SOA_TABLE(DiffractionFilters, "AOD", "DiffFilters", //! Diffraction filters (Collisions) - filtering::UDdiff); + filtering::UDdiffSmall, filtering::UDdiffLarge); using DiffractionFilter = DiffractionFilters::iterator; DECLARE_SOA_TABLE(DiffractionBCFilters, "AOD", "DiffBCFilters", //! Diffraction filters (BCs) @@ -170,17 +246,53 @@ using DiffractionBCFilter = DiffractionBCFilters::iterator; // Dileptons & Quarkonia DECLARE_SOA_TABLE(DqFilters, "AOD", "DqFilters", //! - filtering::SingleE, filtering::LMeeIMR, filtering::LMeeHMR, filtering::DiElectron, filtering::SingleMuLow, filtering::SingleMuHigh, filtering::DiMuon); + filtering::SingleE, filtering::LMeeIMR, filtering::LMeeHMR, filtering::DiElectron, filtering::SingleMuLow, filtering::SingleMuHigh, filtering::DiMuon, filtering::ElectronMuon); using DqFilter = DqFilters::iterator; // heavy flavours DECLARE_SOA_TABLE(HfFilters, "AOD", "HfFilters", //! - filtering::HfHighPt2P, filtering::HfHighPt3P, filtering::HfBeauty3P, filtering::HfBeauty4P, filtering::HfFemto2P, filtering::HfFemto3P, filtering::HfDoubleCharm2P, filtering::HfDoubleCharm3P, filtering::HfDoubleCharmMix, filtering::HfV0Charm2P, filtering::HfV0Charm3P, filtering::HfCharmBarToXiBach, filtering::HfSigmaCPPK, filtering::HfSigmaC0K0, filtering::HfPhotonCharm2P, filtering::HfPhotonCharm3P); + filtering::HfHighPt2P, + filtering::HfHighPt3P, + filtering::HfBeauty3P, + filtering::HfBeauty4P, + filtering::HfFemto2P, + filtering::HfFemto3P, + filtering::HfDoubleCharm2P, + filtering::HfDoubleCharm3P, + filtering::HfDoubleCharmMix, + filtering::HfV0Charm2P, + filtering::HfV0Charm3P, + filtering::HfCharmBarToXiBach, + filtering::HfSigmaCPPK, + filtering::HfSigmaC0K0, + filtering::HfPhotonCharm2P, + filtering::HfPhotonCharm3P, + filtering::HfSingleCharm2P, + filtering::HfSingleCharm3P, + filtering::HfSingleNonPromptCharm2P, + filtering::HfSingleNonPromptCharm3P, + filtering::HfCharmBarToXi2Bach, + filtering::HfPrCharm2P, + filtering::HfBtoJPsiKa, + filtering::HfBtoJPsiKstar, + filtering::HfBtoJPsiPhi, + filtering::HfBtoJPsiPrKa, + filtering::HfBtoJPsiPi); using HfFilter = HfFilters::iterator; DECLARE_SOA_TABLE(CFFilters, "AOD", "CFFilters", //! - filtering::PPP, filtering::PPL, filtering::PLL, filtering::LLL, filtering::PD, filtering::LD); + filtering::PPP_TightQ3, filtering::PPP_LooseQ3, + filtering::PPL_TightQ3, filtering::PPL_LooseQ3, + filtering::PLL_TightQ3, filtering::PLL_LooseQ3, + filtering::LLL_TightQ3, filtering::LLL_LooseQ3, + filtering::PPPHI_TightQ3, filtering::PPPHI_LooseQ3, + filtering::PPRHO_TightQ3, filtering::PPRHO_LooseQ3, + filtering::PD_TightKstar, filtering::PD_LooseKstar, + filtering::LD_TightKstar, filtering::LD_LooseKstar, + filtering::PHID_TightKstar, filtering::PHID_LooseKstar, + filtering::RHOD_TightKstar, filtering::RHOD_LooseKstar); + using CfFilter = CFFilters::iterator; // jets @@ -207,7 +319,7 @@ using FullJetFilter = FullJetFilters::iterator; // strangeness (lf) DECLARE_SOA_TABLE(StrangenessFilters, "AOD", "LFStrgFilters", //! - filtering::Omega, filtering::hadronOmega, filtering::DoubleXi, filtering::TripleXi, filtering::QuadrupleXi, filtering::SingleXiYN, filtering::OmegaLargeRadius, filtering::TrackedXi, filtering::TrackedOmega, filtering::OmegaHighMult); + filtering::Omega, filtering::hadronOmega, filtering::DoubleXi, filtering::TripleXi, filtering::QuadrupleXi, filtering::SingleXiYN, filtering::OmegaLargeRadius, filtering::TrackedXi, filtering::TrackedOmega, filtering::OmegaHighMult, filtering::DoubleOmega, filtering::OmegaXi, filtering::LambdaLambda); using StrangenessFilter = StrangenessFilters::iterator; @@ -216,6 +328,11 @@ DECLARE_SOA_TABLE(F1ProtonFilters, "AOD", "F1ProtonFilters", //! filtering::TriggerEventF1Proton); using F1ProtonFilter = F1ProtonFilters::iterator; +// Double Phi +DECLARE_SOA_TABLE(DoublePhiFilters, "AOD", "DoublePhiFilters", //! + filtering::TriggerEventDoublePhi); +using DoublePhiFilter = DoublePhiFilters::iterator; + // multiplicity DECLARE_SOA_TABLE(MultFilters, "AOD", "MultFilters", //! filtering::HighTrackMult, filtering::HighMultFv0, filtering::HighFt0Mult, filtering::HighFt0Flat, filtering::HighFt0cFv0Mult, filtering::HighFt0cFv0Flat, filtering::LeadingPtTrack); @@ -228,6 +345,15 @@ DECLARE_SOA_TABLE(PhotonFilters, "AOD", "PhotonFilters", //! using PhotonFilter = PhotonFilters::iterator; +// heavy mesons +DECLARE_SOA_TABLE(HeavyNeutralMesonFilters, "AOD", "HeavyNeutralMesonFilters", //! + filtering::PCMOmegaMeson, filtering::EMCOmegaMeson, + filtering::PCMEtaPrimeMeson, filtering::EMCEtaPrimeMeson, + filtering::POmega, filtering::PEtaPrime, + filtering::OmegadOrPP, filtering::EtaPrimedOrPP); + +using HeavyNeutralMesonFilter = HeavyNeutralMesonFilters::iterator; + // cefp decision DECLARE_SOA_TABLE(CefpDecisions, "AOD", "CefpDecision", //! decision::BCId, decision::GlobalBCId, decision::EvSelBC, decision::CollisionTime, decision::CollisionTimeRes, decision::CefpTriggered0, decision::CefpTriggered1, decision::CefpSelected0, decision::CefpSelected1); @@ -239,17 +365,17 @@ DECLARE_SOA_TABLE(BCRanges, "AOD", "BCRanges", //! using BCRange = BCRanges::iterator; /// List of the available filters, the description of their tables and the name of the tasks -constexpr int NumberOfFilters{12}; -constexpr std::array AvailableFilters{"NucleiFilters", "DiffractionFilters", "DqFilters", "HfFilters", "CFFilters", "JetFilters", "JetHFFilters", "FullJetFilters", "StrangenessFilters", "MultFilters", "PhotonFilters", "F1ProtonFilters"}; -constexpr std::array FilterDescriptions{"NucleiFilters", "DiffFilters", "DqFilters", "HfFilters", "CFFilters", "JetFilters", "JetHFFilters", "FullJetFilters", "LFStrgFilters", "MultFilters", "PhotonFilters", "F1ProtonFilters"}; -constexpr std::array FilteringTaskNames{"o2-analysis-nuclei-filter", "o2-analysis-diffraction-filter", "o2-analysis-dq-filter-pp-with-association", "o2-analysis-hf-filter", "o2-analysis-cf-filter", "o2-analysis-je-filter", "o2-analysis-je-hf-filter", "o2-analysis-fje-filter", "o2-analysis-lf-strangeness-filter", "o2-analysis-mult-filter", "o2-analysis-em-photon-filter", "o2-analysis-lf-f1proton-filter"}; -constexpr o2::framework::pack FiltersPack; +constexpr int NumberOfFilters{14}; +constexpr std::array AvailableFilters{"NucleiFilters", "DiffractionFilters", "DqFilters", "HfFilters", "CFFilters", "JetFilters", "JetHFFilters", "FullJetFilters", "StrangenessFilters", "MultFilters", "PhotonFilters", "F1ProtonFilters", "DoublePhiFilters", "HeavyNeutralMesonFilters"}; +constexpr std::array FilterDescriptions{"NucleiFilters", "DiffFilters", "DqFilters", "HfFilters", "CFFilters", "JetFilters", "JetHFFilters", "FullJetFilters", "LFStrgFilters", "MultFilters", "PhotonFilters", "F1ProtonFilters", "2PhiFilters", "HNMesonFilters"}; +constexpr std::array FilteringTaskNames{"o2-analysis-nuclei-filter", "o2-analysis-diffraction-filter", "o2-analysis-dq-filter-pp-with-association", "o2-analysis-hf-filter", "o2-analysis-cf-filter", "o2-analysis-je-filter", "o2-analysis-je-hf-filter", "o2-analysis-fje-filter", "o2-analysis-lf-strangeness-filter", "o2-analysis-mult-filter", "o2-analysis-em-photon-filter", "o2-analysis-lf-f1proton-filter", "o2-analysis-lf-doublephi-filter", "o2-analysis-heavy-meson-filter"}; +constexpr o2::framework::pack FiltersPack; static_assert(o2::framework::pack_size(FiltersPack) == NumberOfFilters); template void addColumnToMap(std::unordered_map>& map) { - map[MetadataTrait::metadata::tableLabel()][C::columnLabel()] = 1.f; + map[o2::soa::getTableLabel()][C::columnLabel()] = 1.f; } template @@ -266,7 +392,7 @@ void addColumnsToMap(o2::framework::pack, std::unordered_map void FillFiltersMap(o2::framework::pack, std::unordered_map>& map) { - (addColumnsToMap(typename T::table_t::columns{}, map), ...); + (addColumnsToMap(typename T::table_t::persistent_columns_t{}, map), ...); } template diff --git a/EventFiltering/macros/checkBCrangesSkimming.C b/EventFiltering/macros/checkBCrangesSkimming.C new file mode 100644 index 00000000000..f71212238c3 --- /dev/null +++ b/EventFiltering/macros/checkBCrangesSkimming.C @@ -0,0 +1,680 @@ +// 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. +// O2 includes + +#include +#include +#include +#include +#include +#include +#include +#include +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/IRFrame.h" + +using o2::InteractionRecord; +using o2::dataformats::IRFrame; + +// Set the bit of trigger which need to be checked +const ULong64_t bcDiffTolerance = 0; +const char outputFileName[15] = "output.root"; + +struct bcTuple { + bcTuple(ULong64_t bcAO2D, ULong64_t bcEvSel) : bcAO2D(bcAO2D), bcEvSel(bcEvSel) {} + ULong64_t bcAO2D{0ull}; + ULong64_t bcEvSel{0ull}; + bool operator==(const bcTuple& t) const + { + return (this->bcAO2D == t.bcAO2D && this->bcEvSel == t.bcEvSel); + } +}; + +struct selectedFrames : public IRFrame { + selectedFrames(ULong64_t bcAO2D, ULong64_t bcEvSel, const IRFrame& frame) : IRFrame(frame), bcAO2D(bcAO2D), bcEvSel(bcEvSel), triMask{0, 0}, selMask{0, 0} {} + selectedFrames(ULong64_t bcAO2D, ULong64_t bcEvSel, ULong64_t triMask[2], ULong64_t selMask[2], const IRFrame& frame) : IRFrame(frame), bcAO2D(bcAO2D), bcEvSel(bcEvSel), triMask{triMask[0], triMask[1]}, selMask{selMask[0], selMask[1]} {} + ULong64_t triMask[2]{0ull}, selMask[2]{0ull}, bcAO2D, bcEvSel; + int numSameTriggerInNearbyBCs = 0; // related to bcDiffTolerance + bool isSingle() { return numSameTriggerInNearbyBCs == 0; } + void SetNInNearbyBC(int n) { numSameTriggerInNearbyBCs = n; } + int GetNInNearbyBC() { return numSameTriggerInNearbyBCs; } +}; + +int DoBCSubraction(ULong64_t bc1, ULong64_t bc2) +{ + if (bc1 > bc2) { + return bc1 - bc2; + } else { + ULong64_t bcsub = bc2 - bc1; + return -static_cast(bcsub); + } +} + +int DoBCSubraction(selectedFrames bc1, selectedFrames bc2) +{ + if (bc1.getMin() > bc2.getMax()) { + return DoBCSubraction(bc1.getMin().toLong(), bc2.getMax().toLong()); + } else if (bc1.getMax() < bc2.getMin()) { + return DoBCSubraction(bc1.getMax().toLong(), bc2.getMin().toLong()); + } else { + return 0; + } +} + +bool isClose(selectedFrames a, selectedFrames b, ULong64_t bcDiffTolerance) +{ + if (a.getMin() > b.getMax() + bcDiffTolerance || a.getMax() + bcDiffTolerance < b.getMin()) + return false; + else + return true; +} + +std::vector> getFrames(std::unique_ptr& file, int trgIDStart, int N) +{ + ULong64_t bcAO2D{0ull}, bcEvSel{0ull}, triMask[2]{0ull}, selMask[2]{0ull}; + std::vector> frames; + frames.resize(N); + for (auto key : *file->GetListOfKeys()) { + auto dir = dynamic_cast(file->Get(key->GetName())); + if (!dir) { + continue; + } + auto tree = dynamic_cast(dir->Get("selectedBC")); + if (!tree) { + continue; + } + tree->SetBranchAddress("bcAO2D", &bcAO2D); + tree->SetBranchAddress("bcEvSel", &bcEvSel); + if (tree->GetBranch("triMask")) { + tree->SetBranchAddress("triMask", &triMask[0]); + tree->SetBranchAddress("selMask", &selMask[0]); + } else { + tree->SetBranchAddress("triMask0", &triMask[0]); + tree->SetBranchAddress("triMask1", &triMask[1]); + tree->SetBranchAddress("selMask0", &selMask[0]); + tree->SetBranchAddress("selMask1", &selMask[1]); + } + + for (int i = 0; i < tree->GetEntries(); i++) { + tree->GetEntry(i); + if (!selMask[0] && !selMask[1]) { + continue; + } + for (int trgID = trgIDStart; trgID < trgIDStart + N; trgID++) { + ULong64_t trigger0Bit = 0, trigger1Bit = 0; + if (trgID < 64) { + trigger0Bit = BIT(trgID); + } else { + trigger1Bit = BIT(trgID - 64); + } + if (selMask[0] & trigger0Bit || selMask[1] & trigger1Bit) { + InteractionRecord irstart, irend; + irstart.setFromLong(std::min(bcAO2D, bcEvSel)); + irend.setFromLong(std::max(bcAO2D, bcEvSel)); + IRFrame frame(irstart, irend); + int index = trgID - trgIDStart; + frames[index].push_back({bcAO2D, bcEvSel, triMask, selMask, frame}); + } + } + } + } + + return frames; +} + +std::vector getSelectedFrames(std::unique_ptr& file, int trgID) +{ + auto frames = getFrames(file, trgID, 1); + return frames[0]; +} + +// Check how many other triggers are in a compatible BC window with the current one +// Ideally, most of triggers are singles (num = 1) +// which means for most triggered events, none of others is in a nearby time window +void checkNearbyBCs(std::vector& frames, ULong64_t bcDiffTolerance) +{ + std::sort(frames.begin(), frames.end(), [](const selectedFrames& a, const selectedFrames& b) { + if (a.getMin() != b.getMin()) { + return a.getMin() < b.getMin(); + } else { + return a.getMax() < b.getMax(); + } + }); + int firstTrg = 0; + for (auto& currentFrame : frames) { + int num = 0; + bool shouldUpdate = true; // true if the maxBC of event in loop is smaller than the evaluating one -> update firstTrg + for (int i = firstTrg; i < frames.size(); i++) { + auto& frame = frames[i]; + if (frame.getMin() > currentFrame.getMax() + bcDiffTolerance) { + break; + } + if (isClose(currentFrame, frame, bcDiffTolerance)) { + shouldUpdate = false; + bool found = currentFrame.selMask[0] & frame.selMask[0] || currentFrame.selMask[1] & frame.selMask[1]; + if (found) { + num++; + } + } else { + if (shouldUpdate) { + firstTrg = i; + } + } + } + currentFrame.SetNInNearbyBC(num); + } +} + +// Get RunNumber +std::string getRunNumber(std::string fileName) +{ + std::string runNumber = ""; + std::regex re("/5[0-9]*"); + std::smatch match; + if (std::regex_search(fileName, match, re)) { + // Remove the leading '/' + runNumber = match.str().substr(1); + } + return runNumber; +} + +// Detailed checks for specific trigger, not enabled by default +void checkBCForSelectedTrg(std::vector& originalFrames, std::vector& skimmedFrames, string runNumber, string triggerLabel) +{ + + TH1D hTriggerCounter("hTriggerCounter", (runNumber + " " + triggerLabel + ";;Total number of trigger").data(), 2, -0.5, 1.5); + hTriggerCounter.GetXaxis()->SetBinLabel(1, "Original"); + hTriggerCounter.GetXaxis()->SetBinLabel(2, "Skimmed"); + TH1D hBCDiffAO2D("hBCDiffAO2D", (runNumber + " " + triggerLabel + ";;#DeltaBC_{AO2D} between paired singles").data(), 201, -100.5, 100.5); + TH1D hBCDiffEvSel("hBCDiffEvSel", (runNumber + " " + triggerLabel + ";;#DeltaBC_{EvSel} between paired singles").data(), 201, -100.5, 100.5); + + TH1D hBCOriginal("hBCOriginal", (runNumber + " " + triggerLabel + " Original;;Trigger counts").data(), 4, -0.5, 3.5); + hBCOriginal.GetXaxis()->SetBinLabel(1, "Total"); + hBCOriginal.GetXaxis()->SetBinLabel(2, "Same AO2D BC"); + hBCOriginal.GetXaxis()->SetBinLabel(3, "Same EvSel BC"); + hBCOriginal.GetXaxis()->SetBinLabel(4, "Same Both BC"); + TH1D hBCSkimmed("hBCSkimmed", (runNumber + " " + triggerLabel + " Skimmed;;Trigger counts").data(), 4, -0.5, 3.5); + hBCSkimmed.GetXaxis()->SetBinLabel(1, "Total"); + hBCSkimmed.GetXaxis()->SetBinLabel(2, "Same AO2D BC"); + hBCSkimmed.GetXaxis()->SetBinLabel(3, "Same EvSel BC"); + hBCSkimmed.GetXaxis()->SetBinLabel(4, "Same Both BC"); + + TH1D hMatchedNumCounter("hMatchedNumCounter", (runNumber + " " + triggerLabel + ";;Number of matched triggers in skimmed data").data(), 10, -0.5, 9.5); + + checkNearbyBCs(originalFrames, bcDiffTolerance); + checkNearbyBCs(skimmedFrames, bcDiffTolerance); + + std::vector bcSet; + int firstTrg = 0; + for (int i = 0; i < originalFrames.size(); i++) { + auto& frame = originalFrames[i]; + hTriggerCounter.Fill(0); + hBCOriginal.Fill(0); + //------------------------------ Check if there are triggers which have same BC, time-consuming! ------------------------------------------------------- + auto p1 = std::find_if(bcSet.begin(), bcSet.end(), [&](const auto& val) { return val.bcAO2D == frame.bcAO2D; }); + if (p1 != bcSet.end()) { + hBCOriginal.Fill(1); + } + auto p2 = std::find_if(bcSet.begin(), bcSet.end(), [&](const auto& val) { return val.bcEvSel == frame.bcEvSel; }); + if (p2 != bcSet.end()) { + hBCOriginal.Fill(2); + } + bcTuple currentBC(frame.bcAO2D, frame.bcEvSel); + auto p3 = std::find(bcSet.begin(), bcSet.end(), currentBC); + if (p3 == bcSet.end()) { + bcSet.push_back(currentBC); + } else { + hBCOriginal.Fill(3); + } + //------------------------------------------------------------------------------------- + + if (frame.GetNInNearbyBC() != 1) { + continue; // Only check singles + } + std::vector skimmedbcs; + int n = 0; + bool shouldUpdate = true; + for (int j = firstTrg; j < skimmedFrames.size(); j++) { + auto& skimmedFrame = skimmedFrames[j]; + if (skimmedFrame.getMin() > frame.getMax()) { + break; + } + if (skimmedFrame.GetNInNearbyBC() != 1) { + continue; // Only check singles + } + if (isClose(frame, skimmedFrame, bcDiffTolerance)) { + shouldUpdate = false; + bool found = frame.selMask[0] & skimmedFrame.selMask[0] || frame.selMask[1] & skimmedFrame.selMask[1]; + if (found) { + // Additional check to avoid match of skimmed singles and original multiplies + if (i != 0 && isClose(originalFrames[i - 1], skimmedFrame, bcDiffTolerance)) { + continue; + } + if (i != originalFrames.size() && isClose(originalFrames[i + 1], skimmedFrame, bcDiffTolerance)) { + continue; + } + skimmedbcs.push_back({skimmedFrame.bcAO2D, skimmedFrame.bcEvSel}); + n++; + } + } else { + if (shouldUpdate) { + firstTrg = j; + } + } + } + if (n == 0) { + // std::cout << "Trigger not found!!!" << std::endl; + } else if (n == 1) { + hBCDiffAO2D.Fill(DoBCSubraction(frame.bcAO2D, skimmedbcs[0].bcAO2D)); + hBCDiffEvSel.Fill(DoBCSubraction(frame.bcEvSel, skimmedbcs[0].bcEvSel)); + } + hMatchedNumCounter.Fill(n); + } + + //------------------------------ Check if there are triggers which have same BC, time-consuming! ------------------------------------------------------- + bcSet.clear(); + for (auto& skimmedFrame : skimmedFrames) { + hTriggerCounter.Fill(1); + hBCSkimmed.Fill(0); + auto p1 = std::find_if(bcSet.begin(), bcSet.end(), [&](const auto& val) { return val.bcAO2D == skimmedFrame.bcAO2D; }); + if (p1 != bcSet.end()) { + hBCSkimmed.Fill(1); + } + auto p2 = std::find_if(bcSet.begin(), bcSet.end(), [&](const auto& val) { return val.bcEvSel == skimmedFrame.bcEvSel; }); + if (p2 != bcSet.end()) { + hBCSkimmed.Fill(2); + } + bcTuple currentBC(skimmedFrame.bcAO2D, skimmedFrame.bcEvSel); + auto p3 = std::find(bcSet.begin(), bcSet.end(), currentBC); + if (p3 == bcSet.end()) { + bcSet.push_back(currentBC); + } else { + hBCSkimmed.Fill(3); + } + } + //------------------------------------------------------------------------------------- + + TFile fout(outputFileName, "UPDATE"); + fout.cd(); + TDirectory* dir1 = fout.GetDirectory(runNumber.data()); + if (!dir1) { + dir1 = fout.mkdir(runNumber.data()); + } + dir1->cd(); + TDirectory* dir2 = dir1->GetDirectory(triggerLabel.data()); + if (!dir2) { + dir2 = dir1->mkdir(triggerLabel.data()); + } + dir2->cd(); + + hTriggerCounter.Write(); + hBCOriginal.Write(); + hBCSkimmed.Write(); + hBCDiffAO2D.Write(); + hBCDiffEvSel.Write(); + hMatchedNumCounter.Write(); + fout.Close(); +} + +// Detailed checks for specific trigger +void checkBCForSelectedTrg(std::string AnaFileName = "AnalysisResults.root", std::string originalFileName = "bcRanges_fullrun.root", std::string skimmedFileName = "bcRanges_fullrun_skimmed.root", int triggerID = 1, bool useAlien = true) +{ + + string runNumber = getRunNumber(originalFileName); + if (useAlien) { + TGrid::Connect("alien://"); + AnaFileName = "alien://" + AnaFileName; + originalFileName = "alien://" + originalFileName; + skimmedFileName = "alien://" + skimmedFileName; + } + + // Readin labels + std::unique_ptr AnaFile{TFile::Open(AnaFileName.c_str(), "READ")}; + TH1* hist0 = dynamic_cast(AnaFile->Get("central-event-filter-task/scalers/mFiltered;1")); + std::vector labels; + std::vector binNum; + for (int i = 1; i <= hist0->GetNbinsX(); i++) { + std::string label = hist0->GetXaxis()->GetBinLabel(i); + if (label != "Total number of events" && label != "Filtered events") { + labels.push_back(label); + binNum.push_back(i); + } + } + AnaFile->Close(); + std::string triggerLabel = labels[triggerID]; + + std::unique_ptr originalFile{TFile::Open(originalFileName.c_str(), "READ")}; + std::unique_ptr skimmedFile{TFile::Open(skimmedFileName.c_str(), "READ")}; + auto originalFrames = getSelectedFrames(originalFile, triggerID); + auto skimmedFrames = getSelectedFrames(skimmedFile, triggerID); + originalFile->Close(); + skimmedFile->Close(); + + checkBCForSelectedTrg(originalFrames, skimmedFrames, runNumber, triggerLabel); +} + +// Check the BCId compatibility of triggers on original and skimmmed data +void checkBCrangesSkimming(std::string AnaFileName = "AnalysisResults.root", std::string originalFileName = "bcRanges_fullrun.root", std::string skimmedFileName = "bcRanges_fullrun_skimmed.root", bool useAlien = true) +{ + + string runNumber = getRunNumber(originalFileName); + if (useAlien) { + TGrid::Connect("alien://"); + AnaFileName = "alien://" + AnaFileName; + originalFileName = "alien://" + originalFileName; + skimmedFileName = "alien://" + skimmedFileName; + } + + // Readin labels + std::unique_ptr AnaFile{TFile::Open(AnaFileName.c_str(), "READ")}; + TH1* hist0 = dynamic_cast(AnaFile->Get("central-event-filter-task/scalers/mFiltered;1")); + std::vector labels; + std::vector binNum; + for (int i = 1; i <= hist0->GetNbinsX(); i++) { + std::string label = hist0->GetXaxis()->GetBinLabel(i); + if (label != "Total number of events" && label != "Filtered events") { + labels.push_back(label); + binNum.push_back(i); + // std::cout << i - 2 << ": " << label << std::endl; + } + } + AnaFile->Close(); + + // Due to potential selection on triggers, histograms should be created later + // for example: skip triggers which have no enrties + std::vector sel_labels; + std::vector numOriginal, numSkimmed, numOriginalSingle, numSkimmedSingle, numOriginalDouble, numSkimmedDouble, numOriginalMultiple, numSkimmedMultiple, numCloseSkimmed; + std::vector numpair, numpairedBCAO2D, numpairedBCEvSel; + std::vector avgDeltaBCAO2D, avgDeltaBCEvSel, avgDeltaBC, rmsDeltaBCAO2D, rmsDeltaBCEvSel, rmsDeltaBC; + std::vector avgNumPairedTrigger, rmsNumPairedTrigger; + + std::unique_ptr originalFile{TFile::Open(originalFileName.c_str(), "READ")}; + std::unique_ptr skimmedFile{TFile::Open(skimmedFileName.c_str(), "READ")}; + std::vector> originalAllFrames = getFrames(originalFile, 0, labels.size()); + std::vector> skimmedAllFrames = getFrames(skimmedFile, 0, labels.size()); + for (int trgID = 0; trgID < labels.size(); trgID++) { + // Caculate singles, doubles, and multiples + int noriginal{0}, nskimmed{0}, noriginalsingle{0}, nskimmedsingle{0}, noriginaldouble{0}, nskimmeddouble{0}, noriginalmultiple{0}, nskimmedmultiple{0}; + // Caculate mean and rms of diff BC + TH1D hDiffBCAO2DCount("hDiffBCAO2DCount", "hDiffBCAO2DCount", 21, -10.5, 10.5); + TH1D hDiffBCEvSelCount("hDiffBCEvSelCount", "hDiffBCEvSelCount", 21, -10.5, 10.5); + TH1D hDiffBCCount("hDiffBCCount", "hDiffBCCount", 21, -10.5, 10.5); + TH1D hNumPairedTriggerCount("hNumPairedTriggerCount", "hNumPairedTriggerCount", 10, -0.5, 9.5); + // For Original dataset + auto& originalFrames = originalAllFrames[trgID]; + checkNearbyBCs(originalFrames, bcDiffTolerance); // include sorting + noriginal = originalFrames.size(); + for (auto originalFrame : originalFrames) { + if (originalFrame.GetNInNearbyBC() == 0) { + std::cerr << "Unexpected trigger!!! " << std::endl; + } else if (originalFrame.GetNInNearbyBC() == 1) { + noriginalsingle++; + } else if (originalFrame.GetNInNearbyBC() == 2) { + noriginaldouble++; + } else { + noriginalmultiple++; + } + } + // For skimmed dataset + auto& skimmedFrames = skimmedAllFrames[trgID]; + checkNearbyBCs(skimmedFrames, bcDiffTolerance); // include sorting + nskimmed = skimmedFrames.size(); + for (auto& skimmedFrame : skimmedFrames) { + if (skimmedFrame.GetNInNearbyBC() == 0) { + std::cerr << "Unexpected trigger!!! " << std::endl; + } else if (skimmedFrame.GetNInNearbyBC() == 1) { + nskimmedsingle++; + } else if (skimmedFrame.GetNInNearbyBC() == 2) { + nskimmeddouble++; + } else { + nskimmedmultiple++; + } + } + + // Check BC differences + int npair{0}, npairedBCAO2D{0}, npairedBCEvSel{0}, ncloseskimmed{0}, maxdeltaBCAO2D{0}, maxdeltaBCEvSel{0}; + int firstTrg = 0; + for (int i = 0; i < originalFrames.size(); i++) { + auto& frame = originalFrames[i]; + if (frame.GetNInNearbyBC() != 1) { + continue; // Only check singles + } + std::vector skimmedbcs; + int n = 0; + bool shouldUpdate = true; + for (int j = firstTrg; j < skimmedFrames.size(); j++) { + auto& skimmedFrame = skimmedFrames[j]; + if (skimmedFrame.getMin() > frame.getMax()) { + break; + } + if (skimmedFrame.GetNInNearbyBC() != 1) { + continue; // Only check singles + } + if (isClose(frame, skimmedFrame, bcDiffTolerance)) { + shouldUpdate = false; + bool found = frame.selMask[0] & skimmedFrame.selMask[0] || frame.selMask[1] & skimmedFrame.selMask[1]; + if (found) { + // Additional check to avoid match of skimmed singles and original multiplies + if (i != 0 && isClose(originalFrames[i - 1], skimmedFrame, bcDiffTolerance)) { + continue; + } + if (i != originalFrames.size() && isClose(originalFrames[i + 1], skimmedFrame, bcDiffTolerance)) { + continue; + } + + InteractionRecord irstart, irend; + irstart.setFromLong(std::min(skimmedFrame.bcAO2D, skimmedFrame.bcEvSel)); + irend.setFromLong(std::max(skimmedFrame.bcAO2D, skimmedFrame.bcEvSel)); + IRFrame frame(irstart, irend); + skimmedbcs.push_back({skimmedFrame.bcAO2D, skimmedFrame.bcEvSel, frame}); + n++; + } + } else { + if (shouldUpdate) { + firstTrg = j; + } + } + } + if (n == 1) { + npair++; + int bcdiffAO2D = DoBCSubraction(frame.bcAO2D, skimmedbcs[0].bcAO2D); + int bcdiffEvSel = DoBCSubraction(frame.bcEvSel, skimmedbcs[0].bcEvSel); + hDiffBCAO2DCount.Fill(std::abs(bcdiffAO2D)); + hDiffBCEvSelCount.Fill(std::abs(bcdiffEvSel)); + hDiffBCCount.Fill(std::abs(DoBCSubraction(frame, skimmedbcs[0]))); + if (frame.bcAO2D == skimmedbcs[0].bcAO2D) { + npairedBCAO2D++; + } + if (frame.bcEvSel == skimmedbcs[0].bcEvSel) { + npairedBCEvSel++; + } + } + ncloseskimmed += n; + hNumPairedTriggerCount.Fill(n); + } + + // if (static_cast(ncloseskimmed) / noriginal > 0.95 || noriginal == 0) + if (noriginal == 0) { + // continue; + } + sel_labels.push_back(labels[trgID]); + numOriginal.push_back(noriginal); + numOriginalSingle.push_back(noriginalsingle); + numOriginalDouble.push_back(noriginaldouble); + numOriginalMultiple.push_back(noriginalmultiple); + numSkimmed.push_back(nskimmed); + numSkimmedSingle.push_back(nskimmedsingle); + numSkimmedDouble.push_back(nskimmeddouble); + numSkimmedMultiple.push_back(nskimmedmultiple); + + numpair.push_back(npair); + numpairedBCAO2D.push_back(npairedBCAO2D); + numpairedBCEvSel.push_back(npairedBCEvSel); + numCloseSkimmed.push_back(ncloseskimmed); + avgDeltaBCAO2D.push_back(hDiffBCAO2DCount.GetMean()); + avgDeltaBCEvSel.push_back(hDiffBCEvSelCount.GetMean()); + avgDeltaBC.push_back(hDiffBCCount.GetMean()); + rmsDeltaBCAO2D.push_back(hDiffBCAO2DCount.GetRMS()); + rmsDeltaBCEvSel.push_back(hDiffBCEvSelCount.GetRMS()); + rmsDeltaBC.push_back(hDiffBCCount.GetRMS()); + avgNumPairedTrigger.push_back(hNumPairedTriggerCount.GetMean()); + rmsNumPairedTrigger.push_back(hNumPairedTriggerCount.GetRMS()); + } + originalFile->Close(); + skimmedFile->Close(); + + TH1D hOriginalTotal("hOriginalTotal", (runNumber + " Original;;Number of events").data(), sel_labels.size(), 0, sel_labels.size()); + TH1D hOriginalSingles("hOriginalSingles", (runNumber + " Original;;Number of singles").data(), sel_labels.size(), 0, sel_labels.size()); + TH1D hOriginalDoubles("hOriginalDoubles", (runNumber + " Original;;Number of doubles").data(), sel_labels.size(), 0, sel_labels.size()); + TH1D hOriginalMultiples("hOriginalMultiples", (runNumber + " Original;;Number of multiples").data(), sel_labels.size(), 0, sel_labels.size()); + + TH1D hSkimmedTotal("hSkimmedTotal", (runNumber + " Skimmed;;Number of events").data(), sel_labels.size(), 0, sel_labels.size()); + TH1D hSkimmedSingles("hSkimmedSingles", (runNumber + " Skimmed;;Number of singles").data(), sel_labels.size(), 0, sel_labels.size()); + TH1D hSkimmedDoubles("hSkimmedDoubles", (runNumber + " Skimmed;;Number of doubles").data(), sel_labels.size(), 0, sel_labels.size()); + TH1D hSkimmedMultiples("hSkimmedMultiples", (runNumber + " Skimmed;;Number of multiples").data(), sel_labels.size(), 0, sel_labels.size()); + + TH1D hTriggerMatchesRatio("hTriggerMatchesRatio", (runNumber + " Skimmed Efficiency;; Matched skimmed triggers / Original singles").data(), sel_labels.size(), 0, sel_labels.size()); // the ratio of triggers in skimmed dataset whose BC is compatible with original triggers to the number of original triggers, might be duplicate since we check it based on every trigger in unskimmed data + TH1D hTriggerSingleMatchesRatio("hTriggerSingleMatchesRatio", (runNumber + " Skimmed Efficiency;; One-to-one matches / Original singles").data(), sel_labels.size(), 0, sel_labels.size()); // the ratio of 1-1 paired triggers to the number of original triggers + TH1D hMatchesSameBCAO2DRatio("hMatchesSameBCAO2DRatio", (runNumber + " One-to-one matches;; Matchess with same BC_{AO2D} / Total").data(), sel_labels.size(), 0, sel_labels.size()); // In 1-1 matches, the ratio of matches who have same BCAO2D + TH1D hMatchesSameBCEvSelRatio("hMatchesSameBCEvSelRatio", (runNumber + " One-to-one matches;; Matches with same BC_{EvSel} / Total").data(), sel_labels.size(), 0, sel_labels.size()); // In 1-1 matches, the ratio of matches who have same BCEvSel + TH1D hDiffBCAO2D("hDiffBCAO2D", (runNumber + " One-to-one matches;;|#DeltaBC_{AO2D}|").data(), sel_labels.size(), 0, sel_labels.size()); // difference in BCAO2D of 1-1 matches + TH1D hDiffBCEvSel("hDiffBCEvSel", (runNumber + " One-to-one matches;;|#DeltaBC_{EvSel}|").data(), sel_labels.size(), 0, sel_labels.size()); // difference in BCEvSel of 1-1 matches + TH1D hDiffBC("hDiffBC", (runNumber + " One-to-one matches;;|#DeltaBC|").data(), sel_labels.size(), 0, sel_labels.size()); // difference between the BC tuple, expected to be 0 if bcDiffTolerance = 0 + TH1D hNumMatchesInSkimmed("hNumMatchesInSkimmed", (runNumber + " number of matched triggers in skimmed data;;Matched trigger count").data(), sel_labels.size(), 0, sel_labels.size()); // number of triggers in skimmed data which are compatible in the BC ranges of singles in original selection + + for (int i = 0; i < sel_labels.size(); i++) { + // Original data + hOriginalTotal.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); + hOriginalSingles.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); + hOriginalDoubles.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); + hOriginalMultiples.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); + + hOriginalTotal.SetBinContent(i + 1, numOriginal[i]); + hOriginalTotal.SetBinError(i + 1, std::sqrt(numOriginal[i])); + hOriginalSingles.SetBinContent(i + 1, numOriginalSingle[i]); + hOriginalSingles.SetBinError(i + 1, std::sqrt(numOriginalSingle[i])); + hOriginalDoubles.SetBinContent(i + 1, numOriginalDouble[i]); + hOriginalDoubles.SetBinError(i + 1, std::sqrt(numOriginalDouble[i])); + hOriginalMultiples.SetBinContent(i + 1, numOriginalMultiple[i]); + hOriginalMultiples.SetBinError(i + 1, std::sqrt(numOriginalMultiple[i])); + + // Skimmed data + hSkimmedTotal.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); + hSkimmedSingles.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); + hSkimmedDoubles.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); + hSkimmedMultiples.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); + + hSkimmedTotal.SetBinContent(i + 1, numSkimmed[i]); + hSkimmedTotal.SetBinError(i + 1, std::sqrt(numSkimmed[i])); + hSkimmedSingles.SetBinContent(i + 1, numSkimmedSingle[i]); + hSkimmedSingles.SetBinError(i + 1, std::sqrt(numSkimmedSingle[i])); + hSkimmedDoubles.SetBinContent(i + 1, numSkimmedDouble[i]); + hSkimmedDoubles.SetBinError(i + 1, std::sqrt(numSkimmedDouble[i])); + hSkimmedMultiples.SetBinContent(i + 1, numSkimmedMultiple[i]); + hSkimmedMultiples.SetBinError(i + 1, std::sqrt(numSkimmedMultiple[i])); + + // Matches QA + hTriggerMatchesRatio.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); + hTriggerSingleMatchesRatio.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); + hMatchesSameBCAO2DRatio.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); + hMatchesSameBCEvSelRatio.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); + hDiffBCAO2D.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); + hDiffBCEvSel.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); + hDiffBC.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); + hNumMatchesInSkimmed.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); + + if (numpair[i] > 0) { + hMatchesSameBCAO2DRatio.SetBinContent(i + 1, static_cast(numpairedBCAO2D[i]) / numpair[i]); + hMatchesSameBCEvSelRatio.SetBinContent(i + 1, static_cast(numpairedBCEvSel[i]) / numpair[i]); + } + hTriggerMatchesRatio.SetBinContent(i + 1, numCloseSkimmed[i]); + hTriggerMatchesRatio.SetBinError(i + 1, std::sqrt(numCloseSkimmed[i])); + hTriggerSingleMatchesRatio.SetBinContent(i + 1, numpair[i]); + hTriggerSingleMatchesRatio.SetBinError(i + 1, std::sqrt(numpair[i])); + hDiffBCAO2D.SetBinContent(i + 1, avgDeltaBCAO2D[i]); + hDiffBCAO2D.SetBinError(i + 1, rmsDeltaBCAO2D[i]); + hDiffBCEvSel.SetBinContent(i + 1, avgDeltaBCEvSel[i]); + hDiffBCEvSel.SetBinError(i + 1, rmsDeltaBCEvSel[i]); + hDiffBC.SetBinContent(i + 1, avgDeltaBC[i]); + hDiffBC.SetBinError(i + 1, rmsDeltaBC[i]); + hNumMatchesInSkimmed.SetBinContent(i + 1, avgNumPairedTrigger[i]); + hNumMatchesInSkimmed.SetBinError(i + 1, rmsNumPairedTrigger[i]); + } + + TH1D* hTriggerEff; // Ratio of the total number of triggers in skimmed data to that in original data (not the real efficiency since the downscalings are removed in skimmed for this QA) + TH1D *hOriginalSinglesRatio, *hOriginalDoublesRatio, *hOriginalMultiplesRatio; + TH1D *hSkimmedSinglesRatio, *hSkimmedDoublesRatio, *hSkimmedMultiplesRatio; + + hTriggerEff = reinterpret_cast(hSkimmedTotal.Clone("hTriggerEff")); + hTriggerEff->SetTitle((runNumber + " skimmed efficiency;; Skimmed / Original").data()); + hTriggerEff->Divide(&hOriginalTotal); + hTriggerMatchesRatio.Divide(&hOriginalSingles); + hTriggerSingleMatchesRatio.Divide(&hOriginalSingles); + hOriginalSinglesRatio = reinterpret_cast(hOriginalSingles.Clone("hOriginalSinglesRatio")); + hOriginalSinglesRatio->SetTitle((runNumber + " Original;;Singles / Total").data()); + hOriginalSinglesRatio->Divide(&hOriginalTotal); + hOriginalDoublesRatio = reinterpret_cast(hOriginalDoubles.Clone("hOriginalDoublesRatio")); + hOriginalDoublesRatio->SetTitle((runNumber + " Original;;Doubles / Total").data()); + hOriginalDoublesRatio->Divide(&hOriginalTotal); + hOriginalMultiplesRatio = reinterpret_cast(hOriginalMultiples.Clone("hOriginalMultiplesRatio")); + hOriginalMultiplesRatio->SetTitle((runNumber + " Original;;Multiples / Total").data()); + hOriginalMultiplesRatio->Divide(&hOriginalTotal); + + hSkimmedSinglesRatio = reinterpret_cast(hSkimmedSingles.Clone("hSkimmedSinglesRatio")); + hSkimmedSinglesRatio->SetTitle((runNumber + " Skimmed;;Singles / Total").data()); + hSkimmedSinglesRatio->Divide(&hSkimmedTotal); + hSkimmedDoublesRatio = reinterpret_cast(hSkimmedDoubles.Clone("hSkimmedDoublesRatio")); + hSkimmedDoublesRatio->SetTitle((runNumber + " Skimmed;;Doubles / Total").data()); + hSkimmedDoublesRatio->Divide(&hSkimmedTotal); + hSkimmedMultiplesRatio = reinterpret_cast(hSkimmedMultiples.Clone("hSkimmedMultiplesRatio")); + hSkimmedMultiplesRatio->SetTitle((runNumber + " Skimmed;;Multiples / Total").data()); + hSkimmedMultiplesRatio->Divide(&hSkimmedTotal); + + TFile fout(outputFileName, "UPDATE"); + fout.cd(); + TDirectory* dir = fout.mkdir(runNumber.data()); + dir->cd(); + hTriggerEff->Write(); + hTriggerMatchesRatio.Write(); + hTriggerSingleMatchesRatio.Write(); + hDiffBCAO2D.Write(); + hDiffBCEvSel.Write(); + hNumMatchesInSkimmed.Write(); + if (bcDiffTolerance > 0) { + hDiffBC.Write(); + } + TDirectory* dirextra = dir->mkdir("ExtraQA"); + dirextra->cd(); + hOriginalTotal.Write(); + hOriginalSingles.Write(); + hOriginalDoubles.Write(); + hOriginalMultiples.Write(); + hOriginalSinglesRatio->Write(); + hOriginalDoublesRatio->Write(); + hOriginalMultiplesRatio->Write(); + hSkimmedTotal.Write(); + hSkimmedSingles.Write(); + hSkimmedDoubles.Write(); + hSkimmedMultiples.Write(); + hSkimmedSinglesRatio->Write(); + hSkimmedDoublesRatio->Write(); + hSkimmedMultiplesRatio->Write(); + hMatchesSameBCAO2DRatio.Write(); + hMatchesSameBCEvSelRatio.Write(); + fout.Close(); + + // Do checks for trigger + for (int trgID = 0; trgID < labels.size(); trgID++) { + // if (trgID == 77 || trgID == 78 || trgID == 79) { + // checkBCForSelectedTrg(originalAllFrames[trgID], skimmedAllFrames[trgID], runNumber, labels[trgID]); + //} + } +} diff --git a/EventFiltering/macros/checkSkimming.C b/EventFiltering/macros/checkSkimming.C index ebad6a0b107..5496f303873 100644 --- a/EventFiltering/macros/checkSkimming.C +++ b/EventFiltering/macros/checkSkimming.C @@ -8,51 +8,51 @@ // 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. -// O2 includes// 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. -// O2 includes #include #include #include +#include +#include #include #include #include +#include -void checkSkimming(std::string original_path = "AnalysisResults.root", std::string skimmed_path = "AnalysisResults_skimmed.root") +void checkSkimming(std::string original_path = "AnalysisResults.root", std::string skimmed_path = "AnalysisResults_skimmed.root", TFile* outputFile = nullptr, bool skipDownscaled = true) { - // Define the labels to be compared (only triggers not downscaled) + gStyle->SetOptStat(0); + std::string runNumber = ""; + std::regex re("/5[0-9]*"); + std::smatch match; + if (std::regex_search(original_path, match, re)) { + // Remove the leading '/' + runNumber = match.str().substr(1); + } // Load the root files TFile file1(original_path.c_str()); TFile file2(skimmed_path.c_str()); // Extract the histograms - TH1* hist1 = dynamic_cast(file1.Get("central-event-filter-task/scalers/mFiltered;1")); // Replace with the correct path - TH1* hist2 = dynamic_cast(file2.Get("central-event-filter-task/scalers/mScalers;1")); // Replace with the correct path + TH1* hist0 = dynamic_cast(file1.Get("central-event-filter-task/scalers/mScalers;1")); + TH1* hist1 = dynamic_cast(file1.Get("central-event-filter-task/scalers/mFiltered;1")); + TH1* hist2 = dynamic_cast(file2.Get("central-event-filter-task/scalers/mScalers;1")); + + if (!hist0 || !hist1 || !hist2) { + std::cerr << "Error: Failed to extract histograms from the root files." << std::endl; + return; + } std::vector labels; for (int i = 1; i <= hist1->GetNbinsX(); i++) { std::string label = hist1->GetXaxis()->GetBinLabel(i); - if (label != "Total number of events" && label != "Filtered events") { + if (label != "Total number of events" && label != "Filtered events" && (!skipDownscaled || hist0->GetBinContent(i) == hist1->GetBinContent(i)) && hist0->GetBinContent(i) > 0) { labels.push_back(label); } } - if (!hist1 || !hist2) { - std::cerr << "Error: Failed to extract histograms from the root files." << std::endl; - return; - } - // Find the bins corresponding to the desired labels std::vector selected_bins1, selected_bins2; for (auto lab : labels) { @@ -71,26 +71,62 @@ void checkSkimming(std::string original_path = "AnalysisResults.root", std::stri selected_bins2.push_back(hist2->GetBinContent(bin2)); } - TFile output("output.root", "RECREATE"); - TH1D* hOriginal = new TH1D("hOriginal", "Original AO2D;;Number of events", labels.size(), 0, labels.size()); // Histogram for the original values - TH1D* hSkimmed = new TH1D("hSkimmed", "AO2D from skimmed CTF;;Number of events", labels.size(), 0, labels.size()); // Histogram for the skimmed values - TH1D* hRatio = new TH1D("hRatio", ";;Skimmed / Original", labels.size(), 0, labels.size()); // Histogram for the ratio of the two + bool localFile = !outputFile; + if (!outputFile) { + outputFile = new TFile("output.root", "RECREATE"); + } + if (!runNumber.empty()) { + outputFile->mkdir(runNumber.data()); + } + outputFile->cd(runNumber.data()); + + TH1D hOriginal("hOriginal", "Original AO2D;;Number of events", labels.size(), 0, labels.size()); // Histogram for the original values + TH1D hSkimmed("hSkimmed", "AO2D from skimmed CTF;;Number of events", labels.size(), 0, labels.size()); // Histogram for the skimmed values + TH1D hRatio("hRatio", (runNumber + ";;Skimmed / Original").data(), labels.size(), 0, labels.size()); // Histogram for the ratio of the two // Fill the histograms for (int i = 0; i < labels.size(); i++) { - hOriginal->SetBinContent(i + 1, selected_bins1[i]); - hSkimmed->SetBinContent(i + 1, selected_bins2[i]); - hOriginal->GetXaxis()->SetBinLabel(i + 1, labels[i].c_str()); - hSkimmed->GetXaxis()->SetBinLabel(i + 1, labels[i].c_str()); + hOriginal.SetBinContent(i + 1, selected_bins1[i]); + hSkimmed.SetBinContent(i + 1, selected_bins2[i]); + hOriginal.GetXaxis()->SetBinLabel(i + 1, labels[i].c_str()); + hSkimmed.GetXaxis()->SetBinLabel(i + 1, labels[i].c_str()); + hRatio.GetXaxis()->SetBinLabel(i + 1, labels[i].c_str()); + hRatio.SetBinContent(i + 1, selected_bins2[i] / selected_bins1[i]); + } + hOriginal.Write(); + hSkimmed.Write(); + hRatio.Write(); - if (selected_bins1[i] < 1. || labels[i].find("Single") != std::string::npos || labels[i].find("Low") != std::string::npos || labels[i].find("Pt3P") != std::string::npos) { - hRatio->GetXaxis()->SetBinLabel(i + 1, "Disabled"); - continue; - } - hRatio->GetXaxis()->SetBinLabel(i + 1, labels[i].c_str()); - hRatio->SetBinContent(i + 1, selected_bins2[i] / selected_bins1[i]); + if (localFile) { + outputFile->Close(); } - hOriginal->Write(); - hSkimmed->Write(); - hRatio->Write(); } + +void checkSkimming(std::string listName = "period.txt", bool skipDownscaled = true) +{ + std::string periodName = listName.substr(0, listName.find_last_of('.')); + std::ifstream file(listName); + std::string line; + TFile* outputFile = new TFile((periodName + ".root").data(), "RECREATE"); + TCanvas c1("c1", "c1", 800, 600); + c1.SetGridy(); + int lineCounter = 0; + while (std::getline(file, line)) { + lineCounter++; + } + file.clear(); + file.seekg(0, std::ios::beg); + int counter = 0; + while (std::getline(file, line)) { + size_t pos = line.find(","); + std::string original_path = line.substr(0, pos); + std::string skimmed_path = line.substr(pos + 1); + checkSkimming(original_path, skimmed_path, outputFile, skipDownscaled); + TH1* hRatio = (TH1*)gDirectory->Get("hRatio"); + hRatio->Draw(); + std::string suffix = counter == 0 ? "(" : (counter == lineCounter - 1 ? ")" : ""); + c1.Print((periodName + ".pdf" + suffix).data()); + counter++; + } + outputFile->Close(); +} \ No newline at end of file diff --git a/EventFiltering/macros/selectivityPlot.C b/EventFiltering/macros/selectivityPlot.C new file mode 100644 index 00000000000..56215bcd3e6 --- /dev/null +++ b/EventFiltering/macros/selectivityPlot.C @@ -0,0 +1,90 @@ +// 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. + +void selectivityPlot(int runNumber = 550781, TString inputfile = "AnalysisResults_550781.root", TString outputfolder = "") +{ + TCanvas* Canvas_1 = new TCanvas("Canvas_1", "Canvas_1", 928, 592); + gStyle->SetOptFit(0); + gStyle->SetOptStat(0); + Canvas_1->Range(-6.079755, -8.734506, 67.09509, -2.808365); + Canvas_1->SetFillColor(0); + Canvas_1->SetBorderMode(0); + Canvas_1->SetBorderSize(2); + Canvas_1->SetLogy(); + Canvas_1->SetGridx(); + Canvas_1->SetGridy(); + Canvas_1->SetTickx(1); + Canvas_1->SetTicky(1); + Canvas_1->SetLeftMargin(0.08991826); + Canvas_1->SetRightMargin(0.02179836); + Canvas_1->SetTopMargin(0.05); + Canvas_1->SetBottomMargin(0.2711864); + Canvas_1->SetFrameBorderMode(0); + Canvas_1->SetFrameBorderMode(0); + + TFile* file = new TFile(inputfile.Data()); + TH1D* mFiltered = (TH1D*)file->Get("central-event-filter-task/scalers/mFiltered"); + double nEvents = mFiltered->GetBinContent(1); + mFiltered->Scale(1. / nEvents); + mFiltered->SetLineColor(2); + mFiltered->SetLineWidth(2); + mFiltered->SetMarkerColor(2); + mFiltered->SetMarkerStyle(4); + mFiltered->SetMarkerSize(0.6); + mFiltered->GetXaxis()->SetRange(2, mFiltered->GetXaxis()->GetNbins()); + for (int i = 1; i <= mFiltered->GetNbinsX(); i++) { + std::string label = mFiltered->GetXaxis()->GetBinLabel(i); + if (label[0] == 'f') { + mFiltered->GetXaxis()->SetBinLabel(i, label.substr(1).c_str()); + } + mFiltered->SetBinContent(i, mFiltered->GetBinContent(i) / mFiltered->GetBinContent(1)); + mFiltered->SetBinError(i, mFiltered->GetBinError(i) / mFiltered->GetBinContent(1)); + } + mFiltered->GetXaxis()->SetBinLabel(mFiltered->GetNbinsX(), "Total"); + mFiltered->GetXaxis()->SetLabelFont(42); + mFiltered->GetXaxis()->SetTitleOffset(1); + mFiltered->GetXaxis()->SetTitleFont(42); + mFiltered->GetYaxis()->SetTitle("Async. trigger selectivity"); + mFiltered->GetYaxis()->SetLabelFont(42); + mFiltered->GetYaxis()->SetTitleFont(42); + mFiltered->GetZaxis()->SetLabelFont(42); + mFiltered->GetZaxis()->SetTitleOffset(1); + mFiltered->GetZaxis()->SetTitleFont(42); + mFiltered->DrawClone(""); + TLine* line = new TLine(mFiltered->GetXaxis()->GetBinLowEdge(2), 5.e-05, mFiltered->GetXaxis()->GetBinLowEdge(mFiltered->GetNbinsX()), 5.e-05); + line->SetLineStyle(2); + line->Draw(); + TArrow* arrow = new TArrow(mFiltered->GetXaxis()->GetXmax(), 0.0005, mFiltered->GetXaxis()->GetXmax() + 1, 0.0005, 0.01, "<|"); + + Int_t ci; // for color index setting + TColor* color; // for color definition with alpha + ci = TColor::GetColor("#0000ff"); + arrow->SetFillColor(ci); + arrow->SetFillStyle(1001); + TLatex* tex = new TLatex(); + tex->SetTextSize(0.035); + tex->SetTextFont(42); + tex->DrawLatexNDC(0.09, 0.96, Form("ALICE Internal, pp #sqrt{s} = 13.6 TeV, Run %d, #it{L}_{int} #approx %.1f nb^{-1}", runNumber, nEvents / 78.e6)); + ci = TColor::GetColor("#0000ff"); + arrow->SetLineColor(ci); + arrow->Draw(); + Canvas_1->Modified(); + Canvas_1->SetSelected(Canvas_1); + + if (outputfolder.IsNull()) { + return; + } + gROOT->SetBatch(true); + TCanvas Canvas_2("Canvas_2", "Canvas_2", Canvas_1->GetWw() * 2, Canvas_1->GetWh() * 2); + Canvas_1->DrawClonePad(); + Canvas_2.SaveAs(Form("%s/asyncTriggerSelectivity_%d.png", outputfolder.Data(), runNumber)); + gROOT->SetBatch(false); +} diff --git a/EventFiltering/macros/uploadOTSobjects.C b/EventFiltering/macros/uploadOTSobjects.C new file mode 100644 index 00000000000..2a9be2de17e --- /dev/null +++ b/EventFiltering/macros/uploadOTSobjects.C @@ -0,0 +1,142 @@ +// 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. +// + +#include +#include +#include +#include +#include +#include +#include + +#include "TFile.h" +#include "TGrid.h" +#include "TH1.h" +#include "TKey.h" +#include "TSystem.h" +#include "TTree.h" + +#include "CCDB/BasicCCDBManager.h" +#include "EventFiltering/ZorroHelper.h" +#include "CommonConstants/LHCConstants.h" + +constexpr uint32_t chunkSize = 1000000; + +void uploadOTSobjects(std::string inputList, std::string passName, bool useAlien, bool chunkedProcessing) +{ + const std::string kBaseCCDBPath = "Users/m/mpuccio/EventFiltering/OTS/"; + std::string baseCCDBpath = passName.empty() ? kBaseCCDBPath : kBaseCCDBPath + passName + "/"; + if (chunkedProcessing) { + baseCCDBpath += "Chunked/"; + } + if (useAlien) { + TGrid::Connect("alien://"); + } + o2::ccdb::CcdbApi api; + api.init("http://alice-ccdb.cern.ch"); + auto& ccdb = o2::ccdb::BasicCCDBManager::instance(); + + std::ifstream file(inputList.data()); + std::string path; + std::map metadata; + while (std::getline(file, path)) { + auto pos = path.find("/5") + 1; /// in the path at some point there is the run number + const std::string runString = path.substr(pos, 6); + std::cout << "Processing run " << runString << std::endl; + const int runNumber = std::stoi(runString); + metadata["runNumber"] = runString; + std::pair duration = o2::ccdb::BasicCCDBManager::getRunDuration(api, runNumber); + duration.first -= 60000; // subtract 1 minutes from the run start + duration.second += 60000; // add 1 minutes to the run duration + std::cout << ">>> Begin - end timestamps for the upload: " << duration.first << " - " << duration.second << std::endl; + auto ctp = ccdb.getForTimeStamp>("CTP/Calib/OrbitReset", duration.first / 2 + duration.second / 2); + auto orbitResetTimestamp = (*ctp)[0]; + path = useAlien ? "alien://" + path : path; + std::unique_ptr scalersFile{TFile::Open((path + "/AnalysisResults_fullrun.root").data(), "READ")}; + TH1* scalers = static_cast(scalersFile->Get("central-event-filter-task/scalers/mScalers")); + TH1* filters = static_cast(scalersFile->Get("central-event-filter-task/scalers/mFiltered")); + api.storeAsTFile(scalers, baseCCDBpath + "FilterCounters", metadata, duration.first, duration.second + 1); + api.storeAsTFile(filters, baseCCDBpath + "SelectionCounters", metadata, duration.first, duration.second + 1); + TH1* hCounterTVX = static_cast(scalersFile->Get("bc-selection-task/hCounterTVX")); + api.storeAsTFile(hCounterTVX, baseCCDBpath + "InspectedTVX", metadata, duration.first, duration.second + 1); + + std::vector zorroHelpers; + std::unique_ptr bcRangesFile{TFile::Open((path + "/bcRanges_fullrun.root").data(), "READ")}; + int Nmax = 0; + for (auto key : *(bcRangesFile->GetListOfKeys())) { + TTree* cefpTree = static_cast(bcRangesFile->Get(Form("%s/selectedBC", key->GetName()))); + if (!cefpTree) + continue; + ZorroHelper bci; + cefpTree->SetBranchAddress("bcAO2D", &bci.bcAOD); + cefpTree->SetBranchAddress("bcEvSel", &bci.bcEvSel); + if (cefpTree->GetBranch("selMask") && cefpTree->GetBranch("triMask")) { + cefpTree->SetBranchAddress("selMask", &bci.selMask[0]); + cefpTree->SetBranchAddress("triMask", &bci.trigMask[0]); + } else { + cefpTree->SetBranchAddress("selMask0", &bci.selMask[0]); + cefpTree->SetBranchAddress("triMask0", &bci.trigMask[0]); + cefpTree->SetBranchAddress("selMask1", &bci.selMask[1]); + cefpTree->SetBranchAddress("triMask1", &bci.trigMask[1]); + } + for (int i = 0; i < cefpTree->GetEntries(); i++) { + if ((i < Nmax) || (Nmax == 0)) { + cefpTree->GetEntry(i); + zorroHelpers.push_back(bci); + } + } + } + std::sort(zorroHelpers.begin(), zorroHelpers.end(), [](const ZorroHelper& a, const ZorroHelper& b) { + return a.bcAOD < b.bcAOD; + }); + if (!chunkedProcessing) { + api.storeAsTFileAny(&zorroHelpers, baseCCDBpath + "ZorroHelpers", metadata, duration.first, duration.second + 1); + std::cout << std::endl; + } else { + uint32_t helperIndex{0}; + auto startTS = duration.first; + int64_t endTS = 0; + while (helperIndex < zorroHelpers.size()) { + std::vector chunk; + uint32_t endIndex = helperIndex + chunkSize; + while (true) { + if (endIndex >= zorroHelpers.size() - 2) { + endTS = duration.second; + chunk.insert(chunk.begin(), zorroHelpers.begin() + helperIndex, zorroHelpers.end()); + break; + } + auto bcEnd{zorroHelpers[endIndex].bcAOD > zorroHelpers[endIndex].bcEvSel ? zorroHelpers[endIndex].bcAOD : zorroHelpers[endIndex].bcEvSel}; + const auto& nextHelper = zorroHelpers[endIndex + 1]; + auto bcNext{nextHelper.bcAOD < nextHelper.bcEvSel ? nextHelper.bcAOD : nextHelper.bcEvSel}; + if (bcNext - bcEnd > 2001 / o2::constants::lhc::LHCBunchSpacingMUS) { /// ensure a gap of 2ms between chunks + chunk.insert(chunk.begin(), zorroHelpers.begin() + helperIndex, zorroHelpers.begin() + endIndex + 1); + endTS = (orbitResetTimestamp + int64_t(bcEnd * o2::constants::lhc::LHCBunchSpacingNS * 1e-3)) / 1000 + 1; + break; + } + bcEnd = nextHelper.bcAOD > nextHelper.bcEvSel ? nextHelper.bcAOD : nextHelper.bcEvSel; + endIndex++; + } + std::cout << ">>> Chunk " << helperIndex << " - " << helperIndex + chunk.size() << " : " << startTS << " - " << endTS << " \t" << (endTS - startTS) * 1.e-3 << std::endl; + api.storeAsTFileAny(&chunk, baseCCDBpath + "ZorroHelpers", metadata, startTS, endTS + 1); + startTS = endTS + 1; + helperIndex += chunk.size(); + } + } + } +} + +void uploadOTSobjects(std::string periodName, bool chunkedProcessing) +{ + int year = 2000 + std::stoi(periodName.substr(3, 2)); + gSystem->Exec(Form("alien_find /alice/data/%i/%s/ ctf_skim_full/AnalysisResults_fullrun.root | sed 's:/AnalysisResults_fullrun\\.root::' > list_%s.txt", year, periodName.data(), periodName.data())); + uploadOTSobjects(Form("list_%s.txt", periodName.data()), "", true, chunkedProcessing); +} diff --git a/EventFiltering/selectBCRange.cxx b/EventFiltering/selectBCRange.cxx index eabdb3db004..8a2d200e8e6 100644 --- a/EventFiltering/selectBCRange.cxx +++ b/EventFiltering/selectBCRange.cxx @@ -49,13 +49,13 @@ struct BCRangeSelector { void run(ProcessingContext& pc) { - auto bcConsumer = pc.inputs().get(aod::MetadataTrait>::metadata::tableLabel()); + auto bcConsumer = pc.inputs().get(o2::soa::getTableLabel()); auto bcTable{bcConsumer->asArrowTable()}; - auto collConsumer = pc.inputs().get(aod::MetadataTrait>::metadata::tableLabel()); + auto collConsumer = pc.inputs().get(o2::soa::getTableLabel()); auto collTable{collConsumer->asArrowTable()}; - auto evSelConsumer = pc.inputs().get(aod::MetadataTrait>::metadata::tableLabel()); + auto evSelConsumer = pc.inputs().get(o2::soa::getTableLabel()); auto evSelTable{evSelConsumer->asArrowTable()}; - auto cefpConsumer = pc.inputs().get(aod::MetadataTrait>::metadata::tableLabel()); + auto cefpConsumer = pc.inputs().get(o2::soa::getTableLabel()); auto cefpTable{cefpConsumer->asArrowTable()}; auto bcs = aod::BCs({bcTable}); diff --git a/PWGCF/Core/AnalysisConfigurableCuts.h b/PWGCF/Core/AnalysisConfigurableCuts.h index f40f0e7cd5b..886d78c95fe 100644 --- a/PWGCF/Core/AnalysisConfigurableCuts.h +++ b/PWGCF/Core/AnalysisConfigurableCuts.h @@ -86,27 +86,28 @@ class TrackSelectionCfg ClassDefNV(TrackSelectionCfg, 1); }; -/// \brief Simple class for fine tuning a track selection object -/// The tune is done after the actual track selection has ben performed -/// Take into consideration that only more restrictive tunes are supported -/// For more relaxed tunes the whole track selection object must be modified +/// \brief Simple class for configuring the fine tuning a track selection object +/// The tune should change the track selection objects and probably do further checks +/// after the actual track selection has ben performed class TrackSelectionTuneCfg { public: - bool mUseIt = false; ///< use this track selection tuning configuration - int mTPCclusters = 0; ///< minimum number of TPC clusters - bool mUseTPCclusters = false; ///< use or not the number of TPC clusters - int mTPCxRows = 70; ///< minimum number of TPC crossed rows - bool mUseTPCxRows = false; ///< use or not the number of TPC crossed rows - float mTPCXRoFClusters = 0.8; ///< minimum value of the TPC ratio no of crossed rows over findable clusters - bool mUseTPCXRoFClusters = false; ///< use or not the TPC ration of no of crossed rows over findable clusters - float mDCAxy = 2.4; ///< maximum DCA on xy plane - bool mUseDCAxy = false; ///< use or not the maximum DCA on the xy plane - float mDCAz = 3.2; ///< maximum DCA on z axis - bool mUseDCAz = false; ///< use or not the maximum DCA on z asis + bool mUseIt = false; ///< use this track selection tuning configuration + int mTPCclusters = 0; ///< minimum number of TPC clusters + bool mUseTPCclusters = false; ///< use or not the number of TPC clusters + int mTPCxRows = 70; ///< minimum number of TPC crossed rows + bool mUseTPCxRows = false; ///< use or not the number of TPC crossed rows + float mTPCXRoFClusters = 0.8; ///< minimum value of the TPC ratio no of crossed rows over findable clusters + bool mUseTPCXRoFClusters = false; ///< use or not the TPC ratio of no of crossed rows over findable clusters + float mFractionTpcSharedClusters = 0.4; ///< the maximum fraction of TPC shared clusters + bool mUseFractionTpcSharedClusters = false; ///< use or not the fraction of TPC share clusters + float mDCAxy = 2.4; ///< maximum DCA on xy plane + bool mUseDCAxy = false; ///< use or not the maximum DCA on the xy plane + float mDCAz = 3.2; ///< maximum DCA on z axis + bool mUseDCAz = false; ///< use or not the maximum DCA on z asis private: - ClassDefNV(TrackSelectionTuneCfg, 1); + ClassDefNV(TrackSelectionTuneCfg, 2); }; /// \brief Simple class to configure a selection based on PID @@ -124,8 +125,10 @@ class TrackSelectionPIDCfg std::vector mMaxNSigmasTOF = {0.0f, 0.0f, 3.0f, 3.0f, 3.0f}; ///< nsigmas TOF upper limit for e, mu, pi, Ka, and p bool m2Dcut = true; ///< use an elliptic cut using TPC and TOF nsigmas bool mExclude = false; ///< should the identified track be excluded for analysis? + float mPtMin = 0.2; ///< increase the lower pT limit for this species + float mPtMax = 2.0; ///< decrease the upper pT limit for this species private: - ClassDefNV(TrackSelectionPIDCfg, 1); + ClassDefNV(TrackSelectionPIDCfg, 2); }; class SimpleInclusiveCut : public TNamed diff --git a/PWGCF/DataModel/CorrelationsDerived.h b/PWGCF/DataModel/CorrelationsDerived.h index d690518012a..fcaf300c2f3 100644 --- a/PWGCF/DataModel/CorrelationsDerived.h +++ b/PWGCF/DataModel/CorrelationsDerived.h @@ -11,6 +11,8 @@ #ifndef PWGCF_DATAMODEL_CORRELATIONSDERIVED_H_ #define PWGCF_DATAMODEL_CORRELATIONSDERIVED_H_ +#include + #include "Framework/ASoA.h" #include "Framework/AnalysisDataModel.h" #include "Common/DataModel/Centrality.h" @@ -83,6 +85,8 @@ using CFTrackWithLabel = CFTracksWithLabel::iterator; //------transient CF-filter to CF-2prong-filter DECLARE_SOA_TABLE(CFCollRefs, "AOD", "CFCOLLREF", o2::soa::Index<>, track::CollisionId); //! Transient cf collision index table +// Reco + using CFCollRef = CFCollRefs::iterator; namespace cftrackref @@ -92,6 +96,16 @@ DECLARE_SOA_INDEX_COLUMN(Track, track); DECLARE_SOA_TABLE(CFTrackRefs, "AOD", "CFTRACKREF", o2::soa::Index<>, track::CollisionId, cftrackref::TrackId); //! Transient cf track index table using CFTrackRef = CFTrackRefs::iterator; + +// MC + +namespace cfmcparticleref +{ +DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); +} // namespace cfmcparticleref +DECLARE_SOA_TABLE(CFMcParticleRefs, "AOD", "CFMCPARTICLEREF", o2::soa::Index<>, mcparticle::McCollisionId, cfmcparticleref::McParticleId); //! Transient cf track index table + +using CFMcParticleRef = CFMcParticleRefs::iterator; //------ namespace cf2prongtrack @@ -107,7 +121,8 @@ enum ParticleDecay { D0ToPiK, D0barToKPi, JPsiToEE, - JPsiToMuMu + JPsiToMuMu, + Generic2Prong, }; } // namespace cf2prongtrack DECLARE_SOA_TABLE(CF2ProngTracks, "AOD", "CF2PRONGTRACK", //! Reduced track table @@ -117,6 +132,31 @@ DECLARE_SOA_TABLE(CF2ProngTracks, "AOD", "CF2PRONGTRACK", //! Reduced track tabl cf2prongtrack::CFTrackProng1Id, cf2prongtrack::Pt, cf2prongtrack::Eta, cf2prongtrack::Phi, cf2prongtrack::InvMass, cf2prongtrack::Decay); using CF2ProngTrack = CF2ProngTracks::iterator; +//------ + +namespace cf2prongtrackml +{ +DECLARE_SOA_COLUMN(MlProbD0, mlProbD0, std::vector); //! +DECLARE_SOA_COLUMN(MlProbD0bar, mlProbD0bar, std::vector); //! +} // namespace cf2prongtrackml +DECLARE_SOA_TABLE(CF2ProngTrackmls, "AOD", "CF2PRONGTRACKML", //! Reduced track table + o2::soa::Index<>, + cftrack::CFCollisionId, + cf2prongtrackml::MlProbD0, cf2prongtrackml::MlProbD0bar); +using CF2ProngTrackml = CF2ProngTrackmls::iterator; +//------ + +namespace cf2prongmcpart +{ +DECLARE_SOA_INDEX_COLUMN_FULL(CFParticleDaugh0, cfParticleDaugh0, int, CFMcParticles, "_0"); //! Index to prong 1 CFMcParticle +DECLARE_SOA_INDEX_COLUMN_FULL(CFParticleDaugh1, cfParticleDaugh1, int, CFMcParticles, "_1"); //! Index to prong 2 CFMcParticle +} // namespace cf2prongmcpart +DECLARE_SOA_TABLE(CF2ProngMcParts, "AOD", "CF2PRONGMCPART", //! Table for the daughter particles of a 2-prong particle, to be joined with CFMcParticles + o2::soa::Index<>, + cf2prongmcpart::CFParticleDaugh0Id, + cf2prongmcpart::CFParticleDaugh1Id) +using CF2ProngMcPart = CF2ProngMcParts::iterator; + } // namespace o2::aod #endif // PWGCF_DATAMODEL_CORRELATIONSDERIVED_H_ diff --git a/PWGCF/DataModel/FemtoDerived.h b/PWGCF/DataModel/FemtoDerived.h index 4475cedc414..f7083c100a5 100644 --- a/PWGCF/DataModel/FemtoDerived.h +++ b/PWGCF/DataModel/FemtoDerived.h @@ -16,6 +16,9 @@ #include "Framework/ASoA.h" #include "MathUtils/Utils.h" #include "Framework/DataTypes.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" #include "Common/DataModel/Multiplicity.h" #include "Framework/AnalysisDataModel.h" #include "Framework/Expressions.h" @@ -49,13 +52,13 @@ DECLARE_SOA_COLUMN(BitMaskTrackThree, bitmaskTrackThree, BitMaskType); //! Bit f DECLARE_SOA_COLUMN(Downsample, downsample, bool); //! Flag for downsampling } // namespace femtodreamcollision -DECLARE_SOA_TABLE(FDCollisions, "AOD", "FDCOLLISION", - o2::soa::Index<>, - o2::aod::collision::PosZ, - femtodreamcollision::MultV0M, - femtodreamcollision::MultNtr, - femtodreamcollision::Sphericity, - femtodreamcollision::MagField); +DECLARE_SOA_TABLE_STAGED(FDCollisions, "FDCOLLISION", + o2::soa::Index<>, + o2::aod::collision::PosZ, + femtodreamcollision::MultV0M, + femtodreamcollision::MultNtr, + femtodreamcollision::Sphericity, + femtodreamcollision::MagField); using FDCollision = FDCollisions::iterator; DECLARE_SOA_TABLE(FDColMasks, "AOD", "FDCOLMASK", @@ -71,27 +74,30 @@ namespace femtodreamMCcollision DECLARE_SOA_COLUMN(MultMCgenPartEta08, multMCgenPartEta08, int); //! Multiplicity of the event as given by the generator in |eta|<0.8 } -DECLARE_SOA_TABLE(FDMCCollisions, "AOD", "FDMCCOLLISION", - o2::soa::Index<>, - femtodreamMCcollision::MultMCgenPartEta08); +DECLARE_SOA_TABLE_STAGED(FDMCCollisions, "FDMCCOLLISION", + o2::soa::Index<>, + femtodreamMCcollision::MultMCgenPartEta08); using FDMCCollision = FDMCCollisions::iterator; namespace mcfdcolllabel { DECLARE_SOA_INDEX_COLUMN(FDMCCollision, fdMCCollision); //! MC collision for femtodreamcollision } -DECLARE_SOA_TABLE(FDMCCollLabels, "AOD", "FDMCCollLabel", mcfdcolllabel::FDMCCollisionId); +DECLARE_SOA_TABLE_STAGED(FDMCCollLabels, "FDMCCollLabel", mcfdcolllabel::FDMCCollisionId); /// FemtoDreamTrack namespace femtodreamparticle { /// Distinuishes the different particle types enum ParticleType { - kTrack, //! Track - kV0, //! V0 - kV0Child, //! Child track of a V0 - kCascade, //! Cascade + kTrack, //! Track + kV0, //! V0 + kV0Child, //! Child track of a V0 + kCascade, //! Cascade + kCascadeV0, + kCascadeV0Child, kCascadeBachelor, //! Bachelor track of a cascade + kCharmHadron, //! Bachelor track of a cascade kNParticleTypes //! Number of particle types }; @@ -101,19 +107,20 @@ enum MomentumType { kPtpc //! momentum at the inner wall of the TPC (useful for PID plots) }; -static constexpr std::string_view ParticleTypeName[kNParticleTypes] = {"Tracks", "V0", "V0Child", "Cascade", "CascadeBachelor"}; //! Naming of the different particle types -static constexpr std::string_view TempFitVarName[kNParticleTypes] = {"/hDCAxy", "/hCPA", "/hDCAxy", "/hCPA", "/hDCAxy"}; +static constexpr std::string_view ParticleTypeName[kNParticleTypes] = {"Tracks", "V0", "V0Child", "Cascade", "CascadeV0", "CascadeV0Child", "CascadeBachelor", "CharmHadron"}; //! Naming of the different particle types +static constexpr std::string_view TempFitVarName[kNParticleTypes] = {"/hDCAxy", "/hCPA", "/hDCAxy", "/hCPA", "/hCPA", "/hDCAxy", "/hDCAxy", "/hCPA"}; using cutContainerType = uint32_t; //! Definition of the data type for the bit-wise container for the different selection criteria enum TrackType { - kNoChild, //! Not a V0 child + kNoChild, //! Not any child kPosChild, //! Positive V0 child kNegChild, //! Negative V0 child + kBachelor, //! Bachelor Cascade child kNTrackTypes //! Number of child types }; -static constexpr std::string_view TrackTypeName[kNTrackTypes] = {"Trk", "Pos", "Neg"}; //! Naming of the different particle types +static constexpr std::string_view TrackTypeName[kNTrackTypes] = {"Trk", "Pos", "Neg", "Bach"}; //! Naming of the different particle types DECLARE_SOA_INDEX_COLUMN(FDCollision, fdCollision); DECLARE_SOA_COLUMN(Pt, pt, float); //! p_T (GeV/c) @@ -133,11 +140,11 @@ DECLARE_SOA_DYNAMIC_COLUMN(Theta, theta, //! Compute the theta of the track }); DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! Compute the momentum in x in GeV/c [](float pt, float phi) -> float { - return pt * std::sin(phi); + return pt * std::cos(phi); }); DECLARE_SOA_DYNAMIC_COLUMN(Py, py, //! Compute the momentum in y in GeV/c [](float pt, float phi) -> float { - return pt * std::cos(phi); + return pt * std::sin(phi); }); DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! Compute the momentum in z in GeV/c [](float pt, float eta) -> float { @@ -162,68 +169,237 @@ DECLARE_SOA_COLUMN(TPCNSigmaPi, tpcNSigmaPi, float); //! Nsigma separation with DECLARE_SOA_COLUMN(TPCNSigmaKa, tpcNSigmaKa, float); //! Nsigma separation with the TPC detector for kaon DECLARE_SOA_COLUMN(TPCNSigmaPr, tpcNSigmaPr, float); //! Nsigma separation with the TPC detector for proton DECLARE_SOA_COLUMN(TPCNSigmaDe, tpcNSigmaDe, float); //! Nsigma separation with the TPC detector for deuteron -DECLARE_SOA_COLUMN(TOFNSigmaEl, tofNSigmaEl, float); //! Nsigma separation with the TPC detector for electron -DECLARE_SOA_COLUMN(TOFNSigmaPi, tofNSigmaPi, float); //! Nsigma separation with the TPC detector for pion -DECLARE_SOA_COLUMN(TOFNSigmaKa, tofNSigmaKa, float); //! Nsigma separation with the TPC detector for kaon -DECLARE_SOA_COLUMN(TOFNSigmaPr, tofNSigmaPr, float); //! Nsigma separation with the TPC detector for proton -DECLARE_SOA_COLUMN(TOFNSigmaDe, tofNSigmaDe, float); //! Nsigma separation with the TPC detector for deuteron +DECLARE_SOA_COLUMN(TPCNSigmaTr, tpcNSigmaTr, float); //! Nsigma separation with the TPC detector for triton +DECLARE_SOA_COLUMN(TPCNSigmaHe, tpcNSigmaHe, float); //! Nsigma separation with the TPC detector for helium3 +DECLARE_SOA_COLUMN(TOFNSigmaEl, tofNSigmaEl, float); //! Nsigma separation with the TOF detector for electron +DECLARE_SOA_COLUMN(TOFNSigmaPi, tofNSigmaPi, float); //! Nsigma separation with the TOF detector for pion +DECLARE_SOA_COLUMN(TOFNSigmaKa, tofNSigmaKa, float); //! Nsigma separation with the TOF detector for kaon +DECLARE_SOA_COLUMN(TOFNSigmaPr, tofNSigmaPr, float); //! Nsigma separation with the TOF detector for proton +DECLARE_SOA_COLUMN(TOFNSigmaDe, tofNSigmaDe, float); //! Nsigma separation with the TOF detector for deuteron +DECLARE_SOA_COLUMN(TOFNSigmaTr, tofNSigmaTr, float); //! Nsigma separation with the TOF detector for triton +DECLARE_SOA_COLUMN(TOFNSigmaHe, tofNSigmaHe, float); //! Nsigma separation with the TOF detector for helium3 +DECLARE_SOA_COLUMN(ITSSignal, itsSignal, float); +DECLARE_SOA_COLUMN(ITSNSigmaEl, itsNSigmaEl, float); //! Nsigma separation with the Its detector for electron +DECLARE_SOA_COLUMN(ITSNSigmaPi, itsNSigmaPi, float); //! Nsigma separation with the Its detector for pion +DECLARE_SOA_COLUMN(ITSNSigmaKa, itsNSigmaKa, float); //! Nsigma separation with the Its detector for kaon +DECLARE_SOA_COLUMN(ITSNSigmaPr, itsNSigmaPr, float); //! Nsigma separation with the Its detector for proton +DECLARE_SOA_COLUMN(ITSNSigmaDe, itsNSigmaDe, float); //! Nsigma separation with the Its detector for deuteron +DECLARE_SOA_COLUMN(ITSNSigmaTr, itsNSigmaTr, float); //! Nsigma separation with the Its detector for triton +DECLARE_SOA_COLUMN(ITSNSigmaHe, itsNSigmaHe, float); //! Nsigma separation with the Its detector for helium3 DECLARE_SOA_COLUMN(DaughDCA, daughDCA, float); //! DCA between daughters DECLARE_SOA_COLUMN(TransRadius, transRadius, float); //! Transverse radius of the decay vertex DECLARE_SOA_COLUMN(DecayVtxX, decayVtxX, float); //! X position of the decay vertex DECLARE_SOA_COLUMN(DecayVtxY, decayVtxY, float); //! Y position of the decay vertex DECLARE_SOA_COLUMN(DecayVtxZ, decayVtxZ, float); //! Z position of the decay vertex DECLARE_SOA_COLUMN(MKaon, mKaon, float); //! The invariant mass of V0 candidate, assuming kaon +// Here the cascade specific collums +DECLARE_SOA_COLUMN(CascV0DCAtoPV, cascV0DCAtoPV, float); //! DCA of the daughter V0 to the primar vertex +DECLARE_SOA_COLUMN(CascDaughDCA, cascDaughDCA, float); //! DCA between daughters +DECLARE_SOA_COLUMN(CascTransRadius, cascTransRadius, float); //! Transverse radius of the decay vertex of the cascade +DECLARE_SOA_COLUMN(CascDecayVtxX, cascDecayVtxX, float); //! X position of the decay vertex of the cascade +DECLARE_SOA_COLUMN(CascDecayVtxY, cascDecayVtxY, float); //! Y position of the decay vertex of the cascade +DECLARE_SOA_COLUMN(CascDecayVtxZ, cascDecayVtxZ, float); //! Z position of the decay vertex of the cascade +DECLARE_SOA_COLUMN(MOmega, mOmega, float); //! The invariant mass of Cascade candidate, assuming Omega } // namespace femtodreamparticle -DECLARE_SOA_TABLE(FDParticles, "AOD", "FDPARTICLE", +namespace fdhf +{ + +enum CharmHadronMassHypo { + wrongParticle = 0, + lcToPKPi = 1, + lcToPiKP = 2 +}; + +DECLARE_SOA_COLUMN(TrackId, trackId, int); //! track id to match associate particle with charm hadron prongs +DECLARE_SOA_COLUMN(Charge, charge, int8_t); //! Charge of charm hadron +DECLARE_SOA_COLUMN(Prong0Id, prong0Id, int); //! Track id of charm hadron prong0 +DECLARE_SOA_COLUMN(Prong1Id, prong1Id, int); //! Track id of charm hadron prong1 +DECLARE_SOA_COLUMN(Prong2Id, prong2Id, int); //! Track id of charm hadron prong2 +DECLARE_SOA_COLUMN(Prong0Pt, prong0Pt, float); //! Track pT of charm hadron prong0 +DECLARE_SOA_COLUMN(Prong1Pt, prong1Pt, float); //! Track pT of charm hadron prong1 +DECLARE_SOA_COLUMN(Prong2Pt, prong2Pt, float); //! Track pT of charm hadron prong2 +DECLARE_SOA_COLUMN(Prong0Eta, prong0Eta, float); //! Track eta of charm hadron prong0 +DECLARE_SOA_COLUMN(Prong1Eta, prong1Eta, float); //! Track eta of charm hadron prong1 +DECLARE_SOA_COLUMN(Prong2Eta, prong2Eta, float); //! Track eta of charm hadron prong2 +DECLARE_SOA_COLUMN(Prong0Phi, prong0Phi, float); //! Track phi of charm hadron prong0 +DECLARE_SOA_COLUMN(Prong1Phi, prong1Phi, float); //! Track phi of charm hadron prong1 +DECLARE_SOA_COLUMN(Prong2Phi, prong2Phi, float); //! Track phi of charm hadron prong2 +DECLARE_SOA_COLUMN(CandidateSelFlag, candidateSelFlag, int8_t); //! Selection of mass hypothesis for charm hadron (1 for Lc -> pkpi, 2 for Lc -> pikp) +DECLARE_SOA_COLUMN(BDTBkg, bdtBkg, float); //! Background score using Boosted Decision Tree for charm hadron +DECLARE_SOA_COLUMN(BDTPrompt, bdtPrompt, float); //! Prompt signal score using Boosted Decision Tree for charm hadron +DECLARE_SOA_COLUMN(BDTFD, bdtFD, float); //! Feed-down score using Boosted Decision Tree for charm hadron +DECLARE_SOA_COLUMN(FlagMc, flagMc, int8_t); //! To select MC particle among charm hadrons, { DplusToPiKPi = 1, LcToPKPi = 2, DsToKKPi = 4, XicToPKP = 8, N3ProngD = 2ecays }; +DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); //! flag for reconstruction level matching (1 for prompt, 2 for non-prompt) +DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! flag for generator level matching (1 for prompt, 2 for non-prompt) +DECLARE_SOA_COLUMN(IsCandidateSwapped, isCandidateSwapped, int8_t); //! swapping of the prongs order (0 for Lc -> pkpi, 1 for Lc -> pikp) +DECLARE_SOA_COLUMN(PtAssoc, ptAssoc, float); //! Transverse momentum of associate femto particle +DECLARE_SOA_COLUMN(Kstar, kstar, float); //! Relative momentum in particles pair frame +DECLARE_SOA_COLUMN(KT, kT, float); //! kT distribution of particle pairs +DECLARE_SOA_COLUMN(MT, mT, float); //! Transverse mass distribution +DECLARE_SOA_COLUMN(CharmM, charmM, float); //! Charm hadron mass +DECLARE_SOA_COLUMN(CharmPt, charmPt, float); //! Transverse momentum of charm hadron for result task +DECLARE_SOA_COLUMN(Mult, mult, int); //! Charge particle multiplicity +DECLARE_SOA_COLUMN(MultPercentile, multPercentile, float); //! Multiplicity precentile +DECLARE_SOA_COLUMN(PairSign, pairSign, int8_t); //! Selection between like sign (1) and unlike sign pair (2) +DECLARE_SOA_COLUMN(ProcessType, processType, int64_t); //! Selection between same-event (1), and mixed-event (2) +DECLARE_SOA_DYNAMIC_COLUMN(M, m, //! + [](float pt0, float phi0, float eta0, float pt1, float phi1, float eta1, float pt2, float phi2, float eta2, const std::array& m) -> float { return RecoDecay::m(std::array{ + RecoDecayPtEtaPhi::pVector(pt0, eta0, phi0), + RecoDecayPtEtaPhi::pVector(pt1, eta1, phi1), + RecoDecayPtEtaPhi::pVector(pt2, eta2, phi2)}, + m); }); //! Charm hadron mass +DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! + [](float pt0, float phi0, float eta0, float pt1, float phi1, float eta1, float pt2, float phi2, float eta2) -> float { return RecoDecay::p(RecoDecay::pVec( + RecoDecayPtEtaPhi::pVector(pt0, eta0, phi0), + RecoDecayPtEtaPhi::pVector(pt1, eta1, phi1), + RecoDecayPtEtaPhi::pVector(pt2, eta2, phi2))); }); //! Momentum of charm hadron +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! + [](float pt0, float phi0, float eta0, float pt1, float phi1, float eta1, float pt2, float phi2, float eta2) -> float { return RecoDecay::pt(RecoDecay::pVec( + RecoDecayPtEtaPhi::pVector(pt0, eta0, phi0), + RecoDecayPtEtaPhi::pVector(pt1, eta1, phi1), + RecoDecayPtEtaPhi::pVector(pt2, eta2, phi2))); }); //! Transverse momentum of charm hadron +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, //! + [](float pt0, float phi0, float eta0, float pt1, float phi1, float eta1, float pt2, float phi2, float eta2) -> float { return RecoDecay::phi(RecoDecay::pVec( + RecoDecayPtEtaPhi::pVector(pt0, eta0, phi0), + RecoDecayPtEtaPhi::pVector(pt1, eta1, phi1), + RecoDecayPtEtaPhi::pVector(pt2, eta2, phi2))); }); //! Phi distribution of charm hadron +DECLARE_SOA_DYNAMIC_COLUMN(Y, y, //! + [](float pt0, float phi0, float eta0, float pt1, float phi1, float eta1, float pt2, float phi2, float eta2) -> float { return RecoDecay::y(RecoDecay::pVec( + RecoDecayPtEtaPhi::pVector(pt0, eta0, phi0), + RecoDecayPtEtaPhi::pVector(pt1, eta1, phi1), + RecoDecayPtEtaPhi::pVector(pt2, eta2, phi2)), + o2::constants::physics::MassLambdaCPlus); }); //! Rapidity distribution of charm hadron +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, //! + [](float pt0, float phi0, float eta0, float pt1, float phi1, float eta1, float pt2, float phi2, float eta2) -> float { return RecoDecay::eta(RecoDecay::pVec( + RecoDecayPtEtaPhi::pVector(pt0, eta0, phi0), + RecoDecayPtEtaPhi::pVector(pt1, eta1, phi1), + RecoDecayPtEtaPhi::pVector(pt2, eta2, phi2))); }); //! Eta distribution of charm hadron + +} // namespace fdhf + +DECLARE_SOA_TABLE(FDHfCand, "AOD", "FDHFCAND", //! Table to store the derived data for charm hadron candidates o2::soa::Index<>, femtodreamparticle::FDCollisionId, - femtodreamparticle::Pt, - femtodreamparticle::Eta, - femtodreamparticle::Phi, - femtodreamparticle::PartType, - femtodreamparticle::Cut, - femtodreamparticle::PIDCut, - femtodreamparticle::TempFitVar, - femtodreamparticle::ChildrenIds, - femtodreamparticle::MLambda, - femtodreamparticle::MAntiLambda, - femtodreamparticle::Theta, - femtodreamparticle::Px, - femtodreamparticle::Py, - femtodreamparticle::Pz, - femtodreamparticle::P); + fdhf::Charge, + fdhf::Prong0Id, + fdhf::Prong1Id, + fdhf::Prong2Id, + fdhf::Prong0Pt, + fdhf::Prong1Pt, + fdhf::Prong2Pt, + fdhf::Prong0Eta, + fdhf::Prong1Eta, + fdhf::Prong2Eta, + fdhf::Prong0Phi, + fdhf::Prong1Phi, + fdhf::Prong2Phi, + fdhf::CandidateSelFlag, + fdhf::BDTBkg, + fdhf::BDTPrompt, + fdhf::BDTFD, + fdhf::M, + fdhf::P, + fdhf::Y, + fdhf::Eta, + fdhf::Phi, + fdhf::Pt); + +DECLARE_SOA_TABLE(FDResultsHF, "AOD", "FDRESULTSHF", //! table to store results for HF femtoscopy + fdhf::CharmM, + fdhf::CharmPt, + fdhf::PtAssoc, + fdhf::BDTBkg, + fdhf::BDTPrompt, + fdhf::BDTFD, + fdhf::Kstar, + fdhf::KT, + fdhf::MT, + fdhf::Mult, + fdhf::MultPercentile, + fdhf::Charge, + fdhf::PairSign, + fdhf::ProcessType, + fdhf::FlagMc, + fdhf::OriginMcRec); + +DECLARE_SOA_TABLE(FDHfCandMC, "AOD", "FDHFCANDMC", //! Table for reconstructed MC charm hadron candidates + o2::soa::Index<>, + fdhf::FlagMc, + fdhf::OriginMcRec); + +DECLARE_SOA_TABLE(FDParticlesIndex, "AOD", "FDPARTICLEINDEX", //! Table track index to match associate particle with charm hadron prongs + o2::soa::Index<>, + fdhf::TrackId); + +DECLARE_SOA_TABLE_STAGED(FDParticles, "FDPARTICLE", + o2::soa::Index<>, + femtodreamparticle::FDCollisionId, + femtodreamparticle::Pt, + femtodreamparticle::Eta, + femtodreamparticle::Phi, + femtodreamparticle::PartType, + femtodreamparticle::Cut, + femtodreamparticle::PIDCut, + femtodreamparticle::TempFitVar, + femtodreamparticle::ChildrenIds, + femtodreamparticle::MLambda, + femtodreamparticle::MAntiLambda, + femtodreamparticle::Theta, + femtodreamparticle::Px, + femtodreamparticle::Py, + femtodreamparticle::Pz, + femtodreamparticle::P); using FDParticle = FDParticles::iterator; -DECLARE_SOA_TABLE(FDExtParticles, "AOD", "FDEXTPARTICLE", - femtodreamparticle::Sign, - femtodreamparticle::TPCNClsFound, - track::TPCNClsFindable, - femtodreamparticle::TPCNClsCrossedRows, - track::TPCNClsShared, - track::TPCInnerParam, - femtodreamparticle::ITSNCls, - femtodreamparticle::ITSNClsInnerBarrel, - track::DcaXY, - track::DcaZ, - track::TPCSignal, - femtodreamparticle::TPCNSigmaEl, - femtodreamparticle::TPCNSigmaPi, - femtodreamparticle::TPCNSigmaKa, - femtodreamparticle::TPCNSigmaPr, - femtodreamparticle::TPCNSigmaDe, - femtodreamparticle::TOFNSigmaEl, - femtodreamparticle::TOFNSigmaPi, - femtodreamparticle::TOFNSigmaKa, - femtodreamparticle::TOFNSigmaPr, - femtodreamparticle::TOFNSigmaDe, - femtodreamparticle::DaughDCA, - femtodreamparticle::TransRadius, - femtodreamparticle::DecayVtxX, - femtodreamparticle::DecayVtxY, - femtodreamparticle::DecayVtxZ, - femtodreamparticle::MKaon, - femtodreamparticle::TPCCrossedRowsOverFindableCls) +DECLARE_SOA_TABLE_STAGED(FDExtParticles, "FDEXTPARTICLE", + femtodreamparticle::Sign, + femtodreamparticle::TPCNClsFound, + track::TPCNClsFindable, + femtodreamparticle::TPCNClsCrossedRows, + track::TPCNClsShared, + track::TPCInnerParam, + femtodreamparticle::ITSNCls, + femtodreamparticle::ITSNClsInnerBarrel, + track::DcaXY, + track::DcaZ, + track::TPCSignal, + femtodreamparticle::TPCNSigmaEl, + femtodreamparticle::TPCNSigmaPi, + femtodreamparticle::TPCNSigmaKa, + femtodreamparticle::TPCNSigmaPr, + femtodreamparticle::TPCNSigmaDe, + femtodreamparticle::TPCNSigmaTr, + femtodreamparticle::TPCNSigmaHe, + femtodreamparticle::TOFNSigmaEl, + femtodreamparticle::TOFNSigmaPi, + femtodreamparticle::TOFNSigmaKa, + femtodreamparticle::TOFNSigmaPr, + femtodreamparticle::TOFNSigmaDe, + femtodreamparticle::TOFNSigmaTr, + femtodreamparticle::TOFNSigmaHe, + femtodreamparticle::ITSSignal, + femtodreamparticle::ITSNSigmaEl, + femtodreamparticle::ITSNSigmaPi, + femtodreamparticle::ITSNSigmaKa, + femtodreamparticle::ITSNSigmaPr, + femtodreamparticle::ITSNSigmaDe, + femtodreamparticle::ITSNSigmaTr, + femtodreamparticle::ITSNSigmaHe, + femtodreamparticle::DaughDCA, + femtodreamparticle::TransRadius, + femtodreamparticle::DecayVtxX, + femtodreamparticle::DecayVtxY, + femtodreamparticle::DecayVtxZ, + femtodreamparticle::MKaon, + femtodreamparticle::CascV0DCAtoPV, + femtodreamparticle::CascDaughDCA, + femtodreamparticle::CascTransRadius, + femtodreamparticle::CascDecayVtxX, + femtodreamparticle::CascDecayVtxY, + femtodreamparticle::CascDecayVtxZ, + femtodreamparticle::MOmega, + femtodreamparticle::TPCCrossedRowsOverFindableCls) using FDFullParticle = FDExtParticles::iterator; /// FemtoDreamTrackMC @@ -239,6 +415,9 @@ enum ParticleOriginMCTruth { kWrongCollision, //! particle, that was associated wrongly to the collision kSecondaryDaughterLambda, //! Daughter from a Lambda decay kSecondaryDaughterSigmaplus, //! Daughter from a Sigma^plus decay + kSecondaryDaughterSigma0, //! Daughter from a Sigma^0 decay + kSecondaryDaughterXiMinus, //! Daughter from a Xi^- decay + kSecondaryDaughterXi0, //! Daughter from a Xi^0 decay kElse, //! none of the above; (NOTE: used to catch bugs. will be removed once MC usage is properly validated) kNOriginMCTruthTypes }; @@ -269,25 +448,25 @@ DECLARE_SOA_COLUMN(PDGMCTruth, pdgMCTruth, int); //! Particle DECLARE_SOA_COLUMN(MotherPDG, motherPDG, int); //! Checks mother PDG, where mother is the primary particle for that decay chain } // namespace femtodreamMCparticle -DECLARE_SOA_TABLE(FDMCParticles, "AOD", "FDMCPARTICLE", - o2::soa::Index<>, - femtodreamMCparticle::PartOriginMCTruth, - femtodreamMCparticle::PDGMCTruth, - femtodreamparticle::Pt, - femtodreamparticle::Eta, - femtodreamparticle::Phi); +DECLARE_SOA_TABLE_STAGED(FDMCParticles, "FDMCPARTICLE", + o2::soa::Index<>, + femtodreamMCparticle::PartOriginMCTruth, + femtodreamMCparticle::PDGMCTruth, + femtodreamparticle::Pt, + femtodreamparticle::Eta, + femtodreamparticle::Phi); using FDMCParticle = FDMCParticles::iterator; -DECLARE_SOA_TABLE(FDExtMCParticles, "AOD", "FDEXTMCPARTICLE", - femtodreamMCparticle::MotherPDG); +DECLARE_SOA_TABLE_STAGED(FDExtMCParticles, "FDEXTMCPARTICLE", + femtodreamMCparticle::MotherPDG); using FDExtMCParticle = FDExtMCParticles::iterator; namespace mcfdlabel { DECLARE_SOA_INDEX_COLUMN(FDMCParticle, fdMCParticle); //! MC particle for femtodreamparticle } // namespace mcfdlabel -DECLARE_SOA_TABLE(FDMCLabels, "AOD", "FDMCLabel", //! Table joinable to FemtoDreamParticle containing the MC labels - mcfdlabel::FDMCParticleId); +DECLARE_SOA_TABLE_STAGED(FDMCLabels, "FDMCLabel", //! Table joinable to FemtoDreamParticle containing the MC labels + mcfdlabel::FDMCParticleId); namespace mcfdextlabel { DECLARE_SOA_INDEX_COLUMN(FDExtMCParticle, fdExtMCParticle); //! MC particle for femtodreamparticle @@ -295,14 +474,24 @@ DECLARE_SOA_INDEX_COLUMN(FDExtMCParticle, fdExtMCParticle); //! MC particle for DECLARE_SOA_TABLE(FDExtMCLabels, "AOD", "FDExtMCLabel", //! Table joinable to FemtoDreamParticle containing the MC labels mcfdextlabel::FDExtMCParticleId); +DECLARE_SOA_TABLE(FDHfCandMCGen, "AOD", "FDHFCANDMCGEN", //! Table for generated MC charm hadron + mcfdlabel::FDMCParticleId, + fdhf::Pt, + fdhf::Eta, + fdhf::Phi, + fdhf::Y, + fdhf::FlagMc, + fdhf::OriginMcGen); + /// Hash namespace hash { DECLARE_SOA_COLUMN(Bin, bin, int); //! Hash for the event mixing } // namespace hash -DECLARE_SOA_TABLE(Hashes, "AOD", "HASH", hash::Bin); -using Hash = Hashes::iterator; +DECLARE_SOA_TABLE(MixingHashes, "AOD", "HASH", hash::Bin); +using MixingHash = MixingHashes::iterator; } // namespace o2::aod #endif // PWGCF_DATAMODEL_FEMTODERIVED_H_ + // diff --git a/PWGCF/DataModel/SPTableZDC.h b/PWGCF/DataModel/SPTableZDC.h new file mode 100644 index 00000000000..fcafff23c90 --- /dev/null +++ b/PWGCF/DataModel/SPTableZDC.h @@ -0,0 +1,57 @@ +// 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 SPTableZDC.h + +#ifndef PWGCF_DATAMODEL_SPTABLEZDC_H_ +#define PWGCF_DATAMODEL_SPTABLEZDC_H_ + +#include + +#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace sptablezdc +{ +DECLARE_SOA_COLUMN(Runnumber, runnumber, int); +DECLARE_SOA_COLUMN(Cent, cent, float); +DECLARE_SOA_COLUMN(Vx, vx, float); +DECLARE_SOA_COLUMN(Vy, vy, float); +DECLARE_SOA_COLUMN(Vz, vz, float); +DECLARE_SOA_COLUMN(QXA, qxA, float); +DECLARE_SOA_COLUMN(QYA, qyA, float); +DECLARE_SOA_COLUMN(QXC, qxC, float); +DECLARE_SOA_COLUMN(QYC, qyC, float); +DECLARE_SOA_COLUMN(IsSelected, isSelected, bool); +DECLARE_SOA_COLUMN(Iteration, iteration, int); +DECLARE_SOA_COLUMN(Step, step, int); + +} // namespace sptablezdc + +DECLARE_SOA_TABLE(SPTableZDC, "AOD", "SPZDC", + sptablezdc::Runnumber, + sptablezdc::Cent, + sptablezdc::Vx, + sptablezdc::Vy, + sptablezdc::Vz, + sptablezdc::QXA, + sptablezdc::QYA, + sptablezdc::QXC, + sptablezdc::QYC, + sptablezdc::IsSelected, + sptablezdc::Iteration, + sptablezdc::Step); +} // namespace o2::aod +#endif // PWGCF_DATAMODEL_SPTABLEZDC_H_ diff --git a/PWGCF/EbyEFluctuations/Tasks/CMakeLists.txt b/PWGCF/EbyEFluctuations/Tasks/CMakeLists.txt index 1332c9ef1dd..1dd4e544331 100644 --- a/PWGCF/EbyEFluctuations/Tasks/CMakeLists.txt +++ b/PWGCF/EbyEFluctuations/Tasks/CMakeLists.txt @@ -15,7 +15,7 @@ o2physics_add_dpl_workflow(meanpt-fluctuations COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(mean-pt-fluc-id - SOURCES MeanPtFlucIdentified.cxx + SOURCES meanPtFlucId.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) @@ -24,6 +24,16 @@ o2physics_add_dpl_workflow(netproton-cumulants PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(netproton-cumulants-mc + SOURCES netprotonCumulantsMc.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(antiproton-cumulants-mc + SOURCES antiprotonCumulantsMc.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(identified-meanpt-fluctuations SOURCES IdentifiedMeanPtFluctuations.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore @@ -43,3 +53,18 @@ o2physics_add_dpl_workflow(factorial-moments SOURCES FactorialMomentsTask.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(kaon-isospin-fluctuations + SOURCES kaonIsospinFluctuations.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(netcharge-fluctuations + SOURCES netchargeFluctuations.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(nch-cumulants-id + SOURCES nchCumulantsId.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/EbyEFluctuations/Tasks/FactorialMomentsTask.cxx b/PWGCF/EbyEFluctuations/Tasks/FactorialMomentsTask.cxx index 6ac38abb077..c76556ec26f 100644 --- a/PWGCF/EbyEFluctuations/Tasks/FactorialMomentsTask.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/FactorialMomentsTask.cxx @@ -16,6 +16,7 @@ #include #include #include +#include "TRandom.h" // O2 includes #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" @@ -28,24 +29,30 @@ #include "ReconstructionDataFormats/GlobalTrackID.h" #include "ReconstructionDataFormats/Track.h" #include "Framework/ASoAHelpers.h" - using std::array; using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; - struct FactorialMoments { - - Configurable confEta{"centralEta", 0.8, "eta limit for tracks"}; + Configurable confEta{"centralEta", 0.9, "eta limit for tracks"}; Configurable confNumPt{"numPt", 1, "number of pT bins"}; Configurable confPtMin{"ptMin", 0.2f, "lower pT cut"}; Configurable confDCAxy{"dcaXY", 2.4f, "DCA xy cut"}; - Configurable confDCAz{"dcaZ", 3.2f, "DCA z cut"}; + Configurable confDCAz{"dcaZ", 2.0f, "DCA z cut"}; Configurable confMinTPCCls{"minTPCCls", 70.0f, "minimum number of TPC clusters"}; Configurable> confCentCut{"centLimits", {0, 5}, "centrality min and max"}; Configurable> confVertex{"vertexXYZ", {0.3f, 0.4f, 10.0f}, "vertex cuts"}; Configurable> confPtBins{"ptCuts", {0.2f, 2.0f}, "pT cuts"}; - + Configurable IsApplySameBunchPileup{"IsApplySameBunchPileup", true, "Enable SameBunchPileup cut"}; + Configurable IsApplyGoodZvtxFT0vsPV{"IsApplyGoodZvtxFT0vsPV", true, "Enable GoodZvtxFT0vsPV cut"}; + Configurable IsApplyVertexITSTPC{"IsApplyVertexITSTPC", true, "Enable VertexITSTPC cut"}; + Configurable IsApplyVertexTOFmatched{"IsApplyVertexTOFmatched", true, "Enable VertexTOFmatched cut"}; + Configurable IsApplyVertexTRDmatched{"IsApplyVertexTRDmatched", true, "Enable VertexTRDmatched cut"}; + Configurable IsApplyExtraCorrCut{"IsApplyExtraCorrCut", false, "Enable extra NPVtracks vs FTOC correlation cut"}; + Configurable IsApplyExtraPhiCut{"IsApplyExtraPhiCut", false, "Enable extra phi cut"}; + Configurable includeGlobalTracks{"includeGlobalTracks", false, "Enable Global Tracks"}; + Configurable includeTPCTracks{"includeTPCTracks", false, "TPC Tracks"}; + Configurable includeITSTracks{"includeITSTracks", false, "ITS Tracks"}; Filter filterTracks = (nabs(aod::track::eta) < confEta) && (aod::track::pt >= confPtMin) && (nabs(aod::track::dcaXY) < confDCAxy) && (nabs(aod::track::dcaZ) < confDCAz); Filter filterCollisions = (nabs(aod::collision::posZ) < confVertex.value[2]) && (nabs(aod::collision::posX) < confVertex.value[0]) && (nabs(aod::collision::posY) < confVertex.value[1]); @@ -71,9 +78,11 @@ struct FactorialMoments { {"mChi2TPC", "chi2 TPC", {HistType::kTH1F, {{100, 0, 10}}}}, {"mChi2ITS", "chi2 ITS", {HistType::kTH1F, {{100, 0, 10}}}}, {"mChi2TRD", "chi2 TRD", {HistType::kTH1F, {{100, 0, 100}}}}, - {"mDCAxy", "DCA xy", {HistType::kTH1F, {{100, -0.8, 0.8}}}}, - {"mDCAx", "DCA z", {HistType::kTH1F, {{100, -2.0, 2.0}}}}, - {"mDCAxyPt", "DCA xy vs #pt;#pt;DCAxy", {HistType::kTH2F, {{100, 0, 20}, {100, -0.5, 0.5}}}}, + {"mDCAxy", "DCA xy", {HistType::kTH1F, {{500, -0.8, 0.8}}}}, + {"mDCAx", "DCA z", {HistType::kTH1F, {{500, -2.0, 2.0}}}}, + {"mDCAxyPt", "DCA xy vs #pt;#pt;DCAxy", {HistType::kTH2F, {{100, 0, 20}, {500, -0.5, 0.5}}}}, + {"mDCAxyPtbcut", "DCA xy vs #pt;#pt;DCAxycut", {HistType::kTH2F, {{100, 0, 20}, {500, -0.5, 0.5}}}}, + {"mDCAzPtbcut", "DCA z vs #pt;#pt;DCAzcut", {HistType::kTH2F, {{100, 0, 20}, {100, -2.0, 2.0}}}}, {"mDCAzPt", "DCA z vs #pt;#pt;DCAz", {HistType::kTH2F, {{100, 0, 20}, {100, -2.0, 2.0}}}}, {"mNSharedClsTPC", "shared clusters in TPC", {HistType::kTH1F, {{100, 0, 10}}}}, {"mCrossedRowsTPC", "crossedrows in TPC", {HistType::kTH1F, {{100, 0, 200}}}}, @@ -95,7 +104,6 @@ struct FactorialMoments { std::vector> mBinConFinal; // max number of bins restricted to 5 static constexpr array mbinNames{"bin1/", "bin2/", "bin3/", "bin4/", "bin5/"}; - void init(o2::framework::InitContext&) { // NOTE: check to make number of pt and the vector consistent @@ -127,15 +135,21 @@ struct FactorialMoments { } } } - template void checkpT(const T& track) { for (auto iPt = 0; iPt < confNumPt; ++iPt) { if (track.pt() > confPtBins.value[2 * iPt] && track.pt() < confPtBins.value[2 * iPt + 1]) { + float iphi = track.phi(); + iphi = gRandom->Gaus(iphi, TMath::TwoPi()); + if (iphi < 0) { + iphi += TMath::TwoPi(); + } else if (iphi > TMath::TwoPi()) { + iphi -= TMath::TwoPi(); + } mHistArrQA[iPt * 4]->Fill(track.eta()); mHistArrQA[iPt * 4 + 1]->Fill(track.pt()); - mHistArrQA[iPt * 4 + 2]->Fill(track.phi()); + mHistArrQA[iPt * 4 + 2]->Fill(iphi); countTracks[iPt]++; for (auto iM = 0; iM < nBins; ++iM) { mHistArrReset[iPt * nBins + iM]->Fill(track.eta(), track.phi()); @@ -143,7 +157,6 @@ struct FactorialMoments { } } } - void calculateMoments(std::vector> hist) { Double_t binContent = 0; @@ -163,7 +176,7 @@ struct FactorialMoments { if (binconVal >= iOrder + 2) { fqBin = TMath::Factorial(binconVal) / (TMath::Factorial(binconVal - (iOrder + 2))); } - if (isnan(fqBin)) { + if (std::isnan(fqBin)) { break; } sumfqBin[iOrder] += fqBin; @@ -179,7 +192,7 @@ struct FactorialMoments { mBinConFinal[iPt * 6 + iOrder]->Fill(iM, binConEvent[iPt][iM]); } } // end of loop over M bins - } // end of loop over pT bins + } // end of loop over pT bins } using TracksFMs = soa::Filtered>; @@ -189,6 +202,15 @@ struct FactorialMoments { if (!coll.sel8()) { return; } + if (IsApplySameBunchPileup && !coll.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return; + } + if (IsApplyGoodZvtxFT0vsPV && !coll.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; + } + if (IsApplyVertexITSTPC && !coll.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return; + } if (coll.centFT0C() < confCentCut.value[0] || coll.centFT0C() > confCentCut.value[1]) { return; } @@ -199,41 +221,39 @@ struct FactorialMoments { histos.fill(HIST("mCentFV0A"), coll.centFV0A()); histos.fill(HIST("mCentFT0A"), coll.centFT0A()); histos.fill(HIST("mCentFT0C"), coll.centFT0C()); - for (auto const& h : mHistArrReset) { h->Reset(); } countTracks = {0, 0, 0, 0, 0}; - fqEvent = {0, 0, 0, 0, 0, 0}; - binConEvent = {0, 0, 0, 0, 0}; - + fqEvent = {{{{{0, 0, 0, 0, 0, 0}}}}}; + binConEvent = {{{0, 0, 0, 0, 0}}}; for (auto const& track : tracks) { - if ((track.pt() < confPtMin) || (!track.isGlobalTrack()) || (track.tpcNClsFindable() < confMinTPCCls)) { - continue; + if (track.hasTPC()) { + histos.fill(HIST("mCollID"), track.collisionId()); + histos.fill(HIST("mEta"), track.eta()); + histos.fill(HIST("mPt"), track.pt()); + histos.fill(HIST("mPhi"), track.phi()); + histos.fill(HIST("mNFindableClsTPC"), track.tpcNClsFindable()); + histos.fill(HIST("mNClsTPC"), track.tpcNClsFound()); + histos.fill(HIST("mNClsITS"), track.itsNCls()); + histos.fill(HIST("mChi2TPC"), track.tpcChi2NCl()); + histos.fill(HIST("mChi2ITS"), track.itsChi2NCl()); + histos.fill(HIST("mChi2TRD"), track.trdChi2()); + histos.fill(HIST("mDCAxy"), track.dcaXY()); + histos.fill(HIST("mDCAx"), track.dcaZ()); + histos.fill(HIST("mDCAxyPt"), track.pt(), track.dcaXY()); + histos.fill(HIST("mDCAzPt"), track.pt(), track.dcaZ()); + histos.fill(HIST("mNSharedClsTPC"), track.tpcNClsShared()); + histos.fill(HIST("mCrossedRowsTPC"), track.tpcNClsCrossedRows()); + histos.fill(HIST("mNFinClsminusCRows"), track.tpcNClsFindableMinusCrossedRows()); + histos.fill(HIST("mNFractionShClsTPC"), track.tpcFractionSharedCls()); + histos.fill(HIST("mSharedClsvsPt"), track.pt(), track.tpcNClsShared()); + histos.fill(HIST("mSharedClsProbvsPt"), track.pt(), track.tpcFractionSharedCls() / track.tpcNClsCrossedRows()); + checkpT(track); } - histos.fill(HIST("mCollID"), track.collisionId()); - histos.fill(HIST("mEta"), track.eta()); - histos.fill(HIST("mPt"), track.pt()); - histos.fill(HIST("mPhi"), track.phi()); - histos.fill(HIST("mNFindableClsTPC"), track.tpcNClsFindable()); - histos.fill(HIST("mNClsTPC"), track.tpcNClsFound()); - histos.fill(HIST("mNClsITS"), track.itsNCls()); - histos.fill(HIST("mChi2TPC"), track.tpcChi2NCl()); - histos.fill(HIST("mChi2ITS"), track.itsChi2NCl()); - histos.fill(HIST("mChi2TRD"), track.trdChi2()); - histos.fill(HIST("mDCAxy"), track.dcaXY()); - histos.fill(HIST("mDCAx"), track.dcaZ()); - histos.fill(HIST("mDCAxyPt"), track.pt(), track.dcaXY()); - histos.fill(HIST("mDCAzPt"), track.pt(), track.dcaZ()); - histos.fill(HIST("mNSharedClsTPC"), track.tpcNClsShared()); - histos.fill(HIST("mCrossedRowsTPC"), track.tpcNClsCrossedRows()); - histos.fill(HIST("mNFinClsminusCRows"), track.tpcNClsFindableMinusCrossedRows()); - histos.fill(HIST("mNFractionShClsTPC"), track.tpcFractionSharedCls()); - histos.fill(HIST("mSharedClsvsPt"), track.pt(), track.tpcNClsShared()); - histos.fill(HIST("mSharedClsProbvsPt"), track.pt(), track.tpcFractionSharedCls() / track.tpcNClsCrossedRows()); - checkpT(track); } for (auto iPt = 0; iPt < confNumPt; ++iPt) { + // if (countTracks[iPt] > 0) if (countTracks[iPt] > 0) { mHistArrQA[iPt * 4 + 3]->Fill(countTracks[iPt]); } @@ -241,7 +261,7 @@ struct FactorialMoments { // Calculate the normalized factorial moments calculateMoments(mHistArrReset); } - PROCESS_SWITCH(FactorialMoments, processRun3, "main process function", false); + PROCESS_SWITCH(FactorialMoments, processRun3, "main process function", true); void processRun2(soa::Filtered>::iterator const& coll, TracksFMs const& tracks) { @@ -255,13 +275,14 @@ struct FactorialMoments { histos.fill(HIST("mVertexY"), coll.posY()); histos.fill(HIST("mVertexZ"), coll.posZ()); histos.fill(HIST("mCentFT0M"), coll.centRun2V0M()); + for (auto const& h : mHistArrReset) { h->Reset(); } countTracks = {0, 0, 0, 0, 0}; - fqEvent = {0, 0, 0, 0, 0, 0}; - binConEvent = {0, 0, 0, 0, 0}; + fqEvent = {{{{{0, 0, 0, 0, 0, 0}}}}}; + binConEvent = {{{0, 0, 0, 0, 0}}}; for (auto const& track : tracks) { if ((track.pt() < confPtMin) || (!track.isGlobalTrack()) || (track.tpcNClsFindable() < confMinTPCCls)) { @@ -290,8 +311,10 @@ struct FactorialMoments { checkpT(track); } for (auto iPt = 0; iPt < confNumPt; ++iPt) { - if (countTracks[iPt] > 0) { + if (countTracks[iPt] > 500) { mHistArrQA[iPt * 4 + 3]->Fill(countTracks[iPt]); + } else { + return; } } // Calculate the normalized factorial moments diff --git a/PWGCF/EbyEFluctuations/Tasks/IdentifiedMeanPtFluctuations.cxx b/PWGCF/EbyEFluctuations/Tasks/IdentifiedMeanPtFluctuations.cxx index be75c1c93b3..2217a2c1f4f 100644 --- a/PWGCF/EbyEFluctuations/Tasks/IdentifiedMeanPtFluctuations.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/IdentifiedMeanPtFluctuations.cxx @@ -30,6 +30,8 @@ #include "PWGCF/Core/CorrelationContainer.h" #include "PWGCF/Core/PairCuts.h" #include "TDatabasePDG.h" +#include +#include "Common/CCDB/TriggerAliases.h" using namespace o2; using namespace o2::framework; @@ -38,6 +40,7 @@ using namespace std; namespace o2::aod { + using MyCollisions = soa::Join; +using MyMCRecoCollisions = soa::Join; + +using MyMCRecoTracks = soa::Join; + using MyCollision = MyCollisions::iterator; using MyTrack = MyTracks::iterator; } // namespace o2::aod @@ -61,6 +73,8 @@ struct IdentifiedMeanPtFluctuations { HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Configurable piluprejection{"piluprejection", false, "Pileup rejection"}; + void init(o2::framework::InitContext&) { AxisSpec vtxZAxis = {100, -20, 20, "Z (cm)"}; @@ -71,13 +85,13 @@ struct IdentifiedMeanPtFluctuations { AxisSpec betaAxis = {200, 0.0, 2.0, "TOF_{#beta} (GeV/#it{c})"}; AxisSpec dEdxAxis = {2000, 0.0, 200.0, "dE/dx (GeV/#it{c})"}; AxisSpec etaAxis = {100, -1.5, 1.5, "#eta"}; - AxisSpec nSigmaTPCAxis = {100, -5., 5., "n#sigma_{TPC}^{proton}"}; - AxisSpec nSigmaTPCAxispid = {110, -5.5, 5.5, "n#sigma_{TPC}"}; - AxisSpec nSigmaTOFAxispid = {110, -5.5, 5.5, "n#sigma_{TOF}"}; + AxisSpec nSigmaTPCAxis = {170, -8.5, 8.5, "n#sigma_{TPC}^{proton}"}; + AxisSpec nSigmaTPCAxispid = {170, -8.5, 8.5, "n#sigma_{TPC}"}; + AxisSpec nSigmaTOFAxispid = {170, -8.5, 8.5, "n#sigma_{TOF}"}; // AxisSpec nChAxis = {2500, -0.5, 2499.5, "nCh"}; AxisSpec centAxis = {100, 0., 100., "centrality"}; AxisSpec subAxis = {30, 0., 30., "sample"}; - AxisSpec nchAxis = {3200, 0., 3200., "nch"}; + AxisSpec nchAxis = {4000, 0., 4000., "nch"}; AxisSpec varAxis1 = {400, 0., 4., "var1"}; AxisSpec varAxis2 = {400, 0., 4., "var2"}; AxisSpec Chi2Axis = {100, 0., 100., "Chi2"}; @@ -98,6 +112,17 @@ struct IdentifiedMeanPtFluctuations { h->GetXaxis()->SetBinLabel(8, "TPC Chai2cluster passed"); h->GetXaxis()->SetBinLabel(9, "ITS Chai2cluster passed"); + histos.add("hEventCounter_recMC", "event counts rec MC", kTH1D, {Counter}); + + auto h_rec = histos.add("tracksel_rec", "tracksel_rec", HistType::kTH1D, {{10, 0.5, 10.5}}); + h_rec->GetXaxis()->SetBinLabel(1, "has_mcCollision() read"); + h_rec->GetXaxis()->SetBinLabel(2, "Vertex Z > 10cm passed"); + h_rec->GetXaxis()->SetBinLabel(3, "sel 8 passed"); + h_rec->GetXaxis()->SetBinLabel(4, "kNoSameBunchPileup passed"); + h_rec->GetXaxis()->SetBinLabel(5, "kNoITSROFrameBorder passed"); + h_rec->GetXaxis()->SetBinLabel(6, "klsGoodZvtxFT0vsPV passed"); + h_rec->GetXaxis()->SetBinLabel(7, "klsVertexITSTPC passed"); + histos.add("hZvtx_before_sel", "hZvtx_before_sel", kTH1D, {vtxZAxis}); histos.add("hZvtx_after_sel", "hZvtx_after_sel", kTH1D, {vtxZAxis}); histos.add("hZvtx_after_sel8", "hZvtx_after_sel8", kTH1D, {vtxZAxis}); @@ -119,10 +144,34 @@ struct IdentifiedMeanPtFluctuations { histos.add("NSigamaTOFkaon", "NSigamaTOFkaon", kTH2D, {ptAxis, nSigmaTOFAxispid}); histos.add("NSigamaTOFproton", "NSigamaTOFproton", kTH2D, {ptAxis, nSigmaTOFAxispid}); + histos.add("NSigamaTPCpion_rec", "NSigamaTPCpion_rec", kTH2D, {pAxis, nSigmaTPCAxispid}); + histos.add("NSigamaTPCkaon_rec", "NSigamaTPCkaon_rec", kTH2D, {pAxis, nSigmaTPCAxispid}); + histos.add("NSigamaTPCproton_rec", "NSigamaTPCproton_rec", kTH2D, {pAxis, nSigmaTPCAxispid}); + + histos.add("NSigamaTOFpion_rec", "NSigamaTOFpion_rec", kTH2D, {pAxis, nSigmaTOFAxispid}); + histos.add("NSigamaTOFkaon_rec", "NSigamaTOFkaon_rec", kTH2D, {pAxis, nSigmaTOFAxispid}); + histos.add("NSigamaTOFproton_rec", "NSigamaTOFproton_rec", kTH2D, {pAxis, nSigmaTOFAxispid}); + histos.add("NSigamaTPCTOFpion", "NSigamaTPCTOFpion", kTH2D, {nSigmaTPCAxispid, nSigmaTOFAxispid}); histos.add("NSigamaTPCTOFkaon", "NSigamaTPCTOFkaon", kTH2D, {nSigmaTPCAxispid, nSigmaTOFAxispid}); histos.add("NSigamaTPCTOFproton", "NSigamaTPCTOFproton", kTH2D, {nSigmaTPCAxispid, nSigmaTOFAxispid}); + histos.add("NSigamaTPCTOFpion_rec", "NSigamaTPCTOFpion_rec", kTH2D, {nSigmaTPCAxispid, nSigmaTOFAxispid}); + histos.add("NSigamaTPCTOFkaon_rec", "NSigamaTPCTOFkaon_rec", kTH2D, {nSigmaTPCAxispid, nSigmaTOFAxispid}); + histos.add("NSigamaTPCTOFproton_rec", "NSigamaTPCTOFproton_rec", kTH2D, {nSigmaTPCAxispid, nSigmaTOFAxispid}); + + histos.add("NSigamaTPCpion_rec_bf_sel", "NSigamaTPCpion_rec_bf_sel", kTH2D, {pAxis, nSigmaTPCAxispid}); + histos.add("NSigamaTPCkaon_rec_bf_sel", "NSigamaTPCkaon_rec_bf_sel", kTH2D, {pAxis, nSigmaTPCAxispid}); + histos.add("NSigamaTPCproton_rec_bf_sel", "NSigamaTPCproton_rec_bf_sel", kTH2D, {pAxis, nSigmaTPCAxispid}); + + histos.add("NSigamaTOFpion_rec_bf_sel", "NSigamaTOFpion_rec_bf_sel", kTH2D, {pAxis, nSigmaTOFAxispid}); + histos.add("NSigamaTOFkaon_rec_bf_sel", "NSigamaTOFkaon_rec_bf_sel", kTH2D, {pAxis, nSigmaTOFAxispid}); + histos.add("NSigamaTOFproton_rec_bf_sel", "NSigamaTOFproton_rec_bf_sel", kTH2D, {pAxis, nSigmaTOFAxispid}); + + histos.add("NSigamaTPCTOFpion_rec_bf_sel", "NSigamaTPCTOFpion_rec_bf_sel", kTH2D, {nSigmaTPCAxispid, nSigmaTOFAxispid}); + histos.add("NSigamaTPCTOFkaon_rec_bf_sel", "NSigamaTPCTOFkaon_rec_bf_sel", kTH2D, {nSigmaTPCAxispid, nSigmaTOFAxispid}); + histos.add("NSigamaTPCTOFproton_rec_bf_sel", "NSigamaTPCTOFproton_rec_bf_sel", kTH2D, {nSigmaTPCAxispid, nSigmaTOFAxispid}); + histos.add("hPtPion", ";#it{p}_{T} (GeV/#it{c})", kTH1D, {ptAxis}); histos.add("hPtKaon", ";#it{p}_{T} (GeV/#it{c})", kTH1D, {ptAxis}); histos.add("hPtProton", ";#it{p}_{T} (GeV/#it{c})", kTH1D, {ptAxis}); @@ -203,6 +252,14 @@ struct IdentifiedMeanPtFluctuations { histos.add("hPtyKaon", "hPtyKaon", kTH2D, {ptAxis, etaAxis}); histos.add("hPtyProton", "hPtyProton", kTH2D, {ptAxis, etaAxis}); + histos.add("hPtyPion_rec", "hPtyPion_rec", kTH2D, {ptAxis, etaAxis}); + histos.add("hPtyKaon_rec", "hPtyKaon_rec", kTH2D, {ptAxis, etaAxis}); + histos.add("hPtyProton_rec", "hPtyProton_rec", kTH2D, {ptAxis, etaAxis}); + + histos.add("hPyPion_rec", "hPyPion_rec", kTH2D, {pAxis, etaAxis}); + histos.add("hPyKaon_rec", "hPyKaon_rec", kTH2D, {pAxis, etaAxis}); + histos.add("hPyProton_rec", "hPyProton_rec", kTH2D, {pAxis, etaAxis}); + histos.add("hTOFbeta", "hTOFbeta", kTH2D, {pAxis, betaAxis}); histos.add("hdEdx", "hdEdx", kTH2D, {pAxis, dEdxAxis}); @@ -212,6 +269,14 @@ struct IdentifiedMeanPtFluctuations { histos.add("hTOFbeta_afterselection1", "hTOFbeta_afterselection1", kTH2D, {pAxis, betaAxis}); histos.add("hdEdx_afterselection1", "hdEdx_afterselection1", kTH2D, {pAxis, dEdxAxis}); + histos.add("hTOFbeta_afterselection_rec_afterpidcut", "hTOFbeta_afterselection_rec_afterpidcut", kTH2D, {pAxis, betaAxis}); + histos.add("hdEdx_afterselection_rec_afterpidcut", "hdEdx_afterselection_rec_afterpidcut", kTH2D, {pAxis, dEdxAxis}); + + histos.add("hTOFbeta_afterselection_rec_beforepidcut", "hTOFbeta_afterselection_rec_beforepidcut", kTH2D, {pAxis, betaAxis}); + histos.add("hdEdx_afterselection_rec_beforepidcut", "hdEdx_afterselection_rec_beforepidcut", kTH2D, {pAxis, dEdxAxis}); + + histos.add("hdEdx_rec_bf_anycut", "hdEdx_rec_bf_anycut", kTH2D, {pAxis, dEdxAxis}); + histos.add("hTPCchi2perCluster_before", "TPC #Chi^{2}/Cluster", kTH1D, {Chi2Axis}); histos.add("hITSchi2perCluster_before", "ITS #Chi^{2}/Cluster", kTH1D, {Chi2Axis}); histos.add("hTPCCrossedrows_before", "Crossed TPC rows", kTH1D, {CrossedrowTPCAxis}); @@ -219,8 +284,544 @@ struct IdentifiedMeanPtFluctuations { histos.add("hTPCchi2perCluster_after", "TPC #Chi^{2}/Cluster", kTH1D, {Chi2Axis}); histos.add("hITSchi2perCluster_after", "ITS #Chi^{2}/Cluster", kTH1D, {Chi2Axis}); histos.add("hTPCCrossedrows_after", "Crossed TPC rows", kTH1D, {CrossedrowTPCAxis}); + + //--------------------------------nch---------------------------------- + histos.add("hVar1x_rec", "hVar1x_rec", kTH2D, {subAxis, nchAxis}); + histos.add("hVar2x_rec", "hVar2x_rec", kTH2D, {subAxis, nchAxis}); + histos.add("hVarx_rec", "hVarx_rec", kTH2D, {subAxis, nchAxis}); + histos.add("hVar2meanptx_rec", "hVar2meanptx_rec", kTH2D, {nchAxis, varAxis2}); + + histos.add("hVar1pix_rec", "hVar1pix_rec", kTH2D, {subAxis, nchAxis}); + histos.add("hVar2pix_rec", "hVar2pix_rec", kTH2D, {subAxis, nchAxis}); + histos.add("hVarpix_rec", "hVarpix_rec", kTH2D, {subAxis, nchAxis}); + histos.add("hVar2meanptpix_rec", "hVar2meanptpix_rec", kTH2D, {nchAxis, varAxis2}); + + histos.add("hVar1kx_rec", "hVar1kx_rec", kTH2D, {subAxis, nchAxis}); + histos.add("hVar2kx_rec", "hVar2kx_rec", kTH2D, {subAxis, nchAxis}); + histos.add("hVarkx_rec", "hVarkx_rec", kTH2D, {subAxis, nchAxis}); + histos.add("hVar2meanptkx_rec", "hVar2meanptkx_rec", kTH2D, {nchAxis, varAxis2}); + + histos.add("hVar1px_rec", "hVar1px_rec", kTH2D, {subAxis, nchAxis}); + histos.add("hVar2px_rec", "hVar2px_rec", kTH2D, {subAxis, nchAxis}); + histos.add("hVarpx_rec", "hVarpx_rec", kTH2D, {subAxis, nchAxis}); + histos.add("hVar2meanptpx_rec", "hVar2meanptpx_rec", kTH2D, {nchAxis, varAxis2}); + + //=======================MC histograms Generated ================================================ + histos.add("ptHistogram_allcharge_gen", "ptHistogram_allcharge_gen", kTH1D, {ptAxis}); + histos.add("ptHistogramPion", "ptHistogramPion", kTH1D, {ptAxis}); + histos.add("ptHistogramKaon", "ptHistogramKaon", kTH1D, {ptAxis}); + histos.add("ptHistogramProton", "ptHistogramProton", kTH1D, {ptAxis}); + + histos.add("hMC_Pt", ";#it{p}_{T} (GeV/#it{c})", kTH1D, {ptAxis}); + histos.add("MC_hZvtx_after_sel", ";#it{p}_{T} (GeV/#it{c})", kTH1D, {vtxZAxis}); + + histos.add("hTOFbeta_gen_pion", "hTOFbeta_gen_pion", kTH2D, {pAxis, betaAxis}); + histos.add("hdEdx_gen_pion", "hdEdx_gen_pion", kTH2D, {pAxis, dEdxAxis}); + + histos.add("hVar1x_gen", "hVar1x_gen", kTH2D, {subAxis, nchAxis}); + histos.add("hVar2x_gen", "hVar2x_gen", kTH2D, {subAxis, nchAxis}); + histos.add("hVarx_gen", "hVarx_gen", kTH2D, {subAxis, nchAxis}); + histos.add("hVar2meanptx_gen", "hVar2meanptx_gen", kTH2D, {nchAxis, varAxis2}); + + histos.add("hVar1pix_gen", "hVar1pix_gen", kTH2D, {subAxis, nchAxis}); + histos.add("hVar2pix_gen", "hVar2pix_gen", kTH2D, {subAxis, nchAxis}); + histos.add("hVarpix_gen", "hVarpix_gen", kTH2D, {subAxis, nchAxis}); + histos.add("hVar2meanptpix_gen", "hVar2meanptpix_gen", kTH2D, {nchAxis, varAxis2}); + + histos.add("hVar1kx_gen", "hVar1kx_gen", kTH2D, {subAxis, nchAxis}); + histos.add("hVar2kx_gen", "hVar2kx_gen", kTH2D, {subAxis, nchAxis}); + histos.add("hVarkx_gen", "hVarkx_gen", kTH2D, {subAxis, nchAxis}); + histos.add("hVar2meanptkx_gen", "hVar2meanptkx_gen", kTH2D, {nchAxis, varAxis2}); + + histos.add("hVar1px_gen", "hVar1px_gen", kTH2D, {subAxis, nchAxis}); + histos.add("hVar2px_gen", "hVar2px_gen", kTH2D, {subAxis, nchAxis}); + histos.add("hVarpx_gen", "hVarpx_gen", kTH2D, {subAxis, nchAxis}); + histos.add("hVar2meanptpx_gen", "hVar2meanptpx_gen", kTH2D, {nchAxis, varAxis2}); + + //========================MC Histograms Reconstructed================================================= + + histos.add("hZvtx_after_sel_rec", "hZvtx_after_sel_rec", kTH1D, {vtxZAxis}); + histos.add("hZvtx_after_sel8_rec", "hZvtx_after_sel8_rec", kTH1D, {vtxZAxis}); + + histos.add("ptHistogram_allcharge_rec", "ptHistogram_allcharge_rec", kTH1D, {ptAxis}); + histos.add("ptHistogramPionrec", "ptHistogramPionrec", kTH1D, {ptAxis}); + histos.add("ptHistogramKaonrec", "ptHistogramKaonrec", kTH1D, {ptAxis}); + histos.add("ptHistogramProtonrec", "ptHistogramProtonrec", kTH1D, {ptAxis}); + + histos.add("ptHistogramPionrec_purity", "ptHistogramPionrec_purity", kTH1D, {ptAxis}); + histos.add("ptHistogramKaonrec_purity", "ptHistogramKaonrec_purity", kTH1D, {ptAxis}); + histos.add("ptHistogramProtonrec_purity", "ptHistogramProtonrec_purity", kTH1D, {ptAxis}); + + histos.add("ptHistogramPionrec_pdg", "ptHistogramPionrec_pdg", kTH1D, {ptAxis}); + histos.add("ptHistogramKaonrec_pdg", "ptHistogramKaonrec_pdg", kTH1D, {ptAxis}); + histos.add("ptHistogramProtonrec_pdg", "ptHistogramProtonrec_pdg", kTH1D, {ptAxis}); + + histos.add("Histogram_mass2_p_rec_beforesel", "Histogram_mass2_p_rec_beforesel", kTH1D, {ptAxis}); + histos.add("Histogram_mass2_p_rec_aftersel", "Histogram_mass2_p_rec_aftersel", kTH1D, {ptAxis}); + } + + //++++++++++++++++++++++++Monte Carlo Reconstructed +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + template + void SelTPConlyPions(const T& track1) + { + (track1.hasTPC() && (track1.p() < 0.7) && abs(track1.tpcNSigmaPi()) < 3. && (std::abs(track1.tpcNSigmaKa()) > 3.0 && std::abs(track1.tpcNSigmaPr()) > 3.0)); + } + template + void SelTPConlyKaons(const T& track1) + { + (track1.hasTPC() && (track1.p() < 0.7) && abs(track1.tpcNSigmaKa()) < 3.0 && (std::abs(track1.tpcNSigmaPi()) > 3.0 && std::abs(track1.tpcNSigmaPr()) > 3.0)); + } + template + void SelTPConlyProtons(const T& track1) + { + (track1.hasTPC() && (track1.p() < 1.1) && abs(track1.tpcNSigmaPr()) < 3.0 && (std::abs(track1.tpcNSigmaPi()) > 3.0 && std::abs(track1.tpcNSigmaKa()) > 3.0)); + } + + template + void SelTPCTOFPions(const T& track1) + { + (track1.hasTPC() && track1.hasTOF() && track1.p() >= 0.7 && TMath::Hypot((track1.tofNSigmaPr() + 2) / 3.0, (track1.tpcNSigmaPr() - 6) / 4.0) > 3. && TMath::Hypot((track1.tofNSigmaKa() + 2) / 3.0, (track1.tpcNSigmaKa() - 6) / 4.0) > 3. && TMath::Hypot((track1.tofNSigmaPi() + 2) / 3.0, (track1.tpcNSigmaPi() - 6) / 4.0) < 3.); + } + + template + void SelTPCTOFKaons(const T& track1) + { + (track1.hasTPC() && track1.hasTOF() && track1.p() >= 0.7 && TMath::Hypot((track1.tofNSigmaPr() + 2) / 3.0, (track1.tpcNSigmaPr() - 6) / 4.0) > 3. && TMath::Hypot((track1.tofNSigmaPi() + 2) / 3.0, (track1.tpcNSigmaPi() - 6) / 4.0) > 3. && TMath::Hypot((track1.tofNSigmaKa() + 2) / 3.0, (track1.tpcNSigmaKa() - 6) / 4.0) < 3.); + } + + template + void SelTPCTOFProtons(const T& track1) + { + if (track1.hasTPC() && track1.hasTOF() && track1.p() >= 1.1 && TMath::Hypot((track1.tofNSigmaPi() + 2) / 3.0, (track1.tpcNSigmaPi() - 6) / 4.0) > 3. && TMath::Hypot((track1.tofNSigmaKa() + 2) / 3.0, (track1.tpcNSigmaKa() - 6) / 4.0) > 3. && TMath::Hypot((track1.tofNSigmaPr() + 2) / 3.0, (track1.tpcNSigmaPr() - 6) / 4.0) < 3.) { + }; } + void processMCReco(aod::MyMCRecoCollisions::iterator const& mccoll, aod::MyMCRecoTracks const& mcrectrack, aod::McParticles const& /*mcParticles*/) + { + if (!mccoll.has_mcCollision()) { + return; + } + histos.fill(HIST("tracksel_rec"), 1); + + if (fabs(mccoll.posZ()) > 10.f) { + return; + } + histos.fill(HIST("hZvtx_after_sel_rec"), mccoll.posZ()); + + histos.fill(HIST("tracksel_rec"), 2); + + if (!mccoll.sel8()) { + return; + } + + histos.fill(HIST("hZvtx_after_sel8_rec"), mccoll.posZ()); + + histos.fill(HIST("tracksel_rec"), 3); + + if (!mccoll.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return; + } + histos.fill(HIST("tracksel_rec"), 4); + + if (!mccoll.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return; + } + histos.fill(HIST("tracksel_rec"), 5); + + if (!mccoll.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; + } + histos.fill(HIST("tracksel_rec"), 6); + + if (!mccoll.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return; + } + histos.fill(HIST("tracksel_rec"), 7); + + double nCh_rec = 0.; + double nChpi_rec = 0.; + double nChk_rec = 0.; + double nChp_rec = 0.; + + double Q1_rec = 0, Q2_rec = 0; + double Q1pi_rec = 0, Q2pi_rec = 0; + double Q1k_rec = 0, Q2k_rec = 0; + double Q1p_rec = 0, Q2p_rec = 0; + double var1_rec = 0, var2_rec = 0; + double var1pi_rec = 0, var2pi_rec = 0; + double var1k_rec = 0, var2k_rec = 0; + double var1p_rec = 0, var2p_rec = 0; + + int sample_rec = histos.get(HIST("hZvtx_after_sel8_rec"))->GetEntries(); + sample_rec = sample_rec % 30; + + for (auto track1 : mcrectrack) { + if (!(track1.has_collision())) + continue; + if (!(track1.has_mcParticle())) + continue; + if (!(track1.mcParticle().isPhysicalPrimary())) + continue; + if (!track1.isGlobalTrack()) + continue; + + if (!(track1.pt() > 0.15) || !(track1.pt() < 2.0)) + continue; // pt = 0.15 + if (!(track1.eta() > -0.8) || !(track1.eta() < 0.8)) + continue; // eta cut + + nCh_rec += 1.; + + Q1_rec += track1.pt(); + Q2_rec += (track1.pt() * track1.pt()); + + histos.fill(HIST("ptHistogram_allcharge_rec"), track1.pt()); + + if (track1.hasTPC()) + histos.fill(HIST("hdEdx_rec_bf_anycut"), track1.p(), track1.tpcSignal()); + + //======================================================================== + + if (abs(track1.mcParticle().pdgCode()) == 211) { + + histos.fill(HIST("ptHistogramPionrec_pdg"), track1.pt()); + } + if (abs(track1.mcParticle().pdgCode()) == 321) { + + histos.fill(HIST("ptHistogramKaonrec_pdg"), track1.pt()); + } + if (abs(track1.mcParticle().pdgCode()) == 2212) { + + histos.fill(HIST("ptHistogramProtonrec_pdg"), track1.pt()); + } + + //+++++++++ electron rejection ++++++++++++++++++++++++++++++++// + + if (abs(track1.tpcNSigmaEl()) < 3.0 && abs(track1.tpcNSigmaPi()) > 3. && abs(track1.tpcNSigmaKa()) > 3. && abs(track1.tpcNSigmaPr()) > 3.) + continue; + + //============Reconstructed MC=================PIONS selection==============================================================// + + if (track1.hasTPC()) + histos.fill(HIST("hdEdx_afterselection_rec_beforepidcut"), track1.p(), track1.tpcSignal()); + if (track1.hasTOF()) + histos.fill(HIST("hTOFbeta_afterselection_rec_beforepidcut"), track1.p(), track1.beta()); + + if (track1.hasTPC() && track1.hasTOF()) { + + histos.fill(HIST("NSigamaTPCpion_rec_bf_sel"), track1.p(), track1.tpcNSigmaPi()); + histos.fill(HIST("NSigamaTOFpion_rec_bf_sel"), track1.p(), track1.tofNSigmaPi()); + histos.fill(HIST("NSigamaTPCTOFpion_rec_bf_sel"), track1.tpcNSigmaPi(), track1.tofNSigmaPi()); + } + + SelTPConlyPions(track1); // Pion (TPC only) + SelTPCTOFPions(track1); // Pion passes TPC and TOF both! + + { + + histos.fill(HIST("ptHistogramPionrec"), track1.pt()); + + nChpi_rec += 1.; + Q1pi_rec += track1.pt(); + Q2pi_rec += (track1.pt() * track1.pt()); + + histos.fill(HIST("NSigamaTPCpion_rec"), track1.p(), track1.tpcNSigmaPi()); + histos.fill(HIST("NSigamaTOFpion_rec"), track1.p(), track1.tofNSigmaPi()); + histos.fill(HIST("NSigamaTPCTOFpion_rec"), track1.tpcNSigmaPi(), track1.tofNSigmaPi()); + + if (track1.beta() > 1) + continue; + + histos.fill(HIST("hdEdx_afterselection_rec_afterpidcut"), track1.p(), track1.tpcSignal()); + histos.fill(HIST("hTOFbeta_afterselection_rec_afterpidcut"), track1.p(), track1.beta()); + + if (abs(track1.mcParticle().pdgCode()) == 211) { + histos.fill(HIST("ptHistogramPionrec_purity"), track1.pt()); + } + + if (abs(track1.rapidity(massPi)) < 0.5) { + + histos.fill(HIST("hPyPion_rec"), track1.p(), track1.rapidity(massPi)); + histos.fill(HIST("hPtyPion_rec"), track1.pt(), track1.rapidity(massPi)); + } + } + + //============Reconstructed MC=================KAONS selection==============================================================// + + if (track1.hasTPC()) + histos.fill(HIST("hdEdx_afterselection_rec_beforepidcut"), track1.p(), track1.tpcSignal()); + if (track1.hasTOF()) + histos.fill(HIST("hTOFbeta_afterselection_rec_beforepidcut"), track1.p(), track1.beta()); + + if (track1.hasTPC() && track1.hasTOF()) { + + histos.fill(HIST("NSigamaTPCkaon_rec_bf_sel"), track1.p(), track1.tpcNSigmaKa()); + histos.fill(HIST("NSigamaTOFkaon_rec_bf_sel"), track1.p(), track1.tofNSigmaKa()); + histos.fill(HIST("NSigamaTPCTOFkaon_rec_bf_sel"), track1.tpcNSigmaKa(), track1.tofNSigmaKa()); + } + + SelTPConlyKaons(track1); // Kaons passes from TPC only! + SelTPCTOFKaons(track1); // Kaons passes from TPC and TOF both! + + { + + histos.fill(HIST("ptHistogramKaonrec"), track1.pt()); + + nChk_rec += 1.; + Q1k_rec += track1.pt(); + Q2k_rec += (track1.pt() * track1.pt()); + + histos.fill(HIST("NSigamaTPCkaon_rec"), track1.p(), track1.tpcNSigmaKa()); + histos.fill(HIST("NSigamaTOFkaon_rec"), track1.p(), track1.tofNSigmaKa()); + histos.fill(HIST("NSigamaTPCTOFkaon_rec"), track1.tpcNSigmaKa(), track1.tofNSigmaKa()); + + if (track1.beta() > 1) + continue; + + histos.fill(HIST("hdEdx_afterselection_rec_afterpidcut"), track1.p(), track1.tpcSignal()); + histos.fill(HIST("hTOFbeta_afterselection_rec_afterpidcut"), track1.p(), track1.beta()); + + if (abs(track1.mcParticle().pdgCode()) == 321) { + histos.fill(HIST("ptHistogramKaonrec_purity"), track1.pt()); + } + + if (abs(track1.rapidity(massKa)) < 0.5) { + + histos.fill(HIST("hPyKaon_rec"), track1.p(), track1.rapidity(massKa)); + histos.fill(HIST("hPtyKaon_rec"), track1.pt(), track1.rapidity(massKa)); + } + } + + //============Reconstructed MC=================PROTONS selection==============================================================// + + if (track1.hasTPC()) + histos.fill(HIST("hdEdx_afterselection_rec_beforepidcut"), track1.p(), track1.tpcSignal()); + if (track1.hasTOF()) + histos.fill(HIST("hTOFbeta_afterselection_rec_beforepidcut"), track1.p(), track1.beta()); + + if (track1.hasTPC() && track1.hasTOF()) { + + histos.fill(HIST("NSigamaTPCproton_rec_bf_sel"), track1.p(), track1.tpcNSigmaPr()); + histos.fill(HIST("NSigamaTOFproton_rec_bf_sel"), track1.p(), track1.tofNSigmaPr()); + histos.fill(HIST("NSigamaTPCTOFproton_rec_bf_sel"), track1.tpcNSigmaPr(), track1.tofNSigmaPr()); + } + + SelTPConlyProtons(track1); // Protons passes from TPC only! + SelTPCTOFProtons(track1); // Protons passes from TPC and TOF both! + + { + + histos.fill(HIST("ptHistogramProtonrec"), track1.pt()); + + nChp_rec += 1.; + Q1p_rec += track1.pt(); + Q2p_rec += (track1.pt() * track1.pt()); + + histos.fill(HIST("NSigamaTPCproton_rec"), track1.p(), track1.tpcNSigmaPr()); + histos.fill(HIST("NSigamaTOFproton_rec"), track1.p(), track1.tofNSigmaPr()); + histos.fill(HIST("NSigamaTPCTOFproton_rec"), track1.tpcNSigmaPr(), track1.tofNSigmaPr()); + + if (track1.beta() > 1) + continue; + + histos.fill(HIST("hdEdx_afterselection_rec_afterpidcut"), track1.p(), track1.tpcSignal()); + histos.fill(HIST("hTOFbeta_afterselection_rec_afterpidcut"), track1.p(), track1.beta()); + + if (abs(track1.mcParticle().pdgCode()) == 2212) { + histos.fill(HIST("ptHistogramProtonrec_purity"), track1.pt()); + } + + if (abs(track1.rapidity(massPr)) < 0.5) { + + histos.fill(HIST("hPyProton_rec"), track1.p(), track1.rapidity(massPr)); + histos.fill(HIST("hPtyProton_rec"), track1.pt(), track1.rapidity(massPr)); + } + } + + //============================================================================ + + } // track loop ends + + if (nCh_rec < 2) + return; + + //------------------ all charges------------------------------------- + var1_rec = (Q1_rec * Q1_rec - Q2_rec) / (nCh_rec * (nCh_rec - 1)); + var2_rec = (Q1_rec / nCh_rec); + + //---------------------- pions ---------------------------------------- + + if (nChpi_rec > 2) { + var1pi_rec = (Q1pi_rec * Q1pi_rec - Q2pi_rec) / (nChpi_rec * (nChpi_rec - 1)); + var2pi_rec = (Q1pi_rec / nChpi_rec); + } + + //----------------------- kaons --------------------------------------- + if (nChk_rec > 2) { + var1k_rec = (Q1k_rec * Q1k_rec - Q2k_rec) / (nChk_rec * (nChk_rec - 1)); + var2k_rec = (Q1k_rec / nChk_rec); + } + + //---------------------------- protons ---------------------------------- + if (nChp_rec > 2) { + var1p_rec = (Q1p_rec * Q1p_rec - Q2p_rec) / (nChp_rec * (nChp_rec - 1)); + var2p_rec = (Q1p_rec / nChp_rec); + } + + //-----------------------nch------------------------------------- + histos.fill(HIST("hVar1x_rec"), sample_rec, nCh_rec, var1_rec); + histos.fill(HIST("hVar2x_rec"), sample_rec, nCh_rec, var2_rec); + histos.fill(HIST("hVarx_rec"), sample_rec, nCh_rec); + histos.fill(HIST("hVar2meanptx_rec"), nCh_rec, var2_rec); + + histos.fill(HIST("hVar1pix_rec"), sample_rec, nCh_rec, var1pi_rec); + histos.fill(HIST("hVar2pix_rec"), sample_rec, nCh_rec, var2pi_rec); + histos.fill(HIST("hVarpix_rec"), sample_rec, nChpi_rec); + histos.fill(HIST("hVar2meanptpix_rec"), nCh_rec, var2pi_rec); + + histos.fill(HIST("hVar1kx_rec"), sample_rec, nCh_rec, var1k_rec); + histos.fill(HIST("hVar2kx_rec"), sample_rec, nCh_rec, var2k_rec); + histos.fill(HIST("hVarkx_rec"), sample_rec, nChk_rec); + histos.fill(HIST("hVar2meanptkx_rec"), nCh_rec, var2k_rec); + + histos.fill(HIST("hVar1px_rec"), sample_rec, nCh_rec, var1p_rec); + histos.fill(HIST("hVar2px_rec"), sample_rec, nCh_rec, var2p_rec); + histos.fill(HIST("hVarpx_rec"), sample_rec, nChp_rec); + histos.fill(HIST("hVar2meanptpx_rec"), nCh_rec, var2p_rec); + + } // ends + + PROCESS_SWITCH(IdentifiedMeanPtFluctuations, processMCReco, "process reconstructed information", true); + + //++++++++++++++++++++++++++++Monte Carlo Generated ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + void processMCGen(aod::McCollision const& mcCollision, aod::McParticles& mcParticles) + + { + + if (fabs(mcCollision.posZ()) > 10.f) { + return; + } + histos.fill(HIST("MC_hZvtx_after_sel"), mcCollision.posZ()); + + double nCh_gen = 0.; + double nChpi_gen = 0.; + double nChk_gen = 0.; + double nChp_gen = 0.; + + double Q1_gen = 0, Q2_gen = 0; + double Q1pi_gen = 0, Q2pi_gen = 0; + double Q1k_gen = 0, Q2k_gen = 0; + double Q1p_gen = 0, Q2p_gen = 0; + + double var1_gen = 0, var2_gen = 0; + double var1pi_gen = 0, var2pi_gen = 0; + double var1k_gen = 0, var2k_gen = 0; + double var1p_gen = 0, var2p_gen = 0; + + int sample_gen = histos.get(HIST("hZvtx_after_sel"))->GetEntries(); + sample_gen = sample_gen % 30; + + for (auto& mcgentrack : mcParticles) + + { + auto pdgcode = std::abs(mcgentrack.pdgCode()); + if (!(mcgentrack.has_mcCollision())) + continue; + if (!(mcgentrack.isPhysicalPrimary())) + continue; + if (!(mcgentrack.pt() > 0.15) || !(mcgentrack.pt() < 2.)) + continue; + if (!(mcgentrack.eta() > -0.8) || !(mcgentrack.eta() < 0.8)) + continue; + + nCh_gen += 1.; + + Q1_gen += mcgentrack.pt(); + Q2_gen += (mcgentrack.pt() * mcgentrack.pt()); + + histos.fill(HIST("ptHistogram_allcharge_gen"), mcgentrack.pt()); + + if (pdgcode == 211) { + + histos.fill(HIST("ptHistogramPion"), mcgentrack.pt()); + + nChpi_gen += 1.; + Q1pi_gen += mcgentrack.pt(); + Q2pi_gen += (mcgentrack.pt() * mcgentrack.pt()); + } + + if (pdgcode == 321) { + + histos.fill(HIST("ptHistogramKaon"), mcgentrack.pt()); + + nChk_gen += 1.; + Q1k_gen += mcgentrack.pt(); + Q2k_gen += (mcgentrack.pt() * mcgentrack.pt()); + } + + if (pdgcode == 2212) { + + histos.fill(HIST("ptHistogramProton"), mcgentrack.pt()); + + nChp_gen += 1.; + Q1p_gen += mcgentrack.pt(); + Q2p_gen += (mcgentrack.pt() * mcgentrack.pt()); + } + + //================================= Pion Generated Calculation ==================================== + + } // track loop ends! + + if (nCh_gen < 2) + return; + + //------------------ all charges------------------------------------- + var1_gen = (Q1_gen * Q1_gen - Q2_gen) / (nCh_gen * (nCh_gen - 1)); + var2_gen = (Q1_gen / nCh_gen); + + //---------------------- pions ---------------------------------------- + + if (nChpi_gen > 2) { + var1pi_gen = (Q1pi_gen * Q1pi_gen - Q2pi_gen) / (nChpi_gen * (nChpi_gen - 1)); + var2pi_gen = (Q1pi_gen / nChpi_gen); + } + + //----------------------- kaons --------------------------------------- + if (nChk_gen > 2) { + var1k_gen = (Q1k_gen * Q1k_gen - Q2k_gen) / (nChk_gen * (nChk_gen - 1)); + var2k_gen = (Q1k_gen / nChk_gen); + } + + //---------------------------- protons ---------------------------------- + if (nChp_gen > 2) { + var1p_gen = (Q1p_gen * Q1p_gen - Q2p_gen) / (nChp_gen * (nChp_gen - 1)); + var2p_gen = (Q1p_gen / nChp_gen); + } + + //-----------------------nch------------------------------------- + histos.fill(HIST("hVar1x_gen"), sample_gen, nCh_gen, var1_gen); + histos.fill(HIST("hVar2x_gen"), sample_gen, nCh_gen, var2_gen); + histos.fill(HIST("hVarx_gen"), sample_gen, nCh_gen); + histos.fill(HIST("hVar2meanptx_gen"), nCh_gen, var2_gen); + + histos.fill(HIST("hVar1pix_gen"), sample_gen, nCh_gen, var1pi_gen); + histos.fill(HIST("hVar2pix_gen"), sample_gen, nCh_gen, var2pi_gen); + histos.fill(HIST("hVarpix_gen"), sample_gen, nChpi_gen); + histos.fill(HIST("hVar2meanptpix_gen"), nCh_gen, var2pi_gen); + + histos.fill(HIST("hVar1kx_gen"), sample_gen, nCh_gen, var1k_gen); + histos.fill(HIST("hVar2kx_gen"), sample_gen, nCh_gen, var2k_gen); + histos.fill(HIST("hVarkx_gen"), sample_gen, nChk_gen); + histos.fill(HIST("hVar2meanptkx_gen"), nCh_gen, var2k_gen); + + histos.fill(HIST("hVar1px_gen"), sample_gen, nCh_gen, var1p_gen); + histos.fill(HIST("hVar2px_gen"), sample_gen, nCh_gen, var2p_gen); + histos.fill(HIST("hVarpx_gen"), sample_gen, nChp_gen); + histos.fill(HIST("hVar2meanptpx_gen"), nCh_gen, var2p_gen); + } + PROCESS_SWITCH(IdentifiedMeanPtFluctuations, processMCGen, "process generated information", true); + + //+++++++++++++++++++++++++++++DATA CALCULATION +++++++++++++++++++++++++++++++++++++++++++++++++++++ void process(aod::MyCollision const& coll, aod::MyTracks const& inputTracks) { @@ -250,19 +851,19 @@ struct IdentifiedMeanPtFluctuations { double nChk = 0.; double nChp = 0.; - double Q1 = 0, Q2 = 0; - double Q1pi = 0, Q2pi = 0; - double Q1k = 0, Q2k = 0; - double Q1p = 0, Q2p = 0; - double var1 = 0, var2 = 0, twopar_allcharge = 0; - double var1pi = 0, var2pi = 0; - double var1k = 0, var2k = 0; - double var1p = 0, var2p = 0; + double Q1 = 0., Q2 = 0.; + double Q1pi = 0., Q2pi = 0.; + double Q1k = 0., Q2k = 0.; + double Q1p = 0., Q2p = 0.; + double var1 = 0., var2 = 0., twopar_allcharge = 0.; + double var1pi = 0., var2pi = 0.; + double var1k = 0., var2k = 0.; + double var1p = 0., var2p = 0.; // cent = 0; // sampling int sample = histos.get(HIST("hZvtx_after_sel8"))->GetEntries(); - sample = sample % 15; + sample = sample % 30; // Perfroming the track selection========================================== for (auto track : inputTracks) { @@ -298,7 +899,7 @@ struct IdentifiedMeanPtFluctuations { histos.fill(HIST("tracksel"), 5); // tracks passed after pT-cut - if (!(track.pt() > 0.0 && track.pt() < 2.)) + if (!(track.pt() > 0.15 && track.pt() < 2.)) continue; // pt = 0.15 histos.fill(HIST("tracksel"), 6); @@ -362,7 +963,7 @@ struct IdentifiedMeanPtFluctuations { // pion-TPC----------------------------------------------------------------------------------- - if ((track.hasTPC() && abs(track.tpcNSigmaPi()) < 2. && (track.pt() >= 0.15 && track.pt() < 0.65) && (abs(track.rapidity(massPi)) < 0.5) && (std::abs(track.tofNSigmaEl()) > 1.0 && std::abs(track.tpcNSigmaKa()) > 2.0 && std::abs(track.tpcNSigmaPr()) > 2.0))) { + if ((track.hasTPC() && abs(track.tpcNSigmaPi()) < 2. && (track.pt() >= 0.15 && track.pt() < 0.65) && (abs(track.rapidity(massPi)) < 0.5) && (std::abs(track.tpcNSigmaEl()) > 1.0 && std::abs(track.tpcNSigmaKa()) > 2.0 && std::abs(track.tpcNSigmaPr()) > 2.0))) { histos.fill(HIST("hPtPion"), track.pt()); histos.fill(HIST("hEtaPion"), track.eta()); @@ -373,12 +974,15 @@ struct IdentifiedMeanPtFluctuations { Q1pi += track.pt(); Q2pi += (track.pt() * track.pt()); + if (track.beta() > 1) + continue; + histos.fill(HIST("hdEdx_afterselection1"), track.p(), track.tpcSignal()); histos.fill(HIST("hTOFbeta_afterselection1"), track.p(), track.beta()); } // pion->(TPC+TOF)------------------------------------------------------------------------------------ - if ((track.pt() >= 0.65 && track.pt() < 2.0) && (abs(track.rapidity(massPi)) < 0.5) && track.hasTPC() && track.hasTOF() && (std::abs(track.tofNSigmaEl()) > 1.0 && std::abs(track.tofNSigmaKa()) > 2.0 && std::abs(track.tofNSigmaPr()) > 2.0) && abs(sqrt(track.tpcNSigmaPi()) * (track.tpcNSigmaPi()) + (track.tofNSigmaPi()) * (track.tofNSigmaPi())) < 2.) { + if ((track.pt() >= 0.65 && track.pt() < 2.0) && (abs(track.rapidity(massPi)) < 0.5) && track.hasTPC() && track.hasTOF() && (std::abs(track.tofNSigmaKa()) > 2.0 && std::abs(track.tofNSigmaPr()) > 2.0) && abs(sqrt(track.tpcNSigmaPi()) * (track.tpcNSigmaPi()) + (track.tofNSigmaPi()) * (track.tofNSigmaPi())) < 2.) { histos.fill(HIST("hPtPion"), track.pt()); histos.fill(HIST("hEtaPion"), track.eta()); @@ -389,6 +993,9 @@ struct IdentifiedMeanPtFluctuations { Q1pi += track.pt(); Q2pi += (track.pt() * track.pt()); + if (track.beta() > 1) + continue; + histos.fill(HIST("hdEdx_afterselection1"), track.p(), track.tpcSignal()); histos.fill(HIST("hTOFbeta_afterselection1"), track.p(), track.beta()); } @@ -401,7 +1008,7 @@ struct IdentifiedMeanPtFluctuations { histos.fill(HIST("hTOFbeta_afterselection"), track.p(), track.beta()); } - if (track.hasTPC() && abs(track.tpcNSigmaKa()) < 2. && (track.pt() >= 0.15 && track.pt() < 0.65) && (abs(track.rapidity(massKa)) < 0.5) && (std::abs(track.tofNSigmaEl()) > 1.0 && std::abs(track.tpcNSigmaPi()) > 2.0 && std::abs(track.tpcNSigmaPr()) > 2.0)) { + if (track.hasTPC() && abs(track.tpcNSigmaKa()) < 2. && (track.pt() >= 0.15 && track.pt() < 0.65) && (abs(track.rapidity(massKa)) < 0.5) && (std::abs(track.tpcNSigmaEl()) > 1.0 && std::abs(track.tpcNSigmaPi()) > 2.0 && std::abs(track.tpcNSigmaPr()) > 2.0)) { histos.fill(HIST("hPtKaon"), track.pt()); histos.fill(HIST("hEtaKaon"), track.eta()); @@ -412,11 +1019,14 @@ struct IdentifiedMeanPtFluctuations { Q1k += track.pt(); Q2k += (track.pt() * track.pt()); + if (track.beta() > 1) + continue; + histos.fill(HIST("hdEdx_afterselection1"), track.p(), track.tpcSignal()); histos.fill(HIST("hTOFbeta_afterselection1"), track.p(), track.beta()); } - if ((track.pt() >= 0.65 && track.pt() < 2.0) && (abs(track.rapidity(massKa)) < 0.5) && track.hasTPC() && track.hasTOF() && (std::abs(track.tofNSigmaEl()) > 1.0 && std::abs(track.tofNSigmaPi()) > 2.0 && std::abs(track.tofNSigmaPr()) > 2.0) && (abs(sqrt(track.tpcNSigmaKa()) * (track.tpcNSigmaKa()) + (track.tofNSigmaKa()) * (track.tofNSigmaKa())) < 2.)) { + if ((track.pt() >= 0.65 && track.pt() < 2.0) && (abs(track.rapidity(massKa)) < 0.5) && track.hasTPC() && track.hasTOF() && (std::abs(track.tofNSigmaPi()) > 2.0 && std::abs(track.tofNSigmaPr()) > 2.0) && (abs(sqrt(track.tpcNSigmaKa()) * (track.tpcNSigmaKa()) + (track.tofNSigmaKa()) * (track.tofNSigmaKa())) < 2.)) { histos.fill(HIST("hPtKaon"), track.pt()); histos.fill(HIST("hEtaKaon"), track.eta()); @@ -427,6 +1037,9 @@ struct IdentifiedMeanPtFluctuations { Q1k += track.pt(); Q2k += (track.pt() * track.pt()); + if (track.beta() > 1) + continue; + histos.fill(HIST("hdEdx_afterselection1"), track.p(), track.tpcSignal()); histos.fill(HIST("hTOFbeta_afterselection1"), track.p(), track.beta()); } @@ -440,7 +1053,7 @@ struct IdentifiedMeanPtFluctuations { histos.fill(HIST("hTOFbeta_afterselection"), track.p(), track.beta()); } - if (track.hasTPC() && abs(track.tpcNSigmaPr()) < 2. && (track.pt() >= 0.4 && track.pt() < 0.85) && (abs(track.rapidity(massPr)) < 0.5) && (std::abs(track.tofNSigmaEl()) > 1.0 && std::abs(track.tpcNSigmaKa()) > 2.0 && std::abs(track.tpcNSigmaPi()) > 2.0)) { + if (track.hasTPC() && abs(track.tpcNSigmaPr()) < 2. && (track.pt() >= 0.4 && track.pt() < 0.85) && (abs(track.rapidity(massPr)) < 0.5) && (std::abs(track.tpcNSigmaEl()) > 1.0 && std::abs(track.tpcNSigmaKa()) > 2.0 && std::abs(track.tpcNSigmaPi()) > 2.0)) { histos.fill(HIST("hPtProton"), track.pt()); histos.fill(HIST("hEtaProton"), track.eta()); @@ -451,11 +1064,14 @@ struct IdentifiedMeanPtFluctuations { Q1p += track.pt(); Q2p += (track.pt() * track.pt()); + if (track.beta() > 1) + continue; + histos.fill(HIST("hdEdx_afterselection1"), track.p(), track.tpcSignal()); histos.fill(HIST("hTOFbeta_afterselection1"), track.p(), track.beta()); } - if ((track.pt() >= 0.85 && track.pt() < 2.0) && (abs(track.rapidity(massPr)) < 0.5) && track.hasTPC() && track.hasTOF() && (std::abs(track.tofNSigmaEl()) > 1.0 && std::abs(track.tofNSigmaKa()) > 2.0 && std::abs(track.tofNSigmaPi()) > 2.0) && (abs(sqrt(track.tpcNSigmaPr()) * (track.tpcNSigmaPr()) + (track.tofNSigmaPr()) * (track.tofNSigmaPr())) < 2.)) { + if ((track.pt() >= 0.85 && track.pt() < 2.0) && (abs(track.rapidity(massPr)) < 0.5) && track.hasTPC() && track.hasTOF() && (std::abs(track.tofNSigmaKa()) > 2.0 && std::abs(track.tofNSigmaPi()) > 2.0) && (abs(sqrt(track.tpcNSigmaPr()) * (track.tpcNSigmaPr()) + (track.tofNSigmaPr()) * (track.tofNSigmaPr())) < 2.)) { histos.fill(HIST("hPtProton"), track.pt()); histos.fill(HIST("hEtaProton"), track.eta()); @@ -466,11 +1082,14 @@ struct IdentifiedMeanPtFluctuations { Q1p += track.pt(); Q2p += (track.pt() * track.pt()); + if (track.beta() > 1) + continue; + histos.fill(HIST("hdEdx_afterselection1"), track.p(), track.tpcSignal()); histos.fill(HIST("hTOFbeta_afterselection1"), track.p(), track.beta()); } - //================================================================================================= + //==================================================================================================== } // Track loop ends! @@ -492,30 +1111,35 @@ struct IdentifiedMeanPtFluctuations { if (nChpi > 2) { var1pi = (Q1pi * Q1pi - Q2pi) / (nChpi * (nChpi - 1)); - histos.fill(HIST("hVar1pi"), sample, cent, var1pi); var2pi = (Q1pi / nChpi); - histos.fill(HIST("hVar2pi"), sample, cent, var2pi); - histos.fill(HIST("hVar2meanptpi"), cent, var2pi); } //----------------------- kaons --------------------------------------- if (nChk > 2) { var1k = (Q1k * Q1k - Q2k) / (nChk * (nChk - 1)); - histos.fill(HIST("hVar1k"), sample, cent, var1k); var2k = (Q1k / nChk); - histos.fill(HIST("hVar2k"), sample, cent, var2k); - histos.fill(HIST("hVar2meanptk"), cent, var2k); } //---------------------------- protons ---------------------------------- if (nChp > 2) { var1p = (Q1p * Q1p - Q2p) / (nChp * (nChp - 1)); - histos.fill(HIST("hVar1p"), sample, cent, var1p); var2p = (Q1p / nChp); - histos.fill(HIST("hVar2p"), sample, cent, var2p); - histos.fill(HIST("hVar2meanptp"), cent, var2p); } + //========================centrality========================================== + + histos.fill(HIST("hVar1pi"), sample, cent, var1pi); + histos.fill(HIST("hVar2pi"), sample, cent, var2pi); + histos.fill(HIST("hVar2meanptpi"), cent, var2pi); + + histos.fill(HIST("hVar1k"), sample, cent, var1k); + histos.fill(HIST("hVar2k"), sample, cent, var2k); + histos.fill(HIST("hVar2meanptk"), cent, var2k); + + histos.fill(HIST("hVar1p"), sample, cent, var1p); + histos.fill(HIST("hVar2p"), sample, cent, var2p); + histos.fill(HIST("hVar2meanptp"), cent, var2p); + //-----------------------nch------------------------------------- histos.fill(HIST("hVar1x"), sample, nCh, var1); histos.fill(HIST("hVar2x"), sample, nCh, var2); @@ -538,6 +1162,8 @@ struct IdentifiedMeanPtFluctuations { histos.fill(HIST("hVar2meanptpx"), nCh, var2p); } // event loop ends! + + PROCESS_SWITCH(IdentifiedMeanPtFluctuations, process, "process real data information", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGCF/EbyEFluctuations/Tasks/MeanPtFlucIdentified.cxx b/PWGCF/EbyEFluctuations/Tasks/MeanPtFlucIdentified.cxx deleted file mode 100644 index 6862de46af0..00000000000 --- a/PWGCF/EbyEFluctuations/Tasks/MeanPtFlucIdentified.cxx +++ /dev/null @@ -1,777 +0,0 @@ -// 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 MeanPtFlucIdentified.cxx -/// \brief Calculate EbyE fluctuations with moments method. -/// For charged particles and identified particles. -/// For RUN-3 -/// -/// \author Tanu Gahlaut - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/HistogramSpec.h" - -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" - -#include "TDatabasePDG.h" -#include "TLorentzVector.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace std; - -double massPi = TDatabasePDG::Instance()->GetParticle(211)->Mass(); -double massKa = TDatabasePDG::Instance()->GetParticle(321)->Mass(); -double massPr = TDatabasePDG::Instance()->GetParticle(2212)->Mass(); - -struct meanPtFlucId { - Configurable nPtBins{"nPtBins", 300, ""}; - Configurable nPartBins{"nPartBins", 500, ""}; - Configurable nCentBins{"nCentBins", 101, ""}; - Configurable nEtaBins{"nEtaBins", 100, ""}; - Configurable ptMax{"ptMax", 2.0, "maximum pT"}; - Configurable ptMin{"ptMin", 0.15, "minimum pT"}; - Configurable etaCut{"etaCut", 0.8, "Eta cut"}; - Configurable rapCut{"rapCut", 0.5, "Rapidity Cut"}; - Configurable dcaXYCut{"dcaXYCut", 0.12, "DCAxy cut"}; - Configurable dcaZCut{"dcaZCut", 1.0, "DCAz cut"}; - Configurable posZCut{"posZCut", 10.0, "cut for vertex Z"}; - Configurable nSigCuttpcEl{"nSigCuttpcEl", 1.5, "TPC nSigma Electron veto cut"}; - Configurable nSigCutEl{"nSigCutEl", 1.5, "TOF nSigma Electron veto cut"}; - Configurable nSigCut1{"nSigCut1", 1.0, "nSigma cut (1)"}; - Configurable nSigCut2{"nSigCut2", 2.0, "nSigma cut (2)"}; - Configurable nSigCut3{"nSigCut3", 3.0, "nSigma cut (3)"}; - Configurable nSigCut4{"nSigCut4", 4.0, "nSigma cut (4)"}; - Configurable nSigCut5{"nSigCut5", 5.0, "nSigma cut (5)"}; - Configurable nSigCut15{"nSigCut15", 1.5, "nSigma cut (1.5)"}; - Configurable nSigCut25{"nSigCut25", 2.5, "nSigma cut (2.5)"}; - Configurable piP1{"piP1", 0.65, "pion p (1)"}; - Configurable piP2{"piP2", 0.70, "pion p (2)"}; - Configurable piP3{"piP3", 1.40, "pion p (3)"}; - Configurable piP4{"piP4", 1.70, "pion p (4)"}; - Configurable kaP1{"kaP1", 0.20, "min kaon p (1)"}; - Configurable kaP2{"kaP2", 0.5, "kaon p (2)"}; - Configurable kaP3{"kaP3", 0.55, "kaon p (3)"}; - Configurable kaP4{"kaP4", 0.60, "kaon p (4)"}; - Configurable kaP5{"kaP5", 0.65, "kaon p (5)"}; - Configurable kaP6{"kaP6", 1.10, "kaon p (6)"}; - Configurable kaP7{"kaP7", 1.28, "kaon p (7)"}; - Configurable kaP8{"kaP8", 1.50, "kaon p (8)"}; - Configurable prP1{"prP1", 0.40, "min proton p (1)"}; - Configurable prP2{"prP2", 0.95, "proton p (2)"}; - Configurable prP3{"prP3", 1.00, "proton p (3)"}; - Configurable prP4{"prP4", 1.05, "proton p (4)"}; - Configurable prP5{"prP5", 1.13, "proton p (5)"}; - Configurable prP6{"prP6", 1.18, "proton p (6)"}; - ConfigurableAxis multTPCBins{"multTPCBins", {150, 0, 150}, "TPC Multiplicity bins"}; - ConfigurableAxis multFT0MBins{"multFT0MBins", {150, 0, 1500}, "Forward Multiplicity bins"}; - ConfigurableAxis dcaXYBins{"dcaXYBins", {100, -0.15, 0.15}, "dcaXY bins"}; - ConfigurableAxis dcaZBins{"dcaZBins", {100, -1.2, 1.2}, "dcaZ bins"}; - - using MyAllTracks = soa::Join; - using MyCollisions = soa::Join; - using MyMCCollisions = soa::Join; - using MyMCTracks = soa::Join; - - HistogramRegistry hist{"hist", {}, OutputObjHandlingPolicy::AnalysisObject}; - void init(InitContext const&) - { - const AxisSpec axisEvents{5, 0, 5, "Counts"}; - const AxisSpec axisEta{nEtaBins, -1., +1., "#eta"}; - const AxisSpec axisY{nEtaBins, -1., +1., "Rapidity"}; - const AxisSpec axisPt{nPtBins, 0., 3., "p_{T} (GeV/c)"}; - const AxisSpec axisP{nPtBins, 0., 3., "p (GeV/c)"}; - const AxisSpec axisPart{nPartBins, 0., 5., " "}; - const AxisSpec axisMeanPt{100, 0., 3., "M(p_{T}) (GeV/c)"}; - const AxisSpec axisMult{100, 0, 100, "N_{ch}"}; - const AxisSpec axisMultTPC{multTPCBins, "N_{TPC} "}; - const AxisSpec axisMultFT0M{multFT0MBins, "N_{FT0M}"}; - const AxisSpec axisCentFT0M{nCentBins, 0, 101, "FT0M (%)"}; - const AxisSpec axisVtxZ{80, -20., 20., "V_{Z} (cm)"}; - const AxisSpec axisDCAz{dcaZBins, "DCA_{Z} (cm)"}; - const AxisSpec axisDCAxy{dcaXYBins, "DCA_{XY} (cm)"}; - const AxisSpec axisTPCNsigma{500, -5., 5., "n #sigma_{TPC}"}; - const AxisSpec axisTOFNsigma{500, -5., 5., "n #sigma_{TOF}"}; - const AxisSpec axisTPCSignal{180, 20., 200., "#frac{dE}{dx}"}; - const AxisSpec axisTOFSignal{100, 0.2, 1.2, "TOF #beta"}; - const AxisSpec axisChi2{40, 0., 40., "Chi2"}; - const AxisSpec axisCrossedTPC{300, 0, 300, "Crossed TPC"}; - - HistogramConfigSpec QnHist({HistType::kTHnSparseD, {axisMultTPC, axisPart, axisCentFT0M}}); - HistogramConfigSpec TOFnSigmaHist({HistType::kTH2D, {axisP, axisTOFNsigma}}); - HistogramConfigSpec TOFSignalHist({HistType::kTH2D, {axisP, axisTOFSignal}}); - HistogramConfigSpec TPCnSigmaHist({HistType::kTH2D, {axisP, axisTPCNsigma}}); - HistogramConfigSpec TPCSignalHist({HistType::kTH2D, {axisP, axisTPCSignal}}); - HistogramConfigSpec TPCTOFHist({HistType::kTH2D, {axisTPCNsigma, axisTOFNsigma}}); - - // QA Plots: - hist.add("QA/before/h_Counts", "Counts", kTH1D, {axisEvents}); - hist.add("QA/before/h_VtxZ", "V_{Z}", kTH1D, {axisVtxZ}); - hist.add("QA/before/h_TPCChi2perCluster", "TPC #Chi^{2}/Cluster", kTH1D, {axisChi2}); - hist.add("QA/before/h_ITSChi2perCluster", "ITS #Chi^{2}/Cluster", kTH1D, {axisChi2}); - hist.add("QA/before/h_crossedTPC", "Crossed TPC", kTH1D, {axisCrossedTPC}); - hist.add("QA/before/h_Pt", "p_{T}", kTH1D, {axisPt}); - hist.add("QA/before/h_Eta", "#eta ", kTH1D, {axisEta}); - hist.add("QA/before/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPt}}); - hist.add("QA/before/h2_DcaZ", "DCA_{Z}", kTH2D, {{axisPt}, {axisDCAz}}); - hist.add("QA/before/h2_DcaXY", "DCA_{XY}", kTH2D, {{axisPt}, {axisDCAxy}}); - hist.add("QA/before/h_NTPC", "N_{TPC}", kTH1D, {axisMultTPC}); - hist.add("QA/before/h_NFT0M", "FT0M Multiplicity", kTH1D, {axisMultFT0M}); - hist.add("QA/before/h_Cent", "FT0M (%)", kTH1D, {axisCentFT0M}); - hist.add("QA/before/h2_NTPC_Cent", "N_{TPC} vs FT0M(%)", kTH2D, {{axisCentFT0M}, {axisMultTPC}}); - hist.add("QA/before/h2_NTPC_NFT0M", "N_{TPC} vs N_{FT0M}", kTH2D, {{axisMultFT0M}, {axisMultTPC}}); - hist.add("QA/before/h2_TPCSignal", "TPC Signal", TPCSignalHist); - hist.add("QA/before/h2_TOFSignal", "TOF Signal", TOFSignalHist); - - hist.addClone("QA/before/", "QA/after/"); - - hist.add("QA/after/p_NTPC_NFT0M", "N_{TPC} vs N_{FT0M} (Profile)", kTProfile, {{axisMultFT0M}}); - hist.add("QA/after/p_NTPC_Cent", "N_{TPC} vs FT0M(%) (Profile)", kTProfile, {{axisCentFT0M}}); - hist.add("QA/after/h2_NTPC_Nch", "N_{ch} vs N_{TPC}", kTH2D, {{axisMultTPC}, {axisMult}}); - - hist.add("QA/Pion/h_Pt", "p_{T} (TPC & TPC+TOF)", kTH1D, {axisPt}); - hist.add("QA/Pion/h_rap", "y (TPC & TPC+TOF)", kTH1D, {axisY}); - hist.add("QA/Pion/h_Eta", "Pseudorapidity (TPC & TPC+TOF)", kTH1D, {axisY}); - hist.add("QA/Pion/h2_Pt_rap", "p_{T} vs y", kTH2D, {{axisY}, {axisPt}}); - hist.add("QA/Pion/h2_DcaZ", "DCA_{z}", kTH2D, {{axisPt}, {axisDCAz}}); - hist.add("QA/Pion/h2_DcaXY", "DCA_{xy}", kTH2D, {{axisPt}, {axisDCAxy}}); - hist.add("QA/Pion/before/h2_TPCNsigma", "n #sigma_{TPC}", TPCnSigmaHist); - hist.add("QA/Pion/before/h2_TOFNsigma", "n #sigma_{TOF}", TOFnSigmaHist); - hist.add("QA/Pion/before/h2_TpcTofNsigma", "n #sigma_{TPC} vs n #sigma_{TOF}", TPCTOFHist); - hist.add("QA/Pion/h2_TPCNsigma", "n #sigma_{TPC}", TPCnSigmaHist); - hist.add("QA/Pion/h2_TPCNsigma_El", "n #sigma_{TPC, El}", TPCnSigmaHist); - hist.add("QA/Pion/h2_TOFNsigma_El", "n #sigma_{TOF, El}", TOFnSigmaHist); - hist.add("QA/Pion/h2_TOFNsigma", "n #sigma_{TOF}", TOFnSigmaHist); - hist.add("QA/Pion/h2_TpcTofNsigma", "n #sigma_{TPC} vs n #sigma_{TOF}", TPCTOFHist); - hist.add("QA/Pion/h2_TPCSignal", "TPC Signal Pions", TPCSignalHist); - hist.add("QA/Pion/h2_TOFSignal", "TOF Signal Pions", TOFSignalHist); - hist.add("QA/Pion/h2_ExpTPCSignal", "Expected TPC Signal Pions", TPCSignalHist); - - hist.addClone("QA/Pion/", "QA/Kaon/"); - hist.addClone("QA/Pion/", "QA/Proton/"); - - // Analysis Plots: - hist.add("Analysis/Charged/h_Mult", "Multiplicity", kTH1D, {axisMult}); - hist.add("Analysis/Charged/h_mean_Q1", " ", kTH1D, {axisMeanPt}); - hist.add("Analysis/Charged/p_mean_Q1_Mult_var", " ", kTProfile, {axisMultTPC}); - hist.add("Analysis/Charged/h_mean_Q1_Mult_var", " vs N_{ch} ", QnHist); - hist.add("Analysis/Charged/h_mean_Q1_Mult_skew", " vs N_{ch} ", QnHist); - hist.add("Analysis/Charged/h_mean_Q1_Mult_kurto", " vs N_{ch} ", QnHist); - hist.add("Analysis/Charged/p_twopart_Mult_var", " ", kTProfile, {axisMultTPC}); - hist.add("Analysis/Charged/h_twopart_Mult_var", "Twopart vs N_{ch} ", QnHist); - hist.add("Analysis/Charged/h_twopart_Mult_skew", "Twopart vs N_{ch} ", QnHist); - hist.add("Analysis/Charged/h_twopart_Mult_kurto", "Twopart vs N_{ch} ", QnHist); - hist.add("Analysis/Charged/h_threepart_Mult_skew", "Threepart vs N_{ch} ", QnHist); - hist.add("Analysis/Charged/h_threepart_Mult_kurto", "Threepart vs N_{ch} ", QnHist); - hist.add("Analysis/Charged/h_fourpart_Mult_kurto", "Fourpart vs N_{ch} ", QnHist); - - hist.addClone("Analysis/Charged/", "Analysis/Pion/"); - hist.addClone("Analysis/Charged/", "Analysis/Kaon/"); - hist.addClone("Analysis/Charged/", "Analysis/Proton/"); - - hist.add("QA/Reco/Charged/h_Pt", "p_{T} ", kTH1D, {axisPt}); - hist.add("QA/Reco/Charged/h_Eta", "Pseudorapidity ", kTH1D, {axisEta}); - hist.add("QA/Reco/Pion/h_Pt", "p_{T} ", kTH1D, {axisPt}); - hist.add("QA/Reco/Pion/h_Eta", "Pseudorapidity ", kTH1D, {axisEta}); - hist.add("QA/Reco/Pion/h_y", "Rapidity ", kTH1D, {axisY}); - hist.add("QA/Reco/Pion/h2_tofSignal", "TOF Signal ", TOFSignalHist); - hist.add("QA/Reco/Pion/h2_tpcSignal", "TPC Signal #frac{dE}{dx}", TPCSignalHist); - - hist.addClone("QA/Reco/Pion/", "QA/Reco/Kaon/"); - hist.addClone("QA/Reco/Pion/", "QA/Reco/Proton/"); - - hist.add("Gen/Counts", "Counts", kTH1D, {axisEvents}); - hist.add("Gen/vtxZ", "Vertex Z ", kTH1D, {axisVtxZ}); - hist.add("Gen/NTPC", "Mid rapidity Multiplicity", kTH1D, {axisMultTPC}); - hist.add("Gen/Charged/h_Mult", "Multiplicity", kTH1D, {axisMult}); - hist.add("Gen/Charged/h_Pt", "p_{T} ", kTH1D, {axisPt}); - hist.add("Gen/Charged/h_mean_pt", " ", kTH1D, {axisMeanPt}); - hist.add("Gen/Charged/h_mean_Q1_Mult_var", " vs N_{ch} ", kTProfile, {axisMultTPC}); - hist.add("Gen/Charged/h_twopart_Mult_var", "Twopart vs N_{ch} ", kTProfile, {axisMultTPC}); - - hist.addClone("Gen/Charged/", "Gen/Pion/"); - hist.addClone("Gen/Charged/", "Gen/Kaon/"); - hist.addClone("Gen/Charged/", "Gen/Proton/"); - } - - template - bool selRun3Col(T const& col) - { - if (std::abs(col.posZ()) > posZCut) - return false; - - if (!col.sel8()) - return false; - - return true; - } - - template - bool selTrack(T const& track) - { - if (!track.isGlobalTrackWoPtEta()) - return false; - - if (track.pt() < ptMin) - return false; - - if (track.pt() > ptMax) - return false; - - if (track.sign() == 0) - return false; - - if (std::abs(track.dcaZ()) > dcaZCut) - return false; - - if (std::abs(track.dcaXY()) > dcaXYCut) - return false; - - return true; - } - - template - bool selPions(T const& track) - { - if (((!track.hasTOF()) && std::abs(track.tpcNSigmaEl()) > nSigCuttpcEl && - ((std::abs(track.tpcNSigmaPi()) < nSigCut3 && track.p() <= piP1) || (std::abs(track.tpcNSigmaPi()) < nSigCut2 && track.p() > piP1 && track.p() <= piP2))) || - (track.hasTOF() && std::abs(track.tpcNSigmaPi()) < nSigCut4 && std::abs(track.tofNSigmaEl()) > nSigCutEl && - ((std::abs(track.tofNSigmaPi()) < nSigCut3 && track.p() <= piP3) || (std::abs(track.tofNSigmaPi()) < nSigCut25 && track.p() > piP3 && track.p() <= piP4) || (std::abs(track.tofNSigmaPi()) < nSigCut2 && track.p() > piP4)))) { - if (abs(track.rapidity(massPi)) < rapCut) - return true; - } - - return false; - } - - template - bool selKaons(T const& track) - { - if (((!track.hasTOF()) && std::abs(track.tpcNSigmaEl()) > nSigCuttpcEl && - ((std::abs(track.tpcNSigmaKa()) < nSigCut3 && track.pt() > kaP1 && track.p() <= kaP2) || (std::abs(track.tpcNSigmaKa()) < nSigCut25 && track.p() > kaP2 && track.p() <= kaP3) || (std::abs(track.tpcNSigmaKa()) < nSigCut2 && track.p() > kaP3 && track.p() <= kaP4) || (std::abs(track.tpcNSigmaKa()) < nSigCut15 && track.p() > kaP4 && track.p() <= kaP5))) || - (track.hasTOF() && std::abs(track.tpcNSigmaKa()) < nSigCut4 && std::abs(track.tofNSigmaEl()) > nSigCutEl && - ((std::abs(track.tofNSigmaKa()) < nSigCut3 && track.pt() > kaP1 && track.p() <= kaP6) || (std::abs(track.tofNSigmaKa()) < nSigCut2 && track.p() > kaP6 && track.p() <= kaP7) || (std::abs(track.tofNSigmaKa()) < nSigCut15 && track.p() > kaP7 && track.p() <= kaP8) || (std::abs(track.tofNSigmaKa()) < nSigCut1 && track.p() > kaP8)))) { - if (abs(track.rapidity(massKa)) < rapCut) - return true; - } - - return false; - } - - template - bool selProtons(T const& track) - { - if (((!track.hasTOF()) && std::abs(track.tpcNSigmaEl()) > nSigCuttpcEl && - ((std::abs(track.tpcNSigmaPr()) < nSigCut3 && track.pt() > prP1 && track.p() <= prP2) || (std::abs(track.tpcNSigmaPr()) < nSigCut25 && track.p() > prP2 && track.p() <= prP3) || (std::abs(track.tpcNSigmaPr()) < nSigCut2 && track.p() > prP3 && track.p() <= prP4) || (std::abs(track.tpcNSigmaPr()) < nSigCut15 && track.p() > prP4 && track.p() <= prP5) || (std::abs(track.tpcNSigmaPr()) < nSigCut1 && track.p() > prP5 && track.p() <= prP6))) || - (track.hasTOF() && std::abs(track.tpcNSigmaPr()) < nSigCut4 && std::abs(track.tofNSigmaEl()) > nSigCutEl && std::abs(track.tofNSigmaPr()) < nSigCut3 && track.pt() > prP1)) { - if (abs(track.rapidity(massPr)) < rapCut) - return true; - } - - return false; - } - - void moments(double pt, double* Q1, double* Q2, double* Q3, double* Q4) - { - *Q1 += pt; - *Q2 += pt * pt; - *Q3 += pt * pt * pt; - *Q4 += pt * pt * pt * pt; - } - - void parts(double Q1, double Q2, double Q3, double Q4, int N, double* mean_Q1, double* twopart, double* threepart, double* fourpart) - { - if (N > 1) { - *mean_Q1 = Q1 / static_cast(N); - *twopart = ((Q1 * Q1) - Q2) / (static_cast(N) * (static_cast(N) - 1)); - } - if (N > 2) { - *threepart = ((Q1 * Q1 * Q1) - (3 * Q2 * Q1) + 2 * Q3) / (static_cast(N) * (static_cast(N) - 1) * (static_cast(N) - 2)); - } - if (N > 3) { - *fourpart = ((Q1 * Q1 * Q1 * Q1) - (6 * Q2 * Q1 * Q1) + (3 * Q2 * Q2) + (8 * Q3 * Q1) - 6 * Q4) / (static_cast(N) * (static_cast(N) - 1) * (static_cast(N) - 2) * (static_cast(N) - 3)); - } - } - - template - void FillHistos(T const& col, U const& tracks) - { - int N_Pi = 0, N_Ka = 0, N_Pr = 0; - int Nch = 0, NTPC = 0, N_FT0C = 0; - double Cent_FT0C = 0; - double pt_ch = 0, Q1_ch = 0, Q2_ch = 0, Q3_ch = 0, Q4_ch = 0; - double pt_Pi = 0, Q1_Pi = 0, Q2_Pi = 0, Q3_Pi = 0, Q4_Pi = 0; - double pt_Pr = 0, Q1_Pr = 0, Q2_Pr = 0, Q3_Pr = 0, Q4_Pr = 0; - double pt_Ka = 0, Q1_Ka = 0, Q2_Ka = 0, Q3_Ka = 0, Q4_Ka = 0; - double mean_Q1_Ch, mean_Q1_Pi, mean_Q1_Ka, mean_Q1_Pr; - double twopart_Ch, twopart_Pi, twopart_Ka, twopart_Pr; - double threepart_Ch, threepart_Pi, threepart_Ka, threepart_Pr; - double fourpart_Ch, fourpart_Pi, fourpart_Ka, fourpart_Pr; - - for (auto& track : tracks) { - if (!selTrack(track)) - continue; - - if constexpr (DataFlag) { - if (std::abs(track.eta()) < 0.8) { - Nch++; - pt_ch = track.pt(); - moments(pt_ch, &Q1_ch, &Q2_ch, &Q3_ch, &Q4_ch); - - hist.fill(HIST("QA/after/h_Eta"), track.eta()); - hist.fill(HIST("QA/after/h_Pt"), track.pt()); - hist.fill(HIST("QA/after/h2_Pt_Eta"), track.eta(), track.pt()); - hist.fill(HIST("QA/after/h2_DcaXY"), track.pt(), track.dcaXY()); - hist.fill(HIST("QA/after/h2_DcaZ"), track.pt(), track.dcaZ()); - - hist.fill(HIST("QA/after/h_TPCChi2perCluster"), track.tpcChi2NCl()); - hist.fill(HIST("QA/after/h_ITSChi2perCluster"), track.itsChi2NCl()); - hist.fill(HIST("QA/after/h_crossedTPC"), track.tpcNClsCrossedRows()); - } - hist.fill(HIST("QA/before/h2_TOFSignal"), track.p(), track.beta()); - hist.fill(HIST("QA/before/h2_TPCSignal"), track.p(), track.tpcSignal()); - - hist.fill(HIST("QA/Pion/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaPi()); - hist.fill(HIST("QA/Pion/before/h2_TOFNsigma"), track.p(), track.tofNSigmaPi()); - hist.fill(HIST("QA/Pion/before/h2_TpcTofNsigma"), track.tpcNSigmaPi(), track.tofNSigmaPi()); - hist.fill(HIST("QA/Proton/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaPr()); - hist.fill(HIST("QA/Proton/before/h2_TOFNsigma"), track.p(), track.tofNSigmaPr()); - hist.fill(HIST("QA/Proton/before/h2_TpcTofNsigma"), track.tpcNSigmaPr(), track.tofNSigmaPr()); - hist.fill(HIST("QA/Kaon/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaKa()); - hist.fill(HIST("QA/Kaon/before/h2_TOFNsigma"), track.p(), track.tofNSigmaKa()); - hist.fill(HIST("QA/Kaon/before/h2_TpcTofNsigma"), track.tpcNSigmaKa(), track.tofNSigmaKa()); - - // For Pions: - if (selPions(track)) { - N_Pi++; - pt_Pi = track.pt(); - moments(pt_Pi, &Q1_Pi, &Q2_Pi, &Q3_Pi, &Q4_Pi); - hist.fill(HIST("QA/Pion/h_Pt"), track.pt()); - hist.fill(HIST("QA/Pion/h_Eta"), track.eta()); - hist.fill(HIST("QA/Pion/h_rap"), track.rapidity(massPi)); - hist.fill(HIST("QA/Pion/h2_Pt_rap"), track.rapidity(massPi), track.pt()); - hist.fill(HIST("QA/Pion/h2_DcaXY"), track.pt(), track.dcaXY()); - hist.fill(HIST("QA/Pion/h2_DcaZ"), track.pt(), track.dcaZ()); - - hist.fill(HIST("QA/Pion/h2_TPCNsigma_El"), track.p(), track.tpcNSigmaEl()); - hist.fill(HIST("QA/Pion/h2_TOFNsigma_El"), track.p(), track.tofNSigmaEl()); - hist.fill(HIST("QA/Pion/h2_TPCNsigma"), track.p(), track.tpcNSigmaPi()); - hist.fill(HIST("QA/Pion/h2_TOFNsigma"), track.p(), track.tofNSigmaPi()); - hist.fill(HIST("QA/Pion/h2_TpcTofNsigma"), track.tpcNSigmaPi(), track.tofNSigmaPi()); - hist.fill(HIST("QA/Pion/h2_TOFSignal"), track.p(), track.beta()); - hist.fill(HIST("QA/Pion/h2_TPCSignal"), track.p(), track.tpcSignal()); - hist.fill(HIST("QA/Pion/h2_ExpTPCSignal"), track.p(), track.tpcExpSignalPi(track.tpcSignal())); - hist.fill(HIST("QA/after/h2_TOFSignal"), track.p(), track.beta()); - hist.fill(HIST("QA/after/h2_TPCSignal"), track.p(), track.tpcSignal()); - } - - // For Kaons: - if (selKaons(track)) { - N_Ka++; - pt_Ka = track.pt(); - moments(pt_Ka, &Q1_Ka, &Q2_Ka, &Q3_Ka, &Q4_Ka); - hist.fill(HIST("QA/Kaon/h_Pt"), track.pt()); - hist.fill(HIST("QA/Kaon/h_Eta"), track.eta()); - hist.fill(HIST("QA/Kaon/h_rap"), track.rapidity(massKa)); - hist.fill(HIST("QA/Kaon/h2_Pt_rap"), track.rapidity(massKa), track.pt()); - hist.fill(HIST("QA/Kaon/h2_DcaXY"), track.pt(), track.dcaXY()); - hist.fill(HIST("QA/Kaon/h2_DcaZ"), track.pt(), track.dcaZ()); - - hist.fill(HIST("QA/Kaon/h2_TPCNsigma_El"), track.p(), track.tpcNSigmaEl()); - hist.fill(HIST("QA/Kaon/h2_TOFNsigma_El"), track.p(), track.tofNSigmaEl()); - hist.fill(HIST("QA/Kaon/h2_TPCNsigma"), track.p(), track.tpcNSigmaKa()); - hist.fill(HIST("QA/Kaon/h2_TOFNsigma"), track.p(), track.tofNSigmaKa()); - hist.fill(HIST("QA/Kaon/h2_TpcTofNsigma"), track.tpcNSigmaKa(), track.tofNSigmaKa()); - hist.fill(HIST("QA/Kaon/h2_TOFSignal"), track.p(), track.beta()); - hist.fill(HIST("QA/Kaon/h2_TPCSignal"), track.p(), track.tpcSignal()); - hist.fill(HIST("QA/Kaon/h2_ExpTPCSignal"), track.p(), track.tpcExpSignalKa(track.tpcSignal())); - hist.fill(HIST("QA/after/h2_TOFSignal"), track.p(), track.beta()); - hist.fill(HIST("QA/after/h2_TPCSignal"), track.p(), track.tpcSignal()); - } - - // For Protons: - if (selProtons(track)) { - N_Pr++; - pt_Pr = track.pt(); - moments(pt_Pr, &Q1_Pr, &Q2_Pr, &Q3_Pr, &Q4_Pr); - hist.fill(HIST("QA/Proton/h_Pt"), track.pt()); - hist.fill(HIST("QA/Proton/h_Eta"), track.eta()); - hist.fill(HIST("QA/Proton/h_rap"), track.rapidity(massPr)); - hist.fill(HIST("QA/Proton/h2_Pt_rap"), track.rapidity(massPr), track.pt()); - hist.fill(HIST("QA/Proton/h2_DcaZ"), track.pt(), track.dcaZ()); - hist.fill(HIST("QA/Proton/h2_DcaXY"), track.pt(), track.dcaXY()); - - hist.fill(HIST("QA/Proton/h2_TPCNsigma_El"), track.p(), track.tpcNSigmaEl()); - hist.fill(HIST("QA/Proton/h2_TOFNsigma_El"), track.p(), track.tofNSigmaEl()); - hist.fill(HIST("QA/Proton/h2_TPCNsigma"), track.p(), track.tpcNSigmaPr()); - hist.fill(HIST("QA/Proton/h2_TOFNsigma"), track.p(), track.tofNSigmaPr()); - hist.fill(HIST("QA/Proton/h2_TpcTofNsigma"), track.tpcNSigmaPr(), track.tofNSigmaPr()); - hist.fill(HIST("QA/Proton/h2_TPCSignal"), track.p(), track.tpcSignal()); - hist.fill(HIST("QA/Proton/h2_TOFSignal"), track.p(), track.beta()); - hist.fill(HIST("QA/Proton/h2_ExpTPCSignal"), track.p(), track.tpcExpSignalPr(track.tpcSignal())); - hist.fill(HIST("QA/after/h2_TPCSignal"), track.p(), track.tpcSignal()); - hist.fill(HIST("QA/after/h2_TOFSignal"), track.p(), track.beta()); - } - } else if constexpr (RecoFlag) { - if (track.has_mcParticle() && track.mcParticle().isPhysicalPrimary()) { - if (std::abs(track.eta()) < 0.8) { - Nch++; - pt_ch = track.pt(); - moments(pt_ch, &Q1_ch, &Q2_ch, &Q3_ch, &Q4_ch); - hist.fill(HIST("QA/Reco/Charged/h_Pt"), track.pt()); - hist.fill(HIST("QA/Reco/Charged/h_Eta"), track.eta()); - } - - if (std::abs(track.mcParticle().pdgCode()) == 211 && selPions(track)) { - N_Pi++; - pt_Pi = track.pt(); - moments(pt_Pi, &Q1_Pi, &Q2_Pi, &Q3_Pi, &Q4_Pi); - hist.fill(HIST("QA/Reco/Pion/h_Pt"), track.pt()); - hist.fill(HIST("QA/Reco/Pion/h_Eta"), track.eta()); - hist.fill(HIST("QA/Reco/Pion/h_y"), track.rapidity(massPi)); - hist.fill(HIST("QA/Reco/Pion/h2_tpcSignal"), track.p(), track.tpcSignal()); - hist.fill(HIST("QA/Reco/Pion/h2_tofSignal"), track.p(), track.beta()); - } - - if (std::abs(track.mcParticle().pdgCode()) == 321 && selKaons(track)) { - N_Ka++; - pt_Ka = track.pt(); - moments(pt_Ka, &Q1_Ka, &Q2_Ka, &Q3_Ka, &Q4_Ka); - hist.fill(HIST("QA/Reco/Kaon/h_Pt"), track.pt()); - hist.fill(HIST("QA/Reco/Kaon/h_Eta"), track.eta()); - hist.fill(HIST("QA/Reco/Kaon/h_y"), track.rapidity(massKa)); - hist.fill(HIST("QA/Reco/Kaon/h2_tpcSignal"), track.p(), track.tpcSignal()); - hist.fill(HIST("QA/Reco/Kaon/h2_tofSignal"), track.p(), track.beta()); - } - - if (std::abs(track.mcParticle().pdgCode()) == 2212 && selProtons(track)) { - N_Pr++; - pt_Pr = track.pt(); - moments(pt_Pr, &Q1_Pr, &Q2_Pr, &Q3_Pr, &Q4_Pr); - hist.fill(HIST("QA/Reco/Proton/h_Pt"), track.pt()); - hist.fill(HIST("QA/Reco/Proton/h_Eta"), track.eta()); - hist.fill(HIST("QA/Reco/Proton/h_y"), track.rapidity(massPr)); - hist.fill(HIST("QA/Reco/Proton/h2_tpcSignal"), track.p(), track.tpcSignal()); - hist.fill(HIST("QA/Reco/Proton/h2_tofSignal"), track.p(), track.beta()); - } - } - } - } - - N_FT0C = col.multFT0C(); - Cent_FT0C = col.centFT0C(); - NTPC = col.multNTracksHasTPC(); - - hist.fill(HIST("QA/after/h_VtxZ"), col.posZ()); - hist.fill(HIST("QA/after/h_Counts"), 2); - hist.fill(HIST("QA/after/h_NTPC"), NTPC); - hist.fill(HIST("QA/after/h_Cent"), Cent_FT0C); - hist.fill(HIST("QA/after/h_NFT0M"), N_FT0C); - hist.fill(HIST("QA/after/h2_NTPC_NFT0M"), N_FT0C, NTPC); - hist.fill(HIST("QA/after/h2_NTPC_Cent"), Cent_FT0C, NTPC); - hist.fill(HIST("QA/after/p_NTPC_Cent"), Cent_FT0C, NTPC); - hist.fill(HIST("QA/after/p_NTPC_NFT0M"), N_FT0C, NTPC); - hist.fill(HIST("QA/after/h2_NTPC_Nch"), NTPC, Nch); - - static constexpr std::string_view dire[] = {"Analysis/Charged/", "Analysis/Pion/", "Analysis/Kaon/", "Analysis/Proton/"}; - - hist.fill(HIST(dire[0]) + HIST("h_Mult"), Nch); - hist.fill(HIST(dire[1]) + HIST("h_Mult"), N_Pi); - hist.fill(HIST(dire[2]) + HIST("h_Mult"), N_Ka); - hist.fill(HIST(dire[3]) + HIST("h_Mult"), N_Pr); - - parts(Q1_ch, Q2_ch, Q3_ch, Q4_ch, Nch, &mean_Q1_Ch, &twopart_Ch, &threepart_Ch, &fourpart_Ch); - if (Nch > 1) { - if (mean_Q1_Ch != 0) { - hist.fill(HIST(dire[0]) + HIST("h_mean_Q1"), mean_Q1_Ch); - hist.fill(HIST(dire[0]) + HIST("p_mean_Q1_Mult_var"), NTPC, mean_Q1_Ch); - hist.fill(HIST(dire[0]) + HIST("h_mean_Q1_Mult_var"), NTPC, mean_Q1_Ch, Cent_FT0C); - } - if (twopart_Ch != 0) { - hist.fill(HIST(dire[0]) + HIST("p_twopart_Mult_var"), NTPC, twopart_Ch); - hist.fill(HIST(dire[0]) + HIST("h_twopart_Mult_var"), NTPC, twopart_Ch, Cent_FT0C); - } - } - if (Nch > 2) { - if (mean_Q1_Ch != 0) - hist.fill(HIST(dire[0]) + HIST("h_mean_Q1_Mult_skew"), NTPC, mean_Q1_Ch, Cent_FT0C); - if (twopart_Ch != 0) - hist.fill(HIST(dire[0]) + HIST("h_twopart_Mult_skew"), NTPC, twopart_Ch, Cent_FT0C); - if (threepart_Ch != 0) - hist.fill(HIST(dire[0]) + HIST("h_threepart_Mult_skew"), NTPC, threepart_Ch, Cent_FT0C); - } - - if (Nch > 3) { - if (mean_Q1_Ch != 0) - hist.fill(HIST(dire[0]) + HIST("h_mean_Q1_Mult_kurto"), NTPC, mean_Q1_Ch, Cent_FT0C); - if (twopart_Ch != 0) - hist.fill(HIST(dire[0]) + HIST("h_twopart_Mult_kurto"), NTPC, twopart_Ch, Cent_FT0C); - if (threepart_Ch != 0) - hist.fill(HIST(dire[0]) + HIST("h_threepart_Mult_kurto"), NTPC, threepart_Ch, Cent_FT0C); - if (fourpart_Ch != 0) - hist.fill(HIST(dire[0]) + HIST("h_fourpart_Mult_kurto"), NTPC, fourpart_Ch, Cent_FT0C); - } - - parts(Q1_Pi, Q2_Pi, Q3_Pi, Q4_Pi, N_Pi, &mean_Q1_Pi, &twopart_Pi, &threepart_Pi, &fourpart_Pi); - if (N_Pi > 1) { - if (mean_Q1_Pi != 0) { - hist.fill(HIST(dire[1]) + HIST("h_mean_Q1"), mean_Q1_Pi); - hist.fill(HIST(dire[1]) + HIST("p_mean_Q1_Mult_var"), NTPC, mean_Q1_Pi); - hist.fill(HIST(dire[1]) + HIST("h_mean_Q1_Mult_var"), NTPC, mean_Q1_Pi, Cent_FT0C); - } - if (twopart_Pi != 0) { - hist.fill(HIST(dire[1]) + HIST("p_twopart_Mult_var"), NTPC, twopart_Pi); - hist.fill(HIST(dire[1]) + HIST("h_twopart_Mult_var"), NTPC, twopart_Pi, Cent_FT0C); - } - } - - if (N_Pi > 2) { - if (mean_Q1_Pi != 0) - hist.fill(HIST(dire[1]) + HIST("h_mean_Q1_Mult_skew"), NTPC, mean_Q1_Pi, Cent_FT0C); - if (twopart_Pi != 0) - hist.fill(HIST(dire[1]) + HIST("h_twopart_Mult_skew"), NTPC, twopart_Pi, Cent_FT0C); - if (threepart_Pi != 0) - hist.fill(HIST(dire[1]) + HIST("h_threepart_Mult_skew"), NTPC, threepart_Pi, Cent_FT0C); - } - - if (N_Pi > 3) { - if (mean_Q1_Pi != 0) - hist.fill(HIST(dire[1]) + HIST("h_mean_Q1_Mult_kurto"), NTPC, mean_Q1_Pi, Cent_FT0C); - if (twopart_Pi != 0) - hist.fill(HIST(dire[1]) + HIST("h_twopart_Mult_kurto"), NTPC, twopart_Pi, Cent_FT0C); - if (threepart_Pi != 0) - hist.fill(HIST(dire[1]) + HIST("h_threepart_Mult_kurto"), NTPC, threepart_Pi, Cent_FT0C); - if (fourpart_Pi != 0) - hist.fill(HIST(dire[1]) + HIST("h_fourpart_Mult_kurto"), NTPC, fourpart_Pi, Cent_FT0C); - } - - parts(Q1_Ka, Q2_Ka, Q3_Ka, Q4_Ka, N_Ka, &mean_Q1_Ka, &twopart_Ka, &threepart_Ka, &fourpart_Ka); - if (N_Ka > 1) { - if (mean_Q1_Ka != 0) { - hist.fill(HIST(dire[2]) + HIST("h_mean_Q1"), mean_Q1_Ka); - hist.fill(HIST(dire[2]) + HIST("p_mean_Q1_Mult_var"), NTPC, mean_Q1_Ka); - hist.fill(HIST(dire[2]) + HIST("h_mean_Q1_Mult_var"), NTPC, mean_Q1_Ka, Cent_FT0C); - } - if (twopart_Ka != 0) { - hist.fill(HIST(dire[2]) + HIST("p_twopart_Mult_var"), NTPC, twopart_Ka); - hist.fill(HIST(dire[2]) + HIST("h_twopart_Mult_var"), NTPC, twopart_Ka, Cent_FT0C); - } - } - if (N_Ka > 2) { - if (mean_Q1_Ka != 0) - hist.fill(HIST(dire[2]) + HIST("h_mean_Q1_Mult_skew"), NTPC, mean_Q1_Ka, Cent_FT0C); - if (twopart_Ka != 0) - hist.fill(HIST(dire[2]) + HIST("h_twopart_Mult_skew"), NTPC, twopart_Ka, Cent_FT0C); - if (threepart_Ka != 0) - hist.fill(HIST(dire[2]) + HIST("h_threepart_Mult_skew"), NTPC, threepart_Ka, Cent_FT0C); - } - - if (N_Ka > 3) { - if (mean_Q1_Ka != 0) - hist.fill(HIST(dire[2]) + HIST("h_mean_Q1_Mult_kurto"), NTPC, mean_Q1_Ka, Cent_FT0C); - if (twopart_Ka != 0) - hist.fill(HIST(dire[2]) + HIST("h_twopart_Mult_kurto"), NTPC, twopart_Ka, Cent_FT0C); - if (threepart_Ka != 0) - hist.fill(HIST(dire[2]) + HIST("h_threepart_Mult_kurto"), NTPC, threepart_Ka, Cent_FT0C); - if (fourpart_Ka != 0) - hist.fill(HIST(dire[2]) + HIST("h_fourpart_Mult_kurto"), NTPC, fourpart_Ka, Cent_FT0C); - } - - parts(Q1_Pr, Q2_Pr, Q3_Pr, Q4_Pr, N_Pr, &mean_Q1_Pr, &twopart_Pr, &threepart_Pr, &fourpart_Pr); - if (N_Pr > 1) { - if (mean_Q1_Pr != 0) { - hist.fill(HIST(dire[3]) + HIST("h_mean_Q1"), mean_Q1_Pr); - hist.fill(HIST(dire[3]) + HIST("p_mean_Q1_Mult_var"), NTPC, mean_Q1_Pr); - hist.fill(HIST(dire[3]) + HIST("h_mean_Q1_Mult_var"), NTPC, mean_Q1_Pr, Cent_FT0C); - } - if (twopart_Pr != 0) { - hist.fill(HIST(dire[3]) + HIST("p_twopart_Mult_var"), NTPC, twopart_Pr); - hist.fill(HIST(dire[3]) + HIST("h_twopart_Mult_var"), NTPC, twopart_Pr, Cent_FT0C); - } - } - - if (N_Pr > 2) { - if (mean_Q1_Pr != 0) - hist.fill(HIST(dire[3]) + HIST("h_mean_Q1_Mult_skew"), NTPC, mean_Q1_Pr, Cent_FT0C); - if (twopart_Pr != 0) - hist.fill(HIST(dire[3]) + HIST("h_twopart_Mult_skew"), NTPC, twopart_Pr, Cent_FT0C); - if (threepart_Pr != 0) - hist.fill(HIST(dire[3]) + HIST("h_threepart_Mult_skew"), NTPC, threepart_Pr, Cent_FT0C); - } - - if (N_Pr > 3) { - if (mean_Q1_Pr != 0) - hist.fill(HIST(dire[3]) + HIST("h_mean_Q1_Mult_kurto"), NTPC, mean_Q1_Pr, Cent_FT0C); - if (twopart_Pr != 0) - hist.fill(HIST(dire[3]) + HIST("h_twopart_Mult_kurto"), NTPC, twopart_Pr, Cent_FT0C); - if (threepart_Pr != 0) - hist.fill(HIST(dire[3]) + HIST("h_threepart_Mult_kurto"), NTPC, threepart_Pr, Cent_FT0C); - if (fourpart_Pr != 0) - hist.fill(HIST(dire[3]) + HIST("h_fourpart_Mult_kurto"), NTPC, fourpart_Pr, Cent_FT0C); - } - } - - void process_Run3(MyCollisions::iterator const& col, MyAllTracks const& tracks) - { - // Before Collision and Track Cuts: - for (auto& myTrack : tracks) { - hist.fill(HIST("QA/before/h_Eta"), myTrack.eta()); - hist.fill(HIST("QA/before/h_Pt"), myTrack.pt()); - hist.fill(HIST("QA/before/h2_Pt_Eta"), myTrack.eta(), myTrack.pt()); - hist.fill(HIST("QA/before/h_TPCChi2perCluster"), myTrack.tpcChi2NCl()); - hist.fill(HIST("QA/before/h_ITSChi2perCluster"), myTrack.itsChi2NCl()); - hist.fill(HIST("QA/before/h_crossedTPC"), myTrack.tpcNClsCrossedRows()); - hist.fill(HIST("QA/before/h2_DcaXY"), myTrack.pt(), myTrack.dcaXY()); - hist.fill(HIST("QA/before/h2_DcaZ"), myTrack.pt(), myTrack.dcaZ()); - } - hist.fill(HIST("QA/before/h_VtxZ"), col.posZ()); - hist.fill(HIST("QA/before/h_Counts"), 2); - - hist.fill(HIST("QA/before/h_NTPC"), col.multTPC()); - hist.fill(HIST("QA/before/h_Cent"), col.centFT0C()); - hist.fill(HIST("QA/before/h_NFT0M"), col.multFT0M()); - hist.fill(HIST("QA/before/h2_NTPC_NFT0M"), col.multFT0M(), col.multTPC()); - hist.fill(HIST("QA/before/h2_NTPC_Cent"), col.centFT0C(), col.multTPC()); - - // After Collision and Track Cuts: - if (selRun3Col(col)) { - FillHistos(col, tracks); - } - } - PROCESS_SWITCH(meanPtFlucId, process_Run3, "Process for Run3", false); - - void process_MCRecoRun3(MyMCCollisions::iterator const& col, aod::McCollisions const&, MyMCTracks const& tracks, aod::McParticles const&) - { - if (selRun3Col(col)) { - FillHistos(col, tracks); - } - } - PROCESS_SWITCH(meanPtFlucId, process_MCRecoRun3, "process MC Reconstructed Run-3", true); - - void process_MCGen(soa::Join::iterator const& mccol, aod::McParticles const& McParticles) - { - int N_Pi = 0, N_Ka = 0, N_Pr = 0; - int Nch = 0, NTPC = 0; - double pt_ch = 0, Q1_ch = 0, Q2_ch = 0, Q3_ch = 0, Q4_ch = 0; - double pt_Pi = 0, Q1_Pi = 0, Q2_Pi = 0, Q3_Pi = 0, Q4_Pi = 0; - double pt_Pr = 0, Q1_Pr = 0, Q2_Pr = 0, Q3_Pr = 0, Q4_Pr = 0; - double pt_Ka = 0, Q1_Ka = 0, Q2_Ka = 0, Q3_Ka = 0, Q4_Ka = 0; - double mean_Q1_Ch, mean_Q1_Pi, mean_Q1_Ka, mean_Q1_Pr; - double twopart_Ch, twopart_Pi, twopart_Ka, twopart_Pr; - double threepart_Ch, threepart_Pi, threepart_Ka, threepart_Pr; - double fourpart_Ch, fourpart_Pi, fourpart_Ka, fourpart_Pr; - - if (abs(mccol.posZ()) > posZCut) - return; - - for (auto& mcParticle : McParticles) { - if (mcParticle.isPhysicalPrimary() && mcParticle.pt() > ptMin && mcParticle.pt() < ptMax && abs(mcParticle.y()) < rapCut) { - Nch++; - pt_ch = mcParticle.pt(); - moments(pt_ch, &Q1_ch, &Q2_ch, &Q3_ch, &Q4_ch); - hist.fill(HIST("Gen/Charged/h_Pt"), mcParticle.pt()); - - if (std::abs(mcParticle.pdgCode()) == 211) { - N_Pi++; - pt_Pi = mcParticle.pt(); - moments(pt_Pi, &Q1_Pi, &Q2_Pi, &Q3_Pi, &Q4_Pi); - hist.fill(HIST("Gen/Pion/h_Pt"), mcParticle.pt()); - } - - if (std::abs(mcParticle.pdgCode()) == 321) { - N_Ka++; - pt_Ka = mcParticle.pt(); - moments(pt_Ka, &Q1_Ka, &Q2_Ka, &Q3_Ka, &Q4_Ka); - hist.fill(HIST("Gen/Kaon/h_Pt"), mcParticle.pt()); - } - - if (std::abs(mcParticle.pdgCode()) == 2212) { - N_Pr++; - pt_Pr = mcParticle.pt(); - moments(pt_Pr, &Q1_Pr, &Q2_Pr, &Q3_Pr, &Q4_Pr); - hist.fill(HIST("Gen/Proton/h_Pt"), mcParticle.pt()); - } - } - } - NTPC = mccol.multMCNParticlesEta08(); - hist.fill(HIST("Gen/Counts"), 2); - hist.fill(HIST("Gen/vtxZ"), mccol.posZ()); - hist.fill(HIST("Gen/NTPC"), NTPC); - - static constexpr std::string_view dire[] = {"Gen/Charged/", "Gen/Pion/", "Gen/Kaon/", "Gen/Proton/"}; - - hist.fill(HIST(dire[0]) + HIST("h_Mult"), Nch); - hist.fill(HIST(dire[1]) + HIST("h_Mult"), N_Pi); - hist.fill(HIST(dire[2]) + HIST("h_Mult"), N_Ka); - hist.fill(HIST(dire[3]) + HIST("h_Mult"), N_Pr); - - parts(Q1_ch, Q2_ch, Q3_ch, Q4_ch, Nch, &mean_Q1_Ch, &twopart_Ch, &threepart_Ch, &fourpart_Ch); - if (Nch > 1) { - if (mean_Q1_Ch != 0) { - hist.fill(HIST(dire[0]) + HIST("h_mean_pt"), mean_Q1_Ch); - hist.fill(HIST(dire[0]) + HIST("h_mean_Q1_Mult_var"), NTPC, mean_Q1_Ch); - } - if (twopart_Ch != 0) - hist.fill(HIST(dire[0]) + HIST("h_twopart_Mult_var"), NTPC, twopart_Ch); - } - - parts(Q1_Pi, Q2_Pi, Q3_Pi, Q4_Pi, N_Pi, &mean_Q1_Pi, &twopart_Pi, &threepart_Pi, &fourpart_Pi); - if (N_Pi > 1) { - if (mean_Q1_Pi != 0) { - hist.fill(HIST(dire[1]) + HIST("h_mean_pt"), mean_Q1_Pi); - hist.fill(HIST(dire[1]) + HIST("h_mean_Q1_Mult_var"), NTPC, mean_Q1_Pi); - } - if (twopart_Pi != 0) - hist.fill(HIST(dire[1]) + HIST("h_twopart_Mult_var"), Nch, twopart_Pi); - } - - parts(Q1_Ka, Q2_Ka, Q3_Ka, Q4_Ka, N_Ka, &mean_Q1_Ka, &twopart_Ka, &threepart_Ka, &fourpart_Ka); - if (N_Ka > 1) { - if (mean_Q1_Ka != 0) { - hist.fill(HIST(dire[2]) + HIST("h_mean_pt"), mean_Q1_Ka); - hist.fill(HIST(dire[2]) + HIST("h_mean_Q1_Mult_var"), NTPC, mean_Q1_Ka); - } - if (twopart_Ka != 0) - hist.fill(HIST(dire[2]) + HIST("h_twopart_Mult_var"), NTPC, twopart_Ka); - } - - parts(Q1_Pr, Q2_Pr, Q3_Pr, Q4_Pr, N_Pr, &mean_Q1_Pr, &twopart_Pr, &threepart_Pr, &fourpart_Pr); - if (N_Pr > 1) { - if (mean_Q1_Pr != 0) { - hist.fill(HIST(dire[3]) + HIST("h_mean_pt"), mean_Q1_Pr); - hist.fill(HIST(dire[3]) + HIST("h_mean_Q1_Mult_var"), NTPC, mean_Q1_Pr); - } - if (twopart_Pr != 0) - hist.fill(HIST(dire[3]) + HIST("h_twopart_Mult_var"), NTPC, twopart_Pr); - } - } - PROCESS_SWITCH(meanPtFlucId, process_MCGen, "process MC Generated", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} diff --git a/PWGCF/EbyEFluctuations/Tasks/RobustFluctuationObservables.cxx b/PWGCF/EbyEFluctuations/Tasks/RobustFluctuationObservables.cxx index 0acee1a1037..f4d50ac9c7a 100644 --- a/PWGCF/EbyEFluctuations/Tasks/RobustFluctuationObservables.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/RobustFluctuationObservables.cxx @@ -14,6 +14,9 @@ #include #include +#include +#include +#include #include "TF1.h" #include "TGraphErrors.h" @@ -63,16 +66,31 @@ using namespace o2::framework::expressions; mHist2D[hName] = v2D.size(); \ v2D.push_back(histosEventNew.add(TString::Format("%s/%s", hName, cutName.c_str()).Data(), title, kTH2F, {axisX, axisY})); +// pt study: +#define ADD_PT_HIST_1D(hName, cutName, hTitle, axisX...) \ + { \ + string str = hName; \ + string fullName = str + "/" + cutName; \ + mPtStudyCuts[fullName] = pHistPtStudy1D.size(); \ + pHistPtStudy1D.push_back(histosDetailedPt.add(TString::Format("%s", fullName.c_str()).Data(), hTitle, kTH1D, {axisX})); \ + } + +#define FILL_PT_HIST_1D(cutName, x, w...) \ + if (!mPtStudyCuts.count(cutName)) \ + LOGF(fatal, "AHTUNG! no key %s in mPtStudyCuts map!", cutName); \ + pHistPtStudy1D[mPtStudyCuts[cutName]]->Fill(x, w); + // main class struct RobustFluctuationObservables { // for vertex vs time: bool flagShowInfo = false; int lastRunNumber = -1; - int nBCsPerOrbit = 3564; + uint64_t nBCsPerOrbit = 3564; // bc position correlations int64_t prevOrbit = -1; int64_t prevBcInTF = -1; + int64_t prevFoundBcInTF = -1; uint64_t prevBC = 9999; //-1; uint64_t prevTF = 9999; //-1; uint64_t prevGlobalFoundBC = 9999; //-1; @@ -86,7 +104,7 @@ struct RobustFluctuationObservables { int64_t orbitSOR = -1; // int64_t bcSORbis = -1; // global bc of the start of the first orbit - try alternative int64_t nBCsPerTF = 1; // 128*3564; // duration of TF in bcs - int64_t TFid = -1; // count time frames in a given run + uint64_t TFid = 0; // count time frames in a given run bool flagWaitForNewTF = false; uint32_t nOrbitsPerTF = 0; @@ -107,6 +125,7 @@ struct RobustFluctuationObservables { HistogramRegistry histosEventBcInTF{"histosEventSelectionBcInTF", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry histosFT0{"histosFT0", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry histosTracks{"histosTracks", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry histosDetailedPt{"histosDetailedPt", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry histosK0S{"kzeroShort", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; // ##### configurables and axes @@ -120,6 +139,7 @@ struct RobustFluctuationObservables { Configurable flagIncludeQAHistK0S{"flagIncludeQAHistK0S", 1, "flagIncludeQAHistK0S: 0 - no, 1 - yes"}; Configurable flagIncludeQATracksInFoundBC{"flagIncludeQATracksInFoundBC", 1, "flagIncludeQATracksInFoundBC: 0 - no, 1 - yes"}; Configurable flagIncludeQAHistPartsOfOrbit{"flagIncludeQAHistPartsOfOrbit", 1, "flagIncludeQAHistPartsOfOrbit: 0 - no, 1 - yes"}; + Configurable flagIncludeQAROFinPtEtaBins{"flagIncludeQAROFinPtEtaBins", 1, "flagIncludeQAROFinPtEtaBins: 0 - no, 1 - yes"}; Configurable nBinsContrib{"nBinsContrib", 200, "N bins in n vertex contrib histo"}; Configurable nMaxContrib{"nMaxContrib", 200, "N max in nContrib histo"}; @@ -137,7 +157,7 @@ struct RobustFluctuationObservables { // hand-made ITS ROF cut Configurable nITSROF{"nITSROF", 6, "nITSROF"}; Configurable nITSROF_BC_offset{"nITSROF_BC_offset", 65, "nITSROF_BC_offset"}; - Configurable nITSROF_BC_cutWidth{"nITSROF_BC_cutWidth", 40, "nITSROF_BC_cutWidth"}; + Configurable nITSROF_BC_cutWidth{"nITSROF_BC_cutWidth", 40, "nITSROF_BC_cutWidth"}; // Configurable nITSROF_middle_cut_forITSonlyVert{"nITSROF_middle_cut_forITSonlyVert", 198/2 /*ROF=198 in pp*/, "nITSROF_middle_cut_forITSonlyVert"}; // Configurable nNoITSonlyVertices{"nNoITSonlyVertices", false, "nITSROF_middle_cut_forITSonlyVert"}; @@ -146,7 +166,7 @@ struct RobustFluctuationObservables { Configurable cutVzTrackT0diffUpper{"cutVzTrackT0diffUpper", 1., "cutVzTrackT0diffUpper, cm"}; // splitting of the orbit into several BC ranges - Configurable> vSplitBCpointsOfTheOrbit{"SplitBCpointsOfTheOrbit", {1200, 2000, 3000}, "BC split points of the orbit"}; + Configurable> vSplitBCpointsOfTheOrbit{"SplitBCpointsOfTheOrbit", {1200, 2000, 3000}, "BC split points of the orbit"}; // orbit QA uint32_t orbitAtCollIndexZero = 0; @@ -164,6 +184,11 @@ struct RobustFluctuationObservables { vector>> pHist1D; vector>> pHist2D; + // QA for pt vs various cuts + map mPtStudyCuts; + vector> pHistPtStudy1D; + + // TF1* funcCutEventsByMultPVvsV0A; TF1* funcCutEventsByMultPVvsT0C; @@ -216,6 +241,28 @@ struct RobustFluctuationObservables { "ALL_CUTS_Handmade_ITSROFcut_Orbit_3_part", "ALL_CUTS_Handmade_ITSROFcut_Orbit_4_part", }; + + // naming of the 1D pT plots + string strPtSelFolderNames[] = + { + "allBC", + "TFborder", + "noTFborder", + "ROFborder", + "noROFborder", + "noTFandROFborder", + }; + + string strPtSelNames[] = + { + "pt", + "pt_w_nTPCcls", + "pos_pt", + "pos_pt_w_nTPCcls", + "neg_pt", + "neg_pt_w_nTPCcls", + }; + funcCutEventsByMultPVvsV0A = new TF1("funcCutEventsByMultPVvsV0A", "[0]*x+[1]", 0, 200000); funcCutEventsByMultPVvsV0A->SetParameters(3200. / 160000, -240); @@ -288,6 +335,7 @@ struct RobustFluctuationObservables { // histosEvent.add("h2D_numContrib_vs_collIndex", "h2D_numContrib_vs_collIndex", kTH2D, {axisCollIndex, axisNcontrib}); histosEvent.add("h2D_numContrib_vs_BC", "h2D_numContrib_vs_BC", kTH2D, {axisBC, axisNcontrib}); histosEvent.add("h2D_diffFoundBC_vs_BC", "h2D_diffFoundBC_vs_BC", kTH2D, {axisBC, {201, -100.5, 100.5, "foundBC-BC"}}); + histosEvent.add("h2D_diffFoundBC_vs_BC_inTF", "h2D_diffFoundBC_vs_BC_inTF", kTH2D, {axisBC, {201, -100.5, 100.5, "foundBC-BC"}}); histosEvent.add("hOrbitStartFromCollIndexZeroAft", "hOrbitStartFromCollIndexZeroAft", kTH1D, {axisOrbit}); histosEvent.add("h2D_Orbit_vs_CollIndex_Aft", "h2D_Orbit_vs_CollIndex_Aft", kTH2D, {axisCollIndex, axisOrbit}); @@ -309,6 +357,9 @@ struct RobustFluctuationObservables { histosEvent.add("hBC_DIFF_to_previous_FOUND_BC_globTrkContrib_globTrkContrib_2D_diff0", "hBC_DIFF_to_previous_FOUND_BC_globTrkContrib_globTrkContrib_2D_diff0", kTH2F, {axisNtracks, axisNtracks}); histosEvent.add("hBC_DIFF_to_previous_FOUND_BC_1goodCont_FTvertexCut_vZvZ_2D_NoBCdiff0", "hBC_DIFF_to_previous_FOUND_BC_1goodCont_FTvertexCut_vZvZ_2D_NoBCdiff0", kTH2F, {axisZvert, axisZvert}); + histosEvent.add("hBCinTF_DIFF_to_previous", "hBCinTF_DIFF_to_previous", kTH1D, {{3564 * 4 + 1, -3564.5, 2 * 3564 + 3564.5, "diff BC"}}); + histosEvent.add("hBCinTF_DIFF_to_previous_FOUND_BC", "hBCinTF_DIFF_to_previous_FOUND_BC", kTH1D, {{3564 * 4 + 1, -3564.5, 2 * 3564 + 3564.5, "diff BC"}}); + // hist vs bcInTF, Feb 2, 2024 if (flagIncludeQAHistBcInTF) { histosEventBcInTF.add("hNumContrib_vs_bcInTF_BEFORE_SEL8_AND_Vz", "hNumContrib_vs_bcInTF_BEFORE_SEL8_AND_Vz;bc in TF; n vertex contributors", kTH1D, {axisBCinTF}); @@ -327,26 +378,26 @@ struct RobustFluctuationObservables { // nTracks vs BC if (flagIncludeQAHistBcVsNtracks) { - histosEvent.add("h2D_nTracksBeforeCuts_vs_BC", "h2D_nTracksBeforeCuts_vs_BC", kTH2D, {axisBC, axisNcontrib}); - histosEvent.add("h2D_nTracksAfterEtaTPCcuts_vs_BC", "h2D_nTracksAfterEtaTPCcuts_vs_BC", kTH2D, {axisBC, axisNcontrib}); - histosEvent.add("h2D_nTracksITSonly_vs_BC", "h2D_nTracksITSonly_vs_BC", kTH2D, {axisBC, axisNtracks}); - histosEvent.add("h2D_nTracksWithITS_vs_BC", "h2D_nTracksWithITS_vs_BC", kTH2D, {axisBC, axisNtracks}); - histosEvent.add("h2D_nTracksWithITS7hits_vs_BC", "h2D_nTracksWithITS7hits_vs_BC", kTH2D, {axisBC, axisNtracks}); - histosEvent.add("h2D_nTracksWithITSandTPC_vs_BC", "h2D_nTracksWithITSandTPC_vs_BC", kTH2D, {axisBC, axisNtracks}); - histosEvent.add("h2D_nTracksWithTRD_vs_BC", "h2D_nTracksWithTRD_vs_BC", kTH2D, {axisBC, axisNtracks}); - histosEvent.add("h2D_nTracksWithTOF_vs_BC", "h2D_nTracksWithTOF_vs_BC", kTH2D, {axisBC, axisNtracks}); - histosEvent.add("h2D_nTracksWithTRDorTOF_vs_BC", "h2D_nTracksWithTRDorTOF_vs_BC", kTH2D, {axisBC, axisNtracks}); - histosEvent.add("h2D_nTracksGlobal_vs_BC", "h2D_nTracksGlobal_vs_BC", kTH2D, {axisBC, axisNtracks}); - histosEvent.add("h2D_nTracksGlobalWithITS7hits_vs_BC", "h2D_nTracksGlobalWithITS7hits_vs_BC", kTH2D, {axisBC, axisNtracks}); - histosEvent.add("h2D_nTracksGlobalWithTRDorTOF_vs_BC", "h2D_nTracksGlobalWithTRDorTOF_vs_BC", kTH2D, {axisBC, axisNtracks}); + histosEvent.add("h2D_nTracksBeforeCuts_vs_BC", "h2D_nTracksBeforeCuts_vs_BC", kTH2F, {axisBC, axisNcontrib}); + histosEvent.add("h2D_nTracksAfterEtaTPCcuts_vs_BC", "h2D_nTracksAfterEtaTPCcuts_vs_BC", kTH2F, {axisBC, axisNcontrib}); + histosEvent.add("h2D_nTracksITSonly_vs_BC", "h2D_nTracksITSonly_vs_BC", kTH2F, {axisBC, axisNtracks}); + histosEvent.add("h2D_nTracksWithITS_vs_BC", "h2D_nTracksWithITS_vs_BC", kTH2F, {axisBC, axisNtracks}); + histosEvent.add("h2D_nTracksWithITS7hits_vs_BC", "h2D_nTracksWithITS7hits_vs_BC", kTH2F, {axisBC, axisNtracks}); + histosEvent.add("h2D_nTracksWithITSandTPC_vs_BC", "h2D_nTracksWithITSandTPC_vs_BC", kTH2F, {axisBC, axisNtracks}); + histosEvent.add("h2D_nTracksWithTRD_vs_BC", "h2D_nTracksWithTRD_vs_BC", kTH2F, {axisBC, axisNtracks}); + histosEvent.add("h2D_nTracksWithTOF_vs_BC", "h2D_nTracksWithTOF_vs_BC", kTH2F, {axisBC, axisNtracks}); + histosEvent.add("h2D_nTracksWithTRDorTOF_vs_BC", "h2D_nTracksWithTRDorTOF_vs_BC", kTH2F, {axisBC, axisNtracks}); + histosEvent.add("h2D_nTracksGlobal_vs_BC", "h2D_nTracksGlobal_vs_BC", kTH2F, {axisBC, axisNtracks}); + histosEvent.add("h2D_nTracksGlobalWithITS7hits_vs_BC", "h2D_nTracksGlobalWithITS7hits_vs_BC", kTH2F, {axisBC, axisNtracks}); + histosEvent.add("h2D_nTracksGlobalWithTRDorTOF_vs_BC", "h2D_nTracksGlobalWithTRDorTOF_vs_BC", kTH2F, {axisBC, axisNtracks}); // mean pT vs BC AxisSpec axisMeanPt{10, 0., 2.0, ""}; - histosEvent.add("h1D_vContributors_1_meanPt_vs_BC", "h1D_vContributors_1_meanPt_vs_BC;bc;entries", kTH2D, {axisBC, axisMeanPt}); - histosEvent.add("h1D_vContributors_2_meanPt_vs_BC", "h1D_vContributors_2_meanPt_vs_BC;bc;entries", kTH2D, {axisBC, axisMeanPt}); - histosEvent.add("h1D_vContributors_3_meanPt_vs_BC", "h1D_vContributors_3_meanPt_vs_BC;bc;entries", kTH2D, {axisBC, axisMeanPt}); - histosEvent.add("h1D_vContributors_4_meanPt_vs_BC", "h1D_vContributors_4_meanPt_vs_BC;bc;entries", kTH2D, {axisBC, axisMeanPt}); - histosEvent.add("h1D_vContributors_5_meanPt_vs_BC", "h1D_vContributors_5_meanPt_vs_BC;bc;entries", kTH2D, {axisBC, axisMeanPt}); + histosEvent.add("h1D_vContributors_1_meanPt_vs_BC", "h1D_vContributors_1_meanPt_vs_BC;bc;entries", kTH2F, {axisBC, axisMeanPt}); + histosEvent.add("h1D_vContributors_2_meanPt_vs_BC", "h1D_vContributors_2_meanPt_vs_BC;bc;entries", kTH2F, {axisBC, axisMeanPt}); + histosEvent.add("h1D_vContributors_3_meanPt_vs_BC", "h1D_vContributors_3_meanPt_vs_BC;bc;entries", kTH2F, {axisBC, axisMeanPt}); + histosEvent.add("h1D_vContributors_4_meanPt_vs_BC", "h1D_vContributors_4_meanPt_vs_BC;bc;entries", kTH2F, {axisBC, axisMeanPt}); + histosEvent.add("h1D_vContributors_5_meanPt_vs_BC", "h1D_vContributors_5_meanPt_vs_BC;bc;entries", kTH2F, {axisBC, axisMeanPt}); } // AxisSpec axisGlobalTracks{flagPbPb ? 2501 : 81, -0.5, flagPbPb ? 2500.5 : 80.5, "n global tracks"}; @@ -403,6 +454,12 @@ struct RobustFluctuationObservables { histosEvent.add("hBC_Aft_rejectedByCutOnMultPVvsT0C_AndIfITSonlyPV", "hBC_Aft_rejectedByCutOnMultPVvsT0C_AndIfITSonlyPV", kTH1D, {axisBC}); histosEvent.add("hBC_Aft_rejectedByCutOnMultPVvsT0C_AndIfITSonlyPV_ANTI", "hBC_Aft_rejectedByCutOnMultPVvsT0C_AndIfITSonlyPV_ANTI", kTH1D, {axisBC}); + histosEvent.add("hOccupancyInTimeRange", "hOccupancyInTimeRange", kTH1D, {{400, 0, 20000, "occupancy (nITStracks nCls>=5)"}}); + histosEvent.add("hOccupancyInTimeRangeIsAvailable", "hOccupancyInTimeRangeIsAvailable", kTH1D, {{203, -2.5, 200.5, "occupancy zoomed (nITStracks nCls>=5)"}}); + + AxisSpec axisCentrForOccupQA{20, 0, 100, "centrality, %"}; + histosEvent.add("hCentralityVsOccupancy", "hCentralityVsOccupancy", kTH2D, {{400, 0, 20000, "occupancy zoomed (nITStracks nCls>=5)"}, axisCentrForOccupQA}); + // ##### tracks for All collisions if (flagIncludeQATracksInFoundBC) { histosEventTracksFoundBC.add("hFoundBC_nAllTracks", "hFoundBC_nAllTracks", kTH1D, {axisBC}); @@ -428,6 +485,7 @@ struct RobustFluctuationObservables { histosEventTracksFoundBC.add("hFoundBC_kTVX_nGlobalTracks", "hFoundBC_kTVX_nGlobalTracks", kTH1D, {axisBC}); histosEventTracksFoundBC.add("hFoundBC_kTVX_nITStracks", "hFoundBC_kTVX_nITStracks", kTH1D, {axisBC}); histosEventTracksFoundBC.add("hFoundBC_kTVX_nTPCtracks", "hFoundBC_kTVX_nTPCtracks", kTH1D, {axisBC}); + histosEventTracksFoundBC.add("hFoundBC_kTVX_nITSTPCtracks", "hFoundBC_kTVX_nITSTPCtracks", kTH1D, {axisBC}); histosEventTracksFoundBC.add("hFoundBC_kTVX_nTOFtracks", "hFoundBC_kTVX_nTOFtracks", kTH1D, {axisBC}); histosEventTracksFoundBC.add("hFoundBC_kTVX_nTRDtracks", "hFoundBC_kTVX_nTRDtracks", kTH1D, {axisBC}); @@ -440,6 +498,12 @@ struct RobustFluctuationObservables { histosEventTracksFoundBC.add("hFoundBC_kTVX_nTOFtracks_HandmadeITSROFcut", "hFoundBC_kTVX_nTOFtracks_HandmadeITSROFcut", kTH1D, {axisBC}); histosEventTracksFoundBC.add("hFoundBC_kTVX_nTRDTOFtracks_HandmadeITSROFcut", "hFoundBC_kTVX_nTRDTOFtracks_HandmadeITSROFcut", kTH1D, {axisBC}); + histosEventTracksFoundBC.add("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks", "hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks", kTH1D, {axisBC}); + histosEventTracksFoundBC.add("hFoundBC_kTVX_nITSlayers_for_GlobalTracks", "hFoundBC_kTVX_nITSlayers_for_GlobalTracks", kTH1D, {axisBC}); + AxisSpec axisPtBinsForROFstudy{{0.1, 0.2, 0.3, 0.4, 0.5, 0.8, 1.0, 1.5, 2.0, 3.0, 5.0}, "p_{T}"}; + histosEventTracksFoundBC.add("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_vs_pt", "hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_vs_pt", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histosEventTracksFoundBC.add("hFoundBC_kTVX_nITSTPCtracks_vs_pt", "hFoundBC_kTVX_nITSTPCtracks_vs_pt", kTH2D, {axisBC, axisPtBinsForROFstudy}); + // ##### tracks for TVXinTRD collisions histosEventTracksFoundBC.add("hFoundBC_kTVXinTRD_nAllTracks", "hFoundBC_kTVXinTRD_nAllTracks", kTH1D, {axisBC}); histosEventTracksFoundBC.add("hFoundBC_kTVXinTRD_nTracksPV", "hFoundBC_kTVXinTRD_nTracksPV", kTH1D, {axisBC}); @@ -458,7 +522,41 @@ struct RobustFluctuationObservables { histosEventTracksFoundBC.add("hFoundBC_kTVX_nITSTPCTRDtracks_mult_1_20", "hFoundBC_kTVX_nITSTPCTRDtracks_mult_1_20", kTH1D, {axisBC}); histosEventTracksFoundBC.add("hFoundBC_kTVX_nITSTPCTRDtracks_mult_20_100", "hFoundBC_kTVX_nITSTPCTRDtracks_mult_20_100", kTH1D, {axisBC}); histosEventTracksFoundBC.add("hFoundBC_kTVX_nITSTPCTRDtracks_mult_100_400", "hFoundBC_kTVX_nITSTPCTRDtracks_mult_100_400", kTH1D, {axisBC}); - histosEventTracksFoundBC.add("hFoundBC_kTVX_nITSTPCTRDtracks_mult_above_400", "hFoundBC_kTVX_nITSTPCTRDtracks_mult_above_400", kTH1D, {axisBC}); + histosEventTracksFoundBC.add("hFoundBC_kTVX_nITSTPCTRDtracks_mult_400_1000", "hFoundBC_kTVX_nITSTPCTRDtracks_mult_400_1000", kTH1D, {axisBC}); + histosEventTracksFoundBC.add("hFoundBC_kTVX_nITSTPCTRDtracks_mult_above_1000", "hFoundBC_kTVX_nITSTPCTRDtracks_mult_above_1000", kTH1D, {axisBC}); + + // to study ITS ROF dips vs pt + if (flagIncludeQAROFinPtEtaBins) { + AxisSpec axisITSlayers{7, -0.5, 7 - 0.5, "layer id"}; + histosEventTracksFoundBC.add("hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta02", "hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta02", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histosEventTracksFoundBC.add("hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta02_04", "hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta02_04", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histosEventTracksFoundBC.add("hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta04_06", "hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta04_06", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histosEventTracksFoundBC.add("hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta06_08", "hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta06_08", kTH2D, {axisBC, axisPtBinsForROFstudy}); + + histosEventTracksFoundBC.add("hITSlayerCounts_vs_BC_pt02_05", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + histosEventTracksFoundBC.add("hITSlayerCounts_vs_BC_pt05_10", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + histosEventTracksFoundBC.add("hITSlayerCounts_vs_BC_pt10_50", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + + // pions + histosEventTracksFoundBC.add("hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta02", "hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta02", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histosEventTracksFoundBC.add("hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta02_04", "hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta02_04", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histosEventTracksFoundBC.add("hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta04_06", "hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta04_06", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histosEventTracksFoundBC.add("hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta06_08", "hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta06_08", kTH2D, {axisBC, axisPtBinsForROFstudy}); + + histosEventTracksFoundBC.add("hITSlayerCounts_vs_BC_pi_pt02_05", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + histosEventTracksFoundBC.add("hITSlayerCounts_vs_BC_pi_pt05_10", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + histosEventTracksFoundBC.add("hITSlayerCounts_vs_BC_pi_pt10_50", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + + // protons + histosEventTracksFoundBC.add("hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta02", "hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta02", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histosEventTracksFoundBC.add("hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta02_04", "hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta02_04", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histosEventTracksFoundBC.add("hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta04_06", "hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta04_06", kTH2D, {axisBC, axisPtBinsForROFstudy}); + histosEventTracksFoundBC.add("hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta06_08", "hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta06_08", kTH2D, {axisBC, axisPtBinsForROFstudy}); + + histosEventTracksFoundBC.add("hITSlayerCounts_vs_BC_p_pt02_05", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + histosEventTracksFoundBC.add("hITSlayerCounts_vs_BC_p_pt05_10", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + histosEventTracksFoundBC.add("hITSlayerCounts_vs_BC_p_pt10_50", "hITSlayerCounts_vs_BC", kTH2D, {axisBC, axisITSlayers}); + } // bcInTF AxisSpec axisBCinTF32orbits{32 * 3564, -0.5, 32 * 3564, "bcInTF"}; @@ -586,16 +684,53 @@ struct RobustFluctuationObservables { AxisSpec axisPhiSpecMod9{nBinsPhi, -2 * TMath::TwoPi() / 9, 2 * TMath::TwoPi() / 9, "#varphi"}; histosTracks.add("eta", "eta", kTH1D, {axisEta}); histosTracks.add("etaAfter08cut", "etaAfter08cut", kTH1D, {axisEta}); - histosTracks.add("ptHistogram", "ptHistogram", kTH1D, {axisPt}); + + // ### detailed pt study + AxisSpec axisLogPt{100, 0.05, 40, "p_{T}"}; + axisLogPt.makeLogarithmic(); + + // #### add pt QA histos via loop + int nFolderPt = sizeof(strPtSelFolderNames) / sizeof(*strPtSelFolderNames); + int nCutsPtQA = sizeof(strPtSelNames) / sizeof(*strPtSelNames); + // int counterPtCuts = 0; + for (int i = 0; i < nFolderPt; i++) { + for (int j = 0; j < nCutsPtQA; j++) { + // add this cut name and id to map + string cutName = (strPtSelFolderNames[i] + "/" + strPtSelNames[j]).c_str(); + + // now add 1D histograms: + ADD_PT_HIST_1D("All", cutName, "", axisLogPt); + ADD_PT_HIST_1D("Global", cutName, "", axisLogPt); + + ADD_PT_HIST_1D("ITS7hits", cutName, "", axisLogPt); + ADD_PT_HIST_1D("ITS7hits_TPC80cl", cutName, "", axisLogPt); + + ADD_PT_HIST_1D("ITS4567", cutName, "", axisLogPt); + ADD_PT_HIST_1D("ITS4567_TPC80cl", cutName, "", axisLogPt); + + ADD_PT_HIST_1D("ITS567", cutName, "", axisLogPt); + ADD_PT_HIST_1D("ITS567_TPC80cl", cutName, "", axisLogPt); + + ADD_PT_HIST_1D("ITS67", cutName, "", axisLogPt); + ADD_PT_HIST_1D("ITS67_TPC80cl", cutName, "", axisLogPt); + } + } + // ### end of detailed pt study + histosTracks.add("phiHistogram", "phiHistogram", kTH1D, {axisPhi}); histosTracks.add("pidCombSigma", "pidCombSigma", kTH1D, {{200, 0, 10, "pidCombSigma"}}); histosTracks.add("hTpcNClsCrossedRows", "hTpcNClsCrossedRows", kTH1D, {{170, -0.5, 169.5, "TpcNClsCrossedRows"}}); + histosTracks.add("hTpcNClsCrossedRows_Global_beforeCrossedRowsCut", "hTpcNClsCrossedRows_Global_beforeCrossedRowsCut", kTH1D, {{170, -0.5, 169.5, "hTpcNClsCrossedRows_Global_beforeCrossedRowsCut"}}); histosTracks.add("hTpcNClsCrossedRowsITS7hits", "hTpcNClsCrossedRowsITS7hits", kTH1D, {{170, -0.5, 169.5, "TpcNClsCrossedRowsITS7hits"}}); histosTracks.add("hNumITSclusters", "hNumITSclusters", kTH1D, {{10, -0.5, 9.5, "NumITSclusters"}}); + histosTracks.add("hNumITSclusters_Global_beforeCrossedRowsCut", "hNumITSclusters_Global_beforeCrossedRowsCut", kTH1D, {{10, -0.5, 9.5, "hNumITSclusters_Global_beforeCrossedRowsCut"}}); histosTracks.add("hNumITSclusters_ITSonlyVert", "hNumITSclusters_ITSonlyVert", kTH1D, {{10, -0.5, 9.5, "NumITSclusters"}}); histosTracks.add("hDcaXY", "hDcaXY", kTH1D, {{800, -4, 4, "DcaXY"}}); + histosTracks.add("hDcaXY_Global_beforeCrossedRowsCut", "hDcaXY_Global_beforeCrossedRowsCut", kTH1D, {{800, -4, 4, "DcaXY"}}); + histosTracks.add("hDcaZ", "hDcaZ", kTH1D, {{800, -4, 4, "DcaZ"}}); + histosTracks.add("hDcaZ_Global_beforeCrossedRowsCut", "hDcaZ_Global_beforeCrossedRowsCut", kTH1D, {{800, -4, 4, "DcaZ"}}); histosTracks.add("hTrackLength", "hTrackLength", kTH1D, {{400, 0, 2000, "TrackLength"}}); AxisSpec axisTrackChi2{200, 0., 10.f, "chi2"}; @@ -617,14 +752,18 @@ struct RobustFluctuationObservables { histosTracks.add("hNumITSclusters_AftCuts", "hNumITSclusters_AftCuts", kTH1D, {{10, -0.5, 9.5, "NumITSclusters_AftCuts"}}); histosTracks.add("hNumITSclusters_AftCuts_Global", "hNumITSclusters_AftCuts_Global", kTH1D, {{10, -0.5, 9.5, "NumITSclusters_AftCuts"}}); histosTracks.add("hDcaXY_AftCuts", "hDcaXY_AftCuts", kTH1D, {{800, -4, 4, "DcaXY_AftCuts"}}); + histosTracks.add("hDcaZ_AftCuts", "hDcaZ_AftCuts", kTH1D, {{800, -4, 4, "DcaZ_AftCuts"}}); histosTracks.add("hTrackLength_AftCuts", "hTrackLength_AftCuts", kTH1D, {{400, 0, 2000, "TrackLength_AftCuts"}}); histosTracks.add("hChi2perDOF_AftCuts", "hChi2perDOF_AftCuts", kTH1D, {{200, 0, 20, "Chi2perDOF_AftCuts"}}); + histosTracks.add("hTpcNClsFound", "hTpcNClsFound", kTH1D, {{170, -0.5, 169.5, "hTpcNClsFound"}}); + histosTracks.add("hTpcNClsFound_Global_beforeCrossedRowsCut", "hTpcNClsFound_Global_beforeCrossedRowsCut", kTH1D, {{170, -0.5, 169.5, "hTpcNClsFound_Global_beforeCrossedRowsCut"}}); histosTracks.add("hTpcNClsFound_AftCuts", "hTpcNClsFound_AftCuts", kTH1D, {{170, -0.5, 169.5, "hTpcNClsFound_AftCuts"}}); histosTracks.add("hTpcNClsFound_ITS7hits_AftCuts", "hTpcNClsFound_ITS7hits_AftCuts", kTH1D, {{170, -0.5, 169.5, "hTpcNClsFound_ITS7hits_AftCuts"}}); histosTracks.add("hNumITScls_vs_TPCcls_AftCuts_Global", "hNumITScls_vs_TPCcls_AftCuts_Global", kTH2D, {{8, -0.5, 7.5, "NumITSclusters"}, {170, -0.5, 169.5, "TpcNCls"}}); histosTracks.add("hNumITScls_vs_TPCcrossedRows_AftCuts_Global", "hNumITScls_vs_TPCcrossedRows_AftCuts_Global", kTH2D, {{8, -0.5, 7.5, "NumITSclusters"}, {170, -0.5, 169.5, "TpcNClsCrossedRows"}}); + histosTracks.add("hNumITScls_vs_TPCcrossedRows_Global_beforeCrossedRowsCut", "hNumITScls_vs_TPCcrossedRows_Global_beforeCrossedRowsCut", kTH2D, {{8, -0.5, 7.5, "NumITSclusters"}, {170, -0.5, 169.5, "TpcNClsCrossedRows"}}); // ### chi2 after cuts: histosTracks.add("hChi2TPCperDOF_ITS7hits", "hChi2TPCperDOF_ITS7hits", kTH1D, {axisTrackChi2}); @@ -664,11 +803,8 @@ struct RobustFluctuationObservables { histosK0S.add("hK0Sradius", "hK0Sradius", kTH1D, {{800, 0, 100, "hK0Sradius"}}); histosK0S.add("hMassK0Short", "hMassK0Short", {HistType::kTH1F, {K0ShortMassAxis}}); histosK0S.add("hMassK0ShortAfterSelection", "hMassK0ShortAfterSelection", {HistType::kTH1F, {K0ShortMassAxis}}); - // for(int iPt=0; iPt; - using Colls = soa::Join; + using Colls = soa::Join; + // using Colls = soa::Join; using BCsRun3 = soa::Join; //, aod::Run3MatchedToBCSparse>; void processRobustFluctuationObservables( @@ -729,7 +888,8 @@ struct RobustFluctuationObservables { aod::Origins const& origins, soa::Join const& tracks, + aod::TracksDCA, aod::pidTPCEl, aod::pidTPCMu, aod::pidTPCPi, + aod::pidTPCKa, aod::pidTPCPr, aod::pidTPCDe, aod::pidTOFEl> const& tracks, aod::V0Datas const& v0s, DaughterTracks const&) { auto bc = collision.bc_as(); @@ -781,7 +941,7 @@ struct RobustFluctuationObservables { double vZ = collision.posZ(); // #### values for 2D histogram axes - auto t0cCentr = 0; // tmp, to be updated + auto t0cCentr = collision.centFT0C(); auto multV0A = collision.multFV0A(); auto multT0A = collision.multFT0A(); @@ -811,7 +971,7 @@ struct RobustFluctuationObservables { } if (myDF_ID >= 0 && myDF_ID < nHistQAplotsDF) { - int diffOrbits = (int32_t)orbit - (int32_t)orbitAtCollIndexZero; + int diffOrbits = static_cast(orbit) - static_cast(orbitAtCollIndexZero); TString strDF = Form("DF_%d", static_cast(DF_ID_raw)); fV_h1D_Orbit_vs_CollIndex[myDF_ID]->Fill(collision.index(), diffOrbits); fV_h1D_Orbit_vs_CollIndex[myDF_ID]->SetTitle(strDF); @@ -1025,6 +1185,12 @@ struct RobustFluctuationObservables { histosEventBcInTF.fill(HIST("hIsTriggerTVX_vs_bcInTF_BEFORE_SEL8_AND_Vz"), bcInTF, collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) ? 1 : 0); } + int64_t foundBcInTF = 0; + if (collision.has_foundBC()) { + auto bcFound = collision.foundBC_as(); + foundBcInTF = (bcFound.globalBC() - bcSOR) % nBCsPerTF; + } + // ### special sub-loop over tracks for numerator of tracks / T0ampl ratios if (collision.has_foundBC() && flagIncludeQATracksInFoundBC) { int nAllTracks = 0; @@ -1032,6 +1198,7 @@ struct RobustFluctuationObservables { int nITStracks = 0; int nTPCtracks = 0; + int nITSTPCtracks = 0; int nTPCtracks_HandmadeITSROFcut = 0; int nTOFtracks = 0; int nTOFtracks_HandmadeITSROFcut = 0; @@ -1062,6 +1229,7 @@ struct RobustFluctuationObservables { nITStracks += track.hasITS() && !track.hasTPC(); nTPCtracks += track.hasTPC(); + nITSTPCtracks += track.hasITS() && track.hasTPC(); nTOFtracks += track.hasTOF(); nTRDtracks += track.hasTRD() && !track.hasTOF(); @@ -1070,6 +1238,78 @@ struct RobustFluctuationObservables { nITSTPCTOFtracks += track.hasITS() && track.hasTPC() && track.hasTOF(); nITSTPCTRDTOFtracks += track.hasITS() && track.hasTPC() && track.hasTOF() && track.hasTRD(); + float eta = track.eta(); + float pt = track.pt(); + + if (track.hasITS() && track.hasTPC()) { + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks"), globalFoundBC, track.itsNCls()); + + if (fabs(eta) < 0.8 && fabs(collision.posZ()) < 10) { + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nITSTPCtracks_vs_pt"), globalFoundBC, pt); + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nITSlayers_for_ITSTPCtracks_vs_pt"), globalFoundBC, pt, track.itsNCls()); + } + } + + if (track.isGlobalTrack()) + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nITSlayers_for_GlobalTracks"), globalFoundBC, track.itsNCls()); + + // ROF study: eta and pt bins + if (flagIncludeQAROFinPtEtaBins && track.itsNCls() >= 2 && track.tpcNClsFound() > 80) { + + bool isPion = (TMath::Abs(track.tpcNSigmaPi()) < 3 && TMath::Abs(track.tpcNSigmaKa()) > 3 && TMath::Abs(track.tpcNSigmaPr()) > 3) ? true : false; + bool isProton = (TMath::Abs(track.tpcNSigmaPr()) < 3 && TMath::Abs(track.tpcNSigmaKa()) > 3 && TMath::Abs(track.tpcNSigmaPi()) > 3) ? true : false; + if (fabs(eta) < 0.2) { + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta02"), globalFoundBC, pt); + if (isPion) + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta02"), globalFoundBC, pt); + if (isProton) + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta02"), globalFoundBC, pt); + + // for this eta: study ITS cluster pattern + for (int layer = 0; layer < 7; layer++) { + if (track.itsClusterMap() & (1 << layer)) { + if (pt > 0.2 && pt < 0.5) { + histosEventTracksFoundBC.fill(HIST("hITSlayerCounts_vs_BC_pt02_05"), globalFoundBC, layer); + if (isPion) + histosEventTracksFoundBC.fill(HIST("hITSlayerCounts_vs_BC_pi_pt02_05"), globalFoundBC, layer); + if (isProton) + histosEventTracksFoundBC.fill(HIST("hITSlayerCounts_vs_BC_p_pt02_05"), globalFoundBC, layer); + } else if (pt > 0.5 && pt < 1.0) { + histosEventTracksFoundBC.fill(HIST("hITSlayerCounts_vs_BC_pt05_10"), globalFoundBC, layer); + if (isPion) + histosEventTracksFoundBC.fill(HIST("hITSlayerCounts_vs_BC_pi_pt05_10"), globalFoundBC, layer); + if (isProton) + histosEventTracksFoundBC.fill(HIST("hITSlayerCounts_vs_BC_p_pt05_10"), globalFoundBC, layer); + } else if (pt > 1.0 && pt < 5.0) { + histosEventTracksFoundBC.fill(HIST("hITSlayerCounts_vs_BC_pt10_50"), globalFoundBC, layer); + if (isPion) + histosEventTracksFoundBC.fill(HIST("hITSlayerCounts_vs_BC_pi_pt10_50"), globalFoundBC, layer); + if (isProton) + histosEventTracksFoundBC.fill(HIST("hITSlayerCounts_vs_BC_p_pt10_50"), globalFoundBC, layer); + } + } + } + } else if (fabs(eta) < 0.4) { + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta02_04"), globalFoundBC, pt); + if (isPion) + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta02_04"), globalFoundBC, pt); + if (isProton) + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta02_04"), globalFoundBC, pt); + } else if (fabs(eta) < 0.6) { + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta04_06"), globalFoundBC, pt); + if (isPion) + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta04_06"), globalFoundBC, pt); + if (isProton) + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta04_06"), globalFoundBC, pt); + } else if (fabs(eta) < 0.8) { + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nITStracks_vs_BC_in_ptBins_eta06_08"), globalFoundBC, pt); + if (isPion) + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_pi_nITStracks_vs_BC_in_ptBins_eta06_08"), globalFoundBC, pt); + if (isProton) + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_p_nITStracks_vs_BC_in_ptBins_eta06_08"), globalFoundBC, pt); + } + } + // if (flagBCisNotInHandmadeBoundariesITSROF) if (flagFoundBCisNotInHandmadeBoundariesITSROF) { nTPCtracks_HandmadeITSROFcut += track.hasTPC(); @@ -1117,6 +1357,7 @@ struct RobustFluctuationObservables { histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nGlobalTracks"), globalFoundBC, nGlobalTracks); histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nITStracks"), globalFoundBC, nITStracks); histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nTPCtracks"), globalFoundBC, nTPCtracks); + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nITSTPCtracks"), globalFoundBC, nITSTPCtracks); histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nTOFtracks"), globalFoundBC, nTOFtracks); histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nTRDtracks"), globalFoundBC, nTRDtracks); @@ -1136,8 +1377,10 @@ struct RobustFluctuationObservables { histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nITSTPCTRDtracks_mult_20_100"), globalFoundBC, nITSTPCTRDtracks); else if (nTracksPV >= 100 && nTracksPV < 400) histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nITSTPCTRDtracks_mult_100_400"), globalFoundBC, nITSTPCTRDtracks); - else if (nTracksPV >= 400) - histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nITSTPCTRDtracks_mult_above_400"), globalFoundBC, nITSTPCTRDtracks); + else if (nTracksPV >= 400 && nTracksPV < 1000) + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nITSTPCTRDtracks_mult_400_1000"), globalFoundBC, nITSTPCTRDtracks); + else if (nTracksPV >= 1000) + histosEventTracksFoundBC.fill(HIST("hFoundBC_kTVX_nITSTPCTRDtracks_mult_above_1000"), globalFoundBC, nITSTPCTRDtracks); // vs bcInTF: histosEventTracksFoundBC.fill(HIST("hBCinTF_kTVX_nTracksPV"), bcInTF, nTracksPV); @@ -1216,12 +1459,13 @@ struct RobustFluctuationObservables { } // ### event selection cuts - if (!collision.sel8()) { + if (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { prevBC = collBC; prevBcInTF = bcInTF; prevOrbit = orbitInTF; prevTF = TFid; prevGlobalFoundBC = globalFoundBC; + prevFoundBcInTF = foundBcInTF; // double prev_vZ_keepForBelow = prev_vZ; prev_vZ = vZ; prev_mult = nTracksAll; @@ -1233,15 +1477,23 @@ struct RobustFluctuationObservables { // ##### check how often we analyze collision in the same BC (and also the vZ difference) if (collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { if (prevBC != 9999) { - int32_t diff = (int32_t)collBC - (int32_t)prevBC; + int32_t diff = static_cast(collBC) - static_cast(prevBC); histosEvent.fill(HIST("hBC_DIFF_to_previous"), diff); if (diff == 0) histosEvent.fill(HIST("hBC_DIFF_to_previous_vZvZ_2D"), vZ, prev_vZ); } + if (prevBcInTF >= 0) { + int32_t diffBcInTF = static_cast(bcInTF) - static_cast(prevBcInTF); + histosEvent.fill(HIST("hBCinTF_DIFF_to_previous"), diffBcInTF); + } + if (prevFoundBcInTF >= 0) { + int32_t diffGlobalBcInTF = static_cast(foundBcInTF) - static_cast(prevFoundBcInTF); + histosEvent.fill(HIST("hBCinTF_DIFF_to_previous_FOUND_BC"), diffGlobalBcInTF); + } // global found BC: if (prevGlobalFoundBC != 9999) { - int32_t diff = (int32_t)globalFoundBC - (int32_t)prevGlobalFoundBC; + int32_t diff = static_cast(globalFoundBC) - static_cast(prevGlobalFoundBC); histosEvent.fill(HIST("hBC_DIFF_to_previous_FOUND_BC"), diff); if (counterPVcontributorsAfterTPCcuts > 0) { @@ -1286,17 +1538,8 @@ struct RobustFluctuationObservables { // auto nextCollBC = bcNext.globalBC() % 3564; int64_t nextBcInTF = (bcNext.globalBC() - bcSOR) % nBCsPerTF; - // found BC - uint64_t globalNextFoundBC = 9999; //-1; - // if (nextColl.has_foundFT0() && nextColl.has_foundBC() && collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && nextColl.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { - if (nextColl.selection_bit(o2::aod::evsel::kIsTriggerTVX) && nextColl.has_foundBC() && collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && nextColl.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { - auto nextBcFound = nextColl.foundBC_as(); // collision.foundBC(); - globalNextFoundBC = nextBcFound.globalBC() % 3564; - } - // check if Found BC is NOT the same for prev, current and next events: - // if (globalFoundBC >= 0 && globalNextFoundBC >= 0 && prevGlobalFoundBC >= 0 && globalFoundBC != globalNextFoundBC && globalFoundBC != prevGlobalFoundBC) { - if (globalFoundBC != 9999 && globalNextFoundBC != 9999 && prevGlobalFoundBC != 9999 && globalFoundBC != globalNextFoundBC && globalFoundBC != prevGlobalFoundBC) { + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { flagNotTheSameFoundBC = true; // check also the distance (in BC) b/n collisions @@ -1304,8 +1547,6 @@ struct RobustFluctuationObservables { int diffWrtPrev = bcInTF - prevBcInTF; int diffWrtNext = nextBcInTF - bcInTF; - // if (TFid < 3 && (bcInTF < 50 && bcInTF > 3564 * 31 - 200)) - // cout << " --> QA: diffWrtPrev = " << diffWrtPrev << ", diffWrtNext = " << diffWrtNext << endl; if (diffWrtPrev >= 10 && diffWrtNext >= 10) flagDiffBnBcIs10 = true; // if (diffWrtPrev >= 20 && diffWrtNext >= 20) @@ -1322,6 +1563,7 @@ struct RobustFluctuationObservables { prevOrbit = orbitInTF; prevTF = TFid; prevGlobalFoundBC = globalFoundBC; + prevFoundBcInTF = foundBcInTF; double prev_vZ_keepForBelow = prev_vZ; prev_vZ = vZ; prev_mult = nTracksAll; @@ -1381,8 +1623,8 @@ struct RobustFluctuationObservables { histosEventBcInTF.fill(HIST("hGlobalTracks_vs_bcInTF"), bcInTF, nTracksGlobalAccepted); } - histosEvent.fill(HIST("hOrbitStartFromCollIndexZeroAft"), (int32_t)orbit - (int32_t)orbitAtCollIndexZero); - histosEvent.fill(HIST("h2D_Orbit_vs_CollIndex_Aft"), collision.index(), (int32_t)orbit - (int32_t)orbitAtCollIndexZero); + histosEvent.fill(HIST("hOrbitStartFromCollIndexZeroAft"), static_cast(orbit) - static_cast(orbitAtCollIndexZero)); + histosEvent.fill(HIST("h2D_Orbit_vs_CollIndex_Aft"), collision.index(), static_cast(orbit) - static_cast(orbitAtCollIndexZero)); histosEvent.fill(HIST("hMF"), magneticField); int MFsign = magneticField > 0 ? +1 : -1; @@ -1441,8 +1683,11 @@ struct RobustFluctuationObservables { histosEvent.fill(HIST("hBCFound_Aft"), globalFoundBC); histosEvent.fill(HIST("h2D_numContrib_vs_BC"), collBC, collision.numContrib()); - int64_t diffFoundBC_vs_BC = (int64_t)globalFoundBC - (int64_t)collBC; - histosEvent.fill(HIST("h2D_diffFoundBC_vs_BC"), collBC, (int64_t)globalFoundBC - (int64_t)collBC); + int64_t diffFoundBC_vs_BC = static_cast(globalFoundBC) - static_cast(collBC); + histosEvent.fill(HIST("h2D_diffFoundBC_vs_BC"), collBC, diffFoundBC_vs_BC); + + if (collision.has_foundBC()) + histosEvent.fill(HIST("h2D_diffFoundBC_vs_BC_inTF"), collBC, static_cast(foundBcInTF) - static_cast(bcInTF)); // with FT0 conditions if (isFT0) { @@ -1522,8 +1767,6 @@ struct RobustFluctuationObservables { // in addition: TF border cuts: if (collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { - // fillHistForThisCut("ITSROF_TF_cuts", multNTracksPV, multTrk, nTracksGlobalAccepted, multT0A, multT0C, multV0A, t0cCentr, collBC); - if (isFT0) { histosFT0.fill(HIST("hVertex_T0_PV_after_ITSROF_and_TFcut"), ft0_posZ, collision.posZ()); histosFT0.fill(HIST("hT0vertexDiff_after_ITSROF_and_TFcut"), diff_PV_ft0_tracks); @@ -1534,10 +1777,6 @@ struct RobustFluctuationObservables { fillHistForThisCut("antiITSROFcut", multNTracksPV, multTrk, nTracksGlobalAccepted, multT0A, multT0C, multV0A, t0cCentr, collBC); } - // global PV contributors - // if (nTracksGlobalPVAccepted >= 1) // 2) - // fillHistForThisCut("1globalPVcontrib", multNTracksPV, multTrk, nTracksGlobalAccepted, multT0A, multT0C, multV0A, t0cCentr, collBC); - // global PV contributors with 7 ITS hits if (nTracksGlobalPVwithITS7hits >= 1) // 2) fillHistForThisCut("1globalPVcontrib_ITS7hits", multNTracksPV, multTrk, nTracksGlobalAccepted, multT0A, multT0C, multV0A, t0cCentr, collBC); @@ -1550,12 +1789,8 @@ struct RobustFluctuationObservables { if (diffFoundBC_vs_BC == 0) fillHistForThisCut("diffFoundBC_vs_BC_0", multNTracksPV, multTrk, nTracksGlobalAccepted, multT0A, multT0C, multV0A, t0cCentr, collBC); - // FT0 present - // if (isFT0) - // fillHistForThisCut("hasFT0_CorrectedValid", multNTracksPV, multTrk, nTracksGlobalAccepted, multT0A, multT0C, multV0A, t0cCentr, collBC); - // cut on diff b/n vertex from FT0 and track-based - if (isFT0 && cutVzTrackT0diffLower < diff_PV_ft0_tracks && diff_PV_ft0_tracks < cutVzTrackT0diffUpper) { + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { fillHistForThisCut("PV_FT0_diff_cut", multNTracksPV, multTrk, nTracksGlobalAccepted, multT0A, multT0C, multV0A, t0cCentr, collBC); // ALL OTHER CUTS: @@ -1598,15 +1833,6 @@ struct RobustFluctuationObservables { else fillHistForThisCut("antiIsITSonlyVertex", multNTracksPV, multTrk, nTracksGlobalAccepted, multT0A, multT0C, multV0A, t0cCentr, collBC); - // cut on diff b/n vertex from FT0 and track-based - TIGHTER - // if (isFT0 && diff_PV_ft0_tracks > -0.8 && diff_PV_ft0_tracks < 0.6) { - // fillHistForThisCut("PV_FT0_diff_cut_TIGHT", multNTracksPV, multTrk, nTracksGlobalAccepted, multT0A, multT0C, multV0A, t0cCentr, collBC); - - // ALL OTHER CUTS TIGHTER: - // if (collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder) && collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && flagNotTheSameFoundBC && !isITSonlyVertex) //&& nTracksGlobalPVAccepted >= 1) - // fillHistForThisCut("ALL_CUTS_Tighter", multNTracksPV, multTrk, nTracksGlobalAccepted, multT0A, multT0C, multV0A, t0cCentr, collBC); - // } - if (collision.alias_bit(kTVXinTRD)) fillHistForThisCut("kTVXinTRD", multNTracksPV, multTrk, nTracksGlobalAccepted, multT0A, multT0C, multV0A, t0cCentr, collBC); @@ -1709,12 +1935,55 @@ struct RobustFluctuationObservables { histosTracks.fill(HIST("etaAfter08cut"), track.eta()); histosTracks.fill(HIST("hTpcNClsCrossedRows"), track.tpcNClsCrossedRows()); + histosTracks.fill(HIST("hTpcNClsFound"), track.tpcNClsFound()); histosTracks.fill(HIST("hNumITSclusters"), track.itsNCls()); + + if (track.isGlobalTrack()) { + histosTracks.fill(HIST("hTpcNClsFound_Global_beforeCrossedRowsCut"), track.tpcNClsFound()); + histosTracks.fill(HIST("hTpcNClsCrossedRows_Global_beforeCrossedRowsCut"), track.tpcNClsCrossedRows()); + histosTracks.fill(HIST("hNumITSclusters_Global_beforeCrossedRowsCut"), track.itsNCls()); + + histosTracks.fill(HIST("hNumITScls_vs_TPCcrossedRows_Global_beforeCrossedRowsCut"), track.itsNCls(), track.tpcNClsCrossedRows()); + histosTracks.fill(HIST("hDcaXY_Global_beforeCrossedRowsCut"), track.dcaXY()); + histosTracks.fill(HIST("hDcaZ_Global_beforeCrossedRowsCut"), track.dcaZ()); + } + if (isITSonlyVertex) histosTracks.fill(HIST("hNumITSclusters_ITSonlyVert"), track.itsNCls()); histosTracks.fill(HIST("hDcaXY"), track.dcaXY()); + histosTracks.fill(HIST("hDcaZ"), track.dcaZ()); + + // #### detailed pt study: + if (1) { + bool noTF = collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder); + bool noROF = collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder); + + fillPtHistos("All", track.pt(), track.sign(), track.tpcNClsFound(), noTF, noROF); + if (track.isGlobalTrack()) + fillPtHistos("Global", track.pt(), track.sign(), track.tpcNClsFound(), noTF, noROF); + + if (track.itsNCls() == 7) + fillPtHistos("ITS7hits", track.pt(), track.sign(), track.tpcNClsFound(), noTF, noROF); + if (track.itsNCls() == 7 && track.tpcNClsFound() >= 80) + fillPtHistos("ITS7hits_TPC80cl", track.pt(), track.sign(), track.tpcNClsFound(), noTF, noROF); + + if (track.itsNCls() >= 4) + fillPtHistos("ITS4567", track.pt(), track.sign(), track.tpcNClsFound(), noTF, noROF); + if (track.itsNCls() >= 4 && track.tpcNClsFound() >= 80) + fillPtHistos("ITS4567_TPC80cl", track.pt(), track.sign(), track.tpcNClsFound(), noTF, noROF); + + if (track.itsNCls() >= 5) + fillPtHistos("ITS567", track.pt(), track.sign(), track.tpcNClsFound(), noTF, noROF); + if (track.itsNCls() >= 5 && track.tpcNClsFound() >= 80) + fillPtHistos("ITS567_TPC80cl", track.pt(), track.sign(), track.tpcNClsFound(), noTF, noROF); + + if (track.itsNCls() >= 6) + fillPtHistos("ITS67", track.pt(), track.sign(), track.tpcNClsFound(), noTF, noROF); + if (track.itsNCls() >= 6 && track.tpcNClsFound() >= 80) + fillPtHistos("ITS67_TPC80cl", track.pt(), track.sign(), track.tpcNClsFound(), noTF, noROF); + + } // #### end of detailed pt study: - histosTracks.fill(HIST("ptHistogram"), track.pt()); histosTracks.fill(HIST("phiHistogram"), track.phi()); histosTracks.fill(HIST("hTrackLength"), track.length()); // from TrackExtras @@ -1813,6 +2082,7 @@ struct RobustFluctuationObservables { histosTracks.fill(HIST("hNumITSclusters_AftCuts"), track.itsNCls()); histosTracks.fill(HIST("hDcaXY_AftCuts"), track.dcaXY()); + histosTracks.fill(HIST("hDcaZ_AftCuts"), track.dcaZ()); histosTracks.fill(HIST("etaAftCuts"), track.eta()); @@ -1824,9 +2094,35 @@ struct RobustFluctuationObservables { } // end of track loop - // ##### v0 analysis - if (flagIncludeQAHistK0S) { + int occupancy = collision.trackOccupancyInTimeRange(); + histosEvent.fill(HIST("hOccupancyInTimeRange"), occupancy); + histosEvent.fill(HIST("hOccupancyInTimeRangeIsAvailable"), occupancy); + histosEvent.fill(HIST("hCentralityVsOccupancy"), occupancy, t0cCentr); + + // n events in occupancy classes + if (occupancy >= 0 && t0cCentr < 95 && collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + histosK0S.fill(HIST("nEventsVsCentrAllOccupancies"), t0cCentr); + + if (occupancy < 250) + histosK0S.fill(HIST("nEventsVsCentrAfterOccupCut_0_250"), t0cCentr); + else if (occupancy >= 250 && occupancy < 500) + histosK0S.fill(HIST("nEventsVsCentrAfterOccupCut_250_500"), t0cCentr); + else if (occupancy >= 500 && occupancy < 750) + histosK0S.fill(HIST("nEventsVsCentrAfterOccupCut_500_750"), t0cCentr); + else if (occupancy >= 750 && occupancy < 1500) + histosK0S.fill(HIST("nEventsVsCentrAfterOccupCut_750_1500"), t0cCentr); + else if (occupancy >= 1500 && occupancy < 3000) + histosK0S.fill(HIST("nEventsVsCentrAfterOccupCut_1500_3000"), t0cCentr); + else if (occupancy >= 3000 && occupancy < 4500) + histosK0S.fill(HIST("nEventsVsCentrAfterOccupCut_3000_4500"), t0cCentr); + else if (occupancy >= 4500 && occupancy < 6000) + histosK0S.fill(HIST("nEventsVsCentrAfterOccupCut_4500_6000"), t0cCentr); + else + histosK0S.fill(HIST("nEventsVsCentrAfterOccupCut_above_6000"), t0cCentr); + } + // ##### v0 analysis + if (flagIncludeQAHistK0S && collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { for (const auto& v0 : v0s) { double v0rad = v0.v0radius(); histosK0S.fill(HIST("hK0Sradius"), v0rad); @@ -1856,6 +2152,27 @@ struct RobustFluctuationObservables { histosK0S.fill(HIST("hMassK0ShortAfterSelection"), v0.mK0Short()); histosK0S.fill(HIST("hMassK0ShortAfterSelectionVsPt"), v0.pt(), v0.mK0Short()); + if (occupancy >= 0 && t0cCentr < 95 && collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder) && posDaughterTrack.tpcNClsFound() > 80 && negDaughterTrack.tpcNClsFound() > 80 && posDaughterTrack.itsNCls() >= 4 && negDaughterTrack.itsNCls() >= 4) { + histosK0S.fill(HIST("hMassK0ShortAfterSelectionVsPt_AllOccupancies"), v0.pt(), v0.mK0Short(), t0cCentr); + + if (occupancy < 250) + histosK0S.fill(HIST("hMassK0ShortAfterSelectionVsPtAfterOccupCut_0_250"), v0.pt(), v0.mK0Short(), t0cCentr); + else if (occupancy >= 250 && occupancy < 500) + histosK0S.fill(HIST("hMassK0ShortAfterSelectionVsPtAfterOccupCut_250_500"), v0.pt(), v0.mK0Short(), t0cCentr); + else if (occupancy >= 500 && occupancy < 750) + histosK0S.fill(HIST("hMassK0ShortAfterSelectionVsPtAfterOccupCut_500_750"), v0.pt(), v0.mK0Short(), t0cCentr); + else if (occupancy >= 750 && occupancy < 1500) + histosK0S.fill(HIST("hMassK0ShortAfterSelectionVsPtAfterOccupCut_750_1500"), v0.pt(), v0.mK0Short(), t0cCentr); + else if (occupancy >= 1500 && occupancy < 3000) + histosK0S.fill(HIST("hMassK0ShortAfterSelectionVsPtAfterOccupCut_1500_3000"), v0.pt(), v0.mK0Short(), t0cCentr); + else if (occupancy >= 3000 && occupancy < 4500) + histosK0S.fill(HIST("hMassK0ShortAfterSelectionVsPtAfterOccupCut_3000_4500"), v0.pt(), v0.mK0Short(), t0cCentr); + else if (occupancy >= 4500 && occupancy < 6000) + histosK0S.fill(HIST("hMassK0ShortAfterSelectionVsPtAfterOccupCut_4500_6000"), v0.pt(), v0.mK0Short(), t0cCentr); + else + histosK0S.fill(HIST("hMassK0ShortAfterSelectionVsPtAfterOccupCut_above_6000"), v0.pt(), v0.mK0Short(), t0cCentr); + } + if (TMath::Abs(posDaughterTrack.tpcNSigmaPi()) > 3) // NSigmaTPCPion) continue; if (TMath::Abs(negDaughterTrack.tpcNSigmaPi()) > 3) // NSigmaTPCPion) @@ -2019,6 +2336,43 @@ struct RobustFluctuationObservables { // } } + void fillPtHistos(string strTrackType, float pt, int charge, float w, bool noTF, bool noROF) + { + fillPtHistosThisCut(strTrackType, "allBC", pt, charge, w); + + // TF + if (noTF) + fillPtHistosThisCut(strTrackType, "noTFborder", pt, charge, w); + else + fillPtHistosThisCut(strTrackType, "TFborder", pt, charge, w); + + // ROF + if (noROF) + fillPtHistosThisCut(strTrackType, "noROFborder", pt, charge, w); + else + fillPtHistosThisCut(strTrackType, "ROFborder", pt, charge, w); + + // TF, ROF + if (noTF && noROF) + fillPtHistosThisCut(strTrackType, "noTFandROFborder", pt, charge, w); + } + + void fillPtHistosThisCut(string strTrackType, string strEvSelType, float pt, int charge, float w) + { + string strPre = strTrackType + "/" + strEvSelType; + + FILL_PT_HIST_1D(strPre + "/pt", pt, 1); + FILL_PT_HIST_1D(strPre + "/pt_w_nTPCcls", pt, w); + + if (charge > 0) { + FILL_PT_HIST_1D(strPre + "/pos_pt", pt, 1); + FILL_PT_HIST_1D(strPre + "/pos_pt_w_nTPCcls", pt, w); + } else { + FILL_PT_HIST_1D(strPre + "/neg_pt", pt, 1); + FILL_PT_HIST_1D(strPre + "/neg_pt_w_nTPCcls", pt, w); + } + } + PROCESS_SWITCH(RobustFluctuationObservables, processRobustFluctuationObservables, "Process RobustFluctuationObservables", true); }; @@ -2080,24 +2434,11 @@ struct RobustFluctuationBunchCrossingQA { histos.add("hBC_kTVXinTRD_nITSTPCTRDtracks", "hBC_kTVXinTRD_nITSTPCTRDtracks", kTH1D, {axisBC}); histos.add("hBC_kTVXinTRD_nITSTPCTOFtracks", "hBC_kTVXinTRD_nITSTPCTOFtracks", kTH1D, {axisBC}); histos.add("hBC_kTVXinTRD_nITSTPCTRDTOFtracks", "hBC_kTVXinTRD_nITSTPCTRDTOFtracks", kTH1D, {axisBC}); - - // histos.add("hCounterTCE", "", kTH1D, {{1, 0., 1.}}); - // histos.add("hCounterZEM", "", kTH1D, {{1, 0., 1.}}); - // histos.add("hCounterZNC", "", kTH1D, {{1, 0., 1.}}); - // histos.add("hLumiTVX", ";;Luminosity, 1/#mub", kTH1D, {{1, 0., 1.}}); - // histos.add("hLumiTCE", ";;Luminosity, 1/#mub", kTH1D, {{1, 0., 1.}}); - // histos.add("hLumiZEM", ";;Luminosity, 1/#mub", kTH1D, {{1, 0., 1.}}); - // histos.add("hLumiZNC", ";;Luminosity, 1/#mub", kTH1D, {{1, 0., 1.}}); } using BCsWithBcSelsRun3 = soa::Join; using FullTracksIU = soa::Join; - using Colls = soa::Join; //, aod::Mults, aod::FT0sCorrected>; - // void processRobustFluctuationBunchCrossingQA(BCsWithRun3Matchings const& bcs, - // aod::Zdcs const& zdcs, - // aod::FV0As const&, - // aod::FT0s const&, - // aod::FDDs const&) + using Colls = soa::Join; Preslice perCollision = aod::track::collisionId; void processRobustFluctuationBunchCrossingQA( diff --git a/PWGCF/EbyEFluctuations/Tasks/antiprotonCumulantsMc.cxx b/PWGCF/EbyEFluctuations/Tasks/antiprotonCumulantsMc.cxx new file mode 100644 index 00000000000..f0398450cae --- /dev/null +++ b/PWGCF/EbyEFluctuations/Tasks/antiprotonCumulantsMc.cxx @@ -0,0 +1,2950 @@ +// 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 antiprotonCumulantsMc.cxx +/// \brief Task for analyzing efficiency of proton, and net-proton distributions in MC reconstructed and generated, and calculating net-proton cumulants +/// \author Swati Saha + +#include +#include +#include +#include +#include +#include +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/StepTHn.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/Core/trackUtilities.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include +#include +#include +#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; + +struct AntiprotonCumulantsMc { + // events + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + // MC + Configurable cfgIsMC{"cfgIsMC", true, "Run MC"}; + // tracks + Configurable cfgCutPtLower{"cfgCutPtLower", 0.2f, "Lower pT cut"}; + Configurable cfgCutPtUpper{"cfgCutPtUpper", 3.0f, "Higher pT cut"}; + Configurable cfgCutEta{"cfgCutEta", 0.8f, "absolute Eta cut"}; + Configurable cfgPIDchoice{"cfgPIDchoice", 1, "PID selection fucntion choice"}; + Configurable cfgCutPtUpperTPC{"cfgCutPtUpperTPC", 0.6f, "Upper pT cut for PID using TPC only"}; + Configurable cfgnSigmaCutTPC{"cfgnSigmaCutTPC", 2.0f, "PID nSigma cut for TPC"}; + Configurable cfgnSigmaCutTOF{"cfgnSigmaCutTOF", 2.0f, "PID nSigma cut for TOF"}; + Configurable cfgnSigmaCutCombTPCTOF{"cfgnSigmaCutCombTPCTOF", 2.0f, "PID nSigma combined cut for TPC and TOF"}; + Configurable cfgCutTpcChi2NCl{"cfgCutTpcChi2NCl", 2.5f, "Maximum TPCchi2NCl"}; + Configurable cfgCutItsChi2NCl{"cfgCutItsChi2NCl", 36.0f, "Maximum ITSchi2NCl"}; + Configurable cfgCutDCAxy{"cfgCutDCAxy", 2.0f, "DCAxy range for tracks"}; + Configurable cfgCutDCAz{"cfgCutDCAz", 2.0f, "DCAz range for tracks"}; + Configurable cfgITScluster{"cfgITScluster", 1, "Minimum Number of ITS cluster"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 80, "Minimum Number of TPC cluster"}; + Configurable cfgTPCnCrossedRows{"cfgTPCnCrossedRows", 70, "Minimum Number of TPC crossed-rows"}; + Configurable cfgUseItsPid{"cfgUseItsPid", true, "Use ITS nSigma Cut"}; + + // Calculation of cumulants central/error + Configurable cfgNSubsample{"cfgNSubsample", 10, "Number of subsamples for ERR"}; + Configurable cfgIsCalculateCentral{"cfgIsCalculateCentral", true, "Calculate Central value"}; + Configurable cfgIsCalculateError{"cfgIsCalculateError", false, "Calculate Error"}; + + // Efficiencies + Configurable> cfgPtBins{"cfgPtBins", {0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0}, "Pt Bins for Efficiency of protons"}; + Configurable> cfgProtonEff{"cfgProtonEff", {0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9}, "Efficiency of protons"}; + Configurable> cfgAntiprotonEff{"cfgAntiprotonEff", {0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9}, "Efficiency of anti-protons"}; + + Configurable cfgLoadEff{"cfgLoadEff", true, "Load efficiency from file"}; + Configurable cfgEvSelkNoSameBunchPileup{"cfgEvSelkNoSameBunchPileup", true, "Pileup removal"}; + Configurable cfgUseGoodITSLayerAllCut{"cfgUseGoodITSLayerAllCut", true, "Remove time interval with dead ITS zone"}; + Configurable cfgIfRejectElectron{"cfgIfRejectElectron", true, "Remove electrons"}; + Configurable cfgIfMandatoryTOF{"cfgIfMandatoryTOF", true, "Mandatory TOF requirement to remove pileup"}; + Configurable cfgEvSelkIsVertexTOFmatched{"cfgEvSelkIsVertexTOFmatched", true, "If matched with TOF, for pileup"}; + ConfigurableAxis cfgCentralityBins{"cfgCentralityBins", {90, 0., 90.}, "Centrality/Multiplicity percentile bining"}; + + // Connect to ccdb + Service ccdb; + Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable ccdbUrl{"ccdbUrl", "https://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPath{"ccdbPath", "Users/s/swati/EtavsPtEfficiency_LHC24f3b_PIDchoice0", "CCDB path to ccdb object containing eff(pt, eta) in 2D hist"}; + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + TRandom3* fRndm = new TRandom3(0); + + // Eff histograms 2d: eff(pT, eta) + TH2F* hRatio2DEtaVsPtProton = nullptr; + TH2F* hRatio2DEtaVsPtAntiproton = nullptr; + + // Filter command for rec (data)*********** + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtLower) && (aod::track::pt < 5.0f) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (aod::track::tpcChi2NCl < cfgCutTpcChi2NCl) && (aod::track::itsChi2NCl < cfgCutItsChi2NCl) && (nabs(aod::track::dcaZ) < cfgCutDCAz) && (nabs(aod::track::dcaXY) < cfgCutDCAxy); + + // filtering collisions and tracks for real data*********** + using AodCollisions = soa::Filtered>; + using AodTracks = soa::Filtered>; + + // filtering collisions and tracks for MC rec data*********** + using MyMCRecCollisions = soa::Filtered>; + using MyMCRecCollision = MyMCRecCollisions::iterator; + using MyMCTracks = soa::Filtered>; + using EventCandidatesMC = soa::Join; + + // Equivalent of the AliRoot task UserCreateOutputObjects + void init(o2::framework::InitContext&) + { + // Loading efficiency histograms from ccdb + if (cfgLoadEff) { + + // Accessing eff histograms + ccdb->setURL(ccdbUrl.value); + // Enabling object caching, otherwise each call goes to the CCDB server + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + // Not later than now, will be replaced by the value of the train creation + // This avoids that users can replace objects **while** a train is running + ccdb->setCreatedNotAfter(ccdbNoLaterThan.value); + LOGF(info, "Getting object %s", ccdbPath.value.data()); + TList* lst = ccdb->getForTimeStamp(ccdbPath.value, ccdbNoLaterThan.value); + hRatio2DEtaVsPtProton = reinterpret_cast(lst->FindObject("hRatio2DEtaVsPtProton")); + hRatio2DEtaVsPtAntiproton = reinterpret_cast(lst->FindObject("hRatio2DEtaVsPtAntiproton")); + if (!hRatio2DEtaVsPtProton || !hRatio2DEtaVsPtAntiproton) + LOGF(info, "FATAL!! could not get efficiency---------> check"); + } + + // Define your axes + // Constant bin width axis + AxisSpec vtxZAxis = {100, -20, 20}; + // Variable bin width axis + std::vector ptBinning = {0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0}; + AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; + std::vector etaBinning = {-0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8}; + AxisSpec etaAxis = {etaBinning, "#it{#eta}"}; + // std::vector centBining = {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90}; + // AxisSpec centAxis = {centBining, "Multiplicity percentile from FT0M (%)"}; + const AxisSpec centAxis{cfgCentralityBins, "Multiplicity percentile from FT0M (%)"}; + AxisSpec netprotonAxis = {41, -20.5, 20.5, "net-proton number"}; + AxisSpec protonAxis = {21, -0.5, 20.5, "proton number"}; + AxisSpec antiprotonAxis = {21, -0.5, 20.5, "antiproton number"}; + AxisSpec nSigmaAxis = {200, -5.0, 5.0, "nSigma(Proton)"}; + + auto noSubsample = static_cast(cfgNSubsample); + float maxSubsample = 1.0 * noSubsample; + AxisSpec subsampleAxis = {noSubsample, 0.0, maxSubsample, "subsample no."}; + + // histograms for events + histos.add("hZvtx_after_sel", "Vertex dist. after event selection;Z (cm)", kTH1F, {vtxZAxis}); + histos.add("hCentrec", "MCRec Multiplicity percentile from FT0M (%)", kTH1F, {{100, 0.0, 100.0}}); + // tracks Rec level histograms + histos.add("hrecPtAll", "Reconstructed All particles;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hrecPtProton", "Reconstructed Protons;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hrecPtAntiproton", "Reconstructed Antiprotons;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hrecPhiAll", "Reconstructed All particles;#phi", kTH1F, {{100, 0., 7.}}); + histos.add("hrecPhiProton", "Reconstructed Protons;#phi", kTH1F, {{100, 0., 7.}}); + histos.add("hrecPhiAntiproton", "Reconstructed Antiprotons;#phi", kTH1F, {{100, 0., 7.}}); + histos.add("hrecEtaAll", "Reconstructed All particles;#eta", kTH1F, {{100, -2.01, 2.01}}); + histos.add("hrecEtaProton", "Reconstructed Proton;#eta", kTH1F, {{100, -2.01, 2.01}}); + histos.add("hrecEtaAntiproton", "Reconstructed Antiprotons;#eta", kTH1F, {{100, -2.01, 2.01}}); + histos.add("hrecDcaXYAll", "Reconstructed All particles;DCA_{xy} (in cm)", kTH1F, {{400, -2.0, 2.0}}); + histos.add("hrecDcaXYProton", "Reconstructed Proton;DCA_{xy} (in cm)", kTH1F, {{400, -2.0, 2.0}}); + histos.add("hrecDcaXYAntiproton", "Reconstructed Antiprotons;DCA_{xy} (in cm)", kTH1F, {{400, -2.0, 2.0}}); + histos.add("hrecDcaZAll", "Reconstructed All particles;DCA_{z} (in cm)", kTH1F, {{400, -2.0, 2.0}}); + histos.add("hrecDcaZProton", "Reconstructed Proton;DCA_{z} (in cm)", kTH1F, {{400, -2.0, 2.0}}); + histos.add("hrecDcaZAntiproton", "Reconstructed Antiprotons;DCA_{z} (in cm)", kTH1F, {{400, -2.0, 2.0}}); + histos.add("hrecPtDistProtonVsCentrality", "Reconstructed proton number vs centrality in 2D", kTH2F, {ptAxis, centAxis}); + histos.add("hrecPtDistAntiprotonVsCentrality", "Reconstructed antiproton number vs centrality in 2D", kTH2F, {ptAxis, centAxis}); + + histos.add("hrecProtonVsCentrality", "Reconstructed proton number vs centrality in 2D", kTH2F, {protonAxis, centAxis}); + histos.add("hrecAntiprotonVsCentrality", "Reconstructed antiproton number vs centrality in 2D", kTH2F, {antiprotonAxis, centAxis}); + histos.add("hrecProfileTotalProton", "Reconstructed total proton number vs. centrality", kTProfile, {centAxis}); + histos.add("hrecProfileProton", "Reconstructed proton number vs. centrality", kTProfile, {centAxis}); + histos.add("hrecProfileAntiproton", "Reconstructed antiproton number vs. centrality", kTProfile, {centAxis}); + histos.add("hCorrProfileTotalProton", "Eff. Corrected total proton number vs. centrality", kTProfile, {centAxis}); + histos.add("hCorrProfileProton", "Eff. Corrected proton number vs. centrality", kTProfile, {centAxis}); + histos.add("hCorrProfileAntiproton", "Eff. Corrected antiproton number vs. centrality", kTProfile, {centAxis}); + histos.add("hrec2DEtaVsPtProton", "2D hist of Reconstructed Proton y: eta vs. x: pT", kTH2F, {ptAxis, etaAxis}); + histos.add("hrec2DEtaVsPtAntiproton", "2D hist of Reconstructed Anti-proton y: eta vs. x: pT", kTH2F, {ptAxis, etaAxis}); + histos.add("hgen2DEtaVsPtProton", "2D hist of Generated Proton y: eta vs. x: pT", kTH2F, {ptAxis, etaAxis}); + histos.add("hgen2DEtaVsPtAntiproton", "2D hist of Generated Anti-proton y: eta vs. x: pT", kTH2F, {ptAxis, etaAxis}); + + // 2D histograms of nSigma + histos.add("h2DnsigmaTpcVsPt", "2D hist of nSigmaTPC vs. pT", kTH2F, {ptAxis, nSigmaAxis}); + histos.add("h2DnsigmaTofVsPt", "2D hist of nSigmaTOF vs. pT", kTH2F, {ptAxis, nSigmaAxis}); + histos.add("h2DnsigmaItsVsPt", "2D hist of nSigmaITS vs. pT", kTH2F, {ptAxis, nSigmaAxis}); + + if (cfgIsCalculateCentral) { + // uncorrected + histos.add("Prof_mu1_antiproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_mu2_antiproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_mu3_antiproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_mu4_antiproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_mu5_antiproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_mu6_antiproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_mu7_antiproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_mu8_antiproton", "", {HistType::kTProfile, {centAxis}}); + + // eff. corrected + histos.add("Prof_Q11_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q11_2", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q11_3", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q11_4", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q21_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q22_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q31_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q32_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q33_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q41_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q42_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q43_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q44_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q21_2", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q22_2", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1131_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1131_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1131_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1132_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1132_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1132_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1133_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1133_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1133_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2122_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2122_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2122_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3132_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3132_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3132_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3133_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3133_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3133_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3233_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3233_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3233_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2241_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2241_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2241_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2242_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2242_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2242_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2243_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2243_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2243_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2244_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2244_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2244_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2141_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2141_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2141_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2142_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2142_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2142_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2143_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2143_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2143_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2144_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2144_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2144_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1151_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1151_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1151_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1152_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1152_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1152_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1153_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1153_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1153_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1154_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1154_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1154_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1155_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1155_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1155_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112233_001", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112233_010", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112233_100", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112233_011", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112233_101", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112233_110", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112232_001", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112232_010", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112232_100", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112232_011", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112232_101", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112232_110", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112231_001", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112231_010", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112231_100", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112231_011", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112231_101", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112231_110", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112133_001", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112133_010", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112133_100", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112133_011", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112133_101", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112133_110", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112132_001", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112132_010", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112132_100", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112132_011", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112132_101", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112132_110", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112131_001", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112131_010", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112131_100", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112131_011", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112131_101", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112131_110", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2221_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2221_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2221_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2221_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2221_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2122_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2122_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_02", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_12", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_22", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_02", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_12", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_22", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_001", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_010", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_100", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_011", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_101", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_110", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_200", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_201", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_210", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_211", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1131_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1131_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1131_31", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1131_30", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1132_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1132_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1132_31", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1132_30", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1133_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1133_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1133_31", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1133_30", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q11_5", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q11_6", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_30", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_31", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_40", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_41", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_30", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_31", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_40", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_41", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2211_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2211_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2211_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2211_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2211_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2111_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2111_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2111_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2111_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2111_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112122_001", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112122_010", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112122_100", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112122_011", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112122_101", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112122_110", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1141_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1141_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1141_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1141_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1141_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1142_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1142_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1142_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1142_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1142_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1143_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1143_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1143_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1143_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1143_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1144_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1144_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1144_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1144_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1144_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2131_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2131_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2131_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2132_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2132_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2132_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2133_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2133_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2133_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2231_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2231_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2231_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2232_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2232_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2232_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2233_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2233_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2233_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q51_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q52_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q53_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q54_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q55_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q21_3", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q22_3", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q31_2", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q32_2", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q33_2", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q61_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q62_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q63_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q64_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q65_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q66_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112122_111", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112131_111", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112132_111", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112133_111", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112231_111", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112232_111", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112233_111", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_111", "", {HistType::kTProfile, {centAxis}}); + } + + if (cfgIsCalculateError) { + // uncorrected + histos.add("Prof2D_mu1_antiproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_mu2_antiproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_mu3_antiproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_mu4_antiproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_mu5_antiproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_mu6_antiproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_mu7_antiproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_mu8_antiproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + + // eff. corrected + histos.add("Prof2D_Q11_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q11_2", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q11_3", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q11_4", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q21_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q22_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q31_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q32_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q33_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q41_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q42_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q43_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q44_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q21_2", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q22_2", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1131_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1131_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1131_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1132_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1132_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1132_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1133_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1133_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1133_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2122_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2122_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2122_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3132_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3132_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3132_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3133_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3133_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3133_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3233_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3233_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3233_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2241_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2241_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2241_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2242_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2242_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2242_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2243_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2243_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2243_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2244_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2244_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2244_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2141_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2141_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2141_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2142_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2142_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2142_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2143_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2143_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2143_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2144_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2144_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2144_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1151_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1151_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1151_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1152_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1152_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1152_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1153_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1153_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1153_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1154_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1154_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1154_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1155_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1155_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1155_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112233_001", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112233_010", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112233_100", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112233_011", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112233_101", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112233_110", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112232_001", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112232_010", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112232_100", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112232_011", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112232_101", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112232_110", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112231_001", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112231_010", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112231_100", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112231_011", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112231_101", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112231_110", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112133_001", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112133_010", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112133_100", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112133_011", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112133_101", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112133_110", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112132_001", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112132_010", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112132_100", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112132_011", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112132_101", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112132_110", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112131_001", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112131_010", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112131_100", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112131_011", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112131_101", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112131_110", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2221_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2221_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2221_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2221_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2221_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2122_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2122_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_02", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_12", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_22", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_02", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_12", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_22", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_001", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_010", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_100", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_011", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_101", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_110", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_200", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_201", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_210", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_211", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1131_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1131_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1131_31", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1131_30", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1132_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1132_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1132_31", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1132_30", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1133_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1133_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1133_31", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1133_30", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q11_5", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q11_6", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_30", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_31", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_40", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_41", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_30", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_31", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_40", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_41", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2211_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2211_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2211_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2211_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2211_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2111_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2111_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2111_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2111_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2111_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112122_001", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112122_010", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112122_100", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112122_011", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112122_101", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112122_110", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1141_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1141_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1141_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1141_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1141_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1142_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1142_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1142_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1142_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1142_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1143_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1143_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1143_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1143_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1143_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1144_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1144_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1144_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1144_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1144_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2131_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2131_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2131_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2132_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2132_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2132_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2133_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2133_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2133_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2231_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2231_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2231_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2232_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2232_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2232_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2233_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2233_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2233_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q51_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q52_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q53_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q54_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q55_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q21_3", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q22_3", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q31_2", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q32_2", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q33_2", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q61_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q62_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q63_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q64_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q65_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q66_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112122_111", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112131_111", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112132_111", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112133_111", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112231_111", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112232_111", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112233_111", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_111", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + } + + if (cfgIsMC) { + // MC event counts + histos.add("hMC", "MC Event statistics", kTH1F, {{10, 0.0f, 10.0f}}); + histos.add("hCentgen", "MCGen Multiplicity percentile from FT0M (%)", kTH1F, {{100, 0.0, 100.0}}); + // tracks Gen level histograms + histos.add("hgenPtAll", "Generated All particles;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hgenPtProton", "Generated Protons;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hgenPtAntiproton", "Generated Antiprotons;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hrecPartPtAll", "Reconstructed All particles filled mcparticle pt;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hrecPartPtProton", "Reconstructed Protons filled mcparticle pt;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hrecPartPtAntiproton", "Reconstructed Antiprotons filled mcparticle pt;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hgenPhiAll", "Generated All particles;#phi", kTH1F, {{100, 0., 7.}}); + histos.add("hgenPhiProton", "Generated Protons;#phi", kTH1F, {{100, 0., 7.}}); + histos.add("hgenPhiAntiproton", "Generated Antiprotons;#phi", kTH1F, {{100, 0., 7.}}); + histos.add("hgenEtaAll", "Generated All particles;#eta", kTH1F, {{100, -2.01, 2.01}}); + histos.add("hgenEtaProton", "Generated Proton;#eta", kTH1F, {{100, -2.01, 2.01}}); + histos.add("hgenEtaAntiproton", "Generated Antiprotons;#eta", kTH1F, {{100, -2.01, 2.01}}); + histos.add("hgenPtDistProtonVsCentrality", "Generated proton number vs centrality in 2D", kTH2F, {ptAxis, centAxis}); + histos.add("hgenPtDistAntiprotonVsCentrality", "Generated antiproton number vs centrality in 2D", kTH2F, {ptAxis, centAxis}); + histos.add("hrecTruePtProton", "Reconstructed pdgcode verified protons;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hrecTruePtAntiproton", "Reconstructed pdgcode verified Antiprotons;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + + histos.add("hgenProtonVsCentrality", "Generated proton number vs centrality in 2D", kTH2F, {protonAxis, centAxis}); + histos.add("hgenAntiprotonVsCentrality", "Generated antiproton number vs centrality in 2D", kTH2F, {antiprotonAxis, centAxis}); + histos.add("hgenProfileTotalProton", "Generated total proton number vs. centrality", kTProfile, {centAxis}); + histos.add("hgenProfileProton", "Generated proton number vs. centrality", kTProfile, {centAxis}); + histos.add("hgenProfileAntiproton", "Generated antiproton number vs. centrality", kTProfile, {centAxis}); + + if (cfgIsCalculateCentral) { + histos.add("GenProf_mu1_antiproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("GenProf_mu2_antiproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("GenProf_mu3_antiproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("GenProf_mu4_antiproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("GenProf_mu5_antiproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("GenProf_mu6_antiproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("GenProf_mu7_antiproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("GenProf_mu8_antiproton", "", {HistType::kTProfile, {centAxis}}); + } + + if (cfgIsCalculateError) { + histos.add("GenProf2D_mu1_antiproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("GenProf2D_mu2_antiproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("GenProf2D_mu3_antiproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("GenProf2D_mu4_antiproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("GenProf2D_mu5_antiproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("GenProf2D_mu6_antiproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("GenProf2D_mu7_antiproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("GenProf2D_mu8_antiproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + } + } + } // end init() + + template + bool selectionPIDold(const T& candidate) + { + if (!candidate.hasTPC()) + return false; + + //! PID checking as done in Run2 my analysis + //! ---------------------------------------------------------------------- + int flag = 0; //! pid check main flag + + if (candidate.pt() > 0.2f && candidate.pt() <= cfgCutPtUpperTPC) { + if (std::abs(candidate.tpcNSigmaPr()) < cfgnSigmaCutTPC) { + flag = 1; + } + } + if (candidate.hasTOF() && candidate.pt() > cfgCutPtUpperTPC && candidate.pt() < 5.0f) { + const float combNSigmaPr = std::sqrt(std::pow(candidate.tpcNSigmaPr(), 2.0) + std::pow(candidate.tofNSigmaPr(), 2.0)); + const float combNSigmaPi = std::sqrt(std::pow(candidate.tpcNSigmaPi(), 2.0) + std::pow(candidate.tofNSigmaPi(), 2.0)); + const float combNSigmaKa = std::sqrt(std::pow(candidate.tpcNSigmaKa(), 2.0) + std::pow(candidate.tofNSigmaKa(), 2.0)); + + int flag2 = 0; + if (combNSigmaPr < 3.0) + flag2 += 1; + if (combNSigmaPi < 3.0) + flag2 += 1; + if (combNSigmaKa < 3.0) + flag2 += 1; + if (!(flag2 > 1) && !(combNSigmaPr > combNSigmaPi) && !(combNSigmaPr > combNSigmaKa)) { + if (combNSigmaPr < cfgnSigmaCutCombTPCTOF) { + flag = 1; + } + } + } + if (flag == 1) + return true; + else + return false; + } + + template + bool selectionPIDoldTOFveto(const T& candidate) + { + if (!candidate.hasTPC()) + return false; + + //! PID checking as done in Run2 my analysis + //! ---------------------------------------------------------------------- + int flag = 0; //! pid check main flag + + if (candidate.pt() > 0.2f && candidate.pt() <= cfgCutPtUpperTPC) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < cfgnSigmaCutTPC) { + flag = 1; + } + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < cfgnSigmaCutTPC && std::abs(candidate.tofNSigmaPr()) < cfgnSigmaCutTOF) { + flag = 1; + } + } + if (candidate.hasTOF() && candidate.pt() > cfgCutPtUpperTPC && candidate.pt() < 5.0f) { + const float combNSigmaPr = std::sqrt(std::pow(candidate.tpcNSigmaPr(), 2.0) + std::pow(candidate.tofNSigmaPr(), 2.0)); + const float combNSigmaPi = std::sqrt(std::pow(candidate.tpcNSigmaPi(), 2.0) + std::pow(candidate.tofNSigmaPi(), 2.0)); + const float combNSigmaKa = std::sqrt(std::pow(candidate.tpcNSigmaKa(), 2.0) + std::pow(candidate.tofNSigmaKa(), 2.0)); + + int flag2 = 0; + if (combNSigmaPr < 3.0) + flag2 += 1; + if (combNSigmaPi < 3.0) + flag2 += 1; + if (combNSigmaKa < 3.0) + flag2 += 1; + if (!(flag2 > 1) && !(combNSigmaPr > combNSigmaPi) && !(combNSigmaPr > combNSigmaKa)) { + if (combNSigmaPr < cfgnSigmaCutCombTPCTOF) { + flag = 1; + } + } + } + if (flag == 1) + return true; + else + return false; + } + + // electron rejection function + template + bool isElectron(const T& candidate) // Victor's BF analysis + { + if (candidate.tpcNSigmaEl() > -3.0f && candidate.tpcNSigmaEl() < 5.0f && std::abs(candidate.tpcNSigmaPi()) > 3.0f && std::abs(candidate.tpcNSigmaKa()) > 3.0f && std::abs(candidate.tpcNSigmaPr()) > 3.0f) { + return true; + } + return false; + } + + template + bool selectionPIDnew(const T& candidate) // Victor's BF analysis + { + // electron rejection + if (candidate.tpcNSigmaEl() > -3.0f && candidate.tpcNSigmaEl() < 5.0f && std::abs(candidate.tpcNSigmaPi()) > 3.0f && std::abs(candidate.tpcNSigmaKa()) > 3.0f && std::abs(candidate.tpcNSigmaPr()) > 3.0f) { + return false; + } + + //! if pt < threshold + if (candidate.pt() > 0.2f && candidate.pt() <= cfgCutPtUpperTPC) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < cfgnSigmaCutTPC && std::abs(candidate.tpcNSigmaPi()) > cfgnSigmaCutTPC && std::abs(candidate.tpcNSigmaKa()) > cfgnSigmaCutTPC) { + return true; + } + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < cfgnSigmaCutTPC && std::abs(candidate.tpcNSigmaPi()) > cfgnSigmaCutTPC && std::abs(candidate.tpcNSigmaKa()) > cfgnSigmaCutTPC && std::abs(candidate.tofNSigmaPr()) < cfgnSigmaCutTOF && std::abs(candidate.tofNSigmaPi()) > cfgnSigmaCutTOF && std::abs(candidate.tofNSigmaKa()) > cfgnSigmaCutTOF) { + return true; + } + } + + //! if pt > threshold + if (candidate.pt() > cfgCutPtUpperTPC) { + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < cfgnSigmaCutTPC && std::abs(candidate.tpcNSigmaPi()) > cfgnSigmaCutTPC && std::abs(candidate.tpcNSigmaKa()) > cfgnSigmaCutTPC && std::abs(candidate.tofNSigmaPr()) < cfgnSigmaCutTOF && std::abs(candidate.tofNSigmaPi()) > cfgnSigmaCutTOF && std::abs(candidate.tofNSigmaKa()) > cfgnSigmaCutTOF) { + return true; + } + } + return false; + } + + // Function to check which pt bin the track lies in and assign the corresponding efficiency + + template + float getEfficiency(const T& candidate) + { + // Load eff from histograms in CCDB + if (cfgLoadEff) { + if (candidate.sign() > 0) { + float effmeanval = hRatio2DEtaVsPtProton->GetBinContent(hRatio2DEtaVsPtProton->FindBin(candidate.pt(), candidate.eta())); + return effmeanval; + } + if (candidate.sign() < 0) { + float effmeanval = hRatio2DEtaVsPtAntiproton->GetBinContent(hRatio2DEtaVsPtAntiproton->FindBin(candidate.pt(), candidate.eta())); + return effmeanval; + } + return 0.0; + } else { + // Find the pt bin index based on the track's pt value + int binIndex = -1; + + for (int i = 0; i < 16; ++i) { + if (candidate.pt() >= cfgPtBins.value[i] && candidate.pt() < cfgPtBins.value[i + 1]) { + binIndex = i; + break; + } + } + // If the pt is outside the defined bins, return a default efficiency or handle it differently + if (binIndex == -1) { + return 0.0; // Default efficiency (0% if outside bins) + } + if (candidate.sign() > 0) + return cfgProtonEff.value[binIndex]; + if (candidate.sign() < 0) + return cfgAntiprotonEff.value[binIndex]; + return 0.0; + } + } + + void processMCGen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& collisions) + { + histos.fill(HIST("hMC"), 0.5); + if (std::abs(mcCollision.posZ()) < cfgCutVertex) { + histos.fill(HIST("hMC"), 1.5); + } + auto cent = 0; + + int nchInel = 0; + for (const auto& mcParticle : mcParticles) { + auto pdgcode = std::abs(mcParticle.pdgCode()); + if (mcParticle.isPhysicalPrimary() && (pdgcode == PDG_t::kPiPlus || pdgcode == PDG_t::kKPlus || pdgcode == PDG_t::kProton || pdgcode == PDG_t::kElectron || pdgcode == PDG_t::kMuonMinus)) { + if (std::abs(mcParticle.eta()) < 1.0) { + nchInel = nchInel + 1; + } + } + } + if (nchInel > 0 && std::abs(mcCollision.posZ()) < cfgCutVertex) + histos.fill(HIST("hMC"), 2.5); + std::vector selectedEvents(collisions.size()); + int nevts = 0; + + for (const auto& collision : collisions) { + if (!collision.sel8() || std::abs(collision.mcCollision().posZ()) > cfgCutVertex) { + continue; + } + if (cfgUseGoodITSLayerAllCut && !(collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll))) { + continue; + } + if (cfgEvSelkNoSameBunchPileup && !(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { + continue; + } + if (cfgEvSelkIsVertexTOFmatched && !(collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched))) { + continue; + } + + cent = collision.centFT0M(); + + selectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); + } + selectedEvents.resize(nevts); + const auto evtReconstructedAndSelected = std::find(selectedEvents.begin(), selectedEvents.end(), mcCollision.globalIndex()) != selectedEvents.end(); + histos.fill(HIST("hMC"), 3.5); + if (!evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection + return; + } + histos.fill(HIST("hMC"), 4.5); + histos.fill(HIST("hCentgen"), cent); + + // creating phi, pt, eta dstribution of generted MC particles + + float nProt = 0.0; + float nAntiprot = 0.0; + + for (const auto& mcParticle : mcParticles) { + if (!mcParticle.has_mcCollision()) + continue; + + if (mcParticle.isPhysicalPrimary()) { + if ((mcParticle.pt() > cfgCutPtLower) && (mcParticle.pt() < 5.0f) && (std::abs(mcParticle.eta()) < cfgCutEta)) { + histos.fill(HIST("hgenPtAll"), mcParticle.pt()); + histos.fill(HIST("hgenEtaAll"), mcParticle.eta()); + histos.fill(HIST("hgenPhiAll"), mcParticle.phi()); + + if (std::abs(mcParticle.pdgCode()) == PDG_t::kProton /*&& std::abs(mcParticle.y()) < 0.5*/) { + if (mcParticle.pdgCode() == PDG_t::kProton) { + histos.fill(HIST("hgenPtProton"), mcParticle.pt()); //! hist for p gen + histos.fill(HIST("hgenPtDistProtonVsCentrality"), mcParticle.pt(), cent); + histos.fill(HIST("hgen2DEtaVsPtProton"), mcParticle.pt(), mcParticle.eta()); + histos.fill(HIST("hgenEtaProton"), mcParticle.eta()); + histos.fill(HIST("hgenPhiProton"), mcParticle.phi()); + if (mcParticle.pt() < cfgCutPtUpper) + nProt = nProt + 1.0; + } + if (mcParticle.pdgCode() == PDG_t::kProtonBar) { + histos.fill(HIST("hgenPtAntiproton"), mcParticle.pt()); //! hist for anti-p gen + histos.fill(HIST("hgenPtDistAntiprotonVsCentrality"), mcParticle.pt(), cent); + histos.fill(HIST("hgen2DEtaVsPtAntiproton"), mcParticle.pt(), mcParticle.eta()); + histos.fill(HIST("hgenEtaAntiproton"), mcParticle.eta()); + histos.fill(HIST("hgenPhiAntiproton"), mcParticle.phi()); + if (mcParticle.pt() < cfgCutPtUpper) + nAntiprot = nAntiprot + 1.0; + } + } + } + } + } //! end particle loop + + float netProt = nAntiprot; // here we are interested in antiproton cumulants + + histos.fill(HIST("hgenProtonVsCentrality"), nProt, cent); + histos.fill(HIST("hgenAntiprotonVsCentrality"), nAntiprot, cent); + histos.fill(HIST("hgenProfileTotalProton"), cent, (nProt + nAntiprot)); + histos.fill(HIST("hgenProfileProton"), cent, nProt); + histos.fill(HIST("hgenProfileAntiproton"), cent, nAntiprot); + + // Profiles for generated level cumulants + //------------------------------------------------------------------------------------------- + + if (cfgIsCalculateCentral) { + histos.get(HIST("GenProf_mu1_antiproton"))->Fill(cent, std::pow(netProt, 1.0)); + histos.get(HIST("GenProf_mu2_antiproton"))->Fill(cent, std::pow(netProt, 2.0)); + histos.get(HIST("GenProf_mu3_antiproton"))->Fill(cent, std::pow(netProt, 3.0)); + histos.get(HIST("GenProf_mu4_antiproton"))->Fill(cent, std::pow(netProt, 4.0)); + histos.get(HIST("GenProf_mu5_antiproton"))->Fill(cent, std::pow(netProt, 5.0)); + histos.get(HIST("GenProf_mu6_antiproton"))->Fill(cent, std::pow(netProt, 6.0)); + histos.get(HIST("GenProf_mu7_antiproton"))->Fill(cent, std::pow(netProt, 7.0)); + histos.get(HIST("GenProf_mu8_antiproton"))->Fill(cent, std::pow(netProt, 8.0)); + } + + if (cfgIsCalculateError) { + + float lRandom = fRndm->Rndm(); + int sampleIndex = static_cast(cfgNSubsample * lRandom); + + histos.get(HIST("GenProf2D_mu1_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 1.0)); + histos.get(HIST("GenProf2D_mu2_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 2.0)); + histos.get(HIST("GenProf2D_mu3_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 3.0)); + histos.get(HIST("GenProf2D_mu4_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 4.0)); + histos.get(HIST("GenProf2D_mu5_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 5.0)); + histos.get(HIST("GenProf2D_mu6_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 6.0)); + histos.get(HIST("GenProf2D_mu7_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 7.0)); + histos.get(HIST("GenProf2D_mu8_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 8.0)); + } + //------------------------------------------------------------------------------------------- + } + PROCESS_SWITCH(AntiprotonCumulantsMc, processMCGen, "Process Generated", true); + + void processMCRec(MyMCRecCollision const& collision, MyMCTracks const& tracks, aod::McCollisions const&, aod::McParticles const&) + { + if (!collision.has_mcCollision()) { + return; + } + + if (!collision.sel8()) { + return; + } + if (cfgUseGoodITSLayerAllCut && !(collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll))) { + return; + } + if (cfgEvSelkNoSameBunchPileup && !(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { + return; + } + if (cfgEvSelkIsVertexTOFmatched && !(collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched))) { + return; + ; + } + + auto cent = collision.centFT0M(); + histos.fill(HIST("hCentrec"), cent); + histos.fill(HIST("hMC"), 5.5); + histos.fill(HIST("hZvtx_after_sel"), collision.posZ()); + + float nProt = 0.0; + float nAntiprot = 0.0; + std::array powerEffProt = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + std::array powerEffAntiprot = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + std::array fTCP0 = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + std::array fTCP1 = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + + o2::aod::ITSResponse itsResponse; + + // Start of the Monte-Carlo reconstructed tracks + for (const auto& track : tracks) { + if (!track.has_collision()) { + continue; + } + + if (!track.has_mcParticle()) //! check if track has corresponding MC particle + { + continue; + } + if (!track.isPVContributor()) //! track check as used in data + { + continue; + } + + auto particle = track.mcParticle(); + if (!particle.has_mcCollision()) + continue; + + if ((particle.pt() < cfgCutPtLower) || (particle.pt() > 5.0f) || (std::abs(particle.eta()) > cfgCutEta)) { + continue; + } + if (!(track.itsNCls() > cfgITScluster) || !(track.tpcNClsFound() >= cfgTPCcluster) || !(track.tpcNClsCrossedRows() >= cfgTPCnCrossedRows)) { + continue; + } + + if (particle.isPhysicalPrimary()) { + histos.fill(HIST("hrecPartPtAll"), particle.pt()); + histos.fill(HIST("hrecPtAll"), track.pt()); + histos.fill(HIST("hrecEtaAll"), particle.eta()); + histos.fill(HIST("hrecPhiAll"), particle.phi()); + histos.fill(HIST("hrecDcaXYAll"), track.dcaXY()); + histos.fill(HIST("hrecDcaZAll"), track.dcaZ()); + + // rejecting electron + if (cfgIfRejectElectron && isElectron(track)) { + continue; + } + // use ITS pid as well + if (cfgUseItsPid && (std::abs(itsResponse.nSigmaITS(track)) > 3.0)) { + continue; + } + // required tracks with TOF mandatory to avoid pileup + if (cfgIfMandatoryTOF && !track.hasTOF()) { + continue; + } + + bool trackSelected = false; + if (cfgPIDchoice == 0) + trackSelected = selectionPIDoldTOFveto(track); + if (cfgPIDchoice == 1) + trackSelected = selectionPIDnew(track); + if (cfgPIDchoice == 2) + trackSelected = selectionPIDold(track); + + if (trackSelected) { + // filling nSigma distribution + histos.fill(HIST("h2DnsigmaTpcVsPt"), track.pt(), track.tpcNSigmaPr()); + histos.fill(HIST("h2DnsigmaTofVsPt"), track.pt(), track.tofNSigmaPr()); + histos.fill(HIST("h2DnsigmaItsVsPt"), track.pt(), itsResponse.nSigmaITS(track)); + + if (track.sign() > 0) { + histos.fill(HIST("hrecPartPtProton"), particle.pt()); //! hist for p rec + histos.fill(HIST("hrecPtProton"), track.pt()); //! hist for p rec + histos.fill(HIST("hrecPtDistProtonVsCentrality"), particle.pt(), cent); + histos.fill(HIST("hrec2DEtaVsPtProton"), particle.pt(), particle.eta()); + histos.fill(HIST("hrecEtaProton"), particle.eta()); + histos.fill(HIST("hrecPhiProton"), particle.phi()); + histos.fill(HIST("hrecDcaXYProton"), track.dcaXY()); + histos.fill(HIST("hrecDcaZProton"), track.dcaZ()); + if (particle.pt() < cfgCutPtUpper) { + nProt = nProt + 1.0; + float pEff = getEfficiency(track); // get efficiency of track + if (pEff != 0) { + for (int i = 1; i < 7; i++) { + powerEffProt[i] += std::pow(1.0 / pEff, i); + } + } + } + if (particle.pdgCode() == PDG_t::kProton) { + histos.fill(HIST("hrecTruePtProton"), particle.pt()); //! hist for p purity + } + } + if (track.sign() < 0) { + histos.fill(HIST("hrecPartPtAntiproton"), particle.pt()); //! hist for anti-p rec + histos.fill(HIST("hrecPtAntiproton"), track.pt()); //! hist for anti-p rec + histos.fill(HIST("hrecPtDistAntiprotonVsCentrality"), particle.pt(), cent); + histos.fill(HIST("hrec2DEtaVsPtAntiproton"), particle.pt(), particle.eta()); + histos.fill(HIST("hrecEtaAntiproton"), particle.eta()); + histos.fill(HIST("hrecPhiAntiproton"), particle.phi()); + histos.fill(HIST("hrecDcaXYAntiproton"), track.dcaXY()); + histos.fill(HIST("hrecDcaZAntiproton"), track.dcaZ()); + if (particle.pt() < cfgCutPtUpper) { + nAntiprot = nAntiprot + 1.0; + float pEff = getEfficiency(track); // get efficiency of track + if (pEff != 0) { + for (int i = 1; i < 7; i++) { + powerEffAntiprot[i] += std::pow(1.0 / pEff, i); + } + } + } + if (particle.pdgCode() == PDG_t::kProtonBar) { + histos.fill(HIST("hrecTruePtAntiproton"), particle.pt()); //! hist for anti-p purity + } + } + } //! checking PID + } //! checking if primary + } //! end track loop + + float netProt = nAntiprot; + + histos.fill(HIST("hrecProtonVsCentrality"), nProt, cent); + histos.fill(HIST("hrecAntiprotonVsCentrality"), nAntiprot, cent); + histos.fill(HIST("hrecProfileTotalProton"), cent, (nProt + nAntiprot)); + histos.fill(HIST("hrecProfileProton"), cent, nProt); + histos.fill(HIST("hrecProfileAntiproton"), cent, nAntiprot); + histos.fill(HIST("hCorrProfileTotalProton"), cent, (powerEffProt[1] + powerEffAntiprot[1])); + histos.fill(HIST("hCorrProfileProton"), cent, powerEffProt[1]); + histos.fill(HIST("hCorrProfileAntiproton"), cent, powerEffAntiprot[1]); + + // Calculating q_{r,s} as required + for (int i = 1; i < 7; i++) { + fTCP0[i] = 0.0 + powerEffAntiprot[i]; + fTCP1[i] = 0.0 - powerEffAntiprot[i]; + } + + //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + float fQ11_1 = fTCP1[1]; + float fQ11_2 = std::pow(fTCP1[1], 2); + float fQ11_3 = std::pow(fTCP1[1], 3); + float fQ11_4 = std::pow(fTCP1[1], 4); + float fQ11_5 = std::pow(fTCP1[1], 5); + float fQ11_6 = std::pow(fTCP1[1], 6); + + float fQ21_3 = std::pow(fTCP0[1], 3); + float fQ22_3 = std::pow(fTCP0[2], 3); + float fQ31_2 = std::pow(fTCP1[1], 2); + float fQ32_2 = std::pow(fTCP1[2], 2); + float fQ33_2 = std::pow(fTCP1[3], 2); + + float fQ61_1 = fTCP0[1]; + float fQ62_1 = fTCP0[2]; + float fQ63_1 = fTCP0[3]; + float fQ64_1 = fTCP0[4]; + float fQ65_1 = fTCP0[5]; + float fQ66_1 = fTCP0[6]; + + float fQ112122_111 = fTCP1[1] * fTCP0[1] * fTCP0[2]; + float fQ112131_111 = fTCP1[1] * fTCP0[1] * fTCP1[1]; + float fQ112132_111 = fTCP1[1] * fTCP0[1] * fTCP1[2]; + float fQ112133_111 = fTCP1[1] * fTCP0[1] * fTCP1[3]; + float fQ112231_111 = fTCP1[1] * fTCP0[2] * fTCP1[1]; + float fQ112232_111 = fTCP1[1] * fTCP0[2] * fTCP1[2]; + float fQ112233_111 = fTCP1[1] * fTCP0[2] * fTCP1[3]; + float fQ112221_111 = fTCP1[1] * fTCP0[2] * fTCP0[1]; + + float fQ21_1 = fTCP0[1]; + float fQ22_1 = fTCP0[2]; + float fQ31_1 = fTCP1[1]; + float fQ32_1 = fTCP1[2]; + float fQ33_1 = fTCP1[3]; + float fQ41_1 = fTCP0[1]; + float fQ42_1 = fTCP0[2]; + float fQ43_1 = fTCP0[3]; + float fQ44_1 = fTCP0[4]; + float fQ21_2 = std::pow(fTCP0[1], 2); + float fQ22_2 = std::pow(fTCP0[2], 2); + float fQ1121_11 = fTCP1[1] * fTCP0[1]; + float fQ1121_01 = fTCP0[1]; + float fQ1121_10 = fTCP1[1]; + float fQ1121_20 = std::pow(fTCP1[1], 2); + float fQ1121_21 = std::pow(fTCP1[1], 2) * fTCP0[1]; + float fQ1122_11 = fTCP1[1] * fTCP0[2]; + float fQ1122_01 = fTCP0[2]; + float fQ1122_10 = fTCP1[1]; + float fQ1122_20 = std::pow(fTCP1[1], 2); + float fQ1122_21 = std::pow(fTCP1[1], 2) * fTCP0[2]; + float fQ1131_11 = fTCP1[1] * fTCP1[1]; + float fQ1131_01 = fTCP1[1]; + float fQ1131_10 = fTCP1[1]; + float fQ1132_11 = fTCP1[1] * fTCP1[2]; + float fQ1132_01 = fTCP1[2]; + float fQ1132_10 = fTCP1[1]; + float fQ1133_11 = fTCP1[1] * fTCP1[3]; + float fQ1133_01 = fTCP1[3]; + float fQ1133_10 = fTCP1[1]; + float fQ2122_11 = fTCP0[1] * fTCP0[2]; + float fQ2122_01 = fTCP0[2]; + float fQ2122_10 = fTCP0[1]; + + ///////////////---------------------> + float fQ3132_11 = fTCP1[1] * fTCP1[2]; + float fQ3132_01 = fTCP1[2]; + float fQ3132_10 = fTCP1[1]; + float fQ3133_11 = fTCP1[1] * fTCP1[3]; + float fQ3133_01 = fTCP1[3]; + float fQ3133_10 = fTCP1[1]; + float fQ3233_11 = fTCP1[2] * fTCP1[3]; + float fQ3233_01 = fTCP1[3]; + float fQ3233_10 = fTCP1[2]; + float fQ2241_11 = fTCP0[2] * fTCP0[1]; + float fQ2241_01 = fTCP0[1]; + float fQ2241_10 = fTCP0[2]; + float fQ2242_11 = fTCP0[2] * fTCP0[2]; + float fQ2242_01 = fTCP0[2]; + float fQ2242_10 = fTCP0[2]; + float fQ2243_11 = fTCP0[2] * fTCP0[3]; + float fQ2243_01 = fTCP0[3]; + float fQ2243_10 = fTCP0[2]; + float fQ2244_11 = fTCP0[2] * fTCP0[4]; + float fQ2244_01 = fTCP0[4]; + float fQ2244_10 = fTCP0[2]; + float fQ2141_11 = fTCP0[1] * fTCP0[1]; + float fQ2141_01 = fTCP0[1]; + float fQ2141_10 = fTCP0[1]; + float fQ2142_11 = fTCP0[1] * fTCP0[2]; + float fQ2142_01 = fTCP0[2]; + float fQ2142_10 = fTCP0[1]; + float fQ2143_11 = fTCP0[1] * fTCP0[3]; + float fQ2143_01 = fTCP0[3]; + float fQ2143_10 = fTCP0[1]; + float fQ2144_11 = fTCP0[1] * fTCP0[4]; + float fQ2144_01 = fTCP0[4]; + float fQ2144_10 = fTCP0[1]; + float fQ1151_11 = fTCP1[1] * fTCP1[1]; + float fQ1151_01 = fTCP1[1]; + float fQ1151_10 = fTCP1[1]; + float fQ1152_11 = fTCP1[1] * fTCP1[2]; + float fQ1152_01 = fTCP1[2]; + float fQ1152_10 = fTCP1[1]; + float fQ1153_11 = fTCP1[1] * fTCP1[3]; + float fQ1153_01 = fTCP1[3]; + float fQ1153_10 = fTCP1[1]; + float fQ1154_11 = fTCP1[1] * fTCP1[4]; + float fQ1154_01 = fTCP1[4]; + float fQ1154_10 = fTCP1[1]; + float fQ1155_11 = fTCP1[1] * fTCP1[5]; + float fQ1155_01 = fTCP1[5]; + float fQ1155_10 = fTCP1[1]; + + float fQ112233_001 = fTCP1[3]; + float fQ112233_010 = fTCP0[2]; + float fQ112233_100 = fTCP1[1]; + float fQ112233_011 = fTCP0[2] * fTCP1[3]; + float fQ112233_101 = fTCP1[1] * fTCP1[3]; + float fQ112233_110 = fTCP1[1] * fTCP0[2]; + float fQ112232_001 = fTCP1[2]; + float fQ112232_010 = fTCP0[2]; + float fQ112232_100 = fTCP1[1]; + float fQ112232_011 = fTCP0[2] * fTCP1[2]; + float fQ112232_101 = fTCP1[1] * fTCP1[2]; + float fQ112232_110 = fTCP1[1] * fTCP0[2]; + // + float fQ112231_001 = fTCP1[1]; + float fQ112231_010 = fTCP0[2]; + float fQ112231_100 = fTCP1[1]; + float fQ112231_011 = fTCP0[2] * fTCP1[1]; + float fQ112231_101 = fTCP1[1] * fTCP1[1]; + float fQ112231_110 = fTCP1[1] * fTCP0[2]; + float fQ112133_001 = fTCP1[3]; + float fQ112133_010 = fTCP0[1]; + float fQ112133_100 = fTCP1[1]; + float fQ112133_011 = fTCP0[1] * fTCP1[3]; + float fQ112133_101 = fTCP1[1] * fTCP1[3]; + float fQ112133_110 = fTCP1[1] * fTCP0[1]; + + float fQ112132_001 = fTCP1[2]; + float fQ112132_010 = fTCP0[1]; + float fQ112132_100 = fTCP1[1]; + float fQ112132_011 = fTCP0[1] * fTCP1[2]; + float fQ112132_101 = fTCP1[1] * fTCP1[2]; + float fQ112132_110 = fTCP1[1] * fTCP0[1]; + float fQ112131_001 = fTCP1[1]; + float fQ112131_010 = fTCP0[1]; + float fQ112131_100 = fTCP1[1]; + float fQ112131_011 = fTCP0[1] * fTCP1[1]; + float fQ112131_101 = fTCP1[1] * fTCP1[1]; + float fQ112131_110 = fTCP1[1] * fTCP0[1]; + + float fQ2221_11 = fTCP0[2] * fTCP0[1]; + float fQ2221_01 = fTCP0[1]; + float fQ2221_10 = fTCP0[2]; + float fQ2221_21 = std::pow(fTCP0[2], 2) * fTCP0[1]; + float fQ2221_20 = std::pow(fTCP0[2], 2); + + float fQ2122_21 = std::pow(fTCP0[1], 2) * fTCP0[2]; + float fQ2122_20 = std::pow(fTCP0[1], 2); + float fQ1121_02 = std::pow(fTCP0[1], 2); + float fQ1121_12 = fTCP1[1] * std::pow(fTCP0[1], 2); + float fQ1121_22 = std::pow(fTCP1[1], 2) * std::pow(fTCP0[1], 2); + float fQ1122_02 = std::pow(fTCP0[2], 2); + float fQ1122_12 = fTCP1[1] * std::pow(fTCP0[2], 2); + float fQ1122_22 = std::pow(fTCP1[1], 2) * std::pow(fTCP0[2], 2); + + float fQ112221_001 = fTCP0[1]; + float fQ112221_010 = fTCP0[2]; + float fQ112221_100 = fTCP1[1]; + float fQ112221_011 = fTCP0[2] * fTCP0[1]; + float fQ112221_101 = fTCP1[1] * fTCP0[1]; + float fQ112221_110 = fTCP1[1] * fTCP0[2]; + float fQ112221_200 = std::pow(fTCP1[1], 2); + float fQ112221_201 = std::pow(fTCP1[1], 2) * fTCP0[1]; + float fQ112221_210 = std::pow(fTCP1[1], 2) * fTCP0[2]; + float fQ112221_211 = std::pow(fTCP1[1], 2) * fTCP0[2] * fTCP0[1]; + float fQ1131_21 = std::pow(fTCP1[1], 2) * fTCP1[1]; + float fQ1131_20 = std::pow(fTCP1[1], 2); + float fQ1131_31 = std::pow(fTCP1[1], 3) * fTCP1[1]; + float fQ1131_30 = std::pow(fTCP1[1], 3); + + float fQ1132_21 = std::pow(fTCP1[1], 2) * fTCP1[2]; + float fQ1132_20 = std::pow(fTCP1[1], 2); + float fQ1132_31 = std::pow(fTCP1[1], 3) * fTCP1[2]; + float fQ1132_30 = std::pow(fTCP1[1], 3); + float fQ1133_21 = std::pow(fTCP1[1], 2) * fTCP1[3]; + float fQ1133_20 = std::pow(fTCP1[1], 2); + float fQ1133_31 = std::pow(fTCP1[1], 3) * fTCP1[3]; + float fQ1133_30 = std::pow(fTCP1[1], 3); + float fQ1121_30 = std::pow(fTCP1[1], 3); + float fQ1121_31 = std::pow(fTCP1[1], 3) * fTCP0[1]; + float fQ1121_40 = std::pow(fTCP1[1], 4); + float fQ1121_41 = std::pow(fTCP1[1], 4) * fTCP0[1]; + float fQ1122_30 = std::pow(fTCP1[1], 3); + float fQ1122_31 = std::pow(fTCP1[1], 3) * fTCP0[2]; + float fQ1122_40 = std::pow(fTCP1[1], 4); + float fQ1122_41 = std::pow(fTCP1[1], 4) * fTCP0[2]; + + float fQ2211_11 = fTCP0[2] * fTCP1[1]; + float fQ2211_01 = fTCP1[1]; + float fQ2211_10 = fTCP0[2]; + float fQ2211_20 = std::pow(fTCP0[2], 2); + float fQ2211_21 = std::pow(fTCP0[2], 2) * fTCP1[1]; + float fQ2111_11 = fTCP0[1] * fTCP1[1]; + float fQ2111_01 = fTCP1[1]; + float fQ2111_10 = fTCP0[1]; + float fQ2111_20 = std::pow(fTCP0[1], 2); + float fQ2111_21 = std::pow(fTCP0[1], 2) * fTCP1[1]; + + float fQ112122_001 = fTCP0[2]; + float fQ112122_010 = fTCP0[1]; + float fQ112122_100 = fTCP1[1]; + float fQ112122_011 = fTCP0[1] * fTCP0[2]; + float fQ112122_101 = fTCP1[1] * fTCP0[2]; + float fQ112122_110 = fTCP1[1] * fTCP0[1]; + + float fQ1141_11 = fTCP1[1] * fTCP0[1]; + float fQ1141_01 = fTCP0[1]; + float fQ1141_10 = fTCP1[1]; + float fQ1141_20 = std::pow(fTCP1[1], 2); + float fQ1141_21 = std::pow(fTCP1[1], 2) * fTCP0[1]; + float fQ1142_11 = fTCP1[1] * fTCP0[2]; + float fQ1142_01 = fTCP0[2]; + float fQ1142_10 = fTCP1[1]; + float fQ1142_20 = std::pow(fTCP1[1], 2); + float fQ1142_21 = std::pow(fTCP1[1], 2) * fTCP0[2]; + + float fQ1143_11 = fTCP1[1] * fTCP0[3]; + float fQ1143_01 = fTCP0[3]; + float fQ1143_10 = fTCP1[1]; + float fQ1143_20 = std::pow(fTCP1[1], 2); + float fQ1143_21 = std::pow(fTCP1[1], 2) * fTCP0[3]; + float fQ1144_11 = fTCP1[1] * fTCP0[4]; + float fQ1144_01 = fTCP0[4]; + float fQ1144_10 = fTCP1[1]; + float fQ1144_20 = std::pow(fTCP1[1], 2); + float fQ1144_21 = std::pow(fTCP1[1], 2) * fTCP0[4]; + float fQ2131_11 = fTCP0[1] * fTCP1[1]; + float fQ2131_01 = fTCP1[1]; + float fQ2131_10 = fTCP0[1]; + + float fQ2132_11 = fTCP0[1] * fTCP1[2]; + float fQ2132_01 = fTCP1[2]; + float fQ2132_10 = fTCP0[1]; + float fQ2133_11 = fTCP0[1] * fTCP1[3]; + float fQ2133_01 = fTCP1[3]; + float fQ2133_10 = fTCP0[1]; + float fQ2231_11 = fTCP0[2] * fTCP1[1]; + float fQ2231_01 = fTCP1[1]; + float fQ2231_10 = fTCP0[2]; + float fQ2232_11 = fTCP0[2] * fTCP1[2]; + float fQ2232_01 = fTCP1[2]; + float fQ2232_10 = fTCP0[2]; + float fQ2233_11 = fTCP0[2] * fTCP1[3]; + float fQ2233_01 = fTCP1[3]; + float fQ2233_10 = fTCP0[2]; + + float fQ51_1 = fTCP1[1]; + float fQ52_1 = fTCP1[2]; + float fQ53_1 = fTCP1[3]; + float fQ54_1 = fTCP1[4]; + float fQ55_1 = fTCP1[5]; + + //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + if (cfgIsCalculateCentral) { + + // uncorrected + histos.get(HIST("Prof_mu1_antiproton"))->Fill(cent, std::pow(netProt, 1.0)); + histos.get(HIST("Prof_mu2_antiproton"))->Fill(cent, std::pow(netProt, 2.0)); + histos.get(HIST("Prof_mu3_antiproton"))->Fill(cent, std::pow(netProt, 3.0)); + histos.get(HIST("Prof_mu4_antiproton"))->Fill(cent, std::pow(netProt, 4.0)); + histos.get(HIST("Prof_mu5_antiproton"))->Fill(cent, std::pow(netProt, 5.0)); + histos.get(HIST("Prof_mu6_antiproton"))->Fill(cent, std::pow(netProt, 6.0)); + histos.get(HIST("Prof_mu7_antiproton"))->Fill(cent, std::pow(netProt, 7.0)); + histos.get(HIST("Prof_mu8_antiproton"))->Fill(cent, std::pow(netProt, 8.0)); + + // eff. corrected + histos.get(HIST("Prof_Q11_1"))->Fill(cent, fQ11_1); + histos.get(HIST("Prof_Q11_2"))->Fill(cent, fQ11_2); + histos.get(HIST("Prof_Q11_3"))->Fill(cent, fQ11_3); + histos.get(HIST("Prof_Q11_4"))->Fill(cent, fQ11_4); + histos.get(HIST("Prof_Q21_1"))->Fill(cent, fQ21_1); + histos.get(HIST("Prof_Q22_1"))->Fill(cent, fQ22_1); + histos.get(HIST("Prof_Q31_1"))->Fill(cent, fQ31_1); + histos.get(HIST("Prof_Q32_1"))->Fill(cent, fQ32_1); + histos.get(HIST("Prof_Q33_1"))->Fill(cent, fQ33_1); + histos.get(HIST("Prof_Q41_1"))->Fill(cent, fQ41_1); + histos.get(HIST("Prof_Q42_1"))->Fill(cent, fQ42_1); + histos.get(HIST("Prof_Q43_1"))->Fill(cent, fQ43_1); + histos.get(HIST("Prof_Q44_1"))->Fill(cent, fQ44_1); + histos.get(HIST("Prof_Q21_2"))->Fill(cent, fQ21_2); + histos.get(HIST("Prof_Q22_2"))->Fill(cent, fQ22_2); + histos.get(HIST("Prof_Q1121_11"))->Fill(cent, fQ1121_11); + histos.get(HIST("Prof_Q1121_01"))->Fill(cent, fQ1121_01); + histos.get(HIST("Prof_Q1121_10"))->Fill(cent, fQ1121_10); + histos.get(HIST("Prof_Q1121_20"))->Fill(cent, fQ1121_20); + histos.get(HIST("Prof_Q1121_21"))->Fill(cent, fQ1121_21); + histos.get(HIST("Prof_Q1122_11"))->Fill(cent, fQ1122_11); + histos.get(HIST("Prof_Q1122_01"))->Fill(cent, fQ1122_01); + histos.get(HIST("Prof_Q1122_10"))->Fill(cent, fQ1122_10); + histos.get(HIST("Prof_Q1122_20"))->Fill(cent, fQ1122_20); + histos.get(HIST("Prof_Q1122_21"))->Fill(cent, fQ1122_21); + histos.get(HIST("Prof_Q1131_11"))->Fill(cent, fQ1131_11); + histos.get(HIST("Prof_Q1131_01"))->Fill(cent, fQ1131_01); + histos.get(HIST("Prof_Q1131_10"))->Fill(cent, fQ1131_10); + histos.get(HIST("Prof_Q1132_11"))->Fill(cent, fQ1132_11); + histos.get(HIST("Prof_Q1132_01"))->Fill(cent, fQ1132_01); + histos.get(HIST("Prof_Q1132_10"))->Fill(cent, fQ1132_10); + histos.get(HIST("Prof_Q1133_11"))->Fill(cent, fQ1133_11); + histos.get(HIST("Prof_Q1133_01"))->Fill(cent, fQ1133_01); + histos.get(HIST("Prof_Q1133_10"))->Fill(cent, fQ1133_10); + histos.get(HIST("Prof_Q2122_11"))->Fill(cent, fQ2122_11); + histos.get(HIST("Prof_Q2122_01"))->Fill(cent, fQ2122_01); + histos.get(HIST("Prof_Q2122_10"))->Fill(cent, fQ2122_10); + histos.get(HIST("Prof_Q3132_11"))->Fill(cent, fQ3132_11); + histos.get(HIST("Prof_Q3132_01"))->Fill(cent, fQ3132_01); + histos.get(HIST("Prof_Q3132_10"))->Fill(cent, fQ3132_10); + histos.get(HIST("Prof_Q3133_11"))->Fill(cent, fQ3133_11); + histos.get(HIST("Prof_Q3133_01"))->Fill(cent, fQ3133_01); + histos.get(HIST("Prof_Q3133_10"))->Fill(cent, fQ3133_10); + histos.get(HIST("Prof_Q3233_11"))->Fill(cent, fQ3233_11); + histos.get(HIST("Prof_Q3233_01"))->Fill(cent, fQ3233_01); + histos.get(HIST("Prof_Q3233_10"))->Fill(cent, fQ3233_10); + histos.get(HIST("Prof_Q2241_11"))->Fill(cent, fQ2241_11); + histos.get(HIST("Prof_Q2241_01"))->Fill(cent, fQ2241_01); + histos.get(HIST("Prof_Q2241_10"))->Fill(cent, fQ2241_10); + histos.get(HIST("Prof_Q2242_11"))->Fill(cent, fQ2242_11); + histos.get(HIST("Prof_Q2242_01"))->Fill(cent, fQ2242_01); + histos.get(HIST("Prof_Q2242_10"))->Fill(cent, fQ2242_10); + histos.get(HIST("Prof_Q2243_11"))->Fill(cent, fQ2243_11); + histos.get(HIST("Prof_Q2243_01"))->Fill(cent, fQ2243_01); + histos.get(HIST("Prof_Q2243_10"))->Fill(cent, fQ2243_10); + histos.get(HIST("Prof_Q2244_11"))->Fill(cent, fQ2244_11); + histos.get(HIST("Prof_Q2244_01"))->Fill(cent, fQ2244_01); + histos.get(HIST("Prof_Q2244_10"))->Fill(cent, fQ2244_10); + histos.get(HIST("Prof_Q2141_11"))->Fill(cent, fQ2141_11); + histos.get(HIST("Prof_Q2141_01"))->Fill(cent, fQ2141_01); + histos.get(HIST("Prof_Q2141_10"))->Fill(cent, fQ2141_10); + histos.get(HIST("Prof_Q2142_11"))->Fill(cent, fQ2142_11); + histos.get(HIST("Prof_Q2142_01"))->Fill(cent, fQ2142_01); + histos.get(HIST("Prof_Q2142_10"))->Fill(cent, fQ2142_10); + histos.get(HIST("Prof_Q2143_11"))->Fill(cent, fQ2143_11); + histos.get(HIST("Prof_Q2143_01"))->Fill(cent, fQ2143_01); + histos.get(HIST("Prof_Q2143_10"))->Fill(cent, fQ2143_10); + histos.get(HIST("Prof_Q2144_11"))->Fill(cent, fQ2144_11); + histos.get(HIST("Prof_Q2144_01"))->Fill(cent, fQ2144_01); + histos.get(HIST("Prof_Q2144_10"))->Fill(cent, fQ2144_10); + histos.get(HIST("Prof_Q1151_11"))->Fill(cent, fQ1151_11); + histos.get(HIST("Prof_Q1151_01"))->Fill(cent, fQ1151_01); + histos.get(HIST("Prof_Q1151_10"))->Fill(cent, fQ1151_10); + histos.get(HIST("Prof_Q1152_11"))->Fill(cent, fQ1152_11); + histos.get(HIST("Prof_Q1152_01"))->Fill(cent, fQ1152_01); + histos.get(HIST("Prof_Q1152_10"))->Fill(cent, fQ1152_10); + histos.get(HIST("Prof_Q1153_11"))->Fill(cent, fQ1153_11); + histos.get(HIST("Prof_Q1153_01"))->Fill(cent, fQ1153_01); + histos.get(HIST("Prof_Q1153_10"))->Fill(cent, fQ1153_10); + histos.get(HIST("Prof_Q1154_11"))->Fill(cent, fQ1154_11); + histos.get(HIST("Prof_Q1154_01"))->Fill(cent, fQ1154_01); + histos.get(HIST("Prof_Q1154_10"))->Fill(cent, fQ1154_10); + histos.get(HIST("Prof_Q1155_11"))->Fill(cent, fQ1155_11); + histos.get(HIST("Prof_Q1155_01"))->Fill(cent, fQ1155_01); + histos.get(HIST("Prof_Q1155_10"))->Fill(cent, fQ1155_10); + histos.get(HIST("Prof_Q112233_001"))->Fill(cent, fQ112233_001); + histos.get(HIST("Prof_Q112233_010"))->Fill(cent, fQ112233_010); + histos.get(HIST("Prof_Q112233_100"))->Fill(cent, fQ112233_100); + histos.get(HIST("Prof_Q112233_011"))->Fill(cent, fQ112233_011); + histos.get(HIST("Prof_Q112233_101"))->Fill(cent, fQ112233_101); + histos.get(HIST("Prof_Q112233_110"))->Fill(cent, fQ112233_110); + histos.get(HIST("Prof_Q112232_001"))->Fill(cent, fQ112232_001); + histos.get(HIST("Prof_Q112232_010"))->Fill(cent, fQ112232_010); + histos.get(HIST("Prof_Q112232_100"))->Fill(cent, fQ112232_100); + histos.get(HIST("Prof_Q112232_011"))->Fill(cent, fQ112232_011); + histos.get(HIST("Prof_Q112232_101"))->Fill(cent, fQ112232_101); + histos.get(HIST("Prof_Q112232_110"))->Fill(cent, fQ112232_110); + histos.get(HIST("Prof_Q112231_001"))->Fill(cent, fQ112231_001); + histos.get(HIST("Prof_Q112231_010"))->Fill(cent, fQ112231_010); + histos.get(HIST("Prof_Q112231_100"))->Fill(cent, fQ112231_100); + histos.get(HIST("Prof_Q112231_011"))->Fill(cent, fQ112231_011); + histos.get(HIST("Prof_Q112231_101"))->Fill(cent, fQ112231_101); + histos.get(HIST("Prof_Q112231_110"))->Fill(cent, fQ112231_110); + histos.get(HIST("Prof_Q112133_001"))->Fill(cent, fQ112133_001); + histos.get(HIST("Prof_Q112133_010"))->Fill(cent, fQ112133_010); + histos.get(HIST("Prof_Q112133_100"))->Fill(cent, fQ112133_100); + histos.get(HIST("Prof_Q112133_011"))->Fill(cent, fQ112133_011); + histos.get(HIST("Prof_Q112133_101"))->Fill(cent, fQ112133_101); + histos.get(HIST("Prof_Q112133_110"))->Fill(cent, fQ112133_110); + histos.get(HIST("Prof_Q112132_001"))->Fill(cent, fQ112132_001); + histos.get(HIST("Prof_Q112132_010"))->Fill(cent, fQ112132_010); + histos.get(HIST("Prof_Q112132_100"))->Fill(cent, fQ112132_100); + histos.get(HIST("Prof_Q112132_011"))->Fill(cent, fQ112132_011); + histos.get(HIST("Prof_Q112132_101"))->Fill(cent, fQ112132_101); + histos.get(HIST("Prof_Q112132_110"))->Fill(cent, fQ112132_110); + histos.get(HIST("Prof_Q112131_001"))->Fill(cent, fQ112131_001); + histos.get(HIST("Prof_Q112131_010"))->Fill(cent, fQ112131_010); + histos.get(HIST("Prof_Q112131_100"))->Fill(cent, fQ112131_100); + histos.get(HIST("Prof_Q112131_011"))->Fill(cent, fQ112131_011); + histos.get(HIST("Prof_Q112131_101"))->Fill(cent, fQ112131_101); + histos.get(HIST("Prof_Q112131_110"))->Fill(cent, fQ112131_110); + histos.get(HIST("Prof_Q2221_11"))->Fill(cent, fQ2221_11); + histos.get(HIST("Prof_Q2221_01"))->Fill(cent, fQ2221_01); + histos.get(HIST("Prof_Q2221_10"))->Fill(cent, fQ2221_10); + histos.get(HIST("Prof_Q2221_21"))->Fill(cent, fQ2221_21); + histos.get(HIST("Prof_Q2221_20"))->Fill(cent, fQ2221_20); + histos.get(HIST("Prof_Q2122_21"))->Fill(cent, fQ2122_21); + histos.get(HIST("Prof_Q2122_20"))->Fill(cent, fQ2122_20); + histos.get(HIST("Prof_Q1121_02"))->Fill(cent, fQ1121_02); + histos.get(HIST("Prof_Q1121_12"))->Fill(cent, fQ1121_12); + histos.get(HIST("Prof_Q1121_22"))->Fill(cent, fQ1121_22); + histos.get(HIST("Prof_Q1122_02"))->Fill(cent, fQ1122_02); + histos.get(HIST("Prof_Q1122_12"))->Fill(cent, fQ1122_12); + histos.get(HIST("Prof_Q1122_22"))->Fill(cent, fQ1122_22); + histos.get(HIST("Prof_Q112221_001"))->Fill(cent, fQ112221_001); + histos.get(HIST("Prof_Q112221_010"))->Fill(cent, fQ112221_010); + histos.get(HIST("Prof_Q112221_100"))->Fill(cent, fQ112221_100); + histos.get(HIST("Prof_Q112221_011"))->Fill(cent, fQ112221_011); + histos.get(HIST("Prof_Q112221_101"))->Fill(cent, fQ112221_101); + histos.get(HIST("Prof_Q112221_110"))->Fill(cent, fQ112221_110); + histos.get(HIST("Prof_Q112221_200"))->Fill(cent, fQ112221_200); + histos.get(HIST("Prof_Q112221_201"))->Fill(cent, fQ112221_201); + histos.get(HIST("Prof_Q112221_210"))->Fill(cent, fQ112221_210); + histos.get(HIST("Prof_Q112221_211"))->Fill(cent, fQ112221_211); + histos.get(HIST("Prof_Q1131_21"))->Fill(cent, fQ1131_21); + histos.get(HIST("Prof_Q1131_20"))->Fill(cent, fQ1131_20); + histos.get(HIST("Prof_Q1131_31"))->Fill(cent, fQ1131_31); + histos.get(HIST("Prof_Q1131_30"))->Fill(cent, fQ1131_30); + histos.get(HIST("Prof_Q1132_21"))->Fill(cent, fQ1132_21); + histos.get(HIST("Prof_Q1132_20"))->Fill(cent, fQ1132_20); + histos.get(HIST("Prof_Q1132_31"))->Fill(cent, fQ1132_31); + histos.get(HIST("Prof_Q1132_30"))->Fill(cent, fQ1132_30); + histos.get(HIST("Prof_Q1133_21"))->Fill(cent, fQ1133_21); + histos.get(HIST("Prof_Q1133_20"))->Fill(cent, fQ1133_20); + histos.get(HIST("Prof_Q1133_31"))->Fill(cent, fQ1133_31); + histos.get(HIST("Prof_Q1133_30"))->Fill(cent, fQ1133_30); + histos.get(HIST("Prof_Q11_5"))->Fill(cent, fQ11_5); + histos.get(HIST("Prof_Q11_6"))->Fill(cent, fQ11_6); + histos.get(HIST("Prof_Q1121_30"))->Fill(cent, fQ1121_30); + histos.get(HIST("Prof_Q1121_31"))->Fill(cent, fQ1121_31); + histos.get(HIST("Prof_Q1121_40"))->Fill(cent, fQ1121_40); + histos.get(HIST("Prof_Q1121_41"))->Fill(cent, fQ1121_41); + histos.get(HIST("Prof_Q1122_30"))->Fill(cent, fQ1122_30); + histos.get(HIST("Prof_Q1122_31"))->Fill(cent, fQ1122_31); + histos.get(HIST("Prof_Q1122_40"))->Fill(cent, fQ1122_40); + histos.get(HIST("Prof_Q1122_41"))->Fill(cent, fQ1122_41); + histos.get(HIST("Prof_Q2211_11"))->Fill(cent, fQ2211_11); + histos.get(HIST("Prof_Q2211_01"))->Fill(cent, fQ2211_01); + histos.get(HIST("Prof_Q2211_10"))->Fill(cent, fQ2211_10); + histos.get(HIST("Prof_Q2211_20"))->Fill(cent, fQ2211_20); + histos.get(HIST("Prof_Q2211_21"))->Fill(cent, fQ2211_21); + histos.get(HIST("Prof_Q2111_11"))->Fill(cent, fQ2111_11); + histos.get(HIST("Prof_Q2111_01"))->Fill(cent, fQ2111_01); + histos.get(HIST("Prof_Q2111_10"))->Fill(cent, fQ2111_10); + histos.get(HIST("Prof_Q2111_20"))->Fill(cent, fQ2111_20); + histos.get(HIST("Prof_Q2111_21"))->Fill(cent, fQ2111_21); + histos.get(HIST("Prof_Q112122_001"))->Fill(cent, fQ112122_001); + histos.get(HIST("Prof_Q112122_010"))->Fill(cent, fQ112122_010); + histos.get(HIST("Prof_Q112122_100"))->Fill(cent, fQ112122_100); + histos.get(HIST("Prof_Q112122_011"))->Fill(cent, fQ112122_011); + histos.get(HIST("Prof_Q112122_101"))->Fill(cent, fQ112122_101); + histos.get(HIST("Prof_Q112122_110"))->Fill(cent, fQ112122_110); + histos.get(HIST("Prof_Q1141_11"))->Fill(cent, fQ1141_11); + histos.get(HIST("Prof_Q1141_01"))->Fill(cent, fQ1141_01); + histos.get(HIST("Prof_Q1141_10"))->Fill(cent, fQ1141_10); + histos.get(HIST("Prof_Q1141_20"))->Fill(cent, fQ1141_20); + histos.get(HIST("Prof_Q1141_21"))->Fill(cent, fQ1141_21); + histos.get(HIST("Prof_Q1142_11"))->Fill(cent, fQ1142_11); + histos.get(HIST("Prof_Q1142_01"))->Fill(cent, fQ1142_01); + histos.get(HIST("Prof_Q1142_10"))->Fill(cent, fQ1142_10); + histos.get(HIST("Prof_Q1142_20"))->Fill(cent, fQ1142_20); + histos.get(HIST("Prof_Q1142_21"))->Fill(cent, fQ1142_21); + histos.get(HIST("Prof_Q1143_11"))->Fill(cent, fQ1143_11); + histos.get(HIST("Prof_Q1143_01"))->Fill(cent, fQ1143_01); + histos.get(HIST("Prof_Q1143_10"))->Fill(cent, fQ1143_10); + histos.get(HIST("Prof_Q1143_20"))->Fill(cent, fQ1143_20); + histos.get(HIST("Prof_Q1143_21"))->Fill(cent, fQ1143_21); + histos.get(HIST("Prof_Q1144_11"))->Fill(cent, fQ1144_11); + histos.get(HIST("Prof_Q1144_01"))->Fill(cent, fQ1144_01); + histos.get(HIST("Prof_Q1144_10"))->Fill(cent, fQ1144_10); + histos.get(HIST("Prof_Q1144_20"))->Fill(cent, fQ1144_20); + histos.get(HIST("Prof_Q1144_21"))->Fill(cent, fQ1144_21); + histos.get(HIST("Prof_Q2131_11"))->Fill(cent, fQ2131_11); + histos.get(HIST("Prof_Q2131_01"))->Fill(cent, fQ2131_01); + histos.get(HIST("Prof_Q2131_10"))->Fill(cent, fQ2131_10); + histos.get(HIST("Prof_Q2132_11"))->Fill(cent, fQ2132_11); + histos.get(HIST("Prof_Q2132_01"))->Fill(cent, fQ2132_01); + histos.get(HIST("Prof_Q2132_10"))->Fill(cent, fQ2132_10); + histos.get(HIST("Prof_Q2133_11"))->Fill(cent, fQ2133_11); + histos.get(HIST("Prof_Q2133_01"))->Fill(cent, fQ2133_01); + histos.get(HIST("Prof_Q2133_10"))->Fill(cent, fQ2133_10); + histos.get(HIST("Prof_Q2231_11"))->Fill(cent, fQ2231_11); + histos.get(HIST("Prof_Q2231_01"))->Fill(cent, fQ2231_01); + histos.get(HIST("Prof_Q2231_10"))->Fill(cent, fQ2231_10); + histos.get(HIST("Prof_Q2232_11"))->Fill(cent, fQ2232_11); + histos.get(HIST("Prof_Q2232_01"))->Fill(cent, fQ2232_01); + histos.get(HIST("Prof_Q2232_10"))->Fill(cent, fQ2232_10); + histos.get(HIST("Prof_Q2233_11"))->Fill(cent, fQ2233_11); + histos.get(HIST("Prof_Q2233_01"))->Fill(cent, fQ2233_01); + histos.get(HIST("Prof_Q2233_10"))->Fill(cent, fQ2233_10); + histos.get(HIST("Prof_Q51_1"))->Fill(cent, fQ51_1); + histos.get(HIST("Prof_Q52_1"))->Fill(cent, fQ52_1); + histos.get(HIST("Prof_Q53_1"))->Fill(cent, fQ53_1); + histos.get(HIST("Prof_Q54_1"))->Fill(cent, fQ54_1); + histos.get(HIST("Prof_Q55_1"))->Fill(cent, fQ55_1); + histos.get(HIST("Prof_Q21_3"))->Fill(cent, fQ21_3); + histos.get(HIST("Prof_Q22_3"))->Fill(cent, fQ22_3); + histos.get(HIST("Prof_Q31_2"))->Fill(cent, fQ31_2); + histos.get(HIST("Prof_Q32_2"))->Fill(cent, fQ32_2); + histos.get(HIST("Prof_Q33_2"))->Fill(cent, fQ33_2); + histos.get(HIST("Prof_Q61_1"))->Fill(cent, fQ61_1); + histos.get(HIST("Prof_Q62_1"))->Fill(cent, fQ62_1); + histos.get(HIST("Prof_Q63_1"))->Fill(cent, fQ63_1); + histos.get(HIST("Prof_Q64_1"))->Fill(cent, fQ64_1); + histos.get(HIST("Prof_Q65_1"))->Fill(cent, fQ65_1); + histos.get(HIST("Prof_Q66_1"))->Fill(cent, fQ66_1); + histos.get(HIST("Prof_Q112122_111"))->Fill(cent, fQ112122_111); + histos.get(HIST("Prof_Q112131_111"))->Fill(cent, fQ112131_111); + histos.get(HIST("Prof_Q112132_111"))->Fill(cent, fQ112132_111); + histos.get(HIST("Prof_Q112133_111"))->Fill(cent, fQ112133_111); + histos.get(HIST("Prof_Q112231_111"))->Fill(cent, fQ112231_111); + histos.get(HIST("Prof_Q112232_111"))->Fill(cent, fQ112232_111); + histos.get(HIST("Prof_Q112233_111"))->Fill(cent, fQ112233_111); + histos.get(HIST("Prof_Q112221_111"))->Fill(cent, fQ112221_111); + } + + if (cfgIsCalculateError) { + // selecting subsample and filling profiles + float lRandom = fRndm->Rndm(); + int sampleIndex = static_cast(cfgNSubsample * lRandom); + + histos.get(HIST("Prof2D_mu1_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 1.0)); + histos.get(HIST("Prof2D_mu2_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 2.0)); + histos.get(HIST("Prof2D_mu3_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 3.0)); + histos.get(HIST("Prof2D_mu4_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 4.0)); + histos.get(HIST("Prof2D_mu5_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 5.0)); + histos.get(HIST("Prof2D_mu6_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 6.0)); + histos.get(HIST("Prof2D_mu7_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 7.0)); + histos.get(HIST("Prof2D_mu8_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 8.0)); + + histos.get(HIST("Prof2D_Q11_1"))->Fill(cent, sampleIndex, fQ11_1); + histos.get(HIST("Prof2D_Q11_2"))->Fill(cent, sampleIndex, fQ11_2); + histos.get(HIST("Prof2D_Q11_3"))->Fill(cent, sampleIndex, fQ11_3); + histos.get(HIST("Prof2D_Q11_4"))->Fill(cent, sampleIndex, fQ11_4); + histos.get(HIST("Prof2D_Q21_1"))->Fill(cent, sampleIndex, fQ21_1); + histos.get(HIST("Prof2D_Q22_1"))->Fill(cent, sampleIndex, fQ22_1); + histos.get(HIST("Prof2D_Q31_1"))->Fill(cent, sampleIndex, fQ31_1); + histos.get(HIST("Prof2D_Q32_1"))->Fill(cent, sampleIndex, fQ32_1); + histos.get(HIST("Prof2D_Q33_1"))->Fill(cent, sampleIndex, fQ33_1); + histos.get(HIST("Prof2D_Q41_1"))->Fill(cent, sampleIndex, fQ41_1); + histos.get(HIST("Prof2D_Q42_1"))->Fill(cent, sampleIndex, fQ42_1); + histos.get(HIST("Prof2D_Q43_1"))->Fill(cent, sampleIndex, fQ43_1); + histos.get(HIST("Prof2D_Q44_1"))->Fill(cent, sampleIndex, fQ44_1); + histos.get(HIST("Prof2D_Q21_2"))->Fill(cent, sampleIndex, fQ21_2); + histos.get(HIST("Prof2D_Q22_2"))->Fill(cent, sampleIndex, fQ22_2); + histos.get(HIST("Prof2D_Q1121_11"))->Fill(cent, sampleIndex, fQ1121_11); + histos.get(HIST("Prof2D_Q1121_01"))->Fill(cent, sampleIndex, fQ1121_01); + histos.get(HIST("Prof2D_Q1121_10"))->Fill(cent, sampleIndex, fQ1121_10); + histos.get(HIST("Prof2D_Q1121_20"))->Fill(cent, sampleIndex, fQ1121_20); + histos.get(HIST("Prof2D_Q1121_21"))->Fill(cent, sampleIndex, fQ1121_21); + histos.get(HIST("Prof2D_Q1122_11"))->Fill(cent, sampleIndex, fQ1122_11); + histos.get(HIST("Prof2D_Q1122_01"))->Fill(cent, sampleIndex, fQ1122_01); + histos.get(HIST("Prof2D_Q1122_10"))->Fill(cent, sampleIndex, fQ1122_10); + histos.get(HIST("Prof2D_Q1122_20"))->Fill(cent, sampleIndex, fQ1122_20); + histos.get(HIST("Prof2D_Q1122_21"))->Fill(cent, sampleIndex, fQ1122_21); + histos.get(HIST("Prof2D_Q1131_11"))->Fill(cent, sampleIndex, fQ1131_11); + histos.get(HIST("Prof2D_Q1131_01"))->Fill(cent, sampleIndex, fQ1131_01); + histos.get(HIST("Prof2D_Q1131_10"))->Fill(cent, sampleIndex, fQ1131_10); + histos.get(HIST("Prof2D_Q1132_11"))->Fill(cent, sampleIndex, fQ1132_11); + histos.get(HIST("Prof2D_Q1132_01"))->Fill(cent, sampleIndex, fQ1132_01); + histos.get(HIST("Prof2D_Q1132_10"))->Fill(cent, sampleIndex, fQ1132_10); + histos.get(HIST("Prof2D_Q1133_11"))->Fill(cent, sampleIndex, fQ1133_11); + histos.get(HIST("Prof2D_Q1133_01"))->Fill(cent, sampleIndex, fQ1133_01); + histos.get(HIST("Prof2D_Q1133_10"))->Fill(cent, sampleIndex, fQ1133_10); + histos.get(HIST("Prof2D_Q2122_11"))->Fill(cent, sampleIndex, fQ2122_11); + histos.get(HIST("Prof2D_Q2122_01"))->Fill(cent, sampleIndex, fQ2122_01); + histos.get(HIST("Prof2D_Q2122_10"))->Fill(cent, sampleIndex, fQ2122_10); + histos.get(HIST("Prof2D_Q3132_11"))->Fill(cent, sampleIndex, fQ3132_11); + histos.get(HIST("Prof2D_Q3132_01"))->Fill(cent, sampleIndex, fQ3132_01); + histos.get(HIST("Prof2D_Q3132_10"))->Fill(cent, sampleIndex, fQ3132_10); + histos.get(HIST("Prof2D_Q3133_11"))->Fill(cent, sampleIndex, fQ3133_11); + histos.get(HIST("Prof2D_Q3133_01"))->Fill(cent, sampleIndex, fQ3133_01); + histos.get(HIST("Prof2D_Q3133_10"))->Fill(cent, sampleIndex, fQ3133_10); + histos.get(HIST("Prof2D_Q3233_11"))->Fill(cent, sampleIndex, fQ3233_11); + histos.get(HIST("Prof2D_Q3233_01"))->Fill(cent, sampleIndex, fQ3233_01); + histos.get(HIST("Prof2D_Q3233_10"))->Fill(cent, sampleIndex, fQ3233_10); + histos.get(HIST("Prof2D_Q2241_11"))->Fill(cent, sampleIndex, fQ2241_11); + histos.get(HIST("Prof2D_Q2241_01"))->Fill(cent, sampleIndex, fQ2241_01); + histos.get(HIST("Prof2D_Q2241_10"))->Fill(cent, sampleIndex, fQ2241_10); + histos.get(HIST("Prof2D_Q2242_11"))->Fill(cent, sampleIndex, fQ2242_11); + histos.get(HIST("Prof2D_Q2242_01"))->Fill(cent, sampleIndex, fQ2242_01); + histos.get(HIST("Prof2D_Q2242_10"))->Fill(cent, sampleIndex, fQ2242_10); + histos.get(HIST("Prof2D_Q2243_11"))->Fill(cent, sampleIndex, fQ2243_11); + histos.get(HIST("Prof2D_Q2243_01"))->Fill(cent, sampleIndex, fQ2243_01); + histos.get(HIST("Prof2D_Q2243_10"))->Fill(cent, sampleIndex, fQ2243_10); + histos.get(HIST("Prof2D_Q2244_11"))->Fill(cent, sampleIndex, fQ2244_11); + histos.get(HIST("Prof2D_Q2244_01"))->Fill(cent, sampleIndex, fQ2244_01); + histos.get(HIST("Prof2D_Q2244_10"))->Fill(cent, sampleIndex, fQ2244_10); + histos.get(HIST("Prof2D_Q2141_11"))->Fill(cent, sampleIndex, fQ2141_11); + histos.get(HIST("Prof2D_Q2141_01"))->Fill(cent, sampleIndex, fQ2141_01); + histos.get(HIST("Prof2D_Q2141_10"))->Fill(cent, sampleIndex, fQ2141_10); + histos.get(HIST("Prof2D_Q2142_11"))->Fill(cent, sampleIndex, fQ2142_11); + histos.get(HIST("Prof2D_Q2142_01"))->Fill(cent, sampleIndex, fQ2142_01); + histos.get(HIST("Prof2D_Q2142_10"))->Fill(cent, sampleIndex, fQ2142_10); + histos.get(HIST("Prof2D_Q2143_11"))->Fill(cent, sampleIndex, fQ2143_11); + histos.get(HIST("Prof2D_Q2143_01"))->Fill(cent, sampleIndex, fQ2143_01); + histos.get(HIST("Prof2D_Q2143_10"))->Fill(cent, sampleIndex, fQ2143_10); + histos.get(HIST("Prof2D_Q2144_11"))->Fill(cent, sampleIndex, fQ2144_11); + histos.get(HIST("Prof2D_Q2144_01"))->Fill(cent, sampleIndex, fQ2144_01); + histos.get(HIST("Prof2D_Q2144_10"))->Fill(cent, sampleIndex, fQ2144_10); + histos.get(HIST("Prof2D_Q1151_11"))->Fill(cent, sampleIndex, fQ1151_11); + histos.get(HIST("Prof2D_Q1151_01"))->Fill(cent, sampleIndex, fQ1151_01); + histos.get(HIST("Prof2D_Q1151_10"))->Fill(cent, sampleIndex, fQ1151_10); + histos.get(HIST("Prof2D_Q1152_11"))->Fill(cent, sampleIndex, fQ1152_11); + histos.get(HIST("Prof2D_Q1152_01"))->Fill(cent, sampleIndex, fQ1152_01); + histos.get(HIST("Prof2D_Q1152_10"))->Fill(cent, sampleIndex, fQ1152_10); + histos.get(HIST("Prof2D_Q1153_11"))->Fill(cent, sampleIndex, fQ1153_11); + histos.get(HIST("Prof2D_Q1153_01"))->Fill(cent, sampleIndex, fQ1153_01); + histos.get(HIST("Prof2D_Q1153_10"))->Fill(cent, sampleIndex, fQ1153_10); + histos.get(HIST("Prof2D_Q1154_11"))->Fill(cent, sampleIndex, fQ1154_11); + histos.get(HIST("Prof2D_Q1154_01"))->Fill(cent, sampleIndex, fQ1154_01); + histos.get(HIST("Prof2D_Q1154_10"))->Fill(cent, sampleIndex, fQ1154_10); + histos.get(HIST("Prof2D_Q1155_11"))->Fill(cent, sampleIndex, fQ1155_11); + histos.get(HIST("Prof2D_Q1155_01"))->Fill(cent, sampleIndex, fQ1155_01); + histos.get(HIST("Prof2D_Q1155_10"))->Fill(cent, sampleIndex, fQ1155_10); + histos.get(HIST("Prof2D_Q112233_001"))->Fill(cent, sampleIndex, fQ112233_001); + histos.get(HIST("Prof2D_Q112233_010"))->Fill(cent, sampleIndex, fQ112233_010); + histos.get(HIST("Prof2D_Q112233_100"))->Fill(cent, sampleIndex, fQ112233_100); + histos.get(HIST("Prof2D_Q112233_011"))->Fill(cent, sampleIndex, fQ112233_011); + histos.get(HIST("Prof2D_Q112233_101"))->Fill(cent, sampleIndex, fQ112233_101); + histos.get(HIST("Prof2D_Q112233_110"))->Fill(cent, sampleIndex, fQ112233_110); + histos.get(HIST("Prof2D_Q112232_001"))->Fill(cent, sampleIndex, fQ112232_001); + histos.get(HIST("Prof2D_Q112232_010"))->Fill(cent, sampleIndex, fQ112232_010); + histos.get(HIST("Prof2D_Q112232_100"))->Fill(cent, sampleIndex, fQ112232_100); + histos.get(HIST("Prof2D_Q112232_011"))->Fill(cent, sampleIndex, fQ112232_011); + histos.get(HIST("Prof2D_Q112232_101"))->Fill(cent, sampleIndex, fQ112232_101); + histos.get(HIST("Prof2D_Q112232_110"))->Fill(cent, sampleIndex, fQ112232_110); + histos.get(HIST("Prof2D_Q112231_001"))->Fill(cent, sampleIndex, fQ112231_001); + histos.get(HIST("Prof2D_Q112231_010"))->Fill(cent, sampleIndex, fQ112231_010); + histos.get(HIST("Prof2D_Q112231_100"))->Fill(cent, sampleIndex, fQ112231_100); + histos.get(HIST("Prof2D_Q112231_011"))->Fill(cent, sampleIndex, fQ112231_011); + histos.get(HIST("Prof2D_Q112231_101"))->Fill(cent, sampleIndex, fQ112231_101); + histos.get(HIST("Prof2D_Q112231_110"))->Fill(cent, sampleIndex, fQ112231_110); + histos.get(HIST("Prof2D_Q112133_001"))->Fill(cent, sampleIndex, fQ112133_001); + histos.get(HIST("Prof2D_Q112133_010"))->Fill(cent, sampleIndex, fQ112133_010); + histos.get(HIST("Prof2D_Q112133_100"))->Fill(cent, sampleIndex, fQ112133_100); + histos.get(HIST("Prof2D_Q112133_011"))->Fill(cent, sampleIndex, fQ112133_011); + histos.get(HIST("Prof2D_Q112133_101"))->Fill(cent, sampleIndex, fQ112133_101); + histos.get(HIST("Prof2D_Q112133_110"))->Fill(cent, sampleIndex, fQ112133_110); + histos.get(HIST("Prof2D_Q112132_001"))->Fill(cent, sampleIndex, fQ112132_001); + histos.get(HIST("Prof2D_Q112132_010"))->Fill(cent, sampleIndex, fQ112132_010); + histos.get(HIST("Prof2D_Q112132_100"))->Fill(cent, sampleIndex, fQ112132_100); + histos.get(HIST("Prof2D_Q112132_011"))->Fill(cent, sampleIndex, fQ112132_011); + histos.get(HIST("Prof2D_Q112132_101"))->Fill(cent, sampleIndex, fQ112132_101); + histos.get(HIST("Prof2D_Q112132_110"))->Fill(cent, sampleIndex, fQ112132_110); + histos.get(HIST("Prof2D_Q112131_001"))->Fill(cent, sampleIndex, fQ112131_001); + histos.get(HIST("Prof2D_Q112131_010"))->Fill(cent, sampleIndex, fQ112131_010); + histos.get(HIST("Prof2D_Q112131_100"))->Fill(cent, sampleIndex, fQ112131_100); + histos.get(HIST("Prof2D_Q112131_011"))->Fill(cent, sampleIndex, fQ112131_011); + histos.get(HIST("Prof2D_Q112131_101"))->Fill(cent, sampleIndex, fQ112131_101); + histos.get(HIST("Prof2D_Q112131_110"))->Fill(cent, sampleIndex, fQ112131_110); + histos.get(HIST("Prof2D_Q2221_11"))->Fill(cent, sampleIndex, fQ2221_11); + histos.get(HIST("Prof2D_Q2221_01"))->Fill(cent, sampleIndex, fQ2221_01); + histos.get(HIST("Prof2D_Q2221_10"))->Fill(cent, sampleIndex, fQ2221_10); + histos.get(HIST("Prof2D_Q2221_21"))->Fill(cent, sampleIndex, fQ2221_21); + histos.get(HIST("Prof2D_Q2221_20"))->Fill(cent, sampleIndex, fQ2221_20); + histos.get(HIST("Prof2D_Q2122_21"))->Fill(cent, sampleIndex, fQ2122_21); + histos.get(HIST("Prof2D_Q2122_20"))->Fill(cent, sampleIndex, fQ2122_20); + histos.get(HIST("Prof2D_Q1121_02"))->Fill(cent, sampleIndex, fQ1121_02); + histos.get(HIST("Prof2D_Q1121_12"))->Fill(cent, sampleIndex, fQ1121_12); + histos.get(HIST("Prof2D_Q1121_22"))->Fill(cent, sampleIndex, fQ1121_22); + histos.get(HIST("Prof2D_Q1122_02"))->Fill(cent, sampleIndex, fQ1122_02); + histos.get(HIST("Prof2D_Q1122_12"))->Fill(cent, sampleIndex, fQ1122_12); + histos.get(HIST("Prof2D_Q1122_22"))->Fill(cent, sampleIndex, fQ1122_22); + histos.get(HIST("Prof2D_Q112221_001"))->Fill(cent, sampleIndex, fQ112221_001); + histos.get(HIST("Prof2D_Q112221_010"))->Fill(cent, sampleIndex, fQ112221_010); + histos.get(HIST("Prof2D_Q112221_100"))->Fill(cent, sampleIndex, fQ112221_100); + histos.get(HIST("Prof2D_Q112221_011"))->Fill(cent, sampleIndex, fQ112221_011); + histos.get(HIST("Prof2D_Q112221_101"))->Fill(cent, sampleIndex, fQ112221_101); + histos.get(HIST("Prof2D_Q112221_110"))->Fill(cent, sampleIndex, fQ112221_110); + histos.get(HIST("Prof2D_Q112221_200"))->Fill(cent, sampleIndex, fQ112221_200); + histos.get(HIST("Prof2D_Q112221_201"))->Fill(cent, sampleIndex, fQ112221_201); + histos.get(HIST("Prof2D_Q112221_210"))->Fill(cent, sampleIndex, fQ112221_210); + histos.get(HIST("Prof2D_Q112221_211"))->Fill(cent, sampleIndex, fQ112221_211); + histos.get(HIST("Prof2D_Q1131_21"))->Fill(cent, sampleIndex, fQ1131_21); + histos.get(HIST("Prof2D_Q1131_20"))->Fill(cent, sampleIndex, fQ1131_20); + histos.get(HIST("Prof2D_Q1131_31"))->Fill(cent, sampleIndex, fQ1131_31); + histos.get(HIST("Prof2D_Q1131_30"))->Fill(cent, sampleIndex, fQ1131_30); + histos.get(HIST("Prof2D_Q1132_21"))->Fill(cent, sampleIndex, fQ1132_21); + histos.get(HIST("Prof2D_Q1132_20"))->Fill(cent, sampleIndex, fQ1132_20); + histos.get(HIST("Prof2D_Q1132_31"))->Fill(cent, sampleIndex, fQ1132_31); + histos.get(HIST("Prof2D_Q1132_30"))->Fill(cent, sampleIndex, fQ1132_30); + histos.get(HIST("Prof2D_Q1133_21"))->Fill(cent, sampleIndex, fQ1133_21); + histos.get(HIST("Prof2D_Q1133_20"))->Fill(cent, sampleIndex, fQ1133_20); + histos.get(HIST("Prof2D_Q1133_31"))->Fill(cent, sampleIndex, fQ1133_31); + histos.get(HIST("Prof2D_Q1133_30"))->Fill(cent, sampleIndex, fQ1133_30); + histos.get(HIST("Prof2D_Q11_5"))->Fill(cent, sampleIndex, fQ11_5); + histos.get(HIST("Prof2D_Q11_6"))->Fill(cent, sampleIndex, fQ11_6); + histos.get(HIST("Prof2D_Q1121_30"))->Fill(cent, sampleIndex, fQ1121_30); + histos.get(HIST("Prof2D_Q1121_31"))->Fill(cent, sampleIndex, fQ1121_31); + histos.get(HIST("Prof2D_Q1121_40"))->Fill(cent, sampleIndex, fQ1121_40); + histos.get(HIST("Prof2D_Q1121_41"))->Fill(cent, sampleIndex, fQ1121_41); + histos.get(HIST("Prof2D_Q1122_30"))->Fill(cent, sampleIndex, fQ1122_30); + histos.get(HIST("Prof2D_Q1122_31"))->Fill(cent, sampleIndex, fQ1122_31); + histos.get(HIST("Prof2D_Q1122_40"))->Fill(cent, sampleIndex, fQ1122_40); + histos.get(HIST("Prof2D_Q1122_41"))->Fill(cent, sampleIndex, fQ1122_41); + histos.get(HIST("Prof2D_Q2211_11"))->Fill(cent, sampleIndex, fQ2211_11); + histos.get(HIST("Prof2D_Q2211_01"))->Fill(cent, sampleIndex, fQ2211_01); + histos.get(HIST("Prof2D_Q2211_10"))->Fill(cent, sampleIndex, fQ2211_10); + histos.get(HIST("Prof2D_Q2211_20"))->Fill(cent, sampleIndex, fQ2211_20); + histos.get(HIST("Prof2D_Q2211_21"))->Fill(cent, sampleIndex, fQ2211_21); + histos.get(HIST("Prof2D_Q2111_11"))->Fill(cent, sampleIndex, fQ2111_11); + histos.get(HIST("Prof2D_Q2111_01"))->Fill(cent, sampleIndex, fQ2111_01); + histos.get(HIST("Prof2D_Q2111_10"))->Fill(cent, sampleIndex, fQ2111_10); + histos.get(HIST("Prof2D_Q2111_20"))->Fill(cent, sampleIndex, fQ2111_20); + histos.get(HIST("Prof2D_Q2111_21"))->Fill(cent, sampleIndex, fQ2111_21); + histos.get(HIST("Prof2D_Q112122_001"))->Fill(cent, sampleIndex, fQ112122_001); + histos.get(HIST("Prof2D_Q112122_010"))->Fill(cent, sampleIndex, fQ112122_010); + histos.get(HIST("Prof2D_Q112122_100"))->Fill(cent, sampleIndex, fQ112122_100); + histos.get(HIST("Prof2D_Q112122_011"))->Fill(cent, sampleIndex, fQ112122_011); + histos.get(HIST("Prof2D_Q112122_101"))->Fill(cent, sampleIndex, fQ112122_101); + histos.get(HIST("Prof2D_Q112122_110"))->Fill(cent, sampleIndex, fQ112122_110); + histos.get(HIST("Prof2D_Q1141_11"))->Fill(cent, sampleIndex, fQ1141_11); + histos.get(HIST("Prof2D_Q1141_01"))->Fill(cent, sampleIndex, fQ1141_01); + histos.get(HIST("Prof2D_Q1141_10"))->Fill(cent, sampleIndex, fQ1141_10); + histos.get(HIST("Prof2D_Q1141_20"))->Fill(cent, sampleIndex, fQ1141_20); + histos.get(HIST("Prof2D_Q1141_21"))->Fill(cent, sampleIndex, fQ1141_21); + histos.get(HIST("Prof2D_Q1142_11"))->Fill(cent, sampleIndex, fQ1142_11); + histos.get(HIST("Prof2D_Q1142_01"))->Fill(cent, sampleIndex, fQ1142_01); + histos.get(HIST("Prof2D_Q1142_10"))->Fill(cent, sampleIndex, fQ1142_10); + histos.get(HIST("Prof2D_Q1142_20"))->Fill(cent, sampleIndex, fQ1142_20); + histos.get(HIST("Prof2D_Q1142_21"))->Fill(cent, sampleIndex, fQ1142_21); + histos.get(HIST("Prof2D_Q1143_11"))->Fill(cent, sampleIndex, fQ1143_11); + histos.get(HIST("Prof2D_Q1143_01"))->Fill(cent, sampleIndex, fQ1143_01); + histos.get(HIST("Prof2D_Q1143_10"))->Fill(cent, sampleIndex, fQ1143_10); + histos.get(HIST("Prof2D_Q1143_20"))->Fill(cent, sampleIndex, fQ1143_20); + histos.get(HIST("Prof2D_Q1143_21"))->Fill(cent, sampleIndex, fQ1143_21); + histos.get(HIST("Prof2D_Q1144_11"))->Fill(cent, sampleIndex, fQ1144_11); + histos.get(HIST("Prof2D_Q1144_01"))->Fill(cent, sampleIndex, fQ1144_01); + histos.get(HIST("Prof2D_Q1144_10"))->Fill(cent, sampleIndex, fQ1144_10); + histos.get(HIST("Prof2D_Q1144_20"))->Fill(cent, sampleIndex, fQ1144_20); + histos.get(HIST("Prof2D_Q1144_21"))->Fill(cent, sampleIndex, fQ1144_21); + histos.get(HIST("Prof2D_Q2131_11"))->Fill(cent, sampleIndex, fQ2131_11); + histos.get(HIST("Prof2D_Q2131_01"))->Fill(cent, sampleIndex, fQ2131_01); + histos.get(HIST("Prof2D_Q2131_10"))->Fill(cent, sampleIndex, fQ2131_10); + histos.get(HIST("Prof2D_Q2132_11"))->Fill(cent, sampleIndex, fQ2132_11); + histos.get(HIST("Prof2D_Q2132_01"))->Fill(cent, sampleIndex, fQ2132_01); + histos.get(HIST("Prof2D_Q2132_10"))->Fill(cent, sampleIndex, fQ2132_10); + histos.get(HIST("Prof2D_Q2133_11"))->Fill(cent, sampleIndex, fQ2133_11); + histos.get(HIST("Prof2D_Q2133_01"))->Fill(cent, sampleIndex, fQ2133_01); + histos.get(HIST("Prof2D_Q2133_10"))->Fill(cent, sampleIndex, fQ2133_10); + histos.get(HIST("Prof2D_Q2231_11"))->Fill(cent, sampleIndex, fQ2231_11); + histos.get(HIST("Prof2D_Q2231_01"))->Fill(cent, sampleIndex, fQ2231_01); + histos.get(HIST("Prof2D_Q2231_10"))->Fill(cent, sampleIndex, fQ2231_10); + histos.get(HIST("Prof2D_Q2232_11"))->Fill(cent, sampleIndex, fQ2232_11); + histos.get(HIST("Prof2D_Q2232_01"))->Fill(cent, sampleIndex, fQ2232_01); + histos.get(HIST("Prof2D_Q2232_10"))->Fill(cent, sampleIndex, fQ2232_10); + histos.get(HIST("Prof2D_Q2233_11"))->Fill(cent, sampleIndex, fQ2233_11); + histos.get(HIST("Prof2D_Q2233_01"))->Fill(cent, sampleIndex, fQ2233_01); + histos.get(HIST("Prof2D_Q2233_10"))->Fill(cent, sampleIndex, fQ2233_10); + histos.get(HIST("Prof2D_Q51_1"))->Fill(cent, sampleIndex, fQ51_1); + histos.get(HIST("Prof2D_Q52_1"))->Fill(cent, sampleIndex, fQ52_1); + histos.get(HIST("Prof2D_Q53_1"))->Fill(cent, sampleIndex, fQ53_1); + histos.get(HIST("Prof2D_Q54_1"))->Fill(cent, sampleIndex, fQ54_1); + histos.get(HIST("Prof2D_Q55_1"))->Fill(cent, sampleIndex, fQ55_1); + histos.get(HIST("Prof2D_Q21_3"))->Fill(cent, sampleIndex, fQ21_3); + histos.get(HIST("Prof2D_Q22_3"))->Fill(cent, sampleIndex, fQ22_3); + histos.get(HIST("Prof2D_Q31_2"))->Fill(cent, sampleIndex, fQ31_2); + histos.get(HIST("Prof2D_Q32_2"))->Fill(cent, sampleIndex, fQ32_2); + histos.get(HIST("Prof2D_Q33_2"))->Fill(cent, sampleIndex, fQ33_2); + histos.get(HIST("Prof2D_Q61_1"))->Fill(cent, sampleIndex, fQ61_1); + histos.get(HIST("Prof2D_Q62_1"))->Fill(cent, sampleIndex, fQ62_1); + histos.get(HIST("Prof2D_Q63_1"))->Fill(cent, sampleIndex, fQ63_1); + histos.get(HIST("Prof2D_Q64_1"))->Fill(cent, sampleIndex, fQ64_1); + histos.get(HIST("Prof2D_Q65_1"))->Fill(cent, sampleIndex, fQ65_1); + histos.get(HIST("Prof2D_Q66_1"))->Fill(cent, sampleIndex, fQ66_1); + histos.get(HIST("Prof2D_Q112122_111"))->Fill(cent, sampleIndex, fQ112122_111); + histos.get(HIST("Prof2D_Q112131_111"))->Fill(cent, sampleIndex, fQ112131_111); + histos.get(HIST("Prof2D_Q112132_111"))->Fill(cent, sampleIndex, fQ112132_111); + histos.get(HIST("Prof2D_Q112133_111"))->Fill(cent, sampleIndex, fQ112133_111); + histos.get(HIST("Prof2D_Q112231_111"))->Fill(cent, sampleIndex, fQ112231_111); + histos.get(HIST("Prof2D_Q112232_111"))->Fill(cent, sampleIndex, fQ112232_111); + histos.get(HIST("Prof2D_Q112233_111"))->Fill(cent, sampleIndex, fQ112233_111); + histos.get(HIST("Prof2D_Q112221_111"))->Fill(cent, sampleIndex, fQ112221_111); + } + } + PROCESS_SWITCH(AntiprotonCumulantsMc, processMCRec, "Process Generated", true); + + void processDataRec(AodCollisions::iterator const& coll, aod::BCsWithTimestamps const&, AodTracks const& inputTracks) + { + if (!coll.sel8()) { + return; + } + if (cfgUseGoodITSLayerAllCut && !(coll.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll))) { + return; + } + if (cfgEvSelkNoSameBunchPileup && !(coll.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { + // rejects collisions which are associated with the same "found-by-T0" bunch crossing + // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof + return; + } + + if (cfgEvSelkIsVertexTOFmatched && !(coll.selection_bit(o2::aod::evsel::kIsVertexTOFmatched))) { + return; + ; + } + + histos.fill(HIST("hZvtx_after_sel"), coll.posZ()); + // variables + auto cent = coll.centFT0M(); + histos.fill(HIST("hCentrec"), cent); + + float nProt = 0.0; + float nAntiprot = 0.0; + std::array powerEffProt = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + std::array powerEffAntiprot = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + std::array fTCP0 = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + std::array fTCP1 = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + + o2::aod::ITSResponse itsResponse; + + // Start of the Monte-Carlo reconstructed tracks + for (const auto& track : inputTracks) { + if (!track.has_collision()) { + continue; + } + + if (!track.isPVContributor()) //! track check as used in data + { + continue; + } + if ((track.pt() < cfgCutPtLower) || (track.pt() > 5.0f) || (std::abs(track.eta()) > cfgCutEta)) { + continue; + } + if (!(track.itsNCls() > cfgITScluster) || !(track.tpcNClsFound() >= cfgTPCcluster) || !(track.tpcNClsCrossedRows() >= cfgTPCnCrossedRows)) { + continue; + } + + histos.fill(HIST("hrecPtAll"), track.pt()); + histos.fill(HIST("hrecEtaAll"), track.eta()); + histos.fill(HIST("hrecPhiAll"), track.phi()); + histos.fill(HIST("hrecDcaXYAll"), track.dcaXY()); + histos.fill(HIST("hrecDcaZAll"), track.dcaZ()); + + // rejecting electron + if (cfgIfRejectElectron && isElectron(track)) { + continue; + } + // use ITS pid as well + if (cfgUseItsPid && (std::abs(itsResponse.nSigmaITS(track)) > 3.0)) { + continue; + } + // required tracks with TOF mandatory to avoid pileup + if (cfgIfMandatoryTOF && !track.hasTOF()) { + continue; + } + + bool trackSelected = false; + if (cfgPIDchoice == 0) + trackSelected = selectionPIDoldTOFveto(track); + if (cfgPIDchoice == 1) + trackSelected = selectionPIDnew(track); + if (cfgPIDchoice == 2) + trackSelected = selectionPIDold(track); + + if (trackSelected) { + // filling nSigma distribution + histos.fill(HIST("h2DnsigmaTpcVsPt"), track.pt(), track.tpcNSigmaPr()); + histos.fill(HIST("h2DnsigmaTofVsPt"), track.pt(), track.tofNSigmaPr()); + histos.fill(HIST("h2DnsigmaItsVsPt"), track.pt(), itsResponse.nSigmaITS(track)); + + // for protons + if (track.sign() > 0) { + histos.fill(HIST("hrecPtProton"), track.pt()); //! hist for p rec + histos.fill(HIST("hrecPtDistProtonVsCentrality"), track.pt(), cent); + histos.fill(HIST("hrecEtaProton"), track.eta()); + histos.fill(HIST("hrecPhiProton"), track.phi()); + histos.fill(HIST("hrecDcaXYProton"), track.dcaXY()); + histos.fill(HIST("hrecDcaZProton"), track.dcaZ()); + + if (track.pt() < cfgCutPtUpper) { + nProt = nProt + 1.0; + float pEff = getEfficiency(track); // get efficiency of track + if (pEff != 0) { + for (int i = 1; i < 7; i++) { + powerEffProt[i] += std::pow(1.0 / pEff, i); + } + } + } + } + // for anti-protons + if (track.sign() < 0) { + histos.fill(HIST("hrecPtAntiproton"), track.pt()); //! hist for anti-p rec + histos.fill(HIST("hrecPtDistAntiprotonVsCentrality"), track.pt(), cent); + histos.fill(HIST("hrecEtaAntiproton"), track.eta()); + histos.fill(HIST("hrecPhiAntiproton"), track.phi()); + histos.fill(HIST("hrecDcaXYAntiproton"), track.dcaXY()); + histos.fill(HIST("hrecDcaZAntiproton"), track.dcaZ()); + if (track.pt() < cfgCutPtUpper) { + nAntiprot = nAntiprot + 1.0; + float pEff = getEfficiency(track); // get efficiency of track + if (pEff != 0) { + for (int i = 1; i < 7; i++) { + powerEffAntiprot[i] += std::pow(1.0 / pEff, i); + } + } + } + } + + } //! checking PID + } //! end track loop + + float netProt = nAntiprot; + + histos.fill(HIST("hrecProtonVsCentrality"), nProt, cent); + histos.fill(HIST("hrecAntiprotonVsCentrality"), nAntiprot, cent); + histos.fill(HIST("hrecProfileTotalProton"), cent, (nProt + nAntiprot)); + histos.fill(HIST("hrecProfileProton"), cent, nProt); + histos.fill(HIST("hrecProfileAntiproton"), cent, nAntiprot); + histos.fill(HIST("hCorrProfileTotalProton"), cent, (powerEffProt[1] + powerEffAntiprot[1])); + histos.fill(HIST("hCorrProfileProton"), cent, powerEffProt[1]); + histos.fill(HIST("hCorrProfileAntiproton"), cent, powerEffAntiprot[1]); + + // Calculating q_{r,s} as required + for (int i = 1; i < 7; i++) { + fTCP0[i] = 0.0 + powerEffAntiprot[i]; + fTCP1[i] = 0.0 - powerEffAntiprot[i]; + } + + //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + float fQ11_1 = fTCP1[1]; + float fQ11_2 = std::pow(fTCP1[1], 2); + float fQ11_3 = std::pow(fTCP1[1], 3); + float fQ11_4 = std::pow(fTCP1[1], 4); + float fQ11_5 = std::pow(fTCP1[1], 5); + float fQ11_6 = std::pow(fTCP1[1], 6); + + float fQ21_3 = std::pow(fTCP0[1], 3); + float fQ22_3 = std::pow(fTCP0[2], 3); + float fQ31_2 = std::pow(fTCP1[1], 2); + float fQ32_2 = std::pow(fTCP1[2], 2); + float fQ33_2 = std::pow(fTCP1[3], 2); + + float fQ61_1 = fTCP0[1]; + float fQ62_1 = fTCP0[2]; + float fQ63_1 = fTCP0[3]; + float fQ64_1 = fTCP0[4]; + float fQ65_1 = fTCP0[5]; + float fQ66_1 = fTCP0[6]; + + float fQ112122_111 = fTCP1[1] * fTCP0[1] * fTCP0[2]; + float fQ112131_111 = fTCP1[1] * fTCP0[1] * fTCP1[1]; + float fQ112132_111 = fTCP1[1] * fTCP0[1] * fTCP1[2]; + float fQ112133_111 = fTCP1[1] * fTCP0[1] * fTCP1[3]; + float fQ112231_111 = fTCP1[1] * fTCP0[2] * fTCP1[1]; + float fQ112232_111 = fTCP1[1] * fTCP0[2] * fTCP1[2]; + float fQ112233_111 = fTCP1[1] * fTCP0[2] * fTCP1[3]; + float fQ112221_111 = fTCP1[1] * fTCP0[2] * fTCP0[1]; + + float fQ21_1 = fTCP0[1]; + float fQ22_1 = fTCP0[2]; + float fQ31_1 = fTCP1[1]; + float fQ32_1 = fTCP1[2]; + float fQ33_1 = fTCP1[3]; + float fQ41_1 = fTCP0[1]; + float fQ42_1 = fTCP0[2]; + float fQ43_1 = fTCP0[3]; + float fQ44_1 = fTCP0[4]; + float fQ21_2 = std::pow(fTCP0[1], 2); + float fQ22_2 = std::pow(fTCP0[2], 2); + float fQ1121_11 = fTCP1[1] * fTCP0[1]; + float fQ1121_01 = fTCP0[1]; + float fQ1121_10 = fTCP1[1]; + float fQ1121_20 = std::pow(fTCP1[1], 2); + float fQ1121_21 = std::pow(fTCP1[1], 2) * fTCP0[1]; + float fQ1122_11 = fTCP1[1] * fTCP0[2]; + float fQ1122_01 = fTCP0[2]; + float fQ1122_10 = fTCP1[1]; + float fQ1122_20 = std::pow(fTCP1[1], 2); + float fQ1122_21 = std::pow(fTCP1[1], 2) * fTCP0[2]; + float fQ1131_11 = fTCP1[1] * fTCP1[1]; + float fQ1131_01 = fTCP1[1]; + float fQ1131_10 = fTCP1[1]; + float fQ1132_11 = fTCP1[1] * fTCP1[2]; + float fQ1132_01 = fTCP1[2]; + float fQ1132_10 = fTCP1[1]; + float fQ1133_11 = fTCP1[1] * fTCP1[3]; + float fQ1133_01 = fTCP1[3]; + float fQ1133_10 = fTCP1[1]; + float fQ2122_11 = fTCP0[1] * fTCP0[2]; + float fQ2122_01 = fTCP0[2]; + float fQ2122_10 = fTCP0[1]; + + ///////////////---------------------> + float fQ3132_11 = fTCP1[1] * fTCP1[2]; + float fQ3132_01 = fTCP1[2]; + float fQ3132_10 = fTCP1[1]; + float fQ3133_11 = fTCP1[1] * fTCP1[3]; + float fQ3133_01 = fTCP1[3]; + float fQ3133_10 = fTCP1[1]; + float fQ3233_11 = fTCP1[2] * fTCP1[3]; + float fQ3233_01 = fTCP1[3]; + float fQ3233_10 = fTCP1[2]; + float fQ2241_11 = fTCP0[2] * fTCP0[1]; + float fQ2241_01 = fTCP0[1]; + float fQ2241_10 = fTCP0[2]; + float fQ2242_11 = fTCP0[2] * fTCP0[2]; + float fQ2242_01 = fTCP0[2]; + float fQ2242_10 = fTCP0[2]; + float fQ2243_11 = fTCP0[2] * fTCP0[3]; + float fQ2243_01 = fTCP0[3]; + float fQ2243_10 = fTCP0[2]; + float fQ2244_11 = fTCP0[2] * fTCP0[4]; + float fQ2244_01 = fTCP0[4]; + float fQ2244_10 = fTCP0[2]; + float fQ2141_11 = fTCP0[1] * fTCP0[1]; + float fQ2141_01 = fTCP0[1]; + float fQ2141_10 = fTCP0[1]; + float fQ2142_11 = fTCP0[1] * fTCP0[2]; + float fQ2142_01 = fTCP0[2]; + float fQ2142_10 = fTCP0[1]; + float fQ2143_11 = fTCP0[1] * fTCP0[3]; + float fQ2143_01 = fTCP0[3]; + float fQ2143_10 = fTCP0[1]; + float fQ2144_11 = fTCP0[1] * fTCP0[4]; + float fQ2144_01 = fTCP0[4]; + float fQ2144_10 = fTCP0[1]; + float fQ1151_11 = fTCP1[1] * fTCP1[1]; + float fQ1151_01 = fTCP1[1]; + float fQ1151_10 = fTCP1[1]; + float fQ1152_11 = fTCP1[1] * fTCP1[2]; + float fQ1152_01 = fTCP1[2]; + float fQ1152_10 = fTCP1[1]; + float fQ1153_11 = fTCP1[1] * fTCP1[3]; + float fQ1153_01 = fTCP1[3]; + float fQ1153_10 = fTCP1[1]; + float fQ1154_11 = fTCP1[1] * fTCP1[4]; + float fQ1154_01 = fTCP1[4]; + float fQ1154_10 = fTCP1[1]; + float fQ1155_11 = fTCP1[1] * fTCP1[5]; + float fQ1155_01 = fTCP1[5]; + float fQ1155_10 = fTCP1[1]; + + float fQ112233_001 = fTCP1[3]; + float fQ112233_010 = fTCP0[2]; + float fQ112233_100 = fTCP1[1]; + float fQ112233_011 = fTCP0[2] * fTCP1[3]; + float fQ112233_101 = fTCP1[1] * fTCP1[3]; + float fQ112233_110 = fTCP1[1] * fTCP0[2]; + float fQ112232_001 = fTCP1[2]; + float fQ112232_010 = fTCP0[2]; + float fQ112232_100 = fTCP1[1]; + float fQ112232_011 = fTCP0[2] * fTCP1[2]; + float fQ112232_101 = fTCP1[1] * fTCP1[2]; + float fQ112232_110 = fTCP1[1] * fTCP0[2]; + // + float fQ112231_001 = fTCP1[1]; + float fQ112231_010 = fTCP0[2]; + float fQ112231_100 = fTCP1[1]; + float fQ112231_011 = fTCP0[2] * fTCP1[1]; + float fQ112231_101 = fTCP1[1] * fTCP1[1]; + float fQ112231_110 = fTCP1[1] * fTCP0[2]; + float fQ112133_001 = fTCP1[3]; + float fQ112133_010 = fTCP0[1]; + float fQ112133_100 = fTCP1[1]; + float fQ112133_011 = fTCP0[1] * fTCP1[3]; + float fQ112133_101 = fTCP1[1] * fTCP1[3]; + float fQ112133_110 = fTCP1[1] * fTCP0[1]; + + float fQ112132_001 = fTCP1[2]; + float fQ112132_010 = fTCP0[1]; + float fQ112132_100 = fTCP1[1]; + float fQ112132_011 = fTCP0[1] * fTCP1[2]; + float fQ112132_101 = fTCP1[1] * fTCP1[2]; + float fQ112132_110 = fTCP1[1] * fTCP0[1]; + float fQ112131_001 = fTCP1[1]; + float fQ112131_010 = fTCP0[1]; + float fQ112131_100 = fTCP1[1]; + float fQ112131_011 = fTCP0[1] * fTCP1[1]; + float fQ112131_101 = fTCP1[1] * fTCP1[1]; + float fQ112131_110 = fTCP1[1] * fTCP0[1]; + + float fQ2221_11 = fTCP0[2] * fTCP0[1]; + float fQ2221_01 = fTCP0[1]; + float fQ2221_10 = fTCP0[2]; + float fQ2221_21 = std::pow(fTCP0[2], 2) * fTCP0[1]; + float fQ2221_20 = std::pow(fTCP0[2], 2); + + float fQ2122_21 = std::pow(fTCP0[1], 2) * fTCP0[2]; + float fQ2122_20 = std::pow(fTCP0[1], 2); + float fQ1121_02 = std::pow(fTCP0[1], 2); + float fQ1121_12 = fTCP1[1] * std::pow(fTCP0[1], 2); + float fQ1121_22 = std::pow(fTCP1[1], 2) * std::pow(fTCP0[1], 2); + float fQ1122_02 = std::pow(fTCP0[2], 2); + float fQ1122_12 = fTCP1[1] * std::pow(fTCP0[2], 2); + float fQ1122_22 = std::pow(fTCP1[1], 2) * std::pow(fTCP0[2], 2); + + float fQ112221_001 = fTCP0[1]; + float fQ112221_010 = fTCP0[2]; + float fQ112221_100 = fTCP1[1]; + float fQ112221_011 = fTCP0[2] * fTCP0[1]; + float fQ112221_101 = fTCP1[1] * fTCP0[1]; + float fQ112221_110 = fTCP1[1] * fTCP0[2]; + float fQ112221_200 = std::pow(fTCP1[1], 2); + float fQ112221_201 = std::pow(fTCP1[1], 2) * fTCP0[1]; + float fQ112221_210 = std::pow(fTCP1[1], 2) * fTCP0[2]; + float fQ112221_211 = std::pow(fTCP1[1], 2) * fTCP0[2] * fTCP0[1]; + float fQ1131_21 = std::pow(fTCP1[1], 2) * fTCP1[1]; + float fQ1131_20 = std::pow(fTCP1[1], 2); + float fQ1131_31 = std::pow(fTCP1[1], 3) * fTCP1[1]; + float fQ1131_30 = std::pow(fTCP1[1], 3); + + float fQ1132_21 = std::pow(fTCP1[1], 2) * fTCP1[2]; + float fQ1132_20 = std::pow(fTCP1[1], 2); + float fQ1132_31 = std::pow(fTCP1[1], 3) * fTCP1[2]; + float fQ1132_30 = std::pow(fTCP1[1], 3); + float fQ1133_21 = std::pow(fTCP1[1], 2) * fTCP1[3]; + float fQ1133_20 = std::pow(fTCP1[1], 2); + float fQ1133_31 = std::pow(fTCP1[1], 3) * fTCP1[3]; + float fQ1133_30 = std::pow(fTCP1[1], 3); + float fQ1121_30 = std::pow(fTCP1[1], 3); + float fQ1121_31 = std::pow(fTCP1[1], 3) * fTCP0[1]; + float fQ1121_40 = std::pow(fTCP1[1], 4); + float fQ1121_41 = std::pow(fTCP1[1], 4) * fTCP0[1]; + float fQ1122_30 = std::pow(fTCP1[1], 3); + float fQ1122_31 = std::pow(fTCP1[1], 3) * fTCP0[2]; + float fQ1122_40 = std::pow(fTCP1[1], 4); + float fQ1122_41 = std::pow(fTCP1[1], 4) * fTCP0[2]; + + float fQ2211_11 = fTCP0[2] * fTCP1[1]; + float fQ2211_01 = fTCP1[1]; + float fQ2211_10 = fTCP0[2]; + float fQ2211_20 = std::pow(fTCP0[2], 2); + float fQ2211_21 = std::pow(fTCP0[2], 2) * fTCP1[1]; + float fQ2111_11 = fTCP0[1] * fTCP1[1]; + float fQ2111_01 = fTCP1[1]; + float fQ2111_10 = fTCP0[1]; + float fQ2111_20 = std::pow(fTCP0[1], 2); + float fQ2111_21 = std::pow(fTCP0[1], 2) * fTCP1[1]; + + float fQ112122_001 = fTCP0[2]; + float fQ112122_010 = fTCP0[1]; + float fQ112122_100 = fTCP1[1]; + float fQ112122_011 = fTCP0[1] * fTCP0[2]; + float fQ112122_101 = fTCP1[1] * fTCP0[2]; + float fQ112122_110 = fTCP1[1] * fTCP0[1]; + + float fQ1141_11 = fTCP1[1] * fTCP0[1]; + float fQ1141_01 = fTCP0[1]; + float fQ1141_10 = fTCP1[1]; + float fQ1141_20 = std::pow(fTCP1[1], 2); + float fQ1141_21 = std::pow(fTCP1[1], 2) * fTCP0[1]; + float fQ1142_11 = fTCP1[1] * fTCP0[2]; + float fQ1142_01 = fTCP0[2]; + float fQ1142_10 = fTCP1[1]; + float fQ1142_20 = std::pow(fTCP1[1], 2); + float fQ1142_21 = std::pow(fTCP1[1], 2) * fTCP0[2]; + + float fQ1143_11 = fTCP1[1] * fTCP0[3]; + float fQ1143_01 = fTCP0[3]; + float fQ1143_10 = fTCP1[1]; + float fQ1143_20 = std::pow(fTCP1[1], 2); + float fQ1143_21 = std::pow(fTCP1[1], 2) * fTCP0[3]; + float fQ1144_11 = fTCP1[1] * fTCP0[4]; + float fQ1144_01 = fTCP0[4]; + float fQ1144_10 = fTCP1[1]; + float fQ1144_20 = std::pow(fTCP1[1], 2); + float fQ1144_21 = std::pow(fTCP1[1], 2) * fTCP0[4]; + float fQ2131_11 = fTCP0[1] * fTCP1[1]; + float fQ2131_01 = fTCP1[1]; + float fQ2131_10 = fTCP0[1]; + + float fQ2132_11 = fTCP0[1] * fTCP1[2]; + float fQ2132_01 = fTCP1[2]; + float fQ2132_10 = fTCP0[1]; + float fQ2133_11 = fTCP0[1] * fTCP1[3]; + float fQ2133_01 = fTCP1[3]; + float fQ2133_10 = fTCP0[1]; + float fQ2231_11 = fTCP0[2] * fTCP1[1]; + float fQ2231_01 = fTCP1[1]; + float fQ2231_10 = fTCP0[2]; + float fQ2232_11 = fTCP0[2] * fTCP1[2]; + float fQ2232_01 = fTCP1[2]; + float fQ2232_10 = fTCP0[2]; + float fQ2233_11 = fTCP0[2] * fTCP1[3]; + float fQ2233_01 = fTCP1[3]; + float fQ2233_10 = fTCP0[2]; + + float fQ51_1 = fTCP1[1]; + float fQ52_1 = fTCP1[2]; + float fQ53_1 = fTCP1[3]; + float fQ54_1 = fTCP1[4]; + float fQ55_1 = fTCP1[5]; + + //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + if (cfgIsCalculateCentral) { + + // uncorrected + histos.get(HIST("Prof_mu1_antiproton"))->Fill(cent, std::pow(netProt, 1.0)); + histos.get(HIST("Prof_mu2_antiproton"))->Fill(cent, std::pow(netProt, 2.0)); + histos.get(HIST("Prof_mu3_antiproton"))->Fill(cent, std::pow(netProt, 3.0)); + histos.get(HIST("Prof_mu4_antiproton"))->Fill(cent, std::pow(netProt, 4.0)); + histos.get(HIST("Prof_mu5_antiproton"))->Fill(cent, std::pow(netProt, 5.0)); + histos.get(HIST("Prof_mu6_antiproton"))->Fill(cent, std::pow(netProt, 6.0)); + histos.get(HIST("Prof_mu7_antiproton"))->Fill(cent, std::pow(netProt, 7.0)); + histos.get(HIST("Prof_mu8_antiproton"))->Fill(cent, std::pow(netProt, 8.0)); + + // eff. corrected + histos.get(HIST("Prof_Q11_1"))->Fill(cent, fQ11_1); + histos.get(HIST("Prof_Q11_2"))->Fill(cent, fQ11_2); + histos.get(HIST("Prof_Q11_3"))->Fill(cent, fQ11_3); + histos.get(HIST("Prof_Q11_4"))->Fill(cent, fQ11_4); + histos.get(HIST("Prof_Q21_1"))->Fill(cent, fQ21_1); + histos.get(HIST("Prof_Q22_1"))->Fill(cent, fQ22_1); + histos.get(HIST("Prof_Q31_1"))->Fill(cent, fQ31_1); + histos.get(HIST("Prof_Q32_1"))->Fill(cent, fQ32_1); + histos.get(HIST("Prof_Q33_1"))->Fill(cent, fQ33_1); + histos.get(HIST("Prof_Q41_1"))->Fill(cent, fQ41_1); + histos.get(HIST("Prof_Q42_1"))->Fill(cent, fQ42_1); + histos.get(HIST("Prof_Q43_1"))->Fill(cent, fQ43_1); + histos.get(HIST("Prof_Q44_1"))->Fill(cent, fQ44_1); + histos.get(HIST("Prof_Q21_2"))->Fill(cent, fQ21_2); + histos.get(HIST("Prof_Q22_2"))->Fill(cent, fQ22_2); + histos.get(HIST("Prof_Q1121_11"))->Fill(cent, fQ1121_11); + histos.get(HIST("Prof_Q1121_01"))->Fill(cent, fQ1121_01); + histos.get(HIST("Prof_Q1121_10"))->Fill(cent, fQ1121_10); + histos.get(HIST("Prof_Q1121_20"))->Fill(cent, fQ1121_20); + histos.get(HIST("Prof_Q1121_21"))->Fill(cent, fQ1121_21); + histos.get(HIST("Prof_Q1122_11"))->Fill(cent, fQ1122_11); + histos.get(HIST("Prof_Q1122_01"))->Fill(cent, fQ1122_01); + histos.get(HIST("Prof_Q1122_10"))->Fill(cent, fQ1122_10); + histos.get(HIST("Prof_Q1122_20"))->Fill(cent, fQ1122_20); + histos.get(HIST("Prof_Q1122_21"))->Fill(cent, fQ1122_21); + histos.get(HIST("Prof_Q1131_11"))->Fill(cent, fQ1131_11); + histos.get(HIST("Prof_Q1131_01"))->Fill(cent, fQ1131_01); + histos.get(HIST("Prof_Q1131_10"))->Fill(cent, fQ1131_10); + histos.get(HIST("Prof_Q1132_11"))->Fill(cent, fQ1132_11); + histos.get(HIST("Prof_Q1132_01"))->Fill(cent, fQ1132_01); + histos.get(HIST("Prof_Q1132_10"))->Fill(cent, fQ1132_10); + histos.get(HIST("Prof_Q1133_11"))->Fill(cent, fQ1133_11); + histos.get(HIST("Prof_Q1133_01"))->Fill(cent, fQ1133_01); + histos.get(HIST("Prof_Q1133_10"))->Fill(cent, fQ1133_10); + histos.get(HIST("Prof_Q2122_11"))->Fill(cent, fQ2122_11); + histos.get(HIST("Prof_Q2122_01"))->Fill(cent, fQ2122_01); + histos.get(HIST("Prof_Q2122_10"))->Fill(cent, fQ2122_10); + histos.get(HIST("Prof_Q3132_11"))->Fill(cent, fQ3132_11); + histos.get(HIST("Prof_Q3132_01"))->Fill(cent, fQ3132_01); + histos.get(HIST("Prof_Q3132_10"))->Fill(cent, fQ3132_10); + histos.get(HIST("Prof_Q3133_11"))->Fill(cent, fQ3133_11); + histos.get(HIST("Prof_Q3133_01"))->Fill(cent, fQ3133_01); + histos.get(HIST("Prof_Q3133_10"))->Fill(cent, fQ3133_10); + histos.get(HIST("Prof_Q3233_11"))->Fill(cent, fQ3233_11); + histos.get(HIST("Prof_Q3233_01"))->Fill(cent, fQ3233_01); + histos.get(HIST("Prof_Q3233_10"))->Fill(cent, fQ3233_10); + histos.get(HIST("Prof_Q2241_11"))->Fill(cent, fQ2241_11); + histos.get(HIST("Prof_Q2241_01"))->Fill(cent, fQ2241_01); + histos.get(HIST("Prof_Q2241_10"))->Fill(cent, fQ2241_10); + histos.get(HIST("Prof_Q2242_11"))->Fill(cent, fQ2242_11); + histos.get(HIST("Prof_Q2242_01"))->Fill(cent, fQ2242_01); + histos.get(HIST("Prof_Q2242_10"))->Fill(cent, fQ2242_10); + histos.get(HIST("Prof_Q2243_11"))->Fill(cent, fQ2243_11); + histos.get(HIST("Prof_Q2243_01"))->Fill(cent, fQ2243_01); + histos.get(HIST("Prof_Q2243_10"))->Fill(cent, fQ2243_10); + histos.get(HIST("Prof_Q2244_11"))->Fill(cent, fQ2244_11); + histos.get(HIST("Prof_Q2244_01"))->Fill(cent, fQ2244_01); + histos.get(HIST("Prof_Q2244_10"))->Fill(cent, fQ2244_10); + histos.get(HIST("Prof_Q2141_11"))->Fill(cent, fQ2141_11); + histos.get(HIST("Prof_Q2141_01"))->Fill(cent, fQ2141_01); + histos.get(HIST("Prof_Q2141_10"))->Fill(cent, fQ2141_10); + histos.get(HIST("Prof_Q2142_11"))->Fill(cent, fQ2142_11); + histos.get(HIST("Prof_Q2142_01"))->Fill(cent, fQ2142_01); + histos.get(HIST("Prof_Q2142_10"))->Fill(cent, fQ2142_10); + histos.get(HIST("Prof_Q2143_11"))->Fill(cent, fQ2143_11); + histos.get(HIST("Prof_Q2143_01"))->Fill(cent, fQ2143_01); + histos.get(HIST("Prof_Q2143_10"))->Fill(cent, fQ2143_10); + histos.get(HIST("Prof_Q2144_11"))->Fill(cent, fQ2144_11); + histos.get(HIST("Prof_Q2144_01"))->Fill(cent, fQ2144_01); + histos.get(HIST("Prof_Q2144_10"))->Fill(cent, fQ2144_10); + histos.get(HIST("Prof_Q1151_11"))->Fill(cent, fQ1151_11); + histos.get(HIST("Prof_Q1151_01"))->Fill(cent, fQ1151_01); + histos.get(HIST("Prof_Q1151_10"))->Fill(cent, fQ1151_10); + histos.get(HIST("Prof_Q1152_11"))->Fill(cent, fQ1152_11); + histos.get(HIST("Prof_Q1152_01"))->Fill(cent, fQ1152_01); + histos.get(HIST("Prof_Q1152_10"))->Fill(cent, fQ1152_10); + histos.get(HIST("Prof_Q1153_11"))->Fill(cent, fQ1153_11); + histos.get(HIST("Prof_Q1153_01"))->Fill(cent, fQ1153_01); + histos.get(HIST("Prof_Q1153_10"))->Fill(cent, fQ1153_10); + histos.get(HIST("Prof_Q1154_11"))->Fill(cent, fQ1154_11); + histos.get(HIST("Prof_Q1154_01"))->Fill(cent, fQ1154_01); + histos.get(HIST("Prof_Q1154_10"))->Fill(cent, fQ1154_10); + histos.get(HIST("Prof_Q1155_11"))->Fill(cent, fQ1155_11); + histos.get(HIST("Prof_Q1155_01"))->Fill(cent, fQ1155_01); + histos.get(HIST("Prof_Q1155_10"))->Fill(cent, fQ1155_10); + histos.get(HIST("Prof_Q112233_001"))->Fill(cent, fQ112233_001); + histos.get(HIST("Prof_Q112233_010"))->Fill(cent, fQ112233_010); + histos.get(HIST("Prof_Q112233_100"))->Fill(cent, fQ112233_100); + histos.get(HIST("Prof_Q112233_011"))->Fill(cent, fQ112233_011); + histos.get(HIST("Prof_Q112233_101"))->Fill(cent, fQ112233_101); + histos.get(HIST("Prof_Q112233_110"))->Fill(cent, fQ112233_110); + histos.get(HIST("Prof_Q112232_001"))->Fill(cent, fQ112232_001); + histos.get(HIST("Prof_Q112232_010"))->Fill(cent, fQ112232_010); + histos.get(HIST("Prof_Q112232_100"))->Fill(cent, fQ112232_100); + histos.get(HIST("Prof_Q112232_011"))->Fill(cent, fQ112232_011); + histos.get(HIST("Prof_Q112232_101"))->Fill(cent, fQ112232_101); + histos.get(HIST("Prof_Q112232_110"))->Fill(cent, fQ112232_110); + histos.get(HIST("Prof_Q112231_001"))->Fill(cent, fQ112231_001); + histos.get(HIST("Prof_Q112231_010"))->Fill(cent, fQ112231_010); + histos.get(HIST("Prof_Q112231_100"))->Fill(cent, fQ112231_100); + histos.get(HIST("Prof_Q112231_011"))->Fill(cent, fQ112231_011); + histos.get(HIST("Prof_Q112231_101"))->Fill(cent, fQ112231_101); + histos.get(HIST("Prof_Q112231_110"))->Fill(cent, fQ112231_110); + histos.get(HIST("Prof_Q112133_001"))->Fill(cent, fQ112133_001); + histos.get(HIST("Prof_Q112133_010"))->Fill(cent, fQ112133_010); + histos.get(HIST("Prof_Q112133_100"))->Fill(cent, fQ112133_100); + histos.get(HIST("Prof_Q112133_011"))->Fill(cent, fQ112133_011); + histos.get(HIST("Prof_Q112133_101"))->Fill(cent, fQ112133_101); + histos.get(HIST("Prof_Q112133_110"))->Fill(cent, fQ112133_110); + histos.get(HIST("Prof_Q112132_001"))->Fill(cent, fQ112132_001); + histos.get(HIST("Prof_Q112132_010"))->Fill(cent, fQ112132_010); + histos.get(HIST("Prof_Q112132_100"))->Fill(cent, fQ112132_100); + histos.get(HIST("Prof_Q112132_011"))->Fill(cent, fQ112132_011); + histos.get(HIST("Prof_Q112132_101"))->Fill(cent, fQ112132_101); + histos.get(HIST("Prof_Q112132_110"))->Fill(cent, fQ112132_110); + histos.get(HIST("Prof_Q112131_001"))->Fill(cent, fQ112131_001); + histos.get(HIST("Prof_Q112131_010"))->Fill(cent, fQ112131_010); + histos.get(HIST("Prof_Q112131_100"))->Fill(cent, fQ112131_100); + histos.get(HIST("Prof_Q112131_011"))->Fill(cent, fQ112131_011); + histos.get(HIST("Prof_Q112131_101"))->Fill(cent, fQ112131_101); + histos.get(HIST("Prof_Q112131_110"))->Fill(cent, fQ112131_110); + histos.get(HIST("Prof_Q2221_11"))->Fill(cent, fQ2221_11); + histos.get(HIST("Prof_Q2221_01"))->Fill(cent, fQ2221_01); + histos.get(HIST("Prof_Q2221_10"))->Fill(cent, fQ2221_10); + histos.get(HIST("Prof_Q2221_21"))->Fill(cent, fQ2221_21); + histos.get(HIST("Prof_Q2221_20"))->Fill(cent, fQ2221_20); + histos.get(HIST("Prof_Q2122_21"))->Fill(cent, fQ2122_21); + histos.get(HIST("Prof_Q2122_20"))->Fill(cent, fQ2122_20); + histos.get(HIST("Prof_Q1121_02"))->Fill(cent, fQ1121_02); + histos.get(HIST("Prof_Q1121_12"))->Fill(cent, fQ1121_12); + histos.get(HIST("Prof_Q1121_22"))->Fill(cent, fQ1121_22); + histos.get(HIST("Prof_Q1122_02"))->Fill(cent, fQ1122_02); + histos.get(HIST("Prof_Q1122_12"))->Fill(cent, fQ1122_12); + histos.get(HIST("Prof_Q1122_22"))->Fill(cent, fQ1122_22); + histos.get(HIST("Prof_Q112221_001"))->Fill(cent, fQ112221_001); + histos.get(HIST("Prof_Q112221_010"))->Fill(cent, fQ112221_010); + histos.get(HIST("Prof_Q112221_100"))->Fill(cent, fQ112221_100); + histos.get(HIST("Prof_Q112221_011"))->Fill(cent, fQ112221_011); + histos.get(HIST("Prof_Q112221_101"))->Fill(cent, fQ112221_101); + histos.get(HIST("Prof_Q112221_110"))->Fill(cent, fQ112221_110); + histos.get(HIST("Prof_Q112221_200"))->Fill(cent, fQ112221_200); + histos.get(HIST("Prof_Q112221_201"))->Fill(cent, fQ112221_201); + histos.get(HIST("Prof_Q112221_210"))->Fill(cent, fQ112221_210); + histos.get(HIST("Prof_Q112221_211"))->Fill(cent, fQ112221_211); + histos.get(HIST("Prof_Q1131_21"))->Fill(cent, fQ1131_21); + histos.get(HIST("Prof_Q1131_20"))->Fill(cent, fQ1131_20); + histos.get(HIST("Prof_Q1131_31"))->Fill(cent, fQ1131_31); + histos.get(HIST("Prof_Q1131_30"))->Fill(cent, fQ1131_30); + histos.get(HIST("Prof_Q1132_21"))->Fill(cent, fQ1132_21); + histos.get(HIST("Prof_Q1132_20"))->Fill(cent, fQ1132_20); + histos.get(HIST("Prof_Q1132_31"))->Fill(cent, fQ1132_31); + histos.get(HIST("Prof_Q1132_30"))->Fill(cent, fQ1132_30); + histos.get(HIST("Prof_Q1133_21"))->Fill(cent, fQ1133_21); + histos.get(HIST("Prof_Q1133_20"))->Fill(cent, fQ1133_20); + histos.get(HIST("Prof_Q1133_31"))->Fill(cent, fQ1133_31); + histos.get(HIST("Prof_Q1133_30"))->Fill(cent, fQ1133_30); + histos.get(HIST("Prof_Q11_5"))->Fill(cent, fQ11_5); + histos.get(HIST("Prof_Q11_6"))->Fill(cent, fQ11_6); + histos.get(HIST("Prof_Q1121_30"))->Fill(cent, fQ1121_30); + histos.get(HIST("Prof_Q1121_31"))->Fill(cent, fQ1121_31); + histos.get(HIST("Prof_Q1121_40"))->Fill(cent, fQ1121_40); + histos.get(HIST("Prof_Q1121_41"))->Fill(cent, fQ1121_41); + histos.get(HIST("Prof_Q1122_30"))->Fill(cent, fQ1122_30); + histos.get(HIST("Prof_Q1122_31"))->Fill(cent, fQ1122_31); + histos.get(HIST("Prof_Q1122_40"))->Fill(cent, fQ1122_40); + histos.get(HIST("Prof_Q1122_41"))->Fill(cent, fQ1122_41); + histos.get(HIST("Prof_Q2211_11"))->Fill(cent, fQ2211_11); + histos.get(HIST("Prof_Q2211_01"))->Fill(cent, fQ2211_01); + histos.get(HIST("Prof_Q2211_10"))->Fill(cent, fQ2211_10); + histos.get(HIST("Prof_Q2211_20"))->Fill(cent, fQ2211_20); + histos.get(HIST("Prof_Q2211_21"))->Fill(cent, fQ2211_21); + histos.get(HIST("Prof_Q2111_11"))->Fill(cent, fQ2111_11); + histos.get(HIST("Prof_Q2111_01"))->Fill(cent, fQ2111_01); + histos.get(HIST("Prof_Q2111_10"))->Fill(cent, fQ2111_10); + histos.get(HIST("Prof_Q2111_20"))->Fill(cent, fQ2111_20); + histos.get(HIST("Prof_Q2111_21"))->Fill(cent, fQ2111_21); + histos.get(HIST("Prof_Q112122_001"))->Fill(cent, fQ112122_001); + histos.get(HIST("Prof_Q112122_010"))->Fill(cent, fQ112122_010); + histos.get(HIST("Prof_Q112122_100"))->Fill(cent, fQ112122_100); + histos.get(HIST("Prof_Q112122_011"))->Fill(cent, fQ112122_011); + histos.get(HIST("Prof_Q112122_101"))->Fill(cent, fQ112122_101); + histos.get(HIST("Prof_Q112122_110"))->Fill(cent, fQ112122_110); + histos.get(HIST("Prof_Q1141_11"))->Fill(cent, fQ1141_11); + histos.get(HIST("Prof_Q1141_01"))->Fill(cent, fQ1141_01); + histos.get(HIST("Prof_Q1141_10"))->Fill(cent, fQ1141_10); + histos.get(HIST("Prof_Q1141_20"))->Fill(cent, fQ1141_20); + histos.get(HIST("Prof_Q1141_21"))->Fill(cent, fQ1141_21); + histos.get(HIST("Prof_Q1142_11"))->Fill(cent, fQ1142_11); + histos.get(HIST("Prof_Q1142_01"))->Fill(cent, fQ1142_01); + histos.get(HIST("Prof_Q1142_10"))->Fill(cent, fQ1142_10); + histos.get(HIST("Prof_Q1142_20"))->Fill(cent, fQ1142_20); + histos.get(HIST("Prof_Q1142_21"))->Fill(cent, fQ1142_21); + histos.get(HIST("Prof_Q1143_11"))->Fill(cent, fQ1143_11); + histos.get(HIST("Prof_Q1143_01"))->Fill(cent, fQ1143_01); + histos.get(HIST("Prof_Q1143_10"))->Fill(cent, fQ1143_10); + histos.get(HIST("Prof_Q1143_20"))->Fill(cent, fQ1143_20); + histos.get(HIST("Prof_Q1143_21"))->Fill(cent, fQ1143_21); + histos.get(HIST("Prof_Q1144_11"))->Fill(cent, fQ1144_11); + histos.get(HIST("Prof_Q1144_01"))->Fill(cent, fQ1144_01); + histos.get(HIST("Prof_Q1144_10"))->Fill(cent, fQ1144_10); + histos.get(HIST("Prof_Q1144_20"))->Fill(cent, fQ1144_20); + histos.get(HIST("Prof_Q1144_21"))->Fill(cent, fQ1144_21); + histos.get(HIST("Prof_Q2131_11"))->Fill(cent, fQ2131_11); + histos.get(HIST("Prof_Q2131_01"))->Fill(cent, fQ2131_01); + histos.get(HIST("Prof_Q2131_10"))->Fill(cent, fQ2131_10); + histos.get(HIST("Prof_Q2132_11"))->Fill(cent, fQ2132_11); + histos.get(HIST("Prof_Q2132_01"))->Fill(cent, fQ2132_01); + histos.get(HIST("Prof_Q2132_10"))->Fill(cent, fQ2132_10); + histos.get(HIST("Prof_Q2133_11"))->Fill(cent, fQ2133_11); + histos.get(HIST("Prof_Q2133_01"))->Fill(cent, fQ2133_01); + histos.get(HIST("Prof_Q2133_10"))->Fill(cent, fQ2133_10); + histos.get(HIST("Prof_Q2231_11"))->Fill(cent, fQ2231_11); + histos.get(HIST("Prof_Q2231_01"))->Fill(cent, fQ2231_01); + histos.get(HIST("Prof_Q2231_10"))->Fill(cent, fQ2231_10); + histos.get(HIST("Prof_Q2232_11"))->Fill(cent, fQ2232_11); + histos.get(HIST("Prof_Q2232_01"))->Fill(cent, fQ2232_01); + histos.get(HIST("Prof_Q2232_10"))->Fill(cent, fQ2232_10); + histos.get(HIST("Prof_Q2233_11"))->Fill(cent, fQ2233_11); + histos.get(HIST("Prof_Q2233_01"))->Fill(cent, fQ2233_01); + histos.get(HIST("Prof_Q2233_10"))->Fill(cent, fQ2233_10); + histos.get(HIST("Prof_Q51_1"))->Fill(cent, fQ51_1); + histos.get(HIST("Prof_Q52_1"))->Fill(cent, fQ52_1); + histos.get(HIST("Prof_Q53_1"))->Fill(cent, fQ53_1); + histos.get(HIST("Prof_Q54_1"))->Fill(cent, fQ54_1); + histos.get(HIST("Prof_Q55_1"))->Fill(cent, fQ55_1); + histos.get(HIST("Prof_Q21_3"))->Fill(cent, fQ21_3); + histos.get(HIST("Prof_Q22_3"))->Fill(cent, fQ22_3); + histos.get(HIST("Prof_Q31_2"))->Fill(cent, fQ31_2); + histos.get(HIST("Prof_Q32_2"))->Fill(cent, fQ32_2); + histos.get(HIST("Prof_Q33_2"))->Fill(cent, fQ33_2); + histos.get(HIST("Prof_Q61_1"))->Fill(cent, fQ61_1); + histos.get(HIST("Prof_Q62_1"))->Fill(cent, fQ62_1); + histos.get(HIST("Prof_Q63_1"))->Fill(cent, fQ63_1); + histos.get(HIST("Prof_Q64_1"))->Fill(cent, fQ64_1); + histos.get(HIST("Prof_Q65_1"))->Fill(cent, fQ65_1); + histos.get(HIST("Prof_Q66_1"))->Fill(cent, fQ66_1); + histos.get(HIST("Prof_Q112122_111"))->Fill(cent, fQ112122_111); + histos.get(HIST("Prof_Q112131_111"))->Fill(cent, fQ112131_111); + histos.get(HIST("Prof_Q112132_111"))->Fill(cent, fQ112132_111); + histos.get(HIST("Prof_Q112133_111"))->Fill(cent, fQ112133_111); + histos.get(HIST("Prof_Q112231_111"))->Fill(cent, fQ112231_111); + histos.get(HIST("Prof_Q112232_111"))->Fill(cent, fQ112232_111); + histos.get(HIST("Prof_Q112233_111"))->Fill(cent, fQ112233_111); + histos.get(HIST("Prof_Q112221_111"))->Fill(cent, fQ112221_111); + } + + if (cfgIsCalculateError) { + // selecting subsample and filling profiles + float lRandom = fRndm->Rndm(); + int sampleIndex = static_cast(cfgNSubsample * lRandom); + + histos.get(HIST("Prof2D_mu1_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 1.0)); + histos.get(HIST("Prof2D_mu2_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 2.0)); + histos.get(HIST("Prof2D_mu3_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 3.0)); + histos.get(HIST("Prof2D_mu4_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 4.0)); + histos.get(HIST("Prof2D_mu5_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 5.0)); + histos.get(HIST("Prof2D_mu6_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 6.0)); + histos.get(HIST("Prof2D_mu7_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 7.0)); + histos.get(HIST("Prof2D_mu8_antiproton"))->Fill(cent, sampleIndex, std::pow(netProt, 8.0)); + + histos.get(HIST("Prof2D_Q11_1"))->Fill(cent, sampleIndex, fQ11_1); + histos.get(HIST("Prof2D_Q11_2"))->Fill(cent, sampleIndex, fQ11_2); + histos.get(HIST("Prof2D_Q11_3"))->Fill(cent, sampleIndex, fQ11_3); + histos.get(HIST("Prof2D_Q11_4"))->Fill(cent, sampleIndex, fQ11_4); + histos.get(HIST("Prof2D_Q21_1"))->Fill(cent, sampleIndex, fQ21_1); + histos.get(HIST("Prof2D_Q22_1"))->Fill(cent, sampleIndex, fQ22_1); + histos.get(HIST("Prof2D_Q31_1"))->Fill(cent, sampleIndex, fQ31_1); + histos.get(HIST("Prof2D_Q32_1"))->Fill(cent, sampleIndex, fQ32_1); + histos.get(HIST("Prof2D_Q33_1"))->Fill(cent, sampleIndex, fQ33_1); + histos.get(HIST("Prof2D_Q41_1"))->Fill(cent, sampleIndex, fQ41_1); + histos.get(HIST("Prof2D_Q42_1"))->Fill(cent, sampleIndex, fQ42_1); + histos.get(HIST("Prof2D_Q43_1"))->Fill(cent, sampleIndex, fQ43_1); + histos.get(HIST("Prof2D_Q44_1"))->Fill(cent, sampleIndex, fQ44_1); + histos.get(HIST("Prof2D_Q21_2"))->Fill(cent, sampleIndex, fQ21_2); + histos.get(HIST("Prof2D_Q22_2"))->Fill(cent, sampleIndex, fQ22_2); + histos.get(HIST("Prof2D_Q1121_11"))->Fill(cent, sampleIndex, fQ1121_11); + histos.get(HIST("Prof2D_Q1121_01"))->Fill(cent, sampleIndex, fQ1121_01); + histos.get(HIST("Prof2D_Q1121_10"))->Fill(cent, sampleIndex, fQ1121_10); + histos.get(HIST("Prof2D_Q1121_20"))->Fill(cent, sampleIndex, fQ1121_20); + histos.get(HIST("Prof2D_Q1121_21"))->Fill(cent, sampleIndex, fQ1121_21); + histos.get(HIST("Prof2D_Q1122_11"))->Fill(cent, sampleIndex, fQ1122_11); + histos.get(HIST("Prof2D_Q1122_01"))->Fill(cent, sampleIndex, fQ1122_01); + histos.get(HIST("Prof2D_Q1122_10"))->Fill(cent, sampleIndex, fQ1122_10); + histos.get(HIST("Prof2D_Q1122_20"))->Fill(cent, sampleIndex, fQ1122_20); + histos.get(HIST("Prof2D_Q1122_21"))->Fill(cent, sampleIndex, fQ1122_21); + histos.get(HIST("Prof2D_Q1131_11"))->Fill(cent, sampleIndex, fQ1131_11); + histos.get(HIST("Prof2D_Q1131_01"))->Fill(cent, sampleIndex, fQ1131_01); + histos.get(HIST("Prof2D_Q1131_10"))->Fill(cent, sampleIndex, fQ1131_10); + histos.get(HIST("Prof2D_Q1132_11"))->Fill(cent, sampleIndex, fQ1132_11); + histos.get(HIST("Prof2D_Q1132_01"))->Fill(cent, sampleIndex, fQ1132_01); + histos.get(HIST("Prof2D_Q1132_10"))->Fill(cent, sampleIndex, fQ1132_10); + histos.get(HIST("Prof2D_Q1133_11"))->Fill(cent, sampleIndex, fQ1133_11); + histos.get(HIST("Prof2D_Q1133_01"))->Fill(cent, sampleIndex, fQ1133_01); + histos.get(HIST("Prof2D_Q1133_10"))->Fill(cent, sampleIndex, fQ1133_10); + histos.get(HIST("Prof2D_Q2122_11"))->Fill(cent, sampleIndex, fQ2122_11); + histos.get(HIST("Prof2D_Q2122_01"))->Fill(cent, sampleIndex, fQ2122_01); + histos.get(HIST("Prof2D_Q2122_10"))->Fill(cent, sampleIndex, fQ2122_10); + histos.get(HIST("Prof2D_Q3132_11"))->Fill(cent, sampleIndex, fQ3132_11); + histos.get(HIST("Prof2D_Q3132_01"))->Fill(cent, sampleIndex, fQ3132_01); + histos.get(HIST("Prof2D_Q3132_10"))->Fill(cent, sampleIndex, fQ3132_10); + histos.get(HIST("Prof2D_Q3133_11"))->Fill(cent, sampleIndex, fQ3133_11); + histos.get(HIST("Prof2D_Q3133_01"))->Fill(cent, sampleIndex, fQ3133_01); + histos.get(HIST("Prof2D_Q3133_10"))->Fill(cent, sampleIndex, fQ3133_10); + histos.get(HIST("Prof2D_Q3233_11"))->Fill(cent, sampleIndex, fQ3233_11); + histos.get(HIST("Prof2D_Q3233_01"))->Fill(cent, sampleIndex, fQ3233_01); + histos.get(HIST("Prof2D_Q3233_10"))->Fill(cent, sampleIndex, fQ3233_10); + histos.get(HIST("Prof2D_Q2241_11"))->Fill(cent, sampleIndex, fQ2241_11); + histos.get(HIST("Prof2D_Q2241_01"))->Fill(cent, sampleIndex, fQ2241_01); + histos.get(HIST("Prof2D_Q2241_10"))->Fill(cent, sampleIndex, fQ2241_10); + histos.get(HIST("Prof2D_Q2242_11"))->Fill(cent, sampleIndex, fQ2242_11); + histos.get(HIST("Prof2D_Q2242_01"))->Fill(cent, sampleIndex, fQ2242_01); + histos.get(HIST("Prof2D_Q2242_10"))->Fill(cent, sampleIndex, fQ2242_10); + histos.get(HIST("Prof2D_Q2243_11"))->Fill(cent, sampleIndex, fQ2243_11); + histos.get(HIST("Prof2D_Q2243_01"))->Fill(cent, sampleIndex, fQ2243_01); + histos.get(HIST("Prof2D_Q2243_10"))->Fill(cent, sampleIndex, fQ2243_10); + histos.get(HIST("Prof2D_Q2244_11"))->Fill(cent, sampleIndex, fQ2244_11); + histos.get(HIST("Prof2D_Q2244_01"))->Fill(cent, sampleIndex, fQ2244_01); + histos.get(HIST("Prof2D_Q2244_10"))->Fill(cent, sampleIndex, fQ2244_10); + histos.get(HIST("Prof2D_Q2141_11"))->Fill(cent, sampleIndex, fQ2141_11); + histos.get(HIST("Prof2D_Q2141_01"))->Fill(cent, sampleIndex, fQ2141_01); + histos.get(HIST("Prof2D_Q2141_10"))->Fill(cent, sampleIndex, fQ2141_10); + histos.get(HIST("Prof2D_Q2142_11"))->Fill(cent, sampleIndex, fQ2142_11); + histos.get(HIST("Prof2D_Q2142_01"))->Fill(cent, sampleIndex, fQ2142_01); + histos.get(HIST("Prof2D_Q2142_10"))->Fill(cent, sampleIndex, fQ2142_10); + histos.get(HIST("Prof2D_Q2143_11"))->Fill(cent, sampleIndex, fQ2143_11); + histos.get(HIST("Prof2D_Q2143_01"))->Fill(cent, sampleIndex, fQ2143_01); + histos.get(HIST("Prof2D_Q2143_10"))->Fill(cent, sampleIndex, fQ2143_10); + histos.get(HIST("Prof2D_Q2144_11"))->Fill(cent, sampleIndex, fQ2144_11); + histos.get(HIST("Prof2D_Q2144_01"))->Fill(cent, sampleIndex, fQ2144_01); + histos.get(HIST("Prof2D_Q2144_10"))->Fill(cent, sampleIndex, fQ2144_10); + histos.get(HIST("Prof2D_Q1151_11"))->Fill(cent, sampleIndex, fQ1151_11); + histos.get(HIST("Prof2D_Q1151_01"))->Fill(cent, sampleIndex, fQ1151_01); + histos.get(HIST("Prof2D_Q1151_10"))->Fill(cent, sampleIndex, fQ1151_10); + histos.get(HIST("Prof2D_Q1152_11"))->Fill(cent, sampleIndex, fQ1152_11); + histos.get(HIST("Prof2D_Q1152_01"))->Fill(cent, sampleIndex, fQ1152_01); + histos.get(HIST("Prof2D_Q1152_10"))->Fill(cent, sampleIndex, fQ1152_10); + histos.get(HIST("Prof2D_Q1153_11"))->Fill(cent, sampleIndex, fQ1153_11); + histos.get(HIST("Prof2D_Q1153_01"))->Fill(cent, sampleIndex, fQ1153_01); + histos.get(HIST("Prof2D_Q1153_10"))->Fill(cent, sampleIndex, fQ1153_10); + histos.get(HIST("Prof2D_Q1154_11"))->Fill(cent, sampleIndex, fQ1154_11); + histos.get(HIST("Prof2D_Q1154_01"))->Fill(cent, sampleIndex, fQ1154_01); + histos.get(HIST("Prof2D_Q1154_10"))->Fill(cent, sampleIndex, fQ1154_10); + histos.get(HIST("Prof2D_Q1155_11"))->Fill(cent, sampleIndex, fQ1155_11); + histos.get(HIST("Prof2D_Q1155_01"))->Fill(cent, sampleIndex, fQ1155_01); + histos.get(HIST("Prof2D_Q1155_10"))->Fill(cent, sampleIndex, fQ1155_10); + histos.get(HIST("Prof2D_Q112233_001"))->Fill(cent, sampleIndex, fQ112233_001); + histos.get(HIST("Prof2D_Q112233_010"))->Fill(cent, sampleIndex, fQ112233_010); + histos.get(HIST("Prof2D_Q112233_100"))->Fill(cent, sampleIndex, fQ112233_100); + histos.get(HIST("Prof2D_Q112233_011"))->Fill(cent, sampleIndex, fQ112233_011); + histos.get(HIST("Prof2D_Q112233_101"))->Fill(cent, sampleIndex, fQ112233_101); + histos.get(HIST("Prof2D_Q112233_110"))->Fill(cent, sampleIndex, fQ112233_110); + histos.get(HIST("Prof2D_Q112232_001"))->Fill(cent, sampleIndex, fQ112232_001); + histos.get(HIST("Prof2D_Q112232_010"))->Fill(cent, sampleIndex, fQ112232_010); + histos.get(HIST("Prof2D_Q112232_100"))->Fill(cent, sampleIndex, fQ112232_100); + histos.get(HIST("Prof2D_Q112232_011"))->Fill(cent, sampleIndex, fQ112232_011); + histos.get(HIST("Prof2D_Q112232_101"))->Fill(cent, sampleIndex, fQ112232_101); + histos.get(HIST("Prof2D_Q112232_110"))->Fill(cent, sampleIndex, fQ112232_110); + histos.get(HIST("Prof2D_Q112231_001"))->Fill(cent, sampleIndex, fQ112231_001); + histos.get(HIST("Prof2D_Q112231_010"))->Fill(cent, sampleIndex, fQ112231_010); + histos.get(HIST("Prof2D_Q112231_100"))->Fill(cent, sampleIndex, fQ112231_100); + histos.get(HIST("Prof2D_Q112231_011"))->Fill(cent, sampleIndex, fQ112231_011); + histos.get(HIST("Prof2D_Q112231_101"))->Fill(cent, sampleIndex, fQ112231_101); + histos.get(HIST("Prof2D_Q112231_110"))->Fill(cent, sampleIndex, fQ112231_110); + histos.get(HIST("Prof2D_Q112133_001"))->Fill(cent, sampleIndex, fQ112133_001); + histos.get(HIST("Prof2D_Q112133_010"))->Fill(cent, sampleIndex, fQ112133_010); + histos.get(HIST("Prof2D_Q112133_100"))->Fill(cent, sampleIndex, fQ112133_100); + histos.get(HIST("Prof2D_Q112133_011"))->Fill(cent, sampleIndex, fQ112133_011); + histos.get(HIST("Prof2D_Q112133_101"))->Fill(cent, sampleIndex, fQ112133_101); + histos.get(HIST("Prof2D_Q112133_110"))->Fill(cent, sampleIndex, fQ112133_110); + histos.get(HIST("Prof2D_Q112132_001"))->Fill(cent, sampleIndex, fQ112132_001); + histos.get(HIST("Prof2D_Q112132_010"))->Fill(cent, sampleIndex, fQ112132_010); + histos.get(HIST("Prof2D_Q112132_100"))->Fill(cent, sampleIndex, fQ112132_100); + histos.get(HIST("Prof2D_Q112132_011"))->Fill(cent, sampleIndex, fQ112132_011); + histos.get(HIST("Prof2D_Q112132_101"))->Fill(cent, sampleIndex, fQ112132_101); + histos.get(HIST("Prof2D_Q112132_110"))->Fill(cent, sampleIndex, fQ112132_110); + histos.get(HIST("Prof2D_Q112131_001"))->Fill(cent, sampleIndex, fQ112131_001); + histos.get(HIST("Prof2D_Q112131_010"))->Fill(cent, sampleIndex, fQ112131_010); + histos.get(HIST("Prof2D_Q112131_100"))->Fill(cent, sampleIndex, fQ112131_100); + histos.get(HIST("Prof2D_Q112131_011"))->Fill(cent, sampleIndex, fQ112131_011); + histos.get(HIST("Prof2D_Q112131_101"))->Fill(cent, sampleIndex, fQ112131_101); + histos.get(HIST("Prof2D_Q112131_110"))->Fill(cent, sampleIndex, fQ112131_110); + histos.get(HIST("Prof2D_Q2221_11"))->Fill(cent, sampleIndex, fQ2221_11); + histos.get(HIST("Prof2D_Q2221_01"))->Fill(cent, sampleIndex, fQ2221_01); + histos.get(HIST("Prof2D_Q2221_10"))->Fill(cent, sampleIndex, fQ2221_10); + histos.get(HIST("Prof2D_Q2221_21"))->Fill(cent, sampleIndex, fQ2221_21); + histos.get(HIST("Prof2D_Q2221_20"))->Fill(cent, sampleIndex, fQ2221_20); + histos.get(HIST("Prof2D_Q2122_21"))->Fill(cent, sampleIndex, fQ2122_21); + histos.get(HIST("Prof2D_Q2122_20"))->Fill(cent, sampleIndex, fQ2122_20); + histos.get(HIST("Prof2D_Q1121_02"))->Fill(cent, sampleIndex, fQ1121_02); + histos.get(HIST("Prof2D_Q1121_12"))->Fill(cent, sampleIndex, fQ1121_12); + histos.get(HIST("Prof2D_Q1121_22"))->Fill(cent, sampleIndex, fQ1121_22); + histos.get(HIST("Prof2D_Q1122_02"))->Fill(cent, sampleIndex, fQ1122_02); + histos.get(HIST("Prof2D_Q1122_12"))->Fill(cent, sampleIndex, fQ1122_12); + histos.get(HIST("Prof2D_Q1122_22"))->Fill(cent, sampleIndex, fQ1122_22); + histos.get(HIST("Prof2D_Q112221_001"))->Fill(cent, sampleIndex, fQ112221_001); + histos.get(HIST("Prof2D_Q112221_010"))->Fill(cent, sampleIndex, fQ112221_010); + histos.get(HIST("Prof2D_Q112221_100"))->Fill(cent, sampleIndex, fQ112221_100); + histos.get(HIST("Prof2D_Q112221_011"))->Fill(cent, sampleIndex, fQ112221_011); + histos.get(HIST("Prof2D_Q112221_101"))->Fill(cent, sampleIndex, fQ112221_101); + histos.get(HIST("Prof2D_Q112221_110"))->Fill(cent, sampleIndex, fQ112221_110); + histos.get(HIST("Prof2D_Q112221_200"))->Fill(cent, sampleIndex, fQ112221_200); + histos.get(HIST("Prof2D_Q112221_201"))->Fill(cent, sampleIndex, fQ112221_201); + histos.get(HIST("Prof2D_Q112221_210"))->Fill(cent, sampleIndex, fQ112221_210); + histos.get(HIST("Prof2D_Q112221_211"))->Fill(cent, sampleIndex, fQ112221_211); + histos.get(HIST("Prof2D_Q1131_21"))->Fill(cent, sampleIndex, fQ1131_21); + histos.get(HIST("Prof2D_Q1131_20"))->Fill(cent, sampleIndex, fQ1131_20); + histos.get(HIST("Prof2D_Q1131_31"))->Fill(cent, sampleIndex, fQ1131_31); + histos.get(HIST("Prof2D_Q1131_30"))->Fill(cent, sampleIndex, fQ1131_30); + histos.get(HIST("Prof2D_Q1132_21"))->Fill(cent, sampleIndex, fQ1132_21); + histos.get(HIST("Prof2D_Q1132_20"))->Fill(cent, sampleIndex, fQ1132_20); + histos.get(HIST("Prof2D_Q1132_31"))->Fill(cent, sampleIndex, fQ1132_31); + histos.get(HIST("Prof2D_Q1132_30"))->Fill(cent, sampleIndex, fQ1132_30); + histos.get(HIST("Prof2D_Q1133_21"))->Fill(cent, sampleIndex, fQ1133_21); + histos.get(HIST("Prof2D_Q1133_20"))->Fill(cent, sampleIndex, fQ1133_20); + histos.get(HIST("Prof2D_Q1133_31"))->Fill(cent, sampleIndex, fQ1133_31); + histos.get(HIST("Prof2D_Q1133_30"))->Fill(cent, sampleIndex, fQ1133_30); + histos.get(HIST("Prof2D_Q11_5"))->Fill(cent, sampleIndex, fQ11_5); + histos.get(HIST("Prof2D_Q11_6"))->Fill(cent, sampleIndex, fQ11_6); + histos.get(HIST("Prof2D_Q1121_30"))->Fill(cent, sampleIndex, fQ1121_30); + histos.get(HIST("Prof2D_Q1121_31"))->Fill(cent, sampleIndex, fQ1121_31); + histos.get(HIST("Prof2D_Q1121_40"))->Fill(cent, sampleIndex, fQ1121_40); + histos.get(HIST("Prof2D_Q1121_41"))->Fill(cent, sampleIndex, fQ1121_41); + histos.get(HIST("Prof2D_Q1122_30"))->Fill(cent, sampleIndex, fQ1122_30); + histos.get(HIST("Prof2D_Q1122_31"))->Fill(cent, sampleIndex, fQ1122_31); + histos.get(HIST("Prof2D_Q1122_40"))->Fill(cent, sampleIndex, fQ1122_40); + histos.get(HIST("Prof2D_Q1122_41"))->Fill(cent, sampleIndex, fQ1122_41); + histos.get(HIST("Prof2D_Q2211_11"))->Fill(cent, sampleIndex, fQ2211_11); + histos.get(HIST("Prof2D_Q2211_01"))->Fill(cent, sampleIndex, fQ2211_01); + histos.get(HIST("Prof2D_Q2211_10"))->Fill(cent, sampleIndex, fQ2211_10); + histos.get(HIST("Prof2D_Q2211_20"))->Fill(cent, sampleIndex, fQ2211_20); + histos.get(HIST("Prof2D_Q2211_21"))->Fill(cent, sampleIndex, fQ2211_21); + histos.get(HIST("Prof2D_Q2111_11"))->Fill(cent, sampleIndex, fQ2111_11); + histos.get(HIST("Prof2D_Q2111_01"))->Fill(cent, sampleIndex, fQ2111_01); + histos.get(HIST("Prof2D_Q2111_10"))->Fill(cent, sampleIndex, fQ2111_10); + histos.get(HIST("Prof2D_Q2111_20"))->Fill(cent, sampleIndex, fQ2111_20); + histos.get(HIST("Prof2D_Q2111_21"))->Fill(cent, sampleIndex, fQ2111_21); + histos.get(HIST("Prof2D_Q112122_001"))->Fill(cent, sampleIndex, fQ112122_001); + histos.get(HIST("Prof2D_Q112122_010"))->Fill(cent, sampleIndex, fQ112122_010); + histos.get(HIST("Prof2D_Q112122_100"))->Fill(cent, sampleIndex, fQ112122_100); + histos.get(HIST("Prof2D_Q112122_011"))->Fill(cent, sampleIndex, fQ112122_011); + histos.get(HIST("Prof2D_Q112122_101"))->Fill(cent, sampleIndex, fQ112122_101); + histos.get(HIST("Prof2D_Q112122_110"))->Fill(cent, sampleIndex, fQ112122_110); + histos.get(HIST("Prof2D_Q1141_11"))->Fill(cent, sampleIndex, fQ1141_11); + histos.get(HIST("Prof2D_Q1141_01"))->Fill(cent, sampleIndex, fQ1141_01); + histos.get(HIST("Prof2D_Q1141_10"))->Fill(cent, sampleIndex, fQ1141_10); + histos.get(HIST("Prof2D_Q1141_20"))->Fill(cent, sampleIndex, fQ1141_20); + histos.get(HIST("Prof2D_Q1141_21"))->Fill(cent, sampleIndex, fQ1141_21); + histos.get(HIST("Prof2D_Q1142_11"))->Fill(cent, sampleIndex, fQ1142_11); + histos.get(HIST("Prof2D_Q1142_01"))->Fill(cent, sampleIndex, fQ1142_01); + histos.get(HIST("Prof2D_Q1142_10"))->Fill(cent, sampleIndex, fQ1142_10); + histos.get(HIST("Prof2D_Q1142_20"))->Fill(cent, sampleIndex, fQ1142_20); + histos.get(HIST("Prof2D_Q1142_21"))->Fill(cent, sampleIndex, fQ1142_21); + histos.get(HIST("Prof2D_Q1143_11"))->Fill(cent, sampleIndex, fQ1143_11); + histos.get(HIST("Prof2D_Q1143_01"))->Fill(cent, sampleIndex, fQ1143_01); + histos.get(HIST("Prof2D_Q1143_10"))->Fill(cent, sampleIndex, fQ1143_10); + histos.get(HIST("Prof2D_Q1143_20"))->Fill(cent, sampleIndex, fQ1143_20); + histos.get(HIST("Prof2D_Q1143_21"))->Fill(cent, sampleIndex, fQ1143_21); + histos.get(HIST("Prof2D_Q1144_11"))->Fill(cent, sampleIndex, fQ1144_11); + histos.get(HIST("Prof2D_Q1144_01"))->Fill(cent, sampleIndex, fQ1144_01); + histos.get(HIST("Prof2D_Q1144_10"))->Fill(cent, sampleIndex, fQ1144_10); + histos.get(HIST("Prof2D_Q1144_20"))->Fill(cent, sampleIndex, fQ1144_20); + histos.get(HIST("Prof2D_Q1144_21"))->Fill(cent, sampleIndex, fQ1144_21); + histos.get(HIST("Prof2D_Q2131_11"))->Fill(cent, sampleIndex, fQ2131_11); + histos.get(HIST("Prof2D_Q2131_01"))->Fill(cent, sampleIndex, fQ2131_01); + histos.get(HIST("Prof2D_Q2131_10"))->Fill(cent, sampleIndex, fQ2131_10); + histos.get(HIST("Prof2D_Q2132_11"))->Fill(cent, sampleIndex, fQ2132_11); + histos.get(HIST("Prof2D_Q2132_01"))->Fill(cent, sampleIndex, fQ2132_01); + histos.get(HIST("Prof2D_Q2132_10"))->Fill(cent, sampleIndex, fQ2132_10); + histos.get(HIST("Prof2D_Q2133_11"))->Fill(cent, sampleIndex, fQ2133_11); + histos.get(HIST("Prof2D_Q2133_01"))->Fill(cent, sampleIndex, fQ2133_01); + histos.get(HIST("Prof2D_Q2133_10"))->Fill(cent, sampleIndex, fQ2133_10); + histos.get(HIST("Prof2D_Q2231_11"))->Fill(cent, sampleIndex, fQ2231_11); + histos.get(HIST("Prof2D_Q2231_01"))->Fill(cent, sampleIndex, fQ2231_01); + histos.get(HIST("Prof2D_Q2231_10"))->Fill(cent, sampleIndex, fQ2231_10); + histos.get(HIST("Prof2D_Q2232_11"))->Fill(cent, sampleIndex, fQ2232_11); + histos.get(HIST("Prof2D_Q2232_01"))->Fill(cent, sampleIndex, fQ2232_01); + histos.get(HIST("Prof2D_Q2232_10"))->Fill(cent, sampleIndex, fQ2232_10); + histos.get(HIST("Prof2D_Q2233_11"))->Fill(cent, sampleIndex, fQ2233_11); + histos.get(HIST("Prof2D_Q2233_01"))->Fill(cent, sampleIndex, fQ2233_01); + histos.get(HIST("Prof2D_Q2233_10"))->Fill(cent, sampleIndex, fQ2233_10); + histos.get(HIST("Prof2D_Q51_1"))->Fill(cent, sampleIndex, fQ51_1); + histos.get(HIST("Prof2D_Q52_1"))->Fill(cent, sampleIndex, fQ52_1); + histos.get(HIST("Prof2D_Q53_1"))->Fill(cent, sampleIndex, fQ53_1); + histos.get(HIST("Prof2D_Q54_1"))->Fill(cent, sampleIndex, fQ54_1); + histos.get(HIST("Prof2D_Q55_1"))->Fill(cent, sampleIndex, fQ55_1); + histos.get(HIST("Prof2D_Q21_3"))->Fill(cent, sampleIndex, fQ21_3); + histos.get(HIST("Prof2D_Q22_3"))->Fill(cent, sampleIndex, fQ22_3); + histos.get(HIST("Prof2D_Q31_2"))->Fill(cent, sampleIndex, fQ31_2); + histos.get(HIST("Prof2D_Q32_2"))->Fill(cent, sampleIndex, fQ32_2); + histos.get(HIST("Prof2D_Q33_2"))->Fill(cent, sampleIndex, fQ33_2); + histos.get(HIST("Prof2D_Q61_1"))->Fill(cent, sampleIndex, fQ61_1); + histos.get(HIST("Prof2D_Q62_1"))->Fill(cent, sampleIndex, fQ62_1); + histos.get(HIST("Prof2D_Q63_1"))->Fill(cent, sampleIndex, fQ63_1); + histos.get(HIST("Prof2D_Q64_1"))->Fill(cent, sampleIndex, fQ64_1); + histos.get(HIST("Prof2D_Q65_1"))->Fill(cent, sampleIndex, fQ65_1); + histos.get(HIST("Prof2D_Q66_1"))->Fill(cent, sampleIndex, fQ66_1); + histos.get(HIST("Prof2D_Q112122_111"))->Fill(cent, sampleIndex, fQ112122_111); + histos.get(HIST("Prof2D_Q112131_111"))->Fill(cent, sampleIndex, fQ112131_111); + histos.get(HIST("Prof2D_Q112132_111"))->Fill(cent, sampleIndex, fQ112132_111); + histos.get(HIST("Prof2D_Q112133_111"))->Fill(cent, sampleIndex, fQ112133_111); + histos.get(HIST("Prof2D_Q112231_111"))->Fill(cent, sampleIndex, fQ112231_111); + histos.get(HIST("Prof2D_Q112232_111"))->Fill(cent, sampleIndex, fQ112232_111); + histos.get(HIST("Prof2D_Q112233_111"))->Fill(cent, sampleIndex, fQ112233_111); + histos.get(HIST("Prof2D_Q112221_111"))->Fill(cent, sampleIndex, fQ112221_111); + } + } + PROCESS_SWITCH(AntiprotonCumulantsMc, processDataRec, "Process real data", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/PWGCF/EbyEFluctuations/Tasks/kaonIsospinFluctuations.cxx b/PWGCF/EbyEFluctuations/Tasks/kaonIsospinFluctuations.cxx new file mode 100644 index 00000000000..4170d078843 --- /dev/null +++ b/PWGCF/EbyEFluctuations/Tasks/kaonIsospinFluctuations.cxx @@ -0,0 +1,2553 @@ +// 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 kaonIsospinFluctuations.cxx +/// \brief Kaon Isospin fluctuations +/// +/// \author Rahul Verma (rahul.verma@iitb.ac.in) :: Sadhana Dash (sadhana@phy.iitb.ac.in) + +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" + +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" + +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "PWGLF/DataModel/mcCentrality.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; // for constants + +#define ID_BIT_PI 0 // Identificationi bits for PID checks +#define ID_BIT_KA 1 +#define ID_BIT_PR 2 +#define ID_BIT_EL 3 +#define ID_BIT_DE 4 + +#define BIT_IS_K0S 0 +#define BIT_IS_LAMBDA 1 +#define BIT_IS_ANTILAMBDA 2 + +// #define kPAIRBIT_ISLAMBDA + +#define BIT_POS_DAU_HAS_SAME_COLL 0 +#define BIT_NEG_DAU_HAS_SAME_COLL 1 +#define BIT_BOTH_DAU_HAS_SAME_COLL 2 + +#define BITSET(mask, ithBit) ((mask) |= (1 << (ithBit))) // avoid name bitset as std::bitset is already there +#define BITCHECK(mask, ithBit) ((mask) & (1 << (ithBit))) // bit check will return int value, not bool, use BITCHECK != 0 in Analysi + +struct KaonIsospinFluctuations { + // Hisogram registry: + HistogramRegistry recoV0s{"recoV0s", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry recoEvent{"recoEvent", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry recoK0s{"recoK0s", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry recoTracks{"recoTracks", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry recoAnalysis{"recoAnalysis", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry genAnalysis{"genAnalysis", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // PDG data base + Service pdgDB; + + // Configurables + // Event Selection + Configurable cutZvertex{"cutZvertex", 8.0f, "Accepted z-vertex range (cm)"}; + + // Configurable parameters for V0 selection + Configurable v0settingDcaPosToPV{"v0settingDcaPosToPV", 0.06, "DCA Pos to PV"}; + Configurable v0settingDcaNegToPV{"v0settingDcaNegToPV", 0.06, "DCA Neg to PV"}; + Configurable v0settingDcaV0Dau{"v0settingDcaV0Dau", 1, "DCA V0 Daughters"}; + Configurable v0settingCosPA{"v0settingCosPA", 0.98, "V0 CosPA"}; + Configurable v0settingRadius{"v0settingRadius", 0.5, "v0radius"}; + + // Configurable K0s + struct : ConfigurableGroup { + Configurable cfgK0sMLow{"cfgK0sMLow", 0.48, "cfgK0sMLow"}; + Configurable cfgK0sMHigh{"cfgK0sMHigh", 0.515, "cfgK0sMHigh"}; + Configurable cfgK0sLowPt{"cfgK0sLowPt", 0.1, "cfgK0sLowPt"}; + Configurable cfgK0sHighPt{"cfgK0sHighPt", 1.5, "cfgK0sHighPt"}; + Configurable cfgK0sRapitidy{"cfgK0sRapitidy", 0.5, "cfgK0sRapitidy"}; + Configurable cfgK0sARMcut{"cfgK0sARMcut", 0.2, "cfgK0sARMcut"}; + } k0sSelCut; + + // Histogram Configurables + struct : ConfigurableGroup { + Configurable centBins{"centBins", 1020, "No of bins in centrality axis"}; + Configurable centBinsxLow{"centBinsxLow", -1.0, "centBinsxLow"}; + Configurable centBinsxUp{"centBinsxUp", 101.0, "centBinsxUp"}; + Configurable centAxisType{"centAxisType", 0, "centAxisType"}; + } cfgCentAxis; + // Track Configurables + struct : ConfigurableGroup { + Configurable cfgTrkTpcNClsCrossedRows{"cfgTrkTpcNClsCrossedRows", 70, "cfgTrkTpcNClsCrossedRows"}; + Configurable cfgTrkdcaXY{"cfgTrkdcaXY", 0.2, "cfgTrkdcaXY"}; + Configurable cfgDoVGselTrackCheck{"cfgDoVGselTrackCheck", false, "cfgDoVGselTrackCheck"}; + Configurable cfgTrackEta{"cfgTrackEta", 0.8, "cfgTrackEta"}; + Configurable cfgTrackPtLow{"cfgTrackPtLow", 0.15, "cfgTrackPtLow"}; + Configurable cfgTrackPtHigh{"cfgTrackPtHigh", 2.0, "cfgTrackPtHigh"}; + } cfgTrackCuts; + + // Configurables for particle Identification + Configurable cfgCheckVetoCut{"cfgCheckVetoCut", false, "cfgCheckVetoCut"}; + Configurable cfgDoElRejection{"cfgDoElRejection", true, "cfgDoElRejection"}; + Configurable cfgDoDeRejection{"cfgDoDeRejection", false, "cfgDoDeRejection"}; + Configurable cfgDoPdependentId{"cfgDoPdependentId", true, "cfgDoPdependentId"}; + Configurable cfgDoTpcInnerParamId{"cfgDoTpcInnerParamId", false, "cfgDoTpcInnerParamId"}; + + Configurable cfgPiThrPforTOF{"cfgPiThrPforTOF", 0.7, "cfgPiThrPforTOF"}; + Configurable cfgPiIdCutTypeLowP{"cfgPiIdCutTypeLowP", 0, "cfgPiIdCutTypeLowP"}; + Configurable cfgPiNSigmaTPCLowP{"cfgPiNSigmaTPCLowP", 3.0, "cfgPiNSigmaTPCLowP"}; + Configurable cfgPiNSigmaTOFLowP{"cfgPiNSigmaTOFLowP", 3.0, "cfgPiNSigmaTOFLowP"}; + Configurable cfgPiNSigmaRadLowP{"cfgPiNSigmaRadLowP", 9.0, "cfgPiNSigmaRadLowP"}; + Configurable cfgPiIdCutTypeHighP{"cfgPiIdCutTypeHighP", 0, "cfgPiIdCutTypeHighP"}; + Configurable cfgPiNSigmaTPCHighP{"cfgPiNSigmaTPCHighP", 3.0, "cfgPiNSigmaTPCHighP"}; + Configurable cfgPiNSigmaTOFHighP{"cfgPiNSigmaTOFHighP", 3.0, "cfgPiNSigmaTOFHighP"}; + Configurable cfgPiNSigmaRadHighP{"cfgPiNSigmaRadHighP", 9.0, "cfgPiNSigmaRadHighP"}; + + Configurable cfgKaThrPforTOF{"cfgKaThrPforTOF", 0.8, "cfgKaThrPforTOF"}; + Configurable cfgKaIdCutTypeLowP{"cfgKaIdCutTypeLowP", 0, "cfgKaIdCutTypeLowP"}; + Configurable cfgKaNSigmaTPCLowP{"cfgKaNSigmaTPCLowP", 3.0, "cfgKaNSigmaTPCLowP"}; + Configurable cfgKaNSigmaTOFLowP{"cfgKaNSigmaTOFLowP", 3.0, "cfgKaNSigmaTOFLowP"}; + Configurable cfgKaNSigmaRadLowP{"cfgKaNSigmaRadLowP", 9.0, "cfgKaNSigmaRadLowP"}; + Configurable cfgKaIdCutTypeHighP{"cfgKaIdCutTypeHighP", 0, "cfgKaIdCutTypeHighP"}; + Configurable cfgKaNSigmaTPCHighP{"cfgKaNSigmaTPCHighP", 3.0, "cfgKaNSigmaTPCHighP"}; + Configurable cfgKaNSigmaTOFHighP{"cfgKaNSigmaTOFHighP", 3.0, "cfgKaNSigmaTOFHighP"}; + Configurable cfgKaNSigmaRadHighP{"cfgKaNSigmaRadHighP", 9.0, "cfgKaNSigmaRadHighP"}; + + Configurable cfgPrThrPforTOF{"cfgPrThrPforTOF", 0.8, "cfgPrThrPforTOF"}; + Configurable cfgPrIdCutTypeLowP{"cfgPrIdCutTypeLowP", 0, "cfgPrIdCutTypeLowP"}; + Configurable cfgPrNSigmaTPCLowP{"cfgPrNSigmaTPCLowP", 3.0, "cfgPrNSigmaTPCLowP"}; + Configurable cfgPrNSigmaTOFLowP{"cfgPrNSigmaTOFLowP", 3.0, "cfgPrNSigmaTOFLowP"}; + Configurable cfgPrNSigmaRadLowP{"cfgPrNSigmaRadLowP", 9.0, "cfgPrNSigmaRadLowP"}; + Configurable cfgPrIdCutTypeHighP{"cfgPrIdCutTypeHighP", 0, "cfgPrIdCutTypeHighP"}; + Configurable cfgPrNSigmaTPCHighP{"cfgPrNSigmaTPCHighP", 3.0, "cfgPrNSigmaTPCHighP"}; + Configurable cfgPrNSigmaTOFHighP{"cfgPrNSigmaTOFHighP", 3.0, "cfgPrNSigmaTOFHighP"}; + Configurable cfgPrNSigmaRadHighP{"cfgPrNSigmaRadHighP", 9.0, "cfgPrNSigmaRadHighP"}; + + // configurable for process functions to reduce memory usage + Configurable cfgFillV0TableFull{"cfgFillV0TableFull", true, "cfgFillV0TableFull"}; + Configurable cfgFillV0TablePostK0sCheck{"cfgFillV0TablePostK0sCheck", false, "cfgFillV0TablePostK0sCheck"}; + Configurable cfgFillV0TablePostMassCut{"cfgFillV0TablePostMassCut", false, "cfgFillV0TablePostMassCut"}; + Configurable cfgFillV0TablePostSelectionCut{"cfgFillV0TablePostSelectionCut", true, "cfgFillV0TablePostSelectionCut"}; + + Configurable cfgFillRecoK0sPreSel{"cfgFillRecoK0sPreSel", false, "cfgFillRecoK0sPreSel"}; + Configurable cfgFillRecoK0sPostSel{"cfgFillRecoK0sPostSel", true, "cfgFillRecoK0sPostSel"}; + + Configurable cfgFillRecoTrackPreSel{"cfgFillRecoTrackPreSel", false, "cfgFillRecoTrackPreSel"}; + Configurable cfgFillRecoTrackPostSel{"cfgFillRecoTrackPostSel", true, "cfgFillRecoTrackPostSel"}; + + Configurable cfgFillPiQA{"cfgFillPiQA", true, "cfgFillPiQA"}; + Configurable cfgFillKaQA{"cfgFillKaQA", true, "cfgFillKaQA"}; + Configurable cfgFillPrQA{"cfgFillPrQA", true, "cfgFillPrQA"}; + Configurable cfgFillElQA{"cfgFillElQA", true, "cfgFillElQA"}; + Configurable cfgFillDeQA{"cfgFillDeQA", true, "cfgFillDeQA"}; + + Configurable cfgFillSparseFullK0sPiKa{"cfgFillSparseFullK0sPiKa", true, "cfgFillSparseFullK0sPiKa"}; + Configurable cfgFillSparseFullK0sPrDe{"cfgFillSparseFullK0sPrDe", true, "cfgFillSparseFullK0sPrDe"}; + Configurable cfgFillSparseFullK0sKaEl{"cfgFillSparseFullK0sKaEl", false, "cfgFillSparseFullK0sKaEl"}; + Configurable cfgFillSparseFullPiKaPr{"cfgFillSparseFullPiKaPr", false, "cfgFillSparseFullPiKaPr"}; + Configurable cfgFillSparseFullPiElDe{"cfgFillSparseFullPiElDe", false, "cfgFillSparseFullPiElDe"}; + Configurable cfgFillSparseFullKaPrDe{"cfgFillSparseFullKaPrDe", false, "cfgFillSparseFullKaPrDe"}; + Configurable cfgFillSparseFullPrElDe{"cfgFillSparseFullPrElDe", false, "cfgFillSparseFullPrElDe"}; + Configurable cfgFillSparsenewDynmK0sKa{"cfgFillSparsenewDynmK0sKa", true, "cfgFillSparsenewDynmK0sKa"}; + Configurable cfgFillSparsenewDynmKpKm{"cfgFillSparsenewDynmKpKm", true, "cfgFillSparsenewDynmKpKm"}; + + Configurable cfgVtxZCheck{"cfgVtxZCheck", 0, "cfgVtxZCheck"}; + Configurable cfgCountFinalParticles{"cfgCountFinalParticles", 1, "cfgCountFinalParticles"}; + Configurable cfgCountNonFinalParticles{"cfgCountNonFinalParticles", 0, "cfgCountNonFinalParticles"}; + Configurable cfgCountPhysicalPrimAndFinalParticles{"cfgCountPhysicalPrimAndFinalParticles", 0, "cfgCountPhysicalPrimAndFinalParticles"}; + Configurable doFWDPtDependentCheck{"doFWDPtDependentCheck", 1, "doFWDPtDependentCheck"}; + Configurable cfgFWDPtCut{"cfgFWDPtCut", 0.2, "cfgFWDPtCut"}; + Configurable> cfgFinalParticleIdList{"cfgFinalParticleIdList", {11, -11, 13, -13, 15, -15, 211, -211, 321, -321, 2212, -2212}, "cfgFinalParticleIdList"}; + Configurable> cfgNonFinalParticleIdList{"cfgNonFinalParticleIdList", {11, -11, 13, -13, 15, -15, 211, -211, 321, -321, 2212, -2212}, "cfgNonFinalParticleIdList"}; + + void init(InitContext const&) + { + // Axes + const AxisSpec axisK0sMass = {200, 0.40f, 0.60f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + const AxisSpec axisLambdaMass = {200, 1.f, 1.2f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + + const AxisSpec axisVertexZ = {30, -15., 15., "vrtx_{Z} [cm]"}; + AxisSpec axisCent = {cfgCentAxis.centBins, cfgCentAxis.centBinsxLow, cfgCentAxis.centBinsxUp, "centFT0C(percentile)"}; + if (cfgCentAxis.centAxisType == 1) { + axisCent = {cfgCentAxis.centBins, cfgCentAxis.centBinsxLow, cfgCentAxis.centBinsxUp, "centFT0M(percentile)"}; + } + if (cfgCentAxis.centAxisType == 2) { + axisCent = {cfgCentAxis.centBins, cfgCentAxis.centBinsxLow, cfgCentAxis.centBinsxUp, "multFT0M"}; + } + if (cfgCentAxis.centAxisType == 3) { + axisCent = {cfgCentAxis.centBins, cfgCentAxis.centBinsxLow, cfgCentAxis.centBinsxUp, "multFT0C"}; + } + + const AxisSpec axisP = {200, 0.0f, 10.0f, "#it{p} (GeV/#it{c})"}; + const AxisSpec axisPt = {200, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisTPCInnerParam = {200, 0.0f, 10.0f, "#it{p}_{tpcInnerParam} (GeV/#it{c})"}; + const AxisSpec axisTOFExpMom = {200, 0.0f, 10.0f, "#it{p}_{tofExpMom} (GeV/#it{c})"}; + + const AxisSpec axisEta = {100, -5, 5, "#eta"}; + const AxisSpec axisPhi = {90, -1, 8, "#phi (radians)"}; + const AxisSpec axisRapidity = {200, -5, 5, "Rapidity (y)"}; + const AxisSpec axisDcaXY = {100, -5, 5, "dcaXY"}; + const AxisSpec axisDcaZ = {100, -5, 5, "dcaZ"}; + const AxisSpec axisDcaXYwide = {2000, -100, 100, "dcaXY"}; + const AxisSpec axisDcaZwide = {2000, -100, 100, "dcaZ"}; + const AxisSpec axisSign = {10, -5, 5, "track.sign"}; + + const AxisSpec axisTPCSignal = {100, -1, 1000, "tpcSignal"}; + const AxisSpec axisTOFBeta = {40, -2.0, 2.0, "tofBeta"}; + + const AxisSpec axisTPCSignalFine = {10010, -1, 1000, "tpcSignal"}; + const AxisSpec axisTOFBetaFine = {10010, -1, 1000, "tpcSignal"}; + + const AxisSpec axisTPCNSigma = {200, -10.0, 10.0, "n#sigma_{TPC}"}; + const AxisSpec axisTOFNSigma = {200, -10.0, 10.0, "n#sigma_{TOF}"}; + + const AxisSpec axisTPCNSigmaPi = {200, -10.0, 10.0, "n#sigma_{TPC}^{Pi}"}; + const AxisSpec axisTOFNSigmaPi = {200, -10.0, 10.0, "n#sigma_{TOF}^{Pi}"}; + + const AxisSpec axisTPCNClsCrossedRows = {200, -1.5, 198.5, "tpcNClsCrossedRows"}; + const AxisSpec axisIsPVContributor = {4, -1, 3, "isPVContributor"}; + const AxisSpec axisIsGlobalTrack = {4, -1, 3, "isGobalTrack"}; + const AxisSpec axisIsK0sDau = {4, -1, 3, "isK0sDau"}; + + const AxisSpec axisDcapostopv = {100000, -50, 50, "dcapostopv"}; + const AxisSpec axisDcanegtopv = {100000, -50, 50, "dcanegtopv"}; + const AxisSpec axisDcaV0daughters = {2000, -10.0, 10.0, "dcaV0daughters"}; + const AxisSpec axisV0cosPA = {3000, -1.5, 1.5, "v0cosPA"}; + const AxisSpec axisV0radius = {100000, -50, 50, "v0radius"}; + + const AxisSpec axisParticleCount1 = {60, -10, 50, "particleCount"}; + const AxisSpec axisParticleCount2 = {260, -10, 250, "particleCount"}; + const AxisSpec axisParticleCount3 = {1060, -10, 1050, "particleCount"}; + + const AxisSpec axisArmenterosAlpha = {100, -1.0, 1.0, "ArmenterosAlpha"}; + const AxisSpec axisArmenterosQt = {150, 0, 0.3, "ArmenterosQt"}; + + HistogramConfigSpec histPDcaXY({HistType::kTH2F, {axisP, axisDcaXY}}); + HistogramConfigSpec histPtDcaXY({HistType::kTH2F, {axisPt, axisDcaXY}}); + HistogramConfigSpec histTpcInnerParamDcaXY({HistType::kTH2F, {axisTPCInnerParam, axisDcaXY}}); + HistogramConfigSpec histTofExpMomDcaXY({HistType::kTH2F, {axisTOFExpMom, axisDcaXY}}); + + HistogramConfigSpec histPDcaZ({HistType::kTH2F, {axisP, axisDcaZ}}); + HistogramConfigSpec histPtDcaZ({HistType::kTH2F, {axisPt, axisDcaZ}}); + HistogramConfigSpec histTpcInnerParamDcaZ({HistType::kTH2F, {axisTPCInnerParam, axisDcaZ}}); + HistogramConfigSpec histTofExpMomDcaZ({HistType::kTH2F, {axisTOFExpMom, axisDcaZ}}); + + HistogramConfigSpec histPPt({HistType::kTH2F, {axisP, axisPt}}); + HistogramConfigSpec histPTpcInnerParam({HistType::kTH2F, {axisP, axisTPCInnerParam}}); + HistogramConfigSpec histPTofExpMom({HistType::kTH2F, {axisP, axisTOFExpMom}}); + + HistogramConfigSpec histPTpcSignal({HistType::kTH2F, {axisP, axisTPCSignal}}); + HistogramConfigSpec histTpcInnerParamTpcSignal({HistType::kTH2F, {axisTPCInnerParam, axisTPCSignal}}); + HistogramConfigSpec histTofExpMomTpcSignal({HistType::kTH2F, {axisTOFExpMom, axisTPCSignal}}); + + HistogramConfigSpec histPBeta({HistType::kTH2F, {axisP, axisTOFBeta}}); + HistogramConfigSpec histTpcInnerParamBeta({HistType::kTH2F, {axisTPCInnerParam, axisTOFBeta}}); + HistogramConfigSpec histTofExpMomBeta({HistType::kTH2F, {axisTOFExpMom, axisTOFBeta}}); + + HistogramConfigSpec histPTpcNSigma({HistType::kTH2F, {axisP, axisTPCNSigma}}); + HistogramConfigSpec histPtTpcNSigma({HistType::kTH2F, {axisPt, axisTPCNSigma}}); + HistogramConfigSpec histTpcInnerParamTpcNSigma({HistType::kTH2F, {axisTPCInnerParam, axisTPCNSigma}}); + HistogramConfigSpec histTofExpMomTpcNSigma({HistType::kTH2F, {axisTOFExpMom, axisTPCNSigma}}); + HistogramConfigSpec histPTofNSigma({HistType::kTH2F, {axisP, axisTOFNSigma}}); + HistogramConfigSpec histPtTofNSigma({HistType::kTH2F, {axisPt, axisTOFNSigma}}); + HistogramConfigSpec histTpcInnerParamTofNSigma({HistType::kTH2F, {axisTPCInnerParam, axisTOFNSigma}}); + HistogramConfigSpec histTofExpMomTofNSigma({HistType::kTH2F, {axisTOFExpMom, axisTOFNSigma}}); + HistogramConfigSpec histTpcNSigmaTofNSigma({HistType::kTH2F, {axisTPCNSigma, axisTOFNSigma}}); + + recoV0s.add("v0Table/Full/h01_K0s_Mass", "K0s_Mass", {HistType::kTH1F, {axisK0sMass}}); + recoV0s.add("v0Table/Full/h02_Lambda_Mass", "Lambda_Mass", {HistType::kTH1F, {axisLambdaMass}}); + recoV0s.add("v0Table/Full/h03_AntiLambda_Mass", "AntiLambda_Mass", {HistType::kTH1F, {axisLambdaMass}}); + recoV0s.add("v0Table/Full/h04_v0DaughterCollisionIndexTag", "hV0s_K0s_v0DaughterCollisionIndexTag", {HistType::kTH1D, {{22, -1.0, 10.0}}}); + recoV0s.add("v0Table/Full/h05_V0Tag", "V0Tag", {HistType::kTH1F, {{12, -2, 10}}}); // 001 = Kaon, 010 = Lambda, 100 = AnitLambda + + // Topological Cuts + recoV0s.add("v0Table/Full/h06_dcapostopv", "dcapostopv", kTH1F, {axisDcapostopv}); + recoV0s.add("v0Table/Full/h07_dcanegtopv", "dcanegtopv", kTH1F, {axisDcanegtopv}); + recoV0s.add("v0Table/Full/h08_dcaV0daughters", "dcaV0daughters", kTH1F, {axisDcaV0daughters}); + recoV0s.add("v0Table/Full/h09_v0cosPA", "v0cosPA", kTH1F, {axisV0cosPA}); + recoV0s.add("v0Table/Full/h10_v0radius", "v0radius", kTH1F, {axisV0radius}); + + // K0s-FullInformation + recoV0s.add("v0Table/Full/h11_mass", "mass", kTH1F, {axisK0sMass}); + recoV0s.add("v0Table/Full/h12_p", "p", kTH1F, {axisP}); + recoV0s.add("v0Table/Full/h13_pt", "pt", kTH1F, {axisPt}); + recoV0s.add("v0Table/Full/h14_eta", "eta", kTH1F, {axisEta}); + recoV0s.add("v0Table/Full/h15_phi", "phi", kTH1F, {axisPhi}); + recoV0s.add("v0Table/Full/h16_rapidity", "rapidity", kTH1F, {axisRapidity}); + recoV0s.add("v0Table/Full/h17_alpha", "alpha", kTH1F, {axisArmenterosAlpha}); + recoV0s.add("v0Table/Full/h18_qtarm", "qtarm", kTH1F, {axisArmenterosQt}); + recoV0s.add("v0Table/Full/h19_alpha_qtarm", "alpha_qtarm", kTH2F, {axisArmenterosAlpha, axisArmenterosQt}); + recoV0s.add("v0Table/Full/h20_pt_eta", "pt_eta", kTH2F, {axisPt, axisEta}); + + // K0s-Daughter Info + recoV0s.add("v0Table/Full/Pi/tpcId/h01_p", "p", kTH1F, {axisP}); + recoV0s.add("v0Table/Full/Pi/tpcId/h02_pt", "pt", kTH1F, {axisPt}); + recoV0s.add("v0Table/Full/Pi/tpcId/h03_tpcInnerParam", "tpcInnerParam", kTH1F, {axisTPCInnerParam}); + recoV0s.add("v0Table/Full/Pi/tpcId/h04_tofExpMom", "tofExpMom", kTH1F, {axisTOFExpMom}); + recoV0s.add("v0Table/Full/Pi/tpcId/h05_eta", "eta", kTH1F, {axisEta}); + recoV0s.add("v0Table/Full/Pi/tpcId/h06_phi", "phi", kTH1F, {axisPhi}); + recoV0s.add("v0Table/Full/Pi/tpcId/h07_rapidity", "rapidity", kTH1F, {axisRapidity}); + recoV0s.add("v0Table/Full/Pi/tpcId/h08_isPVContributor", "isPVContributor", kTH1F, {axisIsPVContributor}); + recoV0s.add("v0Table/Full/Pi/tpcId/h09_isGlobalTrack", "isGlobalTrack", kTH1F, {axisIsGlobalTrack}); + recoV0s.add("v0Table/Full/Pi/tpcId/h10_dcaXY", "dcaXY", kTH1F, {axisDcaXY}); + recoV0s.add("v0Table/Full/Pi/tpcId/h11_dcaZ", "dcaZ", kTH1F, {axisDcaZ}); + + recoV0s.add("v0Table/Full/Pi/tpcId/h12_p_dcaXY", "p_dcaXY", kTH2F, {axisP, axisDcaXY}); + recoV0s.add("v0Table/Full/Pi/tpcId/h13_p_dcaZ", "p_dcaZ", kTH2F, {axisP, axisDcaZ}); + recoV0s.add("v0Table/Full/Pi/tpcId/h14_pt_dcaXY", "pt_dcaXY", kTH2F, {axisP, axisDcaXY}); + recoV0s.add("v0Table/Full/Pi/tpcId/h15_pt_dcaZ", "pt_dcaZ", kTH2F, {axisP, axisDcaZ}); + recoV0s.add("v0Table/Full/Pi/tpcId/h16_dcaXYwide", "dcaXYwide", kTH1F, {axisDcaXYwide}); + recoV0s.add("v0Table/Full/Pi/tpcId/h17_dcaZwide", "dcaZwide", kTH1F, {axisDcaZwide}); + recoV0s.add("v0Table/Full/Pi/tpcId/h20_pt_eta", "pt_eta", kTH2F, {axisPt, axisEta}); + // K0s-Daughter identification + // momemtum + recoV0s.add("v0Table/Full/Pi/tpcId/h20_p_pt", "p_pt", histPPt); + recoV0s.add("v0Table/Full/Pi/tpcId/h21_p_tpcInnerParam", "p_tpcInnerParam", histPTpcInnerParam); + recoV0s.add("v0Table/Full/Pi/tpcId/h22_p_tofExpMom", "p_tofExpMom", histPTofExpMom); + // tpcSignal + recoV0s.add("v0Table/Full/Pi/tpcId/h23_p_tpcSignal", "p_tpcSignal", histPTpcSignal); + recoV0s.add("v0Table/Full/Pi/tpcId/h24_tpcInnerParam_tpcSignal", "tpcInnerParam_tpcSignal", histTpcInnerParamTpcSignal); + recoV0s.add("v0Table/Full/Pi/tpcId/h25_tofExpMom_tpcSignal", "tofExpMom_tpcSignal", histTofExpMomTpcSignal); + // tofBeta + recoV0s.add("v0Table/Full/Pi/tpcId/h26_p_beta", "p_beta", histPBeta); + recoV0s.add("v0Table/Full/Pi/tpcId/h27_tpcInnerParam_beta", "tpcInnerParam_beta", histTpcInnerParamBeta); + recoV0s.add("v0Table/Full/Pi/tpcId/h28_tofExpMom_beta", "tofExpMom_beta", histTofExpMomBeta); + // Look at Pion + recoV0s.add("v0Table/Full/Pi/tpcId/h29_p_tpcNSigma", "p_tpcNSigma", histPTpcNSigma); + recoV0s.add("v0Table/Full/Pi/tpcId/h30_pt_tpcNSigma", "pt_tpcNSigma", histPtTpcNSigma); + recoV0s.add("v0Table/Full/Pi/tpcId/h31_tpcInnerParam_tpcNSigma", "tpcInnerParam_tpcNSigma", histTpcInnerParamTpcNSigma); + recoV0s.add("v0Table/Full/Pi/tpcId/h32_tofExpMom_tpcNSigma", "tofExpMom_tpcNSigma", histTofExpMomTpcNSigma); + recoV0s.add("v0Table/Full/Pi/tpcId/h33_p_tofNSigma", "p_tofNSigma", histPTofNSigma); + recoV0s.add("v0Table/Full/Pi/tpcId/h34_pt_tofNSigma", "pt_tofNSigma", histPtTofNSigma); + recoV0s.add("v0Table/Full/Pi/tpcId/h35_tpcInnerParam_tofNSigma", "tpcInnerParam_tofNSigma", histTpcInnerParamTofNSigma); + recoV0s.add("v0Table/Full/Pi/tpcId/h36_tofExpMom_tofNSigma", "tofExpMom_tofNSigma", histTofExpMomTofNSigma); + recoV0s.add("v0Table/Full/Pi/tpcId/h37_tpcNSigma_tofNSigma", "tpcNSigma_tofNSigma", histTpcNSigmaTofNSigma); + + recoV0s.addClone("v0Table/Full/Pi/tpcId/", "v0Table/Full/Pi/tpctofId/"); // for identification using tof+tpc + recoV0s.addClone("v0Table/Full/Pi/tpcId/", "v0Table/Full/Pi/NoId/"); // for unidentified case // to observe and debug + + if (cfgFillV0TablePostK0sCheck) { + recoV0s.addClone("v0Table/Full/", "v0Table/postK0sCheck/"); + } + if (cfgFillV0TablePostMassCut) { + recoV0s.addClone("v0Table/Full/", "v0Table/postMassCut/"); + } + if (cfgFillV0TablePostSelectionCut) { + recoV0s.addClone("v0Table/Full/", "v0Table/postSelectionCut/"); + } + + recoV0s.add("v0Table/postSelectionCut/hTrueV0TagCount", "hTrueV0TagCount", {HistType::kTH1F, {{12, -2, 10}}}); // 001 = Kaon, 010 = Lambda, 100 = AnitLambda + recoV0s.add("v0Table/postSelectionCut/nCommonPionOfDifferentK0s", "nCommonPionOfDifferentK0s", {HistType::kTH1D, {{44, -2, 20}}}); + + // Event Selection + recoEvent.add("recoEvent/ProcessType", "ProcessType", {HistType::kTH1D, {{20, -1, 9}}}); + recoEvent.add("recoEvent/h01_CollisionCount", "CollisionCount", {HistType::kTH1D, {{1, 0, 1}}}); + recoEvent.add("recoEvent/h02_VertexXRec", "VertexXRec", {HistType::kTH1D, {{1000, -0.2, 0.2}}}); + recoEvent.add("recoEvent/h03_VertexYRec", "VertexYRec", {HistType::kTH1D, {{1000, -0.2, 0.2}}}); + recoEvent.add("recoEvent/h04_VertexZRec", "VertexZRec", {HistType::kTH1F, {axisVertexZ}}); + recoEvent.add("recoEvent/h05_Centrality", "Centrality", {HistType::kTH1F, {axisCent}}); + recoEvent.add("recoEvent/h06_V0Size", "V0Size", {HistType::kTH1F, {{60, -10, 50}}}); + recoEvent.add("recoEvent/h07_TracksSize", "TracksSize", {HistType::kTH1F, {axisParticleCount2}}); + recoEvent.add("recoEvent/h08_nTrack", "nTrack", {HistType::kTH1F, {axisParticleCount2}}); + recoEvent.add("recoEvent/h09_nK0s", "nK0s", {HistType::kTH1F, {axisParticleCount1}}); + recoEvent.add("recoEvent/h10_nPiPlus", "nPiPlus", {HistType::kTH1F, {axisParticleCount2}}); + recoEvent.add("recoEvent/h11_nPiMinus", "nPiMinus", {HistType::kTH1F, {axisParticleCount2}}); + recoEvent.add("recoEvent/h12_nKaPlus", "nKaPlus", {HistType::kTH1F, {axisParticleCount1}}); + recoEvent.add("recoEvent/h13_nKaMinus", "nKaMinus", {HistType::kTH1F, {axisParticleCount1}}); + recoEvent.add("recoEvent/h14_nProton", "nProton", {HistType::kTH1F, {axisParticleCount1}}); + recoEvent.add("recoEvent/h15_nPBar", "nPBar", {HistType::kTH1F, {axisParticleCount1}}); + recoEvent.add("recoEvent/h16_nElPlus", "nElPlus", {HistType::kTH1F, {axisParticleCount1}}); + recoEvent.add("recoEvent/h17_nElMinus", "nElMinus", {HistType::kTH1F, {axisParticleCount1}}); + recoEvent.add("recoEvent/h18_nDePlus", "nDePlus", {HistType::kTH1F, {axisParticleCount1}}); + recoEvent.add("recoEvent/h19_nDeMinus", "nDeMinus", {HistType::kTH1F, {axisParticleCount1}}); + + // + // K0s reconstruction + recoK0s.add("recoK0s/PreSel/h01_K0s_Mass", "K0s_Mass", {HistType::kTH1F, {axisK0sMass}}); + recoK0s.add("recoK0s/PreSel/h02_Lambda_Mass", "Lambda_Mass", {HistType::kTH1F, {axisLambdaMass}}); + recoK0s.add("recoK0s/PreSel/h03_AntiLambda_Mass", "AntiLambda_Mass", {HistType::kTH1F, {axisLambdaMass}}); + recoK0s.add("recoK0s/PreSel/h04_v0DaughterCollisionIndexTag", "hV0s_K0s_v0DaughterCollisionIndexTag", {HistType::kTH1D, {{22, -1.0, 10.0}}}); + recoK0s.add("recoK0s/PreSel/h05_V0Tag", "V0Tag", {HistType::kTH1F, {{12, -2, 10}}}); // 001 = Kaon, 010 = Lambda, 100 = AnitLambda + + // Topological Cuts + recoK0s.add("recoK0s/PreSel/h06_dcapostopv", "dcapostopv", kTH1F, {axisDcapostopv}); + recoK0s.add("recoK0s/PreSel/h07_dcanegtopv", "dcanegtopv", kTH1F, {axisDcanegtopv}); + recoK0s.add("recoK0s/PreSel/h08_dcaV0daughters", "dcaV0daughters", kTH1F, {axisDcaV0daughters}); + recoK0s.add("recoK0s/PreSel/h09_v0cosPA", "v0cosPA", kTH1F, {axisV0cosPA}); + recoK0s.add("recoK0s/PreSel/h10_v0radius", "v0radius", kTH1F, {axisV0radius}); + + // K0s-FullInformation + recoK0s.add("recoK0s/PreSel/h11_mass", "mass", kTH1F, {axisK0sMass}); + recoK0s.add("recoK0s/PreSel/h12_p", "p", kTH1F, {axisP}); + recoK0s.add("recoK0s/PreSel/h13_pt", "pt", kTH1F, {axisPt}); + recoK0s.add("recoK0s/PreSel/h14_eta", "eta", kTH1F, {axisEta}); + recoK0s.add("recoK0s/PreSel/h15_phi", "phi", kTH1F, {axisPhi}); + recoK0s.add("recoK0s/PreSel/h16_rapidity", "rapidity", kTH1F, {axisRapidity}); + recoK0s.add("recoK0s/PreSel/h17_alpha", "alpha", kTH1F, {axisArmenterosAlpha}); + recoK0s.add("recoK0s/PreSel/h18_qtarm", "qtarm", kTH1F, {axisArmenterosQt}); + recoK0s.add("recoK0s/PreSel/h19_alpha_qtarm", "alpha_qtarm", kTH2F, {axisArmenterosAlpha, axisArmenterosQt}); + recoK0s.add("recoK0s/PreSel/h20_pt_eta", "pt_eta", kTH2F, {axisPt, axisEta}); + + // K0s-Daughter Info + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h01_p", "p", kTH1F, {axisP}); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h02_pt", "pt", kTH1F, {axisPt}); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h03_tpcInnerParam", "tpcInnerParam", kTH1F, {axisTPCInnerParam}); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h04_tofExpMom", "tofExpMom", kTH1F, {axisTOFExpMom}); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h05_eta", "eta", kTH1F, {axisEta}); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h06_phi", "phi", kTH1F, {axisPhi}); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h07_rapidity", "rapidity", kTH1F, {axisRapidity}); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h08_isPVContributor", "isPVContributor", kTH1F, {axisIsPVContributor}); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h09_isGlobalTrack", "isGlobalTrack", kTH1F, {axisIsGlobalTrack}); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h10_dcaXY", "dcaXY", kTH1F, {axisDcaXY}); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h11_dcaZ", "dcaZ", kTH1F, {axisDcaZ}); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h12_p_dcaXY", "p_dcaXY", kTH2F, {axisP, axisDcaXY}); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h13_p_dcaZ", "p_dcaZ", kTH2F, {axisP, axisDcaZ}); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h14_pt_dcaXY", "pt_dcaXY", kTH2F, {axisP, axisDcaXY}); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h15_pt_dcaZ", "pt_dcaZ", kTH2F, {axisP, axisDcaZ}); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h16_dcaXYwide", "dcaXYwide", kTH1F, {axisDcaXYwide}); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h17_dcaZwide", "dcaZwide", kTH1F, {axisDcaZwide}); + + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h20_pt_eta", "pt_eta", kTH2F, {axisPt, axisEta}); + // K0s-Daughter identification + // momemtum + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h20_p_pt", "p_pt", histPPt); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h21_p_tpcInnerParam", "p_tpcInnerParam", histPTpcInnerParam); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h22_p_tofExpMom", "p_tofExpMom", histPTofExpMom); + // tpcSignal + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h23_p_tpcSignal", "p_tpcSignal", histPTpcSignal); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h24_tpcInnerParam_tpcSignal", "tpcInnerParam_tpcSignal", histTpcInnerParamTpcSignal); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h25_tofExpMom_tpcSignal", "tofExpMom_tpcSignal", histTofExpMomTpcSignal); + // tofBeta + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h26_p_beta", "p_beta", histPBeta); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h27_tpcInnerParam_beta", "tpcInnerParam_beta", histTpcInnerParamBeta); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h28_tofExpMom_beta", "tofExpMom_beta", histTofExpMomBeta); + // Look at Pion + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h29_p_tpcNSigma", "p_tpcNSigma", histPTpcNSigma); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h30_pt_tpcNSigma", "pt_tpcNSigma", histPtTpcNSigma); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h31_tpcInnerParam_tpcNSigma", "tpcInnerParam_tpcNSigma", histTpcInnerParamTpcNSigma); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h32_tofExpMom_tpcNSigma", "tofExpMom_tpcNSigma", histTofExpMomTpcNSigma); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h33_p_tofNSigma", "p_tofNSigma", histPTofNSigma); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h34_pt_tofNSigma", "pt_tofNSigma", histPtTofNSigma); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h35_tpcInnerParam_tofNSigma", "tpcInnerParam_tofNSigma", histTpcInnerParamTofNSigma); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h36_tofExpMom_tofNSigma", "tofExpMom_tofNSigma", histTofExpMomTofNSigma); + recoK0s.add("recoK0s/PreSel/Pi/tpcId/h37_tpcNSigma_tofNSigma", "tpcNSigma_tofNSigma", histTpcNSigmaTofNSigma); + + recoK0s.addClone("recoK0s/PreSel/Pi/tpcId/", "recoK0s/PreSel/Pi/tpctofId/"); // for identification using tof+tpc + recoK0s.addClone("recoK0s/PreSel/Pi/tpcId/", "recoK0s/PreSel/Pi/NoId/"); // for unidentified case // to observe and debug + + recoK0s.addClone("recoK0s/PreSel/", "recoK0s/PostSel/"); // for unidentified case // to observe and debug + + recoK0s.add("recoK0s/PostSel/mK0s_vs_cent", "mK0s_vs_cent", kTH2F, {axisCent, axisK0sMass}); + + // Tracks reconstruction + // FullTrack + recoTracks.add("recoTracks/PreSel/h01_p", "p", {HistType::kTH1F, {axisP}}); + recoTracks.add("recoTracks/PreSel/h02_pt", "pt", {HistType::kTH1F, {axisPt}}); + recoTracks.add("recoTracks/PreSel/h03_tpcInnerParam", "tpcInnerParam", {HistType::kTH1F, {axisTPCInnerParam}}); + recoTracks.add("recoTracks/PreSel/h04_tofExpMom", "tofExpMom", {HistType::kTH1F, {axisTOFExpMom}}); + recoTracks.add("recoTracks/PreSel/h05_eta", "eta", {HistType::kTH1F, {axisEta}}); + recoTracks.add("recoTracks/PreSel/h06_phi", "phi", {HistType::kTH1F, {axisPhi}}); + recoTracks.add("recoTracks/PreSel/h07_dcaXY", "dcaXY", {HistType::kTH1F, {axisDcaXY}}); + recoTracks.add("recoTracks/PreSel/h08_dcaZ", "dcaZ", {HistType::kTH1F, {axisDcaZ}}); + recoTracks.add("recoTracks/PreSel/h09_sign", "sign", {HistType::kTH1D, {axisSign}}); + + // DcaXY + recoTracks.add("recoTracks/PreSel/h10_p_dcaXY", "p_dcaXY", histPDcaXY); + recoTracks.add("recoTracks/PreSel/h11_pt_dcaXY", "pt_dcaXY", histPtDcaXY); + recoTracks.add("recoTracks/PreSel/h12_tpcInnerParam_dcaXY", "tpcInnerParam_dcaXY", histTpcInnerParamDcaXY); + recoTracks.add("recoTracks/PreSel/h13_tofExpMom_dcaXY", "tofExpMom_dcaXY", histTofExpMomDcaXY); + + // DcaZ + recoTracks.add("recoTracks/PreSel/h14_p_dcaZ", "p_dcaZ", histPDcaZ); + recoTracks.add("recoTracks/PreSel/h15_pt_dcaZ", "pt_dcaZ", histPtDcaZ); + recoTracks.add("recoTracks/PreSel/h16_tpcInnerParam_dcaZ", "tpcInnerParam_dcaZ", histTpcInnerParamDcaZ); + recoTracks.add("recoTracks/PreSel/h17_tofExpMom_dcaZ", "tofExpMom_dcaZ", histTofExpMomDcaZ); + + recoTracks.add("recoTracks/PreSel/h20_pt_eta", "pt_eta", kTH2F, {axisPt, axisEta}); + // momemtum + recoTracks.add("recoTracks/PreSel/h20_p_pt", "p_pt", histPPt); + recoTracks.add("recoTracks/PreSel/h21_p_tpcInnerParam", "p_tpcInnerParam", histPTpcInnerParam); + recoTracks.add("recoTracks/PreSel/h22_p_tofExpMom", "p_tofExpMom", histPTofExpMom); + + // tpcSignal + recoTracks.add("recoTracks/PreSel/h23_p_tpcSignal", "p_tpcSignal", histPTpcSignal); + recoTracks.add("recoTracks/PreSel/h24_tpcInnerParam_tpcSignal", "tpcInnerParam_tpcSignal", histTpcInnerParamTpcSignal); + recoTracks.add("recoTracks/PreSel/h25_tofExpMom_tpcSignal", "tofExpMom_tpcSignal", histTofExpMomTpcSignal); + + // tofBeta + recoTracks.add("recoTracks/PreSel/h26_p_beta", "p_beta", histPBeta); + recoTracks.add("recoTracks/PreSel/h27_tpcInnerParam_beta", "tpcInnerParam_beta", histTpcInnerParamBeta); + recoTracks.add("recoTracks/PreSel/h28_tofExpMom_beta", "tofExpMom_beta", histTofExpMomBeta); + + // Look at Pion + recoTracks.add("recoTracks/PreSel/Pi/NoId/h29_p_tpcNSigma", "p_tpcNSigma", histPTpcNSigma); + recoTracks.add("recoTracks/PreSel/Pi/NoId/h30_pt_tpcNSigma", "pt_tpcNSigma", histPtTpcNSigma); + recoTracks.add("recoTracks/PreSel/Pi/NoId/h31_tpcInnerParam_tpcNSigma", "tpcInnerParam_tpcNSigma", histTpcInnerParamTpcNSigma); + recoTracks.add("recoTracks/PreSel/Pi/NoId/h32_tofExpMom_tpcNSigma", "tofExpMom_tpcNSigma", histTofExpMomTpcNSigma); + recoTracks.add("recoTracks/PreSel/Pi/NoId/h33_p_tofNSigma", "p_tofNSigma", histPTofNSigma); + recoTracks.add("recoTracks/PreSel/Pi/NoId/h34_pt_tofNSigma", "pt_tofNSigma", histPtTofNSigma); + recoTracks.add("recoTracks/PreSel/Pi/NoId/h35_tpcInnerParam_tofNSigma", "tpcInnerParam_tofNSigma", histTpcInnerParamTofNSigma); + recoTracks.add("recoTracks/PreSel/Pi/NoId/h36_tofExpMom_tofNSigma", "tofExpMom_tofNSigma", histTofExpMomTofNSigma); + recoTracks.add("recoTracks/PreSel/Pi/NoId/h37_tpcNSigma_tofNSigma", "tpcNSigma_tofNSigma", histTpcNSigmaTofNSigma); + // Pion + + recoTracks.addClone("recoTracks/PreSel/Pi/", "recoTracks/PreSel/Ka/"); // Kaon + recoTracks.addClone("recoTracks/PreSel/Pi/", "recoTracks/PreSel/Pr/"); // Proton + recoTracks.addClone("recoTracks/PreSel/Pi/", "recoTracks/PreSel/El/"); // Electron + recoTracks.addClone("recoTracks/PreSel/Pi/", "recoTracks/PreSel/De/"); // Deuteron + + // Write Code for naming the axis for Identified Particles + + // Selection + recoTracks.addClone("recoTracks/PreSel/", "recoTracks/PostSel/"); + // + + // Analysis + recoAnalysis.add("recoAnalysis/Pi/tpcId/h20_pt_eta", "pt_eta", kTH2F, {axisPt, axisEta}); + // momemtum + recoAnalysis.add("recoAnalysis/Pi/tpcId/h20_p_pt", "p_pt", histPPt); + recoAnalysis.add("recoAnalysis/Pi/tpcId/h21_p_tpcInnerParam", "p_tpcInnerParam", histPTpcInnerParam); + recoAnalysis.add("recoAnalysis/Pi/tpcId/h22_p_tofExpMom", "p_tofExpMom", histPTofExpMom); + // tpcSignal + recoAnalysis.add("recoAnalysis/Pi/tpcId/h23_p_tpcSignal", "p_tpcSignal", histPTpcSignal); + recoAnalysis.add("recoAnalysis/Pi/tpcId/h24_tpcInnerParam_tpcSignal", "tpcInnerParam_tpcSignal", histTpcInnerParamTpcSignal); + recoAnalysis.add("recoAnalysis/Pi/tpcId/h25_tofExpMom_tpcSignal", "tofExpMom_tpcSignal", histTofExpMomTpcSignal); + // tofBeta + recoAnalysis.add("recoAnalysis/Pi/tpcId/h26_p_beta", "p_beta", histPBeta); + recoAnalysis.add("recoAnalysis/Pi/tpcId/h27_tpcInnerParam_beta", "tpcInnerParam_beta", histTpcInnerParamBeta); + recoAnalysis.add("recoAnalysis/Pi/tpcId/h28_tofExpMom_beta", "tofExpMom_beta", histTofExpMomBeta); + // Pion + recoAnalysis.add("recoAnalysis/Pi/tpcId/h29_p_tpcNSigma", "p_tpcNSigma", histPTpcNSigma); + recoAnalysis.add("recoAnalysis/Pi/tpcId/h30_pt_tpcNSigma", "pt_tpcNSigma", histPtTpcNSigma); + recoAnalysis.add("recoAnalysis/Pi/tpcId/h31_tpcInnerParam_tpcNSigma", "tpcInnerParam_tpcNSigma", histTpcInnerParamTpcNSigma); + recoAnalysis.add("recoAnalysis/Pi/tpcId/h32_tofExpMom_tpcNSigma", "tofExpMom_tpcNSigma", histTofExpMomTpcNSigma); + recoAnalysis.add("recoAnalysis/Pi/tpcId/h33_p_tofNSigma", "p_tofNSigma", histPTofNSigma); + recoAnalysis.add("recoAnalysis/Pi/tpcId/h34_pt_tofNSigma", "pt_tofNSigma", histPtTofNSigma); + recoAnalysis.add("recoAnalysis/Pi/tpcId/h35_tpcInnerParam_tofNSigma", "tpcInnerParam_tofNSigma", histTpcInnerParamTofNSigma); + recoAnalysis.add("recoAnalysis/Pi/tpcId/h36_tofExpMom_tofNSigma", "tofExpMom_tofNSigma", histTofExpMomTofNSigma); + recoAnalysis.add("recoAnalysis/Pi/tpcId/h37_tpcNSigma_tofNSigma", "tpcNSigma_tofNSigma", histTpcNSigmaTofNSigma); + + recoAnalysis.addClone("recoAnalysis/Pi/tpcId/", "recoAnalysis/Pi/tpctofId/"); + recoAnalysis.addClone("recoAnalysis/Pi/tpcId/", "recoAnalysis/Pi/NoId/"); + recoAnalysis.addClone("recoAnalysis/Pi/", "recoAnalysis/Ka/"); // Kaon + recoAnalysis.addClone("recoAnalysis/Pi/", "recoAnalysis/Pr/"); // Proton + recoAnalysis.addClone("recoAnalysis/Pi/", "recoAnalysis/El/"); // Electron + recoAnalysis.addClone("recoAnalysis/Pi/", "recoAnalysis/De/"); // Deuteron + + recoAnalysis.add("recoAnalysis/SelectedTrack_IdentificationTag", "SelectedTrack_IdentificationTag", kTH1D, {{34, -1.5, 32.5, "trackTAG"}}); + recoAnalysis.add("recoAnalysis/RejectedTrack_RejectionTag", "RejectedTrack_RejectionTag", kTH1D, {{16, -1.5, 6.5, "rejectionTAG"}}); + + recoAnalysis.add("recoAnalysis/Sparse_Full_K0sPiKa", "Sparse_Full_K0sPiKa", kTHnSparseD, {axisCent, {2000, -1.5, 1998.5, "nTrack"}, {100, -1.5, 98.5, "nK0s"}, {100, -1.5, 98.5, "nRejectedPiPlus"}, {100, -1.5, 98.5, "nRejectedPiMinus"}, {500, -1.5, 498.5, "nPiPlus"}, {500, -1.5, 498.5, "nPiMinus"}, {500, -1.5, 498.5, "nKaPlus"}, {500, -1.5, 498.5, "nKaMinus"}}); + recoAnalysis.add("recoAnalysis/Sparse_Full_K0sPrDe", "Sparse_Full_K0sPrDe", kTHnSparseD, {axisCent, {2000, -1.5, 1998.5, "nTrack"}, {100, -1.5, 98.5, "nK0s"}, {100, -1.5, 98.5, "nRejectedPiPlus"}, {100, -1.5, 98.5, "nRejectedPiMinus"}, {500, -1.5, 498.5, "nProton"}, {500, -1.5, 498.5, "nPBar"}, {500, -1.5, 498.5, "nDePlus"}, {500, -1.5, 498.5, "nDeMinus"}}); + recoAnalysis.add("recoAnalysis/Sparse_Full_K0sKaEl", "Sparse_Full_K0sKaEl", kTHnSparseD, {axisCent, {2000, -1.5, 1998.5, "nTrack"}, {100, -1.5, 98.5, "nK0s"}, {100, -1.5, 98.5, "nRejectedPiPlus"}, {100, -1.5, 98.5, "nRejectedPiMinus"}, {500, -1.5, 498.5, "nKaPlus"}, {500, -1.5, 498.5, "nKaMinus"}, {500, -1.5, 498.5, "nElPlus"}, {500, -1.5, 498.5, "nElMinus"}}); + recoAnalysis.add("recoAnalysis/Sparse_Full_PiKaPr", "Sparse_Full_PiKaPr", kTHnSparseD, {axisCent, {2000, -1.5, 1998.5, "nTrack"}, {100, -1.5, 98.5, "nRejectedPiPlus"}, {100, -1.5, 98.5, "nRejectedPiMinus"}, {500, -1.5, 498.5, "nPiPlus"}, {500, -1.5, 498.5, "nPiMinus"}, {500, -1.5, 498.5, "nKaPlus"}, {500, -1.5, 498.5, "nKaMinus"}, {500, -1.5, 498.5, "nProton"}, {500, -1.5, 498.5, "nPBar"}}); + recoAnalysis.add("recoAnalysis/Sparse_Full_PiElDe", "Sparse_Full_PiElDe", kTHnSparseD, {axisCent, {2000, -1.5, 1998.5, "nTrack"}, {100, -1.5, 98.5, "nRejectedPiPlus"}, {100, -1.5, 98.5, "nRejectedPiMinus"}, {500, -1.5, 498.5, "nPiPlus"}, {500, -1.5, 498.5, "nPiMinus"}, {500, -1.5, 498.5, "nElPlus"}, {500, -1.5, 498.5, "nElMinus"}, {500, -1.5, 498.5, "nDePlus"}, {500, -1.5, 498.5, "nDeMinus"}}); + recoAnalysis.add("recoAnalysis/Sparse_Full_KaPrDe", "Sparse_Full_KaPrDe", kTHnSparseD, {axisCent, {2000, -1.5, 1998.5, "nTrack"}, {100, -1.5, 98.5, "nRejectedPiPlus"}, {100, -1.5, 98.5, "nRejectedPiMinus"}, {500, -1.5, 498.5, "nKaPlus"}, {500, -1.5, 498.5, "nKaMinus"}, {500, -1.5, 498.5, "nProton"}, {500, -1.5, 498.5, "nPBar"}, {500, -1.5, 498.5, "nDePlus"}, {500, -1.5, 498.5, "nDeMinus"}}); + recoAnalysis.add("recoAnalysis/Sparse_Full_PrElDe", "Sparse_Full_PrElDe", kTHnSparseD, {axisCent, {2000, -1.5, 1998.5, "nTrack"}, {100, -1.5, 98.5, "nRejectedPiPlus"}, {100, -1.5, 98.5, "nRejectedPiMinus"}, {500, -1.5, 498.5, "nProton"}, {500, -1.5, 498.5, "nPBar"}, {500, -1.5, 498.5, "nElPlus"}, {500, -1.5, 498.5, "nElMinus"}, {500, -1.5, 498.5, "nDePlus"}, {500, -1.5, 498.5, "nDeMinus"}}); + + recoAnalysis.add("recoAnalysis/Sparse_newDynm_K0s_Ka", "Sparse_newDynm_K0s_Ka", kTHnSparseD, {axisCent, {2000, -1.5, 1998.5, "nTrack"}, {100, -1.5, 98.5, "nK0s"}, {500, -1.5, 498.5, "nKaon"}, {10000, -1.5, 9998.5, "(nK0s)^{2}"}, {250000, -1.5, 249998.5, "(nKaon)^{2}"}, {500, -1.5, 498.5, "(nK0s*nKaon)"}}); + recoAnalysis.add("recoAnalysis/Sparse_newDynm_Kp_Km", "Sparse_newDynm_Kp_Km", kTHnSparseD, {axisCent, {2000, -1.5, 1998.5, "nTrack"}, {500, -1.5, 498.5, "nKaPlus"}, {500, -1.5, 498.5, "nKaMinus"}, {250000, -1.5, 249998.5, "(nKaPlus)^{2}"}, {250000, -1.5, 249998.5, "(nKaMinus)^{2}"}, {250000, -1.5, 249998.5, "(nKaPlus*nKaMinus)"}}); + // + + genAnalysis.add("genAnalysis/K0s/h12_p", "p", kTH1F, {axisP}); + genAnalysis.add("genAnalysis/K0s/h13_pt", "pt", kTH1F, {axisPt}); + genAnalysis.add("genAnalysis/K0s/h14_eta", "eta", kTH1F, {axisEta}); + genAnalysis.add("genAnalysis/K0s/h15_phi", "phi", kTH1F, {axisPhi}); + genAnalysis.add("genAnalysis/K0s/h16_rapidity", "rapidity", kTH1F, {axisRapidity}); + genAnalysis.add("genAnalysis/K0s/h20_pt_eta", "pt_eta", kTH2F, {axisPt, axisEta}); + genAnalysis.addClone("genAnalysis/K0s/", "genAnalysis/Pi/"); + genAnalysis.addClone("genAnalysis/K0s/", "genAnalysis/Ka/"); + genAnalysis.addClone("genAnalysis/K0s/", "genAnalysis/Pr/"); + genAnalysis.addClone("genAnalysis/K0s/", "genAnalysis/El/"); + genAnalysis.addClone("genAnalysis/K0s/", "genAnalysis/De/"); + + // Printing the Stored Registry information + LOG(info) << "Printing Stored Registry Information"; + LOG(info) << " DEBUG :: 01- recoV0s.print()"; + recoV0s.print(); + LOG(info) << " DEBUG :: 02- recoEvent.print()"; + recoEvent.print(); + LOG(info) << " DEBUG :: 03- recoK0s.print()"; + recoK0s.print(); + LOG(info) << " DEBUG :: 04- recoTracks.print()"; + recoTracks.print(); + LOG(info) << " DEBUG :: 05- recoAnalysis.print()"; + recoAnalysis.print(); + LOG(info) << " DEBUG :: 06- genAnalysis.print()"; + genAnalysis.print(); + } + + enum RejectionTagEnum { + kPassed = 0, + kFailTpcNClsCrossedRows, + kFailTrkdcaXY, + kFailGlobalTrack, + kFailVGSelCheck, + kFailK0ShortDaughter, + kFailPhiDaughter, + }; + + enum IdentificationType { + kTPCidentified = 0, + kTOFidentified, + kTPCTOFidentified, + kUnidentified + }; + + enum TpcTofCutType { + kRectangularCut = 0, + kCircularCut, + kEllipsoidalCut + }; + + enum ProcessTypeEnum { + doDataProcessing = 0, + doRecoProcessing, + doPurityProcessing, + doGenProcessing, + doSimProcessing + }; + + enum HistRegEnum { + v0TableFull = 0, + v0TablePostK0sCheck, + v0TablePostMassCut, + v0TablePostSelectionCut, + recoK0sPreSel, + recoK0sPostSel, + recoTrackPreSel, + recoTrackPostSel, + recoAnalysisDir, + genAnalysisDir + }; + + static constexpr std::string_view HistRegDire[] = { + "v0Table/Full/", + "v0Table/postK0sCheck/", + "v0Table/postMassCut/", + "v0Table/postSelectionCut/", + "recoK0s/PreSel/", + "recoK0s/PostSel/", + "recoTracks/PreSel/", + "recoTracks/PostSel/", + "recoAnalysis/", + "genAnalysis/"}; + + enum PidEnum { + kPi = 0, // dont use kPion, kKaon, as these enumeration + kKa, // are already defined in $ROOTSYS/root/include/TPDGCode.h + kPr, + kEl, + kDe, + kK0s + }; + + static constexpr std::string_view PidDire[] = { + "Pi/", + "Ka/", + "Pr/", + "El/", + "De/", + "K0s/"}; + + enum DetEnum { + tpcId = 0, + tofId, + tpctofId, + NoId + }; + + static constexpr std::string_view DetDire[] = { + "tpcId/", + "tofId/", + "tpctofId/", + "NoId/"}; + + // vetoRejection for particles //From Victor Luis Gonzalez Sebastian's analysis note for balance functions + template + bool selTrackForId(const T& track) + { + if (-3.0 < track.tpcNSigmaEl() && track.tpcNSigmaEl() < 5.0 && + std::fabs(track.tpcNSigmaPi()) > 3.0 && + std::fabs(track.tpcNSigmaKa()) > 3.0 && + std::fabs(track.tpcNSigmaPr()) > 3.0) { + return false; + } else { + return true; + } + } + + template + bool vetoIdOthersTPC(const T& track) + { + if (pidMode != kPi) { + if (std::fabs(track.tpcNSigmaPi()) < 3.0) + return false; + } + if (pidMode != kKa) { + if (std::fabs(track.tpcNSigmaKa()) < 3.0) + return false; + } + if (pidMode != kPr) { + if (std::fabs(track.tpcNSigmaPr()) < 3.0) + return false; + } + if (cfgDoElRejection) { + if (pidMode != kEl) { + if (std::fabs(track.tpcNSigmaEl()) < 3.0) + return false; + } + } + if (cfgDoDeRejection) { + if (pidMode != kDe) { + if (std::fabs(track.tpcNSigmaDe()) < 3.0) + return false; + } + } + return true; + } + + template + bool vetoIdOthersTOF(const T& track) + { + if (pidMode != kPi) { + if (std::fabs(track.tofNSigmaPi()) < 3.0) + return false; + } + if (pidMode != kKa) { + if (std::fabs(track.tofNSigmaKa()) < 3.0) + return false; + } + if (pidMode != kPr) { + if (std::fabs(track.tofNSigmaPr()) < 3.0) + return false; + } + if (cfgDoElRejection) { + if (pidMode != kEl) { + if (std::fabs(track.tofNSigmaEl()) < 3.0) + return false; + } + } + if (cfgDoDeRejection) { + if (pidMode != kDe) { + if (std::fabs(track.tofNSigmaDe()) < 3.0) + return false; + } + } + return true; + } + + template + bool vetoIdOthersTPCTOF(const T& track) + { + if (pidMode != kPi) { + if (std::fabs(track.tpcNSigmaPi()) < 3.0 && std::fabs(track.tofNSigmaPi()) < 3.0) + return false; + } + if (pidMode != kKa) { + if (std::fabs(track.tpcNSigmaKa()) < 3.0 && std::fabs(track.tofNSigmaKa()) < 3.0) + return false; + } + if (pidMode != kPr) { + if (std::fabs(track.tpcNSigmaPr()) < 3.0 && std::fabs(track.tofNSigmaPr()) < 3.0) + return false; + } + if (cfgDoElRejection) { + if (pidMode != kEl) { + if (std::fabs(track.tpcNSigmaEl()) < 3.0 && std::fabs(track.tofNSigmaEl()) < 3.0) + return false; + } + } + if (cfgDoDeRejection) { + if (pidMode != kDe) { + if (std::fabs(track.tpcNSigmaDe()) < 3.0 && std::fabs(track.tofNSigmaDe()) < 3.0) + return false; + } + } + return true; + } + + template + bool selIdRectangularCut(const T& track, const float& nSigmaTPC, const float& nSigmaTOF) + { + switch (pidMode) { + case kPi: + if (std::fabs(track.tpcNSigmaPi()) < nSigmaTPC && + std::fabs(track.tofNSigmaPi()) < nSigmaTOF) { + return true; + } + break; + case kKa: + if (std::fabs(track.tpcNSigmaKa()) < nSigmaTPC && + std::fabs(track.tofNSigmaKa()) < nSigmaTOF) { + return true; + } + break; + case kPr: + if (std::fabs(track.tpcNSigmaPr()) < nSigmaTPC && + std::fabs(track.tofNSigmaPr()) < nSigmaTOF) { + return true; + } + break; + default: + return false; + break; + } + return false; + } + + template + bool selIdEllipsoidalCut(const T& track, const float& nSigmaTPC, const float& nSigmaTOF) + { + switch (pidMode) { + case kPi: + if (std::pow(track.tpcNSigmaPi() / nSigmaTPC, 2) + std::pow(track.tofNSigmaPi() / nSigmaTOF, 2) < 1.0) + return true; + break; + case kKa: + if (std::pow(track.tpcNSigmaKa() / nSigmaTPC, 2) + std::pow(track.tofNSigmaKa() / nSigmaTOF, 2) < 1.0) + return true; + break; + case kPr: + if (std::pow(track.tpcNSigmaPr() / nSigmaTPC, 2) + std::pow(track.tofNSigmaPr() / nSigmaTOF, 2) < 1.0) + return true; + break; + default: + return false; + break; + } + return false; + } + + template + bool selIdCircularCut(const T& track, const float& nSigmaSquaredRad) + { + switch (pidMode) { + case kPi: + if (std::pow(track.tpcNSigmaPi(), 2) + std::pow(track.tofNSigmaPi(), 2) < nSigmaSquaredRad) + return true; + break; + case kKa: + if (std::pow(track.tpcNSigmaKa(), 2) + std::pow(track.tofNSigmaKa(), 2) < nSigmaSquaredRad) + return true; + break; + case kPr: + if (std::pow(track.tpcNSigmaPr(), 2) + std::pow(track.tofNSigmaPr(), 2) < nSigmaSquaredRad) + return true; + break; + default: + return false; + break; + } + return false; + } + + template + bool checkReliableTOF(const T& track) + { + if (track.hasTOF()) + return true; // which check makes the information of TOF relaiable? should track.beta() be checked? + else + return false; + } + + template + bool idTPC(const T& track, const float& nSigmaTPC) + { + if (cfgCheckVetoCut && !vetoIdOthersTPC(track)) + return false; + switch (pidMode) { + case kPi: + if (std::fabs(track.tpcNSigmaPi()) < nSigmaTPC) + return true; + break; + case kKa: + if (std::fabs(track.tpcNSigmaKa()) < nSigmaTPC) + return true; + break; + case kPr: + if (std::fabs(track.tpcNSigmaPr()) < nSigmaTPC) + return true; + break; + default: + return false; + break; + } + return false; + } + + template + bool idTPCTOF(const T& track, const int& pidCutType, const float& nSigmaTPC, const float& nSigmaTOF, const float& nSigmaSquaredRad) + { + if (cfgCheckVetoCut && !vetoIdOthersTPCTOF(track)) + return false; + if (pidCutType == kRectangularCut) { + return selIdRectangularCut(track, nSigmaTPC, nSigmaTOF); + } else if (pidCutType == kCircularCut) { + return selIdCircularCut(track, nSigmaSquaredRad); + } else if (pidCutType == kEllipsoidalCut) { + return selIdEllipsoidalCut(track, nSigmaTPC, nSigmaTOF); + } + return false; + } + + template + bool selPiPdependent(const T& track, int& IdMethod) + { + if (track.p() < cfgPiThrPforTOF) { + if (checkReliableTOF(track)) { + if (idTPCTOF(track, cfgPiIdCutTypeLowP, cfgPiNSigmaTPCLowP, cfgPiNSigmaTOFLowP, cfgPiNSigmaRadLowP)) { + IdMethod = kTPCTOFidentified; + return true; + } + return false; + } else { + if (idTPC(track, cfgPiNSigmaTPCLowP)) { + IdMethod = kTPCidentified; + return true; + } + return false; + } + } else { + if (checkReliableTOF(track)) { + if (idTPCTOF(track, cfgPiIdCutTypeHighP, cfgPiNSigmaTPCHighP, cfgPiNSigmaTOFHighP, cfgPiNSigmaRadHighP)) { + IdMethod = kTPCTOFidentified; + return true; + } + return false; + } + return false; + } + } + + template + bool selKaPdependent(const T& track, int& IdMethod) + { + if (track.p() < cfgKaThrPforTOF) { + if (checkReliableTOF(track)) { + if (idTPCTOF(track, cfgKaIdCutTypeLowP, cfgKaNSigmaTPCLowP, cfgKaNSigmaTOFLowP, cfgKaNSigmaRadLowP)) { + IdMethod = kTPCTOFidentified; + return true; + } + return false; + } else { + if (idTPC(track, cfgKaNSigmaTPCLowP)) { + IdMethod = kTPCidentified; + return true; + } + return false; + } + } else { + if (checkReliableTOF(track)) { + if (idTPCTOF(track, cfgKaIdCutTypeHighP, cfgKaNSigmaTPCHighP, cfgKaNSigmaTOFHighP, cfgKaNSigmaRadHighP)) { + IdMethod = kTPCTOFidentified; + return true; + } + return false; + } + return false; + } + } + + template + bool selPrPdependent(const T& track, int& IdMethod) + { + if (track.p() < cfgPrThrPforTOF) { + if (checkReliableTOF(track)) { + if (idTPCTOF(track, cfgPrIdCutTypeLowP, cfgPrNSigmaTPCLowP, cfgPrNSigmaTOFLowP, cfgPrNSigmaRadLowP)) { + IdMethod = kTPCTOFidentified; + return true; + } + return false; + } else { + if (idTPC(track, cfgPrNSigmaTPCLowP)) { + IdMethod = kTPCidentified; + return true; + } + return false; + } + } else { + if (checkReliableTOF(track)) { + if (idTPCTOF(track, cfgPrIdCutTypeHighP, cfgPrNSigmaTPCHighP, cfgPrNSigmaTOFHighP, cfgPrNSigmaRadHighP)) { + IdMethod = kTPCTOFidentified; + return true; + } + return false; + } + return false; + } + } + + //_______________________________Identification Funtions Depending on the tpcInnerParam _______________________________ + // tpc Selections + template + bool selPionTPCInnerParam(T track) + { + if (vetoIdOthersTPC(track)) { + if (0.05 <= track.tpcInnerParam() && track.tpcInnerParam() < 0.70 && std::abs(track.tpcNSigmaPi()) < cfgPiNSigmaTPCLowP) { + return true; + } + if (0.70 <= track.tpcInnerParam() && std::abs(track.tpcNSigmaPi()) < cfgPiNSigmaTPCHighP) { + return true; + } + } + return false; + } + + template + bool selKaonTPCInnerParam(T track) + { + if (vetoIdOthersTPC(track)) { + if (0.05 <= track.tpcInnerParam() && track.tpcInnerParam() < 0.70 && std::abs(track.tpcNSigmaKa()) < cfgKaNSigmaTPCLowP) { + return true; + } + if (0.70 <= track.tpcInnerParam() && std::abs(track.tpcNSigmaKa()) < cfgKaNSigmaTPCHighP) { + return true; + } + } + return false; + } + + template + bool selProtonTPCInnerParam(T track) + { + if (vetoIdOthersTPC(track)) { + if (0.05 <= track.tpcInnerParam() && track.tpcInnerParam() < 1.60 && std::abs(track.tpcNSigmaPr()) < cfgPrNSigmaTPCLowP) { + return true; + } + if (1.60 <= track.tpcInnerParam() && std::abs(track.tpcNSigmaPr()) < cfgPrNSigmaTPCHighP) { + return true; + } + } + return false; + } + + template + bool selDeuteronTPCInnerParam(T track) + { + if (vetoIdOthersTPC(track)) { + if (0.05 <= track.tpcInnerParam() && track.tpcInnerParam() < 1.80 && std::abs(track.tpcNSigmaDe()) < 3.0) { + return true; + } + if (1.80 <= track.tpcInnerParam() && std::abs(track.tpcNSigmaDe()) < 2.0) { + return true; + } + } + return false; + } + + template + bool selElectronTPCInnerParam(T track) + { + if (track.tpcNSigmaEl() < 3.0 && track.tpcNSigmaPi() > 3.0 && track.tpcNSigmaKa() > 3.0 && track.tpcNSigmaPr() > 3.0 && track.tpcNSigmaDe() > 3.0) { + return true; + } + return false; + } + // + //_____________________________________________________TOF selection Functions _______________________________________________________________________ + // TOF Selections + // Pion + template + bool selPionTOF(T track) + { + if (vetoIdOthersTOF(track)) { + if (track.p() <= 0.75 && std::abs(track.tpcNSigmaPi()) < cfgPiNSigmaTPCLowP && std::abs(track.tofNSigmaPi()) < cfgPiNSigmaTOFLowP) { + return true; + } else if (0.75 < track.p() // after p = 0.75, Pi and Ka lines of nSigma 3.0 will start intersecting + && std::abs(track.tpcNSigmaPi()) < cfgPiNSigmaTPCHighP && std::abs(track.tofNSigmaPi()) < cfgPiNSigmaTOFHighP) { + return true; + } + } + return false; + } + + // Kaon + template + bool selKaonTOF(T track) + { + if (vetoIdOthersTOF(track)) { + if (track.p() <= 0.75 && std::abs(track.tpcNSigmaKa()) < cfgKaNSigmaTPCLowP && std::abs(track.tofNSigmaKa()) < cfgKaNSigmaTOFLowP) { + return true; + } + if (0.75 < track.p() && track.p() <= 1.30 // after 0.75 Pi and Ka lines of nSigma 3.0 will start intersecting + && std::abs(track.tpcNSigmaKa()) < cfgKaNSigmaTPCLowP && std::abs(track.tofNSigmaKa()) < cfgKaNSigmaTOFLowP) { + return true; + } + if (1.30 < track.p() // after 1.30 Pr and Ka lines of nSigma 3.0 will start intersecting + && std::abs(track.tpcNSigmaKa()) < cfgKaNSigmaTPCHighP && std::abs(track.tofNSigmaKa()) < cfgKaNSigmaTOFHighP) { + return true; + } + } + return false; + } + + // Proton + template + bool selProtonTOF(T track) + { + if (vetoIdOthersTOF(track)) { + if (track.p() <= 1.30 && std::abs(track.tpcNSigmaPr()) < cfgPrNSigmaTPCLowP && std::abs(track.tofNSigmaPr()) < cfgPrNSigmaTOFLowP) { + return true; + } + if (1.30 < track.p() && track.p() <= 3.10 // after 1.30 Pr and Ka lines of nSigma 3.0 will start intersecting + && std::abs(track.tpcNSigmaPr()) < cfgPrNSigmaTPCLowP && std::abs(track.tofNSigmaPr()) < cfgPrNSigmaTOFLowP // Some Deuteron contamination is still coming in p dependent cuts + ) { + return true; + } + if (3.10 < track.p() // after 3.10 Pr and De lines of nSigma 3.0 will start intersecting + && std::abs(track.tpcNSigmaPr()) < cfgPrNSigmaTPCHighP && std::abs(track.tofNSigmaPr()) < cfgPrNSigmaTOFHighP) { + return true; + } + } + return false; + } + + // Deuteron + template + bool selDeuteronTOF(T track) + { + if (vetoIdOthersTOF(track)) { + if (track.p() <= 3.10 && std::abs(track.tpcNSigmaDe()) < 3.0 && std::abs(track.tofNSigmaDe()) < 3.0) { + return true; + } + if (3.10 < track.p() // after 3.10 De and Pr lines of nSigma 3.0 will start intersecting + && std::abs(track.tpcNSigmaDe()) < 2.0 && std::abs(track.tofNSigmaDe()) < 2.0) { + return true; + } + } + return false; + } + + // Electron + template + bool selElectronTOF(T track) + { + if ((std::pow(track.tpcNSigmaEl(), 2) + std::pow(track.tofNSigmaEl(), 2)) < 9.00 && vetoIdOthersTOF(track)) { + return true; + } + return false; + } + // + + //______________________________Identification Functions________________________________________________________________ + // Pion + template + bool selPion(T track, int& IdMethod) + { + if (cfgDoPdependentId) { + return selPiPdependent(track, IdMethod); + } else if (cfgDoTpcInnerParamId) { + if (selPionTPCInnerParam(track)) { + IdMethod = kTPCidentified; + return true; + } else if (track.hasTOF() && track.beta() > 0.0 && selPionTOF(track)) { + IdMethod = kTOFidentified; + return true; + } + return false; + } + return false; + } + + // Kaon + template + bool selKaon(T track, int& IdMethod) + { + if (cfgDoPdependentId) { + return selKaPdependent(track, IdMethod); + } else if (cfgDoTpcInnerParamId) { + if (selKaonTPCInnerParam(track)) { + IdMethod = kTPCidentified; + return true; + } else if (track.hasTOF() && track.beta() > 0.0 && selKaonTOF(track)) { + IdMethod = kTOFidentified; + return true; + } + return false; + } + return false; + } + + // Proton + template + bool selProton(T track, int& IdMethod) + { + if (cfgDoPdependentId) { + return selPrPdependent(track, IdMethod); + } else if (cfgDoTpcInnerParamId) { + if (selProtonTPCInnerParam(track)) { + IdMethod = kTPCidentified; + return true; + } else if (track.hasTOF() && track.beta() > 0.0 && selProtonTOF(track)) { + IdMethod = kTOFidentified; + return true; + } + return false; + } + return false; + } + + // Deuteron + template + bool selDeuteron(T track, int& IdMethod) + { + if (cfgDoPdependentId) { + return false; + } else if (cfgDoTpcInnerParamId) { + if (selDeuteronTPCInnerParam(track)) { + IdMethod = kTPCidentified; + return true; + } else if (track.hasTOF() && track.beta() > 0.0 && selDeuteronTOF(track)) { + IdMethod = kTOFidentified; + return true; + } + return false; + } + return false; + } + + // Electron + template + bool selElectron(T track, int& IdMethod) + { + if (cfgDoPdependentId) { + return false; + } else if (cfgDoTpcInnerParamId) { + if (selElectronTPCInnerParam(track)) { + IdMethod = kTPCidentified; + return true; + } else if (track.hasTOF() && track.beta() > 0.0 && selElectronTOF(track)) { + IdMethod = kTOFidentified; + return true; + } + return false; + } + return false; + } + + template + int findV0Tag(const T& posDaughterTrack, const T& negDaughterTrack, int& posPiIdMethod, int& posPrIdMethod, int& negPiIdMethod, int& negPrIdMethod) + { + bool posIsPion = false; + bool posIsProton = false; + bool negIsPion = false; + bool negIsProton = false; + + int v0TagValue = 0; + + // Check if positive track is pion or proton + if (selPion(posDaughterTrack, posPiIdMethod)) + posIsPion = true; // Coming From K0s -> PiPlus + PiMinus and AntiLambda -> PiPlus + AntiProton + if (selProton(posDaughterTrack, posPrIdMethod)) + posIsProton = true; // Coming From Lambda -> proton + PiMinus + if (selPion(negDaughterTrack, negPiIdMethod)) + negIsPion = true; // Coming From K0s -> PiPlus + PiMinus and Lambda -> proton + PiMinus + if (selProton(negDaughterTrack, negPrIdMethod)) + negIsProton = true; // Coming From AntiLambda -> PiPlus + AntiProton + + if (posIsPion && negIsPion) { + BITSET(v0TagValue, BIT_IS_K0S); + } + if (posIsProton && negIsPion) { + BITSET(v0TagValue, BIT_IS_LAMBDA); + } + if (posIsPion && negIsProton) { + BITSET(v0TagValue, BIT_IS_ANTILAMBDA); + } + return v0TagValue; + } + + template + int findCollisionIndexTag(const T& v0, const U& posDaughterTrack, const U& negDaughterTrack) + { + int v0daughterCollisionIndexTag = 0; + if (v0.collisionId() == posDaughterTrack.collisionId()) { + BITSET(v0daughterCollisionIndexTag, BIT_POS_DAU_HAS_SAME_COLL); + } + if (v0.collisionId() == negDaughterTrack.collisionId()) { + BITSET(v0daughterCollisionIndexTag, BIT_NEG_DAU_HAS_SAME_COLL); + } + if (posDaughterTrack.collisionId() == negDaughterTrack.collisionId()) { + BITSET(v0daughterCollisionIndexTag, BIT_BOTH_DAU_HAS_SAME_COLL); + } + return v0daughterCollisionIndexTag; + } + + template + bool selK0s(T v0) + { + if (k0sSelCut.cfgK0sMLow < v0.mK0Short() && v0.mK0Short() < k0sSelCut.cfgK0sMHigh && + k0sSelCut.cfgK0sLowPt < v0.pt() && v0.pt() < k0sSelCut.cfgK0sHighPt && + std::abs(v0.rapidity(MassK0Short)) < k0sSelCut.cfgK0sRapitidy && + v0.qtarm() > (k0sSelCut.cfgK0sARMcut * std::abs(v0.alpha()))) { + return true; + } else { + return false; + } + } + + template + void findRepeatedEntries(std::vector ParticleList, T hist) + { + for (uint ii = 0; ii < ParticleList.size(); ii++) { + int nCommonCount = 0; // checking the repeat number of track + for (uint jj = 0; jj < ParticleList.size(); jj++) { + if (ParticleList[jj] == ParticleList[ii]) { + if (jj < ii) { + break; + } // break if it was already counted + nCommonCount++; // To Calculate no of times the entry was repeated + } + } + hist->Fill(nCommonCount); + } + } + + template + bool checkTrackSelection(const T& track, int& rejectionTag) + { + if (track.tpcNClsCrossedRows() < cfgTrackCuts.cfgTrkTpcNClsCrossedRows) { + rejectionTag = kFailTpcNClsCrossedRows; + return false; + } + if (std::fabs(track.dcaXY()) > cfgTrackCuts.cfgTrkdcaXY) { + rejectionTag = kFailTrkdcaXY; + return false; + } + if (!track.isGlobalTrack()) { + rejectionTag = kFailGlobalTrack; + return false; + } + if (cfgTrackCuts.cfgDoVGselTrackCheck) { + if (!selTrackForId(track)) { + rejectionTag = kFailVGSelCheck; + return false; + } + } + return true; + } + + template + bool checkTrackInList(const T& track, const std::vector& vecList, int& rejectionTag, const int& listTagValue) + { + if (std::binary_search(vecList.begin(), vecList.end(), track.globalIndex())) { + rejectionTag = listTagValue; + return true; // Binary Search is fastest search in a sorted array. + } + return false; + } + + template + void fillIdentificationQA(H histReg, const T& track) + { + + float tpcNSigmaVal = -999, tofNSigmaVal = -999; + switch (pidMode) { + case kPi: + if (!cfgFillPiQA) + return; + tpcNSigmaVal = track.tpcNSigmaPi(); + tofNSigmaVal = track.tofNSigmaPi(); + break; + case kKa: + if (!cfgFillKaQA) + return; + tpcNSigmaVal = track.tpcNSigmaKa(); + tofNSigmaVal = track.tofNSigmaKa(); + break; + case kPr: + if (!cfgFillPrQA) + return; + tpcNSigmaVal = track.tpcNSigmaPr(); + tofNSigmaVal = track.tofNSigmaPr(); + break; + case kEl: + if (!cfgFillElQA) + return; + tpcNSigmaVal = track.tpcNSigmaEl(); + tofNSigmaVal = track.tofNSigmaEl(); + break; + case kDe: + if (!cfgFillDeQA) + return; + tpcNSigmaVal = track.tpcNSigmaDe(); + tofNSigmaVal = track.tofNSigmaDe(); + break; + default: + tpcNSigmaVal = -999, tofNSigmaVal = -999; + break; + } + + if (fillSignal) { + // momemtum + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h20_p_pt"), track.p(), track.pt()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h21_p_tpcInnerParam"), track.p(), track.tpcInnerParam()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h22_p_tofExpMom"), track.p(), track.tofExpMom()); + // tpcSignal + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h23_p_tpcSignal"), track.p(), track.tpcSignal()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h24_tpcInnerParam_tpcSignal"), track.tpcInnerParam(), track.tpcSignal()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h25_tofExpMom_tpcSignal"), track.tofExpMom(), track.tpcSignal()); + // tofBeta + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h26_p_beta"), track.p(), track.beta()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h27_tpcInnerParam_beta"), track.tpcInnerParam(), track.beta()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h28_tofExpMom_beta"), track.tofExpMom(), track.beta()); + } + // NSigma + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h29_p_tpcNSigma"), track.p(), tpcNSigmaVal); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h30_pt_tpcNSigma"), track.pt(), tpcNSigmaVal); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h31_tpcInnerParam_tpcNSigma"), track.tpcInnerParam(), tpcNSigmaVal); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h32_tofExpMom_tpcNSigma"), track.tofExpMom(), tpcNSigmaVal); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h33_p_tofNSigma"), track.p(), tofNSigmaVal); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h34_pt_tofNSigma"), track.pt(), tofNSigmaVal); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h35_tpcInnerParam_tofNSigma"), track.tpcInnerParam(), tofNSigmaVal); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h36_tofExpMom_tofNSigma"), track.tofExpMom(), tofNSigmaVal); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h37_tpcNSigma_tofNSigma"), tpcNSigmaVal, tofNSigmaVal); + } + + template + void fillTrackQA(T track) + { + // FullTrack + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h01_p"), track.p()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h02_pt"), track.pt()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h03_tpcInnerParam"), track.tpcInnerParam()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h04_tofExpMom"), track.tofExpMom()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h05_eta"), track.eta()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h06_phi"), track.phi()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h07_dcaXY"), track.dcaXY()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h08_dcaZ"), track.dcaZ()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h09_sign"), track.sign()); + // DcaXY + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h10_p_dcaXY"), track.p(), track.dcaXY()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h11_pt_dcaXY"), track.pt(), track.dcaXY()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h12_tpcInnerParam_dcaXY"), track.tpcInnerParam(), track.dcaXY()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h13_tofExpMom_dcaXY"), track.tofExpMom(), track.dcaXY()); + + // DcaZ + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h14_p_dcaZ"), track.p(), track.dcaZ()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h15_pt_dcaZ"), track.pt(), track.dcaZ()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h16_tpcInnerParam_dcaZ"), track.tpcInnerParam(), track.dcaZ()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h17_tofExpMom_dcaZ"), track.tofExpMom(), track.dcaZ()); + + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h20_pt_eta"), track.pt(), track.eta()); + // momemtum + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h20_p_pt"), track.p(), track.pt()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h21_p_tpcInnerParam"), track.p(), track.tpcInnerParam()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h22_p_tofExpMom"), track.p(), track.tofExpMom()); + + // tpcSignal + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h23_p_tpcSignal"), track.p(), track.tpcSignal()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h24_tpcInnerParam_tpcSignal"), track.tpcInnerParam(), track.tpcSignal()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h25_tofExpMom_tpcSignal"), track.tofExpMom(), track.tpcSignal()); + + // tofBeta + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h26_p_beta"), track.p(), track.beta()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h27_tpcInnerParam_beta"), track.tpcInnerParam(), track.beta()); + recoTracks.fill(HIST(HistRegDire[Mode]) + HIST("h28_tofExpMom_beta"), track.tofExpMom(), track.beta()); + + fillIdentificationQA(recoTracks, track); // Look at Pion + fillIdentificationQA(recoTracks, track); // Look at Kaon + fillIdentificationQA(recoTracks, track); // Look at Proton + fillIdentificationQA(recoTracks, track); // Look at Electron + fillIdentificationQA(recoTracks, track); // Look at Deuteron + } + + template + void fillV0DaughterQA(H histReg, const T& track, double particleMass) + { + // K0s-Daughter Info + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h01_p"), track.p()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h02_pt"), track.pt()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h03_tpcInnerParam"), track.tpcInnerParam()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h04_tofExpMom"), track.tofExpMom()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h05_eta"), track.eta()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h06_phi"), track.phi()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h07_rapidity"), track.rapidity(particleMass)); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h08_isPVContributor"), track.isPVContributor()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h09_isGlobalTrack"), track.isGlobalTrack()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h10_dcaXY"), track.dcaXY()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h11_dcaZ"), track.dcaZ()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h12_p_dcaXY"), track.p(), track.dcaXY()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h13_p_dcaZ"), track.p(), track.dcaZ()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h14_pt_dcaXY"), track.pt(), track.dcaXY()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h15_pt_dcaZ"), track.pt(), track.dcaZ()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h16_dcaXYwide"), track.dcaXY()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h17_dcaZwide"), track.dcaZ()); + + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("h20_pt_eta"), track.pt(), track.eta()); + + fillIdentificationQA(histReg, track); + } + + template + void fillV0QA(H histReg, const T& v0, const U& posDaughterTrack, const U& negDaughterTrack, const int& v0Tag, const int& v0DauCollisionIndexTag, const int& posPiIdMethod, const int& negPiIdMethod) + { + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h01_K0s_Mass"), v0.mK0Short()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h02_Lambda_Mass"), v0.mLambda()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h03_AntiLambda_Mass"), v0.mAntiLambda()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h04_v0DaughterCollisionIndexTag"), v0DauCollisionIndexTag); + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h05_V0Tag"), v0Tag); + + // Topological Cuts + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h06_dcapostopv"), v0.dcapostopv()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h07_dcanegtopv"), v0.dcanegtopv()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h08_dcaV0daughters"), v0.dcaV0daughters()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h09_v0cosPA"), v0.v0cosPA()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h10_v0radius"), v0.v0radius()); + + // K0s-FullInformation + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h11_mass"), v0.mK0Short()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h12_p"), v0.p()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h13_pt"), v0.pt()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h14_eta"), v0.eta()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h15_phi"), v0.phi()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h16_rapidity"), v0.rapidity(MassK0Short)); + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h17_alpha"), v0.alpha()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h18_qtarm"), v0.qtarm()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h19_alpha_qtarm"), v0.alpha(), v0.qtarm()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST("h20_pt_eta"), v0.pt(), v0.eta()); + + if (posPiIdMethod == kTPCidentified) { + fillV0DaughterQA(histReg, posDaughterTrack, MassProton); + } else if (posPiIdMethod == kTPCTOFidentified) { + fillV0DaughterQA(histReg, posDaughterTrack, MassProton); + } else if (posPiIdMethod == kUnidentified) { + fillV0DaughterQA(histReg, posDaughterTrack, MassProton); + } + + if (negPiIdMethod == kTPCidentified) { + fillV0DaughterQA(histReg, negDaughterTrack, MassProton); + } else if (negPiIdMethod == kTPCTOFidentified) { + fillV0DaughterQA(histReg, negDaughterTrack, MassProton); + } else if (negPiIdMethod == kUnidentified) { + fillV0DaughterQA(histReg, negDaughterTrack, MassProton); + } + } + + template + void fillGenTrackQA(H& histReg, const T& mcTrack) + { + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST("h12_p"), mcTrack.p()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST("h13_pt"), mcTrack.pt()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST("h14_eta"), mcTrack.eta()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST("h15_phi"), mcTrack.phi()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST("h16_rapidity"), mcTrack.y()); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST("h20_pt_eta"), mcTrack.pt(), mcTrack.eta()); + } + + template + void executeV0loop(const T& posDaughterTrack, const T& negDaughterTrack, const U& v0, H& recoV0s, + int& posPiIdMethod, int& posPrIdMethod, int& negPiIdMethod, int& negPrIdMethod, + int& v0Tag, int& trueV0TagValue, bool& isK0s, int& v0DauCollisionIndexTag, + auto& k0sPosDauList, auto& k0sNegDauList) + { + posPiIdMethod = kUnidentified; + posPrIdMethod = kUnidentified; + negPiIdMethod = kUnidentified; + negPrIdMethod = kUnidentified; + v0Tag = findV0Tag(posDaughterTrack, negDaughterTrack, posPiIdMethod, posPrIdMethod, negPiIdMethod, negPrIdMethod); + v0DauCollisionIndexTag = findCollisionIndexTag(v0, posDaughterTrack, negDaughterTrack); + + isK0s = false; + if (BITCHECK(v0Tag, BIT_IS_K0S) != 0) + isK0s = true; + trueV0TagValue = 0; + if (cfgFillV0TableFull) { + fillV0QA(recoV0s, v0, posDaughterTrack, negDaughterTrack, v0Tag, v0DauCollisionIndexTag, posPiIdMethod, negPiIdMethod); + } + // cut on dynamic columns for v0 particles + if (v0.v0cosPA() < v0settingCosPA) + return; // in place of continue; + if (v0.v0radius() < v0settingRadius) + return; // in place of continue; + + // K0s Analysis + if (isK0s) { + if (cfgFillV0TablePostK0sCheck) { + fillV0QA(recoV0s, v0, posDaughterTrack, negDaughterTrack, v0Tag, v0DauCollisionIndexTag, posPiIdMethod, negPiIdMethod); + } + // K0s mass cut + if (cfgFillV0TablePostMassCut) { + if (k0sSelCut.cfgK0sMLow < v0.mK0Short() && v0.mK0Short() < k0sSelCut.cfgK0sMHigh) { + fillV0QA(recoV0s, v0, posDaughterTrack, negDaughterTrack, v0Tag, v0DauCollisionIndexTag, posPiIdMethod, negPiIdMethod); + } + } + // Final K0s Selection. + if (selK0s(v0)) { + if (cfgFillV0TablePostSelectionCut) { + fillV0QA(recoV0s, v0, posDaughterTrack, negDaughterTrack, v0Tag, v0DauCollisionIndexTag, posPiIdMethod, negPiIdMethod); + } + trueV0TagValue += 1; + k0sPosDauList.push_back(posDaughterTrack.globalIndex()); + k0sNegDauList.push_back(negDaughterTrack.globalIndex()); + } + recoV0s.fill(HIST(HistRegDire[v0TablePostSelectionCut]) + HIST("hTrueV0TagCount"), trueV0TagValue); // 001 = Kaon, 010 = Lambda, 100 = AnitLambda + } // End of K0s block + } + + template + void executeSortPairDaughters(const auto& posDauList, const auto& negDauList, auto& fullDauList, const T& hist) + { + findRepeatedEntries(posDauList, hist); + findRepeatedEntries(negDauList, hist); + + // Obtain one single new daughter vector to remove double counting + fullDauList.insert(fullDauList.end(), posDauList.begin(), posDauList.end()); + fullDauList.insert(fullDauList.end(), negDauList.begin(), negDauList.end()); + + // Sort and Remove repeated entries + std::sort(fullDauList.begin(), fullDauList.end()); + auto last = std::unique(fullDauList.begin(), fullDauList.end()); // std::unique only moves duplicates to end of the vector + fullDauList.erase(last, fullDauList.end()); // last is the iterator position from where duplicate entries start + + // Check sorting + if (!std::is_sorted(fullDauList.begin(), fullDauList.end())) { + LOG(error) << "fullDauList is unsorted, will give wrong results when v0 and collisions will be checked"; + } + } + + template //, typename H> + void executeV0InCollisionloop(const T& posDaughterTrack, const T& negDaughterTrack, const U& v0, + int& posPiIdMethod, int& posPrIdMethod, int& negPiIdMethod, int& negPrIdMethod, + int& v0Tag, bool& isK0s, int& v0DauCollisionIndexTag, float& nK0s, const float& centrality) + { + if (v0.v0cosPA() < v0settingCosPA) + return; // for continue; // cut on dynamic columns for v0 particles + if (v0.v0radius() < v0settingRadius) + return; // for continue; + isK0s = false; + + posPiIdMethod = kUnidentified; + posPrIdMethod = kUnidentified; + negPiIdMethod = kUnidentified; + negPrIdMethod = kUnidentified; + v0Tag = findV0Tag(posDaughterTrack, negDaughterTrack, posPiIdMethod, posPrIdMethod, negPiIdMethod, negPrIdMethod); + v0DauCollisionIndexTag = findCollisionIndexTag(v0, posDaughterTrack, negDaughterTrack); + + if (BITCHECK(v0Tag, BIT_IS_K0S) != 0) + isK0s = true; + if (cfgFillRecoK0sPreSel) { + fillV0QA(recoK0s, v0, posDaughterTrack, negDaughterTrack, v0Tag, v0DauCollisionIndexTag, posPiIdMethod, negPiIdMethod); + } + // K0s Analysis + if (isK0s && selK0s(v0)) { + if (cfgFillRecoK0sPostSel) { + fillV0QA(recoK0s, v0, posDaughterTrack, negDaughterTrack, v0Tag, v0DauCollisionIndexTag, posPiIdMethod, negPiIdMethod); + } + recoK0s.fill(HIST(HistRegDire[recoK0sPostSel]) + HIST("mK0s_vs_cent"), centrality, v0.mK0Short()); // centrality dependent mass + nK0s++; + } // End of K0s block + } + + template + void executeTrackQAPart(const T& track, const auto& fullDauList, int& rejectionTag, float& nRejectedPiMinus, float& nRejectedPiPlus, int& nTrack, bool& isAcceptedTrack) + { + if (cfgFillRecoTrackPreSel) { + fillTrackQA(track); + } + rejectionTag = 0; + if (!checkTrackSelection(track, rejectionTag)) { + recoAnalysis.fill(HIST("recoAnalysis/RejectedTrack_RejectionTag"), rejectionTag); + isAcceptedTrack = false; + return; // for continue; + } else if (checkTrackInList(track, fullDauList, rejectionTag, kFailK0ShortDaughter)) { + recoAnalysis.fill(HIST("recoAnalysis/RejectedTrack_RejectionTag"), rejectionTag); + if (track.signed1Pt() > 0) { + nRejectedPiPlus++; // DOEFFCORR + } else if (track.signed1Pt() < 0) { + nRejectedPiMinus++; // DOEFFCORR + } + isAcceptedTrack = false; + return; // for continue; + } + isAcceptedTrack = true; + if (cfgFillRecoTrackPostSel) { + fillTrackQA(track); + } + nTrack++; + } + + template + void executeTrackAnalysisPart(const T& track, const int& trackIdTag, + const int& idMethodPi, const bool& trackIsPion, float& nPiMinus, float& nPiPlus, + const int& idMethodKa, const bool& trackIsKaon, float& nKaMinus, float& nKaPlus, + const int& idMethodPr, const bool& trackIsProton, float& nProton, float& nPBar, + const int& idMethodEl, const bool& trackIsElectron, float& nElPlus, float& nElMinus, + const int& idMethodDe, const bool& trackIsDeuteron, float& nDePlus, float& nDeMinus) + { + if (trackIsPion) { + if (idMethodPi == kTPCidentified) { + fillIdentificationQA(recoAnalysis, track); + } else if (idMethodPi == kTPCTOFidentified) { + fillIdentificationQA(recoAnalysis, track); + } else if (idMethodPi == kUnidentified) { + fillIdentificationQA(recoAnalysis, track); + } + if (track.sign() > 0) { + nPiPlus++; + } else if (track.sign() < 0) { + nPiMinus++; + } + } + if (trackIsKaon) { + if (idMethodKa == kTPCidentified) { + fillIdentificationQA(recoAnalysis, track); + } else if (idMethodKa == kTPCTOFidentified) { + fillIdentificationQA(recoAnalysis, track); + } else if (idMethodKa == kUnidentified) { + fillIdentificationQA(recoAnalysis, track); + } + if (track.sign() > 0) { + nKaPlus++; + } else if (track.sign() < 0) { + nKaMinus++; + } + } + if (trackIsProton) { + if (idMethodPr == kTPCidentified) { + fillIdentificationQA(recoAnalysis, track); + } else if (idMethodPr == kTPCTOFidentified) { + fillIdentificationQA(recoAnalysis, track); + } else if (idMethodPr == kUnidentified) { + fillIdentificationQA(recoAnalysis, track); + } + if (track.sign() > 0) { + nProton++; + } else if (track.sign() < 0) { + nPBar++; + } + } + if (trackIsElectron) { + if (idMethodEl == kTPCidentified) { + fillIdentificationQA(recoAnalysis, track); + } else if (idMethodEl == kTPCTOFidentified) { + fillIdentificationQA(recoAnalysis, track); + } else if (idMethodEl == kUnidentified) { + fillIdentificationQA(recoAnalysis, track); + } + if (track.sign() > 0) { + nElPlus++; + } else if (track.sign() < 0) { + nElMinus++; + } + } + if (trackIsDeuteron) { + if (idMethodDe == kTPCidentified) { + fillIdentificationQA(recoAnalysis, track); + } else if (idMethodDe == kTPCTOFidentified) { + fillIdentificationQA(recoAnalysis, track); + } else if (idMethodDe == kUnidentified) { + fillIdentificationQA(recoAnalysis, track); + } + if (track.sign() > 0) { + nDePlus++; + } + if (track.sign() < 0) { + nDeMinus++; + } + } + recoAnalysis.fill(HIST("recoAnalysis/SelectedTrack_IdentificationTag"), trackIdTag); + } + + void executeSparseAnalysisPart(const float& centFT0C, const float& nTrack, const float& nK0s, + const float& nRejectedPiPlus, const float& nRejectedPiMinus, float& nKaon, + const float& nPiPlus, const float& nKaPlus, const float& nProton, const float& nElPlus, const float& nDePlus, + const float& nPiMinus, const float& nKaMinus, const float& nPBar, const float& nElMinus, const float& nDeMinus) + { + nKaon = nKaPlus + nKaMinus; + if (cfgFillSparseFullK0sPiKa) { + recoAnalysis.fill(HIST("recoAnalysis/Sparse_Full_K0sPiKa"), + centFT0C, nTrack, nK0s, + nRejectedPiPlus, nRejectedPiMinus, + nPiPlus, nPiMinus, nKaPlus, nKaMinus); + } + if (cfgFillSparseFullK0sPrDe) { + recoAnalysis.fill(HIST("recoAnalysis/Sparse_Full_K0sPrDe"), + centFT0C, nTrack, nK0s, + nRejectedPiPlus, nRejectedPiMinus, + nProton, nPBar, nDePlus, nDeMinus); + } + if (cfgFillSparseFullK0sKaEl) { + recoAnalysis.fill(HIST("recoAnalysis/Sparse_Full_K0sKaEl"), + centFT0C, nTrack, nK0s, nRejectedPiPlus, nRejectedPiMinus, + nKaPlus, nKaMinus, nElPlus, nElMinus); + } + if (cfgFillSparseFullPiKaPr) { + recoAnalysis.fill(HIST("recoAnalysis/Sparse_Full_PiKaPr"), + centFT0C, nTrack, + nRejectedPiPlus, nRejectedPiMinus, + nPiPlus, nPiMinus, nKaPlus, nKaMinus, nProton, nPBar); + } + if (cfgFillSparseFullPiElDe) { + recoAnalysis.fill(HIST("recoAnalysis/Sparse_Full_PiElDe"), + centFT0C, nTrack, + nRejectedPiPlus, nRejectedPiMinus, + nPiPlus, nPiMinus, nElPlus, nElMinus, nDePlus, nDeMinus); + } + if (cfgFillSparseFullKaPrDe) { + recoAnalysis.fill(HIST("recoAnalysis/Sparse_Full_KaPrDe"), + centFT0C, nTrack, + nRejectedPiPlus, nRejectedPiMinus, + nKaPlus, nKaMinus, nProton, nPBar, nDePlus, nDeMinus); + } + if (cfgFillSparseFullPrElDe) { + recoAnalysis.fill(HIST("recoAnalysis/Sparse_Full_PrElDe"), + centFT0C, nTrack, + nRejectedPiPlus, nRejectedPiMinus, + nProton, nPBar, nElPlus, nElMinus, nDePlus, nDeMinus); + } + if (cfgFillSparsenewDynmK0sKa) { + recoAnalysis.fill(HIST("recoAnalysis/Sparse_newDynm_K0s_Ka"), + centFT0C, nTrack, nK0s, nKaon, + nK0s * nK0s, nKaon * nKaon, nK0s * nKaon); + } + if (cfgFillSparsenewDynmKpKm) { + recoAnalysis.fill(HIST("recoAnalysis/Sparse_newDynm_Kp_Km"), + centFT0C, nTrack, nKaPlus, nKaMinus, + nKaPlus * nKaPlus, nKaMinus * nKaMinus, nKaPlus * nKaMinus); + } + } + + template + void executeEventInfoPart(const C& collision, const float& centrality, const int v0TableSize, const T& tracksTablePerColl, + const int& nTrack, const int& nK0s, + const int& nPiPlus, const int& nKaPlus, const int& nProton, const int& nElPlus, const int& nDePlus, + const int& nPiMinus, const int& nKaMinus, const int& nPBar, const int& nElMinus, const int& nDeMinus) + { + // Collisions QA + recoEvent.fill(HIST("recoEvent/h01_CollisionCount"), 0.5); + recoEvent.fill(HIST("recoEvent/h02_VertexXRec"), collision.posX()); + recoEvent.fill(HIST("recoEvent/h03_VertexYRec"), collision.posY()); + recoEvent.fill(HIST("recoEvent/h04_VertexZRec"), collision.posZ()); + recoEvent.fill(HIST("recoEvent/h05_Centrality"), centrality); + recoEvent.fill(HIST("recoEvent/h06_V0Size"), v0TableSize); + recoEvent.fill(HIST("recoEvent/h07_TracksSize"), tracksTablePerColl.size()); + recoEvent.fill(HIST("recoEvent/h08_nTrack"), nTrack); + recoEvent.fill(HIST("recoEvent/h09_nK0s"), nK0s); + recoEvent.fill(HIST("recoEvent/h10_nPiPlus"), nPiPlus); + recoEvent.fill(HIST("recoEvent/h11_nPiMinus"), nPiMinus); + recoEvent.fill(HIST("recoEvent/h12_nKaPlus"), nKaPlus); + recoEvent.fill(HIST("recoEvent/h13_nKaMinus"), nKaMinus); + recoEvent.fill(HIST("recoEvent/h14_nProton"), nProton); + recoEvent.fill(HIST("recoEvent/h15_nPBar"), nPBar); + recoEvent.fill(HIST("recoEvent/h16_nElPlus"), nElPlus); + recoEvent.fill(HIST("recoEvent/h17_nElMinus"), nElMinus); + recoEvent.fill(HIST("recoEvent/h18_nDePlus"), nDePlus); + recoEvent.fill(HIST("recoEvent/h19_nDeMinus"), nDeMinus); + } + + // Event Filter + Filter eventFilter = (o2::aod::evsel::sel8 == true); + Filter posZFilter = (nabs(o2::aod::collision::posZ) < cutZvertex); + + // Track Filter + Filter ptFilter = (o2::aod::track::pt) > cfgTrackCuts.cfgTrackPtLow && (o2::aod::track::pt) < cfgTrackCuts.cfgTrackPtHigh; + Filter etaFilter = (nabs(o2::aod::track::eta) < cfgTrackCuts.cfgTrackEta); + + // Filters on V0s + Filter preFilterv0 = (nabs(aod::v0data::dcapostopv) > v0settingDcaPosToPV && + nabs(aod::v0data::dcanegtopv) > v0settingDcaNegToPV && + aod::v0data::dcaV0daughters < v0settingDcaV0Dau); + + using MyCollisions = soa::Filtered>; + + using MyTracks = soa::Filtered>; + + using MyV0s = soa::Filtered; + + // For manual sliceBy + Preslice tracksPerCollisionPreslice = o2::aod::track::collisionId; + Preslice v0sPerCollisionPreslice = o2::aod::track::collisionId; + + using MyCollisionsWithMcLabels = soa::Filtered>; + + using MyTracksWithMcLabels = soa::Filtered>; + + using MyV0sWithMcLabels = soa::Filtered>; + + // Declaring vectors outside the process to avoid slight overhead for stack allocation and deallocation during each iteration. + std::vector k0sPosDauList; + std::vector k0sNegDauList; + std::vector k0sFullDauList; + + template + void executeAnalysis(const C& collisions, const V& V0s, const T& tracks) + { + k0sPosDauList.clear(); + k0sNegDauList.clear(); + k0sFullDauList.clear(); + + int posPiIdMethod = kUnidentified; + int posPrIdMethod = kUnidentified; + int negPiIdMethod = kUnidentified; + int negPrIdMethod = kUnidentified; + + bool isK0s = false; + + int v0Tag = 0; + int trueV0TagValue = 0; + int v0DauCollisionIndexTag = 0; + + // Declaring variables outside the loop to avoid slight overhead for stack allocation and deallocation during each iteration. + + float nK0s = 0; + float nPiPlus = 0; + float nPiMinus = 0; + float nKaPlus = 0; + float nKaMinus = 0; + float nProton = 0; + float nPBar = 0; + float nElPlus = 0; + float nElMinus = 0; + float nDePlus = 0; + float nDeMinus = 0; + + float nKaon = 0; + int nTrack = 0; + + float centrality = 0; + + float nRejectedPiPlus = 0; + float nRejectedPiMinus = 0; + int rejectionTag = 0; + + bool trackIsPion = false; + bool trackIsKaon = false; + bool trackIsProton = false; + bool trackIsElectron = false; + bool trackIsDeuteron = false; + + int trackIdTag = 0; + int idMethodPi = kUnidentified; + int idMethodKa = kUnidentified; + int idMethodPr = kUnidentified; + int idMethodEl = kUnidentified; + int idMethodDe = kUnidentified; + + if constexpr (analysisType == doDataProcessing) { + for (const auto& v0 : V0s) { + const auto& posDaughterTrack = v0.template posTrack_as(); + const auto& negDaughterTrack = v0.template negTrack_as(); + + executeV0loop(posDaughterTrack, negDaughterTrack, v0, recoV0s, + posPiIdMethod, posPrIdMethod, negPiIdMethod, negPrIdMethod, + v0Tag, trueV0TagValue, isK0s, v0DauCollisionIndexTag, + k0sPosDauList, k0sNegDauList); + } // End of V0s Loop + + executeSortPairDaughters(k0sPosDauList, k0sNegDauList, k0sFullDauList, recoV0s.get(HIST(HistRegDire[v0TablePostSelectionCut]) + HIST("nCommonPionOfDifferentK0s"))); + + for (const auto& collision : collisions) { + + nK0s = 0; + nPiPlus = 0; + nPiMinus = 0; + nKaPlus = 0; + nKaMinus = 0; + nProton = 0; + nPBar = 0; + nElPlus = 0; + nElMinus = 0; + nDePlus = 0; + nDeMinus = 0; + nTrack = 0; + nKaon = 0; + + centrality = collision.centFT0C(); + if (cfgCentAxis.centAxisType == 1) { + centrality = collision.centFT0M(); + } else if (cfgCentAxis.centAxisType == 2) { + centrality = collision.multFT0M(); + } else if (cfgCentAxis.centAxisType == 3) { + centrality = collision.multFT0C(); + } + + // group tracks, v0s manually + const uint64_t collIdx = collision.globalIndex(); + const auto tracksTablePerColl = tracks.sliceBy(tracksPerCollisionPreslice, collIdx); + const auto v0sTablePerColl = V0s.sliceBy(v0sPerCollisionPreslice, collIdx); + + for (const auto& v0 : v0sTablePerColl) { + const auto& posDaughterTrack = v0.template posTrack_as(); + const auto& negDaughterTrack = v0.template negTrack_as(); + + executeV0InCollisionloop(posDaughterTrack, negDaughterTrack, v0, + posPiIdMethod, posPrIdMethod, negPiIdMethod, negPrIdMethod, + v0Tag, isK0s, v0DauCollisionIndexTag, nK0s, centrality); + + } // End of V0s Loop + + nTrack = 0; + nRejectedPiPlus = 0; + nRejectedPiMinus = 0; + for (const auto& track : tracksTablePerColl) { + bool isAcceptedTrack = true; + executeTrackQAPart(track, k0sFullDauList, rejectionTag, nRejectedPiMinus, nRejectedPiPlus, nTrack, isAcceptedTrack); + if (!isAcceptedTrack) { + continue; + } + + // Do Proper Track Identification + trackIsPion = false; + trackIsKaon = false; + trackIsProton = false; + trackIsElectron = false; + trackIsDeuteron = false; + + trackIdTag = 0; + idMethodPi = kUnidentified; + idMethodKa = kUnidentified; + idMethodPr = kUnidentified; + idMethodEl = kUnidentified; + idMethodDe = kUnidentified; + + if (selPion(track, idMethodPi)) { + trackIsPion = true; + BITSET(trackIdTag, ID_BIT_PI); + } + if (selKaon(track, idMethodKa)) { + trackIsKaon = true; + BITSET(trackIdTag, ID_BIT_KA); + } + if (selProton(track, idMethodPr)) { + trackIsProton = true; + BITSET(trackIdTag, ID_BIT_PR); + } + if (selElectron(track, idMethodEl)) { + trackIsElectron = true; + BITSET(trackIdTag, ID_BIT_EL); + } + if (selDeuteron(track, idMethodDe)) { + trackIsDeuteron = true; + BITSET(trackIdTag, ID_BIT_DE); + } + + executeTrackAnalysisPart(track, trackIdTag, + idMethodPi, trackIsPion, nPiMinus, nPiPlus, + idMethodKa, trackIsKaon, nKaMinus, nKaPlus, + idMethodPr, trackIsProton, nProton, nPBar, + idMethodEl, trackIsElectron, nElPlus, nElMinus, + idMethodDe, trackIsDeuteron, nDePlus, nDeMinus); + } // track loop ends + + executeSparseAnalysisPart(centrality, nTrack, nK0s, + nRejectedPiPlus, nRejectedPiMinus, nKaon, + nPiPlus, nKaPlus, nProton, nElPlus, nDePlus, + nPiMinus, nKaMinus, nPBar, nElMinus, nDeMinus); + + executeEventInfoPart(collision, centrality, v0sTablePerColl.size(), tracksTablePerColl, + nTrack, nK0s, + nPiPlus, nKaPlus, nProton, nElPlus, nDePlus, + nPiMinus, nKaMinus, nPBar, nElMinus, nDeMinus); + } // collision loop ends + } else if constexpr (analysisType == doRecoProcessing || analysisType == doPurityProcessing) { + for (const auto& v0 : V0s) { + const auto& posDaughterTrack = v0.template posTrack_as(); + const auto& negDaughterTrack = v0.template negTrack_as(); + + //__________________________Reco Level ____________________________________________________ + if (!v0.has_mcParticle() || !posDaughterTrack.has_mcParticle() || !negDaughterTrack.has_mcParticle()) { + continue; + } + + auto v0mcparticle = v0.mcParticle(); // if (v0mcparticle.pdgCode() != 310 || !v0mcparticle.isPhysicalPrimary()) + if (!v0mcparticle.isPhysicalPrimary()) + continue; + + if constexpr (analysisType == doPurityProcessing) { + auto posDauMcPart = posDaughterTrack.mcParticle(); + auto negDauMcPart = negDaughterTrack.mcParticle(); + if (v0mcparticle.pdgCode() != kK0Short || posDauMcPart.pdgCode() != kPiPlus || negDauMcPart.pdgCode() != kPiMinus) + continue; + } + + executeV0loop(posDaughterTrack, negDaughterTrack, v0, recoV0s, + posPiIdMethod, posPrIdMethod, negPiIdMethod, negPrIdMethod, + v0Tag, trueV0TagValue, isK0s, v0DauCollisionIndexTag, + k0sPosDauList, k0sNegDauList); + } // End of V0s Loop + executeSortPairDaughters(k0sPosDauList, k0sNegDauList, k0sFullDauList, recoV0s.get(HIST(HistRegDire[v0TablePostSelectionCut]) + HIST("nCommonPionOfDifferentK0s"))); + + for (const auto& collision : collisions) { + if (!collision.has_mcCollision()) { + LOG(warning) << "No MC collision for this collision, skip..."; + continue; + } + + nK0s = 0; + nPiPlus = 0; + nPiMinus = 0; + nKaPlus = 0; + nKaMinus = 0; + nProton = 0; + nPBar = 0; + nElPlus = 0; + nElMinus = 0; + nDePlus = 0; + nDeMinus = 0; + nTrack = 0; + nKaon = 0; + + centrality = collision.centFT0C(); + if (cfgCentAxis.centAxisType == 1) { + centrality = collision.centFT0M(); + } else if (cfgCentAxis.centAxisType == 2) { + centrality = collision.multFT0M(); + } else if (cfgCentAxis.centAxisType == 3) { + centrality = collision.multFT0C(); + } + + // group tracks, v0s manually + const uint64_t collIdx = collision.globalIndex(); + const auto tracksTablePerColl = tracks.sliceBy(tracksPerCollisionPreslice, collIdx); + const auto v0sTablePerColl = V0s.sliceBy(v0sPerCollisionPreslice, collIdx); + + for (const auto& v0 : v0sTablePerColl) { + const auto& posDaughterTrack = v0.template posTrack_as(); + const auto& negDaughterTrack = v0.template negTrack_as(); + + //__________________________Reco Level ____________________________________________________ + if (!v0.has_mcParticle() || !posDaughterTrack.has_mcParticle() || !negDaughterTrack.has_mcParticle()) { + continue; + } + + auto v0mcparticle = v0.mcParticle(); + if (!v0mcparticle.isPhysicalPrimary()) + continue; + + if constexpr (analysisType == doPurityProcessing) { + auto posDauMcPart = posDaughterTrack.mcParticle(); + auto negDauMcPart = negDaughterTrack.mcParticle(); + if (v0mcparticle.pdgCode() != kK0Short || posDauMcPart.pdgCode() != kPiPlus || negDauMcPart.pdgCode() != kPiMinus) + continue; + } + + executeV0InCollisionloop(posDaughterTrack, negDaughterTrack, v0, + posPiIdMethod, posPrIdMethod, negPiIdMethod, negPrIdMethod, + v0Tag, isK0s, v0DauCollisionIndexTag, nK0s, centrality); + } // End of V0s Loop + + nTrack = 0; + nRejectedPiPlus = 0; + nRejectedPiMinus = 0; + for (const auto& track : tracksTablePerColl) { + if (!track.has_mcParticle()) { + LOG(warning) << "No MC Particle for this track, skip..."; + continue; + } + + auto mcPart = track.mcParticle(); + if (!mcPart.isPhysicalPrimary()) { + continue; + } + + bool isAcceptedTrack = true; + executeTrackQAPart(track, k0sFullDauList, rejectionTag, nRejectedPiMinus, nRejectedPiPlus, nTrack, isAcceptedTrack); + if (!isAcceptedTrack) { + continue; + } + + // Do Proper Track Identification + trackIsPion = false; + trackIsKaon = false; + trackIsProton = false; + trackIsElectron = false; + trackIsDeuteron = false; + + trackIdTag = 0; + idMethodPi = kUnidentified; + idMethodKa = kUnidentified; + idMethodPr = kUnidentified; + idMethodEl = kUnidentified; + idMethodDe = kUnidentified; + + if (selPion(track, idMethodPi)) { + trackIsPion = true; + BITSET(trackIdTag, ID_BIT_PI); + } + if (selKaon(track, idMethodKa)) { + trackIsKaon = true; + BITSET(trackIdTag, ID_BIT_KA); + } + if (selProton(track, idMethodPr)) { + trackIsProton = true; + BITSET(trackIdTag, ID_BIT_PR); + } + if (selElectron(track, idMethodEl)) { + trackIsElectron = true; + BITSET(trackIdTag, ID_BIT_EL); + } + if (selDeuteron(track, idMethodDe)) { + trackIsDeuteron = true; + BITSET(trackIdTag, ID_BIT_DE); + } + + if constexpr (analysisType == doPurityProcessing) { + if (trackIsPion) { + if (track.sign() > 0 && mcPart.pdgCode() != kPiPlus) { + trackIsPion = false; + } + if (track.sign() < 0 && mcPart.pdgCode() != kPiMinus) { + trackIsPion = false; + } + } + if (trackIsKaon) { + if (track.sign() > 0 && mcPart.pdgCode() != kKPlus) { + trackIsKaon = false; + } + if (track.sign() < 0 && mcPart.pdgCode() != kKMinus) { + trackIsKaon = false; + } + } + if (trackIsProton) { + if (track.sign() > 0 && mcPart.pdgCode() != kProton) { + trackIsProton = false; + } + if (track.sign() < 0 && mcPart.pdgCode() != kProtonBar) { + trackIsProton = false; + } + } + if (trackIsElectron) { + if (track.sign() > 0 && mcPart.pdgCode() != kPositron) { + trackIsElectron = false; + } + if (track.sign() < 0 && mcPart.pdgCode() != kElectron) { + trackIsElectron = false; + } + } + if (trackIsDeuteron) { + if (track.sign() > 0 && mcPart.pdgCode() != kDeuteron) { + trackIsDeuteron = false; + } + if (track.sign() < 0 && mcPart.pdgCode() != -kDeuteron) { + trackIsDeuteron = false; + } + } + } + + executeTrackAnalysisPart(track, trackIdTag, + idMethodPi, trackIsPion, nPiMinus, nPiPlus, + idMethodKa, trackIsKaon, nKaMinus, nKaPlus, + idMethodPr, trackIsProton, nProton, nPBar, + idMethodEl, trackIsElectron, nElPlus, nElMinus, + idMethodDe, trackIsDeuteron, nDePlus, nDeMinus); + } // track loop ends + + executeSparseAnalysisPart(centrality, nTrack, nK0s, + nRejectedPiPlus, nRejectedPiMinus, nKaon, + nPiPlus, nKaPlus, nProton, nElPlus, nDePlus, + nPiMinus, nKaMinus, nPBar, nElMinus, nDeMinus); + + executeEventInfoPart(collision, centrality, v0sTablePerColl.size(), tracksTablePerColl, + nTrack, nK0s, + nPiPlus, nKaPlus, nProton, nElPlus, nDePlus, + nPiMinus, nKaMinus, nPBar, nElMinus, nDeMinus); + } // collision loop ends + } + } // + + //____________________________________Process Funtion For Analysis Starts Here____________________________________// + + void processData(MyCollisions const& collisions, MyV0s const& V0s, MyTracks const& tracks) + { + recoEvent.fill(HIST("recoEvent/ProcessType"), doDataProcessing); + executeAnalysis(collisions, V0s, tracks); + + } // Process Function Ends + PROCESS_SWITCH(KaonIsospinFluctuations, processData, "Process for Data", true); + + void processReco(MyCollisionsWithMcLabels const& collisions, MyV0sWithMcLabels const& V0s, MyTracksWithMcLabels const& tracks, aod::McParticles const&) + { + recoEvent.fill(HIST("recoEvent/ProcessType"), doRecoProcessing); + executeAnalysis(collisions, V0s, tracks); + + } // Process function is over + PROCESS_SWITCH(KaonIsospinFluctuations, processReco, "Process for Reco", false); + + void processPurity(MyCollisionsWithMcLabels const& collisions, MyV0sWithMcLabels const& V0s, MyTracksWithMcLabels const& tracks, aod::McParticles const&) + { + recoEvent.fill(HIST("recoEvent/ProcessType"), doPurityProcessing); + executeAnalysis(collisions, V0s, tracks); + + } // Process function is over + PROCESS_SWITCH(KaonIsospinFluctuations, processPurity, "Process for Purity", false); + + Preslice mcTracksPerMcCollisionPreslice = o2::aod::mcparticle::mcCollisionId; + + using MyMcCollisions = aod::McCollisions; + void processGen(MyMcCollisions const&, MyCollisionsWithMcLabels const& collisions, aod::McParticles const& mcParticles) + { + recoEvent.fill(HIST("recoEvent/ProcessType"), doGenProcessing); + float centrality = -1; + for (const auto& collision : collisions) { + if (!collision.has_mcCollision()) { + continue; + } + centrality = -1; + const auto& mcColl = collision.mcCollision(); + + centrality = collision.centFT0C(); + if (cfgCentAxis.centAxisType == 1) { + centrality = collision.centFT0M(); + } else if (cfgCentAxis.centAxisType == 2) { + centrality = collision.multFT0M(); + } else if (cfgCentAxis.centAxisType == 3) { + centrality = collision.multFT0C(); + } + + // group over mcParticles + const auto mcTracksTablePerMcColl = mcParticles.sliceBy(mcTracksPerMcCollisionPreslice, mcColl.globalIndex()); + + float nRejectedPiPlus = 0; + float nRejectedPiMinus = 0; + + float nK0s = 0; + float nPiPlus = 0; + float nPiMinus = 0; + float nKaPlus = 0; + float nKaMinus = 0; + float nProton = 0; + float nPBar = 0; + float nElPlus = 0; + float nElMinus = 0; + float nDePlus = 0; + float nDeMinus = 0; + float nTrack = 0; + float nKaon = 0; + + for (const auto& mcTrack : mcTracksTablePerMcColl) { + if (!mcTrack.isPhysicalPrimary()) { + continue; + } + + if (mcTrack.pdgCode() == kK0Short && + k0sSelCut.cfgK0sLowPt < mcTrack.pt() && mcTrack.pt() < k0sSelCut.cfgK0sHighPt && + std::abs(mcTrack.y()) < k0sSelCut.cfgK0sRapitidy) { + nK0s++; + fillGenTrackQA(genAnalysis, mcTrack); + } + + if (mcTrack.pt() <= cfgTrackCuts.cfgTrackPtLow || mcTrack.pt() >= cfgTrackCuts.cfgTrackPtHigh || std::abs(mcTrack.eta()) >= cfgTrackCuts.cfgTrackEta) { + continue; + } + + if (mcTrack.pdgCode() == kPiPlus) { + fillGenTrackQA(genAnalysis, mcTrack); + nPiPlus++; + } else if (mcTrack.pdgCode() == kPiMinus) { + fillGenTrackQA(genAnalysis, mcTrack); + nPiMinus++; + } else if (mcTrack.pdgCode() == kKPlus) { + fillGenTrackQA(genAnalysis, mcTrack); + nKaPlus++; + } else if (mcTrack.pdgCode() == kKMinus) { + fillGenTrackQA(genAnalysis, mcTrack); + nKaMinus++; + } else if (mcTrack.pdgCode() == kProton) { + fillGenTrackQA(genAnalysis, mcTrack); + nProton++; + } else if (mcTrack.pdgCode() == kProtonBar) { + fillGenTrackQA(genAnalysis, mcTrack); + nPBar++; + } else if (mcTrack.pdgCode() == kElectron) { + fillGenTrackQA(genAnalysis, mcTrack); + nElPlus++; + } else if (mcTrack.pdgCode() == kPositron) { + fillGenTrackQA(genAnalysis, mcTrack); + nElMinus++; + } else if (mcTrack.pdgCode() == kDeuteron) { + fillGenTrackQA(genAnalysis, mcTrack); + nDePlus++; + } else if (mcTrack.pdgCode() == -kDeuteron) { + fillGenTrackQA(genAnalysis, mcTrack); + nDeMinus++; + } + + nTrack++; + } // mcTrack loop is over + nKaon = nKaPlus + nKaMinus; + executeSparseAnalysisPart(centrality, nTrack, nK0s, + nRejectedPiPlus, nRejectedPiMinus, nKaon, + nPiPlus, nKaPlus, nProton, nElPlus, nDePlus, + nPiMinus, nKaMinus, nPBar, nElMinus, nDeMinus); + + executeEventInfoPart(mcColl, centrality, 0, mcTracksTablePerMcColl, + nTrack, nK0s, + nPiPlus, nKaPlus, nProton, nElPlus, nDePlus, + nPiMinus, nKaMinus, nPBar, nElMinus, nDeMinus); + } // collision loop is over + } + PROCESS_SWITCH(KaonIsospinFluctuations, processGen, "Process for Gen", false); + + template + void getV0MCount(const T& mcTrack, float& multV0M) + { + if ((-3.7 < mcTrack.eta() && mcTrack.eta() < -1.7) || (2.8 < mcTrack.eta() && mcTrack.eta() < 5.1)) { + if (doFWDPtDependentCheck) { + if (mcTrack.pt() > cfgFWDPtCut) { + multV0M++; // V0C: at -3.7 < η < -1.7 (backward direction). + // V0A: at 2.8 < η < 5.1 (forward direction). + } + } else { + multV0M++; + } + } + } + + void processSim(MyMcCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + auto finalParticleIdList = (std::vector)cfgFinalParticleIdList; + auto nonFinalParticleIdList = (std::vector)cfgNonFinalParticleIdList; + std::sort(finalParticleIdList.begin(), finalParticleIdList.end()); + std::sort(nonFinalParticleIdList.begin(), nonFinalParticleIdList.end()); + + recoEvent.fill(HIST("recoEvent/ProcessType"), doSimProcessing); + float centrality = -1; + for (const auto& mcColl : mcCollisions) { + centrality = -1; + + if (cfgVtxZCheck) { + if (std::abs(mcColl.posZ()) >= cutZvertex) { + continue; + } + } + // group over mcParticles + const auto mcTracksTablePerMcColl = mcParticles.sliceBy(mcTracksPerMcCollisionPreslice, mcColl.globalIndex()); + + float nRejectedPiPlus = 0; + float nRejectedPiMinus = 0; + float nK0s = 0; + float nPiPlus = 0; + float nPiMinus = 0; + float nKaPlus = 0; + float nKaMinus = 0; + float nProton = 0; + float nPBar = 0; + float nElPlus = 0; + float nElMinus = 0; + float nDePlus = 0; + float nDeMinus = 0; + float nTrack = 0; + float nKaon = 0; + + float multV0M = 0; + + for (const auto& mcTrack : mcTracksTablePerMcColl) { + + if (cfgCountFinalParticles) { + if (!mcTrack.has_daughters() && std::binary_search(finalParticleIdList.begin(), finalParticleIdList.end(), mcTrack.pdgCode())) { + getV0MCount(mcTrack, multV0M); + } + } + if (cfgCountNonFinalParticles) { + if (mcTrack.has_daughters() && std::binary_search(nonFinalParticleIdList.begin(), nonFinalParticleIdList.end(), mcTrack.pdgCode())) { + getV0MCount(mcTrack, multV0M); + } + } + + if (cfgCountPhysicalPrimAndFinalParticles) { + if (!mcTrack.has_daughters() && mcTrack.isPhysicalPrimary()) { + if (!(std::abs(mcTrack.pdgCode()) == kNuE || std::abs(mcTrack.pdgCode()) == kNuMu || std::abs(mcTrack.pdgCode()) == kNuTau)) { + // Removed invisible neutrinos; + getV0MCount(mcTrack, multV0M); + } + } + } + + if (!mcTrack.isPhysicalPrimary()) { + continue; + } + + if (mcTrack.pdgCode() == kK0Short && + k0sSelCut.cfgK0sLowPt < mcTrack.pt() && mcTrack.pt() < k0sSelCut.cfgK0sHighPt && + std::abs(mcTrack.y()) < k0sSelCut.cfgK0sRapitidy) { + nK0s++; + fillGenTrackQA(genAnalysis, mcTrack); + } + + if (mcTrack.pt() <= cfgTrackCuts.cfgTrackPtLow || mcTrack.pt() >= cfgTrackCuts.cfgTrackPtHigh || std::abs(mcTrack.eta()) >= cfgTrackCuts.cfgTrackEta) { + continue; + } + + if (mcTrack.pdgCode() == kPiPlus) { + fillGenTrackQA(genAnalysis, mcTrack); + nPiPlus++; + } else if (mcTrack.pdgCode() == kPiMinus) { + fillGenTrackQA(genAnalysis, mcTrack); + nPiMinus++; + } else if (mcTrack.pdgCode() == kKPlus) { + fillGenTrackQA(genAnalysis, mcTrack); + nKaPlus++; + } else if (mcTrack.pdgCode() == kKMinus) { + fillGenTrackQA(genAnalysis, mcTrack); + nKaMinus++; + } else if (mcTrack.pdgCode() == kProton) { + fillGenTrackQA(genAnalysis, mcTrack); + nProton++; + } else if (mcTrack.pdgCode() == kProtonBar) { + fillGenTrackQA(genAnalysis, mcTrack); + nPBar++; + } else if (mcTrack.pdgCode() == kElectron) { + fillGenTrackQA(genAnalysis, mcTrack); + nElPlus++; + } else if (mcTrack.pdgCode() == kPositron) { + fillGenTrackQA(genAnalysis, mcTrack); + nElMinus++; + } else if (mcTrack.pdgCode() == kDeuteron) { + fillGenTrackQA(genAnalysis, mcTrack); + nDePlus++; + } else if (mcTrack.pdgCode() == -kDeuteron) { + fillGenTrackQA(genAnalysis, mcTrack); + nDeMinus++; + } + + nTrack++; + } // mcTrack loop is over + nKaon = nKaPlus + nKaMinus; + centrality = multV0M; + executeSparseAnalysisPart(centrality, nTrack, nK0s, + nRejectedPiPlus, nRejectedPiMinus, nKaon, + nPiPlus, nKaPlus, nProton, nElPlus, nDePlus, + nPiMinus, nKaMinus, nPBar, nElMinus, nDeMinus); + + executeEventInfoPart(mcColl, centrality, 0, mcTracksTablePerMcColl, + nTrack, nK0s, + nPiPlus, nKaPlus, nProton, nElPlus, nDePlus, + nPiMinus, nKaMinus, nPBar, nElMinus, nDeMinus); + } // collision loop is over + } + PROCESS_SWITCH(KaonIsospinFluctuations, processSim, "Process for Sim", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx b/PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx new file mode 100644 index 00000000000..c2b1a3d71ab --- /dev/null +++ b/PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx @@ -0,0 +1,1263 @@ +// 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 meanPtFlucId.cxx +/// \brief Calculate EbyE fluctuations with cumulant method. +/// For charged particles and identified particles. +/// For RUN-3 +/// +/// \author Tanu Gahlaut + +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" +#include "Framework/O2DatabasePDGPlugin.h" + +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/Core/RecoDecay.h" +#include "CCDB/BasicCCDBManager.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; +using namespace std; + +struct MeanPtFlucId { + Configurable nPBins{"nPBins", 300, ""}; + Configurable nPartBins{"nPartBins", 250, ""}; + Configurable nCentBins{"nCentBins", 101, ""}; + Configurable nRapBins{"nRapBins", 100, ""}; + Configurable nPhiBins{"nPhiBins", 100, ""}; + Configurable cfgCutPtMax{"cfgCutPtMax", 3.0, "maximum pT"}; + Configurable cfgCutPtMin{"cfgCutPtMin", 0.15, "minimum pT"}; + Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut"}; + Configurable cfgCutRap{"cfgCutRap", 0.5, "Rapidity Cut"}; + Configurable cfgCutDcaZ{"cfgCutDcaZ", 0.3, "DCAz cut"}; + Configurable cfgCutPosZ{"cfgCutPosZ", 10.0, "cut for vertex Z"}; + Configurable cfgCutNSig2{"cfgCutNSig2", 2.0, "nSigma cut (2)"}; + Configurable cfgCutNSig3{"cfgCutNSig3", 3.0, "nSigma cut (3)"}; + Configurable cfgCutPiPtMin{"cfgCutPiPtMin", 0.2, "Minimum pion p_{T} cut"}; + Configurable cfgCutKaPtMin{"cfgCutKaPtMin", 0.3, "Minimum kaon p_{T} cut"}; + Configurable cfgCutPrPtMin{"cfgCutPrPtMin", 0.5, "Minimum proton p_{T} cut"}; + Configurable cfgCutPiThrsldP{"cfgCutPiThrsldP", 0.6, "Threshold p cut pion"}; + Configurable cfgCutKaThrsldP{"cfgCutKaThrsldP", 0.6, "Threshold p cut kaon"}; + Configurable cfgCutPrThrsldP{"cfgCutPrThrsldP", 1.0, "Threshold p cut proton "}; + Configurable cfgCutPiP1{"cfgCutPiP1", 0.5, "pion p cut-1"}; + Configurable cfgCutPiP2{"cfgCutPiP2", 0.6, "pion p cut-2"}; + Configurable cfgCutKaP1{"cfgCutKaP1", 0.4, "kaon p cut-1"}; + Configurable cfgCutKaP2{"cfgCutKaP2", 0.6, "kaon p cut-2"}; + Configurable cfgCutKaP3{"cfgCutKaP3", 1.2, "kaon p cut-3"}; + Configurable cfgCutPrP1{"cfgCutPrP1", 0.9, "proton p cut-1"}; + Configurable cfgCutPrP2{"cfgCutPrP2", 1.0, "proton p cut-2"}; + Configurable cfgLoadEff{"cfgLoadEff", true, "Load efficiency"}; + Configurable cfgWeightPtCh{"cfgWeightPtCh", true, "Efficiency correction (pT) for charged particles"}; + Configurable cfgWeightPtId{"cfgWeightPtId", false, "Efficiency correction (pT) "}; + Configurable cfgWeightPtYId{"cfgWeightPtYId", false, "Efficiency correction (pT, rap) "}; + Configurable cfgWeightPtEtaId{"cfgWeightPtEtaId", true, "Efficiency correction (pT, Eta) "}; + Configurable cfgPurityId{"cfgPurityId", false, "Purity correction"}; + Configurable cfgMCReco{"cfgMCReco", false, ""}; + Configurable cfgMCTruth{"cfgMCTruth", false, ""}; + Configurable cfgPosZ{"cfgPosZ", true, "Position Z"}; + Configurable cfgSel8{"cfgSel8", true, "Sel8 trigger"}; + Configurable cfgNoSameBunchPileup{"cfgNoSameBunchPileup", true, "kNoSameBunchPileup"}; + Configurable cfgIsVertexITSTPC{"cfgIsVertexITSTPC", true, "kIsVertexITSTPC"}; + Configurable cfgRejTrk{"cfgRejTrk", true, "Rejected Tracks"}; + ConfigurableAxis multTPCBins{"multTPCBins", {150, 0, 150}, "TPC Multiplicity bins"}; + ConfigurableAxis multFT0MBins{"multFT0MBins", {1000, 0, 5000}, "Forward Multiplicity bins"}; + ConfigurableAxis multFT0MMCBins{"multFT0MMCBins", {250, 0, 250}, "Forward Multiplicity bins"}; + ConfigurableAxis dcaXYBins{"dcaXYBins", {100, -0.15, 0.15}, "dcaXY bins"}; + ConfigurableAxis dcaZBins{"dcaZBins", {100, -1.2, 1.2}, "dcaZ bins"}; + ConfigurableAxis qNBins{"qNBins", {1000, 0., 100.}, "nth moments bins"}; + ConfigurableAxis tpNBins{"tpNBins", {300, 0., 3000.}, ""}; + ConfigurableAxis tpDBins{"tpDBins", {100, 0., 2000.}, ""}; + Configurable> ptBins{"ptBins", {0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00, 1.05, 1.10, 1.15, 1.20, 1.25, 1.30, 1.35, 1.40, 1.45, 1.50, 1.55, 1.60, 1.65, 1.70, 1.75, 1.80, 1.85, 1.90, 1.95, 2.00}, "p_{T} bins"}; + Configurable> etaBins{"etaBins", {-0.8, -0.75, -0.7, -0.65, -0.6, -0.55, -0.5, -0.45, -0.4, -0.35, -0.3, -0.25, -0.2, -0.15, -0.1, -0.05, 0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8}, "#eta bins"}; + Configurable> rapBins{"rapBins", {-0.6, -0.55, -0.5, -0.45, -0.4, -0.35, -0.3, -0.25, -0.2, -0.15, -0.1, -0.05, 0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6}, "#rap bins"}; + + Configurable cfgUrlCCDB{"cfgUrlCCDB", "http://ccdb-test.cern.ch:8080", "url of ccdb"}; + Configurable cfgPathCCDB{"cfgPathCCDB", "Users/t/tgahlaut/weightCorr/", "Path for ccdb-object"}; + + Service ccdb; + + using MyAllTracks = soa::Join; + using MyRun3Collisions = soa::Join; + using MyRun3MCCollisions = soa::Join; + using MyMCTracks = soa::Join; + + Service pdg; + + HistogramRegistry hist{"hist", {}, OutputObjHandlingPolicy::AnalysisObject}; + + TH1D* hWeightPt = nullptr; + TH1D* hPurePt = nullptr; + TH2D* hWeightPtRap = nullptr; + TH2D* hWeightPtEta = nullptr; + TH1D* hWeightPtPi = nullptr; + TH1D* hWeightPtKa = nullptr; + TH1D* hWeightPtPr = nullptr; + TH1D* hPurePtPi = nullptr; + TH1D* hPurePtKa = nullptr; + TH1D* hPurePtPr = nullptr; + TH2D* hWeightPtRapPi = nullptr; + TH2D* hWeightPtRapKa = nullptr; + TH2D* hWeightPtRapPr = nullptr; + TH2D* hWeightPtEtaPi = nullptr; + TH2D* hWeightPtEtaKa = nullptr; + TH2D* hWeightPtEtaPr = nullptr; + + void init(InitContext const&) + { + if (cfgLoadEff) { + // Set CCDB url + ccdb->setURL(cfgUrlCCDB.value); + ccdb->setCaching(true); + + TList* lst = ccdb->getForTimeStamp(cfgPathCCDB.value, -1); + hWeightPt = reinterpret_cast(lst->FindObject("hWeightPt")); + hWeightPtPi = reinterpret_cast(lst->FindObject("hWeightPtPi")); + hWeightPtKa = reinterpret_cast(lst->FindObject("hWeightPtKa")); + hWeightPtPr = reinterpret_cast(lst->FindObject("hWeightPtPr")); + hPurePtPi = reinterpret_cast(lst->FindObject("hPurePtPi")); + hPurePtKa = reinterpret_cast(lst->FindObject("hPurePtKa")); + hPurePtPr = reinterpret_cast(lst->FindObject("hPurePtPr")); + hWeightPtRapPi = reinterpret_cast(lst->FindObject("hWeightPtRapPi")); + hWeightPtRapKa = reinterpret_cast(lst->FindObject("hWeightPtRapKa")); + hWeightPtRapPr = reinterpret_cast(lst->FindObject("hWeightPtRapPr")); + hWeightPtEtaPi = reinterpret_cast(lst->FindObject("hWeightPtEtaPi")); + hWeightPtEtaKa = reinterpret_cast(lst->FindObject("hWeightPtEtaKa")); + hWeightPtEtaPr = reinterpret_cast(lst->FindObject("hWeightPtEtaPr")); + + if (!hWeightPt || !hWeightPtPi || !hWeightPtKa || !hWeightPtPr || !hWeightPtRapPi || !hWeightPtRapKa || !hWeightPtRapPr || !hWeightPtEtaPi || !hWeightPtEtaKa || !hWeightPtEtaPr || !hPurePtPi || !hPurePtKa || !hPurePtPr) { + LOGF(info, "FATAL!! Could not find required histograms in CCDB"); + } + } + + const AxisSpec axisEvents{10, 0, 10, "Counts"}; + const AxisSpec axisEta{etaBins, "#eta"}; + const AxisSpec axisPhi{nPhiBins, 0., +7., "#phi (rad)"}; + const AxisSpec axisY{rapBins, "y"}; + const AxisSpec axisPt{ptBins, "p_{T} (GeV/c)"}; + const AxisSpec axisPt2{40, 0., 4., "p_{T}^2 (GeV/c)^2"}; + const AxisSpec axisP{nPBins, 0., 3., "p (GeV/c)"}; + const AxisSpec axisInnerParam{nPBins, 0., 3., "p_{InnerParam } (GeV/c)"}; + const AxisSpec axisPart{nPartBins, 0., 18., " "}; + const AxisSpec axisQn{qNBins, ""}; + const AxisSpec axisTpN{tpNBins, "(Q_{1}^{2} - Q_{2})"}; + const AxisSpec axisTpD{tpDBins, "N_{pairs}"}; + const AxisSpec axisDeno{100, 1., 2.0, "#frac{1}{#sqrt{1 - #frac{1}{N}}}"}; + const AxisSpec axisMeanPt{100, 0., 3., "M(p_{T}) (GeV/c)"}; + const AxisSpec axisMult{100, 0, 100, "N_{ch}"}; + const AxisSpec axisMultTPC{multTPCBins, "N_{TPC} "}; + const AxisSpec axisMultFT0M{multFT0MBins, "N_{FT0M}"}; + const AxisSpec axisMultFT0MMC{multFT0MMCBins, "N_{FT0M}"}; + const AxisSpec axisCentFT0C{nCentBins, 0, 101, "FT0C (%)"}; + const AxisSpec axisVtxZ{80, -20., 20., "V_{Z} (cm)"}; + const AxisSpec axisDCAz{dcaZBins, "DCA_{Z} (cm)"}; + const AxisSpec axisDCAxy{dcaXYBins, "DCA_{XY} (cm)"}; + const AxisSpec axisTPCNsigma{500, -5., 5., "n #sigma_{TPC}"}; + const AxisSpec axisTOFNsigma{500, -5., 5., "n #sigma_{TOF}"}; + const AxisSpec axisTPCSignal{100, 20., 500., "#frac{dE}{dx}"}; + const AxisSpec axisTOFSignal{200, 0.2, 1.2, "TOF #beta"}; + const AxisSpec axisChi2{40, 0., 40., "Chi2"}; + const AxisSpec axisCrossedTPC{300, 0, 300, "Crossed TPC"}; + const AxisSpec axisM2{100, 0., 1.4, "#it{m}^{2} (GeV/#it{c}^{2})^{2}"}; + + HistogramConfigSpec qNHist({HistType::kTHnSparseD, {axisMultTPC, axisQn, axisMultFT0M}}); + HistogramConfigSpec partHist({HistType::kTHnSparseD, {axisMultTPC, axisPart, axisMultFT0M}}); + HistogramConfigSpec denoHist({HistType::kTHnSparseD, {axisMultTPC, axisDeno, axisMultFT0M}}); + HistogramConfigSpec qNMCHist({HistType::kTHnSparseD, {axisMultTPC, axisQn, axisMultFT0M}}); + HistogramConfigSpec partMCHist({HistType::kTHnSparseD, {axisMultTPC, axisPart, axisMultFT0M}}); + HistogramConfigSpec denoMCHist({HistType::kTHnSparseD, {axisMultTPC, axisDeno, axisMultFT0M}}); + HistogramConfigSpec tofNSigmaHist({HistType::kTH2D, {axisP, axisTOFNsigma}}); + HistogramConfigSpec tofSignalHist({HistType::kTH2D, {axisP, axisTOFSignal}}); + HistogramConfigSpec tpcNSigmaHist({HistType::kTH2D, {axisP, axisTPCNsigma}}); + HistogramConfigSpec tpcSignalHist({HistType::kTH2D, {axisP, axisTPCSignal}}); + HistogramConfigSpec tpcTofHist({HistType::kTH2D, {axisTPCNsigma, axisTOFNsigma}}); + HistogramConfigSpec pvsM2Hist({HistType::kTH2D, {axisM2, axisP}}); + + HistogramConfigSpec tofNSigmaHist1({HistType::kTH2D, {axisInnerParam, axisTOFNsigma}}); + HistogramConfigSpec tofSignalHist1({HistType::kTH2D, {axisInnerParam, axisTOFSignal}}); + HistogramConfigSpec tpcNSigmaHist1({HistType::kTH2D, {axisInnerParam, axisTPCNsigma}}); + HistogramConfigSpec tpcSignalHist1({HistType::kTH2D, {axisInnerParam, axisTPCSignal}}); + HistogramConfigSpec tpcTofHist1({HistType::kTH2D, {axisTPCNsigma, axisTOFNsigma}}); + HistogramConfigSpec pvsM2Hist1({HistType::kTH2D, {axisM2, axisInnerParam}}); + + // QA Plots: + hist.add("QA/before/h_Counts", "Counts", kTH1D, {axisEvents}); + hist.add("QA/before/h_VtxZ", "V_{Z}", kTH1D, {axisVtxZ}); + hist.add("QA/before/h_Pt", "p_{T}", kTH1D, {axisPt}); + hist.add("QA/before/h_Eta", "#eta ", kTH1D, {axisEta}); + hist.add("QA/before/h_Phi", "#phi ", kTH1D, {axisPhi}); + hist.add("QA/before/h_DcaZ", "DCA_{Z}", kTH1D, {axisDCAz}); + hist.add("QA/before/h_DcaXY", "DCA_{XY}", kTH1D, {axisDCAxy}); + hist.add("QA/before/h2_DcaZ", "DCA_{Z}", kTH2D, {{axisPt}, {axisDCAz}}); + hist.add("QA/before/h2_DcaXY", "DCA_{XY}", kTH2D, {{axisPt}, {axisDCAxy}}); + hist.add("QA/before/h_NTPC", "N_{TPC}", kTH1D, {axisMultTPC}); + hist.add("QA/before/h_NFT0M", "FT0M Multiplicity", kTH1D, {axisMultFT0M}); + hist.add("QA/before/h_Cent", "FT0C (%)", kTH1D, {axisCentFT0C}); + hist.add("QA/before/h_CentM", "FT0M (%)", kTH1D, {axisCentFT0C}); + + hist.add("QA/before/h2_TPCSignal", "TPC Signal", tpcSignalHist); + hist.add("QA/before/h2_TOFSignal", "TOF Signal", tofSignalHist); + hist.add("QA/before/h2_pvsm2", "p vs m^{2}", pvsM2Hist); + + hist.add("QA/before/innerParam/h2_TPCSignal", "TPC Signal", tpcSignalHist1); + hist.add("QA/before/innerParam/h2_TOFSignal", "TOF Signal", tofSignalHist1); + hist.add("QA/before/innerParam/h2_pvsm2", "p vs m^{2}", pvsM2Hist1); + + hist.addClone("QA/before/", "QA/after/"); + + hist.add("QA/after/h_TPCChi2perCluster", "TPC #Chi^{2}/Cluster", kTH1D, {axisChi2}); + hist.add("QA/after/h_ITSChi2perCluster", "ITS #Chi^{2}/Cluster", kTH1D, {axisChi2}); + hist.add("QA/after/h_crossedTPC", "Crossed TPC", kTH1D, {axisCrossedTPC}); + hist.add("QA/after/h_counts_evSelCuts", "Event selection cuts", kTH1D, {axisEvents}); + hist.add("QA/after/h_VtxZReco", "Simulated Vertex Z", kTH1D, {axisVtxZ}); + + hist.add("QA/after/h2_PvsPinner", "p_{InnerParam} vs p", kTH2D, {{axisP}, {axisInnerParam}}); + hist.add("QA/after/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPt}}); + hist.add("QA/after/h2_NTPC_Cent", "N_{TPC} vs FT0C(%)", kTH2D, {{axisCentFT0C}, {axisMultTPC}}); + hist.add("QA/after/h2_NTPC_CentM", "N_{TPC} vs FT0M(%)", kTH2D, {{axisCentFT0C}, {axisMultTPC}}); + hist.add("QA/after/h2_NTPC_NFT0M", "N_{TPC} vs N_{FT0M}", kTH2D, {{axisMultFT0M}, {axisMultTPC}}); + + hist.add("QA/after/p_NTPC_NFT0M", "N_{TPC} vs N_{FT0M} (Profile)", kTProfile, {axisMultFT0M}); + hist.add("QA/after/p_NTPC_Cent", "N_{TPC} vs FT0C(%) (Profile)", kTProfile, {axisCentFT0C}); + + hist.add("QA/after/h_Pt2", "p_{T}^2", kTH1D, {axisPt2}); + hist.add("QA/after/h_Pt_weighted", "weighted pT distribution", kTH1D, {axisPt}); + hist.add("QA/after/h_Pt2_weighted", "weighted pT distribution", kTH1D, {axisPt2}); + hist.add("QA/after/h2_Pt_NFT0M", "p_{T} in Multiplicity Classes ", kTH2D, {{axisPt}, {axisMultFT0M}}); + hist.add("QA/after/h_PtEtaPhi_NFT0M", "p_{T}, #eta, #phi in Multiplicity Classes ", kTHnSparseD, {{axisPt}, {axisEta}, {axisPhi}, {axisMultFT0M}}); + hist.add("QA/after/h_PtEtaPhi_centFT0M", "p_{T}, #eta, #phi in centrality Classes ", kTHnSparseD, {{axisPt}, {axisEta}, {axisPhi}, {axisCentFT0C}}); + hist.add("QA/after/h2_pt_nch", "Truth", kTH2D, {{axisMult}, {axisPt}}); + hist.add("QA/after/h3_nft0m_pt_nch", "Reco", kTHnSparseD, {{axisMult}, {axisPt}, {axisMultFT0M}}); + hist.add("QA/after/h2_pt_nch_prof", "Truth", kTProfile, {axisMult}); + + hist.add("QA/Pion/before/h2_TPCNsigma", "n #sigma_{TPC}", tpcNSigmaHist); + hist.add("QA/Pion/before/h2_TOFNsigma", "n #sigma_{TOF}", tofNSigmaHist); + hist.add("QA/Pion/before/h2_TpcTofNsigma", "n #sigma_{TPC} vs n #sigma_{TOF}", tpcTofHist); + + hist.add("QA/Pion/h_Rap", "y ", kTH1D, {axisY}); + hist.add("QA/Pion/h_RapTruth", "y ", kTH1D, {axisY}); + hist.add("QA/Pion/h_Eta", "Pseudorapidity ", kTH1D, {axisEta}); + hist.add("QA/Pion/h_EtaTruth", "Pseudorapidity (Reco Truth) ", kTH1D, {axisEta}); + hist.add("QA/Pion/h_Phi", "Azimuthal Distribution ", kTH1D, {axisPhi}); + hist.add("QA/Pion/h_DcaZ", "DCA_{z}", kTH1D, {axisDCAz}); + hist.add("QA/Pion/h_DcaXY", "DCA_{xy}", kTH1D, {axisDCAxy}); + hist.add("QA/Pion/h_Pt", "p_{T} ", kTH1D, {axisPt}); + hist.add("QA/Pion/h_Pt2", "p_{T}^2 ", kTH1D, {axisPt2}); + hist.add("QA/Pion/h_PtPos", "p_{T} (positive) ", kTH1D, {axisPt}); + hist.add("QA/Pion/h_PtNeg", "p_{T} (negative) ", kTH1D, {axisPt}); + hist.add("QA/Pion/h_PtTruth", "p_{T} ", kTH1D, {axisPt}); + hist.add("QA/Pion/h_PtTruth2", "p_{T}^2 ", kTH1D, {axisPt2}); + hist.add("QA/Pion/h_PtPosTruth", "p_{T} (positive) ", kTH1D, {axisPt}); + hist.add("QA/Pion/h_PtNegTruth", "p_{T} (negative) ", kTH1D, {axisPt}); + hist.add("QA/Pion/h_Pt_weighted", "weighted pT distribution", kTH1D, {axisPt}); + hist.add("QA/Pion/h_Pt2_weighted", "weighted pT distribution", kTH1D, {axisPt2}); + + hist.add("QA/Pion/h2_Pt_Rap", "p_{T} vs y", kTH2D, {{axisY}, {axisPt}}); + hist.add("QA/Pion/h2_PtTruth_Rap", "p_{T} vs y", kTH2D, {{axisY}, {axisPt}}); + hist.add("QA/Pion/h2_PtTruth_Eta", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPt}}); + hist.add("QA/Pion/h2_Pt_Eta", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPt}}); + hist.add("QA/Pion/h2_DcaZ", "DCA_{z}", kTH2D, {{axisPt}, {axisDCAz}}); + hist.add("QA/Pion/h2_DcaXY", "DCA_{xy}", kTH2D, {{axisPt}, {axisDCAxy}}); + hist.add("QA/Pion/h2_Pt_Rap_weighted", "p_{T} vs y weighted", kTH2D, {{axisY}, {axisPt}}); + hist.add("QA/Pion/h2_Pt_Eta_weighted", "p_{T} vs #eta weighted", kTH2D, {{axisEta}, {axisPt}}); + hist.add("QA/Pion/h2_Pt_NFT0M", "p_{T} in Multiplicity Classes ", kTH2D, {{axisPt}, {axisMultFT0M}}); + + hist.add("QA/Pion/h_PtEtaPhi_NFT0M", "p_{T}, #eta, #phi in Multiplicity Classes ", kTHnSparseD, {{axisPt}, {axisEta}, {axisPhi}, {axisMultFT0M}}); + hist.add("QA/Pion/h_PtEtaPhi_centFT0M", "p_{T}, #eta, #phi in centrality Classes ", kTHnSparseD, {{axisPt}, {axisEta}, {axisPhi}, {axisCentFT0C}}); + + hist.add("QA/Pion/h2_PtTruth_NFT0M", "p_{T} in Multiplicity Classes ", kTH2D, {{axisPt}, {axisMultFT0M}}); + hist.add("QA/Pion/h2_pt_nch", "Reco", kTH2D, {{axisMult}, {axisPt}}); + hist.add("QA/Pion/h3_nft0m_pt_nch", "Reco", kTHnSparseD, {{axisMult}, {axisPt}, {axisMultFT0M}}); + hist.add("QA/Pion/h2_pt_nch_prof", "Reco", kTProfile, {axisMult}); + + hist.add("QA/Pion/h2_TPCNsigma", "n #sigma_{TPC}", tpcNSigmaHist); + hist.add("QA/Pion/h2_TPCNsigma_El", "n #sigma_{TPC, El}", tpcNSigmaHist); + hist.add("QA/Pion/h2_TOFNsigma_El", "n #sigma_{TOF, El}", tofNSigmaHist); + hist.add("QA/Pion/h2_TOFNsigma", "n #sigma_{TOF}", tofNSigmaHist); + hist.add("QA/Pion/h2_TpcTofNsigma", "n #sigma_{TPC} vs n #sigma_{TOF}", tpcTofHist); + hist.add("QA/Pion/h2_TPCSignal", "TPC Signal ", tpcSignalHist); + hist.add("QA/Pion/h2_TOFSignal", "TOF Signal", tofSignalHist); + hist.add("QA/Pion/h2_pvsm2", "p vs m^{2}", pvsM2Hist); + + hist.add("QA/Pion/innerParam/before/h2_TPCNsigma", "n #sigma_{TPC}", tpcNSigmaHist1); + hist.add("QA/Pion/innerParam/before/h2_TOFNsigma", "n #sigma_{TOF}", tofNSigmaHist1); + hist.add("QA/Pion/innerParam/before/h2_TpcTofNsigma", "n #sigma_{TPC} vs n #sigma_{TOF}", tpcTofHist1); + hist.add("QA/Pion/innerParam/h2_TPCNsigma", "n #sigma_{TPC}", tpcNSigmaHist1); + hist.add("QA/Pion/innerParam/h2_TPCNsigma_El", "n #sigma_{TPC, El}", tpcNSigmaHist1); + hist.add("QA/Pion/innerParam/h2_TOFNsigma_El", "n #sigma_{TOF, El}", tofNSigmaHist1); + hist.add("QA/Pion/innerParam/h2_TOFNsigma", "n #sigma_{TOF}", tofNSigmaHist1); + hist.add("QA/Pion/innerParam/h2_TpcTofNsigma", "n #sigma_{TPC} vs n #sigma_{TOF}", tpcTofHist1); + hist.add("QA/Pion/innerParam/h2_TPCSignal", "TPC Signal ", tpcSignalHist1); + hist.add("QA/Pion/innerParam/h2_TOFSignal", "TOF Signal", tofSignalHist1); + hist.add("QA/Pion/innerParam/h2_pvsm2", "p vs m^{2}", pvsM2Hist1); + + hist.addClone("QA/Pion/", "QA/Kaon/"); + hist.addClone("QA/Pion/", "QA/Proton/"); + + // Analysis Plots: + hist.add("Analysis/Charged/h_Mult", "Multiplicity", kTH1D, {axisMult}); + hist.add("Analysis/Charged/h_Mult_weighted", "Multiplicity", kTH1D, {axisMult}); + hist.add("Analysis/Charged/h_Q1", "Q1", qNHist); + hist.add("Analysis/Charged/h_Q2", "Q2", qNHist); + hist.add("Analysis/Charged/h_Q3", "Q3", qNHist); + hist.add("Analysis/Charged/h_Q4", "Q4", qNHist); + hist.add("Analysis/Charged/h_mean_pT", " ", kTH1D, {axisMeanPt}); + hist.add("Analysis/Charged/p_mean_pT_Mult_var", " ", kTProfile, {axisMultTPC}); + hist.add("Analysis/Charged/p_CheckNCh", " 1/denominator vs N_{TPC} ", kTProfile, {axisMultTPC}); + hist.add("Analysis/Charged/h_CheckNCh", " 1/denominator vs N_{TPC} ", denoHist); + hist.add("Analysis/Charged/h_Q1_var", "Q1 vs N_{TPC}", qNHist); + hist.add("Analysis/Charged/h_N_var", "N vs N_{TPC}", kTHnSparseD, {axisMultTPC, axisMult, axisMultFT0M}); + hist.add("Analysis/Charged/h_twopart_nume_Mult_var", "twopart numerator", kTHnSparseD, {axisMultTPC, axisTpN, axisMultFT0M}); + hist.add("Analysis/Charged/h_twopart_deno_Mult_var", "twopart denominator", kTHnSparseD, {axisMultTPC, axisTpD, axisMultFT0M}); + hist.add("Analysis/Charged/h_mean_pT_Mult_var", " vs N_{TPC} ", partHist); + hist.add("Analysis/Charged/h_mean_pT_Mult_skew", " vs N_{TPC} ", partHist); + hist.add("Analysis/Charged/h_mean_pT_Mult_kurto", " vs N_{TPC} ", partHist); + hist.add("Analysis/Charged/h_twopart_Mult_var", "Twopart vs N_{TPC} ", partHist); + hist.add("Analysis/Charged/h_twopart_Mult_skew", "Twopart vs N_{TPC} ", partHist); + hist.add("Analysis/Charged/h_twopart_Mult_kurto", "Twopart vs N_{TPC} ", partHist); + hist.add("Analysis/Charged/h_threepart_Mult_skew", "Threepart vs N_{TPC} ", partHist); + hist.add("Analysis/Charged/h_threepart_Mult_kurto", "Threepart vs N_{TPC} ", partHist); + hist.add("Analysis/Charged/h_fourpart_Mult_kurto", "Fourpart vs N_{TPC} ", partHist); + + hist.add("Analysis/Charged/p_twopart_MultFT0M", "Twopart vs N_{FT0M} ", kTProfile, {axisMultFT0M}); + hist.add("Analysis/Charged/p_mean_pT_MultFT0M", " vs N_{FT0M} ", kTProfile, {axisMultFT0M}); + + hist.addClone("Analysis/Charged/", "Analysis/Pion/"); + hist.addClone("Analysis/Charged/", "Analysis/Kaon/"); + hist.addClone("Analysis/Charged/", "Analysis/Proton/"); + + // MC Generated + hist.add("Gen/h_Counts", "Counts", kTH1D, {axisEvents}); + hist.add("Gen/h_VtxZ", "Vertex Z ", kTH1D, {axisVtxZ}); + hist.add("Gen/h_VtxZ_b", "Vertex Z ", kTH1D, {axisVtxZ}); + hist.add("Gen/h_NTPC", "Mid rapidity Multiplicity", kTH1D, {axisMultTPC}); + hist.add("Gen/h_NFT0C", "Forward Multiplicity", kTH1D, {axisMultFT0MMC}); + hist.add("Gen/h2_NTPC_NFT0M", "NTPC vs Forward Multiplicity", kTH2D, {{axisMultFT0M}, {axisMultTPC}}); + + hist.add("Gen/h_NSim", "Truth Multiplicity TPC", kTH1D, {axisMultTPC}); + hist.add("Gen/h2_NTPC_NSim", "Reco vs Truth Multiplicty TPC", kTH2D, {{axisMultTPC}, {axisMultTPC}}); + hist.add("Gen/h2_NChSim_NSim", "Truth Multiplicty NCh vs NTPC", kTH2D, {{axisMultTPC}, {axisMultTPC}}); + + hist.add("Gen/Charged/h_PtEtaPhi_NFT0M", "p_{T}, #eta, #phi in Multiplicity Classes ", kTHnSparseD, {{axisPt}, {axisEta}, {axisPhi}, {axisMultFT0M}}); + hist.add("Gen/Charged/h_PtEtaPhi_centFT0M", "p_{T}, #eta, #phi in centrality Classes ", kTHnSparseD, {{axisPt}, {axisEta}, {axisPhi}, {axisCentFT0C}}); + hist.add("Gen/Charged/h_EtaTruth", "#eta ", kTH1D, {axisEta}); + hist.add("Gen/Charged/h_PhiTruth", "#phi ", kTH1D, {axisPhi}); + hist.add("Gen/Charged/h_PtTruth", "p_{T} ", kTH1D, {axisPt}); + hist.add("Gen/Charged/h_PtTruth2", "p_{T}^2 ", kTH1D, {axisPt2}); + hist.add("Gen/Charged/h2_PtTruth_Eta", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPt}}); + hist.add("Gen/Charged/h2_PtTruth_NFT0M", "p_{T} in Multiplicity Classes", kTH2D, {{axisPt}, {axisMultFT0M}}); + + hist.add("Gen/Charged/h_Mult", "Multiplicity", kTH1D, {axisMult}); + hist.add("Gen/Charged/h_Mult_weighted", "Multiplicity", kTH1D, {axisMult}); + + hist.add("Gen/Charged/h2_pt_nch", "Truth", kTH2D, {{axisMult}, {axisPt}}); + hist.add("Gen/Charged/h3_nft0m_pt_nch", "Truth", kTHnSparseD, {{axisMult}, {axisPt}, {axisMultFT0M}}); + hist.add("Gen/Charged/h2_pt_nch_prof", "Truth", kTProfile, {axisMult}); + hist.add("Gen/Charged/h_mean_pT", " ", kTH1D, {axisMeanPt}); + + hist.add("Gen/Charged/h_Q1", "Q1", qNMCHist); + hist.add("Gen/Charged/h_Q2", "Q2", qNMCHist); + hist.add("Gen/Charged/h_Q3", "Q3", qNMCHist); + hist.add("Gen/Charged/h_Q4", "Q4", qNMCHist); + hist.add("Gen/Charged/h_Q1_var", "Q1 vs N_{TPC}", qNMCHist); + hist.add("Gen/Charged/h_N_var", "N vs N_{TPC}", kTHnSparseD, {axisMultTPC, axisMult, axisMultFT0M}); + hist.add("Gen/Charged/h_twopart_nume_Mult_var", "twopart numerator", kTHnSparseD, {axisMultTPC, axisTpN, axisMultFT0M}); + hist.add("Gen/Charged/h_twopart_deno_Mult_var", "twopart denominator", kTHnSparseD, {axisMultTPC, axisTpD, axisMultFT0M}); + + hist.add("Gen/Charged/p_mean_pT_Mult_var", " ", kTProfile, {axisMultTPC}); + hist.add("Gen/Charged/p_CheckNCh", " 1/denominator vs N_{TPC} ", kTProfile, {axisMultTPC}); + hist.add("Gen/Charged/h_CheckNCh", " 1/denominator vs N_{TPC} ", denoMCHist); + hist.add("Gen/Charged/h_mean_pT_Mult_var", " vs N_{TPC} ", partMCHist); + hist.add("Gen/Charged/h_mean_pT_Mult_skew", " vs N_{TPC} ", partMCHist); + hist.add("Gen/Charged/h_mean_pT_Mult_kurto", " vs N_{TPC} ", partMCHist); + hist.add("Gen/Charged/h_twopart_Mult_var", "Twopart vs N_{TPC} ", partMCHist); + hist.add("Gen/Charged/h_twopart_Mult_skew", "Twopart vs N_{TPC} ", partMCHist); + hist.add("Gen/Charged/h_twopart_Mult_kurto", "Twopart vs N_{TPC} ", partMCHist); + hist.add("Gen/Charged/h_threepart_Mult_skew", "Threepart vs N_{TPC} ", partMCHist); + hist.add("Gen/Charged/h_threepart_Mult_kurto", "Threepart vs N_{TPC} ", partMCHist); + hist.add("Gen/Charged/h_fourpart_Mult_kurto", "Fourpart vs N_{TPC} ", partMCHist); + hist.add("Gen/Charged/p_twopart_MultFT0M", "Twopart vs N_{TPC} ", kTProfile, {axisMultFT0M}); + hist.add("Gen/Charged/p_mean_pT_MultFT0M", " vs N_{TPC} ", kTProfile, {axisMultFT0M}); + + hist.addClone("Gen/Charged/", "Gen/Pion/"); + + hist.add("Gen/Pion/h_RapTruth", "y", kTH1D, {axisY}); + hist.add("Gen/Pion/h2_PtTruth_Rap", "p_{T} vs y", kTH2D, {{axisY}, {axisPt}}); + hist.add("Gen/Pion/h_PtPosTruth", "p_{T} (positive) ", kTH1D, {axisPt}); + hist.add("Gen/Pion/h_PtNegTruth", "p_{T} (negative) ", kTH1D, {axisPt}); + + hist.addClone("Gen/Pion/", "Gen/Kaon/"); + hist.addClone("Gen/Pion/", "Gen/Proton/"); + } + + enum Mode { + QA_Charged = 0, + QA_Pion, + QA_Kaon, + QA_Proton, + Analysis_Charged, + Analysis_Pion, + Analysis_Kaon, + Analysis_Proton, + Gen_Charged, + Gen_Pion, + Gen_Kaon, + Gen_Proton + }; + + static constexpr std::string_view Dire[] = { + "QA/after/", + "QA/Pion/", + "QA/Kaon/", + "QA/Proton/", + "Analysis/Charged/", + "Analysis/Pion/", + "Analysis/Kaon/", + "Analysis/Proton/", + "Gen/Charged/", + "Gen/Pion/", + "Gen/Kaon/", + "Gen/Proton/"}; + + // Event selection cuts: + template + bool selRun3Col(T const& col) + { + hist.fill(HIST("QA/after/h_counts_evSelCuts"), 0); + + if (cfgPosZ) { + if (std::abs(col.posZ()) > cfgCutPosZ) { + return false; + } + hist.fill(HIST("QA/after/h_counts_evSelCuts"), 1); + } + + if (cfgSel8) { + if (!col.sel8()) { + return false; + } + hist.fill(HIST("QA/after/h_counts_evSelCuts"), 2); + } + if (cfgNoSameBunchPileup) { + if (!col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + hist.fill(HIST("QA/after/h_counts_evSelCuts"), 4); + } + + if (cfgIsVertexITSTPC) { + if (!col.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + hist.fill(HIST("QA/after/h_counts_evSelCuts"), 5); + } + + return true; + } + + // Track selection cuts: + template + bool selTrack(T const& track) + { + if (!track.isGlobalTrack()) + return false; + + if (track.pt() < cfgCutPtMin) + return false; + + if (track.pt() > cfgCutPtMax) + return false; + + if (track.sign() == 0) + return false; + + if (std::fabs(track.dcaZ()) > cfgCutDcaZ) + return false; + + if (std::fabs(track.dcaZ()) > (0.0105 + 0.035 / std::pow(track.p(), 1.1))) + + if (std::abs(track.eta()) >= cfgCutEta) + return false; + + return true; + } + + // Cuts to reject the tracks + template + bool rejectTracks(T const& track) + { + if (((track.tpcNSigmaEl()) > -3. && + (track.tpcNSigmaEl()) < 5.) && + (std::fabs(track.tpcNSigmaPi()) > 3 && + std::fabs(track.tpcNSigmaKa()) > 3 && + std::fabs(track.tpcNSigmaPr()) > 3)) { + return true; + } + + return false; + } + + template + bool selElectrons(T const& track) + { + if (std::fabs(track.tpcNSigmaEl()) < cfgCutNSig3) { + return true; + } + + return false; + } + + // PID selction cuts for Low momentum Pions + template + bool selPi(T const& track) + { + if (track.pt() >= cfgCutPiPtMin && + track.p() <= cfgCutPiThrsldP) { + if (!track.hasTOF() && + std::fabs(track.tpcNSigmaPi()) < cfgCutNSig2) { + return true; + } + + if (track.hasTOF() && + std::fabs(track.tpcNSigmaPi()) < cfgCutNSig2 && + std::fabs(track.tofNSigmaPi()) < cfgCutNSig3) { + return true; + } + } else if (track.hasTOF() && + track.p() > cfgCutPiThrsldP && + std::fabs(track.tpcNSigmaPi()) < cfgCutNSig3 && + std::fabs(track.tofNSigmaPi()) < cfgCutNSig3) { + + return true; + } + + return false; + } + + // PID selction cuts for Low momentum Kaons + template + bool selKa(T const& track) + { + if (track.pt() >= cfgCutKaPtMin && + track.p() <= cfgCutKaThrsldP) { + if (!track.hasTOF() && + std::fabs(track.tpcNSigmaKa()) < cfgCutNSig2) { + return true; + } + + if (track.hasTOF() && + std::fabs(track.tpcNSigmaKa()) < cfgCutNSig2 && + std::fabs(track.tofNSigmaKa()) < cfgCutNSig3) { + return true; + } + } + if (track.hasTOF() && + track.p() > cfgCutKaThrsldP && + std::fabs(track.tpcNSigmaKa()) < cfgCutNSig3 && + ((std::fabs(track.tofNSigmaKa()) < cfgCutNSig3 && track.p() <= cfgCutKaP3) || + (std::fabs(track.tofNSigmaKa()) < cfgCutNSig2 && track.p() > cfgCutKaP3))) { + + return true; + } + + return false; + } + + // PID selction cuts for Low momentum Protons + template + bool selPr(T const& track) + { + + if (track.pt() >= cfgCutPrPtMin && + track.p() <= cfgCutPrThrsldP) { + if (!track.hasTOF() && + std::fabs(track.tpcNSigmaPr()) < cfgCutNSig2) { + return true; + } + + if (track.hasTOF() && + std::fabs(track.tpcNSigmaPr()) < cfgCutNSig2 && + std::fabs(track.tofNSigmaPr()) < cfgCutNSig3) { + return true; + } + } else if (track.hasTOF() && + track.p() > cfgCutPrThrsldP && + std::fabs(track.tpcNSigmaPr()) < cfgCutNSig3 && + std::fabs(track.tofNSigmaPr()) < cfgCutNSig3) { + + return true; + } + + return false; + } + + // Fill hist before selection cuts: + template + void fillBeforeQAHistos(T const& col, U const& tracks) + { + for (const auto& track : tracks) { + hist.fill(HIST("QA/before/h_Eta"), track.eta()); + hist.fill(HIST("QA/before/h_Phi"), track.phi()); + hist.fill(HIST("QA/before/h_Pt"), track.pt()); + hist.fill(HIST("QA/before/h_DcaXY"), track.dcaXY()); + hist.fill(HIST("QA/before/h_DcaZ"), track.dcaZ()); + hist.fill(HIST("QA/before/h2_DcaXY"), track.pt(), track.dcaXY()); + hist.fill(HIST("QA/before/h2_DcaZ"), track.pt(), track.dcaZ()); + } + hist.fill(HIST("QA/before/h_VtxZ"), col.posZ()); + hist.fill(HIST("QA/before/h_Counts"), 2); + hist.fill(HIST("QA/before/h_NTPC"), col.multNTracksHasTPC()); + hist.fill(HIST("QA/before/h_Cent"), col.centFT0C()); + hist.fill(HIST("QA/after/h_CentM"), col.centFT0M()); + hist.fill(HIST("QA/before/h_NFT0M"), col.multFT0M()); + } + + // Fill hist after selection cuts: + template + void fillAfterQAHistos(T const& col) + { + hist.fill(HIST("QA/after/h_VtxZ"), col.posZ()); + hist.fill(HIST("QA/after/h_Counts"), 2); + hist.fill(HIST("QA/after/h_NTPC"), col.multNTracksHasTPC()); + hist.fill(HIST("QA/after/h_Cent"), col.centFT0C()); + hist.fill(HIST("QA/after/h_CentM"), col.centFT0M()); + hist.fill(HIST("QA/after/h_NFT0M"), col.multFT0M()); + hist.fill(HIST("QA/after/h2_NTPC_NFT0M"), col.multFT0M(), col.multNTracksHasTPC()); + hist.fill(HIST("QA/after/h2_NTPC_Cent"), col.centFT0C(), col.multNTracksHasTPC()); + hist.fill(HIST("QA/after/h2_NTPC_CentM"), col.centFT0M(), col.multNTracksHasTPC()); + hist.fill(HIST("QA/after/p_NTPC_Cent"), col.centFT0C(), col.multNTracksHasTPC()); + hist.fill(HIST("QA/after/p_NTPC_NFT0M"), col.multFT0M(), col.multNTracksHasTPC()); + } + + // Fill Charged particles QA: + template + void fillChargedQAHistos(T const& track, int nFT0M, double centFT0M) + { + hist.fill(HIST("QA/after/h_Eta"), track.eta()); + hist.fill(HIST("QA/after/h_Phi"), track.phi()); + hist.fill(HIST("QA/after/h_Pt"), track.pt()); + hist.fill(HIST("QA/after/h_Pt2"), track.pt() * track.pt()); + hist.fill(HIST("QA/after/h2_Pt_NFT0M"), track.pt(), nFT0M); + hist.fill(HIST("QA/after/h_PtEtaPhi_NFT0M"), track.pt(), track.eta(), track.phi(), nFT0M); + hist.fill(HIST("QA/after/h_PtEtaPhi_centFT0M"), track.pt(), track.eta(), track.phi(), centFT0M); + hist.fill(HIST("QA/after/h2_PvsPinner"), track.p(), track.tpcInnerParam()); + hist.fill(HIST("QA/after/h2_Pt_Eta"), track.eta(), track.pt()); + hist.fill(HIST("QA/after/h_DcaZ"), track.dcaZ()); + hist.fill(HIST("QA/after/h_DcaXY"), track.dcaXY()); + hist.fill(HIST("QA/after/h2_DcaXY"), track.pt(), track.dcaXY()); + hist.fill(HIST("QA/after/h2_DcaZ"), track.pt(), track.dcaZ()); + + hist.fill(HIST("QA/after/h_TPCChi2perCluster"), track.tpcChi2NCl()); + hist.fill(HIST("QA/after/h_ITSChi2perCluster"), track.itsChi2NCl()); + hist.fill(HIST("QA/after/h_crossedTPC"), track.tpcNClsCrossedRows()); + } + + // Fill before PID cut QA hist: + template + void fillBeforePIDQAHistos(T const& track) + { + hist.fill(HIST("QA/before/h2_TOFSignal"), track.p(), track.beta()); + hist.fill(HIST("QA/before/h2_TPCSignal"), track.p(), track.tpcSignal()); + hist.fill(HIST("QA/before/h2_pvsm2"), track.mass() * track.mass(), track.p()); + + hist.fill(HIST("QA/Pion/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaPi()); + hist.fill(HIST("QA/Pion/before/h2_TOFNsigma"), track.p(), track.tofNSigmaPi()); + hist.fill(HIST("QA/Pion/before/h2_TpcTofNsigma"), track.tpcNSigmaPi(), track.tofNSigmaPi()); + hist.fill(HIST("QA/Proton/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaPr()); + hist.fill(HIST("QA/Proton/before/h2_TOFNsigma"), track.p(), track.tofNSigmaPr()); + hist.fill(HIST("QA/Proton/before/h2_TpcTofNsigma"), track.tpcNSigmaPr(), track.tofNSigmaPr()); + hist.fill(HIST("QA/Kaon/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaKa()); + hist.fill(HIST("QA/Kaon/before/h2_TOFNsigma"), track.p(), track.tofNSigmaKa()); + hist.fill(HIST("QA/Kaon/before/h2_TpcTofNsigma"), track.tpcNSigmaKa(), track.tofNSigmaKa()); + + hist.fill(HIST("QA/before/innerParam/h2_TOFSignal"), track.tpcInnerParam(), track.beta()); + hist.fill(HIST("QA/before/innerParam/h2_TPCSignal"), track.tpcInnerParam(), track.tpcSignal()); + hist.fill(HIST("QA/before/innerParam/h2_pvsm2"), track.mass() * track.mass(), track.tpcInnerParam()); + + hist.fill(HIST("QA/Pion/innerParam/before/h2_TPCNsigma"), track.tpcInnerParam(), track.tpcNSigmaPi()); + hist.fill(HIST("QA/Pion/innerParam/before/h2_TOFNsigma"), track.tpcInnerParam(), track.tofNSigmaPi()); + hist.fill(HIST("QA/Pion/innerParam/before/h2_TpcTofNsigma"), track.tpcNSigmaPi(), track.tofNSigmaPi()); + hist.fill(HIST("QA/Proton/innerParam/before/h2_TPCNsigma"), track.tpcInnerParam(), track.tpcNSigmaPr()); + hist.fill(HIST("QA/Proton/innerParam/before/h2_TOFNsigma"), track.tpcInnerParam(), track.tofNSigmaPr()); + hist.fill(HIST("QA/Proton/innerParam/before/h2_TpcTofNsigma"), track.tpcNSigmaPr(), track.tofNSigmaPr()); + hist.fill(HIST("QA/Kaon/innerParam/before/h2_TPCNsigma"), track.tpcInnerParam(), track.tpcNSigmaKa()); + hist.fill(HIST("QA/Kaon/innerParam/before/h2_TOFNsigma"), track.tpcInnerParam(), track.tofNSigmaKa()); + hist.fill(HIST("QA/Kaon/innerParam/before/h2_TpcTofNsigma"), track.tpcNSigmaKa(), track.tofNSigmaKa()); + } + + // Moments Calculation: + void moments(double pt, double weight, double& Q1, double& Q2, double& Q3, double& Q4) + { + Q1 += pt * weight; + Q2 += pt * pt * weight; + Q3 += pt * pt * pt * weight; + Q4 += pt * pt * pt * pt * weight; + } + + template + float getCorrectedWeight(T1 hWeightPt, T1 hPurePt, T2 hWeightPtY, T2 hWeightPtEta, double pt, double rap, double eta, bool cfgWeightPt, bool cfgWeightPtY, bool cfgWeightPtEta, bool cfgPurity) + { + float weight = 1.0; + float purity = 1.0; + if (cfgPurity) { + purity = hPurePt->GetBinContent(hPurePt->FindBin(pt)); + } else { + purity = 1.0; + } + + if (cfgWeightPt) { + float weightPt = hWeightPt->GetBinContent(hWeightPt->FindBin(pt)); + weight = purity * weightPt; + } else if (cfgWeightPtY) { + float weightPtY = hWeightPtY->GetBinContent(hWeightPtY->FindBin(rap, pt)); + weight = purity * weightPtY; + } else if (cfgWeightPtEta) { + float weightPtEta = hWeightPtEta->GetBinContent(hWeightPtEta->FindBin(eta, pt)); + weight = purity * weightPtEta; + } else { + weight = 1.0; + } + return weight; + } + + // Fill after PID cut QA hist: + template + void fillIdParticleQAHistos(T const& track, double rap, double nSigmaTPC, double nSigmaTOF, int nFT0M, double centFT0M, T1 hWeightPt, T1 hPurePt, T2 hWeightPtY, T2 hWeightPtEta, bool cfgWeightPtId, bool cfgWeightPtYId, bool cfgWeightPtEtaId, bool cfgPurityId, int& N, double& NW, double& Q1, double& Q2, double& Q3, double& Q4, float& weight) + { + double pt = track.pt(); + double eta = track.eta(); + weight = getCorrectedWeight(hWeightPt, hPurePt, hWeightPtY, hWeightPtEta, pt, rap, eta, cfgWeightPtId, cfgWeightPtYId, cfgWeightPtEtaId, cfgPurityId); + if (weight == 0) + return; + + NW += weight; + N++; + moments(pt, weight, Q1, Q2, Q3, Q4); + + if (cfgWeightPtYId) + hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_Rap_weighted"), rap, pt, weight); + + if (cfgWeightPtEtaId) + hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_Eta_weighted"), eta, pt, weight); + + hist.fill(HIST(Dire[Mode]) + HIST("h_Pt_weighted"), pt, weight); + hist.fill(HIST(Dire[Mode]) + HIST("h_Pt2_weighted"), pt * pt, weight); + + hist.fill(HIST(Dire[Mode]) + HIST("h_Pt"), pt); + hist.fill(HIST(Dire[Mode]) + HIST("h_Pt2"), pt * pt); + hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_NFT0M"), pt, nFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h_PtEtaPhi_NFT0M"), pt, eta, track.phi(), nFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h_PtEtaPhi_centFT0M"), pt, eta, track.phi(), centFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_Eta"), eta, pt); + if (track.sign() > 0) { + hist.fill(HIST(Dire[Mode]) + HIST("h_PtPos"), pt); + } + if (track.sign() < 0) { + hist.fill(HIST(Dire[Mode]) + HIST("h_PtNeg"), pt); + } + + hist.fill(HIST(Dire[Mode]) + HIST("h_Eta"), eta); + hist.fill(HIST(Dire[Mode]) + HIST("h_Phi"), track.phi()); + hist.fill(HIST(Dire[Mode]) + HIST("h_Rap"), rap); + hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_Rap"), rap, pt); + hist.fill(HIST(Dire[Mode]) + HIST("h_DcaZ"), track.dcaZ()); + hist.fill(HIST(Dire[Mode]) + HIST("h_DcaXY"), track.dcaXY()); + hist.fill(HIST(Dire[Mode]) + HIST("h2_DcaZ"), pt, track.dcaZ()); + hist.fill(HIST(Dire[Mode]) + HIST("h2_DcaXY"), pt, track.dcaXY()); + + hist.fill(HIST(Dire[Mode]) + HIST("h2_TPCNsigma_El"), track.p(), track.tpcNSigmaEl()); + hist.fill(HIST(Dire[Mode]) + HIST("h2_TOFNsigma_El"), track.p(), track.tofNSigmaEl()); + hist.fill(HIST(Dire[Mode]) + HIST("h2_TPCNsigma"), track.p(), nSigmaTPC); + hist.fill(HIST(Dire[Mode]) + HIST("h2_TOFNsigma"), track.p(), nSigmaTOF); + hist.fill(HIST(Dire[Mode]) + HIST("h2_TpcTofNsigma"), nSigmaTPC, nSigmaTOF); + hist.fill(HIST(Dire[Mode]) + HIST("h2_TPCSignal"), track.p(), track.tpcSignal()); + hist.fill(HIST(Dire[Mode]) + HIST("h2_TOFSignal"), track.p(), track.beta()); + hist.fill(HIST(Dire[Mode]) + HIST("h2_pvsm2"), track.mass() * track.mass(), track.p()); + hist.fill(HIST("QA/after/h2_TPCSignal"), track.p(), track.tpcSignal()); + hist.fill(HIST("QA/after/h2_TOFSignal"), track.p(), track.beta()); + hist.fill(HIST("QA/after/h2_pvsm2"), track.mass() * track.mass(), track.p()); + + hist.fill(HIST(Dire[Mode]) + HIST("innerParam/h2_TPCNsigma_El"), track.tpcInnerParam(), track.tpcNSigmaEl()); + hist.fill(HIST(Dire[Mode]) + HIST("innerParam/h2_TOFNsigma_El"), track.tpcInnerParam(), track.tofNSigmaEl()); + hist.fill(HIST(Dire[Mode]) + HIST("innerParam/h2_TPCNsigma"), track.tpcInnerParam(), nSigmaTPC); + hist.fill(HIST(Dire[Mode]) + HIST("innerParam/h2_TOFNsigma"), track.tpcInnerParam(), nSigmaTOF); + hist.fill(HIST(Dire[Mode]) + HIST("innerParam/h2_TpcTofNsigma"), nSigmaTPC, nSigmaTOF); + hist.fill(HIST(Dire[Mode]) + HIST("innerParam/h2_TPCSignal"), track.tpcInnerParam(), track.tpcSignal()); + hist.fill(HIST(Dire[Mode]) + HIST("innerParam/h2_TOFSignal"), track.tpcInnerParam(), track.beta()); + hist.fill(HIST(Dire[Mode]) + HIST("innerParam/h2_pvsm2"), track.mass() * track.mass(), track.tpcInnerParam()); + hist.fill(HIST("QA/after/innerParam/h2_TPCSignal"), track.tpcInnerParam(), track.tpcSignal()); + hist.fill(HIST("QA/after/innerParam/h2_TOFSignal"), track.tpcInnerParam(), track.beta()); + hist.fill(HIST("QA/after/innerParam/h2_pvsm2"), track.mass() * track.mass(), track.tpcInnerParam()); + } + + template + void fillPtMCHist(double pt, double eta, double rap, int nFT0M, int pid, int pdgCodePos, int pdgCodeNeg) + { + hist.fill(HIST(Dire[Mode]) + HIST("h_PtTruth"), pt); + hist.fill(HIST(Dire[Mode]) + HIST("h_PtTruth2"), pt * pt); + hist.fill(HIST(Dire[Mode]) + HIST("h_EtaTruth"), eta); + hist.fill(HIST(Dire[Mode]) + HIST("h_RapTruth"), rap); + hist.fill(HIST(Dire[Mode]) + HIST("h2_PtTruth_NFT0M"), pt, nFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h2_PtTruth_Rap"), rap, pt); + hist.fill(HIST(Dire[Mode]) + HIST("h2_PtTruth_Eta"), eta, pt); + + if (pid == pdgCodePos) { + hist.fill(HIST(Dire[Mode]) + HIST("h_PtPosTruth"), pt); + } + if (pid == pdgCodeNeg) { + hist.fill(HIST(Dire[Mode]) + HIST("h_PtNegTruth"), pt); + } + } + + template + void fillAnalysisHistos(int nTPC, int nFT0M, int N, double NW, double Q1, double Q2, double Q3, double Q4) + { + if (NW == 0) { + return; + } + double twopart1 = ((Q1 * Q1) - Q2); + double threepart1 = ((Q1 * Q1 * Q1) - (3 * Q2 * Q1) + 2 * Q3); + double fourpart1 = ((Q1 * Q1 * Q1 * Q1) - (6 * Q2 * Q1 * Q1) + (3 * Q2 * Q2) + (8 * Q3 * Q1) - 6 * Q4); + + hist.fill(HIST(Dire[Mode]) + HIST("h_Mult"), N); + hist.fill(HIST(Dire[Mode]) + HIST("h_Mult_weighted"), NW); + hist.fill(HIST(Dire[Mode]) + HIST("h_Q1"), nTPC, Q1, nFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h_Q2"), nTPC, Q2, nFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h_Q3"), nTPC, Q3, nFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h_Q4"), nTPC, Q4, nFT0M); + + if (NW > 1) { + double meanPt = Q1 / NW; + double nPair = (NW * (NW - 1)); + double twopart = twopart1 / nPair; + double checkNDenoVar = (1 / std::sqrt(1 - (1 / NW))); + hist.fill(HIST(Dire[Mode]) + HIST("h_mean_pT"), meanPt); + hist.fill(HIST(Dire[Mode]) + HIST("p_mean_pT_Mult_var"), nTPC, meanPt); + hist.fill(HIST(Dire[Mode]) + HIST("p_mean_pT_MultFT0M"), nFT0M, meanPt); + hist.fill(HIST(Dire[Mode]) + HIST("h_mean_pT_Mult_var"), nTPC, meanPt, nFT0M); + + hist.fill(HIST(Dire[Mode]) + HIST("h_Q1_var"), nTPC, Q1, nFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h_N_var"), nTPC, N, nFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h_twopart_nume_Mult_var"), nTPC, twopart1, nFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h_twopart_deno_Mult_var"), nTPC, nPair, nFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h_twopart_Mult_var"), nTPC, twopart, nFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("p_CheckNCh"), nTPC, checkNDenoVar); + hist.fill(HIST(Dire[Mode]) + HIST("h_CheckNCh"), nTPC, checkNDenoVar, nFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("p_twopart_MultFT0M"), nFT0M, twopart); + + if (NW > 2) { + double nTriplet = (NW * (NW - 1) * (NW - 2)); + double threepart = threepart1 / nTriplet; + hist.fill(HIST(Dire[Mode]) + HIST("h_mean_pT_Mult_skew"), nTPC, meanPt, nFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h_twopart_Mult_skew"), nTPC, twopart, nFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h_threepart_Mult_skew"), nTPC, threepart, nFT0M); + + if (NW > 3) { + double nQuad = (NW * (NW - 1) * (NW - 2) * (NW - 3)); + double fourpart = fourpart1 / nQuad; + hist.fill(HIST(Dire[Mode]) + HIST("h_mean_pT_Mult_kurto"), nTPC, meanPt, nFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h_twopart_Mult_kurto"), nTPC, twopart, nFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h_threepart_Mult_kurto"), nTPC, threepart, nFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h_fourpart_Mult_kurto"), nTPC, fourpart, nFT0M); + } + } + } + } + + template + void fillMeanPt(int N, int nFT0M, double pt, float w) + { + hist.fill(HIST(Dire[Mode]) + HIST("h2_pt_nch"), N, pt, w); + hist.fill(HIST(Dire[Mode]) + HIST("h2_pt_nch_prof"), N, pt, w); + hist.fill(HIST(Dire[Mode]) + HIST("h3_nft0m_pt_nch"), N, pt, nFT0M, w); + } + + template + void fillHistos(T const& col, U const& tracks) + { + int nCh = 0, nTPC = 0, nFT0M = 0; + double centFT0M = 0, vtxZ = 0, vtxZSim = 0; + double nChW = 0; + + int nPi = 0, nKa = 0, nPr = 0; + double nPiW = 0, nKaW = 0, nPrW = 0; + double ptCh = 0, q1Ch = 0, q2Ch = 0, q3Ch = 0, q4Ch = 0; + double ptPi = 0, q1Pi = 0, q2Pi = 0, q3Pi = 0, q4Pi = 0; + double ptPr = 0, q1Pr = 0, q2Pr = 0, q3Pr = 0, q4Pr = 0; + double ptKa = 0, q1Ka = 0, q2Ka = 0, q3Ka = 0, q4Ka = 0; + + int nChSim = 0, nSim = 0, nFT0CSim = 0; + int nPiSim = 0, nKaSim = 0, nPrSim = 0; + double eta = 0, etaSim = -999, rapSim = -999; + double ptChSim = 0, q1ChSim = 0, q2ChSim = 0, q3ChSim = 0, q4ChSim = 0; + double ptPiSim = 0, q1PiSim = 0, q2PiSim = 0, q3PiSim = 0, q4PiSim = 0; + double ptPrSim = 0, q1PrSim = 0, q2PrSim = 0, q3PrSim = 0, q4PrSim = 0; + double ptKaSim = 0, q1KaSim = 0, q2KaSim = 0, q3KaSim = 0, q4KaSim = 0; + + float wghtCh = 1.0, wghtPi = 1.0, wghtKa = 1.0, wghtPr = 1.0; + + if constexpr (DataFlag) { + nTPC = col.multNTracksHasTPC(); + nFT0M = col.multFT0M(); + centFT0M = col.centFT0M(); + vtxZ = col.posZ(); + + fillAfterQAHistos(col); + for (const auto& track : tracks) { + if (!selTrack(track)) { + continue; + } + + double nSigmaTPCPi = track.tpcNSigmaPi(); + double nSigmaTPCKa = track.tpcNSigmaKa(); + double nSigmaTPCPr = track.tpcNSigmaPr(); + double nSigmaTOFPi = track.tofNSigmaPi(); + double nSigmaTOFKa = track.tofNSigmaKa(); + double nSigmaTOFPr = track.tofNSigmaPr(); + double rapPi = track.rapidity(MassPiPlus); + double rapKa = track.rapidity(MassKPlus); + double rapPr = track.rapidity(MassProton); + + if (std::fabs(track.eta()) < 0.8) { + ptCh = track.pt(); + wghtCh = getCorrectedWeight(hWeightPt, hPurePt, hWeightPtRap, hWeightPtEta, ptCh, 0.0, eta, cfgWeightPtCh, false, false, false); + nChW += wghtCh; + nCh++; + moments(ptCh, wghtCh, q1Ch, q2Ch, q3Ch, q4Ch); + + hist.fill(HIST("QA/after/h_Pt_weighted"), ptCh, wghtCh); + hist.fill(HIST("QA/after/h_Pt2_weighted"), ptCh * ptCh, wghtCh); + + fillChargedQAHistos(track, nFT0M, centFT0M); + + fillBeforePIDQAHistos(track); + + if (rejectTracks(track)) { + return; + } + + if (selPi(track)) { + fillIdParticleQAHistos(track, rapPi, nSigmaTPCPi, nSigmaTOFPi, nFT0M, centFT0M, hWeightPtPi, hPurePtPi, hWeightPtRapPi, hWeightPtEtaPi, cfgWeightPtId, cfgWeightPtYId, cfgWeightPtEtaId, cfgPurityId, nPi, nPiW, q1Pi, q2Pi, q3Pi, q4Pi, wghtPi); + } + + if (selKa(track)) { + fillIdParticleQAHistos(track, rapKa, nSigmaTPCKa, nSigmaTOFKa, nFT0M, centFT0M, hWeightPtKa, hPurePtKa, hWeightPtRapKa, hWeightPtEtaKa, cfgWeightPtId, cfgWeightPtYId, cfgWeightPtEtaId, cfgPurityId, nKa, nKaW, q1Ka, q2Ka, q3Ka, q4Ka, wghtKa); + } + + if (selPr(track)) { + fillIdParticleQAHistos(track, rapPr, nSigmaTPCPr, nSigmaTOFPr, nFT0M, centFT0M, hWeightPtPr, hPurePtPr, hWeightPtRapPr, hWeightPtEtaPr, cfgWeightPtId, cfgWeightPtYId, cfgWeightPtEtaId, cfgPurityId, nPr, nPrW, q1Pr, q2Pr, q3Pr, q4Pr, wghtPr); + } + } + } + } else if constexpr (RecoFlag) { + if (!col.has_mcCollision()) { + LOGF(warning, "No MC collision for this collision, skip..."); + return; + } + nTPC = col.multNTracksHasTPC(); + nFT0M = col.multFT0M(); + centFT0M = col.centFT0M(); + vtxZ = col.posZ(); + + fillAfterQAHistos(col); + + vtxZSim = col.mcCollision().posZ(); + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + LOGF(warning, "No MC Particle for this track, skip..."); + continue; + } + auto mcPart = track.mcParticle(); + int pid = mcPart.pdgCode(); + + double nSigmaTPCPi = track.tpcNSigmaPi(); + double nSigmaTPCKa = track.tpcNSigmaKa(); + double nSigmaTPCPr = track.tpcNSigmaPr(); + double nSigmaTOFPi = track.tofNSigmaPi(); + double nSigmaTOFKa = track.tofNSigmaKa(); + double nSigmaTOFPr = track.tofNSigmaPr(); + double rapPi = track.rapidity(MassPiPlus); + double rapKa = track.rapidity(MassKPlus); + double rapPr = track.rapidity(MassProton); + + //______________________________Reconstructed Level____________________________________________________// + + if (selTrack(track)) { + + eta = track.eta(); + ptCh = track.pt(); + wghtCh = getCorrectedWeight(hWeightPt, hPurePt, hWeightPtRap, hWeightPtEta, ptCh, 0.0, eta, cfgWeightPtCh, false, false, false); + nChW += wghtCh; + nCh++; + moments(ptCh, wghtCh, q1Ch, q2Ch, q3Ch, q4Ch); + fillChargedQAHistos(track, nFT0M, centFT0M); + + hist.fill(HIST("QA/after/h_Pt_weighted"), ptCh, wghtCh); + hist.fill(HIST("QA/after/h_Pt2_weighted"), ptCh * ptCh, wghtCh); + + fillBeforePIDQAHistos(track); + + if (cfgRejTrk == true && rejectTracks(track)) { + return; + } + + if (selPi(track)) { + ptPi = track.pt(); + fillIdParticleQAHistos(track, rapPi, nSigmaTPCPi, nSigmaTOFPi, nFT0M, centFT0M, hWeightPtPi, hPurePtPi, hWeightPtRapPi, hWeightPtEtaPi, cfgWeightPtId, cfgWeightPtYId, cfgWeightPtEtaId, cfgPurityId, nPi, nPiW, q1Pi, q2Pi, q3Pi, q4Pi, wghtPi); + if (std::abs(pid) == kPiPlus) { + fillPtMCHist(ptPi, eta, rapPi, nFT0M, pid, kPiPlus, kPiMinus); + } + } + if (selKa(track)) { + ptKa = track.pt(); + fillIdParticleQAHistos(track, rapKa, nSigmaTPCKa, nSigmaTOFKa, nFT0M, centFT0M, hWeightPtKa, hPurePtKa, hWeightPtRapKa, hWeightPtEtaKa, cfgWeightPtId, cfgWeightPtYId, cfgWeightPtEtaId, cfgPurityId, nKa, nKaW, q1Ka, q2Ka, q3Ka, q4Ka, wghtKa); + if (std::abs(pid) == kKPlus) { + fillPtMCHist(ptKa, eta, rapKa, nFT0M, pid, kKPlus, kKMinus); + } + } + + if (selPr(track)) { + ptPr = track.pt(); + fillIdParticleQAHistos(track, rapPr, nSigmaTPCPr, nSigmaTOFPr, nFT0M, centFT0M, hWeightPtPr, hPurePtPr, hWeightPtRapPr, hWeightPtEtaPr, cfgWeightPtId, cfgWeightPtYId, cfgWeightPtEtaId, cfgPurityId, nPr, nPrW, q1Pr, q2Pr, q3Pr, q4Pr, wghtPr); + if (std::abs(pid) == kProton) { + fillPtMCHist(ptPr, eta, rapPr, nFT0M, pid, kProton, kProtonBar); + } + } + } + + //___________________________________Truth Level____________________________________________________// + if (!mcPart.isPhysicalPrimary()) { + continue; + } + auto charge = 0.; + auto* pd = pdg->GetParticle(pid); + if (pd != nullptr) { + charge = pd->Charge(); + } + if (std::fabs(charge) < 1e-3) { + continue; + } + if (std::abs(pid) != kElectron && std::abs(pid) != kMuonMinus && std::abs(pid) != kPiPlus && std::abs(pid) != kKPlus && std::abs(pid) != kProton) { + continue; + } + + if (std::fabs(mcPart.eta()) < 0.8) { + nSim++; + } + + if (mcPart.eta() > -3.3 || mcPart.eta() < -2.1) { + nFT0CSim++; + } + + if (mcPart.pt() > cfgCutPtMin && mcPart.pt() < cfgCutPtMax) { + + if (std::abs(mcPart.eta()) < 0.8) { + nChSim++; + ptChSim = mcPart.pt(); + etaSim = mcPart.eta(); + moments(ptChSim, 1.0, q1ChSim, q2ChSim, q3ChSim, q4ChSim); + hist.fill(HIST("Gen/Charged/h_PtTruth"), ptChSim); + hist.fill(HIST("Gen/Charged/h_PtTruth2"), ptChSim * ptChSim); + hist.fill(HIST("Gen/Charged/h2_PtTruth_NFT0M"), ptChSim, nFT0M); + hist.fill(HIST("Gen/Charged/h2_PtTruth_Eta"), etaSim, ptChSim); + hist.fill(HIST("Gen/Charged/h_EtaTruth"), etaSim); + hist.fill(HIST("Gen/Charged/h_PhiTruth"), mcPart.phi()); + + hist.fill(HIST("Gen/Charged/h_PhiTruth"), mcPart.phi()); + hist.fill(HIST("Gen/Charged/h_PtEtaPhi_NFT0M"), ptChSim, etaSim, mcPart.phi(), nFT0M); + hist.fill(HIST("Gen/Charged/h_PtEtaPhi_centFT0M"), ptChSim, etaSim, mcPart.phi(), centFT0M); + + if (std::abs(pid) == kPiPlus && mcPart.pt() >= cfgCutPiPtMin) { + rapSim = mcPart.y(); + nPiSim++; + ptPiSim = mcPart.pt(); + moments(ptPiSim, 1.0, q1PiSim, q2PiSim, q3PiSim, q4PiSim); + fillPtMCHist(ptPiSim, etaSim, rapSim, nFT0M, pid, kPiPlus, kPiMinus); + + hist.fill(HIST("Gen/Pion/h_PhiTruth"), mcPart.phi()); + hist.fill(HIST("Gen/Pion/h_PtEtaPhi_NFT0M"), ptPiSim, etaSim, mcPart.phi(), nFT0M); + hist.fill(HIST("Gen/Pion/h_PtEtaPhi_centFT0M"), ptPiSim, etaSim, mcPart.phi(), centFT0M); + } + + if (std::abs(pid) == kKPlus && mcPart.pt() >= cfgCutKaPtMin) { + nKaSim++; + ptKaSim = mcPart.pt(); + moments(ptKaSim, 1.0, q1KaSim, q2KaSim, q3KaSim, q4KaSim); + fillPtMCHist(ptKaSim, etaSim, rapSim, nFT0M, pid, kKPlus, kKMinus); + + hist.fill(HIST("Gen/Kaon/h_PhiTruth"), mcPart.phi()); + hist.fill(HIST("Gen/Kaon/h_PtEtaPhi_NFT0M"), ptKaSim, etaSim, mcPart.phi(), nFT0M); + hist.fill(HIST("Gen/Kaon/h_PtEtaPhi_centFT0M"), ptKaSim, etaSim, mcPart.phi(), centFT0M); + } + + if (std::abs(pid) == kProton && mcPart.pt() >= cfgCutPrPtMin) { + nPrSim++; + ptPrSim = mcPart.pt(); + moments(ptPrSim, 1.0, q1PrSim, q2PrSim, q3PrSim, q4PrSim); + fillPtMCHist(ptPrSim, etaSim, rapSim, nFT0M, pid, kProton, kProtonBar); + + hist.fill(HIST("Gen/Proton/h_PhiTruth"), mcPart.phi()); + hist.fill(HIST("Gen/Proton/h_PtEtaPhi_NFT0M"), ptPrSim, etaSim, mcPart.phi(), nFT0M); + hist.fill(HIST("Gen/Proton/h_PtEtaPhi_centFT0M"), ptPrSim, etaSim, mcPart.phi(), centFT0M); + } + } + } + } + + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + LOGF(warning, "No MC Particle for this track, skip..."); + continue; + } + auto mcPart = track.mcParticle(); + int pid = mcPart.pdgCode(); + + if (selTrack(track)) { + double pt = track.pt(); + double eta = track.eta(); + float wght = getCorrectedWeight(hWeightPt, hPurePt, hWeightPtRap, hWeightPtEta, pt, 0.0, eta, cfgWeightPtCh, false, false, false); + fillMeanPt(nCh, nFT0M, pt, wght); + + if (selPi(track)) { + float wghtId = getCorrectedWeight(hWeightPtPi, hPurePtPi, hWeightPtRapPi, hWeightPtEtaPi, pt, 0.0, eta, cfgWeightPtId, cfgWeightPtYId, cfgWeightPtEtaId, cfgPurityId); + fillMeanPt(nPi, nFT0M, pt, wghtId); + } + if (selKa(track)) { + float wghtId = getCorrectedWeight(hWeightPtKa, hPurePtKa, hWeightPtRapKa, hWeightPtEtaKa, pt, 0.0, eta, cfgWeightPtId, cfgWeightPtYId, cfgWeightPtEtaId, cfgPurityId); + fillMeanPt(nKa, nFT0M, pt, wghtId); + } + if (selPr(track)) { + float wghtId = getCorrectedWeight(hWeightPtPr, hPurePtPr, hWeightPtRapPr, hWeightPtEtaPr, pt, 0.0, eta, cfgWeightPtId, cfgWeightPtYId, cfgWeightPtEtaId, cfgPurityId); + fillMeanPt(nPr, nFT0M, pt, wghtId); + } + } + + if (!mcPart.isPhysicalPrimary()) { + continue; + } + auto charge = 0.; + auto* pd = pdg->GetParticle(pid); + if (pd != nullptr) { + charge = pd->Charge(); + } + if (std::fabs(charge) < 1e-3) { + continue; + } + if (std::abs(pid) != kElectron && std::abs(pid) != kMuonMinus && std::abs(pid) != kPiPlus && std::abs(pid) != kKPlus && std::abs(pid) != kProton) { + continue; + } + + if (mcPart.pt() > cfgCutPtMin && mcPart.pt() < cfgCutPtMax) { + + if (std::abs(mcPart.eta()) < 0.8) { + double pt = mcPart.pt(); + float wght = 1.0; + fillMeanPt(nChSim, nFT0M, pt, wght); + + if (std::abs(pid) == kPiPlus && mcPart.pt() >= cfgCutPiPtMin) { + fillMeanPt(nPiSim, nFT0M, pt, wght); + } + if (std::abs(pid) == kKPlus && mcPart.pt() >= cfgCutKaPtMin) { + fillMeanPt(nKaSim, nFT0M, pt, wght); + } + if (std::abs(pid) == kProton && mcPart.pt() >= cfgCutPrPtMin) { + fillMeanPt(nPrSim, nFT0M, pt, wght); + } + } + } + } + + hist.fill(HIST("Gen/h_Counts"), 2); + hist.fill(HIST("QA/after/h_VtxZReco"), vtxZ); + hist.fill(HIST("Gen/h_VtxZ"), vtxZSim); + + if (nSim > 0) + hist.fill(HIST("Gen/h_NSim"), nSim); + + if (nSim > 0 && nChSim > 0) + hist.fill(HIST("Gen/h2_NChSim_NSim"), nSim, nChSim); + + if (nSim > 0 && nTPC > 0) + hist.fill(HIST("Gen/h2_NTPC_NSim"), nSim, nTPC); + + hist.fill(HIST("Gen/h_NTPC"), nTPC); + hist.fill(HIST("Gen/h_NFT0C"), nFT0CSim); + hist.fill(HIST("Gen/h2_NTPC_NFT0M"), nFT0M, nTPC); + + double nChSim1 = static_cast(nChSim); + double nPiSim1 = static_cast(nPiSim); + double nKaSim1 = static_cast(nKaSim); + double nPrSim1 = static_cast(nPrSim); + + fillAnalysisHistos(nTPC, nFT0M, nChSim, nChSim1, q1ChSim, q2ChSim, q3ChSim, q4ChSim); + fillAnalysisHistos(nTPC, nFT0M, nPiSim, nPiSim1, q1PiSim, q2PiSim, q3PiSim, q4PiSim); + fillAnalysisHistos(nTPC, nFT0M, nKaSim, nKaSim1, q1KaSim, q2KaSim, q3KaSim, q4KaSim); + fillAnalysisHistos(nTPC, nFT0M, nPrSim, nPrSim1, q1PrSim, q2PrSim, q3PrSim, q4PrSim); + } + + fillAnalysisHistos(nTPC, nFT0M, nCh, nChW, q1Ch, q2Ch, q3Ch, q4Ch); + fillAnalysisHistos(nTPC, nFT0M, nPi, nPiW, q1Pi, q2Pi, q3Pi, q4Pi); + fillAnalysisHistos(nTPC, nFT0M, nKa, nKaW, q1Ka, q2Ka, q3Ka, q4Ka); + fillAnalysisHistos(nTPC, nFT0M, nPr, nPrW, q1Pr, q2Pr, q3Pr, q4Pr); + } + + void processRun3(MyRun3Collisions::iterator const& col, MyAllTracks const& tracks) + { + // Before Collision and Track Cuts: + fillBeforeQAHistos(col, tracks); + + // After Collision and Track Cuts: + if (selRun3Col(col)) { + fillHistos(col, tracks); + } + } + PROCESS_SWITCH(MeanPtFlucId, processRun3, "Process for Run-3", false); + + void processMCRecoSimRun3(MyRun3MCCollisions::iterator const& col, aod::McCollisions const&, MyMCTracks const& tracks, aod::McParticles const&) + { + // Before Collision and Track Cuts: + fillBeforeQAHistos(col, tracks); + + hist.fill(HIST("Gen/h_VtxZ_b"), col.mcCollision().posZ()); + + // After Collision and Track Cuts: + if (selRun3Col(col)) { + fillHistos(col, tracks); + } + } + PROCESS_SWITCH(MeanPtFlucId, processMCRecoSimRun3, "process MC Reconstructed & Truth Run-3", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/EbyEFluctuations/Tasks/nchCumulantsId.cxx b/PWGCF/EbyEFluctuations/Tasks/nchCumulantsId.cxx new file mode 100644 index 00000000000..e9bdb714580 --- /dev/null +++ b/PWGCF/EbyEFluctuations/Tasks/nchCumulantsId.cxx @@ -0,0 +1,671 @@ +// 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 NchCumulantsId.cxx +/// \brief Event by Event conserved charges fluctuations +/// it is meant to be a blank page for further developments. +/// \author Pravata Panigrahi :: Sadhana Dash (sadhana@phy.iitb.ac.in) and Rahul Verma (rahul.verma@iitb.ac.in) +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" +#include "Framework/O2DatabasePDGPlugin.h" + +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "TLorentzVector.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; // for constants +using namespace std; + +struct NchCumulantsId { + + HistogramRegistry hist{"hist", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // PDG data base + Service pdgDB; + + Configurable cfgCutPosZ{"cfgCutPosZ", 10.0, "cut for vertex Z"}; + Configurable cfgCutDcaXY{"cfgCutDcaXY", 0.12, "cut for dcaXY"}; + Configurable cfgCutDcaZ{"cfgCutDcaZ", 0.3, "cut for dcaZ"}; + Configurable cfgCutEta{"cfgCutEta", 0.8, "cut for eta"}; + + void init(InitContext const&) + { + // QA check axes + const AxisSpec axisEvents{1, 0, 1, "Counts"}; + const AxisSpec axisEta{100, -1., +1., "#eta"}; + const AxisSpec axisPt{100, 0., 3., "p_{T} (GeV/c)"}; + const AxisSpec axisP{100, 0., 5., "p (GeV/c)"}; + const AxisSpec axisTPCInnerParam{100, 0, 3, "P_innerParam_Gev"}; + const AxisSpec axisdEdx(100, 20, 500, {"#frac{dE}{dx}"}); + const AxisSpec axisVtxZ{80, -20., 20., "V_{Z} (cm)"}; + const AxisSpec axisDCAz{200, -3., 3., "DCA_{Z} (cm)"}; + const AxisSpec axisDCAxy{200, -3., 3., "DCA_{XY} (cm)"}; + const AxisSpec axisMultFT0(150, 0, 1500, "MultFT0"); + const AxisSpec axisCent(103, -1., 102., "FT0C(%)"); + const AxisSpec axisPhi(80, -1, 7, "phi"); + + const AxisSpec axisTOFBeta = {40, -2.0, 2.0, "tofBeta"}; + const AxisSpec axisTPCSignal = {100, -1, 1000, "tpcSignal"}; + const AxisSpec axisTPCNSigma = {200, -10.0, 10.0, "n#sigma_{TPC}"}; + const AxisSpec axisTOFNSigma = {200, -10.0, 10.0, "n#sigma_{TOF}"}; + const AxisSpec axisTOFExpMom = {200, 0.0f, 10.0f, "#it{p}_{tofExpMom} (GeV/#it{c})"}; + + const AxisSpec axisNch(100, -50, 50, "Net_charge_dN"); + const AxisSpec axisPosCh(101, -1, 100, "Pos_charge"); + const AxisSpec axisNegCh(101, -1, 100, "Neg_charge"); + const AxisSpec axisNt(201, -1, 200, "Mult_midRap_Nch"); + const AxisSpec axisPrCh(101, -1, 100, "Pr_charge"); + const AxisSpec axisAPrCh(101, -1, 100, "APr_charge"); + const AxisSpec axisKaCh(101, -1, 100, "Ka_charge"); + const AxisSpec axisAKaCh(101, -1, 100, "AKa_charge"); + const AxisSpec axisPiCh(101, -1, 100, "Pion_Positive"); + const AxisSpec axisAPiCh(101, -1, 100, "Pion_Negative"); + + HistogramConfigSpec qnHist1({HistType::kTHnSparseD, {axisNch, axisPosCh, axisNegCh, axisPrCh, axisAPrCh, axisKaCh, axisAKaCh, axisNt, axisCent}}); + HistogramConfigSpec qnHist2({HistType::kTHnSparseD, {axisNch, axisPosCh, axisNegCh, axisPiCh, axisAPiCh, axisKaCh, axisAKaCh, axisNt, axisCent}}); + + HistogramConfigSpec histPPt({HistType::kTH2F, {axisP, axisPt}}); + HistogramConfigSpec histPTpcInnerParam({HistType::kTH2F, {axisP, axisTPCInnerParam}}); + HistogramConfigSpec histPTpcSignal({HistType::kTH2F, {axisP, axisTPCSignal}}); + HistogramConfigSpec histTpcInnerParamTpcSignal({HistType::kTH2F, {axisTPCInnerParam, axisTPCSignal}}); + HistogramConfigSpec histPBeta({HistType::kTH2F, {axisP, axisTOFBeta}}); + HistogramConfigSpec histTpcInnerParamBeta({HistType::kTH2F, {axisTPCInnerParam, axisTOFBeta}}); + HistogramConfigSpec histPTpcNSigma({HistType::kTH2F, {axisP, axisTPCNSigma}}); + HistogramConfigSpec histPtTpcNSigma({HistType::kTH2F, {axisPt, axisTPCNSigma}}); + HistogramConfigSpec histTpcInnerParamTpcNSigma({HistType::kTH2F, {axisTPCInnerParam, axisTPCNSigma}}); + HistogramConfigSpec histTofExpMomTpcNSigma({HistType::kTH2F, {axisTOFExpMom, axisTPCNSigma}}); + HistogramConfigSpec histPTofNSigma({HistType::kTH2F, {axisP, axisTOFNSigma}}); + HistogramConfigSpec histPtTofNSigma({HistType::kTH2F, {axisPt, axisTOFNSigma}}); + HistogramConfigSpec histTpcInnerParamTofNSigma({HistType::kTH2F, {axisTPCInnerParam, axisTOFNSigma}}); + HistogramConfigSpec histTofExpMomTofNSigma({HistType::kTH2F, {axisTOFExpMom, axisTOFNSigma}}); + HistogramConfigSpec histTpcNSigmaTofNSigma({HistType::kTH2F, {axisTPCNSigma, axisTOFNSigma}}); + + // QA check histos + + hist.add("QA/events/preSel/h_VtxZ", "V_{Z}", kTH1D, {axisVtxZ}); + hist.add("QA/events/preSel/h_Counts", "Counts", kTH1D, {axisEvents}); + hist.add("QA/events/preSel/multFT0", "multFT0", kTH1F, {axisMultFT0}); + hist.add("QA/events/preSel/centFT0", "centFT0", kTH1F, {axisCent}); + hist.addClone("QA/events/preSel/", "QA/events/postSel/"); + hist.add("QA/events/postSel/net_charge", "net_charge", kTH1F, {axisNch}); + hist.add("QA/events/postSel/Nt_centFT", "Mid_rap_Mult_VS_Cent", kTH2D, {{axisCent}, {axisNt}}); + + hist.add("QA/tracks/preSel/h_P", "p (Gev/c)", kTH1D, {axisP}); + hist.add("QA/tracks/preSel/h_P_InnerParameter", "p_InnerParameter (Gev/c)", kTH1D, {axisTPCInnerParam}); + hist.add("QA/tracks/preSel/h_Pt", "p_{T} (TPC & TPC+TOF)", kTH1D, {axisPt}); + hist.add("QA/tracks/preSel/h_Eta", "#eta ", kTH1D, {axisEta}); + hist.add("QA/tracks/preSel/h_phi", "#phi ", kTH1D, {axisPhi}); + hist.add("QA/tracks/preSel/h2_Pt_DcaZ", "DCA_{z}", kTH2D, {{axisPt}, {axisDCAz}}); + hist.add("QA/tracks/preSel/h2_Pt_DcaXY", "DCA_{xy}", kTH2D, {{axisPt}, {axisDCAxy}}); + hist.add("QA/tracks/preSel/h2_p_DcaZ", "DCA_{z}", kTH2D, {{axisP}, {axisDCAz}}); + hist.add("QA/tracks/preSel/h2_p_DcaXY", "DCA_{xy}", kTH2D, {{axisP}, {axisDCAxy}}); + hist.add("QA/tracks/preSel/dE_dx1", "dE/dx vs p", kTH2F, {axisP, axisdEdx}); + hist.add("QA/tracks/preSel/dE_dx2", "dE/dx vs innerparam", kTH2F, {axisTPCInnerParam, axisdEdx}); + hist.add("QA/tracks/preSel/p_pt", "p_vs_pT", kTH2F, {axisP, axisPt}); + hist.add("QA/tracks/preSel/p_pInnerParameter", "p_vs_innerparameter", kTH2F, {axisP, axisTPCInnerParam}); + + // tofBeta + hist.add("QA/tracks/preSel/p_beta", "p_beta", histPBeta); + hist.add("QA/tracks/preSel/tpcInnerParam_beta", "tpcInnerParam_beta", histTpcInnerParamBeta); + + // Look at Pion + hist.add("QA/tracks/preSel/Pi/NoId/p_tpcNSigma", "p_tpcNSigma", histPTpcNSigma); + hist.add("QA/tracks/preSel/Pi/NoId/pt_tpcNSigma", "pt_tpcNSigma", histPtTpcNSigma); + hist.add("QA/tracks/preSel/Pi/NoId/tpcInnerParam_tpcNSigma", "tpcInnerParam_tpcNSigma", histTpcInnerParamTpcNSigma); + hist.add("QA/tracks/preSel/Pi/NoId/tofExpMom_tpcNSigma", "tofExpMom_tpcNSigma", histTofExpMomTpcNSigma); + hist.add("QA/tracks/preSel/Pi/NoId/p_tofNSigma", "p_tofNSigma", histPTofNSigma); + hist.add("QA/tracks/preSel/Pi/NoId/pt_tofNSigma", "pt_tofNSigma", histPtTofNSigma); + hist.add("QA/tracks/preSel/Pi/NoId/tpcInnerParam_tofNSigma", "tpcInnerParam_tofNSigma", histTpcInnerParamTofNSigma); + hist.add("QA/tracks/preSel/Pi/NoId/tofExpMom_tofNSigma", "tofExpMom_tofNSigma", histTofExpMomTofNSigma); + hist.add("QA/tracks/preSel/Pi/NoId/tpcNSigma_tofNSigma", "tpcNSigma_tofNSigma", histTpcNSigmaTofNSigma); + + hist.addClone("QA/tracks/preSel/Pi/", "QA/tracks/preSel/Ka/"); + hist.addClone("QA/tracks/preSel/Pi/", "QA/tracks/preSel/Pr/"); + + hist.addClone("QA/tracks/preSel/", "QA/tracks/postSel/"); + + hist.add("QA/tracks/Idfd/Pi/tpcId/p_pt", "p_pt", histPPt); + hist.add("QA/tracks/Idfd/Pi/tpcId/p_tpcInnerParam", "p_tpcInnerParam", histPTpcInnerParam); + // tpcSignal + hist.add("QA/tracks/Idfd/Pi/tpcId/p_tpcSignal", "p_tpcSignal", histPTpcSignal); + hist.add("QA/tracks/Idfd/Pi/tpcId/tpcInnerParam_tpcSignal", "tpcInnerParam_tpcSignal", histTpcInnerParamTpcSignal); + // tofBeta + hist.add("QA/tracks/Idfd/Pi/tpcId/p_beta", "p_beta", histPBeta); + hist.add("QA/tracks/Idfd/Pi/tpcId/tpcInnerParam_beta", "tpcInnerParam_beta", histTpcInnerParamBeta); + // Look at Pion + hist.add("QA/tracks/Idfd/Pi/tpcId/p_tpcNSigma", "p_tpcNSigma", histPTpcNSigma); + hist.add("QA/tracks/Idfd/Pi/tpcId/pt_tpcNSigma", "pt_tpcNSigma", histPtTpcNSigma); + hist.add("QA/tracks/Idfd/Pi/tpcId/tpcInnerParam_tpcNSigma", "tpcInnerParam_tpcNSigma", histTpcInnerParamTpcNSigma); + hist.add("QA/tracks/Idfd/Pi/tpcId/tofExpMom_tpcNSigma", "tofExpMom_tpcNSigma", histTofExpMomTpcNSigma); + hist.add("QA/tracks/Idfd/Pi/tpcId/p_tofNSigma", "p_tofNSigma", histPTofNSigma); + hist.add("QA/tracks/Idfd/Pi/tpcId/pt_tofNSigma", "pt_tofNSigma", histPtTofNSigma); + hist.add("QA/tracks/Idfd/Pi/tpcId/tpcInnerParam_tofNSigma", "tpcInnerParam_tofNSigma", histTpcInnerParamTofNSigma); + hist.add("QA/tracks/Idfd/Pi/tpcId/tofExpMom_tofNSigma", "tofExpMom_tofNSigma", histTofExpMomTofNSigma); + hist.add("QA/tracks/Idfd/Pi/tpcId/tpcNSigma_tofNSigma", "tpcNSigma_tofNSigma", histTpcNSigmaTofNSigma); + + hist.addClone("QA/tracks/Idfd/Pi/tpcId/", "QA/tracks/Idfd/Pi/tofId/"); + hist.addClone("QA/tracks/Idfd/Pi/", "QA/tracks/Idfd/Ka/"); + hist.addClone("QA/tracks/Idfd/Pi/", "QA/tracks/Idfd/Pr/"); + + hist.add("sparse1", "sparse1", qnHist1); + hist.add("sparse2", "sparse2", qnHist2); + } // init ends + + // particle identifications + // tpc Selections + template + bool selPionTPCInnerParam(T track) + { + if (std::abs(track.tpcNSigmaEl()) > 3.0 && std::abs(track.tpcNSigmaKa()) > 3.0 && std::abs(track.tpcNSigmaPr()) > 3.0 && std::abs(track.tpcNSigmaDe()) > 3.0) { + if (0.05 <= track.tpcInnerParam() && track.tpcInnerParam() < 0.70 && std::abs(track.tpcNSigmaPi()) < 3.0) { + return true; + } + if (0.70 <= track.tpcInnerParam() && std::abs(track.tpcNSigmaPi()) < 2.0) { + return true; + } + } + return false; + } + + template + bool selKaonTPCInnerParam(T track) + { + // p dependent cuts + if (std::abs(track.tpcNSigmaEl()) > 3.0 && std::abs(track.tpcNSigmaPi()) > 3.0 && std::abs(track.tpcNSigmaPr()) > 3.0 && std::abs(track.tpcNSigmaDe()) > 3.0) { + if (0.05 <= track.tpcInnerParam() && track.tpcInnerParam() < 0.70 && std::abs(track.tpcNSigmaKa()) < 3.0) { + return true; + } + if (0.70 <= track.tpcInnerParam() && std::abs(track.tpcNSigmaKa()) < 2.0) { + return true; + } + } + return false; + } + + template + bool selProtonTPCInnerParam(T track) + { + if (std::abs(track.tpcNSigmaEl()) > 3.0 && std::abs(track.tpcNSigmaPi()) > 3.0 && std::abs(track.tpcNSigmaKa()) > 3.0 && std::abs(track.tpcNSigmaDe()) > 3.0) { + if (0.05 <= track.tpcInnerParam() && track.tpcInnerParam() < 1.60 && std::abs(track.tpcNSigmaPr()) < 3.0) { + return true; + } + if (1.60 <= track.tpcInnerParam() && std::abs(track.tpcNSigmaPr()) < 2.0) { + return true; + } + } + return false; + } + + template + bool selDeuteronTPCInnerParam(T track) + { + if (std::abs(track.tpcNSigmaEl()) > 3.0 && std::abs(track.tpcNSigmaPi()) > 3.0 && std::abs(track.tpcNSigmaKa()) > 3.0 && std::abs(track.tpcNSigmaPr()) > 3.0) { + if (0.05 <= track.tpcInnerParam() && track.tpcInnerParam() < 1.80 && std::abs(track.tpcNSigmaDe()) < 3.0) { + return true; + } + if (1.80 <= track.tpcInnerParam() && std::abs(track.tpcNSigmaDe()) < 2.0) { + return true; + } + } + return false; + } + + template + bool selElectronTPCInnerParam(T track) + { + if (track.tpcNSigmaEl() < 3.0 && track.tpcNSigmaPi() > 3.0 && track.tpcNSigmaKa() > 3.0 && track.tpcNSigmaPr() > 3.0 && track.tpcNSigmaDe() > 3.0) { + return true; + } + return false; + } + // + + // TOF Selections + // Pion + template + bool selPionTOF(T track) + { + if (track.p() <= 0.75 && std::abs(track.tpcNSigmaPi()) < 3.0 && std::abs(track.tofNSigmaPi()) < 3.0 && std::abs(track.tofNSigmaEl()) > 3.0) { + return true; + } else if (0.75 < track.p() // after p = 0.75, Pi and Ka lines of nSigma 3.0 will start intersecting + && std::abs(track.tpcNSigmaPi()) < 2.0 && std::abs(track.tofNSigmaPi()) < 2.0 && std::abs(track.tofNSigmaEl()) > 3.0 && std::abs(track.tofNSigmaKa()) > 3.0 && std::abs(track.tofNSigmaPr()) > 3.0 && std::abs(track.tofNSigmaDe()) > 3.0) { + return true; + } + return false; + } + + // Kaon + template + bool selKaonTOF(T track) + { + if (track.p() <= 0.75 && std::abs(track.tpcNSigmaKa()) < 3.0 && std::abs(track.tofNSigmaKa()) < 3.0) { + return true; + } + if (0.75 < track.p() && track.p() <= 1.30 // after 0.75 Pi and Ka lines of nSigma 3.0 will start intersecting + && std::abs(track.tpcNSigmaKa()) < 3.0 && std::abs(track.tofNSigmaKa()) < 3.0 && std::abs(track.tofNSigmaPi()) > 3.0 && std::abs(track.tofNSigmaEl()) > 3.0) { + return true; + } + if (1.30 < track.p() // after 1.30 Pr and Ka lines of nSigma 3.0 will start intersecting + && std::abs(track.tpcNSigmaKa()) < 2.0 && std::abs(track.tofNSigmaKa()) < 2.0 && std::abs(track.tofNSigmaEl()) > 3.0 && std::abs(track.tofNSigmaPi()) > 3.0 && std::abs(track.tofNSigmaPr()) > 3.0 && std::abs(track.tofNSigmaDe()) > 3.0) { + return true; + } + return false; + } + + // Proton + template + bool selProtonTOF(T track) + { + if (track.p() <= 1.30 && std::abs(track.tpcNSigmaPr()) < 3.0 && std::abs(track.tofNSigmaPr()) < 3.0) { + return true; + } + if (1.30 < track.p() && track.p() <= 3.10 // after 1.30 Pr and Ka lines of nSigma 3.0 will start intersecting + && std::abs(track.tpcNSigmaPr()) < 3.0 && std::abs(track.tofNSigmaPr()) < 3.0 && std::abs(track.tofNSigmaEl()) > 3.0 && std::abs(track.tofNSigmaPi()) > 3.0 && std::abs(track.tofNSigmaKa()) > 3.0 && std::abs(track.tofNSigmaDe()) > 3.0 // Some Deuteron contamination is still coming in p dependent cuts + ) { + return true; + } + if (3.10 < track.p() // after 3.10 Pr and De lines of nSigma 3.0 will start intersecting + && std::abs(track.tpcNSigmaPr()) < 2.0 && std::abs(track.tofNSigmaPr()) < 2.0 && std::abs(track.tofNSigmaEl()) > 3.0 && std::abs(track.tofNSigmaPi()) > 3.0 && std::abs(track.tofNSigmaKa()) > 3.0 && std::abs(track.tofNSigmaDe()) > 3.0) { + return true; + } + return false; + } + + // Deuteron + template + bool selDeuteronTOF(T track) + { + if (track.p() <= 3.10 && std::abs(track.tpcNSigmaDe()) < 3.0 && std::abs(track.tofNSigmaDe()) < 3.0 && std::abs(track.tofNSigmaEl()) > 3.0 && std::abs(track.tofNSigmaPi()) > 3.0 && std::abs(track.tofNSigmaKa()) > 3.0 && std::abs(track.tofNSigmaPr()) > 3.0) { + return true; + } + if (3.10 < track.p() // after 3.10 De and Pr lines of nSigma 3.0 will start intersecting + && std::abs(track.tpcNSigmaDe()) < 2.0 && std::abs(track.tofNSigmaDe()) < 2.0 && std::abs(track.tofNSigmaEl()) > 3.0 && std::abs(track.tofNSigmaPi()) > 3.0 && std::abs(track.tofNSigmaKa()) > 3.0 && std::abs(track.tofNSigmaPr()) > 3.0) { + return true; + } + return false; + } + + // Electron + template + bool selElectronTOF(T track) + { + if ( + (std::pow(track.tpcNSigmaEl(), 2) + std::pow(track.tofNSigmaEl(), 2)) < 9.00 && std::abs(track.tofNSigmaPi()) > 3.0 && std::abs(track.tofNSigmaKa()) > 3.0 && std::abs(track.tofNSigmaPr()) > 3.0 && std::abs(track.tofNSigmaDe()) > 3.0) { + return true; + } + return false; + } + // + + // SelectionFunctions + // Pion + template + bool selPion(T track, int& IdMethod) + { + if (!track.hasTOF() && selPionTPCInnerParam(track)) { + IdMethod = 0; + return true; + } + if (track.hasTOF() && track.beta() < 0.0 && selPionTPCInnerParam(track)) { + IdMethod = 0; + return true; + } + if (track.hasTOF() && track.beta() > 0.0 && selPionTPCInnerParam(track)) { + IdMethod = 0; + return true; + } + if (track.hasTOF() && track.beta() > 0.0 && !selPionTPCInnerParam(track)) { + IdMethod = 1; + return selPionTOF(track); + } + return false; + } + + // Kaon + template + bool selKaon(T track, int& IdMethod) + { + if (!track.hasTOF() && selKaonTPCInnerParam(track)) { + IdMethod = 0; + return true; + } + if (track.hasTOF() && track.beta() < 0.0 && selKaonTPCInnerParam(track)) { + IdMethod = 0; + return true; + } + if (track.hasTOF() && track.beta() > 0.0 && selKaonTPCInnerParam(track)) { + IdMethod = 0; + return true; + } + if (track.hasTOF() && track.beta() > 0.0 && !selKaonTPCInnerParam(track)) { + IdMethod = 1; + return selKaonTOF(track); + } + return false; + } + + // Proton + template + bool selProton(T track, int& IdMethod) + { + if (!track.hasTOF() && selProtonTPCInnerParam(track)) { + IdMethod = 0; + return true; + } + if (track.hasTOF() && track.beta() < 0.0 && selProtonTPCInnerParam(track)) { + IdMethod = 0; + return true; + } + if (track.hasTOF() && track.beta() > 0.0 && selProtonTPCInnerParam(track)) { + IdMethod = 0; + return true; + } + if (track.hasTOF() && track.beta() > 0.0 && !selProtonTPCInnerParam(track)) { + IdMethod = 1; + return selProtonTOF(track); + } + return false; + } + + // Deuteron + template + bool selDeuteron(T track, int& IdMethod) + { + if (!track.hasTOF() && selDeuteronTPCInnerParam(track)) { + IdMethod = 0; + return true; + } + if (track.hasTOF() && track.beta() < 0.0 && selDeuteronTPCInnerParam(track)) { + IdMethod = 0; + return true; + } + if (track.hasTOF() && track.beta() > 0.0 && selDeuteronTPCInnerParam(track)) { + IdMethod = 0; + return true; + } + if (track.hasTOF() && track.beta() > 0.0 && !selDeuteronTPCInnerParam(track)) { + IdMethod = 1; + return selDeuteronTOF(track); + } + return false; + } + + // Electron + template + bool selElectron(T track, int& IdMethod) + { + if (!track.hasTOF() && selElectronTPCInnerParam(track)) { + IdMethod = 0; + return true; + } + if (track.hasTOF() && track.beta() < 0.0 && selElectronTPCInnerParam(track)) { + IdMethod = 0; + return true; + } + if (track.hasTOF() && track.beta() > 0.0 && selElectronTPCInnerParam(track)) { + IdMethod = 0; + return true; + } + if (track.hasTOF() && track.beta() > 0.0 && !selElectronTPCInnerParam(track)) { + IdMethod = 1; + return selElectronTOF(track); + } + return false; + } + // + + enum HistRegEnum { + qaEventPreSel = 0, + qaEventPostSel, + qaTracksPreSel, + qaTracksPostSel, + qaTracksIdfd + }; + + static constexpr std::string_view HistRegDire[] = { + "QA/events/preSel/", + "QA/events/postSel/", + "QA/tracks/preSel/", + "QA/tracks/postSel/", + "QA/tracks/Idfd/"}; + + enum PidEnum { + kPi = 0, // dont use kPion, kKaon, as these enumeration + kKa, // are already defined in $ROOTSYS/root/include/TPDGCode.h + kPr, + kEl, + kDe + }; + + static constexpr std::string_view PidDire[] = { + "Pi/", + "Ka/", + "Pr/", + "El/", + "De/"}; + + enum DetEnum { + tpcId = 0, + tofId, + NoId + }; + + static constexpr std::string_view DetDire[] = { + "tpcId/", + "tofId/", + "NoId/"}; + + template + void fillIdentificationQA(H histReg, const T& track) + { + float tpcNSigmaVal = -999, tofNSigmaVal = -999; + switch (pidMode) { + case kPi: + tpcNSigmaVal = track.tpcNSigmaPi(); + tofNSigmaVal = track.tofNSigmaPi(); + break; + case kKa: + tpcNSigmaVal = track.tpcNSigmaKa(); + tofNSigmaVal = track.tofNSigmaKa(); + break; + case kPr: + tpcNSigmaVal = track.tpcNSigmaPr(); + tofNSigmaVal = track.tofNSigmaPr(); + break; + case kEl: + tpcNSigmaVal = track.tpcNSigmaEl(); + tofNSigmaVal = track.tofNSigmaEl(); + break; + case kDe: + tpcNSigmaVal = track.tpcNSigmaDe(); + tofNSigmaVal = track.tofNSigmaDe(); + break; + default: + tpcNSigmaVal = -999, tofNSigmaVal = -999; + break; + } + + // NSigma + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("p_tpcNSigma"), track.p(), tpcNSigmaVal); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("pt_tpcNSigma"), track.pt(), tpcNSigmaVal); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("tpcInnerParam_tpcNSigma"), track.tpcInnerParam(), tpcNSigmaVal); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("tofExpMom_tpcNSigma"), track.tofExpMom(), tpcNSigmaVal); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("p_tofNSigma"), track.p(), tofNSigmaVal); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("pt_tofNSigma"), track.pt(), tofNSigmaVal); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("tpcInnerParam_tofNSigma"), track.tpcInnerParam(), tofNSigmaVal); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("tofExpMom_tofNSigma"), track.tofExpMom(), tofNSigmaVal); + histReg.fill(HIST(HistRegDire[Mode]) + HIST(PidDire[pidMode]) + HIST(DetDire[detMode]) + HIST("tpcNSigma_tofNSigma"), tpcNSigmaVal, tofNSigmaVal); + } + + template + void fillCollQA(const T& col, const int& nCh, const int& nT) + { + hist.fill(HIST(HistRegDire[mode]) + HIST("h_VtxZ"), col.posZ()); + hist.fill(HIST(HistRegDire[mode]) + HIST("h_Counts"), 0.5); + hist.fill(HIST(HistRegDire[mode]) + HIST("multFT0"), col.multFT0C()); + hist.fill(HIST(HistRegDire[mode]) + HIST("centFT0"), col.centFT0M()); + if (mode == qaEventPostSel) { + hist.fill(HIST(HistRegDire[mode]) + HIST("net_charge"), nCh); + hist.fill(HIST(HistRegDire[mode]) + HIST("Nt_centFT"), col.centFT0M(), nT); + } + } + + template + void fillTrackQA(const T& track) + { + hist.fill(HIST(HistRegDire[mode]) + HIST("h_P"), track.p()); + hist.fill(HIST(HistRegDire[mode]) + HIST("h_P_InnerParameter"), track.tpcInnerParam()); + hist.fill(HIST(HistRegDire[mode]) + HIST("h_Pt"), track.pt()); + hist.fill(HIST(HistRegDire[mode]) + HIST("h_Eta"), track.eta()); + hist.fill(HIST(HistRegDire[mode]) + HIST("h_phi"), track.phi()); + hist.fill(HIST(HistRegDire[mode]) + HIST("h2_Pt_DcaZ"), track.pt(), track.dcaZ()); + hist.fill(HIST(HistRegDire[mode]) + HIST("h2_Pt_DcaXY"), track.pt(), track.dcaXY()); + hist.fill(HIST(HistRegDire[mode]) + HIST("h2_p_DcaZ"), track.p(), track.dcaZ()); + hist.fill(HIST(HistRegDire[mode]) + HIST("h2_p_DcaXY"), track.p(), track.dcaXY()); + hist.fill(HIST(HistRegDire[mode]) + HIST("dE_dx1"), track.p(), track.tpcSignal()); + hist.fill(HIST(HistRegDire[mode]) + HIST("dE_dx2"), track.tpcInnerParam(), track.tpcSignal()); + hist.fill(HIST(HistRegDire[mode]) + HIST("p_pt"), track.p(), track.pt()); + hist.fill(HIST(HistRegDire[mode]) + HIST("p_pInnerParameter"), track.p(), track.tpcInnerParam()); + + // tofBeta + hist.fill(HIST(HistRegDire[mode]) + HIST("p_beta"), track.p(), track.beta()); + hist.fill(HIST(HistRegDire[mode]) + HIST("tpcInnerParam_beta"), track.tpcInnerParam(), track.beta()); + + // Look at Pion + fillIdentificationQA(hist, track); // Look at Pion + fillIdentificationQA(hist, track); // Look at Kaon + fillIdentificationQA(hist, track); // Look at Proton + } + + using MyAllTracks = soa::Join; + using MyCollisions = soa::Join; + // tracks and collision filters + Filter col = aod::evsel::sel8 == true; + Filter colFilter = nabs(aod::collision::posZ) < cfgCutPosZ; + Filter trackFilter = requireGlobalTrackInFilter(); + Filter trackPt = (aod::track::pt > 0.15f) && (aod::track::pt < 2.0f); + Filter trackDCAxy = nabs(aod::track::dcaXY) < cfgCutDcaXY; + Filter trackDCAz = nabs(aod::track::dcaZ) < cfgCutDcaZ; + Filter tracketa = nabs(aod::track::eta) < cfgCutEta; + + using MyFilteredCol = soa::Filtered; + using MyFilteredTracks = soa::Filtered; + + // manual sliceby + SliceCache cache; + Preslice tracksPerCollisionPreslice = o2::aod::track::collisionId; + + void process(MyFilteredCol const& collisions, MyFilteredTracks const& tracks) + { + for (const auto& col : collisions) { + + int nP = 0; + int nM = 0; + int nCh = 0; + int nT = 0; + int nPr = 0; + int nAPr = 0; + int nKa = 0; + int nAKa = 0; + int nPi = 0; + int nAPi = 0; + // group tracks manually with corresponding collision using col id; + const uint64_t collIdx = col.globalIndex(); + const auto tracksTablePerColl = tracks.sliceBy(tracksPerCollisionPreslice, collIdx); + + for (const auto& track : tracksTablePerColl) { + + fillTrackQA(track); + + if (track.sign() == 1) { + nP++; + } + if (track.sign() == -1) { + nM++; + } + + int idMethod; + // pion + if (selPion(track, idMethod)) { + if (track.sign() == 1) { + nPi++; + } + if (track.sign() == -1) { + nAPi++; + } + + if (idMethod == 0) + fillIdentificationQA(hist, track); + if (idMethod == 1) + fillIdentificationQA(hist, track); + } + // kaon + if (selKaon(track, idMethod)) { + if (track.sign() == 1) { + nKa++; + } + if (track.sign() == -1) { + nAKa++; + } + + if (idMethod == 0) + fillIdentificationQA(hist, track); + if (idMethod == 1) + fillIdentificationQA(hist, track); + } + // proton + if (selProton(track, idMethod)) { + if (track.sign() == 1) { + nPr++; + } + if (track.sign() == -1) { + nAPr++; + } + + if (idMethod == 0) + fillIdentificationQA(hist, track); + if (idMethod == 1) + fillIdentificationQA(hist, track); + } + + } // track itteration ends + nCh = nP - nM; + nT = nP + nM; + + fillCollQA(col, nCh, nT); + + hist.fill(HIST("sparse1"), nCh, nP, nM, nPr, nAPr, nKa, nAKa, nT, col.centFT0M()); + hist.fill(HIST("sparse2"), nCh, nP, nM, nPi, nAPi, nKa, nAKa, nT, col.centFT0M()); + + } // collision ends + } // process ends +}; // structure ends + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/EbyEFluctuations/Tasks/netchargeFluctuations.cxx b/PWGCF/EbyEFluctuations/Tasks/netchargeFluctuations.cxx new file mode 100644 index 00000000000..b927b083066 --- /dev/null +++ b/PWGCF/EbyEFluctuations/Tasks/netchargeFluctuations.cxx @@ -0,0 +1,102 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// author Nida Malik (nida.malik@cern.ch) +// Department of Physics, Aligarh Muslim University, India +// to study the net charge fluctuations by observable, #nu_dyn + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace std; + +namespace o2::aod +{ +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; + +using MyTracks = soa::Join; +using MyTrack = MyTracks::iterator; +} // namespace o2::aod + +struct NetchargeFluctuations { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + void init(o2::framework::InitContext&) + { + AxisSpec vtxZAxis = {100, -20, 20, "Z (cm)"}; + AxisSpec dcaAxis = {1000, -100, 100, "DCA_{xy} (cm)"}; + AxisSpec dcazAxis = {1000, -100, 100, "DCA_{z} (cm)"}; + AxisSpec ptAxis = {40, 0.0, 4.0, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec etaAxis = {30, -1.5, 1.5, "#eta"}; + AxisSpec centAxis = {100, 0., 100., "centrality"}; + AxisSpec multAxis = {2000, 0., 2000., "multiplicity"}; + + histos.add("hVertexZ_bef", "", kTH1F, {vtxZAxis}); + histos.add("hVertexZ_aft", "", kTH1F, {vtxZAxis}); + histos.add("hVertexZ_aft_sel", "", kTH1D, {vtxZAxis}); + histos.add("hDCAxy_bef", "", kTH1D, {dcaAxis}); + histos.add("hDCAxy_aft", "", kTH1D, {dcaAxis}); + histos.add("hDCAz_bef", "", kTH1D, {dcazAxis}); + histos.add("hDCAz_aft", "", kTH1D, {dcazAxis}); + histos.add("hCentrality", "", kTH1D, {centAxis}); + histos.add("hMultiplicity", "", kTH1D, {multAxis}); + histos.add("hEta", "", kTH1F, {etaAxis}); + histos.add("hPt", "", kTH1F, {ptAxis}); + } + + void process(aod::MyCollision const& coll, aod::MyTracks const& inputTracks) + { + histos.fill(HIST("hVertexZ_bef"), coll.posZ()); + + if (std::fabs(coll.posZ()) > 10.f) { + return; + } + histos.fill(HIST("hVertexZ_aft"), coll.posZ()); + + if (!coll.sel7()) { + return; + } + histos.fill(HIST("hVertexZ_aft_sel"), coll.posZ()); + histos.fill(HIST("hCentrality"), coll.centRun2V0M()); + histos.fill(HIST("hMultiplicity"), coll.multFV0M()); + + for (auto const& track : inputTracks) { + if (std::fabs(track.eta()) > 0.8) + continue; + if (!(track.pt() > 0.2 && track.pt() < 2.)) + continue; + + histos.fill(HIST("hDCAxy_bef"), track.dcaXY()); + histos.fill(HIST("hDCAz_bef"), track.dcaZ()); + + if (!track.isGlobalTrack()) + continue; + + histos.fill(HIST("hDCAxy_aft"), track.dcaXY()); + histos.fill(HIST("hDCAz_aft"), track.dcaZ()); + histos.fill(HIST("hPt"), track.pt()); + histos.fill(HIST("hEta"), track.eta()); + } + } +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/PWGCF/EbyEFluctuations/Tasks/netprotonCumulantsMc.cxx b/PWGCF/EbyEFluctuations/Tasks/netprotonCumulantsMc.cxx new file mode 100644 index 00000000000..36a797a17a9 --- /dev/null +++ b/PWGCF/EbyEFluctuations/Tasks/netprotonCumulantsMc.cxx @@ -0,0 +1,2949 @@ +// 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 netprotonCumulantsMc.cxx +/// \brief Task for analyzing efficiency of proton, and net-proton distributions in MC reconstructed and generated, and calculating net-proton cumulants +/// \author Swati Saha + +#include +#include +#include +#include +#include +#include +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/StepTHn.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/Core/trackUtilities.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include +#include +#include +#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; + +struct NetprotonCumulantsMc { + // events + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + // MC + Configurable cfgIsMC{"cfgIsMC", true, "Run MC"}; + // tracks + Configurable cfgCutPtLower{"cfgCutPtLower", 0.2f, "Lower pT cut"}; + Configurable cfgCutPtUpper{"cfgCutPtUpper", 3.0f, "Higher pT cut"}; + Configurable cfgCutEta{"cfgCutEta", 0.8f, "absolute Eta cut"}; + Configurable cfgPIDchoice{"cfgPIDchoice", 1, "PID selection fucntion choice"}; + Configurable cfgCutPtUpperTPC{"cfgCutPtUpperTPC", 0.6f, "Upper pT cut for PID using TPC only"}; + Configurable cfgnSigmaCutTPC{"cfgnSigmaCutTPC", 2.0f, "PID nSigma cut for TPC"}; + Configurable cfgnSigmaCutTOF{"cfgnSigmaCutTOF", 2.0f, "PID nSigma cut for TOF"}; + Configurable cfgnSigmaCutCombTPCTOF{"cfgnSigmaCutCombTPCTOF", 2.0f, "PID nSigma combined cut for TPC and TOF"}; + Configurable cfgCutTpcChi2NCl{"cfgCutTpcChi2NCl", 2.5f, "Maximum TPCchi2NCl"}; + Configurable cfgCutItsChi2NCl{"cfgCutItsChi2NCl", 36.0f, "Maximum ITSchi2NCl"}; + Configurable cfgCutDCAxy{"cfgCutDCAxy", 2.0f, "DCAxy range for tracks"}; + Configurable cfgCutDCAz{"cfgCutDCAz", 2.0f, "DCAz range for tracks"}; + Configurable cfgITScluster{"cfgITScluster", 1, "Minimum Number of ITS cluster"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 80, "Minimum Number of TPC cluster"}; + Configurable cfgTPCnCrossedRows{"cfgTPCnCrossedRows", 70, "Minimum Number of TPC crossed-rows"}; + Configurable cfgUseItsPid{"cfgUseItsPid", true, "Use ITS nSigma Cut"}; + + // Calculation of cumulants central/error + Configurable cfgNSubsample{"cfgNSubsample", 10, "Number of subsamples for ERR"}; + Configurable cfgIsCalculateCentral{"cfgIsCalculateCentral", true, "Calculate Central value"}; + Configurable cfgIsCalculateError{"cfgIsCalculateError", false, "Calculate Error"}; + + // Efficiencies + Configurable> cfgPtBins{"cfgPtBins", {0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0}, "Pt Bins for Efficiency of protons"}; + Configurable> cfgProtonEff{"cfgProtonEff", {0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9}, "Efficiency of protons"}; + Configurable> cfgAntiprotonEff{"cfgAntiprotonEff", {0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9}, "Efficiency of anti-protons"}; + + Configurable cfgLoadEff{"cfgLoadEff", true, "Load efficiency from file"}; + Configurable cfgEvSelkNoSameBunchPileup{"cfgEvSelkNoSameBunchPileup", true, "Pileup removal"}; + Configurable cfgUseGoodITSLayerAllCut{"cfgUseGoodITSLayerAllCut", true, "Remove time interval with dead ITS zone"}; + Configurable cfgIfRejectElectron{"cfgIfRejectElectron", true, "Remove electrons"}; + Configurable cfgIfMandatoryTOF{"cfgIfMandatoryTOF", true, "Mandatory TOF requirement to remove pileup"}; + Configurable cfgEvSelkIsVertexTOFmatched{"cfgEvSelkIsVertexTOFmatched", true, "If matched with TOF, for pileup"}; + ConfigurableAxis cfgCentralityBins{"cfgCentralityBins", {90, 0., 90.}, "Centrality/Multiplicity percentile bining"}; + + // Connect to ccdb + Service ccdb; + Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable ccdbUrl{"ccdbUrl", "https://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPath{"ccdbPath", "Users/s/swati/EtavsPtEfficiency_LHC24f3b_PIDchoice0", "CCDB path to ccdb object containing eff(pt, eta) in 2D hist"}; + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + TRandom3* fRndm = new TRandom3(0); + + // Eff histograms 2d: eff(pT, eta) + TH2F* hRatio2DEtaVsPtProton = nullptr; + TH2F* hRatio2DEtaVsPtAntiproton = nullptr; + + // Filter command for rec (data)*********** + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtLower) && (aod::track::pt < 5.0f) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (aod::track::tpcChi2NCl < cfgCutTpcChi2NCl) && (aod::track::itsChi2NCl < cfgCutItsChi2NCl) && (nabs(aod::track::dcaZ) < cfgCutDCAz) && (nabs(aod::track::dcaXY) < cfgCutDCAxy); + + // filtering collisions and tracks for real data*********** + using AodCollisions = soa::Filtered>; + using AodTracks = soa::Filtered>; + + // filtering collisions and tracks for MC rec data*********** + using MyMCRecCollisions = soa::Filtered>; + using MyMCRecCollision = MyMCRecCollisions::iterator; + using MyMCTracks = soa::Filtered>; + using EventCandidatesMC = soa::Join; + + // Equivalent of the AliRoot task UserCreateOutputObjects + void init(o2::framework::InitContext&) + { + // Loading efficiency histograms from ccdb + if (cfgLoadEff) { + + // Accessing eff histograms + ccdb->setURL(ccdbUrl.value); + // Enabling object caching, otherwise each call goes to the CCDB server + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + // Not later than now, will be replaced by the value of the train creation + // This avoids that users can replace objects **while** a train is running + ccdb->setCreatedNotAfter(ccdbNoLaterThan.value); + LOGF(info, "Getting object %s", ccdbPath.value.data()); + TList* lst = ccdb->getForTimeStamp(ccdbPath.value, ccdbNoLaterThan.value); + hRatio2DEtaVsPtProton = reinterpret_cast(lst->FindObject("hRatio2DEtaVsPtProton")); + hRatio2DEtaVsPtAntiproton = reinterpret_cast(lst->FindObject("hRatio2DEtaVsPtAntiproton")); + if (!hRatio2DEtaVsPtProton || !hRatio2DEtaVsPtAntiproton) + LOGF(info, "FATAL!! could not get efficiency---------> check"); + } + + // Define your axes + // Constant bin width axis + AxisSpec vtxZAxis = {100, -20, 20}; + // Variable bin width axis + std::vector ptBinning = {0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0}; + AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; + std::vector etaBinning = {-0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8}; + AxisSpec etaAxis = {etaBinning, "#it{#eta}"}; + // std::vector centBining = {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90}; + // AxisSpec centAxis = {centBining, "Multiplicity percentile from FT0M (%)"}; + const AxisSpec centAxis{cfgCentralityBins, "Multiplicity percentile from FT0M (%)"}; + AxisSpec netprotonAxis = {41, -20.5, 20.5, "net-proton number"}; + AxisSpec protonAxis = {21, -0.5, 20.5, "proton number"}; + AxisSpec antiprotonAxis = {21, -0.5, 20.5, "antiproton number"}; + AxisSpec nSigmaAxis = {200, -5.0, 5.0, "nSigma(Proton)"}; + + auto noSubsample = static_cast(cfgNSubsample); + float maxSubsample = 1.0 * noSubsample; + AxisSpec subsampleAxis = {noSubsample, 0.0, maxSubsample, "subsample no."}; + + // histograms for events + histos.add("hZvtx_after_sel", "Vertex dist. after event selection;Z (cm)", kTH1F, {vtxZAxis}); + histos.add("hCentrec", "MCRec Multiplicity percentile from FT0M (%)", kTH1F, {{100, 0.0, 100.0}}); + // tracks Rec level histograms + histos.add("hrecPtAll", "Reconstructed All particles;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hrecPtProton", "Reconstructed Protons;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hrecPtAntiproton", "Reconstructed Antiprotons;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hrecPhiAll", "Reconstructed All particles;#phi", kTH1F, {{100, 0., 7.}}); + histos.add("hrecPhiProton", "Reconstructed Protons;#phi", kTH1F, {{100, 0., 7.}}); + histos.add("hrecPhiAntiproton", "Reconstructed Antiprotons;#phi", kTH1F, {{100, 0., 7.}}); + histos.add("hrecEtaAll", "Reconstructed All particles;#eta", kTH1F, {{100, -2.01, 2.01}}); + histos.add("hrecEtaProton", "Reconstructed Proton;#eta", kTH1F, {{100, -2.01, 2.01}}); + histos.add("hrecEtaAntiproton", "Reconstructed Antiprotons;#eta", kTH1F, {{100, -2.01, 2.01}}); + histos.add("hrecDcaXYAll", "Reconstructed All particles;DCA_{xy} (in cm)", kTH1F, {{400, -2.0, 2.0}}); + histos.add("hrecDcaXYProton", "Reconstructed Proton;DCA_{xy} (in cm)", kTH1F, {{400, -2.0, 2.0}}); + histos.add("hrecDcaXYAntiproton", "Reconstructed Antiprotons;DCA_{xy} (in cm)", kTH1F, {{400, -2.0, 2.0}}); + histos.add("hrecDcaZAll", "Reconstructed All particles;DCA_{z} (in cm)", kTH1F, {{400, -2.0, 2.0}}); + histos.add("hrecDcaZProton", "Reconstructed Proton;DCA_{z} (in cm)", kTH1F, {{400, -2.0, 2.0}}); + histos.add("hrecDcaZAntiproton", "Reconstructed Antiprotons;DCA_{z} (in cm)", kTH1F, {{400, -2.0, 2.0}}); + histos.add("hrecPtDistProtonVsCentrality", "Reconstructed proton number vs centrality in 2D", kTH2F, {ptAxis, centAxis}); + histos.add("hrecPtDistAntiprotonVsCentrality", "Reconstructed antiproton number vs centrality in 2D", kTH2F, {ptAxis, centAxis}); + histos.add("hrecNetProtonVsCentrality", "Reconstructed net-proton number vs centrality in 2D", kTH2F, {netprotonAxis, centAxis}); + histos.add("hrecProtonVsCentrality", "Reconstructed proton number vs centrality in 2D", kTH2F, {protonAxis, centAxis}); + histos.add("hrecAntiprotonVsCentrality", "Reconstructed antiproton number vs centrality in 2D", kTH2F, {antiprotonAxis, centAxis}); + histos.add("hrecProfileTotalProton", "Reconstructed total proton number vs. centrality", kTProfile, {centAxis}); + histos.add("hrecProfileProton", "Reconstructed proton number vs. centrality", kTProfile, {centAxis}); + histos.add("hrecProfileAntiproton", "Reconstructed antiproton number vs. centrality", kTProfile, {centAxis}); + histos.add("hCorrProfileTotalProton", "Eff. Corrected total proton number vs. centrality", kTProfile, {centAxis}); + histos.add("hCorrProfileProton", "Eff. Corrected proton number vs. centrality", kTProfile, {centAxis}); + histos.add("hCorrProfileAntiproton", "Eff. Corrected antiproton number vs. centrality", kTProfile, {centAxis}); + histos.add("hrec2DEtaVsPtProton", "2D hist of Reconstructed Proton y: eta vs. x: pT", kTH2F, {ptAxis, etaAxis}); + histos.add("hrec2DEtaVsPtAntiproton", "2D hist of Reconstructed Anti-proton y: eta vs. x: pT", kTH2F, {ptAxis, etaAxis}); + histos.add("hgen2DEtaVsPtProton", "2D hist of Generated Proton y: eta vs. x: pT", kTH2F, {ptAxis, etaAxis}); + histos.add("hgen2DEtaVsPtAntiproton", "2D hist of Generated Anti-proton y: eta vs. x: pT", kTH2F, {ptAxis, etaAxis}); + + // 2D histograms of nSigma + histos.add("h2DnsigmaTpcVsPt", "2D hist of nSigmaTPC vs. pT", kTH2F, {ptAxis, nSigmaAxis}); + histos.add("h2DnsigmaTofVsPt", "2D hist of nSigmaTOF vs. pT", kTH2F, {ptAxis, nSigmaAxis}); + histos.add("h2DnsigmaItsVsPt", "2D hist of nSigmaITS vs. pT", kTH2F, {ptAxis, nSigmaAxis}); + + if (cfgIsCalculateCentral) { + // uncorrected + histos.add("Prof_mu1_netproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_mu2_netproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_mu3_netproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_mu4_netproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_mu5_netproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_mu6_netproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_mu7_netproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_mu8_netproton", "", {HistType::kTProfile, {centAxis}}); + + // eff. corrected + histos.add("Prof_Q11_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q11_2", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q11_3", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q11_4", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q21_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q22_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q31_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q32_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q33_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q41_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q42_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q43_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q44_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q21_2", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q22_2", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1131_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1131_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1131_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1132_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1132_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1132_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1133_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1133_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1133_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2122_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2122_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2122_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3132_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3132_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3132_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3133_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3133_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3133_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3233_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3233_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q3233_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2241_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2241_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2241_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2242_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2242_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2242_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2243_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2243_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2243_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2244_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2244_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2244_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2141_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2141_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2141_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2142_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2142_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2142_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2143_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2143_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2143_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2144_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2144_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2144_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1151_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1151_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1151_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1152_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1152_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1152_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1153_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1153_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1153_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1154_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1154_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1154_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1155_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1155_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1155_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112233_001", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112233_010", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112233_100", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112233_011", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112233_101", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112233_110", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112232_001", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112232_010", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112232_100", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112232_011", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112232_101", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112232_110", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112231_001", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112231_010", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112231_100", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112231_011", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112231_101", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112231_110", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112133_001", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112133_010", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112133_100", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112133_011", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112133_101", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112133_110", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112132_001", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112132_010", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112132_100", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112132_011", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112132_101", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112132_110", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112131_001", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112131_010", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112131_100", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112131_011", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112131_101", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112131_110", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2221_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2221_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2221_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2221_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2221_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2122_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2122_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_02", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_12", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_22", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_02", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_12", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_22", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_001", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_010", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_100", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_011", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_101", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_110", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_200", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_201", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_210", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_211", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1131_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1131_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1131_31", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1131_30", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1132_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1132_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1132_31", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1132_30", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1133_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1133_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1133_31", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1133_30", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q11_5", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q11_6", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_30", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_31", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_40", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1121_41", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_30", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_31", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_40", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1122_41", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2211_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2211_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2211_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2211_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2211_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2111_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2111_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2111_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2111_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2111_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112122_001", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112122_010", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112122_100", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112122_011", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112122_101", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112122_110", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1141_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1141_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1141_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1141_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1141_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1142_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1142_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1142_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1142_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1142_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1143_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1143_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1143_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1143_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1143_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1144_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1144_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1144_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1144_20", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q1144_21", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2131_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2131_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2131_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2132_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2132_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2132_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2133_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2133_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2133_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2231_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2231_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2231_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2232_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2232_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2232_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2233_11", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2233_01", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q2233_10", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q51_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q52_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q53_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q54_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q55_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q21_3", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q22_3", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q31_2", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q32_2", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q33_2", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q61_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q62_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q63_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q64_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q65_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q66_1", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112122_111", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112131_111", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112132_111", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112133_111", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112231_111", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112232_111", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112233_111", "", {HistType::kTProfile, {centAxis}}); + histos.add("Prof_Q112221_111", "", {HistType::kTProfile, {centAxis}}); + } + + if (cfgIsCalculateError) { + // uncorrected + histos.add("Prof2D_mu1_netproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_mu2_netproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_mu3_netproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_mu4_netproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_mu5_netproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_mu6_netproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_mu7_netproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_mu8_netproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + + // eff. corrected + histos.add("Prof2D_Q11_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q11_2", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q11_3", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q11_4", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q21_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q22_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q31_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q32_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q33_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q41_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q42_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q43_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q44_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q21_2", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q22_2", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1131_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1131_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1131_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1132_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1132_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1132_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1133_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1133_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1133_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2122_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2122_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2122_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3132_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3132_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3132_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3133_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3133_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3133_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3233_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3233_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q3233_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2241_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2241_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2241_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2242_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2242_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2242_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2243_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2243_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2243_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2244_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2244_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2244_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2141_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2141_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2141_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2142_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2142_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2142_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2143_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2143_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2143_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2144_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2144_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2144_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1151_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1151_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1151_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1152_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1152_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1152_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1153_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1153_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1153_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1154_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1154_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1154_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1155_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1155_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1155_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112233_001", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112233_010", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112233_100", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112233_011", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112233_101", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112233_110", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112232_001", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112232_010", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112232_100", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112232_011", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112232_101", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112232_110", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112231_001", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112231_010", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112231_100", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112231_011", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112231_101", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112231_110", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112133_001", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112133_010", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112133_100", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112133_011", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112133_101", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112133_110", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112132_001", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112132_010", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112132_100", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112132_011", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112132_101", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112132_110", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112131_001", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112131_010", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112131_100", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112131_011", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112131_101", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112131_110", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2221_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2221_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2221_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2221_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2221_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2122_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2122_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_02", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_12", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_22", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_02", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_12", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_22", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_001", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_010", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_100", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_011", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_101", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_110", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_200", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_201", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_210", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_211", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1131_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1131_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1131_31", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1131_30", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1132_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1132_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1132_31", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1132_30", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1133_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1133_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1133_31", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1133_30", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q11_5", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q11_6", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_30", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_31", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_40", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1121_41", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_30", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_31", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_40", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1122_41", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2211_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2211_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2211_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2211_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2211_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2111_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2111_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2111_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2111_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2111_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112122_001", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112122_010", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112122_100", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112122_011", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112122_101", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112122_110", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1141_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1141_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1141_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1141_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1141_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1142_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1142_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1142_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1142_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1142_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1143_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1143_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1143_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1143_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1143_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1144_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1144_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1144_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1144_20", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q1144_21", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2131_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2131_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2131_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2132_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2132_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2132_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2133_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2133_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2133_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2231_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2231_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2231_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2232_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2232_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2232_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2233_11", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2233_01", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q2233_10", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q51_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q52_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q53_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q54_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q55_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q21_3", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q22_3", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q31_2", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q32_2", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q33_2", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q61_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q62_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q63_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q64_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q65_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q66_1", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112122_111", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112131_111", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112132_111", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112133_111", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112231_111", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112232_111", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112233_111", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("Prof2D_Q112221_111", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + } + + if (cfgIsMC) { + // MC event counts + histos.add("hMC", "MC Event statistics", kTH1F, {{10, 0.0f, 10.0f}}); + histos.add("hCentgen", "MCGen Multiplicity percentile from FT0M (%)", kTH1F, {{100, 0.0, 100.0}}); + // tracks Gen level histograms + histos.add("hgenPtAll", "Generated All particles;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hgenPtProton", "Generated Protons;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hgenPtAntiproton", "Generated Antiprotons;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hrecPartPtAll", "Reconstructed All particles filled mcparticle pt;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hrecPartPtProton", "Reconstructed Protons filled mcparticle pt;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hrecPartPtAntiproton", "Reconstructed Antiprotons filled mcparticle pt;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hgenPhiAll", "Generated All particles;#phi", kTH1F, {{100, 0., 7.}}); + histos.add("hgenPhiProton", "Generated Protons;#phi", kTH1F, {{100, 0., 7.}}); + histos.add("hgenPhiAntiproton", "Generated Antiprotons;#phi", kTH1F, {{100, 0., 7.}}); + histos.add("hgenEtaAll", "Generated All particles;#eta", kTH1F, {{100, -2.01, 2.01}}); + histos.add("hgenEtaProton", "Generated Proton;#eta", kTH1F, {{100, -2.01, 2.01}}); + histos.add("hgenEtaAntiproton", "Generated Antiprotons;#eta", kTH1F, {{100, -2.01, 2.01}}); + histos.add("hgenPtDistProtonVsCentrality", "Generated proton number vs centrality in 2D", kTH2F, {ptAxis, centAxis}); + histos.add("hgenPtDistAntiprotonVsCentrality", "Generated antiproton number vs centrality in 2D", kTH2F, {ptAxis, centAxis}); + histos.add("hrecTruePtProton", "Reconstructed pdgcode verified protons;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hrecTruePtAntiproton", "Reconstructed pdgcode verified Antiprotons;#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hgenNetProtonVsCentrality", "Generated net-proton number vs centrality in 2D", kTH2F, {netprotonAxis, centAxis}); + histos.add("hgenProtonVsCentrality", "Generated proton number vs centrality in 2D", kTH2F, {protonAxis, centAxis}); + histos.add("hgenAntiprotonVsCentrality", "Generated antiproton number vs centrality in 2D", kTH2F, {antiprotonAxis, centAxis}); + histos.add("hgenProfileTotalProton", "Generated total proton number vs. centrality", kTProfile, {centAxis}); + histos.add("hgenProfileProton", "Generated proton number vs. centrality", kTProfile, {centAxis}); + histos.add("hgenProfileAntiproton", "Generated antiproton number vs. centrality", kTProfile, {centAxis}); + + if (cfgIsCalculateCentral) { + histos.add("GenProf_mu1_netproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("GenProf_mu2_netproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("GenProf_mu3_netproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("GenProf_mu4_netproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("GenProf_mu5_netproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("GenProf_mu6_netproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("GenProf_mu7_netproton", "", {HistType::kTProfile, {centAxis}}); + histos.add("GenProf_mu8_netproton", "", {HistType::kTProfile, {centAxis}}); + } + + if (cfgIsCalculateError) { + histos.add("GenProf2D_mu1_netproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("GenProf2D_mu2_netproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("GenProf2D_mu3_netproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("GenProf2D_mu4_netproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("GenProf2D_mu5_netproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("GenProf2D_mu6_netproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("GenProf2D_mu7_netproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + histos.add("GenProf2D_mu8_netproton", "", {HistType::kTProfile2D, {centAxis, subsampleAxis}}); + } + } + } // end init() + + template + bool selectionPIDold(const T& candidate) + { + if (!candidate.hasTPC()) + return false; + + //! PID checking as done in Run2 my analysis + //! ---------------------------------------------------------------------- + int flag = 0; //! pid check main flag + + if (candidate.pt() > 0.2f && candidate.pt() <= cfgCutPtUpperTPC) { + if (std::abs(candidate.tpcNSigmaPr()) < cfgnSigmaCutTPC) { + flag = 1; + } + } + if (candidate.hasTOF() && candidate.pt() > cfgCutPtUpperTPC && candidate.pt() < 5.0f) { + const float combNSigmaPr = std::sqrt(std::pow(candidate.tpcNSigmaPr(), 2.0) + std::pow(candidate.tofNSigmaPr(), 2.0)); + const float combNSigmaPi = std::sqrt(std::pow(candidate.tpcNSigmaPi(), 2.0) + std::pow(candidate.tofNSigmaPi(), 2.0)); + const float combNSigmaKa = std::sqrt(std::pow(candidate.tpcNSigmaKa(), 2.0) + std::pow(candidate.tofNSigmaKa(), 2.0)); + + int flag2 = 0; + if (combNSigmaPr < 3.0) + flag2 += 1; + if (combNSigmaPi < 3.0) + flag2 += 1; + if (combNSigmaKa < 3.0) + flag2 += 1; + if (!(flag2 > 1) && !(combNSigmaPr > combNSigmaPi) && !(combNSigmaPr > combNSigmaKa)) { + if (combNSigmaPr < cfgnSigmaCutCombTPCTOF) { + flag = 1; + } + } + } + if (flag == 1) + return true; + else + return false; + } + + template + bool selectionPIDoldTOFveto(const T& candidate) + { + if (!candidate.hasTPC()) + return false; + + //! PID checking as done in Run2 my analysis + //! ---------------------------------------------------------------------- + int flag = 0; //! pid check main flag + + if (candidate.pt() > 0.2f && candidate.pt() <= cfgCutPtUpperTPC) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < cfgnSigmaCutTPC) { + flag = 1; + } + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < cfgnSigmaCutTPC && std::abs(candidate.tofNSigmaPr()) < cfgnSigmaCutTOF) { + flag = 1; + } + } + if (candidate.hasTOF() && candidate.pt() > cfgCutPtUpperTPC && candidate.pt() < 5.0f) { + const float combNSigmaPr = std::sqrt(std::pow(candidate.tpcNSigmaPr(), 2.0) + std::pow(candidate.tofNSigmaPr(), 2.0)); + const float combNSigmaPi = std::sqrt(std::pow(candidate.tpcNSigmaPi(), 2.0) + std::pow(candidate.tofNSigmaPi(), 2.0)); + const float combNSigmaKa = std::sqrt(std::pow(candidate.tpcNSigmaKa(), 2.0) + std::pow(candidate.tofNSigmaKa(), 2.0)); + + int flag2 = 0; + if (combNSigmaPr < 3.0) + flag2 += 1; + if (combNSigmaPi < 3.0) + flag2 += 1; + if (combNSigmaKa < 3.0) + flag2 += 1; + if (!(flag2 > 1) && !(combNSigmaPr > combNSigmaPi) && !(combNSigmaPr > combNSigmaKa)) { + if (combNSigmaPr < cfgnSigmaCutCombTPCTOF) { + flag = 1; + } + } + } + if (flag == 1) + return true; + else + return false; + } + + // electron rejection function + template + bool isElectron(const T& candidate) // Victor's BF analysis + { + if (candidate.tpcNSigmaEl() > -3.0f && candidate.tpcNSigmaEl() < 5.0f && std::abs(candidate.tpcNSigmaPi()) > 3.0f && std::abs(candidate.tpcNSigmaKa()) > 3.0f && std::abs(candidate.tpcNSigmaPr()) > 3.0f) { + return true; + } + return false; + } + + template + bool selectionPIDnew(const T& candidate) // Victor's BF analysis + { + // electron rejection + if (candidate.tpcNSigmaEl() > -3.0f && candidate.tpcNSigmaEl() < 5.0f && std::abs(candidate.tpcNSigmaPi()) > 3.0f && std::abs(candidate.tpcNSigmaKa()) > 3.0f && std::abs(candidate.tpcNSigmaPr()) > 3.0f) { + return false; + } + + //! if pt < threshold + if (candidate.pt() > 0.2f && candidate.pt() <= cfgCutPtUpperTPC) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < cfgnSigmaCutTPC && std::abs(candidate.tpcNSigmaPi()) > cfgnSigmaCutTPC && std::abs(candidate.tpcNSigmaKa()) > cfgnSigmaCutTPC) { + return true; + } + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < cfgnSigmaCutTPC && std::abs(candidate.tpcNSigmaPi()) > cfgnSigmaCutTPC && std::abs(candidate.tpcNSigmaKa()) > cfgnSigmaCutTPC && std::abs(candidate.tofNSigmaPr()) < cfgnSigmaCutTOF && std::abs(candidate.tofNSigmaPi()) > cfgnSigmaCutTOF && std::abs(candidate.tofNSigmaKa()) > cfgnSigmaCutTOF) { + return true; + } + } + + //! if pt > threshold + if (candidate.pt() > cfgCutPtUpperTPC) { + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < cfgnSigmaCutTPC && std::abs(candidate.tpcNSigmaPi()) > cfgnSigmaCutTPC && std::abs(candidate.tpcNSigmaKa()) > cfgnSigmaCutTPC && std::abs(candidate.tofNSigmaPr()) < cfgnSigmaCutTOF && std::abs(candidate.tofNSigmaPi()) > cfgnSigmaCutTOF && std::abs(candidate.tofNSigmaKa()) > cfgnSigmaCutTOF) { + return true; + } + } + return false; + } + + // Function to check which pt bin the track lies in and assign the corresponding efficiency + + template + float getEfficiency(const T& candidate) + { + // Load eff from histograms in CCDB + if (cfgLoadEff) { + if (candidate.sign() > 0) { + float effmeanval = hRatio2DEtaVsPtProton->GetBinContent(hRatio2DEtaVsPtProton->FindBin(candidate.pt(), candidate.eta())); + return effmeanval; + } + if (candidate.sign() < 0) { + float effmeanval = hRatio2DEtaVsPtAntiproton->GetBinContent(hRatio2DEtaVsPtAntiproton->FindBin(candidate.pt(), candidate.eta())); + return effmeanval; + } + return 0.0; + } else { + // Find the pt bin index based on the track's pt value + int binIndex = -1; + + for (int i = 0; i < 16; ++i) { + if (candidate.pt() >= cfgPtBins.value[i] && candidate.pt() < cfgPtBins.value[i + 1]) { + binIndex = i; + break; + } + } + // If the pt is outside the defined bins, return a default efficiency or handle it differently + if (binIndex == -1) { + return 0.0; // Default efficiency (0% if outside bins) + } + if (candidate.sign() > 0) + return cfgProtonEff.value[binIndex]; + if (candidate.sign() < 0) + return cfgAntiprotonEff.value[binIndex]; + return 0.0; + } + } + + void processMCGen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& collisions) + { + histos.fill(HIST("hMC"), 0.5); + if (std::abs(mcCollision.posZ()) < cfgCutVertex) { + histos.fill(HIST("hMC"), 1.5); + } + auto cent = 0; + + int nchInel = 0; + for (const auto& mcParticle : mcParticles) { + auto pdgcode = std::abs(mcParticle.pdgCode()); + if (mcParticle.isPhysicalPrimary() && (pdgcode == PDG_t::kPiPlus || pdgcode == PDG_t::kKPlus || pdgcode == PDG_t::kProton || pdgcode == PDG_t::kElectron || pdgcode == PDG_t::kMuonMinus)) { + if (std::abs(mcParticle.eta()) < 1.0) { + nchInel = nchInel + 1; + } + } + } + if (nchInel > 0 && std::abs(mcCollision.posZ()) < cfgCutVertex) + histos.fill(HIST("hMC"), 2.5); + std::vector selectedEvents(collisions.size()); + int nevts = 0; + + for (const auto& collision : collisions) { + if (!collision.sel8() || std::abs(collision.mcCollision().posZ()) > cfgCutVertex) { + continue; + } + if (cfgUseGoodITSLayerAllCut && !(collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll))) { + continue; + } + if (cfgEvSelkNoSameBunchPileup && !(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { + continue; + } + if (cfgEvSelkIsVertexTOFmatched && !(collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched))) { + continue; + } + + cent = collision.centFT0M(); + + selectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); + } + selectedEvents.resize(nevts); + const auto evtReconstructedAndSelected = std::find(selectedEvents.begin(), selectedEvents.end(), mcCollision.globalIndex()) != selectedEvents.end(); + histos.fill(HIST("hMC"), 3.5); + if (!evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection + return; + } + histos.fill(HIST("hMC"), 4.5); + histos.fill(HIST("hCentgen"), cent); + + // creating phi, pt, eta dstribution of generted MC particles + + float nProt = 0.0; + float nAntiprot = 0.0; + + for (const auto& mcParticle : mcParticles) { + if (!mcParticle.has_mcCollision()) + continue; + + if (mcParticle.isPhysicalPrimary()) { + if ((mcParticle.pt() > cfgCutPtLower) && (mcParticle.pt() < 5.0f) && (std::abs(mcParticle.eta()) < cfgCutEta)) { + histos.fill(HIST("hgenPtAll"), mcParticle.pt()); + histos.fill(HIST("hgenEtaAll"), mcParticle.eta()); + histos.fill(HIST("hgenPhiAll"), mcParticle.phi()); + + if (std::abs(mcParticle.pdgCode()) == PDG_t::kProton /*&& std::abs(mcParticle.y()) < 0.5*/) { + if (mcParticle.pdgCode() == PDG_t::kProton) { + histos.fill(HIST("hgenPtProton"), mcParticle.pt()); //! hist for p gen + histos.fill(HIST("hgenPtDistProtonVsCentrality"), mcParticle.pt(), cent); + histos.fill(HIST("hgen2DEtaVsPtProton"), mcParticle.pt(), mcParticle.eta()); + histos.fill(HIST("hgenEtaProton"), mcParticle.eta()); + histos.fill(HIST("hgenPhiProton"), mcParticle.phi()); + if (mcParticle.pt() < cfgCutPtUpper) + nProt = nProt + 1.0; + } + if (mcParticle.pdgCode() == PDG_t::kProtonBar) { + histos.fill(HIST("hgenPtAntiproton"), mcParticle.pt()); //! hist for anti-p gen + histos.fill(HIST("hgenPtDistAntiprotonVsCentrality"), mcParticle.pt(), cent); + histos.fill(HIST("hgen2DEtaVsPtAntiproton"), mcParticle.pt(), mcParticle.eta()); + histos.fill(HIST("hgenEtaAntiproton"), mcParticle.eta()); + histos.fill(HIST("hgenPhiAntiproton"), mcParticle.phi()); + if (mcParticle.pt() < cfgCutPtUpper) + nAntiprot = nAntiprot + 1.0; + } + } + } + } + } //! end particle loop + + float netProt = nProt - nAntiprot; + histos.fill(HIST("hgenNetProtonVsCentrality"), netProt, cent); + histos.fill(HIST("hgenProtonVsCentrality"), nProt, cent); + histos.fill(HIST("hgenAntiprotonVsCentrality"), nAntiprot, cent); + histos.fill(HIST("hgenProfileTotalProton"), cent, (nProt + nAntiprot)); + histos.fill(HIST("hgenProfileProton"), cent, nProt); + histos.fill(HIST("hgenProfileAntiproton"), cent, nAntiprot); + + // Profiles for generated level cumulants + //------------------------------------------------------------------------------------------- + + if (cfgIsCalculateCentral) { + histos.get(HIST("GenProf_mu1_netproton"))->Fill(cent, std::pow(netProt, 1.0)); + histos.get(HIST("GenProf_mu2_netproton"))->Fill(cent, std::pow(netProt, 2.0)); + histos.get(HIST("GenProf_mu3_netproton"))->Fill(cent, std::pow(netProt, 3.0)); + histos.get(HIST("GenProf_mu4_netproton"))->Fill(cent, std::pow(netProt, 4.0)); + histos.get(HIST("GenProf_mu5_netproton"))->Fill(cent, std::pow(netProt, 5.0)); + histos.get(HIST("GenProf_mu6_netproton"))->Fill(cent, std::pow(netProt, 6.0)); + histos.get(HIST("GenProf_mu7_netproton"))->Fill(cent, std::pow(netProt, 7.0)); + histos.get(HIST("GenProf_mu8_netproton"))->Fill(cent, std::pow(netProt, 8.0)); + } + + if (cfgIsCalculateError) { + + float lRandom = fRndm->Rndm(); + int sampleIndex = static_cast(cfgNSubsample * lRandom); + + histos.get(HIST("GenProf2D_mu1_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 1.0)); + histos.get(HIST("GenProf2D_mu2_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 2.0)); + histos.get(HIST("GenProf2D_mu3_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 3.0)); + histos.get(HIST("GenProf2D_mu4_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 4.0)); + histos.get(HIST("GenProf2D_mu5_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 5.0)); + histos.get(HIST("GenProf2D_mu6_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 6.0)); + histos.get(HIST("GenProf2D_mu7_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 7.0)); + histos.get(HIST("GenProf2D_mu8_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 8.0)); + } + //------------------------------------------------------------------------------------------- + } + PROCESS_SWITCH(NetprotonCumulantsMc, processMCGen, "Process Generated", true); + + void processMCRec(MyMCRecCollision const& collision, MyMCTracks const& tracks, aod::McCollisions const&, aod::McParticles const&) + { + if (!collision.has_mcCollision()) { + return; + } + + if (!collision.sel8()) { + return; + } + if (cfgUseGoodITSLayerAllCut && !(collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll))) { + return; + } + if (cfgEvSelkNoSameBunchPileup && !(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { + return; + } + if (cfgEvSelkIsVertexTOFmatched && !(collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched))) { + return; + ; + } + + auto cent = collision.centFT0M(); + histos.fill(HIST("hCentrec"), cent); + histos.fill(HIST("hMC"), 5.5); + histos.fill(HIST("hZvtx_after_sel"), collision.posZ()); + + float nProt = 0.0; + float nAntiprot = 0.0; + std::array powerEffProt = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + std::array powerEffAntiprot = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + std::array fTCP0 = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + std::array fTCP1 = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + + o2::aod::ITSResponse itsResponse; + + // Start of the Monte-Carlo reconstructed tracks + for (const auto& track : tracks) { + if (!track.has_collision()) { + continue; + } + + if (!track.has_mcParticle()) //! check if track has corresponding MC particle + { + continue; + } + if (!track.isPVContributor()) //! track check as used in data + { + continue; + } + + auto particle = track.mcParticle(); + if (!particle.has_mcCollision()) + continue; + if ((particle.pt() < cfgCutPtLower) || (particle.pt() > 5.0f) || (std::abs(particle.eta()) > cfgCutEta)) { + continue; + } + if (!(track.itsNCls() > cfgITScluster) || !(track.tpcNClsFound() >= cfgTPCcluster) || !(track.tpcNClsCrossedRows() >= cfgTPCnCrossedRows)) { + continue; + } + + if (particle.isPhysicalPrimary()) { + histos.fill(HIST("hrecPartPtAll"), particle.pt()); + histos.fill(HIST("hrecPtAll"), track.pt()); + histos.fill(HIST("hrecEtaAll"), particle.eta()); + histos.fill(HIST("hrecPhiAll"), particle.phi()); + histos.fill(HIST("hrecDcaXYAll"), track.dcaXY()); + histos.fill(HIST("hrecDcaZAll"), track.dcaZ()); + + // rejecting electron + if (cfgIfRejectElectron && isElectron(track)) { + continue; + } + // use ITS pid as well + if (cfgUseItsPid && (std::abs(itsResponse.nSigmaITS(track)) > 3.0)) { + continue; + } + // required tracks with TOF mandatory to avoid pileup + if (cfgIfMandatoryTOF && !track.hasTOF()) { + continue; + } + + bool trackSelected = false; + if (cfgPIDchoice == 0) + trackSelected = selectionPIDoldTOFveto(track); + if (cfgPIDchoice == 1) + trackSelected = selectionPIDnew(track); + if (cfgPIDchoice == 2) + trackSelected = selectionPIDold(track); + + if (trackSelected) { + // filling nSigma distribution + histos.fill(HIST("h2DnsigmaTpcVsPt"), track.pt(), track.tpcNSigmaPr()); + histos.fill(HIST("h2DnsigmaTofVsPt"), track.pt(), track.tofNSigmaPr()); + histos.fill(HIST("h2DnsigmaItsVsPt"), track.pt(), itsResponse.nSigmaITS(track)); + + if (track.sign() > 0) { + histos.fill(HIST("hrecPartPtProton"), particle.pt()); //! hist for p rec + histos.fill(HIST("hrecPtProton"), track.pt()); //! hist for p rec + histos.fill(HIST("hrecPtDistProtonVsCentrality"), particle.pt(), cent); + histos.fill(HIST("hrec2DEtaVsPtProton"), particle.pt(), particle.eta()); + histos.fill(HIST("hrecEtaProton"), particle.eta()); + histos.fill(HIST("hrecPhiProton"), particle.phi()); + histos.fill(HIST("hrecDcaXYProton"), track.dcaXY()); + histos.fill(HIST("hrecDcaZProton"), track.dcaZ()); + if (particle.pt() < cfgCutPtUpper) { + nProt = nProt + 1.0; + float pEff = getEfficiency(track); // get efficiency of track + if (pEff != 0) { + for (int i = 1; i < 7; i++) { + powerEffProt[i] += std::pow(1.0 / pEff, i); + } + } + } + if (particle.pdgCode() == PDG_t::kProton) { + histos.fill(HIST("hrecTruePtProton"), particle.pt()); //! hist for p purity + } + } + if (track.sign() < 0) { + histos.fill(HIST("hrecPartPtAntiproton"), particle.pt()); //! hist for anti-p rec + histos.fill(HIST("hrecPtAntiproton"), track.pt()); //! hist for anti-p rec + histos.fill(HIST("hrecPtDistAntiprotonVsCentrality"), particle.pt(), cent); + histos.fill(HIST("hrec2DEtaVsPtAntiproton"), particle.pt(), particle.eta()); + histos.fill(HIST("hrecEtaAntiproton"), particle.eta()); + histos.fill(HIST("hrecPhiAntiproton"), particle.phi()); + histos.fill(HIST("hrecDcaXYAntiproton"), track.dcaXY()); + histos.fill(HIST("hrecDcaZAntiproton"), track.dcaZ()); + if (particle.pt() < cfgCutPtUpper) { + nAntiprot = nAntiprot + 1.0; + float pEff = getEfficiency(track); // get efficiency of track + if (pEff != 0) { + for (int i = 1; i < 7; i++) { + powerEffAntiprot[i] += std::pow(1.0 / pEff, i); + } + } + } + if (particle.pdgCode() == PDG_t::kProtonBar) { + histos.fill(HIST("hrecTruePtAntiproton"), particle.pt()); //! hist for anti-p purity + } + } + } //! checking PID + } //! checking if primary + } //! end track loop + + float netProt = nProt - nAntiprot; + histos.fill(HIST("hrecNetProtonVsCentrality"), netProt, cent); + histos.fill(HIST("hrecProtonVsCentrality"), nProt, cent); + histos.fill(HIST("hrecAntiprotonVsCentrality"), nAntiprot, cent); + histos.fill(HIST("hrecProfileTotalProton"), cent, (nProt + nAntiprot)); + histos.fill(HIST("hrecProfileProton"), cent, nProt); + histos.fill(HIST("hrecProfileAntiproton"), cent, nAntiprot); + histos.fill(HIST("hCorrProfileTotalProton"), cent, (powerEffProt[1] + powerEffAntiprot[1])); + histos.fill(HIST("hCorrProfileProton"), cent, powerEffProt[1]); + histos.fill(HIST("hCorrProfileAntiproton"), cent, powerEffAntiprot[1]); + + // Calculating q_{r,s} as required + for (int i = 1; i < 7; i++) { + fTCP0[i] = powerEffProt[i] + powerEffAntiprot[i]; + fTCP1[i] = powerEffProt[i] - powerEffAntiprot[i]; + } + + //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + float fQ11_1 = fTCP1[1]; + float fQ11_2 = std::pow(fTCP1[1], 2); + float fQ11_3 = std::pow(fTCP1[1], 3); + float fQ11_4 = std::pow(fTCP1[1], 4); + float fQ11_5 = std::pow(fTCP1[1], 5); + float fQ11_6 = std::pow(fTCP1[1], 6); + + float fQ21_3 = std::pow(fTCP0[1], 3); + float fQ22_3 = std::pow(fTCP0[2], 3); + float fQ31_2 = std::pow(fTCP1[1], 2); + float fQ32_2 = std::pow(fTCP1[2], 2); + float fQ33_2 = std::pow(fTCP1[3], 2); + + float fQ61_1 = fTCP0[1]; + float fQ62_1 = fTCP0[2]; + float fQ63_1 = fTCP0[3]; + float fQ64_1 = fTCP0[4]; + float fQ65_1 = fTCP0[5]; + float fQ66_1 = fTCP0[6]; + + float fQ112122_111 = fTCP1[1] * fTCP0[1] * fTCP0[2]; + float fQ112131_111 = fTCP1[1] * fTCP0[1] * fTCP1[1]; + float fQ112132_111 = fTCP1[1] * fTCP0[1] * fTCP1[2]; + float fQ112133_111 = fTCP1[1] * fTCP0[1] * fTCP1[3]; + float fQ112231_111 = fTCP1[1] * fTCP0[2] * fTCP1[1]; + float fQ112232_111 = fTCP1[1] * fTCP0[2] * fTCP1[2]; + float fQ112233_111 = fTCP1[1] * fTCP0[2] * fTCP1[3]; + float fQ112221_111 = fTCP1[1] * fTCP0[2] * fTCP0[1]; + + float fQ21_1 = fTCP0[1]; + float fQ22_1 = fTCP0[2]; + float fQ31_1 = fTCP1[1]; + float fQ32_1 = fTCP1[2]; + float fQ33_1 = fTCP1[3]; + float fQ41_1 = fTCP0[1]; + float fQ42_1 = fTCP0[2]; + float fQ43_1 = fTCP0[3]; + float fQ44_1 = fTCP0[4]; + float fQ21_2 = std::pow(fTCP0[1], 2); + float fQ22_2 = std::pow(fTCP0[2], 2); + float fQ1121_11 = fTCP1[1] * fTCP0[1]; + float fQ1121_01 = fTCP0[1]; + float fQ1121_10 = fTCP1[1]; + float fQ1121_20 = std::pow(fTCP1[1], 2); + float fQ1121_21 = std::pow(fTCP1[1], 2) * fTCP0[1]; + float fQ1122_11 = fTCP1[1] * fTCP0[2]; + float fQ1122_01 = fTCP0[2]; + float fQ1122_10 = fTCP1[1]; + float fQ1122_20 = std::pow(fTCP1[1], 2); + float fQ1122_21 = std::pow(fTCP1[1], 2) * fTCP0[2]; + float fQ1131_11 = fTCP1[1] * fTCP1[1]; + float fQ1131_01 = fTCP1[1]; + float fQ1131_10 = fTCP1[1]; + float fQ1132_11 = fTCP1[1] * fTCP1[2]; + float fQ1132_01 = fTCP1[2]; + float fQ1132_10 = fTCP1[1]; + float fQ1133_11 = fTCP1[1] * fTCP1[3]; + float fQ1133_01 = fTCP1[3]; + float fQ1133_10 = fTCP1[1]; + float fQ2122_11 = fTCP0[1] * fTCP0[2]; + float fQ2122_01 = fTCP0[2]; + float fQ2122_10 = fTCP0[1]; + + ///////////////---------------------> + float fQ3132_11 = fTCP1[1] * fTCP1[2]; + float fQ3132_01 = fTCP1[2]; + float fQ3132_10 = fTCP1[1]; + float fQ3133_11 = fTCP1[1] * fTCP1[3]; + float fQ3133_01 = fTCP1[3]; + float fQ3133_10 = fTCP1[1]; + float fQ3233_11 = fTCP1[2] * fTCP1[3]; + float fQ3233_01 = fTCP1[3]; + float fQ3233_10 = fTCP1[2]; + float fQ2241_11 = fTCP0[2] * fTCP0[1]; + float fQ2241_01 = fTCP0[1]; + float fQ2241_10 = fTCP0[2]; + float fQ2242_11 = fTCP0[2] * fTCP0[2]; + float fQ2242_01 = fTCP0[2]; + float fQ2242_10 = fTCP0[2]; + float fQ2243_11 = fTCP0[2] * fTCP0[3]; + float fQ2243_01 = fTCP0[3]; + float fQ2243_10 = fTCP0[2]; + float fQ2244_11 = fTCP0[2] * fTCP0[4]; + float fQ2244_01 = fTCP0[4]; + float fQ2244_10 = fTCP0[2]; + float fQ2141_11 = fTCP0[1] * fTCP0[1]; + float fQ2141_01 = fTCP0[1]; + float fQ2141_10 = fTCP0[1]; + float fQ2142_11 = fTCP0[1] * fTCP0[2]; + float fQ2142_01 = fTCP0[2]; + float fQ2142_10 = fTCP0[1]; + float fQ2143_11 = fTCP0[1] * fTCP0[3]; + float fQ2143_01 = fTCP0[3]; + float fQ2143_10 = fTCP0[1]; + float fQ2144_11 = fTCP0[1] * fTCP0[4]; + float fQ2144_01 = fTCP0[4]; + float fQ2144_10 = fTCP0[1]; + float fQ1151_11 = fTCP1[1] * fTCP1[1]; + float fQ1151_01 = fTCP1[1]; + float fQ1151_10 = fTCP1[1]; + float fQ1152_11 = fTCP1[1] * fTCP1[2]; + float fQ1152_01 = fTCP1[2]; + float fQ1152_10 = fTCP1[1]; + float fQ1153_11 = fTCP1[1] * fTCP1[3]; + float fQ1153_01 = fTCP1[3]; + float fQ1153_10 = fTCP1[1]; + float fQ1154_11 = fTCP1[1] * fTCP1[4]; + float fQ1154_01 = fTCP1[4]; + float fQ1154_10 = fTCP1[1]; + float fQ1155_11 = fTCP1[1] * fTCP1[5]; + float fQ1155_01 = fTCP1[5]; + float fQ1155_10 = fTCP1[1]; + + float fQ112233_001 = fTCP1[3]; + float fQ112233_010 = fTCP0[2]; + float fQ112233_100 = fTCP1[1]; + float fQ112233_011 = fTCP0[2] * fTCP1[3]; + float fQ112233_101 = fTCP1[1] * fTCP1[3]; + float fQ112233_110 = fTCP1[1] * fTCP0[2]; + float fQ112232_001 = fTCP1[2]; + float fQ112232_010 = fTCP0[2]; + float fQ112232_100 = fTCP1[1]; + float fQ112232_011 = fTCP0[2] * fTCP1[2]; + float fQ112232_101 = fTCP1[1] * fTCP1[2]; + float fQ112232_110 = fTCP1[1] * fTCP0[2]; + // + float fQ112231_001 = fTCP1[1]; + float fQ112231_010 = fTCP0[2]; + float fQ112231_100 = fTCP1[1]; + float fQ112231_011 = fTCP0[2] * fTCP1[1]; + float fQ112231_101 = fTCP1[1] * fTCP1[1]; + float fQ112231_110 = fTCP1[1] * fTCP0[2]; + float fQ112133_001 = fTCP1[3]; + float fQ112133_010 = fTCP0[1]; + float fQ112133_100 = fTCP1[1]; + float fQ112133_011 = fTCP0[1] * fTCP1[3]; + float fQ112133_101 = fTCP1[1] * fTCP1[3]; + float fQ112133_110 = fTCP1[1] * fTCP0[1]; + + float fQ112132_001 = fTCP1[2]; + float fQ112132_010 = fTCP0[1]; + float fQ112132_100 = fTCP1[1]; + float fQ112132_011 = fTCP0[1] * fTCP1[2]; + float fQ112132_101 = fTCP1[1] * fTCP1[2]; + float fQ112132_110 = fTCP1[1] * fTCP0[1]; + float fQ112131_001 = fTCP1[1]; + float fQ112131_010 = fTCP0[1]; + float fQ112131_100 = fTCP1[1]; + float fQ112131_011 = fTCP0[1] * fTCP1[1]; + float fQ112131_101 = fTCP1[1] * fTCP1[1]; + float fQ112131_110 = fTCP1[1] * fTCP0[1]; + + float fQ2221_11 = fTCP0[2] * fTCP0[1]; + float fQ2221_01 = fTCP0[1]; + float fQ2221_10 = fTCP0[2]; + float fQ2221_21 = std::pow(fTCP0[2], 2) * fTCP0[1]; + float fQ2221_20 = std::pow(fTCP0[2], 2); + + float fQ2122_21 = std::pow(fTCP0[1], 2) * fTCP0[2]; + float fQ2122_20 = std::pow(fTCP0[1], 2); + float fQ1121_02 = std::pow(fTCP0[1], 2); + float fQ1121_12 = fTCP1[1] * std::pow(fTCP0[1], 2); + float fQ1121_22 = std::pow(fTCP1[1], 2) * std::pow(fTCP0[1], 2); + float fQ1122_02 = std::pow(fTCP0[2], 2); + float fQ1122_12 = fTCP1[1] * std::pow(fTCP0[2], 2); + float fQ1122_22 = std::pow(fTCP1[1], 2) * std::pow(fTCP0[2], 2); + + float fQ112221_001 = fTCP0[1]; + float fQ112221_010 = fTCP0[2]; + float fQ112221_100 = fTCP1[1]; + float fQ112221_011 = fTCP0[2] * fTCP0[1]; + float fQ112221_101 = fTCP1[1] * fTCP0[1]; + float fQ112221_110 = fTCP1[1] * fTCP0[2]; + float fQ112221_200 = std::pow(fTCP1[1], 2); + float fQ112221_201 = std::pow(fTCP1[1], 2) * fTCP0[1]; + float fQ112221_210 = std::pow(fTCP1[1], 2) * fTCP0[2]; + float fQ112221_211 = std::pow(fTCP1[1], 2) * fTCP0[2] * fTCP0[1]; + float fQ1131_21 = std::pow(fTCP1[1], 2) * fTCP1[1]; + float fQ1131_20 = std::pow(fTCP1[1], 2); + float fQ1131_31 = std::pow(fTCP1[1], 3) * fTCP1[1]; + float fQ1131_30 = std::pow(fTCP1[1], 3); + + float fQ1132_21 = std::pow(fTCP1[1], 2) * fTCP1[2]; + float fQ1132_20 = std::pow(fTCP1[1], 2); + float fQ1132_31 = std::pow(fTCP1[1], 3) * fTCP1[2]; + float fQ1132_30 = std::pow(fTCP1[1], 3); + float fQ1133_21 = std::pow(fTCP1[1], 2) * fTCP1[3]; + float fQ1133_20 = std::pow(fTCP1[1], 2); + float fQ1133_31 = std::pow(fTCP1[1], 3) * fTCP1[3]; + float fQ1133_30 = std::pow(fTCP1[1], 3); + float fQ1121_30 = std::pow(fTCP1[1], 3); + float fQ1121_31 = std::pow(fTCP1[1], 3) * fTCP0[1]; + float fQ1121_40 = std::pow(fTCP1[1], 4); + float fQ1121_41 = std::pow(fTCP1[1], 4) * fTCP0[1]; + float fQ1122_30 = std::pow(fTCP1[1], 3); + float fQ1122_31 = std::pow(fTCP1[1], 3) * fTCP0[2]; + float fQ1122_40 = std::pow(fTCP1[1], 4); + float fQ1122_41 = std::pow(fTCP1[1], 4) * fTCP0[2]; + + float fQ2211_11 = fTCP0[2] * fTCP1[1]; + float fQ2211_01 = fTCP1[1]; + float fQ2211_10 = fTCP0[2]; + float fQ2211_20 = std::pow(fTCP0[2], 2); + float fQ2211_21 = std::pow(fTCP0[2], 2) * fTCP1[1]; + float fQ2111_11 = fTCP0[1] * fTCP1[1]; + float fQ2111_01 = fTCP1[1]; + float fQ2111_10 = fTCP0[1]; + float fQ2111_20 = std::pow(fTCP0[1], 2); + float fQ2111_21 = std::pow(fTCP0[1], 2) * fTCP1[1]; + + float fQ112122_001 = fTCP0[2]; + float fQ112122_010 = fTCP0[1]; + float fQ112122_100 = fTCP1[1]; + float fQ112122_011 = fTCP0[1] * fTCP0[2]; + float fQ112122_101 = fTCP1[1] * fTCP0[2]; + float fQ112122_110 = fTCP1[1] * fTCP0[1]; + + float fQ1141_11 = fTCP1[1] * fTCP0[1]; + float fQ1141_01 = fTCP0[1]; + float fQ1141_10 = fTCP1[1]; + float fQ1141_20 = std::pow(fTCP1[1], 2); + float fQ1141_21 = std::pow(fTCP1[1], 2) * fTCP0[1]; + float fQ1142_11 = fTCP1[1] * fTCP0[2]; + float fQ1142_01 = fTCP0[2]; + float fQ1142_10 = fTCP1[1]; + float fQ1142_20 = std::pow(fTCP1[1], 2); + float fQ1142_21 = std::pow(fTCP1[1], 2) * fTCP0[2]; + + float fQ1143_11 = fTCP1[1] * fTCP0[3]; + float fQ1143_01 = fTCP0[3]; + float fQ1143_10 = fTCP1[1]; + float fQ1143_20 = std::pow(fTCP1[1], 2); + float fQ1143_21 = std::pow(fTCP1[1], 2) * fTCP0[3]; + float fQ1144_11 = fTCP1[1] * fTCP0[4]; + float fQ1144_01 = fTCP0[4]; + float fQ1144_10 = fTCP1[1]; + float fQ1144_20 = std::pow(fTCP1[1], 2); + float fQ1144_21 = std::pow(fTCP1[1], 2) * fTCP0[4]; + float fQ2131_11 = fTCP0[1] * fTCP1[1]; + float fQ2131_01 = fTCP1[1]; + float fQ2131_10 = fTCP0[1]; + + float fQ2132_11 = fTCP0[1] * fTCP1[2]; + float fQ2132_01 = fTCP1[2]; + float fQ2132_10 = fTCP0[1]; + float fQ2133_11 = fTCP0[1] * fTCP1[3]; + float fQ2133_01 = fTCP1[3]; + float fQ2133_10 = fTCP0[1]; + float fQ2231_11 = fTCP0[2] * fTCP1[1]; + float fQ2231_01 = fTCP1[1]; + float fQ2231_10 = fTCP0[2]; + float fQ2232_11 = fTCP0[2] * fTCP1[2]; + float fQ2232_01 = fTCP1[2]; + float fQ2232_10 = fTCP0[2]; + float fQ2233_11 = fTCP0[2] * fTCP1[3]; + float fQ2233_01 = fTCP1[3]; + float fQ2233_10 = fTCP0[2]; + + float fQ51_1 = fTCP1[1]; + float fQ52_1 = fTCP1[2]; + float fQ53_1 = fTCP1[3]; + float fQ54_1 = fTCP1[4]; + float fQ55_1 = fTCP1[5]; + + //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + if (cfgIsCalculateCentral) { + + // uncorrected + histos.get(HIST("Prof_mu1_netproton"))->Fill(cent, std::pow(netProt, 1.0)); + histos.get(HIST("Prof_mu2_netproton"))->Fill(cent, std::pow(netProt, 2.0)); + histos.get(HIST("Prof_mu3_netproton"))->Fill(cent, std::pow(netProt, 3.0)); + histos.get(HIST("Prof_mu4_netproton"))->Fill(cent, std::pow(netProt, 4.0)); + histos.get(HIST("Prof_mu5_netproton"))->Fill(cent, std::pow(netProt, 5.0)); + histos.get(HIST("Prof_mu6_netproton"))->Fill(cent, std::pow(netProt, 6.0)); + histos.get(HIST("Prof_mu7_netproton"))->Fill(cent, std::pow(netProt, 7.0)); + histos.get(HIST("Prof_mu8_netproton"))->Fill(cent, std::pow(netProt, 8.0)); + + // eff. corrected + histos.get(HIST("Prof_Q11_1"))->Fill(cent, fQ11_1); + histos.get(HIST("Prof_Q11_2"))->Fill(cent, fQ11_2); + histos.get(HIST("Prof_Q11_3"))->Fill(cent, fQ11_3); + histos.get(HIST("Prof_Q11_4"))->Fill(cent, fQ11_4); + histos.get(HIST("Prof_Q21_1"))->Fill(cent, fQ21_1); + histos.get(HIST("Prof_Q22_1"))->Fill(cent, fQ22_1); + histos.get(HIST("Prof_Q31_1"))->Fill(cent, fQ31_1); + histos.get(HIST("Prof_Q32_1"))->Fill(cent, fQ32_1); + histos.get(HIST("Prof_Q33_1"))->Fill(cent, fQ33_1); + histos.get(HIST("Prof_Q41_1"))->Fill(cent, fQ41_1); + histos.get(HIST("Prof_Q42_1"))->Fill(cent, fQ42_1); + histos.get(HIST("Prof_Q43_1"))->Fill(cent, fQ43_1); + histos.get(HIST("Prof_Q44_1"))->Fill(cent, fQ44_1); + histos.get(HIST("Prof_Q21_2"))->Fill(cent, fQ21_2); + histos.get(HIST("Prof_Q22_2"))->Fill(cent, fQ22_2); + histos.get(HIST("Prof_Q1121_11"))->Fill(cent, fQ1121_11); + histos.get(HIST("Prof_Q1121_01"))->Fill(cent, fQ1121_01); + histos.get(HIST("Prof_Q1121_10"))->Fill(cent, fQ1121_10); + histos.get(HIST("Prof_Q1121_20"))->Fill(cent, fQ1121_20); + histos.get(HIST("Prof_Q1121_21"))->Fill(cent, fQ1121_21); + histos.get(HIST("Prof_Q1122_11"))->Fill(cent, fQ1122_11); + histos.get(HIST("Prof_Q1122_01"))->Fill(cent, fQ1122_01); + histos.get(HIST("Prof_Q1122_10"))->Fill(cent, fQ1122_10); + histos.get(HIST("Prof_Q1122_20"))->Fill(cent, fQ1122_20); + histos.get(HIST("Prof_Q1122_21"))->Fill(cent, fQ1122_21); + histos.get(HIST("Prof_Q1131_11"))->Fill(cent, fQ1131_11); + histos.get(HIST("Prof_Q1131_01"))->Fill(cent, fQ1131_01); + histos.get(HIST("Prof_Q1131_10"))->Fill(cent, fQ1131_10); + histos.get(HIST("Prof_Q1132_11"))->Fill(cent, fQ1132_11); + histos.get(HIST("Prof_Q1132_01"))->Fill(cent, fQ1132_01); + histos.get(HIST("Prof_Q1132_10"))->Fill(cent, fQ1132_10); + histos.get(HIST("Prof_Q1133_11"))->Fill(cent, fQ1133_11); + histos.get(HIST("Prof_Q1133_01"))->Fill(cent, fQ1133_01); + histos.get(HIST("Prof_Q1133_10"))->Fill(cent, fQ1133_10); + histos.get(HIST("Prof_Q2122_11"))->Fill(cent, fQ2122_11); + histos.get(HIST("Prof_Q2122_01"))->Fill(cent, fQ2122_01); + histos.get(HIST("Prof_Q2122_10"))->Fill(cent, fQ2122_10); + histos.get(HIST("Prof_Q3132_11"))->Fill(cent, fQ3132_11); + histos.get(HIST("Prof_Q3132_01"))->Fill(cent, fQ3132_01); + histos.get(HIST("Prof_Q3132_10"))->Fill(cent, fQ3132_10); + histos.get(HIST("Prof_Q3133_11"))->Fill(cent, fQ3133_11); + histos.get(HIST("Prof_Q3133_01"))->Fill(cent, fQ3133_01); + histos.get(HIST("Prof_Q3133_10"))->Fill(cent, fQ3133_10); + histos.get(HIST("Prof_Q3233_11"))->Fill(cent, fQ3233_11); + histos.get(HIST("Prof_Q3233_01"))->Fill(cent, fQ3233_01); + histos.get(HIST("Prof_Q3233_10"))->Fill(cent, fQ3233_10); + histos.get(HIST("Prof_Q2241_11"))->Fill(cent, fQ2241_11); + histos.get(HIST("Prof_Q2241_01"))->Fill(cent, fQ2241_01); + histos.get(HIST("Prof_Q2241_10"))->Fill(cent, fQ2241_10); + histos.get(HIST("Prof_Q2242_11"))->Fill(cent, fQ2242_11); + histos.get(HIST("Prof_Q2242_01"))->Fill(cent, fQ2242_01); + histos.get(HIST("Prof_Q2242_10"))->Fill(cent, fQ2242_10); + histos.get(HIST("Prof_Q2243_11"))->Fill(cent, fQ2243_11); + histos.get(HIST("Prof_Q2243_01"))->Fill(cent, fQ2243_01); + histos.get(HIST("Prof_Q2243_10"))->Fill(cent, fQ2243_10); + histos.get(HIST("Prof_Q2244_11"))->Fill(cent, fQ2244_11); + histos.get(HIST("Prof_Q2244_01"))->Fill(cent, fQ2244_01); + histos.get(HIST("Prof_Q2244_10"))->Fill(cent, fQ2244_10); + histos.get(HIST("Prof_Q2141_11"))->Fill(cent, fQ2141_11); + histos.get(HIST("Prof_Q2141_01"))->Fill(cent, fQ2141_01); + histos.get(HIST("Prof_Q2141_10"))->Fill(cent, fQ2141_10); + histos.get(HIST("Prof_Q2142_11"))->Fill(cent, fQ2142_11); + histos.get(HIST("Prof_Q2142_01"))->Fill(cent, fQ2142_01); + histos.get(HIST("Prof_Q2142_10"))->Fill(cent, fQ2142_10); + histos.get(HIST("Prof_Q2143_11"))->Fill(cent, fQ2143_11); + histos.get(HIST("Prof_Q2143_01"))->Fill(cent, fQ2143_01); + histos.get(HIST("Prof_Q2143_10"))->Fill(cent, fQ2143_10); + histos.get(HIST("Prof_Q2144_11"))->Fill(cent, fQ2144_11); + histos.get(HIST("Prof_Q2144_01"))->Fill(cent, fQ2144_01); + histos.get(HIST("Prof_Q2144_10"))->Fill(cent, fQ2144_10); + histos.get(HIST("Prof_Q1151_11"))->Fill(cent, fQ1151_11); + histos.get(HIST("Prof_Q1151_01"))->Fill(cent, fQ1151_01); + histos.get(HIST("Prof_Q1151_10"))->Fill(cent, fQ1151_10); + histos.get(HIST("Prof_Q1152_11"))->Fill(cent, fQ1152_11); + histos.get(HIST("Prof_Q1152_01"))->Fill(cent, fQ1152_01); + histos.get(HIST("Prof_Q1152_10"))->Fill(cent, fQ1152_10); + histos.get(HIST("Prof_Q1153_11"))->Fill(cent, fQ1153_11); + histos.get(HIST("Prof_Q1153_01"))->Fill(cent, fQ1153_01); + histos.get(HIST("Prof_Q1153_10"))->Fill(cent, fQ1153_10); + histos.get(HIST("Prof_Q1154_11"))->Fill(cent, fQ1154_11); + histos.get(HIST("Prof_Q1154_01"))->Fill(cent, fQ1154_01); + histos.get(HIST("Prof_Q1154_10"))->Fill(cent, fQ1154_10); + histos.get(HIST("Prof_Q1155_11"))->Fill(cent, fQ1155_11); + histos.get(HIST("Prof_Q1155_01"))->Fill(cent, fQ1155_01); + histos.get(HIST("Prof_Q1155_10"))->Fill(cent, fQ1155_10); + histos.get(HIST("Prof_Q112233_001"))->Fill(cent, fQ112233_001); + histos.get(HIST("Prof_Q112233_010"))->Fill(cent, fQ112233_010); + histos.get(HIST("Prof_Q112233_100"))->Fill(cent, fQ112233_100); + histos.get(HIST("Prof_Q112233_011"))->Fill(cent, fQ112233_011); + histos.get(HIST("Prof_Q112233_101"))->Fill(cent, fQ112233_101); + histos.get(HIST("Prof_Q112233_110"))->Fill(cent, fQ112233_110); + histos.get(HIST("Prof_Q112232_001"))->Fill(cent, fQ112232_001); + histos.get(HIST("Prof_Q112232_010"))->Fill(cent, fQ112232_010); + histos.get(HIST("Prof_Q112232_100"))->Fill(cent, fQ112232_100); + histos.get(HIST("Prof_Q112232_011"))->Fill(cent, fQ112232_011); + histos.get(HIST("Prof_Q112232_101"))->Fill(cent, fQ112232_101); + histos.get(HIST("Prof_Q112232_110"))->Fill(cent, fQ112232_110); + histos.get(HIST("Prof_Q112231_001"))->Fill(cent, fQ112231_001); + histos.get(HIST("Prof_Q112231_010"))->Fill(cent, fQ112231_010); + histos.get(HIST("Prof_Q112231_100"))->Fill(cent, fQ112231_100); + histos.get(HIST("Prof_Q112231_011"))->Fill(cent, fQ112231_011); + histos.get(HIST("Prof_Q112231_101"))->Fill(cent, fQ112231_101); + histos.get(HIST("Prof_Q112231_110"))->Fill(cent, fQ112231_110); + histos.get(HIST("Prof_Q112133_001"))->Fill(cent, fQ112133_001); + histos.get(HIST("Prof_Q112133_010"))->Fill(cent, fQ112133_010); + histos.get(HIST("Prof_Q112133_100"))->Fill(cent, fQ112133_100); + histos.get(HIST("Prof_Q112133_011"))->Fill(cent, fQ112133_011); + histos.get(HIST("Prof_Q112133_101"))->Fill(cent, fQ112133_101); + histos.get(HIST("Prof_Q112133_110"))->Fill(cent, fQ112133_110); + histos.get(HIST("Prof_Q112132_001"))->Fill(cent, fQ112132_001); + histos.get(HIST("Prof_Q112132_010"))->Fill(cent, fQ112132_010); + histos.get(HIST("Prof_Q112132_100"))->Fill(cent, fQ112132_100); + histos.get(HIST("Prof_Q112132_011"))->Fill(cent, fQ112132_011); + histos.get(HIST("Prof_Q112132_101"))->Fill(cent, fQ112132_101); + histos.get(HIST("Prof_Q112132_110"))->Fill(cent, fQ112132_110); + histos.get(HIST("Prof_Q112131_001"))->Fill(cent, fQ112131_001); + histos.get(HIST("Prof_Q112131_010"))->Fill(cent, fQ112131_010); + histos.get(HIST("Prof_Q112131_100"))->Fill(cent, fQ112131_100); + histos.get(HIST("Prof_Q112131_011"))->Fill(cent, fQ112131_011); + histos.get(HIST("Prof_Q112131_101"))->Fill(cent, fQ112131_101); + histos.get(HIST("Prof_Q112131_110"))->Fill(cent, fQ112131_110); + histos.get(HIST("Prof_Q2221_11"))->Fill(cent, fQ2221_11); + histos.get(HIST("Prof_Q2221_01"))->Fill(cent, fQ2221_01); + histos.get(HIST("Prof_Q2221_10"))->Fill(cent, fQ2221_10); + histos.get(HIST("Prof_Q2221_21"))->Fill(cent, fQ2221_21); + histos.get(HIST("Prof_Q2221_20"))->Fill(cent, fQ2221_20); + histos.get(HIST("Prof_Q2122_21"))->Fill(cent, fQ2122_21); + histos.get(HIST("Prof_Q2122_20"))->Fill(cent, fQ2122_20); + histos.get(HIST("Prof_Q1121_02"))->Fill(cent, fQ1121_02); + histos.get(HIST("Prof_Q1121_12"))->Fill(cent, fQ1121_12); + histos.get(HIST("Prof_Q1121_22"))->Fill(cent, fQ1121_22); + histos.get(HIST("Prof_Q1122_02"))->Fill(cent, fQ1122_02); + histos.get(HIST("Prof_Q1122_12"))->Fill(cent, fQ1122_12); + histos.get(HIST("Prof_Q1122_22"))->Fill(cent, fQ1122_22); + histos.get(HIST("Prof_Q112221_001"))->Fill(cent, fQ112221_001); + histos.get(HIST("Prof_Q112221_010"))->Fill(cent, fQ112221_010); + histos.get(HIST("Prof_Q112221_100"))->Fill(cent, fQ112221_100); + histos.get(HIST("Prof_Q112221_011"))->Fill(cent, fQ112221_011); + histos.get(HIST("Prof_Q112221_101"))->Fill(cent, fQ112221_101); + histos.get(HIST("Prof_Q112221_110"))->Fill(cent, fQ112221_110); + histos.get(HIST("Prof_Q112221_200"))->Fill(cent, fQ112221_200); + histos.get(HIST("Prof_Q112221_201"))->Fill(cent, fQ112221_201); + histos.get(HIST("Prof_Q112221_210"))->Fill(cent, fQ112221_210); + histos.get(HIST("Prof_Q112221_211"))->Fill(cent, fQ112221_211); + histos.get(HIST("Prof_Q1131_21"))->Fill(cent, fQ1131_21); + histos.get(HIST("Prof_Q1131_20"))->Fill(cent, fQ1131_20); + histos.get(HIST("Prof_Q1131_31"))->Fill(cent, fQ1131_31); + histos.get(HIST("Prof_Q1131_30"))->Fill(cent, fQ1131_30); + histos.get(HIST("Prof_Q1132_21"))->Fill(cent, fQ1132_21); + histos.get(HIST("Prof_Q1132_20"))->Fill(cent, fQ1132_20); + histos.get(HIST("Prof_Q1132_31"))->Fill(cent, fQ1132_31); + histos.get(HIST("Prof_Q1132_30"))->Fill(cent, fQ1132_30); + histos.get(HIST("Prof_Q1133_21"))->Fill(cent, fQ1133_21); + histos.get(HIST("Prof_Q1133_20"))->Fill(cent, fQ1133_20); + histos.get(HIST("Prof_Q1133_31"))->Fill(cent, fQ1133_31); + histos.get(HIST("Prof_Q1133_30"))->Fill(cent, fQ1133_30); + histos.get(HIST("Prof_Q11_5"))->Fill(cent, fQ11_5); + histos.get(HIST("Prof_Q11_6"))->Fill(cent, fQ11_6); + histos.get(HIST("Prof_Q1121_30"))->Fill(cent, fQ1121_30); + histos.get(HIST("Prof_Q1121_31"))->Fill(cent, fQ1121_31); + histos.get(HIST("Prof_Q1121_40"))->Fill(cent, fQ1121_40); + histos.get(HIST("Prof_Q1121_41"))->Fill(cent, fQ1121_41); + histos.get(HIST("Prof_Q1122_30"))->Fill(cent, fQ1122_30); + histos.get(HIST("Prof_Q1122_31"))->Fill(cent, fQ1122_31); + histos.get(HIST("Prof_Q1122_40"))->Fill(cent, fQ1122_40); + histos.get(HIST("Prof_Q1122_41"))->Fill(cent, fQ1122_41); + histos.get(HIST("Prof_Q2211_11"))->Fill(cent, fQ2211_11); + histos.get(HIST("Prof_Q2211_01"))->Fill(cent, fQ2211_01); + histos.get(HIST("Prof_Q2211_10"))->Fill(cent, fQ2211_10); + histos.get(HIST("Prof_Q2211_20"))->Fill(cent, fQ2211_20); + histos.get(HIST("Prof_Q2211_21"))->Fill(cent, fQ2211_21); + histos.get(HIST("Prof_Q2111_11"))->Fill(cent, fQ2111_11); + histos.get(HIST("Prof_Q2111_01"))->Fill(cent, fQ2111_01); + histos.get(HIST("Prof_Q2111_10"))->Fill(cent, fQ2111_10); + histos.get(HIST("Prof_Q2111_20"))->Fill(cent, fQ2111_20); + histos.get(HIST("Prof_Q2111_21"))->Fill(cent, fQ2111_21); + histos.get(HIST("Prof_Q112122_001"))->Fill(cent, fQ112122_001); + histos.get(HIST("Prof_Q112122_010"))->Fill(cent, fQ112122_010); + histos.get(HIST("Prof_Q112122_100"))->Fill(cent, fQ112122_100); + histos.get(HIST("Prof_Q112122_011"))->Fill(cent, fQ112122_011); + histos.get(HIST("Prof_Q112122_101"))->Fill(cent, fQ112122_101); + histos.get(HIST("Prof_Q112122_110"))->Fill(cent, fQ112122_110); + histos.get(HIST("Prof_Q1141_11"))->Fill(cent, fQ1141_11); + histos.get(HIST("Prof_Q1141_01"))->Fill(cent, fQ1141_01); + histos.get(HIST("Prof_Q1141_10"))->Fill(cent, fQ1141_10); + histos.get(HIST("Prof_Q1141_20"))->Fill(cent, fQ1141_20); + histos.get(HIST("Prof_Q1141_21"))->Fill(cent, fQ1141_21); + histos.get(HIST("Prof_Q1142_11"))->Fill(cent, fQ1142_11); + histos.get(HIST("Prof_Q1142_01"))->Fill(cent, fQ1142_01); + histos.get(HIST("Prof_Q1142_10"))->Fill(cent, fQ1142_10); + histos.get(HIST("Prof_Q1142_20"))->Fill(cent, fQ1142_20); + histos.get(HIST("Prof_Q1142_21"))->Fill(cent, fQ1142_21); + histos.get(HIST("Prof_Q1143_11"))->Fill(cent, fQ1143_11); + histos.get(HIST("Prof_Q1143_01"))->Fill(cent, fQ1143_01); + histos.get(HIST("Prof_Q1143_10"))->Fill(cent, fQ1143_10); + histos.get(HIST("Prof_Q1143_20"))->Fill(cent, fQ1143_20); + histos.get(HIST("Prof_Q1143_21"))->Fill(cent, fQ1143_21); + histos.get(HIST("Prof_Q1144_11"))->Fill(cent, fQ1144_11); + histos.get(HIST("Prof_Q1144_01"))->Fill(cent, fQ1144_01); + histos.get(HIST("Prof_Q1144_10"))->Fill(cent, fQ1144_10); + histos.get(HIST("Prof_Q1144_20"))->Fill(cent, fQ1144_20); + histos.get(HIST("Prof_Q1144_21"))->Fill(cent, fQ1144_21); + histos.get(HIST("Prof_Q2131_11"))->Fill(cent, fQ2131_11); + histos.get(HIST("Prof_Q2131_01"))->Fill(cent, fQ2131_01); + histos.get(HIST("Prof_Q2131_10"))->Fill(cent, fQ2131_10); + histos.get(HIST("Prof_Q2132_11"))->Fill(cent, fQ2132_11); + histos.get(HIST("Prof_Q2132_01"))->Fill(cent, fQ2132_01); + histos.get(HIST("Prof_Q2132_10"))->Fill(cent, fQ2132_10); + histos.get(HIST("Prof_Q2133_11"))->Fill(cent, fQ2133_11); + histos.get(HIST("Prof_Q2133_01"))->Fill(cent, fQ2133_01); + histos.get(HIST("Prof_Q2133_10"))->Fill(cent, fQ2133_10); + histos.get(HIST("Prof_Q2231_11"))->Fill(cent, fQ2231_11); + histos.get(HIST("Prof_Q2231_01"))->Fill(cent, fQ2231_01); + histos.get(HIST("Prof_Q2231_10"))->Fill(cent, fQ2231_10); + histos.get(HIST("Prof_Q2232_11"))->Fill(cent, fQ2232_11); + histos.get(HIST("Prof_Q2232_01"))->Fill(cent, fQ2232_01); + histos.get(HIST("Prof_Q2232_10"))->Fill(cent, fQ2232_10); + histos.get(HIST("Prof_Q2233_11"))->Fill(cent, fQ2233_11); + histos.get(HIST("Prof_Q2233_01"))->Fill(cent, fQ2233_01); + histos.get(HIST("Prof_Q2233_10"))->Fill(cent, fQ2233_10); + histos.get(HIST("Prof_Q51_1"))->Fill(cent, fQ51_1); + histos.get(HIST("Prof_Q52_1"))->Fill(cent, fQ52_1); + histos.get(HIST("Prof_Q53_1"))->Fill(cent, fQ53_1); + histos.get(HIST("Prof_Q54_1"))->Fill(cent, fQ54_1); + histos.get(HIST("Prof_Q55_1"))->Fill(cent, fQ55_1); + histos.get(HIST("Prof_Q21_3"))->Fill(cent, fQ21_3); + histos.get(HIST("Prof_Q22_3"))->Fill(cent, fQ22_3); + histos.get(HIST("Prof_Q31_2"))->Fill(cent, fQ31_2); + histos.get(HIST("Prof_Q32_2"))->Fill(cent, fQ32_2); + histos.get(HIST("Prof_Q33_2"))->Fill(cent, fQ33_2); + histos.get(HIST("Prof_Q61_1"))->Fill(cent, fQ61_1); + histos.get(HIST("Prof_Q62_1"))->Fill(cent, fQ62_1); + histos.get(HIST("Prof_Q63_1"))->Fill(cent, fQ63_1); + histos.get(HIST("Prof_Q64_1"))->Fill(cent, fQ64_1); + histos.get(HIST("Prof_Q65_1"))->Fill(cent, fQ65_1); + histos.get(HIST("Prof_Q66_1"))->Fill(cent, fQ66_1); + histos.get(HIST("Prof_Q112122_111"))->Fill(cent, fQ112122_111); + histos.get(HIST("Prof_Q112131_111"))->Fill(cent, fQ112131_111); + histos.get(HIST("Prof_Q112132_111"))->Fill(cent, fQ112132_111); + histos.get(HIST("Prof_Q112133_111"))->Fill(cent, fQ112133_111); + histos.get(HIST("Prof_Q112231_111"))->Fill(cent, fQ112231_111); + histos.get(HIST("Prof_Q112232_111"))->Fill(cent, fQ112232_111); + histos.get(HIST("Prof_Q112233_111"))->Fill(cent, fQ112233_111); + histos.get(HIST("Prof_Q112221_111"))->Fill(cent, fQ112221_111); + } + + if (cfgIsCalculateError) { + // selecting subsample and filling profiles + float lRandom = fRndm->Rndm(); + int sampleIndex = static_cast(cfgNSubsample * lRandom); + + histos.get(HIST("Prof2D_mu1_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 1.0)); + histos.get(HIST("Prof2D_mu2_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 2.0)); + histos.get(HIST("Prof2D_mu3_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 3.0)); + histos.get(HIST("Prof2D_mu4_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 4.0)); + histos.get(HIST("Prof2D_mu5_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 5.0)); + histos.get(HIST("Prof2D_mu6_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 6.0)); + histos.get(HIST("Prof2D_mu7_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 7.0)); + histos.get(HIST("Prof2D_mu8_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 8.0)); + + histos.get(HIST("Prof2D_Q11_1"))->Fill(cent, sampleIndex, fQ11_1); + histos.get(HIST("Prof2D_Q11_2"))->Fill(cent, sampleIndex, fQ11_2); + histos.get(HIST("Prof2D_Q11_3"))->Fill(cent, sampleIndex, fQ11_3); + histos.get(HIST("Prof2D_Q11_4"))->Fill(cent, sampleIndex, fQ11_4); + histos.get(HIST("Prof2D_Q21_1"))->Fill(cent, sampleIndex, fQ21_1); + histos.get(HIST("Prof2D_Q22_1"))->Fill(cent, sampleIndex, fQ22_1); + histos.get(HIST("Prof2D_Q31_1"))->Fill(cent, sampleIndex, fQ31_1); + histos.get(HIST("Prof2D_Q32_1"))->Fill(cent, sampleIndex, fQ32_1); + histos.get(HIST("Prof2D_Q33_1"))->Fill(cent, sampleIndex, fQ33_1); + histos.get(HIST("Prof2D_Q41_1"))->Fill(cent, sampleIndex, fQ41_1); + histos.get(HIST("Prof2D_Q42_1"))->Fill(cent, sampleIndex, fQ42_1); + histos.get(HIST("Prof2D_Q43_1"))->Fill(cent, sampleIndex, fQ43_1); + histos.get(HIST("Prof2D_Q44_1"))->Fill(cent, sampleIndex, fQ44_1); + histos.get(HIST("Prof2D_Q21_2"))->Fill(cent, sampleIndex, fQ21_2); + histos.get(HIST("Prof2D_Q22_2"))->Fill(cent, sampleIndex, fQ22_2); + histos.get(HIST("Prof2D_Q1121_11"))->Fill(cent, sampleIndex, fQ1121_11); + histos.get(HIST("Prof2D_Q1121_01"))->Fill(cent, sampleIndex, fQ1121_01); + histos.get(HIST("Prof2D_Q1121_10"))->Fill(cent, sampleIndex, fQ1121_10); + histos.get(HIST("Prof2D_Q1121_20"))->Fill(cent, sampleIndex, fQ1121_20); + histos.get(HIST("Prof2D_Q1121_21"))->Fill(cent, sampleIndex, fQ1121_21); + histos.get(HIST("Prof2D_Q1122_11"))->Fill(cent, sampleIndex, fQ1122_11); + histos.get(HIST("Prof2D_Q1122_01"))->Fill(cent, sampleIndex, fQ1122_01); + histos.get(HIST("Prof2D_Q1122_10"))->Fill(cent, sampleIndex, fQ1122_10); + histos.get(HIST("Prof2D_Q1122_20"))->Fill(cent, sampleIndex, fQ1122_20); + histos.get(HIST("Prof2D_Q1122_21"))->Fill(cent, sampleIndex, fQ1122_21); + histos.get(HIST("Prof2D_Q1131_11"))->Fill(cent, sampleIndex, fQ1131_11); + histos.get(HIST("Prof2D_Q1131_01"))->Fill(cent, sampleIndex, fQ1131_01); + histos.get(HIST("Prof2D_Q1131_10"))->Fill(cent, sampleIndex, fQ1131_10); + histos.get(HIST("Prof2D_Q1132_11"))->Fill(cent, sampleIndex, fQ1132_11); + histos.get(HIST("Prof2D_Q1132_01"))->Fill(cent, sampleIndex, fQ1132_01); + histos.get(HIST("Prof2D_Q1132_10"))->Fill(cent, sampleIndex, fQ1132_10); + histos.get(HIST("Prof2D_Q1133_11"))->Fill(cent, sampleIndex, fQ1133_11); + histos.get(HIST("Prof2D_Q1133_01"))->Fill(cent, sampleIndex, fQ1133_01); + histos.get(HIST("Prof2D_Q1133_10"))->Fill(cent, sampleIndex, fQ1133_10); + histos.get(HIST("Prof2D_Q2122_11"))->Fill(cent, sampleIndex, fQ2122_11); + histos.get(HIST("Prof2D_Q2122_01"))->Fill(cent, sampleIndex, fQ2122_01); + histos.get(HIST("Prof2D_Q2122_10"))->Fill(cent, sampleIndex, fQ2122_10); + histos.get(HIST("Prof2D_Q3132_11"))->Fill(cent, sampleIndex, fQ3132_11); + histos.get(HIST("Prof2D_Q3132_01"))->Fill(cent, sampleIndex, fQ3132_01); + histos.get(HIST("Prof2D_Q3132_10"))->Fill(cent, sampleIndex, fQ3132_10); + histos.get(HIST("Prof2D_Q3133_11"))->Fill(cent, sampleIndex, fQ3133_11); + histos.get(HIST("Prof2D_Q3133_01"))->Fill(cent, sampleIndex, fQ3133_01); + histos.get(HIST("Prof2D_Q3133_10"))->Fill(cent, sampleIndex, fQ3133_10); + histos.get(HIST("Prof2D_Q3233_11"))->Fill(cent, sampleIndex, fQ3233_11); + histos.get(HIST("Prof2D_Q3233_01"))->Fill(cent, sampleIndex, fQ3233_01); + histos.get(HIST("Prof2D_Q3233_10"))->Fill(cent, sampleIndex, fQ3233_10); + histos.get(HIST("Prof2D_Q2241_11"))->Fill(cent, sampleIndex, fQ2241_11); + histos.get(HIST("Prof2D_Q2241_01"))->Fill(cent, sampleIndex, fQ2241_01); + histos.get(HIST("Prof2D_Q2241_10"))->Fill(cent, sampleIndex, fQ2241_10); + histos.get(HIST("Prof2D_Q2242_11"))->Fill(cent, sampleIndex, fQ2242_11); + histos.get(HIST("Prof2D_Q2242_01"))->Fill(cent, sampleIndex, fQ2242_01); + histos.get(HIST("Prof2D_Q2242_10"))->Fill(cent, sampleIndex, fQ2242_10); + histos.get(HIST("Prof2D_Q2243_11"))->Fill(cent, sampleIndex, fQ2243_11); + histos.get(HIST("Prof2D_Q2243_01"))->Fill(cent, sampleIndex, fQ2243_01); + histos.get(HIST("Prof2D_Q2243_10"))->Fill(cent, sampleIndex, fQ2243_10); + histos.get(HIST("Prof2D_Q2244_11"))->Fill(cent, sampleIndex, fQ2244_11); + histos.get(HIST("Prof2D_Q2244_01"))->Fill(cent, sampleIndex, fQ2244_01); + histos.get(HIST("Prof2D_Q2244_10"))->Fill(cent, sampleIndex, fQ2244_10); + histos.get(HIST("Prof2D_Q2141_11"))->Fill(cent, sampleIndex, fQ2141_11); + histos.get(HIST("Prof2D_Q2141_01"))->Fill(cent, sampleIndex, fQ2141_01); + histos.get(HIST("Prof2D_Q2141_10"))->Fill(cent, sampleIndex, fQ2141_10); + histos.get(HIST("Prof2D_Q2142_11"))->Fill(cent, sampleIndex, fQ2142_11); + histos.get(HIST("Prof2D_Q2142_01"))->Fill(cent, sampleIndex, fQ2142_01); + histos.get(HIST("Prof2D_Q2142_10"))->Fill(cent, sampleIndex, fQ2142_10); + histos.get(HIST("Prof2D_Q2143_11"))->Fill(cent, sampleIndex, fQ2143_11); + histos.get(HIST("Prof2D_Q2143_01"))->Fill(cent, sampleIndex, fQ2143_01); + histos.get(HIST("Prof2D_Q2143_10"))->Fill(cent, sampleIndex, fQ2143_10); + histos.get(HIST("Prof2D_Q2144_11"))->Fill(cent, sampleIndex, fQ2144_11); + histos.get(HIST("Prof2D_Q2144_01"))->Fill(cent, sampleIndex, fQ2144_01); + histos.get(HIST("Prof2D_Q2144_10"))->Fill(cent, sampleIndex, fQ2144_10); + histos.get(HIST("Prof2D_Q1151_11"))->Fill(cent, sampleIndex, fQ1151_11); + histos.get(HIST("Prof2D_Q1151_01"))->Fill(cent, sampleIndex, fQ1151_01); + histos.get(HIST("Prof2D_Q1151_10"))->Fill(cent, sampleIndex, fQ1151_10); + histos.get(HIST("Prof2D_Q1152_11"))->Fill(cent, sampleIndex, fQ1152_11); + histos.get(HIST("Prof2D_Q1152_01"))->Fill(cent, sampleIndex, fQ1152_01); + histos.get(HIST("Prof2D_Q1152_10"))->Fill(cent, sampleIndex, fQ1152_10); + histos.get(HIST("Prof2D_Q1153_11"))->Fill(cent, sampleIndex, fQ1153_11); + histos.get(HIST("Prof2D_Q1153_01"))->Fill(cent, sampleIndex, fQ1153_01); + histos.get(HIST("Prof2D_Q1153_10"))->Fill(cent, sampleIndex, fQ1153_10); + histos.get(HIST("Prof2D_Q1154_11"))->Fill(cent, sampleIndex, fQ1154_11); + histos.get(HIST("Prof2D_Q1154_01"))->Fill(cent, sampleIndex, fQ1154_01); + histos.get(HIST("Prof2D_Q1154_10"))->Fill(cent, sampleIndex, fQ1154_10); + histos.get(HIST("Prof2D_Q1155_11"))->Fill(cent, sampleIndex, fQ1155_11); + histos.get(HIST("Prof2D_Q1155_01"))->Fill(cent, sampleIndex, fQ1155_01); + histos.get(HIST("Prof2D_Q1155_10"))->Fill(cent, sampleIndex, fQ1155_10); + histos.get(HIST("Prof2D_Q112233_001"))->Fill(cent, sampleIndex, fQ112233_001); + histos.get(HIST("Prof2D_Q112233_010"))->Fill(cent, sampleIndex, fQ112233_010); + histos.get(HIST("Prof2D_Q112233_100"))->Fill(cent, sampleIndex, fQ112233_100); + histos.get(HIST("Prof2D_Q112233_011"))->Fill(cent, sampleIndex, fQ112233_011); + histos.get(HIST("Prof2D_Q112233_101"))->Fill(cent, sampleIndex, fQ112233_101); + histos.get(HIST("Prof2D_Q112233_110"))->Fill(cent, sampleIndex, fQ112233_110); + histos.get(HIST("Prof2D_Q112232_001"))->Fill(cent, sampleIndex, fQ112232_001); + histos.get(HIST("Prof2D_Q112232_010"))->Fill(cent, sampleIndex, fQ112232_010); + histos.get(HIST("Prof2D_Q112232_100"))->Fill(cent, sampleIndex, fQ112232_100); + histos.get(HIST("Prof2D_Q112232_011"))->Fill(cent, sampleIndex, fQ112232_011); + histos.get(HIST("Prof2D_Q112232_101"))->Fill(cent, sampleIndex, fQ112232_101); + histos.get(HIST("Prof2D_Q112232_110"))->Fill(cent, sampleIndex, fQ112232_110); + histos.get(HIST("Prof2D_Q112231_001"))->Fill(cent, sampleIndex, fQ112231_001); + histos.get(HIST("Prof2D_Q112231_010"))->Fill(cent, sampleIndex, fQ112231_010); + histos.get(HIST("Prof2D_Q112231_100"))->Fill(cent, sampleIndex, fQ112231_100); + histos.get(HIST("Prof2D_Q112231_011"))->Fill(cent, sampleIndex, fQ112231_011); + histos.get(HIST("Prof2D_Q112231_101"))->Fill(cent, sampleIndex, fQ112231_101); + histos.get(HIST("Prof2D_Q112231_110"))->Fill(cent, sampleIndex, fQ112231_110); + histos.get(HIST("Prof2D_Q112133_001"))->Fill(cent, sampleIndex, fQ112133_001); + histos.get(HIST("Prof2D_Q112133_010"))->Fill(cent, sampleIndex, fQ112133_010); + histos.get(HIST("Prof2D_Q112133_100"))->Fill(cent, sampleIndex, fQ112133_100); + histos.get(HIST("Prof2D_Q112133_011"))->Fill(cent, sampleIndex, fQ112133_011); + histos.get(HIST("Prof2D_Q112133_101"))->Fill(cent, sampleIndex, fQ112133_101); + histos.get(HIST("Prof2D_Q112133_110"))->Fill(cent, sampleIndex, fQ112133_110); + histos.get(HIST("Prof2D_Q112132_001"))->Fill(cent, sampleIndex, fQ112132_001); + histos.get(HIST("Prof2D_Q112132_010"))->Fill(cent, sampleIndex, fQ112132_010); + histos.get(HIST("Prof2D_Q112132_100"))->Fill(cent, sampleIndex, fQ112132_100); + histos.get(HIST("Prof2D_Q112132_011"))->Fill(cent, sampleIndex, fQ112132_011); + histos.get(HIST("Prof2D_Q112132_101"))->Fill(cent, sampleIndex, fQ112132_101); + histos.get(HIST("Prof2D_Q112132_110"))->Fill(cent, sampleIndex, fQ112132_110); + histos.get(HIST("Prof2D_Q112131_001"))->Fill(cent, sampleIndex, fQ112131_001); + histos.get(HIST("Prof2D_Q112131_010"))->Fill(cent, sampleIndex, fQ112131_010); + histos.get(HIST("Prof2D_Q112131_100"))->Fill(cent, sampleIndex, fQ112131_100); + histos.get(HIST("Prof2D_Q112131_011"))->Fill(cent, sampleIndex, fQ112131_011); + histos.get(HIST("Prof2D_Q112131_101"))->Fill(cent, sampleIndex, fQ112131_101); + histos.get(HIST("Prof2D_Q112131_110"))->Fill(cent, sampleIndex, fQ112131_110); + histos.get(HIST("Prof2D_Q2221_11"))->Fill(cent, sampleIndex, fQ2221_11); + histos.get(HIST("Prof2D_Q2221_01"))->Fill(cent, sampleIndex, fQ2221_01); + histos.get(HIST("Prof2D_Q2221_10"))->Fill(cent, sampleIndex, fQ2221_10); + histos.get(HIST("Prof2D_Q2221_21"))->Fill(cent, sampleIndex, fQ2221_21); + histos.get(HIST("Prof2D_Q2221_20"))->Fill(cent, sampleIndex, fQ2221_20); + histos.get(HIST("Prof2D_Q2122_21"))->Fill(cent, sampleIndex, fQ2122_21); + histos.get(HIST("Prof2D_Q2122_20"))->Fill(cent, sampleIndex, fQ2122_20); + histos.get(HIST("Prof2D_Q1121_02"))->Fill(cent, sampleIndex, fQ1121_02); + histos.get(HIST("Prof2D_Q1121_12"))->Fill(cent, sampleIndex, fQ1121_12); + histos.get(HIST("Prof2D_Q1121_22"))->Fill(cent, sampleIndex, fQ1121_22); + histos.get(HIST("Prof2D_Q1122_02"))->Fill(cent, sampleIndex, fQ1122_02); + histos.get(HIST("Prof2D_Q1122_12"))->Fill(cent, sampleIndex, fQ1122_12); + histos.get(HIST("Prof2D_Q1122_22"))->Fill(cent, sampleIndex, fQ1122_22); + histos.get(HIST("Prof2D_Q112221_001"))->Fill(cent, sampleIndex, fQ112221_001); + histos.get(HIST("Prof2D_Q112221_010"))->Fill(cent, sampleIndex, fQ112221_010); + histos.get(HIST("Prof2D_Q112221_100"))->Fill(cent, sampleIndex, fQ112221_100); + histos.get(HIST("Prof2D_Q112221_011"))->Fill(cent, sampleIndex, fQ112221_011); + histos.get(HIST("Prof2D_Q112221_101"))->Fill(cent, sampleIndex, fQ112221_101); + histos.get(HIST("Prof2D_Q112221_110"))->Fill(cent, sampleIndex, fQ112221_110); + histos.get(HIST("Prof2D_Q112221_200"))->Fill(cent, sampleIndex, fQ112221_200); + histos.get(HIST("Prof2D_Q112221_201"))->Fill(cent, sampleIndex, fQ112221_201); + histos.get(HIST("Prof2D_Q112221_210"))->Fill(cent, sampleIndex, fQ112221_210); + histos.get(HIST("Prof2D_Q112221_211"))->Fill(cent, sampleIndex, fQ112221_211); + histos.get(HIST("Prof2D_Q1131_21"))->Fill(cent, sampleIndex, fQ1131_21); + histos.get(HIST("Prof2D_Q1131_20"))->Fill(cent, sampleIndex, fQ1131_20); + histos.get(HIST("Prof2D_Q1131_31"))->Fill(cent, sampleIndex, fQ1131_31); + histos.get(HIST("Prof2D_Q1131_30"))->Fill(cent, sampleIndex, fQ1131_30); + histos.get(HIST("Prof2D_Q1132_21"))->Fill(cent, sampleIndex, fQ1132_21); + histos.get(HIST("Prof2D_Q1132_20"))->Fill(cent, sampleIndex, fQ1132_20); + histos.get(HIST("Prof2D_Q1132_31"))->Fill(cent, sampleIndex, fQ1132_31); + histos.get(HIST("Prof2D_Q1132_30"))->Fill(cent, sampleIndex, fQ1132_30); + histos.get(HIST("Prof2D_Q1133_21"))->Fill(cent, sampleIndex, fQ1133_21); + histos.get(HIST("Prof2D_Q1133_20"))->Fill(cent, sampleIndex, fQ1133_20); + histos.get(HIST("Prof2D_Q1133_31"))->Fill(cent, sampleIndex, fQ1133_31); + histos.get(HIST("Prof2D_Q1133_30"))->Fill(cent, sampleIndex, fQ1133_30); + histos.get(HIST("Prof2D_Q11_5"))->Fill(cent, sampleIndex, fQ11_5); + histos.get(HIST("Prof2D_Q11_6"))->Fill(cent, sampleIndex, fQ11_6); + histos.get(HIST("Prof2D_Q1121_30"))->Fill(cent, sampleIndex, fQ1121_30); + histos.get(HIST("Prof2D_Q1121_31"))->Fill(cent, sampleIndex, fQ1121_31); + histos.get(HIST("Prof2D_Q1121_40"))->Fill(cent, sampleIndex, fQ1121_40); + histos.get(HIST("Prof2D_Q1121_41"))->Fill(cent, sampleIndex, fQ1121_41); + histos.get(HIST("Prof2D_Q1122_30"))->Fill(cent, sampleIndex, fQ1122_30); + histos.get(HIST("Prof2D_Q1122_31"))->Fill(cent, sampleIndex, fQ1122_31); + histos.get(HIST("Prof2D_Q1122_40"))->Fill(cent, sampleIndex, fQ1122_40); + histos.get(HIST("Prof2D_Q1122_41"))->Fill(cent, sampleIndex, fQ1122_41); + histos.get(HIST("Prof2D_Q2211_11"))->Fill(cent, sampleIndex, fQ2211_11); + histos.get(HIST("Prof2D_Q2211_01"))->Fill(cent, sampleIndex, fQ2211_01); + histos.get(HIST("Prof2D_Q2211_10"))->Fill(cent, sampleIndex, fQ2211_10); + histos.get(HIST("Prof2D_Q2211_20"))->Fill(cent, sampleIndex, fQ2211_20); + histos.get(HIST("Prof2D_Q2211_21"))->Fill(cent, sampleIndex, fQ2211_21); + histos.get(HIST("Prof2D_Q2111_11"))->Fill(cent, sampleIndex, fQ2111_11); + histos.get(HIST("Prof2D_Q2111_01"))->Fill(cent, sampleIndex, fQ2111_01); + histos.get(HIST("Prof2D_Q2111_10"))->Fill(cent, sampleIndex, fQ2111_10); + histos.get(HIST("Prof2D_Q2111_20"))->Fill(cent, sampleIndex, fQ2111_20); + histos.get(HIST("Prof2D_Q2111_21"))->Fill(cent, sampleIndex, fQ2111_21); + histos.get(HIST("Prof2D_Q112122_001"))->Fill(cent, sampleIndex, fQ112122_001); + histos.get(HIST("Prof2D_Q112122_010"))->Fill(cent, sampleIndex, fQ112122_010); + histos.get(HIST("Prof2D_Q112122_100"))->Fill(cent, sampleIndex, fQ112122_100); + histos.get(HIST("Prof2D_Q112122_011"))->Fill(cent, sampleIndex, fQ112122_011); + histos.get(HIST("Prof2D_Q112122_101"))->Fill(cent, sampleIndex, fQ112122_101); + histos.get(HIST("Prof2D_Q112122_110"))->Fill(cent, sampleIndex, fQ112122_110); + histos.get(HIST("Prof2D_Q1141_11"))->Fill(cent, sampleIndex, fQ1141_11); + histos.get(HIST("Prof2D_Q1141_01"))->Fill(cent, sampleIndex, fQ1141_01); + histos.get(HIST("Prof2D_Q1141_10"))->Fill(cent, sampleIndex, fQ1141_10); + histos.get(HIST("Prof2D_Q1141_20"))->Fill(cent, sampleIndex, fQ1141_20); + histos.get(HIST("Prof2D_Q1141_21"))->Fill(cent, sampleIndex, fQ1141_21); + histos.get(HIST("Prof2D_Q1142_11"))->Fill(cent, sampleIndex, fQ1142_11); + histos.get(HIST("Prof2D_Q1142_01"))->Fill(cent, sampleIndex, fQ1142_01); + histos.get(HIST("Prof2D_Q1142_10"))->Fill(cent, sampleIndex, fQ1142_10); + histos.get(HIST("Prof2D_Q1142_20"))->Fill(cent, sampleIndex, fQ1142_20); + histos.get(HIST("Prof2D_Q1142_21"))->Fill(cent, sampleIndex, fQ1142_21); + histos.get(HIST("Prof2D_Q1143_11"))->Fill(cent, sampleIndex, fQ1143_11); + histos.get(HIST("Prof2D_Q1143_01"))->Fill(cent, sampleIndex, fQ1143_01); + histos.get(HIST("Prof2D_Q1143_10"))->Fill(cent, sampleIndex, fQ1143_10); + histos.get(HIST("Prof2D_Q1143_20"))->Fill(cent, sampleIndex, fQ1143_20); + histos.get(HIST("Prof2D_Q1143_21"))->Fill(cent, sampleIndex, fQ1143_21); + histos.get(HIST("Prof2D_Q1144_11"))->Fill(cent, sampleIndex, fQ1144_11); + histos.get(HIST("Prof2D_Q1144_01"))->Fill(cent, sampleIndex, fQ1144_01); + histos.get(HIST("Prof2D_Q1144_10"))->Fill(cent, sampleIndex, fQ1144_10); + histos.get(HIST("Prof2D_Q1144_20"))->Fill(cent, sampleIndex, fQ1144_20); + histos.get(HIST("Prof2D_Q1144_21"))->Fill(cent, sampleIndex, fQ1144_21); + histos.get(HIST("Prof2D_Q2131_11"))->Fill(cent, sampleIndex, fQ2131_11); + histos.get(HIST("Prof2D_Q2131_01"))->Fill(cent, sampleIndex, fQ2131_01); + histos.get(HIST("Prof2D_Q2131_10"))->Fill(cent, sampleIndex, fQ2131_10); + histos.get(HIST("Prof2D_Q2132_11"))->Fill(cent, sampleIndex, fQ2132_11); + histos.get(HIST("Prof2D_Q2132_01"))->Fill(cent, sampleIndex, fQ2132_01); + histos.get(HIST("Prof2D_Q2132_10"))->Fill(cent, sampleIndex, fQ2132_10); + histos.get(HIST("Prof2D_Q2133_11"))->Fill(cent, sampleIndex, fQ2133_11); + histos.get(HIST("Prof2D_Q2133_01"))->Fill(cent, sampleIndex, fQ2133_01); + histos.get(HIST("Prof2D_Q2133_10"))->Fill(cent, sampleIndex, fQ2133_10); + histos.get(HIST("Prof2D_Q2231_11"))->Fill(cent, sampleIndex, fQ2231_11); + histos.get(HIST("Prof2D_Q2231_01"))->Fill(cent, sampleIndex, fQ2231_01); + histos.get(HIST("Prof2D_Q2231_10"))->Fill(cent, sampleIndex, fQ2231_10); + histos.get(HIST("Prof2D_Q2232_11"))->Fill(cent, sampleIndex, fQ2232_11); + histos.get(HIST("Prof2D_Q2232_01"))->Fill(cent, sampleIndex, fQ2232_01); + histos.get(HIST("Prof2D_Q2232_10"))->Fill(cent, sampleIndex, fQ2232_10); + histos.get(HIST("Prof2D_Q2233_11"))->Fill(cent, sampleIndex, fQ2233_11); + histos.get(HIST("Prof2D_Q2233_01"))->Fill(cent, sampleIndex, fQ2233_01); + histos.get(HIST("Prof2D_Q2233_10"))->Fill(cent, sampleIndex, fQ2233_10); + histos.get(HIST("Prof2D_Q51_1"))->Fill(cent, sampleIndex, fQ51_1); + histos.get(HIST("Prof2D_Q52_1"))->Fill(cent, sampleIndex, fQ52_1); + histos.get(HIST("Prof2D_Q53_1"))->Fill(cent, sampleIndex, fQ53_1); + histos.get(HIST("Prof2D_Q54_1"))->Fill(cent, sampleIndex, fQ54_1); + histos.get(HIST("Prof2D_Q55_1"))->Fill(cent, sampleIndex, fQ55_1); + histos.get(HIST("Prof2D_Q21_3"))->Fill(cent, sampleIndex, fQ21_3); + histos.get(HIST("Prof2D_Q22_3"))->Fill(cent, sampleIndex, fQ22_3); + histos.get(HIST("Prof2D_Q31_2"))->Fill(cent, sampleIndex, fQ31_2); + histos.get(HIST("Prof2D_Q32_2"))->Fill(cent, sampleIndex, fQ32_2); + histos.get(HIST("Prof2D_Q33_2"))->Fill(cent, sampleIndex, fQ33_2); + histos.get(HIST("Prof2D_Q61_1"))->Fill(cent, sampleIndex, fQ61_1); + histos.get(HIST("Prof2D_Q62_1"))->Fill(cent, sampleIndex, fQ62_1); + histos.get(HIST("Prof2D_Q63_1"))->Fill(cent, sampleIndex, fQ63_1); + histos.get(HIST("Prof2D_Q64_1"))->Fill(cent, sampleIndex, fQ64_1); + histos.get(HIST("Prof2D_Q65_1"))->Fill(cent, sampleIndex, fQ65_1); + histos.get(HIST("Prof2D_Q66_1"))->Fill(cent, sampleIndex, fQ66_1); + histos.get(HIST("Prof2D_Q112122_111"))->Fill(cent, sampleIndex, fQ112122_111); + histos.get(HIST("Prof2D_Q112131_111"))->Fill(cent, sampleIndex, fQ112131_111); + histos.get(HIST("Prof2D_Q112132_111"))->Fill(cent, sampleIndex, fQ112132_111); + histos.get(HIST("Prof2D_Q112133_111"))->Fill(cent, sampleIndex, fQ112133_111); + histos.get(HIST("Prof2D_Q112231_111"))->Fill(cent, sampleIndex, fQ112231_111); + histos.get(HIST("Prof2D_Q112232_111"))->Fill(cent, sampleIndex, fQ112232_111); + histos.get(HIST("Prof2D_Q112233_111"))->Fill(cent, sampleIndex, fQ112233_111); + histos.get(HIST("Prof2D_Q112221_111"))->Fill(cent, sampleIndex, fQ112221_111); + } + } + PROCESS_SWITCH(NetprotonCumulantsMc, processMCRec, "Process Generated", true); + + void processDataRec(AodCollisions::iterator const& coll, aod::BCsWithTimestamps const&, AodTracks const& inputTracks) + { + if (!coll.sel8()) { + return; + } + if (cfgUseGoodITSLayerAllCut && !(coll.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll))) { + return; + } + if (cfgEvSelkNoSameBunchPileup && !(coll.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { + // rejects collisions which are associated with the same "found-by-T0" bunch crossing + // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof + return; + } + + if (cfgEvSelkIsVertexTOFmatched && !(coll.selection_bit(o2::aod::evsel::kIsVertexTOFmatched))) { + return; + ; + } + + histos.fill(HIST("hZvtx_after_sel"), coll.posZ()); + // variables + auto cent = coll.centFT0M(); + histos.fill(HIST("hCentrec"), cent); + + float nProt = 0.0; + float nAntiprot = 0.0; + std::array powerEffProt = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + std::array powerEffAntiprot = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + std::array fTCP0 = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + std::array fTCP1 = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + + o2::aod::ITSResponse itsResponse; + + // Start of the Monte-Carlo reconstructed tracks + for (const auto& track : inputTracks) { + if (!track.has_collision()) { + continue; + } + + if (!track.isPVContributor()) //! track check as used in data + { + continue; + } + if ((track.pt() < cfgCutPtLower) || (track.pt() > 5.0f) || (std::abs(track.eta()) > cfgCutEta)) { + continue; + } + if (!(track.itsNCls() > cfgITScluster) || !(track.tpcNClsFound() >= cfgTPCcluster) || !(track.tpcNClsCrossedRows() >= cfgTPCnCrossedRows)) { + continue; + } + + histos.fill(HIST("hrecPtAll"), track.pt()); + histos.fill(HIST("hrecEtaAll"), track.eta()); + histos.fill(HIST("hrecPhiAll"), track.phi()); + histos.fill(HIST("hrecDcaXYAll"), track.dcaXY()); + histos.fill(HIST("hrecDcaZAll"), track.dcaZ()); + + // rejecting electron + if (cfgIfRejectElectron && isElectron(track)) { + continue; + } + // use ITS pid as well + if (cfgUseItsPid && (std::abs(itsResponse.nSigmaITS(track)) > 3.0)) { + continue; + } + // required tracks with TOF mandatory to avoid pileup + if (cfgIfMandatoryTOF && !track.hasTOF()) { + continue; + } + + bool trackSelected = false; + if (cfgPIDchoice == 0) + trackSelected = selectionPIDoldTOFveto(track); + if (cfgPIDchoice == 1) + trackSelected = selectionPIDnew(track); + if (cfgPIDchoice == 2) + trackSelected = selectionPIDold(track); + + if (trackSelected) { + // filling nSigma distribution + histos.fill(HIST("h2DnsigmaTpcVsPt"), track.pt(), track.tpcNSigmaPr()); + histos.fill(HIST("h2DnsigmaTofVsPt"), track.pt(), track.tofNSigmaPr()); + histos.fill(HIST("h2DnsigmaItsVsPt"), track.pt(), itsResponse.nSigmaITS(track)); + + // for protons + if (track.sign() > 0) { + histos.fill(HIST("hrecPtProton"), track.pt()); //! hist for p rec + histos.fill(HIST("hrecPtDistProtonVsCentrality"), track.pt(), cent); + histos.fill(HIST("hrecEtaProton"), track.eta()); + histos.fill(HIST("hrecPhiProton"), track.phi()); + histos.fill(HIST("hrecDcaXYProton"), track.dcaXY()); + histos.fill(HIST("hrecDcaZProton"), track.dcaZ()); + + if (track.pt() < cfgCutPtUpper) { + nProt = nProt + 1.0; + float pEff = getEfficiency(track); // get efficiency of track + if (pEff != 0) { + for (int i = 1; i < 7; i++) { + powerEffProt[i] += std::pow(1.0 / pEff, i); + } + } + } + } + // for anti-protons + if (track.sign() < 0) { + histos.fill(HIST("hrecPtAntiproton"), track.pt()); //! hist for anti-p rec + histos.fill(HIST("hrecPtDistAntiprotonVsCentrality"), track.pt(), cent); + histos.fill(HIST("hrecEtaAntiproton"), track.eta()); + histos.fill(HIST("hrecPhiAntiproton"), track.phi()); + histos.fill(HIST("hrecDcaXYAntiproton"), track.dcaXY()); + histos.fill(HIST("hrecDcaZAntiproton"), track.dcaZ()); + if (track.pt() < cfgCutPtUpper) { + nAntiprot = nAntiprot + 1.0; + float pEff = getEfficiency(track); // get efficiency of track + if (pEff != 0) { + for (int i = 1; i < 7; i++) { + powerEffAntiprot[i] += std::pow(1.0 / pEff, i); + } + } + } + } + + } //! checking PID + } //! end track loop + + float netProt = nProt - nAntiprot; + histos.fill(HIST("hrecNetProtonVsCentrality"), netProt, cent); + histos.fill(HIST("hrecProtonVsCentrality"), nProt, cent); + histos.fill(HIST("hrecAntiprotonVsCentrality"), nAntiprot, cent); + histos.fill(HIST("hrecProfileTotalProton"), cent, (nProt + nAntiprot)); + histos.fill(HIST("hrecProfileProton"), cent, nProt); + histos.fill(HIST("hrecProfileAntiproton"), cent, nAntiprot); + histos.fill(HIST("hCorrProfileTotalProton"), cent, (powerEffProt[1] + powerEffAntiprot[1])); + histos.fill(HIST("hCorrProfileProton"), cent, powerEffProt[1]); + histos.fill(HIST("hCorrProfileAntiproton"), cent, powerEffAntiprot[1]); + + // Calculating q_{r,s} as required + for (int i = 1; i < 7; i++) { + fTCP0[i] = powerEffProt[i] + powerEffAntiprot[i]; + fTCP1[i] = powerEffProt[i] - powerEffAntiprot[i]; + } + + //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + float fQ11_1 = fTCP1[1]; + float fQ11_2 = std::pow(fTCP1[1], 2); + float fQ11_3 = std::pow(fTCP1[1], 3); + float fQ11_4 = std::pow(fTCP1[1], 4); + float fQ11_5 = std::pow(fTCP1[1], 5); + float fQ11_6 = std::pow(fTCP1[1], 6); + + float fQ21_3 = std::pow(fTCP0[1], 3); + float fQ22_3 = std::pow(fTCP0[2], 3); + float fQ31_2 = std::pow(fTCP1[1], 2); + float fQ32_2 = std::pow(fTCP1[2], 2); + float fQ33_2 = std::pow(fTCP1[3], 2); + + float fQ61_1 = fTCP0[1]; + float fQ62_1 = fTCP0[2]; + float fQ63_1 = fTCP0[3]; + float fQ64_1 = fTCP0[4]; + float fQ65_1 = fTCP0[5]; + float fQ66_1 = fTCP0[6]; + + float fQ112122_111 = fTCP1[1] * fTCP0[1] * fTCP0[2]; + float fQ112131_111 = fTCP1[1] * fTCP0[1] * fTCP1[1]; + float fQ112132_111 = fTCP1[1] * fTCP0[1] * fTCP1[2]; + float fQ112133_111 = fTCP1[1] * fTCP0[1] * fTCP1[3]; + float fQ112231_111 = fTCP1[1] * fTCP0[2] * fTCP1[1]; + float fQ112232_111 = fTCP1[1] * fTCP0[2] * fTCP1[2]; + float fQ112233_111 = fTCP1[1] * fTCP0[2] * fTCP1[3]; + float fQ112221_111 = fTCP1[1] * fTCP0[2] * fTCP0[1]; + + float fQ21_1 = fTCP0[1]; + float fQ22_1 = fTCP0[2]; + float fQ31_1 = fTCP1[1]; + float fQ32_1 = fTCP1[2]; + float fQ33_1 = fTCP1[3]; + float fQ41_1 = fTCP0[1]; + float fQ42_1 = fTCP0[2]; + float fQ43_1 = fTCP0[3]; + float fQ44_1 = fTCP0[4]; + float fQ21_2 = std::pow(fTCP0[1], 2); + float fQ22_2 = std::pow(fTCP0[2], 2); + float fQ1121_11 = fTCP1[1] * fTCP0[1]; + float fQ1121_01 = fTCP0[1]; + float fQ1121_10 = fTCP1[1]; + float fQ1121_20 = std::pow(fTCP1[1], 2); + float fQ1121_21 = std::pow(fTCP1[1], 2) * fTCP0[1]; + float fQ1122_11 = fTCP1[1] * fTCP0[2]; + float fQ1122_01 = fTCP0[2]; + float fQ1122_10 = fTCP1[1]; + float fQ1122_20 = std::pow(fTCP1[1], 2); + float fQ1122_21 = std::pow(fTCP1[1], 2) * fTCP0[2]; + float fQ1131_11 = fTCP1[1] * fTCP1[1]; + float fQ1131_01 = fTCP1[1]; + float fQ1131_10 = fTCP1[1]; + float fQ1132_11 = fTCP1[1] * fTCP1[2]; + float fQ1132_01 = fTCP1[2]; + float fQ1132_10 = fTCP1[1]; + float fQ1133_11 = fTCP1[1] * fTCP1[3]; + float fQ1133_01 = fTCP1[3]; + float fQ1133_10 = fTCP1[1]; + float fQ2122_11 = fTCP0[1] * fTCP0[2]; + float fQ2122_01 = fTCP0[2]; + float fQ2122_10 = fTCP0[1]; + + ///////////////---------------------> + float fQ3132_11 = fTCP1[1] * fTCP1[2]; + float fQ3132_01 = fTCP1[2]; + float fQ3132_10 = fTCP1[1]; + float fQ3133_11 = fTCP1[1] * fTCP1[3]; + float fQ3133_01 = fTCP1[3]; + float fQ3133_10 = fTCP1[1]; + float fQ3233_11 = fTCP1[2] * fTCP1[3]; + float fQ3233_01 = fTCP1[3]; + float fQ3233_10 = fTCP1[2]; + float fQ2241_11 = fTCP0[2] * fTCP0[1]; + float fQ2241_01 = fTCP0[1]; + float fQ2241_10 = fTCP0[2]; + float fQ2242_11 = fTCP0[2] * fTCP0[2]; + float fQ2242_01 = fTCP0[2]; + float fQ2242_10 = fTCP0[2]; + float fQ2243_11 = fTCP0[2] * fTCP0[3]; + float fQ2243_01 = fTCP0[3]; + float fQ2243_10 = fTCP0[2]; + float fQ2244_11 = fTCP0[2] * fTCP0[4]; + float fQ2244_01 = fTCP0[4]; + float fQ2244_10 = fTCP0[2]; + float fQ2141_11 = fTCP0[1] * fTCP0[1]; + float fQ2141_01 = fTCP0[1]; + float fQ2141_10 = fTCP0[1]; + float fQ2142_11 = fTCP0[1] * fTCP0[2]; + float fQ2142_01 = fTCP0[2]; + float fQ2142_10 = fTCP0[1]; + float fQ2143_11 = fTCP0[1] * fTCP0[3]; + float fQ2143_01 = fTCP0[3]; + float fQ2143_10 = fTCP0[1]; + float fQ2144_11 = fTCP0[1] * fTCP0[4]; + float fQ2144_01 = fTCP0[4]; + float fQ2144_10 = fTCP0[1]; + float fQ1151_11 = fTCP1[1] * fTCP1[1]; + float fQ1151_01 = fTCP1[1]; + float fQ1151_10 = fTCP1[1]; + float fQ1152_11 = fTCP1[1] * fTCP1[2]; + float fQ1152_01 = fTCP1[2]; + float fQ1152_10 = fTCP1[1]; + float fQ1153_11 = fTCP1[1] * fTCP1[3]; + float fQ1153_01 = fTCP1[3]; + float fQ1153_10 = fTCP1[1]; + float fQ1154_11 = fTCP1[1] * fTCP1[4]; + float fQ1154_01 = fTCP1[4]; + float fQ1154_10 = fTCP1[1]; + float fQ1155_11 = fTCP1[1] * fTCP1[5]; + float fQ1155_01 = fTCP1[5]; + float fQ1155_10 = fTCP1[1]; + + float fQ112233_001 = fTCP1[3]; + float fQ112233_010 = fTCP0[2]; + float fQ112233_100 = fTCP1[1]; + float fQ112233_011 = fTCP0[2] * fTCP1[3]; + float fQ112233_101 = fTCP1[1] * fTCP1[3]; + float fQ112233_110 = fTCP1[1] * fTCP0[2]; + float fQ112232_001 = fTCP1[2]; + float fQ112232_010 = fTCP0[2]; + float fQ112232_100 = fTCP1[1]; + float fQ112232_011 = fTCP0[2] * fTCP1[2]; + float fQ112232_101 = fTCP1[1] * fTCP1[2]; + float fQ112232_110 = fTCP1[1] * fTCP0[2]; + // + float fQ112231_001 = fTCP1[1]; + float fQ112231_010 = fTCP0[2]; + float fQ112231_100 = fTCP1[1]; + float fQ112231_011 = fTCP0[2] * fTCP1[1]; + float fQ112231_101 = fTCP1[1] * fTCP1[1]; + float fQ112231_110 = fTCP1[1] * fTCP0[2]; + float fQ112133_001 = fTCP1[3]; + float fQ112133_010 = fTCP0[1]; + float fQ112133_100 = fTCP1[1]; + float fQ112133_011 = fTCP0[1] * fTCP1[3]; + float fQ112133_101 = fTCP1[1] * fTCP1[3]; + float fQ112133_110 = fTCP1[1] * fTCP0[1]; + + float fQ112132_001 = fTCP1[2]; + float fQ112132_010 = fTCP0[1]; + float fQ112132_100 = fTCP1[1]; + float fQ112132_011 = fTCP0[1] * fTCP1[2]; + float fQ112132_101 = fTCP1[1] * fTCP1[2]; + float fQ112132_110 = fTCP1[1] * fTCP0[1]; + float fQ112131_001 = fTCP1[1]; + float fQ112131_010 = fTCP0[1]; + float fQ112131_100 = fTCP1[1]; + float fQ112131_011 = fTCP0[1] * fTCP1[1]; + float fQ112131_101 = fTCP1[1] * fTCP1[1]; + float fQ112131_110 = fTCP1[1] * fTCP0[1]; + + float fQ2221_11 = fTCP0[2] * fTCP0[1]; + float fQ2221_01 = fTCP0[1]; + float fQ2221_10 = fTCP0[2]; + float fQ2221_21 = std::pow(fTCP0[2], 2) * fTCP0[1]; + float fQ2221_20 = std::pow(fTCP0[2], 2); + + float fQ2122_21 = std::pow(fTCP0[1], 2) * fTCP0[2]; + float fQ2122_20 = std::pow(fTCP0[1], 2); + float fQ1121_02 = std::pow(fTCP0[1], 2); + float fQ1121_12 = fTCP1[1] * std::pow(fTCP0[1], 2); + float fQ1121_22 = std::pow(fTCP1[1], 2) * std::pow(fTCP0[1], 2); + float fQ1122_02 = std::pow(fTCP0[2], 2); + float fQ1122_12 = fTCP1[1] * std::pow(fTCP0[2], 2); + float fQ1122_22 = std::pow(fTCP1[1], 2) * std::pow(fTCP0[2], 2); + + float fQ112221_001 = fTCP0[1]; + float fQ112221_010 = fTCP0[2]; + float fQ112221_100 = fTCP1[1]; + float fQ112221_011 = fTCP0[2] * fTCP0[1]; + float fQ112221_101 = fTCP1[1] * fTCP0[1]; + float fQ112221_110 = fTCP1[1] * fTCP0[2]; + float fQ112221_200 = std::pow(fTCP1[1], 2); + float fQ112221_201 = std::pow(fTCP1[1], 2) * fTCP0[1]; + float fQ112221_210 = std::pow(fTCP1[1], 2) * fTCP0[2]; + float fQ112221_211 = std::pow(fTCP1[1], 2) * fTCP0[2] * fTCP0[1]; + float fQ1131_21 = std::pow(fTCP1[1], 2) * fTCP1[1]; + float fQ1131_20 = std::pow(fTCP1[1], 2); + float fQ1131_31 = std::pow(fTCP1[1], 3) * fTCP1[1]; + float fQ1131_30 = std::pow(fTCP1[1], 3); + + float fQ1132_21 = std::pow(fTCP1[1], 2) * fTCP1[2]; + float fQ1132_20 = std::pow(fTCP1[1], 2); + float fQ1132_31 = std::pow(fTCP1[1], 3) * fTCP1[2]; + float fQ1132_30 = std::pow(fTCP1[1], 3); + float fQ1133_21 = std::pow(fTCP1[1], 2) * fTCP1[3]; + float fQ1133_20 = std::pow(fTCP1[1], 2); + float fQ1133_31 = std::pow(fTCP1[1], 3) * fTCP1[3]; + float fQ1133_30 = std::pow(fTCP1[1], 3); + float fQ1121_30 = std::pow(fTCP1[1], 3); + float fQ1121_31 = std::pow(fTCP1[1], 3) * fTCP0[1]; + float fQ1121_40 = std::pow(fTCP1[1], 4); + float fQ1121_41 = std::pow(fTCP1[1], 4) * fTCP0[1]; + float fQ1122_30 = std::pow(fTCP1[1], 3); + float fQ1122_31 = std::pow(fTCP1[1], 3) * fTCP0[2]; + float fQ1122_40 = std::pow(fTCP1[1], 4); + float fQ1122_41 = std::pow(fTCP1[1], 4) * fTCP0[2]; + + float fQ2211_11 = fTCP0[2] * fTCP1[1]; + float fQ2211_01 = fTCP1[1]; + float fQ2211_10 = fTCP0[2]; + float fQ2211_20 = std::pow(fTCP0[2], 2); + float fQ2211_21 = std::pow(fTCP0[2], 2) * fTCP1[1]; + float fQ2111_11 = fTCP0[1] * fTCP1[1]; + float fQ2111_01 = fTCP1[1]; + float fQ2111_10 = fTCP0[1]; + float fQ2111_20 = std::pow(fTCP0[1], 2); + float fQ2111_21 = std::pow(fTCP0[1], 2) * fTCP1[1]; + + float fQ112122_001 = fTCP0[2]; + float fQ112122_010 = fTCP0[1]; + float fQ112122_100 = fTCP1[1]; + float fQ112122_011 = fTCP0[1] * fTCP0[2]; + float fQ112122_101 = fTCP1[1] * fTCP0[2]; + float fQ112122_110 = fTCP1[1] * fTCP0[1]; + + float fQ1141_11 = fTCP1[1] * fTCP0[1]; + float fQ1141_01 = fTCP0[1]; + float fQ1141_10 = fTCP1[1]; + float fQ1141_20 = std::pow(fTCP1[1], 2); + float fQ1141_21 = std::pow(fTCP1[1], 2) * fTCP0[1]; + float fQ1142_11 = fTCP1[1] * fTCP0[2]; + float fQ1142_01 = fTCP0[2]; + float fQ1142_10 = fTCP1[1]; + float fQ1142_20 = std::pow(fTCP1[1], 2); + float fQ1142_21 = std::pow(fTCP1[1], 2) * fTCP0[2]; + + float fQ1143_11 = fTCP1[1] * fTCP0[3]; + float fQ1143_01 = fTCP0[3]; + float fQ1143_10 = fTCP1[1]; + float fQ1143_20 = std::pow(fTCP1[1], 2); + float fQ1143_21 = std::pow(fTCP1[1], 2) * fTCP0[3]; + float fQ1144_11 = fTCP1[1] * fTCP0[4]; + float fQ1144_01 = fTCP0[4]; + float fQ1144_10 = fTCP1[1]; + float fQ1144_20 = std::pow(fTCP1[1], 2); + float fQ1144_21 = std::pow(fTCP1[1], 2) * fTCP0[4]; + float fQ2131_11 = fTCP0[1] * fTCP1[1]; + float fQ2131_01 = fTCP1[1]; + float fQ2131_10 = fTCP0[1]; + + float fQ2132_11 = fTCP0[1] * fTCP1[2]; + float fQ2132_01 = fTCP1[2]; + float fQ2132_10 = fTCP0[1]; + float fQ2133_11 = fTCP0[1] * fTCP1[3]; + float fQ2133_01 = fTCP1[3]; + float fQ2133_10 = fTCP0[1]; + float fQ2231_11 = fTCP0[2] * fTCP1[1]; + float fQ2231_01 = fTCP1[1]; + float fQ2231_10 = fTCP0[2]; + float fQ2232_11 = fTCP0[2] * fTCP1[2]; + float fQ2232_01 = fTCP1[2]; + float fQ2232_10 = fTCP0[2]; + float fQ2233_11 = fTCP0[2] * fTCP1[3]; + float fQ2233_01 = fTCP1[3]; + float fQ2233_10 = fTCP0[2]; + + float fQ51_1 = fTCP1[1]; + float fQ52_1 = fTCP1[2]; + float fQ53_1 = fTCP1[3]; + float fQ54_1 = fTCP1[4]; + float fQ55_1 = fTCP1[5]; + + //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + if (cfgIsCalculateCentral) { + + // uncorrected + histos.get(HIST("Prof_mu1_netproton"))->Fill(cent, std::pow(netProt, 1.0)); + histos.get(HIST("Prof_mu2_netproton"))->Fill(cent, std::pow(netProt, 2.0)); + histos.get(HIST("Prof_mu3_netproton"))->Fill(cent, std::pow(netProt, 3.0)); + histos.get(HIST("Prof_mu4_netproton"))->Fill(cent, std::pow(netProt, 4.0)); + histos.get(HIST("Prof_mu5_netproton"))->Fill(cent, std::pow(netProt, 5.0)); + histos.get(HIST("Prof_mu6_netproton"))->Fill(cent, std::pow(netProt, 6.0)); + histos.get(HIST("Prof_mu7_netproton"))->Fill(cent, std::pow(netProt, 7.0)); + histos.get(HIST("Prof_mu8_netproton"))->Fill(cent, std::pow(netProt, 8.0)); + + // eff. corrected + histos.get(HIST("Prof_Q11_1"))->Fill(cent, fQ11_1); + histos.get(HIST("Prof_Q11_2"))->Fill(cent, fQ11_2); + histos.get(HIST("Prof_Q11_3"))->Fill(cent, fQ11_3); + histos.get(HIST("Prof_Q11_4"))->Fill(cent, fQ11_4); + histos.get(HIST("Prof_Q21_1"))->Fill(cent, fQ21_1); + histos.get(HIST("Prof_Q22_1"))->Fill(cent, fQ22_1); + histos.get(HIST("Prof_Q31_1"))->Fill(cent, fQ31_1); + histos.get(HIST("Prof_Q32_1"))->Fill(cent, fQ32_1); + histos.get(HIST("Prof_Q33_1"))->Fill(cent, fQ33_1); + histos.get(HIST("Prof_Q41_1"))->Fill(cent, fQ41_1); + histos.get(HIST("Prof_Q42_1"))->Fill(cent, fQ42_1); + histos.get(HIST("Prof_Q43_1"))->Fill(cent, fQ43_1); + histos.get(HIST("Prof_Q44_1"))->Fill(cent, fQ44_1); + histos.get(HIST("Prof_Q21_2"))->Fill(cent, fQ21_2); + histos.get(HIST("Prof_Q22_2"))->Fill(cent, fQ22_2); + histos.get(HIST("Prof_Q1121_11"))->Fill(cent, fQ1121_11); + histos.get(HIST("Prof_Q1121_01"))->Fill(cent, fQ1121_01); + histos.get(HIST("Prof_Q1121_10"))->Fill(cent, fQ1121_10); + histos.get(HIST("Prof_Q1121_20"))->Fill(cent, fQ1121_20); + histos.get(HIST("Prof_Q1121_21"))->Fill(cent, fQ1121_21); + histos.get(HIST("Prof_Q1122_11"))->Fill(cent, fQ1122_11); + histos.get(HIST("Prof_Q1122_01"))->Fill(cent, fQ1122_01); + histos.get(HIST("Prof_Q1122_10"))->Fill(cent, fQ1122_10); + histos.get(HIST("Prof_Q1122_20"))->Fill(cent, fQ1122_20); + histos.get(HIST("Prof_Q1122_21"))->Fill(cent, fQ1122_21); + histos.get(HIST("Prof_Q1131_11"))->Fill(cent, fQ1131_11); + histos.get(HIST("Prof_Q1131_01"))->Fill(cent, fQ1131_01); + histos.get(HIST("Prof_Q1131_10"))->Fill(cent, fQ1131_10); + histos.get(HIST("Prof_Q1132_11"))->Fill(cent, fQ1132_11); + histos.get(HIST("Prof_Q1132_01"))->Fill(cent, fQ1132_01); + histos.get(HIST("Prof_Q1132_10"))->Fill(cent, fQ1132_10); + histos.get(HIST("Prof_Q1133_11"))->Fill(cent, fQ1133_11); + histos.get(HIST("Prof_Q1133_01"))->Fill(cent, fQ1133_01); + histos.get(HIST("Prof_Q1133_10"))->Fill(cent, fQ1133_10); + histos.get(HIST("Prof_Q2122_11"))->Fill(cent, fQ2122_11); + histos.get(HIST("Prof_Q2122_01"))->Fill(cent, fQ2122_01); + histos.get(HIST("Prof_Q2122_10"))->Fill(cent, fQ2122_10); + histos.get(HIST("Prof_Q3132_11"))->Fill(cent, fQ3132_11); + histos.get(HIST("Prof_Q3132_01"))->Fill(cent, fQ3132_01); + histos.get(HIST("Prof_Q3132_10"))->Fill(cent, fQ3132_10); + histos.get(HIST("Prof_Q3133_11"))->Fill(cent, fQ3133_11); + histos.get(HIST("Prof_Q3133_01"))->Fill(cent, fQ3133_01); + histos.get(HIST("Prof_Q3133_10"))->Fill(cent, fQ3133_10); + histos.get(HIST("Prof_Q3233_11"))->Fill(cent, fQ3233_11); + histos.get(HIST("Prof_Q3233_01"))->Fill(cent, fQ3233_01); + histos.get(HIST("Prof_Q3233_10"))->Fill(cent, fQ3233_10); + histos.get(HIST("Prof_Q2241_11"))->Fill(cent, fQ2241_11); + histos.get(HIST("Prof_Q2241_01"))->Fill(cent, fQ2241_01); + histos.get(HIST("Prof_Q2241_10"))->Fill(cent, fQ2241_10); + histos.get(HIST("Prof_Q2242_11"))->Fill(cent, fQ2242_11); + histos.get(HIST("Prof_Q2242_01"))->Fill(cent, fQ2242_01); + histos.get(HIST("Prof_Q2242_10"))->Fill(cent, fQ2242_10); + histos.get(HIST("Prof_Q2243_11"))->Fill(cent, fQ2243_11); + histos.get(HIST("Prof_Q2243_01"))->Fill(cent, fQ2243_01); + histos.get(HIST("Prof_Q2243_10"))->Fill(cent, fQ2243_10); + histos.get(HIST("Prof_Q2244_11"))->Fill(cent, fQ2244_11); + histos.get(HIST("Prof_Q2244_01"))->Fill(cent, fQ2244_01); + histos.get(HIST("Prof_Q2244_10"))->Fill(cent, fQ2244_10); + histos.get(HIST("Prof_Q2141_11"))->Fill(cent, fQ2141_11); + histos.get(HIST("Prof_Q2141_01"))->Fill(cent, fQ2141_01); + histos.get(HIST("Prof_Q2141_10"))->Fill(cent, fQ2141_10); + histos.get(HIST("Prof_Q2142_11"))->Fill(cent, fQ2142_11); + histos.get(HIST("Prof_Q2142_01"))->Fill(cent, fQ2142_01); + histos.get(HIST("Prof_Q2142_10"))->Fill(cent, fQ2142_10); + histos.get(HIST("Prof_Q2143_11"))->Fill(cent, fQ2143_11); + histos.get(HIST("Prof_Q2143_01"))->Fill(cent, fQ2143_01); + histos.get(HIST("Prof_Q2143_10"))->Fill(cent, fQ2143_10); + histos.get(HIST("Prof_Q2144_11"))->Fill(cent, fQ2144_11); + histos.get(HIST("Prof_Q2144_01"))->Fill(cent, fQ2144_01); + histos.get(HIST("Prof_Q2144_10"))->Fill(cent, fQ2144_10); + histos.get(HIST("Prof_Q1151_11"))->Fill(cent, fQ1151_11); + histos.get(HIST("Prof_Q1151_01"))->Fill(cent, fQ1151_01); + histos.get(HIST("Prof_Q1151_10"))->Fill(cent, fQ1151_10); + histos.get(HIST("Prof_Q1152_11"))->Fill(cent, fQ1152_11); + histos.get(HIST("Prof_Q1152_01"))->Fill(cent, fQ1152_01); + histos.get(HIST("Prof_Q1152_10"))->Fill(cent, fQ1152_10); + histos.get(HIST("Prof_Q1153_11"))->Fill(cent, fQ1153_11); + histos.get(HIST("Prof_Q1153_01"))->Fill(cent, fQ1153_01); + histos.get(HIST("Prof_Q1153_10"))->Fill(cent, fQ1153_10); + histos.get(HIST("Prof_Q1154_11"))->Fill(cent, fQ1154_11); + histos.get(HIST("Prof_Q1154_01"))->Fill(cent, fQ1154_01); + histos.get(HIST("Prof_Q1154_10"))->Fill(cent, fQ1154_10); + histos.get(HIST("Prof_Q1155_11"))->Fill(cent, fQ1155_11); + histos.get(HIST("Prof_Q1155_01"))->Fill(cent, fQ1155_01); + histos.get(HIST("Prof_Q1155_10"))->Fill(cent, fQ1155_10); + histos.get(HIST("Prof_Q112233_001"))->Fill(cent, fQ112233_001); + histos.get(HIST("Prof_Q112233_010"))->Fill(cent, fQ112233_010); + histos.get(HIST("Prof_Q112233_100"))->Fill(cent, fQ112233_100); + histos.get(HIST("Prof_Q112233_011"))->Fill(cent, fQ112233_011); + histos.get(HIST("Prof_Q112233_101"))->Fill(cent, fQ112233_101); + histos.get(HIST("Prof_Q112233_110"))->Fill(cent, fQ112233_110); + histos.get(HIST("Prof_Q112232_001"))->Fill(cent, fQ112232_001); + histos.get(HIST("Prof_Q112232_010"))->Fill(cent, fQ112232_010); + histos.get(HIST("Prof_Q112232_100"))->Fill(cent, fQ112232_100); + histos.get(HIST("Prof_Q112232_011"))->Fill(cent, fQ112232_011); + histos.get(HIST("Prof_Q112232_101"))->Fill(cent, fQ112232_101); + histos.get(HIST("Prof_Q112232_110"))->Fill(cent, fQ112232_110); + histos.get(HIST("Prof_Q112231_001"))->Fill(cent, fQ112231_001); + histos.get(HIST("Prof_Q112231_010"))->Fill(cent, fQ112231_010); + histos.get(HIST("Prof_Q112231_100"))->Fill(cent, fQ112231_100); + histos.get(HIST("Prof_Q112231_011"))->Fill(cent, fQ112231_011); + histos.get(HIST("Prof_Q112231_101"))->Fill(cent, fQ112231_101); + histos.get(HIST("Prof_Q112231_110"))->Fill(cent, fQ112231_110); + histos.get(HIST("Prof_Q112133_001"))->Fill(cent, fQ112133_001); + histos.get(HIST("Prof_Q112133_010"))->Fill(cent, fQ112133_010); + histos.get(HIST("Prof_Q112133_100"))->Fill(cent, fQ112133_100); + histos.get(HIST("Prof_Q112133_011"))->Fill(cent, fQ112133_011); + histos.get(HIST("Prof_Q112133_101"))->Fill(cent, fQ112133_101); + histos.get(HIST("Prof_Q112133_110"))->Fill(cent, fQ112133_110); + histos.get(HIST("Prof_Q112132_001"))->Fill(cent, fQ112132_001); + histos.get(HIST("Prof_Q112132_010"))->Fill(cent, fQ112132_010); + histos.get(HIST("Prof_Q112132_100"))->Fill(cent, fQ112132_100); + histos.get(HIST("Prof_Q112132_011"))->Fill(cent, fQ112132_011); + histos.get(HIST("Prof_Q112132_101"))->Fill(cent, fQ112132_101); + histos.get(HIST("Prof_Q112132_110"))->Fill(cent, fQ112132_110); + histos.get(HIST("Prof_Q112131_001"))->Fill(cent, fQ112131_001); + histos.get(HIST("Prof_Q112131_010"))->Fill(cent, fQ112131_010); + histos.get(HIST("Prof_Q112131_100"))->Fill(cent, fQ112131_100); + histos.get(HIST("Prof_Q112131_011"))->Fill(cent, fQ112131_011); + histos.get(HIST("Prof_Q112131_101"))->Fill(cent, fQ112131_101); + histos.get(HIST("Prof_Q112131_110"))->Fill(cent, fQ112131_110); + histos.get(HIST("Prof_Q2221_11"))->Fill(cent, fQ2221_11); + histos.get(HIST("Prof_Q2221_01"))->Fill(cent, fQ2221_01); + histos.get(HIST("Prof_Q2221_10"))->Fill(cent, fQ2221_10); + histos.get(HIST("Prof_Q2221_21"))->Fill(cent, fQ2221_21); + histos.get(HIST("Prof_Q2221_20"))->Fill(cent, fQ2221_20); + histos.get(HIST("Prof_Q2122_21"))->Fill(cent, fQ2122_21); + histos.get(HIST("Prof_Q2122_20"))->Fill(cent, fQ2122_20); + histos.get(HIST("Prof_Q1121_02"))->Fill(cent, fQ1121_02); + histos.get(HIST("Prof_Q1121_12"))->Fill(cent, fQ1121_12); + histos.get(HIST("Prof_Q1121_22"))->Fill(cent, fQ1121_22); + histos.get(HIST("Prof_Q1122_02"))->Fill(cent, fQ1122_02); + histos.get(HIST("Prof_Q1122_12"))->Fill(cent, fQ1122_12); + histos.get(HIST("Prof_Q1122_22"))->Fill(cent, fQ1122_22); + histos.get(HIST("Prof_Q112221_001"))->Fill(cent, fQ112221_001); + histos.get(HIST("Prof_Q112221_010"))->Fill(cent, fQ112221_010); + histos.get(HIST("Prof_Q112221_100"))->Fill(cent, fQ112221_100); + histos.get(HIST("Prof_Q112221_011"))->Fill(cent, fQ112221_011); + histos.get(HIST("Prof_Q112221_101"))->Fill(cent, fQ112221_101); + histos.get(HIST("Prof_Q112221_110"))->Fill(cent, fQ112221_110); + histos.get(HIST("Prof_Q112221_200"))->Fill(cent, fQ112221_200); + histos.get(HIST("Prof_Q112221_201"))->Fill(cent, fQ112221_201); + histos.get(HIST("Prof_Q112221_210"))->Fill(cent, fQ112221_210); + histos.get(HIST("Prof_Q112221_211"))->Fill(cent, fQ112221_211); + histos.get(HIST("Prof_Q1131_21"))->Fill(cent, fQ1131_21); + histos.get(HIST("Prof_Q1131_20"))->Fill(cent, fQ1131_20); + histos.get(HIST("Prof_Q1131_31"))->Fill(cent, fQ1131_31); + histos.get(HIST("Prof_Q1131_30"))->Fill(cent, fQ1131_30); + histos.get(HIST("Prof_Q1132_21"))->Fill(cent, fQ1132_21); + histos.get(HIST("Prof_Q1132_20"))->Fill(cent, fQ1132_20); + histos.get(HIST("Prof_Q1132_31"))->Fill(cent, fQ1132_31); + histos.get(HIST("Prof_Q1132_30"))->Fill(cent, fQ1132_30); + histos.get(HIST("Prof_Q1133_21"))->Fill(cent, fQ1133_21); + histos.get(HIST("Prof_Q1133_20"))->Fill(cent, fQ1133_20); + histos.get(HIST("Prof_Q1133_31"))->Fill(cent, fQ1133_31); + histos.get(HIST("Prof_Q1133_30"))->Fill(cent, fQ1133_30); + histos.get(HIST("Prof_Q11_5"))->Fill(cent, fQ11_5); + histos.get(HIST("Prof_Q11_6"))->Fill(cent, fQ11_6); + histos.get(HIST("Prof_Q1121_30"))->Fill(cent, fQ1121_30); + histos.get(HIST("Prof_Q1121_31"))->Fill(cent, fQ1121_31); + histos.get(HIST("Prof_Q1121_40"))->Fill(cent, fQ1121_40); + histos.get(HIST("Prof_Q1121_41"))->Fill(cent, fQ1121_41); + histos.get(HIST("Prof_Q1122_30"))->Fill(cent, fQ1122_30); + histos.get(HIST("Prof_Q1122_31"))->Fill(cent, fQ1122_31); + histos.get(HIST("Prof_Q1122_40"))->Fill(cent, fQ1122_40); + histos.get(HIST("Prof_Q1122_41"))->Fill(cent, fQ1122_41); + histos.get(HIST("Prof_Q2211_11"))->Fill(cent, fQ2211_11); + histos.get(HIST("Prof_Q2211_01"))->Fill(cent, fQ2211_01); + histos.get(HIST("Prof_Q2211_10"))->Fill(cent, fQ2211_10); + histos.get(HIST("Prof_Q2211_20"))->Fill(cent, fQ2211_20); + histos.get(HIST("Prof_Q2211_21"))->Fill(cent, fQ2211_21); + histos.get(HIST("Prof_Q2111_11"))->Fill(cent, fQ2111_11); + histos.get(HIST("Prof_Q2111_01"))->Fill(cent, fQ2111_01); + histos.get(HIST("Prof_Q2111_10"))->Fill(cent, fQ2111_10); + histos.get(HIST("Prof_Q2111_20"))->Fill(cent, fQ2111_20); + histos.get(HIST("Prof_Q2111_21"))->Fill(cent, fQ2111_21); + histos.get(HIST("Prof_Q112122_001"))->Fill(cent, fQ112122_001); + histos.get(HIST("Prof_Q112122_010"))->Fill(cent, fQ112122_010); + histos.get(HIST("Prof_Q112122_100"))->Fill(cent, fQ112122_100); + histos.get(HIST("Prof_Q112122_011"))->Fill(cent, fQ112122_011); + histos.get(HIST("Prof_Q112122_101"))->Fill(cent, fQ112122_101); + histos.get(HIST("Prof_Q112122_110"))->Fill(cent, fQ112122_110); + histos.get(HIST("Prof_Q1141_11"))->Fill(cent, fQ1141_11); + histos.get(HIST("Prof_Q1141_01"))->Fill(cent, fQ1141_01); + histos.get(HIST("Prof_Q1141_10"))->Fill(cent, fQ1141_10); + histos.get(HIST("Prof_Q1141_20"))->Fill(cent, fQ1141_20); + histos.get(HIST("Prof_Q1141_21"))->Fill(cent, fQ1141_21); + histos.get(HIST("Prof_Q1142_11"))->Fill(cent, fQ1142_11); + histos.get(HIST("Prof_Q1142_01"))->Fill(cent, fQ1142_01); + histos.get(HIST("Prof_Q1142_10"))->Fill(cent, fQ1142_10); + histos.get(HIST("Prof_Q1142_20"))->Fill(cent, fQ1142_20); + histos.get(HIST("Prof_Q1142_21"))->Fill(cent, fQ1142_21); + histos.get(HIST("Prof_Q1143_11"))->Fill(cent, fQ1143_11); + histos.get(HIST("Prof_Q1143_01"))->Fill(cent, fQ1143_01); + histos.get(HIST("Prof_Q1143_10"))->Fill(cent, fQ1143_10); + histos.get(HIST("Prof_Q1143_20"))->Fill(cent, fQ1143_20); + histos.get(HIST("Prof_Q1143_21"))->Fill(cent, fQ1143_21); + histos.get(HIST("Prof_Q1144_11"))->Fill(cent, fQ1144_11); + histos.get(HIST("Prof_Q1144_01"))->Fill(cent, fQ1144_01); + histos.get(HIST("Prof_Q1144_10"))->Fill(cent, fQ1144_10); + histos.get(HIST("Prof_Q1144_20"))->Fill(cent, fQ1144_20); + histos.get(HIST("Prof_Q1144_21"))->Fill(cent, fQ1144_21); + histos.get(HIST("Prof_Q2131_11"))->Fill(cent, fQ2131_11); + histos.get(HIST("Prof_Q2131_01"))->Fill(cent, fQ2131_01); + histos.get(HIST("Prof_Q2131_10"))->Fill(cent, fQ2131_10); + histos.get(HIST("Prof_Q2132_11"))->Fill(cent, fQ2132_11); + histos.get(HIST("Prof_Q2132_01"))->Fill(cent, fQ2132_01); + histos.get(HIST("Prof_Q2132_10"))->Fill(cent, fQ2132_10); + histos.get(HIST("Prof_Q2133_11"))->Fill(cent, fQ2133_11); + histos.get(HIST("Prof_Q2133_01"))->Fill(cent, fQ2133_01); + histos.get(HIST("Prof_Q2133_10"))->Fill(cent, fQ2133_10); + histos.get(HIST("Prof_Q2231_11"))->Fill(cent, fQ2231_11); + histos.get(HIST("Prof_Q2231_01"))->Fill(cent, fQ2231_01); + histos.get(HIST("Prof_Q2231_10"))->Fill(cent, fQ2231_10); + histos.get(HIST("Prof_Q2232_11"))->Fill(cent, fQ2232_11); + histos.get(HIST("Prof_Q2232_01"))->Fill(cent, fQ2232_01); + histos.get(HIST("Prof_Q2232_10"))->Fill(cent, fQ2232_10); + histos.get(HIST("Prof_Q2233_11"))->Fill(cent, fQ2233_11); + histos.get(HIST("Prof_Q2233_01"))->Fill(cent, fQ2233_01); + histos.get(HIST("Prof_Q2233_10"))->Fill(cent, fQ2233_10); + histos.get(HIST("Prof_Q51_1"))->Fill(cent, fQ51_1); + histos.get(HIST("Prof_Q52_1"))->Fill(cent, fQ52_1); + histos.get(HIST("Prof_Q53_1"))->Fill(cent, fQ53_1); + histos.get(HIST("Prof_Q54_1"))->Fill(cent, fQ54_1); + histos.get(HIST("Prof_Q55_1"))->Fill(cent, fQ55_1); + histos.get(HIST("Prof_Q21_3"))->Fill(cent, fQ21_3); + histos.get(HIST("Prof_Q22_3"))->Fill(cent, fQ22_3); + histos.get(HIST("Prof_Q31_2"))->Fill(cent, fQ31_2); + histos.get(HIST("Prof_Q32_2"))->Fill(cent, fQ32_2); + histos.get(HIST("Prof_Q33_2"))->Fill(cent, fQ33_2); + histos.get(HIST("Prof_Q61_1"))->Fill(cent, fQ61_1); + histos.get(HIST("Prof_Q62_1"))->Fill(cent, fQ62_1); + histos.get(HIST("Prof_Q63_1"))->Fill(cent, fQ63_1); + histos.get(HIST("Prof_Q64_1"))->Fill(cent, fQ64_1); + histos.get(HIST("Prof_Q65_1"))->Fill(cent, fQ65_1); + histos.get(HIST("Prof_Q66_1"))->Fill(cent, fQ66_1); + histos.get(HIST("Prof_Q112122_111"))->Fill(cent, fQ112122_111); + histos.get(HIST("Prof_Q112131_111"))->Fill(cent, fQ112131_111); + histos.get(HIST("Prof_Q112132_111"))->Fill(cent, fQ112132_111); + histos.get(HIST("Prof_Q112133_111"))->Fill(cent, fQ112133_111); + histos.get(HIST("Prof_Q112231_111"))->Fill(cent, fQ112231_111); + histos.get(HIST("Prof_Q112232_111"))->Fill(cent, fQ112232_111); + histos.get(HIST("Prof_Q112233_111"))->Fill(cent, fQ112233_111); + histos.get(HIST("Prof_Q112221_111"))->Fill(cent, fQ112221_111); + } + + if (cfgIsCalculateError) { + // selecting subsample and filling profiles + float lRandom = fRndm->Rndm(); + int sampleIndex = static_cast(cfgNSubsample * lRandom); + + histos.get(HIST("Prof2D_mu1_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 1.0)); + histos.get(HIST("Prof2D_mu2_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 2.0)); + histos.get(HIST("Prof2D_mu3_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 3.0)); + histos.get(HIST("Prof2D_mu4_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 4.0)); + histos.get(HIST("Prof2D_mu5_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 5.0)); + histos.get(HIST("Prof2D_mu6_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 6.0)); + histos.get(HIST("Prof2D_mu7_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 7.0)); + histos.get(HIST("Prof2D_mu8_netproton"))->Fill(cent, sampleIndex, std::pow(netProt, 8.0)); + + histos.get(HIST("Prof2D_Q11_1"))->Fill(cent, sampleIndex, fQ11_1); + histos.get(HIST("Prof2D_Q11_2"))->Fill(cent, sampleIndex, fQ11_2); + histos.get(HIST("Prof2D_Q11_3"))->Fill(cent, sampleIndex, fQ11_3); + histos.get(HIST("Prof2D_Q11_4"))->Fill(cent, sampleIndex, fQ11_4); + histos.get(HIST("Prof2D_Q21_1"))->Fill(cent, sampleIndex, fQ21_1); + histos.get(HIST("Prof2D_Q22_1"))->Fill(cent, sampleIndex, fQ22_1); + histos.get(HIST("Prof2D_Q31_1"))->Fill(cent, sampleIndex, fQ31_1); + histos.get(HIST("Prof2D_Q32_1"))->Fill(cent, sampleIndex, fQ32_1); + histos.get(HIST("Prof2D_Q33_1"))->Fill(cent, sampleIndex, fQ33_1); + histos.get(HIST("Prof2D_Q41_1"))->Fill(cent, sampleIndex, fQ41_1); + histos.get(HIST("Prof2D_Q42_1"))->Fill(cent, sampleIndex, fQ42_1); + histos.get(HIST("Prof2D_Q43_1"))->Fill(cent, sampleIndex, fQ43_1); + histos.get(HIST("Prof2D_Q44_1"))->Fill(cent, sampleIndex, fQ44_1); + histos.get(HIST("Prof2D_Q21_2"))->Fill(cent, sampleIndex, fQ21_2); + histos.get(HIST("Prof2D_Q22_2"))->Fill(cent, sampleIndex, fQ22_2); + histos.get(HIST("Prof2D_Q1121_11"))->Fill(cent, sampleIndex, fQ1121_11); + histos.get(HIST("Prof2D_Q1121_01"))->Fill(cent, sampleIndex, fQ1121_01); + histos.get(HIST("Prof2D_Q1121_10"))->Fill(cent, sampleIndex, fQ1121_10); + histos.get(HIST("Prof2D_Q1121_20"))->Fill(cent, sampleIndex, fQ1121_20); + histos.get(HIST("Prof2D_Q1121_21"))->Fill(cent, sampleIndex, fQ1121_21); + histos.get(HIST("Prof2D_Q1122_11"))->Fill(cent, sampleIndex, fQ1122_11); + histos.get(HIST("Prof2D_Q1122_01"))->Fill(cent, sampleIndex, fQ1122_01); + histos.get(HIST("Prof2D_Q1122_10"))->Fill(cent, sampleIndex, fQ1122_10); + histos.get(HIST("Prof2D_Q1122_20"))->Fill(cent, sampleIndex, fQ1122_20); + histos.get(HIST("Prof2D_Q1122_21"))->Fill(cent, sampleIndex, fQ1122_21); + histos.get(HIST("Prof2D_Q1131_11"))->Fill(cent, sampleIndex, fQ1131_11); + histos.get(HIST("Prof2D_Q1131_01"))->Fill(cent, sampleIndex, fQ1131_01); + histos.get(HIST("Prof2D_Q1131_10"))->Fill(cent, sampleIndex, fQ1131_10); + histos.get(HIST("Prof2D_Q1132_11"))->Fill(cent, sampleIndex, fQ1132_11); + histos.get(HIST("Prof2D_Q1132_01"))->Fill(cent, sampleIndex, fQ1132_01); + histos.get(HIST("Prof2D_Q1132_10"))->Fill(cent, sampleIndex, fQ1132_10); + histos.get(HIST("Prof2D_Q1133_11"))->Fill(cent, sampleIndex, fQ1133_11); + histos.get(HIST("Prof2D_Q1133_01"))->Fill(cent, sampleIndex, fQ1133_01); + histos.get(HIST("Prof2D_Q1133_10"))->Fill(cent, sampleIndex, fQ1133_10); + histos.get(HIST("Prof2D_Q2122_11"))->Fill(cent, sampleIndex, fQ2122_11); + histos.get(HIST("Prof2D_Q2122_01"))->Fill(cent, sampleIndex, fQ2122_01); + histos.get(HIST("Prof2D_Q2122_10"))->Fill(cent, sampleIndex, fQ2122_10); + histos.get(HIST("Prof2D_Q3132_11"))->Fill(cent, sampleIndex, fQ3132_11); + histos.get(HIST("Prof2D_Q3132_01"))->Fill(cent, sampleIndex, fQ3132_01); + histos.get(HIST("Prof2D_Q3132_10"))->Fill(cent, sampleIndex, fQ3132_10); + histos.get(HIST("Prof2D_Q3133_11"))->Fill(cent, sampleIndex, fQ3133_11); + histos.get(HIST("Prof2D_Q3133_01"))->Fill(cent, sampleIndex, fQ3133_01); + histos.get(HIST("Prof2D_Q3133_10"))->Fill(cent, sampleIndex, fQ3133_10); + histos.get(HIST("Prof2D_Q3233_11"))->Fill(cent, sampleIndex, fQ3233_11); + histos.get(HIST("Prof2D_Q3233_01"))->Fill(cent, sampleIndex, fQ3233_01); + histos.get(HIST("Prof2D_Q3233_10"))->Fill(cent, sampleIndex, fQ3233_10); + histos.get(HIST("Prof2D_Q2241_11"))->Fill(cent, sampleIndex, fQ2241_11); + histos.get(HIST("Prof2D_Q2241_01"))->Fill(cent, sampleIndex, fQ2241_01); + histos.get(HIST("Prof2D_Q2241_10"))->Fill(cent, sampleIndex, fQ2241_10); + histos.get(HIST("Prof2D_Q2242_11"))->Fill(cent, sampleIndex, fQ2242_11); + histos.get(HIST("Prof2D_Q2242_01"))->Fill(cent, sampleIndex, fQ2242_01); + histos.get(HIST("Prof2D_Q2242_10"))->Fill(cent, sampleIndex, fQ2242_10); + histos.get(HIST("Prof2D_Q2243_11"))->Fill(cent, sampleIndex, fQ2243_11); + histos.get(HIST("Prof2D_Q2243_01"))->Fill(cent, sampleIndex, fQ2243_01); + histos.get(HIST("Prof2D_Q2243_10"))->Fill(cent, sampleIndex, fQ2243_10); + histos.get(HIST("Prof2D_Q2244_11"))->Fill(cent, sampleIndex, fQ2244_11); + histos.get(HIST("Prof2D_Q2244_01"))->Fill(cent, sampleIndex, fQ2244_01); + histos.get(HIST("Prof2D_Q2244_10"))->Fill(cent, sampleIndex, fQ2244_10); + histos.get(HIST("Prof2D_Q2141_11"))->Fill(cent, sampleIndex, fQ2141_11); + histos.get(HIST("Prof2D_Q2141_01"))->Fill(cent, sampleIndex, fQ2141_01); + histos.get(HIST("Prof2D_Q2141_10"))->Fill(cent, sampleIndex, fQ2141_10); + histos.get(HIST("Prof2D_Q2142_11"))->Fill(cent, sampleIndex, fQ2142_11); + histos.get(HIST("Prof2D_Q2142_01"))->Fill(cent, sampleIndex, fQ2142_01); + histos.get(HIST("Prof2D_Q2142_10"))->Fill(cent, sampleIndex, fQ2142_10); + histos.get(HIST("Prof2D_Q2143_11"))->Fill(cent, sampleIndex, fQ2143_11); + histos.get(HIST("Prof2D_Q2143_01"))->Fill(cent, sampleIndex, fQ2143_01); + histos.get(HIST("Prof2D_Q2143_10"))->Fill(cent, sampleIndex, fQ2143_10); + histos.get(HIST("Prof2D_Q2144_11"))->Fill(cent, sampleIndex, fQ2144_11); + histos.get(HIST("Prof2D_Q2144_01"))->Fill(cent, sampleIndex, fQ2144_01); + histos.get(HIST("Prof2D_Q2144_10"))->Fill(cent, sampleIndex, fQ2144_10); + histos.get(HIST("Prof2D_Q1151_11"))->Fill(cent, sampleIndex, fQ1151_11); + histos.get(HIST("Prof2D_Q1151_01"))->Fill(cent, sampleIndex, fQ1151_01); + histos.get(HIST("Prof2D_Q1151_10"))->Fill(cent, sampleIndex, fQ1151_10); + histos.get(HIST("Prof2D_Q1152_11"))->Fill(cent, sampleIndex, fQ1152_11); + histos.get(HIST("Prof2D_Q1152_01"))->Fill(cent, sampleIndex, fQ1152_01); + histos.get(HIST("Prof2D_Q1152_10"))->Fill(cent, sampleIndex, fQ1152_10); + histos.get(HIST("Prof2D_Q1153_11"))->Fill(cent, sampleIndex, fQ1153_11); + histos.get(HIST("Prof2D_Q1153_01"))->Fill(cent, sampleIndex, fQ1153_01); + histos.get(HIST("Prof2D_Q1153_10"))->Fill(cent, sampleIndex, fQ1153_10); + histos.get(HIST("Prof2D_Q1154_11"))->Fill(cent, sampleIndex, fQ1154_11); + histos.get(HIST("Prof2D_Q1154_01"))->Fill(cent, sampleIndex, fQ1154_01); + histos.get(HIST("Prof2D_Q1154_10"))->Fill(cent, sampleIndex, fQ1154_10); + histos.get(HIST("Prof2D_Q1155_11"))->Fill(cent, sampleIndex, fQ1155_11); + histos.get(HIST("Prof2D_Q1155_01"))->Fill(cent, sampleIndex, fQ1155_01); + histos.get(HIST("Prof2D_Q1155_10"))->Fill(cent, sampleIndex, fQ1155_10); + histos.get(HIST("Prof2D_Q112233_001"))->Fill(cent, sampleIndex, fQ112233_001); + histos.get(HIST("Prof2D_Q112233_010"))->Fill(cent, sampleIndex, fQ112233_010); + histos.get(HIST("Prof2D_Q112233_100"))->Fill(cent, sampleIndex, fQ112233_100); + histos.get(HIST("Prof2D_Q112233_011"))->Fill(cent, sampleIndex, fQ112233_011); + histos.get(HIST("Prof2D_Q112233_101"))->Fill(cent, sampleIndex, fQ112233_101); + histos.get(HIST("Prof2D_Q112233_110"))->Fill(cent, sampleIndex, fQ112233_110); + histos.get(HIST("Prof2D_Q112232_001"))->Fill(cent, sampleIndex, fQ112232_001); + histos.get(HIST("Prof2D_Q112232_010"))->Fill(cent, sampleIndex, fQ112232_010); + histos.get(HIST("Prof2D_Q112232_100"))->Fill(cent, sampleIndex, fQ112232_100); + histos.get(HIST("Prof2D_Q112232_011"))->Fill(cent, sampleIndex, fQ112232_011); + histos.get(HIST("Prof2D_Q112232_101"))->Fill(cent, sampleIndex, fQ112232_101); + histos.get(HIST("Prof2D_Q112232_110"))->Fill(cent, sampleIndex, fQ112232_110); + histos.get(HIST("Prof2D_Q112231_001"))->Fill(cent, sampleIndex, fQ112231_001); + histos.get(HIST("Prof2D_Q112231_010"))->Fill(cent, sampleIndex, fQ112231_010); + histos.get(HIST("Prof2D_Q112231_100"))->Fill(cent, sampleIndex, fQ112231_100); + histos.get(HIST("Prof2D_Q112231_011"))->Fill(cent, sampleIndex, fQ112231_011); + histos.get(HIST("Prof2D_Q112231_101"))->Fill(cent, sampleIndex, fQ112231_101); + histos.get(HIST("Prof2D_Q112231_110"))->Fill(cent, sampleIndex, fQ112231_110); + histos.get(HIST("Prof2D_Q112133_001"))->Fill(cent, sampleIndex, fQ112133_001); + histos.get(HIST("Prof2D_Q112133_010"))->Fill(cent, sampleIndex, fQ112133_010); + histos.get(HIST("Prof2D_Q112133_100"))->Fill(cent, sampleIndex, fQ112133_100); + histos.get(HIST("Prof2D_Q112133_011"))->Fill(cent, sampleIndex, fQ112133_011); + histos.get(HIST("Prof2D_Q112133_101"))->Fill(cent, sampleIndex, fQ112133_101); + histos.get(HIST("Prof2D_Q112133_110"))->Fill(cent, sampleIndex, fQ112133_110); + histos.get(HIST("Prof2D_Q112132_001"))->Fill(cent, sampleIndex, fQ112132_001); + histos.get(HIST("Prof2D_Q112132_010"))->Fill(cent, sampleIndex, fQ112132_010); + histos.get(HIST("Prof2D_Q112132_100"))->Fill(cent, sampleIndex, fQ112132_100); + histos.get(HIST("Prof2D_Q112132_011"))->Fill(cent, sampleIndex, fQ112132_011); + histos.get(HIST("Prof2D_Q112132_101"))->Fill(cent, sampleIndex, fQ112132_101); + histos.get(HIST("Prof2D_Q112132_110"))->Fill(cent, sampleIndex, fQ112132_110); + histos.get(HIST("Prof2D_Q112131_001"))->Fill(cent, sampleIndex, fQ112131_001); + histos.get(HIST("Prof2D_Q112131_010"))->Fill(cent, sampleIndex, fQ112131_010); + histos.get(HIST("Prof2D_Q112131_100"))->Fill(cent, sampleIndex, fQ112131_100); + histos.get(HIST("Prof2D_Q112131_011"))->Fill(cent, sampleIndex, fQ112131_011); + histos.get(HIST("Prof2D_Q112131_101"))->Fill(cent, sampleIndex, fQ112131_101); + histos.get(HIST("Prof2D_Q112131_110"))->Fill(cent, sampleIndex, fQ112131_110); + histos.get(HIST("Prof2D_Q2221_11"))->Fill(cent, sampleIndex, fQ2221_11); + histos.get(HIST("Prof2D_Q2221_01"))->Fill(cent, sampleIndex, fQ2221_01); + histos.get(HIST("Prof2D_Q2221_10"))->Fill(cent, sampleIndex, fQ2221_10); + histos.get(HIST("Prof2D_Q2221_21"))->Fill(cent, sampleIndex, fQ2221_21); + histos.get(HIST("Prof2D_Q2221_20"))->Fill(cent, sampleIndex, fQ2221_20); + histos.get(HIST("Prof2D_Q2122_21"))->Fill(cent, sampleIndex, fQ2122_21); + histos.get(HIST("Prof2D_Q2122_20"))->Fill(cent, sampleIndex, fQ2122_20); + histos.get(HIST("Prof2D_Q1121_02"))->Fill(cent, sampleIndex, fQ1121_02); + histos.get(HIST("Prof2D_Q1121_12"))->Fill(cent, sampleIndex, fQ1121_12); + histos.get(HIST("Prof2D_Q1121_22"))->Fill(cent, sampleIndex, fQ1121_22); + histos.get(HIST("Prof2D_Q1122_02"))->Fill(cent, sampleIndex, fQ1122_02); + histos.get(HIST("Prof2D_Q1122_12"))->Fill(cent, sampleIndex, fQ1122_12); + histos.get(HIST("Prof2D_Q1122_22"))->Fill(cent, sampleIndex, fQ1122_22); + histos.get(HIST("Prof2D_Q112221_001"))->Fill(cent, sampleIndex, fQ112221_001); + histos.get(HIST("Prof2D_Q112221_010"))->Fill(cent, sampleIndex, fQ112221_010); + histos.get(HIST("Prof2D_Q112221_100"))->Fill(cent, sampleIndex, fQ112221_100); + histos.get(HIST("Prof2D_Q112221_011"))->Fill(cent, sampleIndex, fQ112221_011); + histos.get(HIST("Prof2D_Q112221_101"))->Fill(cent, sampleIndex, fQ112221_101); + histos.get(HIST("Prof2D_Q112221_110"))->Fill(cent, sampleIndex, fQ112221_110); + histos.get(HIST("Prof2D_Q112221_200"))->Fill(cent, sampleIndex, fQ112221_200); + histos.get(HIST("Prof2D_Q112221_201"))->Fill(cent, sampleIndex, fQ112221_201); + histos.get(HIST("Prof2D_Q112221_210"))->Fill(cent, sampleIndex, fQ112221_210); + histos.get(HIST("Prof2D_Q112221_211"))->Fill(cent, sampleIndex, fQ112221_211); + histos.get(HIST("Prof2D_Q1131_21"))->Fill(cent, sampleIndex, fQ1131_21); + histos.get(HIST("Prof2D_Q1131_20"))->Fill(cent, sampleIndex, fQ1131_20); + histos.get(HIST("Prof2D_Q1131_31"))->Fill(cent, sampleIndex, fQ1131_31); + histos.get(HIST("Prof2D_Q1131_30"))->Fill(cent, sampleIndex, fQ1131_30); + histos.get(HIST("Prof2D_Q1132_21"))->Fill(cent, sampleIndex, fQ1132_21); + histos.get(HIST("Prof2D_Q1132_20"))->Fill(cent, sampleIndex, fQ1132_20); + histos.get(HIST("Prof2D_Q1132_31"))->Fill(cent, sampleIndex, fQ1132_31); + histos.get(HIST("Prof2D_Q1132_30"))->Fill(cent, sampleIndex, fQ1132_30); + histos.get(HIST("Prof2D_Q1133_21"))->Fill(cent, sampleIndex, fQ1133_21); + histos.get(HIST("Prof2D_Q1133_20"))->Fill(cent, sampleIndex, fQ1133_20); + histos.get(HIST("Prof2D_Q1133_31"))->Fill(cent, sampleIndex, fQ1133_31); + histos.get(HIST("Prof2D_Q1133_30"))->Fill(cent, sampleIndex, fQ1133_30); + histos.get(HIST("Prof2D_Q11_5"))->Fill(cent, sampleIndex, fQ11_5); + histos.get(HIST("Prof2D_Q11_6"))->Fill(cent, sampleIndex, fQ11_6); + histos.get(HIST("Prof2D_Q1121_30"))->Fill(cent, sampleIndex, fQ1121_30); + histos.get(HIST("Prof2D_Q1121_31"))->Fill(cent, sampleIndex, fQ1121_31); + histos.get(HIST("Prof2D_Q1121_40"))->Fill(cent, sampleIndex, fQ1121_40); + histos.get(HIST("Prof2D_Q1121_41"))->Fill(cent, sampleIndex, fQ1121_41); + histos.get(HIST("Prof2D_Q1122_30"))->Fill(cent, sampleIndex, fQ1122_30); + histos.get(HIST("Prof2D_Q1122_31"))->Fill(cent, sampleIndex, fQ1122_31); + histos.get(HIST("Prof2D_Q1122_40"))->Fill(cent, sampleIndex, fQ1122_40); + histos.get(HIST("Prof2D_Q1122_41"))->Fill(cent, sampleIndex, fQ1122_41); + histos.get(HIST("Prof2D_Q2211_11"))->Fill(cent, sampleIndex, fQ2211_11); + histos.get(HIST("Prof2D_Q2211_01"))->Fill(cent, sampleIndex, fQ2211_01); + histos.get(HIST("Prof2D_Q2211_10"))->Fill(cent, sampleIndex, fQ2211_10); + histos.get(HIST("Prof2D_Q2211_20"))->Fill(cent, sampleIndex, fQ2211_20); + histos.get(HIST("Prof2D_Q2211_21"))->Fill(cent, sampleIndex, fQ2211_21); + histos.get(HIST("Prof2D_Q2111_11"))->Fill(cent, sampleIndex, fQ2111_11); + histos.get(HIST("Prof2D_Q2111_01"))->Fill(cent, sampleIndex, fQ2111_01); + histos.get(HIST("Prof2D_Q2111_10"))->Fill(cent, sampleIndex, fQ2111_10); + histos.get(HIST("Prof2D_Q2111_20"))->Fill(cent, sampleIndex, fQ2111_20); + histos.get(HIST("Prof2D_Q2111_21"))->Fill(cent, sampleIndex, fQ2111_21); + histos.get(HIST("Prof2D_Q112122_001"))->Fill(cent, sampleIndex, fQ112122_001); + histos.get(HIST("Prof2D_Q112122_010"))->Fill(cent, sampleIndex, fQ112122_010); + histos.get(HIST("Prof2D_Q112122_100"))->Fill(cent, sampleIndex, fQ112122_100); + histos.get(HIST("Prof2D_Q112122_011"))->Fill(cent, sampleIndex, fQ112122_011); + histos.get(HIST("Prof2D_Q112122_101"))->Fill(cent, sampleIndex, fQ112122_101); + histos.get(HIST("Prof2D_Q112122_110"))->Fill(cent, sampleIndex, fQ112122_110); + histos.get(HIST("Prof2D_Q1141_11"))->Fill(cent, sampleIndex, fQ1141_11); + histos.get(HIST("Prof2D_Q1141_01"))->Fill(cent, sampleIndex, fQ1141_01); + histos.get(HIST("Prof2D_Q1141_10"))->Fill(cent, sampleIndex, fQ1141_10); + histos.get(HIST("Prof2D_Q1141_20"))->Fill(cent, sampleIndex, fQ1141_20); + histos.get(HIST("Prof2D_Q1141_21"))->Fill(cent, sampleIndex, fQ1141_21); + histos.get(HIST("Prof2D_Q1142_11"))->Fill(cent, sampleIndex, fQ1142_11); + histos.get(HIST("Prof2D_Q1142_01"))->Fill(cent, sampleIndex, fQ1142_01); + histos.get(HIST("Prof2D_Q1142_10"))->Fill(cent, sampleIndex, fQ1142_10); + histos.get(HIST("Prof2D_Q1142_20"))->Fill(cent, sampleIndex, fQ1142_20); + histos.get(HIST("Prof2D_Q1142_21"))->Fill(cent, sampleIndex, fQ1142_21); + histos.get(HIST("Prof2D_Q1143_11"))->Fill(cent, sampleIndex, fQ1143_11); + histos.get(HIST("Prof2D_Q1143_01"))->Fill(cent, sampleIndex, fQ1143_01); + histos.get(HIST("Prof2D_Q1143_10"))->Fill(cent, sampleIndex, fQ1143_10); + histos.get(HIST("Prof2D_Q1143_20"))->Fill(cent, sampleIndex, fQ1143_20); + histos.get(HIST("Prof2D_Q1143_21"))->Fill(cent, sampleIndex, fQ1143_21); + histos.get(HIST("Prof2D_Q1144_11"))->Fill(cent, sampleIndex, fQ1144_11); + histos.get(HIST("Prof2D_Q1144_01"))->Fill(cent, sampleIndex, fQ1144_01); + histos.get(HIST("Prof2D_Q1144_10"))->Fill(cent, sampleIndex, fQ1144_10); + histos.get(HIST("Prof2D_Q1144_20"))->Fill(cent, sampleIndex, fQ1144_20); + histos.get(HIST("Prof2D_Q1144_21"))->Fill(cent, sampleIndex, fQ1144_21); + histos.get(HIST("Prof2D_Q2131_11"))->Fill(cent, sampleIndex, fQ2131_11); + histos.get(HIST("Prof2D_Q2131_01"))->Fill(cent, sampleIndex, fQ2131_01); + histos.get(HIST("Prof2D_Q2131_10"))->Fill(cent, sampleIndex, fQ2131_10); + histos.get(HIST("Prof2D_Q2132_11"))->Fill(cent, sampleIndex, fQ2132_11); + histos.get(HIST("Prof2D_Q2132_01"))->Fill(cent, sampleIndex, fQ2132_01); + histos.get(HIST("Prof2D_Q2132_10"))->Fill(cent, sampleIndex, fQ2132_10); + histos.get(HIST("Prof2D_Q2133_11"))->Fill(cent, sampleIndex, fQ2133_11); + histos.get(HIST("Prof2D_Q2133_01"))->Fill(cent, sampleIndex, fQ2133_01); + histos.get(HIST("Prof2D_Q2133_10"))->Fill(cent, sampleIndex, fQ2133_10); + histos.get(HIST("Prof2D_Q2231_11"))->Fill(cent, sampleIndex, fQ2231_11); + histos.get(HIST("Prof2D_Q2231_01"))->Fill(cent, sampleIndex, fQ2231_01); + histos.get(HIST("Prof2D_Q2231_10"))->Fill(cent, sampleIndex, fQ2231_10); + histos.get(HIST("Prof2D_Q2232_11"))->Fill(cent, sampleIndex, fQ2232_11); + histos.get(HIST("Prof2D_Q2232_01"))->Fill(cent, sampleIndex, fQ2232_01); + histos.get(HIST("Prof2D_Q2232_10"))->Fill(cent, sampleIndex, fQ2232_10); + histos.get(HIST("Prof2D_Q2233_11"))->Fill(cent, sampleIndex, fQ2233_11); + histos.get(HIST("Prof2D_Q2233_01"))->Fill(cent, sampleIndex, fQ2233_01); + histos.get(HIST("Prof2D_Q2233_10"))->Fill(cent, sampleIndex, fQ2233_10); + histos.get(HIST("Prof2D_Q51_1"))->Fill(cent, sampleIndex, fQ51_1); + histos.get(HIST("Prof2D_Q52_1"))->Fill(cent, sampleIndex, fQ52_1); + histos.get(HIST("Prof2D_Q53_1"))->Fill(cent, sampleIndex, fQ53_1); + histos.get(HIST("Prof2D_Q54_1"))->Fill(cent, sampleIndex, fQ54_1); + histos.get(HIST("Prof2D_Q55_1"))->Fill(cent, sampleIndex, fQ55_1); + histos.get(HIST("Prof2D_Q21_3"))->Fill(cent, sampleIndex, fQ21_3); + histos.get(HIST("Prof2D_Q22_3"))->Fill(cent, sampleIndex, fQ22_3); + histos.get(HIST("Prof2D_Q31_2"))->Fill(cent, sampleIndex, fQ31_2); + histos.get(HIST("Prof2D_Q32_2"))->Fill(cent, sampleIndex, fQ32_2); + histos.get(HIST("Prof2D_Q33_2"))->Fill(cent, sampleIndex, fQ33_2); + histos.get(HIST("Prof2D_Q61_1"))->Fill(cent, sampleIndex, fQ61_1); + histos.get(HIST("Prof2D_Q62_1"))->Fill(cent, sampleIndex, fQ62_1); + histos.get(HIST("Prof2D_Q63_1"))->Fill(cent, sampleIndex, fQ63_1); + histos.get(HIST("Prof2D_Q64_1"))->Fill(cent, sampleIndex, fQ64_1); + histos.get(HIST("Prof2D_Q65_1"))->Fill(cent, sampleIndex, fQ65_1); + histos.get(HIST("Prof2D_Q66_1"))->Fill(cent, sampleIndex, fQ66_1); + histos.get(HIST("Prof2D_Q112122_111"))->Fill(cent, sampleIndex, fQ112122_111); + histos.get(HIST("Prof2D_Q112131_111"))->Fill(cent, sampleIndex, fQ112131_111); + histos.get(HIST("Prof2D_Q112132_111"))->Fill(cent, sampleIndex, fQ112132_111); + histos.get(HIST("Prof2D_Q112133_111"))->Fill(cent, sampleIndex, fQ112133_111); + histos.get(HIST("Prof2D_Q112231_111"))->Fill(cent, sampleIndex, fQ112231_111); + histos.get(HIST("Prof2D_Q112232_111"))->Fill(cent, sampleIndex, fQ112232_111); + histos.get(HIST("Prof2D_Q112233_111"))->Fill(cent, sampleIndex, fQ112233_111); + histos.get(HIST("Prof2D_Q112221_111"))->Fill(cent, sampleIndex, fQ112221_111); + } + } + PROCESS_SWITCH(NetprotonCumulantsMc, processDataRec, "Process real data", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/PWGCF/Femto3D/CMakeLists.txt b/PWGCF/Femto3D/CMakeLists.txt old mode 100755 new mode 100644 index e57cd178dd8..073719cffa7 --- a/PWGCF/Femto3D/CMakeLists.txt +++ b/PWGCF/Femto3D/CMakeLists.txt @@ -12,4 +12,5 @@ add_subdirectory(Core) add_subdirectory(DataModel) add_subdirectory(TableProducer) -add_subdirectory(Tasks) \ No newline at end of file +add_subdirectory(Tasks) +add_subdirectory(Tools) diff --git a/PWGCF/Femto3D/Core/femto3dPairTask.h b/PWGCF/Femto3D/Core/femto3dPairTask.h index 2bda63575a8..5627215ea55 100755 --- a/PWGCF/Femto3D/Core/femto3dPairTask.h +++ b/PWGCF/Femto3D/Core/femto3dPairTask.h @@ -16,6 +16,7 @@ #ifndef PWGCF_FEMTO3D_CORE_FEMTO3DPAIRTASK_H_ #define PWGCF_FEMTO3D_CORE_FEMTO3DPAIRTASK_H_ +#define THETA(eta) 2.0 * std::atan(std::exp(-eta)) // #include "Framework/ASoA.h" // #include "Framework/DataTypes.h" // #include "Framework/AnalysisDataModel.h" @@ -24,17 +25,72 @@ // #include "Common/DataModel/Multiplicity.h" #include +#include #include "TLorentzVector.h" #include "TVector3.h" #include "TDatabasePDG.h" -double particle_mass(int PDGcode) +#include "CommonConstants/PhysicsConstants.h" +#include "CommonConstants/MathConstants.h" + +double particle_mass(const int PDGcode) +{ + switch (std::abs(PDGcode)) { + case o2::constants::physics::kDeuteron: + return o2::constants::physics::MassDeuteron; + case o2::constants::physics::kTriton: + return o2::constants::physics::MassTriton; + case o2::constants::physics::kHelium3: + return o2::constants::physics::MassHelium3; + case 211: + return o2::constants::physics::MassPionCharged; + case 321: + return o2::constants::physics::MassKaonCharged; + case 2212: + return o2::constants::physics::MassProton; + default: + break; + } + return TDatabasePDG::Instance()->GetParticle(PDGcode)->Mass(); +} + +// for the variable binning in 3D DCA histos in the PairMC task +inline std::unique_ptr calc_const_bins(const int& N, const float& xmin, const float& xmax) // needed only to calculate bins along X axis for DCA histos (even if the bin width is constant have to use an array since want to have variable bins in Y and Z) +{ + auto bins = std::make_unique(N + 1); + + float wbin = (xmax - xmin) / N; + bins[0] = xmin; + + for (int i = 1; i < N + 1; i++) { + bins[i] = bins[i - 1] + wbin; + } + + return bins; +} + +// for the variable binning in 3D DCA histos in the PairMC task +inline std::unique_ptr calc_var_bins(const int& N, const float& xmax, const int& scale) { - // if(PDGcode == 2212) return TDatabasePDG::Instance()->GetParticle(2212)->Mass(); - if (PDGcode == 1000010020) - return 1.87561294257; - else - return TDatabasePDG::Instance()->GetParticle(PDGcode)->Mass(); + auto bins = std::make_unique(N); + + float q = std::pow(scale, 1.0 / (0.5 * N)); // q -- common ratio of the geometric progression, estimated through the requested scaling of w_bin + + float winit = xmax * (1 - q) / (1 - scale); // initial w_bin is estimated through sum of the bin width (sum of N elements in geometric progression) that must be equal to xmax + + float bin_edge = 0.5 * winit; + bins[0.5 * N - 1] = -bin_edge; // first bin edge left to the center (i.e. 0) + bins[0.5 * N] = bin_edge; // first bin edge right to the center (i.e. 0) + bins[0] = -xmax; + bins[N - 1] = xmax; + + for (int i = 1; i < 0.5 * N - 1; i++) { + bin_edge += winit * std::pow(q, i); + bins[0.5 * N - 1 - i] = -bin_edge; + bins[0.5 * N + i] = bin_edge; + } + + return bins; } namespace o2::aod::singletrackselector @@ -67,14 +123,14 @@ float GetKstarFrom4vectors(TLorentzVector& first4momentum, TLorentzVector& secon { if (isIdentical) { TLorentzVector fourmomentadiff = first4momentum - second4momentum; - return 0.5 * abs(fourmomentadiff.Mag()); + return 0.5 * std::fabs(fourmomentadiff.Mag()); } else { TLorentzVector fourmomentasum = first4momentum + second4momentum; TLorentzVector fourmomentadif = first4momentum - second4momentum; fourmomentadif.Boost((-1) * fourmomentasum.BoostVector()); - return 0.5 * abs(fourmomentadif.Vect().Mag()); + return 0.5 * std::fabs(fourmomentadif.Vect().Mag()); } } @@ -151,7 +207,12 @@ class FemtoPair TrackType* GetSecondParticle() const { return _second; } bool IsIdentical() { return _isidentical; } - bool IsClosePair(const float& deta = 0.01, const float& dphi = 0.01, const float& radius = 1.2) const; + bool IsClosePair(const float& deta, const float& dphi, const float& radius) const; + bool IsClosePair(const float& deta, const float& dphi) const; + bool IsClosePair(const float& avgSep) const { return static_cast(GetAvgSep() < avgSep); } + + float GetAvgSep() const; + float GetEtaDiff() const { if (_first != NULL && _second != NULL) @@ -166,10 +227,13 @@ class FemtoPair else return 1000; } + float GetAvgPhiStarDiff() const; + float GetKstar() const; TVector3 GetQLCMS() const; float GetKt() const; - float GetMt() const; // test + float GetMt() const; // test + float GetGammaOut() const; // test private: TrackType _first = NULL; @@ -177,6 +241,7 @@ class FemtoPair float _magfield1 = 0.0, _magfield2 = 0.0; int _PDG1 = 0, _PDG2 = 0; bool _isidentical = true; + std::array TPCradii = {0.85, 1.05, 1.25, 1.45, 1.65, 1.85, 2.05, 2.25, 2.45}; }; template @@ -205,11 +270,69 @@ bool FemtoPair::IsClosePair(const float& deta, const float& dphi, con return true; if (_magfield1 * _magfield2 == 0) return true; - if (abs(GetEtaDiff()) < deta && abs(GetPhiStarDiff(radius)) < dphi) + const float relEtaDiff = GetEtaDiff() / deta; + const float relPhiStarDiff = GetPhiStarDiff(radius) / dphi; + if ((relEtaDiff * relEtaDiff + relPhiStarDiff * relPhiStarDiff) < 1.0f) + return true; + // if (std::fabs(GetEtaDiff()) < deta && std::fabs(GetPhiStarDiff(radius)) < dphi) + // return true; + + return false; +} + +template +bool FemtoPair::IsClosePair(const float& deta, const float& dphi) const +{ + if (_first == NULL || _second == NULL) + return true; + if (_magfield1 * _magfield2 == 0) + return true; + const float relEtaDiff = GetEtaDiff() / deta; + const float relPhiStarDiff = GetAvgPhiStarDiff() / dphi; + if ((relEtaDiff * relEtaDiff + relPhiStarDiff * relPhiStarDiff) < 1.0f) return true; + // if (std::fabs(GetEtaDiff()) < deta && std::fabs(GetPhiStarDiff(radius)) < dphi) + // return true; return false; } +template +float FemtoPair::GetAvgSep() const +{ + if (_first == NULL || _second == NULL) + return -100.f; + if (_magfield1 * _magfield2 == 0) + return -100.f; + + float dtheta = THETA(_first->eta()) - THETA(_second->eta()); + float res = 0.0; + + for (const auto& radius : TPCradii) { + const float dRtrans = 2.0 * radius * std::sin(0.5 * GetPhiStarDiff(radius)); + const float dRlong = 2.0 * radius * std::sin(0.5 * dtheta); + res += std::sqrt(dRtrans * dRtrans + dRlong * dRlong); + } + + return 100.0 * res / TPCradii.size(); +} + +template +float FemtoPair::GetAvgPhiStarDiff() const +{ + if (_first == NULL || _second == NULL) + return -100.f; + if (_magfield1 * _magfield2 == 0) + return -100.f; + + float res = 0.0; + + for (const auto& radius : TPCradii) { + const float dphi = GetPhiStarDiff(radius); + res += std::fabs(dphi) > o2::constants::math::PI ? (1.0 - 2.0 * o2::constants::math::PI / std::fabs(dphi)) * dphi : dphi; + } + + return res / TPCradii.size(); +} template float FemtoPair::GetKstar() const @@ -256,8 +379,9 @@ float FemtoPair::GetKt() const return -1000; if (_PDG1 * _PDG2 == 0) return -1000; - - return 0.5 * std::sqrt(std::pow(_first->px() + _second->px(), 2) + std::pow(_first->py() + _second->py(), 2)); + const float px = _first->px() + _second->px(); + const float py = _first->py() + _second->py(); + return 0.5 * std::sqrt(px * px + py * py); } template @@ -279,6 +403,34 @@ float FemtoPair::GetMt() const return 0.5 * fourmomentasum.Mt(); } + +template +float FemtoPair::GetGammaOut() const +{ + if (_first == NULL || _second == NULL) + return -1000; + if (_magfield1 * _magfield2 == 0) + return -1000; + if (_PDG1 * _PDG2 == 0) + return -1000; + + // double Qinv = 2.0 * GetKstar(); + // TVector3 QLCMS = GetQLCMS(); + // double Qout_PRF = sqrt(Qinv * Qinv - QLCMS.Y() * QLCMS.Y() - QLCMS.Z() * QLCMS.Z()); + // return std::fabs(QLCMS.X() / Qout_PRF); + + TLorentzVector first4momentum; + first4momentum.SetPtEtaPhiM(_first->pt(), _first->eta(), _first->phi(), particle_mass(_PDG1)); + TLorentzVector second4momentum; + second4momentum.SetPtEtaPhiM(_second->pt(), _second->eta(), _second->phi(), particle_mass(_PDG2)); + + TLorentzVector fourmomentasum = first4momentum + second4momentum; + + fourmomentasum.Boost(0.0, 0.0, (-1) * fourmomentasum.BoostVector().Z()); // boost to LCMS + fourmomentasum.RotateZ((-1) * fourmomentasum.Phi()); // rotate so the X axis is along pair's kT + + return fourmomentasum.Gamma(); +} } // namespace o2::aod::singletrackselector #endif // PWGCF_FEMTO3D_CORE_FEMTO3DPAIRTASK_H_ diff --git a/PWGCF/Femto3D/DataModel/PIDutils.h b/PWGCF/Femto3D/DataModel/PIDutils.h new file mode 100644 index 00000000000..9e28f7b5863 --- /dev/null +++ b/PWGCF/Femto3D/DataModel/PIDutils.h @@ -0,0 +1,255 @@ +// 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 PIDutils.h +/// \author Gleb Romanenko gleb.romanenko@cern.ch +/// \brief SFINAE checks for existance of PID info +/// \since 24/03/2025 +/// + +#ifndef PWGCF_FEMTO3D_DATAMODEL_PIDUTILS_H_ +#define PWGCF_FEMTO3D_DATAMODEL_PIDUTILS_H_ + +#include +#include +#include +#include "Common/DataModel/PIDResponse.h" + +namespace o2::aod::singletrackselector +{ +namespace pidutils +{ + +//========================================== SFINAE checks ========================================== + +template +struct hasTPCPi : std::false_type { +}; +template +struct hasTPCPi>> : std::true_type { +}; + +template +struct hasTPCKa : std::false_type { +}; +template +struct hasTPCKa>> : std::true_type { +}; + +template +struct hasTPCPr : std::false_type { +}; +template +struct hasTPCPr>> : std::true_type { +}; + +template +struct hasTPCDe : std::false_type { +}; +template +struct hasTPCDe>> : std::true_type { +}; + +template +struct hasTPCTr : std::false_type { +}; +template +struct hasTPCTr>> : std::true_type { +}; + +template +struct hasTPCHe : std::false_type { +}; +template +struct hasTPCHe>> : std::true_type { +}; + +template +struct hasTOFPi : std::false_type { +}; +template +struct hasTOFPi>> : std::true_type { +}; + +template +struct hasTOFKa : std::false_type { +}; +template +struct hasTOFKa>> : std::true_type { +}; + +template +struct hasTOFPr : std::false_type { +}; +template +struct hasTOFPr>> : std::true_type { +}; + +template +struct hasTOFDe : std::false_type { +}; +template +struct hasTOFDe>> : std::true_type { +}; + +template +struct hasTOFTr : std::false_type { +}; +template +struct hasTOFTr>> : std::true_type { +}; + +template +struct hasTOFHe : std::false_type { +}; +template +struct hasTOFHe>> : std::true_type { +}; + +} // namespace pidutils + +//========================================== ITS PID ========================================== + +template +inline float getITSNsigma(TrackType const& track, int const& PDG) +{ + switch (PDG) { + case 211: + return track.itsNSigmaPi(); + case 321: + return track.itsNSigmaKa(); + case 2212: + return track.itsNSigmaPr(); + case 1000010020: + return track.itsNSigmaDe(); + case 1000020030: + return track.itsNSigmaHe(); + case 1000010030: + return track.itsNSigmaTr(); + case 0: + return -1000.0; + default: + LOG(fatal) << "Cannot interpret PDG for ITS selection: " << PDG; + return -1000.0; + } +} + +template +inline bool ITSselection(TrackType const& track, std::pair> const& PIDcuts) +{ + float Nsigma = getITSNsigma(track, PIDcuts.first); + + if (Nsigma > PIDcuts.second[0] && Nsigma < PIDcuts.second[1]) { + return true; + } + return false; +} + +//========================================== TPC PID ========================================== + +template +inline float getTPCNsigma(TrackType const& track, int const& PDG) +{ + switch (PDG) { + case 211: + if constexpr (o2::aod::singletrackselector::pidutils::hasTPCPi::value) + return track.tpcNSigmaPi(); + case 321: + if constexpr (o2::aod::singletrackselector::pidutils::hasTPCKa::value) + return track.tpcNSigmaKa(); + case 2212: + if constexpr (o2::aod::singletrackselector::pidutils::hasTPCPr::value) + return track.tpcNSigmaPr(); + case 1000010020: + if constexpr (o2::aod::singletrackselector::pidutils::hasTPCDe::value) + return track.tpcNSigmaDe(); + case 1000020030: + if constexpr (o2::aod::singletrackselector::pidutils::hasTPCHe::value) + return track.tpcNSigmaHe(); + case 1000010030: + if constexpr (o2::aod::singletrackselector::pidutils::hasTPCTr::value) + return track.tpcNSigmaTr(); + case 0: + return -1000.0; + default: + LOG(fatal) << "Cannot interpret PDG for TPC selection: " << PDG; + return -1000.0; + } +} + +template +inline bool TPCselection(TrackType const& track, std::pair> const& PIDcuts, std::vector const& ITSCut = std::vector{}) +{ + int PDG = PIDcuts.first; + + if constexpr (useITS) { + if (ITSCut.size() != 0 && !ITSselection(track, std::make_pair(PDG, ITSCut))) + return false; + } + + float Nsigma = getTPCNsigma(track, PDG); + + if (Nsigma > PIDcuts.second[0] && Nsigma < PIDcuts.second[1]) { + return true; + } + return false; +} + +//========================================== TOF PID ========================================== + +template +inline float getTOFNsigma(TrackType const& track, int const& PDG) +{ + switch (PDG) { + case 211: + if constexpr (o2::aod::singletrackselector::pidutils::hasTOFPi::value) + return track.tofNSigmaPi(); + case 321: + if constexpr (o2::aod::singletrackselector::pidutils::hasTOFKa::value) + return track.tofNSigmaKa(); + case 2212: + if constexpr (o2::aod::singletrackselector::pidutils::hasTOFPr::value) + return track.tofNSigmaPr(); + case 1000010020: + if constexpr (o2::aod::singletrackselector::pidutils::hasTOFDe::value) + return track.tofNSigmaDe(); + case 1000020030: + if constexpr (o2::aod::singletrackselector::pidutils::hasTOFHe::value) + return track.tofNSigmaHe(); + case 1000010030: + if constexpr (o2::aod::singletrackselector::pidutils::hasTOFTr::value) + return track.tofNSigmaTr(); + case 0: + return -1000.0; + default: + LOG(fatal) << "Cannot interpret PDG for TOF selection: " << PDG; + return -1000.0; + } +} + +template +inline bool TOFselection(TrackType const& track, std::pair> const& PIDcuts, std::vector const& TPCresidualCut = std::vector{-5.0f, 5.0f}) +{ + int PDG = PIDcuts.first; + if (!TPCselection(track, std::make_pair(PDG, TPCresidualCut))) + return false; + + float Nsigma = getTOFNsigma(track, PDG); + + if (Nsigma > PIDcuts.second[0] && Nsigma < PIDcuts.second[1]) { + return true; + } + return false; +} +} // namespace o2::aod::singletrackselector + +#endif // PWGCF_FEMTO3D_DATAMODEL_PIDUTILS_H_ diff --git a/PWGCF/Femto3D/DataModel/singletrackselector.h b/PWGCF/Femto3D/DataModel/singletrackselector.h old mode 100755 new mode 100644 index e91dafc7bbd..c7323d15a32 --- a/PWGCF/Femto3D/DataModel/singletrackselector.h +++ b/PWGCF/Femto3D/DataModel/singletrackselector.h @@ -16,15 +16,17 @@ #ifndef PWGCF_FEMTO3D_DATAMODEL_SINGLETRACKSELECTOR_H_ #define PWGCF_FEMTO3D_DATAMODEL_SINGLETRACKSELECTOR_H_ -#include +// #include #include #include #include "Framework/ASoA.h" #include "Framework/AnalysisDataModel.h" #include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" #include "Framework/Logger.h" #include "Common/DataModel/Multiplicity.h" +#include "PWGCF/Femto3D/DataModel/PIDutils.h" namespace o2::aod { @@ -55,58 +57,84 @@ inline o2::framework::expressions::Node unPack(const T& b) return binningType::bin_width * b + binningType::binned_center; } +template +inline typename binningType::binned_t packSymmetric(const float& valueToBin) +{ + if (valueToBin <= binningType::binned_min) { + return (binningType::underflowBin); + } else if (valueToBin >= binningType::binned_max) { + return (binningType::overflowBin); + } else if (valueToBin >= 0) { + return (static_cast((valueToBin * binningType::inv_bin_width) + 0.5f)); + } else { + return (static_cast((valueToBin * binningType::inv_bin_width) - 0.5f)); + } +} + +template +inline float unPackSymmetric(const typename binningType::binned_t& b) +{ + return binningType::bin_width * static_cast(b); +} + +template +inline o2::framework::expressions::Node unPackSymmetric(const T& b) +{ + return binningType::bin_width * static_cast(b); +} + namespace binning { + +template lim, typename binVariable = int8_t> struct binningParent { public: - typedef int8_t binned_t; + typedef binVariable binned_t; static constexpr int nbins = (1 << 8 * sizeof(binned_t)) - 2; static constexpr binned_t overflowBin = nbins >> 1; static constexpr binned_t underflowBin = -(nbins >> 1); -}; -struct nsigma : binningParent { - public: - static constexpr float binned_min = -10.0; - static constexpr float binned_max = 10.0; + static constexpr float binned_min = lim.first; + static constexpr float binned_max = lim.second; static constexpr float binned_center = 0.5 * (binned_min + binned_max); static constexpr float bin_width = (binned_max - binned_min) / nbins; + static constexpr float inv_bin_width = 1. / bin_width; + static_assert(binned_min < binned_max, "Invalid binning range"); + static void print() + { + LOG(info) << "Binning: " << binned_min << " - " << binned_max << " with " << nbins << " bins, width = " + << bin_width << ". Overflow bin " << static_cast(overflowBin) << " Underflow bin " << static_cast(underflowBin); + } }; -struct dca : binningParent { - public: - static constexpr float binned_min = -1.0; - static constexpr float binned_max = 1.0; - static constexpr float binned_center = 0.5 * (binned_min + binned_max); - static constexpr float bin_width = (binned_max - binned_min) / nbins; -}; +// using nsigma_v0 = binningParent(-10.f, 10.f)>; +using nsigma_v1 = binningParent(-6.35f, 6.35f)>; // Width 0.05 symmetric around 0 +using nsigma = nsigma_v1; -struct chi2 : binningParent { - public: - static constexpr float binned_min = 0.0; - static constexpr float binned_max = 10.0; - static constexpr float binned_center = 0.5 * (binned_min + binned_max); - static constexpr float bin_width = (binned_max - binned_min) / nbins; -}; +// using dca_v0 = binningParent(-1.f, 1.f)>; +// using dca_v1 = binningParent(-1.f, 1.f), int16_t>; +using dca_v2 = binningParent(-3.2767f, 3.2767f), int16_t>; // Width 0.0001 symmetric around 0 +using dca = dca_v2; -struct rowsOverFindable : binningParent { - public: - static constexpr float binned_min = 0.0; - static constexpr float binned_max = 3.0; - static constexpr float binned_center = 0.5 * (binned_min + binned_max); - static constexpr float bin_width = (binned_max - binned_min) / nbins; -}; +using chi2 = binningParent(0.f, 10.f)>; +using rowsOverFindable = binningParent(0.f, 3.f)>; } // namespace binning +//==================================== base event characteristics ==================================== DECLARE_SOA_COLUMN(Mult, mult, int); // Multiplicity of the collision DECLARE_SOA_COLUMN(MultPercentile, multPerc, float); // Percentiles of multiplicity of the collision DECLARE_SOA_COLUMN(PosZ, posZ, float); // Vertex of the collision DECLARE_SOA_COLUMN(MagField, magField, float); // Magnetic field corresponding to a collision (in T) -DECLARE_SOA_COLUMN(IsNoSameBunchPileup, isNoSameBunchPileup, bool); -DECLARE_SOA_COLUMN(IsGoodZvtxFT0vsPV, isGoodZvtxFT0vsPV, bool); -DECLARE_SOA_COLUMN(IsVertexITSTPC, isVertexITSTPC, bool); +//==================================== extra event characteristics ==================================== +DECLARE_SOA_COLUMN(HadronicRate, hadronicRate, double); +DECLARE_SOA_COLUMN(Occupancy, occupancy, int); +DECLARE_SOA_DYNAMIC_COLUMN(dIsNoSameBunchPileup, isNoSameBunchPileup, [](uint64_t selBit) -> bool { return TESTBIT(selBit, evsel::kNoSameBunchPileup); }); +DECLARE_SOA_DYNAMIC_COLUMN(dIsGoodZvtxFT0vsPV, isGoodZvtxFT0vsPV, [](uint64_t selBit) -> bool { return TESTBIT(selBit, evsel::kIsGoodZvtxFT0vsPV); }); +DECLARE_SOA_DYNAMIC_COLUMN(dIsVertexITSTPC, isVertexITSTPC, [](uint64_t selBit) -> bool { return TESTBIT(selBit, evsel::kIsVertexITSTPC); }); +DECLARE_SOA_DYNAMIC_COLUMN(dIsVertexTOForTRDmatched, isVertexTOForTRDmatched, [](uint64_t selBit) -> int { return static_cast(TESTBIT(selBit, evsel::kIsVertexTOFmatched)) + static_cast(TESTBIT(selBit, evsel::kIsVertexTRDmatched)); }); +DECLARE_SOA_DYNAMIC_COLUMN(dNoCollInTimeRangeStandard, noCollInTimeRangeStandard, [](uint64_t selBit) -> bool { return TESTBIT(selBit, evsel::kNoCollInTimeRangeStandard); }); } // namespace singletrackselector @@ -117,145 +145,332 @@ DECLARE_SOA_TABLE(SingleCollSels, "AOD", "SINGLECOLLSEL", // Table of the variab singletrackselector::PosZ, singletrackselector::MagField); -DECLARE_SOA_TABLE(SingleCollExtras, "AOD", "SINGLECOLLEXTRA", // Joinable collision table with Pile-Up flags - singletrackselector::IsNoSameBunchPileup, - singletrackselector::IsGoodZvtxFT0vsPV, - singletrackselector::IsVertexITSTPC); +DECLARE_SOA_TABLE(SingleCollExtras_v1, "AOD", "SINGLECOLLEXTR1", // Joinable collision table with Pile-Up flags + evsel::Selection, + singletrackselector::HadronicRate, + singletrackselector::Occupancy, + + singletrackselector::dIsNoSameBunchPileup, + singletrackselector::dIsGoodZvtxFT0vsPV, + singletrackselector::dIsVertexITSTPC, + singletrackselector::dIsVertexTOForTRDmatched, + singletrackselector::dNoCollInTimeRangeStandard); + +using SingleCollExtras = SingleCollExtras_v1; namespace singletrackselector { +//==================================== track characteristics ==================================== + DECLARE_SOA_INDEX_COLUMN(SingleCollSel, singleCollSel); // Index to the collision DECLARE_SOA_COLUMN(P, p, float); // Momentum of the track DECLARE_SOA_COLUMN(Eta, eta, float); DECLARE_SOA_COLUMN(Phi, phi, float); DECLARE_SOA_COLUMN(Sign, sign, int8_t); -DECLARE_SOA_COLUMN(TPCNClsFound, tpcNClsFound, int16_t); // Number of TPC clusters -DECLARE_SOA_COLUMN(TPCNClsShared, tpcNClsShared, uint8_t); // Number of shared TPC clusters -DECLARE_SOA_COLUMN(ITSNCls, itsNCls, uint8_t); // Number of ITS clusters - -DECLARE_SOA_COLUMN(StoredDcaXY, storedDcaXY, binning::dca::binned_t); // impact parameter of the track -DECLARE_SOA_COLUMN(StoredDcaZ, storedDcaZ, binning::dca::binned_t); // impact parameter of the track -DECLARE_SOA_COLUMN(StoredTPCChi2NCl, storedTpcChi2NCl, binning::chi2::binned_t); // TPC chi2 -DECLARE_SOA_COLUMN(StoredITSChi2NCl, storedItsChi2NCl, binning::chi2::binned_t); // ITS chi2 -DECLARE_SOA_COLUMN(StoredTPCCrossedRowsOverFindableCls, storedTpcCrossedRowsOverFindableCls, binning::rowsOverFindable::binned_t); // Ratio of found over findable clusters - -DECLARE_SOA_COLUMN(StoredTOFNSigmaPi, storedTofNSigmaPi, binning::nsigma::binned_t); -DECLARE_SOA_COLUMN(StoredTPCNSigmaPi, storedTpcNSigmaPi, binning::nsigma::binned_t); -DECLARE_SOA_COLUMN(StoredTOFNSigmaKa, storedTofNSigmaKa, binning::nsigma::binned_t); -DECLARE_SOA_COLUMN(StoredTPCNSigmaKa, storedTpcNSigmaKa, binning::nsigma::binned_t); -DECLARE_SOA_COLUMN(StoredTOFNSigmaPr, storedTofNSigmaPr, binning::nsigma::binned_t); -DECLARE_SOA_COLUMN(StoredTPCNSigmaPr, storedTpcNSigmaPr, binning::nsigma::binned_t); -DECLARE_SOA_COLUMN(StoredTOFNSigmaDe, storedTofNSigmaDe, binning::nsigma::binned_t); -DECLARE_SOA_COLUMN(StoredTPCNSigmaDe, storedTpcNSigmaDe, binning::nsigma::binned_t); +DECLARE_SOA_COLUMN(TPCNClsFound, tpcNClsFound, int16_t); // Number of TPC clusters +DECLARE_SOA_COLUMN(TPCNClsShared, tpcNClsShared, uint8_t); // Number of shared TPC clusters +DECLARE_SOA_DYNAMIC_COLUMN(TPCFractionSharedCls, tpcFractionSharedCls, //! Fraction of shared TPC clusters + [](uint8_t tpcNClsShared, int16_t tpcNClsFound) -> float { return (float)tpcNClsShared / (float)tpcNClsFound; }); -DECLARE_SOA_DYNAMIC_COLUMN(Energy, energy, [](float p, float mass) -> float { return sqrt(p * p + mass * mass); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float p, float eta) -> float { return p / std::cosh(eta); }); -DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float p, float eta, float phi) -> float { return (p / std::cosh(eta)) * std::sin(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float p, float eta, float phi) -> float { return (p / std::cosh(eta)) * std::cos(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float p, float eta) -> float { return p * std::tanh(eta); }); -DECLARE_SOA_DYNAMIC_COLUMN(PhiStar, phiStar, - [](float p, float eta, float sign, float phi, float magfield = 0.0, float radius = 1.6) -> float { - if (magfield == 0.0) { - return -1000.0; - } else { - return phi + std::asin(-0.3 * magfield * sign * radius / (2.0 * p / std::cosh(eta))); - } - }); +DECLARE_SOA_COLUMN(ITSclsMap, itsClsMap, uint8_t); +DECLARE_SOA_COLUMN(ITSclusterSizes, itsClusterSizes, uint32_t); +DECLARE_SOA_DYNAMIC_COLUMN(ITSNClsDyn, itsNCls, [](uint32_t itsClusterSizes) -> uint8_t { + uint8_t itsNcls = 0; + for (int layer = 0; layer < 7; layer++) { + if ((itsClusterSizes >> (layer * 4)) & 0xf) + itsNcls++; + } + return itsNcls; +}); -DECLARE_SOA_DYNAMIC_COLUMN(DcaXY, dcaXY, - [](binning::dca::binned_t dca_binned) -> float { return singletrackselector::unPack(dca_binned); }); -DECLARE_SOA_DYNAMIC_COLUMN(DcaZ, dcaZ, - [](binning::dca::binned_t dca_binned) -> float { return singletrackselector::unPack(dca_binned); }); +DECLARE_SOA_COLUMN(StoredTPCChi2NCl, storedTpcChi2NCl, binning::chi2::binned_t); // TPC chi2 DECLARE_SOA_DYNAMIC_COLUMN(TPCChi2NCl, tpcChi2NCl, [](binning::chi2::binned_t chi2_binned) -> float { return singletrackselector::unPack(chi2_binned); }); + +DECLARE_SOA_COLUMN(StoredITSChi2NCl, storedItsChi2NCl, binning::chi2::binned_t); // ITS chi2 DECLARE_SOA_DYNAMIC_COLUMN(ITSChi2NCl, itsChi2NCl, [](binning::chi2::binned_t chi2_binned) -> float { return singletrackselector::unPack(chi2_binned); }); +DECLARE_SOA_COLUMN(StoredTPCCrossedRowsOverFindableCls, storedTpcCrossedRowsOverFindableCls, binning::rowsOverFindable::binned_t); // Ratio of found over findable clusters DECLARE_SOA_DYNAMIC_COLUMN(TPCCrossedRowsOverFindableCls, tpcCrossedRowsOverFindableCls, [](binning::rowsOverFindable::binned_t rowsOverFindable_binned) -> float { return singletrackselector::unPack(rowsOverFindable_binned); }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCFractionSharedCls, tpcFractionSharedCls, //! Fraction of shared TPC clusters - [](uint8_t tpcNClsShared, int16_t tpcNClsFound) -> float { return (float)tpcNClsShared / (float)tpcNClsFound; }); +//==================================== DCA ==================================== + +DECLARE_SOA_COLUMN(StoredDcaXY, storedDcaXY, binning::dca::binned_t); // impact parameter of the track with 16 bits (v2, larger range) +DECLARE_SOA_DYNAMIC_COLUMN(DcaXY, dcaXY, + [](binning::dca::binned_t dca_binned) -> float { return singletrackselector::unPackSymmetric(dca_binned); }); +DECLARE_SOA_COLUMN(StoredDcaZ, storedDcaZ, binning::dca::binned_t); // impact parameter of the track with 16 bits (v2, larger range) +DECLARE_SOA_DYNAMIC_COLUMN(DcaZ, dcaZ, + [](binning::dca::binned_t dca_binned) -> float { return singletrackselector::unPackSymmetric(dca_binned); }); + +using StoredDcaXY_v2 = StoredDcaXY; // compatibility with the old tables of version 2 -- to be removed later +using StoredDcaZ_v2 = StoredDcaZ; // compatibility with the old tables of version 2 -- to be removed later +//==================================== PID ==================================== + +//------------------------------------ Electrons ------------------------------------ + +DECLARE_SOA_COLUMN(StoredTOFNSigmaEl, storedTofNSigmaEl, binning::nsigma::binned_t); // (v1) TOF +DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigmaEl, tofNSigmaEl, + [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPackSymmetric(nsigma_binned); }); + +DECLARE_SOA_COLUMN(StoredTPCNSigmaEl, storedTpcNSigmaEl, binning::nsigma::binned_t); // (v1) TPC +DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaEl, tpcNSigmaEl, + [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPackSymmetric(nsigma_binned); }); + +//------------------------------------ Pions ------------------------------------ +DECLARE_SOA_COLUMN(StoredTOFNSigmaPi, storedTofNSigmaPi, binning::nsigma::binned_t); // (v1) TOF DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigmaPi, tofNSigmaPi, - [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPack(nsigma_binned); }); + [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPackSymmetric(nsigma_binned); }); + +DECLARE_SOA_COLUMN(StoredTPCNSigmaPi, storedTpcNSigmaPi, binning::nsigma::binned_t); // (v1) TPC DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaPi, tpcNSigmaPi, - [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPack(nsigma_binned); }); + [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPackSymmetric(nsigma_binned); }); + +//------------------------------------ Kaons ------------------------------------ +DECLARE_SOA_COLUMN(StoredTOFNSigmaKa, storedTofNSigmaKa, binning::nsigma::binned_t); // (v1) TOF DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigmaKa, tofNSigmaKa, - [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPack(nsigma_binned); }); + [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPackSymmetric(nsigma_binned); }); + +DECLARE_SOA_COLUMN(StoredTPCNSigmaKa, storedTpcNSigmaKa, binning::nsigma::binned_t); // (v1) TPC DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaKa, tpcNSigmaKa, - [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPack(nsigma_binned); }); + [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPackSymmetric(nsigma_binned); }); +//------------------------------------ Protons ------------------------------------ +DECLARE_SOA_COLUMN(StoredTOFNSigmaPr, storedTofNSigmaPr, binning::nsigma::binned_t); // (v1) TOF DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigmaPr, tofNSigmaPr, - [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPack(nsigma_binned); }); + [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPackSymmetric(nsigma_binned); }); + +DECLARE_SOA_COLUMN(StoredTPCNSigmaPr, storedTpcNSigmaPr, binning::nsigma::binned_t); // (v1) TPC DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaPr, tpcNSigmaPr, - [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPack(nsigma_binned); }); + [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPackSymmetric(nsigma_binned); }); + +//------------------------------------ Deutrons ------------------------------------ +DECLARE_SOA_COLUMN(StoredTOFNSigmaDe, storedTofNSigmaDe, binning::nsigma::binned_t); // (v1) TOF DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigmaDe, tofNSigmaDe, - [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPack(nsigma_binned); }); + [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPackSymmetric(nsigma_binned); }); + +DECLARE_SOA_COLUMN(StoredTPCNSigmaDe, storedTpcNSigmaDe, binning::nsigma::binned_t); // (v1) TPC DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaDe, tpcNSigmaDe, - [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPack(nsigma_binned); }); + [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPackSymmetric(nsigma_binned); }); -DECLARE_SOA_COLUMN(TPCInnerParam, tpcInnerParam, float); // Momentum at inner wall of the TPC -DECLARE_SOA_COLUMN(TPCSignal, tpcSignal, float); // dE/dx TPC -DECLARE_SOA_COLUMN(Beta, beta, float); // TOF beta +//------------------------------------ Triton ------------------------------------ +DECLARE_SOA_COLUMN(StoredTOFNSigmaTr, storedTofNSigmaTr, binning::nsigma::binned_t); // (v1) TOF +DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigmaTr, tofNSigmaTr, + [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPackSymmetric(nsigma_binned); }); +DECLARE_SOA_COLUMN(StoredTPCNSigmaTr, storedTpcNSigmaTr, binning::nsigma::binned_t); // (v1) TPC +DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaTr, tpcNSigmaTr, + [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPackSymmetric(nsigma_binned); }); + +//------------------------------------ Helium3 ------------------------------------ +DECLARE_SOA_COLUMN(StoredTOFNSigmaHe, storedTofNSigmaHe, binning::nsigma::binned_t); // (v1) TOF +DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigmaHe, tofNSigmaHe, + [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPackSymmetric(nsigma_binned); }); + +DECLARE_SOA_COLUMN(StoredTPCNSigmaHe, storedTpcNSigmaHe, binning::nsigma::binned_t); // (v1) TPC +DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaHe, tpcNSigmaHe, + [](binning::nsigma::binned_t nsigma_binned) -> float { return singletrackselector::unPackSymmetric(nsigma_binned); }); + +using StoredTOFNSigmaPi_v1 = StoredTOFNSigmaPi; // compatibility with the old tables of version 2 -- to be removed later +using StoredTPCNSigmaPi_v1 = StoredTPCNSigmaPi; // compatibility with the old tables of version 2 -- to be removed later + +using StoredTOFNSigmaKa_v1 = StoredTOFNSigmaKa; // compatibility with the old tables of version 2 -- to be removed later +using StoredTPCNSigmaKa_v1 = StoredTPCNSigmaKa; // compatibility with the old tables of version 2 -- to be removed later + +using StoredTOFNSigmaPr_v1 = StoredTOFNSigmaPr; // compatibility with the old tables of version 2 -- to be removed later +using StoredTPCNSigmaPr_v1 = StoredTPCNSigmaPr; // compatibility with the old tables of version 2 -- to be removed later + +using StoredTOFNSigmaDe_v1 = StoredTOFNSigmaDe; // compatibility with the old tables of version 2 -- to be removed later +using StoredTPCNSigmaDe_v1 = StoredTPCNSigmaDe; // compatibility with the old tables of version 2 -- to be removed later + +using StoredTOFNSigmaHe_v1 = StoredTOFNSigmaHe; // compatibility with the old tables of version 2 -- to be removed later +using StoredTPCNSigmaHe_v1 = StoredTPCNSigmaHe; // compatibility with the old tables of version 2 -- to be removed later + +//==================================== Dynamic cols for kinematics ==================================== + +DECLARE_SOA_DYNAMIC_COLUMN(Energy, energy, [](float p, float mass) -> float { return sqrt(p * p + mass * mass); }); DECLARE_SOA_DYNAMIC_COLUMN(Rapidity, rapidity, //! Track rapidity, computed under the mass assumption given as input [](float p, float eta, float mass) -> float { const auto pz = p * std::tanh(eta); const auto energy = std::sqrt(p * p + mass * mass); return 0.5f * log((energy + pz) / (energy - pz)); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float p, float eta) -> float { return p / std::cosh(eta); }); +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float p, float eta, float phi) -> float { return (p / std::cosh(eta)) * std::sin(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float p, float eta, float phi) -> float { return (p / std::cosh(eta)) * std::cos(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float p, float eta) -> float { return p * std::tanh(eta); }); +DECLARE_SOA_DYNAMIC_COLUMN(PhiStar, phiStar, + [](float p, float eta, float sign, float phi, float magfield = 0.0, float radius = 1.6) -> float { + if (magfield == 0.0) { + return -1000.0; + } else { + return phi + std::asin(-0.3 * magfield * sign * radius / (2.0 * p / std::cosh(eta))); + } + }); + +//==================================== EXtra info ==================================== + +DECLARE_SOA_COLUMN(TPCInnerParam, tpcInnerParam, float); // Momentum at inner wall of the TPC +DECLARE_SOA_COLUMN(TPCSignal, tpcSignal, float); // dE/dx TPC +DECLARE_SOA_COLUMN(Beta, beta, float); // TOF beta } // namespace singletrackselector -DECLARE_SOA_TABLE_FULL(SingleTrackSels, "SelTracks", "AOD", "SINGLETRACKSEL", // Table of the variables for single track selection. - o2::soa::Index<>, - singletrackselector::SingleCollSelId, - singletrackselector::P, - singletrackselector::Eta, - singletrackselector::Phi, - singletrackselector::Sign, - singletrackselector::TPCNClsFound, - singletrackselector::TPCNClsShared, - singletrackselector::ITSNCls, - singletrackselector::StoredDcaXY, - singletrackselector::StoredDcaZ, - singletrackselector::StoredTPCChi2NCl, - singletrackselector::StoredITSChi2NCl, - singletrackselector::StoredTPCCrossedRowsOverFindableCls, - - singletrackselector::StoredTOFNSigmaPi, - singletrackselector::StoredTPCNSigmaPi, - singletrackselector::StoredTOFNSigmaKa, - singletrackselector::StoredTPCNSigmaKa, - singletrackselector::StoredTOFNSigmaPr, - singletrackselector::StoredTPCNSigmaPr, - singletrackselector::StoredTOFNSigmaDe, - singletrackselector::StoredTPCNSigmaDe, - - singletrackselector::DcaXY, - singletrackselector::DcaZ, - singletrackselector::TPCChi2NCl, - singletrackselector::ITSChi2NCl, - singletrackselector::TPCCrossedRowsOverFindableCls, - singletrackselector::TPCFractionSharedCls, - - singletrackselector::TOFNSigmaPi, - singletrackselector::TPCNSigmaPi, - singletrackselector::TOFNSigmaKa, - singletrackselector::TPCNSigmaKa, - singletrackselector::TOFNSigmaPr, - singletrackselector::TPCNSigmaPr, - singletrackselector::TOFNSigmaDe, - singletrackselector::TPCNSigmaDe, - - singletrackselector::Rapidity, - singletrackselector::Energy, - singletrackselector::Pt, - singletrackselector::Px, - singletrackselector::Py, - singletrackselector::Pz, - singletrackselector::PhiStar); +DECLARE_SOA_TABLE(SingleTrackSels_v3, "AOD", "SINGLETRACKSEL", // Table of the variables for single track selection. + o2::soa::Index<>, + singletrackselector::SingleCollSelId, + singletrackselector::P, + singletrackselector::Eta, + singletrackselector::Phi, + singletrackselector::Sign, + singletrackselector::TPCNClsFound, + singletrackselector::TPCNClsShared, + singletrackselector::ITSclsMap, + singletrackselector::ITSclusterSizes, + singletrackselector::StoredDcaXY, + singletrackselector::StoredDcaZ, + singletrackselector::StoredTPCChi2NCl, + singletrackselector::StoredITSChi2NCl, + singletrackselector::StoredTPCCrossedRowsOverFindableCls, + + singletrackselector::ITSNClsDyn, + track::v001::ITSClsSizeInLayer, + singletrackselector::DcaXY, + singletrackselector::DcaZ, + singletrackselector::TPCChi2NCl, + singletrackselector::ITSChi2NCl, + singletrackselector::TPCCrossedRowsOverFindableCls, + singletrackselector::TPCFractionSharedCls, + + singletrackselector::Energy, + singletrackselector::Rapidity, + singletrackselector::Pt, + singletrackselector::Px, + singletrackselector::Py, + singletrackselector::Pz, + singletrackselector::PhiStar, + + // PID with ITS (from PIDResponseITS.h) + o2::aod::pidits::ITSNSigmaElImp, + o2::aod::pidits::ITSNSigmaPiImp, + o2::aod::pidits::ITSNSigmaKaImp, + o2::aod::pidits::ITSNSigmaPrImp, + o2::aod::pidits::ITSNSigmaDeImp, + o2::aod::pidits::ITSNSigmaTrImp, + o2::aod::pidits::ITSNSigmaHeImp); + +DECLARE_SOA_TABLE_VERSIONED(SingleTrackSels_v2, "AOD", "SINGLETRACKSEL2", 2, // Table of the variables for single track selection. + o2::soa::Index<>, + singletrackselector::SingleCollSelId, + singletrackselector::P, + singletrackselector::Eta, + singletrackselector::Phi, + singletrackselector::Sign, + singletrackselector::TPCNClsFound, + singletrackselector::TPCNClsShared, + singletrackselector::ITSclsMap, + singletrackselector::ITSclusterSizes, + singletrackselector::StoredDcaXY_v2, + singletrackselector::StoredDcaZ_v2, + singletrackselector::StoredTPCChi2NCl, + singletrackselector::StoredITSChi2NCl, + singletrackselector::StoredTPCCrossedRowsOverFindableCls, + + singletrackselector::StoredTOFNSigmaPi_v1, + singletrackselector::StoredTPCNSigmaPi_v1, + singletrackselector::StoredTOFNSigmaKa_v1, + singletrackselector::StoredTPCNSigmaKa_v1, + singletrackselector::StoredTOFNSigmaPr_v1, + singletrackselector::StoredTPCNSigmaPr_v1, + singletrackselector::StoredTOFNSigmaDe_v1, + singletrackselector::StoredTPCNSigmaDe_v1, + singletrackselector::StoredTOFNSigmaHe_v1, + singletrackselector::StoredTPCNSigmaHe_v1, + + singletrackselector::ITSNClsDyn, + track::v001::ITSClsSizeInLayer, + singletrackselector::DcaXY, + singletrackselector::DcaZ, + singletrackselector::TPCChi2NCl, + singletrackselector::ITSChi2NCl, + singletrackselector::TPCCrossedRowsOverFindableCls, + singletrackselector::TPCFractionSharedCls, + + singletrackselector::TOFNSigmaPi, + singletrackselector::TPCNSigmaPi, + singletrackselector::TOFNSigmaKa, + singletrackselector::TPCNSigmaKa, + singletrackselector::TOFNSigmaPr, + singletrackselector::TPCNSigmaPr, + singletrackselector::TOFNSigmaDe, + singletrackselector::TPCNSigmaDe, + singletrackselector::TOFNSigmaHe, + singletrackselector::TPCNSigmaHe, + + singletrackselector::Rapidity, + singletrackselector::Energy, + singletrackselector::Pt, + singletrackselector::Px, + singletrackselector::Py, + singletrackselector::Pz, + singletrackselector::PhiStar); + +using SingleTrackSels = SingleTrackSels_v3; + +DECLARE_SOA_TABLE(SinglePIDEls_v0, "AOD", "SINGLEPIDEL0", + singletrackselector::StoredTPCNSigmaEl, + singletrackselector::TPCNSigmaEl); + +DECLARE_SOA_TABLE(SinglePIDEls, "AOD", "SINGLEPIDEL", + singletrackselector::StoredTOFNSigmaEl, + singletrackselector::StoredTPCNSigmaEl, + + singletrackselector::TOFNSigmaEl, + singletrackselector::TPCNSigmaEl); + +DECLARE_SOA_TABLE(SinglePIDPis, "AOD", "SINGLEPIDPI", + singletrackselector::StoredTOFNSigmaPi, + singletrackselector::StoredTPCNSigmaPi, + + singletrackselector::TOFNSigmaPi, + singletrackselector::TPCNSigmaPi); + +DECLARE_SOA_TABLE(SinglePIDKas, "AOD", "SINGLEPIDKA", + singletrackselector::StoredTOFNSigmaKa, + singletrackselector::StoredTPCNSigmaKa, + + singletrackselector::TOFNSigmaKa, + singletrackselector::TPCNSigmaKa); + +DECLARE_SOA_TABLE(SinglePIDPrs, "AOD", "SINGLEPIDPR", + singletrackselector::StoredTOFNSigmaPr, + singletrackselector::StoredTPCNSigmaPr, + + singletrackselector::TOFNSigmaPr, + singletrackselector::TPCNSigmaPr); + +DECLARE_SOA_TABLE(SinglePIDDes, "AOD", "SINGLEPIDDE", + singletrackselector::StoredTOFNSigmaDe, + singletrackselector::StoredTPCNSigmaDe, + + singletrackselector::TOFNSigmaDe, + singletrackselector::TPCNSigmaDe); + +DECLARE_SOA_TABLE(SinglePIDTrs, "AOD", "SINGLEPIDTR", + singletrackselector::StoredTOFNSigmaTr, + singletrackselector::StoredTPCNSigmaTr, + + singletrackselector::TOFNSigmaTr, + singletrackselector::TPCNSigmaTr); + +DECLARE_SOA_TABLE(SinglePIDHes, "AOD", "SINGLEPIDHE", + singletrackselector::StoredTOFNSigmaHe, + singletrackselector::StoredTPCNSigmaHe, + + singletrackselector::TOFNSigmaHe, + singletrackselector::TPCNSigmaHe); DECLARE_SOA_TABLE(SingleTrkExtras, "AOD", "SINGLETRKEXTRA", singletrackselector::TPCInnerParam, @@ -275,6 +490,10 @@ DECLARE_SOA_DYNAMIC_COLUMN(Px_MC, px_MC, [](float p, float eta, float phi) -> fl DECLARE_SOA_DYNAMIC_COLUMN(Py_MC, py_MC, [](float p, float eta, float phi) -> float { return (p / std::cosh(eta)) * std::cos(phi); }); DECLARE_SOA_DYNAMIC_COLUMN(Pz_MC, pz_MC, [](float p, float eta) -> float { return p * std::tanh(eta); }); +// DECLARE_SOA_COLUMN(Vx_MC, vx_MC, float); +// DECLARE_SOA_COLUMN(Vy_MC, vy_MC, float); +// DECLARE_SOA_COLUMN(Vz_MC, vz_MC, float); + } // namespace singletrackselector DECLARE_SOA_TABLE(SingleTrkMCs, "AOD", "SINGLETRKMC", // Table with generatad info from MC @@ -288,74 +507,11 @@ DECLARE_SOA_TABLE(SingleTrkMCs, "AOD", "SINGLETRKMC", // Table with generatad in singletrackselector::Py_MC, singletrackselector::Pz_MC); +// DECLARE_SOA_TABLE(SingleTrkMCExtras, "AOD", "SINGLETRKMCEX", // Table with generatad info from MC +// singletrackselector::Vx_MC, +// singletrackselector::Vy_MC, +// singletrackselector::Vz_MC); + } // namespace o2::aod #endif // PWGCF_FEMTO3D_DATAMODEL_SINGLETRACKSELECTOR_H_ - -namespace o2::aod::singletrackselector -{ - -template -inline bool TPCselection(TrackType const& track, std::pair> const& PIDcuts) -{ - int PDG = PIDcuts.first; - float Nsigma = -1000; - switch (PDG) { - case 2212: - Nsigma = track.tpcNSigmaPr(); - break; - case 1000010020: - Nsigma = track.tpcNSigmaDe(); - break; - case 211: - Nsigma = track.tpcNSigmaPi(); - break; - case 321: - Nsigma = track.tpcNSigmaKa(); - break; - case 0: - return false; - default: - LOG(fatal) << "Cannot interpret PDG for TPC selection: " << PIDcuts.first; - } - - if (Nsigma > PIDcuts.second[0] && Nsigma < PIDcuts.second[1]) { - return true; - } - return false; -} - -template -inline bool TOFselection(TrackType const& track, std::pair> const& PIDcuts, float const& TPCresidualCut = 5.0f) -{ - int PDG = PIDcuts.first; - if (!TPCselection(track, std::make_pair(PDG, std::vector{-TPCresidualCut, TPCresidualCut}))) - return false; - - float Nsigma = -1000; - switch (PDG) { - case 2212: - Nsigma = track.tofNSigmaPr(); - break; - case 1000010020: - Nsigma = track.tofNSigmaDe(); - break; - case 211: - Nsigma = track.tofNSigmaPi(); - break; - case 321: - Nsigma = track.tofNSigmaKa(); - break; - case 0: - return false; - default: - LOG(fatal) << "Cannot interpret PDG for TOF selection: " << PIDcuts.first; - } - - if (Nsigma > PIDcuts.second[0] && Nsigma < PIDcuts.second[1]) { - return true; - } - return false; -} - -} // namespace o2::aod::singletrackselector diff --git a/PWGCF/Femto3D/TableProducer/CMakeLists.txt b/PWGCF/Femto3D/TableProducer/CMakeLists.txt old mode 100755 new mode 100644 index 48750decf2e..01831d63091 --- a/PWGCF/Femto3D/TableProducer/CMakeLists.txt +++ b/PWGCF/Femto3D/TableProducer/CMakeLists.txt @@ -9,12 +9,19 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +#add_subdirectory(Converters) + o2physics_add_dpl_workflow(single-track-selector - SOURCES singleTrackSelector.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore - COMPONENT_NAME Analysis) + SOURCES singleTrackSelector.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(single-track-selector-extra - SOURCES singleTrackSelectorExtra.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore - COMPONENT_NAME Analysis) \ No newline at end of file + SOURCES singleTrackSelectorExtra.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(single-track-selector-pid-dummy + SOURCES singleTrackSelectorPIDMaker.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) \ No newline at end of file diff --git a/PWGCF/Femto3D/TableProducer/Converters/CMakeLists.txt b/PWGCF/Femto3D/TableProducer/Converters/CMakeLists.txt new file mode 100644 index 00000000000..9014f8fbe4e --- /dev/null +++ b/PWGCF/Femto3D/TableProducer/Converters/CMakeLists.txt @@ -0,0 +1,21 @@ +# 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(single-track-selector-converter + SOURCES singleTrackSelectorConverter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(single-track-selector-converter-v1 + SOURCES singleTrackSelectorConverterV1.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + diff --git a/PWGCF/Femto3D/TableProducer/Converters/singleTrackSelectorConverter.cxx b/PWGCF/Femto3D/TableProducer/Converters/singleTrackSelectorConverter.cxx new file mode 100644 index 00000000000..4a44e331e9b --- /dev/null +++ b/PWGCF/Femto3D/TableProducer/Converters/singleTrackSelectorConverter.cxx @@ -0,0 +1,75 @@ +// 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 Converter for the different versions of the singletrackselector tables +/// \author Sofia Tomassini, Gleb Romanenko, Nicolò Jacazio +/// \since 03 May 2024 + +#include +#include "PWGCF/Femto3D/DataModel/singletrackselector.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::track; +using namespace o2::aod; +//::singletrackselector; // the namespace defined in .h + +struct singleTrackSelectorConverter { + Produces tableRow; + + void init(InitContext&) {} + + void process(o2::aod::SingleTrackSels_v0 const& tracks) + { + tableRow.reserve(tracks.size()); + for (auto const& track : tracks) { + constexpr uint8_t itsClsMap = 0; // Not in the previous data model + int32_t itsClusterSizes = 0; + for (int l = 0; l < track.itsNCls(); l++) { + itsClusterSizes &= ~(0xf << (l * 4)); + itsClusterSizes |= (1 << (l * 4)); + } + tableRow(track.singleCollSelId(), + track.p(), + track.eta(), + track.phi(), + track.sign(), + track.tpcNClsFound(), + track.tpcNClsShared(), + itsClsMap, + itsClusterSizes, + + singletrackselector::packInTable(track.dcaXY()), + singletrackselector::packInTable(track.dcaZ()), + singletrackselector::packInTable(track.tpcChi2NCl()), + singletrackselector::packInTable(track.itsChi2NCl()), + singletrackselector::packInTable(track.tpcCrossedRowsOverFindableCls()), + singletrackselector::packInTable(track.tofNSigmaPi()), + singletrackselector::packInTable(track.tpcNSigmaPi()), + singletrackselector::packInTable(track.tofNSigmaKa()), + singletrackselector::packInTable(track.tpcNSigmaKa()), + singletrackselector::packInTable(track.tofNSigmaPr()), + singletrackselector::packInTable(track.tpcNSigmaPr()), + singletrackselector::packInTable(track.tofNSigmaDe()), + singletrackselector::packInTable(track.tpcNSigmaDe()), + singletrackselector::binning::nsigma::underflowBin, + singletrackselector::binning::nsigma::underflowBin); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Femto3D/TableProducer/Converters/singleTrackSelectorConverterV1.cxx b/PWGCF/Femto3D/TableProducer/Converters/singleTrackSelectorConverterV1.cxx new file mode 100644 index 00000000000..584760ce74a --- /dev/null +++ b/PWGCF/Femto3D/TableProducer/Converters/singleTrackSelectorConverterV1.cxx @@ -0,0 +1,68 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \brief Converter for the different versions of the singletrackselector tables +/// \author Sofia Tomassini, Gleb Romanenko, Nicolò Jacazio +/// \since 03 May 2024 + +#include +#include "PWGCF/Femto3D/DataModel/singletrackselector.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::track; +using namespace o2::aod; +//::singletrackselector; // the namespace defined in .h + +struct singleTrackSelectorConverter { + Produces tableRow; + + void init(InitContext&) {} + + void process(o2::aod::SingleTrackSels_v1 const& tracks) + { + tableRow.reserve(tracks.size()); + for (auto const& track : tracks) { + tableRow(track.singleCollSelId(), + track.p(), + track.eta(), + track.phi(), + track.sign(), + track.tpcNClsFound(), + track.tpcNClsShared(), + track.itsClsMap(), + track.itsClusterSizes(), + singletrackselector::packSymmetric(track.dcaXY()), + singletrackselector::packSymmetric(track.dcaZ()), + singletrackselector::packInTable(track.tpcChi2NCl()), + singletrackselector::packInTable(track.itsChi2NCl()), + singletrackselector::packInTable(track.tpcCrossedRowsOverFindableCls()), + singletrackselector::packSymmetric(track.tofNSigmaPi()), + singletrackselector::packSymmetric(track.tpcNSigmaPi()), + singletrackselector::packSymmetric(track.tofNSigmaKa()), + singletrackselector::packSymmetric(track.tpcNSigmaKa()), + singletrackselector::packSymmetric(track.tofNSigmaPr()), + singletrackselector::packSymmetric(track.tpcNSigmaPr()), + singletrackselector::packSymmetric(track.tofNSigmaDe()), + singletrackselector::packSymmetric(track.tpcNSigmaDe()), + singletrackselector::packSymmetric(track.tofNSigmaHe()), + singletrackselector::packSymmetric(track.tpcNSigmaHe())); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Femto3D/TableProducer/singleTrackSelector.cxx b/PWGCF/Femto3D/TableProducer/singleTrackSelector.cxx index 3260481ad79..05a47bdc8e2 100644 --- a/PWGCF/Femto3D/TableProducer/singleTrackSelector.cxx +++ b/PWGCF/Femto3D/TableProducer/singleTrackSelector.cxx @@ -17,6 +17,11 @@ #include #include +#include +#include + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" #include "PWGCF/Femto3D/DataModel/singletrackselector.h" @@ -27,6 +32,8 @@ #include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/CCDB/ctpRateFetcher.h" #include "DetectorsBase/Propagator.h" #include "DataFormatsParameters/GRPObject.h" @@ -43,9 +50,14 @@ using namespace o2::aod; struct singleTrackSelector { Service ccdb; + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable applySkimming{"applySkimming", false, "Skimmed dataset processing"}; + Configurable cfgSkimming{"cfgSkimming", "fPD", "Configurable for skimming"}; Configurable applyEvSel{"applyEvSel", 2, "Flag to apply rapidity cut: 0 -> no event selection, 1 -> Run 2 event selection, 2 -> Run 3 event selection"}; // Configurable trackSelection{"trackSelection", 1, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; @@ -53,10 +65,11 @@ struct singleTrackSelector { Configurable multTableToUse{"multTableToUse", 1, "Flag to choose mult. estimator (Run3 only): 0 -> TPCMults, 1 -> MultNTracksPV, 2 -> MultNTracksPVeta1"}; Configurable rejectNotPropagatedTrks{"rejectNotPropagatedTrks", true, "rejects tracks that are not propagated to the primary vertex"}; Configurable enable_gen_info{"enable_gen_info", false, "Enable MC true info"}; + Configurable fetchRate{"fetchRate", true, "Fetch the hadronic rate from the CCDB"}; Configurable> _particlesToKeep{"particlesToKeepPDGs", std::vector{2212, 1000010020}, "PDG codes of perticles for which the 'singletrackselector' tables will be created (only proton and deurton are supported now)"}; Configurable> keepWithinNsigmaTPC{"keepWithinNsigmaTPC", std::vector{-4.0f, 4.0f}, "TPC range for preselection of particles specified with PDG"}; - Configurable> _particlesToReject{"particlesToRejectPDGs", std::vector{211, 321}, "PDG codes of particles that will be rejected with TOF (only pion, kaon, proton and deurton are supported now)"}; + Configurable> _particlesToReject{"particlesToRejectPDGs", std::vector{211, 321, 1000020030}, "PDG codes of particles that will be rejected with TOF (only pion, kaon, proton and deurton are supported now)"}; Configurable> rejectWithinNsigmaTOF{"rejectWithinNsigmaTOF", std::vector{-5.0f, 5.0f}, "TOF rejection Nsigma range for particles specified with PDG to be rejected"}; Configurable _pRemoveTofOutOfRange{"pRemoveTofOutOfRange", 100.f, "momentum starting from which request TOF nSigma to be within the stored range (-10 < Nsigma < 10)"}; @@ -66,15 +79,17 @@ struct singleTrackSelector { Configurable _eta{"eta", 100.f, "abs eta value limit"}; Configurable _dcaXY{"dcaXY", 1000.f, "Maximum dca of track in xy"}; Configurable _dcaZ{"dcaZ", 1000.f, "Maximum dca of track in xy"}; + Configurable _dcaXYmin{"dcaXYmin", -1000.f, "Minimum dca of track in xy"}; + Configurable _dcaZmin{"dcaZmin", -1000.f, "Minimum dca of track in xy"}; Configurable _maxTofChi2{"maxTofChi2", 10.f, "Maximum TOF Chi2 value -> to remove mismatched tracks"}; Configurable _vertexZ{"VertexZ", 15.0, "abs vertexZ value limit"}; Configurable> _centCut{"centCut", std::pair{0.f, 100.f}, "[min., max.] centrality range to keep events within"}; using Trks = soa::Join; using CollRun2 = soa::Join; @@ -85,7 +100,17 @@ struct singleTrackSelector { Produces tableRowCollExtra; Produces tableRow; Produces tableRowExtra; + + Produces tableRowPIDEl; + Produces tableRowPIDPi; + Produces tableRowPIDKa; + Produces tableRowPIDPr; + Produces tableRowPIDDe; + Produces tableRowPIDTr; + Produces tableRowPIDHe; + Produces tableRowMC; + // Produces tableRowMCExtra; Filter eventFilter = (applyEvSel.node() == 0) || ((applyEvSel.node() == 1) && (aod::evsel::sel7 == true)) || @@ -95,16 +120,18 @@ struct singleTrackSelector { Filter pFilter = o2::aod::track::p > _min_P&& o2::aod::track::p < _max_P; Filter etaFilter = nabs(o2::aod::track::eta) < _eta; - Filter dcaFilter = (o2::aod::track::dcaXY <= _dcaXY) && (o2::aod::track::dcaZ <= _dcaZ); + Filter dcaFilter = ((nabs(o2::aod::track::dcaXY) <= _dcaXY) && (nabs(o2::aod::track::dcaZ) <= _dcaZ)) && + ((nabs(o2::aod::track::dcaXY) >= _dcaXYmin) && (nabs(o2::aod::track::dcaZ) >= _dcaZmin)); Filter tofChi2Filter = o2::aod::track::tofChi2 < _maxTofChi2; + ctpRateFetcher mRateFetcher; // inspired by zdcSP.cxx in PWGLF int mRunNumber = 0; float d_bz = 0.f; std::vector particlesToKeep; std::vector particlesToReject; - HistogramRegistry registry{"registry"}; + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; SliceCache cache; void init(InitContext&) @@ -113,17 +140,30 @@ struct singleTrackSelector { particlesToKeep = _particlesToKeep; particlesToReject = _particlesToReject; + if (applySkimming) { + zorroSummary.setObject(zorro.getZorroSummary()); + } ccdb->setURL(ccdburl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); + registry.add("hNEvents", "hNEvents", {HistType::kTH1D, {{2, 0.f, 2.f}}}); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(1, "All"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(2, "Skimmed"); + + registry.add("hNTracks", "hNTracks", {HistType::kTH1D, {{2, 0.f, 2.f}}}); + registry.get(HIST("hNTracks"))->GetXaxis()->SetBinLabel(1, "All"); + registry.get(HIST("hNTracks"))->GetXaxis()->SetBinLabel(2, "Selected"); + if (enable_gen_info) { registry.add("hNEvents_MCGen", "hNEvents_MCGen", {HistType::kTH1F, {{1, 0.f, 1.f}}}); registry.add("hGen_EtaPhiPt_Proton", "Gen (anti)protons in true collisions", {HistType::kTH3F, {{100, -1., 1., "#eta"}, {157, 0., 2 * TMath::Pi(), "#phi"}, {100, -5.f, 5.f, "p_{T} GeV/c"}}}); registry.add("hGen_EtaPhiPt_Deuteron", "Gen (anti)deuteron in true collisions", {HistType::kTH3F, {{100, -1., 1., "#eta"}, {157, 0., 2 * TMath::Pi(), "#phi"}, {100, -5.f, 5.f, "p_{T} GeV/c"}}}); + registry.add("hGen_EtaPhiPt_Helium3", "Gen (anti)Helium3 in true collisions", {HistType::kTH3F, {{100, -1., 1., "#eta"}, {157, 0., 2 * TMath::Pi(), "#phi"}, {100, -5.f, 5.f, "p_{T} GeV/c"}}}); registry.add("hReco_EtaPhiPt_Proton", "Gen (anti)protons in reco collisions", {HistType::kTH3F, {{100, -1., 1., "#eta"}, {157, 0., 2 * TMath::Pi(), "#phi"}, {100, -5.f, 5.f, "p_{T} GeV/c"}}}); registry.add("hReco_EtaPhiPt_Deuteron", "Gen (anti)deuteron in reco collisions", {HistType::kTH3F, {{100, -1., 1., "#eta"}, {157, 0., 2 * TMath::Pi(), "#phi"}, {100, -5.f, 5.f, "p_{T} GeV/c"}}}); + registry.add("hReco_EtaPhiPt_Helium3", "Gen (anti)Helium3 in reco collisions", {HistType::kTH3F, {{100, -1., 1., "#eta"}, {157, 0., 2 * TMath::Pi(), "#phi"}, {100, -5.f, 5.f, "p_{T} GeV/c"}}}); } } @@ -134,6 +174,11 @@ struct singleTrackSelector { } d_bz = 0.f; + if (applySkimming) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), cfgSkimming.value); + zorro.populateHistRegistry(registry, bc.runNumber()); + } + auto run3grp_timestamp = bc.timestamp(); o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); o2::parameters::GRPMagField* grpmag = 0x0; @@ -156,12 +201,13 @@ struct singleTrackSelector { d_bz = 0.1 * d_bz; } - template - inline void fillTrackTables(Trks const& tracks) + template + inline void fillTrackTables(TracksType const& tracks) { bool skip_track = false; // flag used for track rejection for (auto& track : tracks) { + registry.fill(HIST("hNTracks"), 0.5); if constexpr (isMC) { if (!track.has_mcParticle()) continue; @@ -181,10 +227,11 @@ struct singleTrackSelector { if (skip_track) continue; + registry.fill(HIST("hNTracks"), 1.5); for (auto ii : particlesToKeep) - if (o2::aod::singletrackselector::TPCselection(track, std::make_pair(ii, keepWithinNsigmaTPC))) { - if (track.p() > _pRemoveTofOutOfRange && !o2::aod::singletrackselector::TOFselection(track, std::make_pair(ii, std::vector{-10.0, 10.0}), 10.0)) + if (o2::aod::singletrackselector::TPCselection(track, std::make_pair(ii, keepWithinNsigmaTPC))) { + if (track.p() > _pRemoveTofOutOfRange && !o2::aod::singletrackselector::TOFselection(track, std::make_pair(ii, std::vector{-10.0, 10.0}), std::vector{-10.0, 10.0})) continue; tableRow(tableRowColl.lastIndex(), @@ -194,25 +241,39 @@ struct singleTrackSelector { track.sign(), track.tpcNClsFound(), track.tpcNClsShared(), - track.itsNCls(), - singletrackselector::packInTable(track.dcaXY()), - singletrackselector::packInTable(track.dcaZ()), + track.itsClusterMap(), + track.itsClusterSizes(), + singletrackselector::packSymmetric(track.dcaXY()), + singletrackselector::packSymmetric(track.dcaZ()), singletrackselector::packInTable(track.tpcChi2NCl()), singletrackselector::packInTable(track.itsChi2NCl()), - singletrackselector::packInTable(track.tpcCrossedRowsOverFindableCls()), - singletrackselector::packInTable(track.tofNSigmaPi()), - singletrackselector::packInTable(track.tpcNSigmaPi()), - singletrackselector::packInTable(track.tofNSigmaKa()), - singletrackselector::packInTable(track.tpcNSigmaKa()), - singletrackselector::packInTable(track.tofNSigmaPr()), - singletrackselector::packInTable(track.tpcNSigmaPr()), - singletrackselector::packInTable(track.tofNSigmaDe()), - singletrackselector::packInTable(track.tpcNSigmaDe())); + singletrackselector::packInTable(track.tpcCrossedRowsOverFindableCls())); tableRowExtra(track.tpcInnerParam(), track.tpcSignal(), track.beta()); + tableRowPIDEl(singletrackselector::packSymmetric(track.tofNSigmaEl()), + singletrackselector::packSymmetric(track.tpcNSigmaEl())); + + tableRowPIDPi(singletrackselector::packSymmetric(track.tofNSigmaPi()), + singletrackselector::packSymmetric(track.tpcNSigmaPi())); + + tableRowPIDKa(singletrackselector::packSymmetric(track.tofNSigmaKa()), + singletrackselector::packSymmetric(track.tpcNSigmaKa())); + + tableRowPIDPr(singletrackselector::packSymmetric(track.tofNSigmaPr()), + singletrackselector::packSymmetric(track.tpcNSigmaPr())); + + tableRowPIDDe(singletrackselector::packSymmetric(track.tofNSigmaDe()), + singletrackselector::packSymmetric(track.tpcNSigmaDe())); + + tableRowPIDTr(singletrackselector::packSymmetric(track.tofNSigmaTr()), + singletrackselector::packSymmetric(track.tpcNSigmaTr())); + + tableRowPIDHe(singletrackselector::packSymmetric(track.tofNSigmaHe()), + singletrackselector::packSymmetric(track.tpcNSigmaHe())); + if constexpr (isMC) { int origin = -1; if (track.mcParticle().isPhysicalPrimary()) { @@ -232,14 +293,21 @@ struct singleTrackSelector { track.mcParticle().p(), track.mcParticle().eta(), track.mcParticle().phi()); + + // tableRowMCExtra(track.mcParticle().vx(), + // track.mcParticle().vy(), + // track.mcParticle().vz()); } break; // break the loop with particlesToKeep after the 'if' condition is satisfied -- don't want double entries } } } - void processDataRun2(soa::Filtered::iterator const& collision, soa::Filtered const& tracks, aod::BCsWithTimestamps const&) + void processDataRun2(soa::Filtered::iterator const& collision, + soa::Filtered const& tracks, + aod::BCsWithTimestamps const&) { + auto bc = collision.bc_as(); initCCDB(bc); @@ -273,11 +341,28 @@ struct singleTrackSelector { } PROCESS_SWITCH(singleTrackSelector, processDataRun2, "process data Run2", false); - void processDataRun3(soa::Filtered::iterator const& collision, soa::Filtered const& tracks, aod::BCsWithTimestamps const&) + void processDataRun3(soa::Filtered::iterator const& collision, + soa::Filtered const& tracks, + aod::BCsWithTimestamps const&) { - auto bc = collision.bc_as(); + + const auto& bc = collision.bc_as(); initCCDB(bc); + registry.fill(HIST("hNEvents"), 0.5); + if (applySkimming) { + if (!zorro.isSelected(bc.globalBC())) { + return; + } + } + registry.fill(HIST("hNEvents"), 1.5); + + double hadronicRate = 0.; + if (fetchRate) { + hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), mRunNumber, "ZNC hadronic") * 1.e-3; // fetch IR + } + int occupancy = collision.trackOccupancyInTimeRange(); + float centValue = -100.0f; switch (centTableToUse) { @@ -326,17 +411,20 @@ struct singleTrackSelector { collision.posZ(), d_bz); - tableRowCollExtra(collision.selection_bit(aod::evsel::kNoSameBunchPileup), - collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV), - collision.selection_bit(aod::evsel::kIsVertexITSTPC)); + tableRowCollExtra(collision.selection_raw(), + hadronicRate, + occupancy); fillTrackTables(tracks); } } PROCESS_SWITCH(singleTrackSelector, processDataRun3, "process data Run3", true); - void processMCRun2(soa::Filtered::iterator const& collision, soa::Filtered> const& tracks, aod::McParticles const&, aod::BCsWithTimestamps const&) + void processMCRun2(soa::Filtered::iterator const& collision, + soa::Filtered> const& tracks, + aod::McParticles const&, aod::BCsWithTimestamps const&) { + auto bc = collision.bc_as(); initCCDB(bc); @@ -369,10 +457,19 @@ struct singleTrackSelector { } PROCESS_SWITCH(singleTrackSelector, processMCRun2, "process MC Run2", false); - void processMCRun3(soa::Filtered::iterator const& collision, aod::McCollisions const&, soa::Filtered> const& tracks, aod::McParticles const& mcParticles, aod::BCsWithTimestamps const&) + void processMCRun3(soa::Filtered::iterator const& collision, aod::McCollisions const&, + soa::Filtered> const& tracks, + aod::McParticles const& mcParticles, + aod::BCsWithTimestamps const&) { + auto bc = collision.bc_as(); initCCDB(bc); + double hadronicRate = 0.; + if (fetchRate) { + hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), mRunNumber, "ZNC hadronic") * 1.e-3; // fetch IR + } + int occupancy = collision.trackOccupancyInTimeRange(); float centValue = -100.0f; @@ -423,9 +520,9 @@ struct singleTrackSelector { collision.posZ(), d_bz); - tableRowCollExtra(collision.selection_bit(aod::evsel::kNoSameBunchPileup), - collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV), - collision.selection_bit(aod::evsel::kIsVertexITSTPC)); + tableRowCollExtra(collision.selection_raw(), + hadronicRate, + occupancy); fillTrackTables(tracks); @@ -452,6 +549,12 @@ struct singleTrackSelector { } else if (mcParticle.pdgCode() == -2212) { registry.fill(HIST("hReco_EtaPhiPt_Proton"), mcParticle.eta(), mcParticle.phi(), mcParticle.pt() * -1); } + + if (mcParticle.pdgCode() == 1000020030) { + registry.fill(HIST("hReco_EtaPhiPt_Helium3"), mcParticle.eta(), mcParticle.phi(), mcParticle.pt()); + } else if (mcParticle.pdgCode() == -1000020030) { + registry.fill(HIST("hReco_EtaPhiPt_Helium3"), mcParticle.eta(), mcParticle.phi(), mcParticle.pt() * -1); + } } } } @@ -464,7 +567,7 @@ struct singleTrackSelector { return; } - if (abs(mcCollision.posZ()) > _vertexZ) { + if (std::fabs(mcCollision.posZ()) > _vertexZ) { return; } @@ -486,6 +589,12 @@ struct singleTrackSelector { } else if (mcParticle.pdgCode() == -2212) { registry.fill(HIST("hGen_EtaPhiPt_Proton"), mcParticle.eta(), mcParticle.phi(), mcParticle.pt() * -1); } + + if (mcParticle.pdgCode() == 1000020030) { + registry.fill(HIST("hGen_EtaPhiPt_Helium3"), mcParticle.eta(), mcParticle.phi(), mcParticle.pt()); + } else if (mcParticle.pdgCode() == -1000020030) { + registry.fill(HIST("hGen_EtaPhiPt_Helium3"), mcParticle.eta(), mcParticle.phi(), mcParticle.pt() * -1); + } } } PROCESS_SWITCH(singleTrackSelector, processGenRun3, "process MC Gen collisions Run3", false); diff --git a/PWGCF/Femto3D/TableProducer/singleTrackSelectorExtra.cxx b/PWGCF/Femto3D/TableProducer/singleTrackSelectorExtra.cxx old mode 100755 new mode 100644 index eec6197c98f..0f065371ca8 --- a/PWGCF/Femto3D/TableProducer/singleTrackSelectorExtra.cxx +++ b/PWGCF/Femto3D/TableProducer/singleTrackSelectorExtra.cxx @@ -36,9 +36,10 @@ struct singleTrackSelectorDummy { void process(aod::SingleCollSels::iterator const&) { - tableRowCollExtra(true, - true, - true); + uint64_t selection = 0; + tableRowCollExtra(selection, + 0.0, + 0); } }; diff --git a/PWGCF/Femto3D/TableProducer/singleTrackSelectorPIDMaker.cxx b/PWGCF/Femto3D/TableProducer/singleTrackSelectorPIDMaker.cxx new file mode 100644 index 00000000000..ebdc786469b --- /dev/null +++ b/PWGCF/Femto3D/TableProducer/singleTrackSelectorPIDMaker.cxx @@ -0,0 +1,165 @@ +// 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 singleTrackSelectorPIDMaker.cxx +/// \brief creates dummy tables for PID columns that are not in the derived data +/// \author Sofia Tomassini, Gleb Romanenko, Nicolò Jacazio +/// \since 22 January 2025 + +#include +#include + +#include +#include +#include + +#include "PWGCF/Femto3D/DataModel/singletrackselector.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::track; +using namespace o2::aod; +//::singletrackselector; // the namespace defined in .h + +struct StPidEl { + Produces table; + void process(o2::aod::SingleTrackSels const& tracks) + { + table.reserve(tracks.size()); + for (int i = 0; i < tracks.size(); i++) { + table(singletrackselector::binning::nsigma::underflowBin, + singletrackselector::binning::nsigma::underflowBin); + } + } +}; +struct StPidPi { + Produces table; + void process(o2::aod::SingleTrackSels const& tracks) + { + table.reserve(tracks.size()); + for (int i = 0; i < tracks.size(); i++) { + table(singletrackselector::binning::nsigma::underflowBin, + singletrackselector::binning::nsigma::underflowBin); + } + } +}; +struct StPidKa { + Produces table; + void process(o2::aod::SingleTrackSels const& tracks) + { + table.reserve(tracks.size()); + for (int i = 0; i < tracks.size(); i++) { + table(singletrackselector::binning::nsigma::underflowBin, + singletrackselector::binning::nsigma::underflowBin); + } + } +}; +struct StPidPr { + Produces table; + void process(o2::aod::SingleTrackSels const& tracks) + { + table.reserve(tracks.size()); + for (int i = 0; i < tracks.size(); i++) { + table(singletrackselector::binning::nsigma::underflowBin, + singletrackselector::binning::nsigma::underflowBin); + } + } +}; +struct StPidDe { + Produces table; + void process(o2::aod::SingleTrackSels const& tracks) + { + table.reserve(tracks.size()); + for (int i = 0; i < tracks.size(); i++) { + table(singletrackselector::binning::nsigma::underflowBin, + singletrackselector::binning::nsigma::underflowBin); + } + } +}; + +struct StPidTr { + Produces table; + void process(o2::aod::SingleTrackSels const& tracks) + { + table.reserve(tracks.size()); + for (int i = 0; i < tracks.size(); i++) { + table(singletrackselector::binning::nsigma::underflowBin, + singletrackselector::binning::nsigma::underflowBin); + } + } +}; + +struct StPidHe { + Produces table; + void process(o2::aod::SingleTrackSels const& tracks) + { + table.reserve(tracks.size()); + for (int i = 0; i < tracks.size(); i++) { + table(singletrackselector::binning::nsigma::underflowBin, + singletrackselector::binning::nsigma::underflowBin); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + auto workflow = WorkflowSpec{}; + + // Check if 'aod-metadata-tables' option is available in the config context + if (cfgc.options().hasOption("aod-metadata-tables")) { + const std::vector tables = cfgc.options().get>("aod-metadata-tables"); + + // Map of table names to their corresponding converter task functions + std::unordered_map>> tableToTasks = { + {"O2singlepidel", {[&]() { workflow.push_back(adaptAnalysisTask(cfgc)); }}}, + {"O2singlepidpi", {[&]() { workflow.push_back(adaptAnalysisTask(cfgc)); }}}, + {"O2singlepidka", {[&]() { workflow.push_back(adaptAnalysisTask(cfgc)); }}}, + {"O2singlepidpr", {[&]() { workflow.push_back(adaptAnalysisTask(cfgc)); }}}, + {"O2singlepidde", {[&]() { workflow.push_back(adaptAnalysisTask(cfgc)); }}}, + {"O2singlepidtr", {[&]() { workflow.push_back(adaptAnalysisTask(cfgc)); }}}, + {"O2singlepidhe", {[&]() { workflow.push_back(adaptAnalysisTask(cfgc)); }}}}; + + for (auto const& tableInWorkflow : tables) { + LOG(info) << tableInWorkflow; + } + + // Iterate through the tables and process based on the mapping + for (auto const& table : tableToTasks) { + bool foundIt = false; + for (auto const& tableInWorkflow : tables) { + if (tableInWorkflow == table.first) { + foundIt = true; + break; + } + } + if (foundIt) + continue; + for (auto const& task : table.second) { + LOG(info) << "Adding task " << table.first; + task(); + } + } + } else { + LOG(warning) << "AOD converter: No tables found in the meta data. Adding all workflows"; + workflow.push_back(adaptAnalysisTask(cfgc)); + workflow.push_back(adaptAnalysisTask(cfgc)); + workflow.push_back(adaptAnalysisTask(cfgc)); + workflow.push_back(adaptAnalysisTask(cfgc)); + workflow.push_back(adaptAnalysisTask(cfgc)); + workflow.push_back(adaptAnalysisTask(cfgc)); + workflow.push_back(adaptAnalysisTask(cfgc)); + } + return workflow; +} diff --git a/PWGCF/Femto3D/Tasks/CMakeLists.txt b/PWGCF/Femto3D/Tasks/CMakeLists.txt old mode 100755 new mode 100644 index a0338dce678..62a7b310690 --- a/PWGCF/Femto3D/Tasks/CMakeLists.txt +++ b/PWGCF/Femto3D/Tasks/CMakeLists.txt @@ -10,16 +10,16 @@ # or submit itself to any jurisdiction. o2physics_add_dpl_workflow(femto3d-qa - SOURCES femto3dQA.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore - COMPONENT_NAME Analysis) + SOURCES femto3dQA.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(femto3d-pair-task - SOURCES femto3dPairTask.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore - COMPONENT_NAME Analysis) + SOURCES femto3dPairTask.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(femto3d-pair-task-mc - SOURCES femto3dPairTaskMC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore - COMPONENT_NAME Analysis) \ No newline at end of file + SOURCES femto3dPairTaskMC.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) \ No newline at end of file diff --git a/PWGCF/Femto3D/Tasks/femto3dPairTask.cxx b/PWGCF/Femto3D/Tasks/femto3dPairTask.cxx old mode 100755 new mode 100644 index 6d9fd003c1b..bc91f8a25c2 --- a/PWGCF/Femto3D/Tasks/femto3dPairTask.cxx +++ b/PWGCF/Femto3D/Tasks/femto3dPairTask.cxx @@ -18,6 +18,9 @@ #include #include #include +#include +#include +#include #include #include @@ -50,12 +53,16 @@ struct FemtoCorrelations { Configurable _removeSameBunchPileup{"removeSameBunchPileup", false, ""}; Configurable _requestGoodZvtxFT0vsPV{"requestGoodZvtxFT0vsPV", false, ""}; Configurable _requestVertexITSTPC{"requestVertexITSTPC", false, ""}; + Configurable _requestVertexTOForTRDmatched{"requestVertexTOFmatched", 0, "0 -> no selectio; 1 -> vertex is matched to TOF or TRD; 2 -> matched to both;"}; + Configurable _requestNoCollInTimeRangeStandard{"requestNoCollInTimeRangeStandard", false, ""}; + Configurable> _IRcut{"IRcut", std::pair{0.f, 100.f}, "[min., max.] IR range to keep events within"}; + Configurable> _OccupancyCut{"OccupancyCut", std::pair{0, 10000}, "[min., max.] occupancy range to keep events within"}; Configurable _min_P{"min_P", 0.0, "lower mometum limit"}; Configurable _max_P{"max_P", 100.0, "upper mometum limit"}; Configurable _eta{"eta", 100.0, "abs eta value limit"}; - Configurable _dcaXY{"dcaXY", 10.0, "abs dcaXY value limit"}; - Configurable _dcaZ{"dcaZ", 10.0, "abs dcaZ value limit"}; + Configurable> _dcaXY{"dcaXY", std::vector{0.3f, 0.0f, 0.0f}, "abs dcaXY value limit; formula: [0] + [1]*pT^[2]"}; + Configurable> _dcaZ{"dcaZ", std::vector{0.3f, 0.0f, 0.0f}, "abs dcaZ value limit; formula: [0] + [1]*pT^[2]"}; Configurable _tpcNClsFound{"minTpcNClsFound", 0, "minimum allowed number of TPC clasters"}; Configurable _tpcChi2NCl{"tpcChi2NCl", 100.0, "upper limit for chi2 value of a fit over TPC clasters"}; Configurable _tpcCrossedRowsOverFindableCls{"tpcCrossedRowsOverFindableCls", 0, "lower limit of TPC CrossedRows/FindableCls value"}; @@ -67,23 +74,26 @@ struct FemtoCorrelations { Configurable _sign_1{"sign_1", 1, "sign of the first particle in a pair"}; Configurable _particlePDG_1{"particlePDG_1", 2212, "PDG code of the first particle in a pair to perform PID for (only pion, kaon, proton and deurton are supported now)"}; Configurable> _tpcNSigma_1{"tpcNSigma_1", std::vector{-3.0f, 3.0f}, "first particle PID: Nsigma range in TPC before the TOF is used"}; + Configurable> _itsNSigma_1{"itsNSigma_1", std::vector{-10.0f, 10.0f}, "first particle PID: Nsigma range in ITS with TPC is used"}; Configurable _PIDtrshld_1{"PIDtrshld_1", 10.0, "first particle PID: value of momentum from which the PID is done with TOF (before that only TPC is used)"}; Configurable> _tofNSigma_1{"tofNSigma_1", std::vector{-3.0f, 3.0f}, "first particle PID: Nsigma range in TOF"}; - Configurable _tpcNSigmaResidual_1{"tpcNSigmaResidual_1", 5, "first particle PID: residual TPC Nsigma cut (abs. value) to use with the TOF"}; + Configurable> _tpcNSigmaResidual_1{"tpcNSigmaResidual_1", std::vector{-5.0f, 5.0f}, "first particle PID: residual TPC Nsigma cut to use with the TOF"}; Configurable _sign_2{"sign_2", 1, "sign of the second particle in a pair"}; Configurable _particlePDG_2{"particlePDG_2", 2212, "PDG code of the second particle in a pair to perform PID for (only pion, kaon, proton and deurton are supported now)"}; Configurable> _tpcNSigma_2{"tpcNSigma_2", std::vector{-3.0f, 3.0f}, "second particle PID: Nsigma range in TPC before the TOF is used"}; + Configurable> _itsNSigma_2{"itsNSigma_2", std::vector{-10.0f, 10.0f}, "first particle PID: Nsigma range in ITS with TPC is used"}; Configurable _PIDtrshld_2{"PIDtrshld_2", 10.0, "second particle PID: value of momentum from which the PID is done with TOF (before that only TPC is used)"}; Configurable> _tofNSigma_2{"tofNSigma_2", std::vector{-3.0f, 3.0f}, "second particle PID: Nsigma range in TOF"}; - Configurable _tpcNSigmaResidual_2{"tpcNSigmaResidual_2", 5, "second particle PID: residual TPC Nsigma cut (abs. value) to use with the TOF"}; + Configurable> _tpcNSigmaResidual_2{"tpcNSigmaResidual_2", std::vector{-5.0f, 5.0f}, "second particle PID: residual TPC Nsigma cut to use with the TOF"}; Configurable _particlePDGtoReject{"particlePDGtoRejectFromSecond", 0, "applied only if the particles are non-identical and only to the second particle in the pair!!!"}; Configurable> _rejectWithinNsigmaTOF{"rejectWithinNsigmaTOF", std::vector{-0.0f, 0.0f}, "TOF rejection Nsigma range for the particle specified with PDG to be rejected"}; Configurable _deta{"deta", 0.01, "minimum allowed defference in eta between two tracks in a pair"}; Configurable _dphi{"dphi", 0.01, "minimum allowed defference in phi_star between two tracks in a pair"}; - Configurable _radiusTPC{"radiusTPC", 1.2, "TPC radius to calculate phi_star for"}; + // Configurable _radiusTPC{"radiusTPC", 1.2, "TPC radius to calculate phi_star for"}; + Configurable _avgSepTPC{"avgSepTPC", 10, "average sep. (cm) in TPC"}; Configurable _vertexNbinsToMix{"vertexNbinsToMix", 10, "Number of vertexZ bins for the mixing"}; Configurable> _centBins{"multBins", std::vector{0.0f, 100.0f}, "multiplicity percentile/centrality binning (min:0, max:100)"}; @@ -92,7 +102,8 @@ struct FemtoCorrelations { ConfigurableAxis CFkStarBinning{"CFkStarBinning", {500, 0.005, 5.005}, "k* binning of the CF (Nbins, lowlimit, uplimit)"}; Configurable _fill3dCF{"fill3dCF", false, "flag for filling 3D LCMS histos: true -- fill; false -- not"}; - Configurable _fillDetaDphi{"fillDetaDphi", false, "flag for filling dEta(dPhi*) histos: true -- fill; false -- not; note: they're filled before the double track cut"}; + Configurable _fill3dAddHistos{"fill3dAddHistos", 1, "flag for filling additional 3D histos: 0 -- nothing; 1 -- Q_LCMS vs. k*; 2 -- Q_LCMS vs. Gamma_out (currently testing)"}; + Configurable _fillDetaDphi{"fillDetaDphi", -1, "flag for filling dEta(dPhi*) histos: '-1' -- don't fill; '0' -- fill before the cut; '1' -- fill after the cut; '2' -- fill before & after the cut"}; ConfigurableAxis CF3DqLCMSBinning{"CF3DqLCMSBinning", {60, -0.3, 0.3}, "q_out/side/long binning of the CF 3D in LCMS (Nbins, lowlimit, uplimit)"}; // the next configarable is responsible for skipping (pseudo)randomly chosen ($value -1) pairs of events in the mixing process // migth be useful (for the sake of execution time and the output file size ...) in case of too many events per DF since in the SE thacks are mixed in N_ev and in the ME 0.5*N_ev*(N_ev - 1) @@ -112,7 +123,8 @@ struct FemtoCorrelations { std::pair> TOFcuts_2; using FilteredCollisions = soa::Join; - using FilteredTracks = aod::SingleTrackSels; + // using FilteredTracks = soa::Join; // main + using FilteredTracks = soa::Join; // tmp solution till the HL is fixed typedef std::shared_ptr::iterator> trkType; typedef std::shared_ptr::iterator> colType; @@ -130,13 +142,20 @@ struct FemtoCorrelations { o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedTpcChi2NCl) < _tpcChi2NCl && o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedTpcCrossedRowsOverFindableCls) > _tpcCrossedRowsOverFindableCls; - Filter dcaFilter = nabs(o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedDcaXY)) < _dcaXY && - nabs(o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedDcaZ)) < _dcaZ; - Filter itsTrkFilter = o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedItsChi2NCl) < _itsChi2NCl; Filter vertexFilter = nabs(o2::aod::singletrackselector::posZ) < _vertexZ; + std::shared_ptr pHisto_first; // momentum histogram for the first particle + std::shared_ptr ITShisto_first; + std::shared_ptr TPChisto_first; + std::shared_ptr TOFhisto_first; + + std::shared_ptr pHisto_second; // momentum histogram for the second particle + std::shared_ptr ITShisto_second; + std::shared_ptr TPChisto_second; + std::shared_ptr TOFhisto_second; + std::vector> MultHistos; std::vector>> kThistos; std::vector>> mThistos; // test @@ -145,10 +164,13 @@ struct FemtoCorrelations { std::vector>> SEhistos_3D; std::vector>> MEhistos_3D; - std::vector>> qLCMSvskStar; + std::vector>> Add3dHistos; - std::vector>> DoubleTrack_SE_histos; - std::vector>> DoubleTrack_ME_histos; + std::vector>> DoubleTrack_SE_histos_BC; // BC -- before cutting + std::vector>> DoubleTrack_ME_histos_BC; // BC -- before cutting + + std::vector>> DoubleTrack_SE_histos_AC; // AC -- after cutting + std::vector>> DoubleTrack_ME_histos_AC; // AC -- after cutting void init(o2::framework::InitContext&) { @@ -199,44 +221,68 @@ struct FemtoCorrelations { if (_fill3dCF) { std::vector> SEperMult_3D; std::vector> MEperMult_3D; - std::vector> qLCMSvskStarperMult; + std::vector> Add3dHistosperMult; for (unsigned int j = 0; j < _kTbins.value.size() - 1; j++) { auto hSE_3D = registry.add(Form("Cent%i/SE_3D_cent%i_kT%i", i, i, j), Form("SE_3D_cent%i_kT%i", i, j), kTH3F, {{CF3DqLCMSBinning, "q_out (GeV/c)"}, {CF3DqLCMSBinning, "q_side (GeV/c)"}, {CF3DqLCMSBinning, "q_long (GeV/c)"}}); auto hME_3D = registry.add(Form("Cent%i/ME_3D_cent%i_kT%i", i, i, j), Form("ME_3D_cent%i_kT%i", i, j), kTH3F, {{CF3DqLCMSBinning, "q_out (GeV/c)"}, {CF3DqLCMSBinning, "q_side (GeV/c)"}, {CF3DqLCMSBinning, "q_long (GeV/c)"}}); - auto hqLCMSvskStar = registry.add(Form("Cent%i/qLCMSvskStar_cent%i_kT%i", i, i, j), Form("qLCMSvskStar_cent%i_kT%i", i, j), kTH3F, {{CF3DqLCMSBinning, "q_out (GeV/c)"}, {CF3DqLCMSBinning, "q_side (GeV/c)"}, {CF3DqLCMSBinning, "q_long (GeV/c)"}}); SEperMult_3D.push_back(std::move(hSE_3D)); MEperMult_3D.push_back(std::move(hME_3D)); - qLCMSvskStarperMult.push_back(std::move(hqLCMSvskStar)); + + if (_fill3dAddHistos == 1) { + auto hAdd3dHistos = registry.add(Form("Cent%i/qLCMSvskStar_cent%i_kT%i", i, i, j), Form("qLCMSvskStar_cent%i_kT%i", i, j), kTH3F, {{CF3DqLCMSBinning, "q_out (GeV/c)"}, {CF3DqLCMSBinning, "q_side (GeV/c)"}, {CF3DqLCMSBinning, "q_long (GeV/c)"}}); + Add3dHistosperMult.push_back(std::move(hAdd3dHistos)); + } else if (_fill3dAddHistos == 2) { + auto hAdd3dHistos = registry.add(Form("Cent%i/qLCMSvsGout_cent%i_kT%i", i, i, j), Form("qLCMSvsGout_cent%i_kT%i", i, j), kTH3F, {{CF3DqLCMSBinning, "q_out (GeV/c)"}, {CF3DqLCMSBinning, "q_side (GeV/c)"}, {CF3DqLCMSBinning, "q_long (GeV/c)"}}); + Add3dHistosperMult.push_back(std::move(hAdd3dHistos)); + } } SEhistos_3D.push_back(std::move(SEperMult_3D)); MEhistos_3D.push_back(std::move(MEperMult_3D)); - qLCMSvskStar.push_back(std::move(qLCMSvskStarperMult)); + if (_fill3dAddHistos != 0) + Add3dHistos.push_back(std::move(Add3dHistosperMult)); } - if (_fillDetaDphi) { - std::vector> DoubleTrack_SE_histos_perMult; - std::vector> DoubleTrack_ME_histos_perMult; + if (_fillDetaDphi > -1) { + TString suffix[] = {"_nocut", "_cut"}; - for (unsigned int j = 0; j < _kTbins.value.size() - 1; j++) { - auto hDblTrk_SE = registry.add(Form("Cent%i/DoubleTrackEffects_SE_cent%i_kT%i", i, i, j), Form("DoubleTrackEffects_deta(dphi*)_SE_cent%i_kT%i", i, j), kTH2F, {{600, -M_PI, M_PI, "dphi*"}, {200, -0.5, 0.5, "deta"}}); - auto hDblTrk_ME = registry.add(Form("Cent%i/DoubleTrackEffects_ME_cent%i_kT%i", i, i, j), Form("DoubleTrackEffects_deta(dphi*)_ME_cent%i_kT%i", i, j), kTH2F, {{600, -M_PI, M_PI, "dphi*"}, {200, -0.5, 0.5, "deta"}}); + for (int f = 0; f < 2; f++) { + std::vector> DoubleTrack_SE_histos_perMult; + std::vector> DoubleTrack_ME_histos_perMult; + + if (_fillDetaDphi == 0 && f == 1) + continue; + if (_fillDetaDphi == 1 && f == 0) + continue; - DoubleTrack_SE_histos_perMult.push_back(std::move(hDblTrk_SE)); - DoubleTrack_ME_histos_perMult.push_back(std::move(hDblTrk_ME)); + for (unsigned int j = 0; j < _kTbins.value.size() - 1; j++) { + auto hDblTrk_SE = registry.add(Form("Cent%i/DoubleTrackEffects/SE_cent%i_kT%i", i, i, j) + suffix[f], Form("DoubleTrackEffects_deta(dphi*)_SE_cent%i_kT%i", i, j) + suffix[f], kTH2F, {{101, -0.2, 0.2, "dphi*"}, {101, -0.2, 0.2, "deta"}}); + auto hDblTrk_ME = registry.add(Form("Cent%i/DoubleTrackEffects/ME_cent%i_kT%i", i, i, j) + suffix[f], Form("DoubleTrackEffects_deta(dphi*)_ME_cent%i_kT%i", i, j) + suffix[f], kTH2F, {{101, -0.2, 0.2, "dphi*"}, {101, -0.2, 0.2, "deta"}}); + + DoubleTrack_SE_histos_perMult.push_back(std::move(hDblTrk_SE)); + DoubleTrack_ME_histos_perMult.push_back(std::move(hDblTrk_ME)); + } + if (f == 0) { + DoubleTrack_SE_histos_BC.push_back(std::move(DoubleTrack_SE_histos_perMult)); // BC -- before cutting + DoubleTrack_ME_histos_BC.push_back(std::move(DoubleTrack_ME_histos_perMult)); + } else { + DoubleTrack_SE_histos_AC.push_back(std::move(DoubleTrack_SE_histos_perMult)); // AC -- after cutting + DoubleTrack_ME_histos_AC.push_back(std::move(DoubleTrack_ME_histos_perMult)); + } } - DoubleTrack_SE_histos.push_back(std::move(DoubleTrack_SE_histos_perMult)); - DoubleTrack_ME_histos.push_back(std::move(DoubleTrack_ME_histos_perMult)); } } - registry.add("p_first", Form("p_%i", static_cast(_particlePDG_1)), kTH1F, {{100, 0., 5., "p"}}); - registry.add("nsigmaTOF_first", Form("nsigmaTOF_%i", static_cast(_particlePDG_1)), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); - registry.add("nsigmaTPC_first", Form("nsigmaTPC_%i", static_cast(_particlePDG_1)), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); + pHisto_first = registry.add(Form("p_%i", _particlePDG_1.value), Form("p_%i", _particlePDG_1.value), kTH1F, {{100, 0., 5., "p"}}); + ITShisto_first = registry.add(Form("nsigmaITS_PDG%i", _particlePDG_1.value), Form("nsigmaITS_PDG%i", _particlePDG_1.value), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); + TPChisto_first = registry.add(Form("nsigmaTPC_PDG%i", _particlePDG_1.value), Form("nsigmaTPC_PDG%i", _particlePDG_1.value), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); + TOFhisto_first = registry.add(Form("nsigmaTOF_PDG%i", _particlePDG_1.value), Form("nsigmaTOF_PDG%i", _particlePDG_1.value), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); + if (!IsIdentical) { - registry.add("p_second", Form("p_%i", static_cast(_particlePDG_2)), kTH1F, {{100, 0., 5., "p"}}); - registry.add("nsigmaTOF_second", Form("nsigmaTOF_%i", static_cast(_particlePDG_2)), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); - registry.add("nsigmaTPC_second", Form("nsigmaTPC_%i", static_cast(_particlePDG_2)), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); + pHisto_second = registry.add(Form("p_%i", _particlePDG_2.value), Form("p_%i", _particlePDG_2.value), kTH1F, {{100, 0., 5., "p"}}); + ITShisto_second = registry.add(Form("nsigmaITS_PDG%i", _particlePDG_2.value), Form("nsigmaITS_PDG%i", _particlePDG_2.value), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); + TPChisto_second = registry.add(Form("nsigmaTPC_PDG%i", _particlePDG_2.value), Form("nsigmaTPC_PDG%i", _particlePDG_2.value), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); + TOFhisto_second = registry.add(Form("nsigmaTOF_PDG%i", _particlePDG_2.value), Form("nsigmaTOF_PDG%i", _particlePDG_2.value), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); } } @@ -263,10 +309,16 @@ struct FemtoCorrelations { if (_fill3dCF && kTbin > SEhistos_3D[multBin].size()) LOGF(fatal, "kTbin value obtained for a pair exceeds the configured number of kT bins (3D)"); - if (_fillDetaDphi) - DoubleTrack_SE_histos[multBin][kTbin]->Fill(Pair->GetPhiStarDiff(_radiusTPC), Pair->GetEtaDiff()); - if (Pair->IsClosePair(_deta, _dphi, _radiusTPC)) + if (_fillDetaDphi % 2 == 0) + DoubleTrack_SE_histos_BC[multBin][kTbin]->Fill(Pair->GetAvgPhiStarDiff(), Pair->GetEtaDiff()); + + if (_deta > 0 && _dphi > 0 && Pair->IsClosePair(_deta, _dphi)) continue; + if (_avgSepTPC > 0 && Pair->IsClosePair(_avgSepTPC)) + continue; + + if (_fillDetaDphi > 0) + DoubleTrack_SE_histos_AC[multBin][kTbin]->Fill(Pair->GetAvgPhiStarDiff(), Pair->GetEtaDiff()); kThistos[multBin][kTbin]->Fill(pair_kT); mThistos[multBin][kTbin]->Fill(Pair->GetMt()); // test @@ -305,16 +357,25 @@ struct FemtoCorrelations { if (_fill3dCF && kTbin > SEhistos_3D[multBin].size()) LOGF(fatal, "kTbin value obtained for a pair exceeds the configured number of kT bins (3D)"); - if (_fillDetaDphi) { + if (_fillDetaDphi % 2 == 0) { if (!SE_or_ME) - DoubleTrack_SE_histos[multBin][kTbin]->Fill(Pair->GetPhiStarDiff(_radiusTPC), Pair->GetEtaDiff()); + DoubleTrack_SE_histos_BC[multBin][kTbin]->Fill(Pair->GetAvgPhiStarDiff(), Pair->GetEtaDiff()); else - DoubleTrack_ME_histos[multBin][kTbin]->Fill(Pair->GetPhiStarDiff(_radiusTPC), Pair->GetEtaDiff()); + DoubleTrack_ME_histos_BC[multBin][kTbin]->Fill(Pair->GetAvgPhiStarDiff(), Pair->GetEtaDiff()); } - if (Pair->IsClosePair(_deta, _dphi, _radiusTPC)) + if (_deta > 0 && _dphi > 0 && Pair->IsClosePair(_deta, _dphi)) + continue; + if (_avgSepTPC > 0 && Pair->IsClosePair(_avgSepTPC)) continue; + if (_fillDetaDphi > 0) { + if (!SE_or_ME) + DoubleTrack_SE_histos_AC[multBin][kTbin]->Fill(Pair->GetAvgPhiStarDiff(), Pair->GetEtaDiff()); + else + DoubleTrack_ME_histos_AC[multBin][kTbin]->Fill(Pair->GetAvgPhiStarDiff(), Pair->GetEtaDiff()); + } + if (!SE_or_ME) { SEhistos_1D[multBin][kTbin]->Fill(Pair->GetKstar()); kThistos[multBin][kTbin]->Fill(pair_kT); @@ -332,7 +393,10 @@ struct FemtoCorrelations { std::mt19937 mt(std::chrono::steady_clock::now().time_since_epoch().count()); TVector3 qLCMS = std::pow(-1, (mt() % 2)) * Pair->GetQLCMS(); // introducing randomness to the pair order ([first, second]); important only for 3D because if there are any sudden order/correlation in the tables, it could couse unwanted asymmetries in the final 3d rel. momentum distributions; irrelevant in 1D case because the absolute value of the rel.momentum is taken MEhistos_3D[multBin][kTbin]->Fill(qLCMS.X(), qLCMS.Y(), qLCMS.Z()); - qLCMSvskStar[multBin][kTbin]->Fill(qLCMS.X(), qLCMS.Y(), qLCMS.Z(), Pair->GetKstar()); + if (_fill3dAddHistos == 1) + Add3dHistos[multBin][kTbin]->Fill(qLCMS.X(), qLCMS.Y(), qLCMS.Z(), Pair->GetKstar()); + else if (_fill3dAddHistos == 2) + Add3dHistos[multBin][kTbin]->Fill(qLCMS.X(), qLCMS.Y(), qLCMS.Z(), Pair->GetGammaOut()); } } Pair->ResetPair(); @@ -345,8 +409,8 @@ struct FemtoCorrelations { if (_particlePDG_1 == 0 || _particlePDG_2 == 0) LOGF(fatal, "One of passed PDG is 0!!!"); - for (auto track : tracks) { - if (abs(track.template singleCollSel_as>().posZ()) > _vertexZ) + for (const auto& track : tracks) { + if (std::fabs(track.template singleCollSel_as>().posZ()) > _vertexZ) continue; if (_removeSameBunchPileup && !track.template singleCollSel_as>().isNoSameBunchPileup()) continue; @@ -354,61 +418,49 @@ struct FemtoCorrelations { continue; if (_requestVertexITSTPC && !track.template singleCollSel_as>().isVertexITSTPC()) continue; + if (_requestVertexTOForTRDmatched > track.template singleCollSel_as>().isVertexTOForTRDmatched()) + continue; + if (_requestNoCollInTimeRangeStandard && !track.template singleCollSel_as>().noCollInTimeRangeStandard()) + continue; if (track.tpcFractionSharedCls() > _tpcFractionSharedCls || track.itsNCls() < _itsNCls) continue; if (track.template singleCollSel_as>().multPerc() < *_centBins.value.begin() || track.template singleCollSel_as>().multPerc() >= *(_centBins.value.end() - 1)) continue; + if (track.template singleCollSel_as>().hadronicRate() < _IRcut.value.first || track.template singleCollSel_as>().hadronicRate() >= _IRcut.value.second) + continue; + if (track.template singleCollSel_as>().occupancy() < _OccupancyCut.value.first || track.template singleCollSel_as>().occupancy() >= _OccupancyCut.value.second) + continue; + if (std::fabs(track.dcaXY()) > _dcaXY.value[0] + _dcaXY.value[1] * std::pow(track.pt(), _dcaXY.value[2]) || std::fabs(track.dcaZ()) > _dcaZ.value[0] + _dcaZ.value[1] * std::pow(track.pt(), _dcaZ.value[2])) + continue; - if (track.sign() == _sign_1 && (track.p() < _PIDtrshld_1 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_1) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_1, _tpcNSigmaResidual_1))) { // filling the map: eventID <-> selected particles1 - selectedtracks_1[track.singleCollSelId()].push_back(std::make_shared(track)); + if (track.sign() == _sign_1 && (track.p() < _PIDtrshld_1 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_1, _itsNSigma_1.value) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_1, _tpcNSigmaResidual_1.value))) { // filling the map: eventID <-> selected particles1 + selectedtracks_1[track.singleCollSelId()].push_back(std::make_shared::iterator>(track)); - registry.fill(HIST("p_first"), track.p()); - if (_particlePDG_1 == 211) { - registry.fill(HIST("nsigmaTOF_first"), track.p(), track.tofNSigmaPi()); - registry.fill(HIST("nsigmaTPC_first"), track.p(), track.tpcNSigmaPi()); - } - if (_particlePDG_1 == 321) { - registry.fill(HIST("nsigmaTOF_first"), track.p(), track.tofNSigmaKa()); - registry.fill(HIST("nsigmaTPC_first"), track.p(), track.tpcNSigmaKa()); - } - if (_particlePDG_1 == 2212) { - registry.fill(HIST("nsigmaTOF_first"), track.p(), track.tofNSigmaPr()); - registry.fill(HIST("nsigmaTPC_first"), track.p(), track.tpcNSigmaPr()); - } - if (_particlePDG_1 == 1000010020) { - registry.fill(HIST("nsigmaTOF_first"), track.p(), track.tofNSigmaDe()); - registry.fill(HIST("nsigmaTPC_first"), track.p(), track.tpcNSigmaDe()); - } + pHisto_first->Fill(track.p()); + ITShisto_first->Fill(track.p(), o2::aod::singletrackselector::getITSNsigma(track, _particlePDG_1)); + TPChisto_first->Fill(track.p(), o2::aod::singletrackselector::getTPCNsigma(track, _particlePDG_1)); + TOFhisto_first->Fill(track.p(), o2::aod::singletrackselector::getTOFNsigma(track, _particlePDG_1)); } if (IsIdentical) { continue; - } else if (track.sign() != _sign_2 && !TOFselection(track, std::make_pair(_particlePDGtoReject, _rejectWithinNsigmaTOF)) && (track.p() < _PIDtrshld_2 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_2) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_2, _tpcNSigmaResidual_2))) { // filling the map: eventID <-> selected particles2 if (see condition above ^) - selectedtracks_2[track.singleCollSelId()].push_back(std::make_shared(track)); + } else if (track.sign() != _sign_2 && !TOFselection(track, std::make_pair(_particlePDGtoReject, _rejectWithinNsigmaTOF)) && (track.p() < _PIDtrshld_2 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_2, _itsNSigma_2.value) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_2, _tpcNSigmaResidual_2.value))) { // filling the map: eventID <-> selected particles2 if (see condition above ^) + selectedtracks_2[track.singleCollSelId()].push_back(std::make_shared::iterator>(track)); - registry.fill(HIST("p_second"), track.p()); - if (_particlePDG_2 == 211) { - registry.fill(HIST("nsigmaTOF_second"), track.p(), track.tofNSigmaPi()); - registry.fill(HIST("nsigmaTPC_second"), track.p(), track.tpcNSigmaPi()); - } - if (_particlePDG_2 == 321) { - registry.fill(HIST("nsigmaTOF_second"), track.p(), track.tofNSigmaKa()); - registry.fill(HIST("nsigmaTPC_second"), track.p(), track.tpcNSigmaKa()); - } - if (_particlePDG_2 == 2212) { - registry.fill(HIST("nsigmaTOF_second"), track.p(), track.tofNSigmaPr()); - registry.fill(HIST("nsigmaTPC_second"), track.p(), track.tpcNSigmaPr()); - } - if (_particlePDG_2 == 1000010020) { - registry.fill(HIST("nsigmaTOF_second"), track.p(), track.tofNSigmaDe()); - registry.fill(HIST("nsigmaTPC_second"), track.p(), track.tpcNSigmaDe()); - } + pHisto_second->Fill(track.p()); + ITShisto_second->Fill(track.p(), o2::aod::singletrackselector::getITSNsigma(track, _particlePDG_2)); + TPChisto_second->Fill(track.p(), o2::aod::singletrackselector::getTPCNsigma(track, _particlePDG_2)); + TOFhisto_second->Fill(track.p(), o2::aod::singletrackselector::getTOFNsigma(track, _particlePDG_2)); } } - for (auto collision : collisions) { + for (const auto& collision : collisions) { if (collision.multPerc() < *_centBins.value.begin() || collision.multPerc() >= *(_centBins.value.end() - 1)) continue; + if (collision.hadronicRate() < _IRcut.value.first || collision.hadronicRate() >= _IRcut.value.second) + continue; + if (collision.occupancy() < _OccupancyCut.value.first || collision.occupancy() >= _OccupancyCut.value.second) + continue; if (_removeSameBunchPileup && !collision.isNoSameBunchPileup()) continue; @@ -416,6 +468,10 @@ struct FemtoCorrelations { continue; if (_requestVertexITSTPC && !collision.isVertexITSTPC()) continue; + if (_requestVertexTOForTRDmatched > collision.isVertexTOForTRDmatched()) + continue; + if (_requestNoCollInTimeRangeStandard && !collision.noCollInTimeRangeStandard()) + continue; if (selectedtracks_1.find(collision.globalIndex()) == selectedtracks_1.end()) { if (IsIdentical) @@ -426,7 +482,7 @@ struct FemtoCorrelations { int vertexBinToMix = std::floor((collision.posZ() + _vertexZ) / (2 * _vertexZ / _vertexNbinsToMix)); float centBinToMix = o2::aod::singletrackselector::getBinIndex(collision.multPerc(), _centBins, _multNsubBins); - mixbins[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision)); + mixbins[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared::iterator>(collision)); } //====================================== mixing starts here ====================================== diff --git a/PWGCF/Femto3D/Tasks/femto3dPairTaskMC.cxx b/PWGCF/Femto3D/Tasks/femto3dPairTaskMC.cxx old mode 100755 new mode 100644 index 596c6039933..06635858ce0 --- a/PWGCF/Femto3D/Tasks/femto3dPairTaskMC.cxx +++ b/PWGCF/Femto3D/Tasks/femto3dPairTaskMC.cxx @@ -14,6 +14,9 @@ /// \since 31 May 2023 #include +#include +#include +#include #include #include @@ -43,11 +46,19 @@ struct FemtoCorrelationsMC { /// Construct a registry object with direct declaration HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + Configurable _removeSameBunchPileup{"removeSameBunchPileup", false, ""}; + Configurable _requestGoodZvtxFT0vsPV{"requestGoodZvtxFT0vsPV", false, ""}; + Configurable _requestVertexITSTPC{"requestVertexITSTPC", false, ""}; + Configurable _requestVertexTOForTRDmatched{"requestVertexTOFmatched", 0, "0 -> no selectio; 1 -> vertex is matched to TOF or TRD; 2 -> matched to both;"}; + Configurable _requestNoCollInTimeRangeStandard{"requestNoCollInTimeRangeStandard", false, ""}; + Configurable> _IRcut{"IRcut", std::pair{0.f, 100.f}, "[min., max.] IR range to keep events within"}; + Configurable> _OccupancyCut{"OccupancyCut", std::pair{0, 10000}, "[min., max.] occupancy range to keep events within"}; + Configurable _min_P{"min_P", 0.0, "lower mometum limit"}; Configurable _max_P{"max_P", 100.0, "upper mometum limit"}; Configurable _eta{"eta", 100.0, "abs eta value limit"}; - Configurable _dcaXY{"dcaXY", 10.0, "abs dcaXY value limit"}; - Configurable _dcaZ{"dcaZ", 10.0, "abs dcaZ value limit"}; + Configurable> _dcaXY{"dcaXY", std::vector{0.3f, 0.0f, 0.0f}, "abs dcaXY value limit; formula: [0] + [1]*pT^[2]"}; + Configurable> _dcaZ{"dcaZ", std::vector{0.3f, 0.0f, 0.0f}, "abs dcaZ value limit; formula: [0] + [1]*pT^[2]"}; Configurable _tpcNClsFound{"minTpcNClsFound", 0, "minimum allowed number of TPC clasters"}; Configurable _tpcChi2NCl{"tpcChi2NCl", 100.0, "upper limit for chi2 value of a fit over TPC clasters"}; Configurable _tpcCrossedRowsOverFindableCls{"tpcCrossedRowsOverFindableCls", 0, "lower limit of TPC CrossedRows/FindableCls value"}; @@ -59,21 +70,23 @@ struct FemtoCorrelationsMC { Configurable _sign_1{"sign_1", 1, "sign of the first particle in a pair"}; Configurable _particlePDG_1{"particlePDG_1", 2212, "PDG code of the first particle in a pair to perform PID for (only pion, kaon, proton and deurton are supported now)"}; Configurable> _tpcNSigma_1{"tpcNSigma_1", std::vector{-3.0f, 3.0f}, "first particle PID: Nsigma range in TPC before the TOF is used"}; + Configurable> _itsNSigma_1{"itsNSigma_1", std::vector{-10.0f, 10.0f}, "first particle PID: Nsigma range in ITS with TPC is used"}; Configurable _PIDtrshld_1{"PIDtrshld_1", 10.0, "first particle PID: value of momentum from which the PID is done with TOF (before that only TPC is used)"}; Configurable> _tofNSigma_1{"tofNSigma_1", std::vector{-3.0f, 3.0f}, "first particle PID: Nsigma range in TOF"}; - Configurable _tpcNSigmaResidual_1{"tpcNSigmaResidual_1", 5, "first particle PID: residual TPC Nsigma cut (abs. value) to use with the TOF"}; + Configurable> _tpcNSigmaResidual_1{"tpcNSigmaResidual_1", std::vector{-5.0f, 5.0f}, "first particle PID: residual TPC Nsigma cut to use with the TOF"}; Configurable _sign_2{"sign_2", 1, "sign of the second particle in a pair"}; Configurable _particlePDG_2{"particlePDG_2", 2212, "PDG code of the second particle in a pair to perform PID for (only pion, kaon, proton and deurton are supported now)"}; Configurable> _tpcNSigma_2{"tpcNSigma_2", std::vector{-3.0f, 3.0f}, "second particle PID: Nsigma range in TPC before the TOF is used"}; + Configurable> _itsNSigma_2{"itsNSigma_2", std::vector{-10.0f, 10.0f}, "first particle PID: Nsigma range in ITS with TPC is used"}; Configurable _PIDtrshld_2{"PIDtrshld_2", 10.0, "second particle PID: value of momentum from which the PID is done with TOF (before that only TPC is used)"}; Configurable> _tofNSigma_2{"tofNSigma_2", std::vector{-3.0f, 3.0f}, "second particle PID: Nsigma range in TOF"}; - Configurable _tpcNSigmaResidual_2{"tpcNSigmaResidual_2", 5, "second particle PID: residual TPC Nsigma cut (abs. value) to use with the TOF"}; + Configurable> _tpcNSigmaResidual_2{"tpcNSigmaResidual_2", std::vector{-5.0f, 5.0f}, "second particle PID: residual TPC Nsigma cut to use with the TOF"}; Configurable _particlePDGtoReject{"particlePDGtoRejectFromSecond", 0, "applied only if the particles are non-identical and only to the second particle in the pair!!!"}; Configurable> _rejectWithinNsigmaTOF{"rejectWithinNsigmaTOF", std::vector{-0.0f, 0.0f}, "TOF rejection Nsigma range for the particle specified with PDG to be rejected"}; - Configurable _radiusTPC{"radiusTPC", 1.2, "TPC radius to calculate phi_star for"}; + // Configurable _radiusTPC{"radiusTPC", 1.2, "TPC radius to calculate phi_star for"}; Configurable _vertexNbinsToMix{"vertexNbinsToMix", 10, "Number of vertexZ bins for the mixing"}; Configurable> _centBins{"multBins", std::vector{0.0f, 100.0f}, "multiplicity percentile/centrality binning (min:0, max:100)"}; @@ -81,6 +94,8 @@ struct FemtoCorrelationsMC { Configurable> _kTbins{"kTbins", std::vector{0.0f, 100.0f}, "pair transverse momentum kT binning"}; ConfigurableAxis CFkStarBinning{"CFkStarBinning", {500, 0.005, 5.005}, "k* binning of the res. matrix (Nbins, lowlimit, uplimit)"}; + Configurable> _dcaBinning{"dcaBinning", std::vector{151, 0.5f, 8}, "setup for variable binning (geometric progression is used): 1st (int) -- N_bins (must be odd, otherwise will be increased by 1); 2nd (float) -- abs value of the edge of axises in histos (-2nd, +2nd); 3d (int) -- desired ratio between w_bin at the edges and at 0;"}; + bool IsIdentical; std::pair> TPCcuts_1; @@ -89,8 +104,8 @@ struct FemtoCorrelationsMC { std::pair> TPCcuts_2; std::pair> TOFcuts_2; - using FilteredCollisions = aod::SingleCollSels; - using FilteredTracks = soa::Join; + using FilteredCollisions = soa::Join; + using FilteredTracks = soa::Join; typedef std::shared_ptr::iterator> trkType; typedef std::shared_ptr::iterator> colType; @@ -122,6 +137,8 @@ struct FemtoCorrelationsMC { std::vector>> Resolution_histos; std::vector>> DoubleTrack_SE_histos; std::vector>> DoubleTrack_ME_histos; + std::vector>> AvgSep_SE_histos; + std::vector>> AvgSep_ME_histos; void init(o2::framework::InitContext&) { @@ -137,12 +154,22 @@ struct FemtoCorrelationsMC { TPCcuts_2 = std::make_pair(_particlePDG_2, _tpcNSigma_2); TOFcuts_2 = std::make_pair(_particlePDG_2, _tofNSigma_2); + int N = _dcaBinning.value[0]; // number of bins -- must be odd otherwise will be increased by 1 + if (N % 2 != 1) + N += 1; + auto var_bins = calc_var_bins(N + 1, _dcaBinning.value[1], static_cast(_dcaBinning.value[2])); + auto const_bins = calc_const_bins(100, 0., 5.0); + for (unsigned int i = 0; i < _centBins.value.size() - 1; i++) { std::map> DCA_histos_1_perMult; - DCA_histos_1_perMult[0] = registry.add(Form("Cent%i/FirstParticle/dcaxyz_vs_pt_primary", i), "dcaxyz_vs_pt_primary", kTH3F, {{100, 0., 5., "pt"}, {250, -1., 1., "DCA_XY(pt) primary"}, {250, -1., 1., "DCA_Z(pt) primary"}}); - DCA_histos_1_perMult[1] = registry.add(Form("Cent%i/FirstParticle/dcaxyz_vs_pt_weakdecay", i), "dcaxyz_vs_pt_weakdecay", kTH3F, {{100, 0., 5., "pt"}, {250, -1., 1., "DCA_XY(pt) weakdecay"}, {250, -1., 1., "DCA_Z(pt) weakdecay"}}); - DCA_histos_1_perMult[2] = registry.add(Form("Cent%i/FirstParticle/dcaxyz_vs_pt_material", i), "dcaxyz_vs_pt_material", kTH3F, {{100, 0., 5., "pt"}, {250, -1., 1., "DCA_XY(pt) material"}, {250, -1., 1., "DCA_Z(pt) material"}}); + DCA_histos_1_perMult[0] = registry.add(Form("Cent%i/FirstParticle/dcaxyz_vs_pt_primary", i), "dcaxyz_vs_pt_primary", kTH3F, {{1, 0, 1, "pt"}, {1, 0, 1, "DCA_XY(pt) primary"}, {1, 0, 1, "DCA_Z(pt) primary"}}); + DCA_histos_1_perMult[1] = registry.add(Form("Cent%i/FirstParticle/dcaxyz_vs_pt_weakdecay", i), "dcaxyz_vs_pt_weakdecay", kTH3F, {{1, 0, 1, "pt"}, {1, 0, 1, "DCA_XY(pt) weakdecay"}, {1, 0, 1, "DCA_Z(pt) weakdecay"}}); + DCA_histos_1_perMult[2] = registry.add(Form("Cent%i/FirstParticle/dcaxyz_vs_pt_material", i), "dcaxyz_vs_pt_material", kTH3F, {{1, 0, 1, "pt"}, {1, 0, 1, "DCA_XY(pt) material"}, {1, 0, 1, "DCA_Z(pt) material"}}); + + DCA_histos_1_perMult[0]->SetBins(100, &const_bins[0], N, &var_bins[0], N, &var_bins[0]); // set variable bins in Y and Z axis; constant on X + DCA_histos_1_perMult[1]->SetBins(100, &const_bins[0], N, &var_bins[0], N, &var_bins[0]); + DCA_histos_1_perMult[2]->SetBins(100, &const_bins[0], N, &var_bins[0], N, &var_bins[0]); std::map> Purity_histos_1_perMult; Purity_histos_1_perMult[11] = registry.add(Form("Cent%i/FirstParticle/pSpectraEl", i), "pSpectraEl", kTH1F, {{100, 0., 5., "p"}}); @@ -158,9 +185,13 @@ struct FemtoCorrelationsMC { if (!IsIdentical) { std::map> DCA_histos_2_perMult; - DCA_histos_2_perMult[0] = registry.add(Form("Cent%i/SecondParticle/dcaxyz_vs_pt_primary", i), "dcaxyz_vs_pt_primary", kTH3F, {{100, 0., 5., "pt"}, {200, -1., 1., "DCA_XY(pt) primary"}, {200, -1., 1., "DCA_Z(pt) primary"}}); - DCA_histos_2_perMult[1] = registry.add(Form("Cent%i/SecondParticle/dcaxyz_vs_pt_weakdecay", i), "dcaxyz_vs_pt_weakdecay", kTH3F, {{100, 0., 5., "pt"}, {200, -1., 1., "DCA_XY(pt) weakdecay"}, {200, -1., 1., "DCA_Z(pt) weakdecay"}}); - DCA_histos_2_perMult[2] = registry.add(Form("Cent%i/SecondParticle/dcaxyz_vs_pt_material", i), "dcaxyz_vs_pt_material", kTH3F, {{100, 0., 5., "pt"}, {200, -1., 1., "DCA_XY(pt) material"}, {200, -1., 1., "DCA_Z(pt) material"}}); + DCA_histos_2_perMult[0] = registry.add(Form("Cent%i/SecondParticle/dcaxyz_vs_pt_primary", i), "dcaxyz_vs_pt_primary", kTH3F, {{1, 0, 1, "pt"}, {1, 0, 1, "DCA_XY(pt) primary"}, {1, 0, 1, "DCA_Z(pt) primary"}}); + DCA_histos_2_perMult[1] = registry.add(Form("Cent%i/SecondParticle/dcaxyz_vs_pt_weakdecay", i), "dcaxyz_vs_pt_weakdecay", kTH3F, {{1, 0, 1, "pt"}, {1, 0, 1, "DCA_XY(pt) weakdecay"}, {1, 0, 1, "DCA_Z(pt) weakdecay"}}); + DCA_histos_2_perMult[2] = registry.add(Form("Cent%i/SecondParticle/dcaxyz_vs_pt_material", i), "dcaxyz_vs_pt_material", kTH3F, {{1, 0, 1, "pt"}, {1, 0, 1, "DCA_XY(pt) material"}, {1, 0, 1, "DCA_Z(pt) material"}}); + + DCA_histos_2_perMult[0]->SetBins(100, &const_bins[0], N, &var_bins[0], N, &var_bins[0]); // set variable bins in Y and Z axis; constant on X + DCA_histos_2_perMult[1]->SetBins(100, &const_bins[0], N, &var_bins[0], N, &var_bins[0]); + DCA_histos_2_perMult[2]->SetBins(100, &const_bins[0], N, &var_bins[0], N, &var_bins[0]); std::map> Purity_histos_2_perMult; Purity_histos_2_perMult[11] = registry.add(Form("Cent%i/SecondParticle/pSpectraEl", i), "pSpectraEl", kTH1F, {{100, 0., 5., "p"}}); @@ -179,22 +210,30 @@ struct FemtoCorrelationsMC { std::vector> Resolution_histos_perMult; std::vector> DoubleTrack_SE_histos_perMult; std::vector> DoubleTrack_ME_histos_perMult; + std::vector> AvgSep_SE_histos_perMult; + std::vector> AvgSep_ME_histos_perMult; for (unsigned int j = 0; j < _kTbins.value.size() - 1; j++) { auto kT_tmp = registry.add(Form("Cent%i/kT_cent%i_kT%i", i, i, j), Form("kT_cent%i_kT%i", i, j), kTH1F, {{500, 0., 5., "kT"}}); auto Res_tmp = registry.add(Form("Cent%i/ResolutionMatrix_cent%i_kT%i", i, i, j), Form("ResolutionMatrix_rec(gen)_cent%i_kT%i", i, j), kTH2F, {{CFkStarBinning, "k*_gen (GeV/c)"}, {CFkStarBinning, "k*_rec (GeV/c)"}}); - auto DblTrk_SE_tmp = registry.add(Form("Cent%i/DoubleTrackEffects_SE_cent%i_kT%i", i, i, j), Form("DoubleTrackEffects_deta(dphi*)_SE_cent%i_kT%i", i, j), kTH2F, {{600, -M_PI, M_PI, "dphi*"}, {200, -0.5, 0.5, "deta"}}); - auto DblTrk_ME_tmp = registry.add(Form("Cent%i/DoubleTrackEffects_ME_cent%i_kT%i", i, i, j), Form("DoubleTrackEffects_deta(dphi*)_ME_cent%i_kT%i", i, j), kTH2F, {{600, -M_PI, M_PI, "dphi*"}, {200, -0.5, 0.5, "deta"}}); + auto DblTrk_SE_tmp = registry.add(Form("Cent%i/DoubleTrackEffects_SE_cent%i_kT%i", i, i, j), Form("DoubleTrackEffects_deta(dphi*)_SE_cent%i_kT%i", i, j), kTH2F, {{101, -0.2, 0.2, "dphi*"}, {101, -0.2, 0.2, "deta"}}); + auto DblTrk_ME_tmp = registry.add(Form("Cent%i/DoubleTrackEffects_ME_cent%i_kT%i", i, i, j), Form("DoubleTrackEffects_deta(dphi*)_ME_cent%i_kT%i", i, j), kTH2F, {{101, -0.2, 0.2, "dphi*"}, {101, -0.2, 0.2, "deta"}}); + auto AvgSep_SE_tmp = registry.add(Form("Cent%i/AvgSep_SE_cent%i_kT%i", i, i, j), Form("AvgSep_SE_cent%i_kT%i", i, j), kTH1F, {{100, 0.0, 100.0, "avg. sep. (cm)"}}); + auto AvgSep_ME_tmp = registry.add(Form("Cent%i/AvgSep_ME_cent%i_kT%i", i, i, j), Form("AvgSep_ME_cent%i_kT%i", i, j), kTH1F, {{100, 0.0, 100.0, "avg. sep. (cm)"}}); kThistos_perMult.push_back(std::move(kT_tmp)); Resolution_histos_perMult.push_back(std::move(Res_tmp)); DoubleTrack_SE_histos_perMult.push_back(std::move(DblTrk_SE_tmp)); DoubleTrack_ME_histos_perMult.push_back(std::move(DblTrk_ME_tmp)); + AvgSep_SE_histos_perMult.push_back(std::move(AvgSep_SE_tmp)); + AvgSep_ME_histos_perMult.push_back(std::move(AvgSep_ME_tmp)); } kThistos.push_back(std::move(kThistos_perMult)); Resolution_histos.push_back(std::move(Resolution_histos_perMult)); DoubleTrack_SE_histos.push_back(std::move(DoubleTrack_SE_histos_perMult)); DoubleTrack_ME_histos.push_back(std::move(DoubleTrack_ME_histos_perMult)); + AvgSep_SE_histos.push_back(std::move(AvgSep_SE_histos_perMult)); + AvgSep_ME_histos.push_back(std::move(AvgSep_ME_histos_perMult)); } } @@ -215,7 +254,8 @@ struct FemtoCorrelationsMC { LOGF(fatal, "kTbin value obtained for a pair exceeds the configured number of kT bins"); kThistos[centBin][kTbin]->Fill(pair_kT); - DoubleTrack_SE_histos[centBin][kTbin]->Fill(Pair->GetPhiStarDiff(_radiusTPC), Pair->GetEtaDiff()); + DoubleTrack_SE_histos[centBin][kTbin]->Fill(Pair->GetAvgPhiStarDiff(), Pair->GetEtaDiff()); + AvgSep_SE_histos[centBin][kTbin]->Fill(Pair->GetAvgSep()); Pair->ResetPair(); } } @@ -238,7 +278,8 @@ struct FemtoCorrelationsMC { LOGF(fatal, "kTbin value obtained for a pair exceeds the configured number of kT bins"); kThistos[centBin][kTbin]->Fill(pair_kT); - DoubleTrack_SE_histos[centBin][kTbin]->Fill(Pair->GetPhiStarDiff(_radiusTPC), Pair->GetEtaDiff()); + DoubleTrack_SE_histos[centBin][kTbin]->Fill(Pair->GetAvgPhiStarDiff(), Pair->GetEtaDiff()); + AvgSep_SE_histos[centBin][kTbin]->Fill(Pair->GetAvgSep()); Pair->ResetPair(); } } @@ -249,6 +290,7 @@ struct FemtoCorrelationsMC { { // template for ME for (auto ii : tracks1) { for (auto iii : tracks2) { + Pair->SetPair(ii, iii); float pair_kT = Pair->GetKt(); @@ -259,13 +301,18 @@ struct FemtoCorrelationsMC { if (kTbin > Resolution_histos[centBin].size() || kTbin > DoubleTrack_ME_histos[centBin].size()) LOGF(fatal, "kTbin value obtained for a pair exceeds the configured number of kT bins"); + DoubleTrack_ME_histos[centBin][kTbin]->Fill(Pair->GetAvgPhiStarDiff(), Pair->GetEtaDiff()); + AvgSep_ME_histos[centBin][kTbin]->Fill(Pair->GetAvgSep()); + + if (abs(ii->pdgCode()) != _particlePDG_1.value || abs(iii->pdgCode()) != _particlePDG_2.value) + continue; + TLorentzVector first4momentumGen; first4momentumGen.SetPtEtaPhiM(ii->pt_MC(), ii->eta_MC(), ii->phi_MC(), particle_mass(_particlePDG_1)); TLorentzVector second4momentumGen; second4momentumGen.SetPtEtaPhiM(iii->pt_MC(), iii->eta_MC(), iii->phi_MC(), particle_mass(_particlePDG_2)); Resolution_histos[centBin][kTbin]->Fill(o2::aod::singletrackselector::GetKstarFrom4vectors(first4momentumGen, second4momentumGen, IsIdentical), Pair->GetKstar()); - DoubleTrack_ME_histos[centBin][kTbin]->Fill(Pair->GetPhiStarDiff(_radiusTPC), Pair->GetEtaDiff()); Pair->ResetPair(); } } @@ -279,23 +326,37 @@ struct FemtoCorrelationsMC { int trackPDG, trackOrigin; for (auto track : tracks) { - if (abs(track.template singleCollSel_as>().posZ()) > _vertexZ) + if (std::fabs(track.template singleCollSel_as>().posZ()) > _vertexZ) continue; if (track.tpcFractionSharedCls() > _tpcFractionSharedCls || track.itsNCls() < _itsNCls) continue; if (track.template singleCollSel_as>().multPerc() < *_centBins.value.begin() || track.template singleCollSel_as>().multPerc() >= *(_centBins.value.end() - 1)) continue; + if (track.template singleCollSel_as>().hadronicRate() < _IRcut.value.first || track.template singleCollSel_as>().hadronicRate() >= _IRcut.value.second) + continue; + if (track.template singleCollSel_as>().occupancy() < _OccupancyCut.value.first || track.template singleCollSel_as>().occupancy() >= _OccupancyCut.value.second) + continue; + if (_removeSameBunchPileup && !track.template singleCollSel_as>().isNoSameBunchPileup()) + continue; + if (_requestGoodZvtxFT0vsPV && !track.template singleCollSel_as>().isGoodZvtxFT0vsPV()) + continue; + if (_requestVertexITSTPC && !track.template singleCollSel_as>().isVertexITSTPC()) + continue; + if (_requestVertexTOForTRDmatched > track.template singleCollSel_as>().isVertexTOForTRDmatched()) + continue; + if (_requestNoCollInTimeRangeStandard && !track.template singleCollSel_as>().noCollInTimeRangeStandard()) + continue; unsigned int centBin = o2::aod::singletrackselector::getBinIndex(track.template singleCollSel_as>().multPerc(), _centBins); - if (track.sign() == _sign_1 && (track.p() < _PIDtrshld_1 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_1) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_1, _tpcNSigmaResidual_1))) { + if (track.sign() == _sign_1 && (track.p() < _PIDtrshld_1 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_1, _itsNSigma_1.value) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_1, _tpcNSigmaResidual_1.value))) { trackOrigin = track.origin(); if (trackOrigin > -1 && trackOrigin < 3) DCA_histos_1[centBin][track.origin()]->Fill(track.pt(), track.dcaXY(), track.dcaZ()); - if (abs(track.dcaXY()) > _dcaXY || abs(track.dcaZ()) > _dcaZ) + if (std::fabs(track.dcaXY()) > _dcaXY.value[0] + _dcaXY.value[1] * std::pow(track.pt(), _dcaXY.value[2]) || std::fabs(track.dcaZ()) > _dcaZ.value[0] + _dcaZ.value[1] * std::pow(track.pt(), _dcaZ.value[2])) continue; trackPDG = abs(track.pdgCode()); @@ -309,14 +370,14 @@ struct FemtoCorrelationsMC { if (IsIdentical) { continue; - } else if (track.sign() != _sign_2 && !TOFselection(track, std::make_pair(_particlePDGtoReject, _rejectWithinNsigmaTOF)) && (track.p() < _PIDtrshld_2 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_2) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_2, _tpcNSigmaResidual_2))) { // filling the map: eventID <-> selected particles2 if (see condition above ^) + } else if (track.sign() != _sign_2 && !TOFselection(track, std::make_pair(_particlePDGtoReject, _rejectWithinNsigmaTOF)) && (track.p() < _PIDtrshld_2 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_2, _itsNSigma_2.value) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_2, _tpcNSigmaResidual_2.value))) { // filling the map: eventID <-> selected particles2 if (see condition above ^) trackOrigin = track.origin(); if (trackOrigin > -1 && trackOrigin < 3) DCA_histos_2[centBin][track.origin()]->Fill(track.pt(), track.dcaXY(), track.dcaZ()); - if (abs(track.dcaXY()) > _dcaXY || abs(track.dcaZ()) > _dcaZ) + if (std::fabs(track.dcaXY()) > _dcaXY.value[0] + _dcaXY.value[1] * std::pow(track.pt(), _dcaXY.value[2]) || std::fabs(track.dcaZ()) > _dcaZ.value[0] + _dcaZ.value[1] * std::pow(track.pt(), _dcaZ.value[2])) continue; trackPDG = abs(track.pdgCode()); @@ -332,6 +393,21 @@ struct FemtoCorrelationsMC { for (auto collision : collisions) { if (collision.multPerc() < *_centBins.value.begin() || collision.multPerc() >= *(_centBins.value.end() - 1)) continue; + if (collision.hadronicRate() < _IRcut.value.first || collision.hadronicRate() >= _IRcut.value.second) + continue; + if (collision.occupancy() < _OccupancyCut.value.first || collision.occupancy() >= _OccupancyCut.value.second) + continue; + + if (_removeSameBunchPileup && !collision.isNoSameBunchPileup()) + continue; + if (_requestGoodZvtxFT0vsPV && !collision.isGoodZvtxFT0vsPV()) + continue; + if (_requestVertexITSTPC && !collision.isVertexITSTPC()) + continue; + if (_requestVertexTOForTRDmatched > collision.isVertexTOForTRDmatched()) + continue; + if (_requestNoCollInTimeRangeStandard && !collision.noCollInTimeRangeStandard()) + continue; if (selectedtracks_1.find(collision.globalIndex()) == selectedtracks_1.end()) { if (IsIdentical) diff --git a/PWGCF/Femto3D/Tasks/femto3dQA.cxx b/PWGCF/Femto3D/Tasks/femto3dQA.cxx old mode 100755 new mode 100644 index e695c8d5a5a..6923ae91cb6 --- a/PWGCF/Femto3D/Tasks/femto3dQA.cxx +++ b/PWGCF/Femto3D/Tasks/femto3dQA.cxx @@ -13,6 +13,10 @@ /// \author Sofia Tomassini, Gleb Romanenko, Nicolò Jacazio /// \since 31 May 2023 +#include +#include +#include + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" @@ -28,6 +32,7 @@ #include "Framework/StaticFor.h" #include "PWGCF/Femto3D/DataModel/singletrackselector.h" +#include "PWGCF/Femto3D/Core/femto3dPairTask.h" using namespace o2; using namespace o2::soa; @@ -43,14 +48,18 @@ struct QAHistograms { Configurable _removeSameBunchPileup{"removeSameBunchPileup", false, ""}; Configurable _requestGoodZvtxFT0vsPV{"requestGoodZvtxFT0vsPV", false, ""}; Configurable _requestVertexITSTPC{"requestVertexITSTPC", false, ""}; + Configurable _requestVertexTOForTRDmatched{"requestVertexTOFmatched", 0, "0 -> no selectio; 1 -> vertex is matched to TOF or TRD; 2 -> matched to both;"}; + Configurable _requestNoCollInTimeRangeStandard{"requestNoCollInTimeRangeStandard", false, ""}; + Configurable> _IRcut{"IRcut", std::pair{0.f, 100.f}, "[min., max.] IR range to keep events within"}; + Configurable> _OccupancyCut{"OccupancyCut", std::pair{0, 10000}, "[min., max.] occupancy range to keep events within"}; Configurable _sign{"sign", 1, "sign of a track"}; Configurable _vertexZ{"VertexZ", 10.0, "abs vertexZ value limit"}; Configurable _min_P{"min_P", 0.0, "lower mometum limit"}; Configurable _max_P{"max_P", 100.0, "upper mometum limit"}; Configurable _eta{"eta", 100.0, "abs eta value limit"}; - Configurable _dcaXY{"dcaXY", 10.0, "abs dcaXY value limit"}; - Configurable _dcaZ{"dcaZ", 10.0, "abs dcaZ value limit"}; + Configurable> _dcaXY{"dcaXY", std::vector{0.3f, 0.0f, 0.0f}, "abs dcaXY value limit; formula: [0] + [1]*pT^[2]"}; + Configurable> _dcaZ{"dcaZ", std::vector{0.3f, 0.0f, 0.0f}, "abs dcaZ value limit; formula: [0] + [1]*pT^[2]"}; Configurable _tpcNClsFound{"minTpcNClsFound", 0, "minimum allowed number of TPC clasters"}; Configurable _tpcChi2NCl{"tpcChi2NCl", 100.0, "upper limit for chi2 value of a fit over TPC clasters"}; Configurable _tpcCrossedRowsOverFindableCls{"tpcCrossedRowsOverFindableCls", 0, "lower limit of TPC CrossedRows/FindableCls value"}; @@ -59,18 +68,25 @@ struct QAHistograms { Configurable _itsChi2NCl{"itsChi2NCl", 100.0, "upper limit for chi2 value of a fit over ITS clasters for a track"}; Configurable _particlePDG{"particlePDG", 2212, "PDG code of a particle to perform PID for (only pion, kaon, proton and deurton are supported now)"}; Configurable> _tpcNSigma{"tpcNSigma", std::vector{-4.0f, 4.0f}, "Nsigma range in TPC before the TOF is used"}; + Configurable> _itsNSigma{"itsNSigma", std::vector{-10.0f, 10.0f}, "Nsigma range in ITS to use along with TPC"}; Configurable _PIDtrshld{"PIDtrshld", 10.0, "value of momentum from which the PID is done with TOF (before that only TPC is used)"}; Configurable> _tofNSigma{"tofNSigma", std::vector{-4.0f, 4.0f}, "Nsigma range in TOF"}; - Configurable _tpcNSigmaResidual{"tpcNSigmaResidual", 5, "residual TPC Nsigma cut (abs. value) to use with the TOF"}; + Configurable> _tpcNSigmaResidual{"tpcNSigmaResidual", std::vector{-5.0f, 5.0f}, "residual TPC Nsigma cut to use with the TOF"}; Configurable _particlePDGtoReject{"particlePDGtoReject", 211, "PDG codes of perticles that will be rejected with TOF (only pion, kaon, proton and deurton are supported now)"}; Configurable> _rejectWithinNsigmaTOF{"rejectWithinNsigmaTOF", std::vector{-0.0f, 0.0f}, "TOF rejection Nsigma range for particles specified with PDG to be rejected"}; Configurable> _centCut{"centCut", std::pair{0.f, 100.f}, "[min., max.] centrality range to keep tracks within"}; + Configurable> _dcaBinning{"dcaBinning", std::vector{501, 0.5f, 1}, "setup for variable binning (geometric progression is used): 1st (int) -- N_bins (must be odd, otherwise will be increased by 1); 2nd (float) -- abs value of the edge of axises in histos (-2nd, +2nd); 3d (int) -- desired ratio between w_bin at the edges and at 0;"}; + std::pair> TPCcuts; std::pair> TOFcuts; + std::shared_ptr ITShisto; + std::shared_ptr TPChisto; + std::shared_ptr TOFhisto; + Filter signFilter = o2::aod::singletrackselector::sign == _sign; Filter pFilter = o2::aod::singletrackselector::p > _min_P&& o2::aod::singletrackselector::p < _max_P; Filter etaFilter = nabs(o2::aod::singletrackselector::eta) < _eta; @@ -79,9 +95,6 @@ struct QAHistograms { o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedTpcChi2NCl) < _tpcChi2NCl && o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedTpcCrossedRowsOverFindableCls) > _tpcCrossedRowsOverFindableCls; - Filter dcaFilter = nabs(o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedDcaXY)) < _dcaXY && - nabs(o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedDcaZ)) < _dcaZ; - Filter itsTrkFilter = o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedItsChi2NCl) < _itsChi2NCl; Filter vertexFilter = nabs(o2::aod::singletrackselector::posZ) < _vertexZ; @@ -91,6 +104,30 @@ struct QAHistograms { TPCcuts = std::make_pair(_particlePDG, _tpcNSigma); TOFcuts = std::make_pair(_particlePDG, _tofNSigma); + int N = _dcaBinning.value[0]; // number of bins -- must be odd otherwise will be increased by 1 + if (N % 2 != 1) { + N += 1; + } + + std::unique_ptr dca_bins; + if (static_cast(_dcaBinning.value[2]) != 1.0) { + dca_bins = calc_var_bins(N + 1, _dcaBinning.value[1], static_cast(_dcaBinning.value[2])); + } else { + dca_bins = calc_const_bins(N, -_dcaBinning.value[1], _dcaBinning.value[1]); + } + auto const_bins_p = calc_const_bins(100, 0., 5.0); + + auto DCA_XY_p = registry.add("dcaxy_to_p", "dcaxy_to_p", kTH2F, {{100, 0., 5.0, "p"}, {501, -0.5, 0.5, "dcaxy"}}); + auto DCA_XY_pt = registry.add("dcaxy_to_pt", "dcaxy_to_pt", kTH2F, {{100, 0., 5.0, "pt"}, {501, -0.5, 0.5, "dcaxy"}}); + + auto DCA_Z_p = registry.add("dcaz_to_p", "dcaz_to_p", kTH2F, {{100, 0., 5.0, "p"}, {501, -0.5, 0.5, "dcaz"}}); + auto DCA_Z_pt = registry.add("dcaz_to_pt", "dcaz_to_pt", kTH2F, {{100, 0., 5.0, "pt"}, {501, -0.5, 0.5, "dcaz"}}); + + DCA_XY_p->SetBins(100, &const_bins_p[0], N, &dca_bins[0]); // set variable bins in Y and Z axis; constant on X + DCA_XY_pt->SetBins(100, &const_bins_p[0], N, &dca_bins[0]); // set variable bins in Y and Z axis; constant on X + DCA_Z_p->SetBins(100, &const_bins_p[0], N, &dca_bins[0]); // set variable bins in Y and Z axis; constant on X + DCA_Z_pt->SetBins(100, &const_bins_p[0], N, &dca_bins[0]); // set variable bins in Y and Z axis; constant on X + registry.add("TPCSignal_nocuts", "TPC signal without cuts", kTH2F, {{{200, 0., 5.0, "#it{p}_{inner} (GeV/#it{c})"}, {1000, 0., 1000.0, "dE/dx in TPC (arbitrary units)"}}}); registry.add("TOFSignal_nocuts", "TOF signal without cuts", kTH2F, {{{200, 0., 5.0, "#it{p} (GeV/#it{c})"}, {100, 0., 1.5, "#beta"}}}); @@ -102,10 +139,6 @@ struct QAHistograms { registry.add("p", "p", kTH1F, {{100, 0., 5., "p"}}); registry.add("pt", "pt", kTH1F, {{100, 0., 5., "pt"}}); registry.add("sign", "sign", kTH1F, {{3, -1.5, 1.5, "sign"}}); - registry.add("dcaxy_to_p", "dcaxy_to_p", kTH2F, {{100, 0., 5.0, "p"}, {200, -1., 1., "dcaxy"}}); - registry.add("dcaxy_to_pt", "dcaxy_to_pt", kTH2F, {{100, 0., 5., "pt"}, {200, -1., 1., "dcaxy"}}); - registry.add("dcaz_to_p", "dcaz_to_p", kTH2F, {{100, 0., 5., "p"}, {200, -1., 1., "dcaz"}}); - registry.add("dcaz_to_pt", "dcaz_to_pt", kTH2F, {{100, 0., 5., "pt"}, {200, -1., 1., "dcaz"}}); registry.add("TPCClusters", "TPCClusters", kTH1F, {{163, -0.5, 162.5, "NTPCClust"}}); registry.add("TPCCrossedRowsOverFindableCls", "TPCCrossedRowsOverFindableCls", kTH1F, {{100, 0.0, 10.0, "NcrossedRowsOverFindable"}}); registry.add("TPCFractionSharedCls", "TPCFractionSharedCls", kTH1F, {{100, 0.0, 1.0, "TPCsharedFraction"}}); @@ -116,29 +149,16 @@ struct QAHistograms { registry.add("TPCSignal", "TPC Signal", kTH2F, {{{200, 0., 5.0, "#it{p}_{inner} (GeV/#it{c})"}, {1000, 0., 1000.0, "dE/dx in TPC (arbitrary units)"}}}); registry.add("TOFSignal", "TOF Signal", kTH2F, {{200, 0., 5.0, "#it{p} (GeV/#it{c})"}, {100, 0., 1.5, "#beta"}}); - switch (_particlePDG) { - case 211: - registry.add("nsigmaTOFPi", "nsigmaTOFPi", kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); - registry.add("nsigmaTPCPi", "nsigmaTPCPi", kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); - break; - case 321: - registry.add("nsigmaTOFKa", "nsigmaTOFKa", kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); - registry.add("nsigmaTPCKa", "nsigmaTPCKa", kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); - break; - case 2212: - registry.add("nsigmaTOFPr", "nsigmaTOFPr", kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); - registry.add("nsigmaTPCPr", "nsigmaTPCPr", kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); - break; - case 1000010020: - registry.add("nsigmaTOFDe", "nsigmaTOFDe", kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); - registry.add("nsigmaTPCDe", "nsigmaTPCDe", kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); - break; - default: - break; - } + ITShisto = registry.add(Form("nsigmaITS_PDG%i", _particlePDG.value), Form("nsigmaITS_PDG%i", _particlePDG.value), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); + TPChisto = registry.add(Form("nsigmaTPC_PDG%i", _particlePDG.value), Form("nsigmaTPC_PDG%i", _particlePDG.value), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); + TOFhisto = registry.add(Form("nsigmaTOF_PDG%i", _particlePDG.value), Form("nsigmaTOF_PDG%i", _particlePDG.value), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); + const AxisSpec axisMult{5001, -0.5, 5000.5, "mult."}; + const AxisSpec axisPerc{101, -0.5, 100.5, "percentile"}; registry.add("posZ", "posZ", kTH1F, {{300, -16., 16., "posZ"}}); - registry.add("mult", "mult", kTH1F, {{5001, -0.5, 5000.5, "mult."}}); + registry.add("mult", "mult", kTH1F, {axisMult}); + registry.add("MultVsCent", "MultVsCent", kTH2F, {axisMult, axisPerc}); + registry.add("IRvsOccupancy", "IRvsOccupancy", kTH2I, {{10000, 0, 10000, "Occupancy"}, {50, 0, 50, "IR, kHz"}}); } template @@ -151,14 +171,24 @@ struct QAHistograms { continue; if (_requestVertexITSTPC && !collision.isVertexITSTPC()) continue; + if (_requestVertexTOForTRDmatched > collision.isVertexTOForTRDmatched()) + continue; + if (_requestNoCollInTimeRangeStandard && !collision.noCollInTimeRangeStandard()) + continue; if (collision.multPerc() < _centCut.value.first || collision.multPerc() >= _centCut.value.second) continue; + if (collision.hadronicRate() < _IRcut.value.first || collision.hadronicRate() >= _IRcut.value.second) + continue; + if (collision.occupancy() < _OccupancyCut.value.first || collision.occupancy() >= _OccupancyCut.value.second) + continue; registry.fill(HIST("posZ"), collision.posZ()); registry.fill(HIST("mult"), collision.mult()); + registry.fill(HIST("MultVsCent"), collision.mult(), collision.multPerc()); + registry.fill(HIST("IRvsOccupancy"), collision.occupancy(), collision.hadronicRate()); } - for (auto& track : tracks) { + for (const auto& track : tracks) { if (_removeSameBunchPileup && !track.template singleCollSel_as().isNoSameBunchPileup()) continue; @@ -166,20 +196,30 @@ struct QAHistograms { continue; if (_requestVertexITSTPC && !track.template singleCollSel_as().isVertexITSTPC()) continue; + if (_requestVertexTOForTRDmatched > track.template singleCollSel_as().isVertexTOForTRDmatched()) + continue; + if (_requestNoCollInTimeRangeStandard && !track.template singleCollSel_as().noCollInTimeRangeStandard()) + continue; - if (abs(track.template singleCollSel_as().posZ()) > _vertexZ) + if (std::fabs(track.template singleCollSel_as().posZ()) > _vertexZ) continue; if (track.template singleCollSel_as().multPerc() < _centCut.value.first || track.template singleCollSel_as().multPerc() >= _centCut.value.second) continue; + if (track.template singleCollSel_as().hadronicRate() < _IRcut.value.first || track.template singleCollSel_as().hadronicRate() >= _IRcut.value.second) + continue; + if (track.template singleCollSel_as().occupancy() < _OccupancyCut.value.first || track.template singleCollSel_as().occupancy() >= _OccupancyCut.value.second) + continue; if ((track.tpcFractionSharedCls()) > _tpcFractionSharedCls || (track.itsNCls()) < _itsNCls) continue; + if (std::fabs(track.dcaXY()) > _dcaXY.value[0] + _dcaXY.value[1] * std::pow(track.pt(), _dcaXY.value[2]) || std::fabs(track.dcaZ()) > _dcaZ.value[0] + _dcaZ.value[1] * std::pow(track.pt(), _dcaZ.value[2])) + continue; if constexpr (FillExtra) { registry.fill(HIST("TPCSignal_nocuts"), track.tpcInnerParam(), track.tpcSignal()); registry.fill(HIST("TOFSignal_nocuts"), track.p(), track.beta()); } - if (!TOFselection(track, std::make_pair(_particlePDGtoReject, _rejectWithinNsigmaTOF)) && (track.p() < _PIDtrshld ? o2::aod::singletrackselector::TPCselection(track, TPCcuts) : o2::aod::singletrackselector::TOFselection(track, TOFcuts, _tpcNSigmaResidual))) { + if (!TOFselection(track, std::make_pair(_particlePDGtoReject, _rejectWithinNsigmaTOF)) && (track.p() < _PIDtrshld ? o2::aod::singletrackselector::TPCselection(track, TPCcuts, _itsNSigma.value) : o2::aod::singletrackselector::TOFselection(track, TOFcuts, _tpcNSigmaResidual.value))) { registry.fill(HIST("eta"), track.eta()); registry.fill(HIST("phi"), track.phi()); registry.fill(HIST("px"), track.px()); @@ -199,26 +239,9 @@ struct QAHistograms { registry.fill(HIST("ITSchi2"), track.itsChi2NCl()); registry.fill(HIST("TPCchi2"), track.tpcChi2NCl()); - switch (_particlePDG) { - case 211: - registry.fill(HIST("nsigmaTOFPi"), track.p(), track.tofNSigmaPi()); - registry.fill(HIST("nsigmaTPCPi"), track.p(), track.tpcNSigmaPi()); - break; - case 321: - registry.fill(HIST("nsigmaTOFKa"), track.p(), track.tofNSigmaKa()); - registry.fill(HIST("nsigmaTPCKa"), track.p(), track.tpcNSigmaKa()); - break; - case 2212: - registry.fill(HIST("nsigmaTOFPr"), track.p(), track.tofNSigmaPr()); - registry.fill(HIST("nsigmaTPCPr"), track.p(), track.tpcNSigmaPr()); - break; - case 1000010020: - registry.fill(HIST("nsigmaTOFDe"), track.p(), track.tofNSigmaDe()); - registry.fill(HIST("nsigmaTPCDe"), track.p(), track.tpcNSigmaDe()); - break; - default: - break; - } + ITShisto->Fill(track.p(), o2::aod::singletrackselector::getITSNsigma(track, _particlePDG)); + TPChisto->Fill(track.p(), o2::aod::singletrackselector::getTPCNsigma(track, _particlePDG)); + TOFhisto->Fill(track.p(), o2::aod::singletrackselector::getTOFNsigma(track, _particlePDG)); if constexpr (FillExtra) { registry.fill(HIST("TPCSignal"), track.tpcInnerParam(), track.tpcSignal()); @@ -228,13 +251,15 @@ struct QAHistograms { } } - void processDefault(soa::Filtered> const& collisions, soa::Filtered const& tracks) + // void processDefault(soa::Filtered> const& collisions, soa::Filtered> const& tracks) // main + void processDefault(soa::Filtered> const& collisions, soa::Filtered> const& tracks) // tmp solution till the HL is fixed { fillHistograms(collisions, tracks); } PROCESS_SWITCH(QAHistograms, processDefault, "process default", true); - void processExtra(soa::Filtered> const& collisions, soa::Filtered> const& tracks) + // void processExtra(soa::Filtered> const& collisions, soa::Filtered> const& tracks) // main + void processExtra(soa::Filtered> const& collisions, soa::Filtered> const& tracks) // tmp solution till the HL is fixed { fillHistograms(collisions, tracks); } diff --git a/PWGCF/Femto3D/Tools/CMakeLists.txt b/PWGCF/Femto3D/Tools/CMakeLists.txt new file mode 100644 index 00000000000..200d6eeab85 --- /dev/null +++ b/PWGCF/Femto3D/Tools/CMakeLists.txt @@ -0,0 +1,14 @@ +# 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_executable(single-track-selector-check-packing + SOURCES checkPacking.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore) diff --git a/PWGCF/Femto3D/Tools/checkPacking.cxx b/PWGCF/Femto3D/Tools/checkPacking.cxx new file mode 100644 index 00000000000..51d26443200 --- /dev/null +++ b/PWGCF/Femto3D/Tools/checkPacking.cxx @@ -0,0 +1,142 @@ +// 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 checkPacking.cxx +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief exec to check the packing and depacking of femto tables +/// \since 03/05/2024 +/// + +#include "PWGCF/Femto3D/DataModel/singletrackselector.h" +#include "TH1F.h" +#include "TCanvas.h" +#include "TRandom.h" + +using namespace o2; + +template +bool process(const TString outputName, const int nevents = 100000) +{ + class Container + { + public: + Container() {} + void operator()(const float toPack) { mPacked = aod::singletrackselector::packSymmetric(toPack); } + void test(const float toPack) + { + auto bin = aod::singletrackselector::packSymmetric(toPack); + LOG(info) << toPack << " goes to " << aod::singletrackselector::unPackSymmetric(bin) << " bin " << static_cast(bin); + } + T::binned_t mPacked = 0; + float unpack() { return aod::singletrackselector::unPackSymmetric(mPacked); } + } container; + + T::print(); + const float min = T::binned_min; + const float max = T::binned_max; + container.test(0); + container.test(0 + T::bin_width); + container.test(0 - T::bin_width); + container.test(0 - T::bin_width * 0.5); + const int nbins = (max - min) / T::bin_width; + std::vector xbins; + for (int i = 0; i <= nbins; i++) { + const float x = min + i * T::bin_width; + const auto ix = aod::singletrackselector::packSymmetric(x); + const float u = aod::singletrackselector::unPackSymmetric(ix); + LOG(info) << "Bin " << i << "/" << xbins.size() << " " << x << " => " << static_cast(ix) << " " << u; + if (i > 1) { + if (ix == aod::singletrackselector::packSymmetric(xbins.back())) { + continue; + } + } + xbins.push_back(u); + } + LOG(info) << "Min = " << min << " Max = " << max; + TH1F* hgaus = new TH1F("hgaus", "", nbins, min + T::bin_width * 0.5, max + 0.5 * T::bin_width); + hgaus->Print(); + LOG(info) << "Bin width = " << T::bin_width << " vs histo " << hgaus->GetXaxis()->GetBinWidth(1); + hgaus->SetLineColor(2); + hgaus->SetLineStyle(1); + TH1F* hgausPacked = static_cast(hgaus->Clone("hgausPacked")); + hgausPacked->SetLineColor(4); + hgausPacked->SetLineStyle(2); + + TH1F* huniform = static_cast(hgaus->Clone("huniform")); + huniform->SetLineColor(2); + huniform->SetLineStyle(1); + TH1F* huniformPacked = static_cast(hgaus->Clone("huniformPacked")); + huniformPacked->SetLineColor(4); + huniformPacked->SetLineStyle(2); + + for (int i = 0; i < nevents; i++) { + float randomValue = gRandom->Gaus(0, 1); + hgaus->Fill(randomValue); + container(randomValue); + hgausPacked->Fill(container.unpack()); + + randomValue = gRandom->Uniform(-10, 10); + huniform->Fill(randomValue); + container(randomValue); + huniformPacked->Fill(container.unpack()); + } + + TCanvas* can = new TCanvas("can"); + hgaus->Draw(); + hgausPacked->Draw("same"); + TString imgoutputName = "/tmp/" + outputName + ".pdf"; + can->SaveAs("/tmp/" + outputName + "_Gaus.root"); + can->SaveAs(Form("%s[", imgoutputName.Data())); + can->SaveAs(imgoutputName.Data()); + + huniform->Draw(); + huniformPacked->Draw("same"); + can->SaveAs(imgoutputName.Data()); + can->SaveAs(Form("%s]", imgoutputName.Data())); + const bool gausOk = (hgaus->GetBinContent(hgaus->FindBin(0)) == hgausPacked->GetBinContent(hgausPacked->FindBin(0))); + if (!gausOk) { + LOG(info) << "Gaus packing/unpacking failed"; + } + const bool gausMeanOk = (hgaus->GetMean() == hgausPacked->GetMean()); + if (!gausMeanOk) { + LOG(info) << "Gaus packing/unpacking mean failed"; + } + + const bool uniformOk = (huniform->GetBinContent(huniform->FindBin(0)) == huniformPacked->GetBinContent(huniformPacked->FindBin(0))); + if (!uniformOk) { + LOG(info) << "Uniform packing/unpacking failed"; + } + const bool uniformMeanOk = (huniform->GetMean() == huniformPacked->GetMean()); + if (!uniformMeanOk) { + LOG(info) << "Uniform packing/unpacking mean failed"; + } + return gausOk && uniformOk && gausMeanOk && uniformMeanOk; +} + +int main(int /*argc*/, char* /*argv*/[]) +{ + + LOG(info) << "Checking the packing and unpacking of PID signals (nsigmas) in the Femto PID response."; + if (process("Nsigma", 100000)) { + LOG(info) << "Packing and unpacking of PID signals (nsigmas) in the Femto PID response is correct."; + } else { + LOG(fatal) << "Packing and unpacking of PID signals (nsigmas) in the Femto PID response is incorrect."; + } + + LOG(info) << "Checking the packing and unpacking of PID signals (dca) in the Femto DCA."; + if (process("Dca", 100000)) { + LOG(info) << "Packing and unpacking of DCA signals (dca) in the Femto is correct."; + } else { + LOG(fatal) << "Packing and unpacking of DCA signals (dca) in the Femto is incorrect."; + } + +} // main diff --git a/PWGCF/FemtoDream/Core/femtoDreamCascadeSelection.h b/PWGCF/FemtoDream/Core/femtoDreamCascadeSelection.h new file mode 100644 index 00000000000..bc9289dc03a --- /dev/null +++ b/PWGCF/FemtoDream/Core/femtoDreamCascadeSelection.h @@ -0,0 +1,695 @@ +// Copyright 2019-2022 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 femtoDreamCascadeSelection.h +/// \brief Definition of the femtoDreamCascadeSelection +/// \author Valentina Mantovani Sarti, TU München valentina.mantovani-sarti@tum.de +/// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de +/// \author Luca Barioglio, TU München, luca.barioglio@cern.ch +/// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch +/// \author Barbara Chytla, WUT Warsaw, barbara.chytla@cern.ch +/// \author Shirajum Monira, WUT Warsaw, shirajum.monira@cern.ch +/// \author Georgios Mantzaridis, TU München, georgios.mantzaridis@tum.de + +#ifndef PWGCF_FEMTODREAM_CORE_FEMTODREAMCASCADESELECTION_H_ +#define PWGCF_FEMTODREAM_CORE_FEMTODREAMCASCADESELECTION_H_ + +#include +#include +#include + +#include // FIXME + +#include "PWGCF/FemtoDream/Core/femtoDreamObjectSelection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamSelection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamTrackSelection.h" + +#include "Common/Core/RecoDecay.h" +#include "Framework/HistogramRegistry.h" +#include "ReconstructionDataFormats/PID.h" + +using namespace o2::framework; + +namespace o2::analysis::femtoDream +{ +namespace femtoDreamCascadeSelection +{ +/// The different selections this task is capable of doing +enum CascadeSel { + kCascadeSign, ///< +1 particle, -1 antiparticle + kCascadePtMin, + kCascadePtMax, + kCascadeEtaMax, + kCascadeDCADaughMax, + kCascadeCPAMin, + kCascadeTranRadMin, + kCascadeTranRadMax, + kCascadeDecVtxMax, + kCascadeV0DCADaughMax, + kCascadeV0CPAMin, + kCascadeV0TranRadMin, + kCascadeV0TranRadMax, + kCascadeV0DCAtoPVMin, + kCascadeV0DCAtoPVMax +}; + +enum ChildTrackType { kPosTrack, + kNegTrack, + kBachTrack }; + +enum CascadeContainerPosition { + kCascade, + kPosCuts, + kPosPID, + kNegCuts, + kNegPID, + kBachCuts, + kBachPID, +}; /// Position in the full VO cut container (for cutculator) + +} // namespace femtoDreamCascadeSelection + +/// \class FemtoDreamCascadeSelection +/// \brief Cut class to contain and execute all cuts applied to Cascades +class FemtoDreamCascadeSelection + : public FemtoDreamObjectSelection +{ + public: + FemtoDreamCascadeSelection() + : nCascadePtMin(0), + nCascadePtMax(0), + nCascadeEtaMax(0), + nCascadeDCADaughMax(0), + nCascadeCPAMin(0), + nCascadeTranRadMin(0), + nCascadeTranRadMax(0), + nCascadeDecVtxMax(0), + nCascadeV0DCADaughMax(0), + nCascadeV0CPAMin(0), + nCascadeV0TranRadMin(0), + nCascadeV0TranRadMax(0), + nCascadeV0DCAToPVMin(0), + nCascadeV0DCAToPVMax(0), + + fCascadePtMin(9999999), + fCascadePtMax(-9999999), + fCascadeEtaMax(-9999999), + fCascadeDCADaughMax(-9999999), + fCascadeCPAMin(9999999), + fCascadeTranRadMin(9999999), + fCascadeTranRadMax(-9999999), + fCascadeDecVtxMax(-9999999), + fCascadeV0DCADaughMax(-9999999), + fCascadeV0CPAMin(9999999), + fCascadeV0TranRadMin(9999999), + fCascadeV0TranRadMax(-9999999), + fCascadeV0DCAToPVMin(9999999), + fCascadeV0DCAToPVMax(-9999999), + + fV0InvMassLowLimit(1.05), + fV0InvMassUpLimit(1.3), + fInvMassLowLimit(1.25), + fInvMassUpLimit(1.4), + fRejectCompetingMass(false), + fInvMassCompetingLowLimit(1.5), + fInvMassCompetingUpLimit(2.0), + isCascOmega(false) + { + } + + /// Initializes histograms for the task + template + void init(HistogramRegistry* QAregistry, HistogramRegistry* Registry, bool isSelectCascOmega = false); + + template + bool isSelectedMinimal(Col const& col, Casc const& cascade, Track const& posTrack, Track const& negTrack, Track const& bachTrack); + + template + void fillQA(Col const& col, Casc const& cascade, Track const& posTrack, Track const& negTrack, Track const& bachTrack); + + // template + // std::array getCutContainer(Col const& col, Casc const& casc, V0 const& v0Daugh, Track const& posTrack, Track const& negTrack, Track const& bachTrack); + template + std::array getCutContainer(Col const& col, Casc const& casc, Track const& posTrack, Track const& negTrack, Track const& bachTrack); + + template + void setChildCuts(femtoDreamCascadeSelection::ChildTrackType child, + T1 selVal, + T2 selVar, + femtoDreamSelection::SelectionType selType) + { + if (child == femtoDreamCascadeSelection::kPosTrack) { + PosDaughTrack.setSelection(selVal, selVar, selType); + } else if (child == femtoDreamCascadeSelection::kNegTrack) { + NegDaughTrack.setSelection(selVal, selVar, selType); + } else if (child == femtoDreamCascadeSelection::kBachTrack) { + BachDaughTrack.setSelection(selVal, selVar, selType); + } + } + + template + void setChildPIDSpecies(femtoDreamCascadeSelection::ChildTrackType child, + T& pids) + { + if (child == femtoDreamCascadeSelection::kPosTrack) { + PosDaughTrack.setPIDSpecies(pids); + } else if (child == femtoDreamCascadeSelection::kNegTrack) { + NegDaughTrack.setPIDSpecies(pids); + } else if (child == femtoDreamCascadeSelection::kBachTrack) { + BachDaughTrack.setPIDSpecies(pids); + } + } + + /// Helper function to obtain the name of a given selection criterion for consistent naming of the configurables + /// \param iSel Track selection variable to be examined + /// \param prefix Additional prefix for the name of the configurable + /// \param suffix Additional suffix for the name of the configurable + static std::string getSelectionName(femtoDreamCascadeSelection::CascadeSel iSel, + std::string_view prefix = "", + std::string_view suffix = "") + { + std::string outString = static_cast(prefix); + outString += static_cast(mSelectionNames[iSel]); + outString += suffix; + return outString; + } + + /// Helper function to obtain the index of a given selection variable for consistent naming of the configurables + /// \param obs Cascade selection variable (together with prefix) got from file + /// \param prefix Additional prefix for the output of the configurable + static int findSelectionIndex(const std::string_view& obs, + std::string_view prefix = "") + { + for (int index = 0; index < kNcascadeSelection; index++) { + std::string comp = static_cast(prefix) + + static_cast(mSelectionNames[index]); + std::string_view cmp{comp}; + if (obs.compare(cmp) == 0) + return index; + } + LOGF(info, "Variable %s not found", obs); + return -1; + } + + /// Helper function to obtain the type of a given selection variable for consistent naming of the configurables + /// \param iSel Casc selection variable whose type is returned + static femtoDreamSelection::SelectionType getSelectionType(femtoDreamCascadeSelection::CascadeSel iSel) + { + return mSelectionTypes[iSel]; + } + + /// Helper function to obtain the helper string of a given selection criterion + /// for consistent description of the configurables + /// \param iSel Track selection variable to be examined + /// \param prefix Additional prefix for the output of the configurable + static std::string getSelectionHelper(femtoDreamCascadeSelection::CascadeSel iSel, + std::string_view prefix = "") + { + std::string outString = static_cast(prefix); + outString += static_cast(mSelectionHelper[iSel]); + return outString; + } + + /// Set limit for the selection on the invariant mass + /// \param lowLimit Lower limit for the invariant mass distribution + /// \param upLimit Upper limit for the invariant mass distribution + void setInvMassLimits(float lowLimit, float upLimit) + { + fInvMassLowLimit = lowLimit; + fInvMassUpLimit = upLimit; + } + + void setV0InvMassLimits(float lowLimit, float upLimit) + { + fV0InvMassLowLimit = lowLimit; + fV0InvMassUpLimit = upLimit; + } + + /// Set limit for the omega rejection on the invariant mass + /// \param lowLimit Lower limit for the invariant mass distribution + /// \param upLimit Upper limit for the invariant mass distribution + void setCompetingInvMassLimits(float lowLimit, float upLimit) + { + fRejectCompetingMass = true; + fInvMassCompetingLowLimit = lowLimit; + fInvMassCompetingUpLimit = upLimit; + } + + private: + int nCascadePtMin; + int nCascadePtMax; + int nCascadeEtaMax; + int nCascadeDCADaughMax; + int nCascadeCPAMin; + int nCascadeTranRadMin; + int nCascadeTranRadMax; + int nCascadeDecVtxMax; + + int nCascadeV0DCADaughMax; + int nCascadeV0CPAMin; + int nCascadeV0TranRadMin; + int nCascadeV0TranRadMax; + int nCascadeV0DCAToPVMin; + int nCascadeV0DCAToPVMax; + + float fCascadePtMin; + float fCascadePtMax; + float fCascadeEtaMax; + float fCascadeDCADaughMax; + float fCascadeCPAMin; + float fCascadeTranRadMin; + float fCascadeTranRadMax; + float fCascadeDecVtxMax; + + float fCascadeV0DCADaughMax; + float fCascadeV0CPAMin; + float fCascadeV0TranRadMin; + float fCascadeV0TranRadMax; + float fCascadeV0DCAToPVMin; + float fCascadeV0DCAToPVMax; + + float fV0InvMassLowLimit; + float fV0InvMassUpLimit; + + float fInvMassLowLimit; + float fInvMassUpLimit; + + float fRejectCompetingMass; + float fInvMassCompetingLowLimit; + float fInvMassCompetingUpLimit; + + bool isCascOmega; + + // float nSigmaPIDOffsetTPC; + + FemtoDreamTrackSelection PosDaughTrack; + FemtoDreamTrackSelection NegDaughTrack; + FemtoDreamTrackSelection BachDaughTrack; + + static constexpr int kNcascadeSelection = 16; + + static constexpr std::string_view mSelectionNames[kNcascadeSelection] = { + "Sign", "PtMin", "PtMax", "EtaMax", "DCADaughMax", "CPAMin", "TranRadMin", "TranRadMax", "DecVtxMax", // Cascade Selections + "DCAv0daughMax", "v0CPAMin", "v0TranRadMin", "v0TranRadMax", "V0DCAToPVMin", "V0DCAToPVMax"}; // CascadeV0 selections + + static constexpr femtoDreamSelection::SelectionType + mSelectionTypes[kNcascadeSelection]{ + femtoDreamSelection::kEqual, // sign + femtoDreamSelection::kLowerLimit, // pt min + femtoDreamSelection::kUpperLimit, // pt max + femtoDreamSelection::kUpperLimit, // eta max + femtoDreamSelection::kUpperLimit, // DCA cascade daughters max + femtoDreamSelection::kLowerLimit, // cascade cos PA min + femtoDreamSelection::kLowerLimit, // cascade tran rad min + femtoDreamSelection::kUpperLimit, // cascade tran rad max + femtoDreamSelection::kUpperLimit, // cascade maximum distance of decay vertex to PV + femtoDreamSelection::kUpperLimit, // v0 daughters DCA max + femtoDreamSelection::kLowerLimit, // v0 cos PA min + femtoDreamSelection::kLowerLimit, // v0 tran rad min + femtoDreamSelection::kUpperLimit, // v0 tran rad max + femtoDreamSelection::kLowerLimit, // v0 minimum distance of decay vertex to PV + femtoDreamSelection::kUpperLimit // v0 maximum distance of decay vertex to PV + + }; ///< Map to match a variable with + ///< its type + + static constexpr std::string_view mSelectionHelper[kNcascadeSelection] = { + "Cascade particle sign (+1 or -1)", + "Minimum pT (GeV/c)", + "Maximum pT (GeV/c)", + "Maximum |Eta|", + "Maximum DCA between cascade daughters (cm)", + "Minimum Cosine of Pointing Angle for cascade", + "Minimum cascade transverse radius (cm)", + "Maximum cascade transverse radius (cm)", + "Maximum distance of cascade from primary vertex", + "Maximum DCA between v0 daughters (cm)", + "Minimum Cosine of Pointing Angle for v0", + "Minimum v0 transverse radius (cm)", + "Maximum v0 transverse radius (cm)", + "Minimum distance of v0 from primary vertex", + "Maximum distance of v0 from primary vertex" + + //"Minimum V0 mass", + //"Maximum V0 mass" + }; ///< Helper information for the + ///< different selections + + static constexpr int kNcutStages = 2; + static constexpr std::string_view mCutStage[kNcutStages] = {"BeforeSel", "AfterSel"}; +}; // namespace femtoDream + +template +void FemtoDreamCascadeSelection::init(HistogramRegistry* QAregistry, HistogramRegistry* Registry, bool isSelectCascOmega) +{ + + if (QAregistry && Registry) { + mHistogramRegistry = Registry; + mQAHistogramRegistry = QAregistry; + // fillSelectionHistogram(); // cascade + // fillSelectionHistogram(); // pos, neg + // fillSelectionHistogram(); // bach + + AxisSpec ptAxis = {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec etaAxis = {100, -2.0f, 2.0f, "#it{#eta}"}; + AxisSpec phiAxis = {100, 0.0f, 6.0f, "#it{#phi}"}; + AxisSpec DCADaughAxis = {1000, 0.0f, 2.0f, "DCA (cm)"}; + AxisSpec CPAAxis = {1000, 0.95f, 1.0f, "#it{cos #theta_{p}}"}; + AxisSpec tranRadAxis = {1000, 0.0f, 100.0f, "#it{r}_{xy} (cm)"}; + AxisSpec decVtxAxis = {2000, 0, 200, "#it{Vtx}_{z} (cm)"}; + AxisSpec massAxisCascade = {2200, 1.25f, 1.8f, "m_{#Cascade} (GeV/#it{c}^{2})"}; + + AxisSpec DCAToPVAxis = {1000, -10.0f, 10.0f, "DCA to PV (cm)"}; + + AxisSpec massAxisV0 = {600, 0.0f, 3.0f, "m_{#V0} (GeV/#it{c}^{2})"}; + + /// \todo this should be an automatic check in the parent class, and the + /// return type should be templated + size_t nSelections = getNSelections(); + if (nSelections > 8 * sizeof(cutContainerType)) { + LOGF(info, "Number of selections %i", nSelections); + LOG(fatal) << "FemtoDreamCascadeCuts: Number of selections to large for your " + "container - quitting!"; + } + + std::string folderName = static_cast(o2::aod::femtodreamparticle::ParticleTypeName[part]); + for (int istage = 0; istage < kNcutStages; istage++) { + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hSign").c_str(), "; Sign of the Cascade ; Entries", kTH1I, {{3, -1, 2}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hPt").c_str(), "; #it{p}_{T} (GeV/#it{c}); Entries", kTH1F, {{1000, 0, 10}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hEta").c_str(), "; #eta; Entries", kTH1F, {{1000, -1, 1}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hPhi").c_str(), "; #phi; Entries", kTH1F, {{1000, 0, 2. * M_PI}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hDCADaugh").c_str(), "; daughters DCA; Entries", kTH1F, {DCADaughAxis}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hCPA").c_str(), "; Cos PA; Entries", kTH1F, {CPAAxis}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hTranRad").c_str(), "; Transverse Radius; Entries", kTH1F, {tranRadAxis}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hDecVtxX").c_str(), "; Decay vertex x position; Entries", kTH1F, {tranRadAxis}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hDecVtxY").c_str(), "; Decay vertex y position; Entries", kTH1F, {tranRadAxis}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hDecVtxZ").c_str(), "; Decay vertex z position; Entries", kTH1F, {tranRadAxis}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hInvMass").c_str(), "; Invariant mass; Entries", kTH1F, {massAxisCascade}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hV0DCADaugh").c_str(), "; V0-daughters DCA; Entries", kTH1F, {DCADaughAxis}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hV0CPA").c_str(), "; V0 cos PA; Entries", kTH1F, {CPAAxis}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hV0TranRad").c_str(), "; V0 transverse radius; Entries", kTH1F, {tranRadAxis}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hV0DCAToPV").c_str(), "; DCA of the V0 to the PV; Entries", kTH1F, {DCAToPVAxis}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hV0InvMass").c_str(), "; Invariant mass Cascade V0; Entries", kTH1F, {massAxisV0}); + } + + PosDaughTrack.init(mQAHistogramRegistry, mHistogramRegistry); + + NegDaughTrack.init(mQAHistogramRegistry, mHistogramRegistry); + + BachDaughTrack.init(mQAHistogramRegistry, mHistogramRegistry); + } + + /// check whether the most open cuts are fulfilled - most of this should have + /// already be done by the filters + nCascadePtMin = getNSelections(femtoDreamCascadeSelection::kCascadePtMin); + nCascadePtMax = getNSelections(femtoDreamCascadeSelection::kCascadePtMax); + nCascadeEtaMax = getNSelections(femtoDreamCascadeSelection::kCascadeEtaMax); + nCascadeDCADaughMax = getNSelections(femtoDreamCascadeSelection::kCascadeDCADaughMax); + nCascadeCPAMin = getNSelections(femtoDreamCascadeSelection::kCascadeCPAMin); + nCascadeTranRadMin = getNSelections(femtoDreamCascadeSelection::kCascadeTranRadMin); + nCascadeTranRadMax = getNSelections(femtoDreamCascadeSelection::kCascadeTranRadMax); + nCascadeDecVtxMax = getNSelections(femtoDreamCascadeSelection::kCascadeDecVtxMax); + + nCascadeV0DCADaughMax = getNSelections(femtoDreamCascadeSelection::kCascadeV0DCADaughMax); + nCascadeV0CPAMin = getNSelections(femtoDreamCascadeSelection::kCascadeV0CPAMin); + nCascadeV0TranRadMin = getNSelections(femtoDreamCascadeSelection::kCascadeV0TranRadMin); + nCascadeV0TranRadMax = getNSelections(femtoDreamCascadeSelection::kCascadeV0TranRadMax); + + nCascadeV0DCAToPVMin = getNSelections(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMin); + nCascadeV0DCAToPVMax = getNSelections(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMax); + + fCascadePtMin = getMinimalSelection(femtoDreamCascadeSelection::kCascadePtMin, + femtoDreamSelection::kLowerLimit); + fCascadePtMax = getMinimalSelection(femtoDreamCascadeSelection::kCascadePtMax, + femtoDreamSelection::kUpperLimit); + fCascadeEtaMax = getMinimalSelection(femtoDreamCascadeSelection::kCascadeEtaMax, + femtoDreamSelection::kAbsUpperLimit); + fCascadeDCADaughMax = getMinimalSelection(femtoDreamCascadeSelection::kCascadeDCADaughMax, + femtoDreamSelection::kUpperLimit); + fCascadeCPAMin = getMinimalSelection(femtoDreamCascadeSelection::kCascadeCPAMin, + femtoDreamSelection::kLowerLimit); + fCascadeTranRadMin = getMinimalSelection(femtoDreamCascadeSelection::kCascadeTranRadMin, + femtoDreamSelection::kLowerLimit); + fCascadeTranRadMax = getMinimalSelection(femtoDreamCascadeSelection::kCascadeTranRadMax, + femtoDreamSelection::kUpperLimit); + fCascadeDecVtxMax = getMinimalSelection(femtoDreamCascadeSelection::kCascadeDecVtxMax, + femtoDreamSelection::kAbsUpperLimit); + fCascadeV0DCADaughMax = getMinimalSelection(femtoDreamCascadeSelection::kCascadeV0DCADaughMax, + femtoDreamSelection::kUpperLimit); + fCascadeV0CPAMin = getMinimalSelection(femtoDreamCascadeSelection::kCascadeV0CPAMin, + femtoDreamSelection::kLowerLimit); + fCascadeV0TranRadMin = getMinimalSelection(femtoDreamCascadeSelection::kCascadeV0TranRadMin, + femtoDreamSelection::kLowerLimit); + fCascadeV0TranRadMax = getMinimalSelection(femtoDreamCascadeSelection::kCascadeV0TranRadMax, + femtoDreamSelection::kUpperLimit); + fCascadeV0DCAToPVMin = getMinimalSelection(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMin, + femtoDreamSelection::kLowerLimit); + fCascadeV0DCAToPVMax = getMinimalSelection(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMax, + femtoDreamSelection::kUpperLimit); + isCascOmega = isSelectCascOmega; +} + +template +bool FemtoDreamCascadeSelection::isSelectedMinimal(Col const& col, Casc const& cascade, Track const& posTrack, Track const& negTrack, Track const& bachTrack) +{ + const auto signPos = posTrack.sign(); + const auto signNeg = negTrack.sign(); + + if (signPos < 0 || signNeg > 0) { + LOG(warn) << "Something wrong in isSelectedMinimal"; + LOG(warn) << "ERROR - Wrong sign for V0 daughters"; + } + + const std::vector decVtx = {cascade.x(), cascade.y(), cascade.z()}; + + const float cpav0 = cascade.v0cosPA(col.posX(), col.posY(), col.posZ()); + const float cpaCasc = cascade.casccosPA(col.posX(), col.posY(), col.posZ()); + const float v0dcatopv = cascade.dcav0topv(col.posX(), col.posY(), col.posZ()); + const float invMassLambda = cascade.mLambda(); + const float invMass = isCascOmega ? cascade.mOmega() : cascade.mXi(); + // const float invMass = cascade.mXi(); + + if (invMassLambda < fV0InvMassLowLimit || invMassLambda > fV0InvMassUpLimit) { + return false; + } + + if (invMass < fInvMassLowLimit || invMass > fInvMassUpLimit) { + return false; + } + + if (fRejectCompetingMass) { + const float invMassCompeting = isCascOmega ? cascade.mXi() : cascade.mOmega(); + if (invMassCompeting > fInvMassCompetingLowLimit && + invMassCompeting < fInvMassCompetingUpLimit) { + return false; + } + } + + if (nCascadePtMin > 0 && cascade.pt() < fCascadePtMin) { + return false; + } + if (nCascadePtMax > 0 && cascade.pt() > fCascadePtMax) { + return false; + } + if (nCascadeEtaMax > 0 && std::fabs(cascade.eta()) > fCascadeEtaMax) { + return false; + } + if (nCascadeDCADaughMax > 0 && cascade.dcacascdaughters() > fCascadeDCADaughMax) { + return false; + } + if (fCascadeCPAMin > 0 && cpaCasc < fCascadeCPAMin) { + return false; + } + if (nCascadeTranRadMin > 0 && cascade.cascradius() < fCascadeTranRadMin) { + return false; + } + if (nCascadeTranRadMax > 0 && cascade.cascradius() > fCascadeTranRadMax) { + return false; + } + for (size_t i = 0; i < decVtx.size(); i++) { + if (nCascadeDecVtxMax > 0 && decVtx.at(i) > fCascadeDecVtxMax) { + return false; + } + } + + // v0 criteria + if (nCascadeV0DCADaughMax > 0 && cascade.dcaV0daughters() > fCascadeV0DCADaughMax) { + return false; + } + if (nCascadeV0CPAMin > 0 && cpav0 < fCascadeV0CPAMin) { + return false; + } + if (nCascadeV0TranRadMin > 0 && cascade.v0radius() < fCascadeV0TranRadMin) { + return false; + } + if (nCascadeV0TranRadMax > 0 && cascade.v0radius() > fCascadeV0TranRadMax) { + return false; + } + if (nCascadeV0DCAToPVMin > 0 && std::fabs(v0dcatopv) < fCascadeV0DCAToPVMin) { + return false; + } + if (nCascadeV0DCAToPVMax > 0 && std::fabs(v0dcatopv) > fCascadeV0DCAToPVMax) { + return false; + } + + // Chech the selection criteria for the tracks as well + if (!PosDaughTrack.isSelectedMinimal(posTrack)) { + return false; + } + if (!NegDaughTrack.isSelectedMinimal(negTrack)) { + return false; + } + if (!BachDaughTrack.isSelectedMinimal(bachTrack)) { + return false; + } + + return true; +} + +template +std::array FemtoDreamCascadeSelection::getCutContainer(Col const& col, Casc const& casc, Track const& posTrack, Track const& negTrack, Track const& bachTrack) +{ + auto outputPosTrack = PosDaughTrack.getCutContainer(posTrack, posTrack.pt(), posTrack.eta(), posTrack.dcaXY()); + auto outputNegTrack = NegDaughTrack.getCutContainer(negTrack, negTrack.pt(), negTrack.eta(), negTrack.dcaXY()); + auto outputBachTrack = BachDaughTrack.getCutContainer(bachTrack, bachTrack.pt(), bachTrack.eta(), bachTrack.dcaXY()); + + cutContainerType output = 0; + size_t counter = 0; + + float sign = 0.; + if (casc.sign() < 0) { + sign = -1.; + } else { + sign = 1.; + } + + const auto cpaCasc = casc.casccosPA(col.posX(), col.posY(), col.posZ()); + const std::vector decVtx = {casc.x(), casc.y(), casc.z()}; + const auto cpav0 = casc.v0cosPA(col.posX(), col.posY(), col.posZ()); + const auto v0dcatopv = casc.dcav0topv(col.posX(), col.posY(), col.posZ()); + + float observable = 0.; + for (auto& sel : mSelections) { + + const auto selVariable = sel.getSelectionVariable(); + switch (selVariable) { + case (femtoDreamCascadeSelection::kCascadeSign): + observable = sign; + break; + case (femtoDreamCascadeSelection::kCascadePtMin): + observable = casc.pt(); + break; + case (femtoDreamCascadeSelection::kCascadePtMax): + observable = casc.pt(); + break; + case (femtoDreamCascadeSelection::kCascadeEtaMax): + observable = casc.eta(); + break; + case (femtoDreamCascadeSelection::kCascadeDCADaughMax): + observable = casc.dcacascdaughters(); + break; + case (femtoDreamCascadeSelection::kCascadeCPAMin): + observable = cpaCasc; + break; + case (femtoDreamCascadeSelection::kCascadeTranRadMin): + observable = casc.cascradius(); + break; + case (femtoDreamCascadeSelection::kCascadeTranRadMax): + observable = casc.cascradius(); + break; + // kCascadeDecVtxMax is done above + case (femtoDreamCascadeSelection::kCascadeDecVtxMax): + for (size_t i = 0; i < decVtx.size(); ++i) { + auto decVtxValue = decVtx.at(i); + sel.checkSelectionSetBit(decVtxValue, output, counter, nullptr); + } + continue; + break; + + case (femtoDreamCascadeSelection::kCascadeV0DCADaughMax): + observable = casc.dcaV0daughters(); + break; + case (femtoDreamCascadeSelection::kCascadeV0CPAMin): + observable = cpav0; + break; + case (femtoDreamCascadeSelection::kCascadeV0TranRadMin): + observable = casc.v0radius(); + break; + case (femtoDreamCascadeSelection::kCascadeV0TranRadMax): + observable = casc.v0radius(); + break; + case (femtoDreamCascadeSelection::kCascadeV0DCAtoPVMin): + observable = v0dcatopv; + break; + case (femtoDreamCascadeSelection::kCascadeV0DCAtoPVMax): + observable = v0dcatopv; + break; + } // switch + sel.checkSelectionSetBit(observable, output, counter, nullptr); + } // for loop + + return { + output, + outputPosTrack.at(femtoDreamTrackSelection::TrackContainerPosition::kCuts), + outputPosTrack.at(femtoDreamTrackSelection::TrackContainerPosition::kPID), + outputNegTrack.at(femtoDreamTrackSelection::TrackContainerPosition::kCuts), + outputNegTrack.at(femtoDreamTrackSelection::TrackContainerPosition::kPID), + outputBachTrack.at(femtoDreamTrackSelection::TrackContainerPosition::kCuts), + outputBachTrack.at(femtoDreamTrackSelection::TrackContainerPosition::kPID)}; +} + +template +void FemtoDreamCascadeSelection::fillQA(Col const& col, Casc const& casc, Track const& posTrack, Track const& negTrack, Track const& bachTrack) +{ + + const std::vector decVtx = {casc.x(), casc.y(), casc.z()}; + const float cpaCasc = casc.casccosPA(col.posX(), col.posY(), col.posZ()); + const float cpav0 = casc.v0cosPA(col.posX(), col.posY(), col.posZ()); + const float v0dcatopv = casc.dcav0topv(col.posX(), col.posY(), col.posZ()); + if (mQAHistogramRegistry) { + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hSign"), casc.sign()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hPt"), casc.pt()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hEta"), casc.eta()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hPhi"), casc.phi()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hDCADaugh"), casc.dcacascdaughters()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hCPA"), cpaCasc); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hTranRad"), casc.cascradius()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hDecVtxX"), decVtx.at(0)); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hDecVtxY"), decVtx.at(1)); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hDecVtxZ"), decVtx.at(2)); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hInvMass"), casc.mXi()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hV0DCADaugh"), casc.dcaV0daughters()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hV0CPA"), cpav0); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hV0TranRad"), casc.v0radius()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hV0DCAToPV"), v0dcatopv); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hV0InvMass"), casc.mLambda()); + + PosDaughTrack.fillQA(posTrack); + NegDaughTrack.fillQA(negTrack); + BachDaughTrack.fillQA(bachTrack); + } +} + +} // namespace o2::analysis::femtoDream + +#endif // PWGCF_FEMTODREAM_CORE_FEMTODREAMCASCADESELECTION_H_ diff --git a/PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h b/PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h index 5a43a5f6e3b..ef647b69f52 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h +++ b/PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h @@ -136,6 +136,21 @@ class FemtoDreamCollisionSelection return true; } + template + bool isCollisionWithoutTrkCasc(C const& col, Casc const& Cascades, CascC& CascadeCuts, T const& /*Tracks*/) + { + // check if there is no selected Cascade + for (auto const& Cascade : Cascades) { + auto postrack = Cascade.template posTrack_as(); + auto negtrack = Cascade.template negTrack_as(); + auto bachtrack = Cascade.template bachelor_as(); + if (CascadeCuts.isSelectedMinimal(col, Cascade, postrack, negtrack, bachtrack)) { + return false; + } + } + return true; + } + /// Some basic QA of the event /// \tparam T type of the collision /// \param col Collision diff --git a/PWGCF/FemtoDream/Core/femtoDreamContainer.h b/PWGCF/FemtoDream/Core/femtoDreamContainer.h index 761df292f63..8a9038e6198 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamContainer.h +++ b/PWGCF/FemtoDream/Core/femtoDreamContainer.h @@ -35,7 +35,6 @@ using namespace o2::framework; namespace o2::analysis::femtoDream { - namespace femtoDreamContainer { /// Femtoscopic observable to be computed @@ -70,13 +69,18 @@ class FemtoDreamContainer /// \param multAxis axis object for the multiplicity axis /// \param kTAxis axis object for the kT axis /// \param mTAxis axis object for the mT axis - template + + template void init_base(std::string folderName, std::string femtoObs, T& femtoObsAxis, T& pTAxis, T& kTAxis, T& mTAxis, T& multAxis, T& multPercentileAxis, T& /*kstarAxis4D*/, T& mTAxis4D, T& multAxis4D, T& multPercentileAxis4D, - bool use4dplots, bool extendedplots) + bool use4dplots, bool extendedplots, T& mP2Axis) { + if constexpr (isHF) { + mHistogramRegistry->add((folderName + "/relPairkstarmP2").c_str(), ("; " + femtoObs + "; Mass (GeV)").c_str(), kTH2F, {femtoObsAxis, mP2Axis}); + } + mHistogramRegistry->add((folderName + "/relPairDist").c_str(), ("; " + femtoObs + "; Entries").c_str(), kTH1F, {femtoObsAxis}); mHistogramRegistry->add((folderName + "/relPairkT").c_str(), "; #it{k}_{T} (GeV/#it{c}); Entries", kTH1F, {kTAxis}); mHistogramRegistry->add((folderName + "/relPairkstarkT").c_str(), ("; " + femtoObs + "; #it{k}_{T} (GeV/#it{c})").c_str(), kTH2F, {femtoObsAxis, kTAxis}); @@ -94,7 +98,7 @@ class FemtoDreamContainer mHistogramRegistry->add((folderName + "/relPairkstarmTMultMultPercentile").c_str(), ("; " + femtoObs + "; #it{m}_{T} (GeV/#it{c}^{2}); Multiplicity").c_str(), kTHnSparseF, {femtoObsAxis, mTAxis4D, multAxis4D, multPercentileAxis4D}); } if (extendedplots) { - mHistogramRegistry->add((folderName + "/mTPtPart1PtPart2MultPercentile").c_str(), "; #it{m}_{T} (GeV/#it{c}^{2}); #it{p} _{T} Particle 1 (GeV/#it{c}); #it{p} _{T} Particle 2 (GeV/#it{c}); Multiplicity Percentile (%)", kTHnSparseF, {mTAxis4D, pTAxis, pTAxis, multPercentileAxis4D}); + mHistogramRegistry->add((folderName + "/relPairkstarmTPtPart1PtPart2MultPercentile").c_str(), ("; :" + femtoObs + "; #it{m}_{T} (GeV/#it{c}^{2}); #it{p} _{T} Particle 1 (GeV/#it{c}); #it{p} _{T} Particle 2 (GeV/#it{c}); Multiplicity Percentile (%)").c_str(), kTHnSparseF, {femtoObsAxis, mTAxis4D, pTAxis, pTAxis, multPercentileAxis4D}); } } @@ -131,13 +135,13 @@ class FemtoDreamContainer /// \param kTBins kT binning for the histograms /// \param mTBins mT binning for the histograms /// \param isMC add Monte Carlo truth histograms to the output file - template + template void init(HistogramRegistry* registry, T& kstarBins, T& pTBins, T& kTBins, T& mTBins, T& multBins, T& /*multPercentileBins*/, T& kstarBins4D, T& mTBins4D, T& multBins4D, T& multPercentileBins4D, bool isMC, bool use4dplots, bool extendedplots, float highkstarCut, - bool smearingByOrigin = false) + bool smearingByOrigin = false, ConfigurableAxis invMassBin = {"invMassBin", {250, 2.0, 2.5}, "InvMass binning"}) { mHistogramRegistry = registry; std::string femtoObs; @@ -157,18 +161,21 @@ class FemtoDreamContainer framework::AxisSpec multAxis4D = {multBins4D, "Multiplicity"}; framework::AxisSpec multPercentileAxis4D = {multPercentileBins4D, "Multiplicity Percentile (%)"}; + framework::AxisSpec mP2Axis = {invMassBin, "Mass (GeV)"}; + std::string folderName = static_cast(mFolderSuffix[mEventType]) + static_cast(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kRecon]); - init_base(folderName, femtoObs, - femtoObsAxis, pTAxis, kTAxis, mTAxis, multAxis, multPercentileAxis, - kstarAxis4D, mTAxis4D, multAxis4D, multPercentileAxis4D, - use4dplots, extendedplots); + init_base(folderName, femtoObs, + femtoObsAxis, pTAxis, kTAxis, mTAxis, multAxis, multPercentileAxis, + kstarAxis4D, mTAxis4D, multAxis4D, multPercentileAxis4D, + use4dplots, extendedplots, mP2Axis); + if (isMC) { folderName = static_cast(mFolderSuffix[mEventType]) + static_cast(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kTruth]); - init_base(folderName, femtoObs, - femtoObsAxis, pTAxis, kTAxis, mTAxis, multAxis, multPercentileAxis, - kstarAxis4D, mTAxis4D, multAxis4D, multPercentileAxis4D, - use4dplots, extendedplots); + init_base(folderName, femtoObs, + femtoObsAxis, pTAxis, kTAxis, mTAxis, multAxis, multPercentileAxis, + kstarAxis4D, mTAxis4D, multAxis4D, multPercentileAxis4D, + use4dplots, extendedplots, mP2Axis); init_MC(folderName, femtoObs, femtoObsAxis, multAxis, mTAxis, smearingByOrigin); } } @@ -190,10 +197,19 @@ class FemtoDreamContainer /// \param part1 Particle one /// \param part2 Particle two /// \param mult Multiplicity of the event - template - void setPair_base(const float femtoObs, const float mT, T const& part1, T const& part2, const int mult, const float multPercentile, bool use4dplots, bool extendedplots) + template + void setPair_base(const float femtoObs, const float mT, T1 const& part1, T2 const& part2, const int mult, const float multPercentile, bool use4dplots, bool extendedplots) { const float kT = FemtoDreamMath::getkT(part1, mMassOne, part2, mMassTwo); + if constexpr (isHF) { + float mP2; + if (part2.candidateSelFlag() == o2::aod::fdhf::lcToPKPi) { + mP2 = part2.m(std::array{o2::constants::physics::MassProton, o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); + } else { + mP2 = part2.m(std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus, o2::constants::physics::MassProton}); + } + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/relPairkstarmP2"), femtoObs, mP2); + } mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/relPairDist"), femtoObs); mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/relPairkT"), kT); mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/relPairkstarkT"), femtoObs, kT); @@ -211,7 +227,7 @@ class FemtoDreamContainer mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/relPairkstarmTMultMultPercentile"), femtoObs, mT, mult, multPercentile); } if (extendedplots) { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/mTPtPart1PtPart2MultPercentile"), mT, part1.pt(), part2.pt(), multPercentile); + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/relPairkstarmTPtPart1PtPart2MultPercentile"), femtoObs, mT, part1.pt(), part2.pt(), multPercentile); } } @@ -245,8 +261,8 @@ class FemtoDreamContainer /// \param part1 Particle one /// \param part2 Particle two /// \param mult Multiplicity of the event - template - void setPair(T const& part1, T const& part2, const int mult, const float multPercentile, bool use4dplots, bool extendedplots, bool smearingByOrigin = false) + template + void setPair(T1 const& part1, T2 const& part2, const int mult, const float multPercentile, bool use4dplots, bool extendedplots, bool smearingByOrigin = false) { float femtoObs, femtoObsMC; // Calculate femto observable and the mT with reconstructed information @@ -261,10 +277,24 @@ class FemtoDreamContainer const float mT = FemtoDreamMath::getmT(part1, mMassOne, part2, mMassTwo); if (mHistogramRegistry) { - setPair_base(femtoObs, mT, part1, part2, mult, multPercentile, use4dplots, extendedplots); + setPair_base(femtoObs, mT, part1, part2, mult, multPercentile, use4dplots, extendedplots); if constexpr (isMC) { - if (part1.has_fdMCParticle() && part2.has_fdMCParticle()) { + if constexpr (isHF) { + // calculate the femto observable and the mT with MC truth information + if constexpr (mFemtoObs == femtoDreamContainer::Observable::kstar) { + femtoObsMC = FemtoDreamMath::getkstar(part1.fdMCParticle(), mMassOne, part2, mMassTwo); + } + const float mTMC = FemtoDreamMath::getmT(part1.fdMCParticle(), mMassOne, part2, mMassTwo); + + if (abs(part1.fdMCParticle().pdgMCTruth()) == mPDGOne) { // Note: all pair-histogramms are filled with MC truth information ONLY in case of non-fake candidates + setPair_base(femtoObsMC, mTMC, part1.fdMCParticle(), part2, mult, multPercentile, use4dplots, extendedplots); + setPair_MC(femtoObsMC, femtoObs, mT, mult, part1.fdMCParticle().partOriginMCTruth(), part2.flagMc(), smearingByOrigin); + } else { + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kTruth]) + HIST("/hFakePairsCounter"), 0); + } + + } else if (part1.has_fdMCParticle() && part2.has_fdMCParticle()) { // calculate the femto observable and the mT with MC truth information if constexpr (mFemtoObs == femtoDreamContainer::Observable::kstar) { femtoObsMC = FemtoDreamMath::getkstar(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo); @@ -272,7 +302,7 @@ class FemtoDreamContainer const float mTMC = FemtoDreamMath::getmT(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo); if (abs(part1.fdMCParticle().pdgMCTruth()) == mPDGOne && abs(part2.fdMCParticle().pdgMCTruth()) == mPDGTwo) { // Note: all pair-histogramms are filled with MC truth information ONLY in case of non-fake candidates - setPair_base(femtoObsMC, mTMC, part1.fdMCParticle(), part2.fdMCParticle(), mult, multPercentile, use4dplots, extendedplots); + setPair_base(femtoObsMC, mTMC, part1.fdMCParticle(), part2.fdMCParticle(), mult, multPercentile, use4dplots, extendedplots); setPair_MC(femtoObsMC, femtoObs, mT, mult, part1.fdMCParticle().partOriginMCTruth(), part2.fdMCParticle().partOriginMCTruth(), smearingByOrigin); } else { mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kTruth]) + HIST("/hFakePairsCounter"), 0); diff --git a/PWGCF/FemtoDream/Core/femtoDreamContainerThreeBody.h b/PWGCF/FemtoDream/Core/femtoDreamContainerThreeBody.h index c4d1ebe5e66..b1c2c322cd8 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamContainerThreeBody.h +++ b/PWGCF/FemtoDream/Core/femtoDreamContainerThreeBody.h @@ -74,6 +74,10 @@ class FemtoDreamContainerThreeBody mHistogramRegistry->add((folderName + "/relTripletDist").c_str(), ("; " + femtoObs + "; Entries").c_str(), kTH1F, {femtoObsAxis}); mHistogramRegistry->add((folderName + "/relTripletQ3Mult").c_str(), ("; " + femtoObs + "; Multiplicity").c_str(), kTH2F, {femtoObsAxis, multAxis}); + mHistogramRegistry->add((folderName + "/mT1").c_str(), ";mT; Q3", kTH2F, {{1000, 0, 25}, femtoObsAxis}); + mHistogramRegistry->add((folderName + "/mT2").c_str(), ";mT; Q3", kTH2F, {{1000, 0, 25}, femtoObsAxis}); + mHistogramRegistry->add((folderName + "/mT3").c_str(), ";mT; Q3", kTH2F, {{1000, 0, 25}, femtoObsAxis}); + mHistogramRegistry->add((folderName + "/mTAverage").c_str(), ";mT; Q3", kTH2F, {{1000, 0, 25}, femtoObsAxis}); } /// Initializes specialized Monte Carlo truth histograms for the task in case of three-body femtoscopy @@ -145,6 +149,7 @@ class FemtoDreamContainerThreeBody template void setTriplet_base(const float femtoObs, T const& /*part1*/, T const& /*part2*/, T const& /*part3*/, const int mult) { + // FILL MAIN Q3 info mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/relTripletDist"), femtoObs); mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/relTripletQ3Mult"), femtoObs, mult); } @@ -180,6 +185,15 @@ class FemtoDreamContainerThreeBody void setTriplet(T const& part1, T const& part2, T const& part3, const int mult, const float femtoObs) { float femtoObsMC; + float mT1 = FemtoDreamMath::getmT(part1, mMassOne, part2, mMassTwo); + float mT2 = FemtoDreamMath::getmT(part2, mMassTwo, part3, mMassThree); + float mT3 = FemtoDreamMath::getmT(part1, mMassOne, part3, mMassThree); + float mTAverage = (mT1 + mT2 + mT3) / 3.; + // FILL mT info + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kRecon]) + HIST("/mT1"), mT1, femtoObs); + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kRecon]) + HIST("/mT2"), mT2, femtoObs); + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kRecon]) + HIST("/mT3"), mT3, femtoObs); + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kRecon]) + HIST("/mTAverage"), mTAverage, femtoObs); if (mHistogramRegistry) { setTriplet_base(femtoObs, part1, part2, part3, mult); diff --git a/PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h b/PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h index d9ad6d3e0c0..d8711b6fbc5 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h +++ b/PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h @@ -34,6 +34,14 @@ namespace femtoDream /// \brief Class to check particles for the close pair rejection. /// \tparam partOne Type of particle 1 (Track/V0/Cascade/...) /// \tparam partTwo Type of particle 2 (Track/V0/Cascade/...) + +enum ProngCharmHadron { + Prong0 = 0, + Prong1 = 1, + Prong2 = 2, + Nprongs = 3 +}; + template class FemtoDreamDetaDphiStar { @@ -41,7 +49,8 @@ class FemtoDreamDetaDphiStar /// Destructor virtual ~FemtoDreamDetaDphiStar() = default; /// Initialization of the histograms and setting required values - void init(HistogramRegistry* registry, HistogramRegistry* registryQA, float ldeltaPhiMax, float ldeltaEtaMax, bool lplotForEveryRadii, int meORse = 0, bool oldversion = true, float Q3Limit = 8., bool isMELambda = false) + // atWhichRadiiToCut - at which radii apply deta dphi cut; 0 - PV; 1 - average phi at given tpc radii, 2 - at 80 cm + void init(HistogramRegistry* registry, HistogramRegistry* registryQA, float ldeltaPhiMax, float ldeltaEtaMax, bool lplotForEveryRadii, int meORse = 0, bool oldversion = true, float Q3Limit = 8., bool isMELambda = false, int atWhichRadiiToCut = 1, float radiiTPCtoCut = 85., bool fillTHSparse = false) { deltaPhiMax = ldeltaPhiMax; deltaEtaMax = ldeltaEtaMax; @@ -51,61 +60,157 @@ class FemtoDreamDetaDphiStar runOldVersion = oldversion; mHistogramRegistry = registry; mHistogramRegistryQA = registryQA; + atWhichRadiiToSelect = atWhichRadiiToCut; + radiiTPC = radiiTPCtoCut; + fillQA = fillTHSparse; - if constexpr (mPartOneType == o2::aod::femtodreamparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kTrack) { + if constexpr (mPartOneType == o2::aod::femtodreamparticle::ParticleType::kTrack && (mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kTrack || mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kCascadeV0Child || mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kCascadeBachelor)) { std::string dirName = static_cast(dirNames[0]); - histdetadpi[0][0] = mHistogramRegistry->add((dirName + static_cast(histNames[0][0]) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpi[0][1] = mHistogramRegistry->add((dirName + static_cast(histNames[1][0]) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpi[0][0] = mHistogramRegistry->add((dirName + static_cast(histNames[0][0]) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpi[0][1] = mHistogramRegistry->add((dirName + static_cast(histNames[1][0]) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpi[0][2] = mHistogramRegistry->add((dirName + "at_PV_before" + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpi[0][3] = mHistogramRegistry->add((dirName + "at_PV_after" + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); if (plotForEveryRadii) { for (int i = 0; i < 9; i++) { - histdetadpiRadii[0][i] = mHistogramRegistryQA->add((dirName + static_cast(histNamesRadii[0][i]) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpiRadii[0][i] = mHistogramRegistryQA->add((dirName + static_cast(histNamesRadii[0][i]) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); } } + if (fillQA) { + histdetadpi_eta[0] = mHistogramRegistry->add((dirName + "dEtadPhi_Eta" + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}; #eta_{1}; #eta_{2}", kTHnSparseF, {{100, -0.15, 0.15}, {100, -0.15, 0.15}, {100, -0.8, 0.8}, {100, -0.8, 0.8}}); + histdetadpi_phi[0] = mHistogramRegistry->add((dirName + "dEtadPhi_Phi" + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}; #phi_{1}; #phi_{2}", kTHnSparseF, {{100, -0.15, 0.15}, {100, -0.15, 0.15}, {100, 0, 6.28}, {100, 0, 6.28}}); + } } if constexpr (mPartOneType == o2::aod::femtodreamparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kV0) { for (int i = 0; i < 2; i++) { std::string dirName = static_cast(dirNames[1]); - histdetadpi[i][0] = mHistogramRegistry->add((dirName + static_cast(histNames[0][i]) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpi[i][1] = mHistogramRegistry->add((dirName + static_cast(histNames[1][i]) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpi[i][0] = mHistogramRegistry->add((dirName + static_cast(histNames[0][i]) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpi[i][1] = mHistogramRegistry->add((dirName + static_cast(histNames[1][i]) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpi[i][2] = mHistogramRegistry->add((dirName + "at_PV_" + std::to_string(i) + "_before" + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpi[i][3] = mHistogramRegistry->add((dirName + "at_PV_" + std::to_string(i) + "_after" + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + if (plotForEveryRadii) { + for (int j = 0; j < 9; j++) { + histdetadpiRadii[i][j] = mHistogramRegistryQA->add((dirName + static_cast(histNamesRadii[i][j]) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + } + } + if (fillQA) { + histdetadpi_eta[i] = mHistogramRegistry->add((dirName + "dEtadPhi_Eta_" + std::to_string(i) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}; #eta_{1}; #eta_{2}", kTHnSparseF, {{100, -0.15, 0.15}, {100, -0.15, 0.15}, {100, -0.8, 0.8}, {100, -0.8, 0.8}}); + histdetadpi_phi[i] = mHistogramRegistry->add((dirName + "dEtadPhi_Phi_" + std::to_string(i) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}; #phi_{1}; #phi_{2}", kTHnSparseF, {{100, -0.15, 0.15}, {100, -0.15, 0.15}, {100, 0, 6.28}, {100, 0, 6.28}}); + } + } + } + if constexpr (mPartOneType == o2::aod::femtodreamparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kCharmHadron) { + for (int i = 0; i < Nprongs; i++) { + std::string dirName = static_cast(dirNames[2]); + histdetadpi[i][0] = mHistogramRegistry->add((dirName + static_cast(histNames[0][i]) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpi[i][1] = mHistogramRegistry->add((dirName + static_cast(histNames[1][i]) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpi[i][2] = mHistogramRegistry->add((dirName + "at_PV_" + std::to_string(i) + "_before" + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpi[i][3] = mHistogramRegistry->add((dirName + "at_PV_" + std::to_string(i) + "_after" + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); if (plotForEveryRadii) { for (int j = 0; j < 9; j++) { histdetadpiRadii[i][j] = mHistogramRegistryQA->add((dirName + static_cast(histNamesRadii[i][j]) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); } } + if (fillQA) { + histdetadpi_eta[i] = mHistogramRegistry->add((dirName + "dEtadPhi_Eta_" + std::to_string(i) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}; #eta_{1}; #eta_{2}", kTHnSparseF, {{100, -0.15, 0.15}, {100, -0.15, 0.15}, {100, -0.8, 0.8}, {100, -0.8, 0.8}}); + histdetadpi_phi[i] = mHistogramRegistry->add((dirName + "dEtadPhi_Phi_" + std::to_string(i) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}; #phi_{1}; #phi_{2}", kTHnSparseF, {{100, -0.15, 0.15}, {100, -0.15, 0.15}, {100, 0, 6.28}, {100, 0, 6.28}}); + } + } + } + if constexpr (mPartOneType == o2::aod::femtodreamparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kCascade) { + for (int i = 0; i < 3; i++) { + std::string dirName = static_cast(dirNames[3]); + histdetadpi[i][0] = mHistogramRegistry->add((dirName + static_cast(histNames[0][i]) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpi[i][1] = mHistogramRegistry->add((dirName + static_cast(histNames[1][i]) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpi[i][2] = mHistogramRegistry->add((dirName + "at_PV_" + std::to_string(i) + "_before" + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpi[i][3] = mHistogramRegistry->add((dirName + "at_PV_" + std::to_string(i) + "_after" + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + if (plotForEveryRadii) { + for (int j = 0; j < 9; j++) { + histdetadpiRadii[i][j] = mHistogramRegistryQA->add((dirName + static_cast(histNamesRadii[i][j]) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + } + } + if (fillQA) { + histdetadpi_eta[i] = mHistogramRegistry->add((dirName + "dEtadPhi_Eta_" + std::to_string(i) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}; #eta_{1}; #eta_{2}", kTHnSparseF, {{100, -0.15, 0.15}, {100, -0.15, 0.15}, {100, -0.8, 0.8}, {100, -0.8, 0.8}}); + histdetadpi_phi[i] = mHistogramRegistry->add((dirName + "dEtadPhi_Phi_" + std::to_string(i) + static_cast(histNameSEorME[meORse])).c_str(), "; #Delta #eta; #Delta #phi^{*}; #phi_{1}; #phi_{2}", kTHnSparseF, {{100, -0.15, 0.15}, {100, -0.15, 0.15}, {100, 0, 6.28}, {100, 0, 6.28}}); + } } } } /// Check if pair is close or not - template - bool isClosePair(Part const& part1, Part const& part2, Parts const& particles, float lmagfield, float Q3 = 999.) + template + bool isClosePair(Part1 const& part1, Part2 const& part2, Parts const& particles, float lmagfield, float Q3 = 999.) { magfield = lmagfield; - if constexpr (mPartOneType == o2::aod::femtodreamparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kTrack) { + if constexpr (mPartOneType == o2::aod::femtodreamparticle::ParticleType::kTrack && (mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kTrack || mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kCascadeV0Child)) { /// Track-Track combination // check if provided particles are in agreement with the class instantiation - if (part1.partType() != o2::aod::femtodreamparticle::ParticleType::kTrack || part2.partType() != o2::aod::femtodreamparticle::ParticleType::kTrack) { - LOG(fatal) << "FemtoDreamDetaDphiStar: passed arguments don't agree with FemtoDreamDetaDphiStar instantiation! Please provide kTrack,kTrack candidates."; + if (part1.partType() != o2::aod::femtodreamparticle::ParticleType::kTrack || !(part2.partType() == o2::aod::femtodreamparticle::ParticleType::kTrack || part2.partType() == o2::aod::femtodreamparticle::ParticleType::kCascadeV0Child)) { // hotfix to use the CPR + // LOG(fatal) << "FemtoDreamDetaDphiStar: passed arguments don't agree with FemtoDreamDetaDphiStar instantiation! Please provide kTrack,kTrack candidates."; + LOGF(fatal, "FemtoDreamDetaDphiStar: passed arguments don't agree with FemtoDreamDetaDphiStar instantiation! Please provide kTrack,kTrack candidates. Currently: %i", part2.partType()); return false; } auto deta = part1.eta() - part2.eta(); + auto dphi_AT_PV = part1.phi() - part2.phi(); + auto dphi_AT_SpecificRadii = PhiAtSpecificRadiiTPC(part1, radiiTPC) - PhiAtSpecificRadiiTPC(part2, radiiTPC); bool sameCharge = false; auto dphiAvg = AveragePhiStar(part1, part2, 0, &sameCharge); if (Q3 == 999) { histdetadpi[0][0]->Fill(deta, dphiAvg); + histdetadpi[0][2]->Fill(deta, dphi_AT_PV); + if (fillQA) { + histdetadpi_eta[0]->Fill(deta, dphiAvg, part1.eta(), part2.eta()); + histdetadpi_phi[0]->Fill(deta, dphiAvg, part1.phi(), part2.phi()); + } } else if (Q3 < upperQ3LimitForPlotting) { histdetadpi[0][0]->Fill(deta, dphiAvg); + histdetadpi[0][2]->Fill(deta, dphi_AT_PV); + if (fillQA) { + histdetadpi_eta[0]->Fill(deta, dphiAvg, part1.eta(), part2.eta()); + histdetadpi_phi[0]->Fill(deta, dphiAvg, part1.phi(), part2.phi()); + } } if (sameCharge) { - if (pow(dphiAvg, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { - return true; - } else { - if (Q3 == 999) { - histdetadpi[0][1]->Fill(deta, dphiAvg); - } else if (Q3 < upperQ3LimitForPlotting) { - histdetadpi[0][1]->Fill(deta, dphiAvg); + if (atWhichRadiiToSelect == 1) { + if (pow(dphiAvg, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + return true; + } else { + if (Q3 == 999) { + histdetadpi[0][1]->Fill(deta, dphiAvg); + histdetadpi[0][3]->Fill(deta, dphi_AT_PV); + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[0][1]->Fill(deta, dphiAvg); + histdetadpi[0][3]->Fill(deta, dphi_AT_PV); + } + return false; + } + } else if (atWhichRadiiToSelect == 0) { + if (pow(dphi_AT_PV, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + return true; + } else { + if (Q3 == 999) { + histdetadpi[0][1]->Fill(deta, dphiAvg); + histdetadpi[0][3]->Fill(deta, dphi_AT_PV); + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[0][1]->Fill(deta, dphiAvg); + histdetadpi[0][3]->Fill(deta, dphi_AT_PV); + } + return false; + } + } else if (atWhichRadiiToSelect == 2) { + if (pow(dphi_AT_SpecificRadii, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + return true; + } else { + if (Q3 == 999) { + histdetadpi[0][1]->Fill(deta, dphiAvg); + histdetadpi[0][3]->Fill(deta, dphi_AT_PV); + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[0][1]->Fill(deta, dphiAvg); + histdetadpi[0][3]->Fill(deta, dphi_AT_PV); + } + return false; } - return false; + } else { + return true; } } else { return false; @@ -129,21 +234,241 @@ class FemtoDreamDetaDphiStar } auto daughter = particles.begin() + indexOfDaughter; auto deta = part1.eta() - daughter.eta(); + auto dphi_AT_PV = part1.phi() - daughter.phi(); + auto dphi_AT_SpecificRadii = PhiAtSpecificRadiiTPC(part1, radiiTPC) - PhiAtSpecificRadiiTPC(daughter, radiiTPC); bool sameCharge = false; auto dphiAvg = AveragePhiStar(part1, *daughter, i, &sameCharge); if (Q3 == 999) { histdetadpi[i][0]->Fill(deta, dphiAvg); + histdetadpi[i][2]->Fill(deta, dphi_AT_PV); + if (fillQA) { + histdetadpi_eta[i]->Fill(deta, dphiAvg, part1.eta(), daughter.eta()); + histdetadpi_phi[i]->Fill(deta, dphiAvg, part1.phi(), daughter.phi()); + } } else if (Q3 < upperQ3LimitForPlotting) { histdetadpi[i][0]->Fill(deta, dphiAvg); + histdetadpi[i][2]->Fill(deta, dphi_AT_PV); + if (fillQA) { + histdetadpi_eta[i]->Fill(deta, dphiAvg, part1.eta(), daughter.eta()); + histdetadpi_phi[i]->Fill(deta, dphiAvg, part1.phi(), daughter.phi()); + } } if (sameCharge) { + if (atWhichRadiiToSelect == 1) { + if (pow(dphiAvg, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + pass = true; + } else { + if (Q3 == 999) { + histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); + } + } + } else if (atWhichRadiiToSelect == 0) { + if (pow(dphi_AT_PV, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + pass = true; + } else { + if (Q3 == 999) { + histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); + } + } + } else if (atWhichRadiiToSelect == 2) { + if (pow(dphi_AT_SpecificRadii, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + pass = true; + } else { + if (Q3 == 999) { + histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); + } + } + } + } + } + return pass; + } else if constexpr (mPartOneType == o2::aod::femtodreamparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kCharmHadron) { + // check if provided particles are in agreement with the class instantiation + if (part2.candidateSelFlag() < o2::aod::fdhf::lcToPKPi) { + LOG(fatal) << "FemtoDreamDetaDphiStar: passed arguments don't agree with FemtoDreamDetaDphiStar instantiation! Please provide Charm Hadron candidates."; + return false; + } + + bool pass = false; + + for (int i = 0; i < Nprongs; ++i) { + double deta, dphiAvg, dphi_AT_PV, dphi_AT_SpecificRadii, daughterEta, daughterPhi; + bool sameCharge = false; + daughterEta = -999.; + daughterPhi = -999.; + + switch (i) { + case Prong0: + daughterEta = part2.prong0Eta(); + daughterPhi = part2.prong0Phi(); + deta = part1.eta() - daughterEta; + dphi_AT_PV = part1.phi() - daughterPhi; + dphi_AT_SpecificRadii = PhiAtSpecificRadiiTPC(part1, radiiTPC) - PhiAtSpecificRadiiTPC(part2, radiiTPC); + dphiAvg = AveragePhiStar(part1, part2, 0, &sameCharge); + // histdetadpi[0][0]->Fill(deta, dphiAvg); + break; + case Prong1: + daughterEta = part2.prong1Eta(); + daughterPhi = part2.prong1Phi(); + deta = part1.eta() - daughterEta; + dphi_AT_PV = part1.phi() - daughterPhi; + dphi_AT_SpecificRadii = PhiAtSpecificRadiiTPC(part1, radiiTPC) - PhiAtSpecificRadiiTPC(part2, radiiTPC); + dphiAvg = AveragePhiStar(part1, part2, 1, &sameCharge); + // histdetadpi[1][0]->Fill(deta, dphiAvg); + break; + case Prong2: + daughterEta = part2.prong2Eta(); + daughterPhi = part2.prong2Phi(); + deta = part1.eta() - daughterEta; + dphi_AT_PV = part1.phi() - daughterPhi; + dphi_AT_SpecificRadii = PhiAtSpecificRadiiTPC(part1, radiiTPC) - PhiAtSpecificRadiiTPC(part2, radiiTPC); + dphiAvg = AveragePhiStar(part1, part2, 2, &sameCharge); + // histdetadpi[2][0]->Fill(deta, dphiAvg); + break; + } + if (Q3 == 999) { + histdetadpi[i][0]->Fill(deta, dphiAvg); + histdetadpi[i][2]->Fill(deta, dphi_AT_PV); + if (fillQA) { + histdetadpi_eta[i]->Fill(deta, dphiAvg, part1.eta(), daughterEta); + histdetadpi_phi[i]->Fill(deta, dphiAvg, part1.phi(), daughterPhi); + } + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[i][0]->Fill(deta, dphiAvg); + histdetadpi[i][2]->Fill(deta, dphi_AT_PV); + if (fillQA) { + histdetadpi_eta[i]->Fill(deta, dphiAvg, part1.eta(), daughterEta); + histdetadpi_phi[i]->Fill(deta, dphiAvg, part1.phi(), daughterPhi); + } + } + + if (atWhichRadiiToSelect == 1) { if (pow(dphiAvg, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { pass = true; } else { if (Q3 == 999) { histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); + } + } + } else if (atWhichRadiiToSelect == 0) { + if (pow(dphi_AT_PV, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + pass = true; + } else { + if (Q3 == 999) { + histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); + } + } + } else if (atWhichRadiiToSelect == 2) { + if (pow(dphi_AT_SpecificRadii, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + pass = true; + } else { + if (Q3 == 999) { + histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); } else if (Q3 < upperQ3LimitForPlotting) { histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); + } + } + } + } + + return pass; + + } else if constexpr (mPartOneType == o2::aod::femtodreamparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kCascade) { + /// Track-V0 combination + // check if provided particles are in agreement with the class instantiation + if (part1.partType() != o2::aod::femtodreamparticle::ParticleType::kTrack || part2.partType() != o2::aod::femtodreamparticle::ParticleType::kCascade) { + LOG(fatal) << "FemtoDreamDetaDphiStar: passed arguments don't agree with FemtoDreamDetaDphiStar instantiation! Please provide kTrack,kV0 candidates."; + return false; + } + + bool pass = false; + for (int i = 0; i < 3; i++) { + int indexOfDaughter; + if (isMixedEventLambda) { + indexOfDaughter = part2.globalIndex() - 3 + i; + } else { + indexOfDaughter = part2.index() - 3 + i; + } + auto daughter = particles.begin() + indexOfDaughter; + auto deta = part1.eta() - daughter.eta(); + auto dphi_AT_PV = part1.phi() - daughter.phi(); + auto dphi_AT_SpecificRadii = PhiAtSpecificRadiiTPC(part1, radiiTPC) - PhiAtSpecificRadiiTPC(daughter, radiiTPC); + bool sameCharge = false; + auto dphiAvg = AveragePhiStar(part1, *daughter, i, &sameCharge); + if (Q3 == 999) { + histdetadpi[i][0]->Fill(deta, dphiAvg); + histdetadpi[i][2]->Fill(deta, dphi_AT_PV); + if (fillQA) { + histdetadpi_eta[i]->Fill(deta, dphiAvg, part1.eta(), daughter.eta()); + histdetadpi_phi[i]->Fill(deta, dphiAvg, part1.phi(), daughter.phi()); + } + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[i][0]->Fill(deta, dphiAvg); + histdetadpi[i][2]->Fill(deta, dphi_AT_PV); + if (fillQA) { + histdetadpi_eta[i]->Fill(deta, dphiAvg, part1.eta(), daughter.eta()); + histdetadpi_phi[i]->Fill(deta, dphiAvg, part1.phi(), daughter.phi()); + } + } + if (sameCharge) { + if (atWhichRadiiToSelect == 1) { + if (pow(dphiAvg, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + pass = true; + } else { + if (Q3 == 999) { + histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); + } + } + + } else if (atWhichRadiiToSelect == 0) { + if (pow(dphi_AT_PV, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + pass = true; + } else { + if (Q3 == 999) { + histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); + } + } + } else if (atWhichRadiiToSelect == 2) { + if (pow(dphi_AT_SpecificRadii, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + pass = true; + } else { + if (Q3 == 999) { + histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[i][1]->Fill(deta, dphiAvg); + histdetadpi[i][3]->Fill(deta, dphi_AT_PV); + } } } } @@ -158,18 +483,26 @@ class FemtoDreamDetaDphiStar private: HistogramRegistry* mHistogramRegistry = nullptr; ///< For main output HistogramRegistry* mHistogramRegistryQA = nullptr; ///< For QA output - static constexpr std::string_view dirNames[2] = {"kTrack_kTrack/", "kTrack_kV0/"}; + static constexpr std::string_view dirNames[4] = {"kTrack_kTrack/", "kTrack_kV0/", "kTrack_kCharmHadron/", "kTrack_kCascade/"}; static constexpr std::string_view histNameSEorME[3] = {"_SEandME", "_SE", "_ME"}; - static constexpr std::string_view histNames[2][2] = {{"detadphidetadphi0Before_0", "detadphidetadphi0Before_1"}, - {"detadphidetadphi0After_0", "detadphidetadphi0After_1"}}; - static constexpr std::string_view histNamesRadii[2][9] = {{"detadphidetadphi0Before_0_0", "detadphidetadphi0Before_0_1", "detadphidetadphi0Before_0_2", - "detadphidetadphi0Before_0_3", "detadphidetadphi0Before_0_4", "detadphidetadphi0Before_0_5", - "detadphidetadphi0Before_0_6", "detadphidetadphi0Before_0_7", "detadphidetadphi0Before_0_8"}, - {"detadphidetadphi0Before_1_0", "detadphidetadphi0Before_1_1", "detadphidetadphi0Before_1_2", - "detadphidetadphi0Before_1_3", "detadphidetadphi0Before_1_4", "detadphidetadphi0Before_1_5", - "detadphidetadphi0Before_1_6", "detadphidetadphi0Before_1_7", "detadphidetadphi0Before_1_8"}}; + static constexpr std::string_view histNames[2][4] = {{"detadphidetadphi0Before_0", "detadphidetadphi0Before_1", "detadphidetadphi0Before_2", "detadphidetadphi0Before_3"}, + {"detadphidetadphi0After_0", "detadphidetadphi0After_1", "detadphidetadphi0After_2", "detadphidetadphi0After_3"}}; + + static constexpr std::string_view histNamesRadii[4][9] = { + {"detadphidetadphi0Before_0_0", "detadphidetadphi0Before_0_1", "detadphidetadphi0Before_0_2", + "detadphidetadphi0Before_0_3", "detadphidetadphi0Before_0_4", "detadphidetadphi0Before_0_5", + "detadphidetadphi0Before_0_6", "detadphidetadphi0Before_0_7", "detadphidetadphi0Before_0_8"}, + {"detadphidetadphi0Before_1_0", "detadphidetadphi0Before_1_1", "detadphidetadphi0Before_1_2", + "detadphidetadphi0Before_1_3", "detadphidetadphi0Before_1_4", "detadphidetadphi0Before_1_5", + "detadphidetadphi0Before_1_6", "detadphidetadphi0Before_1_7", "detadphidetadphi0Before_1_8"}, + {"detadphidetadphi0Before_2_0", "detadphidetadphi0Before_2_1", "detadphidetadphi0Before_2_2", + "detadphidetadphi0Before_2_3", "detadphidetadphi0Before_2_4", "detadphidetadphi0Before_2_5", + "detadphidetadphi0Before_2_6", "detadphidetadphi0Before_2_7", "detadphidetadphi0Before_2_8"}, + {"detadphidetadphi0Before_3_0", "detadphidetadphi0Before_3_1", "detadphidetadphi0Before_3_2", + "detadphidetadphi0Before_3_3", "detadphidetadphi0Before_3_4", "detadphidetadphi0Before_3_5", + "detadphidetadphi0Before_3_6", "detadphidetadphi0Before_3_7", "detadphidetadphi0Before_3_8"}}; static constexpr o2::aod::femtodreamparticle::ParticleType mPartOneType = partOne; ///< Type of particle 1 static constexpr o2::aod::femtodreamparticle::ParticleType mPartTwoType = partTwo; ///< Type of particle 2 @@ -186,12 +519,17 @@ class FemtoDreamDetaDphiStar bool plotForEveryRadii = false; bool isMixedEventLambda = false; float upperQ3LimitForPlotting = 8.; + int atWhichRadiiToSelect = 1; + float radiiTPC = 85.; + bool fillQA = false; // a possible bug was found, but this must be tested on hyperloop with larger statistics // possiboility to run old code is turned on so a proper comparison of both code versions can be done bool runOldVersion = true; - std::array, 2>, 2> histdetadpi{}; - std::array, 9>, 2> histdetadpiRadii{}; + std::array, 4>, 3> histdetadpi{}; + std::array, 9>, 3> histdetadpiRadii{}; + std::array, 3> histdetadpi_eta{}; + std::array, 3> histdetadpi_phi{}; /// Calculate phi at all required radii stored in tmpRadiiTPC /// Magnetic field to be provided in Tesla @@ -220,7 +558,110 @@ class FemtoDreamDetaDphiStar if (!runOldVersion) { auto arg = 0.3 * charge * magfield * tmpRadiiTPC[i] * 0.01 / (2. * pt); // for very low pT particles, this value goes outside of range -1 to 1 at at large tpc radius; asin fails - if (abs(arg) < 1) { + if (std::fabs(arg) < 1) { + tmpVec.push_back(phi0 - std::asin(0.3 * charge * magfield * tmpRadiiTPC[i] * 0.01 / (2. * pt))); + } else { + tmpVec.push_back(999); + } + } + } + return charge; + } + + /// Calculate phi at specific radii + /// Magnetic field to be provided in Tesla + template + float PhiAtSpecificRadiiTPC(const T& part, float radii) + { + int charge = 0; + float phi0, pt; + if constexpr (isHF) { + switch (prong) { + case Prong0: + charge = part.charge(); // charge calculation according to 3-prong decay, Lc^+ --> P^+ + K^- + pi^+ + phi0 = part.prong0Phi(); + pt = part.prong0Pt(); + break; + case Prong1: + charge = -part.charge(); + phi0 = part.prong1Phi(); + pt = part.prong1Pt(); + break; + case Prong2: + charge = part.charge(); + phi0 = part.prong2Phi(); + pt = part.prong2Pt(); + break; + default: + // Handle invalid prong value if necessary + break; + } + } else { + phi0 = part.phi(); + // Start: Get the charge from cutcontainer using masks + if ((part.cut() & kSignMinusMask) == kValue0 && (part.cut() & kSignPlusMask) == kValue0) { + charge = 0; + } else if ((part.cut() & kSignPlusMask) == kSignPlusMask) { + charge = 1; + } else if ((part.cut() & kSignMinusMask) == kSignMinusMask) { + charge = -1; + } else { + LOG(fatal) << "FemtoDreamDetaDphiStar: Charge bits are set wrong!"; + } + pt = part.pt(); + } + // End: Get the charge from cutcontainer using masks + float phiAtRadii = 0; + if (runOldVersion) { + phiAtRadii = phi0 - std::asin(0.3 * charge * 0.1 * magfield * radii * 0.01 / (2. * pt)); + } + if (!runOldVersion) { + auto arg = 0.3 * charge * magfield * radii * 0.01 / (2. * pt); + // for very low pT particles, this value goes outside of range -1 to 1 at at large tpc radius; asin fails + if (std::fabs(arg) < 1) { + phiAtRadii = phi0 - std::asin(0.3 * charge * magfield * radii * 0.01 / (2. * pt)); + } else { + phiAtRadii = 999.; + } + } + + return phiAtRadii; + } + + template + int PhiAtRadiiTPCForHF(const T& part, std::vector& tmpVec, int prong) + { + int charge = 0; + float pt = -999.; + float phi0 = -999.; + switch (prong) { + case Prong0: + pt = part.prong0Pt(); + phi0 = part.prong0Phi(); + charge = part.charge(); + break; + case Prong1: + pt = part.prong1Pt(); + phi0 = part.prong1Phi(); + charge = -part.charge(); + break; + case Prong2: + pt = part.prong2Pt(); + phi0 = part.prong2Phi(); + charge = part.charge(); + break; + default: + // Handle invalid prong value + break; + } + for (size_t i = 0; i < 9; i++) { + if (runOldVersion) { + tmpVec.push_back(phi0 - std::asin(0.3 * charge * 0.1 * magfield * tmpRadiiTPC[i] * 0.01 / (2. * pt))); + } + if (!runOldVersion) { + auto arg = 0.3 * charge * magfield * tmpRadiiTPC[i] * 0.01 / (2. * pt); + // for very low pT particles, this value goes outside of range -1 to 1 at at large tpc radius; asin fails + if (std::fabs(arg) < 1) { tmpVec.push_back(phi0 - std::asin(0.3 * charge * magfield * tmpRadiiTPC[i] * 0.01 / (2. * pt))); } else { tmpVec.push_back(999); @@ -231,15 +672,20 @@ class FemtoDreamDetaDphiStar } /// Calculate average phi - template + template float AveragePhiStar(const T1& part1, const T2& part2, int iHist, bool* sameCharge) { std::vector tmpVec1; std::vector tmpVec2; auto charge1 = PhiAtRadiiTPC(part1, tmpVec1); - auto charge2 = PhiAtRadiiTPC(part2, tmpVec2); - if (charge1 == charge2) { - *sameCharge = true; + if constexpr (!isHF) { + auto charge2 = PhiAtRadiiTPC(part2, tmpVec2); + if (charge1 == charge2) { + *sameCharge = true; + } + } else { + PhiAtRadiiTPCForHF(part2, tmpVec2, iHist); + *sameCharge = true; // always true as we checked the condition in the HF task } int num = tmpVec1.size(); int meaningfulEntries = num; diff --git a/PWGCF/FemtoDream/Core/femtoDreamEventHisto.h b/PWGCF/FemtoDream/Core/femtoDreamEventHisto.h index 2b5aac77d31..4f70555a849 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamEventHisto.h +++ b/PWGCF/FemtoDream/Core/femtoDreamEventHisto.h @@ -31,7 +31,7 @@ class FemtoDreamEventHisto virtual ~FemtoDreamEventHisto() = default; /// Initializes histograms for the task /// \param registry Histogram registry to be passed - void init(HistogramRegistry* registry, bool isMC) + void init(HistogramRegistry* registry, bool isMC = false) { mHistogramRegistry = registry; mHistogramRegistry->add("Event/hZvtx", "; vtx_{z} (cm); Entries", kTH1F, {{300, -12.5, 12.5}}); @@ -49,7 +49,7 @@ class FemtoDreamEventHisto /// Some basic QA of the event /// \tparam T type of the collision /// \param col Collision - template + template void fillQA(T const& col) { if (mHistogramRegistry) { diff --git a/PWGCF/FemtoDream/Core/femtoDreamMath.h b/PWGCF/FemtoDream/Core/femtoDreamMath.h index d263d4c3ba3..bb3c37b284b 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamMath.h +++ b/PWGCF/FemtoDream/Core/femtoDreamMath.h @@ -37,8 +37,8 @@ class FemtoDreamMath /// \param mass1 Mass of particle 1 /// \param part2 Particle 2 /// \param mass2 Mass of particle 2 - template - static float getkstar(const T& part1, const float mass1, const T& part2, const float mass2) + template + static float getkstar(const T1& part1, const float mass1, const T2& part2, const float mass2) { const ROOT::Math::PtEtaPhiMVector vecpart1(part1.pt(), part1.eta(), part1.phi(), mass1); const ROOT::Math::PtEtaPhiMVector vecpart2(part2.pt(), part2.eta(), part2.phi(), mass2); @@ -116,8 +116,8 @@ class FemtoDreamMath /// \param mass1 Mass of particle 1 /// \param part2 Particle 2 /// \param mass2 Mass of particle 2 - template - static float getkT(const T& part1, const float mass1, const T& part2, const float mass2) + template + static float getkT(const T1& part1, const float mass1, const T2& part2, const float mass2) { const ROOT::Math::PtEtaPhiMVector vecpart1(part1.pt(), part1.eta(), part1.phi(), mass1); const ROOT::Math::PtEtaPhiMVector vecpart2(part2.pt(), part2.eta(), part2.phi(), mass2); @@ -131,11 +131,24 @@ class FemtoDreamMath /// \param mass1 Mass of particle 1 /// \param part2 Particle 2 /// \param mass2 Mass of particle 2 - template - static float getmT(const T& part1, const float mass1, const T& part2, const float mass2) + template + static float getmT(const T1& part1, const float mass1, const T2& part2, const float mass2) { return std::sqrt(std::pow(getkT(part1, mass1, part2, mass2), 2.) + std::pow(0.5 * (mass1 + mass2), 2.)); } + + template + static float getInvMassCascade(const T1& trackpos, const float masspos, const T1& trackneg, const float massneg, const T1& trackbach, const float massbach, const float massv0) + { + // calculate the invariant mass + const ROOT::Math::PtEtaPhiMVector posDaug(trackpos.pt(), trackpos.eta(), trackpos.phi(), masspos); + const ROOT::Math::PtEtaPhiMVector negDaug(trackneg.pt(), trackneg.eta(), trackneg.phi(), massneg); + const ROOT::Math::PtEtaPhiMVector bachDaug(trackbach.pt(), trackbach.eta(), trackbach.phi(), massbach); + const ROOT::Math::PxPyPzMVector v0(posDaug.Px() + negDaug.Px(), posDaug.Py() + negDaug.Py(), posDaug.Pz() + negDaug.Pz(), massv0); + const ROOT::Math::PxPyPzMVector casc = v0 + bachDaug; + + return casc.M(); + } }; } // namespace o2::analysis::femtoDream diff --git a/PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h b/PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h index d6f334c5acb..5243f562fbe 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h +++ b/PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h @@ -52,8 +52,8 @@ class FemtoDreamPairCleaner /// \param part2 Particle 2 /// \param particles Collection of all particles passed to the task /// \return Whether the pair has shared tracks - template - bool isCleanPair(Part const& part1, Part const& part2, Parts const& particles) + template + bool isCleanPair(Part1 const& part1, Part2 const& part2, Parts const& particles) { if constexpr (mPartOneType == o2::aod::femtodreamparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kTrack) { /// Track-Track combination @@ -70,7 +70,31 @@ class FemtoDreamPairCleaner } const auto& posChild = particles.iteratorAt(part2.index() - 2); const auto& negChild = particles.iteratorAt(part2.index() - 1); - if (part1.globalIndex() != posChild.globalIndex() || part1.globalIndex() != negChild.globalIndex()) { + if (part1.index() != posChild.childrenIds()[0] && part1.index() != negChild.childrenIds()[1]) { + return true; + } + return false; + } else if constexpr (mPartOneType == o2::aod::femtodreamparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kCharmHadron) { + /// Track-CharmHadron combination + if (part2.candidateSelFlag() < o2::aod::fdhf::lcToPKPi) { + LOG(fatal) << "FemtoDreamPairCleaner: passed arguments don't agree with FemtoDreamPairCleaner instantiation! Please provide second argument Charm candidate."; + return false; + } + + if (part1.trackId() != part2.prong0Id() && part1.trackId() != part2.prong1Id() && part1.trackId() != part2.prong2Id()) { + return true; + } + return false; + } else if constexpr (mPartOneType == o2::aod::femtodreamparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kCascade) { + /// Track-Cascade combination + if (part2.partType() != o2::aod::femtodreamparticle::ParticleType::kCascade) { + LOG(fatal) << "FemtoDreamPairCleaner: passed arguments don't agree with FemtoDreamPairCleaner instantiation! Please provide second argument kCascade candidate."; + return false; + } + const auto& posChild = particles.iteratorAt(part2.index() - 3); + const auto& negChild = particles.iteratorAt(part2.index() - 2); + const auto& bachChild = particles.iteratorAt(part2.index() - 1); + if (part1.index() != posChild.childrenIds()[0] && part1.index() != negChild.childrenIds()[1] && part1.index() != bachChild.childrenIds()[2]) { return true; } return false; diff --git a/PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h b/PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h index 4b22bc43c30..244466d2cb2 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h +++ b/PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h @@ -22,6 +22,7 @@ #include #include "PWGCF/DataModel/FemtoDerived.h" #include "Framework/HistogramRegistry.h" +#include "CommonConstants/PhysicsConstants.h" using namespace o2::framework; @@ -60,18 +61,22 @@ class FemtoDreamParticleHisto if constexpr (o2::aod::femtodreamMCparticle::MCType::kRecon == mc) { mHistogramRegistry->add((folderName + folderSuffix + static_cast(o2::aod::femtodreamparticle::TempFitVarName[mParticleType])).c_str(), ("; #it{p}_{T} (GeV/#it{c}); " + tempFitVarAxisTitle).c_str(), kTH2F, {{pTAxis}, {tempFitVarAxis}}); } - if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kV0 && mc == o2::aod::femtodreamMCparticle::MCType::kRecon) { + if constexpr ((mParticleType == o2::aod::femtodreamparticle::ParticleType::kV0 || mParticleType == o2::aod::femtodreamparticle::ParticleType::kCascadeV0) && mc == o2::aod::femtodreamMCparticle::MCType::kRecon) { mHistogramRegistry->add((folderName + folderSuffix + "/hInvMassLambda").c_str(), "; M_{#Lambda}; Entries", kTH1F, {InvMassAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/hpTInvMassLambda").c_str(), "; p_{T} (GeV/#it{c{}); M_{#Lambda}", kTH2F, {pTAxis, InvMassAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/hInvMassAntiLambda").c_str(), "; M_{#bar{#Lambda}}; Entries", kTH1F, {InvMassAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/hpTInvMassAntiLambda").c_str(), "; M_{#bar{#Lambda}}; Entries", kTH2F, {pTAxis, InvMassAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/hInvMassLambdaAntiLambda").c_str(), "; M_{#Lambda}; M_{#bar{#Lambda}}", kTH2F, {InvMassAxis, InvMassAxis}); } + if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kCascade) { + mHistogramRegistry->add((folderName + folderSuffix + "/hInvMassCascade").c_str(), "; M_{Cascade}; Entries", kTH1F, {InvMassAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hpTInvMassCascade").c_str(), "; p_{T} (GeV/#it{c{}); M_{Cascade}", kTH2F, {pTAxis, InvMassAxis}); + } } // comment template - void init_debug(std::string folderName, T& multAxis, T& multPercentileAxis, T& pTAxis, T& etaAxis, T& phiAxis, T& tempFitVarAxis, T& dcazAxis, T& NsigmaTPCAxis, T& NsigmaTOFAxis, T& NsigmaTPCTOFAxis, T& /*TPCclustersAxis*/, bool correlatedPlots) + void init_debug(std::string folderName, T& multAxis, T& multPercentileAxis, T& pTAxis, T& etaAxis, T& phiAxis, T& tempFitVarAxis, T& dcazAxis, T& NsigmaTPCAxis, T& NsigmaTOFAxis, T& NsigmaTPCTOFAxis, T& NsigmaITSAxis, T& InvMassCompetingAxis, bool correlatedPlots) { std::string folderSuffix = static_cast(o2::aod::femtodreamMCparticle::MCTypeName[mc]).c_str(); @@ -80,7 +85,7 @@ class FemtoDreamParticleHisto mHistogramRegistry->add((folderName + folderSuffix + "/hMomentumVsPhi").c_str(), "; #it{p} (GeV/#it{c}); #phi", kTH2F, {{500, 0, 10}, {360, 0., TMath::TwoPi()}}); mHistogramRegistry->add((folderName + folderSuffix + "/hEtaVsPhi").c_str(), "; #eta; #phi", kTH2F, {{300, -1.5, 1.5}, {360, 0., TMath::TwoPi()}}); - if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kTrack || mParticleType == o2::aod::femtodreamparticle::ParticleType::kV0Child) { + if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kTrack || mParticleType == o2::aod::femtodreamparticle::ParticleType::kV0Child || mParticleType == o2::aod::femtodreamparticle::ParticleType::kCascadeV0Child || mParticleType == o2::aod::femtodreamparticle::ParticleType::kCascadeBachelor) { mHistogramRegistry->add((folderName + folderSuffix + "/hCharge").c_str(), "; Charge; Entries", kTH1F, {{5, -2.5, 2.5}}); mHistogramRegistry->add((folderName + folderSuffix + "/hTPCfindable").c_str(), "; TPC findable clusters; Entries", kTH1F, {{163, -0.5, 162.5}}); mHistogramRegistry->add((folderName + folderSuffix + "/hTPCfound").c_str(), "; TPC found clusters; Entries", kTH1F, {{163, -0.5, 162.5}}); @@ -100,16 +105,30 @@ class FemtoDreamParticleHisto mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_K").c_str(), "n#sigma_{TPC}^{K}", kTH2F, {pTAxis, NsigmaTPCAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_p").c_str(), "n#sigma_{TPC}^{p}", kTH2F, {pTAxis, NsigmaTPCAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_d").c_str(), "n#sigma_{TPC}^{d}", kTH2F, {pTAxis, NsigmaTPCAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_tr").c_str(), "n#sigma_{TPC}^{tr}", kTH2F, {pTAxis, NsigmaTPCAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_he3").c_str(), "n#sigma_{TPC}^{he3}", kTH2F, {pTAxis, NsigmaTPCAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_el").c_str(), "n#sigma_{TOF}^{e}", kTH2F, {pTAxis, NsigmaTOFAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_pi").c_str(), "n#sigma_{TOF}^{#pi}", kTH2F, {pTAxis, NsigmaTOFAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_K").c_str(), "n#sigma_{TOF}^{K}", kTH2F, {pTAxis, NsigmaTOFAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_p").c_str(), "n#sigma_{TOF}^{p}", kTH2F, {pTAxis, NsigmaTOFAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_d").c_str(), "n#sigma_{TOF}^{d}", kTH2F, {pTAxis, NsigmaTOFAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_tr").c_str(), "n#sigma_{TOF}^{tr}", kTH2F, {pTAxis, NsigmaTOFAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_he3").c_str(), "n#sigma_{TOF}^{he3}", kTH2F, {pTAxis, NsigmaTOFAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaComb_el").c_str(), "n#sigma_{comb}^{e}", kTH2F, {pTAxis, NsigmaTPCTOFAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaComb_pi").c_str(), "n#sigma_{comb}^{#pi}", kTH2F, {pTAxis, NsigmaTPCTOFAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaComb_K").c_str(), "n#sigma_{comb}^{K}", kTH2F, {pTAxis, NsigmaTPCTOFAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaComb_p").c_str(), "n#sigma_{comb}^{p}", kTH2F, {pTAxis, NsigmaTPCTOFAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaComb_d").c_str(), "n#sigma_{comb}^{d}", kTH2F, {pTAxis, NsigmaTPCTOFAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaComb_tr").c_str(), "n#sigma_{comb}^{tr}", kTH2F, {pTAxis, NsigmaTPCTOFAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaComb_he3").c_str(), "n#sigma_{comb}^{he3}", kTH2F, {pTAxis, NsigmaTPCTOFAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/ITSSignal").c_str(), "x", kTH2F, {pTAxis, NsigmaITSAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaITS_el").c_str(), "n#sigma_{ITS}^{e}", kTH2F, {pTAxis, NsigmaITSAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaITS_pi").c_str(), "n#sigma_{ITS}^{#pi}", kTH2F, {pTAxis, NsigmaITSAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaITS_K").c_str(), "n#sigma_{ITS}^{K}", kTH2F, {pTAxis, NsigmaITSAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaITS_p").c_str(), "n#sigma_{ITS}^{p}", kTH2F, {pTAxis, NsigmaITSAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaITS_d").c_str(), "n#sigma_{ITS}^{d}", kTH2F, {pTAxis, NsigmaITSAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaITS_tr").c_str(), "n#sigma_{ITS}^{tr}", kTH2F, {pTAxis, NsigmaITSAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaITS_he3").c_str(), "n#sigma_{ITS}^{he3}", kTH2F, {pTAxis, NsigmaITSAxis}); if (correlatedPlots) { mHistogramRegistry->add((folderName + folderSuffix + "/HighDcorrelator").c_str(), "", kTHnSparseF, {multAxis, multPercentileAxis, pTAxis, etaAxis, phiAxis, tempFitVarAxis, dcazAxis, NsigmaTPCAxis, NsigmaTOFAxis}); } @@ -119,6 +138,17 @@ class FemtoDreamParticleHisto mHistogramRegistry->add((folderName + folderSuffix + "/hDecayVtxX").c_str(), "; #it{Vtx}_{x} (cm); Entries", kTH1F, {{2000, 0, 200}}); mHistogramRegistry->add((folderName + folderSuffix + "/hDecayVtxY").c_str(), "; #it{Vtx}_{y} (cm)); Entries", kTH1F, {{2000, 0, 200}}); mHistogramRegistry->add((folderName + folderSuffix + "/hDecayVtxZ").c_str(), "; #it{Vtx}_{z} (cm); Entries", kTH1F, {{2000, 0, 200}}); + } else if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kCascade) { + mHistogramRegistry->add((folderName + folderSuffix + "/hCascV0DCADaugh").c_str(), "; #DCA{daugh} (cm); Entries", kTH1F, {{300, 0, 3}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hCascV0TransRadius").c_str(), "; #it{r}_{xy} (cm); Entries", kTH1F, {{1500, 0, 150}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hCascV0DCAtoPV").c_str(), "; DCA^{PV} (cm); Entries", kTH1F, {{1000, 0, 10}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hCascDaughDCA").c_str(), "; DCA^{daugh} (cm); Entries", kTH1F, {{1000, 0, 10}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hCascTransRadius").c_str(), "; #it{r}_{xy} (cm); Entries", kTH1F, {{1500, 0, 150}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hCascDecayVtxX").c_str(), "; #it{Vtx}_{x} (cm); Entries", kTH1F, {{2000, 0, 200}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hCascDecayVtxY").c_str(), "; #it{Vtx}_{y} (cm)); Entries", kTH1F, {{2000, 0, 200}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hCascDecayVtxZ").c_str(), "; #it{Vtx}_{z} (cm); Entries", kTH1F, {{2000, 0, 200}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hInvMassCompetingCascade").c_str(), "; M_{Competing Cascade}; Entries", kTH1F, {InvMassCompetingAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hpTInvMassCompetingCascade").c_str(), "; p_{T} (GeV/#it{c{}); M_{Competing Cascade}", kTH2F, {pTAxis, InvMassCompetingAxis}); } } @@ -139,8 +169,11 @@ class FemtoDreamParticleHisto mHistogramRegistry->add((folderName + folderSuffix + "/hPDG").c_str(), "; PDG; Entries", kTH1I, {{6001, -3000.5, 3000.5}}); mHistogramRegistry->add((folderName + folderSuffix + "/hOrigin_MC").c_str(), "; Origin; Entries", kTH1I, {{7, -0.5, 6.5}}); mHistogramRegistry->add((folderName + folderSuffix + "/hNoMCtruthCounter").c_str(), "; Counter; Entries", kTH1I, {{1, -0.5, 0.5}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hPt_DiffTruthReco").c_str(), "; p^{truth}_{T}; (p^{reco}_{T} - p^{truth}_{T}) / p^{truth}_{T}", kTH2F, {tempFitVarpTAxis, {200, -1, 1}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hEta_DiffTruthReco").c_str(), "; #eta^{truth}; #eta^{reco} - #eta^{truth}", kTH2F, {{200, -1, 1}, {200, -1, 1}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hPhi_DiffTruthReco").c_str(), "; #varphi^{truth}; #varphi^{reco} - #varphi^{truth}", kTH2F, {{720, 0, TMath::TwoPi()}, {200, -1, 1}}); - if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kTrack || mParticleType == o2::aod::femtodreamparticle::ParticleType::kV0Child) { + if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kTrack || mParticleType == o2::aod::femtodreamparticle::ParticleType::kV0Child || mParticleType == o2::aod::femtodreamparticle::ParticleType::kCascadeV0Child || mParticleType == o2::aod::femtodreamparticle::ParticleType::kCascadeBachelor) { /// Track histograms if (isDebug) { mHistogramRegistry->add((folderName + folderSuffix + "/Debug/hPDGmother_Primary").c_str(), "; PDG mother; Entries", kTH1I, {{6001, -3000.5, 3000.5}}); @@ -172,7 +205,7 @@ class FemtoDreamParticleHisto } // DCA plots - } else if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kV0) { + } else if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kV0 || mParticleType == o2::aod::femtodreamparticle::ParticleType::kCascadeV0) { if (isDebug) { mHistogramRegistry->add((folderName + folderSuffix + "/hCPA_Primary").c_str(), "; #it{p}_{T} (GeV/#it{c}); CPA", kTHnSparseF, {tempFitVarpTAxis, tempFitVarAxis, multAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/hCPA_Secondary").c_str(), "; #it{p}_{T} (GeV/#it{c}); CPA", kTHnSparseF, {tempFitVarpTAxis, tempFitVarAxis, multAxis}); @@ -180,6 +213,9 @@ class FemtoDreamParticleHisto mHistogramRegistry->add((folderName + folderSuffix + "/hCPA_WrongCollision").c_str(), "; #it{p}_{T} (GeV/#it{c}); CPA", kTHnSparseF, {tempFitVarpTAxis, tempFitVarAxis, multAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/hCPA_Fake").c_str(), "; #it{p}_{T} (GeV/#it{c}); CPA", kTHnSparseF, {tempFitVarpTAxis, tempFitVarAxis, multAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/hCPA_Else").c_str(), "; #it{p}_{T} (GeV/#it{c}); CPA", kTHnSparseF, {tempFitVarpTAxis, tempFitVarAxis, multAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hCPA_Secondary_SIGMA0").c_str(), "; #it{p}_{T} (GeV/#it{c}); CPA", kTHnSparseF, {tempFitVarpTAxis, tempFitVarAxis, multAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hCPA_Secondary_XIMinus").c_str(), "; #it{p}_{T} (GeV/#it{c}); CPA", kTHnSparseF, {tempFitVarpTAxis, tempFitVarAxis, multAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hCPA_Secondary_XI0").c_str(), "; #it{p}_{T} (GeV/#it{c}); CPA", kTHnSparseF, {tempFitVarpTAxis, tempFitVarAxis, multAxis}); } else { mHistogramRegistry->add((folderName + folderSuffix + "/hCPA_Primary").c_str(), "; #it{p}_{T} (GeV/#it{c}); CPA", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/hCPA_Secondary").c_str(), "; #it{p}_{T} (GeV/#it{c}); CPA", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); @@ -187,6 +223,9 @@ class FemtoDreamParticleHisto mHistogramRegistry->add((folderName + folderSuffix + "/hCPA_WrongCollision").c_str(), "; #it{p}_{T} (GeV/#it{c}); CPA", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/hCPA_Fake").c_str(), "; #it{p}_{T} (GeV/#it{c}); CPA", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/hCPA_Else").c_str(), "; #it{p}_{T} (GeV/#it{c}); CPA", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hCPA_Secondary_SIGMA0").c_str(), "; #it{p}_{T} (GeV/#it{c}); CPA", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hCPA_Secondary_XIMinus").c_str(), "; #it{p}_{T} (GeV/#it{c}); CPA", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hCPA_Secondary_XI0").c_str(), "; #it{p}_{T} (GeV/#it{c}); CPA", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); } /// V0 histograms /// to be implemented @@ -207,17 +246,17 @@ class FemtoDreamParticleHisto /// \param tempFitVarBins binning of the tempFitVar (DCA_xy in case of tracks, CPA in case of V0s, etc.) /// \param isMC add Monte Carlo truth histograms to the output file template - void init(HistogramRegistry* registry, T& MultBins, T& PercentileBins, T& pTBins, T& etaBins, T& phiBins, T& tempFitVarBins, T& NsigmaTPCBins, T& NsigmaTOFBins, T& NsigmaTPCTOFBins, T& TPCclustersBins, T& InvMassBins, bool isMC, int pdgCode, bool isDebug = false, bool correlatedPlots = false) + void init(HistogramRegistry* registry, T& MultBins, T& PercentileBins, T& pTBins, T& etaBins, T& phiBins, T& tempFitVarBins, T& NsigmaTPCBins, T& NsigmaTOFBins, T& NsigmaTPCTOFBins, T& NsigmaITSBins, T& InvMassBins, T& InvMassCompetingBins, bool isMC, int pdgCode, bool isDebug = false, bool correlatedPlots = false) { mPDG = pdgCode; if (registry) { mHistogramRegistry = registry; /// The folder names are defined by the type of the object and the suffix (if applicable) std::string tempFitVarAxisTitle; - if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kTrack || mParticleType == o2::aod::femtodreamparticle::ParticleType::kV0Child) { + if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kTrack || mParticleType == o2::aod::femtodreamparticle::ParticleType::kV0Child || mParticleType == o2::aod::femtodreamparticle::ParticleType::kCascadeV0Child || mParticleType == o2::aod::femtodreamparticle::ParticleType::kCascadeBachelor) { /// Track histograms tempFitVarAxisTitle = "DCA_{xy} (cm)"; - } else if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kV0) { + } else if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kV0 || mParticleType == o2::aod::femtodreamparticle::ParticleType::kCascadeV0) { /// V0 histograms tempFitVarAxisTitle = "cos#alpha"; } else if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kCascade) { @@ -237,15 +276,16 @@ class FemtoDreamParticleHisto framework::AxisSpec NsigmaTPCAxis = {NsigmaTPCBins, "n#sigma_{TPC}"}; framework::AxisSpec NsigmaTOFAxis = {NsigmaTOFBins, "n#sigma_{TOF}"}; framework::AxisSpec NsigmaTPCTOFAxis = {NsigmaTPCTOFBins, "n#sigma_{TPC+TOF}"}; - framework::AxisSpec TPCclustersAxis = {TPCclustersBins, "TPC found clusters"}; + framework::AxisSpec NsigmaITSAxis = {NsigmaITSBins, "n#sigma_{ITS}"}; framework::AxisSpec InvMassAxis = {InvMassBins, "M_{inv} (GeV/#it{c}^{2})"}; + framework::AxisSpec InvMassCompetingAxis = {InvMassCompetingBins, "M_{inv} (GeV/#it{c}^{2})"}; std::string folderName = (static_cast(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]).c_str() + static_cast(mFolderSuffix[mFolderSuffixType])).c_str(); // Fill here the actual histogramms by calling init_base and init_MC init_base(folderName, tempFitVarAxisTitle, pTAxis, tempFitVarAxis, InvMassAxis, multAxis); if (isDebug) { - init_debug(folderName, multAxis, multPercentileAxis, pTAxis, etaAxis, phiAxis, tempFitVarAxis, dcazAxis, NsigmaTPCAxis, NsigmaTOFAxis, NsigmaTPCTOFAxis, TPCclustersAxis, correlatedPlots); + init_debug(folderName, multAxis, multPercentileAxis, pTAxis, etaAxis, phiAxis, tempFitVarAxis, dcazAxis, NsigmaTPCAxis, NsigmaTOFAxis, NsigmaTPCTOFAxis, NsigmaITSAxis, InvMassCompetingAxis, correlatedPlots); } if (isMC) { init_base(folderName, tempFitVarAxisTitle, pTAxis, tempFitVarAxis, InvMassAxis, multAxis); @@ -270,13 +310,19 @@ class FemtoDreamParticleHisto if constexpr (mc == o2::aod::femtodreamMCparticle::MCType::kRecon) { mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST(o2::aod::femtodreamparticle::TempFitVarName[mParticleType]), part.pt(), part.tempFitVar()); } - if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kV0 && mc == o2::aod::femtodreamMCparticle::MCType::kRecon) { + if constexpr ((mParticleType == o2::aod::femtodreamparticle::ParticleType::kV0 || mParticleType == o2::aod::femtodreamparticle::ParticleType::kCascadeV0) && mc == o2::aod::femtodreamMCparticle::MCType::kRecon) { mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hInvMassLambda"), part.mLambda()); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hpTInvMassLambda"), part.pt(), part.mLambda()); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hInvMassAntiLambda"), part.mAntiLambda()); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hpTInvMassAntiLambda"), part.pt(), part.mAntiLambda()); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hInvMassLambdaAntiLambda"), part.mLambda(), part.mAntiLambda()); } + if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kCascade) { + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hInvMassCascade"), part.mLambda()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hpTInvMassCascade"), part.pt(), part.mLambda()); + // mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hInvMassCascade"), part.mLambda()); + // mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hpTInvMassCascade"), part.pt(), part.mLambda()); + } } template @@ -304,7 +350,7 @@ class FemtoDreamParticleHisto mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hEtaVsPhi"), part.eta(), part.phi()); // Histograms holding further debug information - if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kTrack || mParticleType == o2::aod::femtodreamparticle::ParticleType::kV0Child) { + if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kTrack || mParticleType == o2::aod::femtodreamparticle::ParticleType::kV0Child || mParticleType == o2::aod::femtodreamparticle::ParticleType::kCascadeV0Child || mParticleType == o2::aod::femtodreamparticle::ParticleType::kCascadeBachelor) { mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hCharge"), part.sign()); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hTPCfindable"), part.tpcNClsFindable()); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hTPCfound"), part.tpcNClsFound()); @@ -324,16 +370,30 @@ class FemtoDreamParticleHisto mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaTPC_K"), momentum, part.tpcNSigmaKa()); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaTPC_p"), momentum, part.tpcNSigmaPr()); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaTPC_d"), momentum, part.tpcNSigmaDe()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaTPC_tr"), momentum, part.tpcNSigmaTr()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaTPC_he3"), momentum, part.tpcNSigmaHe()); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaTOF_el"), momentum, part.tofNSigmaEl()); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaTOF_pi"), momentum, part.tofNSigmaPi()); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaTOF_K"), momentum, part.tofNSigmaKa()); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaTOF_p"), momentum, part.tofNSigmaPr()); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaTOF_d"), momentum, part.tofNSigmaDe()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaTOF_tr"), momentum, part.tofNSigmaTr()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaTOF_he3"), momentum, part.tofNSigmaHe()); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaComb_el"), momentum, std::sqrt(part.tpcNSigmaEl() * part.tpcNSigmaEl() + part.tofNSigmaEl() * part.tofNSigmaEl())); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaComb_pi"), momentum, std::sqrt(part.tpcNSigmaPi() * part.tpcNSigmaPi() + part.tofNSigmaPi() * part.tofNSigmaPi())); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaComb_K"), momentum, std::sqrt(part.tpcNSigmaKa() * part.tpcNSigmaKa() + part.tofNSigmaKa() * part.tofNSigmaKa())); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaComb_p"), momentum, std::sqrt(part.tpcNSigmaPr() * part.tpcNSigmaPr() + part.tofNSigmaPr() * part.tofNSigmaPr())); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaComb_d"), momentum, std::sqrt(part.tpcNSigmaDe() * part.tpcNSigmaDe() + part.tofNSigmaDe() * part.tofNSigmaDe())); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaComb_tr"), momentum, std::sqrt(part.tpcNSigmaTr() * part.tpcNSigmaTr() + part.tofNSigmaTr() * part.tofNSigmaTr())); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaComb_he3"), momentum, std::sqrt(part.tpcNSigmaHe() * part.tpcNSigmaHe() + part.tofNSigmaHe() * part.tofNSigmaHe())); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/ITSSignal"), momentum, part.itsSignal()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaITS_el"), momentum, part.itsNSigmaEl()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaITS_pi"), momentum, part.itsNSigmaPi()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaITS_K"), momentum, part.itsNSigmaKa()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaITS_p"), momentum, part.itsNSigmaPr()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaITS_d"), momentum, part.itsNSigmaDe()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaITS_tr"), momentum, part.itsNSigmaTr()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaITS_he3"), momentum, part.itsNSigmaHe()); if (correlatedPlots) { @@ -341,26 +401,34 @@ class FemtoDreamParticleHisto float pidTOF = 0.; switch (abs(mPDG)) { - case 11: + case kElectron: pidTPC = part.tpcNSigmaEl(); pidTOF = part.tofNSigmaEl(); break; - case 211: + case kPiPlus: pidTPC = part.tpcNSigmaPi(); pidTOF = part.tofNSigmaPi(); break; - case 321: + case kKPlus: pidTPC = part.tpcNSigmaKa(); pidTOF = part.tofNSigmaKa(); break; - case 2212: + case kProton: pidTPC = part.tpcNSigmaPr(); pidTOF = part.tofNSigmaPr(); break; - case 1000010020: + case constants::physics::kDeuteron: pidTPC = part.tpcNSigmaDe(); pidTOF = part.tofNSigmaDe(); break; + case constants::physics::kTriton: + pidTPC = part.tpcNSigmaTr(); + pidTOF = part.tofNSigmaTr(); + break; + case constants::physics::kHelium3: + pidTPC = part.tpcNSigmaHe(); + pidTOF = part.tofNSigmaHe(); + break; default: LOG(warn) << "PDG code " << mPDG << " not supported. No PID information will be used."; } @@ -381,6 +449,17 @@ class FemtoDreamParticleHisto mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hDecayVtxX"), part.decayVtxX()); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hDecayVtxY"), part.decayVtxY()); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hDecayVtxZ"), part.decayVtxZ()); + } else if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kCascade) { + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hCascV0DCADaugh"), part.daughDCA()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hCascV0TransRadius"), part.transRadius()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hCascV0DCAtoPV"), part.cascV0DCAtoPV()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hCascDaughDCA"), part.cascDaughDCA()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hCascTransRadius"), part.cascTransRadius()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hCascDecayVtxX"), part.cascDecayVtxX()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hCascDecayVtxY"), part.cascDecayVtxY()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hCascDecayVtxZ"), part.cascDecayVtxZ()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hInvMassCompetingCascade"), part.mOmega()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hpTInvMassCompetingCascade"), part.pt(), part.mOmega()); } } @@ -398,6 +477,12 @@ class FemtoDreamParticleHisto mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST("_MC/hPDG"), pdgcode); mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST("_MC/hOrigin_MC"), mctruthorigin); + auto MCpart = part.fdMCParticle(); + + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST("_MC/hPt_DiffTruthReco"), MCpart.pt(), (part.pt() - MCpart.pt()) / MCpart.pt()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST("_MC/hEta_DiffTruthReco"), MCpart.eta(), (part.eta() - MCpart.eta())); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST("_MC/hPhi_DiffTruthReco"), MCpart.phi(), (part.phi() - MCpart.phi())); + if (abs(pdgcode) == mPDG) { // fill this histogramm only for TRUE protons (independently of their origin) for the track purity estimation mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST("_MC/hPt_ReconNoFake"), part.pt()); } @@ -514,6 +599,18 @@ class FemtoDreamParticleHisto mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST("_MC/hCPA_Else"), part.pt(), part.tempFitVar(), mult); break; + case (o2::aod::femtodreamMCparticle::kSecondaryDaughterSigma0): + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST("_MC/hCPA_Secondary_SIGMA0"), + part.pt(), part.tempFitVar(), mult); + break; + case (o2::aod::femtodreamMCparticle::kSecondaryDaughterXiMinus): + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST("_MC/hCPA_Secondary_XIMinus"), + part.pt(), part.tempFitVar(), mult); + break; + case (o2::aod::femtodreamMCparticle::kSecondaryDaughterXi0): + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST("_MC/hCPA_Secondary_XI0"), + part.pt(), part.tempFitVar(), mult); + break; default: LOG(fatal) << "femtodreamparticleMC: not known value for ParticleOriginMCTruth - please check. Quitting!"; } @@ -543,6 +640,18 @@ class FemtoDreamParticleHisto mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST("_MC/hCPA_Else"), part.pt(), part.tempFitVar()); break; + case (o2::aod::femtodreamMCparticle::kSecondaryDaughterSigma0): + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST("_MC/hCPA_Secondary_SIGMA0"), + part.pt(), part.tempFitVar()); + break; + case (o2::aod::femtodreamMCparticle::kSecondaryDaughterXiMinus): + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST("_MC/hCPA_Secondary_XIMinus"), + part.pt(), part.tempFitVar()); + break; + case (o2::aod::femtodreamMCparticle::kSecondaryDaughterXi0): + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST("_MC/hCPA_Secondary_XI0"), + part.pt(), part.tempFitVar()); + break; default: LOG(fatal) << "femtodreamparticleMC: not known value for ParticleOriginMCTruth - please check. Quitting!"; } @@ -564,7 +673,6 @@ class FemtoDreamParticleHisto template void fillQA(Tpart const& part, aod::femtodreamparticle::MomentumType MomemtumType, const int mult, const float cent, bool correlatedPlots = false) { - std::string tempFitVarName; if (mHistogramRegistry) { fillQA_base(part, mult); if constexpr (isDebug) { @@ -582,11 +690,11 @@ class FemtoDreamParticleHisto } private: - HistogramRegistry* mHistogramRegistry; ///< For QA output - static constexpr o2::aod::femtodreamparticle::ParticleType mParticleType = particleType; ///< Type of the particle under analysis - static constexpr int mFolderSuffixType = suffixType; ///< Counter for the folder suffix specified below - static constexpr std::string_view mFolderSuffix[8] = {"", "_one", "_two", "_pos", "_neg", "_allSelected", "_allSelected_pos", "_allSelected_neg"}; ///< Suffix for the folder name in case of analyses of pairs of the same kind (T-T, V-V, C-C) - int mPDG = 0; ///< PDG code of the selected particle + HistogramRegistry* mHistogramRegistry; ///< For QA output + static constexpr o2::aod::femtodreamparticle::ParticleType mParticleType = particleType; ///< Type of the particle under analysis + static constexpr int mFolderSuffixType = suffixType; ///< Counter for the folder suffix specified below + static constexpr std::string_view mFolderSuffix[9] = {"", "_one", "_two", "_pos", "_neg", "_allSelected", "_allSelected_pos", "_allSelected_neg", "_bach"}; ///< Suffix for the folder name in case of analyses of pairs of the same kind (T-T, V-V, C-C) + int mPDG = 0; ///< PDG code of the selected particle }; } // namespace o2::analysis::femtoDream diff --git a/PWGCF/FemtoDream/Core/femtoDreamSelection.h b/PWGCF/FemtoDream/Core/femtoDreamSelection.h index 73d29ff7d51..1260f358830 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamSelection.h +++ b/PWGCF/FemtoDream/Core/femtoDreamSelection.h @@ -84,16 +84,16 @@ class FemtoDreamSelection case (femtoDreamSelection::SelectionType::kUpperLimit): return (observable <= mSelVal); case (femtoDreamSelection::SelectionType::kAbsUpperLimit): - return (std::abs(observable) <= mSelVal); + return (std::fabs(observable) <= mSelVal); break; case (femtoDreamSelection::SelectionType::kLowerLimit): return (observable >= mSelVal); case (femtoDreamSelection::SelectionType::kAbsLowerLimit): - return (std::abs(observable) >= mSelVal); + return (std::fabs(observable) >= mSelVal); break; case (femtoDreamSelection::SelectionType::kEqual): /// \todo can the comparison be done a bit nicer? - return (std::abs(observable - mSelVal) < std::abs(mSelVal * 1e-6)); + return (std::fabs(observable - mSelVal) < std::abs(mSelVal * 1e-6)); break; } return false; diff --git a/PWGCF/FemtoDream/Core/femtoDreamTrackSelection.h b/PWGCF/FemtoDream/Core/femtoDreamTrackSelection.h index ccc2913a1e7..f1006504d0c 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamTrackSelection.h +++ b/PWGCF/FemtoDream/Core/femtoDreamTrackSelection.h @@ -24,6 +24,8 @@ #include "PWGCF/DataModel/FemtoDerived.h" #include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" #include "PWGCF/FemtoDream/Core/femtoDreamObjectSelection.h" @@ -129,6 +131,14 @@ class FemtoDreamTrackSelection : public FemtoDreamObjectSelection auto getNsigmaTOF(T const& track, o2::track::PID pid); + /// Computes the n_sigma for a track and a particle-type hypothesis in the ITS + /// \tparam T Data type of the track + /// \param track Track for which PID is evaluated + /// \param pid Particle species for which PID is evaluated + /// \return Value of n_{sigma, ITS} + template + auto getNsigmaITS(T const& track, o2::track::PID pid); + /// Checks whether the most open combination of all selection criteria is fulfilled /// \tparam T Data type of the track /// \param track Track @@ -146,7 +156,7 @@ class FemtoDreamTrackSelection : public FemtoDreamObjectSelection + template std::array getCutContainer(T const& track, R Pt, R Eta, R Dcaxy); /// Some basic QA histograms @@ -154,7 +164,7 @@ class FemtoDreamTrackSelection : public FemtoDreamObjectSelection + template void fillQA(T const& track); /// Helper function to obtain the name of a given selection criterion for consistent naming of the configurables @@ -274,7 +284,7 @@ class FemtoDreamTrackSelection : public FemtoDreamObjectSelection void FemtoDreamTrackSelection::init(HistogramRegistry* QAregistry, HistogramRegistry* Registry) @@ -306,36 +318,39 @@ void FemtoDreamTrackSelection::init(HistogramRegistry* QAregistry, HistogramRegi if (nSelections > 8 * sizeof(cutContainerType)) { LOG(fatal) << "FemtoDreamTrackCuts: Number of selections too large for your container - quitting!"; } - mQAHistogramRegistry->add((folderName + "/hPt").c_str(), "; #it{p}_{T} (GeV/#it{c}); Entries", kTH1F, {{240, 0, 6}}); - mQAHistogramRegistry->add((folderName + "/hEta").c_str(), "; #eta; Entries", kTH1F, {{200, -1.5, 1.5}}); - mQAHistogramRegistry->add((folderName + "/hPhi").c_str(), "; #phi; Entries", kTH1F, {{200, 0, 2. * M_PI}}); - mQAHistogramRegistry->add((folderName + "/hTPCfindable").c_str(), "; TPC findable clusters; Entries", kTH1F, {{163, -0.5, 162.5}}); - mQAHistogramRegistry->add((folderName + "/hTPCfound").c_str(), "; TPC found clusters; Entries", kTH1F, {{163, -0.5, 162.5}}); - mQAHistogramRegistry->add((folderName + "/hTPCcrossedOverFindalbe").c_str(), "; TPC ratio findable; Entries", kTH1F, {{100, 0.5, 1.5}}); - mQAHistogramRegistry->add((folderName + "/hTPCcrossedRows").c_str(), "; TPC crossed rows; Entries", kTH1F, {{163, 0, 163}}); - mQAHistogramRegistry->add((folderName + "/hTPCfindableVsCrossed").c_str(), ";TPC findable clusters ; TPC crossed rows;", kTH2F, {{163, 0, 163}, {163, 0, 163}}); - mQAHistogramRegistry->add((folderName + "/hTPCshared").c_str(), "; TPC shared clusters; Entries", kTH1F, {{163, -0.5, 162.5}}); - mQAHistogramRegistry->add((folderName + "/hITSclusters").c_str(), "; ITS clusters; Entries", kTH1F, {{10, -0.5, 9.5}}); - mQAHistogramRegistry->add((folderName + "/hITSclustersIB").c_str(), "; ITS clusters in IB; Entries", kTH1F, {{10, -0.5, 9.5}}); - mQAHistogramRegistry->add((folderName + "/hDCAxy").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {{100, 0, 10}, {500, -5, 5}}); - mQAHistogramRegistry->add((folderName + "/hDCAz").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{z} (cm)", kTH2F, {{100, 0, 10}, {500, -5, 5}}); - mQAHistogramRegistry->add((folderName + "/hDCA").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA (cm)", kTH2F, {{100, 0, 10}, {301, 0., 1.5}}); - mQAHistogramRegistry->add((folderName + "/hTPCdEdX").c_str(), "; #it{p} (GeV/#it{c}); TPC Signal", kTH2F, {{100, 0, 10}, {1000, 0, 1000}}); - mQAHistogramRegistry->add((folderName + "/nSigmaTPC_el").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{e}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mQAHistogramRegistry->add((folderName + "/nSigmaTPC_pi").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{#pi}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mQAHistogramRegistry->add((folderName + "/nSigmaTPC_K").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{K}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mQAHistogramRegistry->add((folderName + "/nSigmaTPC_p").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{p}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mQAHistogramRegistry->add((folderName + "/nSigmaTPC_d").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{d}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mQAHistogramRegistry->add((folderName + "/nSigmaTOF_el").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{e}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mQAHistogramRegistry->add((folderName + "/nSigmaTOF_pi").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{#pi}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mQAHistogramRegistry->add((folderName + "/nSigmaTOF_K").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{K}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mQAHistogramRegistry->add((folderName + "/nSigmaTOF_p").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{p}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mQAHistogramRegistry->add((folderName + "/nSigmaTOF_d").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{d}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mQAHistogramRegistry->add((folderName + "/nSigmaComb_el").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{e}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mQAHistogramRegistry->add((folderName + "/nSigmaComb_pi").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{#pi}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mQAHistogramRegistry->add((folderName + "/nSigmaComb_K").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{K}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mQAHistogramRegistry->add((folderName + "/nSigmaComb_p").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{p}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mQAHistogramRegistry->add((folderName + "/nSigmaComb_d").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{d}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + + for (int istage = 0; istage < kNcutStages; istage++) { + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hPt").c_str(), "; #it{p}_{T} (GeV/#it{c}); Entries", kTH1F, {{240, 0, 6}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hEta").c_str(), "; #eta; Entries", kTH1F, {{200, -1.5, 1.5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hPhi").c_str(), "; #phi; Entries", kTH1F, {{200, 0, 2. * M_PI}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hTPCfindable").c_str(), "; TPC findable clusters; Entries", kTH1F, {{163, -0.5, 162.5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hTPCfound").c_str(), "; TPC found clusters; Entries", kTH1F, {{163, -0.5, 162.5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hTPCcrossedOverFindalbe").c_str(), "; TPC ratio findable; Entries", kTH1F, {{100, 0.5, 1.5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hTPCcrossedRows").c_str(), "; TPC crossed rows; Entries", kTH1F, {{163, 0, 163}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hTPCfindableVsCrossed").c_str(), ";TPC findable clusters ; TPC crossed rows;", kTH2F, {{163, 0, 163}, {163, 0, 163}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hTPCshared").c_str(), "; TPC shared clusters; Entries", kTH1F, {{163, -0.5, 162.5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hITSclusters").c_str(), "; ITS clusters; Entries", kTH1F, {{10, -0.5, 9.5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hITSclustersIB").c_str(), "; ITS clusters in IB; Entries", kTH1F, {{10, -0.5, 9.5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hDCAxy").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {{100, 0, 10}, {500, -5, 5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hDCAz").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{z} (cm)", kTH2F, {{100, 0, 10}, {500, -5, 5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hDCA").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA (cm)", kTH2F, {{100, 0, 10}, {301, 0., 1.5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/hTPCdEdX").c_str(), "; #it{p} (GeV/#it{c}); TPC Signal", kTH2F, {{100, 0, 10}, {1000, 0, 1000}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/nSigmaTPC_el").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{e}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/nSigmaTPC_pi").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{#pi}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/nSigmaTPC_K").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{K}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/nSigmaTPC_p").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{p}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/nSigmaTPC_d").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{d}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/nSigmaTOF_el").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{e}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/nSigmaTOF_pi").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{#pi}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/nSigmaTOF_K").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{K}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/nSigmaTOF_p").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{p}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/nSigmaTOF_d").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{d}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/nSigmaComb_el").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{e}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/nSigmaComb_pi").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{#pi}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/nSigmaComb_K").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{K}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/nSigmaComb_p").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{p}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + mQAHistogramRegistry->add((folderName + "/" + static_cast(mCutStage[istage]) + "/nSigmaComb_d").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{d}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + } } /// set cuts @@ -371,18 +386,7 @@ void FemtoDreamTrackSelection::init(HistogramRegistry* QAregistry, HistogramRegi template auto FemtoDreamTrackSelection::getNsigmaTPC(T const& track, o2::track::PID pid) { - if (pid == o2::track::PID::Electron) - return track.tpcNSigmaEl(); - else if (pid == o2::track::PID::Pion) - return track.tpcNSigmaPi(); - else if (pid == o2::track::PID::Kaon) - return track.tpcNSigmaKa(); - else if (pid == o2::track::PID::Proton) - return track.tpcNSigmaPr(); - else if (pid == o2::track::PID::Deuteron) - return track.tpcNSigmaDe(); - else - return 999.f; + return o2::aod::pidutils::tpcNSigma(pid, track); } template @@ -392,18 +396,29 @@ auto FemtoDreamTrackSelection::getNsigmaTOF(T const& track, o2::track::PID pid) if (!track.hasTOF()) { return 999.f; } - if (pid == o2::track::PID::Electron) - return track.tofNSigmaEl(); - else if (pid == o2::track::PID::Pion) - return track.tofNSigmaPi(); - else if (pid == o2::track::PID::Kaon) - return track.tofNSigmaKa(); - else if (pid == o2::track::PID::Proton) - return track.tofNSigmaPr(); - else if (pid == o2::track::PID::Deuteron) - return track.tofNSigmaDe(); - else - return 999.f; + return o2::aod::pidutils::tofNSigma(pid, track); +} + +template +auto FemtoDreamTrackSelection::getNsigmaITS(T const& track, o2::track::PID pid) +{ + if (pid == o2::track::PID::Electron) { + return track.itsNSigmaEl(); + } else if (pid == o2::track::PID::Pion) { + return track.itsNSigmaPi(); + } else if (pid == o2::track::PID::Kaon) { + return track.itsNSigmaKa(); + } else if (pid == o2::track::PID::Proton) { + return track.itsNSigmaPr(); + } else if (pid == o2::track::PID::Deuteron) { + return track.itsNSigmaDe(); + } else if (pid == o2::track::PID::Triton) { + return track.itsNSigmaTr(); + } else if (pid == o2::track::PID::Helium3) { + return track.itsNSigmaHe(); + } + // if nothing matched, return default value + return -999.f; } template @@ -433,7 +448,7 @@ bool FemtoDreamTrackSelection::isSelectedMinimal(T const& track) if (nPtMaxSel > 0 && pT > pTMax) { return false; } - if (nEtaSel > 0 && std::abs(eta) > etaMax) { + if (nEtaSel > 0 && std::fabs(eta) > etaMax) { return false; } if (nTPCnMinSel > 0 && tpcNClsF < nClsMin) { @@ -454,16 +469,16 @@ bool FemtoDreamTrackSelection::isSelectedMinimal(T const& track) if (nITScIbMinSel > 0 && itsNClsIB < nITSclsIbMin) { return false; } - if (nDCAxyMaxSel > 0 && std::abs(dcaXY) > dcaXYMax) { + if (nDCAxyMaxSel > 0 && std::fabs(dcaXY) > dcaXYMax) { return false; } - if (nDCAzMaxSel > 0 && std::abs(dcaZ) > dcaZMax) { + if (nDCAzMaxSel > 0 && std::fabs(dcaZ) > dcaZMax) { return false; } - if (nDCAMinSel > 0 && std::abs(dca) < dcaMin) { + if (nDCAMinSel > 0 && std::fabs(dca) < dcaMin) { return false; } - if (nRejectNotPropagatedTracks && std::abs(dca) > 1e3) { + if (nRejectNotPropagatedTracks && std::fabs(dca) > 1e3) { return false; } @@ -471,7 +486,7 @@ bool FemtoDreamTrackSelection::isSelectedMinimal(T const& track) bool isFulfilled = false; for (size_t i = 0; i < pidTPC.size(); ++i) { auto pidTPCVal = pidTPC.at(i); - if (std::abs(pidTPCVal - nSigmaPIDOffsetTPC) < nSigmaPIDMax) { + if (std::fabs(pidTPCVal - nSigmaPIDOffsetTPC) < nSigmaPIDMax) { isFulfilled = true; } } @@ -482,7 +497,7 @@ bool FemtoDreamTrackSelection::isSelectedMinimal(T const& track) return true; } -template +template std::array FemtoDreamTrackSelection::getCutContainer(T const& track, R Pt, R Eta, R Dca) { cutContainerType output = 0; @@ -501,23 +516,30 @@ std::array FemtoDreamTrackSelection::getCutContainer(T cons const auto dcaZ = track.dcaZ(); const auto dca = Dca; - std::vector pidTPC, pidTOF; + std::vector pidTPC, pidTOF, pidITS; for (auto it : mPIDspecies) { pidTPC.push_back(getNsigmaTPC(track, it)); pidTOF.push_back(getNsigmaTOF(track, it)); + if constexpr (useItsPid) { + pidITS.push_back(getNsigmaITS(track, it)); + } } float observable = 0.; for (auto& sel : mSelections) { const auto selVariable = sel.getSelectionVariable(); if (selVariable == femtoDreamTrackSelection::kPIDnSigmaMax) { - /// PID needs to be handled a bit differently since we may need more than one species + /// PID needsgetNsigmaITSto be handled a bit differently since we may need more than one species for (size_t i = 0; i < mPIDspecies.size(); ++i) { auto pidTPCVal = pidTPC.at(i) - nSigmaPIDOffsetTPC; auto pidTOFVal = pidTOF.at(i) - nSigmaPIDOffsetTOF; auto pidComb = std::sqrt(pidTPCVal * pidTPCVal + pidTOFVal * pidTOFVal); sel.checkSelectionSetBitPID(pidTPCVal, outputPID); sel.checkSelectionSetBitPID(pidComb, outputPID); + if constexpr (useItsPid) { + auto pidITSVal = pidITS.at(i); + sel.checkSelectionSetBitPID(pidITSVal, outputPID); + } } } else { /// for the rest it's all the same @@ -568,40 +590,43 @@ std::array FemtoDreamTrackSelection::getCutContainer(T cons return {output, outputPID}; } -template +template void FemtoDreamTrackSelection::fillQA(T const& track) { if (mQAHistogramRegistry) { - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/hPt"), track.pt()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/hEta"), track.eta()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/hPhi"), track.phi()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/hTPCfindable"), track.tpcNClsFindable()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/hTPCfound"), track.tpcNClsFound()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/hTPCcrossedOverFindalbe"), track.tpcCrossedRowsOverFindableCls()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/hTPCcrossedRows"), track.tpcNClsCrossedRows()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/hTPCfindableVsCrossed"), track.tpcNClsFindable(), track.tpcNClsCrossedRows()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/hTPCshared"), track.tpcNClsShared()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/hITSclusters"), track.itsNCls()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/hITSclustersIB"), track.itsNClsInnerBarrel()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/hDCAxy"), track.pt(), track.dcaXY()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/hDCAz"), track.pt(), track.dcaZ()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/hDCA"), track.pt(), std::sqrt(pow(track.dcaXY(), 2.) + pow(track.dcaZ(), 2.))); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/hTPCdEdX"), track.p(), track.tpcSignal()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/nSigmaTPC_el"), track.p(), track.tpcNSigmaEl()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/nSigmaTPC_pi"), track.p(), track.tpcNSigmaPi()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/nSigmaTPC_K"), track.p(), track.tpcNSigmaKa()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/nSigmaTPC_p"), track.p(), track.tpcNSigmaPr()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/nSigmaTPC_d"), track.p(), track.tpcNSigmaDe()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/nSigmaTOF_el"), track.p(), track.tofNSigmaEl()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/nSigmaTOF_pi"), track.p(), track.tofNSigmaPi()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/nSigmaTOF_K"), track.p(), track.tofNSigmaKa()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/nSigmaTOF_p"), track.p(), track.tofNSigmaPr()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/nSigmaTOF_d"), track.p(), track.tofNSigmaDe()); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/nSigmaComb_el"), track.p(), std::sqrt(track.tpcNSigmaEl() * track.tpcNSigmaEl() + track.tofNSigmaEl() * track.tofNSigmaEl())); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/nSigmaComb_pi"), track.p(), std::sqrt(track.tpcNSigmaPi() * track.tpcNSigmaPi() + track.tofNSigmaPi() * track.tofNSigmaPi())); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/nSigmaComb_K"), track.p(), std::sqrt(track.tpcNSigmaKa() * track.tpcNSigmaKa() + track.tofNSigmaKa() * track.tofNSigmaKa())); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/nSigmaComb_p"), track.p(), std::sqrt(track.tpcNSigmaPr() * track.tpcNSigmaPr() + track.tofNSigmaPr() * track.tofNSigmaPr())); - mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/nSigmaComb_d"), track.p(), std::sqrt(track.tpcNSigmaDe() * track.tpcNSigmaDe() + track.tofNSigmaDe() * track.tofNSigmaDe())); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hPt"), track.pt()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hEta"), track.eta()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hPhi"), track.phi()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hTPCfindable"), track.tpcNClsFindable()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hTPCfound"), track.tpcNClsFound()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hTPCcrossedOverFindalbe"), track.tpcCrossedRowsOverFindableCls()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hTPCcrossedRows"), track.tpcNClsCrossedRows()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hTPCfindableVsCrossed"), track.tpcNClsFindable(), track.tpcNClsCrossedRows()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hTPCshared"), track.tpcNClsShared()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hITSclusters"), track.itsNCls()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hITSclustersIB"), track.itsNClsInnerBarrel()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hDCAxy"), track.pt(), track.dcaXY()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hDCAz"), track.pt(), track.dcaZ()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hDCA"), track.pt(), std::sqrt(pow(track.dcaXY(), 2.) + pow(track.dcaZ(), 2.))); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hTPCdEdX"), track.p(), track.tpcSignal()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/nSigmaTPC_pi"), track.p(), track.tpcNSigmaPi()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/nSigmaTPC_K"), track.p(), track.tpcNSigmaKa()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/nSigmaTPC_p"), track.p(), track.tpcNSigmaPr()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/nSigmaTOF_pi"), track.p(), track.tofNSigmaPi()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/nSigmaTOF_K"), track.p(), track.tofNSigmaKa()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/nSigmaTOF_p"), track.p(), track.tofNSigmaPr()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/nSigmaComb_pi"), track.p(), std::sqrt(track.tpcNSigmaPi() * track.tpcNSigmaPi() + track.tofNSigmaPi() * track.tofNSigmaPi())); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/nSigmaComb_K"), track.p(), std::sqrt(track.tpcNSigmaKa() * track.tpcNSigmaKa() + track.tofNSigmaKa() * track.tofNSigmaKa())); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/nSigmaComb_p"), track.p(), std::sqrt(track.tpcNSigmaPr() * track.tpcNSigmaPr() + track.tofNSigmaPr() * track.tofNSigmaPr())); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/nSigmaTPC_d"), track.p(), track.tpcNSigmaDe()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/nSigmaComb_d"), track.p(), std::sqrt(track.tpcNSigmaDe() * track.tpcNSigmaDe() + track.tofNSigmaDe() * track.tofNSigmaDe())); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/nSigmaTOF_d"), track.p(), track.tofNSigmaDe()); + + if constexpr (!isHF) { + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/nSigmaComb_el"), track.p(), std::sqrt(track.tpcNSigmaEl() * track.tpcNSigmaEl() + track.tofNSigmaEl() * track.tofNSigmaEl())); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/nSigmaTOF_el"), track.p(), track.tofNSigmaEl()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtodreamparticle::TrackTypeName[tracktype]) + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/nSigmaTPC_el"), track.p(), track.tpcNSigmaEl()); + } } } diff --git a/PWGCF/FemtoDream/Core/femtoDreamUtils.h b/PWGCF/FemtoDream/Core/femtoDreamUtils.h index 08de682cdb2..b170985233f 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamUtils.h +++ b/PWGCF/FemtoDream/Core/femtoDreamUtils.h @@ -18,87 +18,12 @@ #include #include -#include -#include -#include "Framework/ASoAHelpers.h" #include "CommonConstants/PhysicsConstants.h" #include "PWGCF/DataModel/FemtoDerived.h" namespace o2::analysis::femtoDream { -// TODO: remove all these functions pertaining to PID selection for the next tutorial session they have been removed from femtodream tasks but are still present in tutorial files - -enum kDetector { kTPC, - kTPCTOF, - kNdetectors }; - -/// internal function that returns the kPIDselection element corresponding to a -/// specifica n-sigma value \param nSigma number of sigmas for PID -/// \param vNsigma vector with the number of sigmas of interest -/// \return kPIDselection corresponding to n-sigma -int getPIDselection(float nSigma, std::vector vNsigma) -{ - std::sort(vNsigma.begin(), vNsigma.end(), std::greater<>()); - auto it = std::find(vNsigma.begin(), vNsigma.end(), nSigma); - if (it == vNsigma.end()) { - it = vNsigma.begin() + 1; - LOG(warn) << "Invalid value of nSigma: " << nSigma << ". Return the first value of the vector: " << *(it); - } - return std::distance(vNsigma.begin(), it); -} - -/// function that checks whether the PID selection specified in the vectors is -/// fulfilled -/// \param pidcut Bit-wise container for the PID -/// \param vSpecies vector with ID corresponding to the selected species (output from cutculator) -/// \param nSpecies number of available selected species (output from cutculator) -/// \param nSigma number of sigma selection fo PID -/// \param vNsigma vector with available n-sigma selections for PID -/// \param kDetector enum corresponding to the PID technique -/// \return Whether the PID selection specified in the vectors is fulfilled -bool isPIDSelected(aod::femtodreamparticle::cutContainerType pidcut, - int vSpecies, - int nSpecies, - float nSigma, - std::vector vNsigma, - kDetector iDet) -{ - int iNsigma = getPIDselection(nSigma, vNsigma); - int nDet = static_cast(kDetector::kNdetectors); - int bit_to_check = 1 + (vNsigma.size() - (iNsigma + 1)) * nDet * nSpecies + (nSpecies - (vSpecies + 1)) * nSpecies + (nDet - 1 - iDet); - return ((pidcut >> (bit_to_check)) & 1) == 1; -}; - -/// function that checks whether the PID selection specified in the vectors is fulfilled, depending on the momentum TPC or TPC+TOF PID is conducted -/// \param pidcut Bit-wise container for the PID -/// \param momentum Momentum of the track -/// \param pidThresh Momentum threshold that separates between TPC and TPC+TOF PID -/// \param vSpecies Vector with the species of interest (number returned by the CutCulator) -/// \param nSpecies number of available selected species (output from cutculator) -/// \param nSigmaTPC Number of TPC sigmas for selection -/// \param nSigmaTPCTOF Number of TPC+TOF sigmas for selection (circular selection) -/// \return Whether the PID selection is fulfilled -bool isFullPIDSelected(aod::femtodreamparticle::cutContainerType const& pidCut, - float momentum, - float pidThresh, - int vSpecies, - int nSpecies, - std::vector vNsigma, - float nSigmaTPC, - float nSigmaTPCTOF) -{ - bool pidSelection = true; - if (momentum < pidThresh) { - /// TPC PID only - pidSelection = isPIDSelected(pidCut, vSpecies, nSpecies, nSigmaTPC, vNsigma, kDetector::kTPC); - } else { - /// TPC + TOF PID - pidSelection = isPIDSelected(pidCut, vSpecies, nSpecies, nSigmaTPCTOF, vNsigma, kDetector::kTPCTOF); - } - return pidSelection; -}; - /// function for getting the mass of a particle depending on the pdg code /// \param pdgCode pdg code of the particle /// \return mass of the particle @@ -106,28 +31,43 @@ inline float getMass(int pdgCode) { // use this function instead of TDatabasePDG to return masses defined in the PhysicsConstants.h header // this approach saves a lot of memory and important partilces like deuteron are missing in TDatabasePDG anyway - float Mass = 0; + float mass = 0; // add new particles if necessary here switch (std::abs(pdgCode)) { - case 211: // charged pions - Mass = o2::constants::physics::MassPiPlus; + case kPiPlus: + mass = o2::constants::physics::MassPiPlus; + break; + case kKPlus: + mass = o2::constants::physics::MassKPlus; + break; + case kProton: + mass = o2::constants::physics::MassProton; break; - case 321: // charged kaon - Mass = o2::constants::physics::MassKPlus; + case kLambda0: + mass = o2::constants::physics::MassLambda; break; - case 2212: // proton - Mass = o2::constants::physics::MassProton; + case kXiMinus: + mass = o2::constants::physics::MassXiMinus; break; - case 3122: // Lambda - Mass = o2::constants::physics::MassLambda; + case o2::constants::physics::Pdg::kPhi: + mass = o2::constants::physics::MassPhi; break; - case 1000010020: // Deuteron - Mass = o2::constants::physics::MassDeuteron; + case o2::constants::physics::Pdg::kLambdaCPlus: + mass = o2::constants::physics::MassLambdaCPlus; + break; + case o2::constants::physics::Pdg::kDeuteron: + mass = o2::constants::physics::MassDeuteron; + break; + case o2::constants::physics::Pdg::kTriton: + mass = o2::constants::physics::MassTriton; + break; + case o2::constants::physics::Pdg::kHelium3: + mass = o2::constants::physics::MassHelium3; break; default: LOG(fatal) << "PDG code is not suppored"; } - return Mass; + return mass; } inline int checkDaughterType(o2::aod::femtodreamparticle::ParticleType partType, int motherPDG) @@ -135,10 +75,10 @@ inline int checkDaughterType(o2::aod::femtodreamparticle::ParticleType partType, int partOrigin = 0; if (partType == o2::aod::femtodreamparticle::ParticleType::kTrack) { switch (abs(motherPDG)) { - case 3122: + case kLambda0: partOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kSecondaryDaughterLambda; break; - case 3222: + case kSigmaPlus: partOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kSecondaryDaughterSigmaplus; break; default: @@ -146,14 +86,26 @@ inline int checkDaughterType(o2::aod::femtodreamparticle::ParticleType partType, } // switch } else if (partType == o2::aod::femtodreamparticle::ParticleType::kV0) { - partOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kSecondary; + switch (abs(motherPDG)) { + case kSigma0: + partOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kSecondaryDaughterSigma0; + break; + case kXiMinus: + partOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kSecondaryDaughterXiMinus; + break; + case o2::constants::physics::Pdg::kXi0: + partOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kSecondaryDaughterXi0; + break; + default: + partOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kSecondary; + } } else if (partType == o2::aod::femtodreamparticle::ParticleType::kV0Child) { switch (abs(motherPDG)) { - case 3122: + case kLambda0: partOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kSecondaryDaughterLambda; break; - case 3222: + case kSigmaPlus: partOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kSecondaryDaughterSigmaplus; break; default: @@ -181,5 +133,22 @@ inline bool containsNameValuePair(const std::vector& myVector, const std::str return false; // No match found } +template +float itsSignal(T const& track) +{ + uint32_t clsizeflag = track.itsClusterSizes(); + auto clSizeLayer0 = (clsizeflag >> (0 * 4)) & 0xf; + auto clSizeLayer1 = (clsizeflag >> (1 * 4)) & 0xf; + auto clSizeLayer2 = (clsizeflag >> (2 * 4)) & 0xf; + auto clSizeLayer3 = (clsizeflag >> (3 * 4)) & 0xf; + auto clSizeLayer4 = (clsizeflag >> (4 * 4)) & 0xf; + auto clSizeLayer5 = (clsizeflag >> (5 * 4)) & 0xf; + auto clSizeLayer6 = (clsizeflag >> (6 * 4)) & 0xf; + int numLayers = 7; + int sumClusterSizes = clSizeLayer1 + clSizeLayer2 + clSizeLayer3 + clSizeLayer4 + clSizeLayer5 + clSizeLayer6 + clSizeLayer0; + float cosLamnda = 1. / std::cosh(track.eta()); + return (static_cast(sumClusterSizes) / numLayers) * cosLamnda; +}; + } // namespace o2::analysis::femtoDream #endif // PWGCF_FEMTODREAM_CORE_FEMTODREAMUTILS_H_ diff --git a/PWGCF/FemtoDream/Core/femtoDreamV0Selection.h b/PWGCF/FemtoDream/Core/femtoDreamV0Selection.h index 2ae0f46a967..af9290d51ad 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamV0Selection.h +++ b/PWGCF/FemtoDream/Core/femtoDreamV0Selection.h @@ -471,10 +471,10 @@ bool FemtoDreamV0Selection::isSelectedMinimal(C const& /*col*/, V const& v0, // v0 auto nSigmaPiNeg = negTrack.tpcNSigmaPi(); auto nSigmaPrPos = posTrack.tpcNSigmaPr(); - if (!(abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && - abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax) && - !(abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && - abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax)) { + if (!(std::abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && + std::abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax) && + !(std::abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && + std::abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax)) { return false; } @@ -550,16 +550,16 @@ template std::array FemtoDreamV0Selection::getCutContainer(C const& /*col*/, V const& v0, T const& posTrack, T const& negTrack) { - auto outputPosTrack = PosDaughTrack.getCutContainer(posTrack, v0.positivept(), v0.positiveeta(), v0.dcapostopv()); - auto outputNegTrack = NegDaughTrack.getCutContainer(negTrack, v0.negativept(), v0.negativeeta(), v0.dcanegtopv()); + auto outputPosTrack = PosDaughTrack.getCutContainer(posTrack, v0.positivept(), v0.positiveeta(), v0.dcapostopv()); + auto outputNegTrack = NegDaughTrack.getCutContainer(negTrack, v0.negativept(), v0.negativeeta(), v0.dcanegtopv()); cutContainerType output = 0; size_t counter = 0; auto lambdaMassNominal = o2::constants::physics::MassLambda; auto lambdaMassHypothesis = v0.mLambda(); auto antiLambdaMassHypothesis = v0.mAntiLambda(); - auto diffLambda = abs(lambdaMassNominal - lambdaMassHypothesis); - auto diffAntiLambda = abs(antiLambdaMassHypothesis - lambdaMassHypothesis); + auto diffLambda = std::abs(lambdaMassNominal - lambdaMassHypothesis); + auto diffAntiLambda = std::abs(antiLambdaMassHypothesis - lambdaMassHypothesis); float sign = 0.; int nSigmaPIDMax = PosDaughTrack.getSigmaPIDMax(); @@ -568,15 +568,15 @@ std::array auto nSigmaPiNeg = negTrack.tpcNSigmaPi(); auto nSigmaPrPos = posTrack.tpcNSigmaPr(); // check the mass and the PID of daughters - if (abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && diffAntiLambda > diffLambda) { + if (std::abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && std::abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && diffAntiLambda > diffLambda) { sign = -1.; - } else if (abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && diffAntiLambda < diffLambda) { + } else if (std::abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && std::abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && diffAntiLambda < diffLambda) { sign = 1.; } else { // if it happens that none of these are true, ignore the invariant mass - if (abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax) { + if (std::abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && std::abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax) { sign = -1.; - } else if (abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax) { + } else if (std::abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && std::abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax) { sign = 1.; } } diff --git a/PWGCF/FemtoDream/TableProducer/CMakeLists.txt b/PWGCF/FemtoDream/TableProducer/CMakeLists.txt index 0f8d87d9570..77ece58f958 100644 --- a/PWGCF/FemtoDream/TableProducer/CMakeLists.txt +++ b/PWGCF/FemtoDream/TableProducer/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2019-2024 CERN and copyright holders of ALICE O2. +# Copyright 2019-2025 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. # @@ -11,10 +11,20 @@ o2physics_add_dpl_workflow(femtodream-producer SOURCES femtoDreamProducerTask.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femtodream-producer-withcascades + SOURCES femtoDreamProducerTaskWithCascades.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(femtodream-producer-reduced SOURCES femtoDreamProducerReducedTask.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femtodream-producer-for-specific-analysis + SOURCES femtoDreamProducerTaskForSpecificAnalysis.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/FemtoDream/TableProducer/femtoDreamProducerReducedTask.cxx b/PWGCF/FemtoDream/TableProducer/femtoDreamProducerReducedTask.cxx index 0739c7890e7..621b2693ff9 100644 --- a/PWGCF/FemtoDream/TableProducer/femtoDreamProducerReducedTask.cxx +++ b/PWGCF/FemtoDream/TableProducer/femtoDreamProducerReducedTask.cxx @@ -15,8 +15,9 @@ /// \author Georgios Mantzaridis, TU München, georgios.mantzaridis@tum.de /// \author Anton Riedel, TU München, anton.riedel@tum.de +#include #include "TMath.h" -#include +#include "CCDB/BasicCCDBManager.h" #include "PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h" #include "PWGCF/FemtoDream/Core/femtoDreamTrackSelection.h" #include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" @@ -28,6 +29,7 @@ #include "Framework/ASoAHelpers.h" #include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" #include "ReconstructionDataFormats/Track.h" @@ -50,10 +52,10 @@ using FemtoFullCollisionMC = soa::Join::iterator; using FemtoFullTracks = soa::Join; + aod::pidTPCFullEl, aod::pidTPCFullMu, aod::pidTPCFullPi, aod::pidTPCFullKa, + aod::pidTPCFullPr, aod::pidTPCFullDe, aod::pidTPCFullTr, aod::pidTPCFullHe, + aod::pidTOFFullEl, aod::pidTOFFullMu, aod::pidTOFFullPi, aod::pidTOFFullKa, + aod::pidTOFFullPr, aod::pidTOFFullDe, aod::pidTOFFullTr, aod::pidTOFFullHe>; } // namespace o2::aod struct femtoDreamProducerReducedTask { @@ -266,7 +268,7 @@ struct femtoDreamProducerReducedTask { trackCuts.fillQA(track); // an array of two bit-wise containers of the systematic variations is obtained // one container for the track quality cuts and one for the PID cuts - auto cutContainer = trackCuts.getCutContainer(track, track.pt(), track.eta(), sqrtf(powf(track.dcaXY(), 2.f) + powf(track.dcaZ(), 2.f))); + auto cutContainer = trackCuts.getCutContainer(track, track.pt(), track.eta(), sqrtf(powf(track.dcaXY(), 2.f) + powf(track.dcaZ(), 2.f))); // now the table is filled outputParts(outputCollision.lastIndex(), @@ -298,12 +300,25 @@ struct femtoDreamProducerReducedTask { track.tpcNSigmaKa(), track.tpcNSigmaPr(), track.tpcNSigmaDe(), + track.tpcNSigmaTr(), + track.tpcNSigmaHe(), track.tofNSigmaEl(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), track.tofNSigmaDe(), - -999., -999., -999., -999., -999., -999.); + track.tofNSigmaTr(), + track.tofNSigmaHe(), + -1, + track.itsNSigmaEl(), + track.itsNSigmaPi(), + track.itsNSigmaKa(), + track.itsNSigmaPr(), + track.itsNSigmaDe(), + track.itsNSigmaTr(), + track.itsNSigmaHe(), + -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., -999., -999.); } } } @@ -313,8 +328,11 @@ struct femtoDreamProducerReducedTask { { // get magnetic field for run getMagneticFieldTesla(col.bc_as()); + + auto tracksWithItsPid = soa::Attach(tracks); // fill the tables - fillCollisionsAndTracks(col, tracks); + fillCollisionsAndTracks(col, tracksWithItsPid); } PROCESS_SWITCH(femtoDreamProducerReducedTask, processData, "Provide experimental data", true); @@ -325,8 +343,10 @@ struct femtoDreamProducerReducedTask { { // get magnetic field for run getMagneticFieldTesla(col.bc_as()); + auto tracksWithItsPid = soa::Attach, aod::pidits::ITSNSigmaEl, aod::pidits::ITSNSigmaPi, aod::pidits::ITSNSigmaKa, + aod::pidits::ITSNSigmaPr, aod::pidits::ITSNSigmaDe, aod::pidits::ITSNSigmaTr, aod::pidits::ITSNSigmaHe>(tracks); // fill the tables - fillCollisionsAndTracks(col, tracks); + fillCollisionsAndTracks(col, tracksWithItsPid); } PROCESS_SWITCH(femtoDreamProducerReducedTask, processMC, "Provide MC data", false); @@ -337,8 +357,10 @@ struct femtoDreamProducerReducedTask { { // get magnetic field for run getMagneticFieldTesla(col.bc_as()); + auto tracksWithItsPid = soa::Attach, aod::pidits::ITSNSigmaEl, aod::pidits::ITSNSigmaPi, aod::pidits::ITSNSigmaKa, + aod::pidits::ITSNSigmaPr, aod::pidits::ITSNSigmaDe, aod::pidits::ITSNSigmaTr, aod::pidits::ITSNSigmaHe>(tracks); // fill the tables - fillCollisionsAndTracks(col, tracks); + fillCollisionsAndTracks(col, tracksWithItsPid); } PROCESS_SWITCH(femtoDreamProducerReducedTask, processMC_noCentrality, "Provide MC data", false); }; diff --git a/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTask.cxx b/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTask.cxx index 8bcd862a2c4..6a80a9d2caa 100644 --- a/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTask.cxx +++ b/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTask.cxx @@ -14,28 +14,34 @@ /// \author Laura Serksnyte, TU München, laura.serksnyte@tum.de #include +#include +#include +#include #include "Common/Core/trackUtilities.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" #include "Common/DataModel/TrackSelectionTables.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" #include "PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h" #include "PWGCF/FemtoDream/Core/femtoDreamTrackSelection.h" #include "PWGCF/FemtoDream/Core/femtoDreamV0Selection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamCascadeSelection.h" #include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" -#include "Math/Vector4D.h" +#include "EventFiltering/Zorro.h" #include "PWGCF/DataModel/FemtoDerived.h" #include "PWGLF/DataModel/LFStrangenessTables.h" #include "ReconstructionDataFormats/Track.h" #include "TMath.h" +#include "Math/Vector4D.h" using namespace o2; using namespace o2::framework; @@ -46,17 +52,30 @@ namespace o2::aod { using FemtoFullCollision = soa::Join::iterator; +using FemtoFullCollision_noCent = soa::Join::iterator; +using FemtoFullCollision_CentPbPb = soa::Join::iterator; using FemtoFullCollisionMC = soa::Join::iterator; using FemtoFullCollision_noCent_MC = soa::Join::iterator; +using FemtoFullCollisionMC_CentPbPb = soa::Join::iterator; using FemtoFullMCgenCollisions = soa::Join; using FemtoFullMCgenCollision = FemtoFullMCgenCollisions::iterator; using FemtoFullTracks = soa::Join; + aod::pidTPCFullEl, aod::pidTPCFullPi, aod::pidTPCFullKa, + aod::pidTPCFullPr, aod::pidTPCFullDe, aod::pidTPCFullTr, aod::pidTPCFullHe, + aod::pidTOFFullEl, aod::pidTOFFullPi, aod::pidTOFFullKa, + aod::pidTOFFullPr, aod::pidTOFFullDe, aod::pidTOFFullTr, aod::pidTOFFullHe>; } // namespace o2::aod +namespace softwareTriggers +{ +static const int nTriggers = 6; +static const std::vector triggerNames{"fPPP", "fPPL", "fPLL", "fLLL", "fPD", "fLD"}; +static const float triggerSwitches[1][nTriggers]{ + {0, 0, 0, 0, 0, 0}}; +} // namespace softwareTriggers + template int getRowDaughters(int daughID, T const& vecID) { @@ -72,6 +91,8 @@ int getRowDaughters(int daughID, T const& vecID) struct femtoDreamProducerTask { + Zorro zorro; + Produces outputCollision; Produces outputMCCollision; Produces outputCollsMCLabels; @@ -83,17 +104,27 @@ struct femtoDreamProducerTask { Produces outputPartsExtMCLabels; Configurable ConfIsDebug{"ConfIsDebug", true, "Enable Debug tables"}; + Configurable ConfUseItsPid{"ConfUseItsPid", false, "Enable Debug tables"}; Configurable ConfIsRun3{"ConfIsRun3", false, "Running on Run3 or pilot"}; Configurable ConfIsForceGRP{"ConfIsForceGRP", false, "Set true if the magnetic field configuration is not available in the usual CCDB directory (e.g. for Run 2 converted data or unanchorad Monte Carlo)"}; - /// Event cuts FemtoDreamCollisionSelection colCuts; + // Event cuts - Triggers + Configurable ConfEnableTriggerSelection{"ConfEnableTriggerSelection", false, "Should the trigger selection be enabled for collisions?"}; + Configurable> ConfTriggerSwitches{ + "ConfTriggerSwitches", + {softwareTriggers::triggerSwitches[0], 1, softwareTriggers::nTriggers, std::vector{"Switch"}, softwareTriggers::triggerNames}, + "Turn on which trigger should be checked for recorded events to pass selection"}; + Configurable ConfBaseCCDBPathForTriggers{"ConfBaseCCDBPathForTriggers", "Users/m/mpuccio/EventFiltering/OTS/Chunked/", "Provide ccdb path for trigger table; default - trigger coordination"}; + + // Event cuts - usual selection criteria Configurable ConfEvtZvtx{"ConfEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; Configurable ConfEvtTriggerCheck{"ConfEvtTriggerCheck", true, "Evt sel: check for trigger"}; Configurable ConfEvtTriggerSel{"ConfEvtTriggerSel", kINT7, "Evt sel: trigger"}; Configurable ConfEvtOfflineCheck{"ConfEvtOfflineCheck", false, "Evt sel: check for offline selection"}; Configurable ConfEvtAddOfflineCheck{"ConfEvtAddOfflineCheck", false, "Evt sel: additional checks for offline selection (not part of sel8 yet)"}; Configurable ConfIsActivateV0{"ConfIsActivateV0", true, "Activate filling of V0 into femtodream tables"}; + Configurable ConfIsActivateReso{"ConfIsActivateReso", false, "Activate filling of sl Resonances into femtodream tables"}; Configurable ConfTrkRejectNotPropagated{"ConfTrkRejectNotPropagated", false, "True: reject not propagated tracks"}; // Configurable ConfRejectITSHitandTOFMissing{ "ConfRejectITSHitandTOFMissing", false, "True: reject if neither ITS hit nor TOF timing satisfied"}; @@ -140,6 +171,23 @@ struct femtoDreamProducerTask { Configurable> ConfChildPIDnSigmaMax{"ConfChildPIDnSigmaMax", std::vector{5.f, 4.f}, "V0 Child sel: Max. PID nSigma TPC"}; Configurable> ConfChildPIDspecies{"ConfChildPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Proton}, "V0 Child sel: Particles species for PID"}; + // Resonances + Configurable ConfResoInvMassLowLimit{"ConfResoInvMassLowLimit", 1.011461, "Lower limit of the Reso invariant mass"}; + Configurable ConfResoInvMassUpLimit{"ConfResoInvMassUpLimit", 1.027461, "Upper limit of the Reso invariant mass"}; + Configurable> ConfDaughterCharge{"ConfDaughterCharge", std::vector{1, -1}, "Reso Daughter sel: Charge"}; + Configurable> ConfDaughterEta{"ConfDaughterEta", std::vector{0.8, 0.8}, "Reso Daughter sel: Eta"}; // 0.8 + Configurable> ConfDaughterDCAxy{"ConfDaughterDCAxy", std::vector{0.1, 0.1}, "Reso Daughter sel: DCAxy"}; // 0.1 + Configurable> ConfDaughterDCAz{"ConfDaughterDCAz", std::vector{0.2, 0.2}, "Reso Daughter sel: DCAz"}; // 0.2 + Configurable> ConfDaughterNClus{"ConfDaughterNClus", std::vector{80, 80}, "Reso Daughter sel: NClusters"}; // 0.2 + Configurable> ConfDaughterNCrossed{"ConfDaughterNCrossed", std::vector{70, 70}, "Reso Daughter sel: NCrossedRowss"}; + Configurable> ConfDaughterTPCfCls{"ConfDaughterTPCfCls", std::vector{0.8, 0.8}, "Reso Daughter sel: Minimum fraction of crossed rows over findable cluster"}; // 0.2 + Configurable> ConfDaughterPtUp{"ConfDaughterPtUp", std::vector{2.0, 2.0}, "Reso Daughter sel: Upper limit pT"}; // 2.0 + Configurable> ConfDaughterPtLow{"ConfDaughterPtLow", std::vector{0.15, 0.15}, "Reso Daughter sel: Lower limit pT"}; // 0.15 + Configurable> ConfDaughterPTPCThr{"ConfDaughterPTPCThr", std::vector{0.40, 0.40}, "Reso Daughter sel: momentum threshold TPC only PID, p_TPC,Thr"}; // 0.4 + Configurable> ConfDaughterPIDnSigmaMax{"ConfDaughterPIDnSigmaMax", std::vector{3.00, 3.00}, "Reso Daughter sel: Max. PID nSigma TPC"}; // 3.0 + Configurable> ConfDaughterPIDspecies{"ConfDaughterPIDspecies", std::vector{o2::track::PID::Kaon, o2::track::PID::Kaon}, "Reso Daughter sel: Particles species for PID"}; + Configurable> ConfDaug1Daugh2ResoMass{"ConfDaug1Daugh2ResoMass", std::vector{o2::constants::physics::MassKPlus, o2::constants::physics::MassKMinus, o2::constants::physics::MassPhi}, "Masses: Daughter1 - Daughter2 - Resonance"}; + /// \todo should we add filter on min value pT/eta of V0 and daughters? /*Filter v0Filter = (nabs(aod::v0data::x) < V0DecVtxMax.value) && (nabs(aod::v0data::y) < V0DecVtxMax.value) && @@ -147,20 +195,32 @@ struct femtoDreamProducerTask { // (aod::v0data::v0radius > V0TranRadV0Min.value); to be added, not working // for now do not know why + /// General options + struct : o2::framework::ConfigurableGroup { + Configurable ConfTrkMinChi2PerClusterTPC{"ConfTrkMinChi2PerClusterTPC", 0.f, "Lower limit for chi2 of TPC; currently for testing only"}; + Configurable ConfTrkMaxChi2PerClusterTPC{"ConfTrkMaxChi2PerClusterTPC", 1000.f, "Upper limit for chi2 of TPC; currently for testing only"}; + Configurable ConfTrkMaxChi2PerClusterITS{"ConfTrkMaxChi2PerClusterITS", 1000.0f, "Minimal track selection: max allowed chi2 per ITS cluster"}; // 36.0 is default + Configurable ConfTrkTPCRefit{"ConfTrkTPCRefit", false, "True: require TPC refit"}; + Configurable ConfTrkITSRefit{"ConfTrkITSRefit", false, "True: require ITS refit"}; + + } OptionTrackSpecialSelections; + HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry TrackRegistry{"Tracks", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry V0Registry{"V0", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry ResoRegistry{"Reso", {}, OutputObjHandlingPolicy::AnalysisObject}; int mRunNumber; float mMagField; + std::string zorroTriggerNames = ""; Service ccdb; /// Accessing the CCDB void init(InitContext&) { - if (doprocessData == false && doprocessMC == false && doprocessMC_noCentrality == false) { + if (doprocessData == false && doprocessData_noCentrality == false && doprocessData_CentPbPb == false && doprocessMC == false && doprocessMC_noCentrality == false && doprocessMC_CentPbPb == false) { LOGF(fatal, "Neither processData nor processMC enabled. Please choose one."); } - if ((doprocessData == true && doprocessMC == true) || (doprocessData == true && doprocessMC_noCentrality == true) || (doprocessMC == true && doprocessMC_noCentrality == true)) { + if ((doprocessData == true && doprocessMC == true) || (doprocessData == true && doprocessMC_noCentrality == true) || (doprocessMC == true && doprocessMC_noCentrality == true) || (doprocessData_noCentrality == true && doprocessData == true) || (doprocessData_noCentrality == true && doprocessMC == true) || (doprocessData_noCentrality == true && doprocessMC_noCentrality == true) || (doprocessData_CentPbPb == true && doprocessData == true) || (doprocessData_CentPbPb == true && doprocessData_noCentrality == true) || (doprocessData_CentPbPb == true && doprocessMC == true) || (doprocessData_CentPbPb == true && doprocessMC_noCentrality == true) || (doprocessData_CentPbPb == true && doprocessMC_CentPbPb == true)) { LOGF(fatal, "Cannot enable more than one process switch at the same time. " "Please choose one."); @@ -168,7 +228,32 @@ struct femtoDreamProducerTask { int CutBits = 8 * sizeof(o2::aod::femtodreamparticle::cutContainerType); TrackRegistry.add("AnalysisQA/CutCounter", "; Bit; Counter", kTH1F, {{CutBits + 1, -0.5, CutBits + 0.5}}); + TrackRegistry.add("AnalysisQA/Chi2ITSTPCperCluster", "; ITS_Chi2; TPC_Chi2", kTH2F, {{100, 0, 50}, {100, 0, 20}}); + TrackRegistry.add("AnalysisQA/RefitITSTPC", "; ITS_Refit; TPC_Refit", kTH2F, {{2, 0, 2}, {2, 0, 2}}); + TrackRegistry.add("AnalysisQA/getGenStatusCode", "; Bit; Entries", kTH1F, {{200, 0, 200}}); + TrackRegistry.add("AnalysisQA/getProcess", "; Bit; Entries", kTH1F, {{200, 0, 200}}); + TrackRegistry.add("AnalysisQA/Mother", "; Bit; Entries", kTH1F, {{4000, -4000, 4000}}); + TrackRegistry.add("AnalysisQA/Particle", "; Bit; Entries", kTH1F, {{4000, -4000, 4000}}); V0Registry.add("AnalysisQA/CutCounter", "; Bit; Counter", kTH1F, {{CutBits + 1, -0.5, CutBits + 0.5}}); + ResoRegistry.add("AnalysisQA/Reso/InvMass", "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {{7000, 0.8, 1.5}}); + ResoRegistry.add("AnalysisQA/Reso/InvMass_selected", "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {{7000, 0.8, 1.5}}); + ResoRegistry.add("AnalysisQA/Reso/Daughter1/Pt", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + ResoRegistry.add("AnalysisQA/Reso/Daughter1/Eta", "Pseudorapidity of all processed tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); + ResoRegistry.add("AnalysisQA/Reso/Daughter1/Phi", "Azimuthal angle of all processed tracks;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); + ResoRegistry.add("AnalysisQA/Reso/Daughter2/Pt", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + ResoRegistry.add("AnalysisQA/Reso/Daughter2/Eta", "Pseudorapidity of all processed tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); + ResoRegistry.add("AnalysisQA/Reso/Daughter2/Phi", "Azimuthal angle of all processed tracks;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); + ResoRegistry.add("AnalysisQA/Reso/PtD1_selected", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + ResoRegistry.add("AnalysisQA/Reso/PtD2_selected", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + + if (ConfEnableTriggerSelection) { + for (const std::string& triggerName : softwareTriggers::triggerNames) { + if (ConfTriggerSwitches->get("Switch", triggerName.c_str())) { + zorroTriggerNames += triggerName + ","; + } + } + zorroTriggerNames.pop_back(); + } colCuts.setCuts(ConfEvtZvtx.value, ConfEvtTriggerCheck.value, ConfEvtTriggerSel.value, ConfEvtOfflineCheck.value, ConfEvtAddOfflineCheck.value, ConfIsRun3.value); colCuts.init(&qaRegistry); @@ -209,6 +294,7 @@ struct femtoDreamProducerTask { v0Cuts.setChildCuts(femtoDreamV0Selection::kPosTrack, ConfChildTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); v0Cuts.setChildCuts(femtoDreamV0Selection::kPosTrack, ConfChildDCAMin, femtoDreamTrackSelection::kDCAMin, femtoDreamSelection::kAbsLowerLimit); v0Cuts.setChildCuts(femtoDreamV0Selection::kPosTrack, ConfChildPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + v0Cuts.setChildCuts(femtoDreamV0Selection::kNegTrack, ConfChildCharge, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); v0Cuts.setChildCuts(femtoDreamV0Selection::kNegTrack, ConfChildEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); v0Cuts.setChildCuts(femtoDreamV0Selection::kNegTrack, ConfChildTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); @@ -243,7 +329,7 @@ struct femtoDreamProducerTask { } /// Function to retrieve the nominal magnetic field in kG (0.1T) and convert it directly to T - void getMagneticFieldTesla(aod::BCsWithTimestamps::iterator bc) + void initCCDB_Mag_Trig(aod::BCsWithTimestamps::iterator bc) { // TODO done only once (and not per run). Will be replaced by CCDBConfigurable // get magnetic field for run @@ -277,44 +363,97 @@ struct femtoDreamProducerTask { } mMagField = output; mRunNumber = bc.runNumber(); + + // Init for zorro to get trigger flags + if (ConfEnableTriggerSelection) { + zorro.setCCDBpath(ConfBaseCCDBPathForTriggers); + zorro.initCCDB(ccdb.service, mRunNumber, timestamp, zorroTriggerNames); + } } - template + template void fillDebugParticle(ParticleType const& particle) { if constexpr (isTrackOrV0) { - outputDebugParts(particle.sign(), - (uint8_t)particle.tpcNClsFound(), - particle.tpcNClsFindable(), - (uint8_t)particle.tpcNClsCrossedRows(), - particle.tpcNClsShared(), - particle.tpcInnerParam(), - particle.itsNCls(), - particle.itsNClsInnerBarrel(), - particle.dcaXY(), - particle.dcaZ(), - particle.tpcSignal(), - particle.tpcNSigmaEl(), - particle.tpcNSigmaPi(), - particle.tpcNSigmaKa(), - particle.tpcNSigmaPr(), - particle.tpcNSigmaDe(), - particle.tofNSigmaEl(), - particle.tofNSigmaPi(), - particle.tofNSigmaKa(), - particle.tofNSigmaPr(), - particle.tofNSigmaDe(), - -999., -999., -999., -999., -999., -999.); + if constexpr (hasItsPid) { + outputDebugParts(particle.sign(), + (uint8_t)particle.tpcNClsFound(), + particle.tpcNClsFindable(), + (uint8_t)particle.tpcNClsCrossedRows(), + particle.tpcNClsShared(), + particle.tpcInnerParam(), + particle.itsNCls(), + particle.itsNClsInnerBarrel(), + particle.dcaXY(), + particle.dcaZ(), + particle.tpcSignal(), + particle.tpcNSigmaEl(), + particle.tpcNSigmaPi(), + particle.tpcNSigmaKa(), + particle.tpcNSigmaPr(), + particle.tpcNSigmaDe(), + particle.tpcNSigmaTr(), + particle.tpcNSigmaHe(), + particle.tofNSigmaEl(), + particle.tofNSigmaPi(), + particle.tofNSigmaKa(), + particle.tofNSigmaPr(), + particle.tofNSigmaDe(), + particle.tofNSigmaTr(), + particle.tofNSigmaHe(), + o2::analysis::femtoDream::itsSignal(particle), + particle.itsNSigmaEl(), + particle.itsNSigmaPi(), + particle.itsNSigmaKa(), + particle.itsNSigmaPr(), + particle.itsNSigmaDe(), + particle.itsNSigmaTr(), + particle.itsNSigmaHe(), + -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., -999., -999.); + } else { + outputDebugParts(particle.sign(), + (uint8_t)particle.tpcNClsFound(), + particle.tpcNClsFindable(), + (uint8_t)particle.tpcNClsCrossedRows(), + particle.tpcNClsShared(), + particle.tpcInnerParam(), + particle.itsNCls(), + particle.itsNClsInnerBarrel(), + particle.dcaXY(), + particle.dcaZ(), + particle.tpcSignal(), + particle.tpcNSigmaEl(), + particle.tpcNSigmaPi(), + particle.tpcNSigmaKa(), + particle.tpcNSigmaPr(), + particle.tpcNSigmaDe(), + particle.tpcNSigmaTr(), + particle.tpcNSigmaHe(), + particle.tofNSigmaEl(), + particle.tofNSigmaPi(), + particle.tofNSigmaKa(), + particle.tofNSigmaPr(), + particle.tofNSigmaDe(), + particle.tofNSigmaTr(), + particle.tofNSigmaHe(), + -999., -999., -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., -999., -999.); + } } else { - outputDebugParts(-999., -999., -999., -999., -999., -999., -999., -999., - -999., -999., -999., -999., -999., -999., -999., -999., - -999., -999., -999., -999., -999., + outputDebugParts(-999., // sign + -999., -999., -999., -999., -999., -999., -999., -999., -999., // track properties (DCA, NCls, crossed rows, etc.) + -999., -999., -999., -999., -999., -999., -999., -999., // TPC PID (TPC signal + particle hypothesis) + -999., -999., -999., -999., -999., -999., -999., // TOF PID + -999., -999., -999., -999., -999., -999., -999., -999., // ITS PID particle.dcaV0daughters(), particle.v0radius(), particle.x(), particle.y(), particle.z(), - particle.mK0Short()); + particle.mK0Short(), + -999., -999., -999., -999., -999., -999., -999.); // Cascade properties } } @@ -325,21 +464,43 @@ struct femtoDreamProducerTask { // get corresponding MC particle and its info auto particleMC = particle.mcParticle(); auto pdgCode = particleMC.pdgCode(); + TrackRegistry.fill(HIST("AnalysisQA/Particle"), pdgCode); int particleOrigin = 99; - auto motherparticleMC = particleMC.template mothers_as().front(); - + int pdgCodeMother = -1; + // get list of mothers, but it could be empty (for example in case of injected light nuclei) + auto motherparticlesMC = particleMC.template mothers_as(); + // check pdg code + TrackRegistry.fill(HIST("AnalysisQA/getGenStatusCode"), particleMC.getGenStatusCode()); + TrackRegistry.fill(HIST("AnalysisQA/getProcess"), particleMC.getProcess()); + // if this fails, the particle is a fake if (abs(pdgCode) == abs(ConfTrkPDGCode.value)) { + // check first if particle is from pile up + // check if the collision associated with the particle is the same as the analyzed collision by checking their Ids if ((col.has_mcCollision() && (particleMC.mcCollisionId() != col.mcCollisionId())) || !col.has_mcCollision()) { particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kWrongCollision; + // check if particle is primary } else if (particleMC.isPhysicalPrimary()) { particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kPrimary; - } else if (motherparticleMC.isPhysicalPrimary() && particleMC.getProcess() == 4) { + // check if particle is secondary + // particle is from a decay -> getProcess() == 4 + // particle is generated during transport -> getGenStatusCode() == -1 + // list of mothers is not empty + } else if (particleMC.getProcess() == 4 && particleMC.getGenStatusCode() == -1 && !motherparticlesMC.empty()) { + // get direct mother + auto motherparticleMC = motherparticlesMC.front(); + pdgCodeMother = motherparticleMC.pdgCode(); + TrackRegistry.fill(HIST("AnalysisQA/Mother"), pdgCodeMother); particleOrigin = checkDaughterType(fdparttype, motherparticleMC.pdgCode()); - } else if (particleMC.getGenStatusCode() == -1) { + // check if particle is material + // particle is from inelastic hadronic interaction -> getProcess() == 23 + // particle is generated during transport -> getGenStatusCode() == -1 + } else if (particleMC.getProcess() == 23 && particleMC.getGenStatusCode() == -1) { particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kMaterial; + // cross check to see if we missed a case } else { particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kElse; } + // if pdg code is wrong, particle is fake } else { particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kFake; } @@ -348,7 +509,7 @@ struct femtoDreamProducerTask { outputPartsMCLabels(outputPartsMC.lastIndex()); if (ConfIsDebug) { outputPartsExtMCLabels(outputPartsMC.lastIndex()); - outputDebugPartsMC(motherparticleMC.pdgCode()); + outputDebugPartsMC(pdgCodeMother); } } else { outputPartsMCLabels(-1); @@ -369,16 +530,28 @@ struct femtoDreamProducerTask { outputCollsMCLabels(-1); } } - template - void fillCollisionsAndTracksAndV0(CollisionType const& col, TrackType const& tracks, V0Type const& fullV0s) + template + void fillCollisionsAndTracksAndV0(CollisionType const& col, TrackType const& tracks, TrackTypeWithItsPid const& tracksWithItsPid, V0Type const& fullV0s) { + // If triggering is enabled, select only events which were triggered wit our triggers + if (ConfEnableTriggerSelection) { + bool zorroSelected = zorro.isSelected(col.template bc_as().globalBC()); /// check if event was selected by triggers of interest + if (!zorroSelected) { + return; + } + } + const auto vtxZ = col.posZ(); const auto spher = colCuts.computeSphericity(col, tracks); float mult = 0; int multNtr = 0; if (ConfIsRun3) { if constexpr (useCentrality) { - mult = col.centFT0M(); + if constexpr (analysePbPb) { + mult = col.centFT0C(); + } else { + mult = col.centFT0M(); + } } else { mult = 0; } @@ -412,16 +585,34 @@ struct femtoDreamProducerTask { std::vector childIDs = {0, 0}; // these IDs are necessary to keep track of the children std::vector tmpIDtrack; // this vector keeps track of the matching of the primary track table row <-> aod::track table global index + std::vector Daughter1, Daughter2; - for (auto& track : tracks) { + for (auto& track : tracksWithItsPid) { /// if the most open selection criteria are not fulfilled there is no /// point looking further at the track + trackCuts.fillQA(track); + + if (track.tpcChi2NCl() < OptionTrackSpecialSelections.ConfTrkMinChi2PerClusterTPC || track.tpcChi2NCl() > OptionTrackSpecialSelections.ConfTrkMaxChi2PerClusterTPC) { + continue; + } + if (track.itsChi2NCl() > OptionTrackSpecialSelections.ConfTrkMaxChi2PerClusterITS) { + continue; + } + if ((OptionTrackSpecialSelections.ConfTrkTPCRefit && !track.hasTPC()) || (OptionTrackSpecialSelections.ConfTrkITSRefit && !track.hasITS())) { + continue; + } + if (!trackCuts.isSelectedMinimal(track)) { continue; } - trackCuts.fillQA(track); + + TrackRegistry.fill(HIST("AnalysisQA/Chi2ITSTPCperCluster"), track.itsChi2NCl(), track.tpcChi2NCl()); + TrackRegistry.fill(HIST("AnalysisQA/RefitITSTPC"), track.hasITS(), track.hasTPC()); + + trackCuts.fillQA(track); // the bit-wise container of the systematic variations is obtained - auto cutContainer = trackCuts.getCutContainer(track, track.pt(), track.eta(), sqrtf(powf(track.dcaXY(), 2.f) + powf(track.dcaZ(), 2.f))); + std::array cutContainer; + cutContainer = trackCuts.getCutContainer(track, track.pt(), track.eta(), sqrtf(powf(track.dcaXY(), 2.f) + powf(track.dcaZ(), 2.f))); // now the table is filled outputParts(outputCollision.lastIndex(), @@ -434,16 +625,43 @@ struct femtoDreamProducerTask { track.dcaXY(), childIDs, 0, 0); tmpIDtrack.push_back(track.globalIndex()); if (ConfIsDebug.value) { - fillDebugParticle(track); + fillDebugParticle(track); } if constexpr (isMC) { fillMCParticle(col, track, o2::aod::femtodreamparticle::ParticleType::kTrack); } + + if (ConfIsActivateReso.value) { + // Already strict cuts for Daughter of reso selection + // TO DO: change TTV0 task to apply there the strict selection and have here only loose selection + + // select daugher 1 + if (track.sign() == ConfDaughterCharge.value[0] && track.pt() <= ConfDaughterPtUp.value[0] && track.pt() >= ConfDaughterPtLow.value[0] && std::abs(track.eta()) <= ConfDaughterEta.value[0] && std::abs(track.dcaXY()) <= ConfDaughterDCAxy.value[0] && std::abs(track.dcaZ()) <= ConfDaughterDCAz.value[0] && track.tpcNClsCrossedRows() >= ConfDaughterNCrossed.value[0] && track.tpcNClsFound() >= ConfDaughterNClus.value[0] && track.tpcCrossedRowsOverFindableCls() >= ConfDaughterTPCfCls.value[0]) { + if ((track.tpcInnerParam() < ConfDaughterPTPCThr.value[0] && std::abs(o2::aod::pidutils::tpcNSigma(ConfDaughterPIDspecies.value[0], track)) <= ConfDaughterPIDnSigmaMax.value[0]) || + (track.tpcInnerParam() >= ConfDaughterPTPCThr.value[0] && std::abs(std::sqrt(o2::aod::pidutils::tpcNSigma(ConfDaughterPIDspecies.value[0], track) * o2::aod::pidutils::tpcNSigma(ConfDaughterPIDspecies.value[0], track) + o2::aod::pidutils::tofNSigma(ConfDaughterPIDspecies.value[0], track) * o2::aod::pidutils::tofNSigma(ConfDaughterPIDspecies.value[0], track))) <= ConfDaughterPIDnSigmaMax.value[0])) { + Daughter1.push_back(track); + ResoRegistry.fill(HIST("AnalysisQA/Reso/Daughter1/Pt"), track.pt()); + ResoRegistry.fill(HIST("AnalysisQA/Reso/Daughter1/Eta"), track.eta()); + ResoRegistry.fill(HIST("AnalysisQA/Reso/Daughter1/Phi"), track.phi()); + } + } + // select daugher 2 + if (track.sign() == ConfDaughterCharge.value[1] && track.pt() <= ConfDaughterPtUp.value[1] && track.pt() >= ConfDaughterPtLow.value[1] && std::abs(track.eta()) <= ConfDaughterEta.value[1] && std::abs(track.dcaXY()) <= ConfDaughterDCAxy.value[1] && std::abs(track.dcaZ()) <= ConfDaughterDCAz.value[1] && track.tpcNClsCrossedRows() >= ConfDaughterNCrossed.value[1] && track.tpcNClsFound() >= ConfDaughterNClus.value[1] && track.tpcCrossedRowsOverFindableCls() >= ConfDaughterTPCfCls.value[1]) { + if ((track.tpcInnerParam() < ConfDaughterPTPCThr.value[1] && std::abs(o2::aod::pidutils::tpcNSigma(ConfDaughterPIDspecies.value[1], track)) <= ConfDaughterPIDnSigmaMax.value[1]) || + (track.tpcInnerParam() >= ConfDaughterPTPCThr.value[1] && std::abs(std::sqrt(o2::aod::pidutils::tpcNSigma(ConfDaughterPIDspecies.value[1], track) * o2::aod::pidutils::tpcNSigma(ConfDaughterPIDspecies.value[1], track) + o2::aod::pidutils::tofNSigma(ConfDaughterPIDspecies.value[1], track) * o2::aod::pidutils::tofNSigma(ConfDaughterPIDspecies.value[1], track))) <= ConfDaughterPIDnSigmaMax.value[1])) { + Daughter2.push_back(track); + ResoRegistry.fill(HIST("AnalysisQA/Reso/Daughter2/Pt"), track.pt()); + ResoRegistry.fill(HIST("AnalysisQA/Reso/Daughter2/Eta"), track.eta()); + ResoRegistry.fill(HIST("AnalysisQA/Reso/Daughter2/Phi"), track.phi()); + } + } + } } if (ConfIsActivateV0.value) { for (auto& v0 : fullV0s) { + auto postrack = v0.template posTrack_as(); auto negtrack = v0.template negTrack_as(); ///\tocheck funnily enough if we apply the filter the @@ -518,16 +736,83 @@ struct femtoDreamProducerTask { indexChildID, v0.mLambda(), v0.mAntiLambda()); - if (ConfIsDebug) { - fillDebugParticle(postrack); // QA for positive daughter - fillDebugParticle(negtrack); // QA for negative daughter - fillDebugParticle(v0); // QA for v0 + if (ConfIsDebug.value) { + fillDebugParticle(postrack); // QA for positive daughter + fillDebugParticle(negtrack); // QA for negative daughter + fillDebugParticle(v0); // QA for v0 } if constexpr (isMC) { fillMCParticle(col, v0, o2::aod::femtodreamparticle::ParticleType::kV0); } } } + + if (ConfIsActivateReso.value) { + for (std::size_t iDaug1 = 0; iDaug1 < Daughter1.size(); ++iDaug1) { + for (std::size_t iDaug2 = 0; iDaug2 < Daughter2.size(); ++iDaug2) { + // MC stuff is still missing, also V0 QA + // ALSO: fix indices and other table entries which are now set to 0 as deflaut as not needed for p-p-phi cf ana + + ROOT::Math::PtEtaPhiMVector tempD1(Daughter1.at(iDaug1).pt(), Daughter1.at(iDaug1).eta(), Daughter1.at(iDaug1).phi(), ConfDaug1Daugh2ResoMass.value[0]); + ROOT::Math::PtEtaPhiMVector tempD2(Daughter2.at(iDaug2).pt(), Daughter2.at(iDaug2).eta(), Daughter2.at(iDaug2).phi(), ConfDaug1Daugh2ResoMass.value[1]); + + ROOT::Math::PtEtaPhiMVector tempPhi = tempD1 + tempD2; + + ResoRegistry.fill(HIST("AnalysisQA/Reso/InvMass"), tempPhi.M()); + + if ((tempPhi.M() >= ConfResoInvMassLowLimit.value) && (tempPhi.M() <= ConfResoInvMassUpLimit.value)) { + + ResoRegistry.fill(HIST("AnalysisQA/Reso/InvMass_selected"), tempPhi.M()); + ResoRegistry.fill(HIST("AnalysisQA/Reso/PtD1_selected"), Daughter1.at(iDaug1).pt()); + ResoRegistry.fill(HIST("AnalysisQA/Reso/PtD2_selected"), Daughter2.at(iDaug2).pt()); + + childIDs[0] = 0; + childIDs[1] = 0; + std::vector indexChildID = {0, 0}; + outputParts(outputCollision.lastIndex(), + static_cast(Daughter1.at(iDaug1).pt()), static_cast(Daughter1.at(iDaug1).eta()), static_cast(Daughter1.at(iDaug1).phi()), + aod::femtodreamparticle::ParticleType::kV0Child, + static_cast(0), + static_cast(0), + static_cast(Daughter1.at(iDaug1).dcaXY()), + childIDs, + 0, + 0); + outputParts(outputCollision.lastIndex(), + static_cast(Daughter2.at(iDaug2).pt()), static_cast(Daughter2.at(iDaug2).eta()), static_cast(Daughter2.at(iDaug2).phi()), + aod::femtodreamparticle::ParticleType::kV0Child, + static_cast(0), + static_cast(0), + static_cast(Daughter2.at(iDaug2).dcaXY()), + childIDs, + 0, + 0); + outputParts(outputCollision.lastIndex(), + static_cast(tempPhi.pt()), + static_cast(tempPhi.eta()), + static_cast(tempPhi.phi()), + aod::femtodreamparticle::ParticleType::kV0, + static_cast(0), + 0, + 0.f, + indexChildID, + tempPhi.M(), + tempPhi.M()); + if (ConfIsDebug.value) { + fillDebugParticle(Daughter1.at(iDaug1)); // QA for positive daughter + fillDebugParticle(Daughter2.at(iDaug2)); // QA for negative daughter + outputDebugParts(-999., // sign + -999., -999., -999., -999., -999., -999., -999., -999., -999., // track properties (DCA, NCls, crossed rows, etc.) + -999., -999., -999., -999., -999., -999., -999., -999., // TPC PID (TPC signal + particle hypothesis) + -999., -999., -999., -999., -999., -999., -999., // TOF PID + -999., -999., -999., -999., -999., -999., -999., -999., // ITS PID + -999., -999., -999., -999., -999., -999., // V0 properties + -999., -999., -999., -999., -999., -999., -999.); // Cascade properties + } + } + } + } + } } void @@ -537,13 +822,58 @@ struct femtoDreamProducerTask { o2::aod::V0Datas const& fullV0s) { // get magnetic field for run - getMagneticFieldTesla(col.bc_as()); + initCCDB_Mag_Trig(col.bc_as()); // fill the tables - fillCollisionsAndTracksAndV0(col, tracks, fullV0s); + auto tracksWithItsPid = soa::Attach(tracks); + if (ConfUseItsPid.value) { + fillCollisionsAndTracksAndV0(col, tracks, tracksWithItsPid, fullV0s); + } else { + fillCollisionsAndTracksAndV0(col, tracks, tracks, fullV0s); + } } PROCESS_SWITCH(femtoDreamProducerTask, processData, "Provide experimental data", true); + void + processData_noCentrality(aod::FemtoFullCollision_noCent const& col, + aod::BCsWithTimestamps const&, + aod::FemtoFullTracks const& tracks, + o2::aod::V0Datas const& fullV0s) + { + // get magnetic field for run + initCCDB_Mag_Trig(col.bc_as()); + // fill the tables + auto tracksWithItsPid = soa::Attach(tracks); + if (ConfUseItsPid.value) { + fillCollisionsAndTracksAndV0(col, tracks, tracksWithItsPid, fullV0s); + } else { + fillCollisionsAndTracksAndV0(col, tracks, tracks, fullV0s); + } + } + PROCESS_SWITCH(femtoDreamProducerTask, processData_noCentrality, + "Provide experimental data without centrality information", false); + + void processData_CentPbPb(aod::FemtoFullCollision_CentPbPb const& col, + aod::BCsWithTimestamps const&, + aod::FemtoFullTracks const& tracks, + o2::aod::V0Datas const& fullV0s) + { + // get magnetic field for run + initCCDB_Mag_Trig(col.bc_as()); + // fill the tables + auto tracksWithItsPid = soa::Attach(tracks); + if (ConfUseItsPid.value) { + fillCollisionsAndTracksAndV0(col, tracks, tracksWithItsPid, fullV0s); + } else { + fillCollisionsAndTracksAndV0(col, tracks, tracks, fullV0s); + } + } + PROCESS_SWITCH(femtoDreamProducerTask, processData_CentPbPb, + "Provide experimental data with centrality information for PbPb collisions", false); + void processMC(aod::FemtoFullCollisionMC const& col, aod::BCsWithTimestamps const&, soa::Join const& tracks, @@ -552,9 +882,9 @@ struct femtoDreamProducerTask { soa::Join const& fullV0s) /// \todo with FilteredFullV0s { // get magnetic field for run - getMagneticFieldTesla(col.bc_as()); + initCCDB_Mag_Trig(col.bc_as()); // fill the tables - fillCollisionsAndTracksAndV0(col, tracks, fullV0s); + fillCollisionsAndTracksAndV0(col, tracks, tracks, fullV0s); } PROCESS_SWITCH(femtoDreamProducerTask, processMC, "Provide MC data", false); @@ -566,13 +896,26 @@ struct femtoDreamProducerTask { soa::Join const& fullV0s) /// \todo with FilteredFullV0s { // get magnetic field for run - getMagneticFieldTesla(col.bc_as()); + initCCDB_Mag_Trig(col.bc_as()); // fill the tables - fillCollisionsAndTracksAndV0(col, tracks, fullV0s); + fillCollisionsAndTracksAndV0(col, tracks, tracks, fullV0s); } PROCESS_SWITCH(femtoDreamProducerTask, processMC_noCentrality, "Provide MC data without requiring a centrality calibration", false); -}; + void processMC_CentPbPb(aod::FemtoFullCollisionMC_CentPbPb const& col, + aod::BCsWithTimestamps const&, + soa::Join const& tracks, + aod::FemtoFullMCgenCollisions const&, + aod::McParticles const&, + soa::Join const& fullV0s) /// \todo with FilteredFullV0s + { + // get magnetic field for run + initCCDB_Mag_Trig(col.bc_as()); + // fill the tables + fillCollisionsAndTracksAndV0(col, tracks, tracks, fullV0s); + } + PROCESS_SWITCH(femtoDreamProducerTask, processMC_CentPbPb, "Provide MC data with centrality information for PbPb collisions", false); +}; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; diff --git a/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTaskForSpecificAnalysis.cxx b/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTaskForSpecificAnalysis.cxx new file mode 100644 index 00000000000..10e4c5c5254 --- /dev/null +++ b/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTaskForSpecificAnalysis.cxx @@ -0,0 +1,351 @@ +// Copyright 2019-2022 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 femtoDreamProducerTaskForSpecificAnalysis.cxx +/// \brief Tasks that reads the track tables and creates track triplets; only three identical particles can be used +/// \author Laura Serksnyte, TU München, laura.serksnyte@tum.de + +#include +#include +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "TDatabasePDG.h" + +#include "PWGCF/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamEventHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h" +#include "PWGCF/FemtoDream/Core/femtoDreamContainerThreeBody.h" +#include "PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h" +#include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" + +using namespace o2; +using namespace o2::analysis::femtoDream; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct femtoDreamProducerTaskForSpecificAnalysis { + + SliceCache cache; + + Produces outputCollision; + Produces outputParts; + + Preslice perCol = aod::femtodreamparticle::fdCollisionId; + float mMassOne = -999, mMassTwo = -999, mMassThree = -999; + int collisions = 0; + + Configurable ConfNumberOfTracks{"ConfNumberOfTracks", 3, "Number of tracks"}; + Configurable ConfNumberOfV0{"ConfNumberOfV0", 0, "Number of V0"}; + Configurable ConfNumberOfCascades{"ConfNumberOfCascades", 0, "Number of Cascades"}; + + /// Track selection + Configurable ConfPIDthrMom{"ConfPIDthrMom", 1.f, "Momentum threshold from which TPC and TOF are required for PID"}; + Configurable ConfTPCPIDBit{"ConfTPCPIDBit", 16, "PID TPC bit from cutCulator "}; + Configurable ConfTPCTOFPIDBit{"ConfTPCTOFPIDBit", 8, "PID TPCTOF bit from cutCulator"}; + + /// Partition for selected particles + Partition SelectedParts = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && + ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= ConfPIDthrMom, ncheckbit(aod::femtodreamparticle::pidcut, ConfTPCPIDBit), ncheckbit(aod::femtodreamparticle::pidcut, ConfTPCTOFPIDBit)); + + /// V0 selection + Configurable Conf_minInvMass_V0{"Conf_minInvMass_V0", 1.08, "Minimum invariant mass of V0 (particle)"}; + Configurable Conf_maxInvMass_V0{"Conf_maxInvMass_V0", 1.15, "Maximum invariant mass of V0 (particle)"}; + Configurable Conf_minInvMassAnti_V0{"Conf_minInvMassAnti_V0", 1.08, "Minimum invariant mass of V0 (antiparticle)"}; + Configurable Conf_maxInvMassAnti_V0{"Conf_maxInvMassAnti_V0", 1.15, "Maximum invariant mass of V0 (antiparticle)"}; + /// Cascade selection + Configurable Conf_minInvMass_Cascade{"Conf_minInvMass_Cascade", 1.2, "Minimum invariant mass of Cascade (particle)"}; + Configurable Conf_maxInvMass_Cascade{"Conf_maxInvMass_Cascade", 1.5, "Maximum invariant mass of Cascade (particle)"}; + + // Partition for selected particles + Partition SelectedV0s = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0)); + Partition SelectedCascades = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kCascade)); + + HistogramRegistry EventRegistry{"EventRegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + static constexpr uint32_t kSignPlusMask = 1 << 1; + + template + int getRowDaughters(int daughID, T const& vecID) + { + int rowInPrimaryTrackTableDaugh = -1; + for (size_t i = 0; i < vecID.size(); i++) { + if (vecID.at(i) == daughID) { + rowInPrimaryTrackTableDaugh = i; + break; + } + } + return rowInPrimaryTrackTableDaugh; + } + + void init(InitContext&) + { + EventRegistry.add("hStatistiscs", ";bin;Entries", kTH1F, {{3, 0, 3}}); + // get bit for the collision mask + } + /// This function stores accepted collisions in derived data + /// @tparam PartitionType + /// @tparam PartType + /// @tparam isMC: enables Monte Carlo truth specific histograms + /// @param groupSelectedTracks partition for the first particle passed by the process function + /// @param groupSelectedV0s partition for the second particle passed by the process function + /// @param parts femtoDreamParticles table + template + void createSpecifiedDerivedData(o2::aod::FDCollision& col, PartitionType groupSelectedTracks, PartitionType groupSelectedV0s, PartType parts) + { + /// check tracks + int tracksCount = 0; + int antitracksCount = 0; + for (auto& part : groupSelectedTracks) { + if (part.cut() & 1) { + antitracksCount++; + } else { + tracksCount++; + } + } + + /// check V0s + int V0Count = 0; + int antiV0Count = 0; + for (auto& V0 : groupSelectedV0s) { + if ((V0.mLambda() > Conf_minInvMass_V0) && (V0.mLambda() < Conf_maxInvMass_V0)) { + V0Count++; + } else if ((V0.mAntiLambda() > Conf_minInvMassAnti_V0) && (V0.mAntiLambda() < Conf_maxInvMassAnti_V0)) { + antiV0Count++; + } + } + + std::vector tmpIDtrack; + + if ((V0Count >= ConfNumberOfV0 && tracksCount >= ConfNumberOfTracks) || (antiV0Count >= ConfNumberOfV0 && antitracksCount >= ConfNumberOfTracks)) { + EventRegistry.fill(HIST("hStatistiscs"), 1); + outputCollision(col.posZ(), col.multV0M(), col.multNtr(), col.sphericity(), col.magField()); + for (auto& femtoParticle : parts) { + if (aod::femtodreamparticle::ParticleType::kTrack == femtoParticle.partType()) { + std::vector childIDs = {0, 0}; + outputParts(outputCollision.lastIndex(), + femtoParticle.pt(), + femtoParticle.eta(), + femtoParticle.phi(), + femtoParticle.partType(), + femtoParticle.cut(), + femtoParticle.pidcut(), + femtoParticle.tempFitVar(), + childIDs, + femtoParticle.mLambda(), + femtoParticle.mAntiLambda()); + tmpIDtrack.push_back(femtoParticle.index()); + } + if (aod::femtodreamparticle::ParticleType::kV0Child == femtoParticle.partType()) { + std::vector childIDs = {0, 0}; + const auto& children = femtoParticle.childrenIds(); + int childId = (children[0] != 0) ? children[0] : children[1]; + if (childId != -1) { + int rowInPrimaryTrackTable = getRowDaughters(childId, tmpIDtrack); + childIDs = (children[0] != 0) ? std::vector{rowInPrimaryTrackTable, 0} : std::vector{0, rowInPrimaryTrackTable}; + } else { + childIDs = (children[0] != 0) ? std::vector{-1, 0} : std::vector{0, -1}; + } + outputParts(outputCollision.lastIndex(), + femtoParticle.pt(), + femtoParticle.eta(), + femtoParticle.phi(), + femtoParticle.partType(), + femtoParticle.cut(), + femtoParticle.pidcut(), + femtoParticle.tempFitVar(), + childIDs, + femtoParticle.mLambda(), + femtoParticle.mAntiLambda()); + } + if (aod::femtodreamparticle::ParticleType::kV0 == femtoParticle.partType()) { + // If the order in primary producer is changed of storing first pos, neg daughters and then V0 - this must be updated + const int rowOfLastTrack = outputParts.lastIndex(); + std::vector childIDs = {rowOfLastTrack - 1, rowOfLastTrack}; + outputParts(outputCollision.lastIndex(), + femtoParticle.pt(), + femtoParticle.eta(), + femtoParticle.phi(), + femtoParticle.partType(), + femtoParticle.cut(), + femtoParticle.pidcut(), + femtoParticle.tempFitVar(), + childIDs, + femtoParticle.mLambda(), + femtoParticle.mAntiLambda()); + } + } + } else { + EventRegistry.fill(HIST("hStatistiscs"), 2); + } + } + + /// process function to create derived data with only collisions containing n tracks + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoDreamParticleTable + void processCollisionsWithNTracksAndNV0(o2::aod::FDCollision& col, + o2::aod::FDParticles& parts) + { + EventRegistry.fill(HIST("hStatistiscs"), 0); + auto thegroupSelectedParts = SelectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + auto thegroupSelectedV0s = SelectedV0s->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + + createSpecifiedDerivedData(col, thegroupSelectedParts, thegroupSelectedV0s, parts); + } + PROCESS_SWITCH(femtoDreamProducerTaskForSpecificAnalysis, processCollisionsWithNTracksAndNV0, "Enable producing data with ppp collisions for data", true); + + /// This function stores accepted collisions in derived data + /// @tparam PartitionType + /// @tparam PartType + /// @tparam isMC: enables Monte Carlo truth specific histograms + /// @param groupSelectedTracks partition for the first particle passed by the process function + /// @param groupSelectedV0s partition for the second particle passed by the process function + /// @param parts femtoDreamParticles table + template + void createSpecifiedDerivedData_TrkCascade(o2::aod::FDCollision& col, PartitionType groupSelectedTracks, PartitionType groupSelectedCascades, PartType parts) + { + + /// check tracks + int tracksCount = 0; + int antitracksCount = 0; + for (auto& part : groupSelectedTracks) { + if (part.cut() & 1) { + antitracksCount++; + } else { + tracksCount++; + } + } + + /// check Cascades + int CascadeCount = 0; + int antiCascadeCount = 0; + for (auto& casc : groupSelectedCascades) { + if ((casc.cut() & kSignPlusMask) == kSignPlusMask) { + CascadeCount++; + } else { + antiCascadeCount++; + } + } + + std::vector tmpIDtrack; + + if ((CascadeCount >= ConfNumberOfCascades && tracksCount >= ConfNumberOfTracks) || (antiCascadeCount >= ConfNumberOfCascades && antitracksCount >= ConfNumberOfTracks)) { + EventRegistry.fill(HIST("hStatistiscs"), 1); + outputCollision(col.posZ(), col.multV0M(), col.multNtr(), col.sphericity(), col.magField()); + + for (auto& femtoParticle : parts) { + if (aod::femtodreamparticle::ParticleType::kTrack == femtoParticle.partType()) { + std::vector childIDs = {0, 0}; + outputParts(outputCollision.lastIndex(), + femtoParticle.pt(), + femtoParticle.eta(), + femtoParticle.phi(), + femtoParticle.partType(), + femtoParticle.cut(), + femtoParticle.pidcut(), + femtoParticle.tempFitVar(), + childIDs, + femtoParticle.mLambda(), + femtoParticle.mAntiLambda()); + tmpIDtrack.push_back(femtoParticle.index()); + } + if (aod::femtodreamparticle::ParticleType::kCascadeV0Child == femtoParticle.partType() || aod::femtodreamparticle::ParticleType::kCascadeBachelor == femtoParticle.partType()) { + std::vector childIDs = {0, 0, 0}; + const auto& children = femtoParticle.childrenIds(); + int childId = 0; + if (children[0] != 0) { + childId = children[0]; + } else if (children[1] != 0) { + childId = children[1]; + } else if (children[2] != 0) { + childId = children[2]; + } + + if (childId != -1) { + int rowInPrimaryTrackTable = getRowDaughters(childId, tmpIDtrack); + if (children[0] != 0) { + childIDs = std::vector{rowInPrimaryTrackTable, 0, 0}; + } else if (children[1] != 0) { + childIDs = std::vector{0, rowInPrimaryTrackTable, 0}; + } else if (children[2] != 0) { + childIDs = std::vector{0, 0, rowInPrimaryTrackTable}; + } + } else { + if (children[0] != 0) { + childIDs = std::vector{-1, 0, 0}; + } else if (children[1] != 0) { + childIDs = std::vector{0, -1, 0}; + } else if (children[2] != 0) { + childIDs = std::vector{0, 0, -1}; + } + } + outputParts(outputCollision.lastIndex(), + femtoParticle.pt(), + femtoParticle.eta(), + femtoParticle.phi(), + femtoParticle.partType(), + femtoParticle.cut(), + femtoParticle.pidcut(), + femtoParticle.tempFitVar(), + childIDs, + femtoParticle.mLambda(), + femtoParticle.mAntiLambda()); + } + if (aod::femtodreamparticle::ParticleType::kCascade == femtoParticle.partType()) { + // If the order in primary producer is changed of storing first pos, neg daughters and then V0 - this must be updated + const int rowOfLastTrack = outputParts.lastIndex(); + std::vector childIDs = {rowOfLastTrack - 2, rowOfLastTrack - 1, rowOfLastTrack}; + outputParts(outputCollision.lastIndex(), + femtoParticle.pt(), + femtoParticle.eta(), + femtoParticle.phi(), + femtoParticle.partType(), + femtoParticle.cut(), + femtoParticle.pidcut(), + femtoParticle.tempFitVar(), + childIDs, + femtoParticle.mLambda(), + femtoParticle.mAntiLambda()); + } + } + } else { + EventRegistry.fill(HIST("hStatistiscs"), 2); + } + } + + /// process function to create derived data with only collisions containing n tracks + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoDreamParticleTable + void processCollisionsWithNTracksAndNCascades(o2::aod::FDCollision& col, + o2::aod::FDParticles& parts) + { + EventRegistry.fill(HIST("hStatistiscs"), 0); + auto thegroupSelectedParts = SelectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + auto thegroupSelectedCascades = SelectedCascades->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + + createSpecifiedDerivedData_TrkCascade(col, thegroupSelectedParts, thegroupSelectedCascades, parts); + } + PROCESS_SWITCH(femtoDreamProducerTaskForSpecificAnalysis, processCollisionsWithNTracksAndNCascades, "Enable producing data with tracks and Cascades collisions for data", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTaskWithCascades.cxx b/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTaskWithCascades.cxx new file mode 100644 index 00000000000..34702c55d83 --- /dev/null +++ b/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTaskWithCascades.cxx @@ -0,0 +1,1173 @@ +// Copyright 2019-2022 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 femtoDreamProducerTaskWithCascades.cxx +/// \brief Tasks that produces the track tables used for the pairing +/// \author Laura Serksnyte, TU München, laura.serksnyte@tum.de + +#include +#include +#include +#include +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamTrackSelection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamV0Selection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamCascadeSelection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "EventFiltering/Zorro.h" +#include "PWGCF/DataModel/FemtoDerived.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "ReconstructionDataFormats/Track.h" +#include "TMath.h" +#include "Math/Vector4D.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femtoDream; + +namespace o2::aod +{ + +using FemtoFullCollision = soa::Join::iterator; +using FemtoFullCollision_noCent = soa::Join::iterator; +using FemtoFullCollision_CentPbPb = soa::Join::iterator; +using FemtoFullCollisionMC = soa::Join::iterator; +using FemtoFullCollision_noCent_MC = soa::Join::iterator; +using FemtoFullCollisionMC_CentPbPb = soa::Join::iterator; +using FemtoFullMCgenCollisions = soa::Join; +using FemtoFullMCgenCollision = FemtoFullMCgenCollisions::iterator; + +using FemtoFullTracks = + soa::Join; +} // namespace o2::aod + +namespace softwareTriggers +{ +static const int nTriggers = 6; +static const std::vector triggerNames{"fPPP", "fPPL", "fPLL", "fLLL", "fPD", "fLD"}; +static const float triggerSwitches[1][nTriggers]{ + {0, 0, 0, 0, 0, 0}}; +} // namespace softwareTriggers + +template +int getRowDaughters(int daughID, T const& vecID) +{ + int rowInPrimaryTrackTableDaugh = -1; + for (size_t i = 0; i < vecID.size(); i++) { + if (vecID.at(i) == daughID) { + rowInPrimaryTrackTableDaugh = i; + break; + } + } + return rowInPrimaryTrackTableDaugh; +} + +struct femtoDreamProducerTaskWithCascades { + + Zorro zorro; + + Produces outputCollision; + Produces outputMCCollision; + Produces outputCollsMCLabels; + Produces outputParts; + Produces outputPartsMC; + Produces outputDebugParts; + Produces outputPartsMCLabels; + Produces outputDebugPartsMC; + Produces outputPartsExtMCLabels; + + Configurable ConfIsDebug{"ConfIsDebug", true, "Enable Debug tables"}; + Configurable ConfUseItsPid{"ConfUseItsPid", false, "Enable Debug tables"}; + Configurable ConfIsRun3{"ConfIsRun3", false, "Running on Run3 or pilot"}; + Configurable ConfIsForceGRP{"ConfIsForceGRP", false, "Set true if the magnetic field configuration is not available in the usual CCDB directory (e.g. for Run 2 converted data or unanchorad Monte Carlo)"}; + /// Event cuts + FemtoDreamCollisionSelection colCuts; + // Event cuts - Triggers + Configurable ConfEnableTriggerSelection{"ConfEnableTriggerSelection", false, "Should the trigger selection be enabled for collisions?"}; + Configurable> ConfTriggerSwitches{ + "ConfTriggerSwitches", + {softwareTriggers::triggerSwitches[0], 1, softwareTriggers::nTriggers, std::vector{"Switch"}, softwareTriggers::triggerNames}, + "Turn on which trigger should be checked for recorded events to pass selection"}; + Configurable ConfBaseCCDBPathForTriggers{"ConfBaseCCDBPathForTriggers", "Users/m/mpuccio/EventFiltering/OTS/Chunked/", "Provide ccdb path for trigger table; default - trigger coordination"}; + + // Event cuts - usual selection criteria + Configurable ConfEvtZvtx{"ConfEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; + Configurable ConfEvtTriggerCheck{"ConfEvtTriggerCheck", true, "Evt sel: check for trigger"}; + Configurable ConfEvtTriggerSel{"ConfEvtTriggerSel", kINT7, "Evt sel: trigger"}; + Configurable ConfEvtOfflineCheck{"ConfEvtOfflineCheck", false, "Evt sel: check for offline selection"}; + Configurable ConfEvtAddOfflineCheck{"ConfEvtAddOfflineCheck", false, "Evt sel: additional checks for offline selection (not part of sel8 yet)"}; + Configurable ConfIsActivateV0{"ConfIsActivateV0", true, "Activate filling of V0 into femtodream tables"}; + Configurable ConfIsActivateReso{"ConfIsActivateReso", false, "Activate filling of sl Resonances into femtodream tables"}; + Configurable ConfIsActivateCascade{"ConfIsActivateCascade", false, "Activate filling of Cascades into femtodream tables"}; + + Configurable ConfTrkRejectNotPropagated{"ConfTrkRejectNotPropagated", false, "True: reject not propagated tracks"}; + // Configurable ConfRejectITSHitandTOFMissing{ "ConfRejectITSHitandTOFMissing", false, "True: reject if neither ITS hit nor TOF timing satisfied"}; + Configurable ConfTrkPDGCode{"ConfTrkPDGCode", 2212, "PDG code of the selected track for Monte Carlo truth"}; + FemtoDreamTrackSelection trackCuts; + Configurable> ConfTrkCharge{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kSign, "ConfTrk"), std::vector{-1, 1}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kSign, "Track selection: ")}; + Configurable> ConfTrkPtmin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kpTMin, "ConfTrk"), std::vector{0.5f, 0.4f, 0.6f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kpTMin, "Track selection: ")}; + Configurable> ConfTrkPtmax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kpTMax, "ConfTrk"), std::vector{5.4f, 5.6f, 5.5f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kpTMax, "Track selection: ")}; + Configurable> ConfTrkEta{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kEtaMax, "ConfTrk"), std::vector{0.8f, 0.7f, 0.9f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kEtaMax, "Track selection: ")}; + Configurable> ConfTrkTPCnclsMin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kTPCnClsMin, "ConfTrk"), std::vector{80.f, 70.f, 60.f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kTPCnClsMin, "Track selection: ")}; + Configurable> ConfTrkTPCfCls{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kTPCfClsMin, "ConfTrk"), std::vector{0.7f, 0.83f, 0.9f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kTPCfClsMin, "Track selection: ")}; + Configurable> ConfTrkTPCcRowsMin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kTPCcRowsMin, "ConfTrk"), std::vector{70.f, 60.f, 80.f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kTPCcRowsMin, "Track selection: ")}; + Configurable> ConfTrkTPCsCls{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kTPCsClsMax, "ConfTrk"), std::vector{0.1f, 160.f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kTPCsClsMax, "Track selection: ")}; + Configurable> ConfTrkITSnclsMin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kITSnClsMin, "ConfTrk"), std::vector{-1.f, 2.f, 4.f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kITSnClsMin, "Track selection: ")}; + Configurable> ConfTrkITSnclsIbMin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kITSnClsIbMin, "ConfTrk"), std::vector{-1.f, 1.f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kITSnClsIbMin, "Track selection: ")}; + Configurable> ConfTrkDCAxyMax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kDCAxyMax, "ConfTrk"), std::vector{0.1f, 3.5f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kDCAxyMax, "Track selection: ")}; + Configurable> ConfTrkDCAzMax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kDCAzMax, "ConfTrk"), std::vector{0.2f, 3.5f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kDCAzMax, "Track selection: ")}; + Configurable> ConfTrkPIDnSigmaMax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kPIDnSigmaMax, "ConfTrk"), std::vector{3.5f, 3.f, 2.5f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kPIDnSigmaMax, "Track selection: ")}; + Configurable ConfTrkPIDnSigmaOffsetTPC{"ConfTrkPIDnSigmaOffsetTPC", 0., "Offset for TPC nSigma because of bad calibration"}; + Configurable ConfTrkPIDnSigmaOffsetTOF{"ConfTrkPIDnSigmaOffsetTOF", 0., "Offset for TOF nSigma because of bad calibration"}; + Configurable> ConfTrkPIDspecies{"ConfTrkPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Kaon, o2::track::PID::Proton, o2::track::PID::Deuteron}, "Trk sel: Particles species for PID"}; + + FemtoDreamV0Selection v0Cuts; + Configurable> ConfV0Sign{FemtoDreamV0Selection::getSelectionName(femtoDreamV0Selection::kV0Sign, "ConfV0"), std::vector{-1, 1}, FemtoDreamV0Selection::getSelectionHelper(femtoDreamV0Selection::kV0Sign, "V0 selection: ")}; + Configurable> ConfV0PtMin{FemtoDreamV0Selection::getSelectionName(femtoDreamV0Selection::kV0pTMin, "ConfV0"), std::vector{0.3f, 0.4f, 0.5f}, FemtoDreamV0Selection::getSelectionHelper(femtoDreamV0Selection::kV0pTMin, "V0 selection: ")}; + Configurable> ConfV0PtMax{FemtoDreamV0Selection::getSelectionName(femtoDreamV0Selection::kV0pTMax, "ConfV0"), std::vector{3.3f, 3.4f, 3.5f}, FemtoDreamV0Selection::getSelectionHelper(femtoDreamV0Selection::kV0pTMax, "V0 selection: ")}; + Configurable> ConfV0EtaMax{FemtoDreamV0Selection::getSelectionName(femtoDreamV0Selection::kV0etaMax, "ConfV0"), std::vector{0.8f, 0.7f, 0.9f}, FemtoDreamV0Selection::getSelectionHelper(femtoDreamV0Selection::kV0etaMax, "V0 selection: ")}; + Configurable> ConfV0DCADaughMax{FemtoDreamV0Selection::getSelectionName(femtoDreamV0Selection::kV0DCADaughMax, "ConfV0"), std::vector{1.2f, 1.5f}, FemtoDreamV0Selection::getSelectionHelper(femtoDreamV0Selection::kV0DCADaughMax, "V0 selection: ")}; + Configurable> ConfV0CPAMin{FemtoDreamV0Selection::getSelectionName(femtoDreamV0Selection::kV0CPAMin, "ConfV0"), std::vector{0.99f, 0.995f}, FemtoDreamV0Selection::getSelectionHelper(femtoDreamV0Selection::kV0CPAMin, "V0 selection: ")}; + Configurable> ConfV0TranRadMin{FemtoDreamV0Selection::getSelectionName(femtoDreamV0Selection::kV0TranRadMin, "ConfV0"), std::vector{0.2f}, FemtoDreamV0Selection::getSelectionHelper(femtoDreamV0Selection::kV0TranRadMin, "V0 selection: ")}; + Configurable> ConfV0TranRadMax{FemtoDreamV0Selection::getSelectionName(femtoDreamV0Selection::kV0TranRadMax, "ConfV0"), std::vector{100.f}, FemtoDreamV0Selection::getSelectionHelper(femtoDreamV0Selection::kV0TranRadMax, "V0 selection: ")}; + Configurable> ConfV0DecVtxMax{FemtoDreamV0Selection::getSelectionName(femtoDreamV0Selection::kV0DecVtxMax, "ConfV0"), std::vector{100.f}, FemtoDreamV0Selection::getSelectionHelper(femtoDreamV0Selection::kV0DecVtxMax, "V0 selection: ")}; + + Configurable ConfV0InvMassLowLimit{"ConfV0InvV0MassLowLimit", 1.05, "Lower limit of the V0 invariant mass"}; + Configurable ConfV0InvMassUpLimit{"ConfV0InvV0MassUpLimit", 1.30, "Upper limit of the V0 invariant mass"}; + Configurable ConfV0RejectKaons{"ConfV0RejectKaons", false, "Switch to reject kaons"}; + Configurable ConfV0InvKaonMassLowLimit{"ConfV0InvKaonMassLowLimit", 0.48, "Lower limit of the V0 invariant mass for Kaon rejection"}; + Configurable ConfV0InvKaonMassUpLimit{"ConfV0InvKaonMassUpLimit", 0.515, "Upper limit of the V0 invariant mass for Kaon rejection"}; + + Configurable> ConfChildCharge{"ConfChildSign", std::vector{-1, 1}, "V0 Child sel: Charge"}; + Configurable> ConfChildEtaMax{"ConfChildEtaMax", std::vector{0.8f}, "V0 Child sel: max eta"}; + Configurable> ConfChildTPCnClsMin{"ConfChildTPCnClsMin", std::vector{80.f, 70.f, 60.f}, "V0 Child sel: Min. nCls TPC"}; + Configurable> ConfChildDCAMin{"ConfChildDCAMin", std::vector{0.05f, 0.06f}, "V0 Child sel: Max. DCA Daugh to PV (cm)"}; + Configurable> ConfChildPIDnSigmaMax{"ConfChildPIDnSigmaMax", std::vector{5.f, 4.f}, "V0 Child sel: Max. PID nSigma TPC"}; + Configurable> ConfChildPIDspecies{"ConfChildPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Proton}, "V0 Child sel: Particles species for PID"}; + + FemtoDreamCascadeSelection cascadeCuts; + struct : o2::framework::ConfigurableGroup { + Configurable ConfCascInvMassLowLimit{"ConfCascInvMassLowLimit", 1.2, "Lower limit of the Cascade invariant mass"}; + Configurable ConfCascInvMassUpLimit{"ConfCascInvMassUpLimit", 1.5, "Upper limit of the Cascade invariant mass"}; + Configurable ConfCascIsSelectedOmega{"ConfCascIsSelectedOmega", false, "Select Omegas instead of Xis (invariant mass)"}; + // Cascade + Configurable> ConfCascadeSign{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeSign, "ConfCascade"), std::vector{-1, 1}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeSign, "Cascade selection: ")}; + Configurable> ConfCascadePtMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadePtMin, "ConfCascade"), std::vector{0.3f, 0.4f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadePtMin, "Cascade selection: ")}; + Configurable> ConfCascadePtMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadePtMax, "ConfCascade"), std::vector{5.5f, 6.0f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadePtMax, "Cascade selection: ")}; + Configurable> ConfCascadeEtaMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeEtaMax, "ConfCascade"), std::vector{0.8f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeEtaMax, "Cascade selection: ")}; + Configurable> ConfCascadeDCADaughMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeDCADaughMax, "ConfCascade"), std::vector{1.f, 1.2f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeDCADaughMax, "Cascade selection: ")}; + Configurable> ConfCascadeCPAMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeCPAMin, "ConfCascade"), std::vector{0.99f, 0.95f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeCPAMin, "Cascade selection: ")}; + Configurable> ConfCascadeTranRadMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeTranRadMin, "ConfCascade"), std::vector{0.2f, 0.5f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeTranRadMin, "Cascade selection: ")}; + Configurable> ConfCascadeTranRadMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeTranRadMax, "ConfCascade"), std::vector{100.f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeTranRadMax, "Cascade selection: ")}; + Configurable> ConfCascadeDecVtxMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeDecVtxMax, "ConfCascade"), std::vector{100.f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeDecVtxMax, "Cascade selection: ")}; + + // Cascade v0 daughters + Configurable> ConfCascadeV0DCADaughMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0DCADaughMax, "ConfCascade"), std::vector{1.2f, 1.5f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0DCADaughMax, "CascV0 selection: ")}; + Configurable> ConfCascadeV0CPAMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0CPAMin, "ConfCascade"), std::vector{0.99f, 0.995f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0CPAMin, "CascV0 selection: ")}; + Configurable> ConfCascadeV0TranRadMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0TranRadMin, "ConfCascade"), std::vector{0.2f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0TranRadMin, "CascV0 selection: ")}; + Configurable> ConfCascadeV0TranRadMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0TranRadMax, "ConfCascade"), std::vector{100.f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0TranRadMax, "CascV0 selection: ")}; + Configurable> ConfCascadeV0DCAtoPVMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMin, "ConfCascade"), std::vector{100.f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMin, "CascV0 selection: ")}; + Configurable> ConfCascadeV0DCAtoPVMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMax, "ConfCascade"), std::vector{100.f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMax, "CascV0 selection: ")}; + Configurable ConfCascV0InvMassLowLimit{"ConfCascV0InvMassLowLimit", 1.011461, "Lower limit of the Cascade invariant mass"}; + Configurable ConfCascV0InvMassUpLimit{"ConfCascV0InvMassUpLimit", 1.027461, "Upper limit of the Cascade invariant mass"}; + // Cascade Daughter Tracks + Configurable> ConfCascV0ChildCharge{"ConfCascV0ChildSign", std::vector{-1, 1}, "CascV0 Child sel: Charge"}; + Configurable> ConfCascV0ChildPtMin{"ConfCascV0ChildPtMin", std::vector{0.8f}, "CascV0 Child sel: min pt"}; + Configurable> ConfCascV0ChildEtaMax{"ConfCascV0ChildEtaMax", std::vector{0.8f}, "CascV0 Child sel: max eta"}; + Configurable> ConfCascV0ChildTPCnClsMin{"ConfCascV0ChildTPCnClsMin", std::vector{80.f, 70.f, 60.f}, "CascV0 Child sel: Min. nCls TPC"}; + Configurable> ConfCascV0ChildDCAMin{"ConfCascV0ChildDCAMin", std::vector{0.05f, 0.06f}, "CascV0 Child sel: Max. DCA Daugh to PV (cm)"}; + Configurable> ConfCascV0ChildPIDnSigmaMax{"ConfCascV0ChildPIDnSigmaMax", std::vector{5.f, 4.f}, "CascV0 Child sel: Max. PID nSigma TPC"}; + Configurable> ConfCascV0ChildPIDspecies{"ConfCascV0ChildPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Proton}, "CascV0 Child sel: Particles species for PID"}; + // Cascade Bachelor Track + Configurable> ConfCascBachelorCharge{"ConfCascBachelorSign", std::vector{-1, 1}, "Cascade Bachelor sel: Charge"}; + Configurable> ConfCascBachelorPtMin{"ConfCascBachelorPtMin", std::vector{0.8f}, "Cascade Bachelor sel: min pt"}; + Configurable> ConfCascBachelorEtaMax{"ConfCascBachelorEtaMax", std::vector{0.8f}, "Cascade Bachelor sel: max eta"}; + Configurable> ConfCascBachelorTPCnClsMin{"ConfCascBachelorTPCnClsMin", std::vector{80.f, 70.f, 60.f}, "Cascade Bachelor sel: Min. nCls TPC"}; + Configurable> ConfCascBachelorDCAMin{"ConfCascBachelorDCAMin", std::vector{0.05f, 0.06f}, "Cascade Bachelor sel: Max. DCA Daugh to PV (cm)"}; + Configurable> ConfCascBachelorPIDnSigmaMax{"ConfCascBachelorPIDnSigmaMax", std::vector{5.f, 4.f}, "Cascade Bachelor sel: Max. PID nSigma TPC"}; + Configurable> ConfCascBachelorPIDspecies{"ConfCascBachelorPIDspecies", std::vector{o2::track::PID::Pion}, "Cascade Bachelor sel: Particles species for PID"}; + + Configurable ConfCascRejectCompetingMass{"ConfCascRejectCompetingMass", false, "Switch on to reject Omegas (for Xi) or Xis (for Omegas)"}; + Configurable ConfCascInvCompetingMassLowLimit{"ConfCascInvCompetingMassLowLimit", 1.66, "Lower limit of the cascade invariant mass for competing mass rejection"}; + Configurable ConfCascInvCompetingMassUpLimit{"ConfCascInvCompetingMassUpLimit", 1.68, "Upper limit of the cascade invariant mass for competing mass rejection"}; + + } ConfCascSel; + + // Resonances + Configurable ConfResoInvMassLowLimit{"ConfResoInvMassLowLimit", 1.011461, "Lower limit of the Reso invariant mass"}; + Configurable ConfResoInvMassUpLimit{"ConfResoInvMassUpLimit", 1.027461, "Upper limit of the Reso invariant mass"}; + Configurable> ConfDaughterCharge{"ConfDaughterCharge", std::vector{1, -1}, "Reso Daughter sel: Charge"}; + Configurable> ConfDaughterEta{"ConfDaughterEta", std::vector{0.8, 0.8}, "Reso Daughter sel: Eta"}; // 0.8 + Configurable> ConfDaughterDCAxy{"ConfDaughterDCAxy", std::vector{0.1, 0.1}, "Reso Daughter sel: DCAxy"}; // 0.1 + Configurable> ConfDaughterDCAz{"ConfDaughterDCAz", std::vector{0.2, 0.2}, "Reso Daughter sel: DCAz"}; // 0.2 + Configurable> ConfDaughterNClus{"ConfDaughterNClus", std::vector{80, 80}, "Reso Daughter sel: NClusters"}; // 0.2 + Configurable> ConfDaughterNCrossed{"ConfDaughterNCrossed", std::vector{70, 70}, "Reso Daughter sel: NCrossedRowss"}; + Configurable> ConfDaughterTPCfCls{"ConfDaughterTPCfCls", std::vector{0.8, 0.8}, "Reso Daughter sel: Minimum fraction of crossed rows over findable cluster"}; // 0.2 + Configurable> ConfDaughterPtUp{"ConfDaughterPtUp", std::vector{2.0, 2.0}, "Reso Daughter sel: Upper limit pT"}; // 2.0 + Configurable> ConfDaughterPtLow{"ConfDaughterPtLow", std::vector{0.15, 0.15}, "Reso Daughter sel: Lower limit pT"}; // 0.15 + Configurable> ConfDaughterPTPCThr{"ConfDaughterPTPCThr", std::vector{0.40, 0.40}, "Reso Daughter sel: momentum threshold TPC only PID, p_TPC,Thr"}; // 0.4 + Configurable> ConfDaughterPIDnSigmaMax{"ConfDaughterPIDnSigmaMax", std::vector{3.00, 3.00}, "Reso Daughter sel: Max. PID nSigma TPC"}; // 3.0 + Configurable> ConfDaughterPIDspecies{"ConfDaughterPIDspecies", std::vector{o2::track::PID::Kaon, o2::track::PID::Kaon}, "Reso Daughter sel: Particles species for PID"}; + Configurable> ConfDaug1Daugh2ResoMass{"ConfDaug1Daugh2ResoMass", std::vector{o2::constants::physics::MassKPlus, o2::constants::physics::MassKMinus, o2::constants::physics::MassPhi}, "Masses: Daughter1 - Daughter2 - Resonance"}; + + /// \todo should we add filter on min value pT/eta of V0 and daughters? + /*Filter v0Filter = (nabs(aod::v0data::x) < V0DecVtxMax.value) && + (nabs(aod::v0data::y) < V0DecVtxMax.value) && + (nabs(aod::v0data::z) < V0DecVtxMax.value);*/ + // (aod::v0data::v0radius > V0TranRadV0Min.value); to be added, not working + // for now do not know why + + /// General options + struct : o2::framework::ConfigurableGroup { + Configurable ConfTrkMinChi2PerClusterTPC{"ConfTrkMinChi2PerClusterTPC", 0.f, "Lower limit for chi2 of TPC; currently for testing only"}; + Configurable ConfTrkMaxChi2PerClusterTPC{"ConfTrkMaxChi2PerClusterTPC", 1000.f, "Upper limit for chi2 of TPC; currently for testing only"}; + Configurable ConfTrkMaxChi2PerClusterITS{"ConfTrkMaxChi2PerClusterITS", 1000.0f, "Minimal track selection: max allowed chi2 per ITS cluster"}; // 36.0 is default + Configurable ConfTrkTPCRefit{"ConfTrkTPCRefit", false, "True: require TPC refit"}; + Configurable ConfTrkITSRefit{"ConfTrkITSRefit", false, "True: require ITS refit"}; + + } OptionTrackSpecialSelections; + + HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry TrackRegistry{"Tracks", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry V0Registry{"V0", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry ResoRegistry{"Reso", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry CascadeRegistry{"Cascade", {}, OutputObjHandlingPolicy::AnalysisObject}; + + int mRunNumber; + float mMagField; + std::string zorroTriggerNames = ""; + Service ccdb; /// Accessing the CCDB + + void init(InitContext&) + { + if (doprocessData == false && doprocessData_noCentrality == false && doprocessData_CentPbPb == false && doprocessMC == false && doprocessMC_noCentrality == false && doprocessMC_CentPbPb == false) { + LOGF(fatal, "Neither processData nor processMC enabled. Please choose one."); + } + if ((doprocessData == true && doprocessMC == true) || (doprocessData == true && doprocessMC_noCentrality == true) || (doprocessMC == true && doprocessMC_noCentrality == true) || (doprocessData_noCentrality == true && doprocessData == true) || (doprocessData_noCentrality == true && doprocessMC == true) || (doprocessData_noCentrality == true && doprocessMC_noCentrality == true) || (doprocessData_CentPbPb == true && doprocessData == true) || (doprocessData_CentPbPb == true && doprocessData_noCentrality == true) || (doprocessData_CentPbPb == true && doprocessMC == true) || (doprocessData_CentPbPb == true && doprocessMC_noCentrality == true) || (doprocessData_CentPbPb == true && doprocessMC_CentPbPb == true)) { + LOGF(fatal, + "Cannot enable more than one process switch at the same time. " + "Please choose one."); + } + + int CutBits = 8 * sizeof(o2::aod::femtodreamparticle::cutContainerType); + TrackRegistry.add("AnalysisQA/CutCounter", "; Bit; Counter", kTH1F, {{CutBits + 1, -0.5, CutBits + 0.5}}); + TrackRegistry.add("AnalysisQA/Chi2ITSTPCperCluster", "; ITS_Chi2; TPC_Chi2", kTH2F, {{100, 0, 50}, {100, 0, 20}}); + TrackRegistry.add("AnalysisQA/RefitITSTPC", "; ITS_Refit; TPC_Refit", kTH2F, {{2, 0, 2}, {2, 0, 2}}); + TrackRegistry.add("AnalysisQA/getGenStatusCode", "; Bit; Entries", kTH1F, {{200, 0, 200}}); + TrackRegistry.add("AnalysisQA/getProcess", "; Bit; Entries", kTH1F, {{200, 0, 200}}); + TrackRegistry.add("AnalysisQA/Mother", "; Bit; Entries", kTH1F, {{4000, -4000, 4000}}); + TrackRegistry.add("AnalysisQA/Particle", "; Bit; Entries", kTH1F, {{4000, -4000, 4000}}); + V0Registry.add("AnalysisQA/CutCounter", "; Bit; Counter", kTH1F, {{CutBits + 1, -0.5, CutBits + 0.5}}); + CascadeRegistry.add("AnalysisQA/CutCounter", "; Bit; Counter", kTH1F, {{CutBits + 1, -0.5, CutBits + 0.5}}); + ResoRegistry.add("AnalysisQA/Reso/InvMass", "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {{7000, 0.8, 1.5}}); + ResoRegistry.add("AnalysisQA/Reso/InvMass_selected", "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {{7000, 0.8, 1.5}}); + ResoRegistry.add("AnalysisQA/Reso/Daughter1/Pt", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + ResoRegistry.add("AnalysisQA/Reso/Daughter1/Eta", "Pseudorapidity of all processed tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); + ResoRegistry.add("AnalysisQA/Reso/Daughter1/Phi", "Azimuthal angle of all processed tracks;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); + ResoRegistry.add("AnalysisQA/Reso/Daughter2/Pt", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + ResoRegistry.add("AnalysisQA/Reso/Daughter2/Eta", "Pseudorapidity of all processed tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); + ResoRegistry.add("AnalysisQA/Reso/Daughter2/Phi", "Azimuthal angle of all processed tracks;#phi;Entries", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); + ResoRegistry.add("AnalysisQA/Reso/PtD1_selected", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + ResoRegistry.add("AnalysisQA/Reso/PtD2_selected", "Transverse momentum of all processed tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + + if (ConfEnableTriggerSelection) { + for (const std::string& triggerName : softwareTriggers::triggerNames) { + if (ConfTriggerSwitches->get("Switch", triggerName.c_str())) { + zorroTriggerNames += triggerName + ","; + } + } + zorroTriggerNames.pop_back(); + } + + colCuts.setCuts(ConfEvtZvtx.value, ConfEvtTriggerCheck.value, ConfEvtTriggerSel.value, ConfEvtOfflineCheck.value, ConfEvtAddOfflineCheck.value, ConfIsRun3.value); + colCuts.init(&qaRegistry); + + trackCuts.setSelection(ConfTrkCharge, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + trackCuts.setSelection(ConfTrkPtmin, femtoDreamTrackSelection::kpTMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(ConfTrkPtmax, femtoDreamTrackSelection::kpTMax, femtoDreamSelection::kUpperLimit); + trackCuts.setSelection(ConfTrkEta, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + trackCuts.setSelection(ConfTrkTPCnclsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(ConfTrkTPCfCls, femtoDreamTrackSelection::kTPCfClsMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(ConfTrkTPCcRowsMin, femtoDreamTrackSelection::kTPCcRowsMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(ConfTrkTPCsCls, femtoDreamTrackSelection::kTPCsClsMax, femtoDreamSelection::kUpperLimit); + trackCuts.setSelection(ConfTrkITSnclsMin, femtoDreamTrackSelection::kITSnClsMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(ConfTrkITSnclsIbMin, femtoDreamTrackSelection::kITSnClsIbMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(ConfTrkDCAxyMax, femtoDreamTrackSelection::kDCAxyMax, femtoDreamSelection::kAbsUpperLimit); + trackCuts.setSelection(ConfTrkDCAzMax, femtoDreamTrackSelection::kDCAzMax, femtoDreamSelection::kAbsUpperLimit); + trackCuts.setSelection(ConfTrkPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + trackCuts.setPIDSpecies(ConfTrkPIDspecies); + trackCuts.setnSigmaPIDOffset(ConfTrkPIDnSigmaOffsetTPC, ConfTrkPIDnSigmaOffsetTOF); + trackCuts.init(&qaRegistry, &TrackRegistry); + + /// \todo fix how to pass array to setSelection, getRow() passing a + /// different type! + // v0Cuts.setSelection(ConfV0Selection->getRow(0), + // femtoDreamV0Selection::kDecVtxMax, femtoDreamSelection::kAbsUpperLimit); + if (ConfIsActivateV0) { + v0Cuts.setSelection(ConfV0Sign, femtoDreamV0Selection::kV0Sign, femtoDreamSelection::kEqual); + v0Cuts.setSelection(ConfV0PtMin, femtoDreamV0Selection::kV0pTMin, femtoDreamSelection::kLowerLimit); + v0Cuts.setSelection(ConfV0PtMax, femtoDreamV0Selection::kV0pTMax, femtoDreamSelection::kUpperLimit); + v0Cuts.setSelection(ConfV0EtaMax, femtoDreamV0Selection::kV0etaMax, femtoDreamSelection::kAbsUpperLimit); + v0Cuts.setSelection(ConfV0DCADaughMax, femtoDreamV0Selection::kV0DCADaughMax, femtoDreamSelection::kUpperLimit); + v0Cuts.setSelection(ConfV0CPAMin, femtoDreamV0Selection::kV0CPAMin, femtoDreamSelection::kLowerLimit); + v0Cuts.setSelection(ConfV0TranRadMin, femtoDreamV0Selection::kV0TranRadMin, femtoDreamSelection::kLowerLimit); + v0Cuts.setSelection(ConfV0TranRadMax, femtoDreamV0Selection::kV0TranRadMax, femtoDreamSelection::kUpperLimit); + v0Cuts.setSelection(ConfV0DecVtxMax, femtoDreamV0Selection::kV0DecVtxMax, femtoDreamSelection::kUpperLimit); + v0Cuts.setChildCuts(femtoDreamV0Selection::kPosTrack, ConfChildCharge, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + v0Cuts.setChildCuts(femtoDreamV0Selection::kPosTrack, ConfChildEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + v0Cuts.setChildCuts(femtoDreamV0Selection::kPosTrack, ConfChildTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + v0Cuts.setChildCuts(femtoDreamV0Selection::kPosTrack, ConfChildDCAMin, femtoDreamTrackSelection::kDCAMin, femtoDreamSelection::kAbsLowerLimit); + v0Cuts.setChildCuts(femtoDreamV0Selection::kPosTrack, ConfChildPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + + v0Cuts.setChildCuts(femtoDreamV0Selection::kNegTrack, ConfChildCharge, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + v0Cuts.setChildCuts(femtoDreamV0Selection::kNegTrack, ConfChildEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + v0Cuts.setChildCuts(femtoDreamV0Selection::kNegTrack, ConfChildTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + v0Cuts.setChildCuts(femtoDreamV0Selection::kNegTrack, ConfChildDCAMin, femtoDreamTrackSelection::kDCAMin, femtoDreamSelection::kAbsLowerLimit); + v0Cuts.setChildCuts(femtoDreamV0Selection::kNegTrack, ConfChildPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + v0Cuts.setChildPIDSpecies(femtoDreamV0Selection::kPosTrack, ConfChildPIDspecies); + v0Cuts.setChildPIDSpecies(femtoDreamV0Selection::kNegTrack, ConfChildPIDspecies); + v0Cuts.init(&qaRegistry, &V0Registry); + v0Cuts.setInvMassLimits(ConfV0InvMassLowLimit, ConfV0InvMassUpLimit); + + v0Cuts.setChildRejectNotPropagatedTracks(femtoDreamV0Selection::kPosTrack, ConfTrkRejectNotPropagated); + v0Cuts.setChildRejectNotPropagatedTracks(femtoDreamV0Selection::kNegTrack, ConfTrkRejectNotPropagated); + + v0Cuts.setnSigmaPIDOffsetTPC(ConfTrkPIDnSigmaOffsetTPC); + v0Cuts.setChildnSigmaPIDOffset(femtoDreamV0Selection::kPosTrack, ConfTrkPIDnSigmaOffsetTPC, ConfTrkPIDnSigmaOffsetTOF); + v0Cuts.setChildnSigmaPIDOffset(femtoDreamV0Selection::kNegTrack, ConfTrkPIDnSigmaOffsetTPC, ConfTrkPIDnSigmaOffsetTOF); + + if (ConfV0RejectKaons) { + v0Cuts.setKaonInvMassLimits(ConfV0InvKaonMassLowLimit, ConfV0InvKaonMassUpLimit); + } + } + if (ConfIsActivateCascade) { + // Cascades + cascadeCuts.setSelection(ConfCascSel.ConfCascadeSign, femtoDreamCascadeSelection::kCascadeSign, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeSign)); + cascadeCuts.setSelection(ConfCascSel.ConfCascadePtMin, femtoDreamCascadeSelection::kCascadePtMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadePtMin)); + cascadeCuts.setSelection(ConfCascSel.ConfCascadePtMax, femtoDreamCascadeSelection::kCascadePtMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadePtMax)); + cascadeCuts.setSelection(ConfCascSel.ConfCascadeEtaMax, femtoDreamCascadeSelection::kCascadeEtaMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeEtaMax)); + cascadeCuts.setSelection(ConfCascSel.ConfCascadeDCADaughMax, femtoDreamCascadeSelection::kCascadeDCADaughMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeDCADaughMax)); + cascadeCuts.setSelection(ConfCascSel.ConfCascadeCPAMin, femtoDreamCascadeSelection::kCascadeCPAMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeCPAMin)); + cascadeCuts.setSelection(ConfCascSel.ConfCascadeTranRadMin, femtoDreamCascadeSelection::kCascadeTranRadMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeTranRadMin)); + cascadeCuts.setSelection(ConfCascSel.ConfCascadeTranRadMax, femtoDreamCascadeSelection::kCascadeTranRadMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeTranRadMax)); + cascadeCuts.setSelection(ConfCascSel.ConfCascadeDecVtxMax, femtoDreamCascadeSelection::kCascadeDecVtxMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeDecVtxMax)); + // Cascade v0 + cascadeCuts.setSelection(ConfCascSel.ConfCascadeV0DCADaughMax, femtoDreamCascadeSelection::kCascadeV0DCADaughMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0DCADaughMax)); + cascadeCuts.setSelection(ConfCascSel.ConfCascadeV0CPAMin, femtoDreamCascadeSelection::kCascadeV0CPAMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0CPAMin)); + cascadeCuts.setSelection(ConfCascSel.ConfCascadeV0TranRadMin, femtoDreamCascadeSelection::kCascadeV0TranRadMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0TranRadMin)); + cascadeCuts.setSelection(ConfCascSel.ConfCascadeV0TranRadMax, femtoDreamCascadeSelection::kCascadeV0TranRadMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0TranRadMax)); + cascadeCuts.setSelection(ConfCascSel.ConfCascadeV0DCAtoPVMin, femtoDreamCascadeSelection::kCascadeV0DCAtoPVMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMin)); + cascadeCuts.setSelection(ConfCascSel.ConfCascadeV0DCAtoPVMax, femtoDreamCascadeSelection::kCascadeV0DCAtoPVMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMax)); + + // Cascade Daughter Tracks + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, ConfCascSel.ConfCascV0ChildCharge, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, ConfCascSel.ConfCascV0ChildPtMin, femtoDreamTrackSelection::kpTMin, femtoDreamSelection::kLowerLimit); + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, ConfCascSel.ConfCascV0ChildEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, ConfCascSel.ConfCascV0ChildTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, ConfCascSel.ConfCascV0ChildDCAMin, femtoDreamTrackSelection::kDCAMin, femtoDreamSelection::kAbsLowerLimit); + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, ConfCascSel.ConfCascV0ChildPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + cascadeCuts.setChildPIDSpecies(femtoDreamCascadeSelection::kPosTrack, ConfCascSel.ConfCascV0ChildPIDspecies); + + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, ConfCascSel.ConfCascV0ChildCharge, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, ConfCascSel.ConfCascV0ChildPtMin, femtoDreamTrackSelection::kpTMin, femtoDreamSelection::kLowerLimit); + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, ConfCascSel.ConfCascV0ChildEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, ConfCascSel.ConfCascV0ChildTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, ConfCascSel.ConfCascV0ChildDCAMin, femtoDreamTrackSelection::kDCAMin, femtoDreamSelection::kAbsLowerLimit); + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, ConfCascSel.ConfCascV0ChildPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + cascadeCuts.setChildPIDSpecies(femtoDreamCascadeSelection::kNegTrack, ConfCascSel.ConfCascV0ChildPIDspecies); + + // Cascade Bachelor Track + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, ConfCascSel.ConfCascBachelorCharge, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, ConfCascSel.ConfCascBachelorPtMin, femtoDreamTrackSelection::kpTMin, femtoDreamSelection::kLowerLimit); + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, ConfCascSel.ConfCascBachelorEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, ConfCascSel.ConfCascBachelorTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, ConfCascSel.ConfCascBachelorDCAMin, femtoDreamTrackSelection::kDCAMin, femtoDreamSelection::kAbsLowerLimit); + cascadeCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, ConfCascSel.ConfCascBachelorPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + cascadeCuts.setChildPIDSpecies(femtoDreamCascadeSelection::kBachTrack, ConfCascSel.ConfCascBachelorPIDspecies); + + cascadeCuts.init(&qaRegistry, &CascadeRegistry, ConfCascSel.ConfCascIsSelectedOmega); + cascadeCuts.setInvMassLimits(ConfCascSel.ConfCascInvMassLowLimit, ConfCascSel.ConfCascInvMassUpLimit); + cascadeCuts.setV0InvMassLimits(ConfCascSel.ConfCascV0InvMassLowLimit, ConfCascSel.ConfCascV0InvMassUpLimit); + if (ConfCascSel.ConfCascRejectCompetingMass) { + cascadeCuts.setCompetingInvMassLimits(ConfCascSel.ConfCascInvCompetingMassLowLimit, ConfCascSel.ConfCascInvCompetingMassUpLimit); + } + } + + mRunNumber = 0; + mMagField = 0.0; + /// Initializing CCDB + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + int64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); + } + + /// Function to retrieve the nominal magnetic field in kG (0.1T) and convert it directly to T + void initCCDB_Mag_Trig(aod::BCsWithTimestamps::iterator bc) + { + // TODO done only once (and not per run). Will be replaced by CCDBConfigurable + // get magnetic field for run + if (mRunNumber == bc.runNumber()) + return; + auto timestamp = bc.timestamp(); + float output = -999; + + if (ConfIsRun3 && !ConfIsForceGRP) { + static o2::parameters::GRPMagField* grpo = nullptr; + grpo = ccdb->getForTimeStamp("GLO/Config/GRPMagField", timestamp); + if (grpo == nullptr) { + LOGF(fatal, "GRP object not found for timestamp %llu", timestamp); + return; + } + LOGF(info, "Retrieved GRP for timestamp %llu with L3 ", timestamp, grpo->getL3Current()); + // taken from GRP onject definition of getNominalL3Field; update later to something smarter (mNominalL3Field = std::lround(5.f * mL3Current / 30000.f);) + auto NominalL3Field = std::lround(5.f * grpo->getL3Current() / 30000.f); + output = 0.1 * (NominalL3Field); + + } else { + + static o2::parameters::GRPObject* grpo = nullptr; + grpo = ccdb->getForTimeStamp("GLO/GRP/GRP", timestamp); + if (grpo == nullptr) { + LOGF(fatal, "GRP object not found for timestamp %llu", timestamp); + return; + } + LOGF(info, "Retrieved GRP for timestamp %llu with magnetic field of %d kG", timestamp, grpo->getNominalL3Field()); + output = 0.1 * (grpo->getNominalL3Field()); + } + mMagField = output; + mRunNumber = bc.runNumber(); + + // Init for zorro to get trigger flags + if (ConfEnableTriggerSelection) { + zorro.setCCDBpath(ConfBaseCCDBPathForTriggers); + zorro.initCCDB(ccdb.service, mRunNumber, timestamp, zorroTriggerNames); + } + } + + template + void fillDebugParticle(ParticleType const& particle) + { + if constexpr (isTrackOrV0) { + if constexpr (hasItsPid) { + outputDebugParts(particle.sign(), + (uint8_t)particle.tpcNClsFound(), + particle.tpcNClsFindable(), + (uint8_t)particle.tpcNClsCrossedRows(), + particle.tpcNClsShared(), + particle.tpcInnerParam(), + particle.itsNCls(), + particle.itsNClsInnerBarrel(), + particle.dcaXY(), + particle.dcaZ(), + particle.tpcSignal(), + particle.tpcNSigmaEl(), + particle.tpcNSigmaPi(), + particle.tpcNSigmaKa(), + particle.tpcNSigmaPr(), + particle.tpcNSigmaDe(), + particle.tpcNSigmaTr(), + particle.tpcNSigmaHe(), + particle.tofNSigmaEl(), + particle.tofNSigmaPi(), + particle.tofNSigmaKa(), + particle.tofNSigmaPr(), + particle.tofNSigmaDe(), + particle.tofNSigmaTr(), + particle.tofNSigmaHe(), + o2::analysis::femtoDream::itsSignal(particle), + particle.itsNSigmaEl(), + particle.itsNSigmaPi(), + particle.itsNSigmaKa(), + particle.itsNSigmaPr(), + particle.itsNSigmaDe(), + particle.itsNSigmaTr(), + particle.itsNSigmaHe(), + -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., -999., -999.); + } else { + outputDebugParts(particle.sign(), + (uint8_t)particle.tpcNClsFound(), + particle.tpcNClsFindable(), + (uint8_t)particle.tpcNClsCrossedRows(), + particle.tpcNClsShared(), + particle.tpcInnerParam(), + particle.itsNCls(), + particle.itsNClsInnerBarrel(), + particle.dcaXY(), + particle.dcaZ(), + particle.tpcSignal(), + particle.tpcNSigmaEl(), + particle.tpcNSigmaPi(), + particle.tpcNSigmaKa(), + particle.tpcNSigmaPr(), + particle.tpcNSigmaDe(), + particle.tpcNSigmaTr(), + particle.tpcNSigmaHe(), + particle.tofNSigmaEl(), + particle.tofNSigmaPi(), + particle.tofNSigmaKa(), + particle.tofNSigmaPr(), + particle.tofNSigmaDe(), + particle.tofNSigmaTr(), + particle.tofNSigmaHe(), + -999., -999., -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., -999., -999.); + } + } else { + outputDebugParts(-999., // sign + -999., -999., -999., -999., -999., -999., -999., -999., -999., // track properties (DCA, NCls, crossed rows, etc.) + -999., -999., -999., -999., -999., -999., -999., -999., // TPC PID (TPC signal + particle hypothesis) + -999., -999., -999., -999., -999., -999., -999., // TOF PID + -999., -999., -999., -999., -999., -999., -999., -999., // ITS PID + particle.dcaV0daughters(), + particle.v0radius(), + particle.x(), + particle.y(), + particle.z(), + particle.mK0Short(), + -999., -999., -999., -999., -999., -999., -999.); // Cascade properties + } + } + + template + void fillDebugCascade(ParticleType const& cascade, CollisionType const& col) + { + outputDebugParts(cascade.sign(), // sign + -999., -999., -999., -999., -999., -999., -999., -999., -999., // track properties (DCA, NCls, crossed rows, etc.) + -999., -999., -999., -999., -999., -999., -999., -999., // TPC PID (TPC signal + particle hypothesis) + -999., -999., -999., -999., -999., -999., -999., // TOF PID + -999., -999., -999., -999., -999., -999., -999., -999., // ITS PID + cascade.dcaV0daughters(), + cascade.v0radius(), + -999., // DecVtxV0 x + -999., // DecVtxV0 y + -999., // DecVtxV0 z + -999., // mKaon + cascade.dcav0topv(col.posX(), col.posY(), col.posZ()), + cascade.dcacascdaughters(), + cascade.cascradius(), + cascade.x(), + cascade.y(), + cascade.z(), + cascade.mOmega()); // QA for Reso + } + + template + void fillMCParticle(CollisionType const& col, ParticleType const& particle, o2::aod::femtodreamparticle::ParticleType fdparttype) + { + if (particle.has_mcParticle()) { + // get corresponding MC particle and its info + auto particleMC = particle.mcParticle(); + auto pdgCode = particleMC.pdgCode(); + TrackRegistry.fill(HIST("AnalysisQA/Particle"), pdgCode); + int particleOrigin = 99; + int pdgCodeMother = -1; + // get list of mothers, but it could be empty (for example in case of injected light nuclei) + auto motherparticlesMC = particleMC.template mothers_as(); + // check pdg code + TrackRegistry.fill(HIST("AnalysisQA/getGenStatusCode"), particleMC.getGenStatusCode()); + TrackRegistry.fill(HIST("AnalysisQA/getProcess"), particleMC.getProcess()); + // if this fails, the particle is a fake + if (abs(pdgCode) == abs(ConfTrkPDGCode.value)) { + // check first if particle is from pile up + // check if the collision associated with the particle is the same as the analyzed collision by checking their Ids + if ((col.has_mcCollision() && (particleMC.mcCollisionId() != col.mcCollisionId())) || !col.has_mcCollision()) { + particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kWrongCollision; + // check if particle is primary + } else if (particleMC.isPhysicalPrimary()) { + particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kPrimary; + // check if particle is secondary + // particle is from a decay -> getProcess() == 4 + // particle is generated during transport -> getGenStatusCode() == -1 + // list of mothers is not empty + } else if (particleMC.getProcess() == 4 && particleMC.getGenStatusCode() == -1 && !motherparticlesMC.empty()) { + // get direct mother + auto motherparticleMC = motherparticlesMC.front(); + pdgCodeMother = motherparticleMC.pdgCode(); + TrackRegistry.fill(HIST("AnalysisQA/Mother"), pdgCodeMother); + particleOrigin = checkDaughterType(fdparttype, motherparticleMC.pdgCode()); + // check if particle is material + // particle is from inelastic hadronic interaction -> getProcess() == 23 + // particle is generated during transport -> getGenStatusCode() == -1 + } else if (particleMC.getProcess() == 23 && particleMC.getGenStatusCode() == -1) { + particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kMaterial; + // cross check to see if we missed a case + } else { + particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kElse; + } + // if pdg code is wrong, particle is fake + } else { + particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kFake; + } + + outputPartsMC(particleOrigin, pdgCode, particleMC.pt(), particleMC.eta(), particleMC.phi()); + outputPartsMCLabels(outputPartsMC.lastIndex()); + if (ConfIsDebug) { + outputPartsExtMCLabels(outputPartsMC.lastIndex()); + outputDebugPartsMC(pdgCodeMother); + } + } else { + outputPartsMCLabels(-1); + if (ConfIsDebug) { + outputPartsExtMCLabels(-1); + } + } + } + + template + void fillMCCollision(CollisionType const& col) + { + if (col.has_mcCollision()) { + auto genMCcol = col.template mcCollision_as(); + outputMCCollision(genMCcol.multMCNParticlesEta08()); + outputCollsMCLabels(outputMCCollision.lastIndex()); + } else { + outputCollsMCLabels(-1); + } + } + template + void fillCollisionsAndTracksAndV0AndCascade(CollisionType const& col, TrackType const& tracks, TrackTypeWithItsPid const& tracksWithItsPid, V0Type const& fullV0s, CascadeType const& fullCascades) + { + // If triggering is enabled, select only events which were triggered wit our triggers + if (ConfEnableTriggerSelection) { + bool zorroSelected = zorro.isSelected(col.template bc_as().globalBC()); /// check if event was selected by triggers of interest + if (!zorroSelected) { + return; + } + } + + const auto vtxZ = col.posZ(); + const auto spher = colCuts.computeSphericity(col, tracks); + float mult = 0; + int multNtr = 0; + if (ConfIsRun3) { + if constexpr (useCentrality) { + if constexpr (analysePbPb) { + mult = col.centFT0C(); + } else { + mult = col.centFT0M(); + } + } else { + mult = 0; + } + multNtr = col.multNTracksPV(); + } else { + mult = 1; // multiplicity percentile is know in Run 2 + multNtr = col.multTracklets(); + } + + colCuts.fillQA(col, mult); + + // check whether the basic event selection criteria are fulfilled + // that included checking if there is at least on usable track or V0 + if (!colCuts.isSelectedCollision(col)) { + return; + } + bool emptyCollision = false; + if (ConfIsActivateCascade.value) { + if (colCuts.isEmptyCollision(col, tracks, trackCuts) && colCuts.isCollisionWithoutTrkCasc(col, fullCascades, cascadeCuts, tracks)) { + emptyCollision = true; + } + } + if (ConfIsActivateV0.value) { + if (colCuts.isEmptyCollision(col, tracks, trackCuts) && colCuts.isEmptyCollision(col, fullV0s, v0Cuts, tracks)) { + emptyCollision = true; + } + } else { + if (colCuts.isEmptyCollision(col, tracks, trackCuts)) { + emptyCollision = true; + } + } + if (emptyCollision) { + return; + } + + outputCollision(vtxZ, mult, multNtr, spher, mMagField); + if constexpr (isMC) { + fillMCCollision(col); + } + + std::vector childIDs = {0, 0}; // these IDs are necessary to keep track of the children + std::vector cascadechildIDs = {0, 0, 0}; // these IDs are necessary to keep track of the children + std::vector tmpIDtrack; // this vector keeps track of the matching of the primary track table row <-> aod::track table global index + std::vector Daughter1, Daughter2; + + for (auto& track : tracksWithItsPid) { + /// if the most open selection criteria are not fulfilled there is no + /// point looking further at the track + trackCuts.fillQA(track); + + if (track.tpcChi2NCl() < OptionTrackSpecialSelections.ConfTrkMinChi2PerClusterTPC || track.tpcChi2NCl() > OptionTrackSpecialSelections.ConfTrkMaxChi2PerClusterTPC) { + continue; + } + if (track.itsChi2NCl() > OptionTrackSpecialSelections.ConfTrkMaxChi2PerClusterITS) { + continue; + } + if ((OptionTrackSpecialSelections.ConfTrkTPCRefit && !track.hasTPC()) || (OptionTrackSpecialSelections.ConfTrkITSRefit && !track.hasITS())) { + continue; + } + + if (!trackCuts.isSelectedMinimal(track)) { + continue; + } + + TrackRegistry.fill(HIST("AnalysisQA/Chi2ITSTPCperCluster"), track.itsChi2NCl(), track.tpcChi2NCl()); + TrackRegistry.fill(HIST("AnalysisQA/RefitITSTPC"), track.hasITS(), track.hasTPC()); + + trackCuts.fillQA(track); + // the bit-wise container of the systematic variations is obtained + std::array cutContainer; + cutContainer = trackCuts.getCutContainer(track, track.pt(), track.eta(), sqrtf(powf(track.dcaXY(), 2.f) + powf(track.dcaZ(), 2.f))); + + // now the table is filled + outputParts(outputCollision.lastIndex(), + track.pt(), + track.eta(), + track.phi(), + aod::femtodreamparticle::ParticleType::kTrack, + cutContainer.at(femtoDreamTrackSelection::TrackContainerPosition::kCuts), + cutContainer.at(femtoDreamTrackSelection::TrackContainerPosition::kPID), + track.dcaXY(), childIDs, 0, 0); + tmpIDtrack.push_back(track.globalIndex()); + if (ConfIsDebug.value) { + fillDebugParticle(track); + } + + if constexpr (isMC) { + fillMCParticle(col, track, o2::aod::femtodreamparticle::ParticleType::kTrack); + } + + if (ConfIsActivateReso.value) { + // Already strict cuts for Daughter of reso selection + // TO DO: change TTV0 task to apply there the strict selection and have here only loose selection + + // select daugher 1 + if (track.sign() == ConfDaughterCharge.value[0] && track.pt() <= ConfDaughterPtUp.value[0] && track.pt() >= ConfDaughterPtLow.value[0] && std::abs(track.eta()) <= ConfDaughterEta.value[0] && std::abs(track.dcaXY()) <= ConfDaughterDCAxy.value[0] && std::abs(track.dcaZ()) <= ConfDaughterDCAz.value[0] && track.tpcNClsCrossedRows() >= ConfDaughterNCrossed.value[0] && track.tpcNClsFound() >= ConfDaughterNClus.value[0] && track.tpcCrossedRowsOverFindableCls() >= ConfDaughterTPCfCls.value[0]) { + if ((track.tpcInnerParam() < ConfDaughterPTPCThr.value[0] && std::abs(o2::aod::pidutils::tpcNSigma(ConfDaughterPIDspecies.value[0], track)) <= ConfDaughterPIDnSigmaMax.value[0]) || + (track.tpcInnerParam() >= ConfDaughterPTPCThr.value[0] && std::abs(std::sqrt(o2::aod::pidutils::tpcNSigma(ConfDaughterPIDspecies.value[0], track) * o2::aod::pidutils::tpcNSigma(ConfDaughterPIDspecies.value[0], track) + o2::aod::pidutils::tofNSigma(ConfDaughterPIDspecies.value[0], track) * o2::aod::pidutils::tofNSigma(ConfDaughterPIDspecies.value[0], track))) <= ConfDaughterPIDnSigmaMax.value[0])) { + Daughter1.push_back(track); + ResoRegistry.fill(HIST("AnalysisQA/Reso/Daughter1/Pt"), track.pt()); + ResoRegistry.fill(HIST("AnalysisQA/Reso/Daughter1/Eta"), track.eta()); + ResoRegistry.fill(HIST("AnalysisQA/Reso/Daughter1/Phi"), track.phi()); + } + } + // select daugher 2 + if (track.sign() == ConfDaughterCharge.value[1] && track.pt() <= ConfDaughterPtUp.value[1] && track.pt() >= ConfDaughterPtLow.value[1] && std::abs(track.eta()) <= ConfDaughterEta.value[1] && std::abs(track.dcaXY()) <= ConfDaughterDCAxy.value[1] && std::abs(track.dcaZ()) <= ConfDaughterDCAz.value[1] && track.tpcNClsCrossedRows() >= ConfDaughterNCrossed.value[1] && track.tpcNClsFound() >= ConfDaughterNClus.value[1] && track.tpcCrossedRowsOverFindableCls() >= ConfDaughterTPCfCls.value[1]) { + if ((track.tpcInnerParam() < ConfDaughterPTPCThr.value[1] && std::abs(o2::aod::pidutils::tpcNSigma(ConfDaughterPIDspecies.value[1], track)) <= ConfDaughterPIDnSigmaMax.value[1]) || + (track.tpcInnerParam() >= ConfDaughterPTPCThr.value[1] && std::abs(std::sqrt(o2::aod::pidutils::tpcNSigma(ConfDaughterPIDspecies.value[1], track) * o2::aod::pidutils::tpcNSigma(ConfDaughterPIDspecies.value[1], track) + o2::aod::pidutils::tofNSigma(ConfDaughterPIDspecies.value[1], track) * o2::aod::pidutils::tofNSigma(ConfDaughterPIDspecies.value[1], track))) <= ConfDaughterPIDnSigmaMax.value[1])) { + Daughter2.push_back(track); + ResoRegistry.fill(HIST("AnalysisQA/Reso/Daughter2/Pt"), track.pt()); + ResoRegistry.fill(HIST("AnalysisQA/Reso/Daughter2/Eta"), track.eta()); + ResoRegistry.fill(HIST("AnalysisQA/Reso/Daughter2/Phi"), track.phi()); + } + } + } + } + + if (ConfIsActivateV0.value) { + for (auto& v0 : fullV0s) { + + auto postrack = v0.template posTrack_as(); + auto negtrack = v0.template negTrack_as(); + ///\tocheck funnily enough if we apply the filter the + /// sign of Pos and Neg track is always negative + // const auto dcaXYpos = postrack.dcaXY(); + // const auto dcaZpos = postrack.dcaZ(); + // const auto dcapos = std::sqrt(pow(dcaXYpos, 2.) + pow(dcaZpos, 2.)); + v0Cuts.fillLambdaQA(col, v0, postrack, negtrack); + + if (!v0Cuts.isSelectedMinimal(col, v0, postrack, negtrack)) { + continue; + } + + // if (ConfRejectITSHitandTOFMissing) { + // Uncomment only when TOF timing is solved + // bool itsHit = o2PhysicsTrackSelection->IsSelected(postrack, + // TrackSelection::TrackCuts::kITSHits); bool itsHit = + // o2PhysicsTrackSelection->IsSelected(negtrack, + // TrackSelection::TrackCuts::kITSHits); + // } + + v0Cuts.fillQA(col, v0, postrack, negtrack); ///\todo fill QA also for daughters + auto cutContainerV0 = v0Cuts.getCutContainer(col, v0, postrack, negtrack); + + int postrackID = v0.posTrackId(); + int rowInPrimaryTrackTablePos = -1; + rowInPrimaryTrackTablePos = getRowDaughters(postrackID, tmpIDtrack); + childIDs[0] = rowInPrimaryTrackTablePos; + childIDs[1] = 0; + outputParts(outputCollision.lastIndex(), + v0.positivept(), v0.positiveeta(), v0.positivephi(), + aod::femtodreamparticle::ParticleType::kV0Child, + cutContainerV0.at(femtoDreamV0Selection::V0ContainerPosition::kPosCuts), + cutContainerV0.at(femtoDreamV0Selection::V0ContainerPosition::kPosPID), + postrack.dcaXY(), + childIDs, + 0, + 0); + const int rowOfPosTrack = outputParts.lastIndex(); + if constexpr (isMC) { + fillMCParticle(col, postrack, o2::aod::femtodreamparticle::ParticleType::kV0Child); + } + int negtrackID = v0.negTrackId(); + int rowInPrimaryTrackTableNeg = -1; + rowInPrimaryTrackTableNeg = getRowDaughters(negtrackID, tmpIDtrack); + childIDs[0] = 0; + childIDs[1] = rowInPrimaryTrackTableNeg; + outputParts(outputCollision.lastIndex(), + v0.negativept(), + v0.negativeeta(), + v0.negativephi(), + aod::femtodreamparticle::ParticleType::kV0Child, + cutContainerV0.at(femtoDreamV0Selection::V0ContainerPosition::kNegCuts), + cutContainerV0.at(femtoDreamV0Selection::V0ContainerPosition::kNegPID), + negtrack.dcaXY(), + childIDs, + 0, + 0); + const int rowOfNegTrack = outputParts.lastIndex(); + if constexpr (isMC) { + fillMCParticle(col, negtrack, o2::aod::femtodreamparticle::ParticleType::kV0Child); + } + std::vector indexChildID = {rowOfPosTrack, rowOfNegTrack}; + outputParts(outputCollision.lastIndex(), + v0.pt(), + v0.eta(), + v0.phi(), + aod::femtodreamparticle::ParticleType::kV0, + cutContainerV0.at(femtoDreamV0Selection::V0ContainerPosition::kV0), + 0, + v0.v0cosPA(), + indexChildID, + v0.mLambda(), + v0.mAntiLambda()); + if (ConfIsDebug.value) { + fillDebugParticle(postrack); // QA for positive daughter + fillDebugParticle(negtrack); // QA for negative daughter + fillDebugParticle(v0); // QA for v0 + } + if constexpr (isMC) { + fillMCParticle(col, v0, o2::aod::femtodreamparticle::ParticleType::kV0); + } + } + } + if (ConfIsActivateCascade.value) { + for (auto& casc : fullCascades) { + // get the daughter tracks + const auto& posTrackCasc = casc.template posTrack_as(); + const auto& negTrackCasc = casc.template negTrack_as(); + const auto& bachTrackCasc = casc.template bachelor_as(); + + cascadeCuts.fillQA<0, aod::femtodreamparticle::ParticleType::kCascade>(col, casc, posTrackCasc, negTrackCasc, bachTrackCasc); + if (!cascadeCuts.isSelectedMinimal(col, casc, posTrackCasc, negTrackCasc, bachTrackCasc)) { + continue; + } + cascadeCuts.fillQA<1, aod::femtodreamparticle::ParticleType::kCascade>(col, casc, posTrackCasc, negTrackCasc, bachTrackCasc); + + // auto cutContainerCasc = cascadeCuts.getCutContainer(col, casc, v0daugh, posTrackCasc, negTrackCasc, bachTrackCasc); + auto cutContainerCasc = cascadeCuts.getCutContainer(col, casc, posTrackCasc, negTrackCasc, bachTrackCasc); + + // Fill positive child + int poscasctrackID = casc.posTrackId(); + int rowInPrimaryTrackTablePosCasc = -1; + rowInPrimaryTrackTablePosCasc = getRowDaughters(poscasctrackID, tmpIDtrack); + cascadechildIDs[0] = rowInPrimaryTrackTablePosCasc; + cascadechildIDs[1] = 0; + cascadechildIDs[2] = 0; + outputParts(outputCollision.lastIndex(), + posTrackCasc.pt(), + posTrackCasc.eta(), + posTrackCasc.phi(), + aod::femtodreamparticle::ParticleType::kCascadeV0Child, + cutContainerCasc.at(femtoDreamCascadeSelection::CascadeContainerPosition::kPosCuts), + cutContainerCasc.at(femtoDreamCascadeSelection::CascadeContainerPosition::kPosPID), + posTrackCasc.dcaXY(), + cascadechildIDs, + 0, + 0); + const int rowOfPosCascadeTrack = outputParts.lastIndex(); + // TODO: include here MC filling + //------ + + // Fill negative child + int negcasctrackID = casc.negTrackId(); + int rowInPrimaryTrackTableNegCasc = -1; + rowInPrimaryTrackTableNegCasc = getRowDaughters(negcasctrackID, tmpIDtrack); + cascadechildIDs[0] = 0; + cascadechildIDs[1] = rowInPrimaryTrackTableNegCasc; + cascadechildIDs[2] = 0; + outputParts(outputCollision.lastIndex(), + negTrackCasc.pt(), + negTrackCasc.eta(), + negTrackCasc.phi(), + aod::femtodreamparticle::ParticleType::kCascadeV0Child, + cutContainerCasc.at(femtoDreamCascadeSelection::CascadeContainerPosition::kNegCuts), + cutContainerCasc.at(femtoDreamCascadeSelection::CascadeContainerPosition::kNegPID), + negTrackCasc.dcaXY(), + cascadechildIDs, + 0, + 0); + const int rowOfNegCascadeTrack = outputParts.lastIndex(); + // TODO: include here MC filling + //------ + + // Fill bachelor child + int bachelorcasctrackID = casc.bachelorId(); + int rowInPrimaryTrackTableBachelorCasc = -1; + rowInPrimaryTrackTableBachelorCasc = getRowDaughters(bachelorcasctrackID, tmpIDtrack); + cascadechildIDs[0] = 0; + cascadechildIDs[1] = 0; + cascadechildIDs[2] = rowInPrimaryTrackTableBachelorCasc; + outputParts(outputCollision.lastIndex(), + bachTrackCasc.pt(), + bachTrackCasc.eta(), + bachTrackCasc.phi(), + aod::femtodreamparticle::ParticleType::kCascadeBachelor, + cutContainerCasc.at(femtoDreamCascadeSelection::CascadeContainerPosition::kBachCuts), + cutContainerCasc.at(femtoDreamCascadeSelection::CascadeContainerPosition::kBachPID), + bachTrackCasc.dcaXY(), + cascadechildIDs, + 0, + 0); + const int rowOfBachelorCascadeTrack = outputParts.lastIndex(); + // TODO: include here MC filling + //------ + + // Fill cascades + std::vector indexCascadeChildID = {rowOfPosCascadeTrack, rowOfNegCascadeTrack, rowOfBachelorCascadeTrack}; + outputParts(outputCollision.lastIndex(), + casc.pt(), + casc.eta(), + casc.phi(), + aod::femtodreamparticle::ParticleType::kCascade, + cutContainerCasc.at(femtoDreamCascadeSelection::CascadeContainerPosition::kCascade), + 0, + casc.casccosPA(col.posX(), col.posY(), col.posZ()), + indexCascadeChildID, + casc.mXi(), + casc.mLambda()); + // TODO: include here MC filling + //------ + + if (ConfIsDebug.value) { + fillDebugParticle(posTrackCasc); // QA for positive daughter + fillDebugParticle(negTrackCasc); // QA for negative daughter + fillDebugParticle(bachTrackCasc); // QA for negative daughter + fillDebugCascade(casc, col); // QA for Cascade + } + } + } + + if (ConfIsActivateReso.value) { + for (std::size_t iDaug1 = 0; iDaug1 < Daughter1.size(); ++iDaug1) { + for (std::size_t iDaug2 = 0; iDaug2 < Daughter2.size(); ++iDaug2) { + // MC stuff is still missing, also V0 QA + // ALSO: fix indices and other table entries which are now set to 0 as deflaut as not needed for p-p-phi cf ana + + ROOT::Math::PtEtaPhiMVector tempD1(Daughter1.at(iDaug1).pt(), Daughter1.at(iDaug1).eta(), Daughter1.at(iDaug1).phi(), ConfDaug1Daugh2ResoMass.value[0]); + ROOT::Math::PtEtaPhiMVector tempD2(Daughter2.at(iDaug2).pt(), Daughter2.at(iDaug2).eta(), Daughter2.at(iDaug2).phi(), ConfDaug1Daugh2ResoMass.value[1]); + + ROOT::Math::PtEtaPhiMVector tempPhi = tempD1 + tempD2; + + ResoRegistry.fill(HIST("AnalysisQA/Reso/InvMass"), tempPhi.M()); + + if ((tempPhi.M() >= ConfResoInvMassLowLimit.value) && (tempPhi.M() <= ConfResoInvMassUpLimit.value)) { + + ResoRegistry.fill(HIST("AnalysisQA/Reso/InvMass_selected"), tempPhi.M()); + ResoRegistry.fill(HIST("AnalysisQA/Reso/PtD1_selected"), Daughter1.at(iDaug1).pt()); + ResoRegistry.fill(HIST("AnalysisQA/Reso/PtD2_selected"), Daughter2.at(iDaug2).pt()); + + childIDs[0] = 0; + childIDs[1] = 0; + std::vector indexChildID = {0, 0}; + outputParts(outputCollision.lastIndex(), + static_cast(Daughter1.at(iDaug1).pt()), static_cast(Daughter1.at(iDaug1).eta()), static_cast(Daughter1.at(iDaug1).phi()), + aod::femtodreamparticle::ParticleType::kV0Child, + static_cast(0), + static_cast(0), + static_cast(Daughter1.at(iDaug1).dcaXY()), + childIDs, + 0, + 0); + outputParts(outputCollision.lastIndex(), + static_cast(Daughter2.at(iDaug2).pt()), static_cast(Daughter2.at(iDaug2).eta()), static_cast(Daughter2.at(iDaug2).phi()), + aod::femtodreamparticle::ParticleType::kV0Child, + static_cast(0), + static_cast(0), + static_cast(Daughter2.at(iDaug2).dcaXY()), + childIDs, + 0, + 0); + outputParts(outputCollision.lastIndex(), + static_cast(tempPhi.pt()), + static_cast(tempPhi.eta()), + static_cast(tempPhi.phi()), + aod::femtodreamparticle::ParticleType::kV0, + static_cast(0), + 0, + 0.f, + indexChildID, + tempPhi.M(), + tempPhi.M()); + if (ConfIsDebug.value) { + fillDebugParticle(Daughter1.at(iDaug1)); // QA for positive daughter + fillDebugParticle(Daughter2.at(iDaug2)); // QA for negative daughter + outputDebugParts(-999., // sign + -999., -999., -999., -999., -999., -999., -999., -999., -999., // track properties (DCA, NCls, crossed rows, etc.) + -999., -999., -999., -999., -999., -999., -999., -999., // TPC PID (TPC signal + particle hypothesis) + -999., -999., -999., -999., -999., -999., -999., // TOF PID + -999., -999., -999., -999., -999., -999., -999., -999., // ITS PID + -999., -999., -999., -999., -999., -999., // V0 properties + -999., -999., -999., -999., -999., -999., -999.); // Cascade properties + } + } + } + } + } + } + + void + processData(aod::FemtoFullCollision const& col, + aod::BCsWithTimestamps const&, + aod::FemtoFullTracks const& tracks, + o2::aod::V0Datas const& fullV0s, + o2::aod::V0sLinked const&, + o2::aod::CascDatas const& fullCascades) + { + // get magnetic field for run + initCCDB_Mag_Trig(col.bc_as()); + // fill the tables + auto tracksWithItsPid = soa::Attach(tracks); + if (ConfUseItsPid.value) { + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracksWithItsPid, fullV0s, fullCascades); + } else { + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracks, fullV0s, fullCascades); + } + } + PROCESS_SWITCH(femtoDreamProducerTaskWithCascades, processData, + "Provide experimental data", true); + + void + processData_noCentrality(aod::FemtoFullCollision_noCent const& col, + aod::BCsWithTimestamps const&, + aod::FemtoFullTracks const& tracks, + o2::aod::V0Datas const& fullV0s, + o2::aod::V0sLinked const&, + o2::aod::CascDatas const& fullCascades) + { + // get magnetic field for run + initCCDB_Mag_Trig(col.bc_as()); + // fill the tables + auto tracksWithItsPid = soa::Attach(tracks); + if (ConfUseItsPid.value) { + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracksWithItsPid, fullV0s, fullCascades); + } else { + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracks, fullV0s, fullCascades); + } + } + PROCESS_SWITCH(femtoDreamProducerTaskWithCascades, processData_noCentrality, + "Provide experimental data without centrality information", false); + + void processData_CentPbPb(aod::FemtoFullCollision_CentPbPb const& col, + aod::BCsWithTimestamps const&, + aod::FemtoFullTracks const& tracks, + o2::aod::V0Datas const& fullV0s, + o2::aod::CascDatas const& fullCascades) + { + // get magnetic field for run + initCCDB_Mag_Trig(col.bc_as()); + // fill the tables + auto tracksWithItsPid = soa::Attach(tracks); + if (ConfUseItsPid.value) { + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracksWithItsPid, fullV0s, fullCascades); + } else { + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracks, fullV0s, fullCascades); + } + } + PROCESS_SWITCH(femtoDreamProducerTaskWithCascades, processData_CentPbPb, + "Provide experimental data with centrality information for PbPb collisions", false); + + void processMC(aod::FemtoFullCollisionMC const& col, + aod::BCsWithTimestamps const&, + soa::Join const& tracks, + aod::FemtoFullMCgenCollisions const&, + aod::McParticles const&, + soa::Join const& fullV0s, /// \todo with FilteredFullV0s + soa::Join const& fullCascades) + { + // get magnetic field for run + initCCDB_Mag_Trig(col.bc_as()); + // fill the tables + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracks, fullV0s, fullCascades); + } + PROCESS_SWITCH(femtoDreamProducerTaskWithCascades, processMC, "Provide MC data", false); + + void processMC_noCentrality(aod::FemtoFullCollision_noCent_MC const& col, + aod::BCsWithTimestamps const&, + soa::Join const& tracks, + aod::FemtoFullMCgenCollisions const&, + aod::McParticles const&, + soa::Join const& fullV0s, /// \todo with FilteredFullV0s + soa::Join const& fullCascades) + { + // get magnetic field for run + initCCDB_Mag_Trig(col.bc_as()); + // fill the tables + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracks, fullV0s, fullCascades); + } + PROCESS_SWITCH(femtoDreamProducerTaskWithCascades, processMC_noCentrality, "Provide MC data without requiring a centrality calibration", false); + + void processMC_CentPbPb(aod::FemtoFullCollisionMC_CentPbPb const& col, + aod::BCsWithTimestamps const&, + soa::Join const& tracks, + aod::FemtoFullMCgenCollisions const&, + aod::McParticles const&, + soa::Join const& fullV0s, /// \todo with FilteredFullV0s + soa::Join const& fullCascades) + { + // get magnetic field for run + initCCDB_Mag_Trig(col.bc_as()); + // fill the tables + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracks, fullV0s, fullCascades); + } + PROCESS_SWITCH(femtoDreamProducerTaskWithCascades, processMC_CentPbPb, "Provide MC data with centrality information for PbPb collisions", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/PWGCF/FemtoDream/Tasks/CMakeLists.txt b/PWGCF/FemtoDream/Tasks/CMakeLists.txt index 58d9744c029..b0175157386 100644 --- a/PWGCF/FemtoDream/Tasks/CMakeLists.txt +++ b/PWGCF/FemtoDream/Tasks/CMakeLists.txt @@ -24,6 +24,11 @@ o2physics_add_dpl_workflow(femtodream-pair-track-v0 PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(femtodream-pair-track-cascade + SOURCES femtoDreamPairTaskTrackCascade.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(femtodream-triplet-track-track-v0 SOURCES femtoDreamTripletTaskTrackTrackV0.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore @@ -39,6 +44,11 @@ o2physics_add_dpl_workflow(femtodream-debug-v0 PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(femtodream-debug-cascade + SOURCES femtoDreamDebugCascade.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(femtodream-collision-masker SOURCES femtoDreamCollisionMasker.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamCollisionMasker.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamCollisionMasker.cxx index 62f2f4c3967..218c69d9699 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamCollisionMasker.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamCollisionMasker.cxx @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -76,6 +77,7 @@ struct femoDreamCollisionMasker { // bits indicate number of particles in the event // kPartOne -> 1 track, kPartTwo -> 2 tracks, kPartThree -> 3 tracks std::vector TrackSameSpecies; + std::vector TrackDCACutPtDep; // particle selection for v0 std::array, CollisionMasks::kNParts> V0CutBits; @@ -178,6 +180,8 @@ struct femoDreamCollisionMasker { FilterTempFitVarMax.at(CollisionMasks::kPartTwo).push_back(option.defaultValue.get()); } else if (option.name.compare(std::string("Option.SameSpecies")) == 0) { TrackSameSpecies.push_back(option.defaultValue.get()); + } else if (option.name.compare(std::string("Option.DCACutPtDep")) == 0) { + TrackDCACutPtDep.push_back(option.defaultValue.get()); } } } else if (device.name.find(std::string("femto-dream-pair-task-track-v0")) != std::string::npos) { @@ -188,7 +192,9 @@ struct femoDreamCollisionMasker { counter++; TaskFinder = CollisionMasks::kTrackV0; for (auto const& option : device.options) { - if (option.name.compare(std::string("Track1.CutBit")) == 0) { + if (option.name.compare(std::string("Option.DCACutPtDep")) == 0) { + TrackDCACutPtDep.push_back(option.defaultValue.get()); + } else if (option.name.compare(std::string("Track1.CutBit")) == 0) { TrackCutBits.at(CollisionMasks::kPartOne).push_back(option.defaultValue.get()); } else if (option.name.compare(std::string("Track1.TPCBit")) == 0) { TrackPIDTPCBits.at(CollisionMasks::kPartOne).push_back(option.defaultValue.get()); @@ -258,6 +264,8 @@ struct femoDreamCollisionMasker { FilterTempFitVarMax.at(CollisionMasks::kPartOne).push_back(option.defaultValue.get()); } else if (option.name.compare(std::string("ConfMinDCAxy")) == 0) { FilterTempFitVarMin.at(CollisionMasks::kPartOne).push_back(option.defaultValue.get()); + } else if (option.name.compare(std::string("ConfDCACutPtDep")) == 0) { + TrackDCACutPtDep.push_back(option.defaultValue.get()); } } } else if (device.name.find("femto-dream-triplet-task-track-track-v0") != std::string::npos) { @@ -302,6 +310,8 @@ struct femoDreamCollisionMasker { FilterPtMin.at(CollisionMasks::kPartThree).push_back(option.defaultValue.get()); } else if (option.name.compare(std::string("Conf_maxPt_V0")) == 0) { FilterPtMax.at(CollisionMasks::kPartThree).push_back(option.defaultValue.get()); + } else if (option.name.compare(std::string("ConfDCACutPtDep")) == 0) { + TrackDCACutPtDep.push_back(option.defaultValue.get()); } } } @@ -316,20 +326,31 @@ struct femoDreamCollisionMasker { } // make bitmask for a track for two body task - template - void MaskForTrack(T& BitSet, CollisionMasks::Parts P, R& track) + template + void MaskForTrack(T& BitSet, CollisionMasks::Parts P, R& track, S& counter) { if (track.partType() != static_cast(femtodreamparticle::kTrack)) { return; } for (size_t index = 0; index < TrackCutBits.at(P).size(); index++) { // check filter cuts + // if they are not passed, skip the particle if (track.pt() < FilterPtMin.at(P).at(index) || track.pt() > FilterPtMax.at(P).at(index) || - track.eta() < FilterEtaMin.at(P).at(index) || track.eta() > FilterEtaMax.at(P).at(index) || - track.tempFitVar() < FilterTempFitVarMin.at(P).at(index) || track.tempFitVar() > FilterTempFitVarMax.at(P).at(index)) { - // if they are not passed, skip the particle + track.eta() < FilterEtaMin.at(P).at(index) || track.eta() > FilterEtaMax.at(P).at(index)) { continue; } + // check if we apply pt dependend dca cut + // if they do not pass this cut, skip particle as well + if (TrackDCACutPtDep.at(index)) { + if (std::fabs(track.tempFitVar()) > 0.0105f + (0.035f / std::pow(track.pt(), 1.1f))) { + continue; + } + } else { + // or cut on the DCA directly + if (track.tempFitVar() < FilterTempFitVarMin.at(P).at(index) || track.tempFitVar() > FilterTempFitVarMax.at(P).at(index)) { + continue; + } + } // set the bit at the index of the selection equal to one if the track passes all selections // check track cuts if ((track.cut() & TrackCutBits.at(P).at(index)) == TrackCutBits.at(P).at(index)) { @@ -337,10 +358,12 @@ struct femoDreamCollisionMasker { if (track.p() <= TrackPIDThreshold.at(P).at(index)) { if ((track.pidcut() & TrackPIDTPCBits.at(P).at(index)) == TrackPIDTPCBits.at(P).at(index) && ((track.pidcut() & TrackPIDTPCBitsReject.at(P).at(index)) == 0u)) { BitSet.at(P).set(index); + counter.at(P).at(index)++; } } else { if ((track.pidcut() & TrackPIDTPCTOFBits.at(P).at(index)) == TrackPIDTPCTOFBits.at(P).at(index)) { BitSet.at(P).set(index); + counter.at(P).at(index)++; } } } @@ -369,12 +392,24 @@ struct femoDreamCollisionMasker { if (track.partType() != static_cast(femtodreamparticle::kTrack)) { continue; } + // check filter cuts - if (track.pt() < FilterPtMin.at(P).at(index) || track.pt() > FilterPtMax.at(P).at(index) || - track.tempFitVar() > FilterTempFitVarMax.at(P).at(index) || track.tempFitVar() < FilterTempFitVarMin.at(P).at(index)) { + if (track.pt() < FilterPtMin.at(P).at(index) || track.pt() > FilterPtMax.at(P).at(index)) { // if they are not passed, skip the particle continue; } + + if (TrackDCACutPtDep.at(index)) { + if (std::fabs(track.tempFitVar()) > 0.0105f + (0.035f / std::pow(track.pt(), 1.1f))) { + continue; + } + } else { + // or cut on the DCA directly + if (track.tempFitVar() < FilterTempFitVarMin.at(P).at(index) || track.tempFitVar() > FilterTempFitVarMax.at(P).at(index)) { + continue; + } + } + // set the bit at the index of the selection equal to one if the track passes all selections // check track cuts if ((track.cut() & TrackCutBits.at(P).at(index)) == TrackCutBits.at(P).at(index)) { @@ -515,20 +550,34 @@ struct femoDreamCollisionMasker { // create a bit mask for particle one, particle two and particle three std::array, CollisionMasks::kNParts> Mask = {{0}}; + // array to keep track of found particles + std::array, CollisionMasks::kNParts> FoundParts = {{{0}}}; + switch (TaskFinder) { case CollisionMasks::kTrackTrack: // pair-track-track task // create mask for track 1 and track 2 for (auto const& part : parts) { - MaskForTrack(Mask, CollisionMasks::kPartOne, part); - MaskForTrack(Mask, CollisionMasks::kPartTwo, part); + MaskForTrack(Mask, CollisionMasks::kPartOne, part, FoundParts); + MaskForTrack(Mask, CollisionMasks::kPartTwo, part, FoundParts); + } + // check if SameSpecies option is set + // if so, only set the bit for kPartTwo to true if there are at least to tracks in the collision that pass the selections + // this allows to (optionally) select only events with at least two particles for the mixing + for (size_t index = 0; index < TrackSameSpecies.size(); index++) { + if (TrackSameSpecies.at(index) == true) { + Mask.at(CollisionMasks::kPartTwo).reset(index); + if (FoundParts.at(CollisionMasks::kPartOne).at(index) >= 2) { + Mask.at(CollisionMasks::kPartTwo).set(index); + } + } } break; case CollisionMasks::kTrackV0: // pair-track-v0 task // create mask for track 1 and v0 2 for (auto const& part : parts) { - MaskForTrack(Mask, CollisionMasks::kPartOne, part); + MaskForTrack(Mask, CollisionMasks::kPartOne, part, FoundParts); MaskForV0(Mask, CollisionMasks::kPartTwo, part, parts); } break; @@ -545,7 +594,7 @@ struct femoDreamCollisionMasker { break; // TODO: add all supported pair/triplet tasks default: - LOG(fatal) << "No femtodream pair task found!"; + LOG(fatal) << "No femtodream task found!"; } // fill bitmask for each collision Masks(static_cast(Mask.at(CollisionMasks::kPartOne).to_ulong()), diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamDebugCascade.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamDebugCascade.cxx new file mode 100644 index 00000000000..dd49096907e --- /dev/null +++ b/PWGCF/FemtoDream/Tasks/femtoDreamDebugCascade.cxx @@ -0,0 +1,188 @@ +// Copyright 2019-2022 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 femtoDreamDebugV0.cxx +/// \brief Tasks that reads the particle tables and fills QA histograms for V0s +/// \author Luca Barioglio, TU München, luca.barioglio@cern.ch +/// \author Georgios Mantzaridis, TU München, luca.barioglio@cern.ch + +#include +#include +#include +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "DataFormatsParameters/GRPObject.h" +#include "fairlogger/Logger.h" + +#include "PWGCF/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamEventHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamMath.h" +#include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" + +using namespace o2; +using namespace o2::analysis::femtoDream; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct femtoDreamDebugCascade { + SliceCache cache; + + Configurable ConfCascade_PDGCode{"ConfCascade_PDGCode", 3312, "Cascade - PDG code"}; + Configurable ConfCascade_ChildPos_PDGCode{"ConfCascade_PosChild_PDGCode", 2212, "Positive Child - PDG code"}; + Configurable ConfCascade_ChildNeg_PDGCode{"ConfCascade_NegChild_PDGCode", 211, "Negative Child- PDG code"}; + Configurable ConfCascade_Bach_PDGCode{"ConfCascade_Bach_PDGCode", 211, "Bachelor Child- PDG code"}; + + Configurable ConfCascade_CutBit{"ConfCascade_CutBit", 338, "Cascade - Selection bit from cutCulator"}; + ConfigurableAxis ConfCascadeTempFitVarBins{"ConfCascadeTempFitVarBins", {300, 0.95, 1.}, "Cascade: binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis ConfCascadeTempFitVarMomentumBins{"ConfCascadeTempFitVarMomentumBins", {20, 0.5, 4.05}, "Cascade: pT binning of the pT vs. TempFitVar plot"}; + ConfigurableAxis ConfBinmult{"ConfBinmult", {1, 0, 1}, "multiplicity Binning"}; + ConfigurableAxis ConfDummy{"ConfDummy", {1, 0, 1}, "Dummy axis for inv mass"}; + + Configurable ConfCascadeTempFitVarMomentum{"ConfCascadeTempFitVarMomentum", 0, "Momentum used for binning: 0 -> pt; 1 -> preco; 2 -> ptpc"}; + + ConfigurableAxis ConfCascadeInvMassBins{"ConfCascadeInvMassBins", {200, 1.25, 1.45}, "Cascade: InvMass binning"}; + ConfigurableAxis ConfCascadeInvMassCompetingBins{"ConfCascadeInvMassCompetingBins", {200, 1.57, 1.77}, "Cascade: InvMass binning of the competing candidate"}; + + ConfigurableAxis ConfCascadeChildTempFitVarMomentumBins{"ConfCascadeChildTempFitVarMomentumBins", {600, 0, 6}, "p binning for the p vs Nsigma TPC/TOF plot"}; + ConfigurableAxis ConfCascadeChildNsigmaTPCBins{"ConfCascadeChildNsigmaTPCBins", {1600, -8, 8}, "binning of Nsigma TPC plot"}; + ConfigurableAxis ConfCascadeChildNsigmaTOFBins{"ConfCascadeChildNsigmaTOFBins", {3000, -15, 15}, "binning of the Nsigma TOF plot"}; + ConfigurableAxis ConfCascadeChildNsigmaTPCTOFBins{"ConfCascadeChildNsigmaTPCTOFBins", {1000, 0, 10}, "binning of the Nsigma TPC+TOF plot"}; + + Configurable ConfCascade_ChildPos_CutBit{"ConfCascade_ChildPos_CutBit", 150, "Positive Child of Cascade - Selection bit from cutCulator"}; + Configurable ConfCascade_ChildPos_TPCBit{"ConfCascade_ChildPos_TPCBit", 4, "Positive Child of Cascade - PID bit from cutCulator"}; + Configurable ConfCascade_ChildNeg_CutBit{"ConfCascade_ChildNeg_CutBit", 149, "Negative Child of Cascade - PID bit from cutCulator"}; + Configurable ConfCascade_ChildNeg_TPCBit{"ConfCascade_ChildNeg_TPCBit", 8, "Negative Child of Cascade - PID bit from cutCulator"}; + Configurable ConfCascade_ChildBach_CutBit{"ConfCascade_ChildBach_CutBit", 149, "Bachelor Child of Cascade - PID bit from cutCulator"}; + Configurable ConfCascade_ChildBach_TPCBit{"ConfCascade_ChildBach_TPCBit", 8, "Bachelor Child of Cascade - PID bit from cutCulator"}; + Configurable ConfUseChildCuts{"ConfUseChildCuts", true, "Use cuts on the children of the Cascades additional to those of the selection of the cascade builder"}; + Configurable ConfUseChildPIDCuts{"ConfUseChildPIDCuts", true, "Use cuts on the children of the Cascades additional to those of the selection of the cascade builder"}; + + Configurable ConfIsOmega{"ConfIsOmega", false, "Switch between Xi and Omaga Cascades: If true: Omega; else: Xi"}; + Configurable ConfRejectCompetingMass{"ConfRejectCompetingMass", false, "Reject the competing Cascade Mass (use only for debugging. More efficient to exclude it already at the producer level)"}; + Configurable ConfCompetingCascadeMassLowLimit{"ConfCompetingCascadeMassLowLimit", 0., "Lower Limit of the invariant mass window within which to reject the cascade"}; + Configurable ConfCompetingCascadeMassUpLimit{"ConfCompetingCascadeMassUpLimit", 0., "Upper Limit of the invariant mass window within which to reject the cascade"}; + + ConfigurableAxis ConfCascadeChildTempFitVarBins{"ConfCascadeChildTempFitVarBins", {300, -0.15, 0.15}, "Cascade child: binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis ConfCascadeChildTempFitVarpTBins{"ConfCascadeChildTempFitVarpTBins", {20, 0.5, 4.05}, "Cascade child: pT binning of the pT vs. TempFitVar plot"}; + + using FemtoFullParticles = soa::Join; + Partition partsOne = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kCascade)) && (ncheckbit(aod::femtodreamparticle::cut, ConfCascade_CutBit)); + Preslice perCol = aod::femtodreamparticle::fdCollisionId; + + /// Histogramming + FemtoDreamEventHisto eventHisto; + FemtoDreamParticleHisto posChildHistos; + FemtoDreamParticleHisto negChildHistos; + FemtoDreamParticleHisto bachelorHistos; + FemtoDreamParticleHisto CascadeHistos; + + /// Histogram output + HistogramRegistry EventRegistry{"Event", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry CascadeRegistry{"FullCascQA", {}, OutputObjHandlingPolicy::AnalysisObject}; + + float massProton; + float massPion; + float massKaon; + float massLambda; + float massCompetingBach; + + void init(InitContext&) + { + eventHisto.init(&EventRegistry, false); + posChildHistos.init(&CascadeRegistry, ConfBinmult, ConfDummy, ConfCascadeChildTempFitVarMomentumBins, ConfDummy, ConfDummy, ConfCascadeChildTempFitVarBins, ConfCascadeChildNsigmaTPCBins, ConfCascadeChildNsigmaTOFBins, ConfCascadeChildNsigmaTPCTOFBins, ConfDummy, ConfCascadeInvMassBins, ConfCascadeInvMassCompetingBins, false, ConfCascade_ChildPos_PDGCode.value, true); + negChildHistos.init(&CascadeRegistry, ConfBinmult, ConfDummy, ConfCascadeChildTempFitVarMomentumBins, ConfDummy, ConfDummy, ConfCascadeChildTempFitVarBins, ConfCascadeChildNsigmaTPCBins, ConfCascadeChildNsigmaTOFBins, ConfCascadeChildNsigmaTPCTOFBins, ConfDummy, ConfCascadeInvMassBins, ConfCascadeInvMassCompetingBins, false, ConfCascade_ChildNeg_PDGCode.value, true); + bachelorHistos.init(&CascadeRegistry, ConfBinmult, ConfDummy, ConfCascadeChildTempFitVarMomentumBins, ConfDummy, ConfDummy, ConfCascadeChildTempFitVarBins, ConfCascadeChildNsigmaTPCBins, ConfCascadeChildNsigmaTOFBins, ConfCascadeChildNsigmaTPCTOFBins, ConfDummy, ConfCascadeInvMassBins, ConfCascadeInvMassCompetingBins, false, ConfCascade_Bach_PDGCode.value, true); + CascadeHistos.init(&CascadeRegistry, ConfBinmult, ConfDummy, ConfCascadeTempFitVarMomentumBins, ConfDummy, ConfDummy, ConfCascadeTempFitVarBins, ConfCascadeChildNsigmaTPCBins, ConfCascadeChildNsigmaTOFBins, ConfCascadeChildNsigmaTPCTOFBins, ConfDummy, ConfCascadeInvMassBins, ConfCascadeInvMassCompetingBins, false, ConfCascade_PDGCode.value, true); + + massProton = o2::analysis::femtoDream::getMass(2212); + massPion = o2::analysis::femtoDream::getMass(211); + massKaon = o2::analysis::femtoDream::getMass(321); + massLambda = o2::analysis::femtoDream::getMass(3122); + if (ConfIsOmega) { // if the Cascade is an Omega, then the bachelor is a Kaon + massCompetingBach = o2::analysis::femtoDream::getMass(211); + } else { // if the Cascade is a Xi, then the bachelor is a Pion + massCompetingBach = o2::analysis::femtoDream::getMass(321); + } + } + + /// Porduce QA plots for V0 selection in FemtoDream framework + void process(o2::aod::FDCollision const& col, FemtoFullParticles const& parts) + { + auto groupPartsOne = partsOne->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + eventHisto.fillQA(col); + for (auto& part : groupPartsOne) { + if (!part.has_children()) { + continue; + } + // check cut on v0 children + const auto& posChild = parts.iteratorAt(part.index() - 3); + const auto& negChild = parts.iteratorAt(part.index() - 2); + const auto& bachChild = parts.iteratorAt(part.index() - 1); + if (posChild.globalIndex() != part.childrenIds()[0] || negChild.globalIndex() != part.childrenIds()[1] || bachChild.globalIndex() != part.childrenIds()[2]) { + LOG(warn) << "Indices of V0 children do not match"; + continue; + } + // check cuts on V0 children + if (posChild.partType() == uint8_t(aod::femtodreamparticle::ParticleType::kCascadeV0Child) && + negChild.partType() == uint8_t(aod::femtodreamparticle::ParticleType::kCascadeV0Child) && + bachChild.partType() == uint8_t(aod::femtodreamparticle::ParticleType::kCascadeBachelor)) { + + if (ConfUseChildCuts) { + if (!((posChild.cut() & ConfCascade_ChildPos_CutBit) == ConfCascade_ChildPos_CutBit && + (negChild.cut() & ConfCascade_ChildNeg_CutBit) == ConfCascade_ChildNeg_CutBit && + (bachChild.cut() & ConfCascade_ChildBach_CutBit) == ConfCascade_ChildBach_CutBit)) { + continue; + } + } + if (ConfUseChildPIDCuts) { + if (!((posChild.pidcut() & ConfCascade_ChildPos_TPCBit) == ConfCascade_ChildPos_TPCBit && + (negChild.pidcut() & ConfCascade_ChildNeg_TPCBit) == ConfCascade_ChildNeg_TPCBit && + (bachChild.pidcut() & ConfCascade_ChildBach_TPCBit) == ConfCascade_ChildBach_TPCBit)) { + continue; + } + } + + // Competing mass rejection + if (ConfRejectCompetingMass) { + float invMassCompetingCasc; + if (part.sign() < 0) { + invMassCompetingCasc = FemtoDreamMath::getInvMassCascade(posChild, massProton, negChild, massPion, bachChild, massCompetingBach, massLambda); + } else { + invMassCompetingCasc = FemtoDreamMath::getInvMassCascade(posChild, massPion, negChild, massProton, bachChild, massCompetingBach, massLambda); + } + if (invMassCompetingCasc > ConfCompetingCascadeMassLowLimit.value && + invMassCompetingCasc < ConfCompetingCascadeMassUpLimit.value) { + continue; + } + } + CascadeHistos.fillQA(part, static_cast(ConfCascadeTempFitVarMomentum.value), col.multNtr(), col.multV0M()); + posChildHistos.fillQA(posChild, static_cast(ConfCascadeTempFitVarMomentum.value), col.multNtr(), col.multV0M()); + negChildHistos.fillQA(negChild, static_cast(ConfCascadeTempFitVarMomentum.value), col.multNtr(), col.multV0M()); + bachelorHistos.fillQA(bachChild, static_cast(ConfCascadeTempFitVarMomentum.value), col.multNtr(), col.multV0M()); + } + } + } +}; + +WorkflowSpec + defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamDebugTrack.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamDebugTrack.cxx index 27f6792b584..eb19d28486d 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamDebugTrack.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamDebugTrack.cxx @@ -45,8 +45,11 @@ struct femtoDreamDebugTrack { Configurable ConfTrk1_maxPt{"ConfTrk1_maxPt", 999., "Maximum pT of partricle 1 (Track)"}; Configurable ConfTrk1_minEta{"ConfTrk1_minEta", -10., "Minimum eta of partricle 1 (Track)"}; Configurable ConfTrk1_maxEta{"ConfTrk1_maxEta", 10., "Maximum eta of partricle 1 (Track)"}; + Configurable ConfTrk1_TempFitVarMin{"ConfTrk1_TempFitVarMin", -10., "Minimum DCAxy of partricle 1 (Track)"}; + Configurable ConfTrk1_TempFitVarMax{"ConfTrk1_TempFitVarMax", 10., "Maximum DCAxy of partricle 1 (Track)"}; Configurable ConfTrk1_PIDThres{"ConfTrk1_PIDThres", 0.75, "Particle 1 - Read from cutCulator"}; + Configurable ConfOptDCACutPtDep{"ConfOptDCACutPtDep", false, "Use pt dependent dca cut"}; Configurable ConfOptCorrelatedPlots{"ConfOptCorrelatedPlots", false, "Enable additional three dimensional histogramms. High memory consumption. Use for debugging"}; ConfigurableAxis ConfBinmult{"ConfBinmult", {1, 0, 1}, "multiplicity Binning"}; ConfigurableAxis ConfBinmultPercentile{"ConfBinmultPercentile", {10, 0.0f, 100.0f}, "multiplicity percentile Binning"}; @@ -58,6 +61,7 @@ struct femtoDreamDebugTrack { ConfigurableAxis ConfNsigmaTPCBins{"ConfNsigmaTPCBins", {1600, -8, 8}, "Binning of Nsigma TPC plot"}; ConfigurableAxis ConfNsigmaTOFBins{"ConfNsigmaTOFBins", {3000, -15, 15}, "Binning of the Nsigma TOF plot"}; ConfigurableAxis ConfNsigmaTPCTOFBins{"ConfNsigmaTPCTOFBins", {3000, -15, 15}, "Binning of the Nsigma TPC+TOF plot"}; + ConfigurableAxis ConfNsigmaITSBins{"ConfNsigmaITSBins", {3000, -15, 15}, "Binning of the Nsigma ITS plot"}; ConfigurableAxis ConfTPCclustersBins{"ConfTPCClustersBins", {163, -0.5, 162.5}, "Binning of TPC found clusters plot"}; Configurable ConfTempFitVarMomentum{"ConfTempFitVarMomentum", 0, "Momentum used for binning: 0 -> pt; 1 -> preco; 2 -> ptpc"}; ConfigurableAxis ConfDummy{"ConfDummy", {1, 0, 1}, "Dummy axis for inv mass"}; @@ -73,7 +77,11 @@ struct femtoDreamDebugTrack { (aod::femtodreamparticle::pt > ConfTrk1_minPt) && (aod::femtodreamparticle::pt < ConfTrk1_maxPt) && (aod::femtodreamparticle::eta > ConfTrk1_minEta) && - (aod::femtodreamparticle::eta < ConfTrk1_maxEta); + (aod::femtodreamparticle::eta < ConfTrk1_maxEta) && + ifnode(ConfOptDCACutPtDep, nabs(aod::femtodreamparticle::tempFitVar) < 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f)), + (aod::femtodreamparticle::tempFitVar > ConfTrk1_TempFitVarMin) && + (aod::femtodreamparticle::tempFitVar < ConfTrk1_TempFitVarMax)); + Preslice perColReco = aod::femtodreamparticle::fdCollisionId; // adsf using FemtoFullParticlesMC = soa::Join; @@ -94,7 +102,7 @@ struct femtoDreamDebugTrack { void init(InitContext&) { eventHisto.init(&qaRegistry, ConfIsMC); - trackHisto.init(&qaRegistry, ConfBinmult, ConfBinmultPercentile, ConfBinpT, ConfBineta, ConfBinphi, ConfTempFitVarBins, ConfNsigmaTPCBins, ConfNsigmaTOFBins, ConfNsigmaTPCTOFBins, ConfTPCclustersBins, ConfDummy, ConfIsMC, ConfTrk1_PDGCode.value, true, ConfOptCorrelatedPlots); + trackHisto.init(&qaRegistry, ConfBinmult, ConfBinmultPercentile, ConfBinpT, ConfBineta, ConfBinphi, ConfTempFitVarBins, ConfNsigmaTPCBins, ConfNsigmaTOFBins, ConfNsigmaTPCTOFBins, ConfNsigmaITSBins, ConfDummy, ConfDummy, ConfIsMC, ConfTrk1_PDGCode.value, true, ConfOptCorrelatedPlots); } /// Porduce QA plots for sigle track selection in FemtoDream framework @@ -122,7 +130,7 @@ struct femtoDreamDebugTrack { /// \param col subscribe to FemtoDreamCollision table /// \param parts subscribe to the joined table of FemtoDreamParticles and FemtoDreamMCLabels table /// \param FemtoDramMCParticles subscribe to the table containing the Monte Carlo Truth information - void processMC(FemtoMCCollision& col, o2::aod::FDMCCollisions&, FemtoFullParticlesMC& parts, aod::FDMCParticles&, aod::FDExtMCParticles&) + void processMC(FemtoMCCollision& col, o2::aod::FDMCCollisions&, FemtoFullParticlesMC& /*parts*/, aod::FDMCParticles&, aod::FDExtMCParticles&) { auto groupPartsOne = partsOneMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); FillDebugHistos(col, groupPartsOne); diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamDebugV0.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamDebugV0.cxx index 9f422751008..c20d2b2a445 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamDebugV0.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamDebugV0.cxx @@ -16,6 +16,9 @@ #include #include #include + +#include "TVector3.h" + #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" @@ -55,6 +58,7 @@ struct femtoDreamDebugV0 { ConfigurableAxis ConfV0ChildNsigmaTPCBins{"ConfV0ChildNsigmaTPCBins", {1600, -8, 8}, "binning of Nsigma TPC plot"}; ConfigurableAxis ConfV0ChildNsigmaTOFBins{"ConfV0ChildNsigmaTOFBins", {3000, -15, 15}, "binning of the Nsigma TOF plot"}; ConfigurableAxis ConfV0ChildNsigmaTPCTOFBins{"ConfV0ChildNsigmaTPCTOFBins", {1000, 0, 10}, "binning of the Nsigma TPC+TOF plot"}; + ConfigurableAxis ConfV0ChildNsigmaITSBins{"ConfV0ChildNsigmaITSBins", {600, -3, 3}, "binning of the Nsigma ITS plot"}; Configurable ConfV01_ChildPos_CutBit{"ConfV01_ChildPos_CutBit", 150, "Positive Child of V0 - Selection bit from cutCulator"}; Configurable ConfV01_ChildPos_TPCBit{"ConfV01_ChildPos_TPCBit", 4, "Positive Child of V0 - PID bit from cutCulator"}; @@ -80,9 +84,10 @@ struct femtoDreamDebugV0 { void init(InitContext&) { eventHisto.init(&EventRegistry, false); - posChildHistos.init(&V0Registry, ConfBinmult, ConfDummy, ConfV0ChildTempFitVarMomentumBins, ConfDummy, ConfDummy, ConfChildTempFitVarBins, ConfV0ChildNsigmaTPCBins, ConfV0ChildNsigmaTOFBins, ConfV0ChildNsigmaTPCTOFBins, ConfDummy, ConfV0InvMassBins, false, ConfV01_ChildPos_PDGCode.value, true); - negChildHistos.init(&V0Registry, ConfBinmult, ConfDummy, ConfV0ChildTempFitVarMomentumBins, ConfDummy, ConfDummy, ConfChildTempFitVarBins, ConfV0ChildNsigmaTPCBins, ConfV0ChildNsigmaTOFBins, ConfV0ChildNsigmaTPCTOFBins, ConfDummy, ConfV0InvMassBins, false, ConfV01_ChildNeg_PDGCode, true); - V0Histos.init(&V0Registry, ConfBinmult, ConfDummy, ConfV0TempFitVarMomentumBins, ConfDummy, ConfDummy, ConfV0TempFitVarBins, ConfV0ChildNsigmaTPCBins, ConfV0ChildNsigmaTOFBins, ConfV0ChildNsigmaTPCTOFBins, ConfDummy, ConfV0InvMassBins, false, ConfV01_PDGCode.value, true); + posChildHistos.init(&V0Registry, ConfBinmult, ConfDummy, ConfV0ChildTempFitVarMomentumBins, ConfDummy, ConfDummy, ConfChildTempFitVarBins, ConfV0ChildNsigmaTPCBins, ConfV0ChildNsigmaTOFBins, ConfV0ChildNsigmaTPCTOFBins, ConfV0ChildNsigmaITSBins, ConfV0InvMassBins, ConfDummy, false, ConfV01_ChildPos_PDGCode.value, true); + negChildHistos.init(&V0Registry, ConfBinmult, ConfDummy, ConfV0ChildTempFitVarMomentumBins, ConfDummy, ConfDummy, ConfChildTempFitVarBins, ConfV0ChildNsigmaTPCBins, ConfV0ChildNsigmaTOFBins, ConfV0ChildNsigmaTPCTOFBins, ConfV0ChildNsigmaITSBins, ConfV0InvMassBins, ConfDummy, false, ConfV01_ChildNeg_PDGCode, true); + V0Histos.init(&V0Registry, ConfBinmult, ConfDummy, ConfV0TempFitVarMomentumBins, ConfDummy, ConfDummy, ConfV0TempFitVarBins, ConfV0ChildNsigmaTPCBins, ConfV0ChildNsigmaTOFBins, ConfV0ChildNsigmaTPCTOFBins, ConfV0ChildNsigmaITSBins, ConfV0InvMassBins, ConfDummy, false, ConfV01_PDGCode.value, true); + V0Registry.add("hArmenterosPodolanski/hArmenterosPodolanskiPlot", "; #alpha; p_{T} (MeV/#it{c})", kTH2F, {{100, -1, 1}, {500, -0.3, 2}}); } /// Porduce QA plots for V0 selection in FemtoDream framework @@ -111,6 +116,20 @@ struct femtoDreamDebugV0 { negChild.partType() == uint8_t(aod::femtodreamparticle::ParticleType::kV0Child) && (negChild.cut() & ConfV01_ChildNeg_CutBit) == ConfV01_ChildNeg_CutBit && (negChild.pidcut() & ConfV01_ChildNeg_TPCBit) == ConfV01_ChildNeg_TPCBit) { + + TVector3 p_parent(part.px(), part.py(), part.pz()); // Parent momentum (px, py, pz) + TVector3 p_plus(posChild.px(), posChild.py(), posChild.pz()); // Daughter 1 momentum (px, py, pz) + TVector3 p_minus(negChild.px(), negChild.py(), negChild.pz()); // Daughter 2 momentum (px, py, pz) + + double pL_plus = p_plus.Dot(p_parent) / p_parent.Mag(); + double pL_minus = p_minus.Dot(p_parent) / p_parent.Mag(); + float alpha = (pL_plus - pL_minus) / (pL_plus + pL_minus); + + TVector3 p_perp = p_plus - (p_parent * (pL_plus / p_parent.Mag())); + double qtarm = p_perp.Mag(); + + V0Registry.fill(HIST("hArmenterosPodolanski/hArmenterosPodolanskiPlot"), alpha, qtarm); + V0Histos.fillQA(part, static_cast(ConfV0TempFitVarMomentum.value), col.multNtr(), col.multV0M()); posChildHistos.fillQA(posChild, static_cast(ConfV0TempFitVarMomentum.value), col.multNtr(), col.multV0M()); negChildHistos.fillQA(negChild, static_cast(ConfV0TempFitVarMomentum.value), col.multNtr(), col.multV0M()); diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamHashTask.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamHashTask.cxx index cc449887df1..78fe8c1cce4 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamHashTask.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamHashTask.cxx @@ -31,7 +31,7 @@ struct femtoDreamPairHashTask { std::vector CastCfgVtxBins, CastCfgMultBins; - Produces hashes; + Produces hashes; void init(InitContext&) { diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackCascade.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackCascade.cxx new file mode 100644 index 00000000000..c632d4648c8 --- /dev/null +++ b/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackCascade.cxx @@ -0,0 +1,394 @@ +// Copyright 2019-2022 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 femtoDreamPairTaskTrackTrack.cxx +/// \brief Tasks that reads the track tables used for the pairing and builds pairs of two tracks +/// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de +#include +#include +#include +#include +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/Expressions.h" +#include "PWGCF/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamEventHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h" +#include "PWGCF/FemtoDream/Core/femtoDreamContainer.h" +#include "PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h" +#include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" +using namespace o2; +using namespace o2::aod; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femtoDream; +struct femtoDreamPairTaskTrackCascade { + SliceCache cache; + Preslice perCol = aod::femtodreamparticle::fdCollisionId; + /// General options + struct : ConfigurableGroup { + std::string prefix = std::string("Option"); + Configurable IsMC{"IsMC", false, "Enable additional Histogramms in the case of a MonteCarlo Run"}; + Configurable Use4D{"Use4D", false, "Enable four dimensional histogramms (to be used only for analysis with high statistics): k* vs multiplicity vs multiplicity percentil vs mT"}; + Configurable ExtendedPlots{"ExtendedPlots", false, "Enable additional three dimensional histogramms. High memory consumption. Use for debugging"}; + Configurable HighkstarCut{"HighkstarCut", -1., "Set a cut for high k*, above which the pairs are rejected. Set it to -1 to deactivate it"}; + Configurable CPROn{"CPROn", true, "Close Pair Rejection"}; + Configurable CPROld{"CPROld", false, "Set to FALSE to use fixed version of CPR (for testing now, will be default soon)"}; + Configurable CPRPlotPerRadii{"CPRPlotPerRadii", false, "Plot CPR per radii"}; + Configurable CPRdeltaPhiMax{"CPRdeltaPhiMax", 0.01, "Max. Delta Phi for Close Pair Rejection"}; + Configurable CPRdeltaEtaMax{"CPRdeltaEtaMax", 0.01, "Max. Delta Eta for Close Pair Rejection"}; + Configurable DCACutPtDep{"DCACutPtDep", false, "Use pt dependent dca cut"}; + Configurable MixEventWithPairs{"MixEventWithPairs", false, "Only use events that contain particle 1 and partile 2 for the event mixing"}; + Configurable smearingByOrigin{"smearingByOrigin", false, "Obtain the smearing matrix differential in the MC origin of particle 1 and particle 2. High memory consumption. Use with care!"}; + ConfigurableAxis Dummy{"Dummy", {1, 0, 1}, "Dummy axis"}; + } Option; + /// Event selection + struct : ConfigurableGroup { + std::string prefix = std::string("EventSel"); + Configurable MultMin{"MultMin", 0, "Minimum Multiplicity (MultNtr)"}; + Configurable MultMax{"MultMax", 99999, "Maximum Multiplicity (MultNtr)"}; + Configurable MultPercentileMin{"MultPercentileMin", 0, "Minimum Multiplicity Percentile"}; + Configurable MultPercentileMax{"MultPercentileMax", 100, "Maximum Multiplicity Percentile"}; + } EventSel; + // Filter EventMultiplicity = aod::femtodreamcollision::multNtr >= EventSel.MultMin && aod::femtodreamcollision::multNtr <= EventSel.MultMax; + // Filter EventMultiplicityPercentile = aod::femtodreamcollision::multV0M >= EventSel.MultPercentileMin && aod::femtodreamcollision::multV0M <= EventSel.MultPercentileMax; + /// Histogramming for Event + FemtoDreamEventHisto eventHisto; + // using FilteredCollisions = soa::Filtered; + using FilteredCollisions = FDCollisions; + using FilteredCollision = FilteredCollisions::iterator; + using FDMCParts = soa::Join; + using FDMCPart = FDMCParts::iterator; + femtodreamcollision::BitMaskType BitMask = 1; + /// Particle 1 (track) + struct : ConfigurableGroup { + std::string prefix = std::string("Track1"); + Configurable PDGCode{"PDGCode", 2212, "PDG code of Particle 1 (Track)"}; + Configurable CutBit{"CutBit", 5542474, "Particle 1 (Track) - Selection bit from cutCulator"}; + Configurable TPCBit{"TPCBit", 4, "PID TPC bit from cutCulator for particle 1 (Track)"}; + Configurable TPCBit_Reject{"TPCBit_Reject", 0, "Reject PID TPC bit from cutCulator for particle 1 (Track). Set to 0 to turn off"}; + Configurable TPCTOFBit{"TPCTOFBit", 2, "PID TPCTOF bit from cutCulator for particle 1 (Track)"}; + Configurable PIDThres{"PIDThres", 0.75, "Momentum threshold for PID selection for particle 1 (Track)"}; + Configurable PtMin{"PtMin", 0., "Minimum pT of partricle 1 (Track)"}; + Configurable PtMax{"PtMax", 999., "Maximum pT of partricle 1 (Track)"}; + Configurable EtaMin{"EtaMin", -10., "Minimum eta of partricle 1 (Track)"}; + Configurable EtaMax{"EtaMax", 10., "Maximum eta of partricle 1 (Track)"}; + Configurable TempFitVarMin{"TempFitVarMin", -10., "Minimum DCAxy of partricle 1 (Track)"}; + Configurable TempFitVarMax{"TempFitVarMax", 10., "Maximum DCAxy of partricle 1 (Track)"}; + } Track1; + /// Partition for particle 1 + Partition PartitionTrk1 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && + (ncheckbit(aod::femtodreamparticle::cut, Track1.CutBit)) && + ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= Track1.PIDThres, ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCBit) && ((aod::femtodreamparticle::pidcut & Track1.TPCBit_Reject) == 0u), ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCTOFBit)) && + (aod::femtodreamparticle::pt > Track1.PtMin) && + (aod::femtodreamparticle::pt < Track1.PtMax) && + (aod::femtodreamparticle::eta > Track1.EtaMin) && + (aod::femtodreamparticle::eta < Track1.EtaMax) && + ifnode(Option.DCACutPtDep, (nabs(aod::femtodreamparticle::tempFitVar) <= 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f))), + ((aod::femtodreamparticle::tempFitVar >= Track1.TempFitVarMin) && + (aod::femtodreamparticle::tempFitVar <= Track1.TempFitVarMax))); + /// Histogramming for particle 1 + FemtoDreamParticleHisto trackHistoPartOne; + /// Particle 2 (Cascade) + struct : ConfigurableGroup { + std::string prefix = std::string("Cascade2"); + Configurable PDGCode{"PDGCode", 3312, "PDG code of particle 2 (V0)"}; + Configurable CutBit{"CutBit", 32221874, "Selection bit for particle 2 (Cascade)"}; + Configurable ChildPos_CutBit{"ChildPos_CutBit", 278, "Selection bit for positive child of Cascade"}; + Configurable ChildPos_TPCBit{"ChildPos_TPCBit", 1024, "PID TPC bit for positive child of Cascade"}; + Configurable ChildNeg_CutBit{"ChildNeg_CutBit", 277, "Selection bit for negative child of Cascade"}; + Configurable ChildNeg_TPCBit{"ChildNeg_TPCBit", 4096, "PID TPC bit for negative child of Cascade"}; + Configurable ChildBach_CutBit{"ChildBach_CutBit", 277, "Selection bit for negative child of Cascade"}; + Configurable ChildBach_TPCBit{"ChildBach_TPCBit", 64, "PID TPC bit for bachelor child of Cascade"}; + Configurable InvMassMin{"InvMassMin", 1.2, "Minimum invariant mass of Partricle 2 (particle) (Cascade)"}; + Configurable InvMassMax{"InvMassMax", 1.4, "Maximum invariant mass of Partricle 2 (particle) (Cascade)"}; + Configurable InvMassV0DaughMin{"InvMassV0DaugMin", 0., "Minimum invariant mass of the V0 Daughter"}; + Configurable InvMassV0DaughMax{"InvMassV0DaugMax", 999., "Maximum invariant mass of the V0 Daughter"}; + Configurable PtMin{"PtMin", 0., "Minimum pT of Partricle 2 (V0)"}; + Configurable PtMax{"PtMax", 999., "Maximum pT of Partricle 2 (V0)"}; + Configurable EtaMin{"EtaMin", -10., "Minimum eta of Partricle 2 (V0)"}; + Configurable EtaMax{"EtaMax", 10., "Maximum eta of Partricle 2 (V0)"}; + Configurable UseChildCuts{"UseChildCuts", true, "Use cuts on the children of the Cascades additional to those of the selection of the cascade builder (for debugging purposes)"}; + Configurable UseChildPIDCuts{"UseChildPIDCuts", true, "Use PID cuts on the children of the Cascades additional to those of the selection of the cascade builder (for debugging purposes)"}; + } Cascade2; + /// Partition for particle 2 + Partition PartitionCascade2 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kCascade)) && + ((aod::femtodreamparticle::cut & Cascade2.CutBit) == Cascade2.CutBit) && + (aod::femtodreamparticle::pt > Cascade2.PtMin) && + (aod::femtodreamparticle::pt < Cascade2.PtMax) && + (aod::femtodreamparticle::eta > Cascade2.EtaMin) && + (aod::femtodreamparticle::eta < Cascade2.EtaMax) && + (aod::femtodreamparticle::mLambda > Cascade2.InvMassMin) && + (aod::femtodreamparticle::mLambda < Cascade2.InvMassMax) && + (aod::femtodreamparticle::mAntiLambda > Cascade2.InvMassV0DaughMin) && + (aod::femtodreamparticle::mAntiLambda < Cascade2.InvMassV0DaughMax); + /// Histogramming for particle 2 + FemtoDreamParticleHisto trackHistoPartTwo; + FemtoDreamParticleHisto posChildHistos; + FemtoDreamParticleHisto negChildHistos; + FemtoDreamParticleHisto bachChildHistos; + /// Binning configurables + struct : ConfigurableGroup { + std::string prefix = std::string("Binning"); + ConfigurableAxis TempFitVarTrack{"TempFitVarTrack", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot (Track)"}; + ConfigurableAxis TempFitVarCascade{"TempFitVarCascade", {300, 0.9, 1}, "binning of the TempFitVar in the pT vs. TempFitVar plot (Cascade)"}; + ConfigurableAxis TempFitVarCascadeChild{"TempFitVarCascadeChild", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot (Cascade child)"}; + ConfigurableAxis InvMass{"InvMass", {200, 1.22, 1.42}, "InvMass binning"}; + ConfigurableAxis pTTrack{"pTTrack", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot (Track)"}; + ConfigurableAxis pTCascade{"pTCascade", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot (Cascade)"}; + ConfigurableAxis pTCascadeChild{"pTCascadeChild", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot (Cascade)"}; + ConfigurableAxis pT{"pT", {20, 0.5, 4.05}, "pT binning"}; + ConfigurableAxis kstar{"kstar", {1500, 0., 6.}, "binning kstar"}; + ConfigurableAxis kT{"kT", {150, 0., 9.}, "binning kT"}; + ConfigurableAxis mT{"mT", {225, 0., 7.5}, "binning mT"}; + ConfigurableAxis multTempFit{"multTempFit", {1, 0, 1}, "multiplicity for the TempFitVar plot"}; + } Binning; + struct : ConfigurableGroup { + std::string prefix = std::string("Binning4D"); + ConfigurableAxis kstar{"kstar", {1500, 0., 6.}, "binning kstar for the 4Dimensional plot: k* vs multiplicity vs multiplicity percentile vs mT (set <> to true in order to use)"}; + ConfigurableAxis mT{"mT", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 4Dimensional plot: k* vs multiplicity vs multiplicity percentile vs mT (set <> to true in order to use)"}; + ConfigurableAxis Mult{"mult", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f}, "multiplicity Binning for the 4Dimensional plot: k* vs multiplicity vs multiplicity percentile vs mT (set <> to true in order to use)"}; + ConfigurableAxis multPercentile{"multPercentile", {10, 0.0f, 100.0f}, "multiplicity percentile Binning for the 4Dimensional plot: k* vs multiplicity vs multiplicity percentile vs mT (set <> to true in order to use)"}; + } Binning4D; + // Mixing configurables + struct : ConfigurableGroup { + std::string prefix = std::string("Mixing"); + ConfigurableAxis BinMult{"BinMult", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f}, "bins - multiplicity"}; + ConfigurableAxis BinMultPercentile{"BinMultPercentile", {VARIABLE_WIDTH, 0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.f}, "bins - multiplicity percentile"}; + ConfigurableAxis BinVztx{"BinVztx", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "bins - z-vertex"}; + Configurable Depth{"Depth", 5, "Number of events for mixing"}; + Configurable Policy{"BinPolicy", 0, "Binning policy for mixing - 0: multiplicity, 1: multipliciy percentile, 2: both"}; + } Mixing; + ColumnBinningPolicy colBinningMult{{Mixing.BinVztx, Mixing.BinMult}, true}; + ColumnBinningPolicy colBinningMultPercentile{{Mixing.BinVztx, Mixing.BinMultPercentile}, true}; + ColumnBinningPolicy colBinningMultMultPercentile{{Mixing.BinVztx, Mixing.BinMult, Mixing.BinMultPercentile}, true}; + FemtoDreamContainer sameEventCont; + FemtoDreamContainer mixedEventCont; + FemtoDreamPairCleaner pairCleaner; + FemtoDreamDetaDphiStar pairCloseRejectionSE; + FemtoDreamDetaDphiStar pairCloseRejectionME; + + static constexpr uint32_t kSignPlusMask = 1 << 1; + + /// Histogram output + HistogramRegistry Registry{"Output", {}, OutputObjHandlingPolicy::AnalysisObject}; + void init(InitContext&) + { + // setup binnnig policy for mixing + colBinningMult = {{Mixing.BinVztx, Mixing.BinMult}, true}; + colBinningMultPercentile = {{Mixing.BinVztx, Mixing.BinMultPercentile}, true}; + colBinningMultMultPercentile = {{Mixing.BinVztx, Mixing.BinMult, Mixing.BinMultPercentile}, true}; + eventHisto.init(&Registry, Option.IsMC); + trackHistoPartOne.init(&Registry, Binning.multTempFit, Option.Dummy, Binning.pTTrack, Option.Dummy, Option.Dummy, Binning.TempFitVarTrack, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.IsMC, Track1.PDGCode); + trackHistoPartTwo.init(&Registry, Binning.multTempFit, Option.Dummy, Binning.pTCascade, Option.Dummy, Option.Dummy, Binning.TempFitVarCascade, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Binning.InvMass, Option.Dummy, Option.IsMC, Cascade2.PDGCode); + posChildHistos.init(&Registry, Binning.multTempFit, Option.Dummy, Binning.pTCascadeChild, Option.Dummy, Option.Dummy, Binning.TempFitVarCascadeChild, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, false, 0); + negChildHistos.init(&Registry, Binning.multTempFit, Option.Dummy, Binning.pTCascadeChild, Option.Dummy, Option.Dummy, Binning.TempFitVarCascadeChild, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, false, 0); + bachChildHistos.init(&Registry, Binning.multTempFit, Option.Dummy, Binning.pTCascadeChild, Option.Dummy, Option.Dummy, Binning.TempFitVarCascadeChild, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, false, 0); + sameEventCont.init(&Registry, + Binning.kstar, Binning.pT, Binning.kT, Binning.mT, Mixing.BinMult, Mixing.BinMultPercentile, + Binning4D.kstar, Binning4D.mT, Binning4D.Mult, Binning4D.multPercentile, + Option.IsMC, Option.Use4D, Option.ExtendedPlots, + Option.HighkstarCut, + Option.smearingByOrigin); + + sameEventCont.setPDGCodes(Track1.PDGCode, Cascade2.PDGCode); + + mixedEventCont.init(&Registry, + Binning.kstar, Binning.pT, Binning.kT, Binning.mT, Mixing.BinMult, Mixing.BinMultPercentile, + Binning4D.kstar, Binning4D.mT, Binning4D.Mult, Binning4D.multPercentile, + Option.IsMC, Option.Use4D, Option.ExtendedPlots, + Option.HighkstarCut, + Option.smearingByOrigin); + + mixedEventCont.setPDGCodes(Track1.PDGCode, Cascade2.PDGCode); + + pairCleaner.init(&Registry); + if (Option.CPROn.value) { + pairCloseRejectionSE.init(&Registry, &Registry, Option.CPRdeltaPhiMax.value, Option.CPRdeltaEtaMax.value, Option.CPRPlotPerRadii.value, 1, Option.CPROld.value); + pairCloseRejectionME.init(&Registry, &Registry, Option.CPRdeltaPhiMax.value, Option.CPRdeltaEtaMax.value, Option.CPRPlotPerRadii.value, 2, Option.CPROld.value, 99, true); + } + } + + /// This function processes the same event and takes care of all the histogramming + template + void doSameEvent(PartitionType& SliceTrk1, PartitionType& SliceCascade2, TableTracks const& parts, Collision const& col) + { + /// Histogramming same event + for (auto const& part : SliceTrk1) { + trackHistoPartOne.fillQA(part, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + } + for (auto& casc : SliceCascade2) { + const auto& posChild = parts.iteratorAt(casc.index() - 3); + const auto& negChild = parts.iteratorAt(casc.index() - 2); + const auto& bachChild = parts.iteratorAt(casc.index() - 1); + // This is how it is supposed to work but there seems to be an issue + // with partitions and accessing elements in tables that have been declared + // with an SELF_INDEX column. Under investigation. Maybe need to change + // femtdream dataformat to take special care of v0 candidates + // auto posChild = v0.template children_as().front(); + // auto negChild = v0.template children_as().back(); + // check cuts on V0 children + if (Cascade2.UseChildCuts) { + if (!(((posChild.cut() & Cascade2.ChildPos_CutBit) == Cascade2.ChildPos_CutBit) && + ((negChild.cut() & Cascade2.ChildNeg_CutBit) == Cascade2.ChildNeg_CutBit) && + ((bachChild.cut() & Cascade2.ChildBach_CutBit) == Cascade2.ChildBach_CutBit))) { + continue; + } + } + if (Cascade2.UseChildPIDCuts) { + if (!(((posChild.pidcut() & Cascade2.ChildPos_TPCBit) == Cascade2.ChildPos_TPCBit) && + ((negChild.pidcut() & Cascade2.ChildNeg_TPCBit) == Cascade2.ChildNeg_TPCBit) && + ((bachChild.pidcut() & Cascade2.ChildBach_TPCBit) == Cascade2.ChildBach_TPCBit))) { + continue; + } + } + trackHistoPartTwo.fillQA(casc, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + posChildHistos.fillQA(posChild, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + negChildHistos.fillQA(negChild, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + bachChildHistos.fillQA(bachChild, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + } + /// Now build particle combinations + for (auto const& [p1, p2] : combinations(CombinationsFullIndexPolicy(SliceTrk1, SliceCascade2))) { + const auto& posChild = parts.iteratorAt(p2.index() - 3); + const auto& negChild = parts.iteratorAt(p2.index() - 2); + const auto& bachChild = parts.iteratorAt(p2.index() - 1); + + // cuts on Cascade children still need to be applied + if (Cascade2.UseChildCuts) { + if (!(((posChild.cut() & Cascade2.ChildPos_CutBit) == Cascade2.ChildPos_CutBit) && + ((negChild.cut() & Cascade2.ChildNeg_CutBit) == Cascade2.ChildNeg_CutBit) && + ((bachChild.cut() & Cascade2.ChildBach_CutBit) == Cascade2.ChildBach_CutBit))) { + continue; + } + } + if (Cascade2.UseChildPIDCuts) { + if (!(((posChild.pidcut() & Cascade2.ChildPos_TPCBit) == Cascade2.ChildPos_TPCBit) && + ((negChild.pidcut() & Cascade2.ChildNeg_TPCBit) == Cascade2.ChildNeg_TPCBit) && + ((bachChild.pidcut() & Cascade2.ChildBach_TPCBit) == Cascade2.ChildBach_TPCBit))) { + continue; + } + } + if (Option.CPROn.value) { + if ((p1.cut() & kSignPlusMask) == kSignPlusMask) { + if (pairCloseRejectionSE.isClosePair(p1, posChild, parts, col.magField())) { + continue; + } + } else { + if (pairCloseRejectionSE.isClosePair(p1, posChild, parts, col.magField())) { + continue; + } + } + } + + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + sameEventCont.setPair(p1, p2, col.multNtr(), col.multV0M(), Option.Use4D, Option.ExtendedPlots, Option.smearingByOrigin); + } + } + void processSameEvent(FilteredCollision const& col, FDParticles const& parts) + { + // if ((col.bitmaskTrackOne() & BitMask) != BitMask || (col.bitmaskTrackTwo() & BitMask) != BitMask) { + // return; + // } + eventHisto.fillQA(col); + auto SliceTrk1 = PartitionTrk1->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + auto SliceCascade2 = PartitionCascade2->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + doSameEvent(SliceTrk1, SliceCascade2, parts, col); + } + PROCESS_SWITCH(femtoDreamPairTaskTrackCascade, processSameEvent, "Enable processing same event", true); + + template + void doMixedEvent(CollisionType const& cols, PartType const& parts, PartitionType& part1, PartitionType& part2, BinningType policy) + { + // Partition PartitionMaskedCol = ncheckbit(aod::femtodreamcollision::bitmaskTrackOne, BitMask) && ncheckbit(aod::femtodreamcollision::bitmaskTrackTwo, BitMask);// && aod::femtodreamcollision::downsample == true; + // PartitionMaskedCol.bindTable(cols); + + // use *Partition.mFiltered when passing the partition to mixing object + // there is an issue when the partition is passed directly + // workaround for now, change back once it is fixed + for (auto const& [collision1, collision2] : soa::selfCombinations(policy, Mixing.Depth.value, -1, cols, cols)) { + // make sure that tracks in same events are not mixed + if (collision1.globalIndex() == collision2.globalIndex()) { + continue; + } + auto SliceTrk1 = part1->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); + auto SliceCasc2 = part2->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(SliceTrk1, SliceCasc2))) { + const auto& posChild = parts.iteratorAt(p2.index() - 3); + const auto& negChild = parts.iteratorAt(p2.index() - 2); + const auto& bachChild = parts.iteratorAt(p2.index() - 1); + // check cuts on Cascade children + if (Cascade2.UseChildCuts) { + if (!(((posChild.cut() & Cascade2.ChildPos_CutBit) == Cascade2.ChildPos_CutBit) && + ((negChild.cut() & Cascade2.ChildNeg_CutBit) == Cascade2.ChildNeg_CutBit) && + ((bachChild.cut() & Cascade2.ChildBach_CutBit) == Cascade2.ChildBach_CutBit))) { + continue; + } + } + if (Cascade2.UseChildPIDCuts) { + if (!(((posChild.pidcut() & Cascade2.ChildPos_TPCBit) == Cascade2.ChildPos_TPCBit) && + ((negChild.pidcut() & Cascade2.ChildNeg_TPCBit) == Cascade2.ChildNeg_TPCBit) && + ((bachChild.pidcut() & Cascade2.ChildBach_TPCBit) == Cascade2.ChildBach_TPCBit))) { + continue; + } + } + + if (Option.CPROn.value) { + if ((p1.cut() & kSignPlusMask) == kSignPlusMask) { + if (pairCloseRejectionME.isClosePair(p1, posChild, parts, collision1.magField())) { + continue; + } + } else { + if (pairCloseRejectionME.isClosePair(p1, negChild, parts, collision1.magField())) { + continue; + } + } + } + // Pair cleaner not needed in the mixing + // if (!pairCleaner.isCleanPair(p1, p2, parts)) { + // continue; + //} + + mixedEventCont.setPair(p1, p2, collision1.multNtr(), collision1.multV0M(), Option.Use4D, Option.ExtendedPlots, Option.smearingByOrigin); + } + } + } + + void processMixedEvent(FilteredCollisions const& cols, FDParticles const& parts) + { + switch (Mixing.Policy.value) { + case femtodreamcollision::kMult: + doMixedEvent(cols, parts, PartitionTrk1, PartitionCascade2, colBinningMult); + break; + case femtodreamcollision::kMultPercentile: + doMixedEvent(cols, parts, PartitionTrk1, PartitionCascade2, colBinningMultPercentile); + break; + case femtodreamcollision::kMultMultPercentile: + doMixedEvent(cols, parts, PartitionTrk1, PartitionCascade2, colBinningMultMultPercentile); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + PROCESS_SWITCH(femtoDreamPairTaskTrackCascade, processMixedEvent, "Enable processing mixed events", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackTrack.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackTrack.cxx index 547bf6c905a..5cfd8664985 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackTrack.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackTrack.cxx @@ -18,6 +18,7 @@ #include #include #include +#include #include "TRandom3.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -49,30 +50,32 @@ struct femtoDreamPairTaskTrackTrack { /// General options struct : ConfigurableGroup { - Configurable IsMC{"Option.IsMC", false, "Enable additional Histogramms in the case of runninger over Monte Carlo"}; - Configurable Use4D{"Option.Use4D", false, "Enable four dimensional histogramms (to be used only for analysis with high statistics): k* vs multiplicity vs multiplicity percentil vs mT"}; - Configurable ExtendedPlots{"Option.ExtendedPlots", false, "Enable additional three dimensional histogramms. High memory consumption. Use for debugging"}; - Configurable HighkstarCut{"Option.HighkstarCut", -1., "Set a cut for high k*, above which the pairs are rejected. Set it to -1 to deactivate it"}; - Configurable SameSpecies{"Option.SameSpecies", false, "Set to true if particle 1 and particle 2 are the same species"}; - Configurable MixEventWithPairs{"Option.MixEventWithPairs", false, "Only use events that contain particle 1 and partile 2 for the event mixing"}; - Configurable RandomizePair{"Option.RandomizePair", true, "Randomly mix particle 1 and particle 2 in case both are identical"}; - Configurable CPROn{"Option.CPROn", true, "Close Pair Rejection"}; - Configurable CPROld{"Option.CPROld", false, "Set to FALSE to use fixed version of CPR (for testing now, will be default soon)"}; - Configurable CPRSepMeSe{"Option.CPRSepMESE", true, "Use seperated plots for same and mixed event for CPR plots"}; - Configurable CPRPlotPerRadii{"Option.CPRPlotPerRadii", false, "Plot CPR per radii"}; - Configurable CPRdeltaPhiMax{"Option.CPRdeltaPhiMax", 0.01, "Max. Delta Phi for Close Pair Rejection"}; - Configurable CPRdeltaEtaMax{"Option.CPRdeltaEtaMax", 0.01, "Max. Delta Eta for Close Pair Rejection"}; - Configurable DCACutPtDep{"Option.DCACutPtDep", false, "Use pt dependent dca cut"}; - ConfigurableAxis Dummy{"Option.Dummy", {1, 0, 1}, "Dummy axis"}; - Configurable SmearingByOrigin{"Option.SmearingByOrigin", false, "Obtain the smearing matrix differential in the MC origin of particle 1 and particle 2. High memory consumption"}; + std::string prefix = std::string("Option"); + Configurable IsMC{"IsMC", false, "Enable additional Histogramms in the case of runninger over Monte Carlo"}; + Configurable Use4D{"Use4D", false, "Enable four dimensional histogramms (to be used only for analysis with high statistics): k* vs multiplicity vs multiplicity percentil vs mT"}; + Configurable ExtendedPlots{"ExtendedPlots", false, "Enable additional three dimensional histogramms. High memory consumption. Use for debugging"}; + Configurable HighkstarCut{"HighkstarCut", -1., "Set a cut for high k*, above which the pairs are rejected. Set it to -1 to deactivate it"}; + Configurable SameSpecies{"SameSpecies", false, "Set to true if particle 1 and particle 2 are the same species"}; + Configurable MixEventWithPairs{"MixEventWithPairs", false, "Only use events that contain particle 1 and partile 2 for the event mixing"}; + Configurable RandomizePair{"RandomizePair", true, "Randomly mix particle 1 and particle 2 in case both are identical"}; + Configurable CPROn{"CPROn", true, "Close Pair Rejection"}; + Configurable CPROld{"CPROld", false, "Set to FALSE to use fixed version of CPR (for testing now, will be default soon)"}; + Configurable CPRSepMeSe{"CPRSepMESE", true, "Use seperated plots for same and mixed event for CPR plots"}; + Configurable CPRPlotPerRadii{"CPRPlotPerRadii", false, "Plot CPR per radii"}; + Configurable CPRdeltaPhiMax{"CPRdeltaPhiMax", 0.01, "Max. Delta Phi for Close Pair Rejection"}; + Configurable CPRdeltaEtaMax{"CPRdeltaEtaMax", 0.01, "Max. Delta Eta for Close Pair Rejection"}; + Configurable DCACutPtDep{"DCACutPtDep", false, "Use pt dependent dca cut"}; + Configurable SmearingByOrigin{"SmearingByOrigin", false, "Obtain the smearing matrix differential in the MC origin of particle 1 and particle 2. High memory consumption"}; + ConfigurableAxis Dummy{"Dummy", {1, 0, 1}, "Dummy axis"}; } Option; /// Event selection struct : ConfigurableGroup { - Configurable MultMin{"EventSel.MultMin", 0, "Minimum Multiplicity (MultNtr)"}; - Configurable MultMax{"EventSel.MultMax", 99999, "Maximum Multiplicity (MultNtr)"}; - Configurable MultPercentileMin{"EventSel.MultPercentileMin", 0, "Maximum Multiplicity Percentile"}; - Configurable MultPercentileMax{"EventSel.MultPercentileMax", 100, "Minimum Multiplicity Percentile"}; + std::string prefix = std::string("EventSel"); + Configurable MultMin{"MultMin", 0, "Minimum Multiplicity (MultNtr)"}; + Configurable MultMax{"MultMax", 99999, "Maximum Multiplicity (MultNtr)"}; + Configurable MultPercentileMin{"MultPercentileMin", 0, "Maximum Multiplicity Percentile"}; + Configurable MultPercentileMax{"MultPercentileMax", 100, "Minimum Multiplicity Percentile"}; } EventSel; Filter EventMultiplicity = aod::femtodreamcollision::multNtr >= EventSel.MultMin && aod::femtodreamcollision::multNtr <= EventSel.MultMax; @@ -88,88 +91,94 @@ struct femtoDreamPairTaskTrackTrack { using FilteredMaskedMCCollisions = soa::Filtered>; using FilteredMaskedMCCollision = FilteredMaskedMCCollisions::iterator; - femtodreamcollision::BitMaskType BitMask = -1; + femtodreamcollision::BitMaskType BitMask = 0; /// Track 1 struct : ConfigurableGroup { - Configurable PDGCode{"Track1.PDGCode", 2212, "PDG code of particle 1 (Track)"}; - Configurable CutBit{"Track1.CutBit", 3191978, "Selection bit from cutCulator for particle 1 (Track)"}; - Configurable TPCBit{"Track1.TPCBit", 4, "PID TPC bit from cutCulator for particle 1 (Track)"}; - Configurable TPCBit_Reject{"Track1.TPCBit_Reject", 0, "PID TPC bit from cutCulator to reject a particle hypothesis for particle 1 (set to 0 to ignore)"}; - Configurable TPCTOFBit{"Track1.TPCTOFBit", 2, "PID TPCTOF bit from cutCulator for particle 1 (Track)"}; - Configurable PIDThres{"Track1.PIDThres", 0.75, "Momentum threshold for PID selection for particle 1 (Track)"}; - Configurable PtMin{"Track1.PtMin", 0., "Minimum pT of partricle 1 (Track)"}; - Configurable PtMax{"Track1.PtMax", 999., "Maximum pT of partricle 1 (Track)"}; - Configurable EtaMin{"Track1.EtaMin", -10., "Minimum eta of partricle 1 (Track)"}; - Configurable EtaMax{"Track1.EtaMax", 10., "Maximum eta of partricle 1 (Track)"}; - Configurable TempFitVarMin{"Track1.TempFitVarMin", -10., "Minimum DCAxy of partricle 1 (Track)"}; - Configurable TempFitVarMax{"Track1.TempFitVarMax", 10., "Maximum DCAxy of partricle 1 (Track)"}; + std::string prefix = std::string("Track1"); + Configurable PDGCode{"PDGCode", 2212, "PDG code of particle 1 (Track)"}; + Configurable CutBit{"CutBit", 3191978, "Selection bit from cutCulator for particle 1 (Track)"}; + Configurable TPCBit{"TPCBit", 4, "PID TPC bit from cutCulator for particle 1 (Track)"}; + Configurable TPCBit_Reject{"TPCBit_Reject", 0, "PID TPC bit from cutCulator to reject a particle hypothesis for particle 1 (set to 0 to ignore)"}; + Configurable TPCTOFBit{"TPCTOFBit", 2, "PID TPCTOF bit from cutCulator for particle 1 (Track)"}; + Configurable PIDThres{"PIDThres", 0.75, "Momentum threshold for PID selection for particle 1 (Track)"}; + Configurable PtMin{"PtMin", 0., "Minimum pT of partricle 1 (Track)"}; + Configurable PtMax{"PtMax", 999., "Maximum pT of partricle 1 (Track)"}; + Configurable EtaMin{"EtaMin", -10., "Minimum eta of partricle 1 (Track)"}; + Configurable EtaMax{"EtaMax", 10., "Maximum eta of partricle 1 (Track)"}; + Configurable TempFitVarMin{"TempFitVarMin", -10., "Minimum DCAxy of partricle 1 (Track)"}; + Configurable TempFitVarMax{"TempFitVarMax", 10., "Maximum DCAxy of partricle 1 (Track)"}; } Track1; /// Partition for particle 1 - Partition PartitionTrk1 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && - (ncheckbit(aod::femtodreamparticle::cut, Track1.CutBit)) && - ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= Track1.PIDThres, ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCBit) && ((aod::femtodreamparticle::pidcut & Track1.TPCBit_Reject) == 0u), ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCTOFBit)) && - (aod::femtodreamparticle::pt > Track1.PtMin) && - (aod::femtodreamparticle::pt < Track1.PtMax) && - (aod::femtodreamparticle::eta > Track1.EtaMin) && - (aod::femtodreamparticle::eta < Track1.EtaMax) && - ifnode(Option.DCACutPtDep, nabs(aod::femtodreamparticle::tempFitVar) < 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f)), - (aod::femtodreamparticle::tempFitVar > Track1.TempFitVarMin) && - (aod::femtodreamparticle::tempFitVar < Track1.TempFitVarMax)); - - Partition> PartitionMCTrk1 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && - (ncheckbit(aod::femtodreamparticle::cut, Track1.CutBit)) && - ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= Track1.PIDThres, ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCBit) && ((aod::femtodreamparticle::pidcut & Track1.TPCBit_Reject) == 0u), ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCTOFBit)) && - (aod::femtodreamparticle::pt > Track1.PtMin) && - (aod::femtodreamparticle::pt < Track1.PtMax) && - (aod::femtodreamparticle::eta > Track1.EtaMin) && - (aod::femtodreamparticle::eta < Track1.EtaMax) && - ifnode(Option.DCACutPtDep, nabs(aod::femtodreamparticle::tempFitVar) < 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f)), - (aod::femtodreamparticle::tempFitVar > Track1.TempFitVarMin) && - (aod::femtodreamparticle::tempFitVar < Track1.TempFitVarMax)); + Partition PartitionTrk1 = + (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && + (ncheckbit(aod::femtodreamparticle::cut, Track1.CutBit)) && + ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= Track1.PIDThres, ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCBit) && ((aod::femtodreamparticle::pidcut & Track1.TPCBit_Reject) == 0u), ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCTOFBit)) && + (aod::femtodreamparticle::pt >= Track1.PtMin) && + (aod::femtodreamparticle::pt <= Track1.PtMax) && + (aod::femtodreamparticle::eta >= Track1.EtaMin) && + (aod::femtodreamparticle::eta <= Track1.EtaMax) && + ifnode(Option.DCACutPtDep, (nabs(aod::femtodreamparticle::tempFitVar) <= 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f))), + ((aod::femtodreamparticle::tempFitVar >= Track1.TempFitVarMin) && + (aod::femtodreamparticle::tempFitVar <= Track1.TempFitVarMax))); + + Partition> PartitionMCTrk1 = + (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && + (ncheckbit(aod::femtodreamparticle::cut, Track1.CutBit)) && + ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= Track1.PIDThres, ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCBit) && ((aod::femtodreamparticle::pidcut & Track1.TPCBit_Reject) == 0u), ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCTOFBit)) && + (aod::femtodreamparticle::pt >= Track1.PtMin) && + (aod::femtodreamparticle::pt <= Track1.PtMax) && + (aod::femtodreamparticle::eta >= Track1.EtaMin) && + (aod::femtodreamparticle::eta < Track1.EtaMax) && + ifnode(Option.DCACutPtDep, (nabs(aod::femtodreamparticle::tempFitVar) <= 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f))), + ((aod::femtodreamparticle::tempFitVar >= Track1.TempFitVarMin) && + (aod::femtodreamparticle::tempFitVar <= Track1.TempFitVarMax))); /// Histogramming for particle 1 FemtoDreamParticleHisto trackHistoPartOne; /// Track 2 struct : ConfigurableGroup { - Configurable PDGCode{"Track2.PDGCode", 2212, "PDG code of particle 2 (Track)"}; - Configurable CutBit{"Track2.CutBit", 3191978, "Selection bit from cutCulator for particle 2 (Track)"}; - Configurable TPCBit{"Track2.TPCBit", 4, "PID TPC bit from cutCulator for particle 2 (Track)"}; - Configurable TPCBit_Reject{"Track2.TPCBit_Reject", 0, "PID TPC bit from cutCulator to reject a particle hypothesis for particle 2 (set to 0 to ignore)"}; - Configurable TPCTOFBit{"Track2.TPCTOFBit", 2, "PID TPCTOF bit from cutCulator for particle 2 (Track)"}; - Configurable PIDThres{"Track2.PIDThres", 0.75, "Momentum threshold for PID selection for particle 2 (Track)"}; - Configurable PtMin{"Track2.PtMin", 0., "Minimum pT of particle 2 (Track)"}; - Configurable PtMax{"Track2.PtMax", 999., "Maximum pT of particle 2 (Track)"}; - Configurable EtaMin{"Track2.EtaMin", -10., "Minimum eta of particle 2 (Track)"}; - Configurable EtaMax{"Track2.EtaMax", 10., "Maximum eta of particle 2 (Track)"}; - Configurable TempFitVarMin{"Track2.TempFitVarMin", -10., "Minimum DCAxy of partricle 1 (Track)"}; - Configurable TempFitVarMax{"Track2.TempFitVarMax", 10., "Maximum DCAxy of partricle 1 (Track)"}; + std::string prefix = std::string("Track2"); + Configurable PDGCode{"PDGCode", 2212, "PDG code of particle 2 (Track)"}; + Configurable CutBit{"CutBit", 3191978, "Selection bit from cutCulator for particle 2 (Track)"}; + Configurable TPCBit{"TPCBit", 4, "PID TPC bit from cutCulator for particle 2 (Track)"}; + Configurable TPCBit_Reject{"TPCBit_Reject", 0, "PID TPC bit from cutCulator to reject a particle hypothesis for particle 2 (set to 0 to ignore)"}; + Configurable TPCTOFBit{"TPCTOFBit", 2, "PID TPCTOF bit from cutCulator for particle 2 (Track)"}; + Configurable PIDThres{"PIDThres", 0.75, "Momentum threshold for PID selection for particle 2 (Track)"}; + Configurable PtMin{"PtMin", 0., "Minimum pT of particle 2 (Track)"}; + Configurable PtMax{"PtMax", 999., "Maximum pT of particle 2 (Track)"}; + Configurable EtaMin{"EtaMin", -10., "Minimum eta of particle 2 (Track)"}; + Configurable EtaMax{"EtaMax", 10., "Maximum eta of particle 2 (Track)"}; + Configurable TempFitVarMin{"TempFitVarMin", -10., "Minimum DCAxy of partricle 1 (Track)"}; + Configurable TempFitVarMax{"TempFitVarMax", 10., "Maximum DCAxy of partricle 1 (Track)"}; } Track2; /// Partition for track 2 - Partition PartitionTrk2 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && - (ncheckbit(aod::femtodreamparticle::cut, Track2.CutBit)) && - ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= Track2.PIDThres, ncheckbit(aod::femtodreamparticle::pidcut, Track2.TPCBit) && ((aod::femtodreamparticle::pidcut & Track2.TPCBit_Reject) == 0u), ncheckbit(aod::femtodreamparticle::pidcut, Track2.TPCTOFBit)) && - (aod::femtodreamparticle::pt > Track2.PtMin) && - (aod::femtodreamparticle::pt < Track2.PtMax) && - (aod::femtodreamparticle::eta > Track2.EtaMin) && - (aod::femtodreamparticle::eta < Track2.EtaMax) && - ifnode(Option.DCACutPtDep, nabs(aod::femtodreamparticle::tempFitVar) < 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f)), - (aod::femtodreamparticle::tempFitVar > Track2.TempFitVarMin) && - (aod::femtodreamparticle::tempFitVar < Track2.TempFitVarMax)); - - Partition> PartitionMCTrk2 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && - (ncheckbit(aod::femtodreamparticle::cut, Track2.CutBit)) && - ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= Track2.PIDThres, ncheckbit(aod::femtodreamparticle::pidcut, Track2.TPCBit) && ((aod::femtodreamparticle::pidcut & Track2.TPCBit_Reject) == 0u), ncheckbit(aod::femtodreamparticle::pidcut, Track2.TPCTOFBit)) && - (aod::femtodreamparticle::pt > Track2.PtMin) && - (aod::femtodreamparticle::pt < Track2.PtMax) && - (aod::femtodreamparticle::eta > Track2.EtaMin) && - (aod::femtodreamparticle::eta < Track2.EtaMax) && - ifnode(Option.DCACutPtDep, nabs(aod::femtodreamparticle::tempFitVar) < 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f)), - (aod::femtodreamparticle::tempFitVar > Track2.TempFitVarMin) && - (aod::femtodreamparticle::tempFitVar < Track2.TempFitVarMax)); + Partition PartitionTrk2 = + (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && + (ncheckbit(aod::femtodreamparticle::cut, Track2.CutBit)) && + ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= Track2.PIDThres, ncheckbit(aod::femtodreamparticle::pidcut, Track2.TPCBit) && ((aod::femtodreamparticle::pidcut & Track2.TPCBit_Reject) == 0u), ncheckbit(aod::femtodreamparticle::pidcut, Track2.TPCTOFBit)) && + (aod::femtodreamparticle::pt >= Track2.PtMin) && + (aod::femtodreamparticle::pt <= Track2.PtMax) && + (aod::femtodreamparticle::eta >= Track2.EtaMin) && + (aod::femtodreamparticle::eta <= Track2.EtaMax) && + ifnode(Option.DCACutPtDep, (nabs(aod::femtodreamparticle::tempFitVar) <= 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f))), + ((aod::femtodreamparticle::tempFitVar >= Track2.TempFitVarMin) && + (aod::femtodreamparticle::tempFitVar <= Track2.TempFitVarMax))); + + Partition> PartitionMCTrk2 = + (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && + (ncheckbit(aod::femtodreamparticle::cut, Track2.CutBit)) && + ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= Track2.PIDThres, ncheckbit(aod::femtodreamparticle::pidcut, Track2.TPCBit) && ((aod::femtodreamparticle::pidcut & Track2.TPCBit_Reject) == 0u), ncheckbit(aod::femtodreamparticle::pidcut, Track2.TPCTOFBit)) && + (aod::femtodreamparticle::pt >= Track2.PtMin) && + (aod::femtodreamparticle::pt <= Track2.PtMax) && + (aod::femtodreamparticle::eta > Track2.EtaMin) && + (aod::femtodreamparticle::eta < Track2.EtaMax) && + ifnode(Option.DCACutPtDep, (nabs(aod::femtodreamparticle::tempFitVar) <= 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f))), + ((aod::femtodreamparticle::tempFitVar >= Track2.TempFitVarMin) && + (aod::femtodreamparticle::tempFitVar <= Track2.TempFitVarMax))); /// Histogramming for track 2 FemtoDreamParticleHisto trackHistoPartTwo; @@ -182,7 +191,7 @@ struct femtoDreamPairTaskTrackTrack { std::string prefix = "Binning"; ConfigurableAxis TempFitVar{"TempFitVar", {300, -0.15, 0.15}, "Binning of the TempFitVar in the pT vs. TempFitVar plot"}; ConfigurableAxis TrackpT{"TrackpT", {20, 0.5, 4.05}, "pT binning for pT vs. TempFitVar plot"}; - ConfigurableAxis pT{"pT", {20, 0.5, 4.05}, "pT binning"}; + ConfigurableAxis pT{"pT", {20, 0.5, 4.05}, "pT binning for extended plots"}; ConfigurableAxis kstar{"kstar", {1500, 0., 6.}, "kstar binning"}; ConfigurableAxis kT{"kT", {150, 0., 9.}, "kT binning"}; ConfigurableAxis mT{"mT", {225, 0., 7.5}, "mT binning"}; @@ -217,29 +226,34 @@ struct femtoDreamPairTaskTrackTrack { FemtoDreamDetaDphiStar pairCloseRejectionSE; FemtoDreamDetaDphiStar pairCloseRejectionME; /// Histogram output - HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry resultRegistry{"Correlations", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry Registry{"Output", {}, OutputObjHandlingPolicy::AnalysisObject}; TRandom3* random; void init(InitContext& context) { + + // setup columnpolicy for binning + colBinningMult = {{Mixing.VztxMixBins, Mixing.MultMixBins}, true}; + colBinningMultPercentile = {{Mixing.VztxMixBins, Mixing.MultPercentileMixBins}, true}; + colBinningMultMultPercentile = {{Mixing.VztxMixBins, Mixing.MultMixBins, Mixing.MultPercentileMixBins}, true}; + if (Option.RandomizePair.value) { random = new TRandom3(0); } - eventHisto.init(&qaRegistry, Option.IsMC); - trackHistoPartOne.init(&qaRegistry, Binning.multTempFit, Option.Dummy, Binning.TrackpT, Option.Dummy, Option.Dummy, Binning.TempFitVar, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.IsMC, Track1.PDGCode); + eventHisto.init(&Registry, Option.IsMC); + trackHistoPartOne.init(&Registry, Binning.multTempFit, Option.Dummy, Binning.TrackpT, Option.Dummy, Option.Dummy, Binning.TempFitVar, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.IsMC, Track1.PDGCode); if (!Option.SameSpecies) { - trackHistoPartTwo.init(&qaRegistry, Binning.multTempFit, Option.Dummy, Binning.TrackpT, Option.Dummy, Option.Dummy, Binning.TempFitVar, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.IsMC, Track2.PDGCode); + trackHistoPartTwo.init(&Registry, Binning.multTempFit, Option.Dummy, Binning.TrackpT, Option.Dummy, Option.Dummy, Binning.TempFitVar, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.IsMC, Track2.PDGCode); } - sameEventCont.init(&resultRegistry, + sameEventCont.init(&Registry, Binning.kstar, Binning.pT, Binning.kT, Binning.mT, Mixing.MultMixBins, Mixing.MultPercentileMixBins, Binning4D.kstar, Binning4D.mT, Binning4D.mult, Binning4D.multPercentile, Option.IsMC, Option.Use4D, Option.ExtendedPlots, Option.HighkstarCut, Option.SmearingByOrigin); - mixedEventCont.init(&resultRegistry, + mixedEventCont.init(&Registry, Binning.kstar, Binning.pT, Binning.kT, Binning.mT, Mixing.MultMixBins, Mixing.MultPercentileMixBins, Binning4D.kstar, Binning4D.mT, Binning4D.mult, Binning4D.multPercentile, Option.IsMC, Option.Use4D, Option.ExtendedPlots, @@ -247,10 +261,10 @@ struct femtoDreamPairTaskTrackTrack { Option.SmearingByOrigin); sameEventCont.setPDGCodes(Track1.PDGCode, Track2.PDGCode); mixedEventCont.setPDGCodes(Track1.PDGCode, Track2.PDGCode); - pairCleaner.init(&qaRegistry); + pairCleaner.init(&Registry); if (Option.CPROn.value) { - pairCloseRejectionSE.init(&resultRegistry, &qaRegistry, Option.CPRdeltaPhiMax.value, Option.CPRdeltaEtaMax.value, Option.CPRPlotPerRadii.value, 1, Option.CPROld.value); - pairCloseRejectionME.init(&resultRegistry, &qaRegistry, Option.CPRdeltaPhiMax.value, Option.CPRdeltaEtaMax.value, Option.CPRPlotPerRadii.value, 2, Option.CPROld.value); + pairCloseRejectionSE.init(&Registry, &Registry, Option.CPRdeltaPhiMax.value, Option.CPRdeltaEtaMax.value, Option.CPRPlotPerRadii.value, 1, Option.CPROld.value); + pairCloseRejectionME.init(&Registry, &Registry, Option.CPRdeltaPhiMax.value, Option.CPRdeltaEtaMax.value, Option.CPRPlotPerRadii.value, 2, Option.CPROld.value); } // get bit for the collision mask @@ -259,7 +273,9 @@ struct femtoDreamPairTaskTrackTrack { auto& workflows = context.services().get(); for (DeviceSpec const& device : workflows.devices) { if (device.name.find("femto-dream-pair-task-track-track") != std::string::npos) { - if (containsNameValuePair(device.options, "Track1.CutBit", Track1.CutBit.value) && + if (containsNameValuePair(device.options, "Option.DCACutPtDep", Option.DCACutPtDep.value) && + containsNameValuePair(device.options, "Option.SameSpecies", Option.SameSpecies.value) && + containsNameValuePair(device.options, "Track1.CutBit", Track1.CutBit.value) && containsNameValuePair(device.options, "Track1.TPCBit", Track1.TPCBit.value) && containsNameValuePair(device.options, "Track1.TPCTOFBit", Track1.TPCTOFBit.value) && containsNameValuePair(device.options, "Track1.PIDThres", Track1.PIDThres.value) && @@ -386,7 +402,7 @@ struct femtoDreamPairTaskTrackTrack { return; } } else { - if ((col.bitmaskTrackOne() & BitMask) != BitMask && (col.bitmaskTrackTwo() & BitMask) != BitMask) { + if ((col.bitmaskTrackOne() & BitMask) != BitMask || (col.bitmaskTrackTwo() & BitMask) != BitMask) { return; } } @@ -458,21 +474,24 @@ struct femtoDreamPairTaskTrackTrack { template void doMixedEvent_Masked(CollisionType& cols, PartType& parts, PartitionType& part1, PartitionType& part2, BinningType policy) { - if (Option.SameSpecies.value) { + if (!Option.SameSpecies.value && !Option.MixEventWithPairs.value) { + // If the two particles are not the same species and the events which are mixed should contain at least one particle of interest, create two paritition of collisions that contain at least one of the two particle of interest and mix them + // Make sure there is a check that we do not mix a event with itself in case it contains both partilces Partition PartitionMaskedCol1 = (aod::femtodreamcollision::bitmaskTrackOne & BitMask) == BitMask && aod::femtodreamcollision::downsample == true; PartitionMaskedCol1.bindTable(cols); + Partition PartitionMaskedCol2 = (aod::femtodreamcollision::bitmaskTrackTwo & BitMask) == BitMask && aod::femtodreamcollision::downsample == true; + PartitionMaskedCol2.bindTable(cols); // use *Partition.mFiltered when passing the partition to mixing object // there is an issue when the partition is passed directly // workaround for now, change back once it is fixed - for (auto const& [collision1, collision2] : selfCombinations(policy, Mixing.Depth.value, -1, *PartitionMaskedCol1.mFiltered, *PartitionMaskedCol1.mFiltered)) { - // selfCombinations policy should not allow for same events - // print a warning to be on the safe side + for (auto const& [collision1, collision2] : combinations(soa::CombinationsBlockUpperIndexPolicy(policy, Mixing.Depth.value, -1, *PartitionMaskedCol1.mFiltered, *PartitionMaskedCol2.mFiltered))) { + // make sure that tracks in the same events are not mixed if (collision1.globalIndex() == collision2.globalIndex()) { - LOG(warn) << "Global Collision index " << collision1.globalIndex() << " clashing!"; continue; } auto SliceTrk1 = part1->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); auto SliceTrk2 = part2->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(SliceTrk1, SliceTrk2))) { if (Option.CPROn.value) { if (pairCloseRejectionME.isClosePair(p1, p2, parts, collision1.magField())) { @@ -483,28 +502,39 @@ struct femtoDreamPairTaskTrackTrack { } } } else { - Partition PartitionMaskedCol1 = (aod::femtodreamcollision::bitmaskTrackOne & BitMask) == BitMask && aod::femtodreamcollision::downsample == true; - PartitionMaskedCol1.bindTable(cols); - Partition PartitionMaskedCol2 = (aod::femtodreamcollision::bitmaskTrackTwo & BitMask) == BitMask && aod::femtodreamcollision::downsample == true; - PartitionMaskedCol2.bindTable(cols); - // use *Partition.mFiltered when passing the partition to mixing object - // there is an issue when the partition is passed directly - // workaround for now, change back once it is fixed - for (auto const& [collision1, collision2] : combinations(soa::CombinationsBlockUpperIndexPolicy(policy, Mixing.Depth.value, -1, *PartitionMaskedCol1.mFiltered, *PartitionMaskedCol2.mFiltered))) { - // make sure that tracks in the same events are not mixed - if (collision1.globalIndex() == collision2.globalIndex()) { - continue; - } - auto SliceTrk1 = part1->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); - auto SliceTrk2 = part2->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); - for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(SliceTrk1, SliceTrk2))) { - if (Option.CPROn.value) { - if (pairCloseRejectionME.isClosePair(p1, p2, parts, collision1.magField())) { - continue; + // In the other case where the two particles are not the same species and we do not mix event with pairs, we only need to define one partition of collisions and make self combinations + + // define a lambda function for the mixing with selfCombinations policy + auto MixEvents = [policy, &part1, &part2, parts, this](auto& partition) { + for (auto const& [collision1, collision2] : selfCombinations(policy, Mixing.Depth.value, -1, *partition.mFiltered, *partition.mFiltered)) { + auto SliceTrk1 = part1->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); + auto SliceTrk2 = part2->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(SliceTrk1, SliceTrk2))) { + if (Option.CPROn.value) { + if (pairCloseRejectionME.isClosePair(p1, p2, parts, collision1.magField())) { + continue; + } } + mixedEventCont.setPair(p1, p2, collision1.multNtr(), collision1.multV0M(), Option.Use4D.value, Option.ExtendedPlots.value, Option.SmearingByOrigin.value); } - mixedEventCont.setPair(p1, p2, collision1.multNtr(), collision1.multV0M(), Option.Use4D, Option.ExtendedPlots, Option.SmearingByOrigin); } + }; + if (Option.SameSpecies.value && Option.MixEventWithPairs.value) { + // in case of mixing the same species and events that contain pairs, check for bitmask of particle two + // when same species is set to true the bit of particle two is only set if the event contains at least two selected particles + Partition PartitionMaskedCol1 = ncheckbit(aod::femtodreamcollision::bitmaskTrackTwo, BitMask) && aod::femtodreamcollision::downsample == true; + PartitionMaskedCol1.bindTable(cols); + MixEvents(PartitionMaskedCol1); + } else if (Option.SameSpecies.value && !Option.MixEventWithPairs.value) { + // in case of mixing the same species and events that contain at least one selected paritcle, check for bitmask of particle one + Partition PartitionMaskedCol1 = ncheckbit(aod::femtodreamcollision::bitmaskTrackOne, BitMask) && aod::femtodreamcollision::downsample == true; + PartitionMaskedCol1.bindTable(cols); + MixEvents(PartitionMaskedCol1); + } else if (!Option.SameSpecies.value && Option.MixEventWithPairs.value) { + // in case of mixing different species and events that contain a pair of selected paritcles, check for both bitmasks of paritcle one and particle two + Partition PartitionMaskedCol1 = ncheckbit(aod::femtodreamcollision::bitmaskTrackOne, BitMask) && ncheckbit(aod::femtodreamcollision::bitmaskTrackTwo, BitMask) && aod::femtodreamcollision::downsample == true; + PartitionMaskedCol1.bindTable(cols); + MixEvents(PartitionMaskedCol1); } } } diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackV0.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackV0.cxx index 103e8a22b82..fccbb1716a8 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackV0.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackV0.cxx @@ -16,13 +16,13 @@ #include #include #include +#include #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" #include "Framework/ASoAHelpers.h" #include "Framework/RunningWorkflowInfo.h" #include "Framework/Expressions.h" -#include "Framework/StepTHn.h" #include "PWGCF/DataModel/FemtoDerived.h" #include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" @@ -45,149 +45,172 @@ struct femtoDreamPairTaskTrackV0 { /// General options struct : ConfigurableGroup { - Configurable IsMC{"Option.IsMC", false, "Enable additional Histogramms in the case of a MonteCarlo Run"}; - Configurable Use4D{"Option.Use4D", false, "Enable four dimensional histogramms (to be used only for analysis with high statistics): k* vs multiplicity vs multiplicity percentil vs mT"}; - Configurable ExtendedPlots{"Option.ExtendedPlots", false, "Enable additional three dimensional histogramms. High memory consumption. Use for debugging"}; - Configurable HighkstarCut{"Option.HighkstarCut", -1., "Set a cut for high k*, above which the pairs are rejected. Set it to -1 to deactivate it"}; - Configurable CPROn{"Option.CPROn", true, "Close Pair Rejection"}; - Configurable CPROld{"Option.CPROld", false, "Set to FALSE to use fixed version of CPR (for testing now, will be default soon)"}; - Configurable CPRPlotPerRadii{"Option.CPRPlotPerRadii", false, "Plot CPR per radii"}; - Configurable CPRdeltaPhiMax{"Option.CPRdeltaPhiMax", 0.01, "Max. Delta Phi for Close Pair Rejection"}; - Configurable CPRdeltaEtaMax{"Option.CPRdeltaEtaMax", 0.01, "Max. Delta Eta for Close Pair Rejection"}; - Configurable smearingByOrigin{"Option.smearingByOrigin", false, "Obtain the smearing matrix differential in the MC origin of particle 1 and particle 2. High memory consumption. Use with care!"}; - ConfigurableAxis Dummy{"Option.Dummy", {1, 0, 1}, "Dummy axis"}; + std::string prefix = std::string("Option"); + Configurable IsMC{"IsMC", false, "Enable additional Histogramms in the case of a MonteCarlo Run"}; + Configurable Use4D{"Use4D", false, "Enable four dimensional histogramms (to be used only for analysis with high statistics): k* vs multiplicity vs multiplicity percentil vs mT"}; + Configurable ExtendedPlots{"ExtendedPlots", false, "Enable additional three dimensional histogramms. High memory consumption. Use for debugging"}; + Configurable HighkstarCut{"HighkstarCut", -1., "Set a cut for high k*, above which the pairs are rejected. Set it to -1 to deactivate it"}; + Configurable CPROn{"CPROn", true, "Close Pair Rejection"}; + Configurable CPROld{"CPROld", false, "Set to FALSE to use fixed version of CPR (for testing now, will be default soon)"}; + Configurable CPRPlotPerRadii{"CPRPlotPerRadii", false, "Plot CPR per radii"}; + Configurable CPRdeltaPhiMax{"CPRdeltaPhiMax", 0.01, "Max. Delta Phi for Close Pair Rejection"}; + Configurable CPRdeltaEtaMax{"CPRdeltaEtaMax", 0.01, "Max. Delta Eta for Close Pair Rejection"}; + Configurable DCACutPtDep{"DCACutPtDep", false, "Use pt dependent dca cut"}; + Configurable MixEventWithPairs{"MixEventWithPairs", false, "Only use events that contain particle 1 and partile 2 for the event mixing"}; + Configurable smearingByOrigin{"smearingByOrigin", false, "Obtain the smearing matrix differential in the MC origin of particle 1 and particle 2. High memory consumption. Use with care!"}; + ConfigurableAxis Dummy{"Dummy", {1, 0, 1}, "Dummy axis"}; } Option; /// Event selection struct : ConfigurableGroup { - Configurable MultMin{"EventSel.MultMin", 0, "Minimum Multiplicity (MultNtr)"}; - Configurable MultMax{"EventSel.MultMax", 99999, "Maximum Multiplicity (MultNtr)"}; - Configurable MultPercentileMin{"EventSel.MultPercentileMin", 0, "Minimum Multiplicity Percentile"}; - Configurable MultPercentileMax{"EventSel.MultPercentileMax", 100, "Maximum Multiplicity Percentile"}; + std::string prefix = std::string("EventSel"); + Configurable MultMin{"MultMin", 0, "Minimum Multiplicity (MultNtr)"}; + Configurable MultMax{"MultMax", 99999, "Maximum Multiplicity (MultNtr)"}; + Configurable MultPercentileMin{"MultPercentileMin", 0, "Minimum Multiplicity Percentile"}; + Configurable MultPercentileMax{"MultPercentileMax", 100, "Maximum Multiplicity Percentile"}; } EventSel; Filter EventMultiplicity = aod::femtodreamcollision::multNtr >= EventSel.MultMin && aod::femtodreamcollision::multNtr <= EventSel.MultMax; Filter EventMultiplicityPercentile = aod::femtodreamcollision::multV0M >= EventSel.MultPercentileMin && aod::femtodreamcollision::multV0M <= EventSel.MultPercentileMax; + /// Histogramming for Event + FemtoDreamEventHisto eventHisto; + using FilteredMaskedCollisions = soa::Filtered>; using FilteredMaskedCollision = FilteredMaskedCollisions::iterator; using FilteredMaskedMCCollisions = soa::Filtered>; using FilteredMaskedMCCollision = FilteredMaskedMCCollisions::iterator; - femtodreamcollision::BitMaskType BitMask = -1; + using FDMCParts = soa::Join; + using FDMCPart = FDMCParts::iterator; + + femtodreamcollision::BitMaskType BitMask = 1; /// Particle 1 (track) struct : ConfigurableGroup { - Configurable PDGCode{"Track1.PDGCode", 2212, "PDG code of Particle 1 (Track)"}; - Configurable CutBit{"Track1.CutBit", 5542474, "Particle 1 (Track) - Selection bit from cutCulator"}; - Configurable TPCBit{"Track1.TPCBit", 4, "PID TPC bit from cutCulator for particle 1 (Track)"}; - Configurable TPCBit_Reject{"Track1.TPCBit_Reject", 0, "Reject PID TPC bit from cutCulator for particle 1 (Track). Set to 0 to turn off"}; - Configurable TPCTOFBit{"Track1.TPCTOFBit", 2, "PID TPCTOF bit from cutCulator for particle 1 (Track)"}; - Configurable PIDThres{"Track1.PIDThres", 0.75, "Momentum threshold for PID selection for particle 1 (Track)"}; - Configurable PtMin{"Track1.PtMin", 0., "Minimum pT of partricle 1 (Track)"}; - Configurable PtMax{"Track1.PtMax", 999., "Maximum pT of partricle 1 (Track)"}; - Configurable EtaMin{"Track1.EtaMin", -10., "Minimum eta of partricle 1 (Track)"}; - Configurable EtaMax{"Track1.EtaMax", 10., "Maximum eta of partricle 1 (Track)"}; - Configurable TempFitVarMin{"Track1.TempFitVarMin", -10., "Minimum DCAxy of partricle 1 (Track)"}; - Configurable TempFitVarMax{"Track1.TempFitVarMax", 10., "Maximum DCAxy of partricle 1 (Track)"}; + std::string prefix = std::string("Track1"); + Configurable PDGCode{"PDGCode", 2212, "PDG code of Particle 1 (Track)"}; + Configurable CutBit{"CutBit", 5542474, "Particle 1 (Track) - Selection bit from cutCulator"}; + Configurable TPCBit{"TPCBit", 4, "PID TPC bit from cutCulator for particle 1 (Track)"}; + Configurable TPCBit_Reject{"TPCBit_Reject", 0, "Reject PID TPC bit from cutCulator for particle 1 (Track). Set to 0 to turn off"}; + Configurable TPCTOFBit{"TPCTOFBit", 2, "PID TPCTOF bit from cutCulator for particle 1 (Track)"}; + Configurable PIDThres{"PIDThres", 0.75, "Momentum threshold for PID selection for particle 1 (Track)"}; + Configurable PtMin{"PtMin", 0., "Minimum pT of partricle 1 (Track)"}; + Configurable PtMax{"PtMax", 999., "Maximum pT of partricle 1 (Track)"}; + Configurable EtaMin{"EtaMin", -10., "Minimum eta of partricle 1 (Track)"}; + Configurable EtaMax{"EtaMax", 10., "Maximum eta of partricle 1 (Track)"}; + Configurable TempFitVarMin{"TempFitVarMin", -10., "Minimum DCAxy of partricle 1 (Track)"}; + Configurable TempFitVarMax{"TempFitVarMax", 10., "Maximum DCAxy of partricle 1 (Track)"}; } Track1; - Filter trackPtFilterUp = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack), aod::femtodreamparticle::pt > Track1.PtMin, true); - Filter trackPtFilterLow = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack), aod::femtodreamparticle::pt < Track1.PtMax, true); - Filter trackEtaFilterUp = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack), aod::femtodreamparticle::eta > Track1.EtaMin, true); - Filter trackEtaFilterLow = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack), aod::femtodreamparticle::eta < Track1.EtaMax, true); - Filter trackTempFitVarFilterUp = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack), aod::femtodreamparticle::tempFitVar > Track1.TempFitVarMin, true); - Filter trackTempFitVarFilterLow = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack), aod::femtodreamparticle::tempFitVar < Track1.TempFitVarMax, true); + /// Partition for particle 1 + Partition PartitionTrk1 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && + (ncheckbit(aod::femtodreamparticle::cut, Track1.CutBit)) && + ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= Track1.PIDThres, ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCBit) && ((aod::femtodreamparticle::pidcut & Track1.TPCBit_Reject) == 0u), ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCTOFBit)) && + (aod::femtodreamparticle::pt > Track1.PtMin) && + (aod::femtodreamparticle::pt < Track1.PtMax) && + (aod::femtodreamparticle::eta > Track1.EtaMin) && + (aod::femtodreamparticle::eta < Track1.EtaMax) && + ifnode(Option.DCACutPtDep, (nabs(aod::femtodreamparticle::tempFitVar) <= 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f))), + ((aod::femtodreamparticle::tempFitVar >= Track1.TempFitVarMin) && + (aod::femtodreamparticle::tempFitVar <= Track1.TempFitVarMax))); + + Partition PartitionMCTrk1 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && + (ncheckbit(aod::femtodreamparticle::cut, Track1.CutBit)) && + ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= Track1.PIDThres, ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCBit) && ((aod::femtodreamparticle::pidcut & Track1.TPCBit_Reject) == 0u), ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCTOFBit)) && + (aod::femtodreamparticle::pt > Track1.PtMin) && + (aod::femtodreamparticle::pt < Track1.PtMax) && + (aod::femtodreamparticle::eta > Track1.EtaMin) && + (aod::femtodreamparticle::eta < Track1.EtaMax) && + ifnode(Option.DCACutPtDep, (nabs(aod::femtodreamparticle::tempFitVar) <= 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f))), + ((aod::femtodreamparticle::tempFitVar >= Track1.TempFitVarMin) && + (aod::femtodreamparticle::tempFitVar <= Track1.TempFitVarMax))); /// Histogramming for particle 1 FemtoDreamParticleHisto trackHistoPartOne; /// Particle 2 (V0) struct : ConfigurableGroup { - Configurable PDGCode{"V02.PDGCode", 3122, "PDG code of particle 2 (V0)"}; - Configurable CutBit{"V02.CutBit", 338, "Selection bit for particle 2 (V0)"}; - Configurable ChildPos_CutBit{"V02.ChildPos_CutBit", 149, "Selection bit for positive child of V0"}; - Configurable ChildPos_TPCBit{"V02.ChildPos_TPCBit", 2, "PID TPC bit for positive child of V0"}; - Configurable ChildNeg_CutBit{"V02.ChildNeg_CutBit", 149, "Selection bit for negative child of V0"}; - Configurable ChildNeg_TPCBit{"V02.ChildNeg_TPCBit", 2, "PID TPC bit for negative child of V0"}; - - Configurable InvMassMin{"V02.InvMassMin", 1.08, "Minimum invariant mass of Partricle 2 (particle) (V0)"}; - Configurable InvMassMax{"V02.InvMassMax", 1.15, "Maximum invariant mass of Partricle 2 (particle) (V0)"}; - Configurable InvMassAntiMin{"V02.InvMassAntiMin", 0., "Minimum invariant mass of Partricle 2 (antiparticle) (V0)"}; - Configurable InvMassAntiMax{"V02.InvMassAntiMax", 999., "Maximum invariant mass of Partricle 2 (antiparticle) (V0)"}; - - Configurable PtMin{"V02.PtMin", 0., "Minimum pT of Partricle 2 (V0)"}; - Configurable PtMax{"V02.PtMax", 999., "Maximum pT of Partricle 2 (V0)"}; - Configurable EtaMin{"V02.EtaMin", -10., "Minimum eta of Partricle 2 (V0)"}; - Configurable EtaMax{"V02.EtaMax", 10., "Maximum eta of Partricle 2 (V0)"}; + std::string prefix = std::string("V02"); + Configurable PDGCode{"PDGCode", 3122, "PDG code of particle 2 (V0)"}; + Configurable CutBit{"CutBit", 338, "Selection bit for particle 2 (V0)"}; + Configurable ChildPos_CutBit{"ChildPos_CutBit", 149, "Selection bit for positive child of V0"}; + Configurable ChildPos_TPCBit{"ChildPos_TPCBit", 2, "PID TPC bit for positive child of V0"}; + Configurable ChildNeg_CutBit{"ChildNeg_CutBit", 149, "Selection bit for negative child of V0"}; + Configurable ChildNeg_TPCBit{"ChildNeg_TPCBit", 2, "PID TPC bit for negative child of V0"}; + + Configurable InvMassMin{"InvMassMin", 1.08, "Minimum invariant mass of Partricle 2 (particle) (V0)"}; + Configurable InvMassMax{"InvMassMax", 1.15, "Maximum invariant mass of Partricle 2 (particle) (V0)"}; + Configurable InvMassAntiMin{"InvMassAntiMin", 0., "Minimum invariant mass of Partricle 2 (antiparticle) (V0)"}; + Configurable InvMassAntiMax{"InvMassAntiMax", 999., "Maximum invariant mass of Partricle 2 (antiparticle) (V0)"}; + + Configurable PtMin{"PtMin", 0., "Minimum pT of Partricle 2 (V0)"}; + Configurable PtMax{"PtMax", 999., "Maximum pT of Partricle 2 (V0)"}; + Configurable EtaMin{"EtaMin", -10., "Minimum eta of Partricle 2 (V0)"}; + Configurable EtaMax{"EtaMax", 10., "Maximum eta of Partricle 2 (V0)"}; } V02; - Filter v0MassFilterUp = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0), aod::femtodreamparticle::mLambda > V02.InvMassMin, true); - Filter v0MassFilterLow = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0), aod::femtodreamparticle::mLambda < V02.InvMassMax, true); - Filter antiv0MassFilterUp = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0), aod::femtodreamparticle::mAntiLambda > V02.InvMassAntiMin, true); - Filter antiv0MassFilterLow = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0), aod::femtodreamparticle::mAntiLambda < V02.InvMassAntiMax, true); - - Filter v0PtFilterUp = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0), aod::femtodreamparticle::pt > V02.PtMin, true); - Filter v0PtFilterLow = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0), aod::femtodreamparticle::pt < V02.PtMax, true); - Filter v0EtaFilterUp = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0), aod::femtodreamparticle::eta > V02.EtaMin, true); - Filter v0EtaFilterLow = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0), aod::femtodreamparticle::eta < V02.EtaMax, true); + /// Partition for particle 2 + Partition PartitionV02 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0)) && + ((aod::femtodreamparticle::cut & V02.CutBit) == V02.CutBit) && + (aod::femtodreamparticle::pt > V02.PtMin) && + (aod::femtodreamparticle::pt < V02.PtMax) && + (aod::femtodreamparticle::eta > V02.EtaMin) && + (aod::femtodreamparticle::eta < V02.EtaMax) && + (aod::femtodreamparticle::mLambda > V02.InvMassMin) && + (aod::femtodreamparticle::mLambda < V02.InvMassMax) && + (aod::femtodreamparticle::mAntiLambda > V02.InvMassAntiMin) && + (aod::femtodreamparticle::mAntiLambda < V02.InvMassAntiMax); + + Partition PartitionMCV02 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0)) && + ((aod::femtodreamparticle::cut & V02.CutBit) == V02.CutBit) && + (aod::femtodreamparticle::pt > V02.PtMin) && + (aod::femtodreamparticle::pt < V02.PtMax) && + (aod::femtodreamparticle::eta > V02.EtaMax) && + (aod::femtodreamparticle::eta < V02.EtaMin) && + (aod::femtodreamparticle::mLambda > V02.InvMassMin) && + (aod::femtodreamparticle::mLambda < V02.InvMassMax) && + (aod::femtodreamparticle::mAntiLambda > V02.InvMassAntiMin) && + (aod::femtodreamparticle::mAntiLambda < V02.InvMassAntiMax); /// Histogramming for particle 2 FemtoDreamParticleHisto trackHistoPartTwo; FemtoDreamParticleHisto posChildHistos; FemtoDreamParticleHisto negChildHistos; - using FilteredFDParticles = soa::Filtered; - using FilteredFDParticle = FilteredFDParticles::iterator; - - using FilteredFDMCParts = soa::Filtered>; - using FilteredFDMCPart = FilteredFDMCParts::iterator; - - /// Partition for particle 1 - Partition PartitionTrk1 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && - (ncheckbit(aod::femtodreamparticle::cut, Track1.CutBit)) && - ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= Track1.PIDThres, ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCBit) && ((aod::femtodreamparticle::pidcut & Track1.TPCBit_Reject) == 0u), ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCTOFBit)); - Partition PartitionMCTrk1 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && - (ncheckbit(aod::femtodreamparticle::cut, Track1.CutBit)) && - ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= Track1.PIDThres, ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCBit) && ((aod::femtodreamparticle::pidcut & Track1.TPCBit_Reject) == 0u), ncheckbit(aod::femtodreamparticle::pidcut, Track1.TPCTOFBit)); - - /// Partition for particle 2 - Partition PartitionV02 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0)) && ((aod::femtodreamparticle::cut & V02.CutBit) == V02.CutBit); - Partition PartitionMCV02 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0)) && ((aod::femtodreamparticle::cut & V02.CutBit) == V02.CutBit); - - /// Histogramming for Event - FemtoDreamEventHisto eventHisto; - /// Binning configurables struct : ConfigurableGroup { - ConfigurableAxis TempFitVarTrack{"Binning.TempFitVarTrack", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot (Track)"}; - ConfigurableAxis TempFitVarV0{"Binning.TempFitVarV0", {300, 0.9, 1}, "binning of the TempFitVar in the pT vs. TempFitVar plot (V0)"}; - ConfigurableAxis TempFitVarV0Child{"Binning.TempFitVarV0Child", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot (V0 child)"}; - ConfigurableAxis InvMass{"Binning.InvMass", {200, 1, 1.2}, "InvMass binning"}; - ConfigurableAxis pTTrack{"Binning.pTTrack", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot (Track)"}; - ConfigurableAxis pTV0{"Binning.pTV0", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot (V0)"}; - ConfigurableAxis pTV0Child{"Binning.pTV0Child", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot (V0)"}; - ConfigurableAxis pT{"Binning.pT", {20, 0.5, 4.05}, "pT binning"}; - ConfigurableAxis kstar{"Binning.kstar", {1500, 0., 6.}, "binning kstar"}; - ConfigurableAxis kT{"Binning.kT", {150, 0., 9.}, "binning kT"}; - ConfigurableAxis mT{"Binning.mT", {225, 0., 7.5}, "binning mT"}; - ConfigurableAxis multTempFit{"Binning.multTempFit", {1, 0, 1}, "multiplicity Binning for the TempFitVar plot"}; + std::string prefix = std::string("Binning"); + ConfigurableAxis TempFitVarTrack{"TempFitVarTrack", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot (Track)"}; + ConfigurableAxis TempFitVarV0{"TempFitVarV0", {300, 0.9, 1}, "binning of the TempFitVar in the pT vs. TempFitVar plot (V0)"}; + ConfigurableAxis TempFitVarV0Child{"TempFitVarV0Child", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot (V0 child)"}; + ConfigurableAxis InvMass{"InvMass", {200, 1, 1.2}, "InvMass binning"}; + ConfigurableAxis pTTrack{"pTTrack", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot (Track)"}; + ConfigurableAxis pTV0{"pTV0", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot (V0)"}; + ConfigurableAxis pTV0Child{"pTV0Child", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot (V0)"}; + ConfigurableAxis pT{"pT", {20, 0.5, 4.05}, "pT binning"}; + ConfigurableAxis kstar{"kstar", {1500, 0., 6.}, "binning kstar"}; + ConfigurableAxis kT{"kT", {150, 0., 9.}, "binning kT"}; + ConfigurableAxis mT{"mT", {225, 0., 7.5}, "binning mT"}; + ConfigurableAxis multTempFit{"multTempFit", {1, 0, 1}, "multiplicity for the TempFitVar plot"}; } Binning; struct : ConfigurableGroup { - ConfigurableAxis kstar{"Binning4D.kstar", {1500, 0., 6.}, "binning kstar for the 4Dimensional plot: k* vs multiplicity vs multiplicity percentile vs mT (set <> to true in order to use)"}; - ConfigurableAxis mT{"Binning4D.mT", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 4Dimensional plot: k* vs multiplicity vs multiplicity percentile vs mT (set <> to true in order to use)"}; - ConfigurableAxis Mult{"Binning4D.mult", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f}, "multiplicity Binning for the 4Dimensional plot: k* vs multiplicity vs multiplicity percentile vs mT (set <> to true in order to use)"}; - ConfigurableAxis multPercentile{"Binning4D.multPercentile", {10, 0.0f, 100.0f}, "multiplicity percentile Binning for the 4Dimensional plot: k* vs multiplicity vs multiplicity percentile vs mT (set <> to true in order to use)"}; + std::string prefix = std::string("Binning4D"); + ConfigurableAxis kstar{"kstar", {1500, 0., 6.}, "binning kstar for the 4Dimensional plot: k* vs multiplicity vs multiplicity percentile vs mT (set <> to true in order to use)"}; + ConfigurableAxis mT{"mT", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 4Dimensional plot: k* vs multiplicity vs multiplicity percentile vs mT (set <> to true in order to use)"}; + ConfigurableAxis Mult{"mult", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f}, "multiplicity Binning for the 4Dimensional plot: k* vs multiplicity vs multiplicity percentile vs mT (set <> to true in order to use)"}; + ConfigurableAxis multPercentile{"multPercentile", {10, 0.0f, 100.0f}, "multiplicity percentile Binning for the 4Dimensional plot: k* vs multiplicity vs multiplicity percentile vs mT (set <> to true in order to use)"}; } Binning4D; // Mixing configurables struct : ConfigurableGroup { - ConfigurableAxis BinMult{"Mixing.BinMult", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f}, "Mixing bins - multiplicity"}; - ConfigurableAxis BinMultPercentile{"Mixing.BinMultPercentile", {VARIABLE_WIDTH, 0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.f}, "Mixing bins - multiplicity percentile"}; - ConfigurableAxis BinVztx{"Mixing.BinVztx", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - Configurable Depth{"Mixing.Depth", 5, "Number of events for mixing"}; - Configurable Policy{"Mixing.BinPolicy", 0, "Binning policy for mixing - 0: multiplicity, 1: multipliciy percentile, 2: both"}; + std::string prefix = std::string("Mixing"); + ConfigurableAxis BinMult{"BinMult", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f}, "bins - multiplicity"}; + ConfigurableAxis BinMultPercentile{"BinMultPercentile", {VARIABLE_WIDTH, 0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.f}, "bins - multiplicity percentile"}; + ConfigurableAxis BinVztx{"BinVztx", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "bins - z-vertex"}; + Configurable Depth{"Depth", 5, "Number of events for mixing"}; + Configurable Policy{"BinPolicy", 0, "Binning policy for mixing - 0: multiplicity, 1: multipliciy percentile, 2: both"}; } Mixing; ColumnBinningPolicy colBinningMult{{Mixing.BinVztx, Mixing.BinMult}, true}; @@ -201,21 +224,22 @@ struct femtoDreamPairTaskTrackV0 { FemtoDreamDetaDphiStar pairCloseRejectionME; /// Histogram output - HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry resultRegistry{"Correlations", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry Registry{"Output", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext& context) { - eventHisto.init(&qaRegistry, Option.IsMC); - // void init(HistogramRegistry* registry, - // T& MomentumBins, T& tempFitVarBins, T& NsigmaTPCBins, T& NsigmaTOFBins, T& NsigmaTPCTOFBins, T& InvMassBins, - // bool isMC, int pdgCode, bool isDebug = false) - trackHistoPartOne.init(&qaRegistry, Binning.multTempFit, Option.Dummy, Binning.pTTrack, Option.Dummy, Option.Dummy, Binning.TempFitVarTrack, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.IsMC, Track1.PDGCode); - trackHistoPartTwo.init(&qaRegistry, Binning.multTempFit, Option.Dummy, Binning.pTV0, Option.Dummy, Option.Dummy, Binning.TempFitVarV0, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Binning.InvMass, Option.IsMC, V02.PDGCode); - posChildHistos.init(&qaRegistry, Binning.multTempFit, Option.Dummy, Binning.pTV0Child, Option.Dummy, Option.Dummy, Binning.TempFitVarV0Child, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, false, 0); - negChildHistos.init(&qaRegistry, Binning.multTempFit, Option.Dummy, Binning.pTV0Child, Option.Dummy, Option.Dummy, Binning.TempFitVarV0Child, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, false, 0); - - sameEventCont.init(&resultRegistry, + // setup binnnig policy for mixing + colBinningMult = {{Mixing.BinVztx, Mixing.BinMult}, true}; + colBinningMultPercentile = {{Mixing.BinVztx, Mixing.BinMultPercentile}, true}; + colBinningMultMultPercentile = {{Mixing.BinVztx, Mixing.BinMult, Mixing.BinMultPercentile}, true}; + + eventHisto.init(&Registry, Option.IsMC); + trackHistoPartOne.init(&Registry, Binning.multTempFit, Option.Dummy, Binning.pTTrack, Option.Dummy, Option.Dummy, Binning.TempFitVarTrack, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.IsMC, Track1.PDGCode); + trackHistoPartTwo.init(&Registry, Binning.multTempFit, Option.Dummy, Binning.pTV0, Option.Dummy, Option.Dummy, Binning.TempFitVarV0, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Binning.InvMass, Option.Dummy, Option.IsMC, V02.PDGCode); + posChildHistos.init(&Registry, Binning.multTempFit, Option.Dummy, Binning.pTV0Child, Option.Dummy, Option.Dummy, Binning.TempFitVarV0Child, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, false, 0); + negChildHistos.init(&Registry, Binning.multTempFit, Option.Dummy, Binning.pTV0Child, Option.Dummy, Option.Dummy, Binning.TempFitVarV0Child, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, false, 0); + + sameEventCont.init(&Registry, Binning.kstar, Binning.pT, Binning.kT, Binning.mT, Mixing.BinMult, Mixing.BinMultPercentile, Binning4D.kstar, Binning4D.mT, Binning4D.Mult, Binning4D.multPercentile, Option.IsMC, Option.Use4D, Option.ExtendedPlots, @@ -223,7 +247,7 @@ struct femtoDreamPairTaskTrackV0 { Option.smearingByOrigin); sameEventCont.setPDGCodes(Track1.PDGCode, V02.PDGCode); - mixedEventCont.init(&resultRegistry, + mixedEventCont.init(&Registry, Binning.kstar, Binning.pT, Binning.kT, Binning.mT, Mixing.BinMult, Mixing.BinMultPercentile, Binning4D.kstar, Binning4D.mT, Binning4D.Mult, Binning4D.multPercentile, Option.IsMC, Option.Use4D, Option.ExtendedPlots, @@ -231,10 +255,10 @@ struct femtoDreamPairTaskTrackV0 { Option.smearingByOrigin); mixedEventCont.setPDGCodes(Track1.PDGCode, V02.PDGCode); - pairCleaner.init(&qaRegistry); + pairCleaner.init(&Registry); if (Option.CPROn.value) { - pairCloseRejectionSE.init(&resultRegistry, &qaRegistry, Option.CPRdeltaPhiMax.value, Option.CPRdeltaEtaMax.value, Option.CPRPlotPerRadii.value, 1, Option.CPROld.value); - pairCloseRejectionME.init(&resultRegistry, &qaRegistry, Option.CPRdeltaPhiMax.value, Option.CPRdeltaEtaMax.value, Option.CPRPlotPerRadii.value, 2, Option.CPROld.value, 8, true); + pairCloseRejectionSE.init(&Registry, &Registry, Option.CPRdeltaPhiMax.value, Option.CPRdeltaEtaMax.value, Option.CPRPlotPerRadii.value, 1, Option.CPROld.value); + pairCloseRejectionME.init(&Registry, &Registry, Option.CPRdeltaPhiMax.value, Option.CPRdeltaEtaMax.value, Option.CPRPlotPerRadii.value, 2, Option.CPROld.value, 99, true); } // get bit for the collision mask @@ -328,9 +352,9 @@ struct femtoDreamPairTaskTrackV0 { } } - void processSameEventMasked(FilteredMaskedCollision const& col, FilteredFDParticles const& parts) + void processSameEventMasked(FilteredMaskedCollision const& col, FDParticles const& parts) { - if ((col.bitmaskTrackOne() & BitMask) != BitMask && (col.bitmaskTrackTwo() & BitMask) != BitMask) { + if ((col.bitmaskTrackOne() & BitMask) != BitMask || (col.bitmaskTrackTwo() & BitMask) != BitMask) { return; } eventHisto.fillQA(col); @@ -340,7 +364,7 @@ struct femtoDreamPairTaskTrackV0 { } PROCESS_SWITCH(femtoDreamPairTaskTrackV0, processSameEventMasked, "Enable processing same event with masks", true); - void processSameEventMCMasked(FilteredMaskedMCCollision const& col, o2::aod::FDMCCollisions&, FilteredFDMCParts const& parts, o2::aod::FDMCParticles const&) + void processSameEventMCMasked(FilteredMaskedMCCollision const& col, o2::aod::FDMCCollisions&, FDMCParts const& parts, o2::aod::FDMCParticles const&) { if ((col.bitmaskTrackOne() & BitMask) != BitMask && (col.bitmaskTrackTwo() & BitMask) != BitMask) { return; @@ -355,45 +379,82 @@ struct femtoDreamPairTaskTrackV0 { template void doMixedEvent_Masked(CollisionType const& cols, PartType const& parts, PartitionType& part1, PartitionType& part2, BinningType policy) { - Partition PartitionMaskedCol1 = (aod::femtodreamcollision::bitmaskTrackOne & BitMask) == BitMask && aod::femtodreamcollision::downsample == true; - Partition PartitionMaskedCol2 = (aod::femtodreamcollision::bitmaskTrackTwo & BitMask) == BitMask && aod::femtodreamcollision::downsample == true; - PartitionMaskedCol1.bindTable(cols); - PartitionMaskedCol2.bindTable(cols); - - // use *Partition.mFiltered when passing the partition to mixing object - // there is an issue when the partition is passed directly - // workaround for now, change back once it is fixed - for (auto const& [collision1, collision2] : combinations(soa::CombinationsBlockUpperIndexPolicy(policy, Mixing.Depth.value, -1, *PartitionMaskedCol1.mFiltered, *PartitionMaskedCol2.mFiltered))) { - // make sure that tracks in same events are not mixed - if (collision1.globalIndex() == collision2.globalIndex()) { - continue; - } - auto SliceTrk1 = part1->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); - auto SliceV02 = part2->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); - for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(SliceTrk1, SliceV02))) { - const auto& posChild = parts.iteratorAt(p2.index() - 2); - const auto& negChild = parts.iteratorAt(p2.index() - 1); - // check cuts on V0 children - if (((posChild.cut() & V02.ChildPos_CutBit) == V02.ChildPos_CutBit) && - ((posChild.pidcut() & V02.ChildPos_TPCBit) == V02.ChildPos_TPCBit) && - ((negChild.cut() & V02.ChildNeg_CutBit) == V02.ChildNeg_CutBit) && - ((negChild.pidcut() & V02.ChildNeg_TPCBit) == V02.ChildNeg_TPCBit)) { + + if (Option.MixEventWithPairs.value) { + Partition PartitionMaskedCol = ncheckbit(aod::femtodreamcollision::bitmaskTrackOne, BitMask) && ncheckbit(aod::femtodreamcollision::bitmaskTrackTwo, BitMask) && aod::femtodreamcollision::downsample == true; + PartitionMaskedCol.bindTable(cols); + // use *Partition.mFiltered when passing the partition to mixing object + // there is an issue when the partition is passed directly + // workaround for now, change back once it is fixed + for (auto const& [collision1, collision2] : selfCombinations(policy, Mixing.Depth.value, -1, *PartitionMaskedCol.mFiltered, *PartitionMaskedCol.mFiltered)) { + // make sure that tracks in same events are not mixed + if (collision1.globalIndex() == collision2.globalIndex()) { continue; } - if (Option.CPROn.value) { - if (pairCloseRejectionME.isClosePair(p1, p2, parts, collision1.magField())) { + auto SliceTrk1 = part1->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); + auto SliceV02 = part2->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(SliceTrk1, SliceV02))) { + const auto& posChild = parts.iteratorAt(p2.index() - 2); + const auto& negChild = parts.iteratorAt(p2.index() - 1); + // check cuts on V0 children + if (((posChild.cut() & V02.ChildPos_CutBit) == V02.ChildPos_CutBit) && + ((posChild.pidcut() & V02.ChildPos_TPCBit) == V02.ChildPos_TPCBit) && + ((negChild.cut() & V02.ChildNeg_CutBit) == V02.ChildNeg_CutBit) && + ((negChild.pidcut() & V02.ChildNeg_TPCBit) == V02.ChildNeg_TPCBit)) { continue; } + if (Option.CPROn.value) { + if (pairCloseRejectionME.isClosePair(p1, p2, parts, collision1.magField())) { + continue; + } + } + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + mixedEventCont.setPair(p1, p2, collision1.multNtr(), collision1.multV0M(), Option.Use4D, Option.ExtendedPlots, Option.smearingByOrigin); } - if (!pairCleaner.isCleanPair(p1, p2, parts)) { + } + } else { + Partition PartitionMaskedCol1 = ncheckbit(aod::femtodreamcollision::bitmaskTrackOne, BitMask) && aod::femtodreamcollision::downsample == true; + Partition PartitionMaskedCol2 = ncheckbit(aod::femtodreamcollision::bitmaskTrackTwo, BitMask) && aod::femtodreamcollision::downsample == true; + PartitionMaskedCol1.bindTable(cols); + PartitionMaskedCol2.bindTable(cols); + + // use *Partition.mFiltered when passing the partition to mixing object + // there is an issue when the partition is passed directly + // workaround for now, change back once it is fixed + for (auto const& [collision1, collision2] : combinations(soa::CombinationsBlockUpperIndexPolicy(policy, Mixing.Depth.value, -1, *PartitionMaskedCol1.mFiltered, *PartitionMaskedCol2.mFiltered))) { + // make sure that tracks in same events are not mixed + if (collision1.globalIndex() == collision2.globalIndex()) { continue; } - mixedEventCont.setPair(p1, p2, collision1.multNtr(), collision1.multV0M(), Option.Use4D, Option.ExtendedPlots, Option.smearingByOrigin); + auto SliceTrk1 = part1->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); + auto SliceV02 = part2->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(SliceTrk1, SliceV02))) { + const auto& posChild = parts.iteratorAt(p2.index() - 2); + const auto& negChild = parts.iteratorAt(p2.index() - 1); + // check cuts on V0 children + if (((posChild.cut() & V02.ChildPos_CutBit) == V02.ChildPos_CutBit) && + ((posChild.pidcut() & V02.ChildPos_TPCBit) == V02.ChildPos_TPCBit) && + ((negChild.cut() & V02.ChildNeg_CutBit) == V02.ChildNeg_CutBit) && + ((negChild.pidcut() & V02.ChildNeg_TPCBit) == V02.ChildNeg_TPCBit)) { + continue; + } + if (Option.CPROn.value) { + if (pairCloseRejectionME.isClosePair(p1, p2, parts, collision1.magField())) { + continue; + } + } + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + mixedEventCont.setPair(p1, p2, collision1.multNtr(), collision1.multV0M(), Option.Use4D, Option.ExtendedPlots, Option.smearingByOrigin); + } } } } - void processMixedEventMasked(FilteredMaskedCollisions const& cols, FilteredFDParticles const& parts) + void processMixedEventMasked(FilteredMaskedCollisions const& cols, FDParticles const& parts) { switch (Mixing.Policy.value) { case femtodreamcollision::kMult: @@ -411,7 +472,7 @@ struct femtoDreamPairTaskTrackV0 { } PROCESS_SWITCH(femtoDreamPairTaskTrackV0, processMixedEventMasked, "Enable processing mixed events with masks", true); - void processMixedEventMCMasked(FilteredMaskedMCCollisions const& cols, o2::aod::FDMCCollisions&, FilteredFDMCParts const& parts, o2::aod::FDMCParticles const&) + void processMixedEventMCMasked(FilteredMaskedMCCollisions const& cols, o2::aod::FDMCCollisions&, FDMCParts const& parts, o2::aod::FDMCParticles const&) { switch (Mixing.Policy.value) { case femtodreamcollision::kMult: diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackTrack.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackTrack.cxx index f7a3902f73b..226eaa5c8fb 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackTrack.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackTrack.cxx @@ -14,6 +14,7 @@ /// \author Laura Serksnyte, TU München, laura.serksnyte@tum.de #include +#include #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" @@ -58,10 +59,13 @@ struct femtoDreamTripletTaskTrackTrackTrack { Configurable ConfMaxDCAxy{"ConfMaxDCAxy", -0.1f, "Maximum DCAxy of the particles"}; Configurable ConfMinDCAxy{"ConfMinDCAxy", 0.1f, "Minimum DCAxy of the particles"}; Configurable ConfPIDthrMom{"ConfPIDthrMom", 1.f, "Momentum threshold from which TPC and TOF are required for PID"}; + Configurable ConfAtWhichRadiiToCut{"ConfAtWhichRadiiToCut", 1, "At which radii perform deta dphi selection: 0 - at PV, 1 - averaged phi, 2 - at given radii"}; + Configurable ConfAtWhichTPCRadii{"ConfAtWhichTPCRadii", 85., "If ConfAtWhichRadiiToCut = 2; this allows to select at which TPC radii to cut"}; Configurable ConfTPCPIDBit{"ConfTPCPIDBit", 16, "PID TPC bit from cutCulator "}; Configurable ConfTPCTOFPIDBit{"ConfTPCTOFPIDBit", 8, "PID TPCTOF bit from cutCulator"}; Configurable ConfIsMC{"ConfIsMC", false, "Enable additional Histogramms in the case of a MonteCarlo Run"}; Configurable ConfUse3D{"ConfUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; + Configurable ConfDCACutPtDep{"ConfDCACutPtDep", false, "Use pt dependent dca cut for tracks"}; // Which particles to analyse; currently support only for same species and cuts triplets Configurable ConfPDGCodePart{"ConfPDGCodePart", 2212, "Particle PDG code"}; @@ -73,15 +77,20 @@ struct femtoDreamTripletTaskTrackTrackTrack { (ncheckbit(aod::femtodreamparticle::cut, ConfCutPart)) && (aod::femtodreamparticle::pt < ConfMaxpT) && (aod::femtodreamparticle::pt > ConfMinpT) && - (aod::femtodreamparticle::tempFitVar < ConfMaxDCAxy) && - (aod::femtodreamparticle::tempFitVar > ConfMinDCAxy); + ifnode(ConfDCACutPtDep, (nabs(aod::femtodreamparticle::tempFitVar) <= 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f))), + ((aod::femtodreamparticle::tempFitVar >= ConfMinDCAxy) && + (aod::femtodreamparticle::tempFitVar <= ConfMaxDCAxy))); + ; + Partition> SelectedPartsMC = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= ConfPIDthrMom, ncheckbit(aod::femtodreamparticle::pidcut, ConfTPCPIDBit), ncheckbit(aod::femtodreamparticle::pidcut, ConfTPCTOFPIDBit)) && (ncheckbit(aod::femtodreamparticle::cut, ConfCutPart)) && (aod::femtodreamparticle::pt < ConfMaxpT) && (aod::femtodreamparticle::pt > ConfMinpT) && - (aod::femtodreamparticle::tempFitVar < ConfMaxDCAxy) && - (aod::femtodreamparticle::tempFitVar > ConfMinDCAxy); + ifnode(ConfDCACutPtDep, (nabs(aod::femtodreamparticle::tempFitVar) <= 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f))), + ((aod::femtodreamparticle::tempFitVar >= ConfMinDCAxy) && + (aod::femtodreamparticle::tempFitVar <= ConfMaxDCAxy))); + ; /// Histogramming of Selected Particles FemtoDreamParticleHisto trackHistoSelectedParts; @@ -105,6 +114,7 @@ struct femtoDreamTripletTaskTrackTrackTrack { ConfigurableAxis ConfQ3BinsFor4D{"ConfQ3BinsFor4D", {500, 0., 2.}, "binning Q3 for 4D hist"}; Configurable ConfNEventsMix{"ConfNEventsMix", 5, "Number of events for mixing"}; Configurable ConfIsCPR{"ConfIsCPR", true, "Close Pair Rejection"}; + Configurable ConfFillCPRQA{"ConfFillCPRQA", false, "Fill Close Pair Rejection plots as a function of eta and phi"}; Configurable ConfCPRPlotPerRadii{"ConfCPRPlotPerRadii", false, "Plot CPR per radii"}; Configurable ConfCPRdeltaPhiMax{"ConfCPRdeltaPhiMax", 0.01, "Max. Delta Phi for Close Pair Rejection"}; Configurable ConfCPRdeltaEtaMax{"ConfCPRdeltaEtaMax", 0.01, "Max. Delta Eta for Close Pair Rejection"}; @@ -125,8 +135,11 @@ struct femtoDreamTripletTaskTrackTrackTrack { { eventHisto.init(&qaRegistry, false); - trackHistoSelectedParts.init(&qaRegistry, ConfBinmultTempFit, ConfDummy, ConfTempFitVarpTBins, ConfDummy, ConfDummy, ConfTempFitVarBins, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfIsMC, ConfPDGCodePart); - trackHistoALLSelectedParts.init(&qaRegistry, ConfBinmultTempFit, ConfDummy, ConfTempFitVarpTBins, ConfDummy, ConfDummy, ConfTempFitVarBins, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfIsMC, ConfPDGCodePart); + + colBinning = {{ConfVtxBins, ConfMultBins}, true}; + + trackHistoSelectedParts.init(&qaRegistry, ConfBinmultTempFit, ConfDummy, ConfTempFitVarpTBins, ConfDummy, ConfDummy, ConfTempFitVarBins, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfIsMC, ConfPDGCodePart); + trackHistoALLSelectedParts.init(&qaRegistry, ConfBinmultTempFit, ConfDummy, ConfTempFitVarpTBins, ConfDummy, ConfDummy, ConfTempFitVarBins, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfIsMC, ConfPDGCodePart); ThreeBodyQARegistry.add("TripletTaskQA/hSECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); ThreeBodyQARegistry.add("TripletTaskQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); @@ -135,6 +148,12 @@ struct femtoDreamTripletTaskTrackTrackTrack { std::vector tmpVecMult = ConfMultBins; framework::AxisSpec multAxis = {tmpVecMult, "Multiplicity"}; ThreeBodyQARegistry.add("TripletTaskQA/hSEMultVSGoodTracks", ";Mult;GoodT", kTH2F, {multAxis, {100, 0, 100}}); + ThreeBodyQARegistry.add("TripletTaskQA/hTripletsPerEventBelow14", ";Triplets;Entries", kTH1F, {{10, 0, 10}}); + ThreeBodyQARegistry.add("TripletTaskQA/NumberOfTacksPassingSelection", ";Triplets;Entries", kTH1F, {{30, 0, 30}}); + if (ConfIsMC) { + ThreeBodyQARegistry.add("TrackMC_QA/hMazzachi", ";gen;(reco-gen)/gen", kTH2F, {{100, ConfMinpT, ConfMaxpT}, {300, -1, 1}}); + } + ThreeBodyQARegistry.add("TripletTaskQA/hCentrality", ";Centrality; Q3", kTH2F, {{100, 0, 100}, ConfQ3Bins}); sameEventCont.init(&resultRegistry, ConfQ3Bins, ConfMultBins, ConfIsMC); mixedEventCont.init(&resultRegistry, ConfQ3Bins, ConfMultBins, ConfIsMC); @@ -142,8 +161,8 @@ struct femtoDreamTripletTaskTrackTrackTrack { mixedEventCont.setPDGCodes(ConfPDGCodePart, ConfPDGCodePart, ConfPDGCodePart); pairCleaner.init(&qaRegistry); // SERKSNYTE : later check if init should be updated to have 3 separate histos if (ConfIsCPR.value) { - pairCloseRejectionSE.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiMax.value, ConfCPRdeltaEtaMax.value, ConfCPRPlotPerRadii.value, 1, ConfUseOLD_possiblyWrong_CPR, ConfMaxQ3IncludedInCPRPlots); - pairCloseRejectionME.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiMax.value, ConfCPRdeltaEtaMax.value, ConfCPRPlotPerRadii.value, 2, ConfUseOLD_possiblyWrong_CPR, ConfMaxQ3IncludedInCPRPlots); + pairCloseRejectionSE.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiMax.value, ConfCPRdeltaEtaMax.value, ConfCPRPlotPerRadii.value, 1, ConfUseOLD_possiblyWrong_CPR, ConfMaxQ3IncludedInCPRPlots, false, ConfAtWhichRadiiToCut, ConfAtWhichTPCRadii, ConfFillCPRQA); + pairCloseRejectionME.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiMax.value, ConfCPRdeltaEtaMax.value, ConfCPRPlotPerRadii.value, 2, ConfUseOLD_possiblyWrong_CPR, ConfMaxQ3IncludedInCPRPlots, false, ConfAtWhichRadiiToCut, ConfAtWhichTPCRadii, ConfFillCPRQA); } // get masses @@ -203,11 +222,15 @@ struct femtoDreamTripletTaskTrackTrackTrack { void doSameEvent(PartitionType groupSelectedParts, PartType parts, float magFieldTesla, int multCol, float centCol) { /// Histogramming same event + int numberOfTracksPassingSelection = 0; for (auto& part : groupSelectedParts) { + numberOfTracksPassingSelection = numberOfTracksPassingSelection + 1; trackHistoSelectedParts.fillQA(part, aod::femtodreamparticle::kPt, multCol, centCol); } + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/NumberOfTacksPassingSelection"), numberOfTracksPassingSelection); /// Now build the combinations + int numberOfTriplets = 0; for (auto& [p1, p2, p3] : combinations(CombinationsStrictlyUpperIndexPolicy(groupSelectedParts, groupSelectedParts, groupSelectedParts))) { auto Q3 = FemtoDreamMath::getQ3(p1, mMassOne, p2, mMassTwo, p3, mMassThree); @@ -233,10 +256,16 @@ struct femtoDreamTripletTaskTrackTrackTrack { if (!pairCleaner.isCleanPair(p1, p3, parts)) { continue; } + // fill pT of all three particles as a function of Q3 for lambda calculations + if (Q3 < 1.4) { + numberOfTriplets = numberOfTriplets + 1; + } ThreeBodyQARegistry.fill(HIST("TripletTaskQA/particle_pT_in_Triplet_SE"), p1.pt(), p2.pt(), p3.pt(), Q3); sameEventCont.setTriplet(p1, p2, p3, multCol, Q3); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hCentrality"), centCol, Q3); } + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hTripletsPerEventBelow14"), numberOfTriplets); } /// process function to call doSameEvent with Data @@ -287,6 +316,7 @@ struct femtoDreamTripletTaskTrackTrackTrack { auto thegroupSelectedParts = SelectedPartsMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); for (auto& part : thegroupSelectedParts) { trackHistoALLSelectedParts.fillQA(part, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + ThreeBodyQARegistry.fill(HIST("TrackMC_QA/hMazzachi"), part.fdMCParticle().pt(), (part.pt() - part.fdMCParticle().pt()) / part.fdMCParticle().pt()); } if (thegroupSelectedParts.size() < 3) { return; @@ -307,6 +337,7 @@ struct femtoDreamTripletTaskTrackTrackTrack { auto thegroupSelectedParts = SelectedPartsMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); for (auto& part : thegroupSelectedParts) { trackHistoALLSelectedParts.fillQA(part, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + ThreeBodyQARegistry.fill(HIST("TrackMC_QA/hMazzachi"), part.fdMCParticle().pt(), (part.pt() - part.fdMCParticle().pt()) / part.fdMCParticle().pt()); } if (thegroupSelectedParts.size() < 3) { return; @@ -329,6 +360,7 @@ struct femtoDreamTripletTaskTrackTrackTrack { void doMixedEvent(PartitionType groupPartsOne, PartitionType groupPartsTwo, PartitionType groupPartsThree, PartType parts, float magFieldTesla, int multCol) { for (auto& [p1, p2, p3] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo, groupPartsThree))) { + auto Q3 = FemtoDreamMath::getQ3(p1, mMassOne, p2, mMassTwo, p3, mMassThree); if (ConfIsCPR.value) { if (pairCloseRejectionME.isClosePair(p1, p2, parts, magFieldTesla, Q3)) { @@ -369,7 +401,6 @@ struct femtoDreamTripletTaskTrackTrackTrack { if ((magFieldTesla1 != magFieldTesla2) || (magFieldTesla2 != magFieldTesla3) || (magFieldTesla1 != magFieldTesla3)) { continue; } - // CONSIDER testing different strategies to which events to use doMixedEvent(groupPartsOne, groupPartsTwo, groupPartsThree, parts, magFieldTesla1, multiplicityCol); } @@ -402,6 +433,7 @@ struct femtoDreamTripletTaskTrackTrackTrack { if ((magFieldTesla1 != magFieldTesla2) || (magFieldTesla2 != magFieldTesla3) || (magFieldTesla1 != magFieldTesla3)) { continue; } + doMixedEvent(groupPartsOne, groupPartsTwo, groupPartsThree, parts, magFieldTesla1, multiplicityCol); } } diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackV0.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackV0.cxx index 5e6472108c1..224515339c9 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackV0.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackV0.cxx @@ -15,6 +15,7 @@ #include #include +#include #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" @@ -53,6 +54,8 @@ struct femtoDreamTripletTaskTrackTrackV0 { // which CPR to use, old is with a possible bug and new is fixed Configurable ConfUseOLD_possiblyWrong_CPR{"ConfUseOLD_possiblyWrong_CPR", true, "Use for old CPR, which possibly has a bug. This is implemented only for debugging reasons to compare old and new code on hyperloop datasets."}; + Configurable ConfAtWhichRadiiToCut{"ConfAtWhichRadiiToCut", 1, "At which radii perform deta dphi selection: 0 - at PV, 1 - averaged phi, 2 - at given radii"}; + Configurable ConfAtWhichTPCRadii{"ConfAtWhichTPCRadii", 85., "If ConfAtWhichRadiiToCut = 2; this allows to select at which TPC radii to cut"}; /// Track selection Configurable ConfPDGCodePart{"ConfPDGCodePart", 2212, "Particle PDG code"}; @@ -66,6 +69,7 @@ struct femtoDreamTripletTaskTrackTrackV0 { Configurable ConfPIDthrMom{"ConfPIDthrMom", 1.f, "Momentum threshold from which TPC and TOF are required for PID"}; Configurable ConfIsMC{"ConfIsMC", false, "Enable additional Histogramms in the case of a MonteCarlo Run"}; Configurable ConfUse3D{"ConfUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; + Configurable ConfDCACutPtDep{"ConfDCACutPtDep", false, "Use pt dependent dca cut for tracks"}; /// Partition for selected particles Partition SelectedParts = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && @@ -73,15 +77,20 @@ struct femtoDreamTripletTaskTrackTrackV0 { (ncheckbit(aod::femtodreamparticle::cut, ConfCutPart)) && (aod::femtodreamparticle::pt < ConfMaxpT) && (aod::femtodreamparticle::pt > ConfMinpT) && - (aod::femtodreamparticle::tempFitVar < ConfMaxDCAxy) && - (aod::femtodreamparticle::tempFitVar > ConfMinDCAxy); + ifnode(ConfDCACutPtDep, (nabs(aod::femtodreamparticle::tempFitVar) <= 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f))), + ((aod::femtodreamparticle::tempFitVar >= ConfMinDCAxy) && + (aod::femtodreamparticle::tempFitVar <= ConfMaxDCAxy))); + ; + Partition> SelectedPartsMC = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= ConfPIDthrMom, ncheckbit(aod::femtodreamparticle::pidcut, ConfTPCPIDBit), ncheckbit(aod::femtodreamparticle::pidcut, ConfTPCTOFPIDBit)) && (ncheckbit(aod::femtodreamparticle::cut, ConfCutPart)) && (aod::femtodreamparticle::pt < ConfMaxpT) && (aod::femtodreamparticle::pt > ConfMinpT) && - (aod::femtodreamparticle::tempFitVar < ConfMaxDCAxy) && - (aod::femtodreamparticle::tempFitVar > ConfMinDCAxy); + ifnode(ConfDCACutPtDep, (nabs(aod::femtodreamparticle::tempFitVar) <= 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f))), + ((aod::femtodreamparticle::tempFitVar >= ConfMinDCAxy) && + (aod::femtodreamparticle::tempFitVar <= ConfMaxDCAxy))); + ; /// Histogramming of selected tracks FemtoDreamParticleHisto trackHistoSelectedParts; @@ -151,9 +160,12 @@ struct femtoDreamTripletTaskTrackTrackV0 { ConfigurableAxis ConfQ3BinsFor4D{"ConfQ3BinsFor4D", {500, 0., 2.}, "binning Q3 for 4D hist"}; Configurable ConfNEventsMix{"ConfNEventsMix", 5, "Number of events for mixing"}; Configurable ConfIsCPR{"ConfIsCPR", true, "Close Pair Rejection"}; + Configurable ConfFillCPRQA{"ConfFillCPRQA", false, "Fill Close Pair Rejection plots as a function of eta and phi"}; Configurable ConfCPRPlotPerRadii{"ConfCPRPlotPerRadii", false, "Plot CPR per radii"}; - Configurable ConfCPRdeltaPhiMax{"ConfCPRdeltaPhiMax", 0.01, "Max. Delta Phi for Close Pair Rejection"}; - Configurable ConfCPRdeltaEtaMax{"ConfCPRdeltaEtaMax", 0.01, "Max. Delta Eta for Close Pair Rejection"}; + Configurable ConfCPRdeltaPhiMax_pp{"ConfCPRdeltaPhiMax_pp", 0.01, "Max. Delta Phi for Close Pair Rejection of pp"}; + Configurable ConfCPRdeltaEtaMax_pp{"ConfCPRdeltaEtaMax_pp", 0.01, "Max. Delta Eta for Close Pair Rejection of pp"}; + Configurable ConfCPRdeltaPhiMax_pL{"ConfCPRdeltaPhiMax_pL", 0.1, "Max. Delta Phi for Close Pair Rejection of p and Lambda daughter"}; + Configurable ConfCPRdeltaEtaMax_pL{"ConfCPRdeltaEtaMax_pL", 0.1, "Max. Delta Eta for Close Pair Rejection of p and Lambda daughter"}; Configurable ConfMaxQ3IncludedInCPRPlots{"ConfMaxQ3IncludedInCPRPlots", 8., "Maximum Q3, for which the pair CPR is included in plots"}; ConfigurableAxis ConfDummy{"ConfDummy", {1, 0, 1}, "Dummy axis"}; @@ -174,14 +186,17 @@ struct femtoDreamTripletTaskTrackTrackV0 { { eventHisto.init(&qaRegistry, false); - trackHistoSelectedParts.init(&qaRegistry, ConfDummy, ConfDummy, ConfTempFitVarpTBins, ConfDummy, ConfDummy, ConfTempFitVarBinsTrack, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfIsMC, ConfPDGCodePart); - trackHistoALLSelectedParts.init(&qaRegistry, ConfDummy, ConfDummy, ConfTempFitVarpTBins, ConfDummy, ConfDummy, ConfTempFitVarBinsTrack, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfIsMC, ConfPDGCodePart); - particleHistoSelectedV0s.init(&qaRegistry, ConfDummy, ConfDummy, ConfTempFitVarpTV0Bins, ConfDummy, ConfDummy, ConfTempFitVarBinsV0, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfInvMassBins, ConfIsMC, ConfPDGCodeV0); - particleHistoPosChild.init(&qaRegistry, ConfDummy, ConfDummy, ConfTempFitVarpTV0Child, ConfDummy, ConfDummy, ConfTempFitVarBinsV0Child, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfIsMC, 0); - particleHistoNegChild.init(&qaRegistry, ConfDummy, ConfDummy, ConfTempFitVarpTV0Child, ConfDummy, ConfDummy, ConfTempFitVarBinsV0Child, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfIsMC, 0); - particleHistoALLSelectedV0s.init(&qaRegistry, ConfDummy, ConfDummy, ConfTempFitVarpTV0Bins, ConfDummy, ConfDummy, ConfTempFitVarBinsV0, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfInvMassBins, ConfIsMC, ConfPDGCodeV0); - particleHistoALLPosChild.init(&qaRegistry, ConfDummy, ConfDummy, ConfTempFitVarpTV0Child, ConfDummy, ConfDummy, ConfTempFitVarBinsV0Child, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfIsMC, 0); - particleHistoALLNegChild.init(&qaRegistry, ConfDummy, ConfDummy, ConfTempFitVarpTV0Child, ConfDummy, ConfDummy, ConfTempFitVarBinsV0Child, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfIsMC, 0); + + colBinning = {{ConfVtxBins, ConfMultBins}, true}; + + trackHistoSelectedParts.init(&qaRegistry, ConfDummy, ConfDummy, ConfTempFitVarpTBins, ConfDummy, ConfDummy, ConfTempFitVarBinsTrack, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfIsMC, ConfPDGCodePart); + trackHistoALLSelectedParts.init(&qaRegistry, ConfDummy, ConfDummy, ConfTempFitVarpTBins, ConfDummy, ConfDummy, ConfTempFitVarBinsTrack, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfIsMC, ConfPDGCodePart); + particleHistoSelectedV0s.init(&qaRegistry, ConfDummy, ConfDummy, ConfTempFitVarpTV0Bins, ConfDummy, ConfDummy, ConfTempFitVarBinsV0, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfInvMassBins, ConfDummy, ConfIsMC, ConfPDGCodeV0); + particleHistoPosChild.init(&qaRegistry, ConfDummy, ConfDummy, ConfTempFitVarpTV0Child, ConfDummy, ConfDummy, ConfTempFitVarBinsV0Child, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfIsMC, 0); + particleHistoNegChild.init(&qaRegistry, ConfDummy, ConfDummy, ConfTempFitVarpTV0Child, ConfDummy, ConfDummy, ConfTempFitVarBinsV0Child, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfIsMC, 0); + particleHistoALLSelectedV0s.init(&qaRegistry, ConfDummy, ConfDummy, ConfTempFitVarpTV0Bins, ConfDummy, ConfDummy, ConfTempFitVarBinsV0, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfInvMassBins, ConfDummy, ConfIsMC, ConfPDGCodeV0); + particleHistoALLPosChild.init(&qaRegistry, ConfDummy, ConfDummy, ConfTempFitVarpTV0Child, ConfDummy, ConfDummy, ConfTempFitVarBinsV0Child, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfIsMC, 0); + particleHistoALLNegChild.init(&qaRegistry, ConfDummy, ConfDummy, ConfTempFitVarpTV0Child, ConfDummy, ConfDummy, ConfTempFitVarBinsV0Child, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfDummy, ConfIsMC, 0); ThreeBodyQARegistry.add("TripletTaskQA/hSECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); ThreeBodyQARegistry.add("TripletTaskQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); @@ -191,9 +206,18 @@ struct femtoDreamTripletTaskTrackTrackV0 { ThreeBodyQARegistry.add("TripletTaskQA/hMinvME_AntiLambda", ";Q_{3};M_{inv}", kTH2F, {ConfQ3Bins, ConfInvMassBins}); ThreeBodyQARegistry.add("TripletTaskQA/particle_pT_in_Triplet_SE", "; p_{T1} ; p_{T2} ; p_{T3} ; Q_{3}", kTHnSparseF, {ConfTempFitVarpTBins, ConfTempFitVarpTBins, ConfTempFitVarpTV0Bins, ConfQ3BinsFor4D}); ThreeBodyQARegistry.add("TripletTaskQA/particle_pT_in_Triplet_ME", "; p_{T1} ; p_{T2} ; p_{T3} ; Q_{3}", kTHnSparseF, {ConfTempFitVarpTBins, ConfTempFitVarpTBins, ConfTempFitVarpTV0Bins, ConfQ3BinsFor4D}); + ThreeBodyQARegistry.add("TripletTaskQA/hCentrality", ";Centrality; Q3", kTH2F, {{100, 0, 100}, ConfQ3Bins}); + std::vector tmpVecMult = ConfMultBins; framework::AxisSpec multAxis = {tmpVecMult, "Multiplicity"}; ThreeBodyQARegistry.add("TripletTaskQA/hSEMultVSGoodTracks", ";Mult;GoodT", kTH2F, {multAxis, {100, 0, 100}}); + ThreeBodyQARegistry.add("TripletTaskQA/hTestPairCleaner", ";posDaughtID; negDaughID", kTH2F, {{40, -20, 20}, {40, -20, 20}}); + ThreeBodyQARegistry.add("TripletTaskQA/hTestPairCleanerPos", ";primaryTrack; posDaughtID", kTH2F, {{40, -20, 20}, {40, -20, 20}}); + ThreeBodyQARegistry.add("TripletTaskQA/hTestPairCleanerNeg", ";primaryTrack; negDaughtID", kTH2F, {{40, -20, 20}, {40, -20, 20}}); + ThreeBodyQARegistry.add("TripletTaskQA/hTestPairCleanerPosGlobal", ";primaryTrackGlobal; posDaughtID", kTH2F, {{40, -20, 20}, {40, -20, 20}}); + ThreeBodyQARegistry.add("TripletTaskQA/hTestPairCleanerNegGlobal", ";primaryTrackGlobal; negDaughtID", kTH2F, {{40, -20, 20}, {40, -20, 20}}); + ThreeBodyQARegistry.add("TripletTaskQA/hTestPairCleanerPosAfter", ";primaryTrack; posDaughtID", kTH2F, {{40, -20, 20}, {40, -20, 20}}); + ThreeBodyQARegistry.add("TripletTaskQA/hTestPairCleanerNegAfter", ";primaryTrack; negDaughtID", kTH2F, {{40, -20, 20}, {40, -20, 20}}); sameEventCont.init(&resultRegistry, ConfQ3Bins, ConfMultBins, ConfIsMC); mixedEventCont.init(&resultRegistry, ConfQ3Bins, ConfMultBins, ConfIsMC); @@ -203,10 +227,10 @@ struct femtoDreamTripletTaskTrackTrackV0 { pairCleanerTrackTrack.init(&qaRegistry); pairCleanerTrackV0.init(&qaRegistry); if (ConfIsCPR.value) { - pairCloseRejectionTrackTrackSE.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiMax.value, ConfCPRdeltaEtaMax.value, ConfCPRPlotPerRadii.value, 1, ConfUseOLD_possiblyWrong_CPR, ConfMaxQ3IncludedInCPRPlots); - pairCloseRejectionTrackV0SE.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiMax.value, ConfCPRdeltaEtaMax.value, ConfCPRPlotPerRadii.value, 1, ConfUseOLD_possiblyWrong_CPR, ConfMaxQ3IncludedInCPRPlots); - pairCloseRejectionTrackTrackME.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiMax.value, ConfCPRdeltaEtaMax.value, ConfCPRPlotPerRadii.value, 2, ConfUseOLD_possiblyWrong_CPR, ConfMaxQ3IncludedInCPRPlots); - pairCloseRejectionTrackV0ME.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiMax.value, ConfCPRdeltaEtaMax.value, ConfCPRPlotPerRadii.value, 2, ConfUseOLD_possiblyWrong_CPR, ConfMaxQ3IncludedInCPRPlots, true); + pairCloseRejectionTrackTrackSE.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiMax_pp.value, ConfCPRdeltaEtaMax_pp.value, ConfCPRPlotPerRadii.value, 1, ConfUseOLD_possiblyWrong_CPR, ConfMaxQ3IncludedInCPRPlots, false, ConfAtWhichRadiiToCut, ConfAtWhichTPCRadii, ConfFillCPRQA); + pairCloseRejectionTrackV0SE.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiMax_pL.value, ConfCPRdeltaEtaMax_pL.value, ConfCPRPlotPerRadii.value, 1, ConfUseOLD_possiblyWrong_CPR, ConfMaxQ3IncludedInCPRPlots, false, ConfAtWhichRadiiToCut, ConfAtWhichTPCRadii, ConfFillCPRQA); + pairCloseRejectionTrackTrackME.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiMax_pp.value, ConfCPRdeltaEtaMax_pp.value, ConfCPRPlotPerRadii.value, 2, ConfUseOLD_possiblyWrong_CPR, ConfMaxQ3IncludedInCPRPlots, false, ConfAtWhichRadiiToCut, ConfAtWhichTPCRadii, ConfFillCPRQA); + pairCloseRejectionTrackV0ME.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiMax_pL.value, ConfCPRdeltaEtaMax_pL.value, ConfCPRPlotPerRadii.value, 2, ConfUseOLD_possiblyWrong_CPR, ConfMaxQ3IncludedInCPRPlots, true, ConfAtWhichRadiiToCut, ConfAtWhichTPCRadii, ConfFillCPRQA); } // get masses @@ -303,6 +327,13 @@ struct femtoDreamTripletTaskTrackTrackV0 { for (auto& V0 : groupSelectedV0s) { const auto& posChild = parts.iteratorAt(V0.index() - 2); const auto& negChild = parts.iteratorAt(V0.index() - 1); + + const auto& childrenPos = posChild.childrenIds(); + const auto& childrenNeg = negChild.childrenIds(); + auto posID = childrenPos[0]; + auto negID = childrenNeg[1]; + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hTestPairCleaner"), posID, negID); + if (!((posChild.cut() & Conf_ChildPos_CutV0) == Conf_ChildPos_CutV0 && (posChild.pidcut() & Conf_ChildPos_TPCBitV0) == Conf_ChildPos_TPCBitV0 && (negChild.cut() & Conf_ChildNeg_CutV0) == Conf_ChildNeg_CutV0 && @@ -311,6 +342,14 @@ struct femtoDreamTripletTaskTrackTrackV0 { } for (auto& [T1, T2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupSelectedTracks, groupSelectedTracks))) { + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hTestPairCleanerPos"), T1.index(), posID); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hTestPairCleanerNeg"), T1.index(), negID); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hTestPairCleanerPos"), T2.index(), posID); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hTestPairCleanerNeg"), T2.index(), negID); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hTestPairCleanerPosGlobal"), T1.globalIndex(), posID); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hTestPairCleanerNegGlobal"), T1.globalIndex(), negID); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hTestPairCleanerPosGlobal"), T2.globalIndex(), posID); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hTestPairCleanerNegGlobal"), T2.globalIndex(), negID); auto Q3 = FemtoDreamMath::getQ3(T1, mMassOne, T2, mMassTwo, V0, mMassThree); // Close pair rejection if (ConfIsCPR.value) { @@ -335,11 +374,16 @@ struct femtoDreamTripletTaskTrackTrackV0 { if (!pairCleanerTrackV0.isCleanPair(T1, V0, parts)) { continue; } + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hTestPairCleanerPosAfter"), T1.index(), posID); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hTestPairCleanerNegAfter"), T1.index(), negID); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hTestPairCleanerPosAfter"), T2.index(), posID); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hTestPairCleanerNegAfter"), T2.index(), negID); // fill inv Mass as a function of Q3 for purity fits ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hMinvSE_Lambda"), Q3, V0.mLambda()); ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hMinvSE_AntiLambda"), Q3, V0.mAntiLambda()); ThreeBodyQARegistry.fill(HIST("TripletTaskQA/particle_pT_in_Triplet_SE"), T1.pt(), T2.pt(), V0.pt(), Q3); sameEventCont.setTriplet(T1, T2, V0, multCol, Q3); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hCentrality"), centCol, Q3); } } } @@ -543,7 +587,6 @@ struct femtoDreamTripletTaskTrackTrackV0 { if ((magFieldTesla1 != magFieldTesla2) || (magFieldTesla2 != magFieldTesla3) || (magFieldTesla1 != magFieldTesla3)) { continue; } - // CONSIDER testing different strategies to which events to use doMixedEvent(groupPartsOne, groupPartsTwo, groupPartsThree, parts, magFieldTesla1, multiplicityCol); } diff --git a/PWGCF/FemtoDream/Utils/femtoDreamCutCulator.cxx b/PWGCF/FemtoDream/Utils/femtoDreamCutCulator.cxx index 0096d6840e7..5794f81d7d9 100644 --- a/PWGCF/FemtoDream/Utils/femtoDreamCutCulator.cxx +++ b/PWGCF/FemtoDream/Utils/femtoDreamCutCulator.cxx @@ -13,9 +13,9 @@ /// \brief Executable that encodes physical selection criteria in a bit-wise /// selection \author Andi Mathis, TU München, andreas.mathis@ph.tum.de -#include #include #include +#include #include "PWGCF/FemtoDream/Utils/femtoDreamCutCulator.h" #include "PWGCF/FemtoDream/Core/femtoDreamSelection.h" #include "PWGCF/FemtoDream/Core/femtoDreamTrackSelection.h" @@ -29,14 +29,14 @@ using namespace o2::analysis::femtoDream; int main(int /*argc*/, char* argv[]) { std::string configFileName(argv[1]); - std::filesystem::path configFile{configFileName}; + std::ifstream configFile(configFileName); - if (std::filesystem::exists(configFile)) { + if (configFile.is_open()) { FemtoDreamCutculator cut; cut.init(argv[1]); std::cout - << "Do you want to work with tracks or V0s (T/V)? >"; + << "Do you want to work with tracks or V0s or Cascades (T/V/C)? >"; std::string choice; std::cin >> choice; @@ -49,6 +49,24 @@ int main(int /*argc*/, char* argv[]) cut.setV0SelectionFromFile("ConfV0"); cut.setTrackSelectionFromFile("ConfChild"); cut.setPIDSelectionFromFile("ConfChild"); + } else if (choice == std::string("C")) { + std::cout << "Do you want to select cascades, V0-Daughter tracks of the cascades or the Bachelor track (C/V/B)? >"; + std::cin >> choice; + if (choice == std::string("C")) { + cut.setCascadeSelectionFromFile("ConfCascade"); + choice = "C"; + } else if (choice == std::string("V")) { + cut.setTrackSelectionFromFile("ConfCascV0Child"); + cut.setPIDSelectionFromFile("ConfCascV0Child"); + choice = "T"; + } else if (choice == std::string("B")) { + cut.setTrackSelectionFromFile("ConfCascBachelor"); + cut.setPIDSelectionFromFile("ConfCascBachelor"); + choice = "T"; + } else { + std::cout << "Option not recognized. Break..."; + return 2; + } } else { std::cout << "Option not recognized. Break..."; return 2; @@ -79,7 +97,8 @@ int main(int /*argc*/, char* argv[]) } else { std::cout << "The configuration file " << configFileName - << " could not be found."; + << " could not be found or could not be opened."; + return 1; } return 0; diff --git a/PWGCF/FemtoDream/Utils/femtoDreamCutCulator.h b/PWGCF/FemtoDream/Utils/femtoDreamCutCulator.h index 7bb2035dba9..f36fd80481a 100644 --- a/PWGCF/FemtoDream/Utils/femtoDreamCutCulator.h +++ b/PWGCF/FemtoDream/Utils/femtoDreamCutCulator.h @@ -32,6 +32,7 @@ #include "PWGCF/FemtoDream/Core/femtoDreamSelection.h" #include "PWGCF/FemtoDream/Core/femtoDreamTrackSelection.h" #include "PWGCF/FemtoDream/Core/femtoDreamV0Selection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamCascadeSelection.h" namespace o2::analysis::femtoDream { @@ -59,7 +60,7 @@ class FemtoDreamCutculator // check the config file for all known producer task std::vector ProducerTasks = { - "femto-dream-producer-task", "femto-dream-producer-reduced-task"}; + "femto-dream-producer-task", "femto-dream-producer-reduced-task", "femto-dream-producer-task-with-cascades"}; for (auto& Producer : ProducerTasks) { if (root.count(Producer) > 0) { mConfigTree = root.get_child(Producer); @@ -193,6 +194,44 @@ class FemtoDreamCutculator } } + /// Specialization of the setSelection function for Cascades + + /// The selection passed to the function is retrieved from the dpl-config.json + /// \param obs Observable of the track selection + /// \param type Type of the track selection + /// \param prefix Prefix which is added to the name of the Configurable + void setCascadeSelection(femtoDreamCascadeSelection::CascadeSel obs, + femtoDreamSelection::SelectionType type, + const char* prefix) + { + auto tmpVec = + setSelection(FemtoDreamCascadeSelection::getSelectionName(obs, prefix)); + if (tmpVec.size() > 0) { + mCascadeSel.setSelection(tmpVec, obs, type); + } + } + + /// Automatically retrieves V0 selections from the dpl-config.json + /// \param prefix Prefix which is added to the name of the Configurable + void setCascadeSelectionFromFile(const char* prefix) + { + for (const auto& sel : mConfigTree) { + std::string sel_name = sel.first; + femtoDreamCascadeSelection::CascadeSel obs; + if (sel_name.find(prefix) != std::string::npos) { + int index = FemtoDreamCascadeSelection::findSelectionIndex( + std::string_view(sel_name), prefix); + if (index >= 0) { + obs = femtoDreamCascadeSelection::CascadeSel(index); + } else { + continue; + } + setCascadeSelection(obs, FemtoDreamCascadeSelection::getSelectionType(obs), + prefix); + } + } + } + /// This function investigates a given selection criterion. The available /// options are displayed in the terminal and the bit-wise container is put /// together according to the user input \tparam T1 Selection class under @@ -319,6 +358,8 @@ class FemtoDreamCutculator output = iterateSelection(mTrackSel, SysChecks, sign); } else if (choice == std::string("V")) { output = iterateSelection(mV0Sel, SysChecks, sign); + } else if (choice == std::string("C")) { + output = iterateSelection(mCascadeSel, SysChecks, sign); } else { std::cout << "Option " << choice << " not recognized - available options are (T/V)" << std::endl; @@ -338,22 +379,40 @@ class FemtoDreamCutculator std::sort(mPIDValues.begin(), mPIDValues.end(), std::greater<>()); int Bit = 0; + std::cout << "Activate ITS PID (only valid for tracks)? (y/n)"; + std::string choicePID; + std::cin >> choicePID; + std::cout << "+++++++++++++++++++++++++++++++++" << std::endl; - for (std::size_t i = 0; i < mPIDspecies.size(); i++) { - for (std::size_t j = 0; j < mPIDValues.size(); j++) { - std::cout << "Species " << o2::track::PID::getName(mPIDspecies.at(i)) << " with |NSigma|<" << mPIDValues.at(j) << std::endl; - Bit = (2 * mPIDspecies.size() * (mPIDValues.size() - (j + 1)) + 1) + (mPIDspecies.size() - (1 + i)) * 2; - std::cout << "Bit for Nsigma TPC: " << (1 << (Bit + 1)) << std::endl; - std::cout << "Bit for Nsigma TPCTOF: " << (1 << Bit) << std::endl; - std::cout << "+++++++++++++++++++++++++++++++++" << std::endl; + if (choicePID == std::string("n")) { + for (std::size_t i = 0; i < mPIDspecies.size(); i++) { + for (std::size_t j = 0; j < mPIDValues.size(); j++) { + std::cout << "Species " << o2::track::PID::getName(mPIDspecies.at(i)) << " with |NSigma|<" << mPIDValues.at(j) << std::endl; + Bit = (2 * mPIDspecies.size() * (mPIDValues.size() - (j + 1)) + 1) + (mPIDspecies.size() - (1 + i)) * 2; + std::cout << "Bit for Nsigma TPC: " << (1 << (Bit + 1)) << std::endl; + std::cout << "Bit for Nsigma TPCTOF: " << (1 << Bit) << std::endl; + std::cout << "+++++++++++++++++++++++++++++++++" << std::endl; + } + if (SysChecks) { + // Seed the random number generator + // Select a random element + randomIndex = uni(rng); + std::cout << "Nsigma TPC: " << mPIDValues[randomIndex] << std::endl; + randomIndex = uni(rng); + std::cout << "Nsigma TPCTOF: " << mPIDValues[randomIndex] << std::endl; + } } - if (SysChecks) { - // Seed the random number generator - // Select a random element - randomIndex = uni(rng); - std::cout << "Nsigma TPC: " << mPIDValues[randomIndex] << std::endl; - randomIndex = uni(rng); - std::cout << "Nsigma TPCTOF: " << mPIDValues[randomIndex] << std::endl; + } else { + for (std::size_t i = 0; i < mPIDspecies.size(); i++) { + for (std::size_t j = 0; j < mPIDValues.size(); j++) { + std::cout << "Species " << o2::track::PID::getName(mPIDspecies.at(i)) << " with |NSigma|<" << mPIDValues.at(j) << std::endl; + // Bit = (2 * mPIDspecies.size() * (mPIDValues.size() - (j + 1)) + 1) + (mPIDspecies.size() - (1 + i)) * 2; + Bit = (3 * mPIDspecies.size() * (mPIDValues.size() - (j + 1)) + 1) + (mPIDspecies.size() - (1 + i)) * 3; + std::cout << "Bit for Nsigma TPC: " << (1 << (Bit + 2)) << std::endl; + std::cout << "Bit for Nsigma TPCTOF: " << (1 << (Bit + 1)) << std::endl; + std::cout << "Bit for Nsigma ITS: " << (1 << Bit) << std::endl; + std::cout << "+++++++++++++++++++++++++++++++++" << std::endl; + } } } } @@ -362,6 +421,7 @@ class FemtoDreamCutculator boost::property_tree::ptree mConfigTree; ///< the dpl-config.json buffered into a ptree FemtoDreamTrackSelection mTrackSel; ///< for setting up the bit-wise selection container for tracks FemtoDreamV0Selection mV0Sel; ///< for setting up the bit-wise selection container for V0s + FemtoDreamCascadeSelection mCascadeSel; ///< for setting up the bit-wise selection container for Cascades std::vector mPIDspecies; ///< list of particle species for which PID is stored std::vector mPIDValues; ///< list of nsigma values for which PID is stored }; diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverse3DContainer.h b/PWGCF/FemtoUniverse/Core/FemtoUniverse3DContainer.h index 6d48650c2ba..9d5eee9d2f5 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverse3DContainer.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverse3DContainer.h @@ -29,10 +29,10 @@ using namespace o2::framework; -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { -namespace femtoUniverse3DContainer +namespace femto_universe3d_container { /// Femtoscopic observable to be computed enum Observable { kstar ///< kstar @@ -42,7 +42,7 @@ enum Observable { kstar ///< kstar enum EventType { same, ///< Pair from same event mixed ///< Pair from mixed event }; -}; // namespace femtoUniverse3DContainer +}; // namespace femto_universe3d_container /// \class FemtoUniverse3DContainer /// \brief Container for all histogramming related to the correlation function. The two @@ -50,7 +50,7 @@ enum EventType { same, ///< Pair from same event /// are filled according to the specified observable /// \tparam eventType Type of the event (same/mixed) /// \tparam obs Observable to be computed (k*/Q_inv/...) -template +template class FemtoUniverse3DContainer { public: @@ -74,9 +74,8 @@ class FemtoUniverse3DContainer /// \param mTAxis axis object for the mT axis /// \param use3dplots Flag to fill 3D plots /// \param isiden Identical or non-identical particle pair - /// \param islcms LCMS or PRF template - void init_base(std::string folderName, std::string femtoObs1D, std::string femtoObsKout, std::string femtoObsKside, std::string femtoObsKlong, T femtoObsAxis1D, T femtoObsAxisOut, T femtoObsAxisSide, T femtoObsAxisLong, T multAxis, T kTAxis, T mTAxis, T multAxis3D, T mTAxis3D, bool use3dplots, bool isiden) + void initBase(std::string folderName, std::string femtoObs1D, std::string femtoObsKout, std::string femtoObsKside, std::string femtoObsKlong, T femtoObsAxis1D, T femtoObsAxisOut, T femtoObsAxisSide, T femtoObsAxisLong, T multAxis, T kTAxis, T mTAxis, T multAxis3D, T mTAxis3D, bool use3dplots, bool isiden) { mHistogramRegistry->add((folderName + "/relPairMom3D").c_str(), ("; " + femtoObsKout + "; " + femtoObsKside + "; " + femtoObsKlong).c_str(), kTH3F, {femtoObsAxisOut, femtoObsAxisSide, femtoObsAxisLong}); mHistogramRegistry->add((folderName + "/relPairMomOut").c_str(), ("; " + femtoObsKout + "; Entries").c_str(), kTH1F, {femtoObsAxisOut}); @@ -106,7 +105,7 @@ class FemtoUniverse3DContainer } /// Templated function to initialize the histograms for the task - /// Always calls init_base to initialize the histograms for data/ Monte Carlo reconstructed + /// Always calls initBase to initialize the histograms for data/ Monte Carlo reconstructed /// \tparam T type of the configurable for the axis configuration /// \param registry Histogram registry to be passed /// \param kstarBins k* binning for the histograms @@ -146,9 +145,9 @@ class FemtoUniverse3DContainer framework::AxisSpec multAxis3D = {multBins3D, "Multiplicity"}; framework::AxisSpec mTAxis3D = {mTBins3D, "#it{m}_{T} (GeV/#it{c})"}; - std::string folderName = static_cast(mFolderSuffix[mEventType]) + static_cast(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kRecon]); + std::string folderName = static_cast(FolderSuffix[EventType]) + static_cast(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kRecon]); - init_base(folderName, femtoObs1D, femtoObsKout, femtoObsKside, femtoObsKlong, femtoObsAxis1D, femtoObsAxisOut, femtoObsAxisSide, femtoObsAxisLong, multAxis, kTAxis, mTAxis, multAxis3D, mTAxis3D, use3dplots, isiden); + initBase(folderName, femtoObs1D, femtoObsKout, femtoObsKside, femtoObsKlong, femtoObsAxis1D, femtoObsAxisOut, femtoObsAxisSide, femtoObsAxisLong, multAxis, kTAxis, mTAxis, multAxis3D, mTAxis3D, use3dplots, isiden); } /// Set the PDG codes of the two particles involved @@ -168,44 +167,44 @@ class FemtoUniverse3DContainer /// \param part1 Particle one /// \param part2 Particle two /// \param mult Multiplicity of the event - template - void setPair_base(const float femtoObsKout, const float femtoObsKside, const float femtoObsKlong, const float femtoObs1D, const float kT, const float mT, T const& part1, T const& part2, const int mult, bool use3dplots, const float isiden) + template + void setPairBase(const float femtoObsKout, const float femtoObsKside, const float femtoObsKlong, const float femtoObs1D, const float kT, const float mT, T const& part1, T const& part2, const int mult, bool use3dplots, const float isiden) { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairMomOut"), femtoObsKout); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairMomSide"), femtoObsKside); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairMomLong"), femtoObsKlong); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairMom3D"), femtoObsKout, femtoObsKside, femtoObsKlong); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/MultPtPart1"), part1.pt(), mult); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/MultPtPart2"), part2.pt(), mult); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/PtPart1PtPart2"), part1.pt(), part2.pt()); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairMomOut"), femtoObsKout); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairMomSide"), femtoObsKside); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairMomLong"), femtoObsKlong); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairMom3D"), femtoObsKout, femtoObsKside, femtoObsKlong); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/MultPtPart1"), part1.pt(), mult); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/MultPtPart2"), part2.pt(), mult); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/PtPart1PtPart2"), part1.pt(), part2.pt()); if (isiden) { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairMom1D"), (2.0 * femtoObs1D)); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkT"), kT); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkstarkT"), (2.0 * femtoObs1D), kT); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkstarmT"), (2.0 * femtoObs1D), mT); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkstarMult"), (2.0 * femtoObs1D), mult); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/kstarPtPart1"), (2.0 * femtoObs1D), part1.pt()); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/kstarPtPart2"), (2.0 * femtoObs1D), part2.pt()); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairMom1D"), (2.0 * femtoObs1D)); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkT"), kT); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkstarkT"), (2.0 * femtoObs1D), kT); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkstarmT"), (2.0 * femtoObs1D), mT); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkstarMult"), (2.0 * femtoObs1D), mult); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/kstarPtPart1"), (2.0 * femtoObs1D), part1.pt()); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/kstarPtPart2"), (2.0 * femtoObs1D), part2.pt()); if (use3dplots) { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkstarmTMult"), (2.0 * femtoObs1D), mT, mult); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkstarmTMult"), (2.0 * femtoObs1D), mT, mult); } } else { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairMom1D"), femtoObs1D); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkT"), kT); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkstarkT"), femtoObs1D, kT); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkstarmT"), femtoObs1D, mT); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkstarMult"), femtoObs1D, mult); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/kstarPtPart1"), femtoObs1D, part1.pt()); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/kstarPtPart2"), femtoObs1D, part2.pt()); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairMom1D"), femtoObs1D); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkT"), kT); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkstarkT"), femtoObs1D, kT); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkstarmT"), femtoObs1D, mT); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkstarMult"), femtoObs1D, mult); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/kstarPtPart1"), femtoObs1D, part1.pt()); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/kstarPtPart2"), femtoObs1D, part2.pt()); if (use3dplots) { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkstarmTMult"), femtoObs1D, mT, mult); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkstarmTMult"), femtoObs1D, mT, mult); } } } /// Templated function to compute the necessary observables and fill the respective histograms - /// Always calls setPair_base to compute the observables with reconstructed data + /// Always calls setPairBase to compute the observables with reconstructed data /// \tparam T type of the femtouniverseparticle /// \param part1 Particle one /// \param part2 Particle two @@ -214,13 +213,13 @@ class FemtoUniverse3DContainer /// \param isiden Choosing identical or non-identical pairs /// \param islcm Choosing LCMS or PRF template - void setPair(T const& part1, T const& part2, const int mult, bool use3dplots, bool isiden, bool islcms) + void setPair(T const& part1, T const& part2, const int mult, bool use3dplots, bool isiden) { std::vector f3d; const float kT = FemtoUniverseMath::getkT(part1, mMassOne, part2, mMassTwo); const float mT = FemtoUniverseMath::getmT(part1, mMassOne, part2, mMassTwo); - f3d = FemtoUniverseMath::getpairmom3d(part1, mMassOne, part2, mMassTwo, isiden, islcms); + f3d = FemtoUniverseMath::newpairfunc(part1, mMassOne, part2, mMassTwo, isiden); const float femtoObs1D = f3d[0]; const float femtoObsKout = f3d[1]; @@ -228,37 +227,37 @@ class FemtoUniverse3DContainer const float femtoObsKlong = f3d[3]; if (mHistogramRegistry) { - setPair_base(femtoObsKout, femtoObsKside, femtoObsKlong, femtoObs1D, kT, mT, part1, part2, mult, use3dplots, isiden); + setPairBase(femtoObsKout, femtoObsKside, femtoObsKlong, femtoObs1D, kT, mT, part1, part2, mult, use3dplots, isiden); if (!isiden) { if (femtoObsKout > 0.0) { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kRecon]) + HIST("/KStarOutP"), femtoObs1D); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kRecon]) + HIST("/KStarOutP"), femtoObs1D); } else { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kRecon]) + HIST("/KStarOutN"), femtoObs1D); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kRecon]) + HIST("/KStarOutN"), femtoObs1D); } if (femtoObsKside > 0.0) { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kRecon]) + HIST("/KStarSideP"), femtoObs1D); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kRecon]) + HIST("/KStarSideP"), femtoObs1D); } else { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kRecon]) + HIST("/KStarSideN"), femtoObs1D); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kRecon]) + HIST("/KStarSideN"), femtoObs1D); } if (femtoObsKlong > 0.0) { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kRecon]) + HIST("/KStarLongP"), femtoObs1D); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kRecon]) + HIST("/KStarLongP"), femtoObs1D); } else { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kRecon]) + HIST("/KStarLongN"), femtoObs1D); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kRecon]) + HIST("/KStarLongN"), femtoObs1D); } } } } protected: - HistogramRegistry* mHistogramRegistry = nullptr; ///< For QA output - static constexpr std::string_view mFolderSuffix[2] = {"SameEvent", "MixedEvent"}; ///< Folder naming for the output according to mEventType - static constexpr int mEventType = eventType; ///< Type of the event (same/mixed, according to femtoUniverse3DContainer::EventType) - float mMassOne = 0.f; ///< PDG mass of particle 1 - float mMassTwo = 0.f; ///< PDG mass of particle 2 - int mPDGOne = 0; ///< PDG code of particle 1 - int mPDGTwo = 0; ///< PDG code of particle 2 + HistogramRegistry* mHistogramRegistry = nullptr; ///< For QA output + static constexpr std::string_view FolderSuffix[2] = {"SameEvent", "MixedEvent"}; ///< Folder naming for the output according to EventType + static constexpr int EventType = eventType; ///< Type of the event (same/mixed, according to femto_universe3d_container::EventType) + float mMassOne = 0.f; ///< PDG mass of particle 1 + float mMassTwo = 0.f; ///< PDG mass of particle 2 + int mPDGOne = 0; ///< PDG code of particle 1 + int mPDGTwo = 0; ///< PDG code of particle 2 }; -} // namespace o2::analysis::femtoUniverse +} // namespace o2::analysis::femto_universe #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSE3DCONTAINER_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseAngularContainer.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseAngularContainer.h index e0429bd73e8..a6b80611649 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseAngularContainer.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseAngularContainer.h @@ -25,6 +25,7 @@ #include #include "Framework/HistogramRegistry.h" +#include "Common/Core/RecoDecay.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" #include "Math/Vector4D.h" @@ -33,10 +34,10 @@ using namespace o2::framework; -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { -namespace femtoUniverseAngularContainer +namespace femto_universe_angular_container { /// Femtoscopic observable to be computed enum Observable { kstar ///< kstar @@ -46,7 +47,7 @@ enum Observable { kstar ///< kstar enum EventType { same, ///< Pair from same event mixed ///< Pair from mixed event }; -}; // namespace femtoUniverseAngularContainer +}; // namespace femto_universe_angular_container /// \class FemtoUniverseAngularContainer /// \brief Container for all histogramming related to the correlation function. The two @@ -54,7 +55,7 @@ enum EventType { same, ///< Pair from same event /// are filled according to the specified observable /// \tparam eventType Type of the event (same/mixed) /// \tparam obs Observable to be computed (k*/Q_inv/...) -template +template class FemtoUniverseAngularContainer { public: @@ -71,7 +72,7 @@ class FemtoUniverseAngularContainer /// \param kTAxis axis object for the kT axis /// \param mTAxis axis object for the mT axis template - void init_base(std::string folderName, std::string /*femtoObs*/, T /*femtoObsAxis*/, T /*multAxis*/, T /*kTAxis*/, T /*mTAxis*/, T /*multAxis3D*/, T /*mTAxis3D*/, T etaAxis, T phiAxis, bool use3dplots) + void initBase(std::string folderName, std::string /*femtoObs*/, T /*femtoObsAxis*/, T /*multAxis*/, T /*kTAxis*/, T /*mTAxis*/, T /*multAxis3D*/, T /*mTAxis3D*/, T etaAxis, T phiAxis, bool use3dplots) { mHistogramRegistry->add((folderName + "/DeltaEtaDeltaPhi").c_str(), "; #Delta#varphi (rad); #Delta#eta", kTH2F, {phiAxis, etaAxis}); if (use3dplots) { @@ -85,13 +86,13 @@ class FemtoUniverseAngularContainer /// \param folderName Name of the directory in the output file (no suffix for reconstructed data/ Monte Carlo; "_MC" for Monte Carlo Truth) /// \param femtoObsAxis axis object for the femto observable axis template - void init_MC(std::string /*folderName*/, std::string /*femtoObs*/, T /*femtoObsAxis*/, T /*multAxis*/, T /*mTAxis*/) + void initMC(std::string /*folderName*/, std::string /*femtoObs*/, T /*femtoObsAxis*/, T /*multAxis*/, T /*mTAxis*/) { } /// Templated function to initialize the histograms for the task - /// Always calls init_base to initialize the histograms for data/ Monte Carlo reconstructed - /// In case of Monte Carlo, calls init_base again for Monte Carlo truth and the specialized function init_MC for additional histogramms + /// Always calls initBase to initialize the histograms for data/ Monte Carlo reconstructed + /// In case of Monte Carlo, calls initBase again for Monte Carlo truth and the specialized function initMC for additional histogramms /// \tparam T type of the configurable for the axis configuration /// \param registry Histogram registry to be passed /// \param kstarBins k* binning for the histograms @@ -106,7 +107,7 @@ class FemtoUniverseAngularContainer { mHistogramRegistry = registry; std::string femtoObs; - if constexpr (mFemtoObs == femtoUniverseAngularContainer::Observable::kstar) { + if constexpr (FemtoObs == femto_universe_angular_container::Observable::kstar) { femtoObs = "#it{k*} (GeV/#it{c})"; } @@ -120,18 +121,18 @@ class FemtoUniverseAngularContainer framework::AxisSpec mTAxis3D = {mTBins3D, "#it{m}_{T} (GeV/#it{c})"}; // angular correlations - mPhiLow = (-static_cast(phiBins / 4) + 0.5) * 2. * o2::constants::math::PI / phiBins; - mPhiHigh = 2 * o2::constants::math::PI + (-static_cast(phiBins / 4) + 0.5) * 2. * o2::constants::math::PI / phiBins; + mPhiLow = (-static_cast(phiBins / 4) + 0.5) * o2::constants::math::TwoPI / phiBins; + mPhiHigh = o2::constants::math::TwoPI + (-static_cast(phiBins / 4) + 0.5) * o2::constants::math::TwoPI / phiBins; framework::AxisSpec phiAxis = {phiBins, mPhiLow, mPhiHigh}; framework::AxisSpec etaAxis = {etaBins, -2.0, 2.0}; - std::string folderName = static_cast(mFolderSuffix[mEventType]) + static_cast(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kRecon]); + std::string folderName = static_cast(FolderSuffix[EventType]) + static_cast(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kRecon]); - init_base(folderName, femtoObs, femtoObsAxis, multAxis, kTAxis, mTAxis, multAxis3D, mTAxis3D, etaAxis, phiAxis, use3dplots); + initBase(folderName, femtoObs, femtoObsAxis, multAxis, kTAxis, mTAxis, multAxis3D, mTAxis3D, etaAxis, phiAxis, use3dplots); if (isMC) { - folderName = static_cast(mFolderSuffix[mEventType]) + static_cast(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kTruth]); - init_base(folderName, femtoObs, femtoObsAxis, multAxis, kTAxis, mTAxis, multAxis3D, mTAxis3D, etaAxis, phiAxis, use3dplots); - init_MC(folderName, femtoObs, femtoObsAxis, multAxis, mTAxis); + folderName = static_cast(FolderSuffix[EventType]) + static_cast(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kTruth]); + initBase(folderName, femtoObs, femtoObsAxis, multAxis, kTAxis, mTAxis, multAxis3D, mTAxis3D, etaAxis, phiAxis, use3dplots); + initMC(folderName, femtoObs, femtoObsAxis, multAxis, mTAxis); } } @@ -152,20 +153,21 @@ class FemtoUniverseAngularContainer /// \param part1 Particle one /// \param part2 Particle two /// \param mult Multiplicity of the event - template - void setPair_base(const float /*femtoObs*/, const float /*mT*/, T const& part1, T const& part2, const int /*mult*/, bool use3dplots) + template + void setPairBase(const float /*femtoObs*/, const float /*mT*/, T const& part1, T const& part2, const int /*mult*/, bool use3dplots, float weight = 1.0f) { - delta_eta = part1.eta() - part2.eta(); - delta_phi = part1.phi() - part2.phi(); + deltaEta = part1.eta() - part2.eta(); - while (delta_phi < mPhiLow) { - delta_phi += o2::constants::math::TwoPI; + deltaPhi = part1.phi() - part2.phi(); + + while (deltaPhi < mPhiLow) { + deltaPhi += o2::constants::math::TwoPI; } - while (delta_phi > mPhiHigh) { - delta_phi -= o2::constants::math::TwoPI; + while (deltaPhi > mPhiHigh) { + deltaPhi -= o2::constants::math::TwoPI; } - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/DeltaEtaDeltaPhi"), delta_phi, delta_eta); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/DeltaEtaDeltaPhi"), deltaPhi, deltaEta, weight); if (use3dplots) { // use 3d plots } @@ -175,11 +177,11 @@ class FemtoUniverseAngularContainer /// Fills MC truth specific histogramms: /// - kstar distribution plots with RECONSTRUCTED information but ONLY for non-fake candidates; needed for purity calculations of tracks /// - kstar resolution matrix - /// Note: Standard histogramms with MC truth information are filled with the setPair_base function + /// Note: Standard histogramms with MC truth information are filled with the setPairBase function /// \param part1 Particle one /// \param part2 Particle two /// \param mult Multiplicity of the event - void setPair_MC(const float /*femtoObsMC*/, const float /*femtoObs*/, const float /*mT*/, const int /*mult*/) + void setPairMC(const float /*femtoObsMC*/, const float /*femtoObs*/, const float /*mT*/, const int /*mult*/) { if (mHistogramRegistry) { // Fill the kstar distributions with the reconstructed information but only for particles with the right PDG code @@ -187,36 +189,36 @@ class FemtoUniverseAngularContainer } /// Templated function to handle data/ Monte Carlo reconstructed and Monte Carlo truth - /// Always calls setPair_base to compute the observables with reconstructed data - /// In case of Monte Carlo, calls setPair_base with MC info and specialized function setPair_MC for additional histogramms + /// Always calls setPairBase to compute the observables with reconstructed data + /// In case of Monte Carlo, calls setPairBase with MC info and specialized function setPairMC for additional histogramms /// \tparam T type of the femtouniverseparticle /// \param part1 Particle one /// \param part2 Particle two /// \param mult Multiplicity of the event template - void setPair(T const& part1, T const& part2, const int mult, bool use3dplots) + void setPair(T const& part1, T const& part2, const int mult, bool use3dplots, float weight = 1.0f) { float femtoObs, femtoObsMC; // Calculate femto observable and the mT with reconstructed information - if constexpr (mFemtoObs == femtoUniverseAngularContainer::Observable::kstar) { + if constexpr (FemtoObs == femto_universe_angular_container::Observable::kstar) { femtoObs = FemtoUniverseMath::getkstar(part1, mMassOne, part2, mMassTwo); } const float mT = FemtoUniverseMath::getmT(part1, mMassOne, part2, mMassTwo); if (mHistogramRegistry) { - setPair_base(femtoObs, mT, part1, part2, mult, use3dplots); + setPairBase(femtoObs, mT, part1, part2, mult, use3dplots); if constexpr (isMC) { if (part1.has_fdMCParticle() && part2.has_fdMCParticle()) { // calculate the femto observable and the mT with MC truth information - if constexpr (mFemtoObs == femtoUniverseAngularContainer::Observable::kstar) { + if constexpr (FemtoObs == femto_universe_angular_container::Observable::kstar) { femtoObsMC = FemtoUniverseMath::getkstar(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo); } const float mTMC = FemtoUniverseMath::getmT(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo); - if (abs(part1.fdMCParticle().pdgMCTruth()) == abs(mPDGOne) && abs(part2.fdMCParticle().pdgMCTruth()) == abs(mPDGTwo)) { // Note: all pair-histogramms are filled with MC truth information ONLY in case of non-fake candidates - setPair_base(femtoObsMC, mTMC, part1.fdMCParticle(), part2.fdMCParticle(), mult, use3dplots); - setPair_MC(femtoObsMC, femtoObs, mT, mult); + if (std::abs(part1.fdMCParticle().pdgMCTruth()) == std::abs(mPDGOne) && std::abs(part2.fdMCParticle().pdgMCTruth()) == std::abs(mPDGTwo)) { // Note: all pair-histogramms are filled with MC truth information ONLY in case of non-fake candidates + setPairBase(femtoObsMC, mTMC, part1.fdMCParticle(), part2.fdMCParticle(), mult, use3dplots, weight); + setPairMC(femtoObsMC, femtoObs, mT, mult); } else { } @@ -227,20 +229,20 @@ class FemtoUniverseAngularContainer } protected: - HistogramRegistry* mHistogramRegistry = nullptr; ///< For QA output - static constexpr std::string_view mFolderSuffix[2] = {"SameEvent", "MixedEvent"}; ///< Folder naming for the output according to mEventType - static constexpr femtoUniverseAngularContainer::Observable mFemtoObs = obs; ///< Femtoscopic observable to be computed (according to femtoUniverseAngularContainer::Observable) - static constexpr int mEventType = eventType; ///< Type of the event (same/mixed, according to femtoUniverseAngularContainer::EventType) - float mMassOne = 0.f; ///< PDG mass of particle 1 - float mMassTwo = 0.f; ///< PDG mass of particle 2 - int mPDGOne = 0; ///< PDG code of particle 1 - int mPDGTwo = 0; ///< PDG code of particle 2 + HistogramRegistry* mHistogramRegistry = nullptr; ///< For QA output + static constexpr std::string_view FolderSuffix[2] = {"SameEvent", "MixedEvent"}; ///< Folder naming for the output according to EventType + static constexpr femto_universe_angular_container::Observable FemtoObs = obs; ///< Femtoscopic observable to be computed (according to femto_universe_angular_container::Observable) + static constexpr int EventType = eventType; ///< Type of the event (same/mixed, according to femto_universe_angular_container::EventType) + float mMassOne = 0.f; ///< PDG mass of particle 1 + float mMassTwo = 0.f; ///< PDG mass of particle 2 + int mPDGOne = 0; ///< PDG code of particle 1 + int mPDGTwo = 0; ///< PDG code of particle 2 double mPhiLow; double mPhiHigh; - double delta_eta; - double delta_phi; + double deltaEta; + double deltaPhi; }; -} // namespace o2::analysis::femtoUniverse +} // namespace o2::analysis::femto_universe #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEANGULARCONTAINER_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseCascadeSelection.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseCascadeSelection.h new file mode 100644 index 00000000000..566323d078e --- /dev/null +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseCascadeSelection.h @@ -0,0 +1,584 @@ +// Copyright 2019-2022 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 FemtoUniverseCascadeSelection.h +/// \brief Definition of the femto_universe_cascade_selection +/// \author Valentina Mantovani Sarti, TU München valentina.mantovani-sarti@tum.de +/// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de +/// \author Luca Barioglio, TU München, luca.barioglio@cern.ch +/// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch +/// \author Barbara Chytla, WUT Warsaw, barbara.chytla@cern.ch +/// \author Shirajum Monira, WUT Warsaw, shirajum.monira@cern.ch + +#ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSECASCADESELECTION_H_ +#define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSECASCADESELECTION_H_ + +#include +#include +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseObjectSelection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseSelection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "Common/Core/RecoDecay.h" +#include "Framework/HistogramRegistry.h" +#include "ReconstructionDataFormats/PID.h" + +namespace o2::analysis::femto_universe +{ +namespace femto_universe_cascade_selection +{ +/// The different selections this task is capable of doing +enum CascadeSel { + kCascadeSign, ///< +1 particle, -1 antiparticle + kCascadepTMin, + kCascadepTMax, + kCascadeetaMax, + kCascadeV0DCADaughMax, + kCascadeV0CPAMin, + kCascadeV0TranRadMin, + kCascadeV0TranRadMax, + kCascadeV0DecVtxMax, + kCascadeDCADaughMax, + kCascadeCPAMin, + kCascadeTranRadMin, + kCascadeTranRadMax, + kCascadeDecVtxMax, + kCascadeDCAPosToPV, + kCascadeDCANegToPV, + kCascadeDCABachToPV, + kCascadeDCAV0ToPV, + kCascadeV0MassMin, + kCascadeV0MassMax +}; + +enum ChildTrackType { kPosTrack, + kNegTrack, + kBachTrack }; + +/*enum CascadeContainerPosition { + kCascade, + kPosCuts, + kPosPID, + kNegCuts, + kNegPID, +}; /// Position in the full VO cut container (for cutculator) +*/ +} // namespace femto_universe_cascade_selection + +/// \class FemtoUniverseCascadeSelection +/// \brief Cut class to contain and execute all cuts applied to Cascades +class FemtoUniverseCascadeSelection + : public FemtoUniverseObjectSelection +{ + // do cutculatora + + public: + FemtoUniverseCascadeSelection() + : nPtCascadeMinSel(0), nPtCascadeMaxSel(0), nEtaCascadeMaxSel(0), nDCAV0DaughMax(0), nCPAV0Min(0), nTranRadV0Min(0), nTranRadV0Max(0), nV0DecVtxMax(0), nDCACascadeDaughMax(0), nCPACascadeMin(0), nTranRadCascadeMin(0), nTranRadCascadeMax(0), nDecVtxMax(0), nDCAPosToPV(0), nDCANegToPV(0), nDCABachToPV(0), nDCAV0ToPV(0), pTCascadeMin(9999999.), pTCascadeMax(-9999999.), etaCascadeMax(-9999999.), fDCAV0DaughMax(-9999999.), fCPAV0Min(9999999.), fTranRadV0Min(9999999.), fTranRadV0Max(-9999999.), fV0DecVtxMax(-9999999.), fDCACascadeDaughMax(-9999999.), fCPACascadeMin(9999999.), fTranRadCascadeMin(9999999.), fTranRadCascadeMax(-9999999.), fDecVtxMax(-9999999.), fDCAPosToPV(9999999.), fDCANegToPV(9999999.), fDCABachToPV(9999999.), fDCAV0ToPV(9999999.), fV0InvMassLowLimit(1.05), fV0InvMassUpLimit(1.3), fInvMassLowLimit(1.25), fInvMassUpLimit(1.4), fRejectCompetingMass(false), fInvMassCompetingLowLimit(1.5), fInvMassCompetingUpLimit(2.0), isCascOmega(false) /*, nSigmaPIDOffsetTPC(0.)*/ + { + } + + /// Initializes histograms for the task + template + void init(HistogramRegistry* registry, bool isSelectCascOmega = false); + + template + bool isSelectedMinimal(Col const& col, Casc const& cascade, Track const& posTrack, Track const& negTrack, Track const& bachTrack); + + template + void fillCascadeQA(Col const& col, Casc const& cascade, Track const& posTrack, Track const& negTrack); + + template + void fillQA(Col const& col, Casc const& cascade, Track const& posTrack, Track const& negTrack, Track const& bachTrack); + + template + void setChildCuts(femto_universe_cascade_selection::ChildTrackType child, T1 selVal, + T2 selVar, femto_universe_selection::SelectionType selType) + { + if (child == femto_universe_cascade_selection::kPosTrack) { + posDaughTrack.setSelection(selVal, selVar, selType); + } else if (child == femto_universe_cascade_selection::kNegTrack) { + negDaughTrack.setSelection(selVal, selVar, selType); + } else if (child == femto_universe_cascade_selection::kBachTrack) { + bachTrackSel.setSelection(selVal, selVar, selType); + } + } + + template + void setChildPIDSpecies(femto_universe_cascade_selection::ChildTrackType child, + T& pids) + { + if (child == femto_universe_cascade_selection::kPosTrack) { + posDaughTrack.setPIDSpecies(pids); + } else if (child == femto_universe_cascade_selection::kNegTrack) { + negDaughTrack.setPIDSpecies(pids); + } else if (child == femto_universe_cascade_selection::kBachTrack) { + bachTrackSel.setPIDSpecies(pids); + } + } + + /// Helper function to obtain the name of a given selection criterion for consistent naming of the configurables + /// \param iSel Track selection variable to be examined + /// \param prefix Additional prefix for the name of the configurable + /// \param suffix Additional suffix for the name of the configurable + static std::string getSelectionName(femto_universe_cascade_selection::CascadeSel iSel, + std::string_view prefix = "", + std::string_view suffix = "") + { + std::string outString = static_cast(prefix); + outString += static_cast(SelectionNames[iSel]); + outString += suffix; + return outString; + } + + /// Helper function to obtain the helper string of a given selection criterion + /// for consistent description of the configurables + /// \param iSel Track selection variable to be examined + /// \param prefix Additional prefix for the output of the configurable + static std::string getSelectionHelper(femto_universe_cascade_selection::CascadeSel iSel, + std::string_view prefix = "") + { + std::string outString = static_cast(prefix); + outString += static_cast(SelectionHelper[iSel]); + return outString; + } + + /// Set limit for the selection on the invariant mass + /// \param lowLimit Lower limit for the invariant mass distribution + /// \param upLimit Upper limit for the invariant mass distribution + void setInvMassLimits(float lowLimit, float upLimit) + { + fInvMassLowLimit = lowLimit; + fInvMassUpLimit = upLimit; + } + + /// Set limit for the omega rejection on the invariant mass + /// \param lowLimit Lower limit for the invariant mass distribution + /// \param upLimit Upper limit for the invariant mass distribution + void setCompetingInvMassLimits(float lowLimit, float upLimit) + { + fRejectCompetingMass = true; + fInvMassCompetingLowLimit = lowLimit; + fInvMassCompetingUpLimit = upLimit; + } + + private: + int nPtCascadeMinSel; + int nPtCascadeMaxSel; + int nEtaCascadeMaxSel; + int nDCAV0DaughMax; + int nCPAV0Min; + int nTranRadV0Min; + int nTranRadV0Max; + int nV0DecVtxMax; + int nDCACascadeDaughMax; + int nCPACascadeMin; + int nTranRadCascadeMin; + int nTranRadCascadeMax; + int nDecVtxMax; + int nDCAPosToPV; + int nDCANegToPV; + int nDCABachToPV; + int nDCAV0ToPV; + float pTCascadeMin; + float pTCascadeMax; + float etaCascadeMax; + float fDCAV0DaughMax; + float fCPAV0Min; + float fTranRadV0Min; + float fTranRadV0Max; + float fV0DecVtxMax; + float fDCACascadeDaughMax; + float fCPACascadeMin; + float fTranRadCascadeMin; + float fTranRadCascadeMax; + float fDecVtxMax; + float fDCAPosToPV; + float fDCANegToPV; + float fDCABachToPV; + float fDCAV0ToPV; + + float fV0InvMassLowLimit; + float fV0InvMassUpLimit; + + float fInvMassLowLimit; + float fInvMassUpLimit; + + float fRejectCompetingMass; + float fInvMassCompetingLowLimit; + float fInvMassCompetingUpLimit; + + bool isCascOmega; + + // float nSigmaPIDOffsetTPC; + + FemtoUniverseTrackSelection posDaughTrack; + FemtoUniverseTrackSelection negDaughTrack; + FemtoUniverseTrackSelection bachTrackSel; + + static constexpr int kNcascadeSelection = 20; // can I do less ? + + static constexpr std::string_view SelectionNames[kNcascadeSelection] = { + "Sign", "PtMin", "PtMax", "EtaMax", "DCAv0daughMax", "v0CPAMin", + "v0TranRadMin", "v0TranRadMax", "v0DecVecMax", "DCAcascDaugh", + "CPAMin", "TranRadMin", "TranRadMax", "DecVtxMax", + "DCAPosToPV", "DCANegToPV", "DCABachToPV", "DCAV0ToPV", + "kV0MassMin", "V0MassMax"}; ///< Name of the different + ///< selections + + static constexpr femto_universe_selection::SelectionType + mSelectionTypes[kNcascadeSelection]{ + femto_universe_selection::kEqual, // sign + femto_universe_selection::kLowerLimit, // pt min + femto_universe_selection::kUpperLimit, // pt max + femto_universe_selection::kUpperLimit, // eta max + femto_universe_selection::kUpperLimit, // DCA v0 daughters max + femto_universe_selection::kLowerLimit, // v0 cos PA min + femto_universe_selection::kLowerLimit, // v0 tran rad min + femto_universe_selection::kUpperLimit, // v0 tran rad max + femto_universe_selection::kUpperLimit, // v0 maximum distance of decay vertex to PV + femto_universe_selection::kUpperLimit, // DCA cascade daughters max + femto_universe_selection::kLowerLimit, // cascade cos PA min + femto_universe_selection::kLowerLimit, // cascade tran rad min + femto_universe_selection::kUpperLimit, // cascade tran rad max + femto_universe_selection::kUpperLimit, // cascade maximum distance of decay vertex to PV + femto_universe_selection::kLowerLimit, // DCA pos to PV max + femto_universe_selection::kLowerLimit, // DCA neg to PV max + femto_universe_selection::kLowerLimit, // DCA bach to PV max + femto_universe_selection::kLowerLimit, // DCA v0 to PV max + femto_universe_selection::kLowerLimit, // v0 mass min + femto_universe_selection::kUpperLimit, // v0 mass max + }; ///< Map to match a variable with + ///< its type + + static constexpr std::string_view SelectionHelper[kNcascadeSelection] = { + "Cascade particle sign (+1 or -1)", + "Minimum pT (GeV/c)", + "Maximum pT (GeV/c)", + "Maximum |Eta|", + "Maximum DCA between v0 daughters (cm)", + "Minimum Cosine of Pointing Angle for v0", + "Minimum v0 transverse radius (cm)", + "Maximum v0 transverse radius (cm)", + "Maximum distance of v0 from primary vertex", + "Maximum DCA between cascade daughters (cm)", + "Minimum Cosine of Pointing Angle for cascade", + "Minimum cascade transverse radius (cm)", + "Maximum cascade transverse radius (cm)", + "Maximum distance of cascade from primary vertex", + "Maximum DCA of positive track form primary vertex", + "Maximum DCA of negative track form primary vertex", + "Maximum DCA of bachelor track form primary vertex", + "Maximum DCA of v0 form primary vertex", + "Minimum V0 mass", + "Maximum V0 mass"}; ///< Helper information for the + ///< different selections + +}; // namespace femto_universe + +template +void FemtoUniverseCascadeSelection::init(HistogramRegistry* registry, bool isSelectCascOmega) +{ + + if (registry) { + mHistogramRegistry = registry; + fillSelectionHistogram(); // cascade + fillSelectionHistogram(); // pos, neg + fillSelectionHistogram(); // bach + + AxisSpec massAxisCascade = {2200, 1.25f, 1.8f, "m_{Cascade} (GeV/#it{c}^{2})"}; + AxisSpec massAxisV0 = {600, 0.0f, 3.0f, "m_{V0} (GeV/#it{c}^{2})"}; + AxisSpec aDCADaughAxis = {1000, 0.0f, 2.0f, "DCA (cm)"}; + AxisSpec aDCAToPVAxis = {1000, -10.0f, 10.0f, "DCA to PV (cm)"}; + AxisSpec ptAxis = {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec etaAxis = {100, -2.0f, 2.0f, "#it{#eta}"}; + AxisSpec phiAxis = {100, 0.0f, 6.0f, "#it{#phi}"}; + AxisSpec aCPAAxis = {1000, 0.95f, 1.0f, "#it{cos #theta_{p}}"}; + AxisSpec tranRadAxis = {1000, 0.0f, 100.0f, "#it{r}_{xy} (cm)"}; + + /// \todo this should be an automatic check in the parent class, and the + /// return type should be templated + size_t nSelections = getNSelections(); + if (nSelections > 17 * sizeof(CutContainerType)) { + LOG(fatal) << "FemtoUniverseCascadeCuts: Number of selections to large for your " + "container - quitting!"; + } + + posDaughTrack.init( + mHistogramRegistry); + negDaughTrack.init( + mHistogramRegistry); + bachTrackSel.init( + mHistogramRegistry); + + // V0 (Lambda) + // mHistogramRegistry->add("CascadeQA/hInvMassV0NoCuts", "No cuts", kTH1F, {massAxisV0}); + mHistogramRegistry->add("CascadeQA/hInvMassV0Cut", "Invariant mass cut", kTH1F, {massAxisV0}); + mHistogramRegistry->add("CascadeQA/hDCAV0Daugh", "V0-daughters DCA", kTH1F, {aDCADaughAxis}); + mHistogramRegistry->add("CascadeQA/hV0CPA", "V0 cos PA", kTH1F, {aCPAAxis}); + mHistogramRegistry->add("CascadeQA/hV0TranRad", "V0 transverse radius", kTH1F, {tranRadAxis}); + // mHistogramRegistry->add("CascadeQA/hV0DecVtxMax", "V0 maximum distance on decay vertex", kTH1F, {massAxisV0}); + + // Cascade (Xi, Omega) + // mHistogramRegistry->add("CascadeQA/hInvMassCascadeNoCuts", "No cuts", kTH1F, {massAxisCascade}); + mHistogramRegistry->add("CascadeQA/hInvMassCascadeCut", "Invariant mass with cut", kTH1F, {massAxisCascade}); + mHistogramRegistry->add("CascadeQA/hCascadePt", "pT distribution", kTH1F, {ptAxis}); + mHistogramRegistry->add("CascadeQA/hCascadeEta", "Eta distribution", kTH1F, {etaAxis}); + mHistogramRegistry->add("CascadeQA/hCascadePhi", "Phi distribution", kTH1F, {phiAxis}); + mHistogramRegistry->add("CascadeQA/hDCACascadeDaugh", "Cascade-daughters DCA", kTH1F, {aDCADaughAxis}); + mHistogramRegistry->add("CascadeQA/hCascadeCPA", "Cos PA", kTH1F, {aCPAAxis}); + mHistogramRegistry->add("CascadeQA/hCascadeTranRad", "Transverse radius", kTH1F, {tranRadAxis}); + mHistogramRegistry->add("CascadeQA/hDCAPosToPV", "Pos V0 daughter DCA to primary vertex", kTH1F, {aDCAToPVAxis}); + mHistogramRegistry->add("CascadeQA/hDCANegToPV", "Neg V0 daughter DCA to primary vertex", kTH1F, {aDCAToPVAxis}); + mHistogramRegistry->add("CascadeQA/hDCABachToPV", "Bachelor DCA to primary vertex", kTH1F, {aDCAToPVAxis}); + mHistogramRegistry->add("CascadeQA/hDCAV0ToPV", "V0 DCA to primary vertex", kTH1F, {aDCAToPVAxis}); + } + + /// check whether the most open cuts are fulfilled - most of this should have + /// already be done by the filters + nPtCascadeMinSel = getNSelections(femto_universe_cascade_selection::kCascadepTMin); + nPtCascadeMaxSel = getNSelections(femto_universe_cascade_selection::kCascadepTMax); + nEtaCascadeMaxSel = getNSelections(femto_universe_cascade_selection::kCascadeetaMax); + nDCAV0DaughMax = getNSelections(femto_universe_cascade_selection::kCascadeV0DCADaughMax); + nCPAV0Min = getNSelections(femto_universe_cascade_selection::kCascadeV0CPAMin); + nTranRadV0Min = getNSelections(femto_universe_cascade_selection::kCascadeV0TranRadMin); + nTranRadV0Max = getNSelections(femto_universe_cascade_selection::kCascadeV0TranRadMax); + nV0DecVtxMax = getNSelections(femto_universe_cascade_selection::kCascadeV0DecVtxMax); + nDCACascadeDaughMax = getNSelections(femto_universe_cascade_selection::kCascadeDCADaughMax); + nCPACascadeMin = getNSelections(femto_universe_cascade_selection::kCascadeCPAMin); + nTranRadCascadeMin = getNSelections(femto_universe_cascade_selection::kCascadeTranRadMin); + nTranRadCascadeMax = getNSelections(femto_universe_cascade_selection::kCascadeTranRadMax); + nDecVtxMax = getNSelections(femto_universe_cascade_selection::kCascadeDecVtxMax); + nDCAPosToPV = getNSelections(femto_universe_cascade_selection::kCascadeDCAPosToPV); + nDCANegToPV = getNSelections(femto_universe_cascade_selection::kCascadeDCANegToPV); + nDCABachToPV = getNSelections(femto_universe_cascade_selection::kCascadeDCABachToPV); + nDCAV0ToPV = getNSelections(femto_universe_cascade_selection::kCascadeDCAV0ToPV); + // dodac V0 mass min i max + + pTCascadeMin = getMinimalSelection(femto_universe_cascade_selection::kCascadepTMin, + femto_universe_selection::kLowerLimit); + pTCascadeMax = getMinimalSelection(femto_universe_cascade_selection::kCascadepTMax, + femto_universe_selection::kUpperLimit); + etaCascadeMax = getMinimalSelection(femto_universe_cascade_selection::kCascadeetaMax, + femto_universe_selection::kAbsUpperLimit); + fDCAV0DaughMax = getMinimalSelection(femto_universe_cascade_selection::kCascadeV0DCADaughMax, + femto_universe_selection::kUpperLimit); + fCPAV0Min = getMinimalSelection(femto_universe_cascade_selection::kCascadeV0CPAMin, + femto_universe_selection::kLowerLimit); + fTranRadV0Min = getMinimalSelection(femto_universe_cascade_selection::kCascadeV0TranRadMin, + femto_universe_selection::kLowerLimit); + fTranRadV0Max = getMinimalSelection(femto_universe_cascade_selection::kCascadeV0TranRadMax, + femto_universe_selection::kUpperLimit); + fV0DecVtxMax = getMinimalSelection(femto_universe_cascade_selection::kCascadeV0DecVtxMax, + femto_universe_selection::kAbsUpperLimit); + fDCACascadeDaughMax = getMinimalSelection(femto_universe_cascade_selection::kCascadeDCADaughMax, + femto_universe_selection::kUpperLimit); + fCPACascadeMin = getMinimalSelection(femto_universe_cascade_selection::kCascadeCPAMin, + femto_universe_selection::kLowerLimit); + fTranRadCascadeMin = getMinimalSelection(femto_universe_cascade_selection::kCascadeTranRadMin, + femto_universe_selection::kLowerLimit); + fTranRadCascadeMax = getMinimalSelection(femto_universe_cascade_selection::kCascadeTranRadMax, + femto_universe_selection::kUpperLimit); + fDecVtxMax = getMinimalSelection(femto_universe_cascade_selection::kCascadeDecVtxMax, + femto_universe_selection::kAbsUpperLimit); + fDCAPosToPV = getMinimalSelection(femto_universe_cascade_selection::kCascadeDCAPosToPV, + femto_universe_selection::kLowerLimit); + fDCANegToPV = getMinimalSelection(femto_universe_cascade_selection::kCascadeDCANegToPV, + femto_universe_selection::kLowerLimit); + fDCABachToPV = getMinimalSelection(femto_universe_cascade_selection::kCascadeDCABachToPV, + femto_universe_selection::kLowerLimit); + fDCAV0ToPV = getMinimalSelection(femto_universe_cascade_selection::kCascadeDCAV0ToPV, + femto_universe_selection::kLowerLimit); + fV0InvMassLowLimit = getMinimalSelection(femto_universe_cascade_selection::kCascadeV0MassMin, + femto_universe_selection::kLowerLimit); + fV0InvMassUpLimit = getMinimalSelection(femto_universe_cascade_selection::kCascadeV0MassMax, + femto_universe_selection::kUpperLimit); + + isCascOmega = isSelectCascOmega; +} + +template +bool FemtoUniverseCascadeSelection::isSelectedMinimal(Col const& col, Casc const& cascade, Track const& posTrack, Track const& negTrack, Track const& bachTrack) +{ + const auto signPos = posTrack.sign(); + const auto signNeg = negTrack.sign(); + + if (signPos < 0 || signNeg > 0) { + LOG(warn) << "Something wrong in isSelectedMinimal"; + LOG(warn) << "ERROR - Wrong sign for V0 daughters"; + } + + const std::vector decVtx = {cascade.x(), cascade.y(), cascade.z()}; + + const float cpav0 = cascade.v0cosPA(col.posX(), col.posY(), col.posZ()); + const float cpaCasc = cascade.casccosPA(col.posX(), col.posY(), col.posZ()); + const float dcav0topv = cascade.dcav0topv(col.posX(), col.posY(), col.posZ()); + const float invMassLambda = cascade.mLambda(); + const float invMass = isCascOmega ? cascade.mOmega() : cascade.mXi(); + + if (invMassLambda < fV0InvMassLowLimit || invMassLambda > fV0InvMassUpLimit) { + return false; + } + if (invMass < fInvMassLowLimit || invMass > fInvMassUpLimit) { + return false; + } + if (fRejectCompetingMass) { + const float invMassCompeting = isCascOmega ? cascade.mXi() : cascade.mOmega(); + if (invMassCompeting > fInvMassCompetingLowLimit && + invMassCompeting < fInvMassCompetingUpLimit) { + return false; + } + } + if (nPtCascadeMinSel > 0 && cascade.pt() < pTCascadeMin) { + return false; + } + if (nPtCascadeMaxSel > 0 && cascade.pt() > pTCascadeMax) { + return false; + } + if (nEtaCascadeMaxSel > 0 && std::abs(cascade.eta()) > etaCascadeMax) { + return false; + } + if (nDCAV0DaughMax > 0 && cascade.dcaV0daughters() > fDCAV0DaughMax) { + return false; + } + if (nCPAV0Min > 0 && cpav0 < fCPAV0Min) { + return false; + } + if (nTranRadV0Min > 0 && cascade.v0radius() < fTranRadV0Min) { + return false; + } + if (nTranRadV0Max > 0 && cascade.v0radius() > fTranRadV0Max) { + return false; + } + if (nDCACascadeDaughMax > 0 && cascade.dcacascdaughters() > fDCACascadeDaughMax) { + return false; + } + if (nCPACascadeMin > 0 && cpaCasc < fCPACascadeMin) { + return false; + } + if (nTranRadCascadeMin > 0 && cascade.cascradius() < fTranRadCascadeMin) { + return false; + } + if (nTranRadCascadeMax > 0 && cascade.cascradius() > fTranRadCascadeMax) { + return false; + } + for (size_t i = 0; i < decVtx.size(); i++) { + if (nDecVtxMax > 0 && decVtx.at(i) > fDecVtxMax) { + return false; + } + } + if (nDCAPosToPV > 0 && std::abs(cascade.dcapostopv()) < fDCAPosToPV) { + return false; + } + if (nDCANegToPV > 0 && std::abs(cascade.dcanegtopv()) < fDCANegToPV) { + return false; + } + if (nDCABachToPV > 0 && std::abs(cascade.dcabachtopv()) < fDCABachToPV) { + return false; + } + if (nDCAV0ToPV > 0 && std::abs(dcav0topv) < fDCAV0ToPV) { + return false; + } + + if (!posDaughTrack.isSelectedMinimal(posTrack)) { + return false; + } + if (!negDaughTrack.isSelectedMinimal(negTrack)) { + return false; + } + if (!bachTrackSel.isSelectedMinimal(bachTrack)) { + return false; + } + /* + // check that track combinations for V0 or antiV0 would be fulfilling PID + float nSigmaPIDMax = posDaughTrack.getSigmaPIDMax(); + // antiV0 + auto nSigmaPrNeg = negTrack.tpcNSigmaPr(); + auto nSigmaPiPos = posTrack.tpcNSigmaPi(); + // v0 + auto nSigmaPiNeg = negTrack.tpcNSigmaPi(); + auto nSigmaPrPos = posTrack.tpcNSigmaPr(); + if (!(std::abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && + std::abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax) && + !(std::abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && + std::abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax)) { + return false; + } + */ + return true; +} + +template +void FemtoUniverseCascadeSelection::fillCascadeQA(Col const& col, Casc const& cascade, Track const& posTrack, Track const& negTrack) +{ + const auto signPos = posTrack.sign(); + const auto signNeg = negTrack.sign(); + if (signPos < 0 || signNeg > 0) { + LOG(warn) << "Something wrong in isSelectedMinimal"; + LOG(warn) << "ERROR - Wrong sign for V0 daughters"; + } + + // const std::vector decVtx = {cascade.x(), cascade.y(), cascade.z()}; + const float cpav0 = cascade.v0cosPA(col.posX(), col.posY(), col.posZ()); + const float cpaCasc = cascade.casccosPA(col.posX(), col.posY(), col.posZ()); + const float dcav0topv = cascade.dcav0topv(col.posX(), col.posY(), col.posZ()); + + const float invMassLambda = cascade.mLambda(); + const float invMass = isCascOmega ? cascade.mOmega() : cascade.mXi(); + + mHistogramRegistry->fill(HIST("CascadeQA/hInvMassV0Cut"), invMassLambda); + mHistogramRegistry->fill(HIST("CascadeQA/hInvMassCascadeCut"), invMass); + mHistogramRegistry->fill(HIST("CascadeQA/hCascadePt"), cascade.pt()); + mHistogramRegistry->fill(HIST("CascadeQA/hCascadeEta"), cascade.eta()); + mHistogramRegistry->fill(HIST("CascadeQA/hCascadePhi"), cascade.phi()); + mHistogramRegistry->fill(HIST("CascadeQA/hDCAV0Daugh"), cascade.dcaV0daughters()); + mHistogramRegistry->fill(HIST("CascadeQA/hV0CPA"), cpav0); + mHistogramRegistry->fill(HIST("CascadeQA/hV0TranRad"), cascade.v0radius()); + mHistogramRegistry->fill(HIST("CascadeQA/hCascadeCPA"), cpaCasc); + mHistogramRegistry->fill(HIST("CascadeQA/hDCACascadeDaugh"), cascade.dcacascdaughters()); + mHistogramRegistry->fill(HIST("CascadeQA/hCascadeTranRad"), cascade.cascradius()); + mHistogramRegistry->fill(HIST("CascadeQA/hDCAPosToPV"), cascade.dcapostopv()); + mHistogramRegistry->fill(HIST("CascadeQA/hDCANegToPV"), cascade.dcanegtopv()); + mHistogramRegistry->fill(HIST("CascadeQA/hDCABachToPV"), cascade.dcabachtopv()); + mHistogramRegistry->fill(HIST("CascadeQA/hDCAV0ToPV"), dcav0topv); + + // is this necessary + /* + bool write = true; + for (size_t i = 0; i < decVtx.size(); i++) { + write = write && (decVtx.at(i) < DecVtxMax); + } + if (write) { + mHistogramRegistry->fill(HIST("CAscadeQA/hInvMassCascadeDecVtxMax"), + cascade.mXi()); + } + */ +} + +template +void FemtoUniverseCascadeSelection::fillQA(Col const& /*col*/, Casc const& /*cascade*/, Track const& posTrack, Track const& negTrack, Track const& bachTrack) +{ + posDaughTrack.fillQA(posTrack); + negDaughTrack.fillQA(negTrack); + bachTrackSel.fillQA(bachTrack); +} + +} // namespace o2::analysis::femto_universe + +#endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSECASCADESELECTION_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseCollisionSelection.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseCollisionSelection.h index c75b09e8153..fc33b37ad9a 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseCollisionSelection.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseCollisionSelection.h @@ -19,14 +19,13 @@ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSECOLLISIONSELECTION_H_ #include -#include #include "Common/CCDB/TriggerAliases.h" #include "Framework/HistogramRegistry.h" #include "Framework/Logger.h" using namespace o2::framework; -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { /// \class FemtoUniverseCollisionSelection @@ -160,33 +159,33 @@ class FemtoUniverseCollisionSelection template float computeSphericity(T1 const& /*col*/, T2 const& tracks) { - double S00 = 0; - double S11 = 0; - double S10 = 0; + double kS00 = 0; + double kS11 = 0; + double kS10 = 0; double sumPt = 0; int partNumber = 0; double spher = 0; - for (auto& p : tracks) { + for (const auto& p : tracks) { double phi = p.phi(); double pT = p.pt(); - double px = pT * TMath::Cos(phi); - double py = pT * TMath::Sin(phi); + double px = pT * std::cos(phi); + double py = pT * std::sin(phi); - S00 = S00 + px * px / pT; - S11 = S11 + py * py / pT; - S10 = S10 + px * py / pT; + kS00 = kS00 + px * px / pT; + kS11 = kS11 + py * py / pT; + kS10 = kS10 + px * py / pT; sumPt = sumPt + pT; partNumber++; } if (sumPt != 0) { - S00 = S00 / sumPt; - S11 = S11 / sumPt; - S10 = S10 / sumPt; + kS00 = kS00 / sumPt; + kS11 = kS11 / sumPt; + kS10 = kS10 / sumPt; - double lambda1 = (S00 + S11 + TMath::Sqrt((S00 + S11) * (S00 + S11) - 4.0 * (S00 * S11 - S10 * S10))) / 2.0; - double lambda2 = (S00 + S11 - TMath::Sqrt((S00 + S11) * (S00 + S11) - 4.0 * (S00 * S11 - S10 * S10))) / 2.0; + double lambda1 = (kS00 + kS11 + std::sqrt((kS00 + kS11) * (kS00 + kS11) - 4.0 * (kS00 * kS11 - kS10 * kS10))) / 2.0; + double lambda2 = (kS00 + kS11 - std::sqrt((kS00 + kS11) * (kS00 + kS11) - 4.0 * (kS00 * kS11 - kS10 * kS10))) / 2.0; if ((lambda1 + lambda2) != 0 && partNumber > 2) { spher = 2 * lambda2 / (lambda1 + lambda2); @@ -215,6 +214,6 @@ class FemtoUniverseCollisionSelection float mCentMin = 0.0; ///< Minimum centrality value float mCentMax = 100.0; ///< Maximum centrality value }; -} // namespace o2::analysis::femtoUniverse +} // namespace o2::analysis::femto_universe #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSECOLLISIONSELECTION_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h index 285dabc0b4d..67dce9fc125 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h @@ -25,6 +25,7 @@ #include #include "Framework/HistogramRegistry.h" +#include "Common/Core/RecoDecay.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" #include "Math/Vector4D.h" @@ -33,10 +34,10 @@ using namespace o2::framework; -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { -namespace femtoUniverseContainer +namespace femto_universe_container { /// Femtoscopic observable to be computed enum Observable { kstar ///< kstar @@ -46,7 +47,7 @@ enum Observable { kstar ///< kstar enum EventType { same, ///< Pair from same event mixed ///< Pair from mixed event }; -}; // namespace femtoUniverseContainer +}; // namespace femto_universe_container /// \class FemtoUniverseContainer /// \brief Container for all histogramming related to the correlation function. The two @@ -54,7 +55,7 @@ enum EventType { same, ///< Pair from same event /// are filled according to the specified observable /// \tparam eventType Type of the event (same/mixed) /// \tparam obs Observable to be computed (k*/Q_inv/...) -template +template class FemtoUniverseContainer { public: @@ -71,7 +72,7 @@ class FemtoUniverseContainer /// \param kTAxis axis object for the kT axis /// \param mTAxis axis object for the mT axis template - void init_base(std::string folderName, std::string femtoObs, T femtoObsAxis, T multAxis, T kTAxis, T mTAxis, T multAxis3D, T mTAxis3D, T etaAxis, T phiAxis, bool use3dplots) + void initBase(std::string folderName, std::string femtoObs, T femtoObsAxis, T multAxis, T kTAxis, T mTAxis, T multAxis3D, T mTAxis3D, T etaAxis, T phiAxis, bool use3dplots) { mHistogramRegistry->add((folderName + "/relPairDist").c_str(), ("; " + femtoObs + "; Entries").c_str(), kTH1F, {femtoObsAxis}); mHistogramRegistry->add((folderName + "/relPairkT").c_str(), "; #it{k}_{T} (GeV/#it{c}); Entries", kTH1F, {kTAxis}); @@ -95,7 +96,7 @@ class FemtoUniverseContainer /// \param folderName Name of the directory in the output file (no suffix for reconstructed data/ Monte Carlo; "_MC" for Monte Carlo Truth) /// \param femtoObsAxis axis object for the femto observable axis template - void init_MC(std::string folderName, std::string femtoObs, T femtoObsAxis, T multAxis, T mTAxis) + void initMC(std::string folderName, std::string femtoObs, T femtoObsAxis, T multAxis, T mTAxis) { mHistogramRegistry->add((folderName + "/relPairDist_ReconNoFake").c_str(), ("; " + femtoObs + "; Entries").c_str(), kTH1F, {femtoObsAxis}); mHistogramRegistry->add((folderName + "/relPairkstarmT_ReconNoFake").c_str(), ("; " + femtoObs + "; #it{m}_{T} (GeV/#it{c}^{2})").c_str(), kTH2F, {femtoObsAxis, mTAxis}); @@ -106,8 +107,8 @@ class FemtoUniverseContainer } /// Templated function to initialize the histograms for the task - /// Always calls init_base to initialize the histograms for data/ Monte Carlo reconstructed - /// In case of Monte Carlo, calls init_base again for Monte Carlo truth and the specialized function init_MC for additional histogramms + /// Always calls initBase to initialize the histograms for data/ Monte Carlo reconstructed + /// In case of Monte Carlo, calls initBase again for Monte Carlo truth and the specialized function initMC for additional histogramms /// \tparam T type of the configurable for the axis configuration /// \param registry Histogram registry to be passed /// \param kstarBins k* binning for the histograms @@ -122,7 +123,7 @@ class FemtoUniverseContainer { mHistogramRegistry = registry; std::string femtoObs; - if constexpr (mFemtoObs == femtoUniverseContainer::Observable::kstar) { + if constexpr (FemtoObs == femto_universe_container::Observable::kstar) { femtoObs = "#it{k*} (GeV/#it{c})"; } std::vector tmpVecMult = multBins; @@ -135,18 +136,18 @@ class FemtoUniverseContainer framework::AxisSpec mTAxis3D = {mTBins3D, "#it{m}_{T} (GeV/#it{c})"}; // angular correlations - mPhiLow = (-static_cast(phiBins / 4) + 0.5) * 2. * o2::constants::math::PI / phiBins; - mPhiHigh = 2 * o2::constants::math::PI + (-static_cast(phiBins / 4) + 0.5) * 2. * o2::constants::math::PI / phiBins; + mPhiLow = (-static_cast(phiBins / 4) + 0.5) * o2::constants::math::TwoPI / phiBins; + mPhiHigh = o2::constants::math::TwoPI + (-static_cast(phiBins / 4) + 0.5) * o2::constants::math::TwoPI / phiBins; framework::AxisSpec phiAxis = {phiBins, mPhiLow, mPhiHigh}; framework::AxisSpec etaAxis = {etaBins, -2.0, 2.0}; - std::string folderName = static_cast(mFolderSuffix[mEventType]) + static_cast(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kRecon]); + std::string folderName = static_cast(FolderSuffix[EventType]) + static_cast(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kRecon]); - init_base(folderName, femtoObs, femtoObsAxis, multAxis, kTAxis, mTAxis, multAxis3D, mTAxis3D, etaAxis, phiAxis, use3dplots); + initBase(folderName, femtoObs, femtoObsAxis, multAxis, kTAxis, mTAxis, multAxis3D, mTAxis3D, etaAxis, phiAxis, use3dplots); if (isMC) { - folderName = static_cast(mFolderSuffix[mEventType]) + static_cast(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kTruth]); - init_base(folderName, femtoObs, femtoObsAxis, multAxis, kTAxis, mTAxis, multAxis3D, mTAxis3D, etaAxis, phiAxis, use3dplots); - init_MC(folderName, femtoObs, femtoObsAxis, multAxis, mTAxis); + folderName = static_cast(FolderSuffix[EventType]) + static_cast(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kTruth]); + initBase(folderName, femtoObs, femtoObsAxis, multAxis, kTAxis, mTAxis, multAxis3D, mTAxis3D, etaAxis, phiAxis, use3dplots); + initMC(folderName, femtoObs, femtoObsAxis, multAxis, mTAxis); } } @@ -167,33 +168,33 @@ class FemtoUniverseContainer /// \param part1 Particle one /// \param part2 Particle two /// \param mult Multiplicity of the event - template - void setPair_base(const float femtoObs, const float mT, T const& part1, T const& part2, const int mult, bool use3dplots) + template + void setPairBase(const float femtoObs, const float mT, T const& part1, T const& part2, const int mult, bool use3dplots, float weight = 1.0f) { const float kT = FemtoUniverseMath::getkT(part1, mMassOne, part2, mMassTwo); - delta_eta = part1.eta() - part2.eta(); - delta_phi = part1.phi() - part2.phi(); + deltaEta = part1.eta() - part2.eta(); + deltaPhi = part1.phi() - part2.phi(); - while (delta_phi < mPhiLow) { - delta_phi += o2::constants::math::TwoPI; + while (deltaPhi < mPhiLow) { + deltaPhi += o2::constants::math::TwoPI; } - while (delta_phi > mPhiHigh) { - delta_phi -= o2::constants::math::TwoPI; + while (deltaPhi > mPhiHigh) { + deltaPhi -= o2::constants::math::TwoPI; } - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairDist"), femtoObs); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkT"), kT); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkstarkT"), femtoObs, kT); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkstarmT"), femtoObs, mT); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkstarMult"), femtoObs, mult); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/kstarPtPart1"), femtoObs, part1.pt()); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/kstarPtPart2"), femtoObs, part2.pt()); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/MultPtPart1"), part1.pt(), mult); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/MultPtPart2"), part2.pt(), mult); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/PtPart1PtPart2"), part1.pt(), part2.pt()); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/DeltaEtaDeltaPhi"), delta_phi, delta_eta); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairDist"), femtoObs, weight); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkT"), kT, weight); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkstarkT"), femtoObs, kT, weight); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkstarmT"), femtoObs, mT, weight); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkstarMult"), femtoObs, mult, weight); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/kstarPtPart1"), femtoObs, part1.pt(), weight); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/kstarPtPart2"), femtoObs, part2.pt(), weight); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/MultPtPart1"), part1.pt(), mult, weight); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/MultPtPart2"), part2.pt(), mult, weight); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/PtPart1PtPart2"), part1.pt(), part2.pt(), weight); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/DeltaEtaDeltaPhi"), deltaPhi, deltaEta, weight); if (use3dplots) { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkstarmTMult"), femtoObs, mT, mult); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkstarmTMult"), femtoObs, mT, mult, weight); } } @@ -201,79 +202,87 @@ class FemtoUniverseContainer /// Fills MC truth specific histogramms: /// - kstar distribution plots with RECONSTRUCTED information but ONLY for non-fake candidates; needed for purity calculations of tracks /// - kstar resolution matrix - /// Note: Standard histogramms with MC truth information are filled with the setPair_base function + /// Note: Standard histogramms with MC truth information are filled with the setPairBase function /// \param part1 Particle one /// \param part2 Particle two /// \param mult Multiplicity of the event - void setPair_MC(const float femtoObsMC, const float femtoObs, const float mT, const int mult) + void setPairMC(const float femtoObsMC, const float femtoObs, const float mT, const int mult) { if (mHistogramRegistry) { // Fill the kstar distributions with the reconstructed information but only for particles with the right PDG code - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kTruth]) + HIST("/relPairDist_ReconNoFake"), femtoObs); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kTruth]) + HIST("/relPairkstarmT_ReconNoFake"), femtoObs, mT); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kTruth]) + HIST("/relPairkstarMult_ReconNoFake"), femtoObs, mult); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kTruth]) + HIST("/relPairDist_ReconNoFake"), femtoObs); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kTruth]) + HIST("/relPairkstarmT_ReconNoFake"), femtoObs, mT); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kTruth]) + HIST("/relPairkstarMult_ReconNoFake"), femtoObs, mult); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kTruth]) + HIST("/kstar_resolution"), femtoObsMC, femtoObs); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kTruth]) + HIST("/kstar_resolution"), femtoObsMC, femtoObs); } } /// Templated function to handle data/ Monte Carlo reconstructed and Monte Carlo truth - /// Always calls setPair_base to compute the observables with reconstructed data - /// In case of Monte Carlo, calls setPair_base with MC info and specialized function setPair_MC for additional histogramms + /// Always calls setPairBase to compute the observables with reconstructed data + /// In case of Monte Carlo, calls setPairBase with MC info and specialized function setPairMC for additional histogramms /// \tparam T type of the femtouniverseparticle /// \param part1 Particle one /// \param part2 Particle two /// \param mult Multiplicity of the event template - void setPair(T const& part1, T const& part2, const int mult, bool use3dplots) + void setPair(T const& part1, T const& part2, const int mult, bool use3dplots, float weight = 1.0f, bool isiden = false) { float femtoObs, femtoObsMC; // Calculate femto observable and the mT with reconstructed information - if constexpr (mFemtoObs == femtoUniverseContainer::Observable::kstar) { - femtoObs = FemtoUniverseMath::getkstar(part1, mMassOne, part2, mMassTwo); + if constexpr (FemtoObs == femto_universe_container::Observable::kstar) { + if (!isiden) { + femtoObs = FemtoUniverseMath::getkstar(part1, mMassOne, part2, mMassTwo); + } else { + femtoObs = 2.0 * FemtoUniverseMath::getkstar(part1, mMassOne, part2, mMassTwo); + } } const float mT = FemtoUniverseMath::getmT(part1, mMassOne, part2, mMassTwo); if (mHistogramRegistry) { - setPair_base(femtoObs, mT, part1, part2, mult, use3dplots); + setPairBase(femtoObs, mT, part1, part2, mult, use3dplots, weight); if constexpr (isMC) { if (part1.has_fdMCParticle() && part2.has_fdMCParticle()) { // calculate the femto observable and the mT with MC truth information - if constexpr (mFemtoObs == femtoUniverseContainer::Observable::kstar) { - femtoObsMC = FemtoUniverseMath::getkstar(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo); + if constexpr (FemtoObs == femto_universe_container::Observable::kstar) { + if (!isiden) { + femtoObsMC = FemtoUniverseMath::getkstar(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo); + } else { + femtoObsMC = 2.0 * FemtoUniverseMath::getkstar(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo); + } } const float mTMC = FemtoUniverseMath::getmT(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo); - if (abs(part1.fdMCParticle().pdgMCTruth()) == abs(mPDGOne) && abs(part2.fdMCParticle().pdgMCTruth()) == abs(mPDGTwo)) { // Note: all pair-histogramms are filled with MC truth information ONLY in case of non-fake candidates - setPair_base(femtoObsMC, mTMC, part1.fdMCParticle(), part2.fdMCParticle(), mult, use3dplots); - setPair_MC(femtoObsMC, femtoObs, mT, mult); + if (std::abs(part1.fdMCParticle().pdgMCTruth()) == std::abs(mPDGOne) && std::abs(part2.fdMCParticle().pdgMCTruth()) == std::abs(mPDGTwo)) { // Note: all pair-histogramms are filled with MC truth information ONLY in case of non-fake candidates + setPairBase(femtoObsMC, mTMC, part1.fdMCParticle(), part2.fdMCParticle(), mult, use3dplots, weight); + setPairMC(femtoObsMC, femtoObs, mT, mult); } else { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kTruth]) + HIST("/hFakePairsCounter"), 0); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kTruth]) + HIST("/hFakePairsCounter"), 0); } } else { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kTruth]) + HIST("/hNoMCtruthPairsCounter"), 0); + mHistogramRegistry->fill(HIST(FolderSuffix[EventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kTruth]) + HIST("/hNoMCtruthPairsCounter"), 0); } } } } protected: - HistogramRegistry* mHistogramRegistry = nullptr; ///< For QA output - static constexpr std::string_view mFolderSuffix[2] = {"SameEvent", "MixedEvent"}; ///< Folder naming for the output according to mEventType - static constexpr femtoUniverseContainer::Observable mFemtoObs = obs; ///< Femtoscopic observable to be computed (according to femtoUniverseContainer::Observable) - static constexpr int mEventType = eventType; ///< Type of the event (same/mixed, according to femtoUniverseContainer::EventType) - float mMassOne = 0.f; ///< PDG mass of particle 1 - float mMassTwo = 0.f; ///< PDG mass of particle 2 - int mPDGOne = 0; ///< PDG code of particle 1 - int mPDGTwo = 0; ///< PDG code of particle 2 + HistogramRegistry* mHistogramRegistry = nullptr; ///< For QA output + static constexpr std::string_view FolderSuffix[2] = {"SameEvent", "MixedEvent"}; ///< Folder naming for the output according to EventType + static constexpr femto_universe_container::Observable FemtoObs = obs; ///< Femtoscopic observable to be computed (according to femto_universe_container::Observable) + static constexpr int EventType = eventType; ///< Type of the event (same/mixed, according to femto_universe_container::EventType) + float mMassOne = 0.f; ///< PDG mass of particle 1 + float mMassTwo = 0.f; ///< PDG mass of particle 2 + int mPDGOne = 0; ///< PDG code of particle 1 + int mPDGTwo = 0; ///< PDG code of particle 2 double mPhiLow; double mPhiHigh; - double delta_eta; - double delta_phi; + double deltaEta; + double deltaPhi; }; -} // namespace o2::analysis::femtoUniverse +} // namespace o2::analysis::femto_universe #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSECONTAINER_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseCutculator.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseCutculator.h index 8a18e3c9f8c..863ecee389d 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseCutculator.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseCutculator.h @@ -32,7 +32,7 @@ #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseV0Selection.h" -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { /// \class FemtoUniverseCutculator @@ -45,23 +45,23 @@ class FemtoUniverseCutculator /// femtouniverse-producer task void init(const char* configFile) { - std::cout << "Welcome to the CutCulator!" << std::endl; + LOGF(info, "Welcome to the CutCulator!"); + // std::cout << "Welcome to the CutCulator!" << std::endl; boost::property_tree::ptree root; try { boost::property_tree::read_json(configFile, root); } catch (const boost::property_tree::ptree_error& e) { - std::cout - << "Failed to read JSON config file " << configFile << " (" - << e.what() << ")" << std::endl; + // LOGF(fatal, "Failed to read JSON config file %s (%s)", configFile, e.what()); + std::cout << "Failed to read JSON config file " << configFile << " (" << e.what() << ")" << std::endl; } // check the config file for all known producer task - std::vector ProducerTasks = { - "femto-universe-producer-task"}; - for (auto& Producer : ProducerTasks) { + std::vector producerTasks = {"femto-universe-producer-task"}; + for (const auto& Producer : producerTasks) { if (root.count(Producer) > 0) { mConfigTree = root.get_child(Producer); + // LOGF(info, "Found %s in %s", Producer, configFile); std::cout << "Found " << Producer << " in " << configFile << std::endl; break; } @@ -76,16 +76,15 @@ class FemtoUniverseCutculator { try { boost::property_tree::ptree& selections = mConfigTree.get_child(name); - boost::property_tree::ptree& selectionsValues = - selections.get_child("values"); + boost::property_tree::ptree& selectionsValues = selections.get_child("values"); std::vector tmpVec; for (boost::property_tree::ptree::value_type& val : selectionsValues) { tmpVec.push_back(std::stof(val.second.data())); } return tmpVec; } catch (const boost::property_tree::ptree_error& e) { - std::cout << "Selection " << name << " not available (" << e.what() << ")" - << std::endl; + // LOGF(fatal, "Selection %s not available (%s)", name, e.what()); + std::cout << "Selection " << name << " not available (" << e.what() << ")" << std::endl; return {}; } } @@ -96,12 +95,11 @@ class FemtoUniverseCutculator /// \param obs Observable of the track selection /// \param type Type of the track selection /// \param prefix Prefix which is added to the name of the Configurable - void setTrackSelection(femtoUniverseTrackSelection::TrackSel obs, - femtoUniverseSelection::SelectionType type, + void setTrackSelection(femto_universe_track_selection::TrackSel obs, + femto_universe_selection::SelectionType type, const char* prefix) { - auto tmpVec = - setSelection(FemtoUniverseTrackSelection::getSelectionName(obs, prefix)); + auto tmpVec = setSelection(FemtoUniverseTrackSelection::getSelectionName(obs, prefix)); if (tmpVec.size() > 0) { mTrackSel.setSelection(tmpVec, obs, type); } @@ -112,17 +110,17 @@ class FemtoUniverseCutculator void setTrackSelectionFromFile(const char* prefix) { for (const auto& sel : mConfigTree) { - std::string sel_name = sel.first; - femtoUniverseTrackSelection::TrackSel obs; - if (sel_name.find(prefix) != std::string::npos) { + std::string selName = sel.first; + femto_universe_track_selection::TrackSel obs; + if (selName.find(prefix) != std::string::npos) { int index = FemtoUniverseTrackSelection::findSelectionIndex( - std::string_view(sel_name), prefix); + std::string_view(selName), prefix); if (index >= 0) { - obs = femtoUniverseTrackSelection::TrackSel(index); + obs = femto_universe_track_selection::TrackSel(index); } else { continue; } - if (obs == femtoUniverseTrackSelection::TrackSel::kPIDnSigmaMax) + if (obs == femto_universe_track_selection::TrackSel::kPIDnSigmaMax) continue; // kPIDnSigmaMax is a special case setTrackSelection(obs, FemtoUniverseTrackSelection::getSelectionType(obs), prefix); @@ -134,23 +132,23 @@ class FemtoUniverseCutculator /// \param prefix Prefix which is added to the name of the Configurable void setPIDSelectionFromFile(const char* prefix) { - std::string PIDnodeName = std::string(prefix) + "PIDspecies"; - std::string PIDNsigmaNodeName = std::string(prefix) + "PIDnSigmaMax"; + std::string mPIDnodeName = std::string(prefix) + "PIDspecies"; + std::string mPIDNsigmaNodeName = std::string(prefix) + "PIDnSigmaMax"; try { - boost::property_tree::ptree& pidNode = mConfigTree.get_child(PIDnodeName); + boost::property_tree::ptree& pidNode = mConfigTree.get_child(mPIDnodeName); boost::property_tree::ptree& pidValues = pidNode.get_child("values"); - for (auto& val : pidValues) { + for (const auto& val : pidValues) { mPIDspecies.push_back( static_cast(std::stoi(val.second.data()))); } - boost::property_tree::ptree& pidNsigmaNode = mConfigTree.get_child(PIDNsigmaNodeName); + boost::property_tree::ptree& pidNsigmaNode = mConfigTree.get_child(mPIDNsigmaNodeName); boost::property_tree::ptree& pidNsigmaValues = pidNsigmaNode.get_child("values"); - for (auto& val : pidNsigmaValues) { + for (const auto& val : pidNsigmaValues) { mPIDValues.push_back(std::stof(val.second.data())); } } catch (const boost::property_tree::ptree_error& e) { - std::cout << "PID selection not avalible for these skimmed data." - << std::endl; + // LOGF(fatal, "PID selection not avalible for these skimmed data."); + std::cout << "PID selection not avalible for these skimmed data." << std::endl; } } @@ -160,8 +158,8 @@ class FemtoUniverseCutculator /// \param obs Observable of the track selection /// \param type Type of the track selection /// \param prefix Prefix which is added to the name of the Configurable - void setV0Selection(femtoUniverseV0Selection::V0Sel obs, - femtoUniverseSelection::SelectionType type, + void setV0Selection(femto_universe_v0_selection::V0Sel obs, + femto_universe_selection::SelectionType type, const char* prefix) { auto tmpVec = @@ -176,13 +174,13 @@ class FemtoUniverseCutculator void setV0SelectionFromFile(const char* prefix) { for (const auto& sel : mConfigTree) { - std::string sel_name = sel.first; - femtoUniverseV0Selection::V0Sel obs; - if (sel_name.find(prefix) != std::string::npos) { + std::string selName = sel.first; + femto_universe_v0_selection::V0Sel obs; + if (selName.find(prefix) != std::string::npos) { int index = FemtoUniverseV0Selection::findSelectionIndex( - std::string_view(sel_name), prefix); + std::string_view(selName), prefix); if (index >= 0) { - obs = femtoUniverseV0Selection::V0Sel(index); + obs = femto_universe_v0_selection::V0Sel(index); } else { continue; } @@ -202,13 +200,12 @@ class FemtoUniverseCutculator /// \param selectionType Selection type under investigation, as defined in the /// selection class template - void checkForSelection(aod::femtouniverseparticle::cutContainerType& output, + void checkForSelection(aod::femtouniverseparticle::CutContainerType& output, size_t& counter, T1 objectSelection, T2 selectionType, bool SysChecks, float sign) { /// Output of the available selections and user input - std::cout << "Selection: " - << objectSelection.getSelectionHelper(selectionType) << " - ("; + std::cout << "Selection: " << objectSelection.getSelectionHelper(selectionType) << " - ("; auto selVec = objectSelection.getSelections(selectionType); for (auto selIt : selVec) { std::cout << selIt.getSelectionValue() << " "; @@ -255,19 +252,19 @@ class FemtoUniverseCutculator /// If the input is sane, the selection bit is put together if (inputSane) { - int internal_index = 0; + int internalIndex = 0; for (auto sel : selVec) { double signOffset; switch (sel.getSelectionType()) { - case femtoUniverseSelection::SelectionType::kEqual: + case femto_universe_selection::SelectionType::kEqual: signOffset = 0.; break; - case (femtoUniverseSelection::SelectionType::kLowerLimit): - case (femtoUniverseSelection::SelectionType::kAbsLowerLimit): + case (femto_universe_selection::SelectionType::kLowerLimit): + case (femto_universe_selection::SelectionType::kAbsLowerLimit): signOffset = 1.; break; - case (femtoUniverseSelection::SelectionType::kUpperLimit): - case (femtoUniverseSelection::SelectionType::kAbsUpperLimit): + case (femto_universe_selection::SelectionType::kUpperLimit): + case (femto_universe_selection::SelectionType::kAbsUpperLimit): signOffset = -1.; break; } @@ -276,16 +273,16 @@ class FemtoUniverseCutculator /// the cut is actually fulfilled if (sel.isSelected(input + signOffset * 1.e-6 * input)) { output |= 1UL << counter; - for (int i = internal_index; i > 0; i--) { + for (int i = internalIndex; i > 0; i--) { output &= ~(1UL << (counter - i)); } } ++counter; - ++internal_index; + ++internalIndex; } } else { - std::cout << "Choice " << in << " not recognized - repeating" - << std::endl; + // LOGF(info, "Choice %s not recognized - repeating", in); + std::cout << "Choice " << in << " not recognized - repeating" << std::endl; checkForSelection(output, counter, objectSelection, selectionType, SysChecks, sign); } } @@ -297,10 +294,9 @@ class FemtoUniverseCutculator /// container that will be put to the user task incorporating the user choice /// of selections template - aod::femtouniverseparticle::cutContainerType iterateSelection(T objectSelection, - bool SysChecks, float sign) + aod::femtouniverseparticle::CutContainerType iterateSelection(T objectSelection, bool SysChecks, float sign) { - aod::femtouniverseparticle::cutContainerType output = 0; + aod::femtouniverseparticle::CutContainerType output = 0; size_t counter = 0; auto selectionVariables = objectSelection.getSelectionVariables(); for (auto selVarIt : selectionVariables) { @@ -313,18 +309,23 @@ class FemtoUniverseCutculator /// selection bit-wise container incorporating the user choice of selections void analyseCuts(std::string choice, bool SysChecks = false, float sign = 1) { - aod::femtouniverseparticle::cutContainerType output = -1; + aod::femtouniverseparticle::CutContainerType output = -1; if (choice == std::string("T")) { output = iterateSelection(mTrackSel, SysChecks, sign); } else if (choice == std::string("V")) { output = iterateSelection(mV0Sel, SysChecks, sign); } else { - std::cout << "Option " << choice - << " not recognized - available options are (T/V)" << std::endl; + // LOGF(info, "Option %s not recognized - available options are (T/V)", choice); + std::cout << "Option " << choice << " not recognized - available options are (T/V)" << std::endl; return; } - std::bitset<8 * sizeof(aod::femtouniverseparticle::cutContainerType)> + std::bitset<8 * sizeof(aod::femtouniverseparticle::CutContainerType)> bitOutput = output; + // LOGF(info, "+++++++++++++++++++++++++++++++++"); + // LOGF(info, "CutCulator has spoken - your selection bit is"); + // LOGF(info, "%s (bitwise)", bitOutput); + // LOGF(info, "%s (number representation)", output); + // LOGF(info, "PID for these species is stored:"); std::cout << "+++++++++++++++++++++++++++++++++" << std::endl; std::cout << "CutCulator has spoken - your selection bit is" << std::endl; std::cout << bitOutput << " (bitwise)" << std::endl; @@ -332,6 +333,7 @@ class FemtoUniverseCutculator std::cout << "PID for these species is stored:" << std::endl; int index = 0; for (auto id : mPIDspecies) { + // LOGF(info, "%s : %d", o2::track::PID::getName(id), index++); std::cout << o2::track::PID::getName(id) << " : " << index++ << std::endl; if (SysChecks) { // Seed the random number generator @@ -357,6 +359,6 @@ class FemtoUniverseCutculator std::vector mPIDValues; ///< list of nsigma values for which PID is stored }; -} // namespace o2::analysis::femtoUniverse +} // namespace o2::analysis::femto_universe #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSECUTCULATOR_H_ */ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h index 03c313c689c..792db50bd26 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h @@ -14,6 +14,7 @@ /// \author Laura Serksnyte, TU München, laura.serksnyte@tum.de /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch /// \author Pritam Chakraborty, WUT Warsaw, pritam.chakraborty@cern.ch +/// \author Shirajum Monira, WUT Warsaw, shirajum.monira@cern.ch #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEDETADPHISTAR_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEDETADPHISTAR_H_ @@ -27,16 +28,11 @@ #include "PWGCF/FemtoUniverse/Core/FemtoUniverseAngularContainer.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" #include "Framework/HistogramRegistry.h" - -using namespace o2; -using namespace o2::analysis::femtoUniverse; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::soa; +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" namespace o2::analysis { -namespace femtoUniverse +namespace femto_universe { /// \class FemtoUniverseDetaDphiStar @@ -47,101 +43,120 @@ template (dirNames[0]); - histdetadpisame[0][0] = mHistogramRegistry->add((dirName + static_cast(histNamesSame[0][0])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpisame[0][1] = mHistogramRegistry->add((dirName + static_cast(histNamesSame[1][0])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[0][0] = mHistogramRegistry->add((dirName + static_cast(histNamesMixed[0][0])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[0][1] = mHistogramRegistry->add((dirName + static_cast(histNamesMixed[1][0])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kTrack) { + std::string dirName = static_cast(DirNames[0]); + histdetadpisame[0][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][0])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpisame[0][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][0])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpimixed[0][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][0])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpimixed[0][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][0])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); if (plotForEveryRadii) { for (int i = 0; i < 9; i++) { - histdetadpiRadii[0][i] = mHistogramRegistryQA->add((dirName + static_cast(histNamesRadii[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpiRadii[0][i] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); } } } - if constexpr (mPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kV0) { + if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kV0) { for (int i = 0; i < 2; i++) { - std::string dirName = static_cast(dirNames[1]); - histdetadpisame[i][0] = mHistogramRegistry->add((dirName + static_cast(histNamesSame[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpisame[i][1] = mHistogramRegistry->add((dirName + static_cast(histNamesSame[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[i][0] = mHistogramRegistry->add((dirName + static_cast(histNamesMixed[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[i][1] = mHistogramRegistry->add((dirName + static_cast(histNamesMixed[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + std::string dirName = static_cast(DirNames[1]); + histdetadpisame[i][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpisame[i][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpimixed[i][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpimixed[i][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); if (plotForEveryRadii) { for (int j = 0; j < 9; j++) { - histdetadpiRadii[i][j] = mHistogramRegistryQA->add((dirName + static_cast(histNamesRadii[i][j])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpiRadii[i][j] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[i][j])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); } } } } - if constexpr (mPartOneType == o2::aod::femtouniverseparticle::ParticleType::kV0 && mPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kV0) { + if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kV0 && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kV0) { /// V0-V0 combination for (int k = 0; k < 2; k++) { - std::string dirName = static_cast(dirNames[2]); - histdetadpisame[k][0] = mHistogramRegistry->add((dirName + static_cast(histNamesSame[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpisame[k][1] = mHistogramRegistry->add((dirName + static_cast(histNamesSame[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[k][0] = mHistogramRegistry->add((dirName + static_cast(histNamesMixed[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[k][1] = mHistogramRegistry->add((dirName + static_cast(histNamesMixed[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + std::string dirName = static_cast(DirNames[2]); + histdetadpisame[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpisame[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpimixed[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpimixed[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); if (plotForEveryRadii) { for (int l = 0; l < 9; l++) { - histdetadpiRadii[k][l] = mHistogramRegistryQA->add((dirName + static_cast(histNamesRadii[k][l])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpiRadii[k][l] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[k][l])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); } } } } - if constexpr (mPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kPhi) { + if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kCascade && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kCascade) { + /// Xi-Xi and Omega-Omega combination + for (int k = 0; k < 7; k++) { + std::string dirName = static_cast(DirNames[5]); + histdetadpisame[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpisame[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpimixed[k][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpimixed[k][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][k])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + if (plotForEveryRadii) { + for (int l = 0; l < 9; l++) { + histdetadpiRadii[k][l] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[k][l])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + } + } + } + } + if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kPhi) { for (int i = 0; i < 2; i++) { - std::string dirName = static_cast(dirNames[3]); - histdetadpisame[i][0] = mHistogramRegistry->add((dirName + static_cast(histNamesSame[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{400, -0.30, 0.30}, {400, -0.30, 0.30}}); - histdetadpisame[i][1] = mHistogramRegistry->add((dirName + static_cast(histNamesSame[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{400, -0.30, 0.30}, {400, -0.30, 0.30}}); - histdetadpimixed[i][0] = mHistogramRegistry->add((dirName + static_cast(histNamesMixed[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{400, -0.30, 0.30}, {400, -0.30, 0.30}}); - histdetadpimixed[i][1] = mHistogramRegistry->add((dirName + static_cast(histNamesMixed[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{400, -0.30, 0.30}, {400, -0.30, 0.30}}); + std::string dirName = static_cast(DirNames[3]); + histdetadpisame[i][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][i])).c_str(), "; #Delta #eta; #Delta #varphi*", kTH2F, {{400, -0.30, 0.30}, {400, -0.30, 0.30}}); + histdetadpisame[i][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][i])).c_str(), "; #Delta #eta; #Delta #varphi*", kTH2F, {{400, -0.30, 0.30}, {400, -0.30, 0.30}}); + histdetadpimixed[i][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][i])).c_str(), "; #Delta #eta; #Delta #varphi*", kTH2F, {{400, -0.30, 0.30}, {400, -0.30, 0.30}}); + histdetadpimixed[i][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][i])).c_str(), "; #Delta #eta; #Delta #varphi*", kTH2F, {{400, -0.30, 0.30}, {400, -0.30, 0.30}}); if (plotForEveryRadii) { for (int j = 0; j < 9; j++) { - histdetadpiRadii[i][j] = mHistogramRegistryQA->add((dirName + static_cast(histNamesRadii[i][j])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpiRadii[i][j] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[i][j])).c_str(), "; #Delta #eta; #Delta #varphi*", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); } } } } - if constexpr (mPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kD0) { + if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kD0) { for (int i = 0; i < 2; i++) { - std::string dirName = static_cast(dirNames[4]); - histdetadpisame[i][0] = mHistogramRegistry->add((dirName + static_cast(histNamesSame[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpisame[i][1] = mHistogramRegistry->add((dirName + static_cast(histNamesSame[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[i][0] = mHistogramRegistry->add((dirName + static_cast(histNamesMixed[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); - histdetadpimixed[i][1] = mHistogramRegistry->add((dirName + static_cast(histNamesMixed[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + std::string dirName = static_cast(DirNames[4]); + histdetadpisame[i][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpisame[i][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpimixed[i][0] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[0][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpimixed[i][1] = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][i])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); if (plotForEveryRadii) { for (int j = 0; j < 9; j++) { - histdetadpiRadii[i][j] = mHistogramRegistryQA->add((dirName + static_cast(histNamesRadii[i][j])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpiRadii[i][j] = mHistogramRegistryQA->add((dirName + static_cast(HistNamesRadii[i][j])).c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); } } } } } + /// Check if pair is close or not template bool isClosePair(Part const& part1, Part const& part2, Parts const& particles, float lmagfield, uint8_t ChosenEventType) { magfield = lmagfield; - if constexpr (mPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kTrack) { + if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kTrack) { /// Track-Track combination // check if provided particles are in agreement with the class instantiation if (part1.partType() != o2::aod::femtouniverseparticle::ParticleType::kTrack || part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kTrack) { @@ -149,21 +164,21 @@ class FemtoUniverseDetaDphiStar return false; } auto deta = part1.eta() - part2.eta(); - auto dphiAvg = AveragePhiStar(part1, part2, 0); - if (ChosenEventType == femtoUniverseContainer::EventType::same) { + auto dphiAvg = averagePhiStar(part1, part2, 0); + if (ChosenEventType == femto_universe_container::EventType::same) { histdetadpisame[0][0]->Fill(deta, dphiAvg); - } else if (ChosenEventType == femtoUniverseContainer::EventType::mixed) { + } else if (ChosenEventType == femto_universe_container::EventType::mixed) { histdetadpimixed[0][0]->Fill(deta, dphiAvg); } else { LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar's type of events! Please provide same or mixed."; } - if (pow(dphiAvg, 2) / pow(CutDeltaPhiStarMax, 2) + pow(deta, 2) / pow(CutDeltaEtaMax, 2) < 1.) { + if (std::pow(dphiAvg, 2) / std::pow(cutDeltaPhiStarMax, 2) + std::pow(deta, 2) / std::pow(cutDeltaEtaMax, 2) < 1.) { return true; } else { - if (ChosenEventType == femtoUniverseContainer::EventType::same) { + if (ChosenEventType == femto_universe_container::EventType::same) { histdetadpisame[0][1]->Fill(deta, dphiAvg); - } else if (ChosenEventType == femtoUniverseContainer::EventType::mixed) { + } else if (ChosenEventType == femto_universe_container::EventType::mixed) { histdetadpimixed[0][1]->Fill(deta, dphiAvg); } else { LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar's type of events! Please provide same or mixed."; @@ -171,7 +186,7 @@ class FemtoUniverseDetaDphiStar return false; } - } else if constexpr (mPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kV0) { + } else if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kV0) { /// Track-V0 combination // check if provided particles are in agreement with the class instantiation if (part1.partType() != o2::aod::femtouniverseparticle::ParticleType::kTrack || part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kV0) { @@ -181,24 +196,25 @@ class FemtoUniverseDetaDphiStar bool pass = false; for (int i = 0; i < 2; i++) { - auto indexOfDaughter = part2.index() - 2 + i; + auto indexOfDaughter = (ChosenEventType == femto_universe_container::EventType::mixed ? part2.globalIndex() : part2.index()) - 2 + i; + // auto indexOfDaughter = part2.globalIndex() - 2 + i; auto daughter = particles.begin() + indexOfDaughter; auto deta = part1.eta() - daughter.eta(); - auto dphiAvg = AveragePhiStar(part1, *daughter, i); - if (ChosenEventType == femtoUniverseContainer::EventType::same) { + auto dphiAvg = averagePhiStar(part1, *daughter, i); + if (ChosenEventType == femto_universe_container::EventType::same) { histdetadpisame[i][0]->Fill(deta, dphiAvg); - } else if (ChosenEventType == femtoUniverseContainer::EventType::mixed) { + } else if (ChosenEventType == femto_universe_container::EventType::mixed) { histdetadpimixed[i][0]->Fill(deta, dphiAvg); } else { LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar's type of events! Please provide same or mixed."; } - if (pow(dphiAvg, 2) / pow(CutDeltaPhiStarMax, 2) + pow(deta, 2) / pow(CutDeltaEtaMax, 2) < 1.) { + if (std::pow(dphiAvg, 2) / std::pow(cutDeltaPhiStarMax, 2) + std::pow(deta, 2) / std::pow(cutDeltaEtaMax, 2) < 1.) { pass = true; } else { - if (ChosenEventType == femtoUniverseContainer::EventType::same) { + if (ChosenEventType == femto_universe_container::EventType::same) { histdetadpisame[i][1]->Fill(deta, dphiAvg); - } else if (ChosenEventType == femtoUniverseContainer::EventType::mixed) { + } else if (ChosenEventType == femto_universe_container::EventType::mixed) { histdetadpimixed[i][1]->Fill(deta, dphiAvg); } else { LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar's type of events! Please provide same or mixed."; @@ -207,9 +223,8 @@ class FemtoUniverseDetaDphiStar } return pass; - } else if constexpr (mPartOneType == o2::aod::femtouniverseparticle::ParticleType::kV0 && mPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kV0) { + } else if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kV0 && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kV0) { /// V0-V0 combination - // check if provided particles are in agreement with the class instantiation if (part1.partType() != o2::aod::femtouniverseparticle::ParticleType::kV0 || part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kV0) { LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar instantiation! Please provide kV0,kV0 candidates."; return false; @@ -217,26 +232,65 @@ class FemtoUniverseDetaDphiStar bool pass = false; for (int i = 0; i < 2; i++) { - auto indexOfDaughterpart1 = part1.index() - 2 + i; - auto indexOfDaughterpart2 = part2.index() - 2 + i; + auto indexOfDaughterpart1 = (ChosenEventType == femto_universe_container::EventType::mixed ? part1.globalIndex() : part1.index()) - 2 + i; + auto indexOfDaughterpart2 = (ChosenEventType == femto_universe_container::EventType::mixed ? part2.globalIndex() : part2.index()) - 2 + i; + auto daughterpart1 = particles.begin() + indexOfDaughterpart1; + auto daughterpart2 = particles.begin() + indexOfDaughterpart2; + auto deta = daughterpart1.eta() - daughterpart2.eta(); + auto dphiAvg = averagePhiStar(*daughterpart1, *daughterpart2, i); + if (ChosenEventType == femto_universe_container::EventType::same) { + histdetadpisame[i][0]->Fill(deta, dphiAvg); + } else if (ChosenEventType == femto_universe_container::EventType::mixed) { + histdetadpimixed[i][0]->Fill(deta, dphiAvg); + } else { + LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar's type of events! Please provide same or mixed."; + } + + // if (std::pow(dphiAvg, 2) / std::pow(cutDeltaPhiStarMax, 2) + std::pow(deta, 2) / std::pow(cutDeltaEtaMax, 2) < 1.) { + if ((dphiAvg > cutDeltaPhiStarMin) && (dphiAvg < cutDeltaPhiStarMax) && (deta > cutDeltaEtaMin) && (deta < cutDeltaEtaMax)) { + pass = true; + } else { + if (ChosenEventType == femto_universe_container::EventType::same) { + histdetadpisame[i][1]->Fill(deta, dphiAvg); + } else if (ChosenEventType == femto_universe_container::EventType::mixed) { + histdetadpimixed[i][1]->Fill(deta, dphiAvg); + } else { + LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar's type of events! Please provide same or mixed."; + } + } + } + return pass; + + } else if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kCascade && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kCascade) { + /// Xi-Xi and Omega-Omega combination + if (part1.partType() != o2::aod::femtouniverseparticle::ParticleType::kCascade || part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kCascade) { + LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar instantiation! Please provide kCascade,kCascade candidates."; + return false; + } + + bool pass = false; + static constexpr int CascChildTable[][2] = {{-1, -1}, {-1, -2}, {-1, -3}, {-2, -2}, {-3, -3}, {-2, -1}, {-3, -1}}; + for (int i = 0; i < 5; i++) { + auto indexOfDaughterpart1 = (ChosenEventType == femto_universe_container::EventType::mixed ? part1.globalIndex() : part1.index()) + CascChildTable[i][0]; + auto indexOfDaughterpart2 = (ChosenEventType == femto_universe_container::EventType::mixed ? part2.globalIndex() : part2.index()) + CascChildTable[i][1]; auto daughterpart1 = particles.begin() + indexOfDaughterpart1; auto daughterpart2 = particles.begin() + indexOfDaughterpart2; auto deta = daughterpart1.eta() - daughterpart2.eta(); - auto dphiAvg = AveragePhiStar(*daughterpart1, *daughterpart2, i); - if (ChosenEventType == femtoUniverseContainer::EventType::same) { + auto dphiAvg = averagePhiStar(*daughterpart1, *daughterpart2, i); + if (ChosenEventType == femto_universe_container::EventType::same) { histdetadpisame[i][0]->Fill(deta, dphiAvg); - } else if (ChosenEventType == femtoUniverseContainer::EventType::mixed) { + } else if (ChosenEventType == femto_universe_container::EventType::mixed) { histdetadpimixed[i][0]->Fill(deta, dphiAvg); } else { LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar's type of events! Please provide same or mixed."; } - if (pow(dphiAvg, 2) / pow(CutDeltaPhiStarMax, 2) + pow(deta, 2) / pow(CutDeltaEtaMax, 2) < 1.) { + if ((dphiAvg > cutDeltaPhiStarMin) && (dphiAvg < cutDeltaPhiStarMax) && (deta > cutDeltaEtaMin) && (deta < cutDeltaEtaMax)) { pass = true; } else { - if (ChosenEventType == femtoUniverseContainer::EventType::same) { + if (ChosenEventType == femto_universe_container::EventType::same) { histdetadpisame[i][1]->Fill(deta, dphiAvg); - } else if (ChosenEventType == femtoUniverseContainer::EventType::mixed) { + } else if (ChosenEventType == femto_universe_container::EventType::mixed) { histdetadpimixed[i][1]->Fill(deta, dphiAvg); } else { LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar's type of events! Please provide same or mixed."; @@ -245,7 +299,7 @@ class FemtoUniverseDetaDphiStar } return pass; - } else if constexpr (mPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kD0) { + } else if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kD0) { /// Track-D0 combination // check if provided particles are in agreement with the class instantiation if (part1.partType() != o2::aod::femtouniverseparticle::ParticleType::kTrack || part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kD0) { @@ -255,25 +309,31 @@ class FemtoUniverseDetaDphiStar bool pass = false; for (int i = 0; i < 2; i++) { - auto indexOfDaughter = part2.index() - 2 + i; + auto indexOfDaughter = 0; + if (ChosenEventType == femto_universe_container::EventType::mixed) { + indexOfDaughter = part2.globalIndex() - 2 + i; + } else if (ChosenEventType == femto_universe_container::EventType::same) { + indexOfDaughter = part2.index() - 2 + i; + } + auto daughter = particles.begin() + indexOfDaughter; auto deta = part1.eta() - daughter.eta(); - auto dphiAvg = AveragePhiStar(part1, *daughter, i); // auto dphiAvg = CalculateDphiStar(part1, *daughter); + auto dphiAvg = averagePhiStar(part1, *daughter, i); // auto dphiAvg = calculateDphiStar(part1, *daughter); dphiAvg = TVector2::Phi_mpi_pi(dphiAvg); - if (ChosenEventType == femtoUniverseContainer::EventType::same) { + if (ChosenEventType == femto_universe_container::EventType::same) { histdetadpisame[i][0]->Fill(deta, dphiAvg); - } else if (ChosenEventType == femtoUniverseContainer::EventType::mixed) { + } else if (ChosenEventType == femto_universe_container::EventType::mixed) { histdetadpimixed[i][0]->Fill(deta, dphiAvg); } else { LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar's type of events! Please provide same or mixed."; } - if ((fabs(dphiAvg) < CutDeltaPhiStarMax) && (fabs(deta) < CutDeltaEtaMax)) { + if ((dphiAvg > cutDeltaPhiStarMin) && (dphiAvg < cutDeltaPhiStarMax) && (deta > cutDeltaEtaMin) && (deta < cutDeltaEtaMax)) { pass = true; // pair is close } else { - if (ChosenEventType == femtoUniverseContainer::EventType::same) { + if (ChosenEventType == femto_universe_container::EventType::same) { histdetadpisame[i][1]->Fill(deta, dphiAvg); - } else if (ChosenEventType == femtoUniverseContainer::EventType::mixed) { + } else if (ChosenEventType == femto_universe_container::EventType::mixed) { histdetadpimixed[i][1]->Fill(deta, dphiAvg); } else { LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar's type of events! Please provide same or mixed."; @@ -281,7 +341,7 @@ class FemtoUniverseDetaDphiStar } } return pass; - } else if constexpr (mPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kPhi) { + } else if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kPhi) { /// Track-Phi combination // check if provided particles are in agreement with the class instantiation if (part1.partType() != o2::aod::femtouniverseparticle::ParticleType::kTrack || part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kPhi) { @@ -292,30 +352,45 @@ class FemtoUniverseDetaDphiStar bool pass = false; for (int i = 0; i < 2; i++) { auto indexOfDaughter = 0; - if (ChosenEventType == femtoUniverseContainer::EventType::mixed) { + if (ChosenEventType == femto_universe_container::EventType::mixed) { indexOfDaughter = part2.globalIndex() - 2 + i; - } else if (ChosenEventType == femtoUniverseContainer::EventType::same) { + } else if (ChosenEventType == femto_universe_container::EventType::same) { indexOfDaughter = part2.index() - 2 + i; } auto daughter = particles.begin() + indexOfDaughter; auto deta = part1.eta() - daughter.eta(); - auto dphiAvg = AveragePhiStar(part1, *daughter, i); // CalculateDphiStar(part1, *daughter); + auto dphiAvg = averagePhiStar(part1, *daughter, i); // calculateDphiStar(part1, *daughter); dphiAvg = TVector2::Phi_mpi_pi(dphiAvg); - if (ChosenEventType == femtoUniverseContainer::EventType::same) { + if (ChosenEventType == femto_universe_container::EventType::same) { histdetadpisame[i][0]->Fill(deta, dphiAvg); - } else if (ChosenEventType == femtoUniverseContainer::EventType::mixed) { + } else if (ChosenEventType == femto_universe_container::EventType::mixed) { histdetadpimixed[i][0]->Fill(deta, dphiAvg); } else { LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar's type of events! Please provide same or mixed."; } - if ((dphiAvg > CutDeltaPhiStarMin) && (dphiAvg < CutDeltaPhiStarMax) && (deta > CutDeltaEtaMin) && (deta < CutDeltaEtaMax)) { + // REMOVING THE "RING" -- CALCULATING THE INVARIANT MASS + TLorentzVector part1Vec; + TLorentzVector part2Vec; + float mMassOne = o2::constants::physics::MassKPlus; + float mMassTwo = o2::constants::physics::MassKMinus; + part1Vec.SetPtEtaPhiM(part1.pt(), part1.eta(), part1.phi(), mMassOne); + part2Vec.SetPtEtaPhiM(daughter.pt(), daughter.eta(), daughter.phi(), mMassTwo); + TLorentzVector sumVec(part1Vec); + sumVec += part2Vec; + float phiM = sumVec.M(); + if ((phiM > cutPhiInvMassLow) && (phiM < cutPhiInvMassHigh)) { + pass = true; // pair comes from Phi meson decay + } + + // APPLYING THE CUTS + if ((dphiAvg > cutDeltaPhiStarMin) && (dphiAvg < cutDeltaPhiStarMax) && (deta > cutDeltaEtaMin) && (deta < cutDeltaEtaMax)) { pass = true; // pair is close } else { - if (ChosenEventType == femtoUniverseContainer::EventType::same) { + if (ChosenEventType == femto_universe_container::EventType::same) { histdetadpisame[i][1]->Fill(deta, dphiAvg); - } else if (ChosenEventType == femtoUniverseContainer::EventType::mixed) { + } else if (ChosenEventType == femto_universe_container::EventType::mixed) { histdetadpimixed[i][1]->Fill(deta, dphiAvg); } else { LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar's type of events! Please provide same or mixed."; @@ -332,45 +407,70 @@ class FemtoUniverseDetaDphiStar private: HistogramRegistry* mHistogramRegistry = nullptr; ///< For main output HistogramRegistry* mHistogramRegistryQA = nullptr; ///< For QA output - static constexpr std::string_view dirNames[5] = {"kTrack_kTrack/", "kTrack_kV0/", "kV0_kV0/", "kTrack_kPhi/", "kTrack_kD0/"}; - - static constexpr std::string_view histNamesSame[2][2] = {{"detadphidetadphi0BeforeSame_0", "detadphidetadphi0BeforeSame_1"}, - {"detadphidetadphi0AfterSame_0", "detadphidetadphi0AfterSame_1"}}; - static constexpr std::string_view histNamesMixed[2][2] = {{"detadphidetadphi0BeforeMixed_0", "detadphidetadphi0BeforeMixed_1"}, - {"detadphidetadphi0AfterMixed_0", "detadphidetadphi0AfterMixed_1"}}; - - static constexpr std::string_view histNamesRadii[2][9] = {{"detadphidetadphi0Before_0_0", "detadphidetadphi0Before_0_1", "detadphidetadphi0Before_0_2", + static constexpr std::string_view DirNames[6] = {"kTrack_kTrack/", "kTrack_kV0/", "kV0_kV0/", "kTrack_kPhi/", "kTrack_kD0/", "kCascade_kCascade/"}; + + static constexpr std::string_view HistNamesSame[2][7] = {{"detadphidetadphi0BeforeSame_0", "detadphidetadphi0BeforeSame_1", "detadphidetadphi0BeforeSame_2", + "detadphidetadphi0BeforeSame_3", "detadphidetadphi0BeforeSame_4", "detadphidetadphi0BeforeSame_5", + "detadphidetadphi0BeforeSame_6"}, + {"detadphidetadphi0AfterSame_0", "detadphidetadphi0AfterSame_1", "detadphidetadphi0AfterSame_2", + "detadphidetadphi0AfterSame_3", "detadphidetadphi0AfterSame_4", "detadphidetadphi0AfterSame_5", + "detadphidetadphi0AfterSame_6"}}; + static constexpr std::string_view HistNamesMixed[2][7] = {{"detadphidetadphi0BeforeMixed_0", "detadphidetadphi0BeforeMixed_1", "detadphidetadphi0BeforeMixed_2", + "detadphidetadphi0BeforeMixed_3", "detadphidetadphi0BeforeMixed_4", "detadphidetadphi0BeforeMixed_5", + "detadphidetadphi0BeforeMixed_6"}, + {"detadphidetadphi0AfterMixed_0", "detadphidetadphi0AfterMixed_1", "detadphidetadphi0AfterMixed_2", + "detadphidetadphi0AfterMixed_3", "detadphidetadphi0AfterMixed_4", "detadphidetadphi0AfterMixed_5", + "detadphidetadphi0AfterMixed_6"}}; + + static constexpr std::string_view HistNamesRadii[7][9] = {{"detadphidetadphi0Before_0_0", "detadphidetadphi0Before_0_1", "detadphidetadphi0Before_0_2", "detadphidetadphi0Before_0_3", "detadphidetadphi0Before_0_4", "detadphidetadphi0Before_0_5", "detadphidetadphi0Before_0_6", "detadphidetadphi0Before_0_7", "detadphidetadphi0Before_0_8"}, {"detadphidetadphi0Before_1_0", "detadphidetadphi0Before_1_1", "detadphidetadphi0Before_1_2", "detadphidetadphi0Before_1_3", "detadphidetadphi0Before_1_4", "detadphidetadphi0Before_1_5", - "detadphidetadphi0Before_1_6", "detadphidetadphi0Before_1_7", "detadphidetadphi0Before_1_8"}}; - - static constexpr o2::aod::femtouniverseparticle::ParticleType mPartOneType = partOne; ///< Type of particle 1 - static constexpr o2::aod::femtouniverseparticle::ParticleType mPartTwoType = partTwo; ///< Type of particle 2 - - static constexpr float tmpRadiiTPC[9] = {85., 105., 125., 145., 165., 185., 205., 225., 245.}; + "detadphidetadphi0Before_1_6", "detadphidetadphi0Before_1_7", "detadphidetadphi0Before_1_8"}, + {"detadphidetadphi0Before_2_0", "detadphidetadphi0Before_2_1", "detadphidetadphi0Before_2_2", + "detadphidetadphi0Before_2_3", "detadphidetadphi0Before_2_4", "detadphidetadphi0Before_2_5", + "detadphidetadphi0Before_2_6", "detadphidetadphi0Before_2_7", "detadphidetadphi0Before_2_8"}, + {"detadphidetadphi0Before_3_0", "detadphidetadphi0Before_3_1", "detadphidetadphi0Before_3_2", + "detadphidetadphi0Before_3_3", "detadphidetadphi0Before_3_4", "detadphidetadphi0Before_3_5", + "detadphidetadphi0Before_3_6", "detadphidetadphi0Before_3_7", "detadphidetadphi0Before_3_8"}, + {"detadphidetadphi0Before_4_0", "detadphidetadphi0Before_4_1", "detadphidetadphi0Before_4_2", + "detadphidetadphi0Before_4_3", "detadphidetadphi0Before_4_4", "detadphidetadphi0Before_4_5", + "detadphidetadphi0Before_4_6", "detadphidetadphi0Before_4_7", "detadphidetadphi0Before_4_8"}, + {"detadphidetadphi0Before_5_0", "detadphidetadphi0Before_5_1", "detadphidetadphi0Before_5_2", + "detadphidetadphi0Before_5_3", "detadphidetadphi0Before_5_4", "detadphidetadphi0Before_5_5", + "detadphidetadphi0Before_5_6", "detadphidetadphi0Before_5_7", "detadphidetadphi0Before_5_8"}, + {"detadphidetadphi0Before_6_0", "detadphidetadphi0Before_6_1", "detadphidetadphi0Before_6_2", + "detadphidetadphi0Before_6_3", "detadphidetadphi0Before_6_4", "detadphidetadphi0Before_6_5", + "detadphidetadphi0Before_6_6", "detadphidetadphi0Before_6_7", "detadphidetadphi0Before_6_8"}}; + + static constexpr o2::aod::femtouniverseparticle::ParticleType kPartOneType = partOne; ///< Type of particle 1 + static constexpr o2::aod::femtouniverseparticle::ParticleType kPartTwoType = partTwo; ///< Type of particle 2 + + static constexpr float TmpRadiiTPC[9] = {85., 105., 125., 145., 165., 185., 205., 225., 245.}; static constexpr uint32_t kSignMinusMask = 1; static constexpr uint32_t kSignPlusMask = 1 << 1; static constexpr uint32_t kValue0 = 0; - float ChosenRadii; - float CutDeltaPhiStarMax; - float CutDeltaPhiStarMin; - float CutDeltaEtaMax; - float CutDeltaEtaMin; + float chosenRadii; + float cutDeltaPhiStarMax; + float cutDeltaPhiStarMin; + float cutDeltaEtaMax; + float cutDeltaEtaMin; float magfield; bool plotForEveryRadii = false; + float cutPhiInvMassLow; + float cutPhiInvMassHigh; - std::array, 2>, 2> histdetadpisame{}; - std::array, 2>, 2> histdetadpimixed{}; - std::array, 9>, 2> histdetadpiRadii{}; + std::array, 2>, 7> histdetadpisame{}; + std::array, 2>, 7> histdetadpimixed{}; + std::array, 9>, 7> histdetadpiRadii{}; - /// Calculate phi at all required radii stored in tmpRadiiTPC + /// Calculate phi at all required radii stored in TmpRadiiTPC /// Magnetic field to be provided in Tesla template - void PhiAtRadiiTPC(const T& part, std::vector& tmpVec) + void phiAtRadiiTPC(const T& part, std::vector& tmpVec) { float phi0 = part.phi(); @@ -388,8 +488,8 @@ class FemtoUniverseDetaDphiStar // End: Get the charge from cutcontainer using masks float pt = part.pt(); for (size_t i = 0; i < 9; i++) { - double arg = 0.3 * charge * magfield * tmpRadiiTPC[i] * 0.01 / (2. * pt); - if (abs(arg) < 1.0) { + double arg = 0.3 * charge * magfield * TmpRadiiTPC[i] * 0.01 / (2. * pt); + if (std::abs(arg) < 1.0) { tmpVec.push_back(phi0 - std::asin(arg)); } else { tmpVec.push_back(999.0); @@ -399,12 +499,12 @@ class FemtoUniverseDetaDphiStar /// Calculate average phi template - float AveragePhiStar(const T1& part1, const T2& part2, int iHist) + float averagePhiStar(const T1& part1, const T2& part2, int iHist) { std::vector tmpVec1; std::vector tmpVec2; - PhiAtRadiiTPC(part1, tmpVec1); - PhiAtRadiiTPC(part2, tmpVec2); + phiAtRadiiTPC(part1, tmpVec1); + phiAtRadiiTPC(part2, tmpVec2); int num = tmpVec1.size(); float dPhiAvg = 0; float dphi = 0; @@ -427,7 +527,7 @@ class FemtoUniverseDetaDphiStar // Get particle charge from mask template - float GetCharge(const T1& part) + float getCharge(const T1& part) { float charge = 0; if ((part.cut() & kSignMinusMask) == kValue0 && (part.cut() & kSignPlusMask) == kValue0) { @@ -444,25 +544,25 @@ class FemtoUniverseDetaDphiStar // Calculate phi* as in https://github.com/alisw/AliPhysics/blob/master/PWGCF/FEMTOSCOPY/AliFemtoUser/AliFemtoPairCutRadialDistance.cxx template - double CalculateDphiStar(const T1& part1, const T2& part2) + double calculateDphiStar(const T1& part1, const T2& part2) { - float charge1 = GetCharge(part1); - float charge2 = GetCharge(part2); + float charge1 = getCharge(part1); + float charge2 = getCharge(part2); double deltaphiconstFD = 0.3 / 2; // double deltaphiconstAF = 0.15; - double afsi0b = deltaphiconstFD * magfield * charge1 * ChosenRadii / part1.pt(); - double afsi1b = deltaphiconstFD * magfield * charge2 * ChosenRadii / part2.pt(); + double afsi0b = deltaphiconstFD * magfield * charge1 * chosenRadii / part1.pt(); + double afsi1b = deltaphiconstFD * magfield * charge2 * chosenRadii / part2.pt(); double dphis = 0.0; - if (abs(afsi0b) < 1.0 && abs(afsi0b) < 1.0) { - dphis = part2.phi() - part1.phi() + TMath::ASin(afsi1b) - TMath::ASin(afsi0b); + if (std::abs(afsi0b) < 1.0 && std::abs(afsi0b) < 1.0) { + dphis = part2.phi() - part1.phi() + std::asin(afsi1b) - std::asin(afsi0b); } return dphis; } }; -} /* namespace femtoUniverse */ +} /* namespace femto_universe */ } /* namespace o2::analysis */ #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEDETADPHISTAR_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseEfficiencyCalculator.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseEfficiencyCalculator.h new file mode 100644 index 00000000000..186173ba615 --- /dev/null +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseEfficiencyCalculator.h @@ -0,0 +1,164 @@ +// Copyright 2019-2022 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 FemtoUniverseEfficiencyCalculator.h +/// \brief Abstraction for applying corrections based on efficiency from CCDB +/// \author Dawid Karpiński, WUT Warsaw, dawid.karpinski@cern.ch + +#ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEEFFICIENCYCALCULATOR_H_ +#define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEEFFICIENCYCALCULATOR_H_ + +#include +#include +#include +#include + +#include "Framework/Configurable.h" +#include "CCDB/BasicCCDBManager.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" +#include "FemtoUniverseParticleHisto.h" + +namespace o2::analysis::femto_universe::efficiency +{ +enum ParticleNo : size_t { + ONE = 1, + TWO, +}; + +template +concept isOneOrTwo = T == ParticleNo::ONE || T == ParticleNo::TWO; + +template +consteval auto getHistDim() -> int +{ + if (std::is_same_v) + return 1; + else if (std::is_same_v) + return 2; + else if (std::is_same_v) + return 3; + else + return -1; +} + +struct EfficiencyConfigurableGroup : ConfigurableGroup { + Configurable confEfficiencyApplyCorrections{"confEfficiencyApplyCorrections", false, "Should apply corrections from efficiency"}; + Configurable confEfficiencyCCDBTrainNumber{"confEfficiencyCCDBTrainNumber", 0, "Train number for which to query CCDB objects (set 0 to ignore)"}; + Configurable> confEfficiencyCCDBTimestamps{"confEfficiencyCCDBTimestamps", {}, "Timestamps of efficiency histograms in CCDB, to query for specific objects (default: [], set 0 to ignore, useful when running subwagons)"}; + + // NOTE: in the future we might move the below configurables to a separate struct, eg. CCDBConfigurableGroup + Configurable confCCDBUrl{"confCCDBUrl", "http://alice-ccdb.cern.ch", "CCDB URL to be used"}; + Configurable confCCDBPath{"confCCDBPath", "", "CCDB base path to where to upload objects"}; +}; + +template + requires std::is_base_of_v +class EfficiencyCalculator +{ + public: + explicit EfficiencyCalculator(EfficiencyConfigurableGroup* config) : config(config) // o2-linter: disable=name/function-variable + { + } + + auto init() -> void + { + ccdb.setURL(config->confCCDBUrl); + ccdb.setLocalObjectValidityChecking(); + ccdb.setFatalWhenNull(false); + + auto now = duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb.setCreatedNotAfter(now); + + shouldApplyCorrections = config->confEfficiencyApplyCorrections; + + if (config->confEfficiencyApplyCorrections && !config->confEfficiencyCCDBTimestamps.value.empty()) { + for (auto idx = 0UL; idx < config->confEfficiencyCCDBTimestamps.value.size(); idx++) { + auto timestamp = 0L; + try { + timestamp = std::max(0L, std::stol(config->confEfficiencyCCDBTimestamps.value[idx])); + } catch (const std::exception&) { + LOGF(error, notify("Could not parse CCDB timestamp \"%s\""), config->confEfficiencyCCDBTimestamps.value[idx]); + continue; + } + + hLoaded[idx] = timestamp > 0 ? loadEfficiencyFromCCDB(timestamp) : nullptr; + } + } + } + + template + requires(sizeof...(BinVars) == getHistDim()) + auto getWeight(ParticleNo partNo, const BinVars&... binVars) const -> float + { + auto weight = 1.0f; + auto hEff = hLoaded[partNo - 1]; + + if (shouldApplyCorrections && hEff) { + auto bin = hEff->FindBin(binVars...); + auto eff = hEff->GetBinContent(bin); + weight /= eff > 0 ? eff : 1.0f; + } + + return weight; + } + + private: + static inline auto notify(const std::string& msg) -> const std::string + { + return fmt::format("[EFFICIENCY] {}", msg); + } + + static auto isHistEmpty(HistType* hist) -> bool + { + if (!hist) { + return true; + } + for (auto idx = 0; idx <= hist->GetNbinsX() + 1; idx++) { + if (hist->GetBinContent(idx) > 0) { + return false; + } + } + return true; + } + + auto loadEfficiencyFromCCDB(const int64_t timestamp) const -> HistType* + { + std::map metadata{}; + + if (config->confEfficiencyCCDBTrainNumber > 0) { + metadata["trainNumber"] = std::to_string(config->confEfficiencyCCDBTrainNumber); + } + + auto hEff = ccdb.getSpecific(config->confCCDBPath, timestamp, metadata); + if (!hEff || hEff->IsZombie()) { + LOGF(error, notify("Could not load histogram \"%s/%ld\""), config->confCCDBPath.value, timestamp); + return nullptr; + } + + if (isHistEmpty(hEff)) { + LOGF(warn, notify("Histogram \"%s/%ld\" has been loaded, but it is empty"), config->confCCDBPath.value, timestamp); + } + + LOGF(info, notify("Successfully loaded %ld"), timestamp); + return hEff; + } + + EfficiencyConfigurableGroup* config{}; + + bool shouldApplyCorrections = false; + + o2::ccdb::BasicCCDBManager& ccdb{o2::ccdb::BasicCCDBManager::instance()}; + std::array hLoaded{}; +}; + +} // namespace o2::analysis::femto_universe::efficiency + +#endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEEFFICIENCYCALCULATOR_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseEfficiencyCorrection.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseEfficiencyCorrection.h new file mode 100644 index 00000000000..b866649ab04 --- /dev/null +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseEfficiencyCorrection.h @@ -0,0 +1,154 @@ +// Copyright 2019-2022 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 FemtoUniverseEfficiencyCorrection.h +/// \brief Abstraction for applying efficiency corrections based on weights from CCDB +/// \author Dawid Karpiński, WUT Warsaw, dawid.karpinski@cern.ch + +#ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEEFFICIENCYCORRECTION_H_ +#define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEEFFICIENCYCORRECTION_H_ + +#include +#include +#include + +#include "Framework/Configurable.h" +#include "CCDB/BasicCCDBManager.h" +#include "TH1.h" +#include "TH2.h" +#include "TH3.h" + +namespace o2::analysis::femto_universe::efficiency_correction +{ +enum ParticleNo : size_t { + ONE = 1, + TWO, +}; + +template +concept isOneOrTwo = T == ParticleNo::ONE || T == ParticleNo::TWO; + +template +consteval auto getHistDim() -> int +{ + if (std::is_same_v) + return 1; + else if (std::is_same_v) + return 2; + else if (std::is_same_v) + return 3; + else + return -1; +} + +struct EffCorConfigurableGroup : framework::ConfigurableGroup { + framework::Configurable confEffCorApply{"confEffCorApply", false, "[Efficiency Correction] Should apply efficiency corrections"}; + framework::Configurable confEffCorCCDBUrl{"confEffCorCCDBUrl", "http://alice-ccdb.cern.ch", "[Efficiency Correction] CCDB URL to use"}; + framework::Configurable confEffCorCCDBPath{"confEffCorCCDBPath", "", "[Efficiency Correction] CCDB path to histograms"}; + framework::Configurable> confEffCorCCDBTimestamps{"confEffCorCCDBTimestamps", {}, "[Efficiency Correction] Timestamps of histograms in CCDB (0 can be used as a placeholder, e.g. when running subwagons)"}; +}; + +template + requires std::is_base_of_v +class EfficiencyCorrection +{ + public: + explicit EfficiencyCorrection(EffCorConfigurableGroup* config) : config(config) // o2-linter: disable=name/function-variable + { + } + + auto init() -> void + { + ccdb.setURL(config->confEffCorCCDBUrl); + ccdb.setLocalObjectValidityChecking(); + ccdb.setFatalWhenNull(false); + + auto now = duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb.setCreatedNotAfter(now); + + shouldApplyCorrection = config->confEffCorApply; + + if (shouldApplyCorrection && !config->confEffCorCCDBTimestamps.value.empty()) { + for (auto idx = 0UL; idx < config->confEffCorCCDBTimestamps.value.size(); idx++) { + auto timestamp = 0L; + try { + timestamp = std::max(0L, std::stol(config->confEffCorCCDBTimestamps.value[idx])); + } catch (const std::exception&) { + LOGF(error, notify("Could not parse CCDB timestamp \"%s\""), config->confEffCorCCDBTimestamps.value[idx]); + continue; + } + + hLoaded[idx] = timestamp > 0 ? loadHistFromCCDB(timestamp) : nullptr; + } + } + } + + template + requires(sizeof...(BinVars) == getHistDim()) + auto getWeight(ParticleNo partNo, const BinVars&... binVars) const -> float + { + auto weight = 1.0f; + auto hWeights = hLoaded[partNo - 1]; + + if (shouldApplyCorrection && hWeights) { + auto bin = hWeights->FindBin(binVars...); + weight = hWeights->GetBinContent(bin); + } + + return weight; + } + + private: + static inline auto notify(const std::string& msg) -> const std::string + { + return fmt::format("[EFFICIENCY CORRECTION] {}", msg); + } + + static auto isHistEmpty(HistType* hist) -> bool + { + if (!hist) { + return true; + } + for (auto idx = 0; idx <= hist->GetNbinsX() + 1; idx++) { + if (hist->GetBinContent(idx) > 0) { + return false; + } + } + return true; + } + + auto loadHistFromCCDB(const int64_t timestamp) const -> HistType* + { + auto hWeights = ccdb.getForTimeStamp(config->confEffCorCCDBPath, timestamp); + if (!hWeights || hWeights->IsZombie()) { + LOGF(error, notify("Could not load histogram \"%s/%ld\""), config->confEffCorCCDBPath.value, timestamp); + return nullptr; + } + + if (isHistEmpty(hWeights)) { + LOGF(warn, notify("Histogram \"%s/%ld\" has been loaded, but it is empty"), config->confEffCorCCDBUrl.value, timestamp); + } + + LOGF(info, notify("Successfully loaded %ld"), timestamp); + return hWeights; + } + + EffCorConfigurableGroup* config{}; + + bool shouldApplyCorrection = false; + + o2::ccdb::BasicCCDBManager& ccdb{o2::ccdb::BasicCCDBManager::instance()}; + std::array hLoaded{}; +}; + +} // namespace o2::analysis::femto_universe::efficiency_correction + +#endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEEFFICIENCYCORRECTION_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h index 216cecb1148..36e81e81e76 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h @@ -21,7 +21,7 @@ #include "Framework/HistogramRegistry.h" using namespace o2::framework; -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { /// \class FemtoUniverseEventHisto /// \brief Class for histogramming event properties @@ -35,9 +35,11 @@ class FemtoUniverseEventHisto void init(HistogramRegistry* registry) { mHistogramRegistry = registry; - mHistogramRegistry->add("Event/zvtxhist", "; vtx_{z} (cm); Entries", kTH1F, {{300, -12.5, 12.5}}); - mHistogramRegistry->add("Event/MultV0M", "; vMultV0M; Entries", kTH1F, {{16384, 0, 32768}}); - mHistogramRegistry->add("Event/MultNTr", "; vMultNTr; Entries", kTH1F, {{200, 0, 200}}); + mHistogramRegistry->add("Event/zvtxhist", "; vtx_{z} (cm); Entries", kTH1F, {{250, -12.5, 12.5}}); + mHistogramRegistry->add("Event/MultV0M", "; vMultV0M; Entries", kTH1F, {{2000, 0, 20000}}); + mHistogramRegistry->add("Event/MultNTr", "; vMultNTr; Entries", kTH1F, {{20, 0, 200}}); + mHistogramRegistry->add("Event/MultNTrVSMultV0M", "; vMultNTr; MultV0M", kTH2F, {{200, 0, 4000}, {2000, 0, 20000}}); + mHistogramRegistry->add("Event/zvtxhist_MultNTr", "; zvtxhist; MultNTr", kTH2F, {{250, -12.5, 12.5}, {20, 0, 200}}); } /// Some basic QA of the event @@ -50,12 +52,14 @@ class FemtoUniverseEventHisto mHistogramRegistry->fill(HIST("Event/zvtxhist"), col.posZ()); mHistogramRegistry->fill(HIST("Event/MultV0M"), col.multV0M()); mHistogramRegistry->fill(HIST("Event/MultNTr"), col.multNtr()); + mHistogramRegistry->fill(HIST("Event/MultNTrVSMultV0M"), col.multNtr(), col.multV0M()); + mHistogramRegistry->fill(HIST("Event/zvtxhist_MultNTr"), col.posZ(), col.multNtr()); } } private: HistogramRegistry* mHistogramRegistry; ///< For QA output }; -} // namespace o2::analysis::femtoUniverse +} // namespace o2::analysis::femto_universe #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEEVENTHISTO_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseFemtoContainer.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseFemtoContainer.h index e921bb719df..e973cadee90 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseFemtoContainer.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseFemtoContainer.h @@ -33,10 +33,10 @@ using namespace o2::framework; -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { -namespace femtoUniverseFemtoContainer +namespace femto_universe_femto_container { /// Femtoscopic observable to be computed enum Observable { kstar ///< kstar @@ -46,7 +46,7 @@ enum Observable { kstar ///< kstar enum EventType { same, ///< Pair from same event mixed ///< Pair from mixed event }; -}; // namespace femtoUniverseFemtoContainer +}; // namespace femto_universe_femto_container /// \class FemtoUniverseFemtoContainer /// \brief Container for all histogramming related to the correlation function. The two @@ -54,7 +54,7 @@ enum EventType { same, ///< Pair from same event /// are filled according to the specified observable /// \tparam eventType Type of the event (same/mixed) /// \tparam obs Observable to be computed (k*/Q_inv/...) -template +template class FemtoUniverseFemtoContainer { public: @@ -71,20 +71,20 @@ class FemtoUniverseFemtoContainer /// \param kTAxis axis object for the kT axis /// \param mTAxis axis object for the mT axis template - void init_base(std::string folderName, std::string femtoObs, T femtoObsAxis, T multAxis, T kTAxis, T mTAxis, T multAxis3D, T mTAxis3D, bool use3dplots) + void initBase(std::string folderName, std::string femtoObs, T femtoObsAxis, T multAxis, T kTAxis, T mTAxis, T multAxis3D, T mTAxis3D, bool use3dplots) { - mHistogramRegistry->add((folderName + "/relPairDist").c_str(), ("; " + femtoObs + "; Entries").c_str(), kTH1F, {femtoObsAxis}); - mHistogramRegistry->add((folderName + "/relPairkT").c_str(), "; #it{k}_{T} (GeV/#it{c}); Entries", kTH1F, {kTAxis}); - mHistogramRegistry->add((folderName + "/relPairkstarkT").c_str(), ("; " + femtoObs + "; #it{k}_{T} (GeV/#it{c})").c_str(), kTH2F, {femtoObsAxis, kTAxis}); - mHistogramRegistry->add((folderName + "/relPairkstarmT").c_str(), ("; " + femtoObs + "; #it{m}_{T} (GeV/#it{c}^{2})").c_str(), kTH2F, {femtoObsAxis, mTAxis}); - mHistogramRegistry->add((folderName + "/relPairkstarMult").c_str(), ("; " + femtoObs + "; Multiplicity").c_str(), kTH2F, {femtoObsAxis, multAxis}); - mHistogramRegistry->add((folderName + "/kstarPtPart1").c_str(), ("; " + femtoObs + "; #it{p} _{T} Particle 1 (GeV/#it{c})").c_str(), kTH2F, {femtoObsAxis, {375, 0., 7.5}}); - mHistogramRegistry->add((folderName + "/kstarPtPart2").c_str(), ("; " + femtoObs + "; #it{p} _{T} Particle 2 (GeV/#it{c})").c_str(), kTH2F, {femtoObsAxis, {375, 0., 7.5}}); - mHistogramRegistry->add((folderName + "/MultPtPart1").c_str(), "; #it{p} _{T} Particle 1 (GeV/#it{c}); Multiplicity", kTH2F, {{375, 0., 7.5}, multAxis}); - mHistogramRegistry->add((folderName + "/MultPtPart2").c_str(), "; #it{p} _{T} Particle 2 (GeV/#it{c}); Multiplicity", kTH2F, {{375, 0., 7.5}, multAxis}); - mHistogramRegistry->add((folderName + "/PtPart1PtPart2").c_str(), "; #it{p} _{T} Particle 1 (GeV/#it{c}); #it{p} _{T} Particle 2 (GeV/#it{c})", kTH2F, {{375, 0., 7.5}, {375, 0., 7.5}}); + kHistogramRegistry->add((folderName + "/relPairDist").c_str(), ("; " + femtoObs + "; Entries").c_str(), kTH1F, {femtoObsAxis}); + kHistogramRegistry->add((folderName + "/relPairkT").c_str(), "; #it{k}_{T} (GeV/#it{c}); Entries", kTH1F, {kTAxis}); + kHistogramRegistry->add((folderName + "/relPairkstarkT").c_str(), ("; " + femtoObs + "; #it{k}_{T} (GeV/#it{c})").c_str(), kTH2F, {femtoObsAxis, kTAxis}); + kHistogramRegistry->add((folderName + "/relPairkstarmT").c_str(), ("; " + femtoObs + "; #it{m}_{T} (GeV/#it{c}^{2})").c_str(), kTH2F, {femtoObsAxis, mTAxis}); + kHistogramRegistry->add((folderName + "/relPairkstarMult").c_str(), ("; " + femtoObs + "; Multiplicity").c_str(), kTH2F, {femtoObsAxis, multAxis}); + kHistogramRegistry->add((folderName + "/kstarPtPart1").c_str(), ("; " + femtoObs + "; #it{p} _{T} Particle 1 (GeV/#it{c})").c_str(), kTH2F, {femtoObsAxis, {375, 0., 7.5}}); + kHistogramRegistry->add((folderName + "/kstarPtPart2").c_str(), ("; " + femtoObs + "; #it{p} _{T} Particle 2 (GeV/#it{c})").c_str(), kTH2F, {femtoObsAxis, {375, 0., 7.5}}); + kHistogramRegistry->add((folderName + "/MultPtPart1").c_str(), "; #it{p} _{T} Particle 1 (GeV/#it{c}); Multiplicity", kTH2F, {{375, 0., 7.5}, multAxis}); + kHistogramRegistry->add((folderName + "/MultPtPart2").c_str(), "; #it{p} _{T} Particle 2 (GeV/#it{c}); Multiplicity", kTH2F, {{375, 0., 7.5}, multAxis}); + kHistogramRegistry->add((folderName + "/PtPart1PtPart2").c_str(), "; #it{p} _{T} Particle 1 (GeV/#it{c}); #it{p} _{T} Particle 2 (GeV/#it{c})", kTH2F, {{375, 0., 7.5}, {375, 0., 7.5}}); if (use3dplots) { - mHistogramRegistry->add((folderName + "/relPairkstarmTMult").c_str(), ("; " + femtoObs + "; #it{m}_{T} (GeV/#it{c}^{2}); Multiplicity").c_str(), kTH3F, {femtoObsAxis, mTAxis3D, multAxis3D}); + kHistogramRegistry->add((folderName + "/relPairkstarmTMult").c_str(), ("; " + femtoObs + "; #it{m}_{T} (GeV/#it{c}^{2}); Multiplicity").c_str(), kTH3F, {femtoObsAxis, mTAxis3D, multAxis3D}); } } @@ -94,19 +94,19 @@ class FemtoUniverseFemtoContainer /// \param folderName Name of the directory in the output file (no suffix for reconstructed data/ Monte Carlo; "_MC" for Monte Carlo Truth) /// \param femtoObsAxis axis object for the femto observable axis template - void init_MC(std::string folderName, std::string femtoObs, T femtoObsAxis, T multAxis, T mTAxis) + void initMC(std::string folderName, std::string femtoObs, T femtoObsAxis, T multAxis, T mTAxis) { - mHistogramRegistry->add((folderName + "/relPairDist_ReconNoFake").c_str(), ("; " + femtoObs + "; Entries").c_str(), kTH1F, {femtoObsAxis}); - mHistogramRegistry->add((folderName + "/relPairkstarmT_ReconNoFake").c_str(), ("; " + femtoObs + "; #it{m}_{T} (GeV/#it{c}^{2})").c_str(), kTH2F, {femtoObsAxis, mTAxis}); - mHistogramRegistry->add((folderName + "/relPairkstarMult_ReconNoFake").c_str(), ("; " + femtoObs + "; Multiplicity").c_str(), kTH2F, {femtoObsAxis, multAxis}); - mHistogramRegistry->add((folderName + "/hNoMCtruthPairsCounter").c_str(), "; Counter; Entries", kTH1I, {{1, 0, 1}}); - mHistogramRegistry->add((folderName + "/hFakePairsCounter").c_str(), "; Counter; Entries", kTH1I, {{1, 0, 1}}); - mHistogramRegistry->add((folderName + "/kstar_resolution").c_str(), "; #it{k} _{T} reconstructed (GeV/#it{c}); #it{k} _{T} truth (GeV/#it{c})", kTH2F, {femtoObsAxis, femtoObsAxis}); + kHistogramRegistry->add((folderName + "/relPairDist_ReconNoFake").c_str(), ("; " + femtoObs + "; Entries").c_str(), kTH1F, {femtoObsAxis}); + kHistogramRegistry->add((folderName + "/relPairkstarmT_ReconNoFake").c_str(), ("; " + femtoObs + "; #it{m}_{T} (GeV/#it{c}^{2})").c_str(), kTH2F, {femtoObsAxis, mTAxis}); + kHistogramRegistry->add((folderName + "/relPairkstarMult_ReconNoFake").c_str(), ("; " + femtoObs + "; Multiplicity").c_str(), kTH2F, {femtoObsAxis, multAxis}); + kHistogramRegistry->add((folderName + "/hNoMCtruthPairsCounter").c_str(), "; Counter; Entries", kTH1I, {{1, 0, 1}}); + kHistogramRegistry->add((folderName + "/hFakePairsCounter").c_str(), "; Counter; Entries", kTH1I, {{1, 0, 1}}); + kHistogramRegistry->add((folderName + "/kstar_resolution").c_str(), "; #it{k} _{T} reconstructed (GeV/#it{c}); #it{k} _{T} truth (GeV/#it{c})", kTH2F, {femtoObsAxis, femtoObsAxis}); } /// Templated function to initialize the histograms for the task - /// Always calls init_base to initialize the histograms for data/ Monte Carlo reconstructed - /// In case of Monte Carlo, calls init_base again for Monte Carlo truth and the specialized function init_MC for additional histogramms + /// Always calls initBase to initialize the histograms for data/ Monte Carlo reconstructed + /// In case of Monte Carlo, calls initBase again for Monte Carlo truth and the specialized function initMC for additional histogramms /// \tparam T type of the configurable for the axis configuration /// \param registry Histogram registry to be passed /// \param kstarBins k* binning for the histograms @@ -117,9 +117,9 @@ class FemtoUniverseFemtoContainer template void init(HistogramRegistry* registry, T& kstarBins, T& multBins, T& kTBins, T& mTBins, T& multBins3D, T& mTBins3D, bool isMC, bool use3dplots) { - mHistogramRegistry = registry; + kHistogramRegistry = registry; std::string femtoObs; - if constexpr (mFemtoObs == femtoUniverseFemtoContainer::Observable::kstar) { + if constexpr (kFemtoObs == femto_universe_femto_container::Observable::kstar) { femtoObs = "#it{k*} (GeV/#it{c})"; } std::vector tmpVecMult = multBins; @@ -131,13 +131,13 @@ class FemtoUniverseFemtoContainer framework::AxisSpec multAxis3D = {multBins3D, "Multiplicity"}; framework::AxisSpec mTAxis3D = {mTBins3D, "#it{m}_{T} (GeV/#it{c})"}; - std::string folderName = static_cast(mFolderSuffix[mEventType]) + static_cast(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kRecon]); + std::string folderName = static_cast(kFolderSuffix[kEventType]) + static_cast(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kRecon]); - init_base(folderName, femtoObs, femtoObsAxis, multAxis, kTAxis, mTAxis, multAxis3D, mTAxis3D, use3dplots); + initBase(folderName, femtoObs, femtoObsAxis, multAxis, kTAxis, mTAxis, multAxis3D, mTAxis3D, use3dplots); if (isMC) { - folderName = static_cast(mFolderSuffix[mEventType]) + static_cast(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kTruth]); - init_base(folderName, femtoObs, femtoObsAxis, multAxis, kTAxis, mTAxis, multAxis3D, mTAxis3D, use3dplots); - init_MC(folderName, femtoObs, femtoObsAxis, multAxis, mTAxis); + folderName = static_cast(kFolderSuffix[kEventType]) + static_cast(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kTruth]); + initBase(folderName, femtoObs, femtoObsAxis, multAxis, kTAxis, mTAxis, multAxis3D, mTAxis3D, use3dplots); + initMC(folderName, femtoObs, femtoObsAxis, multAxis, mTAxis); } } @@ -146,10 +146,10 @@ class FemtoUniverseFemtoContainer /// \param pdg2 PDG code of particle two void setPDGCodes(const int pdg1, const int pdg2) { - mMassOne = TDatabasePDG::Instance()->GetParticle(pdg1)->Mass(); - mMassTwo = TDatabasePDG::Instance()->GetParticle(pdg2)->Mass(); - mPDGOne = pdg1; - mPDGTwo = pdg2; + kMassOne = TDatabasePDG::Instance()->GetParticle(pdg1)->Mass(); + kMassTwo = TDatabasePDG::Instance()->GetParticle(pdg2)->Mass(); + kPDGOne = pdg1; + kPDGTwo = pdg2; } /// Pass a pair to the container and compute all the relevant observables @@ -158,23 +158,23 @@ class FemtoUniverseFemtoContainer /// \param part1 Particle one /// \param part2 Particle two /// \param mult Multiplicity of the event - template - void setPair_base(const float femtoObs, const float mT, T const& part1, T const& part2, const int mult, bool use3dplots) + template + void setPairBase(const float femtoObs, const float mT, T const& part1, T const& part2, const int mult, bool use3dplots) { - const float kT = FemtoUniverseMath::getkT(part1, mMassOne, part2, mMassTwo); + const float kT = FemtoUniverseMath::getkT(part1, kMassOne, part2, kMassTwo); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairDist"), femtoObs); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkT"), kT); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkstarkT"), femtoObs, kT); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkstarmT"), femtoObs, mT); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkstarMult"), femtoObs, mult); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/kstarPtPart1"), femtoObs, part1.pt()); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/kstarPtPart2"), femtoObs, part2.pt()); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/MultPtPart1"), part1.pt(), mult); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/MultPtPart2"), part2.pt(), mult); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/PtPart1PtPart2"), part1.pt(), part2.pt()); + kHistogramRegistry->fill(HIST(kFolderSuffix[kEventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairDist"), femtoObs); + kHistogramRegistry->fill(HIST(kFolderSuffix[kEventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkT"), kT); + kHistogramRegistry->fill(HIST(kFolderSuffix[kEventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkstarkT"), femtoObs, kT); + kHistogramRegistry->fill(HIST(kFolderSuffix[kEventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkstarmT"), femtoObs, mT); + kHistogramRegistry->fill(HIST(kFolderSuffix[kEventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkstarMult"), femtoObs, mult); + kHistogramRegistry->fill(HIST(kFolderSuffix[kEventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/kstarPtPart1"), femtoObs, part1.pt()); + kHistogramRegistry->fill(HIST(kFolderSuffix[kEventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/kstarPtPart2"), femtoObs, part2.pt()); + kHistogramRegistry->fill(HIST(kFolderSuffix[kEventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/MultPtPart1"), part1.pt(), mult); + kHistogramRegistry->fill(HIST(kFolderSuffix[kEventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/MultPtPart2"), part2.pt(), mult); + kHistogramRegistry->fill(HIST(kFolderSuffix[kEventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/PtPart1PtPart2"), part1.pt(), part2.pt()); if (use3dplots) { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/relPairkstarmTMult"), femtoObs, mT, mult); + kHistogramRegistry->fill(HIST(kFolderSuffix[kEventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/relPairkstarmTMult"), femtoObs, mT, mult); } } @@ -182,25 +182,25 @@ class FemtoUniverseFemtoContainer /// Fills MC truth specific histogramms: /// - kstar distribution plots with RECONSTRUCTED information but ONLY for non-fake candidates; needed for purity calculations of tracks /// - kstar resolution matrix - /// Note: Standard histogramms with MC truth information are filled with the setPair_base function + /// Note: Standard histogramms with MC truth information are filled with the setPairBase function /// \param part1 Particle one /// \param part2 Particle two /// \param mult Multiplicity of the event - void setPair_MC(const float femtoObsMC, const float femtoObs, const float mT, const int mult) + void setPairMC(const float femtoObsMC, const float femtoObs, const float mT, const int mult) { - if (mHistogramRegistry) { + if (kHistogramRegistry) { // Fill the kstar distributions with the reconstructed information but only for particles with the right PDG code - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kTruth]) + HIST("/relPairDist_ReconNoFake"), femtoObs); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kTruth]) + HIST("/relPairkstarmT_ReconNoFake"), femtoObs, mT); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kTruth]) + HIST("/relPairkstarMult_ReconNoFake"), femtoObs, mult); + kHistogramRegistry->fill(HIST(kFolderSuffix[kEventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kTruth]) + HIST("/relPairDist_ReconNoFake"), femtoObs); + kHistogramRegistry->fill(HIST(kFolderSuffix[kEventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kTruth]) + HIST("/relPairkstarmT_ReconNoFake"), femtoObs, mT); + kHistogramRegistry->fill(HIST(kFolderSuffix[kEventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kTruth]) + HIST("/relPairkstarMult_ReconNoFake"), femtoObs, mult); - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kTruth]) + HIST("/kstar_resolution"), femtoObsMC, femtoObs); + kHistogramRegistry->fill(HIST(kFolderSuffix[kEventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kTruth]) + HIST("/kstar_resolution"), femtoObsMC, femtoObs); } } /// Templated function to handle data/ Monte Carlo reconstructed and Monte Carlo truth - /// Always calls setPair_base to compute the observables with reconstructed data - /// In case of Monte Carlo, calls setPair_base with MC info and specialized function setPair_MC for additional histogramms + /// Always calls setPairBase to compute the observables with reconstructed data + /// In case of Monte Carlo, calls setPairBase with MC info and specialized function setPairMC for additional histogramms /// \tparam T type of the femtouniverseparticle /// \param part1 Particle one /// \param part2 Particle two @@ -210,47 +210,47 @@ class FemtoUniverseFemtoContainer { float femtoObs, femtoObsMC; // Calculate femto observable and the mT with reconstructed information - if constexpr (mFemtoObs == femtoUniverseFemtoContainer::Observable::kstar) { - femtoObs = FemtoUniverseMath::getkstar(part1, mMassOne, part2, mMassTwo); + if constexpr (kFemtoObs == femto_universe_femto_container::Observable::kstar) { + femtoObs = FemtoUniverseMath::getkstar(part1, kMassOne, part2, kMassTwo); } - const float mT = FemtoUniverseMath::getmT(part1, mMassOne, part2, mMassTwo); + const float mT = FemtoUniverseMath::getmT(part1, kMassOne, part2, kMassTwo); - if (mHistogramRegistry) { - setPair_base(femtoObs, mT, part1, part2, mult, use3dplots); + if (kHistogramRegistry) { + setPairBase(femtoObs, mT, part1, part2, mult, use3dplots); if constexpr (isMC) { if (part1.has_fdMCParticle() && part2.has_fdMCParticle()) { // calculate the femto observable and the mT with MC truth information - if constexpr (mFemtoObs == femtoUniverseFemtoContainer::Observable::kstar) { - femtoObsMC = FemtoUniverseMath::getkstar(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo); + if constexpr (kFemtoObs == femto_universe_femto_container::Observable::kstar) { + femtoObsMC = FemtoUniverseMath::getkstar(part1.fdMCParticle(), kMassOne, part2.fdMCParticle(), kMassTwo); } - const float mTMC = FemtoUniverseMath::getmT(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo); + const float mTMC = FemtoUniverseMath::getmT(part1.fdMCParticle(), kMassOne, part2.fdMCParticle(), kMassTwo); - if (abs(part1.fdMCParticle().pdgMCTruth()) == abs(mPDGOne) && abs(part2.fdMCParticle().pdgMCTruth()) == abs(mPDGTwo)) { // Note: all pair-histogramms are filled with MC truth information ONLY in case of non-fake candidates - setPair_base(femtoObsMC, mTMC, part1.fdMCParticle(), part2.fdMCParticle(), mult, use3dplots); - setPair_MC(femtoObsMC, femtoObs, mT, mult); + if (std::abs(part1.fdMCParticle().pdgMCTruth()) == std::abs(kPDGOne) && std::abs(part2.fdMCParticle().pdgMCTruth()) == std::abs(kPDGTwo)) { // Note: all pair-histogramms are filled with MC truth information ONLY in case of non-fake candidates + setPairBase(femtoObsMC, mTMC, part1.fdMCParticle(), part2.fdMCParticle(), mult, use3dplots); + setPairMC(femtoObsMC, femtoObs, mT, mult); } else { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kTruth]) + HIST("/hFakePairsCounter"), 0); + kHistogramRegistry->fill(HIST(kFolderSuffix[kEventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kTruth]) + HIST("/hFakePairsCounter"), 0); } } else { - mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kTruth]) + HIST("/hNoMCtruthPairsCounter"), 0); + kHistogramRegistry->fill(HIST(kFolderSuffix[kEventType]) + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kTruth]) + HIST("/hNoMCtruthPairsCounter"), 0); } } } } protected: - HistogramRegistry* mHistogramRegistry = nullptr; ///< For QA output - static constexpr std::string_view mFolderSuffix[2] = {"SameEvent", "MixedEvent"}; ///< Folder naming for the output according to mEventType - static constexpr femtoUniverseFemtoContainer::Observable mFemtoObs = obs; ///< Femtoscopic observable to be computed (according to femtoUniverseFemtoContainer::Observable) - static constexpr int mEventType = eventType; ///< Type of the event (same/mixed, according to femtoUniverseFemtoContainer::EventType) - float mMassOne = 0.f; ///< PDG mass of particle 1 - float mMassTwo = 0.f; ///< PDG mass of particle 2 - int mPDGOne = 0; ///< PDG code of particle 1 - int mPDGTwo = 0; ///< PDG code of particle 2 + HistogramRegistry* kHistogramRegistry = nullptr; ///< For QA output + static constexpr std::string_view kFolderSuffix[2] = {"SameEvent", "MixedEvent"}; ///< Folder naming for the output according to kEventType + static constexpr femto_universe_femto_container::Observable kFemtoObs = obs; ///< Femtoscopic observable to be computed (according to femto_universe_femto_container::Observable) + static constexpr int kEventType = eventType; ///< Type of the event (same/mixed, according to femto_universe_femto_container::EventType) + float kMassOne = 0.f; ///< PDG mass of particle 1 + float kMassTwo = 0.f; ///< PDG mass of particle 2 + int kPDGOne = 0; ///< PDG code of particle 1 + int kPDGTwo = 0; ///< PDG code of particle 2 }; -} // namespace o2::analysis::femtoUniverse +} // namespace o2::analysis::femto_universe #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEFEMTOCONTAINER_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h index cd992906c89..556f075d819 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h @@ -19,7 +19,6 @@ #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEMATH_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEMATH_H_ -#include #include #include @@ -28,7 +27,7 @@ #include "TLorentzVector.h" #include "TMath.h" -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { /// \class FemtoUniverseMath @@ -54,17 +53,47 @@ class FemtoUniverseMath const float betay = beta * std::sin(trackSum.Phi()) * std::sin(trackSum.Theta()); const float betaz = beta * std::cos(trackSum.Theta()); - ROOT::Math::PxPyPzMVector PartOneCMS(vecpart1); - ROOT::Math::PxPyPzMVector PartTwoCMS(vecpart2); + ROOT::Math::PxPyPzMVector partOneCMS(vecpart1); + ROOT::Math::PxPyPzMVector partTwoCMS(vecpart2); const ROOT::Math::Boost boostPRF = ROOT::Math::Boost(-betax, -betay, -betaz); - PartOneCMS = boostPRF(PartOneCMS); - PartTwoCMS = boostPRF(PartTwoCMS); + partOneCMS = boostPRF(partOneCMS); + partTwoCMS = boostPRF(partTwoCMS); - const ROOT::Math::PxPyPzMVector trackRelK = PartOneCMS - PartTwoCMS; + const ROOT::Math::PxPyPzMVector trackRelK = partOneCMS - partTwoCMS; return 0.5 * trackRelK.P(); } + /// \tparam T type of tracks + /// \param part1 Particle 1 + /// \param mass1 Mass of particle 1 + /// \param part2 Particle 2 + /// \param mass2 Mass of particle 2 + template + static float getthetastar(const T& part1, const float mass1, const T& part2, const float mass2) + { + const ROOT::Math::PtEtaPhiMVector vecpart1(part1.pt(), part1.eta(), part1.phi(), mass1); + const ROOT::Math::PtEtaPhiMVector vecpart2(part2.pt(), part2.eta(), part2.phi(), mass2); + const ROOT::Math::PtEtaPhiMVector trackSum = vecpart1 + vecpart2; + + const float beta = trackSum.Beta(); + const float betax = beta * std::cos(trackSum.Phi()) * std::sin(trackSum.Theta()); + const float betay = beta * std::sin(trackSum.Phi()) * std::sin(trackSum.Theta()); + const float betaz = beta * std::cos(trackSum.Theta()); + + ROOT::Math::PxPyPzMVector partOneCMS(vecpart1); + ROOT::Math::PxPyPzMVector partTwoCMS(vecpart2); + + const ROOT::Math::Boost boostPRF = ROOT::Math::Boost(-betax, -betay, -betaz); + partOneCMS = boostPRF(partOneCMS); + partTwoCMS = boostPRF(partTwoCMS); + + const ROOT::Math::PtEtaPhiMVector partOneCMSGeo(partOneCMS); + const ROOT::Math::PtEtaPhiMVector partTwoCMSGeo(partTwoCMS); + + return (partOneCMSGeo.Theta() - partTwoCMSGeo.Theta()); + } + /// Compute the qij of a pair of particles /// \tparam T type of tracks /// \param vecparti Particle i PxPyPzMVector @@ -98,21 +127,21 @@ class FemtoUniverseMath template static float getQ3(const T& part1, const float mass1, const T& part2, const float mass2, const T& part3, const float mass3) { - float E1 = sqrt(pow(part1.px(), 2) + pow(part1.py(), 2) + pow(part1.pz(), 2) + pow(mass1, 2)); - float E2 = sqrt(pow(part2.px(), 2) + pow(part2.py(), 2) + pow(part2.pz(), 2) + pow(mass2, 2)); - float E3 = sqrt(pow(part3.px(), 2) + pow(part3.py(), 2) + pow(part3.pz(), 2) + pow(mass3, 2)); + float e1 = std::sqrt(std::pow(part1.px(), 2) + std::pow(part1.py(), 2) + std::pow(part1.pz(), 2) + std::pow(mass1, 2)); + float e2 = std::sqrt(std::pow(part2.px(), 2) + std::pow(part2.py(), 2) + std::pow(part2.pz(), 2) + std::pow(mass2, 2)); + float e3 = std::sqrt(std::pow(part3.px(), 2) + std::pow(part3.py(), 2) + std::pow(part3.pz(), 2) + std::pow(mass3, 2)); - const ROOT::Math::PxPyPzEVector vecpart1(part1.px(), part1.py(), part1.pz(), E1); - const ROOT::Math::PxPyPzEVector vecpart2(part2.px(), part2.py(), part2.pz(), E2); - const ROOT::Math::PxPyPzEVector vecpart3(part3.px(), part3.py(), part3.pz(), E3); + const ROOT::Math::PxPyPzEVector vecpart1(part1.px(), part1.py(), part1.pz(), e1); + const ROOT::Math::PxPyPzEVector vecpart2(part2.px(), part2.py(), part2.pz(), e2); + const ROOT::Math::PxPyPzEVector vecpart3(part3.px(), part3.py(), part3.pz(), e3); ROOT::Math::PxPyPzEVector q12 = getqij(vecpart1, vecpart2); ROOT::Math::PxPyPzEVector q23 = getqij(vecpart2, vecpart3); ROOT::Math::PxPyPzEVector q31 = getqij(vecpart3, vecpart1); - float Q32 = q12.M2() + q23.M2() + q31.M2(); + float q32 = q12.M2() + q23.M2() + q31.M2(); - return sqrt(-Q32); + return std::sqrt(-q32); } /// Compute the transverse momentum of a pair of particles @@ -149,15 +178,14 @@ class FemtoUniverseMath /// \param part2 Particle 2 /// \param mass2 Mass of particle 2 /// \param isiden Identical or non-identical particle pair - /// \param islcms LCMS or PRF template - static std::vector getpairmom3d(const T& part1, const float mass1, const T& part2, const float mass2, bool isiden, bool islcms) + static std::vector newpairfunc(const T& part1, const float mass1, const T& part2, const float mass2, bool isiden) { - const double E1 = sqrt(pow(part1.px(), 2) + pow(part1.py(), 2) + pow(part1.pz(), 2) + pow(mass1, 2)); - const double E2 = sqrt(pow(part2.px(), 2) + pow(part2.py(), 2) + pow(part2.pz(), 2) + pow(mass2, 2)); + const double e1 = std::sqrt(std::pow(part1.px(), 2) + std::pow(part1.py(), 2) + std::pow(part1.pz(), 2) + std::pow(mass1, 2)); + const double e2 = std::sqrt(std::pow(part2.px(), 2) + std::pow(part2.py(), 2) + std::pow(part2.pz(), 2) + std::pow(mass2, 2)); - const ROOT::Math::PxPyPzEVector vecpart1(part1.px(), part1.py(), part1.pz(), E1); - const ROOT::Math::PxPyPzEVector vecpart2(part2.px(), part2.py(), part2.pz(), E2); + const ROOT::Math::PxPyPzEVector vecpart1(part1.px(), part1.py(), part1.pz(), e1); + const ROOT::Math::PxPyPzEVector vecpart2(part2.px(), part2.py(), part2.pz(), e2); const ROOT::Math::PxPyPzEVector trackSum = vecpart1 + vecpart2; std::vector vect; @@ -165,85 +193,68 @@ class FemtoUniverseMath const double tPx = trackSum.px(); const double tPy = trackSum.py(); const double tPz = trackSum.pz(); - const double tPE = trackSum.E(); - - const double tPt = trackSum.pt(); - const double tMt = trackSum.mt(); - const double tPinv = std::sqrt((tMt * tMt) - (tPt * tPt)); - - float nullmass = 0.0; - const double m1 = std::max(nullmass, mass1); - const double m2 = std::max(nullmass, mass2); - - const double tQinvL = std::pow((E1 - E2), 2) - std::pow((part1.px() - part2.px()), 2) - - std::pow((part1.py() - part2.py()), 2) - std::pow((part1.pz() - part2.pz()), 2); + const double tE = trackSum.E(); - double tQ = (m1 - m2) / tPinv; - tQ = ::sqrt(tQ * tQ - tQinvL); - - const double fKStarCalc = tQ / 2.0; - vect.push_back(fKStarCalc); + const double tPtSq = (tPx * tPx + tPy * tPy); + const double tMtSq = (tE * tE - tPz * tPz); + const double tM = std::sqrt(tMtSq - tPtSq); + const double tMt = std::sqrt(tMtSq); + const double tPt = std::sqrt(tPtSq); // Boost to LCMS - const double beta = tPz / tPE; - const double gamma = tPE / tMt; - - const double px1L = (part1.px() * tPx + part1.py() * tPy) / tPt; - const double py1L = (-part1.px() * tPy + part1.py() * tPx) / tPt; - const double pz1L = gamma * (part1.pz() - beta * E1); - const double pE1L = gamma * (E1 - beta * part1.pz()); + const double beta = tPz / tE; + const double gamma = tE / tMt; - const double px2L = (part2.px() * tPx + part2.py() * tPy) / tPt; - const double py2L = (-part2.px() * tPy + part2.py() * tPx) / tPt; - const double pz2L = gamma * (part2.pz() - beta * E2); - const double pE2L = gamma * (E2 - beta * part2.pz()); + const double fDKOut = (part1.px() * tPx + part1.py() * tPy) / tPt; + const double fDKSide = (-part1.px() * tPy + part1.py() * tPx) / tPt; + const double fDKLong = gamma * (part1.pz() - beta * e1); + const double fDE = gamma * (e1 - beta * part1.pz()); - double fDKOutLCMS; - double fDKSideLCMS; - double fDKLongLCMS; + const double px1LCMS = fDKOut; + const double py1LCMS = fDKSide; + const double pz1LCMS = fDKLong; + const double pE1LCMS = fDE; - double fDKOutPRF; - double fDKSidePRF; - double fDKLongPRF; + const double px2LCMS = (part2.px() * tPx + part2.py() * tPy) / tPt; + const double py2LCMS = (part2.py() * tPx - part2.px() * tPy) / tPt; + const double pz2LCMS = gamma * (part2.pz() - beta * e2); + const double pE2LCMS = gamma * (e2 - beta * part2.pz()); - if (!isiden) { - fDKOutLCMS = px1L; - fDKSideLCMS = py1L; - fDKLongLCMS = pz1L; - } else { - fDKOutLCMS = px1L - px2L; - fDKSideLCMS = py1L - py2L; - fDKLongLCMS = pz1L - pz2L; - } + const double fDKOutLCMS = px1LCMS - px2LCMS; + const double fDKSideLCMS = py1LCMS - py2LCMS; + const double fDKLongLCMS = pz1LCMS - pz2LCMS; // Boost to PRF + const double betaOut = tPt / tMt; - const double gammaOut = tMt / tPinv; + const double gammaOut = tMt / tM; - if (!isiden) { - fDKOutPRF = gammaOut * (fDKOutLCMS - betaOut * pE1L); - fDKSidePRF = fDKSideLCMS; - fDKLongPRF = fDKLongLCMS; - } else { - fDKOutPRF = gammaOut * (fDKOutLCMS - betaOut * (pE1L - pE2L)); - fDKSidePRF = fDKSideLCMS; - fDKLongPRF = fDKLongLCMS; - } + const double fDKOutPRF = gammaOut * (fDKOutLCMS - betaOut * (pE1LCMS - pE2LCMS)); + const double fDKSidePRF = fDKSideLCMS; + const double fDKLongPRF = fDKLongLCMS; + const double fKOut = gammaOut * (fDKOut - betaOut * fDE); + + const double qlcms = std::sqrt(fDKOutLCMS * fDKOutLCMS + fDKSideLCMS * fDKSideLCMS + fDKLongLCMS * fDKLongLCMS); + const double qinv = std::sqrt(fDKOutPRF * fDKOutPRF + fDKSidePRF * fDKSidePRF + fDKLongPRF * fDKLongPRF); + const double kstar = std::sqrt(fKOut * fKOut + fDKSide * fDKSide + fDKLong * fDKLong); - if (islcms) { + if (isiden) { + vect.push_back(qinv); vect.push_back(fDKOutLCMS); vect.push_back(fDKSideLCMS); vect.push_back(fDKLongLCMS); + vect.push_back(qlcms); } else { - vect.push_back(fDKOutPRF); - vect.push_back(fDKSidePRF); - vect.push_back(fDKLongPRF); + vect.push_back(kstar); + vect.push_back(fDKOut); + vect.push_back(fDKSide); + vect.push_back(fDKLong); } return vect; } }; -} // namespace o2::analysis::femtoUniverse +} // namespace o2::analysis::femto_universe #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEMATH_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseObjectSelection.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseObjectSelection.h index acf802c161e..18281ac198b 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseObjectSelection.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseObjectSelection.h @@ -31,7 +31,7 @@ using namespace o2::framework; namespace o2::analysis { -namespace femtoUniverse +namespace femto_universe { /// \class FemtoUniverseObjectSelection @@ -67,7 +67,7 @@ class FemtoUniverseObjectSelection /// \param selVar Variable to be employed for the selection /// \param selType Type of the selection to be employed template - void setSelection(T& selVals, selVariable selVar, femtoUniverseSelection::SelectionType selType) + void setSelection(T& selVals, selVariable selVar, femto_universe_selection::SelectionType selType) { std::vector tmpSelVals = selVals; // necessary due to some features of the Configurable std::vector> tempVec; @@ -83,15 +83,15 @@ class FemtoUniverseObjectSelection { /// First the selection is sorted so that the most open cuts are conducted first switch (sels.at(0).getSelectionType()) { - case (femtoUniverseSelection::SelectionType::kUpperLimit): - case (femtoUniverseSelection::SelectionType::kAbsUpperLimit): + case (femto_universe_selection::SelectionType::kUpperLimit): + case (femto_universe_selection::SelectionType::kAbsUpperLimit): std::sort(sels.begin(), sels.end(), [](FemtoUniverseSelection a, FemtoUniverseSelection b) { return a.getSelectionValue() > b.getSelectionValue(); }); break; - case (femtoUniverseSelection::SelectionType::kLowerLimit): - case (femtoUniverseSelection::SelectionType::kAbsLowerLimit): - case (femtoUniverseSelection::SelectionType::kEqual): + case (femto_universe_selection::SelectionType::kLowerLimit): + case (femto_universe_selection::SelectionType::kAbsLowerLimit): + case (femto_universe_selection::SelectionType::kEqual): std::sort(sels.begin(), sels.end(), [](FemtoUniverseSelection a, FemtoUniverseSelection b) { return a.getSelectionValue() < b.getSelectionValue(); }); @@ -108,17 +108,17 @@ class FemtoUniverseObjectSelection /// \param selVar Selection variable under consideration /// \param selType Type of the selection variable /// \return The most open selection of the selection variable given to the class - selValDataType getMinimalSelection(selVariable selVar, femtoUniverseSelection::SelectionType selType) + selValDataType getMinimalSelection(selVariable selVar, femto_universe_selection::SelectionType selType) { selValDataType minimalSel{}; switch (selType) { - case (femtoUniverseSelection::SelectionType::kUpperLimit): - case (femtoUniverseSelection::SelectionType::kAbsUpperLimit): + case (femto_universe_selection::SelectionType::kUpperLimit): + case (femto_universe_selection::SelectionType::kAbsUpperLimit): minimalSel = -999.e9; break; - case (femtoUniverseSelection::SelectionType::kLowerLimit): - case (femtoUniverseSelection::SelectionType::kAbsLowerLimit): - case (femtoUniverseSelection::SelectionType::kEqual): + case (femto_universe_selection::SelectionType::kLowerLimit): + case (femto_universe_selection::SelectionType::kAbsLowerLimit): + case (femto_universe_selection::SelectionType::kEqual): minimalSel = 999.e9; break; } @@ -126,15 +126,15 @@ class FemtoUniverseObjectSelection for (auto sel : mSelections) { if (sel.getSelectionVariable() == selVar) { switch (sel.getSelectionType()) { - case (femtoUniverseSelection::SelectionType::kUpperLimit): - case (femtoUniverseSelection::SelectionType::kAbsUpperLimit): + case (femto_universe_selection::SelectionType::kUpperLimit): + case (femto_universe_selection::SelectionType::kAbsUpperLimit): if (minimalSel < sel.getSelectionValue()) { minimalSel = sel.getSelectionValue(); } break; - case (femtoUniverseSelection::SelectionType::kLowerLimit): - case (femtoUniverseSelection::SelectionType::kAbsLowerLimit): - case (femtoUniverseSelection::SelectionType::kEqual): + case (femto_universe_selection::SelectionType::kLowerLimit): + case (femto_universe_selection::SelectionType::kAbsLowerLimit): + case (femto_universe_selection::SelectionType::kEqual): if (minimalSel > sel.getSelectionValue()) { minimalSel = sel.getSelectionValue(); } @@ -193,7 +193,7 @@ class FemtoUniverseObjectSelection std::vector> mSelections; ///< Vector containing all selections }; -} // namespace femtoUniverse +} // namespace femto_universe } // namespace o2::analysis #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEOBJECTSELECTION_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniversePairAngularWithCentMultKt.h b/PWGCF/FemtoUniverse/Core/FemtoUniversePairAngularWithCentMultKt.h index cc017bf192e..31b256f43f7 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniversePairAngularWithCentMultKt.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniversePairAngularWithCentMultKt.h @@ -8,26 +8,25 @@ // 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 FemtoUniversePairAngularWithCentMultKt.h +/// \brief FemtoUniversePairAngularWithCentMultKt - Histogram class for angular pair tracks with centrality and multiplicity /// \author Deependra Sharma, IITB, deependra.sharma@cern.ch /// \author Alicja Płachta, WUT Warsaw, alicja.plachta.stud@pw.edu.pl +/// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPAIRANGULARWITHCENTMULTKT_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPAIRANGULARWITHCENTMULTKT_H_ #include -#include #include #include "Framework/HistogramRegistry.h" -using namespace o2; -using namespace o2::framework; - -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { -class PairWithCentMultKt +class FemtoUniversePairAngularWithCentMultKt { public: - virtual ~PairWithCentMultKt() = default; + virtual ~FemtoUniversePairAngularWithCentMultKt() = default; /// @brief /// @tparam t1 /// @param registry @@ -36,46 +35,46 @@ class PairWithCentMultKt template void init(HistogramRegistry* registry, t1& /*kstarbins*/, t1& centmultbins, t2& phiBins, t2& etaBins, bool processKT) { - PairWithCentMultKtRegistry = registry; + pairWithCentMultKtRegistry = registry; // AxisSpec kstarAxis = {kstarbins, "#it{k*} (GeV/#it{c})"}; - mPhiLow = (-static_cast(phiBins / 4) + 0.5) * 2. * o2::constants::math::PI / phiBins; - mPhiHigh = 2 * o2::constants::math::PI + (-static_cast(phiBins / 4) + 0.5) * 2. * o2::constants::math::PI / phiBins; - framework::AxisSpec phiAxis = {phiBins, mPhiLow, mPhiHigh}; + kPhiLow = (-static_cast(phiBins / 4) + 0.5) * o2::constants::math::TwoPI / phiBins; + kPhiHigh = o2::constants::math::TwoPI + (-static_cast(phiBins / 4) + 0.5) * o2::constants::math::TwoPI / phiBins; + framework::AxisSpec phiAxis = {phiBins, kPhiLow, kPhiHigh}; framework::AxisSpec etaAxis = {etaBins, -2.0, 2.0}; - CentMultBins = centmultbins; - KtBins = {0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f, 2.0f, 99999.f}; // temporary - KtBins.erase(KtBins.begin()); - CentMultBins.erase(CentMultBins.begin()); - UseKt = processKT; + kCentMultBins = centmultbins; + ktBins = {0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f, 2.0f, 99999.f}; // temporary + ktBins.erase(ktBins.begin()); + kCentMultBins.erase(kCentMultBins.begin()); + useKt = processKT; - for (int i = 0; i < static_cast(CentMultBins.size() - 1); i++) { - int lowBin = static_cast((CentMultBins[i])); - int highBin = static_cast((CentMultBins[i + 1])); - std::string HistTitle = "mult_" + std::to_string(lowBin) + "-" + std::to_string(highBin); - std::string HistSuffix1 = static_cast(HistSuffix[i]); - std::string HistSuffix2 = static_cast(HistSuffix[i + 1]); - std::string HistFolderMult = "mult_" + HistSuffix1 + "_" + HistSuffix2; - std::string HistName = HistFolderMult + "/DeltaEtaDeltaPhi"; - PairWithCentMultKtRegistry->add(HistName.c_str(), HistTitle.c_str(), HistType::kTH2F, {phiAxis, etaAxis}); - if (UseKt) { - for (int i = 0; i < static_cast(KtBins.size() - 1); i++) { - std::string kt_bin1_string = std::to_string(KtBins[i]); - std::replace(kt_bin1_string.begin(), kt_bin1_string.end(), '.', '_'); - std::string kt_bin2_string = std::to_string(KtBins[i + 1]); - std::replace(kt_bin2_string.begin(), kt_bin2_string.end(), '.', '_'); - kt_bin1_string.resize(4); - kt_bin2_string.resize(4); - std::string HistTitleKt = "kt_" + kt_bin1_string + "-" + kt_bin2_string; - std::string HistSuffix1Kt = static_cast(HistSuffix[i]); - std::string HistSuffix2Kt = static_cast(HistSuffix[i + 1]); - std::string HistNameKt = HistFolderMult + "/DeltaEtaDeltaPhi" + HistSuffix1Kt + "_" + HistSuffix2Kt; - PairWithCentMultKtRegistry->add(HistNameKt.c_str(), HistTitleKt.c_str(), HistType::kTH2F, {phiAxis, etaAxis}); + for (int i = 0; i < static_cast(kCentMultBins.size() - 1); i++) { + int lowBin = static_cast((kCentMultBins[i])); + int highBin = static_cast((kCentMultBins[i + 1])); + std::string kHistTitle = "mult_" + std::to_string(lowBin) + "-" + std::to_string(highBin); + std::string kHistSuffix1 = static_cast(HistSuffix[i]); + std::string kHistSuffix2 = static_cast(HistSuffix[i + 1]); + std::string kHistFolderMult = "mult_" + kHistSuffix1 + "_" + kHistSuffix2; + std::string kHistName = kHistFolderMult + "/DeltaEtaDeltaPhi"; + pairWithCentMultKtRegistry->add(kHistName.c_str(), kHistTitle.c_str(), HistType::kTH2F, {phiAxis, etaAxis}); + if (useKt) { + for (int i = 0; i < static_cast(ktBins.size() - 1); i++) { + std::string ktBin1String = std::to_string(ktBins[i]); + std::replace(ktBin1String.begin(), ktBin1String.end(), '.', '_'); + std::string ktBin2String = std::to_string(ktBins[i + 1]); + std::replace(ktBin2String.begin(), ktBin2String.end(), '.', '_'); + ktBin1String.resize(4); + ktBin2String.resize(4); + std::string kHistTitleKt = "kt_" + ktBin1String + "-" + ktBin2String; + std::string kHistSuffix1Kt = static_cast(HistSuffix[i]); + std::string kHistSuffix2Kt = static_cast(HistSuffix[i + 1]); + std::string kHistNameKt = kHistFolderMult + "/DeltaEtaDeltaPhi" + kHistSuffix1Kt + "_" + kHistSuffix2Kt; + pairWithCentMultKtRegistry->add(kHistNameKt.c_str(), kHistTitleKt.c_str(), HistType::kTH2F, {phiAxis, etaAxis}); } } } - PairWithCentMultKtRegistry->add("Beyond_Max", "Beyond_Max", HistType::kTH2F, {phiAxis, etaAxis}); + pairWithCentMultKtRegistry->add("Beyond_Max", "Beyond_Max", HistType::kTH2F, {phiAxis, etaAxis}); } /// @brief @@ -86,59 +85,59 @@ class PairWithCentMultKt void fill(t1 kstar_value, t1 cent_mult_value, t1 d_phi_value, t1 d_eta_value) { - if (cent_mult_value > CentMultBins[CentMultBins.size() - 1] || cent_mult_value < CentMultBins[0]) { - PairWithCentMultKtRegistry->fill(HIST("Beyond_Max"), kstar_value); - } else if (cent_mult_value <= CentMultBins[1]) { - PairWithCentMultKtRegistry->fill(HIST("mult_0_1/DeltaEtaDeltaPhi"), d_phi_value, d_eta_value); - if (UseKt) { + if (cent_mult_value > kCentMultBins[kCentMultBins.size() - 1] || cent_mult_value < kCentMultBins[0]) { + pairWithCentMultKtRegistry->fill(HIST("Beyond_Max"), kstar_value); + } else if (cent_mult_value <= kCentMultBins[1]) { + pairWithCentMultKtRegistry->fill(HIST("mult_0_1/DeltaEtaDeltaPhi"), d_phi_value, d_eta_value); + if (useKt) { // auto histMultFolder = HIST("mult_0_1/"); // fill_kT(kstar_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[2]) { - PairWithCentMultKtRegistry->fill(HIST("mult_1_2/DeltaEtaDeltaPhi"), d_phi_value, d_eta_value); - if (UseKt) { + } else if (cent_mult_value <= kCentMultBins[2]) { + pairWithCentMultKtRegistry->fill(HIST("mult_1_2/DeltaEtaDeltaPhi"), d_phi_value, d_eta_value); + if (useKt) { // auto histMultFolder = HIST("mult_1_2/"); // fill_kT(kstar_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[3]) { - PairWithCentMultKtRegistry->fill(HIST("mult_2_3/DeltaEtaDeltaPhi"), d_phi_value, d_eta_value); - if (UseKt) { + } else if (cent_mult_value <= kCentMultBins[3]) { + pairWithCentMultKtRegistry->fill(HIST("mult_2_3/DeltaEtaDeltaPhi"), d_phi_value, d_eta_value); + if (useKt) { // auto histMultFolder = HIST("mult_2_3/"); // fill_kT(kstar_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[4]) { - PairWithCentMultKtRegistry->fill(HIST("mult_3_4/DeltaEtaDeltaPhi"), d_phi_value, d_eta_value); - if (UseKt) { + } else if (cent_mult_value <= kCentMultBins[4]) { + pairWithCentMultKtRegistry->fill(HIST("mult_3_4/DeltaEtaDeltaPhi"), d_phi_value, d_eta_value); + if (useKt) { // auto histMultFolder = HIST("mult_3_4/"); // fill_kT(kstar_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[5]) { - PairWithCentMultKtRegistry->fill(HIST("mult_4_5/DeltaEtaDeltaPhi"), d_phi_value, d_eta_value); - if (UseKt) { + } else if (cent_mult_value <= kCentMultBins[5]) { + pairWithCentMultKtRegistry->fill(HIST("mult_4_5/DeltaEtaDeltaPhi"), d_phi_value, d_eta_value); + if (useKt) { // auto histMultFolder = HIST("mult_4_5/"); // fill_kT(kstar_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[6]) { - PairWithCentMultKtRegistry->fill(HIST("mult_5_6/DeltaEtaDeltaPhi"), d_phi_value, d_eta_value); - if (UseKt) { + } else if (cent_mult_value <= kCentMultBins[6]) { + pairWithCentMultKtRegistry->fill(HIST("mult_5_6/DeltaEtaDeltaPhi"), d_phi_value, d_eta_value); + if (useKt) { // auto histMultFolder = HIST("mult_5_6/"); // fill_kT(kstar_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[7]) { - PairWithCentMultKtRegistry->fill(HIST("mult_6_7/DeltaEtaDeltaPhi"), d_phi_value, d_eta_value); - if (UseKt) { + } else if (cent_mult_value <= kCentMultBins[7]) { + pairWithCentMultKtRegistry->fill(HIST("mult_6_7/DeltaEtaDeltaPhi"), d_phi_value, d_eta_value); + if (useKt) { // auto histMultFolder = HIST("mult_6_7/"); // fill_kT(kstar_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[8]) { - PairWithCentMultKtRegistry->fill(HIST("mult_7_8/DeltaEtaDeltaPhi"), d_phi_value, d_eta_value); - if (UseKt) { + } else if (cent_mult_value <= kCentMultBins[8]) { + pairWithCentMultKtRegistry->fill(HIST("mult_7_8/DeltaEtaDeltaPhi"), d_phi_value, d_eta_value); + if (useKt) { // auto histMultFolder = HIST("mult_7_8/"); // fill_kT(kstar_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[9]) { - PairWithCentMultKtRegistry->fill(HIST("mult_8_9/kstar"), d_phi_value, d_eta_value); - if (UseKt) { + } else if (cent_mult_value <= kCentMultBins[9]) { + pairWithCentMultKtRegistry->fill(HIST("mult_8_9/kstar"), d_phi_value, d_eta_value); + if (useKt) { // auto histMultFolder = HIST("mult_8_9/"); // fill_kT(kstar_value, kt_value, histMultFolder); } @@ -154,38 +153,38 @@ class PairWithCentMultKt // template // void fill_kT(t1 kstar_value, t1 kt_value, t2 folder) // { - // if (kt_value <= KtBins[1]) { - // PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_0_1"), kstar_value); - // } else if (kt_value <= KtBins[2]) { - // PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_1_2"), kstar_value); - // } else if (kt_value <= KtBins[3]) { - // PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_2_3"), kstar_value); - // } else if (kt_value <= KtBins[4]) { - // PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_3_4"), kstar_value); - // } else if (kt_value <= KtBins[5]) { - // PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_4_5"), kstar_value); - // } else if (kt_value <= KtBins[6]) { - // PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_5_6"), kstar_value); - // } else if (kt_value <= KtBins[7]) { - // PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_6_7"), kstar_value); - // } else if (kt_value <= KtBins[8]) { - // PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_7_8"), kstar_value); - // } else if (kt_value <= KtBins[9]) { - // PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_8_9"), kstar_value); + // if (kt_value <= ktBins[1]) { + // pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_0_1"), kstar_value); + // } else if (kt_value <= ktBins[2]) { + // pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_1_2"), kstar_value); + // } else if (kt_value <= ktBins[3]) { + // pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_2_3"), kstar_value); + // } else if (kt_value <= ktBins[4]) { + // pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_3_4"), kstar_value); + // } else if (kt_value <= ktBins[5]) { + // pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_4_5"), kstar_value); + // } else if (kt_value <= ktBins[6]) { + // pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_5_6"), kstar_value); + // } else if (kt_value <= ktBins[7]) { + // pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_6_7"), kstar_value); + // } else if (kt_value <= ktBins[8]) { + // pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_7_8"), kstar_value); + // } else if (kt_value <= ktBins[9]) { + // pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_8_9"), kstar_value); // } // } protected: - HistogramRegistry* PairWithCentMultKtRegistry = nullptr; - std::vector CentMultBins; - std::vector KtBins; - bool UseKt = false; - double mPhiLow; - double mPhiHigh; - double delta_eta; - double delta_phi; + HistogramRegistry* pairWithCentMultKtRegistry = nullptr; + std::vector kCentMultBins; + std::vector ktBins; + bool useKt = false; + double kPhiLow; + double kPhiHigh; + double deltaEta; + double deltaPhi; static constexpr std::string_view HistSuffix[10] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; }; -} // namespace o2::analysis::femtoUniverse +} // namespace o2::analysis::femto_universe #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPAIRANGULARWITHCENTMULTKT_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h b/PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h index c18233ee8f0..6b73b56466d 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h @@ -14,6 +14,7 @@ /// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de /// \author Laura Serksnyte, TU München,laura.serksnyte@cern.ch /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch +/// \author Shirajum Monira, WUT Warsaw, shirajum.monira@cern.ch #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPAIRCLEANER_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPAIRCLEANER_H_ @@ -21,9 +22,7 @@ #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" #include "Framework/HistogramRegistry.h" -using namespace o2::framework; - -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { /// \class FemtoUniversePairCleaner @@ -57,21 +56,21 @@ class FemtoUniversePairCleaner template bool isCleanPair(Part const& part1, Part const& part2, Parts const& particles) { - if constexpr (mPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kTrack) { + if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kTrack) { /// Track-Track combination if (part1.partType() != o2::aod::femtouniverseparticle::ParticleType::kTrack || part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kTrack) { LOG(fatal) << "FemtoUniversePairCleaner: passed arguments don't agree with FemtoUniversePairCleaner instantiation! Please provide kTrack,kTrack candidates."; return false; } return part1.globalIndex() != part2.globalIndex(); - } else if constexpr (mPartOneType == o2::aod::femtouniverseparticle::ParticleType::kMCTruthTrack && mPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kMCTruthTrack) { + } else if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kMCTruthTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kMCTruthTrack) { /// Track-Track combination if (part1.partType() != o2::aod::femtouniverseparticle::ParticleType::kMCTruthTrack || part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kMCTruthTrack) { LOG(fatal) << "FemtoUniversePairCleaner: passed arguments don't agree with FemtoUniversePairCleaner instantiation! Please provide kMCTruthTrack,kMCTruthTrack candidates."; return false; } return part1.globalIndex() != part2.globalIndex(); - } else if constexpr (mPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kV0) { + } else if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kV0) { /// Track-V0 combination part1 is hadron and part2 is v0 if (part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kV0) { LOG(fatal) << "FemtoUniversePairCleaner: passed arguments don't agree with FemtoUniversePairCleaner instantiation! Please provide second argument kV0 candidate."; @@ -84,7 +83,7 @@ class FemtoUniversePairCleaner return false; } return part1.globalIndex() != part2.globalIndex(); - } else if constexpr (mPartOneType == o2::aod::femtouniverseparticle::ParticleType::kV0 && mPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kV0) { + } else if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kV0 && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kV0) { /// V0-V0 combination both part1 and part2 are v0 if (part1.partType() != o2::aod::femtouniverseparticle::ParticleType::kV0 || part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kV0) { LOG(fatal) << "FemtoUniversePairCleaner: passed arguments don't agree with FemtoUniversePairCleaner instantiation! Please provide first and second arguments kV0 candidate."; @@ -100,7 +99,39 @@ class FemtoUniversePairCleaner return false; } return part1.globalIndex() != part2.globalIndex(); - } else if constexpr (mPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kD0) { + } else if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kCascade) { + /// Track-Cascade combination part1 is hadron and part2 is cascade + if (part1.partType() != o2::aod::femtouniverseparticle::ParticleType::kTrack || part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kCascade) { + LOG(fatal) << "FemtoUniversePairCleaner: passed arguments don't agree with FemtoUniversePairCleaner instantiation! Please provide first argument kTrack candidate and second argument kCascade candidate."; + return false; + } + // Getting cascade children for part2 + const auto& posChild = particles.iteratorAt(part2.index() - 3); + const auto& negChild = particles.iteratorAt(part2.index() - 2); + const auto& bachelor = particles.iteratorAt(part2.index() - 1); + if (part1.globalIndex() == posChild.globalIndex() || part1.globalIndex() == negChild.globalIndex() || part1.globalIndex() == bachelor.globalIndex()) { + return false; + } + return part1.globalIndex() != part2.globalIndex(); + } else if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kCascade && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kCascade) { + /// Cascade-Cascade combination both part1 and part2 are cascades + if (part1.partType() != o2::aod::femtouniverseparticle::ParticleType::kCascade || part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kCascade) { + LOG(fatal) << "FemtoUniversePairCleaner: passed arguments don't agree with FemtoUniversePairCleaner instantiation! Please provide first and second arguments kCascade candidate."; + return false; + } + // Getting cascade children for part1 + const auto& posChild1 = particles.iteratorAt(part1.index() - 3); + const auto& negChild1 = particles.iteratorAt(part1.index() - 2); + const auto& bachelor1 = particles.iteratorAt(part1.index() - 1); + // Getting cascade children for part2 + const auto& posChild2 = particles.iteratorAt(part2.index() - 3); + const auto& negChild2 = particles.iteratorAt(part2.index() - 2); + const auto& bachelor2 = particles.iteratorAt(part2.index() - 1); + if (posChild1.globalIndex() == posChild2.globalIndex() || negChild1.globalIndex() == negChild2.globalIndex() || bachelor1.globalIndex() == bachelor2.globalIndex()) { + return false; + } + return part1.globalIndex() != part2.globalIndex(); + } else if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kD0) { /// Track-D0 combination part1 is hadron and part2 is D0 if (part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kD0) { LOG(fatal) << "FemtoUniversePairCleaner: passed arguments don't agree with FemtoUniversePairCleaner instantiation! Please provide second argument kD0 candidate."; @@ -109,11 +140,12 @@ class FemtoUniversePairCleaner // Getting D0 (part2) children const auto& posChild = particles.iteratorAt(part2.index() - 2); const auto& negChild = particles.iteratorAt(part2.index() - 1); - if (part1.globalIndex() == posChild.globalIndex() || part1.globalIndex() == negChild.globalIndex()) { - return false; + + if (part1.globalIndex() != posChild.globalIndex() && part1.globalIndex() != negChild.globalIndex()) { + return true; } - return part1.globalIndex() != part2.globalIndex(); - } else if constexpr (mPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kPhi) { + return false; + } else if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kPhi) { /// Track-Phi combination part1 is Phi and part 2 is hadron if (part1.partType() != o2::aod::femtouniverseparticle::ParticleType::kTrack || part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kPhi) { LOG(fatal) << "FemtoUniversePairCleaner: passed arguments don't agree with FemtoUniversePairCleaner instantiation! Please provide second argument kPhi candidate."; @@ -136,9 +168,9 @@ class FemtoUniversePairCleaner private: HistogramRegistry* mHistogramRegistry; ///< For QA output - static constexpr o2::aod::femtouniverseparticle::ParticleType mPartOneType = partOne; ///< Type of particle 1 - static constexpr o2::aod::femtouniverseparticle::ParticleType mPartTwoType = partTwo; ///< Type of particle 2 + static constexpr o2::aod::femtouniverseparticle::ParticleType kPartOneType = partOne; ///< Type of particle 1 + static constexpr o2::aod::femtouniverseparticle::ParticleType kPartTwoType = partTwo; ///< Type of particle 2 }; -} // namespace o2::analysis::femtoUniverse +} // namespace o2::analysis::femto_universe #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPAIRCLEANER_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniversePairSHCentMultKt.h b/PWGCF/FemtoUniverse/Core/FemtoUniversePairSHCentMultKt.h new file mode 100644 index 00000000000..404fb540745 --- /dev/null +++ b/PWGCF/FemtoUniverse/Core/FemtoUniversePairSHCentMultKt.h @@ -0,0 +1,392 @@ +// Copyright 2019-2022 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 FemtoUniversePairSHCentMultKt.h +/// \brief FemtoUniversePairSHCentMultKt - Spherical Harmonics in mult, kT bins +/// \author Pritam Chakraborty, WUT, pritam.chakraborty@cern.ch + +#ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPAIRSHCENTMULTKT_H_ +#define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPAIRSHCENTMULTKT_H_ + +#include +#include +#include +#include +#include "Framework/HistogramRegistry.h" + +// using namespace o2::constants::physics; + +namespace o2::analysis::femto_universe +{ + +/// \class FemtoUniversePairSHCentMultKt +/// \brief Container for all histogramming related to the spherical harmonics of +/// the correlation function. The two particles of the pair are passed here, and +/// the correlation function are filled according to the specified observable +/// \tparam eventType Type of the event (same/mixed) +/// \tparam obs Observable to be computed (k*/Q_inv/...) +template +class PairSHCentMultKt +{ + public: + virtual ~PairSHCentMultKt() = default; + /// @brief + /// \tparam t1 + /// \param registry Histogram registry to be passed + /// \param kstarbins Binning of k* + /// \param centmultbins Number of multiplicity bins + /// \param ktbins Number of kT bins + /// \param maxl Maximum valie of L component of the spherical harmonics + template + void init(HistogramRegistry* registry, t1& kstarbins, t1& centmultbins, + t1& ktbins, int /*maxl*/) + { + pairSHCentMultKtRegistry = registry; + AxisSpec kstarAxis = {kstarbins, "#it{k*} (GeV/#it{c})"}; + kStarBins = kstarbins; + + centMultBins = centmultbins; + ktBins = ktbins; + ktBins.erase(ktBins.begin()); + centMultBins.erase(centMultBins.begin()); + + std::string femtoObs1D; + + std::vector fels(kMaxJM); + std::vector fems(kMaxJM); + std::vector felsi(kMaxJM); + std::vector femsi(kMaxJM); + + // Fill in els and ems table + int el = 0; + int em = 0; + int il = 0; + do { + + fels[il] = el; + fems[il] = em; + felsi[il] = static_cast(el); + femsi[il] = static_cast(em); + em++; + il++; + if (em > el) { + el++; + em = -el; + } + } while (el <= kMaxL); + + femtoObs1D = "#it{q} (GeV/#it{c})"; + + framework::AxisSpec femtoObsAxis1D = {kstarbins, femtoObs1D.c_str()}; + + for (int i = 0; i < static_cast(centMultBins.size() - 1); i++) { + int lowBin = static_cast((centMultBins[i])); + int highBin = static_cast((centMultBins[i + 1])); + + std::string histTitle = "mult_" + std::to_string(lowBin) + "-" + std::to_string(highBin); + std::string histSuffix1 = std::to_string(static_cast(centMultBins[i])); + std::string histSuffix2 = std::to_string(static_cast(centMultBins[i + 1])); + std::string histFolderMult = "mult_" + histSuffix1 + "_" + histSuffix2; + + for (int j = 0; j < static_cast(ktBins.size() - 1); j++) { + int ktlowBin = static_cast(ktBins[j]); + int kthighBin = static_cast(ktBins[j + 1]); + + std::string histTitlekT = "kT_" + std::to_string(ktlowBin) + "-" + std::to_string(kthighBin); + std::string histSuffixkT1 = std::to_string(static_cast(ktBins[j] * 100.0)); + std::string histSuffixkT2 = std::to_string(static_cast(ktBins[j + 1] * 100.0)); + std::string histFolderkT = "kT_" + histSuffixkT1 + "_" + histSuffixkT2; + + std::string suffix; + fbinctn[i][j] = new TH1D(TString("BinCountNum"), "Bin Occupation (Numerator)", static_cast(kStarBins[0]), kStarBins[1], kStarBins[2]); + fbinctd[i][j] = new TH1D(TString("BinCountDen"), "Bin Occupation (Denominator)", static_cast(kStarBins[0]), kStarBins[1], kStarBins[2]); + + for (int ihist = 0; ihist < kMaxJM; ihist++) { + if (femsi[ihist] < 0) { + suffix = "Ylm" + std::to_string(felsi[ihist]) + + std::to_string(felsi[ihist] - femsi[ihist]); + } else { + suffix = "Ylm" + std::to_string(felsi[ihist]) + std::to_string(femsi[ihist]); + } + // std::cout<<"ihist "<add( + (histFolderMult + "/" + histFolderkT + "/" + "NumRe" + suffix).c_str(), + ("; " + femtoObs1D + "; Entries").c_str(), kTH1D, {femtoObsAxis1D}); + fnumsimag[i][j][ihist] = pairSHCentMultKtRegistry->add( + (histFolderMult + "/" + histFolderkT + "/" + "NumIm" + suffix).c_str(), + ("; " + femtoObs1D + "; Entries").c_str(), kTH1D, {femtoObsAxis1D}); + } else { + fdensreal[i][j][ihist] = pairSHCentMultKtRegistry->add( + (histFolderMult + "/" + histFolderkT + "/" + "DenRe" + suffix).c_str(), + ("; " + femtoObs1D + "; Entries").c_str(), kTH1D, {femtoObsAxis1D}); + fdensimag[i][j][ihist] = pairSHCentMultKtRegistry->add( + (histFolderMult + "/" + histFolderkT + "/" + "DenIm" + suffix).c_str(), + ("; " + femtoObs1D + "; Entries").c_str(), kTH1D, {femtoObsAxis1D}); + } + } + + if (FolderSuffix[EventType] == FolderSuffix[0]) { + std::string bufnameNum = "CovNum"; + fcovnum[i][j] = pairSHCentMultKtRegistry->add((histFolderMult + "/" + histFolderkT + "/" + bufnameNum).c_str(), "; x; y; z", kTH3D, + {{kstarbins}, + {(kMaxJM * 2), -0.5, ((static_cast(kMaxJM) * 2.0 - 0.5))}, + {(kMaxJM * 2), -0.5, + ((static_cast(kMaxJM) * 2.0 - 0.5))}}); + fcovnum[i][j]->Sumw2(); + } else if (FolderSuffix[EventType] == FolderSuffix[1]) { + std::string bufnameDen = "CovDen"; + fcovden[i][j] = pairSHCentMultKtRegistry->add((histFolderMult + "/" + histFolderkT + "/" + bufnameDen).c_str(), "; x; y; z", kTH3D, + {{kstarbins}, + {(kMaxJM * 2), -0.5, ((static_cast(kMaxJM) * 2.0 - 0.5))}, + {(kMaxJM * 2), -0.5, + ((static_cast(kMaxJM) * 2.0 - 0.5))}}); + } + } + } + } + + /// Templated function to access different multiplicity directory and call + /// fillkTNumDen \param part1 particle 1 \param part2 particle 2 \param + /// ChosenEventType Same or Mixed evet type \param maxl Maximum valie of L + /// component of the spherical harmonics \param multval Multiplicity value + /// \param ktval kT value + template + void fillMultNumDen(T const& part1, T const& part2, uint8_t ChosenEventType, + int maxl, int multval, float ktval, bool isiden) + { + int multbinval; + int absmultval = multval; + + if ((absmultval >= centMultBins[0]) && (absmultval < centMultBins[1])) { + multbinval = 0; + } else if ((absmultval >= centMultBins[1]) && (absmultval < centMultBins[2])) { + multbinval = 1; + } else if ((absmultval >= centMultBins[2]) && (absmultval < centMultBins[3])) { + multbinval = 2; + } else if ((absmultval >= centMultBins[3]) && (absmultval < centMultBins[4])) { + multbinval = 3; + } else { + return; + } + // std::cout<<"multbinval "< + void fillkTNumDen(T const& part1, T const& part2, uint8_t ChosenEventType, + int maxl, int multval, float ktval, bool isiden) + { + int ktbinval = -1; + if (ktval >= ktBins[0] && ktval < ktBins[1]) { + ktbinval = 0; + } else if (ktval >= ktBins[1] && ktval < ktBins[2]) { + ktbinval = 1; + } else if (ktval >= ktBins[2] && ktval < ktBins[3]) { + ktbinval = 2; + } else if (ktval >= ktBins[3] && ktval < ktBins[4]) { + ktbinval = 3; + } else if (ktval >= ktBins[4] && ktval < ktBins[5]) { + ktbinval = 4; + } else if (ktval >= ktBins[5] && ktval < ktBins[6]) { + ktbinval = 5; + } else if (ktval >= ktBins[6] && ktval < ktBins[7]) { + ktbinval = 6; + } else { + return; + } + addEventPair(part1, part2, ChosenEventType, maxl, multval, ktbinval, isiden); + } + + /// Set the PDG codes of the two particles involved + /// \param pdg1 PDG code of particle one + /// \param pdg2 PDG code of particle two + void setPionPairMass() + { + mMassOne = o2::constants::physics::MassPiPlus; // FIXME: Get from the PDG service of the common header + mMassTwo = o2::constants::physics::MassPiPlus; // FIXME: Get from the PDG service of the common header + } + + /// To compute the bin value for cavariance matrix + /// \param qbin value of the qth k* bin + /// \param ilmzero + /// \param zeroimag + /// \param ilmprim + /// \param primimag + int getBin(int qbin, int ilmzero, int zeroimag, int ilmprim, int primimag) + { + return qbin * kMaxJM * kMaxJM * 4 + (ilmprim * 2 + primimag) * kMaxJM * 2 + + ilmzero * 2 + zeroimag; + } + + /// Templated function to compute the necessary observables and fill the + /// histograms for respective Spherical Harmonic \tparam T type of the + /// femtouniverseparticle \param part1 Particle one \param part2 Particle two + /// \param ChosenEventType Same or Mixed evet type + /// \param maxl Maximum valie of L component of the spherical harmonics + /// \param multval Multiplicity value + /// \param ktval kT value + template + void addEventPair(T const& part1, T const& part2, uint8_t ChosenEventType, + int /*maxl*/, int multval, int ktval, bool isiden) + { + int fMultBin = multval; + int fKtBin = ktval; + std::vector> fYlmBuffer(kMaxJM); + std::vector f3d; + setPionPairMass(); + f3d = FemtoUniverseMath::newpairfunc(part1, mMassOne, part2, mMassTwo, + isiden); + + const float qout = f3d[1]; + const float qside = f3d[2]; + const float qlong = f3d[3]; + + double kv = std::sqrt(qout * qout + qside * qside + qlong * qlong); + + // int nqbin = fbinctn[0][0]->GetXaxis()->FindFixBin(kv); + // int nqbinnotfix = fbinctn[0][0]->GetXaxis()->FindBin(kv); + + FemtoUniverseSpherHarMath kYlm; + kYlm.doYlmUpToL(kMaxL, qout, qside, qlong, fYlmBuffer.data()); + + if (ChosenEventType == femto_universe_sh_container::EventType::same) { + for (int ihist = 0; ihist < kMaxJM; ihist++) { + fnumsreal[fMultBin][fKtBin][ihist]->Fill(kv, real(fYlmBuffer[ihist])); + fnumsimag[fMultBin][fKtBin][ihist]->Fill(kv, -imag(fYlmBuffer[ihist])); + fbinctn[fMultBin][fKtBin]->Fill(kv, 1.0); + } + for (int ilmzero = 0; ilmzero < kMaxJM * 2; ilmzero++) { + for (int ilmprim = 0; ilmprim < kMaxJM * 2; ilmprim++) { + if ((ilmzero % 2) == 0 && (ilmprim % 2) == 0) { + fcovnum[fMultBin][fKtBin]->Fill(kv, ilmzero, ilmprim, (real(fYlmBuffer[ilmzero / 2]) * real(fYlmBuffer[ilmprim / 2]))); + } else if ((ilmzero % 2) == 0 && (ilmprim % 2) == 1) { + fcovnum[fMultBin][fKtBin]->Fill(kv, ilmzero, ilmprim, (real(fYlmBuffer[ilmzero / 2]) * -imag(fYlmBuffer[ilmprim / 2]))); + } else if ((ilmzero % 2) == 1 && (ilmprim % 2) == 0) { + fcovnum[fMultBin][fKtBin]->Fill(kv, ilmzero, ilmprim, (-imag(fYlmBuffer[ilmzero / 2]) * real(fYlmBuffer[ilmprim / 2]))); + } else if ((ilmzero % 2) == 1 && (ilmprim % 2) == 1) { + fcovnum[fMultBin][fKtBin]->Fill(kv, ilmzero, ilmprim, (-imag(fYlmBuffer[ilmzero / 2]) * -imag(fYlmBuffer[ilmprim / 2]))); + } + } + } + } else if (ChosenEventType == femto_universe_sh_container::EventType::mixed) { + for (int ihist = 0; ihist < kMaxJM; ihist++) { + fdensreal[fMultBin][fKtBin][ihist]->Fill(kv, real(fYlmBuffer[ihist])); + fdensimag[fMultBin][fKtBin][ihist]->Fill(kv, -imag(fYlmBuffer[ihist])); + fbinctd[fMultBin][fKtBin]->Fill(kv, 1.0); + } + for (int ilmzero = 0; ilmzero < kMaxJM * 2; ilmzero++) { + for (int ilmprim = 0; ilmprim < kMaxJM * 2; ilmprim++) { + if ((ilmzero % 2) == 0 && (ilmprim % 2) == 0) { + fcovden[fMultBin][fKtBin]->Fill(kv, ilmzero, ilmprim, (real(fYlmBuffer[ilmzero / 2]) * real(fYlmBuffer[ilmprim / 2]))); + } else if ((ilmzero % 2) == 0 && (ilmprim % 2) == 1) { + fcovden[fMultBin][fKtBin]->Fill(kv, ilmzero, ilmprim, (real(fYlmBuffer[ilmzero / 2]) * -imag(fYlmBuffer[ilmprim / 2]))); + } else if ((ilmzero % 2) == 1 && (ilmprim % 2) == 0) { + fcovden[fMultBin][fKtBin]->Fill(kv, ilmzero, ilmprim, (-imag(fYlmBuffer[ilmzero / 2]) * real(fYlmBuffer[ilmprim / 2]))); + } else if ((ilmzero % 2) == 1 && (ilmprim % 2) == 1) { + fcovden[fMultBin][fKtBin]->Fill(kv, ilmzero, ilmprim, (-imag(fYlmBuffer[ilmzero / 2]) * -imag(fYlmBuffer[ilmprim / 2]))); + } + } + } + } + } + + /// Function to fill covariance matrix in 3D histograms + /// \param ChosenEventType same or mixed event + /// \param MaxJM Maximum value of J + /// \param multval Multiplicity value + /// \param ktval kT value + void packCov(uint8_t ChosenEventType, int /*MaxJM*/, int multval, int ktval) + { + int fMultBin = multval; + int fKtBin = ktval; + if (ChosenEventType == femto_universe_sh_container::EventType::same) { + for (int ibin = 1; ibin <= fcovnum[0][0]->GetNbinsX(); ibin++) { + for (int ilmz = 0; ilmz < kMaxJM * 2; ilmz++) { + for (int ilmp = 0; ilmp < kMaxJM * 2; ilmp++) { + auto bin = getBin(ibin - 1, ilmz / 2, ilmz % 2, ilmp / 2, ilmp % 2); + auto value = fcovmnum[fMultBin][fKtBin][bin]; + fcovnum[fMultBin][fKtBin]->SetBinContent(ibin, ilmz + 1, ilmp + 1, value); + } + } + } + } else if (ChosenEventType == femto_universe_sh_container::EventType::mixed) { + for (int ibin = 1; ibin <= fcovden[0][0]->GetNbinsX(); ibin++) { + for (int ilmz = 0; ilmz < kMaxJM * 2; ilmz++) { + for (int ilmp = 0; ilmp < kMaxJM * 2; ilmp++) { + auto bin = getBin(ibin - 1, ilmz / 2, ilmz % 2, ilmp / 2, ilmp % 2); + auto value = fcovmden[fMultBin][fKtBin][bin]; + fcovden[fMultBin][fKtBin]->SetBinContent(ibin, ilmz + 1, ilmp + 1, value); + } + } + } + } + } + + /// Function to acces each multiplicity and kT directory and call packCov + /// \param ChosenEventType same or mixed event + /// \param MaxJM Maximum value of J + void fillMultkTCov(uint8_t ChosenEventType, int MaxJM) + { + for (int multbinvalcov = 0; + multbinvalcov < static_cast(centMultBins.size() - 1); + multbinvalcov++) { + for (int ktbinvalcov = 0; + ktbinvalcov < static_cast(ktBins.size() - 1); ktbinvalcov++) { + packCov(ChosenEventType, MaxJM, multbinvalcov, ktbinvalcov); + } + } + } + + private: + std::array, 10>, 7>, 4> fnumsreal{}; + std::array, 10>, 7>, 4> fnumsimag{}; + std::array, 10>, 7>, 4> fdensreal{}; + std::array, 10>, 7>, 4> fdensimag{}; + + TH1D* fbinctn[10][10]; + TH1D* fbinctd[10][10]; + + static constexpr int kMaxL = 2; + static constexpr int kMaxJM = (kMaxL + 1) * (kMaxL + 1); + + std::array, 7>, 4> fcovmnum{}; ///< Covariance matrix for the numerator + std::array, 7>, 4> fcovmden{}; ///< Covariance matrix for the numerator + + std::array, 7>, 4> fcovnum{}; + std::array, 7>, 4> fcovden{}; + + protected: + HistogramRegistry* pairSHCentMultKtRegistry = nullptr; + static constexpr std::string_view FolderSuffix[2] = {"SameEvent", "MixedEvent"}; ///< Folder naming for the output according to EventType + static constexpr int EventType = eventType; ///< Type of the event (same/mixed, according to FEMTOUNIVERSESHCONTAINER::EventType) + float mMassOne = 0.f; ///< PDG mass of particle 1 + float mMassTwo = 0.f; ///< PDG mass of particle 2 + int mPDGOne = 0; ///< PDG code of particle 1 + int mPDGTwo = 0; ///< PDG code of particle 2 + std::vector centMultBins; + std::vector ktBins; + std::vector kStarBins; + bool useKt = false; + bool use3D = false; +}; + +} // namespace o2::analysis::femto_universe + +#endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPAIRSHCENTMULTKT_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniversePairWithCentMultKt.h b/PWGCF/FemtoUniverse/Core/FemtoUniversePairWithCentMultKt.h index 01b82ae3b3b..5cfef9c433f 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniversePairWithCentMultKt.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniversePairWithCentMultKt.h @@ -8,26 +8,25 @@ // 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 FemtoUniversePairWithCentMultKt.h +/// \brief FemtoUniversePairWithCentMultKt - Histogram class for tracks with centrality and multiplicity /// \author Deependra Sharma, IITB, deependra.sharma@cern.ch /// \author Alicja Płachta, WUT Warsaw, alicja.plachta.stud@pw.edu.pl +/// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPAIRWITHCENTMULTKT_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPAIRWITHCENTMULTKT_H_ #include -#include #include #include "Framework/HistogramRegistry.h" -using namespace o2; -using namespace o2::framework; - -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { -class PairWithCentMultKt +class FemtoUniversePairWithCentMultKt { public: - virtual ~PairWithCentMultKt() = default; + virtual ~FemtoUniversePairWithCentMultKt() = default; /// @brief /// @tparam t1 /// @param registry @@ -36,65 +35,65 @@ class PairWithCentMultKt template void init(HistogramRegistry* registry, t1& kstarbins, t1& centmultbins, t1& ktbins, bool processKT, bool process3D) { - PairWithCentMultKtRegistry = registry; + pairWithCentMultKtRegistry = registry; AxisSpec kstarAxis = {kstarbins, "#it{k*} (GeV/#it{c})"}; AxisSpec kOutAxis = {kstarbins, "#it{q}_{out} (GeV/#it{c})"}; AxisSpec kSideAxis = {kstarbins, "#it{q}_{side} (GeV/#it{c})"}; AxisSpec kLongAxis = {kstarbins, "#it{q}_{long} (GeV/#it{c})"}; - CentMultBins = centmultbins; - KtBins = ktbins; - KtBins.erase(KtBins.begin()); - CentMultBins.erase(CentMultBins.begin()); - UseKt = processKT; - Use3D = process3D; + centMultBins = centmultbins; + ktBins = ktbins; + ktBins.erase(ktBins.begin()); + centMultBins.erase(centMultBins.begin()); + useKt = processKT; + use3D = process3D; - for (int i = 0; i < static_cast(CentMultBins.size() - 1); i++) { - int lowBin = static_cast((CentMultBins[i])); - int highBin = static_cast((CentMultBins[i + 1])); - std::string HistTitle = "mult_" + std::to_string(lowBin) + "-" + std::to_string(highBin); - std::string HistSuffix1 = static_cast(HistSuffix[i]); - std::string HistSuffix2 = static_cast(HistSuffix[i + 1]); - std::cout << "HistSuffix1 " << HistSuffix1 << " HistSuffix2 " << HistSuffix2 << std::endl; - std::string HistFolderMult = "mult_" + HistSuffix1 + "_" + HistSuffix2; - std::string HistName = HistFolderMult + "/kstar"; - std::string HistName3D = HistFolderMult + "/q3D"; - PairWithCentMultKtRegistry->add(HistName.c_str(), HistTitle.c_str(), HistType::kTH1F, {kstarAxis}); - PairWithCentMultKtRegistry->add(HistName3D.c_str(), HistTitle.c_str(), HistType::kTH3F, {kOutAxis, kSideAxis, kLongAxis}); - if (UseKt) { - for (int i = 0; i < static_cast(KtBins.size() - 1); i++) { - std::string kt_bin1_string = std::to_string(KtBins[i]); - std::replace(kt_bin1_string.begin(), kt_bin1_string.end(), '.', '_'); - std::string kt_bin2_string = std::to_string(KtBins[i + 1]); - std::replace(kt_bin2_string.begin(), kt_bin2_string.end(), '.', '_'); - kt_bin1_string.resize(4); - kt_bin2_string.resize(4); - std::string HistTitleKt = "kt_" + kt_bin1_string + "-" + kt_bin2_string; - std::string HistSuffix1Kt = static_cast(HistSuffix[i]); - std::string HistSuffix2Kt = static_cast(HistSuffix[i + 1]); - std::string HistNameKt = HistFolderMult + "/kstar_kt_" + HistSuffix1Kt + "_" + HistSuffix2Kt; - std::cout << "HistNameKt " << HistNameKt << std::endl; - PairWithCentMultKtRegistry->add(HistNameKt.c_str(), HistTitleKt.c_str(), HistType::kTH1F, {kstarAxis}); + for (int i = 0; i < static_cast(centMultBins.size() - 1); i++) { + int lowBin = static_cast((centMultBins[i])); + int highBin = static_cast((centMultBins[i + 1])); + std::string histTitle = "mult_" + std::to_string(lowBin) + "-" + std::to_string(highBin); + std::string histSuffix1 = static_cast(HistSuffix[i]); + std::string histSuffix2 = static_cast(HistSuffix[i + 1]); + LOGF(info, "histSuffix1 %s histSuffix2", histSuffix1, histSuffix2); + std::string histFolderMult = "mult_" + histSuffix1 + "_" + histSuffix2; + std::string histName = histFolderMult + "/kstar"; + std::string histName3D = histFolderMult + "/q3D"; + pairWithCentMultKtRegistry->add(histName.c_str(), histTitle.c_str(), HistType::kTH1F, {kstarAxis}); + pairWithCentMultKtRegistry->add(histName3D.c_str(), histTitle.c_str(), HistType::kTH3F, {kOutAxis, kSideAxis, kLongAxis}); + if (useKt) { + for (int i = 0; i < static_cast(ktBins.size() - 1); i++) { + std::string ktBin1String = std::to_string(ktBins[i]); + std::replace(ktBin1String.begin(), ktBin1String.end(), '.', '_'); + std::string ktBin2String = std::to_string(ktBins[i + 1]); + std::replace(ktBin2String.begin(), ktBin2String.end(), '.', '_'); + ktBin1String.resize(4); + ktBin2String.resize(4); + std::string histTitleKt = "kt_" + ktBin1String + "-" + ktBin2String; + std::string histSuffix1Kt = static_cast(HistSuffix[i]); + std::string histSuffix2Kt = static_cast(HistSuffix[i + 1]); + std::string histNameKt = histFolderMult + "/kstar_kt_" + histSuffix1Kt + "_" + histSuffix2Kt; + LOGF(info, "histNameKt %s", histNameKt); + pairWithCentMultKtRegistry->add(histNameKt.c_str(), histTitleKt.c_str(), HistType::kTH1F, {kstarAxis}); } } - if (Use3D) { - for (int i = 0; i < static_cast(KtBins.size() - 1); i++) { - std::string kt_bin1_string = std::to_string(KtBins[i]); - std::replace(kt_bin1_string.begin(), kt_bin1_string.end(), '.', '_'); - std::string kt_bin2_string = std::to_string(KtBins[i + 1]); - std::replace(kt_bin2_string.begin(), kt_bin2_string.end(), '.', '_'); - kt_bin1_string.resize(4); - kt_bin2_string.resize(4); - std::string HistTitleKt = "kt_" + kt_bin1_string + "-" + kt_bin2_string; - std::string HistSuffix1Kt = static_cast(HistSuffix[i]); - std::string HistSuffix2Kt = static_cast(HistSuffix[i + 1]); - std::string HistNameKt = HistFolderMult + "/q3D_kt_" + HistSuffix1Kt + "_" + HistSuffix2Kt; - std::cout << "HistNameKt " << HistNameKt << std::endl; - PairWithCentMultKtRegistry->add(HistNameKt.c_str(), HistTitleKt.c_str(), HistType::kTH3F, {kOutAxis, kSideAxis, kLongAxis}); + if (use3D) { + for (int i = 0; i < static_cast(ktBins.size() - 1); i++) { + std::string ktBin1String = std::to_string(ktBins[i]); + std::replace(ktBin1String.begin(), ktBin1String.end(), '.', '_'); + std::string ktBin2String = std::to_string(ktBins[i + 1]); + std::replace(ktBin2String.begin(), ktBin2String.end(), '.', '_'); + ktBin1String.resize(4); + ktBin2String.resize(4); + std::string histTitleKt = "kt_" + ktBin1String + "-" + ktBin2String; + std::string histSuffix1Kt = static_cast(HistSuffix[i]); + std::string histSuffix2Kt = static_cast(HistSuffix[i + 1]); + std::string histNameKt = histFolderMult + "/q3D_kt_" + histSuffix1Kt + "_" + histSuffix2Kt; + LOGF(info, "histNameKt %s", histNameKt); + pairWithCentMultKtRegistry->add(histNameKt.c_str(), histTitleKt.c_str(), HistType::kTH3F, {kOutAxis, kSideAxis, kLongAxis}); } } } - PairWithCentMultKtRegistry->add("Beyond_Max", "Beyond_Max", HistType::kTH1F, {kstarAxis}); - PairWithCentMultKtRegistry->add("Beyond_Max_3D", "Beyond_Max_3D", HistType::kTH3F, {kOutAxis, kSideAxis, kLongAxis}); + pairWithCentMultKtRegistry->add("Beyond_Max", "Beyond_Max", HistType::kTH1F, {kstarAxis}); + pairWithCentMultKtRegistry->add("Beyond_Max_3D", "Beyond_Max_3D", HistType::kTH3F, {kOutAxis, kSideAxis, kLongAxis}); } /// @brief @@ -105,61 +104,61 @@ class PairWithCentMultKt void fill(t1 kstar_value, t1 cent_mult_value, t1 kt_value) { - if (cent_mult_value > CentMultBins[CentMultBins.size() - 1] || cent_mult_value < CentMultBins[0]) { - PairWithCentMultKtRegistry->fill(HIST("Beyond_Max"), kstar_value); - } else if (cent_mult_value <= CentMultBins[1]) { - PairWithCentMultKtRegistry->fill(HIST("mult_0_1/kstar"), kstar_value); - if (UseKt) { + if (cent_mult_value >= centMultBins[centMultBins.size() - 1] || cent_mult_value < centMultBins[0]) { + pairWithCentMultKtRegistry->fill(HIST("Beyond_Max"), kstar_value); + } else if (cent_mult_value >= centMultBins[0] && cent_mult_value < centMultBins[1]) { + pairWithCentMultKtRegistry->fill(HIST("mult_0_1/kstar"), kstar_value); + if (useKt) { auto histMultFolder = HIST("mult_0_1/"); - fill_kT(kstar_value, kt_value, histMultFolder); + fillkT(kstar_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[2]) { - PairWithCentMultKtRegistry->fill(HIST("mult_1_2/kstar"), kstar_value); - if (UseKt) { + } else if (cent_mult_value >= centMultBins[1] && cent_mult_value < centMultBins[2]) { + pairWithCentMultKtRegistry->fill(HIST("mult_1_2/kstar"), kstar_value); + if (useKt) { auto histMultFolder = HIST("mult_1_2/"); - fill_kT(kstar_value, kt_value, histMultFolder); + fillkT(kstar_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[3]) { - PairWithCentMultKtRegistry->fill(HIST("mult_2_3/kstar"), kstar_value); - if (UseKt) { + } else if (cent_mult_value >= centMultBins[2] && cent_mult_value < centMultBins[3]) { + pairWithCentMultKtRegistry->fill(HIST("mult_2_3/kstar"), kstar_value); + if (useKt) { auto histMultFolder = HIST("mult_2_3/"); - fill_kT(kstar_value, kt_value, histMultFolder); + fillkT(kstar_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[4]) { - PairWithCentMultKtRegistry->fill(HIST("mult_3_4/kstar"), kstar_value); - if (UseKt) { + } else if (cent_mult_value >= centMultBins[3] && cent_mult_value < centMultBins[4]) { + pairWithCentMultKtRegistry->fill(HIST("mult_3_4/kstar"), kstar_value); + if (useKt) { auto histMultFolder = HIST("mult_3_4/"); - fill_kT(kstar_value, kt_value, histMultFolder); + fillkT(kstar_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[5]) { - PairWithCentMultKtRegistry->fill(HIST("mult_4_5/kstar"), kstar_value); - if (UseKt) { + } else if (cent_mult_value >= centMultBins[4] && cent_mult_value < centMultBins[5]) { + pairWithCentMultKtRegistry->fill(HIST("mult_4_5/kstar"), kstar_value); + if (useKt) { auto histMultFolder = HIST("mult_4_5/"); - fill_kT(kstar_value, kt_value, histMultFolder); + fillkT(kstar_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[6]) { - PairWithCentMultKtRegistry->fill(HIST("mult_5_6/kstar"), kstar_value); - if (UseKt) { + } else if (cent_mult_value >= centMultBins[5] && cent_mult_value < centMultBins[6]) { + pairWithCentMultKtRegistry->fill(HIST("mult_5_6/kstar"), kstar_value); + if (useKt) { auto histMultFolder = HIST("mult_5_6/"); - fill_kT(kstar_value, kt_value, histMultFolder); + fillkT(kstar_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[7]) { - PairWithCentMultKtRegistry->fill(HIST("mult_6_7/kstar"), kstar_value); - if (UseKt) { + } else if (cent_mult_value >= centMultBins[6] && cent_mult_value < centMultBins[7]) { + pairWithCentMultKtRegistry->fill(HIST("mult_6_7/kstar"), kstar_value); + if (useKt) { auto histMultFolder = HIST("mult_6_7/"); - fill_kT(kstar_value, kt_value, histMultFolder); + fillkT(kstar_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[8]) { - PairWithCentMultKtRegistry->fill(HIST("mult_7_8/kstar"), kstar_value); - if (UseKt) { + } else if (cent_mult_value >= centMultBins[7] && cent_mult_value < centMultBins[8]) { + pairWithCentMultKtRegistry->fill(HIST("mult_7_8/kstar"), kstar_value); + if (useKt) { auto histMultFolder = HIST("mult_7_8/"); - fill_kT(kstar_value, kt_value, histMultFolder); + fillkT(kstar_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[9]) { - PairWithCentMultKtRegistry->fill(HIST("mult_8_9/kstar"), kstar_value); - if (UseKt) { + } else if (cent_mult_value >= centMultBins[8] && cent_mult_value < centMultBins[9]) { + pairWithCentMultKtRegistry->fill(HIST("mult_8_9/kstar"), kstar_value); + if (useKt) { auto histMultFolder = HIST("mult_8_9/"); - fill_kT(kstar_value, kt_value, histMultFolder); + fillkT(kstar_value, kt_value, histMultFolder); } } } @@ -171,26 +170,26 @@ class PairWithCentMultKt /// @param kt_value /// @param folder template - void fill_kT(t1 kstar_value, t1 kt_value, t2 folder) + void fillkT(t1 kstar_value, t1 kt_value, t2 folder) { - if (kt_value <= KtBins[1]) { - PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_0_1"), kstar_value); - } else if (kt_value <= KtBins[2]) { - PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_1_2"), kstar_value); - } else if (kt_value <= KtBins[3]) { - PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_2_3"), kstar_value); - } else if (kt_value <= KtBins[4]) { - PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_3_4"), kstar_value); - } else if (kt_value <= KtBins[5]) { - PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_4_5"), kstar_value); - } else if (kt_value <= KtBins[6]) { - PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_5_6"), kstar_value); - } else if (kt_value <= KtBins[7]) { - PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_6_7"), kstar_value); - } else if (kt_value <= KtBins[8]) { - PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_7_8"), kstar_value); - } else if (kt_value <= KtBins[9]) { - PairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_8_9"), kstar_value); + if (kt_value >= ktBins[0] && kt_value < ktBins[1]) { + pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_0_1"), kstar_value); + } else if (kt_value >= ktBins[1] && kt_value < ktBins[2]) { + pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_1_2"), kstar_value); + } else if (kt_value >= ktBins[2] && kt_value < ktBins[3]) { + pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_2_3"), kstar_value); + } else if (kt_value >= ktBins[3] && kt_value < ktBins[4]) { + pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_3_4"), kstar_value); + } else if (kt_value >= ktBins[4] && kt_value < ktBins[5]) { + pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_4_5"), kstar_value); + } else if (kt_value >= ktBins[5] && kt_value < ktBins[6]) { + pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_5_6"), kstar_value); + } else if (kt_value >= ktBins[6] && kt_value < ktBins[7]) { + pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_6_7"), kstar_value); + } else if (kt_value >= ktBins[7] && kt_value < ktBins[8]) { + pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_7_8"), kstar_value); + } else if (kt_value >= ktBins[8] && kt_value < ktBins[9]) { + pairWithCentMultKtRegistry->fill(folder + HIST("kstar_kt_8_9"), kstar_value); } } @@ -201,64 +200,64 @@ class PairWithCentMultKt /// @param qlong_value /// @param cent_mult_value template - void fill_3D(t1 qout_value, t1 qside_value, t1 qlong_value, t1 cent_mult_value, t1 kt_value) + void fill3D(t1 qout_value, t1 qside_value, t1 qlong_value, t1 cent_mult_value, t1 kt_value) { - if (cent_mult_value > CentMultBins[CentMultBins.size() - 1] || cent_mult_value < CentMultBins[0]) { - PairWithCentMultKtRegistry->fill(HIST("Beyond_Max_3D"), qout_value, qside_value, qlong_value); - } else if (cent_mult_value <= CentMultBins[1]) { - PairWithCentMultKtRegistry->fill(HIST("mult_0_1/q3D"), qout_value, qside_value, qlong_value); - if (Use3D) { + if (cent_mult_value >= centMultBins[centMultBins.size() - 1] || cent_mult_value < centMultBins[0]) { + pairWithCentMultKtRegistry->fill(HIST("Beyond_Max_3D"), qout_value, qside_value, qlong_value); + } else if (cent_mult_value >= centMultBins[0] && cent_mult_value < centMultBins[1]) { + pairWithCentMultKtRegistry->fill(HIST("mult_0_1/q3D"), qout_value, qside_value, qlong_value); + if (use3D) { auto histMultFolder = HIST("mult_0_1/"); - fill_kT_3d(qout_value, qside_value, qlong_value, kt_value, histMultFolder); + fillkT3D(qout_value, qside_value, qlong_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[2]) { - // PairWithCentMultKtRegistry->fill(HIST("mult_1_2/q3D"), qout_value, qside_value, qlong_value); - if (Use3D) { + } else if (cent_mult_value >= centMultBins[1] && cent_mult_value < centMultBins[2]) { + // pairWithCentMultKtRegistry->fill(HIST("mult_1_2/q3D"), qout_value, qside_value, qlong_value); + if (use3D) { auto histMultFolder = HIST("mult_1_2/"); - fill_kT_3d(qout_value, qside_value, qlong_value, kt_value, histMultFolder); + fillkT3D(qout_value, qside_value, qlong_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[3]) { - // PairWithCentMultKtRegistry->fill(HIST("mult_2_3/q3D"), qout_value, qside_value, qlong_value); - if (Use3D) { + } else if (cent_mult_value >= centMultBins[2] && cent_mult_value < centMultBins[3]) { + // pairWithCentMultKtRegistry->fill(HIST("mult_2_3/q3D"), qout_value, qside_value, qlong_value); + if (use3D) { auto histMultFolder = HIST("mult_2_3/"); - fill_kT_3d(qout_value, qside_value, qlong_value, kt_value, histMultFolder); + fillkT3D(qout_value, qside_value, qlong_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[4]) { - // PairWithCentMultKtRegistry->fill(HIST("mult_3_4/q3D"), qout_value, qside_value, qlong_value); - if (Use3D) { + } else if (cent_mult_value >= centMultBins[3] && cent_mult_value < centMultBins[4]) { + // pairWithCentMultKtRegistry->fill(HIST("mult_3_4/q3D"), qout_value, qside_value, qlong_value); + if (use3D) { auto histMultFolder = HIST("mult_3_4/"); - fill_kT_3d(qout_value, qside_value, qlong_value, kt_value, histMultFolder); + fillkT3D(qout_value, qside_value, qlong_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[5]) { - // PairWithCentMultKtRegistry->fill(HIST("mult_4_5/q3D"), qout_value, qside_value, qlong_value); - if (Use3D) { + } else if (cent_mult_value >= centMultBins[4] && cent_mult_value < centMultBins[5]) { + // pairWithCentMultKtRegistry->fill(HIST("mult_4_5/q3D"), qout_value, qside_value, qlong_value); + if (use3D) { auto histMultFolder = HIST("mult_4_5/"); - fill_kT_3d(qout_value, qside_value, qlong_value, kt_value, histMultFolder); + fillkT3D(qout_value, qside_value, qlong_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[6]) { - // PairWithCentMultKtRegistry->fill(HIST("mult_5_6/q3D"), qout_value, qside_value, qlong_value); - if (Use3D) { + } else if (cent_mult_value >= centMultBins[5] && cent_mult_value < centMultBins[6]) { + // pairWithCentMultKtRegistry->fill(HIST("mult_5_6/q3D"), qout_value, qside_value, qlong_value); + if (use3D) { auto histMultFolder = HIST("mult_5_6/"); - fill_kT_3d(qout_value, qside_value, qlong_value, kt_value, histMultFolder); + fillkT3D(qout_value, qside_value, qlong_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[7]) { - // PairWithCentMultKtRegistry->fill(HIST("mult_6_7/q3D"), qout_value, qside_value, qlong_value); - if (Use3D) { + } else if (cent_mult_value >= centMultBins[6] && cent_mult_value < centMultBins[7]) { + // pairWithCentMultKtRegistry->fill(HIST("mult_6_7/q3D"), qout_value, qside_value, qlong_value); + if (use3D) { auto histMultFolder = HIST("mult_6_7/"); - fill_kT_3d(qout_value, qside_value, qlong_value, kt_value, histMultFolder); + fillkT3D(qout_value, qside_value, qlong_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[8]) { - // PairWithCentMultKtRegistry->fill(HIST("mult_7_8/q3D"), qout_value, qside_value, qlong_value); - if (Use3D) { + } else if (cent_mult_value >= centMultBins[7] && cent_mult_value < centMultBins[8]) { + // pairWithCentMultKtRegistry->fill(HIST("mult_7_8/q3D"), qout_value, qside_value, qlong_value); + if (use3D) { auto histMultFolder = HIST("mult_7_8/"); - fill_kT_3d(qout_value, qside_value, qlong_value, kt_value, histMultFolder); + fillkT3D(qout_value, qside_value, qlong_value, kt_value, histMultFolder); } - } else if (cent_mult_value <= CentMultBins[9]) { - // PairWithCentMultKtRegistry->fill(HIST("mult_8_9/q3D"), qout_value, qside_value, qlong_value); - if (Use3D) { + } else if (cent_mult_value >= centMultBins[8] && cent_mult_value < centMultBins[9]) { + // pairWithCentMultKtRegistry->fill(HIST("mult_8_9/q3D"), qout_value, qside_value, qlong_value); + if (use3D) { auto histMultFolder = HIST("mult_8_9/"); - fill_kT_3d(qout_value, qside_value, qlong_value, kt_value, histMultFolder); + fillkT3D(qout_value, qside_value, qlong_value, kt_value, histMultFolder); } } } @@ -271,25 +270,31 @@ class PairWithCentMultKt /// @param qlong_value /// @param folder template - void fill_kT_3d(t1 qout_value, t1 qside_value, t1 qlong_value, t1 kt_value, t2 folder) + void fillkT3D(t1 qout_value, t1 qside_value, t1 qlong_value, t1 kt_value, t2 folder) { - if (kt_value <= KtBins[1]) { - PairWithCentMultKtRegistry->fill(folder + HIST("q3D_kt_0_1"), qout_value, qside_value, qlong_value); - } else if (kt_value <= KtBins[2]) { - PairWithCentMultKtRegistry->fill(folder + HIST("q3D_kt_1_2"), qout_value, qside_value, qlong_value); - } else if (kt_value <= KtBins[3]) { - PairWithCentMultKtRegistry->fill(folder + HIST("q3D_kt_2_3"), qout_value, qside_value, qlong_value); + if (kt_value >= ktBins[0] && kt_value < ktBins[1]) { + pairWithCentMultKtRegistry->fill(folder + HIST("q3D_kt_0_1"), qout_value, qside_value, qlong_value); + } else if (kt_value >= ktBins[1] && kt_value < ktBins[2]) { + pairWithCentMultKtRegistry->fill(folder + HIST("q3D_kt_1_2"), qout_value, qside_value, qlong_value); + } else if (kt_value >= ktBins[2] && kt_value < ktBins[3]) { + pairWithCentMultKtRegistry->fill(folder + HIST("q3D_kt_2_3"), qout_value, qside_value, qlong_value); + } else if (kt_value >= ktBins[3] && kt_value < ktBins[4]) { + pairWithCentMultKtRegistry->fill(folder + HIST("q3D_kt_3_4"), qout_value, qside_value, qlong_value); + } else if (kt_value >= ktBins[4] && kt_value < ktBins[5]) { + pairWithCentMultKtRegistry->fill(folder + HIST("q3D_kt_4_5"), qout_value, qside_value, qlong_value); + } else if (kt_value >= ktBins[5] && kt_value < ktBins[6]) { + pairWithCentMultKtRegistry->fill(folder + HIST("q3D_kt_5_6"), qout_value, qside_value, qlong_value); } } protected: - HistogramRegistry* PairWithCentMultKtRegistry = nullptr; - std::vector CentMultBins; - std::vector KtBins; - bool UseKt = false; - bool Use3D = false; + HistogramRegistry* pairWithCentMultKtRegistry = nullptr; + std::vector centMultBins; + std::vector ktBins; + bool useKt = false; + bool use3D = false; static constexpr std::string_view HistSuffix[10] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; }; -} // namespace o2::analysis::femtoUniverse +} // namespace o2::analysis::femto_universe #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPAIRWITHCENTMULTKT_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h index 9a5070a22e6..668fd84714b 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h @@ -24,10 +24,11 @@ #include #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" #include "Framework/HistogramRegistry.h" +#include "CommonConstants/MathConstants.h" -using namespace o2::framework; +using namespace o2::framework; // o2-linter: disable=using-directive -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe // o2-linter: disable=name/namespace { /// \class FemtoUniverseParticleHisto @@ -49,28 +50,28 @@ class FemtoUniverseParticleHisto /// \param tempFitVarAxisTitle Title of the axis of the tempFitVar (DCA_xy in case of tracks, CPA in case of V0s, etc.) /// \param tempFitVarpTAxis axis object for the pT axis in the pT vs. tempFitVar plots /// \param tempFitVarAxis axis object for the tempFitVar axis - template - void init_base(std::string folderName, std::string tempFitVarAxisTitle, T& tempFitVarpTAxis, T& tempFitVarAxis) + template + void init_base(std::string folderName, std::string tempFitVarAxisTitle, T& tempFitVarpTAxis, T& tempFitVarAxis) // o2-linter: disable=name/function-variable { - std::string folderSuffix = static_cast(o2::aod::femtouniverseMCparticle::MCTypeName[mc]).c_str(); + std::string folderSuffix = static_cast(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]).c_str(); /// Histograms of the kinematic properties - mHistogramRegistry->add((folderName + folderSuffix + "/hPt").c_str(), "; #it{p}_{T} (GeV/#it{c}); Entries", kTH1F, {{240, 0, 6}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hPt").c_str(), "; #it{p}_{T} (GeV/#it{c}); Entries", kTH1F, {tempFitVarpTAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/hEta").c_str(), "; #eta; Entries", kTH1F, {{200, -1.5, 1.5}}); - mHistogramRegistry->add((folderName + folderSuffix + "/hPhi").c_str(), "; #phi; Entries", kTH1F, {{200, 0, 2. * M_PI}}); - mHistogramRegistry->add((folderName + folderSuffix + "/hPhiEta").c_str(), "; #phi; #eta", kTH2F, {{200, 0, 2. * M_PI}, {200, -1.5, 1.5}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hPhi").c_str(), "; #phi; Entries", kTH1F, {{200, 0, o2::constants::math::TwoPI}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hPhiEta").c_str(), "; #phi; #eta", kTH2F, {{200, 0, o2::constants::math::TwoPI}, {200, -1.5, 1.5}}); /// particle specific histogramms for the TempFitVar column in FemtoUniverseParticles - if constexpr (o2::aod::femtouniverseMCparticle::MCType::kRecon == mc) { + if constexpr (o2::aod::femtouniverse_mc_particle::MCType::kRecon == mc) { mHistogramRegistry->add((folderName + folderSuffix + static_cast(o2::aod::femtouniverseparticle::TempFitVarName[mParticleType])).c_str(), ("; #it{p}_{T} (GeV/#it{c}); " + tempFitVarAxisTitle).c_str(), kTH2F, {{tempFitVarpTAxis}, {tempFitVarAxis}}); } } // comment - template - void init_debug(std::string folderName) + template + void init_debug(std::string folderName) // o2-linter: disable=name/function-variable { - std::string folderSuffix = static_cast(o2::aod::femtouniverseMCparticle::MCTypeName[mc]).c_str(); - if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kTrack || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kV0Child || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kMCTruthTrack) { + std::string folderSuffix = static_cast(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]).c_str(); + if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kTrack || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kV0Child || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kCascadeBachelor || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kMCTruthTrack) { mHistogramRegistry->add((folderName + folderSuffix + "/hCharge").c_str(), "; Charge; Entries", kTH1F, {{5, -2.5, 2.5}}); mHistogramRegistry->add((folderName + folderSuffix + "/hTPCfindable").c_str(), "; TPC findable clusters; Entries", kTH1F, {{163, -0.5, 162.5}}); mHistogramRegistry->add((folderName + folderSuffix + "/hTPCfound").c_str(), "; TPC found clusters; Entries", kTH1F, {{163, -0.5, 162.5}}); @@ -78,21 +79,22 @@ class FemtoUniverseParticleHisto mHistogramRegistry->add((folderName + folderSuffix + "/hTPCcrossedRows").c_str(), "; TPC crossed rows; Entries", kTH1F, {{163, -0.5, 162.5}}); mHistogramRegistry->add((folderName + folderSuffix + "/hTPCfindableVsCrossed").c_str(), ";TPC findable clusters ; TPC crossed rows;", kTH2F, {{163, -0.5, 162.5}, {163, -0.5, 162.5}}); mHistogramRegistry->add((folderName + folderSuffix + "/hTPCshared").c_str(), "; TPC shared clusters; Entries", kTH1F, {{163, -0.5, 162.5}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hTPCfractionSharedCls").c_str(), "; TPC fraction of shared clusters; Entries", kTH1F, {{100, 0.0, 100.0}}); mHistogramRegistry->add((folderName + folderSuffix + "/hITSclusters").c_str(), "; ITS clusters; Entries", kTH1F, {{10, -0.5, 9.5}}); mHistogramRegistry->add((folderName + folderSuffix + "/hITSclustersIB").c_str(), "; ITS clusters in IB; Entries", kTH1F, {{10, -0.5, 9.5}}); mHistogramRegistry->add((folderName + folderSuffix + "/hDCAz").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{z} (cm)", kTH2F, {{100, 0, 10}, {500, -5, 5}}); mHistogramRegistry->add((folderName + folderSuffix + "/hDCA").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA (cm)", kTH2F, {{100, 0, 10}, {301, 0., 1.5}}); mHistogramRegistry->add((folderName + folderSuffix + "/hTPCdEdX").c_str(), "; #it{p} (GeV/#it{c}); TPC Signal", kTH2F, {{100, 0, 10}, {1000, 0, 1000}}); - mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_el").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{e}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_pi").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{#pi}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_K").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{K}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_p").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{p}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_d").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{d}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_el").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{e}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_pi").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{#pi}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_K").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{K}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_p").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{p}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_d").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{d}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_el").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{e}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_pi").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{#pi}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_K").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{K}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_p").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{p}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_d").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{d}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_el").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{e}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_pi").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{#pi}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_K").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{K}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_p").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{p}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_d").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{d}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaComb_el").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{e}", kTH2F, {{100, 0, 10}, {100, 0, 5}}); mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaComb_pi").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{#pi}", kTH2F, {{100, 0, 10}, {100, 0, 5}}); mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaComb_K").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{K}", kTH2F, {{100, 0, 10}, {100, 0, 5}}); @@ -105,8 +107,18 @@ class FemtoUniverseParticleHisto mHistogramRegistry->add((folderName + folderSuffix + "/hDecayVtxY").c_str(), "; #it{Vtx}_{y} (cm)); Entries", kTH1F, {{2000, 0, 200}}); mHistogramRegistry->add((folderName + folderSuffix + "/hDecayVtxZ").c_str(), "; #it{Vtx}_{z} (cm); Entries", kTH1F, {{2000, 0, 200}}); mHistogramRegistry->add((folderName + folderSuffix + "/hInvMassLambda").c_str(), "; M_{#Lambda}; Entries", kTH1F, {{2000, 1.f, 3.f}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hInvMassLambdaVsPt").c_str(), "; #it{p}_{T} (GeV/#it{c}); M_{#Lambda}; Entries", kTH2F, {{240, 0, 6}, {2000, 1.f, 3.f}}); mHistogramRegistry->add((folderName + folderSuffix + "/hInvMassAntiLambda").c_str(), "; M_{#bar{#Lambda}}; Entries", kTH1F, {{2000, 1.f, 3.f}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hInvMassAntiLambdaVsPt").c_str(), "; #it{p}_{T} (GeV/#it{c}); M_{#Lambda}; Entries", kTH2F, {{240, 0, 6}, {2000, 1.f, 3.f}}); mHistogramRegistry->add((folderName + folderSuffix + "/hInvMassLambdaAntiLambda").c_str(), "; M_{#Lambda}; M_{#bar{#Lambda}}", kTH2F, {{2000, 1.f, 3.f}, {2000, 1.f, 3.f}}); + } else if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kCascade) { + mHistogramRegistry->add((folderName + folderSuffix + "/hDaughDCA").c_str(), "; DCA^{daugh} (cm); Entries", kTH1F, {{1000, 0, 10}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hTransRadius").c_str(), "; #it{r}_{xy} (cm); Entries", kTH1F, {{1500, 0, 150}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hDecayVtxX").c_str(), "; #it{Vtx}_{x} (cm); Entries", kTH1F, {{2000, 0, 200}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hDecayVtxY").c_str(), "; #it{Vtx}_{y} (cm)); Entries", kTH1F, {{2000, 0, 200}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hDecayVtxZ").c_str(), "; #it{Vtx}_{z} (cm); Entries", kTH1F, {{2000, 0, 200}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hInvMassCascade").c_str(), "; M_{Cascade}; Entries", kTH1F, {{2000, 1.f, 1.8f}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hInvMassAntiCascade").c_str(), "; M_{AntiCascade}; Entries", kTH1F, {{2000, 1.f, 1.8f}}); } } @@ -118,17 +130,18 @@ class FemtoUniverseParticleHisto /// \param tempFitVarpTAxis axis object for the pT axis in the pT vs. tempFitVar plots /// \param tempFitVarAxis axis object for the tempFitVar axis template - void init_MC(std::string folderName, std::string /*tempFitVarAxisTitle*/, T& tempFitVarpTAxis, T& tempFitVarAxis) + void init_MC(std::string folderName, std::string /*tempFitVarAxisTitle*/, T& tempFitVarpTAxis, T& tempFitVarAxis) // o2-linter: disable=name/function-variable { /// Particle-type specific histograms - std::string folderSuffix = static_cast(o2::aod::femtouniverseMCparticle::MCTypeName[o2::aod::femtouniverseMCparticle::MCType::kTruth]).c_str(); + std::string folderSuffix = static_cast(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kTruth]).c_str(); - mHistogramRegistry->add((folderName + folderSuffix + "/hPt_ReconNoFake").c_str(), "; #it{p}_{T} (GeV/#it{c}); Entries", kTH1F, {{240, 0, 6}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hPt_ReconNoFake").c_str(), "; #it{p}_{T} (GeV/#it{c}); Entries", kTH1F, {tempFitVarpTAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hPt_Primary").c_str(), "; #it{p}_{T} (GeV/#it{c}); Entries", kTH1F, {tempFitVarpTAxis}); - if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kTrack || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kV0Child || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kMCTruthTrack) { + if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kTrack || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kV0Child || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kCascadeBachelor || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kMCTruthTrack) { /// Track histograms mHistogramRegistry->add((folderName + folderSuffix + "/hPDG").c_str(), "; PDG; Entries", kTH1I, {{6001, -3000, 3000}}); - mHistogramRegistry->add((folderName + folderSuffix + "/hOrigin_MC").c_str(), "; Origin; Entries", kTH1I, {{7, 0, 7}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hOrigin_MC").c_str(), "; Origin; Entries", kTH1I, {{100, 0, 100}}); mHistogramRegistry->add((folderName + folderSuffix + "/hNoMCtruthCounter").c_str(), "; Counter; Entries", kTH1I, {{1, 0, 1}}); // DCA plots mHistogramRegistry->add((folderName + folderSuffix + "/hDCAxy_Material").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); @@ -137,6 +150,8 @@ class FemtoUniverseParticleHisto mHistogramRegistry->add((folderName + folderSuffix + "/hDCAxy_DaughterSigmaplus").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/hDCAxy_Primary").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); mHistogramRegistry->add((folderName + folderSuffix + "/hDCAxy_Daughter").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hDCAxy_NoMCTruthOrigin").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hMisidentification").c_str(), "; #it{p}_{T} (GeV/#it{c}); Particle; Particle", kTH3F, {{4, 0, 4}, {4, 0, 4}, tempFitVarpTAxis}); } else if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kV0) { /// V0 histograms /// to be implemented @@ -145,6 +160,9 @@ class FemtoUniverseParticleHisto /// to be implemented } else if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kPhi) { // Phi histograms + mHistogramRegistry->add((folderName + folderSuffix + "/hPDG").c_str(), "; PDG; Entries", kTH1I, {{6001, -3000, 3000}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hOrigin_MC").c_str(), "; Origin; Entries", kTH1I, {{7, 0, 7}}); + } else if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kD0) { // D0/D0bar histograms } else { @@ -168,7 +186,7 @@ class FemtoUniverseParticleHisto mHistogramRegistry = registry; /// The folder names are defined by the type of the object and the suffix (if applicable) std::string tempFitVarAxisTitle; - if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kTrack || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kV0Child) { + if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kTrack || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kV0Child || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kCascadeBachelor) { /// Track histograms tempFitVarAxisTitle = "DCA_{xy} (cm)"; } else if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kMCTruthTrack) { @@ -197,12 +215,12 @@ class FemtoUniverseParticleHisto std::string folderName = flexibleFolder.value_or((static_cast(o2::aod::femtouniverseparticle::ParticleTypeName[mParticleType]) + static_cast(mFolderSuffix[mFolderSuffixType]))); // Fill here the actual histogramms by calling init_base and init_MC - init_base(folderName, tempFitVarAxisTitle, tempFitVarpTAxis, tempFitVarAxis); + init_base(folderName, tempFitVarAxisTitle, tempFitVarpTAxis, tempFitVarAxis); if (isDebug) { - init_debug(folderName); + init_debug(folderName); } if (isMC) { - init_base(folderName, tempFitVarAxisTitle, tempFitVarpTAxis, tempFitVarAxis); + init_base(folderName, tempFitVarAxisTitle, tempFitVarpTAxis, tempFitVarAxis); init_MC(folderName, tempFitVarAxisTitle, tempFitVarpTAxis, tempFitVarAxis); } } @@ -212,62 +230,73 @@ class FemtoUniverseParticleHisto /// Called by init both in case of reconstructed data/ Monte Carlo, and for Monte Carlo Truth /// \tparam T Data type of the particle /// \param part Particle - template - void fillQA_base(T const& part, H const& histFolder) + template + void fillQA_base(T const& part, H const& histFolder) // o2-linter: disable=name/function-variable { /// Histograms of the kinematic properties - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hPt"), part.pt()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hEta"), part.eta()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hPhi"), part.phi()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hPhiEta"), part.phi(), part.eta()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hPt"), part.pt()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hEta"), part.eta()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hPhi"), part.phi()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hPhiEta"), part.phi(), part.eta()); /// particle specific histogramms for the TempFitVar column in FemtoUniverseParticles - if constexpr (mc == o2::aod::femtouniverseMCparticle::MCType::kRecon) { - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST(o2::aod::femtouniverseparticle::TempFitVarName[mParticleType]), part.pt(), part.tempFitVar()); + if constexpr (mc == o2::aod::femtouniverse_mc_particle::MCType::kRecon) { + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST(o2::aod::femtouniverseparticle::TempFitVarName[mParticleType]), part.pt(), part.tempFitVar()); } } - template - void fillQA_debug(T const& part, H const& histFolder) + template + void fillQA_debug(T const& part, H const& histFolder) // o2-linter: disable=name/function-variable { // Histograms holding further debug information - if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kTrack || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kV0Child || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kMCTruthTrack) { - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hCharge"), part.sign()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hTPCfindable"), part.tpcNClsFindable()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hTPCfound"), part.tpcNClsFound()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hTPCcrossedOverFindable"), part.tpcCrossedRowsOverFindableCls()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hTPCcrossedRows"), part.tpcNClsCrossedRows()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hTPCfindableVsCrossed"), part.tpcNClsFindable(), part.tpcNClsCrossedRows()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hTPCshared"), part.tpcNClsShared()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hITSclusters"), part.itsNCls()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hITSclustersIB"), part.itsNClsInnerBarrel()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hDCAz"), part.pt(), part.dcaZ()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hDCA"), part.pt(), std::sqrt(std::pow(part.dcaXY(), 2.) + std::pow(part.dcaZ(), 2.))); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hTPCdEdX"), part.p(), part.tpcSignal()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/nSigmaTPC_el"), part.p(), part.tpcNSigmaEl()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/nSigmaTPC_pi"), part.p(), part.tpcNSigmaPi()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/nSigmaTPC_K"), part.p(), part.tpcNSigmaKa()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/nSigmaTPC_p"), part.p(), part.tpcNSigmaPr()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/nSigmaTPC_d"), part.p(), part.tpcNSigmaDe()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/nSigmaTOF_el"), part.p(), part.tofNSigmaEl()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/nSigmaTOF_pi"), part.p(), part.tofNSigmaPi()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/nSigmaTOF_K"), part.p(), part.tofNSigmaKa()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/nSigmaTOF_p"), part.p(), part.tofNSigmaPr()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/nSigmaTOF_d"), part.p(), part.tofNSigmaDe()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/nSigmaComb_el"), part.p(), std::sqrt(part.tpcNSigmaEl() * part.tpcNSigmaEl() + part.tofNSigmaEl() * part.tofNSigmaEl())); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/nSigmaComb_pi"), part.p(), std::sqrt(part.tpcNSigmaPi() * part.tpcNSigmaPi() + part.tofNSigmaPi() * part.tofNSigmaPi())); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/nSigmaComb_K"), part.p(), std::sqrt(part.tpcNSigmaKa() * part.tpcNSigmaKa() + part.tofNSigmaKa() * part.tofNSigmaKa())); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/nSigmaComb_p"), part.p(), std::sqrt(part.tpcNSigmaPr() * part.tpcNSigmaPr() + part.tofNSigmaPr() * part.tofNSigmaPr())); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/nSigmaComb_d"), part.p(), std::sqrt(part.tpcNSigmaDe() * part.tpcNSigmaDe() + part.tofNSigmaDe() * part.tofNSigmaDe())); + if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kTrack || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kV0Child || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kCascadeBachelor || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kMCTruthTrack) { + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hCharge"), part.sign()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hTPCfindable"), part.tpcNClsFindable()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hTPCfound"), part.tpcNClsFound()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hTPCcrossedOverFindable"), part.tpcCrossedRowsOverFindableCls()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hTPCcrossedRows"), part.tpcNClsCrossedRows()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hTPCfindableVsCrossed"), part.tpcNClsFindable(), part.tpcNClsCrossedRows()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hTPCshared"), part.tpcNClsShared()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hTPCfractionSharedCls"), part.tpcFractionSharedCls()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hITSclusters"), part.itsNCls()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hITSclustersIB"), part.itsNClsInnerBarrel()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hDCAz"), part.pt(), part.dcaZ()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hDCA"), part.pt(), std::sqrt(std::pow(part.dcaXY(), 2.) + std::pow(part.dcaZ(), 2.))); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hTPCdEdX"), part.p(), part.tpcSignal()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/nSigmaTPC_el"), part.p(), part.tpcNSigmaEl()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/nSigmaTPC_pi"), part.p(), part.tpcNSigmaPi()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/nSigmaTPC_K"), part.p(), part.tpcNSigmaKa()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/nSigmaTPC_p"), part.p(), part.tpcNSigmaPr()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/nSigmaTPC_d"), part.p(), part.tpcNSigmaDe()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/nSigmaTOF_el"), part.p(), part.tofNSigmaEl()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/nSigmaTOF_pi"), part.p(), part.tofNSigmaPi()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/nSigmaTOF_K"), part.p(), part.tofNSigmaKa()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/nSigmaTOF_p"), part.p(), part.tofNSigmaPr()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/nSigmaTOF_d"), part.p(), part.tofNSigmaDe()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/nSigmaComb_el"), part.p(), std::sqrt(part.tpcNSigmaEl() * part.tpcNSigmaEl() + part.tofNSigmaEl() * part.tofNSigmaEl())); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/nSigmaComb_pi"), part.p(), std::sqrt(part.tpcNSigmaPi() * part.tpcNSigmaPi() + part.tofNSigmaPi() * part.tofNSigmaPi())); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/nSigmaComb_K"), part.p(), std::sqrt(part.tpcNSigmaKa() * part.tpcNSigmaKa() + part.tofNSigmaKa() * part.tofNSigmaKa())); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/nSigmaComb_p"), part.p(), std::sqrt(part.tpcNSigmaPr() * part.tpcNSigmaPr() + part.tofNSigmaPr() * part.tofNSigmaPr())); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/nSigmaComb_d"), part.p(), std::sqrt(part.tpcNSigmaDe() * part.tpcNSigmaDe() + part.tofNSigmaDe() * part.tofNSigmaDe())); } else if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kV0) { - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hDaughDCA"), part.daughDCA()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hTransRadius"), part.transRadius()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hDecayVtxX"), part.decayVtxX()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hDecayVtxY"), part.decayVtxY()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hDecayVtxZ"), part.decayVtxZ()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hInvMassLambda"), part.mLambda()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hInvMassAntiLambda"), part.mAntiLambda()); - mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverseMCparticle::MCTypeName[mc]) + HIST("/hInvMassLambdaAntiLambda"), part.mLambda(), part.mAntiLambda()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hDaughDCA"), part.daughDCA()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hTransRadius"), part.transRadius()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hDecayVtxX"), part.decayVtxX()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hDecayVtxY"), part.decayVtxY()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hDecayVtxZ"), part.decayVtxZ()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hInvMassLambda"), part.mLambda()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hInvMassLambdaVsPt"), part.pt(), part.mLambda()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hInvMassAntiLambda"), part.mAntiLambda()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hInvMassAntiLambdaVsPt"), part.pt(), part.mAntiLambda()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hInvMassLambdaAntiLambda"), part.mLambda(), part.mAntiLambda()); + } else if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kCascade) { + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hDaughDCA"), part.daughDCA()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hTransRadius"), part.transRadius()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hDecayVtxX"), part.decayVtxX()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hDecayVtxY"), part.decayVtxY()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hDecayVtxZ"), part.decayVtxZ()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hInvMassCascade"), part.mLambda()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hInvMassAntiCascade"), part.mAntiLambda()); } } @@ -279,43 +308,51 @@ class FemtoUniverseParticleHisto /// \param mctruthorigin Origin of the associated mc Truth particle /// \param pdgcode PDG of the associated mc Truth particle associated to the reconstructed particle part template - void fillQA_MC(T const& part, int mctruthorigin, int pdgcode, H const& histFolder) + void fillQA_MC(T const& part, int mctruthorigin, int pdgcode, H const& histFolder) // o2-linter: disable=name/function-variable { if (mHistogramRegistry) { mHistogramRegistry->fill(histFolder + HIST("_MC/hPDG"), pdgcode); mHistogramRegistry->fill(histFolder + HIST("_MC/hOrigin_MC"), mctruthorigin); - if (abs(pdgcode) == mPDG) { // fill this histogramm only for TRUE protons (independently of their origin) for the track purity estimation + if (std::abs(pdgcode) == mPDG) { // fill this histogramm only for TRUE protons (independently of their origin) for the track purity estimation mHistogramRegistry->fill(histFolder + HIST("_MC/hPt_ReconNoFake"), part.pt()); } - if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kTrack || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kV0Child || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kMCTruthTrack) { + if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kTrack || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kV0Child || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kCascadeBachelor || mParticleType == o2::aod::femtouniverseparticle::ParticleType::kMCTruthTrack) { /// Track histograms switch (mctruthorigin) { - case (o2::aod::femtouniverseMCparticle::kPrimary): + case (o2::aod::femtouniverse_mc_particle::kPrimary): { + if (pdgcode == mPDG) { + mHistogramRegistry->fill(histFolder + HIST("_MC/hPt_Primary"), part.pt()); + } mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Primary"), part.pt(), part.tempFitVar()); break; - case (o2::aod::femtouniverseMCparticle::kDaughter): + } + case (o2::aod::femtouniverse_mc_particle::kDaughter): mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Daughter"), part.pt(), part.tempFitVar()); break; - case (o2::aod::femtouniverseMCparticle::kMaterial): + case (o2::aod::femtouniverse_mc_particle::kMaterial): mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Material"), part.pt(), part.tempFitVar()); break; - case (o2::aod::femtouniverseMCparticle::kFake): + case (o2::aod::femtouniverse_mc_particle::kFake): mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Fake"), part.pt(), part.tempFitVar()); break; - case (o2::aod::femtouniverseMCparticle::kDaughterLambda): + case (o2::aod::femtouniverse_mc_particle::kDaughterLambda): mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_DaughterLambda"), part.pt(), part.tempFitVar()); break; - case (o2::aod::femtouniverseMCparticle::kDaughterSigmaplus): + case (o2::aod::femtouniverse_mc_particle::kDaughterSigmaplus): mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_DaughterSigmaplus"), part.pt(), part.tempFitVar()); break; + case (99): + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_NoMCTruthOrigin"), + part.pt(), part.tempFitVar()); + break; default: LOG(fatal) << "femtouniverseparticleMC: not known value for ParticleOriginMCTruth - please check. Quitting!"; } @@ -333,6 +370,39 @@ class FemtoUniverseParticleHisto } } + template + void fillQA_MC_MisIden(T const& part, int pdgcode, int confPDG, H const& histFolder) // o2-linter: disable=name/function-variable + { + if (mHistogramRegistry) { + if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kTrack) { + if (confPDG == mConfPDGCodePart[0]) { + binPDG = 0; + } else if (confPDG == mConfPDGCodePart[1]) { + binPDG = 1; + } else if (confPDG == mConfPDGCodePart[2]) { + binPDG = 2; // o2-linter: disable=pdg/explicit-code + } else { + binPDG = 3; // o2-linter: disable=pdg/explicit-code + } + if (std::abs(pdgcode) == 211) { + mHistogramRegistry->fill(histFolder + HIST("_MC/hMisidentification"), + binPDG, 0, part.pt()); + } else if (std::abs(pdgcode) == 321) { + mHistogramRegistry->fill(histFolder + HIST("_MC/hMisidentification"), + binPDG, 1, part.pt()); + } else if (std::abs(pdgcode) == 2212) { + mHistogramRegistry->fill(histFolder + HIST("_MC/hMisidentification"), + binPDG, 2, part.pt()); + } else { + mHistogramRegistry->fill(histFolder + HIST("_MC/hMisidentification"), + binPDG, 3, part.pt()); + } + } + } else { + LOG(fatal) << "FemtoUniverseParticleHisto: Histogramming for requested object not defined - quitting!"; + } + } + /// Templated function to fill particle histograms for data/ Monte Carlo reconstructed and Monte Carlo truth /// Always calls fillQA_base fill histogramms with data/ Monte Carlo reconstructed /// In case of Monte Carlo, calls fillQA_base with Monte Carlo truth info and specialized function fillQA_MC for additional histogramms @@ -348,16 +418,15 @@ class FemtoUniverseParticleHisto template void fillQABase(T const& part, H const& histFolder) { - fillQA_base(part, histFolder); std::string tempFitVarName; if (mHistogramRegistry) { - fillQA_base(part, histFolder); + fillQA_base(part, histFolder); if constexpr (isDebug) { - fillQA_debug(part, histFolder); + fillQA_debug(part, histFolder); } if constexpr (isMC) { if (part.has_fdMCParticle()) { - fillQA_base(part.fdMCParticle(), histFolder); + fillQA_base(part.fdMCParticle(), histFolder); fillQA_MC(part, (part.fdMCParticle()).partOriginMCTruth(), (part.fdMCParticle()).pdgMCTruth(), histFolder); } else { mHistogramRegistry->fill(histFolder + HIST("_MC/hNoMCtruthCounter"), 0); @@ -366,13 +435,40 @@ class FemtoUniverseParticleHisto } } + /// Templated function to fill particle histograms for data/ Monte Carlo reconstructed and Monte Carlo truth + /// Always calls fillQA_base fill histogramms with data/ Monte Carlo reconstructed + /// In case of Monte Carlo, calls fillQA_base with Monte Carlo truth info and specialized function fillQA_MC for additional histogramms + /// \tparam T particle type + /// \tparam isMC fills the additional histograms for Monte Carlo truth + /// \param part particle for which the histograms should be filled + template + void fillQAMisIden(T const& part, int confPDG) + { + fillQABaseMisiden(part, HIST(o2::aod::femtouniverseparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]), confPDG); + } + + template + void fillQABaseMisiden(T const& part, H const& histFolder, int confPDG) + { + std::string tempFitVarName; + if (mHistogramRegistry) { + if constexpr (isMC) { + if (part.has_fdMCParticle()) { + fillQA_MC_MisIden(part, (part.fdMCParticle()).pdgMCTruth(), confPDG, histFolder); + } + } + } + } + private: HistogramRegistry* mHistogramRegistry; ///< For QA output - static constexpr o2::aod::femtouniverseparticle::ParticleType mParticleType = particleType; ///< Type of the particle under analysis - static constexpr int mFolderSuffixType = suffixType; ///< Counter for the folder suffix specified below - static constexpr std::string_view mFolderSuffix[5] = {"", "_one", "_two", "_pos", "_neg"}; ///< Suffix for the folder name in case of analyses of pairs of the same kind (T-T, V-V, C-C) + static constexpr o2::aod::femtouniverseparticle::ParticleType mParticleType = particleType; ///< Type of the particle under analysis // o2-linter: disable=name/constexpr-constant + static constexpr int mFolderSuffixType = suffixType; ///< Counter for the folder suffix specified below // o2-linter: disable=name/constexpr-constant + static constexpr std::string_view mFolderSuffix[5] = {"", "_one", "_two", "_pos", "_neg"}; ///< Suffix for the folder name in case of analyses of pairs of the same kind (T-T, V-V, C-C) // o2-linter: disable=name/constexpr-constant + int mConfPDGCodePart[4] = {211, 321, 2212, 9999}; ///< PDG code as per analysis int mPDG = 0; ///< PDG code of the selected particle + int binPDG = 0; }; -} // namespace o2::analysis::femtoUniverse +} // namespace o2::analysis::femto_universe #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPARTICLEHISTO_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniversePhiSelection.h b/PWGCF/FemtoUniverse/Core/FemtoUniversePhiSelection.h index d18988be907..80bf1797414 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniversePhiSelection.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniversePhiSelection.h @@ -19,12 +19,9 @@ #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPHISELECTION_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPHISELECTION_H_ -#include #include #include -#include // FIXME - #include "PWGCF/FemtoUniverse/Core/FemtoUniverseObjectSelection.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseSelection.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" @@ -34,11 +31,9 @@ #include "ReconstructionDataFormats/PID.h" #include "TLorentzVector.h" -using namespace o2::framework; - -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { -namespace femtoUniversePhiSelection +namespace femto_universe_phi_selection { /// The different selections this task is capable of doing enum PhiSel { @@ -62,22 +57,22 @@ enum PhiContainerPosition { kPosPID, kNegCuts, kNegPID, -}; /// Position in the full VO cut container +}; /// Position in the full Phi cut container -} // namespace femtoUniversePhiSelection +} // namespace femto_universe_phi_selection /// \class FemtoUniversePhiSelection /// \brief Cut class to contain and execute all cuts applied to Phis class FemtoUniversePhiSelection - : public FemtoUniverseObjectSelection + : public FemtoUniverseObjectSelection { public: FemtoUniversePhiSelection() - : nPtPhiMinSel(0), nPtPhiMaxSel(0), nEtaPhiMaxSel(0), nDCAPhiDaughMax(0), nCPAPhiMin(0), nTranRadPhiMin(0), nTranRadPhiMax(0), nDecVtxMax(0), pTPhiMin(9999999.), pTPhiMax(-9999999.), etaPhiMax(-9999999.), DCAPhiDaughMax(-9999999.), CPAPhiMin(9999999.), TranRadPhiMin(9999999.), TranRadPhiMax(-9999999.), DecVtxMax(-9999999.), fInvMassLowLimit(1.05), fInvMassUpLimit(1.3), fRejectKaon(false), fInvMassKaonLowLimit(0.48), fInvMassKaonUpLimit(0.515), nSigmaPIDOffsetTPC(0.) {} + : nPtPhiMinSel(0), nPtPhiMaxSel(0), nEtaPhiMaxSel(0), nDCAPhiDaughMax(0), nCPAPhiMin(0), nTranRadPhiMin(0), nTranRadPhiMax(0), nDecVtxMax(0), pTPhiMin(9999999.), pTPhiMax(-9999999.), etaPhiMax(-9999999.), kDCAPhiDaughMax(-9999999.), kCPAPhiMin(9999999.), kTranRadPhiMin(9999999.), kTranRadPhiMax(-9999999.), kDecVtxMax(-9999999.), fInvMassLowLimit(1.05), fInvMassUpLimit(1.3), fRejectKaon(false), fInvMassKaonLowLimit(0.48), fInvMassKaonUpLimit(0.515), nSigmaPIDOffsetTPC(0.) {} /// Initializes histograms for the task template + typename CutContainerType> void init(HistogramRegistry* registry); template @@ -90,8 +85,8 @@ class FemtoUniversePhiSelection /// \todo for the moment the PID of the tracks is factored out into a separate /// field, hence 5 values in total \\ASK: what does it mean? - template - std::array getCutContainer(C const& col, V const& phi, + template + std::array getCutContainer(C const& col, V const& phi, T const& posTrack, T const& negTrack); @@ -101,23 +96,23 @@ class FemtoUniversePhiSelection void fillQA(C const& col, V const& phi, T const& posTrack, T const& negTrack, Q const& posPID, Q const& negPID); template - void setChildCuts(femtoUniversePhiSelection::ChildTrackType child, T1 selVal, - T2 selVar, femtoUniverseSelection::SelectionType selType) + void setChildCuts(femto_universe_phi_selection::ChildTrackType child, T1 selVal, + T2 selVar, femto_universe_selection::SelectionType selType) { - if (child == femtoUniversePhiSelection::kPosTrack) { - PosDaughTrack.setSelection(selVal, selVar, selType); - } else if (child == femtoUniversePhiSelection::kNegTrack) { - NegDaughTrack.setSelection(selVal, selVar, selType); + if (child == femto_universe_phi_selection::kPosTrack) { + posDaughTrack.setSelection(selVal, selVar, selType); + } else if (child == femto_universe_phi_selection::kNegTrack) { + negDaughTrack.setSelection(selVal, selVar, selType); } } template - void setChildPIDSpecies(femtoUniversePhiSelection::ChildTrackType child, + void setChildPIDSpecies(femto_universe_phi_selection::ChildTrackType child, T& pids) { - if (child == femtoUniversePhiSelection::kPosTrack) { - PosDaughTrack.setPIDSpecies(pids); - } else if (child == femtoUniversePhiSelection::kNegTrack) { - NegDaughTrack.setPIDSpecies(pids); + if (child == femto_universe_phi_selection::kPosTrack) { + posDaughTrack.setPIDSpecies(pids); + } else if (child == femto_universe_phi_selection::kNegTrack) { + negDaughTrack.setPIDSpecies(pids); } } @@ -125,12 +120,12 @@ class FemtoUniversePhiSelection /// \param iSel Track selection variable to be examined /// \param prefix Additional prefix for the name of the configurable /// \param suffix Additional suffix for the name of the configurable - static std::string getSelectionName(femtoUniversePhiSelection::PhiSel iSel, + static std::string getSelectionName(femto_universe_phi_selection::PhiSel iSel, std::string_view prefix = "", std::string_view suffix = "") { std::string outString = static_cast(prefix); - outString += static_cast(mSelectionNames[iSel]); + outString += static_cast(kSelectionNames[iSel]); outString += suffix; return outString; } @@ -143,7 +138,7 @@ class FemtoUniversePhiSelection { for (int index = 0; index < kNphiSelection; index++) { std::string comp = static_cast(prefix) + - static_cast(mSelectionNames[index]); + static_cast(kSelectionNames[index]); std::string_view cmp{comp}; if (obs.compare(cmp) == 0) return index; @@ -154,8 +149,7 @@ class FemtoUniversePhiSelection /// Helper function to obtain the type of a given selection variable for consistent naming of the configurables /// \param iSel Phi selection variable whose type is returned - static femtoUniverseSelection::SelectionType - getSelectionType(femtoUniversePhiSelection::PhiSel iSel) + static femto_universe_selection::SelectionType getSelectionType(femto_universe_phi_selection::PhiSel iSel) { return mSelectionTypes[iSel]; } @@ -164,11 +158,11 @@ class FemtoUniversePhiSelection /// for consistent description of the configurables /// \param iSel Track selection variable to be examined /// \param prefix Additional prefix for the output of the configurable - static std::string getSelectionHelper(femtoUniversePhiSelection::PhiSel iSel, + static std::string getSelectionHelper(femto_universe_phi_selection::PhiSel iSel, std::string_view prefix = "") { std::string outString = static_cast(prefix); - outString += static_cast(mSelectionHelper[iSel]); + outString += static_cast(kSelectionHelper[iSel]); return outString; } @@ -196,21 +190,21 @@ class FemtoUniversePhiSelection nSigmaPIDOffsetTPC = offsetTPC; } - void setChildRejectNotPropagatedTracks(femtoUniversePhiSelection::ChildTrackType child, bool reject) + void setChildRejectNotPropagatedTracks(femto_universe_phi_selection::ChildTrackType child, bool reject) { - if (child == femtoUniversePhiSelection::kPosTrack) { - PosDaughTrack.setRejectNotPropagatedTracks(reject); - } else if (child == femtoUniversePhiSelection::kNegTrack) { - NegDaughTrack.setRejectNotPropagatedTracks(reject); + if (child == femto_universe_phi_selection::kPosTrack) { + posDaughTrack.setRejectNotPropagatedTracks(reject); + } else if (child == femto_universe_phi_selection::kNegTrack) { + negDaughTrack.setRejectNotPropagatedTracks(reject); } } - void setChildnSigmaPIDOffset(femtoUniversePhiSelection::ChildTrackType child, float offsetTPC, float offsetTOF) + void setChildnSigmaPIDOffset(femto_universe_phi_selection::ChildTrackType child, float offsetTPC, float offsetTOF) { - if (child == femtoUniversePhiSelection::kPosTrack) { - PosDaughTrack.setnSigmaPIDOffset(offsetTPC, offsetTOF); - } else if (child == femtoUniversePhiSelection::kNegTrack) { - NegDaughTrack.setnSigmaPIDOffset(offsetTPC, offsetTOF); + if (child == femto_universe_phi_selection::kPosTrack) { + posDaughTrack.setnSigmaPIDOffset(offsetTPC, offsetTOF); + } else if (child == femto_universe_phi_selection::kNegTrack) { + negDaughTrack.setnSigmaPIDOffset(offsetTPC, offsetTOF); } } @@ -226,12 +220,11 @@ class FemtoUniversePhiSelection float pTPhiMin; float pTPhiMax; float etaPhiMax; - float DCAPhiDaughMax; - float CPAPhiMin; - float TranRadPhiMin; - float TranRadPhiMax; - float DecVtxMax; - + float kDCAPhiDaughMax; + float kCPAPhiMin; + float kTranRadPhiMin; + float kTranRadPhiMax; + float kDecVtxMax; float fInvMassLowLimit; float fInvMassUpLimit; @@ -241,30 +234,30 @@ class FemtoUniversePhiSelection float nSigmaPIDOffsetTPC; - FemtoUniverseTrackSelection PosDaughTrack; - FemtoUniverseTrackSelection NegDaughTrack; + FemtoUniverseTrackSelection posDaughTrack; + FemtoUniverseTrackSelection negDaughTrack; static constexpr int kNphiSelection = 9; - static constexpr std::string_view mSelectionNames[kNphiSelection] = { + static constexpr std::string_view kSelectionNames[kNphiSelection] = { "Sign", "PtMin", "PtMax", "EtaMax", "DCAdaughMax", "CPAMin", "TranRadMin", "TranRadMax", "DecVecMax"}; ///< Name of the different ///< selections - static constexpr femtoUniverseSelection::SelectionType + static constexpr femto_universe_selection::SelectionType mSelectionTypes[kNphiSelection]{ - femtoUniverseSelection::kEqual, - femtoUniverseSelection::kLowerLimit, - femtoUniverseSelection::kUpperLimit, - femtoUniverseSelection::kUpperLimit, - femtoUniverseSelection::kUpperLimit, - femtoUniverseSelection::kLowerLimit, - femtoUniverseSelection::kLowerLimit, - femtoUniverseSelection::kUpperLimit, - femtoUniverseSelection::kUpperLimit}; ///< Map to match a variable with - ///< its type - - static constexpr std::string_view mSelectionHelper[kNphiSelection] = { + femto_universe_selection::kEqual, + femto_universe_selection::kLowerLimit, + femto_universe_selection::kUpperLimit, + femto_universe_selection::kUpperLimit, + femto_universe_selection::kUpperLimit, + femto_universe_selection::kLowerLimit, + femto_universe_selection::kLowerLimit, + femto_universe_selection::kUpperLimit, + femto_universe_selection::kUpperLimit}; ///< Map to match a variable with + ///< its type + + static constexpr std::string_view kSelectionHelper[kNphiSelection] = { "+1 for lambda, -1 for antilambda", "Minimum pT (GeV/c)", "Maximum pT (GeV/c)", @@ -276,11 +269,11 @@ class FemtoUniversePhiSelection "Maximum distance from primary vertex"}; ///< Helper information for the ///< different selections -}; // namespace femtoUniverse +}; // namespace femto_universe template + typename CutContainerType> void FemtoUniversePhiSelection::init(HistogramRegistry* registry) { @@ -297,7 +290,7 @@ void FemtoUniversePhiSelection::init(HistogramRegistry* registry) /// \todo this should be an automatic check in the parent class, and the /// return type should be templated size_t nSelections = getNSelections(); - if (nSelections > 8 * sizeof(cutContainerType)) { + if (nSelections > 8 * sizeof(CutContainerType)) { LOG(fatal) << "FemtoUniversePhiCuts: Number of selections to large for your " "container - quitting!"; } @@ -310,17 +303,17 @@ void FemtoUniversePhiSelection::init(HistogramRegistry* registry) mHistogramRegistry->add((folderName + "/hEta").c_str(), "; #eta; Entries", kTH1F, {{1000, -1, 1}}); mHistogramRegistry->add((folderName + "/hPhi").c_str(), "; #phi; Entries", - kTH1F, {{1000, 0, 2. * M_PI}}); + kTH1F, {{1000, 0, o2::constants::math::TwoPI}}); mHistogramRegistry->add((folderName + "/hInvMassPhi").c_str(), "", kTH1F, {massAxisPhi}); - PosDaughTrack.init( + aod::femtouniverseparticle::CutContainerType>( mHistogramRegistry); - NegDaughTrack.init( + aod::femtouniverseparticle::CutContainerType>( mHistogramRegistry); // mHistogramRegistry->add("LambdaQA/hInvMassLambdaNoCuts", "No cuts", kTH1F, @@ -349,31 +342,31 @@ void FemtoUniversePhiSelection::init(HistogramRegistry* registry) } /// check whether the most open cuts are fulfilled - most of this should have /// already be done by the filters - nPtPhiMinSel = getNSelections(femtoUniversePhiSelection::kPhipTMin); - nPtPhiMaxSel = getNSelections(femtoUniversePhiSelection::kPhipTMax); - nEtaPhiMaxSel = getNSelections(femtoUniversePhiSelection::kPhietaMax); - nDCAPhiDaughMax = getNSelections(femtoUniversePhiSelection::kPhiDCADaughMax); - nCPAPhiMin = getNSelections(femtoUniversePhiSelection::kPhiCPAMin); - nTranRadPhiMin = getNSelections(femtoUniversePhiSelection::kPhiTranRadMin); - nTranRadPhiMax = getNSelections(femtoUniversePhiSelection::kPhiTranRadMax); - nDecVtxMax = getNSelections(femtoUniversePhiSelection::kPhiDecVtxMax); - - pTPhiMin = getMinimalSelection(femtoUniversePhiSelection::kPhipTMin, - femtoUniverseSelection::kLowerLimit); - pTPhiMax = getMinimalSelection(femtoUniversePhiSelection::kPhipTMax, - femtoUniverseSelection::kUpperLimit); - etaPhiMax = getMinimalSelection(femtoUniversePhiSelection::kPhietaMax, - femtoUniverseSelection::kAbsUpperLimit); - DCAPhiDaughMax = getMinimalSelection(femtoUniversePhiSelection::kPhiDCADaughMax, - femtoUniverseSelection::kUpperLimit); - CPAPhiMin = getMinimalSelection(femtoUniversePhiSelection::kPhiCPAMin, - femtoUniverseSelection::kLowerLimit); - TranRadPhiMin = getMinimalSelection(femtoUniversePhiSelection::kPhiTranRadMin, - femtoUniverseSelection::kLowerLimit); - TranRadPhiMax = getMinimalSelection(femtoUniversePhiSelection::kPhiTranRadMax, - femtoUniverseSelection::kUpperLimit); - DecVtxMax = getMinimalSelection(femtoUniversePhiSelection::kPhiDecVtxMax, - femtoUniverseSelection::kAbsUpperLimit); + nPtPhiMinSel = getNSelections(femto_universe_phi_selection::kPhipTMin); + nPtPhiMaxSel = getNSelections(femto_universe_phi_selection::kPhipTMax); + nEtaPhiMaxSel = getNSelections(femto_universe_phi_selection::kPhietaMax); + nDCAPhiDaughMax = getNSelections(femto_universe_phi_selection::kPhiDCADaughMax); + nCPAPhiMin = getNSelections(femto_universe_phi_selection::kPhiCPAMin); + nTranRadPhiMin = getNSelections(femto_universe_phi_selection::kPhiTranRadMin); + nTranRadPhiMax = getNSelections(femto_universe_phi_selection::kPhiTranRadMax); + nDecVtxMax = getNSelections(femto_universe_phi_selection::kPhiDecVtxMax); + + pTPhiMin = getMinimalSelection(femto_universe_phi_selection::kPhipTMin, + femto_universe_selection::kLowerLimit); + pTPhiMax = getMinimalSelection(femto_universe_phi_selection::kPhipTMax, + femto_universe_selection::kUpperLimit); + etaPhiMax = getMinimalSelection(femto_universe_phi_selection::kPhietaMax, + femto_universe_selection::kAbsUpperLimit); + kDCAPhiDaughMax = getMinimalSelection(femto_universe_phi_selection::kPhiDCADaughMax, + femto_universe_selection::kUpperLimit); + kCPAPhiMin = getMinimalSelection(femto_universe_phi_selection::kPhiCPAMin, + femto_universe_selection::kLowerLimit); + kTranRadPhiMin = getMinimalSelection(femto_universe_phi_selection::kPhiTranRadMin, + femto_universe_selection::kLowerLimit); + kTranRadPhiMax = getMinimalSelection(femto_universe_phi_selection::kPhiTranRadMax, + femto_universe_selection::kUpperLimit); + kDecVtxMax = getMinimalSelection(femto_universe_phi_selection::kPhiDecVtxMax, + femto_universe_selection::kAbsUpperLimit); } template @@ -419,42 +412,42 @@ bool FemtoUniversePhiSelection::isSelectedMinimal(C const& col, V const& phi, if (nEtaPhiMaxSel > 0 && std::abs(eta) > etaPhiMax) { return false; } - if (nDCAPhiDaughMax > 0 && dcaDaughphi > DCAPhiDaughMax) { + if (nDCAPhiDaughMax > 0 && dcaDaughphi > kDCAPhiDaughMax) { return false; } - if (nCPAPhiMin > 0 && cpaphi < CPAPhiMin) { + if (nCPAPhiMin > 0 && cpaphi < kCPAPhiMin) { return false; } - if (nTranRadPhiMin > 0 && tranRad < TranRadPhiMin) { + if (nTranRadPhiMin > 0 && tranRad < kTranRadPhiMin) { return false; } - if (nTranRadPhiMax > 0 && tranRad > TranRadPhiMax) { + if (nTranRadPhiMax > 0 && tranRad > kTranRadPhiMax) { return false; } for (size_t i = 0; i < decVtx.size(); i++) { - if (nDecVtxMax > 0 && decVtx.at(i) > DecVtxMax) { + if (nDecVtxMax > 0 && decVtx.at(i) > kDecVtxMax) { return false; } } - if (!PosDaughTrack.isSelectedMinimal(posTrack)) { + if (!posDaughTrack.isSelectedMinimal(posTrack)) { return false; } - if (!NegDaughTrack.isSelectedMinimal(negTrack)) { + if (!negDaughTrack.isSelectedMinimal(negTrack)) { return false; } // check that track combinations for Phi or antiPhi would be fulfilling PID - int nSigmaPIDMax = PosDaughTrack.getSigmaPIDMax(); + int nSigmaPIDMax = posDaughTrack.getSigmaPIDMax(); // antiPhi auto nSigmaPrNeg = negTrack.tpcNSigmaPr(); auto nSigmaPiPos = posTrack.tpcNSigmaPi(); // phi auto nSigmaPiNeg = negTrack.tpcNSigmaPi(); auto nSigmaPrPos = posTrack.tpcNSigmaPr(); - if (!(abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && - abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax) && - !(abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && - abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax)) { + if (!(std::abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && + std::abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax) && + !(std::abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && + std::abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax)) { return false; } @@ -499,24 +492,24 @@ void FemtoUniversePhiSelection::fillLambdaQA(C const& col, V const& phi, mHistogramRegistry->fill(HIST("LambdaQA/hInvMassLambdaEtaMax"), phi.mLambda()); } - if (dcaDaughphi < DCAPhiDaughMax) { + if (dcaDaughphi < kDCAPhiDaughMax) { mHistogramRegistry->fill(HIST("LambdaQA/hInvMassLambdaDCAPhiDaugh"), phi.mLambda()); } - if (cpaphi > CPAPhiMin) { + if (cpaphi > kCPAPhiMin) { mHistogramRegistry->fill(HIST("LambdaQA/hInvMassLambdaCPA"), phi.mLambda()); } - if (tranRad > TranRadPhiMin) { + if (tranRad > kTranRadPhiMin) { mHistogramRegistry->fill(HIST("LambdaQA/hInvMassLambdaTranRadMin"), phi.mLambda()); } - if (tranRad < TranRadPhiMax) { + if (tranRad < kTranRadPhiMax) { mHistogramRegistry->fill(HIST("LambdaQA/hInvMassLambdaTranRadMax"), phi.mLambda()); } bool write = true; for (size_t i = 0; i < decVtx.size(); i++) { - write = write && (decVtx.at(i) < DecVtxMax); + write = write && (decVtx.at(i) < kDecVtxMax); } if (write) { mHistogramRegistry->fill(HIST("LambdaQA/hInvMassLambdaDecVtxMax"), @@ -526,37 +519,37 @@ void FemtoUniversePhiSelection::fillLambdaQA(C const& col, V const& phi, /// the CosPA of Phi needs as argument the posXYZ of collisions vertex so we need /// to pass the collsion as well -template -std::array +template +std::array FemtoUniversePhiSelection::getCutContainer(C const& col, V const& phi, T const& posTrack, T const& negTrack) { - auto outputPosTrack = PosDaughTrack.getCutContainer(posTrack); - auto outputNegTrack = NegDaughTrack.getCutContainer(negTrack); - cutContainerType output = 0; + auto outputPosTrack = posDaughTrack.getCutContainer(posTrack); + auto outputNegTrack = negDaughTrack.getCutContainer(negTrack); + CutContainerType output = 0; size_t counter = 0; - auto lambdaMassNominal = TDatabasePDG::Instance()->GetParticle(3122)->Mass(); // FIXME: Get from the common header + auto lambdaMassNominal = o2::constants::physics::MassPhi; auto lambdaMassHypothesis = phi.mLambda(); auto antiLambdaMassHypothesis = phi.mAntiLambda(); - auto diffLambda = abs(lambdaMassNominal - lambdaMassHypothesis); - auto diffAntiLambda = abs(antiLambdaMassHypothesis - lambdaMassHypothesis); + auto diffLambda = std::abs(lambdaMassNominal - lambdaMassHypothesis); + auto diffAntiLambda = std::abs(antiLambdaMassHypothesis - lambdaMassHypothesis); float sign = 0.; - int nSigmaPIDMax = PosDaughTrack.getSigmaPIDMax(); + int nSigmaPIDMax = posDaughTrack.getSigmaPIDMax(); auto nSigmaPrNeg = negTrack.tpcNSigmaPr(); auto nSigmaPiPos = posTrack.tpcNSigmaPi(); auto nSigmaPiNeg = negTrack.tpcNSigmaPi(); auto nSigmaPrPos = posTrack.tpcNSigmaPr(); // check the mass and the PID of daughters - if (abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && diffAntiLambda > diffLambda) { + if (std::abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && std::abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && diffAntiLambda > diffLambda) { sign = -1.; - } else if (abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && diffAntiLambda < diffLambda) { + } else if (std::abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && std::abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && diffAntiLambda < diffLambda) { sign = 1.; } else { // if it happens that none of these are true, ignore the invariant mass - if (abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax) { + if (std::abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && std::abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax) { sign = -1.; - } else if (abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax) { + } else if (std::abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && std::abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax) { sign = 1.; } } @@ -571,38 +564,38 @@ std::array float observable = 0.; for (auto& sel : mSelections) { const auto selVariable = sel.getSelectionVariable(); - if (selVariable == femtoUniversePhiSelection::kPhiDecVtxMax) { + if (selVariable == femto_universe_phi_selection::kPhiDecVtxMax) { for (size_t i = 0; i < decVtx.size(); ++i) { auto decVtxValue = decVtx.at(i); sel.checkSelectionSetBit(decVtxValue, output, counter); } } else { switch (selVariable) { - case (femtoUniversePhiSelection::kPhiSign): + case (femto_universe_phi_selection::kPhiSign): observable = sign; break; - case (femtoUniversePhiSelection::kPhipTMin): + case (femto_universe_phi_selection::kPhipTMin): observable = pT; break; - case (femtoUniversePhiSelection::kPhipTMax): + case (femto_universe_phi_selection::kPhipTMax): observable = pT; break; - case (femtoUniversePhiSelection::kPhietaMax): + case (femto_universe_phi_selection::kPhietaMax): observable = eta; break; - case (femtoUniversePhiSelection::kPhiDCADaughMax): + case (femto_universe_phi_selection::kPhiDCADaughMax): observable = dcaDaughphi; break; - case (femtoUniversePhiSelection::kPhiCPAMin): + case (femto_universe_phi_selection::kPhiCPAMin): observable = cpaphi; break; - case (femtoUniversePhiSelection::kPhiTranRadMin): + case (femto_universe_phi_selection::kPhiTranRadMin): observable = tranRad; break; - case (femtoUniversePhiSelection::kPhiTranRadMax): + case (femto_universe_phi_selection::kPhiTranRadMax): observable = tranRad; break; - case (femtoUniversePhiSelection::kPhiDecVtxMax): + case (femto_universe_phi_selection::kPhiDecVtxMax): break; } sel.checkSelectionSetBit(observable, output, counter); @@ -610,10 +603,10 @@ std::array } return { output, - outputPosTrack.at(femtoUniverseTrackSelection::TrackContainerPosition::kCuts), - outputPosTrack.at(femtoUniverseTrackSelection::TrackContainerPosition::kPID), - outputNegTrack.at(femtoUniverseTrackSelection::TrackContainerPosition::kCuts), - outputNegTrack.at(femtoUniverseTrackSelection::TrackContainerPosition::kPID)}; + outputPosTrack.at(femto_universe_track_selection::TrackContainerPosition::kCuts), + outputPosTrack.at(femto_universe_track_selection::TrackContainerPosition::kPID), + outputNegTrack.at(femto_universe_track_selection::TrackContainerPosition::kCuts), + outputNegTrack.at(femto_universe_track_selection::TrackContainerPosition::kPID)}; } template GetParticle(321)->Mass(); // FIXME: Get from the common header - float mMassTwo = TDatabasePDG::Instance()->GetParticle(321)->Mass(); // FIXME: Get from the common header + float mMassOne = o2::constants::physics::MassKPlus; + float mMassTwo = o2::constants::physics::MassKMinus; part1Vec.SetPtEtaPhiM(posTrack.pt(), posTrack.eta(), posTrack.phi(), mMassOne); part2Vec.SetPtEtaPhiM(negTrack.pt(), negTrack.eta(), negTrack.phi(), mMassTwo); @@ -635,13 +628,7 @@ void FemtoUniversePhiSelection::fillQA(C const& /*col*/, V const& /*phi*/, T con sumVec += part2Vec; float phiEta = sumVec.Eta(); float phiPt = sumVec.Pt(); - // float phiP = sumVec.P(); - float phiPhi = sumVec.Phi(); - if (sumVec.Phi() < 0) { - phiPhi = sumVec.Phi() + 2 * o2::constants::math::PI; - } else if (sumVec.Phi() >= 0) { - phiPhi = sumVec.Phi(); - } + float phiPhi = RecoDecay::constrainAngle(sumVec.Phi(), 0); float phiM = sumVec.M(); @@ -664,12 +651,12 @@ void FemtoUniversePhiSelection::fillQA(C const& /*col*/, V const& /*phi*/, T con phiM); } - PosDaughTrack.fillQA(posTrack); - NegDaughTrack.fillQA(negTrack); } -} // namespace o2::analysis::femtoUniverse +} // namespace o2::analysis::femto_universe #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPHISELECTION_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseSHContainer.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseSHContainer.h new file mode 100644 index 00000000000..e4a0b9d11bd --- /dev/null +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseSHContainer.h @@ -0,0 +1,270 @@ +// Copyright 2019-2022 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 FemtoUniverseSHContainer.h +/// \brief FemtoUniverseSHContainer - Fills the Spherical Harmonics components +/// \remark This file is inherited from ~/FemtoUniverse/Core/FemtoUniverse3DContainer.h on 17/06/2024 +/// \author Pritam Chakraborty, WUT Warsaw, pritam.chakraborty@pw.edu.pl8 + +#ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSESHCONTAINER_H_ +#define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSESHCONTAINER_H_ + +#include +#include +#include +#include +#include + +#include "Framework/HistogramRegistry.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseSpherHarMath.h" +#include "Math/Vector4D.h" +#include "TMath.h" +#include "TDatabasePDG.h" + +namespace o2::analysis::femto_universe +{ + +namespace femto_universe_sh_container +{ +/// Femtoscopic observable to be computed +enum Observable { kstar ///< kstar +}; + +/// Type of the event processind +enum EventType { same, ///< Pair from same event + mixed ///< Pair from mixed event +}; +}; // namespace femto_universe_sh_container + +/// \class femto_universe_sh_container +/// \brief Container for all histogramming related to the correlation function. The two +/// particles of the pair are passed here, and the correlation function and QA histograms +/// are filled according to the specified observable +/// \tparam eventType Type of the event (same/mixed) +/// \tparam obs Observable to be computed (k*/Q_inv/...) +template +class FemtoUniverseSHContainer +{ + public: + /// Destructor + virtual ~FemtoUniverseSHContainer() = default; + + /// Container for all histogramming related to the spherical harmonics of the correlation function. The two + /// particles of the pair are passed here, and the correlation function + /// are filled according to the specified observable + /// \tparam T type of the configurable for the axis configuration + /// \param registry Histogram registry to be passed + /// \param kstarbins k* binning for the histograms + template + void init(HistogramRegistry* registry, T& kstarbins, int /*maxl*/) + { + kStarBins = kstarbins; + std::string femtoObs1D; + + std::vector fels(kMaxJM); + std::vector fems(kMaxJM); + std::vector felsi(kMaxJM); + std::vector femsi(kMaxJM); + + // Fill in els and ems table + int el = 0; + int em = 0; + int il = 0; + do { + + fels[il] = el; + fems[il] = em; + felsi[il] = static_cast(el); + femsi[il] = static_cast(em); + em++; + il++; + if (em > el) { + el++; + em = -el; + } + } while (el <= kMaxL); + + kHistogramRegistry = registry; + femtoObs1D = "#it{q} (GeV/#it{c})"; + + framework::AxisSpec femtoObsAxis1D = {kstarbins, femtoObs1D.c_str()}; + std::string folderName = static_cast(kFolderSuffix[kEventType]) + static_cast(o2::aod::femtouniverse_mc_particle::MCTypeName[o2::aod::femtouniverse_mc_particle::MCType::kRecon]); + std::string suffix; + + for (int ihist = 0; ihist < kMaxJM; ihist++) { + if (femsi[ihist] < 0) { + suffix = "Ylm" + std::to_string(felsi[ihist]) + std::to_string(felsi[ihist] - femsi[ihist]); + } else { + suffix = "Ylm" + std::to_string(felsi[ihist]) + std::to_string(femsi[ihist]); + } + + if (kFolderSuffix[kEventType] == kFolderSuffix[0]) { + fnumsreal[ihist] = kHistogramRegistry->add(("NumRe" + suffix).c_str(), ("; " + femtoObs1D + "; Entries").c_str(), kTH1D, {femtoObsAxis1D}); + fnumsimag[ihist] = kHistogramRegistry->add(("NumIm" + suffix).c_str(), ("; " + femtoObs1D + "; Entries").c_str(), kTH1D, {femtoObsAxis1D}); + } else { + fdensreal[ihist] = kHistogramRegistry->add(("DenRe" + suffix).c_str(), ("; " + femtoObs1D + "; Entries").c_str(), kTH1D, {femtoObsAxis1D}); + fdensimag[ihist] = kHistogramRegistry->add(("DenIm" + suffix).c_str(), ("; " + femtoObs1D + "; Entries").c_str(), kTH1D, {femtoObsAxis1D}); + } + } + + if (kFolderSuffix[kEventType] == kFolderSuffix[0]) { + std::string bufnameNum = "CovNum"; + fcovnum = kHistogramRegistry->add((bufnameNum).c_str(), "; x; y; z", kTH3D, {{kstarbins}, {(kMaxJM * 2), -0.5, ((static_cast(kMaxJM) * 2.0 - 0.5))}, {(kMaxJM * 2), -0.5, ((static_cast(kMaxJM) * 2.0 - 0.5))}}); + } else if (kFolderSuffix[kEventType] == kFolderSuffix[1]) { + std::string bufnameDen = "CovDen"; + fcovden = kHistogramRegistry->add((bufnameDen).c_str(), "; x; y; z", kTH3D, {{kstarbins}, {(kMaxJM * 2), -0.5, ((static_cast(kMaxJM) * 2.0 - 0.5))}, {(kMaxJM * 2), -0.5, ((static_cast(kMaxJM) * 2.0 - 0.5))}}); + } + + fbinctn = new TH1D(TString("BinCountNum"), "Bin Occupation (Numerator)", static_cast(kStarBins[0]), kStarBins[1], kStarBins[2]); + fbinctd = new TH1D(TString("BinCountDen"), "Bin Occupation (Denominator)", static_cast(kStarBins[0]), kStarBins[1], kStarBins[2]); + } + + /// Set the PDG codes of the two particles involved + /// \param pdg1 PDG code of particle one + /// \param pdg2 PDG code of particle two + void setPDGCodes(const int pdg1, const int pdg2) + { + kMassOne = TDatabasePDG::Instance()->GetParticle(pdg1)->Mass(); + kMassTwo = TDatabasePDG::Instance()->GetParticle(pdg2)->Mass(); + kPDGOne = pdg1; + kPDGTwo = pdg2; + } + + /// To compute the bin value for cavariance matrix + /// \param qbin value of the qth k* bin + /// \param ilmzero + /// \param zeroimag + /// \param ilmprim + /// \param primimag + int getBin(int qbin, int ilmzero, int zeroimag, int ilmprim, int primimag) + { + return qbin * kMaxJM * kMaxJM * 4 + (ilmprim * 2 + primimag) * kMaxJM * 2 + ilmzero * 2 + zeroimag; + } + + /// Templated function to compute the necessary observables and fill the histograms for respective Spherical Harmonic + /// \tparam T type of the femtouniverseparticle + /// \param part1 Particle one + /// \param part2 Particle two + /// \param ChosenEventType same or mixed event + /// \param maxl Maximum valie of L component of the spherical harmonics + template + void addEventPair(T const& part1, T const& part2, uint8_t ChosenEventType, int /*maxl*/, bool isiden) + { + std::vector> fYlmBuffer(kMaxJM); + std::vector f3d; + f3d = FemtoUniverseMath::newpairfunc(part1, kMassOne, part2, kMassTwo, isiden); + + const float kv = f3d[0]; + const float qout = f3d[1]; + const float qside = f3d[2]; + const float qlong = f3d[3]; + + int nqbin = fbinctn->GetXaxis()->FindFixBin(kv) - 1; + + FemtoUniverseSpherHarMath kYlm; + kYlm.doYlmUpToL(kMaxL, qout, qside, qlong, fYlmBuffer.data()); + + if (ChosenEventType == femto_universe_sh_container::EventType::same) { + for (int ihist = 0; ihist < kMaxJM; ihist++) { + fnumsreal[ihist]->Fill(kv, real(fYlmBuffer[ihist])); + fnumsimag[ihist]->Fill(kv, -imag(fYlmBuffer[ihist])); + fbinctn->Fill(kv, 1.0); + } + + if (nqbin < fbinctn->GetNbinsX()) { + for (int ilmzero = 0; ilmzero < kMaxJM; ilmzero++) { + for (int ilmprim = 0; ilmprim < kMaxJM; ilmprim++) { + fcovmnum[getBin(nqbin, ilmzero, 0, ilmprim, 0)] += (real(fYlmBuffer[ilmzero]) * real(fYlmBuffer[ilmprim])); + fcovmnum[getBin(nqbin, ilmzero, 0, ilmprim, 1)] += (real(fYlmBuffer[ilmzero]) * -imag(fYlmBuffer[ilmprim])); + fcovmnum[getBin(nqbin, ilmzero, 1, ilmprim, 0)] += (-imag(fYlmBuffer[ilmzero]) * real(fYlmBuffer[ilmprim])); + fcovmnum[getBin(nqbin, ilmzero, 1, ilmprim, 1)] += (-imag(fYlmBuffer[ilmzero]) * -imag(fYlmBuffer[ilmprim])); + } + } + } + } else if (ChosenEventType == femto_universe_sh_container::EventType::mixed) { + for (int ihist = 0; ihist < kMaxJM; ihist++) { + fdensreal[ihist]->Fill(kv, real(fYlmBuffer[ihist])); + fdensimag[ihist]->Fill(kv, -imag(fYlmBuffer[ihist])); + } + if (nqbin < fbinctn->GetNbinsX()) { + for (int ilmzero = 0; ilmzero < kMaxJM; ilmzero++) { + for (int ilmprim = 0; ilmprim < kMaxJM; ilmprim++) { + fcovmden[getBin(nqbin, ilmzero, 0, ilmprim, 0)] += (real(fYlmBuffer[ilmzero]) * real(fYlmBuffer[ilmprim])); + fcovmden[getBin(nqbin, ilmzero, 0, ilmprim, 1)] += (real(fYlmBuffer[ilmzero]) * -imag(fYlmBuffer[ilmprim])); + fcovmden[getBin(nqbin, ilmzero, 1, ilmprim, 0)] += (-imag(fYlmBuffer[ilmzero]) * real(fYlmBuffer[ilmprim])); + fcovmden[getBin(nqbin, ilmzero, 1, ilmprim, 1)] += (-imag(fYlmBuffer[ilmzero]) * -imag(fYlmBuffer[ilmprim])); + } + } + } + } + } + + /// Function to fill covariance matrix in 3D histograms + /// \param ChosenEventType same or mixed event + /// \param MaxJM Maximum value of J + void packCov(uint8_t ChosenEventType, int /*MaxJM*/) + { + if (ChosenEventType == femto_universe_sh_container::EventType::same) { + for (int ibin = 1; ibin <= fcovnum->GetNbinsX(); ibin++) { + for (int ilmz = 0; ilmz < kMaxJM * 2; ilmz++) { + for (int ilmp = 0; ilmp < kMaxJM * 2; ilmp++) { + auto bin = getBin(ibin - 1, ilmz / 2, ilmz % 2, ilmp / 2, ilmp % 2); + auto value = fcovmnum[bin]; + fcovnum->SetBinContent(ibin, ilmz + 1, ilmp + 1, value); + } + } + } + } else if (ChosenEventType == femto_universe_sh_container::EventType::mixed) { + for (int ibin = 1; ibin <= fcovden->GetNbinsX(); ibin++) { + for (int ilmz = 0; ilmz < kMaxJM * 2; ilmz++) { + for (int ilmp = 0; ilmp < kMaxJM * 2; ilmp++) { + auto bin = getBin(ibin - 1, ilmz / 2, ilmz % 2, ilmp / 2, ilmp % 2); + auto value = fcovmden[bin]; + fcovden->SetBinContent(ibin, ilmz + 1, ilmp + 1, value); + } + } + } + } + } + + private: + std::array, 10> fnumsreal{}; + std::array, 10> fnumsimag{}; + std::array, 10> fdensreal{}; + std::array, 10> fdensimag{}; + + std::shared_ptr fcovnum{}; + std::shared_ptr fcovden{}; + + TH1D* fbinctn; + TH1D* fbinctd; + + static constexpr int kMaxL = 1; + static constexpr int kMaxJM = (kMaxL + 1) * (kMaxL + 1); + + std::array fcovmnum{}; ///< Covariance matrix for the numerator + std::array fcovmden{}; ///< Covariance matrix for the numerator + + protected: + HistogramRegistry* kHistogramRegistry = nullptr; ///< For QA output + static constexpr std::string_view kFolderSuffix[2] = {"SameEvent", "MixedEvent"}; ///< Folder naming for the output according to kEventType + static constexpr int kEventType = eventType; ///< Type of the event (same/mixed, according to FEMTOUNIVERSESHCONTAINER::EventType) + float kMassOne = 0.f; ///< PDG mass of particle 1 + float kMassTwo = 0.f; ///< PDG mass of particle 2 + int kPDGOne = 0; ///< PDG code of particle 1 + int kPDGTwo = 0; ///< PDG code of particle 2 + std::vector kStarBins; +}; + +} // namespace o2::analysis::femto_universe + +#endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSESHCONTAINER_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseSelection.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseSelection.h index 4e97786092d..ac49b2d6f42 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseSelection.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseSelection.h @@ -19,10 +19,10 @@ #include -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { -namespace femtoUniverseSelection +namespace femto_universe_selection { /// Type of selection to be employed enum SelectionType { kUpperLimit, ///< simple upper limit for the value, e.g. p_T < 1 GeV/c @@ -32,7 +32,7 @@ enum SelectionType { kUpperLimit, ///< simple upper limit for the value, e.g. kEqual ///< values need to be equal, e.g. sign = 1 }; -} // namespace femtoUniverseSelection +} // namespace femto_universe_selection /// Simple class taking care of individual selections /// \todo In principle all cuts that fulfill the getMinimalSelection are done implicitly and can be removed from the vector containing all cuts @@ -49,7 +49,7 @@ class FemtoUniverseSelection /// \param selVal Value used for the selection /// \param selVar Variable used for the selection /// \param selType Type of selection to be employed - FemtoUniverseSelection(selValDataType selVal, selVariableDataType selVar, femtoUniverseSelection::SelectionType selType) + FemtoUniverseSelection(selValDataType selVal, selVariableDataType selVar, femto_universe_selection::SelectionType selType) : mSelVal(selVal), mSelVar(selVar), mSelType(selType) @@ -69,7 +69,7 @@ class FemtoUniverseSelection /// Get the type of selection to be employed /// \return Type of selection to be employed - femtoUniverseSelection::SelectionType getSelectionType() { return mSelType; } + femto_universe_selection::SelectionType getSelectionType() { return mSelType; } /// Check whether the selection is fulfilled or not /// \param observable Value of the variable to be checked @@ -77,17 +77,17 @@ class FemtoUniverseSelection bool isSelected(selValDataType observable) { switch (mSelType) { - case (femtoUniverseSelection::SelectionType::kUpperLimit): + case (femto_universe_selection::SelectionType::kUpperLimit): return (observable < mSelVal); - case (femtoUniverseSelection::SelectionType::kAbsUpperLimit): + case (femto_universe_selection::SelectionType::kAbsUpperLimit): return (std::abs(observable) < mSelVal); break; - case (femtoUniverseSelection::SelectionType::kLowerLimit): + case (femto_universe_selection::SelectionType::kLowerLimit): return (observable > mSelVal); - case (femtoUniverseSelection::SelectionType::kAbsLowerLimit): + case (femto_universe_selection::SelectionType::kAbsLowerLimit): return (std::abs(observable) > mSelVal); break; - case (femtoUniverseSelection::SelectionType::kEqual): + case (femto_universe_selection::SelectionType::kEqual): /// \todo can the comparison be done a bit nicer? return (std::abs(observable - mSelVal) < std::abs(mSelVal * 1e-6)); break; @@ -123,11 +123,11 @@ class FemtoUniverseSelection } private: - selValDataType mSelVal{0.f}; ///< Value used for the selection - selVariableDataType mSelVar; ///< Variable used for the selection - femtoUniverseSelection::SelectionType mSelType; ///< Type of selection employed + selValDataType mSelVal{0.f}; ///< Value used for the selection + selVariableDataType mSelVar; ///< Variable used for the selection + femto_universe_selection::SelectionType mSelType; ///< Type of selection employed }; -} // namespace o2::analysis::femtoUniverse +} // namespace o2::analysis::femto_universe #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSESELECTION_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseSoftPionRemoval.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseSoftPionRemoval.h new file mode 100644 index 00000000000..ac374c05074 --- /dev/null +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseSoftPionRemoval.h @@ -0,0 +1,120 @@ +// Copyright 2019-2022 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 FemtoUniverseSoftPionRemoval.h +/// \brief FemtoUniverseSoftPionRemoval - Checking the soft pions from D* decay and removing them +/// \author Katarzyna Gwiździel, WUT, katarzyna.gwizdziel@cern.ch + +#ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSESOFTPIONREMOVAL_H_ +#define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSESOFTPIONREMOVAL_H_ + +#include + +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" +#include "Framework/HistogramRegistry.h" + +namespace o2::analysis::femto_universe +{ + +/// \class FemtoUniverseSoftPionRemoval +/// \brief Class taking care of removing soft pions from D* decays +/// \tparam partOne Type of particle 1 (Track/D0/...) +/// \tparam partTwo Type of particle 2 (Track/D0/...) +template +class FemtoUniverseSoftPionRemoval +{ + public: + /// Destructor + virtual ~FemtoUniverseSoftPionRemoval() = default; + + /// Initialization of the QA histograms + /// \param registry HistogramRegistry + void init(HistogramRegistry* registry) + { + if (registry) { + mHistogramRegistry = registry; + mHistogramRegistry->add("SoftPion/softPionMassVsPt", "; M(K#pi#pi-K#pi); p_{T}", kTH2F, {{200, 0.0, 0.2}, {36, 0., 36.}}); + } + } + + /// Check whether a track is a soft pion from D* decay + /// \tparam Part Data type of the particle + /// \tparam Parts Data type of the collection of all particles + /// \param part1 Particle 1 + /// \param part2 Particle 2 + /// \param particles Collection of all particles passed to the task + /// \return Whether the track is a soft pion + template + bool isSoftPion(Part const& part1, Part const& part2, Parts const& particles, bool isD0Cand, bool isD0barCand, double sigma) + { + if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kD0) { + /// Track-D0 combination part1 is hadron and part2 is D0 + if (part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kD0) { + LOG(fatal) << "FemtoUniverseSoftPionRemoval: passed arguments don't agree with FemtoUniverseSoftPionRemoval instantiation! Please provide second argument kD0 candidate."; + return false; + } + // Getting D0 (part2) children + const auto& posChild = particles.iteratorAt(part2.index() - 2); + const auto& negChild = particles.iteratorAt(part2.index() - 1); + // Pion and kaon mass + double massPion = o2::constants::physics::MassPiPlus; + double massKaon = o2::constants::physics::MassKPlus; + // D* reconstruction + double pSum2 = std::pow(posChild.px() + negChild.px() + part1.px(), 2.0) + std::pow(posChild.py() + negChild.py() + part1.py(), 2.0) + std::pow(posChild.pz() + negChild.pz() + part1.pz(), 2.0); + // Energies of the daughters -> D0->K-pi+ + double e1Pi = std::sqrt(std::pow(massPion, 2.0) + std::pow(posChild.px(), 2.0) + std::pow(posChild.py(), 2.0) + std::pow(posChild.pz(), 2.0)); + double e1K = std::sqrt(std::pow(massKaon, 2.0) + std::pow(negChild.px(), 2.0) + std::pow(negChild.py(), 2.0) + std::pow(negChild.pz(), 2.0)); + // Energies of the daughters -> D0bar->K+pi- + double e2Pi = std::sqrt(std::pow(massPion, 2.0) + std::pow(negChild.px(), 2.0) + std::pow(negChild.py(), 2.0) + std::pow(negChild.pz(), 2.0)); + double e2K = std::sqrt(std::pow(massKaon, 2.0) + std::pow(posChild.px(), 2.0) + std::pow(posChild.py(), 2.0) + std::pow(posChild.pz(), 2.0)); + // Soft pion energy + auto ePion = RecoDecay::e(massPion, part1.p()); + // D* masses + double mDstar1 = std::sqrt(std::pow(e1Pi + e1K + ePion, 2.0) - pSum2); + double mDstar2 = std::sqrt(std::pow(e2Pi + e2K + ePion, 2.0) - pSum2); + + bool isSoftPion = false; + double softPiMass = 0.14542; // pion mass in D*->D0pi decay + double lowMassLimitSoftPion = softPiMass - 3.0 * sigma; + double highMassLimitSoftPion = softPiMass + 3.0 * sigma; + + if (isD0Cand) { + if (mDstar1 - part2.mLambda() > 0.) { + mHistogramRegistry->fill(HIST("SoftPion/softPionMassVsPt"), mDstar1 - part2.mLambda(), part2.pt()); + } + if ((std::abs(mDstar1 - part2.mLambda()) > lowMassLimitSoftPion) && (std::abs(mDstar1 - part2.mLambda()) < highMassLimitSoftPion)) { + isSoftPion = true; + } + } + + if (isD0barCand) { + if (mDstar2 - part2.mAntiLambda() > 0.) { + mHistogramRegistry->fill(HIST("SoftPion/softPionMassVsPt"), mDstar2 - part2.mAntiLambda(), part2.pt()); + } + if ((std::abs(mDstar2 - part2.mAntiLambda()) > lowMassLimitSoftPion) && (std::abs(mDstar2 - part2.mAntiLambda()) < highMassLimitSoftPion)) { + isSoftPion = true; + } + } + return isSoftPion; + } else { + LOG(fatal) << "FemtoUniverseSoftPionRemoval: Combination of objects not defined - quitting!"; + return false; + } + } + + private: + HistogramRegistry* mHistogramRegistry; ///< For QA output + static constexpr o2::aod::femtouniverseparticle::ParticleType kPartOneType = partOne; ///< Type of particle 1 + static constexpr o2::aod::femtouniverseparticle::ParticleType kPartTwoType = partTwo; ///< Type of particle 2 +}; +} // namespace o2::analysis::femto_universe + +#endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSESOFTPIONREMOVAL_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseSpherHarMath.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseSpherHarMath.h new file mode 100644 index 00000000000..bb0e8bdaf22 --- /dev/null +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseSpherHarMath.h @@ -0,0 +1,223 @@ +// Copyright 2019-2022 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 FemtoUniverseSpherHarMath.h +/// \brief Definition of the FemtoUniverseMath Container for the calculations of spherical harmonics components +/// \author Pritam Chakraborty, WUT Warsaw, pritam.chakraborty@pw.edu.pl + +#ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSESPHERHARMATH_H_ +#define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSESPHERHARMATH_H_ + +#include +#include + +#include "Math/Vector4D.h" +#include "Math/Boost.h" +#include "TLorentzVector.h" +#include "TMath.h" + +namespace o2::analysis::femto_universe +{ + +/// \class FemtoUniverseMath +/// \brief Container for math calculations of quantities related to pairs +class FemtoUniverseSpherHarMath +{ + public: + /// Values of various coefficients + void initializeYlms() + { + double oneoversqrtpi = 1.0 / std::sqrt(o2::constants::math::PI); + + // l=0 prefactors + fgPrefactors[0] = 0.5 * oneoversqrtpi; + + // l=1 prefactors + fgPrefactors[1] = 0.5 * std::sqrt(3.0 / 2.0) * oneoversqrtpi; + fgPrefactors[2] = 0.5 * std::sqrt(3.0) * oneoversqrtpi; + fgPrefactors[3] = -fgPrefactors[1]; + + // l=2 prefactors + fgPrefactors[4] = 0.25 * std::sqrt(15.0 / 2.0) * oneoversqrtpi; + fgPrefactors[5] = 0.5 * std::sqrt(15.0 / 2.0) * oneoversqrtpi; + fgPrefactors[6] = 0.25 * std::sqrt(5.0) * oneoversqrtpi; + fgPrefactors[7] = -fgPrefactors[5]; + fgPrefactors[8] = fgPrefactors[4]; + + // l=3 prefactors + fgPrefactors[9] = 0.125 * std::sqrt(35.0) * oneoversqrtpi; + fgPrefactors[10] = 0.25 * std::sqrt(105.0 / 2.0) * oneoversqrtpi; + fgPrefactors[11] = 0.125 * std::sqrt(21.0) * oneoversqrtpi; + fgPrefactors[12] = 0.25 * std::sqrt(7.0) * oneoversqrtpi; + fgPrefactors[13] = -fgPrefactors[11]; + fgPrefactors[14] = fgPrefactors[10]; + fgPrefactors[15] = -fgPrefactors[9]; + + // l=4 prefactors + fgPrefactors[16] = 3.0 / 16.0 * std::sqrt(35.0 / 2.0) * oneoversqrtpi; + fgPrefactors[17] = 3.0 / 8.0 * std::sqrt(35.0) * oneoversqrtpi; + fgPrefactors[18] = 3.0 / 8.0 * std::sqrt(5.0 / 2.0) * oneoversqrtpi; + fgPrefactors[19] = 3.0 / 8.0 * std::sqrt(5.0) * oneoversqrtpi; + fgPrefactors[20] = 3.0 / 16.0 * oneoversqrtpi; + fgPrefactors[21] = -fgPrefactors[19]; + fgPrefactors[22] = fgPrefactors[18]; + fgPrefactors[23] = -fgPrefactors[17]; + fgPrefactors[24] = fgPrefactors[16]; + + // l=5 prefactors + fgPrefactors[25] = 3.0 / 32.0 * std::sqrt(77.0) * oneoversqrtpi; + fgPrefactors[26] = 3.0 / 16.0 * std::sqrt(385.0 / 2.0) * oneoversqrtpi; + fgPrefactors[27] = 1.0 / 32.0 * std::sqrt(385.0) * oneoversqrtpi; + fgPrefactors[28] = 1.0 / 8.0 * std::sqrt(1155.0 / 2.0) * oneoversqrtpi; + fgPrefactors[29] = 1.0 / 16.0 * std::sqrt(165.0 / 2.0) * oneoversqrtpi; + fgPrefactors[30] = 1.0 / 16.0 * std::sqrt(11.0) * oneoversqrtpi; + fgPrefactors[31] = -fgPrefactors[29]; + fgPrefactors[32] = fgPrefactors[28]; + fgPrefactors[33] = -fgPrefactors[27]; + fgPrefactors[34] = fgPrefactors[26]; + fgPrefactors[35] = -fgPrefactors[25]; + + fgPrefshift[0] = 0; + fgPrefshift[1] = 2; + fgPrefshift[2] = 6; + fgPrefshift[3] = 12; + fgPrefshift[4] = 20; + fgPrefshift[5] = 30; + + fgPlmshift[0] = 0; + fgPlmshift[1] = 2; + fgPlmshift[2] = 5; + fgPlmshift[3] = 9; + fgPlmshift[4] = 14; + fgPlmshift[5] = 20; + } + + /// Function to calculate Legendre Polynomials + /// \param lmax Maximum value of L component + /// \param ctheta Value of theta + /// \param lbuf values of coefficients + void legendreUpToYlm(int lmax, double ctheta, double* lbuf) + { + // Calculate a set of legendre polynomials up to a given l + // with spherical input + double sins[6]; + double coss[6]; + sins[0] = 0.0; + coss[0] = 1.0; + sins[1] = std::sqrt(1 - ctheta * ctheta); + coss[1] = ctheta; + for (int iter = 2; iter < 6; iter++) { + sins[iter] = sins[iter - 1] * sins[1]; + coss[iter] = coss[iter - 1] * coss[1]; + } + + // Legendre polynomials l=0 + lbuf[0] = 1.0; + + // Legendre polynomials l=1 + if (lmax > 0) { + lbuf[1] = sins[1]; + lbuf[2] = coss[1]; + } + + // Legendre polynomials l=2 + if (lmax > 1) { + lbuf[3] = sins[2]; + lbuf[4] = sins[1] * coss[1]; + lbuf[5] = 3 * coss[2] - 1; + } + + // Legendre polynomials l=3 + if (lmax > 2) { + lbuf[6] = sins[3]; + lbuf[7] = sins[2] * coss[1]; + lbuf[8] = (5 * coss[2] - 1) * sins[1]; + lbuf[9] = 5 * coss[3] - 3 * coss[1]; + } + + // Legendre polynomials l=4 + if (lmax > 3) { + lbuf[10] = sins[4]; + lbuf[11] = sins[3] * coss[1]; + lbuf[12] = (7 * coss[2] - 1) * sins[2]; + lbuf[13] = (7 * coss[3] - 3 * coss[1]) * sins[1]; + lbuf[14] = 35 * coss[4] - 30 * coss[2] + 3; + } + + // Legendre polynomials l=5 + if (lmax > 4) { + lbuf[15] = sins[5]; + lbuf[16] = sins[4] * coss[1]; + lbuf[17] = (9 * coss[2] - 1) * sins[3]; + lbuf[18] = (3 * coss[3] - 1 * coss[1]) * sins[2]; + lbuf[19] = (21 * coss[4] - 14 * coss[2] + 1) * sins[1]; + lbuf[20] = 63 * coss[5] - 70 * coss[3] + 15 * coss[1]; + } + } + + /// Function to calculate a set of Ylms up to a given l with cartesian input + void doYlmUpToL(int lmax, double x, double y, double z, std::complex* ylms) + { + double ctheta, phi; + + double r = std::sqrt(x * x + y * y + z * z); + if (r < 1e-10 || std::fabs(z) < 1e-10) + ctheta = 0.0; + else + ctheta = z / r; + phi = std::atan2(y, x); + doYlmUpToL(lmax, ctheta, phi, ylms); + } + + /// Function to calculate a set of Ylms up to a given l with spherical input + void doYlmUpToL(int lmax, double ctheta, double phi, std::complex* ylms) + { + int lcur = 0; + double lpol; + + double coss[6]; + double sins[6]; + + double lbuf[36]; + legendreUpToYlm(lmax, ctheta, lbuf); + initializeYlms(); + + for (int iter = 1; iter <= lmax; iter++) { + coss[iter - 1] = std::cos(iter * phi); + sins[iter - 1] = std::sin(iter * phi); + } + + ylms[lcur++] = fgPrefactors[0] * lbuf[0] * std::complex(1, 0); + + for (int il = 1; il <= lmax; il++) { + // First im = 0 + ylms[lcur + il] = fgPrefactors[fgPrefshift[il]] * lbuf[static_cast(fgPlmshift[il])] * std::complex(1.0, 0.0); + // Im != 0 + for (int im = 1; im <= il; im++) { + lpol = lbuf[static_cast(fgPlmshift[il]) - im]; + ylms[lcur + il - im] = fgPrefactors[fgPrefshift[il] - im] * lpol * std::complex(coss[im - 1], -sins[im - 1]); + ylms[lcur + il + im] = fgPrefactors[fgPrefshift[il] + im] * lpol * std::complex(coss[im - 1], sins[im - 1]); + } + lcur += 2 * il + 1; + } + } + + private: + static std::complex fCeiphi(double phi); + + std::array fgPrefactors; + std::array fgPrefshift; + std::array fgPlmshift; +}; + +} // namespace o2::analysis::femto_universe + +#endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSESPHERHARMATH_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h index 71086d55b8d..b94a8f85650 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h @@ -9,8 +9,8 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file FemtoUniverseTrackCuts.h -/// \brief Definition of the FemtoUniverseTrackCuts +/// \file FemtoUniverseTrackSelection.h +/// \brief Definition of the FemtoUniverseTrackSelection /// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de /// \author Luca Barioglio, TU München, luca.barioglio@cern.ch /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch @@ -21,7 +21,6 @@ #include #include #include -#include #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -31,27 +30,28 @@ #include "ReconstructionDataFormats/PID.h" #include "Framework/HistogramRegistry.h" -using namespace o2::framework; +// using namespace o2::framework; -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { -namespace femtoUniverseTrackSelection +namespace femto_universe_track_selection { /// The different selections this task is capable of doing -enum TrackSel { kSign, ///< Sign of the track - kpTMin, ///< Min. p_T (GeV/c) - kpTMax, ///< Max. p_T (GeV/c) - kEtaMax, ///< Max. |eta| - kTPCnClsMin, ///< Min. number of TPC clusters - kTPCfClsMin, ///< Min. fraction of crossed rows/findable TPC clusters - kTPCcRowsMin, ///< Min. number of crossed TPC rows - kTPCsClsMax, ///< Max. number of shared TPC clusters - kITSnClsMin, ///< Min. number of ITS clusters - kITSnClsIbMin, ///< Min. number of ITS clusters in the inner barrel - kDCAxyMax, ///< Max. DCA_xy (cm) - kDCAzMax, ///< Max. DCA_z (cm) - kDCAMin, ///< Min. DCA_xyz (cm) - kPIDnSigmaMax ///< Max. |n_sigma| for PID +enum TrackSel { kSign, ///< Sign of the track + kpTMin, ///< Min. p_T (GeV/c) + kpTMax, ///< Max. p_T (GeV/c) + kEtaMax, ///< Max. |eta| + kTPCnClsMin, ///< Min. number of TPC clusters + kTPCfClsMin, ///< Min. fraction of crossed rows/findable TPC clusters + kTPCcRowsMin, ///< Min. number of crossed TPC rows + kTPCsClsMax, ///< Max. number of shared TPC clusters + kTPCfracsClsMax, ///< Max. number of fraction of shared TPC clusters + kITSnClsMin, ///< Min. number of ITS clusters + kITSnClsIbMin, ///< Min. number of ITS clusters in the inner barrel + kDCAxyMax, ///< Max. DCA_xy (cm) + kDCAzMax, ///< Max. DCA_z (cm) + kDCAMin, ///< Min. DCA_xyz (cm) + kPIDnSigmaMax ///< Max. |n_sigma| for PID }; enum TrackContainerPosition { @@ -59,11 +59,11 @@ enum TrackContainerPosition { kPID }; /// Position in the full track cut container -} // namespace femtoUniverseTrackSelection +} // namespace femto_universe_track_selection /// \class FemtoUniverseTrackCuts /// \brief Cut class to contain and execute all cuts applied to tracks -class FemtoUniverseTrackSelection : public FemtoUniverseObjectSelection +class FemtoUniverseTrackSelection : public FemtoUniverseObjectSelection { public: FemtoUniverseTrackSelection() : nRejectNotPropagatedTracks(false), @@ -87,6 +87,7 @@ class FemtoUniverseTrackSelection : public FemtoUniverseObjectSelection + template void init(HistogramRegistry* registry); /// Passes the species to the task for which PID needs to be stored @@ -109,8 +110,8 @@ class FemtoUniverseTrackSelection : public FemtoUniverseObjectSelection tmpPids = pids; /// necessary due to some features of the configurable - for (o2::track::PID pid : tmpPids) { - mPIDspecies.push_back(pid); + for (const o2::track::PID pid : tmpPids) { + kPIDspecies.push_back(pid); } } @@ -139,12 +140,12 @@ class FemtoUniverseTrackSelection : public FemtoUniverseObjectSelection - std::array getCutContainer(T const& track); + template + std::array getCutContainer(T const& track); /// Some basic QA histograms /// \tparam part Type of the particle for proper naming of the folders for QA @@ -158,10 +159,10 @@ class FemtoUniverseTrackSelection : public FemtoUniverseObjectSelection(prefix); - outString += static_cast(mSelectionNames[iSel]); + outString += static_cast(kSelectionNames[iSel]); outString += suffix; return outString; } @@ -172,7 +173,7 @@ class FemtoUniverseTrackSelection : public FemtoUniverseObjectSelection(prefix) + static_cast(mSelectionNames[index]); + std::string comp = static_cast(prefix) + static_cast(kSelectionNames[index]); std::string_view cmp{comp}; if (obs.compare(cmp) == 0) return index; @@ -182,18 +183,18 @@ class FemtoUniverseTrackSelection : public FemtoUniverseObjectSelection(prefix); - outString += static_cast(mSelectionHelper[iSel]); + outString += static_cast(kSelectionHelper[iSel]); return outString; } @@ -221,6 +222,7 @@ class FemtoUniverseTrackSelection : public FemtoUniverseObjectSelection mPIDspecies; ///< All the particle species for which the n_sigma values need to be stored - static constexpr int kNtrackSelection = 14; - static constexpr std::string_view mSelectionNames[kNtrackSelection] = {"Sign", + std::vector kPIDspecies; ///< All the particle species for which the n_sigma values need to be stored + static constexpr int kNtrackSelection = 15; + static constexpr std::string_view kSelectionNames[kNtrackSelection] = {"Sign", "PtMin", "PtMax", "EtaMax", @@ -252,6 +255,7 @@ class FemtoUniverseTrackSelection : public FemtoUniverseObjectSelection +template void FemtoUniverseTrackSelection::init(HistogramRegistry* registry) { if (registry) { @@ -298,20 +304,21 @@ void FemtoUniverseTrackSelection::init(HistogramRegistry* registry) std::string folderName = static_cast(o2::aod::femtouniverseparticle::ParticleTypeName[part]) + "/" + static_cast(o2::aod::femtouniverseparticle::TrackTypeName[tracktype]); /// check whether the number of selection exceeds the bitmap size - unsigned int nSelections = getNSelections() - getNSelections(femtoUniverseTrackSelection::kPIDnSigmaMax); - if (nSelections > 8 * sizeof(cutContainerType)) { + unsigned int nSelections = getNSelections() - getNSelections(femto_universe_track_selection::kPIDnSigmaMax); + if (nSelections > 8 * sizeof(CutContainerType)) { LOG(fatal) << "FemtoUniverseTrackCuts: Number of selections too large for your container - quitting!"; } mHistogramRegistry->add((folderName + "/hPt").c_str(), "; #it{p}_{T} (GeV/#it{c}); Entries", kTH1F, {{240, 0, 6}}); mHistogramRegistry->add((folderName + "/hEta").c_str(), "; #eta; Entries", kTH1F, {{200, -1.5, 1.5}}); - mHistogramRegistry->add((folderName + "/hPhi").c_str(), "; #phi; Entries", kTH1F, {{200, 0, 2. * M_PI}}); + mHistogramRegistry->add((folderName + "/hPhi").c_str(), "; #phi; Entries", kTH1F, {{200, 0, o2::constants::math::TwoPI}}); mHistogramRegistry->add((folderName + "/hTPCfindable").c_str(), "; TPC findable clusters; Entries", kTH1F, {{163, -0.5, 162.5}}); mHistogramRegistry->add((folderName + "/hTPCfound").c_str(), "; TPC found clusters; Entries", kTH1F, {{163, -0.5, 162.5}}); mHistogramRegistry->add((folderName + "/hTPCcrossedOverFindalbe").c_str(), "; TPC ratio findable; Entries", kTH1F, {{100, 0.5, 1.5}}); mHistogramRegistry->add((folderName + "/hTPCcrossedRows").c_str(), "; TPC crossed rows; Entries", kTH1F, {{163, 0, 163}}); mHistogramRegistry->add((folderName + "/hTPCfindableVsCrossed").c_str(), ";TPC findable clusters ; TPC crossed rows;", kTH2F, {{163, 0, 163}, {163, 0, 163}}); mHistogramRegistry->add((folderName + "/hTPCshared").c_str(), "; TPC shared clusters; Entries", kTH1F, {{163, -0.5, 162.5}}); + mHistogramRegistry->add((folderName + "/hTPCfractionSharedCls").c_str(), "; TPC fraction of shared clusters; Entries", kTH1F, {{100, 0.0, 100.0}}); mHistogramRegistry->add((folderName + "/hITSclusters").c_str(), "; ITS clusters; Entries", kTH1F, {{10, -0.5, 9.5}}); mHistogramRegistry->add((folderName + "/hITSclustersIB").c_str(), "; ITS clusters in IB; Entries", kTH1F, {{10, -0.5, 9.5}}); mHistogramRegistry->add((folderName + "/hDCAxy").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {{100, 0, 10}, {500, -5, 5}}); @@ -335,33 +342,35 @@ void FemtoUniverseTrackSelection::init(HistogramRegistry* registry) mHistogramRegistry->add((folderName + "/nSigmaComb_d").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{d}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); } /// set cuts - nPtMinSel = getNSelections(femtoUniverseTrackSelection::kpTMin); - nPtMaxSel = getNSelections(femtoUniverseTrackSelection::kpTMax); - nEtaSel = getNSelections(femtoUniverseTrackSelection::kEtaMax); - nTPCnMinSel = getNSelections(femtoUniverseTrackSelection::kTPCnClsMin); - nTPCfMinSel = getNSelections(femtoUniverseTrackSelection::kTPCfClsMin); - nTPCcMinSel = getNSelections(femtoUniverseTrackSelection::kTPCcRowsMin); - nTPCsMaxSel = getNSelections(femtoUniverseTrackSelection::kTPCsClsMax); - nITScMinSel = getNSelections(femtoUniverseTrackSelection::kITSnClsMin); - nITScIbMinSel = getNSelections(femtoUniverseTrackSelection::kITSnClsIbMin); - nDCAxyMaxSel = getNSelections(femtoUniverseTrackSelection::kDCAxyMax); - nDCAzMaxSel = getNSelections(femtoUniverseTrackSelection::kDCAzMax); - nDCAMinSel = getNSelections(femtoUniverseTrackSelection::kDCAMin); - nPIDnSigmaSel = getNSelections(femtoUniverseTrackSelection::kPIDnSigmaMax); - - pTMin = getMinimalSelection(femtoUniverseTrackSelection::kpTMin, femtoUniverseSelection::kLowerLimit); - pTMax = getMinimalSelection(femtoUniverseTrackSelection::kpTMax, femtoUniverseSelection::kUpperLimit); - etaMax = getMinimalSelection(femtoUniverseTrackSelection::kEtaMax, femtoUniverseSelection::kAbsUpperLimit); - nClsMin = getMinimalSelection(femtoUniverseTrackSelection::kTPCnClsMin, femtoUniverseSelection::kLowerLimit); - fClsMin = getMinimalSelection(femtoUniverseTrackSelection::kTPCfClsMin, femtoUniverseSelection::kLowerLimit); - cTPCMin = getMinimalSelection(femtoUniverseTrackSelection::kTPCcRowsMin, femtoUniverseSelection::kLowerLimit); - sTPCMax = getMinimalSelection(femtoUniverseTrackSelection::kTPCsClsMax, femtoUniverseSelection::kUpperLimit); - nITSclsMin = getMinimalSelection(femtoUniverseTrackSelection::kITSnClsMin, femtoUniverseSelection::kLowerLimit); - nITSclsIbMin = getMinimalSelection(femtoUniverseTrackSelection::kITSnClsIbMin, femtoUniverseSelection::kLowerLimit); - dcaXYMax = getMinimalSelection(femtoUniverseTrackSelection::kDCAxyMax, femtoUniverseSelection::kAbsUpperLimit); - dcaZMax = getMinimalSelection(femtoUniverseTrackSelection::kDCAzMax, femtoUniverseSelection::kAbsUpperLimit); - dcaMin = getMinimalSelection(femtoUniverseTrackSelection::kDCAMin, femtoUniverseSelection::kAbsLowerLimit); - nSigmaPIDMax = getMinimalSelection(femtoUniverseTrackSelection::kPIDnSigmaMax, femtoUniverseSelection::kAbsUpperLimit); + nPtMinSel = getNSelections(femto_universe_track_selection::kpTMin); + nPtMaxSel = getNSelections(femto_universe_track_selection::kpTMax); + nEtaSel = getNSelections(femto_universe_track_selection::kEtaMax); + nTPCnMinSel = getNSelections(femto_universe_track_selection::kTPCnClsMin); + nTPCfMinSel = getNSelections(femto_universe_track_selection::kTPCfClsMin); + nTPCcMinSel = getNSelections(femto_universe_track_selection::kTPCcRowsMin); + nTPCsMaxSel = getNSelections(femto_universe_track_selection::kTPCsClsMax); + nTPCsFracMaxSel = getNSelections(femto_universe_track_selection::kTPCfracsClsMax); + nITScMinSel = getNSelections(femto_universe_track_selection::kITSnClsMin); + nITScIbMinSel = getNSelections(femto_universe_track_selection::kITSnClsIbMin); + nDCAxyMaxSel = getNSelections(femto_universe_track_selection::kDCAxyMax); + nDCAzMaxSel = getNSelections(femto_universe_track_selection::kDCAzMax); + nDCAMinSel = getNSelections(femto_universe_track_selection::kDCAMin); + nPIDnSigmaSel = getNSelections(femto_universe_track_selection::kPIDnSigmaMax); + + pTMin = getMinimalSelection(femto_universe_track_selection::kpTMin, femto_universe_selection::kLowerLimit); + pTMax = getMinimalSelection(femto_universe_track_selection::kpTMax, femto_universe_selection::kUpperLimit); + etaMax = getMinimalSelection(femto_universe_track_selection::kEtaMax, femto_universe_selection::kAbsUpperLimit); + nClsMin = getMinimalSelection(femto_universe_track_selection::kTPCnClsMin, femto_universe_selection::kLowerLimit); + fClsMin = getMinimalSelection(femto_universe_track_selection::kTPCfClsMin, femto_universe_selection::kLowerLimit); + cTPCMin = getMinimalSelection(femto_universe_track_selection::kTPCcRowsMin, femto_universe_selection::kLowerLimit); + sTPCMax = getMinimalSelection(femto_universe_track_selection::kTPCsClsMax, femto_universe_selection::kUpperLimit); + fracsTPCMax = getMinimalSelection(femto_universe_track_selection::kTPCfracsClsMax, femto_universe_selection::kUpperLimit); + nITSclsMin = getMinimalSelection(femto_universe_track_selection::kITSnClsMin, femto_universe_selection::kLowerLimit); + nITSclsIbMin = getMinimalSelection(femto_universe_track_selection::kITSnClsIbMin, femto_universe_selection::kLowerLimit); + dcaXYMax = getMinimalSelection(femto_universe_track_selection::kDCAxyMax, femto_universe_selection::kAbsUpperLimit); + dcaZMax = getMinimalSelection(femto_universe_track_selection::kDCAzMax, femto_universe_selection::kAbsUpperLimit); + dcaMin = getMinimalSelection(femto_universe_track_selection::kDCAMin, femto_universe_selection::kAbsLowerLimit); + nSigmaPIDMax = getMinimalSelection(femto_universe_track_selection::kPIDnSigmaMax, femto_universe_selection::kAbsUpperLimit); } template @@ -390,6 +399,7 @@ bool FemtoUniverseTrackSelection::isSelectedMinimal(T const& track) const auto tpcRClsC = track.tpcCrossedRowsOverFindableCls(); const auto tpcNClsC = track.tpcNClsCrossedRows(); const auto tpcNClsS = track.tpcNClsShared(); + const auto tpcNClsFracS = track.tpcFractionSharedCls(); const auto itsNCls = track.itsNCls(); const auto itsNClsIB = track.itsNClsInnerBarrel(); const auto dcaXY = track.dcaXY(); @@ -397,7 +407,7 @@ bool FemtoUniverseTrackSelection::isSelectedMinimal(T const& track) const auto dca = track.dcaXY(); // Accordingly to FemtoUniverse in AliPhysics as well as LF analysis, // only dcaXY should be checked; NOT std::sqrt(pow(dcaXY, 2.) + pow(dcaZ, 2.)) std::vector pidTPC, pidTOF; - for (auto it : mPIDspecies) { + for (const auto it : kPIDspecies) { pidTPC.push_back(getNsigmaTPC(track, it)); pidTOF.push_back(getNsigmaTOF(track, it)); } @@ -423,6 +433,9 @@ bool FemtoUniverseTrackSelection::isSelectedMinimal(T const& track) if (nTPCsMaxSel > 0 && tpcNClsS > sTPCMax) { return false; } + if (nTPCsFracMaxSel > 0 && tpcNClsFracS > fracsTPCMax) { + return false; + } if (nITScMinSel > 0 && itsNCls < nITSclsMin) { return false; } @@ -457,12 +470,12 @@ bool FemtoUniverseTrackSelection::isSelectedMinimal(T const& track) return true; } -template -std::array FemtoUniverseTrackSelection::getCutContainer(T const& track) +template +std::array FemtoUniverseTrackSelection::getCutContainer(T const& track) { - cutContainerType output = 0; + CutContainerType output = 0; size_t counter = 0; - cutContainerType outputPID = 0; + CutContainerType outputPID = 0; const auto sign = track.sign(); const auto pT = track.pt(); const auto eta = track.eta(); @@ -470,14 +483,15 @@ std::array FemtoUniverseTrackSelection::getCutContainer(T c const auto tpcRClsC = track.tpcCrossedRowsOverFindableCls(); const auto tpcNClsC = track.tpcNClsCrossedRows(); const auto tpcNClsS = track.tpcNClsShared(); + const auto tpcNClsFracS = track.tpcFractionSharedCls(); const auto itsNCls = track.itsNCls(); const auto itsNClsIB = track.itsNClsInnerBarrel(); const auto dcaXY = track.dcaXY(); const auto dcaZ = track.dcaZ(); - const auto dca = std::sqrt(pow(dcaXY, 2.) + pow(dcaZ, 2.)); + const auto dca = std::sqrt(std::pow(dcaXY, 2.) + std::pow(dcaZ, 2.)); std::vector pidTPC, pidTOF; - for (auto it : mPIDspecies) { + for (auto it : kPIDspecies) { pidTPC.push_back(getNsigmaTPC(track, it)); pidTOF.push_back(getNsigmaTOF(track, it)); } @@ -485,9 +499,9 @@ std::array FemtoUniverseTrackSelection::getCutContainer(T c float observable = 0.; for (auto& sel : mSelections) { const auto selVariable = sel.getSelectionVariable(); - if (selVariable == femtoUniverseTrackSelection::kPIDnSigmaMax) { + if (selVariable == femto_universe_track_selection::kPIDnSigmaMax) { /// PID needs to be handled a bit differently since we may need more than one species - for (size_t i = 0; i < mPIDspecies.size(); ++i) { + for (size_t i = 0; i < kPIDspecies.size(); ++i) { auto pidTPCVal = pidTPC.at(i) - nSigmaPIDOffsetTPC; auto pidTOFVal = pidTOF.at(i) - nSigmaPIDOffsetTOF; auto pidComb = std::sqrt(pidTPCVal * pidTPCVal + pidTOFVal * pidTOFVal); @@ -498,44 +512,47 @@ std::array FemtoUniverseTrackSelection::getCutContainer(T c } else { /// for the rest it's all the same switch (selVariable) { - case (femtoUniverseTrackSelection::kSign): + case (femto_universe_track_selection::kSign): observable = sign; break; - case (femtoUniverseTrackSelection::kpTMin): - case (femtoUniverseTrackSelection::kpTMax): + case (femto_universe_track_selection::kpTMin): + case (femto_universe_track_selection::kpTMax): observable = pT; break; - case (femtoUniverseTrackSelection::kEtaMax): + case (femto_universe_track_selection::kEtaMax): observable = eta; break; - case (femtoUniverseTrackSelection::kTPCnClsMin): + case (femto_universe_track_selection::kTPCnClsMin): observable = tpcNClsF; break; - case (femtoUniverseTrackSelection::kTPCfClsMin): + case (femto_universe_track_selection::kTPCfClsMin): observable = tpcRClsC; break; - case (femtoUniverseTrackSelection::kTPCcRowsMin): + case (femto_universe_track_selection::kTPCcRowsMin): observable = tpcNClsC; break; - case (femtoUniverseTrackSelection::kTPCsClsMax): + case (femto_universe_track_selection::kTPCsClsMax): observable = tpcNClsS; break; - case (femtoUniverseTrackSelection::kITSnClsMin): + case (femto_universe_track_selection::kTPCfracsClsMax): + observable = tpcNClsFracS; + break; + case (femto_universe_track_selection::kITSnClsMin): observable = itsNCls; break; - case (femtoUniverseTrackSelection::kITSnClsIbMin): + case (femto_universe_track_selection::kITSnClsIbMin): observable = itsNClsIB; break; - case (femtoUniverseTrackSelection::kDCAxyMax): + case (femto_universe_track_selection::kDCAxyMax): observable = dcaXY; break; - case (femtoUniverseTrackSelection::kDCAzMax): + case (femto_universe_track_selection::kDCAzMax): observable = dcaZ; break; - case (femtoUniverseTrackSelection::kDCAMin): + case (femto_universe_track_selection::kDCAMin): observable = dca; break; - case (femtoUniverseTrackSelection::kPIDnSigmaMax): + case (femto_universe_track_selection::kPIDnSigmaMax): break; } sel.checkSelectionSetBit(observable, output, counter); @@ -557,11 +574,12 @@ void FemtoUniverseTrackSelection::fillQA(T const& track) mHistogramRegistry->fill(HIST(o2::aod::femtouniverseparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtouniverseparticle::TrackTypeName[tracktype]) + HIST("/hTPCcrossedRows"), track.tpcNClsCrossedRows()); mHistogramRegistry->fill(HIST(o2::aod::femtouniverseparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtouniverseparticle::TrackTypeName[tracktype]) + HIST("/hTPCfindableVsCrossed"), track.tpcNClsFindable(), track.tpcNClsCrossedRows()); mHistogramRegistry->fill(HIST(o2::aod::femtouniverseparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtouniverseparticle::TrackTypeName[tracktype]) + HIST("/hTPCshared"), track.tpcNClsShared()); + mHistogramRegistry->fill(HIST(o2::aod::femtouniverseparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtouniverseparticle::TrackTypeName[tracktype]) + HIST("/hTPCfractionSharedCls"), track.tpcFractionSharedCls()); mHistogramRegistry->fill(HIST(o2::aod::femtouniverseparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtouniverseparticle::TrackTypeName[tracktype]) + HIST("/hITSclusters"), track.itsNCls()); mHistogramRegistry->fill(HIST(o2::aod::femtouniverseparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtouniverseparticle::TrackTypeName[tracktype]) + HIST("/hITSclustersIB"), track.itsNClsInnerBarrel()); mHistogramRegistry->fill(HIST(o2::aod::femtouniverseparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtouniverseparticle::TrackTypeName[tracktype]) + HIST("/hDCAxy"), track.pt(), track.dcaXY()); mHistogramRegistry->fill(HIST(o2::aod::femtouniverseparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtouniverseparticle::TrackTypeName[tracktype]) + HIST("/hDCAz"), track.pt(), track.dcaZ()); - mHistogramRegistry->fill(HIST(o2::aod::femtouniverseparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtouniverseparticle::TrackTypeName[tracktype]) + HIST("/hDCA"), track.pt(), std::sqrt(pow(track.dcaXY(), 2.) + pow(track.dcaZ(), 2.))); + mHistogramRegistry->fill(HIST(o2::aod::femtouniverseparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtouniverseparticle::TrackTypeName[tracktype]) + HIST("/hDCA"), track.pt(), std::sqrt(std::pow(track.dcaXY(), 2.) + std::pow(track.dcaZ(), 2.))); mHistogramRegistry->fill(HIST(o2::aod::femtouniverseparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtouniverseparticle::TrackTypeName[tracktype]) + HIST("/hTPCdEdX"), track.p(), track.tpcSignal()); mHistogramRegistry->fill(HIST(o2::aod::femtouniverseparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtouniverseparticle::TrackTypeName[tracktype]) + HIST("/nSigmaTPC_el"), track.p(), track.tpcNSigmaEl()); mHistogramRegistry->fill(HIST(o2::aod::femtouniverseparticle::ParticleTypeName[part]) + HIST("/") + HIST(o2::aod::femtouniverseparticle::TrackTypeName[tracktype]) + HIST("/nSigmaTPC_pi"), track.p(), track.tpcNSigmaPi()); @@ -581,6 +599,6 @@ void FemtoUniverseTrackSelection::fillQA(T const& track) } } -} // namespace o2::analysis::femtoUniverse +} // namespace o2::analysis::femto_universe #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSETRACKSELECTION_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUniverseV0Selection.h b/PWGCF/FemtoUniverse/Core/FemtoUniverseV0Selection.h index 642b11c116f..aa2aad31d23 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseV0Selection.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseV0Selection.h @@ -19,12 +19,9 @@ #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEV0SELECTION_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEV0SELECTION_H_ -#include #include #include -#include // FIXME - #include "PWGCF/FemtoUniverse/Core/FemtoUniverseObjectSelection.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseSelection.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" @@ -33,11 +30,9 @@ #include "Framework/HistogramRegistry.h" #include "ReconstructionDataFormats/PID.h" -using namespace o2::framework; - -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { -namespace femtoUniverseV0Selection +namespace femto_universe_v0_selection { /// The different selections this task is capable of doing enum V0Sel { @@ -63,20 +58,20 @@ enum V0ContainerPosition { kNegPID, }; /// Position in the full VO cut container -} // namespace femtoUniverseV0Selection +} // namespace femto_universe_v0_selection /// \class FemtoUniverseV0Selection /// \brief Cut class to contain and execute all cuts applied to V0s class FemtoUniverseV0Selection - : public FemtoUniverseObjectSelection + : public FemtoUniverseObjectSelection { public: FemtoUniverseV0Selection() - : nPtV0MinSel(0), nPtV0MaxSel(0), nEtaV0MaxSel(0), nDCAV0DaughMax(0), nCPAV0Min(0), nTranRadV0Min(0), nTranRadV0Max(0), nDecVtxMax(0), pTV0Min(9999999.), pTV0Max(-9999999.), etaV0Max(-9999999.), DCAV0DaughMax(-9999999.), CPAV0Min(9999999.), TranRadV0Min(9999999.), TranRadV0Max(-9999999.), DecVtxMax(-9999999.), fInvMassLowLimit(1.05), fInvMassUpLimit(1.3), fRejectKaon(false), fInvMassKaonLowLimit(0.48), fInvMassKaonUpLimit(0.515), nSigmaPIDOffsetTPC(0.) {} + : nPtV0MinSel(0), nPtV0MaxSel(0), nEtaV0MaxSel(0), nDCAV0DaughMax(0), nCPAV0Min(0), nTranRadV0Min(0), nTranRadV0Max(0), nDecVtxMax(0), pTV0Min(9999999.), pTV0Max(-9999999.), etaV0Max(-9999999.), kDCAV0DaughMax(-9999999.), kCPAV0Min(9999999.), kTranRadV0Min(9999999.), kTranRadV0Max(-9999999.), kDecVtxMax(-9999999.), fInvMassLowLimit(1.05), fInvMassUpLimit(1.3), fRejectKaon(false), fInvMassKaonLowLimit(0.48), fInvMassKaonUpLimit(0.515), nSigmaPIDOffsetTPC(0.) {} /// Initializes histograms for the task template + typename CutContainerType> void init(HistogramRegistry* registry); template @@ -89,8 +84,8 @@ class FemtoUniverseV0Selection /// \todo for the moment the PID of the tracks is factored out into a separate /// field, hence 5 values in total \\ASK: what does it mean? - template - std::array getCutContainer(C const& col, V const& v0, + template + std::array getCutContainer(C const& col, V const& v0, T const& posTrack, T const& negTrack); @@ -100,23 +95,23 @@ class FemtoUniverseV0Selection void fillQA(C const& col, V const& v0, T const& posTrack, T const& negTrack); template - void setChildCuts(femtoUniverseV0Selection::ChildTrackType child, T1 selVal, - T2 selVar, femtoUniverseSelection::SelectionType selType) + void setChildCuts(femto_universe_v0_selection::ChildTrackType child, T1 selVal, + T2 selVar, femto_universe_selection::SelectionType selType) { - if (child == femtoUniverseV0Selection::kPosTrack) { - PosDaughTrack.setSelection(selVal, selVar, selType); - } else if (child == femtoUniverseV0Selection::kNegTrack) { - NegDaughTrack.setSelection(selVal, selVar, selType); + if (child == femto_universe_v0_selection::kPosTrack) { + posDaughTrack.setSelection(selVal, selVar, selType); + } else if (child == femto_universe_v0_selection::kNegTrack) { + negDaughTrack.setSelection(selVal, selVar, selType); } } template - void setChildPIDSpecies(femtoUniverseV0Selection::ChildTrackType child, + void setChildPIDSpecies(femto_universe_v0_selection::ChildTrackType child, T& pids) { - if (child == femtoUniverseV0Selection::kPosTrack) { - PosDaughTrack.setPIDSpecies(pids); - } else if (child == femtoUniverseV0Selection::kNegTrack) { - NegDaughTrack.setPIDSpecies(pids); + if (child == femto_universe_v0_selection::kPosTrack) { + posDaughTrack.setPIDSpecies(pids); + } else if (child == femto_universe_v0_selection::kNegTrack) { + negDaughTrack.setPIDSpecies(pids); } } @@ -124,12 +119,12 @@ class FemtoUniverseV0Selection /// \param iSel Track selection variable to be examined /// \param prefix Additional prefix for the name of the configurable /// \param suffix Additional suffix for the name of the configurable - static std::string getSelectionName(femtoUniverseV0Selection::V0Sel iSel, + static std::string getSelectionName(femto_universe_v0_selection::V0Sel iSel, std::string_view prefix = "", std::string_view suffix = "") { std::string outString = static_cast(prefix); - outString += static_cast(mSelectionNames[iSel]); + outString += static_cast(kSelectionNames[iSel]); outString += suffix; return outString; } @@ -142,7 +137,7 @@ class FemtoUniverseV0Selection { for (int index = 0; index < kNv0Selection; index++) { std::string comp = static_cast(prefix) + - static_cast(mSelectionNames[index]); + static_cast(kSelectionNames[index]); std::string_view cmp{comp}; if (obs.compare(cmp) == 0) return index; @@ -153,8 +148,7 @@ class FemtoUniverseV0Selection /// Helper function to obtain the type of a given selection variable for consistent naming of the configurables /// \param iSel V0 selection variable whose type is returned - static femtoUniverseSelection::SelectionType - getSelectionType(femtoUniverseV0Selection::V0Sel iSel) + static femto_universe_selection::SelectionType getSelectionType(femto_universe_v0_selection::V0Sel iSel) { return mSelectionTypes[iSel]; } @@ -163,11 +157,11 @@ class FemtoUniverseV0Selection /// for consistent description of the configurables /// \param iSel Track selection variable to be examined /// \param prefix Additional prefix for the output of the configurable - static std::string getSelectionHelper(femtoUniverseV0Selection::V0Sel iSel, + static std::string getSelectionHelper(femto_universe_v0_selection::V0Sel iSel, std::string_view prefix = "") { std::string outString = static_cast(prefix); - outString += static_cast(mSelectionHelper[iSel]); + outString += static_cast(kSelectionHelper[iSel]); return outString; } @@ -195,21 +189,21 @@ class FemtoUniverseV0Selection nSigmaPIDOffsetTPC = offsetTPC; } - void setChildRejectNotPropagatedTracks(femtoUniverseV0Selection::ChildTrackType child, bool reject) + void setChildRejectNotPropagatedTracks(femto_universe_v0_selection::ChildTrackType child, bool reject) { - if (child == femtoUniverseV0Selection::kPosTrack) { - PosDaughTrack.setRejectNotPropagatedTracks(reject); - } else if (child == femtoUniverseV0Selection::kNegTrack) { - NegDaughTrack.setRejectNotPropagatedTracks(reject); + if (child == femto_universe_v0_selection::kPosTrack) { + posDaughTrack.setRejectNotPropagatedTracks(reject); + } else if (child == femto_universe_v0_selection::kNegTrack) { + negDaughTrack.setRejectNotPropagatedTracks(reject); } } - void setChildnSigmaPIDOffset(femtoUniverseV0Selection::ChildTrackType child, float offsetTPC, float offsetTOF) + void setChildnSigmaPIDOffset(femto_universe_v0_selection::ChildTrackType child, float offsetTPC, float offsetTOF) { - if (child == femtoUniverseV0Selection::kPosTrack) { - PosDaughTrack.setnSigmaPIDOffset(offsetTPC, offsetTOF); - } else if (child == femtoUniverseV0Selection::kNegTrack) { - NegDaughTrack.setnSigmaPIDOffset(offsetTPC, offsetTOF); + if (child == femto_universe_v0_selection::kPosTrack) { + posDaughTrack.setnSigmaPIDOffset(offsetTPC, offsetTOF); + } else if (child == femto_universe_v0_selection::kNegTrack) { + negDaughTrack.setnSigmaPIDOffset(offsetTPC, offsetTOF); } } @@ -225,11 +219,11 @@ class FemtoUniverseV0Selection float pTV0Min; float pTV0Max; float etaV0Max; - float DCAV0DaughMax; - float CPAV0Min; - float TranRadV0Min; - float TranRadV0Max; - float DecVtxMax; + float kDCAV0DaughMax; + float kCPAV0Min; + float kTranRadV0Min; + float kTranRadV0Max; + float kDecVtxMax; float fInvMassLowLimit; float fInvMassUpLimit; @@ -240,30 +234,30 @@ class FemtoUniverseV0Selection float nSigmaPIDOffsetTPC; - FemtoUniverseTrackSelection PosDaughTrack; - FemtoUniverseTrackSelection NegDaughTrack; + FemtoUniverseTrackSelection posDaughTrack; + FemtoUniverseTrackSelection negDaughTrack; static constexpr int kNv0Selection = 9; - static constexpr std::string_view mSelectionNames[kNv0Selection] = { + static constexpr std::string_view kSelectionNames[kNv0Selection] = { "Sign", "PtMin", "PtMax", "EtaMax", "DCAdaughMax", "CPAMin", "TranRadMin", "TranRadMax", "DecVecMax"}; ///< Name of the different ///< selections - static constexpr femtoUniverseSelection::SelectionType + static constexpr femto_universe_selection::SelectionType mSelectionTypes[kNv0Selection]{ - femtoUniverseSelection::kEqual, - femtoUniverseSelection::kLowerLimit, - femtoUniverseSelection::kUpperLimit, - femtoUniverseSelection::kUpperLimit, - femtoUniverseSelection::kUpperLimit, - femtoUniverseSelection::kLowerLimit, - femtoUniverseSelection::kLowerLimit, - femtoUniverseSelection::kUpperLimit, - femtoUniverseSelection::kUpperLimit}; ///< Map to match a variable with - ///< its type - - static constexpr std::string_view mSelectionHelper[kNv0Selection] = { + femto_universe_selection::kEqual, + femto_universe_selection::kLowerLimit, + femto_universe_selection::kUpperLimit, + femto_universe_selection::kUpperLimit, + femto_universe_selection::kUpperLimit, + femto_universe_selection::kLowerLimit, + femto_universe_selection::kLowerLimit, + femto_universe_selection::kUpperLimit, + femto_universe_selection::kUpperLimit}; ///< Map to match a variable with + ///< its type + + static constexpr std::string_view kSelectionHelper[kNv0Selection] = { "+1 for lambda, -1 for antilambda", "Minimum pT (GeV/c)", "Maximum pT (GeV/c)", @@ -275,11 +269,11 @@ class FemtoUniverseV0Selection "Maximum distance from primary vertex"}; ///< Helper information for the ///< different selections -}; // namespace femtoUniverse +}; // namespace femto_universe template + typename CutContainerType> void FemtoUniverseV0Selection::init(HistogramRegistry* registry) { if (registry) { @@ -294,7 +288,7 @@ void FemtoUniverseV0Selection::init(HistogramRegistry* registry) /// \todo this should be an automatic check in the parent class, and the /// return type should be templated size_t nSelections = getNSelections(); - if (nSelections > 8 * sizeof(cutContainerType)) { + if (nSelections > 8 * sizeof(CutContainerType)) { LOG(fatal) << "FemtoUniverseV0Cuts: Number of selections to large for your " "container - quitting!"; } @@ -307,7 +301,7 @@ void FemtoUniverseV0Selection::init(HistogramRegistry* registry) mHistogramRegistry->add((folderName + "/hEta").c_str(), "; #eta; Entries", kTH1F, {{1000, -1, 1}}); mHistogramRegistry->add((folderName + "/hPhi").c_str(), "; #phi; Entries", - kTH1F, {{1000, 0, 2. * M_PI}}); + kTH1F, {{1000, 0, o2::constants::math::TwoPI}}); mHistogramRegistry->add((folderName + "/hDaughDCA").c_str(), "; DCA^{daugh} (cm); Entries", kTH1F, {{1000, 0, 10}}); @@ -335,14 +329,18 @@ void FemtoUniverseV0Selection::init(HistogramRegistry* registry) kTH1F, {massAxisAntiLambda}); mHistogramRegistry->add((folderName + "/hInvMassLambdaAntiLambda").c_str(), "", kTH2F, {massAxisLambda, massAxisAntiLambda}); + mHistogramRegistry->add((folderName + "/hInvMassAntiLambdavsPt").c_str(), + "; ; #it{p}_{T} (GeV/#it{c})", kTH2F, {massAxisAntiLambda, {8, 0.0, 5.0}}); + mHistogramRegistry->add((folderName + "/hInvMassLambdavsPt").c_str(), + "; ; #it{p}_{T} (GeV/#it{c})", kTH2F, {massAxisLambda, {8, 0.0, 5.0}}); - PosDaughTrack.init( + aod::femtouniverseparticle::CutContainerType>( mHistogramRegistry); - NegDaughTrack.init( + aod::femtouniverseparticle::CutContainerType>( mHistogramRegistry); mHistogramRegistry->add("LambdaQA/hInvMassLambdaNoCuts", "No cuts", kTH1F, @@ -371,31 +369,31 @@ void FemtoUniverseV0Selection::init(HistogramRegistry* registry) } /// check whether the most open cuts are fulfilled - most of this should have /// already be done by the filters - nPtV0MinSel = getNSelections(femtoUniverseV0Selection::kV0pTMin); - nPtV0MaxSel = getNSelections(femtoUniverseV0Selection::kV0pTMax); - nEtaV0MaxSel = getNSelections(femtoUniverseV0Selection::kV0etaMax); - nDCAV0DaughMax = getNSelections(femtoUniverseV0Selection::kV0DCADaughMax); - nCPAV0Min = getNSelections(femtoUniverseV0Selection::kV0CPAMin); - nTranRadV0Min = getNSelections(femtoUniverseV0Selection::kV0TranRadMin); - nTranRadV0Max = getNSelections(femtoUniverseV0Selection::kV0TranRadMax); - nDecVtxMax = getNSelections(femtoUniverseV0Selection::kV0DecVtxMax); - - pTV0Min = getMinimalSelection(femtoUniverseV0Selection::kV0pTMin, - femtoUniverseSelection::kLowerLimit); - pTV0Max = getMinimalSelection(femtoUniverseV0Selection::kV0pTMax, - femtoUniverseSelection::kUpperLimit); - etaV0Max = getMinimalSelection(femtoUniverseV0Selection::kV0etaMax, - femtoUniverseSelection::kAbsUpperLimit); - DCAV0DaughMax = getMinimalSelection(femtoUniverseV0Selection::kV0DCADaughMax, - femtoUniverseSelection::kUpperLimit); - CPAV0Min = getMinimalSelection(femtoUniverseV0Selection::kV0CPAMin, - femtoUniverseSelection::kLowerLimit); - TranRadV0Min = getMinimalSelection(femtoUniverseV0Selection::kV0TranRadMin, - femtoUniverseSelection::kLowerLimit); - TranRadV0Max = getMinimalSelection(femtoUniverseV0Selection::kV0TranRadMax, - femtoUniverseSelection::kUpperLimit); - DecVtxMax = getMinimalSelection(femtoUniverseV0Selection::kV0DecVtxMax, - femtoUniverseSelection::kAbsUpperLimit); + nPtV0MinSel = getNSelections(femto_universe_v0_selection::kV0pTMin); + nPtV0MaxSel = getNSelections(femto_universe_v0_selection::kV0pTMax); + nEtaV0MaxSel = getNSelections(femto_universe_v0_selection::kV0etaMax); + nDCAV0DaughMax = getNSelections(femto_universe_v0_selection::kV0DCADaughMax); + nCPAV0Min = getNSelections(femto_universe_v0_selection::kV0CPAMin); + nTranRadV0Min = getNSelections(femto_universe_v0_selection::kV0TranRadMin); + nTranRadV0Max = getNSelections(femto_universe_v0_selection::kV0TranRadMax); + nDecVtxMax = getNSelections(femto_universe_v0_selection::kV0DecVtxMax); + + pTV0Min = getMinimalSelection(femto_universe_v0_selection::kV0pTMin, + femto_universe_selection::kLowerLimit); + pTV0Max = getMinimalSelection(femto_universe_v0_selection::kV0pTMax, + femto_universe_selection::kUpperLimit); + etaV0Max = getMinimalSelection(femto_universe_v0_selection::kV0etaMax, + femto_universe_selection::kAbsUpperLimit); + kDCAV0DaughMax = getMinimalSelection(femto_universe_v0_selection::kV0DCADaughMax, + femto_universe_selection::kUpperLimit); + kCPAV0Min = getMinimalSelection(femto_universe_v0_selection::kV0CPAMin, + femto_universe_selection::kLowerLimit); + kTranRadV0Min = getMinimalSelection(femto_universe_v0_selection::kV0TranRadMin, + femto_universe_selection::kLowerLimit); + kTranRadV0Max = getMinimalSelection(femto_universe_v0_selection::kV0TranRadMax, + femto_universe_selection::kUpperLimit); + kDecVtxMax = getMinimalSelection(femto_universe_v0_selection::kV0DecVtxMax, + femto_universe_selection::kAbsUpperLimit); } template @@ -441,42 +439,42 @@ bool FemtoUniverseV0Selection::isSelectedMinimal(C const& /*col*/, V const& v0, if (nEtaV0MaxSel > 0 && std::abs(eta) > etaV0Max) { return false; } - if (nDCAV0DaughMax > 0 && dcaDaughv0 > DCAV0DaughMax) { + if (nDCAV0DaughMax > 0 && dcaDaughv0 > kDCAV0DaughMax) { return false; } - if (nCPAV0Min > 0 && cpav0 < CPAV0Min) { + if (nCPAV0Min > 0 && cpav0 < kCPAV0Min) { return false; } - if (nTranRadV0Min > 0 && tranRad < TranRadV0Min) { + if (nTranRadV0Min > 0 && tranRad < kTranRadV0Min) { return false; } - if (nTranRadV0Max > 0 && tranRad > TranRadV0Max) { + if (nTranRadV0Max > 0 && tranRad > kTranRadV0Max) { return false; } for (size_t i = 0; i < decVtx.size(); i++) { - if (nDecVtxMax > 0 && decVtx.at(i) > DecVtxMax) { + if (nDecVtxMax > 0 && decVtx.at(i) > kDecVtxMax) { return false; } } - if (!PosDaughTrack.isSelectedMinimal(posTrack)) { + if (!posDaughTrack.isSelectedMinimal(posTrack)) { return false; } - if (!NegDaughTrack.isSelectedMinimal(negTrack)) { + if (!negDaughTrack.isSelectedMinimal(negTrack)) { return false; } // check that track combinations for V0 or antiV0 would be fulfilling PID - float nSigmaPIDMax = PosDaughTrack.getSigmaPIDMax(); + float nSigmaPIDMax = posDaughTrack.getSigmaPIDMax(); // antiV0 auto nSigmaPrNeg = negTrack.tpcNSigmaPr(); auto nSigmaPiPos = posTrack.tpcNSigmaPi(); // v0 auto nSigmaPiNeg = negTrack.tpcNSigmaPi(); auto nSigmaPrPos = posTrack.tpcNSigmaPr(); - if (!(abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && - abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax) && - !(abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && - abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax)) { + if (!(std::abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && + std::abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax) && + !(std::abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && + std::abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax)) { return false; } @@ -521,24 +519,24 @@ void FemtoUniverseV0Selection::fillLambdaQA(C const& /*col*/, V const& v0, mHistogramRegistry->fill(HIST("LambdaQA/hInvMassLambdaEtaMax"), v0.mLambda()); } - if (dcaDaughv0 < DCAV0DaughMax) { + if (dcaDaughv0 < kDCAV0DaughMax) { mHistogramRegistry->fill(HIST("LambdaQA/hInvMassLambdaDCAV0Daugh"), v0.mLambda()); } - if (cpav0 > CPAV0Min) { + if (cpav0 > kCPAV0Min) { mHistogramRegistry->fill(HIST("LambdaQA/hInvMassLambdaCPA"), v0.mLambda()); } - if (tranRad > TranRadV0Min) { + if (tranRad > kTranRadV0Min) { mHistogramRegistry->fill(HIST("LambdaQA/hInvMassLambdaTranRadMin"), v0.mLambda()); } - if (tranRad < TranRadV0Max) { + if (tranRad < kTranRadV0Max) { mHistogramRegistry->fill(HIST("LambdaQA/hInvMassLambdaTranRadMax"), v0.mLambda()); } bool write = true; for (size_t i = 0; i < decVtx.size(); i++) { - write = write && (decVtx.at(i) < DecVtxMax); + write = write && (decVtx.at(i) < kDecVtxMax); } if (write) { mHistogramRegistry->fill(HIST("LambdaQA/hInvMassLambdaDecVtxMax"), @@ -548,37 +546,37 @@ void FemtoUniverseV0Selection::fillLambdaQA(C const& /*col*/, V const& v0, /// the CosPA of V0 needs as argument the posXYZ of collisions vertex so we need /// to pass the collsion as well -template -std::array +template +std::array FemtoUniverseV0Selection::getCutContainer(C const& /*col*/, V const& v0, T const& posTrack, T const& negTrack) { - auto outputPosTrack = PosDaughTrack.getCutContainer(posTrack); - auto outputNegTrack = NegDaughTrack.getCutContainer(negTrack); - cutContainerType output = 0; + auto outputPosTrack = posDaughTrack.getCutContainer(posTrack); + auto outputNegTrack = negDaughTrack.getCutContainer(negTrack); + CutContainerType output = 0; size_t counter = 0; - auto lambdaMassNominal = TDatabasePDG::Instance()->GetParticle(3122)->Mass(); // FIXME: Get from the common header + auto lambdaMassNominal = o2::constants::physics::MassLambda; // FIXME: Get from the common header auto lambdaMassHypothesis = v0.mLambda(); auto antiLambdaMassHypothesis = v0.mAntiLambda(); - auto diffLambda = abs(lambdaMassNominal - lambdaMassHypothesis); - auto diffAntiLambda = abs(antiLambdaMassHypothesis - lambdaMassHypothesis); + auto diffLambda = std::abs(lambdaMassNominal - lambdaMassHypothesis); + auto diffAntiLambda = std::abs(antiLambdaMassHypothesis - lambdaMassHypothesis); float sign = 0.; - float nSigmaPIDMax = PosDaughTrack.getSigmaPIDMax(); + float nSigmaPIDMax = posDaughTrack.getSigmaPIDMax(); auto nSigmaPrNeg = negTrack.tpcNSigmaPr(); auto nSigmaPiPos = posTrack.tpcNSigmaPi(); auto nSigmaPiNeg = negTrack.tpcNSigmaPi(); auto nSigmaPrPos = posTrack.tpcNSigmaPr(); // check the mass and the PID of daughters - if (abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && diffAntiLambda > diffLambda) { + if (std::abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && std::abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && diffAntiLambda > diffLambda) { sign = -1.; - } else if (abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && diffAntiLambda < diffLambda) { + } else if (std::abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && std::abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && diffAntiLambda < diffLambda) { sign = 1.; } else { // if it happens that none of these are true, ignore the invariant mass - if (abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax) { + if (std::abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && std::abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax) { sign = -1.; - } else if (abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax) { + } else if (std::abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && std::abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax) { sign = 1.; } } @@ -591,40 +589,40 @@ std::array const std::vector decVtx = {v0.x(), v0.y(), v0.z()}; float observable = 0.; - for (auto& sel : mSelections) { + for (auto& sel : mSelections) { // o2-linter: disable=const-ref-in-for-loop const auto selVariable = sel.getSelectionVariable(); - if (selVariable == femtoUniverseV0Selection::kV0DecVtxMax) { + if (selVariable == femto_universe_v0_selection::kV0DecVtxMax) { for (size_t i = 0; i < decVtx.size(); ++i) { auto decVtxValue = decVtx.at(i); sel.checkSelectionSetBit(decVtxValue, output, counter); } } else { switch (selVariable) { - case (femtoUniverseV0Selection::kV0Sign): + case (femto_universe_v0_selection::kV0Sign): observable = sign; break; - case (femtoUniverseV0Selection::kV0pTMin): + case (femto_universe_v0_selection::kV0pTMin): observable = pT; break; - case (femtoUniverseV0Selection::kV0pTMax): + case (femto_universe_v0_selection::kV0pTMax): observable = pT; break; - case (femtoUniverseV0Selection::kV0etaMax): + case (femto_universe_v0_selection::kV0etaMax): observable = eta; break; - case (femtoUniverseV0Selection::kV0DCADaughMax): + case (femto_universe_v0_selection::kV0DCADaughMax): observable = dcaDaughv0; break; - case (femtoUniverseV0Selection::kV0CPAMin): + case (femto_universe_v0_selection::kV0CPAMin): observable = cpav0; break; - case (femtoUniverseV0Selection::kV0TranRadMin): + case (femto_universe_v0_selection::kV0TranRadMin): observable = tranRad; break; - case (femtoUniverseV0Selection::kV0TranRadMax): + case (femto_universe_v0_selection::kV0TranRadMax): observable = tranRad; break; - case (femtoUniverseV0Selection::kV0DecVtxMax): + case (femto_universe_v0_selection::kV0DecVtxMax): break; } sel.checkSelectionSetBit(observable, output, counter); @@ -632,10 +630,10 @@ std::array } return { output, - outputPosTrack.at(femtoUniverseTrackSelection::TrackContainerPosition::kCuts), - outputPosTrack.at(femtoUniverseTrackSelection::TrackContainerPosition::kPID), - outputNegTrack.at(femtoUniverseTrackSelection::TrackContainerPosition::kCuts), - outputNegTrack.at(femtoUniverseTrackSelection::TrackContainerPosition::kPID)}; + outputPosTrack.at(femto_universe_track_selection::TrackContainerPosition::kCuts), + outputPosTrack.at(femto_universe_track_selection::TrackContainerPosition::kPID), + outputNegTrack.at(femto_universe_track_selection::TrackContainerPosition::kCuts), + outputNegTrack.at(femto_universe_track_selection::TrackContainerPosition::kPID)}; } template fill( + HIST(o2::aod::femtouniverseparticle::ParticleTypeName[part]) + + HIST("/hInvMassAntiLambdavsPt"), + v0.mAntiLambda(), v0.pt()); + mHistogramRegistry->fill( + HIST(o2::aod::femtouniverseparticle::ParticleTypeName[part]) + + HIST("/hInvMassLambdavsPt"), + v0.mLambda(), v0.pt()); } - PosDaughTrack.fillQA(posTrack); - NegDaughTrack.fillQA(negTrack); } -} // namespace o2::analysis::femtoUniverse +} // namespace o2::analysis::femto_universe #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEV0SELECTION_H_ diff --git a/PWGCF/FemtoUniverse/Core/FemtoUtils.h b/PWGCF/FemtoUniverse/Core/femtoUtils.h similarity index 78% rename from PWGCF/FemtoUniverse/Core/FemtoUtils.h rename to PWGCF/FemtoUniverse/Core/femtoUtils.h index 54dbbe4e02b..080315a594f 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUtils.h +++ b/PWGCF/FemtoUniverse/Core/femtoUtils.h @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file FemtoUtils.h +/// \file femtoUtils.h /// \brief Utilities for the FemtoUniverse framework /// \author Luca Barioglio, TU München, luca.barioglio@cern.ch /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch @@ -23,10 +23,10 @@ #include "Framework/ASoAHelpers.h" #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { -enum kDetector { kTPC, +enum KDetector { kTPC, kTPCTOF, kNdetectors }; @@ -51,19 +51,19 @@ int getPIDselection(float nSigma, std::vector vNsigma) /// \param nSpecies number of available selected species (output from cutculator), i.e. how many particle types were saved in the skimmed data /// \param nSigma Nsigma selection for PID (e.g. 3, for NsigmaTPC < 3 or NsigmaTPCTOF < 3) /// \param vNsigma vector with available n-sigma selections for PID (to check if chosen nSigma value is avialable + size to get the bit number) -/// \param kDetector enum corresponding to the PID technique +/// \param KDetector enum corresponding to the PID technique /// \return Whether the PID selection specified in the vectors is fulfilled -bool isPIDSelected(aod::femtouniverseparticle::cutContainerType pidcut, +bool isPIDSelected(aod::femtouniverseparticle::CutContainerType pidcut, int vSpecies, int nSpecies, float nSigma, std::vector vNsigma, - kDetector iDet) + KDetector iDet) { int iNsigma = getPIDselection(nSigma, vNsigma); - int nDet = static_cast(kDetector::kNdetectors); - int bit_to_check = 1 + (vNsigma.size() - (iNsigma + 1)) * nDet * nSpecies + (nSpecies - (vSpecies + 1)) * nSpecies + (nDet - 1 - iDet); - return ((pidcut >> (bit_to_check)) & 1) == 1; + int nDet = static_cast(KDetector::kNdetectors); + int bitToCheck = 1 + (vNsigma.size() - (iNsigma + 1)) * nDet * nSpecies + (nSpecies - (vSpecies + 1)) * nSpecies + (nDet - 1 - iDet); + return ((pidcut >> (bitToCheck)) & 1) == 1; }; /// function that checks whether the PID selection specified in the vectors is fulfilled, depending on the momentum TPC or TPC+TOF PID is conducted @@ -76,7 +76,7 @@ bool isPIDSelected(aod::femtouniverseparticle::cutContainerType pidcut, /// \param nSigmaTPC Number of TPC sigmas for selection /// \param nSigmaTPCTOF Number of TPC+TOF sigmas for selection (circular selection) /// \return Whether the PID selection is fulfilled -bool isFullPIDSelected(aod::femtouniverseparticle::cutContainerType const& pidCut, +bool isFullPIDSelected(aod::femtouniverseparticle::CutContainerType const& pidCut, float momentum, float pidThresh, int vSpecies, @@ -88,10 +88,10 @@ bool isFullPIDSelected(aod::femtouniverseparticle::cutContainerType const& pidCu bool pidSelection = true; if (momentum < pidThresh) { /// TPC PID only - pidSelection = isPIDSelected(pidCut, vSpecies, nSpecies, nSigmaTPC, vNsigma, kDetector::kTPC); + pidSelection = isPIDSelected(pidCut, vSpecies, nSpecies, nSigmaTPC, vNsigma, KDetector::kTPC); } else { /// TPC + TOF PID - pidSelection = isPIDSelected(pidCut, vSpecies, nSpecies, nSigmaTPCTOF, vNsigma, kDetector::kTPCTOF); + pidSelection = isPIDSelected(pidCut, vSpecies, nSpecies, nSigmaTPCTOF, vNsigma, KDetector::kTPCTOF); } return pidSelection; }; @@ -101,31 +101,31 @@ int checkDaughterType(o2::aod::femtouniverseparticle::ParticleType partType, int int partOrigin = 0; if (partType == o2::aod::femtouniverseparticle::ParticleType::kTrack) { - switch (abs(motherPDG)) { + switch (std::abs(motherPDG)) { case 3122: - partOrigin = aod::femtouniverseMCparticle::ParticleOriginMCTruth::kDaughterLambda; + partOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kDaughterLambda; break; case 3222: - partOrigin = aod::femtouniverseMCparticle::ParticleOriginMCTruth::kDaughterSigmaplus; + partOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kDaughterSigmaplus; break; default: - partOrigin = aod::femtouniverseMCparticle::ParticleOriginMCTruth::kDaughter; + partOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kDaughter; } // switch } else if (partType == o2::aod::femtouniverseparticle::ParticleType::kV0) { - partOrigin = aod::femtouniverseMCparticle::ParticleOriginMCTruth::kDaughter; + partOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kDaughter; } else if (partType == o2::aod::femtouniverseparticle::ParticleType::kV0Child) { - partOrigin = aod::femtouniverseMCparticle::ParticleOriginMCTruth::kDaughter; + partOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kDaughter; } else if (partType == o2::aod::femtouniverseparticle::ParticleType::kCascade) { - partOrigin = aod::femtouniverseMCparticle::ParticleOriginMCTruth::kDaughter; + partOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kDaughter; } else if (partType == o2::aod::femtouniverseparticle::ParticleType::kCascadeBachelor) { - partOrigin = aod::femtouniverseMCparticle::ParticleOriginMCTruth::kDaughter; + partOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kDaughter; } return partOrigin; }; -} // namespace o2::analysis::femtoUniverse +} // namespace o2::analysis::femto_universe #endif // PWGCF_FEMTOUNIVERSE_CORE_FEMTOUTILS_H_ diff --git a/PWGCF/FemtoUniverse/DataModel/FemtoDerived.h b/PWGCF/FemtoUniverse/DataModel/FemtoDerived.h index b7fd3e34524..eaebb852b97 100644 --- a/PWGCF/FemtoUniverse/DataModel/FemtoDerived.h +++ b/PWGCF/FemtoUniverse/DataModel/FemtoDerived.h @@ -9,6 +9,10 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file FemtoDerived.h +/// \brief Declaration of FemtoUniverse tables +/// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch + #ifndef PWGCF_FEMTOUNIVERSE_DATAMODEL_FEMTODERIVED_H_ #define PWGCF_FEMTOUNIVERSE_DATAMODEL_FEMTODERIVED_H_ @@ -27,21 +31,28 @@ namespace o2::aod /// FemtoUniverseCollision namespace femtouniversecollision { -DECLARE_SOA_COLUMN(MultV0M, multV0M, float); //! V0M multiplicity -DECLARE_SOA_COLUMN(MultNtr, multNtr, int); //! multiplicity of charged tracks as defined in the producer -DECLARE_SOA_COLUMN(Sphericity, sphericity, float); //! Sphericity of the event -DECLARE_SOA_COLUMN(MagField, magField, float); //! Magnetic field of the event +DECLARE_SOA_COLUMN(MultV0M, multV0M, float); //! V0M multiplicity +DECLARE_SOA_COLUMN(MultNtr, multNtr, int); //! multiplicity of charged tracks as defined in the producer +DECLARE_SOA_COLUMN(Sphericity, sphericity, float); //! Sphericity of the event +DECLARE_SOA_COLUMN(MagField, magField, float); //! Magnetic field of the event +DECLARE_SOA_COLUMN(InteractionRate, interactionRate, float); //! Interaction rate +DECLARE_SOA_COLUMN(Occupancy, occupancy, int); //! TPC occupancy } // namespace femtouniversecollision -DECLARE_SOA_TABLE(FDCollisions, "AOD", "FDCOLLISION", +DECLARE_SOA_TABLE(FdCollisions, "AOD", "FDCOLLISION", o2::soa::Index<>, o2::aod::collision::PosZ, femtouniversecollision::MultV0M, femtouniversecollision::MultNtr, femtouniversecollision::Sphericity, femtouniversecollision::MagField); -using FDCollision = FDCollisions::iterator; +using FdCollision = FdCollisions::iterator; + +DECLARE_SOA_TABLE(FDExtCollisions, "AOD", "FDEXTCOLLISION", + femtouniversecollision::InteractionRate, + femtouniversecollision::Occupancy); +using FDExtCollision = FDExtCollisions::iterator; /// FemtoUniverseTrack namespace femtouniverseparticle @@ -64,24 +75,25 @@ enum ParticleType { static constexpr std::string_view ParticleTypeName[kNParticleTypes] = {"Tracks", "MCTruthTracks", "V0", "V0Child", "Cascade", "CascadeBachelor", "Phi", "PhiChild", "D0", "D0Child"}; //! Naming of the different particle types static constexpr std::string_view TempFitVarName[kNParticleTypes] = {"/hDCAxy", "/hPDGvspT", "/hCPA", "/hDCAxy", "/hCPA", "/hDCAxy", "/hInvMass", "/hDCAxy", "/hInvMass", "/hDCAxy"}; -using cutContainerType = uint32_t; //! Definition of the data type for the bit-wise container for the different selection criteria +using CutContainerType = uint32_t; //! Definition of the data type for the bit-wise container for the different selection criteria enum TrackType { kNoChild, //! Not a V0 child kPosChild, //! Positive V0 child kNegChild, //! Negative V0 child + kBachelor, //! Cascade bachelor kNTrackTypes //! Number of child types }; -static constexpr std::string_view TrackTypeName[kNTrackTypes] = {"Trk", "Pos", "Neg"}; //! Naming of the different particle types +static constexpr std::string_view TrackTypeName[kNTrackTypes] = {"Trk", "Pos", "Neg", "Bach"}; //! Naming of the different particle types -DECLARE_SOA_INDEX_COLUMN(FDCollision, fdCollision); +DECLARE_SOA_INDEX_COLUMN(FdCollision, fdCollision); DECLARE_SOA_COLUMN(Pt, pt, float); //! p_T (GeV/c) DECLARE_SOA_COLUMN(Eta, eta, float); //! Eta DECLARE_SOA_COLUMN(Phi, phi, float); //! Phi DECLARE_SOA_COLUMN(PartType, partType, uint8_t); //! Type of the particle, according to femtouniverseparticle::ParticleType -DECLARE_SOA_COLUMN(Cut, cut, cutContainerType); //! Bit-wise container for the different selection criteria -DECLARE_SOA_COLUMN(PIDCut, pidcut, cutContainerType); //! Bit-wise container for the different PID selection criteria \todo since bit-masking cannot be done yet with filters we use a second field for the PID +DECLARE_SOA_COLUMN(Cut, cut, CutContainerType); //! Bit-wise container for the different selection criteria +DECLARE_SOA_COLUMN(PidCut, pidCut, CutContainerType); //! Bit-wise container for the different PID selection criteria \todo since bit-masking cannot be done yet with filters we use a second field for the PID DECLARE_SOA_COLUMN(TempFitVar, tempFitVar, float); //! Observable for the template fitting (Track: DCA_xy, V0: CPA) DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(Children, children); //! Field for the track indices to remove auto-correlations DECLARE_SOA_COLUMN(MLambda, mLambda, float); //! The invariant mass of V0 candidate, assuming lambda @@ -93,11 +105,11 @@ DECLARE_SOA_DYNAMIC_COLUMN(Theta, theta, //! Compute the theta of the track }); DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! Compute the momentum in x in GeV/c [](float pt, float phi) -> float { - return pt * std::sin(phi); + return pt * std::cos(phi); }); DECLARE_SOA_DYNAMIC_COLUMN(Py, py, //! Compute the momentum in y in GeV/c [](float pt, float phi) -> float { - return pt * std::cos(phi); + return pt * std::sin(phi); }); DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! Compute the momentum in z in GeV/c [](float pt, float eta) -> float { @@ -109,11 +121,12 @@ DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! Compute the overall momentum in GeV/c }); // debug variables DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! Sign of the track charge -DECLARE_SOA_COLUMN(TPCNClsFound, tpcNClsFound, uint8_t); //! Number of TPC clusters -DECLARE_SOA_COLUMN(TPCNClsCrossedRows, tpcNClsCrossedRows, uint8_t); //! Number of TPC crossed rows -DECLARE_SOA_COLUMN(ITSNCls, itsNCls, uint8_t); //! Number of ITS clusters -DECLARE_SOA_COLUMN(ITSNClsInnerBarrel, itsNClsInnerBarrel, uint8_t); //! Number of ITS clusters in the inner barrel //! TPC signal -DECLARE_SOA_DYNAMIC_COLUMN(TPCCrossedRowsOverFindableCls, tpcCrossedRowsOverFindableCls, //! Compute the number of crossed rows over findable TPC clusters +DECLARE_SOA_COLUMN(TpcNClsFound, tpcNClsFound, uint8_t); //! Number of TPC clusters +DECLARE_SOA_COLUMN(TpcNClsCrossedRows, tpcNClsCrossedRows, uint8_t); //! Number of TPC crossed rows +DECLARE_SOA_COLUMN(TpcFractionSharedCls, tpcFractionSharedCls, float); //! Number of TPC crossed rows +DECLARE_SOA_COLUMN(ItsNCls, itsNCls, uint8_t); //! Number of ITS clusters +DECLARE_SOA_COLUMN(ItsNClsInnerBarrel, itsNClsInnerBarrel, uint8_t); //! Number of ITS clusters in the inner barrel //! TPC signal +DECLARE_SOA_DYNAMIC_COLUMN(TpcCrossedRowsOverFindableCls, tpcCrossedRowsOverFindableCls, //! Compute the number of crossed rows over findable TPC clusters [](uint8_t tpcNClsFindable, uint8_t tpcNClsCrossedRows) -> float { return (float)tpcNClsCrossedRows / (float)tpcNClsFindable; }); @@ -125,15 +138,33 @@ DECLARE_SOA_COLUMN(DecayVtxZ, decayVtxZ, float); //! Z position of the decay DECLARE_SOA_COLUMN(MKaon, mKaon, float); //! The invariant mass of V0 candidate, assuming kaon } // namespace femtouniverseparticle + +/// FemtoUniverseCascadeTrack +namespace femtouniversecascparticle +{ + +DECLARE_SOA_COLUMN(DcaV0daughters, dcaV0daughters, float); //! DCA between V0 daughters +DECLARE_SOA_COLUMN(Cpav0, cpav0, float); //! V0 cos of pointing angle +DECLARE_SOA_COLUMN(V0radius, v0radius, float); //! V0 transverse radius +DECLARE_SOA_COLUMN(CpaCasc, cpaCasc, float); //! cascade cosinus of pointing angle +DECLARE_SOA_COLUMN(Dcacascdaughters, dcacascdaughters, float); //! DCA between cascade daughters +DECLARE_SOA_COLUMN(Cascradius, cascradius, float); //! cascade transverse radius +DECLARE_SOA_COLUMN(Dcapostopv, dcapostopv, float); //! DCA of positive daughter to PV +DECLARE_SOA_COLUMN(Dcanegtopv, dcanegtopv, float); //! DCA of negative daughter to PV +DECLARE_SOA_COLUMN(Dcabachtopv, dcabachtopv, float); //! DCA of bachelor track to PV +DECLARE_SOA_COLUMN(Dcav0topv, dcav0topv, float); //! DCA of V0 to PV + +} // namespace femtouniversecascparticle + DECLARE_SOA_TABLE(FDParticles, "AOD", "FDPARTICLE", o2::soa::Index<>, - femtouniverseparticle::FDCollisionId, + femtouniverseparticle::FdCollisionId, femtouniverseparticle::Pt, femtouniverseparticle::Eta, femtouniverseparticle::Phi, femtouniverseparticle::PartType, femtouniverseparticle::Cut, - femtouniverseparticle::PIDCut, + femtouniverseparticle::PidCut, femtouniverseparticle::TempFitVar, femtouniverseparticle::ChildrenIds, femtouniverseparticle::MLambda, @@ -147,13 +178,14 @@ using FDParticle = FDParticles::iterator; DECLARE_SOA_TABLE(FDExtParticles, "AOD", "FDEXTPARTICLE", femtouniverseparticle::Sign, - femtouniverseparticle::TPCNClsFound, + femtouniverseparticle::TpcNClsFound, track::TPCNClsFindable, - femtouniverseparticle::TPCNClsCrossedRows, + femtouniverseparticle::TpcNClsCrossedRows, track::TPCNClsShared, + femtouniverseparticle::TpcFractionSharedCls, track::TPCInnerParam, - femtouniverseparticle::ITSNCls, - femtouniverseparticle::ITSNClsInnerBarrel, + femtouniverseparticle::ItsNCls, + femtouniverseparticle::ItsNClsInnerBarrel, track::DcaXY, track::DcaZ, track::TPCSignal, @@ -173,7 +205,7 @@ DECLARE_SOA_TABLE(FDExtParticles, "AOD", "FDEXTPARTICLE", femtouniverseparticle::DecayVtxY, femtouniverseparticle::DecayVtxZ, femtouniverseparticle::MKaon, - femtouniverseparticle::TPCCrossedRowsOverFindableCls, + femtouniverseparticle::TpcCrossedRowsOverFindableCls, pidtpc_tiny::TPCNSigmaEl, pidtpc_tiny::TPCNSigmaPi, pidtpc_tiny::TPCNSigmaKa, @@ -186,8 +218,38 @@ DECLARE_SOA_TABLE(FDExtParticles, "AOD", "FDEXTPARTICLE", pidtof_tiny::TOFNSigmaDe); using FDFullParticle = FDExtParticles::iterator; +DECLARE_SOA_TABLE(FDCascParticles, "AOD", "FDCASCPARTICLE", + o2::soa::Index<>, + femtouniverseparticle::FdCollisionId, + femtouniverseparticle::Pt, + femtouniverseparticle::Eta, + femtouniverseparticle::Phi, + femtouniverseparticle::PartType, + femtouniverseparticle::Cut, + femtouniverseparticle::PidCut, + femtouniverseparticle::TempFitVar, + femtouniverseparticle::ChildrenIds, + femtouniverseparticle::MLambda, + femtouniverseparticle::MAntiLambda, + femtouniverseparticle::Theta, + femtouniverseparticle::Px, + femtouniverseparticle::Py, + femtouniverseparticle::Pz, + femtouniverseparticle::P, + femtouniversecascparticle::DcaV0daughters, + femtouniversecascparticle::Cpav0, + femtouniversecascparticle::V0radius, + femtouniversecascparticle::CpaCasc, + femtouniversecascparticle::Dcacascdaughters, + femtouniversecascparticle::Cascradius, + femtouniversecascparticle::Dcapostopv, + femtouniversecascparticle::Dcanegtopv, + femtouniversecascparticle::Dcabachtopv, + femtouniversecascparticle::Dcav0topv); +using FDCascParticle = FDCascParticles::iterator; + /// FemtoUniverseTrackMC -namespace femtouniverseMCparticle +namespace femtouniverse_mc_particle { /// Distinuishes the different particle origins enum ParticleOriginMCTruth { @@ -198,6 +260,8 @@ enum ParticleOriginMCTruth { kFake, //! particle, that has NOT the PDG code of the current analysed particle kDaughterLambda, //! Daughter from a Lambda decay kDaughterSigmaplus, //! Daughter from a Sigma^plus decay + kPrompt, //! Orgin for D0/D0bar mesons + kNonPrompt, //! Orgin for D0/D0bar mesons kNOriginMCTruthTypes }; @@ -209,7 +273,9 @@ static constexpr std::string_view ParticleOriginMCTruthName[kNOriginMCTruthTypes "_NotPrimary", "_Fake", "_DaughterLambda", - "DaughterSigmaPlus"}; + "DaughterSigmaPlus", + "_Prompt", + "_NonPrompt"}; /// Distinguished between reconstructed and truth enum MCType { @@ -221,39 +287,39 @@ enum MCType { static constexpr std::string_view MCTypeName[kNMCTypes] = {"", "_MC"}; DECLARE_SOA_COLUMN(PartOriginMCTruth, partOriginMCTruth, uint8_t); //! Origin of the particle, according to femtouniverseparticle::ParticleOriginMCTruth -DECLARE_SOA_COLUMN(PDGMCTruth, pdgMCTruth, int); //! Particle PDG +DECLARE_SOA_COLUMN(PdgMCTruth, pdgMCTruth, int); //! Particle PDG // debug variables DECLARE_SOA_COLUMN(MotherPDG, motherPDG, int); //! Checks mother PDG, where mother is the primary particle for that decay chain -} // namespace femtouniverseMCparticle +} // namespace femtouniverse_mc_particle -DECLARE_SOA_TABLE(FDMCParticles, "AOD", "FDMCPARTICLE", +DECLARE_SOA_TABLE(FdMCParticles, "AOD", "FDMCPARTICLE", o2::soa::Index<>, - femtouniverseMCparticle::PartOriginMCTruth, - femtouniverseMCparticle::PDGMCTruth, + femtouniverse_mc_particle::PartOriginMCTruth, + femtouniverse_mc_particle::PdgMCTruth, femtouniverseparticle::Pt, femtouniverseparticle::Eta, femtouniverseparticle::Phi); -using FDMCParticle = FDMCParticles::iterator; +using FdMCParticle = FdMCParticles::iterator; DECLARE_SOA_TABLE(FDExtMCParticles, "AOD", "FDEXTMCPARTICLE", - femtouniverseMCparticle::MotherPDG); + femtouniverse_mc_particle::MotherPDG); using FDExtMCParticle = FDExtMCParticles::iterator; namespace mcfdlabel { -DECLARE_SOA_INDEX_COLUMN(FDMCParticle, fdMCParticle); //! MC particle for femtouniverseparticle +DECLARE_SOA_INDEX_COLUMN(FdMCParticle, fdMCParticle); //! MC particle for femtouniverseparticle } // namespace mcfdlabel DECLARE_SOA_TABLE(FDMCLabels, "AOD", "FDMCLabel", //! Table joinable to FemtoUniverseParticle containing the MC labels - mcfdlabel::FDMCParticleId); + mcfdlabel::FdMCParticleId); /// Hash namespace hash { DECLARE_SOA_COLUMN(Bin, bin, int); //! Hash for the event mixing } // namespace hash -DECLARE_SOA_TABLE(Hashes, "AOD", "HASH", hash::Bin); -using Hash = Hashes::iterator; +DECLARE_SOA_TABLE(MixingHashes, "AOD", "HASH", hash::Bin); +using MixingHash = MixingHashes::iterator; } // namespace o2::aod diff --git a/PWGCF/FemtoUniverse/Scripts/femto_universe_efficiency_calculator.py b/PWGCF/FemtoUniverse/Scripts/femto_universe_efficiency_calculator.py new file mode 100755 index 00000000000..2a0b822d215 --- /dev/null +++ b/PWGCF/FemtoUniverse/Scripts/femto_universe_efficiency_calculator.py @@ -0,0 +1,216 @@ +#!/usr/bin/env python3 + +# 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. + +""" +A tool to calculate efficiency and upload it to CCDB. +Author: Dawid Karpiński (dawid.karpinski@cern.ch) +""" + +import argparse +import subprocess +import sys +import tempfile +import time +from pathlib import Path + +import ROOT # pylint: disable=import-error + + +class CustomHelpFormatter(argparse.HelpFormatter): + "Add default value to help format" + + def _get_help_string(self, action): + help_str = action.help + if help_str is not None and action.default not in [argparse.SUPPRESS, None]: + help_str += f" (default: {action.default})" + return help_str + + +parser = argparse.ArgumentParser( + description="A tool to calculate efficiency and upload it to CCDB", + formatter_class=CustomHelpFormatter, +) +parser.add_argument( + "--alien-path", + type=Path, + help="path to train run's directory in Alien with analysis results " + "[example: /alice/cern.ch/user/a/alihyperloop/outputs/0033/332611/70301]", +) +parser.add_argument( + "--mc-reco", + type=str, + nargs="+", + help="paths to MC Reco histograms, separated by space [example: task/mcreco_one/hPt task/mcreco_two/hPt]", + required=True, +) +parser.add_argument( + "--mc-truth", + type=str, + nargs="+", + help="paths to MC Truth histograms, separated by space [example: task/mctruth_one/hPt task/mctruth_one/hPt]", + required=True, +) +parser.add_argument( + "--ccdb-path", + type=str, + help="location in CCDB to where objects will be uploaded", + required=True, +) +parser.add_argument( + "--ccdb-url", + type=str, + help="URL to CCDB", + default="http://ccdb-test.cern.ch:8080", +) +parser.add_argument( + "--ccdb-labels", + type=str, + nargs="+", + help="custom labels to add to objects' metadata in CCDB [example: label1 label2]", + default=[], +) +parser.add_argument( + "--ccdb-lifetime", + type=int, + help="how long should objects in CCDB remain valid (milliseconds)", + default=365 * 24 * 60 * 60 * 1000, # one year +) +args = parser.parse_args() + +if len(args.mc_reco) != len(args.mc_truth): + print("[!] Provided number of histograms with MC Reco must match MC Truth", file=sys.stderr) + sys.exit(1) + +if len(args.ccdb_labels) > 0 and len(args.ccdb_labels) != len(args.mc_reco): + print("[!] You must provide labels for all particles", file=sys.stderr) + sys.exit(1) + +if len(args.ccdb_labels) == 0: + # if flag is not provided, fill with empty strings to match size + args.ccdb_labels = [""] * len(args.mc_reco) + +ANALYSIS_RESULTS = "AnalysisResults.root" +results_path = args.alien_path / ANALYSIS_RESULTS +job_id = results_path.parent.name +train_number = results_path.parent.parent.name + +tmp_dir = Path(tempfile.gettempdir()) + +res_dest = tmp_dir / f"{train_number}-{job_id}-{ANALYSIS_RESULTS}" +eff_dest = tmp_dir / f"{train_number}-{job_id}-Efficiency.root" + +# get file from alien +if not res_dest.is_file(): + print(f"[↓] Downloading analysis results from Alien to '{res_dest}' ...", file=sys.stderr) + ROOT.TGrid.Connect("alien://") + try: + subprocess.run( + ["alien_cp", results_path, "file://" + str(res_dest)], + capture_output=True, + check=True, + ) + print("[-] Download complete!", file=sys.stderr) + except subprocess.CalledProcessError as error: + print(f"[!] Error while downloading results file: {error.stderr}", file=sys.stderr) + sys.exit(1) +else: + print( + f"[-] Skipping download from Alien, since '{res_dest}' is already present", + file=sys.stderr, + ) + +print() + +histos_to_upload = [] + +# get reco & truth histos +with ( + ROOT.TFile.Open(res_dest.as_uri()) as res_file, + ROOT.TFile.Open(eff_dest.as_uri(), "recreate") as eff_file, +): + for idx, (mc_reco, mc_truth) in enumerate(zip(args.mc_reco, args.mc_truth)): + hist_reco = res_file.Get(mc_reco) + if not hist_reco: + print(f"[!] Cannot find MC Reco histogram in '{mc_reco}', aborting", file=sys.stderr) + sys.exit(1) + + hist_truth = res_file.Get(mc_truth) + if not hist_truth: + print(f"[!] Cannot find MC Truth histogram in '{mc_truth}', aborting", file=sys.stderr) + sys.exit(1) + + num_bins = hist_reco.GetNbinsX() + x_max = hist_reco.GetXaxis().GetBinLowEdge(num_bins) + x_max += hist_reco.GetXaxis().GetBinWidth(num_bins) + + hist_name = f"Efficiency_part{idx + 1}" + + # calculate efficiency + eff = ROOT.TH1F(hist_name, "", num_bins, 0, x_max) + for bin_idx in range(len(eff)): + denom = hist_truth.GetBinContent(bin_idx) + eff.SetBinContent(bin_idx, hist_reco.GetBinContent(bin_idx) / denom if denom > 0 else 0) + + # save efficiency object to file + eff_file.WriteObject(eff, hist_name) + histos_to_upload.append(hist_name) + +if len(histos_to_upload) == 0: + print("[-] Exiting, since there is nothing to upload", file=sys.stderr) + sys.exit(1) + +# upload objects to ccdb +try: + for idx, key in enumerate(histos_to_upload): + timestamp_start = int(time.time() * 1000) + timestamp_end = timestamp_start + args.ccdb_lifetime + + print(f"[↑] Uploading {key} to {args.ccdb_url} ... ", file=sys.stderr, end="") + upload_cmd = [ + "o2-ccdb-upload", + "--file", + eff_dest.as_uri(), + "--host", + args.ccdb_url, + "--key", + key, + "--path", + args.ccdb_path, + "--starttimestamp", + str(timestamp_start), + "--endtimestamp", + str(timestamp_end), + "--meta", + f"trainNumber={train_number};label={args.ccdb_labels[idx]}", + ] + result = subprocess.run(upload_cmd, capture_output=True, check=True) + + if "html" in result.stdout.decode("utf-8"): + print( + f"\n[!] Something went wrong with upload request: {result.stdout.decode('utf-8')}", + file=sys.stderr, + ) + sys.exit(1) + + if result.stderr: + print(f"\n[!] Error while uploading: {result.stderr.decode('utf-8')}", file=sys.stderr) + sys.exit(1) + + print("complete!", file=sys.stderr) + +except subprocess.CalledProcessError as error: + print(f"\n[!] Error while uploading: {error.stderr.decode('utf-8')}", file=sys.stderr) + sys.exit(1) + +print() +print("[✓] Success!", file=sys.stderr) diff --git a/PWGCF/FemtoUniverse/Scripts/femto_universe_efficiency_phi_calculator.py b/PWGCF/FemtoUniverse/Scripts/femto_universe_efficiency_phi_calculator.py new file mode 100644 index 00000000000..97f5bede27a --- /dev/null +++ b/PWGCF/FemtoUniverse/Scripts/femto_universe_efficiency_phi_calculator.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python3 + +# 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. + +""" +A tool to calculate efficiency and upload it to CCDB. +Author: Dawid Karpiński (dawid.karpinski@cern.ch) +Modified by: Zuzanna Chochulska (zchochul@cern.ch) +""" + +import argparse +import subprocess +import sys +import tempfile +import time +from pathlib import Path + +import ROOT # pylint: disable=import-error + + +class CustomHelpFormatter(argparse.HelpFormatter): + "Add default value to help format" + + def _get_help_string(self, action): + help_str = action.help + if help_str is not None and action.default not in [argparse.SUPPRESS, None]: + help_str += f" (default: {action.default})" + return help_str + + +parser = argparse.ArgumentParser( + description="A tool to calculate efficiency and upload it to CCDB", + formatter_class=CustomHelpFormatter, +) +parser.add_argument( + "--alien-path", + type=Path, + help="path to train run's directory in Alien with analysis results " + "[example: /alice/cern.ch/user/a/alihyperloop/outputs/0033/332611/70301]", +) +parser.add_argument( + "--mc-reco", + type=str, + nargs="+", + help="paths to MC Reco histograms, separated by space [example: task/mcreco_one/hPt task/mcreco_two/hPt]", + required=True, +) +parser.add_argument( + "--mc-truth", + type=str, + nargs="+", + help="paths to MC Truth histograms, separated by space [example: task/mctruth_one/hPt task/mctruth_one/hPt]", + required=True, +) +parser.add_argument( + "--ccdb-path", + type=str, + help="location in CCDB to where objects will be uploaded", + required=True, +) +parser.add_argument( + "--ccdb-url", + type=str, + help="URL to CCDB", + default="http://ccdb-test.cern.ch:8080", +) +parser.add_argument( + "--ccdb-labels", + type=str, + nargs="+", + help="custom labels to add to objects' metadata in CCDB [example: label1 label2]", + default=[], +) +parser.add_argument( + "--ccdb-lifetime", + type=int, + help="how long should objects in CCDB remain valid (milliseconds)", + default=365 * 24 * 60 * 60 * 1000, # one year +) +args = parser.parse_args() + +if len(args.mc_reco) != len(args.mc_truth): + print("[!] Provided number of histograms with MC Reco must match MC Truth", file=sys.stderr) + sys.exit(1) + +if len(args.ccdb_labels) > 0 and len(args.ccdb_labels) != len(args.mc_reco): + print("[!] You must provide labels for all particles", file=sys.stderr) + sys.exit(1) + +if len(args.ccdb_labels) == 0: + # if flag is not provided, fill with empty strings to match size + args.ccdb_labels = [""] * len(args.mc_reco) + +ANALYSIS_RESULTS = "AnalysisResults.root" +results_path = args.alien_path / ANALYSIS_RESULTS +job_id = results_path.parent.name +train_number = results_path.parent.parent.name + +tmp_dir = Path(tempfile.gettempdir()) + +res_dest = tmp_dir / f"{train_number}-{job_id}-{ANALYSIS_RESULTS}" +eff_dest = tmp_dir / f"{train_number}-{job_id}-Efficiency.root" + +# get file from alien +if not res_dest.is_file(): + print(f"[↓] Downloading analysis results from Alien to '{res_dest}' ...", file=sys.stderr) + ROOT.TGrid.Connect("alien://") + try: + subprocess.run( + ["alien_cp", results_path, "file://" + str(res_dest)], + capture_output=True, + check=True, + ) + print("[-] Download complete!", file=sys.stderr) + except subprocess.CalledProcessError as error: + print(f"[!] Error while downloading results file: {error.stderr}", file=sys.stderr) + sys.exit(1) +else: + print( + f"[-] Skipping download from Alien, since '{res_dest}' is already present", + file=sys.stderr, + ) + +print() + +histos_to_upload = [] + +# get reco & truth histos +with ( + ROOT.TFile.Open(res_dest.as_uri()) as res_file, + ROOT.TFile.Open(eff_dest.as_uri(), "recreate") as eff_file, +): + + for idx, (mc_reco, mc_truth) in enumerate(zip(args.mc_reco, args.mc_truth)): + hist_reco = res_file.Get(mc_reco) + if not hist_reco: + print(f"[!] Cannot find MC Reco histogram in '{mc_reco}', aborting", file=sys.stderr) + sys.exit(1) + + hist_truth = res_file.Get(mc_truth) + if not hist_truth: + print(f"[!] Cannot find MC Truth histogram in '{mc_truth}', aborting", file=sys.stderr) + sys.exit(1) + + hist_reco.Rebin(4) + hist_truth.Rebin(4) + + num_bins = hist_reco.GetNbinsX() + x_max = hist_reco.GetXaxis().GetBinLowEdge(num_bins) + x_max += hist_reco.GetXaxis().GetBinWidth(num_bins) + + hist_name = f"Efficiency_part{idx + 1}" + + # calculate efficiency + eff = ROOT.TH1F(hist_name, "", num_bins, 0, x_max) + for bin_idx in range(1, num_bins + 1): # Bins start at 1 in ROOT + denom = hist_truth.GetBinContent(bin_idx) + if idx == 0: + denom *= 0.489 + eff.SetBinContent(bin_idx, hist_reco.GetBinContent(bin_idx) / denom if denom > 0 else 0) + + # save efficiency object to file + eff_file.WriteObject(eff, hist_name) + histos_to_upload.append(hist_name) + +if len(histos_to_upload) == 0: + print("[-] Exiting, since there is nothing to upload", file=sys.stderr) + sys.exit(1) + +# upload objects to ccdb +try: + for idx, key in enumerate(histos_to_upload): + timestamp_start = int(time.time() * 1000) + timestamp_end = timestamp_start + args.ccdb_lifetime + + print(f"[↑] Uploading {key} to {args.ccdb_url} ... ", file=sys.stderr, end="") + upload_cmd = [ + "o2-ccdb-upload", + "--file", + eff_dest.as_uri(), + "--host", + args.ccdb_url, + "--key", + key, + "--path", + args.ccdb_path, + "--starttimestamp", + str(timestamp_start), + "--endtimestamp", + str(timestamp_end), + "--meta", + f"trainNumber={train_number};label={args.ccdb_labels[idx]}", + ] + result = subprocess.run(upload_cmd, capture_output=True, check=True) + + if "html" in result.stdout.decode("utf-8"): + print( + f"\n[!] Something went wrong with upload request: {result.stdout.decode('utf-8')}", + file=sys.stderr, + ) + sys.exit(1) + + if result.stderr: + print(f"\n[!] Error while uploading: {result.stderr.decode('utf-8')}", file=sys.stderr) + sys.exit(1) + + print("complete!", file=sys.stderr) + +except subprocess.CalledProcessError as error: + print(f"\n[!] Error while uploading: {error.stderr.decode('utf-8')}", file=sys.stderr) + sys.exit(1) + +print() +print("[✓] Success!", file=sys.stderr) diff --git a/PWGCF/FemtoUniverse/TableProducer/CMakeLists.txt b/PWGCF/FemtoUniverse/TableProducer/CMakeLists.txt index ecbb6e46873..b82a2e6d6f1 100644 --- a/PWGCF/FemtoUniverse/TableProducer/CMakeLists.txt +++ b/PWGCF/FemtoUniverse/TableProducer/CMakeLists.txt @@ -11,7 +11,7 @@ o2physics_add_dpl_workflow(femtouniverse-producer SOURCES femtoUniverseProducerTask.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(femtouniverse-mctruth-producer diff --git a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerMCTruthTask.cxx b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerMCTruthTask.cxx index f80d7dafcd6..1b8ba74d889 100644 --- a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerMCTruthTask.cxx +++ b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerMCTruthTask.cxx @@ -26,7 +26,7 @@ #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseV0Selection.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniversePhiSelection.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" @@ -40,7 +40,7 @@ #include "TLorentzVector.h" using namespace o2; -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; using namespace o2::framework; using namespace o2::framework::expressions; @@ -77,10 +77,10 @@ struct femtoUniverseProducerMCTruthTask { Service ccdb; /// Accessing the CCDB // Tables being produced - Produces outputCollision; + Produces outputCollision; Produces outputParts; // Produces outputPartsMCLabels; - // Produces outputPartsMC; + // Produces outputPartsMC; // Analysis configs Configurable ConfIsTrigger{"ConfIsTrigger", false, "Store all collisions"}; // Choose if filtering or skimming version is run @@ -121,7 +121,7 @@ struct femtoUniverseProducerMCTruthTask { colCuts.setCuts(ConfEvtZvtx, ConfEvtTriggerCheck, ConfEvtTriggerSel, ConfEvtOfflineCheck, ConfIsRun3, ConfCentFT0Min, ConfCentFT0Max); colCuts.init(&qaRegistry); - trackCuts.init(&qaRegistry); + trackCuts.init(&qaRegistry); mRunNumber = 0; mMagField = 0.0; @@ -168,7 +168,11 @@ struct femtoUniverseProducerMCTruthTask { bool pass = false; std::vector tmpPDGCodes = ConfPDGCodes; // necessary due to some features of the Configurable for (uint32_t pdg : tmpPDGCodes) { - if (pdgCode == 333) { + if (pdgCode == 333) { // phi meson + pass = true; + } else if (pdgCode == 421) { // D0 meson + pass = true; + } else if (pdgCode == 411) { // D+ meson pass = true; } else if (static_cast(pdg) == static_cast(pdgCode)) { if (particle.isPhysicalPrimary()) @@ -187,7 +191,7 @@ struct femtoUniverseProducerMCTruthTask { // trackCuts.fillQA(track); // the bit-wise container of the systematic variations is obtained - // auto cutContainer = trackCuts.getCutContainer(track); + // auto cutContainer = trackCuts.getCutContainer(track); // instead of the bitmask, the PDG of the particle is stored as uint32_t // now the table is filled diff --git a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerReducedTask.cxx b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerReducedTask.cxx index 9ab0fd70736..3b5de3fcaa1 100644 --- a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerReducedTask.cxx +++ b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerReducedTask.cxx @@ -16,8 +16,10 @@ /// \author Anton Riedel, TU München, anton.riedel@tum.de /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch -#include "TMath.h" #include +#include + +#include "TMath.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseCollisionSelection.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" @@ -36,10 +38,10 @@ #include "DataFormatsParameters/GRPObject.h" #include "DataFormatsParameters/GRPMagField.h" #include "Math/Vector4D.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" using namespace o2; -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; using namespace o2::framework; using namespace o2::framework::expressions; @@ -63,9 +65,9 @@ using FemtoFullTracks = soa::Join outputCollision; + Produces outputCollision; Produces outputParts; - Produces outputPartsMC; + Produces outputPartsMC; Produces outputDebugParts; Produces outputPartsMCLabels; Produces outputDebugPartsMC; @@ -92,19 +94,20 @@ struct femtoUniverseProducerReducedTask { Configurable ConfPDGCodeTrack{"ConfPDGCodeTrack", 2212, "PDG code of the selected track for Monte Carlo truth"}; // Track cuts FemtoUniverseTrackSelection trackCuts; - Configurable> ConfTrkCharge{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kSign, "ConfTrk"), std::vector{-1, 1}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kSign, "Track selection: ")}; - Configurable> ConfTrkPtmin{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kpTMin, "ConfTrk"), std::vector{0.4f, 0.6f, 0.5f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kpTMin, "Track selection: ")}; - Configurable> ConfTrkPtmax{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kpTMax, "ConfTrk"), std::vector{5.4f, 5.6f, 5.5f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kpTMax, "Track selection: ")}; - Configurable> ConfTrkEta{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kEtaMax, "ConfTrk"), std::vector{0.8f, 0.7f, 0.9f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kEtaMax, "Track selection: ")}; - Configurable> ConfTrkTPCnclsMin{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kTPCnClsMin, "ConfTrk"), std::vector{80.f, 70.f, 60.f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kTPCnClsMin, "Track selection: ")}; - Configurable> ConfTrkTPCfCls{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kTPCfClsMin, "ConfTrk"), std::vector{0.7f, 0.83f, 0.9f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kTPCfClsMin, "Track selection: ")}; - Configurable> ConfTrkTPCcRowsMin{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kTPCcRowsMin, "ConfTrk"), std::vector{70.f, 60.f, 80.f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kTPCcRowsMin, "Track selection: ")}; - Configurable> ConfTrkTPCsCls{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kTPCsClsMax, "ConfTrk"), std::vector{0.1f, 160.f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kTPCsClsMax, "Track selection: ")}; - Configurable> ConfTrkITSnclsMin{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kITSnClsMin, "ConfTrk"), std::vector{-1.f, 2.f, 4.f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kITSnClsMin, "Track selection: ")}; - Configurable> ConfTrkITSnclsIbMin{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kITSnClsIbMin, "ConfTrk"), std::vector{-1.f, 1.f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kITSnClsIbMin, "Track selection: ")}; - Configurable> ConfTrkDCAxyMax{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kDCAxyMax, "ConfTrk"), std::vector{0.1f, 0.5f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kDCAxyMax, "Track selection: ")}; /// here we need an open cut to do the DCA fits later on! - Configurable> ConfTrkDCAzMax{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kDCAzMax, "ConfTrk"), std::vector{0.2f, 0.5f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kDCAzMax, "Track selection: ")}; - Configurable> ConfTrkPIDnSigmaMax{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kPIDnSigmaMax, "Conf"), std::vector{3.5f, 3.f, 2.5f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kPIDnSigmaMax, "Track selection: ")}; + Configurable> ConfTrkCharge{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kSign, "ConfTrk"), std::vector{-1, 1}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kSign, "Track selection: ")}; + Configurable> ConfTrkPtmin{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kpTMin, "ConfTrk"), std::vector{0.4f, 0.6f, 0.5f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kpTMin, "Track selection: ")}; + Configurable> ConfTrkPtmax{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kpTMax, "ConfTrk"), std::vector{5.4f, 5.6f, 5.5f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kpTMax, "Track selection: ")}; + Configurable> ConfTrkEta{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kEtaMax, "ConfTrk"), std::vector{0.8f, 0.7f, 0.9f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kEtaMax, "Track selection: ")}; + Configurable> ConfTrkTPCnclsMin{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kTPCnClsMin, "ConfTrk"), std::vector{80.f, 70.f, 60.f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kTPCnClsMin, "Track selection: ")}; + Configurable> ConfTrkTPCfCls{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kTPCfClsMin, "ConfTrk"), std::vector{0.7f, 0.83f, 0.9f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kTPCfClsMin, "Track selection: ")}; + Configurable> ConfTrkTPCcRowsMin{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kTPCcRowsMin, "ConfTrk"), std::vector{70.f, 60.f, 80.f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kTPCcRowsMin, "Track selection: ")}; + Configurable> ConfTrkTPCsCls{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kTPCsClsMax, "ConfTrk"), std::vector{0.1f, 160.f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kTPCsClsMax, "Track selection: ")}; + Configurable> ConfTrkTPCfracsCls{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kTPCfracsClsMax, "ConfTrk"), std::vector{0.1f, 160.f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kTPCfracsClsMax, "Track selection: ")}; + Configurable> ConfTrkITSnclsMin{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kITSnClsMin, "ConfTrk"), std::vector{-1.f, 2.f, 4.f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kITSnClsMin, "Track selection: ")}; + Configurable> ConfTrkITSnclsIbMin{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kITSnClsIbMin, "ConfTrk"), std::vector{-1.f, 1.f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kITSnClsIbMin, "Track selection: ")}; + Configurable> ConfTrkDCAxyMax{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kDCAxyMax, "ConfTrk"), std::vector{0.1f, 0.5f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kDCAxyMax, "Track selection: ")}; /// here we need an open cut to do the DCA fits later on! + Configurable> ConfTrkDCAzMax{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kDCAzMax, "ConfTrk"), std::vector{0.2f, 0.5f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kDCAzMax, "Track selection: ")}; + Configurable> ConfTrkPIDnSigmaMax{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kPIDnSigmaMax, "Conf"), std::vector{3.5f, 3.f, 2.5f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kPIDnSigmaMax, "Track selection: ")}; // off set the center of the nsigma distribution to deal with bad TPC/TOF calibration Configurable ConfPIDnSigmaOffsetTPC{"ConfPIDnSigmaOffsetTPC", 0., "Offset for TPC nSigma because of bad calibration"}; Configurable ConfPIDnSigmaOffsetTOF{"ConfPIDnSigmaOffsetTOF", 0., "Offset for TOF nSigma because of bad calibration"}; @@ -121,24 +124,25 @@ struct femtoUniverseProducerReducedTask { colCuts.setCuts(ConfEvtZvtx, ConfEvtTriggerCheck, ConfEvtTriggerSel, ConfEvtOfflineCheck, ConfIsRun3, ConfCentFT0Min, ConfCentFT0Max); colCuts.init(&qaRegistry); - trackCuts.setSelection(ConfTrkCharge, femtoUniverseTrackSelection::kSign, femtoUniverseSelection::kEqual); - trackCuts.setSelection(ConfTrkPtmin, femtoUniverseTrackSelection::kpTMin, femtoUniverseSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkPtmax, femtoUniverseTrackSelection::kpTMax, femtoUniverseSelection::kUpperLimit); - trackCuts.setSelection(ConfTrkEta, femtoUniverseTrackSelection::kEtaMax, femtoUniverseSelection::kAbsUpperLimit); - trackCuts.setSelection(ConfTrkTPCnclsMin, femtoUniverseTrackSelection::kTPCnClsMin, femtoUniverseSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkTPCfCls, femtoUniverseTrackSelection::kTPCfClsMin, femtoUniverseSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkTPCcRowsMin, femtoUniverseTrackSelection::kTPCcRowsMin, femtoUniverseSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkTPCsCls, femtoUniverseTrackSelection::kTPCsClsMax, femtoUniverseSelection::kUpperLimit); - trackCuts.setSelection(ConfTrkITSnclsMin, femtoUniverseTrackSelection::kITSnClsMin, femtoUniverseSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkITSnclsIbMin, femtoUniverseTrackSelection::kITSnClsIbMin, femtoUniverseSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkDCAxyMax, femtoUniverseTrackSelection::kDCAxyMax, femtoUniverseSelection::kAbsUpperLimit); - trackCuts.setSelection(ConfTrkDCAzMax, femtoUniverseTrackSelection::kDCAzMax, femtoUniverseSelection::kAbsUpperLimit); - trackCuts.setSelection(ConfTrkPIDnSigmaMax, femtoUniverseTrackSelection::kPIDnSigmaMax, femtoUniverseSelection::kAbsUpperLimit); + trackCuts.setSelection(ConfTrkCharge, femto_universe_track_selection::kSign, femto_universe_selection::kEqual); + trackCuts.setSelection(ConfTrkPtmin, femto_universe_track_selection::kpTMin, femto_universe_selection::kLowerLimit); + trackCuts.setSelection(ConfTrkPtmax, femto_universe_track_selection::kpTMax, femto_universe_selection::kUpperLimit); + trackCuts.setSelection(ConfTrkEta, femto_universe_track_selection::kEtaMax, femto_universe_selection::kAbsUpperLimit); + trackCuts.setSelection(ConfTrkTPCnclsMin, femto_universe_track_selection::kTPCnClsMin, femto_universe_selection::kLowerLimit); + trackCuts.setSelection(ConfTrkTPCfCls, femto_universe_track_selection::kTPCfClsMin, femto_universe_selection::kLowerLimit); + trackCuts.setSelection(ConfTrkTPCcRowsMin, femto_universe_track_selection::kTPCcRowsMin, femto_universe_selection::kLowerLimit); + trackCuts.setSelection(ConfTrkTPCsCls, femto_universe_track_selection::kTPCsClsMax, femto_universe_selection::kUpperLimit); + trackCuts.setSelection(ConfTrkTPCfracsCls, femto_universe_track_selection::kTPCfracsClsMax, femto_universe_selection::kUpperLimit); + trackCuts.setSelection(ConfTrkITSnclsMin, femto_universe_track_selection::kITSnClsMin, femto_universe_selection::kLowerLimit); + trackCuts.setSelection(ConfTrkITSnclsIbMin, femto_universe_track_selection::kITSnClsIbMin, femto_universe_selection::kLowerLimit); + trackCuts.setSelection(ConfTrkDCAxyMax, femto_universe_track_selection::kDCAxyMax, femto_universe_selection::kAbsUpperLimit); + trackCuts.setSelection(ConfTrkDCAzMax, femto_universe_track_selection::kDCAzMax, femto_universe_selection::kAbsUpperLimit); + trackCuts.setSelection(ConfTrkPIDnSigmaMax, femto_universe_track_selection::kPIDnSigmaMax, femto_universe_selection::kAbsUpperLimit); trackCuts.setPIDSpecies(ConfPIDspecies); trackCuts.setnSigmaPIDOffset(ConfPIDnSigmaOffsetTPC, ConfPIDnSigmaOffsetTOF); trackCuts.init(&qaRegistry); + aod::femtouniverseparticle::CutContainerType>(&qaRegistry); mRunNumber = 0; mMagField = 0.0; /// Initializing CCDB @@ -201,16 +205,16 @@ struct femtoUniverseProducerReducedTask { if (abs(pdgCode) == abs(ConfPDGCodeTrack.value)) { if (particleMC.isPhysicalPrimary()) { - particleOrigin = aod::femtouniverseMCparticle::ParticleOriginMCTruth::kPrimary; + particleOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary; } else if (motherparticleMC.producedByGenerator()) { particleOrigin = checkDaughterType(fdparttype, motherparticleMC.pdgCode()); } else { - particleOrigin = aod::femtouniverseMCparticle::ParticleOriginMCTruth::kMaterial; + particleOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kMaterial; } } else { - particleOrigin = aod::femtouniverseMCparticle::ParticleOriginMCTruth::kFake; + particleOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kFake; } outputPartsMC(particleOrigin, pdgCode, particleMC.pt(), particleMC.eta(), particleMC.phi()); @@ -267,7 +271,7 @@ struct femtoUniverseProducerReducedTask { trackCuts.fillQA(track); // an array of two bit-wise containers of the systematic variations is obtained // one container for the track quality cuts and one for the PID cuts - auto cutContainer = trackCuts.getCutContainer(track); + auto cutContainer = trackCuts.getCutContainer(track); // now the table is filled outputParts(outputCollision.lastIndex(), @@ -275,8 +279,8 @@ struct femtoUniverseProducerReducedTask { track.eta(), track.phi(), aod::femtouniverseparticle::ParticleType::kTrack, - cutContainer.at(femtoUniverseTrackSelection::TrackContainerPosition::kCuts), - cutContainer.at(femtoUniverseTrackSelection::TrackContainerPosition::kPID), + cutContainer.at(femto_universe_track_selection::TrackContainerPosition::kCuts), + cutContainer.at(femto_universe_track_selection::TrackContainerPosition::kPID), track.dcaXY(), childIDs, 0, 0); if constexpr (isMC) { @@ -289,6 +293,7 @@ struct femtoUniverseProducerReducedTask { track.tpcNClsFindable(), (uint8_t)track.tpcNClsCrossedRows(), track.tpcNClsShared(), + track.tpcFractionSharedCls(), track.tpcInnerParam(), track.itsNCls(), track.itsNClsInnerBarrel(), diff --git a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx index 3d98d484107..f80b8090971 100644 --- a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx +++ b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx @@ -14,11 +14,20 @@ /// \author Laura Serksnyte, TU München, laura.serksnyte@tum.de /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch /// \author Malgorzata Janik, WUT Warsaw, majanik@cern.ch +/// \author Pritam Chakraborty, WUT Warsaw, pritam.chakraborty@cern.ch +/// \author Shirajum Monira, WUT Warsaw, shirajum.monira@cern.ch -#include // FIXME - +#include #include +#include +#include +#include +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "Common/CCDB/ctpRateFetcher.h" #include "Common/Core/trackUtilities.h" +#include "Common/Core/RecoDecay.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Centrality.h" @@ -29,8 +38,9 @@ #include "PWGCF/FemtoUniverse/Core/FemtoUniverseCollisionSelection.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseV0Selection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseCascadeSelection.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniversePhiSelection.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/Core/HfHelper.h" @@ -45,23 +55,30 @@ #include "ReconstructionDataFormats/Track.h" #include "TMath.h" #include "TLorentzVector.h" +#include "Framework/O2DatabasePDGPlugin.h" using namespace o2; -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::constants::physics; namespace o2::aod { using FemtoFullCollision = soa::Join::iterator; +using FemtoFullCollisionCentPP = + soa::Join::iterator; using FemtoFullCollisionCentRun2 = - soa::Join::iterator; + soa::Join::iterator; using FemtoFullCollisionCentRun3 = - soa::Join::iterator; + soa::Join::iterator; using FemtoFullCollisionMC = soa::Join::iterator; - +using FemtoFullCollisionCentRun3MCs = + soa::Join; +using FemtoFullCollisionCentRun3MC = + soa::Join::iterator; using FemtoFullTracks = soa::Join outputCollision; +struct FemtoUniverseProducerTask { + Produces outputCollision; + Produces outputCollExtra; Produces outputParts; - Produces outputPartsMC; + Produces outputPartsMC; Produces outputDebugParts; Produces outputPartsMCLabels; Produces outputDebugPartsMC; + Produces outputCascParts; - Configurable ConfIsDebug{"ConfIsDebug", true, "Enable Debug tables"}; + Configurable confIsDebug{"confIsDebug", true, "Enable Debug tables"}; // Choose if filtering or skimming version is run - Configurable ConfIsTrigger{"ConfIsTrigger", false, "Store all collisions"}; + // Configurable confIsTrigger{"confIsTrigger", false, "Store all collisions"}; //Commented: not used configurable // Choose if running on converted data or Run3 / Pilot - Configurable ConfIsRun3{"ConfIsRun3", false, "Running on Run3 or pilot"}; - Configurable ConfIsMC{"ConfIsMC", false, "Running on MC; implemented only for Run3"}; + Configurable confIsRun3{"confIsRun3", true, "Running on Run3 or pilot"}; + // Configurable confIsMC{"confIsMC", false, "Running on MC; implemented only for Run3"}; //Commented: not used configurable - Configurable ConfIsForceGRP{"ConfIsForceGRP", false, "Set true if the magnetic field configuration is not available in the usual CCDB directory (e.g. for Run 2 converted data or unanchorad Monte Carlo)"}; + Configurable confIsForceGRP{"confIsForceGRP", false, "Set true if the magnetic field configuration is not available in the usual CCDB directory (e.g. for Run 2 converted data or unanchorad Monte Carlo)"}; - Configurable ConfDoSpher{"ConfDoSpher", false, "Calculate sphericity. If false sphericity will take value of 2."}; + Configurable confDoSpher{"confDoSpher", false, "Calculate sphericity. If false sphericity will take value of 2."}; + Configurable confStoreMCmothers{"confStoreMCmothers", false, "MC truth: Fill with not only primary particles and store mothers' PDG in tempFitVar."}; + Configurable confFillCollExt{"confFillCollExt", false, "Option to fill collision extended table"}; /// Event cuts FemtoUniverseCollisionSelection colCuts; - Configurable ConfEvtUseTPCmult{"ConfEvtUseTPCmult", false, "Use multiplicity based on the number of tracks with TPC information"}; - Configurable ConfEvtZvtx{"ConfEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; - Configurable ConfEvtTriggerCheck{"ConfEvtTriggerCheck", true, "Evt sel: check for trigger"}; - Configurable ConfEvtTriggerSel{"ConfEvtTriggerSel", kINT7, "Evt sel: trigger"}; - Configurable ConfEvtOfflineCheck{"ConfEvtOfflineCheck", false, "Evt sel: check for offline selection"}; - Configurable ConfIsActivateV0{"ConfIsActivateV0", true, "Activate filling of V0 into femtouniverse tables"}; - Configurable ConfIsActivatePhi{"ConfIsActivatePhi", false, "Activate filling of Phi into femtouniverse tables"}; - Configurable ConfMCTruthAnalysisWithPID{"ConfMCTruthAnalysisWithPID", true, "1: take only particles with specified PDG, 0: all particles (for MC Truth)"}; - Configurable> ConfMCTruthPDGCodes{"ConfMCTruthPDGCodes", std::vector{211, -211, 2212, -2212, 333}, "PDG of particles to be stored"}; - Configurable ConfCentFT0Min{"ConfCentFT0Min", 0.f, "Min CentFT0 value for centrality selection"}; - Configurable ConfCentFT0Max{"ConfCentFT0Max", 200.f, "Max CentFT0 value for centrality selection"}; - - Filter CustomCollCentFilter = (aod::cent::centFT0C > ConfCentFT0Min) && - (aod::cent::centFT0C < ConfCentFT0Max); + Configurable confEvtUseTPCmult{"confEvtUseTPCmult", false, "Use multiplicity based on the number of tracks with TPC information"}; + Configurable confEvtZvtx{"confEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; + Configurable confEvtTriggerCheck{"confEvtTriggerCheck", true, "Evt sel: check for trigger"}; + Configurable confEvtTriggerSel{"confEvtTriggerSel", kINT7, "Evt sel: trigger"}; + Configurable confEvtOfflineCheck{"confEvtOfflineCheck", false, "Evt sel: check for offline selection"}; + Configurable confIsActivateV0{"confIsActivateV0", false, "Activate filling of V0 into femtouniverse tables"}; + Configurable confActivateSecondaries{"confActivateSecondaries", false, "Fill secondary MC gen particles that were reconstructed"}; + Configurable confIsActivateCascade{"confIsActivateCascade", false, "Activate filling of Cascade into femtouniverse tables"}; + Configurable confIsSelectCascOmega{"confIsSelectCascOmega", false, "Select Omegas for cascade analysis"}; + Configurable confIsActivatePhi{"confIsActivatePhi", false, "Activate filling of Phi into femtouniverse tables"}; + Configurable confIsActiveD0{"confIsActiveD0", false, "Activate filling FU tables for D0/D0bar mesons"}; + Configurable confMCTruthAnalysisWithPID{"confMCTruthAnalysisWithPID", true, "1: take only particles with specified PDG, 0: all particles (for MC Truth)"}; + Configurable> confMCTruthPDGCodes{"confMCTruthPDGCodes", std::vector{211, -211, 2212, -2212, 333}, "PDG of particles to be stored"}; + Configurable confCentFT0Min{"confCentFT0Min", 0.f, "Min CentFT0 value for centrality selection"}; + Configurable confCentFT0Max{"confCentFT0Max", 200.f, "Max CentFT0 value for centrality selection"}; + Configurable confEvIsGoodZvtxFT0vsPV{"confEvIsGoodZvtxFT0vsPV", true, "Require kIsGoodZvtxFT0vsPV selection on Events."}; + Configurable confEvNoSameBunchPileup{"confEvNoSameBunchPileup", true, "Require kNoSameBunchPileup selection on Events."}; + Configurable confIsUsePileUp{"confIsUsePileUp", true, "Required for choosing whether to run the pile-up cuts"}; + Configurable confEvIsVertexITSTPC{"confEvIsVertexITSTPC", true, "Require kIsVertexITSTPC selection on Events"}; + Configurable confTPCOccupancyMin{"confTPCOccupancyMin", 0, "Minimum value for TPC Occupancy selection"}; + Configurable confTPCOccupancyMax{"confTPCOccupancyMax", 500, "Maximum value for TPC Occupancy selection"}; + + Filter customCollCentFilter = (aod::cent::centFT0C > confCentFT0Min) && + (aod::cent::centFT0C < confCentFT0Max); // just sanity check to make sure in case there are problems in conversion or // MC production it does not affect results - Configurable ConfTrkRejectNotPropagated{"ConfTrkRejectNotPropagated", false, "True: reject not propagated tracks"}; + Configurable confTrkRejectNotPropagated{"confTrkRejectNotPropagated", false, "True: reject not propagated tracks"}; // Configurable ConfRejectITSHitandTOFMissing{ // "ConfRejectITSHitandTOFMissing", false, // "True: reject if neither ITS hit nor TOF timing satisfied"}; - Configurable ConfTrkPDGCode{"ConfTrkPDGCode", 2212, "PDG code of the selected track for Monte Carlo truth"}; // only for checking the particle origin (particles for which PDG does not match are marked as "Fake") FemtoUniverseTrackSelection trackCuts; - struct : o2::framework::ConfigurableGroup { - Configurable ConfPtLowFilterCut{"ConfPtLowFilterCut", 0.14, "Lower limit for Pt for the global track"}; // pT low - Configurable ConfPtHighFilterCut{"ConfPtHighFilterCut", 5.0, "Higher limit for Pt for the global track"}; // pT high - Configurable ConfEtaFilterCut{"ConfEtaFilterCut", 0.8, "Eta cut for the global track"}; // eta - Configurable ConfDcaXYFilterCut{"ConfDcaXYFilterCut", 2.4, "Value for DCA_XY for the global track"}; // max dca to vertex XY - Configurable ConfDcaZFilterCut{"ConfDcaZFilterCut", 3.2, "Value for DCA_Z for the global track"}; // max dca to vertex Z - } ConfFilterCuts; - - Configurable> ConfTrkCharge{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kSign, "ConfTrk"), std::vector{-1, 1}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kSign, "Track selection: ")}; - Configurable> ConfTrkPtmin{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kpTMin, "ConfTrk"), std::vector{0.5f, 0.4f, 0.6f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kpTMin, "Track selection: ")}; - Configurable> ConfTrkPtmax{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kpTMax, "ConfTrk"), std::vector{5.4f, 5.6f, 5.5f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kpTMax, "Track selection: ")}; - Configurable> ConfTrkEta{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kEtaMax, "ConfTrk"), std::vector{0.8f, 0.7f, 0.9f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kEtaMax, "Track selection: ")}; - Configurable> ConfTrkTPCnclsMin{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kTPCnClsMin, "ConfTrk"), std::vector{70.f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kTPCnClsMin, "Track selection: ")}; - Configurable> ConfTrkTPCfCls{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kTPCfClsMin, "ConfTrk"), std::vector{0.83f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kTPCfClsMin, "Track selection: ")}; - Configurable> ConfTrkTPCcRowsMin{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kTPCcRowsMin, "ConfTrk"), std::vector{70.f, 60.f, 80.f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kTPCcRowsMin, "Track selection: ")}; - Configurable> ConfTrkTPCsCls{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kTPCsClsMax, "ConfTrk"), std::vector{0.1f, 160.f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kTPCsClsMax, "Track selection: ")}; - Configurable> ConfTrkITSnclsMin{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kITSnClsMin, "ConfTrk"), std::vector{-1.f, 2.f, 4.f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kITSnClsMin, "Track selection: ")}; - Configurable> ConfTrkITSnclsIbMin{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kITSnClsIbMin, "ConfTrk"), std::vector{-1.f, 1.f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kITSnClsIbMin, "Track selection: ")}; - Configurable> ConfTrkDCAxyMax{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kDCAxyMax, "ConfTrk"), std::vector{0.1f, 3.5f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kDCAxyMax, "Track selection: ")}; - Configurable> ConfTrkDCAzMax{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kDCAzMax, "ConfTrk"), std::vector{0.2f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kDCAzMax, "Track selection: ")}; /// \todo Reintegrate PID to the general selection container - Configurable> ConfTrkPIDnSigmaMax{FemtoUniverseTrackSelection::getSelectionName(femtoUniverseTrackSelection::kPIDnSigmaMax, "ConfTrk"), std::vector{3.5f, 3.f, 2.5f}, FemtoUniverseTrackSelection::getSelectionHelper(femtoUniverseTrackSelection::kPIDnSigmaMax, "Track selection: ")}; - Configurable ConfTrkPIDnSigmaOffsetTPC{"ConfTrkPIDnSigmaOffsetTPC", 0., "Offset for TPC nSigma because of bad calibration"}; - Configurable ConfTrkPIDnSigmaOffsetTOF{"ConfTrkPIDnSigmaOffsetTOF", 0., "Offset for TOF nSigma because of bad calibration"}; - Configurable> ConfTrkPIDspecies{"ConfTrkPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Kaon, o2::track::PID::Proton, o2::track::PID::Deuteron}, "Trk sel: Particles species for PID (Pion=2, Kaon=3, Proton=4, Deuteron=5)"}; - // Numbers from ~/alice/O2/DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h //static constexpr ID Pion = 2; static constexpr ID Kaon = 3; static constexpr ID Proton = 4; static constexpr ID Deuteron = 5; - Configurable ConfTOFpTmin{"ConfTOFpTmin", 500, "TOF pT min"}; + Configurable> confTrkCharge{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kSign, "ConfTrk"), std::vector{-1, 1}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kSign, "Track selection: ")}; + Configurable> confTrkPtmin{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kpTMin, "ConfTrk"), std::vector{0.5f, 0.4f, 0.6f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kpTMin, "Track selection: ")}; + Configurable> confTrkPtmax{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kpTMax, "ConfTrk"), std::vector{5.4f, 5.6f, 5.5f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kpTMax, "Track selection: ")}; + Configurable> confTrkEta{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kEtaMax, "ConfTrk"), std::vector{0.8f, 0.7f, 0.9f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kEtaMax, "Track selection: ")}; + Configurable> confTrkTPCnclsMin{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kTPCnClsMin, "ConfTrk"), std::vector{70.f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kTPCnClsMin, "Track selection: ")}; + Configurable> confTrkTPCfCls{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kTPCfClsMin, "ConfTrk"), std::vector{0.83f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kTPCfClsMin, "Track selection: ")}; + Configurable> confTrkTPCcRowsMin{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kTPCcRowsMin, "ConfTrk"), std::vector{70.f, 60.f, 80.f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kTPCcRowsMin, "Track selection: ")}; + Configurable> confTrkTPCsCls{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kTPCsClsMax, "ConfTrk"), std::vector{0.1f, 160.f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kTPCsClsMax, "Track selection: ")}; + Configurable> confTrkTPCfracsCls{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kTPCfracsClsMax, "ConfTrk"), std::vector{0.1f, 160.f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kTPCfracsClsMax, "Track selection: ")}; + Configurable> confTrkITSnclsMin{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kITSnClsMin, "ConfTrk"), std::vector{-1.f, 2.f, 4.f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kITSnClsMin, "Track selection: ")}; + Configurable> confTrkITSnclsIbMin{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kITSnClsIbMin, "ConfTrk"), std::vector{-1.f, 1.f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kITSnClsIbMin, "Track selection: ")}; + Configurable> confTrkDCAxyMax{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kDCAxyMax, "ConfTrk"), std::vector{0.1f, 3.5f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kDCAxyMax, "Track selection: ")}; + Configurable> confTrkDCAzMax{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kDCAzMax, "ConfTrk"), std::vector{0.2f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kDCAzMax, "Track selection: ")}; /// \todo Reintegrate PID to the general selection container + Configurable> confTrkPIDnSigmaMax{FemtoUniverseTrackSelection::getSelectionName(femto_universe_track_selection::kPIDnSigmaMax, "ConfTrk"), std::vector{3.5f, 3.f, 2.5f}, FemtoUniverseTrackSelection::getSelectionHelper(femto_universe_track_selection::kPIDnSigmaMax, "Track selection: ")}; + Configurable> confTrkPIDspecies{"confTrkPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Kaon, o2::track::PID::Proton, o2::track::PID::Deuteron}, "Trk sel: Particles species for PID (Pion=2, Kaon=3, Proton=4, Deuteron=5)"}; + // Numbers from ~/alice/O2/DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h //static constexpr ID Pion = 2; static constexpr ID Kaon = 3; static constexpr ID Proton = 4; static constexpr ID Deuteron = 5; + } ConfTrkSelection; + + Configurable confTrkPIDnSigmaOffsetTPC{"confTrkPIDnSigmaOffsetTPC", 0., "Offset for TPC nSigma because of bad calibration"}; + Configurable confTrkPIDnSigmaOffsetTOF{"confTrkPIDnSigmaOffsetTOF", 0., "Offset for TOF nSigma because of bad calibration"}; + Configurable confTOFpTmin{"confTOFpTmin", 500, "TOF pT min"}; // TrackSelection *o2PhysicsTrackSelection; /// \todo Labeled array (see Track-Track task) // V0 FemtoUniverseV0Selection v0Cuts; - Configurable> ConfV0Sign{FemtoUniverseV0Selection::getSelectionName(femtoUniverseV0Selection::kV0Sign, "ConfV0"), std::vector{-1, 1}, FemtoUniverseV0Selection::getSelectionHelper(femtoUniverseV0Selection::kV0Sign, "V0 selection: ")}; - Configurable> ConfV0PtMin{FemtoUniverseV0Selection::getSelectionName(femtoUniverseV0Selection::kV0pTMin, "ConfV0"), std::vector{0.3f, 0.4f, 0.5f}, FemtoUniverseV0Selection::getSelectionHelper(femtoUniverseV0Selection::kV0pTMin, "V0 selection: ")}; - Configurable> ConfV0PtMax{FemtoUniverseV0Selection::getSelectionName(femtoUniverseV0Selection::kV0pTMax, "ConfV0"), std::vector{3.3f, 3.4f, 3.5f}, FemtoUniverseV0Selection::getSelectionHelper(femtoUniverseV0Selection::kV0pTMax, "V0 selection: ")}; - Configurable> ConfV0EtaMax{FemtoUniverseV0Selection::getSelectionName(femtoUniverseV0Selection::kV0etaMax, "ConfV0"), std::vector{0.8f, 0.7f, 0.9f}, FemtoUniverseV0Selection::getSelectionHelper(femtoUniverseV0Selection::kV0etaMax, "V0 selection: ")}; - Configurable> ConfV0DCADaughMax{FemtoUniverseV0Selection::getSelectionName(femtoUniverseV0Selection::kV0DCADaughMax, "ConfV0"), std::vector{1.2f, 1.5f}, FemtoUniverseV0Selection::getSelectionHelper(femtoUniverseV0Selection::kV0DCADaughMax, "V0 selection: ")}; - Configurable> ConfV0CPAMin{FemtoUniverseV0Selection::getSelectionName(femtoUniverseV0Selection::kV0CPAMin, "ConfV0"), std::vector{0.99f, 0.995f}, FemtoUniverseV0Selection::getSelectionHelper(femtoUniverseV0Selection::kV0CPAMin, "V0 selection: ")}; - Configurable> ConfV0TranRadMin{FemtoUniverseV0Selection::getSelectionName(femtoUniverseV0Selection::kV0TranRadMin, "ConfV0"), std::vector{0.2f}, FemtoUniverseV0Selection::getSelectionHelper(femtoUniverseV0Selection::kV0TranRadMin, "V0 selection: ")}; - Configurable> ConfV0TranRadMax{FemtoUniverseV0Selection::getSelectionName(femtoUniverseV0Selection::kV0TranRadMax, "ConfV0"), std::vector{100.f}, FemtoUniverseV0Selection::getSelectionHelper(femtoUniverseV0Selection::kV0TranRadMax, "V0 selection: ")}; - Configurable> ConfV0DecVtxMax{FemtoUniverseV0Selection::getSelectionName(femtoUniverseV0Selection::kV0DecVtxMax, "ConfV0"), std::vector{100.f}, FemtoUniverseV0Selection::getSelectionHelper(femtoUniverseV0Selection::kV0DecVtxMax, "V0 selection: ")}; - - Configurable> ConfChildCharge{"ConfChildSign", std::vector{-1, 1}, "V0 Child sel: Charge"}; - Configurable> ConfChildEtaMax{"ConfChildEtaMax", std::vector{0.8f}, "V0 Child sel: max eta"}; - Configurable> ConfChildTPCnClsMin{"ConfChildTPCnClsMin", std::vector{80.f, 70.f, 60.f}, "V0 Child sel: Min. nCls TPC"}; - Configurable> ConfChildDCAMin{"ConfChildDCAMin", std::vector{0.05f, 0.06f}, "V0 Child sel: Max. DCA Daugh to PV (cm)"}; - Configurable> ConfChildPIDnSigmaMax{"ConfChildPIDnSigmaMax", std::vector{5.f, 4.f}, "V0 Child sel: Max. PID nSigma TPC"}; - Configurable> ConfChildPIDspecies{"ConfChildPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Proton}, "V0 Child sel: Particles species for PID"}; - - Configurable ConfV0InvMassLowLimit{"ConfV0InvV0MassLowLimit", 1.05, "Lower limit of the V0 invariant mass"}; - Configurable ConfV0InvMassUpLimit{"ConfV0InvV0MassUpLimit", 1.30, "Upper limit of the V0 invariant mass"}; - - Configurable ConfV0RejectKaons{"ConfV0RejectKaons", false, "Switch to reject kaons"}; - Configurable ConfV0InvKaonMassLowLimit{"ConfV0InvKaonMassLowLimit", 0.48, "Lower limit of the V0 invariant mass for Kaon rejection"}; - Configurable ConfV0InvKaonMassUpLimit{"ConfV0InvKaonMassUpLimit", 0.515, "Upper limit of the V0 invariant mass for Kaon rejection"}; - - Filter GlobalCutFilter = requireGlobalTrackInFilter(); - - Filter CustomTrackFilter = (aod::track::pt > ConfFilterCuts.ConfPtLowFilterCut) && - (aod::track::pt < ConfFilterCuts.ConfPtHighFilterCut) && - (nabs(aod::track::eta) < ConfFilterCuts.ConfEtaFilterCut) && - (aod::track::dcaXY < ConfFilterCuts.ConfDcaXYFilterCut) && - (aod::track::dcaZ < ConfFilterCuts.ConfDcaZFilterCut); - - // PHI - FemtoUniversePhiSelection phiCuts; struct : o2::framework::ConfigurableGroup { - Configurable> ConfPhiSign{FemtoUniversePhiSelection::getSelectionName(femtoUniversePhiSelection::kPhiSign, "ConfPhi"), std::vector{-1, 1}, FemtoUniversePhiSelection::getSelectionHelper(femtoUniversePhiSelection::kPhiSign, "Phi selection: ")}; - Configurable> ConfPhiPtMin{FemtoUniversePhiSelection::getSelectionName(femtoUniversePhiSelection::kPhipTMin, "ConfPhi"), std::vector{0.3f, 0.4f, 0.5f}, FemtoUniversePhiSelection::getSelectionHelper(femtoUniversePhiSelection::kPhipTMin, "Phi selection: ")}; - Configurable> ConfPhiPtMax{FemtoUniversePhiSelection::getSelectionName(femtoUniversePhiSelection::kPhipTMax, "ConfPhi"), std::vector{3.3f, 3.4f, 3.5f}, FemtoUniversePhiSelection::getSelectionHelper(femtoUniversePhiSelection::kPhipTMax, "Phi selection: ")}; - Configurable> ConfPhiEtaMax{FemtoUniversePhiSelection::getSelectionName(femtoUniversePhiSelection::kPhietaMax, "ConfPhi"), std::vector{0.8f, 0.7f, 0.9f}, FemtoUniversePhiSelection::getSelectionHelper(femtoUniversePhiSelection::kPhietaMax, "Phi selection: ")}; - Configurable> ConfPhiDCADaughMax{FemtoUniversePhiSelection::getSelectionName(femtoUniversePhiSelection::kPhiDCADaughMax, "ConfPhi"), std::vector{1.2f, 1.5f}, FemtoUniversePhiSelection::getSelectionHelper(femtoUniversePhiSelection::kPhiDCADaughMax, "Phi selection: ")}; - Configurable> ConfPhiCPAMin{FemtoUniversePhiSelection::getSelectionName(femtoUniversePhiSelection::kPhiCPAMin, "ConfPhi"), std::vector{0.99f, 0.995f}, FemtoUniversePhiSelection::getSelectionHelper(femtoUniversePhiSelection::kPhiCPAMin, "Phi selection: ")}; - Configurable> ConfPhiTranRadMin{FemtoUniversePhiSelection::getSelectionName(femtoUniversePhiSelection::kPhiTranRadMin, "ConfPhi"), std::vector{0.2f}, FemtoUniversePhiSelection::getSelectionHelper(femtoUniversePhiSelection::kPhiTranRadMin, "Phi selection: ")}; - Configurable> ConfPhiTranRadMax{FemtoUniversePhiSelection::getSelectionName(femtoUniversePhiSelection::kPhiTranRadMax, "ConfPhi"), std::vector{100.f}, FemtoUniversePhiSelection::getSelectionHelper(femtoUniversePhiSelection::kPhiTranRadMax, "Phi selection: ")}; - Configurable> ConfPhiDecVtxMax{FemtoUniversePhiSelection::getSelectionName(femtoUniversePhiSelection::kPhiDecVtxMax, "ConfPhi"), std::vector{100.f}, FemtoUniversePhiSelection::getSelectionHelper(femtoUniversePhiSelection::kPhiDecVtxMax, "Phi selection: ")}; - } ConfPhiSelection; + // Configurable confIsFillV0s{"confIsFillV0s", false, "Choice to fill V0s"}; //Commented: not used configurable + Configurable> confV0Sign{FemtoUniverseV0Selection::getSelectionName(femto_universe_v0_selection::kV0Sign, "ConfV0"), std::vector{-1, 1}, FemtoUniverseV0Selection::getSelectionHelper(femto_universe_v0_selection::kV0Sign, "V0 selection: ")}; + Configurable> confV0PtMin{FemtoUniverseV0Selection::getSelectionName(femto_universe_v0_selection::kV0pTMin, "ConfV0"), std::vector{0.3f, 0.4f, 0.5f}, FemtoUniverseV0Selection::getSelectionHelper(femto_universe_v0_selection::kV0pTMin, "V0 selection: ")}; + Configurable> confV0PtMax{FemtoUniverseV0Selection::getSelectionName(femto_universe_v0_selection::kV0pTMax, "ConfV0"), std::vector{3.3f, 3.4f, 3.5f}, FemtoUniverseV0Selection::getSelectionHelper(femto_universe_v0_selection::kV0pTMax, "V0 selection: ")}; + Configurable> confV0EtaMax{FemtoUniverseV0Selection::getSelectionName(femto_universe_v0_selection::kV0etaMax, "ConfV0"), std::vector{0.8f, 0.7f, 0.9f}, FemtoUniverseV0Selection::getSelectionHelper(femto_universe_v0_selection::kV0etaMax, "V0 selection: ")}; + Configurable> confV0DCADaughMax{FemtoUniverseV0Selection::getSelectionName(femto_universe_v0_selection::kV0DCADaughMax, "ConfV0"), std::vector{1.2f, 1.5f}, FemtoUniverseV0Selection::getSelectionHelper(femto_universe_v0_selection::kV0DCADaughMax, "V0 selection: ")}; + Configurable> confV0CPAMin{FemtoUniverseV0Selection::getSelectionName(femto_universe_v0_selection::kV0CPAMin, "ConfV0"), std::vector{0.99f, 0.995f}, FemtoUniverseV0Selection::getSelectionHelper(femto_universe_v0_selection::kV0CPAMin, "V0 selection: ")}; + Configurable> confV0TranRadMin{FemtoUniverseV0Selection::getSelectionName(femto_universe_v0_selection::kV0TranRadMin, "ConfV0"), std::vector{0.2f}, FemtoUniverseV0Selection::getSelectionHelper(femto_universe_v0_selection::kV0TranRadMin, "V0 selection: ")}; + Configurable> confV0TranRadMax{FemtoUniverseV0Selection::getSelectionName(femto_universe_v0_selection::kV0TranRadMax, "ConfV0"), std::vector{100.f}, FemtoUniverseV0Selection::getSelectionHelper(femto_universe_v0_selection::kV0TranRadMax, "V0 selection: ")}; + Configurable> confV0DecVtxMax{FemtoUniverseV0Selection::getSelectionName(femto_universe_v0_selection::kV0DecVtxMax, "ConfV0"), std::vector{100.f}, FemtoUniverseV0Selection::getSelectionHelper(femto_universe_v0_selection::kV0DecVtxMax, "V0 selection: ")}; + + Configurable> confChildCharge{"confChildCharge", std::vector{-1, 1}, "V0 Child sel: Charge"}; + Configurable> confChildEtaMax{"confChildEtaMax", std::vector{0.8f}, "V0 Child sel: max eta"}; + Configurable> confChildTPCnClsMin{"confChildTPCnClsMin", std::vector{80.f, 70.f, 60.f}, "V0 Child sel: Min. nCls TPC"}; + Configurable> confChildDCAMin{"confChildDCAMin", std::vector{0.05f, 0.06f}, "V0 Child sel: Max. DCA Daugh to PV (cm)"}; + Configurable> confChildPIDnSigmaMax{"confChildPIDnSigmaMax", std::vector{5.f, 4.f}, "V0 Child sel: Max. PID nSigma TPC"}; + Configurable> confChildPIDspecies{"confChildPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Proton}, "V0 Child sel: Particles species for PID"}; + + Configurable confV0InvMassLowLimit{"confV0InvMassLowLimit", 1.05, "Lower limit of the V0 invariant mass"}; + Configurable confV0InvMassUpLimit{"confV0InvMassUpLimit", 1.30, "Upper limit of the V0 invariant mass"}; + + Configurable confV0RejectKaons{"confV0RejectKaons", false, "Switch to reject kaons"}; + Configurable confV0InvKaonMassLowLimit{"confV0InvKaonMassLowLimit", 0.48, "Lower limit of the V0 invariant mass for Kaon rejection"}; + Configurable confV0InvKaonMassUpLimit{"confV0InvKaonMassUpLimit", 0.515, "Upper limit of the V0 invariant mass for Kaon rejection"}; + } ConfV0Selection; struct : o2::framework::ConfigurableGroup { - Configurable> ConfPhiChildCharge{"ConfPhiChildSign", std::vector{-1, 1}, "Phi Child sel: Charge"}; - Configurable> ConfPhiChildEtaMax{"ConfPhiChildEtaMax", std::vector{0.8f}, "Phi Child sel: max eta"}; - Configurable> ConfPhiChildTPCnClsMin{"ConfPhiChildTPCnClsMin", std::vector{80.f, 70.f, 60.f}, "Phi Child sel: Min. nCls TPC"}; - Configurable> ConfPhiChildDCAMin{"ConfPhiChildDCAMin", std::vector{0.05f, 0.06f}, "Phi Child sel: Max. DCA Daugh to PV (cm)"}; - Configurable> ConfPhiChildPIDnSigmaMax{"ConfPhiChildPIDnSigmaMax", std::vector{5.f, 4.f}, "Phi Child sel: Max. PID nSigma TPC"}; - Configurable> ConfPhiChildPIDspecies{"ConfPhiChildPIDspecies", std::vector{o2::track::PID::Kaon, o2::track::PID::Kaon}, "Phi Child sel: Particles species for PID"}; - } ConfPhiChildSelection; + Configurable confPtLowFilterCut{"confPtLowFilterCut", 0.14, "Lower limit for Pt for the global track"}; // pT low + Configurable confPtHighFilterCut{"confPtHighFilterCut", 5.0, "Higher limit for Pt for the global track"}; // pT high + Configurable confEtaFilterCut{"confEtaFilterCut", 0.8, "Eta cut for the global track"}; // eta + Configurable confDxaXYCustom0Cut{"confDxaXYCustom0Cut", false, "Enable Custom Dcaxy < [0] cut."}; + Configurable confDcaXYFilterCut{"confDcaXYFilterCut", 2.4, "Value for DCA_XY for the global track"}; // max dca to vertex XY + Configurable confDcaZFilterCut{"confDcaZFilterCut", 3.2, "Value for DCA_Z for the global track"}; // max dca to vertex Z + Configurable confDcaXYCustom1Cut{"confDcaXYCustom1Cut", true, "Enable Custom |DCAxy| < [1] + [2]/pt cut."}; + Configurable confDcaXYCustom11FilterCut{"confDcaXYCustom11FilterCut", 0.004, "Value for [1] custom DCAxy cut -> |DCAxy| < [1] + [2]/pT"}; + Configurable confDcaXYCustom12FilterCut{"confDcaXYCustom12FilterCut", 0.013, "Value for [2] custom DCAxy cut -> |DCAxy| < [1] + [2]/pT"}; + } ConfFilterCuts; + Filter globalCutFilter = requireGlobalTrackInFilter(); + Filter customTrackFilter = (aod::track::pt > ConfFilterCuts.confPtLowFilterCut) && + (aod::track::pt < ConfFilterCuts.confPtHighFilterCut) && + (nabs(aod::track::eta) < ConfFilterCuts.confEtaFilterCut) && + (!ConfFilterCuts.confDxaXYCustom0Cut || (aod::track::dcaXY < ConfFilterCuts.confDcaXYFilterCut)) && // true if configurable set to false or if configurable is true and it passes the selection + (aod::track::dcaZ < ConfFilterCuts.confDcaZFilterCut) && + (!ConfFilterCuts.confDcaXYCustom1Cut || (nabs(aod::track::dcaXY) < ConfFilterCuts.confDcaXYCustom11FilterCut + ConfFilterCuts.confDcaXYCustom12FilterCut / aod::track::pt)); // same logic here + + // CASCADE + FemtoUniverseCascadeSelection cascadeCuts; struct : o2::framework::ConfigurableGroup { - Configurable ConfNsigmaCombinedKaon{"ConfNsigmaCombinedKaon", 3.0, "TPC and TOF Kaon Sigma (combined) for momentum > 0.4"}; - Configurable ConfNsigmaTPCKaon{"ConfNsigmaTPCKaon", 3.0, "TPC Kaon Sigma for momentum < 0.4"}; - Configurable ConfNsigmaTPCTOFKaon{"ConfNsigmaTPCTOFKaon", true, "Use TPC and TOF for PID of Kaons"}; - Configurable ConfInvMassLowLimitPhi{"ConfInvMassLowLimitPhi", 1.011, "Lower limit of the Phi invariant mass"}; // change that to do invariant mass cut - Configurable ConfInvMassUpLimitPhi{"ConfInvMassUpLimitPhi", 1.027, "Upper limit of the Phi invariant mass"}; - } ConfPhiCommon; - // PHI child one - struct : o2::framework::ConfigurableGroup { - Configurable ConfPDGCodePartOne{"ConfPDGCodePartOne", 321, "Particle 1 - PDG code"}; - } ConfPhiChildOne; - // PHI child two + // Configurable confIsFillCascades{"confIsFillCascades", false, "Choice to fill cascades"}; //Commented: not used configurable + Configurable> confCascSign{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeSign, "ConfCasc"), std::vector{-1, 1}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeSign, "Cascade selection: ")}; + Configurable> confCascPtMin{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadepTMin, "ConfCasc"), std::vector{0.3f, 0.4f, 0.5f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadepTMin, "Cascade selection: ")}; + Configurable> confCascPtMax{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadepTMax, "ConfCasc"), std::vector{3.3f, 3.4f, 3.5f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadepTMax, "Cascade selection: ")}; + Configurable> confCascEtaMax{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeetaMax, "ConfCasc"), std::vector{0.8f, 0.7f, 0.9f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeetaMax, "Cascade selection: ")}; + Configurable> confCascV0DCADaughMax{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeV0DCADaughMax, "ConfCasc"), std::vector{1.f, 1.2f, 1.5f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeV0DCADaughMax, "Cascade selection: ")}; + Configurable> confCascV0CPAMin{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeV0CPAMin, "ConfCasc"), std::vector{0.99f, 0.95f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeV0CPAMin, "Cascade selection: ")}; + Configurable> confCascV0TranRadMin{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeV0TranRadMin, "ConfCasc"), std::vector{0.2f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeV0TranRadMin, "Cascade selection: ")}; + Configurable> confCascV0TranRadMax{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeV0TranRadMax, "ConfCasc"), std::vector{100.f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeV0TranRadMax, "Cascade selection: ")}; + Configurable> confCascV0DecVtxMax{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeV0DecVtxMax, "ConfCasc"), std::vector{100.f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeV0DecVtxMax, "Cascade selection: ")}; + Configurable> confCascDCADaughMax{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeDCADaughMax, "ConfCasc"), std::vector{1.f, 1.2f, 1.5f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeDCADaughMax, "Cascade selection: ")}; + Configurable> confCascCPAMin{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeCPAMin, "ConfCasc"), std::vector{0.99f, 0.95f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeCPAMin, "Cascade selection: ")}; + Configurable> confCascTranRadMin{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeTranRadMin, "ConfCasc"), std::vector{0.2f, 0.5f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeTranRadMin, "Cascade selection: ")}; + Configurable> confCascTranRadMax{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeTranRadMax, "ConfCasc"), std::vector{100.f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeTranRadMax, "Cascade selection: ")}; + Configurable> confCascDecVtxMax{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeDecVtxMax, "ConfCasc"), std::vector{100.f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeDecVtxMax, "Cascade selection: ")}; + + Configurable> confCascDCAPosToPV{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeDCAPosToPV, "ConfCasc"), std::vector{0.1f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeDCAPosToPV, "Cascade selection: ")}; + Configurable> confCascDCANegToPV{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeDCANegToPV, "ConfCasc"), std::vector{0.1f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeDCANegToPV, "Cascade selection: ")}; + Configurable> confCascDCABachToPV{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeDCABachToPV, "ConfCasc"), std::vector{0.1f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeDCABachToPV, "Cascade selection: ")}; + Configurable> confCascDCAV0ToPV{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeDCAV0ToPV, "ConfCasc"), std::vector{0.01f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeDCAV0ToPV, "Cascade selection: ")}; + Configurable> confCascV0MassLowLimit{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeV0MassMin, "ConfCasc"), std::vector{1.05f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeV0MassMin, "Cascade selection: ")}; + Configurable> confCascV0MassUpLimit{FemtoUniverseCascadeSelection::getSelectionName(femto_universe_cascade_selection::kCascadeV0MassMax, "ConfCasc"), std::vector{1.30f}, FemtoUniverseCascadeSelection::getSelectionHelper(femto_universe_cascade_selection::kCascadeV0MassMax, "Cascade selection: ")}; + + Configurable> confCascChildCharge{"confCascChildCharge", std::vector{-1, 1}, "Cascade Child sel: Charge"}; + Configurable> confCascChildEtaMax{"confCascChildEtaMax", std::vector{0.8f}, "Cascade Child sel: max eta"}; + Configurable> confCascChildTPCnClsMin{"confCascChildTPCnClsMin", std::vector{80.f, 70.f, 60.f}, "Cascade Child sel: Min. nCls TPC"}; + // Configurable> confCascChildDCAMin{"confCascChildDCAMin", std::vector{0.05f, 0.06f}, "Cascade Child sel: Max. DCA Daugh to PV (cm)"}; //Commented: not used variable + Configurable> confCascChildPIDnSigmaMax{"confCascChildPIDnSigmaMax", std::vector{3.f, 4.f}, "Cascade Child sel: Max. PID nSigma TPC"}; + Configurable> confCascChildPIDspecies{"confCascChildPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Proton}, "Cascade Child sel: particle species for PID"}; + + Configurable confCascInvMassLowLimit{"confCascInvMassLowLimit", 1.25, "Lower limit of the cascade invariant mass"}; + Configurable confCascInvMassUpLimit{"confCascInvMassUpLimit", 1.40, "Upper limit of the cascade invariant mass"}; + + Configurable confCascRejectCompetingMass{"confCascRejectCompetingMass", false, "Switch on to reject Omegas (for Xi) or Xis (for Omegas)"}; + Configurable confCascInvCompetingMassLowLimit{"confCascInvCompetingMassLowLimit", 1.66, "Lower limit of the cascade invariant mass for competing mass rejection"}; + Configurable confCascInvCompetingMassUpLimit{"confCascInvCompetingMassUpLimit", 1.68, "Upper limit of the cascade invariant mass for competing mass rejection"}; + } ConfCascadeSelection; + + // PHI + FemtoUniversePhiSelection phiCuts; struct : o2::framework::ConfigurableGroup { - Configurable ConfPDGCodePartTwo{"ConfPDGCodePartTwo", 321, "Particle 2 - PDG code"}; - } ConfPhiChildTwo; + /// Phi meson + Configurable confPhiPtLowLimit{"confPhiPtLowLimit", 0.8, "Lower limit of the Phi pT."}; + Configurable confPhiPtHighLimit{"confPhiPtHighLimit", 4.0, "Higher limit of the Phi pT."}; + Configurable confPhiInvMassLowLimit{"confPhiInvMassLowLimit", 1.011, "Lower limit of the Phi invariant mass"}; + Configurable confPhiInvMassUpLimit{"confPhiInvMassUpLimit", 1.027, "Upper limit of the Phi invariant mass"}; + // Phi meson daughters + Configurable confPhiKaonRejectPionNsigma{"confPhiKaonRejectPionNsigma", 3.0, "Reject if particle could be a Pion combined nsigma value."}; + Configurable confPhiKaonRejectProtonNsigma{"confPhiKaonRejectProtonNsigma", 3.0, "Reject if particle could be a Proton combined nsigma value."}; + // Kaons + Configurable confPhiDoLFPID4Kaons{"confPhiDoLFPID4Kaons", true, "Switch on do PID for Kaons as in LF"}; + Configurable confPhiKaonNsigmaTPCfrom0_0to0_3{"confPhiKaonNsigmaTPCfrom0_0to0_3", 3.0, "Reject if Kaons in 0.0-0.3 are have TPC n sigma above this value."}; + Configurable confPhiKaonNsigmaTPCfrom0_3to0_45{"confPhiKaonNsigmaTPCfrom0_3to0_45", 2.0, "Reject if Kaons in 0.3-0.45 are have TPC n sigma above this value."}; + Configurable confPhiKaonNsigmaTPCfrom0_45to0_55{"confPhiKaonNsigmaTPCfrom0_45to0_55", 1.0, "Reject if Kaons in 0.45-0.55 are have TPC n sigma above this value."}; + Configurable confPhiKaonNsigmaTPCfrom0_55to1_5{"confPhiKaonNsigmaTPCfrom0_55to1_5", 3.0, "Reject if Kaons in 0.55-1.5 are have TPC n sigma above this value."}; + Configurable confPhiKaonNsigmaTOFfrom0_55to1_5{"confPhiKaonNsigmaTOFfrom0_55to1_5", 3.0, "Reject if Kaons in 0.55-1.5 are have TOF n sigma above this value."}; + Configurable confPhiKaonNsigmaTPCfrom1_5{"confPhiKaonNsigmaTPCfrom1_5", 3.0, "Reject if Kaons above 1.5 are have TPC n sigma above this value."}; + Configurable confPhiKaonNsigmaTOFfrom1_5{"confPhiKaonNsigmaTOFfrom1_5", 3.0, "Reject if Kaons above 1.5 are have TOF n sigma above this value."}; + } ConfPhiSelection; + + // PDG codes for fillMCParticle function + Configurable confPDGCodePartOne{"confPDGCodePartOne", 321, "Particle 1 - PDG code"}; + Configurable confPDGCodePartTwo{"confPDGCodePartTwo", 321, "Particle 2 - PDG code"}; // D0/D0bar mesons struct : o2::framework::ConfigurableGroup { - Configurable ConfD0D0barCandMaxY{"ConfD0D0barCandMaxY", -1., "max. cand. rapidity"}; - Configurable ConfD0D0barCandEtaCut{"ConfD0D0barCandEtaCut", 0.8, "max. cand. pseudorapidity"}; - Configurable ConfStoreD0D0barWithinTheMassRange{"ConfStoreD0D0barWithinTheMassRange", false, "Switch to save D0/D0bar within declared inv. mass range"}; - Configurable ConfStoreD0D0barInvMassLowLimit{"ConfStoreD0D0barInvMassLowLimit", 1.810, "Lower inv. mass limit of D0/D0bar candidate"}; - Configurable ConfStoreD0D0barInvMassUpLimit{"ConfStoreD0D0barInvMassUpLimit", 1.922, "Upper inv. mass limit of D0/D0bar candidate"}; + Configurable confD0D0barCandMaxY{"confD0D0barCandMaxY", -1., "max. cand. rapidity"}; + Configurable confD0D0barCandEtaCut{"confD0D0barCandEtaCut", 0.8, "max. cand. pseudorapidity"}; + Configurable yD0D0barCandRecoMax{"yD0D0barCandRecoMax", 0.8, "MC Reco, max. rapidity of D0/D0bar cand."}; + Configurable yD0D0barCandGenMax{"yD0D0barCandGenMax", 0.8, "MC Truth, max. rapidity of D0/D0bar cand."}; + Configurable storeD0D0barDoubleMassHypo{"storeD0D0barDoubleMassHypo", false, "Store D0/D0bar cand. which pass selection criteria for both, D0 and D0bar"}; + Configurable> classMlD0D0bar{"classMlD0D0bar", {0, 1, 2}, "Indexes of ML scores to be stored. Three indexes max."}; } ConfD0Selection; HfHelper hfHelper; - - bool IsKaonNSigma(float mom, float nsigmaTPCK, float nsigmaTOFK) + bool isKaonNSigma(float mom, float nsigmaTPCK, float nsigmaTOFK) { - //|nsigma_TPC| < 5 for p < 0.4 GeV/c - //|nsigma_combined| < 5 for p > 0.4 - - // using configurables: - // ConfNsigmaTPCTOFKaon -> are we doing TPC TOF PID for Kaons? (boolean) - // ConfNsigmaTPCKaon -> TPC Kaon Sigma for momentum < 0.4 - // ConfNsigmaCombinedKaon -> TPC and TOF Kaon Sigma (combined) for momentum > 0.4 if (mom < 0.3) { // 0.0-0.3 - if (TMath::Abs(nsigmaTPCK) < 3.0) { + if (std::abs(nsigmaTPCK) < ConfPhiSelection.confPhiKaonNsigmaTPCfrom0_0to0_3) { return true; } else { return false; } } else if (mom < 0.45) { // 0.30 - 0.45 - if (TMath::Abs(nsigmaTPCK) < 2.0) { + if (std::abs(nsigmaTPCK) < ConfPhiSelection.confPhiKaonNsigmaTPCfrom0_3to0_45) { return true; } else { return false; } } else if (mom < 0.55) { // 0.45-0.55 - if (TMath::Abs(nsigmaTPCK) < 1.0) { + if (std::abs(nsigmaTPCK) < ConfPhiSelection.confPhiKaonNsigmaTPCfrom0_45to0_55) { return true; } else { return false; } } else if (mom < 1.5) { // 0.55-1.5 (now we use TPC and TOF) - if ((TMath::Abs(nsigmaTOFK) < 3.0) && (TMath::Abs(nsigmaTPCK) < 3.0)) { + if ((std::abs(nsigmaTOFK) < ConfPhiSelection.confPhiKaonNsigmaTOFfrom0_55to1_5) && (std::abs(nsigmaTPCK) < ConfPhiSelection.confPhiKaonNsigmaTPCfrom0_55to1_5)) { { return true; } @@ -290,7 +351,52 @@ struct femtoUniverseProducerTask { return false; } } else if (mom > 1.5) { // 1.5 - - if ((TMath::Abs(nsigmaTOFK) < 2.0) && (TMath::Abs(nsigmaTPCK) < 3.0)) { + if ((std::abs(nsigmaTOFK) < ConfPhiSelection.confPhiKaonNsigmaTOFfrom1_5) && (std::abs(nsigmaTPCK) < ConfPhiSelection.confPhiKaonNsigmaTPCfrom1_5)) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + bool isKaonNSigmaLF(float mom, float nsigmaTPCK, float nsigmaTOFK, bool hasTOF) + { + if (mom < 0.5) { + if (std::abs(nsigmaTPCK) < 3.0) { + return true; + } else { + return false; + } + } else if (mom >= 0.5) { // 0.55-1.5 (now we use TPC and TOF) + if (!hasTOF) { + return false; + } else { + if (std::sqrt(nsigmaTPCK * nsigmaTPCK + nsigmaTOFK * nsigmaTOFK) < 3.0) { + return true; + } else { + return false; + } + } + } else { + return false; + } + } + + bool isKaonRejected(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi) + { + if (mom < 0.5) { + if (std::abs(nsigmaTPCPi) < ConfPhiSelection.confPhiKaonRejectPionNsigma.value) { + return true; + } else if (std::abs(nsigmaTPCPr) < ConfPhiSelection.confPhiKaonRejectProtonNsigma.value) { + return true; + } + } + if (mom > 0.5) { + if (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfPhiSelection.confPhiKaonRejectPionNsigma.value) { + return true; + } else if (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfPhiSelection.confPhiKaonRejectProtonNsigma.value) { return true; } else { return false; @@ -308,81 +414,84 @@ struct femtoUniverseProducerTask { // for now do not know why HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::QAObject}; + HistogramRegistry cascadeQaRegistry{"CascadeQAHistos", {}, OutputObjHandlingPolicy::QAObject}; - int mRunNumber; + int mRunNumber = 0; float mMagField; Service ccdb; /// Accessing the CCDB + ctpRateFetcher mRateFetcher; // inspired by zdcSP.cxx in PWGLF void init(InitContext&) { - if ((doprocessFullData || doprocessTrackPhiData || doprocessTrackData || doprocessTrackV0 || doprocessTrackD0mesonData || doprocessTrackCentRun2Data || doprocessTrackCentRun3Data) == false && (doprocessFullMC || doprocessTrackMC || doprocessTrackMCTruth) == false) { + if ((doprocessFullData || doprocessTrackPhiData || doprocessTrackData || doprocessTrackV0 || doprocessTrackCascadeData || doprocessTrackD0mesonData || doprocessTrackD0DataML || doprocessTrackCentRun2Data || doprocessTrackV0CentRun2Data || doprocessTrackCentRun3Data || doprocessV0CentRun3Data || doprocessCascadeCentRun3Data || doprocessTrackDataCentPP) == false && (doprocessFullMC || doprocessTrackMC || doprocessTrackMCTruth || doprocessTrackMCGen || doprocessTruthAndFullMCV0 || doprocessTrackD0MC || doprocessTruthAndFullMCCasc || doprocessFullMCCent || doprocessTrackCentRun3DataMC || doprocessTruthAndFullMCCentRun3 || doprocessTruthAndFullMCCentRun3V0) == false) { LOGF(fatal, "Neither processFullData nor processFullMC enabled. Please choose one."); } - if ((doprocessFullData || doprocessTrackPhiData || doprocessTrackData || doprocessTrackV0 || doprocessTrackD0mesonData || doprocessTrackCentRun2Data || doprocessTrackCentRun3Data) == true && (doprocessFullMC || doprocessTrackMC || doprocessTrackMCTruth) == true) { + if ((doprocessFullData || doprocessTrackPhiData || doprocessTrackData || doprocessTrackV0 || doprocessTrackCascadeData || doprocessTrackD0mesonData || doprocessTrackD0DataML || doprocessTrackCentRun2Data || doprocessTrackV0CentRun2Data || doprocessTrackCentRun3Data || doprocessV0CentRun3Data || doprocessCascadeCentRun3Data || doprocessTrackDataCentPP) == true && (doprocessFullMC || doprocessTrackMC || doprocessTrackMCTruth || doprocessTrackMCGen || doprocessTruthAndFullMCV0 || doprocessTrackD0MC || doprocessTruthAndFullMCCasc || doprocessFullMCCent || doprocessTrackCentRun3DataMC || doprocessTruthAndFullMCCentRun3 || doprocessTruthAndFullMCCentRun3V0) == true) { LOGF(fatal, "Cannot enable process Data and process MC at the same time. " "Please choose one."); } - colCuts.setCuts(ConfEvtZvtx, ConfEvtTriggerCheck, ConfEvtTriggerSel, ConfEvtOfflineCheck, ConfIsRun3, ConfCentFT0Min, ConfCentFT0Max); + colCuts.setCuts(confEvtZvtx, confEvtTriggerCheck, confEvtTriggerSel, confEvtOfflineCheck, confIsRun3, confCentFT0Min, confCentFT0Max); colCuts.init(&qaRegistry); - trackCuts.setSelection(ConfTrkCharge, femtoUniverseTrackSelection::kSign, femtoUniverseSelection::kEqual); - trackCuts.setSelection(ConfTrkPtmin, femtoUniverseTrackSelection::kpTMin, femtoUniverseSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkPtmax, femtoUniverseTrackSelection::kpTMax, femtoUniverseSelection::kUpperLimit); - trackCuts.setSelection(ConfTrkEta, femtoUniverseTrackSelection::kEtaMax, femtoUniverseSelection::kAbsUpperLimit); - trackCuts.setSelection(ConfTrkTPCnclsMin, femtoUniverseTrackSelection::kTPCnClsMin, femtoUniverseSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkTPCfCls, femtoUniverseTrackSelection::kTPCfClsMin, femtoUniverseSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkTPCcRowsMin, femtoUniverseTrackSelection::kTPCcRowsMin, femtoUniverseSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkTPCsCls, femtoUniverseTrackSelection::kTPCsClsMax, femtoUniverseSelection::kUpperLimit); - trackCuts.setSelection(ConfTrkITSnclsMin, femtoUniverseTrackSelection::kITSnClsMin, femtoUniverseSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkITSnclsIbMin, femtoUniverseTrackSelection::kITSnClsIbMin, femtoUniverseSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkDCAxyMax, femtoUniverseTrackSelection::kDCAxyMax, femtoUniverseSelection::kAbsUpperLimit); - trackCuts.setSelection(ConfTrkDCAzMax, femtoUniverseTrackSelection::kDCAzMax, femtoUniverseSelection::kAbsUpperLimit); - trackCuts.setSelection(ConfTrkPIDnSigmaMax, femtoUniverseTrackSelection::kPIDnSigmaMax, femtoUniverseSelection::kAbsUpperLimit); - trackCuts.setPIDSpecies(ConfTrkPIDspecies); - trackCuts.setnSigmaPIDOffset(ConfTrkPIDnSigmaOffsetTPC, ConfTrkPIDnSigmaOffsetTOF); - trackCuts.init(&qaRegistry); + trackCuts.setSelection(ConfTrkSelection.confTrkCharge, femto_universe_track_selection::kSign, femto_universe_selection::kEqual); + trackCuts.setSelection(ConfTrkSelection.confTrkPtmin, femto_universe_track_selection::kpTMin, femto_universe_selection::kLowerLimit); + trackCuts.setSelection(ConfTrkSelection.confTrkPtmax, femto_universe_track_selection::kpTMax, femto_universe_selection::kUpperLimit); + trackCuts.setSelection(ConfTrkSelection.confTrkEta, femto_universe_track_selection::kEtaMax, femto_universe_selection::kAbsUpperLimit); + trackCuts.setSelection(ConfTrkSelection.confTrkTPCnclsMin, femto_universe_track_selection::kTPCnClsMin, femto_universe_selection::kLowerLimit); + trackCuts.setSelection(ConfTrkSelection.confTrkTPCfCls, femto_universe_track_selection::kTPCfClsMin, femto_universe_selection::kLowerLimit); + trackCuts.setSelection(ConfTrkSelection.confTrkTPCcRowsMin, femto_universe_track_selection::kTPCcRowsMin, femto_universe_selection::kLowerLimit); + trackCuts.setSelection(ConfTrkSelection.confTrkTPCsCls, femto_universe_track_selection::kTPCsClsMax, femto_universe_selection::kUpperLimit); + trackCuts.setSelection(ConfTrkSelection.confTrkTPCfracsCls, femto_universe_track_selection::kTPCfracsClsMax, femto_universe_selection::kUpperLimit); + trackCuts.setSelection(ConfTrkSelection.confTrkITSnclsMin, femto_universe_track_selection::kITSnClsMin, femto_universe_selection::kLowerLimit); + trackCuts.setSelection(ConfTrkSelection.confTrkITSnclsIbMin, femto_universe_track_selection::kITSnClsIbMin, femto_universe_selection::kLowerLimit); + trackCuts.setSelection(ConfTrkSelection.confTrkDCAxyMax, femto_universe_track_selection::kDCAxyMax, femto_universe_selection::kAbsUpperLimit); + trackCuts.setSelection(ConfTrkSelection.confTrkDCAzMax, femto_universe_track_selection::kDCAzMax, femto_universe_selection::kAbsUpperLimit); + trackCuts.setSelection(ConfTrkSelection.confTrkPIDnSigmaMax, femto_universe_track_selection::kPIDnSigmaMax, femto_universe_selection::kAbsUpperLimit); + trackCuts.setPIDSpecies(ConfTrkSelection.confTrkPIDspecies); + trackCuts.setnSigmaPIDOffset(confTrkPIDnSigmaOffsetTPC, confTrkPIDnSigmaOffsetTOF); + trackCuts.init(&qaRegistry); /// \todo fix how to pass array to setSelection, getRow() passing a /// different type! // v0Cuts.setSelection(ConfV0Selection->getRow(0), - // femtoUniverseV0Selection::kDecVtxMax, femtoUniverseSelection::kAbsUpperLimit); - if (ConfIsActivateV0) { + // femto_universe_v0_selection::kDecVtxMax, femto_universe_selection::kAbsUpperLimit); + if (confIsActivateV0) { // initializing for V0 - v0Cuts.setSelection(ConfV0Sign, femtoUniverseV0Selection::kV0Sign, femtoUniverseSelection::kEqual); - v0Cuts.setSelection(ConfV0PtMin, femtoUniverseV0Selection::kV0pTMin, femtoUniverseSelection::kLowerLimit); - v0Cuts.setSelection(ConfV0PtMax, femtoUniverseV0Selection::kV0pTMax, femtoUniverseSelection::kUpperLimit); - v0Cuts.setSelection(ConfV0EtaMax, femtoUniverseV0Selection::kV0etaMax, femtoUniverseSelection::kAbsUpperLimit); - v0Cuts.setSelection(ConfV0DCADaughMax, femtoUniverseV0Selection::kV0DCADaughMax, femtoUniverseSelection::kUpperLimit); - v0Cuts.setSelection(ConfV0CPAMin, femtoUniverseV0Selection::kV0CPAMin, femtoUniverseSelection::kLowerLimit); - v0Cuts.setSelection(ConfV0TranRadMin, femtoUniverseV0Selection::kV0TranRadMin, femtoUniverseSelection::kLowerLimit); - v0Cuts.setSelection(ConfV0TranRadMax, femtoUniverseV0Selection::kV0TranRadMax, femtoUniverseSelection::kUpperLimit); - v0Cuts.setSelection(ConfV0DecVtxMax, femtoUniverseV0Selection::kV0DecVtxMax, femtoUniverseSelection::kUpperLimit); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kPosTrack, ConfChildCharge, femtoUniverseTrackSelection::kSign, femtoUniverseSelection::kEqual); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kPosTrack, ConfChildEtaMax, femtoUniverseTrackSelection::kEtaMax, femtoUniverseSelection::kAbsUpperLimit); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kPosTrack, ConfChildTPCnClsMin, femtoUniverseTrackSelection::kTPCnClsMin, femtoUniverseSelection::kLowerLimit); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kPosTrack, ConfChildDCAMin, femtoUniverseTrackSelection::kDCAMin, femtoUniverseSelection::kAbsLowerLimit); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kPosTrack, ConfChildPIDnSigmaMax, femtoUniverseTrackSelection::kPIDnSigmaMax, femtoUniverseSelection::kAbsUpperLimit); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kNegTrack, ConfChildCharge, femtoUniverseTrackSelection::kSign, femtoUniverseSelection::kEqual); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kNegTrack, ConfChildEtaMax, femtoUniverseTrackSelection::kEtaMax, femtoUniverseSelection::kAbsUpperLimit); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kNegTrack, ConfChildTPCnClsMin, femtoUniverseTrackSelection::kTPCnClsMin, femtoUniverseSelection::kLowerLimit); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kNegTrack, ConfChildDCAMin, femtoUniverseTrackSelection::kDCAMin, femtoUniverseSelection::kAbsLowerLimit); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kNegTrack, ConfChildPIDnSigmaMax, femtoUniverseTrackSelection::kPIDnSigmaMax, femtoUniverseSelection::kAbsUpperLimit); - v0Cuts.setChildPIDSpecies(femtoUniverseV0Selection::kPosTrack, ConfChildPIDspecies); - v0Cuts.setChildPIDSpecies(femtoUniverseV0Selection::kNegTrack, ConfChildPIDspecies); - v0Cuts.init(&qaRegistry); - v0Cuts.setInvMassLimits(ConfV0InvMassLowLimit, ConfV0InvMassUpLimit); - - v0Cuts.setChildRejectNotPropagatedTracks(femtoUniverseV0Selection::kPosTrack, ConfTrkRejectNotPropagated); - v0Cuts.setChildRejectNotPropagatedTracks(femtoUniverseV0Selection::kNegTrack, ConfTrkRejectNotPropagated); - - v0Cuts.setnSigmaPIDOffsetTPC(ConfTrkPIDnSigmaOffsetTPC); - v0Cuts.setChildnSigmaPIDOffset(femtoUniverseV0Selection::kPosTrack, ConfTrkPIDnSigmaOffsetTPC, ConfTrkPIDnSigmaOffsetTOF); - v0Cuts.setChildnSigmaPIDOffset(femtoUniverseV0Selection::kNegTrack, ConfTrkPIDnSigmaOffsetTPC, ConfTrkPIDnSigmaOffsetTOF); - - if (ConfV0RejectKaons) { - v0Cuts.setKaonInvMassLimits(ConfV0InvKaonMassLowLimit, ConfV0InvKaonMassUpLimit); + v0Cuts.setSelection(ConfV0Selection.confV0Sign, femto_universe_v0_selection::kV0Sign, femto_universe_selection::kEqual); + v0Cuts.setSelection(ConfV0Selection.confV0PtMin, femto_universe_v0_selection::kV0pTMin, femto_universe_selection::kLowerLimit); + v0Cuts.setSelection(ConfV0Selection.confV0PtMax, femto_universe_v0_selection::kV0pTMax, femto_universe_selection::kUpperLimit); + v0Cuts.setSelection(ConfV0Selection.confV0EtaMax, femto_universe_v0_selection::kV0etaMax, femto_universe_selection::kAbsUpperLimit); + v0Cuts.setSelection(ConfV0Selection.confV0DCADaughMax, femto_universe_v0_selection::kV0DCADaughMax, femto_universe_selection::kUpperLimit); + v0Cuts.setSelection(ConfV0Selection.confV0CPAMin, femto_universe_v0_selection::kV0CPAMin, femto_universe_selection::kLowerLimit); + v0Cuts.setSelection(ConfV0Selection.confV0TranRadMin, femto_universe_v0_selection::kV0TranRadMin, femto_universe_selection::kLowerLimit); + v0Cuts.setSelection(ConfV0Selection.confV0TranRadMax, femto_universe_v0_selection::kV0TranRadMax, femto_universe_selection::kUpperLimit); + v0Cuts.setSelection(ConfV0Selection.confV0DecVtxMax, femto_universe_v0_selection::kV0DecVtxMax, femto_universe_selection::kUpperLimit); + v0Cuts.setChildCuts(femto_universe_v0_selection::kPosTrack, ConfV0Selection.confChildCharge, femto_universe_track_selection::kSign, femto_universe_selection::kEqual); + v0Cuts.setChildCuts(femto_universe_v0_selection::kPosTrack, ConfV0Selection.confChildEtaMax, femto_universe_track_selection::kEtaMax, femto_universe_selection::kAbsUpperLimit); + v0Cuts.setChildCuts(femto_universe_v0_selection::kPosTrack, ConfV0Selection.confChildTPCnClsMin, femto_universe_track_selection::kTPCnClsMin, femto_universe_selection::kLowerLimit); + v0Cuts.setChildCuts(femto_universe_v0_selection::kPosTrack, ConfV0Selection.confChildDCAMin, femto_universe_track_selection::kDCAMin, femto_universe_selection::kAbsLowerLimit); + v0Cuts.setChildCuts(femto_universe_v0_selection::kPosTrack, ConfV0Selection.confChildPIDnSigmaMax, femto_universe_track_selection::kPIDnSigmaMax, femto_universe_selection::kAbsUpperLimit); + v0Cuts.setChildCuts(femto_universe_v0_selection::kNegTrack, ConfV0Selection.confChildCharge, femto_universe_track_selection::kSign, femto_universe_selection::kEqual); + v0Cuts.setChildCuts(femto_universe_v0_selection::kNegTrack, ConfV0Selection.confChildEtaMax, femto_universe_track_selection::kEtaMax, femto_universe_selection::kAbsUpperLimit); + v0Cuts.setChildCuts(femto_universe_v0_selection::kNegTrack, ConfV0Selection.confChildTPCnClsMin, femto_universe_track_selection::kTPCnClsMin, femto_universe_selection::kLowerLimit); + v0Cuts.setChildCuts(femto_universe_v0_selection::kNegTrack, ConfV0Selection.confChildDCAMin, femto_universe_track_selection::kDCAMin, femto_universe_selection::kAbsLowerLimit); + v0Cuts.setChildCuts(femto_universe_v0_selection::kNegTrack, ConfV0Selection.confChildPIDnSigmaMax, femto_universe_track_selection::kPIDnSigmaMax, femto_universe_selection::kAbsUpperLimit); + v0Cuts.setChildPIDSpecies(femto_universe_v0_selection::kPosTrack, ConfV0Selection.confChildPIDspecies); + v0Cuts.setChildPIDSpecies(femto_universe_v0_selection::kNegTrack, ConfV0Selection.confChildPIDspecies); + v0Cuts.init(&qaRegistry); + v0Cuts.setInvMassLimits(ConfV0Selection.confV0InvMassLowLimit, ConfV0Selection.confV0InvMassUpLimit); + + v0Cuts.setChildRejectNotPropagatedTracks(femto_universe_v0_selection::kPosTrack, confTrkRejectNotPropagated); + v0Cuts.setChildRejectNotPropagatedTracks(femto_universe_v0_selection::kNegTrack, confTrkRejectNotPropagated); + + v0Cuts.setnSigmaPIDOffsetTPC(confTrkPIDnSigmaOffsetTPC); + v0Cuts.setChildnSigmaPIDOffset(femto_universe_v0_selection::kPosTrack, confTrkPIDnSigmaOffsetTPC, confTrkPIDnSigmaOffsetTOF); + v0Cuts.setChildnSigmaPIDOffset(femto_universe_v0_selection::kNegTrack, confTrkPIDnSigmaOffsetTPC, confTrkPIDnSigmaOffsetTOF); + + if (ConfV0Selection.confV0RejectKaons) { + v0Cuts.setKaonInvMassLimits(ConfV0Selection.confV0InvKaonMassLowLimit, ConfV0Selection.confV0InvKaonMassUpLimit); } // if (ConfRejectITSHitandTOFMissing) { // o2PhysicsTrackSelection = new @@ -391,9 +500,62 @@ struct femtoUniverseProducerTask { // } } - if (ConfIsActivatePhi) { + if (confIsActivateCascade) { + // initializing for cascades + cascadeCuts.setSelection(ConfCascadeSelection.confCascSign, femto_universe_cascade_selection::kCascadeSign, femto_universe_selection::kEqual); + cascadeCuts.setSelection(ConfCascadeSelection.confCascPtMin, femto_universe_cascade_selection::kCascadepTMin, femto_universe_selection::kLowerLimit); + cascadeCuts.setSelection(ConfCascadeSelection.confCascPtMax, femto_universe_cascade_selection::kCascadepTMax, femto_universe_selection::kUpperLimit); + cascadeCuts.setSelection(ConfCascadeSelection.confCascEtaMax, femto_universe_cascade_selection::kCascadeetaMax, femto_universe_selection::kAbsUpperLimit); + // v0 child cuts + cascadeCuts.setSelection(ConfCascadeSelection.confCascV0DCADaughMax, femto_universe_cascade_selection::kCascadeV0DCADaughMax, femto_universe_selection::kUpperLimit); + cascadeCuts.setSelection(ConfCascadeSelection.confCascV0CPAMin, femto_universe_cascade_selection::kCascadeV0CPAMin, femto_universe_selection::kLowerLimit); + cascadeCuts.setSelection(ConfCascadeSelection.confCascV0TranRadMin, femto_universe_cascade_selection::kCascadeV0TranRadMin, femto_universe_selection::kLowerLimit); + cascadeCuts.setSelection(ConfCascadeSelection.confCascV0TranRadMax, femto_universe_cascade_selection::kCascadeV0TranRadMax, femto_universe_selection::kUpperLimit); + cascadeCuts.setSelection(ConfCascadeSelection.confCascV0DecVtxMax, femto_universe_cascade_selection::kCascadeV0DecVtxMax, femto_universe_selection::kUpperLimit); + // cascade cuts + cascadeCuts.setSelection(ConfCascadeSelection.confCascDCADaughMax, femto_universe_cascade_selection::kCascadeDCADaughMax, femto_universe_selection::kUpperLimit); + cascadeCuts.setSelection(ConfCascadeSelection.confCascCPAMin, femto_universe_cascade_selection::kCascadeCPAMin, femto_universe_selection::kLowerLimit); + cascadeCuts.setSelection(ConfCascadeSelection.confCascTranRadMin, femto_universe_cascade_selection::kCascadeTranRadMin, femto_universe_selection::kLowerLimit); + cascadeCuts.setSelection(ConfCascadeSelection.confCascTranRadMax, femto_universe_cascade_selection::kCascadeTranRadMax, femto_universe_selection::kUpperLimit); + cascadeCuts.setSelection(ConfCascadeSelection.confCascDecVtxMax, femto_universe_cascade_selection::kCascadeDecVtxMax, femto_universe_selection::kUpperLimit); + cascadeCuts.setSelection(ConfCascadeSelection.confCascDCAPosToPV, femto_universe_cascade_selection::kCascadeDCAPosToPV, femto_universe_selection::kLowerLimit); + cascadeCuts.setSelection(ConfCascadeSelection.confCascDCANegToPV, femto_universe_cascade_selection::kCascadeDCANegToPV, femto_universe_selection::kLowerLimit); + cascadeCuts.setSelection(ConfCascadeSelection.confCascDCABachToPV, femto_universe_cascade_selection::kCascadeDCABachToPV, femto_universe_selection::kLowerLimit); + cascadeCuts.setSelection(ConfCascadeSelection.confCascDCAV0ToPV, femto_universe_cascade_selection::kCascadeDCAV0ToPV, femto_universe_selection::kLowerLimit); + cascadeCuts.setSelection(ConfCascadeSelection.confCascV0MassLowLimit, femto_universe_cascade_selection::kCascadeV0MassMin, femto_universe_selection::kLowerLimit); + cascadeCuts.setSelection(ConfCascadeSelection.confCascV0MassUpLimit, femto_universe_cascade_selection::kCascadeV0MassMax, femto_universe_selection::kUpperLimit); + // children cuts + cascadeCuts.setChildCuts(femto_universe_cascade_selection::kPosTrack, ConfCascadeSelection.confCascChildCharge, femto_universe_track_selection::kSign, femto_universe_selection::kEqual); + cascadeCuts.setChildCuts(femto_universe_cascade_selection::kPosTrack, ConfCascadeSelection.confCascChildEtaMax, femto_universe_track_selection::kEtaMax, femto_universe_selection::kAbsUpperLimit); + cascadeCuts.setChildCuts(femto_universe_cascade_selection::kPosTrack, ConfCascadeSelection.confCascChildTPCnClsMin, femto_universe_track_selection::kTPCnClsMin, femto_universe_selection::kLowerLimit); + cascadeCuts.setChildCuts(femto_universe_cascade_selection::kPosTrack, ConfCascadeSelection.confCascChildPIDnSigmaMax, femto_universe_track_selection::kPIDnSigmaMax, femto_universe_selection::kAbsUpperLimit); + cascadeCuts.setChildCuts(femto_universe_cascade_selection::kNegTrack, ConfCascadeSelection.confCascChildCharge, femto_universe_track_selection::kSign, femto_universe_selection::kEqual); + cascadeCuts.setChildCuts(femto_universe_cascade_selection::kNegTrack, ConfCascadeSelection.confCascChildEtaMax, femto_universe_track_selection::kEtaMax, femto_universe_selection::kAbsUpperLimit); + cascadeCuts.setChildCuts(femto_universe_cascade_selection::kNegTrack, ConfCascadeSelection.confCascChildTPCnClsMin, femto_universe_track_selection::kTPCnClsMin, femto_universe_selection::kLowerLimit); + cascadeCuts.setChildCuts(femto_universe_cascade_selection::kNegTrack, ConfCascadeSelection.confCascChildPIDnSigmaMax, femto_universe_track_selection::kPIDnSigmaMax, femto_universe_selection::kAbsUpperLimit); + cascadeCuts.setChildCuts(femto_universe_cascade_selection::kBachTrack, ConfCascadeSelection.confCascChildCharge, femto_universe_track_selection::kSign, femto_universe_selection::kEqual); + cascadeCuts.setChildCuts(femto_universe_cascade_selection::kBachTrack, ConfCascadeSelection.confCascChildEtaMax, femto_universe_track_selection::kEtaMax, femto_universe_selection::kAbsUpperLimit); + cascadeCuts.setChildCuts(femto_universe_cascade_selection::kBachTrack, ConfCascadeSelection.confCascChildTPCnClsMin, femto_universe_track_selection::kTPCnClsMin, femto_universe_selection::kLowerLimit); + cascadeCuts.setChildCuts(femto_universe_cascade_selection::kBachTrack, ConfCascadeSelection.confCascChildPIDnSigmaMax, femto_universe_track_selection::kPIDnSigmaMax, femto_universe_selection::kAbsUpperLimit); + + // TODO + cascadeCuts.setChildPIDSpecies(femto_universe_cascade_selection::kPosTrack, ConfV0Selection.confChildPIDspecies); + cascadeCuts.setChildPIDSpecies(femto_universe_cascade_selection::kNegTrack, ConfV0Selection.confChildPIDspecies); + cascadeCuts.setChildPIDSpecies(femto_universe_cascade_selection::kBachTrack, ConfCascadeSelection.confCascChildPIDspecies); + + // check if works correctly for bachelor track + cascadeCuts.init(&cascadeQaRegistry, confIsSelectCascOmega); + // invmass cuts + cascadeCuts.setInvMassLimits(ConfCascadeSelection.confCascInvMassLowLimit, ConfCascadeSelection.confCascInvMassUpLimit); + + if (ConfCascadeSelection.confCascRejectCompetingMass) { + cascadeCuts.setCompetingInvMassLimits(ConfCascadeSelection.confCascInvCompetingMassLowLimit, ConfCascadeSelection.confCascInvCompetingMassUpLimit); + } + } + + if (confIsActivatePhi) { // initializing for Phi meson - phiCuts.init(&qaRegistry); + phiCuts.init(&qaRegistry); } mRunNumber = 0; @@ -417,7 +579,7 @@ struct femtoUniverseProducerTask { auto timestamp = bc.timestamp(); float output = -999; - if (ConfIsRun3 && !ConfIsForceGRP) { + if (confIsRun3 && !confIsForceGRP) { static o2::parameters::GRPMagField* grpo = nullptr; grpo = ccdb->getForTimeStamp("GLO/Config/GRPMagField", timestamp); if (grpo == nullptr) { @@ -425,12 +587,11 @@ struct femtoUniverseProducerTask { return; } LOGF(info, "Retrieved GRP for timestamp %llu with L3 ", timestamp, grpo->getL3Current()); - // taken from GRP onject definition of getNominalL3Field; update later to something smarter (mNominalL3Field = std::lround(5.f * mL3Current / 30000.f);) - auto NominalL3Field = std::lround(5.f * grpo->getL3Current() / 30000.f); - output = 0.1 * (NominalL3Field); + // taken from GRP onject definition of getnominalL3Field; update later to something smarter (mnominalL3Field = std::lround(5.f * mL3Current / 30000.f);) + auto nominalL3Field = std::lround(5.f * grpo->getL3Current() / 30000.f); + output = 0.1 * (nominalL3Field); } else { - static o2::parameters::GRPObject* grpo = nullptr; grpo = ccdb->getForTimeStamp("GLO/GRP/GRP", timestamp); if (grpo == nullptr) { @@ -444,14 +605,14 @@ struct femtoUniverseProducerTask { mRunNumber = bc.runNumber(); } - template + template void fillDebugParticle(ParticleType const& particle) { if constexpr (isTrackOrV0) { outputDebugParts(particle.sign(), (uint8_t)particle.tpcNClsFound(), particle.tpcNClsFindable(), (uint8_t)particle.tpcNClsCrossedRows(), - particle.tpcNClsShared(), particle.tpcInnerParam(), + particle.tpcNClsShared(), particle.tpcFractionSharedCls(), particle.tpcInnerParam(), particle.itsNCls(), particle.itsNClsInnerBarrel(), particle.dcaXY(), particle.dcaZ(), particle.tpcSignal(), particle.tpcNSigmaStoreEl(), particle.tpcNSigmaStorePi(), @@ -461,16 +622,23 @@ struct femtoUniverseProducerTask { particle.tofNSigmaStorePr(), particle.tofNSigmaStoreDe(), -999., -999., -999., -999., -999., -999.); } else if constexpr (isPhiOrD0) { - outputDebugParts(-999., -999., -999., -999., -999., -999., -999., -999., + outputDebugParts(-999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., - -999.); // QA for phi or D0/D0bar + -999.); // QA for phi or D0/D0bar children + } else if constexpr (isXi) { + outputDebugParts(-999., -999., -999., -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., + particle.dcacascdaughters(), particle.cascradius(), + particle.x(), particle.y(), particle.z(), + particle.mOmega()); // QA for Xi Cascades (later do the same for Omegas) } else { // LOGF(info, "isTrack0orV0: %d, isPhi: %d", isTrackOrV0, isPhiOrD0); - outputDebugParts(-999., -999., -999., -999., -999., -999., -999., -999., - -999., -999., -999., -999., -999., -999., -999., -999., + outputDebugParts(-999., -999., -999., -999., -999., -999., -999., -999., -999., + particle.dcav0topv(), -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., particle.dcaV0daughters(), particle.v0radius(), particle.x(), particle.y(), particle.z(), @@ -478,6 +646,53 @@ struct femtoUniverseProducerTask { } } + template + void fillDebugD0D0barML(ParticleType const& particle) + { + if constexpr (isD0ML) { + outputDebugParts(-999., -999., -999., -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., + -999., -999., + particle.mlProbD0()[0], // getter decayVtxX + particle.mlProbD0()[1], // getter decayVtxY + particle.mlProbD0()[2], // getter decayVtxZ + -999.); // Additional info for D0/D0bar + } else if constexpr (isD0barML) { + outputDebugParts(-999., -999., -999., -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., + -999., -999., + particle.mlProbD0bar()[0], // getter decayVtxX + particle.mlProbD0bar()[1], // getter decayVtxY + particle.mlProbD0bar()[2], // getter decayVtxZ + -999.); // Additional info for D0/D0bar + } else { + outputDebugParts(-999., -999., -999., -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., -999.); + } + } + + template + int32_t getMotherPDG(ParticleType particle) + { + auto motherparticlesMC = particle.template mothers_as(); + if (!motherparticlesMC.empty()) { + auto motherparticleMC = motherparticlesMC.front(); + return particle.isPhysicalPrimary() ? 0 : motherparticleMC.pdgCode(); + } else { + return 9999; + } + } + + template + void fillDebugParticleMC(ParticleType const& particle) + { + outputDebugPartsMC(getMotherPDG(particle)); + } + template void fillMCParticle(ParticleType const& particle, o2::aod::femtouniverseparticle::ParticleType fdparttype) { @@ -486,33 +701,131 @@ struct femtoUniverseProducerTask { auto particleMC = particle.mcParticle(); auto pdgCode = particleMC.pdgCode(); int particleOrigin = 99; - auto motherparticleMC = particleMC.template mothers_as().front(); + auto motherparticlesMC = particleMC.template mothers_as(); - if (abs(pdgCode) == abs(ConfTrkPDGCode.value)) { + if (std::abs(pdgCode) == std::abs(confPDGCodePartOne.value) || std::abs(pdgCode) == std::abs(confPDGCodePartTwo.value)) { if (particleMC.isPhysicalPrimary()) { - particleOrigin = aod::femtouniverseMCparticle::ParticleOriginMCTruth::kPrimary; - } else if (motherparticleMC.producedByGenerator()) { - particleOrigin = checkDaughterType(fdparttype, motherparticleMC.pdgCode()); + particleOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary; + } else if (!motherparticlesMC.empty()) { + auto motherparticleMC = motherparticlesMC.front(); + if (motherparticleMC.producedByGenerator()) + particleOrigin = checkDaughterType(fdparttype, motherparticleMC.pdgCode()); } else { - particleOrigin = aod::femtouniverseMCparticle::ParticleOriginMCTruth::kMaterial; + particleOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kMaterial; } } else { - particleOrigin = aod::femtouniverseMCparticle::ParticleOriginMCTruth::kFake; + particleOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kFake; } outputPartsMC(particleOrigin, pdgCode, particleMC.pt(), particleMC.eta(), particleMC.phi()); + fillDebugParticleMC(particleMC); + outputPartsMCLabels(outputPartsMC.lastIndex()); + } else { + outputPartsMCLabels(-1); + outputDebugPartsMC(9999); + } + } + + template + void fillMCParticlePhi(ParticleType const& kaon1, ParticleType const& kaon2) + { + if (kaon1.has_mcParticle() && kaon2.has_mcParticle()) { + // get corresponding MC particle and its info + auto kaon1MC = kaon1.mcParticle(); + auto kaon2MC = kaon2.mcParticle(); + auto pdgCode1 = kaon1MC.pdgCode(); + auto pdgCode2 = kaon2MC.pdgCode(); + + int phiOrigin = 99; + auto motherskaon1MC = kaon1MC.template mothers_as(); + auto motherskaon2MC = kaon2MC.template mothers_as(); + + if (std::abs(pdgCode1) == std::abs(321) || std::abs(pdgCode2) == std::abs(-321)) { + if ((kaon1MC.isPhysicalPrimary() && kaon2MC.isPhysicalPrimary()) && (!motherskaon1MC.empty() && !motherskaon2MC.empty())) { + for (const auto& particleMotherOfNeg : motherskaon1MC) { + for (const auto& particleMotherOfPos : motherskaon2MC) { + if (particleMotherOfNeg == particleMotherOfPos && particleMotherOfNeg.pdgCode() == 333) { + phiOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary; + } else { + phiOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kFake; + } + } + } + } else { + phiOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kFake; + } + } else { + phiOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kFake; + } + + TLorentzVector part1Vec; + TLorentzVector part2Vec; + + const auto mMassOne = o2::constants::physics::MassKPlus; // FIXME: Get from the PDG service of the common header + const auto mMassTwo = o2::constants::physics::MassKMinus; // FIXME: Get from the PDG service of the common header + + part1Vec.SetPtEtaPhiM(kaon1MC.pt(), kaon1MC.eta(), kaon1MC.phi(), mMassOne); + part2Vec.SetPtEtaPhiM(kaon2MC.pt(), kaon2MC.eta(), kaon2MC.phi(), mMassTwo); + + TLorentzVector sumVec(part1Vec); + sumVec += part2Vec; + + float phiEta = sumVec.Eta(); + float phiPt = sumVec.Pt(); + float phiPhi = sumVec.Phi(); + + outputPartsMC(phiOrigin, 333, phiPt, phiEta, phiPhi); + outputPartsMCLabels(outputPartsMC.lastIndex()); + } else { + outputPartsMCLabels(-1); + } + } + + template + void fillMCParticleD0(ParticleType const& hfCand) + { + if (std::abs(hfCand.flagMcMatchRec()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { + // get corresponding MC particle and its info + int pdgCode = 0; + int hfCandOrigin = 99; + + if (hfCand.originMcRec() == RecoDecay::OriginType::Prompt) { + if (hfCand.isSelD0() == 1 && hfCand.isSelD0bar() == 0) { + hfCandOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrompt; + pdgCode = static_cast(Pdg::kD0); + } else if (hfCand.isSelD0() == 0 && hfCand.isSelD0bar() == 1) { + hfCandOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrompt; + pdgCode = static_cast(Pdg::kD0Bar); + } else { + hfCandOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kFake; + pdgCode = 0; + } + } else { + if (hfCand.isSelD0() == 1 && hfCand.isSelD0bar() == 0) { + hfCandOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kNonPrompt; + pdgCode = static_cast(Pdg::kD0); + } else if (hfCand.isSelD0() == 0 && hfCand.isSelD0bar() == 1) { + hfCandOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kNonPrompt; + pdgCode = static_cast(Pdg::kD0Bar); + } else { + hfCandOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kFake; + pdgCode = 0; + } + } + outputPartsMC(hfCandOrigin, pdgCode, hfCand.pt(), hfHelper.yD0(hfCand), hfCand.phi()); outputPartsMCLabels(outputPartsMC.lastIndex()); } else { outputPartsMCLabels(-1); } } + template - void fillCollisions(CollisionType const& col, TrackType const& tracks) + bool fillCollisions(CollisionType const& col, TrackType const& tracks) { const auto vtxZ = col.posZ(); - int mult = 0; + float mult = 0; int multNtr = 0; - if (ConfIsRun3) { + if (confIsRun3) { mult = col.multFV0M(); multNtr = col.multNTracksPV(); } else { @@ -520,7 +833,7 @@ struct femtoUniverseProducerTask { /// FemtoUniverseRun2 is defined V0M/2 multNtr = col.multTracklets(); } - if (ConfEvtUseTPCmult) { + if (confEvtUseTPCmult) { multNtr = col.multTPC(); } @@ -530,48 +843,86 @@ struct femtoUniverseProducerTask { // in case of trigger run - store such collisions but don't store any // particle candidates for such collisions if (!colCuts.isSelected(col)) { - if (ConfIsTrigger) { - if (ConfDoSpher) { - outputCollision(vtxZ, mult, multNtr, colCuts.computeSphericity(col, tracks), mMagField); - } else { - outputCollision(vtxZ, mult, multNtr, 2, mMagField); - } - } - return; + return false; + } + if (!confIsUsePileUp) { + outputCollision(vtxZ, mult, multNtr, confDoSpher ? colCuts.computeSphericity(col, tracks) : 2, mMagField); + colCuts.fillQA(col); + return true; + } else if ((!confEvNoSameBunchPileup || col.selection_bit(aod::evsel::kNoSameBunchPileup)) && (!confEvIsGoodZvtxFT0vsPV || col.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) && (!confEvIsVertexITSTPC || col.selection_bit(aod::evsel::kIsVertexITSTPC))) { + outputCollision(vtxZ, mult, multNtr, confDoSpher ? colCuts.computeSphericity(col, tracks) : 2, mMagField); + colCuts.fillQA(col); + return true; + } else { + return false; + } + } + + template + bool fillCollisionsCentPP(CollisionType const& col, TrackType const& tracks) + { + const auto vtxZ = col.posZ(); + float mult = 0; + int multNtr = 0; + if (confIsRun3) { + mult = col.centFT0M(); + multNtr = col.multNTracksPV(); + } else { + mult = 0.5 * (col.multFV0M()); /// For benchmarking on Run 2, V0M in + /// FemtoUniverseRun2 is defined V0M/2 + multNtr = col.multTracklets(); + } + if (confEvtUseTPCmult) { + multNtr = col.multTPC(); } - colCuts.fillQA(col); - if (ConfDoSpher) { - outputCollision(vtxZ, mult, multNtr, colCuts.computeSphericity(col, tracks), mMagField); + // check whether the basic event selection criteria are fulfilled + // if the basic selection is NOT fulfilled: + // in case of skimming run - don't store such collisions + // in case of trigger run - store such collisions but don't store any + // particle candidates for such collisions + if (!colCuts.isSelected(col)) { + return false; + } + if (!confIsUsePileUp) { + outputCollision(vtxZ, mult, multNtr, confDoSpher ? colCuts.computeSphericity(col, tracks) : 2, mMagField); + colCuts.fillQA(col); + return true; + } else if ((!confEvNoSameBunchPileup || col.selection_bit(aod::evsel::kNoSameBunchPileup)) && (!confEvIsGoodZvtxFT0vsPV || col.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) && (!confEvIsVertexITSTPC || col.selection_bit(aod::evsel::kIsVertexITSTPC))) { + outputCollision(vtxZ, mult, multNtr, confDoSpher ? colCuts.computeSphericity(col, tracks) : 2, mMagField); + colCuts.fillQA(col); + return true; } else { - outputCollision(vtxZ, mult, multNtr, 2, mMagField); + return false; } } template - void fillMCTruthCollisions(CollisionType const& col, TrackType const&) + void fillMCTruthCollisions(CollisionType const& col, TrackType const& tracks) { - for (auto& c : col) { + for (const auto& c : col) { const auto vtxZ = c.posZ(); - const auto spher = 0; // colCuts.computeSphericity(col, tracks); - int mult = 0; + float mult = 0; int multNtr = 0; - // colCuts.fillQA(c); //for now, TODO: create a configurable so in the FemroUniverseCollisionSelection.h there is an option to plot QA just for the posZ - outputCollision(vtxZ, mult, multNtr, spher, mMagField); + if (std::abs(vtxZ) > confEvtZvtx) { + continue; + } + + if (confDoSpher) { + outputCollision(vtxZ, mult, multNtr, colCuts.computeSphericity(col, tracks), mMagField); + } else { + outputCollision(vtxZ, mult, multNtr, 2, mMagField); + } } } - template - void fillCollisionsCentRun2(CollisionType const& col, TrackType const& tracks) + template + bool fillCollisionsCentRun2(CollisionType const& col) { const auto vtxZ = col.posZ(); - int cent = 0; - int multNtr = 0; - if (!ConfIsRun3) { - cent = col.centRun2V0M(); - multNtr = col.centRun2V0M(); - } + const auto cent = col.centRun2V0M(); + const auto multNtr = col.multNTracksPV(); // check whether the basic event selection criteria are fulfilled // if the basic selection is NOT fulfilled: @@ -579,75 +930,78 @@ struct femtoUniverseProducerTask { // in case of trigger run - store such collisions but don't store any // particle candidates for such collisions if (!colCuts.isSelected(col)) { - if (ConfIsTrigger) { - if (ConfDoSpher) { - outputCollision(vtxZ, cent, multNtr, colCuts.computeSphericity(col, tracks), mMagField); - } else { - outputCollision(vtxZ, cent, multNtr, 2, mMagField); - } - } - - return; - } - - // colCuts.fillQA(col); //for now, TODO: create a configurable so in the FemroUniverseCollisionSelection.h there is an option to plot QA just for the posZ - if (ConfDoSpher) { - outputCollision(vtxZ, cent, multNtr, colCuts.computeSphericity(col, tracks), mMagField); + return false; } else { outputCollision(vtxZ, cent, multNtr, 2, mMagField); + return true; } } - template - void fillCollisionsCentRun3(CollisionType const& col, TrackType const& tracks) + template + bool fillCollisionsCentRun3(CollisionType const& col) { const auto vtxZ = col.posZ(); - int cent = 0; - int multNtr = 0; - if (ConfIsRun3) { - multNtr = col.centFT0C(); - cent = col.centFT0C(); - } + const auto multNtr = col.multNTracksPV(); + const auto cent = col.centFT0C(); + const auto occupancy = col.trackOccupancyInTimeRange(); // check whether the basic event selection criteria are fulfilled // if the basic selection is NOT fulfilled: // in case of skimming run - don't store such collisions // in case of trigger run - store such collisions but don't store any // particle candidates for such collisions - if (!colCuts.isSelectedRun3(col)) { - if (ConfIsTrigger) { - if (ConfDoSpher) { - outputCollision(vtxZ, cent, multNtr, colCuts.computeSphericity(col, tracks), mMagField); - } else { - outputCollision(vtxZ, cent, multNtr, 2, mMagField); - } - } ////// - return; + if (!colCuts.isSelectedRun3(col) || (occupancy < confTPCOccupancyMin || occupancy > confTPCOccupancyMax)) { + return false; + } else { + if (col.selection_bit(aod::evsel::kNoSameBunchPileup) && + col.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && + col.selection_bit(aod::evsel::kIsGoodITSLayersAll) && + col.selection_bit(aod::evsel::kNoCollInRofStandard) && + col.selection_bit(aod::evsel::kNoHighMultCollInPrevRof) && + col.selection_bit(aod::evsel::kNoCollInTimeRangeStandard)) { + outputCollision(vtxZ, cent, multNtr, 2, mMagField); + return true; + } else { + return false; + } } + } + + template + bool fillMCTruthCollisionsCentRun3(CollisionType const& col) + { + const auto vtxZ = col.posZ(); - // colCuts.fillQA(col); //for now, TODO: create a configurable so in the FemroUniverseCollisionSelection.h there is an option to plot QA just for the posZ - if (ConfDoSpher) { - outputCollision(vtxZ, cent, multNtr, colCuts.computeSphericity(col, tracks), mMagField); + if (std::abs(vtxZ) > confEvtZvtx) { + return false; } else { - outputCollision(vtxZ, cent, multNtr, 2, mMagField); + outputCollision(vtxZ, 0, 0, 2, mMagField); + return true; } } + template + void fillCollisionsCentRun3ColExtra(CollisionType const& col, double irrate) + { + const auto occupancy = col.trackOccupancyInTimeRange(); + outputCollExtra(irrate, occupancy); + } + template void fillTracks(TrackType const& tracks) { std::vector childIDs = {0, 0}; // these IDs are necessary to keep track of the children std::vector tmpIDtrack; // this vector keeps track of the matching of the primary track table row <-> aod::track table global index - for (auto& track : tracks) { + for (const auto& track : tracks) { /// if the most open selection criteria are not fulfilled there is no /// point looking further at the track if (!trackCuts.isSelectedMinimal(track)) { continue; } - if (track.pt() > ConfTOFpTmin) { + if (track.pt() > confTOFpTmin) { if (!track.hasTOF()) { continue; } @@ -656,19 +1010,30 @@ struct femtoUniverseProducerTask { trackCuts.fillQA(track); // the bit-wise container of the systematic variations is obtained - auto cutContainer = trackCuts.getCutContainer(track); + auto cutContainer = trackCuts.getCutContainer(track); // now the table is filled - outputParts(outputCollision.lastIndex(), track.pt(), track.eta(), - track.phi(), aod::femtouniverseparticle::ParticleType::kTrack, - cutContainer.at( - femtoUniverseTrackSelection::TrackContainerPosition::kCuts), - cutContainer.at( - femtoUniverseTrackSelection::TrackContainerPosition::kPID), - track.dcaXY(), childIDs, 0, 0); + if (!confIsActivateCascade) { + outputParts(outputCollision.lastIndex(), track.pt(), track.eta(), + track.phi(), aod::femtouniverseparticle::ParticleType::kTrack, + cutContainer.at( + femto_universe_track_selection::TrackContainerPosition::kCuts), + cutContainer.at( + femto_universe_track_selection::TrackContainerPosition::kPID), + track.dcaXY(), childIDs, 0, + track.sign()); // sign getter is mAntiLambda() + } else { + outputCascParts(outputCollision.lastIndex(), track.pt(), track.eta(), + track.phi(), aod::femtouniverseparticle::ParticleType::kTrack, + cutContainer.at( + femto_universe_track_selection::TrackContainerPosition::kCuts), + cutContainer.at( + femto_universe_track_selection::TrackContainerPosition::kPID), + track.dcaXY(), childIDs, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + } tmpIDtrack.push_back(track.globalIndex()); - if (ConfIsDebug) { - fillDebugParticle(track); + if (confIsDebug) { + fillDebugParticle(track); } if constexpr (isMC) { @@ -682,7 +1047,7 @@ struct femtoUniverseProducerTask { { std::vector childIDs = {0, 0}; // these IDs are necessary to keep track of the children std::vector tmpIDtrack; // this vector keeps track of the matching of the primary track table row <-> aod::track table global index - for (auto& v0 : fullV0s) { + for (const auto& v0 : fullV0s) { auto postrack = v0.template posTrack_as(); auto negtrack = v0.template negTrack_as(); ///\tocheck funnily enough if we apply the filter the @@ -705,7 +1070,7 @@ struct femtoUniverseProducerTask { // } v0Cuts.fillQA(col, v0, postrack, negtrack); ///\todo fill QA also for daughters - auto cutContainerV0 = v0Cuts.getCutContainer(col, v0, postrack, negtrack); + auto cutContainerV0 = v0Cuts.getCutContainer(col, v0, postrack, negtrack); int postrackID = v0.posTrackId(); int rowInPrimaryTrackTablePos = -1; @@ -715,8 +1080,8 @@ struct femtoUniverseProducerTask { outputParts(outputCollision.lastIndex(), v0.positivept(), v0.positiveeta(), v0.positivephi(), aod::femtouniverseparticle::ParticleType::kV0Child, - cutContainerV0.at(femtoUniverseV0Selection::V0ContainerPosition::kPosCuts), - cutContainerV0.at(femtoUniverseV0Selection::V0ContainerPosition::kPosPID), + cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kPosCuts), + cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kPosPID), 0., childIDs, 0, @@ -735,8 +1100,8 @@ struct femtoUniverseProducerTask { v0.negativeeta(), v0.negativephi(), aod::femtouniverseparticle::ParticleType::kV0Child, - cutContainerV0.at(femtoUniverseV0Selection::V0ContainerPosition::kNegCuts), - cutContainerV0.at(femtoUniverseV0Selection::V0ContainerPosition::kNegPID), + cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kNegCuts), + cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kNegPID), 0., childIDs, 0, @@ -751,16 +1116,16 @@ struct femtoUniverseProducerTask { v0.eta(), v0.phi(), aod::femtouniverseparticle::ParticleType::kV0, - cutContainerV0.at(femtoUniverseV0Selection::V0ContainerPosition::kV0), + cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kV0), 0, v0.v0cosPA(), indexChildID, v0.mLambda(), v0.mAntiLambda()); - if (ConfIsDebug) { - fillDebugParticle(postrack); // QA for positive daughter - fillDebugParticle(negtrack); // QA for negative daughter - fillDebugParticle(v0); // QA for v0 + if (confIsDebug) { + fillDebugParticle(postrack); // QA for positive daughter + fillDebugParticle(negtrack); // QA for negative daughter + fillDebugParticle(v0); // QA for v0 } if constexpr (isMC) { fillMCParticle(v0, o2::aod::femtouniverseparticle::ParticleType::kV0); @@ -768,6 +1133,156 @@ struct femtoUniverseProducerTask { } } + template + void fillCascade(CollisionType const& col, CascadeType const& fullCascades, TrackType const&) + { + std::vector childIDs = {0, 0, 0}; // child1, child2, bachelor; these IDs are necessary to keep track of the children + std::vector tmpIDtrack; // this vector keeps track of the matching of the primary track table row <-> aod::track table global index + + for (const auto& casc : fullCascades) { + const auto& posTrackCasc = casc.template posTrack_as(); + const auto& negTrackCasc = casc.template negTrack_as(); + const auto& bachTrackCasc = casc.template bachelor_as(); + + if (!cascadeCuts.isSelectedMinimal(col, casc, posTrackCasc, negTrackCasc, bachTrackCasc)) { + continue; + } + + cascadeCuts.fillCascadeQA(col, casc, posTrackCasc, negTrackCasc); + cascadeCuts.fillQA(col, casc, posTrackCasc, negTrackCasc, bachTrackCasc); // fill QA for daughters + + int postrackID = casc.posTrackId(); + int rowInPrimaryTrackTablePos = -1; + rowInPrimaryTrackTablePos = getRowDaughters(postrackID, tmpIDtrack); + childIDs[0] = rowInPrimaryTrackTablePos; // pos + childIDs[1] = 0; // neg + childIDs[2] = 0; // bachelor + float hasTOF = posTrackCasc.hasTOF() ? 1 : 0; + outputCascParts(outputCollision.lastIndex(), + casc.positivept(), + casc.positiveeta(), + casc.positivephi(), + aod::femtouniverseparticle::ParticleType::kV0Child, + 0, // cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kPosCuts), + 0, // cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kPosPID), + hasTOF, + childIDs, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0); + const int rowOfPosTrack = outputCascParts.lastIndex(); + if constexpr (isMC) { + fillMCParticle(posTrackCasc, o2::aod::femtouniverseparticle::ParticleType::kV0Child); + } + int negtrackID = casc.negTrackId(); + int rowInPrimaryTrackTableNeg = -1; + rowInPrimaryTrackTableNeg = getRowDaughters(negtrackID, tmpIDtrack); + childIDs[0] = 0; // pos + childIDs[1] = rowInPrimaryTrackTableNeg; // neg + childIDs[2] = 0; // bachelor + hasTOF = negTrackCasc.hasTOF() ? 1 : 0; + outputCascParts(outputCollision.lastIndex(), + casc.negativept(), + casc.negativeeta(), + casc.negativephi(), + aod::femtouniverseparticle::ParticleType::kV0Child, + 0, // cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kNegCuts), + 0, // cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kNegPID), + hasTOF, + childIDs, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0); + const int rowOfNegTrack = outputCascParts.lastIndex(); + if constexpr (isMC) { + fillMCParticle(negTrackCasc, o2::aod::femtouniverseparticle::ParticleType::kV0Child); + } + // bachelor + int bachtrackID = casc.bachelorId(); + int rowInPrimaryTrackTableBach = -1; + rowInPrimaryTrackTableBach = getRowDaughters(bachtrackID, tmpIDtrack); + childIDs[0] = 0; // pos + childIDs[1] = 0; // neg + childIDs[2] = rowInPrimaryTrackTableBach; // bachelor + hasTOF = bachTrackCasc.hasTOF() ? 1 : 0; + outputCascParts(outputCollision.lastIndex(), + casc.bachelorpt(), + casc.bacheloreta(), + casc.bachelorphi(), + aod::femtouniverseparticle::ParticleType::kCascadeBachelor, + 0, // cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kNegCuts), + 0, // cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kNegPID), + hasTOF, + childIDs, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0); + const int rowOfBachTrack = outputCascParts.lastIndex(); + if constexpr (isMC) { + fillMCParticle(bachTrackCasc, o2::aod::femtouniverseparticle::ParticleType::kCascadeBachelor); + } + // cascade + std::vector indexCascChildID = {rowOfPosTrack, rowOfNegTrack, rowOfBachTrack}; + outputCascParts(outputCollision.lastIndex(), + casc.pt(), + casc.eta(), + casc.phi(), + aod::femtouniverseparticle::ParticleType::kCascade, + 0, // cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kV0), + 0, + 0, + indexCascChildID, + confIsSelectCascOmega ? casc.mOmega() : casc.mXi(), + confIsSelectCascOmega ? casc.mOmega() : casc.mXi(), + casc.dcaV0daughters(), + casc.v0cosPA(col.posX(), col.posY(), col.posZ()), + casc.v0radius(), + casc.casccosPA(col.posX(), col.posY(), col.posZ()), + casc.dcacascdaughters(), + casc.cascradius(), + casc.dcapostopv(), + casc.dcanegtopv(), + casc.dcabachtopv(), + casc.dcav0topv(col.posX(), col.posY(), col.posZ())); + if (confIsDebug) { + fillDebugParticle(posTrackCasc); // QA for positive daughter + fillDebugParticle(negTrackCasc); // QA for negative daughter + fillDebugParticle(bachTrackCasc); // QA for negative daughter + fillDebugParticle(casc); // QA for cascade + } + if constexpr (isMC) { + fillMCParticle(casc, o2::aod::femtouniverseparticle::ParticleType::kCascade); + } + } + } + template void fillD0mesons(CollisionType const&, TrackType const&, HfCandidate const& hfCands) { @@ -776,18 +1291,19 @@ struct femtoUniverseProducerTask { double invMassD0 = 0.0; double invMassD0bar = 0.0; bool isD0D0bar = false; + uint8_t daughFlag = 0; // flag = 0 (daugh of D0 or D0bar), 1 (daug of D0), -1 (daugh of D0bar) - for (auto const& hfCand : hfCands) { + for (const auto& hfCand : hfCands) { if (!(hfCand.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { continue; } - if (ConfD0Selection.ConfD0D0barCandMaxY >= 0. && std::abs(hfHelper.yD0(hfCand)) > ConfD0Selection.ConfD0D0barCandMaxY) { + if (ConfD0Selection.confD0D0barCandMaxY >= 0. && std::abs(hfHelper.yD0(hfCand)) > ConfD0Selection.confD0D0barCandMaxY) { continue; } - if (std::abs(hfCand.eta()) > ConfD0Selection.ConfD0D0barCandEtaCut) { + if (std::abs(hfCand.eta()) > ConfD0Selection.confD0D0barCandEtaCut) { continue; } @@ -804,41 +1320,44 @@ struct femtoUniverseProducerTask { invMassD0 = hfHelper.invMassD0ToPiK(hfCand); invMassD0bar = -hfHelper.invMassD0barToKPi(hfCand); isD0D0bar = true; + daughFlag = 1; } else if (hfCand.isSelD0() == 0 && hfCand.isSelD0bar() == 1) { invMassD0 = -hfHelper.invMassD0ToPiK(hfCand); invMassD0bar = hfHelper.invMassD0barToKPi(hfCand); isD0D0bar = true; + daughFlag = -1; } else if (hfCand.isSelD0() == 1 && hfCand.isSelD0bar() == 1) { invMassD0 = hfHelper.invMassD0ToPiK(hfCand); invMassD0bar = hfHelper.invMassD0barToKPi(hfCand); - isD0D0bar = true; + if (ConfD0Selection.storeD0D0barDoubleMassHypo) { + isD0D0bar = true; + daughFlag = 0; + } else { + isD0D0bar = false; + daughFlag = 0; + } } else { invMassD0 = 0.0; invMassD0bar = 0.0; isD0D0bar = false; } - if (ConfD0Selection.ConfStoreD0D0barWithinTheMassRange) { - if ((invMassD0 < ConfD0Selection.ConfStoreD0D0barInvMassLowLimit && invMassD0 > ConfD0Selection.ConfStoreD0D0barInvMassUpLimit) || (invMassD0bar < ConfD0Selection.ConfStoreD0D0barInvMassLowLimit && invMassD0bar > ConfD0Selection.ConfStoreD0D0barInvMassUpLimit)) - continue; - } - if (isD0D0bar) { outputParts(outputCollision.lastIndex(), hfCand.ptProng0(), RecoDecay::eta(std::array{hfCand.pxProng0(), hfCand.pyProng0(), hfCand.pzProng0()}), // eta RecoDecay::phi(hfCand.pxProng0(), hfCand.pyProng0()), // phi aod::femtouniverseparticle::ParticleType::kD0Child, - -999, // cutContainerV0.at(femtoUniverseV0Selection::V0ContainerPosition::kPosCuts), - -999, // cutContainerV0.at(femtoUniverseV0Selection::V0ContainerPosition::kPosPID), + -999, // cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kPosCuts), + -999, // cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kPosPID), -999, childIDs, - 0, // D0 mass - 0); // D0bar mass + postrack.sign(), // D0 mass -> positive daughter of D0/D0bar + daughFlag); // D0bar mass -> sign that the daugh is from D0 or D0 decay const int rowOfPosTrack = outputParts.lastIndex(); - /*if constexpr (isMC) { - fillMCParticle(tracks, o2::aod::femtouniverseparticle::ParticleType::kDmesonChild); - }*/ + if constexpr (isMC) { + fillMCParticle(postrack, o2::aod::femtouniverseparticle::ParticleType::kD0Child); + } // int negtrackID = hfCand.prong1().globalIndex(); int negtrackID = hfCand.prong1Id(); int rowInPrimaryTrackTableNeg = -1; @@ -851,16 +1370,16 @@ struct femtoUniverseProducerTask { RecoDecay::eta(std::array{hfCand.pxProng1(), hfCand.pyProng1(), hfCand.pzProng1()}), // eta RecoDecay::phi(hfCand.pxProng1(), hfCand.pyProng1()), // phi aod::femtouniverseparticle::ParticleType::kD0Child, - -999, // cutContainerV0.at(femtoUniverseV0Selection::V0ContainerPosition::kNegCuts), - -999, // cutContainerV0.at(femtoUniverseV0Selection::V0ContainerPosition::kNegPID), + -999, // cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kNegCuts), + -999, // cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kNegPID), -999, childIDs, - 0, - 0); + negtrack.sign(), // negative daughter of D0/D0bar + daughFlag); // sign that the daugh is from D0 or D0 decay const int rowOfNegTrack = outputParts.lastIndex(); - /*if constexpr (isMC) { - fillMCParticle(p2, o2::aod::femtouniverseparticle::ParticleType::kDmesonChild); - }*/ + if constexpr (isMC) { + fillMCParticle(negtrack, o2::aod::femtouniverseparticle::ParticleType::kD0Child); + } std::vector indexChildID = {rowOfPosTrack, rowOfNegTrack}; outputParts(outputCollision.lastIndex(), @@ -868,17 +1387,17 @@ struct femtoUniverseProducerTask { hfCand.eta(), hfCand.phi(), aod::femtouniverseparticle::ParticleType::kD0, - -999, // cut, cutContainerType - -999, // PID, cutContainerType - -999, + -999, // cut, CutContainerType + -999, // PID, CutContainerType + -999., indexChildID, invMassD0, // D0 mass (mLambda) invMassD0bar); // D0bar mass (mAntiLambda) - if (ConfIsDebug) { - fillDebugParticle(postrack); // QA for positive daughter - fillDebugParticle(negtrack); // QA for negative daughter - fillDebugParticle(hfCand); // QA for D0/D0bar + if (confIsDebug) { + fillDebugParticle(postrack); // QA for positive daughter + fillDebugParticle(negtrack); // QA for negative daughter + fillDebugParticle(hfCand); // QA for D0/D0bar } if constexpr (isMC) { fillMCParticle(hfCand, o2::aod::femtouniverseparticle::ParticleType::kD0); @@ -887,58 +1406,206 @@ struct femtoUniverseProducerTask { } } - template - void fillPhi(CollisionType const& col, TrackType const& tracks) + template + void fillD0D0barUsingML(CollisionType const&, TrackType const&, HfCandidate const& hfCands) { std::vector childIDs = {0, 0}; // these IDs are necessary to keep track of the children std::vector tmpIDtrack; // this vector keeps track of the matching of the primary track table row <-> aod::track table global index - // lorentz vectors and filling the tables - for (auto& [p1, p2] : combinations(soa::CombinationsStrictlyUpperIndexPolicy(tracks, tracks))) { - // implementing PID cuts for phi children - if (!(IsKaonNSigma(p1.pt(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon)))) { + double invMassD0 = 0.0; + double invMassD0bar = 0.0; + bool isD0D0bar = false; + double mlProbD0D0barBg = 0.0; + uint8_t daughFlag = 0; // flag = 0 (daugh of D0 or D0bar), 1 (daug of D0), -1 (daugh of D0bar) + + for (const auto& hfCand : hfCands) { + + if (!(hfCand.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { continue; } - if (!(IsKaonNSigma(p2.pt(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon)))) { - continue; - } else if ((!(p1.sign() == 1)) || (!(p2.sign() == -1))) { + + if (ConfD0Selection.confD0D0barCandMaxY >= 0. && std::abs(hfHelper.yD0(hfCand)) > ConfD0Selection.confD0D0barCandMaxY) { continue; } - TLorentzVector part1Vec; - TLorentzVector part2Vec; - - float mMassOne = TDatabasePDG::Instance()->GetParticle(ConfPhiChildOne.ConfPDGCodePartOne)->Mass(); // FIXME: Get from the PDG service of the common header - float mMassTwo = TDatabasePDG::Instance()->GetParticle(ConfPhiChildTwo.ConfPDGCodePartTwo)->Mass(); // FIXME: Get from the PDG service of the common header - - part1Vec.SetPtEtaPhiM(p1.pt(), p1.eta(), p1.phi(), mMassOne); - part2Vec.SetPtEtaPhiM(p2.pt(), p2.eta(), p2.phi(), mMassTwo); + if (std::abs(hfCand.eta()) > ConfD0Selection.confD0D0barCandEtaCut) { + continue; + } - TLorentzVector sumVec(part1Vec); - sumVec += part2Vec; + // int postrackID = hfCand.prong0().globalIndex(); + int postrackID = hfCand.prong0Id(); // Index to first prong + int rowInPrimaryTrackTablePos = -1; + rowInPrimaryTrackTablePos = getRowDaughters(postrackID, tmpIDtrack); + childIDs[0] = rowInPrimaryTrackTablePos; + childIDs[1] = 0; + auto postrack = hfCand.template prong0_as(); + auto negtrack = hfCand.template prong1_as(); + + if (hfCand.isSelD0() == 1 && hfCand.isSelD0bar() == 0) { + invMassD0 = hfHelper.invMassD0ToPiK(hfCand); + invMassD0bar = -hfHelper.invMassD0barToKPi(hfCand); + mlProbD0D0barBg = hfCand.mlProbD0()[0]; + isD0D0bar = true; + daughFlag = 1; + } else if (hfCand.isSelD0() == 0 && hfCand.isSelD0bar() == 1) { + invMassD0 = -hfHelper.invMassD0ToPiK(hfCand); + invMassD0bar = hfHelper.invMassD0barToKPi(hfCand); + mlProbD0D0barBg = hfCand.mlProbD0bar()[0]; + isD0D0bar = true; + daughFlag = -1; + } else if (hfCand.isSelD0() == 1 && hfCand.isSelD0bar() == 1) { + invMassD0 = hfHelper.invMassD0ToPiK(hfCand); + invMassD0bar = hfHelper.invMassD0barToKPi(hfCand); + if (ConfD0Selection.storeD0D0barDoubleMassHypo) { + isD0D0bar = true; + daughFlag = 0; + } else { + isD0D0bar = false; + daughFlag = 0; + } + } else { + invMassD0 = 0.0; + invMassD0bar = 0.0; + isD0D0bar = false; + } + + if (isD0D0bar) { + outputParts(outputCollision.lastIndex(), + hfCand.ptProng0(), + RecoDecay::eta(std::array{hfCand.pxProng0(), hfCand.pyProng0(), hfCand.pzProng0()}), // eta + RecoDecay::phi(hfCand.pxProng0(), hfCand.pyProng0()), // phi + aod::femtouniverseparticle::ParticleType::kD0Child, + -999, // cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kPosCuts), + -999, // cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kPosPID), + -999, + childIDs, + postrack.sign(), // D0 mass -> positive daughter of D0/D0bar + daughFlag); // D0bar mass -> sign that the daugh is from D0 or D0 decay + const int rowOfPosTrack = outputParts.lastIndex(); + if constexpr (isMC) { + fillMCParticle(postrack, o2::aod::femtouniverseparticle::ParticleType::kD0Child); + } + // int negtrackID = hfCand.prong1().globalIndex(); + int negtrackID = hfCand.prong1Id(); + int rowInPrimaryTrackTableNeg = -1; + rowInPrimaryTrackTableNeg = getRowDaughters(negtrackID, tmpIDtrack); + childIDs[0] = 0; + childIDs[1] = rowInPrimaryTrackTableNeg; + + outputParts(outputCollision.lastIndex(), + hfCand.ptProng1(), + RecoDecay::eta(std::array{hfCand.pxProng1(), hfCand.pyProng1(), hfCand.pzProng1()}), // eta + RecoDecay::phi(hfCand.pxProng1(), hfCand.pyProng1()), // phi + aod::femtouniverseparticle::ParticleType::kD0Child, + -999, // cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kNegCuts), + -999, // cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kNegPID), + -999, + childIDs, + negtrack.sign(), // negative daughter of D0/D0bar + daughFlag); // sign that the daugh is from D0 or D0 decay + const int rowOfNegTrack = outputParts.lastIndex(); + if constexpr (isMC) { + fillMCParticle(negtrack, o2::aod::femtouniverseparticle::ParticleType::kD0Child); + } + std::vector indexChildID = {rowOfPosTrack, rowOfNegTrack}; + + outputParts(outputCollision.lastIndex(), + hfCand.pt(), + hfCand.eta(), + hfCand.phi(), + aod::femtouniverseparticle::ParticleType::kD0, + -999, // cut, CutContainerType + -999, // PID, CutContainerType + mlProbD0D0barBg, // saving the probability for ML score class 1 + indexChildID, + invMassD0, // D0 mass (mLambda) + invMassD0bar); // D0bar mass (mAntiLambda) + + if (confIsDebug) { + fillDebugParticle(postrack); // QA for positive daughter + fillDebugParticle(negtrack); // QA for negative daughter + if (hfCand.isSelD0() == 1 && hfCand.isSelD0bar() == 0) { + fillDebugD0D0barML(hfCand); // QA for D0/D0bar + } else if (hfCand.isSelD0() == 0 && hfCand.isSelD0bar() == 1) { + fillDebugD0D0barML(hfCand); + } else { + fillDebugD0D0barML(hfCand); + } + } + if constexpr (isMC) { + fillMCParticleD0(hfCand); + } + } + } + } + + template + void fillPhi(CollisionType const& col, TrackType const& tracks) + { + std::vector childIDs = {0, 0}; // these IDs are necessary to keep track of the children + std::vector tmpIDtrack; // this vector keeps track of the matching of the primary track table row <-> aod::track table global index + // lorentz vectors and filling the tables + for (const auto& [p1, p2] : combinations(soa::CombinationsFullIndexPolicy(tracks, tracks))) { + if (!trackCuts.isSelectedMinimal(p1) || !trackCuts.isSelectedMinimal(p1)) { + continue; + } + if ((!(p1.sign() == 1)) || (!(p2.sign() == -1))) { + continue; + } + // implementing PID cuts for phi children + if (ConfPhiSelection.confPhiDoLFPID4Kaons) { + if ((p1.isGlobalTrackWoDCA() == false) || (p2.isGlobalTrackWoDCA() == false) || (p1.isPVContributor() == false) || (p2.isPVContributor() == false)) { + continue; + } + if (!(isKaonNSigmaLF(p1.pt(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon), p1.hasTOF()))) { + continue; + } + if (!(isKaonNSigmaLF(p2.pt(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon), p2.hasTOF()))) { + continue; + } + } else { + if (!(isKaonNSigma(p1.pt(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon)))) { + continue; + } + if (!(isKaonNSigma(p2.pt(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon)))) { + continue; + } + } + if (isKaonRejected(p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion))) { + continue; + } + if (isKaonRejected(p2.p(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion))) { + continue; + } + + TLorentzVector part1Vec; + TLorentzVector part2Vec; + + const auto mMassOne = o2::constants::physics::MassKPlus; // FIXME: Get from the PDG service of the common header + const auto mMassTwo = o2::constants::physics::MassKMinus; // FIXME: Get from the PDG service of the common header + + part1Vec.SetPtEtaPhiM(p1.pt(), p1.eta(), p1.phi(), mMassOne); + part2Vec.SetPtEtaPhiM(p2.pt(), p2.eta(), p2.phi(), mMassTwo); + + TLorentzVector sumVec(part1Vec); + sumVec += part2Vec; float phiEta = sumVec.Eta(); - if (TMath::Abs(phiEta) > 0.8) { + if (std::abs(phiEta) > 0.8) { continue; } float phiPt = sumVec.Pt(); - if ((phiPt < 0.14) || (phiPt > 10.0)) { + if ((phiPt < ConfPhiSelection.confPhiPtLowLimit.value) || (phiPt > ConfPhiSelection.confPhiPtHighLimit.value)) { continue; } - float phiPhi = sumVec.Phi(); - if (sumVec.Phi() < 0) { - phiPhi = sumVec.Phi() + 2 * o2::constants::math::PI; - } else if (sumVec.Phi() >= 0) { - phiPhi = sumVec.Phi(); - } + float phiPhi = RecoDecay::constrainAngle(sumVec.Phi(), 0); float phiM = sumVec.M(); - if (((phiM < ConfPhiCommon.ConfInvMassLowLimitPhi) || (phiM > ConfPhiCommon.ConfInvMassUpLimitPhi))) { + if ((phiM < ConfPhiSelection.confPhiInvMassLowLimit) || (phiM > ConfPhiSelection.confPhiInvMassUpLimit)) continue; - } - phiCuts.fillQA(col, p1, p1, p2, ConfPhiChildOne.ConfPDGCodePartOne, ConfPhiChildTwo.ConfPDGCodePartTwo); ///\todo fill QA also for daughters + phiCuts.fillQA(col, p1, p1, p2, 321, -321); ///\todo fill QA also for daughters int postrackID = p1.globalIndex(); int rowInPrimaryTrackTablePos = -1; // does it do anything? @@ -949,12 +1616,12 @@ struct femtoUniverseProducerTask { outputParts(outputCollision.lastIndex(), p1.pt(), p1.eta(), p1.phi(), aod::femtouniverseparticle::ParticleType::kPhiChild, - -999, // cutContainerV0.at(femtoUniverseV0Selection::V0ContainerPosition::kPosCuts), - -999, // cutContainerV0.at(femtoUniverseV0Selection::V0ContainerPosition::kPosPID), - p1.dcaXY(), + -999, // cutContainer + -999, // cutContainer + p1.dcaXY(), // tempFitVar childIDs, 0, - 1); // sign, workaround for now + p1.sign()); const int rowOfPosTrack = outputParts.lastIndex(); if constexpr (isMC) { fillMCParticle(p1, o2::aod::femtouniverseparticle::ParticleType::kPhiChild); @@ -969,12 +1636,12 @@ struct femtoUniverseProducerTask { p2.eta(), p2.phi(), aod::femtouniverseparticle::ParticleType::kPhiChild, - -999, // cutContainerV0.at(femtoUniverseV0Selection::V0ContainerPosition::kNegCuts), - -999, // cutContainerV0.at(femtoUniverseV0Selection::V0ContainerPosition::kNegPID), - p2.dcaXY(), + -999, // cutContainer + -999, // cutContainer + p2.dcaXY(), // tempFitVar childIDs, 0, - -1); // sign, workaround for now + p2.sign()); // sign, workaround for now const int rowOfNegTrack = outputParts.lastIndex(); if constexpr (isMC) { fillMCParticle(p2, o2::aod::femtouniverseparticle::ParticleType::kPhiChild); @@ -986,49 +1653,50 @@ struct femtoUniverseProducerTask { phiEta, phiPhi, aod::femtouniverseparticle::ParticleType::kPhi, - -999, // cutContainerV0.at(femtoUniverseV0Selection::V0ContainerPosition::kV0), + -999, // cutContainer 0, - phiM, // v0.v0cosPA(), + phiM, // tempFitVar indexChildID, - phiM, // phi.mLambda(), //for now it will have a mLambda getter, maybe we will change it in the future so it's more logical - -999); // v0.mAntiLambda() + phiM, // phi.mLambda(), //for now it will have a mLambda getter, maybe we will change it in the future so it's more logical + 0); // phi.mAntiLambda() <- sign - if (ConfIsDebug) { - fillDebugParticle(p1); // QA for positive daughter - fillDebugParticle(p2); // QA for negative daughter - fillDebugParticle(p1); // QA for phi + if (confIsDebug) { + fillDebugParticle(p1); // QA for positive daughter + fillDebugParticle(p2); // QA for negative daughter + fillDebugParticle(p1); // QA for phi + } + if constexpr (isMC) { + fillMCParticlePhi(p1, p2); } - // if constexpr (isMC) { - // fillMCParticle(v0, o2::aod::femtouniverseparticle::ParticleType::kV0); - // } } } - template - void fillParticles(TrackType const& tracks) + template + void fillParticles(TrackType const& tracks, std::optional>> recoMcIds = std::nullopt) { std::vector childIDs = {0, 0}; // these IDs are necessary to keep track of the children + std::vector tmpIDtrack; - for (auto& particle : tracks) { + for (const auto& particle : tracks) { /// if the most open selection criteria are not fulfilled there is no /// point looking further at the track - if (particle.eta() < -ConfFilterCuts.ConfEtaFilterCut || particle.eta() > ConfFilterCuts.ConfEtaFilterCut) + if (particle.eta() < -ConfFilterCuts.confEtaFilterCut || particle.eta() > ConfFilterCuts.confEtaFilterCut) continue; - if (particle.pt() < ConfFilterCuts.ConfPtLowFilterCut || particle.pt() > ConfFilterCuts.ConfPtHighFilterCut) + if (particle.pt() < ConfFilterCuts.confPtLowFilterCut || particle.pt() > ConfFilterCuts.confPtHighFilterCut) continue; - uint32_t pdgCode = (uint32_t)particle.pdgCode(); + uint32_t pdgCode = static_cast(particle.pdgCode()); - if (ConfMCTruthAnalysisWithPID) { + if (confMCTruthAnalysisWithPID) { bool pass = false; - std::vector tmpPDGCodes = ConfMCTruthPDGCodes; // necessary due to some features of the Configurable - for (uint32_t pdg : tmpPDGCodes) { + std::vector tmpPDGCodes = confMCTruthPDGCodes; // necessary due to some features of the Configurable + for (auto const& pdg : tmpPDGCodes) { if (static_cast(pdg) == static_cast(pdgCode)) { - if (pdgCode == 333) { // ATTENTION: workaround for now, because all Phi mesons are NOT primary particles for now. + if (pdgCode == 333) { // && (recoMcIds && recoMcIds->get().contains(particle.globalIndex()))) { // ATTENTION: all Phi mesons are NOT primary particles pass = true; } else { - if (particle.isPhysicalPrimary()) + if (confStoreMCmothers || particle.isPhysicalPrimary() || (confActivateSecondaries && recoMcIds && recoMcIds->get().contains(particle.globalIndex()))) pass = true; } } @@ -1045,21 +1713,238 @@ struct femtoUniverseProducerTask { // trackCuts.fillQA(track); // the bit-wise container of the systematic variations is obtained - // auto cutContainer = trackCuts.getCutContainer(track); + // auto cutContainer = trackCuts.getCutContainer(track); // instead of the bitmask, the PDG of the particle is stored as uint32_t + int32_t variablePDG = confStoreMCmothers ? getMotherPDG(particle) : particle.pdgCode(); + // now the table is filled - outputParts(outputCollision.lastIndex(), - particle.pt(), - particle.eta(), - particle.phi(), - aod::femtouniverseparticle::ParticleType::kMCTruthTrack, - 0, - pdgCode, - pdgCode, - childIDs, - 0, - 0); + if constexpr (resolveDaughs) { + tmpIDtrack.push_back(particle.globalIndex()); + continue; + } + if (!confIsActivateCascade) { + outputParts(outputCollision.lastIndex(), + particle.pt(), + particle.eta(), + particle.phi(), + aod::femtouniverseparticle::ParticleType::kMCTruthTrack, + 0, + pdgCode, + variablePDG, + childIDs, + 0, + 0); + } else { + childIDs.push_back(0); + outputCascParts(outputCollision.lastIndex(), + particle.pt(), + particle.eta(), + particle.phi(), + aod::femtouniverseparticle::ParticleType::kMCTruthTrack, + 0, + pdgCode, + pdgCode, + childIDs, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + } + if (confIsDebug) { + fillDebugParticle(particle); + } + + // Workaround to keep the FDParticles and MC label tables + // aligned, so that they can be joined in the task. + if constexpr (transientLabels) { + outputPartsMCLabels(-1); + outputDebugPartsMC(9999); + } + } + if constexpr (resolveDaughs) { + childIDs[0] = 0; + childIDs[1] = 0; + auto minDaughs = 2ul; + if (confIsActivateCascade) { + childIDs.push_back(0); + minDaughs = 3ul; + } + for (std::size_t i = 0; i < tmpIDtrack.size(); i++) { + const auto& particle = tracks.iteratorAt(tmpIDtrack[i] - tracks.begin().globalIndex()); + for (int daughIndex = 0, n = std::min(minDaughs, particle.daughtersIds().size()); daughIndex < n; daughIndex++) { + // loop to find the corresponding index of the daughters + for (std::size_t j = 0; j < tmpIDtrack.size(); j++) { + if (tmpIDtrack[j] == particle.daughtersIds()[daughIndex]) { + childIDs[daughIndex] = i - j; + break; + } + } + } + + int32_t variablePDG = confStoreMCmothers ? getMotherPDG(particle) : particle.pdgCode(); + + if (!confIsActivateCascade) { + outputParts(outputCollision.lastIndex(), + particle.pt(), + particle.eta(), + particle.phi(), + aod::femtouniverseparticle::ParticleType::kMCTruthTrack, + 0, + static_cast(particle.pdgCode()), + variablePDG, + childIDs, + 0, + 0); + } else { + outputCascParts(outputCollision.lastIndex(), + particle.pt(), + particle.eta(), + particle.phi(), + aod::femtouniverseparticle::ParticleType::kMCTruthTrack, + 0, + static_cast(particle.pdgCode()), + particle.pdgCode(), + childIDs, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + } + if (confIsDebug) { + fillDebugParticle(particle); + } + + // Workaround to keep the FDParticles and MC label tables + // aligned, so that they can be joined in the task. + if constexpr (transientLabels) { + outputPartsMCLabels(-1); + outputDebugPartsMC(9999); + } + } + } + } + + template + void fillMCTruthParticlesD0(TrackType const& tracks, std::optional>> recoMcIds = std::nullopt) + { + std::vector childIDs = {0, 0}; // these IDs are necessary to keep track of the children + std::vector tmpIDtrack; + + for (const auto& particle : tracks) { + /// if the most open selection criteria are not fulfilled there is no + /// point looking further at the track + + if (particle.eta() < -ConfFilterCuts.confEtaFilterCut || particle.eta() > ConfFilterCuts.confEtaFilterCut) + continue; + if (particle.pt() < ConfFilterCuts.confPtLowFilterCut || particle.pt() > ConfFilterCuts.confPtHighFilterCut) + continue; + + uint32_t pdgCode = static_cast(particle.pdgCode()); + + if (confMCTruthAnalysisWithPID) { + bool pass = false; + std::vector tmpPDGCodes = confMCTruthPDGCodes; // necessary due to some features of the Configurable + for (auto const& pdg : tmpPDGCodes) { + if (static_cast(pdg) == static_cast(pdgCode)) { + if (pdgCode == 333) { // && (recoMcIds && recoMcIds->get().contains(particle.globalIndex()))) { // ATTENTION: all Phi mesons are NOT primary particles + pass = true; + } else if (pdgCode == 421) { + pass = true; + } else { + if (particle.isPhysicalPrimary() || (confActivateSecondaries && recoMcIds && recoMcIds->get().contains(particle.globalIndex()))) + pass = true; + } + } + } + if (!pass) + continue; + } + + // now the table is filled + if constexpr (resolveDaughs) { + tmpIDtrack.push_back(particle.globalIndex()); + continue; + } + if (confIsActiveD0) { + + auto mcD0origin = aod::femtouniverseparticle::ParticleType::kMCTruthTrack; + float ptGenB = -1; + if (std::abs(particle.flagMcMatchGen()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { + if (ConfD0Selection.yD0D0barCandGenMax >= 0. && std::abs(RecoDecay::y(particle.pVector(), o2::constants::physics::MassD0)) > ConfD0Selection.yD0D0barCandGenMax) { + continue; + } + mcD0origin = aod::femtouniverseparticle::ParticleType::kMCTruthTrack; + // WORK IN PROGRESS: If needed changed it to prompt and non-prompt + /*if (particle.originMcGen() == RecoDecay::OriginType::Prompt) { + mcD0origin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrompt; + ptGenB = -1; + } else { + mcD0origin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kNonPrompt; + ptGenB = particle.idxBhadMotherPart().pt(); + }*/ + outputParts(outputCollision.lastIndex(), + particle.pt(), + particle.eta(), + particle.phi(), + mcD0origin, + 0, + pdgCode, + pdgCode, + childIDs, + RecoDecay::y(particle.pVector(), o2::constants::physics::MassD0), + ptGenB); // pT of the B hadron (mother particle, only when non-prompt D0) + } + } else { + outputCascParts(outputCollision.lastIndex(), + particle.pt(), + particle.eta(), + particle.phi(), + aod::femtouniverseparticle::ParticleType::kMCTruthTrack, + 0, + pdgCode, + pdgCode, + childIDs, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + } + if (confIsDebug) { + fillDebugParticle(particle); + } + + // Workaround to keep the FDParticles and MC label tables + // aligned, so that they can be joined in the task. + if constexpr (transientLabels) { + outputPartsMCLabels(-1); + outputDebugPartsMC(9999); + } + } + if constexpr (resolveDaughs) { + childIDs[0] = 0; + childIDs[1] = 0; + for (std::size_t i = 0; i < tmpIDtrack.size(); i++) { + const auto& particle = tracks.iteratorAt(tmpIDtrack[i] - tracks.begin().globalIndex()); + for (int daughIndex = 0, n = std::min(2ul, particle.daughtersIds().size()); daughIndex < n; daughIndex++) { + // loop to find the corresponding index of the daughters + for (std::size_t j = 0; j < tmpIDtrack.size(); j++) { + if (tmpIDtrack[j] == particle.daughtersIds()[daughIndex]) { + childIDs[daughIndex] = i - j; + break; + } + } + } + outputParts(outputCollision.lastIndex(), + particle.pt(), + particle.eta(), + particle.phi(), + aod::femtouniverseparticle::ParticleType::kMCTruthTrack, + 0, + static_cast(particle.pdgCode()), + particle.pdgCode(), + childIDs, + 0, + 0); + if (confIsDebug) { + fillDebugParticle(particle); + } + + // Workaround to keep the FDParticles and MC label tables + // aligned, so that they can be joined in the task. + if constexpr (transientLabels) { + outputPartsMCLabels(-1); + outputDebugPartsMC(9999); + } + } } } @@ -1067,14 +1952,19 @@ struct femtoUniverseProducerTask { typename CollisionType> void fillCollisionsAndTracksAndV0AndPhi(CollisionType const& col, TrackType const& tracks, V0Type const& fullV0s) { - fillCollisions(col, tracks); - fillTracks(tracks); - if (ConfIsActivateV0) { - fillV0(col, fullV0s, tracks); - } - if (ConfIsActivatePhi) { - fillPhi(col, tracks); + const auto colcheck = fillCollisions(col, tracks); + if (colcheck) { + fillTracks(tracks); + if (confIsActivateV0) { + fillV0(col, fullV0s, tracks); + } + if (confIsActivatePhi) { + fillPhi(col, tracks); + } } + // if (confIsActivateCascade) { + // fillCascade(col, fullCascades, tracks); + // } } void processFullData(aod::FemtoFullCollision const& col, @@ -1087,7 +1977,7 @@ struct femtoUniverseProducerTask { // fill the tables fillCollisionsAndTracksAndV0AndPhi(col, tracks, fullV0s); } - PROCESS_SWITCH(femtoUniverseProducerTask, processFullData, "Provide experimental data", false); + PROCESS_SWITCH(FemtoUniverseProducerTask, processFullData, "Provide experimental data", false); void processTrackV0(aod::FemtoFullCollision const& col, aod::BCsWithTimestamps const&, @@ -1099,7 +1989,37 @@ struct femtoUniverseProducerTask { // fill the tables fillCollisionsAndTracksAndV0AndPhi(col, tracks, fullV0s); } - PROCESS_SWITCH(femtoUniverseProducerTask, processTrackV0, "Provide experimental data for track v0", false); + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackV0, "Provide experimental data for track v0", false); + + void processTrackCascadeData(aod::FemtoFullCollision const& col, + aod::BCsWithTimestamps const&, + soa::Filtered const& tracks, + o2::aod::CascDatas const& fullCascades) + { + // get magnetic field for run + getMagneticFieldTesla(col.bc_as()); + // fill the tables + const auto colcheck = fillCollisions(col, tracks); + if (colcheck) { + fillTracks(tracks); + fillCascade(col, fullCascades, tracks); + } + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackCascadeData, "Provide experimental data for track cascades", false); + + /*void processTrackV0CentRun3(aod::FemtoFullCollisionCentRun3 const& col, + aod::BCsWithTimestamps const&, + soa::Filtered const& tracks, + o2::aod::V0Datas const& fullV0s) + { + // get magnetic field for run + getMagneticFieldTesla(col.bc_as()); + // fill the tables + fillCollisionsCentRun3(col, tracks, fullV0s); + fillTracks(tracks); + fillV0(col, fullV0s, tracks); + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackV0CentRun3, "Provide experimental data for track v0", false);*/ void processFullMC(aod::FemtoFullCollisionMC const& col, aod::BCsWithTimestamps const&, @@ -1113,7 +2033,7 @@ struct femtoUniverseProducerTask { // fill the tables fillCollisionsAndTracksAndV0AndPhi(col, tracks, fullV0s); } - PROCESS_SWITCH(femtoUniverseProducerTask, processFullMC, "Provide MC data (tracks, V0, Phi)", false); + PROCESS_SWITCH(FemtoUniverseProducerTask, processFullMC, "Provide MC data (tracks, V0, Phi)", false); void processTrackMC(aod::FemtoFullCollisionMC const& col, aod::BCsWithTimestamps const&, @@ -1124,10 +2044,29 @@ struct femtoUniverseProducerTask { // get magnetic field for run getMagneticFieldTesla(col.bc_as()); // fill the tables - fillCollisions(col, tracks); - fillTracks(tracks); + const auto colcheck = fillCollisions(col, tracks); + if (colcheck) { + fillTracks(tracks); + } } - PROCESS_SWITCH(femtoUniverseProducerTask, processTrackMC, "Provide MC data for track analysis", false); + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackMC, "Provide MC data for track analysis", false); + + void processTrackPhiMC(aod::FemtoFullCollisionMC const& col, + aod::BCsWithTimestamps const&, + soa::Join const& tracks, + aod::McCollisions const&, + aod::McParticles const&) + { + // get magnetic field for run + getMagneticFieldTesla(col.bc_as()); + // fill the tables + const auto colcheck = fillCollisions(col, tracks); + if (colcheck) { + fillTracks(tracks); + fillPhi(col, tracks); + } + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackPhiMC, "Provide MC data for track Phi analysis", false); void processTrackData(aod::FemtoFullCollision const& col, aod::BCsWithTimestamps const&, @@ -1135,13 +2074,38 @@ struct femtoUniverseProducerTask { { // get magnetic field for run getMagneticFieldTesla(col.bc_as()); + const double ir = 1.0; // fetch IR // fill the tables - fillCollisions(col, tracks); - fillTracks(tracks); + const auto colcheck = fillCollisions(col, tracks); + if (colcheck) { + if (confFillCollExt) { + fillCollisionsCentRun3ColExtra(col, ir); + } + fillTracks(tracks); + } } - PROCESS_SWITCH(femtoUniverseProducerTask, processTrackData, + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackData, "Provide experimental data for track track", true); + void processTrackDataCentPP(aod::FemtoFullCollisionCentPP const& col, + aod::BCsWithTimestamps const&, + aod::FemtoFullTracks const& tracks) + { + // get magnetic field for run + getMagneticFieldTesla(col.bc_as()); + const double ir = 1.0; // fetch IR + // fill the tables + const auto colcheck = fillCollisionsCentPP(col, tracks); + if (colcheck) { + if (confFillCollExt) { + fillCollisionsCentRun3ColExtra(col, ir); + } + fillTracks(tracks); + } + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackDataCentPP, + "Provide experimental data for track track", false); + // using FilteredFemtoFullTracks = soa::Filtered; void processTrackPhiData(aod::FemtoFullCollision const& col, aod::BCsWithTimestamps const&, @@ -1150,11 +2114,13 @@ struct femtoUniverseProducerTask { // get magnetic field for run getMagneticFieldTesla(col.bc_as()); // fill the tables - fillCollisions(col, tracks); - fillTracks(tracks); - fillPhi(col, tracks); + const auto colcheck = fillCollisions(col, tracks); + if (colcheck) { + fillTracks(tracks); + fillPhi(col, tracks); + } } - PROCESS_SWITCH(femtoUniverseProducerTask, processTrackPhiData, + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackPhiData, "Provide experimental data for track phi", false); void processTrackD0mesonData(aod::FemtoFullCollision const& col, @@ -1165,13 +2131,32 @@ struct femtoUniverseProducerTask { // get magnetic field for run getMagneticFieldTesla(col.bc_as()); // fill the tables - fillCollisions(col, tracks); - fillTracks(tracks); - fillD0mesons(col, tracks, candidates); + const auto colcheck = fillCollisions(col, tracks); + if (colcheck) { + fillTracks(tracks); + fillD0mesons(col, tracks, candidates); + } } - PROCESS_SWITCH(femtoUniverseProducerTask, processTrackD0mesonData, + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackD0mesonData, "Provide experimental data for track D0 meson", false); + void processTrackD0DataML(aod::FemtoFullCollision const& col, + aod::BCsWithTimestamps const&, + soa::Filtered const& tracks, + soa::Join const& candidates) + { + // get magnetic field for run + getMagneticFieldTesla(col.bc_as()); + // fill the tables + const auto colcheck = fillCollisions(col, tracks); + if (colcheck) { + fillTracks(tracks); + fillD0D0barUsingML(col, tracks, candidates); + } + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackD0DataML, + "Provide experimental data for track D0 meson using ML selection for D0s", false); + void processTrackMCTruth(aod::McCollision const&, soa::SmallGroups> const& collisions, aod::McParticles const& mcParticles, @@ -1182,35 +2167,349 @@ struct femtoUniverseProducerTask { fillMCTruthCollisions(collisions, mcParticles); fillParticles(mcParticles); } - PROCESS_SWITCH(femtoUniverseProducerTask, processTrackMCTruth, "Provide MC data for MC truth track analysis", false); + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackMCTruth, "Provide MC data for MC truth track analysis", false); + + void processTrackMCGen(aod::McCollision const& col, + aod::McParticles const& mcParticles) + { + outputCollision(col.posZ(), 0, 0, 2, 0); + fillParticles(mcParticles); + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackMCGen, "Provide MC Generated for model comparisons", false); + + template + using HasBachelor = decltype(std::declval().bachelorphi()); + + Preslice perMCCollision = aod::mcparticle::mcCollisionId; + PresliceUnsorted> recoCollsPerMCColl = aod::mcparticle::mcCollisionId; + PresliceUnsorted> recoCollsPerMCCollCentPbPb = aod::mcparticle::mcCollisionId; + Preslice> perCollisionTracks = aod::track::collisionId; + + template + + void processTruthAndFullMC( + aod::McCollisions const& mccols, + aod::McParticles const& mcParticles, + soa::Join const& collisions, + soa::Filtered> const& tracks, + StrangePartType const& strangeParts, + aod::BCsWithTimestamps const&, + Preslice& ps) + { + // recos + std::set recoMcIds; + for (const auto& col : collisions) { + auto groupedTracks = tracks.sliceBy(perCollisionTracks, col.globalIndex()); + auto groupedStrageParts = strangeParts.sliceBy(ps, col.globalIndex()); + getMagneticFieldTesla(col.bc_as()); + if constexpr (std::experimental::is_detected::value) { + const auto colcheck = fillCollisions(col, groupedTracks); + if (colcheck) { + fillTracks(groupedTracks); + fillCascade(col, groupedStrageParts, groupedTracks); + } + } else { + fillCollisionsAndTracksAndV0AndPhi(col, groupedTracks, groupedStrageParts); + } + for (const auto& track : groupedTracks) { + if (trackCuts.isSelectedMinimal(track)) + recoMcIds.insert(track.mcParticleId()); + } + } + + // truth + for (const auto& mccol : mccols) { + auto groupedMCParticles = mcParticles.sliceBy(perMCCollision, mccol.globalIndex()); + auto groupedCollisions = collisions.sliceBy(recoCollsPerMCColl, mccol.globalIndex()); + fillMCTruthCollisions(groupedCollisions, groupedMCParticles); // fills the reco collisions for mc collision + fillParticles(groupedMCParticles, recoMcIds); // fills mc particles + } + } + + void processTruthAndFullMCCentRun3(aod::McCollisions const& mccols, + aod::McParticles const& mcParticles, + aod::FemtoFullCollisionCentRun3MCs const& collisions, + soa::Filtered> const& tracks, + aod::BCsWithTimestamps const&) + { + // recos + std::set recoMcIds; + for (const auto& col : collisions) { + auto groupedTracks = tracks.sliceBy(perCollisionTracks, col.globalIndex()); + auto bc = col.bc_as(); + getMagneticFieldTesla(bc); + const auto ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), mRunNumber, "ZNC hadronic") * 1.e-3; // fetch IR + + // fill the tables + const auto colcheck = fillCollisionsCentRun3(col); + if (colcheck) { + fillCollisionsCentRun3ColExtra(col, ir); + fillTracks(groupedTracks); + } + for (const auto& track : groupedTracks) { + if (trackCuts.isSelectedMinimal(track)) + recoMcIds.insert(track.mcParticleId()); + } + } + + // truth + for (const auto& mccol : mccols) { + auto groupedCollisions = collisions.sliceBy(recoCollsPerMCCollCentPbPb, mccol.globalIndex()); + for (const auto& col : groupedCollisions) { + const auto colcheck = fillMCTruthCollisionsCentRun3(col); // fills the reco collisions for mc collision + if (colcheck) { + auto groupedMCParticles = mcParticles.sliceBy(perMCCollision, mccol.globalIndex()); + outputCollExtra(1.0, 1.0); + fillParticles(groupedMCParticles, recoMcIds); // fills mc particles + } + } + } + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processTruthAndFullMCCentRun3, "Provide both MC truth and reco for tracks in Pb-Pb", false); + + Preslice> perCollisionV0s = aod::track::collisionId; + void processTruthAndFullMCV0( + aod::McCollisions const& mccols, + aod::McParticles const& mcParticles, + soa::Join const& collisions, + soa::Filtered> const& tracks, + soa::Join const& fullV0s, + aod::BCsWithTimestamps const& bcs) + { + processTruthAndFullMC(mccols, mcParticles, collisions, tracks, fullV0s, bcs, perCollisionV0s); + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processTruthAndFullMCV0, "Provide both MC truth and reco for tracks and V0s", false); + + void processTruthAndFullMCCentRun3V0( + aod::McCollisions const& mccols, + aod::McParticles const& mcParticles, + aod::FemtoFullCollisionCentRun3MCs const& collisions, + soa::Filtered> const& tracks, + soa::Join const& fullV0s, + aod::BCsWithTimestamps const&) + { + + // recos + std::set recoMcIds; + for (const auto& col : collisions) { + auto groupedTracks = tracks.sliceBy(perCollisionTracks, col.globalIndex()); + auto groupedV0Parts = fullV0s.sliceBy(perCollisionV0s, col.globalIndex()); + getMagneticFieldTesla(col.bc_as()); + const auto colcheck = fillCollisionsCentRun3(col); + if (colcheck) { + fillTracks(groupedTracks); + fillV0(col, groupedV0Parts, groupedTracks); + } + for (const auto& track : groupedTracks) { + if (trackCuts.isSelectedMinimal(track)) + recoMcIds.insert(track.mcParticleId()); + } + } + + // truth + for (const auto& mccol : mccols) { + auto groupedCollisions = collisions.sliceBy(recoCollsPerMCCollCentPbPb, mccol.globalIndex()); + for (const auto& col : groupedCollisions) { + const auto colcheck = fillMCTruthCollisionsCentRun3(col); // fills the reco collisions for mc collision + if (colcheck) { + auto groupedMCParticles = mcParticles.sliceBy(perMCCollision, mccol.globalIndex()); + outputCollExtra(1.0, 1.0); + fillParticles(groupedMCParticles, recoMcIds); // fills mc particles + } + } + } + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processTruthAndFullMCCentRun3V0, "Provide both MC truth and reco for tracks and V0s with centrality", false); + + Preslice> perCollisionCascs = aod::track::collisionId; + void processTruthAndFullMCCasc( + aod::McCollisions const& mccols, + aod::McParticles const& mcParticles, + soa::Join const& collisions, + soa::Filtered> const& tracks, + soa::Join const& fullCascades, + aod::BCsWithTimestamps const& bcs) + { + processTruthAndFullMC(mccols, mcParticles, collisions, tracks, fullCascades, bcs, perCollisionCascs); + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processTruthAndFullMCCasc, "Provide both MC truth and reco for tracks and Cascades", false); + + Preslice> perCollisionD0s = aod::track::collisionId; + void processTrackD0MC(aod::McCollisions const& mccols, + aod::TracksWMc const&, + soa::Join const& collisions, + soa::Filtered> const& tracks, + soa::Join const& hfMcGenCands, + soa::Join const& hfMcRecoCands, + aod::BCsWithTimestamps const&) + { + // MC Reco + std::set recoMcIds; + for (const auto& col : collisions) { + auto groupedTracks = tracks.sliceBy(perCollisionTracks, col.globalIndex()); + auto groupedD0s = hfMcRecoCands.sliceBy(perCollisionD0s, col.globalIndex()); + // get magnetic field for run + getMagneticFieldTesla(col.bc_as()); + // fill the tables + const auto colcheck = fillCollisions(col, tracks); + if (colcheck) { + fillTracks(tracks); + fillD0D0barUsingML(col, groupedTracks, groupedD0s); + for (const auto& track : groupedTracks) { + if (trackCuts.isSelectedMinimal(track)) + recoMcIds.insert(track.mcParticleId()); + } + } + } + // MC Truth + for (const auto& mccol : mccols) { + auto groupedMCParticles = hfMcGenCands.sliceBy(perMCCollision, mccol.globalIndex()); + auto groupedCollisions = collisions.sliceBy(recoCollsPerMCColl, mccol.globalIndex()); + fillMCTruthCollisions(groupedCollisions, groupedMCParticles); // fills the reco collisions for mc collision + fillMCTruthParticlesD0(groupedMCParticles, recoMcIds); // fills mc particles + } + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackD0MC, "Provide MC data for track D0 analysis", false); + + void processFullMCCent(aod::FemtoFullCollisionCentRun3 const& col, + aod::BCsWithTimestamps const&, + soa::Join const& tracks, + aod::McCollisions const&, + aod::McParticles const&) + { + // get magnetic field for run + auto bc = col.bc_as(); + getMagneticFieldTesla(bc); + const double ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), mRunNumber, "ZNC hadronic") * 1.e-3; // fetch IR + + // fill the tables + const auto colcheck = fillCollisionsCentRun3(col); + if (colcheck) { + fillCollisionsCentRun3ColExtra(col, ir); + fillTracks(tracks); + } + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processFullMCCent, "Provide MC data with centrality bins", false); void processTrackCentRun2Data(aod::FemtoFullCollisionCentRun2 const& col, aod::BCsWithTimestamps const&, - aod::FemtoFullTracks const& tracks) + soa::Filtered const& tracks) { // get magnetic field for run - getMagneticFieldTesla(col.bc_as()); + auto bc = col.bc_as(); + getMagneticFieldTesla(bc); + const double ir = 0.0; // fetch IR + // fill the tables - fillCollisionsCentRun2(col, tracks); - fillTracks(tracks); + const auto colcheck = fillCollisionsCentRun2(col); + if (colcheck) { + fillCollisionsCentRun3ColExtra(col, ir); + fillTracks(tracks); + } } - PROCESS_SWITCH(femtoUniverseProducerTask, processTrackCentRun2Data, "Provide experimental data for Run 2 with centrality for track track", false); + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackCentRun2Data, "Provide experimental data for Run 2 with centrality for track track", false); + + void processTrackV0CentRun2Data(aod::FemtoFullCollisionCentRun2 const& col, + aod::BCsWithTimestamps const&, + soa::Filtered const& tracks, + aod::V0Datas const& fullV0s) + { + // get magnetic field for run + auto bc = col.bc_as(); + getMagneticFieldTesla(bc); + const double ir = 0.0; // fetch IR + + // fill the tables + const auto colcheck = fillCollisionsCentRun2(col); + if (colcheck) { + fillCollisionsCentRun3ColExtra(col, ir); + fillTracks(tracks); + fillV0(col, fullV0s, tracks); + } + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackV0CentRun2Data, "Provide experimental data for Run 2 with centrality for track V0", false); void processTrackCentRun3Data(aod::FemtoFullCollisionCentRun3 const& col, aod::BCsWithTimestamps const&, - aod::FemtoFullTracks const& tracks) + soa::Filtered const& tracks) { // get magnetic field for run - getMagneticFieldTesla(col.bc_as()); + auto bc = col.bc_as(); + getMagneticFieldTesla(bc); + const auto ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), mRunNumber, "ZNC hadronic") * 1.e-3; // fetch IR + // fill the tables - fillCollisionsCentRun3(col, tracks); - fillTracks(tracks); + const auto colcheck = fillCollisionsCentRun3(col); + if (colcheck) { + fillCollisionsCentRun3ColExtra(col, ir); + fillTracks(tracks); + } + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackCentRun3Data, "Provide experimental data for Run 3 with centrality for track track", false); + + void processTrackCentRun3DataMC(aod::FemtoFullCollisionCentRun3MC const& col, + aod::BCsWithTimestamps const&, + soa::Join const& tracks, + aod::McCollisions const&, + aod::McParticles const&) + { + // get magnetic field for run + auto bc = col.bc_as(); + getMagneticFieldTesla(bc); + const auto ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), mRunNumber, "ZNC hadronic") * 1.e-3; // fetch IR + + // fill the tables + const auto colcheck = fillCollisionsCentRun3(col); + if (colcheck) { + fillCollisionsCentRun3ColExtra(col, ir); + fillTracks(tracks); + } + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackCentRun3DataMC, "Provide MC data for track analysis", false); + + void processV0CentRun3Data(aod::FemtoFullCollisionCentRun3 const& col, + aod::BCsWithTimestamps const&, + soa::Filtered const& tracks, + aod::V0Datas const& fullV0s) + { + // get magnetic field for run + auto bc = col.bc_as(); + getMagneticFieldTesla(bc); + const auto ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), mRunNumber, "ZNC hadronic") * 1.e-3; // fetch IR + + // fill the tables + const auto colcheck = fillCollisionsCentRun3(col); + if (colcheck) { + fillCollisionsCentRun3ColExtra(col, ir); + fillTracks(tracks); + fillV0(col, fullV0s, tracks); + } + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processV0CentRun3Data, "Provide experimental data for Run 3 with centrality for track track", false); + + void processCascadeCentRun3Data(aod::FemtoFullCollisionCentRun3 const& col, + aod::BCsWithTimestamps const&, + soa::Filtered const& tracks, + aod::CascDatas const& fullCascades) + { + // get magnetic field for run + auto bc = col.bc_as(); + getMagneticFieldTesla(bc); + const auto ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), mRunNumber, "ZNC hadronic") * 1.e-3; // fetch IR + + // fill the tables + const auto colcheck = fillCollisionsCentRun3(col); + if (colcheck) { + fillCollisionsCentRun3ColExtra(col, ir); + fillTracks(tracks); + fillCascade(col, fullCascades, tracks); + } } - PROCESS_SWITCH(femtoUniverseProducerTask, processTrackCentRun3Data, "Provide experimental data for Run 3 with centrality for track track", false); + PROCESS_SWITCH(FemtoUniverseProducerTask, processCascadeCentRun3Data, "Provide experimental data for Run 3 with centrality for track track", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; return workflow; } diff --git a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTaskV0Only.cxx b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTaskV0Only.cxx index f2edc136e3d..cbb9e02b81a 100644 --- a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTaskV0Only.cxx +++ b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTaskV0Only.cxx @@ -14,6 +14,8 @@ /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch #include +#include + #include "Common/Core/trackUtilities.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" @@ -36,7 +38,7 @@ #include "TMath.h" using namespace o2; -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; using namespace o2::framework; using namespace o2::framework::expressions; @@ -77,7 +79,7 @@ int getRowDaughters(int daughID, T const& vecID) struct femtoUniverseProducerTaskV0Only { - Produces outputCollision; + Produces outputCollision; Produces outputParts; Produces outputDebugParts; @@ -109,60 +111,60 @@ struct femtoUniverseProducerTaskV0Only { /// \todo Labeled array (see Track-Track task) Configurable> ConfV0Sign{ - FemtoUniverseV0Selection::getSelectionName(femtoUniverseV0Selection::kV0Sign, + FemtoUniverseV0Selection::getSelectionName(femto_universe_v0_selection::kV0Sign, "ConfV0"), std::vector{-1, 1}, - FemtoUniverseV0Selection::getSelectionHelper(femtoUniverseV0Selection::kV0Sign, + FemtoUniverseV0Selection::getSelectionHelper(femto_universe_v0_selection::kV0Sign, "V0 selection: ")}; Configurable> ConfV0PtMin{ - FemtoUniverseV0Selection::getSelectionName(femtoUniverseV0Selection::kV0pTMin, + FemtoUniverseV0Selection::getSelectionName(femto_universe_v0_selection::kV0pTMin, "ConfV0"), std::vector{0.3f}, - FemtoUniverseV0Selection::getSelectionHelper(femtoUniverseV0Selection::kV0pTMin, + FemtoUniverseV0Selection::getSelectionHelper(femto_universe_v0_selection::kV0pTMin, "V0 selection: ")}; Configurable> ConfV0PtMax{ - FemtoUniverseV0Selection::getSelectionName(femtoUniverseV0Selection::kV0pTMax, + FemtoUniverseV0Selection::getSelectionName(femto_universe_v0_selection::kV0pTMax, "ConfV0"), std::vector{6.f}, - FemtoUniverseV0Selection::getSelectionHelper(femtoUniverseV0Selection::kV0pTMax, + FemtoUniverseV0Selection::getSelectionHelper(femto_universe_v0_selection::kV0pTMax, "V0 selection: ")}; Configurable> ConfV0EtaMax{ - FemtoUniverseV0Selection::getSelectionName(femtoUniverseV0Selection::kV0etaMax, + FemtoUniverseV0Selection::getSelectionName(femto_universe_v0_selection::kV0etaMax, "ConfV0"), std::vector{6.f}, - FemtoUniverseV0Selection::getSelectionHelper(femtoUniverseV0Selection::kV0etaMax, + FemtoUniverseV0Selection::getSelectionHelper(femto_universe_v0_selection::kV0etaMax, "V0 selection: ")}; Configurable> ConfDCAV0DaughMax{ FemtoUniverseV0Selection::getSelectionName( - femtoUniverseV0Selection::kV0DCADaughMax, "ConfV0"), + femto_universe_v0_selection::kV0DCADaughMax, "ConfV0"), std::vector{1.5f}, FemtoUniverseV0Selection::getSelectionHelper( - femtoUniverseV0Selection::kV0DCADaughMax, "V0 selection: ")}; + femto_universe_v0_selection::kV0DCADaughMax, "V0 selection: ")}; Configurable> ConfCPAV0Min{ - FemtoUniverseV0Selection::getSelectionName(femtoUniverseV0Selection::kV0CPAMin, + FemtoUniverseV0Selection::getSelectionName(femto_universe_v0_selection::kV0CPAMin, "ConfV0"), std::vector{0.99f}, FemtoUniverseV0Selection::getSelectionHelper( - femtoUniverseV0Selection::kV0CPAMin, "V0 selection: ")}; + femto_universe_v0_selection::kV0CPAMin, "V0 selection: ")}; Configurable> V0TranRadV0Min{ FemtoUniverseV0Selection::getSelectionName( - femtoUniverseV0Selection::kV0TranRadMin, "ConfV0"), + femto_universe_v0_selection::kV0TranRadMin, "ConfV0"), std::vector{0.2f}, FemtoUniverseV0Selection::getSelectionHelper( - femtoUniverseV0Selection::kV0TranRadMin, "V0 selection: ")}; + femto_universe_v0_selection::kV0TranRadMin, "V0 selection: ")}; Configurable> V0TranRadV0Max{ FemtoUniverseV0Selection::getSelectionName( - femtoUniverseV0Selection::kV0TranRadMax, "ConfV0"), + femto_universe_v0_selection::kV0TranRadMax, "ConfV0"), std::vector{100.f}, FemtoUniverseV0Selection::getSelectionHelper( - femtoUniverseV0Selection::kV0TranRadMax, "V0 selection: ")}; + femto_universe_v0_selection::kV0TranRadMax, "V0 selection: ")}; Configurable> V0DecVtxMax{ FemtoUniverseV0Selection::getSelectionName( - femtoUniverseV0Selection::kV0DecVtxMax, "ConfV0"), + femto_universe_v0_selection::kV0DecVtxMax, "ConfV0"), std::vector{100.f}, FemtoUniverseV0Selection::getSelectionHelper( - femtoUniverseV0Selection::kV0DecVtxMax, "V0 selection: ")}; + femto_universe_v0_selection::kV0DecVtxMax, "V0 selection: ")}; Configurable> ConfV0DaughCharge{ "ConfV0DaughCharge", std::vector{-1, 1}, "V0 Daugh sel: Charge"}; @@ -223,67 +225,67 @@ struct femtoUniverseProducerTaskV0Only { /// \todo fix how to pass array to setSelection, getRow() passing a /// different type! // v0Cuts.setSelection(ConfV0Selection->getRow(0), - // femtoUniverseV0Selection::kDecVtxMax, femtoUniverseSelection::kAbsUpperLimit); + // femto_universe_v0_selection::kDecVtxMax, femto_universe_selection::kAbsUpperLimit); if (ConfStoreV0) { - v0Cuts.setSelection(ConfV0Sign, femtoUniverseV0Selection::kV0Sign, - femtoUniverseSelection::kEqual); - v0Cuts.setSelection(ConfV0PtMin, femtoUniverseV0Selection::kV0pTMin, - femtoUniverseSelection::kLowerLimit); - v0Cuts.setSelection(ConfV0PtMax, femtoUniverseV0Selection::kV0pTMax, - femtoUniverseSelection::kUpperLimit); - v0Cuts.setSelection(ConfV0EtaMax, femtoUniverseV0Selection::kV0etaMax, - femtoUniverseSelection::kUpperLimit); + v0Cuts.setSelection(ConfV0Sign, femto_universe_v0_selection::kV0Sign, + femto_universe_selection::kEqual); + v0Cuts.setSelection(ConfV0PtMin, femto_universe_v0_selection::kV0pTMin, + femto_universe_selection::kLowerLimit); + v0Cuts.setSelection(ConfV0PtMax, femto_universe_v0_selection::kV0pTMax, + femto_universe_selection::kUpperLimit); + v0Cuts.setSelection(ConfV0EtaMax, femto_universe_v0_selection::kV0etaMax, + femto_universe_selection::kUpperLimit); v0Cuts.setSelection(ConfDCAV0DaughMax, - femtoUniverseV0Selection::kV0DCADaughMax, - femtoUniverseSelection::kUpperLimit); - v0Cuts.setSelection(ConfCPAV0Min, femtoUniverseV0Selection::kV0CPAMin, - femtoUniverseSelection::kLowerLimit); - - v0Cuts.setChildCuts(femtoUniverseV0Selection::kPosTrack, ConfV0DaughCharge, - femtoUniverseTrackSelection::kSign, - femtoUniverseSelection::kEqual); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kPosTrack, ConfDaughEta, - femtoUniverseTrackSelection::kEtaMax, - femtoUniverseSelection::kAbsUpperLimit); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kPosTrack, + femto_universe_v0_selection::kV0DCADaughMax, + femto_universe_selection::kUpperLimit); + v0Cuts.setSelection(ConfCPAV0Min, femto_universe_v0_selection::kV0CPAMin, + femto_universe_selection::kLowerLimit); + + v0Cuts.setChildCuts(femto_universe_v0_selection::kPosTrack, ConfV0DaughCharge, + femto_universe_track_selection::kSign, + femto_universe_selection::kEqual); + v0Cuts.setChildCuts(femto_universe_v0_selection::kPosTrack, ConfDaughEta, + femto_universe_track_selection::kEtaMax, + femto_universe_selection::kAbsUpperLimit); + v0Cuts.setChildCuts(femto_universe_v0_selection::kPosTrack, ConfV0DaughTPCnclsMin, - femtoUniverseTrackSelection::kTPCnClsMin, - femtoUniverseSelection::kLowerLimit); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kPosTrack, ConfV0DaughDCAMin, - femtoUniverseTrackSelection::kDCAMin, - femtoUniverseSelection::kAbsLowerLimit); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kPosTrack, + femto_universe_track_selection::kTPCnClsMin, + femto_universe_selection::kLowerLimit); + v0Cuts.setChildCuts(femto_universe_v0_selection::kPosTrack, ConfV0DaughDCAMin, + femto_universe_track_selection::kDCAMin, + femto_universe_selection::kAbsLowerLimit); + v0Cuts.setChildCuts(femto_universe_v0_selection::kPosTrack, ConfV0DaughPIDnSigmaMax, - femtoUniverseTrackSelection::kPIDnSigmaMax, - femtoUniverseSelection::kAbsUpperLimit); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kNegTrack, ConfV0DaughCharge, - femtoUniverseTrackSelection::kSign, - femtoUniverseSelection::kEqual); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kNegTrack, ConfDaughEta, - femtoUniverseTrackSelection::kEtaMax, - femtoUniverseSelection::kAbsUpperLimit); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kNegTrack, + femto_universe_track_selection::kPIDnSigmaMax, + femto_universe_selection::kAbsUpperLimit); + v0Cuts.setChildCuts(femto_universe_v0_selection::kNegTrack, ConfV0DaughCharge, + femto_universe_track_selection::kSign, + femto_universe_selection::kEqual); + v0Cuts.setChildCuts(femto_universe_v0_selection::kNegTrack, ConfDaughEta, + femto_universe_track_selection::kEtaMax, + femto_universe_selection::kAbsUpperLimit); + v0Cuts.setChildCuts(femto_universe_v0_selection::kNegTrack, ConfV0DaughTPCnclsMin, - femtoUniverseTrackSelection::kTPCnClsMin, - femtoUniverseSelection::kLowerLimit); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kNegTrack, ConfV0DaughDCAMin, - femtoUniverseTrackSelection::kDCAMin, - femtoUniverseSelection::kAbsLowerLimit); - v0Cuts.setChildCuts(femtoUniverseV0Selection::kNegTrack, + femto_universe_track_selection::kTPCnClsMin, + femto_universe_selection::kLowerLimit); + v0Cuts.setChildCuts(femto_universe_v0_selection::kNegTrack, ConfV0DaughDCAMin, + femto_universe_track_selection::kDCAMin, + femto_universe_selection::kAbsLowerLimit); + v0Cuts.setChildCuts(femto_universe_v0_selection::kNegTrack, ConfV0DaughPIDnSigmaMax, - femtoUniverseTrackSelection::kPIDnSigmaMax, - femtoUniverseSelection::kAbsUpperLimit); - v0Cuts.setChildPIDSpecies(femtoUniverseV0Selection::kPosTrack, + femto_universe_track_selection::kPIDnSigmaMax, + femto_universe_selection::kAbsUpperLimit); + v0Cuts.setChildPIDSpecies(femto_universe_v0_selection::kPosTrack, ConfV0DaughTPIDspecies); - v0Cuts.setChildPIDSpecies(femtoUniverseV0Selection::kNegTrack, + v0Cuts.setChildPIDSpecies(femto_universe_v0_selection::kNegTrack, ConfV0DaughTPIDspecies); v0Cuts.init(&qaRegistry); + aod::femtouniverseparticle::CutContainerType>(&qaRegistry); v0Cuts.setInvMassLimits(ConfInvMassLowLimit, ConfInvMassUpLimit); - v0Cuts.setChildRejectNotPropagatedTracks(femtoUniverseV0Selection::kPosTrack, + v0Cuts.setChildRejectNotPropagatedTracks(femto_universe_v0_selection::kPosTrack, ConfRejectNotPropagatedTracks); - v0Cuts.setChildRejectNotPropagatedTracks(femtoUniverseV0Selection::kNegTrack, + v0Cuts.setChildRejectNotPropagatedTracks(femto_universe_v0_selection::kNegTrack, ConfRejectNotPropagatedTracks); if (ConfRejectKaons) { v0Cuts.setKaonInvMassLimits(ConfInvKaonMassLowLimit, @@ -419,15 +421,15 @@ struct femtoUniverseProducerTaskV0Only { aod::femtouniverseparticle::ParticleType::kV0Child>( col, v0, postrack, negtrack); ///\todo fill QA also for daughters auto cutContainerV0 = - v0Cuts.getCutContainer( + v0Cuts.getCutContainer( col, v0, postrack, negtrack); if ((cutContainerV0.at( - femtoUniverseV0Selection::V0ContainerPosition::kV0) > 0) && + femto_universe_v0_selection::V0ContainerPosition::kV0) > 0) && (cutContainerV0.at( - femtoUniverseV0Selection::V0ContainerPosition::kPosCuts) > 0) && + femto_universe_v0_selection::V0ContainerPosition::kPosCuts) > 0) && (cutContainerV0.at( - femtoUniverseV0Selection::V0ContainerPosition::kNegCuts) > 0)) { + femto_universe_v0_selection::V0ContainerPosition::kNegCuts) > 0)) { int postrackID = v0.posTrackId(); int rowInPrimaryTrackTablePos = -1; rowInPrimaryTrackTablePos = getRowDaughters(postrackID, tmpIDtrack); @@ -437,9 +439,9 @@ struct femtoUniverseProducerTaskV0Only { v0.positiveeta(), v0.positivephi(), aod::femtouniverseparticle::ParticleType::kV0Child, cutContainerV0.at( - femtoUniverseV0Selection::V0ContainerPosition::kPosCuts), + femto_universe_v0_selection::V0ContainerPosition::kPosCuts), cutContainerV0.at( - femtoUniverseV0Selection::V0ContainerPosition::kPosPID), + femto_universe_v0_selection::V0ContainerPosition::kPosPID), 0., childIDs, 0, 0); const int rowOfPosTrack = outputParts.lastIndex(); int negtrackID = v0.negTrackId(); @@ -451,16 +453,16 @@ struct femtoUniverseProducerTaskV0Only { v0.negativeeta(), v0.negativephi(), aod::femtouniverseparticle::ParticleType::kV0Child, cutContainerV0.at( - femtoUniverseV0Selection::V0ContainerPosition::kNegCuts), + femto_universe_v0_selection::V0ContainerPosition::kNegCuts), cutContainerV0.at( - femtoUniverseV0Selection::V0ContainerPosition::kNegPID), + femto_universe_v0_selection::V0ContainerPosition::kNegPID), 0., childIDs, 0, 0); const int rowOfNegTrack = outputParts.lastIndex(); std::vector indexChildID = {rowOfPosTrack, rowOfNegTrack}; outputParts(outputCollision.lastIndex(), v0.pt(), v0.eta(), v0.phi(), aod::femtouniverseparticle::ParticleType::kV0, cutContainerV0.at( - femtoUniverseV0Selection::V0ContainerPosition::kV0), + femto_universe_v0_selection::V0ContainerPosition::kV0), 0, v0.v0cosPA(), indexChildID, v0.mLambda(), v0.mAntiLambda()); if (ConfDebugOutput) { @@ -468,7 +470,7 @@ struct femtoUniverseProducerTaskV0Only { postrack.sign(), (uint8_t)postrack.tpcNClsFound(), postrack.tpcNClsFindable(), (uint8_t)postrack.tpcNClsCrossedRows(), - postrack.tpcNClsShared(), postrack.tpcInnerParam(), + postrack.tpcNClsShared(), postrack.tpcFractionSharedCls(), postrack.tpcInnerParam(), postrack.itsNCls(), postrack.itsNClsInnerBarrel(), postrack.dcaXY(), postrack.dcaZ(), postrack.tpcSignal(), postrack.tpcNSigmaStoreEl(), postrack.tpcNSigmaStorePi(), @@ -482,7 +484,7 @@ struct femtoUniverseProducerTaskV0Only { negtrack.sign(), (uint8_t)negtrack.tpcNClsFound(), negtrack.tpcNClsFindable(), (uint8_t)negtrack.tpcNClsCrossedRows(), - negtrack.tpcNClsShared(), negtrack.tpcInnerParam(), + negtrack.tpcNClsShared(), negtrack.tpcFractionSharedCls(), negtrack.tpcInnerParam(), negtrack.itsNCls(), negtrack.itsNClsInnerBarrel(), negtrack.dcaXY(), negtrack.dcaZ(), negtrack.tpcSignal(), negtrack.tpcNSigmaStoreEl(), negtrack.tpcNSigmaStorePi(), @@ -492,7 +494,7 @@ struct femtoUniverseProducerTaskV0Only { negtrack.tofNSigmaStorePr(), negtrack.tofNSigmaStoreDe(), -999., -999., -999., -999., -999., -999.); // QA for negative daughter - outputDebugParts(-999., -999., -999., -999., -999., -999., -999., + outputDebugParts(-999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., v0.dcaV0daughters(), v0.v0radius(), v0.x(), v0.y(), diff --git a/PWGCF/FemtoUniverse/Tasks/CMakeLists.txt b/PWGCF/FemtoUniverse/Tasks/CMakeLists.txt index bc459fcb16e..0a4682a7f7a 100644 --- a/PWGCF/FemtoUniverse/Tasks/CMakeLists.txt +++ b/PWGCF/FemtoUniverse/Tasks/CMakeLists.txt @@ -29,11 +29,21 @@ o2physics_add_dpl_workflow(femtouniverse-pair-track-track-mult-kt-extended PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(femtouniverse-pair-track-nucleus + SOURCES femtoUniversePairTaskTrackNucleus.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(femtouniverse-pair-track-track-threedrelmom-mult-kt-extended SOURCES femtoUniversePairTaskTrackTrack3DMultKtExtended.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(o2-analysis-cf-femtouniverse-pair-track-track-spherhar-mult-kt-extended + SOURCES femtoUniversePairTaskTrackTrackSpherHarMultKtExtended.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(femtouniverse-debug-track SOURCES femtoUniverseDebugTrack.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore @@ -44,6 +54,11 @@ o2physics_add_dpl_workflow(femtouniverse-pair-track-v0-extended PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(femtouniverse-pair-track-cascade-extended + SOURCES femtoUniversePairTaskTrackCascadeExtended.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(femtouniverse-pair-track-d0 SOURCES femtoUniversePairTaskTrackD0.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore @@ -74,10 +89,12 @@ o2physics_add_dpl_workflow(femtouniverse-efficiency-task PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_executable(femtouniverse-cutculator - SOURCES femtoUniverseCutCulator.cxx +o2physics_add_dpl_workflow(femtouniverse-efficiency-base + SOURCES femtoUniverseEfficiencyBase.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) - - +o2physics_add_executable(femtouniverse-cutculator + SOURCES femtoUniverseCutCulator.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) \ No newline at end of file diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniverseCutCulator.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniverseCutCulator.cxx index a13c35fa3e3..45edb854cc2 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniverseCutCulator.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniverseCutCulator.cxx @@ -22,7 +22,7 @@ #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; /// The function takes the path to the dpl-config.json as a argument and the /// does a Q&A session for the user to find the appropriate selection criteria @@ -55,8 +55,8 @@ int main(int /*argc*/, char* argv[]) return 2; } /// \todo factor out the pid here - /// cut.setTrackSelection(femtoUniverseTrackSelection::kPIDnSigmaMax, - /// femtoUniverseSelection::kAbsUpperLimit, "ConfTrk"); + /// cut.setTrackSelection(femto_universe_track_selection::kPIDnSigmaMax, + /// femto_universe_selection::kAbsUpperLimit, "ConfTrk"); std::cout << "Do you want to manually select cuts or create systematic " "variations(M/V)? >"; diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniverseDebugTrack.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniverseDebugTrack.cxx index 04bc95eb5c9..0e07e4f4b03 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniverseDebugTrack.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniverseDebugTrack.cxx @@ -24,12 +24,12 @@ #include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" using namespace o2; -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; @@ -53,7 +53,7 @@ struct femtoUniverseDebugTrack { Configurable ConfIsTrackIdentified{"ConfIsTrackIdentified", true, "Enable PID for the track"}; Configurable ConfIsMC{"ConfIsMC", false, "Enable additional Histogramms in the case of a MonteCarlo Run"}; Configurable ConfTrackChoicePartOne{"ConfTrackChoicePartOne", 1, "Type of particle (track1): {0:Proton, 1:Pion, 2:Kaon}"}; - Configurable ConfTrackSign{"ConfTrackSign", 1, "Track sign"}; + Configurable ConfTrackSign{"ConfTrackSign", 1, "Track sign"}; } trackonefilter; struct : o2::framework::ConfigurableGroup { @@ -223,14 +223,14 @@ struct femtoUniverseDebugTrack { /// Porduce QA plots for sigle track selection in FemtoUniverse framework template - void FillDebugHistos(o2::aod::FDCollision& col, PartitionType& groupPartsOne) + void FillDebugHistos(o2::aod::FdCollision& col, PartitionType& groupPartsOne) { eventHisto.fillQA(col); for (auto& part : groupPartsOne) { // if (part.p() > ConfCutTable->get("MaxP") || part.pt() > ConfCutTable->get("MaxPt")) { // continue; // } - // if (!isFullPIDSelected(part.pidcut(), part.p(), ConfCutTable->get("PIDthr"), vPIDPartOne, ConfNspecies, kNsigma, ConfCutTable->get("nSigmaTPC"), ConfCutTable->get("nSigmaTPCTOF"))) { + // if (!isFullPIDSelected(part.pidCut(), part.p(), ConfCutTable->get("PIDthr"), vPIDPartOne, ConfNspecies, kNsigma, ConfCutTable->get("nSigmaTPC"), ConfCutTable->get("nSigmaTPCTOF"))) { // continue; // } if (trackonefilter.ConfIsTrackIdentified) { @@ -245,7 +245,7 @@ struct femtoUniverseDebugTrack { /// process function when runnning over data/ Monte Carlo reconstructed only /// \param col subscribe to FemtoUniverseCollision table /// \param parts subscribe to FemtoUniverseParticles table - void processData(o2::aod::FDCollision& col, FemtoFullParticles&) + void processData(o2::aod::FdCollision& col, FemtoFullParticles&) { auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); FillDebugHistos(col, groupPartsOne); @@ -257,7 +257,7 @@ struct femtoUniverseDebugTrack { /// \param col subscribe to FemtoUniverseCollision table /// \param parts subscribe to the joined table of FemtoUniverseParticles and FemtoUniverseMCLabels table /// \param FemtoDramMCParticles subscribe to the table containing the Monte Carlo Truth information - void processMC(o2::aod::FDCollision& col, FemtoFullParticlesMC&, o2::aod::FDMCParticles&) + void processMC(o2::aod::FdCollision& col, FemtoFullParticlesMC&, o2::aod::FdMCParticles&) { auto groupPartsOne = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); FillDebugHistos(col, groupPartsOne); diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniverseDebugV0.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniverseDebugV0.cxx index fc987815989..219c43472dd 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniverseDebugV0.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniverseDebugV0.cxx @@ -29,10 +29,10 @@ #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" using namespace o2; -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; @@ -81,7 +81,7 @@ struct femtoUniverseDebugV0 { } /// Porduce QA plots for V0 selection in FemtoUniverse framework - void process(o2::aod::FDCollision const& col, FemtoFullParticles const& parts) + void process(o2::aod::FdCollision const& col, FemtoFullParticles const& parts) { auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); eventHisto.fillQA(col); @@ -98,8 +98,8 @@ struct femtoUniverseDebugV0 { // check cuts on V0 children if ((posChild.partType() == uint8_t(aod::femtouniverseparticle::ParticleType::kV0Child) && (posChild.cut() & ConfCutChildPos) == ConfCutChildPos) && (negChild.partType() == uint8_t(aod::femtouniverseparticle::ParticleType::kV0Child) && (negChild.cut() & ConfCutChildNeg) == ConfCutChildNeg) && - isFullPIDSelected(posChild.pidcut(), posChild.p(), 999.f, ConfChildPosIndex.value, ConfChildnSpecies.value, ConfChildPIDnSigmaMax.value, ConfChildPosPidnSigmaMax.value, 1.f) && - isFullPIDSelected(negChild.pidcut(), negChild.p(), 999.f, ConfChildNegIndex.value, ConfChildnSpecies.value, ConfChildPIDnSigmaMax.value, ConfChildNegPidnSigmaMax.value, 1.f)) { + isFullPIDSelected(posChild.pidCut(), posChild.p(), 999.f, ConfChildPosIndex.value, ConfChildnSpecies.value, ConfChildPIDnSigmaMax.value, ConfChildPosPidnSigmaMax.value, 1.f) && + isFullPIDSelected(negChild.pidCut(), negChild.p(), 999.f, ConfChildNegIndex.value, ConfChildnSpecies.value, ConfChildPIDnSigmaMax.value, ConfChildNegPidnSigmaMax.value, 1.f)) { V0Histos.fillQA(part); posChildHistos.fillQA(posChild); negChildHistos.fillQA(negChild); diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniverseEfficiencyBase.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniverseEfficiencyBase.cxx new file mode 100644 index 00000000000..cad94a05c60 --- /dev/null +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniverseEfficiencyBase.cxx @@ -0,0 +1,653 @@ +// Copyright 2019-2022 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 femtoUniverseEfficiencyBase.cxx +/// \brief Tasks that reads the track tables used for the pairing and builds pairs of two tracks +/// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch +/// \author Alicja Płachta, WUT Warsaw, alicja.plachta@cern.ch + +#include +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" + +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" + +using namespace o2; +using namespace o2::analysis::femto_universe; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct femtoUniverseEfficiencyBase { + SliceCache cache; + using FemtoFullParticles = soa::Join; + Preslice perCol = aod::femtouniverseparticle::fdCollisionId; + + Configurable ConfIsDebug{"ConfIsDebug", true, "Enable debug histograms"}; + + // Collisions + Configurable ConfZVertex{"ConfZVertex", 10.f, "Event sel: Maximum z-Vertex (cm)"}; + + Filter collisionFilter = (nabs(aod::collision::posZ) < ConfZVertex); + using FilteredFDCollisions = soa::Filtered; + using FilteredFDCollision = FilteredFDCollisions::iterator; + + /// Particle selection part + /// Configurables for both particles + ConfigurableAxis ConfTempFitVarpTBins{"ConfTempFitVarpTBins", {20, 0.5, 4.05}, "Binning of the pT in the pT vs. TempFitVar plot"}; + ConfigurableAxis ConfTempFitVarPDGBins{"ConfTempFitVarPDGBins", {6000, -2300, 2300}, "Binning of the PDG code in the pT vs. TempFitVar plot"}; + ConfigurableAxis ConfTempFitVarCPABins{"ConfTempFitVarCPABins", {1000, 0.9, 1}, "Binning of the pointing angle cosinus in the pT vs. TempFitVar plot"}; + ConfigurableAxis ConfTempFitVarDCABins{"ConfTempFitVarDCABins", {1000, -5, 5}, "Binning of the PDG code in the pT vs. TempFitVar plot"}; + + struct : o2::framework::ConfigurableGroup { + Configurable ConfEtaMax{"ConfEtaMax", 0.8f, "Higher limit for |Eta| (the same for both particles)"}; + Configurable ConfMomProton{"ConfMomProton", 0.75, "Momentum threshold for proton identification using TOF"}; + Configurable ConfMomPion{"ConfMomPion", 0.75, "Momentum threshold for pion identification using TOF"}; + Configurable ConfNsigmaCombinedProton{"ConfNsigmaCombinedProton", 3.0, "TPC and TOF Proton Sigma (combined) for momentum > ConfMomProton"}; + Configurable ConfNsigmaTPCProton{"ConfNsigmaTPCProton", 3.0, "TPC Proton Sigma for momentum < ConfMomProton"}; + Configurable ConfNsigmaCombinedPion{"ConfNsigmaCombinedPion", 3.0, "TPC and TOF Pion Sigma (combined) for momentum > ConfMomPion"}; + Configurable ConfNsigmaTPCPion{"ConfNsigmaTPCPion", 3.0, "TPC Pion Sigma for momentum < ConfMomPion"}; + } ConfBothTracks; + + /// Lambda cuts + Configurable ConfV0InvMassLowLimit{"ConfV0InvV0MassLowLimit", 1.10, "Lower limit of the V0 invariant mass"}; + Configurable ConfV0InvMassUpLimit{"ConfV0InvV0MassUpLimit", 1.13, "Upper limit of the V0 invariant mass"}; + + /// Kaon configurable + Configurable IsKaonRun2{"IsKaonRun2", false, "Enable kaon selection used in Run2"}; // to check consistency with Run2 results + + /// Deuteron configurables + struct : o2::framework::ConfigurableGroup { + Configurable ConfNsigmaTPCDe{"ConfNsigmaTPCDe", 2.0f, "TPC Deuteron Sigma for momentum < ConfTOFpMinDe"}; + Configurable ConfNsigmaTOFDe{"ConfNsigmaTOFDe", 2.0f, "TOF Deuteron Sigma"}; + Configurable ConfTOFpMinDe{"ConfTOFpMinDe", 0.5f, "Min. momentum for deuterons for which TOF is required for PID"}; + Configurable ConfPLowDe{"ConfPLowDe", 0.8f, "Lower limit for momentum for deuterons"}; + Configurable ConfPHighDe{"ConfPHighDe", 1.8f, "Higher limit for momentum for deuterons"}; + } deuteronconfigs; + + /// Particle 1 + Configurable ConfPDGCodePartOne{"ConfPDGCodePartOne", 2212, "Particle 1 - PDG code"}; + Configurable ConfParticleTypePartOne{"ConfParticleTypePartOne", aod::femtouniverseparticle::ParticleType::kTrack, "Particle 1 - particle type: 0 - track, 2 - V0, 6 - phi"}; + Configurable ConfNoPDGPartOne{"ConfNoPDGPartOne", false, "0: selecting part one by PDG, 1: no PID selection"}; + Configurable ConfPtLowPart1{"ConfPtLowPart1", 0.2, "Lower limit for Pt for the first particle"}; + Configurable ConfPtHighPart1{"ConfPtHighPart1", 2.5, "Higher limit for Pt for the first particle"}; + Configurable ConfChargePart1{"ConfChargePart1", 1, "Charge of the first particle"}; + + /// Partition for particle 1 + Partition partsOneMCGen = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && aod::femtouniverseparticle::pt < ConfPtHighPart1 && aod::femtouniverseparticle::pt > ConfPtLowPart1&& nabs(aod::femtouniverseparticle::eta) < ConfBothTracks.ConfEtaMax; + + Partition partsTrackOneMCReco = aod::femtouniverseparticle::pt < ConfPtHighPart1 && aod::femtouniverseparticle::pt > ConfPtLowPart1&& nabs(aod::femtouniverseparticle::eta) < ConfBothTracks.ConfEtaMax; + + /// Histogramming for particle 1 + FemtoUniverseParticleHisto trackHistoPartOneGen; + FemtoUniverseParticleHisto trackHistoPartOneRec; + FemtoUniverseParticleHisto trackHistoV0OneRec; + FemtoUniverseParticleHisto trackHistoV0OneChildPosRec; + FemtoUniverseParticleHisto trackHistoV0OneChildNegRec; + + /// Particle 2 + Configurable ConfIsSame{"ConfIsSame", false, "Pairs of the same particle"}; + Configurable ConfPDGCodePartTwo{"ConfPDGCodePartTwo", 333, "Particle 2 - PDG code"}; + Configurable ConfParticleTypePartTwo{"ConfParticleTypePartTwo", aod::femtouniverseparticle::ParticleType::kTrack, "Particle 2 - particle type: 0 - track, 2 - V0, 6 - phi"}; + Configurable ConfNoPDGPartTwo{"ConfNoPDGPartTwo", false, "0: selecting part two by PDG, 1: no PID selection"}; + Configurable ConfPtLowPart2{"ConfPtLowPart2", 0.2, "Lower limit for Pt for the second particle"}; + Configurable ConfPtHighPart2{"ConfPtHighPart2", 2.5, "Higher limit for Pt for the second particle"}; + Configurable ConfChargePart2{"ConfChargePart2", 1, "Charge of the second particle"}; + + /// Partition for particle 2 + Partition partsTwoGen = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && aod::femtouniverseparticle::pt < ConfPtHighPart2 && aod::femtouniverseparticle::pt > ConfPtLowPart2&& nabs(aod::femtouniverseparticle::eta) < ConfBothTracks.ConfEtaMax; + + Partition partsTrackTwoMCReco = aod::femtouniverseparticle::pt < ConfPtHighPart2 && aod::femtouniverseparticle::pt > ConfPtLowPart2&& nabs(aod::femtouniverseparticle::eta) < ConfBothTracks.ConfEtaMax; + + /// Histogramming for particle 2 + FemtoUniverseParticleHisto trackHistoPartTwoGen; + FemtoUniverseParticleHisto trackHistoPartTwoRec; + FemtoUniverseParticleHisto trackHistoV0TwoRec; + FemtoUniverseParticleHisto trackHistoV0TwoChildPosRec; + FemtoUniverseParticleHisto trackHistoV0TwoChildNegRec; + + /// Histogramming for Event + FemtoUniverseEventHisto eventHisto; + + FemtoUniverseTrackSelection trackCuts; + + /// Histogram output + HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryPDG{"PDGHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry registryMCOrigin{"MCOriginHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + + void init(InitContext&) + { + + eventHisto.init(&qaRegistry); + trackHistoPartOneGen.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarPDGBins, 0, ConfPDGCodePartOne, false); + trackHistoPartOneRec.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarDCABins, 0, ConfPDGCodePartOne, ConfIsDebug); + registryMCOrigin.add("part1/hPt", " ;#it{p}_{T} (GeV/c); Entries", {HistType::kTH1F, {{240, 0, 6}}}); + registryPDG.add("part1/PDGvspT", "PDG;#it{p}_{T} (GeV/c); PDG", {HistType::kTH2F, {{500, 0, 5}, {16001, -8000.5, 8000.5}}}); + if (ConfParticleTypePartOne == uint8_t(aod::femtouniverseparticle::ParticleType::kV0)) { + trackHistoV0OneRec.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarCPABins, 0, ConfPDGCodePartOne, ConfIsDebug); + trackHistoV0OneChildPosRec.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarDCABins, 0, 0, ConfIsDebug, "posChildV0_1"); + trackHistoV0OneChildNegRec.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarDCABins, 0, 0, ConfIsDebug, "negChildV0_1"); + registryPDG.add("part1/dpositive/PDGvspT", "PDG;#it{p}_{T} (GeV/c); PDG", {HistType::kTH2F, {{500, 0, 5}, {16001, -8000.5, 8000.5}}}); + registryPDG.add("part1/dnegative/PDGvspT", "PDG;#it{p}_{T} (GeV/c); PDG", {HistType::kTH2F, {{500, 0, 5}, {16001, -8000.5, 8000.5}}}); + } + + registryPDG.add("part2/PDGvspT", "PDG;#it{p}_{T} (GeV/c); PDG", {HistType::kTH2F, {{500, 0, 5}, {16001, -8000.5, 8000.5}}}); + if (!ConfIsSame) { + trackHistoPartTwoGen.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarPDGBins, 0, ConfPDGCodePartTwo, false); + trackHistoPartTwoRec.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarDCABins, 0, ConfPDGCodePartTwo, ConfIsDebug); + registryMCOrigin.add("part2/hPt", " ;#it{p}_{T} (GeV/c); Entries", {HistType::kTH1F, {{240, 0, 6}}}); + if (ConfParticleTypePartTwo == uint8_t(aod::femtouniverseparticle::ParticleType::kV0)) { + trackHistoV0TwoRec.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarCPABins, 0, ConfPDGCodePartTwo, ConfIsDebug); + trackHistoV0TwoChildPosRec.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarDCABins, 0, 0, ConfIsDebug, "posChildV0_2"); + trackHistoV0TwoChildNegRec.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarDCABins, 0, 0, ConfIsDebug, "negChildV0_2"); + registryPDG.add("part2/dpositive/PDGvspT", "PDG;#it{p}_{T} (GeV/c); PDG", {HistType::kTH2F, {{500, 0, 5}, {16001, -8000.5, 8000.5}}}); + registryPDG.add("part2/dnegative/PDGvspT", "PDG;#it{p}_{T} (GeV/c); PDG", {HistType::kTH2F, {{500, 0, 5}, {16001, -8000.5, 8000.5}}}); + } + } + } + + bool IsProtonNSigma(float mom, float nsigmaTPCPr, float nsigmaTOFPr) // previous version from: https://github.com/alisw/AliPhysics/blob/master/PWGCF/FEMTOSCOPY/AliFemtoUser/AliFemtoMJTrackCut.cxx + { + if (mom < ConfBothTracks.ConfMomProton) { + if (TMath::Abs(nsigmaTPCPr) < ConfBothTracks.ConfNsigmaTPCProton) { + return true; + } else { + return false; + } + } else { + if (TMath::Hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfBothTracks.ConfNsigmaCombinedProton) { + return true; + } else { + return false; + } + } + return false; + } + + bool IsKaonNSigma(float mom, float nsigmaTPCK, float nsigmaTOFK) + { + if (IsKaonRun2 == true) { + if (mom < 0.4) { + return TMath::Abs(nsigmaTPCK) < 2; + } else if (mom > 0.4 && mom < 0.45) { + return TMath::Abs(nsigmaTPCK) < 1; + } else if (mom > 0.45 && mom < 0.8) { + return (TMath::Abs(nsigmaTPCK) < 3 && TMath::Abs(nsigmaTOFK) < 2); + } else if (mom > 0.8 && mom < 1.5) { + return (TMath::Abs(nsigmaTPCK) < 3 && TMath::Abs(nsigmaTOFK) < 1.5); + } else { + return false; + } + } else { + if (mom < 0.3) { // 0.0-0.3 + if (TMath::Abs(nsigmaTPCK) < 3.0) { + return true; + } else { + return false; + } + } else if (mom < 0.45) { // 0.30 - 0.45 + if (TMath::Abs(nsigmaTPCK) < 2.0) { + return true; + } else { + return false; + } + } else if (mom < 0.55) { // 0.45-0.55 + if (TMath::Abs(nsigmaTPCK) < 1.0) { + return true; + } else { + return false; + } + } else if (mom < 1.5) { // 0.55-1.5 (now we use TPC and TOF) + if ((TMath::Abs(nsigmaTOFK) < 3.0) && (TMath::Abs(nsigmaTPCK) < 3.0)) { + { + return true; + } + } else { + return false; + } + } else if (mom > 1.5) { // 1.5 - + if ((TMath::Abs(nsigmaTOFK) < 2.0) && (TMath::Abs(nsigmaTPCK) < 3.0)) { + return true; + } else { + return false; + } + } else { + return false; + } + } + } + + bool IsPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) + { + if (mom < ConfBothTracks.ConfMomPion) { + if (TMath::Abs(nsigmaTPCPi) < ConfBothTracks.ConfNsigmaTPCPion) { + return true; + } else { + return false; + } + } else { + if (TMath::Hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfBothTracks.ConfNsigmaCombinedPion) { + return true; + } else { + return false; + } + } + return false; + } + + bool IsDeuteronNSigma(float mom, float nsigmaTPCDe, float nsigmaTOFDe) + { + if (mom > deuteronconfigs.ConfPLowDe && mom < deuteronconfigs.ConfPHighDe) { + if (mom < deuteronconfigs.ConfTOFpMinDe) { + return (TMath::Abs(nsigmaTPCDe) < deuteronconfigs.ConfNsigmaTPCDe); + } else { + return (TMath::Abs(nsigmaTOFDe) < deuteronconfigs.ConfNsigmaTOFDe && (TMath::Abs(nsigmaTPCDe) < deuteronconfigs.ConfNsigmaTPCDe)); + } + } else { + return false; + } + } + + bool IsParticleNSigma(int pdgCode, float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK, float nsigmaTPCDe, float nsigmaTOFDe) + { + switch (pdgCode) { + case 2212: // Proton + case -2212: // anty Proton + return IsProtonNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); + break; + case 211: // Pion + case -211: // Pion- + return IsPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); + break; + case 321: // Kaon+ + case -321: // Kaon- + return IsKaonNSigma(mom, nsigmaTPCK, nsigmaTOFK); + break; + case 1000010020: // Deuteron + case -1000010020: // Antideuteron + return IsDeuteronNSigma(mom, nsigmaTPCDe, nsigmaTOFDe); + break; + default: + return false; + } + } + + bool invMLambda(float invMassLambda, float invMassAntiLambda) + { + if ((invMassLambda < ConfV0InvMassLowLimit || invMassLambda > ConfV0InvMassUpLimit) && (invMassAntiLambda < ConfV0InvMassLowLimit || invMassAntiLambda > ConfV0InvMassUpLimit)) { + return false; + } + return true; + } + + template + void fillCollision(CollisionType col) + { + eventHisto.fillQA(col); + } + + /// This function processes the same event and takes care of all the histogramming + /// @tparam PartitionType + /// @tparam isMC: enables Monte Carlo truth specific histograms + /// @param grouppartsOneMCGen partition for the first particle passed by the process function + /// @param grouppartsTwoMCGen partition for the second particle passed by the process function + template + void doMCGen(PartitionType grouppartsOneMCGen, PartitionType grouppartsTwoMCGen) + { + /// Histogramming same event + for (auto& part : grouppartsOneMCGen) { + if (!ConfNoPDGPartOne && part.tempFitVar() != ConfPDGCodePartOne) { + continue; + } + trackHistoPartOneGen.fillQA(part); + } + + if (!ConfIsSame) { + for (auto& part : grouppartsTwoMCGen) { + if (!ConfNoPDGPartTwo && part.tempFitVar() != ConfPDGCodePartTwo) { + continue; + } + trackHistoPartTwoGen.fillQA(part); + } + } + } + + /// This function processes the same event and takes care of all the histogramming + /// @tparam PartitionType + /// @tparam isMC: enables Monte Carlo truth specific histograms + /// @tparam isDebug: enables debug histograms + /// @param grouppartsOneMCRec partition for the first particle passed by the process function + /// @param grouppartsTwoMCRec partition for the second particle passed by the process function + template + void doMCRecTrackTrack(PartitionType grouppartsOneMCRec, PartitionType grouppartsTwoMCRec) + { + /// Histogramming same event + for (auto& part : grouppartsOneMCRec) { + if (part.partType() != ConfParticleTypePartOne || part.sign() != ConfChargePart1 || !IsParticleNSigma(ConfPDGCodePartOne, part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon), trackCuts.getNsigmaTPC(part, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(part, o2::track::PID::Deuteron))) { + continue; + } + trackHistoPartOneRec.fillQA(part); + + if (!part.has_fdMCParticle()) { + continue; + } + const auto mcParticle = part.fdMCParticle(); + + registryPDG.fill(HIST("part1/PDGvspT"), part.pt(), mcParticle.pdgMCTruth()); + registryMCOrigin.fill(HIST("part1/hPt"), mcParticle.pt()); + } + + if (!ConfIsSame) { + for (auto& part : grouppartsTwoMCRec) { + if (part.partType() != ConfParticleTypePartTwo || part.sign() != ConfChargePart2 || !IsParticleNSigma(ConfPDGCodePartTwo, part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon), trackCuts.getNsigmaTPC(part, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(part, o2::track::PID::Deuteron))) { + continue; + } + + trackHistoPartTwoRec.fillQA(part); + + if (!part.has_fdMCParticle()) { + continue; + } + const auto mcParticle = part.fdMCParticle(); + + registryPDG.fill(HIST("part2/PDGvspT"), part.pt(), mcParticle.pdgMCTruth()); + registryMCOrigin.fill(HIST("part2/hPt"), mcParticle.pt()); + } + } + } + + /// This function processes the same event and takes care of all the histogramming + /// @tparam PartitionType + /// @tparam isMC: enables Monte Carlo truth specific histograms + /// @tparam isDebug: enables debug histograms + /// @param grouppartsOneMCRec partition for the first particle passed by the process function + /// @param grouppartsTwoMCRec partition for the second particle passed by the process function + template + void doMCRecTrackPhi(PartitionType grouppartsOneMCRec, PartitionType grouppartsTwoMCRec) + { // part1 is track and part2 is Phi + + for (auto& part : grouppartsOneMCRec) { + if (part.partType() != ConfParticleTypePartOne || part.sign() != ConfChargePart1 || !IsParticleNSigma(ConfPDGCodePartOne, part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon), trackCuts.getNsigmaTPC(part, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(part, o2::track::PID::Deuteron))) { + continue; + } + trackHistoPartOneRec.fillQA(part); + + if (!part.has_fdMCParticle()) { + continue; + } + const auto mcParticle = part.fdMCParticle(); + + registryPDG.fill(HIST("part1/PDGvspT"), part.pt(), mcParticle.pdgMCTruth()); + registryMCOrigin.fill(HIST("part1/hPt"), mcParticle.pt()); + } + + if (!ConfIsSame) { + for (auto& part : grouppartsTwoMCRec) { + if (part.partType() != ConfParticleTypePartTwo || part.sign() != ConfChargePart2) { + continue; + } + + trackHistoPartTwoRec.fillQA(part); + + if (!part.has_fdMCParticle()) { + continue; + } + const auto mcParticle = part.fdMCParticle(); + + registryPDG.fill(HIST("part2/PDGvspT"), part.pt(), mcParticle.pdgMCTruth()); + registryMCOrigin.fill(HIST("part2/hPt"), mcParticle.pt()); + } + } + } + + /// This function processes the same event and takes care of all the histogramming + /// @tparam PartitionType + /// @tparam ParticlesType + /// @tparam isMC: enables Monte Carlo truth specific histograms + /// @tparam isDebug: enables debug histograms + /// @param grouppartsOneMCRec partition for the first particle passed by the process function + /// @param grouppartsTwoMCRec partition for the second particle passed by the process function + /// @param parts all tracks + template + void doMCRecV0V0(PartitionType grouppartsOneMCRec, PartitionType grouppartsTwoMCRec, ParticlesType parts) + { + /// Histogramming same event + for (auto& part : grouppartsOneMCRec) { + + if (part.partType() != ConfParticleTypePartOne || !invMLambda(part.mLambda(), part.mAntiLambda())) { + continue; + } + + const auto& posChild = parts.iteratorAt(part.index() - 2); + const auto& negChild = parts.iteratorAt(part.index() - 1); + + if (ConfPDGCodePartOne > 0 && (!IsProtonNSigma(0, trackCuts.getNsigmaTPC(posChild, o2::track::PID::Proton), trackCuts.getNsigmaTOF(posChild, o2::track::PID::Proton)) || !IsPionNSigma(0, trackCuts.getNsigmaTPC(negChild, o2::track::PID::Pion), trackCuts.getNsigmaTOF(negChild, o2::track::PID::Pion)))) { // give momentum as 0 to only check TPC nSigma, not combined with TOF + continue; + } + if (ConfPDGCodePartOne < 0 && (!IsProtonNSigma(0, trackCuts.getNsigmaTPC(negChild, o2::track::PID::Proton), trackCuts.getNsigmaTOF(negChild, o2::track::PID::Proton)) || !IsPionNSigma(0, trackCuts.getNsigmaTPC(posChild, o2::track::PID::Pion), trackCuts.getNsigmaTOF(posChild, o2::track::PID::Pion)))) { // give momentum as 0 to only check TPC nSigma, not combined with TOF + continue; + } + + trackHistoV0OneRec.fillQA(part); + trackHistoV0OneChildPosRec.fillQABase(posChild, HIST("posChildV0_1")); + trackHistoV0OneChildNegRec.fillQABase(negChild, HIST("negChildV0_1")); + + if (!posChild.has_fdMCParticle() || !negChild.has_fdMCParticle() || !part.has_fdMCParticle()) { + continue; + } + const auto mcParticle = part.fdMCParticle(); + const auto mcPosChild = posChild.fdMCParticle(); + const auto mcNegChild = negChild.fdMCParticle(); + + registryPDG.fill(HIST("part1/PDGvspT"), part.pt(), mcParticle.pdgMCTruth()); + registryPDG.fill(HIST("part1/dpositive/PDGvspT"), part.pt(), mcPosChild.pdgMCTruth()); + registryPDG.fill(HIST("part1/dnegative/PDGvspT"), part.pt(), mcNegChild.pdgMCTruth()); + registryMCOrigin.fill(HIST("part1/hPt"), mcParticle.pt()); + } + + if (!ConfIsSame) { + for (auto& part : grouppartsTwoMCRec) { + + if (part.partType() != ConfParticleTypePartTwo || !invMLambda(part.mLambda(), part.mAntiLambda())) { + continue; + } + + const auto& posChild = parts.iteratorAt(part.index() - 2); + const auto& negChild = parts.iteratorAt(part.index() - 1); + + if (ConfPDGCodePartTwo > 0 && (!IsProtonNSigma(0, trackCuts.getNsigmaTPC(posChild, o2::track::PID::Proton), trackCuts.getNsigmaTOF(posChild, o2::track::PID::Proton)) || !IsPionNSigma(0, trackCuts.getNsigmaTPC(negChild, o2::track::PID::Pion), trackCuts.getNsigmaTOF(negChild, o2::track::PID::Pion)))) { // give momentum as 0 to only check TPC nSigma, not combined with TOF + continue; + } + if (ConfPDGCodePartTwo < 0 && (!IsProtonNSigma(0, trackCuts.getNsigmaTPC(negChild, o2::track::PID::Proton), trackCuts.getNsigmaTOF(negChild, o2::track::PID::Proton)) || !IsPionNSigma(0, trackCuts.getNsigmaTPC(posChild, o2::track::PID::Pion), trackCuts.getNsigmaTOF(posChild, o2::track::PID::Pion)))) { // give momentum as 0 to only check TPC nSigma, not combined with TOF + continue; + } + + trackHistoV0TwoRec.fillQA(part); + trackHistoV0TwoChildPosRec.fillQABase(posChild, HIST("posChildV0_2")); + trackHistoV0TwoChildNegRec.fillQABase(negChild, HIST("negChildV0_2")); + + if (!posChild.has_fdMCParticle() || !negChild.has_fdMCParticle() || !part.has_fdMCParticle()) { + continue; + } + const auto mcParticle = part.fdMCParticle(); + const auto mcPosChild = posChild.fdMCParticle(); + const auto mcNegChild = negChild.fdMCParticle(); + + registryPDG.fill(HIST("part2/PDGvspT"), part.pt(), mcParticle.pdgMCTruth()); + registryPDG.fill(HIST("part2/dpositive/PDGvspT"), part.pt(), mcPosChild.pdgMCTruth()); + registryPDG.fill(HIST("part2/dnegative/PDGvspT"), part.pt(), mcNegChild.pdgMCTruth()); + registryMCOrigin.fill(HIST("part2/hPt"), mcParticle.pt()); + } + } + } + + /// This function processes the same event and takes care of all the histogramming + /// @tparam PartitionType + /// @tparam ParticlesType + /// @tparam isMC: enables Monte Carlo truth specific histograms + /// @tparam isDebug: enables debug histograms + /// @param grouppartsOneMCRec partition for the first particle passed by the process function + /// @param grouppartsTwoMCRec partition for the second particle passed by the process function + /// @param parts all tracks + template + void doMCRecTrackV0(PartitionType grouppartsOneMCRec, PartitionType grouppartsTwoMCRec, ParticlesType const& parts) + { // part1 is track and part2 is V0 + + /// Histogramming same event + for (auto& part : grouppartsOneMCRec) { + if (part.partType() != ConfParticleTypePartOne || part.sign() != ConfChargePart1 || !IsParticleNSigma(ConfPDGCodePartOne, part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon), trackCuts.getNsigmaTPC(part, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(part, o2::track::PID::Deuteron))) { + continue; + } + + trackHistoPartOneRec.fillQA(part); + if (!part.has_fdMCParticle()) + continue; + + const auto mcParticle = part.fdMCParticle(); + registryPDG.fill(HIST("part1/PDGvspT"), part.pt(), mcParticle.pdgMCTruth()); + registryMCOrigin.fill(HIST("part1/hPt"), mcParticle.pt()); + } + + if (!ConfIsSame) { + for (auto& part : grouppartsTwoMCRec) { + + if (part.partType() != ConfParticleTypePartTwo || !invMLambda(part.mLambda(), part.mAntiLambda())) { + continue; + } + const auto& posChild = parts.iteratorAt(part.index() - 2); + const auto& negChild = parts.iteratorAt(part.index() - 1); + + if (ConfPDGCodePartTwo > 0 && (!IsProtonNSigma(0, trackCuts.getNsigmaTPC(posChild, o2::track::PID::Proton), trackCuts.getNsigmaTOF(posChild, o2::track::PID::Proton)) || !IsPionNSigma(0, trackCuts.getNsigmaTPC(negChild, o2::track::PID::Pion), trackCuts.getNsigmaTOF(negChild, o2::track::PID::Pion)))) { // give momentum as 0 to only check TPC nSigma, not combined with TOF + continue; + } + if (ConfPDGCodePartTwo < 0 && (!IsProtonNSigma(0, trackCuts.getNsigmaTPC(negChild, o2::track::PID::Proton), trackCuts.getNsigmaTOF(negChild, o2::track::PID::Proton)) || !IsPionNSigma(0, trackCuts.getNsigmaTPC(posChild, o2::track::PID::Pion), trackCuts.getNsigmaTOF(posChild, o2::track::PID::Pion)))) { // give momentum as 0 to only check TPC nSigma, not combined with TOF + continue; + } + + trackHistoV0TwoRec.fillQA(part); + trackHistoV0TwoChildPosRec.fillQABase(posChild, HIST("posChildV0_2")); + trackHistoV0TwoChildNegRec.fillQABase(negChild, HIST("negChildV0_2")); + + if (!posChild.has_fdMCParticle() || !negChild.has_fdMCParticle() || !part.has_fdMCParticle()) { + continue; + } + const auto mcParticle = part.fdMCParticle(); + const auto mcPosChild = posChild.fdMCParticle(); + const auto mcNegChild = negChild.fdMCParticle(); + + registryPDG.fill(HIST("part2/PDGvspT"), part.pt(), mcParticle.pdgMCTruth()); + registryPDG.fill(HIST("part2/dpositive/PDGvspT"), part.pt(), mcPosChild.pdgMCTruth()); + registryPDG.fill(HIST("part2/dnegative/PDGvspT"), part.pt(), mcNegChild.pdgMCTruth()); + registryMCOrigin.fill(HIST("part2/hPt"), mcParticle.pt()); + } + } + } + + /// process function for to call doMCRecTrackTrack with Data + /// \param col subscribe to the collision table (Data) + void processTrackTrack(FilteredFDCollision& col, + FemtoFullParticles&, aod::FdMCParticles const&) + { + fillCollision(col); + // MCGen + auto thegrouppartsOneMCGen = partsOneMCGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegrouppartsTwoMCGen = partsTwoGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + doMCGen(thegrouppartsOneMCGen, thegrouppartsTwoMCGen); + // MCRec + auto thegroupPartsTrackOneRec = partsTrackOneMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegroupPartsTrackTwoRec = partsTrackTwoMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + if (ConfIsDebug) { + doMCRecTrackTrack(thegroupPartsTrackOneRec, thegroupPartsTrackTwoRec); + } else { + doMCRecTrackTrack(thegroupPartsTrackOneRec, thegroupPartsTrackTwoRec); + } + } + PROCESS_SWITCH(femtoUniverseEfficiencyBase, processTrackTrack, "Enable processing track-track efficiency task", true); + + /// process function for to call doMCRecTrackPhi with Data + /// \param col subscribe to the collision table (Data) + void processTrackPhi(FilteredFDCollision& col, + FemtoFullParticles&, aod::FdMCParticles const&) + { + fillCollision(col); + // MCGen + auto thegrouppartsOneMCGen = partsOneMCGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegrouppartsTwoMCGen = partsTwoGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + doMCGen(thegrouppartsOneMCGen, thegrouppartsTwoMCGen); + // MCRec + auto thegroupPartsTrackOneRec = partsTrackOneMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegroupPartsTrackTwoRec = partsTrackTwoMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + if (ConfIsDebug) { + doMCRecTrackPhi(thegroupPartsTrackOneRec, thegroupPartsTrackTwoRec); + } else { + doMCRecTrackPhi(thegroupPartsTrackOneRec, thegroupPartsTrackTwoRec); + } + } + PROCESS_SWITCH(femtoUniverseEfficiencyBase, processTrackPhi, "Enable processing track-phi efficiency task", false); + + /// process function for to call doMCRecV0V0 with Data + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoUniverseParticleTable + void processV0V0(FilteredFDCollision& col, + FemtoFullParticles& parts, aod::FdMCParticles const&) + { + fillCollision(col); + // MCGen + auto thegrouppartsOneMCGen = partsOneMCGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegrouppartsTwoMCGen = partsTwoGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + doMCGen(thegrouppartsOneMCGen, thegrouppartsTwoMCGen); + + // MCRec + auto thegroupPartsTrackOneRec = partsTrackOneMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegroupPartsTrackTwoRec = partsTrackTwoMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + if (ConfIsDebug) { + doMCRecV0V0(thegroupPartsTrackOneRec, thegroupPartsTrackTwoRec, parts); + } else { + doMCRecV0V0(thegroupPartsTrackOneRec, thegroupPartsTrackTwoRec, parts); + } + } + PROCESS_SWITCH(femtoUniverseEfficiencyBase, processV0V0, "Enable processing V0-V0 efficiency task", false); + + /// process function for to call doMCRecTrackV0 with Data + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoUniverseParticleTable + void processTrackV0(FilteredFDCollision& col, + FemtoFullParticles& parts, aod::FdMCParticles const&) + { + fillCollision(col); + // MCGen + auto thegrouppartsOneMCGen = partsOneMCGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegrouppartsTwoMCGen = partsTwoGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + doMCGen(thegrouppartsOneMCGen, thegrouppartsTwoMCGen); + // MCRec + auto thegroupPartsTrackOneRec = partsTrackOneMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegroupPartsTrackTwoRec = partsTrackTwoMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + if (ConfIsDebug) { + doMCRecTrackV0(thegroupPartsTrackOneRec, thegroupPartsTrackTwoRec, parts); + } else { + doMCRecTrackV0(thegroupPartsTrackOneRec, thegroupPartsTrackTwoRec, parts); + } + } + PROCESS_SWITCH(femtoUniverseEfficiencyBase, processTrackV0, "Enable processing track-V0 efficiency task", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniverseEfficiencyTask.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniverseEfficiencyTask.cxx index 497bbdb503f..fcd9c56d452 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniverseEfficiencyTask.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniverseEfficiencyTask.cxx @@ -35,7 +35,7 @@ #include "TPDGCode.h" using namespace o2; -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; using namespace o2::track; using namespace o2::framework; using namespace o2::framework::expressions; @@ -73,7 +73,7 @@ struct femtoUniverseEficiencyTask { Configurable cfgDcaXY{"cfgDcaXY", 2.4, "Value of max. DCA_XY"}; Configurable cfgDcaZ{"cfgDcaZ", 3.2, "Value of max. DCA_Z"}; /// Event cuts - o2::analysis::femtoUniverse::FemtoUniverseCollisionSelection colCuts; + o2::analysis::femto_universe::FemtoUniverseCollisionSelection colCuts; Configurable ConfEvtZvtx{"ConfEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; Configurable ConfEvtTriggerCheck{"ConfEvtTriggerCheck", true, "Evt sel: check for trigger"}; Configurable ConfEvtTriggerSel{"ConfEvtTriggerSel", kINT7, "Evt sel: trigger"}; @@ -185,6 +185,7 @@ struct femtoUniverseEficiencyTask { registryMCtruth.add("plus/MCtruthPi", "MC truth pions;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); registryMCtruth.add("plus/MCtruthKa", "MC truth kaons;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); registryMCtruth.add("plus/MCtruthPr", "MC truth protons;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCtruth.add("plus/MCtruthPhi", "MC truth Phi mesons;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); registryMCtruth.add("minus/MCtruthPi", "MC truth pions;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); registryMCtruth.add("minus/MCtruthKa", "MC truth kaons;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); @@ -193,6 +194,7 @@ struct femtoUniverseEficiencyTask { registryMCtruth.add("plus/MCtruthPiPt", "MC truth pions;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); registryMCtruth.add("plus/MCtruthKaPt", "MC truth kaons;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); registryMCtruth.add("plus/MCtruthPrPt", "MC truth protons;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + registryMCtruth.add("plus/MCtruthPhiPt", "MC truth Phi mesons;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); registryMCtruth.add("plus/MCtruthAllPt", "MC truth all;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); registryMCtruth.add("minus/MCtruthPiPt", "MC truth pions;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); @@ -378,7 +380,7 @@ struct femtoUniverseEficiencyTask { using BigTracksMC = soa::Join; Preslice perCollisionID = aod::track::collisionId; - void processMCTruth(aod::McCollision const& collision, soa::SmallGroups> const& collisions, aod::McParticles const& mcparticles, soa::Filtered const& tracks) + void processMCTruth(aod::McCollision const& /*collision*/, soa::SmallGroups> const& collisions, aod::McParticles const& mcparticles, soa::Filtered const& tracks) { // Loop over reconstructed collisions corresponding to MC collision for (auto& collision : collisions) { @@ -527,6 +529,10 @@ struct femtoUniverseEficiencyTask { registryMCtruth.fill(HIST("plus/MCtruthPr"), mcparticle.pt(), mcparticle.eta()); registryMCtruth.fill(HIST("plus/MCtruthPrPt"), mcparticle.pt()); } + if (mcparticle.pdgCode() == 333) { + registryMCtruth.fill(HIST("plus/MCtruthPhi"), mcparticle.pt(), mcparticle.eta()); + registryMCtruth.fill(HIST("plus/MCtruthPhiPt"), mcparticle.pt()); + } if (pdgParticle->Charge() < 0) { registryMCtruth.fill(HIST("minus/MCtruthAllPt"), mcparticle.pt()); diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniverseHashTask.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniverseHashTask.cxx index 1fef7a97ac2..7f30fda061f 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniverseHashTask.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniverseHashTask.cxx @@ -9,9 +9,8 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file femtoUniverseReaderTask.cxx +/// \file femtoUniverseHashTask.cxx /// \brief Tasks that reads the track tables used for the pairing -/// This task is common for all femto analyses /// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch @@ -24,34 +23,34 @@ using namespace o2; using namespace o2::framework; -struct femtoUniversePairHashTask { +struct FemtoUniverseHashTask { - Configurable> CfgVtxBins{"CfgVtxBins", std::vector{-10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - Configurable> CfgMultBins{"CfgMultBins", std::vector{0.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; - // Configurable> CfgMultBins{"CfgMultBins", std::vector{0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; + Configurable> cfgVtxBins{"cfgVtxBins", std::vector{-10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + Configurable> cfgMultBins{"cfgMultBins", std::vector{0.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; + // Configurable> cfgMultBins{"cfgMultBins", std::vector{0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; - std::vector CastCfgVtxBins, CastCfgMultBins; + std::vector castCfgVtxBins, castCfgMultBins; - Produces hashes; + Produces hashes; void init(InitContext&) { /// here the Configurables are passed to std::vectors - CastCfgVtxBins = (std::vector)CfgVtxBins; - CastCfgMultBins = (std::vector)CfgMultBins; + castCfgVtxBins = (std::vector)cfgVtxBins; + castCfgMultBins = (std::vector)cfgMultBins; } - void process(o2::aod::FDCollision const& col) + void process(o2::aod::FdCollision const& col) { /// the hash of the collision is computed and written to table - hashes(eventmixing::getMixingBin(CastCfgVtxBins, CastCfgMultBins, col.posZ(), col.multV0M())); + hashes(eventmixing::getMixingBin(castCfgVtxBins, castCfgMultBins, col.posZ(), col.multV0M())); } }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; return workflow; } diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackCascadeExtended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackCascadeExtended.cxx new file mode 100644 index 00000000000..781ff80ef9f --- /dev/null +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackCascadeExtended.cxx @@ -0,0 +1,763 @@ +// Copyright 2019-2022 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 femtoUniversePairTaskTrackCascadeExtended.cxx +/// \brief Task for cascade correlations and QA +/// \author Barbara Chytla, WUT Warsaw, barbara.chytla@cern.ch +/// \author Shirajum Monira, WUT Warsaw, shirajum.monira@cern.ch + +#include +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" +#include "Framework/O2DatabasePDGPlugin.h" + +using namespace o2; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femto_universe; +using namespace o2::aod::pidutils; + +struct femtoUniversePairTaskTrackCascadeExtended { + + Service pdgMC; + SliceCache cache; + using FemtoFullParticles = soa::Join; + Preslice perCol = aod::femtouniverseparticle::fdCollisionId; + + using FemtoRecoParticles = soa::Join; + Preslice perColReco = aod::femtouniverseparticle::fdCollisionId; + + ConfigurableAxis confChildTempFitVarpTBins{"ConfChildTempFitVarpTBins", {20, 0.5, 4.05}, "V0 child: pT binning of the pT vs. TempFitVar plot"}; + ConfigurableAxis confChildTempFitVarBins{"ConfChildTempFitVarBins", {300, -0.15, 0.15}, "V0 child: binning of the TempFitVar in the pT vs. TempFitVar plot"}; + Configurable confCascInvMassLowLimit{"ConfCascInvMassLowLimit", 1.315, "Lower limit of the Casc invariant mass"}; + Configurable confCascInvMassUpLimit{"ConfCascInvMassUpLimit", 1.325, "Upper limit of the Casc invariant mass"}; + Configurable confCascTranRad{"ConfCascTranRad", 0.5, "Cascade transverse radius"}; + + Configurable confNSigmaTPCPion{"NSigmaTPCPion", 4, "NSigmaTPCPion"}; + Configurable confNSigmaTPCProton{"NSigmaTPCProton", 4, "NSigmaTPCProton"}; + + /// applying narrow cut + Configurable confZVertexCut{"ConfZVertexCut", 10.f, "Event sel: Maximum z-Vertex (cm)"}; + Configurable confEta{"ConfEta", 0.8, "Eta cut for the global track"}; + + // configurations for correlation part + Configurable confTrackChoicePartOne{"ConfTrackChoicePartOne", 0, "0:Proton, 1:Pion, 2:Kaon"}; + Configurable confTrkPDGCodePartOne{"ConfTrkPDGCodePartOne", 2212, "Particle 1 (Track) - PDG code"}; + Configurable confCascType1{"ConfCascType1", 0, "select one of the V0s (Omega = 0, Xi = 1, anti-Omega = 2, anti-Xi = 3) for track-cascade combination"}; + Configurable confCascType2{"ConfCascType2", 0, "select one of the V0s (Omega = 0, Xi = 1, anti-Omega = 2, anti-Xi = 3) for cascade-cascade combination"}; + Configurable confIsCPR{"ConfIsCPR", false, "Close Pair Rejection"}; + Configurable confCPRdeltaPhiCutMax{"ConfCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; + Configurable confCPRdeltaPhiCutMin{"ConfCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMax{"ConfCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMin{"ConfCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; + Configurable confCPRPlotPerRadii{"ConfCPRPlotPerRadii", false, "Plot CPR per radii"}; + Configurable confCPRChosenRadii{"ConfCPRChosenRadii", 0.0, "Delta Eta cut for Close Pair Rejection"}; + Configurable confChargePart1{"ConfChargePart1", 1, "sign of particle 1"}; + Configurable confHPtPart1{"ConfHPtPart1", 4.0f, "higher limit for pt of particle 1"}; + Configurable confLPtPart1{"ConfLPtPart1", 0.5f, "lower limit for pt of particle 1"}; + Configurable confHPtPart2{"ConfHPtPart2", 4.0f, "higher limit for pt of particle 2"}; + Configurable confLPtPart2{"ConfLPtPart2", 0.3f, "lower limit for pt of particle 2"}; + Configurable confmom{"Confmom", 0.75, "momentum threshold for particle identification using TOF"}; + Configurable confNsigmaTPCParticle{"ConfNsigmaTPCParticle", 3.0, "TPC Sigma for particle (track) momentum < Confmom"}; + Configurable confNsigmaCombinedParticle{"ConfNsigmaCombinedParticle", 3.0, "TPC and TOF Sigma (combined) for particle (track) momentum > Confmom"}; + Configurable confNsigmaTPCParticleChild{"ConfNsigmaTPCParticleChild", 3.0, "TPC Sigma for particle (daugh & bach) momentum < Confmom"}; + Configurable confNsigmaTOFParticleChild{"ConfNsigmaTOFParticleChild", 3.0, "TOF Sigma for particle (daugh & bach) momentum > Confmom"}; + + ConfigurableAxis confkstarBins{"ConfkstarBins", {1500, 0., 6.}, "binning kstar"}; + ConfigurableAxis confMultBins{"ConfMultBins", {VARIABLE_WIDTH, 0.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; + ConfigurableAxis confkTBins{"ConfkTBins", {150, 0., 9.}, "binning kT"}; + ConfigurableAxis confmTBins{"ConfmTBins", {225, 0., 7.5}, "binning mT"}; + ConfigurableAxis confmultBins3D{"ConfMultBins3D", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + ConfigurableAxis confmTBins3D{"ConfmTBins3D", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + Configurable confEtaBins{"ConfEtaBins", 29, "Number of eta bins in deta dphi"}; + Configurable confPhiBins{"ConfPhiBins", 29, "Number of phi bins in deta dphi"}; + Configurable confIsMC{"ConfIsMC", false, "Enable additional Histograms in the case of a MonteCarlo Run"}; + Configurable confUse3D{"ConfUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; + Configurable confUseCent{"confUseCent", false, "Use centrality in place of multiplicity"}; + ConfigurableAxis confVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis confTrkTempFitVarpTBins{"ConfTrkTempFitVarpTBins", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; + ConfigurableAxis confTrkTempFitVarBins{"ConfTrkDTempFitVarBins", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; + + Filter collisionFilter = (nabs(aod::collision::posZ) < confZVertexCut); + using FilteredFDCollisions = soa::Filtered; + using FilteredFDCollision = FilteredFDCollisions::iterator; + + /// Partition for particle 1 (track) + Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == confChargePart1) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < confHPtPart1) && (aod::femtouniverseparticle::pt > confLPtPart1); + Partition partsOneMCgen = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < confHPtPart1) && (aod::femtouniverseparticle::pt > confLPtPart1); + Partition partsOneMCreco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == confChargePart1) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < confHPtPart1) && (aod::femtouniverseparticle::pt > confLPtPart1); + + /// Partition for particle 2 (cascade) + Partition partsTwo = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kCascade)) && (aod::femtouniverseparticle::pt < confHPtPart2) && (aod::femtouniverseparticle::pt > confLPtPart2); + Partition partsTwoMCgen = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (aod::femtouniverseparticle::pt < confHPtPart2) && (aod::femtouniverseparticle::pt > confLPtPart2); + Partition partsTwoMCreco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kCascade)) && (aod::femtouniverseparticle::pt < confHPtPart2) && (aod::femtouniverseparticle::pt > confLPtPart2); + + /// Partition for cascades + Partition cascs = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kCascade)); + + /// Histogramming for track particle + FemtoUniverseParticleHisto trackHistoPartOnePos; + FemtoUniverseParticleHisto trackHistoPartOneNeg; + + /// Histogramming for cascade + FemtoUniverseParticleHisto posChildHistos; + FemtoUniverseParticleHisto negChildHistos; + FemtoUniverseParticleHisto bachHistos; + FemtoUniverseParticleHisto cascQAHistos; + + /// Histogramming for Event + FemtoUniverseEventHisto eventHisto; + + FemtoUniverseContainer sameEventCont; + FemtoUniverseContainer mixedEventCont; + FemtoUniversePairCleaner pairCleaner; + FemtoUniversePairCleaner pairCleanerCasc; + FemtoUniverseDetaDphiStar pairCloseRejection; + + HistogramRegistry rXiQA{"xi", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry resultRegistry{"Correlations", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryMCgen{"MCgenHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry registryMCreco{"MCrecoHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + + // Table to select cascade daughters + // Charges: = +--, +--, +-+, +-+ + static constexpr unsigned int CascChildTable[][3] = {{0, 1, 2}, {0, 1, 1}, {1, 0, 2}, {1, 0, 1}}; + + bool invMCascade(float invMassCascade, float invMassAntiCascade) + { + if ((invMassCascade < confCascInvMassLowLimit || invMassCascade > confCascInvMassUpLimit) && (invMassAntiCascade < confCascInvMassLowLimit || invMassAntiCascade > confCascInvMassUpLimit)) { + return false; + } + return true; + } + + bool isNSigmaTPC(float nsigmaTPCParticle) + { + if (std::abs(nsigmaTPCParticle) < confNsigmaTPCParticleChild) { + return true; + } else { + return false; + } + } + + bool isNSigmaTOF(float mom, float nsigmaTOFParticle, float hasTOF) + { + // Cut only on daughter and bachelor tracks, that have TOF signal + if (mom > confmom && hasTOF == 1) { + if (std::abs(nsigmaTOFParticle) < confNsigmaTOFParticleChild) { + return true; + } else { + return false; + } + } else { + return true; + } + } + + bool isNSigmaCombined(float mom, float nsigmaTPCParticle, float nsigmaTOFParticle) + { + if (mom <= confmom) { + return (std::abs(nsigmaTPCParticle) < confNsigmaTPCParticle); + } else { + return (TMath::Hypot(nsigmaTOFParticle, nsigmaTPCParticle) < confNsigmaCombinedParticle); + } + } + + template + bool isParticleTPC(const T& part, int id) + { + const float tpcNSigmas[3] = {unPackInTable(part.tpcNSigmaStorePr()), unPackInTable(part.tpcNSigmaStorePi()), unPackInTable(part.tpcNSigmaStoreKa())}; + + return isNSigmaTPC(tpcNSigmas[id]); + } + + template + bool isParticleTOF(const T& part, int id) + { + const float tofNSigmas[3] = {unPackInTable(part.tofNSigmaStorePr()), unPackInTable(part.tofNSigmaStorePi()), unPackInTable(part.tofNSigmaStoreKa())}; + + return isNSigmaTOF(part.p(), tofNSigmas[id], part.tempFitVar()); + } + + template + bool isParticleCombined(const T& part, int id) + { + const float tpcNSigmas[3] = {unPackInTable(part.tpcNSigmaStorePr()), unPackInTable(part.tpcNSigmaStorePi()), unPackInTable(part.tpcNSigmaStoreKa())}; + const float tofNSigmas[3] = {unPackInTable(part.tofNSigmaStorePr()), unPackInTable(part.tofNSigmaStorePi()), unPackInTable(part.tofNSigmaStoreKa())}; + + return isNSigmaCombined(part.p(), tpcNSigmas[id], tofNSigmas[id]); + } + + void init(InitContext const&) + { + // Axes + AxisSpec aXiMassAxis = {200, 1.28f, 1.36f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec ptAxis = {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec etaAxis = {100, -2.0f, 2.0f, "#it{#eta}"}; + AxisSpec phiAxis = {100, 0.0f, 6.0f, "#it{#phi}"}; + AxisSpec aDCADaughAxis = {1000, 0.0f, 2.0f, "DCA (cm)"}; + AxisSpec aCPAAxis = {1000, 0.95f, 1.0f, "#it{cos #theta_{p}}"}; + AxisSpec tranRadAxis = {1000, 0.0f, 100.0f, "#it{r}_{xy} (cm)"}; + AxisSpec aDCAToPVAxis = {1000, -10.0f, 10.0f, "DCA to PV (cm)"}; + + // Histograms + rXiQA.add("hMassXi", "hMassXi", {HistType::kTH1F, {aXiMassAxis}}); + rXiQA.add("hMassXiSelected", "hMassXiSelected", {HistType::kTH1F, {aXiMassAxis}}); + rXiQA.add("hPtXi", "hPtXi", {HistType::kTH1F, {{ptAxis}}}); + rXiQA.add("hEtaXi", "hEtaXi", {HistType::kTH1F, {{etaAxis}}}); + rXiQA.add("hPhiXi", "hPhiXi", {HistType::kTH1F, {{phiAxis}}}); + rXiQA.add("hDCAV0Daughters", "hDCAV0Daughters", {HistType::kTH1F, {aDCADaughAxis}}); + rXiQA.add("hV0CosPA", "hV0CosPA", {HistType::kTH1F, {aCPAAxis}}); + rXiQA.add("hV0TranRad", "hV0TranRad", {HistType::kTH1F, {tranRadAxis}}); + rXiQA.add("hDCACascDaughters", "hDCACascDaughters", {HistType::kTH1F, {aDCADaughAxis}}); + rXiQA.add("hCascCosPA", "hCascCosPA", {HistType::kTH1F, {aCPAAxis}}); + rXiQA.add("hCascTranRad", "hCascTranRad", {HistType::kTH1F, {tranRadAxis}}); + rXiQA.add("hDcaPostoPV", "hDcaPostoPV", {HistType::kTH1F, {aDCAToPVAxis}}); + rXiQA.add("hDcaNegtoPV", "hDcaNegtoPV", {HistType::kTH1F, {aDCAToPVAxis}}); + rXiQA.add("hDcaBachtoPV", "hDcaBachtoPV", {HistType::kTH1F, {aDCAToPVAxis}}); + rXiQA.add("hDcaV0toPV", "hDcaV0toPV", {HistType::kTH1F, {aDCAToPVAxis}}); + rXiQA.add("hInvMpT", "hInvMpT", kTH2F, {{ptAxis}, {aXiMassAxis}}); + + eventHisto.init(&qaRegistry); + qaRegistry.add("Tracks_pos/nSigmaTPC", "; #it{p} (GeV/#it{c}); n#sigma_{TPC}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Tracks_pos/nSigmaTOF", "; #it{p} (GeV/#it{c}); n#sigma_{TOF}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Tracks_neg/nSigmaTPC", "; #it{p} (GeV/#it{c}); n#sigma_{TPC}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Tracks_neg/nSigmaTOF", "; #it{p} (GeV/#it{c}); n#sigma_{TOF}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + + // MC gen + registryMCgen.add("plus/MCgenCasc", "MC gen cascades;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCgen.add("minus/MCgenCasc", "MC gen cascades;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + + registryMCgen.add("plus/MCgenAllPt", "MC gen all;#it{p}_{T} (GeV/c); #eta", {HistType::kTH1F, {{500, 0, 5}}}); + registryMCgen.add("minus/MCgenAllPt", "MC gen all;#it{p}_{T} (GeV/c); #eta", {HistType::kTH1F, {{500, 0, 5}}}); + + registryMCgen.add("plus/MCgenPr", "MC gen protons;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCgen.add("minus/MCgenPr", "MC gen protons;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + + registryMCgen.add("plus/MCgenPrPt", "MC gen protons;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + registryMCgen.add("minus/MCgenPrPt", "MC gen protons;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + + // MC reco + registryMCreco.add("plus/MCrecoCascade", "MC reco Cascades;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCreco.add("minus/MCrecoCascade", "MC reco Cascades;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + + registryMCreco.add("plus/MCrecoAllPt", "MC reco all;#it{p}_{T} (GeV/c); #eta", {HistType::kTH1F, {{500, 0, 5}}}); + registryMCreco.add("minus/MCrecoAllPt", "MC reco all;#it{p}_{T} (GeV/c); #eta", {HistType::kTH1F, {{500, 0, 5}}}); + + registryMCreco.add("plus/MCrecoPr", "MC reco protons;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCreco.add("minus/MCrecoPr", "MC reco protons;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + + registryMCreco.add("plus/MCrecoPrPt", "MC reco protons;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + registryMCreco.add("minus/MCrecoPrPt", "MC reco protons;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + + trackHistoPartOnePos.init(&qaRegistry, confTrkTempFitVarpTBins, confTrkTempFitVarBins, confIsMC, confTrkPDGCodePartOne); + trackHistoPartOneNeg.init(&qaRegistry, confTrkTempFitVarpTBins, confTrkTempFitVarBins, confIsMC, confTrkPDGCodePartOne); + posChildHistos.init(&qaRegistry, confChildTempFitVarpTBins, confChildTempFitVarBins, false, 0, true); + negChildHistos.init(&qaRegistry, confChildTempFitVarpTBins, confChildTempFitVarBins, false, 0, true); + bachHistos.init(&qaRegistry, confChildTempFitVarpTBins, confChildTempFitVarBins, false, 0, true, "hBachelor"); + cascQAHistos.init(&qaRegistry, confChildTempFitVarpTBins, confChildTempFitVarBins, false, 0, true); + + sameEventCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confmultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); + mixedEventCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confmultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); + pairCleaner.init(&qaRegistry); + if (confIsCPR.value) { + pairCloseRejection.init(&resultRegistry, &qaRegistry, confCPRdeltaPhiCutMin.value, confCPRdeltaPhiCutMax.value, confCPRdeltaEtaCutMin.value, confCPRdeltaEtaCutMax.value, confCPRChosenRadii.value, confCPRPlotPerRadii.value); + } + } + + void processCascades(const FilteredFDCollision& col, const FemtoFullParticles& parts) + { + auto groupCascs = cascs->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + // const int multCol = col.multNtr(); + + for (const auto& casc : groupCascs) { + rXiQA.fill(HIST("hMassXi"), casc.mLambda()); + + // if (!invMCascade(casc.mLambda(), casc.mAntiLambda())) + // continue; + + const auto& posChild = parts.iteratorAt(casc.index() - 3); + const auto& negChild = parts.iteratorAt(casc.index() - 2); + const auto& bachelor = parts.iteratorAt(casc.index() - 1); + + // if (casc.transRadius() < confCascTranRad) + // continue; + // std::cout< confNSigmaTPCProton) { + continue; + } + if (std::abs(negChild.tpcNSigmaPi()) > confNSigmaTPCPion) { + continue; + } + } else { + if (std::abs(negChild.tpcNSigmaPr()) > confNSigmaTPCProton) { + continue; + } + if (std::abs(posChild.tpcNSigmaPi()) > confNSigmaTPCPion) { + continue; + } + } + if (std::abs(bachelor.tpcNSigmaPi()) > confNSigmaTPCPion) { + continue; + } + + rXiQA.fill(HIST("hPtXi"), casc.pt()); + rXiQA.fill(HIST("hEtaXi"), casc.eta()); + rXiQA.fill(HIST("hPhiXi"), casc.phi()); + rXiQA.fill(HIST("hMassXiSelected"), casc.mLambda()); + rXiQA.fill(HIST("hDCAV0Daughters"), casc.dcaV0daughters()); + rXiQA.fill(HIST("hV0CosPA"), casc.cpav0()); + rXiQA.fill(HIST("hV0TranRad"), casc.v0radius()); + rXiQA.fill(HIST("hCascCosPA"), casc.cpaCasc()); + rXiQA.fill(HIST("hDCACascDaughters"), casc.dcacascdaughters()); + rXiQA.fill(HIST("hCascTranRad"), casc.cascradius()); + rXiQA.fill(HIST("hDcaPostoPV"), casc.dcapostopv()); + rXiQA.fill(HIST("hDcaNegtoPV"), casc.dcanegtopv()); + rXiQA.fill(HIST("hDcaBachtoPV"), casc.dcabachtopv()); + rXiQA.fill(HIST("hDcaV0toPV"), casc.dcav0topv()); + rXiQA.fill(HIST("hInvMpT"), casc.pt(), casc.mLambda()); + + posChildHistos.fillQA(posChild); + negChildHistos.fillQA(negChild); + bachHistos.fillQABase(bachelor, HIST("hBachelor")); + } + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processCascades, "Enable processing cascades", false); + /// track - cascade + void processSameEvent(const FilteredFDCollision& col, const FemtoFullParticles& parts) + { + auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + eventHisto.fillQA(col); + + const int multCol = confUseCent ? col.multV0M() : col.multNtr(); + + for (const auto& part : groupPartsTwo) { + if (!invMCascade(part.mLambda(), part.mAntiLambda())) + continue; + + cascQAHistos.fillQA(part); + + const auto& posChild = parts.iteratorAt(part.index() - 3); + const auto& negChild = parts.iteratorAt(part.index() - 2); + const auto& bachelor = parts.iteratorAt(part.index() - 1); + /// Child particles must pass this condition to be selected + if (!isParticleTPC(posChild, CascChildTable[confCascType1][0]) || !isParticleTPC(negChild, CascChildTable[confCascType1][1]) || !isParticleTPC(bachelor, CascChildTable[confCascType1][2])) + continue; + + if (!isParticleTOF(posChild, CascChildTable[confCascType1][0]) || !isParticleTOF(negChild, CascChildTable[confCascType1][1]) || !isParticleTOF(bachelor, CascChildTable[confCascType1][2])) + continue; + + posChildHistos.fillQA(posChild); + negChildHistos.fillQA(negChild); + bachHistos.fillQABase(bachelor, HIST("hBachelor")); + } + + for (const auto& part : groupPartsOne) { + /// PID plot for track particle + const float tpcNSigmas[3] = {unPackInTable(part.tpcNSigmaStorePr()), unPackInTable(part.tpcNSigmaStorePi()), unPackInTable(part.tpcNSigmaStoreKa())}; + const float tofNSigmas[3] = {unPackInTable(part.tofNSigmaStorePr()), unPackInTable(part.tofNSigmaStorePi()), unPackInTable(part.tofNSigmaStoreKa())}; + + if (!isNSigmaCombined(part.p(), tpcNSigmas[confTrackChoicePartOne], tofNSigmas[confTrackChoicePartOne])) + continue; + + if (part.sign() > 0) { + qaRegistry.fill(HIST("Tracks_pos/nSigmaTPC"), part.p(), tpcNSigmas[confTrackChoicePartOne]); + qaRegistry.fill(HIST("Tracks_pos/nSigmaTOF"), part.p(), tofNSigmas[confTrackChoicePartOne]); + trackHistoPartOnePos.fillQA(part); + } else if (part.sign() < 0) { + qaRegistry.fill(HIST("Tracks_neg/nSigmaTPC"), part.p(), tpcNSigmas[confTrackChoicePartOne]); + qaRegistry.fill(HIST("Tracks_neg/nSigmaTOF"), part.p(), tofNSigmas[confTrackChoicePartOne]); + trackHistoPartOneNeg.fillQA(part); + } + } + + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + // Cascade invariant mass cut + if (!invMCascade(p2.mLambda(), p2.mAntiLambda())) + continue; + // PID + if (!isParticleCombined(p1, confTrackChoicePartOne)) + continue; + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + const auto& posChild = parts.iteratorAt(p2.index() - 3); + const auto& negChild = parts.iteratorAt(p2.index() - 2); + const auto& bachelor = parts.iteratorAt(p2.index() - 1); + /// Child particles must pass this condition to be selected + if (!isParticleTPC(posChild, CascChildTable[confCascType1][0]) || !isParticleTPC(negChild, CascChildTable[confCascType1][1]) || !isParticleTPC(bachelor, CascChildTable[confCascType1][2])) + continue; + if (!isParticleTOF(posChild, CascChildTable[confCascType1][0]) || !isParticleTOF(negChild, CascChildTable[confCascType1][1]) || !isParticleTOF(bachelor, CascChildTable[confCascType1][2])) + continue; + + sameEventCont.setPair(p1, p2, multCol, confUse3D, 1.0f); + } + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processSameEvent, "Enable processing same event for track - cascade", false); + /// cascade - cascade + void processSameEventCasc(const FilteredFDCollision& col, const FemtoFullParticles& parts) + { + const auto& magFieldTesla = col.magField(); + + auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + eventHisto.fillQA(col); + + const int multCol = confUseCent ? col.multV0M() : col.multNtr(); + + for (const auto& part : groupPartsTwo) { + if (!invMCascade(part.mLambda(), part.mAntiLambda())) + continue; + + cascQAHistos.fillQA(part); + + const auto& posChild = parts.iteratorAt(part.index() - 3); + const auto& negChild = parts.iteratorAt(part.index() - 2); + const auto& bachelor = parts.iteratorAt(part.index() - 1); + /// Check daughters of first cascade + if (isParticleTPC(posChild, CascChildTable[confCascType1][0]) && isParticleTPC(negChild, CascChildTable[confCascType1][1]) && isParticleTPC(bachelor, CascChildTable[confCascType1][2])) { + + posChildHistos.fillQA(posChild); + negChildHistos.fillQA(negChild); + bachHistos.fillQABase(bachelor, HIST("hBachelor")); + } + /// Check daughters of second cascade + /*if (isParticleTPC(posChild, CascChildTable[confCascType2][0]) && isParticleTPC(negChild, CascChildTable[confCascType2][1]) && isParticleTPC(bachelor, CascChildTable[confCascType2][2])) { + }*/ + } + + auto pairProcessFunc = [&](auto& p1, auto& p2) -> void { + // Cascade invariant mass cut for p1 + if (!invMCascade(p1.mLambda(), p1.mAntiLambda())) + return; + // Cascade invariant mass cut for p2 + if (!invMCascade(p2.mLambda(), p2.mAntiLambda())) + return; + // track cleaning + if (!pairCleanerCasc.isCleanPair(p1, p2, parts)) { + return; + } + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { + return; + } + } + const auto& posChild1 = parts.iteratorAt(p1.index() - 3); + const auto& negChild1 = parts.iteratorAt(p1.index() - 2); + const auto& bachelor1 = parts.iteratorAt(p1.index() - 1); + /// Child particles must pass this condition to be selected + if (!isParticleTPC(posChild1, CascChildTable[confCascType1][0]) || !isParticleTPC(negChild1, CascChildTable[confCascType1][1]) || !isParticleTPC(bachelor1, CascChildTable[confCascType1][2])) + return; + const auto& posChild2 = parts.iteratorAt(p2.index() - 3); + const auto& negChild2 = parts.iteratorAt(p2.index() - 2); + const auto& bachelor2 = parts.iteratorAt(p2.index() - 1); + /// Child particles must pass this condition to be selected + if (!isParticleTPC(posChild2, CascChildTable[confCascType2][0]) || !isParticleTPC(negChild2, CascChildTable[confCascType2][1]) || !isParticleTPC(bachelor2, CascChildTable[confCascType2][2])) + return; + + sameEventCont.setPair(p1, p2, multCol, confUse3D, 1.0f); + }; + if (confCascType1 == confCascType2) { + /// Now build the combinations for identical cascades + for (const auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsTwo, groupPartsTwo))) { + pairProcessFunc(p1, p2); + } + } else { + /// Now build the combinations for non-identical cascades + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsTwo, groupPartsTwo))) { + pairProcessFunc(p1, p2); + } + } + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processSameEventCasc, "Enable processing same event for cascade - cascade", false); + /// track - cascade + void processMixedEvent(const FilteredFDCollisions& cols, const FemtoFullParticles& parts) + { + ColumnBinningPolicy colBinning{{confVtxBins, confMultBins}, true}; + + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + const int multCol = confUseCent ? collision1.multV0M() : collision1.multNtr(); + + auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + continue; + } + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + // Cascade invariant mass cut + if (!invMCascade(p2.mLambda(), p2.mAntiLambda())) + continue; + // PID + if (!isParticleCombined(p1, confTrackChoicePartOne)) + continue; + + const auto& posChild = parts.iteratorAt(p2.index() - 3); + const auto& negChild = parts.iteratorAt(p2.index() - 2); + const auto& bachelor = parts.iteratorAt(p2.index() - 1); + /// Child particles must pass this condition to be selected + if (!isParticleTPC(posChild, CascChildTable[confCascType1][0]) || !isParticleTPC(negChild, CascChildTable[confCascType1][1]) || !isParticleTPC(bachelor, CascChildTable[confCascType1][2])) + continue; + if (!isParticleTOF(posChild, CascChildTable[confCascType1][0]) || !isParticleTOF(negChild, CascChildTable[confCascType1][1]) || !isParticleTOF(bachelor, CascChildTable[confCascType1][2])) + continue; + + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + + mixedEventCont.setPair(p1, p2, multCol, confUse3D, 1.0f); + } + } + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processMixedEvent, "Enable processing mixed event for track - cascade", false); + /// cascade - cascade + void processMixedEventCasc(const FilteredFDCollisions& cols, const FemtoFullParticles& parts) + { + ColumnBinningPolicy colBinning{{confVtxBins, confMultBins}, true}; + + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + const int multCol = confUseCent ? collision1.multV0M() : collision1.multNtr(); + + auto groupPartsOne = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + continue; + } + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + // Cascade invariant mass cut for p1 + if (!invMCascade(p1.mLambda(), p1.mAntiLambda())) + continue; + // Cascade invariant mass cut for p2 + if (!invMCascade(p2.mLambda(), p2.mAntiLambda())) + continue; + + const auto& posChild1 = parts.iteratorAt(p1.index() - 3); + const auto& negChild1 = parts.iteratorAt(p1.index() - 2); + const auto& bachelor1 = parts.iteratorAt(p1.index() - 1); + /// Child particles must pass this condition to be selected + if (!isParticleTPC(posChild1, CascChildTable[confCascType1][0]) || !isParticleTPC(negChild1, CascChildTable[confCascType1][1]) || !isParticleTPC(bachelor1, CascChildTable[confCascType1][2])) + return; + const auto& posChild2 = parts.iteratorAt(p2.index() - 3); + const auto& negChild2 = parts.iteratorAt(p2.index() - 2); + const auto& bachelor2 = parts.iteratorAt(p2.index() - 1); + /// Child particles must pass this condition to be selected + if (!isParticleTPC(posChild2, CascChildTable[confCascType2][0]) || !isParticleTPC(negChild2, CascChildTable[confCascType2][1]) || !isParticleTPC(bachelor2, CascChildTable[confCascType2][2])) + return; + // track cleaning + if (!pairCleanerCasc.isCleanPair(p1, p2, parts)) { + continue; + } + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { + continue; + } + } + + mixedEventCont.setPair(p1, p2, multCol, confUse3D, 1.0f); + } + } + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processMixedEventCasc, "Enable processing mixed event for cascade - cascade", false); + // MC truth + void processSameEventMCgen(const FilteredFDCollision& col, [[maybe_unused]] const FemtoFullParticles& parts) + { + auto groupPartsOne = partsOneMCgen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto groupPartsTwo = partsTwoMCgen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + eventHisto.fillQA(col); + + for (const auto& part : groupPartsTwo) { + int pdgCode = static_cast(part.pidCut()); + if ((confCascType1 == 0 && pdgCode != 3334) || (confCascType1 == 2 && pdgCode != -3334) || (confCascType1 == 1 && pdgCode != 3312) || (confCascType1 == 3 && pdgCode != -3312)) + continue; + + cascQAHistos.fillQA(part); + + for (const auto& part : groupPartsOne) { + int pdgCode = static_cast(part.pidCut()); + if (pdgCode != confTrkPDGCodePartOne) + continue; + const auto& pdgTrackParticle = pdgMC->GetParticle(pdgCode); + if (!pdgTrackParticle) { + continue; + } + + if (pdgTrackParticle->Charge() > 0) { + trackHistoPartOnePos.fillQA(part); + } else if (pdgTrackParticle->Charge() < 0) { + trackHistoPartOneNeg.fillQA(part); + } + } + + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + if (static_cast(p1.pidCut()) != confTrkPDGCodePartOne) + continue; + int pdgCodeCasc = static_cast(p2.pidCut()); + if ((confCascType1 == 0 && pdgCodeCasc != 3334) || (confCascType1 == 2 && pdgCodeCasc != -3334) || (confCascType1 == 1 && pdgCodeCasc != 3312) || (confCascType1 == 3 && pdgCodeCasc != -3312)) + continue; + sameEventCont.setPair(p1, p2, col.multNtr(), confUse3D, 1.0f); + } + } + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processSameEventMCgen, "Enable processing same event MC truth for track - cascade", false); + + void processMixedEventMCgen(const FilteredFDCollisions& cols, [[maybe_unused]] const FemtoFullParticles& parts) + { + ColumnBinningPolicy colBinning{{confVtxBins, confMultBins}, true}; + + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + + auto groupPartsOne = partsOneMCgen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMCgen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + continue; + } + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + if (static_cast(p1.pidCut()) != confTrkPDGCodePartOne) + continue; + int pdgCodeCasc = static_cast(p2.pidCut()); + if ((confCascType1 == 0 && pdgCodeCasc != 3334) || (confCascType1 == 2 && pdgCodeCasc != -3334) || (confCascType1 == 1 && pdgCodeCasc != 3312) || (confCascType1 == 3 && pdgCodeCasc != -3312)) + continue; + mixedEventCont.setPair(p1, p2, collision1.multNtr(), confUse3D, 1.0f); + } + } + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processMixedEventMCgen, "Enable processing mixed event MC truth for track - cascade", false); + + /// This function fills MC truth particles from derived MC table + void processMCgen(aod::FDCascParticles const& parts) + { + for (const auto& part : parts) { + if (part.partType() != uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) + continue; + + int pdgCode = static_cast(part.pidCut()); + const auto& pdgParticle = pdgMC->GetParticle(pdgCode); + if (!pdgParticle) { + continue; + } + + if ((confCascType1 == 0 && pdgCode == 3334) || (confCascType1 == 1 && pdgCode == 3312)) { + registryMCgen.fill(HIST("plus/MCgenCasc"), part.pt(), part.eta()); + continue; + } else if ((confCascType1 == 0 && pdgCode == -3334) || (confCascType1 == 1 && pdgCode == -3312)) { + registryMCgen.fill(HIST("minus/MCgenCasc"), part.pt(), part.eta()); + continue; + } + + if (pdgParticle->Charge() > 0.0) { + registryMCgen.fill(HIST("plus/MCgenAllPt"), part.pt()); + } + if (pdgCode == 2212) { + registryMCgen.fill(HIST("plus/MCgenPr"), part.pt(), part.eta()); + registryMCgen.fill(HIST("plus/MCgenPrPt"), part.pt()); + } + + if (pdgParticle->Charge() < 0.0) { + registryMCgen.fill(HIST("minus/MCgenAllPt"), part.pt()); + } + if (pdgCode == -2212) { + registryMCgen.fill(HIST("minus/MCgenPr"), part.pt(), part.eta()); + registryMCgen.fill(HIST("minus/MCgenPrPt"), part.pt()); + } + } + } + + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processMCgen, "Process MC truth data for cascades", false); + + void processMCReco(FemtoRecoParticles const& parts, aod::FdMCParticles const& mcparts) + { + for (const auto& part : parts) { + auto mcPartId = part.fdMCParticleId(); + if (mcPartId == -1) + continue; // no MC particle + const auto& mcpart = mcparts.iteratorAt(mcPartId); + // + if (part.partType() == aod::femtouniverseparticle::ParticleType::kCascade) { + if ((confCascType1 == 0 && mcpart.pdgMCTruth() == 3334) || (confCascType1 == 1 && mcpart.pdgMCTruth() == 3312)) { + const auto& posChild = parts.iteratorAt(part.index() - 3); + const auto& negChild = parts.iteratorAt(part.index() - 2); + const auto& bachelor = parts.iteratorAt(part.index() - 1); + /// Daughters that do not pass this condition are not selected + if (isParticleTPC(posChild, CascChildTable[confCascType1][0]) && isParticleTPC(negChild, CascChildTable[confCascType1][1]) && isParticleTPC(bachelor, CascChildTable[confCascType1][2])) { + registryMCreco.fill(HIST("plus/MCrecoCascade"), mcpart.pt(), mcpart.eta()); + } + } else if ((confCascType1 == 0 && mcpart.pdgMCTruth() == -3334) || (confCascType1 == 1 && mcpart.pdgMCTruth() == -3312)) { + /// Daughters that do not pass this condition are not selected + const auto& posChild = parts.iteratorAt(part.index() - 3); + const auto& negChild = parts.iteratorAt(part.index() - 2); + const auto& bachelor = parts.iteratorAt(part.index() - 1); + if (isParticleTPC(posChild, CascChildTable[confCascType1 + 2][0]) && isParticleTPC(negChild, CascChildTable[confCascType1 + 2][1]) && isParticleTPC(bachelor, CascChildTable[confCascType1 + 2][2])) { + registryMCreco.fill(HIST("minus/MCrecoCascade"), mcpart.pt(), mcpart.eta()); + } + } + } else if (part.partType() == aod::femtouniverseparticle::ParticleType::kTrack) { + if (part.sign() > 0) { + registryMCreco.fill(HIST("plus/MCrecoAllPt"), mcpart.pt()); + if (mcpart.pdgMCTruth() == 2212 && isNSigmaCombined(part.p(), unPackInTable(part.tpcNSigmaStorePr()), unPackInTable(part.tofNSigmaStorePr()))) { + registryMCreco.fill(HIST("plus/MCrecoPr"), mcpart.pt(), mcpart.eta()); + registryMCreco.fill(HIST("plus/MCrecoPrPt"), mcpart.pt()); + } + } + + if (part.sign() < 0) { + registryMCreco.fill(HIST("minus/MCrecoAllPt"), mcpart.pt()); + if (mcpart.pdgMCTruth() == -2212 && isNSigmaCombined(part.p(), unPackInTable(part.tpcNSigmaStorePr()), unPackInTable(part.tofNSigmaStorePr()))) { + registryMCreco.fill(HIST("minus/MCrecoPr"), mcpart.pt(), mcpart.eta()); + registryMCreco.fill(HIST("minus/MCrecoPrPt"), mcpart.pt()); + } + } + } + } + } + + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processMCReco, "Process MC reco data for cascades", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx index e35187cf286..80fc4f54218 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx @@ -18,6 +18,7 @@ /// \author Katarzyna Gwiździel, WUT Warsaw, katarzyna.gwizdziel@cern.ch #include +#include #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" @@ -25,9 +26,9 @@ #include "Framework/RunningWorkflowInfo.h" #include "Framework/StepTHn.h" #include "Framework/O2DatabasePDGPlugin.h" -#include "TDatabasePDG.h" #include "ReconstructionDataFormats/PID.h" #include "Common/DataModel/PIDResponse.h" +#include "Common/Core/RecoDecay.h" #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" @@ -36,8 +37,10 @@ #include "PWGCF/FemtoUniverse/Core/FemtoUniverseFemtoContainer.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseAngularContainer.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseSoftPionRemoval.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEfficiencyCalculator.h" #include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" @@ -45,22 +48,12 @@ using namespace o2; using namespace o2::analysis; -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; +using namespace o2::analysis::femto_universe::efficiency; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; -namespace -{ -static constexpr int nPart = 2; -static constexpr int nCuts = 5; -static const std::vector partNames{"D0", "Track"}; -static const std::vector cutNames{"MaxPt", "PIDthr", "nSigmaTPC", "nSigmaTPCTOF", "MaxP"}; -static const float cutsTable[nPart][nCuts]{ - {4.05f, 1.f, 3.f, 3.f, 100.f}, - {4.05f, 1.f, 3.f, 3.f, 100.f}}; -} // namespace - /// Returns deltaPhi value within the range [-pi/2, 3/2*pi] /// double getDeltaPhi(double phiD, double phiDbar) @@ -68,66 +61,119 @@ double getDeltaPhi(double phiD, double phiDbar) return RecoDecay::constrainAngle(phiDbar - phiD, -o2::constants::math::PIHalf); } -struct femtoUniversePairTaskTrackD0 { +/// Returns deltaPhi value within the range [0, pi] +/// +double wrapDeltaPhi0PI(double phiD, double phiDbar) +{ + double deltaPhi = 0.0; + deltaPhi = RecoDecay::constrainAngle(phiDbar - phiD, 0.0); + if (deltaPhi > o2::constants::math::TwoPI) { + deltaPhi = o2::constants::math::TwoPI - deltaPhi; + } + return deltaPhi; +} + +struct FemtoUniversePairTaskTrackD0 { + + Service pdgMC; using FemtoFullParticles = soa::Join; SliceCache cache; Preslice perCol = aod::femtouniverseparticle::fdCollisionId; + using FemtoMCParticles = soa::Join; + Preslice perColMC = aod::femtouniverseparticle::fdCollisionId; + /// Table for both particles struct : o2::framework::ConfigurableGroup { - Configurable ConfNsigmaCombinedProton{"ConfNsigmaCombinedProton", 3.0, "TPC and TOF Proton Sigma (combined) for momentum > 0.5"}; - Configurable ConfNsigmaTPCProton{"ConfNsigmaTPCProton", 3.0, "TPC Proton Sigma for momentum < 0.5"}; - Configurable ConfNsigmaCombinedPion{"ConfNsigmaCombinedPion", 3.0, "TPC and TOF Pion Sigma (combined) for momentum > 0.5"}; - Configurable ConfNsigmaTPCPion{"ConfNsigmaTPCPion", 3.0, "TPC Pion Sigma for momentum < 0.5"}; - - Configurable> ConfCutTable{"ConfCutTable", {cutsTable[0], nPart, nCuts, partNames, cutNames}, "Particle selections"}; - Configurable ConfNspecies{"ConfNspecies", 2, "Number of particle spieces with PID info"}; - Configurable ConfIsMC{"ConfIsMC", false, "Enable additional Histogramms in the case of a MonteCarlo Run"}; - Configurable> ConfTrkPIDnSigmaMax{"ConfTrkPIDnSigmaMax", std::vector{4.f, 3.f, 2.f}, "This configurable needs to be the same as the one used in the producer task"}; - Configurable ConfUse3D{"ConfUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; - Configurable ConfPhiBins{"ConfPhiBins", 29, "Number of phi bins in deta dphi"}; - Configurable ConfEtaBins{"ConfEtaBins", 29, "Number of eta bins in deta dphi"}; + Configurable confNsigmaCombinedProton{"confNsigmaCombinedProton", 3.0, "TPC and TOF Proton Sigma (combined) for momentum > 0.5"}; + Configurable confNsigmaTPCProton{"confNsigmaTPCProton", 3.0, "TPC Proton Sigma for momentum < 0.5"}; + Configurable confNsigmaCombinedPion{"confNsigmaCombinedPion", 3.0, "TPC and TOF Pion Sigma (combined) for momentum > 0.5"}; + Configurable confNsigmaTPCPion{"confNsigmaTPCPion", 3.0, "TPC Pion Sigma for momentum < 0.5"}; + + Configurable confIsMC{"confIsMC", false, "Enable additional Histogramms in the case of a MonteCarlo Run"}; + Configurable> confTrkPIDnSigmaMax{"confTrkPIDnSigmaMax", std::vector{4.f, 3.f, 2.f}, "This configurable needs to be the same as the one used in the producer task"}; + Configurable confUse3D{"confUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; + Configurable confPhiBins{"confPhiBins", 29, "Number of phi bins in deta dphi"}; + Configurable confEtaBins{"confEtaBins", 29, "Number of eta bins in deta dphi"}; } ConfBothTracks; /// Particle 1 --- IDENTIFIED TRACK struct : o2::framework::ConfigurableGroup { - Configurable ConfIsSame{"ConfIsSame", false, "Pairs of the same particle"}; - Configurable ConfPDGCodeTrack{"ConfPDGCodeTrack", 2212, "Particle 2 - PDG code"}; - Configurable ConfPIDTrack{"ConfPIDTrack", 2, "Particle 2 - Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector> - Configurable ConfTrackSign{"ConfTrackSign", 1, "Track sign"}; - Configurable ConfIsTrackIdentified{"ConfIsTrackIdentified", true, "Enable PID for the track"}; + Configurable confIsSame{"confIsSame", false, "Pairs of the same particle"}; + Configurable confPDGCodeTrack{"confPDGCodeTrack", 2212, "Particle 2 - PDG code"}; + Configurable confPIDTrack{"confPIDTrack", 2, "Particle 2 - Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector> + Configurable confTrackSign{"confTrackSign", 1, "Track sign"}; + Configurable confIsTrackIdentified{"confIsTrackIdentified", true, "Enable PID for the track"}; + Configurable confTrackLowPtCut{"confTrackLowPtCut", 0.5, "Low pT cut of the track"}; + Configurable confTrackHighPtCut{"confTrackHighPtCut", 2.5, "High pT cut of the track"}; + Configurable protonMinPtPidTpcTof{"protonMinPtPidTpcTof", 0.5, "Momentum threshold for change of the PID method (from using TPC to TPC and TOF)."}; + Configurable pionMinPtPidTpcTof{"pionMinPtPidTpcTof", 0.5, "Momentum threshold for change of the PID method (from using TPC to TPC and TOF)."}; } ConfTrack; /// Particle 2 --- D0/D0bar meson struct : o2::framework::ConfigurableGroup { - Configurable ConfPDGCodeD0{"ConfPDGCodeD0", 421, "D0 meson - PDG code"}; - Configurable ConfPDGCodeD0bar{"ConfPDGCodeD0bar", -421, "D0bar meson - PDG code"}; - Configurable ConfMinInvMassD0D0bar{"ConfMinInvMassD0D0bar", 1.65, "D0/D0bar sel. - min. invMass"}; - Configurable ConfMaxInvMassD0D0bar{"ConfMaxInvMassD0D0bar", 2.05, "D0/D0bar sel. - max. invMass"}; + Configurable confPDGCodeD0{"confPDGCodeD0", 421, "D0 meson - PDG code"}; + Configurable confPDGCodeD0bar{"confPDGCodeD0bar", -421, "D0bar meson - PDG code"}; + Configurable confMinPtD0D0bar{"confMinPtD0D0bar", 1.0, "D0/D0bar sel. - min. pT"}; + Configurable confMaxPtD0D0bar{"confMaxPtD0D0bar", 3.0, "D0/D0bar sel. - max. pT"}; + Configurable minInvMassD0D0barSignal{"minInvMassD0D0barSignal", 1.81, "Min. inv. mass of D0/D0bar for signal region"}; + Configurable maxInvMassD0D0barSignal{"maxInvMassD0D0barSignal", 1.922, "Max. inv. mass of D0/D0bar for signal region"}; + Configurable minInvMassD0D0barLeftSB{"minInvMassD0D0barLeftSB", 1.65, "Min. inv. mass of D0/D0bar for left SB region"}; + Configurable maxInvMassD0D0barLeftSB{"maxInvMassD0D0barLeftSB", 1.754, "Max. inv. mass of D0/D0bar for left SB region"}; + Configurable minInvMassD0D0barRightSB{"minInvMassD0D0barRightSB", 1.978, "Min. inv. mass of D0/D0bar for right SB region"}; + Configurable maxInvMassD0D0barRightSB{"maxInvMassD0D0barRightSB", 2.09, "Max. inv. mass of D0/D0bar for right SB region"}; } ConfDmesons; struct : o2::framework::ConfigurableGroup { - Configurable ConfSignalRegionMin{"ConfSignalRegionMin", 1.810, "Min. inv. mass for D0/D0bar in the signal region"}; - Configurable ConfSignalRegionMax{"ConfSignalRegionMax", 1.922, "Max. inv. mass for D0/D0bar in the signal region"}; - Configurable ConfMinInvMassLeftSB{"ConfMinInvMassLeftSB", 1.642, "Min. inv. mass for D0/D0bar in the left sideband region"}; - Configurable ConfMaxInvMassLeftSB{"ConfMaxInvMassLeftSB", 1.754, "Max. inv. mass for D0/D0bar in the left sideband region"}; - Configurable ConfMinInvMassRightSB{"ConfMinInvMassRightSB", 1.978, "Min. inv. mass for D0/D0bar in the right sideband region"}; - Configurable ConfMaxInvMassRightSB{"ConfMaxInvMassRightSB", 2.090, "Max. inv. mass for D0/D0bar in the right sideband region"}; - } ConfD0D0barSideBand; + Configurable confMaxProbMlClass1Bg{"confMaxProbMlClass1Bg", 0.4, "ML: max prob. that D0/D0bar cand. is from the backgound"}; + Configurable confMinProbMlClass2Prompt{"confMinProbMlClass2Prompt", 0.05, "ML: min prob. that D0/D0bar cand. is prompt"}; + Configurable confMaxProbMlClass3NonPrompt{"confMaxProbMlClass3NonPrompt", 1.0, "ML: max prob. that D0/D0bar cand. is non-prompt"}; + Configurable confClass1BgProbStep{"confClass1BgProbStep", 0.05, "ML: prob. step for score class 1"}; + Configurable confClass1BgProbStart{"confClass1BgProbStart", 0.05, "ML: starting prob. value in optimization for score class 1"}; + Configurable confClass2PromptProbStep{"confClass2PromptProbStep", 0.05, "ML: prob. step for score class 2 - prompt"}; + Configurable confClass2PromptProbStart{"confClass2PromptProbStart", 0.1, "ML: starting prob. value in optimization for score class 2"}; + Configurable confClass3NonPromptProbStep{"confClass3NonPromptProbStep", 0.05, "ML: prob. step for score class 2 - non-prompt"}; + Configurable confClass3NonPromptProbStart{"confClass3NonPromptProbStart", 0.05, "ML: starting prob. value in optimization for score class 3"}; + } ConfMlOpt; Configurable> binsPt{"binsPt", std::vector{hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits"}; - Configurable ConfUseAllD0mesons{"ConfUseAllD0mesons", false, "Include cand. which are both D0 and D0bar cand."}; + Configurable confChooseD0trackCorr{"confChooseD0trackCorr", 0, "If 0 correlations with D0s, if 1 with D0bars"}; + + // Efficiency + struct : o2::framework::ConfigurableGroup { + Configurable confEfficiencyTrackPath{"confEfficiencyTrackPath", "", "Local path to hadron efficiency TH2F file"}; + Configurable confEfficiencyD0Path{"confEfficiencyD0Path", "", "Local path to D0 efficiency TH2F file"}; + Configurable confEfficiencyTrackTimestamp{"confEfficiencyTrackTimestamp", 0, "(int64_t) Timestamp for hadron"}; + Configurable confEfficiencyD0Timestamp{"confEfficiencyD0Timestamp", 0, "(int64_t) Timestamp for D0"}; + Configurable doEfficiencyCorr{"doEfficiencyCorr", false, "Apply efficiency corrections"}; + } ConfEff; /// Partitions for particle 1 - Partition partsTrack = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == int8_t(ConfTrack.ConfTrackSign)); - Partition> partsTrackMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)); + Partition partsTrack = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == int8_t(ConfTrack.confTrackSign)) && (aod::femtouniverseparticle::pt > ConfTrack.confTrackLowPtCut) && (aod::femtouniverseparticle::pt < ConfTrack.confTrackHighPtCut); + Partition partsTrackMCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == int8_t(ConfTrack.confTrackSign)) && (aod::femtouniverseparticle::pt > ConfTrack.confTrackLowPtCut) && (aod::femtouniverseparticle::pt < ConfTrack.confTrackHighPtCut); + Partition partsTrackMCTruth = (aod::femtouniverseparticle::partType == static_cast(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (aod::femtouniverseparticle::pidCut == static_cast(ConfTrack.confPDGCodeTrack)) && (aod::femtouniverseparticle::pt > ConfTrack.confTrackLowPtCut) && (aod::femtouniverseparticle::pt < ConfTrack.confTrackHighPtCut); /// Partitions for particle 2 - Partition partsAllDmesons = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)); - Partition partsOnlyD0D0bar = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda < 0.0f || aod::femtouniverseparticle::mAntiLambda < 0.0f); - Partition> partsD0D0barMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)); - + /// Partition with all D0/D0bar mesons (which pass double mass hypothesis) + Partition partsAllDmesons = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && ((aod::femtouniverseparticle::mLambda > 0.0f) || (aod::femtouniverseparticle::mAntiLambda > 0.0f)); + /// Partition with D0/D0bar candidates, which pass only one mass hypothesis + Partition partsOnlyD0D0bar = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda < 0.0f || aod::femtouniverseparticle::mAntiLambda < 0.0f) && (aod::femtouniverseparticle::tempFitVar < ConfMlOpt.confMaxProbMlClass1Bg) && (aod::femtouniverseparticle::decayVtxY > ConfMlOpt.confMinProbMlClass2Prompt); + /// Partition with D0 mesons only (one and double mass hypothesis) + Partition partsAllD0s = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar); + /// Partition with D0 mesons only (one mass hypothesis) + Partition partsD0s = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::mAntiLambda < 0.0f) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::tempFitVar < ConfMlOpt.confMaxProbMlClass1Bg) && (aod::femtouniverseparticle::decayVtxY > ConfMlOpt.confMinProbMlClass2Prompt); + /// Partition with D0s selected from the side-band (SB) regions (candidates with double mass hypothesis included) + Partition partsD0sFromSB = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && ((aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barLeftSB && aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barLeftSB) || (aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barRightSB && aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barRightSB)) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar); + /// Partition with D0bar mesons only (one and double mass hypothesis) + Partition partsAllD0bars = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar); + /// Partition with D0bar mesons only (one mass hypothesis) + Partition partsD0bars = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda < 0.0f) && (aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::tempFitVar < ConfMlOpt.confMaxProbMlClass1Bg) && (aod::femtouniverseparticle::decayVtxY > ConfMlOpt.confMinProbMlClass2Prompt); + /// Partition with D0bars selected from the side-band (SB) regions (candidates with double mass hypothesis included) + Partition partsD0barsFromSB = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && ((aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barLeftSB && aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barLeftSB) || (aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barRightSB && aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barRightSB)) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar); + /// Partition for D0/D0bar mesons from MC + Partition partsD0D0barMCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda < 0.0f || aod::femtouniverseparticle::mAntiLambda < 0.0f) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::tempFitVar < ConfMlOpt.confMaxProbMlClass1Bg) && (aod::femtouniverseparticle::decayVtxY > ConfMlOpt.confMinProbMlClass2Prompt); + Partition partsD0D0barMCTruth = (aod::femtouniverseparticle::partType == static_cast(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (aod::femtouniverseparticle::pidCut == static_cast(ConfDmesons.confPDGCodeD0) || aod::femtouniverseparticle::pidCut == static_cast(ConfDmesons.confPDGCodeD0bar)) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar); /// Partition for D0/D0bar daughters Partition partsDmesonsChildren = aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0Child); @@ -145,57 +191,73 @@ struct femtoUniversePairTaskTrackD0 { std::vector kNsigma; /// particle part - ConfigurableAxis ConfTempFitVarBins{"ConfDTempFitVarBins", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfTempFitVarInvMassBins{"ConfDTempFitVarInvMassBins", {6000, 0.9, 4.0}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfTempFitVarpTBins{"ConfTempFitVarpTBins", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; + ConfigurableAxis confTempFitVarBins{"confTempFitVarBins", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis confTempFitVarInvMassBins{"confTempFitVarInvMassBins", {6000, 0.9, 4.0}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis confTempFitVarpTBins{"confTempFitVarpTBins", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; /// Correlation part - ConfigurableAxis ConfMultBins{"ConfMultBins", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; // \todo to be obtained from the hash task - // ConfigurableAxis ConfMultBins{"CfgMultBins", {VARIABLE_WIDTH, 0.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; - ConfigurableAxis ConfVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - ConfigurableAxis ConfmTBins3D{"ConfmTBins3D", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; - ConfigurableAxis ConfmultBins3D{"ConfmultBins3D", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; - - ColumnBinningPolicy colBinning{{ConfVtxBins, ConfMultBins}, true}; - - ConfigurableAxis ConfkstarBins{"ConfkstarBins", {1500, 0., 6.}, "binning kstar"}; - ConfigurableAxis ConfkTBins{"ConfkTBins", {150, 0., 9.}, "binning kT"}; - ConfigurableAxis ConfmTBins{"ConfmTBins", {225, 0., 7.5}, "binning mT"}; - ConfigurableAxis ConfPtBins{"ConfPtBins", {360, 0., 36.}, "binning pT"}; - ConfigurableAxis ConfInvMassBins{"ConfInvMassBins", {500, 0., 5.0}, "binning inv. mass"}; - ConfigurableAxis ConfInvMassFinerBins{"ConfInvMassFinerBins", {120, 1.5848, 2.1848}, "finer binning of inv. mass"}; - - Configurable ConfIsCPR{"ConfIsCPR", true, "Close Pair Rejection"}; - Configurable ConfCPRPlotPerRadii{"ConfCPRPlotPerRadii", false, "Plot CPR per radii"}; - Configurable ConfCPRdeltaPhiCutMax{"ConfCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaPhiCutMin{"ConfCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaEtaCutMax{"ConfCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaEtaCutMin{"ConfCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; - Configurable ConfCPRChosenRadii{"ConfCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; - - FemtoUniverseFemtoContainer sameEventFemtoCont; - FemtoUniverseFemtoContainer mixedEventFemtoCont; - FemtoUniverseAngularContainer sameEventAngularCont; - FemtoUniverseAngularContainer mixedEventAngularCont; + ConfigurableAxis confMultBins{"confMultBins", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; // \todo to be obtained from the hash task + // ConfigurableAxis confMultBins{"confMultBins", {VARIABLE_WIDTH, 0.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; + ConfigurableAxis confVtxBins{"confVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis confmTBins3D{"confmTBins3D", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + ConfigurableAxis confmultBins3D{"confmultBins3D", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + + ColumnBinningPolicy colBinning{{confVtxBins, confMultBins}, true}; + + ConfigurableAxis confkstarBins{"confkstarBins", {1500, 0., 6.}, "binning kstar"}; + ConfigurableAxis confkTBins{"confkTBins", {150, 0., 9.}, "binning kT"}; + ConfigurableAxis confmTBins{"confmTBins", {225, 0., 7.5}, "binning mT"}; + ConfigurableAxis confPtBins{"confPtBins", {360, 0., 36.}, "binning pT"}; + ConfigurableAxis confInvMassBins{"confInvMassBins", {500, 0., 5.0}, "binning inv. mass"}; + + Configurable confIsCPR{"confIsCPR", true, "Close Pair Rejection"}; + Configurable confCPRPlotPerRadii{"confCPRPlotPerRadii", false, "Plot CPR per radii"}; + Configurable confCPRdeltaPhiCutMax{"confCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; + Configurable confCPRdeltaPhiCutMin{"confCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMax{"confCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMin{"confCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; + Configurable confCPRChosenRadii{"confCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; + + Configurable applyMLOpt{"applyMLOpt", false, "Enable for ML selection optimization"}; + Configurable confRemoveSoftPions{"confRemoveSoftPions", false, "Enable to remove soft pions from D* decays"}; + Configurable confSoftPionD0Flag{"confSoftPionD0Flag", false, "Enable soft pion check for D0s"}; + Configurable confSoftPionD0barFlag{"confSoftPionD0barFlag", false, "Enable soft pion check for D0bars"}; + Configurable sigmaSoftPiInvMass{"sigmaSoftPiInvMass", 0.1, "Sigma value from the inv. mass fit for soft pions"}; + // Event mixing configurables + Configurable confNEventsMix{"confNEventsMix", 5, "Number of events for mixing"}; + + FemtoUniverseAngularContainer sameEventAngularCont; + FemtoUniverseAngularContainer mixedEventAngularCont; FemtoUniversePairCleaner pairCleaner; FemtoUniverseDetaDphiStar pairCloseRejection; + FemtoUniverseSoftPionRemoval softPionRemoval; FemtoUniverseTrackSelection trackCuts; + // Axes for BDT score classes' histograms + AxisSpec axisBdtScore{100, 0.f, 1.f}; + AxisSpec axisSelStatus{2, -0.5f, 1.5f}; /// Histogram output HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry resultRegistry{"Correlations", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry MixQaRegistry{"MixQaRegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry mixQaRegistry{"mixQaRegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry mcRecoRegistry{"mcRecoRegistry", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry mcTruthRegistry{"mcTruthRegistry", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + + // Efficiency + EfficiencyConfigurableGroup effConfGroup; + EfficiencyCalculator efficiencyCalculator{&effConfGroup}; + float weight = 1.0; HistogramRegistry registry{"registry", - {{"hInvMassD0", ";#it{M}(K^{-}#pi^{+}) (GeV/#it{c}^{2});counts", {HistType::kTH1F, {ConfInvMassBins}}}, - {"hInvMassD0bar", ";#it{M}(#pi^{-}K^{+}) (GeV/#it{c}^{2});counts", {HistType::kTH1F, {ConfInvMassBins}}}, - {"hPtDmesonCand", "2-prong candidates;#it{p}_{T} (GeV/#it{c});counts", {HistType::kTH1F, {ConfPtBins}}}, - {"hPtD0", "D^{0} cand.;#it{p}_{T} (GeV/#it{c});counts", {HistType::kTH1F, {ConfPtBins}}}, - {"hPtD0bar", "#bar{D^{0}};#it{p}_{T} (GeV/#it{c});counts", {HistType::kTH1F, {ConfPtBins}}}, - {"hPtD0D0bar", "#bar{D^{0}};#it{p}_{T} (GeV/#it{c});counts", {HistType::kTH1F, {ConfPtBins}}}, - {"hPhiDmesonCand", ";#varphi (rad);counts", {HistType::kTH1F, {{80, 0., 2. * o2::constants::math::PI}}}}, - {"hPhiD0", ";#varphi (rad);counts", {HistType::kTH1F, {{80, 0., 2. * o2::constants::math::PI}}}}, - {"hPhiD0bar", ";#varphi (rad);counts", {HistType::kTH1F, {{80, 0., 2. * o2::constants::math::PI}}}}, + {{"hInvMassD0", ";#it{M}(K^{-}#pi^{+}) (GeV/#it{c}^{2});counts", {HistType::kTH1F, {confInvMassBins}}}, + {"hInvMassD0bar", ";#it{M}(#pi^{-}K^{+}) (GeV/#it{c}^{2});counts", {HistType::kTH1F, {confInvMassBins}}}, + {"hPtDmesonCand", "2-prong candidates;#it{p}_{T} (GeV/#it{c});counts", {HistType::kTH1F, {confPtBins}}}, + {"hPtD0", "D^{0} cand.;#it{p}_{T} (GeV/#it{c});counts", {HistType::kTH1F, {confPtBins}}}, + {"hPtD0bar", "#bar{D^{0}};#it{p}_{T} (GeV/#it{c});counts", {HistType::kTH1F, {confPtBins}}}, + {"hPtD0D0bar", "#bar{D^{0}};#it{p}_{T} (GeV/#it{c});counts", {HistType::kTH1F, {confPtBins}}}, + {"hPhiDmesonCand", ";#varphi (rad);counts", {HistType::kTH1F, {{80, 0., o2::constants::math::TwoPI}}}}, + {"hPhiD0", ";#varphi (rad);counts", {HistType::kTH1F, {{80, 0., o2::constants::math::TwoPI}}}}, + {"hPhiD0bar", ";#varphi (rad);counts", {HistType::kTH1F, {{80, 0., o2::constants::math::TwoPI}}}}, {"hEtaDmesonCand", ";#eta ;counts", {HistType::kTH1F, {{200, -1., 1.}}}}, {"hEtaD0", ";#eta ;counts", {HistType::kTH1F, {{200, -1., 1.}}}}, {"hEtaD0bar", ";#eta ;counts", {HistType::kTH1F, {{200, -1., 1.}}}}, @@ -203,30 +265,20 @@ struct femtoUniversePairTaskTrackD0 { {"hDecayLengthD0bar", ";decay length (cm);counts", {HistType::kTH1F, {{800, 0., 4.}}}}, {"hPtDaughters", ";#it{p}_{T} (GeV/#it{c});counts", {HistType::kTH1F, {{300, 0., 12.}}}}, {"hSignDaughters", ";sign ;counts", {HistType::kTH1F, {{10, -2.5, 2.5}}}}, - {"hbetaDaughters", "; p (GeV/#it{c}); TOF #beta", {HistType::kTH2F, {{300, 0., 15.}, {200, 0., 2.}}}}, - {"hdEdxDaughters", "; p (GeV/#it{c}); TPC dE/dx (KeV/cm)", {HistType::kTH2F, {{300, 0., 15.}, {500, 0., 500.}}}}, {"hDCAxyDaughters", "; #it{DCA}_{xy} (cm); counts", {HistType::kTH1F, {{140, 0., 0.14}}}}, {"hDCAzDaughters", "; #it{DCA}_{z} (cm); counts", {HistType::kTH1F, {{140, 0., 0.14}}}}}}; // PID for protons - bool IsProtonNSigma(float mom, float nsigmaTPCPr, float nsigmaTOFPr) // previous version from: https://github.com/alisw/AliPhysics/blob/master/PWGCF/FEMTOSCOPY/AliFemtoUser/AliFemtoMJTrackCut.cxx + bool isProtonNSigma(float mom, float nsigmaTPCPr, float nsigmaTOFPr) // previous version from: https://github.com/alisw/AliPhysics/blob/master/PWGCF/FEMTOSCOPY/AliFemtoUser/AliFemtoMJTrackCut.cxx { - //|nsigma_TPC| < 3 for p < 0.5 GeV/c - //|nsigma_combined| < 3 for p > 0.5 - - // using configurables: - // ConfNsigmaTPCProton -> TPC Kaon Sigma for momentum < 0.5 - // ConfNsigmaCombinedProton -> TPC and TOF Kaon Sigma (combined) for momentum > 0.5 - - if (mom < 0.5) { - if (TMath::Abs(nsigmaTPCPr) < ConfBothTracks.ConfNsigmaTPCProton) { + if (mom < ConfTrack.protonMinPtPidTpcTof) { + if (std::abs(nsigmaTPCPr) < ConfBothTracks.confNsigmaTPCProton) { return true; } else { return false; } - } else if (mom > 0.4) { - if (TMath::Hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfBothTracks.ConfNsigmaCombinedProton) { - // if (TMath::Abs(nsigmaTPCPr) < ConfBothTracks.ConfNsigmaCombinedProton) { + } else if (mom > ConfTrack.protonMinPtPidTpcTof) { + if (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfBothTracks.confNsigmaCombinedProton) { return true; } else { return false; @@ -235,36 +287,36 @@ struct femtoUniversePairTaskTrackD0 { return false; } - bool IsKaonNSigma(float mom, float nsigmaTPCK, float nsigmaTOFK) + bool isKaonNSigma(float mom, float nsigmaTPCK, float nsigmaTOFK) { if (mom < 0.3) { // 0.0-0.3 - if (TMath::Abs(nsigmaTPCK) < 3.0) { + if (std::abs(nsigmaTPCK) < 3.0) { return true; } else { return false; } } else if (mom < 0.45) { // 0.30 - 0.45 - if (TMath::Abs(nsigmaTPCK) < 2.0) { + if (std::abs(nsigmaTPCK) < 2.0) { return true; } else { return false; } } else if (mom < 0.55) { // 0.45-0.55 - if (TMath::Abs(nsigmaTPCK) < 1.0) { + if (std::abs(nsigmaTPCK) < 1.0) { return true; } else { return false; } } else if (mom < 1.5) { // 0.55-1.5 (now we use TPC and TOF) - if ((TMath::Abs(nsigmaTOFK) < 3.0) && (TMath::Abs(nsigmaTPCK) < 3.0)) { + if ((std::abs(nsigmaTOFK) < 3.0) && (std::abs(nsigmaTPCK) < 3.0)) { { return true; } } else { return false; } - } else if (mom > 1.5) { // 1.5 - - if ((TMath::Abs(nsigmaTOFK) < 2.0) && (TMath::Abs(nsigmaTPCK) < 3.0)) { + } else if (mom > 1.5) { + if ((std::abs(nsigmaTOFK) < 2.0) && (std::abs(nsigmaTPCK) < 3.0)) { return true; } else { return false; @@ -274,24 +326,20 @@ struct femtoUniversePairTaskTrackD0 { } } - bool IsPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) + bool isPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) { - //|nsigma_TPC| < 3 for p < 0.5 GeV/c - //|nsigma_combined| < 3 for p > 0.5 - // using configurables: - // ConfNsigmaTPCPion -> TPC Kaon Sigma for momentum < 0.5 - // ConfNsigmaCombinedPion -> TPC and TOF Pion Sigma (combined) for momentum > 0.5 + // confNsigmaTPCPion -> TPC Pion Sigma for momentum < 0.5 GeV/c + // confNsigmaCombinedPion -> TPC and TOF Pion Sigma (combined) for momentum > 0.5 GeV/c if (true) { - if (mom < 0.5) { - if (TMath::Abs(nsigmaTPCPi) < ConfBothTracks.ConfNsigmaTPCPion) { + if (mom < ConfTrack.pionMinPtPidTpcTof) { + if (std::abs(nsigmaTPCPi) < ConfBothTracks.confNsigmaTPCPion) { return true; } else { return false; } - } else if (mom > 0.5) { - if (TMath::Hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfBothTracks.ConfNsigmaCombinedPion) { - // if (TMath::Abs(nsigmaTPCPi) < ConfBothTracks.ConfNsigmaCombinedPion) { + } else if (mom > ConfTrack.pionMinPtPidTpcTof) { + if (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfBothTracks.confNsigmaCombinedPion) { return true; } else { return false; @@ -301,20 +349,20 @@ struct femtoUniversePairTaskTrackD0 { return false; } - bool IsParticleNSigma(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) + bool isParticleNSigma(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) { - switch (ConfTrack.ConfPDGCodeTrack) { + switch (ConfTrack.confPDGCodeTrack) { case 2212: // Proton case -2212: // anty Proton - return IsProtonNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); + return isProtonNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); break; case 211: // Pion case -211: // Pion- - return IsPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); + return isPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); break; case 321: // Kaon+ case -321: // Kaon- - return IsKaonNSigma(mom, nsigmaTPCK, nsigmaTOFK); + return isKaonNSigma(mom, nsigmaTPCK, nsigmaTOFK); break; default: return false; @@ -323,96 +371,377 @@ struct femtoUniversePairTaskTrackD0 { void init(InitContext&) { + // if (effConfGroup.confEfficiencyDoMCTruth) { + // WORK IN PROGRESS + // hMCTruth1.init(&qaRegistry, confBinsTempFitVarpT, confBinsTempFitVarPDG, false, ConfTrack.confTrackPDGCode, false); + // hMCTruth2.init(&qaRegistry, confBinsTempFitVarpT, confBinsTempFitVarPDG, false, 333, false); + // } + efficiencyCalculator.init(); + eventHisto.init(&qaRegistry); - trackHistoPartD0D0bar.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarInvMassBins, ConfBothTracks.ConfIsMC, ConfDmesons.ConfPDGCodeD0); - if (!ConfTrack.ConfIsSame) { - trackHistoPartTrack.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarBins, ConfBothTracks.ConfIsMC, ConfTrack.ConfPDGCodeTrack); + qaRegistry.add("QA_D0D0barSelection/hInvMassD0", ";#it{M}(K^{-}#pi^{+}) (GeV/#it{c}^{2});counts", kTH1F, {confInvMassBins}); + qaRegistry.add("QA_D0D0barSelection/hPtD0", "D^{0} cand.;#it{p}_{T} (GeV/#it{c});counts", kTH1F, {confPtBins}); + qaRegistry.add("QA_D0D0barSelection/hInvMassD0bar", ";#it{M}(K^{-}#pi^{+}) (GeV/#it{c}^{2});counts", kTH1F, {confInvMassBins}); + qaRegistry.add("QA_D0D0barSelection/hPtD0bar", "#bar{D^{0}} cand.;#it{p}_{T} (GeV/#it{c});counts", kTH1F, {confPtBins}); + qaRegistry.add("QA_D0D0barSelection_SB/hInvMassD0", ";#it{M}(K^{-}#pi^{+}) (GeV/#it{c}^{2});counts", kTH1F, {confInvMassBins}); + qaRegistry.add("QA_D0D0barSelection_SB/hPtD0", "D^{0} cand.;#it{p}_{T} (GeV/#it{c});counts", kTH1F, {confPtBins}); + + qaRegistry.add("D0_pos_daugh/nSigmaTPC", "; #it{p} (GeV/#it{c}); n#sigma_{TPC}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("D0_pos_daugh/nSigmaTOF", "; #it{p} (GeV/#it{c}); n#sigma_{TOF}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("D0_pos_daugh/pt", "; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{100, 0, 10}}); + qaRegistry.add("D0_pos_daugh/eta", "; #it{eta}; Counts", kTH1F, {{200, -1.5, 1.5}}); + qaRegistry.add("D0_pos_daugh/phi", "; #it{varphi}; Counts", kTH1F, {{200, 0, o2::constants::math::TwoPI}}); + qaRegistry.add("D0_pos_daugh/hDCAxy", "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {{100, 0, 10}, {500, -5, 5}}); + + qaRegistry.add("D0_neg_daugh/nSigmaTPC", "; #it{p} (GeV/#it{c}); n#sigma_{TPC}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("D0_neg_daugh/nSigmaTOF", "; #it{p} (GeV/#it{c}); n#sigma_{TOF}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("D0_neg_daugh/pt", "; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{100, 0, 10}}); + qaRegistry.add("D0_neg_daugh/eta", "; #it{eta}; Counts", kTH1F, {{200, -1.5, 1.5}}); + qaRegistry.add("D0_neg_daugh/phi", "; #it{varphi}; Counts", kTH1F, {{200, 0, o2::constants::math::TwoPI}}); + qaRegistry.add("D0_neg_daugh/hDCAxy", "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {{100, 0, 10}, {500, -5, 5}}); + + qaRegistry.add("D0bar_pos_daugh/nSigmaTPC", "; #it{p} (GeV/#it{c}); n#sigma_{TPC}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("D0bar_pos_daugh/nSigmaTOF", "; #it{p} (GeV/#it{c}); n#sigma_{TOF}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("D0bar_pos_daugh/pt", "; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{100, 0, 10}}); + qaRegistry.add("D0bar_pos_daugh/eta", "; #it{eta}; Counts", kTH1F, {{200, -1.5, 1.5}}); + qaRegistry.add("D0bar_pos_daugh/phi", "; #it{varphi}; Counts", kTH1F, {{200, 0, o2::constants::math::TwoPI}}); + qaRegistry.add("D0bar_pos_daugh/hDCAxy", "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {{100, 0, 10}, {500, -5, 5}}); + + qaRegistry.add("D0bar_neg_daugh/nSigmaTPC", "; #it{p} (GeV/#it{c}); n#sigma_{TPC}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("D0bar_neg_daugh/nSigmaTOF", "; #it{p} (GeV/#it{c}); n#sigma_{TOF}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("D0bar_neg_daugh/pt", "; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{100, 0, 10}}); + qaRegistry.add("D0bar_neg_daugh/eta", "; #it{eta}; Counts", kTH1F, {{200, -1.5, 1.5}}); + qaRegistry.add("D0bar_neg_daugh/phi", "; #it{varphi}; Counts", kTH1F, {{200, 0, o2::constants::math::TwoPI}}); + qaRegistry.add("D0bar_neg_daugh/hDCAxy", "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {{100, 0, 10}, {500, -5, 5}}); + + qaRegistry.add("Hadron/nSigmaTPCPr", "; #it{p} (GeV/#it{c}); n#sigma_{TPCPr}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Hadron/nSigmaTOFPr", "; #it{p} (GeV/#it{c}); n#sigma_{TOFPr}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Hadron/nSigmaTPCPi", "; #it{p} (GeV/#it{c}); n#sigma_{TPCPi}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Hadron/nSigmaTOFPi", "; #it{p} (GeV/#it{c}); n#sigma_{TOFPi}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Hadron/nSigmaTPCKa", "; #it{p} (GeV/#it{c}); n#sigma_{TPCKa}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Hadron/nSigmaTOFKa", "; #it{p} (GeV/#it{c}); n#sigma_{TOFKa}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + + // MC truth + mcTruthRegistry.add("MCTruthD0D0bar", "MC Truth D0/D0bar;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{360, 0, 36}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("MCTruthAllPositivePt", "MC Truth all positive;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{360, 0, 36}}}); + mcTruthRegistry.add("MCTruthAllNegativePt", "MC Truth all negative;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{360, 0, 36}}}); + mcTruthRegistry.add("MCTruthKpPtVsEta", "MC Truth K+;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("MCTruthKmPtVsEta", "MC Truth K-;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("MCTruthPipPtVsEta", "MC Truth #pi+;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("MCTruthPimPtVsEta", "MC Truth #pi-;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("MCTruthProtonPtVsEta", "MC Truth proton;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("MCTruthAntiProtonPtVsEta", "MC Truth antiproton;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("MCTruthKpPt", "MC Truth K+;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + mcTruthRegistry.add("MCTruthKmPt", "MC Truth K-;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + mcTruthRegistry.add("MCTruthPipPt", "MC Truth #pi+;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + mcTruthRegistry.add("MCTruthPimPt", "MC Truth #pi-;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + mcTruthRegistry.add("MCTruthProtonPt", "MC Truth proton;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + mcTruthRegistry.add("MCTruthAntiProtonPt", "MC Truth antiproton;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + + trackHistoPartD0D0bar.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarInvMassBins, ConfBothTracks.confIsMC, ConfDmesons.confPDGCodeD0); + if (!ConfTrack.confIsSame) { + trackHistoPartTrack.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarBins, ConfBothTracks.confIsMC, ConfTrack.confPDGCodeTrack); } - MixQaRegistry.add("MixingQA/hSECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); - MixQaRegistry.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); + mixQaRegistry.add("MixingQA/hSECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); + mixQaRegistry.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); - sameEventFemtoCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfBothTracks.ConfIsMC, ConfBothTracks.ConfUse3D); - mixedEventFemtoCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfBothTracks.ConfIsMC, ConfBothTracks.ConfUse3D); - sameEventAngularCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfBothTracks.ConfEtaBins, ConfBothTracks.ConfPhiBins, ConfBothTracks.ConfIsMC, ConfBothTracks.ConfUse3D); - mixedEventAngularCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfBothTracks.ConfEtaBins, ConfBothTracks.ConfPhiBins, ConfBothTracks.ConfIsMC, ConfBothTracks.ConfUse3D); + sameEventAngularCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confmultBins3D, confmTBins3D, ConfBothTracks.confEtaBins, ConfBothTracks.confPhiBins, ConfBothTracks.confIsMC, ConfBothTracks.confUse3D); + mixedEventAngularCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confmultBins3D, confmTBins3D, ConfBothTracks.confEtaBins, ConfBothTracks.confPhiBins, ConfBothTracks.confIsMC, ConfBothTracks.confUse3D); - sameEventFemtoCont.setPDGCodes(ConfDmesons.ConfPDGCodeD0, ConfTrack.ConfPDGCodeTrack); - mixedEventFemtoCont.setPDGCodes(ConfDmesons.ConfPDGCodeD0, ConfTrack.ConfPDGCodeTrack); - sameEventAngularCont.setPDGCodes(ConfDmesons.ConfPDGCodeD0, ConfTrack.ConfPDGCodeTrack); - mixedEventAngularCont.setPDGCodes(ConfDmesons.ConfPDGCodeD0, ConfTrack.ConfPDGCodeTrack); + sameEventAngularCont.setPDGCodes(ConfDmesons.confPDGCodeD0, ConfTrack.confPDGCodeTrack); + mixedEventAngularCont.setPDGCodes(ConfDmesons.confPDGCodeD0, ConfTrack.confPDGCodeTrack); + softPionRemoval.init(&qaRegistry); pairCleaner.init(&qaRegistry); - if (ConfIsCPR.value) { - pairCloseRejection.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiCutMin.value, ConfCPRdeltaPhiCutMax.value, ConfCPRdeltaEtaCutMin.value, ConfCPRdeltaEtaCutMax.value, ConfCPRChosenRadii.value, ConfCPRPlotPerRadii.value); + if (confIsCPR.value) { + pairCloseRejection.init(&resultRegistry, &qaRegistry, confCPRdeltaPhiCutMin.value, confCPRdeltaPhiCutMax.value, confCPRdeltaEtaCutMin.value, confCPRdeltaEtaCutMax.value, confCPRChosenRadii.value, confCPRPlotPerRadii.value); } - vPIDTrack = ConfTrack.ConfPIDTrack.value; - kNsigma = ConfBothTracks.ConfTrkPIDnSigmaMax.value; + vPIDTrack = ConfTrack.confPIDTrack.value; + kNsigma = ConfBothTracks.confTrkPIDnSigmaMax.value; // D0/D0bar histograms auto vbins = (std::vector)binsPt; - registry.add("hMassVsPt", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {ConfInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hMassVsPtFinerBinning", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {ConfInvMassFinerBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hInvMassVsPtOnlyD0D0bar", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {ConfInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hDeltaPhiSigSig", "SxS correlation;#Delta#varphi (rad);counts", {HistType::kTH1F, {{50, -0.5 * o2::constants::math::PI, 1.5 * o2::constants::math::PI}}}); - registry.add("hDeltaPhiD0BgD0barSig", "B(D0)x S(D0bar) correlation;#Delta#varphi (rad);counts", {HistType::kTH1F, {{50, -0.5 * o2::constants::math::PI, 1.5 * o2::constants::math::PI}}}); - registry.add("hDeltaPhiD0SigD0barBg", "S(D0)x B(D0bar) correlation;#Delta#varphi (rad);counts", {HistType::kTH1F, {{50, -0.5 * o2::constants::math::PI, 1.5 * o2::constants::math::PI}}}); - registry.add("hDeltaPhiBgBg", "BxB correlation;#Delta#varphi (rad);counts", {HistType::kTH1F, {{50, -0.5 * o2::constants::math::PI, 1.5 * o2::constants::math::PI}}}); - registry.add("hPtCand1VsPtCand2", "2-prong candidates;#it{p}_{T} (GeV/#it{c});#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hDeltaEtaDeltaPhi", "2-prong candidates;#Delta #eta;#Delta #varphi (rad)", {HistType::kTH2F, {{29, -2., 2.}, {29, -0.5 * o2::constants::math::PI, 1.5 * o2::constants::math::PI}}}); + registry.add("D0D0bar_oneMassHypo/hMassVsPt", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("D0D0bar_oneMassHypo/hMassVsPtReflected", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("D0D0bar_oneMassHypo/hMassVsPtD0", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("D0D0bar_oneMassHypo/hMassVsPtD0bar", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("D0D0bar_oneMassHypo/hMassVsPtD0Reflected", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("D0D0bar_oneMassHypo/hMassVsPtD0barReflected", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("D0D0bar_doubleMassHypo/hMassVsPt", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("D0D0bar_doubleMassHypo/hMassVsPtD0", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("D0D0bar_doubleMassHypo/hMassVsPtD0bar", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + // Histograms for BDT score classes' check + registry.add("DebugBdt/hBdtScore1VsStatus", ";BDT score;status", {HistType::kTH2F, {axisBdtScore, axisSelStatus}}); + registry.add("DebugBdt/hBdtScore2VsStatus", ";BDT score;status", {HistType::kTH2F, {axisBdtScore, axisSelStatus}}); + registry.add("DebugBdt/hBdtScore3VsStatus", ";BDT score;status", {HistType::kTH2F, {axisBdtScore, axisSelStatus}}); + if (applyMLOpt) { + registry.add("D0D0bar_MLSel/hMassVsPt1", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("D0D0bar_MLSel/hMassVsPt2", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("D0D0bar_MLSel/hMassVsPt3", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("D0D0bar_MLSel/hMassVsPt4", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("D0D0bar_MLSel/hMassVsPt5", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("D0D0bar_MLSel/hMassVsPt6", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("D0D0bar_MLSel/hMassVsPt7", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("D0D0bar_MLSel/hMassVsPt8", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("D0D0bar_MLSel/hMassVsPt9", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("D0D0bar_MLSel/hMassVsPt10", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + } } template void fillCollision(CollisionType col) { - MixQaRegistry.fill(HIST("MixingQA/hSECollisionBins"), colBinning.getBin({col.posZ(), col.multNtr()})); + mixQaRegistry.fill(HIST("MixingQA/hSECollisionBins"), colBinning.getBin({col.posZ(), col.multNtr()})); eventHisto.fillQA(col); } - void processD0mesons(o2::aod::FDCollision& col, FemtoFullParticles&) + void processD0MLOptBg(o2::aod::FdCollision const& col, FemtoFullParticles const&) { - auto groupPartsOnlyD0D0bar = partsOnlyD0D0bar->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto groupPartsAllDmesons = partsAllDmesons->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto groupD0D0barCands = partsOnlyD0D0bar->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + // loop over selected D0/D0bar candidates + for (auto const& charmCand : groupD0D0barCands) { + // D0 candidates + if (charmCand.mLambda() > 0.0f && charmCand.mAntiLambda() < 0.0f) { + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt1"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt2"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 2.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt3"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 3.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt4"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 4.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt5"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 5.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt6"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 6.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt7"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 7.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt8"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 8.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt9"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 9.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt10"), charmCand.mLambda(), charmCand.pt()); + } + // DObar candidates + if (charmCand.mLambda() < 0.0f && charmCand.mAntiLambda() > 0.0f) { + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt1"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt2"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 2.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt3"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 3.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt4"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 4.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt5"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 5.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt6"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 6.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt7"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 7.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt8"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 8.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt9"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 9.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt10"), charmCand.mAntiLambda(), charmCand.pt()); + } + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processD0MLOptBg, "Enable filling QA plots for ML Bg D0/D0bar selection optimization", false); + + void processD0MLOptBgAndPrompt(o2::aod::FdCollision const& col, FemtoFullParticles const&) + { + auto groupD0D0barCands = partsOnlyD0D0bar->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + // loop over selected D0/D0bar candidates + for (auto const& charmCand : groupD0D0barCands) { + // D0 candidates + if (charmCand.decayVtxY() > ConfMlOpt.confClass2PromptProbStart) { + if (charmCand.mLambda() > 0.0f && charmCand.mAntiLambda() < 0.0f) { + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt1"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt2"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 2.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt3"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 3.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt4"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 4.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt5"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 5.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt6"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 6.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt7"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 7.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt8"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 8.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt9"), charmCand.mLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 9.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt10"), charmCand.mLambda(), charmCand.pt()); + } + // DObar candidates + if (charmCand.mLambda() < 0.0f && charmCand.mAntiLambda() > 0.0f) { + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt1"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt2"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 2.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt3"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 3.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt4"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 4.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt5"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 5.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt6"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 6.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt7"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 7.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt8"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 8.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt9"), charmCand.mAntiLambda(), charmCand.pt()); + if (charmCand.tempFitVar() < ConfMlOpt.confClass1BgProbStart + 9.0 * ConfMlOpt.confClass1BgProbStep) + registry.fill(HIST("D0D0bar_MLSel/hMassVsPt10"), charmCand.mAntiLambda(), charmCand.pt()); + } + } + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processD0MLOptBgAndPrompt, "Enable filling QA plots for ML Bg and Prompt D0/D0bar selection optimization", false); + + void processQAD0D0barSel(o2::aod::FdCollision const& col, FemtoFullParticles const&) + { + auto groupPartsD0s = partsD0s->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto groupPartsD0bars = partsD0bars->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto groupPartsD0sFromSB = partsD0sFromSB->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + // loop over selected D0 candidates + for (auto const& d0cand : groupPartsD0s) { + + qaRegistry.fill(HIST("QA_D0D0barSelection/hInvMassD0"), d0cand.mLambda()); + qaRegistry.fill(HIST("QA_D0D0barSelection/hPtD0"), d0cand.pt()); + } + // loop over selected D0bar candidates + for (auto const& d0barcand : groupPartsD0bars) { + + qaRegistry.fill(HIST("QA_D0D0barSelection/hInvMassD0bar"), d0barcand.mAntiLambda()); + qaRegistry.fill(HIST("QA_D0D0barSelection/hPtD0bar"), d0barcand.pt()); + } + + // loop over selected D0 candidates from SB regions + for (auto const& d0SB : groupPartsD0sFromSB) { + + qaRegistry.fill(HIST("QA_D0D0barSelection_SB/hInvMassD0"), d0SB.mLambda()); + qaRegistry.fill(HIST("QA_D0D0barSelection_SB/hPtD0"), d0SB.pt()); + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processQAD0D0barSel, "Enable filling QA plots for selected D0/D0bar cand.", true); + + void processAllDmesons(o2::aod::FdCollision const& col, FemtoFullParticles const&) + { + auto groupPartsAllD0D0barCands = partsAllDmesons->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); auto groupPartsD0D0barChildren = partsDmesonsChildren->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - // loop over all D mesons - for (auto const& dmeson : groupPartsAllDmesons) { + // loop over D0/D0bar mesons (ONLY) + for (auto const& d0d0bar : groupPartsAllD0D0barCands) { - if (dmeson.mLambda() > 0.0f) { - registry.fill(HIST("hMassVsPt"), dmeson.mLambda(), dmeson.pt()); - registry.fill(HIST("hMassVsPtFinerBinning"), dmeson.mLambda(), dmeson.pt()); + registry.fill(HIST("hPtD0D0bar"), d0d0bar.pt()); + registry.fill(HIST("hPhiDmesonCand"), d0d0bar.phi()); + registry.fill(HIST("hEtaDmesonCand"), d0d0bar.eta()); + // BDT score classes + registry.fill(HIST("DebugBdt/hBdtScore1VsStatus"), d0d0bar.decayVtxX(), 1); + registry.fill(HIST("DebugBdt/hBdtScore2VsStatus"), d0d0bar.decayVtxY(), 1); + registry.fill(HIST("DebugBdt/hBdtScore3VsStatus"), d0d0bar.decayVtxZ(), 1); + + if (d0d0bar.mLambda() > 0.0f) { + registry.fill(HIST("D0D0bar_doubleMassHypo/hMassVsPt"), d0d0bar.mLambda(), d0d0bar.pt()); + registry.fill(HIST("D0D0bar_doubleMassHypo/hMassVsPtD0"), d0d0bar.mLambda(), d0d0bar.pt()); + if (d0d0bar.mAntiLambda() < 0.0f) { + registry.fill(HIST("D0D0bar_oneMassHypo/hMassVsPt"), d0d0bar.mLambda(), d0d0bar.pt()); + registry.fill(HIST("D0D0bar_oneMassHypo/hMassVsPtD0"), d0d0bar.mLambda(), d0d0bar.pt()); + registry.fill(HIST("hPtD0"), d0d0bar.pt()); + registry.fill(HIST("hPhiD0"), d0d0bar.phi()); + registry.fill(HIST("hEtaD0"), d0d0bar.eta()); + } } - - if (dmeson.mAntiLambda() > 0.0f) { - registry.fill(HIST("hMassVsPt"), dmeson.mAntiLambda(), dmeson.pt()); - registry.fill(HIST("hMassVsPtFinerBinning"), dmeson.mAntiLambda(), dmeson.pt()); + if (d0d0bar.mAntiLambda() > 0.0f) { + registry.fill(HIST("D0D0bar_doubleMassHypo/hMassVsPt"), d0d0bar.mLambda(), d0d0bar.pt()); + registry.fill(HIST("D0D0bar_doubleMassHypo/hMassVsPtD0bar"), d0d0bar.mLambda(), d0d0bar.pt()); + if (d0d0bar.mLambda() < 0.0f) { + registry.fill(HIST("D0D0bar_oneMassHypo/hMassVsPt"), d0d0bar.mAntiLambda(), d0d0bar.pt()); + registry.fill(HIST("D0D0bar_oneMassHypo/hMassVsPtD0bar"), d0d0bar.mAntiLambda(), d0d0bar.pt()); + registry.fill(HIST("hPtD0bar"), d0d0bar.pt()); + registry.fill(HIST("hPhiD0bar"), d0d0bar.phi()); + registry.fill(HIST("hEtaD0bar"), d0d0bar.eta()); + } } + } - registry.fill(HIST("hPtDmesonCand"), dmeson.pt()); - registry.fill(HIST("hPhiDmesonCand"), dmeson.phi()); - registry.fill(HIST("hEtaDmesonCand"), dmeson.eta()); + // loop over D mesons childen + for (auto const& daughD0D0bar : groupPartsD0D0barChildren) { + registry.fill(HIST("hPtDaughters"), daughD0D0bar.pt()); + registry.fill(HIST("hSignDaughters"), daughD0D0bar.mLambda()); + // filling QA plots for D0 mesons' positive daughters (K+) + if (daughD0D0bar.mLambda() == 1 && (daughD0D0bar.mAntiLambda() == 1 || daughD0D0bar.mAntiLambda() == 0)) { + qaRegistry.fill(HIST("D0_pos_daugh/pt"), daughD0D0bar.pt()); + qaRegistry.fill(HIST("D0_pos_daugh/eta"), daughD0D0bar.eta()); + qaRegistry.fill(HIST("D0_pos_daugh/phi"), daughD0D0bar.phi()); + } + // filling QA plots for D0 mesons' negative daughters (pi-) + if (daughD0D0bar.mLambda() == -1 && (daughD0D0bar.mAntiLambda() == 1 || daughD0D0bar.mAntiLambda() == 0)) { + qaRegistry.fill(HIST("D0_neg_daugh/pt"), daughD0D0bar.pt()); + qaRegistry.fill(HIST("D0_neg_daugh/eta"), daughD0D0bar.eta()); + qaRegistry.fill(HIST("D0_neg_daugh/phi"), daughD0D0bar.phi()); + } + // filling QA plots for D0bar mesons' positive daughters (pi+) + if (daughD0D0bar.mLambda() == 1 && (daughD0D0bar.mAntiLambda() == -1 || daughD0D0bar.mAntiLambda() == 0)) { + qaRegistry.fill(HIST("D0bar_pos_daugh/pt"), daughD0D0bar.pt()); + qaRegistry.fill(HIST("D0bar_pos_daugh/eta"), daughD0D0bar.eta()); + qaRegistry.fill(HIST("D0bar_pos_daugh/phi"), daughD0D0bar.phi()); + } + // filling QA plots for D0bar mesons' negative daughters (K-) + if (daughD0D0bar.mLambda() == -1 && (daughD0D0bar.mAntiLambda() == -1 || daughD0D0bar.mAntiLambda() == 0)) { + qaRegistry.fill(HIST("D0bar_neg_daugh/pt"), daughD0D0bar.pt()); + qaRegistry.fill(HIST("D0bar_neg_daugh/eta"), daughD0D0bar.eta()); + qaRegistry.fill(HIST("D0bar_neg_daugh/phi"), daughD0D0bar.phi()); + } } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processAllDmesons, "Enable processing over all D meson candidates", false); + + void processD0mesons(o2::aod::FdCollision const& col, FemtoFullParticles const&) + { + auto groupPartsAllD0D0barCands = partsAllDmesons->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto groupPartsOnlyD0D0bar = partsOnlyD0D0bar->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto groupPartsD0D0barChildren = partsDmesonsChildren->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); // loop over D0/D0bar mesons (ONLY) for (auto const& d0d0bar : groupPartsOnlyD0D0bar) { registry.fill(HIST("hPtD0D0bar"), d0d0bar.pt()); + // BDT score classes + registry.fill(HIST("DebugBdt/hBdtScore1VsStatus"), d0d0bar.decayVtxX(), 1); + registry.fill(HIST("DebugBdt/hBdtScore2VsStatus"), d0d0bar.decayVtxY(), 1); + registry.fill(HIST("DebugBdt/hBdtScore3VsStatus"), d0d0bar.decayVtxZ(), 1); if (d0d0bar.mLambda() > 0.0f && d0d0bar.mAntiLambda() < 0.0f) { - registry.fill(HIST("hInvMassVsPtOnlyD0D0bar"), d0d0bar.mLambda(), d0d0bar.pt()); - if (d0d0bar.mLambda() > ConfDmesons.ConfMinInvMassD0D0bar && d0d0bar.mLambda() < ConfDmesons.ConfMaxInvMassD0D0bar) { - registry.fill(HIST("hInvMassD0"), d0d0bar.mLambda()); - } + registry.fill(HIST("D0D0bar_oneMassHypo/hMassVsPt"), d0d0bar.mLambda(), d0d0bar.pt()); + registry.fill(HIST("D0D0bar_oneMassHypo/hMassVsPtD0"), d0d0bar.mLambda(), d0d0bar.pt()); + registry.fill(HIST("D0D0bar_oneMassHypo/hMassVsPtReflected"), std::abs(d0d0bar.mAntiLambda()), d0d0bar.pt()); + registry.fill(HIST("D0D0bar_oneMassHypo/hMassVsPtD0Reflected"), std::abs(d0d0bar.mAntiLambda()), d0d0bar.pt()); + registry.fill(HIST("hInvMassD0"), d0d0bar.mLambda()); registry.fill(HIST("hPtD0"), d0d0bar.pt()); registry.fill(HIST("hPhiD0"), d0d0bar.phi()); registry.fill(HIST("hEtaD0"), d0d0bar.eta()); } if (d0d0bar.mLambda() < 0.0f && d0d0bar.mAntiLambda() > 0.0f) { - registry.fill(HIST("hInvMassVsPtOnlyD0D0bar"), d0d0bar.mAntiLambda(), d0d0bar.pt()); - if (d0d0bar.mAntiLambda() > ConfDmesons.ConfMinInvMassD0D0bar && d0d0bar.mAntiLambda() < ConfDmesons.ConfMaxInvMassD0D0bar) { - registry.fill(HIST("hInvMassD0bar"), d0d0bar.mAntiLambda()); - } + registry.fill(HIST("D0D0bar_oneMassHypo/hMassVsPt"), d0d0bar.mAntiLambda(), d0d0bar.pt()); + registry.fill(HIST("D0D0bar_oneMassHypo/hMassVsPtD0bar"), d0d0bar.mAntiLambda(), d0d0bar.pt()); + registry.fill(HIST("D0D0bar_oneMassHypo/hMassVsPtReflected"), std::abs(d0d0bar.mLambda()), d0d0bar.pt()); + registry.fill(HIST("D0D0bar_oneMassHypo/hMassVsPtD0barReflected"), std::abs(d0d0bar.mLambda()), d0d0bar.pt()); + registry.fill(HIST("hInvMassD0bar"), d0d0bar.mAntiLambda()); registry.fill(HIST("hPtD0bar"), d0d0bar.pt()); registry.fill(HIST("hPhiD0bar"), d0d0bar.phi()); registry.fill(HIST("hEtaD0bar"), d0d0bar.eta()); @@ -422,65 +751,34 @@ struct femtoUniversePairTaskTrackD0 { // loop over D mesons childen for (auto const& daughD0D0bar : groupPartsD0D0barChildren) { registry.fill(HIST("hPtDaughters"), daughD0D0bar.pt()); - } - } - PROCESS_SWITCH(femtoUniversePairTaskTrackD0, processD0mesons, "Enable processing D0 mesons", true); - - // D0-D0bar pair correlations (side-band methode) - void processSideBand(o2::aod::FDCollision& col, FemtoFullParticles&) - { - auto groupPartsOnlyD0D0bar = partsOnlyD0D0bar->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - - double deltaPhi = 0.0; - double deltaEta = 0.0; - - // loop over D0/D0bar candidates (ONLY) - for (auto const& cand1 : groupPartsOnlyD0D0bar) { - // Check if the first candidate is D0 meson - if (cand1.mLambda() < 0.0f && cand1.mAntiLambda() > 0.0f) { - continue; + registry.fill(HIST("hSignDaughters"), daughD0D0bar.mLambda()); + // filling QA plots for D0 mesons' positive daughters (K+) + if (daughD0D0bar.mLambda() == 1 && daughD0D0bar.mAntiLambda() == 1) { + qaRegistry.fill(HIST("D0_pos_daugh/pt"), daughD0D0bar.pt()); + qaRegistry.fill(HIST("D0_pos_daugh/eta"), daughD0D0bar.eta()); + qaRegistry.fill(HIST("D0_pos_daugh/phi"), daughD0D0bar.phi()); } - - for (auto const& cand2 : groupPartsOnlyD0D0bar) { - // Check if the second candidate is D0bar meson - if (cand2.mLambda() > 0.0f && cand2.mAntiLambda() < 0.0f) { - continue; - } - deltaPhi = getDeltaPhi(cand1.phi(), cand2.phi()); - deltaEta = cand2.eta() - cand1.eta(); - - // General histograms - registry.fill(HIST("hPtCand1VsPtCand2"), cand1.pt(), cand2.pt()); - registry.fill(HIST("hDeltaEtaDeltaPhi"), deltaEta, deltaPhi); - - // ----------------------------------- Creating D0-D0bar pairs correlations ------------------------------------------------ - if (cand1.mLambda() > ConfD0D0barSideBand.ConfSignalRegionMin.value && cand1.mLambda() < ConfD0D0barSideBand.ConfSignalRegionMax.value) { - // S(D0) x S(D0bar) correlation - if (cand2.mAntiLambda() > ConfD0D0barSideBand.ConfSignalRegionMin.value && cand2.mAntiLambda() < ConfD0D0barSideBand.ConfSignalRegionMax.value) { - registry.fill(HIST("hDeltaPhiSigSig"), deltaPhi); - } - // S(D0) x B(D0bar) correlation - if ((cand2.mAntiLambda() > ConfD0D0barSideBand.ConfMinInvMassLeftSB.value && cand2.mAntiLambda() < ConfD0D0barSideBand.ConfMaxInvMassLeftSB.value) || - (cand2.mAntiLambda() > ConfD0D0barSideBand.ConfMinInvMassRightSB.value && cand2.mAntiLambda() < ConfD0D0barSideBand.ConfMaxInvMassRightSB.value)) { - registry.fill(HIST("hDeltaPhiD0SigD0barBg"), deltaPhi); - } - } - if ((cand1.mLambda() > ConfD0D0barSideBand.ConfMinInvMassLeftSB.value && cand1.mLambda() < ConfD0D0barSideBand.ConfMaxInvMassLeftSB.value) || - (cand1.mLambda() > ConfD0D0barSideBand.ConfMinInvMassRightSB.value && cand1.mLambda() < ConfD0D0barSideBand.ConfMaxInvMassRightSB.value)) { - // B(D0) x S (D0bar) correlation - if (cand2.mAntiLambda() > ConfD0D0barSideBand.ConfSignalRegionMin.value && cand2.mAntiLambda() < ConfD0D0barSideBand.ConfSignalRegionMax.value) { - registry.fill(HIST("hDeltaPhiD0BgD0barSig"), deltaPhi); - } - // B(D0) x B(D0bar) correlation - if ((cand2.mAntiLambda() > ConfD0D0barSideBand.ConfMinInvMassLeftSB.value && cand2.mAntiLambda() < ConfD0D0barSideBand.ConfMaxInvMassLeftSB.value) || - (cand2.mAntiLambda() > ConfD0D0barSideBand.ConfMinInvMassRightSB.value && cand2.mAntiLambda() < ConfD0D0barSideBand.ConfMaxInvMassRightSB.value)) { - registry.fill(HIST("hDeltaPhiBgBg"), deltaPhi); - } - } - } // It is the end of the for loop over D0bar mesons - } // It is the end of the for loop over all candidates + // filling QA plots for D0 mesons' negative daughters (pi-) + if (daughD0D0bar.mLambda() == -1 && daughD0D0bar.mAntiLambda() == 1) { + qaRegistry.fill(HIST("D0_neg_daugh/pt"), daughD0D0bar.pt()); + qaRegistry.fill(HIST("D0_neg_daugh/eta"), daughD0D0bar.eta()); + qaRegistry.fill(HIST("D0_neg_daugh/phi"), daughD0D0bar.phi()); + } + // filling QA plots for D0bar mesons' positive daughters (pi+) + if (daughD0D0bar.mLambda() == 1 && daughD0D0bar.mAntiLambda() == -1) { + qaRegistry.fill(HIST("D0bar_pos_daugh/pt"), daughD0D0bar.pt()); + qaRegistry.fill(HIST("D0bar_pos_daugh/eta"), daughD0D0bar.eta()); + qaRegistry.fill(HIST("D0bar_pos_daugh/phi"), daughD0D0bar.phi()); + } + // filling QA plots for D0bar mesons' negative daughters (K-) + if (daughD0D0bar.mLambda() == -1 && daughD0D0bar.mAntiLambda() == -1) { + qaRegistry.fill(HIST("D0bar_neg_daugh/pt"), daughD0D0bar.pt()); + qaRegistry.fill(HIST("D0bar_neg_daugh/eta"), daughD0D0bar.eta()); + qaRegistry.fill(HIST("D0bar_neg_daugh/phi"), daughD0D0bar.phi()); + } + } } - PROCESS_SWITCH(femtoUniversePairTaskTrackD0, processSideBand, "Enable processing side-band methode", false); + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processD0mesons, "Enable processing D0 mesons", true); /// This function processes the same event and takes care of all the histogramming /// \todo the trivial loops over the tracks should be factored out since they will be common to all combinations of T-T, T-V0, V0-V0, ... @@ -497,79 +795,151 @@ struct femtoUniversePairTaskTrackD0 { { /// Histogramming same event - for (auto& d0candidate : groupPartsD0) { + for (auto const& d0candidate : groupPartsD0) { trackHistoPartD0D0bar.fillQA(d0candidate); } - if (!ConfTrack.ConfIsSame) { - for (auto& track : groupPartsTrack) { - if (ConfTrack.ConfIsTrackIdentified) { - if (!IsParticleNSigma(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { + float tpcNSigmaPr, tofNSigmaPr, tpcNSigmaPi, tofNSigmaPi, tpcNSigmaKa, tofNSigmaKa; + + if (!ConfTrack.confIsSame) { + for (auto const& track : groupPartsTrack) { + if (ConfTrack.confIsTrackIdentified) { + if (!isParticleNSigma(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { continue; } } trackHistoPartTrack.fillQA(track); + + tpcNSigmaPi = trackCuts.getNsigmaTPC(track, o2::track::PID::Pion); + tofNSigmaPi = trackCuts.getNsigmaTOF(track, o2::track::PID::Pion); + tpcNSigmaKa = trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon); + tofNSigmaKa = trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon); + tpcNSigmaPr = trackCuts.getNsigmaTPC(track, o2::track::PID::Proton); + tofNSigmaPr = trackCuts.getNsigmaTOF(track, o2::track::PID::Proton); + + qaRegistry.fill(HIST("Hadron/nSigmaTPCPi"), track.p(), tpcNSigmaPi); + qaRegistry.fill(HIST("Hadron/nSigmaTOFPi"), track.p(), tofNSigmaPi); + qaRegistry.fill(HIST("Hadron/nSigmaTPCKa"), track.p(), tpcNSigmaKa); + qaRegistry.fill(HIST("Hadron/nSigmaTOFKa"), track.p(), tofNSigmaKa); + qaRegistry.fill(HIST("Hadron/nSigmaTPCPr"), track.p(), tpcNSigmaPr); + qaRegistry.fill(HIST("Hadron/nSigmaTOFPr"), track.p(), tofNSigmaPr); } } /// Now build the combinations - for (auto& [track, d0candidate] : combinations(CombinationsFullIndexPolicy(groupPartsTrack, groupPartsD0))) { - if (ConfTrack.ConfIsTrackIdentified) { - if (!IsParticleNSigma(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { + for (auto const& [track, d0candidate] : combinations(CombinationsFullIndexPolicy(groupPartsTrack, groupPartsD0))) { + if (ConfTrack.confIsTrackIdentified) { + if (!isParticleNSigma(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { + continue; + } + } + // Soft Pion Removal + if (confRemoveSoftPions) { + if (softPionRemoval.isSoftPion(track, d0candidate, parts, confSoftPionD0Flag, confSoftPionD0barFlag, sigmaSoftPiInvMass)) { continue; } } // // Close Pair Rejection - if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(track, d0candidate, parts, magFieldTesla, femtoUniverseContainer::EventType::same)) { + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(track, d0candidate, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } } - // Track Cleaning if (!pairCleaner.isCleanPair(track, d0candidate, parts)) { continue; } - sameEventFemtoCont.setPair(track, d0candidate, multCol, ConfBothTracks.ConfUse3D); - sameEventAngularCont.setPair(track, d0candidate, multCol, ConfBothTracks.ConfUse3D); + // Efficiency + weight = 1.0f; + if (ConfEff.doEfficiencyCorr) { + weight = efficiencyCalculator.getWeight(ParticleNo::ONE, track.pt()) * efficiencyCalculator.getWeight(ParticleNo::TWO, d0candidate.pt()); + } + sameEventAngularCont.setPair(track, d0candidate, multCol, ConfBothTracks.confUse3D, weight); } } /// process function for to call doSameEvent with Data + /// call this process function if you need D0/D0bar candidates which pass only one mass hypothesis /// \param col subscribe to the collision table (Data) /// \param parts subscribe to the femtoUniverseParticleTable - void processSameEvent(o2::aod::FDCollision& col, - FemtoFullParticles& parts) + void processSameEvent(o2::aod::FdCollision const& col, + FemtoFullParticles const& parts) { fillCollision(col); auto thegroupPartsTrack = partsTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto thegroupPartsAllD0D0bar = partsAllDmesons->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto thegroupPartsOnlyD0D0bar = partsOnlyD0D0bar->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto theGroupPartsD0s = partsD0s->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto theGroupPartsD0bars = partsD0bars->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - if (ConfUseAllD0mesons) { - doSameEvent(thegroupPartsTrack, thegroupPartsAllD0D0bar, parts, col.magField(), col.multNtr()); - } else { - doSameEvent(thegroupPartsTrack, thegroupPartsOnlyD0D0bar, parts, col.magField(), col.multNtr()); + switch (confChooseD0trackCorr) { + case 0: + doSameEvent(thegroupPartsTrack, theGroupPartsD0s, parts, col.magField(), col.multNtr()); + break; + case 1: + doSameEvent(thegroupPartsTrack, theGroupPartsD0bars, parts, col.magField(), col.multNtr()); + break; + default: + break; + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processSameEvent, "Enable processing same event", true); + + /// process function for to call doSameEvent with Data + /// call this process function to include candidates which pass as well the selection for both D0 and D0bar candidates + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoUniverseParticleTable + void processSameEventWithDoubleHypo(o2::aod::FdCollision const& col, + FemtoFullParticles const& parts) + { + fillCollision(col); + + auto thegroupPartsTrack = partsTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto theGroupPartsD0s = partsAllD0s->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto theGroupPartsD0bars = partsAllD0bars->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + switch (confChooseD0trackCorr) { + case 0: + doSameEvent(thegroupPartsTrack, theGroupPartsD0s, parts, col.magField(), col.multNtr()); + break; + case 1: + doSameEvent(thegroupPartsTrack, theGroupPartsD0bars, parts, col.magField(), col.multNtr()); + break; + default: + break; } } - PROCESS_SWITCH(femtoUniversePairTaskTrackD0, processSameEvent, "Enable processing same event", true); + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processSameEventWithDoubleHypo, "Enable processing same event", false); + + /// process function for to call doSameEvent with Data + /// call this process to obtain the function for D0/D0bar candidates from side-band regions + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoUniverseParticleTable + void processSameEventSB(o2::aod::FdCollision const& col, FemtoFullParticles const& parts) + { + fillCollision(col); + + auto groupPartsTrack = partsTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto groupPartsD0sFromSB = partsD0sFromSB->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + doSameEvent(groupPartsTrack, groupPartsD0sFromSB, parts, col.magField(), col.multNtr()); + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processSameEventSB, "Enable processing same event", false); /// process function for to call doSameEvent with Monte Carlo /// \param col subscribe to the collision table (Monte Carlo Reconstructed reconstructed) /// \param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth /// \param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table - void processSameEventMC(o2::aod::FDCollision& col, - soa::Join& parts, - o2::aod::FDMCParticles&) + void processSameEventMC(o2::aod::FdCollision const& col, + soa::Join const& parts, + o2::aod::FdMCParticles const&) { fillCollision(col); - auto thegroupPartsD0 = partsD0D0barMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto thegroupPartsTrack = partsTrackMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegroupPartsD0 = partsD0D0barMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegroupPartsTrack = partsTrackMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); doSameEvent(thegroupPartsTrack, thegroupPartsD0, parts, col.magField(), col.multNtr()); } - PROCESS_SWITCH(femtoUniversePairTaskTrackD0, processSameEventMC, "Enable processing same event for Monte Carlo", false); + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processSameEventMC, "Enable processing same event for Monte Carlo", false); /// This function processes the mixed event /// \todo the trivial loops over the collisions and tracks should be factored out since they will be common to all combinations of T-T, T-V0, V0-V0, ... @@ -585,37 +955,53 @@ struct femtoUniversePairTaskTrackD0 { void doMixedEvent(PartitionType groupPartsTrack, PartitionType groupPartsD0, PartType parts, float magFieldTesla, int multCol) { - for (auto& [track, d0candidate] : combinations(CombinationsFullIndexPolicy(groupPartsTrack, groupPartsD0))) { - if (ConfTrack.ConfIsTrackIdentified) { - if (!IsParticleNSigma(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { + for (auto const& [track, d0candidate] : combinations(CombinationsFullIndexPolicy(groupPartsTrack, groupPartsD0))) { + if (ConfTrack.confIsTrackIdentified) { + if (!isParticleNSigma(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { + continue; + } + } + // // Soft Pion Removal + if (confRemoveSoftPions) { + if (softPionRemoval.isSoftPion(track, d0candidate, parts, confSoftPionD0Flag, confSoftPionD0barFlag, sigmaSoftPiInvMass)) { continue; } } - if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(track, d0candidate, parts, magFieldTesla, femtoUniverseContainer::EventType::mixed)) { + // // Close Pair Rejection + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(track, d0candidate, parts, magFieldTesla, femto_universe_container::EventType::mixed)) { continue; } } + // // Track Cleaning + if (!pairCleaner.isCleanPair(track, d0candidate, parts)) { + continue; + } + // Efficiency + weight = 1.0f; + if (ConfEff.doEfficiencyCorr) { + weight = efficiencyCalculator.getWeight(ParticleNo::ONE, track.pt()) * efficiencyCalculator.getWeight(ParticleNo::TWO, d0candidate.pt()); + } - mixedEventFemtoCont.setPair(track, d0candidate, multCol, ConfBothTracks.ConfUse3D); - mixedEventAngularCont.setPair(track, d0candidate, multCol, ConfBothTracks.ConfUse3D); + mixedEventAngularCont.setPair(track, d0candidate, multCol, ConfBothTracks.confUse3D, weight); } } /// process function for to call doMixedEvent with Data + /// call this process function if you need D0/D0bar candidates which pass only one mass hypothesis /// @param cols subscribe to the collisions table (Data) /// @param parts subscribe to the femtoUniverseParticleTable - void processMixedEvent(o2::aod::FDCollisions& cols, - FemtoFullParticles& parts) + void processMixedEvent(o2::aod::FdCollisions const& cols, + FemtoFullParticles const& parts) { - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + for (auto const& [collision1, collision2] : soa::selfCombinations(colBinning, confNEventsMix, -1, cols, cols)) { const int multiplicityCol = collision1.multNtr(); - MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); auto groupPartsTrack = partsTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); - auto groupPartsAllD0D0bar = partsAllDmesons->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); - auto groupPartsOnlyD0D0bar = partsOnlyD0D0bar->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto theGroupPartsD0s = partsD0s->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto theGroupPartsD0bars = partsD0bars->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); const auto& magFieldTesla1 = collision1.magField(); const auto& magFieldTesla2 = collision2.magField(); @@ -624,32 +1010,104 @@ struct femtoUniversePairTaskTrackD0 { continue; } /// \todo before mixing we should check whether both collisions contain a pair of particles! - // if (partsD0.size() == 0 || nPart2Evt1 == 0 || nPart1Evt2 == 0 || partsTrack.size() == 0 ) continue; + // if (partsD0.size() == 0 || kNPart2Evt1 == 0 || kNPart1Evt2 == 0 || partsTrack.size() == 0 ) continue; + + switch (confChooseD0trackCorr) { + case 0: + doMixedEvent(groupPartsTrack, theGroupPartsD0s, parts, magFieldTesla1, multiplicityCol); + break; + case 1: + doMixedEvent(groupPartsTrack, theGroupPartsD0bars, parts, magFieldTesla1, multiplicityCol); + break; + default: + break; + } + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processMixedEvent, "Enable processing mixed events", true); - if (ConfUseAllD0mesons) { - doMixedEvent(groupPartsTrack, groupPartsAllD0D0bar, parts, magFieldTesla1, multiplicityCol); - } else { - doMixedEvent(groupPartsTrack, groupPartsOnlyD0D0bar, parts, magFieldTesla1, multiplicityCol); + /// process function for to call doMixedEvent with Data + /// call this process function to include candidates which pass as well the selection for both D0 and D0bar candidates + /// @param cols subscribe to the collisions table (Data) + /// @param parts subscribe to the femtoUniverseParticleTable + void processMixedEventWithDoubleHypo(o2::aod::FdCollisions const& cols, + FemtoFullParticles const& parts) + { + for (auto const& [collision1, collision2] : soa::selfCombinations(colBinning, confNEventsMix, -1, cols, cols)) { + + const int multiplicityCol = collision1.multNtr(); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + + auto groupPartsTrack = partsTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + auto theGroupPartsD0s = partsAllD0s->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto theGroupPartsD0bars = partsAllD0bars->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + continue; + } + /// \todo before mixing we should check whether both collisions contain a pair of particles! + // if (partsD0.size() == 0 || kNPart2Evt1 == 0 || kNPart1Evt2 == 0 || partsTrack.size() == 0 ) continue; + + switch (confChooseD0trackCorr) { + case 0: + doMixedEvent(groupPartsTrack, theGroupPartsD0s, parts, magFieldTesla1, multiplicityCol); + break; + case 1: + doMixedEvent(groupPartsTrack, theGroupPartsD0bars, parts, magFieldTesla1, multiplicityCol); + break; + default: + break; + } + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processMixedEventWithDoubleHypo, "Enable processing mixed events", false); + + /// process function for to call doMixedEvent with Data + /// call this process to obtain the function for D0/D0bar candidates from side-band regions + /// @param cols subscribe to the collisions table (Data) + /// @param parts subscribe to the femtoUniverseParticleTable + void processMixedEventSB(o2::aod::FdCollisions const& cols, FemtoFullParticles const& parts) + { + for (auto const& [collision1, collision2] : soa::selfCombinations(colBinning, confNEventsMix, -1, cols, cols)) { + + const int multiplicityCol = collision1.multNtr(); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + + auto groupPartsTrack = partsTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + auto groupPartsD0sFromSB = partsD0sFromSB->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + continue; } + /// \todo before mixing we should check whether both collisions contain a pair of particles! + // if (partsD0.size() == 0 || kNPart2Evt1 == 0 || kNPart1Evt2 == 0 || partsTrack.size() == 0 ) continue; + + doMixedEvent(groupPartsTrack, groupPartsD0sFromSB, parts, magFieldTesla1, multiplicityCol); } } - PROCESS_SWITCH(femtoUniversePairTaskTrackD0, processMixedEvent, "Enable processing mixed events", true); + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processMixedEventSB, "Enable processing mixed events", false); /// brief process function for to call doMixedEvent with Monte Carlo /// @param cols subscribe to the collisions table (Monte Carlo Reconstructed reconstructed) /// @param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth /// @param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table - void processMixedEventMC(o2::aod::FDCollisions& cols, - soa::Join& parts, - o2::aod::FDMCParticles&) + void processMixedEventMC(o2::aod::FdCollisions const& cols, + soa::Join const& parts, + o2::aod::FdMCParticles const&) { - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + for (auto const& [collision1, collision2] : soa::selfCombinations(colBinning, confNEventsMix, -1, cols, cols)) { const int multiplicityCol = collision1.multNtr(); - MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); - auto groupPartsTrack = partsTrackMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); - auto groupPartsD0 = partsD0D0barMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTrack = partsTrackMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + auto groupPartsD0 = partsD0D0barMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); const auto& magFieldTesla1 = collision1.magField(); const auto& magFieldTesla2 = collision2.magField(); @@ -658,18 +1116,78 @@ struct femtoUniversePairTaskTrackD0 { continue; } /// \todo before mixing we should check whether both collisions contain a pair of particles! - // if (partsD0.size() == 0 || nPart2Evt1 == 0 || nPart1Evt2 == 0 || partsTrack.size() == 0 ) continue; + // if (partsD0.size() == 0 || kNPart2Evt1 == 0 || kNPart1Evt2 == 0 || partsTrack.size() == 0 ) continue; doMixedEvent(groupPartsTrack, groupPartsD0, parts, magFieldTesla1, multiplicityCol); } } - PROCESS_SWITCH(femtoUniversePairTaskTrackD0, processMixedEventMC, "Enable processing mixed events MC", false); + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processMixedEventMC, "Enable processing mixed events MC", false); + + void processMCReco(FemtoMCParticles const&, aod::FdMCParticles const&) + { + // WORK IN PROGRESS + // for (auto const& part : parts) {} + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processMCReco, "Process MC reco data", false); + + void processMCTruth(aod::FDParticles const& parts) // WORK IN PROGRESS + { + for (auto const& part : parts) { + if (part.partType() != uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) + continue; + + int pdgCode = static_cast(part.pidCut()); + const auto& pdgParticle = pdgMC->GetParticle(pdgCode); + if (!pdgParticle) { + continue; + } + + if (pdgParticle->Charge() > 0.0) { + mcTruthRegistry.fill(HIST("MCTruthAllPositivePt"), part.pt()); + } + if (pdgCode == 211) { + mcTruthRegistry.fill(HIST("MCTruthPipPtVsEta"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("MCTruthPipPt"), part.pt()); + } + if (pdgCode == 321) { + mcTruthRegistry.fill(HIST("MCTruthKpPtVsEta"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("MCTruthKpPt"), part.pt()); + } + if (pdgCode == 421) { + mcTruthRegistry.fill(HIST("MCTruthD0D0bar"), part.pt(), part.eta()); + } + if (pdgCode == 2212) { + mcTruthRegistry.fill(HIST("MCTruthProtonPtVsEta"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("MCTruthProtonPt"), part.pt()); + } + + if (pdgParticle->Charge() < 0.0) { + mcTruthRegistry.fill(HIST("MCTruthAllNegativePt"), part.pt()); + } + if (pdgCode == -211) { + mcTruthRegistry.fill(HIST("MCTruthPimPtVsEta"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("MCTruthPimPt"), part.pt()); + } + if (pdgCode == -321) { + mcTruthRegistry.fill(HIST("MCTruthKmPtVsEta"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("MCTruthKmPt"), part.pt()); + } + if (pdgCode == -421) { + mcTruthRegistry.fill(HIST("MCTruthD0D0bar"), part.pt(), part.eta()); + } + if (pdgCode == -2212) { + mcTruthRegistry.fill(HIST("MCTruthAntiProtonPtVsEta"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("MCTruthAntiProtonPt"), part.pt()); + } + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processMCTruth, "Process MC truth data", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow{ - adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), }; return workflow; } diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackNucleus.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackNucleus.cxx new file mode 100644 index 00000000000..2fc7a7cf2fa --- /dev/null +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackNucleus.cxx @@ -0,0 +1,846 @@ +// Copyright 2019-2022 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 femtoUniversePairTaskTrackNucleus.cxx +/// \brief Tasks that reads the track tables used for the pairing and builds pairs of a track and a nucleus +/// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de +/// \author Georgios Mantzaridis, TU München, georgios.mantzaridis@tum.de +/// \author Anton Riedel, TU München, anton.riedel@tum.de +/// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch +/// \author Alicja Płachta, WUT Warsaw, alicja.plachta.stud@pw.edu.pl +/// \author Anna-Mariia Andrushko, WUT Warsaw, anna-mariia.andrushko@cern.ch + +#include +#include +#include +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "ReconstructionDataFormats/PID.h" +#include "Common/DataModel/PIDResponse.h" + +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseFemtoContainer.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairWithCentMultKt.h" + +using namespace o2; +using namespace o2::analysis::femto_universe; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +namespace +{ +static constexpr int Npart = 2; +static constexpr int Ncuts = 5; +static const std::vector partNames{"Track", "Nucleus"}; +static const std::vector cutNames{"MaxPt", "PIDthr", "nSigmaTPC", "nSigmaTPCTOF", "MaxP"}; +static const float cutsTable[Npart][Ncuts]{{4.05f, 1.f, 3.f, 3.f, 100.f}, {4.05f, 1.f, 3.f, 3.f, 100.f}}; +} // namespace + +struct FemtoUniversePairTaskTrackNucleus { + + Service pdg; + + /// Selection part + + /// Table for both objects + struct : o2::framework::ConfigurableGroup { + Configurable isKaonNsigma{"isKaonNsigma", false, "Enable a strict cut selection for K+ and K-"}; + Configurable confNsigmaCombined{"confNsigmaCombined", 3.0f, "TPC and TOF Pion Sigma (combined) for momentum > confTOFpMin"}; + Configurable confNsigmaTPC{"confNsigmaTPC", 3.0f, "TPC Pion Sigma for momentum < confTOFpMin"}; + Configurable confTOFpMin{"confTOFpMin", 0.45f, "Min. momentum for which TOF is required for PID."}; + Configurable confEtaMax{"confEtaMax", 0.8f, "Higher limit for |Eta| (the same for both particles)"}; + + Configurable> confCutTable{"confCutTable", {cutsTable[0], Npart, Ncuts, partNames, cutNames}, "Particle selections"}; + Configurable confNspecies{"confNspecies", 2, "Number of particle spieces with PID info"}; + Configurable confIsMC{"confIsMC", false, "Enable additional Histogramms in the case of a MonteCarlo Run"}; + Configurable> confTrkPIDNsigmaMax{"confTrkPIDNsigmaMax", std::vector{4.f, 3.f, 2.f}, "This configurable needs to be the same as the one used in the producer task"}; + Configurable confUse3D{"confUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; + } twoobjectsconfigs; + + /// Table for separate deuteron configurables + struct : o2::framework::ConfigurableGroup { + Configurable confNsigmaTPCDe{"confNsigmaTPCDe", 2.0f, "TPC Deuteron Sigma for momentum < confTOFpMinDe"}; + Configurable confNsigmaTOFDe{"confNsigmaTOFDe", 2.0f, "TOF Deuteron Sigma"}; + Configurable confTOFpMinDe{"confTOFpMinDe", 1.0f, "Min. momentum for deuterons for which TOF is required for PID"}; + Configurable confPlowDe{"confPlowDe", 0.8f, "Lower limit for momentum for deuterons"}; + Configurable confPhighDe{"confPhighDe", 1.8f, "Higher limit for momentum for deuterons"}; + } deuteronconfigs; + + /// Table for linear cut for TPC Deuteron Sigma + struct : o2::framework::ConfigurableGroup { + Configurable confIsLine{"confIsLine", false, "Enable a separation line for clearer TPC Deuteron Sigma"}; + Configurable linCutPlow{"linCutPlow", 0.0f, "Lower limit of momentum for linear cut of TPC Deuteron Sigma"}; + Configurable linCutPhigh{"linCutPhigh", 1.4f, "Higher limit of momentum for linear cut of TPC Deuteron Sigma"}; + Configurable linCutParA{"linCutParA", -167.0f, "Parameter 'A' of the linear function 'y = A * x + B'"}; + Configurable linCutParB{"linCutParB", 300.0f, "Parameter 'B' of the linear function 'y = A * x + B'"}; + } lincut; + + /// Table for polynomial 3 cut for TPC Deuteron Sigma + struct : o2::framework::ConfigurableGroup { + Configurable confIsPol3{"confIsPol3", false, "Enable a separation polynomial 3 curve for clearer TPC Deuteron Sigma"}; + Configurable polCutParA{"polCutParA", -52.2f, "Parameter 'A' of the polynomial function 'y = A * x^3 + B * x^2 + C * x + D'"}; + Configurable polCutParB{"polCutParB", 357.7f, "Parameter 'B' of the polynomial function 'y = A * x^3 + B * x^2 + C * x + D'"}; + Configurable polCutParC{"polCutParC", -834.7f, "Parameter 'C' of the polynomial function 'y = A * x^3 + B * x^2 + C * x + D'"}; + Configurable polCutParD{"polCutParD", 705.8f, "Parameter 'D' of the polynomial function 'y = A * x^3 + B * x^2 + C * x + D'"}; + } polcut; + + using FemtoFullParticles = soa::Join; + + // Filters for selection + Filter trackAdditionalfilter = (nabs(aod::femtouniverseparticle::eta) < twoobjectsconfigs.confEtaMax); // example filtering on configurable + using FilteredFemtoFullParticles = soa::Filtered; + // using FilteredFemtoFullParticles = FemtoFullParticles; //if no filtering is applied uncomment this option + + SliceCache cache; + Preslice perCol = aod::femtouniverseparticle::fdCollisionId; + + /// Track + struct : o2::framework::ConfigurableGroup { + Configurable confPDGCodeTrack{"confPDGCodeTrack", 321, "Track -- PDG code"}; + // Configurable confCutTrack{"confCutTrack", 5542474, "Track -- Selection bit from cutCulator"}; + Configurable confPIDTrack{"confPIDTrack", 3, "Track -- Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector>int>> + Configurable confPtLowTrack{"confPtLowTrack", 0.14, "Lower pT limit for track"}; + Configurable confPtHighTrack{"confPtHighTrack", 1.5, "Higher pT limit for track"}; + Configurable confChargeTrack{"confChargeTrack", 1, "Track sign"}; // -1 means anti-particle + } trackfilter; + + /// Partition for track + Partition partTrack = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == trackfilter.confChargeTrack && aod::femtouniverseparticle::pt < trackfilter.confPtHighTrack && aod::femtouniverseparticle::pt > trackfilter.confPtLowTrack; + + Partition> partTrackMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == trackfilter.confChargeTrack && aod::femtouniverseparticle::pt < trackfilter.confPtHighTrack && aod::femtouniverseparticle::pt > trackfilter.confPtLowTrack; + + /// Histogramming for track + FemtoUniverseParticleHisto trackHistoTrack; + + /// Nucleus + struct : o2::framework::ConfigurableGroup { + Configurable confPDGCodeNucleus{"confPDGCodeNucleus", 1000010020, "Nucleus -- PDG code"}; + // Configurable confCutNucleus{"confCutNucleus", 5542474, "Nucleus -- Selection bit"}; + Configurable confPIDNucleus{"confPIDNucleus", 5, "Nucleus -- Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector> + Configurable confPtLowNucleus{"confPtLowNucleus", 0, "Lower pT limit for nucleus"}; + Configurable confPtHighNucleus{"confPtHighNucleus", 5, "Higher pT limit for nucleus"}; + Configurable confChargeNucleus{"confChargeNucleus", 1, "Nucleus sign"}; // -1 means anti-nucleus + } nucleusfilter; + + /// Partition for nucleus + Partition partNucleus = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == nucleusfilter.confChargeNucleus) && aod::femtouniverseparticle::pt < nucleusfilter.confPtHighNucleus && aod::femtouniverseparticle::pt > nucleusfilter.confPtLowNucleus; + + Partition> partNucleusMC = aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack) && (aod::femtouniverseparticle::sign == nucleusfilter.confChargeNucleus) && aod::femtouniverseparticle::pt < nucleusfilter.confPtHighNucleus && aod::femtouniverseparticle::pt > nucleusfilter.confPtLowNucleus; + + /// Histogramming for nucleus + FemtoUniverseParticleHisto trackHistoNucleus; + + /// Histogramming for Event + FemtoUniverseEventHisto eventHisto; + + /// The configurables need to be passed to an std::vector + int vPIDTrack, vPIDNucleus; + std::vector kNsigma; + + /// Event part + Configurable confV0Mlow{"confV0Mlow", 0.0, "Lower limit for V0M multiplicity"}; + Configurable confV0Mhigh{"confV0Mhigh", 25000.0, "Upper limit for V0M multiplicity"}; + Configurable confSphericityCutMin{"confSphericityCutMin", 0, "Min. sphericity"}; + Configurable confSphericityCutMax{"confSphericityCutMax", 3, "Max. sphericity"}; + + Filter collV0Mfilter = ((o2::aod::femtouniversecollision::multV0M > confV0Mlow) && (o2::aod::femtouniversecollision::multV0M < confV0Mhigh)); + Filter colSpherfilter = ((o2::aod::femtouniversecollision::sphericity > confSphericityCutMin) && (o2::aod::femtouniversecollision::sphericity < confSphericityCutMax)); + // Filter trackAdditionalfilter = (nabs(aod::femtouniverseparticle::eta) < twoobjectsconfigs.confEtaMax); // example filtering on configurable + + /// Particle part + ConfigurableAxis confTempFitVarBins{"confTempFitVarBins", {300, -0.15, 0.15}, "Binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis confTempFitVarPtBins{"confTempFitVarPtBins", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; + + /// Correlation part + ConfigurableAxis confMultBins{"confMultBins", {VARIABLE_WIDTH, 0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 99999.f}, "Mixing bins -- multiplicity or centrality"}; // \todo to be obtained from the hash task + ConfigurableAxis confMultKstarBins{"confMultKstarBins", {VARIABLE_WIDTH, 0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 100.0f, 99999.f}, "Bins for kstar analysis in multiplicity or centrality bins (10 is maximum)"}; + ConfigurableAxis confKtKstarBins{"confKtKstarBins", {VARIABLE_WIDTH, 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f, 2.0f, 99999.f}, "Bins for kstar analysis in kT bins (10 is maximum)"}; + ConfigurableAxis confVtxBins{"confVtxBins", {VARIABLE_WIDTH, -10.0f, 10.f}, "Mixing bins -- z-vertex"}; + + ConfigurableAxis confMtBins3D{"confMtBins3D", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + ConfigurableAxis confMultBins3D{"confMultBins3D", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "Multiplicity binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + + ColumnBinningPolicy colBinning{{confVtxBins, confMultBins}, true}; + + ConfigurableAxis confKstarBins{"confKstarBins", {1500, 0., 6.}, "Binning kstar"}; + ConfigurableAxis confKtBins{"confKtBins", {150, 0., 9.}, "Binning kT"}; + ConfigurableAxis confMtBins{"confMtBins", {225, 0., 7.5}, "Binning mT"}; + Configurable confNEventsMix{"confNEventsMix", 5, "Number of events for mixing"}; + Configurable confIsCPR{"confIsCPR", true, "Close Pair Rejection"}; + Configurable confCPRPlotPerRadii{"confCPRPlotPerRadii", false, "Plot CPR per radii"}; + Configurable confCPRDeltaPhiCutMax{"confCPRDeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; + Configurable confCPRDeltaPhiCutMin{"confCPRDeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; + Configurable confCPRDeltaEtaCutMax{"confCPRDeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; + Configurable confCPRDeltaEtaCutMin{"confCPRDeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; + Configurable confCPRChosenRadii{"confCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; + + Configurable cfgProcessPP{"cfgProcessPP", true, "Process positively charged particles (plus-plus)"}; + Configurable cfgProcessMM{"cfgProcessMM", true, "Process negatively charged particles (minus-minus)"}; + Configurable cfgProcessPM{"cfgProcessPM", false, "Process differently charged particles (plus-minus)"}; + Configurable cfgProcessMP{"cfgProcessMP", false, "Process differently charged particles (minus-plus)"}; + Configurable cfgProcessMultBins{"cfgProcessMultBins", true, "Process kstar histograms (in multiplicity bins)"}; + Configurable cfgProcessKtBins{"cfgProcessKtBins", true, "Process kstar histograms in kT bins (if 'cfgProcessMultBins' is false, it will not be processed regardless of 'cfgProcessKtBins' state)"}; + Configurable cfgProcessKtMt3DCF{"cfgProcessKtMt3DCF", false, "Process 3D histograms in kT and MultBins"}; + + FemtoUniverseFemtoContainer sameEventContPP; + FemtoUniverseFemtoContainer mixedEventContPP; + + FemtoUniverseFemtoContainer sameEventContMM; + FemtoUniverseFemtoContainer mixedEventContMM; + + FemtoUniverseFemtoContainer sameEventContPM; + FemtoUniverseFemtoContainer mixedEventContPM; + + FemtoUniverseFemtoContainer sameEventContMP; + FemtoUniverseFemtoContainer mixedEventContMP; + + FemtoUniversePairCleaner pairCleaner; + FemtoUniverseDetaDphiStar pairCloseRejection; + FemtoUniverseTrackSelection trackCuts; + + FemtoUniversePairWithCentMultKt sameEventMultContPP; + FemtoUniversePairWithCentMultKt mixedEventMultContPP; + + FemtoUniversePairWithCentMultKt sameEventMultContMM; + FemtoUniversePairWithCentMultKt mixedEventMultContMM; + + FemtoUniversePairWithCentMultKt sameEventMultContPM; + FemtoUniversePairWithCentMultKt mixedEventMultContPM; + + FemtoUniversePairWithCentMultKt sameEventMultContMP; + FemtoUniversePairWithCentMultKt mixedEventMultContMP; + + float mass1 = -1; + float mass2 = -1; + + /// Histogram output + HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry resultRegistry{"Correlations", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry resultRegistryPP{"CorrelationsPP", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry resultRegistryMM{"CorrelationsMM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry resultRegistryPM{"CorrelationsPM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry resultRegistryMP{"CorrelationsMP", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry mixQARegistry{"mixQARegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + HistogramRegistry sameMultRegistryPP{"sameMultRegistryPP", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry mixedMultRegistryPP{"mixedMultRegistryPP", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + HistogramRegistry sameMultRegistryMM{"sameMultRegistryMM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry mixedMultRegistryMM{"mixedMultRegistryMM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + HistogramRegistry sameMultRegistryPM{"sameMultRegistryPM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry mixedMultRegistryPM{"mixedMultRegistryPM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + HistogramRegistry sameMultRegistryMP{"sameMultRegistryMP", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry mixedMultRegistryMP{"mixedMultRegistryMP", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + HistogramRegistry sphericityRegistry{"sphericityRegistry", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + /// TPC Pion/Kaon/Proton Sigma selection (general) + bool isNsigma(float mom, float nsigmaTPC, float nsigmaTOF) + { + // |nsigma_TPC| < 3 for p < 0.5 GeV/c + // |nsigma_combined| < 3 for p > 0.5 + + // using configurables: + // confTOFpMin -- momentum value when we start using TOF; set to 1000 if TOF not needed + // confNsigmaTPC -> TPC Sigma for momentum < confTOFpMin + // confNsigmaCombined -> TPC and TOF Sigma (combined) for momentum > confTOFpMin + + if (mom < twoobjectsconfigs.confTOFpMin) { + return std::abs(nsigmaTPC) < twoobjectsconfigs.confNsigmaTPC; + } else { + return std::hypot(nsigmaTOF, nsigmaTPC) < twoobjectsconfigs.confNsigmaCombined; + } + } + + /// TPC Kaon Sigma selection (stricter cuts for K+ and K-) -- based on Run2 results + bool isKaonNsigma(float mom, float nsigmaTPCK, float nsigmaTOFK) + { + if (twoobjectsconfigs.isKaonNsigma == true) { + if (mom < 0.4) { + return std::abs(nsigmaTPCK) < 2; + } else if (mom > 0.4 && mom < 0.45) { + return std::abs(nsigmaTPCK) < 1; + } else if (mom > 0.45 && mom < 0.8) { + return (std::abs(nsigmaTPCK) < 3 && std::abs(nsigmaTOFK) < 2); + } else if (mom > 0.8 && mom < 1.5) { + return (std::abs(nsigmaTPCK) < 3 && std::abs(nsigmaTOFK) < 1.5); + } else { + return false; + } + } else { + return isNsigma(mom, nsigmaTPCK, nsigmaTOFK); + } + } + + /// TPC Deuteron Sigma selection + bool isDeuteronNsigma(float mom, float nsigmaTPCDe, float nsigmaTOFDe) + { + if (mom > deuteronconfigs.confPlowDe && mom < deuteronconfigs.confPhighDe) { + if (mom < deuteronconfigs.confTOFpMinDe) { + return (std::abs(nsigmaTPCDe) < deuteronconfigs.confNsigmaTPCDe); + } else { + return (std::abs(nsigmaTOFDe) < deuteronconfigs.confNsigmaTOFDe && (std::abs(nsigmaTPCDe) < deuteronconfigs.confNsigmaTPCDe)); + } + } else { + return false; + } + } + + /// Linear cut for clearer TPC Deuteron Sigma + bool isDeuteronNsigmaLinearCut(float mom, float nsigmaTPCDe, float nsigmaTOFDe, float tpcSignal) + { + if (lincut.confIsLine == true) { + if (mom > lincut.linCutPlow && mom < lincut.linCutPhigh) { + if (tpcSignal > lincut.linCutParA * mom + lincut.linCutParB) { + return isDeuteronNsigma(mom, nsigmaTPCDe, nsigmaTOFDe); + } else { + return false; + } + } else { + return isDeuteronNsigma(mom, nsigmaTPCDe, nsigmaTOFDe); + } + } else { + return isDeuteronNsigma(mom, nsigmaTPCDe, nsigmaTOFDe); + } + } + + /// Polynomial 3 cut for clearer TPC Deuteron Sigma + bool isDeuteronNsigmaPol3Cut(float mom, float nsigmaTPCDe, float nsigmaTOFDe, float tpcSignal) + { + if (polcut.confIsPol3 == true) { + if (tpcSignal > polcut.polCutParA * std::pow(mom, 3) + polcut.polCutParB * std::pow(mom, 2) + polcut.polCutParC * mom + polcut.polCutParD) { + return isDeuteronNsigma(mom, nsigmaTPCDe, nsigmaTOFDe); + } else { + return false; + } + } else { + return isDeuteronNsigma(mom, nsigmaTPCDe, nsigmaTOFDe); + } + } + + bool isParticleNsigma(int8_t object_number, float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK, float nsigmaTPCDe, float nsigmaTOFDe, float tpcSignal) + { + if (object_number == 1) { + switch (trackfilter.confPDGCodeTrack) { + case 2212: // Proton + case -2212: // Anti-proton + return isNsigma(mom, nsigmaTPCPr, nsigmaTOFPr); + break; + case 211: // Pion+ + case -211: // Pion- + case 111: // Pion 0 + return isNsigma(mom, nsigmaTPCPi, nsigmaTOFPi); + break; + case 321: // Kaon+ + case -321: // Kaon- + return isKaonNsigma(mom, nsigmaTPCK, nsigmaTOFK); + break; + case 130: // Kaon 0 LONG + case 310: // Kaon 0 SHORT + return isNsigma(mom, nsigmaTPCK, nsigmaTOFK); + break; + case 1000010020: // Deuteron + case -1000010020: // Anti-deuteron + return isDeuteronNsigmaPol3Cut(mom, nsigmaTPCDe, nsigmaTOFDe, tpcSignal); + break; + default: + return false; + } + return false; + } else if (object_number == 2) { + switch (nucleusfilter.confPDGCodeNucleus) { + case 2212: // Proton + case -2212: // Anti-proton + return isNsigma(mom, nsigmaTPCPr, nsigmaTOFPr); + break; + case 211: // Pion+ + case -211: // Pion- + case 111: // Pion 0 + return isNsigma(mom, nsigmaTPCPi, nsigmaTOFPi); + break; + case 321: // Kaon+ + case -321: // Kaon- + return isKaonNsigma(mom, nsigmaTPCK, nsigmaTOFK); + break; + case 130: // Kaon 0 LONG + case 310: // Kaon 0 SHORT + return isNsigma(mom, nsigmaTPCK, nsigmaTOFK); + break; + case 1000010020: // Deuteron + case -1000010020: // Anti-deuteron + return isDeuteronNsigmaPol3Cut(mom, nsigmaTPCDe, nsigmaTOFDe, tpcSignal); + break; + default: + return false; + } + return false; + } else { + LOGF(fatal, "Wrong number of objects chosen! It should be 1 or 2. It is -> %d", object_number); + } + return false; + } + + void init(InitContext&) + { + eventHisto.init(&qaRegistry); + sphericityRegistry.add("sphericity", ";Sphericity;Entries", kTH1F, {{150, 0.0, 3, "Sphericity"}}); + + trackHistoTrack.init(&qaRegistry, confTempFitVarPtBins, confTempFitVarBins, twoobjectsconfigs.confIsMC, trackfilter.confPDGCodeTrack, true); + + trackHistoNucleus.init(&qaRegistry, confTempFitVarPtBins, confTempFitVarBins, twoobjectsconfigs.confIsMC, nucleusfilter.confPDGCodeNucleus, true); + + mixQARegistry.add("MixingQA/hSECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); + mixQARegistry.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); + + mass1 = pdg->Mass(trackfilter.confPDGCodeTrack); + mass2 = pdg->Mass(nucleusfilter.confPDGCodeNucleus); + + if (cfgProcessPP) { + sameEventContPP.init(&resultRegistryPP, confKstarBins, confMultBins, confKtBins, confMtBins, confMultBins3D, confMtBins3D, twoobjectsconfigs.confIsMC, twoobjectsconfigs.confUse3D); + mixedEventContPP.init(&resultRegistryPP, confKstarBins, confMultBins, confKtBins, confMtBins, confMultBins3D, confMtBins3D, twoobjectsconfigs.confIsMC, twoobjectsconfigs.confUse3D); + sameEventContPP.setPDGCodes(trackfilter.confPDGCodeTrack, nucleusfilter.confPDGCodeNucleus); + mixedEventContPP.setPDGCodes(trackfilter.confPDGCodeTrack, nucleusfilter.confPDGCodeNucleus); + + if (cfgProcessMultBins) { + sameEventMultContPP.init(&sameMultRegistryPP, confKstarBins, confMultKstarBins, confKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); + mixedEventMultContPP.init(&mixedMultRegistryPP, confKstarBins, confMultKstarBins, confKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); + } + } + + if (cfgProcessMM) { + sameEventContMM.init(&resultRegistryMM, confKstarBins, confMultBins, confKtBins, confMtBins, confMultBins3D, confMtBins3D, twoobjectsconfigs.confIsMC, twoobjectsconfigs.confUse3D); + mixedEventContMM.init(&resultRegistryMM, confKstarBins, confMultBins, confKtBins, confMtBins, confMultBins3D, confMtBins3D, twoobjectsconfigs.confIsMC, twoobjectsconfigs.confUse3D); + sameEventContMM.setPDGCodes(trackfilter.confPDGCodeTrack, nucleusfilter.confPDGCodeNucleus); + mixedEventContMM.setPDGCodes(trackfilter.confPDGCodeTrack, nucleusfilter.confPDGCodeNucleus); + + if (cfgProcessMultBins) { + sameEventMultContMM.init(&sameMultRegistryMM, confKstarBins, confMultKstarBins, confKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); + mixedEventMultContMM.init(&mixedMultRegistryMM, confKstarBins, confMultKstarBins, confKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); + } + } + + if (cfgProcessPM) { + sameEventContPM.init(&resultRegistryPM, confKstarBins, confMultBins, confKtBins, confMtBins, confMultBins3D, confMtBins3D, twoobjectsconfigs.confIsMC, twoobjectsconfigs.confUse3D); + mixedEventContPM.init(&resultRegistryPM, confKstarBins, confMultBins, confKtBins, confMtBins, confMultBins3D, confMtBins3D, twoobjectsconfigs.confIsMC, twoobjectsconfigs.confUse3D); + + sameEventContPM.setPDGCodes(trackfilter.confPDGCodeTrack, nucleusfilter.confPDGCodeNucleus); + mixedEventContPM.setPDGCodes(trackfilter.confPDGCodeTrack, nucleusfilter.confPDGCodeNucleus); + + if (cfgProcessMultBins) { + sameEventMultContPM.init(&sameMultRegistryPM, confKstarBins, confMultKstarBins, confKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); + mixedEventMultContPM.init(&mixedMultRegistryPM, confKstarBins, confMultKstarBins, confKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); + } + } + + if (cfgProcessMP) { + sameEventContMP.init(&resultRegistryMP, confKstarBins, confMultBins, confKtBins, confMtBins, confMultBins3D, confMtBins3D, twoobjectsconfigs.confIsMC, twoobjectsconfigs.confUse3D); + mixedEventContMP.init(&resultRegistryMP, confKstarBins, confMultBins, confKtBins, confMtBins, confMultBins3D, confMtBins3D, twoobjectsconfigs.confIsMC, twoobjectsconfigs.confUse3D); + + sameEventContMP.setPDGCodes(trackfilter.confPDGCodeTrack, nucleusfilter.confPDGCodeNucleus); + mixedEventContMP.setPDGCodes(trackfilter.confPDGCodeTrack, nucleusfilter.confPDGCodeNucleus); + + if (cfgProcessMultBins) { + sameEventMultContMP.init(&sameMultRegistryMP, confKstarBins, confMultKstarBins, confKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); + mixedEventMultContMP.init(&mixedMultRegistryMP, confKstarBins, confMultKstarBins, confKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); + } + } + + pairCleaner.init(&qaRegistry); + if (confIsCPR.value) { + pairCloseRejection.init(&resultRegistry, &qaRegistry, confCPRDeltaPhiCutMin.value, confCPRDeltaPhiCutMax.value, confCPRDeltaEtaCutMin.value, confCPRDeltaEtaCutMax.value, confCPRChosenRadii.value, confCPRPlotPerRadii.value); + } + + vPIDTrack = trackfilter.confPIDTrack.value; + vPIDNucleus = nucleusfilter.confPIDNucleus.value; + kNsigma = twoobjectsconfigs.confTrkPIDNsigmaMax.value; + } + + template + void fillCollision(CollisionType col) + { + mixQARegistry.fill(HIST("MixingQA/hSECollisionBins"), colBinning.getBin({col.posZ(), col.multV0M()})); + eventHisto.fillQA(col); + } + + /// This function processes 'same event' and takes care of all the histogramming + /// \todo the trivial loops over the tracks should be factored out since they will be common to all combinations of T-T, T-V0, V0-V0, ... + /// \tparam PartitionType + /// \tparam PartType + /// \tparam isMC: enables Monte Carlo truth specific histograms + /// \param groupTrack partition for track passed by the process function + /// \param groupNucleus partition for nucleus passed by the process function + /// \param parts femtoUniverseParticles table (in case of Monte Carlo joined with FemtoUniverseMCLabels) + /// \param magFieldTesla magnetic field of the collision + /// \param multCol multiplicity of the collision + /// \param pairType describes charge of correlation pair (plus-plus (1), minus-minus (2), plus-minus (3), minus-plus (4)) + /// \param fillQA enables filling of QA histograms + template + void doSameEvent(PartitionType groupTrack, PartitionType groupNucleus, PartType parts, float magFieldTesla, int multCol, int pairType, bool /*fillQA*/) + { + for (const auto& part : groupTrack) { + if (!isParticleNsigma((int8_t)1, part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon), trackCuts.getNsigmaTPC(part, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(part, o2::track::PID::Deuteron), part.tpcSignal())) { + continue; + } + trackHistoTrack.fillQA(part); + } + + for (const auto& part : groupNucleus) { + if (!isParticleNsigma((int8_t)2, part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon), trackCuts.getNsigmaTPC(part, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(part, o2::track::PID::Deuteron), part.tpcSignal())) { + continue; + } + trackHistoNucleus.fillQA(part); + } + + /// Combinations creation + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupTrack, groupNucleus))) { + + if (!isParticleNsigma((int8_t)1, p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTPC(p1, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(p1, o2::track::PID::Deuteron), p1.tpcSignal())) { + continue; + } + + if (!isParticleNsigma((int8_t)2, p2.p(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTPC(p2, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(p2, o2::track::PID::Deuteron), p2.tpcSignal())) { + continue; + } + + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { + continue; + } + } + + // Cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + + switch (pairType) { + case 1: { + float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass2); + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + + sameEventContPP.setPair(p1, p2, multCol, twoobjectsconfigs.confUse3D); + + if (cfgProcessMultBins) + sameEventMultContPP.fill(kstar, multCol, kT); + + break; + } + + case 2: { + float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass2); + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + + sameEventContMM.setPair(p1, p2, multCol, twoobjectsconfigs.confUse3D); + + if (cfgProcessMultBins) + sameEventMultContMM.fill(kstar, multCol, kT); + + break; + } + + case 3: { + float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass2); + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + + sameEventContPM.setPair(p1, p2, multCol, twoobjectsconfigs.confUse3D); + + if (cfgProcessMultBins) + sameEventMultContPM.fill(kstar, multCol, kT); + + break; + } + + case 4: { + float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass2); + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + + sameEventContMP.setPair(p1, p2, multCol, twoobjectsconfigs.confUse3D); + + if (cfgProcessMultBins) + sameEventMultContMP.fill(kstar, multCol, kT); + + break; + } + + default: + break; + } + } + } + + /// Process function to call doSameEvent with Data + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoUniverseParticleTable + void processSameEvent(const soa::Filtered::iterator& col, + const FilteredFemtoFullParticles& parts) + { + fillCollision(col); + sphericityRegistry.fill(HIST("sphericity"), col.sphericity()); + + auto thegroupTrack = partTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegroupNucleus = partNucleus->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + bool fillQA = true; + + if (cfgProcessPP) + doSameEvent(thegroupTrack, thegroupNucleus, parts, col.magField(), col.multV0M(), 1, fillQA); + + if (cfgProcessMM) + doSameEvent(thegroupTrack, thegroupNucleus, parts, col.magField(), col.multV0M(), 2, fillQA); + + if (cfgProcessPM) { + doSameEvent(thegroupTrack, thegroupNucleus, parts, col.magField(), col.multV0M(), 3, fillQA); + fillQA = false; + } + + if (cfgProcessMP) { + doSameEvent(thegroupTrack, thegroupNucleus, parts, col.magField(), col.multV0M(), 4, fillQA); + fillQA = false; + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackNucleus, processSameEvent, "Enable processing same event", true); + + /// Process function to call doSameEvent with Monte Carlo + /// \param col subscribe to the collision table (Monte Carlo Reconstructed reconstructed) + /// \param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth + /// \param FemtoUniverseMCParticles subscribe to the Monte Carlo Truth table + void processSameEventMC(const o2::aod::FdCollision& col, + const soa::Join& parts, + const o2::aod::FdMCParticles&) + { + fillCollision(col); + + auto thegroupTrack = partTrackMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegroupNucleus = partNucleusMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + bool fillQA = true; + + if (cfgProcessPP) + doSameEvent(thegroupTrack, thegroupNucleus, parts, col.magField(), col.multV0M(), 1, fillQA); + + if (cfgProcessMM) + doSameEvent(thegroupTrack, thegroupNucleus, parts, col.magField(), col.multV0M(), 2, fillQA); + + if (cfgProcessPM) { + doSameEvent(thegroupTrack, thegroupNucleus, parts, col.magField(), col.multV0M(), 3, fillQA); + fillQA = false; + } + + if (cfgProcessMP) { + doSameEvent(thegroupTrack, thegroupNucleus, parts, col.magField(), col.multV0M(), 4, fillQA); + fillQA = false; + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackNucleus, processSameEventMC, "Enable processing same event for Monte Carlo", false); + + /// This function processes 'mixed event' + /// \todo the trivial loops over the collisions and tracks should be factored out since they will be common to all combinations of T-T, T-V0, V0-V0, ... + /// \tparam PartitionType + /// \tparam PartType + /// \tparam isMC: enables Monte Carlo truth specific histograms + /// \param groupTrack partition for track passed by the process function + /// \param groupNucleus partition for nucleus passed by the process function + /// \param parts femtoUniverseParticles table (in case of Monte Carlo joined with FemtoUniverseMCLabels) + /// \param magFieldTesla magnetic field of the collision + /// \param multCol multiplicity of the collision + /// \param pairType describes charge of correlation pair (plus-minus (1), plus-plus (2), minus-minus (3)) + template + void doMixedEvent(PartitionType groupTrack, PartitionType groupNucleus, PartType parts, float magFieldTesla, int multCol, int pairType) + { + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupTrack, groupNucleus))) { + + if (!isParticleNsigma((int8_t)1, p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTPC(p1, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(p1, o2::track::PID::Deuteron), p1.tpcSignal())) { + continue; + } + + if (!isParticleNsigma((int8_t)2, p2.p(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTPC(p2, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(p2, o2::track::PID::Deuteron), p2.tpcSignal())) { + continue; + } + + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::mixed)) { + continue; + } + } + + switch (pairType) { + case 1: { + float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass2); + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + + mixedEventContPP.setPair(p1, p2, multCol, twoobjectsconfigs.confUse3D); + + if (cfgProcessMultBins) + mixedEventMultContPP.fill(kstar, multCol, kT); + + break; + } + + case 2: { + float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass2); + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + + mixedEventContMM.setPair(p1, p2, multCol, twoobjectsconfigs.confUse3D); + + if (cfgProcessMultBins) + mixedEventMultContMM.fill(kstar, multCol, kT); + + break; + } + + case 3: { + float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass2); + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + + mixedEventContPM.setPair(p1, p2, multCol, twoobjectsconfigs.confUse3D); + + if (cfgProcessMultBins) + mixedEventMultContPM.fill(kstar, multCol, kT); + + break; + } + + case 4: { + float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass2); + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + + mixedEventContMP.setPair(p1, p2, multCol, twoobjectsconfigs.confUse3D); + + if (cfgProcessMultBins) + mixedEventMultContMP.fill(kstar, multCol, kT); + + break; + } + + default: + break; + } + } + } + + /// Process function to call doMixedEvent with Data + /// \param cols subscribe to the collisions table (Data) + /// \param parts subscribe to the femtoUniverseParticleTable + void processMixedEvent(const soa::Filtered& cols, + const FilteredFemtoFullParticles& parts) + { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + + const int multiplicityCol = collision1.multV0M(); + mixQARegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + continue; + } + + if (cfgProcessPP) { + auto groupTrack = partTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupNucleus = partNucleus->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupTrack, groupNucleus, parts, magFieldTesla1, multiplicityCol, 1); + } + + if (cfgProcessMM) { + auto groupTrack = partTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupNucleus = partNucleus->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupTrack, groupNucleus, parts, magFieldTesla1, multiplicityCol, 2); + } + + if (cfgProcessPM) { + auto groupTrack = partTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupNucleus = partNucleus->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupTrack, groupNucleus, parts, magFieldTesla1, multiplicityCol, 3); + } + + if (cfgProcessMP) { + auto groupTrack = partTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupNucleus = partNucleus->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupTrack, groupNucleus, parts, magFieldTesla1, multiplicityCol, 4); + } + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackNucleus, processMixedEvent, "Enable processing mixed events", true); + + /// Process function to call doMixedEvent with Monte Carlo + /// \param cols subscribe to the collisions table (Monte Carlo Reconstructed reconstructed) + /// \param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth + /// \param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table + void processMixedEventMC(const o2::aod::FdCollisions& cols, + const soa::Join& parts, + const o2::aod::FdMCParticles&) + { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + + const int multiplicityCol = collision1.multV0M(); + mixQARegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + continue; + } + /// \todo before mixing we should check whether both collisions contain a pair of particles! + // if partTrack.size() == 0 || Npart2Evt1 == 0 || Npart1Evt2 == 0 || partNucleus.size() == 0 ) continue; + + if (cfgProcessPP) { + auto groupTrack = partTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupNucleus = partNucleus->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupTrack, groupNucleus, parts, magFieldTesla1, multiplicityCol, 1); + } + + if (cfgProcessMM) { + auto groupTrack = partTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupNucleus = partNucleus->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupTrack, groupNucleus, parts, magFieldTesla1, multiplicityCol, 2); + } + + if (cfgProcessPM) { + auto groupTrack = partTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupNucleus = partNucleus->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupTrack, groupNucleus, parts, magFieldTesla1, multiplicityCol, 3); + } + + if (cfgProcessMP) { + auto groupTrack = partTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupNucleus = partNucleus->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupTrack, groupNucleus, parts, magFieldTesla1, multiplicityCol, 4); + } + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackNucleus, processMixedEventMC, "Enable processing mixed events MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + + return workflow; +} diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackPhi.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackPhi.cxx index d5e1f9bf25f..7dd0de272fe 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackPhi.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackPhi.cxx @@ -10,162 +10,199 @@ // or submit itself to any jurisdiction. /// \file femtoUniversePairTaskTrackPhi.cxx -/// \brief Tasks that reads the track tables used for the pairing and builds pairs of two tracks +/// \brief Tasks that reads the track tables used for the pairing and builds pairs for h-Phi angular correlation analysis /// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de /// \author Georgios Mantzaridis, TU München, georgios.mantzaridis@tum.de /// \author Anton Riedel, TU München, anton.riedel@tum.de /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch #include +#include #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" #include "Framework/ASoAHelpers.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/StepTHn.h" #include "Framework/O2DatabasePDGPlugin.h" -#include "TDatabasePDG.h" #include "ReconstructionDataFormats/PID.h" -#include "Common/DataModel/PIDResponse.h" #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseFemtoContainer.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseAngularContainer.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEfficiencyCalculator.h" +#include +#include using namespace o2; -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; +using namespace o2::analysis::femto_universe::efficiency; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; namespace { -static constexpr int nPart = 2; -static constexpr int nCuts = 5; +// static constexpr int NPart = 2; +// static constexpr int NCuts = 5; static const std::vector partNames{"PhiCandidate", "Track"}; static const std::vector cutNames{"MaxPt", "PIDthr", "nSigmaTPC", "nSigmaTPCTOF", "MaxP"}; -static const float cutsTable[nPart][nCuts]{ - {4.05f, 1.f, 3.f, 3.f, 100.f}, - {4.05f, 1.f, 3.f, 3.f, 100.f}}; +// static const float cutsTable[NPart][NCuts]{ //unused variable +// {4.05f, 1.f, 3.f, 3.f, 100.f}, +// {4.05f, 1.f, 3.f, 3.f, 100.f}}; } // namespace -struct femtoUniversePairTaskTrackPhi { +struct FemtoUniversePairTaskTrackPhi { + + Service pdgMC; + + using FilteredFemtoFullParticles = soa::Join; - using FemtoFullParticles = soa::Join; SliceCache cache; - Preslice perCol = aod::femtouniverseparticle::fdCollisionId; + Preslice perCol = aod::femtouniverseparticle::fdCollisionId; + + using FemtoRecoParticles = soa::Join; + Preslice perColMC = aod::femtouniverseparticle::fdCollisionId; - Configurable ConfIsCPR{"ConfIsCPR", true, "Close Pair Rejection"}; + Configurable ConfZVertexCut{"ConfZVertexCut", 10.f, "Event sel: Maximum z-Vertex (cm)"}; + Configurable ConfNEventsMix{"ConfNEventsMix", 5, "Number of events for mixing"}; + Filter collisionFilter = (nabs(aod::collision::posZ) < ConfZVertexCut); + using FilteredFDCollisions = soa::Filtered; + using FilteredFDCollision = FilteredFDCollisions::iterator; + + Configurable ConfCPRIsEnabled{"ConfCPRIsEnabled", false, "Close Pair Rejection"}; Configurable ConfCPRPlotPerRadii{"ConfCPRPlotPerRadii", false, "Plot CPR per radii"}; Configurable ConfCPRdeltaPhiCutMax{"ConfCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; Configurable ConfCPRdeltaPhiCutMin{"ConfCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; Configurable ConfCPRdeltaEtaCutMax{"ConfCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; Configurable ConfCPRdeltaEtaCutMin{"ConfCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; + Configurable ConfCPRInvMassCutMin{"ConfCPRInvMassCutMin", 1.014, "Invariant mass (low) cut for Close Pair Rejection"}; + Configurable ConfCPRInvMassCutMax{"ConfCPRInvMassCutMax", 1.026, "Invariant mass (high) cut for Close Pair Rejection"}; Configurable ConfCPRChosenRadii{"ConfCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; /// Table for both particles - struct : o2::framework::ConfigurableGroup { - Configurable ConfNsigmaCombinedProton{"ConfNsigmaCombinedProton", 3.0, "TPC and TOF Proton Sigma (combined) for momentum > 0.5"}; - Configurable ConfNsigmaTPCProton{"ConfNsigmaTPCProton", 3.0, "TPC Proton Sigma for momentum < 0.5"}; - Configurable ConfNsigmaCombinedPion{"ConfNsigmaCombinedPion", 3.0, "TPC and TOF Pion Sigma (combined) for momentum > 0.5"}; - Configurable ConfNsigmaTPCPion{"ConfNsigmaTPCPion", 3.0, "TPC Pion Sigma for momentum < 0.5"}; - - Configurable> ConfCutTable{"ConfCutTable", {cutsTable[0], nPart, nCuts, partNames, cutNames}, "Particle selections"}; - Configurable ConfNspecies{"ConfNspecies", 2, "Number of particle spieces with PID info"}; - Configurable ConfIsMC{"ConfIsMC", false, "Enable additional Histogramms in the case of a MonteCarlo Run"}; - Configurable> ConfTrkPIDnSigmaMax{"ConfTrkPIDnSigmaMax", std::vector{4.f, 3.f, 2.f}, "This configurable needs to be the same as the one used in the producer task"}; - Configurable ConfUse3D{"ConfUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; - Configurable ConfPhiBins{"ConfPhiBins", 29, "Number of phi bins in deta dphi"}; - Configurable ConfEtaBins{"ConfEtaBins", 29, "Number of eta bins in deta dphi"}; - } ConfBothTracks; + Configurable ConfPIDProtonNsigmaCombined{"ConfPIDProtonNsigmaCombined", 3.0, "TPC and TOF Proton Sigma (combined) for momentum > 0.5"}; + Configurable ConfPIDProtonNsigmaTPC{"ConfPIDProtonNsigmaTPC", 3.0, "TPC Proton Sigma for momentum < 0.5"}; + Configurable ConfPIDKaonNsigmaReject{"ConfPIDKaonNsigmaReject", 3.0, "Reject if particle could be a Kaon combined nsigma value."}; + Configurable ConfPIDPionNsigmaReject{"ConfPIDPionNsigmaReject", 3.0, "Reject if particle could be a Pion combined nsigma value."}; + Configurable ConfPIDProtonNsigmaReject{"ConfPIDProtonNsigmaReject", 3.0, "Reject if particle could be a Proton combined nsigma value."}; + Configurable ConfPIDPionNsigmaCombined{"ConfPIDPionNsigmaCombined", 3.0, "TPC and TOF Pion Sigma (combined) for momentum > 0.5"}; + Configurable ConfPIDPionNsigmaTPC{"ConfPIDPionNsigmaTPC", 3.0, "TPC Pion Sigma for momentum < 0.5"}; + Configurable ConfIsMC{"ConfIsMC", false, "Enable additional Histograms in the case of a MonteCarlo Run"}; + Configurable ConfUse3D{"ConfUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; + Configurable ConfBinsPhi{"ConfBinsPhi", 29, "Number of phi bins in deta dphi"}; + Configurable ConfBinsEta{"ConfBinsEta", 29, "Number of eta bins in deta dphi"}; /// Particle 1 --- IDENTIFIED TRACK - struct : o2::framework::ConfigurableGroup { - Configurable ConfIsSame{"ConfIsSame", false, "Pairs of the same particle"}; - Configurable ConfPDGCodeTrack{"ConfPDGCodeTrack", 2212, "Particle 2 - PDG code"}; - Configurable ConfPIDTrack{"ConfPIDTrack", 2, "Particle 2 - Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector> - Configurable ConfTrackSign{"ConfTrackSign", 1, "Track sign"}; - Configurable ConfIsTrackIdentified{"ConfIsTrackIdentified", true, "Enable PID for the track"}; - } ConfTrack; - - /// Particle 2 --- PHI - struct : o2::framework::ConfigurableGroup { - Configurable ConfPDGCodePhi{"ConfPDGCodePhi", 333, "Phi meson - PDG code"}; - Configurable ConfPIDPhi{"ConfPIDPhi", 2, "Phi meson - Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector>int>> - } ConfPhi; - - /// Partitions for particle 1 - Partition partsTrack = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == ConfTrack.ConfTrackSign); - Partition> partsTrackMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)); - - /// Partitions for particle 2 - Partition partsPhi = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kPhi)); - Partition> partsPhiMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kPhi)); + Configurable ConfTrackPDGCode{"ConfTrackPDGCode", 2212, "Particle 2 - PDG code"}; + Configurable ConfTrackSign{"ConfTrackSign", 1, "Track sign"}; + Configurable ConfTrackIsIdentified{"ConfTrackIsIdentified", true, "Enable PID for the track"}; + Configurable ConfTrackIsRejected{"ConfTrackIsRejected", true, "Enable PID rejection for the track other species than the identified one."}; + Configurable ConfTrackPtPIDLimit{"ConfTrackPtPIDLimit", 0.5, "Momentum threshold for change of the PID method (from using TPC to TPC and TOF)."}; + Configurable ConfTrackPtLow{"ConfTrackPtLow", 0.5, "Lower limit of the hadron pT."}; + Configurable ConfTrackPtHigh{"ConfTrackPtHigh", 2.5, "Higher limit of the hadron pT."}; + + /// Partitions for the track (particle 1) + Partition partsTrack = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && + (aod::femtouniverseparticle::sign == ConfTrackSign) && + (aod::femtouniverseparticle::pt > ConfTrackPtLow) && + (aod::femtouniverseparticle::pt < ConfTrackPtHigh); + + Partition partsTrackMCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && + (aod::femtouniverseparticle::sign == ConfTrackSign) && + (aod::femtouniverseparticle::pt > ConfTrackPtLow) && + (aod::femtouniverseparticle::pt < ConfTrackPtHigh); + + /// Particle 2 --- PHI MESON + Configurable ConfPhiPtLow{"ConfPhiPtLow", 0.8, "Lower limit of the Phi pT."}; + Configurable ConfPhiPtHigh{"ConfPhiPtHigh", 4.0, "Higher limit of the Phi pT."}; + Configurable confInvMassLowLimitPhi{"confInvMassLowLimitPhi", 1.011, "Lower limit of the Phi invariant mass"}; // change that to do invariant mass cut + Configurable confInvMassUpLimitPhi{"confInvMassUpLimitPhi", 1.027, "Upper limit of the Phi invariant mass"}; + + /// Partitions for the Phi meson (particle 2) + Partition partsPhi = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kPhi)) && + (aod::femtouniverseparticle::pt > ConfPhiPtLow) && + (aod::femtouniverseparticle::pt < ConfPhiPtHigh) && + (aod::femtouniverseparticle::tempFitVar > confInvMassLowLimitPhi) && + (aod::femtouniverseparticle::tempFitVar < confInvMassUpLimitPhi); + + Partition partsPhiMCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kPhi)) && + (aod::femtouniverseparticle::pt > ConfPhiPtLow) && + (aod::femtouniverseparticle::pt < ConfPhiPtHigh) && + (aod::femtouniverseparticle::tempFitVar > confInvMassLowLimitPhi) && + (aod::femtouniverseparticle::tempFitVar < confInvMassUpLimitPhi); /// Partitions for Phi daughters kPhiChild - Partition partsPhiDaugh = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kPhiChild)); - Partition> partsPhiDaughMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kPhiChild)); + Partition partsPhiDaugh = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kPhiChild)); + Partition> partsPhiDaughMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kPhiChild)); + + // Partition for K+K- minv + Partition partsKaons = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)); + Partition> partsKaonsMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)); /// Histogramming for particle 1 - FemtoUniverseParticleHisto trackHistoPartTrack; + FemtoUniverseParticleHisto trackHistoPartTrack; + FemtoUniverseParticleHisto hTrackDCA; /// Histogramming for particle 2 - FemtoUniverseParticleHisto trackHistoPartPhi; + FemtoUniverseParticleHisto trackHistoPartPhi; /// Histogramming for Event FemtoUniverseEventHisto eventHisto; - /// The configurables need to be passed to an std::vector - int vPIDPhiCandidate, vPIDTrack; - std::vector kNsigma; - /// particle part - ConfigurableAxis ConfTempFitVarBins{"ConfDTempFitVarBins", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfTempFitVarInvMassBins{"ConfDTempFitVarInvMassBins", {6000, 0.9, 4.0}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfTempFitVarpTBins{"ConfTempFitVarpTBins", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; + ConfigurableAxis ConfBinsTempFitVar{"ConfBinsTempFitVar", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis ConfBinsTempFitVarInvMass{"ConfBinsTempFitVarInvMass", {6000, 0.9, 4.0}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis ConfBinsTempFitVarpT{"ConfBinsTempFitVarpT", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; + ConfigurableAxis ConfBinsTempFitVarPDG{"ConfBinsTempFitVarPDG", {6000, -2300, 2300}, "Binning of the PDG code in the pT vs. TempFitVar plot"}; + ConfigurableAxis ConfBinsTempFitVarDCA{"ConfBinsTempFitVarDCA", {300, -3.0, 3.0}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; /// Correlation part - ConfigurableAxis ConfMultBins{"ConfMultBins", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; // \todo to be obtained from the hash task - ConfigurableAxis ConfVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - ConfigurableAxis ConfmTBins3D{"ConfmTBins3D", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; - ConfigurableAxis ConfmultBins3D{"ConfmultBins3D", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; - - ColumnBinningPolicy colBinning{{ConfVtxBins, ConfMultBins}, true}; + ConfigurableAxis ConfBinsMult{"ConfBinsMult", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; // \todo to be obtained from the hash task + ConfigurableAxis ConfBinsVtx{"ConfBinsVtx", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis ConfBins3DmT{"ConfBins3DmT", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + ConfigurableAxis ConfBins3Dmult{"ConfBins3Dmult", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; - ConfigurableAxis ConfkstarBins{"ConfkstarBins", {1500, 0., 6.}, "binning kstar"}; - ConfigurableAxis ConfkTBins{"ConfkTBins", {150, 0., 9.}, "binning kT"}; - ConfigurableAxis ConfmTBins{"ConfmTBins", {225, 0., 7.5}, "binning mT"}; + ConfigurableAxis ConfBinskstar{"ConfBinskstar", {1500, 0., 6.}, "binning kstar"}; + ConfigurableAxis ConfBinskT{"ConfBinskT", {150, 0., 9.}, "binning kT"}; + ConfigurableAxis ConfBinsmT{"ConfBinsmT", {225, 0., 7.5}, "binning mT"}; - FemtoUniverseFemtoContainer sameEventFemtoCont; - FemtoUniverseFemtoContainer mixedEventFemtoCont; - FemtoUniverseAngularContainer sameEventAngularCont; - FemtoUniverseAngularContainer mixedEventAngularCont; + FemtoUniverseContainer sameEventCont; + FemtoUniverseContainer mixedEventCont; FemtoUniversePairCleaner pairCleaner; FemtoUniverseDetaDphiStar pairCloseRejection; FemtoUniverseTrackSelection trackCuts; /// Histogram output - HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry qaRegistry{"qaRegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry resultRegistry{"Correlations", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry MixQaRegistry{"MixQaRegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry mixQaRegistry{"mixQaRegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryMCtruth{"registryMCtruth", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry registryMCreco{"registryMCreco", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry registryPhiMinvBackground{"registryPhiMinvBackground", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry registryDCA{"registryDCA", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry registryMCpT{"registryMCpT", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + + ColumnBinningPolicy colBinning{{ConfBinsVtx, ConfBinsMult}, true}; + + EfficiencyConfigurableGroup effConfGroup; + EfficiencyCalculator efficiencyCalculator{&effConfGroup}; + + float weight = 1; // PID for protons - bool IsProtonNSigma(float mom, float nsigmaTPCPr, float nsigmaTOFPr) // previous version from: https://github.com/alisw/AliPhysics/blob/master/PWGCF/FEMTOSCOPY/AliFemtoUser/AliFemtoMJTrackCut.cxx + bool isProtonNSigma(float mom, float nsigmaTPCPr, float nsigmaTOFPr) // previous version from: https://github.com/alisw/AliPhysics/blob/master/PWGCF/FEMTOSCOPY/AliFemtoUser/AliFemtoMJTrackCut.cxx { - if (mom < 0.5) { - if (TMath::Abs(nsigmaTPCPr) < ConfBothTracks.ConfNsigmaTPCProton) { + if (mom < ConfTrackPtPIDLimit) { + if (std::abs(nsigmaTPCPr) < ConfPIDProtonNsigmaTPC) { return true; } else { return false; } - } else if (mom > 0.4) { - if (TMath::Hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfBothTracks.ConfNsigmaCombinedProton) { + } else if (mom > ConfTrackPtPIDLimit) { + if (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfPIDProtonNsigmaCombined) { return true; } else { return false; @@ -174,28 +211,46 @@ struct femtoUniversePairTaskTrackPhi { return false; } - bool IsKaonNSigma(float mom, float nsigmaTPCK, float nsigmaTOFK) + bool isProtonRejected(float mom, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) + { + if (mom < 0.5) { + return true; + } + if (mom > 0.5) { + if (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfPIDPionNsigmaReject) { + return true; + } else if (std::hypot(nsigmaTOFK, nsigmaTPCK) < ConfPIDKaonNsigmaReject) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + bool isKaonNSigma(float mom, float nsigmaTPCK, float nsigmaTOFK) { if (mom < 0.3) { // 0.0-0.3 - if (TMath::Abs(nsigmaTPCK) < 3.0) { + if (std::abs(nsigmaTPCK) < 3.0) { return true; } else { return false; } } else if (mom < 0.45) { // 0.30 - 0.45 - if (TMath::Abs(nsigmaTPCK) < 2.0) { + if (std::abs(nsigmaTPCK) < 2.0) { return true; } else { return false; } } else if (mom < 0.55) { // 0.45-0.55 - if (TMath::Abs(nsigmaTPCK) < 1.0) { + if (std::abs(nsigmaTPCK) < 1.0) { return true; } else { return false; } } else if (mom < 1.5) { // 0.55-1.5 (now we use TPC and TOF) - if ((TMath::Abs(nsigmaTOFK) < 3.0) && (TMath::Abs(nsigmaTPCK) < 3.0)) { + if ((std::abs(nsigmaTOFK) < 3.0) && (std::abs(nsigmaTPCK) < 3.0)) { { return true; } @@ -203,7 +258,29 @@ struct femtoUniversePairTaskTrackPhi { return false; } } else if (mom > 1.5) { // 1.5 - - if ((TMath::Abs(nsigmaTOFK) < 2.0) && (TMath::Abs(nsigmaTPCK) < 3.0)) { + if ((std::abs(nsigmaTOFK) < 2.0) && (std::abs(nsigmaTPCK) < 3.0)) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + bool isKaonRejected(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi) + { + if (mom < 0.5) { + if (std::abs(nsigmaTPCPi) < ConfPIDPionNsigmaReject) { + return true; + } else if (std::abs(nsigmaTPCPr) < ConfPIDProtonNsigmaReject) { + return true; + } + } + if (mom > 0.5) { + if (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfPIDPionNsigmaReject) { + return true; + } else if (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfPIDProtonNsigmaReject) { return true; } else { return false; @@ -213,17 +290,17 @@ struct femtoUniversePairTaskTrackPhi { } } - bool IsPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) + bool isPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) { if (true) { if (mom < 0.5) { - if (TMath::Abs(nsigmaTPCPi) < ConfBothTracks.ConfNsigmaTPCPion) { + if (std::abs(nsigmaTPCPi) < ConfPIDPionNsigmaTPC) { return true; } else { return false; } } else if (mom > 0.5) { - if (TMath::Hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfBothTracks.ConfNsigmaCombinedPion) { + if (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfPIDPionNsigmaCombined) { return true; } else { return false; @@ -233,20 +310,62 @@ struct femtoUniversePairTaskTrackPhi { return false; } - bool IsParticleNSigma(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) + bool isPionRejected(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCK, float nsigmaTOFK) { - switch (ConfTrack.ConfPDGCodeTrack) { + if (mom < 0.5) { + if (std::abs(nsigmaTPCK) < ConfPIDKaonNsigmaReject) { + return true; + } else if (std::abs(nsigmaTPCPr) < ConfPIDProtonNsigmaReject) { + return true; + } + } + if (mom > 0.5) { + if (std::hypot(nsigmaTOFK, nsigmaTPCK) < ConfPIDKaonNsigmaReject) { + return true; + } else if (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfPIDProtonNsigmaReject) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + bool isParticleNSigmaAccepted(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) + { + switch (ConfTrackPDGCode) { case 2212: // Proton case -2212: // anty Proton - return IsProtonNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); + return isProtonNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); break; case 211: // Pion case -211: // Pion- - return IsPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); + return isPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); break; case 321: // Kaon+ case -321: // Kaon- - return IsKaonNSigma(mom, nsigmaTPCK, nsigmaTOFK); + return isKaonNSigma(mom, nsigmaTPCK, nsigmaTOFK); + break; + default: + return false; + } + } + + bool isParticleNSigmaRejected(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) + { + switch (ConfTrackPDGCode) { + case 2212: // Proton + case -2212: // anty Proton + return isProtonRejected(mom, nsigmaTPCPi, nsigmaTOFPi, nsigmaTPCK, nsigmaTOFK); + break; + case 211: // Pion + case -211: // Pion- + return isPionRejected(mom, nsigmaTPCPr, nsigmaTOFPr, nsigmaTPCK, nsigmaTOFK); + break; + case 321: // Kaon+ + case -321: // Kaon- + return isKaonRejected(mom, nsigmaTPCPr, nsigmaTOFPr, nsigmaTPCPi, nsigmaTOFPi); break; default: return false; @@ -255,155 +374,180 @@ struct femtoUniversePairTaskTrackPhi { void init(InitContext&) { + if (ConfIsMC) { + hTrackDCA.init(®istryDCA, ConfBinsTempFitVarpT, ConfBinsTempFitVarDCA, true, ConfTrackPDGCode, true); + + registryMCpT.add("MCReco/C_phi_pT", "; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{100, 0, 10}}); + registryMCpT.add("MCReco/NC_phi_pT", "; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{100, 0, 10}}); + + registryMCpT.add("MCReco/C_p_pT", "; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{100, 0, 10}}); + registryMCpT.add("MCReco/NC_p_pT", "; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{100, 0, 10}}); + } + efficiencyCalculator.init(); + eventHisto.init(&qaRegistry); - qaRegistry.add("PhiDaugh_pos/nSigmaTPC", "; #it{p} (GeV/#it{c}); n#sigma_{TPC}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - qaRegistry.add("PhiDaugh_pos/nSigmaTOF", "; #it{p} (GeV/#it{c}); n#sigma_{TOF}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + qaRegistry.add("PhiDaugh_pos/nSigmaTPC", "; #it{p} (GeV/#it{c}); n#sigma_{TPC}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("PhiDaugh_pos/nSigmaTOF", "; #it{p} (GeV/#it{c}); n#sigma_{TOF}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); qaRegistry.add("PhiDaugh_pos/pt", "; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{100, 0, 10}}); qaRegistry.add("PhiDaugh_pos/eta", "; #it{eta}; Counts", kTH1F, {{200, -1.5, 1.5}}); - qaRegistry.add("PhiDaugh_pos/phi", "; #it{varphi}; Counts", kTH1F, {{200, 0, 2. * M_PI}}); + qaRegistry.add("PhiDaugh_pos/phi", "; #it{varphi}; Counts", kTH1F, {{200, 0, o2::constants::math::TwoPI}}); qaRegistry.add("PhiDaugh_pos/hDCAxy", "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {{100, 0, 10}, {500, -5, 5}}); - qaRegistry.add("PhiDaugh_neg/nSigmaTPC", "; #it{p} (GeV/#it{c}); n#sigma_{TPC}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - qaRegistry.add("PhiDaugh_neg/nSigmaTOF", "; #it{p} (GeV/#it{c}); n#sigma_{TOF}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); + qaRegistry.add("PhiDaugh_neg/nSigmaTPC", "; #it{p} (GeV/#it{c}); n#sigma_{TPC}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("PhiDaugh_neg/nSigmaTOF", "; #it{p} (GeV/#it{c}); n#sigma_{TOF}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); qaRegistry.add("PhiDaugh_neg/pt", "; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{100, 0, 10}}); qaRegistry.add("PhiDaugh_neg/eta", "; #it{eta}; Counts", kTH1F, {{200, -1.5, 1.5}}); - qaRegistry.add("PhiDaugh_neg/phi", "; #it{varphi}; Counts", kTH1F, {{200, 0, 2. * M_PI}}); + qaRegistry.add("PhiDaugh_neg/phi", "; #it{varphi}; Counts", kTH1F, {{200, 0, o2::constants::math::TwoPI}}); qaRegistry.add("PhiDaugh_neg/hDCAxy", "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {{100, 0, 10}, {500, -5, 5}}); - trackHistoPartPhi.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarInvMassBins, ConfBothTracks.ConfIsMC, ConfPhi.ConfPDGCodePhi); - if (!ConfTrack.ConfIsSame) { - trackHistoPartTrack.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarBins, ConfBothTracks.ConfIsMC, ConfTrack.ConfPDGCodeTrack); - } - - MixQaRegistry.add("MixingQA/hSECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); - MixQaRegistry.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); - - sameEventFemtoCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfBothTracks.ConfIsMC, ConfBothTracks.ConfUse3D); - mixedEventFemtoCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfBothTracks.ConfIsMC, ConfBothTracks.ConfUse3D); - sameEventAngularCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfBothTracks.ConfEtaBins, ConfBothTracks.ConfPhiBins, ConfBothTracks.ConfIsMC, ConfBothTracks.ConfUse3D); - mixedEventAngularCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfBothTracks.ConfEtaBins, ConfBothTracks.ConfPhiBins, ConfBothTracks.ConfIsMC, ConfBothTracks.ConfUse3D); - - sameEventFemtoCont.setPDGCodes(ConfPhi.ConfPDGCodePhi, ConfTrack.ConfPDGCodeTrack); - mixedEventFemtoCont.setPDGCodes(ConfPhi.ConfPDGCodePhi, ConfTrack.ConfPDGCodeTrack); - sameEventAngularCont.setPDGCodes(ConfPhi.ConfPDGCodePhi, ConfTrack.ConfPDGCodeTrack); - mixedEventAngularCont.setPDGCodes(ConfPhi.ConfPDGCodePhi, ConfTrack.ConfPDGCodeTrack); + registryPhiMinvBackground.add("InvariantMassKpKp", "; invariant mass K+K+; Counts", kTH1F, {{6000, 0.9, 4.0}}); + registryPhiMinvBackground.add("InvariantMassKmKm", "; invariant mass K-K-; Counts", kTH1F, {{6000, 0.9, 4.0}}); + + qaRegistry.add("Hadron_pos/nSigmaTPCPr", "; #it{p} (GeV/#it{c}); n#sigma_{TPCPr}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Hadron_pos/nSigmaTOFPr", "; #it{p} (GeV/#it{c}); n#sigma_{TOFPr}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Hadron_pos/nSigmaTPCPi", "; #it{p} (GeV/#it{c}); n#sigma_{TPCPi}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Hadron_pos/nSigmaTOFPi", "; #it{p} (GeV/#it{c}); n#sigma_{TOFPi}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Hadron_pos/nSigmaTPCKa", "; #it{p} (GeV/#it{c}); n#sigma_{TPCKa}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Hadron_pos/nSigmaTOFKa", "; #it{p} (GeV/#it{c}); n#sigma_{TOFKa}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + + qaRegistry.add("Hadron_neg/nSigmaTPCPr", "; #it{p} (GeV/#it{c}); n#sigma_{TPCPr}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Hadron_neg/nSigmaTOFPr", "; #it{p} (GeV/#it{c}); n#sigma_{TOFPr}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Hadron_neg/nSigmaTPCPi", "; #it{p} (GeV/#it{c}); n#sigma_{TPCPi}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Hadron_neg/nSigmaTOFPi", "; #it{p} (GeV/#it{c}); n#sigma_{TOFPi}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Hadron_neg/nSigmaTPCKa", "; #it{p} (GeV/#it{c}); n#sigma_{TPCKa}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Hadron_neg/nSigmaTOFKa", "; #it{p} (GeV/#it{c}); n#sigma_{TOFKa}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + + // MC truth + registryMCtruth.add("MCtruthAllPositivePt", "MC truth all positive;#it{p}_{T} (GeV/c); #eta", {HistType::kTH1F, {{500, 0, 5}}}); + registryMCtruth.add("MCtruthAllNegativePt", "MC truth all negative;#it{p}_{T} (GeV/c); #eta", {HistType::kTH1F, {{500, 0, 5}}}); + // K+ + registryMCtruth.add("MCtruthKp", "MC truth K+;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCtruth.add("MCtruthKpPt", "MC truth kaons positive;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + // K- + registryMCtruth.add("MCtruthKm", "MC truth protons;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCtruth.add("MCtruthKmPt", "MC truth kaons negative;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + // p + registryMCtruth.add("MCtruthPpos", "MC truth protons;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCtruth.add("MCtruthPposPt", "MC truth protons;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + // pbar + registryMCtruth.add("MCtruthPneg", "MC truth antiprotons;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCtruth.add("MCtruthPnegPt", "MC truth antiproton;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + // phi + registryMCtruth.add("MCtruthPhi", "MC truth phi mesons;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCtruth.add("MCtruthPhiPt", "MC truth phi mesons;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + + // MC reco + registryMCreco.add("MCrecoAllPositivePt", "MC reco all;#it{p}_{T} (GeV/c); #eta", {HistType::kTH1F, {{500, 0, 5}}}); + registryMCreco.add("MCrecoAllNegativePt", "MC reco all;#it{p}_{T} (GeV/c); #eta", {HistType::kTH1F, {{500, 0, 5}}}); + // p + registryMCreco.add("MCrecoPpos", "MC reco proton;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCreco.add("MCrecoPposPt", "MC reco proton; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{500, 0, 5}}); + // pbar + registryMCreco.add("MCrecoPneg", "MC reco antiproton;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCreco.add("MCrecoPnegPt", "MC reco antiproton; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{500, 0, 5}}); + // phi + registryMCreco.add("MCrecoPhi", "MC reco Phi;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCreco.add("MCrecoPhiPt", "MC reco Phi; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{500, 0, 5}}); + + trackHistoPartPhi.init(&qaRegistry, ConfBinsTempFitVarpT, ConfBinsTempFitVarInvMass, ConfIsMC, 333); + trackHistoPartTrack.init(&qaRegistry, ConfBinsTempFitVarpT, ConfBinsTempFitVar, ConfIsMC, ConfTrackPDGCode); + + mixQaRegistry.add("MixingQA/hSECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); + mixQaRegistry.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); + + sameEventCont.init(&resultRegistry, ConfBinskstar, ConfBinsMult, ConfBinskT, ConfBinsmT, ConfBins3Dmult, ConfBins3DmT, ConfBinsEta, ConfBinsPhi, ConfIsMC, ConfUse3D); + mixedEventCont.init(&resultRegistry, ConfBinskstar, ConfBinsMult, ConfBinskT, ConfBinsmT, ConfBins3Dmult, ConfBins3DmT, ConfBinsEta, ConfBinsPhi, ConfIsMC, ConfUse3D); + + sameEventCont.setPDGCodes(333, ConfTrackPDGCode); + mixedEventCont.setPDGCodes(333, ConfTrackPDGCode); pairCleaner.init(&qaRegistry); - if (ConfIsCPR.value) { - pairCloseRejection.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiCutMin.value, ConfCPRdeltaPhiCutMax.value, ConfCPRdeltaEtaCutMin.value, ConfCPRdeltaEtaCutMax.value, ConfCPRChosenRadii.value, ConfCPRPlotPerRadii.value); + if (ConfCPRIsEnabled) { + pairCloseRejection.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiCutMin, ConfCPRdeltaPhiCutMax, ConfCPRdeltaEtaCutMin, ConfCPRdeltaEtaCutMax, ConfCPRChosenRadii, ConfCPRPlotPerRadii, ConfCPRInvMassCutMin, ConfCPRInvMassCutMax); } - - vPIDPhiCandidate = ConfPhi.ConfPIDPhi.value; - vPIDTrack = ConfTrack.ConfPIDTrack.value; - kNsigma = ConfBothTracks.ConfTrkPIDnSigmaMax.value; - } - - template - void fillCollision(CollisionType col) - { - MixQaRegistry.fill(HIST("MixingQA/hSECollisionBins"), colBinning.getBin({col.posZ(), col.multNtr()})); - eventHisto.fillQA(col); } - /// This function processes the same event and takes care of all the histogramming - /// \todo the trivial loops over the tracks should be factored out since they will be common to all combinations of T-T, T-V0, V0-V0, ... - /// @tparam PartitionType - /// @tparam PartType - /// @tparam isMC: enables Monte Carlo truth specific histograms - /// @param groupPartsTrack partition for the first particle passed by the process function - /// @param groupPartsPhi partition for the second particle passed by the process function - /// @param parts femtoUniverseParticles table (in case of Monte Carlo joined with FemtoUniverseMCLabels) - /// @param magFieldTesla magnetic field of the collision - /// @param multCol multiplicity of the collision - template - void doSameEvent(PartitionType groupPartsTrack, PartitionType groupPartsPhi, PartitionType groupPartsPhiDaugh, PartType parts, float magFieldTesla, int multCol) + template + void doSameEvent(PartitionType groupPartsTrack, PartitionType groupPartsPhi, PartType parts, float magFieldTesla, int multCol, [[maybe_unused]] MCParticles mcParts = nullptr) { - - /// Histogramming same event - for (auto& phicandidate : groupPartsPhi) { - trackHistoPartPhi.fillQA(phicandidate); + for (auto const& phicandidate : groupPartsPhi) { + // TODO: add phi meson minv cut here + const auto& posChild = parts.iteratorAt(phicandidate.index() - 2); + float tpcNSigmaKp = trackCuts.getNsigmaTPC(posChild, o2::track::PID::Kaon); + float tofNSigmaKp = trackCuts.getNsigmaTOF(posChild, o2::track::PID::Kaon); + qaRegistry.fill(HIST("PhiDaugh_pos/nSigmaTPC"), posChild.p(), tpcNSigmaKp); + qaRegistry.fill(HIST("PhiDaugh_pos/nSigmaTOF"), posChild.p(), tofNSigmaKp); + qaRegistry.fill(HIST("PhiDaugh_pos/hDCAxy"), posChild.p(), posChild.tempFitVar()); + qaRegistry.fill(HIST("PhiDaugh_pos/pt"), posChild.pt()); + qaRegistry.fill(HIST("PhiDaugh_pos/eta"), posChild.eta()); + qaRegistry.fill(HIST("PhiDaugh_pos/phi"), posChild.phi()); + + const auto& negChild = parts.iteratorAt(phicandidate.index() - 1); + float tpcNSigmaKm = trackCuts.getNsigmaTPC(negChild, o2::track::PID::Kaon); + float tofNSigmaKm = trackCuts.getNsigmaTOF(negChild, o2::track::PID::Kaon); + qaRegistry.fill(HIST("PhiDaugh_neg/nSigmaTPC"), negChild.p(), tpcNSigmaKm); + qaRegistry.fill(HIST("PhiDaugh_neg/nSigmaTOF"), negChild.p(), tofNSigmaKm); + qaRegistry.fill(HIST("PhiDaugh_neg/pt"), negChild.pt()); + qaRegistry.fill(HIST("PhiDaugh_neg/eta"), negChild.eta()); + qaRegistry.fill(HIST("PhiDaugh_neg/phi"), negChild.phi()); + qaRegistry.fill(HIST("PhiDaugh_neg/hDCAxy"), negChild.p(), negChild.tempFitVar()); + + trackHistoPartPhi.fillQA(phicandidate); } - float tpcNSigma; - float tofNSigma; - for (auto& phidaugh : groupPartsPhiDaugh) { - if (phidaugh.mAntiLambda() == 1) { // workaround - tpcNSigma = trackCuts.getNsigmaTPC(phidaugh, o2::track::PID::Kaon); - tofNSigma = trackCuts.getNsigmaTOF(phidaugh, o2::track::PID::Kaon); - - qaRegistry.fill(HIST("PhiDaugh_pos/nSigmaTPC"), phidaugh.p(), tpcNSigma); - qaRegistry.fill(HIST("PhiDaugh_pos/nSigmaTOF"), phidaugh.p(), tofNSigma); - qaRegistry.fill(HIST("PhiDaugh_pos/hDCAxy"), phidaugh.p(), phidaugh.tempFitVar()); - qaRegistry.fill(HIST("PhiDaugh_pos/pt"), phidaugh.pt()); - qaRegistry.fill(HIST("PhiDaugh_pos/eta"), phidaugh.eta()); - qaRegistry.fill(HIST("PhiDaugh_pos/phi"), phidaugh.phi()); - } else if (phidaugh.mAntiLambda() == -1) { // workaround - tpcNSigma = trackCuts.getNsigmaTPC(phidaugh, o2::track::PID::Kaon); - tofNSigma = trackCuts.getNsigmaTOF(phidaugh, o2::track::PID::Kaon); - - qaRegistry.fill(HIST("PhiDaugh_neg/nSigmaTPC"), phidaugh.p(), tpcNSigma); - qaRegistry.fill(HIST("PhiDaugh_neg/nSigmaTOF"), phidaugh.p(), tofNSigma); - qaRegistry.fill(HIST("PhiDaugh_neg/pt"), phidaugh.pt()); - qaRegistry.fill(HIST("PhiDaugh_neg/eta"), phidaugh.eta()); - qaRegistry.fill(HIST("PhiDaugh_neg/phi"), phidaugh.phi()); - qaRegistry.fill(HIST("PhiDaugh_neg/hDCAxy"), phidaugh.p(), phidaugh.tempFitVar()); - } - } + for (auto const& track : groupPartsTrack) { + float tpcNSigmaPi = trackCuts.getNsigmaTPC(track, o2::track::PID::Pion); + float tofNSigmaPi = trackCuts.getNsigmaTOF(track, o2::track::PID::Pion); + float tpcNSigmaKa = trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon); + float tofNSigmaKa = trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon); + float tpcNSigmaPr = trackCuts.getNsigmaTPC(track, o2::track::PID::Proton); + float tofNSigmaPr = trackCuts.getNsigmaTOF(track, o2::track::PID::Proton); - if (!ConfTrack.ConfIsSame) { - for (auto& track : groupPartsTrack) { - // if (track.p() > ConfBothTracks.ConfCutTable->get("Track", "MaxP") || track.pt() > ConfBothTracks.ConfCutTable->get("Track", "MaxPt")) { - // continue; - // } - // if (!isFullPIDSelected(track.pidcut(), - // track.p(), - // ConfBothTracks.ConfCutTable->get("Track", "PIDthr"), - // vPIDTrack, - // ConfBothTracks.ConfNspecies, - // kNsigma, - // ConfBothTracks.ConfCutTable->get("Track", "nSigmaTPC"), - // ConfBothTracks.ConfCutTable->get("Track", "nSigmaTPCTOF"))) { - // continue; - // } - if (ConfTrack.ConfIsTrackIdentified) { - if (!IsParticleNSigma(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { + if (ConfTrackIsIdentified) { + if (!isParticleNSigmaAccepted(track.p(), tpcNSigmaPr, tofNSigmaPr, tpcNSigmaPi, tofNSigmaPi, tpcNSigmaKa, tofNSigmaKa)) { + continue; + } + if (ConfTrackIsRejected) { + if (isParticleNSigmaRejected(track.p(), tpcNSigmaPr, tofNSigmaPr, tpcNSigmaPi, tofNSigmaPi, tpcNSigmaKa, tofNSigmaKa)) { continue; } } - trackHistoPartTrack.fillQA(track); } + if (track.sign() > 0) { + qaRegistry.fill(HIST("Hadron_pos/nSigmaTPCPi"), track.p(), tpcNSigmaPi); + qaRegistry.fill(HIST("Hadron_pos/nSigmaTOFPi"), track.p(), tofNSigmaPi); + qaRegistry.fill(HIST("Hadron_pos/nSigmaTPCKa"), track.p(), tpcNSigmaKa); + qaRegistry.fill(HIST("Hadron_pos/nSigmaTOFKa"), track.p(), tofNSigmaKa); + qaRegistry.fill(HIST("Hadron_pos/nSigmaTPCPr"), track.p(), tpcNSigmaPr); + qaRegistry.fill(HIST("Hadron_pos/nSigmaTOFPr"), track.p(), tofNSigmaPr); + } else if (track.sign() < 0) { + qaRegistry.fill(HIST("Hadron_neg/nSigmaTPCPi"), track.p(), tpcNSigmaPi); + qaRegistry.fill(HIST("Hadron_neg/nSigmaTOFPi"), track.p(), tofNSigmaPi); + qaRegistry.fill(HIST("Hadron_neg/nSigmaTPCKa"), track.p(), tpcNSigmaKa); + qaRegistry.fill(HIST("Hadron_neg/nSigmaTOFKa"), track.p(), tofNSigmaKa); + qaRegistry.fill(HIST("Hadron_neg/nSigmaTPCPr"), track.p(), tpcNSigmaPr); + qaRegistry.fill(HIST("Hadron_neg/nSigmaTOFPr"), track.p(), tofNSigmaPr); + } + trackHistoPartTrack.fillQA(track); } + /// Now build the combinations - for (auto& [track, phicandidate] : combinations(CombinationsFullIndexPolicy(groupPartsTrack, groupPartsPhi))) { - // if (track.p() > ConfBothTracks.ConfCutTable->get("PhiCandidate", "MaxP") || track.pt() > ConfBothTracks.ConfCutTable->get("PhiCandidate", "MaxPt") || phicandidate.p() > ConfBothTracks.ConfCutTable->get("Track", "MaxP") || phicandidate.pt() > ConfBothTracks.ConfCutTable->get("Track", "MaxPt")) { - // continue; - // } - // if (!isFullPIDSelected(track.pidcut(), - // track.p(), - // ConfBothTracks.ConfCutTable->get("PhiCandidate", "PIDthr"), - // vPIDPhiCandidate, - // ConfBothTracks.ConfNspecies, - // kNsigma, - // ConfBothTracks.ConfCutTable->get("PhiCandidate", "nSigmaTPC"), - // ConfBothTracks.ConfCutTable->get("PhiCandidate", "nSigmaTPCTOF")) || - // !isFullPIDSelected(phicandidate.pidcut(), - // phicandidate.p(), - // ConfBothTracks.ConfCutTable->get("Track", "PIDthr"), - // vPIDTrack, - // ConfBothTracks.ConfNspecies, - // kNsigma, - // ConfBothTracks.ConfCutTable->get("Track", "nSigmaTPC"), - // ConfBothTracks.ConfCutTable->get("Track", "nSigmaTPCTOF"))) { - // continue; - // } - if (ConfTrack.ConfIsTrackIdentified) { - if (!IsParticleNSigma(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { + for (auto const& [track, phicandidate] : combinations(CombinationsFullIndexPolicy(groupPartsTrack, groupPartsPhi))) { + if (ConfTrackIsIdentified) { + if (!isParticleNSigmaAccepted(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { + continue; + } + } + + if (ConfTrackIsRejected) { + if (isParticleNSigmaRejected(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { continue; } } - // // Close Pair Rejection - if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(track, phicandidate, parts, magFieldTesla, femtoUniverseContainer::EventType::same)) { + + // Close Pair Rejection + if (ConfCPRIsEnabled) { + if (pairCloseRejection.isClosePair(track, phicandidate, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } } @@ -412,107 +556,89 @@ struct femtoUniversePairTaskTrackPhi { if (!pairCleaner.isCleanPair(track, phicandidate, parts)) { continue; } - sameEventFemtoCont.setPair(track, phicandidate, multCol, ConfBothTracks.ConfUse3D); - sameEventAngularCont.setPair(track, phicandidate, multCol, ConfBothTracks.ConfUse3D); - } - } - /// process function for to call doSameEvent with Data - /// \param col subscribe to the collision table (Data) - /// \param parts subscribe to the femtoUniverseParticleTable - void processSameEvent(o2::aod::FDCollision& col, - FemtoFullParticles& parts) - { - fillCollision(col); + weight = efficiencyCalculator.getWeight(ParticleNo::ONE, phicandidate.pt()) * efficiencyCalculator.getWeight(ParticleNo::TWO, track.pt()); - auto thegroupPartsTrack = partsTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto thegroupPartsPhi = partsPhi->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto thegroupPartsPhiDaugh = partsPhiDaugh->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + if constexpr (std::is_same::value) + sameEventCont.setPair(track, phicandidate, multCol, ConfUse3D, weight); + else + sameEventCont.setPair(track, phicandidate, multCol, ConfUse3D, weight); + } - doSameEvent(thegroupPartsTrack, thegroupPartsPhi, thegroupPartsPhiDaugh, parts, col.magField(), col.multNtr()); + // // Used for better fitting of invariant mass background. + + // TLorentzVector part1Vec; + // TLorentzVector part2Vec; + + // float mMassOne = o2::constants::physics::MassKPlus; + // float mMassTwo = o2::constants::physics::MassKMinus; + + // for (auto const& [kaon1, kaon2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsKaons, groupPartsKaons))) { + // if ((kaon1.mAntiLambda() == 1) && (kaon2.mAntiLambda() == 1)) { + // part1Vec.SetPtEtaPhiM(kaon1.pt(), kaon1.eta(), kaon1.phi(), mMassOne); + // part2Vec.SetPtEtaPhiM(kaon2.pt(), kaon2.eta(), kaon2.phi(), mMassOne); + // TLorentzVector sumVec(part1Vec); + // sumVec += part2Vec; + // registryPhiMinvBackground.fill(HIST("InvariantMassKpKp"), sumVec.M()); + // } + // if ((kaon1.mAntiLambda() == -1) && (kaon2.mAntiLambda() == -1)) { + // part1Vec.SetPtEtaPhiM(kaon1.pt(), kaon1.eta(), kaon1.phi(), mMassTwo); + // part2Vec.SetPtEtaPhiM(kaon2.pt(), kaon2.eta(), kaon2.phi(), mMassTwo); + + // TLorentzVector sumVec(part1Vec); + // sumVec += part2Vec; + // registryPhiMinvBackground.fill(HIST("InvariantMassKmKm"), sumVec.M()); + // } + // } } - PROCESS_SWITCH(femtoUniversePairTaskTrackPhi, processSameEvent, "Enable processing same event", true); - - /// process function for to call doSameEvent with Monte Carlo - /// \param col subscribe to the collision table (Monte Carlo Reconstructed reconstructed) - /// \param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth - /// \param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table - void processSameEventMC(o2::aod::FDCollision& col, - soa::Join& parts, - o2::aod::FDMCParticles&) - { - fillCollision(col); - - auto thegroupPartsPhi = partsPhiMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto thegroupPartsTrack = partsTrackMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto thegroupPartsPhiDaugh = partsPhiDaughMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - doSameEvent(thegroupPartsTrack, thegroupPartsPhi, thegroupPartsPhiDaugh, parts, col.magField(), col.multNtr()); - } - PROCESS_SWITCH(femtoUniversePairTaskTrackPhi, processSameEventMC, "Enable processing same event for Monte Carlo", false); - - /// This function processes the mixed event - /// \todo the trivial loops over the collisions and tracks should be factored out since they will be common to all combinations of T-T, T-V0, V0-V0, ... - /// \tparam PartitionType - /// \tparam PartType - /// \tparam isMC: enables Monte Carlo truth specific histograms - /// \param groupPartsTrack partition for the identified passed by the process function - /// \param groupPartsPhi partition for Phi meson passed by the process function - /// \param parts femtoUniverseParticles table (in case of Monte Carlo joined with FemtoUniverseMCLabels) - /// \param magFieldTesla magnetic field of the collision - /// \param multCol multiplicity of the collision - template - void doMixedEvent(PartitionType groupPartsTrack, PartitionType groupPartsPhi, PartType parts, float magFieldTesla, int multCol) + template + void doMixedEvent(PartitionType groupPartsTrack, PartitionType groupPartsPhi, PartType parts, float magFieldTesla, int multCol, [[maybe_unused]] MCParticles mcParts = nullptr) { - - for (auto& [track, phicandidate] : combinations(CombinationsFullIndexPolicy(groupPartsTrack, groupPartsPhi))) { - // if (track.p() > ConfBothTracks.ConfCutTable->get("PhiCandidate", "MaxP") || track.pt() > ConfBothTracks.ConfCutTable->get("PhiCandidate", "MaxPt") || phicandidate.p() > ConfBothTracks.ConfCutTable->get("Track", "MaxP") || phicandidate.pt() > ConfBothTracks.ConfCutTable->get("Track", "MaxPt")) { - // continue; - // } - // if (!isFullPIDSelected(track.pidcut(), - // track.p(), - // ConfBothTracks.ConfCutTable->get("PhiCandidate", "PIDthr"), - // vPIDPhiCandidate, - // ConfBothTracks.ConfNspecies, - // kNsigma, - // ConfBothTracks.ConfCutTable->get("PhiCandidate", "nSigmaTPC"), - // ConfBothTracks.ConfCutTable->get("PhiCandidate", "nSigmaTPCTOF")) || - // !isFullPIDSelected(phicandidate.pidcut(), - // phicandidate.p(), - // ConfBothTracks.ConfCutTable->get("Track", "PIDthr"), - // vPIDTrack, - // ConfBothTracks.ConfNspecies, - // kNsigma, - // ConfBothTracks.ConfCutTable->get("Track", "nSigmaTPC"), - // ConfBothTracks.ConfCutTable->get("Track", "nSigmaTPCTOF"))) { - // continue; - // } - if (ConfTrack.ConfIsTrackIdentified) { - if (!IsParticleNSigma(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { + for (auto const& [track, phicandidate] : combinations(CombinationsFullIndexPolicy(groupPartsTrack, groupPartsPhi))) { + if (ConfTrackIsIdentified) { + if (!isParticleNSigmaAccepted(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { continue; } + if (ConfTrackIsRejected) { + if (isParticleNSigmaRejected(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { + continue; + } + } } - if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(track, phicandidate, parts, magFieldTesla, femtoUniverseContainer::EventType::mixed)) { + + if (ConfCPRIsEnabled) { + if (pairCloseRejection.isClosePair(track, phicandidate, parts, magFieldTesla, femto_universe_container::EventType::mixed)) { continue; } } - mixedEventFemtoCont.setPair(track, phicandidate, multCol, ConfBothTracks.ConfUse3D); - mixedEventAngularCont.setPair(track, phicandidate, multCol, ConfBothTracks.ConfUse3D); + weight = efficiencyCalculator.getWeight(ParticleNo::ONE, phicandidate.pt()) * efficiencyCalculator.getWeight(ParticleNo::TWO, track.pt()); + + if constexpr (std::is_same::value) + mixedEventCont.setPair(track, phicandidate, multCol, ConfUse3D, weight); + else + mixedEventCont.setPair(track, phicandidate, multCol, ConfUse3D, weight); } } - /// process function for to call doMixedEvent with Data - /// @param cols subscribe to the collisions table (Data) - /// @param parts subscribe to the femtoUniverseParticleTable - void processMixedEvent(o2::aod::FDCollisions& cols, - FemtoFullParticles& parts) + void processSameEvent(FilteredFDCollision const& col, FilteredFemtoFullParticles const& parts) { - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + auto thegroupPartsTrack = partsTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegroupPartsPhi = partsPhi->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + // auto thegroupPartsPhiDaugh = partsPhiDaugh->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + // auto thegroupPartsKaons = partsKaons->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + eventHisto.fillQA(col); + doSameEvent(thegroupPartsTrack, thegroupPartsPhi, parts, col.magField(), col.multNtr()); + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackPhi, processSameEvent, "Enable processing same event", true); + + void processMixedEvent(FilteredFDCollisions const& cols, FilteredFemtoFullParticles const& parts) + { + for (auto const& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { const int multiplicityCol = collision1.multNtr(); - MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); auto groupPartsTrack = partsTrack->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); auto groupPartsPhi = partsPhi->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); @@ -523,29 +649,30 @@ struct femtoUniversePairTaskTrackPhi { if (magFieldTesla1 != magFieldTesla2) { continue; } - /// \todo before mixing we should check whether both collisions contain a pair of particles! - // if (partsPhi.size() == 0 || nPart2Evt1 == 0 || nPart1Evt2 == 0 || partsTrack.size() == 0 ) continue; - doMixedEvent(groupPartsTrack, groupPartsPhi, parts, magFieldTesla1, multiplicityCol); + doMixedEvent(groupPartsTrack, groupPartsPhi, parts, magFieldTesla1, multiplicityCol); } } - PROCESS_SWITCH(femtoUniversePairTaskTrackPhi, processMixedEvent, "Enable processing mixed events", true); - - /// brief process function for to call doMixedEvent with Monte Carlo - /// @param cols subscribe to the collisions table (Monte Carlo Reconstructed reconstructed) - /// @param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth - /// @param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table - void processMixedEventMC(o2::aod::FDCollisions& cols, - soa::Join& parts, - o2::aod::FDMCParticles&) + PROCESS_SWITCH(FemtoUniversePairTaskTrackPhi, processMixedEvent, "Enable processing mixed events", true); + + ///--------------------------------------------MC-------------------------------------------------/// + void processSameEventMCReco(FilteredFDCollision const& col, FemtoRecoParticles const& parts, aod::FdMCParticles const& mcparts) + { + auto thegroupPartsTrack = partsTrackMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegroupPartsPhi = partsPhiMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + // auto thegroupPartsPhiDaugh = partsPhiDaugh->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + // auto thegroupPartsKaons = partsKaons->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + eventHisto.fillQA(col); + doSameEvent(thegroupPartsTrack, thegroupPartsPhi, parts, col.magField(), col.multNtr(), mcparts); + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackPhi, processSameEventMCReco, "Enable processing same event for MC Reco", true); + + void processMixedEventMCReco(FilteredFDCollisions const& cols, FemtoRecoParticles const& parts, aod::FdMCParticles const& mcparts) { - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + for (auto const& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { const int multiplicityCol = collision1.multNtr(); - MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); - - auto groupPartsTrack = partsTrackMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); - auto groupPartsPhi = partsPhiMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); const auto& magFieldTesla1 = collision1.magField(); const auto& magFieldTesla2 = collision2.magField(); @@ -553,19 +680,116 @@ struct femtoUniversePairTaskTrackPhi { if (magFieldTesla1 != magFieldTesla2) { continue; } - /// \todo before mixing we should check whether both collisions contain a pair of particles! - // if (partsPhi.size() == 0 || nPart2Evt1 == 0 || nPart1Evt2 == 0 || partsTrack.size() == 0 ) continue; - doMixedEvent(groupPartsTrack, groupPartsPhi, parts, magFieldTesla1, multiplicityCol); + auto groupPartsTrack = partsTrackMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + auto groupPartsPhi = partsPhiMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + + doMixedEvent(groupPartsTrack, groupPartsPhi, parts, magFieldTesla1, multiplicityCol, mcparts); } } - PROCESS_SWITCH(femtoUniversePairTaskTrackPhi, processMixedEventMC, "Enable processing mixed events MC", false); + PROCESS_SWITCH(FemtoUniversePairTaskTrackPhi, processMixedEventMCReco, "Enable processing mixed events for MC Reco", false); + + /// This function fills MC truth particles from derived MC table + void processMCTruth(aod::FDParticles const& parts) + { + for (auto const& part : parts) { + if (part.partType() != uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) + continue; + + int pdgCode = static_cast(part.pidCut()); + const auto& pdgParticle = pdgMC->GetParticle(pdgCode); + if (!pdgParticle) { + continue; + } + + // charge + + if (pdgParticle->Charge() > 0.0) { + registryMCtruth.fill(HIST("MCtruthAllPositivePt"), part.pt()); + if (pdgCode == 2212) { + registryMCtruth.fill(HIST("MCtruthPpos"), part.pt(), part.eta()); + registryMCtruth.fill(HIST("MCtruthPposPt"), part.pt()); + continue; + } else if (pdgCode == 321) { + registryMCtruth.fill(HIST("MCtruthKp"), part.pt(), part.eta()); + registryMCtruth.fill(HIST("MCtruthKpPt"), part.pt()); + continue; + } + } + // charge 0 + if (pdgCode == 333) { + registryMCtruth.fill(HIST("MCtruthPhi"), part.pt(), part.eta()); + registryMCtruth.fill(HIST("MCtruthPhiPt"), part.pt()); + continue; + } + + // charge - + if (pdgParticle->Charge() < 0.0) { + registryMCtruth.fill(HIST("MCtruthAllNegativePt"), part.pt()); + + if (pdgCode == -321) { + registryMCtruth.fill(HIST("MCtruthKm"), part.pt(), part.eta()); + registryMCtruth.fill(HIST("MCtruthKmPt"), part.pt()); + continue; + } else if (pdgCode == -2212) { + registryMCtruth.fill(HIST("MCtruthPneg"), part.pt(), part.eta()); + registryMCtruth.fill(HIST("MCtruthPnegPt"), part.pt()); + continue; + } + } + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackPhi, processMCTruth, "Process MC truth data", false); + + void processMCReco(FemtoRecoParticles const& parts, aod::FdMCParticles const& mcparts) + { + for (auto const& part : parts) { + auto mcPartId = part.fdMCParticleId(); + if (mcPartId == -1) + continue; // no MC particle + const auto& mcpart = mcparts.iteratorAt(mcPartId); + + if (mcpart.pdgMCTruth() == ConfTrackPDGCode && (part.pt() > ConfTrackPtLow) && (part.pt() < ConfTrackPtHigh) && isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { + registryMCpT.fill(HIST("MCReco/NC_p_pT"), part.pt()); + float weightTrack = efficiencyCalculator.getWeight(ParticleNo::TWO, part.pt()); + registryMCpT.fill(HIST("MCReco/C_p_pT"), part.pt(), weightTrack); + } + if ((mcpart.pdgMCTruth() == 333) && (part.partType() == aod::femtouniverseparticle::ParticleType::kPhi) && (part.pt() > ConfPhiPtLow) && (part.pt() < ConfPhiPtHigh)) { + registryMCpT.fill(HIST("MCReco/NC_phi_pT"), part.pt()); + float weightPhi = efficiencyCalculator.getWeight(ParticleNo::ONE, part.pt()); + registryMCpT.fill(HIST("MCReco/C_phi_pT"), part.pt(), weightPhi); + } + + if (isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) + hTrackDCA.fillQA(part); + if ((part.partType() == aod::femtouniverseparticle::ParticleType::kPhi) && (mcpart.pdgMCTruth() == 333) && (mcpart.partOriginMCTruth() == aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary)) { + registryMCreco.fill(HIST("MCrecoPhi"), mcpart.pt(), mcpart.eta()); // phi + registryMCreco.fill(HIST("MCrecoPhiPt"), mcpart.pt()); + } else if (part.partType() == aod::femtouniverseparticle::ParticleType::kTrack) { + if (part.sign() > 0) { + registryMCreco.fill(HIST("MCrecoAllPositivePt"), mcpart.pt()); + if (mcpart.pdgMCTruth() == 2212 && isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { + registryMCreco.fill(HIST("MCrecoPpos"), mcpart.pt(), mcpart.eta()); + registryMCreco.fill(HIST("MCrecoPposPt"), mcpart.pt()); + } + } else if (part.sign() < 0) { + registryMCreco.fill(HIST("MCrecoAllNegativePt"), mcpart.pt()); + if (mcpart.pdgMCTruth() == -2212 && isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { + registryMCreco.fill(HIST("MCrecoPneg"), mcpart.pt(), mcpart.eta()); + registryMCreco.fill(HIST("MCrecoPnegPt"), mcpart.pt()); + } + } + + } // partType kTrack + } + } + + PROCESS_SWITCH(FemtoUniversePairTaskTrackPhi, processMCReco, "Process MC reco data", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow{ - adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), }; return workflow; } diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrack.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrack.cxx index 72157d49253..8bb56e9d53a 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrack.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrack.cxx @@ -14,6 +14,7 @@ /// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de /// \author Georgios Mantzaridis, TU München, georgios.mantzaridis@tum.de /// \author Anton Riedel, TU München, anton.riedel@tum.de +/// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch #include #include "Framework/AnalysisTask.h" @@ -23,7 +24,6 @@ #include "Framework/RunningWorkflowInfo.h" #include "Framework/StepTHn.h" #include "Framework/O2DatabasePDGPlugin.h" -#include "TDatabasePDG.h" #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" @@ -32,63 +32,63 @@ #include "PWGCF/FemtoUniverse/Core/FemtoUniverseFemtoContainer.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseAngularContainer.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" using namespace o2; -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; namespace { -static constexpr int nPart = 2; -static constexpr int nCuts = 5; +static constexpr int NPart = 2; +static constexpr int NCuts = 5; static const std::vector partNames{"PartOne", "PartTwo"}; static const std::vector cutNames{"MaxPt", "PIDthr", "nSigmaTPC", "nSigmaTPCTOF", "MaxP"}; -static const float cutsTable[nPart][nCuts]{ +static const float cutsTable[NPart][NCuts]{ {4.05f, 1.f, 3.f, 3.f, 100.f}, {4.05f, 1.f, 3.f, 3.f, 100.f}}; } // namespace -struct femtoUniversePairTaskTrackTrack { +struct FemtoUniversePairTaskTrackTrack { SliceCache cache; Preslice perCol = aod::femtouniverseparticle::fdCollisionId; /// Particle selection part /// Table for both particles - Configurable> ConfCutTable{"ConfCutTable", {cutsTable[0], nPart, nCuts, partNames, cutNames}, "Particle selections"}; - Configurable ConfNspecies{"ConfNspecies", 2, "Number of particle spieces with PID info"}; - Configurable ConfIsMC{"ConfIsMC", false, "Enable additional Histogramms in the case of a MonteCarlo Run"}; - Configurable> ConfTrkPIDnSigmaMax{"ConfTrkPIDnSigmaMax", std::vector{4.f, 3.f, 2.f}, "This configurable needs to be the same as the one used in the producer task"}; - Configurable ConfUse3D{"ConfUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; + Configurable> confCutTable{"confCutTable", {cutsTable[0], NPart, NCuts, partNames, cutNames}, "Particle selections"}; + Configurable confNspecies{"confNspecies", 2, "Number of particle spieces with PID info"}; + Configurable confIsMC{"confIsMC", false, "Enable additional Histogramms in the case of a MonteCarlo Run"}; + Configurable> confTrkPIDnSigmaMax{"confTrkPIDnSigmaMax", std::vector{4.f, 3.f, 2.f}, "This configurable needs to be the same as the one used in the producer task"}; + Configurable confUse3D{"confUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; /// Particle 1 - Configurable ConfPDGCodePartOne{"ConfPDGCodePartOne", 2212, "Particle 1 - PDG code"}; - Configurable ConfCutPartOne{"ConfCutPartOne", 5542474, "Particle 1 - Selection bit from cutCulator"}; - Configurable ConfPIDPartOne{"ConfPIDPartOne", 2, "Particle 1 - Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector>int>> + Configurable confPDGCodePartOne{"confPDGCodePartOne", 2212, "Particle 1 - PDG code"}; + Configurable confCutPartOne{"confCutPartOne", 5542474, "Particle 1 - Selection bit from cutCulator"}; + Configurable confPIDPartOne{"confPIDPartOne", 2, "Particle 1 - Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector>int>> /// Partition for particle 1 - Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && ((aod::femtouniverseparticle::cut & ConfCutPartOne) == ConfCutPartOne); - Partition> partsOneMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && ((aod::femtouniverseparticle::cut & ConfCutPartOne) == ConfCutPartOne); + Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && ((aod::femtouniverseparticle::cut & confCutPartOne) == confCutPartOne); + Partition> partsOneMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && ((aod::femtouniverseparticle::cut & confCutPartOne) == confCutPartOne); /// Histogramming for particle 1 FemtoUniverseParticleHisto trackHistoPartOne; /// Particle 2 - Configurable ConfIsSame{"ConfIsSame", false, "Pairs of the same particle"}; - Configurable ConfPDGCodePartTwo{"ConfPDGCodePartTwo", 2212, "Particle 2 - PDG code"}; - Configurable ConfCutPartTwo{"ConfCutPartTwo", 5542474, "Particle 2 - Selection bit"}; - Configurable ConfPIDPartTwo{"ConfPIDPartTwo", 2, "Particle 2 - Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector> + Configurable confIsSame{"confIsSame", false, "Pairs of the same particle"}; + Configurable confPDGCodePartTwo{"confPDGCodePartTwo", 2212, "Particle 2 - PDG code"}; + Configurable confCutPartTwo{"confCutPartTwo", 5542474, "Particle 2 - Selection bit"}; + Configurable confPIDPartTwo{"confPIDPartTwo", 2, "Particle 2 - Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector> /// Partition for particle 2 Partition partsTwo = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && // (aod::femtouniverseparticle::pt < cfgCutTable->get("PartTwo", "MaxPt")) && - ((aod::femtouniverseparticle::cut & ConfCutPartTwo) == ConfCutPartTwo); + ((aod::femtouniverseparticle::cut & confCutPartTwo) == confCutPartTwo); Partition> partsTwoMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && - ((aod::femtouniverseparticle::cut & ConfCutPartTwo) == ConfCutPartTwo); + ((aod::femtouniverseparticle::cut & confCutPartTwo) == confCutPartTwo); /// Histogramming for particle 2 FemtoUniverseParticleHisto trackHistoPartTwo; @@ -101,81 +101,80 @@ struct femtoUniversePairTaskTrackTrack { std::vector kNsigma; /// particle part - ConfigurableAxis ConfTempFitVarBins{"ConfDTempFitVarBins", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfTempFitVarpTBins{"ConfTempFitVarpTBins", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; + ConfigurableAxis confTempFitVarBins{"confTempFitVarBins", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis confTempFitVarpTBins{"confTempFitVarpTBins", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; /// Correlation part - ConfigurableAxis ConfMultBins{"ConfMultBins", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; // \todo to be obtained from the hash task - // ConfigurableAxis ConfMultBins{"CfgMultBins", {VARIABLE_WIDTH, 0.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; - ConfigurableAxis ConfVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - - ConfigurableAxis ConfmTBins3D{"ConfmTBins3D", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; - ConfigurableAxis ConfmultBins3D{"ConfmultBins3D", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; - - ColumnBinningPolicy colBinning{{ConfVtxBins, ConfMultBins}, true}; - - ConfigurableAxis ConfkstarBins{"ConfkstarBins", {1500, 0., 6.}, "binning kstar"}; - ConfigurableAxis ConfkTBins{"ConfkTBins", {150, 0., 9.}, "binning kT"}; - ConfigurableAxis ConfmTBins{"ConfmTBins", {225, 0., 7.5}, "binning mT"}; - Configurable ConfNEventsMix{"ConfNEventsMix", 5, "Number of events for mixing"}; - Configurable ConfIsCPR{"ConfIsCPR", true, "Close Pair Rejection"}; - Configurable ConfCPRPlotPerRadii{"ConfCPRPlotPerRadii", false, "Plot CPR per radii"}; - Configurable ConfCPRdeltaPhiCutMax{"ConfCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaPhiCutMin{"ConfCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaEtaCutMax{"ConfCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaEtaCutMin{"ConfCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; - Configurable ConfCPRChosenRadii{"ConfCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; - Configurable ConfPhiBins{"ConfPhiBins", 29, "Number of phi bins in deta dphi"}; - Configurable ConfEtaBins{"ConfEtaBins", 29, "Number of eta bins in deta dphi"}; - - FemtoUniverseFemtoContainer sameEventFemtoCont; - FemtoUniverseFemtoContainer mixedEventFemtoCont; - FemtoUniverseAngularContainer sameEventAngularCont; - FemtoUniverseAngularContainer mixedEventAngularCont; + ConfigurableAxis confMultBins{"confMultBins", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; // \todo to be obtained from the hash task + ConfigurableAxis confVtxBins{"confVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + + ConfigurableAxis confmTBins3D{"confmTBins3D", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + ConfigurableAxis confMultBins3D{"confMultBins3D", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + + ColumnBinningPolicy colBinning{{confVtxBins, confMultBins}, true}; + + ConfigurableAxis confkstarBins{"confkstarBins", {1500, 0., 6.}, "binning kstar"}; + ConfigurableAxis confkTBins{"confkTBins", {150, 0., 9.}, "binning kT"}; + ConfigurableAxis confmTBins{"confmTBins", {225, 0., 7.5}, "binning mT"}; + Configurable confNEventsMix{"confNEventsMix", 5, "Number of events for mixing"}; + Configurable confIsCPR{"confIsCPR", true, "Close Pair Rejection"}; + Configurable confCPRPlotPerRadii{"confCPRPlotPerRadii", false, "Plot CPR per radii"}; + Configurable confCPRdeltaPhiCutMax{"confCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; + Configurable confCPRdeltaPhiCutMin{"confCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMax{"confCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMin{"confCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; + Configurable confCPRChosenRadii{"confCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; + Configurable confPhiBins{"confPhiBins", 29, "Number of phi bins in deta dphi"}; + Configurable confEtaBins{"confEtaBins", 29, "Number of eta bins in deta dphi"}; + + FemtoUniverseFemtoContainer sameEventFemtoCont; + FemtoUniverseFemtoContainer mixedEventFemtoCont; + FemtoUniverseAngularContainer sameEventAngularCont; + FemtoUniverseAngularContainer mixedEventAngularCont; FemtoUniversePairCleaner pairCleaner; FemtoUniverseDetaDphiStar pairCloseRejection; /// Histogram output HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry resultRegistry{"Correlations", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry MixQaRegistry{"MixQaRegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry mixQaRegistry{"mixQaRegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext&) { eventHisto.init(&qaRegistry); - trackHistoPartOne.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarBins, ConfIsMC, ConfPDGCodePartOne, false); - if (!ConfIsSame) { - trackHistoPartTwo.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarBins, ConfIsMC, ConfPDGCodePartTwo, false); + trackHistoPartOne.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarBins, confIsMC, confPDGCodePartOne, false); + if (!confIsSame) { + trackHistoPartTwo.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarBins, confIsMC, confPDGCodePartTwo, false); } - MixQaRegistry.add("MixingQA/hSECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); - MixQaRegistry.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); + mixQaRegistry.add("MixingQA/hSECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); + mixQaRegistry.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); - sameEventFemtoCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfIsMC, ConfUse3D); - mixedEventFemtoCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfIsMC, ConfUse3D); - sameEventAngularCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfEtaBins, ConfPhiBins, ConfIsMC, ConfUse3D); - mixedEventAngularCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfEtaBins, ConfPhiBins, ConfIsMC, ConfUse3D); + sameEventFemtoCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confIsMC, confUse3D); + mixedEventFemtoCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confIsMC, confUse3D); + sameEventAngularCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); + mixedEventAngularCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); - sameEventFemtoCont.setPDGCodes(ConfPDGCodePartOne, ConfPDGCodePartTwo); - mixedEventFemtoCont.setPDGCodes(ConfPDGCodePartOne, ConfPDGCodePartTwo); - sameEventAngularCont.setPDGCodes(ConfPDGCodePartOne, ConfPDGCodePartTwo); - mixedEventAngularCont.setPDGCodes(ConfPDGCodePartOne, ConfPDGCodePartTwo); + sameEventFemtoCont.setPDGCodes(confPDGCodePartOne, confPDGCodePartTwo); + mixedEventFemtoCont.setPDGCodes(confPDGCodePartOne, confPDGCodePartTwo); + sameEventAngularCont.setPDGCodes(confPDGCodePartOne, confPDGCodePartTwo); + mixedEventAngularCont.setPDGCodes(confPDGCodePartOne, confPDGCodePartTwo); pairCleaner.init(&qaRegistry); - if (ConfIsCPR.value) { - pairCloseRejection.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiCutMin.value, ConfCPRdeltaPhiCutMax.value, ConfCPRdeltaEtaCutMin.value, ConfCPRdeltaEtaCutMax.value, ConfCPRChosenRadii.value, ConfCPRPlotPerRadii.value); + if (confIsCPR.value) { + pairCloseRejection.init(&resultRegistry, &qaRegistry, confCPRdeltaPhiCutMin.value, confCPRdeltaPhiCutMax.value, confCPRdeltaEtaCutMin.value, confCPRdeltaEtaCutMax.value, confCPRChosenRadii.value, confCPRPlotPerRadii.value); } - vPIDPartOne = ConfPIDPartOne.value; - vPIDPartTwo = ConfPIDPartTwo.value; - kNsigma = ConfTrkPIDnSigmaMax.value; + vPIDPartOne = confPIDPartOne.value; + vPIDPartTwo = confPIDPartTwo.value; + kNsigma = confTrkPIDnSigmaMax.value; } template void fillCollision(CollisionType col) { - MixQaRegistry.fill(HIST("MixingQA/hSECollisionBins"), colBinning.getBin({col.posZ(), col.multNtr()})); + mixQaRegistry.fill(HIST("MixingQA/hSECollisionBins"), colBinning.getBin({col.posZ(), col.multNtr()})); eventHisto.fillQA(col); } @@ -194,68 +193,68 @@ struct femtoUniversePairTaskTrackTrack { { /// Histogramming same event - for (auto& part : groupPartsOne) { - if (part.p() > ConfCutTable->get("PartOne", "MaxP") || part.pt() > ConfCutTable->get("PartOne", "MaxPt")) { + for (const auto& part : groupPartsOne) { + if (part.p() > confCutTable->get("PartOne", "MaxP") || part.pt() > confCutTable->get("PartOne", "MaxPt")) { continue; } - if (!isFullPIDSelected(part.pidcut(), + if (!isFullPIDSelected(part.pidCut(), part.p(), - ConfCutTable->get("PartOne", "PIDthr"), + confCutTable->get("PartOne", "PIDthr"), vPIDPartOne, - ConfNspecies, + confNspecies, kNsigma, - ConfCutTable->get("PartOne", "nSigmaTPC"), - ConfCutTable->get("PartOne", "nSigmaTPCTOF"))) { + confCutTable->get("PartOne", "nSigmaTPC"), + confCutTable->get("PartOne", "nSigmaTPCTOF"))) { continue; } trackHistoPartOne.fillQA(part); } - if (!ConfIsSame) { - for (auto& part : groupPartsTwo) { - if (part.p() > ConfCutTable->get("PartTwo", "MaxP") || part.pt() > ConfCutTable->get("PartTwo", "MaxPt")) { + if (!confIsSame) { + for (const auto& part : groupPartsTwo) { + if (part.p() > confCutTable->get("PartTwo", "MaxP") || part.pt() > confCutTable->get("PartTwo", "MaxPt")) { continue; } - if (!isFullPIDSelected(part.pidcut(), + if (!isFullPIDSelected(part.pidCut(), part.p(), - ConfCutTable->get("PartTwo", "PIDthr"), + confCutTable->get("PartTwo", "PIDthr"), vPIDPartTwo, - ConfNspecies, + confNspecies, kNsigma, - ConfCutTable->get("PartTwo", "nSigmaTPC"), - ConfCutTable->get("PartTwo", "nSigmaTPCTOF"))) { + confCutTable->get("PartTwo", "nSigmaTPC"), + confCutTable->get("PartTwo", "nSigmaTPCTOF"))) { continue; } trackHistoPartTwo.fillQA(part); } } /// Now build the combinations - for (auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsOne, groupPartsTwo))) { - if (p1.p() > ConfCutTable->get("PartOne", "MaxP") || p1.pt() > ConfCutTable->get("PartOne", "MaxPt") || p2.p() > ConfCutTable->get("PartTwo", "MaxP") || p2.pt() > ConfCutTable->get("PartTwo", "MaxPt")) { + for (const auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsOne, groupPartsTwo))) { + if (p1.p() > confCutTable->get("PartOne", "MaxP") || p1.pt() > confCutTable->get("PartOne", "MaxPt") || p2.p() > confCutTable->get("PartTwo", "MaxP") || p2.pt() > confCutTable->get("PartTwo", "MaxPt")) { continue; } - if (!isFullPIDSelected(p1.pidcut(), + if (!isFullPIDSelected(p1.pidCut(), p1.p(), - ConfCutTable->get("PartOne", "PIDthr"), + confCutTable->get("PartOne", "PIDthr"), vPIDPartOne, - ConfNspecies, + confNspecies, kNsigma, - ConfCutTable->get("PartOne", "nSigmaTPC"), - ConfCutTable->get("PartOne", "nSigmaTPCTOF")) || - !isFullPIDSelected(p2.pidcut(), + confCutTable->get("PartOne", "nSigmaTPC"), + confCutTable->get("PartOne", "nSigmaTPCTOF")) || + !isFullPIDSelected(p2.pidCut(), p2.p(), - ConfCutTable->get("PartTwo", "PIDthr"), + confCutTable->get("PartTwo", "PIDthr"), vPIDPartTwo, - ConfNspecies, + confNspecies, kNsigma, - ConfCutTable->get("PartTwo", "nSigmaTPC"), - ConfCutTable->get("PartTwo", "nSigmaTPCTOF"))) { + confCutTable->get("PartTwo", "nSigmaTPC"), + confCutTable->get("PartTwo", "nSigmaTPCTOF"))) { continue; } - if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::same)) { + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } } @@ -265,16 +264,16 @@ struct femtoUniversePairTaskTrackTrack { continue; } - sameEventFemtoCont.setPair(p1, p2, multCol, ConfUse3D); - sameEventAngularCont.setPair(p1, p2, multCol, ConfUse3D); + sameEventFemtoCont.setPair(p1, p2, multCol, confUse3D); + sameEventAngularCont.setPair(p1, p2, multCol, confUse3D); } } /// process function for to call doSameEvent with Data /// \param col subscribe to the collision table (Data) /// \param parts subscribe to the femtoUniverseParticleTable - void processSameEvent(o2::aod::FDCollision& col, - o2::aod::FDParticles& parts) + void processSameEvent(const o2::aod::FdCollision& col, + const o2::aod::FDParticles& parts) { fillCollision(col); @@ -283,15 +282,15 @@ struct femtoUniversePairTaskTrackTrack { doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multNtr()); } - PROCESS_SWITCH(femtoUniversePairTaskTrackTrack, processSameEvent, "Enable processing same event", true); + PROCESS_SWITCH(FemtoUniversePairTaskTrackTrack, processSameEvent, "Enable processing same event", true); /// process function for to call doSameEvent with Monte Carlo /// \param col subscribe to the collision table (Monte Carlo Reconstructed reconstructed) /// \param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth /// \param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table - void processSameEventMC(o2::aod::FDCollision& col, - soa::Join& parts, - o2::aod::FDMCParticles&) + void processSameEventMC(const o2::aod::FdCollision& col, + const soa::Join& parts, + const o2::aod::FdMCParticles&) { fillCollision(col); @@ -300,7 +299,7 @@ struct femtoUniversePairTaskTrackTrack { doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multNtr()); } - PROCESS_SWITCH(femtoUniversePairTaskTrackTrack, processSameEventMC, "Enable processing same event for Monte Carlo", false); + PROCESS_SWITCH(FemtoUniversePairTaskTrackTrack, processSameEventMC, "Enable processing same event for Monte Carlo", false); /// This function processes the mixed event /// \todo the trivial loops over the collisions and tracks should be factored out since they will be common to all combinations of T-T, T-V0, V0-V0, ... @@ -316,50 +315,50 @@ struct femtoUniversePairTaskTrackTrack { void doMixedEvent(PartitionType groupPartsOne, PartitionType groupPartsTwo, PartType parts, float magFieldTesla, int multCol) { - for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { - if (p1.p() > ConfCutTable->get("PartOne", "MaxP") || p1.pt() > ConfCutTable->get("PartOne", "MaxPt") || p2.p() > ConfCutTable->get("PartTwo", "MaxP") || p2.pt() > ConfCutTable->get("PartTwo", "MaxPt")) { + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + if (p1.p() > confCutTable->get("PartOne", "MaxP") || p1.pt() > confCutTable->get("PartOne", "MaxPt") || p2.p() > confCutTable->get("PartTwo", "MaxP") || p2.pt() > confCutTable->get("PartTwo", "MaxPt")) { continue; } - if (!isFullPIDSelected(p1.pidcut(), + if (!isFullPIDSelected(p1.pidCut(), p1.p(), - ConfCutTable->get("PartOne", "PIDthr"), + confCutTable->get("PartOne", "PIDthr"), vPIDPartOne, - ConfNspecies, + confNspecies, kNsigma, - ConfCutTable->get("PartOne", "nSigmaTPC"), - ConfCutTable->get("PartOne", "nSigmaTPCTOF")) || - !isFullPIDSelected(p2.pidcut(), + confCutTable->get("PartOne", "nSigmaTPC"), + confCutTable->get("PartOne", "nSigmaTPCTOF")) || + !isFullPIDSelected(p2.pidCut(), p2.p(), - ConfCutTable->get("PartTwo", "PIDthr"), + confCutTable->get("PartTwo", "PIDthr"), vPIDPartTwo, - ConfNspecies, + confNspecies, kNsigma, - ConfCutTable->get("PartTwo", "nSigmaTPC"), - ConfCutTable->get("PartTwo", "nSigmaTPCTOF"))) { + confCutTable->get("PartTwo", "nSigmaTPC"), + confCutTable->get("PartTwo", "nSigmaTPCTOF"))) { continue; } - if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::mixed)) { + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::mixed)) { continue; } } - mixedEventFemtoCont.setPair(p1, p2, multCol, ConfUse3D); - mixedEventAngularCont.setPair(p1, p2, multCol, ConfUse3D); + mixedEventFemtoCont.setPair(p1, p2, multCol, confUse3D); + mixedEventAngularCont.setPair(p1, p2, multCol, confUse3D); } } /// process function for to call doMixedEvent with Data /// @param cols subscribe to the collisions table (Data) /// @param parts subscribe to the femtoUniverseParticleTable - void processMixedEvent(o2::aod::FDCollisions& cols, - o2::aod::FDParticles& parts) + void processMixedEvent(const o2::aod::FdCollisions& cols, + const o2::aod::FDParticles& parts) { - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { const int multiplicityCol = collision1.multNtr(); - MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); @@ -376,20 +375,20 @@ struct femtoUniversePairTaskTrackTrack { doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol); } } - PROCESS_SWITCH(femtoUniversePairTaskTrackTrack, processMixedEvent, "Enable processing mixed events", true); + PROCESS_SWITCH(FemtoUniversePairTaskTrackTrack, processMixedEvent, "Enable processing mixed events", true); /// brief process function for to call doMixedEvent with Monte Carlo /// @param cols subscribe to the collisions table (Monte Carlo Reconstructed reconstructed) /// @param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth /// @param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table - void processMixedEventMC(o2::aod::FDCollisions& cols, - soa::Join& parts, - o2::aod::FDMCParticles&) + void processMixedEventMC(const o2::aod::FdCollisions& cols, + const soa::Join& parts, + const o2::aod::FdMCParticles&) { - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { const int multiplicityCol = collision1.multNtr(); - MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); auto groupPartsOne = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); auto groupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); @@ -406,13 +405,13 @@ struct femtoUniversePairTaskTrackTrack { doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol); } } - PROCESS_SWITCH(femtoUniversePairTaskTrackTrack, processMixedEventMC, "Enable processing mixed events MC", false); + PROCESS_SWITCH(FemtoUniversePairTaskTrackTrack, processMixedEventMC, "Enable processing mixed events MC", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow{ - adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), }; return workflow; } diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrack3DMultKtExtended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrack3DMultKtExtended.cxx index 2e8827a8594..066469bd0e9 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrack3DMultKtExtended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrack3DMultKtExtended.cxx @@ -15,6 +15,7 @@ /// \author Pritam Chakraborty, WUT Warsaw, pritam.chakraborty@pw.edu.pl #include +#include #include "TRandom2.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -23,7 +24,6 @@ #include "Framework/RunningWorkflowInfo.h" #include "Framework/StepTHn.h" #include "Framework/O2DatabasePDGPlugin.h" -#include "TDatabasePDG.h" #include "ReconstructionDataFormats/PID.h" #include "Common/DataModel/PIDResponse.h" @@ -32,14 +32,15 @@ #include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverse3DContainer.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniversePairWithCentMultKt.h" using namespace o2; -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; @@ -75,15 +76,17 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { Configurable ConfUse3D{"ConfUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; } twotracksconfigs; + SliceCache cache; + using FemtoFullParticles = soa::Join; - // Filters for selecting particles (both p1 and p2) Filter trackAdditionalfilter = (nabs(aod::femtouniverseparticle::eta) < twotracksconfigs.ConfEtaMax); // example filtering on configurable using FilteredFemtoFullParticles = soa::Filtered; - // using FilteredFemtoFullParticles = FemtoFullParticles; //if no filtering is applied uncomment this option - - SliceCache cache; Preslice perCol = aod::femtouniverseparticle::fdCollisionId; + using FemtoRecoParticles = soa::Join; + using FilteredFemtoRecoParticles = soa::Filtered; + Preslice perColMC = aod::femtouniverseparticle::fdCollisionId; + /// Particle 1 struct : o2::framework::ConfigurableGroup { Configurable ConfPDGCodePartOne{"ConfPDGCodePartOne", 211, "Particle 1 - PDG code"}; @@ -97,7 +100,7 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { /// Partition for particle 1 Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == trackonefilter.ConfChargePart1 && aod::femtouniverseparticle::pt < trackonefilter.ConfPtHighPart1 && aod::femtouniverseparticle::pt > trackonefilter.ConfPtLowPart1; - Partition> partsOneMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == trackonefilter.ConfChargePart1 && aod::femtouniverseparticle::pt < trackonefilter.ConfPtHighPart1 && aod::femtouniverseparticle::pt > trackonefilter.ConfPtLowPart1; + Partition partsOneMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == trackonefilter.ConfChargePart1 && aod::femtouniverseparticle::pt < trackonefilter.ConfPtHighPart1 && aod::femtouniverseparticle::pt > trackonefilter.ConfPtLowPart1; // /// Histogramming for particle 1 @@ -117,7 +120,7 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { /// Partition for particle 2 Partition partsTwo = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == tracktwofilter.ConfChargePart2) && aod::femtouniverseparticle::pt < tracktwofilter.ConfPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.ConfPtLowPart2; - Partition> partsTwoMC = aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack) && (aod::femtouniverseparticle::sign == tracktwofilter.ConfChargePart2) && aod::femtouniverseparticle::pt < tracktwofilter.ConfPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.ConfPtLowPart2; + Partition partsTwoMC = aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack) && (aod::femtouniverseparticle::sign == tracktwofilter.ConfChargePart2) && aod::femtouniverseparticle::pt < tracktwofilter.ConfPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.ConfPtLowPart2; /// Histogramming for particle 2 FemtoUniverseParticleHisto trackHistoPartTwo; @@ -132,9 +135,14 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { /// Event part Configurable ConfV0MLow{"ConfV0MLow", 0.0, "Lower limit for V0M multiplicity"}; Configurable ConfV0MHigh{"ConfV0MHigh", 25000.0, "Upper limit for V0M multiplicity"}; + Configurable ConfTPCOccupancyLow{"ConfTPCOccupancyLow", 0, "Lower limit for TPC occupancy"}; + Configurable ConfTPCOccupancyHigh{"ConfTPCOccupancyHigh", 500, "Higher limit for TPC occupancy"}; + Configurable ConfIsCent{"ConfIsCent", true, "Condition to choose centrality of multiplicity for mixing"}; - Filter collV0Mfilter = ((o2::aod::femtouniversecollision::multV0M > ConfV0MLow) && (o2::aod::femtouniversecollision::multV0M < ConfV0MHigh)); - // Filter trackAdditionalfilter = (nabs(aod::femtouniverseparticle::eta) < twotracksconfigs.ConfEtaMax); // example filtering on configurable + Filter collfilter = (o2::aod::femtouniversecollision::multV0M > ConfV0MLow) && (o2::aod::femtouniversecollision::multV0M < ConfV0MHigh) && + (o2::aod::femtouniversecollision::occupancy >= ConfTPCOccupancyLow) && (o2::aod::femtouniversecollision::occupancy < ConfTPCOccupancyHigh); + using FilteredFDCollisions = soa::Filtered>; + using FilteredFDCollision = FilteredFDCollisions::iterator; /// Particle part ConfigurableAxis ConfTempFitVarBins{"ConfDTempFitVarBins", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; @@ -149,7 +157,8 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { ConfigurableAxis ConfmTBins3D{"ConfmTBins3D", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; ConfigurableAxis ConfmultBins3D{"ConfmultBins3D", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; - ColumnBinningPolicy colBinning{{ConfVtxBins, ConfMultBins}, true}; + ColumnBinningPolicy colBinningCent{{ConfVtxBins, ConfMultBins}, true}; + ColumnBinningPolicy colBinningNtr{{ConfVtxBins, ConfMultBins}, true}; ConfigurableAxis ConfkstarBins{"ConfkstarBins", {300, -1.5, 1.5}, "binning kstar"}; ConfigurableAxis ConfkTBins{"ConfkTBins", {150, 0., 9.}, "binning kT"}; @@ -164,6 +173,8 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { Configurable ConfCPRdeltaEtaCutMax{"ConfCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; Configurable ConfCPRdeltaEtaCutMin{"ConfCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; Configurable ConfCPRChosenRadii{"ConfCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; + Configurable ConfPhiBins{"ConfPhiBins", 29, "Number of phi bins in deta dphi"}; + Configurable ConfEtaBins{"ConfEtaBins", 29, "Number of eta bins in deta dphi"}; Configurable cfgProcessPM{"cfgProcessPM", false, "Process particles of the opposite charge"}; Configurable cfgProcessPP{"cfgProcessPP", true, "Process particles of the same, positice charge"}; Configurable cfgProcessMM{"cfgProcessMM", true, "Process particles of the same, positice charge"}; @@ -171,27 +182,30 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { Configurable cfgProcessKtBins{"cfgProcessKtBins", true, "Process kstar histograms in kT bins (if cfgProcessMultBins is set false, this will not be processed regardless this Configurable state)"}; Configurable cfgProcessKtMt3DCF{"cfgProcessKtMt3DCF", false, "Process 3D histograms in kT and Mult bins"}; - FemtoUniverse3DContainer sameEventCont; - FemtoUniverse3DContainer mixedEventCont; + FemtoUniverseContainer sameEventCont1D; + FemtoUniverseContainer mixedEventCont1D; + + FemtoUniverse3DContainer sameEventCont; + FemtoUniverse3DContainer mixedEventCont; - FemtoUniverse3DContainer sameEventContPP; - FemtoUniverse3DContainer mixedEventContPP; + FemtoUniverse3DContainer sameEventContPP; + FemtoUniverse3DContainer mixedEventContPP; - FemtoUniverse3DContainer sameEventContMM; - FemtoUniverse3DContainer mixedEventContMM; + FemtoUniverse3DContainer sameEventContMM; + FemtoUniverse3DContainer mixedEventContMM; FemtoUniversePairCleaner pairCleaner; FemtoUniverseDetaDphiStar pairCloseRejection; FemtoUniverseTrackSelection trackCuts; - PairWithCentMultKt sameEventMultCont; - PairWithCentMultKt mixedEventMultCont; + FemtoUniversePairWithCentMultKt sameEventMultCont; + FemtoUniversePairWithCentMultKt mixedEventMultCont; - PairWithCentMultKt sameEventMultContPP; - PairWithCentMultKt mixedEventMultContPP; + FemtoUniversePairWithCentMultKt sameEventMultContPP; + FemtoUniversePairWithCentMultKt mixedEventMultContPP; - PairWithCentMultKt sameEventMultContMM; - PairWithCentMultKt mixedEventMultContMM; + FemtoUniversePairWithCentMultKt sameEventMultContMM; + FemtoUniversePairWithCentMultKt mixedEventMultContMM; float mass1 = -1; float mass2 = -1; @@ -199,6 +213,7 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { /// Histogram output HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry resultRegistry{"Correlations", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry resultRegistry1D{"Correlations1D", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry resultRegistryPM{"CorrelationsPM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry resultRegistryPP{"CorrelationsPP", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry resultRegistryMM{"CorrelationsMM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; @@ -213,6 +228,8 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { HistogramRegistry SameMultRegistryMM{"SameMultRegistryMM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry MixedMultRegistryMM{"MixedMultRegistryMM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + TRandom2* randgen; + // PID for protons bool IsProtonNSigma(float mom, float nsigmaTPCPr, float nsigmaTOFPr) // previous version from: https://github.com/alisw/AliPhysics/blob/master/PWGCF/FEMTOSCOPY/AliFemtoUser/AliFemtoMJTrackCut.cxx { @@ -225,13 +242,13 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { // ConfNsigmaCombined -> TPC and TOF Sigma (combined) for momentum > 0.5 if (mom < twotracksconfigs.ConfTOFPtMin) { - if (TMath::Abs(nsigmaTPCPr) < twotracksconfigs.ConfNsigmaTPC) { + if (std::abs(nsigmaTPCPr) < twotracksconfigs.ConfNsigmaTPC) { return true; } else { return false; } } else { - if (TMath::Hypot(nsigmaTOFPr, nsigmaTPCPr) < twotracksconfigs.ConfNsigmaCombined) { + if (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < twotracksconfigs.ConfNsigmaCombined) { return true; } else { return false; @@ -242,30 +259,41 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { bool IsKaonNSigma(float mom, float nsigmaTPCK, float nsigmaTOFK) { - //|nsigma_TPC| < 3 for p < 0.5 GeV/c - //|nsigma_combined| < 3 for p > 0.5 - - // using configurables: - // ConfTOFPtMin - momentum value when we start using TOF; set to 1000 if TOF not needed - // ConfNsigmaTPCTOFKaon -> are we doing TPC TOF PID for Kaons? (boolean) - // ConfNsigmaTPC -> TPC Kaon Sigma for momentum < 0.5 - // ConfNsigmaCombined -> TPC and TOF Sigma (combined) for momentum > 0.5 - if (true) { - if (mom < twotracksconfigs.ConfTOFPtMin) { - if (TMath::Abs(nsigmaTPCK) < twotracksconfigs.ConfNsigmaTPC) { - return true; - } else { - return false; - } + if (mom < 0.3) { // 0.0-0.3 + if (std::abs(nsigmaTPCK) < 3.0) { + return true; + } else { + return false; + } + } else if (mom < 0.45) { // 0.30 - 0.45 + if (std::abs(nsigmaTPCK) < 2.0) { + return true; + } else { + return false; + } + } else if (mom < 0.55) { // 0.45-0.55 + if (std::abs(nsigmaTPCK) < 1.0) { + return true; } else { - if (TMath::Hypot(nsigmaTOFK, nsigmaTPCK) < twotracksconfigs.ConfNsigmaCombined) { + return false; + } + } else if (mom < 1.5) { // 0.55-1.5 (now we use TPC and TOF) + if ((std::abs(nsigmaTOFK) < 3.0) && (std::abs(nsigmaTPCK) < 3.0)) { + { return true; - } else { - return false; } + } else { + return false; } + } else if (mom > 1.5) { // 1.5 - + if ((std::abs(nsigmaTOFK) < 2.0) && (std::abs(nsigmaTPCK) < 3.0)) { + return true; + } else { + return false; + } + } else { + return false; } - return false; } bool IsPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) @@ -279,13 +307,13 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { // ConfNsigmaCombined -> TPC and TOF Pion Sigma (combined) for momentum > 0.5 if (true) { if (mom < twotracksconfigs.ConfTOFPtMin) { - if (TMath::Abs(nsigmaTPCPi) < twotracksconfigs.ConfNsigmaTPC) { + if (std::abs(nsigmaTPCPi) < twotracksconfigs.ConfNsigmaTPC) { return true; } else { return false; } } else { - if (TMath::Hypot(nsigmaTOFPi, nsigmaTPCPi) < twotracksconfigs.ConfNsigmaCombined) { + if (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < twotracksconfigs.ConfNsigmaCombined) { return true; } else { return false; @@ -374,6 +402,10 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { sameEventMultContPP.init(&SameMultRegistryPP, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); mixedEventMultContPP.init(&MixedMultRegistryPP, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); } + sameEventCont1D.init(&resultRegistry1D, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfEtaBins, ConfPhiBins, twotracksconfigs.ConfIsMC, twotracksconfigs.ConfUse3D); + sameEventCont1D.setPDGCodes(trackonefilter.ConfPDGCodePartOne, tracktwofilter.ConfPDGCodePartTwo); + mixedEventCont1D.init(&resultRegistry1D, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfEtaBins, ConfPhiBins, twotracksconfigs.ConfIsMC, twotracksconfigs.ConfUse3D); + mixedEventCont1D.setPDGCodes(trackonefilter.ConfPDGCodePartOne, tracktwofilter.ConfPDGCodePartTwo); } if (cfgProcessMM) { @@ -399,9 +431,13 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { } template - void fillCollision(CollisionType col) + void fillCollision(CollisionType col, bool IsCent) { - MixQaRegistry.fill(HIST("MixingQA/hSECollisionBins"), colBinning.getBin({col.posZ(), col.multNtr()})); + if (IsCent) { + MixQaRegistry.fill(HIST("MixingQA/hSECollisionBins"), colBinningCent.getBin({col.posZ(), col.multV0M()})); + } else { + MixQaRegistry.fill(HIST("MixingQA/hSECollisionBins"), colBinningNtr.getBin({col.posZ(), col.multNtr()})); + } eventHisto.fillQA(col); } @@ -415,22 +451,23 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { /// @param parts femtoUniverseParticles table (in case of Monte Carlo joined with FemtoUniverseMCLabels) /// @param magFieldTesla magnetic field of the collision /// @param multCol multiplicity of the collision - template - void doSameEvent(PartitionType groupPartsOne, PartitionType groupPartsTwo, PartType parts, float magFieldTesla, int multCol, int ContType, bool fillQA) + template + void doSameEvent(PartitionType groupPartsOne, PartitionType groupPartsTwo, PartType parts, float magFieldTesla, int multCol, int ContType, bool fillQA, [[maybe_unused]] MCParticles mcParts = nullptr) { /// Histogramming same event if ((ContType == 1 || ContType == 2) && fillQA) { - for (auto& part : groupPartsOne) { + for (const auto& part : groupPartsOne) { if (!IsParticleNSigma((int8_t)1, part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { continue; } trackHistoPartOne.fillQA(part); + trackHistoPartOne.fillQAMisIden(part, trackonefilter.ConfPDGCodePartOne); } } if ((ContType == 1 || ContType == 3) && fillQA) { - for (auto& part : groupPartsTwo) { + for (const auto& part : groupPartsTwo) { if (!IsParticleNSigma((int8_t)2, part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { continue; } @@ -441,7 +478,7 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { if (ContType == 1) { /// Now build the combinations for non-identical particle pairs - for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { if (!IsParticleNSigma((int8_t)1, p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { continue; @@ -452,7 +489,7 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { } if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::same)) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } } @@ -465,17 +502,16 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); if (!cfgProcessMultBins) { - sameEventCont.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, ConfIsIden, ConfIsLCMS); + sameEventCont.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, ConfIsIden); } else { - std::vector k3d = FemtoUniverseMath::getpairmom3d(p1, mass1, p2, mass2, ConfIsIden, ConfIsLCMS); - sameEventMultCont.fill_3D(k3d[1], k3d[2], k3d[3], multCol, kT); + std::vector k3d = FemtoUniverseMath::newpairfunc(p1, mass1, p2, mass2, ConfIsIden); + sameEventMultCont.fill3D(k3d[1], k3d[2], k3d[3], multCol, kT); } } } else { /// Now build the combinations for identical particles pairs - TRandom2* randgen = new TRandom2(1); double rand; - for (auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsOne, groupPartsOne))) { + for (const auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsOne, groupPartsOne))) { if (!IsParticleNSigma((int8_t)2, p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { continue; @@ -486,7 +522,7 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { } if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::same)) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } } @@ -504,17 +540,29 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { if (rand > 0.5) { if (!cfgProcessMultBins) { - sameEventContPP.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, ConfIsIden, ConfIsLCMS); + sameEventContPP.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, ConfIsIden); + } else { + k3d = FemtoUniverseMath::newpairfunc(p1, mass1, p2, mass2, ConfIsIden); + sameEventMultContPP.fill3D(k3d[1], k3d[2], k3d[3], multCol, kT); + } + float weight = 1.0f; + if constexpr (std::is_same::value) { + sameEventCont1D.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, weight, ConfIsIden); } else { - k3d = FemtoUniverseMath::getpairmom3d(p1, mass1, p2, mass2, ConfIsIden, ConfIsLCMS); - sameEventMultContPP.fill_3D(k3d[1], k3d[2], k3d[3], multCol, kT); + sameEventCont1D.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, weight, ConfIsIden); } } else { if (!cfgProcessMultBins) { - sameEventContPP.setPair(p2, p1, multCol, twotracksconfigs.ConfUse3D, ConfIsIden, ConfIsLCMS); + sameEventContPP.setPair(p2, p1, multCol, twotracksconfigs.ConfUse3D, ConfIsIden); } else { - k3d = FemtoUniverseMath::getpairmom3d(p2, mass2, p1, mass1, ConfIsIden, ConfIsLCMS); - sameEventMultContPP.fill_3D(k3d[1], k3d[2], k3d[3], multCol, kT); + k3d = FemtoUniverseMath::newpairfunc(p2, mass2, p1, mass1, ConfIsIden); + sameEventMultContPP.fill3D(k3d[1], k3d[2], k3d[3], multCol, kT); + } + float weight = 1.0f; + if constexpr (std::is_same::value) { + sameEventCont1D.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, weight, ConfIsIden); + } else { + sameEventCont1D.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, weight, ConfIsIden); } } break; @@ -527,17 +575,29 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { if (rand > 0.5) { if (!cfgProcessMultBins) { - sameEventContMM.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, ConfIsIden, ConfIsLCMS); + sameEventContMM.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, ConfIsIden); + } else { + k3d = FemtoUniverseMath::newpairfunc(p1, mass1, p2, mass2, ConfIsIden); + sameEventMultContMM.fill3D(k3d[1], k3d[2], k3d[3], multCol, kT); + } + float weight = 1.0f; + if constexpr (std::is_same::value) { + sameEventCont1D.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, weight, ConfIsIden); } else { - k3d = FemtoUniverseMath::getpairmom3d(p1, mass1, p2, mass2, ConfIsIden, ConfIsLCMS); - sameEventMultContMM.fill_3D(k3d[1], k3d[2], k3d[3], multCol, kT); + sameEventCont1D.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, weight, ConfIsIden); } } else { if (!cfgProcessMultBins) { - sameEventContMM.setPair(p2, p1, multCol, twotracksconfigs.ConfUse3D, ConfIsIden, ConfIsLCMS); + sameEventContMM.setPair(p2, p1, multCol, twotracksconfigs.ConfUse3D, ConfIsIden); + } else { + k3d = FemtoUniverseMath::newpairfunc(p2, mass2, p1, mass1, ConfIsIden); + sameEventMultContMM.fill3D(k3d[1], k3d[2], k3d[3], multCol, kT); + } + float weight = 1.0f; + if constexpr (std::is_same::value) { + sameEventCont1D.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, weight, ConfIsIden); } else { - k3d = FemtoUniverseMath::getpairmom3d(p2, mass2, p1, mass1, ConfIsIden, ConfIsLCMS); - sameEventMultContMM.fill_3D(k3d[1], k3d[2], k3d[3], multCol, kT); + sameEventCont1D.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, weight, ConfIsIden); } } break; @@ -552,27 +612,39 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { /// process function for to call doSameEvent with Data /// \param col subscribe to the collision table (Data) /// \param parts subscribe to the femtoUniverseParticleTable - void processSameEvent(soa::Filtered::iterator& col, - FilteredFemtoFullParticles& parts) + void processSameEvent(FilteredFDCollision const& col, + FilteredFemtoFullParticles const& parts) { - fillCollision(col); + fillCollision(col, ConfIsCent); auto thegroupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); auto thegroupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); bool fillQA = true; + randgen = new TRandom2(0); - if (cfgProcessPM) { - doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multNtr(), 1, fillQA); - } - - if (cfgProcessPP) { - doSameEvent(thegroupPartsOne, thegroupPartsOne, parts, col.magField(), col.multNtr(), 2, fillQA); - } - - if (cfgProcessMM) { - doSameEvent(thegroupPartsTwo, thegroupPartsTwo, parts, col.magField(), col.multNtr(), 3, fillQA); + if (ConfIsCent) { + if (cfgProcessPM) { + doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multV0M(), 1, fillQA); + } + if (cfgProcessPP) { + doSameEvent(thegroupPartsOne, thegroupPartsOne, parts, col.magField(), col.multV0M(), 2, fillQA); + } + if (cfgProcessMM) { + doSameEvent(thegroupPartsTwo, thegroupPartsTwo, parts, col.magField(), col.multV0M(), 3, fillQA); + } + } else { + if (cfgProcessPM) { + doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multNtr(), 1, fillQA); + } + if (cfgProcessPP) { + doSameEvent(thegroupPartsOne, thegroupPartsOne, parts, col.magField(), col.multNtr(), 2, fillQA); + } + if (cfgProcessMM) { + doSameEvent(thegroupPartsTwo, thegroupPartsTwo, parts, col.magField(), col.multNtr(), 3, fillQA); + } } + delete randgen; } PROCESS_SWITCH(femtoUniversePairTaskTrackTrack3DMultKtExtended, processSameEvent, "Enable processing same event", true); @@ -580,28 +652,39 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { /// \param col subscribe to the collision table (Monte Carlo Reconstructed reconstructed) /// \param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth /// \param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table - void processSameEventMC(o2::aod::FDCollision& col, - soa::Join& parts, - o2::aod::FDMCParticles&) + void processSameEventMC(FilteredFDCollision const& col, + FilteredFemtoRecoParticles const& parts, + aod::FdMCParticles const& mcparts) { - fillCollision(col); - + fillCollision(col, ConfIsCent); auto thegroupPartsOne = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); auto thegroupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); bool fillQA = true; + randgen = new TRandom2(0); - if (cfgProcessPM) { - doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multNtr(), 1, fillQA); - } - - if (cfgProcessPP) { - doSameEvent(thegroupPartsOne, thegroupPartsOne, parts, col.magField(), col.multNtr(), 2, fillQA); - } - - if (cfgProcessMM) { - doSameEvent(thegroupPartsTwo, thegroupPartsTwo, parts, col.magField(), col.multNtr(), 3, fillQA); + if (ConfIsCent) { + if (cfgProcessPM) { + doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multV0M(), 1, fillQA); + } + if (cfgProcessPP) { + doSameEvent(thegroupPartsOne, thegroupPartsOne, parts, col.magField(), col.multV0M(), 2, fillQA, mcparts); + } + if (cfgProcessMM) { + doSameEvent(thegroupPartsTwo, thegroupPartsTwo, parts, col.magField(), col.multV0M(), 3, fillQA); + } + } else { + if (cfgProcessPM) { + doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multNtr(), 1, fillQA); + } + if (cfgProcessPP) { + doSameEvent(thegroupPartsOne, thegroupPartsOne, parts, col.magField(), col.multNtr(), 2, fillQA, mcparts); + } + if (cfgProcessMM) { + doSameEvent(thegroupPartsTwo, thegroupPartsTwo, parts, col.magField(), col.multNtr(), 3, fillQA); + } } + delete randgen; } PROCESS_SWITCH(femtoUniversePairTaskTrackTrack3DMultKtExtended, processSameEventMC, "Enable processing same event for Monte Carlo", false); @@ -619,7 +702,7 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { void doMixedEvent(PartitionType groupPartsOne, PartitionType groupPartsTwo, PartType parts, float magFieldTesla, int multCol, int ContType) { - for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { if (!IsParticleNSigma((int8_t)2, p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { continue; @@ -630,43 +713,77 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { } if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::mixed)) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::mixed)) { continue; } } + double rand; + rand = randgen->Rndm(); + switch (ContType) { case 1: { float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); - if (!cfgProcessMultBins) { - mixedEventCont.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, ConfIsIden, ConfIsLCMS); + + if (rand > 0.5) { + if (!cfgProcessMultBins) { + mixedEventCont.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, ConfIsIden); + } else { + std::vector k3d = FemtoUniverseMath::newpairfunc(p1, mass1, p2, mass2, ConfIsIden); + mixedEventMultCont.fill3D(k3d[1], k3d[2], k3d[3], multCol, kT); + } } else { - std::vector k3d = FemtoUniverseMath::getpairmom3d(p1, mass1, p2, mass2, ConfIsIden, ConfIsLCMS); - mixedEventMultCont.fill_3D(k3d[1], k3d[2], k3d[3], multCol, kT); + if (!cfgProcessMultBins) { + mixedEventCont.setPair(p2, p1, multCol, twotracksconfigs.ConfUse3D, ConfIsIden); + } else { + std::vector k3d = FemtoUniverseMath::newpairfunc(p2, mass2, p1, mass1, ConfIsIden); + mixedEventMultCont.fill3D(k3d[1], k3d[2], k3d[3], multCol, kT); + } } break; } case 2: { float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass1); - if (!cfgProcessMultBins) { - mixedEventContPP.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, ConfIsIden, ConfIsLCMS); + + if (rand > 0.5) { + if (!cfgProcessMultBins) { + mixedEventContPP.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, ConfIsIden); + } else { + std::vector k3d = FemtoUniverseMath::newpairfunc(p1, mass1, p2, mass2, ConfIsIden); + mixedEventMultContPP.fill3D(k3d[1], k3d[2], k3d[3], multCol, kT); + } } else { - std::vector k3d = FemtoUniverseMath::getpairmom3d(p1, mass1, p2, mass2, ConfIsIden, ConfIsLCMS); - mixedEventMultContPP.fill_3D(k3d[1], k3d[2], k3d[3], multCol, kT); + if (!cfgProcessMultBins) { + mixedEventContPP.setPair(p2, p1, multCol, twotracksconfigs.ConfUse3D, ConfIsIden); + } else { + std::vector k3d = FemtoUniverseMath::newpairfunc(p2, mass2, p1, mass1, ConfIsIden); + mixedEventMultContPP.fill3D(k3d[1], k3d[2], k3d[3], multCol, kT); + } } break; } case 3: { float kT = FemtoUniverseMath::getkT(p1, mass2, p2, mass2); - if (!cfgProcessMultBins) { - mixedEventContMM.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, ConfIsIden, ConfIsLCMS); + + if (rand > 0.5) { + if (!cfgProcessMultBins) { + mixedEventContMM.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, ConfIsIden); + } else { + std::vector k3d = FemtoUniverseMath::newpairfunc(p1, mass1, p2, mass2, ConfIsIden); + mixedEventMultContMM.fill3D(k3d[1], k3d[2], k3d[3], multCol, kT); + } } else { - std::vector k3d = FemtoUniverseMath::getpairmom3d(p1, mass1, p2, mass2, ConfIsIden, ConfIsLCMS); - mixedEventMultContMM.fill_3D(k3d[1], k3d[2], k3d[3], multCol, kT); + if (!cfgProcessMultBins) { + mixedEventContMM.setPair(p2, p1, multCol, twotracksconfigs.ConfUse3D, ConfIsIden); + } else { + std::vector k3d = FemtoUniverseMath::newpairfunc(p2, mass2, p1, mass1, ConfIsIden); + mixedEventMultContMM.fill3D(k3d[1], k3d[2], k3d[3], multCol, kT); + } } break; } + default: break; } @@ -676,13 +793,99 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { /// process function for to call doMixedEvent with Data /// @param cols subscribe to the collisions table (Data) /// @param parts subscribe to the femtoUniverseParticleTable - void processMixedEvent(soa::Filtered& cols, - FilteredFemtoFullParticles& parts) + void processMixedEventCent(FilteredFDCollisions const& cols, + FilteredFemtoFullParticles const& parts) { - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + randgen = new TRandom2(0); + + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningCent, ConfNEventsMix, -1, cols, cols)) { + + const int multiplicityCol = collision1.multV0M(); + MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningCent.getBin({collision1.posZ(), multiplicityCol})); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + continue; + } + + if (cfgProcessPM) { + auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 1); + } + if (cfgProcessPP) { + auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 2); + } + if (cfgProcessMM) { + auto groupPartsOne = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 3); + } + } + delete randgen; + } + PROCESS_SWITCH(femtoUniversePairTaskTrackTrack3DMultKtExtended, processMixedEventCent, "Enable processing mixed events", true); + + /// brief process function for to call doMixedEvent with Monte Carlo + /// @param cols subscribe to the collisions table (Monte Carlo Reconstructed reconstructed) + /// @param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth + /// @param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table + void processMixedEventMCCent(FilteredFDCollisions const& cols, + FemtoRecoParticles const& parts, + aod::FdMCParticles const&) + { + randgen = new TRandom2(0); + + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningCent, ConfNEventsMix, -1, cols, cols)) { + + const int multiplicityCol = collision1.multV0M(); + MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningCent.getBin({collision1.posZ(), multiplicityCol})); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + continue; + } + /// \todo before mixing we should check whether both collisions contain a pair of particles! + // if (partsOne.size() == 0 || nPart2Evt1 == 0 || nPart1Evt2 == 0 || partsTwo.size() == 0 ) continue; + + if (cfgProcessPM) { + auto groupPartsOne = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 1); + } + if (cfgProcessPP) { + auto groupPartsOne = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 2); + } + if (cfgProcessMM) { + auto groupPartsOne = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 3); + } + } + delete randgen; + } + PROCESS_SWITCH(femtoUniversePairTaskTrackTrack3DMultKtExtended, processMixedEventMCCent, "Enable processing mixed events MC", false); + + /// process function for to call doMixedEvent with Data + /// @param cols subscribe to the collisions table (Data) + /// @param parts subscribe to the femtoUniverseParticleTable + void processMixedEventNtr(FilteredFDCollisions& cols, + FilteredFemtoFullParticles& parts) + { + randgen = new TRandom2(0); + + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningNtr, ConfNEventsMix, -1, cols, cols)) { const int multiplicityCol = collision1.multNtr(); - MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningNtr.getBin({collision1.posZ(), multiplicityCol})); const auto& magFieldTesla1 = collision1.magField(); const auto& magFieldTesla2 = collision2.magField(); @@ -707,21 +910,24 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 3); } } + delete randgen; } - PROCESS_SWITCH(femtoUniversePairTaskTrackTrack3DMultKtExtended, processMixedEvent, "Enable processing mixed events", true); + PROCESS_SWITCH(femtoUniversePairTaskTrackTrack3DMultKtExtended, processMixedEventNtr, "Enable processing mixed events", false); /// brief process function for to call doMixedEvent with Monte Carlo /// @param cols subscribe to the collisions table (Monte Carlo Reconstructed reconstructed) /// @param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth /// @param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table - void processMixedEventMC(o2::aod::FDCollisions& cols, - soa::Join& parts, - o2::aod::FDMCParticles&) + void processMixedEventMCNtr(FilteredFDCollisions const& cols, + FemtoRecoParticles const& parts, + aod::FdMCParticles const&) { - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + randgen = new TRandom2(0); + + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningCent, ConfNEventsMix, -1, cols, cols)) { const int multiplicityCol = collision1.multNtr(); - MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningNtr.getBin({collision1.posZ(), multiplicityCol})); const auto& magFieldTesla1 = collision1.magField(); const auto& magFieldTesla2 = collision2.magField(); @@ -735,21 +941,22 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { if (cfgProcessPM) { auto groupPartsOne = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); auto groupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); - doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 1); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 1); } if (cfgProcessPP) { auto groupPartsOne = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); auto groupPartsTwo = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); - doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 2); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 2); } if (cfgProcessMM) { auto groupPartsOne = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); auto groupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); - doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 3); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 3); } } + delete randgen; } - PROCESS_SWITCH(femtoUniversePairTaskTrackTrack3DMultKtExtended, processMixedEventMC, "Enable processing mixed events MC", false); + PROCESS_SWITCH(femtoUniversePairTaskTrackTrack3DMultKtExtended, processMixedEventMCNtr, "Enable processing mixed events MC", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackExtended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackExtended.cxx index 985c7466ce3..27e865ce552 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackExtended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackExtended.cxx @@ -16,17 +16,15 @@ /// \author Anton Riedel, TU München, anton.riedel@tum.de /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch +#include +#include #include + #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" #include "Framework/ASoAHelpers.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/StepTHn.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "TDatabasePDG.h" #include "ReconstructionDataFormats/PID.h" -#include "Common/DataModel/PIDResponse.h" #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" @@ -34,48 +32,50 @@ #include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEfficiencyCorrection.h" using namespace o2; -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; +using namespace o2::analysis::femto_universe::efficiency_correction; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; namespace { -static constexpr int nPart = 2; -static constexpr int nCuts = 5; +static constexpr int NPart = 2; +static constexpr int NCuts = 5; static const std::vector partNames{"PartOne", "PartTwo"}; static const std::vector cutNames{"MaxPt", "PIDthr", "nSigmaTPC", "nSigmaTPCTOF", "MaxP"}; -static const float cutsTable[nPart][nCuts]{ +static const float cutsTable[NPart][NCuts]{ {4.05f, 1.f, 3.f, 3.f, 100.f}, {4.05f, 1.f, 3.f, 3.f, 100.f}}; } // namespace -struct femtoUniversePairTaskTrackTrackExtended { +struct FemtoUniversePairTaskTrackTrackExtended { + Service pdgMC; /// Particle selection part /// Table for both particles struct : o2::framework::ConfigurableGroup { - Configurable ConfNsigmaCombined{"ConfNsigmaCombined", 3.0f, "TPC and TOF Pion Sigma (combined) for momentum > ConfTOFPtMin"}; - Configurable ConfNsigmaTPC{"ConfNsigmaTPC", 3.0f, "TPC Pion Sigma for momentum < ConfTOFPtMin"}; - Configurable ConfTOFPtMin{"ConfTOFPtMin", 0.5f, "Min. Pt for which TOF is required for PID."}; - Configurable ConfEtaMax{"ConfEtaMax", 0.8f, "Higher limit for |Eta| (the same for both particles)"}; - - Configurable> ConfCutTable{"ConfCutTable", {cutsTable[0], nPart, nCuts, partNames, cutNames}, "Particle selections"}; - Configurable ConfNspecies{"ConfNspecies", 2, "Number of particle spieces with PID info"}; - Configurable ConfIsMC{"ConfIsMC", false, "Enable additional Histogramms in the case of a MonteCarlo Run"}; - Configurable> ConfTrkPIDnSigmaMax{"ConfTrkPIDnSigmaMax", std::vector{4.f, 3.f, 2.f}, "This configurable needs to be the same as the one used in the producer task"}; - Configurable ConfUse3D{"ConfUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; + Configurable confNsigmaCombined{"confNsigmaCombined", 3.0f, "TPC and TOF Pion Sigma (combined) for momentum > confTOFPtMin"}; + Configurable confNsigmaTPC{"confNsigmaTPC", 3.0f, "TPC Pion Sigma for momentum < confTOFPtMin"}; + Configurable confTOFPtMin{"confTOFPtMin", 0.5f, "Min. Pt for which TOF is required for PID."}; + Configurable confEtaMax{"confEtaMax", 0.8f, "Higher limit for |Eta| (the same for both particles)"}; + + Configurable> confCutTable{"confCutTable", {cutsTable[0], NPart, NCuts, partNames, cutNames}, "Particle selections"}; + Configurable confNspecies{"confNspecies", 2, "Number of particle spieces with PID info"}; + Configurable confIsMC{"confIsMC", false, "Enable additional Histogramms in the case of a MonteCarlo Run"}; + Configurable> confTrkPIDnSigmaMax{"confTrkPIDnSigmaMax", std::vector{4.f, 3.f, 2.f}, "This configurable needs to be the same as the one used in the producer task"}; + Configurable confUse3D{"confUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; } twotracksconfigs; using FemtoFullParticles = soa::Join; // Filters for selecting particles (both p1 and p2) Filter trackCutFilter = requireGlobalTrackInFilter(); // Global track cuts - Filter trackAdditionalfilter = (nabs(aod::femtouniverseparticle::eta) < twotracksconfigs.ConfEtaMax); // example filtering on configurable + Filter trackAdditionalfilter = (nabs(aod::femtouniverseparticle::eta) < twotracksconfigs.confEtaMax); // example filtering on configurable using FilteredFemtoFullParticles = soa::Filtered; // using FilteredFemtoFullParticles = FemtoFullParticles; //if no filtering is applied uncomment this option @@ -84,41 +84,52 @@ struct femtoUniversePairTaskTrackTrackExtended { /// Particle 1 struct : o2::framework::ConfigurableGroup { - Configurable ConfPDGCodePartOne{"ConfPDGCodePartOne", 2212, "Particle 1 - PDG code"}; - Configurable ConfIsTrackOneIdentified{"ConfIsTrackOneIdentified", true, "Enable PID for the track one"}; - // Configurable ConfCutPartOne{"ConfCutPartOne", 5542474, "Particle 1 - Selection bit from cutCulator"}; - Configurable ConfPIDPartOne{"ConfPIDPartOne", 2, "Particle 1 - Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector>int>> - Configurable ConfPtLowPart1{"ConfPtLowPart1", 0.5, "Lower limit for Pt for the first particle"}; - Configurable ConfPtHighPart1{"ConfPtHighPart1", 1.5, "Higher limit for Pt for the first particle"}; - Configurable ConfChargePart1{"ConfChargePart1", 1, "Particle 1 sign"}; + Configurable confPDGCodePartOne{"confPDGCodePartOne", 2212, "Particle 1 - PDG code"}; + Configurable confIsTrackOneIdentified{"confIsTrackOneIdentified", true, "Enable PID for the track one"}; + // Configurable confCutPartOne{"confCutPartOne", 5542474, "Particle 1 - Selection bit from cutCulator"}; + Configurable confPIDPartOne{"confPIDPartOne", 2, "Particle 1 - Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector>int>> + Configurable confPtLowPart1{"confPtLowPart1", 0.5, "Lower limit for Pt for the first particle"}; + Configurable confPtHighPart1{"confPtHighPart1", 1.5, "Higher limit for Pt for the first particle"}; + Configurable confChargePart1{"confChargePart1", 1, "Particle 1 sign"}; } trackonefilter; /// Partition for particle 1 - Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == trackonefilter.ConfChargePart1 && aod::femtouniverseparticle::pt < trackonefilter.ConfPtHighPart1 && aod::femtouniverseparticle::pt > trackonefilter.ConfPtLowPart1; - Partition> partsOneMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == trackonefilter.ConfChargePart1 && aod::femtouniverseparticle::pt < trackonefilter.ConfPtHighPart1 && aod::femtouniverseparticle::pt > trackonefilter.ConfPtLowPart1; - // && ((aod::femtouniverseparticle::cut & ConfCutPartOne) == ConfCutPartOne); + Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == trackonefilter.confChargePart1 && aod::femtouniverseparticle::pt < trackonefilter.confPtHighPart1 && aod::femtouniverseparticle::pt > trackonefilter.confPtLowPart1; + Partition> partsOneMCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == trackonefilter.confChargePart1 && aod::femtouniverseparticle::pt < trackonefilter.confPtHighPart1 && aod::femtouniverseparticle::pt > trackonefilter.confPtLowPart1; + // && ((aod::femtouniverseparticle::cut & confCutPartOne) == confCutPartOne); + + Partition> partsOneMCTruth = + aod::femtouniverseparticle::partType == static_cast(aod::femtouniverseparticle::ParticleType::kMCTruthTrack) && + aod::femtouniverseparticle::pt < trackonefilter.confPtHighPart1 && + aod::femtouniverseparticle::pt > trackonefilter.confPtLowPart1; /// Histogramming for particle 1 FemtoUniverseParticleHisto trackHistoPartOne; + FemtoUniverseParticleHisto hMCTruth1; /// Particle 2 - Configurable ConfIsSame{"ConfIsSame", false, "Pairs of the same particle"}; + Configurable confIsSame{"confIsSame", false, "Pairs of the same particle"}; struct : o2::framework::ConfigurableGroup { - Configurable ConfPDGCodePartTwo{"ConfPDGCodePartTwo", 2212, "Particle 2 - PDG code"}; - Configurable ConfIsTrackTwoIdentified{"ConfIsTrackTwoIdentified", true, "Enable PID for the track two"}; - // Configurable ConfCutPartTwo{"ConfCutPartTwo", 5542474, "Particle 2 - Selection bit"}; - Configurable ConfPIDPartTwo{"ConfPIDPartTwo", 2, "Particle 2 - Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector> - Configurable ConfPtLowPart2{"ConfPtLowPart2", 0.5, "Lower limit for Pt for the second particle"}; - Configurable ConfPtHighPart2{"ConfPtHighPart2", 1.5, "Higher limit for Pt for the second particle"}; - Configurable ConfChargePart2{"ConfChargePart2", -1, "Particle 2 sign"}; + Configurable confPDGCodePartTwo{"confPDGCodePartTwo", 2212, "Particle 2 - PDG code"}; + Configurable confIsTrackTwoIdentified{"confIsTrackTwoIdentified", true, "Enable PID for the track two"}; + Configurable confPIDPartTwo{"confPIDPartTwo", 2, "Particle 2 - Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector> + Configurable confPtLowPart2{"confPtLowPart2", 0.5, "Lower limit for Pt for the second particle"}; + Configurable confPtHighPart2{"confPtHighPart2", 1.5, "Higher limit for Pt for the second particle"}; + Configurable confChargePart2{"confChargePart2", -1, "Particle 2 sign"}; } tracktwofilter; /// Partition for particle 2 - Partition partsTwo = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == tracktwofilter.ConfChargePart2) && aod::femtouniverseparticle::pt < tracktwofilter.ConfPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.ConfPtLowPart2; + Partition partsTwo = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == tracktwofilter.confChargePart2) && aod::femtouniverseparticle::pt < tracktwofilter.confPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.confPtLowPart2; + + Partition> partsTwoMCReco = aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack) && (aod::femtouniverseparticle::sign == tracktwofilter.confChargePart2) && aod::femtouniverseparticle::pt < tracktwofilter.confPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.confPtLowPart2; - Partition> partsTwoMC = aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack) && (aod::femtouniverseparticle::sign == tracktwofilter.ConfChargePart2) && aod::femtouniverseparticle::pt < tracktwofilter.ConfPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.ConfPtLowPart2; + Partition> partsTwoMCTruth = + aod::femtouniverseparticle::partType == static_cast(aod::femtouniverseparticle::ParticleType::kMCTruthTrack) && + aod::femtouniverseparticle::pt < tracktwofilter.confPtHighPart2 && + aod::femtouniverseparticle::pt > tracktwofilter.confPtLowPart2; /// Histogramming for particle 2 FemtoUniverseParticleHisto trackHistoPartTwo; + FemtoUniverseParticleHisto hMCTruth2; /// Histogramming for Event FemtoUniverseEventHisto eventHisto; @@ -128,64 +139,69 @@ struct femtoUniversePairTaskTrackTrackExtended { std::vector kNsigma; /// particle part - ConfigurableAxis ConfTempFitVarBins{"ConfDTempFitVarBins", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfTempFitVarpTBins{"ConfTempFitVarpTBins", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; + ConfigurableAxis confTempFitVarBins{"confTempFitVarBins", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis confTempFitVarpTBins{"confTempFitVarpTBins", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; + ConfigurableAxis confTempFitVarPDGBins{"confTempFitVarPDGBins", {6000, -2300, 2300}, "Binning of the PDG code in the pT vs. TempFitVar plot"}; /// Correlation part - ConfigurableAxis ConfMultBins{"ConfMultBins", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; // \todo to be obtained from the hash task - // ConfigurableAxis ConfMultBins{"CfgMultBins", {VARIABLE_WIDTH, 0.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; - ConfigurableAxis ConfVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - - ConfigurableAxis ConfmTBins3D{"ConfmTBins3D", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; - ConfigurableAxis ConfmultBins3D{"ConfmultBins3D", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; - - ColumnBinningPolicy colBinning{{ConfVtxBins, ConfMultBins}, true}; - - ConfigurableAxis ConfkstarBins{"ConfkstarBins", {1500, 0., 6.}, "binning kstar"}; - ConfigurableAxis ConfkTBins{"ConfkTBins", {150, 0., 9.}, "binning kT"}; - ConfigurableAxis ConfmTBins{"ConfmTBins", {225, 0., 7.5}, "binning mT"}; - Configurable ConfNEventsMix{"ConfNEventsMix", 5, "Number of events for mixing"}; - Configurable ConfIsCPR{"ConfIsCPR", true, "Close Pair Rejection"}; - Configurable ConfCPRPlotPerRadii{"ConfCPRPlotPerRadii", false, "Plot CPR per radii"}; - Configurable ConfCPRdeltaPhiCutMax{"ConfCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaPhiCutMin{"ConfCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaEtaCutMax{"ConfCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaEtaCutMin{"ConfCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; - Configurable ConfCPRChosenRadii{"ConfCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; - Configurable ConfPhiBins{"ConfPhiBins", 29, "Number of phi bins in deta dphi"}; - Configurable ConfEtaBins{"ConfEtaBins", 29, "Number of eta bins in deta dphi"}; - - FemtoUniverseContainer sameEventCont; - FemtoUniverseContainer mixedEventCont; + ConfigurableAxis confMultBins{"confMultBins", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; // \todo to be obtained from the hash task + // ConfigurableAxis confMultBins{"confMultBins", {VARIABLE_WIDTH, 0.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; + ConfigurableAxis confVtxBins{"confVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + + ConfigurableAxis confmTBins3D{"confmTBins3D", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + ConfigurableAxis confMultBins3D{"confMultBins3D", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + + ColumnBinningPolicy colBinning{{confVtxBins, confMultBins}, true}; + + ConfigurableAxis confkstarBins{"confkstarBins", {1500, 0., 6.}, "binning kstar"}; + ConfigurableAxis confkTBins{"confkTBins", {150, 0., 9.}, "binning kT"}; + ConfigurableAxis confmTBins{"confmTBins", {225, 0., 7.5}, "binning mT"}; + Configurable confNEventsMix{"confNEventsMix", 5, "Number of events for mixing"}; + Configurable confIsCPR{"confIsCPR", true, "Close Pair Rejection"}; + Configurable confCPRPlotPerRadii{"confCPRPlotPerRadii", false, "Plot CPR per radii"}; + Configurable confCPRdeltaPhiCutMax{"confCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; + Configurable confCPRdeltaPhiCutMin{"confCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMax{"confCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMin{"confCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; + Configurable confCPRChosenRadii{"confCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; + Configurable confPhiBins{"confPhiBins", 29, "Number of phi bins in deta dphi"}; + Configurable confEtaBins{"confEtaBins", 29, "Number of eta bins in deta dphi"}; + + FemtoUniverseContainer sameEventCont; + FemtoUniverseContainer mixedEventCont; FemtoUniversePairCleaner pairCleaner; FemtoUniverseDetaDphiStar pairCloseRejection; FemtoUniverseTrackSelection trackCuts; /// Histogram output HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry resultRegistry{"Correlations", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry MixQaRegistry{"MixQaRegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry mixQaRegistry{"mixQaRegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + EffCorConfigurableGroup effCorConfGroup; + EfficiencyCorrection effCorrection{&effCorConfGroup}; /// @brief Counter for particle swapping int fNeventsProcessed = 0; + // PID for protons - bool IsProtonNSigma(float mom, float nsigmaTPCPr, float nsigmaTOFPr) // previous version from: https://github.com/alisw/AliPhysics/blob/master/PWGCF/FEMTOSCOPY/AliFemtoUser/AliFemtoMJTrackCut.cxx + bool isProtonNSigma(float mom, float nsigmaTPCPr, float nsigmaTOFPr) // previous version from: https://github.com/alisw/AliPhysics/blob/master/PWGCF/FEMTOSCOPY/AliFemtoUser/AliFemtoMJTrackCut.cxx { //|nsigma_TPC| < 3 for p < 0.5 GeV/c //|nsigma_combined| < 3 for p > 0.5 // using configurables: - // ConfTOFPtMin - momentum value when we start using TOF; set to 1000 if TOF not needed - // ConfNsigmaTPC -> TPC Sigma for momentum < ConfTOFPtMin - // ConfNsigmaCombined -> TPC and TOF Sigma (combined) for momentum > ConfTOFPtMin + // confTOFPtMin - momentum value when we start using TOF; set to 1000 if TOF not needed + // confNsigmaTPC -> TPC Sigma for momentum < confTOFPtMin + // confNsigmaCombined -> TPC and TOF Sigma (combined) for momentum > confTOFPtMin - if (mom < twotracksconfigs.ConfTOFPtMin) { - if (TMath::Abs(nsigmaTPCPr) < twotracksconfigs.ConfNsigmaTPC) { + if (mom < twotracksconfigs.confTOFPtMin) { + if (std::abs(nsigmaTPCPr) < twotracksconfigs.confNsigmaTPC) { return true; } else { return false; } } else { - if (TMath::Hypot(nsigmaTOFPr, nsigmaTPCPr) < twotracksconfigs.ConfNsigmaCombined) { + if (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < twotracksconfigs.confNsigmaCombined) { return true; } else { return false; @@ -194,24 +210,24 @@ struct femtoUniversePairTaskTrackTrackExtended { return false; } - bool IsKaonNSigma(float mom, float nsigmaTPCK, float nsigmaTOFK) + bool isKaonNSigma(float mom, float nsigmaTPCK, float nsigmaTOFK) { //|nsigma_TPC| < 3 for p < 0.5 GeV/c //|nsigma_combined| < 3 for p > 0.5 // using configurables: - // ConfTOFPtMin - momentum value when we start using TOF; set to 1000 if TOF not needed - // ConfNsigmaTPC -> TPC Sigma for momentum < ConfTOFPtMin - // ConfNsigmaCombined -> TPC and TOF Sigma (combined) for momentum > ConfTOFPtMin + // confTOFPtMin - momentum value when we start using TOF; set to 1000 if TOF not needed + // confNsigmaTPC -> TPC Sigma for momentum < confTOFPtMin + // confNsigmaCombined -> TPC and TOF Sigma (combined) for momentum > confTOFPtMin if (true) { - if (mom < twotracksconfigs.ConfTOFPtMin) { - if (TMath::Abs(nsigmaTPCK) < twotracksconfigs.ConfNsigmaTPC) { + if (mom < twotracksconfigs.confTOFPtMin) { + if (std::abs(nsigmaTPCK) < twotracksconfigs.confNsigmaTPC) { return true; } else { return false; } } else { - if (TMath::Hypot(nsigmaTOFK, nsigmaTPCK) < twotracksconfigs.ConfNsigmaCombined) { + if (std::hypot(nsigmaTOFK, nsigmaTPCK) < twotracksconfigs.confNsigmaCombined) { return true; } else { return false; @@ -221,24 +237,24 @@ struct femtoUniversePairTaskTrackTrackExtended { return false; } - bool IsPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) + bool isPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) { //|nsigma_TPC| < 3 for p < 0.5 GeV/c //|nsigma_combined| < 3 for p > 0.5 // using configurables: - // ConfTOFPtMin - momentum value when we start using TOF; set to 1000 if TOF not needed - // ConfNsigmaTPC -> TPC Sigma for momentum < ConfTOFPtMin - // ConfNsigmaCombined -> TPC and TOF Sigma (combined) for momentum > ConfTOFPtMin + // confTOFPtMin - momentum value when we start using TOF; set to 1000 if TOF not needed + // confNsigmaTPC -> TPC Sigma for momentum < confTOFPtMin + // confNsigmaCombined -> TPC and TOF Sigma (combined) for momentum > confTOFPtMin if (true) { - if (mom < twotracksconfigs.ConfTOFPtMin) { - if (TMath::Abs(nsigmaTPCPi) < twotracksconfigs.ConfNsigmaTPC) { + if (mom < twotracksconfigs.confTOFPtMin) { + if (std::abs(nsigmaTPCPi) < twotracksconfigs.confNsigmaTPC) { return true; } else { return false; } } else { - if (TMath::Hypot(nsigmaTOFPi, nsigmaTPCPi) < twotracksconfigs.ConfNsigmaCombined) { + if (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < twotracksconfigs.confNsigmaCombined) { return true; } else { return false; @@ -248,45 +264,45 @@ struct femtoUniversePairTaskTrackTrackExtended { return false; } - bool IsParticleNSigma(int8_t particle_number, float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) + bool isParticleNSigma(int8_t particle_number, float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) { if (particle_number == 1) { - switch (trackonefilter.ConfPDGCodePartOne) { + switch (trackonefilter.confPDGCodePartOne) { case 2212: // Proton case -2212: // anty Proton - return IsProtonNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); + return isProtonNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); break; case 211: // Pion case -211: // Pion- case 111: // Pion 0 - return IsPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); + return isPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); break; case 321: // Kaon+ case -321: // Kaon- case 130: // Kaon 0 LONG case 310: // Kaon 0 SHORT - return IsKaonNSigma(mom, nsigmaTPCK, nsigmaTOFK); + return isKaonNSigma(mom, nsigmaTPCK, nsigmaTOFK); break; default: return false; } return false; } else if (particle_number == 2) { - switch (tracktwofilter.ConfPDGCodePartTwo) { + switch (tracktwofilter.confPDGCodePartTwo) { case 2212: // Proton case -2212: // anty Proton - return IsProtonNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); + return isProtonNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); break; case 211: // Pion case -211: // Pion- case 111: // Pion 0 - return IsPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); + return isPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); break; case 321: // Kaon+ case -321: // Kaon- case 130: // Kaon 0 LONG case 310: // Kaon 0 SHORT - return IsKaonNSigma(mom, nsigmaTPCK, nsigmaTOFK); + return isKaonNSigma(mom, nsigmaTPCK, nsigmaTOFK); break; default: return false; @@ -298,38 +314,84 @@ struct femtoUniversePairTaskTrackTrackExtended { return false; } + /// @returns 1 if positive, -1 if negative, 0 if zero + auto sign(auto number) -> int8_t + { + return (number > 0) - (number < 0); + } + void init(InitContext&) { + if (twotracksconfigs.confIsMC) { + hMCTruth1.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarPDGBins, false, trackonefilter.confPDGCodePartOne, false); + if (!confIsSame) { + hMCTruth2.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarPDGBins, false, tracktwofilter.confPDGCodePartTwo, false); + } + } + effCorrection.init(); + eventHisto.init(&qaRegistry); - trackHistoPartOne.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarBins, twotracksconfigs.ConfIsMC, trackonefilter.ConfPDGCodePartOne, true); // last true = isDebug - if (!ConfIsSame) { - trackHistoPartTwo.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarBins, twotracksconfigs.ConfIsMC, tracktwofilter.ConfPDGCodePartTwo, true); // last true = isDebug + trackHistoPartOne.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarBins, twotracksconfigs.confIsMC, trackonefilter.confPDGCodePartOne, true); // last true = isDebug + if (!confIsSame) { + trackHistoPartTwo.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarBins, twotracksconfigs.confIsMC, tracktwofilter.confPDGCodePartTwo, true); // last true = isDebug } - MixQaRegistry.add("MixingQA/hSECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); - MixQaRegistry.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); + mixQaRegistry.add("MixingQA/hSECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); + mixQaRegistry.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); - sameEventCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfEtaBins, ConfPhiBins, twotracksconfigs.ConfIsMC, twotracksconfigs.ConfUse3D); - mixedEventCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfEtaBins, ConfPhiBins, twotracksconfigs.ConfIsMC, twotracksconfigs.ConfUse3D); - sameEventCont.setPDGCodes(trackonefilter.ConfPDGCodePartOne, tracktwofilter.ConfPDGCodePartTwo); - mixedEventCont.setPDGCodes(trackonefilter.ConfPDGCodePartOne, tracktwofilter.ConfPDGCodePartTwo); + sameEventCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, twotracksconfigs.confIsMC, twotracksconfigs.confUse3D); + mixedEventCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, twotracksconfigs.confIsMC, twotracksconfigs.confUse3D); + sameEventCont.setPDGCodes(trackonefilter.confPDGCodePartOne, tracktwofilter.confPDGCodePartTwo); + mixedEventCont.setPDGCodes(trackonefilter.confPDGCodePartOne, tracktwofilter.confPDGCodePartTwo); pairCleaner.init(&qaRegistry); - if (ConfIsCPR.value) { - pairCloseRejection.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiCutMin.value, ConfCPRdeltaPhiCutMax.value, ConfCPRdeltaEtaCutMin.value, ConfCPRdeltaEtaCutMax.value, ConfCPRChosenRadii.value, ConfCPRPlotPerRadii.value); + if (confIsCPR.value) { + pairCloseRejection.init(&resultRegistry, &qaRegistry, confCPRdeltaPhiCutMin.value, confCPRdeltaPhiCutMax.value, confCPRdeltaEtaCutMin.value, confCPRdeltaEtaCutMax.value, confCPRChosenRadii.value, confCPRPlotPerRadii.value); } - vPIDPartOne = trackonefilter.ConfPIDPartOne.value; - vPIDPartTwo = tracktwofilter.ConfPIDPartTwo.value; - kNsigma = twotracksconfigs.ConfTrkPIDnSigmaMax.value; + vPIDPartOne = trackonefilter.confPIDPartOne.value; + vPIDPartTwo = tracktwofilter.confPIDPartTwo.value; + kNsigma = twotracksconfigs.confTrkPIDnSigmaMax.value; } template void fillCollision(CollisionType col) { - MixQaRegistry.fill(HIST("MixingQA/hSECollisionBins"), colBinning.getBin({col.posZ(), col.multNtr()})); + mixQaRegistry.fill(HIST("MixingQA/hSECollisionBins"), colBinning.getBin({col.posZ(), col.multNtr()})); eventHisto.fillQA(col); } + template + requires isOneOrTwo + auto doMCTruth(FemtoUniverseParticleHisto hist, auto parts) -> void + { + auto expectedPDG = 0; + auto expectedCharge = 0.0l; + + if constexpr (N == ParticleNo::ONE) { + expectedPDG = trackonefilter.confPDGCodePartOne; + expectedCharge = trackonefilter.confChargePart1; + } else if constexpr (N == ParticleNo::TWO) { + expectedPDG = tracktwofilter.confPDGCodePartTwo; + expectedCharge = tracktwofilter.confChargePart2; + } + + for (const auto& particle : parts) { + auto pdgCode = static_cast(particle.pidCut()); + if (pdgCode != expectedPDG) { + continue; + } + + const auto& pdgParticle = pdgMC->GetParticle(pdgCode); + if (!pdgParticle) { + continue; + } + + if (sign(pdgParticle->Charge()) == sign(expectedCharge)) { + hist.template fillQA(particle); + } + } + } + /// This function processes the same event and takes care of all the histogramming /// \todo the trivial loops over the tracks should be factored out since they will be common to all combinations of T-T, T-V0, V0-V0, ... /// @tparam PartitionType @@ -348,22 +410,23 @@ struct femtoUniversePairTaskTrackTrackExtended { fNeventsProcessed++; /// Histogramming same event - for (auto& part : groupPartsOne) { - // if (part.p() > twotracksconfigs.ConfCutTable->get("PartOne", "MaxP") || part.pt() > twotracksconfigs.ConfCutTable->get("PartOne", "MaxPt")) { + for (const auto& part : groupPartsOne) { + // if (part.p() > twotracksconfigs.confCutTable->get("PartOne", "MaxP") || part.pt() > twotracksconfigs.confCutTable->get("PartOne", "MaxPt")) { // continue; // } - // if (!isFullPIDSelected(part.pidcut(), + // if (!isFullPIDSelected(part.pidCut(), // part.p(), - // twotracksconfigs.ConfCutTable->get("PartOne", "PIDthr"), + // twotracksconfigs.confCutTable->get("PartOne", "PIDthr"), // vPIDPartOne, - // twotracksconfigs.ConfNspecies, + // twotracksconfigs.confNspecies, // kNsigma, - // twotracksconfigs.ConfCutTable->get("PartOne", "nSigmaTPC"), - // twotracksconfigs.ConfCutTable->get("PartOne", "nSigmaTPCTOF"))) { + // twotracksconfigs.confCutTable->get("PartOne", "nSigmaTPC"), + // twotracksconfigs.confCutTable->get("PartOne", "nSigmaTPCTOF"))) { // continue; // } - if (trackonefilter.ConfIsTrackOneIdentified) { - if (!IsParticleNSigma((int8_t)1, part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { + + if (trackonefilter.confIsTrackOneIdentified) { + if (!isParticleNSigma((int8_t)1, part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { continue; } } @@ -371,23 +434,24 @@ struct femtoUniversePairTaskTrackTrackExtended { trackHistoPartOne.fillQA(part); } - if (!ConfIsSame) { - for (auto& part : groupPartsTwo) { - // if (part.p() > twotracksconfigs.ConfCutTable->get("PartTwo", "MaxP") || part.pt() > twotracksconfigs.ConfCutTable->get("PartTwo", "MaxPt")) { + if (!confIsSame) { + for (const auto& part : groupPartsTwo) { + // if (part.p() > twotracksconfigs.confCutTable->get("PartTwo", "MaxP") || part.pt() > twotracksconfigs.confCutTable->get("PartTwo", "MaxPt")) { // continue; // } - // if (!isFullPIDSelected(part.pidcut(), + // if (!isFullPIDSelected(part.pidCut(), // part.p(), - // twotracksconfigs.ConfCutTable->get("PartTwo", "PIDthr"), + // twotracksconfigs.confCutTable->get("PartTwo", "PIDthr"), // vPIDPartTwo, - // twotracksconfigs.ConfNspecies, + // twotracksconfigs.confNspecies, // kNsigma, - // twotracksconfigs.ConfCutTable->get("PartTwo", "nSigmaTPC"), - // twotracksconfigs.ConfCutTable->get("PartTwo", "nSigmaTPCTOF"))) { + // twotracksconfigs.confCutTable->get("PartTwo", "nSigmaTPC"), + // twotracksconfigs.confCutTable->get("PartTwo", "nSigmaTPCTOF"))) { // continue; // } - if (tracktwofilter.ConfIsTrackTwoIdentified) { - if (!IsParticleNSigma((int8_t)2, part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { + + if (tracktwofilter.confIsTrackTwoIdentified) { + if (!isParticleNSigma((int8_t)2, part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { continue; } } @@ -395,43 +459,43 @@ struct femtoUniversePairTaskTrackTrackExtended { } /// Now build the combinations for non-identical particle pairs - for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { - // if (p1.p() > twotracksconfigs.ConfCutTable->get("PartOne", "MaxP") || p1.pt() > twotracksconfigs.ConfCutTable->get("PartOne", "MaxPt") || p2.p() > twotracksconfigs.ConfCutTable->get("PartTwo", "MaxP") || p2.pt() > twotracksconfigs.ConfCutTable->get("PartTwo", "MaxPt")) { + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + // if (p1.p() > twotracksconfigs.confCutTable->get("PartOne", "MaxP") || p1.pt() > twotracksconfigs.confCutTable->get("PartOne", "MaxPt") || p2.p() > twotracksconfigs.confCutTable->get("PartTwo", "MaxP") || p2.pt() > twotracksconfigs.confCutTable->get("PartTwo", "MaxPt")) { // continue; // } - // if (!isFullPIDSelected(p1.pidcut(), + // if (!isFullPIDSelected(p1.pidCut(), // p1.p(), - // twotracksconfigs.ConfCutTable->get("PartOne", "PIDthr"), + // twotracksconfigs.confCutTable->get("PartOne", "PIDthr"), // vPIDPartOne, - // twotracksconfigs.ConfNspecies, + // twotracksconfigs.confNspecies, // kNsigma, - // twotracksconfigs.ConfCutTable->get("PartOne", "nSigmaTPC"), - // twotracksconfigs.ConfCutTable->get("PartOne", "nSigmaTPCTOF")) || - // !isFullPIDSelected(p2.pidcut(), + // twotracksconfigs.confCutTable->get("PartOne", "nSigmaTPC"), + // twotracksconfigs.confCutTable->get("PartOne", "nSigmaTPCTOF")) || + // !isFullPIDSelected(p2.pidCut(), // p2.p(), - // twotracksconfigs.ConfCutTable->get("PartTwo", "PIDthr"), + // twotracksconfigs.confCutTable->get("PartTwo", "PIDthr"), // vPIDPartTwo, - // twotracksconfigs.ConfNspecies, + // twotracksconfigs.confNspecies, // kNsigma, - // twotracksconfigs.ConfCutTable->get("PartTwo", "nSigmaTPC"), - // twotracksconfigs.ConfCutTable->get("PartTwo", "nSigmaTPCTOF"))) { + // twotracksconfigs.confCutTable->get("PartTwo", "nSigmaTPC"), + // twotracksconfigs.confCutTable->get("PartTwo", "nSigmaTPCTOF"))) { // continue; // } - if (trackonefilter.ConfIsTrackOneIdentified) { - if (!IsParticleNSigma((int8_t)1, p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { + if (trackonefilter.confIsTrackOneIdentified) { + if (!isParticleNSigma((int8_t)1, p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { continue; } } - if (tracktwofilter.ConfIsTrackTwoIdentified) { - if (!IsParticleNSigma((int8_t)2, p2.p(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon))) { + if (tracktwofilter.confIsTrackTwoIdentified) { + if (!isParticleNSigma((int8_t)2, p2.p(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon))) { continue; } } - if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::same)) { + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } } @@ -441,53 +505,58 @@ struct femtoUniversePairTaskTrackTrackExtended { continue; } + float weight = effCorrection.getWeight(ParticleNo::ONE, p1.pt()); + if (!confIsSame) { + weight *= effCorrection.getWeight(ParticleNo::TWO, p2.pt()); + } + if (swpart) - sameEventCont.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); + sameEventCont.setPair(p1, p2, multCol, twotracksconfigs.confUse3D, weight); else - sameEventCont.setPair(p2, p1, multCol, twotracksconfigs.ConfUse3D); + sameEventCont.setPair(p2, p1, multCol, twotracksconfigs.confUse3D, weight); swpart = !swpart; } } else { /// Now build the combinations for identical particle pairs (different combination policy than for non-identical!) - for (auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsOne, groupPartsTwo))) { - // if (p1.p() > twotracksconfigs.ConfCutTable->get("PartOne", "MaxP") || p1.pt() > twotracksconfigs.ConfCutTable->get("PartOne", "MaxPt") || p2.p() > twotracksconfigs.ConfCutTable->get("PartTwo", "MaxP") || p2.pt() > twotracksconfigs.ConfCutTable->get("PartTwo", "MaxPt")) { + for (const auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsOne, groupPartsTwo))) { + // if (p1.p() > twotracksconfigs.confCutTable->get("PartOne", "MaxP") || p1.pt() > twotracksconfigs.confCutTable->get("PartOne", "MaxPt") || p2.p() > twotracksconfigs.confCutTable->get("PartTwo", "MaxP") || p2.pt() > twotracksconfigs.confCutTable->get("PartTwo", "MaxPt")) { // continue; // } - // if (!isFullPIDSelected(p1.pidcut(), + // if (!isFullPIDSelected(p1.pidCut(), // p1.p(), - // twotracksconfigs.ConfCutTable->get("PartOne", "PIDthr"), + // twotracksconfigs.confCutTable->get("PartOne", "PIDthr"), // vPIDPartOne, - // twotracksconfigs.ConfNspecies, + // twotracksconfigs.confNspecies, // kNsigma, - // twotracksconfigs.ConfCutTable->get("PartOne", "nSigmaTPC"), - // twotracksconfigs.ConfCutTable->get("PartOne", "nSigmaTPCTOF")) || - // !isFullPIDSelected(p2.pidcut(), + // twotracksconfigs.confCutTable->get("PartOne", "nSigmaTPC"), + // twotracksconfigs.confCutTable->get("PartOne", "nSigmaTPCTOF")) || + // !isFullPIDSelected(p2.pidCut(), // p2.p(), - // twotracksconfigs.ConfCutTable->get("PartTwo", "PIDthr"), + // twotracksconfigs.confCutTable->get("PartTwo", "PIDthr"), // vPIDPartTwo, - // twotracksconfigs.ConfNspecies, + // twotracksconfigs.confNspecies, // kNsigma, - // twotracksconfigs.ConfCutTable->get("PartTwo", "nSigmaTPC"), - // twotracksconfigs.ConfCutTable->get("PartTwo", "nSigmaTPCTOF"))) { + // twotracksconfigs.confCutTable->get("PartTwo", "nSigmaTPC"), + // twotracksconfigs.confCutTable->get("PartTwo", "nSigmaTPCTOF"))) { // continue; // } - if (trackonefilter.ConfIsTrackOneIdentified) { - if (!IsParticleNSigma((int8_t)1, p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { + if (trackonefilter.confIsTrackOneIdentified) { + if (!isParticleNSigma((int8_t)1, p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { continue; } } - if (tracktwofilter.ConfIsTrackTwoIdentified) { - if (!IsParticleNSigma((int8_t)2, p2.p(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon))) { + if (tracktwofilter.confIsTrackTwoIdentified) { + if (!isParticleNSigma((int8_t)2, p2.p(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon))) { continue; } } - if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::same)) { + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } } @@ -496,7 +565,13 @@ struct femtoUniversePairTaskTrackTrackExtended { if (!pairCleaner.isCleanPair(p1, p2, parts)) { continue; } - sameEventCont.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); + + float weight = effCorrection.getWeight(ParticleNo::ONE, p1.pt()); + if (!confIsSame) { + weight *= effCorrection.getWeight(ParticleNo::TWO, p2.pt()); + } + + sameEventCont.setPair(p1, p2, multCol, twotracksconfigs.confUse3D, weight); } } } @@ -504,8 +579,8 @@ struct femtoUniversePairTaskTrackTrackExtended { /// process function for to call doSameEvent with Data /// \param col subscribe to the collision table (Data) /// \param parts subscribe to the femtoUniverseParticleTable - void processSameEvent(o2::aod::FDCollision& col, - FilteredFemtoFullParticles& parts) + void processSameEvent(const o2::aod::FdCollision& col, + const FilteredFemtoFullParticles& parts) { fillCollision(col); @@ -514,24 +589,32 @@ struct femtoUniversePairTaskTrackTrackExtended { doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multNtr()); } - PROCESS_SWITCH(femtoUniversePairTaskTrackTrackExtended, processSameEvent, "Enable processing same event", true); + PROCESS_SWITCH(FemtoUniversePairTaskTrackTrackExtended, processSameEvent, "Enable processing same event", true); /// process function for to call doSameEvent with Monte Carlo /// \param col subscribe to the collision table (Monte Carlo Reconstructed reconstructed) /// \param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth /// \param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table - void processSameEventMC(o2::aod::FDCollision& col, - soa::Join& parts, - o2::aod::FDMCParticles&) + void processSameEventMC(const o2::aod::FdCollision& col, + const soa::Join& parts, + const o2::aod::FdMCParticles&) { fillCollision(col); - auto thegroupPartsOne = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto thegroupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto groupMCTruth1 = partsOneMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + doMCTruth<1>(hMCTruth1, groupMCTruth1); - doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multNtr()); + if (!confIsSame) { + auto groupMCTruth2 = partsTwoMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + doMCTruth<2>(hMCTruth2, groupMCTruth2); + } + + auto groupMCReco1 = partsOneMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto groupMCReco2 = partsTwoMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + doSameEvent(groupMCReco1, groupMCReco2, parts, col.magField(), col.multNtr()); } - PROCESS_SWITCH(femtoUniversePairTaskTrackTrackExtended, processSameEventMC, "Enable processing same event for Monte Carlo", false); + PROCESS_SWITCH(FemtoUniversePairTaskTrackTrackExtended, processSameEventMC, "Enable processing same event for Monte Carlo", false); /// This function processes the mixed event /// \todo the trivial loops over the collisions and tracks should be factored out since they will be common to all combinations of T-T, T-V0, V0-V0, ... @@ -551,50 +634,55 @@ struct femtoUniversePairTaskTrackTrackExtended { bool swpart = fNeventsProcessed % 2; fNeventsProcessed++; - for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { - // if (p1.p() > twotracksconfigs.ConfCutTable->get("PartOne", "MaxP") || p1.pt() > twotracksconfigs.ConfCutTable->get("PartOne", "MaxPt") || p2.p() > twotracksconfigs.ConfCutTable->get("PartTwo", "MaxP") || p2.pt() > twotracksconfigs.ConfCutTable->get("PartTwo", "MaxPt")) { + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + // if (p1.p() > twotracksconfigs.confCutTable->get("PartOne", "MaxP") || p1.pt() > twotracksconfigs.confCutTable->get("PartOne", "MaxPt") || p2.p() > twotracksconfigs.confCutTable->get("PartTwo", "MaxP") || p2.pt() > twotracksconfigs.confCutTable->get("PartTwo", "MaxPt")) { // continue; // } - // if (!isFullPIDSelected(p1.pidcut(), + // if (!isFullPIDSelected(p1.pidCut(), // p1.p(), - // twotracksconfigs.ConfCutTable->get("PartOne", "PIDthr"), + // twotracksconfigs.confCutTable->get("PartOne", "PIDthr"), // vPIDPartOne, - // twotracksconfigs.ConfNspecies, + // twotracksconfigs.confNspecies, // kNsigma, - // twotracksconfigs.ConfCutTable->get("PartOne", "nSigmaTPC"), - // twotracksconfigs.ConfCutTable->get("PartOne", "nSigmaTPCTOF")) || - // !isFullPIDSelected(p2.pidcut(), + // twotracksconfigs.confCutTable->get("PartOne", "nSigmaTPC"), + // twotracksconfigs.confCutTable->get("PartOne", "nSigmaTPCTOF")) || + // !isFullPIDSelected(p2.pidCut(), // p2.p(), - // twotracksconfigs.ConfCutTable->get("PartTwo", "PIDthr"), + // twotracksconfigs.confCutTable->get("PartTwo", "PIDthr"), // vPIDPartTwo, - // twotracksconfigs.ConfNspecies, + // twotracksconfigs.confNspecies, // kNsigma, - // twotracksconfigs.ConfCutTable->get("PartTwo", "nSigmaTPC"), - // twotracksconfigs.ConfCutTable->get("PartTwo", "nSigmaTPCTOF"))) { + // twotracksconfigs.confCutTable->get("PartTwo", "nSigmaTPC"), + // twotracksconfigs.confCutTable->get("PartTwo", "nSigmaTPCTOF"))) { // continue; // } - if (trackonefilter.ConfIsTrackOneIdentified) { - if (!IsParticleNSigma((int8_t)1, p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { + if (trackonefilter.confIsTrackOneIdentified) { + if (!isParticleNSigma((int8_t)1, p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { continue; } } - if (tracktwofilter.ConfIsTrackTwoIdentified) { - if (!IsParticleNSigma((int8_t)2, p2.p(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon))) { + if (tracktwofilter.confIsTrackTwoIdentified) { + if (!isParticleNSigma((int8_t)2, p2.p(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon))) { continue; } } - if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::mixed)) { + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::mixed)) { continue; } } + float weight = effCorrection.getWeight(ParticleNo::ONE, p1.pt()); + if (!confIsSame) { + weight *= effCorrection.getWeight(ParticleNo::TWO, p2.pt()); + } + if (swpart) - mixedEventCont.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); + mixedEventCont.setPair(p1, p2, multCol, twotracksconfigs.confUse3D, weight); else - mixedEventCont.setPair(p2, p1, multCol, twotracksconfigs.ConfUse3D); + mixedEventCont.setPair(p2, p1, multCol, twotracksconfigs.confUse3D, weight); swpart = !swpart; } @@ -603,13 +691,13 @@ struct femtoUniversePairTaskTrackTrackExtended { /// process function for to call doMixedEvent with Data /// @param cols subscribe to the collisions table (Data) /// @param parts subscribe to the femtoUniverseParticleTable - void processMixedEvent(o2::aod::FDCollisions& cols, - FilteredFemtoFullParticles& parts) + void processMixedEvent(const o2::aod::FdCollisions& cols, + const FilteredFemtoFullParticles& parts) { - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { const int multiplicityCol = collision1.multNtr(); - MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); @@ -626,23 +714,23 @@ struct femtoUniversePairTaskTrackTrackExtended { doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol); } } - PROCESS_SWITCH(femtoUniversePairTaskTrackTrackExtended, processMixedEvent, "Enable processing mixed events", true); + PROCESS_SWITCH(FemtoUniversePairTaskTrackTrackExtended, processMixedEvent, "Enable processing mixed events", true); /// brief process function for to call doMixedEvent with Monte Carlo /// @param cols subscribe to the collisions table (Monte Carlo Reconstructed reconstructed) /// @param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth /// @param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table - void processMixedEventMC(o2::aod::FDCollisions& cols, - soa::Join& parts, - o2::aod::FDMCParticles&) + void processMixedEventMC(const o2::aod::FdCollisions& cols, + const soa::Join& parts, + const o2::aod::FdMCParticles&) { - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { const int multiplicityCol = collision1.multNtr(); - MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); - auto groupPartsOne = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); - auto groupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + auto groupPartsOne = partsOneMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); const auto& magFieldTesla1 = collision1.magField(); const auto& magFieldTesla2 = collision2.magField(); @@ -656,13 +744,13 @@ struct femtoUniversePairTaskTrackTrackExtended { doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol); } } - PROCESS_SWITCH(femtoUniversePairTaskTrackTrackExtended, processMixedEventMC, "Enable processing mixed events MC", false); + PROCESS_SWITCH(FemtoUniversePairTaskTrackTrackExtended, processMixedEventMC, "Enable processing mixed events MC", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow{ - adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), }; return workflow; } diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMC.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMC.cxx index 2a9a1bb8153..09386709a01 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMC.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMC.cxx @@ -35,13 +35,13 @@ #include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniversePairAngularWithCentMultKt.h" using namespace o2; -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; @@ -167,27 +167,27 @@ struct femtoUniversePairTaskTrackTrackMC { Configurable cfgProcessMultBins{"cfgProcessMultBins", true, "Process kstar histograms in multiplicity bins (in multiplicity bins)"}; Configurable cfgProcessKtBins{"cfgProcessKtBins", true, "Process kstar histograms in kT bins (if cfgProcessMultBins is set false, this will not be processed regardless this Configurable state)"}; - FemtoUniverseContainer sameEventCont; - FemtoUniverseContainer mixedEventCont; + FemtoUniverseContainer sameEventCont; + FemtoUniverseContainer mixedEventCont; - FemtoUniverseContainer sameEventContPP; - FemtoUniverseContainer mixedEventContPP; + FemtoUniverseContainer sameEventContPP; + FemtoUniverseContainer mixedEventContPP; - FemtoUniverseContainer sameEventContMM; - FemtoUniverseContainer mixedEventContMM; + FemtoUniverseContainer sameEventContMM; + FemtoUniverseContainer mixedEventContMM; FemtoUniversePairCleaner pairCleaner; FemtoUniverseDetaDphiStar pairCloseRejection; FemtoUniverseTrackSelection trackCuts; - PairWithCentMultKt sameEventMultCont; - PairWithCentMultKt mixedEventMultCont; + FemtoUniversePairAngularWithCentMultKt sameEventMultCont; + FemtoUniversePairAngularWithCentMultKt mixedEventMultCont; - PairWithCentMultKt sameEventMultContPP; - PairWithCentMultKt mixedEventMultContPP; + FemtoUniversePairAngularWithCentMultKt sameEventMultContPP; + FemtoUniversePairAngularWithCentMultKt mixedEventMultContPP; - PairWithCentMultKt sameEventMultContMM; - PairWithCentMultKt mixedEventMultContMM; + FemtoUniversePairAngularWithCentMultKt sameEventMultContMM; + FemtoUniversePairAngularWithCentMultKt mixedEventMultContMM; float mass1 = -1; float mass2 = -1; @@ -449,7 +449,7 @@ struct femtoUniversePairTaskTrackTrackMC { } if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::same)) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } } @@ -481,7 +481,7 @@ struct femtoUniversePairTaskTrackTrackMC { } if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::same)) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } } @@ -524,7 +524,7 @@ struct femtoUniversePairTaskTrackTrackMC { /// process function for to call doSameEvent with Data /// \param col subscribe to the collision table (Data) /// \param parts subscribe to the femtoUniverseParticleTable - void processSameEvent(o2::aod::FDCollision& col, + void processSameEvent(o2::aod::FdCollision& col, FilteredFemtoFullParticles& parts) { fillCollision(col); @@ -549,9 +549,9 @@ struct femtoUniversePairTaskTrackTrackMC { /// \param col subscribe to the collision table (Monte Carlo Reconstructed reconstructed) /// \param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth /// \param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table - void processSameEventMC(o2::aod::FDCollision& col, + void processSameEventMC(o2::aod::FdCollision& col, soa::Join& parts, - o2::aod::FDMCParticles&) + o2::aod::FdMCParticles&) { fillCollision(col); @@ -595,7 +595,7 @@ struct femtoUniversePairTaskTrackTrackMC { } if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::mixed)) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::mixed)) { continue; } } @@ -641,7 +641,7 @@ struct femtoUniversePairTaskTrackTrackMC { /// process function for to call doMixedEvent with Data /// @param cols subscribe to the collisions table (Data) /// @param parts subscribe to the femtoUniverseParticleTable - void processMixedEvent(o2::aod::FDCollisions& cols, + void processMixedEvent(o2::aod::FdCollisions& cols, FilteredFemtoFullParticles& parts) { for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { @@ -679,9 +679,9 @@ struct femtoUniversePairTaskTrackTrackMC { /// @param cols subscribe to the collisions table (Monte Carlo Reconstructed reconstructed) /// @param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth /// @param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table - void processMixedEventMC(o2::aod::FDCollisions& cols, + void processMixedEventMC(o2::aod::FdCollisions& cols, soa::Join& parts, - o2::aod::FDMCParticles&) + o2::aod::FdMCParticles&) { for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMcTruth.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMcTruth.cxx index f1d7285d070..91da795ca2f 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMcTruth.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMcTruth.cxx @@ -30,11 +30,11 @@ #include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" using namespace o2; -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; @@ -50,28 +50,28 @@ struct femtoUniversePairTaskTrackTrackMcTruth { Configurable ConfEtaMax{"ConfEtaMax", 0.8f, "Higher limit for |Eta| (the same for both particles)"}; /// Particle 1 - Configurable ConfPDGCodePartOne{"ConfPDGCodePartOne", 211, "Particle 1 - PDG code"}; + Configurable ConfPDGCodePartOne{"ConfPDGCodePartOne", 2212, "Particle 1 - PDG code"}; Configurable ConfNoPDGPartOne{"ConfNoPDGPartOne", false, "0: selecting part by PDG, 1: no PID selection"}; Configurable ConfPtLowPart1{"ConfPtLowPart1", 0.2, "Lower limit for Pt for the first particle"}; Configurable ConfPtHighPart1{"ConfPtHighPart1", 2.5, "Higher limit for Pt for the first particle"}; /// Partition for particle 1 - Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (ConfNoPDGPartOne || aod::femtouniverseparticle::pidcut == uint32_t(ConfPDGCodePartOne)) && - aod::femtouniverseparticle::pt < ConfPtHighPart1 && aod::femtouniverseparticle::pt > ConfPtLowPart1&& nabs(aod::femtouniverseparticle::eta) < ConfEtaMax; + Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && + (aod::femtouniverseparticle::pt < ConfPtHighPart1) && (aod::femtouniverseparticle::pt > ConfPtLowPart1) && (nabs(aod::femtouniverseparticle::eta) < ConfEtaMax); /// Histogramming for particle 1 FemtoUniverseParticleHisto trackHistoPartOne; /// Particle 2 Configurable ConfIsSame{"ConfIsSame", false, "Pairs of the same particle"}; - Configurable ConfPDGCodePartTwo{"ConfPDGCodePartTwo", 211, "Particle 2 - PDG code"}; + Configurable ConfPDGCodePartTwo{"ConfPDGCodePartTwo", 333, "Particle 2 - PDG code"}; Configurable ConfNoPDGPartTwo{"ConfNoPDGPartTwo", false, "0: selecting part by PDG, 1: no PID selection"}; Configurable ConfPtLowPart2{"ConfPtLowPart2", 0.2, "Lower limit for Pt for the second particle"}; Configurable ConfPtHighPart2{"ConfPtHighPart2", 2.5, "Higher limit for Pt for the second particle"}; /// Partition for particle 2 - Partition partsTwo = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (ConfNoPDGPartTwo || aod::femtouniverseparticle::pidcut == uint32_t(ConfPDGCodePartTwo)) && - aod::femtouniverseparticle::pt < ConfPtHighPart2 && aod::femtouniverseparticle::pt > ConfPtLowPart2&& nabs(aod::femtouniverseparticle::eta) < ConfEtaMax; + Partition partsTwo = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && + (aod::femtouniverseparticle::pt < ConfPtHighPart2) && (aod::femtouniverseparticle::pt > ConfPtLowPart2) && (nabs(aod::femtouniverseparticle::eta) < ConfEtaMax); /// Histogramming for particle 2 FemtoUniverseParticleHisto trackHistoPartTwo; @@ -106,8 +106,8 @@ struct femtoUniversePairTaskTrackTrackMcTruth { Configurable ConfPhiBins{"ConfPhiBins", 29, "Number of phi bins in deta dphi"}; Configurable ConfEtaBins{"ConfEtaBins", 29, "Number of eta bins in deta dphi"}; - FemtoUniverseContainer sameEventCont; - FemtoUniverseContainer mixedEventCont; + FemtoUniverseContainer sameEventCont; + FemtoUniverseContainer mixedEventCont; FemtoUniversePairCleaner pairCleaner; /// Histogram output HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -161,35 +161,61 @@ struct femtoUniversePairTaskTrackTrackMcTruth { /// Histogramming same event for (auto& part : groupPartsOne) { - + if (!ConfNoPDGPartOne && part.tempFitVar() != ConfPDGCodePartOne) { + continue; + } trackHistoPartOne.fillQA(part); } if (!ConfIsSame) { for (auto& part : groupPartsTwo) { - + if (!ConfNoPDGPartTwo && part.tempFitVar() != ConfPDGCodePartTwo) { + continue; + } trackHistoPartTwo.fillQA(part); } } /// Now build the combinations - for (auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsOne, groupPartsTwo))) { - // track cleaning - if (!pairCleaner.isCleanPair(p1, p2, parts)) { - continue; + if (!ConfIsSame) { + // Build the combinations for pairs of non-identical particles + for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + if ((!ConfNoPDGPartOne && p2.tempFitVar() != ConfPDGCodePartOne) || (!ConfNoPDGPartTwo && p1.tempFitVar() != ConfPDGCodePartTwo)) { + continue; + } + if (swpart) + sameEventCont.setPair(p1, p2, multCol, ConfUse3D); + else + sameEventCont.setPair(p2, p1, multCol, ConfUse3D); + + swpart = !swpart; + } + } else { + // Build the combinations for pairs of identical pairs + for (auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsOne, groupPartsTwo))) { + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + if ((!ConfNoPDGPartOne && p2.tempFitVar() != ConfPDGCodePartOne) || (!ConfNoPDGPartTwo && p1.tempFitVar() != ConfPDGCodePartTwo)) { + continue; + } + if (swpart) + sameEventCont.setPair(p1, p2, multCol, ConfUse3D); + else + sameEventCont.setPair(p2, p1, multCol, ConfUse3D); + + swpart = !swpart; } - if (swpart) - sameEventCont.setPair(p1, p2, multCol, ConfUse3D); - else - sameEventCont.setPair(p2, p1, multCol, ConfUse3D); - - swpart = !swpart; } } - /// process function for to call doSameEvent with Data /// \param col subscribe to the collision table (Data) /// \param parts subscribe to the femtoUniverseParticleTable - void processSameEvent(o2::aod::FDCollision& col, + void processSameEvent(o2::aod::FdCollision& col, o2::aod::FDParticles& parts) { fillCollision(col); @@ -218,6 +244,9 @@ struct femtoUniversePairTaskTrackTrackMcTruth { fNeventsProcessed++; for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + if ((!ConfNoPDGPartOne && p2.tempFitVar() != ConfPDGCodePartOne) || (!ConfNoPDGPartTwo && p1.tempFitVar() != ConfPDGCodePartTwo)) { + continue; + } if (swpart) mixedEventCont.setPair(p1, p2, multCol, ConfUse3D); else @@ -230,7 +259,7 @@ struct femtoUniversePairTaskTrackTrackMcTruth { /// process function for to call doMixedEvent with Data /// @param cols subscribe to the collisions table (Data) /// @param parts subscribe to the femtoUniverseParticleTable - void processMixedEvent(o2::aod::FDCollisions& cols, + void processMixedEvent(o2::aod::FdCollisions& cols, o2::aod::FDParticles& parts) { for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx index ff1761f8fb4..9d862855874 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx @@ -18,6 +18,7 @@ /// \author Alicja Płachta, WUT Warsaw, alicja.plachta.stud@pw.edu.pl #include +#include #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" @@ -35,13 +36,13 @@ #include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseFemtoContainer.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniversePairWithCentMultKt.h" using namespace o2; -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; @@ -52,9 +53,7 @@ static constexpr int nPart = 2; static constexpr int nCuts = 5; static const std::vector partNames{"PartOne", "PartTwo"}; static const std::vector cutNames{"MaxPt", "PIDthr", "nSigmaTPC", "nSigmaTPCTOF", "MaxP"}; -static const float cutsTable[nPart][nCuts]{ - {4.05f, 1.f, 3.f, 3.f, 100.f}, - {4.05f, 1.f, 3.f, 3.f, 100.f}}; +static const float cutsTable[nPart][nCuts]{{4.05f, 1.f, 3.f, 3.f, 100.f}, {4.05f, 1.f, 3.f, 3.f, 100.f}}; } // namespace struct femtoUniversePairTaskTrackTrackMultKtExtended { @@ -65,9 +64,10 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { /// Table for both particles struct : o2::framework::ConfigurableGroup { - Configurable ConfNsigmaCombined{"ConfNsigmaCombined", 3.0f, "TPC and TOF Pion Sigma (combined) for momentum > ConfTOFPtMin"}; - Configurable ConfNsigmaTPC{"ConfNsigmaTPC", 3.0f, "TPC Pion Sigma for momentum < ConfTOFPtMin"}; - Configurable ConfTOFPtMin{"ConfTOFPtMin", 0.5f, "Min. Pt for which TOF is required for PID."}; + Configurable IsKaonNsigma{"IsKaonNsigma", false, "Enable a strict cut selection for K+ and K-"}; + Configurable ConfNsigmaCombined{"ConfNsigmaCombined", 3.0f, "TPC and TOF Pion Sigma (combined) for momentum > ConfTOFpMin"}; + Configurable ConfNsigmaTPC{"ConfNsigmaTPC", 3.0f, "TPC Pion Sigma for momentum < ConfTOFpMin"}; + Configurable ConfTOFpMin{"ConfTOFpMin", 0.5f, "Min. momentum for which TOF is required for PID."}; Configurable ConfEtaMax{"ConfEtaMax", 0.8f, "Higher limit for |Eta| (the same for both particles)"}; Configurable> ConfCutTable{"ConfCutTable", {cutsTable[0], nPart, nCuts, partNames, cutNames}, "Particle selections"}; @@ -75,7 +75,6 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { Configurable ConfIsMC{"ConfIsMC", false, "Enable additional Histogramms in the case of a MonteCarlo Run"}; Configurable> ConfTrkPIDnSigmaMax{"ConfTrkPIDnSigmaMax", std::vector{4.f, 3.f, 2.f}, "This configurable needs to be the same as the one used in the producer task"}; Configurable ConfUse3D{"ConfUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; - } twotracksconfigs; using FemtoFullParticles = soa::Join; @@ -89,38 +88,36 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { /// Particle 1 struct : o2::framework::ConfigurableGroup { - Configurable ConfPDGCodePartOne{"ConfPDGCodePartOne", 211, "Particle 1 - PDG code"}; - // Configurable ConfCutPartOne{"ConfCutPartOne", 5542474, "Particle 1 - Selection bit from cutCulator"}; - Configurable ConfPIDPartOne{"ConfPIDPartOne", 2, "Particle 1 - Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector>int>> - Configurable ConfPtLowPart1{"ConfPtLowPart1", 0.14, "Lower limit for Pt for the first particle"}; + Configurable ConfPDGCodePartOne{"ConfPDGCodePartOne", 211, "Particle 1 -- PDG code"}; + // Configurable ConfCutPartOne{"ConfCutPartOne", 5542474, "Particle 1 -- Selection bit from cutCulator"}; + Configurable ConfPIDPartOne{"ConfPIDPartOne", 2, "Particle 1 -- Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector>int>> + Configurable ConfpLowPart1{"ConfpLowPart1", 0.14, "Lower limit for Pt for the first particle"}; Configurable ConfPtHighPart1{"ConfPtHighPart1", 1.5, "Higher limit for Pt for the first particle"}; Configurable ConfChargePart1{"ConfChargePart1", 1, "Particle 1 sign"}; } trackonefilter; /// Partition for particle 1 - Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == trackonefilter.ConfChargePart1 && aod::femtouniverseparticle::pt < trackonefilter.ConfPtHighPart1 && aod::femtouniverseparticle::pt > trackonefilter.ConfPtLowPart1; + Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == trackonefilter.ConfChargePart1 && aod::femtouniverseparticle::pt < trackonefilter.ConfPtHighPart1 && aod::femtouniverseparticle::pt > trackonefilter.ConfpLowPart1; - Partition> partsOneMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == trackonefilter.ConfChargePart1 && aod::femtouniverseparticle::pt < trackonefilter.ConfPtHighPart1 && aod::femtouniverseparticle::pt > trackonefilter.ConfPtLowPart1; - // + Partition> partsOneMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == trackonefilter.ConfChargePart1 && aod::femtouniverseparticle::pt < trackonefilter.ConfPtHighPart1 && aod::femtouniverseparticle::pt > trackonefilter.ConfpLowPart1; /// Histogramming for particle 1 FemtoUniverseParticleHisto trackHistoPartOne; /// Particle 2 struct : o2::framework::ConfigurableGroup { - Configurable ConfPDGCodePartTwo{"ConfPDGCodePartTwo", 211, "Particle 2 - PDG code"}; - // Configurable ConfCutPartTwo{"ConfCutPartTwo", 5542474, "Particle 2 - Selection bit"}; - Configurable ConfPIDPartTwo{"ConfPIDPartTwo", 2, "Particle 2 - Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector> - - Configurable ConfPtLowPart2{"ConfPtLowPart2", 0.14, "Lower limit for Pt for the second particle"}; + Configurable ConfPDGCodePartTwo{"ConfPDGCodePartTwo", 211, "Particle 2 -- PDG code"}; + // Configurable ConfCutPartTwo{"ConfCutPartTwo", 5542474, "Particle 2 -- Selection bit"}; + Configurable ConfPIDPartTwo{"ConfPIDPartTwo", 2, "Particle 2 -- Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector> + Configurable ConfpLowPart2{"ConfpLowPart2", 0.14, "Lower limit for Pt for the second particle"}; Configurable ConfPtHighPart2{"ConfPtHighPart2", 1.5, "Higher limit for Pt for the second particle"}; Configurable ConfChargePart2{"ConfChargePart2", -1, "Particle 2 sign"}; } tracktwofilter; /// Partition for particle 2 - Partition partsTwo = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == tracktwofilter.ConfChargePart2) && aod::femtouniverseparticle::pt < tracktwofilter.ConfPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.ConfPtLowPart2; + Partition partsTwo = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == tracktwofilter.ConfChargePart2) && aod::femtouniverseparticle::pt < tracktwofilter.ConfPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.ConfpLowPart2; - Partition> partsTwoMC = aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack) && (aod::femtouniverseparticle::sign == tracktwofilter.ConfChargePart2) && aod::femtouniverseparticle::pt < tracktwofilter.ConfPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.ConfPtLowPart2; + Partition> partsTwoMC = aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack) && (aod::femtouniverseparticle::sign == tracktwofilter.ConfChargePart2) && aod::femtouniverseparticle::pt < tracktwofilter.ConfPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.ConfpLowPart2; /// Histogramming for particle 2 FemtoUniverseParticleHisto trackHistoPartTwo; @@ -155,7 +152,7 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { ConfigurableAxis ConfmTBins3D{"ConfmTBins3D", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; ConfigurableAxis ConfmultBins3D{"ConfmultBins3D", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; - ColumnBinningPolicy colBinning{{ConfVtxBins, ConfMultBins}, true}; + ColumnBinningPolicy colBinning{{ConfVtxBins, ConfMultBins}, true}; ConfigurableAxis ConfkstarBins{"ConfkstarBins", {1500, 0., 6.}, "binning kstar"}; ConfigurableAxis ConfkTBins{"ConfkTBins", {150, 0., 9.}, "binning kT"}; @@ -169,34 +166,35 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { Configurable ConfCPRdeltaEtaCutMin{"ConfCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; Configurable ConfCPRChosenRadii{"ConfCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; - Configurable cfgProcessPM{"cfgProcessPM", false, "Process particles of the opposite charge"}; - Configurable cfgProcessPP{"cfgProcessPP", true, "Process particles of the same, positice charge"}; - Configurable cfgProcessMM{"cfgProcessMM", true, "Process particles of the same, positice charge"}; - Configurable cfgProcessMultBins{"cfgProcessMultBins", true, "Process kstar histograms in multiplicity bins (in multiplicity bins)"}; - Configurable cfgProcessKtBins{"cfgProcessKtBins", true, "Process kstar histograms in kT bins (if cfgProcessMultBins is set false, this will not be processed regardless this Configurable state)"}; - Configurable cfgProcessKtMt3DCF{"cfgProcessKtMt3DCF", false, "Process 3D histograms in kT and Mult bins"}; + Configurable IsPairIdentical{"IsPairIdentical", true, "'true' for identical particles, 'false' for non-identical particles"}; + Configurable cfgProcessPM{"cfgProcessPM", true, "Process differently charged particles (plus-minus)"}; + Configurable cfgProcessPP{"cfgProcessPP", true, "Process positively charged particles (plus-plus)"}; + Configurable cfgProcessMM{"cfgProcessMM", true, "Process negatively charged particles (minus-minus)"}; + Configurable cfgProcessMultBins{"cfgProcessMultBins", true, "Process kstar histograms (in multiplicity bins)"}; + Configurable cfgProcessKtBins{"cfgProcessKtBins", true, "Process kstar histograms in kT bins (if 'cfgProcessMultBins' is false, it will not be processed regardless of 'cfgProcessKtBins' state)"}; + Configurable cfgProcessKtMt3DCF{"cfgProcessKtMt3DCF", false, "Process 3D histograms in kT and MultBins"}; - FemtoUniverseFemtoContainer sameEventCont; - FemtoUniverseFemtoContainer mixedEventCont; + FemtoUniverseFemtoContainer sameEventCont; + FemtoUniverseFemtoContainer mixedEventCont; - FemtoUniverseFemtoContainer sameEventContPP; - FemtoUniverseFemtoContainer mixedEventContPP; + FemtoUniverseFemtoContainer sameEventContPP; + FemtoUniverseFemtoContainer mixedEventContPP; - FemtoUniverseFemtoContainer sameEventContMM; - FemtoUniverseFemtoContainer mixedEventContMM; + FemtoUniverseFemtoContainer sameEventContMM; + FemtoUniverseFemtoContainer mixedEventContMM; FemtoUniversePairCleaner pairCleaner; FemtoUniverseDetaDphiStar pairCloseRejection; FemtoUniverseTrackSelection trackCuts; - PairWithCentMultKt sameEventMultCont; - PairWithCentMultKt mixedEventMultCont; + FemtoUniversePairWithCentMultKt sameEventMultCont; + FemtoUniversePairWithCentMultKt mixedEventMultCont; - PairWithCentMultKt sameEventMultContPP; - PairWithCentMultKt mixedEventMultContPP; + FemtoUniversePairWithCentMultKt sameEventMultContPP; + FemtoUniversePairWithCentMultKt mixedEventMultContPP; - PairWithCentMultKt sameEventMultContMM; - PairWithCentMultKt mixedEventMultContMM; + FemtoUniversePairWithCentMultKt sameEventMultContMM; + FemtoUniversePairWithCentMultKt mixedEventMultContMM; float mass1 = -1; float mass2 = -1; @@ -220,123 +218,88 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { HistogramRegistry sphericityRegistry{"SphericityHisto", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - // PID for protons - bool IsProtonNSigma(float mom, float nsigmaTPCPr, float nsigmaTOFPr) // previous version from: https://github.com/alisw/AliPhysics/blob/master/PWGCF/FEMTOSCOPY/AliFemtoUser/AliFemtoMJTrackCut.cxx + /// TPC Pion/Kaon/Proton Sigma selection (general) + bool IsNSigma(float mom, float nsigmaTPC, float nsigmaTOF) { - //|nsigma_TPC| < 3 for p < 0.5 GeV/c - //|nsigma_combined| < 3 for p > 0.5 + // |nsigma_TPC| < 3 for p < 0.5 GeV/c + // |nsigma_combined| < 3 for p > 0.5 // using configurables: - // ConfTOFPtMin - momentum value when we start using TOF; set to 1000 if TOF not needed - // ConfNsigmaTPC -> TPC Sigma for momentum < 0.5 - // ConfNsigmaCombined -> TPC and TOF Sigma (combined) for momentum > 0.5 + // ConfTOFpMin -- momentum value when we start using TOF; set to 1000 if TOF not needed + // ConfNsigmaTPC -> TPC Sigma for momentum < ConfTOFpMin + // ConfNsigmaCombined -> TPC and TOF Sigma (combined) for momentum > ConfTOFpMin - if (mom < twotracksconfigs.ConfTOFPtMin) { - if (TMath::Abs(nsigmaTPCPr) < twotracksconfigs.ConfNsigmaTPC) { - return true; - } else { - return false; - } + if (mom < twotracksconfigs.ConfTOFpMin) { + return TMath::Abs(nsigmaTPC) < twotracksconfigs.ConfNsigmaTPC; } else { - if (TMath::Hypot(nsigmaTOFPr, nsigmaTPCPr) < twotracksconfigs.ConfNsigmaCombined) { - return true; - } else { - return false; - } + return TMath::Hypot(nsigmaTOF, nsigmaTPC) < twotracksconfigs.ConfNsigmaCombined; } - return false; } + /// TPC Kaon Sigma selection (stricter cuts for K+ and K-) -- based on Run2 results bool IsKaonNSigma(float mom, float nsigmaTPCK, float nsigmaTOFK) { - //|nsigma_TPC| < 3 for p < 0.5 GeV/c - //|nsigma_combined| < 3 for p > 0.5 - - // using configurables: - // ConfTOFPtMin - momentum value when we start using TOF; set to 1000 if TOF not needed - // ConfNsigmaTPCTOFKaon -> are we doing TPC TOF PID for Kaons? (boolean) - // ConfNsigmaTPC -> TPC Kaon Sigma for momentum < 0.5 - // ConfNsigmaCombined -> TPC and TOF Sigma (combined) for momentum > 0.5 - if (true) { - if (mom < twotracksconfigs.ConfTOFPtMin) { - if (TMath::Abs(nsigmaTPCK) < twotracksconfigs.ConfNsigmaTPC) { - return true; - } else { - return false; - } - } else { - if (TMath::Hypot(nsigmaTOFK, nsigmaTPCK) < twotracksconfigs.ConfNsigmaCombined) { - return true; - } else { - return false; - } - } - } - return false; - } - - bool IsPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) - { - //|nsigma_TPC| < 3 for p < 0.5 GeV/c - //|nsigma_combined| < 3 for p > 0.5 - - // using configurables: - // ConfTOFPtMin - momentum value when we start using TOF; set to 1000 if TOF not needed - // ConfNsigmaTPC -> TPC Sigma for momentum < 0.5 - // ConfNsigmaCombined -> TPC and TOF Pion Sigma (combined) for momentum > 0.5 - if (true) { - if (mom < twotracksconfigs.ConfTOFPtMin) { - if (TMath::Abs(nsigmaTPCPi) < twotracksconfigs.ConfNsigmaTPC) { - return true; - } else { - return false; - } + if (twotracksconfigs.IsKaonNsigma == true) { + if (mom < 0.4) { + return TMath::Abs(nsigmaTPCK) < 2; + } else if (mom > 0.4 && mom < 0.45) { + return TMath::Abs(nsigmaTPCK) < 1; + } else if (mom > 0.45 && mom < 0.8) { + return (TMath::Abs(nsigmaTPCK) < 3 && TMath::Abs(nsigmaTOFK) < 2); + } else if (mom > 0.8 && mom < 1.5) { + return (TMath::Abs(nsigmaTPCK) < 3 && TMath::Abs(nsigmaTOFK) < 1.5); } else { - if (TMath::Hypot(nsigmaTOFPi, nsigmaTPCPi) < twotracksconfigs.ConfNsigmaCombined) { - return true; - } else { - return false; - } + return false; } + } else { + return IsNSigma(mom, nsigmaTPCK, nsigmaTOFK); } - return false; } bool IsParticleNSigma(int8_t particle_number, float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) { if (particle_number == 1) { switch (trackonefilter.ConfPDGCodePartOne) { - case 2212: // Proton - case -2212: // Antiproton - return IsProtonNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); + case 2212: // Proton+ + case -2212: // Proton- + return IsNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); break; case 211: // Pion+ case -211: // Pion- - return IsPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); + case 111: // Pion 0 + return IsNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); break; case 321: // Kaon+ case -321: // Kaon- return IsKaonNSigma(mom, nsigmaTPCK, nsigmaTOFK); break; + case 130: // Kaon 0 LONG + case 310: // Kaon 0 SHORT + return IsNSigma(mom, nsigmaTPCK, nsigmaTOFK); + break; default: return false; } return false; } else if (particle_number == 2) { switch (tracktwofilter.ConfPDGCodePartTwo) { - case 2212: // Proton - case -2212: // Antiproton - return IsProtonNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); + case 2212: // Proton+ + case -2212: // Proton- + return IsNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); break; case 211: // Pion+ case -211: // Pion- - return IsPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); + case 111: // Pion 0 + return IsNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); break; case 321: // Kaon+ case -321: // Kaon- return IsKaonNSigma(mom, nsigmaTPCK, nsigmaTOFK); break; - default: + case 130: // Kaon 0 LONG + case 310: // Kaon 0 SHORT + return IsNSigma(mom, nsigmaTPCK, nsigmaTOFK); + break; return false; } return false; @@ -411,58 +374,60 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { template void fillCollision(CollisionType col) { - MixQaRegistry.fill(HIST("MixingQA/hSECollisionBins"), colBinning.getBin({col.posZ(), col.multNtr()})); + MixQaRegistry.fill(HIST("MixingQA/hSECollisionBins"), colBinning.getBin({col.posZ(), col.multV0M()})); eventHisto.fillQA(col); } /// This function processes the same event and takes care of all the histogramming /// \todo the trivial loops over the tracks should be factored out since they will be common to all combinations of T-T, T-V0, V0-V0, ... - /// @tparam PartitionType - /// @tparam PartType - /// @tparam isMC: enables Monte Carlo truth specific histograms - /// @param groupPartsOne partition for the first particle passed by the process function - /// @param groupPartsTwo partition for the second particle passed by the process function - /// @param parts femtoUniverseParticles table (in case of Monte Carlo joined with FemtoUniverseMCLabels) - /// @param magFieldTesla magnetic field of the collision - /// @param multCol multiplicity of the collision + /// \tparam PartitionType + /// \tparam PartType + /// \tparam isMC: enables Monte Carlo truth specific histograms + /// \param groupPartsOne partition for the first particle passed by the process function + /// \param groupPartsTwo partition for the second particle passed by the process function + /// \param parts femtoUniverseParticles table (in case of Monte Carlo joined with FemtoUniverseMCLabels) + /// \param magFieldTesla magnetic field of the collision + /// \param multCol multiplicity of the collision + /// \param pairType describes charge of correlation pair (plus-minus (1), plus-plus (2), minus-minus (3)) + /// \param fillQA enables filling of QA histograms template - void doSameEvent(PartitionType groupPartsOne, PartitionType groupPartsTwo, PartType parts, float magFieldTesla, int multCol, int ContType, bool fillQA) + void doSameEvent(PartitionType groupPartsOne, PartitionType groupPartsTwo, PartType parts, float magFieldTesla, int multCol, int pairType, bool fillQA) { /// Histogramming same event - if ((ContType == 1 || ContType == 2) && fillQA) { + if ((pairType == 1 || pairType == 2) && fillQA) { for (auto& part : groupPartsOne) { - if (!IsParticleNSigma((int8_t)1, part.pt(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { + if (!IsParticleNSigma((int8_t)1, part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { continue; } trackHistoPartOne.fillQA(part); } } - if ((ContType == 1 || ContType == 3) && fillQA) { + if ((pairType == 1 || pairType == 3) && fillQA) { for (auto& part : groupPartsTwo) { - if (!IsParticleNSigma((int8_t)2, part.pt(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { + if (!IsParticleNSigma((int8_t)2, part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { continue; } trackHistoPartTwo.fillQA(part); } } - if (ContType == 1) { + if (pairType == 1) { /// Now build the combinations for non-identical particle pairs for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { - if (!IsParticleNSigma((int8_t)1, p1.pt(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { + if (!IsParticleNSigma((int8_t)1, p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { continue; } - if (!IsParticleNSigma((int8_t)2, p2.pt(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon))) { + if (!IsParticleNSigma((int8_t)2, p2.p(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon))) { continue; } if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::same)) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } } @@ -483,16 +448,16 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { /// Now build the combinations for identical particles pairs for (auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsOne, groupPartsOne))) { - if (!IsParticleNSigma((int8_t)2, p1.pt(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { + if (!IsParticleNSigma((int8_t)2, p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { continue; } - if (!IsParticleNSigma((int8_t)2, p2.pt(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon))) { + if (!IsParticleNSigma((int8_t)2, p2.p(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon))) { continue; } if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::same)) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } } @@ -502,24 +467,44 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { continue; } - switch (ContType) { + switch (pairType) { case 2: { - float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass1); - float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass1); + if (IsPairIdentical == true) { + float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass1); + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass1); + + sameEventContPP.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); + if (cfgProcessMultBins) + sameEventMultContPP.fill(kstar, multCol, kT); + } else { + float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass2); + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + + sameEventContPP.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); + if (cfgProcessMultBins) + sameEventMultContPP.fill(kstar, multCol, kT); + } - sameEventContPP.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); - if (cfgProcessMultBins) - sameEventMultContPP.fill(kstar, multCol, kT); break; } case 3: { - float kstar = FemtoUniverseMath::getkstar(p1, mass2, p2, mass2); - float kT = FemtoUniverseMath::getkT(p1, mass2, p2, mass2); + if (IsPairIdentical == true) { + float kstar = FemtoUniverseMath::getkstar(p1, mass2, p2, mass2); + float kT = FemtoUniverseMath::getkT(p1, mass2, p2, mass2); + + sameEventContMM.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); + if (cfgProcessMultBins) + sameEventMultContMM.fill(kstar, multCol, kT); + } else { + float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass2); + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + + sameEventContMM.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); + if (cfgProcessMultBins) + sameEventMultContMM.fill(kstar, multCol, kT); + } - sameEventContMM.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); - if (cfgProcessMultBins) - sameEventMultContMM.fill(kstar, multCol, kT); break; } default: @@ -532,7 +517,7 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { /// process function for to call doSameEvent with Data /// \param col subscribe to the collision table (Data) /// \param parts subscribe to the femtoUniverseParticleTable - void processSameEvent(soa::Filtered::iterator& col, + void processSameEvent(soa::Filtered::iterator& col, FilteredFemtoFullParticles& parts) { fillCollision(col); @@ -544,13 +529,13 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { bool fillQA = true; if (cfgProcessPM) { - doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multNtr(), 1, fillQA); + doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multV0M(), 1, fillQA); fillQA = false; } if (cfgProcessPP) - doSameEvent(thegroupPartsOne, thegroupPartsOne, parts, col.magField(), col.multNtr(), 2, fillQA); + doSameEvent(thegroupPartsOne, thegroupPartsOne, parts, col.magField(), col.multV0M(), 2, fillQA); if (cfgProcessMM) - doSameEvent(thegroupPartsTwo, thegroupPartsTwo, parts, col.magField(), col.multNtr(), 3, fillQA); + doSameEvent(thegroupPartsTwo, thegroupPartsTwo, parts, col.magField(), col.multV0M(), 3, fillQA); } PROCESS_SWITCH(femtoUniversePairTaskTrackTrackMultKtExtended, processSameEvent, "Enable processing same event", true); @@ -558,9 +543,9 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { /// \param col subscribe to the collision table (Monte Carlo Reconstructed reconstructed) /// \param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth /// \param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table - void processSameEventMC(o2::aod::FDCollision& col, + void processSameEventMC(o2::aod::FdCollision& col, soa::Join& parts, - o2::aod::FDMCParticles&) + o2::aod::FdMCParticles&) { fillCollision(col); @@ -569,13 +554,13 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { bool fillQA = true; if (cfgProcessPM) { - doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multNtr(), 1, fillQA); + doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multV0M(), 1, fillQA); fillQA = false; } if (cfgProcessPP) - doSameEvent(thegroupPartsOne, thegroupPartsOne, parts, col.magField(), col.multNtr(), 2, fillQA); + doSameEvent(thegroupPartsOne, thegroupPartsOne, parts, col.magField(), col.multV0M(), 2, fillQA); if (cfgProcessMM) - doSameEvent(thegroupPartsTwo, thegroupPartsTwo, parts, col.magField(), col.multNtr(), 3, fillQA); + doSameEvent(thegroupPartsTwo, thegroupPartsTwo, parts, col.magField(), col.multV0M(), 3, fillQA); } PROCESS_SWITCH(femtoUniversePairTaskTrackTrackMultKtExtended, processSameEventMC, "Enable processing same event for Monte Carlo", false); @@ -589,50 +574,75 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { /// \param parts femtoUniverseParticles table (in case of Monte Carlo joined with FemtoUniverseMCLabels) /// \param magFieldTesla magnetic field of the collision /// \param multCol multiplicity of the collision + /// \param pairType describes charge of correlation pair (plus-minus (1), plus-plus (2), minus-minus (3)) template - void doMixedEvent(PartitionType groupPartsOne, PartitionType groupPartsTwo, PartType parts, float magFieldTesla, int multCol, int ContType) + void doMixedEvent(PartitionType groupPartsOne, PartitionType groupPartsTwo, PartType parts, float magFieldTesla, int multCol, int pairType) { for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { - if (!IsParticleNSigma((int8_t)2, p1.pt(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { + if (!IsParticleNSigma((int8_t)2, p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { continue; } - if (!IsParticleNSigma((int8_t)2, p2.pt(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon))) { + if (!IsParticleNSigma((int8_t)2, p2.p(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon))) { continue; } if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::mixed)) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::mixed)) { continue; } } - switch (ContType) { + switch (pairType) { case 1: { float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass2); float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + mixedEventCont.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); if (cfgProcessMultBins) mixedEventMultCont.fill(kstar, multCol, kT); + break; } case 2: { - float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass1); - float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass1); - mixedEventContPP.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); - if (cfgProcessMultBins) - mixedEventMultContPP.fill(kstar, multCol, kT); + if (IsPairIdentical == true) { + float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass1); + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass1); + + mixedEventContPP.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); + if (cfgProcessMultBins) + mixedEventMultContPP.fill(kstar, multCol, kT); + } else { + float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass2); + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + + mixedEventContPP.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); + if (cfgProcessMultBins) + mixedEventMultContPP.fill(kstar, multCol, kT); + } + break; } case 3: { - float kstar = FemtoUniverseMath::getkstar(p1, mass2, p2, mass2); - float kT = FemtoUniverseMath::getkT(p1, mass2, p2, mass2); - mixedEventContMM.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); - if (cfgProcessMultBins) - mixedEventMultContMM.fill(kstar, multCol, kT); + if (IsPairIdentical == true) { + float kstar = FemtoUniverseMath::getkstar(p1, mass2, p2, mass2); + float kT = FemtoUniverseMath::getkT(p1, mass2, p2, mass2); + + mixedEventContMM.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); + if (cfgProcessMultBins) + mixedEventMultContMM.fill(kstar, multCol, kT); + } else { + float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass2); + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + + mixedEventContMM.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); + if (cfgProcessMultBins) + mixedEventMultContMM.fill(kstar, multCol, kT); + } + break; } default: @@ -642,14 +652,14 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { } /// process function for to call doMixedEvent with Data - /// @param cols subscribe to the collisions table (Data) - /// @param parts subscribe to the femtoUniverseParticleTable - void processMixedEvent(soa::Filtered& cols, + /// \param cols subscribe to the collisions table (Data) + /// \param parts subscribe to the femtoUniverseParticleTable + void processMixedEvent(soa::Filtered& cols, FilteredFemtoFullParticles& parts) { for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { - const int multiplicityCol = collision1.multNtr(); + const int multiplicityCol = collision1.multV0M(); MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); const auto& magFieldTesla1 = collision1.magField(); @@ -679,16 +689,16 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { PROCESS_SWITCH(femtoUniversePairTaskTrackTrackMultKtExtended, processMixedEvent, "Enable processing mixed events", true); /// brief process function for to call doMixedEvent with Monte Carlo - /// @param cols subscribe to the collisions table (Monte Carlo Reconstructed reconstructed) - /// @param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth - /// @param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table - void processMixedEventMC(o2::aod::FDCollisions& cols, + /// \param cols subscribe to the collisions table (Monte Carlo Reconstructed reconstructed) + /// \param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth + /// \param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table + void processMixedEventMC(o2::aod::FdCollisions& cols, soa::Join& parts, - o2::aod::FDMCParticles&) + o2::aod::FdMCParticles&) { for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { - const int multiplicityCol = collision1.multNtr(); + const int multiplicityCol = collision1.multV0M(); MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); const auto& magFieldTesla1 = collision1.magField(); diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackSpherHarMultKtExtended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackSpherHarMultKtExtended.cxx new file mode 100644 index 00000000000..0c5a91e1115 --- /dev/null +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackSpherHarMultKtExtended.cxx @@ -0,0 +1,888 @@ +// Copyright 2019-2022 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 femtoUniversePairTaskTrackTrackSpherHarMultKtExtended.cxx +/// \brief Tasks that reads the track tables used for the pairing and builds pairs of two tracks and compute relative pair-momentum in three dimesnions +/// \remark This file is inherited from ~/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrack3DMultKtExtended.cxx on 17/06/2024 +/// \author Pritam Chakraborty, WUT Warsaw, pritam.chakraborty@pw.edu.pl + +#include +#include +#include "TRandom2.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "ReconstructionDataFormats/PID.h" +#include "Common/DataModel/PIDResponse.h" + +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseSHContainer.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairSHCentMultKt.h" + +using namespace o2; +using namespace o2::analysis::femto_universe; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +namespace +{ +static constexpr int nPart = 2; +static constexpr int nCuts = 5; +static const std::vector partNames{"PartOne", "PartTwo"}; +static const std::vector cutNames{"MaxPt", "PIDthr", "nSigmaTPC", "nSigmaTPCTOF", "MaxP"}; +static const float cutsTable[nPart][nCuts]{ + {4.05f, 1.f, 3.f, 3.f, 100.f}, + {4.05f, 1.f, 3.f, 3.f, 100.f}}; +} // namespace + +struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { + + Service pdg; + + /// Particle selection part + + /// Table for both particles + struct : o2::framework::ConfigurableGroup { + Configurable ConfNsigmaCombined{"ConfNsigmaCombined", 3.0f, "TPC and TOF Pion Sigma (combined) for momentum > ConfTOFPtMin"}; + Configurable ConfNsigmaTPC{"ConfNsigmaTPC", 3.0f, "TPC Pion Sigma for momentum < ConfTOFPtMin"}; + Configurable ConfTOFPtMin{"ConfTOFPtMin", 0.5f, "Min. Pt for which TOF is required for PID."}; + Configurable ConfEtaMax{"ConfEtaMax", 0.8f, "Higher limit for |Eta| (the same for both particles)"}; + + Configurable> ConfCutTable{"ConfCutTable", {cutsTable[0], nPart, nCuts, partNames, cutNames}, "Particle selections"}; + Configurable ConfNspecies{"ConfNspecies", 2, "Number of particle spieces with PID info"}; + Configurable ConfIsMC{"ConfIsMC", false, "Enable additional Histogramms in the case of a MonteCarlo Run"}; + Configurable> ConfTrkPIDnSigmaMax{"ConfTrkPIDnSigmaMax", std::vector{4.f, 3.f, 2.f}, "This configurable needs to be the same as the one used in the producer task"}; + Configurable ConfUse3D{"ConfUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; + } twotracksconfigs; + + using FemtoFullParticles = soa::Join; + // Filters for selecting particles (both p1 and p2) + Filter trackAdditionalfilter = (nabs(aod::femtouniverseparticle::eta) < twotracksconfigs.ConfEtaMax); // example filtering on configurable + using FilteredFemtoFullParticles = soa::Filtered; + // using FilteredFemtoFullParticles = FemtoFullParticles; //if no filtering is applied uncomment this option + + SliceCache cache; + Preslice perCol = aod::femtouniverseparticle::fdCollisionId; + + /// Particle 1 + struct : o2::framework::ConfigurableGroup { + Configurable ConfPDGCodePartOne{"ConfPDGCodePartOne", 211, "Particle 1 - PDG code"}; + // Configurable ConfCutPartOne{"ConfCutPartOne", 5542474, "Particle 1 - Selection bit from cutCulator"}; + Configurable ConfPIDPartOne{"ConfPIDPartOne", 2, "Particle 1 - Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector>int>> + Configurable ConfPtLowPart1{"ConfPtLowPart1", 0.14, "Lower limit for Pt for the first particle"}; + Configurable ConfPtHighPart1{"ConfPtHighPart1", 1.5, "Higher limit for Pt for the first particle"}; + Configurable ConfChargePart1{"ConfChargePart1", 1, "Particle 1 sign"}; + } trackonefilter; + + /// Partition for particle 1 + Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == trackonefilter.ConfChargePart1 && aod::femtouniverseparticle::pt < trackonefilter.ConfPtHighPart1 && aod::femtouniverseparticle::pt > trackonefilter.ConfPtLowPart1; + + Partition> partsOneMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == trackonefilter.ConfChargePart1 && aod::femtouniverseparticle::pt < trackonefilter.ConfPtHighPart1 && aod::femtouniverseparticle::pt > trackonefilter.ConfPtLowPart1; + // + + /// Histogramming for particle 1 + FemtoUniverseParticleHisto trackHistoPartOne; + + /// Particle 2 + struct : o2::framework::ConfigurableGroup { + Configurable ConfPDGCodePartTwo{"ConfPDGCodePartTwo", 211, "Particle 2 - PDG code"}; + // Configurable ConfCutPartTwo{"ConfCutPartTwo", 5542474, "Particle 2 - Selection bit"}; + Configurable ConfPIDPartTwo{"ConfPIDPartTwo", 2, "Particle 2 - Read from cutCulator"}; // we also need the possibility to specify whether the bit is true/false ->std>>vector> + + Configurable ConfPtLowPart2{"ConfPtLowPart2", 0.14, "Lower limit for Pt for the second particle"}; + Configurable ConfPtHighPart2{"ConfPtHighPart2", 1.5, "Higher limit for Pt for the second particle"}; + Configurable ConfChargePart2{"ConfChargePart2", -1, "Particle 2 sign"}; + } tracktwofilter; + + /// Partition for particle 2 + Partition partsTwo = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == tracktwofilter.ConfChargePart2) && aod::femtouniverseparticle::pt < tracktwofilter.ConfPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.ConfPtLowPart2; + + Partition> partsTwoMC = aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack) && (aod::femtouniverseparticle::sign == tracktwofilter.ConfChargePart2) && aod::femtouniverseparticle::pt < tracktwofilter.ConfPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.ConfPtLowPart2; + + /// Histogramming for particle 2 + FemtoUniverseParticleHisto trackHistoPartTwo; + + /// Histogramming for Event + FemtoUniverseEventHisto eventHisto; + + /// The configurables need to be passed to an std::vector + int vPIDPartOne, vPIDPartTwo; + std::vector kNsigma; + + /// Event part + Configurable ConfV0MLow{"ConfV0MLow", 0.0, "Lower limit for V0M multiplicity"}; + Configurable ConfV0MHigh{"ConfV0MHigh", 25000.0, "Upper limit for V0M multiplicity"}; + Configurable ConfTPCOccupancyLow{"ConfTPCOccupancyLow", 0, "Lower limit for TPC occupancy"}; + Configurable ConfTPCOccupancyHigh{"ConfTPCOccupancyHigh", 500, "Higher limit for TPC occupancy"}; + Configurable ConfIntRateLow{"ConfIntRateLow", 0.0, "Lower limit for interaction rate"}; + Configurable ConfIntRateHigh{"ConfIntRateHigh", 10000.0, "Higher limit for interaction rate"}; + Configurable ConfIsCent{"ConfIsCent", true, "Condition to choose centrality of multiplicity for mixing"}; + + Filter collfilterFDtable = (o2::aod::femtouniversecollision::multV0M > ConfV0MLow) && (o2::aod::femtouniversecollision::multV0M < ConfV0MHigh); + Filter collfilterFDExttable = (o2::aod::femtouniversecollision::interactionRate > ConfIntRateLow) && (o2::aod::femtouniversecollision::interactionRate < ConfIntRateHigh) && + (o2::aod::femtouniversecollision::occupancy >= ConfTPCOccupancyLow) && (o2::aod::femtouniversecollision::occupancy < ConfTPCOccupancyHigh); + using FilteredFDCollisions = soa::Filtered>; + using FilteredFDCollision = FilteredFDCollisions::iterator; + // Filter trackAdditionalfilter = (nabs(aod::femtouniverseparticle::eta) < twotracksconfigs.ConfEtaMax); // example filtering on configurable + + /// Particle part + ConfigurableAxis ConfTempFitVarBins{"ConfDTempFitVarBins", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis ConfTempFitVarpTBins{"ConfTempFitVarpTBins", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; + + /// Correlation part + ConfigurableAxis ConfMultBins{"ConfMultBins", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity or centrality"}; // \todo to be obtained from the hash task + ConfigurableAxis ConfMultKstarBins{"ConfMultKstarBins", {VARIABLE_WIDTH, 0.0f, 200.0f}, "Bins for kstar analysis in multiplicity or centrality bins (10 is maximum)"}; + ConfigurableAxis ConfKtKstarBins{"ConfKtKstarBins", {VARIABLE_WIDTH, 0.1f, 0.2f, 0.3f, 0.4f}, "Bins for kstar analysis in kT bins"}; + ConfigurableAxis ConfVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + + ConfigurableAxis ConfmTBins3D{"ConfmTBins3D", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + ConfigurableAxis ConfmultBins3D{"ConfmultBins3D", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + + ColumnBinningPolicy colBinningCent{{ConfVtxBins, ConfMultBins}, true}; + ColumnBinningPolicy colBinningNtr{{ConfVtxBins, ConfMultBins}, true}; + + ConfigurableAxis ConfkstarBins{"ConfkstarBins", {60, 0.0, 0.3}, "binning kstar"}; + ConfigurableAxis ConfkTBins{"ConfkTBins", {150, 0., 9.}, "binning kT"}; + ConfigurableAxis ConfmTBins{"ConfmTBins", {225, 0., 7.5}, "binning mT"}; + Configurable ConfIsIden{"ConfIsIden", true, "Choosing identical or non-identical pairs"}; + Configurable ConfIsLCMS{"ConfIsLCMS", true, "Choosing LCMS or PRF"}; + Configurable ConfNEventsMix{"ConfNEventsMix", 5, "Number of events for mixing"}; + Configurable ConfLMax{"ConfLMax", 2, "Maximum value of l"}; + Configurable ConfIsCPR{"ConfIsCPR", true, "Close Pair Rejection"}; + Configurable ConfCPRPlotPerRadii{"ConfCPRPlotPerRadii", false, "Plot CPR per radii"}; + Configurable ConfCPRdeltaPhiCutMax{"ConfCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; + Configurable ConfCPRdeltaPhiCutMin{"ConfCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; + Configurable ConfCPRdeltaEtaCutMax{"ConfCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; + Configurable ConfCPRdeltaEtaCutMin{"ConfCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; + Configurable ConfCPRChosenRadii{"ConfCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; + Configurable cfgProcessPM{"cfgProcessPM", false, "Process particles of the opposite charge"}; + Configurable cfgProcessPP{"cfgProcessPP", true, "Process particles of the same, positice charge"}; + Configurable cfgProcessMM{"cfgProcessMM", true, "Process particles of the same, positice charge"}; + Configurable cfgProcessMultBins{"cfgProcessMultBins", true, "Process kstar histograms in multiplicity bins (in multiplicity bins)"}; + Configurable cfgProcessKtBins{"cfgProcessKtBins", true, "Process kstar histograms in kT bins (if cfgProcessMultBins is set false, this will not be processed regardless this Configurable state)"}; + Configurable cfgProcessKtMt3DCF{"cfgProcessKtMt3DCF", false, "Process 3D histograms in kT and Mult bins"}; + + FemtoUniverseSHContainer sameEventCont; + FemtoUniverseSHContainer mixedEventCont; + + FemtoUniverseSHContainer sameEventContPP; + FemtoUniverseSHContainer mixedEventContPP; + + FemtoUniverseSHContainer sameEventContMM; + FemtoUniverseSHContainer mixedEventContMM; + + FemtoUniversePairCleaner pairCleaner; + FemtoUniverseDetaDphiStar pairCloseRejection; + FemtoUniverseTrackSelection trackCuts; + + PairSHCentMultKt sameEventMultCont; + PairSHCentMultKt mixedEventMultCont; + + PairSHCentMultKt sameEventMultContPP; + PairSHCentMultKt mixedEventMultContPP; + + PairSHCentMultKt sameEventMultContMM; + PairSHCentMultKt mixedEventMultContMM; + + float mass1 = -1; + float mass2 = -1; + + /// Histogram output + HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry resultRegistry{"Correlations", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry resultRegistryPM{"CorrelationsPM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry resultRegistryPP{"CorrelationsPP", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry resultRegistryMM{"CorrelationsMM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry MixQaRegistry{"MixQaRegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + HistogramRegistry SameMultRegistryPM{"SameMultRegistryPM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry MixedMultRegistryPM{"MixedMultRegistryPM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + HistogramRegistry SameMultRegistryPP{"SameMultRegistryPP", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry MixedMultRegistryPP{"MixedMultRegistryPP", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + HistogramRegistry SameMultRegistryMM{"SameMultRegistryMM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry MixedMultRegistryMM{"MixedMultRegistryMM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + TRandom2* randgen; + + // PID for protons + bool IsProtonNSigma(float mom, float nsigmaTPCPr, float nsigmaTOFPr) // previous version from: https://github.com/alisw/AliPhysics/blob/master/PWGCF/FEMTOSCOPY/AliFemtoUser/AliFemtoMJTrackCut.cxx + { + //|nsigma_TPC| < 3 for p < 0.5 GeV/c + //|nsigma_combined| < 3 for p > 0.5 + + // using configurables: + // ConfTOFPtMin - momentum value when we start using TOF; set to 1000 if TOF not needed + // ConfNsigmaTPC -> TPC Sigma for momentum < 0.5 + // ConfNsigmaCombined -> TPC and TOF Sigma (combined) for momentum > 0.5 + + if (mom < twotracksconfigs.ConfTOFPtMin) { + if (std::abs(nsigmaTPCPr) < twotracksconfigs.ConfNsigmaTPC) { + return true; + } else { + return false; + } + } else { + if (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < twotracksconfigs.ConfNsigmaCombined) { + return true; + } else { + return false; + } + } + return false; + } + + bool IsKaonNSigma(float mom, float nsigmaTPCK, float nsigmaTOFK) + { + if (mom < 0.3) { // 0.0-0.3 + if (std::abs(nsigmaTPCK) < 3.0) { + return true; + } else { + return false; + } + } else if (mom < 0.45) { // 0.30 - 0.45 + if (std::abs(nsigmaTPCK) < 2.0) { + return true; + } else { + return false; + } + } else if (mom < 0.55) { // 0.45-0.55 + if (std::abs(nsigmaTPCK) < 1.0) { + return true; + } else { + return false; + } + } else if (mom < 1.5) { // 0.55-1.5 (now we use TPC and TOF) + if ((std::abs(nsigmaTOFK) < 3.0) && (std::abs(nsigmaTPCK) < 3.0)) { + { + return true; + } + } else { + return false; + } + } else if (mom > 1.5) { // 1.5 - + if ((std::abs(nsigmaTOFK) < 2.0) && (std::abs(nsigmaTPCK) < 3.0)) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + bool IsPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) + { + //|nsigma_TPC| < 3 for p < 0.5 GeV/c + //|nsigma_combined| < 3 for p > 0.5 + + // using configurables: + // ConfTOFPtMin - momentum value when we start using TOF; set to 1000 if TOF not needed + // ConfNsigmaTPC -> TPC Sigma for momentum < 0.5 + // ConfNsigmaCombined -> TPC and TOF Pion Sigma (combined) for momentum > 0.5 + if (true) { + if (mom < twotracksconfigs.ConfTOFPtMin) { + if (std::abs(nsigmaTPCPi) < twotracksconfigs.ConfNsigmaTPC) { + return true; + } else { + return false; + } + } else { + if (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < twotracksconfigs.ConfNsigmaCombined) { + return true; + } else { + return false; + } + } + } + return false; + } + + bool IsParticleNSigma(int8_t particle_number, float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) + { + if (particle_number == 1) { + switch (trackonefilter.ConfPDGCodePartOne) { + case 2212: // Proton + case -2212: // Antiproton + return IsProtonNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); + break; + case 211: // Pion+ + case -211: // Pion- + return IsPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); + break; + case 321: // Kaon+ + case -321: // Kaon- + return IsKaonNSigma(mom, nsigmaTPCK, nsigmaTOFK); + break; + default: + return false; + } + return false; + } else if (particle_number == 2) { + switch (tracktwofilter.ConfPDGCodePartTwo) { + case 2212: // Proton + case -2212: // Antiproton + return IsProtonNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); + break; + case 211: // Pion+ + case -211: // Pion- + return IsPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); + break; + case 321: // Kaon+ + case -321: // Kaon- + return IsKaonNSigma(mom, nsigmaTPCK, nsigmaTOFK); + break; + default: + return false; + } + return false; + } else { + LOGF(fatal, "Wrong number of particle chosen! It should be 1 or 2. It is -> %d", particle_number); + } + return false; + } + + void init(InitContext&) + { + eventHisto.init(&qaRegistry); + trackHistoPartOne.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarBins, twotracksconfigs.ConfIsMC, trackonefilter.ConfPDGCodePartOne, true); + + trackHistoPartTwo.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarBins, twotracksconfigs.ConfIsMC, tracktwofilter.ConfPDGCodePartTwo, true); + + MixQaRegistry.add("MixingQA/hSECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); + MixQaRegistry.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); + + mass1 = pdg->Mass(trackonefilter.ConfPDGCodePartOne); + mass2 = pdg->Mass(tracktwofilter.ConfPDGCodePartTwo); + + if (cfgProcessPM) { + if (!cfgProcessKtMt3DCF) { + sameEventCont.init(&resultRegistryPM, ConfkstarBins, ConfLMax); + mixedEventCont.init(&resultRegistryPM, ConfkstarBins, ConfLMax); + sameEventCont.setPDGCodes(trackonefilter.ConfPDGCodePartOne, tracktwofilter.ConfPDGCodePartTwo); + mixedEventCont.setPDGCodes(trackonefilter.ConfPDGCodePartOne, tracktwofilter.ConfPDGCodePartTwo); + } else { + sameEventMultCont.init(&SameMultRegistryPM, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, ConfLMax); + mixedEventMultCont.init(&MixedMultRegistryPM, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, ConfLMax); + } + } + + if (cfgProcessPP) { + if (!cfgProcessKtMt3DCF) { + sameEventContPP.init(&resultRegistryPP, ConfkstarBins, ConfLMax); + mixedEventContPP.init(&resultRegistryPP, ConfkstarBins, ConfLMax); + sameEventContPP.setPDGCodes(trackonefilter.ConfPDGCodePartOne, tracktwofilter.ConfPDGCodePartTwo); + mixedEventContPP.setPDGCodes(trackonefilter.ConfPDGCodePartOne, tracktwofilter.ConfPDGCodePartTwo); + } else { + sameEventMultContPP.init(&SameMultRegistryPP, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, ConfLMax); + mixedEventMultContPP.init(&MixedMultRegistryPP, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, ConfLMax); + } + } + + if (cfgProcessMM) { + if (!cfgProcessKtMt3DCF) { + sameEventContMM.init(&resultRegistryMM, ConfkstarBins, ConfLMax); + mixedEventContMM.init(&resultRegistryMM, ConfkstarBins, ConfLMax); + sameEventContMM.setPDGCodes(trackonefilter.ConfPDGCodePartOne, tracktwofilter.ConfPDGCodePartTwo); + mixedEventContMM.setPDGCodes(trackonefilter.ConfPDGCodePartOne, tracktwofilter.ConfPDGCodePartTwo); + } else { + sameEventMultContMM.init(&SameMultRegistryMM, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, ConfLMax); + mixedEventMultContMM.init(&MixedMultRegistryMM, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, ConfLMax); + } + } + + pairCleaner.init(&qaRegistry); + if (ConfIsCPR.value) { + pairCloseRejection.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiCutMin.value, ConfCPRdeltaPhiCutMax.value, ConfCPRdeltaEtaCutMin.value, ConfCPRdeltaEtaCutMax.value, ConfCPRChosenRadii.value, ConfCPRPlotPerRadii.value); + } + + vPIDPartOne = trackonefilter.ConfPIDPartOne.value; + vPIDPartTwo = tracktwofilter.ConfPIDPartTwo.value; + kNsigma = twotracksconfigs.ConfTrkPIDnSigmaMax.value; + } + + template + void fillCollision(CollisionType col, bool IsCent) + { + if (IsCent) { + MixQaRegistry.fill(HIST("MixingQA/hSECollisionBins"), colBinningCent.getBin({col.posZ(), col.multV0M()})); + } else { + MixQaRegistry.fill(HIST("MixingQA/hSECollisionBins"), colBinningNtr.getBin({col.posZ(), col.multNtr()})); + } + eventHisto.fillQA(col); + } + + /// This function processes the same event and takes care of all the histogramming + /// \todo the trivial loops over the tracks should be factored out since they will be common to all combinations of T-T, T-V0, V0-V0, ... + /// @tparam PartitionType + /// @tparam PartType + /// @tparam isMC: enables Monte Carlo truth specific histograms + /// @param groupPartsOne partition for the first particle passed by the process function + /// @param groupPartsTwo partition for the second particle passed by the process function + /// @param parts femtoUniverseParticles table (in case of Monte Carlo joined with FemtoUniverseMCLabels) + /// @param magFieldTesla magnetic field of the collision + /// @param multCol multiplicity of the collision + template + void doSameEvent(PartitionType groupPartsOne, PartitionType groupPartsTwo, PartType parts, float magFieldTesla, int multCol, int ContType, bool fillQA) + { + + /// Histogramming same event + if ((ContType == 1 || ContType == 2) && fillQA) { + for (const auto& part : groupPartsOne) { + if (!IsParticleNSigma((int8_t)1, part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { + continue; + } + trackHistoPartOne.fillQA(part); + } + } + + if ((ContType == 1 || ContType == 3) && fillQA) { + for (const auto& part : groupPartsTwo) { + if (!IsParticleNSigma((int8_t)2, part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { + continue; + } + trackHistoPartTwo.fillQA(part); + } + } + + if (ContType == 1) { + + /// Now build the combinations for non-identical particle pairs + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + + if (!IsParticleNSigma((int8_t)1, p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { + continue; + } + + if (!IsParticleNSigma((int8_t)2, p2.p(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon))) { + continue; + } + + if (ConfIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { + continue; + } + } + + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + sameEventMultCont.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } + } else { + for (const auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsOne, groupPartsOne))) { + + if (!IsParticleNSigma((int8_t)2, p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { + continue; + } + + if (!IsParticleNSigma((int8_t)2, p2.p(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon))) { + continue; + } + + if (ConfIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { + continue; + } + } + + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + double rand; + rand = randgen->Rndm(); + + switch (ContType) { + case 2: { + if (rand > 0.5) { + sameEventMultContPP.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } else if (rand <= 0.5) { + sameEventMultContPP.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } + break; + } + + case 3: { + if (rand > 0.5) { + sameEventMultContMM.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } else if (rand <= 0.5) { + sameEventMultContMM.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } + break; + } + default: + break; + } + } + } + } + + /// process function for to call doSameEvent with Data + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoUniverseParticleTable + void processSameEvent(FilteredFDCollision const& col, + FilteredFemtoFullParticles const& parts) + { + fillCollision(col, ConfIsCent); + + auto thegroupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegroupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + bool fillQA = true; + randgen = new TRandom2(0); + + if (ConfIsCent) { + if (cfgProcessPM) { + doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multV0M(), 1, fillQA); + } + if (cfgProcessPP) { + doSameEvent(thegroupPartsOne, thegroupPartsOne, parts, col.magField(), col.multV0M(), 2, fillQA); + } + if (cfgProcessMM) { + doSameEvent(thegroupPartsTwo, thegroupPartsTwo, parts, col.magField(), col.multV0M(), 3, fillQA); + } + } else { + if (cfgProcessPM) { + doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multNtr(), 1, fillQA); + } + if (cfgProcessPP) { + doSameEvent(thegroupPartsOne, thegroupPartsOne, parts, col.magField(), col.multNtr(), 2, fillQA); + } + if (cfgProcessMM) { + doSameEvent(thegroupPartsTwo, thegroupPartsTwo, parts, col.magField(), col.multNtr(), 3, fillQA); + } + } + delete randgen; + } + PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processSameEvent, "Enable processing same event", true); + + /// process function for to call doSameEvent with Monte Carlo + /// \param col subscribe to the collision table (Monte Carlo Reconstructed reconstructed) + /// \param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth + /// \param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table + void processSameEventMC(o2::aod::FdCollision const& col, + soa::Join const& parts, + o2::aod::FdMCParticles const&) + { + fillCollision(col, ConfIsCent); + + auto thegroupPartsOne = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegroupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + bool fillQA = true; + randgen = new TRandom2(0); + + if (ConfIsCent) { + if (cfgProcessPM) { + doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multV0M(), 1, fillQA); + } + if (cfgProcessPP) { + doSameEvent(thegroupPartsOne, thegroupPartsOne, parts, col.magField(), col.multV0M(), 2, fillQA); + } + if (cfgProcessMM) { + doSameEvent(thegroupPartsTwo, thegroupPartsTwo, parts, col.magField(), col.multV0M(), 3, fillQA); + } + } else { + if (cfgProcessPM) { + doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multNtr(), 1, fillQA); + } + if (cfgProcessPP) { + doSameEvent(thegroupPartsOne, thegroupPartsOne, parts, col.magField(), col.multNtr(), 2, fillQA); + } + if (cfgProcessMM) { + doSameEvent(thegroupPartsTwo, thegroupPartsTwo, parts, col.magField(), col.multNtr(), 3, fillQA); + } + } + delete randgen; + } + PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processSameEventMC, "Enable processing same event for Monte Carlo", false); + + /// This function processes the mixed event + /// \todo the trivial loops over the collisions and tracks should be factored out since they will be common to all combinations of T-T, T-V0, V0-V0, ... + /// \tparam PartitionType + /// \tparam PartType + /// \tparam isMC: enables Monte Carlo truth specific histograms + /// \param groupPartsOne partition for the first particle passed by the process function + /// \param groupPartsTwo partition for the second particle passed by the process function + /// \param parts femtoUniverseParticles table (in case of Monte Carlo joined with FemtoUniverseMCLabels) + /// \param magFieldTesla magnetic field of the collision + /// \param multCol multiplicity of the collision + template + void doMixedEvent(PartitionType groupPartsOne, PartitionType groupPartsTwo, PartType parts, float magFieldTesla, int multCol, int ContType) + { + + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + + if (!IsParticleNSigma((int8_t)2, p1.p(), trackCuts.getNsigmaTPC(p1, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p1, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p1, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p1, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p1, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p1, o2::track::PID::Kaon))) { + continue; + } + + if (!IsParticleNSigma((int8_t)2, p2.p(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Proton), trackCuts.getNsigmaTOF(p2, o2::track::PID::Proton), trackCuts.getNsigmaTPC(p2, o2::track::PID::Pion), trackCuts.getNsigmaTOF(p2, o2::track::PID::Pion), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon))) { + continue; + } + + if (ConfIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::mixed)) { + continue; + } + } + + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + double rand; + rand = randgen->Rndm(); + + switch (ContType) { + case 1: { + if (rand > 0.5) { + mixedEventMultCont.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } else { + mixedEventMultCont.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } + break; + } + + case 2: { + if (rand > 0.5) { + mixedEventMultContPP.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } else { + mixedEventMultContPP.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } + break; + } + + case 3: { + if (rand > 0.5) { + mixedEventMultContMM.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } else { + mixedEventMultContMM.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } + break; + } + + default: + break; + } + } + } + + /// process function for to call doMixedEvent with Data + /// @param cols subscribe to the collisions table (Data) + /// @param parts subscribe to the femtoUniverseParticleTable + void processMixedEventCent(FilteredFDCollisions const& cols, + FilteredFemtoFullParticles const& parts) + { + randgen = new TRandom2(0); + + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningCent, ConfNEventsMix, -1, cols, cols)) { + + const int multiplicityCol = collision1.multV0M(); + MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningCent.getBin({collision1.posZ(), multiplicityCol})); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + continue; + } + + if (cfgProcessPM) { + auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 1); + } + if (cfgProcessPP) { + auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 2); + } + if (cfgProcessMM) { + auto groupPartsOne = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 3); + } + } + delete randgen; + } + PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processMixedEventCent, "Enable processing mixed events for centrality", true); + + /// process function for to call doMixedEvent with Data + /// @param cols subscribe to the collisions table (Data) + /// @param parts subscribe to the femtoUniverseParticleTable + void processMixedEventNtr(FilteredFDCollisions const& cols, + FilteredFemtoFullParticles const& parts) + { + randgen = new TRandom2(0); + + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningNtr, ConfNEventsMix, -1, cols, cols)) { + + const int multiplicityCol = collision1.multNtr(); + MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningNtr.getBin({collision1.posZ(), multiplicityCol})); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + continue; + } + + if (cfgProcessPM) { + auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 1); + } + if (cfgProcessPP) { + auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 2); + } + if (cfgProcessMM) { + auto groupPartsOne = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 3); + } + } + delete randgen; + } + PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processMixedEventNtr, "Enable processing mixed events for centrality", false); + + /// process function for to fill covariance histograms + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoUniverseParticleTable + void processCov(soa::Filtered::iterator const& /*col*/, + FilteredFemtoFullParticles const& /*parts*/) + { + int JMax = (ConfLMax + 1) * (ConfLMax + 1); + if (cfgProcessMM) { + sameEventMultContMM.fillMultkTCov(femto_universe_sh_container::EventType::same, JMax); + mixedEventMultContMM.fillMultkTCov(femto_universe_sh_container::EventType::mixed, JMax); + } else if (cfgProcessPP) { + sameEventMultContPP.fillMultkTCov(femto_universe_sh_container::EventType::same, JMax); + mixedEventMultContPP.fillMultkTCov(femto_universe_sh_container::EventType::mixed, JMax); + } else if (cfgProcessPM) { + sameEventMultCont.fillMultkTCov(femto_universe_sh_container::EventType::same, JMax); + mixedEventMultCont.fillMultkTCov(femto_universe_sh_container::EventType::mixed, JMax); + } + } + PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processCov, "Enable processing same event covariance", false); + + /// brief process function for to call doMixedEvent with Monte Carlo + /// @param cols subscribe to the collisions table (Monte Carlo Reconstructed reconstructed) + /// @param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth + /// @param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table + void processMixedEventMCCent(o2::aod::FdCollisions const& cols, + soa::Join const& parts, + o2::aod::FdMCParticles const&) + { + randgen = new TRandom2(0); + + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningCent, ConfNEventsMix, -1, cols, cols)) { + + const int multiplicityCol = collision1.multV0M(); + MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningCent.getBin({collision1.posZ(), multiplicityCol})); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + continue; + } + /// \todo before mixing we should check whether both collisions contain a pair of particles! + // if (partsOne.size() == 0 || nPart2Evt1 == 0 || nPart1Evt2 == 0 || partsTwo.size() == 0 ) continue; + + if (cfgProcessPM) { + auto groupPartsOne = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 1); + } + if (cfgProcessPP) { + auto groupPartsOne = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 2); + } + if (cfgProcessMM) { + auto groupPartsOne = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 3); + } + } + delete randgen; + } + PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processMixedEventMCCent, "Enable processing mixed events MC", false); + + /// brief process function for to call doMixedEvent with Monte Carlo + /// @param cols subscribe to the collisions table (Monte Carlo Reconstructed reconstructed) + /// @param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth + /// @param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table + void processMixedEventMCNtr(o2::aod::FdCollisions const& cols, + soa::Join const& parts, + o2::aod::FdMCParticles const&) + { + randgen = new TRandom2(0); + + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningNtr, ConfNEventsMix, -1, cols, cols)) { + + const int multiplicityCol = collision1.multV0M(); + MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningNtr.getBin({collision1.posZ(), multiplicityCol})); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + continue; + } + /// \todo before mixing we should check whether both collisions contain a pair of particles! + // if (partsOne.size() == 0 || nPart2Evt1 == 0 || nPart1Evt2 == 0 || partsTwo.size() == 0 ) continue; + + if (cfgProcessPM) { + auto groupPartsOne = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 1); + } + if (cfgProcessPP) { + auto groupPartsOne = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 2); + } + if (cfgProcessMM) { + auto groupPartsOne = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol, 3); + } + } + delete randgen; + } + PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processMixedEventMCNtr, "Enable processing mixed events MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx index ed272428a08..2cf45ce0475 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx @@ -9,71 +9,95 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file femtoUniversePairTaskTrackV0Extended.cxx /// \brief Tasks that build pairs of track particles and v0s /// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch /// \author Shirajum Monira, WUT Warsaw, shirajum.monira.dokt@pw.edu.pl #include +#include +#include #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" #include "Framework/ASoAHelpers.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/StepTHn.h" #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include +#include +#include using namespace o2; using namespace o2::soa; using namespace o2::framework; using namespace o2::framework::expressions; -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; using namespace o2::aod::pidutils; +using namespace o2::track; -struct femtoUniversePairTaskTrackV0Extended { +struct FemtoUniversePairTaskTrackV0Extended { + + Service pdgMC; SliceCache cache; using FemtoFullParticles = soa::Join; Preslice perCol = aod::femtouniverseparticle::fdCollisionId; + using FemtoRecoParticles = soa::Join; + Preslice perColMC = aod::femtouniverseparticle::fdCollisionId; + + /// To apply narrow cut + Configurable confZVertexCut{"confZVertexCut", 10.f, "Event sel: Maximum z-Vertex (cm)"}; + Configurable confEta{"confEta", 0.8, "Eta cut for the global track"}; + /// Particle 1 (track) - Configurable ConfTrkPDGCodePartOne{"ConfTrkPDGCodePartOne", 211, "Particle 1 (Track) - PDG code"}; - Configurable ConfTrackChoicePartOne{"ConfTrackChoicePartOne", 1, "0:Proton, 1:Pion, 2:Kaon"}; - ConfigurableAxis ConfTrkTempFitVarBins{"ConfTrkDTempFitVarBins", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfTrkTempFitVarpTBins{"ConfTrkTempFitVarpTBins", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; - Configurable ConfChargePart1{"ConfChargePart1", 0, "sign of particle 1"}; - Configurable ConfHPtPart1{"ConfHPtPart1", 4.0f, "higher limit for pt of particle 1"}; - Configurable ConfLPtPart1{"ConfLPtPart1", 0.3f, "lower limit for pt of particle 1"}; - Configurable Confmom{"Confmom", 0.5, "momentum threshold for particle identification using TOF"}; - Configurable ConfNsigmaTPCParticle{"ConfNsigmaTPCParticle", 3.0, "TPC Sigma for particle momentum < Confmom"}; - Configurable ConfNsigmaCombinedParticle{"ConfNsigmaCombinedParticle", 3.0, "TPC and TOF Sigma (combined) for particle momentum > Confmom"}; + Configurable confTrkPDGCodePartOne{"confTrkPDGCodePartOne", 211, "Particle 1 (Track) - PDG code"}; + Configurable confTrackChoicePartOne{"confTrackChoicePartOne", 1, "0:Proton, 1:Pion, 2:Kaon"}; + ConfigurableAxis confTrkTempFitVarBins{"confTrkTempFitVarBins", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis confTrkTempFitVarpTBins{"confTrkTempFitVarpTBins", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; + Configurable confChargePart1{"confChargePart1", 0, "sign of particle 1"}; + Configurable confHPtPart1{"confHPtPart1", 4.0f, "higher limit for pt of particle 1"}; + Configurable confLPtPart1{"confLPtPart1", 0.3f, "lower limit for pt of particle 1"}; + Configurable confmom{"confmom", 0.5, "momentum threshold for particle identification using TOF"}; + Configurable confNsigmaTPCParticle{"confNsigmaTPCParticle", 3.0, "TPC Sigma for particle momentum < confmom"}; + Configurable confNsigmaCombinedParticle{"confNsigmaCombinedParticle", 3.0, "TPC and TOF Sigma (combined) for particle momentum > confmom"}; + + Filter collisionFilter = (nabs(aod::collision::posZ) < confZVertexCut); + using FilteredFDCollisions = soa::Filtered; + using FilteredFDCollision = FilteredFDCollisions::iterator; /// Partition for particle 1 - Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == ConfChargePart1 && aod::femtouniverseparticle::pt < ConfHPtPart1 && aod::femtouniverseparticle::pt > ConfLPtPart1; + Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == confChargePart1) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < confHPtPart1) && (aod::femtouniverseparticle::pt > confLPtPart1); + Partition partsOneMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < confHPtPart1) && (aod::femtouniverseparticle::pt > confLPtPart1); + Partition partsOneMCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == confChargePart1) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < confHPtPart1) && (aod::femtouniverseparticle::pt > confLPtPart1); /// Histogramming for particle 1 FemtoUniverseParticleHisto trackHistoPartOnePos; FemtoUniverseParticleHisto trackHistoPartOneNeg; /// Particle 2 (V0) - Configurable ConfV0PDGCodePartTwo{"ConfV0PDGCodePartTwo", 3122, "Particle 2 (V0) - PDG code"}; - ConfigurableAxis ConfV0TempFitVarBins{"ConfV0TempFitVarBins", {300, 0.95, 1.}, "V0: binning of the TempFitVar in the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfV0TempFitVarpTBins{"ConfV0TempFitVarpTBins", {20, 0.5, 4.05}, "V0: pT binning of the pT vs. TempFitVar plot"}; - Configurable ConfV0Type1{"ConfV0Type1", 0, "select one of the V0s (lambda = 0, anti-lambda = 1, k0 = 2) for v0-v0 and Track-v0 combination"}; - Configurable ConfV0Type2{"ConfV0Type2", 0, "select one of the V0s (lambda = 0, anti-lambda = 1, k0 = 2) for v0-v0 combination"}; - ConfigurableAxis ConfChildTempFitVarBins{"ConfChildTempFitVarBins", {300, -0.15, 0.15}, "V0 child: binning of the TempFitVar in the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfChildTempFitVarpTBins{"ConfChildTempFitVarpTBins", {20, 0.5, 4.05}, "V0 child: pT binning of the pT vs. TempFitVar plot"}; - Configurable ConfHPtPart2{"ConfHPtPart2", 4.0f, "higher limit for pt of particle 2"}; - Configurable ConfLPtPart2{"ConfLPtPart2", 0.3f, "lower limit for pt of particle 2"}; + Configurable confV0PDGCodePartTwo{"confV0PDGCodePartTwo", 3122, "Particle 2 (V0) - PDG code"}; + ConfigurableAxis confV0TempFitVarBins{"confV0TempFitVarBins", {300, 0.95, 1.}, "V0: binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis confV0TempFitVarpTBins{"confV0TempFitVarpTBins", {20, 0.5, 4.05}, "V0: pT binning of the pT vs. TempFitVar plot"}; + Configurable confV0Type1{"confV0Type1", 0, "select one of the V0s (lambda = 0, anti-lambda = 1, k0 = 2) for v0-v0 and Track-v0 combination"}; + Configurable confV0Type2{"confV0Type2", 0, "select one of the V0s (lambda = 0, anti-lambda = 1, k0 = 2) for v0-v0 combination"}; + Configurable confV0InvMassLowLimit{"confV0InvMassLowLimit", 1.10, "Lower limit of the V0 invariant mass"}; + Configurable confV0InvMassUpLimit{"confV0InvMassUpLimit", 1.13, "Upper limit of the V0 invariant mass"}; + ConfigurableAxis confChildTempFitVarBins{"confChildTempFitVarBins", {300, -0.15, 0.15}, "V0 child: binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis confChildTempFitVarpTBins{"confChildTempFitVarpTBins", {20, 0.5, 4.05}, "V0 child: pT binning of the pT vs. TempFitVar plot"}; + Configurable confHPtPart2{"confHPtPart2", 4.0f, "higher limit for pt of particle 2"}; + Configurable confLPtPart2{"confLPtPart2", 0.3f, "lower limit for pt of particle 2"}; /// Partition for particle 2 - Partition partsTwo = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kV0)) && aod::femtouniverseparticle::pt < ConfHPtPart2 && aod::femtouniverseparticle::pt > ConfLPtPart2; + Partition partsTwo = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kV0)) && (aod::femtouniverseparticle::pt < confHPtPart2) && (aod::femtouniverseparticle::pt > confLPtPart2); + Partition partsTwoMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (aod::femtouniverseparticle::pt < confHPtPart2) && (aod::femtouniverseparticle::pt > confLPtPart2); + Partition partsTwoMCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kV0)) && (aod::femtouniverseparticle::pt < confHPtPart2) && (aod::femtouniverseparticle::pt > confLPtPart2); /// Histogramming for particle 2 FemtoUniverseParticleHisto trackHistoPartTwo; @@ -91,32 +115,35 @@ struct femtoUniversePairTaskTrackV0Extended { FemtoUniverseEventHisto eventHisto; /// Correlation part - // Configurable ConfTrackChoicePartTwo{"ConfTrackChoicePartTwo", 1, "0:Proton, 1:Pion, 2:Kaon"}; //not used - Configurable ConfIsMC{"ConfIsMC", false, "Enable additional Histogramms in the case of a MonteCarlo Run"}; - Configurable ConfUse3D{"ConfUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; - ConfigurableAxis ConfMultBins{"ConfMultBins", {VARIABLE_WIDTH, 0.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; - ConfigurableAxis ConfVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - ConfigurableAxis ConfkstarBins{"ConfkstarBins", {1500, 0., 6.}, "binning kstar"}; - ConfigurableAxis ConfkTBins{"ConfkTBins", {150, 0., 9.}, "binning kT"}; - ConfigurableAxis ConfmTBins{"ConfmTBins", {225, 0., 7.5}, "binning mT"}; - Configurable ConfIsCPR{"ConfIsCPR", true, "Close Pair Rejection"}; - Configurable ConfCPRPlotPerRadii{"ConfCPRPlotPerRadii", false, "Plot CPR per radii"}; - Configurable ConfCPRdeltaPhiMax{"ConfCPRdeltaPhiMax", 0.01, "Max. Delta Phi for Close Pair Rejection"}; - Configurable ConfCPRdeltaEtaMax{"ConfCPRdeltaEtaMax", 0.01, "Max. Delta Eta for Close Pair Rejection"}; - Configurable ConfCPRdeltaPhiCutMax{"ConfCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaPhiCutMin{"ConfCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaEtaCutMax{"ConfCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaEtaCutMin{"ConfCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; - Configurable ConfCPRChosenRadii{"ConfCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; - Configurable ConfPhiBins{"ConfPhiBins", 29, "Number of phi bins in deta dphi"}; - Configurable ConfEtaBins{"ConfEtaBins", 29, "Number of eta bins in deta dphi"}; - ConfigurableAxis ConfmTBins3D{"ConfmTBins3D", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; - ConfigurableAxis ConfmultBins3D{"ConfMultBins3D", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; - - static constexpr UInt_t V0ChildTable[][2] = {{0, 1}, {1, 0}, {1, 1}}; // Table to select the V0 children - - FemtoUniverseContainer sameEventCont; - FemtoUniverseContainer mixedEventCont; + // Configurable confTrackChoicePartTwo{"confTrackChoicePartTwo", 1, "0:Proton, 1:Pion, 2:Kaon"}; //not used + Configurable confIsMC{"confIsMC", false, "Enable additional Histograms in the case of a MonteCarlo Run"}; + Configurable confUse3D{"confUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; + Configurable confUseCent{"confUseCent", false, "Use centrality in place of multiplicity"}; + ConfigurableAxis confMultBins{"confMultBins", {VARIABLE_WIDTH, 0.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; + ConfigurableAxis confVtxBins{"confVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + Configurable confNEventsMix{"confNEventsMix", 5, "Number of events for mixing"}; + ConfigurableAxis confkstarBins{"confkstarBins", {1500, 0., 6.}, "binning kstar"}; + ConfigurableAxis confkTBins{"confkTBins", {150, 0., 9.}, "binning kT"}; + ConfigurableAxis confmTBins{"confmTBins", {225, 0., 7.5}, "binning mT"}; + Configurable confIsCPR{"confIsCPR", true, "Close Pair Rejection"}; + Configurable confCPRPlotPerRadii{"confCPRPlotPerRadii", false, "Plot CPR per radii"}; + Configurable confCPRdeltaPhiCutMax{"confCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; + Configurable confCPRdeltaPhiCutMin{"confCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMax{"confCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMin{"confCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; + Configurable confCPRChosenRadii{"confCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; + Configurable confPhiBins{"confPhiBins", 29, "Number of phi bins in deta dphi"}; + Configurable confEtaBins{"confEtaBins", 29, "Number of eta bins in deta dphi"}; + ConfigurableAxis confmTBins3D{"confmTBins3D", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + ConfigurableAxis confMultBins3D{"confMultBins3D", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + + // Efficiency + Configurable confLocalEfficiency{"confLocalEfficiency", "", "Local path to efficiency .root file"}; + + static constexpr unsigned int V0ChildTable[][2] = {{0, 1}, {1, 0}, {1, 1}}; // Table to select the V0 children + + FemtoUniverseContainer sameEventCont; + FemtoUniverseContainer mixedEventCont; FemtoUniversePairCleaner pairCleaner; FemtoUniversePairCleaner pairCleanerV0; FemtoUniverseDetaDphiStar pairCloseRejection; @@ -124,27 +151,35 @@ struct femtoUniversePairTaskTrackV0Extended { /// Histogram output HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry resultRegistry{"Correlations", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryMCtruth{"MCtruthHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry registryMCreco{"MCrecoHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + + HistogramRegistry mixQaRegistry{"mixQaRegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + std::unique_ptr plocalEffFile; + std::unique_ptr plocalEffp1; + std::unique_ptr plocalEffp2; - bool IsNSigmaCombined(float mom, float nsigmaTPCParticle, float nsigmaTOFParticle) + bool isNSigmaCombined(float mom, float nsigmaTPCParticle, float nsigmaTOFParticle) { - if (mom <= Confmom) { - if (TMath::Abs(nsigmaTPCParticle) < ConfNsigmaTPCParticle) { - return true; - } else { - return false; - } + if (mom <= confmom) { + return (std::abs(nsigmaTPCParticle) < confNsigmaTPCParticle); } else { - if (TMath::Hypot(nsigmaTOFParticle, nsigmaTPCParticle) < ConfNsigmaCombinedParticle) { - return true; - } else { - return false; - } + return (std::hypot(nsigmaTOFParticle, nsigmaTPCParticle) < confNsigmaCombinedParticle); + } + } + + bool invMLambda(float invMassLambda, float invMassAntiLambda) + { + if ((invMassLambda < confV0InvMassLowLimit || invMassLambda > confV0InvMassUpLimit) && (invMassAntiLambda < confV0InvMassLowLimit || invMassAntiLambda > confV0InvMassUpLimit)) { + return false; } + return true; } - bool IsNSigmaTPC(float nsigmaTPCParticle) + bool isNSigmaTPC(float nsigmaTPCParticle) { - if (TMath::Abs(nsigmaTPCParticle) < ConfNsigmaTPCParticle) { + if (std::abs(nsigmaTPCParticle) < confNsigmaTPCParticle) { return true; } else { return false; @@ -152,280 +187,940 @@ struct femtoUniversePairTaskTrackV0Extended { } template - bool IsParticleCombined(const T& part, int id) + bool isParticleCombined(const T& part, int id) { const float tpcNSigmas[3] = {unPackInTable(part.tpcNSigmaStorePr()), unPackInTable(part.tpcNSigmaStorePi()), unPackInTable(part.tpcNSigmaStoreKa())}; // const float tofNSigmas[3] = {part.tofNSigmaPr(), part.tofNSigmaPi(), part.tofNSigmaKa()}; const float tofNSigmas[3] = {unPackInTable(part.tofNSigmaStorePr()), unPackInTable(part.tofNSigmaStorePi()), unPackInTable(part.tofNSigmaStoreKa())}; - return IsNSigmaCombined(part.p(), tpcNSigmas[id], tofNSigmas[id]); + return isNSigmaCombined(part.p(), tpcNSigmas[id], tofNSigmas[id]); } template - bool IsParticleTPC(const T& part, int id) + bool isParticleTPC(const T& part, int id) { const float tpcNSigmas[3] = {unPackInTable(part.tpcNSigmaStorePr()), unPackInTable(part.tpcNSigmaStorePi()), unPackInTable(part.tpcNSigmaStoreKa())}; - return IsNSigmaTPC(tpcNSigmas[id]); + return isNSigmaTPC(tpcNSigmas[id]); } void init(InitContext&) { eventHisto.init(&qaRegistry); - qaRegistry.add("Tracks_pos/nSigmaTPC", "; #it{p} (GeV/#it{c}); n#sigma_{TPC}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - qaRegistry.add("Tracks_pos/nSigmaTOF", "; #it{p} (GeV/#it{c}); n#sigma_{TOF}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - qaRegistry.add("Tracks_neg/nSigmaTPC", "; #it{p} (GeV/#it{c}); n#sigma_{TPC}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - qaRegistry.add("Tracks_neg/nSigmaTOF", "; #it{p} (GeV/#it{c}); n#sigma_{TOF}", kTH2F, {{100, 0, 10}, {100, -5, 5}}); - trackHistoPartOnePos.init(&qaRegistry, ConfTrkTempFitVarpTBins, ConfTrkTempFitVarBins, ConfIsMC, ConfTrkPDGCodePartOne); - trackHistoPartOneNeg.init(&qaRegistry, ConfTrkTempFitVarpTBins, ConfTrkTempFitVarBins, ConfIsMC, ConfTrkPDGCodePartOne); - trackHistoPartTwo.init(&qaRegistry, ConfV0TempFitVarpTBins, ConfV0TempFitVarBins, ConfIsMC, ConfV0PDGCodePartTwo); - posChildHistos.init(&qaRegistry, ConfChildTempFitVarpTBins, ConfChildTempFitVarBins, false, false); - negChildHistos.init(&qaRegistry, ConfChildTempFitVarpTBins, ConfChildTempFitVarBins, false, false); - - trackHistoV0Type1.init(&qaRegistry, ConfV0TempFitVarpTBins, ConfV0TempFitVarBins, ConfIsMC, ConfV0PDGCodePartTwo, false, "V0Type1"); - posChildV0Type1.init(&qaRegistry, ConfChildTempFitVarpTBins, ConfChildTempFitVarBins, false, false, false, "posChildV0Type1"); - negChildV0Type1.init(&qaRegistry, ConfChildTempFitVarpTBins, ConfChildTempFitVarBins, false, false, false, "negChildV0Type1"); - trackHistoV0Type2.init(&qaRegistry, ConfV0TempFitVarpTBins, ConfV0TempFitVarBins, ConfIsMC, ConfV0PDGCodePartTwo, false, "V0Type2"); - posChildV0Type2.init(&qaRegistry, ConfChildTempFitVarpTBins, ConfChildTempFitVarBins, false, false, false, "posChildV0Type2"); - negChildV0Type2.init(&qaRegistry, ConfChildTempFitVarpTBins, ConfChildTempFitVarBins, false, false, false, "negChildV0Type2"); - - sameEventCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfEtaBins, ConfPhiBins, ConfIsMC, ConfUse3D); - sameEventCont.setPDGCodes(ConfTrkPDGCodePartOne, ConfV0PDGCodePartTwo); - mixedEventCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfEtaBins, ConfPhiBins, ConfIsMC, ConfUse3D); - mixedEventCont.setPDGCodes(ConfTrkPDGCodePartOne, ConfV0PDGCodePartTwo); + qaRegistry.add("Tracks_pos/nSigmaTPC", "; #it{p} (GeV/#it{c}); n#sigma_{TPC}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Tracks_pos/nSigmaTOF", "; #it{p} (GeV/#it{c}); n#sigma_{TOF}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Tracks_neg/nSigmaTPC", "; #it{p} (GeV/#it{c}); n#sigma_{TPC}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("Tracks_neg/nSigmaTOF", "; #it{p} (GeV/#it{c}); n#sigma_{TOF}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + trackHistoPartOnePos.init(&qaRegistry, confTrkTempFitVarpTBins, confTrkTempFitVarBins, confIsMC, confTrkPDGCodePartOne); + trackHistoPartOneNeg.init(&qaRegistry, confTrkTempFitVarpTBins, confTrkTempFitVarBins, confIsMC, confTrkPDGCodePartOne); + trackHistoPartTwo.init(&qaRegistry, confV0TempFitVarpTBins, confV0TempFitVarBins, confIsMC, confV0PDGCodePartTwo, true); + posChildHistos.init(&qaRegistry, confChildTempFitVarpTBins, confChildTempFitVarBins, false, 0, true); + negChildHistos.init(&qaRegistry, confChildTempFitVarpTBins, confChildTempFitVarBins, false, 0, true); + + qaRegistry.add("V0Type1/hInvMassLambdaVsCent", "; Centrality; M_{#Lambda}; Entries", kTH2F, {confMultBins, {2000, 1.f, 3.f}}); + qaRegistry.add("V0Type2/hInvMassLambdaVsCent", "; Centrality; M_{#Lambda}; Entries", kTH2F, {confMultBins, {2000, 1.f, 3.f}}); + qaRegistry.add("V0Type1/hInvMassAntiLambdaVsCent", "; Centrality; M_{#Lambda}; Entries", kTH2F, {confMultBins, {2000, 1.f, 3.f}}); + qaRegistry.add("V0Type2/hInvMassAntiLambdaVsCent", "; Centrality; M_{#Lambda}; Entries", kTH2F, {confMultBins, {2000, 1.f, 3.f}}); + trackHistoV0Type1.init(&qaRegistry, confV0TempFitVarpTBins, confV0TempFitVarBins, confIsMC, confV0PDGCodePartTwo, true, "V0Type1"); + posChildV0Type1.init(&qaRegistry, confChildTempFitVarpTBins, confChildTempFitVarBins, false, 0, true, "posChildV0Type1"); + negChildV0Type1.init(&qaRegistry, confChildTempFitVarpTBins, confChildTempFitVarBins, false, 0, true, "negChildV0Type1"); + trackHistoV0Type2.init(&qaRegistry, confV0TempFitVarpTBins, confV0TempFitVarBins, confIsMC, confV0PDGCodePartTwo, true, "V0Type2"); + posChildV0Type2.init(&qaRegistry, confChildTempFitVarpTBins, confChildTempFitVarBins, false, 0, true, "posChildV0Type2"); + negChildV0Type2.init(&qaRegistry, confChildTempFitVarpTBins, confChildTempFitVarBins, false, 0, true, "negChildV0Type2"); + + mixQaRegistry.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); + + // MC truth + registryMCtruth.add("plus/MCtruthLambda", "MC truth Lambdas;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCtruth.add("minus/MCtruthLambda", "MC truth Lambdas;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + + registryMCtruth.add("plus/MCtruthAllPt", "MC truth all;#it{p}_{T} (GeV/c); #eta", {HistType::kTH1F, {{500, 0, 5}}}); + registryMCtruth.add("minus/MCtruthAllPt", "MC truth all;#it{p}_{T} (GeV/c); #eta", {HistType::kTH1F, {{500, 0, 5}}}); + + registryMCtruth.add("plus/MCtruthPi", "MC truth pions;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCtruth.add("plus/MCtruthPr", "MC truth protons;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + + registryMCtruth.add("minus/MCtruthPi", "MC truth pions;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCtruth.add("minus/MCtruthPr", "MC truth protons;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + + registryMCtruth.add("plus/MCtruthPiPt", "MC truth pions;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + registryMCtruth.add("plus/MCtruthPrPt", "MC truth protons;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + registryMCtruth.add("minus/MCtruthPiPt", "MC truth pions;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + registryMCtruth.add("minus/MCtruthPrPt", "MC truth protons;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + + registryMCtruth.add("motherParticle", "pair fractions;part1 mother PDG;part2 mother PDG", {HistType::kTH2F, {{8001, -4000, 4000}, {8001, -4000, 4000}}}); + + // MC reco + registryMCreco.add("plus/MCrecoLambda", "MC reco Lambdas;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCreco.add("plus/MCrecoLambdaChildPr", "MC reco Lambdas;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCreco.add("plus/MCrecoLambdaChildPi", "MC reco Lambdas;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCreco.add("minus/MCrecoLambda", "MC reco Lambdas;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCreco.add("minus/MCrecoLambdaChildPr", "MC reco Lambdas;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCreco.add("minus/MCrecoLambdaChildPi", "MC reco Lambdas;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + + registryMCreco.add("plus/MCrecoAllPt", "MC reco all;#it{p}_{T} (GeV/c); #eta", {HistType::kTH1F, {{500, 0, 5}}}); + registryMCreco.add("minus/MCrecoAllPt", "MC reco all;#it{p}_{T} (GeV/c); #eta", {HistType::kTH1F, {{500, 0, 5}}}); + + registryMCreco.add("plus/MCrecoPi", "MC reco pions;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCreco.add("plus/MCrecoPr", "MC reco protons;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + + registryMCreco.add("minus/MCrecoPi", "MC reco pions;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + registryMCreco.add("minus/MCrecoPr", "MC reco protons;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + + registryMCreco.add("plus/MCrecoPiPt", "MC reco pions;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + registryMCreco.add("plus/MCrecoPrPt", "MC reco protons;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + registryMCreco.add("minus/MCrecoPiPt", "MC reco pions;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + registryMCreco.add("minus/MCrecoPrPt", "MC reco protons;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + + registryMCreco.add("motherParticle", "pair fractions;part1 mother PDG;part2 mother PDG", {HistType::kTH2F, {{8001, -4000, 4000}, {8001, -4000, 4000}}}); + + sameEventCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); + sameEventCont.setPDGCodes(confTrkPDGCodePartOne, confV0PDGCodePartTwo); + mixedEventCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); + mixedEventCont.setPDGCodes(confTrkPDGCodePartOne, confV0PDGCodePartTwo); pairCleaner.init(&qaRegistry); pairCleanerV0.init(&qaRegistry); - if (ConfIsCPR.value) { - pairCloseRejection.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiCutMin.value, ConfCPRdeltaPhiCutMax.value, ConfCPRdeltaEtaCutMin.value, ConfCPRdeltaEtaCutMax.value, ConfCPRChosenRadii.value, ConfCPRPlotPerRadii.value); - pairCloseRejectionV0.init(&resultRegistry, &qaRegistry, ConfCPRdeltaPhiCutMin.value, ConfCPRdeltaPhiCutMax.value, ConfCPRdeltaEtaCutMin.value, ConfCPRdeltaEtaCutMax.value, ConfCPRChosenRadii.value, ConfCPRPlotPerRadii.value); + if (confIsCPR.value) { + pairCloseRejection.init(&resultRegistry, &qaRegistry, confCPRdeltaPhiCutMin.value, confCPRdeltaPhiCutMax.value, confCPRdeltaEtaCutMin.value, confCPRdeltaEtaCutMax.value, confCPRChosenRadii.value, confCPRPlotPerRadii.value); + pairCloseRejectionV0.init(&resultRegistry, &qaRegistry, confCPRdeltaPhiCutMin.value, confCPRdeltaPhiCutMax.value, confCPRdeltaEtaCutMin.value, confCPRdeltaEtaCutMax.value, confCPRChosenRadii.value, confCPRPlotPerRadii.value); + } + + if (!confLocalEfficiency.value.empty()) { + plocalEffFile = std::unique_ptr(TFile::Open(confLocalEfficiency.value.c_str(), "read")); + if (!plocalEffFile || plocalEffFile.get()->IsZombie()) + LOGF(fatal, "Could not load efficiency histogram from %s", confLocalEfficiency.value.c_str()); + if (doprocessSameEvent || doprocessMixedEvent) { + plocalEffp1 = (confChargePart1 > 0) ? std::unique_ptr(plocalEffFile.get()->Get("PrPlus")) : std::unique_ptr(plocalEffFile.get()->Get("PrMinus")); // note: works only for protons for now + plocalEffp2 = (confV0Type1 == 0) ? std::unique_ptr(plocalEffFile.get()->Get("Lambda")) : std::unique_ptr(plocalEffFile.get()->Get("AntiLambda")); + LOGF(info, "Loaded efficiency histograms for track-V0."); + } else if (doprocessSameEventV0 || doprocessMixedEventV0) { + plocalEffp1 = (confV0Type1 == 0) ? std::unique_ptr(plocalEffFile.get()->Get("Lambda")) : std::unique_ptr(plocalEffFile.get()->Get("AntiLambda")); + plocalEffp2 = (confV0Type2 == 0) ? std::unique_ptr(plocalEffFile.get()->Get("Lambda")) : std::unique_ptr(plocalEffFile.get()->Get("AntiLambda")); + LOGF(info, "Loaded efficiency histograms for V0-V0."); + } } } /// This function processes the same event for track - V0 - void processSameEvent(o2::aod::FDCollision& col, FemtoFullParticles& parts) + template + void doSameEvent(FilteredFDCollision const& col, PartType const& parts, PartitionType& groupPartsOne, PartitionType& groupPartsTwo, [[maybe_unused]] MCParticles mcParts = nullptr) { const auto& magFieldTesla = col.magField(); - auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - const int multCol = col.multNtr(); + const int multCol = confUseCent ? col.multV0M() : col.multNtr(); eventHisto.fillQA(col); /// Histogramming same event - for (auto& part : groupPartsTwo) { + for (const auto& part : groupPartsTwo) { + if (!invMLambda(part.mLambda(), part.mAntiLambda())) + continue; const auto& posChild = parts.iteratorAt(part.index() - 2); const auto& negChild = parts.iteratorAt(part.index() - 1); /// Daughters that do not pass this condition are not selected - if (!IsParticleTPC(posChild, V0ChildTable[ConfV0Type1][0]) || !IsParticleTPC(negChild, V0ChildTable[ConfV0Type1][1])) + if (!isParticleTPC(posChild, V0ChildTable[confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[confV0Type1][1])) continue; - trackHistoPartTwo.fillQA(part); - posChildHistos.fillQA(posChild); - negChildHistos.fillQA(negChild); + trackHistoPartTwo.fillQA(part); + posChildHistos.fillQA(posChild); + negChildHistos.fillQA(negChild); } - for (auto& part : groupPartsOne) { + for (const auto& part : groupPartsOne) { /// PID plot for particle 1 const float tpcNSigmas[3] = {unPackInTable(part.tpcNSigmaStorePr()), unPackInTable(part.tpcNSigmaStorePi()), unPackInTable(part.tpcNSigmaStoreKa())}; const float tofNSigmas[3] = {unPackInTable(part.tofNSigmaStorePr()), unPackInTable(part.tofNSigmaStorePi()), unPackInTable(part.tofNSigmaStoreKa())}; - if (!IsNSigmaCombined(part.p(), tpcNSigmas[ConfTrackChoicePartOne], tofNSigmas[ConfTrackChoicePartOne])) + if (!isNSigmaCombined(part.p(), tpcNSigmas[confTrackChoicePartOne], tofNSigmas[confTrackChoicePartOne])) continue; if (part.sign() > 0) { - qaRegistry.fill(HIST("Tracks_pos/nSigmaTPC"), part.p(), tpcNSigmas[ConfTrackChoicePartOne]); - qaRegistry.fill(HIST("Tracks_pos/nSigmaTOF"), part.p(), tofNSigmas[ConfTrackChoicePartOne]); + qaRegistry.fill(HIST("Tracks_pos/nSigmaTPC"), part.p(), tpcNSigmas[confTrackChoicePartOne]); + qaRegistry.fill(HIST("Tracks_pos/nSigmaTOF"), part.p(), tofNSigmas[confTrackChoicePartOne]); trackHistoPartOnePos.fillQA(part); } else if (part.sign() < 0) { - qaRegistry.fill(HIST("Tracks_neg/nSigmaTPC"), part.p(), tpcNSigmas[ConfTrackChoicePartOne]); - qaRegistry.fill(HIST("Tracks_neg/nSigmaTOF"), part.p(), tofNSigmas[ConfTrackChoicePartOne]); + qaRegistry.fill(HIST("Tracks_neg/nSigmaTPC"), part.p(), tpcNSigmas[confTrackChoicePartOne]); + qaRegistry.fill(HIST("Tracks_neg/nSigmaTOF"), part.p(), tofNSigmas[confTrackChoicePartOne]); trackHistoPartOneNeg.fillQA(part); } } /// Now build the combinations - for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + // Lambda invariant mass cut + if (!invMLambda(p2.mLambda(), p2.mAntiLambda())) + continue; + /// PID using stored binned nsigma + if (!isParticleCombined(p1, confTrackChoicePartOne)) + continue; // track cleaning if (!pairCleaner.isCleanPair(p1, p2, parts)) { continue; } - if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::same)) { + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } } - /// PID using stored binned nsigma - if (!IsParticleCombined(p1, ConfTrackChoicePartOne)) - continue; const auto& posChild = parts.iteratorAt(p2.index() - 2); const auto& negChild = parts.iteratorAt(p2.index() - 1); /// Daughters that do not pass this condition are not selected - if (!IsParticleTPC(posChild, V0ChildTable[ConfV0Type1][0]) || !IsParticleTPC(negChild, V0ChildTable[ConfV0Type1][1])) + if (!isParticleTPC(posChild, V0ChildTable[confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[confV0Type1][1])) continue; - sameEventCont.setPair(p1, p2, multCol, ConfUse3D); + float weight = 1.0f; + if (plocalEffp1) + weight = plocalEffp1.get()->GetBinContent(plocalEffp1->FindBin(p1.pt(), p1.eta())) * plocalEffp2.get()->GetBinContent(plocalEffp2->FindBin(p2.pt(), p2.eta())); + if constexpr (std::is_same::value) + sameEventCont.setPair(p1, p2, multCol, confUse3D, weight); + else + sameEventCont.setPair(p1, p2, multCol, confUse3D, weight); } } - PROCESS_SWITCH(femtoUniversePairTaskTrackV0Extended, processSameEvent, "Enable processing same event for track - V0", false); - /// This function processes the same event for V0 - V0 - void processSameEventV0(o2::aod::FDCollision& col, FemtoFullParticles& parts) + template + void doSameEventV0(FilteredFDCollision const& col, PartType const& parts, PartitionType& groupPartsTwo, [[maybe_unused]] MCParticles mcParts = nullptr) { const auto& magFieldTesla = col.magField(); - auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - const int multCol = col.multNtr(); + const int multCol = confUseCent ? col.multV0M() : col.multNtr(); eventHisto.fillQA(col); /// Histogramming same event - for (auto& part : groupPartsTwo) { + for (const auto& part : groupPartsTwo) { + if (!invMLambda(part.mLambda(), part.mAntiLambda())) + continue; const auto& posChild = parts.iteratorAt(part.index() - 2); const auto& negChild = parts.iteratorAt(part.index() - 1); /// Check daughters of first V0 particle - if (IsParticleTPC(posChild, V0ChildTable[ConfV0Type1][0]) && IsParticleTPC(negChild, V0ChildTable[ConfV0Type1][1])) { - trackHistoV0Type1.fillQABase(part, HIST("V0Type1")); - posChildV0Type1.fillQABase(posChild, HIST("posChildV0Type1")); - negChildV0Type1.fillQABase(negChild, HIST("negChildV0Type1")); + if (isParticleTPC(posChild, V0ChildTable[confV0Type1][0]) && isParticleTPC(negChild, V0ChildTable[confV0Type1][1])) { + trackHistoV0Type1.fillQABase(part, HIST("V0Type1")); + posChildV0Type1.fillQABase(posChild, HIST("posChildV0Type1")); + negChildV0Type1.fillQABase(negChild, HIST("negChildV0Type1")); + qaRegistry.fill(HIST("V0Type1/hInvMassLambdaVsCent"), multCol, part.mLambda()); + qaRegistry.fill(HIST("V0Type1/hInvMassAntiLambdaVsCent"), multCol, part.mAntiLambda()); } /// Check daughters of second V0 particle - if (IsParticleTPC(posChild, V0ChildTable[ConfV0Type2][0]) && IsParticleTPC(negChild, V0ChildTable[ConfV0Type2][1])) { - trackHistoV0Type2.fillQABase(part, HIST("V0Type2")); - posChildV0Type2.fillQABase(posChild, HIST("posChildV0Type2")); - negChildV0Type2.fillQABase(negChild, HIST("negChildV0Type2")); + if (isParticleTPC(posChild, V0ChildTable[confV0Type2][0]) && isParticleTPC(negChild, V0ChildTable[confV0Type2][1])) { + trackHistoV0Type2.fillQABase(part, HIST("V0Type2")); + posChildV0Type2.fillQABase(posChild, HIST("posChildV0Type2")); + negChildV0Type2.fillQABase(negChild, HIST("negChildV0Type2")); + qaRegistry.fill(HIST("V0Type2/hInvMassLambdaVsCent"), multCol, part.mLambda()); + qaRegistry.fill(HIST("V0Type2/hInvMassAntiLambdaVsCent"), multCol, part.mAntiLambda()); } } - /// Now build the combinations - for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsTwo, groupPartsTwo))) { + auto pairProcessFunc = [&](auto& p1, auto& p2) -> void { + // Lambda invariant mass cut for p1 + if (!invMLambda(p1.mLambda(), p1.mAntiLambda())) + return; + // Lambda invariant mass cut for p2 + if (!invMLambda(p2.mLambda(), p2.mAntiLambda())) + return; // track cleaning if (!pairCleanerV0.isCleanPair(p1, p2, parts)) { - continue; + return; } - if (ConfIsCPR.value) { - if (pairCloseRejectionV0.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::same)) { - continue; + if (confIsCPR.value) { + if (pairCloseRejectionV0.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { + return; } } const auto& posChild1 = parts.iteratorAt(p1.index() - 2); const auto& negChild1 = parts.iteratorAt(p1.index() - 1); /// Daughters that do not pass this condition are not selected - if (!IsParticleTPC(posChild1, V0ChildTable[ConfV0Type1][0]) || !IsParticleTPC(negChild1, V0ChildTable[ConfV0Type1][1])) - continue; + if (!isParticleTPC(posChild1, V0ChildTable[confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[confV0Type1][1])) + return; const auto& posChild2 = parts.iteratorAt(p2.index() - 2); const auto& negChild2 = parts.iteratorAt(p2.index() - 1); /// Daughters that do not pass this condition are not selected - if (!IsParticleTPC(posChild2, V0ChildTable[ConfV0Type2][0]) || !IsParticleTPC(negChild2, V0ChildTable[ConfV0Type2][1])) + if (!isParticleTPC(posChild2, V0ChildTable[confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[confV0Type2][1])) + return; + + if constexpr (std::is_same::value) + sameEventCont.setPair(p1, p2, multCol, confUse3D); + else + sameEventCont.setPair(p1, p2, multCol, confUse3D); + }; + + if (confV0Type1 == confV0Type2) { + /// Now build the combinations for identical V0s + for (const auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsTwo, groupPartsTwo))) { + pairProcessFunc(p1, p2); + } + } else { + /// Now build the combinations for not identical identical V0s + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsTwo, groupPartsTwo))) { + pairProcessFunc(p1, p2); + } + } + } + + void + processSameEvent(FilteredFDCollision const& col, FemtoFullParticles const& parts) + { + auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + doSameEvent(col, parts, groupPartsOne, groupPartsTwo); + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processSameEvent, "Enable processing same event for track - V0", false); + + void processSameEventMCReco(FilteredFDCollision const& col, FemtoRecoParticles const& parts, aod::FdMCParticles const& mcparts) + { + auto groupPartsOne = partsOneMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto groupPartsTwo = partsTwoMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + doSameEvent(col, parts, groupPartsOne, groupPartsTwo, mcparts); + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processSameEventMCReco, "Enable processing same event for track - V0 MC Reco", false); + + /// This function processes the same event for V0 - V0 + void processSameEventV0(FilteredFDCollision const& col, FemtoFullParticles const& parts) + { + auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + doSameEventV0(col, parts, groupPartsTwo); + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processSameEventV0, "Enable processing same event for V0 - V0", false); + + void processSameEventV0MCReco(FilteredFDCollision const& col, FemtoRecoParticles const& parts, aod::FdMCParticles const& mcparts) + { + auto groupPartsTwo = partsTwoMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + doSameEventV0(col, parts, groupPartsTwo, mcparts); + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processSameEventV0MCReco, "Enable processing same event for V0 - V0 MC Reco", false); + + /// This function processes MC same events for Track - V0 + void processMCSameEvent(FilteredFDCollision const& col, FemtoFullParticles const& parts) + { + const auto& magFieldTesla = col.magField(); + + auto groupPartsOne = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto groupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + const int multCol = confUseCent ? col.multV0M() : col.multNtr(); + + eventHisto.fillQA(col); + + /// Histogramming same event + for (const auto& part : groupPartsTwo) { + int pdgCode = static_cast(part.pidCut()); + if ((confV0Type1 == 0 && pdgCode != kLambda0) || (confV0Type1 == 1 && pdgCode != kLambda0Bar)) + continue; + trackHistoPartTwo.fillQA(part); + } + + for (const auto& part : groupPartsOne) { + int pdgCode = static_cast(part.pidCut()); + if (pdgCode != confTrkPDGCodePartOne) + continue; + const auto& pdgParticle = pdgMC->GetParticle(pdgCode); + if (!pdgParticle) { + continue; + } + /// PID plot for particle 1 + if (pdgParticle->Charge() > 0.0) { + trackHistoPartOnePos.fillQA(part); + } else if (pdgParticle->Charge() < 0.0) { + trackHistoPartOneNeg.fillQA(part); + } + } + + /// Now build the combinations + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + if (static_cast(p1.pidCut()) != confTrkPDGCodePartOne) + continue; + int pdgCode2 = static_cast(p2.pidCut()); + if ((confV0Type1 == 0 && pdgCode2 != kLambda0) || (confV0Type1 == 1 && pdgCode2 != kLambda0Bar)) continue; + // track cleaning + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { + continue; + } + } + sameEventCont.setPair(p1, p2, multCol, confUse3D); + } + } - sameEventCont.setPair(p1, p2, multCol, ConfUse3D); + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processMCSameEvent, "Enable processing same event for MC truth track - V0", false); + + /// This function processes MC same events for V0 - V0 + void processMCSameEventV0(FilteredFDCollision const& col, FemtoFullParticles const& parts) + { + auto groupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + const int multCol = confUseCent ? col.multV0M() : col.multNtr(); + + eventHisto.fillQA(col); + + /// Histogramming same event + for (const auto& part : groupPartsTwo) { + const auto& posChild = parts.iteratorAt(part.index() - 2); + const auto& negChild = parts.iteratorAt(part.index() - 1); + int pdgCode = static_cast(part.pidCut()); + if ((confV0Type1 == 0 && pdgCode == kLambda0) || (confV0Type1 == 1 && pdgCode == kLambda0Bar)) { + trackHistoV0Type1.fillQABase(part, HIST("V0Type1")); + posChildV0Type1.fillQABase(posChild, HIST("posChildV0Type1")); + negChildV0Type1.fillQABase(negChild, HIST("negChildV0Type1")); + qaRegistry.fill(HIST("V0Type1/hInvMassLambdaVsCent"), multCol, part.mLambda()); + qaRegistry.fill(HIST("V0Type1/hInvMassAntiLambdaVsCent"), multCol, part.mAntiLambda()); + } + if ((confV0Type2 == 0 && pdgCode == kLambda0) || (confV0Type2 == 1 && pdgCode == kLambda0Bar)) { + trackHistoV0Type2.fillQABase(part, HIST("V0Type2")); + posChildV0Type2.fillQABase(posChild, HIST("posChildV0Type2")); + negChildV0Type2.fillQABase(negChild, HIST("negChildV0Type2")); + qaRegistry.fill(HIST("V0Type2/hInvMassLambdaVsCent"), multCol, part.mLambda()); + qaRegistry.fill(HIST("V0Type2/hInvMassAntiLambdaVsCent"), multCol, part.mAntiLambda()); + } + } + + auto pairProcessFunc = [&](auto& p1, auto& p2) -> void { + int pdgCode1 = static_cast(p1.pidCut()); + if ((confV0Type1 == 0 && pdgCode1 != kLambda0) || (confV0Type1 == 1 && pdgCode1 != kLambda0Bar)) + return; + int pdgCode2 = static_cast(p2.pidCut()); + if ((confV0Type2 == 0 && pdgCode2 != kLambda0) || (confV0Type2 == 1 && pdgCode2 != kLambda0Bar)) + return; + sameEventCont.setPair(p1, p2, multCol, confUse3D); + }; + /// Now build the combinations + if (confV0Type1 == confV0Type2) { + /// Now build the combinations for identical V0s + for (const auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsTwo, groupPartsTwo))) { + pairProcessFunc(p1, p2); + } + } else { + /// Now build the combinations for not identical identical V0s + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsTwo, groupPartsTwo))) { + pairProcessFunc(p1, p2); + } } } - PROCESS_SWITCH(femtoUniversePairTaskTrackV0Extended, processSameEventV0, "Enable processing same event for V0 - V0", false); + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processMCSameEventV0, "Enable processing same event for MC truth V0 - V0", false); /// This function processes the mixed event for track - V0 - void processMixedEvent(o2::aod::FDCollisions& cols, FemtoFullParticles& parts) + template + void doMixedEvent(FilteredFDCollisions const& cols, PartType const& parts, PartitionType& partitionOne, PartitionType& partitionTwo, [[maybe_unused]] MCParticles mcParts = nullptr) { - ColumnBinningPolicy colBinning{{ConfVtxBins, ConfMultBins}, true}; + ColumnBinningPolicy colBinningMult{{confVtxBins, confMultBins}, true}; + ColumnBinningPolicy colBinningCent{{confVtxBins, confMultBins}, true}; - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { + const int multCol = confUseCent ? collision1.multV0M() : collision1.multNtr(); - const int multCol = collision1.multNtr(); - - auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); - auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + auto groupPartsOne = partitionOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partitionTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); const auto& magFieldTesla1 = collision1.magField(); const auto& magFieldTesla2 = collision2.magField(); if (magFieldTesla1 != magFieldTesla2) { - continue; + return; } - for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + // Lambda invariant mass cut + if (!invMLambda(p2.mLambda(), p2.mAntiLambda())) + continue; + /// PID using stored binned nsigma + if (!isParticleCombined(p1, confTrackChoicePartOne)) + continue; + + const auto& posChild = parts.iteratorAt(p2.globalIndex() - 2); + const auto& negChild = parts.iteratorAt(p2.globalIndex() - 1); + /// Daughters that do not pass this condition are not selected + if (!isParticleTPC(posChild, V0ChildTable[confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[confV0Type1][1])) + continue; + // track cleaning if (!pairCleaner.isCleanPair(p1, p2, parts)) { continue; } - if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla1, femtoUniverseContainer::EventType::mixed)) { + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { continue; } } - /// PID using stored binned nsigma - if (!IsParticleCombined(p1, ConfTrackChoicePartOne)) + float weight = 1.0f; + if (plocalEffp1) + weight = plocalEffp1.get()->GetBinContent(plocalEffp1->FindBin(p1.pt(), p1.eta())) * plocalEffp2.get()->GetBinContent(plocalEffp2->FindBin(p2.pt(), p2.eta())); + + if constexpr (std::is_same::value) + mixedEventCont.setPair(p1, p2, multCol, confUse3D, weight); + else + mixedEventCont.setPair(p1, p2, multCol, confUse3D, weight); + } + }; + + if (confUseCent) { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningCent, confNEventsMix, -1, cols, cols)) { + mixedCollProcessFunc(collision1, collision2); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningCent.getBin({collision1.posZ(), collision1.multV0M()})); + } + } else { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningMult, confNEventsMix, -1, cols, cols)) { + mixedCollProcessFunc(collision1, collision2); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningMult.getBin({collision1.posZ(), collision1.multNtr()})); + } + } + } + + /// This function processes the mixed event for V0 - V0 + template + void doMixedEventV0(FilteredFDCollisions const& cols, PartType const& parts, PartitionType& partitionTwo, [[maybe_unused]] MCParticles mcParts = nullptr) + { + ColumnBinningPolicy colBinningMult{{confVtxBins, confMultBins}, true}; + ColumnBinningPolicy colBinningCent{{confVtxBins, confMultBins}, true}; + + auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { + const int multCol = confUseCent ? collision1.multV0M() : collision1.multNtr(); + + auto groupPartsOne = partitionTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partitionTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + return; + } + + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + // Lambda invariant mass cut for p1 + if (!invMLambda(p1.mLambda(), p1.mAntiLambda())) { + continue; + } + // Lambda invariant mass cut for p2 + if (!invMLambda(p2.mLambda(), p2.mAntiLambda())) { continue; - const auto& posChild = parts.iteratorAt(p2.index() - 2); - const auto& negChild = parts.iteratorAt(p2.index() - 1); + } + + const auto& posChild1 = parts.iteratorAt(p1.globalIndex() - 2); + const auto& negChild1 = parts.iteratorAt(p1.globalIndex() - 1); /// Daughters that do not pass this condition are not selected - if (!IsParticleTPC(posChild, V0ChildTable[ConfV0Type1][0]) || !IsParticleTPC(negChild, V0ChildTable[ConfV0Type1][1])) + if (!isParticleTPC(posChild1, V0ChildTable[confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[confV0Type1][1])) continue; - mixedEventCont.setPair(p1, p2, multCol, ConfUse3D); + const auto& posChild2 = parts.iteratorAt(p2.globalIndex() - 2); + const auto& negChild2 = parts.iteratorAt(p2.globalIndex() - 1); + /// Daughters that do not pass this condition are not selected + if (!isParticleTPC(posChild2, V0ChildTable[confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[confV0Type2][1])) + continue; + + // track cleaning + if (!pairCleanerV0.isCleanPair(p1, p2, parts)) { + continue; + } + if (confIsCPR.value) { + if (pairCloseRejectionV0.isClosePair(p1, p2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { + continue; + } + } + + if constexpr (std::is_same::value) + mixedEventCont.setPair(p1, p2, multCol, confUse3D); + else + mixedEventCont.setPair(p1, p2, multCol, confUse3D); + } + }; + + if (confUseCent) { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningCent, confNEventsMix, -1, cols, cols)) { + mixedCollProcessFunc(collision1, collision2); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningCent.getBin({collision1.posZ(), collision1.multV0M()})); + } + } else { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningMult, confNEventsMix, -1, cols, cols)) { + mixedCollProcessFunc(collision1, collision2); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningMult.getBin({collision1.posZ(), collision1.multNtr()})); } } } - PROCESS_SWITCH(femtoUniversePairTaskTrackV0Extended, processMixedEvent, "Enable processing mixed events for track - V0", false); + void processMixedEvent(FilteredFDCollisions const& cols, FemtoFullParticles const& parts) + { + doMixedEvent(cols, parts, partsOne, partsTwo); + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processMixedEvent, "Enable processing mixed event for track - V0", false); - /// This function processes the mixed event for V0 - V0 - void processMixedEventV0(o2::aod::FDCollisions& cols, FemtoFullParticles& parts) + void processMixedEventMCReco(FilteredFDCollisions const& cols, FemtoRecoParticles const& parts, aod::FdMCParticles const& mcparts) + { + doMixedEvent(cols, parts, partsOneMCReco, partsTwoMCReco, mcparts); + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processMixedEventMCReco, "Enable processing mixed event for track - V0 for MC Reco", false); + + void processMixedEventV0(FilteredFDCollisions const& cols, FemtoFullParticles const& parts) { - ColumnBinningPolicy colBinning{{ConfVtxBins, ConfMultBins}, true}; + doMixedEventV0(cols, parts, partsTwo); + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processMixedEventV0, "Enable processing mixed events for V0 - V0", false); - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + void processMixedEventV0MCReco(FilteredFDCollisions const& cols, FemtoRecoParticles const& parts, aod::FdMCParticles const& mcparts) + { + doMixedEventV0(cols, parts, partsTwoMCReco, mcparts); + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processMixedEventV0MCReco, "Enable processing mixed event for V0 - V0 for MC Reco", false); + + /// This function processes MC mixed events for Track - V0 + void processMCMixedEvent(FilteredFDCollisions const& cols, FemtoFullParticles const& parts) + { + ColumnBinningPolicy colBinningMult{{confVtxBins, confMultBins}, true}; + ColumnBinningPolicy colBinningCent{{confVtxBins, confMultBins}, true}; - const int multCol = collision1.multNtr(); + auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { + const int multCol = confUseCent ? collision1.multV0M() : collision1.multNtr(); - auto groupPartsOne = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); - auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + auto groupPartsOne = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); const auto& magFieldTesla1 = collision1.magField(); const auto& magFieldTesla2 = collision2.magField(); if (magFieldTesla1 != magFieldTesla2) { + return; + } + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + if (static_cast(p1.pidCut()) != confTrkPDGCodePartOne) + continue; + int pdgCode2 = static_cast(p2.pidCut()); + if ((confV0Type1 == 0 && pdgCode2 != kLambda0) || (confV0Type1 == 1 && pdgCode2 != kLambda0Bar)) + continue; + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { + continue; + } + } + mixedEventCont.setPair(p1, p2, multCol, confUse3D); + } + }; + + if (confUseCent) { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningCent, confNEventsMix, -1, cols, cols)) { + mixedCollProcessFunc(collision1, collision2); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningCent.getBin({collision1.posZ(), collision1.multV0M()})); + } + } else { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningMult, confNEventsMix, -1, cols, cols)) { + mixedCollProcessFunc(collision1, collision2); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningMult.getBin({collision1.posZ(), collision1.multNtr()})); + } + } + } + + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processMCMixedEvent, "Enable processing mixed events for MC truth track - V0", false); + + /// This function processes MC mixed events for V0 - V0 + void processMCMixedEventV0(FilteredFDCollisions const& cols, FemtoFullParticles const& /*parts*/) + { + ColumnBinningPolicy colBinningMult{{confVtxBins, confMultBins}, true}; + ColumnBinningPolicy colBinningCent{{confVtxBins, confMultBins}, true}; + + auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { + const int multCol = confUseCent ? collision1.multV0M() : collision1.multNtr(); + + auto groupPartsOne = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + int pdgCode1 = static_cast(p1.pidCut()); + if ((confV0Type1 == 0 && pdgCode1 != kLambda0) || (confV0Type1 == 1 && pdgCode1 != kLambda0Bar)) + continue; + int pdgCode2 = static_cast(p2.pidCut()); + if ((confV0Type2 == 0 && pdgCode2 != kLambda0) || (confV0Type2 == 1 && pdgCode2 != kLambda0Bar)) + continue; + mixedEventCont.setPair(p1, p2, multCol, confUse3D); + } + }; + + if (confUseCent) { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningCent, confNEventsMix, -1, cols, cols)) { + mixedCollProcessFunc(collision1, collision2); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningCent.getBin({collision1.posZ(), collision1.multV0M()})); + } + } else { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningMult, confNEventsMix, -1, cols, cols)) { + mixedCollProcessFunc(collision1, collision2); + mixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningMult.getBin({collision1.posZ(), collision1.multNtr()})); + } + } + } + + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processMCMixedEventV0, "Enable processing mixed events for MC truth V0 - V0", false); + + ///--------------------------------------------MC-------------------------------------------------/// + + /// This function fills MC truth particles from derived MC table + void processMCTruth(aod::FDParticles const& parts) + { + for (const auto& part : parts) { + if (part.partType() != uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) continue; + + int pdgCode = static_cast(part.pidCut()); + const auto& pdgParticle = pdgMC->GetParticle(pdgCode); + if (!pdgParticle) { + continue; + } + + if (pdgCode == kLambda0) { + registryMCtruth.fill(HIST("plus/MCtruthLambda"), part.pt(), part.eta()); + continue; + } else if (pdgCode == kLambda0Bar) { + registryMCtruth.fill(HIST("minus/MCtruthLambda"), part.pt(), part.eta()); + continue; + } + + if (pdgParticle->Charge() > 0.0) { + registryMCtruth.fill(HIST("plus/MCtruthAllPt"), part.pt()); + } + if (pdgCode == kPiPlus) { + registryMCtruth.fill(HIST("plus/MCtruthPi"), part.pt(), part.eta()); + registryMCtruth.fill(HIST("plus/MCtruthPiPt"), part.pt()); + } + if (pdgCode == kProton) { + registryMCtruth.fill(HIST("plus/MCtruthPr"), part.pt(), part.eta()); + registryMCtruth.fill(HIST("plus/MCtruthPrPt"), part.pt()); + } + + if (pdgParticle->Charge() < 0.0) { + registryMCtruth.fill(HIST("minus/MCtruthAllPt"), part.pt()); + } + if (pdgCode == kPiMinus) { + registryMCtruth.fill(HIST("minus/MCtruthPi"), part.pt(), part.eta()); + registryMCtruth.fill(HIST("minus/MCtruthPiPt"), part.pt()); + } + if (pdgCode == kProtonBar) { + registryMCtruth.fill(HIST("minus/MCtruthPr"), part.pt(), part.eta()); + registryMCtruth.fill(HIST("minus/MCtruthPrPt"), part.pt()); + } + } + } + + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processMCTruth, "Process MC truth data", false); + + void processPairFractions(FilteredFDCollisions const& cols, FemtoRecoParticles const& parts) + { + + ColumnBinningPolicy colBinningMult{{confVtxBins, confMultBins}, true}; + ColumnBinningPolicy colBinningCent{{confVtxBins, confMultBins}, true}; + + auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { + auto groupPartsOne = partsOneMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + return; } - for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + // Lambda invariant mass cut + if (!invMLambda(p2.mLambda(), p2.mAntiLambda())) + continue; + /// PID using stored binned nsigma + if (!isParticleCombined(p1, confTrackChoicePartOne)) + continue; + + const auto& posChild = parts.iteratorAt(p2.globalIndex() - 2); + const auto& negChild = parts.iteratorAt(p2.globalIndex() - 1); + /// Daughters that do not pass this condition are not selected + if (!isParticleTPC(posChild, V0ChildTable[confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[confV0Type1][1])) + continue; + // track cleaning - if (!pairCleanerV0.isCleanPair(p1, p2, parts)) { + if (!pairCleaner.isCleanPair(p1, p2, parts)) { continue; } - if (ConfIsCPR.value) { - if (pairCloseRejectionV0.isClosePair(p1, p2, parts, magFieldTesla1, femtoUniverseContainer::EventType::mixed)) { + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { continue; } } - const auto& posChild1 = parts.iteratorAt(p1.index() - 2); - const auto& negChild1 = parts.iteratorAt(p1.index() - 1); + registryMCreco.fill(HIST("motherParticle"), p1.motherPDG(), p2.motherPDG()); + } + }; + + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningCent, confNEventsMix, -1, cols, cols)) { + mixedCollProcessFunc(collision1, collision2); + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processPairFractions, "Process MC data to obtain pair fractions", false); + + void processPairFractionsV0(FilteredFDCollisions const& cols, FemtoRecoParticles const& parts) + { + + ColumnBinningPolicy colBinningMult{{confVtxBins, confMultBins}, true}; + ColumnBinningPolicy colBinningCent{{confVtxBins, confMultBins}, true}; + + auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { + auto groupPartsOne = partsTwoMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + return; + } + + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + // Lambda invariant mass cut for p1 + if (!invMLambda(p1.mLambda(), p1.mAntiLambda())) { + continue; + } + // Lambda invariant mass cut for p2 + if (!invMLambda(p2.mLambda(), p2.mAntiLambda())) { + continue; + } + + const auto& posChild1 = parts.iteratorAt(p1.globalIndex() - 2); + const auto& negChild1 = parts.iteratorAt(p1.globalIndex() - 1); /// Daughters that do not pass this condition are not selected - if (!IsParticleTPC(posChild1, V0ChildTable[ConfV0Type1][0]) || !IsParticleTPC(negChild1, V0ChildTable[ConfV0Type1][1])) + if (!isParticleTPC(posChild1, V0ChildTable[confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[confV0Type1][1])) continue; - const auto& posChild2 = parts.iteratorAt(p2.index() - 2); - const auto& negChild2 = parts.iteratorAt(p2.index() - 1); + const auto& posChild2 = parts.iteratorAt(p2.globalIndex() - 2); + const auto& negChild2 = parts.iteratorAt(p2.globalIndex() - 1); /// Daughters that do not pass this condition are not selected - if (!IsParticleTPC(posChild2, V0ChildTable[ConfV0Type2][0]) || !IsParticleTPC(negChild2, V0ChildTable[ConfV0Type2][1])) + if (!isParticleTPC(posChild2, V0ChildTable[confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[confV0Type2][1])) + continue; + + // track cleaning + if (!pairCleanerV0.isCleanPair(p1, p2, parts)) { continue; + } + if (confIsCPR.value) { + if (pairCloseRejectionV0.isClosePair(p1, p2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { + continue; + } + } - mixedEventCont.setPair(p1, p2, multCol, ConfUse3D); + registryMCreco.fill(HIST("motherParticle"), p1.motherPDG(), p2.motherPDG()); + } + }; + + if (confUseCent) { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningCent, confNEventsMix, -1, cols, cols)) { + mixedCollProcessFunc(collision1, collision2); + } + } else { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningMult, confNEventsMix, -1, cols, cols)) { + mixedCollProcessFunc(collision1, collision2); } } } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processPairFractionsV0, "Process MC data to obtain pair fractions for V0V0 pairs", false); + + void processPairFractionsMCTruthV0(FilteredFDCollisions const& cols, FemtoFullParticles const& /*parts*/) + { + ColumnBinningPolicy colBinningMult{{confVtxBins, confMultBins}, true}; + ColumnBinningPolicy colBinningCent{{confVtxBins, confMultBins}, true}; + + auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { + auto groupPartsOne = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + int pdgCode1 = static_cast(p1.pidCut()); + if ((confV0Type1 == 0 && pdgCode1 != kLambda0) || (confV0Type1 == 1 && pdgCode1 != kLambda0Bar)) + continue; + int pdgCode2 = static_cast(p2.pidCut()); + if ((confV0Type2 == 0 && pdgCode2 != kLambda0) || (confV0Type2 == 1 && pdgCode2 != kLambda0Bar)) + continue; + + registryMCtruth.fill(HIST("motherParticle"), p1.tempFitVar(), p2.tempFitVar()); + } + }; + + if (confUseCent) { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningCent, confNEventsMix, -1, cols, cols)) { + mixedCollProcessFunc(collision1, collision2); + } + } else { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningMult, confNEventsMix, -1, cols, cols)) { + mixedCollProcessFunc(collision1, collision2); + } + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processPairFractionsMCTruthV0, "Process MC data to obtain pair fractions for V0V0 MC truth pairs", false); + + void processMCReco(FemtoRecoParticles const& parts, aod::FdMCParticles const& mcparts) + { + for (const auto& part : parts) { + auto mcPartId = part.fdMCParticleId(); + if (mcPartId == -1) + continue; // no MC particle + const auto& mcpart = mcparts.iteratorAt(mcPartId); + // + if (part.partType() == aod::femtouniverseparticle::ParticleType::kV0) { + if (mcpart.pdgMCTruth() == kLambda0) { + const auto& posChild = parts.iteratorAt(part.globalIndex() - 2); + const auto& negChild = parts.iteratorAt(part.globalIndex() - 1); + /// Daughters that do not pass this condition are not selected + if (isParticleTPC(posChild, 0) && isParticleTPC(negChild, 1)) { + registryMCreco.fill(HIST("plus/MCrecoLambda"), mcpart.pt(), mcpart.eta()); // lambda + if (auto mcpartIdChild = posChild.fdMCParticleId(); mcpartIdChild != -1) { + const auto& mcpartChild = mcparts.iteratorAt(mcpartIdChild); + registryMCreco.fill(HIST("plus/MCrecoLambdaChildPr"), mcpartChild.pt(), mcpartChild.eta()); // lambda proton child + } + if (auto mcpartIdChild = negChild.fdMCParticleId(); mcpartIdChild != -1) { + const auto& mcpartChild = mcparts.iteratorAt(mcpartIdChild); + registryMCreco.fill(HIST("plus/MCrecoLambdaChildPi"), mcpartChild.pt(), mcpartChild.eta()); // lambda pion child + } + } + } else if (mcpart.pdgMCTruth() == kLambda0Bar) { + const auto& posChild = parts.iteratorAt(part.globalIndex() - 2); + const auto& negChild = parts.iteratorAt(part.globalIndex() - 1); + /// Daughters that do not pass this condition are not selected + if (isParticleTPC(posChild, 1) && isParticleTPC(negChild, 0)) { + registryMCreco.fill(HIST("minus/MCrecoLambda"), mcpart.pt(), mcpart.eta()); // anti-lambda + if (auto mcpartIdChild = posChild.fdMCParticleId(); mcpartIdChild != -1) { + const auto& mcpartChild = mcparts.iteratorAt(mcpartIdChild); + registryMCreco.fill(HIST("minus/MCrecoLambdaChildPi"), mcpartChild.pt(), mcpartChild.eta()); // anti-lambda pion child + } + if (auto mcpartIdChild = negChild.fdMCParticleId(); mcpartIdChild != -1) { + const auto& mcpartChild = mcparts.iteratorAt(mcpartIdChild); + registryMCreco.fill(HIST("minus/MCrecoLambdaChildPr"), mcpartChild.pt(), mcpartChild.eta()); // anti-lambda proton child + } + } + } + } else if (part.partType() == aod::femtouniverseparticle::ParticleType::kTrack) { + if (part.sign() > 0) { + registryMCreco.fill(HIST("plus/MCrecoAllPt"), mcpart.pt()); + if (mcpart.pdgMCTruth() == kPiPlus && isNSigmaCombined(part.p(), unPackInTable(part.tpcNSigmaStorePi()), unPackInTable(part.tofNSigmaStorePi()))) { + registryMCreco.fill(HIST("plus/MCrecoPi"), mcpart.pt(), mcpart.eta()); + registryMCreco.fill(HIST("plus/MCrecoPiPt"), mcpart.pt()); + } else if (mcpart.pdgMCTruth() == kProton && isNSigmaCombined(part.p(), unPackInTable(part.tpcNSigmaStorePr()), unPackInTable(part.tofNSigmaStorePr()))) { + registryMCreco.fill(HIST("plus/MCrecoPr"), mcpart.pt(), mcpart.eta()); + registryMCreco.fill(HIST("plus/MCrecoPrPt"), mcpart.pt()); + } + } + + if (part.sign() < 0) { + registryMCreco.fill(HIST("minus/MCrecoAllPt"), mcpart.pt()); + if (mcpart.pdgMCTruth() == kPiMinus && isNSigmaCombined(part.p(), unPackInTable(part.tpcNSigmaStorePi()), unPackInTable(part.tofNSigmaStorePi()))) { + registryMCreco.fill(HIST("minus/MCrecoPi"), mcpart.pt(), mcpart.eta()); + registryMCreco.fill(HIST("minus/MCrecoPiPt"), mcpart.pt()); + } else if (mcpart.pdgMCTruth() == kProtonBar && isNSigmaCombined(part.p(), unPackInTable(part.tpcNSigmaStorePr()), unPackInTable(part.tofNSigmaStorePr()))) { + registryMCreco.fill(HIST("minus/MCrecoPr"), mcpart.pt(), mcpart.eta()); + registryMCreco.fill(HIST("minus/MCrecoPrPt"), mcpart.pt()); + } + } + } // partType + } + } - PROCESS_SWITCH(femtoUniversePairTaskTrackV0Extended, processMixedEventV0, "Enable processing mixed events for V0 - V0", false); + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processMCReco, "Process MC reco data", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow{ - adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), }; return workflow; } diff --git a/PWGCF/FemtoWorld/Core/FemtoWorldPhiSelection.h b/PWGCF/FemtoWorld/Core/FemtoWorldPhiSelection.h index e6581daaa13..39040d70ec0 100644 --- a/PWGCF/FemtoWorld/Core/FemtoWorldPhiSelection.h +++ b/PWGCF/FemtoWorld/Core/FemtoWorldPhiSelection.h @@ -388,7 +388,7 @@ void FemtoWorldPhiSelection::initPhi(HistogramRegistry* registry) } template -bool FemtoWorldPhiSelection::isSelectedMinimal(C const& col, V const& v0, T const& posTrack, T const& negTrack) +bool FemtoWorldPhiSelection::isSelectedMinimal(C const& /*col*/, V const& v0, T const& posTrack, T const& negTrack) { const auto signPos = posTrack.sign(); const auto signNeg = negTrack.sign(); @@ -460,7 +460,7 @@ bool FemtoWorldPhiSelection::isSelectedMinimal(C const& col, V const& v0, T cons } template -void FemtoWorldPhiSelection::fillPhiQA(C const& col, V const& v0, T const& posTrack, T const& negTrack) +void FemtoWorldPhiSelection::fillPhiQA(C const& /*col*/, V const& v0, T const& posTrack, T const& negTrack) { const auto signPos = posTrack.sign(); const auto signNeg = negTrack.sign(); @@ -510,7 +510,7 @@ void FemtoWorldPhiSelection::fillPhiQA(C const& col, V const& v0, T const& posTr } template -void FemtoWorldPhiSelection::fillPhiQAMass(C const& col, V const& MassPhi, T const& posTrack, T const& negTrack, P const& ConfInvMassLowLimit, P const& ConfInvMassUpLimit) +void FemtoWorldPhiSelection::fillPhiQAMass(C const& /*col*/, V const& MassPhi, T const& posTrack, T const& negTrack, P const& /*ConfInvMassLowLimit*/, P const& /*ConfInvMassUpLimit*/) { const auto signPos = posTrack.sign(); const auto signNeg = negTrack.sign(); @@ -652,7 +652,7 @@ void FemtoWorldPhiSelection::fillQA(C const& /*col*/, V const& /*v0*/, T const& } template -void FemtoWorldPhiSelection::fillQAPhi(C const& col, V const& v0, T const& posTrack, T const& negTrack) +void FemtoWorldPhiSelection::fillQAPhi(C const& /*col*/, V const& v0, T const& posTrack, T const& negTrack) { if (mHistogramRegistry) { mHistogramRegistry->fill(HIST(o2::aod::femtoworldparticle::ParticleTypeName[part]) + HIST("/hPtPhi"), v0.pt()); diff --git a/PWGCF/FemtoWorld/TableProducer/femtoWorldProducerTask.cxx b/PWGCF/FemtoWorld/TableProducer/femtoWorldProducerTask.cxx index 7071e232356..ce5b415b275 100644 --- a/PWGCF/FemtoWorld/TableProducer/femtoWorldProducerTask.cxx +++ b/PWGCF/FemtoWorld/TableProducer/femtoWorldProducerTask.cxx @@ -100,114 +100,117 @@ struct femtoWorldProducerTask { Produces outputCollision; Produces outputParts; - // Configurables for D0/D0bar mesons - Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; - Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection Flag for D0bar"}; - Configurable yCandMax{"yCandMax", -1., "max. cand. rapidity"}; - - // Choose if filtering or skimming version is run - Configurable ConfIsTrigger{"ConfIsTrigger", false, "Store all collisions"}; - - // Choose if running on converted data or pilot beam - Configurable ConfIsRun3{"ConfIsRun3", false, "Running on Pilot beam"}; - Configurable ConfIsForceGRP{"ConfIsForceGRP", false, "Set true if the magnetic field configuration is not available in the usual CCDB directory (e.g. for Run 2 converted data or unanchorad Monte Carlo)"}; - /// Event cuts FemtoWorldCollisionSelection colCuts; - Configurable ConfEvtZvtx{"ConfEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; - Configurable ConfEvtTriggerCheck{"ConfEvtTriggerCheck", true, "Evt sel: check for trigger"}; - Configurable ConfEvtTriggerSel{"ConfEvtTriggerSel", kINT7, "Evt sel: trigger"}; - Configurable ConfEvtOfflineCheck{"ConfEvtOfflineCheck", false, "Evt sel: check for offline selection"}; - - Configurable ConfStoreV0{"ConfStoreV0", true, "True: store V0 table"}; - Configurable ConfStorePhi{"ConfStorePhi", true, "True: store Phi table"}; - - // just sanity check to make sure in case there are problems in conversion or MC production it does not affect results - Configurable ConfRejectNotPropagatedTracks{"ConfRejectNotPropagatedTracks", false, "True: reject not propagated tracks"}; - Configurable ConfRejectITSHitandTOFMissing{"ConfRejectITSHitandTOFMissing", false, "True: reject if neither ITS hit nor TOF timing satisfied"}; - FemtoWorldTrackSelection trackCuts; - Configurable> ConfTrkCharge{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kSign, "ConfTrk"), std::vector{-1, 1}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kSign, "Track selection: ")}; - Configurable> ConfTrkPtmin{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kpTMin, "ConfTrk"), std::vector{0.4f, 0.6f, 0.5f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kpTMin, "Track selection: ")}; - Configurable> ConfTrkEta{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kEtaMax, "ConfTrk"), std::vector{0.8f, 0.7f, 0.9f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kEtaMax, "Track selection: ")}; - Configurable> ConfTrkTPCnclsMin{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kTPCnClsMin, "ConfTrk"), std::vector{80.f, 70.f, 60.f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kTPCnClsMin, "Track selection: ")}; - Configurable> ConfTrkTPCfCls{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kTPCfClsMin, "ConfTrk"), std::vector{0.7f, 0.83f, 0.9f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kTPCfClsMin, "Track selection: ")}; - Configurable> ConfTrkTPCcRowsMin{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kTPCcRowsMin, "ConfTrk"), std::vector{70.f, 60.f, 80.f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kTPCcRowsMin, "Track selection: ")}; - Configurable> ConfTrkTPCsCls{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kTPCsClsMax, "ConfTrk"), std::vector{0.1f, 160.f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kTPCsClsMax, "Track selection: ")}; - Configurable> ConfTrkITSnclsMin{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kITSnClsMin, "ConfTrk"), std::vector{-1.f, 2.f, 4.f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kITSnClsMin, "Track selection: ")}; - Configurable> ConfTrkITSnclsIbMin{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kITSnClsIbMin, "ConfTrk"), std::vector{-1.f, 1.f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kITSnClsIbMin, "Track selection: ")}; - Configurable> ConfTrkDCAxyMax{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kDCAxyMax, "ConfTrk"), std::vector{0.1f, 3.5f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kDCAxyMax, "Track selection: ")}; /// here we need an open cut to do the DCA fits later on! - Configurable> ConfTrkDCAzMax{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kDCAzMax, "ConfTrk"), std::vector{0.2f, 3.5f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kDCAzMax, "Track selection: ")}; - /// \todo Reintegrate PID to the general selection container - Configurable> ConfTrkPIDnSigmaMax{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kPIDnSigmaMax, "ConfTrk"), std::vector{3.5f, 3.f, 2.5f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kPIDnSigmaMax, "Track selection: ")}; - Configurable> ConfTrkTPIDspecies{"ConfTrkTPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Kaon, o2::track::PID::Proton, o2::track::PID::Deuteron}, "Trk sel: Particles species for PID"}; - FemtoWorldV0Selection v0Cuts; TrackSelection* o2PhysicsTrackSelection; - /// \todo Labeled array (see Track-Track task) - /// V0 - Configurable> ConfV0Sign{FemtoWorldV0Selection::getSelectionName(femtoWorldV0Selection::kV0Sign, "ConfV0"), std::vector{-1, 1}, FemtoWorldV0Selection::getSelectionHelper(femtoWorldV0Selection::kV0Sign, "V0 selection: ")}; - Configurable> ConfV0PtMin{FemtoWorldV0Selection::getSelectionName(femtoWorldV0Selection::kpTV0Min, "ConfV0"), std::vector{0.3f, 0.4f, 0.5f}, FemtoWorldV0Selection::getSelectionHelper(femtoWorldV0Selection::kpTV0Min, "V0 selection: ")}; - Configurable> ConfDCAV0DaughMax{FemtoWorldV0Selection::getSelectionName(femtoWorldV0Selection::kDCAV0DaughMax, "ConfV0"), std::vector{1.2f, 1.5f}, FemtoWorldV0Selection::getSelectionHelper(femtoWorldV0Selection::kDCAV0DaughMax, "V0 selection: ")}; - Configurable> ConfCPAV0Min{FemtoWorldV0Selection::getSelectionName(femtoWorldV0Selection::kCPAV0Min, "ConfV0"), std::vector{0.99f, 0.995f}, FemtoWorldV0Selection::getSelectionHelper(femtoWorldV0Selection::kCPAV0Min, "V0 selection: ")}; - - Configurable> V0TranRadV0Min{FemtoWorldV0Selection::getSelectionName(femtoWorldV0Selection::kTranRadV0Min, "ConfV0"), std::vector{0.2f}, FemtoWorldV0Selection::getSelectionHelper(femtoWorldV0Selection::kTranRadV0Min, "V0 selection: ")}; - Configurable> V0TranRadV0Max{FemtoWorldV0Selection::getSelectionName(femtoWorldV0Selection::kTranRadV0Max, "ConfV0"), std::vector{100.f}, FemtoWorldV0Selection::getSelectionHelper(femtoWorldV0Selection::kTranRadV0Max, "V0 selection: ")}; - Configurable> V0DecVtxMax{FemtoWorldV0Selection::getSelectionName(femtoWorldV0Selection::kDecVtxMax, "ConfV0"), std::vector{100.f}, FemtoWorldV0Selection::getSelectionHelper(femtoWorldV0Selection::kDecVtxMax, "V0 selection: ")}; - - Configurable> ConfV0DaughCharge{"ConfV0DaughCharge", std::vector{-1, 1}, "V0 Daugh sel: Charge"}; - Configurable> ConfDaughEta{"ConfDaughEta", std::vector{0.8f}, "V0 Daugh sel: max eta"}; - Configurable> ConfV0DaughTPCnclsMin{"ConfV0DaughTPCnclsMin", std::vector{80.f, 70.f, 60.f}, "V0 Daugh sel: Min. nCls TPC"}; - Configurable> ConfV0DaughDCAMin{"ConfV0DaughDCAMin", std::vector{0.05f, 0.06f}, "V0 Daugh sel: Max. DCA Daugh to PV (cm)"}; - Configurable> ConfV0DaughPIDnSigmaMax{"ConfV0DaughPIDnSigmaMax", std::vector{5.f, 4.f}, "V0 Daugh sel: Max. PID nSigma TPC"}; - - Configurable> ConfV0DaughTPIDspecies{"ConfV0DaughTPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Proton}, "V0 Daugh sel: Particles species for PID"}; - - Configurable ConfInvMassLowLimit{"ConfInvMassLowLimit", 1.005, "Lower limit of the V0 invariant mass"}; - Configurable ConfInvMassUpLimit{"ConfInvMassUpLimit", 1.035, "Upper limit of the V0 invariant mass"}; - - Configurable ConfRejectKaons{"ConfRejectKaons", false, "Switch to reject kaons"}; - Configurable ConfInvKaonMassLowLimit{"ConfInvKaonMassLowLimit", 0.48, "Lower limit of the V0 invariant mass for Kaon rejection"}; - Configurable ConfInvKaonMassUpLimit{"ConfInvKaonMassUpLimit", 0.515, "Upper limit of the V0 invariant mass for Kaon rejection"}; - - // PHI Daughters (Kaons) - Configurable ConfInvMassLowLimitPhi{"ConfInvMassLowLimitPhi", 1.011, "Lower limit of the Phi invariant mass"}; // change that to do invariant mass cut - Configurable ConfInvMassUpLimitPhi{"ConfInvMassUpLimitPhi", 1.027, "Upper limit of the Phi invariant mass"}; - Configurable ConfRejectKaonsPhi{"ConfRejectKaonsPhi", false, "Switch to reject kaons"}; - Configurable ConfInvKaonMassLowLimitPhi{"ConfInvKaonMassLowLimitPhi", 0.48, "Lower limit of the Phi invariant mass for Kaon rejection"}; - Configurable ConfInvKaonMassUpLimitPhi{"ConfInvKaonMassUpLimitPhi", 0.515, "Upper limit of the Phi invariant mass for Kaon rejection"}; - Configurable ConfNsigmaTPCTOFKaon{"ConfNsigmaTPCTOFKaon", true, "Use TPC and TOF for PID of Kaons"}; - Configurable ConfNsigmaCombinedKaon{"ConfNsigmaCombinedKaon", 3.0, "TPC and TOF Kaon Sigma (combined) for momentum > 0.4"}; - Configurable ConfNsigmaTPCKaon{"ConfNsigmaTPCKaon", 3.0, "TPC Kaon Sigma for momentum < 0.4"}; - // For Phi (daughter 1) - Configurable ConfPDGCodePartOne{"ConfPDGCodePartOne", 321, "Particle 1 - PDG code"}; - Configurable cfgPtLowPart1{"cfgPtLowPart1", 0.14, "Lower limit for Pt for the first particle"}; - Configurable cfgPtHighPart1{"cfgPtHighPart1", 4.0, "Higher limit for Pt for the first particle"}; - Configurable cfgPLowPart1{"cfgPLowPart1", 0.14, "Lower limit for P for the first particle"}; - Configurable cfgPHighPart1{"cfgPHighPart1", 1.5, "Higher limit for P for the first particle"}; - Configurable cfgEtaLowPart1{"cfgEtaLowPart1", -0.8, "Lower limit for Eta for the first particle"}; - Configurable cfgEtaHighPart1{"cfgEtaHighPart1", 0.8, "Higher limit for Eta for the first particle"}; - Configurable cfgDcaXYPart1{"cfgDcaXYPart1", 2.4, "Value for DCA_XY for the first particle"}; - Configurable cfgDcaZPart1{"cfgDcaZPart1", 3.2, "Value for DCA_Z for the first particle"}; - Configurable cfgTpcClPart1{"cfgTpcClPart1", 88, "Number of tpc clasters for the first particle"}; // min number of found TPC clusters - Configurable cfgTpcCrosRoPart1{"cfgTpcCrosRoPart1", 70, "Number of tpc crossed rows for the first particle"}; // min number of crossed rows - Configurable cfgChi2TpcPart1{"cfgChi2TpcPart1", 4.0, "Chi2 / cluster for the TPC track segment for the first particle"}; - Configurable cfgChi2ItsPart1{"cfgChi2ItsPart1", 36.0, "Chi2 / cluster for the ITS track segment for the first particle"}; - - // For Phi (daughter 2) - Configurable ConfPDGCodePartTwo{"ConfPDGCodePartTwo", 321, "Particle 2 - PDG code"}; - Configurable cfgPtLowPart2{"cfgPtLowPart2", 0.14, "Lower limit for Pt for the second particle"}; - Configurable cfgPtHighPart2{"cfgPtHighPart2", 4.0, "Higher limit for Pt for the second particle"}; - Configurable cfgPLowPart2{"cfgPLowPart2", 0.14, "Lower limit for P for the second particle"}; - Configurable cfgPHighPart2{"cfgPHighPart2", 1.5, "Higher limit for P for the second particle"}; - Configurable cfgEtaLowPart2{"cfgEtaLowPart2", -0.8, "Lower limit for Eta for the second particle"}; - Configurable cfgEtaHighPart2{"cfgEtaHighPart2", 0.8, "Higher limit for Eta for the second particle"}; - Configurable cfgDcaXYPart2{"cfgDcaXYPart2", 2.4, "Value for DCA_XY for the second particle"}; - Configurable cfgDcaZPart2{"cfgDcaZPart2", 3.2, "Value for DCA_Z for the second particle"}; - Configurable cfgTpcClPart2{"cfgTpcClPart2", 88, "Number of tpc clasters for the second particle"}; // min number of found TPC clusters - Configurable cfgTpcCrosRoPart2{"cfgTpcCrosRoPart2", 70, "Number of tpc crossed rows for the second particle"}; // min number of crossed rows - Configurable cfgChi2TpcPart2{"cfgChi2TpcPart2", 4.0, "Chi2 / cluster for the TPC track segment for the second particle"}; - Configurable cfgChi2ItsPart2{"cfgChi2ItsPart2", 36.0, "Chi2 / cluster for the ITS track segment for the second particle"}; + + struct : ConfigurableGroup { + // Configurables for D0/D0bar mesons + Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; + Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection Flag for D0bar"}; + Configurable yCandMax{"yCandMax", -1., "max. cand. rapidity"}; + + // Choose if filtering or skimming version is run + Configurable ConfIsTrigger{"ConfIsTrigger", false, "Store all collisions"}; + + // Choose if running on converted data or pilot beam + Configurable ConfIsRun3{"ConfIsRun3", false, "Running on Pilot beam"}; + Configurable ConfIsForceGRP{"ConfIsForceGRP", false, "Set true if the magnetic field configuration is not available in the usual CCDB directory (e.g. for Run 2 converted data or unanchorad Monte Carlo)"}; + + Configurable ConfEvtZvtx{"ConfEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; + Configurable ConfEvtTriggerCheck{"ConfEvtTriggerCheck", true, "Evt sel: check for trigger"}; + Configurable ConfEvtTriggerSel{"ConfEvtTriggerSel", kINT7, "Evt sel: trigger"}; + Configurable ConfEvtOfflineCheck{"ConfEvtOfflineCheck", false, "Evt sel: check for offline selection"}; + + Configurable ConfStoreV0{"ConfStoreV0", true, "True: store V0 table"}; + Configurable ConfStorePhi{"ConfStorePhi", true, "True: store Phi table"}; + + // just sanity check to make sure in case there are problems in conversion or MC production it does not affect results + Configurable ConfRejectNotPropagatedTracks{"ConfRejectNotPropagatedTracks", false, "True: reject not propagated tracks"}; + Configurable ConfRejectITSHitandTOFMissing{"ConfRejectITSHitandTOFMissing", false, "True: reject if neither ITS hit nor TOF timing satisfied"}; + + Configurable> ConfTrkCharge{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kSign, "ConfTrk"), std::vector{-1, 1}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kSign, "Track selection: ")}; + Configurable> ConfTrkPtmin{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kpTMin, "ConfTrk"), std::vector{0.4f, 0.6f, 0.5f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kpTMin, "Track selection: ")}; + Configurable> ConfTrkEta{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kEtaMax, "ConfTrk"), std::vector{0.8f, 0.7f, 0.9f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kEtaMax, "Track selection: ")}; + Configurable> ConfTrkTPCnclsMin{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kTPCnClsMin, "ConfTrk"), std::vector{80.f, 70.f, 60.f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kTPCnClsMin, "Track selection: ")}; + Configurable> ConfTrkTPCfCls{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kTPCfClsMin, "ConfTrk"), std::vector{0.7f, 0.83f, 0.9f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kTPCfClsMin, "Track selection: ")}; + Configurable> ConfTrkTPCcRowsMin{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kTPCcRowsMin, "ConfTrk"), std::vector{70.f, 60.f, 80.f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kTPCcRowsMin, "Track selection: ")}; + Configurable> ConfTrkTPCsCls{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kTPCsClsMax, "ConfTrk"), std::vector{0.1f, 160.f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kTPCsClsMax, "Track selection: ")}; + Configurable> ConfTrkITSnclsMin{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kITSnClsMin, "ConfTrk"), std::vector{-1.f, 2.f, 4.f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kITSnClsMin, "Track selection: ")}; + Configurable> ConfTrkITSnclsIbMin{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kITSnClsIbMin, "ConfTrk"), std::vector{-1.f, 1.f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kITSnClsIbMin, "Track selection: ")}; + Configurable> ConfTrkDCAxyMax{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kDCAxyMax, "ConfTrk"), std::vector{0.1f, 3.5f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kDCAxyMax, "Track selection: ")}; /// here we need an open cut to do the DCA fits later on! + Configurable> ConfTrkDCAzMax{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kDCAzMax, "ConfTrk"), std::vector{0.2f, 3.5f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kDCAzMax, "Track selection: ")}; + /// \todo Reintegrate PID to the general selection container + Configurable> ConfTrkPIDnSigmaMax{FemtoWorldTrackSelection::getSelectionName(femtoWorldTrackSelection::kPIDnSigmaMax, "ConfTrk"), std::vector{3.5f, 3.f, 2.5f}, FemtoWorldTrackSelection::getSelectionHelper(femtoWorldTrackSelection::kPIDnSigmaMax, "Track selection: ")}; + Configurable> ConfTrkTPIDspecies{"ConfTrkTPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Kaon, o2::track::PID::Proton, o2::track::PID::Deuteron}, "Trk sel: Particles species for PID"}; + + /// \todo Labeled array (see Track-Track task) + /// V0 + Configurable> ConfV0Sign{FemtoWorldV0Selection::getSelectionName(femtoWorldV0Selection::kV0Sign, "ConfV0"), std::vector{-1, 1}, FemtoWorldV0Selection::getSelectionHelper(femtoWorldV0Selection::kV0Sign, "V0 selection: ")}; + Configurable> ConfV0PtMin{FemtoWorldV0Selection::getSelectionName(femtoWorldV0Selection::kpTV0Min, "ConfV0"), std::vector{0.3f, 0.4f, 0.5f}, FemtoWorldV0Selection::getSelectionHelper(femtoWorldV0Selection::kpTV0Min, "V0 selection: ")}; + Configurable> ConfDCAV0DaughMax{FemtoWorldV0Selection::getSelectionName(femtoWorldV0Selection::kDCAV0DaughMax, "ConfV0"), std::vector{1.2f, 1.5f}, FemtoWorldV0Selection::getSelectionHelper(femtoWorldV0Selection::kDCAV0DaughMax, "V0 selection: ")}; + Configurable> ConfCPAV0Min{FemtoWorldV0Selection::getSelectionName(femtoWorldV0Selection::kCPAV0Min, "ConfV0"), std::vector{0.99f, 0.995f}, FemtoWorldV0Selection::getSelectionHelper(femtoWorldV0Selection::kCPAV0Min, "V0 selection: ")}; + + Configurable> V0TranRadV0Min{FemtoWorldV0Selection::getSelectionName(femtoWorldV0Selection::kTranRadV0Min, "ConfV0"), std::vector{0.2f}, FemtoWorldV0Selection::getSelectionHelper(femtoWorldV0Selection::kTranRadV0Min, "V0 selection: ")}; + Configurable> V0TranRadV0Max{FemtoWorldV0Selection::getSelectionName(femtoWorldV0Selection::kTranRadV0Max, "ConfV0"), std::vector{100.f}, FemtoWorldV0Selection::getSelectionHelper(femtoWorldV0Selection::kTranRadV0Max, "V0 selection: ")}; + Configurable> V0DecVtxMax{FemtoWorldV0Selection::getSelectionName(femtoWorldV0Selection::kDecVtxMax, "ConfV0"), std::vector{100.f}, FemtoWorldV0Selection::getSelectionHelper(femtoWorldV0Selection::kDecVtxMax, "V0 selection: ")}; + + Configurable> ConfV0DaughCharge{"ConfV0DaughCharge", std::vector{-1, 1}, "V0 Daugh sel: Charge"}; + Configurable> ConfDaughEta{"ConfDaughEta", std::vector{0.8f}, "V0 Daugh sel: max eta"}; + Configurable> ConfV0DaughTPCnclsMin{"ConfV0DaughTPCnclsMin", std::vector{80.f, 70.f, 60.f}, "V0 Daugh sel: Min. nCls TPC"}; + Configurable> ConfV0DaughDCAMin{"ConfV0DaughDCAMin", std::vector{0.05f, 0.06f}, "V0 Daugh sel: Max. DCA Daugh to PV (cm)"}; + Configurable> ConfV0DaughPIDnSigmaMax{"ConfV0DaughPIDnSigmaMax", std::vector{5.f, 4.f}, "V0 Daugh sel: Max. PID nSigma TPC"}; + + Configurable> ConfV0DaughTPIDspecies{"ConfV0DaughTPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Proton}, "V0 Daugh sel: Particles species for PID"}; + + Configurable ConfInvMassLowLimit{"ConfInvMassLowLimit", 1.005, "Lower limit of the V0 invariant mass"}; + Configurable ConfInvMassUpLimit{"ConfInvMassUpLimit", 1.035, "Upper limit of the V0 invariant mass"}; + + Configurable ConfRejectKaons{"ConfRejectKaons", false, "Switch to reject kaons"}; + Configurable ConfInvKaonMassLowLimit{"ConfInvKaonMassLowLimit", 0.48, "Lower limit of the V0 invariant mass for Kaon rejection"}; + Configurable ConfInvKaonMassUpLimit{"ConfInvKaonMassUpLimit", 0.515, "Upper limit of the V0 invariant mass for Kaon rejection"}; + + // PHI Daughters (Kaons) + Configurable ConfInvMassLowLimitPhi{"ConfInvMassLowLimitPhi", 1.011, "Lower limit of the Phi invariant mass"}; // change that to do invariant mass cut + Configurable ConfInvMassUpLimitPhi{"ConfInvMassUpLimitPhi", 1.027, "Upper limit of the Phi invariant mass"}; + Configurable ConfRejectKaonsPhi{"ConfRejectKaonsPhi", false, "Switch to reject kaons"}; + Configurable ConfInvKaonMassLowLimitPhi{"ConfInvKaonMassLowLimitPhi", 0.48, "Lower limit of the Phi invariant mass for Kaon rejection"}; + Configurable ConfInvKaonMassUpLimitPhi{"ConfInvKaonMassUpLimitPhi", 0.515, "Upper limit of the Phi invariant mass for Kaon rejection"}; + Configurable ConfNsigmaTPCTOFKaon{"ConfNsigmaTPCTOFKaon", true, "Use TPC and TOF for PID of Kaons"}; + Configurable ConfNsigmaCombinedKaon{"ConfNsigmaCombinedKaon", 3.0, "TPC and TOF Kaon Sigma (combined) for momentum > 0.4"}; + Configurable ConfNsigmaTPCKaon{"ConfNsigmaTPCKaon", 3.0, "TPC Kaon Sigma for momentum < 0.4"}; + // For Phi (daughter 1) + Configurable ConfPDGCodePartOne{"ConfPDGCodePartOne", 321, "Particle 1 - PDG code"}; + Configurable cfgPtLowPart1{"cfgPtLowPart1", 0.14, "Lower limit for Pt for the first particle"}; + Configurable cfgPtHighPart1{"cfgPtHighPart1", 4.0, "Higher limit for Pt for the first particle"}; + Configurable cfgPLowPart1{"cfgPLowPart1", 0.14, "Lower limit for P for the first particle"}; + Configurable cfgPHighPart1{"cfgPHighPart1", 1.5, "Higher limit for P for the first particle"}; + Configurable cfgEtaLowPart1{"cfgEtaLowPart1", -0.8, "Lower limit for Eta for the first particle"}; + Configurable cfgEtaHighPart1{"cfgEtaHighPart1", 0.8, "Higher limit for Eta for the first particle"}; + Configurable cfgDcaXYPart1{"cfgDcaXYPart1", 2.4, "Value for DCA_XY for the first particle"}; + Configurable cfgDcaZPart1{"cfgDcaZPart1", 3.2, "Value for DCA_Z for the first particle"}; + Configurable cfgTpcClPart1{"cfgTpcClPart1", 88, "Number of tpc clasters for the first particle"}; // min number of found TPC clusters + Configurable cfgTpcCrosRoPart1{"cfgTpcCrosRoPart1", 70, "Number of tpc crossed rows for the first particle"}; // min number of crossed rows + Configurable cfgChi2TpcPart1{"cfgChi2TpcPart1", 4.0, "Chi2 / cluster for the TPC track segment for the first particle"}; + Configurable cfgChi2ItsPart1{"cfgChi2ItsPart1", 36.0, "Chi2 / cluster for the ITS track segment for the first particle"}; + + // For Phi (daughter 2) + Configurable ConfPDGCodePartTwo{"ConfPDGCodePartTwo", 321, "Particle 2 - PDG code"}; + Configurable cfgPtLowPart2{"cfgPtLowPart2", 0.14, "Lower limit for Pt for the second particle"}; + Configurable cfgPtHighPart2{"cfgPtHighPart2", 4.0, "Higher limit for Pt for the second particle"}; + Configurable cfgPLowPart2{"cfgPLowPart2", 0.14, "Lower limit for P for the second particle"}; + Configurable cfgPHighPart2{"cfgPHighPart2", 1.5, "Higher limit for P for the second particle"}; + Configurable cfgEtaLowPart2{"cfgEtaLowPart2", -0.8, "Lower limit for Eta for the second particle"}; + Configurable cfgEtaHighPart2{"cfgEtaHighPart2", 0.8, "Higher limit for Eta for the second particle"}; + Configurable cfgDcaXYPart2{"cfgDcaXYPart2", 2.4, "Value for DCA_XY for the second particle"}; + Configurable cfgDcaZPart2{"cfgDcaZPart2", 3.2, "Value for DCA_Z for the second particle"}; + Configurable cfgTpcClPart2{"cfgTpcClPart2", 88, "Number of tpc clasters for the second particle"}; // min number of found TPC clusters + Configurable cfgTpcCrosRoPart2{"cfgTpcCrosRoPart2", 70, "Number of tpc crossed rows for the second particle"}; // min number of crossed rows + Configurable cfgChi2TpcPart2{"cfgChi2TpcPart2", 4.0, "Chi2 / cluster for the TPC track segment for the second particle"}; + Configurable cfgChi2ItsPart2{"cfgChi2ItsPart2", 36.0, "Chi2 / cluster for the ITS track segment for the second particle"}; + } config; // PHI Candidates FemtoWorldPhiSelection PhiCuts; @@ -223,64 +226,64 @@ struct femtoWorldProducerTask { void init(InitContext&) { - colCuts.setCuts(ConfEvtZvtx, ConfEvtTriggerCheck, ConfEvtTriggerSel, ConfEvtOfflineCheck, ConfIsRun3); + colCuts.setCuts(config.ConfEvtZvtx, config.ConfEvtTriggerCheck, config.ConfEvtTriggerSel, config.ConfEvtOfflineCheck, config.ConfIsRun3); colCuts.init(&qaRegistry); - trackCuts.setSelection(ConfTrkCharge, femtoWorldTrackSelection::kSign, femtoWorldSelection::kEqual); - trackCuts.setSelection(ConfTrkPtmin, femtoWorldTrackSelection::kpTMin, femtoWorldSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkEta, femtoWorldTrackSelection::kEtaMax, femtoWorldSelection::kAbsUpperLimit); - trackCuts.setSelection(ConfTrkTPCnclsMin, femtoWorldTrackSelection::kTPCnClsMin, femtoWorldSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkTPCfCls, femtoWorldTrackSelection::kTPCfClsMin, femtoWorldSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkTPCcRowsMin, femtoWorldTrackSelection::kTPCcRowsMin, femtoWorldSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkTPCsCls, femtoWorldTrackSelection::kTPCsClsMax, femtoWorldSelection::kUpperLimit); - trackCuts.setSelection(ConfTrkITSnclsMin, femtoWorldTrackSelection::kITSnClsMin, femtoWorldSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkITSnclsIbMin, femtoWorldTrackSelection::kITSnClsIbMin, femtoWorldSelection::kLowerLimit); - trackCuts.setSelection(ConfTrkDCAxyMax, femtoWorldTrackSelection::kDCAxyMax, femtoWorldSelection::kAbsUpperLimit); - trackCuts.setSelection(ConfTrkDCAzMax, femtoWorldTrackSelection::kDCAzMax, femtoWorldSelection::kAbsUpperLimit); - trackCuts.setSelection(ConfTrkPIDnSigmaMax, femtoWorldTrackSelection::kPIDnSigmaMax, femtoWorldSelection::kAbsUpperLimit); - trackCuts.setPIDSpecies(ConfTrkTPIDspecies); + trackCuts.setSelection(config.ConfTrkCharge, femtoWorldTrackSelection::kSign, femtoWorldSelection::kEqual); + trackCuts.setSelection(config.ConfTrkPtmin, femtoWorldTrackSelection::kpTMin, femtoWorldSelection::kLowerLimit); + trackCuts.setSelection(config.ConfTrkEta, femtoWorldTrackSelection::kEtaMax, femtoWorldSelection::kAbsUpperLimit); + trackCuts.setSelection(config.ConfTrkTPCnclsMin, femtoWorldTrackSelection::kTPCnClsMin, femtoWorldSelection::kLowerLimit); + trackCuts.setSelection(config.ConfTrkTPCfCls, femtoWorldTrackSelection::kTPCfClsMin, femtoWorldSelection::kLowerLimit); + trackCuts.setSelection(config.ConfTrkTPCcRowsMin, femtoWorldTrackSelection::kTPCcRowsMin, femtoWorldSelection::kLowerLimit); + trackCuts.setSelection(config.ConfTrkTPCsCls, femtoWorldTrackSelection::kTPCsClsMax, femtoWorldSelection::kUpperLimit); + trackCuts.setSelection(config.ConfTrkITSnclsMin, femtoWorldTrackSelection::kITSnClsMin, femtoWorldSelection::kLowerLimit); + trackCuts.setSelection(config.ConfTrkITSnclsIbMin, femtoWorldTrackSelection::kITSnClsIbMin, femtoWorldSelection::kLowerLimit); + trackCuts.setSelection(config.ConfTrkDCAxyMax, femtoWorldTrackSelection::kDCAxyMax, femtoWorldSelection::kAbsUpperLimit); + trackCuts.setSelection(config.ConfTrkDCAzMax, femtoWorldTrackSelection::kDCAzMax, femtoWorldSelection::kAbsUpperLimit); + trackCuts.setSelection(config.ConfTrkPIDnSigmaMax, femtoWorldTrackSelection::kPIDnSigmaMax, femtoWorldSelection::kAbsUpperLimit); + trackCuts.setPIDSpecies(config.ConfTrkTPIDspecies); trackCuts.init(&qaRegistry); /// \todo fix how to pass array to setSelection, getRow() passing a different type! // v0Cuts.setSelection(ConfV0Selection->getRow(0), femtoWorldV0Selection::kDecVtxMax, femtoWorldSelection::kAbsUpperLimit); - if (ConfStoreV0) { - v0Cuts.setSelection(ConfV0Sign, femtoWorldV0Selection::kV0Sign, femtoWorldSelection::kEqual); - v0Cuts.setSelection(ConfV0PtMin, femtoWorldV0Selection::kpTV0Min, femtoWorldSelection::kLowerLimit); - v0Cuts.setSelection(ConfDCAV0DaughMax, femtoWorldV0Selection::kDCAV0DaughMax, femtoWorldSelection::kUpperLimit); - v0Cuts.setSelection(ConfCPAV0Min, femtoWorldV0Selection::kCPAV0Min, femtoWorldSelection::kLowerLimit); - - v0Cuts.setChildCuts(femtoWorldV0Selection::kPosTrack, ConfV0DaughCharge, femtoWorldTrackSelection::kSign, femtoWorldSelection::kEqual); - v0Cuts.setChildCuts(femtoWorldV0Selection::kPosTrack, ConfDaughEta, femtoWorldTrackSelection::kEtaMax, femtoWorldSelection::kAbsUpperLimit); - v0Cuts.setChildCuts(femtoWorldV0Selection::kPosTrack, ConfV0DaughTPCnclsMin, femtoWorldTrackSelection::kTPCnClsMin, femtoWorldSelection::kLowerLimit); - v0Cuts.setChildCuts(femtoWorldV0Selection::kPosTrack, ConfV0DaughDCAMin, femtoWorldTrackSelection::kDCAMin, femtoWorldSelection::kAbsLowerLimit); - v0Cuts.setChildCuts(femtoWorldV0Selection::kPosTrack, ConfV0DaughPIDnSigmaMax, femtoWorldTrackSelection::kPIDnSigmaMax, femtoWorldSelection::kAbsUpperLimit); - v0Cuts.setChildCuts(femtoWorldV0Selection::kNegTrack, ConfV0DaughCharge, femtoWorldTrackSelection::kSign, femtoWorldSelection::kEqual); - v0Cuts.setChildCuts(femtoWorldV0Selection::kNegTrack, ConfDaughEta, femtoWorldTrackSelection::kEtaMax, femtoWorldSelection::kAbsUpperLimit); - v0Cuts.setChildCuts(femtoWorldV0Selection::kNegTrack, ConfV0DaughTPCnclsMin, femtoWorldTrackSelection::kTPCnClsMin, femtoWorldSelection::kLowerLimit); - v0Cuts.setChildCuts(femtoWorldV0Selection::kNegTrack, ConfV0DaughDCAMin, femtoWorldTrackSelection::kDCAMin, femtoWorldSelection::kAbsLowerLimit); - v0Cuts.setChildCuts(femtoWorldV0Selection::kNegTrack, ConfV0DaughPIDnSigmaMax, femtoWorldTrackSelection::kPIDnSigmaMax, femtoWorldSelection::kAbsUpperLimit); - v0Cuts.setChildPIDSpecies(femtoWorldV0Selection::kPosTrack, ConfV0DaughTPIDspecies); - v0Cuts.setChildPIDSpecies(femtoWorldV0Selection::kNegTrack, ConfV0DaughTPIDspecies); + if (config.ConfStoreV0) { + v0Cuts.setSelection(config.ConfV0Sign, femtoWorldV0Selection::kV0Sign, femtoWorldSelection::kEqual); + v0Cuts.setSelection(config.ConfV0PtMin, femtoWorldV0Selection::kpTV0Min, femtoWorldSelection::kLowerLimit); + v0Cuts.setSelection(config.ConfDCAV0DaughMax, femtoWorldV0Selection::kDCAV0DaughMax, femtoWorldSelection::kUpperLimit); + v0Cuts.setSelection(config.ConfCPAV0Min, femtoWorldV0Selection::kCPAV0Min, femtoWorldSelection::kLowerLimit); + + v0Cuts.setChildCuts(femtoWorldV0Selection::kPosTrack, config.ConfV0DaughCharge, femtoWorldTrackSelection::kSign, femtoWorldSelection::kEqual); + v0Cuts.setChildCuts(femtoWorldV0Selection::kPosTrack, config.ConfDaughEta, femtoWorldTrackSelection::kEtaMax, femtoWorldSelection::kAbsUpperLimit); + v0Cuts.setChildCuts(femtoWorldV0Selection::kPosTrack, config.ConfV0DaughTPCnclsMin, femtoWorldTrackSelection::kTPCnClsMin, femtoWorldSelection::kLowerLimit); + v0Cuts.setChildCuts(femtoWorldV0Selection::kPosTrack, config.ConfV0DaughDCAMin, femtoWorldTrackSelection::kDCAMin, femtoWorldSelection::kAbsLowerLimit); + v0Cuts.setChildCuts(femtoWorldV0Selection::kPosTrack, config.ConfV0DaughPIDnSigmaMax, femtoWorldTrackSelection::kPIDnSigmaMax, femtoWorldSelection::kAbsUpperLimit); + v0Cuts.setChildCuts(femtoWorldV0Selection::kNegTrack, config.ConfV0DaughCharge, femtoWorldTrackSelection::kSign, femtoWorldSelection::kEqual); + v0Cuts.setChildCuts(femtoWorldV0Selection::kNegTrack, config.ConfDaughEta, femtoWorldTrackSelection::kEtaMax, femtoWorldSelection::kAbsUpperLimit); + v0Cuts.setChildCuts(femtoWorldV0Selection::kNegTrack, config.ConfV0DaughTPCnclsMin, femtoWorldTrackSelection::kTPCnClsMin, femtoWorldSelection::kLowerLimit); + v0Cuts.setChildCuts(femtoWorldV0Selection::kNegTrack, config.ConfV0DaughDCAMin, femtoWorldTrackSelection::kDCAMin, femtoWorldSelection::kAbsLowerLimit); + v0Cuts.setChildCuts(femtoWorldV0Selection::kNegTrack, config.ConfV0DaughPIDnSigmaMax, femtoWorldTrackSelection::kPIDnSigmaMax, femtoWorldSelection::kAbsUpperLimit); + v0Cuts.setChildPIDSpecies(femtoWorldV0Selection::kPosTrack, config.ConfV0DaughTPIDspecies); + v0Cuts.setChildPIDSpecies(femtoWorldV0Selection::kNegTrack, config.ConfV0DaughTPIDspecies); v0Cuts.init(&qaRegistry); - v0Cuts.setInvMassLimits(ConfInvMassLowLimit, ConfInvMassUpLimit); - v0Cuts.setChildRejectNotPropagatedTracks(femtoWorldV0Selection::kPosTrack, ConfRejectNotPropagatedTracks); - v0Cuts.setChildRejectNotPropagatedTracks(femtoWorldV0Selection::kNegTrack, ConfRejectNotPropagatedTracks); + v0Cuts.setInvMassLimits(config.ConfInvMassLowLimit, config.ConfInvMassUpLimit); + v0Cuts.setChildRejectNotPropagatedTracks(femtoWorldV0Selection::kPosTrack, config.ConfRejectNotPropagatedTracks); + v0Cuts.setChildRejectNotPropagatedTracks(femtoWorldV0Selection::kNegTrack, config.ConfRejectNotPropagatedTracks); - if (ConfRejectKaons) { - v0Cuts.setKaonInvMassLimits(ConfInvKaonMassLowLimit, ConfInvKaonMassUpLimit); + if (config.ConfRejectKaons) { + v0Cuts.setKaonInvMassLimits(config.ConfInvKaonMassLowLimit, config.ConfInvKaonMassUpLimit); } - if (ConfRejectITSHitandTOFMissing) { + if (config.ConfRejectITSHitandTOFMissing) { o2PhysicsTrackSelection = new TrackSelection(getGlobalTrackSelection()); o2PhysicsTrackSelection->SetRequireHitsInITSLayers(1, {0, 1, 2, 3}); } } - if (ConfStorePhi) { + if (config.ConfStorePhi) { PhiCuts.init(&qaRegistry); - if (ConfRejectKaonsPhi) { + if (config.ConfRejectKaonsPhi) { //! PhiCuts.setKaonInvMassLimits(ConfInvKaonMassLowLimitPhi, ConfInvKaonMassUpLimitPhi); } - if (ConfRejectITSHitandTOFMissing) { + if (config.ConfRejectITSHitandTOFMissing) { o2PhysicsTrackSelection = new TrackSelection(getGlobalTrackSelection()); o2PhysicsTrackSelection->SetRequireHitsInITSLayers(1, {0, 1, 2, 3}); } @@ -308,15 +311,15 @@ struct femtoWorldProducerTask { // ConfNsigmaTPCTOFKaon -> are we doing TPC TOF PID for Kaons? (boolean) // ConfNsigmaTPCKaon -> TPC Kaon Sigma for momentum < 0.4 // ConfNsigmaCombinedKaon -> TPC and TOF Kaon Sigma (combined) for momentum > 0.4 - if (ConfNsigmaTPCTOFKaon) { + if (config.ConfNsigmaTPCTOFKaon) { if (mom < 0.4) { - if (TMath::Abs(nsigmaTPCK) < ConfNsigmaTPCKaon) { + if (TMath::Abs(nsigmaTPCK) < config.ConfNsigmaTPCKaon) { return true; } else { return false; } } else if (mom > 0.4) { - if (TMath::Hypot(nsigmaTOFK, nsigmaTPCK) < ConfNsigmaCombinedKaon) { + if (TMath::Hypot(nsigmaTOFK, nsigmaTPCK) < config.ConfNsigmaCombinedKaon) { return true; } else { return false; @@ -336,7 +339,7 @@ struct femtoWorldProducerTask { auto timestamp = bc.timestamp(); float output = -999; - if (ConfIsRun3 && !ConfIsForceGRP) { + if (config.ConfIsRun3 && !config.ConfIsForceGRP) { static o2::parameters::GRPMagField* grpo = nullptr; grpo = ccdb->getForTimeStamp("GLO/Config/GRPMagField", timestamp); if (grpo == nullptr) { @@ -378,7 +381,7 @@ struct femtoWorldProducerTask { // in case of skimming run - don't store such collisions // in case of trigger run - store such collisions but don't store any particle candidates for such collisions if (!colCuts.isSelected(col)) { - if (ConfIsTrigger) { + if (config.ConfIsTrigger) { outputCollision(col.posZ(), col.multFV0M(), colCuts.computeSphericity(col, tracks), mMagField, col.centRun2V0M()); } return; @@ -467,7 +470,7 @@ struct femtoWorldProducerTask { // in case of skimming run - don't store such collisions // in case of trigger run - store such collisions but don't store any particle candidates for such collisions if (!colCuts.isSelected(col)) { - if (ConfIsTrigger) { + if (config.ConfIsTrigger) { outputCollision(col.posZ(), col.multFV0M(), colCuts.computeSphericity(col, tracks), mMagField, col.centRun2V0M()); } return; @@ -555,7 +558,7 @@ struct femtoWorldProducerTask { continue; } - if (ConfRejectITSHitandTOFMissing) { + if (config.ConfRejectITSHitandTOFMissing) { // Uncomment only when TOF timing is solved // bool itsHit = o2PhysicsTrackSelection->IsSelected(postrack, TrackSelection::TrackCuts::kITSHits); // bool itsHit = o2PhysicsTrackSelection->IsSelected(negtrack, TrackSelection::TrackCuts::kITSHits); @@ -744,7 +747,7 @@ struct femtoWorldProducerTask { // in case of skimming run - don't store such collisions // in case of trigger run - store such collisions but don't store any particle candidates for such collisions if (!colCuts.isSelected(col)) { - if (ConfIsTrigger) { + if (config.ConfIsTrigger) { outputCollision(col.posZ(), col.multFV0M(), colCuts.computeSphericity(col, tracks), mMagField, col.centRun2V0M()); } return; @@ -825,17 +828,17 @@ struct femtoWorldProducerTask { continue; } else if (p1.globalIndex() == p2.globalIndex()) { // checking not to correlate same particles continue; - } else if ((p1.pt() < cfgPtLowPart1) || (p1.pt() > cfgPtHighPart1)) { // pT cuts for part1 + } else if ((p1.pt() < config.cfgPtLowPart1) || (p1.pt() > config.cfgPtHighPart1)) { // pT cuts for part1 continue; - } else if ((p1.p() < cfgPLowPart1) || (p1.p() > cfgPHighPart1)) { // p cuts for part1 + } else if ((p1.p() < config.cfgPLowPart1) || (p1.p() > config.cfgPHighPart1)) { // p cuts for part1 continue; - } else if ((p1.eta() < cfgEtaLowPart1) || (p1.eta() > cfgEtaHighPart1)) { // eta cuts for part1 + } else if ((p1.eta() < config.cfgEtaLowPart1) || (p1.eta() > config.cfgEtaHighPart1)) { // eta cuts for part1 continue; - } else if ((p2.pt() < cfgPtLowPart2) || (p2.pt() > cfgPtHighPart2)) { // pT cuts for part2 + } else if ((p2.pt() < config.cfgPtLowPart2) || (p2.pt() > config.cfgPtHighPart2)) { // pT cuts for part2 continue; - } else if ((p2.p() < cfgPLowPart2) || (p2.p() > cfgPHighPart2)) { // p cuts for part2 + } else if ((p2.p() < config.cfgPLowPart2) || (p2.p() > config.cfgPHighPart2)) { // p cuts for part2 continue; - } else if ((p2.eta() < cfgEtaLowPart2) || (p2.eta() > cfgEtaHighPart2)) { // eta for part2 + } else if ((p2.eta() < config.cfgEtaLowPart2) || (p2.eta() > config.cfgEtaHighPart2)) { // eta for part2 continue; } else if (!(IsKaonNSigma(p1.p(), p1.tpcNSigmaKa(), p1.tofNSigmaKa()))) { // PID for Kaons continue; @@ -845,8 +848,8 @@ struct femtoWorldProducerTask { TLorentzVector part1Vec; TLorentzVector part2Vec; - float mMassOne = TDatabasePDG::Instance()->GetParticle(ConfPDGCodePartOne)->Mass(); // FIXME: Get from the PDG service of the common header - float mMassTwo = TDatabasePDG::Instance()->GetParticle(ConfPDGCodePartTwo)->Mass(); // FIXME: Get from the PDG service of the common header + float mMassOne = TDatabasePDG::Instance()->GetParticle(config.ConfPDGCodePartOne)->Mass(); // FIXME: Get from the PDG service of the common header + float mMassTwo = TDatabasePDG::Instance()->GetParticle(config.ConfPDGCodePartTwo)->Mass(); // FIXME: Get from the PDG service of the common header part1Vec.SetPtEtaPhiM(p1.pt(), p1.eta(), p1.phi(), mMassOne); part2Vec.SetPtEtaPhiM(p2.pt(), p2.eta(), p2.phi(), mMassTwo); @@ -859,7 +862,7 @@ struct femtoWorldProducerTask { float phiP = sumVec.P(); float phiM = sumVec.M(); - if (((phiM < ConfInvMassLowLimitPhi) || (phiM > ConfInvMassUpLimitPhi))) { + if (((phiM < config.ConfInvMassLowLimitPhi) || (phiM > config.ConfInvMassUpLimitPhi))) { continue; } @@ -1052,7 +1055,7 @@ struct femtoWorldProducerTask { // in case of skimming run - don't store such collisions // in case of trigger run - store such collisions but don't store any particle candidates for such collisions if (!colCuts.isSelected(col)) { - if (ConfIsTrigger) { + if (config.ConfIsTrigger) { outputCollision(col.posZ(), col.multFV0M(), colCuts.computeSphericity(col, tracks), mMagField, col.centRun2V0M()); } return; @@ -1147,7 +1150,7 @@ struct femtoWorldProducerTask { if (!(candidate.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yD0(candidate)) > yCandMax) { + if (config.yCandMax >= 0. && std::abs(hfHelper.yD0(candidate)) > config.yCandMax) { continue; } @@ -1155,7 +1158,7 @@ struct femtoWorldProducerTask { auto posDauTrack = candidate.prong0_as(); // positive daughter auto negDauTrack = candidate.prong1_as(); // negative daughter - if ((candidate.isSelD0() >= selectionFlagD0) || (candidate.isSelD0bar() >= selectionFlagD0bar)) { // temporary true value, we are doing simpler version first + if ((candidate.isSelD0() >= config.selectionFlagD0) || (candidate.isSelD0bar() >= config.selectionFlagD0bar)) { // temporary true value, we are doing simpler version first int postrackID = candidate.prong0Id(); int rowInPrimaryTrackTablePos = -1; rowInPrimaryTrackTablePos = getRowDaughters(postrackID, tmpIDtrack); @@ -1336,7 +1339,7 @@ struct femtoWorldProducerTask { // in case of skimming run - don't store such collisions // in case of trigger run - store such collisions but don't store any particle candidates for such collisions if (!colCuts.isSelected(col)) { - if (ConfIsTrigger) { + if (config.ConfIsTrigger) { outputCollision(col.posZ(), col.multFV0M(), colCuts.computeSphericity(col, tracks), mMagField, col.centFT0M()); } return; @@ -1425,7 +1428,7 @@ struct femtoWorldProducerTask { // in case of skimming run - don't store such collisions // in case of trigger run - store such collisions but don't store any particle candidates for such collisions if (!colCuts.isSelected(col)) { - if (ConfIsTrigger) { + if (config.ConfIsTrigger) { outputCollision(col.posZ(), col.multFV0M(), colCuts.computeSphericity(col, tracks), mMagField, col.centFT0M()); } return; @@ -1501,7 +1504,7 @@ struct femtoWorldProducerTask { tmpIDtrack.push_back(track.globalIndex()); } - if (ConfStoreV0) { + if (config.ConfStoreV0) { for (auto& v0 : fullV0s) { auto postrack = v0.posTrack_as(); auto negtrack = v0.negTrack_as(); ///\tocheck funnily enough if we apply the filter the sign of Pos and Neg track is always negative @@ -1514,7 +1517,7 @@ struct femtoWorldProducerTask { continue; } - if (ConfRejectITSHitandTOFMissing) { + if (config.ConfRejectITSHitandTOFMissing) { // Uncomment only when TOF timing is solved // bool itsHit = o2PhysicsTrackSelection->IsSelected(postrack, TrackSelection::TrackCuts::kITSHits); // bool itsHit = o2PhysicsTrackSelection->IsSelected(negtrack, TrackSelection::TrackCuts::kITSHits); @@ -1704,7 +1707,7 @@ struct femtoWorldProducerTask { // in case of skimming run - don't store such collisions // in case of trigger run - store such collisions but don't store any particle candidates for such collisions if (!colCuts.isSelected(col)) { - if (ConfIsTrigger) { + if (config.ConfIsTrigger) { outputCollision(col.posZ(), col.multFV0M(), colCuts.computeSphericity(col, tracks), mMagField, col.centFT0M()); } return; @@ -1785,17 +1788,17 @@ struct femtoWorldProducerTask { continue; } else if (p1.globalIndex() == p2.globalIndex()) { // checking not to correlate same particles continue; - } else if ((p1.pt() < cfgPtLowPart1) || (p1.pt() > cfgPtHighPart1)) { // pT cuts for part1 + } else if ((p1.pt() < config.cfgPtLowPart1) || (p1.pt() > config.cfgPtHighPart1)) { // pT cuts for part1 continue; - } else if ((p1.p() < cfgPLowPart1) || (p1.p() > cfgPHighPart1)) { // p cuts for part1 + } else if ((p1.p() < config.cfgPLowPart1) || (p1.p() > config.cfgPHighPart1)) { // p cuts for part1 continue; - } else if ((p1.eta() < cfgEtaLowPart1) || (p1.eta() > cfgEtaHighPart1)) { // eta cuts for part1 + } else if ((p1.eta() < config.cfgEtaLowPart1) || (p1.eta() > config.cfgEtaHighPart1)) { // eta cuts for part1 continue; - } else if ((p2.pt() < cfgPtLowPart2) || (p2.pt() > cfgPtHighPart2)) { // pT cuts for part2 + } else if ((p2.pt() < config.cfgPtLowPart2) || (p2.pt() > config.cfgPtHighPart2)) { // pT cuts for part2 continue; - } else if ((p2.p() < cfgPLowPart2) || (p2.p() > cfgPHighPart2)) { // p cuts for part2 + } else if ((p2.p() < config.cfgPLowPart2) || (p2.p() > config.cfgPHighPart2)) { // p cuts for part2 continue; - } else if ((p2.eta() < cfgEtaLowPart2) || (p2.eta() > cfgEtaHighPart2)) { // eta for part2 + } else if ((p2.eta() < config.cfgEtaLowPart2) || (p2.eta() > config.cfgEtaHighPart2)) { // eta for part2 continue; } else if (!(IsKaonNSigma(p1.p(), p1.tpcNSigmaKa(), p1.tofNSigmaKa()))) { // PID for Kaons continue; @@ -1805,8 +1808,8 @@ struct femtoWorldProducerTask { TLorentzVector part1Vec; TLorentzVector part2Vec; - float mMassOne = TDatabasePDG::Instance()->GetParticle(ConfPDGCodePartOne)->Mass(); // FIXME: Get from the PDG service of the common header - float mMassTwo = TDatabasePDG::Instance()->GetParticle(ConfPDGCodePartTwo)->Mass(); // FIXME: Get from the PDG service of the common header + float mMassOne = TDatabasePDG::Instance()->GetParticle(config.ConfPDGCodePartOne)->Mass(); // FIXME: Get from the PDG service of the common header + float mMassTwo = TDatabasePDG::Instance()->GetParticle(config.ConfPDGCodePartTwo)->Mass(); // FIXME: Get from the PDG service of the common header part1Vec.SetPtEtaPhiM(p1.pt(), p1.eta(), p1.phi(), mMassOne); part2Vec.SetPtEtaPhiM(p2.pt(), p2.eta(), p2.phi(), mMassTwo); @@ -1819,7 +1822,7 @@ struct femtoWorldProducerTask { float phiP = sumVec.P(); float phiM = sumVec.M(); - if (((phiM < ConfInvMassLowLimitPhi) || (phiM > ConfInvMassUpLimitPhi))) { + if (((phiM < config.ConfInvMassLowLimitPhi) || (phiM > config.ConfInvMassUpLimitPhi))) { continue; } @@ -2013,7 +2016,7 @@ struct femtoWorldProducerTask { // in case of skimming run - don't store such collisions // in case of trigger run - store such collisions but don't store any particle candidates for such collisions if (!colCuts.isSelected(col)) { - if (ConfIsTrigger) { + if (config.ConfIsTrigger) { outputCollision(col.posZ(), col.multFT0M(), colCuts.computeSphericity(col, tracks), mMagField, col.centFT0M()); } return; @@ -2094,7 +2097,7 @@ struct femtoWorldProducerTask { if (!(candidate.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yD0(candidate)) > yCandMax) { + if (config.yCandMax >= 0. && std::abs(hfHelper.yD0(candidate)) > config.yCandMax) { continue; } diff --git a/PWGCF/FemtoWorld/Tasks/femtoWorldEfficiencyTask.cxx b/PWGCF/FemtoWorld/Tasks/femtoWorldEfficiencyTask.cxx index e7812a0afea..9cad450302f 100644 --- a/PWGCF/FemtoWorld/Tasks/femtoWorldEfficiencyTask.cxx +++ b/PWGCF/FemtoWorld/Tasks/femtoWorldEfficiencyTask.cxx @@ -168,6 +168,15 @@ struct femtoWorldEficiencyTask { registryPri.add("plus/TOFmatchingPr", ";#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); registryPri.add("minus/TOFmatchingPr", ";#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + registryPri.add("plus/GenPriPi", ";#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + registryPri.add("minus/GenPriPi", ";#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + + registryPri.add("plus/GenPriKa", ";#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + registryPri.add("minus/GenPriKa", ";#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + + registryPri.add("plus/GenPriPr", ";#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + registryPri.add("minus/GenPriPr", ";#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); + // Pri our tracking cuts only registryPriCuts.add("plus/PiPriPt", "PiPri;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); registryPriCuts.add("plus/KaPriPt", "KaPri;#it{p}_{T} (GeV/c)", {HistType::kTH1F, {{500, 0, 5}}}); @@ -417,6 +426,16 @@ struct femtoWorldEficiencyTask { // PID only registryPri.fill(HIST("plus/AllPri"), track.pt(), track.eta()); registryPri.fill(HIST("plus/AllPriPt"), mcParticle.pt()); + // generated primary, no cuts, no nsigma + if (mcParticle.pdgCode() == 211) { + registryPri.fill(HIST("plus/GenPriPi"), mcParticle.pt()); + } + if (mcParticle.pdgCode() == 321) { + registryPri.fill(HIST("plus/GenPriKa"), mcParticle.pt()); + } + if (mcParticle.pdgCode() == 2212) { + registryPri.fill(HIST("plus/GenPriPr"), mcParticle.pt()); + } // histogram pt TOF matching if (track.hasTOF()) { registryPri.fill(HIST("plus/TOFmatchingAll"), mcParticle.pt()); @@ -458,6 +477,16 @@ struct femtoWorldEficiencyTask { // PID only registryPri.fill(HIST("minus/AllPri"), track.pt(), track.eta()); registryPri.fill(HIST("minus/AllPriPt"), mcParticle.pt()); + // generated primary, no cuts, no nsigma + if (mcParticle.pdgCode() == -211) { + registryPri.fill(HIST("minus/GenPriPi"), mcParticle.pt()); + } + if (mcParticle.pdgCode() == -321) { + registryPri.fill(HIST("minus/GenPriKa"), mcParticle.pt()); + } + if (mcParticle.pdgCode() == -2212) { + registryPri.fill(HIST("minus/GenPriPr"), mcParticle.pt()); + } // histogram pt TOF matching if (track.hasTOF()) { registryPri.fill(HIST("minus/TOFmatchingAll"), mcParticle.pt()); diff --git a/PWGCF/FemtoWorld/Tasks/femtoWorldHashTask.cxx b/PWGCF/FemtoWorld/Tasks/femtoWorldHashTask.cxx index a9c678bc2e5..4a6bdac3a2b 100644 --- a/PWGCF/FemtoWorld/Tasks/femtoWorldHashTask.cxx +++ b/PWGCF/FemtoWorld/Tasks/femtoWorldHashTask.cxx @@ -33,7 +33,7 @@ struct femtoWorldPairHashTask { std::vector CastCfgVtxBins, CastCfgMultBins; - Produces hashes; + Produces hashes; void init(InitContext&) { diff --git a/PWGCF/Flow/TableProducer/CMakeLists.txt b/PWGCF/Flow/TableProducer/CMakeLists.txt index bbfd7adac2b..8774e589414 100644 --- a/PWGCF/Flow/TableProducer/CMakeLists.txt +++ b/PWGCF/Flow/TableProducer/CMakeLists.txt @@ -8,3 +8,9 @@ # 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(zdc-q-vectors + SOURCES zdcQVectors.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + COMPONENT_NAME Analysis) \ No newline at end of file diff --git a/PWGCF/Flow/TableProducer/zdcQVectors.cxx b/PWGCF/Flow/TableProducer/zdcQVectors.cxx new file mode 100644 index 00000000000..21fcbdc3c55 --- /dev/null +++ b/PWGCF/Flow/TableProducer/zdcQVectors.cxx @@ -0,0 +1,770 @@ +// 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 zdcQVectors.cxx +/// \author Noor Koster +/// \since 11/2024 +/// \brief In this task the energy calibration and recentring of Q-vectors constructed in the ZDCs will be done + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CCDB/BasicCCDBManager.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/EventSelection.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StaticFor.h" + +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/Track.h" +#include "PWGCF/DataModel/SPTableZDC.h" + +#include "TH1F.h" +#include "TH2F.h" +#include "TProfile.h" +#include "TObjArray.h" +#include "TF1.h" +#include "TFitResult.h" +#include "TCanvas.h" +#include "TSystem.h" +#include "TROOT.h" + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::track; +using namespace o2::aod::evsel; + +namespace o2::analysis::qvectortask +{ +int counter = 0; + +// Define histogrm names here to use same names for creating and later uploading and retrieving data from ccdb +// Energy calibration: +std::vector namesEcal(10, ""); +std::vector> names(5, std::vector()); //(1x 4d 4x 1d) +std::vector vnames = {"hvertex_vx", "hvertex_vy"}; + +// https://alice-notes.web.cern.ch/system/files/notes/analysis/620/017-May-31-analysis_note-ALICE_analysis_note_v2.pdf +std::vector pxZDC = {-1.75, 1.75, -1.75, 1.75}; +std::vector pyZDC = {-1.75, -1.75, 1.75, 1.75}; +double alphaZDC = 0.395; + +// q-vectors before (q) and after (qRec) recentering. +std::vector q(4); // start values of [QxA, QyA, QxC, QyC] + +// for energy calibration +std::vector eZN(8); // uncalibrated energy for the 2x4 towers (a1, a2, a3, a4, c1, c2, c3, c4) +std::vector meanEZN(10); // mean energies from calibration histos (common A, t1-4 A,common C, t1-4C) +std::vector e(8, 0.); // calibrated energies (a1, a2, a3, a4, c1, c2, c3, c4)) + +// Define variables needed to do the recentring steps. +double centrality = 0; +int runnumber = 0; +int lastRunNumber = 0; +std::vector v(3, 0); // vx, vy, vz +bool isSelected = true; + +} // namespace o2::analysis::qvectortask + +using namespace o2::analysis::qvectortask; + +struct ZdcQVectors { + + Produces spTableZDC; + + ConfigurableAxis axisCent{"axisCent", {90, 0, 90}, "Centrality axis in 1% bins"}; + ConfigurableAxis axisCent10{"axisCent10", {9, 0, 90}, "Centrality axis in 10% bins"}; + ConfigurableAxis axisQ{"axisQ", {100, -2, 2}, "Q vector (xy) in ZDC"}; + ConfigurableAxis axisVxBig{"axisVxBig", {3, -0.01, 0.01}, "for Pos X of collision"}; + ConfigurableAxis axisVyBig{"axisVyBig", {3, -0.01, 0.01}, "for Pos Y of collision"}; + ConfigurableAxis axisVzBig{"axisVzBig", {3, -10, 10}, "for Pos Z of collision"}; + ConfigurableAxis axisVx{"axisVx", {100, -0.01, 0.01}, "for Pos X of collision"}; + ConfigurableAxis axisVy{"axisVy", {100, -0.01, 0.01}, "for Pos Y of collision"}; + ConfigurableAxis axisVz{"axisVz", {100, -10, 10}, "for vz of collision"}; + + // Centrality Estimators -> standard is FT0C + O2_DEFINE_CONFIGURABLE(cfgFT0Cvariant1, bool, false, "Set centrality estimator to cfgFT0Cvariant1"); + O2_DEFINE_CONFIGURABLE(cfgFT0M, bool, false, "Set centrality estimator to cfgFT0M"); + O2_DEFINE_CONFIGURABLE(cfgFV0A, bool, false, "Set centrality estimator to cfgFV0A"); + O2_DEFINE_CONFIGURABLE(cfgNGlobal, bool, false, "Set centrality estimator to cfgNGlobal"); + + O2_DEFINE_CONFIGURABLE(cfgVtxZ, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMin, float, 0.2f, "Minimal.q pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMax, float, 10.0f, "Maximal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 3.0f, "Maximal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5, "Chi2 per TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgMagField, float, 99999, "Configurable magnetic field; default CCDB will be queried") + O2_DEFINE_CONFIGURABLE(cfgEnergyCal, std::string, "Users/c/ckoster/ZDC/LHC23_zzh_pass4/Energy", "ccdb path for energy calibration histos") + O2_DEFINE_CONFIGURABLE(cfgMeanv, std::string, "Users/c/ckoster/ZDC/LHC23_zzh_pass4/vmean", "ccdb path for mean v histos") + O2_DEFINE_CONFIGURABLE(cfgMinEntriesSparseBin, int, 100, "Minimal number of entries allowed in 4D recentering histogram to use for recentering.") + O2_DEFINE_CONFIGURABLE(cfgRec, std::string, "Users/c/ckoster/ZDC/LHC23_PbPb_pass4/", "ccdb path for recentering histos"); + O2_DEFINE_CONFIGURABLE(cfgFillCommonRegistry, bool, true, "Fill common registry with histograms"); + + // Additional event selections + O2_DEFINE_CONFIGURABLE(cfgEvSelsMaxOccupancy, int, 10000, "Maximum occupancy of selected events"); + O2_DEFINE_CONFIGURABLE(cfgEvSelsNoSameBunchPileupCut, bool, true, "kNoSameBunchPileupCut"); + O2_DEFINE_CONFIGURABLE(cfgEvSelsIsGoodZvtxFT0vsPV, bool, true, "kIsGoodZvtxFT0vsPV"); + O2_DEFINE_CONFIGURABLE(cfgEvSelsNoCollInTimeRangeStandard, bool, true, "kNoCollInTimeRangeStandard"); + O2_DEFINE_CONFIGURABLE(cfgEvSelsDoOccupancySel, bool, true, "Bool for event selection on detector occupancy"); + O2_DEFINE_CONFIGURABLE(cfgEvSelsIsVertexITSTPC, bool, true, "Selects collisions with at least one ITS-TPC track"); + O2_DEFINE_CONFIGURABLE(cfgEvSelsIsGoodITSLayersAll, bool, true, "Cut time intervals with dead ITS staves"); + O2_DEFINE_CONFIGURABLE(cfgEvSelsCentMin, float, 0, "Minimum cenrality for selected events"); + O2_DEFINE_CONFIGURABLE(cfgEvSelsCentMax, float, 90, "Maximum cenrality for selected events"); + + // define my..... + // Filter collisionFilter = nabs(aod::collision::posZ) < cfgVtxZ; + using UsedCollisions = soa::Join; + using BCsRun3 = soa::Join; + + enum SelectionCriteria { + evSel_Zvtx, + evSel_sel8, + evSel_occupancy, + evSel_kNoSameBunchPileup, + evSel_kIsGoodZvtxFT0vsPV, + evSel_kNoCollInTimeRangeStandard, + evSel_kIsVertexITSTPC, + evSel_CentCuts, + evSel_kIsGoodITSLayersAll, + evSel_isSelectedZDC, + nEventSelections + }; + + enum CalibModes { + kEnergyCal, + kMeanv, + kRec + }; + + // Define output + HistogramRegistry registry{"Registry"}; + + Service ccdb; + + // keep track of calibration histos for each given step and iteration + struct Calib { + std::vector calibList = std::vector(3, nullptr); // [0] Enerfy cal, [1] vmean, [2] recentering + std::vector calibfilesLoaded = std::vector(3, false); + int atStep = 0; + int atIteration = 0; + } cal; + + enum FillType { + kBefore, + kAfter + }; + + void init(InitContext const&) + { + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + int64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); + + std::vector sides = {"A", "C"}; + std::vector capCOORDS = {"X", "Y"}; + + if (cfgFillCommonRegistry) { + registry.add(Form("QA/before/hSPplaneA"), "hSPplaneA", kTH2D, {{100, -4, 4}, axisCent10}); + registry.add(Form("QA/before/hSPplaneC"), "hSPplaneC", kTH2D, {{100, -4, 4}, axisCent10}); + registry.add(Form("QA/before/hSPplaneFull"), "hSPplaneFull", kTH2D, {{100, -4, 4}, axisCent10}); + for (const auto& side : sides) { + registry.add(Form("QA/before/hZN%s_Qx_vs_Qy", side), Form("hZN%s_Qx_vs_Qy", side), kTH2F, {axisQ, axisQ}); + } + + for (const auto& COORD1 : capCOORDS) { + for (const auto& COORD2 : capCOORDS) { + // Now we get: & vs. Centrality + registry.add(Form("QA/before/hQ%sA_Q%sC_vs_cent", COORD1, COORD2), Form("hQ%sA_Q%sC_vs_cent", COORD1, COORD2), kTProfile, {axisCent}); + registry.add(Form("QA/before/hQ%sA_Q%sC_vs_vx", COORD1, COORD2), Form("hQ%sA_Q%sC_vs_vx", COORD1, COORD2), kTProfile, {axisVx}); + registry.add(Form("QA/before/hQ%sA_Q%sC_vs_vy", COORD1, COORD2), Form("hQ%sA_Q%sC_vs_vy", COORD1, COORD2), kTProfile, {axisVy}); + registry.add(Form("QA/before/hQ%sA_Q%sC_vs_vz", COORD1, COORD2), Form("hQ%sA_Q%sC_vs_vz", COORD1, COORD2), kTProfile, {axisVz}); + } + } + + // Add histograms for each step in the calibration process. + // Sides is {A,C} and capcoords is {X,Y} + for (const auto& side : sides) { + for (const auto& coord : capCOORDS) { + registry.add(Form("QA/before/hQ%s%s_vs_cent", coord, side), Form("hQ%s%s_vs_cent", coord, side), {HistType::kTProfile, {axisCent10}}); + registry.add(Form("QA/before/hQ%s%s_vs_vx", coord, side), Form("hQ%s%s_vs_vx", coord, side), {HistType::kTProfile, {axisVx}}); + registry.add(Form("QA/before/hQ%s%s_vs_vy", coord, side), Form("hQ%s%s_vs_vy", coord, side), {HistType::kTProfile, {axisVy}}); + registry.add(Form("QA/before/hQ%s%s_vs_vz", coord, side), Form("hQ%s%s_vs_vz", coord, side), {HistType::kTProfile, {axisVz}}); + + names[0].push_back(TString::Format("hQ%s%s_mean_Cent_V_run", coord, side)); + names[1].push_back(TString::Format("hQ%s%s_mean_cent_run", coord, side)); + names[2].push_back(TString::Format("hQ%s%s_mean_vx_run", coord, side)); + names[3].push_back(TString::Format("hQ%s%s_mean_vy_run", coord, side)); + names[4].push_back(TString::Format("hQ%s%s_mean_vz_run", coord, side)); + } // end of capCOORDS + } // end of sides + + registry.add("QA/centrality_before", "centrality_before", kTH1D, {{200, 0, 100}}); + registry.add("QA/centrality_after", "centrality_after", kTH1D, {{200, 0, 100}}); + + registry.add("QA/ZNA_Energy", "ZNA_Energy", kTProfile, {{8, 0, 8}}); + registry.add("QA/ZNC_Energy", "ZNC_Energy", kTProfile, {{8, 0, 8}}); + + registry.add("QA/before/ZNA_pm1", "ZNA_pm1", kTProfile, {{1, 0, 1.}}); + registry.add("QA/before/ZNA_pm2", "ZNA_pm2", kTProfile, {{1, 0, 1.}}); + registry.add("QA/before/ZNA_pm3", "ZNA_pm3", kTProfile, {{1, 0, 1.}}); + registry.add("QA/before/ZNA_pm4", "ZNA_pm4", kTProfile, {{1, 0, 1.}}); + + registry.add("QA/before/ZNC_pm1", "ZNC_pm1", kTProfile, {{1, 0, 1.}}); + registry.add("QA/before/ZNC_pm2", "ZNC_pm2", kTProfile, {{1, 0, 1.}}); + registry.add("QA/before/ZNC_pm3", "ZNC_pm3", kTProfile, {{1, 0, 1.}}); + registry.add("QA/before/ZNC_pm4", "ZNC_pm4", kTProfile, {{1, 0, 1.}}); + + registry.addClone("QA/before/", "QA/after/"); + } + + // Tower mean energies vs. centrality used for tower gain equalisation + int totalTowers = 10; + int totalTowersPerSide = 5; + for (int tower = 0; tower < totalTowers; tower++) { + namesEcal[tower] = TString::Format("hZN%s_mean_t%i_cent", sides[(tower < totalTowersPerSide) ? 0 : 1], tower % 5); + registry.add(Form("Energy/%s", namesEcal[tower].Data()), Form("%s", namesEcal[tower].Data()), kTProfile2D, {{1, 0, 1}, axisCent}); + } + + // recentered q-vectors (to check what steps are finished in the end) + registry.add("vmean/hvertex_vx", "hvertex_vx", kTProfile, {{1, 0., 1.}}); + registry.add("vmean/hvertex_vy", "hvertex_vy", kTProfile, {{1, 0., 1.}}); + registry.add("vmean/hvertex_vz", "hvertex_vz", kTProfile, {{1, 0., 1.}}); + + registry.add("hEventCount", "Number of Event; Cut; #Events Passed Cut", {HistType::kTH1D, {{nEventSelections, 0, nEventSelections}}}); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_Zvtx + 1, "Z vertex cut event"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_sel8 + 1, "Sel8"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_occupancy + 1, "kOccupancy"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kNoSameBunchPileup + 1, "kNoSameBunchPileup"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsGoodZvtxFT0vsPV + 1, "kIsGoodZvtxFT0vsPV"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kNoCollInTimeRangeStandard + 1, "kNoCollInTimeRangeStandard"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsVertexITSTPC + 1, "kIsVertexITSTPC"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_CentCuts + 1, "Cenrality range"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsGoodITSLayersAll + 1, "kkIsGoodITSLayersAll"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_isSelectedZDC + 1, "isSelected"); + } + + template + bool eventSelected(TCollision collision, const float& centrality) + { + if (std::fabs(collision.posZ()) > cfgVtxZ) + return 0; + registry.fill(HIST("hEventCount"), evSel_sel8); + + if (!collision.sel8()) + return 0; + registry.fill(HIST("hEventCount"), evSel_sel8); + + // Occupancy + if (cfgEvSelsDoOccupancySel) { + auto occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy > cfgEvSelsMaxOccupancy) { + return 0; + } + registry.fill(HIST("hEventCount"), evSel_occupancy); + } + + if (cfgEvSelsNoSameBunchPileupCut) { + if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + // rejects collisions which are associated with the same "found-by-T0" bunch crossing + // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof + return 0; + } + registry.fill(HIST("hEventCount"), evSel_kNoSameBunchPileup); + } + if (cfgEvSelsIsGoodZvtxFT0vsPV) { + if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference + // use this cut at low multiplicities with caution + return 0; + } + registry.fill(HIST("hEventCount"), evSel_kIsGoodZvtxFT0vsPV); + } + if (cfgEvSelsNoCollInTimeRangeStandard) { + if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // Rejection of the collisions which have other events nearby + return 0; + } + registry.fill(HIST("hEventCount"), evSel_kNoCollInTimeRangeStandard); + } + + if (cfgEvSelsIsVertexITSTPC) { + if (!collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + // selects collisions with at least one ITS-TPC track, and thus rejects vertices built from ITS-only tracks + return 0; + } + registry.fill(HIST("hEventCount"), evSel_kIsVertexITSTPC); + } + + if (centrality > cfgEvSelsCentMax || centrality < cfgEvSelsCentMin) + return 0; + registry.fill(HIST("hEventCount"), evSel_CentCuts); + + if (cfgEvSelsIsGoodITSLayersAll) { + if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + // New event selection bits to cut time intervals with dead ITS staves + // https://indico.cern.ch/event/1493023/ (09-01-2025) + return 0; + } + registry.fill(HIST("hEventCount"), evSel_kIsGoodITSLayersAll); + } + + return 1; + } + + template + inline void fillCommonRegistry(double qxa, double qya, double qxc, double qyc, std::vector v, double centrality) + { + // loop for filling multiple histograms with different naming patterns + // Always fill the uncentered "raw" Q-vector histos! + static constexpr std::string_view Time[] = {"before", "after"}; + + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hZNA_Qx_vs_Qy"), qxa, qya); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hZNC_Qx_vs_Qy"), qxc, qyc); + + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQXA_QXC_vs_cent"), centrality, qxa * qxc); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQYA_QYC_vs_cent"), centrality, qya * qyc); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQYA_QXC_vs_cent"), centrality, qya * qxc); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQXA_QYC_vs_cent"), centrality, qxa * qyc); + + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQXA_vs_cent"), centrality, qxa); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQYA_vs_cent"), centrality, qya); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQXC_vs_cent"), centrality, qxc); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQYC_vs_cent"), centrality, qyc); + + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQXA_vs_vx"), v[0], qxa); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQYA_vs_vx"), v[0], qya); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQXC_vs_vx"), v[0], qxc); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQYC_vs_vx"), v[0], qyc); + + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQXA_QXC_vs_vx"), v[0], qxa * qxc); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQYA_QYC_vs_vx"), v[0], qya * qyc); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQYA_QXC_vs_vx"), v[0], qya * qxc); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQXA_QYC_vs_vx"), v[0], qxa * qyc); + + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQXA_vs_vy"), v[1], qxa); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQYA_vs_vy"), v[1], qya); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQXC_vs_vy"), v[1], qxc); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQYC_vs_vy"), v[1], qyc); + + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQXA_QXC_vs_vy"), v[1], qxa * qxc); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQYA_QYC_vs_vy"), v[1], qya * qyc); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQYA_QXC_vs_vy"), v[1], qya * qxc); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQXA_QYC_vs_vy"), v[1], qxa * qyc); + + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQXA_vs_vz"), v[2], qxa); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQYA_vs_vz"), v[2], qya); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQXC_vs_vz"), v[2], qxc); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQYC_vs_vz"), v[2], qyc); + + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQXA_QXC_vs_vz"), v[2], qxa * qxc); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQYA_QYC_vs_vz"), v[2], qya * qyc); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQYA_QXC_vs_vz"), v[2], qya * qxc); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hQXA_QYC_vs_vz"), v[2], qxa * qyc); + + // add psi!! + double psiA = 1.0 * std::atan2(qxc, qxa); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hSPplaneA"), psiA, centrality, 1); + double psiC = 1.0 * std::atan2(qyc, qya); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hSPplaneC"), psiC, centrality, 1); + double psiFull = 1.0 * std::atan2(qxc + qyc, qxa + qya); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hSPplaneFull"), psiFull, centrality, 1); + } + + template + void loadCalibrations(uint64_t timestamp, std::string ccdb_dir) + { + // iteration = 0 (Energy calibration) -> step 0 only + // iteration 1,2,3,4,5 = recentering -> 5 steps per iteration (1x 4D + 4x 1D) + + if (cal.calibfilesLoaded[cm]) + return; + + if (ccdb_dir.empty() == false) { + cal.calibList[cm] = ccdb->getForTimeStamp(ccdb_dir, timestamp); + cal.calibfilesLoaded[cm] = true; + LOGF(info, "Loaded calibration histos from %s", ccdb_dir.c_str()); + } else { + LOGF(info, "No ccdb path given for calibration histos. Do not recenter."); + } + } + + template + double getCorrection(const char* objName, int iteration = 0, int step = 0) + { + T* hist = nullptr; + double calibConstant{0}; + + if (cm == kEnergyCal) { + TList* list = cal.calibList[cm]; + hist = reinterpret_cast(list->FindObject(Form("%s", objName))); + } else if (cm == kMeanv) { + TList* list = cal.calibList[cm]; + hist = reinterpret_cast(list->FindObject(Form("%s", objName))); + } else if (cm == kRec) { + TList* list = reinterpret_cast(cal.calibList[cm]->FindObject(Form("it%i_step%i", iteration, step))); + hist = reinterpret_cast(list->FindObject(Form("%s", objName))); + cal.atStep = step; + cal.atIteration = iteration; + } + + if (!hist) { + LOGF(fatal, "%s not available.. Abort..", objName); + } + + if (hist->InheritsFrom("TProfile2D")) { + // needed for energy calibration! + TProfile2D* h = reinterpret_cast(hist); + TString name = h->GetName(); + int binrunnumber = h->GetXaxis()->FindBin(TString::Format("%d", runnumber)); + int bin = h->GetYaxis()->FindBin(centrality); + calibConstant = h->GetBinContent(binrunnumber, bin); + } else if (hist->InheritsFrom("TProfile")) { + TProfile* h = reinterpret_cast(hist); + TString name = h->GetName(); + int bin{}; + if (name.Contains("mean_vx")) + bin = h->GetXaxis()->FindBin(v[0]); + if (name.Contains("mean_vy")) + bin = h->GetXaxis()->FindBin(v[1]); + if (name.Contains("mean_vz")) + bin = h->GetXaxis()->FindBin(v[2]); + if (name.Contains("mean_cent")) + bin = h->GetXaxis()->FindBin(centrality); + if (name.Contains("vertex")) + bin = h->GetXaxis()->FindBin(TString::Format("%i", runnumber)); + calibConstant = h->GetBinContent(bin); + } else if (hist->InheritsFrom("THnSparse")) { + std::vector sparsePars; + THnSparseD* h = reinterpret_cast(hist); + sparsePars.push_back(h->GetAxis(0)->FindBin(centrality)); + sparsePars.push_back(h->GetAxis(1)->FindBin(v[0])); + sparsePars.push_back(h->GetAxis(2)->FindBin(v[1])); + sparsePars.push_back(h->GetAxis(3)->FindBin(v[2])); + + for (std::size_t i = 0; i < sparsePars.size(); i++) { + h->GetAxis(i)->SetRange(sparsePars[i], sparsePars[i]); + } + + TH1D* tempProj = h->Projection(4); + calibConstant = tempProj->GetMean(); + + if (tempProj->GetEntries() < cfgMinEntriesSparseBin) { + LOGF(debug, "1 entry in sparse bin! Not used... (increase binsize)"); + calibConstant = 0; + isSelected = false; + } + + delete tempProj; + } + + return calibConstant; + } + + void process(UsedCollisions::iterator const& collision, + BCsRun3 const& /*bcs*/, + aod::Zdcs const& /*zdcs*/) + { + // for Q-vector calculation + // A[0] & C[1] + std::vector sumZN(2, 0.); + std::vector xEnZN(2, 0.); + std::vector yEnZN(2, 0.); + + isSelected = true; + + // TODO Implement other ZDC estimators + auto cent = collision.centFT0C(); + if (cfgFT0Cvariant1) + cent = collision.centFT0CVariant1(); + if (cfgFT0M) + cent = collision.centFT0M(); + if (cfgFV0A) + cent = collision.centFV0A(); + if (cfgNGlobal) + cent = collision.centNGlobal(); + + registry.fill(HIST("QA/centrality_before"), cent); + + if (!eventSelected(collision, cent)) { + // event not selected + isSelected = false; + spTableZDC(runnumber, cent, v[0], v[1], v[2], 0, 0, 0, 0, isSelected, 0, 0); + counter++; + return; + } + + const auto& foundBC = collision.foundBC_as(); + + if (!foundBC.has_zdc()) { + isSelected = false; + spTableZDC(runnumber, cent, v[0], v[1], v[2], 0, 0, 0, 0, isSelected, 0, 0); + counter++; + return; + } + + v[0] = collision.posX(); + v[1] = collision.posY(); + v[2] = collision.posZ(); + centrality = cent; + runnumber = foundBC.runNumber(); + + // load new calibrations for new runs only + if (runnumber != lastRunNumber) { + cal.calibfilesLoaded[2] = false; + cal.calibList[2] = nullptr; + lastRunNumber = runnumber; + } + + const auto& zdcCol = foundBC.zdc(); + + // Get the raw energies eZN[8] (not the common A,C) + int nTowers = 8; + int nTowersPerSide = 4; + + for (int tower = 0; tower < nTowers; tower++) { + eZN[tower] = (tower < nTowersPerSide) ? zdcCol.energySectorZNA()[tower] : zdcCol.energySectorZNC()[tower % nTowersPerSide]; + } + + // load the calibration histos for iteration 0 step 0 (Energy Calibration) + loadCalibrations(foundBC.timestamp(), cfgEnergyCal.value); + + if (!cal.calibfilesLoaded[0]) { + if (counter < 1) { + LOGF(info, " --> No Energy calibration files found.. -> Only Energy calibration will be done. "); + } + } + // load the calibrations for the mean v + loadCalibrations(foundBC.timestamp(), cfgMeanv.value); + + if (!cal.calibfilesLoaded[1]) { + registry.get(HIST("vmean/hvertex_vx"))->Fill(Form("%d", runnumber), v[0]); + registry.get(HIST("vmean/hvertex_vy"))->Fill(Form("%d", runnumber), v[1]); + registry.get(HIST("vmean/hvertex_vz"))->Fill(Form("%d", runnumber), v[2]); + } + + bool isZNAhit = true; + bool isZNChit = true; + + for (int i = 0; i < nTowers; ++i) { + if (i < nTowersPerSide && eZN[i] <= 0) + isZNAhit = false; + if (i >= nTowersPerSide && eZN[i] <= 0) + isZNChit = false; + } + + if (zdcCol.energyCommonZNA() <= 0) + isZNAhit = false; + if (zdcCol.energyCommonZNC() <= 0) + isZNChit = false; + + // Fill to get mean energy per tower in 1% centrality bins + if (isZNAhit) { + registry.get(HIST("Energy/hZNA_mean_t0_cent"))->Fill(Form("%d", runnumber), cent, zdcCol.energyCommonZNA(), 1); + registry.get(HIST("Energy/hZNA_mean_t1_cent"))->Fill(Form("%d", runnumber), cent, eZN[0], 1); + registry.get(HIST("Energy/hZNA_mean_t2_cent"))->Fill(Form("%d", runnumber), cent, eZN[1], 1); + registry.get(HIST("Energy/hZNA_mean_t3_cent"))->Fill(Form("%d", runnumber), cent, eZN[2], 1); + registry.get(HIST("Energy/hZNA_mean_t4_cent"))->Fill(Form("%d", runnumber), cent, eZN[3], 1); + } + if (isZNChit) { + registry.get(HIST("Energy/hZNC_mean_t0_cent"))->Fill(Form("%d", runnumber), cent, zdcCol.energyCommonZNC(), 1); + registry.get(HIST("Energy/hZNC_mean_t1_cent"))->Fill(Form("%d", runnumber), cent, eZN[4], 1); + registry.get(HIST("Energy/hZNC_mean_t2_cent"))->Fill(Form("%d", runnumber), cent, eZN[5], 1); + registry.get(HIST("Energy/hZNC_mean_t3_cent"))->Fill(Form("%d", runnumber), cent, eZN[6], 1); + registry.get(HIST("Energy/hZNC_mean_t4_cent"))->Fill(Form("%d", runnumber), cent, eZN[7], 1); + } + + // if ZNA or ZNC not hit correctly.. do not use event in q-vector calculation + if (!isZNAhit || !isZNChit) { + counter++; + isSelected = false; + spTableZDC(runnumber, centrality, v[0], v[1], v[2], 0, 0, 0, 0, isSelected, 0, 0); + return; + } + + registry.fill(HIST("hEventCount"), evSel_isSelectedZDC); + + // Do not continue if Energy calibration is not loaded + if (!cal.calibfilesLoaded[0]) { + counter++; + isSelected = false; + spTableZDC(runnumber, centrality, v[0], v[1], v[2], 0, 0, 0, 0, isSelected, 0, 0); + return; + } + + // Now start gain equalisation! + // Fill the list with calibration constants. + for (int tower = 0; tower < (nTowers + 2); tower++) { + meanEZN[tower] = getCorrection(namesEcal[tower].Data()); + } + + // Use the calibration constants but now only loop over towers 1-4 + int calibtower = 0; + std::vector towersNocom = {1, 2, 3, 4, 6, 7, 8, 9}; + + for (const auto& tower : towersNocom) { + if (meanEZN[tower] > 0) { + double ecommon = (tower > nTowersPerSide) ? meanEZN[5] : meanEZN[0]; + e[calibtower] = eZN[calibtower] * (0.25 * ecommon) / meanEZN[tower]; + } + calibtower++; + } + + for (int i = 0; i < nTowersPerSide; i++) { + float bincenter = i + .5; + registry.fill(HIST("QA/ZNA_Energy"), bincenter, eZN[i]); + registry.fill(HIST("QA/ZNA_Energy"), bincenter + 4, e[i]); + registry.fill(HIST("QA/ZNC_Energy"), bincenter, eZN[i + 4]); + registry.fill(HIST("QA/ZNC_Energy"), bincenter + 4, e[i + 4]); + + registry.get(HIST("QA/before/ZNA_pm1"))->Fill(Form("%d", runnumber), eZN[0]); + registry.get(HIST("QA/before/ZNA_pm2"))->Fill(Form("%d", runnumber), eZN[1]); + registry.get(HIST("QA/before/ZNA_pm3"))->Fill(Form("%d", runnumber), eZN[2]); + registry.get(HIST("QA/before/ZNA_pm4"))->Fill(Form("%d", runnumber), eZN[3]); + registry.get(HIST("QA/before/ZNC_pm1"))->Fill(Form("%d", runnumber), eZN[4]); + registry.get(HIST("QA/before/ZNC_pm2"))->Fill(Form("%d", runnumber), eZN[5]); + registry.get(HIST("QA/before/ZNC_pm3"))->Fill(Form("%d", runnumber), eZN[6]); + registry.get(HIST("QA/before/ZNC_pm4"))->Fill(Form("%d", runnumber), eZN[7]); + + registry.get(HIST("QA/after/ZNA_pm1"))->Fill(Form("%d", runnumber), e[0]); + registry.get(HIST("QA/after/ZNA_pm2"))->Fill(Form("%d", runnumber), e[1]); + registry.get(HIST("QA/after/ZNA_pm3"))->Fill(Form("%d", runnumber), e[2]); + registry.get(HIST("QA/after/ZNA_pm4"))->Fill(Form("%d", runnumber), e[3]); + registry.get(HIST("QA/after/ZNC_pm1"))->Fill(Form("%d", runnumber), e[4]); + registry.get(HIST("QA/after/ZNC_pm2"))->Fill(Form("%d", runnumber), e[5]); + registry.get(HIST("QA/after/ZNC_pm3"))->Fill(Form("%d", runnumber), e[6]); + registry.get(HIST("QA/after/ZNC_pm4"))->Fill(Form("%d", runnumber), e[7]); + } + + // Now calculate Q-vector + for (int tower = 0; tower < nTowers; tower++) { + int side = (tower >= nTowersPerSide) ? 1 : 0; + int sector = tower % nTowersPerSide; + double energy = std::pow(e[tower], alphaZDC); + sumZN[side] += energy; + xEnZN[side] += (side == 0) ? -1.0 * pxZDC[sector] * energy : pxZDC[sector] * energy; + yEnZN[side] += pyZDC[sector] * energy; + } + + // "QXA", "QYA", "QXC", "QYC" + int sides = 2; + for (int i = 0; i < sides; ++i) { + if (sumZN[i] > 0) { + q[i * 2] = xEnZN[i] / sumZN[i]; // for QXA[0] and QXC[2] + q[i * 2 + 1] = yEnZN[i] / sumZN[i]; // for QYA[1] and QYC[3] + } + } + + if (cal.calibfilesLoaded[1]) { + v[0] = v[0] - getCorrection(vnames[0].Data()); + v[1] = v[1] - getCorrection(vnames[1].Data()); + } else { + LOGF(warning, " --> No mean V found.. -> THis wil lead to wrong axis for vx, vy (will be created in vmean/)"); + return; + } + + loadCalibrations(foundBC.timestamp(), cfgRec.value); + + std::vector qRec(q); + + if (cal.atIteration == 0) { + if (isSelected) + if (cfgFillCommonRegistry) + fillCommonRegistry(q[0], q[1], q[2], q[3], v, centrality); + spTableZDC(runnumber, centrality, v[0], v[1], v[2], q[0], q[1], q[2], q[3], isSelected, 0, 0); + counter++; + return; + } else { + if (cfgFillCommonRegistry) + fillCommonRegistry(q[0], q[1], q[2], q[3], v, centrality); + + // vector of 4 + std::vector corrQxA; + std::vector corrQyA; + std::vector corrQxC; + std::vector corrQyC; + + int pb = 0; + + int nIterations = 6; + int nSteps = 5; + + for (int it = 1; it < nIterations; it++) { + corrQxA.push_back(getCorrection(names[0][0].Data(), it, 0)); + corrQyA.push_back(getCorrection(names[0][1].Data(), it, 0)); + corrQxC.push_back(getCorrection(names[0][2].Data(), it, 0)); + corrQyC.push_back(getCorrection(names[0][3].Data(), it, 0)); + pb++; + + for (int step = 1; step < nSteps; step++) { + corrQxA.push_back(getCorrection(names[step][0].Data(), it, step)); + corrQyA.push_back(getCorrection(names[step][1].Data(), it, step)); + corrQxC.push_back(getCorrection(names[step][2].Data(), it, step)); + corrQyC.push_back(getCorrection(names[step][3].Data(), it, step)); + pb++; + } + } + + for (int cor = 0; cor < pb; cor++) { + qRec[0] -= corrQxA[cor]; + qRec[1] -= corrQyA[cor]; + qRec[2] -= corrQxC[cor]; + qRec[3] -= corrQyC[cor]; + } + + if (isSelected) { + if (cfgFillCommonRegistry) + fillCommonRegistry(qRec[0], qRec[1], qRec[2], qRec[3], v, centrality); + registry.fill(HIST("QA/centrality_after"), centrality); + } + + spTableZDC(runnumber, centrality, v[0], v[1], v[2], qRec[0], qRec[1], qRec[2], qRec[3], isSelected, cal.atIteration, cal.atStep); + + qRec.clear(); + + counter++; + return; + } + LOGF(warning, "We return without saving table... -> THis is a problem"); + } // end of process +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Flow/Tasks/CMakeLists.txt b/PWGCF/Flow/Tasks/CMakeLists.txt index 49953226773..c62480f8d79 100644 --- a/PWGCF/Flow/Tasks/CMakeLists.txt +++ b/PWGCF/Flow/Tasks/CMakeLists.txt @@ -11,15 +11,70 @@ o2physics_add_dpl_workflow(flow-pt-efficiency SOURCES flowPtEfficiency.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-task + SOURCES flowTask.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-runby-run + SOURCES flowRunbyRun.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-mc + SOURCES flowMc.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-qa + SOURCES flowQa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-gfw-task + SOURCES flowGfwTask.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-zdc-task + SOURCES flowZdcTask.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-gf + SOURCES flowAnalysisGF.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-pbpb-pikp + SOURCES flowPbpbPikp.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-gfw-omega-xi + SOURCES flowGfwOmegaXi.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-pid-cme + SOURCES pidcme.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-sp + SOURCES flowSP.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(flow-pbpb-task - SOURCES FlowPbPbTask.cxx +o2physics_add_dpl_workflow(resonances-gfw-flow + SOURCES resonancesGfwFlow.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(flow-gfw-pbpb - SOURCES FlowGFWPbPb.cxx +o2physics_add_dpl_workflow(flow-efficiency-casc + SOURCES flowEfficiencyCasc.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore COMPONENT_NAME Analysis) diff --git a/PWGCF/Flow/Tasks/FlowGFWPbPb.cxx b/PWGCF/Flow/Tasks/FlowGFWPbPb.cxx deleted file mode 100644 index df07e0d9d63..00000000000 --- a/PWGCF/Flow/Tasks/FlowGFWPbPb.cxx +++ /dev/null @@ -1,158 +0,0 @@ -// 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. - -#include -#include -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/HistogramRegistry.h" - -#include "Common/DataModel/EventSelection.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/Centrality.h" - -#include "GFWPowerArray.h" -#include "GFW.h" -#include "GFWCumulant.h" -#include "TList.h" -#include -#include - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; - -struct FlowGFWPbPb { - - O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") - O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMin, float, 0.2f, "Minimal pT for poi tracks") - O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMax, float, 10.0f, "Maximal pT for poi tracks") - O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for ref tracks") - O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 3.0f, "Maximal pT for ref tracks") - O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") - O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5, "Chi2 per TPC clusters") - O2_DEFINE_CONFIGURABLE(cfgUseNch, bool, false, "Use Nch for flow observables") - O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 10, "Number of subsamples") - - ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for histograms"}; - ConfigurableAxis axisPhi{"axisPhi", {60, 0.0, constants::math::TwoPI}, "phi axis for histograms"}; - ConfigurableAxis axisEta{"axisEta", {40, -1., 1.}, "eta axis for histograms"}; - ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.2, 0.25, 0.30, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.20, 2.40, 2.60, 2.80, 3.00}, "pt axis for histograms"}; - // ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}, "centrality axis for histograms"}; - AxisSpec axisMultiplicity{{0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}, "Centrality (%)"}; - // AxisSpec axisC22{{0,0.02}, "C_2{2}"}; - - // std::vector centBinning = {0, 5., 10., 20., 30., 40., 50., 60., 70.}; - // AxisSpec axisCentBins{centBinning, "centrality percentile"}; - - Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; - Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtMin) && (aod::track::pt < cfgCutPtMax) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (aod::track::tpcChi2NCl < cfgCutChi2prTPCcls); - - // Connect to ccdb - Service ccdb; - Configurable nolaterthan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; - Configurable url{"ccdb-url", "http://ccdb-test.cern.ch:8080", "url of the ccdb repository"}; - - // Define output - HistogramRegistry registry{"registry"}; - - // define global variables - GFW* fGFW = new GFW(); // GFW class used from main src - std::vector corrconfigs; - - using aodCollisions = soa::Filtered>; // collisions filter - using aodTracks = soa::Filtered>; // tracks filter - - void init(InitContext const&) // Initialization - { - ccdb->setURL(url.value); - ccdb->setCaching(true); - ccdb->setCreatedNotAfter(nolaterthan.value); - - // Add some output objects to the histogram registry - registry.add("hPhi", "", {HistType::kTH1D, {axisPhi}}); - registry.add("hEta", "", {HistType::kTH1D, {axisEta}}); - registry.add("hVtxZ", "", {HistType::kTH1D, {axisVertex}}); - registry.add("hMult", "", {HistType::kTH1D, {{3000, 0.5, 3000.5}}}); - registry.add("hCent", "", {HistType::kTH1D, {{90, 0, 90}}}); - registry.add("c22", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); - registry.add("c24", ";Centrality (%) ; C_{2}{4}", {HistType::kTProfile, {axisMultiplicity}}); - registry.add("c26", ";Centrality (%) ; C_{2}{6}", {HistType::kTProfile, {axisMultiplicity}}); - registry.add("c28", ";Centrality (%) ; C_{2}{8}", {HistType::kTProfile, {axisMultiplicity}}); - - fGFW->AddRegion("full", -0.8, 0.8, 1, 1); // eta region -0.8 to 0.8 - corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 2 -2 -2}", "ChFull24", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 2 2 -2 -2 -2}", "ChFull26", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 2 2 2 -2 -2 -2 -2}", "ChFull28", kFALSE)); - - fGFW->CreateRegions(); // finalize the initialization - } - - template - void FillProfile(const GFW::CorrConfig& corrconf, const ConstStr& tarName, const double& cent) - { - double dnx, val; - dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); - if (dnx == 0) - return; - - if (!corrconf.pTDif) { - val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; - if (TMath::Abs(val) < 1) - registry.fill(tarName, cent, val, dnx); - return; - } - return; - } - - void process(aodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, aodTracks const& tracks) - { - int Ntot = tracks.size(); - - if (Ntot < 1) - return; - - // if (!collision.sel7()) return; - - float vtxz = collision.posZ(); - registry.fill(HIST("hVtxZ"), vtxz); - registry.fill(HIST("hMult"), Ntot); - registry.fill(HIST("hCent"), collision.centFT0C()); - fGFW->Clear(); - - const auto cent = collision.centFT0C(); - float weff = 1, wacc = 1; - for (auto& track : tracks) { - registry.fill(HIST("hPhi"), track.phi()); - registry.fill(HIST("hEta"), track.eta()); - - fGFW->Fill(track.eta(), 1, track.phi(), wacc * weff, 1); - } - - // Filling c22 with ROOT TProfile - FillProfile(corrconfigs.at(0), HIST("c22"), cent); - FillProfile(corrconfigs.at(1), HIST("c24"), cent); - FillProfile(corrconfigs.at(2), HIST("c26"), cent); - FillProfile(corrconfigs.at(3), HIST("c28"), cent); - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGCF/Flow/Tasks/FlowPbPbTask.cxx b/PWGCF/Flow/Tasks/FlowPbPbTask.cxx deleted file mode 100644 index cd9e8147517..00000000000 --- a/PWGCF/Flow/Tasks/FlowPbPbTask.cxx +++ /dev/null @@ -1,663 +0,0 @@ -// 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. -// -// code author: Zhiyong Lu (zhiyong.lu@cern.ch) -// jira: PWGCF-254 - -#include -#include -#include -#include -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/HistogramRegistry.h" - -#include "Common/DataModel/EventSelection.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/Multiplicity.h" - -#include "GFWPowerArray.h" -#include "GFW.h" -#include "GFWCumulant.h" -#include "GFWWeights.h" -#include "FlowContainer.h" -#include "TList.h" -#include -#include -#include - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; - -struct FlowPbPbTask { - - O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") - O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMin, float, 0.2f, "Minimal pT for poi tracks") - O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMax, float, 10.0f, "Maximal pT for poi tracks") - O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for ref tracks") - O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 3.0f, "Maximal pT for ref tracks") - O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") - O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5, "Chi2 per TPC clusters") - O2_DEFINE_CONFIGURABLE(cfgCutTPCclu, float, 70.0f, "minimum TPC clusters") - O2_DEFINE_CONFIGURABLE(cfgUseAdditionalEventCut, bool, false, "Use additional event cut on mult correlations") - O2_DEFINE_CONFIGURABLE(cfgUseAdditionalTrackCut, bool, false, "Use additional track cut on phi") - O2_DEFINE_CONFIGURABLE(cfgUseNch, bool, false, "Use Nch for flow observables") - O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 10, "Number of subsamples") - O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeights, bool, false, "Fill and output NUA weights") - O2_DEFINE_CONFIGURABLE(cfgEfficiency, std::string, "", "CCDB path to efficiency object") - O2_DEFINE_CONFIGURABLE(cfgAcceptance, std::string, "", "CCDB path to acceptance object") - O2_DEFINE_CONFIGURABLE(cfgMagnetField, std::string, "GLO/Config/GRPMagField", "CCDB path to Magnet field object") - - ConfigurableAxis axisVertex{"axisVertex", {40, -20, 20}, "vertex axis for histograms"}; - ConfigurableAxis axisPhi{"axisPhi", {60, 0.0, constants::math::TwoPI}, "phi axis for histograms"}; - ConfigurableAxis axisPhiMod{"axisPhiMod", {100, 0, constants::math::PI / 9}, "fmod(#varphi,#pi/9)"}; - ConfigurableAxis axisEta{"axisEta", {40, -1., 1.}, "eta axis for histograms"}; - ConfigurableAxis axisPtHist{"axisPtHist", {100, 0., 10.}, "pt axis for histograms"}; - ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.2, 2.4, 2.6, 2.8, 3, 3.5, 4, 5, 6, 8, 10}, "pt axis for histograms"}; - ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}, "centrality axis for histograms"}; - ConfigurableAxis axisCentForQA{"axisCentForQA", {100, 0, 100}, "centrality for QA"}; - ConfigurableAxis axisNch{"axisNch", {4000, 0, 4000}, "N_{ch}"}; - ConfigurableAxis axisT0C{"axisT0C", {70, 0, 70000}, "N_{ch} (T0C)"}; - ConfigurableAxis axisT0A{"axisT0A", {200, 0, 200000}, "N_{ch} (T0A)"}; - ConfigurableAxis axisNchPV{"axisNchPV", {4000, 0, 4000}, "N_{ch} (PV)"}; - ConfigurableAxis axisDCAz{"axisDCAz", {200, -2, 2}, "DCA_{z} (cm)"}; - ConfigurableAxis axisDCAxy{"axisDCAxy", {200, -1, 1}, "DCA_{xy} (cm)"}; - - Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; - Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (aod::track::tpcChi2NCl < cfgCutChi2prTPCcls); - - // Corrections - TH1D* mEfficiency = nullptr; - GFWWeights* mAcceptance = nullptr; - bool correctionsLoaded = false; - - // Connect to ccdb - Service ccdb; - Configurable nolaterthan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; - Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - - // Define output - OutputObj fFC{FlowContainer("FlowContainer")}; - OutputObj fWeights{GFWWeights("weights")}; - HistogramRegistry registry{"registry"}; - - // define global variables - GFW* fGFW = new GFW(); - std::vector corrconfigs; - TAxis* fPtAxis; - TRandom3* fRndm = new TRandom3(0); - std::vector>> BootstrapArray; - enum ExtraProfile { - // here are TProfiles for vn-pt correlations that are not implemented in GFW - kMeanPt_InGap08 = 0, - kC22_Gap08_Weff, - kC22_Gap08_MeanPt, - kPtVarParA_InGap08, - kPtVarParB_InGap08, - // Count the total number of enum - kCount_ExtraProfile - }; - - using aodCollisions = soa::Filtered>; - using aodTracks = soa::Filtered>; - - // Additional Event selection cuts - Copy from flowGenericFramework.cxx - TF1* fPhiCutLow = nullptr; - TF1* fPhiCutHigh = nullptr; - TF1* fMultPVCutLow = nullptr; - TF1* fMultPVCutHigh = nullptr; - TF1* fMultCutLow = nullptr; - TF1* fMultCutHigh = nullptr; - TF1* fMultMultPVCut = nullptr; - TF1* fT0AV0AMean = nullptr; - TF1* fT0AV0ASigma = nullptr; - - void init(InitContext const&) - { - ccdb->setURL(url.value); - ccdb->setCaching(true); - ccdb->setCreatedNotAfter(nolaterthan.value); - - // Add some output objects to the histogram registry - // Event QA - registry.add("hEventCount", "Number of Event;; Count", {HistType::kTH1D, {{5, 0, 5}}}); - registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(1, "Filtered event"); - registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(2, "after sel8"); - registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(3, "after strict Pile-up cut"); - registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(4, "after additional event cut"); - registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(5, "after correction loads"); - registry.add("hVtxZ", "Vexter Z distribution", {HistType::kTH1D, {axisVertex}}); - registry.add("hMult", "Multiplicity distribution", {HistType::kTH1D, {{3000, 0.5, 3000.5}}}); - registry.add("hCent", "Centrality distribution", {HistType::kTH1D, {{90, 0, 90}}}); - registry.add("BeforeCut_globalTracks_centT0C", "before cut;Centrality T0C;mulplicity global tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); - registry.add("BeforeCut_PVTracks_centT0C", "before cut;Centrality T0C;mulplicity PV tracks", {HistType::kTH2D, {axisCentForQA, axisNchPV}}); - registry.add("BeforeCut_globalTracks_PVTracks", "before cut;mulplicity PV tracks;mulplicity global tracks", {HistType::kTH2D, {axisNchPV, axisNch}}); - registry.add("BeforeCut_globalTracks_multT0A", "before cut;mulplicity T0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); - registry.add("BeforeCut_globalTracks_multV0A", "before cut;mulplicity V0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); - registry.add("BeforeCut_multV0A_multT0A", "before cut;mulplicity T0A;mulplicity V0A", {HistType::kTH2D, {axisT0A, axisT0A}}); - registry.add("BeforeCut_multT0C_centT0C", "before cut;Centrality T0C;mulplicity T0C", {HistType::kTH2D, {axisCentForQA, axisT0C}}); - registry.add("globalTracks_centT0C", "after cut;Centrality T0C;mulplicity global tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); - registry.add("PVTracks_centT0C", "after cut;Centrality T0C;mulplicity PV tracks", {HistType::kTH2D, {axisCentForQA, axisNchPV}}); - registry.add("globalTracks_PVTracks", "after cut;mulplicity PV tracks;mulplicity global tracks", {HistType::kTH2D, {axisNchPV, axisNch}}); - registry.add("globalTracks_multT0A", "after cut;mulplicity T0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); - registry.add("globalTracks_multV0A", "after cut;mulplicity V0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); - registry.add("multV0A_multT0A", "after cut;mulplicity T0A;mulplicity V0A", {HistType::kTH2D, {axisT0A, axisT0A}}); - registry.add("multT0C_centT0C", "after cut;Centrality T0C;mulplicity T0C", {HistType::kTH2D, {axisCentForQA, axisT0C}}); - // Track QA - registry.add("hPhi", "#phi distribution", {HistType::kTH1D, {axisPhi}}); - registry.add("hPhiWeighted", "corrected #phi distribution", {HistType::kTH1D, {axisPhi}}); - registry.add("hEta", "#eta distribution", {HistType::kTH1D, {axisEta}}); - registry.add("hPt", "p_{T} distribution before cut", {HistType::kTH1D, {axisPtHist}}); - registry.add("hPtRef", "p_{T} distribution after cut", {HistType::kTH1D, {axisPtHist}}); - registry.add("pt_phi_bef", "before cut;p_{T};#phi_{modn}", {HistType::kTH2D, {axisPt, axisPhiMod}}); - registry.add("pt_phi_aft", "after cut;p_{T};#phi_{modn}", {HistType::kTH2D, {axisPt, axisPhiMod}}); - registry.add("hChi2prTPCcls", "#chi^{2}/cluster for the TPC track segment", {HistType::kTH1D, {{100, 0., 5.}}}); - registry.add("hnTPCClu", "Number of found TPC clusters", {HistType::kTH1D, {{100, 40, 180}}}); - registry.add("hnTPCCrossedRow", "Number of crossed TPC Rows", {HistType::kTH1D, {{100, 40, 180}}}); - registry.add("hDCAz", "DCAz after cuts", {HistType::kTH1D, {{100, -3, 3}}}); - registry.add("hDCAxy", "DCAxy after cuts; DCAxy (cm); Pt", {HistType::kTH2D, {{50, -1, 1}, {50, 0, 10}}}); - registry.add("hTrackCorrection2d", "Correlation table for number of tracks table; uncorrected track; corrected track", {HistType::kTH2D, {axisNch, axisNch}}); - // additional Output histograms - registry.add("hMeanPt", "", {HistType::kTProfile, {axisCentrality}}); - registry.add("hMeanPtWithinGap08", "", {HistType::kTProfile, {axisCentrality}}); - registry.add("c22_gap08_Weff", "", {HistType::kTProfile, {axisCentrality}}); - registry.add("c22_gap08_trackMeanPt", "", {HistType::kTProfile, {axisCentrality}}); - registry.add("PtVariance_partA_WithinGap08", "", {HistType::kTProfile, {axisCentrality}}); - registry.add("PtVariance_partB_WithinGap08", "", {HistType::kTProfile, {axisCentrality}}); - - // initial array - BootstrapArray.resize(cfgNbootstrap); - for (int i = 0; i < cfgNbootstrap; i++) { - BootstrapArray[i].resize(kCount_ExtraProfile); - } - for (int i = 0; i < cfgNbootstrap; i++) { - BootstrapArray[i][kMeanPt_InGap08] = registry.add(Form("BootstrapContainer_%d/hMeanPtWithinGap08", i), "", {HistType::kTProfile, {axisCentrality}}); - BootstrapArray[i][kC22_Gap08_Weff] = registry.add(Form("BootstrapContainer_%d/c22_gap08_Weff", i), "", {HistType::kTProfile, {axisCentrality}}); - BootstrapArray[i][kC22_Gap08_MeanPt] = registry.add(Form("BootstrapContainer_%d/c22_gap08_trackMeanPt", i), "", {HistType::kTProfile, {axisCentrality}}); - BootstrapArray[i][kPtVarParA_InGap08] = registry.add(Form("BootstrapContainer_%d/PtVariance_partA_WithinGap08", i), "", {HistType::kTProfile, {axisCentrality}}); - BootstrapArray[i][kPtVarParB_InGap08] = registry.add(Form("BootstrapContainer_%d/PtVariance_partB_WithinGap08", i), "", {HistType::kTProfile, {axisCentrality}}); - } - - o2::framework::AxisSpec axis = axisPt; - int nPtBins = axis.binEdges.size() - 1; - double* PtBins = &(axis.binEdges)[0]; - fPtAxis = new TAxis(nPtBins, PtBins); - - if (cfgOutputNUAWeights) { - fWeights->SetPtBins(nPtBins, PtBins); - fWeights->Init(true, false); - } - - // add in FlowContainer to Get boostrap sample automatically - TObjArray* oba = new TObjArray(); - oba->Add(new TNamed("ChGap22", "ChGap22")); - for (Int_t i = 0; i < fPtAxis->GetNbins(); i++) - oba->Add(new TNamed(Form("ChGap22_pt_%i", i + 1), "ChGap22_pTDiff")); - oba->Add(new TNamed("ChFull22", "ChFull22")); - oba->Add(new TNamed("ChFull32", "ChFull32")); - oba->Add(new TNamed("ChFull42", "ChFull42")); - oba->Add(new TNamed("ChFull24", "ChFull24")); - oba->Add(new TNamed("ChFull26", "ChFull26")); - oba->Add(new TNamed("Ch04Gap22", "Ch04Gap22")); - oba->Add(new TNamed("Ch06Gap22", "Ch06Gap22")); - oba->Add(new TNamed("Ch08Gap22", "Ch08Gap22")); - oba->Add(new TNamed("Ch10Gap22", "Ch10Gap22")); - oba->Add(new TNamed("Ch04Gap32", "Ch04Gap32")); - oba->Add(new TNamed("Ch06Gap32", "Ch06Gap32")); - oba->Add(new TNamed("Ch08Gap32", "Ch08Gap32")); - oba->Add(new TNamed("Ch10Gap32", "Ch10Gap32")); - oba->Add(new TNamed("Ch04Gap42", "Ch04Gap42")); - oba->Add(new TNamed("Ch06Gap42", "Ch06Gap42")); - oba->Add(new TNamed("Ch08Gap42", "Ch08Gap42")); - oba->Add(new TNamed("Ch10Gap42", "Ch10Gap42")); - oba->Add(new TNamed("ChFull422", "ChFull422")); - oba->Add(new TNamed("Ch04GapA422", "Ch04GapA422")); - oba->Add(new TNamed("Ch04GapB422", "Ch04GapB422")); - oba->Add(new TNamed("Ch10GapA422", "Ch10GapA422")); - oba->Add(new TNamed("Ch10GapB422", "Ch10GapB422")); - oba->Add(new TNamed("ChFull3232", "ChFull3232")); - oba->Add(new TNamed("ChFull4242", "ChFull4242")); - oba->Add(new TNamed("Ch04Gap3232", "Ch04Gap3232")); - oba->Add(new TNamed("Ch04Gap4242", "Ch04Gap4242")); - oba->Add(new TNamed("Ch04Gap24", "Ch04Gap24")); - oba->Add(new TNamed("Ch10Gap3232", "Ch10Gap3232")); - oba->Add(new TNamed("Ch10Gap4242", "Ch10Gap4242")); - oba->Add(new TNamed("Ch10Gap24", "Ch10Gap24")); - fFC->SetName("FlowContainer"); - fFC->SetXAxis(fPtAxis); - fFC->Initialize(oba, axisCentrality, cfgNbootstrap); - delete oba; - - // eta region - fGFW->AddRegion("full", -0.8, 0.8, 1, 1); - fGFW->AddRegion("refN04", -0.8, -0.2, 1, 1); // gap4 negative region - fGFW->AddRegion("refP04", 0.2, 0.8, 1, 1); // gap4 positve region - fGFW->AddRegion("refN06", -0.8, -0.3, 1, 1); // gap6 negative region - fGFW->AddRegion("refP06", 0.3, 0.8, 1, 1); // gap6 positve region - fGFW->AddRegion("refN08", -0.8, -0.4, 1, 1); - fGFW->AddRegion("refP08", 0.4, 0.8, 1, 1); - fGFW->AddRegion("refN10", -0.8, -0.5, 1, 1); - fGFW->AddRegion("refP10", 0.5, 0.8, 1, 1); - fGFW->AddRegion("refP", 0.4, 0.8, 1, 1); - fGFW->AddRegion("refN", -0.8, -0.4, 1, 1); - fGFW->AddRegion("poiN", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 2); - fGFW->AddRegion("olN", -0.8, -0.4, 1, 4); - - corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {3 -3}", "ChFull32", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {4 -4}", "ChFull42", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 2 -2 -2}", "ChFull24", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 2 2 -2 -2 -2}", "ChFull26", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {2} refP04 {-2}", "Ch04Gap22", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN06 {2} refP06 {-2}", "Ch06Gap22", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {2} refP08 {-2}", "Ch08Gap22", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {2} refP10 {-2}", "Ch10Gap22", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {3} refP04 {-3}", "Ch04Gap32", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN06 {3} refP06 {-3}", "Ch06Gap32", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {3} refP08 {-3}", "Ch08Gap32", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {3} refP10 {-3}", "Ch10Gap32", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {4} refP04 {-4}", "Ch04Gap42", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN06 {4} refP06 {-4}", "Ch06Gap42", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {4} refP08 {-4}", "Ch08Gap42", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {4} refP10 {-4}", "Ch10Gap42", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN {2} refP {-2}", "ChGap22", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiN refN | olN {2} refP {-2}", "ChGap22", kTRUE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {4 -2 -2}", "ChFull422", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {-2 -2} refP04 {4}", "Ch04GapA422", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {4} refP04 {-2 -2}", "Ch04GapB422", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {-2 -2} refP10 {4}", "Ch10GapA422", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {4} refP10 {-2 -2}", "Ch10GapB422", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {3 2 -3 -2}", "ChFull3232", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {4 2 -4 -2}", "ChFull4242", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {3 2} refP04 {-3 -2}", "Ch04Gap3232", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {4 2} refP04 {-4 -2}", "Ch04Gap4242", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {2 2} refP04 {-2 -2}", "Ch04Gap24", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {3 2} refP10 {-3 -2}", "Ch10Gap3232", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {4 2} refP10 {-4 -2}", "Ch10Gap4242", kFALSE)); - corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {2 2} refP10 {-2 -2}", "Ch10Gap24", kFALSE)); - fGFW->CreateRegions(); - - if (cfgUseAdditionalEventCut) { - fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x - 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); - fMultPVCutLow->SetParameters(3257.29, -121.848, 1.98492, -0.0172128, 6.47528e-05, 154.756, -1.86072, -0.0274713, 0.000633499, -3.37757e-06); - fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x + 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); - fMultPVCutHigh->SetParameters(3257.29, -121.848, 1.98492, -0.0172128, 6.47528e-05, 154.756, -1.86072, -0.0274713, 0.000633499, -3.37757e-06); - - fMultCutLow = new TF1("fMultCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); - fMultCutLow->SetParameters(1654.46, -47.2379, 0.449833, -0.0014125, 150.773, -3.67334, 0.0530503, -0.000614061, 3.15956e-06); - fMultCutHigh = new TF1("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 3.*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); - fMultCutHigh->SetParameters(1654.46, -47.2379, 0.449833, -0.0014125, 150.773, -3.67334, 0.0530503, -0.000614061, 3.15956e-06); - - fT0AV0AMean = new TF1("fT0AV0AMean", "[0]+[1]*x", 0, 200000); - fT0AV0AMean->SetParameters(-1601.0581, 9.417652e-01); - fT0AV0ASigma = new TF1("fT0AV0ASigma", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 200000); - fT0AV0ASigma->SetParameters(463.4144, 6.796509e-02, -9.097136e-07, 7.971088e-12, -2.600581e-17); - } - - if (cfgUseAdditionalTrackCut) { - fPhiCutLow = new TF1("fPhiCutLow", "0.06/x+pi/18.0-0.06", 0, 100); - fPhiCutHigh = new TF1("fPhiCutHigh", "0.1/x+pi/18.0+0.06", 0, 100); - } - } - - template - void FillProfile(const GFW::CorrConfig& corrconf, const ConstStr& tarName, const double& cent) - { - double dnx, val; - dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); - if (dnx == 0) - return; - if (!corrconf.pTDif) { - val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; - if (TMath::Abs(val) < 1) - registry.fill(tarName, cent, val, dnx); - return; - } - return; - } - - template - void FillpTvnProfile(const GFW::CorrConfig& corrconf, const double& sum_pt, const double& WeffEvent, const ConstStr& vnWeff, const ConstStr& vnpT, const double& cent) - { - double meanPt = sum_pt / WeffEvent; - double dnx, val; - dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); - if (dnx == 0) - return; - if (!corrconf.pTDif) { - val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; - if (TMath::Abs(val) < 1) { - registry.fill(vnWeff, cent, val, dnx * WeffEvent); - registry.fill(vnpT, cent, val * meanPt, dnx * WeffEvent); - } - return; - } - return; - } - - void FillpTvnProfile(const GFW::CorrConfig& corrconf, const double& sum_pt, const double& WeffEvent, std::shared_ptr vnWeff, std::shared_ptr vnpT, const double& cent) - { - double meanPt = sum_pt / WeffEvent; - double dnx, val; - dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); - if (dnx == 0) - return; - if (!corrconf.pTDif) { - val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; - if (TMath::Abs(val) < 1) { - vnWeff->Fill(cent, val, dnx * WeffEvent); - vnpT->Fill(cent, val * meanPt, dnx * WeffEvent); - } - return; - } - return; - } - - void FillFC(const GFW::CorrConfig& corrconf, const double& cent, const double& rndm) - { - double dnx, val; - dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); - if (dnx == 0) - return; - if (!corrconf.pTDif) { - val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; - if (TMath::Abs(val) < 1) - fFC->FillProfile(corrconf.Head.c_str(), cent, val, dnx, rndm); - return; - } - for (Int_t i = 1; i <= fPtAxis->GetNbins(); i++) { - dnx = fGFW->Calculate(corrconf, i - 1, kTRUE).real(); - if (dnx == 0) - continue; - val = fGFW->Calculate(corrconf, i - 1, kFALSE).real() / dnx; - if (TMath::Abs(val) < 1) - fFC->FillProfile(Form("%s_pt_%i", corrconf.Head.c_str(), i), cent, val, dnx, rndm); - } - return; - } - - void loadCorrections(uint64_t timestamp) - { - if (correctionsLoaded) - return; - if (cfgAcceptance.value.empty() == false) { - mAcceptance = ccdb->getForTimeStamp(cfgAcceptance, timestamp); - if (mAcceptance) - LOGF(info, "Loaded acceptance weights from %s (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance); - else - LOGF(warning, "Could not load acceptance weights from %s (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance); - } - if (cfgEfficiency.value.empty() == false) { - mEfficiency = ccdb->getForTimeStamp(cfgEfficiency, timestamp); - if (mEfficiency == nullptr) { - LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgEfficiency.value.c_str()); - } - LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgEfficiency.value.c_str(), (void*)mEfficiency); - } - correctionsLoaded = true; - } - - bool setCurrentParticleWeights(float& weight_nue, float& weight_nua, float phi, float eta, float pt, float vtxz) - { - float eff = 1.; - if (mEfficiency) - eff = mEfficiency->GetBinContent(mEfficiency->FindBin(pt)); - else - eff = 1.0; - if (eff == 0) - return false; - weight_nue = 1. / eff; - if (mAcceptance) - weight_nua = mAcceptance->GetNUA(phi, eta, vtxz); - else - weight_nua = 1; - return true; - } - - template - bool eventSelected(TCollision collision, const int multTrk, const float centrality) - { - if (collision.alias_bit(kTVXinTRD)) { - // TRD triggered - return 0; - } - if (!collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { - // reject collisions close to Time Frame borders - // https://its.cern.ch/jira/browse/O2-4623 - return 0; - } - if (!collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { - // reject events affected by the ITS ROF border - // https://its.cern.ch/jira/browse/O2-4309 - return 0; - } - if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { - // rejects collisions which are associated with the same "found-by-T0" bunch crossing - // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof - return 0; - } - if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { - // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference - // use this cut at low multiplicities with caution - return 0; - } - float vtxz = -999; - if (collision.numContrib() > 1) { - vtxz = collision.posZ(); - float zRes = TMath::Sqrt(collision.covZZ()); - if (zRes > 0.25 && collision.numContrib() < 20) - vtxz = -999; - } - auto multNTracksPV = collision.multNTracksPV(); - - if (abs(vtxz) > cfgCutVertex) - return 0; - if (multNTracksPV < fMultPVCutLow->Eval(centrality)) - return 0; - if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) - return 0; - if (multTrk < fMultCutLow->Eval(centrality)) - return 0; - if (multTrk > fMultCutHigh->Eval(centrality)) - return 0; - - // V0A T0A 5 sigma cut - if (abs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > 5 * fT0AV0ASigma->Eval(collision.multFT0A())) - return 0; - - return 1; - } - - int getMagneticField(uint64_t timestamp) - { - static o2::parameters::GRPMagField* grpo = nullptr; - if (grpo == nullptr) { - grpo = ccdb->getForTimeStamp(cfgMagnetField, timestamp); - if (grpo == nullptr) { - LOGF(fatal, "GRP object not found in %s for timestamp %llu", cfgMagnetField.value.c_str(), timestamp); - return 0; - } - LOGF(info, "Retrieved GRP from %s for timestamp %llu with magnetic field of %d kG", cfgMagnetField.value.c_str(), timestamp, grpo->getNominalL3Field()); - } - return grpo->getNominalL3Field(); - } - - template - bool trackSelected(TTrack track, const int field) - { - double phimodn = track.phi(); - if (field < 0) // for negative polarity field - phimodn = TMath::TwoPi() - phimodn; - if (track.sign() < 0) // for negative charge - phimodn = TMath::TwoPi() - phimodn; - if (phimodn < 0) - LOGF(warning, "phi < 0: %g", phimodn); - - phimodn += TMath::Pi() / 18.0; // to center gap in the middle - phimodn = fmod(phimodn, TMath::Pi() / 9.0); - registry.fill(HIST("pt_phi_bef"), track.pt(), phimodn); - if (phimodn < fPhiCutHigh->Eval(track.pt()) && phimodn > fPhiCutLow->Eval(track.pt())) - return false; // reject track - registry.fill(HIST("pt_phi_aft"), track.pt(), phimodn); - return true; - } - - void process(aodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, aodTracks const& tracks) - { - registry.fill(HIST("hEventCount"), 0.5); - if (!collision.sel8()) - return; - if (tracks.size() < 1) - return; - registry.fill(HIST("BeforeCut_globalTracks_centT0C"), collision.centFT0C(), tracks.size()); - registry.fill(HIST("BeforeCut_PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV()); - registry.fill(HIST("BeforeCut_globalTracks_PVTracks"), collision.multNTracksPV(), tracks.size()); - registry.fill(HIST("BeforeCut_globalTracks_multT0A"), collision.multFT0A(), tracks.size()); - registry.fill(HIST("BeforeCut_globalTracks_multV0A"), collision.multFV0A(), tracks.size()); - registry.fill(HIST("BeforeCut_multV0A_multT0A"), collision.multFT0A(), collision.multFV0A()); - registry.fill(HIST("BeforeCut_multT0C_centT0C"), collision.centFT0C(), collision.multFT0C()); - registry.fill(HIST("hEventCount"), 1.5); - // place holder for pile-up rejection - registry.fill(HIST("hEventCount"), 2.5); - const auto cent = collision.centFT0C(); - if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), cent)) - return; - registry.fill(HIST("hEventCount"), 3.5); - float l_Random = fRndm->Rndm(); - float vtxz = collision.posZ(); - registry.fill(HIST("hVtxZ"), vtxz); - registry.fill(HIST("hMult"), tracks.size()); - registry.fill(HIST("hCent"), collision.centFT0C()); - fGFW->Clear(); - auto bc = collision.bc_as(); - loadCorrections(bc.timestamp()); - registry.fill(HIST("hEventCount"), 4.5); - - // fill event QA - registry.fill(HIST("globalTracks_centT0C"), collision.centFT0C(), tracks.size()); - registry.fill(HIST("PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV()); - registry.fill(HIST("globalTracks_PVTracks"), collision.multNTracksPV(), tracks.size()); - registry.fill(HIST("globalTracks_multT0A"), collision.multFT0A(), tracks.size()); - registry.fill(HIST("globalTracks_multV0A"), collision.multFV0A(), tracks.size()); - registry.fill(HIST("multV0A_multT0A"), collision.multFT0A(), collision.multFV0A()); - registry.fill(HIST("multT0C_centT0C"), collision.centFT0C(), collision.multFT0C()); - - // track weights - float weff = 1, wacc = 1; - double weffEvent = 0; - double ptSum = 0., ptSum_Gap08 = 0.; - double weffEvent_WithinGap08 = 0., weffEventSquare_WithinGap08 = 0.; - double sum_ptSquare_wSquare_WithinGap08 = 0., sum_pt_wSquare_WithinGap08 = 0.; - int Magnetfield = 0; - double NTracksCorrected = 0; - if (cfgUseAdditionalTrackCut) { - // magnet field dependence cut - Magnetfield = getMagneticField(bc.timestamp()); - } - - for (auto& track : tracks) { - if (track.tpcNClsFound() < cfgCutTPCclu) - continue; - if (cfgUseAdditionalTrackCut && !trackSelected(track, Magnetfield)) - continue; - if (cfgOutputNUAWeights) - fWeights->Fill(track.phi(), track.eta(), vtxz, track.pt(), cent, 0); - if (!setCurrentParticleWeights(weff, wacc, track.phi(), track.eta(), track.pt(), vtxz)) - continue; - bool WithinPtPOI = (cfgCutPtPOIMin < track.pt()) && (track.pt() < cfgCutPtPOIMax); // within POI pT range - bool WithinPtRef = (cfgCutPtMin < track.pt()) && (track.pt() < cfgCutPtMax); // within RF pT range - bool WithinEtaGap08 = (track.eta() >= -0.4) && (track.eta() <= 0.4); - registry.fill(HIST("hPt"), track.pt()); - if (WithinPtRef) { - registry.fill(HIST("hPhi"), track.phi()); - registry.fill(HIST("hPhiWeighted"), track.phi(), wacc); - registry.fill(HIST("hEta"), track.eta()); - registry.fill(HIST("hPtRef"), track.pt()); - registry.fill(HIST("hChi2prTPCcls"), track.tpcChi2NCl()); - registry.fill(HIST("hnTPCClu"), track.tpcNClsFound()); - registry.fill(HIST("hnTPCCrossedRow"), track.tpcNClsCrossedRows()); - registry.fill(HIST("hDCAz"), track.dcaZ()); - registry.fill(HIST("hDCAxy"), track.dcaXY(), track.pt()); - weffEvent += weff; - ptSum += weff * track.pt(); - NTracksCorrected += weff; - if (WithinEtaGap08) { - ptSum_Gap08 += weff * track.pt(); - sum_pt_wSquare_WithinGap08 += weff * weff * track.pt(); - sum_ptSquare_wSquare_WithinGap08 += weff * weff * track.pt() * track.pt(); - weffEvent_WithinGap08 += weff; - weffEventSquare_WithinGap08 += weff * weff; - } - } - if (WithinPtRef) - fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), wacc * weff, 1); - if (WithinPtPOI) - fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), wacc * weff, 2); - if (WithinPtPOI && WithinPtRef) - fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), wacc * weff, 4); - } - registry.fill(HIST("hTrackCorrection2d"), tracks.size(), NTracksCorrected); - - double WeffEvent_diff_WithGap08 = weffEvent_WithinGap08 * weffEvent_WithinGap08 - weffEventSquare_WithinGap08; - // Filling TProfile - // MeanPt - if (weffEvent > 1e-6) - registry.fill(HIST("hMeanPt"), cent, ptSum / weffEvent, weffEvent); - if (weffEvent_WithinGap08 > 1e-6) - registry.fill(HIST("hMeanPtWithinGap08"), cent, ptSum_Gap08 / weffEvent_WithinGap08, weffEvent_WithinGap08); - // v22-Pt - // c22_gap8 * pt_withGap8 - if (weffEvent_WithinGap08 > 1e-6) - FillpTvnProfile(corrconfigs.at(7), ptSum_Gap08, weffEvent_WithinGap08, HIST("c22_gap08_Weff"), HIST("c22_gap08_trackMeanPt"), cent); - // PtVariance - if (WeffEvent_diff_WithGap08 > 1e-6) { - registry.fill(HIST("PtVariance_partA_WithinGap08"), cent, - (ptSum_Gap08 * ptSum_Gap08 - sum_ptSquare_wSquare_WithinGap08) / WeffEvent_diff_WithGap08, - WeffEvent_diff_WithGap08); - registry.fill(HIST("PtVariance_partB_WithinGap08"), cent, - (weffEvent_WithinGap08 * ptSum_Gap08 - sum_pt_wSquare_WithinGap08) / WeffEvent_diff_WithGap08, - WeffEvent_diff_WithGap08); - } - - // Filling Bootstrap Samples - int SampleIndex = static_cast(cfgNbootstrap * l_Random); - if (weffEvent_WithinGap08 > 1e-6) - BootstrapArray[SampleIndex][kMeanPt_InGap08]->Fill(cent, ptSum_Gap08 / weffEvent_WithinGap08, weffEvent_WithinGap08); - if (weffEvent_WithinGap08 > 1e-6) - FillpTvnProfile(corrconfigs.at(7), ptSum_Gap08, weffEvent_WithinGap08, BootstrapArray[SampleIndex][kC22_Gap08_Weff], BootstrapArray[SampleIndex][kC22_Gap08_MeanPt], cent); - if (WeffEvent_diff_WithGap08 > 1e-6) { - BootstrapArray[SampleIndex][kPtVarParA_InGap08]->Fill(cent, - (ptSum_Gap08 * ptSum_Gap08 - sum_ptSquare_wSquare_WithinGap08) / WeffEvent_diff_WithGap08, - WeffEvent_diff_WithGap08); - BootstrapArray[SampleIndex][kPtVarParB_InGap08]->Fill(cent, - (weffEvent_WithinGap08 * ptSum_Gap08 - sum_pt_wSquare_WithinGap08) / WeffEvent_diff_WithGap08, - WeffEvent_diff_WithGap08); - } - - // Filling Flow Container - for (uint l_ind = 0; l_ind < corrconfigs.size(); l_ind++) { - FillFC(corrconfigs.at(l_ind), cent, l_Random); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGCF/Flow/Tasks/flowAnalysisGF.cxx b/PWGCF/Flow/Tasks/flowAnalysisGF.cxx new file mode 100644 index 00000000000..08e223befb6 --- /dev/null +++ b/PWGCF/Flow/Tasks/flowAnalysisGF.cxx @@ -0,0 +1,763 @@ +// 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. + +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" + +#include "GFWPowerArray.h" +#include "GFW.h" +#include "GFWCumulant.h" +#include "FlowContainer.h" +#include "FlowPtContainer.h" +#include "GFWConfig.h" +#include "GFWWeights.h" +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; +namespace o2::analysis::flowanalysis +{ +std::vector ptbinning = { + 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, + 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, + 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, + 2, 2.2, 2.4, 2.6, 2.8, 3, 3.5, 4, 5, 6, 8, 10}; +float ptpoilow = 0.2, ptpoiup = 10.0; +float ptreflow = 0.2, ptrefup = 3.0; +float ptlow = 0.2, ptup = 10.0; +int etabins = 16; +float etalow = -0.8, etaup = 0.8; +int vtxZbins = 20; +float vtxZlow = -10.0, vtxZup = 10.0; +int phibins = 72; +float philow = 0.0; +float phiup = constants::math::TwoPI; +int nchbins = 300; +float nchlow = 0; +float nchup = 3000; +std::vector centbinning(90); +int nBootstrap = 10; +GFWRegions regions; +GFWCorrConfigs configs; +int eventBin = 0; +} // namespace o2::analysis::flowanalysis + +using namespace o2::analysis::flowanalysis; + +struct flowAnalysisGF { + + O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 10, "Number of subsamples") + O2_DEFINE_CONFIGURABLE(cfgMpar, int, 8, "Highest order of pt-pt correlations") + O2_DEFINE_CONFIGURABLE(cfgUseNch, bool, false, "Do correlations as function of Nch") + O2_DEFINE_CONFIGURABLE(cfgFillWeights, bool, false, "Fill NUA weights") + O2_DEFINE_CONFIGURABLE(cfgFillQA, bool, false, "Fill QA histograms") + O2_DEFINE_CONFIGURABLE(cfgUseAdditionalEventCut, bool, true, "Use additional event cut on mult correlations") + O2_DEFINE_CONFIGURABLE(cfgUseAdditionalTrackCut, bool, true, "Use additional track cut on phi") + O2_DEFINE_CONFIGURABLE(cfgEfficiency, std::string, "", "CCDB path to efficiency object") + O2_DEFINE_CONFIGURABLE(cfgAcceptance, std::string, "", "CCDB path to acceptance object") + O2_DEFINE_CONFIGURABLE(cfgDCAxy, float, 0.2, "Cut on DCA in the transverse direction (cm)"); + O2_DEFINE_CONFIGURABLE(cfgDCAz, float, 2, "Cut on DCA in the longitudinal direction (cm)"); + O2_DEFINE_CONFIGURABLE(cfgNcls, float, 70, "Cut on number of TPC clusters found"); + O2_DEFINE_CONFIGURABLE(cfgPtmin, float, 0.2, "minimum pt (GeV/c)"); + O2_DEFINE_CONFIGURABLE(cfgPtmax, float, 10, "maximum pt (GeV/c)"); + O2_DEFINE_CONFIGURABLE(cfgEta, float, 0.8, "eta cut"); + O2_DEFINE_CONFIGURABLE(cfgVtxZ, float, 10, "vertex cut (cm)"); + O2_DEFINE_CONFIGURABLE(cfgMagField, float, 99999, "Configurable magnetic field; default CCDB will be queried"); + // added + O2_DEFINE_CONFIGURABLE(cfgDoubleTrackFunction, bool, true, "Include track cut at low pt"); + O2_DEFINE_CONFIGURABLE(cfgTrackCutSize, float, 0.06, "Spread of track cut"); + O2_DEFINE_CONFIGURABLE(cfgMaxOccupancy, int, 500, "Maximum occupancy of selected events"); + O2_DEFINE_CONFIGURABLE(cfgNoSameBunchPileupCut, bool, true, "kNoSameBunchPileupCut"); + O2_DEFINE_CONFIGURABLE(cfgIsGoodZvtxFT0vsPV, bool, true, "kIsGoodZvtxFT0vsPV"); + O2_DEFINE_CONFIGURABLE(cfgNoCollInTimeRangeStandard, bool, true, "kNoCollInTimeRangeStandard"); + O2_DEFINE_CONFIGURABLE(cfgDoOccupancySel, bool, true, "Bool for event selection on detector occupancy"); + O2_DEFINE_CONFIGURABLE(cfgMultCut, bool, true, "Use additional evenr cut on mult correlations"); + O2_DEFINE_CONFIGURABLE(cfgTVXinTRD, bool, true, "Use kTVXinTRD (reject TRD triggered events)"); + O2_DEFINE_CONFIGURABLE(cfgIsVertexITSTPC, bool, true, "Selects collisions with at least one ITS-TPC track"); + + Configurable cfgGFWBinning{"cfgGFWBinning", {40, 16, 72, 300, 0, 3000, 0.2, 10.0, 0.2, 3.0, {0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 2.75, 3, 3.25, 3.5, 3.75, 4, 4.5, 5, 5.5, 6, 7, 8, 9, 10}, {0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}}, "Configuration for binning"}; + Configurable cfgRegions{"cfgRegions", {{"refN", "refP", "refFull", "poiN", "poiP", "poiFull", "olN", "olP", "olFull"}, {-0.8, 0.5, -0.8, -0.8, -0.8, 0.5, -0.8, -0.8}, {-0.5, 0.8, 0.8, -0.5, 0.8, 0.8, -0.5}, {0, 0, 0, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 2, 2, 2, 4, 4, 4}}, "Configurations for GFW regions"}; + + Configurable cfgCorrConfig{"cfgCorrConfig", {{"refP {2} refN {-2}", "poiP refP | olP {2} refN {-2}", "refP {3} refN {-3}", "refP {4} refN {-4}", "refFull {2 -2}", "poiFull refFull | olFull {2 -2}", "refFull {2 2 -2 -2}", "poiFull refFull | olFull {2 2 -2 -2}"}, {"ChGap22", "ChGap22", "ChGap32", "ChGap42", "ChFull22", "ChFull22", "ChFull24", "ChFull24"}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 1, 0, 1}}, "Configurations for each correlation to calculate"}; + + // Connect to ccdb + Service ccdb; + + struct Config { + TH1D* mEfficiency = nullptr; + GFWWeights* mAcceptance = nullptr; + bool correctionsLoaded = false; + } cfg; + + // Define output + OutputObj fFC{FlowContainer("FlowContainer")}; + OutputObj fFCpt{FlowPtContainer("FlowPtContainer")}; + OutputObj fFC_gen{FlowContainer("FlowContainer_gen")}; + OutputObj fWeights{GFWWeights("weights")}; + HistogramRegistry registry{"registry"}; + + // define global variables + GFW* fGFW = new GFW(); + std::vector corrconfigs; + TRandom3* fRndm = new TRandom3(0); + TAxis* fPtAxis; + + // Event selection cuts - Alex + TF1* fPhiCutLow = nullptr; + TF1* fPhiCutHigh = nullptr; + // for double track cut + TF1* fPhiCutLow2 = nullptr; + TF1* fPhiCutHigh2 = nullptr; + + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + TF1* fMultCutLow = nullptr; + TF1* fMultCutHigh = nullptr; + TF1* fMultMultPVCut = nullptr; + + void init(InitContext const&) + { + LOGF(info, "flowAnalysisGF::init()"); + regions.SetNames(cfgRegions->GetNames()); + regions.SetEtaMin(cfgRegions->GetEtaMin()); + regions.SetEtaMax(cfgRegions->GetEtaMax()); + regions.SetpTDifs(cfgRegions->GetpTDifs()); + regions.SetBitmasks(cfgRegions->GetBitmasks()); + configs.SetCorrs(cfgCorrConfig->GetCorrs()); + configs.SetHeads(cfgCorrConfig->GetHeads()); + configs.SetpTDifs(cfgCorrConfig->GetpTDifs()); + configs.SetpTCorrMasks(cfgCorrConfig->GetpTCorrMasks()); + + regions.Print(); + configs.Print(); + + ptbinning = cfgGFWBinning->GetPtBinning(); + ptpoilow = cfgGFWBinning->GetPtPOImin(); + ptpoiup = cfgGFWBinning->GetPtPOImax(); + ptreflow = cfgGFWBinning->GetPtRefMin(); + ptrefup = cfgGFWBinning->GetPtRefMax(); + ptlow = cfgPtmin; + ptup = cfgPtmax; + etabins = cfgGFWBinning->GetEtaBins(); + vtxZbins = cfgGFWBinning->GetVtxZbins(); + phibins = cfgGFWBinning->GetPhiBins(); + philow = 0.0f; + phiup = constants::math::TwoPI; + nchbins = cfgGFWBinning->GetNchBins(); + nchlow = cfgGFWBinning->GetNchMin(); + nchup = cfgGFWBinning->GetNchMax(); + centbinning = cfgGFWBinning->GetCentBinning(); + cfgGFWBinning->Print(); + + AxisSpec phiAxis = {phibins, philow, phiup, "#phi"}; + AxisSpec phiModAxis = {100, 0, constants::math::PI / 9, "fmod(#varphi,#pi/9)"}; + AxisSpec etaAxis = {etabins, -cfgEta, cfgEta, "#eta"}; + AxisSpec vtxAxis = {vtxZbins, -cfgVtxZ, cfgVtxZ, "Vtx_{z} (cm)"}; + AxisSpec ptAxis = {ptbinning, "#it{p}_{T} GeV/#it{c}"}; + AxisSpec centAxis = {centbinning, "Centrality (%)"}; + std::vector nchbinning; + int nchskip = (nchup - nchlow) / nchbins; + for (int i = 0; i <= nchbins; ++i) { + nchbinning.push_back(nchskip * i + nchlow + 0.5); + } + + AxisSpec nchAxis = {nchbinning, "N_{ch}"}; + AxisSpec t0cAxis = {70, 0, 70000, "N_{ch} (T0C)"}; + AxisSpec t0aAxis = {200, 0, 200, "N_{ch}"}; + AxisSpec multpvAxis = {4000, 0, 4000, "N_{ch} (PV)"}; + AxisSpec multAxis = (cfgUseNch) ? nchAxis : centAxis; + AxisSpec dcaZAxis = {200, -2, 2, "DCA_{z} (cm)"}; + AxisSpec dcaXYAxis = {200, -1, 1, "DCA_{xy} (cm)"}; + AxisSpec tpcAxis = {200, 0, 200, "TPC Clusters"}; + AxisSpec tpcAxisCl = {10, 0, 10, "TPC Crossed rows / findable Clusters"}; + AxisSpec dEdxAxis = {400, 0, 200, "TPC: dE/dx"}; + AxisSpec itsClAxis = {10, 0, 10, "Number of ITS clusters"}; + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + int64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); + + int ptbins = ptbinning.size() - 1; + fPtAxis = new TAxis(ptbins, &ptbinning[0]); + + if (cfgFillWeights) { + fWeights->setPtBins(ptbins, &ptbinning[0]); + fWeights->init(true, false); + } + + if (doprocessMCGen) { + registry.add("trackMCGen/pt_gen", "", {HistType::kTH1D, {ptAxis}}); + registry.add("trackMCGen/phi_eta_vtxZ_gen", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + } + if (doprocessMCReco || doprocessData || doprocessRun2) { + registry.add("trackQA/phi_eta_vtxZ", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + registry.add("trackQA/pt_dcaXY_dcaZ", "", {HistType::kTH3D, {ptAxis, dcaXYAxis, dcaZAxis}}); + registry.add("trackQA/pt_phi_bef", "", {HistType::kTH2D, {ptAxis, phiModAxis}}); + registry.add("trackQA/pt_phi_aft", "", {HistType::kTH2D, {ptAxis, phiModAxis}}); + registry.add("trackQA/phi_eta_vtxZ_corrected", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + registry.add("trackQA/pt_reco", "", {HistType::kTH1D, {ptAxis}}); + + registry.add("hEventCount", "Number of Event;; Count", {HistType::kTH1D, {{10, 0, 10}}}); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(1, "Filtered event"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(2, "sel8"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(3, "occupancy"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(4, "kTVXinTRD"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(5, "kNoSameBunchPileup"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(6, "kIsGoodZvtxFT0vsPV"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(7, "kNoCollInTimeRangeStandard"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(8, "kIsVertexITSTPC"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(9, "after Mult cuts"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(10, "corr + cent"); + + registry.add("eventQA/nITS_nTPC_Tracks", "", {HistType::kTH2D, {nchAxis, nchAxis}}); + + // track QA before and after selections + registry.add("trackQA/before/CrossedTPCRows_pt", "", {HistType::kTH2D, {ptAxis, tpcAxis}}); + registry.add("trackQA/before/NumberSharedClustersTPC_pt", "", {HistType::kTH2D, {ptAxis, tpcAxis}}); + registry.add("trackQA/before/ITSClusters_pt", "", {HistType::kTH2D, {ptAxis, itsClAxis}}); + registry.add("trackQA/before/DCAxy_pt", "", {HistType::kTH2D, {ptAxis, dcaXYAxis}}); + registry.add("trackQA/before/DCAz_pt", "", {HistType::kTH2D, {ptAxis, dcaZAxis}}); + registry.add("trackQA/before/tpcSignal_pt", "", {HistType::kTH2D, {ptAxis, dEdxAxis}}); + registry.add("trackQA/before/phi_pt", "", {HistType::kTH2D, {ptAxis, phiAxis}}); + registry.add("trackQA/before/phi_eta", "", {HistType::kTH2D, {etaAxis, phiAxis}}); + registry.add("trackQA/before/tpcCrossedRowsOverFindableCls_pt", "", {HistType::kTH2D, {ptAxis, tpcAxisCl}}); + registry.addClone("trackQA/before/", "trackQA/after/"); + + // track QA after selections + registry.add("eventQA/before/globalTracks_centT0C", "", {HistType::kTH2D, {centAxis, nchAxis}}); + registry.add("eventQA/before/PVTracks_centT0C", "", {HistType::kTH2D, {centAxis, multpvAxis}}); + registry.add("eventQA/before/globalTracks_PVTracks", "", {HistType::kTH2D, {multpvAxis, nchAxis}}); + registry.add("eventQA/before/globalTracks_multT0A", "", {HistType::kTH2D, {t0aAxis, nchAxis}}); + registry.add("eventQA/before/globalTracks_multV0A", "", {HistType::kTH2D, {t0aAxis, nchAxis}}); + registry.add("eventQA/before/multV0A_multT0A", "", {HistType::kTH2D, {t0aAxis, t0aAxis}}); + registry.add("eventQA/before/multT0C_centT0C", "", {HistType::kTH2D, {centAxis, t0cAxis}}); + registry.addClone("eventQA/before/", "eventQA/after/"); + } + + if (regions.GetSize() < 0) + LOGF(error, "Configuration contains vectors of different size - check the GFWRegions configurable"); + for (auto i(0); i < regions.GetSize(); ++i) { + fGFW->AddRegion(regions.GetNames()[i], regions.GetEtaMin()[i], regions.GetEtaMax()[i], (regions.GetpTDifs()[i]) ? ptbins + 1 : 1, regions.GetBitmasks()[i]); + } + for (auto i = 0; i < configs.GetSize(); ++i) { + corrconfigs.push_back(fGFW->GetCorrelatorConfig(configs.GetCorrs()[i], configs.GetHeads()[i], configs.GetpTDifs()[i])); + } + if (corrconfigs.empty()) + LOGF(error, "Configuration contains vectors of different size - check the GFWCorrConfig configurable"); + fGFW->CreateRegions(); + TObjArray* oba = new TObjArray(); + AddConfigObjectsToObjArray(oba, corrconfigs); + + fFC->SetName("FlowContainer"); + fFC->SetXAxis(fPtAxis); + fFC->Initialize(oba, multAxis, cfgNbootstrap); + + delete oba; + fFCpt->initialise(multAxis, cfgMpar, configs, cfgNbootstrap); + + // Event selection - Alex + if (cfgUseAdditionalEventCut) { + // zzh pas3 + fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x - 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); + fMultPVCutLow->SetParameters(3307.55, -122.1, 1.97653, -0.0172405, 6.57892e-05, 147.955, -2.40658, 0.00626944, 7.19406e-05, -3.92605e-07); + + fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x + 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); + fMultPVCutHigh->SetParameters(3307.55, -122.1, 1.97653, -0.0172405, 6.57892e-05, 147.955, -2.40658, 0.00626944, 7.19406e-05, -3.92605e-07); + + fMultCutLow = new TF1("fMultCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultCutLow->SetParameters(1770.02, -49.5537, 0.460941, -0.00140622, 105.477, -1.58301, 0.011655, -0.000190804, 1.36003e-06); + + fMultCutHigh = new TF1("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 3.*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultCutHigh->SetParameters(1770.02, -49.5537, 0.460941, -0.00140622, 105.477, -1.58301, 0.011655, -0.000190804, 1.36003e-06); + } + + if (cfgUseAdditionalTrackCut) { + // 0.06 + fPhiCutLow = new TF1("fPhiCutLow", TString::Format("0.06/x+pi/18.0-%f", static_cast(cfgTrackCutSize)), 0, 100); + fPhiCutHigh = new TF1("fPhiCutHigh", TString::Format("0.1/x+pi/18.0+%f", static_cast(cfgTrackCutSize)), 0, 100); + + if (cfgDoubleTrackFunction) { + fPhiCutLow2 = new TF1("fPhiCutLow2", TString::Format("0.06/x+pi/18.0-%f-pi/9", static_cast(cfgTrackCutSize)), 0, 100); // for the lower part of the gap (pt<1) + fPhiCutHigh2 = new TF1("fPhiCutHigh2", TString::Format("0.1/x+pi/18.0+%f-pi/9", static_cast(cfgTrackCutSize)), 0, 100); + } + } + } + + static constexpr std::string_view moment[] = { + "before/", + "after/"}; + + enum QAtime { + kBefore, + kAfter + }; + + void AddConfigObjectsToObjArray(TObjArray* oba, const std::vector& configs) + { + for (auto it = configs.begin(); it != configs.end(); ++it) { + if (it->pTDif) { + std::string suffix = "_ptDiff"; + for (auto i = 0; i < fPtAxis->GetNbins(); ++i) { + std::string index = Form("_pt_%i", i + 1); + oba->Add(new TNamed(it->Head.c_str() + index, it->Head.c_str() + suffix)); + } + } else { + oba->Add(new TNamed(it->Head.c_str(), it->Head.c_str())); + } + } + } + + int getMagneticField(uint64_t timestamp) + { + // TODO done only once (and not per run). Will be replaced by CCDBConfigurable + // static o2::parameters::GRPObject* grpo = nullptr; + static o2::parameters::GRPMagField* grpo = nullptr; + if (grpo == nullptr) { + grpo = ccdb->getForTimeStamp("GLO/Config/GRPMagField", timestamp); + if (grpo == nullptr) { + LOGF(fatal, "GRP object not found for timestamp %llu", timestamp); + return 0; + } + LOGF(info, "Retrieved GRP for timestamp %llu with magnetic field of %d kG", timestamp, grpo->getNominalL3Field()); + } + return grpo->getNominalL3Field(); + } + + void loadCorrections(uint64_t timestamp) + { + if (cfg.correctionsLoaded) + return; + if (cfgAcceptance.value.empty() == false) { + cfg.mAcceptance = ccdb->getForTimeStamp(cfgAcceptance, timestamp); + if (cfg.mAcceptance) + LOGF(info, "Loaded acceptance weights from %s (%p)", cfgAcceptance.value.c_str(), (void*)cfg.mAcceptance); + else + LOGF(warning, "Could not load acceptance weights from %s (%p)", cfgAcceptance.value.c_str(), (void*)cfg.mAcceptance); + } + if (cfgEfficiency.value.empty() == false) { + cfg.mEfficiency = ccdb->getForTimeStamp(cfgEfficiency, timestamp); + if (cfg.mEfficiency == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgEfficiency.value.c_str()); + } + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgEfficiency.value.c_str(), (void*)cfg.mEfficiency); + } + cfg.correctionsLoaded = true; + } + + bool setCurrentParticleWeights(float& weight_nue, float& weight_nua, const float& phi, const float& eta, const float& pt, const float& vtxz) + { + float eff = 1.; + if (cfg.mEfficiency) + eff = cfg.mEfficiency->GetBinContent(cfg.mEfficiency->FindBin(pt)); + else + eff = 1.0; + if (eff == 0) + return false; + weight_nue = 1. / eff; + if (cfg.mAcceptance) + weight_nua = cfg.mAcceptance->getNUA(phi, eta, vtxz); + else + weight_nua = 1; + return true; + } + + template + bool eventSelected(TCollision collision, const int& multTrk, const float& centrality) + { + if (cfgTVXinTRD) { + if (collision.alias_bit(kTVXinTRD)) { + // TRD triggered + // "CMTVX-B-NOPF-TRD,minbias_TVX" + return 0; + } + registry.fill(HIST("hEventCount"), 3.5); + } + + if (cfgNoSameBunchPileupCut) { + if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + // rejects collisions which are associated with the same "found-by-T0" bunch crossing + // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof + return 0; + } + registry.fill(HIST("hEventCount"), 4.5); + } + if (cfgIsGoodZvtxFT0vsPV) { + if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference + // use this cut at low multiplicities with caution + return 0; + } + registry.fill(HIST("hEventCount"), 5.5); + } + if (cfgNoCollInTimeRangeStandard) { + if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // Rejection of the collisions which have other events nearby + return 0; + } + registry.fill(HIST("hEventCount"), 6.5); + } + + if (cfgIsVertexITSTPC) { + if (!collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + // selects collisions with at least one ITS-TPC track, and thus rejects vertices built from ITS-only tracks + return 0; + } + registry.fill(HIST("hEventCount"), 7.5); + } + + float vtxz = -999; + if (collision.numContrib() > 1) { + vtxz = collision.posZ(); + float zRes = TMath::Sqrt(collision.covZZ()); + if (zRes > 0.25 && collision.numContrib() < 20) + vtxz = -999; + } + + auto multNTracksPV = collision.multNTracksPV(); + + if (vtxz > vtxZup || vtxz < vtxZlow) + return 0; + + if (cfgMultCut) { + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) + return 0; + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) + return 0; + if (multTrk < fMultCutLow->Eval(centrality)) + return 0; + if (multTrk > fMultCutHigh->Eval(centrality)) + return 0; + registry.fill(HIST("hEventCount"), 8.5); + } + + return 1; + } + + template + bool trackSelected(TTrack track, const int& field) + { + double phimodn = track.phi(); + if (field < 0) // for negative polarity field + phimodn = TMath::TwoPi() - phimodn; + if (track.sign() < 0) // for negative charge + phimodn = TMath::TwoPi() - phimodn; + if (phimodn < 0) + LOGF(debug, "phi < 0: %g", phimodn); + + phimodn += TMath::Pi() / 18.0; // to center gap in the middle + phimodn = fmod(phimodn, TMath::Pi() / 9.0); + registry.fill(HIST("trackQA/pt_phi_bef"), track.pt(), phimodn); + if (phimodn < fPhiCutHigh->Eval(track.pt()) && phimodn > fPhiCutLow->Eval(track.pt())) + return false; // reject track + if (cfgDoubleTrackFunction) { + if (phimodn < fPhiCutHigh2->Eval(track.pt()) && phimodn > fPhiCutLow2->Eval(track.pt())) + return false; // reject track + } + registry.fill(HIST("trackQA/pt_phi_aft"), track.pt(), phimodn); + return true; + } + + enum datatype { + kReco, + kGen + }; + + void FillOutputContainers(datatype dt, const float& centmult, const double& rndm) + { + fFCpt->calculateCorrelations(); + fFCpt->fillPtProfiles(centmult, rndm); + fFCpt->fillCMProfiles(centmult, rndm); + for (uint l_ind = 0; l_ind < corrconfigs.size(); ++l_ind) { + auto dnx = fGFW->Calculate(corrconfigs.at(l_ind), 0, kTRUE).real(); + if (dnx == 0) + continue; + if (!corrconfigs.at(l_ind).pTDif) { + auto val = fGFW->Calculate(corrconfigs.at(l_ind), 0, kFALSE).real() / dnx; + if (TMath::Abs(val) < 1) { + (dt == kGen) ? fFC_gen->FillProfile(corrconfigs.at(l_ind).Head.c_str(), centmult, val, dnx, rndm) : fFC->FillProfile(corrconfigs.at(l_ind).Head.c_str(), centmult, val, dnx, rndm); + fFCpt->fillVnPtProfiles(centmult, val, dnx, rndm, configs.GetpTCorrMasks()[l_ind]); + } + continue; + } + for (Int_t i = 1; i <= fPtAxis->GetNbins(); i++) { + dnx = fGFW->Calculate(corrconfigs.at(l_ind), i - 1, kTRUE).real(); + if (dnx == 0) + continue; + auto val = fGFW->Calculate(corrconfigs.at(l_ind), i - 1, kFALSE).real() / dnx; + if (TMath::Abs(val) < 1) + (dt == kGen) ? fFC_gen->FillProfile(Form("%s_pt_%i", corrconfigs.at(l_ind).Head.c_str(), i), centmult, val, dnx, rndm) : fFC->FillProfile(Form("%s_pt_%i", corrconfigs.at(l_ind).Head.c_str(), i), centmult, val, dnx, rndm); + } + } + return; + } + + template + void processCollision(datatype dt, TCollision const& collision, TTracks tracks, const float& centrality, const int& field) + { + + if (tracks.size() < 1) + return; + if (centrality < centbinning.front() || centrality > centbinning.back()) + return; + registry.fill(HIST("hEventCount"), 9.5); + float vtxz = collision.posZ(); + fGFW->Clear(); + fFCpt->clearVector(); + float l_Random = fRndm->Rndm(); + + std::vector ITS_TPC_tracks(6, 0); + + for (auto& track : tracks) { + ProcessTrack(track, centrality, vtxz, field); + FillITSTPCQA(track, ITS_TPC_tracks); + } + registry.fill(HIST("eventQA/nITS_nTPC_Tracks"), ITS_TPC_tracks[1], ITS_TPC_tracks[2]); + + FillOutputContainers(dt, (cfgUseNch) ? tracks.size() : centrality, l_Random); + } + + template + inline void FillITSTPCQA(TrackObject const& track, std::vector& ITS_TPC_tracks) + { + if constexpr (!framework::has_type_v) { + // if track its and tpc required then these three are the same + if (track.hasITS() || track.hasTPC()) + ITS_TPC_tracks[0] += 1; + if (track.hasITS()) + ITS_TPC_tracks[1] += 1; + if (track.hasTPC()) + ITS_TPC_tracks[2] += 1; + if (track.hasITS() && track.hasTPC()) + ITS_TPC_tracks[3] += 1; + if (track.hasITS() && !track.hasTPC()) + ITS_TPC_tracks[4] += 1; + if (track.hasTPC() && !track.hasITS()) + ITS_TPC_tracks[5] += 1; + } + } + + template + inline void ProcessTrack(TrackObject const& track, const float& centrality, const float& vtxz, const int& field) + { + float weff = 1, wacc = 1; + + auto handleReco = [&](auto const& particle) -> bool { + if (cfgFillQA) + FillTrackQA(track, vtxz); + + if (cfgUseAdditionalTrackCut && !trackSelected(track, field)) + return false; + + if (cfgFillWeights) + fWeights->fill(particle.phi(), particle.eta(), vtxz, particle.pt(), centrality, 0); + + if (!setCurrentParticleWeights(weff, wacc, particle.phi(), particle.eta(), particle.pt(), vtxz)) + return false; + + if (cfgFillQA) + FillTrackQA(track, vtxz); + + FillGFW(particle, weff, wacc); + + return true; + }; + + if constexpr (framework::has_type_v) { + if (track.mcParticleId() < 0 || !(track.has_mcParticle())) + return; + + auto mcParticle = track.mcParticle(); + if (!mcParticle.isPhysicalPrimary() || mcParticle.eta() < etalow || mcParticle.eta() > etaup || mcParticle.pt() < ptlow || mcParticle.pt() > ptup || track.tpcNClsFound() < cfgNcls) + return; + + if (!handleReco(mcParticle)) + return; + + registry.fill(HIST("trackQA/phi_eta_vtxZ_corrected"), mcParticle.phi(), mcParticle.eta(), vtxz, wacc); + + } else if constexpr (framework::has_type_v) { + if (!track.isPhysicalPrimary() || track.eta() < etalow || track.eta() > etaup || track.pt() < ptlow || track.pt() > ptup) + return; + + if (cfgFillQA) + FillTrackQA(track, vtxz); + + FillGFW(track, 1., 1.); + } else { + if (track.tpcNClsFound() < cfgNcls) + return; + + if (!handleReco(track)) + return; + + registry.fill(HIST("trackQA/phi_eta_vtxZ_corrected"), track.phi(), track.eta(), vtxz, wacc); + } + } + + template + inline void FillGFW(TrackObject track, float weff, float wacc) + { + fFCpt->fill(weff, track.pt()); + bool WithinPtPOI = (ptpoilow < track.pt()) && (track.pt() < ptpoiup); // within POI pT range + bool WithinPtRef = (ptreflow < track.pt()) && (track.pt() < ptrefup); // within RF pT range + if (WithinPtRef) + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 1); + if (WithinPtPOI) + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 2); + if (WithinPtPOI && WithinPtRef) + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 4); + return; + } + + template + inline void FillTrackQA(TrackObject track, const float vtxz) + { + if constexpr (framework::has_type_v) { + registry.fill(HIST("trackMCGen/phi_eta_vtxZ_gen"), track.phi(), track.eta(), vtxz); + registry.fill(HIST("trackMCGen/pt_gen"), track.pt()); + } else { + registry.fill(HIST("trackQA/phi_eta_vtxZ"), track.phi(), track.eta(), vtxz); + registry.fill(HIST("trackQA/pt_dcaXY_dcaZ"), track.pt(), track.dcaXY(), track.dcaZ()); + registry.fill(HIST("trackQA/pt_reco"), track.pt()); + registry.fill(HIST("trackQA/") + HIST(moment[qt]) + HIST("CrossedTPCRows_pt"), track.pt(), track.tpcNClsCrossedRows()); + registry.fill(HIST("trackQA/") + HIST(moment[qt]) + HIST("NumberSharedClustersTPC_pt"), track.pt(), track.tpcNClsShared()); + registry.fill(HIST("trackQA/") + HIST(moment[qt]) + HIST("ITSClusters_pt"), track.pt(), track.itsNCls()); + registry.fill(HIST("trackQA/") + HIST(moment[qt]) + HIST("DCAxy_pt"), track.pt(), track.dcaXY()); + registry.fill(HIST("trackQA/") + HIST(moment[qt]) + HIST("DCAz_pt"), track.pt(), track.dcaZ()); + registry.fill(HIST("trackQA/") + HIST(moment[qt]) + HIST("tpcSignal_pt"), track.pt(), track.tpcSignal()); + registry.fill(HIST("trackQA/") + HIST(moment[qt]) + HIST("phi_pt"), track.pt(), track.phi()); + registry.fill(HIST("trackQA/") + HIST(moment[qt]) + HIST("phi_eta"), track.eta(), track.phi()); + registry.fill(HIST("trackQA/") + HIST(moment[qt]) + HIST("tpcCrossedRowsOverFindableCls_pt"), track.pt(), track.tpcCrossedRowsOverFindableCls()); + } + } + + template + inline void FillEventQA(CollisionObject collision, TracksObject tracks) + { + + if constexpr (framework::has_type_v) { + registry.fill(HIST("eventQA/") + HIST(moment[qt]) + HIST("globalTracks_centT0C"), collision.centFT0C(), tracks.size()); + registry.fill(HIST("eventQA/") + HIST(moment[qt]) + HIST("PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV()); + registry.fill(HIST("eventQA/") + HIST(moment[qt]) + HIST("globalTracks_PVTracks"), collision.multNTracksPV(), tracks.size()); + registry.fill(HIST("eventQA/") + HIST(moment[qt]) + HIST("globalTracks_multT0A"), collision.multFT0A(), tracks.size()); + registry.fill(HIST("eventQA/") + HIST(moment[qt]) + HIST("globalTracks_multV0A"), collision.multFV0A(), tracks.size()); + registry.fill(HIST("eventQA/") + HIST(moment[qt]) + HIST("multV0A_multT0A"), collision.multFT0A(), collision.multFV0A()); + registry.fill(HIST("eventQA/") + HIST(moment[qt]) + HIST("multT0C_centT0C"), collision.centFT0C(), collision.multFT0C()); + } + } + + template + inline void RunProcess(CollisionObject collision, TracksObject tracks) + { + + float centrality; + + if constexpr (framework::has_type_v) { + if (!collision.sel7()) + return; + centrality = collision.centRun2V0M(); + } else if constexpr (framework::has_type_v) { + registry.fill(HIST("hEventCount"), .5); + if (!collision.sel8()) + return; + registry.fill(HIST("hEventCount"), 1.5); + centrality = collision.centFT0C(); + + if (cfgFillQA) + FillEventQA(collision, tracks); + } + + if (cfgDoOccupancySel) { + int occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy < 0 || occupancy > cfgMaxOccupancy) + return; + registry.fill(HIST("hEventCount"), 2.5); + } + + auto bc = collision.template bc_as(); + if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), centrality)) + return; + if (cfgFillQA) + FillEventQA(collision, tracks); + + loadCorrections(bc.timestamp()); + auto field = (cfgMagField == 99999) ? getMagneticField(bc.timestamp()) : cfgMagField; + processCollision(kReco, collision, tracks, centrality, field); + } + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgVtxZ; + Filter trackFilter = nabs(aod::track::eta) < cfgEta && aod::track::pt > cfgPtmin&& aod::track::pt < cfgPtmax && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && nabs(aod::track::dcaXY) < cfgDCAxy&& nabs(aod::track::dcaZ) < cfgDCAz; + + using myTracks = soa::Filtered>; + + void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, myTracks const& tracks) + { + RunProcess(collision, tracks); + } + PROCESS_SWITCH(flowAnalysisGF, processData, "Process analysis for non-derived data", true); + + void processMCReco(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks, aod::McParticles const&) + { + RunProcess(collision, tracks); + } + PROCESS_SWITCH(flowAnalysisGF, processMCReco, "Process analysis for MC reconstructed events", false); + + Filter mcCollFilter = nabs(aod::mccollision::posZ) < cfgVtxZ; + void processMCGen(soa::Filtered::iterator const& mcCollision, soa::SmallGroups> const& collisions, aod::McParticles const& particles) + { + if (collisions.size() != 1) + return; + float centrality = -1; + for (auto& collision : collisions) { + centrality = collision.centFT0C(); + } + processCollision(kGen, mcCollision, particles, centrality, -999); + } + PROCESS_SWITCH(flowAnalysisGF, processMCGen, "Process analysis for MC generated events", false); + + void processRun2(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, myTracks const& tracks) + { + RunProcess(collision, tracks); + } + PROCESS_SWITCH(flowAnalysisGF, processRun2, "Process analysis for Run 2 converted data", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGCF/Flow/Tasks/flowEfficiencyCasc.cxx b/PWGCF/Flow/Tasks/flowEfficiencyCasc.cxx new file mode 100644 index 00000000000..25e23838586 --- /dev/null +++ b/PWGCF/Flow/Tasks/flowEfficiencyCasc.cxx @@ -0,0 +1,379 @@ +// 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 flowEfficiencyCasc.cxx +/// \author Fuchun Cui(fcui@cern.ch) +/// \since Feb/21/2025 +/// \brief This task is to calculate V0s and cascades local density efficiency + +#include +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGLF/DataModel/cascqaanalysis.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "CommonConstants/PhysicsConstants.h" +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct FlowEfficiencyCasc { + O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 3.0f, "Maximal pT for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5f, "max chi2 per TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyHigh, int, 500, "High cut on TPC occupancy") + // topological cut for V0 + O2_DEFINE_CONFIGURABLE(cfgv0_radius, float, 5.0f, "minimum decay radius") + O2_DEFINE_CONFIGURABLE(cfgv0_v0cospa, float, 0.995f, "minimum cosine of pointing angle") + O2_DEFINE_CONFIGURABLE(cfgv0_dcadautopv, float, 0.1f, "minimum daughter DCA to PV") + O2_DEFINE_CONFIGURABLE(cfgv0_dcav0dau, float, 0.5f, "maximum DCA among V0 daughters") + O2_DEFINE_CONFIGURABLE(cfgv0_mk0swindow, float, 0.1f, "Invariant mass window of K0s") + O2_DEFINE_CONFIGURABLE(cfgv0_mlambdawindow, float, 0.04f, "Invariant mass window of lambda") + O2_DEFINE_CONFIGURABLE(cfgv0_ArmPodocut, float, 0.2f, "Armenteros Podolski cut for K0") + // topological cut for cascade + O2_DEFINE_CONFIGURABLE(cfgcasc_radius, float, 0.5f, "minimum decay radius") + O2_DEFINE_CONFIGURABLE(cfgcasc_casccospa, float, 0.999f, "minimum cosine of pointing angle") + O2_DEFINE_CONFIGURABLE(cfgcasc_v0cospa, float, 0.998f, "minimum cosine of pointing angle") + O2_DEFINE_CONFIGURABLE(cfgcasc_dcav0topv, float, 0.01f, "minimum daughter DCA to PV") + O2_DEFINE_CONFIGURABLE(cfgcasc_dcabachtopv, float, 0.01f, "minimum bachelor DCA to PV") + O2_DEFINE_CONFIGURABLE(cfgcasc_dcacascdau, float, 0.3f, "maximum DCA among cascade daughters") + O2_DEFINE_CONFIGURABLE(cfgcasc_dcav0dau, float, 1.0f, "maximum DCA among V0 daughters") + O2_DEFINE_CONFIGURABLE(cfgcasc_mlambdawindow, float, 0.04f, "Invariant mass window of lambda") + // track quality and type selections + O2_DEFINE_CONFIGURABLE(cfgtpcclusters, int, 0, "minimum number of TPC clusters requirement") + O2_DEFINE_CONFIGURABLE(cfgitsclusters, int, 0, "minimum number of ITS clusters requirement") + O2_DEFINE_CONFIGURABLE(cfgtpcclufindable, int, 0, "minimum number of findable TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgtpccrossoverfindable, int, 0, "minimum number of Ratio crossed rows over findable clusters") + O2_DEFINE_CONFIGURABLE(cfgcheckDauTPC, bool, true, "check daughter tracks TPC or not") + O2_DEFINE_CONFIGURABLE(cfgcheckDauTOF, bool, false, "check daughter tracks TOF or not") + O2_DEFINE_CONFIGURABLE(cfgcheckMCParticle, bool, false, "check the particle and deacy channel match or not") + O2_DEFINE_CONFIGURABLE(cfgCasc_rapidity, float, 0.5, "rapidity") + + O2_DEFINE_CONFIGURABLE(cfgNSigmatpctof, std::vector, (std::vector{3, 3, 3}), "tpc and tof NSigma for Pion Kaon Proton") + + ConfigurableAxis cfgaxisPt{"cfgaxisPt", {VARIABLE_WIDTH, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.20, 2.40, 2.60, 2.80, 3.00, 3.50, 4.00, 4.50, 5.00, 5.50, 6.00, 10.0}, "pt (GeV)"}; + ConfigurableAxis cfgaxisPtXi{"cfgaxisPtXi", {VARIABLE_WIDTH, 0, 0.1, 0.5, 0.9, 1.1, 1.3, 1.5, 1.7, 1.9, 2.1, 2.3, 2.5, 2.7, 2.9, 3.9, 4.9, 5.9, 9.9}, "pt (GeV)"}; + ConfigurableAxis cfgaxisPtOmega{"cfgaxisPtOmega", {VARIABLE_WIDTH, 0, 0.1, 0.5, 0.9, 1.1, 1.3, 1.5, 1.7, 1.9, 2.1, 2.3, 2.5, 2.7, 2.9, 3.9, 4.9, 5.9, 9.9}, "pt (GeV)"}; + ConfigurableAxis cfgaxisPtV0{"cfgaxisPtV0", {VARIABLE_WIDTH, 0, 0.1, 0.5, 0.9, 1.1, 1.3, 1.5, 1.7, 1.9, 2.1, 2.3, 2.5, 2.7, 2.9, 3.9, 4.9, 5.9, 9.9}, "pt (GeV)"}; + ConfigurableAxis cfgaxisMultiplicity{"cfgaxisMultiplicity", {1000, 0, 5000}, "Nch"}; + ConfigurableAxis cfgaxisCentrality{"cfgaxisCentrality", {0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}, "Centrality (%)"}; + + AxisSpec axisOmegaMass = {80, 1.63f, 1.71f, "Inv. Mass (GeV)"}; + AxisSpec axisXiMass = {70, 1.3f, 1.37f, "Inv. Mass (GeV)"}; + AxisSpec axisK0sMass = {400, 0.4f, 0.6f, "Inv. Mass (GeV)"}; + AxisSpec axisLambdaMass = {160, 1.08f, 1.16f, "Inv. Mass (GeV)"}; + + using MyCollisions = soa::Join; + using MyMcCollisions = soa::Join; + using CascMCCandidates = soa::Join; + using V0MCCandidates = soa::Join; + using DaughterTracks = soa::Join; + + // Define the output + HistogramRegistry registry{"registry"}; + + std::vector cfgNSigma = cfgNSigmatpctof; + + void init(InitContext const&) + { + const AxisSpec axisCounter{2, 0, 2, ""}; + // create histograms + registry.add("eventCounter", "eventCounter", kTH1F, {axisCounter}); + registry.add("mcEventCounter", "Monte Carlo Truth EventCounter", kTH1F, {axisCounter}); + registry.add("h2DCentvsNch", "", {HistType::kTH2D, {cfgaxisCentrality, cfgaxisMultiplicity}}); + + registry.add("h2DGenK0s", "", {HistType::kTH2D, {cfgaxisPtV0, cfgaxisMultiplicity}}); + registry.add("h2DGenLambda", "", {HistType::kTH2D, {cfgaxisPtV0, cfgaxisMultiplicity}}); + registry.add("h2DGenXi", "", {HistType::kTH2D, {cfgaxisPtXi, cfgaxisMultiplicity}}); + registry.add("h2DGenOmega", "", {HistType::kTH2D, {cfgaxisPtOmega, cfgaxisMultiplicity}}); + registry.add("h3DRecK0s", "", {HistType::kTH3D, {cfgaxisPtV0, cfgaxisMultiplicity, axisK0sMass}}); + registry.add("h3DRecLambda", "", {HistType::kTH3D, {cfgaxisPtV0, cfgaxisMultiplicity, axisLambdaMass}}); + registry.add("h3DRecXi", "", {HistType::kTH3D, {cfgaxisPtXi, cfgaxisMultiplicity, axisXiMass}}); + registry.add("h3DRecOmega", "", {HistType::kTH3D, {cfgaxisPtOmega, cfgaxisMultiplicity, axisOmegaMass}}); + + // V0 QA + registry.add("QAhisto/V0/hqaV0radiusbefore", "", {HistType::kTH1D, {{200, 0, 200}}}); + registry.add("QAhisto/V0/hqaV0radiusafter", "", {HistType::kTH1D, {{200, 0, 200}}}); + registry.add("QAhisto/V0/hqaV0cosPAbefore", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/V0/hqaV0cosPAafter", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/V0/hqadcaV0daubefore", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/V0/hqadcaV0dauafter", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/V0/hqaarm_podobefore", "", {HistType::kTH2D, {{100, -1, 1}, {50, 0, 0.3}}}); + registry.add("QAhisto/V0/hqaarm_podoafter", "", {HistType::kTH2D, {{100, -1, 1}, {50, 0, 0.3}}}); + registry.add("QAhisto/V0/hqadcapostoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/V0/hqadcapostoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/V0/hqadcanegtoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/V0/hqadcanegtoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + // Cascade QA + registry.add("QAhisto/Casc/hqaCasccosPAbefore", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Casc/hqaCasccosPAafter", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Casc/hqaCascV0cosPAbefore", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Casc/hqaCascV0cosPAafter", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Casc/hqadcaCascV0toPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Casc/hqadcaCascV0toPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Casc/hqadcaCascBachtoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Casc/hqadcaCascBachtoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Casc/hqadcaCascdaubefore", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/Casc/hqadcaCascdauafter", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/Casc/hqadcaCascV0daubefore", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/Casc/hqadcaCascV0dauafter", "", {HistType::kTH1D, {{100, 0, 1}}}); + } + template + bool eventSelected(TCollision collision) + { + if (collision.alias_bit(kTVXinTRD)) { + // TRD triggered + return false; + } + if (!collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + // reject collisions close to Time Frame borders + // https://its.cern.ch/jira/browse/O2-4623 + return false; + } + if (!collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + // reject events affected by the ITS ROF border + // https://its.cern.ch/jira/browse/O2-4309 + return false; + } + if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + // rejects collisions which are associated with the same "found-by-T0" bunch crossing + // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof + return false; + } + if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference + // use this cut at low multiplicities with caution + return false; + } + if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // no collisions in specified time range + return false; + } + if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + // cut time intervals with dead ITS staves + return false; + } + + auto occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy > cfgCutOccupancyHigh) + return false; + + // // V0A T0A 5 sigma cut + // if (std::fabs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > 5 * fT0AV0ASigma->Eval(collision.multFT0A())) + // return false; + + return true; + } + + void processRec(MyCollisions::iterator const& collision, V0MCCandidates const& V0s, CascMCCandidates const& Cascades, DaughterTracks const&, soa::Join const&, soa::Join const&) + { + registry.fill(HIST("eventCounter"), 0.5); + if (!collision.sel8()) + return; + if (eventSelected(collision)) + return; + registry.fill(HIST("eventCounter"), 1.5); + int rectracknum = collision.multNTracksGlobal(); + registry.fill(HIST("h2DCentvsNch"), collision.centFT0C(), rectracknum); + for (const auto& casc : Cascades) { + if (!casc.has_cascMCCore()) + continue; + auto cascMC = casc.cascMCCore_as>(); + auto negdau = casc.negTrackExtra_as(); + auto posdau = casc.posTrackExtra_as(); + auto bachelor = casc.bachTrackExtra_as(); + // fill QA + registry.fill(HIST("QAhisto/Casc/hqaCasccosPAbefore"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqaCascV0cosPAbefore"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqadcaCascV0toPVbefore"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqadcaCascBachtoPVbefore"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Casc/hqadcaCascdaubefore"), casc.dcacascdaughters()); + registry.fill(HIST("QAhisto/Casc/hqadcaCascV0daubefore"), casc.dcaV0daughters()); + // track quality check + if (bachelor.tpcNClsFound() < cfgtpcclusters) + continue; + if (posdau.tpcNClsFound() < cfgtpcclusters) + continue; + if (negdau.tpcNClsFound() < cfgtpcclusters) + continue; + if (bachelor.itsNCls() < cfgitsclusters) + continue; + if (posdau.itsNCls() < cfgitsclusters) + continue; + if (negdau.itsNCls() < cfgitsclusters) + continue; + // topological cut + if (casc.cascradius() < cfgcasc_radius) + continue; + if (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cfgcasc_casccospa) + continue; + if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cfgcasc_v0cospa) + continue; + if (std::fabs(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < cfgcasc_dcav0topv) + continue; + if (std::fabs(casc.dcabachtopv()) < cfgcasc_dcabachtopv) + continue; + if (casc.dcacascdaughters() > cfgcasc_dcacascdau) + continue; + if (casc.dcaV0daughters() > cfgcasc_dcav0dau) + continue; + if (std::fabs(casc.mLambda() - o2::constants::physics::MassLambda0) > cfgcasc_mlambdawindow) + continue; + // fill QA + registry.fill(HIST("QAhisto/Casc/hqaCasccosPAafter"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqaCascV0cosPAafter"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqadcaCascV0toPVafter"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqadcaCascBachtoPVafter"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Casc/hqadcaCascdauafter"), casc.dcacascdaughters()); + registry.fill(HIST("QAhisto/Casc/hqadcaCascV0dauafter"), casc.dcaV0daughters()); + // Omega and antiOmega + int pdgCode{cascMC.pdgCode()}; + if (!cfgcheckMCParticle || (std::abs(pdgCode) == kOmegaMinus && std::abs(cascMC.pdgCodeV0()) == kLambda0 && std::abs(cascMC.pdgCodeBachelor()) == kKPlus)) { + if (casc.sign() < 0 && (casc.mOmega() > 1.63) && (casc.mOmega() < 1.71) && std::fabs(casc.yOmega()) < cfgCasc_rapidity && + (!cfgcheckDauTPC || (std::fabs(bachelor.tpcNSigmaKa()) < cfgNSigma[2] && std::fabs(posdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(negdau.tpcNSigmaPi()) < cfgNSigma[0]))) { + registry.fill(HIST("h3DRecOmega"), casc.pt(), rectracknum, casc.mOmega()); + } else if (casc.sign() > 0 && (casc.mOmega() > 1.63) && (casc.mOmega() < 1.71) && std::fabs(casc.yOmega()) < cfgCasc_rapidity && + (!cfgcheckDauTPC || (std::fabs(bachelor.tpcNSigmaKa()) < cfgNSigma[2] && std::fabs(negdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(posdau.tpcNSigmaPi()) < cfgNSigma[0]))) { + registry.fill(HIST("h3DRecOmega"), casc.pt(), rectracknum, casc.mOmega()); + } + } + // Xi and antiXi + if (!cfgcheckMCParticle || (std::abs(pdgCode) == kXiMinus && std::abs(cascMC.pdgCodeV0()) == kLambda0 && std::abs(cascMC.pdgCodeBachelor()) == kPiPlus)) { + if (casc.sign() < 0 && (casc.mXi() > 1.30) && (casc.mXi() < 1.37) && std::fabs(casc.yXi()) < cfgCasc_rapidity && + (!cfgcheckDauTPC || (std::fabs(bachelor.tpcNSigmaPi()) < cfgNSigma[0] && std::fabs(posdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(negdau.tpcNSigmaPi()) < cfgNSigma[0]))) { + registry.fill(HIST("h3DRecXi"), casc.pt(), rectracknum, casc.mXi()); + } else if (casc.sign() > 0 && (casc.mXi() > 1.30) && (casc.mXi() < 1.37) && std::fabs(casc.yXi()) < cfgCasc_rapidity && + (!cfgcheckDauTPC || (std::fabs(bachelor.tpcNSigmaPi()) < cfgNSigma[0] && std::fabs(negdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(posdau.tpcNSigmaPi()) < cfgNSigma[0]))) { + registry.fill(HIST("h3DRecXi"), casc.pt(), rectracknum, casc.mXi()); + } + } + } + + for (const auto& v0 : V0s) { + if (!v0.has_v0MCCore()) + continue; + auto v0MC = v0.v0MCCore_as>(); + auto v0negdau = v0.negTrackExtra_as(); + auto v0posdau = v0.posTrackExtra_as(); + + // fill QA before cut + registry.fill(HIST("QAhisto/V0/hqaV0radiusbefore"), v0.v0radius()); + registry.fill(HIST("QAhisto/V0/hqaV0cosPAbefore"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/V0/hqadcaV0daubefore"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/V0/hqadcapostoPVbefore"), v0.dcapostopv()); + registry.fill(HIST("QAhisto/V0/hqadcanegtoPVbefore"), v0.dcanegtopv()); + registry.fill(HIST("QAhisto/V0/hqaarm_podobefore"), v0.alpha(), v0.qtarm()); + // track quality check + if (v0posdau.tpcNClsFound() < cfgtpcclusters) + continue; + if (v0negdau.tpcNClsFound() < cfgtpcclusters) + continue; + if (v0posdau.tpcNClsFindable() < cfgtpcclufindable) + continue; + if (v0negdau.tpcNClsFindable() < cfgtpcclufindable) + continue; + if (v0posdau.tpcCrossedRowsOverFindableCls() < cfgtpccrossoverfindable) + continue; + if (v0posdau.itsNCls() < cfgitsclusters) + continue; + if (v0negdau.itsNCls() < cfgitsclusters) + continue; + // topological cut + if (v0.v0radius() < cfgv0_radius) + continue; + if (v0.v0cosPA() < cfgv0_v0cospa) + continue; + if (v0.dcaV0daughters() > cfgv0_dcav0dau) + continue; + if (std::fabs(v0.dcapostopv()) < cfgv0_dcadautopv) + continue; + if (std::fabs(v0.dcanegtopv()) < cfgv0_dcadautopv) + continue; + // fill QA after cut + registry.fill(HIST("QAhisto/V0/hqaV0radiusafter"), v0.v0radius()); + registry.fill(HIST("QAhisto/V0/hqaV0cosPAafter"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/V0/hqadcaV0dauafter"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/V0/hqadcapostoPVafter"), v0.dcapostopv()); + registry.fill(HIST("QAhisto/V0/hqadcanegtoPVafter"), v0.dcanegtopv()); + + int pdgCode{v0MC.pdgCode()}; + // K0short + if (!cfgcheckMCParticle || (std::abs(pdgCode) == kK0Short && v0MC.pdgCodePositive() == kPiPlus && v0MC.pdgCodeNegative() == kPiMinus)) { + if (v0.qtarm() / std::fabs(v0.alpha()) > cfgv0_ArmPodocut && std::fabs(v0.y()) < 0.5 && std::fabs(v0.mK0Short() - o2::constants::physics::MassK0Short) < cfgv0_mk0swindow && + (!cfgcheckDauTPC || (std::fabs(v0posdau.tpcNSigmaPi()) < cfgNSigma[0] && std::fabs(v0negdau.tpcNSigmaPi()) < cfgNSigma[0]))) { + registry.fill(HIST("h3DRecK0s"), v0.pt(), rectracknum, v0.mK0Short()); + registry.fill(HIST("QAhisto/V0/hqaarm_podoafter"), v0.alpha(), v0.qtarm()); + } + } + // Lambda and antiLambda + if (std::fabs(v0.mLambda() - o2::constants::physics::MassLambda) < cfgv0_mlambdawindow && + (!cfgcheckDauTPC || (std::fabs(v0posdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(v0negdau.tpcNSigmaPi()) < cfgNSigma[0]))) { + if (!cfgcheckMCParticle || (std::abs(pdgCode) == kLambda0 && v0MC.pdgCodePositive() == kProton && v0MC.pdgCodeNegative() == kPiMinus)) + registry.fill(HIST("h3DRecLambda"), v0.pt(), rectracknum, v0.mLambda()); + } else if (std::fabs(v0.mLambda() - o2::constants::physics::MassLambda) < cfgv0_mlambdawindow && + (!cfgcheckDauTPC || (std::fabs(v0negdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(v0posdau.tpcNSigmaPi()) < cfgNSigma[0]))) { + if (!cfgcheckMCParticle || (std::abs(pdgCode) == kLambda0 && v0MC.pdgCodePositive() == kPiPlus && v0MC.pdgCodeNegative() == kProtonBar)) + registry.fill(HIST("h3DRecLambda"), v0.pt(), rectracknum, v0.mLambda()); + } + } + } + PROCESS_SWITCH(FlowEfficiencyCasc, processRec, "process reconstructed information", true); + + void processGen(MyMcCollisions::iterator const&, soa::SmallGroups> const& coll, const soa::SmallGroups>& cascMCs, const soa::SmallGroups>& v0MCs) + { + registry.fill(HIST("mcEventCounter"), 0.5); + int rectracknum = 0; + for (const auto& col : coll) { + rectracknum = col.multNTracksGlobal(); + } + for (auto const& cascmc : cascMCs) { + if (std::abs(cascmc.pdgCode()) == kXiMinus) { + if (std::fabs(cascmc.yMC()) < cfgCasc_rapidity) + registry.fill(HIST("h2DGenXi"), cascmc.ptMC(), rectracknum); + } + if (std::abs(cascmc.pdgCode()) == kOmegaMinus) { + if (std::fabs(cascmc.yMC()) < cfgCasc_rapidity) + registry.fill(HIST("h2DGenOmega"), cascmc.ptMC(), rectracknum); + } + } + for (auto const& v0mc : v0MCs) { + if (std::abs(v0mc.pdgCode()) == kK0Short) { + if (std::fabs(v0mc.yMC()) < cfgCasc_rapidity) + registry.fill(HIST("h2DGenK0s"), v0mc.ptMC(), rectracknum); + } + if (std::abs(v0mc.pdgCode()) == kLambda0) { + if (std::fabs(v0mc.yMC()) < cfgCasc_rapidity) + registry.fill(HIST("h2DGenLambda"), v0mc.ptMC(), rectracknum); + } + } + } + PROCESS_SWITCH(FlowEfficiencyCasc, processGen, "process gen information", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Flow/Tasks/flowGfwOmegaXi.cxx b/PWGCF/Flow/Tasks/flowGfwOmegaXi.cxx new file mode 100644 index 00000000000..c4d9d5d0ef7 --- /dev/null +++ b/PWGCF/Flow/Tasks/flowGfwOmegaXi.cxx @@ -0,0 +1,1499 @@ +// 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 flowGfwOmegaXi.cxx +/// \author Fuchun Cui(fcui@cern.ch) +/// \since Sep/13/2024 +/// \brief This task is to caculate V0s and cascades flow by GenericFramework + +#include +#include +#include +#include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/HistogramRegistry.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "GFWPowerArray.h" +#include "GFW.h" +#include "GFWCumulant.h" +#include "GFWWeights.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/Core/EventPlaneHelper.h" +#include "ReconstructionDataFormats/Track.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGMM/Mult/DataModel/Index.h" +#include "TList.h" +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +namespace +{ +std::shared_ptr refc22[10]; +std::shared_ptr refc24[10]; +std::shared_ptr k0sc22[10]; +std::shared_ptr k0sc24[10]; +std::shared_ptr lambdac22[10]; +std::shared_ptr lambdac24[10]; +std::shared_ptr xic22[10]; +std::shared_ptr xic24[10]; +std::shared_ptr omegac22[10]; +std::shared_ptr omegac24[10]; +} // namespace + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct FlowGfwOmegaXi { + + O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMin, float, 0.2f, "Minimal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMax, float, 10.0f, "Maximal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 10.0f, "Maximal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5, "Chi2 per TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyHigh, int, 500, "High cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgMassBins, std::vector, (std::vector{80, 32, 14, 16}), "Number of K0s, Lambda, Xi, Omega mass axis bins for c22") + O2_DEFINE_CONFIGURABLE(cfgDeltaPhiLocDen, int, 3, "Number of delta phi for local density, 200 bins in 2 pi") + // topological cut for V0 + O2_DEFINE_CONFIGURABLE(cfgv0_radius, float, 5.0f, "minimum decay radius") + O2_DEFINE_CONFIGURABLE(cfgv0_v0cospa, float, 0.995f, "minimum cosine of pointing angle") + O2_DEFINE_CONFIGURABLE(cfgv0_dcadautopv, float, 0.1f, "minimum daughter DCA to PV") + O2_DEFINE_CONFIGURABLE(cfgv0_dcav0dau, float, 0.5f, "maximum DCA among V0 daughters") + O2_DEFINE_CONFIGURABLE(cfgv0_mk0swindow, float, 0.1f, "Invariant mass window of K0s") + O2_DEFINE_CONFIGURABLE(cfgv0_mlambdawindow, float, 0.04f, "Invariant mass window of lambda") + O2_DEFINE_CONFIGURABLE(cfgv0_ArmPodocut, float, 0.2f, "Armenteros Podolski cut for K0") + // topological cut for cascade + O2_DEFINE_CONFIGURABLE(cfgcasc_radius, float, 0.5f, "minimum decay radius") + O2_DEFINE_CONFIGURABLE(cfgcasc_casccospa, float, 0.999f, "minimum cosine of pointing angle") + O2_DEFINE_CONFIGURABLE(cfgcasc_v0cospa, float, 0.998f, "minimum cosine of pointing angle") + O2_DEFINE_CONFIGURABLE(cfgcasc_dcav0topv, float, 0.01f, "minimum daughter DCA to PV") + O2_DEFINE_CONFIGURABLE(cfgcasc_dcabachtopv, float, 0.01f, "minimum bachelor DCA to PV") + O2_DEFINE_CONFIGURABLE(cfgcasc_dcacascdau, float, 0.3f, "maximum DCA among cascade daughters") + O2_DEFINE_CONFIGURABLE(cfgcasc_dcav0dau, float, 1.0f, "maximum DCA among V0 daughters") + O2_DEFINE_CONFIGURABLE(cfgcasc_mlambdawindow, float, 0.04f, "Invariant mass window of lambda") + // track quality and type selections + O2_DEFINE_CONFIGURABLE(cfgtpcclusters, int, 70, "minimum number of TPC clusters requirement") + O2_DEFINE_CONFIGURABLE(cfgitsclusters, int, 1, "minimum number of ITS clusters requirement") + O2_DEFINE_CONFIGURABLE(cfgtpcclufindable, int, 1, "minimum number of findable TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgtpccrossoverfindable, int, 1, "minimum number of Ratio crossed rows over findable clusters") + O2_DEFINE_CONFIGURABLE(cfgCasc_rapidity, float, 0.5, "rapidity") + O2_DEFINE_CONFIGURABLE(cfgNSigmatpctof, std::vector, (std::vector{3, 3, 3, 3, 3, 3}), "tpc and tof NSigma for Pion Proton Kaon") + O2_DEFINE_CONFIGURABLE(cfgAcceptancePath, std::vector, (std::vector{"Users/f/fcui/NUA/NUAREFPartical", "Users/f/fcui/NUA/NUAK0s", "Users/f/fcui/NUA/NUALambda", "Users/f/fcui/NUA/NUAXi", "Users/f/fcui/NUA/NUAOmega"}), "CCDB path to acceptance object") + O2_DEFINE_CONFIGURABLE(cfgEfficiencyPath, std::vector, (std::vector{"PathtoRef"}), "CCDB path to efficiency object") + O2_DEFINE_CONFIGURABLE(cfgLocDenParaXi, std::vector, (std::vector{-0.000986187, -3.86861, -0.000912481, -3.29206, -0.000859271, -2.89389, -0.000817039, -2.61201, -0.000788792, -2.39079, -0.000780182, -2.19276, -0.000750457, -2.07205, -0.000720279, -1.96865, -0.00073247, -1.85642, -0.000695091, -1.82625, -0.000693332, -1.72679, -0.000681225, -1.74305, -0.000652818, -1.92608, -0.000618892, -2.31985}), "Local density efficiency function parameter for Xi, exp(Ax + B)") + O2_DEFINE_CONFIGURABLE(cfgLocDenParaOmega, std::vector, (std::vector{-0.000444324, -6.0424, -0.000566208, -5.42168, -0.000580338, -4.96967, -0.000721054, -4.41994, -0.000626394, -4.27934, -0.000652167, -3.9543, -0.000592327, -3.79053, -0.000544721, -3.73292, -0.000613419, -3.43849, -0.000402506, -3.47687, -0.000602687, -3.24491, -0.000460848, -3.056, -0.00039428, -2.35188, -0.00041908, -2.03642}), "Local density efficiency function parameter for Omega, exp(Ax + B)") + O2_DEFINE_CONFIGURABLE(cfgLocDenParaK0s, std::vector, (std::vector{-0.00043057, -3.2435, -0.000385085, -2.97687, -0.000350298, -2.81502, -0.000326159, -2.71091, -0.000299563, -2.65448, -0.000294284, -2.60865, -0.000277938, -2.589, -0.000277091, -2.56983, -0.000272783, -2.56825, -0.000252706, -2.58996, -0.000247834, -2.63158, -0.00024379, -2.76976, -0.000286468, -2.92484, -0.000310149, -3.27746}), "Local density efficiency function parameter for K0s, exp(Ax + B)") + O2_DEFINE_CONFIGURABLE(cfgLocDenParaLambda, std::vector, (std::vector{-0.000510948, -4.4846, -0.000460629, -4.14465, -0.000433729, -3.94173, -0.000412751, -3.81839, -0.000411211, -3.72502, -0.000401511, -3.68426, -0.000407461, -3.67005, -0.000379371, -3.71153, -0.000392828, -3.73214, -0.000403996, -3.80717, -0.000403376, -3.90917, -0.000354624, -4.34629, -0.000477606, -4.66307, -0.000541139, -4.61364}), "Local density efficiency function parameter for Lambda, exp(Ax + B)") + // switch + O2_DEFINE_CONFIGURABLE(cfgcheckDauTPC, bool, true, "check daughter tracks TPC or not") + O2_DEFINE_CONFIGURABLE(cfgcheckDauTOF, bool, false, "check daughter tracks TOF or not") + O2_DEFINE_CONFIGURABLE(cfgDoAccEffCorr, bool, false, "do acc and eff corr") + O2_DEFINE_CONFIGURABLE(cfgDoLocDenCorr, bool, false, "do local density corr") + O2_DEFINE_CONFIGURABLE(cfgDoJackknife, bool, false, "do jackknife") + O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeights, bool, false, "Fill and output NUA weights") + O2_DEFINE_CONFIGURABLE(cfgOutputLocDenWeights, bool, false, "Fill and output local density weights") + + ConfigurableAxis cfgaxisVertex{"cfgaxisVertex", {20, -10, 10}, "vertex axis for histograms"}; + ConfigurableAxis cfgaxisPhi{"cfgaxisPhi", {60, 0.0, constants::math::TwoPI}, "phi axis for histograms"}; + ConfigurableAxis cfgaxisEta{"cfgaxisEta", {40, -1., 1.}, "eta axis for histograms"}; + ConfigurableAxis cfgaxisPt{"cfgaxisPt", {VARIABLE_WIDTH, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.20, 2.40, 2.60, 2.80, 3.00, 3.50, 4.00, 4.50, 5.00, 5.50, 6.00, 10.0}, "pt (GeV)"}; + ConfigurableAxis cfgaxisPtXi{"cfgaxisPtXi", {VARIABLE_WIDTH, 0.9, 1.1, 1.3, 1.5, 1.7, 1.9, 2.1, 2.3, 2.5, 2.7, 2.9, 3.9, 4.9, 5.9, 9.9}, "pt (GeV)"}; + ConfigurableAxis cfgaxisPtOmega{"cfgaxisPtOmega", {VARIABLE_WIDTH, 0.9, 1.1, 1.3, 1.5, 1.7, 1.9, 2.1, 2.3, 2.5, 2.7, 2.9, 3.9, 4.9, 5.9, 9.9}, "pt (GeV)"}; + ConfigurableAxis cfgaxisPtV0{"cfgaxisPtV0", {VARIABLE_WIDTH, 0.9, 1.1, 1.3, 1.5, 1.7, 1.9, 2.1, 2.3, 2.5, 2.7, 2.9, 3.9, 4.9, 5.9, 9.9}, "pt (GeV)"}; + ConfigurableAxis cfgaxisOmegaMassforflow{"cfgaxisOmegaMassforflow", {16, 1.63f, 1.71f}, "Inv. Mass (GeV)"}; + ConfigurableAxis cfgaxisXiMassforflow{"cfgaxisXiMassforflow", {14, 1.3f, 1.37f}, "Inv. Mass (GeV)"}; + ConfigurableAxis cfgaxisK0sMassforflow{"cfgaxisK0sMassforflow", {40, 0.4f, 0.6f}, "Inv. Mass (GeV)"}; + ConfigurableAxis cfgaxisLambdaMassforflow{"cfgaxisLambdaMassforflow", {32, 1.08f, 1.16f}, "Inv. Mass (GeV)"}; + ConfigurableAxis cfgaxisNch{"cfgaxisNch", {3000, 0.5, 3000.5}, "Nch"}; + ConfigurableAxis cfgaxisLocalDensity{"cfgaxisLocalDensity", {200, 0, 600}, "local density"}; + + AxisSpec axisMultiplicity{{0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}, "Centrality (%)"}; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtPOIMin) && (aod::track::pt < cfgCutPtPOIMax) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (aod::track::tpcChi2NCl < cfgCutChi2prTPCcls); + + using TracksPID = soa::Join; + using AodTracks = soa::Filtered>; // tracks filter + using AodCollisions = soa::Filtered>; // collisions filter + using DaughterTracks = soa::Join; + + // Connect to ccdb + Service ccdb; + O2_DEFINE_CONFIGURABLE(cfgnolaterthan, int64_t, std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object") + O2_DEFINE_CONFIGURABLE(cfgurl, std::string, "http://alice-ccdb.cern.ch", "url of the ccdb repository") + + // Define output + HistogramRegistry registry{"registry"}; + OutputObj fWeightsREF{GFWWeights("weightsREF")}; + OutputObj fWeightsK0s{GFWWeights("weightsK0s")}; + OutputObj fWeightsLambda{GFWWeights("weightsLambda")}; + OutputObj fWeightsXi{GFWWeights("weightsXi")}; + OutputObj fWeightsOmega{GFWWeights("weightsOmega")}; + + // define global variables + GFW* fGFW = new GFW(); // GFW class used from main src + std::vector corrconfigs; + std::vector cfgAcceptance = cfgAcceptancePath; + std::vector cfgEfficiency = cfgEfficiencyPath; + std::vector cfgNSigma = cfgNSigmatpctof; + std::vector cfgmassbins = cfgMassBins; + + std::vector mAcceptance; + std::vector mEfficiency; + bool correctionsLoaded = false; + + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + TF1* fT0AV0AMean = nullptr; + TF1* fT0AV0ASigma = nullptr; + + // Declare the pt, mult and phi Axis; + int nPtBins = 0; + TAxis* fPtAxis = nullptr; + + int nXiPtBins = 0; + TAxis* fXiPtAxis = nullptr; + + int nV0PtBins = 0; + TAxis* fV0PtAxis = nullptr; + + TAxis* fMultAxis = nullptr; + + TAxis* fOmegaMass = nullptr; + + TAxis* fXiMass = nullptr; + + TAxis* fK0sMass = nullptr; + + TAxis* fLambdaMass = nullptr; + + void init(InitContext const&) // Initialization + { + ccdb->setURL(cfgurl.value); + ccdb->setCaching(true); + ccdb->setCreatedNotAfter(cfgnolaterthan.value); + + // Set the pt, mult and phi Axis; + o2::framework::AxisSpec axisPt = cfgaxisPt; + nPtBins = axisPt.binEdges.size() - 1; + fPtAxis = new TAxis(nPtBins, &(axisPt.binEdges)[0]); + + o2::framework::AxisSpec axisXiPt = cfgaxisPtXi; + nXiPtBins = axisXiPt.binEdges.size() - 1; + fXiPtAxis = new TAxis(nXiPtBins, &(axisXiPt.binEdges)[0]); + + o2::framework::AxisSpec axisV0Pt = cfgaxisPtV0; + nV0PtBins = axisV0Pt.binEdges.size() - 1; + fV0PtAxis = new TAxis(nV0PtBins, &(axisV0Pt.binEdges)[0]); + + o2::framework::AxisSpec axisMult = axisMultiplicity; + int nMultBins = axisMult.binEdges.size() - 1; + fMultAxis = new TAxis(nMultBins, &(axisMult.binEdges)[0]); + + fOmegaMass = new TAxis(cfgmassbins[3], 1.63, 1.71); + + fXiMass = new TAxis(cfgmassbins[2], 1.3, 1.37); + + fK0sMass = new TAxis(cfgmassbins[0], 0.4, 0.6); + + fLambdaMass = new TAxis(cfgmassbins[1], 1.08, 1.16); + + // Add some output objects to the histogram registry + registry.add("hPhi", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hPhicorr", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hEta", "", {HistType::kTH1D, {cfgaxisEta}}); + registry.add("hVtxZ", "", {HistType::kTH1D, {cfgaxisVertex}}); + registry.add("hMult", "", {HistType::kTH1D, {cfgaxisNch}}); + registry.add("hCent", "", {HistType::kTH1D, {{90, 0, 90}}}); + registry.add("hCentvsNch", "", {HistType::kTH2D, {{18, 0, 90}, cfgaxisNch}}); + registry.add("MC/hCentvsNchMC", "", {HistType::kTH2D, {{18, 0, 90}, cfgaxisNch}}); + registry.add("hPt", "", {HistType::kTH1D, {cfgaxisPt}}); + registry.add("hEtaPhiVtxzREF", "", {HistType::kTH3D, {cfgaxisPhi, cfgaxisEta, {20, -10, 10}}}); + registry.add("hEtaPhiVtxzPOIXi", "", {HistType::kTH3D, {cfgaxisPhi, cfgaxisEta, {20, -10, 10}}}); + registry.add("hEtaPhiVtxzPOIOmega", "", {HistType::kTH3D, {cfgaxisPhi, cfgaxisEta, {20, -10, 10}}}); + registry.add("hEtaPhiVtxzPOIK0s", "", {HistType::kTH3D, {cfgaxisPhi, cfgaxisEta, {20, -10, 10}}}); + registry.add("hEtaPhiVtxzPOILambda", "", {HistType::kTH3D, {cfgaxisPhi, cfgaxisEta, {20, -10, 10}}}); + registry.add("hEventCount", "", {HistType::kTH2D, {{4, 0, 4}, {4, 0, 4}}}); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(1, "Filtered event"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(2, "after sel8"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(3, "before topological cut"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(4, "after topological cut"); + registry.get(HIST("hEventCount"))->GetYaxis()->SetBinLabel(1, "K0s"); + registry.get(HIST("hEventCount"))->GetYaxis()->SetBinLabel(2, "Lambda"); + registry.get(HIST("hEventCount"))->GetYaxis()->SetBinLabel(3, "XiMinus"); + registry.get(HIST("hEventCount"))->GetYaxis()->SetBinLabel(4, "Omega"); + + // QA + // V0 QA + registry.add("QAhisto/V0/hqaV0radiusbefore", "", {HistType::kTH1D, {{200, 0, 200}}}); + registry.add("QAhisto/V0/hqaV0radiusafter", "", {HistType::kTH1D, {{200, 0, 200}}}); + registry.add("QAhisto/V0/hqaV0cosPAbefore", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/V0/hqaV0cosPAafter", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/V0/hqadcaV0daubefore", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/V0/hqadcaV0dauafter", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/V0/hqaarm_podobefore", "", {HistType::kTH2D, {{100, -1, 1}, {50, 0, 0.3}}}); + registry.add("QAhisto/V0/hqaarm_podoafter", "", {HistType::kTH2D, {{100, -1, 1}, {50, 0, 0.3}}}); + registry.add("QAhisto/V0/hqadcapostoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/V0/hqadcapostoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/V0/hqadcanegtoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/V0/hqadcanegtoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + // Cascade QA + registry.add("QAhisto/Casc/hqaCasccosPAbefore", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Casc/hqaCasccosPAafter", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Casc/hqaCascV0cosPAbefore", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Casc/hqaCascV0cosPAafter", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Casc/hqadcaCascV0toPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Casc/hqadcaCascV0toPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Casc/hqadcaCascBachtoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Casc/hqadcaCascBachtoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Casc/hqadcaCascdaubefore", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/Casc/hqadcaCascdauafter", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/Casc/hqadcaCascV0daubefore", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/Casc/hqadcaCascV0dauafter", "", {HistType::kTH1D, {{100, 0, 1}}}); + + // cumulant of flow + registry.add("c22", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("c24", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("K0sc22", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("Lambdac22", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("c22dpt", ";Centrality (%) ; C_{2}{2}", {HistType::kTProfile2D, {cfgaxisPt, axisMultiplicity}}); + registry.add("c24dpt", ";Centrality (%) ; C_{2}{4}", {HistType::kTProfile2D, {cfgaxisPt, axisMultiplicity}}); + // pt-diff cumulant of flow + registry.add("Xic22dpt", ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtXi, cfgaxisXiMassforflow, axisMultiplicity}}); + registry.add("Omegac22dpt", ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtXi, cfgaxisOmegaMassforflow, axisMultiplicity}}); + registry.add("K0sc22dpt", ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtV0, cfgaxisK0sMassforflow, axisMultiplicity}}); + registry.add("Lambdac22dpt", ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtV0, cfgaxisLambdaMassforflow, axisMultiplicity}}); + registry.add("Xic24dpt", ";pt ; C_{2}{4} ", {HistType::kTProfile3D, {cfgaxisPtXi, cfgaxisXiMassforflow, axisMultiplicity}}); + registry.add("Omegac24dpt", ";pt ; C_{2}{4} ", {HistType::kTProfile3D, {cfgaxisPtXi, cfgaxisOmegaMassforflow, axisMultiplicity}}); + registry.add("K0sc24dpt", ";pt ; C_{2}{4} ", {HistType::kTProfile3D, {cfgaxisPtV0, cfgaxisK0sMassforflow, axisMultiplicity}}); + registry.add("Lambdac24dpt", ";pt ; C_{2}{4} ", {HistType::kTProfile3D, {cfgaxisPtV0, cfgaxisLambdaMassforflow, axisMultiplicity}}); + // for Jackknife + if (cfgDoJackknife) { + int nsubevent = 10; + for (int i = 1; i <= nsubevent; i++) { + refc22[i - 1] = registry.add(Form("Jackknife/REF/c22_%d", i), ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + refc24[i - 1] = registry.add(Form("Jackknife/REF/c24_%d", i), ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + xic22[i - 1] = registry.add(Form("Jackknife/Xi/Xic22dpt_%d", i), ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtXi, cfgaxisXiMassforflow, axisMultiplicity}}); + omegac22[i - 1] = registry.add(Form("Jackknife/Omega/Omegac22dpt_%d", i), ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtXi, cfgaxisOmegaMassforflow, axisMultiplicity}}); + k0sc22[i - 1] = registry.add(Form("Jackknife/K0s/K0sc22dpt_%d", i), ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtV0, cfgaxisK0sMassforflow, axisMultiplicity}}); + lambdac22[i - 1] = registry.add(Form("Jackknife/Lambda/Lambdac22dpt_%d", i), ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtV0, cfgaxisLambdaMassforflow, axisMultiplicity}}); + xic24[i - 1] = registry.add(Form("Jackknife/Xi/Xic24dpt_%d", i), ";pt ; C_{2}{4} ", {HistType::kTProfile3D, {cfgaxisPtXi, cfgaxisXiMassforflow, axisMultiplicity}}); + omegac24[i - 1] = registry.add(Form("Jackknife/Omega/Omegac24dpt_%d", i), ";pt ; C_{2}{4} ", {HistType::kTProfile3D, {cfgaxisPtXi, cfgaxisOmegaMassforflow, axisMultiplicity}}); + k0sc24[i - 1] = registry.add(Form("Jackknife/K0s/K0sc24dpt_%d", i), ";pt ; C_{2}{4} ", {HistType::kTProfile3D, {cfgaxisPtV0, cfgaxisK0sMassforflow, axisMultiplicity}}); + lambdac24[i - 1] = registry.add(Form("Jackknife/Lambda/Lambdac24dpt_%d", i), ";pt ; C_{2}{4} ", {HistType::kTProfile3D, {cfgaxisPtV0, cfgaxisLambdaMassforflow, axisMultiplicity}}); + } + } + // MC True flow + registry.add("MC/c22MC", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("MC/Xic22dptMC", ";pt ; C_{2}{2} ", {HistType::kTProfile2D, {cfgaxisPtXi, axisMultiplicity}}); + registry.add("MC/Omegac22dptMC", ";pt ; C_{2}{2} ", {HistType::kTProfile2D, {cfgaxisPtXi, axisMultiplicity}}); + registry.add("MC/K0sc22dptMC", ";pt ; C_{2}{2} ", {HistType::kTProfile2D, {cfgaxisPtV0, axisMultiplicity}}); + registry.add("MC/Lambdac22dptMC", ";pt ; C_{2}{2} ", {HistType::kTProfile2D, {cfgaxisPtV0, axisMultiplicity}}); + // InvMass(GeV) of casc and v0 + AxisSpec axisOmegaMass = {80, 1.63f, 1.71f, "Inv. Mass (GeV)"}; + AxisSpec axisXiMass = {70, 1.3f, 1.37f, "Inv. Mass (GeV)"}; + AxisSpec axisK0sMass = {400, 0.4f, 0.6f, "Inv. Mass (GeV)"}; + AxisSpec axisLambdaMass = {160, 1.08f, 1.16f, "Inv. Mass (GeV)"}; + registry.add("InvMassXi_all", "", {HistType::kTHnSparseF, {cfgaxisPtXi, axisXiMass, cfgaxisEta, axisMultiplicity}}); + registry.add("InvMassOmega_all", "", {HistType::kTHnSparseF, {cfgaxisPtXi, axisOmegaMass, cfgaxisEta, axisMultiplicity}}); + registry.add("InvMassOmega", "", {HistType::kTHnSparseF, {cfgaxisPtXi, axisOmegaMass, cfgaxisEta, axisMultiplicity}}); + registry.add("InvMassXi", "", {HistType::kTHnSparseF, {cfgaxisPtXi, axisXiMass, cfgaxisEta, axisMultiplicity}}); + registry.add("InvMassK0s_all", "", {HistType::kTHnSparseF, {cfgaxisPtV0, axisK0sMass, cfgaxisEta, axisMultiplicity}}); + registry.add("InvMassLambda_all", "", {HistType::kTHnSparseF, {cfgaxisPtV0, axisLambdaMass, cfgaxisEta, axisMultiplicity}}); + registry.add("InvMassK0s", "", {HistType::kTHnSparseF, {cfgaxisPtV0, axisK0sMass, cfgaxisEta, axisMultiplicity}}); + registry.add("InvMassLambda", "", {HistType::kTHnSparseF, {cfgaxisPtV0, axisLambdaMass, cfgaxisEta, axisMultiplicity}}); + // for local density correlation + registry.add("MC/densityMCGenK0s", "", {HistType::kTH3D, {cfgaxisPtV0, cfgaxisNch, cfgaxisLocalDensity}}); + registry.add("MC/densityMCGenLambda", "", {HistType::kTH3D, {cfgaxisPtV0, cfgaxisNch, cfgaxisLocalDensity}}); + registry.add("MC/densityMCGenXi", "", {HistType::kTH3D, {cfgaxisPtXi, cfgaxisNch, cfgaxisLocalDensity}}); + registry.add("MC/densityMCGenOmega", "", {HistType::kTH3D, {cfgaxisPtXi, cfgaxisNch, cfgaxisLocalDensity}}); + registry.add("MC/densityMCRecK0s", "", {HistType::kTHnSparseF, {cfgaxisPtV0, cfgaxisNch, cfgaxisLocalDensity, axisK0sMass}}); + registry.add("MC/densityMCRecLambda", "", {HistType::kTHnSparseF, {cfgaxisPtV0, cfgaxisNch, cfgaxisLocalDensity, axisLambdaMass}}); + registry.add("MC/densityMCRecXi", "", {HistType::kTHnSparseF, {cfgaxisPtXi, cfgaxisNch, cfgaxisLocalDensity, axisXiMass}}); + registry.add("MC/densityMCRecOmega", "", {HistType::kTHnSparseF, {cfgaxisPtXi, cfgaxisNch, cfgaxisLocalDensity, axisOmegaMass}}); + + // Data + fGFW->AddRegion("reffull", -0.8, 0.8, 1, 1); // ("name", etamin, etamax, ptbinnum, bitmask)eta region -0.8 to 0.8 + fGFW->AddRegion("refN10", -0.8, -0.4, 1, 1); + fGFW->AddRegion("refP10", 0.4, 0.8, 1, 1); + // POI + fGFW->AddRegion("poiN10dpt", -0.8, -0.4, nPtBins, 32); + fGFW->AddRegion("poiP10dpt", 0.4, 0.8, nPtBins, 32); + fGFW->AddRegion("poifulldpt", -0.8, 0.8, nPtBins, 32); + fGFW->AddRegion("poioldpt", -0.8, 0.8, nPtBins, 1); + + int nXiptMassBins = nXiPtBins * cfgmassbins[2]; + fGFW->AddRegion("poiXiPdpt", 0.4, 0.8, nXiptMassBins, 2); + fGFW->AddRegion("poiXiNdpt", -0.8, -0.4, nXiptMassBins, 2); + fGFW->AddRegion("poiXifulldpt", -0.8, 0.8, nXiptMassBins, 2); + fGFW->AddRegion("poiXiP", 0.4, 0.8, 1, 2); + fGFW->AddRegion("poiXiN", -0.8, -0.4, 1, 2); + int nOmegaptMassBins = nXiPtBins * cfgmassbins[3]; + fGFW->AddRegion("poiOmegaPdpt", 0.4, 0.8, nOmegaptMassBins, 4); + fGFW->AddRegion("poiOmegaNdpt", -0.8, -0.4, nOmegaptMassBins, 4); + fGFW->AddRegion("poiOmegafulldpt", -0.8, 0.8, nOmegaptMassBins, 4); + fGFW->AddRegion("poiOmegaP", 0.4, 0.8, 1, 4); + fGFW->AddRegion("poiOmegaN", -0.8, -0.4, 1, 4); + int nK0sptMassBins = nV0PtBins * cfgmassbins[0]; + fGFW->AddRegion("poiK0sPdpt", 0.4, 0.8, nK0sptMassBins, 8); + fGFW->AddRegion("poiK0sNdpt", -0.8, -0.4, nK0sptMassBins, 8); + fGFW->AddRegion("poiK0sfulldpt", -0.8, 0.8, nK0sptMassBins, 8); + fGFW->AddRegion("poiK0sP", 0.4, 0.8, 1, 8); + fGFW->AddRegion("poiK0sN", -0.8, 0.4, 1, 8); + int nLambdaptMassBins = nV0PtBins * cfgmassbins[1]; + fGFW->AddRegion("poiLambdaPdpt", 0.4, 0.8, nLambdaptMassBins, 16); + fGFW->AddRegion("poiLambdaNdpt", -0.8, -0.4, nLambdaptMassBins, 16); + fGFW->AddRegion("poiLambdafulldpt", -0.8, 0.8, nLambdaptMassBins, 16); + fGFW->AddRegion("poiLambdaP", 0.4, 0.8, 1, 16); + fGFW->AddRegion("poiLambdaN", -0.8, -0.4, 1, 16); + // MC + fGFW->AddRegion("refN10MC", -0.8, -0.4, 1, 64); + fGFW->AddRegion("refP10MC", 0.4, 0.8, 1, 64); + fGFW->AddRegion("poiXiPdptMC", 0.4, 0.8, nXiptMassBins, 128); + fGFW->AddRegion("poiXiNdptMC", -0.8, -0.4, nXiptMassBins, 128); + fGFW->AddRegion("poiOmegaPdptMC", 0.4, 0.8, nOmegaptMassBins, 256); + fGFW->AddRegion("poiOmegaNdptMC", -0.8, -0.4, nOmegaptMassBins, 256); + fGFW->AddRegion("poiK0sPdptMC", 0.4, 0.8, nK0sptMassBins, 512); + fGFW->AddRegion("poiK0sNdptMC", -0.8, -0.4, nK0sptMassBins, 512); + fGFW->AddRegion("poiLambdaPdptMC", 0.4, 0.8, nLambdaptMassBins, 1024); + fGFW->AddRegion("poiLambdaNdptMC", -0.8, -0.4, nLambdaptMassBins, 1024); + // pushback + // Data + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiP10dpt {2} refN10 {-2}", "Poi10Gap22dpta", kTRUE)); // 0 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiN10dpt {2} refP10 {-2}", "Poi10Gap22dptb", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poifulldpt reffull | poioldpt {2 2 -2 -2}", "Poi10Gap24dpt", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiXiPdpt {2} refN10 {-2}", "Xi10Gap22a", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiXiNdpt {2} refP10 {-2}", "Xi10Gap22b", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiXifulldpt reffull {2 2 -2 -2}", "Xi10Gap24", kTRUE)); // 5 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiOmegaPdpt {2} refN10 {-2}", "Omega10Gap22a", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiOmegaNdpt {2} refP10 {-2}", "Omega10Gap22b", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiOmegafulldpt reffull {2 2 -2 -2}", "Xi10Gap24", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiK0sPdpt {2} refN10 {-2}", "K0short10Gap22a", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiK0sNdpt {2} refP10 {-2}", "K0short10Gap22b", kTRUE)); // 10 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiK0sfulldpt reffull {2 2 -2 -2}", "Xi10Gap24", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiLambdaPdpt {2} refN10 {-2}", "Lambda10Gap22a", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiLambdaNdpt {2} refP10 {-2}", "Lambda10Gap22b", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiLambdafulldpt reffull {2 2 -2 -2}", "Xi10Gap24a", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refP10 {2} refN10 {-2}", "Ref10Gap22a", kFALSE)); // 15 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("reffull reffull {2 2 -2 -2}", "Ref10Gap24", kFALSE)); + // MC + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiXiPdptMC {2} refN10MC {-2}", "MCXi10Gap22a", kTRUE)); // 17 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiXiNdptMC {2} refP10MC {-2}", "MCXi10Gap22b", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiOmegaPdptMC {2} refN10MC {-2}", "MCOmega10Gap22a", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiOmegaNdptMC {2} refP10MC {-2}", "MCOmega10Gap22b", kTRUE)); // 20 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiK0sPdptMC {2} refN10MC {-2}", "MCK0s10Gap22a", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiK0sNdptMC {2} refP10MC {-2}", "MCK0s10Gap22b", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiLambdaPdptMC {2} refN10MC {-2}", "MCLambda10Gap22a", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiLambdaNdptMC {2} refP10MC {-2}", "MCLambda10Gap22b", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refP10MC {2} refN10MC {-2}", "MCRef10Gap22a", kFALSE)); // 25 + fGFW->CreateRegions(); // finalize the initialization + + // used for event selection + fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x - 3.5*([5]+[6must ]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); + fMultPVCutLow->SetParameters(3257.29, -121.848, 1.98492, -0.0172128, 6.47528e-05, 154.756, -1.86072, -0.0274713, 0.000633499, -3.37757e-06); + fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x + 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); + fMultPVCutHigh->SetParameters(3257.29, -121.848, 1.98492, -0.0172128, 6.47528e-05, 154.756, -1.86072, -0.0274713, 0.000633499, -3.37757e-06); + fT0AV0AMean = new TF1("fT0AV0AMean", "[0]+[1]*x", 0, 200000); + fT0AV0AMean->SetParameters(-1601.0581, 9.417652e-01); + fT0AV0ASigma = new TF1("fT0AV0ASigma", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 200000); + fT0AV0ASigma->SetParameters(463.4144, 6.796509e-02, -9.097136e-07, 7.971088e-12, -2.600581e-17); + + // fWeight output + if (cfgOutputNUAWeights) { + fWeightsREF->setPtBins(nPtBins, &(axisPt.binEdges)[0]); + fWeightsREF->init(true, false); + fWeightsK0s->setPtBins(nPtBins, &(axisPt.binEdges)[0]); + fWeightsK0s->init(true, false); + fWeightsLambda->setPtBins(nPtBins, &(axisPt.binEdges)[0]); + fWeightsLambda->init(true, false); + fWeightsXi->setPtBins(nPtBins, &(axisPt.binEdges)[0]); + fWeightsXi->init(true, false); + fWeightsOmega->setPtBins(nPtBins, &(axisPt.binEdges)[0]); + fWeightsOmega->init(true, false); + } + } + + // input HIST("name") + template + void fillProfile(const GFW::CorrConfig& corrconf, const ConstStr& tarName, const double& cent) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) + return; + if (!corrconf.pTDif) { + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + registry.fill(tarName, cent, val, dnx); + return; + } + return; + } + + // input shared_ptr + void fillProfile(const GFW::CorrConfig& corrconf, std::shared_ptr TProfile, const double& cent) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) + return; + if (!corrconf.pTDif) { + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + TProfile->Fill(cent, val, dnx); + return; + } + return; + } + + template + void fillProfilepT(const GFW::CorrConfig& corrconf, const ConstStr& tarName, const int& ptbin, const double& cent) + { + float dnx = 0; + float val = 0; + dnx = fGFW->Calculate(corrconf, ptbin - 1, kTRUE).real(); + if (dnx == 0) + return; + val = fGFW->Calculate(corrconf, ptbin - 1, kFALSE).real() / dnx; + if (std::fabs(val) < 1) { + registry.fill(tarName, fPtAxis->GetBinCenter(ptbin), cent, val, dnx); + } + return; + } + + template + void fillProfilepTMC(const GFW::CorrConfig& corrconf, const ConstStr& tarName, const int& ptbin, const int& PDGCode, const double& cent) + { + TAxis* fpt = nullptr; + if (PDGCode == kXiMinus) { + fpt = fXiPtAxis; + } else if (PDGCode == kOmegaMinus) { + fpt = fXiPtAxis; + } else if (PDGCode == kK0Short) { + fpt = fV0PtAxis; + } else if (PDGCode == kLambda0) { + fpt = fV0PtAxis; + } else { + LOGF(error, "Error, please put in correct PDGCode of K0s, Lambda, Xi or Omega"); + return; + } + float dnx = 0; + float val = 0; + dnx = fGFW->Calculate(corrconf, ptbin - 1, kTRUE).real(); + if (dnx == 0) + return; + val = fGFW->Calculate(corrconf, ptbin - 1, kFALSE).real() / dnx; + if (std::fabs(val) < 1) { + registry.fill(tarName, fpt->GetBinCenter(ptbin), cent, val, dnx); + } + return; + } + + // input HIST("name") + template + void fillProfilepTMass(const GFW::CorrConfig& corrconf, const ConstStr& tarName, const int& ptbin, const int& PDGCode, const float& cent) + { + int nMassBins = 0; + int nptbins = 0; + TAxis* fMass = nullptr; + TAxis* fpt = nullptr; + if (PDGCode == kXiMinus) { + nMassBins = cfgmassbins[2]; + nptbins = nXiPtBins; + fpt = fXiPtAxis; + fMass = fXiMass; + } else if (PDGCode == kOmegaMinus) { + nMassBins = cfgmassbins[3]; + nptbins = nXiPtBins; + fpt = fXiPtAxis; + fMass = fOmegaMass; + } else if (PDGCode == kK0Short) { + nMassBins = cfgmassbins[0]; + nptbins = nV0PtBins; + fpt = fV0PtAxis; + fMass = fK0sMass; + } else if (PDGCode == kLambda0) { + nMassBins = cfgmassbins[1]; + nptbins = nV0PtBins; + fpt = fV0PtAxis; + fMass = fLambdaMass; + } else { + LOGF(error, "Error, please put in correct PDGCode of K0s, Lambda, Xi or Omega"); + return; + } + for (int massbin = 1; massbin <= nMassBins; massbin++) { + float dnx = 0; + float val = 0; + dnx = fGFW->Calculate(corrconf, (ptbin - 1) + ((massbin - 1) * nptbins), kTRUE).real(); + if (dnx == 0) + continue; + val = fGFW->Calculate(corrconf, (ptbin - 1) + ((massbin - 1) * nptbins), kFALSE).real() / dnx; + if (std::fabs(val) < 1) { + registry.fill(tarName, fpt->GetBinCenter(ptbin), fMass->GetBinCenter(massbin), cent, val, dnx); + } + } + return; + } + + // input shared_ptr + void fillProfilepTMass(const GFW::CorrConfig& corrconf, std::shared_ptr TProfile3D, const int& ptbin, const int& PDGCode, const float& cent) + { + int nMassBins = 0; + int nptbins = 0; + TAxis* fMass = nullptr; + TAxis* fpt = nullptr; + if (PDGCode == kXiMinus) { + nMassBins = cfgmassbins[2]; + nptbins = nXiPtBins; + fpt = fXiPtAxis; + fMass = fXiMass; + } else if (PDGCode == kOmegaMinus) { + nMassBins = cfgmassbins[3]; + nptbins = nXiPtBins; + fpt = fXiPtAxis; + fMass = fOmegaMass; + } else if (PDGCode == kK0Short) { + nMassBins = cfgmassbins[0]; + nptbins = nV0PtBins; + fpt = fV0PtAxis; + fMass = fK0sMass; + } else if (PDGCode == kLambda0) { + nMassBins = cfgmassbins[1]; + nptbins = nV0PtBins; + fpt = fV0PtAxis; + fMass = fLambdaMass; + } else { + LOGF(error, "Error, please put in correct PDGCode of K0s, Lambda, Xi or Omega"); + return; + } + for (int massbin = 1; massbin <= nMassBins; massbin++) { + float dnx = 0; + float val = 0; + dnx = fGFW->Calculate(corrconf, (ptbin - 1) + ((massbin - 1) * nptbins), kTRUE).real(); + if (dnx == 0) + continue; + val = fGFW->Calculate(corrconf, (ptbin - 1) + ((massbin - 1) * nptbins), kFALSE).real() / dnx; + if (std::fabs(val) < 1) { + TProfile3D->Fill(fpt->GetBinCenter(ptbin), fMass->GetBinCenter(massbin), cent, val, dnx); + } + } + return; + } + + void loadCorrections(uint64_t timestamp) + { + if (correctionsLoaded) + return; + int nspecies = 5; + if (cfgAcceptance.size() == static_cast(nspecies)) { + for (int i = 0; i <= nspecies - 1; i++) { + mAcceptance.push_back(ccdb->getForTimeStamp(cfgAcceptance[i], timestamp)); + } + if (mAcceptance.size() == static_cast(nspecies)) + LOGF(info, "Loaded acceptance weights"); + else + LOGF(warning, "Could not load acceptance weights"); + } + if (cfgEfficiency.size() == static_cast(nspecies)) { + for (int i = 0; i <= nspecies - 1; i++) { + mEfficiency.push_back(ccdb->getForTimeStamp(cfgEfficiency[i], timestamp)); + } + if (mEfficiency.size() == static_cast(nspecies)) + LOGF(info, "Loaded efficiency histogram"); + else + LOGF(fatal, "Could not load efficiency histogram"); + } + correctionsLoaded = true; + } + + template + bool setCurrentParticleWeights(float& weight_nue, float& weight_nua, TrackObject track, float vtxz, int ispecies) + { + float eff = 1.; + int nspecies = 5; + if (mEfficiency.size() == static_cast(nspecies)) + eff = mEfficiency[ispecies]->GetBinContent(mEfficiency[ispecies]->FindBin(track.pt())); + else + eff = 1.0; + if (eff == 0) + return false; + weight_nue = 1. / eff; + if (mAcceptance.size() == static_cast(nspecies)) + weight_nua = mAcceptance[ispecies]->getNUA(track.phi(), track.eta(), vtxz); + else + weight_nua = 1; + return true; + } + + template + bool setCurrentLocalDensityWeights(float& weight_loc, TrackObject track, double locDensity, int ispecies) + { + auto cfgLocDenPara = (std::vector>){cfgLocDenParaK0s, cfgLocDenParaLambda, cfgLocDenParaXi, cfgLocDenParaOmega}; + int ptbin = fXiPtAxis->FindBin(track.pt()); + if (ptbin == 0 || ptbin == (fXiPtAxis->GetNbins() + 1)) { + weight_loc = 1.0; + return true; + } + double paraA = cfgLocDenPara[ispecies - 1][2 * ptbin - 2]; + double paraB = cfgLocDenPara[ispecies - 1][2 * ptbin - 1]; + double density = locDensity * 200 / (2 * cfgDeltaPhiLocDen + 1); + double eff = std::exp(paraA * density + paraB); + weight_loc = 1 / eff; + return true; + } + // event selection + template + bool eventSelected(TCollision collision, const float centrality) + { + if (collision.alias_bit(kTVXinTRD)) { + // TRD triggered + return false; + } + if (!collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + // reject collisions close to Time Frame borders + // https://its.cern.ch/jira/browse/O2-4623 + return false; + } + if (!collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + // reject events affected by the ITS ROF border + // https://its.cern.ch/jira/browse/O2-4309 + return false; + } + if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + // rejects collisions which are associated with the same "found-by-T0" bunch crossing + // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof + return false; + } + if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference + // use this cut at low multiplicities with caution + return false; + } + if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // no collisions in specified time range + return 0; + } + if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + // cut time intervals with dead ITS staves + return 0; + } + float vtxz = -999; + if (collision.numContrib() > 1) { + vtxz = collision.posZ(); + float zRes = std::sqrt(collision.covZZ()); + double zResMin = 0.25; + int numContMax = 20; + if (zRes > zResMin && collision.numContrib() < numContMax) + vtxz = -999; + } + auto multNTracksPV = collision.multNTracksPV(); + auto occupancy = collision.trackOccupancyInTimeRange(); + + if (std::fabs(vtxz) > cfgCutVertex) + return false; + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) + return false; + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) + return false; + if (occupancy > cfgCutOccupancyHigh) + return 0; + + // V0A T0A 5 sigma cut + int nsigma = 5; + if (std::fabs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > nsigma * fT0AV0ASigma->Eval(collision.multFT0A())) + return 0; + + return true; + } + + void processData(AodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, AodTracks const& tracks, aod::CascDataExt const& Cascades, aod::V0Datas const& V0s, DaughterTracks const&) + { + int nTot = tracks.size(); + int candNumAll[4] = {0, 0, 0, 0}; + int candNum[4] = {0, 0, 0, 0}; + int nspecies = 5; + for (int i = 0; i < nspecies - 1; i++) { + registry.fill(HIST("hEventCount"), 0.5, i + 0.5); + } + if (nTot < 1) + return; + fGFW->Clear(); + const auto cent = collision.centFT0C(); + if (!collision.sel8()) + return; + if (eventSelected(collision, cent)) + return; + TH1D* hLocalDensity = new TH1D("hphi", "hphi", 400, -constants::math::TwoPI, constants::math::TwoPI); + auto bc = collision.bc_as(); + loadCorrections(bc.timestamp()); + float vtxz = collision.posZ(); + registry.fill(HIST("hVtxZ"), vtxz); + registry.fill(HIST("hMult"), nTot); + registry.fill(HIST("hCent"), cent); + for (int i = 0; i < nspecies - 1; i++) { + registry.fill(HIST("hEventCount"), 1.5, i + 0.5); + } + + float weff = 1; + float wacc = 1; + float wloc = 1; + double nch = 0; + // fill GFW ref flow + for (const auto& track : tracks) { + if (cfgDoAccEffCorr) { + if (!setCurrentParticleWeights(weff, wacc, track, vtxz, 0)) + continue; + } + registry.fill(HIST("hPhi"), track.phi()); + registry.fill(HIST("hPhicorr"), track.phi(), wacc); + registry.fill(HIST("hEta"), track.eta()); + registry.fill(HIST("hEtaPhiVtxzREF"), track.phi(), track.eta(), vtxz, wacc); + registry.fill(HIST("hPt"), track.pt()); + int ptbin = fPtAxis->FindBin(track.pt()) - 1; + if ((track.pt() > cfgCutPtMin) && (track.pt() < cfgCutPtMax)) { + fGFW->Fill(track.eta(), ptbin, track.phi(), wacc * weff, 1); //(eta, ptbin, phi, wacc*weff, bitmask) + } + if ((track.pt() > cfgCutPtPOIMin) && (track.pt() < cfgCutPtPOIMax)) { + fGFW->Fill(track.eta(), ptbin, track.phi(), wacc * weff, 32); + if (cfgDoLocDenCorr) { + hLocalDensity->Fill(track.phi(), wacc * weff); + hLocalDensity->Fill(RecoDecay::constrainAngle(track.phi(), -constants::math::TwoPI), wacc * weff); + nch += wacc * weff; + } + } + if (cfgOutputNUAWeights) + fWeightsREF->fill(track.phi(), track.eta(), vtxz, track.pt(), cent, 0); + } + if (cfgDoLocDenCorr) { + registry.fill(HIST("hCentvsNch"), cent, nch); + } + // fill GFW of V0 flow + double lowpt = 0.4; + for (const auto& v0 : V0s) { + auto v0posdau = v0.posTrack_as(); + auto v0negdau = v0.negTrack_as(); + // check tpc + bool isK0s = false; + bool isLambda = false; + // fill QA + registry.fill(HIST("QAhisto/V0/hqaarm_podobefore"), v0.alpha(), v0.qtarm()); + // check daughter TPC and TOF + // K0short + if (v0.qtarm() / std::fabs(v0.alpha()) > cfgv0_ArmPodocut && std::fabs(v0.mK0Short() - o2::constants::physics::MassK0Short) < cfgv0_mk0swindow && + (!cfgcheckDauTPC || (std::fabs(v0posdau.tpcNSigmaPi()) < cfgNSigma[0] && std::fabs(v0negdau.tpcNSigmaPi()) < cfgNSigma[0])) && + (!cfgcheckDauTOF || ((std::fabs(v0posdau.tofNSigmaPi()) < cfgNSigma[3] || v0posdau.pt() < lowpt) && (std::fabs(v0negdau.tofNSigmaPi()) < cfgNSigma[3] || v0negdau.pt() < lowpt)))) { + registry.fill(HIST("InvMassK0s_all"), v0.pt(), v0.mK0Short(), v0.eta(), cent); + isK0s = true; + candNumAll[0] = candNumAll[0] + 1; + registry.fill(HIST("QAhisto/V0/hqaarm_podoafter"), v0.alpha(), v0.qtarm()); + } + // Lambda and antiLambda + if (std::fabs(v0.mLambda() - o2::constants::physics::MassLambda) < cfgv0_mlambdawindow && + (!cfgcheckDauTPC || (std::fabs(v0posdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(v0negdau.tpcNSigmaPi()) < cfgNSigma[0])) && + (!cfgcheckDauTOF || ((std::fabs(v0posdau.tofNSigmaPr()) < cfgNSigma[4] || v0posdau.pt() < lowpt) && (std::fabs(v0negdau.tofNSigmaPi()) < cfgNSigma[3] || v0negdau.pt() < lowpt)))) { + registry.fill(HIST("InvMassLambda_all"), v0.pt(), v0.mLambda(), v0.eta(), cent); + isLambda = true; + candNumAll[1] = candNumAll[1] + 1; + } else if (std::fabs(v0.mLambda() - o2::constants::physics::MassLambda) < cfgv0_mlambdawindow && + (!cfgcheckDauTPC || (std::fabs(v0negdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(v0posdau.tpcNSigmaPi()) < cfgNSigma[0])) && + (!cfgcheckDauTOF || ((std::fabs(v0negdau.tofNSigmaPr()) < cfgNSigma[4] || v0negdau.pt() < lowpt) && (std::fabs(v0posdau.tofNSigmaPi()) < cfgNSigma[3] || v0posdau.pt() < lowpt)))) { + registry.fill(HIST("InvMassLambda_all"), v0.pt(), v0.mLambda(), v0.eta(), cent); + isLambda = true; + candNumAll[1] = candNumAll[1] + 1; + } + // fill QA before cut + registry.fill(HIST("QAhisto/V0/hqaV0radiusbefore"), v0.v0radius()); + registry.fill(HIST("QAhisto/V0/hqaV0cosPAbefore"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/V0/hqadcaV0daubefore"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/V0/hqadcapostoPVbefore"), v0.dcapostopv()); + registry.fill(HIST("QAhisto/V0/hqadcanegtoPVbefore"), v0.dcanegtopv()); + if (!isK0s && !isLambda) + continue; + // track quality check + if (v0posdau.tpcNClsFound() < cfgtpcclusters) + continue; + if (v0negdau.tpcNClsFound() < cfgtpcclusters) + continue; + if (v0posdau.tpcNClsFindable() < cfgtpcclufindable) + continue; + if (v0negdau.tpcNClsFindable() < cfgtpcclufindable) + continue; + if (v0posdau.tpcCrossedRowsOverFindableCls() < cfgtpccrossoverfindable) + continue; + if (v0posdau.itsNCls() < cfgitsclusters) + continue; + if (v0negdau.itsNCls() < cfgitsclusters) + continue; + // topological cut + if (v0.v0radius() < cfgv0_radius) + continue; + if (v0.v0cosPA() < cfgv0_v0cospa) + continue; + if (v0.dcaV0daughters() > cfgv0_dcav0dau) + continue; + if (std::fabs(v0.dcapostopv()) < cfgv0_dcadautopv) + continue; + if (std::fabs(v0.dcanegtopv()) < cfgv0_dcadautopv) + continue; + // fill QA after cut + registry.fill(HIST("QAhisto/V0/hqaV0radiusafter"), v0.v0radius()); + registry.fill(HIST("QAhisto/V0/hqaV0cosPAafter"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/V0/hqadcaV0dauafter"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/V0/hqadcapostoPVafter"), v0.dcapostopv()); + registry.fill(HIST("QAhisto/V0/hqadcanegtoPVafter"), v0.dcanegtopv()); + if (isK0s) { + if (cfgDoAccEffCorr) + setCurrentParticleWeights(weff, wacc, v0, vtxz, 1); + if (cfgDoLocDenCorr) { + int phibin = -999; + phibin = hLocalDensity->FindBin(RecoDecay::constrainAngle(v0.phi(), -constants::math::PI)); + double density = hLocalDensity->Integral(phibin - cfgDeltaPhiLocDen, phibin + cfgDeltaPhiLocDen); + setCurrentLocalDensityWeights(wloc, v0, density, 1); + if (cfgOutputLocDenWeights) + registry.fill(HIST("MC/densityMCRecK0s"), v0.pt(), nch, density, v0.mK0Short()); + } + candNum[0] = candNum[0] + 1; + registry.fill(HIST("InvMassK0s"), v0.pt(), v0.mK0Short(), v0.eta(), cent); + registry.fill(HIST("hEtaPhiVtxzPOIK0s"), v0.phi(), v0.eta(), vtxz, wacc); + fGFW->Fill(v0.eta(), fV0PtAxis->FindBin(v0.pt()) - 1 + ((fK0sMass->FindBin(v0.mK0Short()) - 1) * nV0PtBins), v0.phi(), wacc * weff * wloc, 8); + if (cfgOutputNUAWeights) + fWeightsK0s->fill(v0.phi(), v0.eta(), vtxz, v0.pt(), cent, 0); + } + if (isLambda) { + if (cfgDoAccEffCorr) + setCurrentParticleWeights(weff, wacc, v0, vtxz, 2); + if (cfgDoLocDenCorr) { + int phibin = -999; + phibin = hLocalDensity->FindBin(RecoDecay::constrainAngle(v0.phi(), -constants::math::PI)); + double density = hLocalDensity->Integral(phibin - cfgDeltaPhiLocDen, phibin + cfgDeltaPhiLocDen); + setCurrentLocalDensityWeights(wloc, v0, density, 2); + if (cfgOutputLocDenWeights) + registry.fill(HIST("MC/densityMCRecLambda"), v0.pt(), nch, density, v0.mLambda()); + } + candNum[1] = candNum[1] + 1; + registry.fill(HIST("InvMassLambda"), v0.pt(), v0.mLambda(), v0.eta(), cent); + registry.fill(HIST("hEtaPhiVtxzPOILambda"), v0.phi(), v0.eta(), vtxz, wacc); + fGFW->Fill(v0.eta(), fV0PtAxis->FindBin(v0.pt()) - 1 + ((fLambdaMass->FindBin(v0.mLambda()) - 1) * nV0PtBins), v0.phi(), wacc * weff * wloc, 16); + if (cfgOutputNUAWeights) + fWeightsLambda->fill(v0.phi(), v0.eta(), vtxz, v0.pt(), cent, 0); + } + } + // fill GFW of casc flow + for (const auto& casc : Cascades) { + auto bachelor = casc.bachelor_as(); + auto posdau = casc.posTrack_as(); + auto negdau = casc.negTrack_as(); + // check TPC + if (cfgcheckDauTPC && (!posdau.hasTPC() || !negdau.hasTPC() || !bachelor.hasTPC())) { + continue; + } + bool isOmega = false; + bool isXi = false; + // Omega and antiOmega + if (casc.sign() < 0 && std::fabs(casc.yOmega()) < cfgCasc_rapidity && + (!cfgcheckDauTPC || (std::fabs(bachelor.tpcNSigmaKa()) < cfgNSigma[2] && std::fabs(posdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(negdau.tpcNSigmaPi()) < cfgNSigma[0])) && + (!cfgcheckDauTOF || ((std::fabs(bachelor.tofNSigmaKa()) < cfgNSigma[5] || bachelor.pt() < lowpt) && (std::fabs(posdau.tofNSigmaPr()) < cfgNSigma[4] || posdau.pt() < lowpt) && (std::fabs(negdau.tofNSigmaPi()) < cfgNSigma[3] || negdau.pt() < lowpt)))) { + registry.fill(HIST("InvMassOmega_all"), casc.pt(), casc.mOmega(), casc.eta(), cent); + isOmega = true; + candNumAll[3] = candNumAll[3] + 1; + } else if (casc.sign() > 0 && std::fabs(casc.yOmega()) < cfgCasc_rapidity && + (!cfgcheckDauTPC || (std::fabs(bachelor.tpcNSigmaKa()) < cfgNSigma[2] && std::fabs(negdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(posdau.tpcNSigmaPi()) < cfgNSigma[0])) && + (!cfgcheckDauTOF || ((std::fabs(bachelor.tofNSigmaKa()) < cfgNSigma[5] || bachelor.pt() < lowpt) && (std::fabs(negdau.tofNSigmaPr()) < cfgNSigma[4] || negdau.pt() < lowpt) && (std::fabs(posdau.tofNSigmaPi()) < cfgNSigma[3] || posdau.pt() < lowpt)))) { + registry.fill(HIST("InvMassOmega_all"), casc.pt(), casc.mOmega(), casc.eta(), cent); + isOmega = true; + candNumAll[3] = candNumAll[3] + 1; + } + // Xi and antiXi + if (casc.sign() < 0 && std::fabs(casc.yXi()) < cfgCasc_rapidity && + (!cfgcheckDauTPC || (std::fabs(bachelor.tpcNSigmaPi()) < cfgNSigma[0] && std::fabs(posdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(negdau.tpcNSigmaPi()) < cfgNSigma[0])) && + (!cfgcheckDauTOF || ((std::fabs(bachelor.tofNSigmaPi()) < cfgNSigma[3] || bachelor.pt() < lowpt) && (std::fabs(posdau.tofNSigmaPr()) < cfgNSigma[4] || posdau.pt() < lowpt) && (std::fabs(negdau.tofNSigmaPi()) < cfgNSigma[3] || negdau.pt() < lowpt)))) { + registry.fill(HIST("InvMassXi_all"), casc.pt(), casc.mXi(), casc.eta(), cent); + isXi = true; + candNumAll[2] = candNumAll[2] + 1; + } else if (casc.sign() > 0 && std::fabs(casc.yXi()) < cfgCasc_rapidity && + (!cfgcheckDauTPC || (std::fabs(bachelor.tpcNSigmaPi()) < cfgNSigma[0] && std::fabs(negdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(posdau.tpcNSigmaPi()) < cfgNSigma[0])) && + (!cfgcheckDauTOF || ((std::fabs(bachelor.tofNSigmaPi()) < cfgNSigma[3] || bachelor.pt() < lowpt) && (std::fabs(negdau.tofNSigmaPr()) < cfgNSigma[4] || negdau.pt() < lowpt) && (std::fabs(posdau.tofNSigmaPi()) < cfgNSigma[3] || posdau.pt() < lowpt)))) { + registry.fill(HIST("InvMassXi_all"), casc.pt(), casc.mXi(), casc.eta(), cent); + isXi = true; + candNumAll[2] = candNumAll[2] + 1; + } + // fill QA + registry.fill(HIST("QAhisto/Casc/hqaCasccosPAbefore"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqaCascV0cosPAbefore"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqadcaCascV0toPVbefore"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqadcaCascBachtoPVbefore"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Casc/hqadcaCascdaubefore"), casc.dcacascdaughters()); + registry.fill(HIST("QAhisto/Casc/hqadcaCascV0daubefore"), casc.dcaV0daughters()); + + if (!isXi && !isOmega) + continue; + // topological cut + if (casc.cascradius() < cfgcasc_radius) + continue; + if (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cfgcasc_casccospa) + continue; + if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cfgcasc_v0cospa) + continue; + if (std::fabs(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < cfgcasc_dcav0topv) + continue; + if (std::fabs(casc.dcabachtopv()) < cfgcasc_dcabachtopv) + continue; + if (casc.dcacascdaughters() > cfgcasc_dcacascdau) + continue; + if (casc.dcaV0daughters() > cfgcasc_dcav0dau) + continue; + if (std::fabs(casc.mLambda() - o2::constants::physics::MassLambda0) > cfgcasc_mlambdawindow) + continue; + // track quality check + if (bachelor.tpcNClsFound() < cfgtpcclusters) + continue; + if (posdau.tpcNClsFound() < cfgtpcclusters) + continue; + if (negdau.tpcNClsFound() < cfgtpcclusters) + continue; + if (bachelor.itsNCls() < cfgitsclusters) + continue; + if (posdau.itsNCls() < cfgitsclusters) + continue; + if (negdau.itsNCls() < cfgitsclusters) + continue; + // fill QA + registry.fill(HIST("QAhisto/Casc/hqaCasccosPAafter"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqaCascV0cosPAafter"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqadcaCascV0toPVafter"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqadcaCascBachtoPVafter"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Casc/hqadcaCascdauafter"), casc.dcacascdaughters()); + registry.fill(HIST("QAhisto/Casc/hqadcaCascV0dauafter"), casc.dcaV0daughters()); + + if (isOmega) { + if (cfgDoAccEffCorr) + setCurrentParticleWeights(weff, wacc, casc, vtxz, 4); + if (cfgDoLocDenCorr) { + int phibin = -999; + phibin = hLocalDensity->FindBin(RecoDecay::constrainAngle(casc.phi(), -constants::math::PI)); + double density = hLocalDensity->Integral(phibin - cfgDeltaPhiLocDen, phibin + cfgDeltaPhiLocDen); + setCurrentLocalDensityWeights(wloc, casc, density, 4); + if (cfgOutputLocDenWeights) + registry.fill(HIST("MC/densityMCRecOmega"), casc.pt(), nch, density, casc.mOmega()); + } + candNum[3] = candNum[3] + 1; + registry.fill(HIST("hEtaPhiVtxzPOIOmega"), casc.phi(), casc.eta(), vtxz, wacc); + registry.fill(HIST("InvMassOmega"), casc.pt(), casc.mOmega(), casc.eta(), cent); + fGFW->Fill(casc.eta(), fXiPtAxis->FindBin(casc.pt()) - 1 + ((fOmegaMass->FindBin(casc.mOmega()) - 1) * nXiPtBins), casc.phi(), wacc * weff * wloc, 4); + if (cfgOutputNUAWeights) + fWeightsOmega->fill(casc.phi(), casc.eta(), vtxz, casc.pt(), cent, 0); + } + if (isXi) { + if (cfgDoAccEffCorr) + setCurrentParticleWeights(weff, wacc, casc, vtxz, 3); + if (cfgDoLocDenCorr) { + int phibin = -999; + phibin = hLocalDensity->FindBin(RecoDecay::constrainAngle(casc.phi(), -constants::math::PI)); + double density = hLocalDensity->Integral(phibin - cfgDeltaPhiLocDen, phibin + cfgDeltaPhiLocDen); + setCurrentLocalDensityWeights(wloc, casc, density, 3); + if (cfgOutputLocDenWeights) + registry.fill(HIST("MC/densityMCRecXi"), casc.pt(), nch, density, casc.mXi()); + } + candNum[2] = candNum[2] + 1; + registry.fill(HIST("hEtaPhiVtxzPOIXi"), casc.phi(), casc.eta(), vtxz, wacc); + registry.fill(HIST("InvMassXi"), casc.pt(), casc.mXi(), casc.eta(), cent); + fGFW->Fill(casc.eta(), fXiPtAxis->FindBin(casc.pt()) - 1 + ((fXiMass->FindBin(casc.mXi()) - 1) * nXiPtBins), casc.phi(), wacc * weff * wloc, 2); + if (cfgOutputNUAWeights) + fWeightsXi->fill(casc.phi(), casc.eta(), vtxz, casc.pt(), cent, 0); + } + } + for (int i = 0; i < nspecies - 1; i++) { + if (candNumAll[i] > 0) { + registry.fill(HIST("hEventCount"), 2.5, i + 0.5); + } + if (candNum[i] > 0) { + registry.fill(HIST("hEventCount"), 3.5, i + 0.5); + } + } + delete hLocalDensity; + // Filling cumulant with ROOT TProfile and loop for all ptBins + fillProfile(corrconfigs.at(15), HIST("c22"), cent); + fillProfile(corrconfigs.at(16), HIST("c24"), cent); + for (int i = 1; i <= nPtBins; i++) { + fillProfilepT(corrconfigs.at(0), HIST("c22dpt"), i, cent); + fillProfilepT(corrconfigs.at(1), HIST("c22dpt"), i, cent); + fillProfilepT(corrconfigs.at(2), HIST("c24dpt"), i, cent); + } + for (int i = 1; i <= nV0PtBins; i++) { + fillProfilepTMass(corrconfigs.at(9), HIST("K0sc22dpt"), i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(10), HIST("K0sc22dpt"), i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(11), HIST("K0sc24dpt"), i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(12), HIST("Lambdac22dpt"), i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(13), HIST("Lambdac22dpt"), i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(14), HIST("Lambdac24dpt"), i, kLambda0, cent); + } + for (int i = 1; i <= nXiPtBins; i++) { + fillProfilepTMass(corrconfigs.at(3), HIST("Xic22dpt"), i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(4), HIST("Xic22dpt"), i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(5), HIST("Xic24dpt"), i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(6), HIST("Omegac22dpt"), i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(7), HIST("Omegac22dpt"), i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(8), HIST("Omegac24dpt"), i, kOmegaMinus, cent); + } + // Fill subevents flow + if (cfgDoJackknife) { + TRandom3* fRdm = new TRandom3(0); + int nsubevent = 10; + double eventrdm = nsubevent * fRdm->Rndm(); + for (int j = 1; j <= nsubevent; j++) { + if (eventrdm > (j - 1) && eventrdm < j) + continue; + fillProfile(corrconfigs.at(15), refc22[j - 1], cent); + fillProfile(corrconfigs.at(16), refc24[j - 1], cent); + for (int i = 1; i <= nV0PtBins; i++) { + fillProfilepTMass(corrconfigs.at(9), k0sc22[j - 1], i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(10), k0sc22[j - 1], i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(11), k0sc24[j - 1], i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(12), lambdac22[j - 1], i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(13), lambdac22[j - 1], i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(14), lambdac24[j - 1], i, kLambda0, cent); + } + for (int i = 1; i <= nXiPtBins; i++) { + fillProfilepTMass(corrconfigs.at(3), xic22[j - 1], i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(4), xic22[j - 1], i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(5), xic24[j - 1], i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(6), omegac22[j - 1], i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(7), omegac22[j - 1], i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(8), omegac24[j - 1], i, kOmegaMinus, cent); + } + } + } + } + PROCESS_SWITCH(FlowGfwOmegaXi, processData, "", true); + + void processMCGen(aod::McCollisions::iterator const&, soa::Join const& tracksGen, soa::SmallGroups> const& collisionsRec, AodTracks const&) + { + fGFW->Clear(); + int nch = 0; + double cent = -1; + TH1D* hLocalDensity = new TH1D("hphi", "hphi", 400, -constants::math::TwoPI, constants::math::TwoPI); + for (const auto& collision : collisionsRec) { + if (!collision.sel8()) + return; + if (eventSelected(collision, cent)) + return; + cent = collision.centFT0C(); + } + if (cent < 0) + return; + + for (auto const& mcParticle : tracksGen) { + if (!mcParticle.isPhysicalPrimary()) + continue; + + if (mcParticle.has_tracks()) { + auto const& tracks = mcParticle.tracks_as(); + for (const auto& track : tracks) { + if (track.pt() < cfgCutPtPOIMin || track.pt() > cfgCutPtPOIMax) { + continue; + } + if (std::fabs(track.eta()) > cfgCutEta) { + continue; + } + if (!(track.isGlobalTrack())) { + continue; + } + if (track.tpcChi2NCl() > cfgCutChi2prTPCcls) { + continue; + } + int ptbin = fPtAxis->FindBin(mcParticle.pt()) - 1; + if ((mcParticle.pt() > cfgCutPtMin) && (mcParticle.pt() < cfgCutPtMax)) { + fGFW->Fill(mcParticle.eta(), ptbin, mcParticle.phi(), 1, 64); //(eta, ptbin, phi, wacc*weff, bitmask) + } + if ((mcParticle.pt() > cfgCutPtPOIMin) && (mcParticle.pt() < cfgCutPtPOIMax)) { + hLocalDensity->Fill(mcParticle.phi(), 1); + hLocalDensity->Fill(RecoDecay::constrainAngle(mcParticle.phi(), -constants::math::TwoPI), 1); + nch++; + } + } + } + } + registry.fill(HIST("MC/hCentvsNchMC"), cent, nch); + + for (const auto& straGen : tracksGen) { + if (!straGen.isPhysicalPrimary()) + continue; + int pdgCode = std::abs(straGen.pdgCode()); + if (pdgCode != PDG_t::kXiMinus && pdgCode != PDG_t::kOmegaMinus && pdgCode != PDG_t::kK0Short && pdgCode != PDG_t::kLambda0) + continue; + if (std::fabs(straGen.eta()) > cfgCutEta) + continue; + + if (pdgCode == PDG_t::kXiMinus) { + int phibin = hLocalDensity->FindBin(RecoDecay::constrainAngle(straGen.phi(), -constants::math::PI)); + double density = hLocalDensity->Integral(phibin - cfgDeltaPhiLocDen, phibin + cfgDeltaPhiLocDen); + if (cfgOutputLocDenWeights) + registry.fill(HIST("MC/densityMCGenXi"), straGen.pt(), nch, density); + fGFW->Fill(straGen.eta(), fXiPtAxis->FindBin(straGen.pt()) - 1, straGen.phi(), 1, 128); + } + if (pdgCode == PDG_t::kOmegaMinus) { + int phibin = hLocalDensity->FindBin(RecoDecay::constrainAngle(straGen.phi(), -constants::math::PI)); + double density = hLocalDensity->Integral(phibin - cfgDeltaPhiLocDen, phibin + cfgDeltaPhiLocDen); + if (cfgOutputLocDenWeights) + registry.fill(HIST("MC/densityMCGenOmega"), straGen.pt(), nch, density); + fGFW->Fill(straGen.eta(), fXiPtAxis->FindBin(straGen.pt()) - 1, straGen.phi(), 1, 256); + } + + if (pdgCode == PDG_t::kK0Short) { + int phibin = hLocalDensity->FindBin(RecoDecay::constrainAngle(straGen.phi(), -constants::math::PI)); + double density = hLocalDensity->Integral(phibin - cfgDeltaPhiLocDen, phibin + cfgDeltaPhiLocDen); + if (cfgOutputLocDenWeights) + registry.fill(HIST("MC/densityMCGenK0s"), straGen.pt(), nch, density); + fGFW->Fill(straGen.eta(), fXiPtAxis->FindBin(straGen.pt()) - 1, straGen.phi(), 1, 512); + } + if (pdgCode == PDG_t::kLambda0) { + int phibin = hLocalDensity->FindBin(RecoDecay::constrainAngle(straGen.phi(), -constants::math::PI)); + double density = hLocalDensity->Integral(phibin - cfgDeltaPhiLocDen, phibin + cfgDeltaPhiLocDen); + if (cfgOutputLocDenWeights) + registry.fill(HIST("MC/densityMCGenLambda"), straGen.pt(), nch, density); + fGFW->Fill(straGen.eta(), fXiPtAxis->FindBin(straGen.pt()) - 1, straGen.phi(), 1, 1024); + } + } + fillProfile(corrconfigs.at(25), HIST("MC/c22MC"), cent); + for (int i = 1; i <= nV0PtBins; i++) { + fillProfilepTMC(corrconfigs.at(21), HIST("MC/K0sc22dptMC"), i, kK0Short, cent); + fillProfilepTMC(corrconfigs.at(22), HIST("MC/K0sc22dptMC"), i, kK0Short, cent); + fillProfilepTMC(corrconfigs.at(23), HIST("MC/Lambdac22dptMC"), i, kLambda0, cent); + fillProfilepTMC(corrconfigs.at(24), HIST("MC/Lambdac22dptMC"), i, kLambda0, cent); + } + for (int i = 1; i <= nXiPtBins; i++) { + fillProfilepTMC(corrconfigs.at(17), HIST("MC/Xic22dptMC"), i, kXiMinus, cent); + fillProfilepTMC(corrconfigs.at(18), HIST("MC/Xic22dptMC"), i, kXiMinus, cent); + fillProfilepTMC(corrconfigs.at(19), HIST("MC/Omegac22dptMC"), i, kOmegaMinus, cent); + fillProfilepTMC(corrconfigs.at(20), HIST("MC/Omegac22dptMC"), i, kOmegaMinus, cent); + } + + delete hLocalDensity; + } + PROCESS_SWITCH(FlowGfwOmegaXi, processMCGen, "", true); + + void processMCRec(AodCollisions::iterator const& collision, soa::Join const& tracks, aod::BCsWithTimestamps const&, soa::Join const& V0s, soa::Join const& Cascades, DaughterTracks const&, aod::McParticles const&) + { + fGFW->Clear(); + const auto cent = collision.centFT0C(); + if (!collision.sel8()) + return; + if (eventSelected(collision, cent)) + return; + TH1D* hLocalDensity = new TH1D("hphi", "hphi", 400, -constants::math::TwoPI, constants::math::TwoPI); + auto bc = collision.bc_as(); + loadCorrections(bc.timestamp()); + float vtxz = collision.posZ(); + registry.fill(HIST("hVtxZ"), vtxz); + registry.fill(HIST("hCent"), cent); + + float weff = 1; + float wacc = 1; + float wloc = 1; + double nch = 0; + + for (const auto& track : tracks) { + if (!track.has_mcParticle()) + continue; + if (track.pt() < cfgCutPtPOIMin || track.pt() > cfgCutPtPOIMax) + continue; + if (std::fabs(track.eta()) > cfgCutEta) + continue; + if (!(track.isGlobalTrack())) + continue; + if (track.tpcChi2NCl() > cfgCutChi2prTPCcls) + continue; + auto mcParticle = track.mcParticle_as(); + if (cfgDoAccEffCorr) { + if (!setCurrentParticleWeights(weff, wacc, track, vtxz, 0)) + continue; + } + registry.fill(HIST("hPhi"), track.phi()); + registry.fill(HIST("hPhicorr"), track.phi(), wacc); + registry.fill(HIST("hEta"), track.eta()); + registry.fill(HIST("hEtaPhiVtxzREF"), track.phi(), track.eta(), vtxz, wacc); + registry.fill(HIST("hPt"), track.pt()); + int ptbin = fPtAxis->FindBin(track.pt()) - 1; + if ((track.pt() > cfgCutPtMin) && (track.pt() < cfgCutPtMax)) { + fGFW->Fill(track.eta(), ptbin, track.phi(), wacc * weff, 1); //(eta, ptbin, phi, wacc*weff, bitmask) + } + if ((track.pt() > cfgCutPtPOIMin) && (track.pt() < cfgCutPtPOIMax)) { + fGFW->Fill(track.eta(), ptbin, track.phi(), wacc * weff, 32); + if (cfgDoLocDenCorr) { + hLocalDensity->Fill(mcParticle.phi(), wacc * weff); + hLocalDensity->Fill(RecoDecay::constrainAngle(mcParticle.phi(), -constants::math::TwoPI), wacc * weff); + nch += wacc * weff; + } + } + } + + if (cfgDoLocDenCorr) { + registry.fill(HIST("hCentvsNch"), cent, nch); + } + + for (const auto& casc : Cascades) { + if (!casc.has_mcParticle()) + continue; + auto cascMC = casc.mcParticle_as(); + auto negdau = casc.negTrack_as(); + auto posdau = casc.posTrack_as(); + auto bachelor = casc.bachelor_as(); + // fill QA + registry.fill(HIST("QAhisto/Casc/hqaCasccosPAbefore"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqaCascV0cosPAbefore"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqadcaCascV0toPVbefore"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqadcaCascBachtoPVbefore"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Casc/hqadcaCascdaubefore"), casc.dcacascdaughters()); + registry.fill(HIST("QAhisto/Casc/hqadcaCascV0daubefore"), casc.dcaV0daughters()); + // track quality check + if (bachelor.tpcNClsFound() < cfgtpcclusters) + continue; + if (posdau.tpcNClsFound() < cfgtpcclusters) + continue; + if (negdau.tpcNClsFound() < cfgtpcclusters) + continue; + if (bachelor.itsNCls() < cfgitsclusters) + continue; + if (posdau.itsNCls() < cfgitsclusters) + continue; + if (negdau.itsNCls() < cfgitsclusters) + continue; + // topological cut + if (casc.cascradius() < cfgcasc_radius) + continue; + if (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cfgcasc_casccospa) + continue; + if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cfgcasc_v0cospa) + continue; + if (std::fabs(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < cfgcasc_dcav0topv) + continue; + if (std::fabs(casc.dcabachtopv()) < cfgcasc_dcabachtopv) + continue; + if (casc.dcacascdaughters() > cfgcasc_dcacascdau) + continue; + if (casc.dcaV0daughters() > cfgcasc_dcav0dau) + continue; + if (std::fabs(casc.mLambda() - o2::constants::physics::MassLambda0) > cfgcasc_mlambdawindow) + continue; + // fill QA + registry.fill(HIST("QAhisto/Casc/hqaCasccosPAafter"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqaCascV0cosPAafter"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqadcaCascV0toPVafter"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Casc/hqadcaCascBachtoPVafter"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Casc/hqadcaCascdauafter"), casc.dcacascdaughters()); + registry.fill(HIST("QAhisto/Casc/hqadcaCascV0dauafter"), casc.dcaV0daughters()); + // Omega and antiOmega + int pdgCode{cascMC.pdgCode()}; + double cascPt{cascMC.pt()}; + double cascPhi{cascMC.phi()}; + double cascEta{cascMC.eta()}; + if (std::abs(pdgCode) == kOmegaMinus) { + if (casc.sign() < 0 && std::fabs(casc.yOmega()) < cfgCasc_rapidity && + (!cfgcheckDauTPC || (std::fabs(bachelor.tpcNSigmaKa()) < cfgNSigma[2] && std::fabs(posdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(negdau.tpcNSigmaPi()) < cfgNSigma[0]))) { + if (cfgDoAccEffCorr) + setCurrentParticleWeights(weff, wacc, casc, vtxz, 4); + if (cfgDoLocDenCorr) { + int phibin = -999; + phibin = hLocalDensity->FindBin(RecoDecay::constrainAngle(cascPhi, -constants::math::PI)); + double density = hLocalDensity->Integral(phibin - cfgDeltaPhiLocDen, phibin + cfgDeltaPhiLocDen); + setCurrentLocalDensityWeights(wloc, casc, density, 4); + if (cfgOutputLocDenWeights) + registry.fill(HIST("MC/densityMCRecOmega"), cascPt, nch, density, casc.mOmega()); + } + fGFW->Fill(cascEta, fXiPtAxis->FindBin(cascPt) - 1, cascPhi, wacc * weff * wloc, 4); + } else if (casc.sign() > 0 && std::fabs(casc.yOmega()) < cfgCasc_rapidity && + (!cfgcheckDauTPC || (std::fabs(bachelor.tpcNSigmaKa()) < cfgNSigma[2] && std::fabs(negdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(posdau.tpcNSigmaPi()) < cfgNSigma[0]))) { + if (cfgDoAccEffCorr) + setCurrentParticleWeights(weff, wacc, casc, vtxz, 4); + if (cfgDoLocDenCorr) { + int phibin = -999; + phibin = hLocalDensity->FindBin(RecoDecay::constrainAngle(cascPhi, -constants::math::PI)); + double density = hLocalDensity->Integral(phibin - cfgDeltaPhiLocDen, phibin + cfgDeltaPhiLocDen); + setCurrentLocalDensityWeights(wloc, casc, density, 4); + if (cfgOutputLocDenWeights) + registry.fill(HIST("MC/densityMCRecOmega"), cascPt, nch, density, casc.mOmega()); + } + fGFW->Fill(cascEta, fXiPtAxis->FindBin(cascPt) - 1, cascPhi, wacc * weff * wloc, 4); + } + } + // Xi and antiXi + if (std::abs(pdgCode) == kXiMinus) { + if (casc.sign() < 0 && std::fabs(casc.yXi()) < cfgCasc_rapidity && + (!cfgcheckDauTPC || (std::fabs(bachelor.tpcNSigmaPi()) < cfgNSigma[0] && std::fabs(posdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(negdau.tpcNSigmaPi()) < cfgNSigma[0]))) { + if (cfgDoAccEffCorr) + setCurrentParticleWeights(weff, wacc, casc, vtxz, 3); + if (cfgDoLocDenCorr) { + int phibin = -999; + phibin = hLocalDensity->FindBin(RecoDecay::constrainAngle(cascPhi, -constants::math::PI)); + double density = hLocalDensity->Integral(phibin - cfgDeltaPhiLocDen, phibin + cfgDeltaPhiLocDen); + setCurrentLocalDensityWeights(wloc, casc, density, 3); + if (cfgOutputLocDenWeights) + registry.fill(HIST("MC/densityMCRecXi"), cascPt, nch, density, casc.mXi()); + } + fGFW->Fill(cascEta, fXiPtAxis->FindBin(cascPt) - 1, cascPhi, wacc * weff * wloc, 2); + } else if (casc.sign() > 0 && std::fabs(casc.yXi()) < cfgCasc_rapidity && + (!cfgcheckDauTPC || (std::fabs(bachelor.tpcNSigmaPi()) < cfgNSigma[0] && std::fabs(negdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(posdau.tpcNSigmaPi()) < cfgNSigma[0]))) { + if (cfgDoAccEffCorr) + setCurrentParticleWeights(weff, wacc, casc, vtxz, 3); + if (cfgDoLocDenCorr) { + int phibin = -999; + phibin = hLocalDensity->FindBin(RecoDecay::constrainAngle(cascPhi, -constants::math::PI)); + double density = hLocalDensity->Integral(phibin - cfgDeltaPhiLocDen, phibin + cfgDeltaPhiLocDen); + setCurrentLocalDensityWeights(wloc, casc, density, 3); + if (cfgOutputLocDenWeights) + registry.fill(HIST("MC/densityMCRecXi"), cascPt, nch, density, casc.mXi()); + } + fGFW->Fill(cascEta, fXiPtAxis->FindBin(cascPt) - 1, cascPhi, wacc * weff * wloc, 2); + } + } + } + + for (const auto& v0 : V0s) { + if (!v0.has_mcParticle()) + continue; + auto v0MC = v0.mcParticle_as(); + auto v0negdau = v0.negTrack_as(); + auto v0posdau = v0.posTrack_as(); + + // fill QA before cut + registry.fill(HIST("QAhisto/V0/hqaV0radiusbefore"), v0.v0radius()); + registry.fill(HIST("QAhisto/V0/hqaV0cosPAbefore"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/V0/hqadcaV0daubefore"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/V0/hqadcapostoPVbefore"), v0.dcapostopv()); + registry.fill(HIST("QAhisto/V0/hqadcanegtoPVbefore"), v0.dcanegtopv()); + registry.fill(HIST("QAhisto/V0/hqaarm_podobefore"), v0.alpha(), v0.qtarm()); + // track quality check + if (v0posdau.tpcNClsFound() < cfgtpcclusters) + continue; + if (v0negdau.tpcNClsFound() < cfgtpcclusters) + continue; + if (v0posdau.tpcNClsFindable() < cfgtpcclufindable) + continue; + if (v0negdau.tpcNClsFindable() < cfgtpcclufindable) + continue; + if (v0posdau.tpcCrossedRowsOverFindableCls() < cfgtpccrossoverfindable) + continue; + if (v0posdau.itsNCls() < cfgitsclusters) + continue; + if (v0negdau.itsNCls() < cfgitsclusters) + continue; + // topological cut + if (v0.v0radius() < cfgv0_radius) + continue; + if (v0.v0cosPA() < cfgv0_v0cospa) + continue; + if (v0.dcaV0daughters() > cfgv0_dcav0dau) + continue; + if (std::fabs(v0.dcapostopv()) < cfgv0_dcadautopv) + continue; + if (std::fabs(v0.dcanegtopv()) < cfgv0_dcadautopv) + continue; + // fill QA after cut + registry.fill(HIST("QAhisto/V0/hqaV0radiusafter"), v0.v0radius()); + registry.fill(HIST("QAhisto/V0/hqaV0cosPAafter"), v0.v0cosPA()); + registry.fill(HIST("QAhisto/V0/hqadcaV0dauafter"), v0.dcaV0daughters()); + registry.fill(HIST("QAhisto/V0/hqadcapostoPVafter"), v0.dcapostopv()); + registry.fill(HIST("QAhisto/V0/hqadcanegtoPVafter"), v0.dcanegtopv()); + + int pdgCode{v0MC.pdgCode()}; + double v0Pt{v0MC.pt()}; + double v0Phi{v0MC.phi()}; + double v0Eta{v0MC.eta()}; + // K0short + if (std::abs(pdgCode) == kK0Short) { + if (v0.qtarm() / std::fabs(v0.alpha()) > cfgv0_ArmPodocut && std::fabs(v0.mK0Short() - o2::constants::physics::MassK0Short) < cfgv0_mk0swindow && + (!cfgcheckDauTPC || (std::fabs(v0posdau.tpcNSigmaPi()) < cfgNSigma[0] && std::fabs(v0negdau.tpcNSigmaPi()) < cfgNSigma[0]))) { + if (cfgDoAccEffCorr) + setCurrentParticleWeights(weff, wacc, v0, vtxz, 1); + if (cfgDoLocDenCorr) { + int phibin = -999; + phibin = hLocalDensity->FindBin(RecoDecay::constrainAngle(v0Phi, -constants::math::PI)); + double density = hLocalDensity->Integral(phibin - cfgDeltaPhiLocDen, phibin + cfgDeltaPhiLocDen); + setCurrentLocalDensityWeights(wloc, v0, density, 1); + if (cfgOutputLocDenWeights) + registry.fill(HIST("MC/densityMCRecK0s"), v0Pt, nch, density, v0.mK0Short()); + } + fGFW->Fill(v0Eta, fV0PtAxis->FindBin(v0Pt) - 1, v0Phi, wacc * weff * wloc, 8); + } + } + // Lambda and antiLambda + if (std::fabs(v0.mLambda() - o2::constants::physics::MassLambda) < cfgv0_mlambdawindow && + (!cfgcheckDauTPC || (std::fabs(v0posdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(v0negdau.tpcNSigmaPi()) < cfgNSigma[0]))) { + if (std::abs(pdgCode) == kLambda0) { + if (cfgDoAccEffCorr) + setCurrentParticleWeights(weff, wacc, v0, vtxz, 2); + if (cfgDoLocDenCorr) { + int phibin = -999; + phibin = hLocalDensity->FindBin(RecoDecay::constrainAngle(v0Phi, -constants::math::PI)); + double density = hLocalDensity->Integral(phibin - cfgDeltaPhiLocDen, phibin + cfgDeltaPhiLocDen); + setCurrentLocalDensityWeights(wloc, v0, density, 2); + if (cfgOutputLocDenWeights) + registry.fill(HIST("MC/densityMCRecLambda"), v0Pt, nch, density, v0.mLambda()); + } + fGFW->Fill(v0Eta, fV0PtAxis->FindBin(v0Pt) - 1, v0Phi, wacc * weff * wloc, 16); + } + } else if (std::fabs(v0.mLambda() - o2::constants::physics::MassLambda) < cfgv0_mlambdawindow && + (!cfgcheckDauTPC || (std::fabs(v0negdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(v0posdau.tpcNSigmaPi()) < cfgNSigma[0]))) { + if (std::abs(pdgCode) == kLambda0) { + if (cfgDoAccEffCorr) + setCurrentParticleWeights(weff, wacc, v0, vtxz, 2); + if (cfgDoLocDenCorr) { + int phibin = -999; + phibin = hLocalDensity->FindBin(RecoDecay::constrainAngle(v0Phi, -constants::math::PI)); + double density = hLocalDensity->Integral(phibin - cfgDeltaPhiLocDen, phibin + cfgDeltaPhiLocDen); + setCurrentLocalDensityWeights(wloc, v0, density, 2); + if (cfgOutputLocDenWeights) + registry.fill(HIST("MC/densityMCRecLambda"), v0Pt, nch, density, v0.mLambda()); + } + fGFW->Fill(v0Eta, fV0PtAxis->FindBin(v0Pt) - 1, v0Phi, wacc * weff * wloc, 16); + } + } + } + delete hLocalDensity; + fillProfile(corrconfigs.at(15), HIST("c22"), cent); + for (int i = 1; i <= nV0PtBins; i++) { + fillProfilepTMass(corrconfigs.at(9), HIST("K0sc22dpt"), i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(10), HIST("K0sc22dpt"), i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(12), HIST("Lambdac22dpt"), i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(13), HIST("Lambdac22dpt"), i, kLambda0, cent); + } + for (int i = 1; i <= nXiPtBins; i++) { + fillProfilepTMass(corrconfigs.at(3), HIST("Xic22dpt"), i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(4), HIST("Xic22dpt"), i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(6), HIST("Omegac22dpt"), i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(7), HIST("Omegac22dpt"), i, kOmegaMinus, cent); + } + } + PROCESS_SWITCH(FlowGfwOmegaXi, processMCRec, "", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Flow/Tasks/flowGfwTask.cxx b/PWGCF/Flow/Tasks/flowGfwTask.cxx new file mode 100644 index 00000000000..e5854dcf43b --- /dev/null +++ b/PWGCF/Flow/Tasks/flowGfwTask.cxx @@ -0,0 +1,1287 @@ +// 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 flowGfwTask.cxx +/// \author Iris Likmeta (iris.likmeta@cern.ch) +/// \since Mar 28, 2024 +/// \brief Multiparticle flow measurements with FT0 and ZDC + +#include +#include +#include +#include +#include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/AnalysisDataModel.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" + +#include "Framework/O2DatabasePDGPlugin.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/Track.h" +#include "TPDGCode.h" + +#include "GFWPowerArray.h" +#include "GFW.h" +#include "GFWCumulant.h" +#include "GFWWeights.h" +#include "FlowContainer.h" +#include "TList.h" +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::track; +using namespace o2::aod::evsel; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +using MyCollisions = soa::Join; +using MyTracks = soa::Join; +using Colls = soa::Filtered>; +using AodTracks = soa::Filtered>; +using BCsRun3 = soa::Join; + +struct FlowGfwTask { + + O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 3.0f, "Maximal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5, "Chi2 per TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutTPCclu, float, 70.0f, "minimum TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutITSclu, float, 5.0f, "minimum ITS clusters") + O2_DEFINE_CONFIGURABLE(cfgTrackSel, bool, false, "ITS and TPC cluster selection") + O2_DEFINE_CONFIGURABLE(cfgMinCentFT0C, float, 0.0f, "Minimum FT0C Centrality") + O2_DEFINE_CONFIGURABLE(cfgMaxCentFT0C, float, 100.0f, "Maximum FT0C Centrality") + O2_DEFINE_CONFIGURABLE(cfgcentEstFt0c, bool, false, "Centrality estimator based on FT0C signal") + O2_DEFINE_CONFIGURABLE(cfgcentEstFt0a, bool, false, "Centrality estimator based on FT0A signal") + O2_DEFINE_CONFIGURABLE(cfgcentEstFt0m, bool, false, " A centrality estimator based on FT0A+FT0C signals.") + O2_DEFINE_CONFIGURABLE(cfgcentEstFv0a, bool, false, "Centrality estimator based on FV0A signal") + O2_DEFINE_CONFIGURABLE(cfgcentEstFt0cVariant1, bool, false, "A variant of FT0C") + O2_DEFINE_CONFIGURABLE(cfgUseAdditionalEventCut, bool, false, "Use additional event cut on mult correlations") + O2_DEFINE_CONFIGURABLE(cfgUseAdditionalTrackCut, bool, false, "Use additional track cut on phi") + O2_DEFINE_CONFIGURABLE(cfgTrackSelRun3ITSMatch, bool, false, "Track selection for ITS matches") + O2_DEFINE_CONFIGURABLE(cfgUseNch, bool, false, "Use Nch for flow observables") + O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 10, "Number of subsamples") + O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeights, bool, false, "Fill and output NUA weights") + O2_DEFINE_CONFIGURABLE(cfgEfficiency, std::string, "", "CCDB path to efficiency object") + O2_DEFINE_CONFIGURABLE(cfgEfficiencyNch, std::string, "", "CCDB path to Nch efficiency object") + O2_DEFINE_CONFIGURABLE(cfgAcceptance, std::string, "", "CCDB path to acceptance object") + O2_DEFINE_CONFIGURABLE(cfgMagnetField, std::string, "GLO/Config/GRPMagField", "CCDB path to Magnet field object") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyHigh, int, 500, "High cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyLow, int, 0, "Low cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgCutDCAz, float, 2, "Custom DCA Z cut") + O2_DEFINE_CONFIGURABLE(cfgCutDCAxy, float, 0.2f, "Custom DCA XY cut") + O2_DEFINE_CONFIGURABLE(cfgDCAzPt, bool, false, "switch for DCAz pt dependent") + O2_DEFINE_CONFIGURABLE(cfgNoTimeFrameBorder, bool, false, "kNoTimeFrameBorder"); + O2_DEFINE_CONFIGURABLE(cfgNoITSROFrameBorder, bool, false, "kNoITSROFrameBorder"); + O2_DEFINE_CONFIGURABLE(cfgNoSameBunchPileup, bool, false, "kNoSameBunchPileup"); + O2_DEFINE_CONFIGURABLE(cfgIsGoodZvtxFT0vsPV, bool, false, "kIsGoodZvtxFT0vsPV"); + O2_DEFINE_CONFIGURABLE(cfgIsVertexITSTPC, bool, false, "kIsVertexITSTPC"); + O2_DEFINE_CONFIGURABLE(cfgNoCollInTimeRangeStandard, bool, false, "kNoCollInTimeRangeStandard"); + O2_DEFINE_CONFIGURABLE(cfgEvSelkIsGoodITSLayersAll, bool, false, "kIsGoodITSLayersAll") + O2_DEFINE_CONFIGURABLE(cfgOccupancy, bool, false, "Bool for event selection on detector occupancy"); + O2_DEFINE_CONFIGURABLE(cfgMultCut, bool, false, "Use additional event cut on mult correlations"); + O2_DEFINE_CONFIGURABLE(cfgV0AT0A5Sigma, bool, false, "V0A T0A 5 sigma cut") + O2_DEFINE_CONFIGURABLE(cfgGlobalplusITS, bool, false, "Global and ITS tracks") + O2_DEFINE_CONFIGURABLE(cfgGlobalonly, bool, false, "Global only tracks") + O2_DEFINE_CONFIGURABLE(cfgITSonly, bool, false, "ITS only tracks") + O2_DEFINE_CONFIGURABLE(cfgFineBinning, bool, false, "Manually change to fine binning") + + ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for histograms"}; + ConfigurableAxis axisPhi{"axisPhi", {60, 0.0, constants::math::TwoPI}, "phi axis for histograms"}; + ConfigurableAxis axisPhiMod{"axisPhiMod", {100, 0, constants::math::PI / 9}, "fmod(#varphi,#pi/9)"}; + ConfigurableAxis axisEta{"axisEta", {40, -1., 1.}, "eta axis for histograms"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.2, 0.25, 0.30, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.20, 2.40, 2.60, 2.80, 3.00}, "pt axis for histograms"}; + ConfigurableAxis axisPtHist{"axisPtHist", {100, 0., 10.}, "pt axis for histograms"}; + ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}, "centrality axis for histograms"}; + ConfigurableAxis axisNch{"axisNch", {4000, 0, 4000}, "N_{ch}"}; + ConfigurableAxis axisCentForQA{"axisCentForQA", {100, 0, 100}, "centrality for QA"}; + ConfigurableAxis axisT0C{"axisT0C", {70, 0, 70000}, "N_{ch} (T0C)"}; + ConfigurableAxis axisT0A{"axisT0A", {200, 0, 200000}, "N_{ch} (T0A)"}; + ConfigurableAxis axisT0M{"axisT0M", {70, 0, 70000}, "N_{ch} (T0M)"}; + ConfigurableAxis axisFT0CAmp{"axisFT0CAmp", {50000, 0, 50000}, "axisFT0CAmp"}; + ConfigurableAxis axisFT0AAmp{"axisFT0AAmp", {50000, 0, 50000}, "axisFT0AAmp"}; + ConfigurableAxis axisFT0MAmp{"axisFT0MAmp", {50000, 0, 50000}, "axisFT0MAmp"}; + ConfigurableAxis axisNchPV{"axisNchPV", {4000, 0, 4000}, "N_{ch} (PV)"}; + ConfigurableAxis axisDCAz{"axisDCAz", {200, -2, 2}, "DCA_{z} (cm)"}; + ConfigurableAxis axisDCAxy{"axisDCAxy", {200, -1, 1}, "DCA_{xy} (cm)"}; + + // Configurables for ZDC + Configurable nBinsAmp{"nBinsAmp", 1025, "nbinsAmp"}; + Configurable maxZN{"maxZN", 4099.5, "Max ZN signal"}; + Configurable maxZP{"maxZP", 3099.5, "Max ZP signal"}; + Configurable maxZEM{"maxZEM", 3099.5, "Max ZEM signal"}; + Configurable nBinsFit{"nBinsFit", 1000, "nbinsFit"}; + Configurable maxMultFT0{"maxMultFT0", 5000, "Max FT0 signal"}; + + // Corrections + TH1D* mEfficiency = nullptr; + TH1D* mEfficiencyNch = nullptr; + GFWWeights* mAcceptance = nullptr; + bool correctionsLoaded = false; + + // Connect to ccdb + Service ccdb; + Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + // Define output + OutputObj fFC{FlowContainer("FlowContainer")}; + OutputObj fWeights{GFWWeights("weights")}; + HistogramRegistry registry{"registry"}; + + // define global variables + GFW* fGFW = new GFW(); // GFW class used from main src + std::vector corrconfigs; + TRandom3* fRndm = new TRandom3(0); + TAxis* fPtAxis; + std::vector>> bootstrapArray; // TProfile is a shared pointer + + enum ExtraProfile { + + // here are TProfiles for vn-ft0 correlations that are not implemented in GFW + kc22, + kc24, + kc26, + kc28, + kc22etagap, + kc32, + kc32etagap, + kc34, + kc22Nch, + kc24Nch, + kc26Nch, + kc28Nch, + kc22Nchetagap, + kc32Nch, + kc32Nchetagap, + kc34Nch, + kc22Nch05, + kc24Nch05, + kc26Nch05, + kc28Nch05, + kc22Nch05etagap, + kc32Nch05, + kc32Nch05etagap, + kc34Nch05, + + // Count the total number of enum + kCount_ExtraProfile + }; + + enum EventProgress { + kFILTERED, + kSEL8, + kOCCUPANCY, + kNOTIMEFRAMEBORDER, + kNOITSROFRAMEBORDER, + kNOPSAMEBUNCHPILEUP, + kISGOODZVTXFT0VSPV, + kISVERTEXITSTPC, + kNOCOLLINTIMERANGESTANDART, + kISGOODITSLAYERSALL, + kAFTERMULTCUTS, + kCENTRALITY, + kNOOFEVENTSTEPS + }; + + enum CentEstimators { + kCentFT0C, + kCentFT0A, + kCentFT0M, + kCentFV0A, + kCentFT0CVariant1, + kNoCentEstimators + }; + + // Contruct Global+ITS sample + static constexpr TrackSelectionFlags::flagtype TrackSelectionITS = + TrackSelectionFlags::kITSNCls | TrackSelectionFlags::kITSChi2NDF | + TrackSelectionFlags::kITSHits; + static constexpr TrackSelectionFlags::flagtype TrackSelectionTPC = + TrackSelectionFlags::kTPCNCls | + TrackSelectionFlags::kTPCCrossedRowsOverNCls | + TrackSelectionFlags::kTPCChi2NDF; + static constexpr TrackSelectionFlags::flagtype TrackSelectionDCA = + TrackSelectionFlags::kDCAz | TrackSelectionFlags::kDCAxy; + static constexpr TrackSelectionFlags::flagtype TrackSelectionDCAXYonly = + TrackSelectionFlags::kDCAxy; + + // Additional Event selection cuts - Copy from flowGenericFramework.cxx + TrackSelection myTrackSel; + TF1* fPhiCutLow = nullptr; + TF1* fPhiCutHigh = nullptr; + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + TF1* fMultCutLow = nullptr; + TF1* fMultCutHigh = nullptr; + TF1* fMultMultPVCut = nullptr; + TF1* fT0AV0AMean = nullptr; + TF1* fT0AV0ASigma = nullptr; + + bool isStable(int pdg) + { + if (std::abs(pdg) == kPiPlus) + return true; + if (std::abs(pdg) == kKPlus) + return true; + if (std::abs(pdg) == kProton) + return true; + if (std::abs(pdg) == kElectron) + return true; + if (std::abs(pdg) == kMuonMinus) + return true; + return false; + } + + void init(InitContext const&) // Initialization + { + ccdb->setURL(ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setCreatedNotAfter(ccdbNoLaterThan.value); + + // Add some output objects to the histogram registry + registry.add("hEventCount", "Number of Events;; No. of Events", {HistType::kTH1D, {{kNOOFEVENTSTEPS, -0.5, static_cast(kNOOFEVENTSTEPS) - 0.5}}}); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kFILTERED + 1, "Filtered events"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kSEL8 + 1, "Sel8"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kOCCUPANCY + 1, "Occupancy"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kNOTIMEFRAMEBORDER + 1, "kNoTimeFrameBorder"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kNOITSROFRAMEBORDER + 1, "kNoITSROFrameBorder"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kNOPSAMEBUNCHPILEUP + 1, "kNoSameBunchPileup"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kISGOODZVTXFT0VSPV + 1, "kIsGoodZvtxFT0vsPV"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kISVERTEXITSTPC + 1, "kIsVertexITSTPC"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kNOCOLLINTIMERANGESTANDART + 1, "kNoCollInTimeRangeStandard"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kISGOODITSLAYERSALL + 1, "kIsGoodITSLayersAll"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kAFTERMULTCUTS + 1, "After Mult cuts"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kCENTRALITY + 1, "Centrality"); + + if (doprocessData) { + registry.add("hPhi", "#phi distribution", {HistType::kTH1D, {axisPhi}}); + registry.add("hPhiWeighted", "corrected #phi distribution", {HistType::kTH1D, {axisPhi}}); + registry.add("hEta", "", {HistType::kTH1D, {axisEta}}); + registry.add("hVtxZ", "Vexter Z distribution", {HistType::kTH1D, {axisVertex}}); + registry.add("hMult", "Multiplicity distribution", {HistType::kTH1D, {axisNch}}); + registry.add("hMultCorr", "Corrected Multiplicity distribution", {HistType::kTH1D, {axisNch}}); + registry.add("hCent", "Centrality distribution", {HistType::kTH1D, {{90, 0, 90}}}); + registry.add("cent_vs_Nch", ";Centrality (%); M (|#eta| < 0.8);", {HistType::kTH2D, {axisCentrality, axisNch}}); + registry.add("cent_vs_NchCorr", ";Centrality (%); M (|#eta| < 0.8);", {HistType::kTH2D, {axisCentrality, axisNch}}); + + // Centrality estimators + registry.add("hCentEstimators", "Number of Unfiltered Events;; No. of Events", {HistType::kTH1D, {{kNoCentEstimators, -0.5, static_cast(kNoCentEstimators) - 0.5}}}); + registry.get(HIST("hCentEstimators"))->GetXaxis()->SetBinLabel(kCentFT0C + 1, "FT0C"); + registry.get(HIST("hCentEstimators"))->GetXaxis()->SetBinLabel(kCentFT0A + 1, "FT0A"); + registry.get(HIST("hCentEstimators"))->GetXaxis()->SetBinLabel(kCentFT0M + 1, "FT0M"); + registry.get(HIST("hCentEstimators"))->GetXaxis()->SetBinLabel(kCentFV0A + 1, "FV0A"); + registry.get(HIST("hCentEstimators"))->GetXaxis()->SetBinLabel(kCentFT0CVariant1 + 1, "FT0CVar1"); + registry.add("hCentFT0C", "Uncorrected FT0C;Centrality FT0C ;Events", kTH1F, {axisCentrality}); + registry.add("hCentFT0A", "Uncorrected FT0A;Centrality FT0A ;Events", kTH1F, {axisCentrality}); + registry.add("hCentFT0M", "Uncorrected FT0M;Centrality FT0M ;Events", kTH1F, {axisCentrality}); + registry.add("hCentFV0A", "Uncorrected FV0A;Centrality FV0A ;Events", kTH1F, {axisCentrality}); + registry.add("hCentFT0CVariant1", "Uncorrected FT0CVariant1;Centrality FT0CVariant1 ;Events", kTH1F, {axisCentrality}); + + // Before cuts + registry.add("BeforeCut_globalTracks_centT0C", "before cut;Centrality T0C;mulplicity global tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + registry.add("BeforeCut_PVTracks_centT0C", "before cut;Centrality T0C;mulplicity PV tracks", {HistType::kTH2D, {axisCentForQA, axisNchPV}}); + registry.add("BeforeCut_globalTracks_PVTracks", "before cut;mulplicity PV tracks;mulplicity global tracks", {HistType::kTH2D, {axisNchPV, axisNch}}); + registry.add("BeforeCut_globalTracks_multT0A", "before cut;mulplicity T0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + registry.add("BeforeCut_globalTracks_multV0A", "before cut;mulplicity V0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + registry.add("BeforeCut_multV0A_multT0A", "before cut;mulplicity T0A;mulplicity V0A", {HistType::kTH2D, {axisT0A, axisT0A}}); + registry.add("BeforeCut_multT0C_centT0C", "before cut;Centrality T0C;mulplicity T0C", {HistType::kTH2D, {axisCentForQA, axisT0C}}); + registry.add("BeforeCut_multT0A_centT0A", "before cut;Centrality T0C;mulplicity T0A", {HistType::kTH2D, {axisCentForQA, axisT0A}}); + registry.add("BeforeCut_multFT0M_centFT0M", "before cut;Centrality FT0M;mulplicity FT0M", {HistType::kTH2D, {axisCentForQA, axisT0M}}); + + // After cuts + registry.add("globalTracks_centT0C_Aft", "after cut;Centrality T0C;mulplicity global tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + registry.add("PVTracks_centT0C_Aft", "after cut;Centrality T0C;mulplicity PV tracks", {HistType::kTH2D, {axisCentForQA, axisNchPV}}); + registry.add("globalTracks_PVTracks_Aft", "after cut;mulplicity PV tracks;mulplicity global tracks", {HistType::kTH2D, {axisNchPV, axisNch}}); + registry.add("globalTracks_multT0A_Aft", "after cut;mulplicity T0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + registry.add("globalTracks_multV0A_Aft", "after cut;mulplicity V0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + registry.add("multV0A_multT0A_Aft", "after cut;mulplicity T0A;mulplicity V0A", {HistType::kTH2D, {axisT0A, axisT0A}}); + registry.add("multT0C_centT0C_Aft", "after cut;Centrality T0C;mulplicity T0C", {HistType::kTH2D, {axisCentForQA, axisT0C}}); + registry.add("multT0A_centT0A_Aft", "after cut;Centrality T0A;mulplicity T0A", {HistType::kTH2D, {axisCentForQA, axisT0A}}); + registry.add("multFT0M_centFT0M_Aft", "after cut;Centrality FT0M;mulplicity FT0M", {HistType::kTH2D, {axisCentForQA, axisT0M}}); + + // FT0 plots + registry.add("FT0CAmp", ";FT0C amplitude;Events", kTH1F, {axisFT0CAmp}); + registry.add("FT0AAmp", ";FT0A amplitude;Events", kTH1F, {axisFT0AAmp}); + registry.add("FT0MAmp", ";FT0M amplitude;Events", kTH1F, {axisFT0MAmp}); + + // ZDC plots + const AxisSpec axisEvent{3, 0., +3.0, ""}; + registry.add("hEventCounterForZDC", "Event counter", kTH1F, {axisEvent}); + registry.add("ZNAcoll", "ZNAcoll; ZNA amplitude; Entries", {HistType::kTH1F, {{nBinsAmp, -0.5, maxZN}}}); + registry.add("ZPAcoll", "ZPAcoll; ZPA amplitude; Entries", {HistType::kTH1F, {{nBinsAmp, -0.5, maxZP}}}); + registry.add("ZNCcoll", "ZNCcoll; ZNC amplitude; Entries", {HistType::kTH1F, {{nBinsAmp, -0.5, maxZN}}}); + registry.add("ZPCcoll", "ZPCcoll; ZPC amplitude; Entries", {HistType::kTH1F, {{nBinsAmp, -0.5, maxZP}}}); + registry.add("ZNvsFT0correl", "ZNvsFT0correl; FT0 amplitude; ZN", {HistType::kTH2F, {{{nBinsFit, 0., maxMultFT0}, {nBinsAmp, -0.5, 2. * maxZN}}}}); + registry.add("ZDCAmp", "ZDC Amplitude; ZDC Amplitude; Events", {HistType::kTH1F, {{nBinsAmp, -0.5, maxZP}}}); + registry.add("ZNAmp", "ZNA+ZNC Amplitude; ZN Amplitude; Events", {HistType::kTH1F, {{nBinsAmp, -0.5, maxZN}}}); + registry.add("ZPAmp", "ZPA+ZPC Amplitude; ZP Amplitude; Events", {HistType::kTH1F, {{nBinsAmp, -0.5, maxZP}}}); + registry.add("ZNvsZEMcoll", "ZNvsZEMcoll; ZEM; ZDC energy (GeV)", {HistType::kTH2F, {{{nBinsAmp, -0.5, maxZEM}, {nBinsAmp, -0.5, 2. * maxZN}}}}); + registry.add("ZNvsZEMcoll05", "ZNvsZEMcoll; ZEM; ZDC energy (GeV)", {HistType::kTH2F, {{{nBinsAmp, -0.5, maxZEM}, {nBinsAmp, -0.5, 2. * maxZN}}}}); + registry.add("ZNvsZEMcoll510", "ZNvsZEMcoll; ZEM; ZDC energy (GeV)", {HistType::kTH2F, {{{nBinsAmp, -0.5, maxZEM}, {nBinsAmp, -0.5, 2. * maxZN}}}}); + registry.add("ZNvsZEMcoll1020", "ZNvsZEMcoll; ZEM; ZDC energy (GeV)", {HistType::kTH2F, {{{nBinsAmp, -0.5, maxZEM}, {nBinsAmp, -0.5, 2. * maxZN}}}}); + registry.add("ZNvsZEMcoll2030", "ZNvsZEMcoll; ZEM; ZDC energy (GeV)", {HistType::kTH2F, {{{nBinsAmp, -0.5, maxZEM}, {nBinsAmp, -0.5, 2. * maxZN}}}}); + registry.add("ZNvsZEMcollrest", "ZNvsZEMcoll; ZEM; ZDC energy (GeV)", {HistType::kTH2F, {{{nBinsAmp, -0.5, maxZEM}, {nBinsAmp, -0.5, 2. * maxZN}}}}); + + // Track plots + registry.add("Nch", "N_{ch} vs #Events;N_{ch};No. of Events", {HistType::kTH1D, {axisNch}}); + registry.add("Nch05", "N_{ch 0-5%} vs #Events;N_{ch 0-5%};No. of Events", {HistType::kTH1D, {axisNch}}); + registry.add("Events_per_Centrality_Bin", "Events_per_Centrality_Bin;Centrality FT0C;No. of Events", kTH1F, {axisCentrality}); + registry.add("Tracks_per_Centrality_Bin", "Tracks_per_Centrality_Bin;Centrality FT0C;No. of Tracks", kTH1F, {axisCentrality}); + registry.add("pt_Cen_GlobalOnly", "pt_Cen_Global;Centrality (%); p_{T} (GeV/c);", {HistType::kTH2D, {axisCentrality, axisPt}}); + registry.add("phi_Cen_GlobalOnly", "phi_Cen_Global;Centrality (%); #phi;", {HistType::kTH2D, {axisCentrality, axisPhi}}); + registry.add("pt_Cen_ITSOnly", "pt_Cen_ITS;Centrality (%); p_{T} (GeV/c);", {HistType::kTH2D, {axisCentrality, axisPt}}); + registry.add("phi_Cen_ITSOnly", "phi_Cen_ITS;Centrality (%); #phi;", {HistType::kTH2D, {axisCentrality, axisPhi}}); + + // Track types + registry.add("GlobalplusITS", "Global plus ITS;Centrality FT0C;Nch", {HistType::kTH2D, {axisCentrality, axisNch}}); + registry.add("Globalonly", "Global only;Centrality FT0C;Nch", {HistType::kTH2D, {axisCentrality, axisNch}}); + registry.add("ITSonly", "ITS only;Centrality FT0C;Nch", {HistType::kTH2D, {axisCentrality, axisNch}}); + + // Track QA + registry.add("hPt", "p_{T} distribution before cut", {HistType::kTH1D, {axisPtHist}}); + registry.add("hPtRef", "p_{T} distribution after cut", {HistType::kTH1D, {axisPtHist}}); + registry.add("pt_phi_bef", "before cut;p_{T};#phi_{modn}", {HistType::kTH2D, {axisPt, axisPhiMod}}); + registry.add("pt_phi_aft", "after cut;p_{T};#phi_{modn}", {HistType::kTH2D, {axisPt, axisPhiMod}}); + registry.add("hChi2prTPCcls", "#chi^{2}/cluster for the TPC track segment", {HistType::kTH1D, {{100, 0., 5.}}}); + registry.add("hnTPCClu", "Number of found TPC clusters", {HistType::kTH1D, {{100, 40, 180}}}); + registry.add("hnTPCCrossedRow", "Number of crossed TPC Rows", {HistType::kTH1D, {{100, 40, 180}}}); + registry.add("hDCAz", "DCAz after cuts", {HistType::kTH1D, {{100, -3, 3}}}); + registry.add("hDCAxy", "DCAxy after cuts; DCAxy (cm); Pt", {HistType::kTH2D, {{50, -1, 1}, {50, 0, 10}}}); + + // Additional Output histograms + registry.add("c22", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisCentrality}}); + registry.add("c24", ";Centrality (%) ; C_{2}{4}", {HistType::kTProfile, {axisCentrality}}); + registry.add("c26", ";Centrality (%) ; C_{2}{6}", {HistType::kTProfile, {axisCentrality}}); + registry.add("c28", ";Centrality (%) ; C_{2}{8}", {HistType::kTProfile, {axisCentrality}}); + registry.add("c22etagap", ";Centrality (%) ; C_{2}{2} (|#eta| < 0.8) ", {HistType::kTProfile, {axisCentrality}}); + registry.add("c32", ";Centrality (%) ; C_{3}{2} ", {HistType::kTProfile, {axisCentrality}}); + registry.add("c32etagap", ";Centrality (%) ; C_{3}{2} (|#eta| < 0.8) ", {HistType::kTProfile, {axisCentrality}}); + registry.add("c34", ";Centrality (%) ; C_{3}{4} ", {HistType::kTProfile, {axisCentrality}}); + + registry.add("c22Nch", ";N_{ch}(|#eta| < 0.8) ; C_{2}{2} ", {HistType::kTProfile, {axisNch}}); + registry.add("c24Nch", ";N_{ch}(|#eta| < 0.8) ; C_{2}{4}", {HistType::kTProfile, {axisNch}}); + registry.add("c26Nch", ";N_{ch}(|#eta| < 0.8) ; C_{2}{6}", {HistType::kTProfile, {axisNch}}); + registry.add("c28Nch", ";N_{ch}(|#eta| < 0.8) ; C_{2}{8}", {HistType::kTProfile, {axisNch}}); + registry.add("c22Nchetagap", ";N_ch(|#eta| < 0.8) ; C_{2}{2} (|#eta| < 0.8) ", {HistType::kTProfile, {axisNch}}); + registry.add("c32Nch", ";N_{ch}(|#eta| < 0.8) ; C_{3}{2} ", {HistType::kTProfile, {axisNch}}); + registry.add("c32Nchetagap", ";N_ch(|#eta| < 0.8) ; C_{3}{2} (|#eta| < 0.8) ", {HistType::kTProfile, {axisNch}}); + registry.add("c34Nch", ";N_{ch}(|#eta| < 0.8) ; C_{3}{4} ", {HistType::kTProfile, {axisNch}}); + + registry.add("c22Nch05", ";N_{ch 0-5%}(|#eta| < 0.8) ; C_{2}{2} ", {HistType::kTProfile, {axisNch}}); + registry.add("c24Nch05", ";N_{ch 0-5%}(|#eta| < 0.8) ; C_{2}{4}", {HistType::kTProfile, {axisNch}}); + registry.add("c26Nch05", ";N_{ch 0-5%}(|#eta| < 0.8) ; C_{2}{6}", {HistType::kTProfile, {axisNch}}); + registry.add("c28Nch05", ";N_{ch 0-5%}(|#eta| < 0.8) ; C_{2}{8}", {HistType::kTProfile, {axisNch}}); + registry.add("c22Nch05etagap", ";N_{ch 0-5%}(|#eta| < 0.8) ; C_{2}{2} (|#eta| < 0.8) ", {HistType::kTProfile, {axisNch}}); + registry.add("c32Nch05", ";N_{ch 0-5%}(|#eta| < 0.8) ; C_{3}{2} ", {HistType::kTProfile, {axisNch}}); + registry.add("c32Nch05etagap", ";N_{ch 0-5%}(|#eta| < 0.8) ; C_{3}{2} (|#eta| < 0.8) ", {HistType::kTProfile, {axisNch}}); + registry.add("c34Nch05", ";N_{ch 0-5%}(|#eta| < 0.8) ; C_{3}{4} ", {HistType::kTProfile, {axisNch}}); + } // End doprocessData + + const AxisSpec axisZpos{48, -12., 12., "Vtx_{z} (cm)"}; + const AxisSpec axisEvent{3, 0, 3, ""}; + // MC Histograms + if (doprocesspTEff) { + registry.add("hEventCounterMCRec", "Event counter", kTH1F, {axisEvent}); + registry.add("zPos", ";;Entries;", kTH1F, {axisZpos}); + registry.add("T0Ccent", ";;Entries", kTH1F, {axisCentrality}); + registry.add("nRecColvsCent", "", kTH2F, {{6, -0.5, 5.5}, {{axisCentrality}}}); + registry.add("Pt_all_ch", "", kTH2F, {{axisCentrality}, {axisPt}}); + registry.add("Pt_ch", "", kTH2F, {{axisCentrality}, {axisPt}}); + registry.add("hPtMCRec", "Monte Carlo Reco; pT (GeV/c)", {HistType::kTH1D, {axisPt}}); + registry.add("hCenMCRec", "Monte Carlo Reco; Centrality (%)", {HistType::kTH1D, {axisCentrality}}); + registry.add("hPtNchMCRec", "Reco production; pT (GeV/c); Multiplicity", {HistType::kTH2D, {axisPt, axisNch}}); + registry.add("hPtMCRec05", "Monte Carlo Reco 0-5%; pT (GeV/c)", {HistType::kTH1D, {axisPt}}); + registry.add("hCenMCRec05", "Monte Carlo Reco 0-5%; Centrality (%)", {HistType::kTH1D, {axisCentrality}}); + registry.add("hPtNchMCRec05", "Reco production 0-5%; pT (GeV/c); Multiplicity", {HistType::kTH2D, {axisPt, axisNch}}); + registry.add("Pt_pi", "", kTH2F, {{axisCentrality}, {axisPt}}); + registry.add("Pt_ka", "", kTH2F, {{axisCentrality}, {axisPt}}); + registry.add("Pt_pr", "", kTH2F, {{axisCentrality}, {axisPt}}); + registry.add("Pt_sigpos", "", kTH2F, {{axisCentrality}, {axisPt}}); + registry.add("Pt_signeg", "", kTH2F, {{axisCentrality}, {axisPt}}); + registry.add("Pt_re", "", kTH2F, {{axisCentrality}, {axisPt}}); + registry.add("EtaVsPhi", ";;#varphi;", kTH2F, + {{{axisEta}, {100, -0.1 * o2::constants::math::PI, +2.1 * o2::constants::math::PI}}}); + registry.add("hEventCounterMCGen", "Event counter", kTH1F, {axisEvent}); + registry.add("zPosMC", ";;Entries;", kTH1F, {axisZpos}); + registry.add("PtMC_ch", "", kTH2F, {{axisCentrality}, {axisPt}}); + registry.add("hPtMCGen", "Monte Carlo Truth; pT (GeV/c)", {HistType::kTH1D, {axisPt}}); + registry.add("hCenMCGen", "Monte Carlo Truth; Centrality (%)", {HistType::kTH1D, {axisCentrality}}); + registry.add("hPtNchMCGen", "Truth production; pT (GeV/c); multiplicity", {HistType::kTH2D, {axisPt, axisNch}}); + registry.add("hPtMCGen05", "Monte Carlo Truth 0-5%; pT (GeV/c)", {HistType::kTH1D, {axisPt}}); + registry.add("hCenMCGen05", "Monte Carlo Truth 0-5%; Centrality (%)", {HistType::kTH1D, {axisCentrality}}); + registry.add("hPtNchMCGen05", "Truth production 0-5%; pT (GeV/c); multiplicity", {HistType::kTH2D, {axisPt, axisNch}}); + + registry.add("hCorr", "Correlation Matrix; N_{ch True}; N_{ch Reco}", {HistType::kTH2D, {axisNch, axisNch}}); + registry.add("hCorr05", "Correlation Matrix 0-5%; N_{ch True}; N_{ch Reco}", {HistType::kTH2D, {axisNch, axisNch}}); + + registry.add("PtMC_pi", "", kTH2F, {{axisCentrality}, {axisPt}}); + registry.add("PtMC_ka", "", kTH2F, {{axisCentrality}, {axisPt}}); + registry.add("PtMC_pr", "", kTH2F, {{axisCentrality}, {axisPt}}); + registry.add("PtMC_sigpos", "", kTH2F, {{axisCentrality}, {axisPt}}); + registry.add("PtMC_signeg", "", kTH2F, {{axisCentrality}, {axisPt}}); + registry.add("PtMC_re", "", kTH2F, {{axisCentrality}, {axisPt}}); + } + + // initial array + bootstrapArray.resize(cfgNbootstrap); + for (int i = 0; i < cfgNbootstrap; i++) { + bootstrapArray[i].resize(kCount_ExtraProfile); + } + + for (int i = 0; i < cfgNbootstrap; i++) { + bootstrapArray[i][kc22] = registry.add(Form("BootstrapContainer_%d/c22", i), ";Centrality (%) ; C_{2}{2}", {HistType::kTProfile, {axisCentrality}}); + bootstrapArray[i][kc24] = registry.add(Form("BootstrapContainer_%d/c24", i), ";Centrality (%) ; C_{2}{4}", {HistType::kTProfile, {axisCentrality}}); + bootstrapArray[i][kc26] = registry.add(Form("BootstrapContainer_%d/c26", i), ";Centrality (%) ; C_{2}{6}", {HistType::kTProfile, {axisCentrality}}); + bootstrapArray[i][kc28] = registry.add(Form("BootstrapContainer_%d/c28", i), ";Centrality (%) ; C_{2}{8}", {HistType::kTProfile, {axisCentrality}}); + bootstrapArray[i][kc22etagap] = registry.add(Form("BootstrapContainer_%d/c22etagap", i), ";Centrality (%) ; C_{2}{2} (|#eta| < 0.8)", {HistType::kTProfile, {axisCentrality}}); + bootstrapArray[i][kc32] = registry.add(Form("BootstrapContainer_%d/c32", i), ";Centrality (%) ; C_{3}{2}", {HistType::kTProfile, {axisCentrality}}); + bootstrapArray[i][kc32etagap] = registry.add(Form("BootstrapContainer_%d/c32etagap", i), ";Centrality (%) ; C_{3}{2} (|#eta| < 0.8)", {HistType::kTProfile, {axisCentrality}}); + bootstrapArray[i][kc34] = registry.add(Form("BootstrapContainer_%d/c34", i), ";Centrality (%) ; C_{3}{4}", {HistType::kTProfile, {axisCentrality}}); + + bootstrapArray[i][kc22Nch] = registry.add(Form("BootstrapContainer_%d/c22Nch", i), ";N_ch(|#eta| < 0.8) ; C_{2}{2}", {HistType::kTProfile, {axisNch}}); + bootstrapArray[i][kc24Nch] = registry.add(Form("BootstrapContainer_%d/c24Nch", i), ";N_ch(|#eta| < 0.8) ; C_{2}{4}", {HistType::kTProfile, {axisNch}}); + bootstrapArray[i][kc26Nch] = registry.add(Form("BootstrapContainer_%d/c26Nch", i), ";N_ch(|#eta| < 0.8) ; C_{2}{6}", {HistType::kTProfile, {axisNch}}); + bootstrapArray[i][kc28Nch] = registry.add(Form("BootstrapContainer_%d/c28Nch", i), ";N_ch(|#eta| < 0.8) ; C_{2}{8}", {HistType::kTProfile, {axisNch}}); + bootstrapArray[i][kc22Nchetagap] = registry.add(Form("BootstrapContainer_%d/c22Nchetagap", i), ";N_ch(|#eta| < 0.8) ; C_{2}{2} (|#eta| < 0.8)", {HistType::kTProfile, {axisNch}}); + bootstrapArray[i][kc32Nch] = registry.add(Form("BootstrapContainer_%d/c32Nch", i), ";N_ch(|#eta| < 0.8) ; C_{3}{2}", {HistType::kTProfile, {axisNch}}); + bootstrapArray[i][kc32Nchetagap] = registry.add(Form("BootstrapContainer_%d/c32Nchetagap", i), ";N_ch(|#eta| < 0.8) ; C_{3}{2} (|#eta| < 0.8)", {HistType::kTProfile, {axisNch}}); + bootstrapArray[i][kc34Nch] = registry.add(Form("BootstrapContainer_%d/c34Nch", i), ";N_ch(|#eta| < 0.8) ; C_{3}{4}", {HistType::kTProfile, {axisNch}}); + + bootstrapArray[i][kc22Nch05] = registry.add(Form("BootstrapContainer_%d/c22Nch05", i), ";N_ch05(|#eta| < 0.8) ; C_{2}{2}", {HistType::kTProfile, {axisNch}}); + bootstrapArray[i][kc24Nch05] = registry.add(Form("BootstrapContainer_%d/c24Nch05", i), ";N_ch05(|#eta| < 0.8) ; C_{2}{4}", {HistType::kTProfile, {axisNch}}); + bootstrapArray[i][kc26Nch05] = registry.add(Form("BootstrapContainer_%d/c26Nch05", i), ";N_ch05(|#eta| < 0.8) ; C_{2}{6}", {HistType::kTProfile, {axisNch}}); + bootstrapArray[i][kc28Nch05] = registry.add(Form("BootstrapContainer_%d/c28Nch05", i), ";N_ch05(|#eta| < 0.8) ; C_{2}{8}", {HistType::kTProfile, {axisNch}}); + bootstrapArray[i][kc22Nch05etagap] = registry.add(Form("BootstrapContainer_%d/c22Nch05etagap", i), ";N_ch05(|#eta| < 0.8) ; C_{2}{2} (|#eta| < 0.8)", {HistType::kTProfile, {axisNch}}); + bootstrapArray[i][kc32Nch05] = registry.add(Form("BootstrapContainer_%d/c32Nch05", i), ";N_ch05(|#eta| < 0.8) ; C_{3}{2}", {HistType::kTProfile, {axisNch}}); + bootstrapArray[i][kc32Nch05etagap] = registry.add(Form("BootstrapContainer_%d/c32Nch05etagap", i), ";N_ch05(|#eta| < 0.8) ; C_{3}{2} (|#eta| < 0.8)", {HistType::kTProfile, {axisNch}}); + bootstrapArray[i][kc34Nch05] = registry.add(Form("BootstrapContainer_%d/c34Nch05", i), ";N_ch05(|#eta| < 0.8) ; C_{3}{4}", {HistType::kTProfile, {axisNch}}); + } + + o2::framework::AxisSpec axis = axisPt; + int nPtBins = axis.binEdges.size() - 1; + double* ptBins = &(axis.binEdges)[0]; + fPtAxis = new TAxis(nPtBins, ptBins); + + if (cfgOutputNUAWeights) { + fWeights->setPtBins(nPtBins, ptBins); + fWeights->init(true, false); + } + + // add in FlowContainer to Get boostrap sample automatically -- Use post process flow task + TObjArray* oba = new TObjArray(); + fFC->SetXAxis(fPtAxis); + fFC->SetName("FlowContainer"); + fFC->Initialize(oba, axisCentrality, cfgNbootstrap); + delete oba; + + fGFW->AddRegion("full", -0.8, 0.8, 1, 1); // eta region -0.8 to 0.8 + fGFW->AddRegion("refN10", -0.8, -0.5, 1, 1); + fGFW->AddRegion("refP10", 0.5, 0.8, 1, 1); + + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 2 -2 -2}", "ChFull24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 2 2 -2 -2 -2}", "ChFull26", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 2 2 2 -2 -2 -2 -2}", "ChFull28", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {2} refP10 {-2}", "Ch10Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {3 -3}", "ChFull32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {3} refP10 {-3}", "Ch10Gap32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {3 3 -3 -3}", "ChFull34", kFALSE)); + fGFW->CreateRegions(); // finalize the initialization + + if (cfgUseAdditionalEventCut) { + fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x - 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); + fMultPVCutLow->SetParameters(3257.29, -121.848, 1.98492, -0.0172128, 6.47528e-05, 154.756, -1.86072, -0.0274713, 0.000633499, -3.37757e-06); + fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x + 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); + fMultPVCutHigh->SetParameters(3257.29, -121.848, 1.98492, -0.0172128, 6.47528e-05, 154.756, -1.86072, -0.0274713, 0.000633499, -3.37757e-06); + + fMultCutLow = new TF1("fMultCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultCutLow->SetParameters(1654.46, -47.2379, 0.449833, -0.0014125, 150.773, -3.67334, 0.0530503, -0.000614061, 3.15956e-06); + fMultCutHigh = new TF1("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 3.*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultCutHigh->SetParameters(1654.46, -47.2379, 0.449833, -0.0014125, 150.773, -3.67334, 0.0530503, -0.000614061, 3.15956e-06); + + fT0AV0AMean = new TF1("fT0AV0AMean", "[0]+[1]*x", 0, 200000); + fT0AV0AMean->SetParameters(-1601.0581, 9.417652e-01); + fT0AV0ASigma = new TF1("fT0AV0ASigma", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 200000); + fT0AV0ASigma->SetParameters(463.4144, 6.796509e-02, -9.097136e-07, 7.971088e-12, -2.600581e-17); + } + + if (cfgUseAdditionalTrackCut) { + fPhiCutLow = new TF1("fPhiCutLow", "0.06/x+pi/18.0-0.06", 0, 100); + fPhiCutHigh = new TF1("fPhiCutHigh", "0.1/x+pi/18.0+0.06", 0, 100); + } + + if (cfgTrackSelRun3ITSMatch) { + myTrackSel = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSall7Layers, TrackSelection::GlobalTrackRun3DCAxyCut::Default); + } else { + myTrackSel = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::Default); + } + + myTrackSel.SetMinNClustersTPC(cfgCutTPCclu); + myTrackSel.SetMinNClustersITS(cfgCutITSclu); + + } // end of Initialization + + template + void fillProfile(const GFW::CorrConfig& corrconf, const ConstStr& tarName, const double& cent) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) + return; + if (!corrconf.pTDif) { + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::abs(val) < 1) + registry.fill(tarName, cent, val, dnx); + return; + } + return; + } + + void fillProfile(const GFW::CorrConfig& corrconf, std::shared_ptr tarName, const double& cent) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) + return; + if (!corrconf.pTDif) { + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::abs(val) < 1) { + tarName->Fill(cent, val, dnx); + } + return; + } + return; + } + + void fillFC(const GFW::CorrConfig& corrconf, const double& cent, const double& rndm) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) + return; + if (!corrconf.pTDif) { + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::abs(val) < 1) + fFC->FillProfile(corrconf.Head.c_str(), cent, val, dnx, rndm); + return; + } + for (int i = 1; i <= fPtAxis->GetNbins(); i++) { + dnx = fGFW->Calculate(corrconf, i - 1, kTRUE).real(); + if (dnx == 0) + continue; + val = fGFW->Calculate(corrconf, i - 1, kFALSE).real() / dnx; + if (std::abs(val) < 1) + fFC->FillProfile(Form("%s_pt_%i", corrconf.Head.c_str(), i), cent, val, dnx, rndm); + } + return; + } + + void loadCorrections(uint64_t timestamp) + { + if (correctionsLoaded) + return; + if (cfgAcceptance.value.empty() == false) { + mAcceptance = ccdb->getForTimeStamp(cfgAcceptance, timestamp); + if (mAcceptance) + LOGF(info, "Loaded acceptance weights from %s (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance); + else + LOGF(warning, "Could not load acceptance weights from %s (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance); + } + if (cfgEfficiency.value.empty() == false) { + mEfficiency = ccdb->getForTimeStamp(cfgEfficiency, timestamp); + if (mEfficiency == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgEfficiency.value.c_str()); + } + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgEfficiency.value.c_str(), (void*)mEfficiency); + } + + if (cfgEfficiencyNch.value.empty() == false) { + mEfficiencyNch = ccdb->getForTimeStamp(cfgEfficiencyNch, timestamp); + if (mEfficiencyNch == nullptr) { + LOGF(fatal, "Could not load Nch efficiency histogram for trigger particles from %s", cfgEfficiencyNch.value.c_str()); + } + LOGF(info, "Loaded Nch efficiency histogram from %s (%p)", cfgEfficiencyNch.value.c_str(), (void*)mEfficiencyNch); + } + + correctionsLoaded = true; + } + + bool setCurrentParticleWeights(float& weight_nue, float& weight_nua, float phi, float eta, float pt, float vtxz) + { + float eff = 1.; + if (mEfficiency) + eff = mEfficiency->GetBinContent(mEfficiency->FindBin(pt)); + else + eff = 1.0; + if (eff == 0) + return false; + weight_nue = 1. / eff; + if (mAcceptance) + weight_nua = mAcceptance->getNUA(phi, eta, vtxz); + else + weight_nua = 1; + return true; + } + + bool setNch(float& weight_nueNch, float nch) + { + float effNch = 1.; + if (mEfficiencyNch) + effNch = mEfficiencyNch->GetBinContent(mEfficiencyNch->FindBin(nch)); + else + effNch = 1.0; + if (effNch == 0.0) + return false; + weight_nueNch = 1. / effNch; + return true; + } + + template + bool eventSelected(o2::aod::mult::MultNTracksPV, TCollision collision, const int multTrk, const float centrality) + { + if (cfgNoTimeFrameBorder) { + if (!collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + // reject collisions close to Time Frame borders + // https://its.cern.ch/jira/browse/O2-4623 + return false; + } + registry.fill(HIST("hEventCount"), kNOTIMEFRAMEBORDER); + } + if (cfgNoITSROFrameBorder) { + if (!collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + // reject events affected by the ITS ROF border + // https://its.cern.ch/jira/browse/O2-4309 + return false; + } + registry.fill(HIST("hEventCount"), kNOITSROFRAMEBORDER); + } + if (cfgNoSameBunchPileup) { + if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + // rejects collisions which are associated with the same "found-by-T0" bunch crossing + // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof + return false; + } + registry.fill(HIST("hEventCount"), kNOPSAMEBUNCHPILEUP); + } + if (cfgIsGoodZvtxFT0vsPV) { + if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference + // use this cut at low multiplicities with caution + return false; + } + registry.fill(HIST("hEventCount"), kISGOODZVTXFT0VSPV); + } + if (cfgIsVertexITSTPC) { + if (!collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + // removes collisions without vertex match between ITS-TPC + return false; + } + registry.fill(HIST("hEventCount"), kISVERTEXITSTPC); + } + if (cfgNoCollInTimeRangeStandard) { + if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // no collisions in specified time range + return false; + } + registry.fill(HIST("hEventCount"), kNOCOLLINTIMERANGESTANDART); + } + if (cfgEvSelkIsGoodITSLayersAll) { + if (cfgEvSelkIsGoodITSLayersAll && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + // removes dead staves of ITS + return false; + } + registry.fill(HIST("hEventCount"), kISGOODITSLAYERSALL); + } + + float vtxz = -999; + if (collision.numContrib() > 1) { + vtxz = collision.posZ(); + float zRes = std::sqrt(collision.covZZ()); + if (zRes > 0.25 && collision.numContrib() < 20) + vtxz = -999; + } + + auto multNTracksPV = collision.multNTracksPV(); + + if (std::abs(vtxz) > cfgCutVertex) + return false; + + if (cfgMultCut) { + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) + return false; + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) + return false; + if (multTrk < fMultCutLow->Eval(centrality)) + return false; + if (multTrk > fMultCutHigh->Eval(centrality)) + return false; + registry.fill(HIST("hEventCount"), kAFTERMULTCUTS); + } + + // V0A T0A 5 sigma cut + if (cfgV0AT0A5Sigma) { + if (std::abs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > 5 * fT0AV0ASigma->Eval(collision.multFT0A())) + return false; + } + + return true; + } + + int getMagneticField(uint64_t timestamp) + { + static o2::parameters::GRPMagField* grpo = nullptr; + if (grpo == nullptr) { + grpo = ccdb->getForTimeStamp(cfgMagnetField, timestamp); + if (grpo == nullptr) { + LOGF(fatal, "GRP object not found in %s for timestamp %llu", cfgMagnetField.value.c_str(), timestamp); + return 0; + } + LOGF(info, "Retrieved GRP from %s for timestamp %llu with magnetic field of %d kG", cfgMagnetField.value.c_str(), timestamp, grpo->getNominalL3Field()); + } + return grpo->getNominalL3Field(); + } + + template + bool trackSelected(TTrack track, const int field) + { + double phimodn = track.phi(); + if (field < 0) // for negative polarity field + phimodn = o2::constants::math::TwoPI - phimodn; + if (track.sign() < 0) // for negative charge + phimodn = o2::constants::math::TwoPI - phimodn; + if (phimodn < 0) + LOGF(warning, "phi < 0: %g", phimodn); + + phimodn += o2::constants::math::PI / 18.0; // to center gap in the middle + phimodn = fmod(phimodn, o2::constants::math::PI / 9.0); + registry.fill(HIST("pt_phi_bef"), track.pt(), phimodn); + if (phimodn < fPhiCutHigh->Eval(track.pt()) && phimodn > fPhiCutLow->Eval(track.pt())) + return false; // reject track + registry.fill(HIST("pt_phi_aft"), track.pt(), phimodn); + return true; + } + + template + bool trackSelected(TTrack track) + { + if (cfgDCAzPt && (std::fabs(track.dcaZ()) > (0.004f + 0.013f / track.pt()))) + return false; + + if (cfgTrackSel) { + return myTrackSel.IsSelected(track); + } else if (cfgGlobalplusITS) { + return ((track.tpcNClsFound() >= cfgCutTPCclu) || (track.itsNCls() >= cfgCutITSclu)); + } else if (cfgGlobalonly) { + return ((track.tpcNClsFound() >= cfgCutTPCclu) && (track.itsNCls() >= cfgCutITSclu)); + } else if (cfgITSonly) { + return ((track.itsNCls() >= cfgCutITSclu)); + } else { + return false; + } + } + + // Apply process filters + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex && (aod::cent::centFT0C > cfgMinCentFT0C) && (aod::cent::centFT0C < cfgMaxCentFT0C); + Filter trackFilter = ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) && + ncheckbit(aod::track::trackCutFlag, TrackSelectionITS) && + ifnode(ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC), + ncheckbit(aod::track::trackCutFlag, TrackSelectionTPC), true) && + ifnode(dcaZ > 0.f, nabs(aod::track::dcaZ) <= dcaZ && ncheckbit(aod::track::trackCutFlag, TrackSelectionDCAXYonly), + ncheckbit(aod::track::trackCutFlag, TrackSelectionDCA)) && + (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtMin) && (aod::track::pt < cfgCutPtMax) && (aod::track::tpcChi2NCl < cfgCutChi2prTPCcls); + + void processData(Colls::iterator const& collision, aod::BCsWithTimestamps const&, AodTracks const& tracks, aod::FT0s const&, aod::Zdcs const&, BCsRun3 const&) + { + registry.fill(HIST("hEventCount"), kFILTERED); + if (!collision.sel8()) + return; + + if (tracks.size() < 1) + return; + + registry.fill(HIST("hEventCount"), kSEL8); + + // Choose centrality estimator -- Only one can be true + auto centrality = -1; + if (cfgcentEstFt0c) { + centrality = collision.centFT0C(); + registry.fill(HIST("hCentEstimators"), kCentFT0C); + registry.fill(HIST("hCentFT0C"), centrality); + } + if (cfgcentEstFt0a) { + centrality = collision.centFT0A(); + registry.fill(HIST("hCentEstimators"), kCentFT0A); + registry.fill(HIST("hCentFT0A"), centrality); + } + if (cfgcentEstFt0m) { + centrality = collision.centFT0M(); + registry.fill(HIST("hCentEstimators"), kCentFT0M); + registry.fill(HIST("hCentFT0M"), centrality); + } + if (cfgcentEstFv0a) { + centrality = collision.centFV0A(); + registry.fill(HIST("hCentEstimators"), kCentFV0A); + registry.fill(HIST("hCentFV0A"), centrality); + } + if (cfgcentEstFt0cVariant1) { + centrality = collision.centFT0CVariant1(); + registry.fill(HIST("hCentEstimators"), kCentFT0CVariant1); + registry.fill(HIST("hCentFT0CVariant1"), centrality); + } + + // fill event QA before cuts + registry.fill(HIST("BeforeCut_globalTracks_centT0C"), collision.centFT0C(), tracks.size()); + registry.fill(HIST("BeforeCut_PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV()); + registry.fill(HIST("BeforeCut_globalTracks_PVTracks"), collision.multNTracksPV(), tracks.size()); + registry.fill(HIST("BeforeCut_globalTracks_multT0A"), collision.multFT0A(), tracks.size()); + registry.fill(HIST("BeforeCut_globalTracks_multV0A"), collision.multFV0A(), tracks.size()); + registry.fill(HIST("BeforeCut_multV0A_multT0A"), collision.multFT0A(), collision.multFV0A()); + registry.fill(HIST("BeforeCut_multT0C_centT0C"), collision.centFT0C(), collision.multFT0C()); + registry.fill(HIST("BeforeCut_multT0A_centT0A"), collision.centFT0A(), collision.multFT0A()); + registry.fill(HIST("BeforeCut_multFT0M_centFT0M"), collision.centFT0M(), collision.multFT0M()); + + if (cfgOccupancy) { + int occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh) + return; + registry.fill(HIST("hEventCount"), kOCCUPANCY); + } + + if (cfgUseAdditionalEventCut && !eventSelected(o2::aod::mult::MultNTracksPV(), collision, tracks.size(), centrality)) { + return; + } + + const auto& foundBC = collision.foundBC_as(); + if (foundBC.has_zdc()) { + registry.fill(HIST("hEventCounterForZDC"), 1); + + // FT0 amplitude to use in fine binning + double ft0aAmp = 0; + double ft0cAmp = 0; + double ft0mAmp = 0; + + if (foundBC.has_ft0()) { + for (const auto& amplitude : foundBC.ft0().amplitudeA()) { + ft0aAmp += amplitude; + } + for (const auto& amplitude : foundBC.ft0().amplitudeC()) { + ft0cAmp += amplitude; + } + } else { + ft0aAmp = ft0cAmp = -999; + } + + registry.fill(HIST("FT0AAmp"), ft0aAmp); + registry.fill(HIST("FT0CAmp"), ft0cAmp); + + ft0mAmp = ft0aAmp + ft0cAmp; + registry.fill(HIST("FT0MAmp"), ft0mAmp); + + // ZDC amplitude to use in fine binning + const auto& zdcread = foundBC.zdc(); + auto aZNA = zdcread.amplitudeZNA(); + auto aZNC = zdcread.amplitudeZNC(); + auto aZPA = zdcread.amplitudeZPA(); + auto aZPC = zdcread.amplitudeZPC(); + auto aZEM1 = zdcread.amplitudeZEM1(); + auto aZEM2 = zdcread.amplitudeZEM2(); + + registry.fill(HIST("ZNAcoll"), aZNA); + registry.fill(HIST("ZNCcoll"), aZNC); + registry.fill(HIST("ZPAcoll"), aZPA); + registry.fill(HIST("ZPCcoll"), aZPC); + + registry.fill(HIST("ZNvsFT0correl"), (ft0aAmp + ft0cAmp) / 100., aZNC + aZNA); + + double aZDC = aZNC + aZNA + aZPA + aZPC; + registry.fill(HIST("ZDCAmp"), aZDC); + registry.fill(HIST("ZNAmp"), aZNC + aZNA); + registry.fill(HIST("ZPAmp"), aZPA + aZPC); + + registry.fill(HIST("ZNvsZEMcoll"), aZEM1 + aZEM2, aZNA + aZNC); + + if (centrality >= 0 && centrality <= 5) { + registry.fill(HIST("ZNvsZEMcoll05"), aZEM1 + aZEM2, aZNA + aZNC); + } else if (centrality > 5 && centrality <= 10) { + registry.fill(HIST("ZNvsZEMcoll510"), aZEM1 + aZEM2, aZNA + aZNC); + } else if (centrality > 10 && centrality <= 20) { + registry.fill(HIST("ZNvsZEMcoll1020"), aZEM1 + aZEM2, aZNA + aZNC); + } else if (centrality > 20 && centrality <= 30) { + registry.fill(HIST("ZNvsZEMcoll2030"), aZEM1 + aZEM2, aZNA + aZNC); + } else { + registry.fill(HIST("ZNvsZEMcollrest"), aZEM1 + aZEM2, aZNA + aZNC); + } + } // End of ZDC + + float vtxz = collision.posZ(); + float lRandom = fRndm->Rndm(); + registry.fill(HIST("hVtxZ"), vtxz); + registry.fill(HIST("hMult"), tracks.size()); + registry.fill(HIST("hCent"), centrality); + registry.fill(HIST("cent_vs_Nch"), centrality, tracks.size()); + + float weffNch = 1; + if (!setNch(weffNch, tracks.size())) + return; + + // Corrected nch + float nch = tracks.size() * weffNch; + registry.fill(HIST("hMultCorr"), nch); + registry.fill(HIST("cent_vs_NchCorr"), centrality, nch); + + fGFW->Clear(); + + auto bc = collision.bc_as(); + loadCorrections(bc.timestamp()); + registry.fill(HIST("hEventCount"), kCENTRALITY); + + // fill event QA after cuts + registry.fill(HIST("globalTracks_centT0C_Aft"), collision.centFT0C(), tracks.size()); + registry.fill(HIST("PVTracks_centT0C_Aft"), collision.centFT0C(), collision.multNTracksPV()); + registry.fill(HIST("globalTracks_PVTracks_Aft"), collision.multNTracksPV(), tracks.size()); + registry.fill(HIST("globalTracks_multT0A_Aft"), collision.multFT0A(), tracks.size()); + registry.fill(HIST("globalTracks_multV0A_Aft"), collision.multFV0A(), tracks.size()); + registry.fill(HIST("multV0A_multT0A_Aft"), collision.multFT0A(), collision.multFV0A()); + registry.fill(HIST("multT0C_centT0C_Aft"), collision.centFT0C(), collision.multFT0C()); + registry.fill(HIST("multT0A_centT0A_Aft"), collision.centFT0A(), collision.multFT0A()); + registry.fill(HIST("multFT0M_centFT0M_Aft"), collision.centFT0M(), collision.multFT0M()); + + // track weights + float weff = 1, wacc = 1; + int magnetfield = 0; + + if (cfgUseAdditionalTrackCut) { + // magnet field dependence cut + magnetfield = getMagneticField(bc.timestamp()); + } + + // track loop + + for (const auto& track : tracks) { + if (!trackSelected(track)) + continue; + + if (cfgUseAdditionalTrackCut && !trackSelected(track, magnetfield)) + continue; + + if (cfgOutputNUAWeights) + fWeights->fill(track.phi(), track.eta(), vtxz, track.pt(), centrality, 0); + + if (!setCurrentParticleWeights(weff, wacc, track.phi(), track.eta(), track.pt(), vtxz)) + continue; + + bool withinPtRef = (cfgCutPtMin < track.pt()) && (track.pt() < cfgCutPtMax); // within RF pT range + registry.fill(HIST("hPt"), track.pt()); + + if (withinPtRef) { + registry.fill(HIST("hPhi"), track.phi()); + registry.fill(HIST("hPhiWeighted"), track.phi(), wacc); + registry.fill(HIST("hEta"), track.eta()); + registry.fill(HIST("hPtRef"), track.pt()); + registry.fill(HIST("hChi2prTPCcls"), track.tpcChi2NCl()); + registry.fill(HIST("hnTPCClu"), track.tpcNClsFound()); + registry.fill(HIST("hnTPCCrossedRow"), track.tpcNClsCrossedRows()); + registry.fill(HIST("hDCAz"), track.dcaZ()); + registry.fill(HIST("hDCAxy"), track.dcaXY(), track.pt()); + } + + if (cfgGlobalplusITS) { + if (withinPtRef) { + registry.fill(HIST("GlobalplusITS"), centrality, nch); + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), wacc * weff, 1); + } + } + + if (track.hasTPC()) { + if (cfgGlobalonly) { + if (withinPtRef) { + registry.fill(HIST("Globalonly"), centrality, nch); + registry.fill(HIST("pt_Cen_GlobalOnly"), centrality, track.pt()); + registry.fill(HIST("phi_Cen_GlobalOnly"), centrality, track.phi()); + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), wacc * weff, 1); + } + } + } else { + if (cfgITSonly) { + if (withinPtRef) { + registry.fill(HIST("ITSonly"), centrality, nch); + registry.fill(HIST("pt_Cen_ITSOnly"), centrality, track.pt()); + registry.fill(HIST("phi_Cen_ITSOnly"), centrality, track.phi()); + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), wacc * weff, 1); + } + } + } + + if (cfgFineBinning) + fGFW->Fill(track.eta(), 1, track.phi(), wacc * weff, 1); + + } // End of track loop + + // Only one type of track will be plotted + registry.fill(HIST("Events_per_Centrality_Bin"), centrality); + registry.fill(HIST("Tracks_per_Centrality_Bin"), centrality, nch); + + // Filling c22 with ROOT TProfile + fillProfile(corrconfigs.at(0), HIST("c22"), centrality); + fillProfile(corrconfigs.at(1), HIST("c24"), centrality); + fillProfile(corrconfigs.at(2), HIST("c26"), centrality); + fillProfile(corrconfigs.at(3), HIST("c28"), centrality); + fillProfile(corrconfigs.at(4), HIST("c22etagap"), centrality); + fillProfile(corrconfigs.at(5), HIST("c32"), centrality); + fillProfile(corrconfigs.at(6), HIST("c32etagap"), centrality); + fillProfile(corrconfigs.at(7), HIST("c34"), centrality); + + fillProfile(corrconfigs.at(0), HIST("c22Nch"), nch); + fillProfile(corrconfigs.at(1), HIST("c24Nch"), nch); + fillProfile(corrconfigs.at(2), HIST("c26Nch"), nch); + fillProfile(corrconfigs.at(3), HIST("c28Nch"), nch); + fillProfile(corrconfigs.at(4), HIST("c22Nchetagap"), nch); + fillProfile(corrconfigs.at(5), HIST("c32Nch"), nch); + fillProfile(corrconfigs.at(6), HIST("c32Nchetagap"), nch); + fillProfile(corrconfigs.at(7), HIST("c34Nch"), nch); + + // 0-5% centrality Nch + if (centrality >= 0 && centrality <= 5) { + fillProfile(corrconfigs.at(0), HIST("c22Nch05"), nch); + fillProfile(corrconfigs.at(1), HIST("c24Nch05"), nch); + fillProfile(corrconfigs.at(2), HIST("c26Nch05"), nch); + fillProfile(corrconfigs.at(3), HIST("c28Nch05"), nch); + fillProfile(corrconfigs.at(4), HIST("c22Nch05etagap"), nch); + fillProfile(corrconfigs.at(5), HIST("c32Nch05"), nch); + fillProfile(corrconfigs.at(6), HIST("c32Nch05etagap"), nch); + fillProfile(corrconfigs.at(7), HIST("c34Nch05"), nch); + } + + // Filling Bootstrap Samples + int sampleIndex = static_cast(cfgNbootstrap * lRandom); + fillProfile(corrconfigs.at(0), bootstrapArray[sampleIndex][kc22], centrality); + fillProfile(corrconfigs.at(1), bootstrapArray[sampleIndex][kc24], centrality); + fillProfile(corrconfigs.at(2), bootstrapArray[sampleIndex][kc26], centrality); + fillProfile(corrconfigs.at(3), bootstrapArray[sampleIndex][kc28], centrality); + fillProfile(corrconfigs.at(4), bootstrapArray[sampleIndex][kc22etagap], centrality); + fillProfile(corrconfigs.at(5), bootstrapArray[sampleIndex][kc32], centrality); + fillProfile(corrconfigs.at(6), bootstrapArray[sampleIndex][kc32etagap], centrality); + fillProfile(corrconfigs.at(7), bootstrapArray[sampleIndex][kc34], centrality); + + fillProfile(corrconfigs.at(0), bootstrapArray[sampleIndex][kc22Nch], nch); + fillProfile(corrconfigs.at(1), bootstrapArray[sampleIndex][kc24Nch], nch); + fillProfile(corrconfigs.at(2), bootstrapArray[sampleIndex][kc26Nch], nch); + fillProfile(corrconfigs.at(3), bootstrapArray[sampleIndex][kc28Nch], nch); + fillProfile(corrconfigs.at(4), bootstrapArray[sampleIndex][kc22Nchetagap], nch); + fillProfile(corrconfigs.at(5), bootstrapArray[sampleIndex][kc32Nch], nch); + fillProfile(corrconfigs.at(6), bootstrapArray[sampleIndex][kc32Nchetagap], nch); + fillProfile(corrconfigs.at(7), bootstrapArray[sampleIndex][kc34Nch], nch); + + if (centrality >= 0 && centrality <= 5) { + fillProfile(corrconfigs.at(0), bootstrapArray[sampleIndex][kc22Nch05], nch); + fillProfile(corrconfigs.at(1), bootstrapArray[sampleIndex][kc24Nch05], nch); + fillProfile(corrconfigs.at(2), bootstrapArray[sampleIndex][kc26Nch05], nch); + fillProfile(corrconfigs.at(3), bootstrapArray[sampleIndex][kc28Nch05], nch); + fillProfile(corrconfigs.at(4), bootstrapArray[sampleIndex][kc22Nch05etagap], nch); + fillProfile(corrconfigs.at(5), bootstrapArray[sampleIndex][kc32Nch05], nch); + fillProfile(corrconfigs.at(6), bootstrapArray[sampleIndex][kc32Nch05etagap], nch); + fillProfile(corrconfigs.at(7), bootstrapArray[sampleIndex][kc34Nch05], nch); + + registry.fill(HIST("Nch05"), nch); + } + + registry.fill(HIST("Nch"), nch); + + // Filling Flow Container + for (uint l_ind = 0; l_ind < corrconfigs.size(); l_ind++) { + fillFC(corrconfigs.at(l_ind), centrality, lRandom); + } + + } // End of process + PROCESS_SWITCH(FlowGfwTask, processData, "Process analysis for Run 3 data", false); + + using TheFilteredMyTracks = soa::Filtered; + using TheFilteredMyCollisions = soa::Filtered; + + Preslice perMCCollision = aod::mcparticle::mcCollisionId; + Preslice perCollision = aod::track::collisionId; + void processpTEff(aod::McCollisions::iterator const& mccollision, + soa::SmallGroups const& collisions, + aod::McParticles const& mcParticles, + TheFilteredMyTracks const& tracks) + { + // MC reconstructed + for (const auto& collision : collisions) { + if (!collision.sel8()) + return; + + if (tracks.size() < 1) + return; + + const auto& centrality = collision.centFT0C(); + + if (cfgUseAdditionalEventCut && !eventSelected(o2::aod::mult::MultNTracksPV(), collision, tracks.size(), centrality)) { + return; + } + + if (!collision.has_mcCollision()) + continue; + + registry.fill(HIST("zPos"), collision.posZ()); + registry.fill(HIST("nRecColvsCent"), collisions.size(), collision.centFT0C()); + registry.fill(HIST("T0Ccent"), centrality); + + const auto& groupedTracksReco = tracks.sliceBy(perCollision, collision.globalIndex()); + for (const auto& track : groupedTracksReco) { + + if (!trackSelected(track)) + continue; + + if (!track.has_mcParticle()) + continue; + + const auto& particle = track.mcParticle(); + + if (isStable(particle.pdgCode())) { + + registry.fill(HIST("hEventCounterMCRec"), 0.5); + registry.fill(HIST("hPtMCRec"), track.pt()); + registry.fill(HIST("hCenMCRec"), centrality); + registry.fill(HIST("hPtNchMCRec"), track.pt(), track.size()); + + if (centrality >= 0 && centrality <= 5) { + registry.fill(HIST("hPtMCRec05"), track.pt()); + registry.fill(HIST("hCenMCRec05"), centrality); + registry.fill(HIST("hPtNchMCRec05"), track.pt(), track.size()); + } + } + + registry.fill(HIST("Pt_all_ch"), centrality, track.pt()); + registry.fill(HIST("EtaVsPhi"), track.eta(), track.phi()); + + if (!particle.isPhysicalPrimary()) + continue; + + registry.fill(HIST("Pt_ch"), centrality, track.pt()); + if (particle.pdgCode() == kPiPlus || + particle.pdgCode() == kPiMinus) { + registry.fill(HIST("Pt_pi"), centrality, track.pt()); + } else if (particle.pdgCode() == kKPlus || + particle.pdgCode() == kKMinus) { + registry.fill(HIST("Pt_ka"), centrality, track.pt()); + } else if (particle.pdgCode() == kProton || + particle.pdgCode() == kProtonBar) { + registry.fill(HIST("Pt_pr"), centrality, track.pt()); + } else if (particle.pdgCode() == kSigmaPlus || + particle.pdgCode() == kSigmaBarMinus) { + registry.fill(HIST("Pt_sigpos"), centrality, track.pt()); + } else if (particle.pdgCode() == kSigmaMinus || + particle.pdgCode() == kSigmaBarPlus) { + registry.fill(HIST("Pt_signeg"), centrality, track.pt()); + } else { + registry.fill(HIST("Pt_re"), centrality, track.pt()); + } + } + + // Generated MC + registry.fill(HIST("hEventCounterMCGen"), 0.5); + if (std::fabs(mccollision.posZ()) > cfgCutVertex) + continue; + registry.fill(HIST("zPosMC"), mccollision.posZ()); + registry.fill(HIST("hEventCounterMCGen"), 1.5); + + std::vector numberOfTracks; + for (auto const& collision : collisions) { + auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex()); + numberOfTracks.emplace_back(groupedTracks.size()); + } + + for (const auto& particle : mcParticles) { + if (particle.eta() < -cfgCutEta || particle.eta() > cfgCutEta) { + continue; + } + if (particle.pt() < cfgCutPtMin || particle.pt() > cfgCutPtMax) { + continue; + } + + if (!particle.isPhysicalPrimary()) { + continue; + } + + if (isStable(particle.pdgCode())) { + registry.fill(HIST("hEventCounterMCGen"), 2.5); + registry.fill(HIST("hPtMCGen"), particle.pt()); + registry.fill(HIST("hCenMCGen"), centrality); + + if (centrality >= 0 && centrality <= 5) { + registry.fill(HIST("hPtMCGen05"), particle.pt()); + registry.fill(HIST("hCenMCGen05"), centrality); + registry.fill(HIST("hPtNchMCGen05"), particle.pt(), numberOfTracks[0]); + } + + if (collisions.size() > 0) { + registry.fill(HIST("hPtNchMCGen"), particle.pt(), numberOfTracks[0]); + } + } + + for (const auto& track : groupedTracksReco) { + + registry.fill(HIST("hCorr"), numberOfTracks[0], track.size()); + if (centrality >= 0 && centrality <= 5) { + registry.fill(HIST("hCorr05"), numberOfTracks[0], track.size()); + } + } + + registry.fill(HIST("PtMC_ch"), centrality, particle.pt()); + if (particle.pdgCode() == kPiPlus || + particle.pdgCode() == kPiMinus) { // pion + registry.fill(HIST("PtMC_pi"), centrality, particle.pt()); + } else if (particle.pdgCode() == kKPlus || + particle.pdgCode() == kKMinus) { // kaon + registry.fill(HIST("PtMC_ka"), centrality, particle.pt()); + } else if (particle.pdgCode() == kProton || + particle.pdgCode() == kProtonBar) { // proton + registry.fill(HIST("PtMC_pr"), centrality, particle.pt()); + } else if (particle.pdgCode() == kSigmaPlus || + particle.pdgCode() == + kSigmaBarMinus) { // positive sigma + registry.fill(HIST("PtMC_sigpos"), centrality, particle.pt()); + } else if (particle.pdgCode() == kSigmaMinus || + particle.pdgCode() == + kSigmaBarPlus) { // negative sigma + registry.fill(HIST("PtMC_signeg"), centrality, particle.pt()); + } else { // rest + registry.fill(HIST("PtMC_re"), centrality, particle.pt()); + } + } + } + } + PROCESS_SWITCH(FlowGfwTask, processpTEff, "Process pT Eff", false); + +}; // End of struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Flow/Tasks/flowMc.cxx b/PWGCF/Flow/Tasks/flowMc.cxx new file mode 100644 index 00000000000..b310096ef40 --- /dev/null +++ b/PWGCF/Flow/Tasks/flowMc.cxx @@ -0,0 +1,561 @@ +// 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 flowMc.cxx +/// \author Zhiyong Lu (zhiyong.lu@cern.ch) +/// \since Feb/5/2025 +/// \brief QC of synthetic flow exercise + +#include +#include +#include +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/Core/trackUtilities.h" +#include "ReconstructionDataFormats/Track.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table +#include "GFWPowerArray.h" +#include "GFW.h" +#include "GFWCumulant.h" +#include "GFWWeights.h" +#include "FlowContainer.h" +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct FlowMc { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable minB{"minB", 0.0f, "min impact parameter"}; + Configurable maxB{"maxB", 20.0f, "max impact parameter"}; + O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeights, bool, false, "Fill and output NUA weights") + O2_DEFINE_CONFIGURABLE(cfgCutPtRefMin, float, 0.2f, "Minimal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtRefMax, float, 3.0f, "Maximal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMin, float, 0.2f, "Minimal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMax, float, 10.0f, "Maximal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutTPCclu, float, 70.0f, "minimum TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutITSclu, float, 6.0f, "minimum ITS clusters") + O2_DEFINE_CONFIGURABLE(cfgFlowAcceptance, std::string, "", "CCDB path to acceptance object") + O2_DEFINE_CONFIGURABLE(cfgFlowEfficiency, std::string, "", "CCDB path to efficiency object") + O2_DEFINE_CONFIGURABLE(cfgCentVsIPTruth, std::string, "", "CCDB path to centrality vs IP truth") + O2_DEFINE_CONFIGURABLE(cfgIsGlobalTrack, bool, false, "Use global tracks instead of hasTPC&&hasITS") + O2_DEFINE_CONFIGURABLE(cfgK0Lambda0Enabled, bool, false, "Add K0 and Lambda0") + O2_DEFINE_CONFIGURABLE(cfgFlowCumulantEnabled, bool, false, "switch of calculating flow") + O2_DEFINE_CONFIGURABLE(cfgFlowCumulantNbootstrap, int, 30, "Number of subsamples") + O2_DEFINE_CONFIGURABLE(cfgTrackDensityCorrUse, bool, false, "Use track density efficiency correction") + O2_DEFINE_CONFIGURABLE(cfgTrackDensityCorrSlopeFactor, float, 1.0f, "A factor to scale the track density efficiency slope") + Configurable> cfgTrackDensityP0{"cfgTrackDensityP0", std::vector{0.6003720411, 0.6152630970, 0.6288860646, 0.6360694031, 0.6409494798, 0.6450540203, 0.6482117301, 0.6512592056, 0.6640008690, 0.6862631416, 0.7005738691, 0.7106567432, 0.7170728333}, "parameter 0 for track density efficiency correction"}; + Configurable> cfgTrackDensityP1{"cfgTrackDensityP1", std::vector{-1.007592e-05, -8.932635e-06, -9.114538e-06, -1.054818e-05, -1.220212e-05, -1.312304e-05, -1.376433e-05, -1.412813e-05, -1.289562e-05, -1.050065e-05, -8.635725e-06, -7.380821e-06, -6.201250e-06}, "parameter 1 for track density efficiency correction"}; + float maxEta = 0.8; + + ConfigurableAxis axisB{"axisB", {100, 0.0f, 20.0f}, ""}; + ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}, "X axis for histograms"}; + ConfigurableAxis axisPhi{"axisPhi", {100, 0.0f, constants::math::TwoPI}, ""}; + ConfigurableAxis axisNch{"axisNch", {300, 0.0f, 3000.0f}, "Nch in |eta|<0.8"}; + + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f}, "pt axis"}; + + // Cent vs IP + TH1D* mCentVsIPTruth = nullptr; + bool centVsIPTruthLoaded = false; + + // Corrections + TH1D* mEfficiency = nullptr; + GFWWeights* mAcceptance = nullptr; + bool correctionsLoaded = false; + + std::vector funcEff; + TH1D* hFindPtBin; + TF1* funcV2; + TF1* funcV3; + TF1* funcV4; + + // Connect to ccdb + Service ccdb; + Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + OutputObj fWeights{GFWWeights("weights")}; + OutputObj fFCTrue{FlowContainer("FlowContainerTrue")}; + OutputObj fFCReco{FlowContainer("FlowContainerReco")}; + GFW* fGFWTrue = new GFW(); + GFW* fGFWReco = new GFW(); + TAxis* fPtAxis; + std::vector corrconfigsTruth; + std::vector corrconfigsReco; + TRandom3* fRndm = new TRandom3(0); + + void init(InitContext&) + { + // QA histograms + histos.add("hnTPCClu", "Number of found TPC clusters", HistType::kTH1D, {{100, 40, 180}}); + histos.add("hnITSClu", "Number of found ITS clusters", HistType::kTH1D, {{100, 0, 20}}); + // pT histograms + histos.add("hImpactParameter", "hImpactParameter", HistType::kTH1D, {axisB}); + histos.add("hNchVsImpactParameter", "hNchVsImpactParameter", HistType::kTH2D, {axisB, axisNch}); + histos.add("hEventPlaneAngle", "hEventPlaneAngle", HistType::kTH1D, {axisPhi}); + histos.add("hPtVsPhiGenerated", "hPtVsPhiGenerated", HistType::kTH2D, {axisPhi, axisPt}); + histos.add("hPtVsPhiGlobal", "hPtVsPhiGlobal", HistType::kTH2D, {axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGenerated", "hBVsPtVsPhiGenerated", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGlobal", "hBVsPtVsPhiGlobal", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiAny", "hBVsPtVsPhiAny", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiTPCTrack", "hBVsPtVsPhiTPCTrack", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiITSTrack", "hBVsPtVsPhiITSTrack", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiITSABTrack", "hBVsPtVsPhiITSABTrack", HistType::kTH3D, {axisB, axisPhi, axisPt}); + + histos.add("hBVsPtVsPhiGeneratedK0Short", "hBVsPtVsPhiGeneratedK0Short", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGlobalK0Short", "hBVsPtVsPhiGlobalK0Short", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGeneratedLambda", "hBVsPtVsPhiGeneratedLambda", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGlobalLambda", "hBVsPtVsPhiGlobalLambda", HistType::kTH3D, {axisB, axisPhi, axisPt}); + + histos.add("hBVsPtVsPhiGeneratedXi", "hBVsPtVsPhiGeneratedXi", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGlobalXi", "hBVsPtVsPhiGlobalXi", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGeneratedOmega", "hBVsPtVsPhiGeneratedOmega", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGlobalOmega", "hBVsPtVsPhiGlobalOmega", HistType::kTH3D, {axisB, axisPhi, axisPt}); + + histos.add("hPhi", "#phi distribution", HistType::kTH1D, {axisPhi}); + histos.add("hPhiWeighted", "corrected #phi distribution", HistType::kTH1D, {axisPhi}); + histos.add("hEPVsPhiMC", "hEPVsPhiMC;Event Plane Angle; #varphi", HistType::kTH2D, {axisPhi, axisPhi}); + histos.add("hEPVsPhi", "hEPVsPhi;Event Plane Angle; #varphi", HistType::kTH2D, {axisPhi, axisPhi}); + histos.add("hPtNchGenerated", "Reco production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGlobal", "Global production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGeneratedPion", "Reco production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGlobalPion", "Global production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGeneratedKaon", "Reco production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGlobalKaon", "Global production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGeneratedProton", "Reco production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGlobalProton", "Global production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGeneratedK0", "Reco production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGlobalK0", "Global production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGeneratedLambda", "Reco production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGlobalLambda", "Global production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtMCGen", "Monte Carlo Truth; pT (GeV/c);", {HistType::kTH1D, {axisPt}}); + histos.add("hPtMCGlobal", "Monte Carlo Global; pT (GeV/c);", {HistType::kTH1D, {axisPt}}); + histos.add("hPhiWeightedTrDen", "corrected #phi distribution, considering track density", {HistType::kTH1D, {axisPhi}}); + + o2::framework::AxisSpec axis = axisPt; + int nPtBins = axis.binEdges.size() - 1; + double* ptBins = &(axis.binEdges)[0]; + fPtAxis = new TAxis(nPtBins, ptBins); + + if (cfgOutputNUAWeights) { + fWeights->setPtBins(nPtBins, ptBins); + fWeights->init(true, false); + } + + if (cfgFlowCumulantEnabled) { + TObjArray* oba = new TObjArray(); + oba->Add(new TNamed("ChFull22", "ChFull22")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("ChFull22_pt_%i", i + 1), "ChFull22_pTDiff")); + oba->Add(new TNamed("Ch10Gap22", "Ch10Gap22")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ch10Gap22_pt_%i", i + 1), "Ch10Gap22_pTDiff")); + fFCTrue->SetName("FlowContainerTrue"); + fFCTrue->SetXAxis(fPtAxis); + fFCTrue->Initialize(oba, axisCentrality, cfgFlowCumulantNbootstrap); + fFCReco->SetName("FlowContainerReco"); + fFCReco->SetXAxis(fPtAxis); + fFCReco->Initialize(oba, axisCentrality, cfgFlowCumulantNbootstrap); + delete oba; + + fGFWTrue->AddRegion("full", -0.8, 0.8, 1, 1); + fGFWTrue->AddRegion("refN10", -0.8, -0.5, 1, 1); + fGFWTrue->AddRegion("refP10", 0.5, 0.8, 1, 1); + fGFWTrue->AddRegion("poiN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 2); + fGFWTrue->AddRegion("poifull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 2); + fGFWTrue->AddRegion("olN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 4); + fGFWTrue->AddRegion("olfull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 4); + corrconfigsTruth.push_back(fGFWTrue->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); + corrconfigsTruth.push_back(fGFWTrue->GetCorrelatorConfig("poifull full | olfull {2 -2}", "ChFull22", kTRUE)); + corrconfigsTruth.push_back(fGFWTrue->GetCorrelatorConfig("refN10 {2} refP10 {-2}", "Ch10Gap22", kFALSE)); + corrconfigsTruth.push_back(fGFWTrue->GetCorrelatorConfig("poiN10 refN10 | olN10 {2} refP10 {-2}", "Ch10Gap22", kTRUE)); + fGFWTrue->CreateRegions(); + + fGFWReco->AddRegion("full", -0.8, 0.8, 1, 1); + fGFWReco->AddRegion("refN10", -0.8, -0.5, 1, 1); + fGFWReco->AddRegion("refP10", 0.5, 0.8, 1, 1); + fGFWReco->AddRegion("poiN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 2); + fGFWReco->AddRegion("poifull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 2); + fGFWReco->AddRegion("olN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 4); + fGFWReco->AddRegion("olfull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 4); + corrconfigsReco.push_back(fGFWReco->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); + corrconfigsReco.push_back(fGFWReco->GetCorrelatorConfig("poifull full | olfull {2 -2}", "ChFull22", kTRUE)); + corrconfigsReco.push_back(fGFWReco->GetCorrelatorConfig("refN10 {2} refP10 {-2}", "Ch10Gap22", kFALSE)); + corrconfigsReco.push_back(fGFWReco->GetCorrelatorConfig("poiN10 refN10 | olN10 {2} refP10 {-2}", "Ch10Gap22", kTRUE)); + fGFWReco->CreateRegions(); + } + + if (cfgTrackDensityCorrUse) { + std::vector pTEffBins = {0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.4, 1.8, 2.2, 2.6, 3.0}; + hFindPtBin = new TH1D("hFindPtBin", "hFindPtBin", pTEffBins.size() - 1, &pTEffBins[0]); + funcEff.resize(pTEffBins.size() - 1); + // LHC24g3 Eff + std::vector f1p0 = cfgTrackDensityP0; + std::vector f1p1 = cfgTrackDensityP1; + for (uint ifunc = 0; ifunc < pTEffBins.size() - 1; ifunc++) { + funcEff[ifunc] = new TF1(Form("funcEff%i", ifunc), "[0]+[1]*x", 0, 3000); + funcEff[ifunc]->SetParameters(f1p0[ifunc], f1p1[ifunc] * cfgTrackDensityCorrSlopeFactor); + } + funcV2 = new TF1("funcV2", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV2->SetParameters(0.0186111, 0.00351907, -4.38264e-05, 1.35383e-07, -3.96266e-10); + funcV3 = new TF1("funcV3", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV3->SetParameters(0.0174056, 0.000703329, -1.45044e-05, 1.91991e-07, -1.62137e-09); + funcV4 = new TF1("funcV4", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV4->SetParameters(0.008845, 0.000259668, -3.24435e-06, 4.54837e-08, -6.01825e-10); + } + } + + void loadCorrections(uint64_t timestamp) + { + if (correctionsLoaded) + return; + if (cfgFlowAcceptance.value.empty() == false) { + mAcceptance = ccdb->getForTimeStamp(cfgFlowAcceptance, timestamp); + if (mAcceptance) + LOGF(info, "Loaded acceptance weights from %s (%p)", cfgFlowAcceptance.value.c_str(), (void*)mAcceptance); + else + LOGF(warning, "Could not load acceptance weights from %s (%p)", cfgFlowAcceptance.value.c_str(), (void*)mAcceptance); + } + if (cfgFlowEfficiency.value.empty() == false) { + mEfficiency = ccdb->getForTimeStamp(cfgFlowEfficiency, timestamp); + if (mEfficiency == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgFlowEfficiency.value.c_str()); + } + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgFlowEfficiency.value.c_str(), (void*)mEfficiency); + } + correctionsLoaded = true; + } + + bool setCurrentParticleWeights(float& weight_nue, float& weight_nua, float phi, float eta, float pt, float vtxz) + { + float eff = 1.; + if (mEfficiency) + eff = mEfficiency->GetBinContent(mEfficiency->FindBin(pt)); + else + eff = 1.0; + if (eff == 0) + return false; + weight_nue = 1. / eff; + if (mAcceptance) + weight_nua = mAcceptance->getNUA(phi, eta, vtxz); + else + weight_nua = 1; + return true; + } + + void fillFC(GFW* fGFW, bool isMCTruth, const GFW::CorrConfig& corrconf, const double& cent, const double& rndm) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (!corrconf.pTDif) { + if (dnx == 0) + return; + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) { + if (isMCTruth) + fFCTrue->FillProfile(corrconf.Head.c_str(), cent, val, dnx, rndm); + else + fFCReco->FillProfile(corrconf.Head.c_str(), cent, val, dnx, rndm); + } + return; + } + for (auto i = 1; i <= fPtAxis->GetNbins(); i++) { + dnx = fGFW->Calculate(corrconf, i - 1, kTRUE).real(); + if (dnx == 0) + continue; + val = fGFW->Calculate(corrconf, i - 1, kFALSE).real() / dnx; + if (std::fabs(val) < 1) { + if (isMCTruth) + fFCTrue->FillProfile(Form("%s_pt_%i", corrconf.Head.c_str(), i), cent, val, dnx, rndm); + else + fFCReco->FillProfile(Form("%s_pt_%i", corrconf.Head.c_str(), i), cent, val, dnx, rndm); + } + } + return; + } + + void loadCentVsIPTruth(uint64_t timestamp) + { + if (centVsIPTruthLoaded) + return; + if (cfgCentVsIPTruth.value.empty() == false) { + mCentVsIPTruth = ccdb->getForTimeStamp(cfgCentVsIPTruth, timestamp); + if (mCentVsIPTruth) + LOGF(info, "Loaded CentVsIPTruth weights from %s (%p)", cfgCentVsIPTruth.value.c_str(), (void*)mCentVsIPTruth); + else + LOGF(fatal, "Failed to load CentVsIPTruth weights from %s", cfgCentVsIPTruth.value.c_str()); + + centVsIPTruthLoaded = true; + } else { + LOGF(fatal, "when calculate flow, Cent Vs IP distribution must be provided"); + } + } + + using RecoTracks = soa::Join; + + void process(aod::McCollision const& mcCollision, aod::BCsWithTimestamps const&, soa::Join const& mcParticles, RecoTracks const&) + { + + float imp = mcCollision.impactParameter(); + float evPhi = mcCollision.eventPlaneAngle(); + float vtxz = mcCollision.posZ(); + evPhi = RecoDecay::constrainAngle(evPhi); + + int64_t nCh = 0; + int64_t nChGlobal = 0; + float centrality = 0; + float lRandom = fRndm->Rndm(); + float weff = 1.; + float wacc = 1.; + auto bc = mcCollision.bc_as(); + loadCorrections(bc.timestamp()); + + if (imp > minB && imp < maxB) { + // event within range + histos.fill(HIST("hImpactParameter"), imp); + histos.fill(HIST("hEventPlaneAngle"), evPhi); + if (cfgFlowCumulantEnabled) { + loadCentVsIPTruth(bc.timestamp()); + centrality = mCentVsIPTruth->GetBinContent(mCentVsIPTruth->GetXaxis()->FindBin(imp)); + fGFWTrue->Clear(); + fGFWReco->Clear(); + } + + double psi2Est = 0, psi3Est = 0, psi4Est = 0; + float wEPeff = 1; + double v2 = 0, v3 = 0, v4 = 0; + double q2x = 0, q2y = 0; + double q3x = 0, q3y = 0; + double q4x = 0, q4y = 0; + for (auto const& mcParticle : mcParticles) { + int pdgCode = std::abs(mcParticle.pdgCode()); + if (pdgCode != PDG_t::kElectron && pdgCode != PDG_t::kMuonMinus && pdgCode != PDG_t::kPiPlus && pdgCode != kKPlus && pdgCode != PDG_t::kProton) + continue; + if (!mcParticle.isPhysicalPrimary()) + continue; + if (std::fabs(mcParticle.eta()) > maxEta) // main acceptance + continue; + if (mcParticle.has_tracks()) { + auto const& tracks = mcParticle.tracks_as(); + for (auto const& track : tracks) { + if (!((track.tpcNClsFound() >= cfgCutTPCclu) && (track.itsNCls() >= cfgCutITSclu))) { + continue; + } + if (cfgIsGlobalTrack && track.isGlobalTrack()) { + nChGlobal++; + } + if (!cfgIsGlobalTrack && track.hasTPC() && track.hasITS()) { + nChGlobal++; + } + if (cfgTrackDensityCorrUse && cfgFlowCumulantEnabled) { + bool withinPtRef = (cfgCutPtRefMin < track.pt()) && (track.pt() < cfgCutPtRefMax); // within RF pT rang + if (withinPtRef) { + q2x += std::cos(2 * track.phi()); + q2y += std::sin(2 * track.phi()); + q3x += std::cos(3 * track.phi()); + q3y += std::sin(3 * track.phi()); + q4x += std::cos(4 * track.phi()); + q4y += std::sin(4 * track.phi()); + } + } + } + } + } + if (cfgTrackDensityCorrUse && cfgFlowCumulantEnabled) { + psi2Est = std::atan2(q2y, q2x) / 2.; + psi3Est = std::atan2(q3y, q3x) / 3.; + psi4Est = std::atan2(q4y, q4x) / 4.; + v2 = funcV2->Eval(centrality); + v3 = funcV3->Eval(centrality); + v4 = funcV4->Eval(centrality); + } + + for (auto const& mcParticle : mcParticles) { + // focus on bulk: e, mu, pi, k, p + int pdgCode = std::abs(mcParticle.pdgCode()); + bool extraPDGType = true; + if (cfgK0Lambda0Enabled) { + extraPDGType = (pdgCode != PDG_t::kK0Short && pdgCode != PDG_t::kLambda0); + } + if (extraPDGType && pdgCode != PDG_t::kElectron && pdgCode != PDG_t::kMuonMinus && pdgCode != PDG_t::kPiPlus && pdgCode != kKPlus && pdgCode != PDG_t::kProton) + continue; + + if (!mcParticle.isPhysicalPrimary()) + continue; + if (std::fabs(mcParticle.eta()) > maxEta) // main acceptance + continue; + + float deltaPhi = mcParticle.phi() - mcCollision.eventPlaneAngle(); + deltaPhi = RecoDecay::constrainAngle(deltaPhi); + histos.fill(HIST("hPtVsPhiGenerated"), deltaPhi, mcParticle.pt()); + histos.fill(HIST("hBVsPtVsPhiGenerated"), imp, deltaPhi, mcParticle.pt()); + histos.fill(HIST("hPtNchGenerated"), mcParticle.pt(), nChGlobal); + histos.fill(HIST("hPtMCGen"), mcParticle.pt()); + if (pdgCode == PDG_t::kPiPlus) + histos.fill(HIST("hPtNchGeneratedPion"), mcParticle.pt(), nChGlobal); + if (pdgCode == PDG_t::kKPlus) + histos.fill(HIST("hPtNchGeneratedKaon"), mcParticle.pt(), nChGlobal); + if (pdgCode == PDG_t::kProton) + histos.fill(HIST("hPtNchGeneratedProton"), mcParticle.pt(), nChGlobal); + if (pdgCode == PDG_t::kK0Short) + histos.fill(HIST("hPtNchGeneratedK0"), mcParticle.pt(), nChGlobal); + if (pdgCode == PDG_t::kLambda0) + histos.fill(HIST("hPtNchGeneratedLambda"), mcParticle.pt(), nChGlobal); + + nCh++; + + bool validGlobal = false; + bool validTrack = false; + bool validTPCTrack = false; + bool validITSTrack = false; + bool validITSABTrack = false; + if (mcParticle.has_tracks()) { + auto const& tracks = mcParticle.tracks_as(); + for (auto const& track : tracks) { + if (!((track.tpcNClsFound() >= cfgCutTPCclu) && (track.itsNCls() >= cfgCutITSclu))) { + continue; + } + histos.fill(HIST("hnTPCClu"), track.tpcNClsFound()); + histos.fill(HIST("hnITSClu"), track.itsNCls()); + if (cfgIsGlobalTrack && track.isGlobalTrack()) { + validGlobal = true; + } + if (!cfgIsGlobalTrack && track.hasTPC() && track.hasITS()) { + validGlobal = true; + } + if (track.hasTPC() || track.hasITS()) { + validTrack = true; + } + if (track.hasTPC()) { + validTPCTrack = true; + } + if (track.hasITS() && track.itsChi2NCl() > -1e-6) { + validITSTrack = true; + } + if (track.hasITS() && track.itsChi2NCl() < -1e-6) { + validITSABTrack = true; + } + } + } + + bool withinPtRef = (cfgCutPtRefMin < mcParticle.pt()) && (mcParticle.pt() < cfgCutPtRefMax); // within RF pT range + bool withinPtPOI = (cfgCutPtPOIMin < mcParticle.pt()) && (mcParticle.pt() < cfgCutPtPOIMax); // within POI pT range + if (cfgOutputNUAWeights && withinPtRef) + fWeights->fill(mcParticle.phi(), mcParticle.eta(), vtxz, mcParticle.pt(), 0, 0); + if (!setCurrentParticleWeights(weff, wacc, mcParticle.phi(), mcParticle.eta(), mcParticle.pt(), vtxz)) + continue; + if (cfgTrackDensityCorrUse && cfgFlowCumulantEnabled && withinPtRef) { + double fphi = v2 * std::cos(2 * (mcParticle.phi() - psi2Est)) + v3 * std::cos(3 * (mcParticle.phi() - psi3Est)) + v4 * std::cos(4 * (mcParticle.phi() - psi4Est)); + fphi = (1 + 2 * fphi); + int pTBinForEff = hFindPtBin->FindBin(mcParticle.pt()); + if (pTBinForEff >= 1 && pTBinForEff <= hFindPtBin->GetNbinsX()) { + wEPeff = funcEff[pTBinForEff - 1]->Eval(fphi * nChGlobal); + if (wEPeff > 0.) { + wEPeff = 1. / wEPeff; + weff *= wEPeff; + histos.fill(HIST("hPhiWeightedTrDen"), mcParticle.phi(), wacc * wEPeff); + } + } + } + + if (cfgFlowCumulantEnabled) { + if (withinPtRef) + fGFWTrue->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), wacc * weff, 1); + if (withinPtPOI) + fGFWTrue->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), wacc * weff, 2); + if (withinPtPOI && withinPtRef) + fGFWTrue->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), wacc * weff, 4); + + if (validGlobal) { + if (withinPtRef) + fGFWReco->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), wacc * weff, 1); + if (withinPtPOI) + fGFWReco->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), wacc * weff, 2); + if (withinPtPOI && withinPtRef) + fGFWReco->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), wacc * weff, 4); + } + } + + if (withinPtRef) { + histos.fill(HIST("hEPVsPhiMC"), evPhi, mcParticle.phi()); + } + + if (validGlobal && withinPtRef) { + histos.fill(HIST("hPhi"), mcParticle.phi()); + histos.fill(HIST("hPhiWeighted"), mcParticle.phi(), wacc); + histos.fill(HIST("hEPVsPhi"), evPhi, mcParticle.phi()); + } + + // if valid global, fill + if (validGlobal) { + histos.fill(HIST("hPtVsPhiGlobal"), deltaPhi, mcParticle.pt(), wacc * weff); + histos.fill(HIST("hBVsPtVsPhiGlobal"), imp, deltaPhi, mcParticle.pt(), wacc * weff); + histos.fill(HIST("hPtNchGlobal"), mcParticle.pt(), nChGlobal); + histos.fill(HIST("hPtMCGlobal"), mcParticle.pt()); + if (pdgCode == PDG_t::kPiPlus) + histos.fill(HIST("hPtNchGlobalPion"), mcParticle.pt(), nChGlobal); + if (pdgCode == PDG_t::kKPlus) + histos.fill(HIST("hPtNchGlobalKaon"), mcParticle.pt(), nChGlobal); + if (pdgCode == PDG_t::kProton) + histos.fill(HIST("hPtNchGlobalProton"), mcParticle.pt(), nChGlobal); + if (pdgCode == PDG_t::kK0Short) + histos.fill(HIST("hPtNchGlobalK0"), mcParticle.pt(), nChGlobal); + if (pdgCode == PDG_t::kLambda0) + histos.fill(HIST("hPtNchGlobalLambda"), mcParticle.pt(), nChGlobal); + } + // if any track present, fill + if (validTrack) + histos.fill(HIST("hBVsPtVsPhiAny"), imp, deltaPhi, mcParticle.pt(), wacc * weff); + if (validTPCTrack) + histos.fill(HIST("hBVsPtVsPhiTPCTrack"), imp, deltaPhi, mcParticle.pt(), wacc * weff); + if (validITSTrack) + histos.fill(HIST("hBVsPtVsPhiITSTrack"), imp, deltaPhi, mcParticle.pt(), wacc * weff); + if (validITSABTrack) + histos.fill(HIST("hBVsPtVsPhiITSABTrack"), imp, deltaPhi, mcParticle.pt(), wacc * weff); + } + + if (cfgFlowCumulantEnabled) { + for (uint l_ind = 0; l_ind < corrconfigsTruth.size(); l_ind++) { + fillFC(fGFWTrue, true, corrconfigsTruth.at(l_ind), centrality, lRandom); + } + for (uint l_ind = 0; l_ind < corrconfigsReco.size(); l_ind++) { + fillFC(fGFWReco, false, corrconfigsReco.at(l_ind), centrality, lRandom); + } + } + } + histos.fill(HIST("hNchVsImpactParameter"), imp, nCh); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Flow/Tasks/flowPbpbPikp.cxx b/PWGCF/Flow/Tasks/flowPbpbPikp.cxx new file mode 100644 index 00000000000..f880deaf75b --- /dev/null +++ b/PWGCF/Flow/Tasks/flowPbpbPikp.cxx @@ -0,0 +1,691 @@ +// 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 flowPbpbPikp.cxx +/// \brief PID flow using the generic framework +/// \author Preet Bhanjan Pati + +#include +#include +#include +#include +#include +#include +#include + +#include "Math/Vector4D.h" + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/StepTHn.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Multiplicity.h" +#include "CommonConstants/PhysicsConstants.h" + +#include "PWGCF/GenericFramework/Core/GFWPowerArray.h" +#include "PWGCF/GenericFramework/Core/GFW.h" +#include "PWGCF/GenericFramework/Core/GFWCumulant.h" +#include "PWGCF/GenericFramework/Core/FlowContainer.h" +#include "PWGCF/GenericFramework/Core/GFWWeights.h" +#include "PWGCF/GenericFramework/Core/GFWWeightsList.h" + +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/PID.h" + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace std; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct FlowPbpbPikp { + Service ccdb; + Configurable noLaterThan{"noLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMin, float, 0.2f, "Minimal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMax, float, 10.0f, "Maximal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 3.0f, "Maximal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") + O2_DEFINE_CONFIGURABLE(cfgTpcCluster, int, 70, "Number of TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5, "Chi2 per TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgUseNch, bool, false, "Use Nch for flow observables") + O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 10, "Number of subsamples") + O2_DEFINE_CONFIGURABLE(cfgFillWeights, bool, true, "Fill NUA weights") + O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeights, bool, true, "Fill and output NUA weights") + O2_DEFINE_CONFIGURABLE(cfgOutputRunByRun, bool, true, "Fill and output NUA weights run by run") + O2_DEFINE_CONFIGURABLE(cfgEfficiency, std::string, "", "CCDB path to efficiency object") + O2_DEFINE_CONFIGURABLE(cfgAcceptance, std::string, "", "CCDB path to acceptance object") + O2_DEFINE_CONFIGURABLE(cfgTpcNsigmaCut, float, 2.0f, "TPC N-sigma cut for pions, kaons, protons") + O2_DEFINE_CONFIGURABLE(cfgTofPtCut, float, 0.5f, "Minimum pt to use TOF N-sigma") + O2_DEFINE_CONFIGURABLE(cfgCutDCAxy, float, 2.0f, "DCAxy range for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutDCAz, float, 2.0f, "DCAz range for tracks") + + O2_DEFINE_CONFIGURABLE(cfgCutOccupancy, int, 3000, "Occupancy cut") + O2_DEFINE_CONFIGURABLE(cfgUseGlobalTrack, bool, true, "use Global track") + O2_DEFINE_CONFIGURABLE(cfgITScluster, int, 0, "Number of ITS cluster") + O2_DEFINE_CONFIGURABLE(cfgTrackDensityCorrUse, bool, true, "Use track density efficiency correction") + + Configurable> cfgTrackDensityP0{"cfgTrackDensityP0", std::vector{0.7217476707, 0.7384792571, 0.7542625668, 0.7640680200, 0.7701951667, 0.7755299053, 0.7805901710, 0.7849446786, 0.7957356586, 0.8113039262, 0.8211968966, 0.8280558878, 0.8329342135}, "parameter 0 for track density efficiency correction"}; + Configurable> cfgTrackDensityP1{"cfgTrackDensityP1", std::vector{-2.169488e-05, -2.191913e-05, -2.295484e-05, -2.556538e-05, -2.754463e-05, -2.816832e-05, -2.846502e-05, -2.843857e-05, -2.705974e-05, -2.477018e-05, -2.321730e-05, -2.203315e-05, -2.109474e-05}, "parameter 1 for track density efficiency correction"}; + + ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for histograms"}; + ConfigurableAxis axisPhi{"axisPhi", {60, 0.0, constants::math::TwoPI}, "phi axis for histograms"}; + ConfigurableAxis axisEta{"axisEta", {40, -1., 1.}, "eta axis for histograms"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.00, 1.20, 1.40, 1.60, 1.80, 2.00, 2.20, 2.40, 2.60, 2.80, 3.00, 3.50, 4.00, 5.00, 6.00, 8.00, 10.00}, "pt axis for histograms"}; + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}, "centrality axis for histograms"}; + ConfigurableAxis axisNsigmaTPC{"axisNsigmaTPC", {80, -5, 5}, "nsigmaTPC axis"}; + ConfigurableAxis axisNsigmaTOF{"axisNsigmaTOF", {80, -5, 5}, "nsigmaTOF axis"}; + ConfigurableAxis axisParticles{"axisParticles", {3, 0, 3}, "axis for different hadrons"}; + ConfigurableAxis axisTPCsignal{"axisTPCsignal", {10000, 0, 1000}, "axis for TPC signal"}; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter trackFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz) && (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtPOIMin) && (aod::track::pt < cfgCutPtPOIMax) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (aod::track::tpcChi2NCl < cfgCutChi2prTPCcls); + + using AodCollisions = soa::Filtered>; + using AodTracksWithoutBayes = soa::Filtered>; + + OutputObj fFC{FlowContainer("FlowContainer")}; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + GFW* fGFW = new GFW(); + std::vector corrconfigs; + TAxis* fPtAxis; + TRandom3* fRndm = new TRandom3(0); + + std::map>> th3sList; + enum OutputSpecies { + hRef = 0, + hCharge, + hPion, + hKaon, + hProton, + kCount_OutputSpecies + }; + int lastRunNumer = -1; + std::vector runNumbers; + std::vector mAcceptance; + bool correctionsLoaded = false; + + // local track density correction + std::vector funcEff; + TH1D* hFindPtBin; + TF1* funcV2; + TF1* funcV3; + TF1* funcV4; + + void init(InitContext const&) + { + ccdb->setURL(ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setCreatedNotAfter(noLaterThan.value); + + histos.add("hVtxZ", "", {HistType::kTH1D, {axisVertex}}); + histos.add("hMult", "", {HistType::kTH1D, {{3000, 0.5, 3000.5}}}); + histos.add("hCent", "", {HistType::kTH1D, {{90, 0, 90}}}); + histos.add("hPhi", "", {HistType::kTH1D, {axisPhi}}); + histos.add("hPhiWeighted", "", {HistType::kTH1D, {axisPhi}}); + histos.add("hEta", "", {HistType::kTH1D, {axisEta}}); + histos.add("hPt", "", {HistType::kTH1D, {axisPt}}); + histos.add("c22_gap08", "", {HistType::kTProfile, {axisMultiplicity}}); + histos.add("c22_gap08_pi", "", {HistType::kTProfile, {axisMultiplicity}}); + histos.add("c22_gap08_ka", "", {HistType::kTProfile, {axisMultiplicity}}); + histos.add("c22_gap08_pr", "", {HistType::kTProfile, {axisMultiplicity}}); + histos.add("c24_full", "", {HistType::kTProfile, {axisMultiplicity}}); + histos.add("c24_gap08", "", {HistType::kTProfile, {axisMultiplicity}}); + histos.add("c24_gap08_pi", "", {HistType::kTProfile, {axisMultiplicity}}); + histos.add("c24_gap08_ka", "", {HistType::kTProfile, {axisMultiplicity}}); + histos.add("c24_gap08_pr", "", {HistType::kTProfile, {axisMultiplicity}}); + histos.add("TofTpcNsigma", "", {HistType::kTHnSparseD, {{axisParticles, axisNsigmaTPC, axisNsigmaTOF, axisPt}}}); + histos.add("partCount", "", {HistType::kTHnSparseD, {{axisParticles, axisMultiplicity, axisPt}}}); + if (cfgOutputNUAWeights && !cfgOutputRunByRun) { + histos.add("NUA/hPhiEtaVtxz_ref", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, {40, -10, 10}}}); + histos.add("NUA/hPhiEtaVtxz_ch", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, {40, -10, 10}}}); + histos.add("NUA/hPhiEtaVtxz_pi", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, {40, -10, 10}}}); + histos.add("NUA/hPhiEtaVtxz_ka", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, {40, -10, 10}}}); + histos.add("NUA/hPhiEtaVtxz_pr", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, {40, -10, 10}}}); + } + + o2::framework::AxisSpec axis = axisPt; + int nPtBins = axis.binEdges.size() - 1; + double* ptBins = &(axis.binEdges)[0]; + fPtAxis = new TAxis(nPtBins, ptBins); + + TObjArray* oba = new TObjArray(); + oba->Add(new TNamed("ChFull22", "ChFull22")); + for (int i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("ChFull22_pt_%i", i + 1), "ChFull22_pTDiff")); + + oba->Add(new TNamed("Ch08Gap22", "Ch08Gap22")); + for (int i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ch08Gap22_pt_%i", i + 1), "Ch08Gap22_pTDiff")); + oba->Add(new TNamed("Pi08Gap22", "Pi08Gap22")); + for (int i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Pi08Gap22_pt_%i", i + 1), "Pi08Gap22_pTDiff")); + oba->Add(new TNamed("Ka08Gap22", "Ka08Gap22")); + for (int i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ka08Gap22_pt_%i", i + 1), "Ka08Gap22_pTDiff")); + oba->Add(new TNamed("Pr08Gap22", "Pr08Gap22")); + for (int i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Pr08Gap22_pt_%i", i + 1), "Pr08Gap22_pTDiff")); + + oba->Add(new TNamed("ChFull24", "ChFull24")); + for (int i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("ChFull24_pt_%i", i + 1), "ChFull24_pTDiff")); + + oba->Add(new TNamed("Ch08Gap24", "Ch08Gap24")); + for (int i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ch08Gap24_pt_%i", i + 1), "Ch08Gap24_pTDiff")); + oba->Add(new TNamed("Pi08Gap24", "Pi08Gap24")); + for (int i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Pi08Gap24_pt_%i", i + 1), "Pi08Gap24_pTDiff")); + oba->Add(new TNamed("Ka08Gap24", "Ka08Gap24")); + for (int i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ka08Gap24_pt_%i", i + 1), "Ka08Gap24_pTDiff")); + oba->Add(new TNamed("Pr08Gap24", "Pr08Gap24")); + for (int i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Pr08Gap24_pt_%i", i + 1), "Pr08Gap24_pTDiff")); + + oba->Add(new TNamed("Pi08BGap22", "Pi08BGap22")); + for (int i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Pi08BGap22_pt_%i", i + 1), "Pi08BGap22_pTDiff")); + + fFC->SetName("FlowContainer"); + fFC->SetXAxis(fPtAxis); + fFC->Initialize(oba, axisMultiplicity, cfgNbootstrap); + delete oba; + + // reference particles + fGFW->AddRegion("refN08", -0.8, -0.4, 1, 1); + fGFW->AddRegion("refP08", 0.4, 0.8, 1, 1); + fGFW->AddRegion("full", -0.8, 0.8, 1, 512); + + // pt dependent charged particles + fGFW->AddRegion("poiN", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 128); + fGFW->AddRegion("olN", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 256); + fGFW->AddRegion("poi", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 1024); + fGFW->AddRegion("ol", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 2048); + + // pion + fGFW->AddRegion("poiNpi", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("olNpi", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 16); + + fGFW->AddRegion("poiPpi", 0.4, 0.8, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("olPpi", 0.4, 0.8, 1 + fPtAxis->GetNbins(), 16); + + // kaon + fGFW->AddRegion("poiNk", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olNk", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 32); + + // proton + fGFW->AddRegion("poiNpr", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 8); + fGFW->AddRegion("olNpr", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 64); + + // reference particles + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {2} refP08 {-2}", "Ch08Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {2} refP08 {-2}", "Pi08Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {2} refP08 {-2}", "Ka08Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {2} refP08 {-2}", "Pr08Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 2 -2 -2}", "ChFull24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {2 2} refP08 {-2 -2}", "Ch08Gap24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {2 2} refP08 {-2 -2}", "Pi08Gap24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {2 2} refP08 {-2 -2}", "Ka08Gap24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {2 2} refP08 {-2 -2}", "Pr08Gap24", kFALSE)); + + // pt differential pois + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poi full | ol {2 -2}", "ChFull22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiN refN08 | olN {2} refP08 {-2}", "Ch08Gap22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiNpi refN08 | olNpi {2} refP08 {-2}", "Pi08Gap22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiNk refN08 | olNk {2} refP08 {-2}", "Ka08Gap22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiNpr refN08 | olNpr {2} refP08 {-2}", "Pr08Gap22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poi full | ol {2 2 -2 -2}", "ChFull24", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiN refN08 | olN {2 2} refP08 {-2 -2}", "Ch08Gap24", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiNpi refN08 | olNpi {2 2} refP08 {-2 -2}", "Pi08Gap24", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiNk refN08 | olNk {2 2} refP08 {-2 -2}", "Ka08Gap24", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiNpr refN08 | olNpr {2 2} refP08 {-2 -2}", "Pr08Gap24", kTRUE)); + + // Backward correlations + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {2} refP08 {-2}", "Pi08BGap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPpi refP08 | olPpi {2} refN08 {-2}", "Pi08BGap22", kTRUE)); + + fGFW->CreateRegions(); + + if (cfgTrackDensityCorrUse) { + std::vector pTEffBins = {0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.4, 1.8, 2.2, 2.6, 3.0}; + hFindPtBin = new TH1D("hFindPtBin", "hFindPtBin", pTEffBins.size() - 1, &pTEffBins[0]); + funcEff.resize(pTEffBins.size() - 1); + // LHC24g3 Eff + std::vector f1p0 = cfgTrackDensityP0; + std::vector f1p1 = cfgTrackDensityP1; + for (uint ifunc = 0; ifunc < pTEffBins.size() - 1; ifunc++) { + funcEff[ifunc] = new TF1(Form("funcEff%i", ifunc), "[0]+[1]*x", 0, 3000); + funcEff[ifunc]->SetParameters(f1p0[ifunc], f1p1[ifunc]); + } + funcV2 = new TF1("funcV2", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV2->SetParameters(0.0186111, 0.00351907, -4.38264e-05, 1.35383e-07, -3.96266e-10); + funcV3 = new TF1("funcV3", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV3->SetParameters(0.0174056, 0.000703329, -1.45044e-05, 1.91991e-07, -1.62137e-09); + funcV4 = new TF1("funcV4", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV4->SetParameters(0.008845, 0.000259668, -3.24435e-06, 4.54837e-08, -6.01825e-10); + } + } + + enum Particles { + PIONS, + KAONS, + PROTONS + }; + + template + bool selectionTrack(const TTrack& track) + { + if (cfgUseGlobalTrack && !(track.isGlobalTrack() && track.isPVContributor() && track.itsNCls() > cfgITScluster && track.tpcNClsFound() > cfgTpcCluster && track.hasTPC())) { + return false; + } + if (!cfgUseGlobalTrack && !(track.isPVContributor() && track.itsNCls() > cfgITScluster && track.hasTPC())) { + return false; + } + return true; + } + + template + int getNsigmaPID(TTrack track) + { + // Computing Nsigma arrays for pion, kaon, and protons + std::array nSigmaTPC = {track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + std::array nSigmaCombined = {std::hypot(track.tpcNSigmaPi(), track.tofNSigmaPi()), std::hypot(track.tpcNSigmaKa(), track.tofNSigmaKa()), std::hypot(track.tpcNSigmaPr(), track.tofNSigmaPr())}; + int pid = -1; + float nsigma = cfgTpcNsigmaCut; + + // Choose which nSigma to use + std::array nSigmaToUse = (track.pt() > cfgTofPtCut && track.hasTOF()) ? nSigmaCombined : nSigmaTPC; + if (track.pt() >= cfgTofPtCut && !track.hasTOF()) + return -1; + + const int numSpecies = 3; + // Select particle with the lowest nsigma + for (int i = 0; i < numSpecies; ++i) { + if (std::abs(nSigmaToUse[i]) < nsigma) { + pid = i; + nsigma = std::abs(nSigmaToUse[i]); + } + } + return pid + 1; // shift the pid by 1, 1 = pion, 2 = kaon, 3 = proton + } + + /*template + std::pair getBayesID(TTrack track) + { + std::array bayesprobs = {static_cast(track.bayesPi()), static_cast(track.bayesKa()), static_cast(track.bayesPr())}; + int bayesid = -1; + int prob = 0; + + const int nParts = 3; + const int bayesCut = 80; + for (int i = 0; i < nParts; ++i) { + if (bayesprobs[i] > prob && bayesprobs[i] > bayesCut) { + bayesid = i; + prob = bayesprobs[i]; + } + } + return std::make_pair(bayesid, prob); + } + + template + int getBayesPIDIndex(TTrack track) + { + int maxProb[3] = {80, 80, 80}; + int pidID = -1; + const int nParts = 3; + std::pair idprob = getBayesID(track); + if (idprob.first == PIONS || idprob.first == KAONS || idprob.first == PROTONS) { // 0 = pion, 1 = kaon, 2 = proton + pidID = idprob.first; + float nsigmaTPC[3] = {track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + if (idprob.second > maxProb[pidID]) { + if (std::fabs(nsigmaTPC[pidID]) > nParts) + return 0; + return pidID + 1; // shift the pid by 1, 1 = pion, 2 = kaon, 3 = proton + } else { + return 0; + } + } + return 0; + }*/ + + template + void fillProfile(const GFW::CorrConfig& corrconf, const ConstStr& tarName, const double& cent) + { + double dnx, val; + if (!corrconf.pTDif) { + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) + return; + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + histos.fill(tarName, cent, val, dnx); + return; + } + for (int i = 1; i <= fPtAxis->GetNbins(); i++) { + dnx = fGFW->Calculate(corrconf, i - 1, kTRUE).real(); + if (dnx == 0) + continue; + val = fGFW->Calculate(corrconf, i - 1, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + histos.fill(tarName, fPtAxis->GetBinCenter(i), val, dnx); + } + return; + } + + void fillFC(const GFW::CorrConfig& corrconf, const double& cent, const double& rndm) + { + double dnx, val; + if (!corrconf.pTDif) { + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) { + return; + } + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) { + fFC->FillProfile(corrconf.Head.c_str(), cent, val, dnx, rndm); + } + return; + } + for (int i = 1; i <= fPtAxis->GetNbins(); i++) { + dnx = fGFW->Calculate(corrconf, i - 1, kTRUE).real(); + if (dnx == 0) + continue; + val = fGFW->Calculate(corrconf, i - 1, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + fFC->FillProfile(Form("%s_pt_%i", corrconf.Head.c_str(), i), cent, val, dnx, rndm); + } + return; + } + + void createRunByRunHistos(int runNumber) + { + if (cfgOutputNUAWeights) { + std::vector> tH3s(kCount_OutputSpecies); + tH3s[hRef] = histos.add(Form("NUA/%d/hPhiEtaVtxz_ref", runNumber), ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, {40, -10, 10}}}); + tH3s[hCharge] = histos.add(Form("NUA/%d/hPhiEtaVtxz_ch", runNumber), ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, {40, -10, 10}}}); + tH3s[hPion] = histos.add(Form("NUA/%d/hPhiEtaVtxz_pi", runNumber), ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, {40, -10, 10}}}); + tH3s[hKaon] = histos.add(Form("NUA/%d/hPhiEtaVtxz_ka", runNumber), ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, {40, -10, 10}}}); + tH3s[hProton] = histos.add(Form("NUA/%d/hPhiEtaVtxz_pr", runNumber), ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, {40, -10, 10}}}); + th3sList.insert(std::make_pair(runNumber, tH3s)); + } + } + + void loadCorrections(aod::BCsWithTimestamps::iterator const& bc) + { + if (correctionsLoaded) + return; + if (!cfgAcceptance.value.empty()) { + uint64_t timestamp = bc.timestamp(); + mAcceptance.clear(); + mAcceptance.resize(kCount_OutputSpecies); + mAcceptance[hRef] = ccdb->getForTimeStamp(cfgAcceptance.value + "_ref", timestamp); + if (mAcceptance[hRef]) + LOGF(info, "Loaded acceptance weights from %s_ref (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[hRef]); + else + LOGF(fatal, "Could not load acceptance weights from %s_ref (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[hRef]); + + mAcceptance[hCharge] = ccdb->getForTimeStamp(cfgAcceptance.value + "_ch", timestamp); + if (mAcceptance[hCharge]) + LOGF(info, "Loaded acceptance weights from %s_ch (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[hCharge]); + else + LOGF(fatal, "Could not load acceptance weights from %s_ch (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[hCharge]); + + mAcceptance[hPion] = ccdb->getForTimeStamp(cfgAcceptance.value + "_pi", timestamp); + if (mAcceptance[hPion]) + LOGF(info, "Loaded acceptance weights from %s_pi (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[hPion]); + else + LOGF(fatal, "Could not load acceptance weights from %s_pi (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[hPion]); + + mAcceptance[hKaon] = ccdb->getForTimeStamp(cfgAcceptance.value + "_ka", timestamp); + if (mAcceptance[hKaon]) + LOGF(info, "Loaded acceptance weights from %s_ka (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[hKaon]); + else + LOGF(fatal, "Could not load acceptance weights from %s_ka (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[hKaon]); + + mAcceptance[hProton] = ccdb->getForTimeStamp(cfgAcceptance.value + "_pr", timestamp); + if (mAcceptance[hProton]) + LOGF(info, "Loaded acceptance weights from %s_pr (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[hProton]); + else + LOGF(fatal, "Could not load acceptance weights from %s_pr (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[hProton]); + } + + correctionsLoaded = true; + } + + template + double getAcceptance(TTrack track, const double& vtxz, int index) + { // 0 ref, 1 ch, 2 pi, 3 ka, 4 pr + if (index < 0 || index >= kCount_OutputSpecies) { + return 1; + } + double wacc = 1; + if (!mAcceptance.empty() && correctionsLoaded) { + if (!mAcceptance[index]) { + LOGF(fatal, "Acceptance weights not loaded for index %d", index); + return 1; + } + wacc = mAcceptance[index]->getNUA(track.phi(), track.eta(), vtxz); + } + return wacc; + } + + template + void fillWeights(const TTrack track, const double vtxz, const int& pid_index, const int& run) + { + double pt = track.pt(); + bool withinPtPOI = (cfgCutPtPOIMin < pt) && (pt < cfgCutPtPOIMax); // within POI pT range + bool withinPtRef = (cfgCutPtMin < pt) && (pt < cfgCutPtMax); // within RF pT range + + if (cfgOutputRunByRun) { + if (withinPtRef && !pid_index) + th3sList[run][hRef]->Fill(track.phi(), track.eta(), vtxz); // pt-subset of charged particles for ref flow + if (withinPtPOI) + th3sList[run][hCharge + pid_index]->Fill(track.phi(), track.eta(), vtxz); // charged and id'ed particle weights + } else { + if (withinPtRef && !pid_index) + histos.fill(HIST("NUA/hPhiEtaVtxz_ref"), track.phi(), track.eta(), vtxz); // pt-subset of charged particles for ref flow + if (withinPtPOI) { + switch (pid_index) { + case 0: + histos.fill(HIST("NUA/hPhiEtaVtxz_ch"), track.phi(), track.eta(), vtxz); // charged particle weights + break; + case 1: + histos.fill(HIST("NUA/hPhiEtaVtxz_pi"), track.phi(), track.eta(), vtxz); // pion weights + break; + case 2: + histos.fill(HIST("NUA/hPhiEtaVtxz_ka"), track.phi(), track.eta(), vtxz); // kaon weights + break; + case 3: + histos.fill(HIST("NUA/hPhiEtaVtxz_pr"), track.phi(), track.eta(), vtxz); // proton weights + break; + } + } + } + } + + void process(AodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, AodTracksWithoutBayes const& tracks) + { + int nTot = tracks.size(); + if (nTot < 1) + return; + + if (!collision.sel8() || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) + return; + + int occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy > cfgCutOccupancy) + return; + + float lRandom = fRndm->Rndm(); + float vtxz = collision.posZ(); + const auto cent = collision.centFT0C(); + auto bc = collision.bc_as(); + int runNumber = bc.runNumber(); + if (cfgOutputRunByRun && runNumber != lastRunNumer) { + lastRunNumer = runNumber; + if (std::find(runNumbers.begin(), runNumbers.end(), runNumber) == runNumbers.end()) { + // if run number is not in the preconfigured list, create new output histograms for this run + createRunByRunHistos(runNumber); + runNumbers.push_back(runNumber); + } + } + + histos.fill(HIST("hVtxZ"), vtxz); + histos.fill(HIST("hMult"), nTot); + histos.fill(HIST("hCent"), cent); + fGFW->Clear(); + + float weff = 1; + int pidIndex; + loadCorrections(bc); // load corrections for the each event + + // Track loop for calculating the Qn angles + double psi2Est = 0, psi3Est = 0, psi4Est = 0; + float wEPeff = 1; + double v2 = 0, v3 = 0, v4 = 0; + // be cautious, this only works for Pb-Pb + // esimate the Qn angles and vn for this event + if (cfgTrackDensityCorrUse) { + double q2x = 0, q2y = 0; + double q3x = 0, q3y = 0; + double q4x = 0, q4y = 0; + for (const auto& track : tracks) { + bool withinPtRef = (cfgCutPtMin < track.pt()) && (track.pt() < cfgCutPtMax); // within RF pT range + if (withinPtRef) { + q2x += std::cos(2 * track.phi()); + q2y += std::sin(2 * track.phi()); + q3x += std::cos(3 * track.phi()); + q3y += std::sin(3 * track.phi()); + q4x += std::cos(4 * track.phi()); + q4y += std::sin(4 * track.phi()); + } + } + psi2Est = std::atan2(q2y, q2x) / 2.; + psi3Est = std::atan2(q3y, q3x) / 3.; + psi4Est = std::atan2(q4y, q4x) / 4.; + + v2 = funcV2->Eval(cent); + v3 = funcV3->Eval(cent); + v4 = funcV4->Eval(cent); + } + + // Actual track loop + for (auto const& track : tracks) { + if (!selectionTrack(track)) + continue; + double pt = track.pt(); + histos.fill(HIST("hPhi"), track.phi()); + histos.fill(HIST("hEta"), track.eta()); + histos.fill(HIST("hPt"), pt); + + histos.fill(HIST("TofTpcNsigma"), PIONS, track.tpcNSigmaPi(), track.tofNSigmaPi(), pt); + histos.fill(HIST("TofTpcNsigma"), KAONS, track.tpcNSigmaKa(), track.tofNSigmaKa(), pt); + histos.fill(HIST("TofTpcNsigma"), PROTONS, track.tpcNSigmaPr(), track.tofNSigmaPr(), pt); + + bool withinPtPOI = (cfgCutPtPOIMin < pt) && (pt < cfgCutPtPOIMax); // within POI pT range + bool withinPtRef = (cfgCutPtMin < pt) && (pt < cfgCutPtMax); // within RF pT range + + // pidIndex = getBayesPIDIndex(track); + pidIndex = getNsigmaPID(track); + + weff = 1; // Initializing weff for each track + // NUA weights + if (cfgOutputNUAWeights) + fillWeights(track, vtxz, pidIndex, runNumber); + + if (!withinPtPOI && !withinPtRef) + return; + double waccRef = getAcceptance(track, vtxz, 0); + double waccPOI = withinPtPOI ? getAcceptance(track, vtxz, pidIndex + 1) : getAcceptance(track, vtxz, 0); + if (withinPtRef && withinPtPOI && pidIndex) + waccRef = waccPOI; // if particle is both (then it's overlap), override ref with POI + + // Track density correction + if (cfgTrackDensityCorrUse && withinPtRef) { + double fphi = v2 * std::cos(2 * (track.phi() - psi2Est)) + v3 * std::cos(3 * (track.phi() - psi3Est)) + v4 * std::cos(4 * (track.phi() - psi4Est)); + fphi = (1 + 2 * fphi); + int pTBinForEff = hFindPtBin->FindBin(track.pt()); + if (pTBinForEff >= 1 && pTBinForEff <= hFindPtBin->GetNbinsX()) { + wEPeff = funcEff[pTBinForEff - 1]->Eval(fphi * tracks.size()); + if (wEPeff > 0.) { + wEPeff = 1. / wEPeff; + weff *= wEPeff; + } + } + } // end of track density correction loop + + if (withinPtRef) { + histos.fill(HIST("hPhiWeighted"), track.phi(), waccRef); + fGFW->Fill(track.eta(), fPtAxis->FindBin(pt) - 1, track.phi(), waccRef * weff, 1); + fGFW->Fill(track.eta(), fPtAxis->FindBin(pt) - 1, track.phi(), waccRef * weff, 512); + } + if (withinPtPOI) { + fGFW->Fill(track.eta(), fPtAxis->FindBin(pt) - 1, track.phi(), waccPOI * weff, 128); + fGFW->Fill(track.eta(), fPtAxis->FindBin(pt) - 1, track.phi(), waccPOI * weff, 1024); + } + if (withinPtPOI && withinPtRef) { + fGFW->Fill(track.eta(), fPtAxis->FindBin(pt) - 1, track.phi(), waccPOI * weff, 256); + fGFW->Fill(track.eta(), fPtAxis->FindBin(pt) - 1, track.phi(), waccPOI * weff, 2048); + } + + if (pidIndex) { + histos.fill(HIST("partCount"), pidIndex - 1, cent, pt); + if (withinPtPOI) + fGFW->Fill(track.eta(), fPtAxis->FindBin(pt) - 1, track.phi(), waccPOI * weff, 1 << (pidIndex)); + if (withinPtPOI && withinPtRef) + fGFW->Fill(track.eta(), fPtAxis->FindBin(pt) - 1, track.phi(), waccPOI * weff, 1 << (pidIndex + 3)); + } + } // track loop ends + + // Filling cumulants with ROOT TProfile + fillProfile(corrconfigs.at(1), HIST("c22_gap08"), cent); + fillProfile(corrconfigs.at(2), HIST("c22_gap08_pi"), cent); + fillProfile(corrconfigs.at(3), HIST("c22_gap08_ka"), cent); + fillProfile(corrconfigs.at(4), HIST("c22_gap08_pr"), cent); + fillProfile(corrconfigs.at(5), HIST("c24_full"), cent); + fillProfile(corrconfigs.at(6), HIST("c24_gap08"), cent); + fillProfile(corrconfigs.at(7), HIST("c24_gap08_pi"), cent); + fillProfile(corrconfigs.at(8), HIST("c24_gap08_ka"), cent); + fillProfile(corrconfigs.at(9), HIST("c24_gap08_pr"), cent); + + for (uint l_ind = 0; l_ind < corrconfigs.size(); l_ind++) { + fillFC(corrconfigs.at(l_ind), cent, lRandom); + } + + } // end of process +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Flow/Tasks/flowPtEfficiency.cxx b/PWGCF/Flow/Tasks/flowPtEfficiency.cxx index 43a6eff399d..0e272eb78a1 100644 --- a/PWGCF/Flow/Tasks/flowPtEfficiency.cxx +++ b/PWGCF/Flow/Tasks/flowPtEfficiency.cxx @@ -8,56 +8,137 @@ // 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 This task is an empty skeleton that fills a simple eta histogram. -/// it is meant to be a blank page for further developments. -/// \author everyone -#include +/// \file flowPtEfficiency.cxx +/// \author Mingrui Zhao (mingrui.zhao@cern.ch), Zhiyong Lu (zhiyong.lu@cern.ch), Tao Jiang (tao.jiang@cern.ch) +/// \since Jun/08/2023 +/// \brief a task to calculate the pt efficiency + +#include +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" #include "Framework/HistogramRegistry.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "GFWPowerArray.h" +#include "GFW.h" +#include "GFWCumulant.h" +#include "GFWWeights.h" +#include "FlowContainer.h" +#include +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; #define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; -struct flowPtEfficiency { +struct FlowPtEfficiency { O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for tracks") - O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 3.0f, "Maximal pT for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 1000.0f, "Maximal pT for tracks") O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") + O2_DEFINE_CONFIGURABLE(cfgkIsTrackGlobal, bool, false, "GlobalTrack requirement for tracks") + O2_DEFINE_CONFIGURABLE(cfgTrkSelRun3ITSMatch, bool, false, "GlobalTrackRun3ITSMatching::Run3ITSall7Layers selection") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5f, "max chi2 per TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutTPCclu, float, 70.0f, "minimum TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutITSclu, float, 5.0f, "minimum ITS clusters") + O2_DEFINE_CONFIGURABLE(cfgCutTPCcrossedrows, float, 70.0f, "minimum TPC crossed rows") O2_DEFINE_CONFIGURABLE(cfgCutDCAxy, float, 0.2f, "DCAxy cut for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutDCAz, float, 2.0f, "DCAz cut for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutDCAxyppPass3Enabled, bool, false, "switch of ppPass3 DCAxy pt dependent cut") + O2_DEFINE_CONFIGURABLE(cfgCutDCAzPtDepEnabled, bool, false, "switch of DCAz pt dependent cut") + O2_DEFINE_CONFIGURABLE(cfgSelRunNumberEnabled, bool, false, "switch of run number selection") + O2_DEFINE_CONFIGURABLE(cfgFlowEnabled, bool, false, "switch of calculating flow") + O2_DEFINE_CONFIGURABLE(cfgFlowNbootstrap, int, 30, "Number of subsamples") + O2_DEFINE_CONFIGURABLE(cfgFlowCutPtPOIMin, float, 0.2f, "Minimal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgFlowCutPtPOIMax, float, 10.0f, "Maximal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgFlowCutPtRefMin, float, 0.2f, "Minimal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgFlowCutPtRefMax, float, 3.0f, "Maximal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCentVsIPTruth, std::string, "", "CCDB path to centrality vs IP truth") + O2_DEFINE_CONFIGURABLE(cfgCentVsIPReco, std::string, "", "CCDB path to centrality vs IP reco") + O2_DEFINE_CONFIGURABLE(cfgFlowAcceptance, std::string, "", "CCDB path to acceptance object") + O2_DEFINE_CONFIGURABLE(cfgFlowEfficiency, std::string, "", "CCDB path to efficiency object") + Configurable> cfgRunNumberList{"cfgRunNumberList", std::vector{-1}, "runnumber list in consideration for analysis"}; - ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.2, 0.25, 0.30, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.20, 2.40, 2.60, 2.80, 3.00}, "pt axis for histograms"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.2, 2.4, 2.6, 2.8, 3, 3.5, 4, 5, 6, 8, 10}, "pt axis for histograms"}; + ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}, "X axis for histograms"}; + ConfigurableAxis axisPhi{"axisPhi", {100, 0.0f, constants::math::TwoPI}, ""}; + ConfigurableAxis axisB{"axisB", {100, 0.0f, 20.0f}, "b (fm)"}; + ConfigurableAxis axisNch{"axisNch", {6000, 0, 6000}, "N_{ch}"}; // Filter the tracks - Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtMin) && (aod::track::pt < cfgCutPtMax) && (nabs(aod::track::dcaXY) < cfgCutDCAxy); - using myTracks = soa::Filtered>; + Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtMin) && (aod::track::pt < cfgCutPtMax) && (aod::track::tpcChi2NCl < cfgCutChi2prTPCcls); + using MyTracks = soa::Filtered>; + + // Filter for collisions + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + using MyCollisions = soa::Filtered>; // Filter for MCParticle Filter particleFilter = (nabs(aod::mcparticle::eta) < cfgCutEta) && (aod::mcparticle::pt > cfgCutPtMin) && (aod::mcparticle::pt < cfgCutPtMax); - using myMcParticles = soa::Filtered; + using MyMcParticles = soa::Filtered; + + // Filter for MCcollisions + Filter mccollisionFilter = nabs(aod::mccollision::posZ) < cfgCutVertex; + using MyMcCollisions = soa::Filtered; + + Preslice perCollision = aod::track::collisionId; + + // Additional filters for tracks + TrackSelection myTrackSel; + + // Cent vs IP + TH1D* mCentVsIPTruth = nullptr; + bool centVsIPTruthLoaded = false; + TH1D* mCentVsIPReco = nullptr; + bool centVsIPRecoLoaded = false; + + // corrections + TH1D* mEfficiency = nullptr; + GFWWeights* mAcceptance = nullptr; + bool correctionsLoaded = false; + + // Connect to ccdb + Service ccdb; + Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; // Define the output HistogramRegistry registry{"registry"}; + OutputObj fFCTrue{FlowContainer("FlowContainerTrue")}; + OutputObj fFCReco{FlowContainer("FlowContainerReco")}; + OutputObj fWeights{GFWWeights("weights")}; + GFW* fGFWTrue = new GFW(); + GFW* fGFWReco = new GFW(); + TAxis* fPtAxis; + std::vector corrconfigsTruth; + std::vector corrconfigsReco; + TRandom3* fRndm = new TRandom3(0); bool isStable(int pdg) { - if (abs(pdg) == 211) + if (std::abs(pdg) == PDG_t::kPiPlus) return true; - if (abs(pdg) == 321) + if (std::abs(pdg) == PDG_t::kKPlus) return true; - if (abs(pdg) == 2212) + if (std::abs(pdg) == PDG_t::kProton) return true; - if (abs(pdg) == 11) + if (std::abs(pdg) == PDG_t::kElectron) return true; - if (abs(pdg) == 13) + if (std::abs(pdg) == PDG_t::kMuonMinus) return true; return false; } @@ -68,43 +149,367 @@ struct flowPtEfficiency { // create histograms registry.add("eventCounter", "eventCounter", kTH1F, {axisCounter}); registry.add("hPtMCRec", "Monte Carlo Reco", {HistType::kTH1D, {axisPt}}); + registry.add("hPtNchMCRec", "Reco production; pT (GeV/c); multiplicity", {HistType::kTH2D, {axisPt, axisNch}}); + registry.add("hBVsPtVsPhiRec", "hBVsPtVsPhiRec", HistType::kTH3D, {axisB, axisPhi, axisPt}); registry.add("mcEventCounter", "Monte Carlo Truth EventCounter", kTH1F, {axisCounter}); registry.add("hPtMCGen", "Monte Carlo Truth", {HistType::kTH1D, {axisPt}}); + registry.add("hPtNchMCGen", "Truth production; pT (GeV/c); multiplicity", {HistType::kTH2D, {axisPt, axisNch}}); + registry.add("numberOfRecoCollisions", "numberOfRecoCollisions", kTH1F, {{10, -0.5f, 9.5f}}); + registry.add("hBVsPtVsPhiTrue", "hBVsPtVsPhiTrue", HistType::kTH3D, {axisB, axisPhi, axisPt}); + + if (cfgFlowEnabled) { + registry.add("hImpactParameterReco", "hImpactParameterReco", {HistType::kTH1D, {axisB}}); + registry.add("hImpactParameterTruth", "hImpactParameterTruth", {HistType::kTH1D, {axisB}}); + registry.add("hPhi", "#phi distribution", {HistType::kTH1D, {axisPhi}}); + registry.add("hPhiMCTruth", "#phi distribution", {HistType::kTH1D, {axisPhi}}); + registry.add("hPhiWeighted", "corrected #phi distribution", {HistType::kTH1D, {axisPhi}}); + + o2::framework::AxisSpec axis = axisPt; + int nPtBins = axis.binEdges.size() - 1; + double* ptBins = &(axis.binEdges)[0]; + fPtAxis = new TAxis(nPtBins, ptBins); + + fWeights->setPtBins(nPtBins, ptBins); + fWeights->init(true, false); + + TObjArray* oba = new TObjArray(); + oba->Add(new TNamed("ChFull22", "ChFull22")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("ChFull22_pt_%i", i + 1), "ChFull22_pTDiff")); + oba->Add(new TNamed("Ch10Gap22", "Ch10Gap22")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ch10Gap22_pt_%i", i + 1), "Ch10Gap22_pTDiff")); + fFCTrue->SetName("FlowContainerTrue"); + fFCTrue->SetXAxis(fPtAxis); + fFCTrue->Initialize(oba, axisCentrality, cfgFlowNbootstrap); + fFCReco->SetName("FlowContainerReco"); + fFCReco->SetXAxis(fPtAxis); + fFCReco->Initialize(oba, axisCentrality, cfgFlowNbootstrap); + delete oba; + + fGFWTrue->AddRegion("full", -0.8, 0.8, 1, 1); + fGFWTrue->AddRegion("refN10", -0.8, -0.5, 1, 1); + fGFWTrue->AddRegion("refP10", 0.5, 0.8, 1, 1); + fGFWTrue->AddRegion("poiN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 2); + fGFWTrue->AddRegion("poifull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 2); + fGFWTrue->AddRegion("olN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 4); + fGFWTrue->AddRegion("olfull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 4); + corrconfigsTruth.push_back(fGFWTrue->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); + corrconfigsTruth.push_back(fGFWTrue->GetCorrelatorConfig("poifull full | olfull {2 -2}", "ChFull22", kTRUE)); + corrconfigsTruth.push_back(fGFWTrue->GetCorrelatorConfig("refN10 {2} refP10 {-2}", "Ch10Gap22", kFALSE)); + corrconfigsTruth.push_back(fGFWTrue->GetCorrelatorConfig("poiN10 refN10 | olN10 {2} refP10 {-2}", "Ch10Gap22", kTRUE)); + fGFWTrue->CreateRegions(); + + fGFWReco->AddRegion("full", -0.8, 0.8, 1, 1); + fGFWReco->AddRegion("refN10", -0.8, -0.5, 1, 1); + fGFWReco->AddRegion("refP10", 0.5, 0.8, 1, 1); + fGFWReco->AddRegion("poiN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 2); + fGFWReco->AddRegion("poifull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 2); + fGFWReco->AddRegion("olN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 4); + fGFWReco->AddRegion("olfull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 4); + corrconfigsReco.push_back(fGFWReco->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); + corrconfigsReco.push_back(fGFWReco->GetCorrelatorConfig("poifull full | olfull {2 -2}", "ChFull22", kTRUE)); + corrconfigsReco.push_back(fGFWReco->GetCorrelatorConfig("refN10 {2} refP10 {-2}", "Ch10Gap22", kFALSE)); + corrconfigsReco.push_back(fGFWReco->GetCorrelatorConfig("poiN10 refN10 | olN10 {2} refP10 {-2}", "Ch10Gap22", kTRUE)); + fGFWReco->CreateRegions(); + } + + if (cfgTrkSelRun3ITSMatch) { + myTrackSel = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSall7Layers, TrackSelection::GlobalTrackRun3DCAxyCut::Default); + } else { + myTrackSel = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::Default); + } + if (cfgCutDCAxyppPass3Enabled) { + myTrackSel.SetMaxDcaXYPtDep([](float pt) { return 0.004f + 0.013f / pt; }); + } else { + myTrackSel.SetMaxDcaXY(cfgCutDCAxy); + } + myTrackSel.SetMinNClustersTPC(cfgCutTPCclu); + myTrackSel.SetMinNClustersITS(cfgCutITSclu); + myTrackSel.SetMinNCrossedRowsTPC(cfgCutTPCcrossedrows); + if (!cfgCutDCAzPtDepEnabled) + myTrackSel.SetMaxDcaZ(cfgCutDCAz); + } + + template + void fillProfile(GFW* fGFW, const GFW::CorrConfig& corrconf, const ConstStr& tarName, const double& cent) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) + return; + if (!corrconf.pTDif) { + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + registry.fill(tarName, cent, val, dnx); + return; + } + return; + } + + void fillFC(GFW* fGFW, bool isMCTruth, const GFW::CorrConfig& corrconf, const double& cent, const double& rndm) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) + return; + if (!corrconf.pTDif) { + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) { + if (isMCTruth) + fFCTrue->FillProfile(corrconf.Head.c_str(), cent, val, dnx, rndm); + else + fFCReco->FillProfile(corrconf.Head.c_str(), cent, val, dnx, rndm); + } + return; + } + for (auto i = 1; i <= fPtAxis->GetNbins(); i++) { + dnx = fGFW->Calculate(corrconf, i - 1, kTRUE).real(); + if (dnx == 0) + continue; + val = fGFW->Calculate(corrconf, i - 1, kFALSE).real() / dnx; + if (std::fabs(val) < 1) { + if (isMCTruth) + fFCTrue->FillProfile(Form("%s_pt_%i", corrconf.Head.c_str(), i), cent, val, dnx, rndm); + else + fFCReco->FillProfile(Form("%s_pt_%i", corrconf.Head.c_str(), i), cent, val, dnx, rndm); + } + } + return; + } + + void loadCentVsIPTruth(uint64_t timestamp) + { + if (centVsIPTruthLoaded) + return; + if (cfgCentVsIPTruth.value.empty() == false) { + mCentVsIPTruth = ccdb->getForTimeStamp(cfgCentVsIPTruth, timestamp); + if (mCentVsIPTruth) + LOGF(info, "Loaded CentVsIPTruth weights from %s (%p)", cfgCentVsIPTruth.value.c_str(), (void*)mCentVsIPTruth); + else + LOGF(fatal, "Failed to load CentVsIPTruth weights from %s", cfgCentVsIPTruth.value.c_str()); + + centVsIPTruthLoaded = true; + } else { + LOGF(fatal, "when calculate flow, Cent Vs IP distribution must be provided"); + } } - void processReco(o2::aod::Collision const&, myTracks const& tracks, aod::McParticles const&) + void loadCentVsIPReco(uint64_t timestamp) + { + if (centVsIPRecoLoaded) + return; + if (cfgCentVsIPReco.value.empty() == false) { + mCentVsIPReco = ccdb->getForTimeStamp(cfgCentVsIPReco, timestamp); + if (mCentVsIPReco) + LOGF(info, "Loaded CentVsIPReco weights from %s (%p)", cfgCentVsIPReco.value.c_str(), (void*)mCentVsIPReco); + else + LOGF(fatal, "Failed to load CentVsIPReco weights from %s", cfgCentVsIPReco.value.c_str()); + + centVsIPRecoLoaded = true; + } else { + LOGF(fatal, "when calculate flow, Cent Vs IP distribution must be provided"); + } + } + + void loadCorrections(uint64_t timestamp) + { + if (correctionsLoaded) + return; + if (cfgFlowAcceptance.value.empty() == false) { + mAcceptance = ccdb->getForTimeStamp(cfgFlowAcceptance, timestamp); + if (mAcceptance) + LOGF(info, "Loaded acceptance weights from %s (%p)", cfgFlowAcceptance.value.c_str(), (void*)mAcceptance); + else + LOGF(warning, "Could not load acceptance weights from %s (%p)", cfgFlowAcceptance.value.c_str(), (void*)mAcceptance); + } + if (cfgFlowEfficiency.value.empty() == false) { + mEfficiency = ccdb->getForTimeStamp(cfgFlowEfficiency, timestamp); + if (mEfficiency == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgFlowEfficiency.value.c_str()); + } + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgFlowEfficiency.value.c_str(), (void*)mEfficiency); + } + correctionsLoaded = true; + } + + bool setCurrentParticleWeights(float& weight_nue, float& weight_nua, float phi, float eta, float pt, float vtxz) + { + float eff = 1.; + if (mEfficiency) + eff = mEfficiency->GetBinContent(mEfficiency->FindBin(pt)); + else + eff = 1.0; + if (eff == 0) + return false; + weight_nue = 1. / eff; + if (mAcceptance) + weight_nua = mAcceptance->getNUA(phi, eta, vtxz); + else + weight_nua = 1; + return true; + } + + template + bool trackSelected(TTrack track) + { + if (cfgkIsTrackGlobal && !track.isGlobalTrack()) + return false; + if (cfgCutDCAzPtDepEnabled && (track.dcaZ() > (0.004f + 0.013f / track.pt()))) + return false; + return myTrackSel.IsSelected(track); + } + + void processReco(MyCollisions::iterator const& collision, aod::BCsWithTimestamps const&, MyTracks const& tracks, aod::McParticles const&, aod::McCollisions const&) { registry.fill(HIST("eventCounter"), 0.5); + if (!collision.sel8()) + return; + if (tracks.size() < 1) + return; + auto bc = collision.bc_as(); + int runNumber = bc.runNumber(); + if (cfgSelRunNumberEnabled) { + if (!std::count(cfgRunNumberList.value.begin(), cfgRunNumberList.value.end(), runNumber)) + return; + } + + float imp = 0; + bool impFetched = false; + float evPhi = 0; + float centrality = 0.; + float lRandom = fRndm->Rndm(); + float vtxz = collision.posZ(); + float wacc = 1.0f; + float weff = 1.0f; + if (cfgFlowEnabled) { + loadCentVsIPReco(bc.timestamp()); + loadCorrections(bc.timestamp()); + + fGFWReco->Clear(); + } + for (const auto& track : tracks) { - if (track.tpcNClsCrossedRows() < 70) + if (!trackSelected(track)) continue; if (track.has_mcParticle()) { auto mcParticle = track.mcParticle(); + if (cfgFlowEnabled && !impFetched) { + auto mcCollision = mcParticle.mcCollision(); + imp = mcCollision.impactParameter(); + registry.fill(HIST("hImpactParameterReco"), imp); + centrality = mCentVsIPReco->GetBinContent(mCentVsIPReco->GetXaxis()->FindBin(imp)); + evPhi = RecoDecay::constrainAngle(mcCollision.eventPlaneAngle()); + impFetched = true; + } if (isStable(mcParticle.pdgCode())) { registry.fill(HIST("hPtMCRec"), track.pt()); + registry.fill(HIST("hPtNchMCRec"), track.pt(), tracks.size()); + + if (cfgFlowEnabled) { + float deltaPhi = RecoDecay::constrainAngle(track.phi() - evPhi); + registry.fill(HIST("hBVsPtVsPhiRec"), imp, deltaPhi, track.pt()); + bool withinPtPOI = (cfgFlowCutPtPOIMin < track.pt()) && (track.pt() < cfgFlowCutPtPOIMax); // within POI pT range + bool withinPtRef = (cfgFlowCutPtRefMin < track.pt()) && (track.pt() < cfgFlowCutPtRefMax); // within RF pT range + if (withinPtRef) + fWeights->fill(track.phi(), track.eta(), vtxz, track.pt(), centrality, 0); + if (!setCurrentParticleWeights(weff, wacc, track.phi(), track.eta(), track.pt(), vtxz)) + continue; + if (withinPtRef) { + registry.fill(HIST("hPhi"), track.phi()); + registry.fill(HIST("hPhiWeighted"), track.phi(), wacc); + } + if (withinPtRef) + fGFWReco->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), wacc * weff, 1); + if (withinPtPOI) + fGFWReco->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), wacc * weff, 2); + if (withinPtPOI && withinPtRef) + fGFWReco->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), wacc * weff, 4); + } } } } + if (cfgFlowEnabled) { + // Filling Flow Container + for (uint l_ind = 0; l_ind < corrconfigsReco.size(); l_ind++) { + fillFC(fGFWReco, false, corrconfigsReco.at(l_ind), centrality, lRandom); + } + } } - PROCESS_SWITCH(flowPtEfficiency, processReco, "process reconstructed information", true); + PROCESS_SWITCH(FlowPtEfficiency, processReco, "process reconstructed information", true); - void processSim(aod::McCollision const&, soa::SmallGroups> const& collisions, myMcParticles const& mcParticles) + void processSim(MyMcCollisions::iterator const& mcCollision, aod::BCsWithTimestamps const&, soa::SmallGroups> const& collisions, MyMcParticles const& mcParticles, MyTracks const& tracks) { + if (cfgSelRunNumberEnabled) { + auto bc = mcCollision.bc_as(); + int runNumber = bc.runNumber(); + if (!std::count(cfgRunNumberList.value.begin(), cfgRunNumberList.value.end(), runNumber)) + return; + } + + float imp = mcCollision.impactParameter(); + float evPhi = RecoDecay::constrainAngle(mcCollision.eventPlaneAngle()); + float centrality = 0.; + if (cfgFlowEnabled) { + registry.fill(HIST("hImpactParameterTruth"), imp); + auto bc = mcCollision.bc_as(); + loadCentVsIPTruth(bc.timestamp()); + centrality = mCentVsIPTruth->GetBinContent(mCentVsIPTruth->GetXaxis()->FindBin(imp)); + + fGFWTrue->Clear(); + } + float lRandom = fRndm->Rndm(); + float wacc = 1.0f; + float weff = 1.0f; + if (collisions.size() > -1) { registry.fill(HIST("mcEventCounter"), 0.5); + + registry.fill(HIST("numberOfRecoCollisions"), collisions.size()); // number of times coll was reco-ed + + std::vector numberOfTracks; + for (auto const& collision : collisions) { + auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex()); + numberOfTracks.emplace_back(groupedTracks.size()); + } + for (const auto& mcParticle : mcParticles) { if (mcParticle.isPhysicalPrimary() && isStable(mcParticle.pdgCode())) { registry.fill(HIST("hPtMCGen"), mcParticle.pt()); + if (collisions.size() > 0) + registry.fill(HIST("hPtNchMCGen"), mcParticle.pt(), numberOfTracks[0]); + + if (cfgFlowEnabled) { + float deltaPhi = RecoDecay::constrainAngle(mcParticle.phi() - evPhi); + registry.fill(HIST("hBVsPtVsPhiTrue"), imp, deltaPhi, mcParticle.pt()); + bool withinPtPOI = (cfgFlowCutPtPOIMin < mcParticle.pt()) && (mcParticle.pt() < cfgFlowCutPtPOIMax); // within POI pT range + bool withinPtRef = (cfgFlowCutPtRefMin < mcParticle.pt()) && (mcParticle.pt() < cfgFlowCutPtRefMax); // within RF pT range + if (withinPtRef) { + registry.fill(HIST("hPhiMCTruth"), mcParticle.phi()); + } + if (withinPtRef) + fGFWTrue->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), wacc * weff, 1); + if (withinPtPOI) + fGFWTrue->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), wacc * weff, 2); + if (withinPtPOI && withinPtRef) + fGFWTrue->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), wacc * weff, 4); + } + } + } + if (cfgFlowEnabled) { + // Filling Flow Container + for (uint l_ind = 0; l_ind < corrconfigsTruth.size(); l_ind++) { + fillFC(fGFWTrue, true, corrconfigsTruth.at(l_ind), centrality, lRandom); } } } } - PROCESS_SWITCH(flowPtEfficiency, processSim, "process pure simulation information", true); + PROCESS_SWITCH(FlowPtEfficiency, processSim, "process pure simulation information", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGCF/Flow/Tasks/flowQa.cxx b/PWGCF/Flow/Tasks/flowQa.cxx new file mode 100644 index 00000000000..1eaa6d8437d --- /dev/null +++ b/PWGCF/Flow/Tasks/flowQa.cxx @@ -0,0 +1,792 @@ +// 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 flowQa.cxx +/// \author Zhiyong Lu (zhiyong.lu@cern.ch) +/// \since Feb/23/2025 +/// \brief jira: PWGCF-254, QA for flow analysis + +#include +#include +#include +#include +#include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/CCDB/ctpRateFetcher.h" + +#include "GFWPowerArray.h" +#include "GFW.h" +#include "GFWCumulant.h" +#include "GFWWeights.h" +#include "FlowContainer.h" +#include "TList.h" +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct FlowQa { + + O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCentEstimator, int, 0, "0:FT0C; 1:FT0CVariant1; 2:FT0M; 3:FT0A") + O2_DEFINE_CONFIGURABLE(cfgCentFT0CMin, float, 0.0f, "Minimum centrality (FT0C) to cut events in filter") + O2_DEFINE_CONFIGURABLE(cfgCentFT0CMax, float, 100.0f, "Maximum centrality (FT0C) to cut events in filter") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMin, float, 0.2f, "Minimal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMax, float, 10.0f, "Maximal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtRefMin, float, 0.2f, "Minimal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtRefMax, float, 3.0f, "Maximal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for all tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 10.0f, "Maximal pT for all tracks") + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutTPCclu, float, 30.0f, "minimum TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutITSclu, float, 5.0f, "minimum ITS clusters") + O2_DEFINE_CONFIGURABLE(cfgCutITSTPCcluEnabled, bool, false, "switch of minimum ITS/TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutDCAz, float, 2.0f, "max DCA to vertex z") + O2_DEFINE_CONFIGURABLE(cfgCutDCAxyppPass3Enabled, bool, false, "switch of ppPass3 DCAxy pt dependent cut") + O2_DEFINE_CONFIGURABLE(cfgCutDCAzPtDepEnabled, bool, false, "switch of DCAz pt dependent cut") + O2_DEFINE_CONFIGURABLE(cfgTrackType, int, 0, "0:Global; 1:GlobalSDD; 2:QualityITS; 3:QualityTPC; 4:ITS; 5: TPC; 6:GloalorITS; 7: GlobalorTPC") + O2_DEFINE_CONFIGURABLE(cfgUseAdditionalEventCut, bool, false, "Use additional event cut on mult correlations") + O2_DEFINE_CONFIGURABLE(cfgUseTentativeEventCounter, bool, false, "After sel8(), count events regardless of real event selection") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoSameBunchPileup, bool, false, "rejects collisions which are associated with the same found-by-T0 bunch crossing") + O2_DEFINE_CONFIGURABLE(cfgEvSelkIsGoodZvtxFT0vsPV, bool, false, "removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference, use this cut at low multiplicities with caution") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoCollInTimeRangeStandard, bool, false, "no collisions in specified time range") + O2_DEFINE_CONFIGURABLE(cfgEvSelkIsGoodITSLayersAll, bool, true, "cut time intervals with dead ITS staves") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoCollInRofStandard, bool, false, "no other collisions in this Readout Frame with per-collision multiplicity above threshold") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoHighMultCollInPrevRof, bool, false, "veto an event if FT0C amplitude in previous ITS ROF is above threshold") + O2_DEFINE_CONFIGURABLE(cfgGetInteractionRate, bool, false, "Get interaction rate from CCDB") + O2_DEFINE_CONFIGURABLE(cfgUseInteractionRateCut, bool, false, "Use events with low interaction rate") + O2_DEFINE_CONFIGURABLE(cfgCutMaxIR, float, 50.0f, "maximum interaction rate (kHz)") + O2_DEFINE_CONFIGURABLE(cfgCutMinIR, float, 0.0f, "minimum interaction rate (kHz)") + O2_DEFINE_CONFIGURABLE(cfgUseNch, bool, false, "Use Nch for flow observables") + O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 30, "Number of subsamples") + O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeights, bool, false, "Fill and output NUA weights") + O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeightsRefPt, bool, false, "NUA weights are filled in ref pt bins") + O2_DEFINE_CONFIGURABLE(cfgEfficiency, std::string, "", "CCDB path to efficiency object") + O2_DEFINE_CONFIGURABLE(cfgAcceptance, std::string, "", "CCDB path to acceptance object") + O2_DEFINE_CONFIGURABLE(cfgAcceptanceList, std::string, "", "CCDB path to acceptance lsit object") + O2_DEFINE_CONFIGURABLE(cfgAcceptanceListEnabled, bool, false, "switch of acceptance list") + O2_DEFINE_CONFIGURABLE(cfgEvSelOccupancy, bool, true, "Occupancy cut") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyHigh, int, 500, "High cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyLow, int, 0, "Low cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgUseSmallMemory, bool, false, "Use small memory mode") + O2_DEFINE_CONFIGURABLE(cfgTrackDensityCorrUse, bool, false, "Use track density efficiency correction") + O2_DEFINE_CONFIGURABLE(cfgTrackDensityCorrSlopeFactor, float, 1.0f, "A factor to scale the track density efficiency slope") + Configurable> cfgUserDefineGFWCorr{"cfgUserDefineGFWCorr", std::vector{"refN02 {2} refP02 {-2}", "refN12 {2} refP12 {-2}"}, "User defined GFW CorrelatorConfig"}; + Configurable> cfgUserDefineGFWName{"cfgUserDefineGFWName", std::vector{"Ch02Gap22", "Ch12Gap22"}, "User defined GFW Name"}; + Configurable> cfgRunRemoveList{"cfgRunRemoveList", std::vector{-1}, "excluded run numbers"}; + Configurable> cfgTrackDensityP0{"cfgTrackDensityP0", std::vector{0.6003720411, 0.6152630970, 0.6288860646, 0.6360694031, 0.6409494798, 0.6450540203, 0.6482117301, 0.6512592056, 0.6640008690, 0.6862631416, 0.7005738691, 0.7106567432, 0.7170728333}, "parameter 0 for track density efficiency correction"}; + Configurable> cfgTrackDensityP1{"cfgTrackDensityP1", std::vector{-1.007592e-05, -8.932635e-06, -9.114538e-06, -1.054818e-05, -1.220212e-05, -1.312304e-05, -1.376433e-05, -1.412813e-05, -1.289562e-05, -1.050065e-05, -8.635725e-06, -7.380821e-06, -6.201250e-06}, "parameter 1 for track density efficiency correction"}; + + ConfigurableAxis axisPtHist{"axisPtHist", {100, 0., 10.}, "pt axis for histograms"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.2, 2.4, 2.6, 2.8, 3, 3.5, 4, 5, 6, 8, 10}, "pt axis for histograms"}; + ConfigurableAxis axisIndependent{"axisIndependent", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}, "X axis for histograms"}; + ConfigurableAxis axisNch{"axisNch", {4000, 0, 4000}, "N_{ch}"}; + ConfigurableAxis axisDCAz{"axisDCAz", {200, -2, 2}, "DCA_{z} (cm)"}; + ConfigurableAxis axisDCAxy{"axisDCAxy", {200, -1, 1}, "DCA_{xy} (cm)"}; + + Filter collisionFilter = (nabs(aod::collision::posZ) < cfgCutVertex) && (aod::cent::centFT0C > cfgCentFT0CMin) && (aod::cent::centFT0C < cfgCentFT0CMax); + Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtMin) && (aod::track::pt < cfgCutPtMax) && (nabs(aod::track::dcaZ) < cfgCutDCAz); + + // Corrections + TH1D* mEfficiency = nullptr; + GFWWeights* mAcceptance = nullptr; + TObjArray* mAcceptanceList = nullptr; + bool correctionsLoaded = false; + + // Connect to ccdb + Service ccdb; + Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + // Define output + OutputObj fFC{FlowContainer("FlowContainer")}; + OutputObj fWeights{GFWWeights("weights")}; + HistogramRegistry registry{"registry"}; + + // define global variables + GFW* fGFW = new GFW(); + std::vector corrconfigs; + TAxis* fPtAxis; + TRandom3* fRndm = new TRandom3(0); + enum CentEstimators { + kCentFT0C = 0, + kCentFT0CVariant1, + kCentFT0M, + kCentFV0A, + // Count the total number of enum + kCount_CentEstimators + }; + enum TrackType { + kGlobalTrack = 0, + kGlobalTrackSDD, + kQualityTracksITS, + kQualityTracksTPC, + kITSTracks, + kTPCTracks, + kGlobalOrITSTracks, + kGlobalOrTPCTracks, + // Count the total number of enum + kCount_TrackType + }; + int mRunNumber{-1}; + uint64_t mSOR{0}; + double mMinSeconds{-1.}; + std::unordered_map gHadronicRate; + ctpRateFetcher mRateFetcher; + TH2* gCurrentHadronicRate; + + std::vector funcEff; + TH1D* hFindPtBin; + TF1* funcV2; + TF1* funcV3; + TF1* funcV4; + + using AodCollisions = soa::Filtered>; + using AodTracks = soa::Filtered>; + + void init(InitContext const&) + { + const AxisSpec axisVertex{40, -20, 20, "Vtxz (cm)"}; + const AxisSpec axisPhi{60, 0.0, constants::math::TwoPI, "#varphi"}; + const AxisSpec axisEta{40, -1., 1., "#eta"}; + const AxisSpec axisCentForQA{100, 0, 100, "centrality (%)"}; + const AxisSpec axisT0C{70, 0, 70000, "N_{ch} (T0C)"}; + const AxisSpec axisT0A{200, 0, 200000, "N_{ch} (T0A)"}; + + ccdb->setURL(ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setCreatedNotAfter(ccdbNoLaterThan.value); + + // Add some output objects to the histogram registry + // Event QA + registry.add("hEventCount", "Number of Event;; Count", {HistType::kTH1D, {{5, 0, 5}}}); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(1, "Filtered event"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(2, "after sel8"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(3, "after supicious Runs removal"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(4, "after additional event cut"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(5, "after correction loads"); + registry.add("hEventCountSpecific", "Number of Event;; Count", {HistType::kTH1D, {{8, 0, 8}}}); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(1, "after sel8"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(2, "kNoSameBunchPileup"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(3, "kIsGoodZvtxFT0vsPV"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(4, "kNoCollInTimeRangeStandard"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(5, "kIsGoodITSLayersAll"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(6, "kNoCollInRofStandard"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(7, "kNoHighMultCollInPrevRof"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(8, "occupancy"); + if (cfgUseTentativeEventCounter) { + registry.add("hEventCountTentative", "Number of Event;; Count", {HistType::kTH1D, {{8, 0, 8}}}); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(1, "after sel8"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(2, "kNoSameBunchPileup"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(3, "kIsGoodZvtxFT0vsPV"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(4, "kNoCollInTimeRangeStandard"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(5, "kIsGoodITSLayersAll"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(6, "kNoCollInRofStandard"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(7, "kNoHighMultCollInPrevRof"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(8, "occupancy"); + } + registry.add("hVtxZ", "Vexter Z distribution", {HistType::kTH1D, {axisVertex}}); + std::string hMultTitle = "Multiplicity distribution, TrackType " + std::to_string(cfgTrackType); + registry.add("hMult", hMultTitle.c_str(), {HistType::kTH1D, {{6000, 0, 6000}}}); + std::string hCentTitle = "Centrality distribution, Estimator " + std::to_string(cfgCentEstimator); + registry.add("hCent", hCentTitle.c_str(), {HistType::kTH1D, {{90, 0, 90}}}); + if (!cfgUseSmallMemory) { + registry.add("BeforeSel8_Tracks_centT0C", "before sel8;Centrality T0C;mulplicity tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + registry.add("BeforeCut_Tracks_centT0C", "before cut;Centrality T0C;mulplicity tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + registry.add("BeforeCut_PVTracks_centT0C", "before cut;Centrality T0C;mulplicity PV tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + registry.add("BeforeCut_Tracks_PVTracks", "before cut;mulplicity PV tracks;mulplicity tracks", {HistType::kTH2D, {axisNch, axisNch}}); + registry.add("BeforeCut_Tracks_multT0A", "before cut;mulplicity T0A;mulplicity tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + registry.add("BeforeCut_Tracks_multV0A", "before cut;mulplicity V0A;mulplicity tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + registry.add("BeforeCut_multV0A_multT0A", "before cut;mulplicity T0A;mulplicity V0A", {HistType::kTH2D, {axisT0A, axisT0A}}); + registry.add("BeforeCut_multT0C_centT0C", "before cut;Centrality T0C;mulplicity T0C", {HistType::kTH2D, {axisCentForQA, axisT0C}}); + registry.add("Tracks_centT0C", "after cut;Centrality T0C;mulplicity tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + registry.add("PVTracks_centT0C", "after cut;Centrality T0C;mulplicity PV tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + registry.add("Tracks_PVTracks", "after cut;mulplicity PV tracks;mulplicity tracks", {HistType::kTH2D, {axisNch, axisNch}}); + registry.add("Tracks_multT0A", "after cut;mulplicity T0A;mulplicity tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + registry.add("Tracks_multV0A", "after cut;mulplicity V0A;mulplicity tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + registry.add("multV0A_multT0A", "after cut;mulplicity T0A;mulplicity V0A", {HistType::kTH2D, {axisT0A, axisT0A}}); + registry.add("multT0C_centT0C", "after cut;Centrality T0C;mulplicity T0C", {HistType::kTH2D, {axisCentForQA, axisT0C}}); + registry.add("centFT0CVar_centFT0C", "after cut;Centrality T0C;Centrality T0C Var", {HistType::kTH2D, {axisCentForQA, axisCentForQA}}); + registry.add("centFT0M_centFT0C", "after cut;Centrality T0C;Centrality T0M", {HistType::kTH2D, {axisCentForQA, axisCentForQA}}); + registry.add("centFV0A_centFT0C", "after cut;Centrality T0C;Centrality V0A", {HistType::kTH2D, {axisCentForQA, axisCentForQA}}); + } + // Track QA + registry.add("hPhi", "#phi distribution", {HistType::kTH1D, {axisPhi}}); + registry.add("hPhiWeighted", "corrected #phi distribution", {HistType::kTH1D, {axisPhi}}); + registry.add("hPhiWeightedTrDen", "corrected #phi distribution, considering track density", {HistType::kTH1D, {axisPhi}}); + registry.add("hEta", "#eta distribution", {HistType::kTH1D, {axisEta}}); + registry.add("hPt", "p_{T} distribution before cut", {HistType::kTH1D, {axisPtHist}}); + registry.add("hPtRef", "p_{T} distribution after cut", {HistType::kTH1D, {axisPtHist}}); + registry.add("hChi2prTPCcls", "#chi^{2}/cluster for the TPC track segment", {HistType::kTH1D, {{100, 0., 5.}}}); + registry.add("hChi2prITScls", "#chi^{2}/cluster for the ITS track", {HistType::kTH1D, {{100, 0., 50.}}}); + registry.add("hnTPCClu", "Number of found TPC clusters", {HistType::kTH1D, {{100, 40, 180}}}); + registry.add("hnITSClu", "Number of found ITS clusters", {HistType::kTH1D, {{100, 0, 20}}}); + registry.add("hnTPCCrossedRow", "Number of crossed TPC Rows", {HistType::kTH1D, {{100, 40, 180}}}); + registry.add("hDCAz", "DCAz after cuts; DCAz (cm); Pt", {HistType::kTH2D, {{200, -0.5, 0.5}, {200, 0, 5}}}); + registry.add("hDCAxy", "DCAxy after cuts; DCAxy (cm); Pt", {HistType::kTH2D, {{200, -0.5, 0.5}, {200, 0, 5}}}); + registry.add("hTrackCorrection2d", "Correlation table for number of tracks table; uncorrected track; corrected track", {HistType::kTH2D, {axisNch, axisNch}}); + + o2::framework::AxisSpec axis = axisPt; + int nPtBins = axis.binEdges.size() - 1; + double* ptBins = &(axis.binEdges)[0]; + fPtAxis = new TAxis(nPtBins, ptBins); + + if (cfgOutputNUAWeights) { + fWeights->setPtBins(nPtBins, ptBins); + fWeights->init(true, false); + } + + // add in FlowContainer to Get boostrap sample automatically + TObjArray* oba = new TObjArray(); + oba->Add(new TNamed("ChGap22", "ChGap22")); + oba->Add(new TNamed("ChFull22", "ChFull22")); + oba->Add(new TNamed("ChFull32", "ChFull32")); + oba->Add(new TNamed("ChFull42", "ChFull42")); + oba->Add(new TNamed("ChFull24", "ChFull24")); + oba->Add(new TNamed("ChFull26", "ChFull26")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("ChFull22_pt_%i", i + 1), "ChFull22_pTDiff")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("ChFull24_pt_%i", i + 1), "ChFull24_pTDiff")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("ChFull26_pt_%i", i + 1), "ChFull26_pTDiff")); + oba->Add(new TNamed("Ch10Gap22", "Ch10Gap22")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ch10Gap22_pt_%i", i + 1), "Ch10Gap22_pTDiff")); + oba->Add(new TNamed("Ch10Gap32", "Ch10Gap32")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ch10Gap32_pt_%i", i + 1), "Ch10Gap32_pTDiff")); + oba->Add(new TNamed("Ch10Gap42", "Ch10Gap42")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ch10Gap42_pt_%i", i + 1), "Ch10Gap42_pTDiff")); + oba->Add(new TNamed("Ch10GapA422", "Ch10GapA422")); + oba->Add(new TNamed("Ch10GapB422", "Ch10GapB422")); + oba->Add(new TNamed("ChFull3232", "ChFull3232")); + oba->Add(new TNamed("ChFull4242", "ChFull4242")); + oba->Add(new TNamed("Ch10Gap24", "Ch10Gap24")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ch10Gap24_pt_%i", i + 1), "Ch10Gap24_pTDiff")); + std::vector userDefineGFWCorr = cfgUserDefineGFWCorr; + std::vector userDefineGFWName = cfgUserDefineGFWName; + if (!userDefineGFWCorr.empty() && !userDefineGFWName.empty()) { + for (uint i = 0; i < userDefineGFWName.size(); i++) { + oba->Add(new TNamed(userDefineGFWName.at(i).c_str(), userDefineGFWName.at(i).c_str())); + } + } + fFC->SetName("FlowContainer"); + fFC->SetXAxis(fPtAxis); + fFC->Initialize(oba, axisIndependent, cfgNbootstrap); + delete oba; + + // eta region + fGFW->AddRegion("full", -0.8, 0.8, 1, 1); + fGFW->AddRegion("refN00", -0.8, 0., 1, 1); // gap0 negative region + fGFW->AddRegion("refP00", 0., 0.8, 1, 1); // gap0 positve region + fGFW->AddRegion("refN02", -0.8, -0.1, 1, 1); // gap2 negative region + fGFW->AddRegion("refP02", 0.1, 0.8, 1, 1); // gap2 positve region + fGFW->AddRegion("refN04", -0.8, -0.2, 1, 1); // gap4 negative region + fGFW->AddRegion("refP04", 0.2, 0.8, 1, 1); // gap4 positve region + fGFW->AddRegion("refN06", -0.8, -0.3, 1, 1); // gap6 negative region + fGFW->AddRegion("refP06", 0.3, 0.8, 1, 1); // gap6 positve region + fGFW->AddRegion("refN08", -0.8, -0.4, 1, 1); + fGFW->AddRegion("refP08", 0.4, 0.8, 1, 1); + fGFW->AddRegion("refN10", -0.8, -0.5, 1, 1); + fGFW->AddRegion("refP10", 0.5, 0.8, 1, 1); + fGFW->AddRegion("refN12", -0.8, -0.6, 1, 1); + fGFW->AddRegion("refP12", 0.6, 0.8, 1, 1); + fGFW->AddRegion("refN14", -0.8, -0.7, 1, 1); + fGFW->AddRegion("refP14", 0.7, 0.8, 1, 1); + fGFW->AddRegion("refN", -0.8, -0.4, 1, 1); + fGFW->AddRegion("refP", 0.4, 0.8, 1, 1); + fGFW->AddRegion("refM", -0.4, 0.4, 1, 1); + fGFW->AddRegion("poiN", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poifull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("olN", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olfull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 4); + + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {3 -3}", "ChFull32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {4 -4}", "ChFull42", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 2 -2 -2}", "ChFull24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 2 2 -2 -2 -2}", "ChFull26", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {2} refP10 {-2}", "Ch10Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {3} refP10 {-3}", "Ch10Gap32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {4} refP10 {-4}", "Ch10Gap42", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN {2} refP {-2}", "ChGap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poifull full | olfull {2 -2}", "ChFull22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poifull full | olfull {2 2 -2 -2}", "ChFull24", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poifull full | olfull {2 2 2 -2 -2 -2}", "ChFull26", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiN10 refN10 | olN10 {2} refP10 {-2}", "Ch10Gap22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiN10 refN10 | olN10 {3} refP10 {-3}", "Ch10Gap32", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiN10 refN10 | olN10 {4} refP10 {-4}", "Ch10Gap42", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {-2 -2} refP10 {4}", "Ch10GapA422", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {4} refP10 {-2 -2}", "Ch10GapB422", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {3 2 -3 -2}", "ChFull3232", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {4 2 -4 -2}", "ChFull4242", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {2 2} refP10 {-2 -2}", "Ch10Gap24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiN10 refN10 | olN10 {2 2} refP10 {-2 -2}", "Ch10Gap24", kTRUE)); + if (!userDefineGFWCorr.empty() && !userDefineGFWName.empty()) { + LOGF(info, "User adding GFW CorrelatorConfig:"); + // attentaion: here we follow the index of cfgUserDefineGFWCorr + for (uint i = 0; i < userDefineGFWCorr.size(); i++) { + if (i >= userDefineGFWName.size()) { + LOGF(fatal, "The names you provided are more than configurations. userDefineGFWName.size(): %d > userDefineGFWCorr.size(): %d", userDefineGFWName.size(), userDefineGFWCorr.size()); + break; + } + LOGF(info, "%d: %s %s", i, userDefineGFWCorr.at(i).c_str(), userDefineGFWName.at(i).c_str()); + corrconfigs.push_back(fGFW->GetCorrelatorConfig(userDefineGFWCorr.at(i).c_str(), userDefineGFWName.at(i).c_str(), kFALSE)); + } + } + fGFW->CreateRegions(); + + if (cfgTrackDensityCorrUse) { + std::vector pTEffBins = {0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.4, 1.8, 2.2, 2.6, 3.0}; + hFindPtBin = new TH1D("hFindPtBin", "hFindPtBin", pTEffBins.size() - 1, &pTEffBins[0]); + funcEff.resize(pTEffBins.size() - 1); + // LHC24g3 Eff + std::vector f1p0 = cfgTrackDensityP0; + std::vector f1p1 = cfgTrackDensityP1; + for (uint ifunc = 0; ifunc < pTEffBins.size() - 1; ifunc++) { + funcEff[ifunc] = new TF1(Form("funcEff%i", ifunc), "[0]+[1]*x", 0, 3000); + funcEff[ifunc]->SetParameters(f1p0[ifunc], f1p1[ifunc] * cfgTrackDensityCorrSlopeFactor); + } + funcV2 = new TF1("funcV2", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV2->SetParameters(0.0186111, 0.00351907, -4.38264e-05, 1.35383e-07, -3.96266e-10); + funcV3 = new TF1("funcV3", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV3->SetParameters(0.0174056, 0.000703329, -1.45044e-05, 1.91991e-07, -1.62137e-09); + funcV4 = new TF1("funcV4", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV4->SetParameters(0.008845, 0.000259668, -3.24435e-06, 4.54837e-08, -6.01825e-10); + } + } + + template + void fillProfile(const GFW::CorrConfig& corrconf, const ConstStr& tarName, const double& cent) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) + return; + if (!corrconf.pTDif) { + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + registry.fill(tarName, cent, val, dnx); + return; + } + return; + } + + void fillFC(const GFW::CorrConfig& corrconf, const double& cent, const double& rndm) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) + return; + if (!corrconf.pTDif) { + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + fFC->FillProfile(corrconf.Head.c_str(), cent, val, dnx, rndm); + return; + } + for (auto i = 1; i <= fPtAxis->GetNbins(); i++) { + dnx = fGFW->Calculate(corrconf, i - 1, kTRUE).real(); + if (dnx == 0) + continue; + val = fGFW->Calculate(corrconf, i - 1, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + fFC->FillProfile(Form("%s_pt_%i", corrconf.Head.c_str(), i), cent, val, dnx, rndm); + } + return; + } + + void loadCorrections(uint64_t timestamp, int runNumber) + { + if (correctionsLoaded) + return; + if (!cfgAcceptanceListEnabled && cfgAcceptance.value.empty() == false) { + mAcceptance = ccdb->getForTimeStamp(cfgAcceptance, timestamp); + if (mAcceptance) + LOGF(info, "Loaded acceptance weights from %s (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance); + else + LOGF(warning, "Could not load acceptance weights from %s (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance); + } + if (cfgAcceptanceListEnabled && cfgAcceptanceList.value.empty() == false) { + mAcceptanceList = ccdb->getForTimeStamp(cfgAcceptanceList, timestamp); + if (mAcceptanceList == nullptr) { + LOGF(fatal, "Could not load acceptance weights list from %s", cfgAcceptanceList.value.c_str()); + } + LOGF(info, "Loaded acceptance weights list from %s (%p)", cfgAcceptanceList.value.c_str(), (void*)mAcceptanceList); + + mAcceptance = static_cast(mAcceptanceList->FindObject(Form("%d", runNumber))); + if (mAcceptance == nullptr) { + LOGF(fatal, "Could not find acceptance weights for run %d in acceptance list", runNumber); + } + LOGF(info, "Loaded acceptance weights (%p) for run %d from list (%p)", (void*)mAcceptance, runNumber, (void*)mAcceptanceList); + } + if (cfgEfficiency.value.empty() == false) { + mEfficiency = ccdb->getForTimeStamp(cfgEfficiency, timestamp); + if (mEfficiency == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgEfficiency.value.c_str()); + } + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgEfficiency.value.c_str(), (void*)mEfficiency); + } + correctionsLoaded = true; + } + + bool setCurrentParticleWeights(float& weight_nue, float& weight_nua, float phi, float eta, float pt, float vtxz) + { + float eff = 1.; + if (mEfficiency) + eff = mEfficiency->GetBinContent(mEfficiency->FindBin(pt)); + else + eff = 1.0; + if (eff == 0) + return false; + weight_nue = 1. / eff; + + if (mAcceptance) + weight_nua = mAcceptance->getNUA(phi, eta, vtxz); + else + weight_nua = 1; + return true; + } + + template + bool eventSelected(TCollision collision) + { + registry.fill(HIST("hEventCountSpecific"), 0.5); + if (cfgEvSelkNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + // rejects collisions which are associated with the same "found-by-T0" bunch crossing + // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof + return 0; + } + if (cfgEvSelkNoSameBunchPileup) + registry.fill(HIST("hEventCountSpecific"), 1.5); + if (cfgEvSelkIsGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference + // use this cut at low multiplicities with caution + return 0; + } + if (cfgEvSelkIsGoodZvtxFT0vsPV) + registry.fill(HIST("hEventCountSpecific"), 2.5); + if (cfgEvSelkNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // no collisions in specified time range + return 0; + } + if (cfgEvSelkNoCollInTimeRangeStandard) + registry.fill(HIST("hEventCountSpecific"), 3.5); + if (cfgEvSelkIsGoodITSLayersAll && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + // from Jan 9 2025 AOT meeting + // cut time intervals with dead ITS staves + return 0; + } + if (cfgEvSelkIsGoodITSLayersAll) + registry.fill(HIST("hEventCountSpecific"), 4.5); + if (cfgEvSelkNoCollInRofStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + // no other collisions in this Readout Frame with per-collision multiplicity above threshold + return 0; + } + if (cfgEvSelkNoCollInRofStandard) + registry.fill(HIST("hEventCountSpecific"), 5.5); + if (cfgEvSelkNoHighMultCollInPrevRof && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + // veto an event if FT0C amplitude in previous ITS ROF is above threshold + return 0; + } + if (cfgEvSelkNoHighMultCollInPrevRof) + registry.fill(HIST("hEventCountSpecific"), 6.5); + auto occupancy = collision.trackOccupancyInTimeRange(); + if (cfgEvSelOccupancy && (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh)) + return 0; + if (cfgEvSelOccupancy) + registry.fill(HIST("hEventCountSpecific"), 7.5); + + return 1; + } + + template + void eventCounterQA(TCollision collision) + { + registry.fill(HIST("hEventCountTentative"), 0.5); + // Regradless of the event selection, fill the event counter histograms + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + registry.fill(HIST("hEventCountTentative"), 1.5); + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + registry.fill(HIST("hEventCountTentative"), 2.5); + if (collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) + registry.fill(HIST("hEventCountTentative"), 3.5); + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) + registry.fill(HIST("hEventCountTentative"), 4.5); + if (collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) + registry.fill(HIST("hEventCountTentative"), 5.5); + if (collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) + registry.fill(HIST("hEventCountTentative"), 6.5); + auto occupancy = collision.trackOccupancyInTimeRange(); + if (!(occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh)) + registry.fill(HIST("hEventCountTentative"), 7.5); + } + + template + bool trackSelected(TTrack track) + { + // track type selection + bool passTrackTypeSelection = false; + switch (cfgTrackType) { + case kGlobalTrack: + passTrackTypeSelection = track.isGlobalTrack(); + break; + case kGlobalTrackSDD: + passTrackTypeSelection = track.isGlobalTrackSDD(); + break; + case kQualityTracksITS: + passTrackTypeSelection = track.isQualityTrackITS(); + break; + case kQualityTracksTPC: + passTrackTypeSelection = track.isQualityTrackTPC(); + break; + case kITSTracks: + passTrackTypeSelection = (track.isQualityTrackITS() && track.isPrimaryTrack() && track.isInAcceptanceTrack()); + break; + case kTPCTracks: + passTrackTypeSelection = (track.isQualityTrackTPC() && track.isPrimaryTrack() && track.isInAcceptanceTrack()); + break; + case kGlobalOrITSTracks: + passTrackTypeSelection = (track.isGlobalTrack() || (track.isQualityTrackITS() && track.isPrimaryTrack() && track.isInAcceptanceTrack())); + break; + case kGlobalOrTPCTracks: + passTrackTypeSelection = (track.isGlobalTrack() || (track.isQualityTrackTPC() && track.isPrimaryTrack() && track.isInAcceptanceTrack())); + break; + } + if (!passTrackTypeSelection) + return false; + + if (cfgCutDCAzPtDepEnabled && (std::fabs(track.dcaZ()) > (0.004f + 0.013f / track.pt()))) + return false; + + if (cfgCutITSTPCcluEnabled && (track.tpcNClsFound() < cfgCutTPCclu || track.itsNCls() < cfgCutITSclu)) + return false; + + return true; + } + + void initHadronicRate(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + if (gHadronicRate.find(mRunNumber) == gHadronicRate.end()) { + auto runDuration = ccdb->getRunDuration(mRunNumber); + mSOR = runDuration.first; + mMinSeconds = std::floor(mSOR * 1.e-3); /// round tsSOR to the highest integer lower than tsSOR + double maxSec = std::ceil(runDuration.second * 1.e-3); /// round tsEOR to the lowest integer higher than tsEOR + const AxisSpec axisSeconds{static_cast((maxSec - mMinSeconds) / 20.f), 0, maxSec - mMinSeconds, "Seconds since SOR"}; + gHadronicRate[mRunNumber] = registry.add(Form("HadronicRate/%i", mRunNumber), ";Time since SOR (s);Hadronic rate (kHz)", kTH2D, {axisSeconds, {510, 0., 51.}}).get(); + } + gCurrentHadronicRate = gHadronicRate[mRunNumber]; + } + + void process(AodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, AodTracks const& tracks) + { + registry.fill(HIST("hEventCount"), 0.5); + if (!cfgUseSmallMemory && tracks.size() >= 1) { + registry.fill(HIST("BeforeSel8_Tracks_centT0C"), collision.centFT0C(), tracks.size()); + } + if (!collision.sel8()) + return; + if (tracks.size() < 1) + return; + registry.fill(HIST("hEventCount"), 1.5); + auto bc = collision.bc_as(); + int currentRunNumber = bc.runNumber(); + for (const auto& ExcludedRun : cfgRunRemoveList.value) { + if (currentRunNumber == ExcludedRun) { + return; + } + } + registry.fill(HIST("hEventCount"), 2.5); + if (!cfgUseSmallMemory) { + registry.fill(HIST("BeforeCut_Tracks_centT0C"), collision.centFT0C(), tracks.size()); + registry.fill(HIST("BeforeCut_PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV()); + registry.fill(HIST("BeforeCut_Tracks_PVTracks"), collision.multNTracksPV(), tracks.size()); + registry.fill(HIST("BeforeCut_Tracks_multT0A"), collision.multFT0A(), tracks.size()); + registry.fill(HIST("BeforeCut_Tracks_multV0A"), collision.multFV0A(), tracks.size()); + registry.fill(HIST("BeforeCut_multV0A_multT0A"), collision.multFT0A(), collision.multFV0A()); + registry.fill(HIST("BeforeCut_multT0C_centT0C"), collision.centFT0C(), collision.multFT0C()); + } + float cent; + switch (cfgCentEstimator) { + case kCentFT0C: + cent = collision.centFT0C(); + break; + case kCentFT0CVariant1: + cent = collision.centFT0CVariant1(); + break; + case kCentFT0M: + cent = collision.centFT0M(); + break; + case kCentFV0A: + cent = collision.centFV0A(); + break; + default: + cent = collision.centFT0C(); + } + if (cfgUseTentativeEventCounter) + eventCounterQA(collision); + if (cfgUseAdditionalEventCut && !eventSelected(collision)) + return; + registry.fill(HIST("hEventCount"), 3.5); + float lRandom = fRndm->Rndm(); + float vtxz = collision.posZ(); + registry.fill(HIST("hVtxZ"), vtxz); + registry.fill(HIST("hMult"), tracks.size()); + registry.fill(HIST("hCent"), cent); + fGFW->Clear(); + if (cfgGetInteractionRate) { + initHadronicRate(bc); + double hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), mRunNumber, "ZNC hadronic") * 1.e-3; // + double seconds = bc.timestamp() * 1.e-3 - mMinSeconds; + if (cfgUseInteractionRateCut && (hadronicRate < cfgCutMinIR || hadronicRate > cfgCutMaxIR)) // cut on hadronic rate + return; + gCurrentHadronicRate->Fill(seconds, hadronicRate); + } + loadCorrections(bc.timestamp(), currentRunNumber); + registry.fill(HIST("hEventCount"), 4.5); + + // fill event QA + if (!cfgUseSmallMemory) { + registry.fill(HIST("Tracks_centT0C"), collision.centFT0C(), tracks.size()); + registry.fill(HIST("PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV()); + registry.fill(HIST("Tracks_PVTracks"), collision.multNTracksPV(), tracks.size()); + registry.fill(HIST("Tracks_multT0A"), collision.multFT0A(), tracks.size()); + registry.fill(HIST("Tracks_multV0A"), collision.multFV0A(), tracks.size()); + registry.fill(HIST("multV0A_multT0A"), collision.multFT0A(), collision.multFV0A()); + registry.fill(HIST("multT0C_centT0C"), collision.centFT0C(), collision.multFT0C()); + registry.fill(HIST("centFT0CVar_centFT0C"), collision.centFT0C(), collision.centFT0CVariant1()); + registry.fill(HIST("centFT0M_centFT0C"), collision.centFT0C(), collision.centFT0M()); + registry.fill(HIST("centFV0A_centFT0C"), collision.centFT0C(), collision.centFV0A()); + } + + // track weights + float weff = 1, wacc = 1; + double nTracksCorrected = 0; + float independent = cent; + if (cfgUseNch) + independent = static_cast(tracks.size()); + + double psi2Est = 0, psi3Est = 0, psi4Est = 0; + float wEPeff = 1; + double v2 = 0, v3 = 0, v4 = 0; + if (cfgTrackDensityCorrUse) { + double q2x = 0, q2y = 0; + double q3x = 0, q3y = 0; + double q4x = 0, q4y = 0; + for (const auto& track : tracks) { + bool withinPtRef = (cfgCutPtRefMin < track.pt()) && (track.pt() < cfgCutPtRefMax); // within RF pT rang + if (withinPtRef) { + q2x += std::cos(2 * track.phi()); + q2y += std::sin(2 * track.phi()); + q3x += std::cos(3 * track.phi()); + q3y += std::sin(3 * track.phi()); + q4x += std::cos(4 * track.phi()); + q4y += std::sin(4 * track.phi()); + } + } + psi2Est = std::atan2(q2y, q2x) / 2.; + psi3Est = std::atan2(q3y, q3x) / 3.; + psi4Est = std::atan2(q4y, q4x) / 4.; + v2 = funcV2->Eval(cent); + v3 = funcV3->Eval(cent); + v4 = funcV4->Eval(cent); + } + + for (const auto& track : tracks) { + if (!trackSelected(track)) + continue; + bool withinPtPOI = (cfgCutPtPOIMin < track.pt()) && (track.pt() < cfgCutPtPOIMax); // within POI pT range + bool withinPtRef = (cfgCutPtRefMin < track.pt()) && (track.pt() < cfgCutPtRefMax); // within RF pT range + if (cfgOutputNUAWeights) { + if (cfgOutputNUAWeightsRefPt) { + if (withinPtRef) + fWeights->fill(track.phi(), track.eta(), vtxz, track.pt(), cent, 0); + } else { + fWeights->fill(track.phi(), track.eta(), vtxz, track.pt(), cent, 0); + } + } + if (!setCurrentParticleWeights(weff, wacc, track.phi(), track.eta(), track.pt(), vtxz)) + continue; + if (cfgTrackDensityCorrUse && withinPtRef) { + double fphi = v2 * std::cos(2 * (track.phi() - psi2Est)) + v3 * std::cos(3 * (track.phi() - psi3Est)) + v4 * std::cos(4 * (track.phi() - psi4Est)); + fphi = (1 + 2 * fphi); + int pTBinForEff = hFindPtBin->FindBin(track.pt()); + if (pTBinForEff >= 1 && pTBinForEff <= hFindPtBin->GetNbinsX()) { + wEPeff = funcEff[pTBinForEff - 1]->Eval(fphi * tracks.size()); + if (wEPeff > 0.) { + wEPeff = 1. / wEPeff; + weff *= wEPeff; + registry.fill(HIST("hPhiWeightedTrDen"), track.phi(), wacc * wEPeff); + } + } + } + registry.fill(HIST("hPt"), track.pt()); + if (withinPtRef) { + registry.fill(HIST("hPhi"), track.phi()); + registry.fill(HIST("hPhiWeighted"), track.phi(), wacc); + registry.fill(HIST("hEta"), track.eta()); + registry.fill(HIST("hPtRef"), track.pt()); + registry.fill(HIST("hChi2prTPCcls"), track.tpcChi2NCl()); + registry.fill(HIST("hChi2prITScls"), track.itsChi2NCl()); + registry.fill(HIST("hnTPCClu"), track.tpcNClsFound()); + registry.fill(HIST("hnITSClu"), track.itsNCls()); + registry.fill(HIST("hnTPCCrossedRow"), track.tpcNClsCrossedRows()); + registry.fill(HIST("hDCAz"), track.dcaZ(), track.pt()); + registry.fill(HIST("hDCAxy"), track.dcaXY(), track.pt()); + nTracksCorrected += weff; + } + if (withinPtRef) + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), wacc * weff, 1); + if (withinPtPOI) + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), wacc * weff, 2); + if (withinPtPOI && withinPtRef) + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), wacc * weff, 4); + } + registry.fill(HIST("hTrackCorrection2d"), tracks.size(), nTracksCorrected); + + // Filling Flow Container + for (uint l_ind = 0; l_ind < corrconfigs.size(); l_ind++) { + fillFC(corrconfigs.at(l_ind), independent, lRandom); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Flow/Tasks/flowRunbyRun.cxx b/PWGCF/Flow/Tasks/flowRunbyRun.cxx new file mode 100644 index 00000000000..620063e1d5d --- /dev/null +++ b/PWGCF/Flow/Tasks/flowRunbyRun.cxx @@ -0,0 +1,560 @@ +// 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 flowRunbyRun.cxx +/// \author Zhiyong Lu (zhiyong.lu@cern.ch) +/// \since Oct/30/2024 +/// \brief jira: PWGCF-254, produce Run-by-Run QA plots and flow analysis for Run3 + +#include +#include +#include +#include +#include +#include +#include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/CCDB/ctpRateFetcher.h" + +#include "GFWPowerArray.h" +#include "GFW.h" +#include "GFWCumulant.h" +#include "GFWWeights.h" +#include "FlowContainer.h" +#include "TList.h" +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct FlowRunbyRun { + + O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMin, float, 0.2f, "Minimal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMax, float, 10.0f, "Maximal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtRefMin, float, 0.2f, "Minimal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtRefMax, float, 3.0f, "Maximal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for all tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 10.0f, "Maximal pT for all tracks") + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5, "Chi2 per TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutTPCclu, float, 70.0f, "minimum TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutITSclu, float, 5.0f, "minimum ITS clusters") + O2_DEFINE_CONFIGURABLE(cfgCutDCAz, float, 2.0f, "max DCA to vertex z") + O2_DEFINE_CONFIGURABLE(cfgCutDCAzPtDepEnabled, bool, false, "switch of DCAz pt dependent cut") + O2_DEFINE_CONFIGURABLE(cfgUseAdditionalEventCut, bool, false, "Use additional event cut on mult correlations") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoSameBunchPileup, bool, false, "rejects collisions which are associated with the same found-by-T0 bunch crossing") + O2_DEFINE_CONFIGURABLE(cfgEvSelkIsGoodZvtxFT0vsPV, bool, false, "removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference, use this cut at low multiplicities with caution") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoCollInTimeRangeStandard, bool, false, "no collisions in specified time range") + O2_DEFINE_CONFIGURABLE(cfgEvSelkIsGoodITSLayersAll, bool, true, "cut time intervals with dead ITS staves") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoCollInRofStandard, bool, false, "no other collisions in this Readout Frame with per-collision multiplicity above threshold") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoHighMultCollInPrevRof, bool, false, "veto an event if FT0C amplitude in previous ITS ROF is above threshold") + O2_DEFINE_CONFIGURABLE(cfgEvSelMultCorrelation, bool, true, "Multiplicity correlation cut") + O2_DEFINE_CONFIGURABLE(cfgEvSelV0AT0ACut, bool, true, "V0A T0A 5 sigma cut") + O2_DEFINE_CONFIGURABLE(cfgEvSelOccupancy, bool, true, "Occupancy cut") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyHigh, int, 500, "High cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyLow, int, 0, "Low cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgUseNch, bool, false, "Use Nch for flow observables") + O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 30, "Number of subsamples") + O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeights, bool, false, "NUA weights are filled in ref pt bins") + O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeightsRefPt, bool, false, "NUA weights are filled in ref pt bins") + O2_DEFINE_CONFIGURABLE(cfgEfficiency, std::string, "", "CCDB path to efficiency object") + O2_DEFINE_CONFIGURABLE(cfgAcceptance, std::string, "", "CCDB path to acceptance object") + O2_DEFINE_CONFIGURABLE(cfgAcceptanceList, std::string, "", "CCDB path to acceptance lsit object") + O2_DEFINE_CONFIGURABLE(cfgAcceptanceListEnabled, bool, false, "switch of acceptance list") + O2_DEFINE_CONFIGURABLE(cfgDynamicRunNumber, bool, false, "Add runNumber during runtime") + O2_DEFINE_CONFIGURABLE(cfgGetInteractionRate, bool, false, "Get interaction rate from CCDB") + O2_DEFINE_CONFIGURABLE(cfgUseInteractionRateCut, bool, false, "Use events with low interaction rate") + O2_DEFINE_CONFIGURABLE(cfgCutMaxIR, float, 50.0f, "maximum interaction rate (kHz)") + O2_DEFINE_CONFIGURABLE(cfgCutMinIR, float, 0.0f, "minimum interaction rate (kHz)") + Configurable> cfgRunNumbers{"cfgRunNumbers", std::vector{544095, 544098, 544116, 544121, 544122, 544123, 544124}, "Preconfigured run numbers"}; + Configurable> cfgUserDefineGFWCorr{"cfgUserDefineGFWCorr", std::vector{"refN10 {2} refP10 {-2}"}, "User defined GFW CorrelatorConfig"}; + Configurable> cfgUserDefineGFWName{"cfgUserDefineGFWName", std::vector{"Ch10Gap22"}, "User defined GFW Name"}; + + ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for histograms"}; + ConfigurableAxis axisPhi{"axisPhi", {60, 0.0, constants::math::TwoPI}, "phi axis for histograms"}; + ConfigurableAxis axisEta{"axisEta", {40, -1., 1.}, "eta axis for histograms"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.2, 2.4, 2.6, 2.8, 3, 3.5, 4, 5, 6, 8, 10}, "pt axis for histograms"}; + ConfigurableAxis axisIndependent{"axisIndependent", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}, "X axis for histograms"}; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter trackFilter = ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtMin) && (aod::track::pt < cfgCutPtMax) && (aod::track::tpcChi2NCl < cfgCutChi2prTPCcls) && (nabs(aod::track::dcaZ) < cfgCutDCAz); + + // Corrections + TH1D* mEfficiency = nullptr; + GFWWeights* mAcceptance = nullptr; + TObjArray* mAcceptanceList = nullptr; + bool correctionsLoaded = false; + + // Connect to ccdb + Service ccdb; + Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + // Define output + OutputObj fFC{FlowContainer("FlowContainer")}; + HistogramRegistry registry{"registry"}; + + // define global variables + GFW* fGFW = new GFW(); + std::vector corrconfigs; + std::vector corrconfigsFC; + TAxis* fPtAxis; + TRandom3* fRndm = new TRandom3(0); + int lastRunNumer = -1; + std::vector runNumbers; // vector of run numbers + std::map>> th1sList; // map of histograms for all runs + std::map>> th3sList; // map of TH3 histograms for all runs + std::map>> profilesList; // map of profiles for all runs + enum OutputTH1Names { + // here are TProfiles for vn-pt correlations that are not implemented in GFW + hPhi = 0, + hPhiWeighted, + hEta, + hVtxZ, + hMult, + hCent, + hEventCountSpecific, + kCount_TH1Names + }; + enum OutputTH3Names { + hPhiEtaVtxz = 0, + kCount_TH3Names + }; + enum OutputTProfileNames { + c22 = 0, + c22_gap10, + c32, + c32_gap10, + c3232, + kCount_TProfileNames + }; + int mRunNumber{-1}; + uint64_t mSOR{0}; + double mMinSeconds{-1.}; + std::unordered_map gHadronicRate; + ctpRateFetcher mRateFetcher; + TH2* gCurrentHadronicRate; + + // Additional Event selection cuts - Copy from flowGenericFramework.cxx + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + TF1* fMultCutLow = nullptr; + TF1* fMultCutHigh = nullptr; + TF1* fMultMultPVCut = nullptr; + TF1* fT0AV0AMean = nullptr; + TF1* fT0AV0ASigma = nullptr; + + using AodCollisions = soa::Filtered>; + using AodTracks = soa::Filtered>; + + void init(InitContext const&) + { + ccdb->setURL(ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setCreatedNotAfter(ccdbNoLaterThan.value); + + // Add output histograms to the registry + runNumbers = cfgRunNumbers; + for (const auto& runNumber : runNumbers) { + createOutputObjectsForRun(runNumber); + } + + o2::framework::AxisSpec axis = axisPt; + int nPtBins = axis.binEdges.size() - 1; + double* ptBins = &(axis.binEdges)[0]; + fPtAxis = new TAxis(nPtBins, ptBins); + + // Create FlowContainer + TObjArray* oba = new TObjArray(); + std::vector userDefineGFWCorr = cfgUserDefineGFWCorr; + std::vector userDefineGFWName = cfgUserDefineGFWName; + if (!userDefineGFWCorr.empty() && !userDefineGFWName.empty()) { + for (uint i = 0; i < userDefineGFWName.size(); i++) { + oba->Add(new TNamed(userDefineGFWName.at(i).c_str(), userDefineGFWName.at(i).c_str())); + } + } + fFC->SetName("FlowContainer"); + fFC->SetXAxis(fPtAxis); + fFC->Initialize(oba, axisIndependent, cfgNbootstrap); + delete oba; + + fGFW->AddRegion("full", -0.8, 0.8, 1, 1); + fGFW->AddRegion("refN10", -0.8, -0.5, 1, 1); + fGFW->AddRegion("refP10", 0.5, 0.8, 1, 1); + corrconfigs.resize(kCount_TProfileNames); + corrconfigs[c22] = fGFW->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE); + corrconfigs[c22_gap10] = fGFW->GetCorrelatorConfig("refN10 {2} refP10 {-2}", "Ch10Gap22", kFALSE); + corrconfigs[c32] = fGFW->GetCorrelatorConfig("full {3 -3}", "ChFull32", kFALSE); + corrconfigs[c32_gap10] = fGFW->GetCorrelatorConfig("refN10 {3} refP10 {-3}", "Ch10Gap32", kFALSE); + corrconfigs[c3232] = fGFW->GetCorrelatorConfig("full {3 2 -3 -2}", "ChFull3232", kFALSE); + if (!userDefineGFWCorr.empty() && !userDefineGFWName.empty()) { + LOGF(info, "User adding GFW CorrelatorConfig:"); + // attentaion: here we follow the index of cfgUserDefineGFWCorr + for (uint i = 0; i < userDefineGFWCorr.size(); i++) { + if (i >= userDefineGFWName.size()) { + LOGF(fatal, "The names you provided are more than configurations. userDefineGFWName.size(): %d > userDefineGFWCorr.size(): %d", userDefineGFWName.size(), userDefineGFWCorr.size()); + break; + } + LOGF(info, "%d: %s %s", i, userDefineGFWCorr.at(i).c_str(), userDefineGFWName.at(i).c_str()); + corrconfigsFC.push_back(fGFW->GetCorrelatorConfig(userDefineGFWCorr.at(i).c_str(), userDefineGFWName.at(i).c_str(), kFALSE)); + } + } + fGFW->CreateRegions(); + + if (cfgUseAdditionalEventCut) { + fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x - 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); + fMultPVCutLow->SetParameters(3257.29, -121.848, 1.98492, -0.0172128, 6.47528e-05, 154.756, -1.86072, -0.0274713, 0.000633499, -3.37757e-06); + fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x + 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); + fMultPVCutHigh->SetParameters(3257.29, -121.848, 1.98492, -0.0172128, 6.47528e-05, 154.756, -1.86072, -0.0274713, 0.000633499, -3.37757e-06); + + fMultCutLow = new TF1("fMultCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultCutLow->SetParameters(1654.46, -47.2379, 0.449833, -0.0014125, 150.773, -3.67334, 0.0530503, -0.000614061, 3.15956e-06); + fMultCutHigh = new TF1("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 3.*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultCutHigh->SetParameters(1654.46, -47.2379, 0.449833, -0.0014125, 150.773, -3.67334, 0.0530503, -0.000614061, 3.15956e-06); + + fT0AV0AMean = new TF1("fT0AV0AMean", "[0]+[1]*x", 0, 200000); + fT0AV0AMean->SetParameters(-1601.0581, 9.417652e-01); + fT0AV0ASigma = new TF1("fT0AV0ASigma", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 200000); + fT0AV0ASigma->SetParameters(463.4144, 6.796509e-02, -9.097136e-07, 7.971088e-12, -2.600581e-17); + } + } + + template + void fillProfile(const GFW::CorrConfig& corrconf, std::shared_ptr profile, const double& cent) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) + return; + if (!corrconf.pTDif) { + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + profile->Fill(cent, val, dnx); + return; + } + return; + } + + void fillFC(const GFW::CorrConfig& corrconf, const double& cent, const double& rndm) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) + return; + if (!corrconf.pTDif) { + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + fFC->FillProfile(corrconf.Head.c_str(), cent, val, dnx, rndm); + return; + } + for (auto i = 1; i <= fPtAxis->GetNbins(); i++) { + dnx = fGFW->Calculate(corrconf, i - 1, kTRUE).real(); + if (dnx == 0) + continue; + val = fGFW->Calculate(corrconf, i - 1, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + fFC->FillProfile(Form("%s_pt_%i", corrconf.Head.c_str(), i), cent, val, dnx, rndm); + } + return; + } + + void loadCorrections(uint64_t timestamp, int runNumber) + { + if (correctionsLoaded) + return; + if (!cfgAcceptanceListEnabled && cfgAcceptance.value.empty() == false) { + mAcceptance = ccdb->getForTimeStamp(cfgAcceptance, timestamp); + if (mAcceptance) + LOGF(info, "Loaded acceptance weights from %s (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance); + else + LOGF(warning, "Could not load acceptance weights from %s (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance); + } + if (cfgAcceptanceListEnabled && cfgAcceptanceList.value.empty() == false) { + mAcceptanceList = ccdb->getForTimeStamp(cfgAcceptanceList, timestamp); + if (mAcceptanceList == nullptr) { + LOGF(fatal, "Could not load acceptance weights list from %s", cfgAcceptanceList.value.c_str()); + } + LOGF(info, "Loaded acceptance weights list from %s (%p)", cfgAcceptanceList.value.c_str(), (void*)mAcceptanceList); + + mAcceptance = static_cast(mAcceptanceList->FindObject(Form("%d", runNumber))); + if (mAcceptance == nullptr) { + LOGF(fatal, "Could not find acceptance weights for run %d in acceptance list", runNumber); + } + LOGF(info, "Loaded acceptance weights (%p) for run %d from list (%p)", (void*)mAcceptance, runNumber, (void*)mAcceptanceList); + } + if (cfgEfficiency.value.empty() == false) { + mEfficiency = ccdb->getForTimeStamp(cfgEfficiency, timestamp); + if (mEfficiency == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgEfficiency.value.c_str()); + } + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgEfficiency.value.c_str(), (void*)mEfficiency); + } + correctionsLoaded = true; + } + + bool setCurrentParticleWeights(float& weight_nue, float& weight_nua, float phi, float eta, float pt, float vtxz) + { + float eff = 1.; + if (mEfficiency) + eff = mEfficiency->GetBinContent(mEfficiency->FindBin(pt)); + else + eff = 1.0; + if (eff == 0) + return false; + weight_nue = 1. / eff; + + if (mAcceptance) + weight_nua = mAcceptance->getNUA(phi, eta, vtxz); + else + weight_nua = 1; + return true; + } + + void createOutputObjectsForRun(int runNumber) + { + std::vector> histos(kCount_TH1Names); + histos[hPhi] = registry.add(Form("%d/hPhi", runNumber), "", {HistType::kTH1D, {axisPhi}}); + histos[hPhiWeighted] = registry.add(Form("%d/hPhiWeighted", runNumber), "", {HistType::kTH1D, {axisPhi}}); + histos[hEta] = registry.add(Form("%d/hEta", runNumber), "", {HistType::kTH1D, {axisEta}}); + histos[hVtxZ] = registry.add(Form("%d/hVtxZ", runNumber), "", {HistType::kTH1D, {axisVertex}}); + histos[hMult] = registry.add(Form("%d/hMult", runNumber), "", {HistType::kTH1D, {{3000, 0.5, 3000.5}}}); + histos[hCent] = registry.add(Form("%d/hCent", runNumber), "", {HistType::kTH1D, {{90, 0, 90}}}); + histos[hEventCountSpecific] = registry.add(Form("%d/hEventCountSpecific", runNumber), "", {HistType::kTH1D, {{10, 0, 10}}}); + histos[hEventCountSpecific]->GetXaxis()->SetBinLabel(1, "after sel8"); + histos[hEventCountSpecific]->GetXaxis()->SetBinLabel(2, "kNoSameBunchPileup"); + histos[hEventCountSpecific]->GetXaxis()->SetBinLabel(3, "kIsGoodZvtxFT0vsPV"); + histos[hEventCountSpecific]->GetXaxis()->SetBinLabel(4, "kNoCollInTimeRangeStandard"); + histos[hEventCountSpecific]->GetXaxis()->SetBinLabel(5, "kIsGoodITSLayersAll"); + histos[hEventCountSpecific]->GetXaxis()->SetBinLabel(6, "kNoCollInRofStandard"); + histos[hEventCountSpecific]->GetXaxis()->SetBinLabel(7, "kNoHighMultCollInPrevRof"); + histos[hEventCountSpecific]->GetXaxis()->SetBinLabel(8, "occupancy"); + histos[hEventCountSpecific]->GetXaxis()->SetBinLabel(9, "MultCorrelation"); + histos[hEventCountSpecific]->GetXaxis()->SetBinLabel(10, "cfgEvSelV0AT0ACut"); + th1sList.insert(std::make_pair(runNumber, histos)); + + std::vector> profiles(kCount_TProfileNames); + profiles[c22] = registry.add(Form("%d/c22", runNumber), "", {HistType::kTProfile, {axisIndependent}}); + profiles[c22_gap10] = registry.add(Form("%d/c22_gap10", runNumber), "", {HistType::kTProfile, {axisIndependent}}); + profiles[c32] = registry.add(Form("%d/c32", runNumber), "", {HistType::kTProfile, {axisIndependent}}); + profiles[c32_gap10] = registry.add(Form("%d/c32_gap10", runNumber), "", {HistType::kTProfile, {axisIndependent}}); + profiles[c3232] = registry.add(Form("%d/c3232", runNumber), "", {HistType::kTProfile, {axisIndependent}}); + profilesList.insert(std::make_pair(runNumber, profiles)); + + if (cfgOutputNUAWeights) { + std::vector> tH3s(kCount_TH3Names); + tH3s[hPhiEtaVtxz] = registry.add(Form("%d/hPhiEtaVtxz", runNumber), ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, {40, -10, 10}}}); + th3sList.insert(std::make_pair(runNumber, tH3s)); + } + } + + void initHadronicRate(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + if (gHadronicRate.find(mRunNumber) == gHadronicRate.end()) { + auto runDuration = ccdb->getRunDuration(mRunNumber); + mSOR = runDuration.first; + mMinSeconds = std::floor(mSOR * 1.e-3); /// round tsSOR to the highest integer lower than tsSOR + double maxSec = std::ceil(runDuration.second * 1.e-3); /// round tsEOR to the lowest integer higher than tsEOR + const AxisSpec axisSeconds{static_cast((maxSec - mMinSeconds) / 20.f), 0, maxSec - mMinSeconds, "Seconds since SOR"}; + int hadronicRateBins = static_cast(cfgCutMaxIR - cfgCutMinIR); + gHadronicRate[mRunNumber] = registry.add(Form("HadronicRate/%i", mRunNumber), ";Time since SOR (s);Hadronic rate (kHz)", kTH2D, {axisSeconds, {hadronicRateBins, cfgCutMinIR, cfgCutMaxIR}}).get(); + } + gCurrentHadronicRate = gHadronicRate[mRunNumber]; + } + + template + bool eventSelected(TCollision collision, const int multTrk, const float centrality, const int runNumber) + { + th1sList[runNumber][hEventCountSpecific]->Fill(0.5); + if (cfgEvSelkNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + // rejects collisions which are associated with the same "found-by-T0" bunch crossing + // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof + return 0; + } + if (cfgEvSelkNoSameBunchPileup) + th1sList[runNumber][hEventCountSpecific]->Fill(1.5); + if (cfgEvSelkIsGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference + // use this cut at low multiplicities with caution + return 0; + } + if (cfgEvSelkIsGoodZvtxFT0vsPV) + th1sList[runNumber][hEventCountSpecific]->Fill(2.5); + if (cfgEvSelkNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // no collisions in specified time range + return 0; + } + if (cfgEvSelkNoCollInTimeRangeStandard) + th1sList[runNumber][hEventCountSpecific]->Fill(3.5); + if (cfgEvSelkIsGoodITSLayersAll && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + // from Jan 9 2025 AOT meeting + // cut time intervals with dead ITS staves + return 0; + } + if (cfgEvSelkIsGoodITSLayersAll) + th1sList[runNumber][hEventCountSpecific]->Fill(4.5); + if (cfgEvSelkNoCollInRofStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + // no other collisions in this Readout Frame with per-collision multiplicity above threshold + return 0; + } + if (cfgEvSelkNoCollInRofStandard) + th1sList[runNumber][hEventCountSpecific]->Fill(5.5); + if (cfgEvSelkNoHighMultCollInPrevRof && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + // veto an event if FT0C amplitude in previous ITS ROF is above threshold + return 0; + } + if (cfgEvSelkNoHighMultCollInPrevRof) + th1sList[runNumber][hEventCountSpecific]->Fill(6.5); + auto multNTracksPV = collision.multNTracksPV(); + auto occupancy = collision.trackOccupancyInTimeRange(); + if (cfgEvSelOccupancy && (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh)) + return 0; + if (cfgEvSelOccupancy) + th1sList[runNumber][hEventCountSpecific]->Fill(7.5); + + if (cfgEvSelMultCorrelation) { + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) + return 0; + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) + return 0; + if (multTrk < fMultCutLow->Eval(centrality)) + return 0; + if (multTrk > fMultCutHigh->Eval(centrality)) + return 0; + } + if (cfgEvSelMultCorrelation) + th1sList[runNumber][hEventCountSpecific]->Fill(8.5); + + // V0A T0A 5 sigma cut + if (cfgEvSelV0AT0ACut && (std::fabs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > 5 * fT0AV0ASigma->Eval(collision.multFT0A()))) + return 0; + if (cfgEvSelV0AT0ACut) + th1sList[runNumber][hEventCountSpecific]->Fill(9.5); + + return 1; + } + + template + bool trackSelected(TTrack track) + { + if (cfgCutDCAzPtDepEnabled && (std::fabs(track.dcaZ()) > (0.004f + 0.013f / track.pt()))) + return false; + + return ((track.tpcNClsFound() >= cfgCutTPCclu) && (track.itsNCls() >= cfgCutITSclu)); + } + + void process(AodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, AodTracks const& tracks) + { + if (!collision.sel8()) + return; + if (tracks.size() < 1) + return; + // detect run number + auto bc = collision.bc_as(); + const auto cent = collision.centFT0C(); + int runNumber = bc.runNumber(); + if (runNumber != lastRunNumer) { + lastRunNumer = runNumber; + if (cfgDynamicRunNumber && std::find(runNumbers.begin(), runNumbers.end(), runNumber) == runNumbers.end()) { + // if run number is not in the preconfigured list, create new output histograms for this run + createOutputObjectsForRun(runNumber); + runNumbers.push_back(runNumber); + } + + if (th1sList.find(runNumber) == th1sList.end()) { + LOGF(fatal, "RunNumber %d not found in th1sList", runNumber); + return; + } + } + + if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), cent, runNumber)) + return; + if (cfgGetInteractionRate) { + initHadronicRate(bc); + double hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), mRunNumber, "ZNC hadronic") * 1.e-3; // + double seconds = bc.timestamp() * 1.e-3 - mMinSeconds; + if (cfgUseInteractionRateCut && (hadronicRate < cfgCutMinIR || hadronicRate > cfgCutMaxIR)) // cut on hadronic rate + return; + gCurrentHadronicRate->Fill(seconds, hadronicRate); + } + float lRandom = fRndm->Rndm(); + + th1sList[runNumber][hVtxZ]->Fill(collision.posZ()); + th1sList[runNumber][hMult]->Fill(tracks.size()); + th1sList[runNumber][hCent]->Fill(collision.centFT0C()); + + loadCorrections(bc.timestamp(), runNumber); + + fGFW->Clear(); + float weff = 1, wacc = 1; + for (const auto& track : tracks) { + if (!trackSelected(track)) + continue; + // bool WithinPtPOI = (cfgCutPtPOIMin < track.pt()) && (track.pt() < cfgCutPtPOIMax); // within POI pT range + bool withinPtRef = (cfgCutPtRefMin < track.pt()) && (track.pt() < cfgCutPtRefMax); // within RF pT range + if (cfgOutputNUAWeights) { + if (cfgOutputNUAWeightsRefPt) { + if (withinPtRef) { + th3sList[runNumber][hPhiEtaVtxz]->Fill(track.phi(), track.eta(), collision.posZ()); + } + } else { + th3sList[runNumber][hPhiEtaVtxz]->Fill(track.phi(), track.eta(), collision.posZ()); + } + } + if (!setCurrentParticleWeights(weff, wacc, track.phi(), track.eta(), track.pt(), collision.posZ())) + continue; + if (withinPtRef) { + th1sList[runNumber][hPhi]->Fill(track.phi()); + th1sList[runNumber][hPhiWeighted]->Fill(track.phi(), wacc); + th1sList[runNumber][hEta]->Fill(track.eta()); + } + if (withinPtRef) { + fGFW->Fill(track.eta(), 1, track.phi(), wacc * weff, 1); + } + } + + // Filling TProfile + for (uint i = 0; i < kCount_TProfileNames; ++i) { + fillProfile(corrconfigs[i], profilesList[runNumber][i], cent); + } + // Filling Flow Container + for (uint l_ind = 0; l_ind < corrconfigsFC.size(); l_ind++) { + fillFC(corrconfigsFC.at(l_ind), cent, lRandom); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Flow/Tasks/flowSP.cxx b/PWGCF/Flow/Tasks/flowSP.cxx new file mode 100644 index 00000000000..9be9242c107 --- /dev/null +++ b/PWGCF/Flow/Tasks/flowSP.cxx @@ -0,0 +1,1317 @@ +// 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 flowSP.cxx +/// \author Noor Koster +/// \since 01/12/2024 +/// \brief task to evaluate flow with respect to spectator plane. + +#include +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/Core/RecoDecay.h" + +#include "PWGCF/DataModel/SPTableZDC.h" +#include "GFWWeights.h" +#include "TF1.h" +#include "TPDGCode.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +// using namespace o2::analysis; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct FlowSP { + // QA Plots + O2_DEFINE_CONFIGURABLE(cfgFillQAHistos, bool, true, "Fill histograms for event and track QA"); + // Flags to make and fill histograms + O2_DEFINE_CONFIGURABLE(cfgFillMixedHarmonics, bool, true, "Flag to make and fill histos for mixed harmonics"); + O2_DEFINE_CONFIGURABLE(cfgFillEventPlane, bool, true, "Flag to make and fill histos with Event Plane"); + O2_DEFINE_CONFIGURABLE(cfgFillXandYterms, bool, true, "Flag to make and fill histos for with separate x and y terms for SPM"); + O2_DEFINE_CONFIGURABLE(cfgFillChargeDependence, bool, true, "Flag to make and fill histos for charge dependent flow"); + // Centrality Estimators -> standard is FT0C + O2_DEFINE_CONFIGURABLE(cfgCentFT0Cvariant1, bool, false, "Set centrality estimator to cfgCentFT0Cvariant1"); + O2_DEFINE_CONFIGURABLE(cfgCentFT0M, bool, false, "Set centrality estimator to cfgCentFT0M"); + O2_DEFINE_CONFIGURABLE(cfgCentFV0A, bool, false, "Set centrality estimator to cfgCentFV0A"); + O2_DEFINE_CONFIGURABLE(cfgCentNGlobal, bool, false, "Set centrality estimator to cfgCentNGlobal"); + // Standard selections + O2_DEFINE_CONFIGURABLE(cfgDCAxy, float, 0.2, "Cut on DCA in the transverse direction (cm)"); + O2_DEFINE_CONFIGURABLE(cfgDCAz, float, 2, "Cut on DCA in the longitudinal direction (cm)"); + O2_DEFINE_CONFIGURABLE(cfgNcls, float, 70, "Cut on number of TPC clusters found"); + O2_DEFINE_CONFIGURABLE(cfgFshcls, float, 0.2, "Cut on fraction of shared TPC clusters found"); + O2_DEFINE_CONFIGURABLE(cfgPtmin, float, 0.2, "minimum pt (GeV/c)"); + O2_DEFINE_CONFIGURABLE(cfgPtmax, float, 10, "maximum pt (GeV/c)"); + O2_DEFINE_CONFIGURABLE(cfgEta, float, 0.8, "eta cut"); + O2_DEFINE_CONFIGURABLE(cfgVtxZ, float, 10, "vertex cut (cm)"); + O2_DEFINE_CONFIGURABLE(cfgMagField, float, 99999, "Configurable magnetic field;default CCDB will be queried"); + + O2_DEFINE_CONFIGURABLE(cfgCentMin, float, 0, "Minimum cenrality for selected events"); + O2_DEFINE_CONFIGURABLE(cfgCentMax, float, 90, "Maximum cenrality for selected events"); + // NUA and NUE weights + O2_DEFINE_CONFIGURABLE(cfgFillWeights, bool, true, "Fill NUA weights"); + O2_DEFINE_CONFIGURABLE(cfgFillWeightsPOS, bool, false, "Fill NUA weights only for positive charges"); + O2_DEFINE_CONFIGURABLE(cfgFillWeightsNEG, bool, false, "Fill NUA weights only for negative charges"); + O2_DEFINE_CONFIGURABLE(cfgNUA, std::string, "", "ccdb dir for NUA corrections"); + O2_DEFINE_CONFIGURABLE(cfgNUE, std::string, "", "ccdb dir for NUE corrections"); + // Additional track Selections + O2_DEFINE_CONFIGURABLE(cfgUseAdditionalTrackCut, bool, true, "Bool to enable Additional Track Cut"); + O2_DEFINE_CONFIGURABLE(cfgDoubleTrackFunction, bool, true, "Include track cut at low pt"); + O2_DEFINE_CONFIGURABLE(cfgTrackCutSize, float, 0.06, "Spread of track cut"); + // Additional event selections + O2_DEFINE_CONFIGURABLE(cfgUseAdditionalEventCut, bool, true, "Bool to enable Additional Event Cut"); + O2_DEFINE_CONFIGURABLE(cfgnSigmaMultCuts, int, 1, "Sigma cut on Additional event cut: 1 (default), 2 or 3 sigma available"); + O2_DEFINE_CONFIGURABLE(cfgManualEventParameters, bool, false, "Use manual event parameters for the pile up fits. Needed for Cent estimaters other than FT0C"); + O2_DEFINE_CONFIGURABLE(cfgMultPv, std::vector, {}, "Multiplicity cuts for PV first 5 parameters cutLOW last 5 cutHIGH"); + O2_DEFINE_CONFIGURABLE(cfgMult, std::vector, {}, "Multiplicity cuts for T0C first 5 parameters cutLOW last 5 cutHIGH"); + O2_DEFINE_CONFIGURABLE(cfgMaxOccupancy, int, 10000, "Maximum occupancy of selected events"); + O2_DEFINE_CONFIGURABLE(cfgNoSameBunchPileupCut, bool, true, "kNoSameBunchPileupCut"); + O2_DEFINE_CONFIGURABLE(cfgIsGoodZvtxFT0vsPV, bool, true, "kIsGoodZvtxFT0vsPV"); + O2_DEFINE_CONFIGURABLE(cfgNoCollInTimeRangeStandard, bool, true, "kNoCollInTimeRangeStandard"); + O2_DEFINE_CONFIGURABLE(cfgDoOccupancySel, bool, true, "Bool for event selection on detector occupancy"); + O2_DEFINE_CONFIGURABLE(cfgTVXinTRD, bool, false, "Use kTVXinTRD (reject TRD triggered events)"); + O2_DEFINE_CONFIGURABLE(cfgIsVertexITSTPC, bool, true, "Selects collisions with at least one ITS-TPC track"); + O2_DEFINE_CONFIGURABLE(cfgIsGoodITSLayersAll, bool, true, "Cut time intervals with dead ITS staves"); + // harmonics for v coefficients + O2_DEFINE_CONFIGURABLE(cfgHarm, int, 1, "Flow harmonic n for ux and uy: (Cos(n*phi), Sin(n*phi))"); + O2_DEFINE_CONFIGURABLE(cfgHarmMixed, int, 2, "Flow harmonic n for ux and uy in mixed harmonics (MH): (Cos(n*phi), Sin(n*phi))"); + // settings for CCDB data + O2_DEFINE_CONFIGURABLE(cfgLoadAverageQQ, bool, true, "Load average values for QQ (in centrality bins)"); + O2_DEFINE_CONFIGURABLE(cfgCCDBdir, std::string, "Users/c/ckoster/ZDC/LHC23_zzh_pass4_small/meanQQ", "ccdb dir for average QQ values in 1% centrality bins"); + O2_DEFINE_CONFIGURABLE(cfgLoadSPPlaneRes, bool, false, "Load ZDC spectator plane resolution"); + O2_DEFINE_CONFIGURABLE(cfgCCDBdir_SP, std::string, "Users/c/ckoster/ZDC/LHC23_zzh_pass4_small/SPPlaneRes", "ccdb dir for average event plane resolution in 1% centrality bins"); + // axis + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgVtxZ; + Filter trackFilter = nabs(aod::track::eta) < cfgEta && aod::track::pt > cfgPtmin&& aod::track::pt < cfgPtmax && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && nabs(aod::track::dcaXY) < cfgDCAxy&& nabs(aod::track::dcaZ) < cfgDCAz; + Filter trackFilterMC = nabs(aod::mcparticle::eta) < cfgEta && aod::mcparticle::pt > cfgPtmin&& aod::mcparticle::pt < cfgPtmax; + using UsedCollisions = soa::Filtered>; + using UsedTracks = soa::Filtered>; + + // For MC Reco and Gen + using CCs = soa::Filtered>; + using CC = CCs::iterator; + using TCs = soa::Join; + using FilteredTCs = soa::Filtered>; + using TC = TCs::iterator; + using MCs = soa::Filtered; + + Preslice partPerMcCollision = aod::mcparticle::mcCollisionId; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + PresliceUnsorted trackPerMcParticle = aod::mctracklabel::mcParticleId; + Preslice trackPerCollision = aod::track::collisionId; + + // Connect to ccdb + Service ccdb; + Service pdg; + + // struct to hold the correction histos/ + struct Config { + std::vector mEfficiency = {}; + std::vector mAcceptance = {}; + bool correctionsLoaded = false; + int lastRunNumber = 0; + + TProfile* hcorrQQ = nullptr; + TProfile* hcorrQQx = nullptr; + TProfile* hcorrQQy = nullptr; + TProfile* hEvPlaneRes = nullptr; + bool clQQ = false; + bool clEvPlaneRes = false; + + } cfg; + + // define output objects + OutputObj fWeights{GFWWeights("weights")}; + OutputObj fWeightsPOS{GFWWeights("weights_positive")}; + OutputObj fWeightsNEG{GFWWeights("weights_negative")}; + HistogramRegistry registry{"registry"}; + + // Event selection cuts - Alex + TF1* fPhiCutLow = nullptr; + TF1* fPhiCutHigh = nullptr; + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + TF1* fMultCutLow = nullptr; + TF1* fMultCutHigh = nullptr; + TF1* fMultMultPVCut = nullptr; + + enum SelectionCriteria { + evSel_FilteredEvent, + evSel_sel8, + evSel_occupancy, + evSel_kTVXinTRD, + evSel_kNoSameBunchPileup, + evSel_kIsGoodZvtxFT0vsPV, + evSel_kNoCollInTimeRangeStandard, + evSel_kIsVertexITSTPC, + evSel_MultCuts, + evSel_CentCuts, + evSel_kIsGoodITSLayersAll, + evSel_isSelectedZDC, + nEventSelections + }; + + enum TrackSelectionsUnFiltered { + trackSel_Eta, + trackSel_Pt, + trackSel_DCAxy, + trackSel_DCAz, + trackSel_GlobalTracks, + trackSel_NCls, + trackSel_FshCls, + trackSel_TPCBoundary, + trackSel_ZeroCharge, + trackSel_ParticleWeights, + nTrackSelections + }; + + enum ChargeType { + kInclusive, + kPositive, + kNegative + }; + + enum FillType { + kBefore, + kAfter + }; + + enum ModeType { + kGen, + kReco + }; + + static constexpr std::string_view Charge[] = {"incl/", "pos/", "neg/"}; + static constexpr std::string_view Time[] = {"before/", "after"}; + + void init(InitContext const&) + { + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + int64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); + + AxisSpec axisDCAz = {100, -.5, .5, "DCA_{z} (cm)"}; + AxisSpec axisDCAxy = {100, -.5, .5, "DCA_{xy} (cm)"}; + AxisSpec axisPhiMod = {100, 0, constants::math::PI / 9, "fmod(#varphi,#pi/9)"}; + AxisSpec axisPhi = {60, 0, constants::math::TwoPI, "#varphi"}; + AxisSpec axisEta = {64, -1.8, 1.8, "#eta"}; + AxisSpec axisEtaVn = {8, -.8, .8, "#eta"}; + AxisSpec axisVx = {40, -0.01, 0.01, "v_{x}"}; + AxisSpec axisVy = {40, -0.01, 0.01, "v_{y}"}; + AxisSpec axisVz = {40, -10, 10, "v_{z}"}; + AxisSpec axisCent = {90, 0, 90, "Centrality(%)"}; + AxisSpec axisPhiPlane = {100, -constants::math::PI, constants::math::PI, "#Psi"}; + AxisSpec axisNch = {40, 0, 40000, "N_{ch}"}; + AxisSpec axisT0c = {70, 0, 100000, "N_{ch} (T0C)"}; + AxisSpec axisT0a = {70, 0, 200000, "N_{ch} (T0A)"}; + AxisSpec axisV0a = {70, 0, 200000, "N_{ch} (V0A)"}; + AxisSpec axisMultpv = {40, 0, 4000, "N_{ch} (PV)"}; + AxisSpec axisShCl = {100, 0, 1, "Fraction shared cl. TPC"}; + AxisSpec axisCl = {100, 0, 160, "Number of cl. TPC"}; + + std::vector ptbinning = {0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.2, 2.4, 2.6, 2.8, 3, 3.5, 4, 5, 6, 8, 10}; + AxisSpec axisPt = {ptbinning, "#it{p}_{T} GeV/#it{c}"}; + + int ptbins = ptbinning.size() - 1; + + if (cfgFillWeights) { + fWeights->setPtBins(ptbins, &ptbinning[0]); + fWeights->init(true, false); + + fWeightsPOS->setPtBins(ptbins, &ptbinning[0]); + fWeightsPOS->init(true, false); + + fWeightsNEG->setPtBins(ptbins, &ptbinning[0]); + fWeightsNEG->init(true, false); + } + + if (doprocessData || doprocessMCReco || doprocessMCGen) { + if (cfgFillQAHistos) { + registry.add("QA/after/hCentFT0C", " ; Cent FT0C (%); ", {HistType::kTH1D, {axisCent}}); + registry.add("QA/after/hCentFT0M", "; Cent FT0M (%); ", {HistType::kTH1D, {axisCent}}); + registry.add("QA/after/hCentFV0A", "; Cent FV0A (%); ", {HistType::kTH1D, {axisCent}}); + registry.add("QA/after/hCentNGlobal", "; Cent NGlobal (%); ", {HistType::kTH1D, {axisCent}}); + + registry.add("QA/after/pt_phi", "", {HistType::kTH2D, {axisPt, axisPhiMod}}); + registry.add("QA/after/hPt_inclusive", "", {HistType::kTH1D, {axisPt}}); + registry.add("QA/after/hPt_positive", "", {HistType::kTH1D, {axisPt}}); + registry.add("QA/after/hPt_negative", "", {HistType::kTH1D, {axisPt}}); + registry.add("QA/after/globalTracks_centT0C", "", {HistType::kTH2D, {axisCent, axisNch}}); + registry.add("QA/after/globalTracks_centNGlobal", "", {HistType::kTH2D, {axisCent, axisNch}}); + registry.add("QA/after/PVTracks_centT0C", "", {HistType::kTH2D, {axisCent, axisMultpv}}); + registry.add("QA/after/PVTracks_centNGlobal", "", {HistType::kTH2D, {axisCent, axisMultpv}}); + registry.add("QA/after/globalTracks_PVTracks", "", {HistType::kTH2D, {axisMultpv, axisNch}}); + registry.add("QA/after/globalTracks_multT0A", "", {HistType::kTH2D, {axisT0a, axisNch}}); + registry.add("QA/after/globalTracks_multV0A", "", {HistType::kTH2D, {axisV0a, axisNch}}); + registry.add("QA/after/multV0A_multT0A", "", {HistType::kTH2D, {axisT0a, axisV0a}}); + registry.add("QA/after/multT0C_centT0C", "", {HistType::kTH2D, {axisCent, axisT0c}}); + + registry.add("QA/after/CentFT0C_vs_CentFT0Cvariant1", " ; Cent FT0C (%); Cent FT0Cvariant1 (%) ", {HistType::kTH2D, {axisCent, axisCent}}); + registry.add("QA/after/CentFT0C_vs_CentFT0M", " ; Cent FT0C (%); Cent FT0M (%) ", {HistType::kTH2D, {axisCent, axisCent}}); + registry.add("QA/after/CentFT0C_vs_CentFV0A", " ; Cent FT0C (%); Cent FV0A (%) ", {HistType::kTH2D, {axisCent, axisCent}}); + registry.add("QA/after/CentFT0C_vs_CentNGlobal", " ; Cent FT0C (%); Cent NGlobal (%) ", {HistType::kTH2D, {axisCent, axisCent}}); + + if (doprocessData || doprocessMCReco) { + // track QA for pos, neg, incl + registry.add("incl/QA/hPt", "", kTH1D, {axisPt}); + registry.add("incl/QA/hPhi", "", kTH1D, {axisPhi}); + registry.add("incl/QA/hPhiCorrected", "", kTH1D, {axisPhi}); + registry.add("incl/QA/hEta", "", kTH1D, {axisEta}); + registry.add("incl/QA/hPhi_Eta_vz", "", kTH3D, {axisPhi, axisEta, axisVz}); + registry.add("incl/QA/hDCAxy_pt", "", kTH2D, {axisPt, axisDCAxy}); + registry.add("incl/QA/hDCAz_pt", "", kTH2D, {axisPt, axisDCAz}); + registry.add("incl/QA/hSharedClusters_pt", "", {HistType::kTH2D, {axisPt, axisShCl}}); + registry.add("incl/QA/hCrossedRows_pt", "", {HistType::kTH2D, {axisPt, axisCl}}); + } + } + + if (doprocessMCReco) { + registry.add("trackMCReco/after/hIsPhysicalPrimary", "", {HistType::kTH1D, {{2, 0, 2}}}); + registry.add("trackMCReco/hTrackSize_unFiltered", "", {HistType::kTH1D, {{100, 0, 200000}}}); + registry.add("trackMCReco/hTrackSize_Filtered", "", {HistType::kTH1D, {{100, 0, 20000}}}); + registry.get(HIST("trackMCReco/after/hIsPhysicalPrimary"))->GetXaxis()->SetBinLabel(1, "Secondary"); + registry.get(HIST("trackMCReco/after/hIsPhysicalPrimary"))->GetXaxis()->SetBinLabel(2, "Primary"); + + registry.add("trackMCReco/after/incl/hPt_hadron", "", {HistType::kTH1D, {axisPt}}); + registry.add("trackMCReco/after/incl/hPt_proton", "", {HistType::kTH1D, {axisPt}}); + registry.add("trackMCReco/after/incl/hPt_pion", "", {HistType::kTH1D, {axisPt}}); + registry.add("trackMCReco/after/incl/hPt_kaon", "", {HistType::kTH1D, {axisPt}}); + + registry.addClone("trackMCReco/after/incl/", "trackMCReco/after/pos/"); + registry.addClone("trackMCReco/after/incl/", "trackMCReco/after/neg/"); + + registry.addClone("trackMCReco/after/", "trackMCReco/before/"); + } + + if (doprocessData) { + // track properties per centrality and per eta, pt bin + registry.add("incl/vnC_eta", "", kTProfile, {axisEtaVn}); + registry.add("incl/vnA_eta", "", kTProfile, {axisEtaVn}); + + registry.add("incl/vnC_pt", "", kTProfile, {axisPt}); + registry.add("incl/vnA_pt", "", kTProfile, {axisPt}); + registry.add("incl/vnC_pt_odd", "", kTProfile, {axisPt}); + registry.add("incl/vnA_pt_odd", "", kTProfile, {axisPt}); + + registry.add("incl/vnC_cent_minEta", "", kTProfile, {axisCent}); + registry.add("incl/vnA_cent_minEta", "", kTProfile, {axisCent}); + registry.add("incl/vnC_cent_plusEta", "", kTProfile, {axisCent}); + registry.add("incl/vnA_cent_plusEta", "", kTProfile, {axisCent}); + + if (cfgFillXandYterms) { + registry.add("incl/vnAx_eta", "", kTProfile, {axisEtaVn}); + registry.add("incl/vnAy_eta", "", kTProfile, {axisEtaVn}); + registry.add("incl/vnCx_eta", "", kTProfile, {axisEtaVn}); + registry.add("incl/vnCy_eta", "", kTProfile, {axisEtaVn}); + registry.add("incl/vnAx_pt", "", kTProfile, {axisPt}); + registry.add("incl/vnAy_pt", "", kTProfile, {axisPt}); + registry.add("incl/vnCx_pt", "", kTProfile, {axisPt}); + registry.add("incl/vnCy_pt", "", kTProfile, {axisPt}); + registry.add("incl/vnCx_pt_odd", "", kTProfile, {axisPt}); + registry.add("incl/vnAx_pt_odd", "", kTProfile, {axisPt}); + registry.add("incl/vnCy_pt_odd", "", kTProfile, {axisPt}); + registry.add("incl/vnAy_pt_odd", "", kTProfile, {axisPt}); + } + + if (cfgFillMixedHarmonics) { + registry.add("incl/vnAxCxUx_pt_MH", "", kTProfile, {axisPt}); + registry.add("incl/vnAxCyUx_pt_MH", "", kTProfile, {axisPt}); + registry.add("incl/vnAxCyUy_pt_MH", "", kTProfile, {axisPt}); + registry.add("incl/vnAyCxUy_pt_MH", "", kTProfile, {axisPt}); + + registry.add("incl/vnAxCxUx_cent_MH", "", kTProfile, {axisCent}); + registry.add("incl/vnAxCyUx_cent_MH", "", kTProfile, {axisCent}); + registry.add("incl/vnAxCyUy_cent_MH", "", kTProfile, {axisCent}); + registry.add("incl/vnAyCxUy_cent_MH", "", kTProfile, {axisCent}); + + registry.add("incl/vnAxCxUx_eta_MH", "", kTProfile, {axisEtaVn}); + registry.add("incl/vnAxCyUx_eta_MH", "", kTProfile, {axisEtaVn}); + registry.add("incl/vnAxCyUy_eta_MH", "", kTProfile, {axisEtaVn}); + registry.add("incl/vnAyCxUy_eta_MH", "", kTProfile, {axisEtaVn}); + } + + if (cfgFillEventPlane) { + registry.add("incl/vnA_cent_EP", "", kTProfile, {axisCent}); + registry.add("incl/vnC_cent_EP", "", kTProfile, {axisCent}); + registry.add("incl/vnFull_cent_EP", "", kTProfile, {axisCent}); + registry.add("incl/vnA_pt_EP", "", kTProfile, {axisPt}); + registry.add("incl/vnC_pt_EP", "", kTProfile, {axisPt}); + registry.add("incl/vnFull_pt_EP", "", kTProfile, {axisPt}); + registry.add("incl/vnA_eta_EP", "", kTProfile, {axisEtaVn}); + registry.add("incl/vnC_eta_EP", "", kTProfile, {axisEtaVn}); + registry.add("incl/vnFull_eta_EP", "", kTProfile, {axisEtaVn}); + } + + if (cfgFillQAHistos) { + registry.add("QA/qAqCX", "", kTProfile, {axisCent}); + registry.add("QA/qAqCY", "", kTProfile, {axisCent}); + registry.add("QA/qAqCXY", "", kTProfile, {axisCent}); + registry.add("QA/qAXqCY", "", kTProfile, {axisCent}); + registry.add("QA/qAYqCX", "", kTProfile, {axisCent}); + registry.add("QA/qAXYqCXY", "", kTProfile, {axisCent}); + + registry.add("QA/hSPplaneA", "hSPplaneA", kTH1D, {axisPhiPlane}); + registry.add("QA/hSPplaneC", "hSPplaneC", kTH1D, {axisPhiPlane}); + registry.add("QA/hSPplaneFull", "hSPplaneFull", kTH1D, {axisPhiPlane}); + + registry.add("QA/hCosPhiACosPhiC", "hCosPhiACosPhiC; Centrality(%); #LT Cos(#Psi^{A})Cos(#Psi^{C})#GT", kTProfile, {axisCent}); + registry.add("QA/hSinPhiASinPhiC", "hSinPhiASinPhiC; Centrality(%); #LT Sin(#Psi^{A})Sin(#Psi^{C})#GT", kTProfile, {axisCent}); + registry.add("QA/hSinPhiACosPhiC", "hSinPhiACosPhiC; Centrality(%); #LT Sin(#Psi^{A})Cos(#Psi^{C})#GT", kTProfile, {axisCent}); + registry.add("QA/hCosPhiASinsPhiC", "hCosPhiASinsPhiC; Centrality(%); #LT Cos(#Psi^{A})Sin(#Psi^{C})#GT", kTProfile, {axisCent}); + registry.add("QA/hFullEvPlaneRes", "hFullEvPlaneRes; Centrality(%); -#LT Cos(#Psi^{A} - #Psi^{C})#GT ", kTProfile, {axisCent}); + + registry.add("QA/after/PsiA_vs_Cent", "", {HistType::kTH2D, {axisPhiPlane, axisCent}}); + registry.add("QA/after/PsiC_vs_Cent", "", {HistType::kTH2D, {axisPhiPlane, axisCent}}); + registry.add("QA/after/PsiFull_vs_Cent", "", {HistType::kTH2D, {axisPhiPlane, axisCent}}); + + registry.add("QA/after/PsiA_vs_Vx", "", {HistType::kTH2D, {axisPhiPlane, axisVx}}); + registry.add("QA/after/PsiC_vs_Vx", "", {HistType::kTH2D, {axisPhiPlane, axisVx}}); + registry.add("QA/after/PsiFull_vs_Vx", "", {HistType::kTH2D, {axisPhiPlane, axisVx}}); + + registry.add("QA/after/PsiA_vs_Vy", "", {HistType::kTH2D, {axisPhiPlane, axisVy}}); + registry.add("QA/after/PsiC_vs_Vy", "", {HistType::kTH2D, {axisPhiPlane, axisVy}}); + registry.add("QA/after/PsiFull_vs_Vy", "", {HistType::kTH2D, {axisPhiPlane, axisVy}}); + + registry.add("QA/after/PsiA_vs_Vz", "", {HistType::kTH2D, {axisPhiPlane, axisVz}}); + registry.add("QA/after/PsiC_vs_Vz", "", {HistType::kTH2D, {axisPhiPlane, axisVz}}); + registry.add("QA/after/PsiFull_vs_Vz", "", {HistType::kTH2D, {axisPhiPlane, axisVz}}); + } + } + + registry.addClone("QA/after/", "QA/before/"); + + if (cfgFillChargeDependence) { + registry.addClone("incl/", "pos/"); + registry.addClone("incl/", "neg/"); + } + } + + if (doprocessMCGen) { + registry.add("trackMCGen/nCollReconstructedPerMcCollision", "", {HistType::kTH1D, {{10, -5, 5}}}); + registry.add("trackMCGen/before/incl/hPt_hadron", "", {HistType::kTH1D, {axisPt}}); + registry.add("trackMCGen/before/incl/hPt_proton", "", {HistType::kTH1D, {axisPt}}); + registry.add("trackMCGen/before/incl/hPt_pion", "", {HistType::kTH1D, {axisPt}}); + registry.add("trackMCGen/before/incl/hPt_kaon", "", {HistType::kTH1D, {axisPt}}); + registry.add("trackMCGen/before/incl/phi_eta_vtxZ_gen", "", {HistType::kTH3D, {axisPhi, axisEta, axisVz}}); + registry.addClone("trackMCGen/before/incl/", "trackMCGen/before/pos/"); + registry.addClone("trackMCGen/before/incl/", "trackMCGen/before/neg/"); + registry.addClone("trackMCGen/before/", "trackMCGen/after/"); + } + + registry.add("hEventCount", "Number of Event; Cut; #Events Passed Cut", {HistType::kTH1D, {{nEventSelections, 0, nEventSelections}}}); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_FilteredEvent + 1, "Filtered event"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_sel8 + 1, "Sel8"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_occupancy + 1, "kOccupancy"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kTVXinTRD + 1, "kTVXinTRD"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kNoSameBunchPileup + 1, "kNoSameBunchPileup"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsGoodZvtxFT0vsPV + 1, "kIsGoodZvtxFT0vsPV"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kNoCollInTimeRangeStandard + 1, "kNoCollInTimeRangeStandard"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsVertexITSTPC + 1, "kIsVertexITSTPC"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_MultCuts + 1, "Mult cuts (Alex)"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_CentCuts + 1, "Cenrality range"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsGoodITSLayersAll + 1, "kkIsGoodITSLayersAll"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_isSelectedZDC + 1, "isSelected"); + + registry.add("hTrackCount", "Number of Tracks; Cut; #Tracks Passed Cut", {HistType::kTH1D, {{nTrackSelections, 0, nTrackSelections}}}); + registry.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_Eta + 1, "Eta"); + registry.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_Pt + 1, "Pt"); + registry.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_DCAxy + 1, "DCAxy"); + registry.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_DCAz + 1, "DCAz"); + registry.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_GlobalTracks + 1, "GlobalTracks"); + registry.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_NCls + 1, "nClusters TPC"); + registry.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_FshCls + 1, "Frac. sh. Cls TPC"); + registry.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_TPCBoundary + 1, "TPC Boundary"); + registry.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_ZeroCharge + 1, "Only charged"); + registry.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_ParticleWeights + 1, "Apply weights"); + + if (cfgUseAdditionalEventCut) { + + int twoSigma = 2; + int threeSigma = 3; + // Fitted for LHC23zzh_pass4 + fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + + // Variables from fitting distribution with mean+1sigma + double fitParamLowPV1 = 2942.55; + double fitParamLowPV2 = -103.111; + double fitParamLowPV3 = 1.4397; + double fitParamLowPV4 = -0.00974862; + double fitParamLowPV5 = 2.71433e-05; + + if (cfgnSigmaMultCuts == twoSigma) { + fitParamLowPV1 = 2665.68; + fitParamLowPV2 = -93.3784; + fitParamLowPV3 = 1.27137; + fitParamLowPV4 = -0.00818936; + fitParamLowPV5 = 2.115e-05; + } else if (cfgnSigmaMultCuts == threeSigma) { + fitParamLowPV1 = 2389.99; + fitParamLowPV2 = -83.8483; + fitParamLowPV3 = 1.11062; + fitParamLowPV4 = -0.00672263; + fitParamLowPV5 = 1.54725e-05; + } + + fMultPVCutLow->SetParameters(fitParamLowPV1, fitParamLowPV2, fitParamLowPV3, fitParamLowPV4, fitParamLowPV5); + + fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + + // Variables from fitting distribution with mean+1sigma + double fitParamHighPV1 = 3508.13; + double fitParamHighPV2 = -124.831; + double fitParamHighPV3 = 1.87871; + double fitParamHighPV4 = -0.0145343; + double fitParamHighPV5 = 4.80688e-05; + + if (cfgnSigmaMultCuts == twoSigma) { + fitParamHighPV1 = 3787.93; + fitParamHighPV2 = -135.184; + fitParamHighPV3 = 2.07683; + fitParamHighPV4 = -0.0165997; + fitParamHighPV5 = 5.68725e-05; + } else if (cfgnSigmaMultCuts == threeSigma) { + fitParamHighPV1 = 4067.4; + fitParamHighPV2 = -145.485; + fitParamHighPV3 = 2.27273; + fitParamHighPV4 = -0.0186308; + fitParamHighPV5 = 6.5501e-05; + } + fMultPVCutHigh->SetParameters(fitParamHighPV1, fitParamHighPV2, fitParamHighPV3, fitParamHighPV4, fitParamHighPV5); + + fMultCutLow = new TF1("fMultCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + + double fitParamLow1 = 1566.5; + double fitParamLow2 = -48.2114; + double fitParamLow3 = 0.529522; + double fitParamLow4 = -0.00235284; + double fitParamLow5 = 3.01132e-06; + + if (cfgnSigmaMultCuts == twoSigma) { + fitParamLow1 = 1307.92; + fitParamLow2 = -39.9168; + fitParamLow3 = 0.412675; + fitParamLow4 = -0.00148081; + fitParamLow5 = 1.10868e-07; + } else if (cfgnSigmaMultCuts == threeSigma) { + fitParamLow1 = 1048.48; + fitParamLow2 = -31.4568; + fitParamLow3 = 0.287794; + fitParamLow4 = -0.00046847; + fitParamLow5 = -3.5909e-06; + } + fMultCutLow->SetParameters(fitParamLow1, fitParamLow2, fitParamLow3, fitParamLow4, fitParamLow5); + + fMultCutHigh = new TF1("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + + double fitParamHigh1 = 2089.73; + double fitParamHigh2 = -65.9772; + double fitParamHigh3 = 0.816781; + double fitParamHigh4 = -0.00496563; + double fitParamHigh5 = 1.34314e-05; + + if (cfgnSigmaMultCuts == twoSigma) { + fitParamHigh1 = 2350.39; + fitParamHigh2 = -74.6939; + fitParamHigh3 = 0.953287; + fitParamHigh4 = -0.006162; + fitParamHigh5 = 1.80808e-05; + } else if (cfgnSigmaMultCuts == threeSigma) { + fitParamHigh1 = 2610.98; + fitParamHigh2 = -83.3983; + fitParamHigh3 = 1.0893; + fitParamHigh4 = -0.00735094; + fitParamHigh5 = 2.26929e-05; + } + + fMultCutHigh->SetParameters(fitParamHigh1, fitParamHigh2, fitParamHigh3, fitParamHigh4, fitParamHigh5); + + if (cfgManualEventParameters) { + fMultPVCutLow->SetParameters((cfgMultPv.value)[0], (cfgMultPv.value)[1], (cfgMultPv.value)[2], (cfgMultPv.value)[3], (cfgMultPv.value)[4]); + fMultPVCutHigh->SetParameters((cfgMultPv.value)[5], (cfgMultPv.value)[6], (cfgMultPv.value)[7], (cfgMultPv.value)[8], (cfgMultPv.value)[9]); + fMultCutLow->SetParameters((cfgMult.value)[0], (cfgMult.value)[1], (cfgMult.value)[2], (cfgMult.value)[3], (cfgMult.value)[4]); + fMultCutHigh->SetParameters((cfgMult.value)[5], (cfgMult.value)[6], (cfgMult.value)[7], (cfgMult.value)[8], (cfgMult.value)[9]); + } + } + + if (cfgUseAdditionalTrackCut) { + fPhiCutLow = new TF1("fPhiCutLow", "0.06/x+pi/18.0-0.06", 0, 100); + fPhiCutHigh = new TF1("fPhiCutHigh", "0.1/x+pi/18.0+0.06", 0, 100); + } + } + + int getMagneticField(uint64_t timestamp) + { + // TODO done only once (and not per run). Will be replaced by CCDBConfigurable + // static o2::parameters::GRPObject* grpo = nullptr; + static o2::parameters::GRPMagField* grpo = nullptr; + if (grpo == nullptr) { + // grpo = ccdb->getForTimeStamp("GLO/GRP/GRP", timestamp); + grpo = ccdb->getForTimeStamp("GLO/Config/GRPMagField", timestamp); + if (grpo == nullptr) { + LOGF(fatal, "GRP object not found for timestamp %llu", timestamp); + return 0; + } + LOGF(info, "Retrieved GRP for timestamp %llu with magnetic field of %d kG", timestamp, grpo->getNominalL3Field()); + } + return grpo->getNominalL3Field(); + } + + // From Generic Framework + void loadCorrections(uint64_t timestamp) + { + // corrections saved on CCDB as TList {incl, pos, neg} of GFWWeights (acc) TH1D (eff) objects! + if (cfg.correctionsLoaded) + return; + + int nWeights = 3; + + if (cfgNUA.value.empty() == false) { + TList* listCorrections = ccdb->getForTimeStamp(cfgNUA, timestamp); + cfg.mAcceptance.push_back(reinterpret_cast(listCorrections->FindObject("weights"))); + cfg.mAcceptance.push_back(reinterpret_cast(listCorrections->FindObject("weights_positive"))); + cfg.mAcceptance.push_back(reinterpret_cast(listCorrections->FindObject("weights_negative"))); + int sizeAcc = cfg.mAcceptance.size(); + if (sizeAcc < nWeights) + LOGF(warning, "Could not load acceptance weights from %s", cfgNUA.value.c_str()); + else + LOGF(info, "Loaded acceptance weights from %s", cfgNUA.value.c_str()); + } else { + LOGF(info, "cfgNUA empty! No corrections loaded"); + } + if (cfgNUE.value.empty() == false) { + TList* listCorrections = ccdb->getForTimeStamp(cfgNUE, timestamp); + cfg.mEfficiency.push_back(reinterpret_cast(listCorrections->FindObject("Efficiency"))); + cfg.mEfficiency.push_back(reinterpret_cast(listCorrections->FindObject("Efficiency_pos"))); + cfg.mEfficiency.push_back(reinterpret_cast(listCorrections->FindObject("Efficiency_neg"))); + int sizeEff = cfg.mEfficiency.size(); + if (sizeEff < nWeights) + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgNUE.value.c_str()); + else + LOGF(info, "Loaded efficiency histogram from %s", cfgNUE.value.c_str()); + } else { + LOGF(info, "cfgNUE empty! No corrections loaded"); + } + cfg.correctionsLoaded = true; + } + + // From Generic Framework + bool setCurrentParticleWeights(int pID, float& weight_nue, float& weight_nua, const float& phi, const float& eta, const float& pt, const float& vtxz) + { + float eff = 1.; + int sizeEff = cfg.mEfficiency.size(); + if (sizeEff > pID) + eff = cfg.mEfficiency[pID]->GetBinContent(cfg.mEfficiency[pID]->FindBin(pt)); + else + eff = 1.0; + if (eff == 0) + return false; + weight_nue = 1. / eff; + int sizeAcc = cfg.mAcceptance.size(); + if (sizeAcc > pID) + weight_nua = cfg.mAcceptance[pID]->getNUA(phi, eta, vtxz); + else + weight_nua = 1; + return true; + } + + template + bool eventSelected(TCollision collision, const int& multTrk, const float& centrality) + { + if (!collision.sel8()) + return 0; + registry.fill(HIST("hEventCount"), evSel_sel8); + + // Occupancy + if (cfgDoOccupancySel) { + auto occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy > cfgMaxOccupancy) { + return 0; + } + registry.fill(HIST("hEventCount"), evSel_occupancy); + } + + if (cfgTVXinTRD) { + if (collision.alias_bit(kTVXinTRD)) { + // TRD triggered + // "CMTVX-B-NOPF-TRD,minbias_TVX" + return 0; + } + registry.fill(HIST("hEventCount"), evSel_kTVXinTRD); + } + + if (cfgNoSameBunchPileupCut) { + if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + // rejects collisions which are associated with the same "found-by-T0" bunch crossing + // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof + return 0; + } + registry.fill(HIST("hEventCount"), evSel_kNoSameBunchPileup); + } + if (cfgIsGoodZvtxFT0vsPV) { + if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference + // use this cut at low multiplicities with caution + return 0; + } + registry.fill(HIST("hEventCount"), evSel_kIsGoodZvtxFT0vsPV); + } + if (cfgNoCollInTimeRangeStandard) { + if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // Rejection of the collisions which have other events nearby + return 0; + } + registry.fill(HIST("hEventCount"), evSel_kNoCollInTimeRangeStandard); + } + + if (cfgIsVertexITSTPC) { + if (!collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + // selects collisions with at least one ITS-TPC track, and thus rejects vertices built from ITS-only tracks + return 0; + } + registry.fill(HIST("hEventCount"), evSel_kIsVertexITSTPC); + } + + if (cfgUseAdditionalEventCut) { + float vtxz = -999; + if (collision.numContrib() > 1) { + vtxz = collision.posZ(); + float zRes = std::sqrt(collision.covZZ()); + float minzRes = 0.25; + int maxNumContrib = 20; + if (zRes > minzRes && collision.numContrib() < maxNumContrib) + vtxz = -999; + } + + auto multNTracksPV = collision.multNTracksPV(); + + if (vtxz > cfgVtxZ || vtxz < -cfgVtxZ) + return 0; + if (multNTracksPV < fMultPVCutLow->Eval(collision.centFT0C())) + return 0; + if (multNTracksPV > fMultPVCutHigh->Eval(collision.centFT0C())) + return 0; + if (multTrk < fMultCutLow->Eval(collision.centFT0C())) + return 0; + if (multTrk > fMultCutHigh->Eval(collision.centFT0C())) + return 0; + + registry.fill(HIST("hEventCount"), evSel_MultCuts); + } + + if (centrality > cfgCentMax || centrality < cfgCentMin) + return 0; + registry.fill(HIST("hEventCount"), evSel_CentCuts); + + if (cfgIsGoodITSLayersAll) { + if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + // New event selection bits to cut time intervals with dead ITS staves + // https://indico.cern.ch/event/1493023/ (09-01-2025) + return 0; + } + registry.fill(HIST("hEventCount"), evSel_kIsGoodITSLayersAll); + } + + return 1; + } + + template + bool trackSelected(TrackObject track, const int& field) + { + if (std::fabs(track.eta()) > cfgEta) + return false; + registry.fill(HIST("hTrackCount"), trackSel_Eta); + + if (track.pt() < cfgPtmin || track.pt() > cfgPtmax) + return false; + + registry.fill(HIST("hTrackCount"), trackSel_Pt); + + if (track.dcaXY() > cfgDCAxy) + return false; + + registry.fill(HIST("hTrackCount"), trackSel_DCAxy); + + if (track.dcaZ() > cfgDCAz) + return false; + + registry.fill(HIST("hTrackCount"), trackSel_DCAz); + + // registry.fill(HIST("hTrackCount"), trackSel_GlobalTracks); + + if (track.tpcNClsFound() < cfgNcls) + return false; + registry.fill(HIST("hTrackCount"), trackSel_NCls); + + if (track.tpcFractionSharedCls() > cfgFshcls) + return false; + registry.fill(HIST("hTrackCount"), trackSel_FshCls); + + double phimodn = track.phi(); + if (field < 0) // for negative polarity field + phimodn = o2::constants::math::TwoPI - phimodn; + if (track.sign() < 0) // for negative charge + phimodn = o2::constants::math::TwoPI - phimodn; + if (phimodn < 0) + LOGF(warning, "phi < 0: %g", phimodn); + + phimodn += o2::constants::math::PI / 18.0; // to center gap in the middle + phimodn = fmod(phimodn, o2::constants::math::PI / 9.0); + if (cfgFillQAHistos) + registry.fill(HIST("QA/before/pt_phi"), track.pt(), phimodn); + + if (cfgUseAdditionalTrackCut) { + if (phimodn < fPhiCutHigh->Eval(track.pt()) && phimodn > fPhiCutLow->Eval(track.pt())) + return false; // reject track + } + if (cfgFillQAHistos) + registry.fill(HIST("QA/after/pt_phi"), track.pt(), phimodn); + registry.fill(HIST("hTrackCount"), trackSel_TPCBoundary); + return true; + } + + template + inline void fillEventQA(CollisionObject collision, TracksObject tracks) + { + static constexpr std::string_view Time[] = {"before", "after"}; + + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hCentFT0C"), collision.centFT0C()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hCentNGlobal"), collision.centNGlobal()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hCentFT0M"), collision.centFT0M()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hCentFV0A"), collision.centFV0A()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/globalTracks_centT0C"), collision.centFT0C(), tracks.size()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/globalTracks_PVTracks"), collision.multNTracksPV(), tracks.size()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/globalTracks_multT0A"), collision.multFT0A(), tracks.size()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/globalTracks_multV0A"), collision.multFV0A(), tracks.size()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/multV0A_multT0A"), collision.multFT0A(), collision.multFV0A()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/multT0C_centT0C"), collision.centFT0C(), collision.multFT0C()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/CentFT0C_vs_CentFT0Cvariant1"), collision.centFT0C(), collision.centFT0CVariant1()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/CentFT0C_vs_CentFT0M"), collision.centFT0C(), collision.centFT0M()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/CentFT0C_vs_CentFV0A"), collision.centFT0C(), collision.centFV0A()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/CentFT0C_vs_CentNGlobal"), collision.centFT0C(), collision.centNGlobal()); + + if constexpr (framework::has_type_v) { + double psiA = 1.0 * std::atan2(collision.qyA(), collision.qxA()); + double psiC = 1.0 * std::atan2(collision.qyC(), collision.qxC()); + double psiFull = 1.0 * std::atan2(collision.qyA() + collision.qyC(), collision.qxA() + collision.qxC()); + + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiA_vs_Cent"), psiA, collision.centFT0C()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiC_vs_Cent"), psiC, collision.centFT0C()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiFull_vs_Cent"), psiFull, collision.centFT0C()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiA_vs_Vx"), psiA, collision.vx()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiC_vs_Vx"), psiC, collision.vx()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiFull_vs_Vx"), psiFull, collision.vx()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiA_vs_Vy"), psiA, collision.vy()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiC_vs_Vy"), psiC, collision.vy()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiFull_vs_Vy"), psiFull, collision.vy()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiA_vs_Vz"), psiA, collision.posZ()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiC_vs_Vz"), psiC, collision.posZ()); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiFull_vs_Vz"), psiFull, collision.posZ()); + } + return; + } + + template + inline void fillHistograms(TrackObject track, float wacc, float weff, double ux, double uy, double uxMH, double uyMH, double qxA, double qyA, double qxC, double qyC, double corrQQx, double corrQQy, double corrQQ, double vnA, double vnC, double vnFull, double centrality) + { + registry.fill(HIST(Charge[ct]) + HIST("vnA_eta"), track.eta(), (uy * qyA + ux * qxA) / std::sqrt(std::fabs(corrQQ)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnC_eta"), track.eta(), (uy * qyC + ux * qxC) / std::sqrt(std::fabs(corrQQ)), wacc * weff); + + registry.fill(HIST(Charge[ct]) + HIST("vnA_pt"), track.pt(), (uy * qyA + ux * qxA) / std::sqrt(std::fabs(corrQQ)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnC_pt"), track.pt(), (uy * qyC + ux * qxC) / std::sqrt(std::fabs(corrQQ)), wacc * weff); + + if (cfgFillMixedHarmonics) { + registry.fill(HIST(Charge[ct]) + HIST("vnAxCxUx_eta_MH"), track.eta(), (uxMH * qxA * qxC) / corrQQx, wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnAxCyUx_eta_MH"), track.eta(), (uxMH * qyA * qyC) / corrQQy, wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnAxCyUy_eta_MH"), track.eta(), (uyMH * qxA * qyC) / corrQQx, wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnAyCxUy_eta_MH"), track.eta(), (uyMH * qyA * qxC) / corrQQy, wacc * weff); + + registry.fill(HIST(Charge[ct]) + HIST("vnAxCxUx_pt_MH"), track.pt(), (uxMH * qxA * qxC) / corrQQx, wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnAxCyUx_pt_MH"), track.pt(), (uxMH * qyA * qyC) / corrQQy, wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnAxCyUy_pt_MH"), track.pt(), (uyMH * qxA * qyC) / corrQQx, wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnAyCxUy_pt_MH"), track.pt(), (uyMH * qyA * qxC) / corrQQy, wacc * weff); + + registry.fill(HIST(Charge[ct]) + HIST("vnAxCxUx_cent_MH"), centrality, (uxMH * qxA * qxC) / corrQQx, wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnAxCyUx_cent_MH"), centrality, (uxMH * qyA * qyC) / corrQQy, wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnAxCyUy_cent_MH"), centrality, (uyMH * qxA * qyC) / corrQQx, wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnAyCxUy_cent_MH"), centrality, (uyMH * qyA * qxC) / corrQQy, wacc * weff); + } + + if (cfgFillXandYterms) { + registry.fill(HIST(Charge[ct]) + HIST("vnAx_eta"), track.eta(), (ux * qxA) / std::sqrt(std::fabs(corrQQx)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnAy_eta"), track.eta(), (uy * qyA) / std::sqrt(std::fabs(corrQQy)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnCx_eta"), track.eta(), (ux * qxC) / std::sqrt(std::fabs(corrQQx)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnCy_eta"), track.eta(), (uy * qyC) / std::sqrt(std::fabs(corrQQy)), wacc * weff); + + registry.fill(HIST(Charge[ct]) + HIST("vnAx_pt"), track.pt(), (ux * qxA) / std::sqrt(std::fabs(corrQQx)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnAy_pt"), track.pt(), (uy * qyA) / std::sqrt(std::fabs(corrQQy)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnCx_pt"), track.pt(), (ux * qxC) / std::sqrt(std::fabs(corrQQx)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnCy_pt"), track.pt(), (uy * qyC) / std::sqrt(std::fabs(corrQQy)), wacc * weff); + } + + if (cfgFillEventPlane) { + registry.fill(HIST(Charge[ct]) + HIST("vnA_eta_EP"), track.eta(), vnA, wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnC_eta_EP"), track.eta(), vnC, wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnFull_eta_EP"), track.eta(), vnFull, wacc * weff); + + registry.fill(HIST(Charge[ct]) + HIST("vnA_pt_EP"), track.pt(), vnA, wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnC_pt_EP"), track.pt(), vnC, wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnFull_pt_EP"), track.pt(), vnFull, wacc * weff); + + registry.fill(HIST(Charge[ct]) + HIST("vnA_cent_EP"), centrality, vnA, wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnC_cent_EP"), centrality, vnC, wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnFull_cent_EP"), centrality, vnFull, wacc * weff); + } + + // For integrated v1 take only tracks from eta>0. + // Following https://arxiv.org/pdf/1306.4145 + if (track.eta() < 0 && cfgHarm == 1) { + registry.fill(HIST(Charge[ct]) + HIST("vnA_cent_minEta"), centrality, -1.0 * (uy * qyA + ux * qxA) / std::sqrt(std::fabs(corrQQ)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnC_cent_minEta"), centrality, -1.0 * (uy * qyC + ux * qxC) / std::sqrt(std::fabs(corrQQ)), wacc * weff); + + registry.fill(HIST(Charge[ct]) + HIST("vnA_pt_odd"), track.pt(), -1.0 * (uy * qyA + ux * qxA) / std::sqrt(std::fabs(corrQQ)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnC_pt_odd"), track.pt(), -1.0 * (uy * qyC + ux * qxC) / std::sqrt(std::fabs(corrQQ)), wacc * weff); + + if (cfgFillXandYterms) { + registry.fill(HIST(Charge[ct]) + HIST("vnAx_pt_odd"), track.pt(), -1.0 * (ux * qxA) / std::sqrt(std::fabs(corrQQx)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnAy_pt_odd"), track.pt(), -1.0 * (uy * qyA) / std::sqrt(std::fabs(corrQQy)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnCx_pt_odd"), track.pt(), -1.0 * (ux * qxC) / std::sqrt(std::fabs(corrQQx)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnCy_pt_odd"), track.pt(), -1.0 * (uy * qyC) / std::sqrt(std::fabs(corrQQy)), wacc * weff); + } + } else { + registry.fill(HIST(Charge[ct]) + HIST("vnA_cent_plusEta"), centrality, (uy * qyA + ux * qxA) / std::sqrt(std::fabs(corrQQ)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnC_cent_plusEta"), centrality, (uy * qyC + ux * qxC) / std::sqrt(std::fabs(corrQQ)), wacc * weff); + + registry.fill(HIST(Charge[ct]) + HIST("vnA_pt_odd"), track.pt(), (uy * qyA + ux * qxA) / std::sqrt(std::fabs(corrQQ)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnC_pt_odd"), track.pt(), (uy * qyC + ux * qxC) / std::sqrt(std::fabs(corrQQ)), wacc * weff); + + if (cfgFillXandYterms) { + registry.fill(HIST(Charge[ct]) + HIST("vnAx_pt_odd"), track.pt(), (ux * qxA) / std::sqrt(std::fabs(corrQQx)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnAy_pt_odd"), track.pt(), (uy * qyA) / std::sqrt(std::fabs(corrQQy)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnCx_pt_odd"), track.pt(), (ux * qxC) / std::sqrt(std::fabs(corrQQx)), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("vnCy_pt_odd"), track.pt(), (uy * qyC) / std::sqrt(std::fabs(corrQQy)), wacc * weff); + } + } + } + + template + inline void fillTrackQA(TrackObject track, double vz, float wacc = 1, float weff = 1) + { + registry.fill(HIST(Charge[ct]) + HIST("QA/hPt"), track.pt()); + registry.fill(HIST(Charge[ct]) + HIST("QA/hPhi"), track.phi()); + registry.fill(HIST(Charge[ct]) + HIST("QA/hPhiCorrected"), track.phi(), wacc * weff); + registry.fill(HIST(Charge[ct]) + HIST("QA/hEta"), track.eta()); + registry.fill(HIST(Charge[ct]) + HIST("QA/hPhi_Eta_vz"), track.phi(), track.eta(), vz); + registry.fill(HIST(Charge[ct]) + HIST("QA/hDCAxy_pt"), track.pt(), track.dcaXY()); + registry.fill(HIST(Charge[ct]) + HIST("QA/hDCAz_pt"), track.pt(), track.dcaZ()); + registry.fill(HIST(Charge[ct]) + HIST("QA/hSharedClusters_pt"), track.pt(), track.tpcFractionSharedCls()); + registry.fill(HIST(Charge[ct]) + HIST("QA/hCrossedRows_pt"), track.pt(), track.tpcNClsFound()); + } + + template + inline void fillMCPtHistos(TrackObject track, int pdgCode) + { + static constexpr std::string_view Time[] = {"before/", "after/"}; + static constexpr std::string_view Mode[] = {"Gen/", "Reco/"}; + + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("incl/hPt_hadron"), track.pt()); + if (pdgCode > 0) { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("pos/hPt_hadron"), track.pt()); + } else { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("neg/hPt_hadron"), track.pt()); + } + + if (pdgCode == kPiPlus || pdgCode == kPiMinus) { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("incl/hPt_pion"), track.pt()); + if (pdgCode == kPiPlus) { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("pos/hPt_pion"), track.pt()); + } else { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("neg/hPt_pion"), track.pt()); + } + } else if (pdgCode == kKPlus || pdgCode == kKMinus) { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("incl/hPt_kaon"), track.pt()); + if (pdgCode == kKPlus) { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("pos/hPt_kaon"), track.pt()); + } else { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("neg/hPt_kaon"), track.pt()); + } + } else if (pdgCode == kProton || pdgCode == kProtonBar) { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("incl/hPt_proton"), track.pt()); + if (pdgCode == kProton) { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("pos/hPt_proton"), track.pt()); + } else { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("neg/hPt_proton"), track.pt()); + } + } + } + + void processData(UsedCollisions::iterator const& collision, aod::BCsWithTimestamps const&, UsedTracks const& tracks) + { + registry.fill(HIST("hEventCount"), evSel_FilteredEvent); + auto bc = collision.bc_as(); + int standardMagField = 99999; + auto field = (cfgMagField == standardMagField) ? getMagneticField(bc.timestamp()) : cfgMagField; + + if (bc.runNumber() != cfg.lastRunNumber) { + // load corrections again for new run! + cfg.correctionsLoaded = false; + cfg.lastRunNumber = bc.runNumber(); + } + if (cfgFillQAHistos) + fillEventQA(collision, tracks); + + loadCorrections(bc.timestamp()); + + float centrality = collision.centFT0C(); + + if (cfgCentFT0Cvariant1) + centrality = collision.centFT0CVariant1(); + if (cfgCentFT0M) + centrality = collision.centFT0M(); + if (cfgCentFV0A) + centrality = collision.centFV0A(); + if (cfgCentNGlobal) + centrality = collision.centNGlobal(); + + if (!eventSelected(collision, tracks.size(), centrality)) + return; + + if (collision.isSelected()) { + + registry.fill(HIST("hEventCount"), evSel_isSelectedZDC); + + double qxA = collision.qxA(); + double qyA = collision.qyA(); + double qxC = collision.qxC(); + double qyC = collision.qyC(); + + double vtxz = collision.posZ(); + double psiA = 1.0 * std::atan2(qyA, qxA); + double psiC = 1.0 * std::atan2(qyC, qxC); + + // https://twiki.cern.ch/twiki/pub/ALICE/DirectedFlowAnalysisNote/vn_ZDC_ALICE_INT_NOTE_version02.pdf + double psiFull = 1.0 * std::atan2(qyA + qyC, qxA + qxC); + + if (cfgFillQAHistos) { + fillEventQA(collision, tracks); + + registry.fill(HIST("QA/hSPplaneA"), psiA, 1); + registry.fill(HIST("QA/hSPplaneC"), psiC, 1); + registry.fill(HIST("QA/hSPplaneFull"), psiFull, 1); + registry.fill(HIST("QA/hCosPhiACosPhiC"), centrality, std::cos(psiA) * std::cos(psiC)); + registry.fill(HIST("QA/hSinPhiASinPhiC"), centrality, std::sin(psiA) * std::sin(psiC)); + registry.fill(HIST("QA/hSinPhiACosPhiC"), centrality, std::sin(psiA) * std::cos(psiC)); + registry.fill(HIST("QA/hCosPhiASinsPhiC"), centrality, std::cos(psiA) * std::sin(psiC)); + registry.fill(HIST("QA/hFullEvPlaneRes"), centrality, -1 * std::cos(psiA - psiC)); + registry.fill(HIST("QA/qAqCXY"), centrality, qxA * qxC + qyA * qyC); + registry.fill(HIST("QA/qAXqCY"), centrality, qxA * qyC); + registry.fill(HIST("QA/qAYqCX"), centrality, qyA * qxC); + registry.fill(HIST("QA/qAXYqCXY"), centrality, qyA * qxC + qxA * qyC); + registry.fill(HIST("QA/qAqCX"), centrality, qxA * qxC); + registry.fill(HIST("QA/qAqCY"), centrality, qyA * qyC); + } + + double corrQQ = 1., corrQQx = 1., corrQQy = 1.; + + // Load correlations and SP resolution needed for Scalar Product and event plane methods. + // Only load once! + // If not loaded set to 1 + if (cfgLoadAverageQQ) { + if (!cfg.clQQ) { + TList* hcorrList = ccdb->getForTimeStamp(cfgCCDBdir.value, bc.timestamp()); + cfg.hcorrQQ = reinterpret_cast(hcorrList->FindObject("qAqCXY")); + cfg.hcorrQQx = reinterpret_cast(hcorrList->FindObject("qAqCX")); + cfg.hcorrQQy = reinterpret_cast(hcorrList->FindObject("qAqCY")); + cfg.clQQ = true; + } + corrQQ = cfg.hcorrQQ->GetBinContent(cfg.hcorrQQ->FindBin(centrality)); + corrQQx = cfg.hcorrQQx->GetBinContent(cfg.hcorrQQx->FindBin(centrality)); + corrQQy = cfg.hcorrQQy->GetBinContent(cfg.hcorrQQy->FindBin(centrality)); + } + + double evPlaneRes = 1.; + if (cfgLoadSPPlaneRes) { + if (!cfg.clEvPlaneRes) { + cfg.hEvPlaneRes = ccdb->getForTimeStamp(cfgCCDBdir_SP.value, bc.timestamp()); + cfg.clEvPlaneRes = true; + } + evPlaneRes = cfg.hEvPlaneRes->GetBinContent(cfg.hEvPlaneRes->FindBin(centrality)); + if (evPlaneRes < 0) + LOGF(fatal, " > 0 for centrality %.2f! Cannot determine resolution.. Change centrality ranges!!!", centrality); + evPlaneRes = std::sqrt(evPlaneRes); + } + + for (const auto& track : tracks) { + if (cfgFillQAHistos) + registry.fill(HIST("QA/before/hPt_inclusive"), track.pt()); + + // registry.fill(HIST("hTrackCount"), trackSel_FilteredTracks); + + float weff = 1., wacc = 1.; + float weffP = 1., waccP = 1.; + float weffN = 1., waccN = 1.; + + if (!trackSelected(track, field)) + continue; + + if (track.sign() == 0.0) + continue; + + registry.fill(HIST("hTrackCount"), trackSel_ZeroCharge); + bool pos = (track.sign() > 0) ? true : false; + + // Fill NUA weights + if (cfgFillWeights) { + fWeights->fill(track.phi(), track.eta(), vtxz, track.pt(), centrality, 0); + } + if (cfgFillWeightsPOS) { + if (pos) + fWeightsPOS->fill(track.phi(), track.eta(), vtxz, track.pt(), centrality, 0); + } + if (cfgFillWeightsNEG) { + if (!pos) + fWeightsNEG->fill(track.phi(), track.eta(), vtxz, track.pt(), centrality, 0); + } + + // Set weff and wacc for inclusice, negative and positive hadrons + if (!setCurrentParticleWeights(kInclusive, weff, wacc, track.phi(), track.eta(), track.pt(), vtxz)) + continue; + if (pos && !setCurrentParticleWeights(kPositive, weffP, waccP, track.phi(), track.eta(), track.pt(), vtxz)) + continue; + if (!pos && !setCurrentParticleWeights(kNegative, weffN, waccN, track.phi(), track.eta(), track.pt(), vtxz)) + continue; + + registry.fill(HIST("hTrackCount"), trackSel_ParticleWeights); + + if (cfgFillQAHistos) + registry.fill(HIST("QA/after/hPt_inclusive"), track.pt(), wacc * weff); + + // // constrain angle to 0 -> [0,0+2pi] + auto phi = RecoDecay::constrainAngle(track.phi(), 0); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + auto ux = std::cos(cfgHarm * phi); + auto uy = std::sin(cfgHarm * phi); + + auto uxMH = std::cos(cfgHarmMixed * phi); + auto uyMH = std::sin(cfgHarmMixed * phi); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + double vnA = std::cos(cfgHarm * (phi - psiA)) / evPlaneRes; + double vnC = std::cos(cfgHarm * (phi - psiC)) / evPlaneRes; + double vnFull = std::cos(cfgHarm * (phi - psiFull)) / evPlaneRes; + + fillHistograms(track, wacc, weff, ux, uy, uxMH, uyMH, qxA, qyA, qxC, qyC, corrQQx, corrQQy, corrQQ, vnA, vnC, vnFull, centrality); + + if (cfgFillQAHistos) + fillTrackQA(track, vtxz, wacc, weff); + + if (cfgFillChargeDependence) { + if (pos) { + fillHistograms(track, waccP, weffP, ux, uy, uxMH, uyMH, qxA, qyA, qxC, qyC, corrQQx, corrQQy, corrQQ, vnA, vnC, vnFull, centrality); + fillTrackQA(track, vtxz, waccP, weffP); + } else { + fillHistograms(track, waccN, weffN, ux, uy, uxMH, uyMH, qxA, qyA, qxC, qyC, corrQQx, corrQQy, corrQQ, vnA, vnC, vnFull, centrality); + fillTrackQA(track, vtxz, waccN, weffN); + } + } + } // end of track loop + } // end of collision isSelected loop + } + PROCESS_SWITCH(FlowSP, processData, "Process analysis for non-derived data", true); + + void processMCReco(CC const& collision, aod::BCsWithTimestamps const&, TCs const& tracks, FilteredTCs const& filteredTracks, aod::McParticles const&) + { + auto bc = collision.template bc_as(); + int standardMagField = 99999; + auto field = (cfgMagField == standardMagField) ? getMagneticField(bc.timestamp()) : cfgMagField; + + double vtxz = collision.posZ(); + float centrality = collision.centFT0C(); + if (cfgCentFT0Cvariant1) + centrality = collision.centFT0CVariant1(); + if (cfgCentFT0M) + centrality = collision.centFT0M(); + if (cfgCentFV0A) + centrality = collision.centFV0A(); + if (cfgCentNGlobal) + centrality = collision.centNGlobal(); + + if (cfgFillQAHistos) + fillEventQA(collision, tracks); + + if (!eventSelected(collision, filteredTracks.size(), centrality)) + return; + + if (!collision.has_mcCollision()) { + LOGF(info, "No mccollision found for this collision"); + return; + } + + if (cfgFillQAHistos) + fillEventQA(collision, tracks); + + // LOGF(info, "Size of tracks: %i", tracks.size()); + registry.fill(HIST("trackMCReco/hTrackSize_unFiltered"), tracks.size()); + registry.fill(HIST("trackMCReco/hTrackSize_Filtered"), filteredTracks.size()); + + for (const auto& track : filteredTracks) { + auto mcParticle = track.mcParticle(); + if (track.sign() == 0.0) + continue; + registry.fill(HIST("hTrackCount"), trackSel_ZeroCharge); + + fillMCPtHistos(track, mcParticle.pdgCode()); + + if (!mcParticle.isPhysicalPrimary()) { + registry.fill(HIST("trackMCReco/before/hIsPhysicalPrimary"), 0); + continue; + } else { + registry.fill(HIST("trackMCReco/before/hIsPhysicalPrimary"), 1); + } + + if (!trackSelected(track, field)) + continue; + + fillMCPtHistos(track, mcParticle.pdgCode()); + + if (cfgFillQAHistos) + fillTrackQA(track, vtxz); + + } // end of track loop + } + PROCESS_SWITCH(FlowSP, processMCReco, "Process analysis for MC reconstructed events", false); + + // Filter mcCollFilter = nabs(aod::mccollision::posZ) < cfgVtxZ; + void processMCGen(aod::McCollisions const& mcCollisions, CCs const& collisions, TCs const& tracks, FilteredTCs const& filteredTracks, MCs const& McParts) + { + // LOGF(info, "Size of mccollisions: %i", mcCollisions.size()); + + for (const auto& mcCollision : mcCollisions) { + float centrality = -1; + bool colSelected = true; + + // get McParticles which belong to mccollision + auto partSlice = McParts.sliceBy(partPerMcCollision, mcCollision.globalIndex()); + + // get reconstructed collision which belongs to mccollision + auto colSlice = collisions.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + registry.fill(HIST("trackMCGen/nCollReconstructedPerMcCollision"), colSlice.size()); + if (colSlice.size() != 1) { // check if MC collision is only reconstructed once! (https://indico.cern.ch/event/1425820/contributions/6170879/attachments/2947721/5180548/DDChinellato-O2AT4-HandsOn-03a.pdf) + continue; + } + + for (const auto& col : colSlice) { + // get tracks that belong to reconstructed collision + auto trackSlice = tracks.sliceBy(trackPerCollision, col.globalIndex()); + + auto filteredTrackSlice = filteredTracks.sliceBy(trackPerCollision, col.globalIndex()); + + centrality = col.centFT0C(); + if (cfgCentFT0Cvariant1) + centrality = col.centFT0CVariant1(); + if (cfgCentFT0M) + centrality = col.centFT0M(); + if (cfgCentFV0A) + centrality = col.centFV0A(); + if (cfgCentNGlobal) + centrality = col.centNGlobal(); + fillEventQA(col, trackSlice); + if (trackSlice.size() < 1) { + colSelected = false; + continue; + } + if (!eventSelected(col, filteredTrackSlice.size(), centrality)) { + colSelected = false; + continue; + } + fillEventQA(col, trackSlice); + + if (!colSelected) + continue; + + float vtxz = mcCollision.posZ(); + + for (const auto& particle : partSlice) { + if (!particle.isPhysicalPrimary()) + continue; + + int charge = 0; + ; + + auto pdgCode = particle.pdgCode(); + auto pdgInfo = pdg->GetParticle(pdgCode); + if (pdgInfo != nullptr) { + charge = pdgInfo->Charge(); + } + + if (std::fabs(charge) < 1) + continue; + + bool pos = (charge > 0) ? true : false; + + fillMCPtHistos(particle, pdgCode); + + registry.fill(HIST("trackMCGen/before/incl/phi_eta_vtxZ_gen"), particle.phi(), particle.eta(), vtxz); + + if (pos) { + registry.fill(HIST("trackMCGen/before/pos/phi_eta_vtxZ_gen"), particle.phi(), particle.eta(), vtxz); + } else { + registry.fill(HIST("trackMCGen/before/neg/phi_eta_vtxZ_gen"), particle.phi(), particle.eta(), vtxz); + } + + if (particle.eta() < -cfgEta || particle.eta() > cfgEta || particle.pt() < cfgPtmin || particle.pt() > cfgPtmax) + continue; + + fillMCPtHistos(particle, pdgCode); + + registry.fill(HIST("trackMCGen/after/incl/phi_eta_vtxZ_gen"), particle.phi(), particle.eta(), vtxz); + + if (pos) { + registry.fill(HIST("trackMCGen/after/pos/phi_eta_vtxZ_gen"), particle.phi(), particle.eta(), vtxz); + } else { + registry.fill(HIST("trackMCGen/after/neg/phi_eta_vtxZ_gen"), particle.phi(), particle.eta(), vtxz); + } + } + } + } + } + PROCESS_SWITCH(FlowSP, processMCGen, "Process analysis for MC generated events", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Flow/Tasks/flowTask.cxx b/PWGCF/Flow/Tasks/flowTask.cxx new file mode 100644 index 00000000000..91c7402cf90 --- /dev/null +++ b/PWGCF/Flow/Tasks/flowTask.cxx @@ -0,0 +1,856 @@ +// 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 flowTask.cxx +/// \author Zhiyong Lu (zhiyong.lu@cern.ch) +/// \since Dec/10/2023 +/// \brief jira: PWGCF-254, task to measure flow observables with cumulant method + +#include +#include +#include +#include +#include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/CCDB/ctpRateFetcher.h" + +#include "GFWPowerArray.h" +#include "GFW.h" +#include "GFWCumulant.h" +#include "GFWWeights.h" +#include "FlowContainer.h" +#include "TList.h" +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct FlowTask { + + O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCentEstimator, int, 0, "0:FT0C; 1:FT0CVariant1; 2:FT0M; 3:FT0A") + O2_DEFINE_CONFIGURABLE(cfgCentFT0CMin, float, 0.0f, "Minimum centrality (FT0C) to cut events in filter") + O2_DEFINE_CONFIGURABLE(cfgCentFT0CMax, float, 100.0f, "Maximum centrality (FT0C) to cut events in filter") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMin, float, 0.2f, "Minimal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMax, float, 10.0f, "Maximal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtRefMin, float, 0.2f, "Minimal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtRefMax, float, 3.0f, "Maximal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for all tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 10.0f, "Maximal pT for all tracks") + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5f, "max chi2 per TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutTPCclu, float, 70.0f, "minimum TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutITSclu, float, 5.0f, "minimum ITS clusters") + O2_DEFINE_CONFIGURABLE(cfgCutDCAz, float, 2.0f, "max DCA to vertex z") + O2_DEFINE_CONFIGURABLE(cfgCutDCAxyppPass3Enabled, bool, false, "switch of ppPass3 DCAxy pt dependent cut") + O2_DEFINE_CONFIGURABLE(cfgCutDCAzPtDepEnabled, bool, false, "switch of DCAz pt dependent cut") + O2_DEFINE_CONFIGURABLE(cfgTrkSelSwitch, bool, false, "switch for self-defined track selection") + O2_DEFINE_CONFIGURABLE(cfgUseAdditionalEventCut, bool, false, "Use additional event cut on mult correlations") + O2_DEFINE_CONFIGURABLE(cfgUseTentativeEventCounter, bool, false, "After sel8(), count events regardless of real event selection") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoSameBunchPileup, bool, false, "rejects collisions which are associated with the same found-by-T0 bunch crossing") + O2_DEFINE_CONFIGURABLE(cfgEvSelkIsGoodZvtxFT0vsPV, bool, false, "removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference, use this cut at low multiplicities with caution") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoCollInTimeRangeStandard, bool, false, "no collisions in specified time range") + O2_DEFINE_CONFIGURABLE(cfgEvSelkIsGoodITSLayersAll, bool, true, "cut time intervals with dead ITS staves") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoCollInRofStandard, bool, false, "no other collisions in this Readout Frame with per-collision multiplicity above threshold") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoHighMultCollInPrevRof, bool, false, "veto an event if FT0C amplitude in previous ITS ROF is above threshold") + O2_DEFINE_CONFIGURABLE(cfgEvSelMultCorrelation, bool, true, "Multiplicity correlation cut") + O2_DEFINE_CONFIGURABLE(cfgEvSelV0AT0ACut, bool, true, "V0A T0A 5 sigma cut") + O2_DEFINE_CONFIGURABLE(cfgGetInteractionRate, bool, false, "Get interaction rate from CCDB") + O2_DEFINE_CONFIGURABLE(cfgUseInteractionRateCut, bool, false, "Use events with low interaction rate") + O2_DEFINE_CONFIGURABLE(cfgCutMaxIR, float, 50.0f, "maximum interaction rate (kHz)") + O2_DEFINE_CONFIGURABLE(cfgCutMinIR, float, 0.0f, "minimum interaction rate (kHz)") + O2_DEFINE_CONFIGURABLE(cfgUseNch, bool, false, "Use Nch for flow observables") + O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 30, "Number of subsamples") + O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeights, bool, false, "Fill and output NUA weights") + O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeightsRefPt, bool, false, "NUA weights are filled in ref pt bins") + O2_DEFINE_CONFIGURABLE(cfgEfficiency, std::string, "", "CCDB path to efficiency object") + O2_DEFINE_CONFIGURABLE(cfgAcceptance, std::string, "", "CCDB path to acceptance object") + O2_DEFINE_CONFIGURABLE(cfgAcceptanceList, std::string, "", "CCDB path to acceptance lsit object") + O2_DEFINE_CONFIGURABLE(cfgAcceptanceListEnabled, bool, false, "switch of acceptance list") + O2_DEFINE_CONFIGURABLE(cfgEvSelOccupancy, bool, true, "Occupancy cut") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyHigh, int, 500, "High cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyLow, int, 0, "Low cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgUseSmallMemory, bool, false, "Use small memory mode") + O2_DEFINE_CONFIGURABLE(cfgTrackDensityCorrUse, bool, false, "Use track density efficiency correction") + Configurable> cfgUserDefineGFWCorr{"cfgUserDefineGFWCorr", std::vector{"refN02 {2} refP02 {-2}", "refN12 {2} refP12 {-2}"}, "User defined GFW CorrelatorConfig"}; + Configurable> cfgUserDefineGFWName{"cfgUserDefineGFWName", std::vector{"Ch02Gap22", "Ch12Gap22"}, "User defined GFW Name"}; + Configurable> cfgRunRemoveList{"cfgRunRemoveList", std::vector{-1}, "excluded run numbers"}; + Configurable> cfgTrackDensityP0{"cfgTrackDensityP0", std::vector{0.7217476707, 0.7384792571, 0.7542625668, 0.7640680200, 0.7701951667, 0.7755299053, 0.7805901710, 0.7849446786, 0.7957356586, 0.8113039262, 0.8211968966, 0.8280558878, 0.8329342135}, "parameter 0 for track density efficiency correction"}; + Configurable> cfgTrackDensityP1{"cfgTrackDensityP1", std::vector{-2.169488e-05, -2.191913e-05, -2.295484e-05, -2.556538e-05, -2.754463e-05, -2.816832e-05, -2.846502e-05, -2.843857e-05, -2.705974e-05, -2.477018e-05, -2.321730e-05, -2.203315e-05, -2.109474e-05}, "parameter 1 for track density efficiency correction"}; + + ConfigurableAxis axisPtHist{"axisPtHist", {100, 0., 10.}, "pt axis for histograms"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.2, 2.4, 2.6, 2.8, 3, 3.5, 4, 5, 6, 8, 10}, "pt axis for histograms"}; + ConfigurableAxis axisIndependent{"axisIndependent", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}, "X axis for histograms"}; + ConfigurableAxis axisNch{"axisNch", {4000, 0, 4000}, "N_{ch}"}; + ConfigurableAxis axisDCAz{"axisDCAz", {200, -2, 2}, "DCA_{z} (cm)"}; + ConfigurableAxis axisDCAxy{"axisDCAxy", {200, -1, 1}, "DCA_{xy} (cm)"}; + + Filter collisionFilter = (nabs(aod::collision::posZ) < cfgCutVertex) && (aod::cent::centFT0C > cfgCentFT0CMin) && (aod::cent::centFT0C < cfgCentFT0CMax); + Filter trackFilter = ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtMin) && (aod::track::pt < cfgCutPtMax) && (aod::track::tpcChi2NCl < cfgCutChi2prTPCcls) && (nabs(aod::track::dcaZ) < cfgCutDCAz); + + // Corrections + TH1D* mEfficiency = nullptr; + GFWWeights* mAcceptance = nullptr; + TObjArray* mAcceptanceList = nullptr; + bool correctionsLoaded = false; + + // Connect to ccdb + Service ccdb; + Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + // Define output + OutputObj fFC{FlowContainer("FlowContainer")}; + OutputObj fWeights{GFWWeights("weights")}; + HistogramRegistry registry{"registry"}; + + // define global variables + GFW* fGFW = new GFW(); + std::vector corrconfigs; + TAxis* fPtAxis; + TRandom3* fRndm = new TRandom3(0); + enum CentEstimators { + kCentFT0C = 0, + kCentFT0CVariant1, + kCentFT0M, + kCentFV0A, + // Count the total number of enum + kCount_CentEstimators + }; + int mRunNumber{-1}; + uint64_t mSOR{0}; + double mMinSeconds{-1.}; + std::unordered_map gHadronicRate; + ctpRateFetcher mRateFetcher; + TH2* gCurrentHadronicRate; + + // phi-EP correction + std::vector funcEff; + TH1D* hFindPtBin; + TF1* funcV2; + TF1* funcV3; + TF1* funcV4; + + using AodCollisions = soa::Filtered>; + using AodTracks = soa::Filtered>; + + // Track selection + TrackSelection myTrackSel; + TF1* fPhiCutLow = nullptr; + TF1* fPhiCutHigh = nullptr; + // Additional Event selection cuts - Copy from flowGenericFramework.cxx + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + TF1* fMultCutLow = nullptr; + TF1* fMultCutHigh = nullptr; + TF1* fMultMultPVCut = nullptr; + TF1* fT0AV0AMean = nullptr; + TF1* fT0AV0ASigma = nullptr; + + void init(InitContext const&) + { + const AxisSpec axisVertex{40, -20, 20, "Vtxz (cm)"}; + const AxisSpec axisPhi{60, 0.0, constants::math::TwoPI, "#varphi"}; + const AxisSpec axisEta{40, -1., 1., "#eta"}; + const AxisSpec axisCentForQA{100, 0, 100, "centrality (%)"}; + const AxisSpec axisT0C{70, 0, 70000, "N_{ch} (T0C)"}; + const AxisSpec axisT0A{200, 0, 200000, "N_{ch} (T0A)"}; + + ccdb->setURL(ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setCreatedNotAfter(ccdbNoLaterThan.value); + + // Add some output objects to the histogram registry + // Event QA + registry.add("hEventCount", "Number of Event;; Count", {HistType::kTH1D, {{5, 0, 5}}}); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(1, "Filtered event"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(2, "after sel8"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(3, "after supicious Runs removal"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(4, "after additional event cut"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(5, "after correction loads"); + registry.add("hEventCountSpecific", "Number of Event;; Count", {HistType::kTH1D, {{10, 0, 10}}}); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(1, "after sel8"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(2, "kNoSameBunchPileup"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(3, "kIsGoodZvtxFT0vsPV"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(4, "kNoCollInTimeRangeStandard"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(5, "kIsGoodITSLayersAll"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(6, "kNoCollInRofStandard"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(7, "kNoHighMultCollInPrevRof"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(8, "occupancy"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(9, "MultCorrelation"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(10, "cfgEvSelV0AT0ACut"); + if (cfgUseTentativeEventCounter) { + registry.add("hEventCountTentative", "Number of Event;; Count", {HistType::kTH1D, {{10, 0, 10}}}); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(1, "after sel8"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(2, "kNoSameBunchPileup"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(3, "kIsGoodZvtxFT0vsPV"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(4, "kNoCollInTimeRangeStandard"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(5, "kIsGoodITSLayersAll"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(6, "kNoCollInRofStandard"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(7, "kNoHighMultCollInPrevRof"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(8, "occupancy"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(9, "MultCorrelation"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(10, "cfgEvSelV0AT0ACut"); + } + registry.add("hVtxZ", "Vexter Z distribution", {HistType::kTH1D, {axisVertex}}); + registry.add("hMult", "Multiplicity distribution", {HistType::kTH1D, {{3000, 0.5, 3000.5}}}); + std::string hCentTitle = "Centrality distribution, Estimator " + std::to_string(cfgCentEstimator); + registry.add("hCent", hCentTitle.c_str(), {HistType::kTH1D, {{90, 0, 90}}}); + if (!cfgUseSmallMemory) { + registry.add("BeforeSel8_globalTracks_centT0C", "before sel8;Centrality T0C;mulplicity global tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + registry.add("BeforeCut_globalTracks_centT0C", "before cut;Centrality T0C;mulplicity global tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + registry.add("BeforeCut_PVTracks_centT0C", "before cut;Centrality T0C;mulplicity PV tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + registry.add("BeforeCut_globalTracks_PVTracks", "before cut;mulplicity PV tracks;mulplicity global tracks", {HistType::kTH2D, {axisNch, axisNch}}); + registry.add("BeforeCut_globalTracks_multT0A", "before cut;mulplicity T0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + registry.add("BeforeCut_globalTracks_multV0A", "before cut;mulplicity V0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + registry.add("BeforeCut_multV0A_multT0A", "before cut;mulplicity T0A;mulplicity V0A", {HistType::kTH2D, {axisT0A, axisT0A}}); + registry.add("BeforeCut_multT0C_centT0C", "before cut;Centrality T0C;mulplicity T0C", {HistType::kTH2D, {axisCentForQA, axisT0C}}); + registry.add("globalTracks_centT0C", "after cut;Centrality T0C;mulplicity global tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + registry.add("PVTracks_centT0C", "after cut;Centrality T0C;mulplicity PV tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + registry.add("globalTracks_PVTracks", "after cut;mulplicity PV tracks;mulplicity global tracks", {HistType::kTH2D, {axisNch, axisNch}}); + registry.add("globalTracks_multT0A", "after cut;mulplicity T0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + registry.add("globalTracks_multV0A", "after cut;mulplicity V0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + registry.add("multV0A_multT0A", "after cut;mulplicity T0A;mulplicity V0A", {HistType::kTH2D, {axisT0A, axisT0A}}); + registry.add("multT0C_centT0C", "after cut;Centrality T0C;mulplicity T0C", {HistType::kTH2D, {axisCentForQA, axisT0C}}); + registry.add("centFT0CVar_centFT0C", "after cut;Centrality T0C;Centrality T0C Var", {HistType::kTH2D, {axisCentForQA, axisCentForQA}}); + registry.add("centFT0M_centFT0C", "after cut;Centrality T0C;Centrality T0M", {HistType::kTH2D, {axisCentForQA, axisCentForQA}}); + registry.add("centFV0A_centFT0C", "after cut;Centrality T0C;Centrality V0A", {HistType::kTH2D, {axisCentForQA, axisCentForQA}}); + } + // Track QA + registry.add("hPhi", "#phi distribution", {HistType::kTH1D, {axisPhi}}); + registry.add("hPhiWeighted", "corrected #phi distribution", {HistType::kTH1D, {axisPhi}}); + registry.add("hEta", "#eta distribution", {HistType::kTH1D, {axisEta}}); + registry.add("hPt", "p_{T} distribution before cut", {HistType::kTH1D, {axisPtHist}}); + registry.add("hPtRef", "p_{T} distribution after cut", {HistType::kTH1D, {axisPtHist}}); + registry.add("hChi2prTPCcls", "#chi^{2}/cluster for the TPC track segment", {HistType::kTH1D, {{100, 0., 5.}}}); + registry.add("hChi2prITScls", "#chi^{2}/cluster for the ITS track", {HistType::kTH1D, {{100, 0., 50.}}}); + registry.add("hnTPCClu", "Number of found TPC clusters", {HistType::kTH1D, {{100, 40, 180}}}); + registry.add("hnITSClu", "Number of found ITS clusters", {HistType::kTH1D, {{100, 0, 20}}}); + registry.add("hnTPCCrossedRow", "Number of crossed TPC Rows", {HistType::kTH1D, {{100, 40, 180}}}); + registry.add("hDCAz", "DCAz after cuts; DCAz (cm); Pt", {HistType::kTH2D, {{200, -0.5, 0.5}, {200, 0, 5}}}); + registry.add("hDCAxy", "DCAxy after cuts; DCAxy (cm); Pt", {HistType::kTH2D, {{200, -0.5, 0.5}, {200, 0, 5}}}); + registry.add("hTrackCorrection2d", "Correlation table for number of tracks table; uncorrected track; corrected track", {HistType::kTH2D, {axisNch, axisNch}}); + + o2::framework::AxisSpec axis = axisPt; + int nPtBins = axis.binEdges.size() - 1; + double* ptBins = &(axis.binEdges)[0]; + fPtAxis = new TAxis(nPtBins, ptBins); + + if (cfgOutputNUAWeights) { + fWeights->setPtBins(nPtBins, ptBins); + fWeights->init(true, false); + } + + // add in FlowContainer to Get boostrap sample automatically + TObjArray* oba = new TObjArray(); + oba->Add(new TNamed("ChGap22", "ChGap22")); + oba->Add(new TNamed("ChFull22", "ChFull22")); + oba->Add(new TNamed("ChFull32", "ChFull32")); + oba->Add(new TNamed("ChFull42", "ChFull42")); + oba->Add(new TNamed("ChFull24", "ChFull24")); + oba->Add(new TNamed("ChFull26", "ChFull26")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("ChFull22_pt_%i", i + 1), "ChFull22_pTDiff")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("ChFull24_pt_%i", i + 1), "ChFull24_pTDiff")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("ChFull26_pt_%i", i + 1), "ChFull26_pTDiff")); + oba->Add(new TNamed("Ch04Gap22", "Ch04Gap22")); + oba->Add(new TNamed("Ch06Gap22", "Ch06Gap22")); + oba->Add(new TNamed("Ch08Gap22", "Ch08Gap22")); + oba->Add(new TNamed("Ch10Gap22", "Ch10Gap22")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ch10Gap22_pt_%i", i + 1), "Ch10Gap22_pTDiff")); + oba->Add(new TNamed("Ch12Gap22", "Ch12Gap22")); + oba->Add(new TNamed("Ch04Gap32", "Ch04Gap32")); + oba->Add(new TNamed("Ch06Gap32", "Ch06Gap32")); + oba->Add(new TNamed("Ch08Gap32", "Ch08Gap32")); + oba->Add(new TNamed("Ch10Gap32", "Ch10Gap32")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ch10Gap32_pt_%i", i + 1), "Ch10Gap32_pTDiff")); + oba->Add(new TNamed("Ch12Gap32", "Ch12Gap32")); + oba->Add(new TNamed("Ch04Gap42", "Ch04Gap42")); + oba->Add(new TNamed("Ch06Gap42", "Ch06Gap42")); + oba->Add(new TNamed("Ch08Gap42", "Ch08Gap42")); + oba->Add(new TNamed("Ch10Gap42", "Ch10Gap42")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ch10Gap42_pt_%i", i + 1), "Ch10Gap42_pTDiff")); + oba->Add(new TNamed("Ch12Gap42", "Ch12Gap42")); + oba->Add(new TNamed("ChFull422", "ChFull422")); + oba->Add(new TNamed("Ch04GapA422", "Ch04GapA422")); + oba->Add(new TNamed("Ch04GapB422", "Ch04GapB422")); + oba->Add(new TNamed("Ch10GapA422", "Ch10GapA422")); + oba->Add(new TNamed("Ch10GapB422", "Ch10GapB422")); + oba->Add(new TNamed("ChFull3232", "ChFull3232")); + oba->Add(new TNamed("ChFull4242", "ChFull4242")); + oba->Add(new TNamed("Ch04Gap3232", "Ch04Gap3232")); + oba->Add(new TNamed("Ch04Gap4242", "Ch04Gap4242")); + oba->Add(new TNamed("Ch04Gap24", "Ch04Gap24")); + oba->Add(new TNamed("Ch10Gap3232", "Ch10Gap3232")); + oba->Add(new TNamed("Ch10Gap4242", "Ch10Gap4242")); + oba->Add(new TNamed("Ch10Gap24", "Ch10Gap24")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ch10Gap24_pt_%i", i + 1), "Ch10Gap24_pTDiff")); + std::vector userDefineGFWCorr = cfgUserDefineGFWCorr; + std::vector userDefineGFWName = cfgUserDefineGFWName; + if (!userDefineGFWCorr.empty() && !userDefineGFWName.empty()) { + for (uint i = 0; i < userDefineGFWName.size(); i++) { + oba->Add(new TNamed(userDefineGFWName.at(i).c_str(), userDefineGFWName.at(i).c_str())); + } + } + fFC->SetName("FlowContainer"); + fFC->SetXAxis(fPtAxis); + fFC->Initialize(oba, axisIndependent, cfgNbootstrap); + delete oba; + + // eta region + fGFW->AddRegion("full", -0.8, 0.8, 1, 1); + fGFW->AddRegion("refN00", -0.8, 0., 1, 1); // gap0 negative region + fGFW->AddRegion("refP00", 0., 0.8, 1, 1); // gap0 positve region + fGFW->AddRegion("refN02", -0.8, -0.1, 1, 1); // gap2 negative region + fGFW->AddRegion("refP02", 0.1, 0.8, 1, 1); // gap2 positve region + fGFW->AddRegion("refN04", -0.8, -0.2, 1, 1); // gap4 negative region + fGFW->AddRegion("refP04", 0.2, 0.8, 1, 1); // gap4 positve region + fGFW->AddRegion("refN06", -0.8, -0.3, 1, 1); // gap6 negative region + fGFW->AddRegion("refP06", 0.3, 0.8, 1, 1); // gap6 positve region + fGFW->AddRegion("refN08", -0.8, -0.4, 1, 1); + fGFW->AddRegion("refP08", 0.4, 0.8, 1, 1); + fGFW->AddRegion("refN10", -0.8, -0.5, 1, 1); + fGFW->AddRegion("refP10", 0.5, 0.8, 1, 1); + fGFW->AddRegion("refN12", -0.8, -0.6, 1, 1); + fGFW->AddRegion("refP12", 0.6, 0.8, 1, 1); + fGFW->AddRegion("refN14", -0.8, -0.7, 1, 1); + fGFW->AddRegion("refP14", 0.7, 0.8, 1, 1); + fGFW->AddRegion("refN", -0.8, -0.4, 1, 1); + fGFW->AddRegion("refP", 0.4, 0.8, 1, 1); + fGFW->AddRegion("refM", -0.4, 0.4, 1, 1); + fGFW->AddRegion("poiN", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poifull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("olN", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olfull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 4); + + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {3 -3}", "ChFull32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {4 -4}", "ChFull42", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 2 -2 -2}", "ChFull24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 2 2 -2 -2 -2}", "ChFull26", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {2} refP04 {-2}", "Ch04Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN06 {2} refP06 {-2}", "Ch06Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {2} refP08 {-2}", "Ch08Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {2} refP10 {-2}", "Ch10Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN12 {2} refP12 {-2}", "Ch12Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {3} refP04 {-3}", "Ch04Gap32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN06 {3} refP06 {-3}", "Ch06Gap32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {3} refP08 {-3}", "Ch08Gap32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {3} refP10 {-3}", "Ch10Gap32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN12 {3} refP12 {-3}", "Ch12Gap32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {4} refP04 {-4}", "Ch04Gap42", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN06 {4} refP06 {-4}", "Ch06Gap42", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {4} refP08 {-4}", "Ch08Gap42", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {4} refP10 {-4}", "Ch10Gap42", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN12 {4} refP12 {-4}", "Ch12Gap42", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN {2} refP {-2}", "ChGap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poifull full | olfull {2 -2}", "ChFull22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poifull full | olfull {2 2 -2 -2}", "ChFull24", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poifull full | olfull {2 2 2 -2 -2 -2}", "ChFull26", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiN10 refN10 | olN10 {2} refP10 {-2}", "Ch10Gap22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiN10 refN10 | olN10 {3} refP10 {-3}", "Ch10Gap32", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiN10 refN10 | olN10 {4} refP10 {-4}", "Ch10Gap42", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {4 -2 -2}", "ChFull422", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {-2 -2} refP04 {4}", "Ch04GapA422", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {4} refP04 {-2 -2}", "Ch04GapB422", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {-2 -2} refP10 {4}", "Ch10GapA422", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {4} refP10 {-2 -2}", "Ch10GapB422", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {3 2 -3 -2}", "ChFull3232", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {4 2 -4 -2}", "ChFull4242", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {3 2} refP04 {-3 -2}", "Ch04Gap3232", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {4 2} refP04 {-4 -2}", "Ch04Gap4242", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {2 2} refP04 {-2 -2}", "Ch04Gap24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {3 2} refP10 {-3 -2}", "Ch10Gap3232", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {4 2} refP10 {-4 -2}", "Ch10Gap4242", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {2 2} refP10 {-2 -2}", "Ch10Gap24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiN10 refN10 | olN10 {2 2} refP10 {-2 -2}", "Ch10Gap24", kTRUE)); + if (!userDefineGFWCorr.empty() && !userDefineGFWName.empty()) { + LOGF(info, "User adding GFW CorrelatorConfig:"); + // attentaion: here we follow the index of cfgUserDefineGFWCorr + for (uint i = 0; i < userDefineGFWCorr.size(); i++) { + if (i >= userDefineGFWName.size()) { + LOGF(fatal, "The names you provided are more than configurations. userDefineGFWName.size(): %d > userDefineGFWCorr.size(): %d", userDefineGFWName.size(), userDefineGFWCorr.size()); + break; + } + LOGF(info, "%d: %s %s", i, userDefineGFWCorr.at(i).c_str(), userDefineGFWName.at(i).c_str()); + corrconfigs.push_back(fGFW->GetCorrelatorConfig(userDefineGFWCorr.at(i).c_str(), userDefineGFWName.at(i).c_str(), kFALSE)); + } + } + fGFW->CreateRegions(); + + if (cfgUseAdditionalEventCut) { + fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x - 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); + fMultPVCutLow->SetParameters(3257.29, -121.848, 1.98492, -0.0172128, 6.47528e-05, 154.756, -1.86072, -0.0274713, 0.000633499, -3.37757e-06); + fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x + 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); + fMultPVCutHigh->SetParameters(3257.29, -121.848, 1.98492, -0.0172128, 6.47528e-05, 154.756, -1.86072, -0.0274713, 0.000633499, -3.37757e-06); + + fMultCutLow = new TF1("fMultCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultCutLow->SetParameters(1654.46, -47.2379, 0.449833, -0.0014125, 150.773, -3.67334, 0.0530503, -0.000614061, 3.15956e-06); + fMultCutHigh = new TF1("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 3.*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultCutHigh->SetParameters(1654.46, -47.2379, 0.449833, -0.0014125, 150.773, -3.67334, 0.0530503, -0.000614061, 3.15956e-06); + + fT0AV0AMean = new TF1("fT0AV0AMean", "[0]+[1]*x", 0, 200000); + fT0AV0AMean->SetParameters(-1601.0581, 9.417652e-01); + fT0AV0ASigma = new TF1("fT0AV0ASigma", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 200000); + fT0AV0ASigma->SetParameters(463.4144, 6.796509e-02, -9.097136e-07, 7.971088e-12, -2.600581e-17); + } + + if (cfgTrackDensityCorrUse) { + std::vector pTEffBins = {0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.4, 1.8, 2.2, 2.6, 3.0}; + hFindPtBin = new TH1D("hFindPtBin", "hFindPtBin", pTEffBins.size() - 1, &pTEffBins[0]); + funcEff.resize(pTEffBins.size() - 1); + // LHC24g3 Eff + std::vector f1p0 = cfgTrackDensityP0; + std::vector f1p1 = cfgTrackDensityP1; + for (uint ifunc = 0; ifunc < pTEffBins.size() - 1; ifunc++) { + funcEff[ifunc] = new TF1(Form("funcEff%i", ifunc), "[0]+[1]*x", 0, 3000); + funcEff[ifunc]->SetParameters(f1p0[ifunc], f1p1[ifunc]); + } + funcV2 = new TF1("funcV2", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV2->SetParameters(0.0186111, 0.00351907, -4.38264e-05, 1.35383e-07, -3.96266e-10); + funcV3 = new TF1("funcV3", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV3->SetParameters(0.0174056, 0.000703329, -1.45044e-05, 1.91991e-07, -1.62137e-09); + funcV4 = new TF1("funcV4", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV4->SetParameters(0.008845, 0.000259668, -3.24435e-06, 4.54837e-08, -6.01825e-10); + } + + myTrackSel = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::Default); + myTrackSel.SetMinNClustersTPC(cfgCutTPCclu); + myTrackSel.SetMinNClustersITS(cfgCutITSclu); + if (cfgCutDCAxyppPass3Enabled) + myTrackSel.SetMaxDcaXYPtDep([](float pt) { return 0.004f + 0.013f / pt; }); // Tuned on the LHC22f anchored MC LHC23d1d on primary pions. 7 Sigmas of the resolution + } + + template + void fillProfile(const GFW::CorrConfig& corrconf, const ConstStr& tarName, const double& cent) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) + return; + if (!corrconf.pTDif) { + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + registry.fill(tarName, cent, val, dnx); + return; + } + return; + } + + void fillFC(const GFW::CorrConfig& corrconf, const double& cent, const double& rndm) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (!corrconf.pTDif) { + if (dnx == 0) + return; + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + fFC->FillProfile(corrconf.Head.c_str(), cent, val, dnx, rndm); + return; + } + for (auto i = 1; i <= fPtAxis->GetNbins(); i++) { + dnx = fGFW->Calculate(corrconf, i - 1, kTRUE).real(); + if (dnx == 0) + continue; + val = fGFW->Calculate(corrconf, i - 1, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + fFC->FillProfile(Form("%s_pt_%i", corrconf.Head.c_str(), i), cent, val, dnx, rndm); + } + return; + } + + void loadCorrections(uint64_t timestamp, int runNumber) + { + if (correctionsLoaded) + return; + if (!cfgAcceptanceListEnabled && cfgAcceptance.value.empty() == false) { + mAcceptance = ccdb->getForTimeStamp(cfgAcceptance, timestamp); + if (mAcceptance) + LOGF(info, "Loaded acceptance weights from %s (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance); + else + LOGF(warning, "Could not load acceptance weights from %s (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance); + } + if (cfgAcceptanceListEnabled && cfgAcceptanceList.value.empty() == false) { + mAcceptanceList = ccdb->getForTimeStamp(cfgAcceptanceList, timestamp); + if (mAcceptanceList == nullptr) { + LOGF(fatal, "Could not load acceptance weights list from %s", cfgAcceptanceList.value.c_str()); + } + LOGF(info, "Loaded acceptance weights list from %s (%p)", cfgAcceptanceList.value.c_str(), (void*)mAcceptanceList); + + mAcceptance = static_cast(mAcceptanceList->FindObject(Form("%d", runNumber))); + if (mAcceptance == nullptr) { + LOGF(fatal, "Could not find acceptance weights for run %d in acceptance list", runNumber); + } + LOGF(info, "Loaded acceptance weights (%p) for run %d from list (%p)", (void*)mAcceptance, runNumber, (void*)mAcceptanceList); + } + if (cfgEfficiency.value.empty() == false) { + mEfficiency = ccdb->getForTimeStamp(cfgEfficiency, timestamp); + if (mEfficiency == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgEfficiency.value.c_str()); + } + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgEfficiency.value.c_str(), (void*)mEfficiency); + } + correctionsLoaded = true; + } + + bool setCurrentParticleWeights(float& weight_nue, float& weight_nua, float phi, float eta, float pt, float vtxz) + { + float eff = 1.; + if (mEfficiency) + eff = mEfficiency->GetBinContent(mEfficiency->FindBin(pt)); + else + eff = 1.0; + if (eff == 0) + return false; + weight_nue = 1. / eff; + + if (mAcceptance) + weight_nua = mAcceptance->getNUA(phi, eta, vtxz); + else + weight_nua = 1; + return true; + } + + template + bool eventSelected(TCollision collision, const int multTrk, const float centrality) + { + registry.fill(HIST("hEventCountSpecific"), 0.5); + if (cfgEvSelkNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + // rejects collisions which are associated with the same "found-by-T0" bunch crossing + // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof + return 0; + } + if (cfgEvSelkNoSameBunchPileup) + registry.fill(HIST("hEventCountSpecific"), 1.5); + if (cfgEvSelkIsGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference + // use this cut at low multiplicities with caution + return 0; + } + if (cfgEvSelkIsGoodZvtxFT0vsPV) + registry.fill(HIST("hEventCountSpecific"), 2.5); + if (cfgEvSelkNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // no collisions in specified time range + return 0; + } + if (cfgEvSelkNoCollInTimeRangeStandard) + registry.fill(HIST("hEventCountSpecific"), 3.5); + if (cfgEvSelkIsGoodITSLayersAll && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + // from Jan 9 2025 AOT meeting + // cut time intervals with dead ITS staves + return 0; + } + if (cfgEvSelkIsGoodITSLayersAll) + registry.fill(HIST("hEventCountSpecific"), 4.5); + if (cfgEvSelkNoCollInRofStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + // no other collisions in this Readout Frame with per-collision multiplicity above threshold + return 0; + } + if (cfgEvSelkNoCollInRofStandard) + registry.fill(HIST("hEventCountSpecific"), 5.5); + if (cfgEvSelkNoHighMultCollInPrevRof && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + // veto an event if FT0C amplitude in previous ITS ROF is above threshold + return 0; + } + if (cfgEvSelkNoHighMultCollInPrevRof) + registry.fill(HIST("hEventCountSpecific"), 6.5); + auto multNTracksPV = collision.multNTracksPV(); + auto occupancy = collision.trackOccupancyInTimeRange(); + if (cfgEvSelOccupancy && (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh)) + return 0; + if (cfgEvSelOccupancy) + registry.fill(HIST("hEventCountSpecific"), 7.5); + + if (cfgEvSelMultCorrelation) { + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) + return 0; + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) + return 0; + if (multTrk < fMultCutLow->Eval(centrality)) + return 0; + if (multTrk > fMultCutHigh->Eval(centrality)) + return 0; + } + if (cfgEvSelMultCorrelation) + registry.fill(HIST("hEventCountSpecific"), 8.5); + + // V0A T0A 5 sigma cut + if (cfgEvSelV0AT0ACut && (std::fabs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > 5 * fT0AV0ASigma->Eval(collision.multFT0A()))) + return 0; + if (cfgEvSelV0AT0ACut) + registry.fill(HIST("hEventCountSpecific"), 9.5); + + return 1; + } + + template + void eventCounterQA(TCollision collision, const int multTrk, const float centrality) + { + registry.fill(HIST("hEventCountTentative"), 0.5); + // Regradless of the event selection, fill the event counter histograms + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + registry.fill(HIST("hEventCountTentative"), 1.5); + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + registry.fill(HIST("hEventCountTentative"), 2.5); + if (collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) + registry.fill(HIST("hEventCountTentative"), 3.5); + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) + registry.fill(HIST("hEventCountTentative"), 4.5); + if (collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) + registry.fill(HIST("hEventCountTentative"), 5.5); + if (collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) + registry.fill(HIST("hEventCountTentative"), 6.5); + auto multNTracksPV = collision.multNTracksPV(); + auto occupancy = collision.trackOccupancyInTimeRange(); + if (!(occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh)) + registry.fill(HIST("hEventCountTentative"), 7.5); + if (!((multNTracksPV < fMultPVCutLow->Eval(centrality)) || (multNTracksPV > fMultPVCutHigh->Eval(centrality)) || (multTrk < fMultCutLow->Eval(centrality)) || (multTrk > fMultCutHigh->Eval(centrality)))) + registry.fill(HIST("hEventCountTentative"), 8.5); + if (!(std::fabs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > 5 * fT0AV0ASigma->Eval(collision.multFT0A()))) + registry.fill(HIST("hEventCountTentative"), 9.5); + } + + template + bool trackSelected(TTrack track) + { + if (cfgCutDCAzPtDepEnabled && (std::fabs(track.dcaZ()) > (0.004f + 0.013f / track.pt()))) + return false; + + if (cfgTrkSelSwitch) { + return myTrackSel.IsSelected(track); + } else { + return ((track.tpcNClsFound() >= cfgCutTPCclu) && (track.itsNCls() >= cfgCutITSclu)); + } + } + + void initHadronicRate(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + if (gHadronicRate.find(mRunNumber) == gHadronicRate.end()) { + auto runDuration = ccdb->getRunDuration(mRunNumber); + mSOR = runDuration.first; + mMinSeconds = std::floor(mSOR * 1.e-3); /// round tsSOR to the highest integer lower than tsSOR + double maxSec = std::ceil(runDuration.second * 1.e-3); /// round tsEOR to the lowest integer higher than tsEOR + const AxisSpec axisSeconds{static_cast((maxSec - mMinSeconds) / 20.f), 0, maxSec - mMinSeconds, "Seconds since SOR"}; + gHadronicRate[mRunNumber] = registry.add(Form("HadronicRate/%i", mRunNumber), ";Time since SOR (s);Hadronic rate (kHz)", kTH2D, {axisSeconds, {510, 0., 51.}}).get(); + } + gCurrentHadronicRate = gHadronicRate[mRunNumber]; + } + + void process(AodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, AodTracks const& tracks) + { + registry.fill(HIST("hEventCount"), 0.5); + if (!cfgUseSmallMemory && tracks.size() >= 1) { + registry.fill(HIST("BeforeSel8_globalTracks_centT0C"), collision.centFT0C(), tracks.size()); + } + if (!collision.sel8()) + return; + if (tracks.size() < 1) + return; + registry.fill(HIST("hEventCount"), 1.5); + auto bc = collision.bc_as(); + int currentRunNumber = bc.runNumber(); + for (const auto& ExcludedRun : cfgRunRemoveList.value) { + if (currentRunNumber == ExcludedRun) { + return; + } + } + registry.fill(HIST("hEventCount"), 2.5); + if (!cfgUseSmallMemory) { + registry.fill(HIST("BeforeCut_globalTracks_centT0C"), collision.centFT0C(), tracks.size()); + registry.fill(HIST("BeforeCut_PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV()); + registry.fill(HIST("BeforeCut_globalTracks_PVTracks"), collision.multNTracksPV(), tracks.size()); + registry.fill(HIST("BeforeCut_globalTracks_multT0A"), collision.multFT0A(), tracks.size()); + registry.fill(HIST("BeforeCut_globalTracks_multV0A"), collision.multFV0A(), tracks.size()); + registry.fill(HIST("BeforeCut_multV0A_multT0A"), collision.multFT0A(), collision.multFV0A()); + registry.fill(HIST("BeforeCut_multT0C_centT0C"), collision.centFT0C(), collision.multFT0C()); + } + float cent; + switch (cfgCentEstimator) { + case kCentFT0C: + cent = collision.centFT0C(); + break; + case kCentFT0CVariant1: + cent = collision.centFT0CVariant1(); + break; + case kCentFT0M: + cent = collision.centFT0M(); + break; + case kCentFV0A: + cent = collision.centFV0A(); + break; + default: + cent = collision.centFT0C(); + } + if (cfgUseTentativeEventCounter) + eventCounterQA(collision, tracks.size(), cent); + if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), cent)) + return; + registry.fill(HIST("hEventCount"), 3.5); + float lRandom = fRndm->Rndm(); + float vtxz = collision.posZ(); + registry.fill(HIST("hVtxZ"), vtxz); + registry.fill(HIST("hMult"), tracks.size()); + registry.fill(HIST("hCent"), cent); + fGFW->Clear(); + if (cfgGetInteractionRate) { + initHadronicRate(bc); + double hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), mRunNumber, "ZNC hadronic") * 1.e-3; // + double seconds = bc.timestamp() * 1.e-3 - mMinSeconds; + if (cfgUseInteractionRateCut && (hadronicRate < cfgCutMinIR || hadronicRate > cfgCutMaxIR)) // cut on hadronic rate + return; + gCurrentHadronicRate->Fill(seconds, hadronicRate); + } + loadCorrections(bc.timestamp(), currentRunNumber); + registry.fill(HIST("hEventCount"), 4.5); + + // fill event QA + if (!cfgUseSmallMemory) { + registry.fill(HIST("globalTracks_centT0C"), collision.centFT0C(), tracks.size()); + registry.fill(HIST("PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV()); + registry.fill(HIST("globalTracks_PVTracks"), collision.multNTracksPV(), tracks.size()); + registry.fill(HIST("globalTracks_multT0A"), collision.multFT0A(), tracks.size()); + registry.fill(HIST("globalTracks_multV0A"), collision.multFV0A(), tracks.size()); + registry.fill(HIST("multV0A_multT0A"), collision.multFT0A(), collision.multFV0A()); + registry.fill(HIST("multT0C_centT0C"), collision.centFT0C(), collision.multFT0C()); + registry.fill(HIST("centFT0CVar_centFT0C"), collision.centFT0C(), collision.centFT0CVariant1()); + registry.fill(HIST("centFT0M_centFT0C"), collision.centFT0C(), collision.centFT0M()); + registry.fill(HIST("centFV0A_centFT0C"), collision.centFT0C(), collision.centFV0A()); + } + + // track weights + float weff = 1, wacc = 1; + double nTracksCorrected = 0; + float independent = cent; + if (cfgUseNch) + independent = static_cast(tracks.size()); + + double psi2Est = 0, psi3Est = 0, psi4Est = 0; + float wEPeff = 1; + double v2 = 0, v3 = 0, v4 = 0; + // be cautious, this only works for Pb-Pb + // esimate the Event plane and vn for this event + if (cfgTrackDensityCorrUse) { + double q2x = 0, q2y = 0; + double q3x = 0, q3y = 0; + double q4x = 0, q4y = 0; + for (const auto& track : tracks) { + bool withinPtRef = (cfgCutPtRefMin < track.pt()) && (track.pt() < cfgCutPtRefMax); // within RF pT rang + if (withinPtRef) { + q2x += std::cos(2 * track.phi()); + q2y += std::sin(2 * track.phi()); + q3x += std::cos(3 * track.phi()); + q3y += std::sin(3 * track.phi()); + q4x += std::cos(4 * track.phi()); + q4y += std::sin(4 * track.phi()); + } + } + psi2Est = std::atan2(q2y, q2x) / 2.; + psi3Est = std::atan2(q3y, q3x) / 3.; + psi4Est = std::atan2(q4y, q4x) / 4.; + v2 = funcV2->Eval(cent); + v3 = funcV3->Eval(cent); + v4 = funcV4->Eval(cent); + } + + for (const auto& track : tracks) { + if (!trackSelected(track)) + continue; + bool withinPtPOI = (cfgCutPtPOIMin < track.pt()) && (track.pt() < cfgCutPtPOIMax); // within POI pT range + bool withinPtRef = (cfgCutPtRefMin < track.pt()) && (track.pt() < cfgCutPtRefMax); // within RF pT range + if (cfgOutputNUAWeights) { + if (cfgOutputNUAWeightsRefPt) { + if (withinPtRef) + fWeights->fill(track.phi(), track.eta(), vtxz, track.pt(), cent, 0); + } else { + fWeights->fill(track.phi(), track.eta(), vtxz, track.pt(), cent, 0); + } + } + if (!setCurrentParticleWeights(weff, wacc, track.phi(), track.eta(), track.pt(), vtxz)) + continue; + if (cfgTrackDensityCorrUse && withinPtRef) { + double fphi = v2 * std::cos(2 * (track.phi() - psi2Est)) + v3 * std::cos(3 * (track.phi() - psi3Est)) + v4 * std::cos(4 * (track.phi() - psi4Est)); + fphi = (1 + 2 * fphi); + int pTBinForEff = hFindPtBin->FindBin(track.pt()); + if (pTBinForEff >= 1 && pTBinForEff <= hFindPtBin->GetNbinsX()) { + wEPeff = funcEff[pTBinForEff - 1]->Eval(fphi * tracks.size()); + if (wEPeff > 0.) { + wEPeff = 1. / wEPeff; + weff *= wEPeff; + } + } + } + registry.fill(HIST("hPt"), track.pt()); + if (withinPtRef) { + registry.fill(HIST("hPhi"), track.phi()); + registry.fill(HIST("hPhiWeighted"), track.phi(), wacc); + registry.fill(HIST("hEta"), track.eta()); + registry.fill(HIST("hPtRef"), track.pt()); + registry.fill(HIST("hChi2prTPCcls"), track.tpcChi2NCl()); + registry.fill(HIST("hChi2prITScls"), track.itsChi2NCl()); + registry.fill(HIST("hnTPCClu"), track.tpcNClsFound()); + registry.fill(HIST("hnITSClu"), track.itsNCls()); + registry.fill(HIST("hnTPCCrossedRow"), track.tpcNClsCrossedRows()); + registry.fill(HIST("hDCAz"), track.dcaZ(), track.pt()); + registry.fill(HIST("hDCAxy"), track.dcaXY(), track.pt()); + nTracksCorrected += weff; + } + if (withinPtRef) + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), wacc * weff, 1); + if (withinPtPOI) + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), wacc * weff, 2); + if (withinPtPOI && withinPtRef) + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), wacc * weff, 4); + } + registry.fill(HIST("hTrackCorrection2d"), tracks.size(), nTracksCorrected); + + // Filling Flow Container + for (uint l_ind = 0; l_ind < corrconfigs.size(); l_ind++) { + fillFC(corrconfigs.at(l_ind), independent, lRandom); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Flow/Tasks/flowZdcTask.cxx b/PWGCF/Flow/Tasks/flowZdcTask.cxx new file mode 100644 index 00000000000..7c368aa1818 --- /dev/null +++ b/PWGCF/Flow/Tasks/flowZdcTask.cxx @@ -0,0 +1,553 @@ +// 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 flowZdcTask.cxx +/// \author Sabrina Hernandez +/// \since 10/01/2024 +/// \brief task to evaluate flow and neutron skin with information from ZDC + +#include +#include +#include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" + +#include "TList.h" +#include +#include +#include +#include +#include +#include +#include +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::mult; +using namespace o2::aod::evsel; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct FlowZdcTask { + SliceCache cache; + + O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMin, float, 0.2f, "Minimal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMax, float, 10.0f, "Maximal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 10.0f, "Maximal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5, "Chi2 per TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgUseNch, bool, false, "Use Nch for flow observables") + O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 10, "Number of subsamples") + O2_DEFINE_CONFIGURABLE(cfgCutDCAz, float, 2, "DCA Z cut") + O2_DEFINE_CONFIGURABLE(cfgCutDCAxy, float, 0.2f, "DCA XY cut") + + Configurable nBinsPt{"nBinsPt", 500, "N bins in pT histo"}; + Configurable eventSelection{"eventSelection", 1, "event selection"}; + Configurable maxZp{"maxZp", 3099.5, "Max ZP signal"}; + Configurable minTpcNcrossedRows{"minTpcNcrossedRows", 20, "minTpcNcrossedRows"}; + Configurable maxZem{"maxZem", 3099.5, "Max ZEM signal"}; + // for ZDC info and analysis + Configurable nBinsAmp{"nBinsAmp", 1025, "nbinsAmp"}; + Configurable nBinsFT0Amp{"nBinsFT0Amp", 250000, "nbinsAmp"}; + Configurable maxZn{"maxZn", 4099.5, "Max ZN signal"}; + Configurable acceptanceZna{"acceptanceZna", 0.92, "ZNA acceptance factor"}; + Configurable acceptanceZnc{"acceptanceZnc", 0.90, "ZNC acceptance factor"}; + Configurable acceptanceZpa{"acceptanceZpa", 0.52, "ZPA acceptance factor"}; + Configurable acceptanceZpc{"acceptanceZpc", 0.50, "ZPC acceptance factor"}; + Configurable vtxRange{"vtxRange", 10.0f, "Vertex Z range to consider"}; + Configurable etaRange{"etaRange", 1.0f, "Eta range to consider"}; + Configurable maxNch{"maxNch", 2500, "Max Nch (|eta|<0.8)"}; + Configurable npvTracksCut{"npvTracksCut", 1.0f, "Apply extra NPVtracks cut"}; + Configurable nBinsTDC{"nBinsTDC", 150, "nbinsTDC"}; + Configurable minTdc{"minTdc", -15.0, "minimum TDC"}; + Configurable maxTdc{"maxTdc", 15.0, "maximum TDC"}; + Configurable nBinsNch{"nBinsNch", 2501, "N bins Nch (|eta|<0.8)"}; + // event selection + Configurable isApplySameBunchPileup{"isApplySameBunchPileup", true, "Enable SameBunchPileup cut"}; + Configurable isApplyGoodZvtxFT0vsPV{"isApplyGoodZvtxFT0vsPV", true, "Enable GoodZvtxFT0vsPV cut"}; + Configurable isApplyVertexITSTPC{"isApplyVertexITSTPC", false, "Enable VertexITSTPC cut"}; + Configurable isApplyVertexTOFmatched{"isApplyVertexTOFmatched", false, "Enable VertexTOFmatched cut"}; + Configurable isApplyVertexTRDmatched{"isApplyVertexTRDmatched", false, "Enable VertexTRDmatched cut"}; + Configurable isApplyExtraCorrCut{"isApplyExtraCorrCut", false, "Enable extra NPVtracks vs FTOC correlation cut"}; + Configurable isApplyFT0CbasedOccupancy{"isApplyFT0CbasedOccupancy", false, "Enable FT0CbasedOccupancy cut"}; + Configurable isGoodITSLayersAll{"isGoodITSLayersAll", false, "Centrality based on no other collisions in this Readout Frame with per-collision multiplicity above threshold tracks"}; + Configurable isOccupancyCut{"isOccupancyCut", true, "Occupancy cut?"}; + Configurable isZEMcut{"isZEMcut", true, "Use ZEM cut?"}; + Configurable ft0cCut{"ft0cCut", 1.0f, "Apply extra FT0C cut"}; + Configurable minOccCut{"minOccCut", 0, "min Occu cut"}; + Configurable maxOccCut{"maxOccCut", 500, "max Occu cut"}; + Configurable posZcut{"posZcut", +10.0, "z-vertex position cut"}; + Configurable zemCut{"zemCut", 1000., "ZEM cut"}; + + ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for histograms"}; + ConfigurableAxis axisPhi{"axisPhi", {60, 0.0, constants::math::TwoPI}, "phi axis for histograms"}; + ConfigurableAxis axisEta{"axisEta", {40, -1., 1.}, "eta axis for histograms"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.2, 0.25, 0.30, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.20, 2.40, 2.60, 2.80, 3.00}, "pt axis for histograms"}; + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {3500, 0, 3500}, "centrality axis for histograms"}; + ConfigurableAxis axisEnergy{"axisEnergy", {100, 0, 700}, "energy axis for zdc histos"}; + ConfigurableAxis axisMultTpc{"axisMultTpc", {2000, -0.5f, 2999.5f}, "TPCmultiplicity"}; + ConfigurableAxis axisZN{"axisZN", {5000, 0, 500}, "axisZN"}; + ConfigurableAxis axisZP{"axisZP", {5000, 0, 500}, "axisZP"}; + ConfigurableAxis axisFT0CAmp{"axisFT0CAmp", {5000, 0, 5000}, "axisFT0CAmp"}; + ConfigurableAxis axisFT0AAmp{"axisFT0AAmp", {5000, 0, 5000}, "axisFT0AAmp"}; + ConfigurableAxis axisFT0MAmp{"axisFT0MAmp", {10000, 0, 10000}, "axisFT0MAmp"}; + ConfigurableAxis ft0cMultHistBin{"ft0cMultHistBin", {501, -0.5, 500.5}, ""}; + ConfigurableAxis multHistBin{"multHistBin", {501, -0.5, 500.5}, ""}; + ConfigurableAxis axisCent{"axisCent", {10, 0, 100}, "axisCent"}; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtMin) && (aod::track::pt < cfgCutPtMax) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (aod::track::tpcChi2NCl < cfgCutChi2prTPCcls) && (nabs(aod::track::dcaZ) < cfgCutDCAz) && (nabs(aod::track::dcaXY) < cfgCutDCAxy); + using ColEvSels = soa::Join; + using AodCollisions = soa::Filtered>; + using AodTracks = soa::Filtered>; + Partition tracksIUWithTPC = (aod::track::tpcNClsFindable > (uint8_t)0); + using BCsRun3 = soa::Join; + using AodZDCs = soa::Join; + using CollisionDataTable = soa::Join; + using TrackDataTable = soa::Join; + using FilTrackDataTable = soa::Filtered; + std::complex qTPC; // init q TPC + std::complex qZNA{0, 0}; // init qZNA + std::complex qZNC{0, 0}; // init qZNC + + // Begin Histogram Registry + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + OutputObj pCosPsiDifferences{TProfile("pCosPsiDifferences", "Differences in cos(psi) vs Centrality;Centrality;Mean cos(psi) Difference", 200, 0, 100, -1, 1)}; + OutputObj pSinPsiDifferences{TProfile("pSinPsiDifferences", "Differences in sin(psi) vs Centrality;Centrality;Mean sin(psi) Difference", 200, 0, 100, -1, 1)}; + OutputObj pZNvsFT0Ccent{TProfile("pZNvsFT0Ccent", "ZN Energy vs FT0C Centrality", 100, 0, 100, 0, 500)}; + OutputObj pZPvsFT0Ccent{TProfile("pZPvsFT0Ccent", "ZP Energy vs FT0C Centrality", 100, 0, 100, 0, 500)}; + OutputObj pZNratiovscent{TProfile("pZNratiovscent", "Ratio ZNC/ZNA vs FT0C Centrality", 100, 0, 100, 0, 5)}; + OutputObj pZPratiovscent{TProfile("pZPratiovscent", "Ratio ZPC/ZPA vs FT0C Centrality", 100, 0, 100, 0, 5)}; + + double sumCosPsiDiff = 0.0; // Sum of cos(psiZNC) - cos(psiZNA) + int countEvents = 0; // Count of processed events + + void init(InitContext const&) + { + // define axes + const AxisSpec axisCounter{1, 0, +1, ""}; + const AxisSpec axisQ{100, -1, 1, "Q"}; + const AxisSpec axisQZNA{100, -1, 1, "Q"}; + const AxisSpec axisREQ{100, -1, 1, "real Q"}; + const AxisSpec axisIMQ{100, -1, 1, "imag Q"}; + + AxisSpec axisVtxZ{40, -20, 20, "Vertex Z", "VzAxis"}; + AxisSpec axisEvent{12, 0.5, 12.5, "#Event", "EventAxis"}; + AxisSpec axisMult = {multHistBin, "Mult", "MultAxis"}; + AxisSpec axisFT0CMult = {ft0cMultHistBin, "ft0c", "FT0CMultAxis"}; + + // create histograms + histos.add("etaHistogram", "etaHistogram", kTH1F, {axisEta}); + histos.add("ptHistogram", "ptHistogram", kTH1F, {axisPt}); + + histos.add("eventCounter", "eventCounter", kTH1F, {axisCounter}); + histos.add("centHistogram", "centHistogram", kTH1F, {axisCent}); + histos.add("multHistogram", "multHistogram", kTH1F, {axisMultiplicity}); + histos.add("multvsCent", "centrality vs multiplicity", kTH2F, {axisCent, axisMultiplicity}); + histos.add("phiHistogram", "phiHistogram", kTH1F, {axisPhi}); + histos.add("TPCmultiplicity", "TPCmultiplicity", kTH1F, {axisMultTpc}); + + histos.add("REqHistogram", "REqHistogram", kTH1F, {axisQ}); + histos.add("IMqHistogram", "IMqHistogram", kTH1F, {axisQ}); + + histos.add("REqHistogramZNA", "REqHistogramZNA", kTH1F, {axisQZNA}); + histos.add("IMqHistogramZNA", "IMqHistogramZNA", kTH1F, {axisQZNA}); + + histos.add("REqHistogramZNC", "REqHistogramZNC", kTH1F, {axisQZNA}); + histos.add("IMqHistogramZNC", "IMqHistogramZNC", kTH1F, {axisQZNA}); + + histos.add("EnergyZNA", "ZNA Sector Energy", kTH1F, {axisEnergy}); + histos.add("EnergyZNC", "ZNC Sector Energy", kTH1F, {axisEnergy}); + histos.add("hCentFT0C", "FT0C Centrality Distribution", kTH1F, {{100, 0, 105}}); + histos.add("hZNvsFT0Ccent", + "ZN Energy vs FT0C Centrality", + kTH2F, + {axisCent, axisZN}); + + histos.add("hZPvsFT0Ccent", + "ZP Energy vs FT0C Centrality;Centrality [%];ZP Energy", + kTH2F, + {axisCent, axisZP}); + histos.add("hNchvsNPV", ";NPVTracks (|#eta|<1);N_{ch} (|#eta|<0.8);", + kTH2F, + {{{nBinsNch, -0.5, maxNch}, {nBinsNch, -0.5, maxNch}}}); + histos.add("revsimag", "revsimag", kTH2F, {axisREQ, axisIMQ}); // for q vector recentering + histos.add("hYield", "Nch vs pT", kTH2F, {axisMultiplicity, axisPt}); + histos.add("hGlobalTracks", "hGlobalTracks", kTH1F, {axisMultiplicity}); + // event selection steps + histos.add("eventSelectionSteps", "eventSelectionSteps", kTH1D, {axisEvent}); + auto hstat = histos.get(HIST("eventSelectionSteps")); + auto* xAxis = hstat->GetXaxis(); + xAxis->SetBinLabel(1, "All events"); + xAxis->SetBinLabel(2, "sel8"); + xAxis->SetBinLabel(3, "kNoSameBunchPileup"); // reject collisions in case of pileup with another collision in the same foundBC + xAxis->SetBinLabel(4, "kIsGoodZvtxFT0vsPV"); // small difference between z-vertex from PV and from FT0 + xAxis->SetBinLabel(5, "kIsVertexITSTPC"); // at least one ITS-TPC track (reject vertices built from ITS-only tracks) + xAxis->SetBinLabel(6, "kIsApplyVertexTOFmatched"); //"Centrality based on no other collisions in this Readout Frame with per-collision multiplicity above threshold tracks" + xAxis->SetBinLabel(7, "Occupancy Cuts"); + xAxis->SetBinLabel(8, "kITSLayersAll"); + xAxis->SetBinLabel(9, "kTRDVertexMatched"); + xAxis->SetBinLabel(10, "Centrality cut"); + xAxis->SetBinLabel(11, "Vertex Z cut"); + xAxis->SetBinLabel(12, "Extra Correlation Cut"); + + histos.add("GlobalMult_vs_FT0C", "GlobalMult_vs_FT0C", kTH2F, {axisMult, axisFT0CMult}); + histos.add("VtxZHist", "VtxZHist", kTH1D, {axisVtxZ}); + + if (doprocessZdcCollAssoc) { // Check if the process function for ZDCCollAssoc is enabled + histos.add("ZNAcoll", "ZNAcoll; ZNA amplitude; Entries", {HistType::kTH1F, {{nBinsAmp, -0.5, maxZn}}}); + histos.add("ZNCcoll", "ZNCcoll; ZNC amplitude; Entries", {HistType::kTH1F, {{nBinsAmp, -0.5, maxZn}}}); + histos.add("ZEM1coll", "ZEM1coll; ZEM1 amplitude; Entries", {HistType::kTH1F, {{nBinsAmp, -0.5, maxZem}}}); + histos.add("ZEM2coll", "ZEM2coll; ZEM2 amplitude; Entries", {HistType::kTH1F, {{nBinsAmp, -0.5, maxZem}}}); + histos.add("ZNvsZEMcoll", "ZNvsZEMcoll; ZEM; ZNA+ZNC", {HistType::kTH2F, {{{nBinsAmp, -0.5, maxZem}, {nBinsAmp, -0.5, 2. * maxZn}}}}); + histos.add("ZNAvsZNCcoll", "ZNAvsZNCcoll; ZNC; ZNA", {HistType::kTH2F, {{{nBinsAmp, -0.5, maxZn}, {nBinsAmp, -0.5, maxZn}}}}); + + histos.add("RealQHistogramZNA", "RealQHistogramZNA", kTH1F, {axisQZNA}); + histos.add("ImagQHistogramZNA", "ImagQHistogramZNA", kTH1F, {axisQZNA}); + histos.add("RealQHistogramZNC", "RealQHistogramZNC", kTH1F, {axisQZNA}); + histos.add("ImagQHistogramZNC", "ImagQHistogramZNC", kTH1F, {axisQZNA}); + + histos.add("Acorrelations", "Acorrelations", kTH2F, {{axisQZNA}, {axisQZNA}}); + histos.add("SPAngleZNA", "Spectator Plane Angle ZNA;Angle (radians);Entries", {HistType::kTH1F, {{100, -o2::constants::math::PI, o2::constants::math::PI}}}); + histos.add("SPAngleZNC", "Spectator Plane Angle ZNC;Angle (radians);Entries", {HistType::kTH1F, {{100, -o2::constants::math::PI, o2::constants::math::PI}}}); + + histos.add("RunningAverageCosPsiDiff", "Running Average of cos(psi) Differences;Running Average;Entries", {HistType::kTH1F, {{100, -1, 1}}}); + + histos.add("CosPsiDifferences", "Differences in cos(psi);cos(psiZNC) - cos(psiZNA);Entries", {HistType::kTH1F, {{100, -2, 2}}}); + histos.add("hSinDifferences", "Differences in sin(psi);sin(psiZNC) - sin(psiZNA);Entries", {HistType::kTH1F, {{100, -2, 2}}}); + histos.add("ZDC_energy_vs_ZEM", "ZDCvsZEM; ZEM; ZNA+ZNC+ZPA+ZPC", {HistType::kTH2F, {{{nBinsAmp, -0.5, maxZem}, {nBinsAmp, -0.5, 2. * maxZn}}}}); + // common energies information for ZDC + histos.add("ZNCenergy", "ZN energy side c", kTH1F, {axisEnergy}); + histos.add("ZNAenergy", "ZN energy side a", kTH1F, {axisEnergy}); + histos.add("ZPCenergy", "ZP energy side c", kTH1F, {axisEnergy}); + histos.add("ZPAenergy", "ZP energy side a", kTH1F, {axisEnergy}); + histos.add("ZNenergy", "common zn (a + c sides) energy", kTH1F, {axisEnergy}); + histos.add("ZPenergy", "common zp energy (a + c sides)", kTH1F, {axisEnergy}); + histos.add("hFT0CAmp", ";Amplitude;counts", kTH1F, {axisFT0CAmp}); + histos.add("hFT0AAmp", ";Amplitude;counts", kTH1F, {axisFT0AAmp}); + histos.add("hFT0MAmp", ";Amplitude;counts", kTH1F, {axisFT0MAmp}); + histos.add("hZNvsFT0CAmp", "ZN Energy vs FT0C Amplitude", kTH2F, {axisFT0CAmp, axisZN}); + histos.add("hZPvsFT0CAmp", "ZP Energy vs FT0C Amplitude", kTH2F, {axisFT0CAmp, axisZP}); + histos.add("hZNvsMult", "ZN Energy vs Multiplicity", kTH2F, {axisMultiplicity, axisZN}); + histos.add("hZPvsMult", "ZP Energy vs Multiplicity", kTH2F, {axisMultiplicity, axisZP}); + histos.add("debunch", ";t_{ZDC}-t_{ZDA};t_{ZDC}+t_{ZDA}", kTH2F, {{{nBinsTDC, minTdc, maxTdc}, {nBinsTDC, minTdc, maxTdc}}}); + } + } + template + bool isEventSelected(EventCuts const& col) + { + histos.fill(HIST("eventSelectionSteps"), 1); + + if (!col.sel8()) { + return false; + } + histos.fill(HIST("eventSelectionSteps"), 2); + + if (isApplySameBunchPileup && !col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + histos.fill(HIST("eventSelectionSteps"), 3); + + if (isApplyGoodZvtxFT0vsPV && !col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + histos.fill(HIST("eventSelectionSteps"), 4); + + if (isApplyVertexITSTPC && !col.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + histos.fill(HIST("eventSelectionSteps"), 5); + + if (isApplyVertexTOFmatched && !col.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return false; + } + histos.fill(HIST("eventSelectionSteps"), 6); + + if (isOccupancyCut) { + auto occuValue{isApplyFT0CbasedOccupancy + ? col.ft0cOccupancyInTimeRange() + : col.trackOccupancyInTimeRange()}; + + if (occuValue < minOccCut || occuValue > maxOccCut) + return false; + } + histos.fill(HIST("eventSelectionSteps"), 7); + if (isGoodITSLayersAll && !col.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return false; + } + histos.fill(HIST("eventSelectionSteps"), 8); + if (isApplyVertexTRDmatched && !col.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + return false; + } + histos.fill(HIST("eventSelectionSteps"), 9); + if (col.centFT0C() < 0. || col.centFT0C() > 100.) { + return false; + } + histos.fill(HIST("eventSelectionSteps"), 10); + if (std::fabs(col.posZ()) > posZcut) { + return false; + } + histos.fill(HIST("eventSelectionSteps"), 11); + if (isApplyExtraCorrCut && col.multNTracksPV() > npvTracksCut && col.multFT0C() < (10 * col.multNTracksPV() - ft0cCut)) { + return false; + } + histos.fill(HIST("eventSelectionSteps"), 12); + return true; + } + + void processQVector(AodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, AodTracks const& tracks, BCsRun3 const& /*bcs*/, aod::Zdcs const& /*zdcsData*/, aod::ZDCMults const& /*zdcMults*/) + { + if (!isEventSelected(collision)) { + return; + } + histos.fill(HIST("eventCounter"), 0.5); + histos.fill(HIST("centHistogram"), collision.centFT0C()); + const auto& tracksGrouped = tracksIUWithTPC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + const int multTPC = tracksGrouped.size(); + const auto cent = collision.centFT0C(); + int globalTracks = tracks.size(); + if (globalTracks < 1) + return; + // this is the q vector for the TPC data. it is a complex function + double qTpcReal = 0.0; // Initialize qTPC_real + double qTpcIm = 0.0; // init qTPC_imaginary + std::complex qTPC(0, 0); // Starting with a q-vector of zero + int nTot{0}; // Tracks are already filtered with GlobalTrack || GlobalTrackSDD + for (const auto& track : tracks) { + double phi = track.phi(); + nTot++; + histos.fill(HIST("etaHistogram"), track.eta()); + histos.fill(HIST("phiHistogram"), track.phi()); + histos.fill(HIST("ptHistogram"), track.pt()); + qTPC += std::complex(std::cos(2.0 * phi), std::sin(2.0 * phi)); + } // end track loop 1 + double pT{0}; + for (const auto& track : tracks) { + if (track.tpcNClsCrossedRows() < minTpcNcrossedRows) + continue; + if (std::fabs(track.dcaXY()) > cfgCutDCAxy) + continue; + pT = track.pt(); + pT++; + } // end track loop 2 + histos.fill(HIST("multvsCent"), cent, nTot); + histos.fill(HIST("hYield"), nTot, pT); + histos.fill(HIST("multHistogram"), nTot); + qTpcReal = qTPC.real() / nTot; // normalize these vectors by the total number of particles + qTpcIm = qTPC.imag() / nTot; + + histos.fill(HIST("REqHistogram"), qTpcReal); + histos.fill(HIST("IMqHistogram"), qTpcIm); + + histos.fill(HIST("TPCmultiplicity"), multTPC); + histos.fill(HIST("hGlobalTracks"), globalTracks); + + histos.fill(HIST("revsimag"), qTpcReal, qTpcIm); + } + void processZdcCollAssoc( + AodCollisions::iterator const& collision, + AodTracks const& tracks, + BCsRun3 const& /*bcs*/, + aod::Zdcs const& /*zdcs*/, + aod::FT0s const& /*ft0s*/) + { + if (!isEventSelected(collision)) { + return; + } + int nTot = tracks.size(); + double sumCosPsiDiff = 0.0; // initialize Sum of cosPsiDiff for averaging + double sumSinPsiDiff = 0.0; // initialize Sum of cosPsiDiff for averaging + int countEvents = 0; // initialize Counter for the number of events processed + double ft0aAmp = 0; + double ft0cAmp = 0; + float tZNA{0.0}; + float tZNC{0.0}; + float tZPA{0.0}; + float tZPC{0.0}; + float tZDCdif{0.0}; + float tZDCsum{0.0}; + const auto& foundBC = collision.foundBC_as(); + if (collision.has_foundFT0()) { + auto ft0 = collision.foundFT0(); + for (const auto& amplitude : ft0.amplitudeA()) { + ft0aAmp += amplitude; + } + for (const auto& amplitude : ft0.amplitudeC()) { + ft0cAmp += amplitude; + } + } + histos.fill(HIST("hFT0AAmp"), ft0aAmp); + histos.fill(HIST("hFT0CAmp"), ft0cAmp); + double ft0mAmp = ft0aAmp + ft0cAmp; + histos.fill(HIST("hFT0MAmp"), ft0mAmp); + if (foundBC.has_zdc()) { + const auto& zdcread = foundBC.zdc(); + const auto cent = collision.centFT0C(); + + // ZDC data and histogram filling + histos.get(HIST("ZNAcoll"))->Fill(zdcread.amplitudeZNA()); + histos.get(HIST("ZNCcoll"))->Fill(zdcread.amplitudeZNC()); + histos.get(HIST("ZNvsZEMcoll"))->Fill(zdcread.amplitudeZEM1() + zdcread.amplitudeZEM2(), zdcread.amplitudeZNA() + zdcread.amplitudeZNC()); + histos.get(HIST("ZNAvsZNCcoll"))->Fill(zdcread.amplitudeZNC(), zdcread.amplitudeZNA()); + + histos.get(HIST("ZEM1coll"))->Fill(zdcread.amplitudeZEM1()); + histos.get(HIST("ZEM2coll"))->Fill(zdcread.amplitudeZEM2()); + tZNA = foundBC.zdc().timeZNA(); + tZNC = foundBC.zdc().timeZNC(); + tZPA = foundBC.zdc().timeZPA(); + tZPC = foundBC.zdc().timeZPC(); + tZDCdif = tZNC + tZPC - tZNA - tZPA; + tZDCsum = tZNC + tZPC + tZNA + tZPA; + + float sumZNC = (zdcread.energySectorZNC())[0] + (zdcread.energySectorZNC())[1] + (zdcread.energySectorZNC())[2] + (zdcread.energySectorZNC())[3]; + float sumZNA = (zdcread.energySectorZNA())[0] + (zdcread.energySectorZNA())[1] + (zdcread.energySectorZNA())[2] + (zdcread.energySectorZNA())[3]; + float sumZPC = (zdcread.energySectorZPC())[0] + (zdcread.energySectorZPC())[1] + (zdcread.energySectorZPC())[2] + (zdcread.energySectorZPC())[3]; + float sumZPA = (zdcread.energySectorZPA())[0] + (zdcread.energySectorZPA())[1] + (zdcread.energySectorZPA())[2] + (zdcread.energySectorZPA())[3]; + float sumZDC = sumZPA + sumZPC + sumZNA + sumZNC; + float sumZEM = zdcread.amplitudeZEM1() + zdcread.amplitudeZEM2(); + // ZEM cut + if (isZEMcut) { + if (sumZEM < zemCut) { + return; + } + } + // common energies + float commonSumZnc = (zdcread.energyCommonZNC()) / acceptanceZnc; + float commonSumZna = (zdcread.energyCommonZNA()) / acceptanceZna; + float commonSumZpc = (zdcread.energyCommonZPC()) / acceptanceZpc; + float commonSumZpa = (zdcread.energyCommonZPA()) / acceptanceZpa; + float sumZN = (sumZNC) + (sumZNA); + float sumZP = (sumZPC) + (sumZPA); + + histos.fill(HIST("ZNenergy"), sumZN); + histos.fill(HIST("ZPenergy"), sumZP); + histos.fill(HIST("ZNCenergy"), commonSumZnc); + histos.fill(HIST("ZNAenergy"), commonSumZna); + histos.fill(HIST("ZPAenergy"), commonSumZpa); + histos.fill(HIST("ZPCenergy"), commonSumZpc); + histos.fill(HIST("hZNvsFT0Ccent"), cent, sumZN); + histos.fill(HIST("hZPvsFT0Ccent"), cent, sumZP); + histos.fill(HIST("hZNvsFT0CAmp"), ft0cAmp, sumZN); + histos.fill(HIST("hZPvsFT0CAmp"), ft0cAmp, sumZP); + histos.fill(HIST("hZNvsMult"), nTot, sumZN); + histos.fill(HIST("hZPvsMult"), nTot, sumZP); + histos.fill(HIST("debunch"), tZDCdif, tZDCsum); + histos.fill(HIST("hNchvsNPV"), collision.multNTracksPVeta1(), nTot); + + float ratioZN = sumZNC / sumZNA; + float ratioZP = sumZPC / sumZPA; + pZNratiovscent->Fill(cent, ratioZN); + pZPratiovscent->Fill(cent, ratioZP); + pZNvsFT0Ccent->Fill(cent, sumZN); + pZPvsFT0Ccent->Fill(cent, sumZP); + + histos.get(HIST("ZDC_energy_vs_ZEM"))->Fill(sumZEM, sumZDC); + + // Spectator plane angle calculations and histograms + const auto nTotZna = zdcread.amplitudeZNA(); + const auto nTotZnc = zdcread.amplitudeZNC(); + double qZnaReal = 0.0; + double qZnaIm = 0.0; + double qZncReal = 0.0; + double qZncIm = 0.0; + const double phiRadians[4] = {45 * o2::constants::math::PI / 180, 135 * o2::constants::math::PI / 180, 225 * o2::constants::math::PI / 180, 315 * o2::constants::math::PI / 180}; + std::complex qZNA = std::complex(0.0, 0.0); + std::complex qZNC = std::complex(0.0, 0.0); + + for (int sector = 0; sector < 4; ++sector) { + float energyZNA = zdcread.energySectorZNA()[sector]; + float energyZNC = zdcread.energySectorZNC()[sector]; + + qZNA += std::complex(std::cos(2 * phiRadians[sector]) * energyZNA / sumZNA, std::sin(2 * phiRadians[sector]) * energyZNA / sumZNA); + qZNC += std::complex(std::cos(2 * phiRadians[sector]) * energyZNC / sumZNC, std::sin(2 * phiRadians[sector]) * energyZNC / sumZNC); + } + + qZnaReal = qZNA.real() / nTotZna; + qZnaIm = qZNA.imag() / nTotZna; + qZncReal = qZNC.real() / nTotZnc; + qZncIm = qZNC.imag() / nTotZnc; + + histos.fill(HIST("Acorrelations"), qZNA.real(), qZNA.imag()); + histos.fill(HIST("RealQHistogramZNA"), qZnaReal); + histos.fill(HIST("ImagQHistogramZNA"), qZnaIm); + histos.fill(HIST("RealQHistogramZNC"), qZncReal); + histos.fill(HIST("ImagQHistogramZNC"), qZncIm); + + // Calculate the spectator plane angles for ZNA and ZNC + double psiZNA = std::atan2(qZNA.imag(), qZNA.real()) / 2.0; + double psiZNC = std::atan2(qZNC.imag(), qZNC.real()) / 2.0; + + // Fill the histograms with the calculated angles + histos.fill(HIST("SPAngleZNA"), psiZNA); + histos.fill(HIST("SPAngleZNC"), psiZNC); + + double cosPsiDiff = std::cos(psiZNA) - std::cos(psiZNC); + double sinPsiDiff = std::sin(psiZNA) - std::sin(psiZNC); + + sumCosPsiDiff += cosPsiDiff; + sumSinPsiDiff += sinPsiDiff; + ++countEvents; + + if (countEvents > 0) { + double runningAverageCosPsiDiff = sumCosPsiDiff / countEvents; + double runningAverageSinPsiDiff = sumSinPsiDiff / countEvents; + histos.fill(HIST("RunningAverageCosPsiDiff"), runningAverageCosPsiDiff); + pCosPsiDifferences->Fill(cent, runningAverageCosPsiDiff); + pSinPsiDifferences->Fill(cent, runningAverageSinPsiDiff); + } + histos.fill(HIST("CosPsiDifferences"), cosPsiDiff); + histos.fill(HIST("hSinDifferences"), sinPsiDiff); + } + } + + void processCorrelation(CollisionDataTable::iterator const& collision, FilTrackDataTable const& tracks) + { + if (!isEventSelected(collision)) { + return; + } + if (std::abs(collision.posZ()) >= vtxRange) { + return; + } + histos.fill(HIST("VtxZHist"), collision.posZ()); + auto nchTracks = 0; + for (const auto& track : tracks) { + if (std::abs(track.eta()) >= etaRange) { + continue; + } + nchTracks++; + } + histos.fill(HIST("GlobalMult_vs_FT0C"), nchTracks, collision.multFT0C()); + } + + PROCESS_SWITCH(FlowZdcTask, processZdcCollAssoc, "Processing ZDC w. collision association", true); + PROCESS_SWITCH(FlowZdcTask, processQVector, "Process before recentering", true); + PROCESS_SWITCH(FlowZdcTask, processCorrelation, "Process correlations", true); + +}; // end of struct function + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Flow/Tasks/pidcme.cxx b/PWGCF/Flow/Tasks/pidcme.cxx new file mode 100644 index 00000000000..8242b9af48b --- /dev/null +++ b/PWGCF/Flow/Tasks/pidcme.cxx @@ -0,0 +1,3434 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author ZhengqingWang(zhengqing.wang@cern.ch) +/// \file pidcme.cxx +/// \brief task to calculate the pikp cme signal and bacground. +// C++/ROOT includes. +// o2-linter: disable=name/workflow-file +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// o2Physics includes. +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StaticFor.h" + +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/Core/EventPlaneHelper.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" + +#include "CommonConstants/PhysicsConstants.h" + +// o2 includes. + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace o2::aod +{ +namespace cme_track_pid_columns +{ +DECLARE_SOA_COLUMN(NPidFlag, nPidFlag, int8_t); // Flag tracks without proper binning as -1, and indicate type of particle [0->(un_Id) 1->(pi_only), 2->(ka_only), 3->(pr_only), 4->(pi_ITSleft), 5->(ka_ITSleft), 6->(pr_ITSleft), 7->(pi_ka), 8->(pi_Pr), 9->(ka_pr), 10->(pi_ka_pr), 11->(pi_ka_ITSleft), 12->(pi_pr_ITSleft), 13->(ka_pr_ITSleft), 14->(pi_ka_pr_ITSleft)] +DECLARE_SOA_COLUMN(AverClusterSizeCosl, averClusterSizeCosl, float); +DECLARE_SOA_COLUMN(NSigmaPiITS, nSigmaPiITS, float); +DECLARE_SOA_COLUMN(NSigmaKaITS, nSigmaKaITS, float); +DECLARE_SOA_COLUMN(NSigmaPrITS, nSigmaPrITS, float); +DECLARE_SOA_COLUMN(NSigmaPiTPC, nSigmaPiTPC, float); +DECLARE_SOA_COLUMN(NSigmaKaTPC, nSigmaKaTPC, float); +DECLARE_SOA_COLUMN(NSigmaPrTPC, nSigmaPrTPC, float); +DECLARE_SOA_COLUMN(NSigmaPiTOF, nSigmaPiTOF, float); +DECLARE_SOA_COLUMN(NSigmaKaTOF, nSigmaKaTOF, float); +DECLARE_SOA_COLUMN(NSigmaPrTOF, nSigmaPrTOF, float); +} // namespace cme_track_pid_columns +DECLARE_SOA_TABLE(Flags, "AOD", "Flags", cme_track_pid_columns::NPidFlag); +DECLARE_SOA_TABLE(PidInfo, "AOD", "PidInfo", cme_track_pid_columns::AverClusterSizeCosl, cme_track_pid_columns::NSigmaPiITS, cme_track_pid_columns::NSigmaKaITS, cme_track_pid_columns::NSigmaPrITS, cme_track_pid_columns::NSigmaPiTPC, cme_track_pid_columns::NSigmaKaTPC, cme_track_pid_columns::NSigmaPrTPC, cme_track_pid_columns::NSigmaPiTOF, cme_track_pid_columns::NSigmaKaTOF, cme_track_pid_columns::NSigmaPrTOF); +} // namespace o2::aod + +using TracksPID = soa::Join; +using CollisionPID = soa::Join; +struct FillPIDcolums { + Configurable cfgPtMaxforTPCOnlyPID{"cfgPtMaxforTPCOnlyPID", 0.4, "Maxmium track pt for TPC only PID,only when onlyTOF and onlyTOFHIT closed"}; + Configurable cfgMinPtPID{"cfgMinPtPID", 0.15, "Minimum track #P_{t} for PID"}; + Configurable cfgMaxPtPID{"cfgMaxPtPID", 99.9, "Maximum track #P_{t} for PID"}; + Configurable cfgMaxEtaPID{"cfgMaxEtaPID", 0.8, "Maximum track #eta for PID"}; + Configurable cfgMaxTPCChi2NCl{"cfgMaxTPCChi2NCl", 2.5, "Maximum chi2 per cluster TPC for PID if not use costom track cuts"}; + Configurable cfgMaxChi2NClITS{"cfgMaxChi2NClITS", 2.5, "Maximum chi2 per cluster ITS for PID if not use costom track cuts"}; + Configurable cfgMinTPCCls{"cfgMinTPCCls", 70, "Minimum TPC clusters for PID if not use costom track cuts"}; + Configurable cfgMinITSCls{"cfgMinITSCls", 1, "Minimum ITS clusters for PID if not use costom track cuts"}; + Configurable cfgMaxTPCCls{"cfgMaxTPCCls", 999, "Max TPC clusters for PID if not use costom track cuts"}; + Configurable cfgMaxITSCls{"cfgMaxITSCls", 999, "Max ITS clusters for PID if not use costom track cuts"}; + Configurable cfgMaxDCAxy{"cfgMaxDCAxy", 99, "Maxium DCAxy for standard PID tracking"}; + Configurable cfgMaxDCAz{"cfgMaxDCAz", 2, "Maxium DCAz for standard PID tracking"}; + Configurable cfgAveClusSizeCoslMinPi{"cfgAveClusSizeCoslMinPi", 0, "Base line for minmum ITS cluster size x cos(#lambda) for Pions"}; + Configurable cfgAveClusSizeCoslMaxPi{"cfgAveClusSizeCoslMaxPi", 1e9, "Base line for maxmum ITS cluster size x cos(#lambda) for Pions"}; + Configurable cfgAveClusSizeCoslMinKa{"cfgAveClusSizeCoslMinKa", 0, "Base line for minmum ITS cluster size x cos(#lambda) for Kaons"}; + Configurable cfgAveClusSizeCoslMaxKa{"cfgAveClusSizeCoslMaxKa", 1e9, "Base line for maxmum ITS cluster size x cos(#lambda) for Kaons"}; + Configurable cfgAveClusSizeCoslMinPr{"cfgAveClusSizeCoslMinPr", 0, "Base line for minmum ITS cluster size x cos(#lambda) for Protons"}; + Configurable cfgAveClusSizeCoslMaxPr{"cfgAveClusSizeCoslMaxPr", 1e9, "Base line for maxmum ITS cluster size x cos(#lambda) for Protons"}; + + ConfigurableAxis cfgrigidityBins{"cfgrigidityBins", {200, -10.f, 10.f}, "Binning for rigidity #it{p}^{TPC}/#it{z}"}; + ConfigurableAxis cfgdedxBins{"cfgdedxBins", {1000, 0.f, 1000.f}, "Binning for dE/dx"}; + ConfigurableAxis cfgnSigmaBinsTPC{"cfgnSigmaBinsTPC", {200, -5.f, 5.f}, "Binning for n sigma TPC"}; + ConfigurableAxis cfgnSigmaBinsTOF{"cfgnSigmaBinsTOF", {200, -5.f, 5.f}, "Binning for n sigma TOF"}; + ConfigurableAxis cfgnSigmaBinsITS{"cfgnSigmaBinsITS", {200, -5.f, 5.f}, "Binning for n sigma ITS"}; + ConfigurableAxis cfgnSigmaBinsCom{"cfgnSigmaBinsCom", {100, 0.f, 10.f}, "Combination Binning for TPC&TOF nsigma"}; + ConfigurableAxis cfgaxisptPID{"cfgaxisptPID", {120, 0, 12}, "Binning for P_{t} PID"}; + ConfigurableAxis cfgaxispPID{"cfgaxispPID", {50, 0, 5}, "Binning for P PID"}; + ConfigurableAxis cfgaxisAverClusterCosl{"cfgaxisAverClusterCosl", {50, 0, 10}, "Binning for average cluster size x cos(#lambda)"}; + ConfigurableAxis cfgaxisAverClusterCoslnSigma{"cfgaxisAverClusterCoslnSigma", {50, 0, 5}, "Binning for average cluster size x cos(#lambda) vs nSigam"}; + ConfigurableAxis cfgaxisetaPID{"cfgaxisetaPID", {90, -0.9, 0.9}, "Binning for Pt QA"}; + ConfigurableAxis cfgaxisDCAz{"cfgaxisDCAz", {200, -1, 1}, "Binning for DCAz"}; + ConfigurableAxis cfgaxisDCAxy{"cfgaxisDCAxy", {100, -0.5, 0.5}, "Binning for DCAxy"}; + ConfigurableAxis cfgaxisChi2Ncls{"cfgaxisChi2Ncls", {50, 0, 5}, "Binning for Chi2Ncls TPC/ITS"}; + + Configurable cfgQuietMode{"cfgQuietMode", false, "open quiet mode for saving cpu cost and only do some basic QA plots"}; + Configurable cfgRequireGlobalTrack{"cfgRequireGlobalTrack", false, "Require track used must be the global track"}; + Configurable cfgOpenPIDPtSelection{"cfgOpenPIDPtSelection", false, "Cut Pt reign PID particles for use"}; + Configurable cfgOpenPlotnSigmaOrigin{"cfgOpenPlotnSigmaOrigin", true, "Open origin nSigma plots before PID selections"}; + Configurable cfgOpenPlotnSigmaTOFITSPt{"cfgOpenPlotnSigmaTOFITSPt", true, "plot nSigmaTOF vs nSigmaITS vs Pt"}; + Configurable cfgOpenPlotnSigmaITSTPCPt{"cfgOpenPlotnSigmaITSTPCPt", true, "plot nSigmaITS vs nSigmaTOF vs Pt"}; + Configurable cfgOpenPlotnSigmaTOFTPCPt{"cfgOpenPlotnSigmaTOFTPCPt", true, "plot nSigmaTOF vs nSigmaTPC vs Pt"}; + Configurable cfgOpenPlotAverClus{"cfgOpenPlotAverClus", true, "plot average cluster size x cos(#lambda)"}; + Configurable cfgOpenPlotAverClusP{"cfgOpenPlotAverClusP", true, "plot average cluster size x cos(#lambda) vs p"}; + Configurable cfgOpenPlotAverClusnSigmaTPC{"cfgOpenPlotAverClusnSigmaTPC", true, "plot average cluster size x cos(#lambda) vs nSigmaTPC"}; + Configurable cfgOpenPlotPhiDis{"cfgOpenPlotPhiDis", true, "plot phi distribution QA"}; + Configurable cfgOpenPlotPhiDisPtEta{"cfgOpenPlotPhiDisPtEta", true, "plot phi pt eta distribution QA"}; + Configurable cfgOpenITSCut{"cfgOpenITSCut", true, "open ITSnsigma cut"}; + Configurable cfgOpenITSCutQAPlots{"cfgOpenITSCutQAPlots", true, "open QA plots after ITS nsigma cut"}; + Configurable cfgOpenDetailPlotsTPCITSContaimination{"cfgOpenDetailPlotsTPCITSContaimination", false, "open detail TH3D plots for nSigmaTPC-ITS Pt-eta-Phi nSigmaITS-clustersize"}; + Configurable cfgOpenAllowCrossTrack{"cfgOpenAllowCrossTrack", false, "Allow one track to be identified as different kind of PID particles"}; + Configurable cfgOpenCrossTrackQAPlots{"cfgOpenCrossTrackQAPlots", true, "open cross pid track QA plots"}; + Configurable cfgOpenTOFOnlyPID{"cfgOpenTOFOnlyPID", true, "only accept tracks who has TOF infomation and use TOFnsigma for PID(priority greater than TPConly and combined"}; + Configurable cfgOpenTPCAssistanceTOFOnlyPID{"cfgOpenTPCAssistanceTOFOnlyPID", false, "Set loose TPC nsigma cut for TOFOnlyPID mode using cfg nsigmaTPC configurations"}; + Configurable cfgOpenTPCOnlyPID{"cfgOpenTPCOnlyPID", false, "only use TPCnsigma for PID(priority grater than combined less than TOFOnly)"}; + Configurable cfgUseCostomTrackCuts{"cfgUseCostomTrackCuts", true, "use track cuts from default track selection table producer"}; + Configurable cfgOpenPtRangedTOFnSigmacutPi{"cfgOpenPtRangedTOFnSigmacutPi", false, "use nSigma TOF cut for different pt Pion"}; + Configurable cfgOpenPtRangedTPCnSigmacutPi{"cfgOpenPtRangedTPCnSigmacutPi", false, "use nSigma TPC cut for different pt Pion"}; + Configurable cfgOpenPtRangedITSnSigmacutPi{"cfgOpenPtRangedITSnSigmacutPi", false, "use nSigma ITS cut for different pt Pion"}; + Configurable cfgOpenPtRangedTOFnSigmacutKa{"cfgOpenPtRangedTOFnSigmacutKa", false, "use nSigma TOF cut for different pt Kaon"}; + Configurable cfgOpenPtRangedTPCnSigmacutKa{"cfgOpenPtRangedTPCnSigmacutKa", false, "use nSigma TPC cut for different pt Kaon"}; + Configurable cfgOpenPtRangedITSnSigmacutKa{"cfgOpenPtRangedITSnSigmacutKa", false, "use nSigma ITS cut for different pt Kaon"}; + Configurable cfgOpenPtRangedTOFnSigmacutPr{"cfgOpenPtRangedTOFnSigmacutPr", false, "use nSigma TOF cut for different pt Proton"}; + Configurable cfgOpenPtRangedTPCnSigmacutPr{"cfgOpenPtRangedTPCnSigmacutPr", false, "use nSigma TPC cut for different pt Proton"}; + Configurable cfgOpenPtRangedITSnSigmacutPr{"cfgOpenPtRangedITSnSigmacutPr", false, "use nSigma ITS cut for different pt Proton"}; + Configurable cfgOpenPlotCheckITSOnlytrackInfo{"cfgOpenPlotCheckITSOnlytrackInfo", true, "plot checks if track NclsTPC is 0 for assure it has p info or not"}; + Configurable cfgOpenTrackingInfoCheck{"cfgOpenTrackingInfoCheck", true, "plot track infomation check"}; + + Configurable> cfgPtCutLower{"cfgPtCutLower", {0.15, 0.15, 0.15}, "Pt lower limit for pi k p respectively"}; + Configurable> cfgPtCutUpper{"cfgPtCutUpper", {99., 99., 99.}, "Pt upper limit for pi k p respectively"}; + Configurable> cfgnSigmaCutTPCUpper{"cfgnSigmaCutTPCUpper", {3, 3, 3}, "TPC nsigma cut upper limit for pi k p respectively at low pt and for the TPCOnly case"}; + Configurable> cfgnSigmaCutTOFUpper{"cfgnSigmaCutTOFUpper", {1.5, 1.5, 1.5}, "TOF nsigma cut upper limit for pi k p respectively for the TOFonly case"}; + Configurable> cfgnSigmaCutRMSUpper{"cfgnSigmaCutRMSUpper", {3, 3, 3}, "TPC_TOF combined cut upper limit for pi k p respectively at high pt"}; + Configurable> cfgnSigmaCutITSUpper{"cfgnSigmaCutITSUpper", {3, 2.5, 2}, "ITS nSigma cut upper limit for pi k p"}; + Configurable> cfgnSigmaCutTPCLower{"cfgnSigmaCutTPCLower", {-3, -3, -3}, "TPC nsigma cut lower limit for pi k p respectively at low pt and for the TPCOnly case"}; + Configurable> cfgnSigmaCutTOFLower{"cfgnSigmaCutTOFLower", {-1.5, -1.5, -1.5}, "TOF nsigma cut lower limit for pi k p respectively for the TOFonly case"}; + Configurable> cfgnSigmaCutRMSLower{"cfgnSigmaCutRMSLower", {-3, -3, -3}, "TPC_TOF combined cut lower limit for pi k p respectively at high pt"}; + Configurable> cfgnSigmaCutITSLower{"cfgnSigmaCutITSLower", {-3, -2.5, -2}, "ITS nSigma cut lower limit for pi k p"}; + Configurable> cfgPtBinPionPID{"cfgPtBinPionPID", {0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 3.0, 3.5, 4.0, 5.0, 6.0, 8.0, 10.0}, "pt bin for pion PIDnsigma"}; + Configurable> cfgPtBinKaonPID{"cfgPtBinKaonPID", {0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 3.0, 3.5, 4.0, 5.0, 6.0}, "pt bin for pion PIDnsigma"}; + Configurable> cfgPtBinProtonPID{"cfgPtBinProtonPID", {0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 3.0, 3.5, 4.0, 5.0, 6.0}, "pt bin for pion PIDnsigma"}; + Configurable> cfgnSigmaTPCPionPtUpper{"cfgnSigmaTPCPionPtUpper", {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, "nSigmaTPC cut upper limit anchored to pion pt bins"}; + Configurable> cfgnSigmaTOFPionPtUpper{"cfgnSigmaTOFPionPtUpper", {1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5}, "nSigmaTOF cut upper limit anchored to pion pt bins"}; + Configurable> cfgnSigmaITSPionPtUpper{"cfgnSigmaITSPionPtUpper", {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, "nSigmaITS cut upper limit anchored to pion pt bins"}; + Configurable> cfgnSigmaTPCKaonPtUpper{"cfgnSigmaTPCKaonPtUpper", {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, "nSigmaTPC cut upper limit anchored to kaon pt bins"}; + Configurable> cfgnSigmaTOFKaonPtUpper{"cfgnSigmaTOFKaonPtUpper", {1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5}, "nSigmaTOF cut upper limit anchored to kaon pt bins"}; + Configurable> cfgnSigmaITSKaonPtUpper{"cfgnSigmaITSKaonPtUpper", {2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5}, "nSigmaITS cut upper limit anchored to kaon pt bins"}; + Configurable> cfgnSigmaTPCProtonPtUpper{"cfgnSigmaTPCProtonPtUpper", {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, "nSigmaTPC cut upper limit anchored to proton pt bins"}; + Configurable> cfgnSigmaTOFProtonPtUpper{"cfgnSigmaTOFProtonPtUpper", {1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5}, "nSigmaTOF cut upper limit anchored to proton pt bins"}; + Configurable> cfgnSigmaITSProtonPtUpper{"cfgnSigmaITSProtonPtUpper", {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, "nSigmaITS cut upper limit anchored to proton pt bins"}; + Configurable> cfgnSigmaTPCPionPtLower{"cfgnSigmaTPCPionPtLower", {-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3}, "nSigmaTPC cut lower limit anchored to pion pt bins"}; + Configurable> cfgnSigmaTOFPionPtLower{"cfgnSigmaTOFPionPtLower", {-1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5}, "nSigmaTOF cut lower limit anchored to pion pt bins"}; + Configurable> cfgnSigmaITSPionPtLower{"cfgnSigmaITSPionPtLower", {-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3}, "nSigmaITS cut lower limit anchored to pion pt bins"}; + Configurable> cfgnSigmaTPCKaonPtLower{"cfgnSigmaTPCKaonPtLower", {-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3}, "nSigmaTPC cut lower limit anchored to kaon pt bins"}; + Configurable> cfgnSigmaTOFKaonPtLower{"cfgnSigmaTOFKaonPtLower", {-1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5}, "nSigmaTOF cut lower limit anchored to kaon pt bins"}; + Configurable> cfgnSigmaITSKaonPtLower{"cfgnSigmaITSKaonPtLower", {-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5}, "nSigmaITS cut lower limit anchored to kaon pt bins"}; + Configurable> cfgnSigmaTPCProtonPtLower{"cfgnSigmaTPCProtonPtLower", {-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3}, "nSigmaTPC cut lower limit anchored to proton pt bins"}; + Configurable> cfgnSigmaTOFProtonPtLower{"cfgnSigmaTOFProtonPtLower", {-1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5}, "nSigmaTOF cut lower limit anchored to proton pt bins"}; + Configurable> cfgnSigmaITSProtonPtLower{"cfgnSigmaITSProtonPtLower", {-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2}, "nSigmaITS cut lower limit anchored to proton pt bins"}; + + static float averageClusterSizeCosl(uint32_t itsClusterSizes, float eta) + { + float average = 0; + int nclusters = 0; + const float cosl = 1. / std::cosh(eta); + + for (int layer = 0; layer < 7; layer++) { + if ((itsClusterSizes >> (layer * 4)) & 0xf) { + nclusters++; + average += (itsClusterSizes >> (layer * 4)) & 0xf; + } + } + if (nclusters == 0) { + return 0; + } + return average * cosl / nclusters; + }; + + template + bool selTrackPid(const TrackType track) + { + if ((track.pt() < cfgMinPtPID) || (track.pt() > cfgMaxPtPID)) + return false; + if (std::abs(track.eta()) > cfgMaxEtaPID) + return false; + if (cfgRequireGlobalTrack) { + if (!(track.isGlobalTrackSDD() == (uint8_t) true)) + return false; + } + if (cfgUseCostomTrackCuts) { + if (!track.passedITSNCls()) + return false; + if (!track.passedITSChi2NDF()) + return false; + if (!track.passedITSHits()) + return false; + if (!track.passedTPCChi2NDF()) + return false; + if (!track.passedTPCCrossedRowsOverNCls()) + return false; + if (!track.passedDCAxy()) + return false; + if (!track.passedDCAz()) + return false; + } else { + if (track.tpcChi2NCl() > cfgMaxTPCChi2NCl) + return false; + if (track.tpcNClsFound() < cfgMinTPCCls || track.tpcNClsFound() > cfgMaxTPCCls) + return false; + if (track.itsChi2NCl() > cfgMaxChi2NClITS) + return false; + if (track.itsNCls() < cfgMinITSCls || track.itsNCls() > cfgMaxITSCls) + return false; + if (std::abs(track.dcaXY()) > cfgMaxDCAxy) + return false; + if (std::abs(track.dcaZ()) > cfgMaxDCAz) + return false; + } + return true; + } + + template + int selectionPidtpctof(const T& candidate, std::array nSigmaTOFCutPtUpper, std::array nSigmaTOFCutPtLower, std::array nSigmaTPCCutPtUpper, std::array nSigmaTPCCutPtLower) + { + // initialization for basic parameter + float averClusSizeCosl = averageClusterSizeCosl(candidate.itsClusterSizes(), candidate.eta()); + std::array nSigmaTPC = {candidate.tpcNSigmaPi(), candidate.tpcNSigmaKa(), candidate.tpcNSigmaPr()}; + std::array nSigmaTOF = {candidate.tofNSigmaPi(), candidate.tofNSigmaKa(), candidate.tofNSigmaPr()}; + std::array nSigmaCombined = {std::hypot(candidate.tpcNSigmaPi(), candidate.tofNSigmaPi()), std::hypot(candidate.tpcNSigmaKa(), candidate.tofNSigmaKa()), std::hypot(candidate.tpcNSigmaPr(), candidate.tofNSigmaPr())}; + std::array nSigmaToUse; + std::vector pidVectorUpper; + std::vector pidVectorLower; + std::vector pidVectorTOFPtUpper; + std::vector pidVectorTOFPtLower; + std::vector pidVectorTPCPtUpper; + std::vector pidVectorTPCPtLower; + int pid = -1; + bool kIsPi = false, kIsKa = false, kIsPr = false; + pidVectorTOFPtUpper.push_back(nSigmaTOFCutPtUpper[0]); + pidVectorTOFPtUpper.push_back(nSigmaTOFCutPtUpper[1]); + pidVectorTOFPtUpper.push_back(nSigmaTOFCutPtUpper[2]); + pidVectorTOFPtLower.push_back(nSigmaTOFCutPtLower[0]); + pidVectorTOFPtLower.push_back(nSigmaTOFCutPtLower[1]); + pidVectorTOFPtLower.push_back(nSigmaTOFCutPtLower[2]); + pidVectorTPCPtUpper.push_back(nSigmaTPCCutPtUpper[0]); + pidVectorTPCPtUpper.push_back(nSigmaTPCCutPtUpper[1]); + pidVectorTPCPtUpper.push_back(nSigmaTPCCutPtUpper[2]); + pidVectorTPCPtLower.push_back(nSigmaTPCCutPtLower[0]); + pidVectorTPCPtLower.push_back(nSigmaTPCCutPtLower[1]); + pidVectorTPCPtLower.push_back(nSigmaTPCCutPtLower[2]); + // Choose which nSigma array and PIDcut array to use + if (cfgOpenTOFOnlyPID) { + if (!candidate.hasTOF()) + return 0; + nSigmaToUse = nSigmaTOF; + pidVectorUpper = pidVectorTOFPtUpper; + pidVectorLower = pidVectorTOFPtLower; + } else if (cfgOpenTPCOnlyPID) { + nSigmaToUse = nSigmaTPC; + pidVectorUpper = pidVectorTPCPtUpper; + pidVectorLower = pidVectorTPCPtLower; + } else { + nSigmaToUse = (candidate.pt() > cfgPtMaxforTPCOnlyPID && candidate.hasTOF()) ? nSigmaCombined : nSigmaTPC; + pidVectorUpper = (candidate.pt() > cfgPtMaxforTPCOnlyPID && candidate.hasTOF()) ? cfgnSigmaCutRMSUpper.value : cfgnSigmaCutTPCUpper.value; + pidVectorLower = (candidate.pt() > cfgPtMaxforTPCOnlyPID && candidate.hasTOF()) ? cfgnSigmaCutRMSLower.value : cfgnSigmaCutTPCLower.value; + } + float nsigma = 9999.99; + // Fill cross pid QA + for (int i = 0; i < 3; ++i) { + if (nSigmaToUse[i] > pidVectorLower[i] && nSigmaToUse[i] < pidVectorUpper[i]) { + if (i == 0) { + kIsPi = true; + if (!cfgQuietMode) { + if (cfgOpenCrossTrackQAPlots) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_nSigmaTPC_cross_Pi"), candidate.itsNSigmaPi(), candidate.tpcNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaITS_cross_Pi"), candidate.tofNSigmaPi(), candidate.itsNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaTPC_cross_Pi"), candidate.tofNSigmaPi(), candidate.tpcNSigmaPi()); + histosQA.fill(HIST("QA/PID/histdEdxTPC_cross_Pi"), candidate.sign() * candidate.tpcInnerParam(), candidate.tpcSignal()); + histosQA.fill(HIST("QA/PID/histnSigma_TOF_cross_Pi"), candidate.tofNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_TOF_Pt_cross_Pi"), candidate.pt(), candidate.tofNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_cross_Pi"), candidate.tpcNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_Pt_cross_Pi"), candidate.pt(), candidate.tpcNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_ITS_cross_Pi"), candidate.itsNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_ITS_Pt_cross_Pi"), candidate.pt(), candidate.itsNSigmaPi()); + if (cfgOpenPlotnSigmaTOFITSPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_ITS_Pt_cross_Pi"), candidate.pt(), candidate.tofNSigmaPi(), candidate.itsNSigmaPi()); + } + if (cfgOpenPlotnSigmaTOFTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_TPC_Pt_cross_Pi"), candidate.pt(), candidate.tofNSigmaPi(), candidate.tpcNSigmaPi()); + } + if (cfgOpenPlotnSigmaITSTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_ITS_TPC_Pt_cross_Pi"), candidate.pt(), candidate.itsNSigmaPi(), candidate.tpcNSigmaPi()); + } + if (cfgOpenPlotAverClus) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_cross_Pi"), averClusSizeCosl); + } + if (cfgOpenPlotAverClusP) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_P_cross_Pi"), candidate.p(), averClusSizeCosl); + } + if (cfgOpenPlotAverClusnSigmaTPC) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_cross_Pi"), candidate.tpcNSigmaPi(), averClusSizeCosl); + } + if (cfgOpenPlotPhiDis) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_cross_Pi"), candidate.phi()); + } + if (cfgOpenPlotPhiDisPtEta) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_Pt_Eta_cross_Pi"), candidate.phi(), candidate.pt(), candidate.eta()); + } + } + } + } + if (i == 1) { + kIsKa = true; + if (!cfgQuietMode) { + if (cfgOpenCrossTrackQAPlots) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_nSigmaTPC_cross_Ka"), candidate.itsNSigmaKa(), candidate.tpcNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaITS_cross_Ka"), candidate.tofNSigmaKa(), candidate.itsNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaTPC_cross_Ka"), candidate.tofNSigmaKa(), candidate.tpcNSigmaKa()); + histosQA.fill(HIST("QA/PID/histdEdxTPC_cross_Ka"), candidate.sign() * candidate.tpcInnerParam(), candidate.tpcSignal()); + histosQA.fill(HIST("QA/PID/histnSigma_TOF_cross_Ka"), candidate.tofNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_TOF_Pt_cross_Ka"), candidate.pt(), candidate.tofNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_cross_Ka"), candidate.tpcNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_Pt_cross_Ka"), candidate.pt(), candidate.tpcNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_ITS_cross_Ka"), candidate.itsNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_ITS_Pt_cross_Ka"), candidate.pt(), candidate.itsNSigmaKa()); + if (cfgOpenPlotnSigmaTOFITSPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_ITS_Pt_cross_Ka"), candidate.pt(), candidate.tofNSigmaKa(), candidate.itsNSigmaKa()); + } + if (cfgOpenPlotnSigmaTOFTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_TPC_Pt_cross_Ka"), candidate.pt(), candidate.tofNSigmaKa(), candidate.tpcNSigmaKa()); + } + if (cfgOpenPlotnSigmaITSTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_ITS_TPC_Pt_cross_Ka"), candidate.pt(), candidate.itsNSigmaKa(), candidate.tpcNSigmaKa()); + } + if (cfgOpenPlotAverClus) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_cross_Ka"), averClusSizeCosl); + } + if (cfgOpenPlotAverClusP) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_P_cross_Ka"), candidate.p(), averClusSizeCosl); + } + if (cfgOpenPlotAverClusnSigmaTPC) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_cross_Ka"), candidate.tpcNSigmaKa(), averClusSizeCosl); + } + if (cfgOpenPlotPhiDis) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_cross_Ka"), candidate.phi()); + } + if (cfgOpenPlotPhiDisPtEta) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_Pt_Eta_cross_Ka"), candidate.phi(), candidate.pt(), candidate.eta()); + } + } + } + } + if (i == 2) { + kIsPr = true; + if (!cfgQuietMode) { + if (cfgOpenCrossTrackQAPlots) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_nSigmaTPC_cross_Pr"), candidate.itsNSigmaPr(), candidate.tpcNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaITS_cross_Pr"), candidate.tofNSigmaPr(), candidate.itsNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaTPC_cross_Pr"), candidate.tofNSigmaPr(), candidate.tpcNSigmaPr()); + histosQA.fill(HIST("QA/PID/histdEdxTPC_cross_Pr"), candidate.sign() * candidate.tpcInnerParam(), candidate.tpcSignal()); + histosQA.fill(HIST("QA/PID/histnSigma_TOF_cross_Pr"), candidate.tofNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_TOF_Pt_cross_Pr"), candidate.pt(), candidate.tofNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_cross_Pr"), candidate.tpcNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_Pt_cross_Pr"), candidate.pt(), candidate.tpcNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_ITS_cross_Pr"), candidate.itsNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_ITS_Pt_cross_Pr"), candidate.pt(), candidate.itsNSigmaPr()); + if (cfgOpenPlotnSigmaTOFITSPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_ITS_Pt_cross_Pr"), candidate.pt(), candidate.tofNSigmaPr(), candidate.itsNSigmaPr()); + } + if (cfgOpenPlotnSigmaTOFTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_TPC_Pt_cross_Pr"), candidate.pt(), candidate.tofNSigmaPr(), candidate.tpcNSigmaPr()); + } + if (cfgOpenPlotnSigmaITSTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_ITS_TPC_Pt_cross_Pr"), candidate.pt(), candidate.itsNSigmaPr(), candidate.tpcNSigmaPr()); + } + if (cfgOpenPlotAverClus) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_cross_Pr"), averClusSizeCosl); + } + if (cfgOpenPlotAverClusP) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_P_cross_Pr"), candidate.p(), averClusSizeCosl); + } + if (cfgOpenPlotAverClusnSigmaTPC) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_cross_Pr"), candidate.tpcNSigmaPr(), averClusSizeCosl); + } + if (cfgOpenPlotPhiDis) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_cross_Pr"), candidate.phi()); + } + if (cfgOpenPlotPhiDisPtEta) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_Pt_Eta_cross_Pr"), candidate.phi(), candidate.pt(), candidate.eta()); + } + } + } + } + } + } + if (cfgOpenAllowCrossTrack) { + // one track can be recognized as different PID particles + int index = (kIsPr << 2) | (kIsKa << 1) | kIsPi; + const int map[] = {0, 1, 2, 7, 3, 8, 9, 10}; + return map[index]; + } else { + // Select particle with the lowest nsigma (If not allow cross track) + for (int i = 0; i < 3; ++i) { + if (std::abs(nSigmaToUse[i]) < nsigma && (nSigmaToUse[i] > pidVectorLower[i] && nSigmaToUse[i] < pidVectorUpper[i])) { + pid = i; + nsigma = std::abs(nSigmaToUse[i]); + } + } + return pid + 1; // shift the pid by 1, 1 = pion, 2 = kaon, 3 = proton + } + // Clear the vectors + std::vector().swap(pidVectorLower); + std::vector().swap(pidVectorUpper); + std::vector().swap(pidVectorTOFPtUpper); + std::vector().swap(pidVectorTPCPtLower); + std::vector().swap(pidVectorTOFPtUpper); + std::vector().swap(pidVectorTPCPtLower); + } + + template + bool selectionITS(const T& candidate, int mode, float avgclssize, std::array nSigmaITSToUseUpper, std::array nSigmaITSToUseLower) + { + switch (mode) { + case 1: // For Pion + if (!((candidate.itsNSigmaPi() > nSigmaITSToUseLower[0] && candidate.itsNSigmaPi() < nSigmaITSToUseUpper[0]) && avgclssize > cfgAveClusSizeCoslMinPi && avgclssize < cfgAveClusSizeCoslMaxPi)) { + return false; + } else { + return true; + } + break; + + case 2: // For Kaon + if (!((candidate.itsNSigmaKa() > nSigmaITSToUseLower[1] && candidate.itsNSigmaKa() < nSigmaITSToUseUpper[1]) && avgclssize > cfgAveClusSizeCoslMinKa && avgclssize < cfgAveClusSizeCoslMaxKa)) { + return false; + } else { + return true; + } + break; + + case 3: // For Proton + if (!((candidate.itsNSigmaPr() > nSigmaITSToUseLower[2] && candidate.itsNSigmaPr() < nSigmaITSToUseUpper[2]) && avgclssize > cfgAveClusSizeCoslMinPr && avgclssize < cfgAveClusSizeCoslMaxPr)) { + return false; + } else { + return true; + } + break; + } + return false; + } + + HistogramRegistry histosQA{"histosQAPID", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext const&) + { + + AxisSpec axisRigidity{cfgrigidityBins, "#it{p}^{TPC}/#it{z}"}; + AxisSpec axisdEdx{cfgdedxBins, "d#it{E}/d#it{x}"}; + AxisSpec axisnSigmaTPC{cfgnSigmaBinsTPC, "n_{#sigma}TPC"}; + AxisSpec axisnSigmaTOF{cfgnSigmaBinsTOF, "n_{#sigma}TOF"}; + AxisSpec axisnSigmaITS{cfgnSigmaBinsITS, "n_{#sigma}ITS"}; + AxisSpec axisnSigmaCom{cfgnSigmaBinsCom, "hypot(n_{#sigma}TPC,TOF)"}; + AxisSpec axisPtPID{cfgaxisptPID, "#it{p}_{T}"}; + AxisSpec axisPPID{cfgaxispPID, "#it{p}"}; + AxisSpec axisEtaPID{cfgaxisetaPID, "#it{#eta}"}; + AxisSpec axisClusterSize{cfgaxisAverClusterCosl, " x "}; + AxisSpec axisClusterSizenSigma{cfgaxisAverClusterCoslnSigma, " x "}; + AxisSpec axisPhi = {100, 0, 2.1 * constants::math::PI, "#phi"}; + AxisSpec axisDCAz{cfgaxisDCAz, "#it{DCA_{z}}"}; + AxisSpec axisDCAxy{cfgaxisDCAxy, "#it{DCA_{xy}}"}; + AxisSpec axisITSNcls = {10, -1.5, 8.5, "ITSNcls"}; + AxisSpec axisTPCNcls = {160, 0, 160, "TPCNcls"}; + AxisSpec axisP{50, -5, 5, "#it{p}"}; + AxisSpec axisChi2Ncls = {cfgaxisChi2Ncls, "#chi^{2}/Ncls"}; + + if (!cfgQuietMode) { + // ITSOnly track check + if (cfgOpenPlotCheckITSOnlytrackInfo) { + histosQA.add(Form("QA/PID/histDCAz_ITSOnly_Px"), "", {HistType::kTH1F, {axisP}}); + histosQA.add(Form("QA/PID/histDCAz_ITSOnly_Py"), "", {HistType::kTH1F, {axisP}}); + histosQA.add(Form("QA/PID/histDCAz_ITSOnly_Pz"), "", {HistType::kTH1F, {axisP}}); + } + // TPCChi2Ncls Checking + if (cfgOpenTrackingInfoCheck) { + histosQA.add(Form("QA/PID/histTPCChi2Ncls_total_origin"), "#chi^{2}/Ncls_{TPC},counts", {HistType::kTH1F, {axisChi2Ncls}}); + histosQA.add(Form("QA/PID/histTPCChi2Ncls_total"), "#chi^{2}/Ncls_{TPC},counts", {HistType::kTH1F, {axisChi2Ncls}}); + histosQA.add(Form("QA/PID/histTPCChi2Ncls_Pi"), "#chi^{2}/Ncls_{TPC},counts", {HistType::kTH1F, {axisChi2Ncls}}); + histosQA.add(Form("QA/PID/histTPCChi2Ncls_Ka"), "#chi^{2}/Ncls_{TPC},counts", {HistType::kTH1F, {axisChi2Ncls}}); + histosQA.add(Form("QA/PID/histTPCChi2Ncls_Pr"), "#chi^{2}/Ncls_{TPC},counts", {HistType::kTH1F, {axisChi2Ncls}}); + if (cfgOpenITSCutQAPlots) { + histosQA.add(Form("QA/PID/histTPCChi2Ncls_total_AfterITS"), ",#chi^{2}/Ncls_{TPC},counts", {HistType::kTH1F, {axisChi2Ncls}}); + histosQA.add(Form("QA/PID/histTPCChi2Ncls_Pi_AfterITS"), "#chi^{2}/Ncls_{TPC},counts", {HistType::kTH1F, {axisChi2Ncls}}); + histosQA.add(Form("QA/PID/histTPCChi2Ncls_Ka_AfterITS"), "#chi^{2}/Ncls_{TPC},counts", {HistType::kTH1F, {axisChi2Ncls}}); + histosQA.add(Form("QA/PID/histTPCChi2Ncls_Pr_AfterITS"), "#chi^{2}/Ncls_{TPC},counts", {HistType::kTH1F, {axisChi2Ncls}}); + } + } + // ITSChi2Ncls Checking + if (cfgOpenTrackingInfoCheck) { + histosQA.add(Form("QA/PID/histITSChi2Ncls_total_origin"), "#chi^{2}/Ncls_{ITS},counts", {HistType::kTH1F, {axisChi2Ncls}}); + histosQA.add(Form("QA/PID/histITSChi2Ncls_total"), "#chi^{2}/Ncls_{ITS},counts", {HistType::kTH1F, {axisChi2Ncls}}); + histosQA.add(Form("QA/PID/histITSChi2Ncls_Pi"), "#chi^{2}/Ncls_{ITS},counts", {HistType::kTH1F, {axisChi2Ncls}}); + histosQA.add(Form("QA/PID/histITSChi2Ncls_Ka"), "#chi^{2}/Ncls_{ITS},counts", {HistType::kTH1F, {axisChi2Ncls}}); + histosQA.add(Form("QA/PID/histITSChi2Ncls_Pr"), "#chi^{2}/Ncls_{ITS},counts", {HistType::kTH1F, {axisChi2Ncls}}); + if (cfgOpenITSCutQAPlots) { + histosQA.add(Form("QA/PID/histITSChi2Ncls_total_AfterITS"), ",#chi^{2}/Ncls_{ITS},counts", {HistType::kTH1F, {axisChi2Ncls}}); + histosQA.add(Form("QA/PID/histITSChi2Ncls_Pi_AfterITS"), "#chi^{2}/Ncls_{ITS},counts", {HistType::kTH1F, {axisChi2Ncls}}); + histosQA.add(Form("QA/PID/histITSChi2Ncls_Ka_AfterITS"), "#chi^{2}/Ncls_{ITS},counts", {HistType::kTH1F, {axisChi2Ncls}}); + histosQA.add(Form("QA/PID/histITSChi2Ncls_Pr_AfterITS"), "#chi^{2}/Ncls_{ITS},counts", {HistType::kTH1F, {axisChi2Ncls}}); + } + } + // DCA Chencks + if (cfgOpenTrackingInfoCheck) { + histosQA.add(Form("QA/PID/histDCAz_total_origin"), "", {HistType::kTH1F, {axisDCAz}}); + histosQA.add(Form("QA/PID/histDCAxy_total_origin"), "", {HistType::kTH1F, {axisDCAxy}}); + histosQA.add(Form("QA/PID/histDCAz_total"), "", {HistType::kTH1F, {axisDCAz}}); + histosQA.add(Form("QA/PID/histDCAxy_total"), "", {HistType::kTH1F, {axisDCAxy}}); + histosQA.add(Form("QA/PID/histDCAz_Pi"), "", {HistType::kTH1F, {axisDCAz}}); + histosQA.add(Form("QA/PID/histDCAxy_Pi"), "", {HistType::kTH1F, {axisDCAxy}}); + histosQA.add(Form("QA/PID/histDCAz_Ka"), "", {HistType::kTH1F, {axisDCAz}}); + histosQA.add(Form("QA/PID/histDCAxy_Ka"), "", {HistType::kTH1F, {axisDCAxy}}); + histosQA.add(Form("QA/PID/histDCAz_Pr"), "", {HistType::kTH1F, {axisDCAz}}); + histosQA.add(Form("QA/PID/histDCAxy_Pr"), "", {HistType::kTH1F, {axisDCAxy}}); + if (cfgOpenITSCutQAPlots) { + histosQA.add(Form("QA/PID/histDCAz_total_AfterITS"), "", {HistType::kTH1F, {axisDCAz}}); + histosQA.add(Form("QA/PID/histDCAxy_total_AfterITS"), "", {HistType::kTH1F, {axisDCAxy}}); + histosQA.add(Form("QA/PID/histDCAz_Pi_AfterITS"), "", {HistType::kTH1F, {axisDCAz}}); + histosQA.add(Form("QA/PID/histDCAxy_Pi_AfterITS"), "", {HistType::kTH1F, {axisDCAxy}}); + histosQA.add(Form("QA/PID/histDCAz_Ka_AfterITS"), "", {HistType::kTH1F, {axisDCAz}}); + histosQA.add(Form("QA/PID/histDCAxy_Ka_AfterITS"), "", {HistType::kTH1F, {axisDCAxy}}); + histosQA.add(Form("QA/PID/histDCAz_Pr_AfterITS"), "", {HistType::kTH1F, {axisDCAz}}); + histosQA.add(Form("QA/PID/histDCAxy_Pr_AfterITS"), "", {HistType::kTH1F, {axisDCAxy}}); + } + } + // ITSNcls Checks + if (cfgOpenTrackingInfoCheck) { + histosQA.add(Form("QA/PID/histITSNcls_total_origin"), "", {HistType::kTH1F, {axisITSNcls}}); + histosQA.add(Form("QA/PID/histITSNcls_total"), "", {HistType::kTH1F, {axisITSNcls}}); + histosQA.add(Form("QA/PID/histITSNcls_Pi"), "", {HistType::kTH1F, {axisITSNcls}}); + histosQA.add(Form("QA/PID/histITSNcls_Ka"), "", {HistType::kTH1F, {axisITSNcls}}); + histosQA.add(Form("QA/PID/histITSNcls_Pr"), "", {HistType::kTH1F, {axisITSNcls}}); + if (cfgOpenITSCutQAPlots) { + histosQA.add(Form("QA/PID/histITSNcls_total_AfterITS"), "", {HistType::kTH1F, {axisITSNcls}}); + histosQA.add(Form("QA/PID/histITSNcls_Pi_AfterITS"), "", {HistType::kTH1F, {axisITSNcls}}); + histosQA.add(Form("QA/PID/histITSNcls_Ka_AfterITS"), "", {HistType::kTH1F, {axisITSNcls}}); + histosQA.add(Form("QA/PID/histITSNcls_Pr_AfterITS"), "", {HistType::kTH1F, {axisITSNcls}}); + } + } + // TPCNcls Checks + if (cfgOpenTrackingInfoCheck) { + histosQA.add(Form("QA/PID/histTPCNcls_total_origin"), "", {HistType::kTH1F, {axisTPCNcls}}); + histosQA.add(Form("QA/PID/histTPCNcls_total"), "", {HistType::kTH1F, {axisTPCNcls}}); + histosQA.add(Form("QA/PID/histTPCNcls_Pi"), "", {HistType::kTH1F, {axisTPCNcls}}); + histosQA.add(Form("QA/PID/histTPCNcls_Ka"), "", {HistType::kTH1F, {axisTPCNcls}}); + histosQA.add(Form("QA/PID/histTPCNcls_Pr"), "", {HistType::kTH1F, {axisTPCNcls}}); + if (cfgOpenITSCutQAPlots) { + histosQA.add(Form("QA/PID/histTPCNcls_total_AfterITS"), "", {HistType::kTH1F, {axisTPCNcls}}); + histosQA.add(Form("QA/PID/histTPCNcls_Pi_AfterITS"), "", {HistType::kTH1F, {axisTPCNcls}}); + histosQA.add(Form("QA/PID/histTPCNcls_Ka_AfterITS"), "", {HistType::kTH1F, {axisTPCNcls}}); + histosQA.add(Form("QA/PID/histTPCNcls_Pr_AfterITS"), "", {HistType::kTH1F, {axisTPCNcls}}); + } + } + // PID Origin plots + if (cfgOpenPlotnSigmaOrigin) { + if (cfgOpenPlotnSigmaTOFITSPt) { + histosQA.add(Form("QA/PID/histnSigma_Origin_TOF_ITS_Pt_Pi"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_TOF_ITS_Pt_Ka"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_TOF_ITS_Pt_Pr"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaITS, axisPtPID}}); + } + if (cfgOpenPlotnSigmaTOFTPCPt) { + histosQA.add(Form("QA/PID/histnSigma_Origin_TOF_TPC_Pt_Pi"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaTPC, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_TOF_TPC_Pt_Ka"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaTPC, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_TOF_TPC_Pt_Pr"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaTPC, axisPtPID}}); + } + if (cfgOpenPlotnSigmaITSTPCPt) { + histosQA.add(Form("QA/PID/histnSigma_Origin_ITS_TPC_Pt_Pi"), "", {HistType::kTH3F, {axisnSigmaITS, axisnSigmaTPC, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_ITS_TPC_Pt_Ka"), "", {HistType::kTH3F, {axisnSigmaITS, axisnSigmaTPC, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_ITS_TPC_Pt_Pr"), "", {HistType::kTH3F, {axisnSigmaITS, axisnSigmaTPC, axisPtPID}}); + } + histosQA.add(Form("QA/PID/histnSigma_Origin_TPC_Pi"), "", {HistType::kTH1F, {axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_TPC_Ka"), "", {HistType::kTH1F, {axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_TPC_Pr"), "", {HistType::kTH1F, {axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_TPC_Pt_Pi"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_TPC_Pt_Ka"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_TPC_Pt_Pr"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_TOF_Pi"), "", {HistType::kTH1F, {axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_TOF_Ka"), "", {HistType::kTH1F, {axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_TOF_Pr"), "", {HistType::kTH1F, {axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_TOF_Pt_Pi"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_TOF_Pt_Ka"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_TOF_Pt_Pr"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_ITS_Pi"), "", {HistType::kTH1F, {axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_ITS_Ka"), "", {HistType::kTH1F, {axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_ITS_Pr"), "", {HistType::kTH1F, {axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_ITS_Pt_Pi"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_ITS_Pt_Ka"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigma_Origin_ITS_Pt_Pr"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaITS}}); + } + // TH3D NSigmaTPC,NSigmaTOF,NSigmaITS combo vs pt(if necessary for whole centrality) + if (cfgOpenPlotnSigmaTOFITSPt) { + histosQA.add(Form("QA/PID/histnSigma_TOF_ITS_Pt_Pi"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_ITS_Pt_Ka"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_ITS_Pt_Pr"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaITS, axisPtPID}}); + if (cfgOpenCrossTrackQAPlots) { + histosQA.add(Form("QA/PID/histnSigma_TOF_ITS_Pt_cross_Pi"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_ITS_Pt_cross_Ka"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_ITS_Pt_cross_Pr"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaITS, axisPtPID}}); + } + if (cfgOpenITSCutQAPlots) { + histosQA.add(Form("QA/PID/histnSigma_TOF_ITS_Pt_AfterITS_Pi"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_ITS_Pt_AfterITS_Ka"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_ITS_Pt_AfterITS_Pr"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaITS, axisPtPID}}); + } + } + if (cfgOpenPlotnSigmaTOFTPCPt) { + histosQA.add(Form("QA/PID/histnSigma_TOF_TPC_Pt_Pi"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaTPC, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_TPC_Pt_Ka"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaTPC, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_TPC_Pt_Pr"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaTPC, axisPtPID}}); + if (cfgOpenCrossTrackQAPlots) { + histosQA.add(Form("QA/PID/histnSigma_TOF_TPC_Pt_cross_Pi"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaTPC, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_TPC_Pt_cross_Ka"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaTPC, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_TPC_Pt_cross_Pr"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaTPC, axisPtPID}}); + } + if (cfgOpenITSCutQAPlots) { + histosQA.add(Form("QA/PID/histnSigma_TOF_TPC_Pt_AfterITS_Pi"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaTPC, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_TPC_Pt_AfterITS_Ka"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaTPC, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_TPC_Pt_AfterITS_Pr"), "", {HistType::kTH3F, {axisnSigmaTOF, axisnSigmaTPC, axisPtPID}}); + } + } + if (cfgOpenPlotnSigmaITSTPCPt) { + histosQA.add(Form("QA/PID/histnSigma_ITS_TPC_Pt_Pi"), "", {HistType::kTH3F, {axisnSigmaITS, axisnSigmaTPC, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_TPC_Pt_Ka"), "", {HistType::kTH3F, {axisnSigmaITS, axisnSigmaTPC, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_TPC_Pt_Pr"), "", {HistType::kTH3F, {axisnSigmaITS, axisnSigmaTPC, axisPtPID}}); + if (cfgOpenCrossTrackQAPlots) { + histosQA.add(Form("QA/PID/histnSigma_ITS_TPC_Pt_cross_Pi"), "", {HistType::kTH3F, {axisnSigmaITS, axisnSigmaTPC, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_TPC_Pt_cross_Ka"), "", {HistType::kTH3F, {axisnSigmaITS, axisnSigmaTPC, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_TPC_Pt_cross_Pr"), "", {HistType::kTH3F, {axisnSigmaITS, axisnSigmaTPC, axisPtPID}}); + } + if (cfgOpenITSCutQAPlots) { + histosQA.add(Form("QA/PID/histnSigma_ITS_TPC_Pt_AfterITS_Pi"), "", {HistType::kTH3F, {axisnSigmaITS, axisnSigmaTPC, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_TPC_Pt_AfterITS_Ka"), "", {HistType::kTH3F, {axisnSigmaITS, axisnSigmaTPC, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_TPC_Pt_AfterITS_Pr"), "", {HistType::kTH3F, {axisnSigmaITS, axisnSigmaTPC, axisPtPID}}); + } + } + if (cfgOpenPlotAverClus) { + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_Pi"), "", {HistType::kTH1F, {axisClusterSize}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_Ka"), "", {HistType::kTH1F, {axisClusterSize}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_Pr"), "", {HistType::kTH1F, {axisClusterSize}}); + if (cfgOpenCrossTrackQAPlots) { + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_cross_Pi"), "", {HistType::kTH1F, {axisClusterSize}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_cross_Ka"), "", {HistType::kTH1F, {axisClusterSize}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_cross_Pr"), "", {HistType::kTH1F, {axisClusterSize}}); + } + if (cfgOpenITSCutQAPlots) { + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_AfterITS_Pi"), "", {HistType::kTH1F, {axisClusterSize}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_AfterITS_Ka"), "", {HistType::kTH1F, {axisClusterSize}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_AfterITS_Pr"), "", {HistType::kTH1F, {axisClusterSize}}); + } + } + if (cfgOpenPlotAverClusP) { + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_P_Pi"), "", {HistType::kTH2F, {axisPPID, axisClusterSize}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_P_Ka"), "", {HistType::kTH2F, {axisPPID, axisClusterSize}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_P_Pr"), "", {HistType::kTH2F, {axisPPID, axisClusterSize}}); + if (cfgOpenCrossTrackQAPlots) { + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_P_cross_Pi"), "", {HistType::kTH2F, {axisPPID, axisClusterSize}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_P_cross_Ka"), "", {HistType::kTH2F, {axisPPID, axisClusterSize}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_P_cross_Pr"), "", {HistType::kTH2F, {axisPPID, axisClusterSize}}); + } + if (cfgOpenITSCutQAPlots) { + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_P_AfterITS_Pi"), "", {HistType::kTH2F, {axisPPID, axisClusterSize}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_P_AfterITS_Ka"), "", {HistType::kTH2F, {axisPPID, axisClusterSize}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_P_AfterITS_Pr"), "", {HistType::kTH2F, {axisPPID, axisClusterSize}}); + } + } + if (cfgOpenPlotAverClusnSigmaTPC) { + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pi"), "", {HistType::kTH2F, {axisnSigmaTPC, axisClusterSizenSigma}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Ka"), "", {HistType::kTH2F, {axisnSigmaTPC, axisClusterSizenSigma}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pr"), "", {HistType::kTH2F, {axisnSigmaTPC, axisClusterSizenSigma}}); + if (cfgOpenCrossTrackQAPlots) { + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_cross_Pi"), "", {HistType::kTH2F, {axisnSigmaTPC, axisClusterSizenSigma}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_cross_Ka"), "", {HistType::kTH2F, {axisnSigmaTPC, axisClusterSizenSigma}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_cross_Pr"), "", {HistType::kTH2F, {axisnSigmaTPC, axisClusterSizenSigma}}); + } + if (cfgOpenITSCutQAPlots) { + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_AfterITS_Pi"), "", {HistType::kTH2F, {axisnSigmaTPC, axisClusterSizenSigma}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_AfterITS_Ka"), "", {HistType::kTH2F, {axisnSigmaTPC, axisClusterSizenSigma}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_AfterITS_Pr"), "", {HistType::kTH2F, {axisnSigmaTPC, axisClusterSizenSigma}}); + } + } + if (cfgOpenPlotPhiDis) { + histosQA.add(Form("QA/PID/histPhi_Dis_Pi"), "", {HistType::kTH1F, {axisPhi}}); + histosQA.add(Form("QA/PID/histPhi_Dis_Ka"), "", {HistType::kTH1F, {axisPhi}}); + histosQA.add(Form("QA/PID/histPhi_Dis_Pr"), "", {HistType::kTH1F, {axisPhi}}); + if (cfgOpenCrossTrackQAPlots) { + histosQA.add(Form("QA/PID/histPhi_Dis_cross_Pi"), "", {HistType::kTH1F, {axisPhi}}); + histosQA.add(Form("QA/PID/histPhi_Dis_cross_Ka"), "", {HistType::kTH1F, {axisPhi}}); + histosQA.add(Form("QA/PID/histPhi_Dis_cross_Pr"), "", {HistType::kTH1F, {axisPhi}}); + } + if (cfgOpenITSCutQAPlots) { + histosQA.add(Form("QA/PID/histPhi_Dis_AfterITS_Pi"), "", {HistType::kTH1F, {axisPhi}}); + histosQA.add(Form("QA/PID/histPhi_Dis_AfterITS_Ka"), "", {HistType::kTH1F, {axisPhi}}); + histosQA.add(Form("QA/PID/histPhi_Dis_AfterITS_Pr"), "", {HistType::kTH1F, {axisPhi}}); + } + } + if (cfgOpenPlotPhiDisPtEta) { + histosQA.add(Form("QA/PID/histPhi_Dis_Pt_Eta_Pi"), "", {HistType::kTH3F, {axisPhi, axisPtPID, axisEtaPID}}); + histosQA.add(Form("QA/PID/histPhi_Dis_Pt_Eta_Ka"), "", {HistType::kTH3F, {axisPhi, axisPtPID, axisEtaPID}}); + histosQA.add(Form("QA/PID/histPhi_Dis_Pt_Eta_Pr"), "", {HistType::kTH3F, {axisPhi, axisPtPID, axisEtaPID}}); + if (cfgOpenCrossTrackQAPlots) { + histosQA.add(Form("QA/PID/histPhi_Dis_Pt_Eta_cross_Pi"), "", {HistType::kTH3F, {axisPhi, axisPtPID, axisEtaPID}}); + histosQA.add(Form("QA/PID/histPhi_Dis_Pt_Eta_cross_Ka"), "", {HistType::kTH3F, {axisPhi, axisPtPID, axisEtaPID}}); + histosQA.add(Form("QA/PID/histPhi_Dis_Pt_Eta_cross_Pr"), "", {HistType::kTH3F, {axisPhi, axisPtPID, axisEtaPID}}); + } + if (cfgOpenITSCutQAPlots) { + histosQA.add(Form("QA/PID/histPhi_Dis_Pt_Eta_AfterITS_Pi"), "", {HistType::kTH3F, {axisPhi, axisPtPID, axisEtaPID}}); + histosQA.add(Form("QA/PID/histPhi_Dis_Pt_Eta_AfterITS_Ka"), "", {HistType::kTH3F, {axisPhi, axisPtPID, axisEtaPID}}); + histosQA.add(Form("QA/PID/histPhi_Dis_Pt_Eta_AfterITS_Pr"), "", {HistType::kTH3F, {axisPhi, axisPtPID, axisEtaPID}}); + } + } + // some basic plots should be ploted (except for the quite mode) + // nSigma TPC TOF ITS combo plots + histosQA.add(Form("QA/PID/histnSigmaITS_nSigmaTPC_Pi"), "", {HistType::kTH2F, {axisnSigmaITS, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigmaITS_nSigmaTPC_Ka"), "", {HistType::kTH2F, {axisnSigmaITS, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigmaITS_nSigmaTPC_Pr"), "", {HistType::kTH2F, {axisnSigmaITS, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaITS_Pi"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaITS_Ka"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaITS_Pr"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaTPC_Pi"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaTPC_Ka"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaTPC_Pr"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaTPC}}); + if (cfgOpenCrossTrackQAPlots) { + histosQA.add(Form("QA/PID/histnSigmaITS_nSigmaTPC_cross_Pi"), "", {HistType::kTH2F, {axisnSigmaITS, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigmaITS_nSigmaTPC_cross_Ka"), "", {HistType::kTH2F, {axisnSigmaITS, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigmaITS_nSigmaTPC_cross_Pr"), "", {HistType::kTH2F, {axisnSigmaITS, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaITS_cross_Pi"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaITS_cross_Ka"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaITS_cross_Pr"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaTPC_cross_Pi"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaTPC_cross_Ka"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaTPC_cross_Pr"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaTPC}}); + } + if (cfgOpenITSCutQAPlots) { + histosQA.add(Form("QA/PID/histnSigmaITS_nSigmaTPC_AfterITS_Pi"), "", {HistType::kTH2F, {axisnSigmaITS, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigmaITS_nSigmaTPC_AfterITS_Ka"), "", {HistType::kTH2F, {axisnSigmaITS, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigmaITS_nSigmaTPC_AfterITS_Pr"), "", {HistType::kTH2F, {axisnSigmaITS, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaITS_AfterITS_Pi"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaITS_AfterITS_Ka"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaITS_AfterITS_Pr"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaTPC_AfterITS_Pi"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaTPC_AfterITS_Ka"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigmaTOF_nSigmaTPC_AfterITS_Pr"), "", {HistType::kTH2F, {axisnSigmaTOF, axisnSigmaTPC}}); + } + // nSigma TPC TOF ITS signle and some simple QA plots + histosQA.add(Form("QA/PID/histdEdxTPC_All"), "", {HistType::kTH2F, {axisRigidity, axisdEdx}}); + histosQA.add(Form("QA/PID/histdEdxTPC_Pi"), "", {HistType::kTH2F, {axisRigidity, axisdEdx}}); + histosQA.add(Form("QA/PID/histdEdxTPC_Ka"), "", {HistType::kTH2F, {axisRigidity, axisdEdx}}); + histosQA.add(Form("QA/PID/histdEdxTPC_Pr"), "", {HistType::kTH2F, {axisRigidity, axisdEdx}}); + histosQA.add(Form("QA/PID/histnSigma_TPC_Pi"), "", {HistType::kTH1F, {axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_TPC_Ka"), "", {HistType::kTH1F, {axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_TPC_Pr"), "", {HistType::kTH1F, {axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_TPC_Pt_Pi"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_TPC_Pt_Ka"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_TPC_Pt_Pr"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_com_Pi"), "", {HistType::kTH1F, {axisnSigmaCom}}); + histosQA.add(Form("QA/PID/histnSigma_com_Ka"), "", {HistType::kTH1F, {axisnSigmaCom}}); + histosQA.add(Form("QA/PID/histnSigma_com_Pr"), "", {HistType::kTH1F, {axisnSigmaCom}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_Pi"), "", {HistType::kTH1F, {axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_Ka"), "", {HistType::kTH1F, {axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_Pr"), "", {HistType::kTH1F, {axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_Pt_Pi"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_Pt_Ka"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_Pt_Pr"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_Pi"), "", {HistType::kTH1F, {axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_Ka"), "", {HistType::kTH1F, {axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_Pr"), "", {HistType::kTH1F, {axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_Pt_Pi"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_Pt_Ka"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_Pt_Pr"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaITS}}); + if (cfgOpenCrossTrackQAPlots) { + histosQA.add(Form("QA/PID/histdEdxTPC_cross_Pi"), "", {HistType::kTH2F, {axisRigidity, axisdEdx}}); + histosQA.add(Form("QA/PID/histdEdxTPC_cross_Ka"), "", {HistType::kTH2F, {axisRigidity, axisdEdx}}); + histosQA.add(Form("QA/PID/histdEdxTPC_cross_Pr"), "", {HistType::kTH2F, {axisRigidity, axisdEdx}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_cross_Pi"), "", {HistType::kTH1F, {axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_cross_Ka"), "", {HistType::kTH1F, {axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_cross_Pr"), "", {HistType::kTH1F, {axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_Pt_cross_Pi"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_Pt_cross_Ka"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_Pt_cross_Pr"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_cross_Pi"), "", {HistType::kTH1F, {axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_cross_Ka"), "", {HistType::kTH1F, {axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_cross_Pr"), "", {HistType::kTH1F, {axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_Pt_cross_Pi"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_Pt_cross_Ka"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_Pt_cross_Pr"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_cross_Pi"), "", {HistType::kTH1F, {axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_cross_Ka"), "", {HistType::kTH1F, {axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_cross_Pr"), "", {HistType::kTH1F, {axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_Pt_cross_Pi"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_Pt_cross_Ka"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_Pt_cross_Pr"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaITS}}); + } + if (cfgOpenITSCutQAPlots) { + histosQA.add(Form("QA/PID/histnSigma_TOF_Pt_AfterITS_Pi"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_Pt_AfterITS_Ka"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_TOF_Pt_AfterITS_Pr"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTOF}}); + histosQA.add(Form("QA/PID/histnSigma_TPC_Pt_AfterITS_Pi"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_TPC_Pt_AfterITS_Ka"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_TPC_Pt_AfterITS_Pr"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaTPC}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_Pt_AfterITS_Pi"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_Pt_AfterITS_Ka"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaITS}}); + histosQA.add(Form("QA/PID/histnSigma_ITS_Pt_AfterITS_Pr"), "", {HistType::kTH2F, {axisPtPID, axisnSigmaITS}}); + } + // plots for TPC-ITS contamination (whole centrality) + if (cfgOpenDetailPlotsTPCITSContaimination) { + histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_PosPi_Before"), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_PosKa_Before"), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_PosPr_Before"), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_NegPi_Before"), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_NegKa_Before"), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_NegPr_Before"), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_PosPi_Before"), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisClusterSizenSigma, axisPtPID}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_PosKa_Before"), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisClusterSizenSigma, axisPtPID}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_PosPr_Before"), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisClusterSizenSigma, axisPtPID}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_NegPi_Before"), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisClusterSizenSigma, axisPtPID}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_NegKa_Before"), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisClusterSizenSigma, axisPtPID}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_NegPr_Before"), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisClusterSizenSigma, axisPtPID}}); + if (cfgOpenITSCutQAPlots) { + histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_PosPi_After"), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_PosKa_After"), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_PosPr_After"), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_NegPi_After"), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_NegKa_After"), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_NegPr_After"), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisnSigmaITS, axisPtPID}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSIgmaTPC_Pt_PosPi_After"), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisClusterSizenSigma, axisPtPID}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSIgmaTPC_Pt_PosKa_After"), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisClusterSizenSigma, axisPtPID}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSIgmaTPC_Pt_PosPr_After"), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisClusterSizenSigma, axisPtPID}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSIgmaTPC_Pt_NegPi_After"), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisClusterSizenSigma, axisPtPID}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSIgmaTPC_Pt_NegKa_After"), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisClusterSizenSigma, axisPtPID}}); + histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSIgmaTPC_Pt_NegPr_After"), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {axisnSigmaTPC, axisClusterSizenSigma, axisPtPID}}); + } + } + } + } + Produces pidCmeTable; + Produces pidInfoTable; + void process(TracksPID const& tracks) + { + auto tracksWithITSPid = soa::Attach(tracks); + int8_t pidFlag; + for (const auto& track : tracksWithITSPid) { + // Fill the original plots first + if (!cfgQuietMode) { + if (cfgOpenTrackingInfoCheck) { + histosQA.fill(HIST("QA/PID/histDCAz_total_origin"), track.dcaZ()); + histosQA.fill(HIST("QA/PID/histDCAxy_total_origin"), track.dcaXY()); + histosQA.fill(HIST("QA/PID/histTPCNcls_total_origin"), track.tpcNClsFound()); + histosQA.fill(HIST("QA/PID/histITSNcls_total_origin"), track.itsNCls()); + histosQA.fill(HIST("QA/PID/histTPCChi2Ncls_total_origin"), track.tpcChi2NCl()); + histosQA.fill(HIST("QA/PID/histITSChi2Ncls_total_origin"), track.itsChi2NCl()); + } + if (cfgOpenPlotCheckITSOnlytrackInfo && track.tpcNClsFound() == 0) { + histosQA.fill(HIST("QA/PID/histDCAz_ITSOnly_Px"), track.px()); + histosQA.fill(HIST("QA/PID/histDCAz_ITSOnly_Py"), track.py()); + histosQA.fill(HIST("QA/PID/histDCAz_ITSOnly_Pz"), track.pz()); + } + if (cfgOpenPlotnSigmaOrigin) { + if (cfgOpenPlotnSigmaTOFITSPt) { + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TOF_ITS_Pt_Pi"), track.tofNSigmaPi(), track.itsNSigmaPi(), track.pt()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TOF_ITS_Pt_Ka"), track.tofNSigmaKa(), track.itsNSigmaKa(), track.pt()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TOF_ITS_Pt_Pr"), track.tofNSigmaPr(), track.itsNSigmaPr(), track.pt()); + } + if (cfgOpenPlotnSigmaTOFTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TOF_TPC_Pt_Pi"), track.tofNSigmaPi(), track.tpcNSigmaPi(), track.pt()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TOF_TPC_Pt_Ka"), track.tofNSigmaKa(), track.tpcNSigmaKa(), track.pt()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TOF_TPC_Pt_Pr"), track.tofNSigmaPr(), track.tpcNSigmaPr(), track.pt()); + } + if (cfgOpenPlotnSigmaITSTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_Origin_ITS_TPC_Pt_Pi"), track.itsNSigmaPi(), track.tpcNSigmaPi(), track.pt()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_ITS_TPC_Pt_Ka"), track.itsNSigmaKa(), track.tpcNSigmaKa(), track.pt()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_ITS_TPC_Pt_Pr"), track.itsNSigmaPr(), track.tpcNSigmaPr(), track.pt()); + } + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TPC_Pi"), track.tpcNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TPC_Ka"), track.tpcNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TPC_Pr"), track.tpcNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TOF_Pi"), track.tofNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TOF_Ka"), track.tofNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TOF_Pr"), track.tofNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_ITS_Pi"), track.itsNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_ITS_Ka"), track.itsNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_ITS_Pr"), track.itsNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TPC_Pt_Pi"), track.pt(), track.tpcNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TPC_Pt_Ka"), track.pt(), track.tpcNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TPC_Pt_Pr"), track.pt(), track.tpcNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TOF_Pt_Pi"), track.pt(), track.tofNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TOF_Pt_Ka"), track.pt(), track.tofNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_TOF_Pt_Pr"), track.pt(), track.tofNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_ITS_Pt_Pi"), track.pt(), track.itsNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_ITS_Pt_Ka"), track.pt(), track.itsNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_Origin_ITS_Pt_Pr"), track.pt(), track.itsNSigmaPr()); + } + } + int currentPtBinPi = -1, currentPtBinKa = -1, currentPtBinPr = -1; + if (cfgOpenPtRangedTOFnSigmacutPi || cfgOpenPtRangedTPCnSigmacutPi || cfgOpenPtRangedITSnSigmacutPi) { + for (int i = 0; i < static_cast(cfgPtBinPionPID.value.size()) - 1; ++i) { + if (track.pt() >= cfgPtBinPionPID.value[i] && track.pt() < cfgPtBinPionPID.value[i + 1]) { + currentPtBinPi = i; + break; + } + } + } + if (cfgOpenPtRangedTOFnSigmacutKa || cfgOpenPtRangedTPCnSigmacutKa || cfgOpenPtRangedITSnSigmacutKa) { + for (int i = 0; i < static_cast(cfgPtBinKaonPID.value.size()) - 1; ++i) { + if (track.pt() >= cfgPtBinKaonPID.value[i] && track.pt() < cfgPtBinKaonPID.value[i + 1]) { + currentPtBinKa = i; + break; + } + } + } + if (cfgOpenPtRangedTOFnSigmacutPr || cfgOpenPtRangedTPCnSigmacutPr || cfgOpenPtRangedITSnSigmacutPr) { + for (int i = 0; i < static_cast(cfgPtBinProtonPID.value.size()) - 1; ++i) { + if (track.pt() >= cfgPtBinProtonPID.value[i] && track.pt() < cfgPtBinProtonPID.value[i + 1]) { + currentPtBinPr = i; + break; + } + } + } + float nSigmaTOFCutPiPtUpper = (currentPtBinPi == -1) ? cfgnSigmaCutTOFUpper.value[0] : cfgnSigmaTOFPionPtUpper.value[currentPtBinPi]; + float nSigmaTOFCutKaPtUpper = (currentPtBinKa == -1) ? cfgnSigmaCutTOFUpper.value[1] : cfgnSigmaTOFKaonPtUpper.value[currentPtBinKa]; + float nSigmaTOFCutPrPtUpper = (currentPtBinPr == -1) ? cfgnSigmaCutTOFUpper.value[2] : cfgnSigmaTOFProtonPtUpper.value[currentPtBinPr]; + float nSigmaTPCCutPiPtUpper = (currentPtBinPi == -1) ? cfgnSigmaCutTPCUpper.value[0] : cfgnSigmaTPCPionPtUpper.value[currentPtBinPi]; + float nSigmaTPCCutKaPtUpper = (currentPtBinKa == -1) ? cfgnSigmaCutTPCUpper.value[1] : cfgnSigmaTPCKaonPtUpper.value[currentPtBinKa]; + float nSigmaTPCCutPrPtUpper = (currentPtBinPr == -1) ? cfgnSigmaCutTPCUpper.value[2] : cfgnSigmaTPCProtonPtUpper.value[currentPtBinPr]; + float nSigmaTOFCutPiPtLower = (currentPtBinPi == -1) ? cfgnSigmaCutTOFLower.value[0] : cfgnSigmaTOFPionPtLower.value[currentPtBinPi]; + float nSigmaTOFCutKaPtLower = (currentPtBinKa == -1) ? cfgnSigmaCutTOFLower.value[1] : cfgnSigmaTOFKaonPtLower.value[currentPtBinKa]; + float nSigmaTOFCutPrPtLower = (currentPtBinPr == -1) ? cfgnSigmaCutTOFLower.value[2] : cfgnSigmaTOFProtonPtLower.value[currentPtBinPr]; + float nSigmaTPCCutPiPtLower = (currentPtBinPi == -1) ? cfgnSigmaCutTPCLower.value[0] : cfgnSigmaTPCPionPtLower.value[currentPtBinPi]; + float nSigmaTPCCutKaPtLower = (currentPtBinKa == -1) ? cfgnSigmaCutTPCLower.value[1] : cfgnSigmaTPCKaonPtLower.value[currentPtBinKa]; + float nSigmaTPCCutPrPtLower = (currentPtBinPr == -1) ? cfgnSigmaCutTPCLower.value[2] : cfgnSigmaTPCProtonPtLower.value[currentPtBinPr]; + float nSigmaITSCutPiPtUpper = (currentPtBinPi == -1) ? cfgnSigmaCutITSUpper.value[0] : cfgnSigmaITSPionPtUpper.value[currentPtBinPi]; + float nSigmaITSCutKaPtUpper = (currentPtBinKa == -1) ? cfgnSigmaCutITSUpper.value[1] : cfgnSigmaITSKaonPtUpper.value[currentPtBinKa]; + float nSigmaITSCutPrPtUpper = (currentPtBinPr == -1) ? cfgnSigmaCutITSUpper.value[2] : cfgnSigmaITSProtonPtUpper.value[currentPtBinPr]; + float nSigmaITSCutPiPtLower = (currentPtBinPi == -1) ? cfgnSigmaCutITSLower.value[0] : cfgnSigmaITSPionPtLower.value[currentPtBinPi]; + float nSigmaITSCutKaPtLower = (currentPtBinKa == -1) ? cfgnSigmaCutITSLower.value[1] : cfgnSigmaITSKaonPtLower.value[currentPtBinKa]; + float nSigmaITSCutPrPtLower = (currentPtBinPr == -1) ? cfgnSigmaCutITSLower.value[2] : cfgnSigmaITSProtonPtLower.value[currentPtBinPr]; + std::array nSigmaTOFCutPtUpper = {nSigmaTOFCutPiPtUpper, nSigmaTOFCutKaPtUpper, nSigmaTOFCutPrPtUpper}; + std::array nSigmaTPCCutPtUpper = {nSigmaTPCCutPiPtUpper, nSigmaTPCCutKaPtUpper, nSigmaTPCCutPrPtUpper}; + std::array nSigmaTOFCutPtLower = {nSigmaTOFCutPiPtLower, nSigmaTOFCutKaPtLower, nSigmaTOFCutPrPtLower}; + std::array nSigmaTPCCutPtLower = {nSigmaTPCCutPiPtLower, nSigmaTPCCutKaPtLower, nSigmaTPCCutPrPtLower}; + std::array nSigmaITSCutPtUpper = {nSigmaITSCutPiPtUpper, nSigmaITSCutKaPtUpper, nSigmaITSCutPrPtUpper}; + std::array nSigmaITSCutPtLower = {nSigmaITSCutPiPtLower, nSigmaITSCutKaPtLower, nSigmaITSCutPrPtLower}; + const float averClusSizeCosl = averageClusterSizeCosl(track.itsClusterSizes(), track.eta()); + if (!selTrackPid(track)) { + pidFlag = -1; + } else { + if (!cfgQuietMode) { + histosQA.fill(HIST("QA/PID/histdEdxTPC_All"), track.sign() * track.tpcInnerParam(), track.tpcSignal()); + if (cfgOpenTrackingInfoCheck) { + histosQA.fill(HIST("QA/PID/histDCAz_total"), track.dcaZ()); + histosQA.fill(HIST("QA/PID/histDCAxy_total"), track.dcaXY()); + histosQA.fill(HIST("QA/PID/histITSNcls_total"), track.itsNCls()); + histosQA.fill(HIST("QA/PID/histTPCNcls_total"), track.tpcNClsFound()); + histosQA.fill(HIST("QA/PID/histTPCChi2Ncls_total"), track.tpcChi2NCl()); + histosQA.fill(HIST("QA/PID/histITSChi2Ncls_total"), track.itsChi2NCl()); + } + } + pidFlag = selectionPidtpctof(track, nSigmaTOFCutPtUpper, nSigmaTOFCutPtLower, nSigmaTPCCutPtUpper, nSigmaTPCCutPtLower); + if (!(pidFlag == 0 || pidFlag == -1)) { + // First fill ITS uncut plots + if ((pidFlag == 1) || (pidFlag == 7) || (pidFlag == 8) || (pidFlag == 10)) { + if (cfgOpenTPCAssistanceTOFOnlyPID && !(track.tpcNSigmaPi() > nSigmaTPCCutPiPtLower && track.tpcNSigmaPi() < nSigmaTPCCutPiPtUpper)) { + pidFlag = 0; + } + if (cfgOpenPIDPtSelection && !(track.pt() > cfgPtCutLower.value[0] && track.pt() < cfgPtCutUpper.value[0])) { + pidFlag = 0; + } + if (!(cfgQuietMode || pidFlag == 0)) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_nSigmaTPC_Pi"), track.itsNSigmaPi(), track.tpcNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaITS_Pi"), track.tofNSigmaPi(), track.itsNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaTPC_Pi"), track.tofNSigmaPi(), track.tpcNSigmaPi()); + histosQA.fill(HIST("QA/PID/histdEdxTPC_Pi"), track.sign() * track.tpcInnerParam(), track.tpcSignal()); + histosQA.fill(HIST("QA/PID/histnSigma_TPC_Pi"), track.tpcNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_TPC_Pt_Pi"), track.pt(), track.tpcNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_com_Pi"), std::hypot(track.tpcNSigmaPi(), track.tofNSigmaPi())); + histosQA.fill(HIST("QA/PID/histnSigma_TOF_Pi"), track.tofNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_TOF_Pt_Pi"), track.pt(), track.tofNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_ITS_Pi"), track.itsNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_ITS_Pt_Pi"), track.pt(), track.itsNSigmaPi()); + if (cfgOpenTrackingInfoCheck) { + histosQA.fill(HIST("QA/PID/histDCAz_Pi"), track.dcaZ()); + histosQA.fill(HIST("QA/PID/histDCAxy_Pi"), track.dcaXY()); + histosQA.fill(HIST("QA/PID/histITSNcls_Pi"), track.itsNCls()); + histosQA.fill(HIST("QA/PID/histTPCNcls_Pi"), track.tpcNClsFound()); + histosQA.fill(HIST("QA/PID/histTPCChi2Ncls_Pi"), track.tpcChi2NCl()); + histosQA.fill(HIST("QA/PID/histITSChi2Ncls_Pi"), track.itsChi2NCl()); + } + if (cfgOpenPlotnSigmaTOFITSPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_ITS_Pt_Pi"), track.tofNSigmaPi(), track.itsNSigmaPi(), track.pt()); + } + if (cfgOpenPlotnSigmaTOFTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_TPC_Pt_Pi"), track.tofNSigmaPi(), track.tpcNSigmaPi(), track.pt()); + } + if (cfgOpenPlotnSigmaITSTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_ITS_TPC_Pt_Pi"), track.itsNSigmaPi(), track.tpcNSigmaPi(), track.pt()); + } + if (cfgOpenPlotAverClus) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_Pi"), averClusSizeCosl); + } + if (cfgOpenPlotAverClusP) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_P_Pi"), track.p(), averClusSizeCosl); + } + if (cfgOpenPlotAverClusnSigmaTPC) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pi"), track.tpcNSigmaPi(), averClusSizeCosl); + } + if (cfgOpenPlotPhiDis) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_Pi"), track.phi()); + } + if (cfgOpenPlotPhiDisPtEta) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_Pt_Eta_Pi"), track.phi(), track.pt(), track.eta()); + } + if (cfgOpenDetailPlotsTPCITSContaimination) { + if (track.sign() > 0) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_TPC_Pt_PosPi_Before"), track.tpcNSigmaPi(), track.itsNSigmaPi(), track.pt()); + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_PosPi_Before"), track.tpcNSigmaPi(), averClusSizeCosl, track.pt()); + } else if (track.sign() < 0) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_TPC_Pt_NegPi_Before"), track.tpcNSigmaPi(), track.itsNSigmaPi(), track.pt()); + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_NegPi_Before"), track.tpcNSigmaPi(), averClusSizeCosl, track.pt()); + } + } + } + } + if ((pidFlag == 2) || (pidFlag == 7) || (pidFlag == 9) || (pidFlag == 10)) { + if (cfgOpenTPCAssistanceTOFOnlyPID && !(track.tpcNSigmaKa() > nSigmaTPCCutKaPtLower && track.tpcNSigmaKa() < nSigmaTPCCutKaPtUpper)) { + pidFlag = 0; + } + if (cfgOpenPIDPtSelection && !(track.pt() > cfgPtCutLower.value[1] && track.pt() < cfgPtCutUpper.value[1])) { + pidFlag = 0; + } + if (!(cfgQuietMode || pidFlag == 0)) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_nSigmaTPC_Ka"), track.itsNSigmaKa(), track.tpcNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaITS_Ka"), track.tofNSigmaKa(), track.itsNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaTPC_Ka"), track.tofNSigmaKa(), track.tpcNSigmaKa()); + histosQA.fill(HIST("QA/PID/histdEdxTPC_Ka"), track.sign() * track.tpcInnerParam(), track.tpcSignal()); + histosQA.fill(HIST("QA/PID/histnSigma_TPC_Ka"), track.tpcNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_TPC_Pt_Ka"), track.pt(), track.tpcNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_com_Ka"), std::hypot(track.tpcNSigmaKa(), track.tofNSigmaKa())); + histosQA.fill(HIST("QA/PID/histnSigma_TOF_Ka"), track.tofNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_TOF_Pt_Ka"), track.pt(), track.tofNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_ITS_Ka"), track.itsNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_ITS_Pt_Ka"), track.pt(), track.itsNSigmaKa()); + if (cfgOpenTrackingInfoCheck) { + histosQA.fill(HIST("QA/PID/histDCAz_Ka"), track.dcaZ()); + histosQA.fill(HIST("QA/PID/histDCAxy_Ka"), track.dcaXY()); + histosQA.fill(HIST("QA/PID/histITSNcls_Ka"), track.itsNCls()); + histosQA.fill(HIST("QA/PID/histTPCNcls_Ka"), track.tpcNClsFound()); + histosQA.fill(HIST("QA/PID/histTPCChi2Ncls_Ka"), track.tpcChi2NCl()); + histosQA.fill(HIST("QA/PID/histITSChi2Ncls_Ka"), track.itsChi2NCl()); + } + if (cfgOpenPlotnSigmaTOFITSPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_ITS_Pt_Ka"), track.tofNSigmaKa(), track.itsNSigmaKa(), track.pt()); + } + if (cfgOpenPlotnSigmaTOFTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_TPC_Pt_Ka"), track.tofNSigmaKa(), track.tpcNSigmaKa(), track.pt()); + } + if (cfgOpenPlotnSigmaITSTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_ITS_TPC_Pt_Ka"), track.itsNSigmaKa(), track.tpcNSigmaKa(), track.pt()); + } + if (cfgOpenPlotAverClus) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_Ka"), averClusSizeCosl); + } + if (cfgOpenPlotAverClusP) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_P_Ka"), track.p(), averClusSizeCosl); + } + if (cfgOpenPlotAverClusnSigmaTPC) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Ka"), track.tpcNSigmaKa(), averClusSizeCosl); + } + if (cfgOpenPlotPhiDis) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_Ka"), track.phi()); + } + if (cfgOpenPlotPhiDisPtEta) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_Pt_Eta_Ka"), track.phi(), track.pt(), track.eta()); + } + if (cfgOpenDetailPlotsTPCITSContaimination) { + if (track.sign() > 0) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_TPC_Pt_PosKa_Before"), track.tpcNSigmaKa(), track.itsNSigmaKa(), track.pt()); + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_PosKa_Before"), track.tpcNSigmaKa(), averClusSizeCosl, track.pt()); + } else if (track.sign() < 0) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_TPC_Pt_NegKa_Before"), track.tpcNSigmaKa(), track.itsNSigmaKa(), track.pt()); + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_NegKa_Before"), track.tpcNSigmaKa(), averClusSizeCosl, track.pt()); + } + } + } + } + if ((pidFlag == 3) || (pidFlag == 8) || (pidFlag == 9) || (pidFlag == 10)) { + if (cfgOpenTPCAssistanceTOFOnlyPID && !(track.tpcNSigmaPr() > nSigmaTPCCutPrPtLower && track.tpcNSigmaPr() < nSigmaTPCCutPrPtUpper)) { + pidFlag = 0; + } + if (cfgOpenPIDPtSelection && !(track.pt() > cfgPtCutLower.value[2] && track.pt() < cfgPtCutUpper.value[2])) { + pidFlag = 0; + } + if (!(cfgQuietMode || pidFlag == 0)) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_nSigmaTPC_Pr"), track.itsNSigmaPr(), track.tpcNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaITS_Pr"), track.tofNSigmaPr(), track.itsNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaTPC_Pr"), track.tofNSigmaPr(), track.tpcNSigmaPr()); + histosQA.fill(HIST("QA/PID/histdEdxTPC_Pr"), track.sign() * track.tpcInnerParam(), track.tpcSignal()); + histosQA.fill(HIST("QA/PID/histnSigma_TPC_Pr"), track.tpcNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_TPC_Pt_Pr"), track.pt(), track.tpcNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_com_Pr"), std::hypot(track.tpcNSigmaPr(), track.tofNSigmaPr())); + histosQA.fill(HIST("QA/PID/histnSigma_TOF_Pr"), track.tofNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_TOF_Pt_Pr"), track.pt(), track.tofNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_ITS_Pr"), track.itsNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_ITS_Pt_Pr"), track.pt(), track.itsNSigmaPr()); + if (cfgOpenTrackingInfoCheck) { + histosQA.fill(HIST("QA/PID/histDCAz_Pr"), track.dcaZ()); + histosQA.fill(HIST("QA/PID/histDCAxy_Pr"), track.dcaXY()); + histosQA.fill(HIST("QA/PID/histITSNcls_Pr"), track.itsNCls()); + histosQA.fill(HIST("QA/PID/histTPCNcls_Pr"), track.tpcNClsFound()); + histosQA.fill(HIST("QA/PID/histTPCChi2Ncls_Pr"), track.tpcChi2NCl()); + histosQA.fill(HIST("QA/PID/histITSChi2Ncls_Pr"), track.itsChi2NCl()); + } + if (cfgOpenPlotnSigmaTOFITSPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_ITS_Pt_Pr"), track.tofNSigmaPr(), track.itsNSigmaPr(), track.pt()); + } + if (cfgOpenPlotnSigmaTOFTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_TPC_Pt_Pr"), track.tofNSigmaPr(), track.tpcNSigmaPr(), track.pt()); + } + if (cfgOpenPlotnSigmaITSTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_ITS_TPC_Pt_Pr"), track.itsNSigmaPr(), track.tpcNSigmaPr(), track.pt()); + } + if (cfgOpenPlotAverClus) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_Pr"), averClusSizeCosl); + } + if (cfgOpenPlotAverClusP) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_P_Pr"), track.p(), averClusSizeCosl); + } + if (cfgOpenPlotAverClusnSigmaTPC) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pr"), track.tpcNSigmaPr(), averClusSizeCosl); + } + if (cfgOpenPlotPhiDis) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_Pr"), track.phi()); + } + if (cfgOpenPlotPhiDisPtEta) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_Pt_Eta_Pr"), track.phi(), track.pt(), track.eta()); + } + if (cfgOpenDetailPlotsTPCITSContaimination) { + if (track.sign() > 0) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_TPC_Pt_PosPr_Before"), track.tpcNSigmaPr(), track.itsNSigmaPr(), track.pt()); + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_PosPr_Before"), track.tpcNSigmaPr(), averClusSizeCosl, track.pt()); + } else if (track.sign() < 0) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_TPC_Pt_NegPr_Before"), track.tpcNSigmaPr(), track.itsNSigmaPr(), track.pt()); + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_NegPr_Before"), track.tpcNSigmaPr(), averClusSizeCosl, track.pt()); + } + } + } + } + // Second proform ITS cut + if (cfgOpenITSCut) { + int idx = -1; + switch (pidFlag) { + case 1: + if (!selectionITS(track, 1, averClusSizeCosl, nSigmaITSCutPtUpper, nSigmaITSCutPtLower)) { + pidFlag = 4; + } + break; + case 2: + if (!selectionITS(track, 2, averClusSizeCosl, nSigmaITSCutPtUpper, nSigmaITSCutPtLower)) { + pidFlag = 5; + } + break; + case 3: + if (!selectionITS(track, 3, averClusSizeCosl, nSigmaITSCutPtUpper, nSigmaITSCutPtLower)) { + pidFlag = 6; + } + break; + case 7: + idx = (selectionITS(track, 1, averClusSizeCosl, nSigmaITSCutPtUpper, nSigmaITSCutPtLower) << 1) | selectionITS(track, 2, averClusSizeCosl, nSigmaITSCutPtUpper, nSigmaITSCutPtLower); + switch (idx) { + case 0: + pidFlag = 11; + break; + + case 1: + pidFlag = 2; + break; + + case 2: + pidFlag = 1; + break; + } + break; + case 8: + idx = (selectionITS(track, 1, averClusSizeCosl, nSigmaITSCutPtUpper, nSigmaITSCutPtLower) << 1) | selectionITS(track, 3, averClusSizeCosl, nSigmaITSCutPtUpper, nSigmaITSCutPtLower); + switch (idx) { + case 0: + pidFlag = 12; + break; + + case 1: + pidFlag = 3; + break; + + case 2: + pidFlag = 1; + break; + } + break; + case 9: + idx = (selectionITS(track, 2, averClusSizeCosl, nSigmaITSCutPtUpper, nSigmaITSCutPtLower) << 1) | selectionITS(track, 3, averClusSizeCosl, nSigmaITSCutPtUpper, nSigmaITSCutPtLower); + switch (idx) { + case 0: + pidFlag = 13; + break; + + case 1: + pidFlag = 3; + break; + + case 2: + pidFlag = 2; + break; + } + break; + case 10: + idx = (selectionITS(track, 1, averClusSizeCosl, nSigmaITSCutPtUpper, nSigmaITSCutPtLower) << 2) | (selectionITS(track, 2, averClusSizeCosl, nSigmaITSCutPtUpper, nSigmaITSCutPtLower) << 1) | selectionITS(track, 3, averClusSizeCosl, nSigmaITSCutPtUpper, nSigmaITSCutPtLower); + switch (idx) { + case 0: + pidFlag = 14; + break; + + case 1: + pidFlag = 3; + break; + + case 2: + pidFlag = 2; + break; + + case 3: + pidFlag = 9; + break; + + case 4: + pidFlag = 1; + break; + + case 5: + pidFlag = 8; + break; + + case 6: + pidFlag = 7; + break; + } + break; + } + } + // Third Fill ITS cut plots + if (cfgOpenITSCutQAPlots) { + if (!cfgQuietMode) { + if (cfgOpenTrackingInfoCheck) { + histosQA.fill(HIST("QA/PID/histDCAz_total_AfterITS"), track.dcaZ()); + histosQA.fill(HIST("QA/PID/histDCAxy_total_AfterITS"), track.dcaXY()); + histosQA.fill(HIST("QA/PID/histITSNcls_total_AfterITS"), track.itsNCls()); + histosQA.fill(HIST("QA/PID/histTPCNcls_total_AfterITS"), track.tpcNClsFound()); + histosQA.fill(HIST("QA/PID/histTPCChi2Ncls_total_AfterITS"), track.tpcChi2NCl()); + histosQA.fill(HIST("QA/PID/histITSChi2Ncls_total_AfterITS"), track.itsChi2NCl()); + } + if ((pidFlag == 1) || (pidFlag == 7) || (pidFlag == 8) || (pidFlag == 10)) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_nSigmaTPC_AfterITS_Pi"), track.itsNSigmaPi(), track.tpcNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaITS_AfterITS_Pi"), track.tofNSigmaPi(), track.itsNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaTPC_AfterITS_Pi"), track.tofNSigmaPi(), track.tpcNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_TPC_Pt_AfterITS_Pi"), track.pt(), track.tpcNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_TOF_Pt_AfterITS_Pi"), track.pt(), track.tofNSigmaPi()); + histosQA.fill(HIST("QA/PID/histnSigma_ITS_Pt_AfterITS_Pi"), track.pt(), track.itsNSigmaPi()); + if (cfgOpenTrackingInfoCheck) { + histosQA.fill(HIST("QA/PID/histDCAz_Pi_AfterITS"), track.dcaZ()); + histosQA.fill(HIST("QA/PID/histDCAxy_Pi_AfterITS"), track.dcaXY()); + histosQA.fill(HIST("QA/PID/histITSNcls_Pi_AfterITS"), track.itsNCls()); + histosQA.fill(HIST("QA/PID/histTPCNcls_Pi_AfterITS"), track.tpcNClsFound()); + histosQA.fill(HIST("QA/PID/histTPCChi2Ncls_Pi_AfterITS"), track.tpcChi2NCl()); + histosQA.fill(HIST("QA/PID/histITSChi2Ncls_Pi_AfterITS"), track.itsChi2NCl()); + } + if (cfgOpenPlotnSigmaTOFITSPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_ITS_Pt_AfterITS_Pi"), track.tofNSigmaPi(), track.itsNSigmaPi(), track.pt()); + } + if (cfgOpenPlotnSigmaTOFTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_TPC_Pt_AfterITS_Pi"), track.tofNSigmaPi(), track.tpcNSigmaPi(), track.pt()); + } + if (cfgOpenPlotnSigmaITSTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_ITS_TPC_Pt_AfterITS_Pi"), track.itsNSigmaPi(), track.tpcNSigmaPi(), track.pt()); + } + if (cfgOpenPlotAverClus) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_AfterITS_Pi"), averClusSizeCosl); + } + if (cfgOpenPlotAverClusP) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_P_AfterITS_Pi"), track.p(), averClusSizeCosl); + } + if (cfgOpenPlotAverClusnSigmaTPC) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_AfterITS_Pi"), track.tpcNSigmaPi(), averClusSizeCosl); + } + if (cfgOpenPlotPhiDis) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_AfterITS_Pi"), track.phi()); + } + if (cfgOpenPlotPhiDisPtEta) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_Pt_Eta_AfterITS_Pi"), track.phi(), track.pt(), track.eta()); + } + if (cfgOpenDetailPlotsTPCITSContaimination) { + if (track.sign() > 0) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_TPC_Pt_PosPi_After"), track.tpcNSigmaPi(), track.itsNSigmaPi(), track.pt()); + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_PosPi_After"), track.tpcNSigmaPi(), averClusSizeCosl, track.pt()); + } else if (track.sign() < 0) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_TPC_Pt_NegPi_After"), track.tpcNSigmaPi(), track.itsNSigmaPi(), track.pt()); + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_NegPi_After"), track.tpcNSigmaPi(), averClusSizeCosl, track.pt()); + } + } + } + if ((pidFlag == 2) || (pidFlag == 7) || (pidFlag == 9) || (pidFlag == 10)) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_nSigmaTPC_AfterITS_Ka"), track.itsNSigmaKa(), track.tpcNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaITS_AfterITS_Ka"), track.tofNSigmaKa(), track.itsNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaTPC_AfterITS_Ka"), track.tofNSigmaKa(), track.tpcNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_TPC_Pt_AfterITS_Ka"), track.pt(), track.tpcNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_TOF_Pt_AfterITS_Ka"), track.pt(), track.tofNSigmaKa()); + histosQA.fill(HIST("QA/PID/histnSigma_ITS_Pt_AfterITS_Ka"), track.pt(), track.itsNSigmaKa()); + if (cfgOpenTrackingInfoCheck) { + histosQA.fill(HIST("QA/PID/histDCAz_Ka_AfterITS"), track.dcaZ()); + histosQA.fill(HIST("QA/PID/histDCAxy_Ka_AfterITS"), track.dcaXY()); + histosQA.fill(HIST("QA/PID/histITSNcls_Ka_AfterITS"), track.itsNCls()); + histosQA.fill(HIST("QA/PID/histTPCNcls_Ka_AfterITS"), track.tpcNClsFound()); + histosQA.fill(HIST("QA/PID/histTPCChi2Ncls_Ka_AfterITS"), track.tpcChi2NCl()); + histosQA.fill(HIST("QA/PID/histITSChi2Ncls_Ka_AfterITS"), track.itsChi2NCl()); + } + if (cfgOpenPlotnSigmaTOFITSPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_ITS_Pt_AfterITS_Ka"), track.tofNSigmaKa(), track.itsNSigmaKa(), track.pt()); + } + if (cfgOpenPlotnSigmaTOFTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_TPC_Pt_AfterITS_Ka"), track.tofNSigmaKa(), track.tpcNSigmaKa(), track.pt()); + } + if (cfgOpenPlotnSigmaITSTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_ITS_TPC_Pt_AfterITS_Ka"), track.itsNSigmaKa(), track.tpcNSigmaKa(), track.pt()); + } + if (cfgOpenPlotAverClus) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_AfterITS_Ka"), averClusSizeCosl); + } + if (cfgOpenPlotAverClusP) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_P_AfterITS_Ka"), track.p(), averClusSizeCosl); + } + if (cfgOpenPlotAverClusnSigmaTPC) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_AfterITS_Ka"), track.tpcNSigmaKa(), averClusSizeCosl); + } + if (cfgOpenPlotPhiDis) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_AfterITS_Ka"), track.phi()); + } + if (cfgOpenPlotPhiDisPtEta) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_Pt_Eta_AfterITS_Ka"), track.phi(), track.pt(), track.eta()); + } + if (cfgOpenDetailPlotsTPCITSContaimination) { + if (track.sign() > 0) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_TPC_Pt_PosKa_After"), track.tpcNSigmaKa(), track.itsNSigmaKa(), track.pt()); + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_PosKa_After"), track.tpcNSigmaKa(), averClusSizeCosl, track.pt()); + } else if (track.sign() < 0) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_TPC_Pt_NegKa_After"), track.tpcNSigmaKa(), track.itsNSigmaKa(), track.pt()); + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_NegKa_After"), track.tpcNSigmaKa(), averClusSizeCosl, track.pt()); + } + } + } + if ((pidFlag == 3) || (pidFlag == 8) || (pidFlag == 9) || (pidFlag == 10)) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_nSigmaTPC_AfterITS_Pr"), track.itsNSigmaPr(), track.tpcNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaITS_AfterITS_Pr"), track.tofNSigmaPr(), track.itsNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigmaTOF_nSigmaTPC_AfterITS_Pr"), track.tofNSigmaPr(), track.tpcNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_TPC_Pt_AfterITS_Pr"), track.pt(), track.tpcNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_TOF_Pt_AfterITS_Pr"), track.pt(), track.tofNSigmaPr()); + histosQA.fill(HIST("QA/PID/histnSigma_ITS_Pt_AfterITS_Pr"), track.pt(), track.itsNSigmaPr()); + if (cfgOpenTrackingInfoCheck) { + histosQA.fill(HIST("QA/PID/histDCAz_Pr_AfterITS"), track.dcaZ()); + histosQA.fill(HIST("QA/PID/histDCAxy_Pr_AfterITS"), track.dcaXY()); + histosQA.fill(HIST("QA/PID/histITSNcls_Pr_AfterITS"), track.itsNCls()); + histosQA.fill(HIST("QA/PID/histTPCNcls_Pr_AfterITS"), track.tpcNClsFound()); + histosQA.fill(HIST("QA/PID/histTPCChi2Ncls_Pr_AfterITS"), track.tpcChi2NCl()); + histosQA.fill(HIST("QA/PID/histITSChi2Ncls_Pr_AfterITS"), track.itsChi2NCl()); + } + if (cfgOpenPlotnSigmaTOFITSPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_ITS_Pt_AfterITS_Pr"), track.tofNSigmaPr(), track.itsNSigmaPr(), track.pt()); + } + if (cfgOpenPlotnSigmaTOFTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_TOF_TPC_Pt_AfterITS_Pr"), track.tofNSigmaPr(), track.tpcNSigmaPr(), track.pt()); + } + if (cfgOpenPlotnSigmaITSTPCPt) { + histosQA.fill(HIST("QA/PID/histnSigma_ITS_TPC_Pt_AfterITS_Pr"), track.itsNSigmaPr(), track.tpcNSigmaPr(), track.pt()); + } + if (cfgOpenPlotAverClus) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_AfterITS_Pr"), averClusSizeCosl); + } + if (cfgOpenPlotAverClusP) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_P_AfterITS_Pr"), track.p(), averClusSizeCosl); + } + if (cfgOpenPlotAverClusnSigmaTPC) { + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_AfterITS_Pr"), track.tpcNSigmaPr(), averClusSizeCosl); + } + if (cfgOpenPlotPhiDis) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_AfterITS_Pr"), track.phi()); + } + if (cfgOpenPlotPhiDisPtEta) { + histosQA.fill(HIST("QA/PID/histPhi_Dis_Pt_Eta_AfterITS_Pr"), track.phi(), track.pt(), track.eta()); + } + if (cfgOpenDetailPlotsTPCITSContaimination) { + if (track.sign() > 0) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_TPC_Pt_PosPr_After"), track.tpcNSigmaPr(), track.itsNSigmaPr(), track.pt()); + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_PosPr_After"), track.tpcNSigmaPr(), averClusSizeCosl, track.pt()); + } else if (track.sign() < 0) { + histosQA.fill(HIST("QA/PID/histnSigmaITS_TPC_Pt_NegPr_After"), track.tpcNSigmaPr(), track.itsNSigmaPr(), track.pt()); + histosQA.fill(HIST("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_NegPr_After"), track.tpcNSigmaPr(), averClusSizeCosl, track.pt()); + } + } + } + } + } + } + } + pidCmeTable(pidFlag); + pidInfoTable(averClusSizeCosl, track.itsNSigmaPi(), track.itsNSigmaKa(), track.itsNSigmaPr(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()); + } + } +}; + +struct QAProcessCent { + HistogramRegistry histosQA{"histosQAwithcent", {}, OutputObjHandlingPolicy::AnalysisObject}; + Configurable> cfgCentralitybinsforQA{"cfgCentralitybinsforQA", {0, 30, 60}, "Centrality bins for track phi and TPC_ITS matching check"}; + Configurable cfgOpenDetailPlots{"cfgOpenDetailPlots", true, "open detail TH3D plots for nSigmaTPC-ITS Pt-eta-Phi nSigmaITS-clustersize"}; + Configurable cfgOpenITSafter{"cfgOpenITSafter", true, "open check for after ITS cut check(if used ITScut in table producer it need else close to save cpu usage)"}; + Configurable cfgOpenPtEtaPhi{"cfgOpenPtEtaPhi", true, "open pt-#eta-#phi PID QA (Optional for limited memory usage)"}; + Configurable cfgOpenITSTPCnSigma{"cfgOpenITSTPCnSigma", true, "open ITS-TPC nSigma QA (Optional for limited memory usage)"}; + Configurable cfgOpenClusSizenSigmaTPC{"cfgOpenClusSizenSigmaTPC", true, "open ITSClustersize-TPCnsigma QA (Optional for limited memory usage)"}; + Configurable cfgOpenPi{"cfgOpenPi", true, "open Pion QA (Optional for limited memory usage)"}; + Configurable cfgOpenKa{"cfgOpenKa", true, "open Kaon QA (Optional for limited memory usage)"}; + Configurable cfgOpenPr{"cfgOpenPr", true, "open Proton QA (Optional for limited memory usage)"}; + Configurable cfgOpenTOFITSnSigma{"cfgOpenTOFITSnSigma", false, "open TOF-ITS nsigma 2D plots vs pt at a certain centrality"}; + Configurable cfgOpenTOFTPCnSigma{"cfgOpenTOFTPCnSigma", false, "open TOF-TPC nsigma 2D plots vs pt at a certain centrality"}; + ConfigurableAxis cfgaxisetaPID{"cfgaxisetaPID", {90, -0.9, 0.9}, "Binning for Pt QA"}; + ConfigurableAxis cfgaxisptPID{"cfgaxisptPID", {120, 0, 12}, "Binning for P_{t} PID"}; + ConfigurableAxis cfgnSigmaBinsTPC{"cfgnSigmaBinsTPC", {200, -5.f, 5.f}, "Binning for n sigma TPC"}; + ConfigurableAxis cfgnSigmaBinsITS{"cfgnSigmaBinsITS", {200, -5.f, 5.f}, "Binning for n sigma ITS"}; + ConfigurableAxis cfgnSigmaBinsTOF{"cfgnSigmaBinsTOF", {200, -5.f, 5.f}, "Binning for n sigma TOF"}; + ConfigurableAxis cfgaxisAverClusterCoslnSigma{"cfgaxisAverClusterCoslnSigma", {50, 0, 5}, "Binning for average cluster size x cos(#lambda) vs nSigam"}; + + std::vector> vhistPhiPtEtaPosPiCen; + std::vector> vhistPhiPtEtaNegPiCen; + std::vector> vhistPhiPtEtaPosKaCen; + std::vector> vhistPhiPtEtaNegKaCen; + std::vector> vhistPhiPtEtaPosPrCen; + std::vector> vhistPhiPtEtaNegPrCen; + std::vector> vhistnSigmaITSTPCPtPosPiBeforeCen; + std::vector> vhistnSigmaITSTPCPtNegPiBeforeCen; + std::vector> vhistnSigmaITSTPCPtPosKaBeforeCen; + std::vector> vhistnSigmaITSTPCPtNegKaBeforeCen; + std::vector> vhistnSigmaITSTPCPtPosPrBeforeCen; + std::vector> vhistnSigmaITSTPCPtNegPrBeforeCen; + std::vector> vhistnSigmaITSTPCPtPosPiAfterCen; + std::vector> vhistnSigmaITSTPCPtNegPiAfterCen; + std::vector> vhistnSigmaITSTPCPtPosKaAfterCen; + std::vector> vhistnSigmaITSTPCPtNegKaAfterCen; + std::vector> vhistnSigmaITSTPCPtPosPrAfterCen; + std::vector> vhistnSigmaITSTPCPtNegPrAfterCen; + std::vector> vhistAverClusterSizeCoslnSigmaTPCPtPosPiBeforeCen; + std::vector> vhistAverClusterSizeCoslnSigmaTPCPtNegPiBeforeCen; + std::vector> vhistAverClusterSizeCoslnSigmaTPCPtPosKaBeforeCen; + std::vector> vhistAverClusterSizeCoslnSigmaTPCPtNegKaBeforeCen; + std::vector> vhistAverClusterSizeCoslnSigmaTPCPtPosPrBeforeCen; + std::vector> vhistAverClusterSizeCoslnSigmaTPCPtNegPrBeforeCen; + std::vector> vhistAverClusterSizeCoslnSigmaTPCPtPosPiAfterCen; + std::vector> vhistAverClusterSizeCoslnSigmaTPCPtNegPiAfterCen; + std::vector> vhistAverClusterSizeCoslnSigmaTPCPtPosKaAfterCen; + std::vector> vhistAverClusterSizeCoslnSigmaTPCPtNegKaAfterCen; + std::vector> vhistAverClusterSizeCoslnSigmaTPCPtPosPrAfterCen; + std::vector> vhistAverClusterSizeCoslnSigmaTPCPtNegPrAfterCen; + std::vector> vhistnSigmaTOFITSPtPosPiBeforeCen; + std::vector> vhistnSigmaTOFITSPtNegPiBeforeCen; + std::vector> vhistnSigmaTOFITSPtPosKaBeforeCen; + std::vector> vhistnSigmaTOFITSPtNegKaBeforeCen; + std::vector> vhistnSigmaTOFITSPtPosPrBeforeCen; + std::vector> vhistnSigmaTOFITSPtNegPrBeforeCen; + std::vector> vhistnSigmaTOFITSPtPosPiAfterCen; + std::vector> vhistnSigmaTOFITSPtNegPiAfterCen; + std::vector> vhistnSigmaTOFITSPtPosKaAfterCen; + std::vector> vhistnSigmaTOFITSPtNegKaAfterCen; + std::vector> vhistnSigmaTOFITSPtPosPrAfterCen; + std::vector> vhistnSigmaTOFITSPtNegPrAfterCen; + std::vector> vhistnSigmaTOFTPCPtPosPiBeforeCen; + std::vector> vhistnSigmaTOFTPCPtNegPiBeforeCen; + std::vector> vhistnSigmaTOFTPCPtPosKaBeforeCen; + std::vector> vhistnSigmaTOFTPCPtNegKaBeforeCen; + std::vector> vhistnSigmaTOFTPCPtPosPrBeforeCen; + std::vector> vhistnSigmaTOFTPCPtNegPrBeforeCen; + std::vector> vhistnSigmaTOFTPCPtPosPiAfterCen; + std::vector> vhistnSigmaTOFTPCPtNegPiAfterCen; + std::vector> vhistnSigmaTOFTPCPtPosKaAfterCen; + std::vector> vhistnSigmaTOFTPCPtNegKaAfterCen; + std::vector> vhistnSigmaTOFTPCPtPosPrAfterCen; + std::vector> vhistnSigmaTOFTPCPtNegPrAfterCen; + Filter trackPIDfilter = aod::cme_track_pid_columns::nPidFlag > (int8_t)0; + void init(InitContext const&) + { + AxisSpec axisPhicme = {100, 0, 2.1 * constants::math::PI, "#phi"}; + // Additional QA histograms for PID + if (cfgOpenDetailPlots) { + for (int i = 0; i < static_cast(cfgCentralitybinsforQA.value.size()) - 1; ++i) { + if (cfgOpenPtEtaPhi) { + if (cfgOpenPi) { + auto hPhiPtEtaPosPi = histosQA.add(Form("QA/PID/histPhi_Pt_Eta_PosPi_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";#phi;#p_{t};#eta", {HistType::kTH3F, {axisPhicme, cfgaxisptPID, cfgaxisetaPID}}); + auto hPhiPtEtaNegPi = histosQA.add(Form("QA/PID/histPhi_Pt_Eta_NegPi_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";#phi;#p_{t};#eta", {HistType::kTH3F, {axisPhicme, cfgaxisptPID, cfgaxisetaPID}}); + vhistPhiPtEtaPosPiCen.push_back(std::move(hPhiPtEtaPosPi)); + vhistPhiPtEtaNegPiCen.push_back(std::move(hPhiPtEtaNegPi)); + } + if (cfgOpenKa) { + auto hPhiPtEtaPosKa = histosQA.add(Form("QA/PID/histPhi_Pt_Eta_PosKa_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";#phi;#p_{t};#eta", {HistType::kTH3F, {axisPhicme, cfgaxisptPID, cfgaxisetaPID}}); + auto hPhiPtEtaNegKa = histosQA.add(Form("QA/PID/histPhi_Pt_Eta_NegKa_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";#phi;#p_{t};#eta", {HistType::kTH3F, {axisPhicme, cfgaxisptPID, cfgaxisetaPID}}); + vhistPhiPtEtaPosKaCen.push_back(std::move(hPhiPtEtaPosKa)); + vhistPhiPtEtaNegKaCen.push_back(std::move(hPhiPtEtaNegKa)); + } + if (cfgOpenPr) { + auto hPhiPtEtaPosPr = histosQA.add(Form("QA/PID/histPhi_Pt_Eta_PosPr_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";#phi;#p_{t};#eta", {HistType::kTH3F, {axisPhicme, cfgaxisptPID, cfgaxisetaPID}}); + auto hPhiPtEtaNegPr = histosQA.add(Form("QA/PID/histPhi_Pt_Eta_NegPr_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";#phi;#p_{t};#eta", {HistType::kTH3F, {axisPhicme, cfgaxisptPID, cfgaxisetaPID}}); + vhistPhiPtEtaPosPrCen.push_back(std::move(hPhiPtEtaPosPr)); + vhistPhiPtEtaNegPrCen.push_back(std::move(hPhiPtEtaNegPr)); + } + } + if (cfgOpenITSTPCnSigma) { + if (cfgOpenPi) { + auto hnSigmaITSTPCPtPosPiBefore = histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_PosPi_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgnSigmaBinsITS, cfgaxisptPID}}); + auto hnSigmaITSTPCPtNegPiBefore = histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_NegPi_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgnSigmaBinsITS, cfgaxisptPID}}); + vhistnSigmaITSTPCPtPosPiBeforeCen.push_back(std::move(hnSigmaITSTPCPtPosPiBefore)); + vhistnSigmaITSTPCPtNegPiBeforeCen.push_back(std::move(hnSigmaITSTPCPtNegPiBefore)); + if (cfgOpenITSafter) { + auto hnSigmaITSTPCPtPosPiAfter = histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_PosPi_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgnSigmaBinsITS, cfgaxisptPID}}); + auto hnSigmaITSTPCPtNegPiAfter = histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_NegPi_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgnSigmaBinsITS, cfgaxisptPID}}); + vhistnSigmaITSTPCPtPosPiAfterCen.push_back(std::move(hnSigmaITSTPCPtPosPiAfter)); + vhistnSigmaITSTPCPtNegPiAfterCen.push_back(std::move(hnSigmaITSTPCPtNegPiAfter)); + } + } + if (cfgOpenKa) { + auto hnSigmaITSTPCPtPosKaBefore = histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_PosKa_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgnSigmaBinsITS, cfgaxisptPID}}); + auto hnSigmaITSTPCPtNegKaBefore = histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_NegKa_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgnSigmaBinsITS, cfgaxisptPID}}); + vhistnSigmaITSTPCPtPosKaBeforeCen.push_back(std::move(hnSigmaITSTPCPtPosKaBefore)); + vhistnSigmaITSTPCPtNegKaBeforeCen.push_back(std::move(hnSigmaITSTPCPtNegKaBefore)); + if (cfgOpenITSafter) { + auto hnSigmaITSTPCPtPosKaAfter = histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_PosKa_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgnSigmaBinsITS, cfgaxisptPID}}); + auto hnSigmaITSTPCPtNegKaAfter = histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_NegKa_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgnSigmaBinsITS, cfgaxisptPID}}); + vhistnSigmaITSTPCPtPosKaAfterCen.push_back(std::move(hnSigmaITSTPCPtPosKaAfter)); + vhistnSigmaITSTPCPtNegKaAfterCen.push_back(std::move(hnSigmaITSTPCPtNegKaAfter)); + } + } + if (cfgOpenPr) { + auto hnSigmaITSTPCPtPosPrBefore = histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_PosPr_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgnSigmaBinsITS, cfgaxisptPID}}); + auto hnSigmaITSTPCPtNegPrBefore = histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_NegPr_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgnSigmaBinsITS, cfgaxisptPID}}); + vhistnSigmaITSTPCPtPosPrBeforeCen.push_back(std::move(hnSigmaITSTPCPtPosPrBefore)); + vhistnSigmaITSTPCPtNegPrBeforeCen.push_back(std::move(hnSigmaITSTPCPtNegPrBefore)); + if (cfgOpenITSafter) { + auto hnSigmaITSTPCPtPosPrAfter = histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_PosPr_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgnSigmaBinsITS, cfgaxisptPID}}); + auto hnSigmaITSTPCPtNegPrAfter = histosQA.add(Form("QA/PID/histnSigmaITS_TPC_Pt_NegPr_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgnSigmaBinsITS, cfgaxisptPID}}); + vhistnSigmaITSTPCPtPosPrAfterCen.push_back(std::move(hnSigmaITSTPCPtPosPrAfter)); + vhistnSigmaITSTPCPtNegPrAfterCen.push_back(std::move(hnSigmaITSTPCPtNegPrAfter)); + } + } + } + if (cfgOpenClusSizenSigmaTPC) { + if (cfgOpenPi) { + auto hAverClusterSizeCoslnSigmaTPCPtPosPiBefore = histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_PosPi_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgaxisAverClusterCoslnSigma, cfgaxisptPID}}); + auto hAverClusterSizeCoslnSigmaTPCPtNegPiBefore = histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_NegPi_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgaxisAverClusterCoslnSigma, cfgaxisptPID}}); + vhistAverClusterSizeCoslnSigmaTPCPtPosPiBeforeCen.push_back(std::move(hAverClusterSizeCoslnSigmaTPCPtPosPiBefore)); + vhistAverClusterSizeCoslnSigmaTPCPtNegPiBeforeCen.push_back(std::move(hAverClusterSizeCoslnSigmaTPCPtNegPiBefore)); + if (cfgOpenITSafter) { + auto hAverClusterSizeCoslnSigmaTPCPtPosPiAfter = histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_PosPi_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgaxisAverClusterCoslnSigma, cfgaxisptPID}}); + auto hAverClusterSizeCoslnSigmaTPCPtNegPiAfter = histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_NegPi_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgaxisAverClusterCoslnSigma, cfgaxisptPID}}); + vhistAverClusterSizeCoslnSigmaTPCPtPosPiAfterCen.push_back(std::move(hAverClusterSizeCoslnSigmaTPCPtPosPiAfter)); + vhistAverClusterSizeCoslnSigmaTPCPtNegPiAfterCen.push_back(std::move(hAverClusterSizeCoslnSigmaTPCPtNegPiAfter)); + } + } + if (cfgOpenKa) { + auto hAverClusterSizeCoslnSigmaTPCPtPosKaBefore = histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_PosKa_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgaxisAverClusterCoslnSigma, cfgaxisptPID}}); + auto hAverClusterSizeCoslnSigmaTPCPtNegKaBefore = histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_NegKa_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgaxisAverClusterCoslnSigma, cfgaxisptPID}}); + vhistAverClusterSizeCoslnSigmaTPCPtPosKaBeforeCen.push_back(std::move(hAverClusterSizeCoslnSigmaTPCPtPosKaBefore)); + vhistAverClusterSizeCoslnSigmaTPCPtNegKaBeforeCen.push_back(std::move(hAverClusterSizeCoslnSigmaTPCPtNegKaBefore)); + if (cfgOpenITSafter) { + auto hAverClusterSizeCoslnSigmaTPCPtPosKaAfter = histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_PosKa_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgaxisAverClusterCoslnSigma, cfgaxisptPID}}); + auto hAverClusterSizeCoslnSigmaTPCPtNegKaAfter = histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_NegKa_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgaxisAverClusterCoslnSigma, cfgaxisptPID}}); + vhistAverClusterSizeCoslnSigmaTPCPtPosKaAfterCen.push_back(std::move(hAverClusterSizeCoslnSigmaTPCPtPosKaAfter)); + vhistAverClusterSizeCoslnSigmaTPCPtNegKaAfterCen.push_back(std::move(hAverClusterSizeCoslnSigmaTPCPtNegKaAfter)); + } + } + if (cfgOpenPr) { + auto hAverClusterSizeCoslnSigmaTPCPtPosPrBefore = histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_PosPr_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgaxisAverClusterCoslnSigma, cfgaxisptPID}}); + auto hAverClusterSizeCoslnSigmaTPCPtNegPrBefore = histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_NegPr_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgaxisAverClusterCoslnSigma, cfgaxisptPID}}); + vhistAverClusterSizeCoslnSigmaTPCPtPosPrBeforeCen.push_back(std::move(hAverClusterSizeCoslnSigmaTPCPtPosPrBefore)); + vhistAverClusterSizeCoslnSigmaTPCPtNegPrBeforeCen.push_back(std::move(hAverClusterSizeCoslnSigmaTPCPtNegPrBefore)); + if (cfgOpenITSafter) { + auto hAverClusterSizeCoslnSigmaTPCPtPosPrAfter = histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_PosPr_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgaxisAverClusterCoslnSigma, cfgaxisptPID}}); + auto hAverClusterSizeCoslnSigmaTPCPtNegPrAfter = histosQA.add(Form("QA/PID/histAverClusterSizeCosl_nSigmaTPC_Pt_NegPr_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TPC}; x ;#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgaxisAverClusterCoslnSigma, cfgaxisptPID}}); + vhistAverClusterSizeCoslnSigmaTPCPtPosPrAfterCen.push_back(std::move(hAverClusterSizeCoslnSigmaTPCPtPosPrAfter)); + vhistAverClusterSizeCoslnSigmaTPCPtNegPrAfterCen.push_back(std::move(hAverClusterSizeCoslnSigmaTPCPtNegPrAfter)); + } + } + } + if (cfgOpenTOFITSnSigma) { + if (cfgOpenPi) { + auto hnSigmaTOFITSPtPosPiBefore = histosQA.add(Form("QA/PID/histnSigmaTOF_ITS_Pt_PosPi_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsITS, cfgaxisptPID}}); + auto hnSigmaTOFITSPtNegPiBefore = histosQA.add(Form("QA/PID/histnSigmaTOF_ITS_Pt_NegPi_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsITS, cfgaxisptPID}}); + vhistnSigmaTOFITSPtPosPiBeforeCen.push_back(std::move(hnSigmaTOFITSPtPosPiBefore)); + vhistnSigmaTOFITSPtNegPiBeforeCen.push_back(std::move(hnSigmaTOFITSPtNegPiBefore)); + if (cfgOpenITSafter) { + auto hnSigmaTOFITSPtPosPiAfter = histosQA.add(Form("QA/PID/histnSigmaTOF_ITS_Pt_PosPi_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsITS, cfgaxisptPID}}); + auto hnSigmaTOFITSPtNegPiAfter = histosQA.add(Form("QA/PID/histnSigmaTOF_ITS_Pt_NegPi_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsITS, cfgaxisptPID}}); + vhistnSigmaTOFITSPtPosPiAfterCen.push_back(std::move(hnSigmaTOFITSPtPosPiAfter)); + vhistnSigmaTOFITSPtNegPiAfterCen.push_back(std::move(hnSigmaTOFITSPtNegPiAfter)); + } + } + if (cfgOpenKa) { + auto hnSigmaTOFITSPtPosKaBefore = histosQA.add(Form("QA/PID/histnSigmaTOF_ITS_Pt_PosKa_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsITS, cfgaxisptPID}}); + auto hnSigmaTOFITSPtNegKaBefore = histosQA.add(Form("QA/PID/histnSigmaTOF_ITS_Pt_NegKa_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsITS, cfgaxisptPID}}); + vhistnSigmaTOFITSPtPosKaBeforeCen.push_back(std::move(hnSigmaTOFITSPtPosKaBefore)); + vhistnSigmaTOFITSPtNegKaBeforeCen.push_back(std::move(hnSigmaTOFITSPtNegKaBefore)); + if (cfgOpenITSafter) { + auto hnSigmaTOFITSPtPosKaAfter = histosQA.add(Form("QA/PID/histnSigmaTOF_ITS_Pt_PosKa_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsITS, cfgaxisptPID}}); + auto hnSigmaTOFITSPtNegKaAfter = histosQA.add(Form("QA/PID/histnSigmaTOF_ITS_Pt_NegKa_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsITS, cfgaxisptPID}}); + vhistnSigmaTOFITSPtPosKaAfterCen.push_back(std::move(hnSigmaTOFITSPtPosKaAfter)); + vhistnSigmaTOFITSPtNegKaAfterCen.push_back(std::move(hnSigmaTOFITSPtNegKaAfter)); + } + } + if (cfgOpenPr) { + auto hnSigmaTOFITSPtPosPrBefore = histosQA.add(Form("QA/PID/histnSigmaTOF_ITS_Pt_PosPr_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsITS, cfgaxisptPID}}); + auto hnSigmaTOFITSPtNegPrBefore = histosQA.add(Form("QA/PID/histnSigmaTOF_ITS_Pt_NegPr_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsITS, cfgaxisptPID}}); + vhistnSigmaTOFITSPtPosPrBeforeCen.push_back(std::move(hnSigmaTOFITSPtPosPrBefore)); + vhistnSigmaTOFITSPtNegPrBeforeCen.push_back(std::move(hnSigmaTOFITSPtNegPrBefore)); + if (cfgOpenITSafter) { + auto hnSigmaTOFITSPtPosPrAfter = histosQA.add(Form("QA/PID/histnSigmaTOF_ITS_Pt_PosPr_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsITS, cfgaxisptPID}}); + auto hnSigmaTOFITSPtNegPrAfter = histosQA.add(Form("QA/PID/histnSigmaTOF_ITS_Pt_NegPr_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsITS, cfgaxisptPID}}); + vhistnSigmaTOFITSPtPosPrAfterCen.push_back(std::move(hnSigmaTOFITSPtPosPrAfter)); + vhistnSigmaTOFITSPtNegPrAfterCen.push_back(std::move(hnSigmaTOFITSPtNegPrAfter)); + } + } + } + if (cfgOpenTOFTPCnSigma) { + if (cfgOpenPi) { + auto hnSigmaTOFTPCPtPosPiBefore = histosQA.add(Form("QA/PID/histnSigmaTOF_TPC_Pt_PosPi_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{TPC};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsTPC, cfgaxisptPID}}); + auto hnSigmaTOFTPCPtNegPiBefore = histosQA.add(Form("QA/PID/histnSigmaTOF_TPC_Pt_NegPi_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{TPC};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsTPC, cfgaxisptPID}}); + vhistnSigmaTOFTPCPtPosPiBeforeCen.push_back(std::move(hnSigmaTOFTPCPtPosPiBefore)); + vhistnSigmaTOFTPCPtNegPiBeforeCen.push_back(std::move(hnSigmaTOFTPCPtNegPiBefore)); + if (cfgOpenITSafter) { + auto hnSigmaTOFTPCPtPosPiAfter = histosQA.add(Form("QA/PID/histnSigmaTOF_TPC_Pt_PosPi_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{TPC};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsTPC, cfgaxisptPID}}); + auto hnSigmaTOFTPCPtNegPiAfter = histosQA.add(Form("QA/PID/histnSigmaTOF_TPC_Pt_NegPi_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{TPC};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsTPC, cfgaxisptPID}}); + vhistnSigmaTOFTPCPtPosPiAfterCen.push_back(std::move(hnSigmaTOFTPCPtPosPiAfter)); + vhistnSigmaTOFTPCPtNegPiAfterCen.push_back(std::move(hnSigmaTOFTPCPtNegPiAfter)); + } + } + if (cfgOpenKa) { + auto hnSigmaTOFTPCPtPosKaBefore = histosQA.add(Form("QA/PID/histnSigmaTOF_TPC_Pt_PosKa_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{TPC};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsTPC, cfgaxisptPID}}); + auto hnSigmaTOFTPCPtNegKaBefore = histosQA.add(Form("QA/PID/histnSigmaTOF_TPC_Pt_NegKa_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{TPC};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsTPC, cfgaxisptPID}}); + vhistnSigmaTOFTPCPtPosKaBeforeCen.push_back(std::move(hnSigmaTOFTPCPtPosKaBefore)); + vhistnSigmaTOFTPCPtNegKaBeforeCen.push_back(std::move(hnSigmaTOFTPCPtNegKaBefore)); + if (cfgOpenITSafter) { + auto hnSigmaTOFTPCPtPosKaAfter = histosQA.add(Form("QA/PID/histnSigmaTOF_TPC_Pt_PosKa_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{TPC};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsTPC, cfgaxisptPID}}); + auto hnSigmaTOFTPCPtNegKaAfter = histosQA.add(Form("QA/PID/histnSigmaTOF_TPC_Pt_NegKa_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{TPC};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsTPC, cfgaxisptPID}}); + vhistnSigmaTOFTPCPtPosKaAfterCen.push_back(std::move(hnSigmaTOFTPCPtPosKaAfter)); + vhistnSigmaTOFTPCPtNegKaAfterCen.push_back(std::move(hnSigmaTOFTPCPtNegKaAfter)); + } + } + if (cfgOpenPr) { + auto hnSigmaTOFTPCPtPosPrBefore = histosQA.add(Form("QA/PID/histnSigmaTOF_TPC_Pt_PosPr_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{TPC};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsTPC, cfgaxisptPID}}); + auto hnSigmaTOFTPCPtNegPrBefore = histosQA.add(Form("QA/PID/histnSigmaTOF_TPC_Pt_NegPr_Before_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{TPC};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsTPC, cfgaxisptPID}}); + vhistnSigmaTOFTPCPtPosPrBeforeCen.push_back(std::move(hnSigmaTOFTPCPtPosPrBefore)); + vhistnSigmaTOFTPCPtNegPrBeforeCen.push_back(std::move(hnSigmaTOFTPCPtNegPrBefore)); + if (cfgOpenITSafter) { + auto hnSigmaTOFTPCPtPosPrAfter = histosQA.add(Form("QA/PID/histnSigmaTOF_TPC_Pt_PosPr_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{TPC};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsTPC, cfgaxisptPID}}); + auto hnSigmaTOFTPCPtNegPrAfter = histosQA.add(Form("QA/PID/histnSigmaTOF_TPC_Pt_NegPr_After_Cen_%d_%d", cfgCentralitybinsforQA.value[i], cfgCentralitybinsforQA.value[i + 1]), ";n#sigma_{TOF};n#sigma_{TPC};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsTPC, cfgaxisptPID}}); + vhistnSigmaTOFTPCPtPosPrAfterCen.push_back(std::move(hnSigmaTOFTPCPtPosPrAfter)); + vhistnSigmaTOFTPCPtNegPrAfterCen.push_back(std::move(hnSigmaTOFTPCPtNegPrAfter)); + } + } + } + } + } + } + void process(CollisionPID::iterator const& collision, soa::Filtered> const& tracks) + { + if (cfgOpenDetailPlots) { + const auto cent = collision.centFT0C(); + int currentBin = -1; + for (int i = 0; i < static_cast(cfgCentralitybinsforQA.value.size()) - 1; ++i) { + if (cent >= cfgCentralitybinsforQA.value[i] && cent < cfgCentralitybinsforQA.value[i + 1]) { + currentBin = i; + break; + } + } + if (currentBin >= 0) { + for (const auto& trk : tracks) { + int8_t pidFlag = trk.nPidFlag(); + if (cfgOpenPi) { + if ((pidFlag == 1) || (pidFlag == 4) || (pidFlag == 7) || (pidFlag == 8) || (pidFlag == 10) || (pidFlag == 11) || (pidFlag == 12) || (pidFlag == 14)) { + if (trk.sign() > 0) { + if (!((pidFlag == 4) || (pidFlag == 11) || (pidFlag == 12) || (pidFlag == 14))) { + if (cfgOpenPtEtaPhi) { + vhistPhiPtEtaPosPiCen[currentBin]->Fill(trk.phi(), trk.pt(), trk.eta()); + } + if (cfgOpenITSafter) { + if (cfgOpenITSTPCnSigma) { + vhistnSigmaITSTPCPtPosPiAfterCen[currentBin]->Fill(trk.nSigmaPiTPC(), trk.nSigmaPiITS(), trk.pt()); + } + if (cfgOpenClusSizenSigmaTPC) { + vhistAverClusterSizeCoslnSigmaTPCPtPosPiAfterCen[currentBin]->Fill(trk.nSigmaPiTPC(), trk.averClusterSizeCosl(), trk.pt()); + } + if (cfgOpenTOFITSnSigma) { + vhistnSigmaTOFITSPtPosPiAfterCen[currentBin]->Fill(trk.nSigmaPiTOF(), trk.nSigmaPiITS(), trk.pt()); + } + if (cfgOpenTOFTPCnSigma) { + vhistnSigmaTOFTPCPtPosPiAfterCen[currentBin]->Fill(trk.nSigmaPiTOF(), trk.nSigmaPiTPC(), trk.pt()); + } + } + } + if (cfgOpenITSTPCnSigma) { + vhistnSigmaITSTPCPtPosPiBeforeCen[currentBin]->Fill(trk.nSigmaPiTPC(), trk.nSigmaPiITS(), trk.pt()); + } + if (cfgOpenClusSizenSigmaTPC) { + vhistAverClusterSizeCoslnSigmaTPCPtPosPiBeforeCen[currentBin]->Fill(trk.nSigmaPiTPC(), trk.averClusterSizeCosl(), trk.pt()); + } + if (cfgOpenTOFITSnSigma) { + vhistnSigmaTOFITSPtPosPiBeforeCen[currentBin]->Fill(trk.nSigmaPiTOF(), trk.nSigmaPiITS(), trk.pt()); + } + if (cfgOpenTOFTPCnSigma) { + vhistnSigmaTOFTPCPtPosPiBeforeCen[currentBin]->Fill(trk.nSigmaPiTOF(), trk.nSigmaPiTPC(), trk.pt()); + } + } else if (trk.sign() < 0) { + if (!((pidFlag == 4) || (pidFlag == 11) || (pidFlag == 12) || (pidFlag == 14))) { + if (cfgOpenPtEtaPhi) { + vhistPhiPtEtaNegPiCen[currentBin]->Fill(trk.phi(), trk.pt(), trk.eta()); + } + if (cfgOpenITSafter) { + if (cfgOpenITSTPCnSigma) { + vhistnSigmaITSTPCPtNegPiAfterCen[currentBin]->Fill(trk.nSigmaPiTPC(), trk.nSigmaPiITS(), trk.pt()); + } + if (cfgOpenClusSizenSigmaTPC) { + vhistAverClusterSizeCoslnSigmaTPCPtNegPiAfterCen[currentBin]->Fill(trk.nSigmaPiTPC(), trk.averClusterSizeCosl(), trk.pt()); + } + if (cfgOpenTOFITSnSigma) { + vhistnSigmaTOFITSPtNegPiAfterCen[currentBin]->Fill(trk.nSigmaPiTOF(), trk.nSigmaPiITS(), trk.pt()); + } + if (cfgOpenTOFTPCnSigma) { + vhistnSigmaTOFTPCPtNegPiAfterCen[currentBin]->Fill(trk.nSigmaPiTOF(), trk.nSigmaPiTPC(), trk.pt()); + } + } + } + if (cfgOpenITSTPCnSigma) { + vhistnSigmaITSTPCPtNegPiBeforeCen[currentBin]->Fill(trk.nSigmaPiTPC(), trk.nSigmaPiITS(), trk.pt()); + } + if (cfgOpenClusSizenSigmaTPC) { + vhistAverClusterSizeCoslnSigmaTPCPtNegPiBeforeCen[currentBin]->Fill(trk.nSigmaPiTPC(), trk.averClusterSizeCosl(), trk.pt()); + } + if (cfgOpenTOFITSnSigma) { + vhistnSigmaTOFITSPtNegPiBeforeCen[currentBin]->Fill(trk.nSigmaPiTOF(), trk.nSigmaPiITS(), trk.pt()); + } + if (cfgOpenTOFTPCnSigma) { + vhistnSigmaTOFTPCPtNegPiBeforeCen[currentBin]->Fill(trk.nSigmaPiTOF(), trk.nSigmaPiTPC(), trk.pt()); + } + } + } + } + if (cfgOpenKa) { + if ((pidFlag == 2) || (pidFlag == 5) || (pidFlag == 7) || (pidFlag == 9) || (pidFlag == 10) || (pidFlag == 11) || (pidFlag == 13) || (pidFlag == 14)) { + if (trk.sign() > 0) { + if (!((pidFlag == 5) || (pidFlag == 11) || (pidFlag == 13) || (pidFlag == 14))) { + if (cfgOpenPtEtaPhi) { + vhistPhiPtEtaPosKaCen[currentBin]->Fill(trk.phi(), trk.pt(), trk.eta()); + } + if (cfgOpenITSafter) { + if (cfgOpenITSTPCnSigma) { + vhistnSigmaITSTPCPtPosKaAfterCen[currentBin]->Fill(trk.nSigmaKaTPC(), trk.nSigmaKaITS(), trk.pt()); + } + if (cfgOpenClusSizenSigmaTPC) { + vhistAverClusterSizeCoslnSigmaTPCPtPosKaAfterCen[currentBin]->Fill(trk.nSigmaKaTPC(), trk.averClusterSizeCosl(), trk.pt()); + } + if (cfgOpenTOFITSnSigma) { + vhistnSigmaTOFITSPtPosKaAfterCen[currentBin]->Fill(trk.nSigmaKaTOF(), trk.nSigmaKaITS(), trk.pt()); + } + if (cfgOpenTOFTPCnSigma) { + vhistnSigmaTOFTPCPtPosKaAfterCen[currentBin]->Fill(trk.nSigmaKaTOF(), trk.nSigmaKaTPC(), trk.pt()); + } + } + } + if (cfgOpenITSTPCnSigma) { + vhistnSigmaITSTPCPtPosKaBeforeCen[currentBin]->Fill(trk.nSigmaKaTPC(), trk.nSigmaKaITS(), trk.pt()); + } + if (cfgOpenClusSizenSigmaTPC) { + vhistAverClusterSizeCoslnSigmaTPCPtPosKaBeforeCen[currentBin]->Fill(trk.nSigmaKaTPC(), trk.averClusterSizeCosl(), trk.pt()); + } + if (cfgOpenTOFITSnSigma) { + vhistnSigmaTOFITSPtPosKaBeforeCen[currentBin]->Fill(trk.nSigmaKaTOF(), trk.nSigmaKaITS(), trk.pt()); + } + if (cfgOpenTOFTPCnSigma) { + vhistnSigmaTOFTPCPtPosKaBeforeCen[currentBin]->Fill(trk.nSigmaKaTOF(), trk.nSigmaKaTPC(), trk.pt()); + } + } else if (trk.sign() < 0) { + if (!((pidFlag == 5) || (pidFlag == 11) || (pidFlag == 13) || (pidFlag == 14))) { + if (cfgOpenPtEtaPhi) { + vhistPhiPtEtaNegKaCen[currentBin]->Fill(trk.phi(), trk.pt(), trk.eta()); + } + if (cfgOpenITSafter) { + if (cfgOpenITSTPCnSigma) { + vhistnSigmaITSTPCPtNegKaAfterCen[currentBin]->Fill(trk.nSigmaKaTPC(), trk.nSigmaKaITS(), trk.pt()); + } + if (cfgOpenClusSizenSigmaTPC) { + vhistAverClusterSizeCoslnSigmaTPCPtNegKaAfterCen[currentBin]->Fill(trk.nSigmaKaTPC(), trk.averClusterSizeCosl(), trk.pt()); + } + if (cfgOpenTOFITSnSigma) { + vhistnSigmaTOFITSPtNegKaAfterCen[currentBin]->Fill(trk.nSigmaKaTOF(), trk.nSigmaKaITS(), trk.pt()); + } + if (cfgOpenTOFTPCnSigma) { + vhistnSigmaTOFTPCPtNegKaAfterCen[currentBin]->Fill(trk.nSigmaKaTOF(), trk.nSigmaKaTPC(), trk.pt()); + } + } + } + if (cfgOpenITSTPCnSigma) { + vhistnSigmaITSTPCPtNegKaBeforeCen[currentBin]->Fill(trk.nSigmaKaTPC(), trk.nSigmaKaITS(), trk.pt()); + } + if (cfgOpenClusSizenSigmaTPC) { + vhistAverClusterSizeCoslnSigmaTPCPtNegKaBeforeCen[currentBin]->Fill(trk.nSigmaKaTPC(), trk.averClusterSizeCosl(), trk.pt()); + } + if (cfgOpenTOFITSnSigma) { + vhistnSigmaTOFITSPtNegKaBeforeCen[currentBin]->Fill(trk.nSigmaKaTOF(), trk.nSigmaKaITS(), trk.pt()); + } + if (cfgOpenTOFTPCnSigma) { + vhistnSigmaTOFTPCPtNegKaBeforeCen[currentBin]->Fill(trk.nSigmaKaTOF(), trk.nSigmaKaTPC(), trk.pt()); + } + } + } + } + if (cfgOpenPr) { + if ((pidFlag == 3) || (pidFlag == 6) || (pidFlag == 8) || (pidFlag == 9) || (pidFlag == 10) || (pidFlag == 12) || (pidFlag == 13) || (pidFlag == 14)) { + if (trk.sign() > 0) { + if (!((pidFlag == 6) || (pidFlag == 12) || (pidFlag == 13) || (pidFlag == 14))) { + if (cfgOpenPtEtaPhi) { + vhistPhiPtEtaPosPrCen[currentBin]->Fill(trk.phi(), trk.pt(), trk.eta()); + } + if (cfgOpenITSafter) { + if (cfgOpenITSTPCnSigma) { + vhistnSigmaITSTPCPtPosPrAfterCen[currentBin]->Fill(trk.nSigmaPrTPC(), trk.nSigmaPrITS(), trk.pt()); + } + if (cfgOpenClusSizenSigmaTPC) { + vhistAverClusterSizeCoslnSigmaTPCPtPosPrAfterCen[currentBin]->Fill(trk.nSigmaPrTPC(), trk.averClusterSizeCosl(), trk.pt()); + } + if (cfgOpenTOFITSnSigma) { + vhistnSigmaTOFITSPtPosPrAfterCen[currentBin]->Fill(trk.nSigmaPrTOF(), trk.nSigmaPrITS(), trk.pt()); + } + if (cfgOpenTOFTPCnSigma) { + vhistnSigmaTOFTPCPtPosPrAfterCen[currentBin]->Fill(trk.nSigmaPrTOF(), trk.nSigmaPrTPC(), trk.pt()); + } + } + } + if (cfgOpenITSTPCnSigma) { + vhistnSigmaITSTPCPtPosPrBeforeCen[currentBin]->Fill(trk.nSigmaPrTPC(), trk.nSigmaPrITS(), trk.pt()); + } + if (cfgOpenClusSizenSigmaTPC) { + vhistAverClusterSizeCoslnSigmaTPCPtPosPrBeforeCen[currentBin]->Fill(trk.nSigmaPrTPC(), trk.averClusterSizeCosl(), trk.pt()); + } + if (cfgOpenTOFITSnSigma) { + vhistnSigmaTOFITSPtPosPrBeforeCen[currentBin]->Fill(trk.nSigmaPrTOF(), trk.nSigmaPrITS(), trk.pt()); + } + if (cfgOpenTOFTPCnSigma) { + vhistnSigmaTOFTPCPtPosPrBeforeCen[currentBin]->Fill(trk.nSigmaPrTOF(), trk.nSigmaPrTPC(), trk.pt()); + } + } else if (trk.sign() < 0) { + if (!((pidFlag == 6) || (pidFlag == 12) || (pidFlag == 13) || (pidFlag == 14))) { + if (cfgOpenPtEtaPhi) { + vhistPhiPtEtaNegPrCen[currentBin]->Fill(trk.phi(), trk.pt(), trk.eta()); + } + if (cfgOpenITSafter) { + if (cfgOpenITSTPCnSigma) { + vhistnSigmaITSTPCPtNegPrAfterCen[currentBin]->Fill(trk.nSigmaPrTPC(), trk.nSigmaPrITS(), trk.pt()); + } + if (cfgOpenClusSizenSigmaTPC) { + vhistAverClusterSizeCoslnSigmaTPCPtNegPrAfterCen[currentBin]->Fill(trk.nSigmaPrTPC(), trk.averClusterSizeCosl(), trk.pt()); + } + if (cfgOpenTOFITSnSigma) { + vhistnSigmaTOFITSPtNegPrAfterCen[currentBin]->Fill(trk.nSigmaPrTOF(), trk.nSigmaPrITS(), trk.pt()); + } + if (cfgOpenTOFTPCnSigma) { + vhistnSigmaTOFTPCPtNegPrAfterCen[currentBin]->Fill(trk.nSigmaPrTOF(), trk.nSigmaPrTPC(), trk.pt()); + } + } + } + if (cfgOpenITSTPCnSigma) { + vhistnSigmaITSTPCPtNegPrBeforeCen[currentBin]->Fill(trk.nSigmaPrTPC(), trk.nSigmaPrITS(), trk.pt()); + } + if (cfgOpenClusSizenSigmaTPC) { + vhistAverClusterSizeCoslnSigmaTPCPtNegPrBeforeCen[currentBin]->Fill(trk.nSigmaPrTPC(), trk.averClusterSizeCosl(), trk.pt()); + } + if (cfgOpenTOFITSnSigma) { + vhistnSigmaTOFITSPtNegPrBeforeCen[currentBin]->Fill(trk.nSigmaPrTOF(), trk.nSigmaPrITS(), trk.pt()); + } + if (cfgOpenTOFTPCnSigma) { + vhistnSigmaTOFTPCPtNegPrBeforeCen[currentBin]->Fill(trk.nSigmaPrTOF(), trk.nSigmaPrTPC(), trk.pt()); + } + } + } + } + } + } + } + } +}; + +struct pidcme { // o2-linter: disable=name/struct(keep the saving dir name for offline analysis) + HistogramRegistry histosQA{"histosmain", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable> cfgnMods{"cfgnMods", {2}, "Modulation of interest"}; + Configurable cfgDetName{"cfgDetName", "FT0C", "The name of detector to be analyzed"}; + Configurable cfgRefAName{"cfgRefAName", "TPCpos", "The name of detector for reference A"}; + Configurable cfgRefBName{"cfgRefBName", "TPCneg", "The name of detector for reference B"}; + + Configurable cfgnTotalSystem{"cfgnTotalSystem", 7, "total qvector number"}; + Configurable cfgCutOccupancyLow{"cfgCutOccupancyLow", 0, "Low boundary cut on TPC occupancy"}; + Configurable cfgCutOccupancyHigh{"cfgCutOccupancyHigh", 3000, "High boundary cut on TPC occupancy"}; + + Configurable cfgVtzCut{"cfgVtzCut", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCentMin{"cfgCentMin", 0.0f, "Centrality min"}; + Configurable cfgCentMax{"cfgCentMax", 100.0f, "Centrality max"}; + Configurable cfgMinPt{"cfgMinPt", 0.15, "Minimum transverse momentum for charged track"}; + Configurable cfgMaxEta{"cfgMaxEta", 0.8, "Maximum pseudorapidiy for charged track"}; + Configurable cfgMaxDCArToPVcut{"cfgMaxDCArToPVcut", 0.1, "Maximum transverse DCA"}; + Configurable cfgMaxDCAzToPVcut{"cfgMaxDCAzToPVcut", 1.0, "Maximum longitudinal DCA"}; + + ConfigurableAxis cfgaxisQvecF{"cfgaxisQvecF", {300, -1, 1}, ""}; + ConfigurableAxis cfgaxisQvec{"cfgaxisQvec", {100, -3, 3}, ""}; + ConfigurableAxis cfgaxisCent{"cfgaxisCent", {100, 0, 100}, ""}; + + ConfigurableAxis cfgaxiscos{"cfgaxiscos", {102, -1.02, 1.02}, ""}; + ConfigurableAxis cfgaxispt{"cfgaxispt", {100, 0, 10}, ""}; + ConfigurableAxis cfgaxisCentMerged{"cfgaxisCentMerged", {20, 0, 100}, ""}; + ConfigurableAxis cfgaxisCentForQA{"cfgaxisCentForQA", {100, 0, 100}, "centrality for event QA"}; + ConfigurableAxis cfgaxisNch{"cfgaxisNch", {4000, 0, 4000}, "N_{ch}"}; + ConfigurableAxis cfgaxisT0C{"cfgaxisT0C", {70, 0, 70000}, "N_{ch} (T0C)"}; + ConfigurableAxis cfgaxisT0A{"cfgaxisT0A", {200, 0, 200000}, "N_{ch} (T0A)"}; + ConfigurableAxis cfgaxisNchPV{"cfgaxisNchPV", {4000, 0, 4000}, "N_{ch} (PV)"}; + ConfigurableAxis cfgaxisptPID{"cfgaxisptPID", {120, 0, 12}, "Binning for P_{t} PID"}; + ConfigurableAxis cfgnSigmaBinsTPC{"cfgnSigmaBinsTPC", {200, -5.f, 5.f}, "Binning for n sigma TPC"}; + ConfigurableAxis cfgnSigmaBinsITS{"cfgnSigmaBinsITS", {200, -5.f, 5.f}, "Binning for n sigma TPC"}; + + ConfigurableAxis cfgaxissumpt{"cfgaxissumpt", {16, 0, 16}, "Binning for #gamma and #delta sum p_{t}(particle1 + particle2)"}; + ConfigurableAxis cfgaxisdeltaeta{"cfgaxisdeltaeta", {16, -1.6, 1.6}, "Binning for #gamma and #delta #eta(particle1 - particle2)"}; + ConfigurableAxis cfgaxisdeltapt{"cfgaxisdeltapt", {16, -8, 8}, "Binning for #gamma and #delta p_{t}(particle1 - particle2)"}; + + Configurable cfgUseAdditionalEventCut{"cfgUseAdditionalEventCut", true, "Use additional event cut beyond sel8"}; + Configurable cfgOpenEvSelkIsGoodZvtxFT0vsPV{"cfgOpenEvSelkIsGoodZvtxFT0vsPV", true, "removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference, use this cut at low multiplicities with caution"}; + Configurable cfgOpenEvSelkNoSameBunchPileup{"cfgOpenEvSelkNoSameBunchPileup", true, "rejects collisions which are associated with the same found-by-T0 bunch crossing"}; + Configurable cfgOpenEvSelkNoCollInTimeRangeStandard{"cfgOpenEvSelkNoCollInTimeRangeStandard", true, "no collisions in specified time range"}; + Configurable cfgOpenEvSelkIsGoodITSLayersAll{"cfgOpenEvSelkIsGoodITSLayersAll", true, "cut time intervals with dead ITS staves"}; + Configurable cfgOpenEvSelkNoCollInRofStandard{"cfgOpenEvSelkNoCollInRofStandard", true, "no other collisions in this Readout Frame with per-collision multiplicity above threshold"}; + Configurable cfgOpenEvSelkNoHighMultCollInPrevRof{"cfgOpenEvSelkNoHighMultCollInPrevRof", true, "veto an event if FT0C amplitude in previous ITS ROF is above threshold"}; + Configurable cfgOpenEvSelOccupancy{"cfgOpenEvSelOccupancy", true, "Occupancy cut"}; + Configurable cfgOpenEvSelMultCorrelationPVTracks{"cfgOpenEvSelMultCorrelationPVTracks", true, "Multiplicity correlation cut for PVtracks vs centrality(FT0C)"}; + Configurable cfgOpenEvSelMultCorrelationGlobalTracks{"cfgOpenEvSelMultCorrelationGlobalTracks", false, "Multiplicity correlation cut for Globaltracks vs centrality(FT0C)"}; + Configurable cfgOpenEvSelV0AT0ACut{"cfgOpenEvSelV0AT0ACut", true, "V0A T0A 5 sigma cut"}; + Configurable cfgOpenFullEventQA{"cfgOpenFullEventQA", true, "Open full QA plots for event QA"}; + Configurable cfgkOpenV2{"cfgkOpenV2", true, "open V2 plots"}; + Configurable cfgkOpenCME{"cfgkOpenCME", true, "open PID CME"}; + Configurable cfgkOpenCMEDifferential{"cfgkOpenCMEDifferential", true, "open Differential plot(#delta pt, #delta eta, #average pt) for cme #delta and #gamma"}; + Configurable cfgkOpenDeltaPt{"cfgkOpenDeltaPt", true, "open CME Differential #Delta Pt"}; + Configurable cfgkOpenDeltaEta{"cfgkOpenDeltaEta", true, "open CME Differential #Delta Eta"}; + Configurable cfgkOpenAveragePt{"cfgkOpenAveragePt", true, "open CME Differential #Average Pt"}; + Configurable cfgkOpenPiPi{"cfgkOpenPiPi", true, "open Pi-Pi"}; + Configurable cfgkOpenKaKa{"cfgkOpenKaKa", true, "open Ka-Ka"}; + Configurable cfgkOpenPrPr{"cfgkOpenPrPr", true, "open Pr-Pr"}; + Configurable cfgkOpenPiKa{"cfgkOpenPiKa", true, "open Pi-Ka"}; + Configurable cfgkOpenPiPr{"cfgkOpenPiPr", true, "open Pi-Pr"}; + Configurable cfgkOpenKaPr{"cfgkOpenKaPr", true, "open Ka-Pr"}; + Configurable cfgkOpenHaHa{"cfgkOpenHaHa", true, "open Ha-Ha"}; + Configurable cfgkOpenSsOsCrossCheck{"cfgkOpenSsOsCrossCheck", false, "open check for matter an antimatter #gamma#delta"}; + Configurable cfgkOpenTPCITSPurityCut{"cfgkOpenTPCITSPurityCut", true, "open ITS-TPC purity cut"}; + Configurable cfgkOpenTPCITSPurityCutQA{"cfgkOpenTPCITSPurityCutQA", true, "open ITS-TPC purity cut QA plots"}; + Configurable cfgkOpenDebugPIDCME{"cfgkOpenDebugPIDCME", false, "open pidcme workflow debug mode"}; + Configurable cfgOpenPlotITSNcls{"cfgOpenPlotITSNcls", true, "open QA for overall ITSNcls distribution"}; + Configurable cfgOpenPlotITSNclsPtCent{"cfgOpenPlotITSNclsPtCent", false, "open QA for ITSNcls distribution vs centality and pt"}; + Configurable cfgOpenPlotTPCNcls{"cfgOpenPlotTPCNcls", true, "open QA for overall TPCNcls distribution"}; + Configurable cfgOpenPlotTPCNclsPtCent{"cfgOpenPlotTPCNclsPtCent", false, "open QA for TPCNcls distribution vs centality and pt"}; + Configurable cfgOpenCustomTrackCutAssurance{"cfgOpenCustomTrackCutAssurance", true, "Assure track using for v2 and cme pass the custom track cuts"}; + + Configurable> cfgITSPurityCen{"cfgITSPurityCen", {20, 30}, "ITS purity cut centrality"}; + Configurable> cfgPtPrCut{"cfgPtPrCut", {0.5, 0.6, 0.7, 0.8, 0.9}, "pt binings for proton ITS purity cut"}; + Configurable cfgCCDBPurityPath{"cfgCCDBPurityPath", "Users/z/zhengqiw/PurityCut", "CCDB path for nsigmaITS - nSigmaTPC purity cut"}; + Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + Service ccdb; + EventPlaneHelper helperEP; + SliceCache cache; + + unsigned int mult1, mult2, mult3; + int detId; + int refAId; + int refBId; + // Additional Event selection cuts - Copy from flowGenericFramework.cxx + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + TF1* fMultCutLow = nullptr; + TF1* fMultCutHigh = nullptr; + TF1* fMultMultPVCut = nullptr; + TF1* fT0AV0AMean = nullptr; + TF1* fT0AV0ASigma = nullptr; + // vectors for ITS-TPC contanmination cut + std::vector>> hPosPrCut; + std::vector>> hNegPrCut; + + template + int getDetId(const T& name) + { + if (name.value == "BPos" || name.value == "BNeg" || name.value == "BTot") { + LOGF(warning, "Using deprecated label: %s. Please use TPCpos, TPCneg, TPCall instead.", name.value); + } + if (name.value == "FT0C") { + return 0; + } else if (name.value == "FT0A") { + return 1; + } else if (name.value == "FT0M") { + return 2; + } else if (name.value == "FV0A") { + return 3; + } else if (name.value == "TPCpos" || name.value == "BPos") { + return 4; + } else if (name.value == "TPCneg" || name.value == "BNeg") { + return 5; + } else if (name.value == "TPCall" || name.value == "BTot") { + return 6; + } else { + return 0; + } + } + + Filter collisionFilter = (nabs(aod::collision::posZ) < cfgVtzCut) && (aod::cent::centFT0C > cfgCentMin) && (aod::cent::centFT0C < cfgCentMax); + Filter ptfilter = aod::track::pt > cfgMinPt; + Filter etafilter = aod::track::eta < cfgMaxEta; + Filter properPIDfilter = aod::cme_track_pid_columns::nPidFlag >= (int8_t)0; + + Partition>> tracksSet1 = ((aod::cme_track_pid_columns::nPidFlag == 1) || (aod::cme_track_pid_columns::nPidFlag == 7) || (aod::cme_track_pid_columns::nPidFlag == 8) || (aod::cme_track_pid_columns::nPidFlag == 10)); + Partition>> tracksSet2 = ((aod::cme_track_pid_columns::nPidFlag == 2) || (aod::cme_track_pid_columns::nPidFlag == 7) || (aod::cme_track_pid_columns::nPidFlag == 9) || (aod::cme_track_pid_columns::nPidFlag == 10)); + Partition>> tracksSet3 = ((aod::cme_track_pid_columns::nPidFlag == 3) || (aod::cme_track_pid_columns::nPidFlag == 8) || (aod::cme_track_pid_columns::nPidFlag == 9) || (aod::cme_track_pid_columns::nPidFlag == 10)); + void init(InitContext const&) + { + + ccdb->setURL(ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(ccdbNoLaterThan.value); + ccdb->setFatalWhenNull(false); + + detId = getDetId(cfgDetName); + refAId = getDetId(cfgRefAName); + refBId = getDetId(cfgRefBName); + + if (detId == refAId || detId == refBId || refAId == refBId) { + LOGF(info, "Wrong detector configuration \n The FT0C will be used to get Q-Vector \n The TPCpos and TPCneg will be used as reference systems"); + detId = 0; + refAId = 4; + refBId = 5; + } + + if (cfgUseAdditionalEventCut) { + fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x - 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); + fMultPVCutLow->SetParameters(3257.29, -121.848, 1.98492, -0.0172128, 6.47528e-05, 154.756, -1.86072, -0.0274713, 0.000633499, -3.37757e-06); + fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x + 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); + fMultPVCutHigh->SetParameters(3257.29, -121.848, 1.98492, -0.0172128, 6.47528e-05, 154.756, -1.86072, -0.0274713, 0.000633499, -3.37757e-06); + + fMultCutLow = new TF1("fMultCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultCutLow->SetParameters(1654.46, -47.2379, 0.449833, -0.0014125, 150.773, -3.67334, 0.0530503, -0.000614061, 3.15956e-06); + fMultCutHigh = new TF1("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 3.*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultCutHigh->SetParameters(1654.46, -47.2379, 0.449833, -0.0014125, 150.773, -3.67334, 0.0530503, -0.000614061, 3.15956e-06); + + fT0AV0AMean = new TF1("fT0AV0AMean", "[0]+[1]*x", 0, 200000); + fT0AV0AMean->SetParameters(-1601.0581, 9.417652e-01); + fT0AV0ASigma = new TF1("fT0AV0ASigma", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 200000); + fT0AV0ASigma->SetParameters(463.4144, 6.796509e-02, -9.097136e-07, 7.971088e-12, -2.600581e-17); + } + + AxisSpec axisCent{cfgaxisCent, "centrality"}; + AxisSpec axisQvec{cfgaxisQvec, "Q"}; + AxisSpec axisQvecF{cfgaxisQvecF, "Q"}; + AxisSpec axisEvtPl = {100, -1.0 * constants::math::PI, constants::math::PI}; + + AxisSpec axisCos{cfgaxiscos, "angle function"}; + AxisSpec axisPt{cfgaxispt, "trasverse momentum"}; + AxisSpec axisCentMerged{cfgaxisCentMerged, "merged centrality for cme and PID v2"}; + + AxisSpec axissumpt{cfgaxissumpt, "#it{p}_{T}^{sum}"}; + AxisSpec axisdeltaeta{cfgaxisdeltaeta, "#Delta#eta"}; + AxisSpec axisdeltapt{cfgaxisdeltapt, "#Delta#it{p}_{T}"}; + AxisSpec axisvertexz = {100, -15., 15., "vrtx_{Z} [cm]"}; + AxisSpec axisITSNcls = {10, -0.5, 9.5, "ITSNcls"}; + AxisSpec axisTPCNcls = {160, 0, 160, "TPCNcls"}; + + histosQA.add(Form("QA/histEventCount"), "", {HistType::kTH1F, {{3, 0.0, 3.0}}}); + histosQA.get(HIST("QA/histEventCount"))->GetXaxis()->SetBinLabel(1, "Filtered event"); + histosQA.get(HIST("QA/histEventCount"))->GetXaxis()->SetBinLabel(2, "after sel8"); + histosQA.get(HIST("QA/histEventCount"))->GetXaxis()->SetBinLabel(3, "after additional event cut"); + if (cfgUseAdditionalEventCut) { + histosQA.add(Form("QA/histEventCountDetail"), "Number of Event;; Count", {HistType::kTH1F, {{11, 0, 11}}}); + histosQA.get(HIST("QA/histEventCountDetail"))->GetXaxis()->SetBinLabel(1, "after sel8"); + histosQA.get(HIST("QA/histEventCountDetail"))->GetXaxis()->SetBinLabel(2, "kIsGoodZvtxFT0vsPV"); + histosQA.get(HIST("QA/histEventCountDetail"))->GetXaxis()->SetBinLabel(3, "kNoSameBunchPileup"); + histosQA.get(HIST("QA/histEventCountDetail"))->GetXaxis()->SetBinLabel(4, "kNoCollInTimeRangeStandard"); + histosQA.get(HIST("QA/histEventCountDetail"))->GetXaxis()->SetBinLabel(5, "kIsGoodITSLayersAll"); + histosQA.get(HIST("QA/histEventCountDetail"))->GetXaxis()->SetBinLabel(6, "kNoCollInRofStandard"); + histosQA.get(HIST("QA/histEventCountDetail"))->GetXaxis()->SetBinLabel(7, "kNoHighMultCollInPrevRof"); + histosQA.get(HIST("QA/histEventCountDetail"))->GetXaxis()->SetBinLabel(8, "occupancy"); + histosQA.get(HIST("QA/histEventCountDetail"))->GetXaxis()->SetBinLabel(9, "MultCorrelationPVTracks"); + histosQA.get(HIST("QA/histEventCountDetail"))->GetXaxis()->SetBinLabel(10, "MultCorrelationGlobalTracks"); + histosQA.get(HIST("QA/histEventCountDetail"))->GetXaxis()->SetBinLabel(11, "cfgEvSelV0AT0ACut"); + } + if (cfgOpenFullEventQA) { + histosQA.add("QA/hist_globalTracks_centT0C_before", "before cut;Centrality T0C;mulplicity global tracks", {HistType::kTH2D, {cfgaxisCentForQA, cfgaxisNch}}); + histosQA.add("QA/hist_PVTracks_centT0C_before", "before cut;Centrality T0C;mulplicity PV tracks", {HistType::kTH2D, {cfgaxisCentForQA, cfgaxisNchPV}}); + histosQA.add("QA/hist_globalTracks_PVTracks_before", "before cut;mulplicity PV tracks;mulplicity global tracks", {HistType::kTH2D, {cfgaxisNchPV, cfgaxisNch}}); + histosQA.add("QA/hist_globalTracks_multT0A_before", "before cut;mulplicity T0A;mulplicity global tracks", {HistType::kTH2D, {cfgaxisT0A, cfgaxisNch}}); + histosQA.add("QA/hist_globalTracks_multV0A_before", "before cut;mulplicity V0A;mulplicity global tracks", {HistType::kTH2D, {cfgaxisT0A, cfgaxisNch}}); + histosQA.add("QA/hist_multV0A_multT0A_before", "before cut;mulplicity T0A;mulplicity V0A", {HistType::kTH2D, {cfgaxisT0A, cfgaxisT0A}}); + histosQA.add("QA/hist_multT0C_centT0C_before", "before cut;Centrality T0C;mulplicity T0C", {HistType::kTH2D, {cfgaxisCentForQA, cfgaxisT0C}}); + histosQA.add("QA/hist_globalTracks_centT0C_after", "after cut;Centrality T0C;mulplicity global tracks", {HistType::kTH2D, {cfgaxisCentForQA, cfgaxisNch}}); + histosQA.add("QA/hist_PVTracks_centT0C_after", "after cut;Centrality T0C;mulplicity PV tracks", {HistType::kTH2D, {cfgaxisCentForQA, cfgaxisNchPV}}); + histosQA.add("QA/hist_globalTracks_PVTracks_after", "after cut;mulplicity PV tracks;mulplicity global tracks", {HistType::kTH2D, {cfgaxisNchPV, cfgaxisNch}}); + histosQA.add("QA/hist_globalTracks_multT0A_after", "after cut;mulplicity T0A;mulplicity global tracks", {HistType::kTH2D, {cfgaxisT0A, cfgaxisNch}}); + histosQA.add("QA/hist_globalTracks_multV0A_after", "after cut;mulplicity V0A;mulplicity global tracks", {HistType::kTH2D, {cfgaxisT0A, cfgaxisNch}}); + histosQA.add("QA/hist_multV0A_multT0A_after", "after cut;mulplicity T0A;mulplicity V0A", {HistType::kTH2D, {cfgaxisT0A, cfgaxisT0A}}); + histosQA.add("QA/hist_multT0C_centT0C_after", "after cut;Centrality T0C;mulplicity T0C", {HistType::kTH2D, {cfgaxisCentForQA, cfgaxisT0C}}); + } + histosQA.add(Form("QA/histVertexZRec"), "", {HistType::kTH1F, {axisvertexz}}); + histosQA.add(Form("QA/histCentrality"), "", {HistType::kTH1F, {axisCent}}); + histosQA.add(Form("QA/histQvec_CorrL0_V2"), "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); + histosQA.add(Form("QA/histQvec_CorrL1_V2"), "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); + histosQA.add(Form("QA/histQvec_CorrL2_V2"), "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); + histosQA.add(Form("QA/histQvec_CorrL3_V2"), "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); + histosQA.add(Form("QA/histEvtPl_CorrL0_V2"), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("QA/histEvtPl_CorrL1_V2"), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("QA/histEvtPl_CorrL2_V2"), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("QA/histEvtPl_CorrL3_V2"), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("QA/histQvecRes_SigRefAV2"), "", {HistType::kTH2F, {axisQvecF, axisCent}}); + histosQA.add(Form("QA/histQvecRes_SigRefBV2"), "", {HistType::kTH2F, {axisQvecF, axisCent}}); + histosQA.add(Form("QA/histQvecRes_RefARefBV2"), "", {HistType::kTH2F, {axisQvecF, axisCent}}); + + if (cfgkOpenV2) { + histosQA.add(Form("V2/histCosDetV2"), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisCos}}); + histosQA.add(Form("V2/histSinDetV2"), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisCos}}); + histosQA.add(Form("V2/PID/histCosDetV2_Pi"), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisCos}}); + histosQA.add(Form("V2/PID/histCosDetV2_Ka"), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisCos}}); + histosQA.add(Form("V2/PID/histCosDetV2_Pr"), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisCos}}); + histosQA.add(Form("V2/PID/histCosDetV2_Pi_Neg"), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisCos}}); + histosQA.add(Form("V2/PID/histCosDetV2_Ka_Neg"), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisCos}}); + histosQA.add(Form("V2/PID/histCosDetV2_Pr_Neg"), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisCos}}); + } + + if (cfgkOpenTPCITSPurityCut && cfgkOpenTPCITSPurityCutQA) { + histosQA.add(Form("QA/histITSPuritycheck_Pr_Pos_Cen_20_30"), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgnSigmaBinsITS, cfgaxisptPID}}); + histosQA.add(Form("QA/histITSPuritycheck_Pr_Neg_Cen_20_30"), ";n#sigma_{TPC};n#sigma_{ITS};#p_{t}", {HistType::kTH3F, {cfgnSigmaBinsTPC, cfgnSigmaBinsITS, cfgaxisptPID}}); + } + if (cfgOpenPlotITSNcls) { + histosQA.add(Form("QA/histITSNcls_PosPi"), ";ITSNcls;counts", {HistType::kTH1F, {axisITSNcls}}); + histosQA.add(Form("QA/histITSNcls_NegPi"), ";ITSNcls;counts", {HistType::kTH1F, {axisITSNcls}}); + histosQA.add(Form("QA/histITSNcls_PosKa"), ";ITSNcls;counts", {HistType::kTH1F, {axisITSNcls}}); + histosQA.add(Form("QA/histITSNcls_NegKa"), ";ITSNcls;counts", {HistType::kTH1F, {axisITSNcls}}); + histosQA.add(Form("QA/histITSNcls_PosPr"), ";ITSNcls;counts", {HistType::kTH1F, {axisITSNcls}}); + histosQA.add(Form("QA/histITSNcls_NegPr"), ";ITSNcls;counts", {HistType::kTH1F, {axisITSNcls}}); + } + if (cfgOpenPlotITSNclsPtCent) { + histosQA.add(Form("QA/histITSNclsPtCent_PosPi"), ";ITSNcls;Pt;Centrality", {HistType::kTH3F, {axisITSNcls, axisPt, axisCentMerged}}); + histosQA.add(Form("QA/histITSNclsPtCent_NegPi"), ";ITSNcls;Pt;Centrality", {HistType::kTH3F, {axisITSNcls, axisPt, axisCentMerged}}); + histosQA.add(Form("QA/histITSNclsPtCent_PosKa"), ";ITSNcls;Pt;Centrality", {HistType::kTH3F, {axisITSNcls, axisPt, axisCentMerged}}); + histosQA.add(Form("QA/histITSNclsPtCent_NegKa"), ";ITSNcls;Pt;Centrality", {HistType::kTH3F, {axisITSNcls, axisPt, axisCentMerged}}); + histosQA.add(Form("QA/histITSNclsPtCent_PosPr"), ";ITSNcls;Pt;Centrality", {HistType::kTH3F, {axisITSNcls, axisPt, axisCentMerged}}); + histosQA.add(Form("QA/histITSNclsPtCent_NegPr"), ";ITSNcls;Pt;Centrality", {HistType::kTH3F, {axisITSNcls, axisPt, axisCentMerged}}); + } + if (cfgOpenPlotTPCNcls) { + histosQA.add(Form("QA/histTPCNcls_PosPi"), ";TPCNcls;counts", {HistType::kTH1F, {axisTPCNcls}}); + histosQA.add(Form("QA/histTPCNcls_NegPi"), ";TPCNcls;counts", {HistType::kTH1F, {axisTPCNcls}}); + histosQA.add(Form("QA/histTPCNcls_PosKa"), ";TPCNcls;counts", {HistType::kTH1F, {axisTPCNcls}}); + histosQA.add(Form("QA/histTPCNcls_NegKa"), ";TPCNcls;counts", {HistType::kTH1F, {axisTPCNcls}}); + histosQA.add(Form("QA/histTPCNcls_PosPr"), ";TPCNcls;counts", {HistType::kTH1F, {axisTPCNcls}}); + histosQA.add(Form("QA/histTPCNcls_NegPr"), ";TPCNcls;counts", {HistType::kTH1F, {axisTPCNcls}}); + } + if (cfgOpenPlotTPCNclsPtCent) { + histosQA.add(Form("QA/histTPCNclsPtCent_PosPi"), ";TPCNcls;Pt;Centrality", {HistType::kTH3F, {axisTPCNcls, axisPt, axisCentMerged}}); + histosQA.add(Form("QA/histTPCNclsPtCent_NegPi"), ";TPCNcls;Pt;Centrality", {HistType::kTH3F, {axisTPCNcls, axisPt, axisCentMerged}}); + histosQA.add(Form("QA/histTPCNclsPtCent_PosKa"), ";TPCNcls;Pt;Centrality", {HistType::kTH3F, {axisTPCNcls, axisPt, axisCentMerged}}); + histosQA.add(Form("QA/histTPCNclsPtCent_NegKa"), ";TPCNcls;Pt;Centrality", {HistType::kTH3F, {axisTPCNcls, axisPt, axisCentMerged}}); + histosQA.add(Form("QA/histTPCNclsPtCent_PosPr"), ";TPCNcls;Pt;Centrality", {HistType::kTH3F, {axisTPCNcls, axisPt, axisCentMerged}}); + histosQA.add(Form("QA/histTPCNclsPtCent_NegPr"), ";TPCNcls;Pt;Centrality", {HistType::kTH3F, {axisTPCNcls, axisPt, axisCentMerged}}); + } + + if (cfgkOpenCME) { + if (cfgkOpenPiPi) { + histosQA.add(Form("PIDCME/histgamma_PiPi_ss"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_PiPi_os"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiPi_ss"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiPi_os"), "", {HistType::kTProfile, {axisCentMerged}}); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.add("PIDCME/Differential/histgamma_PiPi_ss_DPt", ";centrality;#Delta #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histgamma_PiPi_os_DPt", ";centrality;#Delta #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histdelta_PiPi_ss_DPt", ";centrality;#Delta #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histdelta_PiPi_os_DPt", ";centrality;#Delta #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + } + if (cfgkOpenDeltaEta) { + histosQA.add("PIDCME/Differential/histgamma_PiPi_ss_DEt", ";centrality;#Delta #eta;#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histgamma_PiPi_os_DEt", ";centrality;#Delta #eta;#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histdelta_PiPi_ss_DEt", ";centrality;#Delta #eta;#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histdelta_PiPi_os_DEt", ";centrality;#Delta #eta;#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + } + if (cfgkOpenAveragePt) { + histosQA.add("PIDCME/Differential/histgamma_PiPi_ss_SPt", ";centrality;Sum #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histgamma_PiPi_os_SPt", ";centrality;Sum #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histdelta_PiPi_ss_SPt", ";centrality;Sum #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histdelta_PiPi_os_SPt", ";centrality;Sum #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + } + } + if (cfgkOpenSsOsCrossCheck) { + histosQA.add(Form("PIDCME/histgamma_PiPi_PP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_PiPi_NN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_PiPi_PN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_PiPi_NP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiPi_PP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiPi_NN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiPi_PN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiPi_NP"), "", {HistType::kTProfile, {axisCentMerged}}); + } + } + if (cfgkOpenKaKa) { + histosQA.add(Form("PIDCME/histgamma_KaKa_ss"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_KaKa_os"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_KaKa_ss"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_KaKa_os"), "", {HistType::kTProfile, {axisCentMerged}}); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.add("PIDCME/Differential/histgamma_KaKa_ss_DPt", ";centrality;#Delta #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histgamma_KaKa_os_DPt", ";centrality;#Delta #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histdelta_KaKa_ss_DPt", ";centrality;#Delta #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histdelta_KaKa_os_DPt", ";centrality;#Delta #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + } + if (cfgkOpenDeltaEta) { + histosQA.add("PIDCME/Differential/histgamma_KaKa_ss_DEt", ";centrality;#Delta #eta;#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histgamma_KaKa_os_DEt", ";centrality;#Delta #eta;#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histdelta_KaKa_ss_DEt", ";centrality;#Delta #eta;#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histdelta_KaKa_os_DEt", ";centrality;#Delta #eta;#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + } + if (cfgkOpenAveragePt) { + histosQA.add("PIDCME/Differential/histgamma_KaKa_ss_SPt", ";centrality;Sum #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histgamma_KaKa_os_SPt", ";centrality;Sum #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histdelta_KaKa_ss_SPt", ";centrality;Sum #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histdelta_KaKa_os_SPt", ";centrality;Sum #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + } + } + if (cfgkOpenSsOsCrossCheck) { + histosQA.add(Form("PIDCME/histgamma_KaKa_PP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_KaKa_NN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_KaKa_PN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_KaKa_NP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_KaKa_PP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_KaKa_NN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_KaKa_PN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_KaKa_NP"), "", {HistType::kTProfile, {axisCentMerged}}); + } + } + if (cfgkOpenPrPr) { + histosQA.add(Form("PIDCME/histgamma_PrPr_ss"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_PrPr_os"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PrPr_ss"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PrPr_os"), "", {HistType::kTProfile, {axisCentMerged}}); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.add("PIDCME/Differential/histgamma_PrPr_ss_DPt", ";centrality;#Delta #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histgamma_PrPr_os_DPt", ";centrality;#Delta #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histdelta_PrPr_ss_DPt", ";centrality;#Delta #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histdelta_PrPr_os_DPt", ";centrality;#Delta #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + } + if (cfgkOpenDeltaEta) { + histosQA.add("PIDCME/Differential/histgamma_PrPr_ss_DEt", ";centrality;#Delta #eta;#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histgamma_PrPr_os_DEt", ";centrality;#Delta #eta;#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histdelta_PrPr_ss_DEt", ";centrality;#Delta #eta;#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histdelta_PrPr_os_DEt", ";centrality;#Delta #eta;#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + } + if (cfgkOpenAveragePt) { + histosQA.add("PIDCME/Differential/histgamma_PrPr_ss_SPt", ";centrality;Sum #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histgamma_PrPr_os_SPt", ";centrality;Sum #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histdelta_PrPr_ss_SPt", ";centrality;Sum #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histdelta_PrPr_os_SPt", ";centrality;Sum #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + } + } + if (cfgkOpenSsOsCrossCheck) { + histosQA.add(Form("PIDCME/histgamma_PrPr_PP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_PrPr_NN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_PrPr_PN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_PrPr_NP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PrPr_PP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PrPr_NN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PrPr_PN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PrPr_NP"), "", {HistType::kTProfile, {axisCentMerged}}); + } + } + if (cfgkOpenPiKa) { + histosQA.add(Form("PIDCME/histgamma_PiKa_ss"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_PiKa_os"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiKa_ss"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiKa_os"), "", {HistType::kTProfile, {axisCentMerged}}); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.add("PIDCME/Differential/histgamma_PiKa_ss_DPt", ";centrality;#Delta #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histgamma_PiKa_os_DPt", ";centrality;#Delta #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histdelta_PiKa_ss_DPt", ";centrality;#Delta #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histdelta_PiKa_os_DPt", ";centrality;#Delta #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + } + if (cfgkOpenDeltaEta) { + histosQA.add("PIDCME/Differential/histgamma_PiKa_ss_DEt", ";centrality;#Delta #eta;#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histgamma_PiKa_os_DEt", ";centrality;#Delta #eta;#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histdelta_PiKa_ss_DEt", ";centrality;#Delta #eta;#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histdelta_PiKa_os_DEt", ";centrality;#Delta #eta;#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + } + if (cfgkOpenAveragePt) { + histosQA.add("PIDCME/Differential/histgamma_PiKa_ss_SPt", ";centrality;Sum #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histgamma_PiKa_os_SPt", ";centrality;Sum #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histdelta_PiKa_ss_SPt", ";centrality;Sum #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histdelta_PiKa_os_SPt", ";centrality;Sum #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + } + } + if (cfgkOpenSsOsCrossCheck) { + histosQA.add(Form("PIDCME/histgamma_PiKa_PP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_PiKa_NN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_PiKa_PN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_PiKa_NP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiKa_PP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiKa_NN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiKa_PN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiKa_NP"), "", {HistType::kTProfile, {axisCentMerged}}); + } + } + if (cfgkOpenPiPr) { + histosQA.add(Form("PIDCME/histgamma_PiPr_ss"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_PiPr_os"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiPr_ss"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiPr_os"), "", {HistType::kTProfile, {axisCentMerged}}); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.add("PIDCME/Differential/histgamma_PiPr_ss_DPt", ";centrality;#Delta #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histgamma_PiPr_os_DPt", ";centrality;#Delta #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histdelta_PiPr_ss_DPt", ";centrality;#Delta #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histdelta_PiPr_os_DPt", ";centrality;#Delta #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + } + if (cfgkOpenDeltaEta) { + histosQA.add("PIDCME/Differential/histgamma_PiPr_ss_DEt", ";centrality;#Delta #eta;#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histgamma_PiPr_os_DEt", ";centrality;#Delta #eta;#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histdelta_PiPr_ss_DEt", ";centrality;#Delta #eta;#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histdelta_PiPr_os_DEt", ";centrality;#Delta #eta;#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + } + if (cfgkOpenAveragePt) { + histosQA.add("PIDCME/Differential/histgamma_PiPr_ss_SPt", ";centrality;Sum #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histgamma_PiPr_os_SPt", ";centrality;Sum #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histdelta_PiPr_ss_SPt", ";centrality;Sum #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histdelta_PiPr_os_SPt", ";centrality;Sum #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + } + } + if (cfgkOpenSsOsCrossCheck) { + histosQA.add(Form("PIDCME/histgamma_PiPr_PP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_PiPr_NN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_PiPr_PN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_PiPr_NP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiPr_PP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiPr_NN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiPr_PN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_PiPr_NP"), "", {HistType::kTProfile, {axisCentMerged}}); + } + } + if (cfgkOpenKaPr) { + histosQA.add(Form("PIDCME/histgamma_KaPr_ss"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_KaPr_os"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_KaPr_ss"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_KaPr_os"), "", {HistType::kTProfile, {axisCentMerged}}); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.add("PIDCME/Differential/histgamma_KaPr_ss_DPt", ";centrality;#Delta #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histgamma_KaPr_os_DPt", ";centrality;#Delta #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histdelta_KaPr_ss_DPt", ";centrality;#Delta #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histdelta_KaPr_os_DPt", ";centrality;#Delta #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + } + if (cfgkOpenDeltaEta) { + histosQA.add("PIDCME/Differential/histgamma_KaPr_ss_DEt", ";centrality;#Delta #eta;#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histgamma_KaPr_os_DEt", ";centrality;#Delta #eta;#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histdelta_KaPr_ss_DEt", ";centrality;#Delta #eta;#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histdelta_KaPr_os_DEt", ";centrality;#Delta #eta;#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + } + if (cfgkOpenAveragePt) { + histosQA.add("PIDCME/Differential/histgamma_KaPr_ss_SPt", ";centrality;Sum #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histgamma_KaPr_os_SPt", ";centrality;Sum #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histdelta_KaPr_ss_SPt", ";centrality;Sum #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histdelta_KaPr_os_SPt", ";centrality;Sum #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + } + } + if (cfgkOpenSsOsCrossCheck) { + histosQA.add(Form("PIDCME/histgamma_KaPr_PP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_KaPr_NN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_KaPr_PN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_KaPr_NP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_KaPr_PP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_KaPr_NN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_KaPr_PN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_KaPr_NP"), "", {HistType::kTProfile, {axisCentMerged}}); + } + } + if (cfgkOpenHaHa) { + histosQA.add(Form("PIDCME/histgamma_HaHa_ss"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_HaHa_os"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_HaHa_ss"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_HaHa_os"), "", {HistType::kTProfile, {axisCentMerged}}); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.add("PIDCME/Differential/histgamma_HaHa_ss_DPt", ";centrality;#Delta #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histgamma_HaHa_os_DPt", ";centrality;#Delta #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histdelta_HaHa_ss_DPt", ";centrality;#Delta #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + histosQA.add("PIDCME/Differential/histdelta_HaHa_os_DPt", ";centrality;#Delta #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltapt}}); + } + if (cfgkOpenDeltaEta) { + histosQA.add("PIDCME/Differential/histgamma_HaHa_ss_DEt", ";centrality;#Delta #eta;#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histgamma_HaHa_os_DEt", ";centrality;#Delta #eta;#gamma", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histdelta_HaHa_ss_DEt", ";centrality;#Delta #eta;#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + histosQA.add("PIDCME/Differential/histdelta_HaHa_os_DEt", ";centrality;#Delta #eta;#delta", {HistType::kTProfile2D, {axisCentMerged, axisdeltaeta}}); + } + if (cfgkOpenAveragePt) { + histosQA.add("PIDCME/Differential/histgamma_HaHa_ss_SPt", ";centrality;Sum #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histgamma_HaHa_os_SPt", ";centrality;Sum #p_{T};#gamma", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histdelta_HaHa_ss_SPt", ";centrality;Sum #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + histosQA.add("PIDCME/Differential/histdelta_HaHa_os_SPt", ";centrality;Sum #p_{T};#delta", {HistType::kTProfile2D, {axisCentMerged, axissumpt}}); + } + } + if (cfgkOpenSsOsCrossCheck) { + histosQA.add(Form("PIDCME/histgamma_HaHa_PP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_HaHa_NN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_HaHa_PN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histgamma_HaHa_NP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_HaHa_PP"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_HaHa_NN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_HaHa_PN"), "", {HistType::kTProfile, {axisCentMerged}}); + histosQA.add(Form("PIDCME/histdelta_HaHa_NP"), "", {HistType::kTProfile, {axisCentMerged}}); + } + } + } + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + std::string fullPath; + auto timestamp = bc.timestamp(); + // hPosPrCut.clear(); + // hNegPrCut.clear(); + for (auto i = 0; i < static_cast(cfgITSPurityCen->size()) - 1; i++) { + std::vector> hPosPrCutCen; + std::vector> hNegPrCutCen; + for (auto j = 0; j < static_cast(cfgPtPrCut->size()) - 1; j++) { + fullPath = cfgCCDBPurityPath; + fullPath += Form("/ProtonPos/Cen_%d_%d/Pt_%d_%d", cfgITSPurityCen->at(i), cfgITSPurityCen->at(i + 1), static_cast(std::round(1e3 * cfgPtPrCut->at(j))), static_cast(std::round(1e3 * cfgPtPrCut->at(j + 1)))); + auto posPrHist = ccdb->getForTimeStamp(fullPath, timestamp); + fullPath = cfgCCDBPurityPath; + fullPath += Form("/ProtonNeg/Cen_%d_%d/Pt_%d_%d", cfgITSPurityCen->at(i), cfgITSPurityCen->at(i + 1), static_cast(std::round(1e3 * cfgPtPrCut->at(j))), static_cast(std::round(1e3 * cfgPtPrCut->at(j + 1)))); + auto negPrHist = ccdb->getForTimeStamp(fullPath, timestamp); + if (!posPrHist) { + LOGF(fatal, Form("could not load Pos Proton ITS TPC purity hist for Cent_%d_%d Pt_%d_%d(MeV)", cfgITSPurityCen->at(i), cfgITSPurityCen->at(i + 1), static_cast(std::round(1e3 * cfgPtPrCut->at(j))), static_cast(std::round(1e3 * cfgPtPrCut->at(j + 1))))); + } + if (!negPrHist) { + LOGF(fatal, Form("could not load Neg Proton ITS TPC purity hist for Cent_%d_%d Pt_%d_%d(MeV)", cfgITSPurityCen->at(i), cfgITSPurityCen->at(i + 1), static_cast(std::round(1e3 * cfgPtPrCut->at(j))), static_cast(std::round(1e3 * cfgPtPrCut->at(j + 1))))); + } + std::shared_ptr sharedPosPrHist(posPrHist); + std::shared_ptr sharedNegPrHist(negPrHist); + hPosPrCutCen.push_back(std::move(sharedPosPrHist)); + hNegPrCutCen.push_back(std::move(sharedNegPrHist)); + } + hPosPrCut.push_back(std::move(hPosPrCutCen)); + hNegPrCut.push_back(std::move(hNegPrCutCen)); + } + } + + template + bool selEvent(const CollType& collision, const int multTrk, const float centrality) + { + histosQA.fill(HIST("QA/histEventCountDetail"), 0.5); + if (cfgOpenEvSelkIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return 0; + } + if (cfgOpenEvSelkIsGoodZvtxFT0vsPV) { + histosQA.fill(HIST("QA/histEventCountDetail"), 1.5); + } + if (cfgOpenEvSelkNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return 0; + } + if (cfgOpenEvSelkNoSameBunchPileup) { + histosQA.fill(HIST("QA/histEventCountDetail"), 2.5); + } + if (cfgOpenEvSelkNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return 0; + } + if (cfgOpenEvSelkNoCollInTimeRangeStandard) { + histosQA.fill(HIST("QA/histEventCountDetail"), 3.5); + } + if (cfgOpenEvSelkIsGoodITSLayersAll && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return 0; + } + if (cfgOpenEvSelkIsGoodITSLayersAll) { + histosQA.fill(HIST("QA/histEventCountDetail"), 4.5); + } + if (cfgOpenEvSelkNoCollInRofStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return 0; + } + if (cfgOpenEvSelkNoCollInRofStandard) { + histosQA.fill(HIST("QA/histEventCountDetail"), 5.5); + } + if (cfgOpenEvSelkNoHighMultCollInPrevRof && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + return 0; + } + if (cfgOpenEvSelkNoHighMultCollInPrevRof) { + histosQA.fill(HIST("QA/histEventCountDetail"), 6.5); + } + auto multNTracksPV = collision.multNTracksPV(); + auto occupancy = collision.trackOccupancyInTimeRange(); + if (cfgOpenEvSelOccupancy && (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh)) { + return 0; + } + if (cfgOpenEvSelOccupancy) { + histosQA.fill(HIST("QA/histEventCountDetail"), 7.5); + } + if (cfgOpenEvSelMultCorrelationPVTracks) { + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) + return 0; + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) + return 0; + } + if (cfgOpenEvSelMultCorrelationPVTracks) { + histosQA.fill(HIST("QA/histEventCountDetail"), 8.5); + } + if (cfgOpenEvSelMultCorrelationGlobalTracks) { + if (multTrk < fMultCutLow->Eval(centrality)) + return 0; + if (multTrk > fMultCutHigh->Eval(centrality)) + return 0; + } + if (cfgOpenEvSelMultCorrelationGlobalTracks) { + histosQA.fill(HIST("QA/histEventCountDetail"), 9.5); + } + if (cfgOpenEvSelV0AT0ACut && (std::fabs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > 5 * fT0AV0ASigma->Eval(collision.multFT0A()))) { + return 0; + } + if (cfgOpenEvSelV0AT0ACut) { + histosQA.fill(HIST("QA/histEventCountDetail"), 10.5); + } + return 1; + } + + template + bool selTrack(const TrackType track, float centrality) + { + if (cfgkOpenDebugPIDCME) { + LOGF(info, "====================Entering track selection============================="); + } + if (cfgOpenCustomTrackCutAssurance) { + if (!track.passedITSNCls()) + return false; + if (!track.passedITSChi2NDF()) + return false; + if (!track.passedITSHits()) + return false; + if (!track.passedTPCCrossedRowsOverNCls()) + return false; + if (!track.passedTPCChi2NDF()) + return false; + if (!track.passedDCAxy()) + return false; + if (!track.passedDCAz()) + return false; + } + if (cfgkOpenTPCITSPurityCut) { + int cenBin = -1; + int ptBin = -1; + for (int i = 0; i < static_cast(cfgITSPurityCen.value.size()) - 1; ++i) { + if (centrality >= cfgITSPurityCen.value[i] && centrality < cfgITSPurityCen.value[i + 1]) { + cenBin = i; + break; + } + } + for (int i = 0; i < static_cast(cfgPtPrCut.value.size()) - 1; ++i) { + if (track.pt() >= cfgPtPrCut.value[i] && track.pt() < cfgPtPrCut.value[i + 1]) { + ptBin = i; + break; + } + } + if ((cenBin >= 0) && (ptBin >= 0)) { + if ((track.nPidFlag() == 3) || (track.nPidFlag() == 8) || (track.nPidFlag() == 9) || (track.nPidFlag() == 10)) { + if (cfgkOpenDebugPIDCME) { + LOGF(info, Form("=========cen_bin: %d pt_bin: %d=========", cenBin, ptBin)); + } + float nSigmaITSPr = track.nSigmaPrITS(); + int xBin = hPosPrCut[cenBin][ptBin]->GetXaxis()->FindBin(nSigmaITSPr); + float binContentPosPr = hPosPrCut[cenBin][ptBin]->GetBinContent(xBin); + float binContentNegPr = hNegPrCut[cenBin][ptBin]->GetBinContent(xBin); + if (track.sign() > 0) { + if ((binContentPosPr != 0) && (track.nSigmaPrTPC() < binContentPosPr)) { + if (cfgkOpenDebugPIDCME) { + LOGF(info, "====================Track selection Finished with cut============================="); + } + return false; + } + } else { + if ((binContentNegPr != 0) && (track.nSigmaPrTPC() < binContentNegPr)) { + if (cfgkOpenDebugPIDCME) { + LOGF(info, "====================Track selection Finished with cut============================="); + } + return false; + } + } + } + } + } + if (cfgkOpenDebugPIDCME) { + LOGF(info, "====================Track selection Finished without cut============================="); + } + return true; + } + + template + void fillHistosQvec(const CollType& collision, int nmode) + { + int detInd = detId * 4 + cfgnTotalSystem * 4 * (nmode - 2); + int refAInd = refAId * 4 + cfgnTotalSystem * 4 * (nmode - 2); + int refBInd = refBId * 4 + cfgnTotalSystem * 4 * (nmode - 2); + if (nmode == 2) { + if (collision.qvecAmp()[detId] > 1e-8) { + histosQA.fill(HIST("QA/histQvec_CorrL0_V2"), collision.qvecRe()[detInd], collision.qvecIm()[detInd], collision.centFT0C()); + histosQA.fill(HIST("QA/histQvec_CorrL1_V2"), collision.qvecRe()[detInd + 1], collision.qvecIm()[detInd + 1], collision.centFT0C()); + histosQA.fill(HIST("QA/histQvec_CorrL2_V2"), collision.qvecRe()[detInd + 2], collision.qvecIm()[detInd + 2], collision.centFT0C()); + histosQA.fill(HIST("QA/histQvec_CorrL3_V2"), collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], collision.centFT0C()); + histosQA.fill(HIST("QA/histEvtPl_CorrL0_V2"), helperEP.GetEventPlane(collision.qvecRe()[detInd], collision.qvecIm()[detInd], nmode), collision.centFT0C()); + histosQA.fill(HIST("QA/histEvtPl_CorrL1_V2"), helperEP.GetEventPlane(collision.qvecRe()[detInd + 1], collision.qvecIm()[detInd + 1], nmode), collision.centFT0C()); + histosQA.fill(HIST("QA/histEvtPl_CorrL2_V2"), helperEP.GetEventPlane(collision.qvecRe()[detInd + 2], collision.qvecIm()[detInd + 2], nmode), collision.centFT0C()); + histosQA.fill(HIST("QA/histEvtPl_CorrL3_V2"), helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode), collision.centFT0C()); + } + if (collision.qvecAmp()[detId] > 1e-8 && collision.qvecAmp()[refAId] > 1e-8 && collision.qvecAmp()[refBId] > 1e-8) { + histosQA.fill(HIST("QA/histQvecRes_SigRefAV2"), helperEP.GetResolution(helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode), helperEP.GetEventPlane(collision.qvecRe()[refAInd + 3], collision.qvecIm()[refAInd + 3], nmode), nmode), collision.centFT0C()); + histosQA.fill(HIST("QA/histQvecRes_SigRefBV2"), helperEP.GetResolution(helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode), helperEP.GetEventPlane(collision.qvecRe()[refBInd + 3], collision.qvecIm()[refBInd + 3], nmode), nmode), collision.centFT0C()); + histosQA.fill(HIST("QA/histQvecRes_RefARefBV2"), helperEP.GetResolution(helperEP.GetEventPlane(collision.qvecRe()[refAInd + 3], collision.qvecIm()[refAInd + 3], nmode), helperEP.GetEventPlane(collision.qvecRe()[refBInd + 3], collision.qvecIm()[refBInd + 3], nmode), nmode), collision.centFT0C()); + } + } + } + + template + void fillHistosFlowGammaDelta(const CollType& collision, const TrackType& track1, const TrackType& track2, const TrackType& track3, int nmode) + { + if (collision.qvecAmp()[detId] < 1e-8) { + return; + } + auto cent = collision.centFT0C(); + int detInd = detId * 4 + cfgnTotalSystem * 4 * (nmode - 2); + float psiN = helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode); + if (cfgkOpenV2) { + for (const auto& trk : track1) { + if (!selTrack(trk, cent)) + continue; + if (nmode == 2) { + if (trk.sign() > 0) { + histosQA.fill(HIST("V2/PID/histCosDetV2_Pi"), cent, trk.pt(), + std::cos(static_cast(nmode) * (trk.phi() - psiN))); + if (cfgOpenPlotITSNcls) { + histosQA.fill(HIST("QA/histITSNcls_PosPi"), trk.itsNCls()); + } + if (cfgOpenPlotITSNclsPtCent) { + histosQA.fill(HIST("QA/histITSNclsPtCent_PosPi"), trk.itsNCls(), trk.pt(), cent); + } + if (cfgOpenPlotTPCNcls) { + histosQA.fill(HIST("QA/histTPCNcls_PosPi"), trk.tpcNClsFound()); + } + if (cfgOpenPlotTPCNclsPtCent) { + histosQA.fill(HIST("QA/histTPCNclsPtCent_PosPi"), trk.tpcNClsFound(), trk.pt(), cent); + } + } else if (trk.sign() < 0) { + histosQA.fill(HIST("V2/PID/histCosDetV2_Pi_Neg"), cent, trk.pt(), + std::cos(static_cast(nmode) * (trk.phi() - psiN))); + if (cfgOpenPlotITSNcls) { + histosQA.fill(HIST("QA/histITSNcls_NegPi"), trk.itsNCls()); + } + if (cfgOpenPlotITSNclsPtCent) { + histosQA.fill(HIST("QA/histITSNclsPtCent_NegPi"), trk.itsNCls(), trk.pt(), cent); + } + if (cfgOpenPlotTPCNcls) { + histosQA.fill(HIST("QA/histTPCNcls_NegPi"), trk.tpcNClsFound()); + } + if (cfgOpenPlotTPCNclsPtCent) { + histosQA.fill(HIST("QA/histTPCNclsPtCent_NegPi"), trk.tpcNClsFound(), trk.pt(), cent); + } + } + } + } + for (const auto& trk : track2) { + if (!selTrack(trk, cent)) + continue; + if (nmode == 2) { + if (trk.sign() > 0) { + histosQA.fill(HIST("V2/PID/histCosDetV2_Ka"), cent, trk.pt(), + std::cos(static_cast(nmode) * (trk.phi() - psiN))); + if (cfgOpenPlotITSNcls) { + histosQA.fill(HIST("QA/histITSNcls_PosKa"), trk.itsNCls()); + } + if (cfgOpenPlotITSNclsPtCent) { + histosQA.fill(HIST("QA/histITSNclsPtCent_PosKa"), trk.itsNCls(), trk.pt(), cent); + } + if (cfgOpenPlotTPCNcls) { + histosQA.fill(HIST("QA/histTPCNcls_PosKa"), trk.tpcNClsFound()); + } + if (cfgOpenPlotTPCNclsPtCent) { + histosQA.fill(HIST("QA/histTPCNclsPtCent_PosKa"), trk.tpcNClsFound(), trk.pt(), cent); + } + } else if (trk.sign() < 0) { + histosQA.fill(HIST("V2/PID/histCosDetV2_Ka_Neg"), cent, trk.pt(), + std::cos(static_cast(nmode) * (trk.phi() - psiN))); + if (cfgOpenPlotITSNcls) { + histosQA.fill(HIST("QA/histITSNcls_NegKa"), trk.itsNCls()); + } + if (cfgOpenPlotITSNclsPtCent) { + histosQA.fill(HIST("QA/histITSNclsPtCent_NegKa"), trk.itsNCls(), trk.pt(), cent); + } + if (cfgOpenPlotTPCNcls) { + histosQA.fill(HIST("QA/histTPCNcls_NegKa"), trk.tpcNClsFound()); + } + if (cfgOpenPlotTPCNclsPtCent) { + histosQA.fill(HIST("QA/histTPCNclsPtCent_NegKa"), trk.tpcNClsFound(), trk.pt(), cent); + } + } + } + } + for (const auto& trk : track3) { + if (!selTrack(trk, cent)) + continue; + if (nmode == 2) { + if (trk.sign() > 0) { + histosQA.fill(HIST("V2/PID/histCosDetV2_Pr"), cent, trk.pt(), + std::cos(static_cast(nmode) * (trk.phi() - psiN))); + if (cfgOpenPlotITSNcls) { + histosQA.fill(HIST("QA/histITSNcls_PosPr"), trk.itsNCls()); + } + if (cfgOpenPlotITSNclsPtCent) { + histosQA.fill(HIST("QA/histITSNclsPtCent_PosPr"), trk.itsNCls(), trk.pt(), cent); + } + if (cfgOpenPlotTPCNcls) { + histosQA.fill(HIST("QA/histTPCNcls_PosPr"), trk.tpcNClsFound()); + } + if (cfgOpenPlotTPCNclsPtCent) { + histosQA.fill(HIST("QA/histTPCNclsPtCent_PosPr"), trk.tpcNClsFound(), trk.pt(), cent); + } + } else if (trk.sign() < 0) { + histosQA.fill(HIST("V2/PID/histCosDetV2_Pr_Neg"), cent, trk.pt(), + std::cos(static_cast(nmode) * (trk.phi() - psiN))); + if (cfgOpenPlotITSNcls) { + histosQA.fill(HIST("QA/histITSNcls_NegPr"), trk.itsNCls()); + } + if (cfgOpenPlotITSNclsPtCent) { + histosQA.fill(HIST("QA/histITSNclsPtCent_NegPr"), trk.itsNCls(), trk.pt(), cent); + } + if (cfgOpenPlotTPCNcls) { + histosQA.fill(HIST("QA/histTPCNcls_NegPr"), trk.tpcNClsFound()); + } + if (cfgOpenPlotTPCNclsPtCent) { + histosQA.fill(HIST("QA/histTPCNclsPtCent_NegPr"), trk.tpcNClsFound(), trk.pt(), cent); + } + } + } + } + } + if (cfgkOpenCME) { + if (cfgkOpenPiPi) { + for (const auto& trk1 : track1) { + if (!selTrack(trk1, cent)) + continue; + for (const auto& trk2 : track1) { + if (trk1.globalIndex() == trk2.globalIndex()) + continue; + if (!selTrack(trk2, cent)) + continue; + if (nmode == 2) { + if (trk1.sign() == trk2.sign()) { + histosQA.fill(HIST("PIDCME/histgamma_PiPi_ss"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiPi_ss"), cent, std::cos((trk1.phi() - trk2.phi()))); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiPi_ss_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiPi_ss_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenDeltaEta) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiPi_ss_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiPi_ss_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenAveragePt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiPi_ss_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiPi_ss_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + } + if (cfgkOpenSsOsCrossCheck) { + if (trk1.sign() > 0 && trk2.sign() > 0) { + histosQA.fill(HIST("PIDCME/histgamma_PiPi_PP"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiPi_PP"), cent, std::cos((trk1.phi() - trk2.phi()))); + } else { + histosQA.fill(HIST("PIDCME/histgamma_PiPi_NN"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiPi_NN"), cent, std::cos((trk1.phi() - trk2.phi()))); + } + } + } else { + histosQA.fill(HIST("PIDCME/histgamma_PiPi_os"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiPi_os"), cent, std::cos((trk1.phi() - trk2.phi()))); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiPi_os_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiPi_os_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenDeltaEta) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiPi_os_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiPi_os_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenAveragePt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiPi_os_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiPi_os_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + } + if (cfgkOpenSsOsCrossCheck) { + if (trk1.sign() > 0 && trk2.sign() < 0) { + histosQA.fill(HIST("PIDCME/histgamma_PiPi_PN"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiPi_PN"), cent, std::cos((trk1.phi() - trk2.phi()))); + } else { + histosQA.fill(HIST("PIDCME/histgamma_PiPi_NP"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiPi_NP"), cent, std::cos((trk1.phi() - trk2.phi()))); + } + } + } + } + } + } + } + if (cfgkOpenKaKa) { + for (const auto& trk1 : track2) { + if (!selTrack(trk1, cent)) + continue; + for (const auto& trk2 : track2) { + if (trk1.globalIndex() == trk2.globalIndex()) + continue; + if (!selTrack(trk2, cent)) + continue; + if (nmode == 2) { + if (trk1.sign() == trk2.sign()) { + histosQA.fill(HIST("PIDCME/histgamma_KaKa_ss"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_KaKa_ss"), cent, std::cos((trk1.phi() - trk2.phi()))); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_KaKa_ss_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_KaKa_ss_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenDeltaEta) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_KaKa_ss_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_KaKa_ss_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenAveragePt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_KaKa_ss_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_KaKa_ss_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + } + if (cfgkOpenSsOsCrossCheck) { + if (trk1.sign() > 0 && trk2.sign() > 0) { + histosQA.fill(HIST("PIDCME/histgamma_KaKa_PP"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_KaKa_PP"), cent, std::cos((trk1.phi() - trk2.phi()))); + } else { + histosQA.fill(HIST("PIDCME/histgamma_KaKa_NN"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_KaKa_NN"), cent, std::cos((trk1.phi() - trk2.phi()))); + } + } + } else { + histosQA.fill(HIST("PIDCME/histgamma_KaKa_os"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_KaKa_os"), cent, std::cos((trk1.phi() - trk2.phi()))); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_KaKa_os_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_KaKa_os_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenDeltaEta) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_KaKa_os_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_KaKa_os_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenAveragePt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_KaKa_os_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_KaKa_os_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + } + if (cfgkOpenSsOsCrossCheck) { + if (trk1.sign() > 0 && trk2.sign() < 0) { + histosQA.fill(HIST("PIDCME/histgamma_KaKa_PN"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_KaKa_PN"), cent, std::cos((trk1.phi() - trk2.phi()))); + } else { + histosQA.fill(HIST("PIDCME/histgamma_KaKa_NP"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_KaKa_NP"), cent, std::cos((trk1.phi() - trk2.phi()))); + } + } + } + } + } + } + } + if (cfgkOpenPrPr) { + for (const auto& trk1 : track3) { + if (!selTrack(trk1, cent)) + continue; + for (const auto& trk2 : track3) { + if (trk1.globalIndex() == trk2.globalIndex()) + continue; + if (!selTrack(trk2, cent)) + continue; + if (nmode == 2) { + if (trk1.sign() == trk2.sign()) { + histosQA.fill(HIST("PIDCME/histgamma_PrPr_ss"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PrPr_ss"), cent, std::cos((trk1.phi() - trk2.phi()))); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PrPr_ss_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PrPr_ss_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenDeltaEta) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PrPr_ss_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PrPr_ss_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenAveragePt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PrPr_ss_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PrPr_ss_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + } + if (cfgkOpenSsOsCrossCheck) { + if (trk1.sign() > 0 && trk2.sign() > 0) { + histosQA.fill(HIST("PIDCME/histgamma_PrPr_PP"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PrPr_PP"), cent, std::cos((trk1.phi() - trk2.phi()))); + } else { + histosQA.fill(HIST("PIDCME/histgamma_PrPr_NN"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PrPr_NN"), cent, std::cos((trk1.phi() - trk2.phi()))); + } + } + } else { + histosQA.fill(HIST("PIDCME/histgamma_PrPr_os"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PrPr_os"), cent, std::cos((trk1.phi() - trk2.phi()))); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PrPr_os_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PrPr_os_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenDeltaEta) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PrPr_os_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PrPr_os_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenAveragePt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PrPr_os_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PrPr_os_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + } + if (cfgkOpenSsOsCrossCheck) { + if (trk1.sign() > 0 && trk2.sign() < 0) { + histosQA.fill(HIST("PIDCME/histgamma_PrPr_PN"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PrPr_PN"), cent, std::cos((trk1.phi() - trk2.phi()))); + } else { + histosQA.fill(HIST("PIDCME/histgamma_PrPr_NP"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PrPr_NP"), cent, std::cos((trk1.phi() - trk2.phi()))); + } + } + } + } + } + } + } + if (cfgkOpenPiKa) { + for (const auto& trk1 : track1) { + if (!selTrack(trk1, cent)) + continue; + for (const auto& trk2 : track2) { + if (trk1.globalIndex() == trk2.globalIndex()) + continue; + if (!selTrack(trk2, cent)) + continue; + if (nmode == 2) { + if (trk1.sign() == trk2.sign()) { + histosQA.fill(HIST("PIDCME/histgamma_PiKa_ss"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiKa_ss"), cent, std::cos((trk1.phi() - trk2.phi()))); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiKa_ss_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiKa_ss_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenDeltaEta) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiKa_ss_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiKa_ss_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenAveragePt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiKa_ss_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiKa_ss_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + } + if (cfgkOpenSsOsCrossCheck) { + if (trk1.sign() > 0 && trk2.sign() > 0) { + histosQA.fill(HIST("PIDCME/histgamma_PiKa_PP"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiKa_PP"), cent, std::cos((trk1.phi() - trk2.phi()))); + } else { + histosQA.fill(HIST("PIDCME/histgamma_PiKa_NN"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiKa_NN"), cent, std::cos((trk1.phi() - trk2.phi()))); + } + } + } else { + histosQA.fill(HIST("PIDCME/histgamma_PiKa_os"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiKa_os"), cent, std::cos((trk1.phi() - trk2.phi()))); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiKa_os_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiKa_os_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenDeltaEta) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiKa_os_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiKa_os_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenAveragePt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiKa_os_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiKa_os_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + } + if (cfgkOpenSsOsCrossCheck) { + if (trk1.sign() > 0 && trk2.sign() < 0) { + histosQA.fill(HIST("PIDCME/histgamma_PiKa_PN"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiKa_PN"), cent, std::cos((trk1.phi() - trk2.phi()))); + } else { + histosQA.fill(HIST("PIDCME/histgamma_PiKa_NP"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiKa_NP"), cent, std::cos((trk1.phi() - trk2.phi()))); + } + } + } + } + } + } + } + if (cfgkOpenPiPr) { + for (const auto& trk1 : track1) { + if (!selTrack(trk1, cent)) + continue; + for (const auto& trk3 : track3) { + if (trk1.globalIndex() == trk3.globalIndex()) + continue; + if (!selTrack(trk3, cent)) + continue; + if (nmode == 2) { + if (trk1.sign() == trk3.sign()) { + histosQA.fill(HIST("PIDCME/histgamma_PiPr_ss"), cent, std::cos((trk1.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiPr_ss"), cent, std::cos((trk1.phi() - trk3.phi()))); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiPr_ss_DPt"), cent, trk1.pt() - trk3.pt(), + std::cos((trk1.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiPr_ss_DPt"), cent, trk1.pt() - trk3.pt(), + std::cos((trk1.phi() - trk3.phi()))); + } + if (cfgkOpenDeltaEta) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiPr_ss_DEt"), cent, trk1.eta() - trk3.eta(), + std::cos((trk1.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiPr_ss_DEt"), cent, trk1.eta() - trk3.eta(), + std::cos((trk1.phi() - trk3.phi()))); + } + if (cfgkOpenAveragePt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiPr_ss_SPt"), cent, trk1.pt() + trk3.pt(), + std::cos((trk1.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiPr_ss_SPt"), cent, trk1.pt() + trk3.pt(), + std::cos((trk1.phi() - trk3.phi()))); + } + } + if (cfgkOpenSsOsCrossCheck) { + if (trk1.sign() > 0 && trk3.sign() > 0) { + histosQA.fill(HIST("PIDCME/histgamma_PiPr_PP"), cent, std::cos((trk1.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiPr_PP"), cent, std::cos((trk1.phi() - trk3.phi()))); + } else { + histosQA.fill(HIST("PIDCME/histgamma_PiPr_NN"), cent, std::cos((trk1.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiPr_NN"), cent, std::cos((trk1.phi() - trk3.phi()))); + } + } + } else { + histosQA.fill(HIST("PIDCME/histgamma_PiPr_os"), cent, std::cos((trk1.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiPr_os"), cent, std::cos((trk1.phi() - trk3.phi()))); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiPr_os_DPt"), cent, trk1.pt() - trk3.pt(), + std::cos((trk1.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiPr_os_DPt"), cent, trk1.pt() - trk3.pt(), + std::cos((trk1.phi() - trk3.phi()))); + } + if (cfgkOpenDeltaEta) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiPr_os_DEt"), cent, trk1.eta() - trk3.eta(), + std::cos((trk1.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiPr_os_DEt"), cent, trk1.eta() - trk3.eta(), + std::cos((trk1.phi() - trk3.phi()))); + } + if (cfgkOpenAveragePt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_PiPr_os_SPt"), cent, trk1.pt() + trk3.pt(), + std::cos((trk1.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_PiPr_os_SPt"), cent, trk1.pt() + trk3.pt(), + std::cos((trk1.phi() - trk3.phi()))); + } + } + if (cfgkOpenSsOsCrossCheck) { + if (trk1.sign() > 0 && trk3.sign() < 0) { + histosQA.fill(HIST("PIDCME/histgamma_PiPr_PN"), cent, std::cos((trk1.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiPr_PN"), cent, std::cos((trk1.phi() - trk3.phi()))); + } else { + histosQA.fill(HIST("PIDCME/histgamma_PiPr_NP"), cent, std::cos((trk1.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_PiPr_NP"), cent, std::cos((trk1.phi() - trk3.phi()))); + } + } + } + } + } + } + } + if (cfgkOpenKaPr) { + for (const auto& trk2 : track2) { + if (!selTrack(trk2, cent)) + continue; + for (const auto& trk3 : track3) { + if (trk2.globalIndex() == trk3.globalIndex()) + continue; + if (!selTrack(trk3, cent)) + continue; + if (nmode == 2) { + if (trk2.sign() == trk3.sign()) { + histosQA.fill(HIST("PIDCME/histgamma_KaPr_ss"), cent, std::cos((trk2.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_KaPr_ss"), cent, std::cos((trk2.phi() - trk3.phi()))); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_KaPr_ss_DPt"), cent, trk2.pt() - trk3.pt(), + std::cos((trk2.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_KaPr_ss_DPt"), cent, trk2.pt() - trk3.pt(), + std::cos((trk2.phi() - trk3.phi()))); + } + if (cfgkOpenDeltaEta) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_KaPr_ss_DEt"), cent, trk2.eta() - trk3.eta(), + std::cos((trk2.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_KaPr_ss_DEt"), cent, trk2.eta() - trk3.eta(), + std::cos((trk2.phi() - trk3.phi()))); + } + if (cfgkOpenAveragePt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_KaPr_ss_SPt"), cent, trk2.pt() + trk3.pt(), + std::cos((trk2.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_KaPr_ss_SPt"), cent, trk2.pt() + trk3.pt(), + std::cos((trk2.phi() - trk3.phi()))); + } + } + if (cfgkOpenSsOsCrossCheck) { + if (trk2.sign() > 0 && trk3.sign() > 0) { + histosQA.fill(HIST("PIDCME/histgamma_KaPr_PP"), cent, std::cos((trk2.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_KaPr_PP"), cent, std::cos((trk2.phi() - trk3.phi()))); + } else { + histosQA.fill(HIST("PIDCME/histgamma_KaPr_NN"), cent, std::cos((trk2.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_KaPr_NN"), cent, std::cos((trk2.phi() - trk3.phi()))); + } + } + } else { + histosQA.fill(HIST("PIDCME/histgamma_KaPr_os"), cent, std::cos((trk2.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_KaPr_os"), cent, std::cos((trk2.phi() - trk3.phi()))); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_KaPr_os_DPt"), cent, trk2.pt() - trk3.pt(), + std::cos((trk2.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_KaPr_os_DPt"), cent, trk2.pt() - trk3.pt(), + std::cos((trk2.phi() - trk3.phi()))); + } + if (cfgkOpenDeltaEta) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_KaPr_os_DEt"), cent, trk2.eta() - trk3.eta(), + std::cos((trk2.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_KaPr_os_DEt"), cent, trk2.eta() - trk3.eta(), + std::cos((trk2.phi() - trk3.phi()))); + } + if (cfgkOpenAveragePt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_KaPr_os_SPt"), cent, trk2.pt() + trk3.pt(), + std::cos((trk2.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_KaPr_os_SPt"), cent, trk2.pt() + trk3.pt(), + std::cos((trk2.phi() - trk3.phi()))); + } + } + if (cfgkOpenSsOsCrossCheck) { + if (trk2.sign() > 0 && trk3.sign() < 0) { + histosQA.fill(HIST("PIDCME/histgamma_KaPr_PN"), cent, std::cos((trk2.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_KaPr_PN"), cent, std::cos((trk2.phi() - trk3.phi()))); + } else { + histosQA.fill(HIST("PIDCME/histgamma_KaPr_NP"), cent, std::cos((trk2.phi() + trk3.phi() - static_cast(nmode) * psiN))); + histosQA.fill(HIST("PIDCME/histdelta_KaPr_NP"), cent, std::cos((trk2.phi() - trk3.phi()))); + } + } + } + } + } + } + } + } + } + + void process(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks) + { + auto bc = collision.bc_as(); + if ((hPosPrCut.empty()) || (hNegPrCut.empty())) { + initCCDB(bc); + LOGF(info, "==================CCDB file successfuly applied===================="); + LOGF(info, Form("size of hPosPrCut is %lu x %lu", hPosPrCut.size(), hPosPrCut[0].size())); + LOGF(info, Form("size of hNegPrCut is %lu x %lu", hNegPrCut.size(), hNegPrCut[0].size())); + LOGF(info, "==================================================================="); + } + const auto cent = collision.centFT0C(); + histosQA.fill(HIST("QA/histEventCount"), 0.5); + if (!collision.sel8()) + return; + if (tracks.size() < 1) + return; + histosQA.fill(HIST("QA/histEventCount"), 1.5); + if (cfgOpenFullEventQA) { + histosQA.fill(HIST("QA/hist_globalTracks_centT0C_before"), cent, tracks.size()); + histosQA.fill(HIST("QA/hist_PVTracks_centT0C_before"), cent, collision.multNTracksPV()); + histosQA.fill(HIST("QA/hist_globalTracks_PVTracks_before"), collision.multNTracksPV(), tracks.size()); + histosQA.fill(HIST("QA/hist_globalTracks_multT0A_before"), collision.multFT0A(), tracks.size()); + histosQA.fill(HIST("QA/hist_globalTracks_multV0A_before"), collision.multFV0A(), tracks.size()); + histosQA.fill(HIST("QA/hist_multV0A_multT0A_before"), collision.multFT0A(), collision.multFV0A()); + histosQA.fill(HIST("QA/hist_multT0C_centT0C_before"), cent, collision.multFT0C()); + } + if (cfgUseAdditionalEventCut && !selEvent(collision, tracks.size(), cent)) { + return; + } + histosQA.fill(HIST("QA/histEventCount"), 2.5); + histosQA.fill(HIST("QA/histCentrality"), cent); + histosQA.fill(HIST("QA/histVertexZRec"), collision.posZ()); + if (cfgOpenFullEventQA) { + histosQA.fill(HIST("QA/hist_globalTracks_centT0C_after"), cent, tracks.size()); + histosQA.fill(HIST("QA/hist_PVTracks_centT0C_after"), cent, collision.multNTracksPV()); + histosQA.fill(HIST("QA/hist_globalTracks_PVTracks_after"), collision.multNTracksPV(), tracks.size()); + histosQA.fill(HIST("QA/hist_globalTracks_multT0A_after"), collision.multFT0A(), tracks.size()); + histosQA.fill(HIST("QA/hist_globalTracks_multV0A_after"), collision.multFV0A(), tracks.size()); + histosQA.fill(HIST("QA/hist_multV0A_multT0A_after"), collision.multFT0A(), collision.multFV0A()); + histosQA.fill(HIST("QA/hist_multT0C_centT0C_after"), cent, collision.multFT0C()); + } + if (cfgkOpenDebugPIDCME) { + LOGF(info, "==================Event Cut Finished===================="); + } + auto tracks1 = tracksSet1->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto tracks2 = tracksSet2->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto tracks3 = tracksSet3->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + mult1 = tracks1.size(); + mult2 = tracks2.size(); + mult3 = tracks3.size(); + if (mult1 < 1 || mult2 < 1 || mult3 < 1) // Reject Collisions without sufficient particles + return; + for (auto i = 0; i < static_cast(cfgnMods->size()); i++) { + int detIndGlobal = detId * 4 + cfgnTotalSystem * 4 * (cfgnMods->at(i) - 2); + float psiNGlobal = helperEP.GetEventPlane(collision.qvecRe()[detIndGlobal + 3], collision.qvecIm()[detIndGlobal + 3], cfgnMods->at(i)); + for (const auto& trk : tracks) { + if (!selTrack(trk, cent)) + continue; + if (cfgkOpenTPCITSPurityCut && cfgkOpenTPCITSPurityCutQA) { + if (cent >= 20 && cent < 30) { + if ((trk.nPidFlag() == 3) || (trk.nPidFlag() == 8) || (trk.nPidFlag() == 9) || (trk.nPidFlag() == 10)) { + if (trk.sign() > 0) { + histosQA.fill(HIST("QA/histITSPuritycheck_Pr_Pos_Cen_20_30"), trk.nSigmaPrTPC(), trk.nSigmaPrITS(), trk.pt()); + } else { + histosQA.fill(HIST("QA/histITSPuritycheck_Pr_Neg_Cen_20_30"), trk.nSigmaPrTPC(), trk.nSigmaPrITS(), trk.pt()); + } + } + } + } + if (cfgkOpenV2) { + histosQA.fill(HIST("V2/histSinDetV2"), cent, trk.pt(), + std::sin(static_cast(cfgnMods->at(i)) * (trk.phi() - psiNGlobal))); + histosQA.fill(HIST("V2/histCosDetV2"), cent, trk.pt(), + std::cos(static_cast(cfgnMods->at(i)) * (trk.phi() - psiNGlobal))); + } + } + if (cfgkOpenCME && cfgkOpenHaHa && cfgnMods->at(i) == 2) { + for (const auto& trk1 : tracks) { + if (!selTrack(trk1, cent)) + continue; + for (const auto& trk2 : tracks) { + if (trk1.globalIndex() == trk2.globalIndex()) + continue; + if (!selTrack(trk2, cent)) + continue; + if (trk1.sign() == trk2.sign()) { + histosQA.fill(HIST("PIDCME/histgamma_HaHa_ss"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(cfgnMods->at(i)) * psiNGlobal))); + histosQA.fill(HIST("PIDCME/histdelta_HaHa_ss"), cent, std::cos((trk1.phi() - trk2.phi()))); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_HaHa_ss_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(cfgnMods->at(i)) * psiNGlobal))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_HaHa_ss_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenDeltaEta) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_HaHa_ss_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() + trk2.phi() - static_cast(cfgnMods->at(i)) * psiNGlobal))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_HaHa_ss_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenAveragePt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_HaHa_ss_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(cfgnMods->at(i)) * psiNGlobal))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_HaHa_ss_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + } + if (cfgkOpenSsOsCrossCheck) { + if (trk1.sign() > 0 && trk2.sign() > 0) { + histosQA.fill(HIST("PIDCME/histgamma_HaHa_PP"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(cfgnMods->at(i)) * psiNGlobal))); + histosQA.fill(HIST("PIDCME/histdelta_HaHa_PP"), cent, std::cos((trk1.phi() - trk2.phi()))); + } else { + histosQA.fill(HIST("PIDCME/histgamma_HaHa_NN"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(cfgnMods->at(i)) * psiNGlobal))); + histosQA.fill(HIST("PIDCME/histdelta_HaHa_NN"), cent, std::cos((trk1.phi() - trk2.phi()))); + } + } + } else { + histosQA.fill(HIST("PIDCME/histgamma_HaHa_os"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(cfgnMods->at(i)) * psiNGlobal))); + histosQA.fill(HIST("PIDCME/histdelta_HaHa_os"), cent, std::cos((trk1.phi() - trk2.phi()))); + if (cfgkOpenCMEDifferential) { + if (cfgkOpenDeltaPt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_HaHa_os_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(cfgnMods->at(i)) * psiNGlobal))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_HaHa_os_DPt"), cent, trk1.pt() - trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenDeltaEta) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_HaHa_os_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() + trk2.phi() - static_cast(cfgnMods->at(i)) * psiNGlobal))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_HaHa_os_DEt"), cent, trk1.eta() - trk2.eta(), + std::cos((trk1.phi() - trk2.phi()))); + } + if (cfgkOpenAveragePt) { + histosQA.fill(HIST("PIDCME/Differential/histgamma_HaHa_os_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() + trk2.phi() - static_cast(cfgnMods->at(i)) * psiNGlobal))); + histosQA.fill(HIST("PIDCME/Differential/histdelta_HaHa_os_SPt"), cent, trk1.pt() + trk2.pt(), + std::cos((trk1.phi() - trk2.phi()))); + } + } + if (cfgkOpenSsOsCrossCheck) { + if (trk1.sign() > 0 && trk2.sign() < 0) { + histosQA.fill(HIST("PIDCME/histgamma_HaHa_PN"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(cfgnMods->at(i)) * psiNGlobal))); + histosQA.fill(HIST("PIDCME/histdelta_HaHa_PN"), cent, std::cos((trk1.phi() - trk2.phi()))); + } else { + histosQA.fill(HIST("PIDCME/histgamma_HaHa_NP"), cent, std::cos((trk1.phi() + trk2.phi() - static_cast(cfgnMods->at(i)) * psiNGlobal))); + histosQA.fill(HIST("PIDCME/histdelta_HaHa_NP"), cent, std::cos((trk1.phi() - trk2.phi()))); + } + } + } + } + } + } + fillHistosQvec(collision, cfgnMods->at(i)); + fillHistosFlowGammaDelta(collision, tracks1, tracks2, tracks3, cfgnMods->at(i)); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGCF/Flow/Tasks/resonancesGfwFlow.cxx b/PWGCF/Flow/Tasks/resonancesGfwFlow.cxx new file mode 100644 index 00000000000..8f6db97fde8 --- /dev/null +++ b/PWGCF/Flow/Tasks/resonancesGfwFlow.cxx @@ -0,0 +1,1197 @@ +// 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 resonancesGfwFlow.cxx +/// \brief PID flow for resonances using the generic framework +/// \author Preet Bhanjan Pati + +#include +#include +#include +#include +#include +#include +#include + +#include "Math/Vector4D.h" + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/StepTHn.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/Core/RecoDecay.h" +#include "CommonConstants/PhysicsConstants.h" + +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "PWGCF/GenericFramework/Core/GFWPowerArray.h" +#include "PWGCF/GenericFramework/Core/GFW.h" +#include "PWGCF/GenericFramework/Core/GFWCumulant.h" +#include "PWGCF/GenericFramework/Core/FlowContainer.h" +#include "PWGCF/GenericFramework/Core/GFWWeights.h" +#include "PWGCF/GenericFramework/Core/GFWWeightsList.h" + +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/PID.h" + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace std; + +namespace +{ +std::shared_ptr refC22Boot[10]; +std::shared_ptr refC24Boot[10]; + +std::shared_ptr phiD22FPtBoot[10]; +std::shared_ptr phiD22BPtBoot[10]; +std::shared_ptr phiD24FPtBoot[10]; +std::shared_ptr phiD24BPtBoot[10]; + +std::shared_ptr k0D22FPtBoot[10]; +std::shared_ptr k0D22BPtBoot[10]; +std::shared_ptr k0D24FPtBoot[10]; +std::shared_ptr k0D24BPtBoot[10]; + +std::shared_ptr lambdaD22FPtBoot[10]; +std::shared_ptr lambdaD22BPtBoot[10]; +std::shared_ptr lambdaD24FPtBoot[10]; +std::shared_ptr lambdaD24BPtBoot[10]; + +std::shared_ptr anLambdaD22FPtBoot[10]; +std::shared_ptr anLambdaD22BPtBoot[10]; +std::shared_ptr anLambdaD24FPtBoot[10]; +std::shared_ptr anLambdaD24BPtBoot[10]; +} // namespace + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct ResonancesGfwFlow { + Service ccdb; + Configurable noLaterThan{"noLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMin, float, 0.2f, "Minimal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMax, float, 10.0f, "Maximal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 3.0f, "Maximal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5, "Chi2 per TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgTpcCluster, int, 70, "Number of TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgTpcNsigmaCut, float, 3.0f, "TPC N-sigma cut for pions, kaons, protons") + O2_DEFINE_CONFIGURABLE(cfgTofNsigmaCut, float, 3.0f, "TOF N-sigma cut for pions, kaons, protons") + O2_DEFINE_CONFIGURABLE(cfgTofPtCut, float, 0.5f, "Minimum pt to use TOF N-sigma") + O2_DEFINE_CONFIGURABLE(cfgITScluster, int, 0, "Number of ITS cluster") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancy, int, 3000, "Occupancy cut") + O2_DEFINE_CONFIGURABLE(cfgUseGlobalTrack, bool, true, "use Global track") + O2_DEFINE_CONFIGURABLE(cfgFakeKaonCut, float, 0.1f, "Maximum difference in measured momentum and TPC inner ring momentum of particle") + O2_DEFINE_CONFIGURABLE(cfgRapidityCut, float, 0.5, "Rapidity cut for the reconstructed particles") + O2_DEFINE_CONFIGURABLE(cfgUseCosPA, bool, false, "Use Pointing angle for resonances") + O2_DEFINE_CONFIGURABLE(cfgUseV0Radius, bool, true, "Use V0 radius for particle identification") + O2_DEFINE_CONFIGURABLE(cfgLambdaRadiusMin, float, 0.5f, "Minimum Lambda radius in cm") + O2_DEFINE_CONFIGURABLE(cfgLambdaRadiusMax, float, 200.0f, "Maximum Lambda radius in cm") + O2_DEFINE_CONFIGURABLE(cfgK0RadiusMin, float, 0.5f, "Minimum K0 radius in cm") + O2_DEFINE_CONFIGURABLE(cfgK0RadiusMax, float, 200.0f, "Maximum K0 radius in cm") + O2_DEFINE_CONFIGURABLE(cfgUseProperLifetime, bool, false, "Use proper lifetime for particle identification") + O2_DEFINE_CONFIGURABLE(cfgK0LifeTime, float, 20.0f, "Maximum lifetime for K0 in cm") + O2_DEFINE_CONFIGURABLE(cfgLambdaLifeTime, float, 30.0f, "Maximum lifetime for Lambda in cm") + O2_DEFINE_CONFIGURABLE(cfgCutDCAxy, float, 2.0f, "DCAxy range for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutDCAz, float, 2.0f, "DCAz range for tracks") + O2_DEFINE_CONFIGURABLE(cfgDCALambdaPosToPVMin, float, 0.1f, "minimum DCA to PV for Lambda positive track") + O2_DEFINE_CONFIGURABLE(cfgDCALambdaNegToPVMin, float, 0.25f, "minimum DCA to PV for Lambda negative track") + O2_DEFINE_CONFIGURABLE(cfgDCAK0PosToPVMin, float, 0.06f, "minimum DCA to PV for K0 positive track") + O2_DEFINE_CONFIGURABLE(cfgDCAK0NegToPVMin, float, 0.06f, "minimum DCA to PV for K0 negative track") + O2_DEFINE_CONFIGURABLE(cfgUseMCCLambda, bool, false, "Use mass cross check for lambda") + O2_DEFINE_CONFIGURABLE(cfgUseMCCK0, bool, false, "Use mass cross check for K0") + O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeights, bool, true, "Fill and output NUA weights") + O2_DEFINE_CONFIGURABLE(cfgAcceptance, std::string, "", "CCDB path to acceptance object") + O2_DEFINE_CONFIGURABLE(cfgUseWeightPhiEtaVtxz, bool, true, "Use Phi, Eta, VertexZ dependent NUA weights") + O2_DEFINE_CONFIGURABLE(cfgUseWeightPhiPtCent, bool, false, "Use Phi, Pt, Centrality dependent NUA weights") + O2_DEFINE_CONFIGURABLE(cfgUseWeightPhiEtaPt, bool, false, "Use Phi, Eta, Pt dependent NUA weights") + O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 10, "Number of subsamples") + O2_DEFINE_CONFIGURABLE(cfgUseBootStrap, bool, true, "Use bootstrap for error estimation") + O2_DEFINE_CONFIGURABLE(cfgTrackDensityCorrUse, bool, true, "Use track density efficiency correction") + O2_DEFINE_CONFIGURABLE(cfgUsePhi, bool, true, "Analyze Phi") + O2_DEFINE_CONFIGURABLE(cfgUseK0, bool, true, "Analyze K0") + O2_DEFINE_CONFIGURABLE(cfgUseLambda, bool, true, "Analyze Lambda") + + enum OutputSpecies { + Ref = 0, + K0 = 1, + Lambda = 2, + AnLambda = 3, + Phi = 4, + kCount_OutputSpecies + }; + + struct : ConfigurableGroup { + Configurable> cfgCosPAs{"cfgCosPAs", std::vector{0.97f, 0.995f, 0.04f}, "Minimum Pointing angle for resonances [K0, Lambda, Phi]"}; + Configurable> cfgDCABetDaug{"cfgDCABetDaug", std::vector{1, 1, 1}, "Maximum DCA between resonance daughters [K0, Lambda, Phi]"}; + Configurable> cfgMassMin{"cfgMassMin", std::vector{0.44f, 1.1f, 0.99f}, "Minimum mass for resonances [K0, Lambda, Phi]"}; + Configurable> cfgMassMax{"cfgMassMax", std::vector{0.56f, 1.16f, 1.06f}, "Maximum mass for resonances [K0, Lambda, Phi]"}; + Configurable> cfgNMassBins{"cfgNMassBins", std::vector{70, 70, 70}, "Invariant mass bins for resonances [K0, Lambda, Phi]"}; + Configurable> cfgMccCut{"cfgMccCut", std::vector{0.005f, 0.01f, 0.0f}, "MCC cut for resonances [K0, Lambda, Phi]"}; + Configurable> cfgPosTrackPt{"cfgPosTrackPt", std::vector{0.15f, 0.15f, 0.15f}, "Pt cut for positive track of resonances [K0, Lambda, Phi]"}; + Configurable> cfgNegTrackPt{"cfgNegTrackPt", std::vector{0.15f, 0.15f, 0.15f}, "Pt cut for negative track of resonances [K0, Lambda, Phi]"}; + } resoCuts; + + Configurable> cfgTrackDensityP0{"cfgTrackDensityP0", std::vector{0.7217476707, 0.7384792571, 0.7542625668, 0.7640680200, 0.7701951667, 0.7755299053, 0.7805901710, 0.7849446786, 0.7957356586, 0.8113039262, 0.8211968966, 0.8280558878, 0.8329342135}, "parameter 0 for track density efficiency correction"}; + Configurable> cfgTrackDensityP1{"cfgTrackDensityP1", std::vector{-2.169488e-05, -2.191913e-05, -2.295484e-05, -2.556538e-05, -2.754463e-05, -2.816832e-05, -2.846502e-05, -2.843857e-05, -2.705974e-05, -2.477018e-05, -2.321730e-05, -2.203315e-05, -2.109474e-05}, "parameter 1 for track density efficiency correction"}; + + // Reading in the configurables + std::vector vMassMin = resoCuts.cfgMassMin; + std::vector vMassMax = resoCuts.cfgMassMax; + std::vector vMassBins = resoCuts.cfgNMassBins; + std::vector vCosPAs = resoCuts.cfgCosPAs; + std::vector vDCABetDaug = resoCuts.cfgDCABetDaug; + std::vector vMccCut = resoCuts.cfgMccCut; + std::vector vPosTrackPt = resoCuts.cfgPosTrackPt; + std::vector vNegTrackPt = resoCuts.cfgNegTrackPt; + + // Defining configurable axis + ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for histograms"}; + ConfigurableAxis axisPhi{"axisPhi", {60, 0.0, constants::math::TwoPI}, "phi axis for histograms"}; + ConfigurableAxis axisEta{"axisEta", {40, -1., 1.}, "eta axis for histograms"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.00, 1.20, 1.40, 1.60, 1.80, 2.00, 2.20, 2.40, 2.60, 2.80, 3.00, 3.50, 4.00, 5.00, 6.00, 8.00, 10.00}, "pt axis for histograms"}; + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}, "centrality axis for histograms"}; + ConfigurableAxis axisNsigmaTPC{"axisNsigmaTPC", {80, -5, 5}, "nsigmaTPC axis"}; + ConfigurableAxis axisNsigmaTOF{"axisNsigmaTOF", {80, -5, 5}, "nsigmaTOF axis"}; + ConfigurableAxis axisParticles{"axisParticles", {3, 0, 3}, "axis for different hadrons"}; + ConfigurableAxis axisPhiMass{"axisPhiMass", {vMassBins[Phi - 2], vMassMin[Phi - 2], vMassMax[Phi - 2]}, "axis for invariant mass distibution for Phi"}; + ConfigurableAxis axisK0Mass{"axisK0Mass", {vMassBins[K0 - 1], vMassMin[K0 - 1], vMassMax[K0 - 1]}, "axis for invariant mass distibution for K0"}; + ConfigurableAxis axisLambdaMass{"axisLambdaMass", {vMassBins[Lambda - 1], vMassMin[Lambda - 1], vMassMax[Lambda - 1]}, "axis for invariant mass distibution for Lambda"}; + ConfigurableAxis axisTPCsignal{"axisTPCsignal", {10000, 0, 1000}, "axis for TPC signal"}; + ConfigurableAxis axisTOFsignal{"axisTOFsignal", {10000, 0, 1000}, "axis for TOF signal"}; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter trackFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz) && (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtPOIMin) && (aod::track::pt < cfgCutPtPOIMax) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (aod::track::tpcChi2NCl < cfgCutChi2prTPCcls); + + using AodCollisions = soa::Filtered>; + using AodTracksWithoutBayes = soa::Filtered>; + using V0TrackCandidate = aod::V0Datas; + + SliceCache cache; + Partition posTracks = aod::track::signed1Pt > 0.0f; + Partition negTracks = aod::track::signed1Pt < 0.0f; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + GFW* fGFW = new GFW(); + std::vector corrconfigs; + TAxis* fPtAxis; + TAxis* fPhiMassAxis; + TAxis* fK0MassAxis; + TAxis* fLambdaMassAxis; + TRandom3* fRndm = new TRandom3(0); + + std::vector mAcceptance; + bool correctionsLoaded = false; + + // local track density correction + std::vector funcEff; + TH1D* hFindPtBin; + TF1* funcV2; + TF1* funcV3; + TF1* funcV4; + + void init(InitContext const&) + { + // Initilizing ccdb + ccdb->setURL(ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setCreatedNotAfter(noLaterThan.value); + + AxisSpec singleCount = {1, 0, 1}; + + histos.add("hVtxZ", "", {HistType::kTH1D, {axisVertex}}); + histos.add("hMult", "", {HistType::kTH1D, {{3000, 0.5, 3000.5}}}); + histos.add("hCent", "", {HistType::kTH1D, {{90, 0, 90}}}); + + histos.add("Refc22", "", {HistType::kTProfile, {axisMultiplicity}}); + histos.add("Refc24", "", {HistType::kTProfile, {axisMultiplicity}}); + + if (cfgUsePhi) { + histos.add("KaplusTPC", "", {HistType::kTH2D, {{axisPt, axisTPCsignal}}}); + histos.add("KaminusTPC", "", {HistType::kTH2D, {{axisPt, axisTPCsignal}}}); + histos.add("KaplusTOF", "", {HistType::kTH2D, {{axisPt, axisTOFsignal}}}); + histos.add("KaminusTOF", "", {HistType::kTH2D, {{axisPt, axisTOFsignal}}}); + histos.add("hPhiPhi", "", {HistType::kTH1D, {axisPhi}}); + histos.add("hPhiEta", "", {HistType::kTH1D, {axisEta}}); + histos.add("hPhiMass_sparse", "", {HistType::kTHnSparseD, {{axisPhiMass, axisPt, axisMultiplicity}}}); + histos.add("hPhimassSparse_RD", "", {HistType::kTHnSparseD, {{axisPhiMass, axisPt, axisMultiplicity}}}); + + histos.add("Phid22Fpt", "", {HistType::kTProfile3D, {axisPt, axisPhiMass, axisMultiplicity}}); + histos.add("Phid24Fpt", "", {HistType::kTProfile3D, {axisPt, axisPhiMass, axisMultiplicity}}); + histos.add("Phid22Bpt", "", {HistType::kTProfile3D, {axisPt, axisPhiMass, axisMultiplicity}}); + histos.add("Phid24Bpt", "", {HistType::kTProfile3D, {axisPt, axisPhiMass, axisMultiplicity}}); + } + if (cfgUseK0) { + histos.add("PlusTPC_K0", "", {HistType::kTH2D, {{axisPt, axisTPCsignal}}}); + histos.add("MinusTPC_K0", "", {HistType::kTH2D, {{axisPt, axisTPCsignal}}}); + histos.add("PlusTOF_K0", "", {HistType::kTH2D, {{axisPt, axisTOFsignal}}}); + histos.add("MinusTOF_K0", "", {HistType::kTH2D, {{axisPt, axisTOFsignal}}}); + histos.add("hK0Phi", "", {HistType::kTH1D, {axisPhi}}); + histos.add("hK0Eta", "", {HistType::kTH1D, {axisEta}}); + histos.add("hK0Mass_sparse", "", {HistType::kTHnSparseF, {{axisK0Mass, axisPt, axisMultiplicity}}}); + histos.add("hK0s", "", {HistType::kTH1D, {singleCount}}); + + histos.add("K0d22Fpt", "", {HistType::kTProfile3D, {axisPt, axisK0Mass, axisMultiplicity}}); + histos.add("K0d24Fpt", "", {HistType::kTProfile3D, {axisPt, axisK0Mass, axisMultiplicity}}); + histos.add("K0d22Bpt", "", {HistType::kTProfile3D, {axisPt, axisK0Mass, axisMultiplicity}}); + histos.add("K0d24Bpt", "", {HistType::kTProfile3D, {axisPt, axisK0Mass, axisMultiplicity}}); + + histos.add("hK0Count", "Number of K0;; Count", {HistType::kTH1D, {{10, 0, 10}}}); + histos.get(HIST("hK0Count"))->GetXaxis()->SetBinLabel(1, "K0 candidates"); + histos.get(HIST("hK0Count"))->GetXaxis()->SetBinLabel(2, "Daughter pt"); + histos.get(HIST("hK0Count"))->GetXaxis()->SetBinLabel(3, "Mass cut"); + histos.get(HIST("hK0Count"))->GetXaxis()->SetBinLabel(4, "Rapidity cut"); + histos.get(HIST("hK0Count"))->GetXaxis()->SetBinLabel(5, "DCA to PV"); + histos.get(HIST("hK0Count"))->GetXaxis()->SetBinLabel(6, "DCA between daughters"); + histos.get(HIST("hK0Count"))->GetXaxis()->SetBinLabel(7, "V0radius"); + histos.get(HIST("hK0Count"))->GetXaxis()->SetBinLabel(8, "CosPA"); + histos.get(HIST("hK0Count"))->GetXaxis()->SetBinLabel(9, "Proper lifetime"); + histos.get(HIST("hK0Count"))->GetXaxis()->SetBinLabel(10, "Daughter track selection"); + } + if (cfgUseLambda) { + histos.add("PlusTPC_L", "", {HistType::kTH2D, {{axisPt, axisTPCsignal}}}); + histos.add("MinusTPC_L", "", {HistType::kTH2D, {{axisPt, axisTPCsignal}}}); + histos.add("PlusTOF_L", "", {HistType::kTH2D, {{axisPt, axisTOFsignal}}}); + histos.add("MinusTOF_L", "", {HistType::kTH2D, {{axisPt, axisTOFsignal}}}); + histos.add("hLambdaPhi", "", {HistType::kTH1D, {axisPhi}}); + histos.add("hLambdaEta", "", {HistType::kTH1D, {axisEta}}); + histos.add("hLambdaMass_sparse", "", {HistType::kTHnSparseF, {{axisLambdaMass, axisPt, axisMultiplicity}}}); + histos.add("PlusTPC_AL", "", {HistType::kTH2D, {{axisPt, axisTPCsignal}}}); + histos.add("MinusTPC_AL", "", {HistType::kTH2D, {{axisPt, axisTPCsignal}}}); + histos.add("PlusTOF_AL", "", {HistType::kTH2D, {{axisPt, axisTOFsignal}}}); + histos.add("MinusTOF_AL", "", {HistType::kTH2D, {{axisPt, axisTOFsignal}}}); + histos.add("hAntiLambdaPhi", "", {HistType::kTH1D, {axisPhi}}); + histos.add("hAntiLambdaEta", "", {HistType::kTH1D, {axisEta}}); + histos.add("hAntiLambdaMass_sparse", "", {HistType::kTHnSparseF, {{axisLambdaMass, axisPt, axisMultiplicity}}}); + histos.add("hLambdas", "", {HistType::kTH1D, {singleCount}}); + + histos.add("Lambdad22Fpt", "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}}); + histos.add("Lambdad24Fpt", "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}}); + histos.add("Lambdad22Bpt", "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}}); + histos.add("Lambdad24Bpt", "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}}); + + histos.add("AnLambdad22Fpt", "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}}); + histos.add("AnLambdad24Fpt", "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}}); + histos.add("AnLambdad22Bpt", "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}}); + histos.add("AnLambdad24Bpt", "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}}); + + histos.add("hLambdaCount", "Number of Lambda;; Count", {HistType::kTH1D, {{10, 0, 10}}}); + histos.get(HIST("hLambdaCount"))->GetXaxis()->SetBinLabel(1, "Lambda candidates"); + histos.get(HIST("hLambdaCount"))->GetXaxis()->SetBinLabel(2, "Daughter pt"); + histos.get(HIST("hLambdaCount"))->GetXaxis()->SetBinLabel(3, "Mass cut"); + histos.get(HIST("hLambdaCount"))->GetXaxis()->SetBinLabel(4, "Rapidity cut"); + histos.get(HIST("hLambdaCount"))->GetXaxis()->SetBinLabel(5, "DCA to PV"); + histos.get(HIST("hLambdaCount"))->GetXaxis()->SetBinLabel(6, "DCA between daughters"); + histos.get(HIST("hLambdaCount"))->GetXaxis()->SetBinLabel(7, "V0radius"); + histos.get(HIST("hLambdaCount"))->GetXaxis()->SetBinLabel(8, "CosPA"); + histos.get(HIST("hLambdaCount"))->GetXaxis()->SetBinLabel(9, "Proper lifetime"); + histos.get(HIST("hLambdaCount"))->GetXaxis()->SetBinLabel(10, "Daughter track selection"); + } + + histos.add("hEventCount", "Number of Event;; Count", {HistType::kTH1D, {{8, 0, 8}}}); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(1, "Filtered event"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(2, "After sel8"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(3, "kNoTimeFrameBorder"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(5, "kNoSameBunchPileup"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(6, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(7, "kNoCollInTimeRangeStandard"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(8, "After Occupancy"); + + if (cfgOutputNUAWeights) { + histos.add("NUA/hPhiEtaVtxz_ref", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, {40, -10, 10}}}); + histos.add("NUA/hPhiEtaVtxz_k0", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, {40, -10, 10}}}); + histos.add("NUA/hPhiEtaVtxz_lambda", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, {40, -10, 10}}}); + histos.add("NUA/hPhiEtaVtxz_anlambda", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, {40, -10, 10}}}); + histos.add("NUA/hPhiEtaVtxz_phi", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, {40, -10, 10}}}); + + histos.add("NUA/hPhiPtCent_ref", ";#varphi;p_{T};Cent", {HistType::kTH3D, {axisPhi, axisPt, {20, 0, 100}}}); + histos.add("NUA/hPhiPtCent_k0", ";#varphi;p_{T};Cent", {HistType::kTH3D, {axisPhi, axisPt, {20, 0, 100}}}); + histos.add("NUA/hPhiPtCent_lambda", ";#varphi;p_{T};Cent", {HistType::kTH3D, {axisPhi, axisPt, {20, 0, 100}}}); + histos.add("NUA/hPhiPtCent_anlambda", ";#varphi;p_{T};Cent", {HistType::kTH3D, {axisPhi, axisPt, {20, 0, 100}}}); + histos.add("NUA/hPhiPtCent_phi", ";#varphi;p_{T};Cent", {HistType::kTH3D, {axisPhi, axisPt, {20, 0, 100}}}); + + histos.add("NUA/hPhiEtaPt_ref", ";#varphi;#eta;p_{T}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, axisPt}}); + histos.add("NUA/hPhiEtaPt_k0", ";#varphi;#eta;p_{T}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, axisPt}}); + histos.add("NUA/hPhiEtaPt_lambda", ";#varphi;#eta;p_{T}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, axisPt}}); + histos.add("NUA/hPhiEtaPt_anlambda", ";#varphi;#eta;p_{T}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, axisPt}}); + histos.add("NUA/hPhiEtaPt_phi", ";#varphi;#eta;p_{T}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, axisPt}}); + } + + if (cfgUseBootStrap) { + for (int i = 0; i < cfgNbootstrap; i++) { + refC22Boot[i] = histos.add(Form("BootStrap/Refc22_bootstrap_%d", i), "", {HistType::kTProfile, {axisMultiplicity}}); + refC24Boot[i] = histos.add(Form("BootStrap/Refc24_bootstrap_%d", i), "", {HistType::kTProfile, {axisMultiplicity}}); + if (cfgUsePhi) { + phiD22FPtBoot[i] = histos.add(Form("BootStrap/phid22Fpt_bootstrap_%d", i), "", {HistType::kTProfile3D, {axisPt, axisPhiMass, axisMultiplicity}}); + phiD24FPtBoot[i] = histos.add(Form("BootStrap/phid24Fpt_bootstrap_%d", i), "", {HistType::kTProfile3D, {axisPt, axisPhiMass, axisMultiplicity}}); + phiD22BPtBoot[i] = histos.add(Form("BootStrap/phid22Bpt_bootstrap_%d", i), "", {HistType::kTProfile3D, {axisPt, axisPhiMass, axisMultiplicity}}); + phiD24BPtBoot[i] = histos.add(Form("BootStrap/phid24Bpt_bootstrap_%d", i), "", {HistType::kTProfile3D, {axisPt, axisPhiMass, axisMultiplicity}}); + } + if (cfgUseK0) { + k0D22FPtBoot[i] = histos.add(Form("BootStrap/k0d22Fpt_bootstrap_%d", i), "", {HistType::kTProfile3D, {axisPt, axisK0Mass, axisMultiplicity}}); + k0D24FPtBoot[i] = histos.add(Form("BootStrap/k0d24Fpt_bootstrap_%d", i), "", {HistType::kTProfile3D, {axisPt, axisK0Mass, axisMultiplicity}}); + k0D22BPtBoot[i] = histos.add(Form("BootStrap/k0d22Bpt_bootstrap_%d", i), "", {HistType::kTProfile3D, {axisPt, axisK0Mass, axisMultiplicity}}); + k0D24BPtBoot[i] = histos.add(Form("BootStrap/k0d24Bpt_bootstrap_%d", i), "", {HistType::kTProfile3D, {axisPt, axisK0Mass, axisMultiplicity}}); + } + if (cfgUseLambda) { + lambdaD22FPtBoot[i] = histos.add(Form("BootStrap/lambdad22Fpt_bootstrap_%d", i), "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}}); + lambdaD24FPtBoot[i] = histos.add(Form("BootStrap/lambdad24Fpt_bootstrap_%d", i), "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}}); + lambdaD22BPtBoot[i] = histos.add(Form("BootStrap/lambdad22Bpt_bootstrap_%d", i), "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}}); + lambdaD24BPtBoot[i] = histos.add(Form("BootStrap/lambdad24Bpt_bootstrap_%d", i), "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}}); + + anLambdaD22FPtBoot[i] = histos.add(Form("BootStrap/anlambdad22Fpt_bootstrap_%d", i), "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}}); + anLambdaD24FPtBoot[i] = histos.add(Form("BootStrap/anlambdad24Fpt_bootstrap_%d", i), "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}}); + anLambdaD22BPtBoot[i] = histos.add(Form("BootStrap/anlambdad22Bpt_bootstrap_%d", i), "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}}); + anLambdaD24BPtBoot[i] = histos.add(Form("BootStrap/anlambdad24Bpt_bootstrap_%d", i), "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}}); + } + } // end of bootstrap loop + } // end of bootstrap condition + + o2::framework::AxisSpec axis = axisPt; + int nPtBins = axis.binEdges.size() - 1; + double* ptBins = &(axis.binEdges)[0]; + fPtAxis = new TAxis(nPtBins, ptBins); + + fPhiMassAxis = new TAxis(vMassBins[Phi - 2], vMassMin[Phi - 2], vMassMax[Phi - 2]); + fK0MassAxis = new TAxis(vMassBins[K0 - 1], vMassMin[K0 - 1], vMassMax[K0 - 1]); + fLambdaMassAxis = new TAxis(vMassBins[Lambda - 1], vMassMin[Lambda - 1], vMassMax[Lambda - 1]); + + int nPhisPtMassBins = nPtBins * vMassBins[Phi - 2]; + int nK0sPtMassBins = nPtBins * vMassBins[K0 - 1]; + int nLambdasPtMassBins = nPtBins * vMassBins[Lambda - 1]; + + //********** Defining the regions ********** + // reference particles + fGFW->AddRegion("refN08", -0.8, -0.4, 1, 1); + fGFW->AddRegion("refP08", 0.4, 0.8, 1, 1); + + // phi + fGFW->AddRegion("poiNphi", -0.8, -0.4, 1 + nPhisPtMassBins, 2); + fGFW->AddRegion("poiPphi", -0.8, -0.4, 1 + nPhisPtMassBins, 2); + fGFW->AddRegion("olNphi", -0.8, -0.4, 1 + nPhisPtMassBins, 32); + fGFW->AddRegion("olPphi", -0.8, -0.4, 1 + nPhisPtMassBins, 32); + + // kshort + fGFW->AddRegion("poiNk0", -0.8, -0.4, 1 + nK0sPtMassBins, 4); + fGFW->AddRegion("poiPk0", -0.8, -0.4, 1 + nK0sPtMassBins, 4); + fGFW->AddRegion("olNk0", -0.8, -0.4, 1 + nK0sPtMassBins, 64); + fGFW->AddRegion("olPk0", -0.8, -0.4, 1 + nK0sPtMassBins, 64); + + // lambda + fGFW->AddRegion("poiNlam", -0.8, -0.4, 1 + nLambdasPtMassBins, 8); + fGFW->AddRegion("poiPlam", -0.8, -0.4, 1 + nLambdasPtMassBins, 8); + fGFW->AddRegion("olNlam", -0.8, -0.4, 1 + nLambdasPtMassBins, 128); + fGFW->AddRegion("olPlam", -0.8, -0.4, 1 + nLambdasPtMassBins, 128); + + // antilambda + fGFW->AddRegion("poiNantilam", -0.8, -0.4, 1 + nLambdasPtMassBins, 16); + fGFW->AddRegion("poiPantilam", -0.8, -0.4, 1 + nLambdasPtMassBins, 16); + fGFW->AddRegion("olNantilam", -0.8, -0.4, 1 + nLambdasPtMassBins, 256); + fGFW->AddRegion("olPantilam", -0.8, -0.4, 1 + nLambdasPtMassBins, 256); + + //********** Defining the correlations ************ + // NAMING CONVENTION: + // F: Forward --> REF from negative eta + POI from negative eta correlated to REF from positive eta + // B: Backward --> REF from negative eta correlated to REF from positive eta + POI from positive eta + + //--------- reference particles + // Forward and Backward correlations are the same for reference particles + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {2} refP08 {-2}", "Ref08Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {2 2} refP08 {-2 -2}", "Ref08Gap24", kFALSE)); + + //--------- pt differential pois + // Phi + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiNphi refN08 | olNphi {2} refP08 {-2}", "PhiF08Gap22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiNphi refN08 | olNphi {2 2} refP08 {-2 -2}", "PhiF08Gap24", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPphi refP08 | olPphi {2} refN08 {-2}", "PhiB08Gap22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPphi refP08 | olPphi {2 2} refN08 {-2 -2}", "PhiB08Gap24", kTRUE)); + + // K0 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiNk0 refN08 | olNk0 {2} refP08 {-2}", "KsF08Gap22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiNk0 refN08 | olNk0 {2 2} refP08 {-2 -2}", "KsF08Gap24", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPk0 refP08 | olPk0 {2} refN08 {-2}", "KsB08Gap22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPk0 refP08 | olPk0 {2 2} refN08 {-2 -2}", "KsB08Gap24", kTRUE)); + + // Lambda + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiNlam refN08 | olNlam {2} refP08 {-2}", "LamF08Gap22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiNlam refN08 | olNlam {2 2} refP08 {-2 -2}", "LamF08Gap24", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPlam refP08 | olPlam {2} refN08 {-2}", "LamB08Gap22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPlam refP08 | olPlam {2 2} refN08 {-2 -2}", "LamB08Gap24", kTRUE)); + + // Antilambda + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiNantilam refN08 | olNantilam {2} refP08 {-2}", "AnLamF08Gap22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiNantilam refN08 | olNantilam {2 2} refP08 {-2 -2}", "AnLamF08Gap24", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPantilam refP08 | olPantilam {2} refN08 {-2}", "AnLamB08Gap22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPantilam refP08 | olPantilam {2 2} refN08 {-2 -2}", "AnLamB08Gap24", kTRUE)); + + fGFW->CreateRegions(); + + if (cfgTrackDensityCorrUse) { + std::vector pTEffBins = {0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.4, 1.8, 2.2, 2.6, 3.0}; + hFindPtBin = new TH1D("hFindPtBin", "hFindPtBin", pTEffBins.size() - 1, &pTEffBins[0]); + funcEff.resize(pTEffBins.size() - 1); + // LHC24g3 Eff + std::vector f1p0 = cfgTrackDensityP0; + std::vector f1p1 = cfgTrackDensityP1; + for (uint ifunc = 0; ifunc < pTEffBins.size() - 1; ifunc++) { + funcEff[ifunc] = new TF1(Form("funcEff%i", ifunc), "[0]+[1]*x", 0, 3000); + funcEff[ifunc]->SetParameters(f1p0[ifunc], f1p1[ifunc]); + } + funcV2 = new TF1("funcV2", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV2->SetParameters(0.0186111, 0.00351907, -4.38264e-05, 1.35383e-07, -3.96266e-10); + funcV3 = new TF1("funcV3", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV3->SetParameters(0.0174056, 0.000703329, -1.45044e-05, 1.91991e-07, -1.62137e-09); + funcV4 = new TF1("funcV4", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV4->SetParameters(0.008845, 0.000259668, -3.24435e-06, 4.54837e-08, -6.01825e-10); + } + } + + template + void fillResoProfile(const GFW::CorrConfig& corrconf, const ConstStr& tarName, const double cent, TAxis* partaxis) + { + double dnx, val; + if (!corrconf.pTDif) { + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) + return; + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + histos.fill(tarName, cent, val, dnx); + return; + } + for (int i = 1; i <= fPtAxis->GetNbins(); i++) { + for (int j = 1; j <= partaxis->GetNbins(); j++) { + dnx = fGFW->Calculate(corrconf, ((i - 1) * partaxis->GetNbins()) + (j - 1), kTRUE).real(); + if (dnx == 0) + continue; + val = fGFW->Calculate(corrconf, ((i - 1) * partaxis->GetNbins()) + (j - 1), kFALSE).real() / dnx; + if (std::fabs(val) < 1) + histos.fill(tarName, fPtAxis->GetBinCenter(i), partaxis->GetBinCenter(j), cent, val, dnx); + } + } + return; + } + + void fillProfileBoot(const GFW::CorrConfig& corrconf, std::shared_ptr profile, const double& cent) + { + double dnx, val; + if (!corrconf.pTDif) { + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) + return; + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + profile->Fill(cent, val, dnx); + return; + } + return; + } + + void fillProfileBoot3D(const GFW::CorrConfig& corrconf, std::shared_ptr profile, const double& cent, TAxis* partaxis) + { + double dnx, val; + for (int i = 1; i <= fPtAxis->GetNbins(); i++) { + for (int j = 1; j <= partaxis->GetNbins(); j++) { + dnx = fGFW->Calculate(corrconf, ((i - 1) * partaxis->GetNbins()) + (j - 1), kTRUE).real(); + if (dnx == 0) + continue; + val = fGFW->Calculate(corrconf, ((i - 1) * partaxis->GetNbins()) + (j - 1), kFALSE).real() / dnx; + if (std::fabs(val) < 1) + profile->Fill(fPtAxis->GetBinCenter(i), partaxis->GetBinCenter(j), cent, val, dnx); + } + } + return; + } + // Cosine pointing angle cut + template + bool selectionPair(const TTrack1& track1, const TTrack2& track2) + { + double pt1, pt2, pz1, pz2, p1, p2, angle; + pt1 = track1.pt(); + pt2 = track2.pt(); + pz1 = track1.pz(); + pz2 = track2.pz(); + p1 = track1.p(); + p2 = track2.p(); + angle = std::acos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); + if (cfgUseCosPA && angle < vCosPAs[Phi - 2]) { + return false; + } + return true; + } + + template + bool isFakeKaon(TTrack const& track) + { + const auto pglobal = track.p(); + const auto ptpc = track.tpcInnerParam(); + if (std::abs(pglobal - ptpc) > cfgFakeKaonCut) { + return true; + } + return false; + } + + template + bool selectionTrack(const TTrack& track) + { + if (cfgUseGlobalTrack && !(track.isGlobalTrack() && track.isPVContributor() && track.itsNCls() > cfgITScluster && track.tpcNClsFound() > cfgTpcCluster && track.hasTPC())) { + return false; + } + if (!cfgUseGlobalTrack && !(track.isPVContributor() && track.itsNCls() > cfgITScluster && track.hasTPC())) { + return false; + } + return true; + } + + template + int getNsigmaPID(TTrack track) + { + // Computing Nsigma arrays for pion, kaon, and protons + std::array nSigmaTPC = {track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + std::array nSigmaCombined = {std::hypot(track.tpcNSigmaPi(), track.tofNSigmaPi()), std::hypot(track.tpcNSigmaKa(), track.tofNSigmaKa()), std::hypot(track.tpcNSigmaPr(), track.tofNSigmaPr())}; + int pid = -1; + float nsigma = cfgTpcNsigmaCut; + + // Choose which nSigma to use + std::array nSigmaToUse = (track.pt() >= cfgTofPtCut && track.hasTOF()) ? nSigmaCombined : nSigmaTPC; + if (track.pt() >= cfgTofPtCut && !track.hasTOF()) + return -1; + + const int numSpecies = 3; + // Select particle with the lowest nsigma + for (int i = 0; i < numSpecies; ++i) { + if (std::abs(nSigmaToUse[i]) < nsigma) { + pid = i; + nsigma = std::abs(nSigmaToUse[i]); + } + } + + return pid + 1; // shift the pid by 1, 1 = pion, 2 = kaon, 3 = proton + } + + void loadCorrections(aod::BCsWithTimestamps::iterator const& bc) + { + if (correctionsLoaded) + return; + if (!cfgAcceptance.value.empty()) { + uint64_t timestamp = bc.timestamp(); + mAcceptance.clear(); + mAcceptance.resize(kCount_OutputSpecies); + + mAcceptance[Ref] = ccdb->getForTimeStamp(cfgAcceptance.value + "_ref", timestamp); + if (mAcceptance[Ref]) + LOGF(info, "Loaded acceptance weights from %s_ref (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[Ref]); + else + LOGF(fatal, "Could not load acceptance weights from %s_ref (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[Ref]); + + mAcceptance[K0] = ccdb->getForTimeStamp(cfgAcceptance.value + "_k0", timestamp); + if (mAcceptance[K0]) + LOGF(info, "Loaded acceptance weights from %s_k0 (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[K0]); + else + LOGF(fatal, "Could not load acceptance weights from %s_k0 (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[K0]); + + mAcceptance[Lambda] = ccdb->getForTimeStamp(cfgAcceptance.value + "_lambda", timestamp); + if (mAcceptance[Lambda]) + LOGF(info, "Loaded acceptance weights from %s_lambda (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[Lambda]); + else + LOGF(fatal, "Could not load acceptance weights from %s_lambda (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[Lambda]); + + mAcceptance[AnLambda] = ccdb->getForTimeStamp(cfgAcceptance.value + "_AnLambda", timestamp); + if (mAcceptance[AnLambda]) + LOGF(info, "Loaded acceptance weights from %s_anlambda (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[AnLambda]); + else + LOGF(fatal, "Could not load acceptance weights from %s_anlambda (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[AnLambda]); + + mAcceptance[Phi] = ccdb->getForTimeStamp(cfgAcceptance.value + "_phi", timestamp); + if (mAcceptance[Phi]) + LOGF(info, "Loaded acceptance weights from %s_phi (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[Phi]); + else + LOGF(fatal, "Could not load acceptance weights from %s_phi (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance[Phi]); + } + + correctionsLoaded = true; + } + + template + double getAcceptance(TTrack track, const TCollision collision, int pid_index_reso) + { // 0 = ref, 1 = k0, 2 = lambda, 3 = anti-lambda, 4 = phi + if (pid_index_reso < 0 || pid_index_reso >= kCount_OutputSpecies) { + return 1; + } + + double wacc = 1; + double cent = collision.centFT0C(); + double vtxz = collision.posZ(); + + if ((cfgUseWeightPhiEtaVtxz && cfgUseWeightPhiPtCent) || (cfgUseWeightPhiEtaPt && cfgUseWeightPhiPtCent) || (cfgUseWeightPhiEtaVtxz && cfgUseWeightPhiEtaPt)) { + LOGF(fatal, "Only one of the three weight options can be used at a time"); + } + if (!mAcceptance.empty() && correctionsLoaded) { + if (!mAcceptance[pid_index_reso]) { + LOGF(fatal, "Acceptance weights not loaded for pidIndex %d", pid_index_reso); + return 1; + } + if (cfgUseWeightPhiEtaVtxz) + wacc = mAcceptance[pid_index_reso]->getNUA(track.phi(), track.eta(), vtxz); + if (cfgUseWeightPhiPtCent) + wacc = mAcceptance[pid_index_reso]->getNUA(track.phi(), track.pt(), cent); + if (cfgUseWeightPhiEtaPt) + wacc = mAcceptance[pid_index_reso]->getNUA(track.phi(), track.eta(), track.pt()); + } + return wacc; + } + + template + double getAcceptancePhi(vector mom, const TCollision collision, int pid_index_reso) + { // 0 = ref, 1 = k0, 2 = lambda, 3 = anti-lambda, 4 = phi + if (pid_index_reso < 0 || pid_index_reso >= kCount_OutputSpecies) { + return 1; + } + + double wacc = 1; + double cent = collision.centFT0C(); + double vtxz = collision.posZ(); + double phi = mom.Phi(); + phi = RecoDecay::constrainAngle(phi, 0.0, 1); // constrain azimuthal angle to [0,2pi] + + if ((cfgUseWeightPhiEtaVtxz && cfgUseWeightPhiPtCent) || (cfgUseWeightPhiEtaPt && cfgUseWeightPhiPtCent) || (cfgUseWeightPhiEtaVtxz && cfgUseWeightPhiEtaPt)) { + LOGF(fatal, "Only one of the three weight options can be used at a time"); + } + if (!mAcceptance.empty() && correctionsLoaded) { + if (!mAcceptance[pid_index_reso]) { + LOGF(fatal, "Acceptance weights not loaded for pidIndex %d", pid_index_reso); + return 1; + } + if (cfgUseWeightPhiEtaVtxz) + wacc = mAcceptance[pid_index_reso]->getNUA(phi, mom.Eta(), vtxz); + if (cfgUseWeightPhiPtCent) + wacc = mAcceptance[pid_index_reso]->getNUA(phi, mom.Pt(), cent); + if (cfgUseWeightPhiEtaPt) + wacc = mAcceptance[pid_index_reso]->getNUA(phi, mom.Eta(), mom.Pt()); + } + return wacc; + } + + template + void fillWeights(const TTrack track, const TCollision collision, const int& pid_index_reso) + { + double cent = collision.centFT0C(); + double vtxz = collision.posZ(); + double pt = track.pt(); + bool withinPtPOI = (cfgCutPtPOIMin < pt) && (pt < cfgCutPtPOIMax); // within POI pT range + bool withinPtRef = (cfgCutPtMin < pt) && (pt < cfgCutPtMax); // within RF pT range + + if (withinPtRef && !pid_index_reso) { + histos.fill(HIST("NUA/hPhiEtaVtxz_ref"), track.phi(), track.eta(), vtxz); // pt-subset of charged particles for ref flow + histos.fill(HIST("NUA/hPhiPtCent_ref"), track.phi(), track.pt(), cent); + histos.fill(HIST("NUA/hPhiEtaPt_ref"), track.phi(), track.eta(), track.pt()); + } + + if (withinPtPOI) { + switch (pid_index_reso) { + case K0: + histos.fill(HIST("NUA/hPhiEtaVtxz_k0"), track.phi(), track.eta(), vtxz); // K0 weights + histos.fill(HIST("NUA/hPhiPtCent_k0"), track.phi(), track.pt(), cent); + histos.fill(HIST("NUA/hPhiEtaPt_k0"), track.phi(), track.eta(), track.pt()); + break; + case Lambda: + histos.fill(HIST("NUA/hPhiEtaVtxz_lambda"), track.phi(), track.eta(), vtxz); // Lambda weights + histos.fill(HIST("NUA/hPhiPtCent_lambda"), track.phi(), track.pt(), cent); + histos.fill(HIST("NUA/hPhiEtaPt_lambda"), track.phi(), track.eta(), track.pt()); + break; + case AnLambda: + histos.fill(HIST("NUA/hPhiEtaVtxz_anlambda"), track.phi(), track.eta(), vtxz); // Anti-Lambda weights + histos.fill(HIST("NUA/hPhiPtCent_anlambda"), track.phi(), track.pt(), cent); + histos.fill(HIST("NUA/hPhiEtaPt_anlambda"), track.phi(), track.eta(), track.pt()); + break; + // Phi weights are filled in the resurrectPhi function + } + } + } + + template + void resurrectPhi(TTrack trackplus, TTrack trackminus, const TCollision collision, vector plusdaug, vector minusdaug, vector mom, double plusmass, const ConstStr& hist) + { + const int nKaon = 2; + for (auto const& [partplus, partminus] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(trackplus, trackminus))) { + if (getNsigmaPID(partplus) != nKaon) + continue; + if (getNsigmaPID(partminus) != nKaon) + continue; + if (isFakeKaon(partplus) || isFakeKaon(partminus)) + continue; + if (!selectionPair(partplus, partminus)) + continue; + if (!selectionTrack(partplus) || !selectionTrack(partminus)) + continue; + + histos.fill(HIST("KaplusTPC"), partplus.pt(), partplus.tpcNSigmaKa()); + histos.fill(HIST("KaplusTOF"), partplus.pt(), partplus.tofNSigmaKa()); + histos.fill(HIST("KaminusTPC"), partminus.pt(), partminus.tpcNSigmaKa()); + histos.fill(HIST("KaminusTOF"), partminus.pt(), partminus.tofNSigmaKa()); + + std::array, 2> ptarr = {{{partplus.px(), partplus.py(), partplus.pz()}, {partminus.px(), partminus.py(), partminus.pz()}}}; + std::array massarr = {plusmass, plusmass}; + + // Calculation using RecoDecay + double invMassRD = RecoDecay::m2(ptarr, massarr); + double ptRD = std::sqrt(RecoDecay::sumOfSquares(partplus.pt(), partminus.pt())); + + // Calculation using ROOT vectors + plusdaug = ROOT::Math::PxPyPzMVector(partplus.px(), partplus.py(), partplus.pz(), plusmass); + minusdaug = ROOT::Math::PxPyPzMVector(partminus.px(), partminus.py(), partminus.pz(), plusmass); + mom = plusdaug + minusdaug; + + double pt = mom.Pt(); + double invMass = mom.M(); + double phi = mom.Phi(); + bool withinPtPOI = (cfgCutPtPOIMin < pt) && (pt < cfgCutPtPOIMax); // within POI pT range + bool withinPtRef = (cfgCutPtMin < pt) && (pt < cfgCutPtMax); + + phi = RecoDecay::constrainAngle(phi, 0.0, 1); // constrain azimuthal angle to [0,2pi] + + if (std::abs(mom.Rapidity()) < cfgRapidityCut) { + histos.fill(hist, invMass, pt, collision.centFT0C()); + histos.fill(HIST("hPhiPhi"), phi); + histos.fill(HIST("hPhiEta"), mom.Eta()); + histos.fill(HIST("hPhimassSparse_RD"), invMassRD, ptRD, collision.centFT0C()); // fill RecoDecay mass and pt + + // Fill Phi weights + if (cfgOutputNUAWeights && withinPtPOI) { + histos.fill(HIST("NUA/hPhiEtaVtxz_phi"), phi, mom.Eta(), collision.posZ()); + histos.fill(HIST("NUA/hPhiPtCent_phi"), phi, pt, collision.centFT0C()); + histos.fill(HIST("NUA/hPhiEtaPt_phi"), phi, mom.Eta(), pt); + } + double weff = 1; + double waccPOI = getAcceptancePhi(mom, collision, Phi); + + if (withinPtPOI) + fGFW->Fill(mom.Eta(), ((fPtAxis->FindBin(pt) - 1) * fPhiMassAxis->GetNbins()) + (fPhiMassAxis->FindBin(invMass) - 1), phi, weff * waccPOI, 2); + if (withinPtPOI && withinPtRef) + fGFW->Fill(mom.Eta(), ((fPtAxis->FindBin(pt) - 1) * fPhiMassAxis->GetNbins()) + (fPhiMassAxis->FindBin(invMass) - 1), phi, weff * waccPOI, 32); + } + } + return; + } + + template + bool selectionV0Daughter(TTrack const& track, int pid) // pid 1: proton, pid 0: pion + { + if (track.tpcNClsFound() < cfgTpcCluster) + return false; + if (!track.hasTPC()) + return false; + if (pid == 1 && std::abs(track.tpcNSigmaPr()) > cfgTpcNsigmaCut) + return false; + if (pid == 0 && std::abs(track.tpcNSigmaPi()) > cfgTpcNsigmaCut) + return false; + + return true; + } + + template + bool selectionLambda(TCollision const& collision, V0 const& candidate) + { + bool isL = false; // Is lambda candidate + bool isAL = false; // Is anti-lambda candidate + + double mlambda = candidate.mLambda(); + double mantilambda = candidate.mAntiLambda(); + + // separate the positive and negative V0 daughters + auto postrack = candidate.template posTrack_as(); + auto negtrack = candidate.template negTrack_as(); + + histos.fill(HIST("hLambdaCount"), 0.5); + if (postrack.pt() < vPosTrackPt[Lambda - 1] || negtrack.pt() < vNegTrackPt[Lambda - 1]) + return false; + + histos.fill(HIST("hLambdaCount"), 1.5); + if (mlambda > vMassMin[Lambda - 1] && mlambda < vMassMax[Lambda - 1]) + isL = true; + if (mantilambda > vMassMin[Lambda - 1] && mantilambda < vMassMax[Lambda - 1]) + isAL = true; + + if (!isL && !isAL) { + return false; + } + histos.fill(HIST("hLambdaCount"), 2.5); + + // Rapidity correction + if (candidate.yLambda() > cfgRapidityCut) + return false; + histos.fill(HIST("hLambdaCount"), 3.5); + // DCA cuts for lambda and antilambda + if (isL) { + if (std::abs(candidate.dcapostopv()) < cfgDCALambdaPosToPVMin || std::abs(candidate.dcanegtopv()) < cfgDCALambdaNegToPVMin) + return false; + } + if (isAL) { + if (std::abs(candidate.dcapostopv()) < cfgDCALambdaNegToPVMin || std::abs(candidate.dcanegtopv()) < cfgDCALambdaPosToPVMin) + return false; + } + histos.fill(HIST("hLambdaCount"), 4.5); + if (std::abs(candidate.dcaV0daughters()) > vDCABetDaug[Lambda - 1]) + return false; + histos.fill(HIST("hLambdaCount"), 5.5); + // v0 radius cuts + if (cfgUseV0Radius && (candidate.v0radius() < cfgLambdaRadiusMin || candidate.v0radius() > cfgLambdaRadiusMax)) + return false; + histos.fill(HIST("hLambdaCount"), 6.5); + // cosine pointing angle cuts + if (candidate.v0cosPA() < vCosPAs[Lambda - 1]) + return false; + histos.fill(HIST("hLambdaCount"), 7.5); + // Proper lifetime + if (cfgUseProperLifetime && candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massLambda > cfgLambdaLifeTime) + return false; + histos.fill(HIST("hLambdaCount"), 8.5); + if (isL) { + if (!selectionV0Daughter(postrack, 1) || !selectionV0Daughter(negtrack, 0)) + return false; + } + if (isAL) { + if (!selectionV0Daughter(postrack, 0) || !selectionV0Daughter(negtrack, 1)) + return false; + } + histos.fill(HIST("hLambdaCount"), 9.5); + bool withinPtPOI = (cfgCutPtPOIMin < candidate.pt()) && (candidate.pt() < cfgCutPtPOIMax); // within POI pT range + bool withinPtRef = (cfgCutPtMin < candidate.pt()) && (candidate.pt() < cfgCutPtMax); + + float weff = 1; + + if (isL) { + if (cfgOutputNUAWeights) + fillWeights(candidate, collision, Lambda); + + double waccPOI = getAcceptance(candidate, collision, Lambda); + if (withinPtPOI) + fGFW->Fill(candidate.eta(), ((fPtAxis->FindBin(candidate.pt()) - 1) * fLambdaMassAxis->GetNbins()) + (fLambdaMassAxis->FindBin(mlambda) - 1), candidate.phi(), waccPOI * weff, 8); + if (withinPtPOI && withinPtRef) + fGFW->Fill(candidate.eta(), ((fPtAxis->FindBin(candidate.pt()) - 1) * fLambdaMassAxis->GetNbins()) + (fLambdaMassAxis->FindBin(mlambda) - 1), candidate.phi(), waccPOI * weff, 128); + + histos.fill(HIST("hLambdaMass_sparse"), mlambda, candidate.pt(), collision.centFT0C()); + histos.fill(HIST("hLambdaPhi"), candidate.phi()); + histos.fill(HIST("hLambdaEta"), candidate.eta()); + histos.fill(HIST("PlusTPC_L"), postrack.pt(), postrack.tpcNSigmaKa()); + histos.fill(HIST("PlusTOF_L"), postrack.pt(), postrack.tofNSigmaKa()); + histos.fill(HIST("MinusTPC_L"), negtrack.pt(), negtrack.tpcNSigmaKa()); + histos.fill(HIST("MinusTOF_L"), negtrack.pt(), negtrack.tofNSigmaKa()); + } + if (isAL) { + if (cfgOutputNUAWeights) + fillWeights(candidate, collision, AnLambda); + + double waccPOI = getAcceptance(candidate, collision, AnLambda); + if (withinPtPOI) + fGFW->Fill(candidate.eta(), ((fPtAxis->FindBin(candidate.pt()) - 1) * fLambdaMassAxis->GetNbins()) + (fLambdaMassAxis->FindBin(mantilambda) - 1), candidate.phi(), waccPOI * weff, 16); + if (withinPtPOI && withinPtRef) + fGFW->Fill(candidate.eta(), ((fPtAxis->FindBin(candidate.pt()) - 1) * fLambdaMassAxis->GetNbins()) + (fLambdaMassAxis->FindBin(mantilambda) - 1), candidate.phi(), waccPOI * weff, 256); + + histos.fill(HIST("hAntiLambdaMass_sparse"), mantilambda, candidate.pt(), collision.centFT0C()); + histos.fill(HIST("hAntiLambdaPhi"), candidate.phi()); + histos.fill(HIST("hAntiLambdaEta"), candidate.eta()); + histos.fill(HIST("PlusTPC_AL"), postrack.pt(), postrack.tpcNSigmaKa()); + histos.fill(HIST("PlusTOF_AL"), postrack.pt(), postrack.tofNSigmaKa()); + histos.fill(HIST("MinusTPC_AL"), negtrack.pt(), negtrack.tpcNSigmaKa()); + histos.fill(HIST("MinusTOF_AL"), negtrack.pt(), negtrack.tofNSigmaKa()); + } + return true; + } + + template + bool selectionK0(TCollision const& collision, V0 const& candidate) + { + double mk0 = candidate.mK0Short(); + + // separate the positive and negative V0 daughters + auto postrack = candidate.template posTrack_as(); + auto negtrack = candidate.template negTrack_as(); + + histos.fill(HIST("hK0Count"), 0.5); + if (postrack.pt() < vPosTrackPt[K0 - 1] || negtrack.pt() < vNegTrackPt[K0 - 1]) + return false; + histos.fill(HIST("hK0Count"), 1.5); + if (mk0 < vMassMin[K0 - 1] && mk0 > vMassMax[K0 - 1]) + return false; + histos.fill(HIST("hK0Count"), 2.5); + // Rapidity correction + if (candidate.yK0Short() > cfgRapidityCut) + return false; + histos.fill(HIST("hK0Count"), 3.5); + // DCA cuts for K0short + if (std::abs(candidate.dcapostopv()) < cfgDCAK0PosToPVMin || std::abs(candidate.dcanegtopv()) < cfgDCAK0NegToPVMin) + return false; + histos.fill(HIST("hK0Count"), 4.5); + if (std::abs(candidate.dcaV0daughters()) > vDCABetDaug[K0 - 1]) + return false; + histos.fill(HIST("hK0Count"), 5.5); + // v0 radius cuts + if (cfgUseV0Radius && (candidate.v0radius() < cfgK0RadiusMin || candidate.v0radius() > cfgK0RadiusMax)) + return false; + histos.fill(HIST("hK0Count"), 6.5); + // cosine pointing angle cuts + if (candidate.v0cosPA() < vCosPAs[K0 - 1]) + return false; + histos.fill(HIST("hK0Count"), 7.5); + // Proper lifetime + if (cfgUseProperLifetime && candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massK0Short > cfgK0LifeTime) + return false; + histos.fill(HIST("hK0Count"), 8.5); + if (!selectionV0Daughter(postrack, 0) || !selectionV0Daughter(negtrack, 0)) + return false; + histos.fill(HIST("hK0Count"), 9.5); + bool withinPtPOI = (cfgCutPtPOIMin < candidate.pt()) && (candidate.pt() < cfgCutPtPOIMax); // within POI pT range + bool withinPtRef = (cfgCutPtMin < candidate.pt()) && (candidate.pt() < cfgCutPtMax); + + if (cfgOutputNUAWeights) + fillWeights(candidate, collision, K0); + + float weff = 1; + double waccPOI = getAcceptance(candidate, collision, K0); + + if (withinPtPOI) + fGFW->Fill(candidate.eta(), ((fPtAxis->FindBin(candidate.pt()) - 1) * fK0MassAxis->GetNbins()) + (fK0MassAxis->FindBin(mk0) - 1), candidate.phi(), waccPOI * weff, 4); + if (withinPtPOI && withinPtRef) + fGFW->Fill(candidate.eta(), ((fPtAxis->FindBin(candidate.pt()) - 1) * fK0MassAxis->GetNbins()) + (fK0MassAxis->FindBin(mk0) - 1), candidate.phi(), waccPOI * weff, 64); + + histos.fill(HIST("hK0Mass_sparse"), mk0, candidate.pt(), collision.centFT0C()); + histos.fill(HIST("hK0Phi"), candidate.phi()); + histos.fill(HIST("hK0Eta"), candidate.eta()); + histos.fill(HIST("PlusTPC_K0"), postrack.pt(), postrack.tpcNSigmaKa()); + histos.fill(HIST("PlusTOF_K0"), postrack.pt(), postrack.tofNSigmaKa()); + histos.fill(HIST("MinusTPC_K0"), negtrack.pt(), negtrack.tpcNSigmaKa()); + histos.fill(HIST("MinusTOF_K0"), negtrack.pt(), negtrack.tofNSigmaKa()); + + return true; + } + + using BinningTypeVertexContributor = ColumnBinningPolicy; + ROOT::Math::PxPyPzMVector phiMom, kaonPlus, kaonMinus; + double massKaPlus = o2::constants::physics::MassKPlus; + double massLambda = o2::constants::physics::MassLambda; + double massK0Short = o2::constants::physics::MassK0Short; + + void process(AodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, AodTracksWithoutBayes const& tracks, aod::V0Datas const& V0s) + { + histos.fill(HIST("hEventCount"), 0.5); + int nTot = tracks.size(); + if (nTot < 1) + return; + + if (!collision.sel8()) + return; + histos.fill(HIST("hEventCount"), 1.5); + + if (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + return; + histos.fill(HIST("hEventCount"), 2.5); + + if (!collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) + return; + histos.fill(HIST("hEventCount"), 3.5); + + if (!collision.selection_bit(aod::evsel::kNoSameBunchPileup)) + return; + histos.fill(HIST("hEventCount"), 4.5); + + if (!collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + return; + histos.fill(HIST("hEventCount"), 5.5); + + if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) + return; + histos.fill(HIST("hEventCount"), 6.5); + + int occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy > cfgCutOccupancy) + return; + histos.fill(HIST("hEventCount"), 7.5); + + const auto cent = collision.centFT0C(); + float vtxz = collision.posZ(); + auto bc = collision.bc_as(); + + histos.fill(HIST("hVtxZ"), vtxz); + histos.fill(HIST("hMult"), nTot); + histos.fill(HIST("hCent"), cent); + fGFW->Clear(); + + float weff = 1; + + loadCorrections(bc); // load corrections for the each event + + // Track loop for calculating the Qn angles + double psi2Est = 0, psi3Est = 0, psi4Est = 0; + float wEPeff = 1; + double v2 = 0, v3 = 0, v4 = 0; + // be cautious, this only works for Pb-Pb + // esimate the Qn angles and vn for this event + if (cfgTrackDensityCorrUse) { + double q2x = 0, q2y = 0; + double q3x = 0, q3y = 0; + double q4x = 0, q4y = 0; + for (const auto& track : tracks) { + bool withinPtRef = (cfgCutPtMin < track.pt()) && (track.pt() < cfgCutPtMax); // within RF pT rang + if (withinPtRef) { + q2x += std::cos(2 * track.phi()); + q2y += std::sin(2 * track.phi()); + q3x += std::cos(3 * track.phi()); + q3y += std::sin(3 * track.phi()); + q4x += std::cos(4 * track.phi()); + q4y += std::sin(4 * track.phi()); + } + } + psi2Est = std::atan2(q2y, q2x) / 2.; + psi3Est = std::atan2(q3y, q3x) / 3.; + psi4Est = std::atan2(q4y, q4x) / 4.; + v2 = funcV2->Eval(cent); + v3 = funcV3->Eval(cent); + v4 = funcV4->Eval(cent); + } + + // Actual track loop + for (auto const& track : tracks) { + if (!selectionTrack(track)) + continue; + double pt = track.pt(); + bool withinPtRef = (cfgCutPtMin < pt) && (pt < cfgCutPtMax); + + weff = 1; // Initializing weff for each track + + if (withinPtRef) + if (cfgOutputNUAWeights) + fillWeights(track, collision, Ref); + + double waccRef = getAcceptance(track, collision, 0); + + if (cfgTrackDensityCorrUse && withinPtRef) { + double fphi = v2 * std::cos(2 * (track.phi() - psi2Est)) + v3 * std::cos(3 * (track.phi() - psi3Est)) + v4 * std::cos(4 * (track.phi() - psi4Est)); + fphi = (1 + 2 * fphi); + int pTBinForEff = hFindPtBin->FindBin(track.pt()); + if (pTBinForEff >= 1 && pTBinForEff <= hFindPtBin->GetNbinsX()) { + wEPeff = funcEff[pTBinForEff - 1]->Eval(fphi * tracks.size()); + if (wEPeff > 0.) { + wEPeff = 1. / wEPeff; + weff *= wEPeff; + } + } + } + + fGFW->Fill(track.eta(), fPtAxis->FindBin(pt) - 1, track.phi(), waccRef * weff, 1); + } + + auto posSlicedTracks = posTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negSlicedTracks = negTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + if (cfgUsePhi) { + resurrectPhi(posSlicedTracks, negSlicedTracks, collision, kaonPlus, kaonMinus, phiMom, massKaPlus, HIST("hPhiMass_sparse")); + } + + for (auto const& v0s : V0s) { + if (cfgUseK0) { + if (selectionK0(collision, v0s) == true) + histos.fill(HIST("hK0s"), 1); + } + if (cfgUseLambda) { + if (selectionLambda(collision, v0s) == true) + histos.fill(HIST("hLambdas"), 1); + } + } // End of v0 loop + + fillResoProfile(corrconfigs.at(0), HIST("Refc22"), cent, fPhiMassAxis); + fillResoProfile(corrconfigs.at(1), HIST("Refc24"), cent, fPhiMassAxis); + if (cfgUsePhi) { + fillResoProfile(corrconfigs.at(2), HIST("Phid22Fpt"), cent, fPhiMassAxis); + fillResoProfile(corrconfigs.at(3), HIST("Phid24Fpt"), cent, fPhiMassAxis); + fillResoProfile(corrconfigs.at(4), HIST("Phid22Bpt"), cent, fPhiMassAxis); + fillResoProfile(corrconfigs.at(5), HIST("Phid24Bpt"), cent, fPhiMassAxis); + } + if (cfgUseK0) { + fillResoProfile(corrconfigs.at(6), HIST("K0d22Fpt"), cent, fK0MassAxis); + fillResoProfile(corrconfigs.at(7), HIST("K0d24Fpt"), cent, fK0MassAxis); + fillResoProfile(corrconfigs.at(8), HIST("K0d22Bpt"), cent, fK0MassAxis); + fillResoProfile(corrconfigs.at(9), HIST("K0d24Bpt"), cent, fK0MassAxis); + } + if (cfgUseLambda) { + fillResoProfile(corrconfigs.at(10), HIST("Lambdad22Fpt"), cent, fLambdaMassAxis); + fillResoProfile(corrconfigs.at(11), HIST("Lambdad24Fpt"), cent, fLambdaMassAxis); + fillResoProfile(corrconfigs.at(12), HIST("Lambdad22Bpt"), cent, fLambdaMassAxis); + fillResoProfile(corrconfigs.at(13), HIST("Lambdad24Bpt"), cent, fLambdaMassAxis); + + fillResoProfile(corrconfigs.at(14), HIST("AnLambdad22Fpt"), cent, fLambdaMassAxis); + fillResoProfile(corrconfigs.at(15), HIST("AnLambdad24Fpt"), cent, fLambdaMassAxis); + fillResoProfile(corrconfigs.at(16), HIST("AnLambdad22Bpt"), cent, fLambdaMassAxis); + fillResoProfile(corrconfigs.at(17), HIST("AnLambdad24Bpt"), cent, fLambdaMassAxis); + } + + // bootstraping + if (cfgUseBootStrap) { + double r = fRndm->Rndm(); + int bootId = static_cast(r * 10); + + fillProfileBoot(corrconfigs.at(0), refC22Boot[bootId], cent); + fillProfileBoot(corrconfigs.at(1), refC24Boot[bootId], cent); + + if (cfgUsePhi) { + fillProfileBoot3D(corrconfigs.at(2), phiD22FPtBoot[bootId], cent, fPhiMassAxis); + fillProfileBoot3D(corrconfigs.at(3), phiD24FPtBoot[bootId], cent, fPhiMassAxis); + fillProfileBoot3D(corrconfigs.at(4), phiD22BPtBoot[bootId], cent, fPhiMassAxis); + fillProfileBoot3D(corrconfigs.at(5), phiD24BPtBoot[bootId], cent, fPhiMassAxis); + } + if (cfgUseK0) { + fillProfileBoot3D(corrconfigs.at(6), k0D22FPtBoot[bootId], cent, fK0MassAxis); + fillProfileBoot3D(corrconfigs.at(7), k0D24FPtBoot[bootId], cent, fK0MassAxis); + fillProfileBoot3D(corrconfigs.at(8), k0D22BPtBoot[bootId], cent, fK0MassAxis); + fillProfileBoot3D(corrconfigs.at(9), k0D24BPtBoot[bootId], cent, fK0MassAxis); + } + if (cfgUseLambda) { + fillProfileBoot3D(corrconfigs.at(10), lambdaD22FPtBoot[bootId], cent, fLambdaMassAxis); + fillProfileBoot3D(corrconfigs.at(11), lambdaD24FPtBoot[bootId], cent, fLambdaMassAxis); + fillProfileBoot3D(corrconfigs.at(12), lambdaD22BPtBoot[bootId], cent, fLambdaMassAxis); + fillProfileBoot3D(corrconfigs.at(13), lambdaD24BPtBoot[bootId], cent, fLambdaMassAxis); + + fillProfileBoot3D(corrconfigs.at(14), anLambdaD22FPtBoot[bootId], cent, fLambdaMassAxis); + fillProfileBoot3D(corrconfigs.at(15), anLambdaD24FPtBoot[bootId], cent, fLambdaMassAxis); + fillProfileBoot3D(corrconfigs.at(16), anLambdaD22BPtBoot[bootId], cent, fLambdaMassAxis); + fillProfileBoot3D(corrconfigs.at(17), anLambdaD24BPtBoot[bootId], cent, fLambdaMassAxis); + } + } // end of bootstrap condition + } // end of process +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/GenericFramework/Core/CMakeLists.txt b/PWGCF/GenericFramework/Core/CMakeLists.txt index b7e0a916db0..c82c4a5c751 100755 --- a/PWGCF/GenericFramework/Core/CMakeLists.txt +++ b/PWGCF/GenericFramework/Core/CMakeLists.txt @@ -16,6 +16,7 @@ o2physics_add_library(GFWCore ProfileSubset.cxx FlowContainer.cxx GFWWeights.cxx + GFWWeightsList.cxx FlowPtContainer.cxx BootstrapProfile.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore) @@ -27,6 +28,7 @@ o2physics_target_root_dictionary(GFWCore ProfileSubset.h FlowContainer.h GFWWeights.h + GFWWeightsList.h GFWConfig.h FlowPtContainer.h BootstrapProfile.h diff --git a/PWGCF/GenericFramework/Core/FlowPtContainer.cxx b/PWGCF/GenericFramework/Core/FlowPtContainer.cxx index d7b6b8dd114..d12ee4d3d4d 100644 --- a/PWGCF/GenericFramework/Core/FlowPtContainer.cxx +++ b/PWGCF/GenericFramework/Core/FlowPtContainer.cxx @@ -9,23 +9,37 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file FlowPtContainer.cxx +/// \brief Class to handle angular and transverse momentum correlations +/// \author Emil Gorm Nielsen, NBI, emil.gorm.nielsen@cern.ch + #include "FlowPtContainer.h" +#include +#include +#include -FlowPtContainer::FlowPtContainer() : TNamed("name", "name"), - fCMTermList(0), +FlowPtContainer::FlowPtContainer() : fCMTermList(0), fCorrList(0), fCovList(0), fCumulantList(0), fCentralMomentList(0), mpar(0), fillCounter(0), - fEventWeight(kEventWeight::kUnity), + fEventWeight(EventWeight::UnityWeight), + fUseCentralMoments(true), + fUseGap(false), + sumP(), corrNum(), - corrDen() {} + corrDen(), + cmVal(), + cmDen(), + arr(), + warr() {} FlowPtContainer::~FlowPtContainer() { delete fCMTermList; delete fCorrList; + delete fCovList; }; FlowPtContainer::FlowPtContainer(const char* name) : TNamed(name, name), fCMTermList(0), @@ -35,39 +49,38 @@ FlowPtContainer::FlowPtContainer(const char* name) : TNamed(name, name), fCentralMomentList(0), mpar(0), fillCounter(0), - fEventWeight(kEventWeight::kUnity), + fEventWeight(EventWeight::UnityWeight), + fUseCentralMoments(true), + fUseGap(false), + sumP(), corrNum(), - corrDen() {} -FlowPtContainer::FlowPtContainer(const char* name, const char* title, int nbinsx, double* xbins, const int& m, const GFWCorrConfigs& configs) : TNamed(name, title), - fCMTermList(0), - fCorrList(0), - fCovList(0), - fCumulantList(0), - fCentralMomentList(0), - mpar(m), - fillCounter(0), - fEventWeight(kEventWeight::kUnity), - corrNum(), - corrDen() -{ - Initialise(nbinsx, xbins, m, configs); -}; -FlowPtContainer::FlowPtContainer(const char* name, const char* title, int nbinsx, double xlow, double xhigh, const int& m, const GFWCorrConfigs& configs) : TNamed(name, title), - fCMTermList(0), - fCorrList(0), - fCovList(0), - fCumulantList(0), - fCentralMomentList(0), - mpar(m), - fillCounter(0), - fEventWeight(kEventWeight::kUnity), - corrNum(), - corrDen() -{ - Initialise(nbinsx, xlow, xhigh, m, configs); -}; -void FlowPtContainer::Initialise(const o2::framework::AxisSpec axis, const int& m, const GFWCorrConfigs& configs, const int& nsub) + corrDen(), + cmVal(), + cmDen(), + arr(), + warr() {} +FlowPtContainer::FlowPtContainer(const char* name, const char* title) : TNamed(name, title), + fCMTermList(0), + fCorrList(0), + fCovList(0), + fCumulantList(0), + fCentralMomentList(0), + mpar(0), + fillCounter(0), + fEventWeight(EventWeight::UnityWeight), + fUseCentralMoments(true), + fUseGap(false), + sumP(), + corrNum(), + corrDen(), + cmVal(), + cmDen(), + arr(), + warr() {} +void FlowPtContainer::initialise(const o2::framework::AxisSpec axis, const int& m, const GFWCorrConfigs& configs, const int& nsub) { + arr.resize(3 * 3 * 3 * 3); + warr.resize(3 * 3 * 3 * 3); if (!mpar) mpar = m; std::vector multiBins = axis.binEdges; @@ -75,7 +88,7 @@ void FlowPtContainer::Initialise(const o2::framework::AxisSpec axis, const int& if (nMultiBins <= 0) nMultiBins = multiBins.size() - 1; if (nMultiBins <= 0) { - printf("Multiplicity axis does not exist"); + LOGF(warning, "Multiplicity axis does not exist"); return; } if (fCMTermList) @@ -90,19 +103,51 @@ void FlowPtContainer::Initialise(const o2::framework::AxisSpec axis, const int& delete fCovList; fCovList = new TList(); fCovList->SetOwner(kTRUE); - for (int m = 0; m < mpar; ++m) - fCorrList->Add(new BootstrapProfile(Form("mpt%i", m + 1), Form("corr_%ipar", m + 1), nMultiBins, &multiBins[0])); + for (int m = 0; m < mpar; ++m) { + fCorrList->Add(new BootstrapProfile(Form("mpt%i", m + 1), Form("mpt%i", m + 1), nMultiBins, &multiBins[0])); + } for (int m = 0; m < 4; ++m) { - for (int i = 0; i <= m; ++i) + for (int i = 0; i <= m; ++i) { fCMTermList->Add(new BootstrapProfile(Form("cm%i_Mpt%i", m + 1, i), Form("cm%i_Mpt%i", m + 1, i), nMultiBins, &multiBins[0])); + } } - for (int i = 0; i < configs.GetSize(); ++i) { - for (auto m(1); m <= mpar; ++m) { - if (!(configs.GetpTCorrMasks()[i] & (1 << (m - 1)))) - continue; - fCovList->Add(new BootstrapProfile(Form("%s_mpt%i", configs.GetHeads()[i].c_str(), m), Form("%s_mpt%i", configs.GetHeads()[i].c_str(), m), nMultiBins, &multiBins[0])); + if (fUseGap) { + for (int i = 0; i < configs.GetSize(); ++i) { + for (auto m(1); m <= mpar; ++m) { + if (!(configs.GetpTCorrMasks()[i] & (1 << (m - 1)))) + continue; + if (fUseCentralMoments) { + for (auto j = 0; j <= m; ++j) { + fCovList->Add(new BootstrapProfile(Form("%spt%i_Mpt%i", configs.GetHeads()[i].c_str(), m, j), Form("%spt%i_Mpt%i", configs.GetHeads()[i].c_str(), m, j), nMultiBins, &multiBins[0])); + } + } else { + fCovList->Add(new BootstrapProfile(Form("%spt%i", configs.GetHeads()[i].c_str(), m), Form("%spt%i", configs.GetHeads()[i].c_str(), m), nMultiBins, &multiBins[0])); + } + } + } + } else { + if (fUseCentralMoments) { + fCovList->Add(new BootstrapProfile("ChFull24pt2_Mpt0", "ChFull24pt2_Mpt0", nMultiBins, &multiBins[0])); + fCovList->Add(new BootstrapProfile("ChFull24pt2_Mpt1", "ChFull24pt2_Mpt1", nMultiBins, &multiBins[0])); + fCovList->Add(new BootstrapProfile("ChFull24pt2_Mpt2", "ChFull24pt2_Mpt2", nMultiBins, &multiBins[0])); + + fCovList->Add(new BootstrapProfile("ChFull24pt1_Mpt0", "ChFull24pt1_Mpt0", nMultiBins, &multiBins[0])); + fCovList->Add(new BootstrapProfile("ChFull24pt1_Mpt1", "ChFull24pt1_Mpt1", nMultiBins, &multiBins[0])); + + fCovList->Add(new BootstrapProfile("ChFull22pt2_Mpt0", "ChFull22pt2_Mpt0", nMultiBins, &multiBins[0])); + fCovList->Add(new BootstrapProfile("ChFull22pt2_Mpt1", "ChFull22pt2_Mpt1", nMultiBins, &multiBins[0])); + fCovList->Add(new BootstrapProfile("ChFull22pt2_Mpt2", "ChFull22pt2_Mpt2", nMultiBins, &multiBins[0])); + + fCovList->Add(new BootstrapProfile("ChFull22pt1_Mpt0", "ChFull22pt1_Mpt0", nMultiBins, &multiBins[0])); + fCovList->Add(new BootstrapProfile("ChFull22pt1_Mpt1", "ChFull22pt1_Mpt1", nMultiBins, &multiBins[0])); + } else { + fCovList->Add(new BootstrapProfile("ChFull24pt2", "ChFull24pt2", nMultiBins, &multiBins[0])); + fCovList->Add(new BootstrapProfile("ChFull24pt1", "ChFull24pt1", nMultiBins, &multiBins[0])); + fCovList->Add(new BootstrapProfile("ChFull22pt2", "ChFull22pt2", nMultiBins, &multiBins[0])); + fCovList->Add(new BootstrapProfile("ChFull22pt1", "ChFull22pt1", nMultiBins, &multiBins[0])); } } + if (nsub) { for (int i = 0; i < fCorrList->GetEntries(); ++i) dynamic_cast(fCorrList->At(i))->InitializeSubsamples(nsub); @@ -111,11 +156,13 @@ void FlowPtContainer::Initialise(const o2::framework::AxisSpec axis, const int& for (int i = 0; i < fCovList->GetEntries(); ++i) dynamic_cast(fCovList->At(i))->InitializeSubsamples(nsub); } - printf("Container %s initialized with m = %i\n and %i subsamples", this->GetName(), mpar, nsub); + LOGF(info, "Container %s initialized with m = %i\n and %i subsamples", this->GetName(), mpar, nsub); return; }; -void FlowPtContainer::Initialise(int nbinsx, double* xbins, const int& m, const GFWCorrConfigs& configs, const int& nsub) +void FlowPtContainer::initialise(int nbinsx, double* xbins, const int& m, const GFWCorrConfigs& configs, const int& nsub) { + arr.resize(3 * 3 * 3 * 3); + warr.resize(3 * 3 * 3 * 3); if (!mpar) mpar = m; if (fCMTermList) @@ -126,17 +173,52 @@ void FlowPtContainer::Initialise(int nbinsx, double* xbins, const int& m, const delete fCorrList; fCorrList = new TList(); fCorrList->SetOwner(kTRUE); - for (int m = 0; m < mpar; ++m) + if (fCovList) + delete fCovList; + fCovList = new TList(); + fCovList->SetOwner(kTRUE); + for (int m = 0; m < mpar; ++m) { fCorrList->Add(new BootstrapProfile(Form("mpt%i", m + 1), Form("mpt%i", m + 1), nbinsx, xbins)); + } for (int m = 0; m < 4; ++m) { - for (int i = 0; i <= m; ++i) + for (int i = 0; i <= m; ++i) { fCMTermList->Add(new BootstrapProfile(Form("cm%i_Mpt%i", m + 1, i), Form("cm%i_Mpt%i", m + 1, i), nbinsx, xbins)); + } } - for (int i = 0; i < configs.GetSize(); ++i) { - for (auto m(1); m <= mpar; ++m) { - if (!(configs.GetpTCorrMasks()[i] & (1 << (m - 1)))) - continue; - fCovList->Add(new BootstrapProfile(Form("%s_mpt%i", configs.GetHeads()[i].c_str(), m + 1), Form("%s_mpt%i", configs.GetHeads()[i].c_str(), m + 1), nbinsx, xbins)); + if (fUseGap) { + for (int i = 0; i < configs.GetSize(); ++i) { + for (auto m(1); m <= mpar; ++m) { + if (!(configs.GetpTCorrMasks()[i] & (1 << (m - 1)))) + continue; + if (fUseCentralMoments) { + for (auto j = 0; j <= m; ++j) { + fCovList->Add(new BootstrapProfile(Form("%spt%i_Mpt%i", configs.GetHeads()[i].c_str(), m, j), Form("%spt%i_Mpt%i", configs.GetHeads()[i].c_str(), m, j), nbinsx, xbins)); + } + } else { + fCovList->Add(new BootstrapProfile(Form("%spt%i", configs.GetHeads()[i].c_str(), m), Form("%spt%i", configs.GetHeads()[i].c_str(), m), nbinsx, xbins)); + } + } + } + } else { + if (fUseCentralMoments) { + fCovList->Add(new BootstrapProfile("ChFull24pt2_Mpt0", "ChFull24pt2_Mpt0", nbinsx, xbins)); + fCovList->Add(new BootstrapProfile("ChFull24pt2_Mpt1", "ChFull24pt2_Mpt1", nbinsx, xbins)); + fCovList->Add(new BootstrapProfile("ChFull24pt2_Mpt2", "ChFull24pt2_Mpt2", nbinsx, xbins)); + + fCovList->Add(new BootstrapProfile("ChFull24pt1_Mpt0", "ChFull24pt1_Mpt0", nbinsx, xbins)); + fCovList->Add(new BootstrapProfile("ChFull24pt1_Mpt1", "ChFull24pt1_Mpt1", nbinsx, xbins)); + + fCovList->Add(new BootstrapProfile("ChFull22pt2_Mpt0", "ChFull22pt2_Mpt0", nbinsx, xbins)); + fCovList->Add(new BootstrapProfile("ChFull22pt2_Mpt1", "ChFull22pt2_Mpt1", nbinsx, xbins)); + fCovList->Add(new BootstrapProfile("ChFull22pt2_Mpt2", "ChFull22pt2_Mpt2", nbinsx, xbins)); + + fCovList->Add(new BootstrapProfile("ChFull22pt1_Mpt0", "ChFull22pt1_Mpt0", nbinsx, xbins)); + fCovList->Add(new BootstrapProfile("ChFull22pt1_Mpt1", "ChFull22pt1_Mpt1", nbinsx, xbins)); + } else { + fCovList->Add(new BootstrapProfile("ChFull24pt2", "ChFull24pt2", nbinsx, xbins)); + fCovList->Add(new BootstrapProfile("ChFull24pt1", "ChFull24pt1", nbinsx, xbins)); + fCovList->Add(new BootstrapProfile("ChFull22pt2", "ChFull22pt2", nbinsx, xbins)); + fCovList->Add(new BootstrapProfile("ChFull22pt1", "ChFull22pt1", nbinsx, xbins)); } } if (nsub) { @@ -147,10 +229,12 @@ void FlowPtContainer::Initialise(int nbinsx, double* xbins, const int& m, const for (int i = 0; i < fCovList->GetEntries(); ++i) dynamic_cast(fCovList->At(i))->InitializeSubsamples(nsub); } - printf("Container %s initialized with m = %i\n", this->GetName(), mpar); + LOGF(info, "Container %s initialized with m = %i\n", this->GetName(), mpar); }; -void FlowPtContainer::Initialise(int nbinsx, double xlow, double xhigh, const int& m, const GFWCorrConfigs& configs, const int& nsub) +void FlowPtContainer::initialise(int nbinsx, double xlow, double xhigh, const int& m, const GFWCorrConfigs& configs, const int& nsub) { + arr.resize(3 * 3 * 3 * 3); + warr.resize(3 * 3 * 3 * 3); if (!mpar) mpar = m; if (fCMTermList) @@ -161,17 +245,52 @@ void FlowPtContainer::Initialise(int nbinsx, double xlow, double xhigh, const in delete fCorrList; fCorrList = new TList(); fCorrList->SetOwner(kTRUE); - for (int m = 0; m < mpar; ++m) + if (fCovList) + delete fCovList; + fCovList = new TList(); + fCovList->SetOwner(kTRUE); + for (int m = 0; m < mpar; ++m) { fCorrList->Add(new BootstrapProfile(Form("mpt%i", m + 1), Form("mpt%i", m + 1), nbinsx, xlow, xhigh)); + } for (int m = 0; m < 4; ++m) { - for (int i = 0; i <= m; ++i) + for (int i = 0; i <= m; ++i) { fCMTermList->Add(new BootstrapProfile(Form("cm%i_Mpt%i", m + 1, i), Form("cm%i_Mpt%i", m + 1, i), nbinsx, xlow, xhigh)); + } } - for (int i = 0; i < configs.GetSize(); ++i) { - for (auto m(1); m <= mpar; ++m) { - if (!(configs.GetpTCorrMasks()[i] & (1 << (m - 1)))) - continue; - fCovList->Add(new BootstrapProfile(Form("%s_mpt%i", configs.GetHeads()[i].c_str(), m + 1), Form("%s_mpt%i", configs.GetHeads()[i].c_str(), m + 1), nbinsx, xlow, xhigh)); + if (fUseGap) { + for (int i = 0; i < configs.GetSize(); ++i) { + for (auto m(1); m <= mpar; ++m) { + if (!(configs.GetpTCorrMasks()[i] & (1 << (m - 1)))) + continue; + if (fUseCentralMoments) { + for (auto j = 0; j <= m; ++j) { + fCovList->Add(new BootstrapProfile(Form("%spt%i_Mpt%i", configs.GetHeads()[i].c_str(), m, j), Form("%spt%i_Mpt%i", configs.GetHeads()[i].c_str(), m, j), nbinsx, xlow, xhigh)); + } + } else { + fCovList->Add(new BootstrapProfile(Form("%spt%i", configs.GetHeads()[i].c_str(), m), Form("%spt%i", configs.GetHeads()[i].c_str(), m), nbinsx, xlow, xhigh)); + } + } + } + } else { + if (fUseCentralMoments) { + fCovList->Add(new BootstrapProfile("ChFull24pt2_Mpt0", "ChFull24pt2_Mpt0", nbinsx, xlow, xhigh)); + fCovList->Add(new BootstrapProfile("ChFull24pt2_Mpt1", "ChFull24pt2_Mpt1", nbinsx, xlow, xhigh)); + fCovList->Add(new BootstrapProfile("ChFull24pt2_Mpt2", "ChFull24pt2_Mpt2", nbinsx, xlow, xhigh)); + + fCovList->Add(new BootstrapProfile("ChFull24pt1_Mpt0", "ChFull24pt1_Mpt0", nbinsx, xlow, xhigh)); + fCovList->Add(new BootstrapProfile("ChFull24pt1_Mpt1", "ChFull24pt1_Mpt1", nbinsx, xlow, xhigh)); + + fCovList->Add(new BootstrapProfile("ChFull22pt2_Mpt0", "ChFull22pt2_Mpt0", nbinsx, xlow, xhigh)); + fCovList->Add(new BootstrapProfile("ChFull22pt2_Mpt1", "ChFull22pt2_Mpt1", nbinsx, xlow, xhigh)); + fCovList->Add(new BootstrapProfile("ChFull22pt2_Mpt2", "ChFull22pt2_Mpt2", nbinsx, xlow, xhigh)); + + fCovList->Add(new BootstrapProfile("ChFull22pt1_Mpt0", "ChFull22pt1_Mpt0", nbinsx, xlow, xhigh)); + fCovList->Add(new BootstrapProfile("ChFull22pt1_Mpt1", "ChFull22pt1_Mpt1", nbinsx, xlow, xhigh)); + } else { + fCovList->Add(new BootstrapProfile("ChFull24pt2", "ChFull24pt2", nbinsx, xlow, xhigh)); + fCovList->Add(new BootstrapProfile("ChFull24pt1", "ChFull24pt1", nbinsx, xlow, xhigh)); + fCovList->Add(new BootstrapProfile("ChFull22pt2", "ChFull22pt2", nbinsx, xlow, xhigh)); + fCovList->Add(new BootstrapProfile("ChFull22pt1", "ChFull22pt1", nbinsx, xlow, xhigh)); } } if (nsub) { @@ -182,16 +301,16 @@ void FlowPtContainer::Initialise(int nbinsx, double xlow, double xhigh, const in for (int i = 0; i < fCovList->GetEntries(); ++i) dynamic_cast(fCovList->At(i))->InitializeSubsamples(nsub); } - printf("Container %s initialized with m = %i\n", this->GetName(), mpar); + LOGF(info, "Container %s initialized with m = %i\n", this->GetName(), mpar); }; -void FlowPtContainer::Fill(const double& w, const double& pt) +void FlowPtContainer::fill(const double& w, const double& pt) { - for (auto i = 0; i < sumP.size(); ++i) { - sumP[i] += pow(w, i % (mpar + 1)) * pow(pt, i / (mpar + 1)); + for (size_t i = 0; i < sumP.size(); ++i) { + sumP[i] += std::pow(w, i % (mpar + 1)) * std::pow(pt, i / (mpar + 1)); } return; } -void FlowPtContainer::CalculateCorrelations() +void FlowPtContainer::calculateCorrelations() { corrNum.clear(); corrNum.resize(mpar + 1, 0); @@ -205,11 +324,11 @@ void FlowPtContainer::CalculateCorrelations() std::vector valDenum; for (int m(1); m <= mpar; ++m) { for (int k(1); k <= m; ++k) { - valNum.push_back(fSign[k - 1] * corrNum[m - k] * (fFactorial[m - 1] / fFactorial[m - k]) * sumP[GetVectorIndex(k, k)]); - valDenum.push_back(fSign[k - 1] * corrDen[m - k] * (fFactorial[m - 1] / fFactorial[m - k]) * sumP[GetVectorIndex(k, 0)]); + valNum.push_back(SignArray[k - 1] * corrNum[m - k] * (FactorialArray[m - 1] / FactorialArray[m - k]) * sumP[getVectorIndex(k, k)]); + valDenum.push_back(SignArray[k - 1] * corrDen[m - k] * (FactorialArray[m - 1] / FactorialArray[m - k]) * sumP[getVectorIndex(k, 0)]); } - sumNum = OrderedAddition(valNum); - sumDenum = OrderedAddition(valDenum); + sumNum = orderedAddition(valNum); + sumDenum = orderedAddition(valDenum); valNum.clear(); valDenum.clear(); @@ -218,115 +337,488 @@ void FlowPtContainer::CalculateCorrelations() } return; } -void FlowPtContainer::FillPtProfiles(const double& centmult, const double& rn) +void FlowPtContainer::fillPtProfiles(const double& centmult, const double& rn) { for (int m = 1; m <= mpar; ++m) { - if (corrDen[m] != 0) - dynamic_cast(fCorrList->At(m - 1))->FillProfile(centmult, corrNum[m] / corrDen[m], (fEventWeight == kEventWeight::kUnity) ? 1.0 : corrDen[m], rn); + if (corrDen[m] != 0) { + dynamic_cast(fCorrList->At(m - 1))->FillProfile(centmult, corrNum[m] / corrDen[m], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : corrDen[m], rn); + } } return; } -void FlowPtContainer::FillVnPtProfiles(const double& centmult, const double& flowval, const double& flowtuples, const double& rn, uint8_t mask) +void FlowPtContainer::fillVnPtCorrProfiles(const double& centmult, const double& flowval, const double& flowtuples, const double& rn, uint8_t mask) { - if (!mask) + if (!mask) { return; + } for (auto m(1); m <= mpar; ++m) { - if (!(mask & (1 << (m - 1)))) + if (!(mask & (1 << (m - 1)))) { continue; - if (corrDen[m] != 0) - dynamic_cast(fCovList->At(fillCounter))->FillProfile(centmult, flowval * corrNum[m] / corrDen[m], (fEventWeight == kUnity) ? 1.0 : flowtuples * corrDen[m], rn); + } + if (corrDen[m] != 0) { + dynamic_cast(fCovList->At(fillCounter))->FillProfile(centmult, flowval * corrNum[m] / corrDen[m], (fEventWeight == UnityWeight) ? 1.0 : flowtuples * corrDen[m], rn); + } ++fillCounter; } return; } -void FlowPtContainer::FillCMProfiles(const double& centmult, const double& rn) +void FlowPtContainer::fillVnDeltaPtProfiles(const double& centmult, const double& flowval, const double& flowtuples, const double& rn, uint8_t mask) +{ + if (!mask) { + return; + } + for (auto m(1); m <= mpar; ++m) { + if (!(mask & (1 << (m - 1)))) + continue; + for (auto i = 0; i <= m; ++i) { + if (cmDen[m] != 0) { + dynamic_cast(fCovList->At(fillCounter))->FillProfile(centmult, flowval * ((i == m) ? cmVal[0] : cmVal[m * (m - 1) / 2 + i + 1]), (fEventWeight == UnityWeight) ? 1.0 : flowtuples * cmDen[m], rn); + } + ++fillCounter; + } + } + return; +} +void FlowPtContainer::fillVnPtCorrStdProfiles(const double& centmult, const double& rn) +{ + double wAABBCC = getStdAABBCC(warr); + if (wAABBCC != 0) + dynamic_cast(fCovList->At(0))->FillProfile(centmult, getStdAABBCC(arr) / wAABBCC, (fEventWeight == UnityWeight) ? 1.0 : wAABBCC, rn); + double wAABBC = getStdAABBC(warr); + if (wAABBC != 0) + dynamic_cast(fCovList->At(1))->FillProfile(centmult, getStdAABBCC(arr) / wAABBC, (fEventWeight == UnityWeight) ? 1.0 : wAABBC, rn); + double wABCC = getStdAABBC(warr); + if (wABCC != 0) + dynamic_cast(fCovList->At(2))->FillProfile(centmult, getStdABCC(arr) / wABCC, (fEventWeight == UnityWeight) ? 1.0 : wABCC, rn); + double wABC = getStdABC(warr); + if (wABC != 0) + dynamic_cast(fCovList->At(3))->FillProfile(centmult, getStdABC(arr) / wABC, (fEventWeight == UnityWeight) ? 1.0 : wABC, rn); + return; +} +void FlowPtContainer::fillVnDeltaPtStdProfiles(const double& centmult, const double& rn) { - if (sumP[GetVectorIndex(0, 0)] == 0) + double wAABBCC = getStdAABBCC(warr); + if (wAABBCC != 0) + dynamic_cast(fCovList->At(0))->FillProfile(centmult, getStdAABBCC(arr) / wAABBCC, (fEventWeight == UnityWeight) ? 1.0 : wAABBCC, rn); + double wAABBCD = getStdAABBCD(warr); + if (wAABBCD != 0) + dynamic_cast(fCovList->At(1))->FillProfile(centmult, getStdAABBCD(arr) / wAABBCD, (fEventWeight == UnityWeight) ? 1.0 : wAABBCD, rn); + double wAABBDD = getStdAABBDD(warr); + if (wAABBDD != 0) + dynamic_cast(fCovList->At(2))->FillProfile(centmult, getStdAABBDD(arr) / wAABBDD, (fEventWeight == UnityWeight) ? 1.0 : wAABBDD, rn); + + double wAABBC = getStdAABBC(warr); + if (wAABBC != 0) + dynamic_cast(fCovList->At(3))->FillProfile(centmult, getStdAABBC(arr) / wAABBC, (fEventWeight == UnityWeight) ? 1.0 : wAABBC, rn); + double wAABBD = getStdAABBD(warr); + if (wAABBD != 0) + dynamic_cast(fCovList->At(4))->FillProfile(centmult, getStdAABBD(arr) / wAABBD, (fEventWeight == UnityWeight) ? 1.0 : wAABBD, rn); + + double wABCC = getStdABCC(warr); + if (wABCC != 0) + dynamic_cast(fCovList->At(5))->FillProfile(centmult, getStdABCC(arr) / wABCC, (fEventWeight == UnityWeight) ? 1.0 : wABCC, rn); + double wABCD = getStdABCD(warr); + if (wABCD != 0) + dynamic_cast(fCovList->At(6))->FillProfile(centmult, getStdABCD(arr) / wABCD, (fEventWeight == UnityWeight) ? 1.0 : wABCD, rn); + double wABDD = getStdABDD(warr); + if (wABDD != 0) + dynamic_cast(fCovList->At(7))->FillProfile(centmult, getStdABDD(arr) / wABDD, (fEventWeight == UnityWeight) ? 1.0 : wABDD, rn); + + double wABC = getStdABC(warr); + if (wABC != 0) + dynamic_cast(fCovList->At(8))->FillProfile(centmult, getStdABC(arr) / wABC, (fEventWeight == UnityWeight) ? 1.0 : wABC, rn); + double wABD = getStdABD(warr); + if (wABD != 0) + dynamic_cast(fCovList->At(9))->FillProfile(centmult, getStdABD(arr) / wABD, (fEventWeight == UnityWeight) ? 1.0 : wABD, rn); + return; +} +void FlowPtContainer::fillCMProfiles(const double& centmult, const double& rn) +{ + if (sumP[getVectorIndex(0, 0)] == 0) return; - double tau1 = sumP[GetVectorIndex(2, 0)] / pow(sumP[GetVectorIndex(1, 0)], 2); - double tau2 = sumP[GetVectorIndex(3, 0)] / pow(sumP[GetVectorIndex(1, 0)], 3); - double tau3 = sumP[GetVectorIndex(4, 0)] / pow(sumP[GetVectorIndex(1, 0)], 4); - // double tau4 = sumP[GetVectorIndex(5,0)]/pow(sumP[GetVectorIndex(1,0)],5); - double weight1 = 1 - tau1; - double weight2 = 1 - 3 * tau1 + 2 * tau2; - double weight3 = 1 - 6 * tau1 + 3 * tau1 * tau1 + 8 * tau2 - 6 * tau3; - // double weight4 = 1 - 10*tau1 + 15*tau1*tau1 + 20*tau2 - 20*tau1*tau2 - 30*tau3 + 24*tau4; - if (mpar < 1 || sumP[GetVectorIndex(1, 0)] == 0) + // 0th order correlation + cmDen.push_back(1.); + cmVal.push_back(1.); + + cmDen.push_back(sumP[getVectorIndex(1, 0)]); + cmDen.push_back(sumP[getVectorIndex(1, 0)] * sumP[getVectorIndex(1, 0)] - sumP[getVectorIndex(2, 0)]); + cmDen.push_back(sumP[getVectorIndex(1, 0)] * sumP[getVectorIndex(1, 0)] * sumP[getVectorIndex(1, 0)] - 3 * sumP[getVectorIndex(2, 0)] * sumP[getVectorIndex(1, 0)] + 2 * sumP[getVectorIndex(3, 0)]); + cmDen.push_back(sumP[getVectorIndex(1, 0)] * sumP[getVectorIndex(1, 0)] * sumP[getVectorIndex(1, 0)] * sumP[getVectorIndex(1, 0)] - 6 * sumP[getVectorIndex(2, 0)] * sumP[getVectorIndex(1, 0)] * sumP[getVectorIndex(1, 0)] + 8 * sumP[getVectorIndex(1, 0)] * sumP[getVectorIndex(3, 0)] + 3 * sumP[getVectorIndex(2, 0)] * sumP[getVectorIndex(2, 0)] - 6 * sumP[getVectorIndex(4, 0)]); + if (mpar < 1 || cmDen[1] == 0) return; - dynamic_cast(fCMTermList->At(0))->FillProfile(centmult, sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)], (fEventWeight == kEventWeight::kUnity) ? 1.0 : sumP[GetVectorIndex(1, 0)], rn); - if (mpar < 2 || sumP[GetVectorIndex(2, 0)] == 0 || weight1 == 0) + cmVal.push_back(sumP[getVectorIndex(1, 1)] / cmDen[1]); + dynamic_cast(fCMTermList->At(0))->FillProfile(centmult, cmVal[1], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen[1], rn); + if (mpar < 2 || sumP[getVectorIndex(2, 0)] == 0 || cmDen[2] == 0) return; - dynamic_cast(fCMTermList->At(1))->FillProfile(centmult, 1 / weight1 * (sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] - tau1 * sumP[GetVectorIndex(2, 2)] / sumP[GetVectorIndex(2, 0)]), (fEventWeight == kEventWeight::kUnity) ? 1.0 : weight1, rn); - dynamic_cast(fCMTermList->At(2))->FillProfile(centmult, 1 / weight1 * (-2 * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] + 2 * tau1 * sumP[GetVectorIndex(2, 1)] / sumP[GetVectorIndex(2, 0)]), (fEventWeight == kEventWeight::kUnity) ? 1.0 : weight1, rn); - if (mpar < 3 || sumP[GetVectorIndex(3, 0)] == 0 || weight2 == 0) + cmVal.push_back(1 / cmDen[2] * (sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 1)] - sumP[getVectorIndex(2, 2)])); + dynamic_cast(fCMTermList->At(1))->FillProfile(centmult, cmVal[2], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen[2], rn); + cmVal.push_back(-2 * 1 / cmDen[2] * (sumP[getVectorIndex(1, 0)] * sumP[getVectorIndex(1, 1)] - sumP[getVectorIndex(2, 1)])); + dynamic_cast(fCMTermList->At(2))->FillProfile(centmult, cmVal[3], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen[2], rn); + if (mpar < 3 || sumP[getVectorIndex(3, 0)] == 0 || cmDen[3] == 0) return; - dynamic_cast(fCMTermList->At(3))->FillProfile(centmult, 1 / weight2 * (sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] - 3 * tau1 * sumP[GetVectorIndex(2, 2)] / sumP[GetVectorIndex(2, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] + 2 * tau2 * sumP[GetVectorIndex(3, 3)] / sumP[GetVectorIndex(3, 0)]), (fEventWeight == kEventWeight::kUnity) ? 1.0 : weight2, rn); - dynamic_cast(fCMTermList->At(4))->FillProfile(centmult, 1 / weight2 * (-3 * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] + 3 * tau1 * sumP[GetVectorIndex(2, 2)] / sumP[GetVectorIndex(2, 0)] + 6 * tau1 * sumP[GetVectorIndex(2, 1)] / sumP[GetVectorIndex(2, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] - 6 * tau2 * sumP[GetVectorIndex(3, 2)] / sumP[GetVectorIndex(3, 0)]), (fEventWeight == kEventWeight::kUnity) ? 1.0 : weight2, rn); - dynamic_cast(fCMTermList->At(5))->FillProfile(centmult, 1 / weight2 * (3 * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] - 6 * tau1 * sumP[GetVectorIndex(2, 1)] / sumP[GetVectorIndex(2, 0)] - 3 * tau1 * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] + 6 * tau2 * sumP[GetVectorIndex(3, 1)] / sumP[GetVectorIndex(3, 0)]), (fEventWeight == kEventWeight::kUnity) ? 1.0 : weight2, rn); - if (mpar < 4 || sumP[GetVectorIndex(4, 0)] == 0 || weight3 == 0) + cmVal.push_back(1 / cmDen[3] * (sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 1)] - 3 * sumP[getVectorIndex(2, 2)] * sumP[getVectorIndex(1, 1)] + 2 * sumP[getVectorIndex(3, 3)])); + dynamic_cast(fCMTermList->At(3))->FillProfile(centmult, cmVal[4], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen[3], rn); + cmVal.push_back(-3 * 1 / cmDen[3] * (sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 0)] - 2 * sumP[getVectorIndex(2, 1)] * sumP[getVectorIndex(1, 1)] + 2 * sumP[getVectorIndex(3, 2)] - sumP[getVectorIndex(2, 2)] * sumP[getVectorIndex(1, 0)])); + dynamic_cast(fCMTermList->At(4))->FillProfile(centmult, cmVal[5], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen[3], rn); + cmVal.push_back(3 * 1 / cmDen[3] * (sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 0)] * sumP[getVectorIndex(1, 0)] - 2 * sumP[getVectorIndex(2, 1)] * sumP[getVectorIndex(1, 0)] + 2 * sumP[getVectorIndex(3, 1)] - sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(2, 0)])); + dynamic_cast(fCMTermList->At(5))->FillProfile(centmult, cmVal[6], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen[3], rn); + if (mpar < 4 || sumP[getVectorIndex(4, 0)] == 0 || cmDen[4] == 0) return; - dynamic_cast(fCMTermList->At(6))->FillProfile(centmult, 1 / weight3 * (sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] - 6 * tau1 * sumP[GetVectorIndex(2, 2)] / sumP[GetVectorIndex(2, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] + 3 * tau1 * tau1 * sumP[GetVectorIndex(2, 2)] / sumP[GetVectorIndex(2, 0)] * sumP[GetVectorIndex(2, 2)] / sumP[GetVectorIndex(2, 0)] + 8 * tau2 * sumP[GetVectorIndex(3, 3)] / sumP[GetVectorIndex(3, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] - 6 * tau3 * sumP[GetVectorIndex(4, 4)] / sumP[GetVectorIndex(4, 0)]), (fEventWeight == kEventWeight::kUnity) ? 1.0 : weight3, rn); - dynamic_cast(fCMTermList->At(7))->FillProfile(centmult, 1 / weight3 * (-4 * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] + 12 * tau1 * sumP[GetVectorIndex(2, 2)] / sumP[GetVectorIndex(2, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] + 12 * tau1 * sumP[GetVectorIndex(2, 1)] / sumP[GetVectorIndex(2, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] - 12 * tau1 * tau1 * sumP[GetVectorIndex(2, 2)] / sumP[GetVectorIndex(2, 0)] * sumP[GetVectorIndex(2, 1)] / sumP[GetVectorIndex(2, 0)] - 8 * tau2 * sumP[GetVectorIndex(3, 3)] / sumP[GetVectorIndex(3, 0)] - 24 * tau2 * sumP[GetVectorIndex(3, 2)] / sumP[GetVectorIndex(3, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] + 24 * tau3 * sumP[GetVectorIndex(4, 3)] / sumP[GetVectorIndex(4, 0)]), (fEventWeight == kEventWeight::kUnity) ? 1.0 : weight3, rn); - dynamic_cast(fCMTermList->At(8))->FillProfile(centmult, 1 / weight3 * (6 * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] - 6 * tau1 * sumP[GetVectorIndex(2, 2)] / sumP[GetVectorIndex(2, 0)] - 24 * tau1 * sumP[GetVectorIndex(2, 1)] / sumP[GetVectorIndex(2, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] - 6 * tau1 * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] + 6 * tau1 * tau1 * sumP[GetVectorIndex(2, 2)] / sumP[GetVectorIndex(2, 0)] + 12 * tau1 * tau1 * sumP[GetVectorIndex(2, 1)] / sumP[GetVectorIndex(2, 0)] * sumP[GetVectorIndex(2, 1)] / sumP[GetVectorIndex(2, 0)] + 24 * tau2 * sumP[GetVectorIndex(3, 2)] / sumP[GetVectorIndex(3, 0)] + 24 * tau2 * sumP[GetVectorIndex(3, 1)] / sumP[GetVectorIndex(3, 0)] * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] - 36 * tau3 * sumP[GetVectorIndex(4, 2)] / sumP[GetVectorIndex(4, 0)]), (fEventWeight == kEventWeight::kUnity) ? 1.0 : weight3, rn); - dynamic_cast(fCMTermList->At(9))->FillProfile(centmult, 1 / weight3 * (-4 * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] + 12 * tau1 * sumP[GetVectorIndex(2, 1)] / sumP[GetVectorIndex(2, 0)] + 12 * tau1 * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] - 12 * tau1 * tau1 * sumP[GetVectorIndex(2, 1)] / sumP[GetVectorIndex(2, 0)] - 24 * tau2 * sumP[GetVectorIndex(3, 1)] / sumP[GetVectorIndex(3, 0)] - 8 * tau2 * sumP[GetVectorIndex(1, 1)] / sumP[GetVectorIndex(1, 0)] + 24 * tau3 * sumP[GetVectorIndex(4, 1)] / sumP[GetVectorIndex(4, 0)]), (fEventWeight == kEventWeight::kUnity) ? 1.0 : weight3, rn); + cmVal.push_back(1 / cmDen[4] * (sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 1)] - 6 * sumP[getVectorIndex(2, 2)] * sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 1)] + 3 * sumP[getVectorIndex(2, 2)] * sumP[getVectorIndex(2, 2)] + 8 * sumP[getVectorIndex(3, 3)] * sumP[getVectorIndex(1, 1)] - 6 * sumP[getVectorIndex(4, 4)])); + dynamic_cast(fCMTermList->At(6))->FillProfile(centmult, cmVal[7], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen[4], rn); + cmVal.push_back(-4 * 1 / cmDen[4] * (sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 0)] - 3 * sumP[getVectorIndex(2, 2)] * sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 0)] - 3 * sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(2, 1)] + 3 * sumP[getVectorIndex(2, 2)] * sumP[getVectorIndex(2, 1)] + 6 * sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(3, 2)] - 6 * sumP[getVectorIndex(4, 3)])); + dynamic_cast(fCMTermList->At(7))->FillProfile(centmult, cmVal[8], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen[4], rn); + cmVal.push_back(6 * 1 / cmDen[4] * (sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 0)] * sumP[getVectorIndex(1, 0)] - sumP[getVectorIndex(2, 2)] * sumP[getVectorIndex(1, 0)] * sumP[getVectorIndex(1, 0)] - sumP[getVectorIndex(2, 0)] * sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 1)] + sumP[getVectorIndex(2, 0)] * sumP[getVectorIndex(2, 2)] - 4 * sumP[getVectorIndex(2, 1)] * sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 0)] + 4 * sumP[getVectorIndex(3, 2)] * sumP[getVectorIndex(1, 0)] + 4 * sumP[getVectorIndex(3, 1)] * sumP[getVectorIndex(1, 1)] + 2 * sumP[getVectorIndex(2, 1)] * sumP[getVectorIndex(2, 1)] - 6 * sumP[getVectorIndex(4, 2)])); + dynamic_cast(fCMTermList->At(8))->FillProfile(centmult, cmVal[9], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen[4], rn); + cmVal.push_back(-4 * 1 / cmDen[4] * (sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(1, 0)] * sumP[getVectorIndex(1, 0)] * sumP[getVectorIndex(1, 0)] - 3 * sumP[getVectorIndex(2, 1)] * sumP[getVectorIndex(1, 0)] * sumP[getVectorIndex(1, 0)] - 3 * sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(2, 0)] * sumP[getVectorIndex(1, 0)] + 3 * sumP[getVectorIndex(2, 1)] * sumP[getVectorIndex(2, 0)] + 2 * sumP[getVectorIndex(1, 1)] * sumP[getVectorIndex(3, 0)] + 6 * sumP[getVectorIndex(3, 1)] * sumP[getVectorIndex(1, 0)] - 6 * sumP[getVectorIndex(4, 1)])); + dynamic_cast(fCMTermList->At(9))->FillProfile(centmult, cmVal[10], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen[4], rn); + return; +} +void FlowPtContainer::fillArray(FillType a, FillType b, double c, double d) +{ + for (int idx = 0; idx < 81; ++idx) { + int i = idx % 3; + int j = ((idx - i) / 3) % 3; + int k = ((idx - j * 3 - i) / 9) % 3; + int l = ((idx - k * 9 - j * 3 - i) / 27) % 3; + if (std::holds_alternative>(a) && std::holds_alternative>(b)) { + arr[idx] += std::pow(std::get<0>(a), i) * std::pow(std::get<0>(b), j) * std::pow(c, k) * std::pow(d, l); + } else if (std::holds_alternative(a) && std::holds_alternative(b)) { + warr[idx] += std::pow(std::get<1>(a), i) * std::pow(std::get<1>(b), j) * std::pow(c, k) * std::pow(d, l); + } else { + LOGF(error, "FillType variant should hold same type for a and b during single function c"); + } + } return; } -double FlowPtContainer::OrderedAddition(std::vector vec) +template +double FlowPtContainer::getStdAABBCC(T& inarr) +{ + std::complex a = inarr[getVectorIndex(1, 0, 0, 0)]; + std::complex b = inarr[getVectorIndex(0, 1, 0, 0)]; + std::complex c = inarr[getVectorIndex(0, 0, 1, 0)]; + std::complex aa = inarr[getVectorIndex(2, 0, 0, 0)]; + std::complex bb = inarr[getVectorIndex(0, 2, 0, 0)]; + std::complex cc = inarr[getVectorIndex(0, 0, 2, 0)]; + std::complex ab = inarr[getVectorIndex(1, 1, 0, 0)]; + std::complex ac = inarr[getVectorIndex(1, 0, 1, 0)]; + std::complex bc = inarr[getVectorIndex(0, 1, 1, 0)]; + std::complex aab = inarr[getVectorIndex(2, 1, 0, 0)]; + std::complex aac = inarr[getVectorIndex(2, 0, 1, 0)]; + std::complex abb = inarr[getVectorIndex(1, 2, 0, 0)]; + std::complex acc = inarr[getVectorIndex(1, 0, 2, 0)]; + std::complex abc = inarr[getVectorIndex(1, 1, 1, 0)]; + std::complex bbc = inarr[getVectorIndex(0, 2, 1, 0)]; + std::complex bcc = inarr[getVectorIndex(0, 1, 2, 0)]; + std::complex aabb = inarr[getVectorIndex(2, 2, 0, 0)]; + std::complex aacc = inarr[getVectorIndex(2, 0, 2, 0)]; + std::complex aabc = inarr[getVectorIndex(2, 1, 1, 0)]; + std::complex abbc = inarr[getVectorIndex(1, 2, 1, 0)]; + std::complex abcc = inarr[getVectorIndex(1, 1, 2, 0)]; + std::complex bbcc = inarr[getVectorIndex(0, 2, 2, 0)]; + std::complex aabbc = inarr[getVectorIndex(2, 2, 1, 0)]; + std::complex aabcc = inarr[getVectorIndex(2, 1, 2, 0)]; + std::complex abbcc = inarr[getVectorIndex(1, 2, 2, 0)]; + std::complex aabbcc = inarr[getVectorIndex(2, 2, 2, 0)]; + return (a * a * b * b * c * c - aa * b * b * c * c - a * a * bb * c * c - a * a * b * b * cc - 4. * a * ab * b * c * c - + 4. * a * ac * b * b * c - 4. * a * a * b * bc * c + 4. * aab * b * c * c + 4. * aac * b * b * c + + 4. * a * abb * c * c + 4. * a * acc * b * b + 4. * a * a * bbc * c + 4. * a * a * b * bcc + + 16. * a * abc * b * c + aa * bb * c * c + aa * b * b * cc + a * a * bb * cc + 2. * ab * ab * c * c + + 2. * ac * ac * b * b + 2. * a * a * bc * bc + 4. * aa * b * bc * c + 4. * a * ac * bb * c + + 4. * a * ab * b * cc + 8. * ab * ac * b * c + 8. * a * ab * bc * c + 8. * a * ac * b * bc - 6. * aabb * c * c - + 24. * aabc * b * c - 6. * aacc * b * b - 24. * abbc * a * c - 24. * abcc * a * b - 6. * bbcc * a * a - + 8. * aab * bc * c - 8. * aac * b * bc - 4. * aac * bb * c - 4. * aab * b * cc - 8. * abb * ac * c - + 4. * abb * a * cc - 8. * acc * ab * b - 4. * acc * a * bb - 8. * bbc * a * ac - 4. * bbc * aa * c - + 8. * bcc * a * ab - 4. * bcc * aa * b - 16. * abc * ab * c - 16. * abc * ac * b - 16. * abc * a * bc - + aa * bb * cc - 2. * ab * ab * cc - 2. * ac * ac * bb - 2. * bc * bc * aa - 8. * ab * ac * bc + + 48. * aabbc * c + 48. * aabcc * b + 48. * abbcc * a + 6. * aabb * cc + 6. * aacc * bb + + 6. * bbcc * aa + 24. * aabc * bc + 24. * abbc * ac + 24. * abcc * ab + 8. * aab * bcc + + 8. * aac * bbc + 8. * abb * acc + 16. * abc * abc - 120. * aabbcc) + .real(); +} +template +double FlowPtContainer::getStdAABBCD(T& inarr) +{ + std::complex a = inarr[getVectorIndex(1, 0, 0, 0)]; + std::complex b = inarr[getVectorIndex(0, 1, 0, 0)]; + std::complex c = inarr[getVectorIndex(0, 0, 1, 0)]; + std::complex d = inarr[getVectorIndex(0, 0, 0, 1)]; + std::complex aa = inarr[getVectorIndex(2, 0, 0, 0)]; + std::complex bb = inarr[getVectorIndex(0, 2, 0, 0)]; + std::complex ab = inarr[getVectorIndex(1, 1, 0, 0)]; + std::complex ac = inarr[getVectorIndex(1, 0, 1, 0)]; + std::complex ad = inarr[getVectorIndex(1, 0, 0, 1)]; + std::complex bc = inarr[getVectorIndex(0, 1, 1, 0)]; + std::complex bd = inarr[getVectorIndex(0, 1, 0, 1)]; + std::complex cd = inarr[getVectorIndex(0, 0, 1, 1)]; + std::complex aab = inarr[getVectorIndex(2, 1, 0, 0)]; + std::complex aac = inarr[getVectorIndex(2, 0, 1, 0)]; + std::complex aad = inarr[getVectorIndex(2, 0, 0, 1)]; + std::complex abb = inarr[getVectorIndex(1, 2, 0, 0)]; + std::complex abc = inarr[getVectorIndex(1, 1, 1, 0)]; + std::complex abd = inarr[getVectorIndex(1, 1, 0, 1)]; + std::complex acd = inarr[getVectorIndex(1, 0, 1, 1)]; + std::complex bbc = inarr[getVectorIndex(0, 2, 1, 0)]; + std::complex bbd = inarr[getVectorIndex(0, 2, 0, 1)]; + std::complex bcd = inarr[getVectorIndex(0, 1, 1, 1)]; + std::complex aabb = inarr[getVectorIndex(2, 2, 0, 0)]; + std::complex aabc = inarr[getVectorIndex(2, 1, 1, 0)]; + std::complex aabd = inarr[getVectorIndex(2, 1, 0, 1)]; + std::complex aacd = inarr[getVectorIndex(2, 0, 1, 1)]; + std::complex abbc = inarr[getVectorIndex(1, 2, 1, 0)]; + std::complex abbd = inarr[getVectorIndex(1, 2, 0, 1)]; + std::complex abcd = inarr[getVectorIndex(1, 1, 1, 1)]; + std::complex bbcd = inarr[getVectorIndex(0, 2, 1, 1)]; + std::complex aabbc = inarr[getVectorIndex(2, 2, 1, 0)]; + std::complex aabbd = inarr[getVectorIndex(2, 2, 0, 1)]; + std::complex aabcd = inarr[getVectorIndex(2, 1, 1, 1)]; + std::complex abbcd = inarr[getVectorIndex(1, 2, 1, 1)]; + std::complex aabbcd = inarr[getVectorIndex(2, 2, 1, 1)]; + return (-120. * aabbcd + 48. * a * abbcd + 24. * ab * abcd + 16. * abc * abd + 12. * abbd * ac + + 8. * abb * acd + 12. * abbc * ad + 48. * aabcd * b - 24. * a * abcd * b - 8. * abd * ac * b - + 8. * ab * acd * b - 8. * abc * ad * b - 6. * aacd * b * b + 4. * a * acd * b * b + 2. * ac * ad * b * b + + 6. * aacd * bb - 4. * a * acd * bb - 2. * ac * ad * bb + 4. * aad * bbc - 4. * a * ad * bbc - + 6. * a * a * bbcd + 6. * aa * bbcd + 4. * aac * bbd - 4. * a * ac * bbd + 12. * aabd * bc - + 8. * a * abd * bc - 4. * ab * ad * bc - 4. * aad * b * bc + 4. * a * ad * b * bc + 8. * aab * bcd - + 8. * a * ab * bcd + 4. * a * a * b * bcd - 4. * aa * b * bcd + 12. * aabc * bd - 8. * a * abc * bd - + 4. * ab * ac * bd - 4. * aac * b * bd + 4. * a * ac * b * bd + 2. * a * a * bc * bd - 2. * aa * bc * bd + + 24. * aabbd * c - 12. * a * abbd * c - 8. * ab * abd * c - 4. * abb * ad * c - 12. * aabd * b * c + + 8. * a * abd * b * c + 4. * ab * ad * b * c + 2. * aad * b * b * c - 2. * a * ad * b * b * c - + 2. * aad * bb * c + 2. * a * ad * bb * c + 2. * a * a * bbd * c - 2. * aa * bbd * c - 4. * aab * bd * c + + 4. * a * ab * bd * c - 2. * a * a * b * bd * c + 2. * aa * b * bd * c + 6. * aabb * cd - 2. * ab * ab * cd - + 4. * a * abb * cd - 4. * aab * b * cd + 4. * a * ab * b * cd - a * a * b * b * cd + aa * b * b * cd + + a * a * bb * cd - aa * bb * cd + 24. * aabbc * d - 12. * a * abbc * d - 8. * ab * abc * d - + 4. * abb * ac * d - 12. * aabc * b * d + 8. * a * abc * b * d + 4. * ab * ac * b * d + 2. * aac * b * b * d - + 2. * a * ac * b * b * d - 2. * aac * bb * d + 2. * a * ac * bb * d + 2. * a * a * bbc * d - 2. * aa * bbc * d - + 4. * aab * bc * d + 4. * a * ab * bc * d - 2. * a * a * b * bc * d + 2. * aa * b * bc * d - 6. * aabb * c * d + + 2. * ab * ab * c * d + 4. * a * abb * c * d + 4. * aab * b * c * d - 4. * a * ab * b * c * d + + a * a * b * b * c * d - aa * b * b * c * d - a * a * bb * c * d + aa * bb * c * d) + .real(); +} +template +double FlowPtContainer::getStdAABBDD(T& inarr) +{ + std::complex a = inarr[getVectorIndex(1, 0, 0, 0)]; + std::complex b = inarr[getVectorIndex(0, 1, 0, 0)]; + std::complex d = inarr[getVectorIndex(0, 0, 0, 1)]; + std::complex aa = inarr[getVectorIndex(2, 0, 0, 0)]; + std::complex bb = inarr[getVectorIndex(0, 2, 0, 0)]; + std::complex dd = inarr[getVectorIndex(0, 0, 0, 2)]; + std::complex ab = inarr[getVectorIndex(1, 1, 0, 0)]; + std::complex ad = inarr[getVectorIndex(1, 0, 0, 1)]; + std::complex bd = inarr[getVectorIndex(0, 1, 0, 1)]; + std::complex aab = inarr[getVectorIndex(2, 1, 0, 0)]; + std::complex aad = inarr[getVectorIndex(2, 0, 0, 1)]; + std::complex abb = inarr[getVectorIndex(1, 2, 0, 0)]; + std::complex add = inarr[getVectorIndex(1, 0, 0, 2)]; + std::complex abd = inarr[getVectorIndex(1, 1, 0, 1)]; + std::complex bbd = inarr[getVectorIndex(0, 2, 0, 1)]; + std::complex bdd = inarr[getVectorIndex(0, 1, 0, 2)]; + std::complex aabb = inarr[getVectorIndex(2, 2, 0, 0)]; + std::complex aadd = inarr[getVectorIndex(2, 0, 0, 2)]; + std::complex aabd = inarr[getVectorIndex(2, 1, 0, 1)]; + std::complex abbd = inarr[getVectorIndex(1, 2, 0, 1)]; + std::complex abdd = inarr[getVectorIndex(1, 1, 0, 2)]; + std::complex bbdd = inarr[getVectorIndex(0, 2, 0, 2)]; + std::complex aabbd = inarr[getVectorIndex(2, 2, 0, 1)]; + std::complex aabdd = inarr[getVectorIndex(2, 1, 0, 2)]; + std::complex abbdd = inarr[getVectorIndex(1, 2, 0, 2)]; + std::complex aabbdd = inarr[getVectorIndex(2, 2, 0, 2)]; + return (-120. * aabbdd + 48. * a * abbdd + 16. * abd * abd + 24. * ab * abdd + 24. * abbd * ad + + 8. * abb * add + 48. * aabdd * b - 24. * a * abdd * b - 16. * abd * ad * b - 8. * ab * add * b - + 6. * aadd * b * b + 2. * ad * ad * b * b + 4. * a * add * b * b + 6. * aadd * bb - 2. * ad * ad * bb - + 4. * a * add * bb + 8. * aad * bbd - 8. * a * ad * bbd - 6. * a * a * bbdd + 6. * aa * bbdd + + 24. * aabd * bd - 16. * a * abd * bd - 8. * ab * ad * bd - 8. * aad * b * bd + 8. * a * ad * b * bd + + 2. * a * a * bd * bd - 2. * aa * bd * bd + 8. * aab * bdd - 8. * a * ab * bdd + 4. * a * a * b * bdd - + 4. * aa * b * bdd + 48. * aabbd * d - 24. * a * abbd * d - 16. * ab * abd * d - 8. * abb * ad * d - + 24. * aabd * b * d + 16. * a * abd * b * d + 8. * ab * ad * b * d + 4. * aad * b * b * d - + 4. * a * ad * b * b * d - 4. * aad * bb * d + 4. * a * ad * bb * d + 4. * a * a * bbd * d - 4. * aa * bbd * d - + 8. * aab * bd * d + 8. * a * ab * bd * d - 4. * a * a * b * bd * d + 4. * aa * b * bd * d - 6. * aabb * d * d + + 2. * ab * ab * d * d + 4. * a * abb * d * d + 4. * aab * b * d * d - 4. * a * ab * b * d * d + + a * a * b * b * d * d - aa * b * b * d * d - a * a * bb * d * d + aa * bb * d * d + 6. * aabb * dd - + 2. * ab * ab * dd - 4. * a * abb * dd - 4. * aab * b * dd + 4. * a * ab * b * dd - a * a * b * b * dd + + aa * b * b * dd + a * a * bb * dd - aa * bb * dd) + .real(); +} +template +double FlowPtContainer::getStdAABBC(T& inarr) +{ + std::complex a = inarr[getVectorIndex(1, 0, 0, 0)]; + std::complex b = inarr[getVectorIndex(0, 1, 0, 0)]; + std::complex c = inarr[getVectorIndex(0, 0, 1, 0)]; + std::complex aa = inarr[getVectorIndex(2, 0, 0, 0)]; + std::complex ab = inarr[getVectorIndex(1, 1, 0, 0)]; + std::complex ac = inarr[getVectorIndex(1, 0, 1, 0)]; + std::complex bb = inarr[getVectorIndex(0, 2, 0, 0)]; + std::complex bc = inarr[getVectorIndex(0, 1, 1, 0)]; + std::complex aab = inarr[getVectorIndex(2, 1, 0, 0)]; + std::complex aac = inarr[getVectorIndex(2, 0, 1, 0)]; + std::complex abb = inarr[getVectorIndex(1, 2, 0, 0)]; + std::complex abc = inarr[getVectorIndex(1, 1, 1, 0)]; + std::complex bbc = inarr[getVectorIndex(0, 2, 1, 0)]; + std::complex aabb = inarr[getVectorIndex(2, 2, 0, 0)]; + std::complex aabc = inarr[getVectorIndex(2, 1, 1, 0)]; + std::complex abbc = inarr[getVectorIndex(1, 2, 1, 0)]; + std::complex aabbc = inarr[getVectorIndex(2, 2, 1, 0)]; + return (a * a * b * b * c - aa * b * b * c - a * a * bb * c - 4. * ab * a * b * c - 2. * a * ac * b * b - 2. * a * a * bc * b + 2. * ab * ab * c + 4. * ab * ac * b + 4. * ab * bc * a + 8. * abc * a * b + 4. * aab * b * c + 2. * aac * b * b + 4. * abb * a * c + 2. * bbc * a * a + aa * bb * c + 2. * aa * b * bc + 2. * bb * a * ac - 12. * aabc * b - 12. * abbc * a - 6. * aabb * c - 8. * abc * ab - 2. * bbc * aa - 2. * aac * bb - 4. * aab * bc - 4. * abb * ac + 24. * aabbc).real(); +} +template +double FlowPtContainer::getStdAABBD(T& inarr) +{ + std::complex a = inarr[getVectorIndex(1, 0, 0, 0)]; + std::complex b = inarr[getVectorIndex(0, 1, 0, 0)]; + std::complex d = inarr[getVectorIndex(0, 0, 1, 0)]; + std::complex aa = inarr[getVectorIndex(2, 0, 0, 0)]; + std::complex ab = inarr[getVectorIndex(1, 1, 0, 0)]; + std::complex ad = inarr[getVectorIndex(1, 0, 1, 0)]; + std::complex bb = inarr[getVectorIndex(0, 2, 0, 0)]; + std::complex bd = inarr[getVectorIndex(0, 1, 1, 0)]; + std::complex aab = inarr[getVectorIndex(2, 1, 0, 0)]; + std::complex aad = inarr[getVectorIndex(2, 0, 1, 0)]; + std::complex abb = inarr[getVectorIndex(1, 2, 0, 0)]; + std::complex abd = inarr[getVectorIndex(1, 1, 1, 0)]; + std::complex bbd = inarr[getVectorIndex(0, 2, 1, 0)]; + std::complex aabb = inarr[getVectorIndex(2, 2, 0, 0)]; + std::complex aabd = inarr[getVectorIndex(2, 1, 1, 0)]; + std::complex abbd = inarr[getVectorIndex(1, 2, 1, 0)]; + std::complex aabbd = inarr[getVectorIndex(2, 2, 1, 0)]; + return (a * a * b * b * d - aa * b * b * d - a * a * bb * d - 4. * ab * a * b * d - 2. * a * ad * b * b - 2. * a * a * bd * b + 2. * ab * ab * d + 4. * ab * ad * b + 4. * ab * bd * a + 8. * abd * a * b + 4. * aab * b * d + 2. * aad * b * b + 4. * abb * a * d + 2. * bbd * a * a + aa * bb * d + 2. * aa * b * bd + 2. * bb * a * ad - 12. * aabd * b - 12. * abbd * a - 6. * aabb * d - 8. * abd * ab - 2. * bbd * aa - 2. * aad * bb - 4. * aab * bd - 4. * abb * ad + 24. * aabbd).real(); +} +template +double FlowPtContainer::getStdABCC(T& inarr) +{ + std::complex a = inarr[getVectorIndex(1, 0, 0, 0)]; + std::complex b = inarr[getVectorIndex(0, 1, 0, 0)]; + std::complex c = inarr[getVectorIndex(0, 0, 1, 0)]; + std::complex ab = inarr[getVectorIndex(1, 1, 0, 0)]; + std::complex ac = inarr[getVectorIndex(1, 0, 1, 0)]; + std::complex bc = inarr[getVectorIndex(0, 1, 1, 0)]; + std::complex cc = inarr[getVectorIndex(0, 0, 2, 0)]; + std::complex abc = inarr[getVectorIndex(1, 1, 1, 0)]; + std::complex acc = inarr[getVectorIndex(1, 0, 2, 0)]; + std::complex bcc = inarr[getVectorIndex(0, 1, 2, 0)]; + std::complex abcc = inarr[getVectorIndex(1, 1, 2, 0)]; + return (a * b * c * c - a * b * cc - 2. * a * bc * c - 2. * ac * b * c - ab * c * c + 2. * acc * b + 2. * a * bcc + 4. * abc * c + ab * cc + 2. * ac * bc - 6. * abcc).real(); +} +template +double FlowPtContainer::getStdABCD(T& inarr) +{ + std::complex a = inarr[getVectorIndex(1, 0, 0, 0)]; + std::complex b = inarr[getVectorIndex(0, 1, 0, 0)]; + std::complex c = inarr[getVectorIndex(0, 0, 1, 0)]; + std::complex d = inarr[getVectorIndex(0, 0, 0, 1)]; + std::complex ab = inarr[getVectorIndex(1, 1, 0, 0)]; + std::complex ac = inarr[getVectorIndex(1, 0, 1, 0)]; + std::complex ad = inarr[getVectorIndex(1, 0, 0, 1)]; + std::complex bc = inarr[getVectorIndex(0, 1, 1, 0)]; + std::complex bd = inarr[getVectorIndex(0, 1, 0, 1)]; + std::complex cd = inarr[getVectorIndex(0, 0, 1, 1)]; + std::complex abc = inarr[getVectorIndex(1, 1, 1, 0)]; + std::complex abd = inarr[getVectorIndex(1, 1, 0, 1)]; + std::complex acd = inarr[getVectorIndex(1, 0, 1, 1)]; + std::complex bcd = inarr[getVectorIndex(0, 1, 1, 1)]; + std::complex abcd = inarr[getVectorIndex(1, 1, 0, 1)]; + return (-6. * abcd + 2. * acd * b + ad * bc + 2. * a * bcd + ac * bd + 2. * abd * c - ad * b * c - + a * bd * c + ab * cd - a * b * cd + 2. * abc * d - ac * b * d - a * bc * d - ab * c * d + + a * b * c * d) + .real(); +} +template +double FlowPtContainer::getStdABDD(T& inarr) +{ + std::complex a = inarr[getVectorIndex(1, 0, 0, 0)]; + std::complex b = inarr[getVectorIndex(0, 1, 0, 0)]; + std::complex d = inarr[getVectorIndex(0, 0, 0, 1)]; + std::complex ab = inarr[getVectorIndex(1, 1, 0, 0)]; + std::complex ad = inarr[getVectorIndex(1, 0, 0, 1)]; + std::complex bd = inarr[getVectorIndex(0, 1, 0, 1)]; + std::complex dd = inarr[getVectorIndex(0, 0, 0, 2)]; + std::complex abd = inarr[getVectorIndex(1, 1, 0, 1)]; + std::complex add = inarr[getVectorIndex(1, 0, 0, 2)]; + std::complex bdd = inarr[getVectorIndex(0, 1, 0, 2)]; + std::complex abdd = inarr[getVectorIndex(1, 1, 0, 2)]; + return (a * b * d * d - a * b * dd - 2. * a * bd * d - 2. * ad * b * d - ab * d * d + 2. * add * b + 2. * a * bdd + 4. * abd * d + ab * dd + 2. * ad * bd - 6. * abdd).real(); +} +template +double FlowPtContainer::getStdABC(T& inarr) +{ + std::complex a = inarr[getVectorIndex(1, 0, 0, 0)]; + std::complex b = inarr[getVectorIndex(0, 1, 0, 0)]; + std::complex c = inarr[getVectorIndex(0, 0, 1, 0)]; + std::complex ab = inarr[getVectorIndex(1, 1, 0, 0)]; + std::complex ac = inarr[getVectorIndex(1, 0, 1, 0)]; + std::complex bc = inarr[getVectorIndex(0, 1, 1, 0)]; + std::complex abc = inarr[getVectorIndex(1, 1, 1, 0)]; + return (a * b * c - ab * c - ac * b - a * bc + 2. * abc).real(); +} +template +double FlowPtContainer::getStdABD(T& inarr) +{ + std::complex a = inarr[getVectorIndex(1, 0, 0, 0)]; + std::complex b = inarr[getVectorIndex(0, 1, 0, 0)]; + std::complex d = inarr[getVectorIndex(0, 0, 0, 1)]; + std::complex ab = inarr[getVectorIndex(1, 1, 0, 0)]; + std::complex ad = inarr[getVectorIndex(1, 0, 0, 1)]; + std::complex bd = inarr[getVectorIndex(0, 1, 0, 1)]; + std::complex abd = inarr[getVectorIndex(1, 1, 0, 1)]; + return (a * b * d - ab * d - ad * b - a * bd + 2. * abd).real(); +} +double FlowPtContainer::orderedAddition(std::vector vec) { double sum = 0; std::sort(vec.begin(), vec.end()); - for (int i = 0; i < vec.size(); i++) { + for (size_t i = 0; i < vec.size(); i++) { sum += vec[i]; } return sum; } -void FlowPtContainer::RebinMulti(Int_t nbins) +void FlowPtContainer::rebinMulti(int nbins) { if (fCMTermList) { - for (Int_t i = 0; i < fCMTermList->GetEntries(); i++) + for (int i = 0; i < fCMTermList->GetEntries(); i++) dynamic_cast(fCMTermList->At(i))->RebinMulti(nbins); } if (fCorrList) { - for (Int_t i = 0; i < fCorrList->GetEntries(); i++) + for (int i = 0; i < fCorrList->GetEntries(); i++) dynamic_cast(fCorrList->At(i))->RebinMulti(nbins); } if (fCovList) { - for (Int_t i = 0; i < fCovList->GetEntries(); i++) + for (int i = 0; i < fCovList->GetEntries(); i++) dynamic_cast(fCovList->At(i))->RebinMulti(nbins); } return; } -void FlowPtContainer::RebinMulti(Int_t nbins, Double_t* binedges) +void FlowPtContainer::rebinMulti(int nbins, double* binedges) { if (fCMTermList) { - for (Int_t i = 0; i < fCMTermList->GetEntries(); i++) + for (int i = 0; i < fCMTermList->GetEntries(); i++) dynamic_cast(fCMTermList->At(i))->RebinMulti(nbins, binedges); } if (fCorrList) { - for (Int_t i = 0; i < fCorrList->GetEntries(); i++) + for (int i = 0; i < fCorrList->GetEntries(); i++) dynamic_cast(fCorrList->At(i))->RebinMulti(nbins, binedges); } if (fCovList) { - for (Int_t i = 0; i < fCovList->GetEntries(); i++) + for (int i = 0; i < fCovList->GetEntries(); i++) dynamic_cast(fCovList->At(i))->RebinMulti(nbins, binedges); } return; } TH1* FlowPtContainer::getCorrHist(int ind, int m) { - return dynamic_cast(fCorrList->FindObject(Form("corr_%ipar", m)))->getHist(ind); + return dynamic_cast(fCorrList->FindObject(Form("mpt%i", m)))->getHist(ind); } TH1* FlowPtContainer::getCentralMomentHist(int ind, int m) { if (!fCentralMomentList) - CreateCentralMomentList(); + createCentralMomentList(); if (!fCentralMomentList) return 0; if (ind + 1 < fCentralMomentList->GetEntries()) - return dynamic_cast(fCentralMomentList->FindObject(Form("cm%i_%i", m + 1, ind))); + return dynamic_cast(fCentralMomentList->FindObject(Form("cm%i_%i", m, ind))); return 0; } -void FlowPtContainer::CreateCentralMomentList() +void FlowPtContainer::createCentralMomentList() { if (fCentralMomentList) delete fCentralMomentList; @@ -340,12 +832,12 @@ void FlowPtContainer::CreateCentralMomentList() dynamic_cast(fCMTermList->FindObject(Form("cm%i_Mpt%i", m, j)))->SetErrorOption("g"); hTs.push_back(reinterpret_cast(fCMTermList->FindObject(Form("cm%i_Mpt%i", m, j)))->getHist(i)); } - CalculateCentralMomentHists(hTs, i, m, hMpt); + calculateCentralMomentHists(hTs, i, m, hMpt); } } return; } -void FlowPtContainer::CalculateCentralMomentHists(std::vector inh, int ind, int m, TH1* hMpt) +void FlowPtContainer::calculateCentralMomentHists(std::vector inh, int ind, int m, TH1* hMpt) { TH1* reth = reinterpret_cast(inh[0]->Clone(Form("cm%i_%i", m, ind))); for (auto i(1); i < m; ++i) { @@ -361,14 +853,14 @@ void FlowPtContainer::CalculateCentralMomentHists(std::vector inh, int ind TH1* FlowPtContainer::getCumulantHist(int ind, int m) { if (!fCumulantList) - CreateCumulantList(); + createCumulantList(); if (!fCumulantList) return 0; if (ind + 1 < fCumulantList->GetEntries()) return reinterpret_cast(fCumulantList->At((ind + 1) * mpar + m - 1)); return 0; } -void FlowPtContainer::CreateCumulantList() +void FlowPtContainer::createCumulantList() { if (fCumulantList) delete fCumulantList; @@ -378,17 +870,17 @@ void FlowPtContainer::CreateCumulantList() for (int i = -1; i < reinterpret_cast(fCorrList->At(0))->getNSubs(); ++i) { std::vector hTs; for (int j = 0; j < mpar; ++j) { - dynamic_cast(fCorrList->FindObject(Form("corr_%ipar", j + 1)))->SetErrorOption("g"); - hTs.push_back(reinterpret_cast(fCorrList->FindObject(Form("corr_%ipar", j + 1)))->getHist(i)); + dynamic_cast(fCorrList->FindObject(Form("mpt%i", j + 1)))->SetErrorOption("g"); + hTs.push_back(reinterpret_cast(fCorrList->FindObject(Form("mpt%i", j + 1)))->getHist(i)); } - CalculateCumulantHists(hTs, i); + calculateCumulantHists(hTs, i); } //((BootstrapProfile*)fCorrList->At(0))->PresetWeights(0); return; } -void FlowPtContainer::CalculateCumulantHists(std::vector inh, int ind) +void FlowPtContainer::calculateCumulantHists(std::vector inh, int ind) { - auto binomial = [&](const int n, const int m) { assert(n >= m); return fFactorial[n]/(fFactorial[m]*fFactorial[n-m]); }; + auto binomial = [&](const int n, const int m) { assert(n >= m); return FactorialArray[n]/(FactorialArray[m]*FactorialArray[n-m]); }; for (int m = 1; m <= mpar; ++m) { TH1* reth = dynamic_cast(inh[m - 1]->Clone(Form("reth%i_%i", m, ind))); // TH1* hWeights = (TH1*)inh[m-1]->Clone(Form("hWeights%i_%i",m,ind)); @@ -410,51 +902,58 @@ Long64_t FlowPtContainer::Merge(TCollection* collist) if (!fCorrList || !fCMTermList) return 0; Long64_t nmerged = 0; - TIter all_PTC(collist); - FlowPtContainer* l_PTC = 0; - while ((l_PTC = dynamic_cast(all_PTC()))) { - TList* t_CMTerm = l_PTC->fCMTermList; - TList* t_Corr = l_PTC->fCorrList; - TList* t_Cum = l_PTC->fCumulantList; - TList* t_CM = l_PTC->fCentralMomentList; - if (t_CMTerm) { + TIter allPTC(collist); + FlowPtContainer* lPTC = 0; + while ((lPTC = dynamic_cast(allPTC()))) { + TList* tCMTerm = lPTC->fCMTermList; + TList* tCorr = lPTC->fCorrList; + TList* tCov = lPTC->fCovList; + TList* tCum = lPTC->fCumulantList; + TList* tCM = lPTC->fCentralMomentList; + if (tCMTerm) { if (!fCMTermList) - fCMTermList = dynamic_cast(t_CMTerm->Clone()); + fCMTermList = dynamic_cast(tCMTerm->Clone()); else - MergeBSLists(fCMTermList, t_CMTerm); + mergeBSLists(fCMTermList, tCMTerm); nmerged++; } - if (t_Corr) { + if (tCorr) { if (!fCorrList) - fCorrList = dynamic_cast(t_Corr->Clone()); + fCorrList = dynamic_cast(tCorr->Clone()); + else + mergeBSLists(fCorrList, tCorr); + } + if (tCov) { + if (!fCovList) + fCovList = dynamic_cast(tCov->Clone()); else - MergeBSLists(fCorrList, t_Corr); + mergeBSLists(fCovList, tCov); } - if (t_Cum) { + if (tCum) { if (!fCumulantList) - fCumulantList = dynamic_cast(t_Cum->Clone()); + fCumulantList = dynamic_cast(tCum->Clone()); else - MergeBSLists(fCumulantList, t_Cum); + mergeBSLists(fCumulantList, tCum); } - if (t_CM) { + if (tCM) { if (!fCentralMomentList) - fCentralMomentList = dynamic_cast(t_CM->Clone()); + fCentralMomentList = dynamic_cast(tCM->Clone()); else - MergeBSLists(fCentralMomentList, t_CM); + mergeBSLists(fCentralMomentList, tCM); } } return nmerged; } -void FlowPtContainer::MergeBSLists(TList* source, TList* target) +void FlowPtContainer::mergeBSLists(TList* source, TList* target) { if (source->GetEntries() != target->GetEntries()) { - printf("Number in lists to be merged are not the same, skipping...\n"); + LOGF(warning, "Number in lists to be merged are not the same, skipping...\n"); return; } - for (Int_t i = 0; i < source->GetEntries(); i++) { - BootstrapProfile* l_obj = dynamic_cast(source->At(i)); - BootstrapProfile* t_obj = dynamic_cast(target->At(i)); - l_obj->MergeBS(t_obj); + for (int i = 0; i < source->GetEntries(); i++) { + BootstrapProfile* lObj = dynamic_cast(source->At(i)); + BootstrapProfile* tObj = dynamic_cast(target->At(i)); + lObj->MergeBS(tObj); } } TH1* FlowPtContainer::raiseHistToPower(TH1* inh, double p) @@ -463,8 +962,8 @@ TH1* FlowPtContainer::raiseHistToPower(TH1* inh, double p) reth->SetName(Form("power%.2f_%s", p, inh->GetName())); for (int i = 1; i <= inh->GetNbinsX(); i++) { if (inh->GetBinContent(i) >= 0 || std::floor(p) == p) { - reth->SetBinContent(i, pow(inh->GetBinContent(i), p)); - reth->SetBinError(i, p * pow(reth->GetBinContent(i), p - 1) * inh->GetBinError(i)); + reth->SetBinContent(i, std::pow(inh->GetBinContent(i), p)); + reth->SetBinError(i, p * std::pow(reth->GetBinContent(i), p - 1) * inh->GetBinError(i)); } else { reth->SetBinContent(i, -999); reth->SetBinError(i, 0.000000001); diff --git a/PWGCF/GenericFramework/Core/FlowPtContainer.h b/PWGCF/GenericFramework/Core/FlowPtContainer.h index 981c1d0540c..91442985cc0 100644 --- a/PWGCF/GenericFramework/Core/FlowPtContainer.h +++ b/PWGCF/GenericFramework/Core/FlowPtContainer.h @@ -9,11 +9,17 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file FlowPtContainer.h +/// \brief Class to handle angular and transverse momentum correlations +/// \author Emil Gorm Nielsen, NBI, emil.gorm.nielsen@cern.ch + #ifndef PWGCF_GENERICFRAMEWORK_CORE_FLOWPTCONTAINER_H_ #define PWGCF_GENERICFRAMEWORK_CORE_FLOWPTCONTAINER_H_ #include #include +#include +#include #include "BootstrapProfile.h" #include "TNamed.h" #include "TList.h" @@ -24,9 +30,9 @@ namespace o2::analysis::genericframework::eventweight { -enum kEventWeight { - kUnity, - kTuples +enum EventWeight { + UnityWeight, + TupleWeight }; }; @@ -36,60 +42,117 @@ using namespace o2::analysis::genericframework::eventweight; class FlowPtContainer : public TNamed { public: + using FillType = std::variant, double>; FlowPtContainer(); explicit FlowPtContainer(const char* name); ~FlowPtContainer(); - FlowPtContainer(const char* name, const char* title, int nbinsx, double* xbins, const int& m, const GFWCorrConfigs& configs); - FlowPtContainer(const char* name, const char* title, int nbinsx, double xlow, double xhigh, const int& m, const GFWCorrConfigs& configs); - void Initialise(const o2::framework::AxisSpec axis, const int& m, const GFWCorrConfigs& configs, const int& nsub = 10); - void Initialise(int nbinsx, double* xbins, const int& m, const GFWCorrConfigs& configs, const int& nsub = 10); - void Initialise(int nbinsx, double xlow, double xhigh, const int& m, const GFWCorrConfigs& configs, const int& nsub = 10); - void Fill(const double& w, const double& pt); - int GetVectorIndex(const int i, const int j) { return j * (mpar + 1) + i; } - void CalculateCorrelations(); - void CalculateCMTerms(); - void FillPtProfiles(const Double_t& lMult, const Double_t& rn); - void FillVnPtProfiles(const double& lMult, const double& flowval, const double& flowtuples, const double& rn, uint8_t mask); - void FillCMProfiles(const double& lMult, const double& rn); - TList* GetCorrList() { return fCorrList; } - TList* GetCMTermList() { return fCMTermList; } - void SetEventWeight(const unsigned int& lWeight) { fEventWeight = lWeight; } - void RebinMulti(Int_t nbins); - void RebinMulti(Int_t nbins, double* binedges); + FlowPtContainer(const char* name, const char* title); + void initialise(const o2::framework::AxisSpec axis, const int& m, const GFWCorrConfigs& configs, const int& nsub = 10); + void initialise(int nbinsx, double* xbins, const int& m, const GFWCorrConfigs& configs, const int& nsub = 10); + void initialise(int nbinsx, double xlow, double xhigh, const int& m, const GFWCorrConfigs& configs, const int& nsub = 10); + void fill(const double& w, const double& pt); + void fillArray(FillType a, FillType b, double c, double d); + int getVectorIndex(const int i, const int j) { return j * (mpar + 1) + i; } // index for 2d array for storing pt correlations + int getVectorIndex(const int i, const int j, const int k, const int l) { return i + j * 3 + k * 3 * 3 + l * 3 * 3 * 3; } // index for 4d array for std vnpt correlation - size 3x3x3x3 + void calculateCorrelations(); + void calculateCMTerms(); + void fillPtProfiles(const double& lMult, const double& rn); + void fillVnPtCorrProfiles(const double& lMult, const double& flowval, const double& flowtuples, const double& rn, uint8_t mask); + void fillVnDeltaPtProfiles(const double& centmult, const double& flowval, const double& flowtuples, const double& rn, uint8_t mask); + void fillVnDeltaPtStdProfiles(const double& centmult, const double& rn); + void fillVnPtCorrStdProfiles(const double& centmult, const double& rn); + void fillVnPtProfiles(const double& centmult, const double& flowval, const double& flowtuples, const double& rn, uint8_t mask) + { + if (fUseCentralMoments) + fillVnDeltaPtProfiles(centmult, flowval, flowtuples, rn, mask); + else + fillVnPtCorrProfiles(centmult, flowval, flowtuples, rn, mask); + } + void fillVnPtStdProfiles(const double& centmult, const double& rn) + { + if (fUseCentralMoments) + fillVnDeltaPtStdProfiles(centmult, rn); + else + fillVnPtCorrStdProfiles(centmult, rn); + } + void fillCMProfiles(const double& lMult, const double& rn); + TList* getCorrList() { return fCorrList; } + TList* getCMTermList() { return fCMTermList; } + TList* getCovList() { return fCovList; } + void setEventWeight(const unsigned int& lWeight) { fEventWeight = lWeight; } + void setUseCentralMoments(bool newval) { fUseCentralMoments = newval; } + void setUseGapMethod(bool newval) { fUseGap = newval; } + bool usesCentralMoments() { return fUseCentralMoments; } + bool usesGap() { return fUseGap; } + void rebinMulti(int nbins); + void rebinMulti(int nbins, double* binedges); TH1* getCentralMomentHist(int ind, int m); TH1* getCumulantHist(int ind, int m); TH1* getCorrHist(int ind, int m); - Int_t getMpar() { return mpar; } + int getMpar() { return mpar; } Long64_t Merge(TCollection* collist); - Double_t OrderedAddition(std::vector vec); - void CreateCentralMomentList(); - void CalculateCentralMomentHists(std::vector inh, int ind, int m, TH1* hMpt); - void CreateCumulantList(); - void CalculateCumulantHists(std::vector inh, Int_t ind); - void ClearVector() + double orderedAddition(std::vector vec); + void createCentralMomentList(); + void calculateCentralMomentHists(std::vector inh, int ind, int m, TH1* hMpt); + void createCumulantList(); + void calculateCumulantHists(std::vector inh, int ind); + void clearVector() { sumP.clear(); sumP.resize((mpar + 1) * (mpar + 1)); + cmVal.clear(); + cmDen.clear(); fillCounter = 0; + arr.clear(); + arr.resize(3 * 3 * 3 * 3, {0.0, 0.0}); + warr.clear(); + warr.resize(3 * 3 * 3 * 3, 0.0); }; - private: TList* fCMTermList; TList* fCorrList; TList* fCovList; TList* fCumulantList; TList* fCentralMomentList; - int mpar; - int fillCounter; - unsigned int fEventWeight; - void MergeBSLists(TList* source, TList* target); + + int mpar; //! + int fillCounter; //! + unsigned int fEventWeight; //! + bool fUseCentralMoments; //! + bool fUseGap; //! + void mergeBSLists(TList* source, TList* target); TH1* raiseHistToPower(TH1* inh, double p); - std::vector sumP; //! - std::vector corrNum; //! - std::vector corrDen; //! + std::vector sumP; //! + std::vector corrNum; //! + std::vector corrDen; //! + std::vector cmVal; //! + std::vector cmDen; //! + std::vector> arr; //! + std::vector warr; //! + template + double getStdAABBCC(T& inarr); + template + double getStdAABBCD(T& inarr); + template + double getStdAABBDD(T& inarr); + template + double getStdAABBC(T& inarr); + template + double getStdAABBD(T& inarr); + template + double getStdABCC(T& inarr); + template + double getStdABCD(T& inarr); + template + double getStdABDD(T& inarr); + template + double getStdABC(T& inarr); + template + double getStdABD(T& inarr); - static constexpr float fFactorial[9] = {1., 1., 2., 6., 24., 120., 720., 5040., 40320.}; - static constexpr int fSign[9] = {1, -1, 1, -1, 1, -1, 1, -1, 1}; - ClassDef(FlowPtContainer, 1); + private: + static constexpr float FactorialArray[9] = {1., 1., 2., 6., 24., 120., 720., 5040., 40320.}; + static constexpr int SignArray[9] = {1, -1, 1, -1, 1, -1, 1, -1, 1}; + ClassDef(FlowPtContainer, 2); }; #endif // PWGCF_GENERICFRAMEWORK_CORE_FLOWPTCONTAINER_H_ diff --git a/PWGCF/GenericFramework/Core/GFWConfig.h b/PWGCF/GenericFramework/Core/GFWConfig.h index 9c086acbef1..779d06b604e 100644 --- a/PWGCF/GenericFramework/Core/GFWConfig.h +++ b/PWGCF/GenericFramework/Core/GFWConfig.h @@ -35,7 +35,7 @@ int CheckSameSize(const std::vector& first) template int CheckSameSize(const std::vector& first, const std::vector&... rest) { - int size = first.size(); + size_t size = first.size(); bool allSameSize = ((size == rest.size()) && ...); return allSameSize ? size : -1; @@ -145,7 +145,7 @@ class GFWRegions auto Print() const { - for (auto i = 0; i < names.size(); ++i) { + for (size_t i = 0; i < names.size(); ++i) { LOGF(info, "{%s, %.1f, %.1f, %d, %d}", names[i].c_str(), etaminvals[i], etamaxvals[i], pTDifs[i], bitmasks[i]); } return; @@ -190,7 +190,7 @@ class GFWCorrConfigs auto Print() const { - for (auto i = 0; i < corrs.size(); ++i) { + for (size_t i = 0; i < corrs.size(); ++i) { LOGF(info, "{%s,%s,%d,%d}", heads[i].c_str(), corrs[i].c_str(), pTDifs[i], pTCorrMasks[i]); } return; diff --git a/PWGCF/GenericFramework/Core/GFWPowerArray.cxx b/PWGCF/GenericFramework/Core/GFWPowerArray.cxx index 82291e507a2..609b235ec6f 100644 --- a/PWGCF/GenericFramework/Core/GFWPowerArray.cxx +++ b/PWGCF/GenericFramework/Core/GFWPowerArray.cxx @@ -52,7 +52,7 @@ void GFWPowerArray::RecursiveFunction(HarSet& masterVector, HarSet hars, int off { HarSet compVec = AddConstant(hars, offset); FlushVectorToMaster(masterVector, compVec, MaxPower); - for (int i = 0; i < hars.size(); i++) + for (size_t i = 0; i < hars.size(); i++) RecursiveFunction(masterVector, TrimVec(hars, i), offset + hars.at(i), MaxPower); ; }; diff --git a/PWGCF/GenericFramework/Core/GFWWeights.cxx b/PWGCF/GenericFramework/Core/GFWWeights.cxx index 8ff60183f99..4d2d41cd85d 100644 --- a/PWGCF/GenericFramework/Core/GFWWeights.cxx +++ b/PWGCF/GenericFramework/Core/GFWWeights.cxx @@ -11,6 +11,8 @@ #include "GFWWeights.h" #include "TMath.h" +#include + GFWWeights::GFWWeights() : TNamed("", ""), fDataFilled(kFALSE), fMCFilled(kFALSE), @@ -44,7 +46,7 @@ GFWWeights::~GFWWeights() if (fbinsPt) delete[] fbinsPt; }; -void GFWWeights::SetPtBins(int Nbins, double* bins) +void GFWWeights::setPtBins(int Nbins, double* bins) { if (fbinsPt) delete[] fbinsPt; @@ -53,7 +55,7 @@ void GFWWeights::SetPtBins(int Nbins, double* bins) for (int i = 0; i <= fNbinsPt; ++i) fbinsPt[i] = bins[i]; }; -void GFWWeights::Init(bool AddData, bool AddMC) +void GFWWeights::init(bool AddData, bool AddMC) { if (!fbinsPt) { // If pT bins not initialized, set to default (-1 to 1e6) to accept everything fNbinsPt = 1; @@ -65,7 +67,7 @@ void GFWWeights::Init(bool AddData, bool AddMC) fW_data = new TObjArray(); fW_data->SetName("GFWWeights_Data"); fW_data->SetOwner(kTRUE); - const char* tnd = GetBinName(0, 0, Form("data_%s", this->GetName())); + const char* tnd = getBinName(0, 0, Form("data_%s", this->GetName())); fW_data->Add(new TH3D(tnd, ";#varphi;#eta;v_{z}", 60, 0, TMath::TwoPi(), 64, -1.6, 1.6, 40, -10, 10)); fDataFilled = kTRUE; } @@ -76,8 +78,8 @@ void GFWWeights::Init(bool AddData, bool AddMC) fW_mcgen->SetName("GFWWeights_MCGen"); fW_mcrec->SetOwner(kTRUE); fW_mcgen->SetOwner(kTRUE); - const char* tnr = GetBinName(0, 0, "mcrec"); // all integrated over cent. anyway - const char* tng = GetBinName(0, 0, "mcgen"); // all integrated over cent. anyway + const char* tnr = getBinName(0, 0, "mcrec"); // all integrated over cent. anyway + const char* tng = getBinName(0, 0, "mcgen"); // all integrated over cent. anyway fW_mcrec->Add(new TH3D(tnr, ";#it{p}_{T};#eta;v_{z}", fNbinsPt, 0, 20, 64, -1.6, 1.6, 40, -10, 10)); fW_mcgen->Add(new TH3D(tng, ";#it{p}_{T};#eta;v_{z}", fNbinsPt, 0, 20, 64, -1.6, 1.6, 40, -10, 10)); reinterpret_cast(fW_mcrec->At(fW_mcrec->GetEntries() - 1))->GetXaxis()->Set(fNbinsPt, fbinsPt); @@ -86,7 +88,7 @@ void GFWWeights::Init(bool AddData, bool AddMC) } }; -void GFWWeights::Fill(double phi, double eta, double vz, double pt, double /*cent*/, int htype, double weight) +void GFWWeights::fill(double phi, double eta, double vz, double pt, double /*cent*/, int htype, double weight) { TObjArray* tar = 0; const char* pf = ""; @@ -104,15 +106,15 @@ void GFWWeights::Fill(double phi, double eta, double vz, double pt, double /*cen } if (!tar) return; - TH3D* th3 = reinterpret_cast(tar->FindObject(GetBinName(0, 0, pf))); // pT bin 0, V0M bin 0, since all integrated + TH3D* th3 = reinterpret_cast(tar->FindObject(getBinName(0, 0, pf))); // pT bin 0, V0M bin 0, since all integrated if (!th3) { if (!htype) - tar->Add(new TH3D(GetBinName(0, 0, pf), ";#varphi;#eta;v_{z}", 60, 0, TMath::TwoPi(), 64, -1.6, 1.6, 40, -10, 10)); // 0,0 since all integrated + tar->Add(new TH3D(getBinName(0, 0, pf), ";#varphi;#eta;v_{z}", 60, 0, TMath::TwoPi(), 64, -1.6, 1.6, 40, -10, 10)); // 0,0 since all integrated th3 = reinterpret_cast(tar->At(tar->GetEntries() - 1)); } th3->Fill(htype ? pt : phi, eta, vz, weight); }; -double GFWWeights::GetWeight(double phi, double eta, double vz, double pt, double /*cent*/, int htype) +double GFWWeights::getWeight(double phi, double eta, double vz, double pt, double /*cent*/, int htype) { TObjArray* tar = 0; const char* pf = ""; @@ -130,7 +132,7 @@ double GFWWeights::GetWeight(double phi, double eta, double vz, double pt, doubl } if (!tar) return 1; - TH3D* th3 = reinterpret_cast(tar->FindObject(GetBinName(0, 0, pf))); + TH3D* th3 = reinterpret_cast(tar->FindObject(getBinName(0, 0, pf))); if (!th3) return 1; //-1; int xind = th3->GetXaxis()->FindBin(htype ? pt : phi); @@ -141,10 +143,10 @@ double GFWWeights::GetWeight(double phi, double eta, double vz, double pt, doubl return 1. / weight; return 1; }; -double GFWWeights::GetNUA(double phi, double eta, double vz) +double GFWWeights::getNUA(double phi, double eta, double vz) { if (!fAccInt) - CreateNUA(); + createNUA(); int xind = fAccInt->GetXaxis()->FindBin(phi); int etaind = fAccInt->GetYaxis()->FindBin(eta); int vzind = fAccInt->GetZaxis()->FindBin(vz); @@ -153,10 +155,10 @@ double GFWWeights::GetNUA(double phi, double eta, double vz) return 1. / weight; return 1; } -double GFWWeights::GetNUE(double pt, double eta, double vz) +double GFWWeights::getNUE(double pt, double eta, double vz) { if (!fEffInt) - CreateNUE(); + createNUE(); int xind = fEffInt->GetXaxis()->FindBin(pt); int etaind = fEffInt->GetYaxis()->FindBin(eta); int vzind = fEffInt->GetZaxis()->FindBin(vz); @@ -165,7 +167,7 @@ double GFWWeights::GetNUE(double pt, double eta, double vz) return 1. / weight; return 1; } -double GFWWeights::FindMax(TH3D* inh, int& ix, int& iy, int& iz) +double GFWWeights::findMax(TH3D* inh, int& ix, int& iy, int& iz) { double maxv = inh->GetBinContent(1, 1, 1); for (int i = 1; i <= inh->GetNbinsX(); i++) @@ -179,10 +181,10 @@ double GFWWeights::FindMax(TH3D* inh, int& ix, int& iy, int& iz) } return maxv; }; -void GFWWeights::MCToEfficiency() +void GFWWeights::mcToEfficiency() { if (fW_mcgen->GetEntries() < 1) { - printf("MC gen. array empty. This is probably because effs. have been calculated and the generated particle histograms have been cleared out!\n"); + LOGF(info, "MC gen. array empty. This is probably because effs. have been calculated and the generated particle histograms have been cleared out!\n"); return; } for (int i = 0; i < fW_mcrec->GetEntries(); i++) { @@ -194,7 +196,7 @@ void GFWWeights::MCToEfficiency() } fW_mcgen->Clear(); }; -void GFWWeights::RebinNUA(int nX, int nY, int nZ) +void GFWWeights::rebinNUA(int nX, int nY, int nZ) { if (fW_data->GetEntries() < 1) return; @@ -204,10 +206,10 @@ void GFWWeights::RebinNUA(int nX, int nY, int nZ) reinterpret_cast(fW_data->At(i))->RebinZ(nZ); } }; -void GFWWeights::CreateNUA(bool IntegrateOverCentAndPt) +void GFWWeights::createNUA(bool IntegrateOverCentAndPt) { if (!IntegrateOverCentAndPt) { - printf("Method is outdated! NUA is integrated over centrality and pT. Quit now, or the behaviour will be bad\n"); + LOGF(info, "Method is outdated! NUA is integrated over centrality and pT. Quit now, or the behaviour will be bad\n"); return; } TH1D* h1; @@ -240,7 +242,7 @@ void GFWWeights::CreateNUA(bool IntegrateOverCentAndPt) return; } }; -TH1D* GFWWeights::GetdNdPhi() +TH1D* GFWWeights::getdNdPhi() { TH3D* temph = reinterpret_cast(fW_data->At(0)->Clone("tempH3")); TH1D* reth = reinterpret_cast(temph->Project3D("x")); @@ -257,10 +259,10 @@ TH1D* GFWWeights::GetdNdPhi() } return reth; } -void GFWWeights::CreateNUE(bool IntegrateOverCentrality) +void GFWWeights::createNUE(bool IntegrateOverCentrality) { if (!IntegrateOverCentrality) { - printf("Method is outdated! NUE is integrated over centrality. Quit now, or the behaviour will be bad\n"); + LOGF(info, "Method is outdated! NUE is integrated over centrality. Quit now, or the behaviour will be bad\n"); return; } TH3D* num = 0; @@ -281,7 +283,7 @@ void GFWWeights::CreateNUE(bool IntegrateOverCentrality) return; } }; -void GFWWeights::ReadAndMerge(TString filelinks, TString listName, bool addData, bool addRec, bool addGen) +void GFWWeights::readAndMerge(TString filelinks, TString listName, bool addData, bool addRec, bool addGen) { FILE* flist = fopen(filelinks.Data(), "r"); char str[150]; @@ -290,7 +292,7 @@ void GFWWeights::ReadAndMerge(TString filelinks, TString listName, bool addData, nFiles++; rewind(flist); if (nFiles == 0) { - printf("No files to read!\n"); + LOGF(info, "No files to read!\n"); return; } if (!fW_data && addData) { @@ -314,31 +316,31 @@ void GFWWeights::ReadAndMerge(TString filelinks, TString listName, bool addData, (void)retVal; tf = new TFile(str, "READ"); if (tf->IsZombie()) { - printf("Could not open file %s!\n", str); + LOGF(warning, "Could not open file %s!\n", str); tf->Close(); continue; } TList* tl = reinterpret_cast(tf->Get(listName.Data())); GFWWeights* tw = reinterpret_cast(tl->FindObject(this->GetName())); if (!tw) { - printf("Could not fetch weights object from %s\n", str); + LOGF(warning, "Could not fetch weights object from %s\n", str); tf->Close(); continue; } if (addData) - AddArray(fW_data, tw->GetDataArray()); + addArray(fW_data, tw->getDataArray()); if (addRec) - AddArray(fW_mcrec, tw->GetRecArray()); + addArray(fW_mcrec, tw->getRecArray()); if (addGen) - AddArray(fW_mcgen, tw->GetGenArray()); + addArray(fW_mcgen, tw->getGenArray()); tf->Close(); delete tw; } }; -void GFWWeights::AddArray(TObjArray* targ, TObjArray* sour) +void GFWWeights::addArray(TObjArray* targ, TObjArray* sour) { if (!sour) { - printf("Source array does not exist!\n"); + LOGF(info, "Source array does not exist!\n"); return; } for (int i = 0; i < sour->GetEntries(); i++) { @@ -353,10 +355,10 @@ void GFWWeights::AddArray(TObjArray* targ, TObjArray* sour) } } }; -void GFWWeights::OverwriteNUA() +void GFWWeights::overwriteNUA() { if (!fAccInt) - CreateNUA(); + createNUA(); TString ts(fW_data->At(0)->GetName()); TH3D* trash = reinterpret_cast(fW_data->RemoveAt(0)); delete trash; @@ -384,29 +386,29 @@ Long64_t GFWWeights::Merge(TCollection* collist) GFWWeights* l_w = 0; TIter all_w(collist); while ((l_w = (reinterpret_cast(all_w())))) { - AddArray(fW_data, l_w->GetDataArray()); - AddArray(fW_mcrec, l_w->GetRecArray()); - AddArray(fW_mcgen, l_w->GetGenArray()); + addArray(fW_data, l_w->getDataArray()); + addArray(fW_mcrec, l_w->getRecArray()); + addArray(fW_mcgen, l_w->getGenArray()); nmerged++; } return nmerged; }; -TH1D* GFWWeights::GetIntegratedEfficiencyHist() +TH1D* GFWWeights::getIntegratedEfficiencyHist() { if (!fW_mcgen) { - printf("MCGen array does not exist!\n"); + LOGF(warning, "MCGen array does not exist!\n"); return 0; } if (!fW_mcrec) { - printf("MCRec array does not exist!\n"); + LOGF(warning, "MCRec array does not exist!\n"); return 0; } if (!fW_mcgen->GetEntries()) { - printf("MCGen array is empty!\n"); + LOGF(warning, "MCGen array is empty!\n"); return 0; } if (!fW_mcrec->GetEntries()) { - printf("MCRec array is empty!\n"); + LOGF(warning, "MCRec array is empty!\n"); return 0; } TH3D* num = reinterpret_cast(fW_mcrec->At(0)->Clone("Numerator")); @@ -426,25 +428,25 @@ TH1D* GFWWeights::GetIntegratedEfficiencyHist() delete den1d; return num1d; } -bool GFWWeights::CalculateIntegratedEff() +bool GFWWeights::calculateIntegratedEff() { if (fIntEff) delete fIntEff; - fIntEff = GetIntegratedEfficiencyHist(); + fIntEff = getIntegratedEfficiencyHist(); if (!fIntEff) { return kFALSE; } fIntEff->SetName("IntegratedEfficiency"); return kTRUE; } -double GFWWeights::GetIntegratedEfficiency(double pt) +double GFWWeights::getIntegratedEfficiency(double pt) { if (!fIntEff) - if (!CalculateIntegratedEff()) + if (!calculateIntegratedEff()) return 0; return fIntEff->GetBinContent(fIntEff->FindBin(pt)); } -TH1D* GFWWeights::GetEfficiency(double etamin, double etamax, double vzmin, double vzmax) +TH1D* GFWWeights::getEfficiency(double etamin, double etamax, double vzmin, double vzmax) { TH3D* num = reinterpret_cast(fW_mcrec->At(0)->Clone("Numerator")); for (int i = 1; i < fW_mcrec->GetEntries(); i++) @@ -470,3 +472,27 @@ TH1D* GFWWeights::GetEfficiency(double etamin, double etamax, double vzmin, doub delete den1d; return num1d; } +void GFWWeights::mergeWeights(GFWWeights* other) +{ + if (!fW_data) { + fW_data = new TObjArray(); + fW_data->SetName("Weights_Data"); + fW_data->SetOwner(kTRUE); + } + addArray(fW_data, other->getDataArray()); + return; +} +void GFWWeights::setTH3D(TH3D* th3d) +{ + if (!fW_data) { + fW_data = new TObjArray(); + fW_data->SetName("GFWWeights_Data"); + fW_data->SetOwner(kTRUE); + fW_data->Add(th3d); + return; + } + TString ts(fW_data->At(0)->GetName()); + TH3D* trash = reinterpret_cast(fW_data->RemoveAt(0)); + delete trash; + fW_data->Add(reinterpret_cast(th3d->Clone(ts.Data()))); +} diff --git a/PWGCF/GenericFramework/Core/GFWWeights.h b/PWGCF/GenericFramework/Core/GFWWeights.h index e88904f14e8..f60783ccec8 100644 --- a/PWGCF/GenericFramework/Core/GFWWeights.h +++ b/PWGCF/GenericFramework/Core/GFWWeights.h @@ -9,8 +9,15 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file GFWWeights.h +/// \brief Class to store corrections for the Generic Framework +/// \author Emil Gorm Nielsen, NBI, emil.gorm.nielsen@cern.ch + #ifndef PWGCF_GENERICFRAMEWORK_CORE_GFWWEIGHTS_H_ #define PWGCF_GENERICFRAMEWORK_CORE_GFWWEIGHTS_H_ + +#include "Framework/Logger.h" + #include "TObjArray.h" #include "TNamed.h" #include "TH3D.h" @@ -26,32 +33,34 @@ class GFWWeights : public TNamed GFWWeights(); explicit GFWWeights(const char* name); ~GFWWeights(); - void Init(bool AddData = kTRUE, bool AddM = kTRUE); - void Fill(double phi, double eta, double vz, double pt, double cent, int htype, double weight = 1); // htype: 0 for data, 1 for mc rec, 2 for mc gen - double GetWeight(double phi, double eta, double vz, double pt, double cent, int htype); // htype: 0 for data, 1 for mc rec, 2 for mc gen - double GetNUA(double phi, double eta, double vz); // This just fetches correction from integrated NUA, should speed up - double GetNUE(double pt, double eta, double vz); // fetches weight from fEffInt - bool IsDataFilled() { return fDataFilled; } - bool IsMCFilled() { return fMCFilled; } - double FindMax(TH3D* inh, int& ix, int& iy, int& iz); - void MCToEfficiency(); - TObjArray* GetRecArray() { return fW_mcrec; } - TObjArray* GetGenArray() { return fW_mcgen; } - TObjArray* GetDataArray() { return fW_data; } - void CreateNUA(bool IntegrateOverCentAndPt = kTRUE); - void CreateNUE(bool IntegrateOverCentrality = kTRUE); - TH1D* GetIntegratedEfficiencyHist(); - bool CalculateIntegratedEff(); - double GetIntegratedEfficiency(double pt); - void SetDataFilled(bool newval) { fDataFilled = newval; } - void SetMCFilled(bool newval) { fMCFilled = newval; } - void ReadAndMerge(TString filelinks, TString listName = "OutputList", bool addData = kTRUE, bool addRec = kTRUE, bool addGen = kTRUE); - void SetPtBins(int Nbins, double* bins); + void init(bool AddData = kTRUE, bool AddM = kTRUE); + void fill(double phi, double eta, double vz, double pt, double cent, int htype, double weight = 1); // htype: 0 for data, 1 for mc rec, 2 for mc gen + double getWeight(double phi, double eta, double vz, double pt, double cent, int htype); // htype: 0 for data, 1 for mc rec, 2 for mc gen + double getNUA(double phi, double eta, double vz); // This just fetches correction from integrated NUA, should speed up + double getNUE(double pt, double eta, double vz); // fetches weight from fEffInt + bool isDataFilled() { return fDataFilled; } + bool isMCFilled() { return fMCFilled; } + double findMax(TH3D* inh, int& ix, int& iy, int& iz); + void mcToEfficiency(); + TObjArray* getRecArray() { return fW_mcrec; } + TObjArray* getGenArray() { return fW_mcgen; } + TObjArray* getDataArray() { return fW_data; } + void createNUA(bool IntegrateOverCentAndPt = kTRUE); + void createNUE(bool IntegrateOverCentrality = kTRUE); + TH1D* getIntegratedEfficiencyHist(); + bool calculateIntegratedEff(); + double getIntegratedEfficiency(double pt); + void setDataFilled(bool newval) { fDataFilled = newval; } + void setMCFilled(bool newval) { fMCFilled = newval; } + void readAndMerge(TString filelinks, TString listName = "OutputList", bool addData = kTRUE, bool addRec = kTRUE, bool addGen = kTRUE); + void setPtBins(int Nbins, double* bins); Long64_t Merge(TCollection* collist); - void RebinNUA(int nX = 1, int nY = 2, int nZ = 5); - void OverwriteNUA(); - TH1D* GetdNdPhi(); - TH1D* GetEfficiency(double etamin, double etamax, double vzmin, double vzmax); + void rebinNUA(int nX = 1, int nY = 2, int nZ = 5); + void overwriteNUA(); + TH1D* getdNdPhi(); + TH1D* getEfficiency(double etamin, double etamax, double vzmin, double vzmax); + void mergeWeights(GFWWeights* other); + void setTH3D(TH3D* th3d); private: bool fDataFilled; @@ -64,8 +73,8 @@ class GFWWeights : public TNamed TH3D* fAccInt; //! int fNbinsPt; //! do not store double* fbinsPt; //! do not store - void AddArray(TObjArray* targ, TObjArray* sour); - const char* GetBinName(double /*ptv*/, double /*v0mv*/, const char* pf = "") + void addArray(TObjArray* targ, TObjArray* sour); + const char* getBinName(double /*ptv*/, double /*v0mv*/, const char* pf = "") { int ptind = 0; // GetPtBin(ptv); int v0mind = 0; // GetV0MBin(v0mv); diff --git a/PWGCF/GenericFramework/Core/GFWWeightsList.cxx b/PWGCF/GenericFramework/Core/GFWWeightsList.cxx new file mode 100644 index 00000000000..11a6ffe3159 --- /dev/null +++ b/PWGCF/GenericFramework/Core/GFWWeightsList.cxx @@ -0,0 +1,201 @@ +// 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 GFWWeightsList.cxx +/// \author Zhiyong Lu (zhiyong.lu@cern.ch) +/// \since Dec/25/2024 +/// \brief one object to hold a list of GFWWeights objects, + +#include +#include "GFWWeightsList.h" + +GFWWeightsList::GFWWeightsList() : TNamed("", ""), list(0) +{ + runNumberMap.clear(); + runNumberPIDMap.clear(); +} + +GFWWeightsList::GFWWeightsList(const char* name) : TNamed(name, name), list(0) +{ + runNumberMap.clear(); + runNumberPIDMap.clear(); +} + +GFWWeightsList::~GFWWeightsList() +{ + delete list; + runNumberMap.clear(); + runNumberPIDMap.clear(); +} + +void GFWWeightsList::init(const char* listName) +{ + list = new TObjArray(); + list->SetName(listName); + list->SetOwner(kTRUE); +} + +void GFWWeightsList::addGFWWeightsByName(const char* weightName, int nPtBins, double* ptBins, bool addData, bool addMC) +{ + if (!list) { + init("weightList"); + } + if (reinterpret_cast(list->FindObject(weightName))) { + return; + } + GFWWeights* weight = new GFWWeights(weightName); + weight->setPtBins(nPtBins, ptBins); + weight->init(addData, addMC); + list->Add(weight); +} + +GFWWeights* GFWWeightsList::getGFWWeightsByName(const char* weightName) +{ + if (!list) { + LOGF(error, "weight list is not initialized\n"); + return nullptr; + } + return reinterpret_cast(list->FindObject(weightName)); +} + +void GFWWeightsList::addGFWWeightsByRun(int runNumber, int nPtBins, double* ptBins, bool addData, bool addMC) +{ + if (!list) { + init("weightList"); + } + if (runNumberMap.contains(runNumber)) { + return; + } + GFWWeights* weight = new GFWWeights(Form("weight_%d", runNumber)); + weight->setPtBins(nPtBins, ptBins); + weight->init(addData, addMC); + list->Add(weight); + runNumberMap.insert(std::make_pair(runNumber, weight)); +} + +GFWWeights* GFWWeightsList::getGFWWeightsByRun(int runNumber) +{ + if (!list) { + LOGF(error, "weight list is not initialized\n"); + return nullptr; + } + if (!runNumberMap.contains(runNumber)) { + LOGF(error, "weight for run %d is not found\n", runNumber); + return nullptr; + } + return runNumberMap.at(runNumber); +} + +void GFWWeightsList::addPIDGFWWeightsByName(const char* weightName, int nPtBins, double* ptBins, double ptrefup, bool addData, bool addMC) +{ + if (!list) { + init("weightList"); + } + + std::vector ptbins(ptBins, ptBins + nPtBins + 1); + auto it = std::find(ptbins.begin(), ptbins.end(), ptrefup); + std::vector refpt(ptbins.begin(), it + 1); + + for (auto& type : species) { + if (reinterpret_cast(list->FindObject((static_cast(weightName) + type).c_str()))) { + continue; + } + GFWWeights* weight = new GFWWeights(Form("%s", (static_cast(weightName) + type).c_str())); + if (!type.compare("_ref")) + weight->setPtBins(refpt.size() - 1, &(refpt[0])); + else + weight->setPtBins(nPtBins, ptBins); + weight->init(addData, addMC); + list->Add(weight); + } +} +GFWWeights* GFWWeightsList::getPIDGFWWeightsByName(const char* weightName, int pidIndex) +{ + if (static_cast(pidIndex) >= species.size()) + return nullptr; + if (!list) { + LOGF(error, "weight list is not initialized\n"); + return nullptr; + } + return reinterpret_cast(list->FindObject((static_cast(weightName) + species[pidIndex]).c_str())); +} +void GFWWeightsList::addPIDGFWWeightsByRun(int runNumber, int nPtBins, double* ptBins, double ptrefup, bool addData, bool addMC) +{ + if (!list) { + init("weightList"); + } + + if (runNumberPIDMap.contains(runNumber)) + return; + std::vector ptbins(ptBins, ptBins + nPtBins + 1); + auto it = std::find(ptbins.begin(), ptbins.end(), ptrefup); + std::vector refpt(ptbins.begin(), it + 1); + + std::vector weights; + for (auto& type : species) { + GFWWeights* weight = new GFWWeights(Form("weight_%d%s", runNumber, type.c_str())); + if (!type.compare("_ref")) + weight->setPtBins(refpt.size() - 1, &(refpt[0])); + else + weight->setPtBins(nPtBins, ptBins); + weight->init(addData, addMC); + list->Add(weight); + weights.push_back(weight); + } + LOGF(info, "Adding weights for run %d\n", runNumber); + runNumberPIDMap.insert(std::make_pair(runNumber, weights)); + return; +} + +GFWWeights* GFWWeightsList::getPIDGFWWeightsByRun(int runNumber, int pidIndex) +{ + if (!list) { + LOGF(error, "weight list is not initialized\n"); + return nullptr; + } + if (!runNumberPIDMap.contains(runNumber)) { + LOGF(error, "PID weights for run %d is not found\n", runNumber); + return nullptr; + } + return runNumberPIDMap.at(runNumber)[pidIndex]; +} +Long64_t GFWWeightsList::Merge(TCollection* collist) +{ + Long64_t nmerged = 0; + if (!list) { + list = new TObjArray(); + list->SetName("weightList"); + list->SetOwner(kTRUE); + } + TIter allWeights(collist); + GFWWeightsList* lWeight = 0; + while ((lWeight = (reinterpret_cast(allWeights())))) { + addArray(list, lWeight->getList()); + nmerged++; + } + return nmerged; +} +void GFWWeightsList::addArray(TObjArray* target, TObjArray* source) +{ + if (!source) { + return; + } + for (int i = 0; i < source->GetEntries(); i++) { + GFWWeights* sourw = reinterpret_cast(source->At(i)); + GFWWeights* targw = reinterpret_cast(target->FindObject(sourw->GetName())); + if (!targw) { + targw = reinterpret_cast(sourw->Clone(sourw->GetName())); + target->Add(targw); + } else { + targw->mergeWeights(sourw); + } + } +}; diff --git a/PWGCF/GenericFramework/Core/GFWWeightsList.h b/PWGCF/GenericFramework/Core/GFWWeightsList.h new file mode 100644 index 00000000000..c0f208a7088 --- /dev/null +++ b/PWGCF/GenericFramework/Core/GFWWeightsList.h @@ -0,0 +1,63 @@ +// 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 GFWWeightsList.h +/// \author Zhiyong Lu (zhiyong.lu@cern.ch) +/// \since Dec/25/2024 +/// \brief one object to hold a list of GFWWeights objects, + +#ifndef PWGCF_GENERICFRAMEWORK_CORE_GFWWEIGHTSLIST_H_ +#define PWGCF_GENERICFRAMEWORK_CORE_GFWWEIGHTSLIST_H_ +#include +#include +#include +#include + +#include "Framework/Logger.h" + +#include "TObjArray.h" +#include "GFWWeights.h" + +class GFWWeightsList : public TNamed +{ + public: + GFWWeightsList(); + explicit GFWWeightsList(const char* name); + ~GFWWeightsList(); + void init(const char* listName); + void addGFWWeightsByName(const char* weightName, int nPtBins, double* ptBins, bool addData = kTRUE, bool addMC = kTRUE); + GFWWeights* getGFWWeightsByName(const char* weightName); + void addGFWWeightsByRun(int runNumber, int nPtBins, double* ptBins, bool addData = kTRUE, bool addMC = kTRUE); + GFWWeights* getGFWWeightsByRun(int runNumber); + void addPIDGFWWeightsByName(const char* weightName, int nPtBins, double* ptBins, double ptrefup, bool addData = kTRUE, bool addMC = kTRUE); + GFWWeights* getPIDGFWWeightsByName(const char* weightName, int pidIndex); + void addPIDGFWWeightsByRun(int runNumber, int nPtBins, double* ptBins, double ptrefup, bool addData = kTRUE, bool addMC = kTRUE); + GFWWeights* getPIDGFWWeightsByRun(int runNumber, int pidIndex); + void printRuns() + { + for (auto& el : runNumberPIDMap) + printf("%i\n", el.first); + } + + TObjArray* getList() const { return list; } + Long64_t Merge(TCollection* collist); + + private: + TObjArray* list; + std::vector species = {"_ref", "_ch", "_pi", "_ka", "_pr"}; //! + std::map runNumberMap; + std::map> runNumberPIDMap; + void addArray(TObjArray* target, TObjArray* source); + + ClassDef(GFWWeightsList, 1); +}; + +#endif // PWGCF_GENERICFRAMEWORK_CORE_GFWWEIGHTSLIST_H_ diff --git a/PWGCF/GenericFramework/Core/GenericFrameworkLinkDef.h b/PWGCF/GenericFramework/Core/GenericFrameworkLinkDef.h index 2279a79b473..3fea9523064 100755 --- a/PWGCF/GenericFramework/Core/GenericFrameworkLinkDef.h +++ b/PWGCF/GenericFramework/Core/GenericFrameworkLinkDef.h @@ -22,6 +22,7 @@ #pragma link C++ class ProfileSubset + ; #pragma link C++ class FlowContainer + ; #pragma link C++ class GFWWeights + ; +#pragma link C++ class GFWWeightsList + ; #pragma link C++ class BootstrapProfile + ; #pragma link C++ class FlowPtContainer + ; #pragma link C++ class o2::analysis::genericframework::GFWBinningCuts + ; diff --git a/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx b/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx index d18d08309bf..03f4a82a3fd 100644 --- a/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx +++ b/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx @@ -9,12 +9,20 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file flowGenericFramework.cxx +/// \brief Task to analyse angular and transverse momentum correlations with GFW +/// \author Emil Gorm Nielsen, NBI, emil.gorm.nielsen@cern.ch + #include #include #include #include #include #include +#include +#include +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -27,6 +35,7 @@ #include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" #include "GFWPowerArray.h" #include "GFW.h" @@ -35,24 +44,23 @@ #include "FlowPtContainer.h" #include "GFWConfig.h" #include "GFWWeights.h" +#include "GFWWeightsList.h" #include #include #include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::analysis; +using namespace o2::constants::math; #define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; namespace o2::analysis::genericframework { -std::vector ptbinning = { - 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, - 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, - 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, - 2, 2.2, 2.4, 2.6, 2.8, 3, 3.5, 4, 5, 6, 8, 10}; +std::vector ptbinning = {0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.2, 2.4, 2.6, 2.8, 3, 3.5, 4, 5, 6, 8, 10}; float ptpoilow = 0.2, ptpoiup = 10.0; float ptreflow = 0.2, ptrefup = 3.0; float ptlow = 0.2, ptup = 10.0; @@ -62,7 +70,7 @@ int vtxZbins = 40; float vtxZlow = -10.0, vtxZup = 10.0; int phibins = 72; float philow = 0.0; -float phiup = constants::math::TwoPI; +float phiup = TwoPI; int nchbins = 300; float nchlow = 0; float nchup = 3000; @@ -74,15 +82,18 @@ GFWCorrConfigs configs; using namespace o2::analysis::genericframework; -struct GenericFramework { +struct FlowGenericFramework { O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 10, "Number of subsamples") O2_DEFINE_CONFIGURABLE(cfgMpar, int, 8, "Highest order of pt-pt correlations") O2_DEFINE_CONFIGURABLE(cfgUseNch, bool, false, "Do correlations as function of Nch") O2_DEFINE_CONFIGURABLE(cfgFillWeights, bool, false, "Fill NUA weights") + O2_DEFINE_CONFIGURABLE(cfgRunByRun, bool, false, "Fill histograms on a run-by-run basis") O2_DEFINE_CONFIGURABLE(cfgFillQA, bool, false, "Fill QA histograms") O2_DEFINE_CONFIGURABLE(cfgUseAdditionalEventCut, bool, false, "Use additional event cut on mult correlations") - O2_DEFINE_CONFIGURABLE(cfgUseAdditionalTrackCut, bool, false, "Use additional track cut on phi") + O2_DEFINE_CONFIGURABLE(cfgUseCentralMoments, bool, true, "Use central moments in vn-pt calculations") + O2_DEFINE_CONFIGURABLE(cfgUsePID, bool, true, "Enable PID information") + O2_DEFINE_CONFIGURABLE(cfgUseGapMethod, bool, false, "Use gap method in vn-pt calculations") O2_DEFINE_CONFIGURABLE(cfgEfficiency, std::string, "", "CCDB path to efficiency object") O2_DEFINE_CONFIGURABLE(cfgAcceptance, std::string, "", "CCDB path to acceptance object") O2_DEFINE_CONFIGURABLE(cfgDCAxy, float, 0.2, "Cut on DCA in the transverse direction (cm)"); @@ -91,8 +102,19 @@ struct GenericFramework { O2_DEFINE_CONFIGURABLE(cfgPtmin, float, 0.2, "minimum pt (GeV/c)"); O2_DEFINE_CONFIGURABLE(cfgPtmax, float, 10, "maximum pt (GeV/c)"); O2_DEFINE_CONFIGURABLE(cfgEta, float, 0.8, "eta cut"); + O2_DEFINE_CONFIGURABLE(cfgEtaPtPt, float, 0.4, "eta cut for pt-pt correlations"); O2_DEFINE_CONFIGURABLE(cfgVtxZ, float, 10, "vertex cut (cm)"); + O2_DEFINE_CONFIGURABLE(cfgOccupancySelection, int, -999, "Max occupancy selection, -999 to disable"); + O2_DEFINE_CONFIGURABLE(cfgNoSameBunchPileupCut, bool, true, "kNoSameBunchPileupCut"); + O2_DEFINE_CONFIGURABLE(cfgIsGoodZvtxFT0vsPV, bool, true, "kIsGoodZvtxFT0vsPV"); + O2_DEFINE_CONFIGURABLE(cfgIsGoodITSLayersAll, bool, true, "kIsGoodITSLayersAll"); + O2_DEFINE_CONFIGURABLE(cfgNoCollInTimeRangeStandard, bool, true, "kNoCollInTimeRangeStandard"); + O2_DEFINE_CONFIGURABLE(cfgDoOccupancySel, bool, true, "Bool for event selection on detector occupancy"); + O2_DEFINE_CONFIGURABLE(cfgMultCut, bool, true, "Use additional event cut on mult correlations"); + O2_DEFINE_CONFIGURABLE(cfgTVXinTRD, bool, true, "Use kTVXinTRD (reject TRD triggered events)"); + O2_DEFINE_CONFIGURABLE(cfgIsVertexITSTPC, bool, true, "Selects collisions with at least one ITS-TPC track"); O2_DEFINE_CONFIGURABLE(cfgMagField, float, 99999, "Configurable magnetic field; default CCDB will be queried"); + O2_DEFINE_CONFIGURABLE(cfgTofPtCut, float, 0.5, "pt cut on TOF for PID"); Configurable cfgGFWBinning{"cfgGFWBinning", {40, 16, 72, 300, 0, 3000, 0.2, 10.0, 0.2, 3.0, {0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.2, 2.4, 2.6, 2.8, 3, 3.5, 4, 5, 6, 8, 10}, {0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}}, "Configuration for binning"}; Configurable cfgRegions{"cfgRegions", {{"refN", "refP", "refFull"}, {-0.8, 0.4, -0.8}, {-0.4, 0.8, 0.8}, {0, 0, 0}, {1, 1, 1}}, "Configurations for GFW regions"}; @@ -105,23 +127,43 @@ struct GenericFramework { struct Config { TH1D* mEfficiency = nullptr; - GFWWeights* mAcceptance = nullptr; + std::vector mAcceptance; bool correctionsLoaded = false; } cfg; // Define output OutputObj fFC{FlowContainer("FlowContainer")}; OutputObj fFCpt{FlowPtContainer("FlowPtContainer")}; - OutputObj fFC_gen{FlowContainer("FlowContainer_gen")}; - OutputObj fWeights{GFWWeights("weights")}; + OutputObj fFCgen{FlowContainer("FlowContainer_gen")}; HistogramRegistry registry{"registry"}; + std::map>> th1sList; + std::map>> th3sList; + enum OutputTH1Names { + hPhi = 0, + hEta, + hVtxZ, + hMult, + hCent, + hEventSel, + kCount_TH1Names + }; + enum OutputTH3Names { + hNUAref = 0, + hNUAch, + hNUApi, + hNUAka, + hNUApr, + kCount_TH3Names + }; + // define global variables GFW* fGFW = new GFW(); std::vector corrconfigs; TRandom3* fRndm = new TRandom3(0); TAxis* fPtAxis; - + int lastRun = -1; + std::vector runNumbers; // Event selection cuts - Alex TF1* fPhiCutLow = nullptr; TF1* fPhiCutHigh = nullptr; @@ -156,7 +198,7 @@ struct GenericFramework { vtxZbins = cfgGFWBinning->GetVtxZbins(); phibins = cfgGFWBinning->GetPhiBins(); philow = 0.0f; - phiup = constants::math::TwoPI; + phiup = TwoPI; nchbins = cfgGFWBinning->GetNchBins(); nchlow = cfgGFWBinning->GetNchMin(); nchup = cfgGFWBinning->GetNchMax(); @@ -164,7 +206,6 @@ struct GenericFramework { cfgGFWBinning->Print(); AxisSpec phiAxis = {phibins, philow, phiup, "#phi"}; - AxisSpec phiModAxis = {100, 0, constants::math::PI / 9, "fmod(#varphi,#pi/9)"}; AxisSpec etaAxis = {etabins, -cfgEta, cfgEta, "#eta"}; AxisSpec vtxAxis = {vtxZbins, -cfgVtxZ, cfgVtxZ, "Vtx_{z} (cm)"}; AxisSpec ptAxis = {ptbinning, "#it{p}_{T} GeV/#it{c}"}; @@ -191,28 +232,50 @@ struct GenericFramework { int ptbins = ptbinning.size() - 1; fPtAxis = new TAxis(ptbins, &ptbinning[0]); - if (cfgFillWeights) { - fWeights->SetPtBins(ptbins, &ptbinning[0]); - fWeights->Init(true, false); - } - if (doprocessMCGen) { - registry.add("pt_gen", "", {HistType::kTH1D, {ptAxis}}); - registry.add("phi_eta_vtxZ_gen", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + registry.add("MCGen/before/pt_gen", "", {HistType::kTH1D, {ptAxis}}); + registry.add("MCGen/before/phi_eta_vtxZ_gen", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + registry.addClone("MCGen/before/", "MCGen/after/"); } if (doprocessMCReco || doprocessData || doprocessRun2) { - registry.add("phi_eta_vtxZ", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); - registry.add("pt_dcaXY_dcaZ", "", {HistType::kTH3D, {ptAxis, dcaXYAXis, dcaZAXis}}); - registry.add("pt_phi_bef", "", {HistType::kTH2D, {ptAxis, phiModAxis}}); - registry.add("pt_phi_aft", "", {HistType::kTH2D, {ptAxis, phiModAxis}}); - registry.add("phi_eta_vtxZ_corrected", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); - registry.add("globalTracks_centT0C", "", {HistType::kTH2D, {centAxis, nchAxis}}); - registry.add("PVTracks_centT0C", "", {HistType::kTH2D, {centAxis, multpvAxis}}); - registry.add("globalTracks_PVTracks", "", {HistType::kTH2D, {multpvAxis, nchAxis}}); - registry.add("globalTracks_multT0A", "", {HistType::kTH2D, {t0aAxis, nchAxis}}); - registry.add("globalTracks_multV0A", "", {HistType::kTH2D, {t0aAxis, nchAxis}}); - registry.add("multV0A_multT0A", "", {HistType::kTH2D, {t0aAxis, t0aAxis}}); - registry.add("multT0C_centT0C", "", {HistType::kTH2D, {centAxis, t0cAxis}}); + registry.add("trackQA/before/phi_eta_vtxZ", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + registry.add("trackQA/before/pt_dcaXY_dcaZ", "", {HistType::kTH3D, {ptAxis, dcaXYAXis, dcaZAXis}}); + registry.addClone("trackQA/before/", "trackQA/after/"); + registry.add("trackQA/after/pt_ref", "", {HistType::kTH1D, {{100, ptreflow, ptrefup}}}); + registry.add("trackQA/after/pt_poi", "", {HistType::kTH1D, {{100, ptpoilow, ptpoiup}}}); + + registry.add("eventQA/before/globalTracks_centT0C", "", {HistType::kTH2D, {centAxis, nchAxis}}); + registry.add("eventQA/before/PVTracks_centT0C", "", {HistType::kTH2D, {centAxis, multpvAxis}}); + registry.add("eventQA/before/globalTracks_PVTracks", "", {HistType::kTH2D, {multpvAxis, nchAxis}}); + registry.add("eventQA/before/globalTracks_multT0A", "", {HistType::kTH2D, {t0aAxis, nchAxis}}); + registry.add("eventQA/before/globalTracks_multV0A", "", {HistType::kTH2D, {t0aAxis, nchAxis}}); + registry.add("eventQA/before/multV0A_multT0A", "", {HistType::kTH2D, {t0aAxis, t0aAxis}}); + registry.add("eventQA/before/multT0C_centT0C", "", {HistType::kTH2D, {centAxis, t0cAxis}}); + registry.addClone("eventQA/before/", "eventQA/after/"); + registry.add("eventQA/eventSel", "Number of Events;; Counts", {HistType::kTH1D, {{11, 0, 11}}}); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(1, "Filtered event"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(2, "sel8"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(3, "occupancy"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(4, "kTVXinTRD"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(5, "kNoSameBunchPileup"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(6, "kIsGoodZvtxFT0vsPV"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(7, "kNoCollInTimeRangeStandard"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(8, "kIsVertexITSTPC"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(9, "kIsGoodITSLayersAll"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(10, "after Mult cuts"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(11, "has track + within cent"); + + if (!cfgRunByRun) { + if (cfgUsePID) { + registry.add("phi_eta_vtxz_ref", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + registry.add("phi_eta_vtxz_ch", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + registry.add("phi_eta_vtxz_pi", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + registry.add("phi_eta_vtxz_ka", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + registry.add("phi_eta_vtxz_pr", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + } else { + registry.add("phi_eta_vtxz_ref", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + } + } } if (regions.GetSize() < 0) @@ -227,35 +290,23 @@ struct GenericFramework { LOGF(error, "Configuration contains vectors of different size - check the GFWCorrConfig configurable"); fGFW->CreateRegions(); TObjArray* oba = new TObjArray(); - AddConfigObjectsToObjArray(oba, corrconfigs); + addConfigObjectsToObjArray(oba, corrconfigs); if (doprocessData || doprocessRun2 || doprocessMCReco) { fFC->SetName("FlowContainer"); fFC->SetXAxis(fPtAxis); fFC->Initialize(oba, multAxis, cfgNbootstrap); } if (doprocessMCGen) { - fFC_gen->SetName("FlowContainer_gen"); - fFC_gen->SetXAxis(fPtAxis); - fFC_gen->Initialize(oba, multAxis, cfgNbootstrap); + fFCgen->SetName("FlowContainer_gen"); + fFCgen->SetXAxis(fPtAxis); + fFCgen->Initialize(oba, multAxis, cfgNbootstrap); } delete oba; - fFCpt->Initialise(multAxis, cfgMpar, configs, cfgNbootstrap); + fFCpt->setUseCentralMoments(cfgUseCentralMoments); + fFCpt->setUseGapMethod(cfgUseGapMethod); + fFCpt->initialise(multAxis, cfgMpar, configs, cfgNbootstrap); // Event selection - Alex if (cfgUseAdditionalEventCut) { - /* - //22s cuts - fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); - fMultPVCutLow->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05); - fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); - fMultPVCutHigh->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05); - - fMultCutLow = new TF1("fMultCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.5*([4]+[5]*x)", 0, 100); - fMultCutLow->SetParameters(1893.94, -53.86, 0.502913, -0.0015122, 109.625, -1.19253); - fMultCutHigh = new TF1("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 3.*([4]+[5]*x)", 0, 100); - fMultCutHigh->SetParameters(1893.94, -53.86, 0.502913, -0.0015122, 109.625, -1.19253); - fMultMultPVCut = new TF1("fMultMultPVCut", "[0]+[1]*x+[2]*x*x", 0, 5000); - fMultMultPVCut->SetParameters(-0.1, 0.785, -4.7e-05); - */ fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x - 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); fMultPVCutLow->SetParameters(3257.29, -121.848, 1.98492, -0.0172128, 6.47528e-05, 154.756, -1.86072, -0.0274713, 0.000633499, -3.37757e-06); fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x + 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); @@ -266,14 +317,16 @@ struct GenericFramework { fMultCutHigh = new TF1("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 3.*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); fMultCutHigh->SetParameters(1654.46, -47.2379, 0.449833, -0.0014125, 150.773, -3.67334, 0.0530503, -0.000614061, 3.15956e-06); } - - if (cfgUseAdditionalTrackCut) { - fPhiCutLow = new TF1("fPhiCutLow", "0.06/x+pi/18.0-0.06", 0, 100); - fPhiCutHigh = new TF1("fPhiCutHigh", "0.1/x+pi/18.0+0.06", 0, 100); - } } - void AddConfigObjectsToObjArray(TObjArray* oba, const std::vector& configs) + static constexpr std::string_view FillTimeName[] = {"before/", "after/"}; + + enum QAFillTime { + kBefore, + kAfter + }; + + void addConfigObjectsToObjArray(TObjArray* oba, const std::vector& configs) { for (auto it = configs.begin(); it != configs.end(); ++it) { if (it->pTDif) { @@ -305,55 +358,145 @@ struct GenericFramework { return grpo->getNominalL3Field(); } - void loadCorrections(uint64_t timestamp) + void loadCorrections(aod::BCsWithTimestamps::iterator const& bc) { - if (cfg.correctionsLoaded) + uint64_t timestamp = bc.timestamp(); + if (!cfgRunByRun && cfg.correctionsLoaded) return; - if (cfgAcceptance.value.empty() == false) { - cfg.mAcceptance = ccdb->getForTimeStamp(cfgAcceptance, timestamp); - if (cfg.mAcceptance) - LOGF(info, "Loaded acceptance weights from %s (%p)", cfgAcceptance.value.c_str(), (void*)cfg.mAcceptance); - else - LOGF(warning, "Could not load acceptance weights from %s (%p)", cfgAcceptance.value.c_str(), (void*)cfg.mAcceptance); + if (!cfgAcceptance.value.empty()) { + std::string runstr = (cfgRunByRun) ? "RunByRun/" : ""; + cfg.mAcceptance.clear(); + if (cfgUsePID) { + cfg.mAcceptance.push_back(ccdb->getForTimeStamp(cfgAcceptance.value + runstr + "ref/", timestamp)); + cfg.mAcceptance.push_back(ccdb->getForTimeStamp(cfgAcceptance.value + runstr + "ch/", timestamp)); + cfg.mAcceptance.push_back(ccdb->getForTimeStamp(cfgAcceptance.value + runstr + "pi/", timestamp)); + cfg.mAcceptance.push_back(ccdb->getForTimeStamp(cfgAcceptance.value + runstr + "ka/", timestamp)); + cfg.mAcceptance.push_back(ccdb->getForTimeStamp(cfgAcceptance.value + runstr + "pr/", timestamp)); + } else { + cfg.mAcceptance.push_back(ccdb->getForTimeStamp(cfgAcceptance.value + runstr, timestamp)); + } } - if (cfgEfficiency.value.empty() == false) { + if (!cfgEfficiency.value.empty()) { cfg.mEfficiency = ccdb->getForTimeStamp(cfgEfficiency, timestamp); if (cfg.mEfficiency == nullptr) { - LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgEfficiency.value.c_str()); + LOGF(fatal, "Could not load efficiency histogram from %s", cfgEfficiency.value.c_str()); } LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgEfficiency.value.c_str(), (void*)cfg.mEfficiency); } cfg.correctionsLoaded = true; } - bool setCurrentParticleWeights(float& weight_nue, float& weight_nua, const float& phi, const float& eta, const float& pt, const float& vtxz) - { - float eff = 1.; + template + double getAcceptance(TTrack track, const double& vtxz, int index) + { // 0 ref, 1 ch, 2 pi, 3 ka, 4 pr + double wacc = 1; + if (!cfg.mAcceptance.empty()) + wacc = cfg.mAcceptance[index]->getNUA(track.phi(), track.eta(), vtxz); + return wacc; + } + + template + double getEfficiency(TTrack track) + { //-1 ref, 0 ch, 1 pi, 2 ka, 3 pr + double eff = 1.; if (cfg.mEfficiency) - eff = cfg.mEfficiency->GetBinContent(cfg.mEfficiency->FindBin(pt)); - else - eff = 1.0; + eff = cfg.mEfficiency->GetBinContent(cfg.mEfficiency->FindBin(track.pt())); if (eff == 0) - return false; - weight_nue = 1. / eff; - if (cfg.mAcceptance) - weight_nua = cfg.mAcceptance->GetNUA(phi, eta, vtxz); + return -1.; else - weight_nua = 1; - return true; + return 1. / eff; + } + + template + int getNsigmaPID(TTrack track) + { + // Computing Nsigma arrays for pion, kaon, and protons + std::array nSigmaTPC = {track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + std::array nSigmaCombined = {std::hypot(track.tpcNSigmaPi(), track.tofNSigmaPi()), std::hypot(track.tpcNSigmaKa(), track.tofNSigmaKa()), std::hypot(track.tpcNSigmaPr(), track.tofNSigmaPr())}; + int pid = -1; + float nsigma = 3.0; + + // Choose which nSigma to use + std::array nSigmaToUse = (track.pt() > cfgTofPtCut && track.hasTOF()) ? nSigmaCombined : nSigmaTPC; + if (track.pt() >= cfgTofPtCut && !track.hasTOF()) + return -1; + + // Select particle with the lowest nsigma + for (int i = 0; i < 3; ++i) { + if (std::abs(nSigmaToUse[i]) < nsigma) { + pid = i; + nsigma = std::abs(nSigmaToUse[i]); + } + } + return pid + 1; // shift the pid by 1, 1 = pion, 2 = kaon, 3 = proton } template - bool eventSelected(TCollision collision, const int& multTrk, const float& centrality) + bool eventSelected(TCollision collision, const int& multTrk, const float& centrality, const int& run) { - if (collision.alias_bit(kTVXinTRD)) { - // TRD triggered - return 0; + if (cfgTVXinTRD) { + if (collision.alias_bit(kTVXinTRD)) { + // TRD triggered + // "CMTVX-B-NOPF-TRD,minbias_TVX" + return 0; + } + registry.fill(HIST("eventQA/eventSel"), 3.5); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(3.5); + } + + if (cfgNoSameBunchPileupCut) { + if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + // rejects collisions which are associated with the same "found-by-T0" bunch crossing + // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof + return 0; + } + registry.fill(HIST("eventQA/eventSel"), 4.5); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(4.5); + } + if (cfgIsGoodZvtxFT0vsPV) { + if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference + // use this cut at low multiplicities with caution + return 0; + } + registry.fill(HIST("eventQA/eventSel"), 5.5); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(5.5); + } + if (cfgNoCollInTimeRangeStandard) { + if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // Rejection of the collisions which have other events nearby + return 0; + } + registry.fill(HIST("eventQA/eventSel"), 6.5); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(6.5); + } + + if (cfgIsVertexITSTPC) { + if (!collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + // selects collisions with at least one ITS-TPC track, and thus rejects vertices built from ITS-only tracks + return 0; + } + registry.fill(HIST("eventQA/eventSel"), 7.5); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(7.5); + } + + if (cfgIsGoodITSLayersAll) { + if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return 0; + } + registry.fill(HIST("eventQA/eventSel"), 8.5); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(8.5); } float vtxz = -999; if (collision.numContrib() > 1) { vtxz = collision.posZ(); - float zRes = TMath::Sqrt(collision.covZZ()); + float zRes = std::sqrt(collision.covZZ()); if (zRes > 0.25 && collision.numContrib() < 20) vtxz = -999; } @@ -364,232 +507,428 @@ struct GenericFramework { if (vtxz > vtxZup || vtxz < vtxZlow) return 0; - if (multNTracksPV < fMultPVCutLow->Eval(centrality)) - return 0; - if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) - return 0; - if (multTrk < fMultCutLow->Eval(centrality)) - return 0; - if (multTrk > fMultCutHigh->Eval(centrality)) - return 0; - /* 22s - if (multNTracksPV < fMultPVCutLow->Eval(centrality)) - return 0; - if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) - return 0; - if (multTrk < fMultCutLow->Eval(centrality)) - return 0; - if (multTrk > fMultCutHigh->Eval(centrality)) - return 0; - if (multTrk > fMultMultPVCut->Eval(multNTracksPV)) - return 0; - */ + if (cfgMultCut) { + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) + return 0; + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) + return 0; + if (multTrk < fMultCutLow->Eval(centrality)) + return 0; + if (multTrk > fMultCutHigh->Eval(centrality)) + return 0; + registry.fill(HIST("eventQA/eventSel"), 9.5); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(9.5); + } return 1; } + enum DataType { + kReco, + kGen + }; + template - bool trackSelected(TTrack track, const int& field) + void fillWeights(const TTrack track, const double vtxz, const int& pid_index, const int& run) { - double phimodn = track.phi(); - if (field < 0) // for negative polarity field - phimodn = TMath::TwoPi() - phimodn; - if (track.sign() < 0) // for negative charge - phimodn = TMath::TwoPi() - phimodn; - if (phimodn < 0) - LOGF(warning, "phi < 0: %g", phimodn); - - phimodn += TMath::Pi() / 18.0; // to center gap in the middle - phimodn = fmod(phimodn, TMath::Pi() / 9.0); - registry.fill(HIST("pt_phi_bef"), track.pt(), phimodn); - if (phimodn < fPhiCutHigh->Eval(track.pt()) && phimodn > fPhiCutLow->Eval(track.pt())) - return false; // reject track - registry.fill(HIST("pt_phi_aft"), track.pt(), phimodn); - return true; + if (cfgUsePID) { + double ptpidmins[] = {ptpoilow, ptpoilow, 0.3, 0.5}; // min pt for ch, pi, ka, pr + double ptpidmaxs[] = {ptpoiup, ptpoiup, 6.0, 6.0}; // max pt for ch, pi, ka, pr + bool withinPtPOI = (ptpidmins[pid_index] < track.pt()) && (track.pt() < ptpidmaxs[pid_index]); // within POI pT range + bool withinPtRef = (ptreflow < track.pt()) && (track.pt() < ptrefup); // within RF pT range + if (cfgRunByRun) { + if (withinPtRef && !pid_index) + th3sList[run][hNUAref]->Fill(track.phi(), track.eta(), vtxz); // pt-subset of charged particles for ref flow + if (withinPtPOI) + th3sList[run][hNUAch + pid_index]->Fill(track.phi(), track.eta(), vtxz); // charged and id'ed particle weights + } else { + if (withinPtRef && !pid_index) + registry.fill(HIST("phi_eta_vtxz_ref"), track.phi(), track.eta(), vtxz); // pt-subset of charged particles for ref flow + if (withinPtPOI) { + switch (pid_index) { + case 0: + registry.fill(HIST("phi_eta_vtxz_ch"), track.phi(), track.eta(), vtxz); // charged particle weights + break; + case 1: + registry.fill(HIST("phi_eta_vtxz_pi"), track.phi(), track.eta(), vtxz); // pion weights + break; + case 2: + registry.fill(HIST("phi_eta_vtxz_ka"), track.phi(), track.eta(), vtxz); // kaon weights + break; + case 3: + registry.fill(HIST("phi_eta_vtxz_pr"), track.phi(), track.eta(), vtxz); // proton weights + break; + } + } + } + } else { + if (cfgRunByRun) + th3sList[run][hNUAref]->Fill(track.phi(), track.eta(), vtxz); + else + registry.fill(HIST("phi_eta_vtxz_ref"), track.phi(), track.eta(), vtxz); + } + return; } - enum datatype { - kReco, - kGen - }; + void createRunByRunHistograms(const int& run) + { + AxisSpec phiAxis = {phibins, philow, phiup, "#phi"}; + AxisSpec etaAxis = {etabins, -cfgEta, cfgEta, "#eta"}; + AxisSpec vtxAxis = {vtxZbins, -cfgVtxZ, cfgVtxZ, "Vtx_{z} (cm)"}; + std::vector> histos(kCount_TH1Names); + histos[hPhi] = registry.add(Form("%d/phi", run), "", {HistType::kTH1D, {phiAxis}}); + histos[hEta] = registry.add(Form("%d/eta", run), "", {HistType::kTH1D, {etaAxis}}); + histos[hVtxZ] = registry.add(Form("%d/vtxz", run), "", {HistType::kTH1D, {vtxAxis}}); + histos[hMult] = registry.add(Form("%d/mult", run), "", {HistType::kTH1D, {{3000, 0.5, 3000.5}}}); + histos[hCent] = registry.add(Form("%d/cent", run), "", {HistType::kTH1D, {{90, 0, 90}}}); + histos[hEventSel] = registry.add(Form("%d/eventSel", run), "Number of Events;; Counts", {HistType::kTH1D, {{11, 0, 11}}}); + histos[hEventSel]->GetXaxis()->SetBinLabel(1, "Filtered event"); + histos[hEventSel]->GetXaxis()->SetBinLabel(2, "sel8"); + histos[hEventSel]->GetXaxis()->SetBinLabel(3, "occupancy"); + histos[hEventSel]->GetXaxis()->SetBinLabel(4, "kTVXinTRD"); + histos[hEventSel]->GetXaxis()->SetBinLabel(5, "kNoSameBunchPileup"); + histos[hEventSel]->GetXaxis()->SetBinLabel(6, "kIsGoodZvtxFT0vsPV"); + histos[hEventSel]->GetXaxis()->SetBinLabel(7, "kNoCollInTimeRangeStandard"); + histos[hEventSel]->GetXaxis()->SetBinLabel(8, "kIsVertexITSTPC"); + histos[hEventSel]->GetXaxis()->SetBinLabel(9, "kIsGoodITSLayersAll"); + histos[hEventSel]->GetXaxis()->SetBinLabel(10, "after Mult cuts"); + histos[hEventSel]->GetXaxis()->SetBinLabel(11, "has track + within cent"); + th1sList.insert(std::make_pair(run, histos)); + std::vector> histos3d(kCount_TH3Names); + if (cfgUsePID) { + histos3d[hNUAref] = registry.add(Form("%d/phi_eta_vtxz_ref", run), "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + histos3d[hNUAch] = registry.add(Form("%d/phi_eta_vtxz_ch", run), "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + histos3d[hNUApi] = registry.add(Form("%d/phi_eta_vtxz_pi", run), "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + histos3d[hNUAka] = registry.add(Form("%d/phi_eta_vtxz_ka", run), "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + histos3d[hNUApr] = registry.add(Form("%d/phi_eta_vtxz_pr", run), "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + } else { + histos3d[hNUAref] = registry.add(Form("%d/phi_eta_vtxz_ref", run), "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + } + th3sList.insert(std::make_pair(run, histos3d)); + return; + } - template - void FillOutputContainers(const float& centmult, const double& rndm) + template + void fillOutputContainers(const float& centmult, const double& rndm) { - fFCpt->CalculateCorrelations(); - fFCpt->FillPtProfiles(centmult, rndm); - fFCpt->FillCMProfiles(centmult, rndm); + fFCpt->calculateCorrelations(); + fFCpt->fillPtProfiles(centmult, rndm); + fFCpt->fillCMProfiles(centmult, rndm); + if (!cfgUseGapMethod) + fFCpt->fillVnPtStdProfiles(centmult, rndm); for (uint l_ind = 0; l_ind < corrconfigs.size(); ++l_ind) { - auto dnx = fGFW->Calculate(corrconfigs.at(l_ind), 0, kTRUE).real(); - if (dnx == 0) - continue; if (!corrconfigs.at(l_ind).pTDif) { + auto dnx = fGFW->Calculate(corrconfigs.at(l_ind), 0, kTRUE).real(); + if (dnx == 0) + continue; auto val = fGFW->Calculate(corrconfigs.at(l_ind), 0, kFALSE).real() / dnx; - if (TMath::Abs(val) < 1) { - (dt == kGen) ? fFC_gen->FillProfile(corrconfigs.at(l_ind).Head.c_str(), centmult, val, dnx, rndm) : fFC->FillProfile(corrconfigs.at(l_ind).Head.c_str(), centmult, val, dnx, rndm); - fFCpt->FillVnPtProfiles(centmult, val, dnx, rndm, configs.GetpTCorrMasks()[l_ind]); + if (std::abs(val) < 1) { + (dt == kGen) ? fFCgen->FillProfile(corrconfigs.at(l_ind).Head.c_str(), centmult, val, dnx, rndm) : fFC->FillProfile(corrconfigs.at(l_ind).Head.c_str(), centmult, val, dnx, rndm); + if (cfgUseGapMethod) + fFCpt->fillVnPtProfiles(centmult, val, dnx, rndm, configs.GetpTCorrMasks()[l_ind]); } continue; } - for (Int_t i = 1; i <= fPtAxis->GetNbins(); i++) { - dnx = fGFW->Calculate(corrconfigs.at(l_ind), i - 1, kTRUE).real(); + for (int i = 1; i <= fPtAxis->GetNbins(); i++) { + auto dnx = fGFW->Calculate(corrconfigs.at(l_ind), i - 1, kTRUE).real(); if (dnx == 0) continue; auto val = fGFW->Calculate(corrconfigs.at(l_ind), i - 1, kFALSE).real() / dnx; - if (TMath::Abs(val) < 1) - (dt == kGen) ? fFC_gen->FillProfile(Form("%s_pt_%i", corrconfigs.at(l_ind).Head.c_str(), i), centmult, val, dnx, rndm) : fFC->FillProfile(Form("%s_pt_%i", corrconfigs.at(l_ind).Head.c_str(), i), centmult, val, dnx, rndm); + if (std::abs(val) < 1) + (dt == kGen) ? fFCgen->FillProfile(Form("%s_pt_%i", corrconfigs.at(l_ind).Head.c_str(), i), centmult, val, dnx, rndm) : fFC->FillProfile(Form("%s_pt_%i", corrconfigs.at(l_ind).Head.c_str(), i), centmult, val, dnx, rndm); } } return; } - template - void processCollision(TCollision collision, TTracks tracks, const float& centrality, const int& field) + template + void processCollision(TCollision collision, TTracks tracks, const float& centrality, const int& run) { if (tracks.size() < 1) return; if (centrality < centbinning.front() || centrality > centbinning.back()) return; + registry.fill(HIST("eventQA/eventSel"), 10.5); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(10.5); float vtxz = collision.posZ(); + if (dt != kGen && cfgRunByRun) { + th1sList[run][hVtxZ]->Fill(vtxz); + th1sList[run][hMult]->Fill(tracks.size()); + th1sList[run][hCent]->Fill(centrality); + } fGFW->Clear(); - fFCpt->ClearVector(); - float l_Random = fRndm->Rndm(); - for (auto& track : tracks) { - ProcessTrack(track, centrality, vtxz, field); + fFCpt->clearVector(); + float lRandom = fRndm->Rndm(); + for (const auto& track : tracks) { + processTrack(track, vtxz, run); } - FillOutputContainers
((cfgUseNch) ? tracks.size() : centrality, l_Random); + if (!cfgFillWeights) + fillOutputContainers
((cfgUseNch) ? tracks.size() : centrality, lRandom); } - template - inline void ProcessTrack(TrackObject const& track, const float& centrality, const float& vtxz, const int& field) + template + inline void processTrack(TTrack const& track, const float& vtxz, const int& run) { - float weff = 1, wacc = 1; - if constexpr (framework::has_type_v) { + if constexpr (framework::has_type_v) { if (track.mcParticleId() < 0 || !(track.has_mcParticle())) return; auto mcParticle = track.mcParticle(); - if (!mcParticle.isPhysicalPrimary() || mcParticle.eta() < etalow || mcParticle.eta() > etaup || mcParticle.pt() < ptlow || mcParticle.pt() > ptup || track.tpcNClsFound() < cfgNcls) + if (!mcParticle.isPhysicalPrimary()) return; + if (cfgFillQA) + fillTrackQA(track, vtxz); - if (cfgUseAdditionalTrackCut && !trackSelected(track, field)) + if (mcParticle.eta() < etalow || mcParticle.eta() > etaup || mcParticle.pt() < ptlow || mcParticle.pt() > ptup || track.tpcNClsFound() < cfgNcls) return; - if (cfgFillWeights) - fWeights->Fill(mcParticle.phi(), mcParticle.eta(), vtxz, mcParticle.pt(), centrality, 0); + int pidIndex = 0; + if (cfgUsePID) { + if (std::abs(mcParticle.pdgCode()) == kPiPlus) + pidIndex = 1; + if (std::abs(mcParticle.pdgCode()) == kKPlus) + pidIndex = 2; + if (std::abs(mcParticle.pdgCode()) == kProton) + pidIndex = 3; + } - if (!setCurrentParticleWeights(weff, wacc, mcParticle.phi(), mcParticle.eta(), mcParticle.pt(), vtxz)) - return; + if (cfgFillWeights) { + fillWeights(mcParticle, vtxz, 0, run); + } else { + fillPtSums(track, vtxz); + fillGFW(mcParticle, vtxz, pidIndex); + } - registry.fill(HIST("phi_eta_vtxZ_corrected"), mcParticle.phi(), mcParticle.eta(), vtxz, wacc); - if (cfgFillQA) - FillTrackQA(track, vtxz); + if (cfgFillQA) { + fillTrackQA(track, vtxz); + if (cfgRunByRun) { + th1sList[run][hPhi]->Fill(track.phi()); + th1sList[run][hEta]->Fill(track.eta()); + } + } - FillGFW(mcParticle, weff, wacc); - } else if constexpr (framework::has_type_v) { - if (!track.isPhysicalPrimary() || track.eta() < etalow || track.eta() > etaup || track.pt() < ptlow || track.pt() > ptup) + } else if constexpr (framework::has_type_v) { + if (!track.isPhysicalPrimary()) return; - if (cfgFillQA) - FillTrackQA(track, vtxz); + fillTrackQA(track, vtxz); - FillGFW(track, 1., 1.); - } else { - if (track.tpcNClsFound() < cfgNcls) + if (track.eta() < etalow || track.eta() > etaup || track.pt() < ptlow || track.pt() > ptup) return; - if (cfgUseAdditionalTrackCut && !trackSelected(track, field)) - return; + int pidIndex = 0; + if (cfgUsePID) { + if (std::abs(track.pdgCode()) == kPiPlus) + pidIndex = 1; + if (std::abs(track.pdgCode()) == kKPlus) + pidIndex = 2; + if (std::abs(track.pdgCode()) == kProton) + pidIndex = 3; + } - if (cfgFillWeights) - fWeights->Fill(track.phi(), track.eta(), vtxz, track.pt(), centrality, 0); + fillPtSums(track, vtxz); + fillGFW(track, vtxz, pidIndex); - if (!setCurrentParticleWeights(weff, wacc, track.phi(), track.eta(), track.pt(), vtxz)) + if (cfgFillQA) + fillTrackQA(track, vtxz); + } else { + if (cfgFillQA) + fillTrackQA(track, vtxz); + if (track.tpcNClsFound() < cfgNcls) return; - registry.fill(HIST("phi_eta_vtxZ_corrected"), track.phi(), track.eta(), vtxz, wacc); - if (cfgFillQA) - FillTrackQA(track, vtxz); + int pidIndex = 0; + if (cfgUsePID) { + // pid_index = getBayesPIDIndex(track); + pidIndex = getNsigmaPID(track); + } + if (cfgFillWeights) { + fillWeights(track, vtxz, pidIndex, run); + } else { + fillPtSums(track, vtxz); + fillGFW(track, vtxz, pidIndex); + } + if (cfgFillQA) { + fillTrackQA(track, vtxz); + if (cfgRunByRun) { + th1sList[run][hPhi]->Fill(track.phi()); + th1sList[run][hEta]->Fill(track.eta()); + } + } + } + } - FillGFW(track, weff, wacc); + template + inline void fillPtSums(TTrack track, const double& vtxz) + { + double wacc = (dt == kGen) ? 1. : getAcceptance(track, vtxz, 0); + double weff = (dt == kGen) ? 1. : getEfficiency(track); + if (weff < 0) + return; + if (std::abs(track.eta()) < cfgEtaPtPt) { + fFCpt->fill(weff, track.pt()); + } + if (!cfgUseGapMethod) { + std::complex q2p = {weff * wacc * std::cos(2 * track.phi()), weff * wacc * std::sin(2 * track.phi())}; + std::complex q2n = {weff * wacc * std::cos(-2 * track.phi()), weff * wacc * std::sin(-2 * track.phi())}; + fFCpt->fillArray(q2p, q2n, weff * track.pt(), weff); + fFCpt->fillArray(weff * wacc, weff * wacc, weff, weff); } } - template - inline void FillGFW(TrackObject track, float weff, float wacc) + template + inline void fillGFW(TTrack track, const double& vtxz, int pid_index) { - fFCpt->Fill(weff, track.pt()); - bool WithinPtPOI = (ptpoilow < track.pt()) && (track.pt() < ptpoiup); // within POI pT range - bool WithinPtRef = (ptreflow < track.pt()) && (track.pt() < ptrefup); // within RF pT range - if (WithinPtRef) - fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 1); - if (WithinPtPOI) - fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 2); - if (WithinPtPOI && WithinPtRef) - fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 4); + if (cfgUsePID) { // Analysing POI flow with id'ed particles + double ptmins[] = {ptpoilow, ptpoilow, 0.3, 0.5}; + double ptmaxs[] = {ptpoiup, ptpoiup, 6.0, 6.0}; + bool withinPtRef = (track.pt() > ptreflow && track.pt() < ptrefup); + bool withinPtPOI = (track.pt() > ptmins[pid_index] && track.pt() < ptmaxs[pid_index]); + bool withinPtNch = (track.pt() > ptmins[0] && track.pt() < ptmaxs[0]); + if (!withinPtPOI && !withinPtRef) + return; + double waccRef = (dt == kGen) ? 1. : getAcceptance(track, vtxz, 0); + double waccPOI = (dt == kGen) ? 1. : withinPtPOI ? getAcceptance(track, vtxz, pid_index + 1) + : getAcceptance(track, vtxz, 0); // + if (withinPtRef && withinPtPOI && pid_index) + waccRef = waccPOI; // if particle is both (then it's overlap), override ref with POI + if (withinPtRef) + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), waccRef, 1); + if (withinPtPOI && pid_index) + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), waccPOI, (1 << (pid_index + 1))); + if (withinPtNch) + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), waccPOI, 2); + if (withinPtPOI && withinPtRef && pid_index) + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), waccPOI, (1 << (pid_index + 5))); + if (withinPtNch && withinPtRef) + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), waccPOI, 32); + } else { // Analysing only integrated flow + bool withinPtRef = (track.pt() > ptreflow && track.pt() < ptrefup); + bool withinPtPOI = (track.pt() > ptpoilow && track.pt() < ptpoiup); + if (!withinPtPOI && !withinPtRef) + return; + double weff = (dt == kGen) ? 1. : getEfficiency(track); + if (weff < 0) + return; + double wacc = (dt == kGen) ? 1. : getAcceptance(track, vtxz, 0); + if (withinPtRef) + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 1); + if (withinPtPOI) + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 2); + if (withinPtRef && withinPtPOI) + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 4); + } return; } - template - inline void FillTrackQA(TrackObject track, const float vtxz) + template + inline void fillTrackQA(TTrack track, const float vtxz) { if constexpr (dt == kGen) { - registry.fill(HIST("phi_eta_vtxZ_gen"), track.phi(), track.eta(), vtxz); - registry.fill(HIST("pt_gen"), track.pt()); + registry.fill(HIST("MCGen/") + HIST(FillTimeName[ft]) + HIST("phi_eta_vtxZ_gen"), track.phi(), track.eta(), vtxz); + registry.fill(HIST("MCGen/") + HIST(FillTimeName[ft]) + HIST("pt_gen"), track.pt()); } else { - registry.fill(HIST("phi_eta_vtxZ"), track.phi(), track.eta(), vtxz); - registry.fill(HIST("pt_dcaXY_dcaZ"), track.pt(), track.dcaXY(), track.dcaZ()); + double wacc = getAcceptance(track, vtxz, 0); + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("phi_eta_vtxZ"), track.phi(), track.eta(), vtxz, (ft == kAfter) ? wacc : 1.0); + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("pt_dcaXY_dcaZ"), track.pt(), track.dcaXY(), track.dcaZ()); + if (ft == kAfter) { + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("pt_ref"), track.pt()); + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("pt_poi"), track.pt()); + } } } - template - inline void FillEventQA(CollisionObject collision, TracksObject tracks) + template + inline void fillEventQA(CollisionObject collision, TracksObject tracks) { - registry.fill(HIST("globalTracks_centT0C"), collision.centFT0C(), tracks.size()); - registry.fill(HIST("PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV()); - registry.fill(HIST("globalTracks_PVTracks"), collision.multNTracksPV(), tracks.size()); - registry.fill(HIST("globalTracks_multT0A"), collision.multFT0A(), tracks.size()); - registry.fill(HIST("globalTracks_multV0A"), collision.multFV0A(), tracks.size()); - registry.fill(HIST("multV0A_multT0A"), collision.multFT0A(), collision.multFV0A()); - registry.fill(HIST("multT0C_centT0C"), collision.centFT0C(), collision.multFT0C()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("globalTracks_centT0C"), collision.centFT0C(), tracks.size()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("globalTracks_PVTracks"), collision.multNTracksPV(), tracks.size()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("globalTracks_multT0A"), collision.multFT0A(), tracks.size()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("globalTracks_multV0A"), collision.multFV0A(), tracks.size()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("multV0A_multT0A"), collision.multFT0A(), collision.multFV0A()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("multT0C_centT0C"), collision.centFT0C(), collision.multFT0C()); return; } Filter collisionFilter = nabs(aod::collision::posZ) < cfgVtxZ; Filter trackFilter = nabs(aod::track::eta) < cfgEta && aod::track::pt > cfgPtmin&& aod::track::pt < cfgPtmax && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && nabs(aod::track::dcaXY) < cfgDCAxy&& nabs(aod::track::dcaZ) < cfgDCAz; - using myTracks = soa::Filtered>; + using GFWTracks = soa::Filtered>; - void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, myTracks const& tracks) + void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, GFWTracks const& tracks) { + auto bc = collision.bc_as(); + int run = bc.runNumber(); + if (run != lastRun) { + lastRun = run; + LOGF(info, "run = %d", run); + if (cfgRunByRun) { + if (std::find(runNumbers.begin(), runNumbers.end(), run) == runNumbers.end()) { + LOGF(info, "Creating histograms for run %d", run); + createRunByRunHistograms(run); + runNumbers.push_back(run); + } else { + LOGF(info, "run %d already in runNumbers", run); + } + if (!cfgFillWeights) + loadCorrections(bc); + } + } + if (!cfgFillWeights && !cfgRunByRun) + loadCorrections(bc); + registry.fill(HIST("eventQA/eventSel"), 0.5); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(0.5); if (!collision.sel8()) return; + registry.fill(HIST("eventQA/eventSel"), 1.5); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(1.5); + if (cfgOccupancySelection != -999) { + int occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy < 0 || occupancy > cfgOccupancySelection) + return; + } + registry.fill(HIST("eventQA/eventSel"), 2.5); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(2.5); const auto centrality = collision.centFT0C(); - auto bc = collision.bc_as(); - if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), centrality)) + if (cfgFillQA) + fillEventQA(collision, tracks); + if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), centrality, run)) return; if (cfgFillQA) - FillEventQA(collision, tracks); - loadCorrections(bc.timestamp()); - auto field = (cfgMagField == 99999) ? getMagneticField(bc.timestamp()) : cfgMagField; - processCollision(collision, tracks, centrality, field); + fillEventQA(collision, tracks); + processCollision(collision, tracks, centrality, run); } - PROCESS_SWITCH(GenericFramework, processData, "Process analysis for non-derived data", true); + PROCESS_SWITCH(FlowGenericFramework, processData, "Process analysis for non-derived data", true); void processMCReco(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks, aod::McParticles const&) { + auto bc = collision.bc_as(); + int run = bc.runNumber(); + if (run != lastRun) { + lastRun = run; + if (cfgRunByRun) + createRunByRunHistograms(run); + } if (!collision.sel8()) return; const auto centrality = collision.centFT0C(); - auto bc = collision.bc_as(); - if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), centrality)) + if (cfgFillQA) + fillEventQA(collision, tracks); + if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), centrality, run)) return; if (cfgFillQA) - FillEventQA(collision, tracks); - loadCorrections(bc.timestamp()); - auto field = (cfgMagField == 99999) ? getMagneticField(bc.timestamp()) : cfgMagField; - processCollision(collision, tracks, centrality, field); + fillEventQA(collision, tracks); + + if (!cfgFillWeights) + loadCorrections(bc); + processCollision(collision, tracks, centrality, run); } - PROCESS_SWITCH(GenericFramework, processMCReco, "Process analysis for MC reconstructed events", false); + PROCESS_SWITCH(FlowGenericFramework, processMCReco, "Process analysis for MC reconstructed events", false); Filter mcCollFilter = nabs(aod::mccollision::posZ) < cfgVtxZ; void processMCGen(soa::Filtered::iterator const& mcCollision, soa::SmallGroups> const& collisions, aod::McParticles const& particles) @@ -597,29 +936,35 @@ struct GenericFramework { if (collisions.size() != 1) return; float centrality = -1; - for (auto& collision : collisions) { + for (const auto& collision : collisions) { centrality = collision.centFT0C(); } - processCollision(mcCollision, particles, centrality, -999); + processCollision(mcCollision, particles, centrality, 0); } - PROCESS_SWITCH(GenericFramework, processMCGen, "Process analysis for MC generated events", false); + PROCESS_SWITCH(FlowGenericFramework, processMCGen, "Process analysis for MC generated events", false); - void processRun2(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, myTracks const& tracks) + void processRun2(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, GFWTracks const& tracks) { + auto bc = collision.bc_as(); + int run = bc.runNumber(); + if (run != lastRun) { + lastRun = run; + if (cfgRunByRun) + createRunByRunHistograms(run); + } if (!collision.sel7()) return; const auto centrality = collision.centRun2V0M(); - auto bc = collision.bc_as(); - loadCorrections(bc.timestamp()); - auto field = (cfgMagField == 99999) ? getMagneticField(bc.timestamp()) : cfgMagField; - processCollision(collision, tracks, centrality, field); + if (!cfgFillWeights) + loadCorrections(bc); + processCollision(collision, tracks, centrality, run); } - PROCESS_SWITCH(GenericFramework, processRun2, "Process analysis for Run 2 converted data", false); + PROCESS_SWITCH(FlowGenericFramework, processRun2, "Process analysis for Run 2 converted data", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), }; } diff --git a/PWGCF/JCorran/Core/CMakeLists.txt b/PWGCF/JCorran/Core/CMakeLists.txt index 57ebd1b2d85..6c4e10529bb 100644 --- a/PWGCF/JCorran/Core/CMakeLists.txt +++ b/PWGCF/JCorran/Core/CMakeLists.txt @@ -1,20 +1,27 @@ -#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. +# 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". +# 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 +# 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_library(JCorran SOURCES JFFlucAnalysis.cxx - JHistManager.cxx + JFFlucAnalysisO2Hist.cxx + FlowJSPCAnalysis.cxx + FlowJHistManager.cxx + JEPFlowAnalysis.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore) o2physics_target_root_dictionary(JCorran HEADERS JFFlucAnalysis.h - JHistManager.h + JFFlucAnalysisO2Hist.h + FlowJHistManager.h + FlowJSPCAnalysis.h + FlowJSPCObservables.h + JEPFlowAnalysis.h LINKDEF JCORRANLinkDef.h) diff --git a/PWGCF/JCorran/Core/FlowJHistManager.cxx b/PWGCF/JCorran/Core/FlowJHistManager.cxx new file mode 100644 index 00000000000..880ec409dbd --- /dev/null +++ b/PWGCF/JCorran/Core/FlowJHistManager.cxx @@ -0,0 +1,174 @@ +// 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. + +// Header files. +#include + +// O2 headers. + +// O2 Physics headers. +#include "PWGCF/JCorran/Core/FlowJHistManager.h" +#include "CommonConstants/MathConstants.h" + +// Namespaces. +using namespace o2; +using namespace o2::framework; + +/// \brief Create the histograms in the QA registry. +void FlowJHistManager::createHistQA() +{ + // Security checks for proper use of the method. + if (!mHistRegistryQA) { + LOGF(error, "QA histogram registry missing. Quitting..."); + return; + } + + // Definition of the QA histograms. + // All the histograms are defined in details for the first centrality + // class after additional cuts, then cloned for the other classes. + const AxisSpec axisCent{100, 0., 100., "Centrality percentile"}; + mHistRegistryQA->add("Centrality_00-01/After/histCent", "Centrality", + HistType::kTH1F, {axisCent}, true); + + const AxisSpec axisMulti{2500, 0., 25000., "N_{tracks}"}; + mHistRegistryQA->add("Centrality_00-01/After/histMulti", "Multiplicity", + HistType::kTH1I, {axisMulti}, true); + + const AxisSpec axisZvtx{30, -15., 15., "Z_{vtx} [cm]"}; + mHistRegistryQA->add("Centrality_00-01/After/histZvtx", "Z_{vtx}", + HistType::kTH1F, {axisZvtx}, true); + + AxisSpec axisPt = {60, 0., 6., "#it{p}_{T} [GeV/#it{c}]"}; + if (mUseVariablePtBins) { + std::vector ptBinning = {0., 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, + 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, + 0.8, 0.85, 0.9, 0.95, 1., 1.1, 1.2, 1.3, 1.4, + 1.5, 1.6, 1.7, 1.8, 1.9, 2., 2.2, 2.4, 2.6, + 2.8, 3., 3.2, 3.4, 3.6, 3.8, 4., 4.5, 5., 6.}; + axisPt = {ptBinning, "#it{p}_{T} [GeV/#it{c}]"}; + } + mHistRegistryQA->add("Centrality_00-01/After/histPt", "#it{p}_{T} (no NUE)", + HistType::kTH1F, {axisPt}, true); + + const AxisSpec axisEta = {20, -1., 1., "#eta"}; + mHistRegistryQA->add("Centrality_00-01/After/histEta", "Pseudorapidity", + HistType::kTH1F, {axisEta}, true); + + const AxisSpec axisPhi = {100, 0., o2::constants::math::TwoPI, "#varphi"}; + mHistRegistryQA->add("Centrality_00-01/After/histPhi", "Azimuthal angles (no NUA)", + HistType::kTH1F, {axisPhi}, true); + + const AxisSpec axisCharge = {2, -2., 2., "Charge"}; + mHistRegistryQA->add("Centrality_00-01/After/histCharge", "Electric charge", + HistType::kTH1I, {axisCharge}, true); + + // Additional QA for the full QA task. + if (mSaveAllQA) { + // TPC information. + const AxisSpec axisTPCNcls = {163, -0.5, 162.5, "N_{cls}"}; + mHistRegistryQA->add("Centrality_00-01/After/histTPCNClsFound", + "Number of found TPC clusters", + HistType::kTH1I, {axisTPCNcls}, true); + + mHistRegistryQA->add("Centrality_00-01/After/histTPCNClsCrossedRows", + "Number of crossed TPC rows", + HistType::kTH1I, {axisTPCNcls}, true); + + const AxisSpec axisTPCRatio = {20, -0.5, 19.5, "Ratio"}; + mHistRegistryQA->add("Centrality_00-01/After/histTPCCrossedRowsOverFindableCls", + "Ratio crossed rows over findable clusters in TPC", + HistType::kTH1F, {axisTPCRatio}, true); + + mHistRegistryQA->add("Centrality_00-01/After/histTPCFoundOverFindableCls", + "Ratio of found over findable clusters in TPC", + HistType::kTH1F, {axisTPCRatio}, true); + + const AxisSpec axisTPCFraction = {30, -0.5, 2.5, "Fraction"}; + mHistRegistryQA->add("Centrality_00-01/After/histTPCFractionSharedCls", + "Fraction of shared TPC clusters", + HistType::kTH1F, {axisTPCFraction}, true); + + const AxisSpec axisTPCChi = {200, -0.5, 19.5, "#chi^{2} per cl"}; + mHistRegistryQA->add("Centrality_00-01/After/histTPCChi2NCl", + "Chi2 per cluster for the TPC track segment", + HistType::kTH1F, {axisTPCChi}, true); + + // ITS information. + const AxisSpec axisITSNcls = {10, -0.5, 9.5, "N_{cls}"}; + mHistRegistryQA->add("Centrality_00-01/After/histITSNCls", "Number of ITS clusters", + HistType::kTH1I, {axisITSNcls}, true); + + mHistRegistryQA->add("Centrality_00-01/After/histITSNClsInnerBarrel", + "Number of ITS clusters in the Inner Barrel", + HistType::kTH1I, {axisITSNcls}, true); + + const AxisSpec axisITSChi = {500, -0.5, 50.5, "#chi^{2} per cl"}; + mHistRegistryQA->add("Centrality_00-01/After/histITSChi2NCl", + "Chi2 per cluster for the ITS track segment", + HistType::kTH1F, {axisITSChi}, true); + + // DCA information. + const AxisSpec axisDCAxy = {100, -2.5, 2.5, "DCA_{xy} (cm)"}; + mHistRegistryQA->add("Centrality_00-01/After/histDCAxy", "DCA_{xy} vs #it{p}_{T}", + HistType::kTH2F, {axisPt, axisDCAxy}, true); + + const AxisSpec axisDCAz = {110, -5.5, 5.5, "DCA_{z} (cm)"}; + mHistRegistryQA->add("Centrality_00-01/After/histDCAz", "DCA_{z}", + HistType::kTH1F, {axisDCAz}, true); + + if (mSaveQABefore) { + // Clone all the QA for the Before/ distributions. + mHistRegistryQA->addClone("Centrality_00-01/After/", "Centrality_00-01/Before/"); + } + } + + if (mObtainNUA) { // TODO: Replace with THnSparse if better with more events. + mHistRegistryQA->add("Centrality_00-01/After/histZvtxEtaPhi", "Zvtx-eta-phi", + HistType::kTH3F, {axisZvtx, axisEta, axisPhi}, true); + } + + // Add NUE/NUA related histograms for pT and phi only in After/. + mHistRegistryQA->add("Centrality_00-01/After/histPtCorrected", "#it{p}_{T} (with NUE)", + HistType::kTH1F, {axisPt}, true); + mHistRegistryQA->add("Centrality_00-01/After/histNUEWeights", "NUE weights", + HistType::kTH1F, {axisPt}, true); + mHistRegistryQA->add("Centrality_00-01/After/histPhiCorrected", "Azimuthal angles (with NUA)", + HistType::kTH1F, {axisPhi}, true); + mHistRegistryQA->add("Centrality_00-01/After/histNUAWeights", "NUA weights (projection)", + HistType::kTH1F, {axisPhi}, true); + + // Clone the first centrality class into the other classes. + for (int iBin = 1; iBin < mNcentBins; iBin++) { + mHistRegistryQA->addClone("Centrality_00-01/", MCentClasses[iBin].data()); + } + + LOGF(info, "QA histograms created."); +} + +/// \brief Get the centrality bin value corresponding to the percentile. +/// \param Centrality percentile of the collision. +/// \return Bin for the histograms,... +int FlowJHistManager::getCentBin(float cValue) +{ + const float centClasses[] = {0., 5., 10., 20., 30., 40., 50., 60., 70., 100.}; + + for (int i = 0; i < mNcentBins + 1; i++) { + if (cValue >= centClasses[i]) { + continue; + } else { + return i - 1; + } + } + + // We went through all centrality edges without returning at all. + // --> The measured percentile is larger than the final class we consider. + return -1; +} diff --git a/PWGCF/JCorran/Core/FlowJHistManager.h b/PWGCF/JCorran/Core/FlowJHistManager.h new file mode 100644 index 00000000000..e067a9f00b5 --- /dev/null +++ b/PWGCF/JCorran/Core/FlowJHistManager.h @@ -0,0 +1,312 @@ +// 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 Histogram manager for the AC-related analyses. +// \author Cindy Mordasini (cindy.mordasini@cern.ch) + +#ifndef PWGCF_JCORRAN_CORE_FLOWJHISTMANAGER_H_ +#define PWGCF_JCORRAN_CORE_FLOWJHISTMANAGER_H_ + +/* Header files. */ +#include +#include +#include +#include +#include "TH1.h" +#include "TH2.h" +#include "TH3.h" +#include "TProfile.h" +#include "TProfile2D.h" + +// O2 headers. // +#include "Framework/HistogramRegistry.h" + +// O2 Physics headers. + +/* Namespaces. */ + +// ---------------------------------------------------------------------------- +// Histogram manager to fill the general QA common to all flow tasks. +// ---------------------------------------------------------------------------- +class FlowJHistManager +{ + public: + FlowJHistManager() = default; + + // Setters and getters, in the same order as the data members. + void setHistRegistryQA(o2::framework::HistogramRegistry* myRegistry) + { + mHistRegistryQA = myRegistry; + LOGF(info, "QA histogram registry successfully set."); + } + o2::framework::HistogramRegistry* getHistRegistryQA() const { return mHistRegistryQA; } + + void setDebugLog(bool debug) + { + mDebugLog = debug; + LOGF(info, "Debug level: %d", mDebugLog); + } + bool getDebugLog() const { return mDebugLog; } + + void setObtainNUA(bool nua) + { + mObtainNUA = nua; + LOGF(info, "Obtain 3D Zvtx-eta-phi distribution: %d", mObtainNUA); + } + bool getObtainNUA() const { return mObtainNUA; } + + void setSaveAllQA(bool saveQA) + { + mSaveAllQA = saveQA; + LOGF(info, "Save the additional QA : %d.", mSaveAllQA); + } + bool getSaveAllQA() const { return mSaveAllQA; } + + void setSaveQABefore(bool saveQA) + { + mSaveQABefore = saveQA; + LOGF(info, "Save the QA before the selection : %d.", mSaveQABefore); + } + bool getSaveQABefore() const { return mSaveQABefore; } + + void setUseVariablePtBins(bool myAxis) + { + mUseVariablePtBins = myAxis; + LOGF(info, "Use variable pT binning: %d.", mUseVariablePtBins); + } + bool getUseVariablePtBins() const { return mUseVariablePtBins; } + + /* Methods specific to this class. */ + // The template functions are defined down here to prevent compilation errors. + void createHistQA(); + int getCentBin(float cValue); + + /// \brief Fill the event QA histograms. + /// \tparam T Type of collision. + /// \tparam mode Indicate if Before/ or After/ selection. + /// \param coll Collision entry of the table. + /// \param cBin Centrality bin of the collision. + /// \param cent Centrality percentile of the collision. + /// \param multi Collision multiplicity at this step. + template + void fillEventQA(T const& coll, int cBin, float cent, int multi) + { + if (!mHistRegistryQA) { + LOGF(fatal, "QA histogram registry missing. Quitting..."); + return; + } + + static constexpr std::string_view SubDir[] = {"Before/", "After/"}; + switch (cBin) { + case 0: + mHistRegistryQA->fill(HIST(MCentClasses[0]) + HIST(SubDir[mode]) + HIST("histCent"), cent); + mHistRegistryQA->fill(HIST(MCentClasses[0]) + HIST(SubDir[mode]) + HIST("histMulti"), multi); + mHistRegistryQA->fill(HIST(MCentClasses[0]) + HIST(SubDir[mode]) + HIST("histZvtx"), coll.posZ()); + break; + case 1: + mHistRegistryQA->fill(HIST(MCentClasses[1]) + HIST(SubDir[mode]) + HIST("histCent"), cent); + mHistRegistryQA->fill(HIST(MCentClasses[1]) + HIST(SubDir[mode]) + HIST("histMulti"), multi); + mHistRegistryQA->fill(HIST(MCentClasses[1]) + HIST(SubDir[mode]) + HIST("histZvtx"), coll.posZ()); + break; + case 2: + mHistRegistryQA->fill(HIST(MCentClasses[2]) + HIST(SubDir[mode]) + HIST("histCent"), cent); + mHistRegistryQA->fill(HIST(MCentClasses[2]) + HIST(SubDir[mode]) + HIST("histMulti"), multi); + mHistRegistryQA->fill(HIST(MCentClasses[2]) + HIST(SubDir[mode]) + HIST("histZvtx"), coll.posZ()); + break; + case 3: + mHistRegistryQA->fill(HIST(MCentClasses[3]) + HIST(SubDir[mode]) + HIST("histCent"), cent); + mHistRegistryQA->fill(HIST(MCentClasses[3]) + HIST(SubDir[mode]) + HIST("histMulti"), multi); + mHistRegistryQA->fill(HIST(MCentClasses[3]) + HIST(SubDir[mode]) + HIST("histZvtx"), coll.posZ()); + break; + case 4: + mHistRegistryQA->fill(HIST(MCentClasses[4]) + HIST(SubDir[mode]) + HIST("histCent"), cent); + mHistRegistryQA->fill(HIST(MCentClasses[4]) + HIST(SubDir[mode]) + HIST("histMulti"), multi); + mHistRegistryQA->fill(HIST(MCentClasses[4]) + HIST(SubDir[mode]) + HIST("histZvtx"), coll.posZ()); + break; + case 5: + mHistRegistryQA->fill(HIST(MCentClasses[5]) + HIST(SubDir[mode]) + HIST("histCent"), cent); + mHistRegistryQA->fill(HIST(MCentClasses[5]) + HIST(SubDir[mode]) + HIST("histMulti"), multi); + mHistRegistryQA->fill(HIST(MCentClasses[5]) + HIST(SubDir[mode]) + HIST("histZvtx"), coll.posZ()); + break; + case 6: + mHistRegistryQA->fill(HIST(MCentClasses[6]) + HIST(SubDir[mode]) + HIST("histCent"), cent); + mHistRegistryQA->fill(HIST(MCentClasses[6]) + HIST(SubDir[mode]) + HIST("histMulti"), multi); + mHistRegistryQA->fill(HIST(MCentClasses[6]) + HIST(SubDir[mode]) + HIST("histZvtx"), coll.posZ()); + break; + case 7: + mHistRegistryQA->fill(HIST(MCentClasses[7]) + HIST(SubDir[mode]) + HIST("histCent"), cent); + mHistRegistryQA->fill(HIST(MCentClasses[7]) + HIST(SubDir[mode]) + HIST("histMulti"), multi); + mHistRegistryQA->fill(HIST(MCentClasses[7]) + HIST(SubDir[mode]) + HIST("histZvtx"), coll.posZ()); + break; + case 8: + mHistRegistryQA->fill(HIST(MCentClasses[8]) + HIST(SubDir[mode]) + HIST("histCent"), cent); + mHistRegistryQA->fill(HIST(MCentClasses[8]) + HIST(SubDir[mode]) + HIST("histMulti"), multi); + mHistRegistryQA->fill(HIST(MCentClasses[8]) + HIST(SubDir[mode]) + HIST("histZvtx"), coll.posZ()); + break; + case 9: + mHistRegistryQA->fill(HIST(MCentClasses[9]) + HIST(SubDir[mode]) + HIST("histCent"), cent); + mHistRegistryQA->fill(HIST(MCentClasses[9]) + HIST(SubDir[mode]) + HIST("histMulti"), multi); + mHistRegistryQA->fill(HIST(MCentClasses[9]) + HIST(SubDir[mode]) + HIST("histZvtx"), coll.posZ()); + break; + } + + if (mDebugLog) + LOGF(info, "The EventQA has been filled."); + } + + /// \brief Hardcode the cBin for fillThisTrackQA if not constant. + /// \tparam T Type of track. + /// \tparam mode Set if we fill Before/ or After/ objects. + /// \param track Track entry. + /// \param cBin Centrality bin of the collision. + /// \param weightNUE Value of the NUE weight to apply to pT. + /// \param weightNUA Value of the NUA weight to apply to phi. + template + void fillTrackQA(T const& track, int cBin, + float weightNUE = 1., float weightNUA = 1., float zVtx = 0.) + { + if (!mHistRegistryQA) { + LOGF(fatal, "QA histogram registry missing. Quitting..."); + return; + } + + switch (cBin) { + case 0: + fillThisTrackQA<0, mode>(track, zVtx, weightNUE, weightNUA); + break; + case 1: + fillThisTrackQA<1, mode>(track, zVtx, weightNUE, weightNUA); + break; + case 2: + fillThisTrackQA<2, mode>(track, zVtx, weightNUE, weightNUA); + break; + case 3: + fillThisTrackQA<3, mode>(track, zVtx, weightNUE, weightNUA); + break; + case 4: + fillThisTrackQA<4, mode>(track, zVtx, weightNUE, weightNUA); + break; + case 5: + fillThisTrackQA<5, mode>(track, zVtx, weightNUE, weightNUA); + break; + case 6: + fillThisTrackQA<6, mode>(track, zVtx, weightNUE, weightNUA); + break; + case 7: + fillThisTrackQA<7, mode>(track, zVtx, weightNUE, weightNUA); + break; + case 8: + fillThisTrackQA<8, mode>(track, zVtx, weightNUE, weightNUA); + break; + case 9: + fillThisTrackQA<9, mode>(track, zVtx, weightNUE, weightNUA); + break; + } + + if (mDebugLog) { + LOGF(info, "The TrackQA has been filled for cBin = %d and mode = %d.", cBin, mode); + } + } + + /// \brief Fill the track QA histograms in a fixed centrality bin. + /// \tparam T Type of track. + /// \tparam cBin Centrality bin of the collision. + /// \tparam mode Fill the QA before/after the full selection. + /// \param track Track entry of the table. + /// \param zVtx Value of the Zvtx of the collision the track belongs to. + /// \param weightNUE Value of the NUE weight, the inverse is applied to pT. + /// \param weightNUA Value of the NUA weight, the inverse is applied to phi. + /// \note This method can be directly used if no switch is previously needed. + // TODO: Add filling of the weight histograms. + template + void fillThisTrackQA(T const& track, float zVtx = 0., + float weightNUE = 1., float weightNUA = 1.) + { + static constexpr std::string_view SubDir[] = {"Before/", "After/"}; + + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histPt"), track.pt()); + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histEta"), track.eta()); + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histPhi"), track.phi()); + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histCharge"), track.sign()); + + if (mode == 1) { // 'Weight' distributions are defined only for After/. + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST("After/histPtCorrected"), + track.pt(), 1. / weightNUE); + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST("After/histPhiCorrected"), + track.phi(), 1. / weightNUA); + + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST("After/histNUEWeights"), + track.pt(), weightNUE); + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST("After/histNUAWeights"), + track.phi(), weightNUA); + + // 3D distribution Zvtx-eta-phi. + if (mObtainNUA) { + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST("After/histZvtxEtaPhi"), + zVtx, track.eta(), track.phi()); + } + } + + if (mSaveAllQA) { + // TPC information. + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histTPCNClsFound"), + track.tpcNClsFound()); + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histTPCNClsCrossedRows"), + track.tpcNClsCrossedRows()); + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histTPCCrossedRowsOverFindableCls"), + track.tpcCrossedRowsOverFindableCls()); + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histTPCFoundOverFindableCls"), + track.tpcFoundOverFindableCls()); + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histTPCFractionSharedCls"), + track.tpcFractionSharedCls()); + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histTPCChi2NCl"), + track.tpcChi2NCl()); + + // ITS information. + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histITSNCls"), + track.itsNCls()); + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histITSNClsInnerBarrel"), + track.itsNClsInnerBarrel()); + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histITSChi2NCl"), + track.itsChi2NCl()); + + // DCA information. + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histDCAxy"), + track.pt(), track.dcaXY()); + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histDCAz"), + track.dcaZ()); + } + + if (mDebugLog) { + LOGF(info, "The ThisTrackQA has been filled for cBin = %d and mode = %d.", cBin, mode); + } + } + + private: + o2::framework::HistogramRegistry* mHistRegistryQA = nullptr; ///< For the QA output. + + bool mDebugLog = false; ///< Enable to print additional log for debug. + bool mObtainNUA = false; ///< Enable to get the 3D Zvtx-eta-phi distribution for NUA. + bool mSaveAllQA = false; ///< Save the additional QA (true for QA task). + bool mSaveQABefore = false; ///< Save the QA output before any selection. + bool mUseVariablePtBins = false; ///< Enable the use of a variable width pT binning. + + static const int mNcentBins = 10; ///< Number of centrality classes. + static constexpr std::string_view MCentClasses[] = { ///< Centrality classes. + "Centrality_00-01/", "Centrality_01-02/", "Centrality_02-05/", + "Centrality_05-10/", "Centrality_10-20/", "Centrality_20-30/", + "Centrality_30-40/", "Centrality_40-50/", "Centrality_50-60/", + "Centrality_60-70/"}; + + ClassDefNV(FlowJHistManager, 1); +}; + +#endif // PWGCF_JCORRAN_CORE_FLOWJHISTMANAGER_H_ diff --git a/PWGCF/JCorran/Core/FlowJSPCAnalysis.cxx b/PWGCF/JCorran/Core/FlowJSPCAnalysis.cxx new file mode 100644 index 00000000000..40585b3abec --- /dev/null +++ b/PWGCF/JCorran/Core/FlowJSPCAnalysis.cxx @@ -0,0 +1,442 @@ +// 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. + +// Header files. + +// O2 headers. + +// O2 Physics headers. + +#include "PWGCF/JCorran/Core/FlowJSPCAnalysis.h" + +using namespace o2; +using namespace o2::framework; +using namespace std; + +TComplex FlowJSPCAnalysis::q(const int harmN, const int p) +{ + if (harmN >= 0) + return qvecs->QvectorQC[harmN][p]; + return TComplex::Conjugate(qvecs->QvectorQC[-harmN][p]); +} // End of Q + +/// \brief Calculate multi-particle correlators using recursion. +/// \param n Number of particles in the correlator. +/// \param harmonic Array of length n of harmonics. +/// \return Complex value of the multiparticle correlator. +/// \note Improved faster version) originally developed by Kristjan Gulbrandsen +/// (gulbrand@nbi.dk). +TComplex FlowJSPCAnalysis::recursion(int n, int* harmonic, int mult = 1, int skip = 0) +{ + int nm1 = n - 1; + TComplex c(q(harmonic[nm1], mult)); + if (nm1 == 0) + return c; + c *= recursion(nm1, harmonic); + if (nm1 == skip) + return c; + + int multp1 = mult + 1; + int nm2 = n - 2; + int counter1 = 0; + int hhold = harmonic[counter1]; + harmonic[counter1] = harmonic[nm2]; + harmonic[nm2] = hhold + harmonic[nm1]; + TComplex c2(recursion(nm1, harmonic, multp1, nm2)); + int counter2 = n - 3; + + while (counter2 >= skip) { + harmonic[nm2] = harmonic[counter1]; + harmonic[counter1] = hhold; + ++counter1; + hhold = harmonic[counter1]; + harmonic[counter1] = harmonic[nm2]; + harmonic[nm2] = hhold + harmonic[nm1]; + c2 += recursion(nm1, harmonic, multp1, counter2); + --counter2; + } + harmonic[nm2] = harmonic[counter1]; + harmonic[counter1] = hhold; + + if (mult == 1) + return c - c2; + return c - static_cast(mult) * c2; +} // End of recursion + +void FlowJSPCAnalysis::calculateCorrelators(const int fCentBin) +{ + // Loop over the combinations of harmonics and calculate the corresponding SPC num and den. + + // Declare the arrays to later fill all the needed bins for the correlators + // and the error terms. + double* dataCorrelation = new double[3]; // cosine, weight, sine. + double correlationNum; + double weightCorrelationNum; + double correlationDenom; + double weightCorrelationDenom; + + for (int i = 0; i < 14; ++i) + fCorrelDenoms[i] = 0; + + for (int j = 0; j < 12; j++) { + if (fHarmosArray[j][0] == 0) { + continue; + } // Skip null correlator list. + + // Calculate the numerator. + int hArrayNum[7] = {0}; + for (int iH = 0; iH < 7; iH++) { + hArrayNum[iH] = fHarmosArray[j][iH + 1]; + } + correlation(fHarmosArray[j][0], 7, hArrayNum, dataCorrelation); + correlationNum = dataCorrelation[0]; + weightCorrelationNum = dataCorrelation[1]; + + // Calculate the denominator. + int nPartDen = 2 * fHarmosArray[j][0]; + int hArrayDen[14] = {0}; + for (int iH = 0; iH < 7; iH++) { + hArrayDen[2 * iH] = hArrayNum[iH]; + hArrayDen[2 * iH + 1] = -1 * hArrayNum[iH]; + } + + correlation(nPartDen, 14, hArrayDen, dataCorrelation); + correlationDenom = dataCorrelation[0]; + weightCorrelationDenom = dataCorrelation[1]; + + // Check if the values are real numbers before filling. + if (std::isnan(correlationNum) || std::isnan(correlationDenom) || std::isnan(weightCorrelationNum) || std::isnan(weightCorrelationDenom)) + continue; + + // Histogram filling + fillHistograms(fCentBin, j, correlationNum, correlationDenom, weightCorrelationNum, weightCorrelationDenom); + + correlationNum = 0.; + weightCorrelationNum = 0.; + correlationDenom = 0.; + weightCorrelationDenom = 0.; + } +} + +void FlowJSPCAnalysis::fillHistograms(const int fCentBin, int ind, double cNum, double cDenom, double wNum, double wDenom) +{ + switch (fCentBin) { + case 0: { + mHistRegistry->fill(HIST(MCentClasses[0]) + HIST("fResults"), 2. * static_cast(ind) + 0.5, cNum, wNum); + mHistRegistry->fill(HIST(MCentClasses[0]) + HIST("fResults"), 2. * static_cast(ind) + 1.5, cDenom, wDenom); + mHistRegistry->fill(HIST(MCentClasses[0]) + HIST("fCovResults"), 4. * static_cast(ind) + 0.5, cNum * cDenom, wNum * wDenom); + mHistRegistry->fill(HIST(MCentClasses[0]) + HIST("fCovResults"), 4. * static_cast(ind) + 1.5, wNum * wDenom, 1.); + mHistRegistry->fill(HIST(MCentClasses[0]) + HIST("fCovResults"), 4. * static_cast(ind) + 2.5, wNum, 1.); + mHistRegistry->fill(HIST(MCentClasses[0]) + HIST("fCovResults"), 4. * static_cast(ind) + 3.5, wDenom, 1.); + } break; + case 1: { + mHistRegistry->fill(HIST(MCentClasses[1]) + HIST("fResults"), 2. * static_cast(ind) + 0.5, cNum, wNum); + mHistRegistry->fill(HIST(MCentClasses[1]) + HIST("fResults"), 2. * static_cast(ind) + 1.5, cDenom, wDenom); + mHistRegistry->fill(HIST(MCentClasses[1]) + HIST("fCovResults"), 4. * static_cast(ind) + 0.5, cNum * cDenom, wNum * wDenom); + mHistRegistry->fill(HIST(MCentClasses[1]) + HIST("fCovResults"), 4. * static_cast(ind) + 1.5, wNum * wDenom, 1.); + mHistRegistry->fill(HIST(MCentClasses[1]) + HIST("fCovResults"), 4. * static_cast(ind) + 2.5, wNum, 1.); + mHistRegistry->fill(HIST(MCentClasses[1]) + HIST("fCovResults"), 4. * static_cast(ind) + 3.5, wDenom, 1.); + } break; + case 2: { + mHistRegistry->fill(HIST(MCentClasses[2]) + HIST("fResults"), 2. * static_cast(ind) + 0.5, cNum, wNum); + mHistRegistry->fill(HIST(MCentClasses[2]) + HIST("fResults"), 2. * static_cast(ind) + 1.5, cDenom, wDenom); + mHistRegistry->fill(HIST(MCentClasses[2]) + HIST("fCovResults"), 4. * static_cast(ind) + 0.5, cNum * cDenom, wNum * wDenom); + mHistRegistry->fill(HIST(MCentClasses[2]) + HIST("fCovResults"), 4. * static_cast(ind) + 1.5, wNum * wDenom, 1.); + mHistRegistry->fill(HIST(MCentClasses[2]) + HIST("fCovResults"), 4. * static_cast(ind) + 2.5, wNum, 1.); + mHistRegistry->fill(HIST(MCentClasses[2]) + HIST("fCovResults"), 4. * static_cast(ind) + 3.5, wDenom, 1.); + } break; + case 3: { + mHistRegistry->fill(HIST(MCentClasses[3]) + HIST("fResults"), 2. * static_cast(ind) + 0.5, cNum, wNum); + mHistRegistry->fill(HIST(MCentClasses[3]) + HIST("fResults"), 2. * static_cast(ind) + 1.5, cDenom, wDenom); + mHistRegistry->fill(HIST(MCentClasses[3]) + HIST("fCovResults"), 4. * static_cast(ind) + 0.5, cNum * cDenom, wNum * wDenom); + mHistRegistry->fill(HIST(MCentClasses[3]) + HIST("fCovResults"), 4. * static_cast(ind) + 1.5, wNum * wDenom, 1.); + mHistRegistry->fill(HIST(MCentClasses[3]) + HIST("fCovResults"), 4. * static_cast(ind) + 2.5, wNum, 1.); + mHistRegistry->fill(HIST(MCentClasses[3]) + HIST("fCovResults"), 4. * static_cast(ind) + 3.5, wDenom, 1.); + } break; + case 4: { + mHistRegistry->fill(HIST(MCentClasses[4]) + HIST("fResults"), 2. * static_cast(ind) + 0.5, cNum, wNum); + mHistRegistry->fill(HIST(MCentClasses[4]) + HIST("fResults"), 2. * static_cast(ind) + 1.5, cDenom, wDenom); + mHistRegistry->fill(HIST(MCentClasses[4]) + HIST("fCovResults"), 4. * static_cast(ind) + 0.5, cNum * cDenom, wNum * wDenom); + mHistRegistry->fill(HIST(MCentClasses[4]) + HIST("fCovResults"), 4. * static_cast(ind) + 1.5, wNum * wDenom, 1.); + mHistRegistry->fill(HIST(MCentClasses[4]) + HIST("fCovResults"), 4. * static_cast(ind) + 2.5, wNum, 1.); + mHistRegistry->fill(HIST(MCentClasses[4]) + HIST("fCovResults"), 4. * static_cast(ind) + 3.5, wDenom, 1.); + } break; + case 5: { + mHistRegistry->fill(HIST(MCentClasses[5]) + HIST("fResults"), 2. * static_cast(ind) + 0.5, cNum, wNum); + mHistRegistry->fill(HIST(MCentClasses[5]) + HIST("fResults"), 2. * static_cast(ind) + 1.5, cDenom, wDenom); + mHistRegistry->fill(HIST(MCentClasses[5]) + HIST("fCovResults"), 4. * static_cast(ind) + 0.5, cNum * cDenom, wNum * wDenom); + mHistRegistry->fill(HIST(MCentClasses[5]) + HIST("fCovResults"), 4. * static_cast(ind) + 1.5, wNum * wDenom, 1.); + mHistRegistry->fill(HIST(MCentClasses[5]) + HIST("fCovResults"), 4. * static_cast(ind) + 2.5, wNum, 1.); + mHistRegistry->fill(HIST(MCentClasses[5]) + HIST("fCovResults"), 4. * static_cast(ind) + 3.5, wDenom, 1.); + } break; + case 6: { + mHistRegistry->fill(HIST(MCentClasses[6]) + HIST("fResults"), 2. * static_cast(ind) + 0.5, cNum, wNum); + mHistRegistry->fill(HIST(MCentClasses[6]) + HIST("fResults"), 2. * static_cast(ind) + 1.5, cDenom, wDenom); + mHistRegistry->fill(HIST(MCentClasses[6]) + HIST("fCovResults"), 4. * static_cast(ind) + 0.5, cNum * cDenom, wNum * wDenom); + mHistRegistry->fill(HIST(MCentClasses[6]) + HIST("fCovResults"), 4. * static_cast(ind) + 1.5, wNum * wDenom, 1.); + mHistRegistry->fill(HIST(MCentClasses[6]) + HIST("fCovResults"), 4. * static_cast(ind) + 2.5, wNum, 1.); + mHistRegistry->fill(HIST(MCentClasses[6]) + HIST("fCovResults"), 4. * static_cast(ind) + 3.5, wDenom, 1.); + } break; + case 7: { + mHistRegistry->fill(HIST(MCentClasses[7]) + HIST("fResults"), 2. * static_cast(ind) + 0.5, cNum, wNum); + mHistRegistry->fill(HIST(MCentClasses[7]) + HIST("fResults"), 2. * static_cast(ind) + 1.5, cDenom, wDenom); + mHistRegistry->fill(HIST(MCentClasses[7]) + HIST("fCovResults"), 4. * static_cast(ind) + 0.5, cNum * cDenom, wNum * wDenom); + mHistRegistry->fill(HIST(MCentClasses[7]) + HIST("fCovResults"), 4. * static_cast(ind) + 1.5, wNum * wDenom, 1.); + mHistRegistry->fill(HIST(MCentClasses[7]) + HIST("fCovResults"), 4. * static_cast(ind) + 2.5, wNum, 1.); + mHistRegistry->fill(HIST(MCentClasses[7]) + HIST("fCovResults"), 4. * static_cast(ind) + 3.5, wDenom, 1.); + } break; + case 8: { + mHistRegistry->fill(HIST(MCentClasses[8]) + HIST("fResults"), 2. * static_cast(ind) + 0.5, cNum, wNum); + mHistRegistry->fill(HIST(MCentClasses[8]) + HIST("fResults"), 2. * static_cast(ind) + 1.5, cDenom, wDenom); + mHistRegistry->fill(HIST(MCentClasses[8]) + HIST("fCovResults"), 4. * static_cast(ind) + 0.5, cNum * cDenom, wNum * wDenom); + mHistRegistry->fill(HIST(MCentClasses[8]) + HIST("fCovResults"), 4. * static_cast(ind) + 1.5, wNum * wDenom, 1.); + mHistRegistry->fill(HIST(MCentClasses[8]) + HIST("fCovResults"), 4. * static_cast(ind) + 2.5, wNum, 1.); + mHistRegistry->fill(HIST(MCentClasses[8]) + HIST("fCovResults"), 4. * static_cast(ind) + 3.5, wDenom, 1.); + } break; + default: + return; + } +} + +void FlowJSPCAnalysis::fillQAHistograms(const int fCentBin, double phi, double phiWeight) +{ + switch (fCentBin) { + case 0: { + mHistRegistry->fill(HIST(MCentClasses[0]) + HIST("phiBefore"), phi); + mHistRegistry->fill(HIST(MCentClasses[0]) + HIST("phiAfter"), phi, phiWeight); + } break; + case 1: { + mHistRegistry->fill(HIST(MCentClasses[1]) + HIST("phiBefore"), phi); + mHistRegistry->fill(HIST(MCentClasses[1]) + HIST("phiAfter"), phi, phiWeight); + } break; + case 2: { + mHistRegistry->fill(HIST(MCentClasses[2]) + HIST("phiBefore"), phi); + mHistRegistry->fill(HIST(MCentClasses[2]) + HIST("phiAfter"), phi, phiWeight); + } break; + case 3: { + mHistRegistry->fill(HIST(MCentClasses[3]) + HIST("phiBefore"), phi); + mHistRegistry->fill(HIST(MCentClasses[3]) + HIST("phiAfter"), phi, phiWeight); + } break; + case 4: { + mHistRegistry->fill(HIST(MCentClasses[4]) + HIST("phiBefore"), phi); + mHistRegistry->fill(HIST(MCentClasses[4]) + HIST("phiAfter"), phi, phiWeight); + } break; + case 5: { + mHistRegistry->fill(HIST(MCentClasses[5]) + HIST("phiBefore"), phi); + mHistRegistry->fill(HIST(MCentClasses[5]) + HIST("phiAfter"), phi, phiWeight); + } break; + case 6: { + mHistRegistry->fill(HIST(MCentClasses[6]) + HIST("phiBefore"), phi); + mHistRegistry->fill(HIST(MCentClasses[6]) + HIST("phiAfter"), phi, phiWeight); + } break; + case 7: { + mHistRegistry->fill(HIST(MCentClasses[7]) + HIST("phiBefore"), phi); + mHistRegistry->fill(HIST(MCentClasses[7]) + HIST("phiAfter"), phi, phiWeight); + } break; + case 8: { + mHistRegistry->fill(HIST(MCentClasses[8]) + HIST("phiBefore"), phi); + mHistRegistry->fill(HIST(MCentClasses[8]) + HIST("phiAfter"), phi, phiWeight); + } break; + default: + return; + } +} + +void FlowJSPCAnalysis::correlation(int c_nPart, int c_nHarmo, int* harmo, double* correlData) +{ + // Calculate the correlators for the provided set of harmonics using Q-vectors. + // Protection against anisotropic correlators. + int sumHarmo = 0; + for (int i = 0; i < c_nHarmo; i++) { + sumHarmo += harmo[i]; + } + if (sumHarmo != 0) { + LOGF(error, "\nOups, this correlator is not isotropic(sum = %d). Bye\n", sumHarmo); + return; + } + + switch (c_nPart) { + case 2: { + int harmonicsTwoNum[2] = {harmo[0], harmo[1]}; + int harmonicsTwoDen[2] = {0, 0}; + + if (!fCorrelDenoms[1]) { + fCorrelDenoms[1] = recursion(2, harmonicsTwoDen).Re(); + } + + TComplex twoRecursion = recursion(2, harmonicsTwoNum) / fCorrelDenoms[1]; + + correlData[0] = twoRecursion.Re(); // + correlData[1] = fCorrelDenoms[1]; // weight + correlData[2] = twoRecursion.Im(); // + } break; + case 3: { + int harmonicsThreeNum[3] = {harmo[0], harmo[1], harmo[2]}; + int harmonicsThreeDen[3] = {0, 0, 0}; + + if (!fCorrelDenoms[2]) { + fCorrelDenoms[2] = recursion(3, harmonicsThreeDen).Re(); + } + + TComplex threeRecursion = recursion(3, harmonicsThreeNum) / fCorrelDenoms[2]; + + correlData[0] = threeRecursion.Re(); // + correlData[1] = fCorrelDenoms[2]; // weight + correlData[2] = threeRecursion.Im(); // + } break; + case 4: { + int harmonicsFourNum[4] = {harmo[0], harmo[1], harmo[2], harmo[3]}; + int harmonicsFourDen[4] = {0, 0, 0, 0}; + + if (!fCorrelDenoms[3]) { + fCorrelDenoms[3] = recursion(4, harmonicsFourDen).Re(); + } + + TComplex fourRecursion = recursion(4, harmonicsFourNum) / fCorrelDenoms[3]; + + correlData[0] = fourRecursion.Re(); // + correlData[1] = fCorrelDenoms[3]; // weight + correlData[2] = fourRecursion.Im(); // + } break; + case 5: { + int harmonicsFiveNum[5] = {harmo[0], harmo[1], harmo[2], harmo[3], harmo[4]}; + int harmonicsFiveDen[5] = {0, 0, 0, 0, 0}; + + if (!fCorrelDenoms[4]) { + fCorrelDenoms[4] = recursion(5, harmonicsFiveDen).Re(); + } + + TComplex fiveRecursion = recursion(5, harmonicsFiveNum) / fCorrelDenoms[4]; + + correlData[0] = fiveRecursion.Re(); // + correlData[1] = fCorrelDenoms[4]; // weight + correlData[2] = fiveRecursion.Im(); // + } break; + case 6: { + int harmonicsSixNum[6] = {harmo[0], harmo[1], harmo[2], harmo[3], harmo[4], harmo[5]}; + int harmonicsSixDen[6] = {0, 0, 0, 0, 0, 0}; + + if (!fCorrelDenoms[5]) { + fCorrelDenoms[5] = recursion(6, harmonicsSixDen).Re(); + } + + TComplex sixRecursion = recursion(6, harmonicsSixNum) / fCorrelDenoms[5]; + + correlData[0] = sixRecursion.Re(); // + correlData[1] = fCorrelDenoms[5]; // weight + correlData[2] = sixRecursion.Im(); // + } break; + case 7: { + int harmonicsSevenNum[7] = {harmo[0], harmo[1], harmo[2], harmo[3], harmo[4], harmo[5], harmo[6]}; + int harmonicsSevenDen[7] = {0, 0, 0, 0, 0, 0, 0}; + + if (!fCorrelDenoms[6]) { + fCorrelDenoms[6] = recursion(7, harmonicsSevenDen).Re(); + } + + TComplex sevenRecursion = recursion(7, harmonicsSevenNum) / fCorrelDenoms[6]; + + correlData[0] = sevenRecursion.Re(); // + correlData[1] = fCorrelDenoms[6]; // weight + correlData[2] = sevenRecursion.Im(); // + } break; + case 8: { + int harmonicsEightNum[8] = {harmo[0], harmo[1], harmo[2], harmo[3], + harmo[4], harmo[5], harmo[6], harmo[7]}; + int harmonicsEightDen[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + + if (!fCorrelDenoms[7]) { + fCorrelDenoms[7] = recursion(8, harmonicsEightDen).Re(); + } + + TComplex eightRecursion = recursion(8, harmonicsEightNum) / fCorrelDenoms[7]; + + correlData[0] = eightRecursion.Re(); // + correlData[1] = fCorrelDenoms[7]; // weight + correlData[2] = eightRecursion.Im(); // + } break; + case 9: { + int harmonicsNineNum[9] = {harmo[0], harmo[1], harmo[2], harmo[3], harmo[4], + harmo[5], harmo[6], harmo[7], harmo[8]}; + int harmonicsNineDen[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; + + if (!fCorrelDenoms[8]) { + fCorrelDenoms[8] = recursion(9, harmonicsNineDen).Re(); + } + + TComplex nineRecursion = recursion(9, harmonicsNineNum) / fCorrelDenoms[8]; + + correlData[0] = nineRecursion.Re(); + correlData[1] = fCorrelDenoms[8]; + correlData[2] = nineRecursion.Im(); + } break; + case 10: { + int harmonicsTenNum[10] = {harmo[0], harmo[1], harmo[2], harmo[3], harmo[4], + harmo[5], harmo[6], harmo[7], harmo[8], harmo[9]}; + int harmonicsTenDen[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + if (!fCorrelDenoms[9]) { + fCorrelDenoms[9] = recursion(10, harmonicsTenDen).Re(); + } + + TComplex tenRecursion = recursion(10, harmonicsTenNum) / fCorrelDenoms[9]; + + correlData[0] = tenRecursion.Re(); + correlData[1] = fCorrelDenoms[9]; + correlData[2] = tenRecursion.Im(); + } break; + case 12: { + int harmonicsTwelveNum[12] = {harmo[0], harmo[1], harmo[2], harmo[3], harmo[4], harmo[5], + harmo[6], harmo[7], harmo[8], harmo[9], harmo[10], harmo[11]}; + int harmonicsTwelveDen[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + if (!fCorrelDenoms[11]) { + fCorrelDenoms[11] = recursion(12, harmonicsTwelveDen).Re(); + } + + TComplex twelveRecursion = recursion(12, harmonicsTwelveNum) / fCorrelDenoms[11]; + + correlData[0] = twelveRecursion.Re(); + correlData[1] = fCorrelDenoms[11]; + correlData[2] = twelveRecursion.Im(); + } break; + case 14: { + int harmonicsFourteenNum[14] = {harmo[0], harmo[1], harmo[2], harmo[3], harmo[4], harmo[5], harmo[6], + harmo[7], harmo[8], harmo[9], harmo[10], harmo[11], harmo[12], harmo[13]}; + int harmonicsFourteenDen[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + if (!fCorrelDenoms[13]) { + fCorrelDenoms[13] = recursion(14, harmonicsFourteenDen).Re(); + } + + TComplex fourteenRecursion = recursion(14, harmonicsFourteenNum) / fCorrelDenoms[13]; + + correlData[0] = fourteenRecursion.Re(); + correlData[1] = fCorrelDenoms[13]; + correlData[2] = fourteenRecursion.Im(); + } break; + } +} +int FlowJSPCAnalysis::getCentBin(float cValue) +{ + const float centClasses[] = {0., 1., 2., 5., 10., 20., 30., 40., 50., 60., 70.}; + for (int i = 0; i < 8; i++) { + if (cValue >= centClasses[i]) { + continue; + } else { + return i - 1; + } + } + + // We went through all centrality edges without returning at all. + // --> The measured percentile is larger than the final class we consider. + return -1; +} diff --git a/PWGCF/JCorran/Core/FlowJSPCAnalysis.h b/PWGCF/JCorran/Core/FlowJSPCAnalysis.h new file mode 100644 index 00000000000..ba584d1e1eb --- /dev/null +++ b/PWGCF/JCorran/Core/FlowJSPCAnalysis.h @@ -0,0 +1,98 @@ +// 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 Calculation class for the SPC-related analyses. +// \author Maxim Virta (maxim.virta@cern.fi), Cindy Mordasini (cindy.mordasini@cern.ch) + +#ifndef PWGCF_JCORRAN_CORE_FLOWJSPCANALYSIS_H_ +#define PWGCF_JCORRAN_CORE_FLOWJSPCANALYSIS_H_ + +/* Header files. */ +#include +#include +#include +#include + +// O2 headers. // +#include "Framework/HistogramRegistry.h" +#include "PWGCF/JCorran/Core/JQVectors.h" +#include "CommonConstants/MathConstants.h" + +class FlowJSPCAnalysis +{ + public: + FlowJSPCAnalysis() = default; + + void setHistRegistry(o2::framework::HistogramRegistry* histReg) { mHistRegistry = histReg; } + int getCentBin(float cValue); + + using JQVectorsT = JQVectors; + inline void setQvectors(const JQVectorsT* _qvecs) { qvecs = _qvecs; } + void correlation(int c_nPart, int c_nHarmo, int* harmo, double* correlData); + void calculateCorrelators(const int fCentBin); + void fillHistograms(const int fCentBin, int ind, double cNum, double cDenom, double wNum, double wDenom); + void fillQAHistograms(const int fCentBin, double phi, double phiWeight); + TComplex recursion(int n, int* harmonic, int mult, int skip); + TComplex q(const int harmN, const int p); + + void createHistos() + { + if (!mHistRegistry) { + LOGF(error, "QA histogram registry missing. Quitting..."); + return; + } + mHistRegistry->add("FullCentrality", "FullCentrality", o2::framework::HistType::kTH1D, {{100, 0., 100.}}, true); + mHistRegistry->add("Centrality_0/fResults", "Numerators and denominators", {o2::framework::HistType::kTProfile, {{24, 0., 24.}}}, true); + mHistRegistry->add("Centrality_0/fCovResults", "Covariance N*D", {o2::framework::HistType::kTProfile, {{48, 0., 48.}}}, true); + mHistRegistry->add("Centrality_0/phiBefore", "Phi before", {o2::framework::HistType::kTH1D, {{100, 0., o2::constants::math::TwoPI}}}, true); + mHistRegistry->add("Centrality_0/phiAfter", "Phi after", {o2::framework::HistType::kTH1D, {{100, 0., o2::constants::math::TwoPI}}}, true); + + for (uint i = 1; i < 9; i++) { + mHistRegistry->addClone("Centrality_0/", Form("Centrality_%u/", i)); + } + } + + void setCorrSet(int obsInd, int harmo[8]) + { + for (int i = 0; i < 8; i++) { + fHarmosArray[obsInd][i] = harmo[i]; + } + } + void setFullCorrSet(int harmo[12][8]) + { + memcpy(fHarmosArray, harmo, sizeof(int) * 12 * 8); + } + + static constexpr std::string_view MCentClasses[] = { + "Centrality_0/", + "Centrality_1/", + "Centrality_2/", + "Centrality_3/", + "Centrality_4/", + "Centrality_5/", + "Centrality_6/", + "Centrality_7/", + "Centrality_8/"}; + + private: + const int mNqHarmos = 113; ///< Highest harmo for Q(n,p): (v8*14part)+1. + const int mNqPowers = 15; ///< Max power for Q(n,p): 14part+1. + const JQVectorsT* qvecs; + + o2::framework::HistogramRegistry* mHistRegistry = nullptr; + + int fHarmosArray[12][8]; + + double fCorrelDenoms[14]; + + ClassDefNV(FlowJSPCAnalysis, 1); +}; +#endif // PWGCF_JCORRAN_CORE_FLOWJSPCANALYSIS_H_ diff --git a/PWGCF/JCorran/Core/FlowJSPCObservables.h b/PWGCF/JCorran/Core/FlowJSPCObservables.h new file mode 100644 index 00000000000..bc504fe31fe --- /dev/null +++ b/PWGCF/JCorran/Core/FlowJSPCObservables.h @@ -0,0 +1,95 @@ +// 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 Helper class for the SPC-related analyses. +// \author Maxim Virta (maxim.virta@cern.fi) + +#ifndef PWGCF_JCORRAN_CORE_FLOWJSPCOBSERVABLES_H_ +#define PWGCF_JCORRAN_CORE_FLOWJSPCOBSERVABLES_H_ + +// O2 headers. // +#include "Framework/HistogramRegistry.h" + +const int maxNrComb = 12; +class FlowJSPCObservables +{ + public: + FlowJSPCObservables() = default; + + int harmonicArray[maxNrComb][8] = {{0}}; + + void setSPCObservables(int index) + { + // int *harmonicArray = (int*)malloc(sizeof(int)*maxNrComb*8); + + // Switch to set up correct symmetry plane combinations + switch (index) { + case 0: { + LOGF(info, "Computing three harmonic SPC"); + int harmonicArray01[maxNrComb][8] = { + {3, 6, -3, -3, 0, 0, 0, 0}, + {3, 4, -2, -2, 0, 0, 0, 0}, + {3, 8, -4, -4, 0, 0, 0, 0}, + {3, 2, 4, -6, 0, 0, 0, 0}, + {3, 2, 3, -5, 0, 0, 0, 0}, + {3, 3, 4, -7, 0, 0, 0, 0}, // These are three harmonic SPC!! + {3, 2, 5, -7, 0, 0, 0, 0}, // These are three harmonic SPC!! + {3, 3, 5, -8, 0, 0, 0, 0}, // These are three harmonic SPC!! + {0, 6, -2, -2, -2, 0, 0, 0}, + {0, 2, -3, -4, 5, 0, 0, 0}, + {0, 2, -3, -3, 4, 0, 0, 0}, + {0, 3, 3, -2, -2, -2, 0, 0}}; + + memcpy(harmonicArray, harmonicArray01, sizeof(int) * maxNrComb * 8); + } break; + case 1: { + LOGF(info, "Computing four harmonic SPC"); + int harmonicArray02[maxNrComb][8] = { + {4, 6, -2, -2, -2, 0, 0, 0}, + {4, 2, -3, -4, 5, 0, 0, 0}, + {4, 2, -3, -3, 4, 0, 0, 0}, + {4, 2, 2, 3, -7, 0, 0, 0}, // These are three harmonic SPC!! + {4, 2, 2, 4, -8, 0, 0, 0}, // These are three harmonic SPC!! + {4, 2, 7, -4, -5, 0, 0, 0}, + {4, 3, -4, -4, 5, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}}; + memcpy(harmonicArray, harmonicArray02, sizeof(int) * maxNrComb * 8); + } break; + case 3: { + LOGF(info, "Computing five and six harmonic SPC"); + int harmonicArray03[maxNrComb][8] = { + {5, 3, 3, -2, -2, -2, 0, 0}, + {5, 2, 2, -3, 4, -5, 0, 0}, + {5, 2, 3, 3, -4, -4, 0, 0}, + {5, 3, 3, 3, -4, -5, 0, 0}, + {5, 2, 3, -4, 5, -6, 0, 0}, + {5, 8, -2, -2, -2, -2, 0, 0}, + {6, 2, 2, 2, 2, -4, -4, 0}, + {6, 2, 3, 4, 4, -6, -7, 0}, + {6, 2, 2, 2, 2, -3, -5, 0}, + {6, 2, 2, 2, 3, -4, -5, 0}, + {6, 2, 2, 3, 3, -4, -6, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}}; + memcpy(harmonicArray, harmonicArray03, sizeof(int) * maxNrComb * 8); + } break; + default: + LOGF(error, "ERROR: Invalid configuration index. Skipping this element."); + } + } + + private: + ClassDefNV(FlowJSPCObservables, 1); +}; +#endif // PWGCF_JCORRAN_CORE_FLOWJSPCOBSERVABLES_H_ diff --git a/PWGCF/JCorran/Core/JCORRANLinkDef.h b/PWGCF/JCorran/Core/JCORRANLinkDef.h index 173d8828284..d0e9bef308d 100755 --- a/PWGCF/JCorran/Core/JCORRANLinkDef.h +++ b/PWGCF/JCorran/Core/JCORRANLinkDef.h @@ -9,9 +9,18 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#ifndef PWGCF_JCORRAN_CORE_JCORRANLINKDEF_H_ +#define PWGCF_JCORRAN_CORE_JCORRANLINKDEF_H_ + #pragma link off all globals; #pragma link off all classes; #pragma link off all functions; #pragma link C++ class JFFlucAnalysis + ; -#pragma link C++ class JHistManager + ; +#pragma link C++ class JFFlucAnalysisO2Hist + ; +#pragma link C++ class FlowJHistManager + ; +#pragma link C++ class FlowJSPCAnalysis + ; +#pragma link C++ class FlowJSPCObservables + ; +#pragma link C++ class JEPFlowAnalysis + ; + +#endif // PWGCF_JCORRAN_CORE_JCORRANLINKDEF_H_ diff --git a/PWGCF/JCorran/Core/JEPFlowAnalysis.cxx b/PWGCF/JCorran/Core/JEPFlowAnalysis.cxx new file mode 100644 index 00000000000..6d027002e8c --- /dev/null +++ b/PWGCF/JCorran/Core/JEPFlowAnalysis.cxx @@ -0,0 +1,43 @@ +// 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. + +#include "JEPFlowAnalysis.h" + +using namespace o2; +using namespace o2::framework; +using namespace std; + +void JEPFlowAnalysis::FillVnHistograms(const Int_t harmN, Float_t cent, Float_t det, Float_t pT, Float_t vn, Float_t vn_sin) +{ + switch (harmN) { + case 2: { + mHistRegistry->fill(HIST("fV2EP"), vn, det, pT, cent, 1.); + mHistRegistry->fill(HIST("fV2EP_sin"), vn_sin, det, pT, cent, 1.); + } break; + case 3: { + mHistRegistry->fill(HIST("fV3EP"), vn, det, pT, cent, 1.); + mHistRegistry->fill(HIST("fV3EP_sin"), vn_sin, det, pT, cent, 1.); + } break; + case 4: { + mHistRegistry->fill(HIST("fV4EP"), vn, det, pT, cent, 1.); + mHistRegistry->fill(HIST("fV4EP_sin"), vn_sin, det, pT, cent, 1.); + } break; + default: + break; + } +} + +void JEPFlowAnalysis::FillResolutionHistograms(Float_t cent, Float_t harmN, Float_t ResNumA, Float_t ResNumB, Float_t ResDenom) +{ + mHistRegistry->fill(HIST("fResNumA"), ResNumA, harmN, cent, 1.); + mHistRegistry->fill(HIST("fResNumB"), ResNumB, harmN, cent, 1.); + mHistRegistry->fill(HIST("fResDenom"), ResDenom, harmN, cent, 1.); +} diff --git a/PWGCF/JCorran/Core/JEPFlowAnalysis.h b/PWGCF/JCorran/Core/JEPFlowAnalysis.h new file mode 100644 index 00000000000..f1bc994099c --- /dev/null +++ b/PWGCF/JCorran/Core/JEPFlowAnalysis.h @@ -0,0 +1,63 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// \author Maxim Virta (maxim.virta@cern.ch) + +#ifndef PWGCF_JCORRAN_CORE_JEPFLOWANALYSIS_H_ +#define PWGCF_JCORRAN_CORE_JEPFLOWANALYSIS_H_ + +#include + +// O2 headers. // +#include "Framework/HistogramRegistry.h" + +using namespace o2; +using namespace o2::framework; +using namespace std; + +class JEPFlowAnalysis +{ + public: + JEPFlowAnalysis() = default; + void SetHistRegistry(HistogramRegistry* histReg) { mHistRegistry = histReg; } + + void FillHistograms(const Int_t fCentBin, Float_t det, Float_t v2, Float_t v3, Float_t v4); + void FillVnHistograms(const Int_t harmN, Float_t fCent, Float_t det, Float_t pT, Float_t vn, Float_t vn_sin); + void FillResolutionHistograms(Float_t fCent, Float_t harmN, Float_t ResNumA, Float_t ResNumB, Float_t ResDenom); + TComplex Q(const Int_t harmN, const Int_t p); + + void CreateHistograms() + { + if (!mHistRegistry) { + LOGF(error, "Histogram registry missing. Quitting..."); + return; + } + + mHistRegistry->add("FullCentrality", "FullCentrality", HistType::kTH1D, {{100, 0., 100.}}, true); + mHistRegistry->add("fV2EP", "", {HistType::kTHnD, {{200, -1.05, 1.05}, {3, 0.5, 3.5}, {100, 0.2, 12.}, {20, 0., 100.}}}, true); // x: v2_cos, y: detector, z: pT, t: centrality + mHistRegistry->add("fV3EP", "", {HistType::kTHnD, {{200, -1.05, 1.05}, {3, 0.5, 3.5}, {100, 0.2, 12.}, {20, 0., 100.}}}, true); // x: v2_cos, y: detector, z: pT, t: centrality + mHistRegistry->add("fV4EP", "", {HistType::kTHnD, {{200, -1.05, 1.05}, {3, 0.5, 3.5}, {100, 0.2, 12.}, {20, 0., 100.}}}, true); // x: v2_cos, y: detector, z: pT, t: centrality + mHistRegistry->add("fV2EP_sin", "", {HistType::kTHnD, {{200, -1.05, 1.05}, {3, 0.5, 3.5}, {100, 0.2, 12.}, {20, 0., 100.}}}, true); // x: v2_sin, y: detector, z: pT, t: centrality + mHistRegistry->add("fV3EP_sin", "", {HistType::kTHnD, {{200, -1.05, 1.05}, {3, 0.5, 3.5}, {100, 0.2, 12.}, {20, 0., 100.}}}, true); // x: v2_sin, y: detector, z: pT, t: centrality + mHistRegistry->add("fV4EP_sin", "", {HistType::kTHnD, {{200, -1.05, 1.05}, {3, 0.5, 3.5}, {100, 0.2, 12.}, {20, 0., 100.}}}, true); // x: v2_sin, y: detector, z: pT, t: centrality + mHistRegistry->add("fResNumA", "", {HistType::kTH3D, {{100, -1.05, 1.05}, {3, 1.5, 4.5}, {20, 0., 100.}}}, true); // x: resolution, y: harmonic, t: centrality + mHistRegistry->add("fResNumB", "", {HistType::kTH3D, {{100, -1.05, 1.05}, {3, 1.5, 4.5}, {20, 0., 100.}}}, true); // x: resolution, y: harmonic, t: centrality + mHistRegistry->add("fResDenom", "", {HistType::kTH3D, {{100, -1.05, 1.05}, {3, 1.5, 4.5}, {20, 0., 100.}}}, true); // x: resolution, y: harmonic, t: centrality + mHistRegistry->add("phi", "Phi", {HistType::kTH1D, {{100, 0., TMath::TwoPi()}}}, true); + } + + private: + HistogramRegistry* mHistRegistry; + + ClassDefNV(JEPFlowAnalysis, 1); +}; + +#endif // PWGCF_JCORRAN_CORE_JEPFLOWANALYSIS_H_ diff --git a/PWGCF/JCorran/Core/JFFlucAnalysis.cxx b/PWGCF/JCorran/Core/JFFlucAnalysis.cxx index 39f8f700b36..9dc4189a810 100644 --- a/PWGCF/JCorran/Core/JFFlucAnalysis.cxx +++ b/PWGCF/JCorran/Core/JFFlucAnalysis.cxx @@ -12,104 +12,48 @@ /// \author Jasper Parkkila (jparkkil@cern.ch) /// \since Sep 2022 -#include -#include -#include -#include #include #include #include - #include "JFFlucAnalysis.h" -JFFlucAnalysis::JFFlucAnalysis() : fVertex(0), +JFFlucAnalysis::JFFlucAnalysis() : TNamed(), + fVertex(0), + fAvgInvariantMass(0.0f), fCent(0), - fCBin(0), - fHMG(0), - fBin_Subset(), - fBin_h(), - fBin_k(), - fBin_hh(), - fBin_kk(), - fHistCentBin(), - fh_cent(), - fh_ImpactParameter(), - fh_vertex(), - fh_eta(), - fh_phi(), - fh_phieta(), - fh_phietaz(), - fh_ntracks(), - fh_vn(), - fh_vna(), - fh_vn_vn() + fImpactParameter(-1), + subeventMask(kSubEvent_A | kSubEvent_B), + flags(0), + pqvecs(0), + pqvecsRef(0) { - subeventMask = kSubEvent_A | kSubEvent_B; - flags = 0; - fEta_min = 0; - fEta_max = 0; - fImpactParameter = -1; + // } //________________________________________________________________________ -JFFlucAnalysis::JFFlucAnalysis(const char* /*name*/) : fVertex(0), +JFFlucAnalysis::JFFlucAnalysis(const char* /*name*/) : TNamed(), + fVertex(0), + fAvgInvariantMass(0.0f), fCent(0), - fCBin(0), - fHMG(0), - fBin_Subset(), - fBin_h(), - fBin_k(), - fBin_hh(), - fBin_kk(), - fHistCentBin(), - fh_cent(), - fh_ImpactParameter(), - fh_vertex(), - fh_eta(), - fh_phi(), - fh_phieta(), - fh_phietaz(), - fh_ntracks(), - fh_vn(), - fh_vna(), - fh_vn_vn() + fImpactParameter(-1), + subeventMask(kSubEvent_A | kSubEvent_B), + flags(0), + pqvecs(0), + pqvecsRef(0) { - // cout << "analysis task created " << endl; - - subeventMask = kSubEvent_A | kSubEvent_B; - flags = 0; - fEta_min = 0; - fEta_max = 0; - fImpactParameter = -1; + // } -Double_t JFFlucAnalysis::pttJacek[74] = {0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.2, 2.4, 2.6, 2.8, 3, 3.2, 3.4, 3.6, 3.8, 4, 4.5, 5, 5.5, 6, 6.5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 40, 45, 50, 60, 70, 80, 90, 100}; -UInt_t JFFlucAnalysis::NpttJacek = sizeof(JFFlucAnalysis::pttJacek) / sizeof(JFFlucAnalysis::pttJacek[0]) - 1; - //________________________________________________________________________ -JFFlucAnalysis::JFFlucAnalysis(const JFFlucAnalysis& a) : // AliAnalysisTaskSE(a.GetName()), - +JFFlucAnalysis::JFFlucAnalysis(const JFFlucAnalysis& a) : TNamed(a), fVertex(a.fVertex), + fAvgInvariantMass(a.fAvgInvariantMass), fCent(a.fCent), - fCBin(a.fCBin), - fHMG(a.fHMG), - fBin_Subset(a.fBin_Subset), - fBin_h(a.fBin_h), - fBin_k(a.fBin_k), - fBin_hh(a.fBin_hh), - fBin_kk(a.fBin_kk), - fHistCentBin(a.fHistCentBin), - fh_cent(a.fh_cent), - fh_ImpactParameter(a.fh_ImpactParameter), - fh_vertex(a.fh_vertex), - fh_eta(a.fh_eta), - fh_phi(a.fh_phi), - fh_phieta(a.fh_phieta), - fh_phietaz(a.fh_phietaz), - fh_ntracks(a.fh_ntracks), - fh_vn(a.fh_vn), - fh_vna(a.fh_vna), - fh_vn_vn(a.fh_vn_vn) + fImpactParameter(a.fImpactParameter), + subeventMask(a.subeventMask), + flags(a.flags), + pqvecs(a.pqvecs), + pqvecsRef(a.pqvecsRef) { // copy constructor } @@ -129,206 +73,40 @@ void JFFlucAnalysis::Init() //________________________________________________________________________ void JFFlucAnalysis::UserCreateOutputObjects() { - fHMG = new JHistManager("JFFlucHistManager", "jfluc"); - // set JBin here // - fBin_Subset.Set("Sub", "Sub", "Sub:%d", JBin::kSingle).SetBin(2); - fBin_h.Set("NH", "NH", "NH:%d", JBin::kSingle).SetBin(kNH); - fBin_k.Set("K", "K", "K:%d", JBin::kSingle).SetBin(nKL); - - fBin_hh.Set("NHH", "NHH", "NHH:%d", JBin::kSingle).SetBin(kcNH); - fBin_kk.Set("KK", "KK", "KK:%d", JBin::kSingle).SetBin(nKL); - - // TODO: index with binning the array of pointers - fHistCentBin.Set("CentBin", "CentBin", "Cent:%d", JBin::kSingle).SetBin(numBins); - - fVertexBin.Set("Vtx", "Vtx", "Vtx:%d", JBin::kSingle).SetBin(3); - fCorrBin.Set("C", "C", "C:%d", JBin::kSingle).SetBin(28); - - fBin_Nptbins.Set("PtBin", "PtBin", "Pt:%d", JBin::kSingle).SetBin(N_ptbins); - - // set JTH1D here // - fh_cent - << TH1D("h_cent", "h_cent", 200, 0, 100) - << "END"; - - fh_ImpactParameter - << TH1D("h_IP", "h_IP", 400, -2, 20) - << "END"; - - fh_TrkQA_TPCvsCent - << TH2D("h_trk_Cent_vs_TPC", "h_trk_Cent_vs_TPC", 100, 0, 100, 100, 0, 3000) - << "END"; - - fh_TrkQA_TPCvsGlob - << TH2D("h_trk_Glob_vs_TPC", "h_trk_Glob_vs_TPC", 100, 0, 2000, 100, 0, 3000) - << "END"; - - fh_TrkQA_FB32_vs_FB32TOF - << TH2D("h_trk_FB32_vs_FB32TOF", "h_trk_FB32_vs_FB32TOF", 200, 0, 4000, 100, 0, 2000) - << "END"; - - fh_vertex - << TH1D("h_vertex", "h_vertex", 400, -20, 20) - << fVertexBin - << "END"; - fh_pt - << TH1D("hChargedPtJacek", "", JFFlucAnalysis::NpttJacek, JFFlucAnalysis::pttJacek) - << fHistCentBin - << "END"; - - fh_eta - << TH1D("h_eta", "h_eta", 40, -2.0, 2.0) - << fHistCentBin - << "END"; - fh_phi - << TH1D("h_phi", "h_phi", 50, -TMath::Pi(), TMath::Pi()) - << fHistCentBin << fBin_Subset - << "END"; - if (!(flags & kFlucPhiCorrection)) { - fh_phieta - << TH2D("h_phieta", "h_phieta", 50, -TMath::Pi(), TMath::Pi(), 40, -2.0, 2.0) - << fHistCentBin - << "END"; - fh_phietaz - << TH3D("h_phietaz", "h_phietaz", 50, -TMath::Pi(), TMath::Pi(), 40, -2.0, 2.0, 20, -10.0, 10.0) - << fHistCentBin - << "END"; - } - - fh_psi_n - << TH1D("h_psi", "h_psi", 50, -0.5 * TMath::Pi(), 0.5 * TMath::Pi()) - << fBin_h - << fHistCentBin - << "END"; - - fh_cos_n_phi - << TH1D("h_cos_n_phi", "h_cos_n_phi", 50, -1, 1) - << fBin_h - << fHistCentBin - << "END"; - - fh_sin_n_phi - << TH1D("h_sin_n_phi", "h_sin_n_phi", 50, -1, 1) - << fBin_h - << fHistCentBin - << "END"; - - fh_cos_n_psi_n - << TH1D("h_cos_n_psi", "h_cos_n_psi", 50, -1, 1) - << fBin_h - << fHistCentBin - << "END"; - - fh_sin_n_psi_n - << TH1D("h_sin_n_psi", "h_sin_n_psi", 50, -1, 1) - << fBin_h - << fHistCentBin - << "END"; - - fh_ntracks - << TH1D("h_tracks", "h_tracks", 100, 0, 5000) - << fHistCentBin - << "END"; - - fh_vn - << TH1D("hvn", "hvn", 1024, -1.0, 1.0) - << fBin_h << fBin_k - << fHistCentBin - << "END"; // histogram of vn_h^k values for [ih][ik][iCent] - fh_vna - << TH1D("hvna", "hvna", 1024, -1.0, 1.0) - << fBin_h << fBin_k - << fHistCentBin - << "END"; // histogram of vn_h^k values for [ih][ik][iCent] - fh_vn_vn - << TH1D("hvn_vn", "hvn_vn", 1024, -1.0, 1.0) - << fBin_h << fBin_k - << fBin_hh << fBin_kk - << fHistCentBin - << "END"; // histo of < vn * vn > for [ih][ik][ihh][ikk][iCent] - fh_correlator - << TH1D("h_corr", "h_corr", 1024, -3.0, 3.0) - << fCorrBin - << fHistCentBin - << "END"; - - fh_SC_ptdep_4corr - << TH1D("hvnvm_SC", "hvnvm_SC", 1024, -1.5, 1.5) - << fBin_h << fBin_k - << fBin_hh << fBin_kk - << fHistCentBin << fBin_Nptbins - << "END"; - fh_SC_ptdep_2corr - << TH1D("hvn_SC", "hvn_SC", 1024, -1.5, 1.5) - << fBin_h << fBin_k - << fHistCentBin << fBin_Nptbins - << "END"; - - fh_SC_with_QC_4corr - << TH1D("hQC_SC4p", "hQC_SC4p", 1024, -1.5, 1.5) - << fBin_h << fBin_hh - << fHistCentBin - << "END"; - fh_SC_with_QC_2corr - << TH1D("hQC_SC2p", "hQC_SC2p", 1024, -1.5, 1.5) - << fBin_h - << fHistCentBin - << "END"; - fh_SC_with_QC_2corr_gap - << TH1D("hQC_SC2p_eta10", "hQC_SC2p_eta10", 1024, -1.5, 1.5) - << fBin_h - << fHistCentBin - << "END"; - /*fh_evt_SP_QC_ratio_4p - << TH1D("hSPQCratio4p", "hSPQCratio4p", 1024, -100, 100) - << fBin_h - << fHistCentBin - << "END"; // fBin_h > not stand for harmonics, just case(32, 42, 52, 53, 43) - - fh_evt_SP_QC_ratio_2p - << TH1D("hSPQCratio", "hSPQCratio", 1024, -100, 100) - << fBin_h - << fHistCentBin - << "END"; // fBin_h > not stand for harmonics, only for v2, v3, v4, v5*/ - // JTH1D set done. - - fHMG->Print(); - // fHMG->WriteConfig(); + // } //________________________________________________________________________ JFFlucAnalysis::~JFFlucAnalysis() { - delete fHMG; + // } -#define A i -#define B (1 - i) #define C(u) TComplex::Conjugate(u) // TODO: conjugate macro -inline TComplex TwoGap(const TComplex (*pQq)[JFFlucAnalysis::kNH][JFFlucAnalysis::nKL], uint i, uint a, uint b) +inline TComplex TwoGap(const TComplex (&Qa)[JFFlucAnalysis::kNH][JFFlucAnalysis::nKL], const TComplex (&Qb)[JFFlucAnalysis::kNH][JFFlucAnalysis::nKL], UInt_t a, UInt_t b) { - return pQq[A][a][1] * C(pQq[B][b][1]); + return Qa[a][1] * C(Qb[b][1]); } -inline TComplex ThreeGap(const TComplex (*pQq)[JFFlucAnalysis::kNH][JFFlucAnalysis::nKL], uint i, uint a, uint b, uint c) +inline TComplex ThreeGap(const TComplex (&Qa)[JFFlucAnalysis::kNH][JFFlucAnalysis::nKL], const TComplex (&Qb)[JFFlucAnalysis::kNH][JFFlucAnalysis::nKL], UInt_t a, UInt_t b, UInt_t c) { - return pQq[A][a][1] * C(pQq[B][b][1] * pQq[B][c][1] - pQq[B][b + c][2]); + return Qa[a][1] * C(Qb[b][1] * Qb[c][1] - Qb[b + c][2]); } -inline TComplex FourGap22(const TComplex (*pQq)[JFFlucAnalysis::kNH][JFFlucAnalysis::nKL], uint i, uint a, uint b, uint c, uint d) +inline TComplex FourGap22(const TComplex (&Qa)[JFFlucAnalysis::kNH][JFFlucAnalysis::nKL], const TComplex (&Qb)[JFFlucAnalysis::kNH][JFFlucAnalysis::nKL], UInt_t a, UInt_t b, UInt_t c, UInt_t d) { - return pQq[A][a][1] * pQq[A][b][1] * C(pQq[B][c][1] * pQq[B][d][1]) - pQq[A][a + b][2] * C(pQq[B][c][1] * pQq[B][d][1]) - pQq[A][a][1] * pQq[A][b][1] * C(pQq[B][c + d][2]) + pQq[A][a + b][2] * C(pQq[B][c + d][2]); + return Qa[a][1] * Qa[b][1] * C(Qb[c][1] * Qb[d][1]) - Qa[a + b][2] * C(Qb[c][1] * Qb[d][1]) - Qa[a][1] * Qa[b][1] * C(Qb[c + d][2]) + Qa[a + b][2] * C(Qb[c + d][2]); } -inline TComplex FourGap13(const TComplex (*pQq)[JFFlucAnalysis::kNH][JFFlucAnalysis::nKL], uint i, uint a, uint b, uint c, uint d) +inline TComplex FourGap13(const TComplex (&Qa)[JFFlucAnalysis::kNH][JFFlucAnalysis::nKL], const TComplex (&Qb)[JFFlucAnalysis::kNH][JFFlucAnalysis::nKL], UInt_t a, UInt_t b, UInt_t c, UInt_t d) { - return pQq[A][a][1] * C(pQq[B][b][1] * pQq[B][c][1] * pQq[B][d][1] - pQq[B][b + c][2] * pQq[B][d][1] - pQq[B][b + d][2] * pQq[B][c][1] - pQq[B][c + d][2] * pQq[B][b][1] + 2.0 * pQq[B][b + c + d][3]); + return Qa[a][1] * C(Qb[b][1] * Qb[c][1] * Qb[d][1] - Qb[b + c][2] * Qb[d][1] - Qb[b + d][2] * Qb[c][1] - Qb[c + d][2] * Qb[b][1] + 2.0 * Qb[b + c + d][3]); } -inline TComplex SixGap33(const TComplex (*pQq)[JFFlucAnalysis::kNH][JFFlucAnalysis::nKL], uint i, uint n1, uint n2, uint n3, uint n4, uint n5, uint n6) +inline TComplex SixGap33(const TComplex (&Qa)[JFFlucAnalysis::kNH][JFFlucAnalysis::nKL], const TComplex (&Qb)[JFFlucAnalysis::kNH][JFFlucAnalysis::nKL], UInt_t n1, UInt_t n2, UInt_t n3, UInt_t n4, UInt_t n5, UInt_t n6) { - return pQq[A][n1][1] * pQq[A][n2][1] * pQq[A][n3][1] * C(pQq[B][n4][1] * pQq[B][n5][1] * pQq[B][n6][1]) - pQq[A][n1][1] * pQq[A][n2][1] * pQq[A][n3][1] * C(pQq[B][n4 + n5][2] * pQq[B][n6][1]) - pQq[A][n1][1] * pQq[A][n2][1] * pQq[A][n3][1] * C(pQq[B][n4 + n6][2] * pQq[B][n5][1]) - pQq[A][n1][1] * pQq[A][n2][1] * pQq[A][n3][1] * C(pQq[B][n5 + n6][2] * pQq[B][n4][1]) + 2.0 * pQq[A][n1][1] * pQq[A][n2][1] * pQq[A][n3][1] * C(pQq[B][n4 + n5 + n6][3]) - pQq[A][n1 + n2][2] * pQq[A][n3][1] * C(pQq[B][n4][1] * pQq[B][n5][1] * pQq[B][n6][1]) + pQq[A][n1 + n2][2] * pQq[A][n3][1] * C(pQq[B][n4 + n5][2] * pQq[B][n6][1]) + pQq[A][n1 + n2][2] * pQq[A][n3][1] * C(pQq[B][n4 + n6][2] * pQq[B][n5][1]) + pQq[A][n1 + n2][2] * pQq[A][n3][1] * C(pQq[B][n5 + n6][2] * pQq[B][n4][1]) - 2.0 * pQq[A][n1 + n2][2] * pQq[A][n3][1] * C(pQq[B][n4 + n5 + n6][3]) - pQq[A][n1 + n3][2] * pQq[A][n2][1] * C(pQq[B][n4][1] * pQq[B][n5][1] * pQq[B][n6][1]) + pQq[A][n1 + n3][2] * pQq[A][n2][1] * C(pQq[B][n4 + n5][2] * pQq[B][n6][1]) + pQq[A][n1 + n3][2] * pQq[A][n2][1] * C(pQq[B][n4 + n6][2] * pQq[B][n5][1]) + pQq[A][n1 + n3][2] * pQq[A][n2][1] * C(pQq[B][n5 + n6][2] * pQq[B][n4][1]) - 2.0 * pQq[A][n1 + n3][2] * pQq[A][n2][1] * C(pQq[B][n4 + n5 + n6][3]) - pQq[A][n2 + n3][2] * pQq[A][n1][1] * C(pQq[B][n4][1] * pQq[B][n5][1] * pQq[B][n6][1]) + pQq[A][n2 + n3][2] * pQq[A][n1][1] * C(pQq[B][n4 + n5][2] * pQq[B][n6][1]) + pQq[A][n2 + n3][2] * pQq[A][n1][1] * C(pQq[B][n4 + n6][2] * pQq[B][n5][1]) + pQq[A][n2 + n3][2] * pQq[A][n1][1] * C(pQq[B][n5 + n6][2] * pQq[B][n4][1]) - 2.0 * pQq[A][n2 + n3][2] * pQq[A][n1][1] * C(pQq[B][n4 + n5 + n6][3]) + 2.0 * pQq[A][n1 + n2 + n3][3] * C(pQq[B][n4][1] * pQq[B][n5][1] * pQq[B][n6][1]) - 2.0 * pQq[A][n1 + n2 + n3][3] * C(pQq[B][n4 + n5][2] * pQq[B][n6][1]) - 2.0 * pQq[A][n1 + n2 + n3][3] * C(pQq[B][n4 + n6][2] * pQq[B][n5][1]) - 2.0 * pQq[A][n1 + n2 + n3][3] * C(pQq[B][n5 + n6][2] * pQq[B][n4][1]) + 4.0 * pQq[A][n1 + n2 + n3][3] * C(pQq[B][n4 + n5 + n6][3]); + return Qa[n1][1] * Qa[n2][1] * Qa[n3][1] * C(Qb[n4][1] * Qb[n5][1] * Qb[n6][1]) - Qa[n1][1] * Qa[n2][1] * Qa[n3][1] * C(Qb[n4 + n5][2] * Qb[n6][1]) - Qa[n1][1] * Qa[n2][1] * Qa[n3][1] * C(Qb[n4 + n6][2] * Qb[n5][1]) - Qa[n1][1] * Qa[n2][1] * Qa[n3][1] * C(Qb[n5 + n6][2] * Qb[n4][1]) + 2.0 * Qa[n1][1] * Qa[n2][1] * Qa[n3][1] * C(Qb[n4 + n5 + n6][3]) - Qa[n1 + n2][2] * Qa[n3][1] * C(Qb[n4][1] * Qb[n5][1] * Qb[n6][1]) + Qa[n1 + n2][2] * Qa[n3][1] * C(Qb[n4 + n5][2] * Qb[n6][1]) + Qa[n1 + n2][2] * Qa[n3][1] * C(Qb[n4 + n6][2] * Qb[n5][1]) + Qa[n1 + n2][2] * Qa[n3][1] * C(Qb[n5 + n6][2] * Qb[n4][1]) - 2.0 * Qa[n1 + n2][2] * Qa[n3][1] * C(Qb[n4 + n5 + n6][3]) - Qa[n1 + n3][2] * Qa[n2][1] * C(Qb[n4][1] * Qb[n5][1] * Qb[n6][1]) + Qa[n1 + n3][2] * Qa[n2][1] * C(Qb[n4 + n5][2] * Qb[n6][1]) + Qa[n1 + n3][2] * Qa[n2][1] * C(Qb[n4 + n6][2] * Qb[n5][1]) + Qa[n1 + n3][2] * Qa[n2][1] * C(Qb[n5 + n6][2] * Qb[n4][1]) - 2.0 * Qa[n1 + n3][2] * Qa[n2][1] * C(Qb[n4 + n5 + n6][3]) - Qa[n2 + n3][2] * Qa[n1][1] * C(Qb[n4][1] * Qb[n5][1] * Qb[n6][1]) + Qa[n2 + n3][2] * Qa[n1][1] * C(Qb[n4 + n5][2] * Qb[n6][1]) + Qa[n2 + n3][2] * Qa[n1][1] * C(Qb[n4 + n6][2] * Qb[n5][1]) + Qa[n2 + n3][2] * Qa[n1][1] * C(Qb[n5 + n6][2] * Qb[n4][1]) - 2.0 * Qa[n2 + n3][2] * Qa[n1][1] * C(Qb[n4 + n5 + n6][3]) + 2.0 * Qa[n1 + n2 + n3][3] * C(Qb[n4][1] * Qb[n5][1] * Qb[n6][1]) - 2.0 * Qa[n1 + n2 + n3][3] * C(Qb[n4 + n5][2] * Qb[n6][1]) - 2.0 * Qa[n1 + n2 + n3][3] * C(Qb[n4 + n6][2] * Qb[n5][1]) - 2.0 * Qa[n1 + n2 + n3][3] * C(Qb[n5 + n6][2] * Qb[n4][1]) + 4.0 * Qa[n1 + n2 + n3][3] * C(Qb[n4 + n5 + n6][3]); } TComplex JFFlucAnalysis::Q(int n, int p) @@ -338,6 +116,13 @@ TComplex JFFlucAnalysis::Q(int n, int p) return n >= 0 ? pqvecs->QvectorQC[n][p] : C(pqvecs->QvectorQC[-n][p]); } +TComplex JFFlucAnalysis::Q(const JQVectorsT& qvecs, int n, int p) +{ + // Return QvectorQC + // Q{-n, p} = Q{n, p}* + return n >= 0 ? qvecs.QvectorQC[n][p] : C(qvecs.QvectorQC[-n][p]); +} + TComplex JFFlucAnalysis::Two(int n1, int n2) { // two-particle correlation @@ -346,42 +131,45 @@ TComplex JFFlucAnalysis::Two(int n1, int n2) TComplex JFFlucAnalysis::Four(int n1, int n2, int n3, int n4) { - return Q(n1, 1) * Q(n2, 1) * Q(n3, 1) * Q(n4, 1) - Q(n1 + n2, 2) * Q(n3, 1) * Q(n4, 1) - Q(n2, 1) * Q(n1 + n3, 2) * Q(n4, 1) - Q(n1, 1) * Q(n2 + n3, 2) * Q(n4, 1) + 2. * Q(n1 + n2 + n3, 3) * Q(n4, 1) - Q(n2, 1) * Q(n3, 1) * Q(n1 + n4, 2) + Q(n2 + n3, 2) * Q(n1 + n4, 2) - Q(n1, 1) * Q(n3, 1) * Q(n2 + n4, 2) + Q(n1 + n3, 2) * Q(n2 + n4, 2) + 2. * Q(n3, 1) * Q(n1 + n2 + n4, 3) - Q(n1, 1) * Q(n2, 1) * Q(n3 + n4, 2) + Q(n1 + n2, 2) * Q(n3 + n4, 2) + 2. * Q(n2, 1) * Q(n1 + n3 + n4, 3) + 2. * Q(n1, 1) * Q(n2 + n3 + n4, 3) - 6. * Q(n1 + n2 + n3 + n4, 4); } -#undef C -//________________________________________________________________________ -void JFFlucAnalysis::UserExec(Option_t* /*popt*/) +TComplex JFFlucAnalysis::TwoDiff(int n1, int n2) { - for (UInt_t ih = 2; ih < kNH; ih++) { - fh_cos_n_phi[ih][fCBin]->Fill(pqvecs->QvectorQC[ih][1].Re() / pqvecs->QvectorQC[0][1].Re()); - fh_sin_n_phi[ih][fCBin]->Fill(pqvecs->QvectorQC[ih][1].Im() / pqvecs->QvectorQC[0][1].Re()); - // - // - Double_t psi = pqvecs->QvectorQC[ih][1].Theta(); - fh_psi_n[ih][fCBin]->Fill(psi); - fh_cos_n_psi_n[ih][fCBin]->Fill(TMath::Cos((Double_t)ih * psi)); - fh_sin_n_psi_n[ih][fCBin]->Fill(TMath::Sin((Double_t)ih * psi)); - } +#define dp(n, p) Q(*pqvecs, n, p) // POI +#define dQ(n, p) Q(*pqvecsRef, n, p) // REF +#define dq(n, p) dp(n, p) //(dp(n,p)+dQ(n,p)) //POI+REF in narrow bin. Since there is no mass for ref, q = POI + // #define dq(n,p) (dp(n,p)+dQ(n,p)) //POI+REF in narrow bin. Since there is no mass for ref, q = POI + return dp(n1, 1) * dQ(n2, 1) - dq(n1 + n2, 2); +} + +TComplex JFFlucAnalysis::FourDiff(int n1, int n2, int n3, int n4) +{ + return dp(n1, 1) * dQ(n2, 1) * dQ(n3, 1) * dQ(n4, 1) - dq(n1 + n2, 2) * dQ(n3, 1) * dQ(n4, 1) - dq(n1 + n3, 2) * dQ(n2, 1) * dQ(n4, 1) - dp(n1, 1) * dQ(n2 + n3, 2) * dQ(n4, 1) + 2. * dq(n1 + n2 + n3, 3) * dQ(n4, 1) - dQ(n2, 1) * dQ(n3, 1) * dq(n1 + n4, 2) + dQ(n2 + n3, 2) * dq(n1 + n4, 2) - dp(n1, 1) * dQ(n3, 1) * dQ(n2 + n4, 2) + dq(n1 + n3, 2) * dQ(n2 + n4, 2) + 2. * dQ(n3, 1) * dq(n1 + n2 + n4, 3) - dp(n1, 1) * dQ(n2, 1) * dQ(n3 + n4, 2) + dq(n1 + n2, 2) * dQ(n3 + n4, 2) + 2. * dQ(n2, 1) * dq(n1 + n3 + n4, 3) + 2. * dp(n1, 1) * dQ(n2 + n3 + n4, 3) - 6. * dq(n1 + n2 + n3 + n4, 4); +} - Double_t vn2[kNH][nKL]; - Double_t vn2_vn2[kNH][nKL][kNH][nKL]; +#undef dp +#undef dQ +#undef dq +#undef C +//________________________________________________________________________ +void JFFlucAnalysis::UserExec(Option_t* /*popt*/) // NOLINT(readability/casting) false positive: https://github.com/cpplint/cpplint/issues/131 +{ TComplex corr[kNH][nKL]; TComplex ncorr[kNH][nKL]; TComplex ncorr2[kNH][nKL][kcNH][nKL]; - const TComplex(*pQq)[kNH][nKL] = pqvecs->QvectorQCgap; - for (UInt_t i = 0; i < 2; ++i) { if ((subeventMask & (1 << i)) == 0) continue; - Double_t ref_2p = TwoGap(pQq, i, 0, 0).Re(); - Double_t ref_3p = ThreeGap(pQq, i, 0, 0, 0).Re(); - Double_t ref_4p = FourGap22(pQq, i, 0, 0, 0, 0).Re(); - Double_t ref_4pB = FourGap13(pQq, i, 0, 0, 0, 0).Re(); - Double_t ref_6p = SixGap33(pQq, i, 0, 0, 0, 0, 0, 0).Re(); + decltype(pqvecs->QvectorQCgap[i])& Qa = pqvecs->QvectorQCgap[i]; // this is for one differential bin only. + decltype(pqvecs->QvectorQCgap[1 - i])& Qb = (pqvecsRef ? pqvecsRef : pqvecs)->QvectorQCgap[1 - i]; // A & B subevents from POI and REF, when given + Double_t ref_2p = TwoGap(Qa, Qb, 0, 0).Re(); + Double_t ref_3p = ThreeGap(Qa, Qb, 0, 0, 0).Re(); + Double_t ref_4p = FourGap22(Qa, Qb, 0, 0, 0, 0).Re(); + Double_t ref_4pB = FourGap13(Qa, Qb, 0, 0, 0, 0).Re(); + Double_t ref_6p = SixGap33(Qa, Qb, 0, 0, 0, 0, 0, 0).Re(); Double_t ebe_2p_weight = 1.0; Double_t ebe_3p_weight = 1.0; @@ -406,31 +194,31 @@ void JFFlucAnalysis::UserExec(Option_t* /*popt*/) if (flags & kFlucEbEWeighting) { for (UInt_t ik = 3; ik < 2 * nKL; ik++) { double dk = static_cast(ik); - ref_2Np[ik] = ref_2Np[ik - 1] * std::max(pQq[A][0][1].Re() - dk, 1.0) * std::max(pQq[B][0][1].Re() - dk, 1.0); - ebe_2Np_weight[ik] = ebe_2Np_weight[ik - 1] * std::max(pQq[A][0][1].Re() - dk, 1.0) * std::max(pQq[B][0][1].Re() - dk, 1.0); + ref_2Np[ik] = ref_2Np[ik - 1] * std::max(Qa[0][1].Re() - dk, 1.0) * std::max(Qb[0][1].Re() - dk, 1.0); + ebe_2Np_weight[ik] = ebe_2Np_weight[ik - 1] * std::max(Qa[0][1].Re() - dk, 1.0) * std::max(Qb[0][1].Re() - dk, 1.0); } } else { for (UInt_t ik = 3; ik < 2 * nKL; ik++) { double dk = static_cast(ik); - ref_2Np[ik] = ref_2Np[ik - 1] * std::max(pQq[A][0][1].Re() - dk, 1.0) * std::max(pQq[B][0][1].Re() - dk, 1.0); + ref_2Np[ik] = ref_2Np[ik - 1] * std::max(Qa[0][1].Re() - dk, 1.0) * std::max(Qb[0][1].Re() - dk, 1.0); ebe_2Np_weight[ik] = 1.0; } } for (UInt_t ih = 2; ih < kNH; ih++) { - corr[ih][1] = TwoGap(pQq, i, ih, ih); + corr[ih][1] = TwoGap(Qa, Qb, ih, ih); for (UInt_t ik = 2; ik < nKL; ik++) corr[ih][ik] = corr[ih][ik - 1] * corr[ih][1]; // TComplex::Power(corr[ih][1],ik); ncorr[ih][1] = corr[ih][1]; - ncorr[ih][2] = FourGap22(pQq, i, ih, ih, ih, ih); - ncorr[ih][3] = SixGap33(pQq, i, ih, ih, ih, ih, ih, ih); + ncorr[ih][2] = FourGap22(Qa, Qb, ih, ih, ih, ih); + ncorr[ih][3] = SixGap33(Qa, Qb, ih, ih, ih, ih, ih, ih); for (UInt_t ik = 4; ik < nKL; ik++) ncorr[ih][ik] = corr[ih][ik]; // for 8,...-particle correlations, ignore the autocorrelation / weight dependency for now for (UInt_t ihh = 2; ihh < kcNH; ihh++) { - ncorr2[ih][1][ihh][1] = FourGap22(pQq, i, ih, ihh, ih, ihh); - ncorr2[ih][1][ihh][2] = SixGap33(pQq, i, ih, ihh, ihh, ih, ihh, ihh); - ncorr2[ih][2][ihh][1] = SixGap33(pQq, i, ih, ih, ihh, ih, ih, ihh); + ncorr2[ih][1][ihh][1] = FourGap22(Qa, Qb, ih, ihh, ih, ihh); + ncorr2[ih][1][ihh][2] = SixGap33(Qa, Qb, ih, ihh, ihh, ih, ihh, ihh); + ncorr2[ih][2][ihh][1] = SixGap33(Qa, Qb, ih, ih, ihh, ih, ih, ihh); for (UInt_t ik = 2; ik < nKL; ik++) for (UInt_t ikk = 2; ikk < nKL; ikk++) ncorr2[ih][ik][ihh][ikk] = ncorr[ih][ik] * ncorr[ihh][ikk]; @@ -439,117 +227,120 @@ void JFFlucAnalysis::UserExec(Option_t* /*popt*/) for (UInt_t ih = 2; ih < kNH; ih++) { for (UInt_t ik = 1; ik < nKL; ik++) { // 2k(0) =1, 2k(1) =2, 2k(2)=4.... - vn2[ih][ik] = corr[ih][ik].Re() / ref_2Np[ik - 1]; - fh_vn[ih][ik][fCBin]->Fill(vn2[ih][ik], ebe_2Np_weight[ik - 1]); - fh_vna[ih][ik][fCBin]->Fill(ncorr[ih][ik].Re() / ref_2Np[ik - 1], ebe_2Np_weight[ik - 1]); + // vn2[ih][ik] = corr[ih][ik].Re() / ref_2Np[ik - 1]; + // fh_vn[ih][ik][fCBin]->Fill(vn2[ih][ik], ebe_2Np_weight[ik - 1]); + // fh_vna[ih][ik][fCBin]->Fill(ncorr[ih][ik].Re() / ref_2Np[ik - 1], ebe_2Np_weight[ik - 1]); + phs[HIST_THN_SPARSE_VN]->Fill(fCent, fAvgInvariantMass, ih, ik, ncorr[ih][ik].Re() / ref_2Np[ik - 1], ebe_2Np_weight[ik - 1]); for (UInt_t ihh = 2; ihh < kcNH; ihh++) { for (UInt_t ikk = 1; ikk < nKL; ikk++) { - vn2_vn2[ih][ik][ihh][ikk] = ncorr2[ih][ik][ihh][ikk] / ref_2Np[ik + ikk - 1]; - fh_vn_vn[ih][ik][ihh][ikk][fCBin]->Fill(vn2_vn2[ih][ik][ihh][ikk], ebe_2Np_weight[ik + ikk - 1]); + Double_t vn2_vn2 = ncorr2[ih][ik][ihh][ikk] / ref_2Np[ik + ikk - 1]; + phs[HIST_THN_SPARSE_VN_VN]->Fill(fCent, fAvgInvariantMass, ih, ik, ihh, ikk, vn2_vn2, ebe_2Np_weight[ik + ikk - 1]); } } } } //************************************************************************ - TComplex V4V2star_2 = pQq[A][4][1] * pQq[B][2][1] * pQq[B][2][1]; - TComplex V4V2starv2_2 = V4V2star_2 * corr[2][1] / ref_2Np[0]; // vn[2][1] - TComplex V4V2starv2_4 = V4V2star_2 * corr[2][2] / ref_2Np[1]; // vn2[2][2] - TComplex V5V2starV3starv2_2 = pQq[A][5][1] * pQq[B][2][1] * pQq[B][3][1] * corr[2][1] / ref_2Np[0]; // vn2[2][1] - TComplex V5V2starV3star = pQq[A][5][1] * pQq[B][2][1] * pQq[B][3][1]; + TComplex V4V2star_2 = Qa[4][1] * Qb[2][1] * Qb[2][1]; + TComplex V4V2starv2_2 = V4V2star_2 * corr[2][1] / ref_2Np[0]; // vn[2][1] + TComplex V4V2starv2_4 = V4V2star_2 * corr[2][2] / ref_2Np[1]; // vn2[2][2] + TComplex V5V2starV3starv2_2 = Qa[5][1] * Qb[2][1] * Qb[3][1] * corr[2][1] / ref_2Np[0]; // vn2[2][1] + TComplex V5V2starV3star = Qa[5][1] * Qb[2][1] * Qb[3][1]; TComplex V5V2starV3startv3_2 = V5V2starV3star * corr[3][1] / ref_2Np[0]; // vn2[3][1] - TComplex V6V2star_3 = pQq[A][6][1] * pQq[B][2][1] * pQq[B][2][1] * pQq[B][2][1]; - TComplex V6V3star_2 = pQq[A][6][1] * pQq[B][3][1] * pQq[B][3][1]; - TComplex V6V2starV4star = pQq[A][6][1] * pQq[B][2][1] * pQq[B][4][1]; - TComplex V7V2star_2V3star = pQq[A][7][1] * pQq[B][2][1] * pQq[B][2][1] * pQq[B][3][1]; - TComplex V7V2starV5star = pQq[A][7][1] * pQq[B][2][1] * pQq[B][5][1]; - TComplex V7V3starV4star = pQq[A][7][1] * pQq[B][3][1] * pQq[B][4][1]; - TComplex V8V2starV3star_2 = pQq[A][8][1] * pQq[B][2][1] * pQq[B][3][1] * pQq[B][3][1]; - TComplex V8V2star_4 = pQq[A][8][1] * TComplex::Power(pQq[B][2][1], 4); + TComplex V6V2star_3 = Qa[6][1] * Qb[2][1] * Qb[2][1] * Qb[2][1]; + TComplex V6V3star_2 = Qa[6][1] * Qb[3][1] * Qb[3][1]; + TComplex V6V2starV4star = Qa[6][1] * Qb[2][1] * Qb[4][1]; + TComplex V7V2star_2V3star = Qa[7][1] * Qb[2][1] * Qb[2][1] * Qb[3][1]; + TComplex V7V2starV5star = Qa[7][1] * Qb[2][1] * Qb[5][1]; + TComplex V7V3starV4star = Qa[7][1] * Qb[3][1] * Qb[4][1]; + TComplex V8V2starV3star_2 = Qa[8][1] * Qb[2][1] * Qb[3][1] * Qb[3][1]; + TComplex V8V2star_4 = Qa[8][1] * TComplex::Power(Qb[2][1], 4); // New correlators (Modified by You's correction term for self-correlations) - TComplex nV4V2star_2 = ThreeGap(pQq, i, 4, 2, 2) / ref_3p; - TComplex nV5V2starV3star = ThreeGap(pQq, i, 5, 2, 3) / ref_3p; - TComplex nV6V2star_3 = FourGap13(pQq, i, 6, 2, 2, 2) / ref_4pB; - TComplex nV6V3star_2 = ThreeGap(pQq, i, 6, 3, 3) / ref_3p; - TComplex nV6V2starV4star = ThreeGap(pQq, i, 6, 2, 4) / ref_3p; - TComplex nV7V2star_2V3star = FourGap13(pQq, i, 7, 2, 2, 3) / ref_4pB; - TComplex nV7V2starV5star = ThreeGap(pQq, i, 7, 2, 5) / ref_3p; - TComplex nV7V3starV4star = ThreeGap(pQq, i, 7, 3, 4) / ref_3p; - TComplex nV8V2starV3star_2 = FourGap13(pQq, i, 8, 2, 3, 3) / ref_4pB; - - TComplex nV4V4V2V2 = FourGap22(pQq, i, 4, 2, 4, 2) / ref_4p; - TComplex nV3V3V2V2 = FourGap22(pQq, i, 3, 2, 3, 2) / ref_4p; - TComplex nV5V5V2V2 = FourGap22(pQq, i, 5, 2, 5, 2) / ref_4p; - TComplex nV5V5V3V3 = FourGap22(pQq, i, 5, 3, 5, 3) / ref_4p; - TComplex nV4V4V3V3 = FourGap22(pQq, i, 4, 3, 4, 3) / ref_4p; - - fh_correlator[0][fCBin]->Fill(V4V2starv2_2.Re()); - fh_correlator[1][fCBin]->Fill(V4V2starv2_4.Re()); - fh_correlator[2][fCBin]->Fill(V4V2star_2.Re(), ebe_3p_weight); // added 2015.3.18 - fh_correlator[3][fCBin]->Fill(V5V2starV3starv2_2.Re()); - fh_correlator[4][fCBin]->Fill(V5V2starV3star.Re(), ebe_3p_weight); - fh_correlator[5][fCBin]->Fill(V5V2starV3startv3_2.Re()); - fh_correlator[6][fCBin]->Fill(V6V2star_3.Re(), ebe_4p_weightB); - fh_correlator[7][fCBin]->Fill(V6V3star_2.Re(), ebe_3p_weight); - fh_correlator[8][fCBin]->Fill(V7V2star_2V3star.Re(), ebe_4p_weightB); - - fh_correlator[9][fCBin]->Fill(nV4V2star_2.Re(), ebe_3p_weight); // added 2015.6.10 - fh_correlator[10][fCBin]->Fill(nV5V2starV3star.Re(), ebe_3p_weight); - fh_correlator[11][fCBin]->Fill(nV6V3star_2.Re(), ebe_3p_weight); + TComplex nV4V2star_2 = ThreeGap(Qa, Qb, 4, 2, 2) / ref_3p; + TComplex nV5V2starV3star = ThreeGap(Qa, Qb, 5, 2, 3) / ref_3p; + TComplex nV6V2star_3 = FourGap13(Qa, Qb, 6, 2, 2, 2) / ref_4pB; + TComplex nV6V3star_2 = ThreeGap(Qa, Qb, 6, 3, 3) / ref_3p; + TComplex nV6V2starV4star = ThreeGap(Qa, Qb, 6, 2, 4) / ref_3p; + TComplex nV7V2star_2V3star = FourGap13(Qa, Qb, 7, 2, 2, 3) / ref_4pB; + TComplex nV7V2starV5star = ThreeGap(Qa, Qb, 7, 2, 5) / ref_3p; + TComplex nV7V3starV4star = ThreeGap(Qa, Qb, 7, 3, 4) / ref_3p; + TComplex nV8V2starV3star_2 = FourGap13(Qa, Qb, 8, 2, 3, 3) / ref_4pB; + + TComplex nV4V4V2V2 = FourGap22(Qa, Qb, 4, 2, 4, 2) / ref_4p; + TComplex nV3V3V2V2 = FourGap22(Qa, Qb, 3, 2, 3, 2) / ref_4p; + TComplex nV5V5V2V2 = FourGap22(Qa, Qb, 5, 2, 5, 2) / ref_4p; + TComplex nV5V5V3V3 = FourGap22(Qa, Qb, 5, 3, 5, 3) / ref_4p; + TComplex nV4V4V3V3 = FourGap22(Qa, Qb, 4, 3, 4, 3) / ref_4p; + + pht[HIST_THN_V4V2starv2_2]->Fill(fCent, fAvgInvariantMass, V4V2starv2_2.Re()); + pht[HIST_THN_V4V2starv2_4]->Fill(fCent, fAvgInvariantMass, V4V2starv2_4.Re()); + pht[HIST_THN_V4V2star_2]->Fill(fCent, fAvgInvariantMass, V4V2star_2.Re(), ebe_3p_weight); // added 2015.3.18 + pht[HIST_THN_V5V2starV3starv2_2]->Fill(fCent, fAvgInvariantMass, V5V2starV3starv2_2.Re()); + pht[HIST_THN_V5V2starV3star]->Fill(fCent, fAvgInvariantMass, V5V2starV3star.Re(), ebe_3p_weight); + pht[HIST_THN_V5V2starV3startv3_2]->Fill(fCent, fAvgInvariantMass, V5V2starV3startv3_2.Re()); + pht[HIST_THN_V6V2star_3]->Fill(fCent, fAvgInvariantMass, V6V2star_3.Re(), ebe_4p_weightB); + pht[HIST_THN_V6V3star_2]->Fill(fCent, fAvgInvariantMass, V6V3star_2.Re(), ebe_3p_weight); + pht[HIST_THN_V7V2star_2V3star]->Fill(fCent, fAvgInvariantMass, V7V2star_2V3star.Re(), ebe_4p_weightB); + + pht[HIST_THN_V4V2star_2]->Fill(fCent, fAvgInvariantMass, nV4V2star_2.Re(), ebe_3p_weight); // added 2015.6.10 + pht[HIST_THN_V5V2starV3star]->Fill(fCent, fAvgInvariantMass, nV5V2starV3star.Re(), ebe_3p_weight); + pht[HIST_THN_V6V3star_2]->Fill(fCent, fAvgInvariantMass, nV6V3star_2.Re(), ebe_3p_weight); // use this to avoid self-correlation 4p correlation (2 particles from A, 2 particles from B) -> MA(MA-1)MB(MB-1) : evt weight.. - fh_correlator[12][fCBin]->Fill(nV4V4V2V2.Re(), ebe_2Np_weight[1]); - fh_correlator[13][fCBin]->Fill(nV3V3V2V2.Re(), ebe_2Np_weight[1]); + pht[HIST_THN_nV4V4V2V2]->Fill(fCent, fAvgInvariantMass, nV4V4V2V2.Re(), ebe_2Np_weight[1]); + pht[HIST_THN_nV3V3V2V2]->Fill(fCent, fAvgInvariantMass, nV3V3V2V2.Re(), ebe_2Np_weight[1]); - fh_correlator[14][fCBin]->Fill(nV5V5V2V2.Re(), ebe_2Np_weight[1]); - fh_correlator[15][fCBin]->Fill(nV5V5V3V3.Re(), ebe_2Np_weight[1]); - fh_correlator[16][fCBin]->Fill(nV4V4V3V3.Re(), ebe_2Np_weight[1]); + pht[HIST_THN_nV5V5V2V2]->Fill(fCent, fAvgInvariantMass, nV5V5V2V2.Re(), ebe_2Np_weight[1]); + pht[HIST_THN_nV5V5V3V3]->Fill(fCent, fAvgInvariantMass, nV5V5V3V3.Re(), ebe_2Np_weight[1]); + pht[HIST_THN_nV4V4V3V3]->Fill(fCent, fAvgInvariantMass, nV4V4V3V3.Re(), ebe_2Np_weight[1]); // higher order correlators, added 2017.8.10 - fh_correlator[17][fCBin]->Fill(V8V2starV3star_2.Re(), ebe_4p_weightB); - fh_correlator[18][fCBin]->Fill(V8V2star_4.Re()); // 5p weight - fh_correlator[19][fCBin]->Fill(nV6V2star_3.Re(), ebe_4p_weightB); - fh_correlator[20][fCBin]->Fill(nV7V2star_2V3star.Re(), ebe_4p_weightB); - fh_correlator[21][fCBin]->Fill(nV8V2starV3star_2.Re(), ebe_4p_weightB); - - fh_correlator[22][fCBin]->Fill(V6V2starV4star.Re(), ebe_3p_weight); - fh_correlator[23][fCBin]->Fill(V7V2starV5star.Re(), ebe_3p_weight); - fh_correlator[24][fCBin]->Fill(V7V3starV4star.Re(), ebe_3p_weight); - fh_correlator[25][fCBin]->Fill(nV6V2starV4star.Re(), ebe_3p_weight); - fh_correlator[26][fCBin]->Fill(nV7V2starV5star.Re(), ebe_3p_weight); - fh_correlator[27][fCBin]->Fill(nV7V3starV4star.Re(), ebe_3p_weight); - } + pht[HIST_THN_V8V2starV3star_2]->Fill(fCent, fAvgInvariantMass, V8V2starV3star_2.Re(), ebe_4p_weightB); + pht[HIST_THN_V8V2star_4]->Fill(fCent, fAvgInvariantMass, V8V2star_4.Re()); // 5p weight + pht[HIST_THN_V6V2star_3]->Fill(fCent, fAvgInvariantMass, nV6V2star_3.Re(), ebe_4p_weightB); + pht[HIST_THN_V7V2star_2V3star]->Fill(fCent, fAvgInvariantMass, nV7V2star_2V3star.Re(), ebe_4p_weightB); + pht[HIST_THN_V8V2starV3star_2]->Fill(fCent, fAvgInvariantMass, nV8V2starV3star_2.Re(), ebe_4p_weightB); + + pht[HIST_THN_V6V2starV4star]->Fill(fCent, fAvgInvariantMass, V6V2starV4star.Re(), ebe_3p_weight); + pht[HIST_THN_V7V2starV5star]->Fill(fCent, fAvgInvariantMass, V7V2starV5star.Re(), ebe_3p_weight); + pht[HIST_THN_V7V3starV4star]->Fill(fCent, fAvgInvariantMass, V7V3starV4star.Re(), ebe_3p_weight); + pht[HIST_THN_V6V2starV4star]->Fill(fCent, fAvgInvariantMass, nV6V2starV4star.Re(), ebe_3p_weight); + pht[HIST_THN_V7V2starV5star]->Fill(fCent, fAvgInvariantMass, nV7V2starV5star.Re(), ebe_3p_weight); + pht[HIST_THN_V7V3starV4star]->Fill(fCent, fAvgInvariantMass, nV7V3starV4star.Re(), ebe_3p_weight); + + Double_t event_weight_two_gap = 1.0; + if (flags & kFlucEbEWeighting) { + event_weight_two_gap = (Qa[0][1] * Qb[0][1]).Re(); + } - enum { kSubA, - kSubB, - kNSub }; + for (UInt_t ih = 2; ih < kNH; ih++) { + TComplex sctwoGap = (Qa[ih][1] * TComplex::Conjugate(Qb[ih][1])) / (Qa[0][1] * Qb[0][1]).Re(); + pht[HIST_THN_SC_with_QC_2corr_gap]->Fill(fCent, fAvgInvariantMass, ih, sctwoGap.Re(), event_weight_two_gap); + } + } + auto four = [&](int a, int b, int c, int d) -> TComplex { return pqvecsRef ? FourDiff(a, b, c, d) : Four(a, b, c, d); }; + auto two = [&](int a, int b) -> TComplex { return pqvecsRef ? TwoDiff(a, b) : Two(a, b); }; Double_t event_weight_four = 1.0; Double_t event_weight_two = 1.0; - Double_t event_weight_two_gap = 1.0; if (flags & kFlucEbEWeighting) { - event_weight_four = Four(0, 0, 0, 0).Re(); - event_weight_two = Two(0, 0).Re(); - event_weight_two_gap = (pqvecs->QvectorQCgap[kSubA][0][1] * pqvecs->QvectorQCgap[kSubB][0][1]).Re(); + event_weight_four = four(0, 0, 0, 0).Re(); + event_weight_two = two(0, 0).Re(); } for (UInt_t ih = 2; ih < kNH; ih++) { - for (UInt_t ihh = 2, mm = (ih < kcNH ? ih : kcNH); ihh < mm; ihh++) { - TComplex scfour = Four(ih, ihh, -ih, -ihh) / Four(0, 0, 0, 0).Re(); - - fh_SC_with_QC_4corr[ih][ihh][fCBin]->Fill(scfour.Re(), event_weight_four); + for (UInt_t ihh = 2, mm = (ih < kcNH ? ih : static_cast(kcNH)); ihh < mm; ihh++) { + TComplex scfour = four(ih, ihh, -ih, -ihh) / four(0, 0, 0, 0).Re(); + pht[HIST_THN_SC_with_QC_4corr]->Fill(fCent, fAvgInvariantMass, ih, ihh, scfour.Re(), event_weight_four); } - - TComplex sctwo = Two(ih, -ih) / Two(0, 0).Re(); - fh_SC_with_QC_2corr[ih][fCBin]->Fill(sctwo.Re(), event_weight_two); - - TComplex sctwoGap = (pqvecs->QvectorQCgap[kSubA][ih][1] * TComplex::Conjugate(pqvecs->QvectorQCgap[kSubB][ih][1])) / (pqvecs->QvectorQCgap[kSubA][0][1] * pqvecs->QvectorQCgap[kSubB][0][1]).Re(); - fh_SC_with_QC_2corr_gap[ih][fCBin]->Fill(sctwoGap.Re(), event_weight_two_gap); + TComplex sctwo = two(ih, -ih) / two(0, 0).Re(); + pht[HIST_THN_SC_with_QC_2corr]->Fill(fCent, fAvgInvariantMass, ih, sctwo.Re(), event_weight_two); } } //________________________________________________________________________ -void JFFlucAnalysis::Terminate(Option_t* /*popt*/) +void JFFlucAnalysis::Terminate(Option_t* /*popt*/) // NOLINT(readability/casting) false positive: https://github.com/cpplint/cpplint/issues/131 { + // } diff --git a/PWGCF/JCorran/Core/JFFlucAnalysis.h b/PWGCF/JCorran/Core/JFFlucAnalysis.h index 57fddda80b5..01589a09849 100644 --- a/PWGCF/JCorran/Core/JFFlucAnalysis.h +++ b/PWGCF/JCorran/Core/JFFlucAnalysis.h @@ -16,72 +16,94 @@ #define PWGCF_JCORRAN_CORE_JFFLUCANALYSIS_H_ #include -#include "JHistManager.h" #include "JQVectors.h" #include -#include +#include +#include +#include +#include -class JFFlucAnalysis +class JFFlucAnalysis : public TNamed { - public: + protected: JFFlucAnalysis(); explicit JFFlucAnalysis(const char* name); explicit JFFlucAnalysis(const JFFlucAnalysis& a); // not implemented JFFlucAnalysis& operator=(const JFFlucAnalysis& ap); // not implemented - + public: ~JFFlucAnalysis(); void UserCreateOutputObjects(); void Init(); TComplex Q(int n, int p); TComplex Two(int n1, int n2); TComplex Four(int n1, int n2, int n3, int n4); + TComplex TwoDiff(int n1, int n2); + TComplex FourDiff(int n1, int n2, int n3, int n4); void UserExec(Option_t* option); void Terminate(Option_t*); - inline void SetEventCentralityAndBin(float cent, UInt_t cbin) - { - fCent = cent; - fCBin = cbin; - } + inline void SetEventCentrality(float cent) { fCent = cent; } inline float GetEventCentrality() const { return fCent; } inline void SetEventImpactParameter(float ip) { fImpactParameter = ip; } - inline void SetEventVertex(const Double_t* vtx) { fVertex = vtx; } - inline void SetEtaRange(Double_t eta_min, Double_t eta_max) - { - fEta_min = eta_min; - fEta_max = eta_max; - } - inline void SetEventTracksQA(unsigned int tpc, unsigned int glb) - { - fTPCtrks = static_cast(tpc); - fGlbtrks = static_cast(glb); - } - inline void SetEventFB32TracksQA(unsigned int fb32, unsigned int fb32tof) - { - fFB32trks = static_cast(fb32); - fFB32TOFtrks = static_cast(fb32tof); - } + inline void SetEventVertex(float zvertex) { fVertex = zvertex; } + inline void SetAverageInvariantMass(float mass) { fAvgInvariantMass = mass; } enum SubEvent { kSubEvent_A = 0x1, kSubEvent_B = 0x2 }; - inline void SelectSubevents(UInt_t _subeventMask) - { - subeventMask = _subeventMask; - } - // set the number of bins before initialization (UserCreateOutputObjects) - inline void SetNumBins(UInt_t _numBins) - { - numBins = _numBins; - } + inline void SelectSubevents(UInt_t _subeventMask) { subeventMask = _subeventMask; } + enum HIST_TH1 { + HIST_TH1_CENTRALITY, + HIST_TH1_IMPACTPARAM, + HIST_TH1_ZVERTEX, + HIST_TH1_COUNT + }; + enum HIST_THN { + HIST_THN_PHIETAZ, + HIST_THN_PTETA, + HIST_THN_PHIETA, + HIST_THN_SC_with_QC_4corr, + HIST_THN_SC_with_QC_2corr, + HIST_THN_SC_with_QC_2corr_gap, + HIST_THN_V4V2star_2, + HIST_THN_V4V2starv2_2, + HIST_THN_V4V2starv2_4, + HIST_THN_V5V2starV3starv2_2, + HIST_THN_V5V2starV3star, + HIST_THN_V5V2starV3startv3_2, + HIST_THN_V6V2star_3, + HIST_THN_V6V3star_2, + HIST_THN_V6V2starV4star, + HIST_THN_V7V2star_2V3star, + HIST_THN_V7V2starV5star, + HIST_THN_V7V3starV4star, + HIST_THN_V8V2starV3star_2, + HIST_THN_V8V2star_4, + HIST_THN_nV4V2star_2, + HIST_THN_nV5V2starV3star, + HIST_THN_nV6V2star_3, + HIST_THN_nV6V3star_2, + HIST_THN_nV6V2starV4star, + HIST_THN_nV7V2star_2V3star, + HIST_THN_nV7V2starV5star, + HIST_THN_nV7V3starV4star, + HIST_THN_nV8V2starV3star_2, + HIST_THN_nV4V4V2V2, + HIST_THN_nV3V3V2V2, + HIST_THN_nV5V5V2V2, + HIST_THN_nV5V5V3V3, + HIST_THN_nV4V4V3V3, + HIST_THN_COUNT + }; + enum HIST_THN_SPARSE { + HIST_THN_SPARSE_VN, + HIST_THN_SPARSE_VN_VN, + HIST_THN_SPARSE_COUNT + }; enum { - kFlucPhiCorrection = 0x2, - kFlucEbEWeighting = 0x4 + kFlucEbEWeighting = 0x1 }; - inline void AddFlags(UInt_t _flags) - { - flags |= _flags; - } + inline void AddFlags(UInt_t _flags) { flags |= _flags; } enum { kH0, kH1, @@ -104,124 +126,66 @@ class JFFlucAnalysis kK4, nKL }; // order using JQVectorsT = JQVectors; - inline void SetJQVectors(const JQVectorsT* _pqvecs) { pqvecs = _pqvecs; } + TComplex Q(const JQVectorsT& qvecs, int n, int p); + inline void SetJQVectors(const JQVectorsT* _pqvecs) + { + pqvecs = _pqvecs; + pqvecsRef = 0; + } + inline void SetJQVectors(const JQVectorsT* _pqvecs, const JQVectorsT* _pqvecsRef) + { + pqvecs = _pqvecs; + pqvecsRef = _pqvecsRef; + } template using hasWeightNUA = decltype(std::declval().weightNUA()); template using hasWeightEff = decltype(std::declval().weightEff()); + template + using hasSign = decltype(std::declval().sign()); template - inline void FillQA(JInputClass& inputInst) + inline void FillQA(JInputClass& inputInst, UInt_t type = 0u) { - fh_ntracks[fCBin]->Fill(inputInst.size()); - fh_ImpactParameter->Fill(fImpactParameter); - fh_cent->Fill(fCent); - - fh_TrkQA_TPCvsCent->Fill(fCent, fTPCtrks); - fh_TrkQA_TPCvsGlob->Fill(fGlbtrks, fTPCtrks); - fh_TrkQA_FB32_vs_FB32TOF->Fill(fFB32trks, fFB32TOFtrks); + ph1[HIST_TH1_CENTRALITY]->Fill(fCent); + ph1[HIST_TH1_IMPACTPARAM]->Fill(fImpactParameter); for (auto& track : inputInst) { - if (!(flags & kFlucPhiCorrection)) { - fh_phieta[fCBin]->Fill(track.phi(), track.eta()); - fh_phietaz[fCBin]->Fill(track.phi(), track.eta(), fVertex[2]); - } - - if (TMath::Abs(track.eta()) < fEta_min || TMath::Abs(track.eta()) > fEta_max) - continue; - Double_t corrInv = 1.0; using JInputClassIter = typename JInputClass::iterator; if constexpr (std::experimental::is_detected::value) corrInv /= track.weightEff(); - fh_eta[fCBin]->Fill(track.eta(), corrInv); - fh_pt[fCBin]->Fill(track.pt(), corrInv); + if constexpr (std::experimental::is_detected::value) + pht[HIST_THN_PTETA]->Fill(fCent, track.pt(), track.eta(), track.sign(), corrInv); + else + pht[HIST_THN_PTETA]->Fill(fCent, track.pt(), track.eta(), 0.0, corrInv); if constexpr (std::experimental::is_detected::value) corrInv /= track.weightNUA(); - fh_phi[fCBin][(UInt_t)(track.eta() > 0.0)]->Fill(track.phi(), corrInv); + pht[HIST_THN_PHIETA]->Fill(fCent, track.phi(), track.eta(), corrInv); + pht[HIST_THN_PHIETAZ]->Fill(fCent, static_cast(type), track.phi(), track.eta(), fVertex, corrInv); } - for (UInt_t iaxis = 0; iaxis < 3; iaxis++) - fh_vertex[iaxis]->Fill(fVertex[iaxis]); + ph1[HIST_TH1_ZVERTEX]->Fill(fVertex); } - static Double_t pttJacek[74]; - static UInt_t NpttJacek; - -#define kcNH kH6 // max second dimension + 1 - private: - const Double_t* fVertex; //! - Float_t fCent; - Float_t fImpactParameter; - UInt_t fCBin; - float fTPCtrks; - float fGlbtrks; - float fFB32trks; - float fFB32TOFtrks; - UInt_t subeventMask; - UInt_t numBins; // total number of bins - UInt_t flags; - - Double_t fEta_min; - Double_t fEta_max; - - const JQVectorsT* pqvecs; - - JHistManager* fHMG; //! - - JBin fBin_Subset; //! - JBin fBin_h; //! - JBin fBin_k; //! - JBin fBin_hh; //! - JBin fBin_kk; //! - JBin fHistCentBin; //! - JBin fVertexBin; //! // x, y, z - JBin fCorrBin; //! - - JTH1D fh_cent; //! // for cent dist - JTH1D fh_ImpactParameter; //! // for impact parameter for mc - JTH1D fh_vertex; //! - JTH1D fh_pt; //! // for pt dist of tracks - JTH1D fh_eta; //! // for eta dist of tracks - JTH1D fh_phi; //! // for phi dist [ic][isub] - JTH2D fh_phieta; //! - JTH3D fh_phietaz; //! - - JTH1D fh_psi_n; //! - JTH1D fh_cos_n_phi; //! - JTH1D fh_sin_n_phi; //! - JTH1D fh_cos_n_psi_n; //! - JTH1D fh_sin_n_psi_n; //! +#define kcNH kH4 // max second dimension + 1 + protected: + Float_t fVertex; //! + Float_t fAvgInvariantMass; //! + Float_t fCent; //! + Float_t fImpactParameter; //! + UInt_t subeventMask; //! + UInt_t flags; //! - JTH1D fh_ntracks; //! // for number of tracks dist - JTH1D fh_vn; //! // single vn^k array [ih][ik][iCent] - JTH1D fh_vna; //! // single vn^k with autocorrelation removed (up to a limited order) - JTH1D fh_vn_vn; //! // combination for [ih][ik][ihh][ikk][iCent] + const JQVectorsT* pqvecs; //! + const JQVectorsT* pqvecsRef; //! - JTH1D fh_correlator; //! // some more complex correlators - JTH2D fh_TrkQA_TPCvsGlob; //! // QA histos - JTH2D fh_TrkQA_TPCvsCent; //! // QA histos - JTH2D fh_TrkQA_FB32_vs_FB32TOF; //! + TH1* ph1[HIST_TH1_COUNT]; //! + THnSparse* pht[HIST_THN_COUNT]; //! + THnSparse* phs[HIST_THN_SPARSE_COUNT]; //! - // additional variables for ptbins(Standard Candles only) - enum { kPt0, - kPt1, - kPt2, - kPt3, - kPt4, - kPt5, - kPt6, - kPt7, - N_ptbins }; - JBin fBin_Nptbins; //! - JTH1D fh_SC_ptdep_4corr; //! // for < vn^2 vm^2 > - JTH1D fh_SC_ptdep_2corr; //! // for < vn^2 > - JTH1D fh_SC_with_QC_4corr; //! // for - JTH1D fh_SC_with_QC_2corr; //! // for - JTH1D fh_SC_with_QC_2corr_gap; //! - // JTH1D fh_evt_SP_QC_ratio_2p; //! // check SP QC evt by evt ratio - // JTH1D fh_evt_SP_QC_ratio_4p; //! // check SP QC evt by evt ratio + ClassDef(JFFlucAnalysis, 1) }; #endif // PWGCF_JCORRAN_CORE_JFFLUCANALYSIS_H_ diff --git a/PWGCF/JCorran/Core/JFFlucAnalysisO2Hist.cxx b/PWGCF/JCorran/Core/JFFlucAnalysisO2Hist.cxx new file mode 100644 index 00000000000..b3419ff7dc8 --- /dev/null +++ b/PWGCF/JCorran/Core/JFFlucAnalysisO2Hist.cxx @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// \author Jasper Parkkila (jparkkil@cern.ch) +/// \since Sep 2024 + +#include "JFFlucAnalysisO2Hist.h" +#include +#include +#include "CommonConstants/MathConstants.h" + +using namespace o2; + +JFFlucAnalysisO2Hist::JFFlucAnalysisO2Hist(HistogramRegistry& registry, AxisSpec& axisMultiplicity, AxisSpec& phiAxis, AxisSpec& etaAxis, AxisSpec& zvtAxis, AxisSpec& ptAxis, AxisSpec& massAxis, const TString& folder) : JFFlucAnalysis() +{ + + ph1[HIST_TH1_CENTRALITY] = std::get>(registry.add(Form("%s/h_cent", folder.Data()), "multiplicity/centrality", {HistType::kTH1F, {axisMultiplicity}})).get(); + ph1[HIST_TH1_IMPACTPARAM] = std::get>(registry.add(Form("%s/h_IP", folder.Data()), "impact parameter", {HistType::kTH1F, {{400, -2.0, 20.0}}})).get(); + ph1[HIST_TH1_ZVERTEX] = std::get>(registry.add(Form("%s/h_vertex", folder.Data()), "z vertex", {HistType::kTH1F, {{100, -20.0, 20.0}}})).get(); + + AxisSpec chgAxis = {3, -1.5, 1.5, "charge"}; + AxisSpec typeAxis = {2, -0.5, 1.5, "type"}; + pht[HIST_THN_PHIETAZ] = std::get>(registry.add(Form("%s/h_phietaz", folder.Data()), "multiplicity/centrality, type, phi, eta, z", {HistType::kTHnSparseF, {axisMultiplicity, typeAxis, phiAxis, etaAxis, zvtAxis}})).get(); + pht[HIST_THN_PTETA] = std::get>(registry.add(Form("%s/h_pteta", folder.Data()), "(corrected) multiplicity/centrality, pT, eta, charge", {HistType::kTHnSparseF, {axisMultiplicity, ptAxis, etaAxis, chgAxis}})).get(); + pht[HIST_THN_PHIETA] = std::get>(registry.add(Form("%s/h_phieta", folder.Data()), "(corrected) multiplicity/centrality, phi, eta", {HistType::kTHnSparseF, {axisMultiplicity, phiAxis, etaAxis}})).get(); + AxisSpec hAxis = {kNH, -0.5, static_cast(kNH - 1) + 0.5, "#it{n}"}; + AxisSpec kAxis = {nKL, -0.5, static_cast(nKL - 1) + 0.5, "#it{k}"}; + AxisSpec vnAxis = {2048, -0.1, 0.1, "#it{V}_#it{n}"}; + pht[HIST_THN_SC_with_QC_4corr] = std::get>(registry.add(Form("%s/h_SC_with_QC_4corr", folder.Data()), "SC_with_QC_4corr", {HistType::kTHnSparseF, {axisMultiplicity, massAxis, hAxis, hAxis, {2048, -0.001, 0.001, "correlation"}}})).get(); + pht[HIST_THN_SC_with_QC_2corr] = std::get>(registry.add(Form("%s/h_SC_with_QC_2corr", folder.Data()), "SC_with_QC_2corr", {HistType::kTHnSparseF, {axisMultiplicity, massAxis, hAxis, {2048, -0.1, 0.1, "correlation"}}})).get(); + pht[HIST_THN_SC_with_QC_2corr_gap] = std::get>(registry.add(Form("%s/h_SC_with_QC_2corr_gap", folder.Data()), "SC_with_QC_2corr_gap", {HistType::kTHnSparseF, {axisMultiplicity, massAxis, hAxis, {2048, -0.1, 0.1, "correlation"}}})).get(); + for (UInt_t i = HIST_THN_V4V2star_2; i < HIST_THN_COUNT; ++i) + pht[i] = std::get>(registry.add(Form("%s/h_corrC%02u", folder.Data(), i - HIST_THN_V4V2star_2), "correlator", {HistType::kTHnSparseF, {axisMultiplicity, massAxis, {2048, -3.0, 3.0, "correlation"}}})).get(); + for (UInt_t i = 0; i < HIST_THN_COUNT; ++i) + pht[i]->Sumw2(); + + phs[HIST_THN_SPARSE_VN] = std::get>(registry.add(Form("%s/hvna", folder.Data()), "#it{V}_#it{n}^#it{k}", {HistType::kTHnSparseF, {axisMultiplicity, massAxis, hAxis, kAxis, vnAxis}})).get(); + phs[HIST_THN_SPARSE_VN_VN] = std::get>(registry.add(Form("%s/hvn_vn", folder.Data()), "#it{V}_#it{n_1}^#it{k_1}#it{V}_#it{n_2}^#it{k_2}", {HistType::kTHnSparseF, {axisMultiplicity, massAxis, hAxis, kAxis, hAxis, kAxis, vnAxis}})).get(); + for (UInt_t i = 0; i < HIST_THN_SPARSE_COUNT; ++i) + phs[i]->Sumw2(); +} + +JFFlucAnalysisO2Hist::~JFFlucAnalysisO2Hist() +{ + // +} diff --git a/PWGCF/JCorran/Core/JFFlucAnalysisO2Hist.h b/PWGCF/JCorran/Core/JFFlucAnalysisO2Hist.h new file mode 100644 index 00000000000..a9de2fd7864 --- /dev/null +++ b/PWGCF/JCorran/Core/JFFlucAnalysisO2Hist.h @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// \author Jasper Parkkila (jparkkil@cern.ch) +/// \since Sep 2024 + +#ifndef PWGCF_JCORRAN_CORE_JFFLUCANALYSISO2HIST_H_ +#define PWGCF_JCORRAN_CORE_JFFLUCANALYSISO2HIST_H_ + +#include "JFFlucAnalysis.h" +#include "Framework/HistogramRegistry.h" + +using namespace o2; +using namespace o2::framework; + +class JFFlucAnalysisO2Hist : public JFFlucAnalysis +{ + public: + JFFlucAnalysisO2Hist(HistogramRegistry&, AxisSpec&, AxisSpec&, AxisSpec&, AxisSpec&, AxisSpec&, AxisSpec&, const TString&); + ~JFFlucAnalysisO2Hist(); +}; + +#endif // PWGCF_JCORRAN_CORE_JFFLUCANALYSISO2HIST_H_ diff --git a/PWGCF/JCorran/Core/JHistManager.cxx b/PWGCF/JCorran/Core/JHistManager.cxx deleted file mode 100644 index 22c07ad2585..00000000000 --- a/PWGCF/JCorran/Core/JHistManager.cxx +++ /dev/null @@ -1,1050 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// \author Dong Jo Kim (djkim@jyu.fi) -/// \since Sep 2022 - -#include "JHistManager.h" -#include -using namespace std; -////////////////////////////////////////////////////// -// JBin -////////////////////////////////////////////////////// - -JNamed::JNamed(TString name, TString title, TString opt, int mode) : fName(name), - fTitle(title), - fOption(opt), - fMode(mode) -{ - // constructor -} - -JNamed::~JNamed() -{ - // virtual destructor for base class -} - -TString JNamed::GetOption(TString key) -{ - TPMERegexp a("&" + key + "=?([^&]*)", "i"); - int nMatch = a.Match(fOption); - if (nMatch < 2) - return UndefinedOption(); - return a[1]; -} -void JNamed::SetOption(TString key, TString value) -{ - TPMERegexp a("&" + key + "=?[^&]*", "i"); - int nMatch = a.Match(fOption); - TString newOpt = "&" + key + (value.Length() ? "=" + value : ""); - if (value == UndefinedOption()) - newOpt = ""; - if (nMatch < 1) - fOption += newOpt; - else - fOption.ReplaceAll(a[0], newOpt); -} -void JNamed::RemoveOption(TString key) -{ - SetOption(key, UndefinedOption()); -} -TString JNamed::UndefinedOption() -{ - // static TString undefinedOption = "Undefined"; - // return undefinedOption; - return "Undefined"; -} - -////////////////////////////////////////////////////// -// JBin -////////////////////////////////////////////////////// - -//_____________________________________________________ -JBin::JBin() : JNamed("JBin", "%.2f-%2.f", "&Mode=Range", kRange), - fBinD(0), - fBinStr(0), - fIsFixedBin(false), - fIndexName("H"), - fHMG(NULL) -{ - ; -} -//_____________________________________________________ -JBin::JBin(TString config, JHistManager* hmg) : JNamed("JBin", "%.2f-%2.f", "&Mode=Range", kRange), - fBinD(0), - fBinStr(0), - fIsFixedBin(false), - fIndexName("H"), - fHMG(NULL) -{ - // cout<< config< t = Tokenize(config, " \t,"); - TString type = t[0]; - SetName(t[1]); - fIndexName = t[2]; - SetTitle(t[3]); - fTitle.ReplaceAll("\"", ""); - SetFullOption(t[4]); - fMode = GetMode(GetOption("mode")); - AddToManager(hmg); - TString s; - for (UInt_t i = 5; i < t.size(); i++) - s += " " + t[i]; - SetBin(s); -} - -//_____________________________________________________ -JBin::JBin(const JBin& obj) : JNamed(obj.fName, obj.fTitle, obj.fOption, obj.fMode), - fBinD(obj.fBinD), - fBinStr(obj.fBinStr), - fIsFixedBin(obj.fIsFixedBin), - fIndexName(obj.fIndexName), - fHMG(obj.fHMG) -{ - // copy constructor TODO: proper handling of pointer data members -} - -//_____________________________________________________ -JBin& JBin::operator=(const JBin& obj) -{ - // assignment operator - if (this != &obj) { - // TODO: proper implementation - } - return *this; -} - -//_____________________________________________________ -void JBin::FixBin() -{ - if (fIsFixedBin) - return; - fIsFixedBin = true; - if (!fHMG) - AddToManager(JHistManager::CurrentManager()); -} -//_____________________________________________________ -void JBin::AddToManager(JHistManager* hmg) -{ - hmg->Add(this); -} -//_____________________________________________________ -JBin& JBin::Set(TString name, TString iname, TString title, int mode) -{ - SetNameTitle(name, title); - fIndexName = iname; - fMode = mode; - SetOption("mode", GetModeString(mode)); - return *this; -} -//_____________________________________________________ -TString JBin::GetModeString(int i) -{ - static TString mode[] = {"Single", "Range", "String"}; - if (i < 0 || i > 2) - return ""; - return mode[i]; -} -int JBin::GetMode(TString mode) -{ - for (int i = 0; i < kNMode; i++) - if (mode == GetModeString(i)) - return i; - return -1; -} -//_____________________________________________________ -JBin& JBin::SetBin(const int n, const float* v) -{ - for (int i = 0; i < n; i++) { - AddBin(v[i]); - } - FixBin(); - return *this; -} -//_____________________________________________________ -JBin& JBin::SetBin(const int n, const double* v) -{ - for (int i = 0; i < n; i++) { - AddBin(v[i]); - } - FixBin(); - return *this; -} -JBin& JBin::SetBin(TVector* v) -{ - for (int i = 0; i < v->GetNrows(); i++) { - AddBin((v->GetMatrixArray())[i]); - } - FixBin(); - return *this; -} -//_____________________________________________________ -JBin& JBin::SetBin(const TString v) -{ - std::vector ar = Tokenize(v, "\t ,"); - for (UInt_t i = 0; i < ar.size(); i++) { - AddBin(ar[i]); - } - FixBin(); - return *this; -} - -//_____________________________________________________ -JBin& JBin::SetBin(const int n) -{ - for (UInt_t i = 0; i < UInt_t(n); i++) { - AddBin(i); - } - FixBin(); - return *this; -} -//_____________________________________________________ -void JBin::AddBin(const TString& v) -{ - if (fIsFixedBin) { - JERROR("You can't Add Bini %s", GetName().Data()); - } - fBinStr.push_back((v == "_") ? "" : v); - fBinD.push_back(v.Atof()); -} -//_____________________________________________________ -void JBin::AddBin(float v) -{ - if (fIsFixedBin) { - JERROR("You can't Add Bin %s", GetName().Data()); - } - fBinD.push_back(v); - fBinStr.push_back(Form("%f", v)); -} -//_____________________________________________________ -TString JBin::BuildTitle(int i) -{ - if (i < 0 || i > Size()) - return ""; - if (fMode == kSingle) - return TString(Form(fTitle.Data(), fBinD[i])); - if (fMode == kRange) - return TString(Form(fTitle.Data(), fBinD[i], fBinD[i + 1])); - if (fMode == kString) - return TString(Form(fTitle.Data(), fBinStr[i].Data())); - JERROR("Bad Mode of JBin type %d in %s", fMode, fName.Data()); - return ""; -} -//_____________________________________________________ -TString JBin::GetString() -{ - SetOption("mode", GetModeString(fMode)); - return "JBin\t" + fName + "\t" + fIndexName + "\t\"" + fTitle + "\"" + "\t" + fOption + "\t" + Join(fBinStr, " "); -} -//_____________________________________________________ -void JBin::Print() -{ - // std::cout<<"*"+GetString()<= decltype(i)(fBinD.size())) - return -1; - return i; -} - -////////////////////////////////////////////////////// -// JArrayBase -////////////////////////////////////////////////////// - -//_____________________________________________________ -JArrayBase::JArrayBase() : JNamed("JArayBase", "", "&Dir=default&Lazy", 0), - // JNamed("JArayBase","","&Dir=default&LessLazy",0), - fDim(0), - fIndex(0), - fArraySize(0), - fNGenerated(0), - fIsBinFixed(false), - fIsBinLocked(false), - fAlg(NULL) -{ - // constrctor -} -//_____________________________________________________ -JArrayBase::~JArrayBase() -{ - // destructor - if (fAlg) - delete fAlg; -} - -//_____________________________________________________ -JArrayBase::JArrayBase(const JArrayBase& obj) : JNamed(obj.fName, obj.fTitle, obj.fOption, obj.fMode), - fDim(obj.fDim), - fIndex(obj.fIndex), - fArraySize(obj.fArraySize), - fNGenerated(obj.fNGenerated), - fIsBinFixed(obj.fIsBinFixed), - fIsBinLocked(obj.fIsBinLocked), - fAlg(obj.fAlg) -{ - // copy constructor TODO: proper handling of pointer data members -} - -//_____________________________________________________ -JArrayBase& JArrayBase::operator=(const JArrayBase& obj) -{ - // assignment operator - if (this != &obj) { - // TODO: proper implementation - } - return *this; -} - -//_____________________________________________________ -void* JArrayBase::GetItem() -{ - void* item = fAlg->GetItem(); - if (!item) { - BuildItem(); - item = fAlg->GetItem(); - } - return item; -} -//_____________________________________________________ -void* JArrayBase::GetSingleItem() -{ - if (fMode == kSingle) - return GetItem(); - JERROR("This is not single array"); - return NULL; -} -//_____________________________________________________ -void JArrayBase::FixBin() -{ - if (Dimension() == 0) { - AddDim(1); - SetOption("Single"); - fMode = kSingle; - if (HasOption("dir", "default")) - RemoveOption("dir"); - } - ClearIndex(); - fAlg = new JArrayAlgorithmSimple(this); - fArraySize = fAlg->BuildArray(); -} -//_____________________________________________________ -int JArrayBase::Index(int d) -{ - if (OutOfDim(d)) - JERROR("Wrong Dim"); - return fIndex[d]; -} -void JArrayBase::SetIndex(int i, int d) -{ - if (OutOfSize(i, d)) - JERROR("Wrong Index"); - fIndex[d] = i; -} - -void JArrayBase::InitIterator() { fAlg->InitIterator(); } -bool JArrayBase::Next(void*& item) { return fAlg->Next(item); } - -////////////////////////////////////////////////////// -// JArrayAlgorithm -////////////////////////////////////////////////////// - -//_____________________________________________________ -JArrayAlgorithm::JArrayAlgorithm(JArrayBase* cmd) : fCMD(cmd) -{ - // constructor -} -//_____________________________________________________ -JArrayAlgorithm::~JArrayAlgorithm() -{ - // destructor -} - -//_____________________________________________________ -JArrayAlgorithm::JArrayAlgorithm(const JArrayAlgorithm& obj) : fCMD(obj.fCMD) -{ - // copy constructor TODO: proper handling of pointer data members -} - -//_____________________________________________________ -JArrayAlgorithm& JArrayAlgorithm::operator=(const JArrayAlgorithm& obj) -{ - // assignment operator - if (this != &obj) { - *fCMD = *(obj.fCMD); - } - return *this; -} - -////////////////////////////////////////////////////// -// JArrayAlgorithmSimple -////////////////////////////////////////////////////// - -//_____________________________________________________ -JArrayAlgorithmSimple::JArrayAlgorithmSimple(JArrayBase* cmd) : JArrayAlgorithm(cmd), - fDimFactor(0), - fArray(NULL), - fPos(0) -{ - // constructor -} -//_____________________________________________________ -JArrayAlgorithmSimple::~JArrayAlgorithmSimple() -{ - // Dimension, GetEntries, SizeOf - if (fArray) - delete[] fArray; -} - -//_____________________________________________________ -JArrayAlgorithmSimple::JArrayAlgorithmSimple(const JArrayAlgorithmSimple& obj) : JArrayAlgorithm(obj.fCMD), - fDimFactor(obj.fDimFactor), - fArray(obj.fArray), - fPos(obj.fPos) -{ - // copy constructor TODO: proper handling of pointer data members -} - -//_____________________________________________________ -JArrayAlgorithmSimple& JArrayAlgorithmSimple::operator=(const JArrayAlgorithmSimple& obj) -{ - // assignment operator TODO: proper implementation - if (this != &obj) { - *fCMD = *(obj.fCMD); - } - return *this; -} -//_____________________________________________________ -int JArrayAlgorithmSimple::BuildArray() -{ - fDimFactor.resize(Dimension(), 1); - for (int i = Dimension() - 2; i >= 0; i--) { - fDimFactor[i] = fDimFactor[i + 1] * SizeOf(i + 1); - } // TODO split to BuildArray and lazyArray in GetItem - int arraySize = fDimFactor[0] * SizeOf(0); - fArray = new void*[arraySize]; - for (int i = 0; i < arraySize; i++) - fArray[i] = NULL; - return arraySize; -} -//_____________________________________________________ -int JArrayAlgorithmSimple::GlobalIndex() -{ - int iG = 0; - for (int i = 0; i < Dimension(); i++) // Index is checked by fCMD - iG += Index(i) * fDimFactor[i]; - // TODO check iG - return iG; -} -void JArrayAlgorithmSimple::ReverseIndex(int iG) -{ - int n = iG; - for (int i = 0; i < Dimension(); i++) { - int n1 = static_cast(n / fDimFactor[i]); - fCMD->SetIndex(n1, i); - n -= n1 * fDimFactor[i]; - } -} -void* JArrayAlgorithmSimple::GetItem() -{ - return fArray[GlobalIndex()]; -} -void JArrayAlgorithmSimple::SetItem(void* item) -{ - fArray[GlobalIndex()] = item; -} - -////////////////////////////////////////////////////// -// JTH1 -////////////////////////////////////////////////////// -//_____________________________________________________ -JTH1::JTH1() : fDirectory(NULL), - fSubDirectory(NULL), - fHMG(NULL), - fTemplate(NULL), - fBins(0) -{ - // default constructor - fName = "JTH1"; -} - -//_____________________________________________________ -JTH1::JTH1(TString config, JHistManager* hmg) : fDirectory(NULL), - fSubDirectory(NULL), - fHMG(NULL), - fTemplate(NULL), - fBins(0) -{ - // constructor - std::vector t = Tokenize(config, " \t,"); - TString type = t[0]; - SetName(t[1]); - SetTitle(t[2]); - fTitle.ReplaceAll("\"", ""); - SetFullOption(t[3]); - fMode = HasOption("mode", "Single") ? kSingle : kNormal; - AddToManager(hmg); - TString s; - for (UInt_t i = 4; i < t.size(); i++) - s += " " + t[i]; - AddDim(s); - FixBin(); -} -//_____________________________________________________ -JTH1::~JTH1() -{ - // destructor - if (fNGenerated == 0 && fTemplate) - delete fTemplate; -} - -//_____________________________________________________ -JTH1::JTH1(const JTH1& obj) : JArrayBase(), - fDirectory(obj.fDirectory), - fSubDirectory(obj.fSubDirectory), - fHMG(obj.fHMG), - fTemplate(obj.fTemplate), - fBins(obj.fBins) -{ - // copy constructor TODO: proper handling of pointer data members -} - -//_____________________________________________________ -JTH1& JTH1::operator=(const JTH1& obj) -{ - // assignment operator - if (this != &obj) { - // TODO: proper implementation - } - return *this; -} - -//_____________________________________________________ -int JTH1::AddDim(JBin* bin) -{ - int ndim = this->JArrayBase::AddDim(bin->Size()); - fBins.resize(ndim, NULL); - fBins[ndim - 1] = bin; - return ndim; -} - -int JTH1::AddDim(TString v) -{ - if (v == "END") { - FixBin(); - } else { - std::vector o = Tokenize(v, "\t ,"); - for (UInt_t i = 0; i < o.size(); i++) { - TString& s = o[i]; - if (s.Length() == 0) - continue; - if (s.IsFloat()) { // TODO IsInt? IsDigit? - AddDim(s.Atoi()); - continue; - } - JBin* b = NULL; - if (fHMG) - b = fHMG->GetBin(s); - if (b) - this->AddDim(b); - else - JERROR("Wrong terminator of Array : \"%s\" in %s", s.Data(), fName.Data()); - } - } - return Dimension(); -} -//_____________________________________________________ -Int_t JTH1::Write() -{ - TDirectory* owd = gDirectory; - InitIterator(); - void* item; - if (fSubDirectory) - fSubDirectory->cd(); - // else fDirectory->cd(); - while (Next(item)) { - if (!item) - continue; - TH1* obj = static_cast(item); - obj->Write(); - // obj->Write( 0, TObject::kOverwrite ); - } - if (owd != gDirectory) - owd->cd(); - return 0; -} -//_____________________________________________________ -TString JTH1::GetString() -{ - TString s = Form("%s\t%s\t\"%s\"\t%s\t", - ClassName(), fName.Data(), fTitle.Data(), fOption.Data()); - for (int i = 0; i < Dimension(); i++) { - if (decltype(i)(fBins.size()) > i && fBins[i] != NULL) { - s += " " + fBins[i]->GetName(); - } else { - s += TString(" ") + Form("%d", SizeOf(i)); - } - } - return s; -} -//_____________________________________________________ -void JTH1::FixBin() -{ - this->JArrayBase::FixBin(); - - if (!fHMG) { - AddToManager(JHistManager::CurrentManager()); - } - if (!fDirectory) - fDirectory = fHMG->GetDirectory(); -} - -//_____________________________________________________ -void JTH1::AddToManager(JHistManager* hmg) -{ - if (fHMG) - return; // TODO handle error - fHMG = hmg; - hmg->Add(this); -} -//_____________________________________________________ -void JTH1::Print() -{ - // std::cout<<"*"<(h->Clone()); - fTemplate->Sumw2(); - fTemplate->SetDirectory(0); - fName = h->GetName(); - fTitle = h->GetTitle(); -} -//_____________________________________________________ -TString JTH1::BuildName() -{ - TString name = fName; - if (!HasOption("Single")) { - for (int i = 0; i < Dimension(); i++) { - name += ((decltype(i)(fBins.size()) > i && fBins[i] != NULL) ? fBins[i]->GetIndexName() : "H") + Form("%02d", Index(i)); - } - } - return name; -} -//_____________________________________________________ -TString JTH1::BuildTitle() -{ - TString title = fTitle; - for (int i = 0; i < Dimension(); i++) - title += ((static_cast(fBins.size()) > i && fBins[i] != NULL) ? " " + fBins[i]->BuildTitle(Index(i)) : "") + Form("%02d", Index(i)); - return title; -} -//_____________________________________________________ -void* JTH1::BuildItem() -{ - TDirectory* owd = gDirectory; - gROOT->cd(); - TString name = BuildName(); - TH1* item = NULL; - if (!fSubDirectory) { - if (!HasOption("dir")) { - fSubDirectory = fDirectory; - } else { - fSubDirectory = fDirectory->GetDirectory(fName); - if (!fSubDirectory && !IsLoadMode()) { - fSubDirectory = fDirectory->mkdir(fName); - } - } - } - if (IsLoadMode()) { - // if( fSubDirectory ) JDEBUG(2, fSubDirectory->GetName() ); - if (fSubDirectory) - item = dynamic_cast(fSubDirectory->Get(name)); - if (!item) { - void** rawItem = fAlg->GetRawItem(); - InitIterator(); - void* tmp; - while (Next(tmp)) { - item = static_cast(fSubDirectory->Get(BuildName())); - if (item) - break; - } - if (item) { - item = dynamic_cast((static_cast(item))->Clone(name)); - if (!item) { - JERROR("Any of %s doesn't exists. I need at least one", fName.Data()); - return NULL; - } - item->Reset(); - item->SetTitle(BuildTitle()); - item->SetDirectory(0); - *rawItem = item; - } - } - if (!item) { - JERROR("Any of %s doesn't exists. I need at least one", fName.Data()); - return NULL; - } - } else { // Gen Mode - TH1* titem = NULL; - if (fNGenerated == 0) - titem = fTemplate; - else - titem = static_cast(fTemplate->Clone()); - titem->SetDirectory(fSubDirectory); - titem->Reset(); - titem->SetName(BuildName()); - titem->SetTitle(BuildTitle()); - fNGenerated++; - item = titem; - } - if (item) - fAlg->SetItem(item); - owd->cd(); - return item; -} -//_____________________________________________________ -bool JTH1::IsLoadMode() -{ - return fHMG->IsLoadMode(); -} - -////////////////////////////////////////////////////////////////////////// -// // -// JTH1Derived // -// // -////////////////////////////////////////////////////////////////////////// -template -JTH1Derived::JTH1Derived() : JTH1(), fPlayer(this) -{ -} -template -JTH1Derived::~JTH1Derived() -{ -} - -////////////////////////////////////////////////////////////////////////// -// // -// JHistManager // -// // -// Array Base Class // -// // -////////////////////////////////////////////////////////////////////////// -JHistManager::JHistManager(TString name, TString dirname) : JNamed(name, "", "", 0), - fIsLoadMode(false), - fDirectory(gDirectory), - fConfigStr(), - fBin(0), - fHist(0), - fManager(0), - fBinNames(0), - fBinConfigs(0), - fHistNames(0), - fHistConfigs(0) -{ - // constructor - if (dirname.Length() == 0) - dirname = name; - if (dirname.Length() > 0) { - fDirectory = static_cast(gDirectory->Get(dirname)); - if (fDirectory) { - LOGF(warning, "Hist directory %s exists", dirname.Data()); - // gSystem->Exit(1); // We might actually want the directory to exist, so no exit - } - if (!fDirectory) { - fDirectory = gDirectory->mkdir(dirname); - } - } - if (!fDirectory) { - JERROR("Fail to generate Hist directory %s", dirname.Data()); - // gSystem->Exit(1); - } - this->cd(); -} - -//_____________________________________________________ -JHistManager::JHistManager(const JHistManager& obj) : JNamed(obj.fName, obj.fTitle, obj.fOption, obj.fMode), - fIsLoadMode(obj.fIsLoadMode), - fDirectory(obj.fDirectory), - fConfigStr(obj.fConfigStr), - fBin(obj.fBin), - fHist(obj.fHist), - fManager(obj.fManager), - fBinNames(obj.fBinNames), - fBinConfigs(obj.fBinConfigs), - fHistNames(obj.fHistNames), - fHistConfigs(obj.fHistConfigs) -{ - // copy constructor TODO: proper handling of pointer data members -} - -//_____________________________________________________ -JHistManager& JHistManager::operator=(const JHistManager& obj) -{ - // assignment operator - if (this != &obj) { - // TODO: proper implementation - } - return *this; -} - -JHistManager* JHistManager::GlobalManager() -{ - static JHistManager* singleton = new JHistManager("GlobalHistManager"); - return singleton; -} - -JHistManager* JHistManager::CurrentManager(JHistManager* hmg) -{ - static JHistManager* currentManager = NULL; //;JHistManager::GlobalManager(); - if (hmg) - currentManager = hmg; - return currentManager; -} - -JBin* JHistManager::GetBuiltBin(TString s) -{ - for (UInt_t i = 0; i < fBin.size(); i++) - if (fBin[i]->GetName() == s) - return fBin[i]; - return NULL; -} -JBin* JHistManager::GetBin(TString s) -{ - JBin* h = GetBuiltBin(s); - if (h) - return h; - for (UInt_t i = 0; i < GetNBin(); i++) - if (fBinNames[i] == s) { - return new JBin(fBinConfigs[i], this); - } - return NULL; -} -JTH1* JHistManager::GetBuiltTH1(TString s) -{ - for (UInt_t i = 0; i < fHist.size(); i++) - if (fHist[i]->GetName() == s) - return fHist[i]; - return NULL; -} -// Note: Returning NULL crashes the code, something should be done about this. -// The error given by compiler is: non-const lvalue reference to type 'JTH1D' (aka 'JTH1Derived') cannot bind to a temporary of type 'long' -// The reoson for crash is that NULL cannot be used in dynamic_cast -JTH1* JHistManager::GetTH1(TString s) -{ - JTH1* h = GetBuiltTH1(s); - if (h) - return h; - for (UInt_t i = 0; i < GetNHist(); i++) - if (fHistNames[i] == s) { - if (fHistConfigs[i].BeginsWith("JTH1D")) - return new JTH1D(fHistConfigs[i], this); - if (fHistConfigs[i].BeginsWith("JTH2D")) - return new JTH2D(fHistConfigs[i], this); - if (fHistConfigs[i].BeginsWith("JTH3D")) - return new JTH3D(fHistConfigs[i], this); - if (fHistConfigs[i].BeginsWith("JTProfile")) - return new JTProfile(fHistConfigs[i], this); - } - return NULL; -} -void JHistManager::Add(JBin* o) -{ - if (!o) - return; - if (GetBuiltBin(o->GetName())) - return; // TODO error handle - fBin.push_back(o); -} -void JHistManager::Add(JTH1* o) -{ - if (!o) - return; - if (GetBuiltTH1(o->GetName())) - return; // TODO error handle - fHist.push_back(o); -} -void JHistManager::Print() -{ - if (IsLoadMode()) { - // cout<Print(); - } - LOGF(info, "\n---- JTH1 ----\n"); - for (UInt_t i = 0; i < GetNHist(); i++) { - fHist[i]->Print(); - } -} -void JHistManager::Write() -{ - for (UInt_t i = 0; i < GetNHist(); i++) - fHist[i]->Write(); -} - -void JHistManager::WriteConfig() -{ - TDirectory* owd = fDirectory; - // cout<<"DEBUG_T1: "<GetName()<mkdir("HistManager"); - fHistConfigDir->cd(); - TObjString* config = new TObjString(GetString().Data()); - config->Write("Config"); - owd->cd(); -} - -int JHistManager::LoadConfig() -{ - SetLoadMode(true); - TObjString* strobj = static_cast(fDirectory->Get("HistManager/Config")); - if (!strobj) - return 0; // TODO - TString config = strobj->String(); - fConfigStr = config; - vector lines = Tokenize(config, "\n"); - LOGF(info, "Read Config.%d objects found", (int)lines.size()); - for (UInt_t i = 0; i < lines.size(); i++) { - TString line = lines.at(i); - std::vector t = Tokenize(line, " \t,"); - if (line.BeginsWith("JBin")) { - fBinNames.push_back(t[1]); - fBinConfigs.push_back(line); - } else if (line.BeginsWith("J")) { - fHistNames.push_back(t[1]); - fHistConfigs.push_back(line); - } - } - return 1; -} - -bool JHistManager::HistogramExists(TString name) -{ - for (UInt_t i = 0; i < fHistNames.size(); i++) { - if (fHistNames[i] == name) - return true; - } - return false; -} - -////////////////////////////////////////////////////// -// Utils -////////////////////////////////////////////////////// -vector Tokenize(TString s, TString d, int quote) -{ - // int nd = d.Length(); - bool flagBeforeToken = 0; - bool inQuote = 0; - TString tok = ""; - vector toks; - s += d[0]; - for (int i = 0; i < s.Length(); i++) { - if (quote == 1 && s[i] == '\"') { - inQuote = !inQuote; - } - if (d.First(s[i]) != kNPOS && !inQuote) { - if (flagBeforeToken == 0 && tok.Length() > 0) { - toks.push_back(tok); - tok.Clear(); - flagBeforeToken = 1; - } - } else { - tok += s[i]; - flagBeforeToken = 0; - } - } - return toks; -} - -TString Join(vector& ss, TString del) -{ - if (ss.size() < 1) - return ""; - TString s = ss[0]; - for (UInt_t i = 1; i < ss.size(); i++) - s += del + ss[i]; - return s; -} - -template class JTH1Derived; -template class JTH1Derived; -template class JTH1Derived; -template class JTH1Derived; - -bool OutOf(int i, int x, int y) { return (i < x || i > y); } - -#include - -void ttestJArray() -{ - JHistManager* fHMG; - JBin fCentBin; - JBin fVtxBin; - JBin fPTtBin; - JBin fPTaBin; - JBin fXEBin; - JBin fKLongBin; - JBin fRGapBin; - JBin fEtaGapBin; - JBin fPhiGapBin; - JBin fMassBin; - JBin fTypBin; - JBin fTypBin3; - JBin fPairPtBin; - JTH1D fhTriggPtBin; - JTH1D fhTriggMult; - JTH1D fhIphiTrigg; - JTH1D fhIetaTrigg; - JTH2D test1; - JTProfile test2; - - TFile* f = new TFile("test.root", "RECREATE"); - fHMG = JHistManager::GlobalManager(); - fCentBin.Set("Cent", "C", "C %2.0f-%2.0f%%").SetBin("0 100"); - fVtxBin.Set("Vtx", "V", "Vtx %.0f-%.0f").SetBin("-10 10"); - fPTtBin.Set("PTt", "T", "p_{Tt} %.1f-%.1f").SetBin("3 5 8 10 15 20"); - fPTaBin.Set("PTa", "A", "p_{Tt} %.1f-%.1f").SetBin("3 5 8 10 15 20"); - - fhTriggMult - << TH1D("hTriggMult", "", 100, -0.5, 99.5) - << fCentBin << fPTtBin << "END"; - fhIphiTrigg - << TH1D("fhIphiTrigg", "", 3, -0.1, 0.1) - << fCentBin << fPTtBin << "END"; - fhIetaTrigg - << TH1D("hIetaTrigg", "", 80, -5, 5) - << fCentBin << fPTtBin << "END"; // inclusive eta - fhTriggPtBin - << TH1D("hTriggPtBin", "", 10, 0, 10) - << fCentBin << fVtxBin << fPTtBin << "END"; - - fhTriggMult[0][0]->Fill(1); - fHMG->Print(); - - f->Write(); - fHMG->Write(); - fHMG->WriteConfig(); -} diff --git a/PWGCF/JCorran/Core/JHistManager.h b/PWGCF/JCorran/Core/JHistManager.h deleted file mode 100644 index c1cbf2ce9bd..00000000000 --- a/PWGCF/JCorran/Core/JHistManager.h +++ /dev/null @@ -1,521 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// \author Dong Jo Kim (djkim@jyu.fi) -/// \since Sep 2022 - -#ifndef PWGCF_JCORRAN_CORE_JHISTMANAGER_H_ -#define PWGCF_JCORRAN_CORE_JHISTMANAGER_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "Framework/Logger.h" - -#define STR_HELPER(x) #x -#define STR(x) STR_HELPER(x) -#define JERROR(...) LOGF(error, "JERROR: " __FILE__ ":" STR(__LINE__) ": " __VA_ARGS__) - -class JArrayBase; -class JBin; -class JArrayAlgorithm; -class JArrayAlgorithmSimple; -class JTH1; -class JHistManager; -template -class JTH1Derived; -template -class JTH1DerivedPlayer; - -////////////////////////////////////////////////////// -// Utils -////////////////////////////////////////////////////// -std::vector Tokenize(TString s, TString d, int quote = 1); -TString Join(std::vector& ss, TString del = " "); -bool OutOf(int, int, int); - -typedef std::vector ArrayInt; -typedef std::vector ArrayDouble; -// typedef JArray ArrayVoid*; - -////////////////////////////////////////////////////////////////////////// -// // -// JNamed // -// // -// -// // -////////////////////////////////////////////////////////////////////////// -//________________________________________________________________________ -class JNamed -{ - public: - JNamed(TString name, TString title, TString opt, int mode); - virtual ~JNamed(); - TString GetName() { return fName; } - TString GetTitle() { return fTitle; } - TString GetOption() { return fOption; } - TString GetOption(TString key); - bool HasOption(TString key) { return GetOption(key) != UndefinedOption(); } - bool HasOption(TString key, TString val) { return GetOption(key) == val; } // TODO sensitive? - void SetName(const char* s) { fName = s; } - void SetTitle(const char* s) { fTitle = s; } - void SetNameTitle(TString n, TString t) - { - SetName(n); - SetTitle(t); - } - void SetFullOption(const char* s) { fOption = s; } - void SetOption(TString key, TString value = ""); - void RemoveOption(TString key); // TODO - // void SetOptionWithString( TString s );// TODO - static TString UndefinedOption(); - - protected: - TString fName; - TString fTitle; - TString fOption; - int fMode; -}; - -////////////////////////////////////////////////////////////////////////// -// // -// JBin // -// // -// -// // -////////////////////////////////////////////////////////////////////////// -//________________________________________________________________________ -class JBin : public JNamed -{ - public: - enum { kSingle, - kRange, - kString, - kNMode }; - JBin(); - JBin(TString config, JHistManager* hmg); - explicit JBin(const JBin& obj); - JBin& operator=(const JBin& obj); - JBin& Set(TString name, TString iname, TString Title, int mode = kRange); - void AddToManager(JHistManager* hmg); - JBin& SetBin(const int n, const float* v); - JBin& SetBin(const int n, const double* v); - JBin& SetBin(TVector* v); - JBin& SetBin(const TString v); - JBin& SetBin(const int n); - - int GetBin(double x); - - double GetMin() { return fBinD[0]; } - double GetMax() { return fBinD[RawSize() - 1]; } - - TString BuildTitle(int i); - int RawSize() { return fBinD.size(); } - int Size() { return fMode == kRange ? fBinD.size() - 1 : fBinD.size(); } - double At(int i) { return fBinD[i]; } - TString GetIndexName() { return fIndexName; } - - void Print(); - TString GetString(); - - operator int() { return Size(); } - - static TString GetModeString(int i); - static int GetMode(TString mode); - - private: - void AddBin(const TString& v); - void AddBin(float v); - virtual void FixBin(); - - std::vector fBinD; - std::vector fBinStr; - bool fIsFixedBin; - TString fIndexName; - JHistManager* fHMG; -}; - -////////////////////////////////////////////////////////////////////////// -// // -// JArrayBase // -// // -// Array Base Class // -// // -////////////////////////////////////////////////////////////////////////// - -//________________________________________________________________________ -class JArrayBase : public JNamed -{ - public: - enum { kNormal, - kSingle }; - virtual ~JArrayBase(); - JArrayBase& operator=(const JArrayBase& obj); - - int AddDim(int i) - { - fDim.push_back(i); - return fDim.size(); - } - int Dimension() { return fDim.size(); } - int GetEntries() { return fArraySize; } - int SizeOf(int i) { return fDim.at(i); } - - ArrayInt& Index() { return fIndex; } - int Index(int d); - void SetIndex(int i, int d); - void ClearIndex() - { - fIndex.clear(); - fIndex.resize(Dimension(), 0); - } - - void* GetItem(); - void* GetSingleItem(); - - /// void LockBin(bool is=true){}//TODO - // bool IsBinLocked(){ return fIsBinLocked; } - - virtual void FixBin(); - bool IsBinFixed() { return fIsBinFixed; } - - bool OutOfDim(int d) { return OutOf(d, 0, Dimension() - 1); } - bool OutOfSize(int i, int d) { return OutOfDim(d) || OutOf(i, 0, SizeOf(d) - 1); } - - // Virtual - virtual void* BuildItem() = 0; - virtual TString BuildName() = 0; - virtual TString BuildTitle() = 0; - virtual void Print() = 0; - virtual TString GetString() = 0; - - // int Resize( int size, int dim=-1 ); // NextStep - void InitIterator(); - bool Next(void*& item); - - protected: - JArrayBase(); // Prevent direct creation of JArrayBase - JArrayBase(const JArrayBase& obj); - - ArrayInt fDim; // Comment test - ArrayInt fIndex; /// Comment test - int fArraySize; /// Comment test3 - int fNGenerated; - bool fIsBinFixed; - bool fIsBinLocked; - JArrayAlgorithm* fAlg; - friend class JArrayAlgorithm; -}; - -//________________________________________________________________________ -class JArrayAlgorithm -{ - public: - explicit JArrayAlgorithm(JArrayBase* cmd); // TODO Move to private - JArrayAlgorithm(const JArrayAlgorithm& obj); - JArrayAlgorithm& operator=(const JArrayAlgorithm& obj); - virtual ~JArrayAlgorithm(); - int Dimension() { return fCMD->Dimension(); } - int SizeOf(int i) { return fCMD->SizeOf(i); } - int GetEntries() { return fCMD->GetEntries(); } - int Index(int i) { return fCMD->Index(i); } - virtual int BuildArray() = 0; - virtual void* GetItem() = 0; - virtual void SetItem(void* item) = 0; - virtual void InitIterator() = 0; - virtual bool Next(void*& item) = 0; - virtual void** GetRawItem() = 0; - virtual void* GetPosition() = 0; - virtual bool IsCurrentPosition(void* pos) = 0; - virtual void SetPosition(void* pos) = 0; - virtual void DeletePosition(void* pos) = 0; - - protected: - JArrayBase* fCMD; -}; - -//________________________________________________________________________ -class JArrayAlgorithmSimple : public JArrayAlgorithm -{ - public: - explicit JArrayAlgorithmSimple(JArrayBase* cmd); - JArrayAlgorithmSimple(const JArrayAlgorithmSimple& obj); - JArrayAlgorithmSimple& operator=(const JArrayAlgorithmSimple& obj); - virtual ~JArrayAlgorithmSimple(); - virtual int BuildArray(); - int GlobalIndex(); - void ReverseIndex(int iG); - virtual void* GetItem(); - virtual void SetItem(void* item); - virtual void InitIterator() { fPos = 0; } - virtual void** GetRawItem() { return &fArray[GlobalIndex()]; } - virtual bool Next(void*& item) - { - item = fPos < GetEntries() ? fArray[fPos] : NULL; - if (fPos < GetEntries()) - ReverseIndex(fPos); - return fPos++ < GetEntries(); - } - virtual void* GetPosition() { return static_cast(new int(fPos)); } - virtual bool IsCurrentPosition(void* pos) { return *static_cast(pos) == fPos; } - virtual void SetPosition(void* pos) - { - fPos = *static_cast(pos); - ReverseIndex(fPos); - } - virtual void DeletePosition(void* pos) { delete static_cast(pos); } - - private: - ArrayInt fDimFactor; - void** fArray; - int fPos; -}; - -////////////////////////////////////////////////////////////////////////// -// // -// JTH1 // -// // -// Array Base Class // -// // -////////////////////////////////////////////////////////////////////////// -//________________________________________________________________________ -class JTH1 : public JArrayBase -{ - public: - JTH1(); - JTH1(TString config, JHistManager* hmg); - JTH1(const JTH1& obj); - JTH1& operator=(const JTH1& obj); - virtual ~JTH1(); - - int AddDim(int i) - { - fDim.push_back(i); - return fDim.size(); - } - int AddDim(JBin* bin); - int AddDim(TString v); - void AddToManager(JHistManager* hmg); - JBin* GetBinPtr(int i) { return fBins.at(i); } - - // Virtual from JArrayBase - virtual void* BuildItem(); - virtual TString GetString(); - virtual void Print(); - virtual void FixBin(); - // Virtual from this - virtual Int_t Write(); - // virtual Int_t WriteAll(); - virtual const char* ClassName() { return "JTH1"; } - - // Not Virtual - virtual TString BuildName(); - virtual TString BuildTitle(); - bool IsLoadMode(); - void SetTemplate(TH1* h); - TH1* GetTemplatePtr() { return fTemplate; } - - protected: - TDirectory* fDirectory; - TDirectory* fSubDirectory; - JHistManager* fHMG; - TH1* fTemplate; - std::vector fBins; -}; -////////////////////////////////////////////////////////////////////////// -// // -// JTH1Derived // -// // -// Array Base Class // -// // -////////////////////////////////////////////////////////////////////////// -template -class JTH1Derived : public JTH1 -{ - protected: - public: - JTH1Derived(); - JTH1Derived(TString config, JHistManager* hmg) : JTH1(config, hmg), fPlayer(this) {} - virtual ~JTH1Derived(); - - JTH1DerivedPlayer& operator[](int i) - { - fPlayer.Init(); - fPlayer[i]; - return fPlayer; - } - T* operator->() { return static_cast(GetSingleItem()); } - operator T*() { return static_cast(GetSingleItem()); } - // Virtual from JArrayBase - - // Virtual from JTH1 - virtual const char* ClassName() { return Form("J%s", T::Class()->GetName()); } - - JTH1Derived& operator<<(int i) - { - AddDim(i); - return *this; - } - JTH1Derived& operator<<(JBin& v) - { - AddDim(&v); - return *this; - } - JTH1Derived& operator<<(TString v) - { - AddDim(v); - return *this; - } - JTH1Derived& operator<<(T v) - { - SetTemplate(&v); - return *this; - } - void SetWith(JTH1Derived& v, TString name, TString title = "") - { - SetTemplate(v.GetTemplatePtr()); - fName = name; - fTitle = title; - GetTemplatePtr()->SetName(name); - GetTemplatePtr()->SetTitle(title); - for (int i = 0; i < v.Dimension(); i++) - AddDim(v.GetBinPtr(i)); - AddDim("END"); - } - void SetWith(JTH1Derived& v, T tem) - { - SetTemplate(&tem); - for (int i = 0; i < v.Dimension(); i++) - AddDim(v.GetBinPtr(i)); - AddDim("END"); - } - - protected: - JTH1DerivedPlayer fPlayer; -}; - -////////////////////////////////////////////////////////////////////////// -// JTH1DerivedPlayer // -////////////////////////////////////////////////////////////////////////// -template -class JTH1DerivedPlayer -{ - public: - explicit JTH1DerivedPlayer(JTH1Derived* cmd) : fLevel(0), fCMD(cmd) {} - JTH1DerivedPlayer& operator[](int i) - { - if (fLevel > fCMD->Dimension()) { - JERROR("Exceed Dimension"); - } - if (OutOf(i, 0, fCMD->SizeOf(fLevel) - 1)) { - JERROR("wrong Index %d of %dth in %s", i, fLevel, fCMD->GetName().Data()); - } - fCMD->SetIndex(i, fLevel++); - return *this; - } - void Init() - { - fLevel = 0; - fCMD->ClearIndex(); - } - T* operator->() { return static_cast(fCMD->GetItem()); } - operator T*() { return static_cast(fCMD->GetItem()); } - operator TObject*() { return static_cast(fCMD->GetItem()); } - operator TH1*() { return static_cast(fCMD->GetItem()); } - - private: - int fLevel; - JTH1Derived* fCMD; -}; - -typedef JTH1Derived JTH1D; -typedef JTH1Derived JTH2D; -typedef JTH1Derived JTH3D; -typedef JTH1Derived JTProfile; - -////////////////////////////////////////////////////////////////////////// -// // -// JHistManager // -// // -// Array Base Class // -// // -////////////////////////////////////////////////////////////////////////// -class JHistManager : public JNamed -{ - public: - explicit JHistManager(TString name, TString dirname = ""); - explicit JHistManager(const JHistManager& obj); - JHistManager& operator=(const JHistManager& obj); - void Add(JBin* o); - void Add(JTH1* o); - - UInt_t GetNBin() { return fBin.size() > fBinNames.size() ? fBin.size() : fBinNames.size(); } // TODO - UInt_t GetNHist() { return fHist.size() > fHistNames.size() ? fHist.size() : fHistNames.size(); } // TODO - void Print(); - int LoadConfig(); - TDirectory* GetDirectory() { return fDirectory; } - void SetDirectory(TDirectory* d) { fDirectory = d; } - static JHistManager* GlobalManager(); - static JHistManager* CurrentManager(JHistManager* hmg = NULL); - JHistManager* cd() { return JHistManager::CurrentManager(this); } - void SetLoadMode(bool b = true) { fIsLoadMode = b; } - bool IsLoadMode() { return fIsLoadMode; } - TString GetString() - { - TString st; - for (UInt_t i = 0; i < GetNBin(); i++) - st += fBin[i]->GetString() + "\n"; - for (UInt_t i = 0; i < GetNHist(); i++) { - st += fHist[i]->GetString() + "\n"; - } - return st; - } - void Write(); - void WriteConfig(); - - JBin* GetBin(TString name); - JBin* GetBuiltBin(TString name); - JTH1* GetTH1(TString name); - JTH1* GetBuiltTH1(TString name); - JTProfile& GetTProfile(TString name) { return dynamic_cast(*GetTH1(name)); } - JTH1D& GetTH1D(TString name) { return dynamic_cast(*GetTH1(name)); } - JTH2D& GetTH2D(TString name) { return dynamic_cast(*GetTH1(name)); } - JTH3D& GetTH3D(TString name) { return dynamic_cast(*GetTH1(name)); } - bool fIsLoadMode; - - TString GetHistName(int i) { return fHistNames[i]; } - - JTH1* GetJTH1(int i) { return GetTH1(fHistNames[i]); } - int GetNJTH1() { return fHistNames.size(); } - bool HistogramExists(TString name); - - private: - TDirectory* fDirectory; - TString fConfigStr; - std::vector fBin; - std::vector fHist; - std::vector fManager; - std::vector fBinNames; - std::vector fBinConfigs; - std::vector fHistNames; - std::vector fHistConfigs; -}; - -#endif // PWGCF_JCORRAN_CORE_JHISTMANAGER_H_ diff --git a/PWGCF/JCorran/Core/JQVectors.h b/PWGCF/JCorran/Core/JQVectors.h index 884840010bf..c96aac454b7 100644 --- a/PWGCF/JCorran/Core/JQVectors.h +++ b/PWGCF/JCorran/Core/JQVectors.h @@ -44,9 +44,11 @@ class JQVectors : public std::conditional_t, JQ using hasWeightNUA = decltype(std::declval().weightNUA()); template using hasWeightEff = decltype(std::declval().weightEff()); + template + using hasInvMass = decltype(std::declval().invMass()); template - inline void Calculate(JInputClass& inputInst, float etamin, float etamax) + inline void Calculate(JInputClass& inputInst, float etamin, float etamax, float massMin = 0.0f, float massMax = 999.9f) { // calculate Q-vector for QC method ( no subgroup ) for (UInt_t ih = 0; ih < nh; ++ih) { @@ -61,6 +63,11 @@ class JQVectors : public std::conditional_t, JQ for (auto& track : inputInst) { if (track.eta() < -etamax || track.eta() > etamax) continue; + using JInputClassIter = typename JInputClass::iterator; + if constexpr (std::experimental::is_detected::value) { + if (track.invMass() < massMin || track.invMass() >= massMax) + continue; + } UInt_t isub = (UInt_t)(track.eta() > 0.0); for (UInt_t ih = 0; ih < nh; ++ih) { @@ -74,7 +81,6 @@ class JQVectors : public std::conditional_t, JQ this->QvectorQCgap[isub][ih][ik] += q; } - using JInputClassIter = typename JInputClass::iterator; if constexpr (std::experimental::is_detected::value) tf /= track.weightNUA(); if constexpr (std::experimental::is_detected::value) diff --git a/PWGCF/JCorran/DataModel/JCatalyst.h b/PWGCF/JCorran/DataModel/JCatalyst.h index 076ac1d06b7..71797429589 100644 --- a/PWGCF/JCorran/DataModel/JCatalyst.h +++ b/PWGCF/JCorran/DataModel/JCatalyst.h @@ -42,6 +42,21 @@ DECLARE_SOA_TABLE(JTracks, "AOD", "JTRACK", //! Reduced track table jtrack::JCollisionId, jtrack::Pt, jtrack::Eta, jtrack::Phi, jtrack::Sign); using JTrack = JTracks::iterator; + +namespace jweight +{ +DECLARE_SOA_COLUMN(WeightNUA, weightNUA, float); //! Non-uniform acceptance weight +DECLARE_SOA_COLUMN(WeightEff, weightEff, float); //! Non-uniform efficiency weight +} // namespace jweight +DECLARE_SOA_TABLE(JWeights, "AOD", "JWEIGHT", jweight::WeightNUA, jweight::WeightEff); //! JFluc table for weights + +namespace j2prongweight +{ +DECLARE_SOA_COLUMN(WeightNUA, weightNUA, float); //! Non-uniform acceptance weight +DECLARE_SOA_COLUMN(WeightEff, weightEff, float); //! Non-uniform efficiency weight +} // namespace j2prongweight +DECLARE_SOA_TABLE(J2ProngWeights, "AOD", "J2PRONGWEIGHT", j2prongweight::WeightNUA, j2prongweight::WeightEff); //! JFluc table for weights, associated with 2Prong particles + } // namespace o2::aod #endif // PWGCF_JCORRAN_DATAMODEL_JCATALYST_H_ diff --git a/PWGCF/JCorran/Tasks/CMakeLists.txt b/PWGCF/JCorran/Tasks/CMakeLists.txt index dc7b95bc5d7..465083509d0 100644 --- a/PWGCF/JCorran/Tasks/CMakeLists.txt +++ b/PWGCF/JCorran/Tasks/CMakeLists.txt @@ -13,3 +13,33 @@ o2physics_add_dpl_workflow(jfluc-analysis SOURCES jflucAnalysisTask.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::JCorran COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jfluc-weights-loader + SOURCES jflucWeightsLoader.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::JCorran + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-spc + SOURCES flowJSPCAnalysis.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::JCorran + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-nuacreation + SOURCES flowJNUACreation.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::JCorran + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(epflow-analysis + SOURCES jEPFlowAnalysis.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::JCorran + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(epdzeroflow-analysis + SOURCES jEPDzeroFlowAnalysis.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(j-fluc-efficiency-task + SOURCES jFlucEfficiencyTask.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::JCorran + COMPONENT_NAME Analysis) diff --git a/PWGCF/JCorran/Tasks/flowJNUACreation.cxx b/PWGCF/JCorran/Tasks/flowJNUACreation.cxx new file mode 100644 index 00000000000..31edc2a7c3d --- /dev/null +++ b/PWGCF/JCorran/Tasks/flowJNUACreation.cxx @@ -0,0 +1,150 @@ +// 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 Task for the NUA correction with filtered data. +// \author Maxim Virta (maxim.virta@cern.ch) + +// Standard headers. +#include +#include +#include +#include + +// O2 headers. // +// The first two are mandatory. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "CCDB/BasicCCDBManager.h" +#include "Framework/HistogramRegistry.h" + +// O2 Physics headers. // +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGCF/JCorran/Core/FlowJHistManager.h" + +// Namespaces and definitions. +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace std; + +using MyCollisions = soa::Join; + +using MyTracks = soa::Join; + +struct flowJNUACreation { + HistogramRegistry qaHistRegistry{"qaHistRegistry", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + FlowJHistManager histManager; + + // Set Configurables here + struct : ConfigurableGroup { + Configurable cfgPtMin{"cfgPtMin", 0.2f, "Minimum pT used for track selection."}; + Configurable cfgPtMax{"cfgPtMax", 5.0f, "Maximum pT used for track selection."}; + Configurable cfgEtaMax{"cfgEtaMax", 1.f, "Maximum eta used for track selection."}; + } cfgTrackCuts; + + // The centrality estimators are the ones available for Run 3. + enum centEstimators { FT0M, + FT0A, + FT0C, + FDDM, + NTPV }; + struct : ConfigurableGroup { + Configurable cfgCentEst{"cfgCentEst", 2, "Centrality estimator."}; + Configurable cfgZvtxMax{"cfgZvtxMax", 15.0f, "Maximum primary vertex cut applied for the events."}; + Configurable cfgMultMin{"cfgMultMin", 10, "Minimum number of particles required for the event to have."}; + } cfgEventCuts; + + // Set the access to the CCDB for the NUA/NUE weights. + struct : ConfigurableGroup { + Configurable cfgURL{"cfgURL", "http://alice-ccdb.cern.ch", + "Address of the CCDB to get the NUA/NUE."}; + Configurable cfgTime{"ccdb-no-later-than", + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), + "Latest acceptable timestamp of creation for the object."}; + } cfgCCDB; + Service ccdb; + + // // Filters to be applied to the received data. + // // The analysis assumes the data has been subjected to a QA of its selection, + // // and thus only the final distributions of the data for analysis are saved. + Filter collFilter = (nabs(aod::collision::posZ) < cfgEventCuts.cfgZvtxMax); + Filter trackFilter = (aod::track::pt > cfgTrackCuts.cfgPtMin) && (aod::track::pt < cfgTrackCuts.cfgPtMax) && (nabs(aod::track::eta) < cfgTrackCuts.cfgEtaMax); + + void init(InitContext const&) + { + // Add histomanager here + histManager.setHistRegistryQA(&qaHistRegistry); + histManager.setDebugLog(false); + histManager.setObtainNUA(true); + histManager.createHistQA(); + + // Add CCDB access here + ccdb->setURL(cfgCCDB.cfgURL); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(cfgCCDB.cfgTime.value); + } + + void process(soa::Filtered::iterator const& coll, soa::Filtered const& tracks) + { + if (tracks.size() < cfgEventCuts.cfgMultMin) + return; + + float cent = -1.; + switch (cfgEventCuts.cfgCentEst) { + case FT0M: + cent = coll.centFT0M(); + break; + case FT0A: + cent = coll.centFT0A(); + break; + case FT0C: + cent = coll.centFT0C(); + break; + case FDDM: + cent = coll.centFDDM(); + break; + case NTPV: + cent = coll.centNTPV(); + break; + } + if (cent < 0. || cent > 70.) { + return; + } + Int_t cBin = histManager.getCentBin(cent); + int nTracks = tracks.size(); + + for (auto& track : tracks) { + histManager.fillTrackQA<1>(track, cBin, 1., 1., coll.posZ()); + } + histManager.fillEventQA<1>(coll, cBin, cent, nTracks); + + LOGF(info, "Collision analysed. Next..."); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx new file mode 100644 index 00000000000..2ce4568348f --- /dev/null +++ b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx @@ -0,0 +1,168 @@ +// 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 Task for the calculation of SPC with filtered data. +// \author Maxim Virta (maxim.virta@cern.ch), Cindy Mordasini (cindy.mordasini@cern.ch) + +// Standard headers. +#include +#include +#include +#include + +// O2 headers. // +// The first two are mandatory. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/HistogramRegistry.h" + +// O2 Physics headers. // +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGCF/DataModel/CorrelationsDerived.h" +#include "PWGCF/JCorran/DataModel/JCatalyst.h" +#include "PWGCF/JCorran/Core/FlowJSPCAnalysis.h" +#include "PWGCF/JCorran/Core/FlowJSPCObservables.h" +#include "PWGCF/JCorran/Core/FlowJHistManager.h" + +// Namespaces and definitions. +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using MyCollisions = soa::Join; + +using MyTracks = soa::Join; + +struct flowJSPCAnalysis { + HistogramRegistry spcHistograms{"SPCResults", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + FlowJSPCAnalysis spcAnalysis; + FlowJSPCAnalysis::JQVectorsT jqvecs; + template + using HasWeightNUA = decltype(std::declval().weightNUA()); + + HistogramRegistry qaHistRegistry{"qaHistRegistry", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + FlowJHistManager histManager; + + FlowJSPCObservables spcObservables; + + // Set Configurables here + Configurable cfgFillQA{"cfgFillQA", true, "Fill QA plots"}; + + Configurable cfgWhichSPC{"cfgWhichSPC", 0, "Which SPC observables to compute."}; + + struct : ConfigurableGroup { + Configurable cfgPtMin{"cfgPtMin", 0.2f, "Minimum pT used for track selection."}; + Configurable cfgPtMax{"cfgPtMax", 5.0f, "Maximum pT used for track selection."}; + Configurable cfgEtaMax{"cfgEtaMax", 0.8f, "Maximum eta used for track selection."}; + } cfgTrackCuts; + + struct : ConfigurableGroup { + Configurable cfgCentEst{"cfgCentEst", 2, "Centrality estimator."}; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.0f, "Maximum primary vertex cut applied for the events."}; + Configurable cfgMultMin{"cfgMultMin", 10, "Minimum number of particles required for the event to have."}; + } cfgEventCuts; + + // // Filters to be applied to the received data. + // // The analysis assumes the data has been subjected to a QA of its selection, + // // and thus only the final distributions of the data for analysis are saved. + Filter collFilter = (nabs(aod::collision::posZ) < cfgEventCuts.cfgZvtxMax); + Filter trackFilter = (aod::track::pt > cfgTrackCuts.cfgPtMin) && (aod::track::pt < cfgTrackCuts.cfgPtMax) && (nabs(aod::track::eta) < cfgTrackCuts.cfgEtaMax); + Filter cftrackFilter = (aod::cftrack::pt > cfgTrackCuts.cfgPtMin) && (aod::cftrack::pt < cfgTrackCuts.cfgPtMax); // eta cuts done by jfluc + + void init(InitContext const&) + { + // Add histomanager here + spcAnalysis.setHistRegistry(&spcHistograms); + spcAnalysis.createHistos(); + + spcObservables.setSPCObservables(cfgWhichSPC); + spcAnalysis.setFullCorrSet(spcObservables.harmonicArray); + + histManager.setHistRegistryQA(&qaHistRegistry); + histManager.setDebugLog(false); + histManager.createHistQA(); + } + + template + void analyze(CollisionT const& collision, TrackT const& tracks) + // void process(soa::Filtered::iterator const& coll, soa::Filtered> const& tracks) + { + if (tracks.size() < cfgEventCuts.cfgMultMin) + return; + + float cent = collision.multiplicity(); + if (cent < 0. || cent > 100.) { + return; + } + int cBin = histManager.getCentBin(cent); + spcHistograms.fill(HIST("FullCentrality"), cent); + int nTracks = tracks.size(); + for (const auto& track : tracks) { + if (cfgFillQA) { + // histManager.FillTrackQA<0>(track, cBin, collision.posZ()); + + using JInputClassIter = typename TrackT::iterator; + if constexpr (std::experimental::is_detected::value) { + spcAnalysis.fillQAHistograms(cBin, track.phi(), 1. / track.weightNUA()); + } + } + } + + if (cfgFillQA) + histManager.fillEventQA<1>(collision, cBin, cent, nTracks); + + jqvecs.Calculate(tracks, 0.0, cfgTrackCuts.cfgEtaMax); + spcAnalysis.setQvectors(&jqvecs); + spcAnalysis.calculateCorrelators(cBin); + } + + void processJDerived(aod::JCollision const& collision, soa::Filtered const& tracks) + { + analyze(collision, tracks); + } + PROCESS_SWITCH(flowJSPCAnalysis, processJDerived, "Process derived data", false); + + void processJDerivedCorrected(aod::JCollision const& collision, soa::Filtered> const& tracks) + { + analyze(collision, tracks); + } + PROCESS_SWITCH(flowJSPCAnalysis, processJDerivedCorrected, "Process derived data with corrections", false); + + void processCFDerived(aod::CFCollision const& collision, soa::Filtered const& tracks) + { + analyze(collision, tracks); + } + PROCESS_SWITCH(flowJSPCAnalysis, processCFDerived, "Process CF derived data", false); + + void processCFDerivedCorrected(aod::CFCollision const& collision, soa::Filtered> const& tracks) + { + analyze(collision, tracks); + } + PROCESS_SWITCH(flowJSPCAnalysis, processCFDerivedCorrected, "Process CF derived data with corrections", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/JCorran/Tasks/jEPDzeroFlowAnalysis.cxx b/PWGCF/JCorran/Tasks/jEPDzeroFlowAnalysis.cxx new file mode 100644 index 00000000000..be132b44684 --- /dev/null +++ b/PWGCF/JCorran/Tasks/jEPDzeroFlowAnalysis.cxx @@ -0,0 +1,222 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// \author junlee.kim@cern.ch +/// \since Jul 2024 + +#include +#include +#include +#include +#include +#include +#include + +#include "TLorentzVector.h" +#include "TRandom3.h" +#include "TF1.h" +#include "TVector2.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/StaticFor.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Qvectors.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/EventPlaneHelper.h" + +#include "CommonConstants/PhysicsConstants.h" + +#include "ReconstructionDataFormats/Track.h" + +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" + +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" + +#include "PWGCF/DataModel/CorrelationsDerived.h" + +using namespace std; +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; + +struct jEPDzeroFlowAnalysis { + enum { + kFT0C = 0, + kFT0A = 1, + kFT0M, + kFV0A, + kTPCpos, + kTPCneg, + kTPCall + }; + + using MyCollisions = soa::Join; + HistogramRegistry histos{ + "histos", + {}, + OutputObjHandlingPolicy::AnalysisObject}; + + Configurable cfgCentSel{"cfgCentSel", 80., "Centrality selection"}; + Configurable cfgCentEst{"cfgCentEst", "FT0C", "Centrality estimator; FT0M or FT0C available"}; + + Configurable cfgPVSel{"cfgPVSel", false, "Additional PV selection flag for syst"}; + Configurable cfgPV{"cfgPV", 8.0, "Additional PV selection range for syst"}; + Configurable cfgAddEvtSelPileup{"cfgAddEvtSelPileup", false, "flag for additional pileup selection"}; + Configurable cfgMaxOccupancy{"cfgMaxOccupancy", 999999, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable cfgMinOccupancy{"cfgMinOccupancy", 0, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + + Configurable cfgnMods{"cfgnMods", 1, "The number of modulations of interest starting from 2"}; + Configurable cfgNQvec{"cfgNQvec", 7, "The number of total Qvectors for looping over the task"}; + + Configurable cfgEtaMax{"cfgEtaMax", 0.8, "eta selection"}; + Configurable cfgPtMin{"cfgPtMin", 0.0, "pt selection"}; + + Configurable cfgDetName{"cfgDetName", "FT0C", "The name of detector to be analyzed"}; + Configurable cfgRefAName{"cfgRefAName", "TPCPos", "The name of detector for reference A"}; + Configurable cfgRefBName{"cfgRefBName", "TPCNeg", "The name of detector for reference B"}; + + ConfigurableAxis massAxis{"massAxis", {175, 1.7, 2.05}, "Invariant mass axis"}; + ConfigurableAxis ptAxis{"ptAxis", {VARIABLE_WIDTH, 0.2, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.5, 8.0, 10.0, 100.0}, "Transverse momentum bins"}; + ConfigurableAxis centAxis{"centAxis", {VARIABLE_WIDTH, 0, 10, 20, 30, 40, 50, 60, 70, 80, 100}, "Centrality interval"}; + ConfigurableAxis cosAxis{"cosAxis", {110, -1.05, 1.05}, "Cosine axis"}; + + // Filter track2pFilter = (nabs(aod::cf2prongtrack::eta) < cfgEtaMax) && (aod::cf2prongtrack::pt > cfgPtMin); + + EventPlaneHelper helperEP; + + int DetId; + int RefAId; + int RefBId; + + float centrality; + + template + using hasInvMass = decltype(std::declval().invMass()); + + template + int GetDetId(const T& name) + { + if (name.value == "FT0C") { + return kFT0C; + } else if (name.value == "FT0A") { + return kFT0A; + } else if (name.value == "FT0M") { + return kFT0M; + } else if (name.value == "FV0A") { + return kFV0A; + } else if (name.value == "TPCpos") { + return kTPCpos; + } else if (name.value == "TPCneg") { + return kTPCneg; + } else if (name.value == "TPCall") { + return kTPCall; + } else { + return 0; + } + } + + template + bool eventSelected(TCollision collision) + { + if (!collision.sel8()) { + return false; + } + if (cfgCentSel < centrality) { + return false; + } + if (!collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (!collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (cfgPVSel && std::abs(collision.posZ()) > cfgPV) { + return false; + } + if (cfgAddEvtSelPileup && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if (collision.trackOccupancyInTimeRange() > cfgMaxOccupancy || collision.trackOccupancyInTimeRange() < cfgMinOccupancy) { + return false; + } + return true; + } // event selection + + template + void fillHistosFlow(const CollType& coll, TrackType& trks) + { + if (coll.qvecAmp()[DetId] < 1e-4 || coll.qvecAmp()[RefAId] < 1e-4 || coll.qvecAmp()[RefBId] < 1e-4) { + return; + } + int DetInd = DetId * 4 + cfgNQvec * 4; + // int RefAInd = RefAId * 4 + cfgNQvec * 4; + // int RefBInd = RefBId * 4 + cfgNQvec * 4; + for (auto& trk : trks) { + histos.fill(HIST("hist_EP_cos_Det_v2"), trk.invMass(), trk.pt(), std::cos(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[DetInd + 3], coll.qvecIm()[DetInd + 3], 2))), centrality); + histos.fill(HIST("hist_EP_sin_Det_v2"), trk.invMass(), trk.pt(), std::sin(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecRe()[DetInd + 3], coll.qvecIm()[DetInd + 3], 2))), centrality); + } + } + + void init(InitContext const&) + { + DetId = GetDetId(cfgDetName); + RefAId = GetDetId(cfgRefAName); + RefBId = GetDetId(cfgRefBName); + + if (DetId == RefAId || DetId == RefBId || RefAId == RefBId) { + LOGF(fatal, "Wrong detector configuration \n set the systems correctly"); + DetId = 0; + RefAId = 4; + RefBId = 5; + } + + histos.add(Form("hist_EP_cos_Det_v2"), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add(Form("hist_EP_sin_Det_v2"), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + } + + void processData(MyCollisions::iterator const& collision, aod::CF2ProngTracks const& p2tracks) + { + if (cfgCentEst.value == "FT0C") { + centrality = collision.centFT0C(); + } else if (cfgCentEst.value == "FT0M") { + centrality = collision.centFT0M(); + } + if (!eventSelected(collision)) { + return; + } + fillHistosFlow(collision, p2tracks); + } + PROCESS_SWITCH(jEPDzeroFlowAnalysis, processData, "Process Event for data", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/JCorran/Tasks/jEPFlowAnalysis.cxx b/PWGCF/JCorran/Tasks/jEPFlowAnalysis.cxx new file mode 100644 index 00000000000..f3f43744f19 --- /dev/null +++ b/PWGCF/JCorran/Tasks/jEPFlowAnalysis.cxx @@ -0,0 +1,132 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// \author Maxim Virta (maxim.virta@cern.ch) +/// \since Jul 2024 + +#include "Framework/AnalysisTask.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelection.h" +#include "Framework/runDataProcessing.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Common/DataModel/Qvectors.h" +#include "Common/Core/EventPlaneHelper.h" + +#include "FlowJHistManager.h" +#include "JEPFlowAnalysis.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace std; + +using MyCollisions = soa::Join; + +using MyTracks = aod::Tracks; + +struct jEPFlowAnalysis { + + HistogramRegistry EPFlowHistograms{"EPFlow", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + JEPFlowAnalysis epAnalysis; + EventPlaneHelper helperEP; + FlowJHistManager histManager; + Bool_t debug = kFALSE; + + // Set Configurables here + struct : ConfigurableGroup { + Configurable cfgPtMin{"cfgPtMin", 0.2f, "Minimum pT used for track selection."}; + Configurable cfgPtMax{"cfgPtMax", 5.0f, "Maximum pT used for track selection."}; + Configurable cfgEtaMax{"cfgEtaMax", 1.f, "Maximum eta used for track selection."}; + } cfgTrackCuts; + + Configurable cfgAddEvtSel{"cfgAddEvtSel", true, "Use event selection"}; + Configurable cfgnTotalSystem{"cfgnTotalSystem", 7, "Total number of detectors in qVectorsTable"}; + + Configurable cfgDetName{"cfgDetName", "FT0C", "The name of detector to be analyzed"}; + Configurable cfgRefAName{"cfgRefAName", "TPCPos", "The name of detector for reference A"}; + Configurable cfgRefBName{"cfgRefBName", "TPCNeg", "The name of detector for reference B"}; + + Filter trackFilter = (aod::track::pt > cfgTrackCuts.cfgPtMin) && (aod::track::pt < cfgTrackCuts.cfgPtMax) && (nabs(aod::track::eta) < cfgTrackCuts.cfgEtaMax); + + int DetId; + int RefAId; + int RefBId; + int harmInd; + + template + int GetDetId(const T& name) + { + if (name.value == "FT0C") { + return 0; + } else if (name.value == "FT0A") { + return 1; + } else if (name.value == "FT0M") { + return 2; + } else if (name.value == "FV0A") { + return 3; + } else if (name.value == "TPCPos") { + return 4; + } else if (name.value == "TPCNeg") { + return 5; + } else if (name.value == "TPCTot") { + return 6; + } else { + return 0; + } + } + + void init(InitContext const&) + { + DetId = GetDetId(cfgDetName); + RefAId = GetDetId(cfgRefAName); + RefBId = GetDetId(cfgRefBName); + + epAnalysis.SetHistRegistry(&EPFlowHistograms); + epAnalysis.CreateHistograms(); + } + + void process(MyCollisions::iterator const& coll, soa::Filtered const& tracks) + { + if (cfgAddEvtSel && (!coll.sel8() || !coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !coll.selection_bit(aod::evsel::kNoSameBunchPileup))) + return; + + Float_t cent = coll.cent(); + EPFlowHistograms.fill(HIST("FullCentrality"), cent); + Float_t EPs[3] = {0.}; + for (int i = 2; i < 5; i++) { // loop over different harmonic orders + harmInd = cfgnTotalSystem * 4 * (i - 2) + 3; // harmonic index to access corresponding Q-vector as all Q-vectors are in same vector + EPs[0] = helperEP.GetEventPlane(coll.qvecRe()[DetId + harmInd], coll.qvecIm()[DetId + harmInd], i); + EPs[1] = helperEP.GetEventPlane(coll.qvecRe()[RefAId + harmInd], coll.qvecIm()[RefAId + harmInd], i); + EPs[2] = helperEP.GetEventPlane(coll.qvecRe()[RefBId + harmInd], coll.qvecIm()[RefBId + harmInd], i); + + Float_t resNumA = helperEP.GetResolution(EPs[0], EPs[1], i); + Float_t resNumB = helperEP.GetResolution(EPs[0], EPs[2], i); + Float_t resDenom = helperEP.GetResolution(EPs[1], EPs[2], i); + epAnalysis.FillResolutionHistograms(cent, static_cast(i), resNumA, resNumB, resDenom); + for (uint j = 0; j < 3; j++) { // loop over detectors used + for (auto& track : tracks) { + Float_t vn = TMath::Cos((i) * (track.phi() - EPs[j])); + Float_t vn_sin = TMath::Sin((i) * (track.phi() - EPs[j])); + epAnalysis.FillVnHistograms(i, cent, static_cast(j + 1), track.pt(), vn, vn_sin); + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/JCorran/Tasks/jFlucEfficiencyTask.cxx b/PWGCF/JCorran/Tasks/jFlucEfficiencyTask.cxx new file mode 100644 index 00000000000..59ca8b18903 --- /dev/null +++ b/PWGCF/JCorran/Tasks/jFlucEfficiencyTask.cxx @@ -0,0 +1,659 @@ +// 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 jFlucEfficiencyTask.cxx +/// \brief Task to calculate the efficiency of the cf-derived tracks/particles +/// \author DongJo Kim, Jasper Parkkila, Bong-Hwi Lim (djkim@cern.ch, jparkkil@cern.ch, bong-hwi.lim@cern.ch) +/// \since March 2024 + +#include +#include +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGCF/DataModel/CorrelationsDerived.h" +#include "PWGLF/Utils/collisionCuts.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::rctsel; + +struct JFlucEfficiencyTask { + Service pdg; + // Add the pT binning array as a static member + static constexpr std::array PttJacek = { + 0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, + 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, + 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, + 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, + 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 8.0, 9.0, 10.0, + 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 18.0, 20.0, 22.0, 24.0, + 26.0, 28.0, 30.0, 32.0, 34.0, 36.0, 40.0, 45.0, 50.0, 60.0, + 70.0, 80.0, 90.0, 100.0, 110.0, 120.0, 130.0, 140.0, 150.0, 160.0, + 170.0, 180.0, 190.0, 200.0, 210.0, 220.0, 230.0, 240.0, 250.0, 260.0, + 270.0, 280.0, 290.0, 300.0}; + + // Update the axisPt configuration with proper vector initialization + ConfigurableAxis axisPt{"axisPt", std::vector(PttJacek.begin(), PttJacek.end()), "pT axis"}; + + // Event cuts + Configurable cfgAcceptSplitCollisions{"cfgAcceptSplitCollisions", 0, "0: only look at mcCollisions that are not split; 1: accept split mcCollisions, 2: accept split mcCollisions but only look at the first reco collision associated with it"}; + o2::analysis::CollisonCuts colCuts; + struct : ConfigurableGroup { + Configurable cfgEvtZvtx{"cfgEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; + Configurable cfgCentMin{"cfgCentMin", 0.0f, "Min centrality"}; + Configurable cfgCentMax{"cfgCentMax", 100.0f, "Max centrality"}; + Configurable cfgEvtOccupancyInTimeRangeMax{"cfgEvtOccupancyInTimeRangeMax", -1, "Evt sel: maximum track occupancy"}; + Configurable cfgEvtOccupancyInTimeRangeMin{"cfgEvtOccupancyInTimeRangeMin", -1, "Evt sel: minimum track occupancy"}; + Configurable cfgEvtTriggerCheck{"cfgEvtTriggerCheck", false, "Evt sel: check for trigger"}; + Configurable cfgEvtOfflineCheck{"cfgEvtOfflineCheck", true, "Evt sel: check for offline selection"}; + Configurable cfgEvtTriggerTVXSel{"cfgEvtTriggerTVXSel", false, "Evt sel: triggerTVX selection (MB)"}; + Configurable cfgEvtTFBorderCut{"cfgEvtTFBorderCut", false, "Evt sel: apply TF border cut"}; + Configurable cfgEvtUseITSTPCvertex{"cfgEvtUseITSTPCvertex", false, "Evt sel: use at lease on ITS-TPC track for vertexing"}; + Configurable cfgEvtZvertexTimedifference{"cfgEvtZvertexTimedifference", true, "Evt sel: apply Z-vertex time difference"}; + Configurable cfgEvtPileupRejection{"cfgEvtPileupRejection", true, "Evt sel: apply pileup rejection"}; + Configurable cfgEvtNoITSROBorderCut{"cfgEvtNoITSROBorderCut", false, "Evt sel: apply NoITSRO border cut"}; + Configurable cfgEvtCollInTimeRangeStandard{"cfgEvtCollInTimeRangeStandard", true, "Evt sel: apply NoCollInTimeRangeStandard"}; + Configurable cfgEvtRun2AliEventCuts{"cfgEvtRun2AliEventCuts", true, "Evt sel: apply Run2 Ali event cuts"}; + Configurable cfgEvtRun2INELgtZERO{"cfgEvtRun2INELgtZERO", false, "Evt sel: apply Run2 INEL>0 event cuts"}; + Configurable cfgEvtUseRCTFlagChecker{"cfgEvtUseRCTFlagChecker", false, "Evt sel: use RCT flag checker"}; + Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; + Configurable cfgEvtRCTFlagCheckerZDCCheck{"cfgEvtRCTFlagCheckerZDCCheck", false, "Evt sel: RCT flag checker ZDC check"}; + Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", false, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } EventCuts; + RCTFlagsChecker rctChecker; + + // Track selections + struct : ConfigurableGroup { + Configurable cfgMinPt{"cfgMinPt", 0.6, "Track minium pt cut"}; + Configurable cfgMaxPt{"cfgMaxPt", 300.0f, "Maximum transverse momentum"}; + Configurable cfgEtaMin{"cfgEtaMin", -1.0f, "Minimum pseudorapidity"}; + Configurable cfgEtaMax{"cfgEtaMax", 1.0f, "Maximum pseudorapidity"}; + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", false, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", false, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) + Configurable cfgGlobalTrack{"cfgGlobalTrack", true, "Global track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgPVContributor{"cfgPVContributor", false, "PV contributor track selection"}; // PV Contriuibutor + Configurable cfgpTdepDCAxyCut{"cfgpTdepDCAxyCut", false, "pT-dependent DCAxy cut"}; + Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 0, "Number of TPC cluster"}; + Configurable cfgRatioTPCRowsOverFindableCls{"cfgRatioTPCRowsOverFindableCls", 0.0f, "TPC Crossed Rows to Findable Clusters"}; + Configurable cfgITSChi2NCl{"cfgITSChi2NCl", 999.0, "ITS Chi2/NCl"}; + Configurable cfgTPCChi2NCl{"cfgTPCChi2NCl", 999.0, "TPC Chi2/NCl"}; + Configurable cfgUseTPCRefit{"cfgUseTPCRefit", false, "Require TPC Refit"}; + Configurable cfgUseITSRefit{"cfgUseITSRefit", false, "Require ITS Refit"}; + Configurable cfgHasITS{"cfgHasITS", false, "Require ITS"}; + Configurable cfgHasTPC{"cfgHasTPC", false, "Require TPC"}; + Configurable cfgHasTOF{"cfgHasTOF", false, "Require TOF"}; + // DCA to PV + Configurable cfgMaxbDCArToPVcut{"cfgMaxbDCArToPVcut", 0.5, "Track DCAr cut to PV Maximum"}; + Configurable cfgMaxbDCAzToPVcut{"cfgMaxbDCAzToPVcut", 1.0, "Track DCAz cut to PV Maximum"}; + } TrackCuts; + + // Configurable for track selection + Configurable trackSelection{"trackSelection", 0, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; + + // Configurable axes + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}, "multiplicity / centrality axis"}; + + // Filter declarations + Filter cfCollisionFilter = (nabs(aod::collision::posZ) < EventCuts.cfgEvtZvtx); + Filter cfTrackFilter = (aod::cftrack::pt >= TrackCuts.cfgMinPt) && + (aod::cftrack::pt <= TrackCuts.cfgMaxPt) && + (aod::cftrack::eta >= TrackCuts.cfgEtaMin) && + (aod::cftrack::eta <= TrackCuts.cfgEtaMax); + // Filter collisionFilter = (nabs(aod::collision::posZ) < EventCuts.cfgEvtZvtx); + Filter trackFilter = (aod::track::pt >= TrackCuts.cfgMinPt) && + (aod::track::pt <= TrackCuts.cfgMaxPt) && + (aod::track::eta >= TrackCuts.cfgEtaMin) && + (aod::track::eta <= TrackCuts.cfgEtaMax); + + Configurable cfgCentBinsForMC{"cfgCentBinsForMC", 1, "Centrality bins for MC, 0: off, 1: on"}; + using CollisionCandidates = soa::Join; + using CollisionRun2Candidates = soa::Join; + using TrackCandidates = soa::Join; + using MCCollisionCandidates = soa::Join; + using MCRun2CollisionCandidates = soa::Join; + using MCTrackCandidates = soa::Join; + using BCsWithRun2Info = soa::Join; + + // Histogram Registry + HistogramRegistry registry{ + "registry", + {{"hEventCounterMC", "Event counter MC;Counter;Counts", {HistType::kTH1F, {{3, -0.5, 2.5}}}}, + {"hEventCounterReco", "Event counter Reco;Counter;Counts", {HistType::kTH1F, {{3, -0.5, 2.5}}}}, + {"hZVertexMC", "MC Z vertex distribution;Z vertex (cm);Centrality (%)", {HistType::kTH2F, {{200, -20, 20}, {axisMultiplicity}}}}, + {"hZVertexReco", "Reconstructed Z vertex distribution;Z vertex (cm);Centrality (%)", {HistType::kTH2F, {{200, -20, 20}, {axisMultiplicity}}}}, + {"hZVertexCorrelation", "Z vertex correlation;MC Z vertex (cm);Reco Z vertex (cm)", {HistType::kTH2F, {{200, -20, 20}, {200, -20, 20}}}}}}; + + // Configurable for debugging + Configurable debugMode{"debugMode", false, "Debug mode"}; + + void init(InitContext const&) + { + if (debugMode) { + LOGF(info, "Initializing JFlucEfficiencyTask"); + } + if (!doprocessMCRun2 && !doprocessDataRun2) { + colCuts.setCuts(EventCuts.cfgEvtZvtx, EventCuts.cfgEvtTriggerCheck, EventCuts.cfgEvtOfflineCheck, /*checkRun3*/ true, /*triggerTVXsel*/ false, EventCuts.cfgEvtOccupancyInTimeRangeMax, EventCuts.cfgEvtOccupancyInTimeRangeMin); + } else { + colCuts.setCuts(EventCuts.cfgEvtZvtx, EventCuts.cfgEvtTriggerCheck, EventCuts.cfgEvtOfflineCheck, false); + } + colCuts.init(®istry); + colCuts.setTriggerTVX(EventCuts.cfgEvtTriggerTVXSel); + colCuts.setApplyTFBorderCut(EventCuts.cfgEvtTFBorderCut); + colCuts.setApplyITSTPCvertex(EventCuts.cfgEvtUseITSTPCvertex); + colCuts.setApplyZvertexTimedifference(EventCuts.cfgEvtZvertexTimedifference); + colCuts.setApplyPileupRejection(EventCuts.cfgEvtPileupRejection); + colCuts.setApplyNoITSROBorderCut(EventCuts.cfgEvtNoITSROBorderCut); + colCuts.setApplyCollInTimeRangeStandard(EventCuts.cfgEvtCollInTimeRangeStandard); + colCuts.setApplyRun2AliEventCuts(EventCuts.cfgEvtRun2AliEventCuts); + colCuts.setApplyRun2INELgtZERO(EventCuts.cfgEvtRun2INELgtZERO); + colCuts.printCuts(); + + rctChecker.init(EventCuts.cfgEvtRCTFlagCheckerLabel, EventCuts.cfgEvtRCTFlagCheckerZDCCheck, EventCuts.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + + if (doprocessDerivedMC || doprocessMC || doprocessMCRun2) { + registry.add("hPtGen", "Generated p_{T} (all);p_{T} (GeV/c);Centrality (%);Counts", + o2::framework::HistType::kTH2F, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}); + registry.add("hEtaGen", "Generated #eta (all);#eta;Centrality (%);Counts", + o2::framework::HistType::kTH2F, {AxisSpec(100, -1, 1), AxisSpec(axisMultiplicity)}); + registry.add("hPtGenPos", "Generated p_{T} (positive);p_{T} (GeV/c);Centrality (%);Counts", + o2::framework::HistType::kTH2F, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}); + registry.add("hPtGenNeg", "Generated p_{T} (negative);p_{T} (GeV/c);Centrality (%);Counts", + o2::framework::HistType::kTH2F, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}); + } + registry.add("hPtRec", "Reconstructed p_{T} (all);p_{T} (GeV/c);Centrality (%);Counts", + o2::framework::HistType::kTH2F, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}); + registry.add("hEtaRec", "Reconstructed #eta (all);#eta;Centrality (%);Counts", + o2::framework::HistType::kTH2F, {AxisSpec(100, -1, 1), AxisSpec(axisMultiplicity)}); + registry.add("hPtRecPos", "Reconstructed p_{T} (positive);p_{T} (GeV/c);Centrality (%);Counts", + o2::framework::HistType::kTH2F, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}); + registry.add("hPtRecNeg", "Reconstructed p_{T} (negative);p_{T} (GeV/c);Centrality (%);Counts", + o2::framework::HistType::kTH2F, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}); + + if (doprocessEfficiency) { + registry.add("hPtGenData", "Generated p_{T} from data events (all);p_{T} (GeV/c);Centrality (%);Counts", + {HistType::kTH2F, {axisPt, axisMultiplicity}}); + registry.add("hEtaGenData", "Generated #eta from data events (all);#eta;Centrality (%);Counts", + {HistType::kTH2F, {AxisSpec(100, -1, 1), axisMultiplicity}}); + registry.add("hPtGenDataPos", "Generated p_{T} from data events (positive);p_{T} (GeV/c);Centrality (%);Counts", + {HistType::kTH2F, {axisPt, axisMultiplicity}}); + registry.add("hPtGenDataNeg", "Generated p_{T} from data events (negative);p_{T} (GeV/c);Centrality (%);Counts", + {HistType::kTH2F, {axisPt, axisMultiplicity}}); + registry.add("hPtRecData", "Reconstructed p_{T} (all);p_{T} (GeV/c);Centrality (%);Counts", + o2::framework::HistType::kTH2F, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}); + registry.add("hEtaRecData", "Reconstructed #eta (all);#eta;Centrality (%);Counts", + o2::framework::HistType::kTH2F, {AxisSpec(100, -1, 1), AxisSpec(axisMultiplicity)}); + registry.add("hPtRecDataPos", "Reconstructed p_{T} (positive);p_{T} (GeV/c);Centrality (%);Counts", + o2::framework::HistType::kTH2F, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}); + registry.add("hPtRecDataNeg", "Reconstructed p_{T} (negative);p_{T} (GeV/c);Centrality (%);Counts", + o2::framework::HistType::kTH2F, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}); + } + + // Initialize histogram labels + auto h1 = registry.get(HIST("hEventCounterMC")); + auto h2 = registry.get(HIST("hEventCounterReco")); + + if (h1 && h2) { + h1->GetXaxis()->SetBinLabel(1, "All MC Events"); + h1->GetXaxis()->SetBinLabel(2, "Selected MC Events"); + h1->GetXaxis()->SetBinLabel(3, "Analyzed MC Events"); + + h2->GetXaxis()->SetBinLabel(1, "All Reco Events"); + h2->GetXaxis()->SetBinLabel(2, "Selected Reco Events"); + h2->GetXaxis()->SetBinLabel(3, "Analyzed Reco Events"); + } else { + LOGF(error, "Failed to get histograms from registry"); + } + } + + template + double getCharge(ParticleType const& particle) + { + auto pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (!pdgParticle) { + return 10.f; + } + return pdgParticle->Charge(); + } + bool isChargedParticle(int code) + { + auto p = pdg->GetParticle(code); + auto charge = 0.; + if (p != nullptr) { + charge = p->Charge(); + } + return std::abs(charge) >= 3.; + } + // Track selection + template + bool trackCut(TrackType const& track) + { + // basic track cuts + if (std::abs(track.pt()) < TrackCuts.cfgMinPt) + return false; + if (std::abs(track.pt()) > TrackCuts.cfgMaxPt) + return false; + if (track.eta() < TrackCuts.cfgEtaMin) + return false; + if (track.eta() > TrackCuts.cfgEtaMax) + return false; + if (track.itsNCls() < TrackCuts.cfgITScluster) + return false; + if (track.tpcNClsFound() < TrackCuts.cfgTPCcluster) + return false; + if (track.tpcCrossedRowsOverFindableCls() < TrackCuts.cfgRatioTPCRowsOverFindableCls) + return false; + if (track.itsChi2NCl() >= TrackCuts.cfgITSChi2NCl) + return false; + if (track.tpcChi2NCl() >= TrackCuts.cfgTPCChi2NCl) + return false; + if (TrackCuts.cfgHasITS && !track.hasITS()) + return false; + if (TrackCuts.cfgHasTPC && !track.hasTPC()) + return false; + if (TrackCuts.cfgHasTOF && !track.hasTOF()) + return false; + if (TrackCuts.cfgUseITSRefit && !track.passedITSRefit()) + return false; + if (TrackCuts.cfgUseTPCRefit && !track.passedTPCRefit()) + return false; + if (TrackCuts.cfgPVContributor && !track.isPVContributor()) + return false; + if (TrackCuts.cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (TrackCuts.cfgGlobalTrack && !track.isGlobalTrack()) + return false; + if (TrackCuts.cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (TrackCuts.cfgpTdepDCAxyCut) { + // Tuned on the LHC22f anchored MC LHC23d1d on primary pions. 7 Sigmas of the resolution + if (std::abs(track.dcaXY()) > (0.004 + (0.013 / track.pt()))) + return false; + } else { + if (std::abs(track.dcaXY()) > TrackCuts.cfgMaxbDCArToPVcut) + return false; + } + if (std::abs(track.dcaZ()) > TrackCuts.cfgMaxbDCAzToPVcut) + return false; + return true; + } + + void processDerivedMC(soa::Filtered::iterator const& mcCollision, soa::Filtered const& mcParticles) + { + float centrality = mcCollision.multiplicity(); // multiplicity: number of primary particles TODO: apply percentiles + registry.fill(HIST("hEventCounterMC"), 0); + registry.fill(HIST("hZVertexMC"), mcCollision.posZ(), centrality); + + for (const auto& particle : mcParticles) { + if (!particle.isPhysicalPrimary()) { + continue; + } + + registry.fill(HIST("hPtGen"), particle.pt(), centrality); + registry.fill(HIST("hEtaGen"), particle.eta(), centrality); + + if (particle.sign() > 0) { // Positive particles + registry.fill(HIST("hPtGenPos"), particle.pt(), centrality); + } else if (particle.sign() < 0) { // Negative particles + registry.fill(HIST("hPtGenNeg"), particle.pt(), centrality); + } + } + } + + void processDerivedData(soa::Filtered::iterator const& cfCollision, soa::Filtered const& cfTracks) + { + float centrality = cfCollision.multiplicity(); + + if (centrality < EventCuts.cfgCentMin || centrality > EventCuts.cfgCentMax) { + return; + } + registry.fill(HIST("hZVertexReco"), cfCollision.posZ(), centrality); + + for (const auto& track : cfTracks) { + registry.fill(HIST("hPtRec"), track.pt(), centrality); + registry.fill(HIST("hEtaRec"), track.eta(), centrality); + + if (track.sign() > 0) { // Positive tracks + registry.fill(HIST("hPtRecPos"), track.pt(), centrality); + } else if (track.sign() < 0) { // Negative tracks + registry.fill(HIST("hPtRecNeg"), track.pt(), centrality); + } + } + } + + Preslice perCollision = aod::track::collisionId; + void processMC(aod::McCollisions::iterator const& mcCollision, + soa::SmallGroups const& collisions, + soa::Filtered const& mcTracks, + aod::McParticles const& mcParticles) + { + registry.fill(HIST("hEventCounterMC"), 0); + if (!(std::abs(mcCollision.posZ()) < EventCuts.cfgEvtZvtx)) { + return; + } + if (collisions.size() < 1) { + return; + } + if (cfgAcceptSplitCollisions == 0 && collisions.size() > 1) { + return; + } + float centrality = -999; + for (const auto& collision : collisions) { // Anayway only 1 collision per mcCollision will be selected + if (!colCuts.isSelected(collision)) // Default event selection + return; + if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) { + return; + } + colCuts.fillQA(collision); + centrality = collision.centFT0C(); + } + registry.fill(HIST("hEventCounterMC"), 1); + registry.fill(HIST("hZVertexMC"), mcCollision.posZ(), centrality); + if (centrality < EventCuts.cfgCentMin || centrality > EventCuts.cfgCentMax) { + return; + } + for (const auto& particle : mcParticles) { + auto charge = getCharge(particle); + if ((!particle.isPhysicalPrimary()) || !isChargedParticle(particle.pdgCode())) { + continue; + } + // pT and eta selections + if (particle.pt() < TrackCuts.cfgMinPt || particle.pt() > TrackCuts.cfgMaxPt || particle.eta() < TrackCuts.cfgEtaMin || particle.eta() > TrackCuts.cfgEtaMax) { + continue; + } + registry.fill(HIST("hPtGen"), particle.pt(), centrality); + registry.fill(HIST("hEtaGen"), particle.eta(), centrality); + if (charge > 0) { // Positive particles + registry.fill(HIST("hPtGenPos"), particle.pt(), centrality); + } else if (charge < 0) { // Negative particles + registry.fill(HIST("hPtGenNeg"), particle.pt(), centrality); + } + } + // Reconstruct tracks from MC particles + for (const auto& collision : collisions) { + registry.fill(HIST("hZVertexReco"), collision.posZ(), centrality); + registry.fill(HIST("hZVertexCorrelation"), mcCollision.posZ(), collision.posZ()); + auto tracks = mcTracks.sliceBy(perCollision, collision.globalIndex()); + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + continue; + } + if (!trackCut(track)) { + continue; + } + auto mcPart = track.mcParticle(); + if (!mcPart.isPhysicalPrimary() || !isChargedParticle(mcPart.pdgCode())) { + continue; + } + registry.fill(HIST("hPtRec"), track.pt(), centrality); + registry.fill(HIST("hEtaRec"), track.eta(), centrality); + if (track.sign() > 0) { // Positive tracks + registry.fill(HIST("hPtRecPos"), track.pt(), centrality); + } else if (track.sign() < 0) { // Negative tracks + registry.fill(HIST("hPtRecNeg"), track.pt(), centrality); + } + } + } + } + + void processMCRun2(aod::McCollisions::iterator const& mcCollision, + soa::SmallGroups const& collisions, + soa::Filtered const& mcTracks, + aod::McParticles const& mcParticles, + BCsWithRun2Info const&) + { + registry.fill(HIST("hEventCounterMC"), 0); + if (!(std::abs(mcCollision.posZ()) < EventCuts.cfgEvtZvtx)) { + return; + } + if (collisions.size() < 1) { + return; + } + if (cfgAcceptSplitCollisions == 0 && collisions.size() > 1) { + return; + } + float centrality = -999; + for (const auto& collision : collisions) { // Anayway only 1 collision per mcCollision will be selected + if (!colCuts.isSelected(collision)) // Default event selection + return; + colCuts.fillQARun2(collision); + centrality = collision.centRun2V0M(); + } + registry.fill(HIST("hEventCounterMC"), 1); + registry.fill(HIST("hZVertexMC"), mcCollision.posZ(), centrality); + if (centrality < EventCuts.cfgCentMin || centrality > EventCuts.cfgCentMax) { + return; + } + for (const auto& particle : mcParticles) { + auto charge = getCharge(particle); + if ((!particle.isPhysicalPrimary()) || !isChargedParticle(particle.pdgCode())) { + continue; + } + // pT and eta selections + if (particle.pt() < TrackCuts.cfgMinPt || particle.pt() > TrackCuts.cfgMaxPt || particle.eta() < TrackCuts.cfgEtaMin || particle.eta() > TrackCuts.cfgEtaMax) { + continue; + } + registry.fill(HIST("hPtGen"), particle.pt(), centrality); + registry.fill(HIST("hEtaGen"), particle.eta(), centrality); + if (charge > 0) { // Positive particles + registry.fill(HIST("hPtGenPos"), particle.pt(), centrality); + } else if (charge < 0) { // Negative particles + registry.fill(HIST("hPtGenNeg"), particle.pt(), centrality); + } + } + // Reconstruct tracks from MC particles + for (const auto& collision : collisions) { + registry.fill(HIST("hZVertexReco"), collision.posZ(), centrality); + registry.fill(HIST("hZVertexCorrelation"), mcCollision.posZ(), collision.posZ()); + auto tracks = mcTracks.sliceBy(perCollision, collision.globalIndex()); + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + continue; + } + auto mcPart = track.mcParticle(); + if (!mcPart.isPhysicalPrimary() || !isChargedParticle(mcPart.pdgCode())) { + continue; + } + // pT and eta selections + if (!trackCut(track)) { + continue; + } + registry.fill(HIST("hPtRec"), track.pt(), centrality); + registry.fill(HIST("hEtaRec"), track.eta(), centrality); + if (track.sign() > 0) { // Positive tracks + registry.fill(HIST("hPtRecPos"), track.pt(), centrality); + } else if (track.sign() < 0) { // Negative tracks + registry.fill(HIST("hPtRecNeg"), track.pt(), centrality); + } + } + } + } + + void processData(CollisionCandidates::iterator const& collision, soa::Filtered const& tracks) + { + if (!colCuts.isSelected(collision)) // Default event selection + return; + if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) { + return; + } + colCuts.fillQA(collision); + auto centrality = collision.centFT0C(); + if (centrality < EventCuts.cfgCentMin || centrality > EventCuts.cfgCentMax) { + return; + } + registry.fill(HIST("hZVertexReco"), collision.posZ(), centrality); + for (const auto& track : tracks) { + // pT and eta selections + if (!trackCut(track)) { + continue; + } + registry.fill(HIST("hPtRec"), track.pt(), centrality); + registry.fill(HIST("hEtaRec"), track.eta(), centrality); + if (track.sign() > 0) { // Positive tracks + registry.fill(HIST("hPtRecPos"), track.pt(), centrality); + } else if (track.sign() < 0) { // Negative tracks + registry.fill(HIST("hPtRecNeg"), track.pt(), centrality); + } + } + } + + void processDataRun2(CollisionRun2Candidates::iterator const& collision, soa::Filtered const& tracks, BCsWithRun2Info const&) + { + if (!colCuts.isSelected(collision)) // Default event selection + return; + colCuts.fillQARun2(collision); + auto centrality = collision.centRun2V0M(); + if (centrality < EventCuts.cfgCentMin || centrality > EventCuts.cfgCentMax) { + return; + } + registry.fill(HIST("hZVertexReco"), collision.posZ(), centrality); + for (const auto& track : tracks) { + // pT and eta selections + if (!trackCut(track)) { + continue; + } + registry.fill(HIST("hPtRec"), track.pt(), centrality); + registry.fill(HIST("hEtaRec"), track.eta(), centrality); + if (track.sign() > 0) { // Positive tracks + registry.fill(HIST("hPtRecPos"), track.pt(), centrality); + } else if (track.sign() < 0) { // Negative tracks + registry.fill(HIST("hPtRecNeg"), track.pt(), centrality); + } + } + } + + // NOTE SmallGroups includes soa::Filtered always + Preslice perCFCollision = aod::cftrack::cfCollisionId; + void processEfficiency(soa::Filtered::iterator const& mcCollision, + aod::CFMcParticles const& mcParticles, + soa::SmallGroups const& collisions, + soa::Filtered const& tracks) + { + try { + // Count MC events and fill MC z-vertex with centrality + if (debugMode) { + LOGF(info, "MC collision at vtx-z = %f with %d mc particles and %d reconstructed collisions", mcCollision.posZ(), mcParticles.size(), collisions.size()); + } + auto multiplicity = mcCollision.multiplicity(); + if (cfgCentBinsForMC > 0) { + if (collisions.size() == 0) { + return; + } + for (const auto& collision : collisions) { + multiplicity = collision.multiplicity(); + } + } + if (debugMode) { + LOGF(info, "MC collision multiplicity: %f", multiplicity); + } + registry.fill(HIST("hEventCounterMC"), 0); + registry.fill(HIST("hZVertexMC"), mcCollision.posZ(), multiplicity); + if (debugMode) { + LOGF(info, "Processing MC collision %d at z = %.3f", mcCollision.globalIndex(), mcCollision.posZ()); + } + + // Fill MC particle histograms + for (const auto& mcParticle : mcParticles) { + if (!mcParticle.isPhysicalPrimary() || mcParticle.sign() == 0) { + continue; + } + registry.fill(HIST("hPtGenData"), mcParticle.pt(), multiplicity); + registry.fill(HIST("hEtaGenData"), mcParticle.eta(), multiplicity); + if (mcParticle.sign() > 0) { + registry.fill(HIST("hPtGenDataPos"), mcParticle.pt(), multiplicity); + } else if (mcParticle.sign() < 0) { + registry.fill(HIST("hPtGenDataNeg"), mcParticle.pt(), multiplicity); + } + } + registry.fill(HIST("hEventCounterMC"), 1); + + // Check reconstructed collisions + if (collisions.size() == 0) { + if (debugMode) { + LOGF(info, "No reconstructed collisions found for MC collision %d", mcCollision.globalIndex()); + } + return; + } + + // Process reconstructed events + for (const auto& collision : collisions) { + registry.fill(HIST("hEventCounterReco"), 0); + registry.fill(HIST("hZVertexReco"), collision.posZ(), collision.multiplicity()); + registry.fill(HIST("hZVertexCorrelation"), mcCollision.posZ(), collision.posZ()); + + if (debugMode) { + LOGF(info, "Processing reconstructed collision %d at z = %.3f", + collision.globalIndex(), collision.posZ()); + } + registry.fill(HIST("hEventCounterReco"), 1); + + // Fill track histograms + auto groupedTracks = tracks.sliceBy(perCFCollision, collision.globalIndex()); + if (debugMode) { + LOGF(info, "Reconstructed collision %d has %d tracks", collision.globalIndex(), groupedTracks.size()); + } + for (const auto& track : groupedTracks) { + if (!track.has_cfMCParticle()) { + if (debugMode) { + LOGF(debug, "Track without MC particle found"); + } + continue; + } + // primary particles only + const auto& mcParticle = track.cfMCParticle(); + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + registry.fill(HIST("hPtRecData"), track.pt(), collision.multiplicity()); + registry.fill(HIST("hEtaRecData"), track.eta(), collision.multiplicity()); + if (track.sign() > 0) { + registry.fill(HIST("hPtRecDataPos"), track.pt(), collision.multiplicity()); + } else if (track.sign() < 0) { + registry.fill(HIST("hPtRecDataNeg"), track.pt(), collision.multiplicity()); + } + } + + // Count selected and analyzed events + registry.fill(HIST("hEventCounterReco"), 2); + } + + registry.fill(HIST("hEventCounterMC"), 2); + + } catch (const std::exception& e) { + LOGF(error, "Exception caught in processEfficiency: %s", e.what()); + } catch (...) { + LOGF(error, "Unknown exception caught in processEfficiency"); + } + } + + PROCESS_SWITCH(JFlucEfficiencyTask, processMC, "Process MC only", false); + PROCESS_SWITCH(JFlucEfficiencyTask, processMCRun2, "Process Run2 MC only", false); + PROCESS_SWITCH(JFlucEfficiencyTask, processData, "Process data only", false); + PROCESS_SWITCH(JFlucEfficiencyTask, processDataRun2, "Process Run2 data only", false); + PROCESS_SWITCH(JFlucEfficiencyTask, processDerivedMC, "Process derived MC only", false); + PROCESS_SWITCH(JFlucEfficiencyTask, processDerivedData, "Process derived data only", false); + PROCESS_SWITCH(JFlucEfficiencyTask, processEfficiency, "Process efficiency task", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/JCorran/Tasks/jflucAnalysisTask.cxx b/PWGCF/JCorran/Tasks/jflucAnalysisTask.cxx index 592f3c647fd..6e0ba68d2df 100644 --- a/PWGCF/JCorran/Tasks/jflucAnalysisTask.cxx +++ b/PWGCF/JCorran/Tasks/jflucAnalysisTask.cxx @@ -12,11 +12,7 @@ /// \author Dong Jo Kim (djkim@jyu.fi) /// \since Sep 2022 -#include -#include -#include #include -#include #include "Framework/AnalysisTask.h" #include "Framework/ASoAHelpers.h" @@ -34,181 +30,117 @@ #include "PWGCF/JCorran/DataModel/JCatalyst.h" #include "PWGCF/DataModel/CorrelationsDerived.h" #include "JFFlucAnalysis.h" +#include "JFFlucAnalysisO2Hist.h" +#include "Framework/runDataProcessing.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -void customize(std::vector& workflowOptions) -{ - ConfigParamSpec optionLoadWeights{"loadWeights", VariantType::Bool, false, {"Load correction weights"}}; - workflowOptions.push_back(optionLoadWeights); -} - -#include "Framework/runDataProcessing.h" - #define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; -namespace o2::aod -{ -namespace jweight -{ -DECLARE_SOA_COLUMN(WeightNUA, weightNUA, float); //! Non-uniform acceptance weight -DECLARE_SOA_COLUMN(WeightEff, weightEff, float); //! Non-uniform efficiency weight -} // namespace jweight -DECLARE_SOA_TABLE(JWeights, "AOD", "JWEIGHT", jweight::WeightNUA, jweight::WeightEff); //! JFluc table for weights -} // namespace o2::aod - -// The standalone jfluc code expects the entire list of tracks for an event. At the same time, it expects weights together with other track attributes. -// This workflow creates a table of weights that can be joined with track tables. -struct jflucWeightsLoader { - O2_DEFINE_CONFIGURABLE(pathPhiWeights, std::string, "", "Local (local://) or CCDB path for the phi acceptance correction histogram"); - - UInt_t ncent; - float* pcentEdges = 0; - - struct Map { - Map(int _runNumber, UInt_t _centBin, TH1* _ph) : runNumber(_runNumber), centBin(_centBin), ph(_ph) {} - ~Map() { delete ph; } - int runNumber; - UInt_t centBin; - TH1* ph; - }; - std::deque nuaCache; - TFile* pf = 0; - - ~jflucWeightsLoader() - { - if (pcentEdges) - delete[] pcentEdges; - if (pf) { - pf->Close(); - delete pf; - } - } - - Produces output; - void init(InitContext const&) - { - // - if (!doprocessLoadWeights) - return; - if (pathPhiWeights.value.substr(0, 8) == "local://") { - pf = new TFile(pathPhiWeights.value.substr(8).c_str(), "read"); - - // TODO: who knows someday, replace the old collection of TH3Ds with a 4D axis that includes the centrality info. - // At the same time, the centBin indexing needs to go, use actual bin edges instead. - TTree* pt = static_cast(pf->Get("axes")); - if (pt) - LOGF(fatal, "The NUA correction root file does not have the axis information."); - pt->SetBranchAddress("Ncentrality", &ncent); - pt->GetEntry(0); - - pcentEdges = new float[ncent]; - pt->SetBranchAddress("centrality", pcentEdges); - pt->GetEntry(0); - } - } - - void processLoadWeights(aod::JCollision const& collision, aod::JTracks const& tracks) - { - UInt_t centBin = 0; - for (UInt_t i = 0, n = ncent - 1; i < n; ++i) - if (collision.multiplicity() < pcentEdges[i + 1]) { - centBin = i; - break; - } - - for (auto& track : tracks) { - if (pf) { - float phiWeight, effWeight; - auto m = std::find_if(nuaCache.begin(), nuaCache.end(), [&](auto& t) -> bool { - return t.runNumber == collision.runNumber() && t.centBin == centBin; - }); - if (m == nuaCache.end()) { - TH1* ph = static_cast(pf->Get(Form("PhiWeights_%u_%02u", collision.runNumber(), centBin))); - if (ph) { - ph->SetDirectory(0); // we delete when we please - nuaCache.emplace_back(collision.runNumber(), centBin, ph); - if (nuaCache.size() > ncent * 3) - nuaCache.pop_front(); // keep at most maps for 3 runs - Int_t bin = ph->FindBin(track.phi(), track.eta(), collision.posZ()); - phiWeight = ph->GetBinContent(bin); - } else { - phiWeight = 1.0f; - } - } else { - Int_t bin = m->ph->FindBin(track.phi(), track.eta(), collision.posZ()); - phiWeight = m->ph->GetBinContent(bin); - } - - effWeight = 1.0f; //<--- todo - - output(phiWeight, effWeight); - } - } - } - PROCESS_SWITCH(jflucWeightsLoader, processLoadWeights, "Load weights histograms", false); -}; - struct jflucAnalysisTask { ~jflucAnalysisTask() { - delete pcf; + if (pcf) + delete pcf; + if (pcf2Prong) + delete pcf2Prong; } - O2_DEFINE_CONFIGURABLE(etamin, float, 0.4, "Minimal eta for tracks"); - O2_DEFINE_CONFIGURABLE(etamax, float, 0.8, "Maximal eta for tracks"); - O2_DEFINE_CONFIGURABLE(ptmin, float, 0.2, "Minimal pt for tracks"); - O2_DEFINE_CONFIGURABLE(ptmax, float, 0.5, "Maximal pt for tracks"); + O2_DEFINE_CONFIGURABLE(etamin, float, 0.4, "Minimum eta for tracks"); + O2_DEFINE_CONFIGURABLE(etamax, float, 0.8, "Maximum eta for tracks"); + O2_DEFINE_CONFIGURABLE(ptmin, float, 0.2, "Minimum pt for tracks"); + O2_DEFINE_CONFIGURABLE(ptmax, float, 5.0, "Maximum pt for tracks"); ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 100.1}, "multiplicity / centrality axis for histograms"}; + ConfigurableAxis phiAxis{"axisPhi", {50, 0.0, o2::constants::math::TwoPI}, "phi axis for histograms"}; + ConfigurableAxis etaAxis{"axisEta", {40, -2.0, 2.0}, "eta axis for histograms"}; + ConfigurableAxis zvtAxis{"axisZvt", {20, -10.0, 10.0}, "zvertex axis for histograms"}; + ConfigurableAxis ptAxis{"axisPt", {60, 0.0, 300.0}, "pt axis for histograms"}; + ConfigurableAxis massAxis{"axisMass", {1, 0.0, 10.0}, "mass axis for histograms"}; Filter jtrackFilter = (aod::jtrack::pt > ptmin) && (aod::jtrack::pt < ptmax); // eta cuts done by jfluc Filter cftrackFilter = (aod::cftrack::pt > ptmin) && (aod::cftrack::pt < ptmax); // eta cuts done by jfluc + Filter cf2pFilter = (aod::cf2prongtrack::pt > ptmin) && (aod::cf2prongtrack::pt < ptmax); - OutputObj output{"jflucO2"}; + HistogramRegistry registry{"registry"}; void init(InitContext const&) { - pcf = new JFFlucAnalysis("jflucAnalysis"); - pcf->SetNumBins(AxisSpec(axisMultiplicity).getNbins()); - pcf->AddFlags(JFFlucAnalysis::kFlucEbEWeighting); - - output->cd(); - pcf->UserCreateOutputObjects(); + auto axisSpecMult = AxisSpec(axisMultiplicity); + auto axisSpecPhi = AxisSpec(phiAxis); + auto axisSpecEta = AxisSpec(etaAxis); + auto axisSpecZvt = AxisSpec(zvtAxis); + auto axisSpecPt = AxisSpec(ptAxis); + auto axisSpecMass = AxisSpec(massAxis); + if (doprocessJDerived || doprocessJDerivedCorrected || doprocessCFDerived || doprocessCFDerivedCorrected) { + pcf = new JFFlucAnalysisO2Hist(registry, axisSpecMult, axisSpecPhi, axisSpecEta, axisSpecZvt, axisSpecPt, axisSpecMass, "jfluc"); + pcf->AddFlags(JFFlucAnalysis::kFlucEbEWeighting); + pcf->UserCreateOutputObjects(); + } else { + pcf = 0; + } + if (doprocessCF2ProngDerived || doprocessCF2ProngDerivedCorrected) { + pcf2Prong = new JFFlucAnalysisO2Hist(registry, axisSpecMult, axisSpecPhi, axisSpecEta, axisSpecZvt, axisSpecPt, axisSpecMass, "jfluc2prong"); + pcf2Prong->AddFlags(JFFlucAnalysis::kFlucEbEWeighting); + pcf2Prong->UserCreateOutputObjects(); + + ConfigurableAxis axisInvMassHistogram{"axisInvMassHistogram", {1000, 1.0, 3.0}, "invariant mass histogram binning"}; + registry.add("invMass", "2-prong invariant mass (GeV/c^2)", {HistType::kTH3F, {axisInvMassHistogram, {8, 0.0, 8.0, "p_{T}"}, axisMultiplicity}}); + } else { + pcf2Prong = 0; + } } + template + using hasInvMass = decltype(std::declval().invMass()); + template void analyze(CollisionT const& collision, TrackT const& tracks) { pcf->Init(); + pcf->SetEventCentrality(collision.multiplicity()); + pcf->SetEventVertex(collision.posZ()); pcf->FillQA(tracks); qvecs.Calculate(tracks, etamin, etamax); pcf->SetJQVectors(&qvecs); - const auto& edges = AxisSpec(axisMultiplicity).binEdges; - for (UInt_t i = 0, n = AxisSpec(axisMultiplicity).getNbins(); i < n; ++i) - if (collision.multiplicity() < edges[i + 1]) { - pcf->SetEventCentralityAndBin(collision.multiplicity(), i); - break; - } - const double fVertex[3] = {0.0f, 0.0f, collision.posZ()}; // TODO: check if posX/Y is really needed - pcf->SetEventVertex(fVertex); - pcf->SetEtaRange(etamin, etamax); pcf->UserExec(""); } - void process(aod::JCollision const& collision, soa::Filtered const& tracks) + template + void analyze(CollisionT const& collision, POITrackT const& poiTracks, REFTrackT const& refTracks) + { + if constexpr (std::experimental::is_detected::value) { + for (auto& track : poiTracks) + registry.fill(HIST("invMass"), track.invMass(), track.pt(), collision.multiplicity()); + } + pcf2Prong->Init(); + pcf2Prong->SetEventCentrality(collision.multiplicity()); + pcf2Prong->SetEventVertex(collision.posZ()); + pcf2Prong->FillQA(refTracks, 0u); + pcf2Prong->FillQA(poiTracks, 1u); // type = 1, all POI tracks in this list are of the same type + qvecsRef.Calculate(refTracks, etamin, etamax); + pcf2Prong->SetJQVectors(&qvecs, &qvecsRef); + const AxisSpec& a = AxisSpec(massAxis); + for (uint i = 0; i < a.getNbins(); ++i) { + qvecs.Calculate(poiTracks, etamin, etamax, a.binEdges[i], a.binEdges[i + 1]); + pcf2Prong->SetAverageInvariantMass(0.5f * (a.binEdges[i] + a.binEdges[i + 1])); + pcf2Prong->UserExec(""); // The analysis needs to be called many times, once for each mass bin. For each of the bins, SetInvariantMass is used + } + } + + void processJDerived(aod::JCollision const& collision, soa::Filtered const& tracks) { analyze(collision, tracks); } - PROCESS_SWITCH(jflucAnalysisTask, process, "Process data", true); + PROCESS_SWITCH(jflucAnalysisTask, processJDerived, "Process derived data", false); - void processCorrected(aod::JCollision const& collision, soa::Filtered> const& tracks) + void processJDerivedCorrected(aod::JCollision const& collision, soa::Filtered> const& tracks) { analyze(collision, tracks); } - PROCESS_SWITCH(jflucAnalysisTask, processCorrected, "Process data with corrections", false); + PROCESS_SWITCH(jflucAnalysisTask, processJDerivedCorrected, "Process derived data with corrections", false); void processCFDerived(aod::CFCollision const& collision, soa::Filtered const& tracks) { @@ -220,19 +152,29 @@ struct jflucAnalysisTask { { analyze(collision, tracks); } - PROCESS_SWITCH(jflucAnalysisTask, processCFDerivedCorrected, "Process CF derived data with corrections", false); + PROCESS_SWITCH(jflucAnalysisTask, processCFDerivedCorrected, "Process CF derived data with corrections", true); + + void processCF2ProngDerived(aod::CFCollision const& collision, soa::Filtered const& tracks, soa::Filtered const& p2tracks) + { + analyze(collision, p2tracks, tracks); + } + PROCESS_SWITCH(jflucAnalysisTask, processCF2ProngDerived, "Process CF derived data with 2-prongs as POI and charged particles as REF.", false); + + void processCF2ProngDerivedCorrected(aod::CFCollision const& collision, soa::Filtered> const& tracks, soa::Filtered> const& p2tracks) + { + analyze(collision, p2tracks, tracks); + } + PROCESS_SWITCH(jflucAnalysisTask, processCF2ProngDerivedCorrected, "Process CF derived data with 2-prongs as POI and charged particles as REF with corrections.", false); JFFlucAnalysis::JQVectorsT qvecs; - JFFlucAnalysis* pcf; + JFFlucAnalysis::JQVectorsT qvecsRef; + JFFlucAnalysisO2Hist* pcf; + JFFlucAnalysisO2Hist* pcf2Prong; }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - if (cfgc.options().get("loadWeights")) { - return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; - } else { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; - } + return WorkflowSpec{ + // adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; } diff --git a/PWGCF/JCorran/Tasks/jflucWeightsLoader.cxx b/PWGCF/JCorran/Tasks/jflucWeightsLoader.cxx new file mode 100644 index 00000000000..244035fd310 --- /dev/null +++ b/PWGCF/JCorran/Tasks/jflucWeightsLoader.cxx @@ -0,0 +1,217 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// \author Jasper Parkkila (jparkkil@cern.ch) +/// \since May 2024 +// o2-linter: disable='doc/file' + +#include +#include +#include +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "ReconstructionDataFormats/V0.h" + +#include "CCDB/BasicCCDBManager.h" + +#include "PWGCF/JCorran/DataModel/JCatalyst.h" +#include "PWGCF/DataModel/CorrelationsDerived.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +// The standalone jfluc code expects the entire list of tracks for an event. At the same time, it expects weights together with other track attributes. +// This workflow creates a table of weights that can be joined with track tables. +struct JflucWeightsLoader { + O2_DEFINE_CONFIGURABLE(cfgPathPhiWeights, std::string, "http://alice-ccdb.cern.ch", "Local (local://) or CCDB path for the phi acceptance correction histogram"); + O2_DEFINE_CONFIGURABLE(cfgPathEffWeights, std::string, "", "Local (local://) or CCDB path for the efficiency correction histogram"); + O2_DEFINE_CONFIGURABLE(cfgForRunNumber, bool, false, "Get CCDB object by run"); + O2_DEFINE_CONFIGURABLE(cfgCCDBPath, std::string, "Users/m/mavirta/corrections/NUA/LHC23zzh", "Internal path in CCDB"); + + THnF* ph = 0; + TFile* pf = 0; + THnD* pheff = 0; + TFile* pfeff = 0; + int runNumber = 0; + int timestamp = 0; + bool useCCDB = false; + Service ccdb; + + ~JflucWeightsLoader() + { + if (ph) + delete ph; + if (pf) { + pf->Close(); + delete pf; + } + if (pheff) + delete pheff; + if (pfeff) { + pfeff->Close(); + delete pfeff; + } + } + + void initCCDB(int runNum, int ts) + { + if (cfgForRunNumber) { + ph = ccdb->getForRun(cfgCCDBPath, runNum); + } else { + ph = ccdb->getForTimeStamp(cfgCCDBPath, ts); + } + } + + void init(InitContext const&) + { + if (!doprocessLoadWeights && !doprocessLoadWeightsCF) { + return; + } + + if (doprocessLoadWeights && doprocessLoadWeightsCF) + LOGF(fatal, "Only one of JTracks or CFTracks processing can be enabled at a time."); + if (cfgPathPhiWeights.value.find("ccdb") != std::string::npos) { + LOGF(info, "Using corrections from: ccdb"); + useCCDB = true; + ccdb->setURL(cfgPathPhiWeights); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + } else if (cfgPathPhiWeights.value.substr(0, 8) == "local://") { + LOGF(info, "Using non-uniform acceptance corrections from: %s", cfgPathPhiWeights.value.substr(8).c_str()); + pf = new TFile(cfgPathPhiWeights.value.substr(8).c_str(), "read"); + if (!pf->IsOpen()) { + delete pf; + pf = 0; + LOGF(fatal, "NUA correction weights file not found: %s", cfgPathPhiWeights.value.substr(8).c_str()); + } + useCCDB = false; + } else { + LOGF(info, "Didn't find \"local://\" or \"ccdb\" for non-uniform acceptance corrections."); + return; + } + + if (cfgPathEffWeights.value.substr(0, 8) == "local://") { + LOGF(info, "Using efficiency corrections from: %s", cfgPathEffWeights.value.substr(8).c_str()); + pfeff = new TFile(cfgPathEffWeights.value.substr(8).c_str(), "read"); + if (!pfeff->IsOpen()) { + delete pfeff; + pfeff = 0; + LOGF(fatal, "Efficiency correction weights file not found: %s", cfgPathEffWeights.value.substr(8).c_str()); + } + // + if (!(pheff = pfeff->Get("ccdb_object"))) { + LOGF(warning, "Efficiency correction histogram not found."); + } else { + LOGF(info, "Loaded efficiency correction histogram locally."); + } + } else { + LOGF(info, "Didn't find \"local://\" or \"ccdb\" for efficiency corrections."); + return; + } + } + + template + using HasDecay = decltype(std::declval().decay()); + + template + void loadWeights(Produces& outputT, CollisionT const& collision, TrackT const& tracks) + { + if (pf || useCCDB) { + if (collision.runNumber() != runNumber) { + if (ph) + delete ph; + if (!useCCDB) { + // Check if NUA correction can be found from a local file and load it + if (!(ph = pf->Get(Form("NUAWeights_%d", collision.runNumber())))) + LOGF(warning, "NUA correction histogram not found for run %d.", collision.runNumber()); + else + LOGF(info, "Loaded NUA correction histogram locally for run %d.", collision.runNumber()); + } else { + initCCDB(collision.runNumber(), timestamp); + LOGF(info, "Loaded NUA correction histogram from CCDB for run %d.", collision.runNumber()); + } + runNumber = collision.runNumber(); + } + } + for (const auto& track : tracks) { + float phiWeight, effWeight; + if (ph) { + uint partType = 0; // partType 0 = all charged hadrons + // TODO: code below to be enabled + /*if constexpr (std::experimental::is_detected::value) { + switch (track.decay()) { + case aod::cf2prongtrack::D0ToPiK: + case aod::cf2prongtrack::D0barToKPi: + partType = 1; + break; + default: + break; + } + }*/ + const double coords[] = {collision.multiplicity(), static_cast(partType), track.phi(), track.eta(), collision.posZ()}; + phiWeight = ph->GetBinContent(ph->GetBin(coords)); + } else { + phiWeight = 1.0f; + } + + if (pheff) { + const int effVars[] = { + pheff->GetAxis(0)->FindBin(track.eta()), + pheff->GetAxis(1)->FindBin(track.pt()), + pheff->GetAxis(2)->FindBin(collision.multiplicity()), + pheff->GetAxis(3)->FindBin(collision.posZ())}; + effWeight = pheff->GetBinContent(effVars); + } else { + effWeight = 1.0f; + } + + outputT(phiWeight, effWeight); + } + } + + Produces output; + void processLoadWeights(aod::JCollision const& collision, aod::JTracks const& tracks) + { + loadWeights(output, collision, tracks); + } + PROCESS_SWITCH(JflucWeightsLoader, processLoadWeights, "Load weights histograms for derived data table", false); + + void processLoadWeightsCF(aod::CFCollision const& collision, aod::CFTracks const& tracks) + { + loadWeights(output, collision, tracks); + } + PROCESS_SWITCH(JflucWeightsLoader, processLoadWeightsCF, "Load weights histograms for CF derived data table", true); + + Produces output2p; + void processLoadWeightsCF2Prong(aod::CFCollision const& collision, aod::CF2ProngTracks const& tracks2p) + { + loadWeights(output2p, collision, tracks2p); + } + PROCESS_SWITCH(JflucWeightsLoader, processLoadWeightsCF2Prong, "Load weights histograms for CF derived 2-prong tracks data table", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/MultiparticleCorrelations/Core/MuPa-Configurables.h b/PWGCF/MultiparticleCorrelations/Core/MuPa-Configurables.h index 96813af4404..6a91e2f6e4b 100644 --- a/PWGCF/MultiparticleCorrelations/Core/MuPa-Configurables.h +++ b/PWGCF/MultiparticleCorrelations/Core/MuPa-Configurables.h @@ -16,162 +16,291 @@ #include #include -// Task configuration: -Configurable cfTaskName{ - "cfTaskName", "Default task name", - "set task name - use eventually to determine weights for this task"}; -Configurable cfDryRun{ - "cfDryRun", false, - "book all histos and run without storing and calculating anything"}; -Configurable cfVerbose{ - "cfVerbose", false, - "run or not in verbose mode (but not for function calls per particle)"}; -Configurable cfVerboseForEachParticle{ - "cfVerboseForEachParticle", false, - "run or not in verbose mode (also for function calls per particle)"}; -Configurable cfDoAdditionalInsanityChecks{ - "cfDoAdditionalInsanityChecks", false, - "do additional insanity checks at run time (this leads to small loss of performance)"}; -Configurable cfUseCCDB{ - "cfUseCCDB", true, - "access personal files from CCDB or from home dir in AliEn"}; -Configurable cfRandomSeed{ - "cfRandomSeed", 0, - "0 = random seed is guaranteed to be unique in space and time"}; -Configurable cfUseFisherYates{ - "cfUseFisherYates", false, - "use or not Fisher-Yates algorithm to randomize particle indices"}; -Configurable cfFixedNumberOfRandomlySelectedTracks{ - "cfFixedNumberOfRandomlySelectedTracks", -1, - "Set to some integer > 0, to apply and use. Set to <=0, to ignore."}; -Configurable cfUseStopwatch{ - "cfUseStopwatch", false, - "If true, some basic info on time execution is printed, here and there."}; - -// Default booking: -Configurable> cfBookEventHistograms{"cfBookEventHistograms", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, "Book (1) or do not book (0) event histogram, ordering is the same as in enum eEventHistograms"}; -Configurable> cfBookParticleHistograms{"cfBookParticleHistograms", {1, 1, 1, 1, 1, 1, 1}, "Book (1) or do not book (0) particle histogram, ordering is the same as in enum eParticleHistograms"}; - -// Q-vector: -Configurable cfCalculateQvectors{"cfCalculateQvectors", true, - "calculate or not Q-vectors (all, also diff. ones). If I want only to fill control histograms, then I can set here false"}; - -// Correlations: -Configurable cfCalculateCorrelations{"cfCalculateCorrelations", false, - "calculate or not correlations"}; - -// Test0: -Configurable cfCalculateTest0{"cfCalculateTest0", false, - "calculate or not Test0"}; -Configurable cfCalculateTest0AsFunctionOfIntegrated{"cfCalculateTest0AsFunctionOfIntegrated", true, - "calculate or not Test0 as a function of integrated"}; -Configurable cfCalculateTest0AsFunctionOfMultiplicity{"cfCalculateTest0AsFunctionOfMultiplicity", true, - "calculate or not Test0 as a function of multiplicity"}; -Configurable cfCalculateTest0AsFunctionOfCentrality{"cfCalculateTest0AsFunctionOfCentrality", true, - "calculate or not Test0 as a function of centrality"}; -Configurable cfCalculateTest0AsFunctionOfPt{"cfCalculateTest0AsFunctionOfPt", false, - "calculate or not Test0 as a function of pt"}; -Configurable cfCalculateTest0AsFunctionOfEta{"cfCalculateTest0AsFunctionOfEta", false, - "calculate or not Test0 as a function of eta"}; -Configurable cfFileWithLabels{"cfFileWithLabels", - "/home/abilandz/DatasetsO2/labels.root", "path to external ROOT file which specifies all labels"}; // for AliEn file prepend "/alice/cern.ch/", for CCDB prepend "/alice-ccdb.cern.ch" - -// Particle weights: -Configurable cfUsePhiWeights{"cfUsePhiWeights", false, - "use or not phi weights"}; -Configurable cfUsePtWeights{"cfUsePtWeights", false, - "use or not pt weights"}; -Configurable cfUseEtaWeights{"cfUseEtaWeights", false, - "use or not eta weights"}; -Configurable cfUseDiffPhiPtWeights{"cfUseDiffPhiPtWeights", false, - "use or not differential phi(pt) weights"}; -Configurable cfUseDiffPhiEtaWeights{"cfUseDiffPhiEtaWeights", false, - "use or not differential phi(eta) weights"}; -Configurable cfFileWithWeights{"cfFileWithWeights", - "/home/abilandz/DatasetsO2/weights.root", "path to external ROOT file which holds all particle weights in O2 format"}; // for AliEn file prepend "/alice/cern.ch/", for CCDB prepend "/alice-ccdb.cern.ch" - -// Nested loops: -Configurable cfCalculateNestedLoops{"cfCalculateNestedLoops", false, - "cross-check for all events all correlations with nested loops"}; -Configurable cfCalculateCustomNestedLoops{"cfCalculateCustomNestedLoops", false, - "cross-check e-b-e all correlations with custom nested loops"}; - -// Event cuts: -Configurable cfTrigger{ - "cfTrigger", "some supported trigger", - "set here some supported trigger (kINT7, ...) "}; -Configurable cfUseSel7{"cfUseSel7", false, "use for Run 2 data and MC (see official doc)"}; -Configurable cfUseSel8{"cfUseSel8", false, "use for Run 3 data and MC (see official doc)"}; -Configurable cfCentralityEstimator{ - "cfCentralityEstimator", "some supported centrality estimator", - "set here some supported centrality estimator (CentFT0M, CentFV0A, CentNTPV, ... for Run 3, CentRun2V0M, CentRun2SPDTracklets, ..., for Run 2) "}; - -Configurable cNumberOfEvents_min{ - "cNumberOfEvents_min", -1, - "minimum number of events to process (set to -1 to ignore)"}; -Configurable cNumberOfEvents_max{"cNumberOfEvents_max", 1000000000, - "maximum number of events to process (use only in the local analysis, because after that BailOut() is forced)"}; -Configurable cTotalMultiplicity_min{ - "cTotalMultiplicity_min", -1, - "minimum total multiplicity of an event to be processed (set to -1 to " - "ignore)"}; -Configurable cTotalMultiplicity_max{ - "cTotalMultiplicity_max", 1000000000, - "maximum total multiplicity of an event to be processed"}; -Configurable cSelectedTracks_min{ - "cSelectedTracks_min", -1, - "minimum number of selected tracks (set to -1 to ignore)"}; -Configurable cSelectedTracks_max{"cSelectedTracks_max", 1000000000, - "maximum number of selected tracks"}; -Configurable cCentrality_min{"cCentrality_min", 0., - "minimum centrality"}; -Configurable cCentrality_max{"cCentrality_max", 100., - "maximum centrality"}; -Configurable cVertex_x_min{"cVertex_x_min", -10.0, - "minimum vertex x range [cm]"}; -Configurable cVertex_x_max{"cVertex_x_max", 10.0, - "maximum vertex x range [cm]"}; -Configurable cVertex_y_min{"cVertex_y_min", -10.0, - "minimum vertex y range [cm]"}; -Configurable cVertex_y_max{"cVertex_y_max", 10.0, - "maximum vertex y range [cm]"}; -Configurable cVertex_z_min{"cVertex_z_min", -10.0, - "minimum vertex z range [cm]"}; -Configurable cVertex_z_max{"cVertex_z_max", 10.0, - "maximum vertex z range [cm]"}; -Configurable cNContributors_min{ - "cNContributors_min", -1, - "minimum number of vertex contributors (set to -1 to ignore)"}; -Configurable cNContributors_max{"cNContributors_max", 1000000000, - "maximum number of vertex contributors"}; -Configurable cImpactParameter_min{ - "cImpactParameter_min", -1, - "minimum value of impact parameter (can be used only for sim) (set to -1 to ignore)"}; -Configurable cImpactParameter_max{"cImpactParameter_max", 1000000000, - "maximum value of impact parameter (can be used osnly for sim)"}; - -// Particle cuts: -Configurable pt_min{"pt_min", 0.2, "minimum track pt value [GeV/c]"}; -Configurable pt_max{"pt_max", 5.0, "maximum track pt value [GeV/c]"}; - -// Results histograms: -Configurable cfSaveResultsHistograms{"cfSaveResultsHistograms", false, - "save or not results histograms"}; - -// Fixed-length binning (default): -Configurable> cFixedLength_mult_bins{"cFixedLength_mult_bins", {2000, 0., 20000.}, "nMultBins, multMin, multMax"}; -Configurable> cFixedLength_cent_bins{"cFixedLength_cent_bins", {110, 0., 110.}, "nCentBins, centMin, centMax"}; -Configurable> cFixedLength_pt_bins{"cFixedLength_pt_bins", {1000, 0., 100.}, "nPtBins, ptMin, ptMax"}; -Configurable> cFixedLength_eta_bins{"cFixedLength_eta_bins", {1000, -2., 2.}, "nEtaBins, etaMin, etaMax"}; - -// Variable-length binning: TBI 20240113 I do it via string + tokenize + Atof(), use arrays eventually as for FixedLength case above. -Configurable cUseVariableLength_mult_bins{"cUseVariableLength_mult_bins", false, "use or not variable-length multiplicity bins"}; -Configurable cVariableLength_mult_bins{"cVariableLength_mult_bins", "0.,100.,250.,1000.", "variable-length multiplicity bins"}; -Configurable cUseVariableLength_cent_bins{"cUseVariableLength_cent_bins", false, "use or not variable-length centrality bins"}; -Configurable cVariableLength_cent_bins{"cVariableLength_cent_bins", "0.,10.,50.,100.", "variable-length centrality bins"}; -Configurable cUseVariableLength_pt_bins{"cUseVariableLength_pt_bins", false, "use or not variable-length pt bins"}; -Configurable cVariableLength_pt_bins{"cVariableLength_pt_bins", "1.0,2.0,5.0", "variable-length pt bins"}; -Configurable cUseVariableLength_eta_bins{"cUseVariableLength_eta_bins", false, "use or not variable-length eta bins"}; -Configurable cVariableLength_eta_bins{"cVariableLength_eta_bins", "-0.8,-0.4,0.0,0.4,0.8", "variable-length eta bins"}; +// *) Task configuration: +struct : ConfigurableGroup { + // std::string prefix = "Task configuration"; // AA: now these configurables also appear grouped on hyperloop => TBI 20240522 check if this work, and if further modifications in init are needed + Configurable cfTaskIsConfiguredFromJson{"cfTaskIsConfiguredFromJson", "no", "always set manaully to \"yes\" via JSON, merely to ensure that settings are not ignored silently"}; + Configurable cfTaskName{"cfTaskName", "Default task name", "set task name - use eventually to determine weights for this task"}; + Configurable cfDryRun{"cfDryRun", false, "book all histos and run without storing and calculating anything"}; + Configurable cfVerbose{"cfVerbose", false, "run or not in verbose mode (but not for simple utility functions or function calls per particle)"}; + Configurable cfVerboseUtility{"cfVerboseUtility", false, "run or not in verbose mode, also for simple utility functions (but not for function calls per particle)"}; + Configurable cfVerboseForEachParticle{"cfVerboseForEachParticle", false, "run or not in verbose mode (also for function calls per particle)"}; + Configurable cfVerboseEventCounter{"cfVerboseEventCounter", false, "print or not only event counter"}; + Configurable cfVerboseEventCut{"cfVerboseEventCut", false, "print or not which event cut didn't survive"}; + Configurable cfPlainPrintout{"cfPlainPrintout", false, "print in color or in plain (use the latter in HL)"}; + Configurable cfDoAdditionalInsanityChecks{"cfDoAdditionalInsanityChecks", false, "do additional insanity checks at run time (this leads to small loss of performance)"}; + Configurable cfInsanityCheckForEachParticle{"cfInsanityCheckForEachParticle", false, "do insanity checks at run time for each particle, at the expense of losing a lot of performance. Use only during debugging."}; + Configurable cfRandomSeed{"cfRandomSeed", 0, "0 = random seed is guaranteed to be unique in space and time"}; + Configurable cfUseFisherYates{"cfUseFisherYates", false, "use or not Fisher-Yates algorithm to randomize particle indices"}; + Configurable cfFixedNumberOfRandomlySelectedTracks{"cfFixedNumberOfRandomlySelectedTracks", -1, "set to some integer > 0, to apply and use. Set to <=0, to ignore."}; + Configurable cfUseStopwatch{"cfUseStopwatch", false, "if true, some basic info on time execution is printed, here and there. Very loosely, this can be used for execution time profiling."}; + Configurable cfFloatingPointPrecision{"cfFloatingPointPrecision", 0.000001, "two floats are the same if TMath::Abs(f1 - f2) < fFloatingPointPrecision"}; + Configurable cfSequentialBailout{"cfSequentialBailout", 0, "if fSequentialBailout > 0, then each fSequentialBailout events the function BailOut() is called. Can be used for real analysis and for IV"}; + Configurable cfUseSpecificCuts{"cfUseSpecificCuts", false, "if true, analysis-specific cuts set via configurable cfWhichSpecificCuts are applied after DefaultCuts(). "}; + Configurable cfWhichSpecificCuts{"cfWhichSpecificCuts", "some supported set of analysis-specific cuts (e.g. LHC23zzh, ...)", "determine which set of analysis-specific cuts will be applied after DefaultCuts(). Use in combination with tc.fUseSpecificCuts"}; + Configurable cfSkipTheseRuns{"cfSkipTheseRuns", "", "Set here via comma-separated list which runs will be skipped during hl analysis (a.k.a. \"bad runs\"). Leave empty to ignore. Example format and list for LHC23zzh: \"544116,544091\""}; +} cf_tc; + +// *) QA: +struct : ConfigurableGroup { + Configurable cfCheckUnderflowAndOverflow{"cfCheckUnderflowAndOverflow", false, "check and bail out if in event and particle histograms there are entries which went to underflow or overflow bins (use only locally)"}; + Configurable cfRebin{"cfRebin", 10, "number of bins of selected heavy 2D histograms are devided with this number"}; + Configurable cfFillQAEventHistograms2D{"cfFillQAEventHistograms2D", false, "if false, all QA 2D event histograms are not filled. if true, only the ones for which fBookQAEventHistograms2D[...] is true, are filled"}; + Configurable> cfBookQAEventHistograms2D{"cfBookQAEventHistograms2D", {"1-Multiplicity_vs_ReferenceMultiplicity", "1-Multiplicity_vs_NContributors", "1-Multiplicity_vs_Centrality", "1-Multiplicity_vs_VertexZ", "1-Multiplicity_vs_Occupancy", "1-Multiplicity_vs_InteractionRate", "1-ReferenceMultiplicity_vs_NContributors", "1-ReferenceMultiplicity_vs_Centrality", "1-ReferenceMultiplicity_vs_VertexZ", "1-ReferenceMultiplicity_vs_Occupancy", "1-ReferenceMultiplicity_vs_InteractionRate", "1-NContributors_vs_Centrality", "1-NContributors_vs_VertexZ", "1-NContributors_vs_Occupancy", "1-NContributors_vs_InteractionRate", "1-Centrality_vs_VertexZ", "1-Centrality_vs_Occupancy", "0-Centrality_vs_ImpactParameter", "1-Centrality_vs_InteractionRate", "1-VertexZ_vs_Occupancy", "1-VertexZ_vs_InteractionRate", "0-MultNTracksPV_vs_MultNTracksGlobal", "1-CentFT0C_vs_CentFT0CVariant1", "1-CentFT0C_vs_CentFT0M", "1-CentFT0C_vs_CentFV0A", "0-CentFT0C_vs_CentNTPV", "0-CentFT0C_vs_CentNGlobal", "0-CentFT0M_vs_CentNTPV", "0-CentRun2V0M_vs_CentRun2SPDTracklets", "1-TrackOccupancyInTimeRange_vs_FT0COccupancyInTimeRange", "1-CurrentRunDuration_vs_InteractionRate", "1-Multiplicity_vs_FT0CAmplitudeOnFoundBC", "1-CentFT0C_vs_FT0CAmplitudeOnFoundBC"}, "book (1) or do not book (0) this QA 2D event histogram"}; + Configurable cfFillQAParticleHistograms2D{"cfFillQAParticleHistograms2D", false, "if false, all QA 2D particle histograms are not filled. if true, only the ones for which fBookQAParticleHistograms2D[...] is true, are filled"}; + Configurable> cfBookQAParticleHistograms2D{"cfBookQAParticleHistograms2D", {"1-Pt_vs_dcaXY"}, "book (1) or do not book (0) this QA 2D particle histogram"}; + Configurable cfFillQAParticleEventHistograms2D{"cfFillQAParticleEventHistograms2D", false, "if false, all QA 2D particle event histograms are not filled. if true, only the ones for which fBookQAParticleEventHistograms2D[...] is true, are filled"}; + Configurable> cfBookQAParticleEventHistograms2D{"cfBookQAParticleEventHistograms2D", {"1-CurrentRunDuration_vs_itsNCls", "1-CurrentRunDuration_vs_itsNClsNegEtaEbyE", "1-CurrentRunDuration_vs_itsNClsPosEtaEbyE", "1-CurrentRunDuration_vs_Eta0804EbyE", "1-CurrentRunDuration_vs_Eta0400EbyE", "1-CurrentRunDuration_vs_Eta0004EbyE", "1-CurrentRunDuration_vs_Eta0408EbyE", "1-CurrentRunDuration_vs_Pt0005EbyE", "1-CurrentRunDuration_vs_Pt0510EbyE", "1-CurrentRunDuration_vs_Pt1050EbyE"}, "book (1) or do not book (0) this QA 2D particle event histogram"}; + + Configurable cfFillQACorrelationsVsHistograms2D{"cfFillQACorrelationsVsHistograms2D", false, "if false, all QA 2D histograms of this category are not filled. if true, only the ones for which fBookQACorrelationsVsHistograms2D[...] is true, are filled"}; + Configurable> cfBookQACorrelationsVsHistograms2D{"cfBookQACorrelationsVsHistograms2D", {"1-Correlations_vs_Multiplicity", "1-Correlations_vs_ReferenceMultiplicity", "1-Correlations_vs_Centrality", "1-Correlations_vs_Phi", "1-Correlations_vs_Pt", "1-Correlations_vs_Eta", "1-Correlations_vs_Charge", "1-Correlations_vs_tpcNClsFindable", "1-Correlations_vs_tpcNClsShared", "1-Correlations_vs_itsChi2NCl", "1-Correlations_vs_tpcNClsFound", "1-Correlations_vs_tpcNClsCrossedRows", "1-Correlations_vs_itsNCls", "1-Correlations_vs_itsNClsInnerBarrel", "1-Correlations_vs_tpcCrossedRowsOverFindableCls", "1-Correlations_vs_tpcFoundOverFindableCls", "1-Correlations_vs_tpcFractionSharedCls", "1-Correlations_vs_tpcChi2NCl", "1-Correlations_vs_dcaXY", "1-Correlations_vs_dcaZ"}, "book (1) or do not book (0) this QA 2D histogram"}; + Configurable> cfQACorrelationsVsHistogramsMinMaxHarmonic{"cfQACorrelationsVsHistogramsMinMaxHarmonic", {1, 5}, "harmonics are filled for min <= harmonic < max"}; + + Configurable cfFillQACorrelationsVsInteractionRateVsProfiles2D{"cfFillQACorrelationsVsInteractionRateVsProfiles2D", false, "if false, all QA 2D profiles of this category are not filled. if true, only the ones for which fBookQACorrelationsVsInteractionRateVsProfiles2D[...] is true, are filled"}; + Configurable> cfBookQACorrelationsVsInteractionRateVsProfiles2D{"cfBookQACorrelationsVsInteractionRateVsProfiles2D", {"1-CorrVsIR_vs_CurrentRunDuration", "1-CorrVsIR_vs_Multiplicity", "1-CorrVsIR_vs_ReferenceMultiplicity", "1-CorrVsIR_vs_Centrality", "1-CorrVsIR_vs_MeanPhi", "1-CorrVsIR_vs_SigmaMeanPhi", "1-CorrVsIR_vs_MeanPt", "1-CorrVsIR_vs_SigmaMeanPt", "1-CorrVsIR_vs_MeanEta", "1-CorrVsIR_vs_SigmaMeanEta"}, "book (1) or do not book (0) this QA 2D profile"}; + Configurable> cfQACorrelationsVsInteractionRateVsProfilesMinMaxHarmonic{"cfQACorrelationsVsInteractionRateVsProfilesMinMaxHarmonic", {1, 5}, "harmonics are filled for min <= harmonic < max"}; + +} cf_qa; + +// *) Event histograms: +struct : ConfigurableGroup { + Configurable cfFillEventHistograms{"cfFillEventHistograms", true, "if false, all event histograms are not filled. if true, only the ones for which fBookEventHistograms[...] is true, are filled"}; + Configurable> cfBookEventHistograms{"cfBookEventHistograms", {"1-NumberOfEvents", "1-TotalMultiplicity", "1-Multiplicity", "1-ReferenceMultiplicity", "1-Centrality", "1-VertexX", "1-VertexY", "1-VertexZ", "1-NContributors", "0-ImpactParameter", "0-EventPlaneAngle", "1-Occupancy", "1-InteractionRate", "1-CurrentRunDuration", "0-MultMCNParticlesEta08"}, "Book (1) or do not book (0) event histogram"}; +} cf_eh; + +// *) Event cuts: +struct : ConfigurableGroup { + Configurable> cfUseEventCuts{"cfUseEventCuts", {"1-NumberOfEvents", "1-TotalMultiplicity", "1-Multiplicity", "1-ReferenceMultiplicity", "1-Centrality", "1-VertexX", "1-VertexY", "1-VertexZ", "1-NContributors", "1-ImpactParameter", "0-EventPlaneAngle", "1-Occupancy", "1-InteractionRate", "1-CurrentRunDuration", "0-MultMCNParticlesEta08", "0-Trigger", "0-Sel7", "1-Sel8", "1-MultiplicityEstimator", "1-ReferenceMultiplicityEstimator", "1-CentralityEstimator", "1-SelectedEvents", "1-NoSameBunchPileup", "1-IsGoodZvtxFT0vsPV", "1-IsVertexITSTPC", "1-IsVertexTOFmatched", "1-IsVertexTRDmatched", "0-NoCollInTimeRangeStrict", "0-NoCollInTimeRangeStandard", "0-NoCollInRofStrict", "0-NoCollInRofStandard", "0-NoHighMultCollInPrevRof", "0-IsGoodITSLayer3", "0-IsGoodITSLayer0123", "0-IsGoodITSLayersAll", "1-OccupancyEstimator", "1-MinVertexDistanceFromIP", "0-NoPileupTPC", "0-NoPileupFromSPD", "0-NoSPDOnVsOfPileup", "1-RefMultVsNContrUp", "1-RefMultVsNContrLow", "1-CentralityCorrelationsCut", "1-CentralityWeights"}, "use (1) or do not use (0) event cuts"}; + Configurable cfUseEventCutCounterAbsolute{"cfUseEventCutCounterAbsolute", false, "profile and save how many times each event cut counter triggered (absolute). Use with care, as this is computationally heavy"}; + Configurable cfUseEventCutCounterSequential{"cfUseEventCutCounterSequential", false, "profile and save how many times each event cut counter triggered (sequential). Use with care, as this is computationally heavy"}; + Configurable cfPrintCutCounterContent{"cfPrintCutCounterContent", false, "if true, prints on the screen after each event the content of fEventCutCounterHist[*][*] (all which were booked)"}; + // Remark: Preserve below the same ordering as in enum's eEventHistograms + eEventCuts. In hyperloop, in any case this ordering is lost, because there it's alphabetical TBI 20240521 check this, after I added now std::string prefix thingie + Configurable> cfNumberOfEvents{"cfNumberOfEvents", {-1, 1000000000}, "total number of events to process (whether or not they survive event cuts): {min, max}, with convention: min <= N < max"}; + Configurable> cfTotalMultiplicity{"cfTotalMultiplicity", {-1, 1000000000}, "total multiplicity range: {min, max}, with convention: min <= M < max"}; + Configurable> cfMultiplicity{"cfMultiplicity", {-1., 1000000000.}, "multiplicity (defined via cfMultiplicityEstimator) range {min, max}, with convention: min <= M < max"}; + Configurable> cfReferenceMultiplicity{"cfReferenceMultiplicity", {-1., 1000000000.}, "reference multiplicity (defined via cfReferenceMultiplicityEstimator) range {min, max}, with convention: min <= M < max"}; + Configurable> cfCentrality{"cfCentrality", {-10., 110.}, "centrality range: {min, max}, with convention: min <= cent < max"}; + Configurable> cfVertexX{"cfVertexX", {-10., 10.}, "vertex x position range: {min, max}[cm], with convention: min <= Vx < max"}; + Configurable> cfVertexY{"cfVertexY", {-10., 10.}, "vertex y position range: {min, max}[cm], with convention: min <= Vy < max"}; + Configurable> cfVertexZ{"cfVertexZ", {-10, 10.}, "vertex z position range: {min, max}[cm], with convention: min <= Vz < max"}; + Configurable cfMinVertexDistanceFromIP{"cfMinVertexDistanceFromIP", {0.000001}, "if sqrt(vx^2+vy^2+vz^2) < cfMinVertexDistanceFromIP [cm], the event is reject. IP = nominal Interaction Point."}; + Configurable> cfNContributors{"cfNContributors", {2, 1000000000}, "Number of vertex contributors: {min, max}, with convention: min <= N < max"}; + Configurable> cfImpactParameter{"cfImpactParameter", {-1, 1000000000}, "Impact parameter range (can be used only for sim): {min, max}, with convention: min <= IP < max"}; + Configurable> cfEventPlaneAngle{"cfEventPlaneAngle", {-o2::constants::math::PI, o2::constants::math::TwoPI}, "Event Plane Angle range (can be used only for sim): {min, max}, with convention: min <= EP < max"}; + Configurable> cfOccupancy{"cfOccupancy", {-0.0001, 1000000000}, "Range for occupancy (use cfOccupancyEstimator to set specific estimator): {min, max}, with convention: min <= X < max. Important: remember that 0. has to be included, therefore I set -0.0001 by default for low edge"}; + Configurable> cfInteractionRate{"cfInteractionRate", {0.1, 1000000000.}, "Range for interaction rate (in kHz): {min, max}, with convention: min <= X < max"}; + Configurable> cfCurrentRunDuration{"cfCurrentRunDuration", {-2, 1000000000}, "Range for current run duration (i.e. seconds since start of run) in seconds: {min, max}, with convention: min <= X < max. Only collisions taken in this range (measured from SOR) are taken for analysis"}; + Configurable> cfMultMCNParticlesEta08{"cfMultMCNParticlesEta08", {-1, 1000000000}, "Range for MultMCNParticlesEta08 : {min, max}, with convention: min <= X < max"}; + Configurable cfTrigger{"cfTrigger", "some supported trigger (e.g. \"kINT7\" for Run 2, \"kTVXinTRD\" for Run 3, etc...)", "set here some supported trigger"}; + Configurable cfUseSel7{"cfUseSel7", false, "use for Run 1 and 2 data and MC (see official doc)"}; + Configurable cfUseSel8{"cfUseSel8", false, "use for Run 3 data and MC (see official doc)"}; + Configurable cfMultiplicityEstimator{"cfMultiplicityEstimator", "SelectedTracks", "all results vs. mult are calculated against this multiplicity. Can be set to SelectedTracks (calculated internally), ReferenceMultiplicity (calculated outside of my code), etc."}; + Configurable cfReferenceMultiplicityEstimator{"cfReferenceMultiplicityEstimator", "MultFT0C", "Reference multiplicity, calculated outside of my code. Can be MultFT0C, MultFV0M, MultTPC, etc."}; + // Configurable cfCentralityEstimator{"cfCentralityEstimator", "some supported centrality estimator (e.g. CentFT0C, ...)", "set here some supported centrality estimator (CentFT0C, CentFT0M, CentFV0A, CentNTPV, ... for Run 3, and CentRun2V0M, CentRun2SPDTracklets, ..., for Run 2 and 1) "}; + Configurable cfCentralityEstimator{"cfCentralityEstimator", "CentFT0C", "set here some supported centrality estimator (CentFT0C, CentFT0M, CentFV0A, CentNTPV, ... for Run 3, and CentRun2V0M, CentRun2SPDTracklets, ..., for Run 2 and 1) "}; + Configurable> cfSelectedEvents{"cfSelectedEvents", {-1, 1000000000}, "Selected number of events to process (i.e. only events which survive event cuts): {min, max}, with convention: min <= N < max"}; + Configurable cfUseNoSameBunchPileup{"cfUseNoSameBunchPileup", false, "TBI 20240521 explanation"}; + Configurable cfUseIsGoodZvtxFT0vsPV{"cfUseIsGoodZvtxFT0vsPV", false, "TBI 20240521 explanation"}; + Configurable cfUseIsVertexITSTPC{"cfUseIsVertexITSTPC", false, "TBI 20240521 explanation"}; + Configurable cfUseIsVertexTOFmatched{"cfUseIsVertexTOFmatched", false, "TBI 20240521 explanation"}; + Configurable cfUseIsVertexTRDmatched{"cfUseIsVertexTRDmatched", false, "TBI 20240521 explanation"}; + Configurable cfUseNoCollInTimeRangeStrict{"cfUseNoCollInTimeRangeStrict", false, "TBI 20240521 explanation"}; + Configurable cfUseNoCollInTimeRangeStandard{"cfUseNoCollInTimeRangeStandard", false, "TBI 20240521 explanation"}; + Configurable cfUseNoCollInRofStrict{"cfUseNoCollInRofStrict", false, "TBI 20240521 explanation"}; + Configurable cfUseNoCollInRofStandard{"cfUseNoCollInRofStandard", false, "TBI 20240521 explanation"}; + Configurable cfUseNoHighMultCollInPrevRof{"cfUseNoHighMultCollInPrevRof", false, "TBI 20240521 explanation"}; + Configurable cfUseIsGoodITSLayer3{"cfUseIsGoodITSLayer3", false, "TBI 20241220 explanation (or see enum)"}; + Configurable cfUseIsGoodITSLayer0123{"cfUseIsGoodITSLayer0123", false, "TBI 20241220 explanation (or see enum)"}; + Configurable cfUseIsGoodITSLayersAll{"cfUseIsGoodITSLayersAll", false, "TBI 20241220 explanation (or see enum)"}; + Configurable cfUseNoPileupTPC{"cfUseNoPileupTPC", false, "TBI 20250318 explanation"}; + Configurable cfUseNoPileupFromSPD{"cfUseNoPileupFromSPD", false, "TBI 20250318 explanation"}; + Configurable cfUseNoSPDOnVsOfPileup{"cfUseNoSPDOnVsOfPileup", false, "TBI 20250318 explanation"}; + Configurable cfOccupancyEstimator{"cfOccupancyEstimator", "FT0COccupancyInTimeRange", "set here some supported occupancy estimator (TrackOccupancyInTimeRange, FT0COccupancyInTimeRange, ..."}; + Configurable cfRefMultVsNContrUp{"cfRefMultVsNContrUp", "1200. + 0.20*x", "set here some TF1 formula for the upper boundary cut in RefMult_vs_NContr correlation"}; + Configurable cfRefMultVsNContrLow{"cfRefMultVsNContrLow", "-650. + 0.08*x", "set here some TF1 formula for the lower boundary cut in RefMult_vs_NContr correlation"}; + Configurable cfCentralityCorrelationsCut{"cfCentralityCorrelationsCut", "CentFT0C_CentFT0M", "Indicate two centrality estimators for the calculation of centrality correlation cut"}; + Configurable cfCentralityCorrelationsCutTreshold{"cfCentralityCorrelationsCutTreshold", 10.0, "set the treshold for centrality correlation cut"}; + Configurable cfCentralityCorrelationsCutVersion{"cfCentralityCorrelationsCutVersion", "Absolute", "set the version of centrality correlation cut. Supported: \"Relative\" and \"Absolute\""}; + +} cf_ec; + +// *) Particle histograms: +struct : ConfigurableGroup { + Configurable cfFillParticleHistograms{"cfFillParticleHistograms", true, "if false, all 1D particle histograms are not filled. if kTRUE, the ones for which fBookParticleHistograms[...] is kTRUE, are filled"}; + Configurable> cfBookParticleHistograms{"cfBookParticleHistograms", {"1-Phi", "1-Pt", "1-Eta", "1-Charge", "1-tpcNClsFindable", "1-tpcNClsShared", "1-itsChi2NCl", "1-tpcNClsFound", "1-tpcNClsCrossedRows", "1-itsNCls", "1-itsNClsInnerBarrel", "1-tpcCrossedRowsOverFindableCls", "1-tpcFoundOverFindableCls", "1-tpcFractionSharedCls", "1-tpcChi2NCl", "1-dcaXY", "1-dcaZ", "0-PDG"}, "Book (1) or do not book (0) particle histogram"}; + Configurable cfFillParticleHistograms2D{"cfFillParticleHistograms2D", false, "if false, all 2D particle histograms are not filled. if kTRUE, the ones for which fBookParticleHistograms2D[...] is kTRUE, are filled"}; + Configurable> cfBookParticleHistograms2D{"cfBookParticleHistograms2D", {"1-Phi_vs_Pt", "1-Phi_vs_Eta"}, "Book (1) or do not book (0) 2D particle histograms"}; + Configurable cfRebinSparse{"cfRebinSparse", 1, "used only for all fixed-length bins which are implemented directly for sparse histograms (i.e. not inherited from results histograms)"}; + Configurable> cfBookParticleSparseHistograms{"cfBookParticleSparseHistograms", {"0-DWPhi", "0-DWPt", "0-DWEta"}, "Book (1) or do not book (0) particular category of sparse histograms"}; + // TBI 20250223 add eventually configurable for FillParticleSparseHistogramsDimension +} cf_ph; + +// *) Particle cuts: +struct : ConfigurableGroup { + Configurable> cfUseParticleCuts{"cfUseParticleCuts", {"1-Phi", "1-Pt", "1-Eta", "1-Charge", "1-tpcNClsFindable", "1-tpcNClsShared", "1-itsChi2NCl", "1-tpcNClsFound", "1-tpcNClsCrossedRows", "1-itsNCls", "1-itsNClsInnerBarrel", "1-tpcCrossedRowsOverFindableCls", "1-tpcFoundOverFindableCls", "1-tpcFractionSharedCls", "1-tpcChi2NCl", "1-dcaXY", "1-dcaZ", "1-PDG", "0-trackCutFlag", "0-trackCutFlagFb1", "0-trackCutFlagFb2", "0-isQualityTrack", "1-isPrimaryTrack", "0-isInAcceptanceTrack", "0-isGlobalTrack", "1-isPVContributor", "0-PtDependentDCAxyParameterization"}, "Use (1) or do not use (0) particle cuts"}; + Configurable cfUseParticleCutCounterAbsolute{"cfUseParticleCutCounterAbsolute", false, "profile and save how many times each particle cut counter triggered (absolute). Use with care, as this is computationally heavy"}; + Configurable cfUseParticleCutCounterSequential{"cfUseParticleCutCounterSequential", false, "profile and save how many times each particle cut counter triggered (sequential). Use with care, as this is computationally heavy"}; + Configurable> cfPhi{"cfPhi", {0.0, o2::constants::math::TwoPI}, "phi range: {min, max}[rad], with convention: min <= phi < max"}; + Configurable> cfPt{"cfPt", {0.2, 5.0}, "pt range: {min, max}[GeV], with convention: min <= pt < max"}; + Configurable> cfEta{"cfEta", {-0.8, 0.8}, "eta range: {min, max}, with convention: min <= eta < max"}; + Configurable> cfCharge{"cfCharge", {-1.5, 1.5}, "particle charge. {-1.5,0} = only negative, {0,1.5} = only positive"}; + Configurable> cftpcNClsFindable{"cftpcNClsFindable", {-1000., 1000.}, "tpcNClsFindable range: {min, max}, with convention: min <= cftpcNClsFindable < max"}; + Configurable> cftpcNClsShared{"cftpcNClsShared", {-1000., 1000.}, "tpcNClsShared range: {min, max}, with convention: min <= cftpcNClsShared < max"}; + Configurable> cfitsChi2NCl{"cfitsChi2NCl", {-1000., 36.}, "itsChi2NCl range: {min, max}, with convention: min <= cfitsChi2NCl < max"}; + Configurable> cftpcNClsFound{"cftpcNClsFound", {70., 1000.}, "tpcNClsFound range: {min, max}, with convention: min <= cftpcNClsFound < max"}; + Configurable> cftpcNClsCrossedRows{"cftpcNClsCrossedRows", {70., 1000.}, "tpcNClsCrossedRows range: {min, max}, with convention: min <= tpcNClsCrossedRows < max"}; + Configurable> cfitsNCls{"cfitsNCls", {5., 1000.}, "itsNCls range: {min, max}, with convention: min <= itsNCls < max"}; + Configurable> cfitsNClsInnerBarrel{"cfitsNClsInnerBarrel", {-1000., 1000.}, "itsNClsInnerBarrel range: {min, max}, with convention: min <= cfitsNClsInnerBarrel < max"}; + Configurable> cftpcCrossedRowsOverFindableCls{"cftpcCrossedRowsOverFindableCls", {0.8, 1000.}, "tpcCrossedRowsOverFindableCls range: {min, max}, with convention: min <= cftpcCrossedRowsOverFindableCls < max"}; + Configurable> cftpcFoundOverFindableCls{"cftpcFoundOverFindableCls", {0.8, 1000.}, "tpcFoundOverFindableCls range: {min, max}, with convention: min <= cftpcFoundOverFindableCls < max"}; + Configurable> cftpcFractionSharedCls{"cftpcFractionSharedCls", {-1000., 0.4}, "tpcFractionSharedCls range: {min, max}, with convention: min <= cftpcFractionSharedCls < max"}; + Configurable> cftpcChi2NCl{"cftpcChi2NCl", {-1000., 4.}, "tpcChi2NCl range: {min, max}, with convention: min <= cftpcChi2NCl < max"}; + Configurable> cfdcaXY{"cfdcaXY", {-2.4, 2.4}, "dcaXY range: {min, max}, with convention: min <= dcaXY < max (yes, DCA can be negative!)"}; + Configurable> cfdcaZ{"cfdcaZ", {-3.2, 3.2}, "dcaZ range: {min, max}, with convention: min <= dcaZ < max (yes, DCA can be negative!)"}; + Configurable> cfPDG{"cfPDG", {-5000., 5000.}, "PDG code"}; + Configurable cftrackCutFlag{"cftrackCutFlag", false, "general selection, particle cuts are tuned centrally. Use only in Run 3."}; + Configurable cftrackCutFlagFb1{"cftrackCutFlagFb1", false, "general selection + 1 point in ITS IB. Use only in Run 3."}; + Configurable cftrackCutFlagFb2{"cftrackCutFlagFb2", false, "general selection + 2 point in ITS IB. Use only in Run 3."}; + Configurable cfisQualityTrack{"cfisQualityTrack", false, "TBI 20240510 add description"}; + Configurable cfisPrimaryTrack{"cfisPrimaryTrack", true, "Set to true by default both in Run 3 and Run 2 TBI 20250319 validate still for Run 1"}; + Configurable cfisInAcceptanceTrack{"cfisInAcceptanceTrack", false, "TBI 20250113 obsolete - see enum, to be removed"}; + Configurable cfisGlobalTrack{"cfisGlobalTrack", false, "TBI 20240510 add description"}; + Configurable cfisPVContributor{"cfisPVContributor", false, "Has this track contributed to the collision vertex fit"}; + Configurable cfPtDependentDCAxyParameterization{"cfPtDependentDCAxyParameterization", "some formula TBI add some default formula, e.g. 0.0105+0.0350/x^1.1", "set here formula for pt-dependence DCAxy cut, in the following example format 0.0105+0.0350/x^1.1"}; + // TBI 20240426 do I need to add separate support for booleans to use each specific cut? +} cf_pc; + +// *) Q-vector: +struct : ConfigurableGroup { + Configurable cfCalculateQvectors{"cfCalculateQvectors", true, "calculate or not Q-vectors (all, also diff. ones). If I want only to fill control histograms, then set here false"}; +} cf_qv; + +// *) Multiparticle correlations: +struct : ConfigurableGroup { + Configurable cfCalculateCorrelations{"cfCalculateCorrelations", false, "calculate or not multiparticle correlations"}; + Configurable cfCalculateCorrelationsAsFunctionOfIntegrated{"cfCalculateCorrelationsAsFunctionOfIntegrated", true, "calculate or not correlations as a function of integrated"}; + Configurable cfCalculateCorrelationsAsFunctionOfMultiplicity{"cfCalculateCorrelationsAsFunctionOfMultiplicity", true, "calculate or not correlations as a function of multiplicity"}; + Configurable cfCalculateCorrelationsAsFunctionOfCentrality{"cfCalculateCorrelationsAsFunctionOfCentrality", true, "calculate or not correlations as a function of centrality"}; + Configurable cfCalculateCorrelationsAsFunctionOfPt{"cfCalculateCorrelationsAsFunctionOfPt", false, "calculate or not correlations as a function of pt"}; + Configurable cfCalculateCorrelationsAsFunctionOfEta{"cfCalculateCorrelationsAsFunctionOfEta", false, "calculate or not correlations as a function of eta"}; + Configurable cfCalculateCorrelationsAsFunctionOfOccupancy{"cfCalculateCorrelationsAsFunctionOfOccupancy", true, "calculate or not correlations as a function of occupancy"}; + Configurable cfCalculateCorrelationsAsFunctionOfInteractionRate{"cfCalculateCorrelationsAsFunctionOfInteractionRate", true, "calculate or not correlations as a function of interaction rate"}; + Configurable cfCalculateCorrelationsAsFunctionOfCurrentRunDuration{"cfCalculateCorrelationsAsFunctionOfCurrentRunDuration", true, "calculate or not correlations as a function of current run duration (i.e. vs. seconds since start of run)"}; + Configurable cfCalculateCorrelationsAsFunctionOfVz{"cfCalculateCorrelationsAsFunctionOfVz", true, "calculate or not correlations as a function of vertex z position"}; +} cf_mupa; + +// *) Test0: +struct : ConfigurableGroup { + Configurable cfCalculateTest0{"cfCalculateTest0", false, "calculate or not Test0"}; + Configurable cfCalculateTest0AsFunctionOfIntegrated{"cfCalculateTest0AsFunctionOfIntegrated", false, "calculate or not Test0 as a function of integrated"}; + Configurable cfCalculateTest0AsFunctionOfMultiplicity{"cfCalculateTest0AsFunctionOfMultiplicity", false, "calculate or not Test0 as a function of multiplicity"}; + Configurable cfCalculateTest0AsFunctionOfCentrality{"cfCalculateTest0AsFunctionOfCentrality", false, "calculate or not Test0 as a function of centrality"}; + Configurable cfCalculateTest0AsFunctionOfPt{"cfCalculateTest0AsFunctionOfPt", false, "calculate or not Test0 as a function of pt"}; + Configurable cfCalculateTest0AsFunctionOfEta{"cfCalculateTest0AsFunctionOfEta", false, "calculate or not Test0 as a function of eta"}; + Configurable cfCalculateTest0AsFunctionOfOccupancy{"cfCalculateTest0AsFunctionOfOccupancy", false, "calculate or not Test0 as a function of occupancy"}; + Configurable cfCalculateTest0AsFunctionOfInteractionRate{"cfCalculateTest0AsFunctionOfInteractionRate", false, "calculate or not Test0 as a function of interaction rate"}; + Configurable cfCalculateTest0AsFunctionOfCurrentRunDuration{"cfCalculateTest0AsFunctionOfCurrentRunDuration", false, "calculate or not Test0 as a function of current run duration (i.e. vs. seconds since start of run)"}; + Configurable cfCalculateTest0AsFunctionOfVz{"cfCalculateTest0AsFunctionOfVz", false, "calculate or not Test0 as a function of vertex z position"}; + Configurable cfFileWithLabels{"cfFileWithLabels", "/home/abilandz/DatasetsO2/labels.root", "path to external ROOT file which specifies all labels"}; // for AliEn file prepend "/alice/cern.ch/", for CCDB prepend "/alice-ccdb.cern.ch" + Configurable cfUseDefaultLabels{"cfUseDefaultLabels", false, "use default internally hardwired labels, only for testing purposes"}; + Configurable cfWhichDefaultLabels{"cfWhichDefaultLabels", "standard", "only for testing purposes, select one set of default labels, see GetDefaultObjArrayWithLabels for supported options"}; +} cf_t0; + +// *) Eta separation: +struct : ConfigurableGroup { + Configurable cfCalculateEtaSeparations{"cfCalculateEtaSeparations", false, "calculate or not 2p corr. vs. eta separations"}; + Configurable cfCalculateEtaSeparationsAsFunctionOfIntegrated{"cfCalculateEtaSeparationsAsFunctionOfIntegrated", false, "calculate or not 2p corr. vs. eta separations ..."}; + Configurable cfCalculateEtaSeparationsAsFunctionOfMultiplicity{"cfCalculateEtaSeparationsAsFunctionOfMultiplicity", false, "calculate or not 2p corr. vs. eta separations as a function of multiplicity"}; + Configurable cfCalculateEtaSeparationsAsFunctionOfCentrality{"cfCalculateEtaSeparationsAsFunctionOfCentrality", false, "calculate or not 2p corr. vs. eta separations as a function of centrality"}; + Configurable cfCalculateEtaSeparationsAsFunctionOfPt{"cfCalculateEtaSeparationsAsFunctionOfPt", false, "calculate or not 2p corr. vs. eta separations as a function of pt"}; + // Configurable cfCalculateEtaSeparationsAsFunctionOfEta{"cfCalculateEtaSeparationsAsFunctionOfEta", false, "this one doesn't make sense in this context"}; + Configurable cfCalculateEtaSeparationsAsFunctionOfOccupancy{"cfCalculateEtaSeparationsAsFunctionOfOccupancy", false, "calculate or not 2p corr. vs. eta separations as a function of occupancy"}; + Configurable cfCalculateEtaSeparationsAsFunctionOfInteractionRate{"cfCalculateEtaSeparationsAsFunctionOfInteractionRate", false, "calculate or not 2p corr. vs. eta separations as a function of interaction rate"}; + Configurable cfCalculateEtaSeparationsAsFunctionOfCurrentRunDuration{"cfCalculateEtaSeparationsAsFunctionOfCurrentRunDuration", false, "calculate or not 2p corr. vs. eta separations as a function of current run duration (i.e. vs. seconds since start of run)"}; + Configurable cfCalculateEtaSeparationsAsFunctionOfVz{"cfCalculateEtaSeparationsAsFunctionOfVz", false, "calculate or not 2p corr. vs. eta separations as a function of vertex z position"}; + Configurable> cfEtaSeparationsValues{"cfEtaSeparationsValues", {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8}, "Eta separation between interval A (-eta) and B (+eta)"}; + Configurable> cfEtaSeparationsSkipHarmonics{"cfEtaSeparationsSkipHarmonics", {"0-v1", "0-v2", "0-v3", "0-v4", "1-v5", "1-v6", "1-v7", "1-v8", "1-v9"}, "For calculation of 2p correlation with eta separation these harmonics will be skipped (if first flag = \"0-v1\", v1 will be NOT be skipped in the calculus of 2p correlations with eta separations, etc.)"}; +} cf_es; + +// *) Particle weights: +struct : ConfigurableGroup { + Configurable cfUsePhiWeights{"cfUsePhiWeights", false, "use or not phi weights"}; + Configurable cfUsePtWeights{"cfUsePtWeights", false, "use or not pt weights"}; + Configurable cfUseEtaWeights{"cfUseEtaWeights", false, "use or not eta weights"}; + Configurable cfUseDiffPhiPtWeights{"cfUseDiffPhiPtWeights", false, "use or not differential phi(pt) weights"}; + Configurable cfUseDiffPhiEtaWeights{"cfUseDiffPhiEtaWeights", false, "use or not differential phi(eta) weights"}; + Configurable> cfWhichDiffPhiWeights{"cfWhichDiffPhiWeights", {"1-wPhi", "1-wPt", "1-wEta", "1-wCharge", "1-wCentrality", "1-wVertexZ"}, "use (1) or do not use (0) differential phi weight for particular dimension. If only phi is set to 1, integrated phi weights are used. If phi is set to 0, ALL dimensions are switched off (yes!)"}; + Configurable> cfWhichDiffPtWeights{"cfWhichDiffPtWeights", {"1-wPt"}, "use (1) or do not use (0) differential pt weight for particular dimension. If only pt is set to 1, integrated pt weights are used. If pt is set to 0, ALL dimensions are switched off (yes!)"}; + Configurable> cfWhichDiffEtaWeights{"cfWhichDiffEtaWeights", {"1-wEta"}, "use (1) or do not use (0) differential eta weight for particular dimension. If only eta is set to 1, integrated eta weights are used. If eta is set to 0, ALL dimensions are switched off (yes!)"}; + Configurable cfFileWithWeights{"cfFileWithWeights", "/home/abilandz/DatasetsO2/weights.root", "path to external ROOT file which holds all particle weights in O2 format"}; // for AliEn file prepend "/alice/cern.ch/", for CCDB prepend "/alice-ccdb.cern.ch" +} cf_pw; + +// *) Centrality weights: +struct : ConfigurableGroup { + Configurable cfUseCentralityWeights{"cfUseCentralityWeights", false, "use or not centrality weights"}; + Configurable cfFileWithCentralityWeights{"cfFileWithCentralityWeights", "/home/abilandz/DatasetsO2/centralityWeights.root", "path to external ROOT file which holds centrality weights in O2 format"}; // for AliEn file prepend "/alice/cern.ch/", for CCDB prepend "/alice-ccdb.cern.ch" +} cf_cw; + +// *) Nested loops: +struct : ConfigurableGroup { + Configurable cfCalculateNestedLoops{"cfCalculateNestedLoops", false, "cross-check for all events all correlations with nested loops"}; + Configurable cfCalculateCustomNestedLoops{"cfCalculateCustomNestedLoops", false, "cross-check e-b-e all correlations with custom nested loops"}; + Configurable cfCalculateKineCustomNestedLoops{"cfCalculateKineCustomNestedLoops", false, "cross-check e-b-e all differential (vs. pt, eta, etc.) correlations with custom nested loops"}; + Configurable cfMaxNestedLoop{"cfMaxNestedLoop", -1, "if set to e.g. 4, all nested loops beyond that, e.g. 6-p and 8-p, are NOT calculated"}; +} cf_nl; + +// *) Toy NUA: +struct : ConfigurableGroup { + Configurable> cfApplyNUAPDF{"cfApplyNUAPDF", {0, 0, 0}, "Apply (1) or do not apply (0) NUA on variable, ordering is the same as in enum eNUAPDF (phi, pt, eta)"}; + Configurable> cfUseDefaultNUAPDF{"cfUseDefaultNUAPDF", {1, 1, 1}, "Use (1) or do not use (0) default NUA profile, ordering is the same as in enum eNUAPDF (phi, pt, eta)"}; + Configurable> cfCustomNUAPDFHistNames{"cfCustomNUAPDFHistNames", {"a", "bb", "ccc"}, "the names of histograms holding custom NUA in an external file."}; + Configurable cfFileWithCustomNUA{"cfFileWithCustomNUA", "/home/abilandz/DatasetsO2/customNUA.root", "path to external ROOT file which holds all histograms with custom NUA"}; // for AliEn file prepend "/alice/cern.ch/", for CCDB prepend "/alice-ccdb.cern.ch" +} cf_nua; + +// *) Internal validation: +struct : ConfigurableGroup { + Configurable cfUseInternalValidation{"cfUseInternalValidation", false, "perform internal validation using flow analysis on-the-fly"}; + Configurable cfInternalValidationForceBailout{"cfInternalValidationForceBailout", false, "force bailout (use only locally, since there is no graceful exit (yet))"}; + Configurable cfnEventsInternalValidation{"cfnEventsInternalValidation", 0, "number of events simulated on-the-fly for internal validation"}; + Configurable cfHarmonicsOptionInternalValidation{"cfHarmonicsOptionInternalValidation", "constant", "for internal validation, supported options are \"constant\", \"correlated\" and \"persistent\""}; + Configurable cfRescaleWithTheoreticalInput{"cfRescaleWithTheoreticalInput", false, "if kTRUE, all correlators are rescaled with theoretical input, so that all results in profiles are 1"}; + Configurable> cfInternalValidationAmplitudes{"cfInternalValidationAmplitudes", {0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09}, "{v1, v2, v3, v4, ...} + has an effect only in combination with cfHarmonicsOptionInternalValidation = \"constant\". Max number of vn's is gMaxHarmonic."}; + Configurable> cfInternalValidationPlanes{"cfInternalValidationPlanes", {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, "{Psi1, Psi2, Psi3, Psi4, ...} + has an effect only in combination with cfHarmonicsOptionInternalValidation = \"constant\". Max number of Psin's is gMaxHarmonic."}; + Configurable> cfMultRangeInternalValidation{"cfMultRangeInternalValidation", {1000, 1001}, "{min, max}, with convention: min <= M < max"}; +} cf_iv; + +// *) Results histograms: +struct : ConfigurableGroup { + Configurable cfSaveResultsHistograms{"cfSaveResultsHistograms", false, "save or not results histograms"}; + + // Fixed-length binning (default): + Configurable> cfFixedLength_mult_bins{"cfFixedLength_mult_bins", {2000, 0., 20000.}, "nMultBins, multMin, multMax (only for results histograms)"}; + Configurable> cfFixedLength_cent_bins{"cfFixedLength_cent_bins", {110, 0., 110.}, "nCentBins, centMin, centMax (only for results histograms)"}; + Configurable> cfFixedLength_pt_bins{"cfFixedLength_pt_bins", {1000, 0., 10.}, "nPtBins, ptMin, ptMax (only for results histograms)"}; + Configurable> cfFixedLength_eta_bins{"cfFixedLength_eta_bins", {80, -2., 2.}, "nEtaBins, etaMin, etaMax (only for results histograms)"}; + Configurable> cfFixedLength_occu_bins{"cfFixedLength_occu_bins", {200, 0., 60000.}, "nOccuBins, occuMin, occuMax (only for results histograms)"}; + Configurable> cfFixedLength_ir_bins{"cfFixedLength_ir_bins", {1000, 0., 100.}, "nirBins, irMin, irMax (only for results histograms)"}; + Configurable> cfFixedLength_crd_bins{"cfFixedLength_crd_bins", {100000, 0., 100000.}, "ncrdBins, crdMin, crdMax (only for results histograms)"}; + Configurable> cfFixedLength_vz_bins{"cfFixedLength_vz_bins", {400, -20., 20.}, "nvzBins, vzMin, vzMax (only for results histograms)"}; + + // Variable-length binning (per request): + Configurable cfUseVariableLength_mult_bins{"cfUseVariableLength_mult_bins", false, "use or not variable-length multiplicity bins"}; + Configurable> cfVariableLength_mult_bins{"cfVariableLength_mult_bins", {0., 5., 6., 7., 8., 9., 100., 200., 500., 1000., 10000.}, "variable-length multiplicity bins"}; + Configurable cfUseVariableLength_cent_bins{"cfUseVariableLength_cent_bins", false, "use or not variable-length centrality bins"}; + Configurable> cfVariableLength_cent_bins{"cfVariableLength_cent_bins", {0., 10., 50., 100.}, "variable-length centrality bins"}; + Configurable cfUseVariableLength_pt_bins{"cfUseVariableLength_pt_bins", true, "use or not variable-length pt bins"}; + Configurable> cfVariableLength_pt_bins{"cfVariableLength_pt_bins", {0.20, 0.25, 0.30, 0.35, 0.40, 0.50, 0.60, 0.80, 1.00, 1.25, 1.50, 1.75, 2.00, 2.50, 3.00, 4.00, 5.00}, "variable-length pt bins"}; + Configurable cfUseVariableLength_eta_bins{"cfUseVariableLength_eta_bins", true, "use or not variable-length eta bins"}; + Configurable> cfVariableLength_eta_bins{"cfVariableLength_eta_bins", {-0.8, -0.6, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.6, 0.8}, "variable-length eta bins"}; + Configurable cfUseVariableLength_occu_bins{"cfUseVariableLength_occu_bins", false, "use or not variable-length occupancy bins"}; + Configurable> cfVariableLength_occu_bins{"cfVariableLength_occu_bins", {0., 5., 6., 7., 8., 9., 100., 200., 500., 1000., 10000.}, "variable-length occupancy bins"}; + Configurable cfUseVariableLength_ir_bins{"cfUseVariableLength_ir_bins", false, "use or not variable-length interaction rate bins"}; + Configurable> cfVariableLength_ir_bins{"cfVariableLength_ir_bins", {0., 5., 10., 50., 100., 200.}, "variable-length ineraction rate bins"}; + Configurable cfUseVariableLength_crd_bins{"cfUseVariableLength_crd_bins", false, "use or not variable-length current run duration bins"}; + Configurable> cfVariableLength_crd_bins{"cfVariableLength_crd_bins", {0., 5., 10., 50., 100., 500.}, "variable-length current run duration bins"}; + Configurable cfUseVariableLength_vz_bins{"cfUseVariableLength_vz_bins", false, "use or not variable-length vertex z bins"}; + Configurable> cfVariableLength_vz_bins{"cfVariableLength_vz_bins", {-10., -8., -6., -4, -2., -1., 0., 1., 2., 4., 6., 8., 10.}, "variable-length vertex z bins"}; + +} cf_res; #endif // PWGCF_MULTIPARTICLECORRELATIONS_CORE_MUPA_CONFIGURABLES_H_ diff --git a/PWGCF/MultiparticleCorrelations/Core/MuPa-DataMembers.h b/PWGCF/MultiparticleCorrelations/Core/MuPa-DataMembers.h index 9e11900ce2c..1a083a64471 100644 --- a/PWGCF/MultiparticleCorrelations/Core/MuPa-DataMembers.h +++ b/PWGCF/MultiparticleCorrelations/Core/MuPa-DataMembers.h @@ -12,11 +12,9 @@ #ifndef PWGCF_MULTIPARTICLECORRELATIONS_CORE_MUPA_DATAMEMBERS_H_ #define PWGCF_MULTIPARTICLECORRELATIONS_CORE_MUPA_DATAMEMBERS_H_ -// Remarks: -// 0. Starting with C++11, it's possible to initialize data members at -// declaration, so I do it here -// 1. Use //! 0. Set to <=0 to ignore. - Bool_t fUseStopwatch = kFALSE; // do some basing profiling with TStopwatch for where the execution time is going - TStopwatch* fTimer[eTimer_N] = {NULL}; // stopwatch, global (overal execution time) and local - // Bool_t fRescaleWithTheoreticalInput; // if kTRUE, all measured correlators are - // rescaled with theoretical input, so that in profiles everything is at 1. Used - // both in OTF and internal val. -} tc; // "tc" labels an instance of this group of variables. + TString fTaskIsConfiguredFromJson = "no"; // the trick to ensure that settings from JSON are taken into account, even if only one configurable is misconfigured, when everything dies silently + TString fTaskName = ""; // task name - this one is used to get the right weights programatically for this analysis. + // If not set, weights are fetched from TDirectoryFile whose name ends with "multiparticle-correlations-a-b" (default) + // If set to "someName", weights are fetched from TDirectoryFile whose name ends with "multiparticle-correlations-a-b_someName" + // TBI 20250122 Therefore, when running in HL, it's important to configure manually cfTaskName to be exactly the same as subwagon name. + // Can I automate this? + TString fRunNumber = ""; // over which run number this task is executed + bool fRunNumberIsDetermined = false; // ensures that run number is determined in process() and propagated to already booked objects only once + int64_t fRunTime[eRunTime_N] = {0}; // stores permanently start of run, end of run, and run duration + bool fDryRun = false; // book all histos and run without storing and calculating anything + bool fVerbose = false; // print additional info during debugging, but not for simply utility function or function calls per particle (see next) + bool fVerboseUtility = false; // print additional info during debugging also for simply utility function, but not for function calls per particle (see next) + bool fVerboseForEachParticle = false; // print additional info during debugging, also for function calls per particle + bool fVerboseEventCounter = true; // print or not only event counter + bool fVerboseEventCut = true; // print or not only which event cut didn't survive + bool fPlainPrintout = false; // print in color or in plain (use the latter in HL) + bool fDoAdditionalInsanityChecks = false; // do additional insanity checks at run time, at the expense of losing a bit of performance + // (for instance, check if the run number in the current 'collision' is the same as run number in the first 'collision', etc.) + bool fInsanityCheckForEachParticle = false; // do additional insanity checks at run time for each particle, at the expense of losing a lot of performance. Use only during debugging. + bool fProcess[eProcess_N] = {false}; // set what to process. See enum eProcess for full description. Set via implicit variables within a PROCESS_SWITCH clause. + TString fWhichProcess = "ProcessRec"; // dump in this variable which process was used + UInt_t fRandomSeed = 0; // argument for TRandom3 constructor. By default it is 0 (seed is guaranteed to be unique in time and space) + bool fUseFisherYates = false; // algorithm used to randomize particle indices, set via configurable + TArrayI* fRandomIndices = NULL; // array to store random indices obtained from Fisher-Yates algorithm + int fFixedNumberOfRandomlySelectedTracks = -1; // use a fixed number of randomly selected particles in each event, applies to all centralities. It is set and applied if > 0. Set to <=0 to ignore. + + bool fUseStopwatch = false; // do some basing profiling with TStopwatch for where the execution time is going + TStopwatch* fTimer[eTimer_N] = {NULL}; // stopwatch, global (overal execution time) and local + float fFloatingPointPrecision = 1.e-6; // two floats are the same if TMath::Abs(f1 - f2) < fFloatingPointPrecision (there is configurable for it) + int fSequentialBailout = 0; // if fSequentialBailout > 0, then each fSequentialBailout events the function BailOut() is called. Can be used for real analysis and for IV. + bool fUseSpecificCuts = false; // apply after DefaultCuts() also hardwired analysis-specific cuts, determined via tc.fWhichSpecificCuts + TString fWhichSpecificCuts = ""; // determine which set of analysis-specific cuts will be applied after DefaultCuts(). Use in combination with tc.fUseSpecificCuts + TString fSkipTheseRuns = ""; // comma-separated list of runs which will be skipped during analysis in hl (a.k.a. "bad runs") + bool fSkipRun = false; // based on the content of fWhichSpecificCuts, skip or not the current run +} tc; // "tc" labels an instance of this group of variables. // *) Event-by-event quantities: struct EventByEventQuantities { - Int_t fSelectedTracks = 0; // integer counter of tracks used to calculate Q-vectors, after all particle cuts have been applied - Double_t fCentrality = 0.; // event-by-event centrality from default estimator -} ebye; // "ebye" is a common label for objects in this struct + int fSelectedTracks = 0; // integer counter of tracks used to calculate Q-vectors, after all particle cuts have been applied + float fMultiplicity = 0.; // my internal multiplicity, can be set to fSelectedTracks (calculated internally), fReferenceMultiplicity (calculated outside of my code), etc. + // Results "vs. mult" are plotted against fMultiplicity, whatever it is set to. + // Use configurable cfMultiplicityEstimator[eMultiplicityEstimator] to define what is this multiplicity, by default it is "SelectedTracks" + float fReferenceMultiplicity = 0.; // reference multiplicity, calculated outside of my code. Can be "MultTPC", "MultFV0M", etc. + // Use configurable cfReferenceMultiplicityEstimator[eReferenceMultiplicityEstimator]" to define what is this multiplicity, by default it is "TBI 20241123 I do not know yet which estimator is best for ref. mult." + float fCentrality = 0.; // event-by-event centrality. Value of the default centrality estimator, set via configurable cfCentralityEstimator + float fOccupancy = 0.; // event-by-event occupancy. Value of the default occupancy estimator, set via configurable cfOccupancyEstimator. + // Remebmer that collision with occupanct 0. shall NOT be rejected, therefore in configurable I set -0.0001 for low edge by default. + float fInteractionRate = 0.; // event-by-event interaction rate + float fCurrentRunDuration = 0.; // how many seconds after start of run this collision was taken, i.e. seconds after start of run (SOR) + float fVz = 0.; // vertex z position + float fFT0CAmplitudeOnFoundBC = 0.; // TBI20250331 finalize the comment here +} ebye; // "ebye" is a common label for objects in this struct // *) QA: +// Remark 1: I keep new histograms in this group, until I need them permanently in the analysis. Then, they are moved to EventHistograms or ParticleHistograms (yes, even if they are 2D). +// Remark 2: All 2D histograms book as TH2F, due to "stmem error" in terminate (see .cxx for further details) struct QualityAssurance { - TList* fQAList = NULL; //! event-by-event + // [reco, sim][before, after]. Type dimension is bin. + + TList* fQACorrelationsVsList = NULL; //! TBI 20250215 this is obsolete and superseeded with fUseDiffPhiWeights, etc. + TH1D* fDiffWeightsHist[eDiffWeights_N][gMaxBinsDiffWeights] = {{NULL}}; // histograms holding differential weights [phipt,phieta][bin number] => TBI 20250222 obsolete + + // ** sparse histograms: + THnSparse* fDiffWeightsSparse[eDiffWeightCategory_N] = {NULL}; // multidimensional sparse histogram to hold all differential phi-weights (as a function of pt, eta, etc.). + // each dimension has its own enum category, e.g. 0 = eDWPhi => eDiffPhiWeights, 1 = eDWPt => eDiffPtWeights, etc. + bool fUseDiffPhiWeights[eDiffPhiWeights_N] = {false}; // use differential phi weights, see enum eDiffPhiWeights for supported dimensions + bool fUseDiffPtWeights[eDiffPtWeights_N] = {false}; // use differential pt weights, see enum eDiffPtWeights for supported dimensions + bool fUseDiffEtaWeights[eDiffEtaWeights_N] = {false}; // use differential eta weights, see enum eDiffEtaWeights for supported dimensions + // ... + int fDWdimension[eDiffWeightCategory_N] = {0}; // dimension of differential weight for each category in current analysis + TArrayD* fFindBinVector[eDiffWeightCategory_N] = {NULL}; // this is the vector I use to find bin TBI 20250224 finalie description + + TString fFileWithWeights = ""; // path to external ROOT file which holds all particle weights + bool fParticleWeightsAreFetched = false; // ensures that particle weights are fetched only once +} pw; // "pw" labels an instance of this group of histograms + +// *) Centrality weights: +struct CentralityWeights { + TList* fCentralityWeightsList = NULL; // list to hold all Q-vector objects + TProfile* fCentralityWeightsFlagsPro = NULL; // profile to hold all flags for CentralityWeights + bool fUseCentralityWeights = false; // use centrality weights + TH1D* fCentralityWeightsHist = NULL; // histograms holding centrality weights + TString fFileWithCentralityWeights = ""; // path to external ROOT file which holds all centrality weights + bool fCentralityWeightsAreFetched = false; // ensures that centrality weights are fetched only once +} cw; // *) Nested loops: struct NestedLoops { - TList* fNestedLoopsList = NULL; // list to hold all nested loops objects - TProfile* fNestedLoopsFlagsPro = NULL; // profile to hold all flags for nested loops - Bool_t fCalculateNestedLoops = kTRUE; // calculate and store correlations with nested loops, as a cross-check - Bool_t fCalculateCustomNestedLoop = kFALSE; // validate e-b-e all correlations with custom nested loop - TProfile* fNestedLoopsPro[4][gMaxHarmonic][eAsFunctionOf_N] = {{{NULL}}}; //! multiparticle correlations from nested loops - //! [2p=0,4p=1,6p=2,8p=3][n=1,n=2,...,n=gMaxHarmonic][0=integrated,1=vs. - //! multiplicity,2=vs. centrality,3=pT,4=eta] - TArrayD* ftaNestedLoops[2] = {NULL}; //! e-b-e container for nested loops [0=angles;1=product of all weights] - // TArrayD *ftaNestedLoopsKine[gKineDependenceVariables][gMaxNoBinsKine][2]; - // //! e-b-e container for nested loops - // [0=pT,1=eta][kine.bin][0=angles;1=product of all weights] -} nl; // "nl" labels an instance of this group of histograms + TList* fNestedLoopsList = NULL; // list to hold all nested loops objects + TProfile* fNestedLoopsFlagsPro = NULL; // profile to hold all flags for nested loops + bool fCalculateNestedLoops = false; // calculate and store correlations with nested loops, as a cross-check + bool fCalculateCustomNestedLoops = false; // validate e-b-e all correlations with custom nested loop + bool fCalculateKineCustomNestedLoops = false; // validate e-b-e all differential (vs pt, eta, etc.) correlations with custom nested loop + int fMaxNestedLoop = -1; // if set to e.g. 4, all nested loops beyond that, e.g. 6-p and 8-p, are NOT calculated + TProfile* fNestedLoopsPro[4][gMaxHarmonic][eAsFunctionOf_N] = {{{NULL}}}; //! multiparticle correlations from nested loops + //! [2p=0,4p=1,6p=2,8p=3][n=1,n=2,...,n=gMaxHarmonic][0=integrated,1=vs. + //! multiplicity,2=vs. centrality,3=pT,4=eta] + TArrayD* ftaNestedLoops[2] = {NULL}; //! e-b-e container for nested loops [0=angles;1=product of all weights] + TArrayD* ftaNestedLoopsKine[eqvectorKine_N][gMaxNoBinsKine][2] = {{{NULL}}}; //! e-b-e container for nested loops // [0=pT,1=eta][kine bin][0=angles;1=product of all weights] +} nl; // "nl" labels an instance of this group of histograms + +// *) Toy NUA (can be applied both in real data analysis and in analysis 'on-the-fly', e.g. when running internal validation): +struct NUA { + TList* fNUAList = NULL; // list to hold all NUA objects + TProfile* fNUAFlagsPro = NULL; // profile to hold all flags for NUA objects + bool fApplyNUAPDF[eNUAPDF_N] = {false}; // apply NUA to particular kine variable (see the corresponding enum eNUAPDF) + bool fUseDefaultNUAPDF[eNUAPDF_N] = {true, true, true}; // by default, use simple hardcoded expressions for NUA acceptance profile + TF1* fDefaultNUAPDF[eNUAPDF_N] = {NULL}; // default distributions used as pdfs to simulate NUA on-the-fly + TH1D* fCustomNUAPDF[eNUAPDF_N] = {NULL}; // custom, user-supplied distributions used to simulate NUA + TString* fCustomNUAPDFHistNames[eNUAPDF_N] = {NULL}; // these are the names of histograms holding custom NUA in an external file. There is a configurable for this one. + TString fFileWithCustomNUA = ""; // path to external ROOT file which holds all histograms with custom NUA + Double_t fMaxValuePDF[eNUAPDF_N] = {0.}; // see algorithm used in Accept(...). I implemented it as a data member, so that it is not calculated again and again at each particle call +} nua; + +// *) Internal validation: +struct InternalValidation { + TList* fInternalValidationList = NULL; // list to hold all objects for internal validation + TProfile* fInternalValidationFlagsPro = NULL; // profile to hold all flags for internal validation + bool fUseInternalValidation = false; // use internal validation + bool fInternalValidationForceBailout = false; // force bailout in internal validation after either eNumberOfEvents or eSelectedEvents is reached. + // This is OK as long as I do not apply any event cuts in InternalValidation(). + // Remember that for each real event, I do fnEventsInternalValidation events on-the-fly. + // Can be used in combination with setting fSequentialBailout > 0. + UInt_t fnEventsInternalValidation = 0; // how many on-the-fly events will be sampled for each real event, for internal validation + TString* fHarmonicsOptionInternalValidation = NULL; // "constant", "correlated" or "persistent", see .cxx for full documentation + bool fRescaleWithTheoreticalInput = false; // if true, all measured correlators are rescaled with theoretical input, so that in profiles everything is at 1 + TArrayD* fInternalValidationVnPsin[2] = {NULL}; // 0 = { v1, v2, ... }, 1 = { Psi1, Psi2, ... } + int fMultRangeInternalValidation[2] = {0, 0}; // min and max values for uniform multiplicity distribution in on-the-fly analysis (convention: min <= M < max) +} iv; // *) Test0: struct Test0 { - TList* fTest0List = NULL; // list to hold all objects for Test0 - TProfile* fTest0FlagsPro = NULL; // store all flags for Test0 - Bool_t fCalculateTest0 = kFALSE; // calculate or not Test0 - TProfile* fTest0Pro[gMaxCorrelator][gMaxIndex][eAsFunctionOf_N] = {{{NULL}}}; //! [order][index][0=integrated,1=vs. multiplicity,2=vs. centrality,3=pT,4=eta] - TString* fTest0Labels[gMaxCorrelator][gMaxIndex] = {{NULL}}; // all labels: k-p'th order is stored in k-1'th index. So yes, I also store 1-p - Bool_t fCalculateTest0AsFunctionOf[eAsFunctionOf_N] = {true, true, true, false, false}; //! [0=integrated,1=vs. multiplicity,2=vs. centrality,3=pT,4=eta] - TString fFileWithLabels = ""; // path to external ROOT file which specifies all labels of interest - TH1I* fTest0LabelsPlaceholder = NULL; // store all Test0 labels in this histogram -} t0; // "t0" labels an instance of this group of histograms + TList* fTest0List = NULL; // list to hold all objects for Test0 + TProfile* fTest0FlagsPro = NULL; // store all flags for Test0 + bool fCalculateTest0 = false; // calculate or not Test0 + TProfile* fTest0Pro[gMaxCorrelator][gMaxIndex][eAsFunctionOf_N] = {{{NULL}}}; //! [order][index][0=integrated,1=vs. multiplicity,2=vs. centrality,3=pT,4=eta] + TString* fTest0Labels[gMaxCorrelator][gMaxIndex] = {{NULL}}; // all labels: k-p'th order is stored in k-1'th index. So yes, I also store 1-p + bool fCalculateTest0AsFunctionOf[eAsFunctionOf_N] = {false}; //! [0=integrated,1=vs. multiplicity,2=vs. centrality,3=pT,4=eta,5=vs. occupancy, ...] + TString fFileWithLabels = ""; // path to external ROOT file which specifies all labels of interest + bool fUseDefaultLabels = false; // use default labels hardwired in GetDefaultObjArrayWithLabels(), the choice is made with cfWhichDefaultLabels + TString fWhichDefaultLabels = ""; // only for testing purposes, select one set of default labels, see GetDefaultObjArrayWithLabels for supported options + TH1I* fTest0LabelsPlaceholder = NULL; // store all Test0 labels in this histogram +} t0; // "t0" labels an instance of this group of histograms + +// *) Eta separations: +struct EtaSeparations { + TList* fEtaSeparationsList; // list to hold all correlations with eta separations + TProfile* fEtaSeparationsFlagsPro; // profile to hold all flags for correlations with eta separations + bool fCalculateEtaSeparations; // calculate correlations with eta separations + bool fCalculateEtaSeparationsAsFunctionOf[eAsFunctionOf_N] = {false}; //! [0=integrated,1=vs. multiplicity,2=vs. centrality,3=pT,4=eta,5=vs. occupancy, ...] + float fEtaSeparationsValues[gMaxNumberEtaSeparations] = {-1.}; // this array holds eta separation interals for which 2p correlations with eta separation will be calculated + // See the corresponding cofigurable cfEtaSeparationsValues. If entry is -1, it's ignored + bool fEtaSeparationsSkipHarmonics[gMaxHarmonic] = {false}; // For calculation of 2p correlation with eta separation these harmonics will be skipped + TProfile* fEtaSeparationsPro[gMaxHarmonic][gMaxNumberEtaSeparations][eAsFunctionOf_N]; // [harmonic, 0 = v1, 8 = v9][ different eta Separations - see that enum ] [ AFO ] +} es; + +// *) Global cosmetics: +struct GlobalCosmetics { + TString srs[2] = {"rec", "sim"}; // used in the histogram name as index when saved to the file + TString srs_long[2] = {"reconstructed", "simulated"}; // used in the histogram title + TString sba[2] = {"before", "after"}; // used in the histogram name as index when saved to the file + TString sba_long[2] = {"before cuts", "after cuts"}; // used in the histogram title + TString scc[eCutCounter_N] = {"abs", "seq"}; // used in the histogram name as index when saved to the file + TString scc_long[eCutCounter_N] = {"absolute", "sequential"}; // used in the histogram title +} gc; // *) Results: struct Results { // This is in addition also sort of "abstract" interface, which defines common binning, etc., for other groups of histograms. TList* fResultsList = NULL; //! use only in Run 2 and Run 1. + // TBI 20250115 it removes 99% of events in MC LHC21i6a, check this further + eSel8, // See def. of sel8 in Ref. b) above. Event selection decision based on TVX => use only in Run 3, both for data and MC + // *) As of 20240410, kNoITSROFrameBorder (only in MC) and kNoTimeFrameBorder event selection cuts are part of Sel8 + // See also email from EK from 2024041 + eMultiplicityEstimator, // see documentation for ebye.fMultiplicity + eReferenceMultiplicityEstimator, // see documentation for ebye.fReferenceMultiplicity + eCentralityEstimator, // the default centrality estimator, set via configurable. All supported centrality estimators, for QA, etc, are in enum eCentralityEstimators + eSelectedEvents, // selected events = eNumberOfEvents + eAfter => therefore I do not need a special histogram for it + eNoSameBunchPileup, // reject collisions in case of pileup with another collision in the same foundBC (emails from IA on 20240404 and EK on 20240410) + eIsGoodZvtxFT0vsPV, // small difference between z-vertex from PV and from FT0 (emails from IA on 20240404 and EK on 20240410) + // Avoid using kIsGoodZvtxFT0vsPV selection bit for Pb-Pb 2024 apass1, see IA email from 20250115. + // Therefore, until further notice, use this one in LHC23zzh, but not in LHC24ar and LHC24as + eIsVertexITSTPC, // at least one ITS-TPC track (reject vertices built from ITS-only tracks) (emails from IA on 20240404 and EK on 20240410 + eIsVertexTOFmatched, // at least one of vertex contributors is matched to TOF + eIsVertexTRDmatched, // at least one of vertex contributors is matched to TRD + eNoCollInTimeRangeStrict, // rejects a collision if there are other events in dtime +/- 10 μs, see IA Slide 39 in https://indico.cern.ch/event/1462154/ + // 20250122 Per feedback from IA, use this one only as a part of systematic check, and use eNoCollInTimeRangeStandard by default + eNoCollInTimeRangeStandard, // rejects a collision if there are other events in dtime +/- 2 μs + additional cuts on multiplicity, see IA Slide 39 in https://indico.cern.ch/event/1462154/ + eNoCollInRofStrict, // rejects a collision if there are other events within the same ROF (in-ROF pileup), ROF = "ITS Readout Frames", + // see IA Slide 39 in https://indico.cern.ch/event/1462154/ + // 20250122 Per feedback from IA, use this one only as a part of systematic check, and use eNoCollInRofStandard by default + eNoCollInRofStandard, // same as previous + additional cuts on multiplicity, see IA Slide 39 in https://indico.cern.ch/event/1462154/ + eNoHighMultCollInPrevRof, // veto an event if FT0C amplitude in previous ITS ROF is above threshold (default is >5000 a.e. by FT0C), see IA Slide 39 in https://indico.cern.ch/event/1462154/ + // 20250122 Per feedback from IA, use it only in 2023 PbPb data (e.g. eLHC23zzh), in 2024 PbPb data this one has no effect (do not use in eLHC24ar and eLHC24as) + eIsGoodITSLayer3, // number of inactive chips on ITS layer 3 is below maximum allowed value + eIsGoodITSLayer0123, // numbers of inactive chips on ITS layers 0-3 are below maximum allowed values + eIsGoodITSLayersAll, // numbers of inactive chips on all ITS layers are below maximum allowed values + eOccupancyEstimator, // the default Occupancy estimator, set via configurable. All supported centrality estimators, for QA, etc, are in enum eOccupancyEstimators + eMinVertexDistanceFromIP, // if sqrt(vx^2+vy^2+vz^2) < MinVertexDistanceFromIP, the event is rejected. This way, I remove suspicious events with |vertex| = 0. + eNoPileupTPC, // no pileup in TPC + eNoPileupFromSPD, // no pileup according to SPD vertexer + eNoSPDOnVsOfPileup, // no out-of-bunch pileup according to online-vs-offline SPD correlation + eRefMultVsNContrUp, // formula for upper boundary cut in eReferenceMultiplicity_vs_NContributors (remember that I use naming convention "x_vs_y") + eRefMultVsNContrLow, // formula for lower boundary cut in eReferenceMultiplicity_vs_NContributors (remember that I use naming convention "x_vs_y") + eCentralityCorrelationsCut, // port of void SetCentralityCorrelationsCuts(...) from MuPa class. Example format: "CentFT0C_CentFT0M", so IFS is "_", until proven otherwise + // ... + eCentralityWeights, // used for centrality flattening. Remember that this event cut must be implemented very last, + // therefore I have it separately implemented for Run 3,2,1 in EventCuts() at the very end in each case. + // Use only for small non-uniformity in centrality distribution (e.g. of the biggest dip in distribution is up to 20% compared to uniform part of cent. distribution), + // otherwise this flattening is too costly in terms of statistics. eEventCuts_N }; +enum eEventCutsFormulas { // special treatment for all event cuts defined via mathematical formula, because for them I have to do one additional layer of booking using TFormula + eRefMultVsNContrUp_Formula = 0, + eRefMultVsNContrLow_Formula, + eEventCutsFormulas_N +}; + enum eParticleHistograms { + + // from o2::aod::Tracks (Track parameters at their point closest to the collision vertex) ePhi = 0, ePt, eEta, - etpcNClsCrossedRows, // from aod::TracksExtra - eDCA_xy, // from aod::TracksDCA - eDCA_z, + eCharge, // Charge: positive: 1, negative: -1 + + // from o2::aod::TracksExtra_001 - I keep the ordering here the same as in the TracksExtra_001 table + etpcNClsFindable, + etpcNClsShared, + eitsChi2NCl, // TBI 20250110 I see for this one [478682:track-selection]: [15:35:00][INFO] Track selection, set max chi2 per cluster ITS: 36 + // But even with open particle cuts, this distribution doesn't cross 30... There is a sudden drop round 22, but when I apply other cuts + // that tail is gone already. + etpcNClsFound, + etpcNClsCrossedRows, + eitsNCls, + eitsNClsInnerBarrel, + etpcCrossedRowsOverFindableCls, + etpcFoundOverFindableCls, // TBI 20250110 I keep this one in sync with values for etpcCrossedRowsOverFindableCls + etpcFractionSharedCls, + etpcChi2NCl, // TBI 20250110 this one shall resemble aodTrack->GetTPCchi2()/aodTrack->GetTPCNcls(), but cross-check with the experts. Particles with tpcChi2NCl > 4. I reject now by default. + // See what I documented in AliPhysics below // task->SetParticleCuts("TPCChi2perNDF",4.,-44); // VAL + // 20250123 in some Run 2 analysis, 2.5 was used as a default. Check that value as a part of systematics + // from o2::aod::TracksDCA + edcaXY, + edcaZ, + + // the rest: ePDG, + + // counter: eParticleHistograms_N }; +enum eParticleHistograms2D { // All 2D histograms are first implemented in eQAParticleHistograms2D, the ones which I need regularly, are then promoted to this category. + ePhiPt = 0, + ePhiEta, + eParticleHistograms2D_N +}; + enum eParticleCuts { - eTBI = 1, // here I start from 1 exceptionally, because these enums are used as bin contents, and ROOT starts counting bins from 1 + + // from o2::aod::TrackSelection (https://aliceo2group.github.io/analysis-framework/docs/datamodel/helperTaskTables.html#o2-analysis-trackselection) + // See also O2Physics/Common/DataModel/TrackSelectionTables.h + etrackCutFlag = eParticleHistograms_N, // General selection, with centrally tuned particle cuts for tpcNClsFound, itsNCls, etc. + // As of 20250113, this cut still has not effect, neither in Run 3 nor in converted Run 2. Use instead trackCutFlagFb1 and/or trackCutFlagFb2 below. + etrackCutFlagFb1, // Global tracks in Run 3. Closest possible match to global track definition in Run 2, which are selected with eisGlobalTrack. + // For the definition, see: + // a) "filtbit1" in https://github.com/AliceO2Group/O2Physics/blob/master/Common/TableProducer/trackselection.cxx#L128 + // b) "getGlobalTrackSelectionRun3ITSMatch" in https://github.com/AliceO2Group/O2Physics/blob/master/Common/Core/TrackSelectionDefaults.cxx#L43 + // When I use this flag, make sure I do NOT cut on something on which this cut is already cutting by default (e.g. pt-dependent DCA xy cut) + etrackCutFlagFb2, // Global tracks in Run 3, similar as etrackCutFlagFb1, but more stringent (since 2 points in ITS are required in inner barrel (IB)). + // Unlike etrackCutFlagFb1 (1 ITS point is required), it produces a 20% dip in azimuthal acceptance for 1.2 < phi < 1.6, in LHC24ar/559545 + // DCAxy and z are significantly further depleted, when compared to etrackCutFlagFb1 + eisQualityTrack, // Do not use in Run 3, but it can be used in Run 2 and Run 1 + // In Run 2, it is already requested in isGlobalTrack, through definition kGlobalTrack = kQualityTracks | kPrimaryTracks | kInAcceptanceTracks + // See O2Physics/Common/DataModel/TrackSelectionTables.h for further details. + // Therefore, vary in Run 2 only is isGlobalTrack is NOT requested by default. + eisPrimaryTrack, // Validated in Run 3. See also isPVContributor + // In Run 2, it is already requested in isGlobalTrack, through definition kGlobalTrack = kQualityTracks | kPrimaryTracks | kInAcceptanceTracks + // See O2Physics/Common/DataModel/TrackSelectionTables.h for further details. + // Therefore, vary in Run 2 only is isGlobalTrack is NOT requested by default. + eisInAcceptanceTrack, // kInAcceptanceTracks = kPtRange | kEtaRange . Pt is open, and |eta| < 0.8. + // But after I already cut directly on 0.2 < pt < 5.0 and |eta| < 0.8, it has no effect. + // Can be used both in Run 3 and Run 2. + // TBI 20250113 remove this cut eventually from the code, because I cut direcly on 0.2 < pt < 5.0 and |eta| < 0.8 in any case. + eisGlobalTrack, // Do not use in Run 3, it can be used directly only in Run 2 and Run 1, see definition in: + // https://github.com/AliceO2Group/O2Physics/blob/master/Common/Core/TrackSelectionDefaults.cxx#L23 + // For Run 3 global tracks, I need to use TrackSelection getGlobalTrackSelectionRun3ITSMatch(int matching, int passFlag) from + // https://github.com/AliceO2Group/O2Physics/blob/master/Common/Core/TrackSelectionDefaults.cxx#L43 + // That is precisely definition of filtBit1 in https://github.com/AliceO2Group/O2Physics/blob/master/Common/TableProducer/trackselection.cxx + // So: etrackCutFlagFb1 in Run 3 is a closest match to eisGlobalTrack in Run 2 + eisPVContributor, // Run 3: Has this track contributed to the collision vertex fit + // Tracks used in vertex fit are flagged as "contributors" (-> track.isPVContributor() for AO2D tracks). Such a track is + // allowed to contribute to only one PV. => See further details in RS presentation https://indico.cern.ch/event/1453901/timetable/#12-track-reconstruction + // This cut affects significantly distributions of other tracking parameters. Most notably, after using this cut, DCAz distribution is reduced to ~ 1mm range. + // But for global tracks in any case we request very stringent DCA cut. + // pt and eta distributions are only mildly affected. + // Do not use in Run 2 and Run 1. + // It's not the same as isPrimaryTrack cut, albeit there is an overlap. + // special treatment: + ePtDependentDCAxyParameterization, + eParticleCuts_N }; enum eAsFunctionOf { AFO_INTEGRATED = 0, - AFO_MULTIPLICITY = 1, // vs. default multiplicity, which is (at the moment) fSelectedTracks, i.e. number of tracks in Q-vector - AFO_CENTRALITY = 2, // vs. default centrality estimator, see how it's calculated in DetermineCentrality(...) - AFO_PT = 3, - AFO_ETA = 4, + AFO_MULTIPLICITY, // vs. default multiplicity, which is (at the moment) fSelectedTracks, i.e. number of tracks in Q-vector + AFO_CENTRALITY, // vs. default centrality estimator, see how it's calculated in DetermineCentrality(...) + AFO_PT, + AFO_ETA, + AFO_OCCUPANCY, // vs. default "occupancy" variable which is (at the moment) "FT0COccupancyInTimeRange" (alternative is "TrackOccupancyInTimeRange") + AFO_INTERACTIONRATE, // vs. "interation rate" + AFO_CURRENTRUNDURATION, // vs. "current run duration", i.e. vs "seconds since start of run" + AFO_VZ, // vs. "vertex z position" eAsFunctionOf_N }; // prefix is needed, to avoid conflict with enum eKinematics +enum eNUAPDF { + ePhiNUAPDF = 0, + ePtNUAPDF, + eEtaNUAPDF, + eNUAPDF_N +}; + enum eqvectorKine { // Here "kine" originally meant "kinematic", i.e. vs. pt or vs. eta, now it's general. PTq = 0, ETAq, @@ -121,4 +319,232 @@ enum eTimer { eLocal, eTimer_N }; + +enum eEventCounterForDryRun { + eFill = 0, + ePrint +}; + +enum eCutModus { + eCut = 0, // standard, i.e. no cut counters are used + eCutCounterBinning, // dry call to EventCuts and ParticleCuts, just to establish order of binning in CutCountets, which resembles order of cut implementation + eCutCounterAbsolute, + eCutCounterSequential +}; + +enum eCutCounter { + eAbsolute = 0, + eSequential, + eCutCounter_N +}; + +enum eQAEventHistograms2D { + // General (estimators can be chosen via configurables): + eMultiplicity_vs_ReferenceMultiplicity = 0, // multiplicity is x, reference multiplicity is y. I can swap offline if needed: histOriginal->GetBinContent(x,y); histSwapped->Fill(y,x); + eMultiplicity_vs_NContributors, + eMultiplicity_vs_Centrality, + eMultiplicity_vs_VertexZ, + eMultiplicity_vs_Occupancy, + eMultiplicity_vs_InteractionRate, // TBI 20250331 I ctd. below with more histos in category eMultiplicity_vs_... - re-organize at some point bookkeping here + eReferenceMultiplicity_vs_NContributors, + eReferenceMultiplicity_vs_Centrality, + eReferenceMultiplicity_vs_VertexZ, + eReferenceMultiplicity_vs_Occupancy, + eReferenceMultiplicity_vs_InteractionRate, + eNContributors_vs_Centrality, + eNContributors_vs_VertexZ, + eNContributors_vs_Occupancy, + eNContributors_vs_InteractionRate, + eCentrality_vs_VertexZ, + eCentrality_vs_Occupancy, + eCentrality_vs_ImpactParameter, // [sim] = reconstructed centrality vs. simulated impact parameter. [rec] = ... TBI 20241210 + eCentrality_vs_InteractionRate, + eVertexZ_vs_Occupancy, + eVertexZ_vs_InteractionRate, + // ... + // Specific (everything is hardwired): + eMultNTracksPV_vs_MultNTracksGlobal, // Run 3 multiplicity + eCentFT0C_vs_CentFT0CVariant1, // Run 3 centrality + eCentFT0C_vs_CentFT0M, // Run 3 centrality + eCentFT0C_vs_CentFV0A, // Run 3 centrality + eCentFT0C_vs_CentNTPV, // Run 3 centrality + eCentFT0C_vs_CentNGlobal, // Run 3 centrality + eCentFT0M_vs_CentNTPV, // Run 3 centrality + eCentRun2V0M_vs_CentRun2SPDTracklets, // Run 2 centrality (do not use in Run 1 converted, because there is no centrality information) + eTrackOccupancyInTimeRange_vs_FT0COccupancyInTimeRange, + eCurrentRunDuration_vs_InteractionRate, // ... + // ... + // Unsorted category: TBI 20250331 not sure if I will keep these ones permanently: + eMultiplicity_vs_FT0CAmplitudeOnFoundBC, + eCentFT0C_vs_FT0CAmplitudeOnFoundBC, + // ... + eQAEventHistograms2D_N +}; + +enum eQAParticleHistograms2D { + ePt_vs_dcaXY, + eQAParticleHistograms2D_N +}; + +enum eQAParticleEventHistograms2D { + // In this category I do correlation vs. some-event-property. + // The < ... > goes over all particles in that event. + // All < ... > over particles are calculated with helper TProfile fQAParticleEventProEbyE + // For instance: vs. current run duration + eCurrentRunDuration_vs_itsNClsEbyE, + eCurrentRunDuration_vs_itsNClsNegEtaEbyE, + eCurrentRunDuration_vs_itsNClsPosEtaEbyE, + eCurrentRunDuration_vs_Eta0804EbyE, + eCurrentRunDuration_vs_Eta0400EbyE, + eCurrentRunDuration_vs_Eta0004EbyE, + eCurrentRunDuration_vs_Eta0408EbyE, + eCurrentRunDuration_vs_Pt0005EbyE, + eCurrentRunDuration_vs_Pt0510EbyE, + eCurrentRunDuration_vs_Pt1050EbyE, + eQAParticleEventHistograms2D_N +}; + +enum eQAParticleEventProEbyE { + eitsNClsEbyE = 1, // Labels average in a given event (therefore "EbyE" is appended). Yes, from one, because it runs over bin content and entries in TProfile for most of the time. + eitsNClsNegEtaEbyE, // in a given event for eta < 0 + eitsNClsPosEtaEbyE, // in a given event for eta > 0 + eEta0804EbyE, // in a given event for -0.8 < eta < -0.4 + eEta0400EbyE, // in a given event for -0.4 < eta < 0.0 + eEta0004EbyE, // in a given event for 0.0 < eta < 0.4 + eEta0408EbyE, // in a given event for 0.4 < eta < 0.8 + ePt0005EbyE, // in a given event for 0.0 < pt < 0.5 + ePt0510EbyE, // in a given event for 0.5 < pt < 1.0 + ePt1050EbyE, // in a given event for 1.0 < pt < 5.0 + eMeanPhi, // in an event TBI 20250214 I need to unify naming convention for <> with previous enums in above in the series, but okay... + eMeanPt, // in an event + eMeanEta, // in an event + eMeanCharge, // in an event + eMeantpcNClsFindable, // in an event + eMeantpcNClsShared, // in an event + eMeanitsChi2NCl, // in an event + eMeantpcNClsFound, // in an event + eMeantpcNClsCrossedRows, // in an event + eMeanitsNCls, // in an event + eMeanitsNClsInnerBarrel, // in an event + eMeantpcCrossedRowsOverFindableCls, // in an event + eMeantpcFoundOverFindableCls, // in an event + eMeantpcFractionSharedCls, // in an event + eMeantpcChi2NCl, // in an event + eMeandcaXY, // in an event + eMeandcaZ, // in an event + eQAParticleEventProEbyE_N +}; + +enum eQACorrelationsVsHistograms2D { + // In this category I correlate <2> vs. some-event-property. + // For instance: <2> vs. ref. mult + // <2> vs. , where is calculated from all particles in that event (so in this sense, it's an event property as well) + // Remark 1: If I would ever need the same thingie for <4>, <6>, etc., just introduce new dimension in 2D histogram + // Remark 2: All < ... > over particles are calculated with helper TProfile fQAParticleEventProEbyE + eCorrelations_vs_Multiplicity = 0, + eCorrelations_vs_ReferenceMultiplicity, + eCorrelations_vs_Centrality, + // ... + eCorrelations_vs_MeanPhi, + eCorrelations_vs_MeanPt, + eCorrelations_vs_MeanEta, + eCorrelations_vs_MeanCharge, + eCorrelations_vs_MeantpcNClsFindable, + eCorrelations_vs_MeantpcNClsShared, + eCorrelations_vs_MeanitsChi2NCl, + eCorrelations_vs_MeantpcNClsFound, + eCorrelations_vs_MeantpcNClsCrossedRows, + eCorrelations_vs_MeanitsNCls, + eCorrelations_vs_MeanitsNClsInnerBarrel, + eCorrelations_vs_MeantpcCrossedRowsOverFindableCls, + eCorrelations_vs_MeantpcFoundOverFindableCls, + eCorrelations_vs_MeantpcFractionSharedCls, + eCorrelations_vs_MeantpcChi2NCl, + eCorrelations_vs_MeandcaXY, + eCorrelations_vs_MeandcaZ, + // ... + eQACorrelationsVsHistograms2D_N +}; + +enum eQACorrelationsVsInteractionRateVsProfiles2D_N { + // In this category I fill <2> in 2D profile spanned by IR vs. some-other-observable (IR is always x axis) + // For instance: <2> is filled in TProfile2D spanned by IR vs. CurrentRunDuration (crd) + // <2> is filled in TProfile2D spanned by IR vs. , where is calculated from all particles in that event + // Remark 1: If I would ever need the same thingie for <4>, <6>, etc., just introduce new dimension in 2D profile + // Remark 2: All < ... > over particles are calculated with helper TProfile fQAParticleEventProEbyE + eCorrelationsVsInteractionRate_vs_CurrentRunDuration = 0, + eCorrelationsVsInteractionRate_vs_Multiplicity, + eCorrelationsVsInteractionRate_vs_ReferenceMultiplicity, + eCorrelationsVsInteractionRate_vs_Centrality, + // ... + eCorrelationsVsInteractionRate_vs_MeanPhi, + eCorrelationsVsInteractionRate_vs_SigmaMeanPhi, + eCorrelationsVsInteractionRate_vs_MeanPt, + eCorrelationsVsInteractionRate_vs_SigmaMeanPt, + eCorrelationsVsInteractionRate_vs_MeanEta, + eCorrelationsVsInteractionRate_vs_SigmaMeanEta, + // ... + eQACorrelationsVsInteractionRateVsProfiles2D_N +}; + +enum eReferenceMultiplicityEstimators { + // Run 3: + eMultTPC = 0, + eMultFV0M, // ref. mult from helper task o2-analysis-multiplicity-table + eMultFT0C, // ref. mult from helper task o2-analysis-multiplicity-table + eMultFT0M, // ref. mult from helper task o2-analysis-multiplicity-table + eMultNTracksPV, // ref. mult from helper task o2-analysis-multiplicity-table + eMultNTracksGlobal, // ref. mult from helper task o2-analysis-multiplicity-table + // Run 2: + eMultTracklets, // ref. mult from helper task o2-analysis-multiplicity-table, use only for Run 2 + eReferenceMultiplicityEstimators_N +}; + +enum eCentralityEstimators { + // Run 3: + eCentFT0C = 0, + eCentFT0CVariant1, + eCentFT0M, + eCentFV0A, + eCentNTPV, + eCentNGlobal, + // Run 2: + eCentRun2V0M, + eCentRun2SPDTracklets, + eCentralityEstimators_N +}; + +enum eOccupancyEstimators { + eTrackOccupancyInTimeRange, // from helper task o2-analysis-event-selection, see also IA's presentation in https://indico.cern.ch/event/1464946, slide 38 + eFT0COccupancyInTimeRange, // from helper task o2-analysis-event-selection + eOccupancyEstimators_N +}; + +enum eEventCounter { + eTotal, // total number of events, before any cuts are applied + eProcessed, // number of processed events, i.e. number of events which survived cuts and on which analysis have been performed + eEventCounter_N +}; + +enum eSpecificCuts { + // Run 3: + eLHC23zzh, + eLHC24ar, + eLHC24as, + // Run 2: + eLHC15o, + // Run 1: + // ... + // Cuts for minimal subscription, "processTest": "true in JSON + eTestCuts, + eSpecificCuts_N +}; + +enum eRunTime { + eStartOfRun = 0, // in abs. seconds since Unix epoch + eEndOfRun, // in abs. seconds since Unix epoch + eDurationInSec, // in seconds + eRunTime_N +}; + #endif // PWGCF_MULTIPARTICLECORRELATIONS_CORE_MUPA_ENUMS_H_ diff --git a/PWGCF/MultiparticleCorrelations/Core/MuPa-GlobalConstants.h b/PWGCF/MultiparticleCorrelations/Core/MuPa-GlobalConstants.h index b7cc29c4232..e7a31c445df 100644 --- a/PWGCF/MultiparticleCorrelations/Core/MuPa-GlobalConstants.h +++ b/PWGCF/MultiparticleCorrelations/Core/MuPa-GlobalConstants.h @@ -12,10 +12,12 @@ #ifndef PWGCF_MULTIPARTICLECORRELATIONS_CORE_MUPA_GLOBALCONSTANTS_H_ #define PWGCF_MULTIPARTICLECORRELATIONS_CORE_MUPA_GLOBALCONSTANTS_H_ -const Int_t gMaxCorrelator = 12; -const Int_t gMaxHarmonic = 9; -const Int_t gMaxIndex = 300; // per order, used only in Test0 -const Int_t gMaxNoBinsKine = 1000; // max number of bins for differential q-vector -const Int_t fMaxBinsDiffWeights = 100; // max number of bins for differential weights, see MakeWeights.C +const int gMaxCorrelator = 12; +const int gMaxHarmonic = 9; +const int gMaxIndex = 300; // per order, used only in Test0 +const int gMaxNoBinsKine = 1000; // max number of bins for differential q-vector +const int gMaxBinsDiffWeights = 100; // max number of bins for differential weights, see MakeWeights.C +const int gMaxNumberEtaSeparations = 9; // max number of different eta separations used to calculated 2p corr. with eta separations +const int gMaxNumberSparseDimensions = 10; // max number of dimensions in sparse histograms #endif // PWGCF_MULTIPARTICLECORRELATIONS_CORE_MUPA_GLOBALCONSTANTS_H_ diff --git a/PWGCF/MultiparticleCorrelations/Core/MuPa-MemberFunctions.h b/PWGCF/MultiparticleCorrelations/Core/MuPa-MemberFunctions.h index fcce28e31ca..dc33b8d3d30 100644 --- a/PWGCF/MultiparticleCorrelations/Core/MuPa-MemberFunctions.h +++ b/PWGCF/MultiparticleCorrelations/Core/MuPa-MemberFunctions.h @@ -14,68 +14,100 @@ // ... #include +#include //============================================================ void BookBaseList() { - // ... + // Book base TList and store task configuration. + + // a) Book base TList; + // b) Store task configuration. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); } + // a) Book base TList: TList* temp = new TList(); - temp->SetOwner(kTRUE); + temp->SetOwner(true); fBaseList.setObject(temp); - // fBaseList.object->SetName("4444"); - fBasePro = new TProfile("fBasePro", "flags for the whole analysis", - eConfiguration_N, 0., eConfiguration_N); - fBasePro->SetStats(kFALSE); + // b) Store task configuration: + fBasePro = new TProfile("fBasePro", "flags for the whole analysis", eConfiguration_N - 1, 0.5, static_cast(eConfiguration_N) - 0.5); + // yes, eConfiguration_N - 1 and -0.5, because eConfiguration kicks off from 1 + fBasePro->SetStats(false); fBasePro->SetLineColor(eColor); fBasePro->SetFillColor(eFillColor); - // Remark: If I want to change the ordering of bin lables, simply change the + // Remark: If I want to change the ordering of bin labels, simply change the // ordering in enum eConfiguration { ... }, nothing needs to be changed here. - fBasePro->GetXaxis()->SetBinLabel(eTaskName, - Form("fTaskName = %s", tc.fTaskName.Data())); + fBasePro->GetXaxis()->SetBinLabel(eTaskIsConfiguredFromJson, Form("fTaskIsConfiguredFromJson = %s", tc.fTaskIsConfiguredFromJson.Data())); - fBasePro->GetXaxis()->SetBinLabel(eRunNumber, - Form("fRunNumber = %s", tc.fRunNumber.Data())); + fBasePro->GetXaxis()->SetBinLabel(eTaskName, Form("fTaskName = %s", tc.fTaskName.Data())); + + fBasePro->GetXaxis()->SetBinLabel(eRunNumber, Form("fRunNumber = %s", "__RUN_NUMBER__")); + // I have to do it this way via placeholder, because run number is available only when i start to process data. + // Then, I replace placeholder with run number in PropagateRunNumber(...) fBasePro->GetXaxis()->SetBinLabel(eDryRun, "fDryRun"); - fBasePro->Fill(+eDryRun - 0.5, (Int_t)tc.fDryRun); + fBasePro->Fill(eDryRun, static_cast(tc.fDryRun)); fBasePro->GetXaxis()->SetBinLabel(eVerbose, "fVerbose"); - fBasePro->Fill(+eVerbose - 0.5, (Int_t)tc.fVerbose); + fBasePro->Fill(eVerbose, static_cast(tc.fVerbose)); + + fBasePro->GetXaxis()->SetBinLabel(eVerboseUtility, "fVerboseUtility"); + fBasePro->Fill(eVerboseUtility, static_cast(tc.fVerboseUtility)); fBasePro->GetXaxis()->SetBinLabel(eVerboseForEachParticle, "fVerboseForEachParticle"); - fBasePro->Fill(+eVerboseForEachParticle - 0.5, (Int_t)tc.fVerboseForEachParticle); + fBasePro->Fill(eVerboseForEachParticle, static_cast(tc.fVerboseForEachParticle)); + + fBasePro->GetXaxis()->SetBinLabel(eVerboseEventCounter, "fVerboseEventCounter"); + fBasePro->Fill(eVerboseEventCounter, static_cast(tc.fVerboseEventCounter)); + + fBasePro->GetXaxis()->SetBinLabel(ePlainPrintout, "fPlainPrintout"); + fBasePro->Fill(ePlainPrintout, static_cast(tc.fPlainPrintout)); fBasePro->GetXaxis()->SetBinLabel(eDoAdditionalInsanityChecks, "fDoAdditionalInsanityChecks"); - fBasePro->Fill(+eDoAdditionalInsanityChecks - 0.5, (Int_t)tc.fDoAdditionalInsanityChecks); + fBasePro->Fill(eDoAdditionalInsanityChecks, static_cast(tc.fDoAdditionalInsanityChecks)); - fBasePro->GetXaxis()->SetBinLabel(eUseCCDB, "fUseCCDB"); - fBasePro->Fill(+eUseCCDB - 0.5, (Int_t)tc.fUseCCDB); + fBasePro->GetXaxis()->SetBinLabel(eInsanityCheckForEachParticle, "fInsanityCheckForEachParticle"); + fBasePro->Fill(eInsanityCheckForEachParticle, static_cast(tc.fInsanityCheckForEachParticle)); - fBasePro->GetXaxis()->SetBinLabel(eWhichProcess, - Form("WhichProcess = %s", tc.fWhichProcess.Data())); + fBasePro->GetXaxis()->SetBinLabel(eWhichProcess, Form("WhichProcess = %s", tc.fWhichProcess.Data())); fBasePro->GetXaxis()->SetBinLabel(eRandomSeed, "fRandomSeed"); - fBasePro->Fill(+eRandomSeed - 0.5, (Int_t)tc.fRandomSeed); + fBasePro->Fill(eRandomSeed, static_cast(tc.fRandomSeed)); fBasePro->GetXaxis()->SetBinLabel(eUseFisherYates, "fUseFisherYates"); - fBasePro->Fill(+eUseFisherYates - 0.5, (Int_t)tc.fUseFisherYates); + fBasePro->Fill(eUseFisherYates, static_cast(tc.fUseFisherYates)); fBasePro->GetXaxis()->SetBinLabel(eFixedNumberOfRandomlySelectedTracks, "fFixedNumberOfRandomlySelectedTracks"); - fBasePro->Fill(+eFixedNumberOfRandomlySelectedTracks - 0.5, (Int_t)tc.fFixedNumberOfRandomlySelectedTracks); + fBasePro->Fill(eFixedNumberOfRandomlySelectedTracks, static_cast(tc.fFixedNumberOfRandomlySelectedTracks)); fBasePro->GetXaxis()->SetBinLabel(eUseStopwatch, "fUseStopwatch"); - fBasePro->Fill(+eUseStopwatch - 0.5, (Int_t)tc.fUseStopwatch); + fBasePro->Fill(eUseStopwatch, static_cast(tc.fUseStopwatch)); + + fBasePro->GetXaxis()->SetBinLabel(eFloatingPointPrecision, "fFloatingPointPrecision"); + fBasePro->Fill(eFloatingPointPrecision, tc.fFloatingPointPrecision); + + fBasePro->GetXaxis()->SetBinLabel(eSequentialBailout, "fSequentialBailout"); + fBasePro->Fill(eSequentialBailout, static_cast(tc.fSequentialBailout)); + + fBasePro->GetXaxis()->SetBinLabel(eUseSpecificCuts, "fUseSpecificCuts"); + fBasePro->Fill(eUseSpecificCuts, static_cast(tc.fUseSpecificCuts)); + + fBasePro->GetXaxis()->SetBinLabel(eWhichSpecificCuts, Form("WhichSpecificCuts = %s", tc.fWhichSpecificCuts.Data())); + + fBasePro->GetXaxis()->SetBinLabel(eSkipTheseRuns, Form("SkipTheseRuns = %s", tc.fSkipTheseRuns.Data())); fBaseList->Add(fBasePro); + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + } // void BookBaseList() //============================================================ @@ -83,8 +115,7 @@ void BookBaseList() void DefaultConfiguration() { // Default task configuration. - // a) Default values are hardcoded as Configurables in the file - // MuPa-Configurables.h + // a) Default values are hardcoded as Configurables in the file MuPa-Configurables.h // b) If corresponding fields are available in an external json file at run time, the default values hardcoded here are // overwritten with values set in json file. @@ -104,222 +135,1101 @@ void DefaultConfiguration() // d) There are also implicit variables like "doprocessSomeProcessName" within a PROCESS_SWITCH clause. For them, I do not need an entry in Configurables - // Configurable cfTaskName{ ... } - tc.fTaskName = TString(cfTaskName); - - // Configurable cfDryRun{ ... } - tc.fDryRun = cfDryRun; - - // Configurable cfVerbose{ ... } - tc.fVerbose = cfVerbose; - + // e) Use whenever you can ConfigurableGroup, keep grouping in sync with all struct's in MuPa-DataMembers.h. + // This is needed, to avoid this compilation error: + // Framework/StructToTuple.h:286:6: error: only 99 names provided for structured binding + // *) As far as I can tell, that means that sum of individual data members + struct fields + individual configurables > 99 + // *) Therefore, wrap up all data members in some struct fields + use in instead of individual configurables ConfigurableGroup whenever possible. + // *) Within a given struct field, number of data members do not add to that number. Also, number of enum fields do not add. + + tc.fTaskIsConfiguredFromJson = TString(cf_tc.cfTaskIsConfiguredFromJson); + tc.fTaskName = TString(cf_tc.cfTaskName); + tc.fDryRun = cf_tc.cfDryRun; + tc.fVerbose = cf_tc.cfVerbose; if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); // yes, here - } - - // Configurable cfVerboseForEachParticle{ ... } - tc.fVerboseForEachParticle = cfVerboseForEachParticle; - - // Configurable cfDoAdditionalInsanityChecks{ ... } - tc.fDoAdditionalInsanityChecks = cfDoAdditionalInsanityChecks; - - // Configurable cfUseCCDB{ ... } - tc.fUseCCDB = cfUseCCDB; - + StartFunction(__FUNCTION__); // yes, here + } + tc.fVerboseUtility = cf_tc.cfVerboseUtility; + tc.fVerboseForEachParticle = cf_tc.cfVerboseForEachParticle; + tc.fVerboseEventCounter = cf_tc.cfVerboseEventCounter; + tc.fVerboseEventCut = cf_tc.cfVerboseEventCut; + tc.fPlainPrintout = cf_tc.cfPlainPrintout; + tc.fDoAdditionalInsanityChecks = cf_tc.cfDoAdditionalInsanityChecks; // Set automatically what to process, from an implicit variable "doprocessSomeProcessName" within a PROCESS_SWITCH clause: - // Remark: As of 20240224, I have abandoned Configurable cfWhatToProcess{ ... ), which is now obsolete - tc.fProcessRec = doprocessRec; - tc.fProcessRecSim = doprocessRecSim; - tc.fProcessSim = doprocessSim; - tc.fProcessRec_Run2 = doprocessRec_Run2; - tc.fProcessRecSim_Run2 = doprocessRecSim_Run2; - tc.fProcessSim_Run2 = doprocessSim_Run2; - tc.fProcessRec_Run1 = doprocessRec_Run1; - tc.fProcessRecSim_Run1 = doprocessRecSim_Run1; - tc.fProcessSim_Run1 = doprocessSim_Run1; - tc.fProcessTest = doprocessTest; + tc.fProcess[eProcessRec] = doprocessRec; + tc.fProcess[eProcessRecSim] = doprocessRecSim; + tc.fProcess[eProcessSim] = doprocessSim; + tc.fProcess[eProcessRec_Run2] = doprocessRec_Run2; + tc.fProcess[eProcessRecSim_Run2] = doprocessRecSim_Run2; + tc.fProcess[eProcessSim_Run2] = doprocessSim_Run2; + tc.fProcess[eProcessRec_Run1] = doprocessRec_Run1; + tc.fProcess[eProcessRecSim_Run1] = doprocessRecSim_Run1; + tc.fProcess[eProcessSim_Run1] = doprocessSim_Run1; + tc.fProcess[eProcessTest] = doprocessTest; + tc.fProcess[eProcessQA] = doprocessQA; // Temporarary bailout protection against cases which are not implemented/validated yet: - if (tc.fProcessSim) { - LOGF(fatal, "in function \033[1;31m%s at line %d - processSim(...) is not implemented/validated yet \033[0m", __PRETTY_FUNCTION__, __LINE__); + if (tc.fProcess[eProcessSim]) { + LOGF(fatal, "\033[1;31m%s at line %d - processSim(...) is not implemented/validated yet \033[0m", __FUNCTION__, __LINE__); + // TBI 20240512 Most likely, for this case i will have to establish a separate workflow. But since I can with the current + // workflow run both over Rec and RecSim, this case is not of a high priority + // TBI 20240512 See also if I need to extand subscription, both in the definition of CollisionSim and TrackSim } - if (tc.fProcessSim_Run2) { - LOGF(fatal, "in function \033[1;31m%s at line %d - processSim_Run2(...) is not implemented/validated yet \033[0m", __PRETTY_FUNCTION__, __LINE__); + + if (tc.fProcess[eProcessSim_Run2]) { + LOGF(fatal, "\033[1;31m%s at line %d - processSim_Run2(...) is not implemented/validated yet \033[0m", __FUNCTION__, __LINE__); + // TBI 20240517 see above comments for eProcessSim , most likely they also apply for this case } - if (tc.fProcessRecSim_Run1) { - LOGF(fatal, "in function \033[1;31m%s at line %d - processRecSim_Run1(...) is not implemented/validated yet \033[0m", __PRETTY_FUNCTION__, __LINE__); + + if (tc.fProcess[eProcessRecSim_Run1]) { + LOGF(fatal, "\033[1;31m%s at line %d - processRecSim_Run1(...) is not implemented/validated yet \033[0m", __FUNCTION__, __LINE__); } - if (tc.fProcessSim_Run1) { - LOGF(fatal, "in function \033[1;31m%s at line %d - processSim_Run1(...) is not implemented/validated yet \033[0m", __PRETTY_FUNCTION__, __LINE__); + + if (tc.fProcess[eProcessSim_Run1]) { + LOGF(fatal, "\033[1;31m%s at line %d - processSim_Run1(...) is not implemented/validated yet \033[0m", __FUNCTION__, __LINE__); } // Set automatically generic flags, from above individual flags: - tc.fGenericRec = tc.fProcessRec || tc.fProcessRec_Run2 || tc.fProcessRec_Run1 || tc.fProcessTest; - tc.fGenericRecSim = tc.fProcessRecSim || tc.fProcessRecSim_Run2 || tc.fProcessRecSim_Run1; - tc.fGenericSim = tc.fProcessSim || tc.fProcessSim_Run2 || tc.fProcessSim_Run1; + tc.fProcess[eGenericRec] = tc.fProcess[eProcessRec] || tc.fProcess[eProcessRec_Run2] || tc.fProcess[eProcessRec_Run1] || tc.fProcess[eProcessTest] || tc.fProcess[eProcessQA]; + tc.fProcess[eGenericRecSim] = tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessRecSim_Run2] || tc.fProcess[eProcessRecSim_Run1]; + tc.fProcess[eGenericSim] = tc.fProcess[eProcessSim] || tc.fProcess[eProcessSim_Run2] || tc.fProcess[eProcessSim_Run1]; // Set automatically tc.fWhichProcess from above individual flags: - if (tc.fProcessRec) { + if (tc.fProcess[eProcessRec]) { tc.fWhichProcess = "ProcessRec"; - } else if (tc.fProcessRecSim) { + } else if (tc.fProcess[eProcessRecSim]) { tc.fWhichProcess = "ProcessRecSim"; - } else if (tc.fProcessSim) { + } else if (tc.fProcess[eProcessSim]) { tc.fWhichProcess = "ProcessSim"; - } else if (tc.fProcessRec_Run2) { + } else if (tc.fProcess[eProcessRec_Run2]) { tc.fWhichProcess = "ProcessRec_Run2"; - } else if (tc.fProcessRecSim_Run2) { + } else if (tc.fProcess[eProcessRecSim_Run2]) { tc.fWhichProcess = "ProcessRecSim_Run2"; - } else if (tc.fProcessSim_Run2) { + } else if (tc.fProcess[eProcessSim_Run2]) { tc.fWhichProcess = "ProcessSim_Run2"; - } else if (tc.fProcessRec_Run1) { + } else if (tc.fProcess[eProcessRec_Run1]) { tc.fWhichProcess = "ProcessRec_Run1"; - } else if (tc.fProcessRecSim_Run1) { + } else if (tc.fProcess[eProcessRecSim_Run1]) { tc.fWhichProcess = "ProcessRecSim_Run1"; - } else if (tc.fProcessSim_Run1) { + } else if (tc.fProcess[eProcessSim_Run1]) { tc.fWhichProcess = "ProcessSim_Run1"; - } else if (tc.fProcessTest) { + } else if (tc.fProcess[eProcessTest]) { tc.fWhichProcess = "ProcessTest"; + } else if (tc.fProcess[eProcessQA]) { + tc.fWhichProcess = "ProcessQA"; + } + + tc.fRandomSeed = cf_tc.cfRandomSeed; + tc.fUseFisherYates = cf_tc.cfUseFisherYates; + tc.fFixedNumberOfRandomlySelectedTracks = cf_tc.cfFixedNumberOfRandomlySelectedTracks; + tc.fUseStopwatch = cf_tc.cfUseStopwatch; + tc.fFloatingPointPrecision = cf_tc.cfFloatingPointPrecision; + tc.fSequentialBailout = cf_tc.cfSequentialBailout; + tc.fUseSpecificCuts = cf_tc.cfUseSpecificCuts; + tc.fWhichSpecificCuts = cf_tc.cfWhichSpecificCuts; + tc.fSkipTheseRuns = cf_tc.cfSkipTheseRuns; + + // *) Event histograms (for QA see below): + eh.fEventHistogramsName[eNumberOfEvents] = "NumberOfEvents"; + eh.fEventHistogramsName[eTotalMultiplicity] = "TotalMultiplicity"; + eh.fEventHistogramsName[eMultiplicity] = "Multiplicity"; + eh.fEventHistogramsName[eReferenceMultiplicity] = "ReferenceMultiplicity"; + eh.fEventHistogramsName[eCentrality] = "Centrality"; + eh.fEventHistogramsName[eVertexX] = "VertexX"; + eh.fEventHistogramsName[eVertexY] = "VertexY"; + eh.fEventHistogramsName[eVertexZ] = "VertexZ"; + eh.fEventHistogramsName[eNContributors] = "NContributors"; + eh.fEventHistogramsName[eImpactParameter] = "ImpactParameter"; + eh.fEventHistogramsName[eEventPlaneAngle] = "EventPlaneAngle"; + eh.fEventHistogramsName[eOccupancy] = "Occupancy"; + eh.fEventHistogramsName[eInteractionRate] = "InteractionRate"; + eh.fEventHistogramsName[eCurrentRunDuration] = "CurrentRunDuration"; + eh.fEventHistogramsName[eMultMCNParticlesEta08] = "MultMCNParticlesEta08"; + + for (int t = 0; t < eEventHistograms_N; t++) { + if (eh.fEventHistogramsName[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : name of fEventHistogramsName[%d] is not set \033[0m", __FUNCTION__, __LINE__, static_cast(t)); + } + } + + // *) Event cuts: + ec.fUseEventCutCounterAbsolute = cf_ec.cfUseEventCutCounterAbsolute; + ec.fUseEventCutCounterSequential = cf_ec.cfUseEventCutCounterSequential; + ec.fPrintCutCounterContent = cf_ec.cfPrintCutCounterContent; + + // Set names of all event cuts: + ec.fEventCutName[eNumberOfEvents] = "NumberOfEvents"; + ec.fEventCutName[eTotalMultiplicity] = "TotalMultiplicity"; + ec.fEventCutName[eMultiplicity] = "Multiplicity"; + ec.fEventCutName[eReferenceMultiplicity] = "ReferenceMultiplicity"; + ec.fEventCutName[eCentrality] = "Centrality"; + ec.fEventCutName[eVertexX] = "VertexX"; + ec.fEventCutName[eVertexY] = "VertexY"; + ec.fEventCutName[eVertexZ] = "VertexZ"; + ec.fEventCutName[eNContributors] = "NContributors"; + ec.fEventCutName[eImpactParameter] = "ImpactParameter"; + ec.fEventCutName[eEventPlaneAngle] = "EventPlaneAngle"; + ec.fEventCutName[eOccupancy] = "Occupancy"; + ec.fEventCutName[eInteractionRate] = "InteractionRate"; + ec.fEventCutName[eCurrentRunDuration] = "CurrentRunDuration"; + ec.fEventCutName[eMultMCNParticlesEta08] = "MultMCNParticlesEta08"; + ec.fEventCutName[eTrigger] = "Trigger"; + ec.fEventCutName[eSel7] = "Sel7"; + ec.fEventCutName[eSel8] = "Sel8"; + ec.fEventCutName[eCentralityEstimator] = "CentralityEstimator"; + ec.fEventCutName[eMultiplicityEstimator] = "MultiplicityEstimator"; + ec.fEventCutName[eReferenceMultiplicityEstimator] = "ReferenceMultiplicityEstimator"; + ec.fEventCutName[eSelectedEvents] = "SelectedEvents"; + ec.fEventCutName[eNoSameBunchPileup] = "NoSameBunchPileup"; + ec.fEventCutName[eIsGoodZvtxFT0vsPV] = "IsGoodZvtxFT0vsPV"; + ec.fEventCutName[eIsVertexITSTPC] = "IsVertexITSTPC"; + ec.fEventCutName[eIsVertexTOFmatched] = "IsVertexTOFmatched"; + ec.fEventCutName[eIsVertexTRDmatched] = "IsVertexTRDmatched"; + ec.fEventCutName[eNoCollInTimeRangeStrict] = "NoCollInTimeRangeStrict"; + ec.fEventCutName[eNoCollInTimeRangeStandard] = "NoCollInTimeRangeStandard"; + ec.fEventCutName[eNoCollInRofStrict] = "NoCollInRofStrict"; + ec.fEventCutName[eNoCollInRofStandard] = "NoCollInRofStandard"; + ec.fEventCutName[eNoHighMultCollInPrevRof] = "NoHighMultCollInPrevRof"; + ec.fEventCutName[eIsGoodITSLayer3] = "IsGoodITSLayer3"; + ec.fEventCutName[eIsGoodITSLayer0123] = "IsGoodITSLayer0123"; + ec.fEventCutName[eIsGoodITSLayersAll] = "IsGoodITSLayersAll"; + ec.fEventCutName[eOccupancyEstimator] = "OccupancyEstimator"; + ec.fEventCutName[eMinVertexDistanceFromIP] = "MinVertexDistanceFromIP"; + ec.fEventCutName[eNoPileupTPC] = "NoPileupTPC"; + ec.fEventCutName[eNoPileupFromSPD] = "NoPileupFromSPD"; + ec.fEventCutName[eNoSPDOnVsOfPileup] = "NoSPDOnVsOfPileup"; + ec.fEventCutName[eRefMultVsNContrUp] = "RefMultVsNContrUp"; + ec.fEventCutName[eRefMultVsNContrLow] = "RefMultVsNContrLow"; + ec.fEventCutName[eCentralityCorrelationsCut] = "CentralityCorrelationsCut"; + ec.fEventCutName[eCentralityWeights] = "CentralityWeights"; + for (int t = 0; t < eEventCuts_N; t++) { + if (ec.fEventCutName[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : event cut name is not set for ec.fEventCutName[%d]. The last cut name which was set is \"%s\" \033[0m", __FUNCTION__, __LINE__, t, ec.fEventCutName[t - 1].Data()); + } + } + + // *) Particle histograms 1D (for QA see below): + ph.fParticleHistogramsName[ePhi] = "Phi"; + ph.fParticleHistogramsName[ePt] = "Pt"; + ph.fParticleHistogramsName[eEta] = "Eta"; + ph.fParticleHistogramsName[eCharge] = "Charge"; + ph.fParticleHistogramsName[etpcNClsFindable] = "tpcNClsFindable"; + ph.fParticleHistogramsName[etpcNClsShared] = "tpcNClsShared"; + ph.fParticleHistogramsName[eitsChi2NCl] = "itsChi2NCl"; + ph.fParticleHistogramsName[etpcNClsFound] = "tpcNClsFound"; + ph.fParticleHistogramsName[etpcNClsCrossedRows] = "tpcNClsCrossedRows"; + ph.fParticleHistogramsName[eitsNCls] = "itsNCls"; + ph.fParticleHistogramsName[eitsNClsInnerBarrel] = "itsNClsInnerBarrel"; + ph.fParticleHistogramsName[etpcCrossedRowsOverFindableCls] = "tpcCrossedRowsOverFindableCls"; + ph.fParticleHistogramsName[etpcFoundOverFindableCls] = "tpcFoundOverFindableCls"; + ph.fParticleHistogramsName[etpcFractionSharedCls] = "tpcFractionSharedCls"; + ph.fParticleHistogramsName[etpcChi2NCl] = "tpcChi2NCl"; + ph.fParticleHistogramsName[edcaXY] = "dcaXY"; + ph.fParticleHistogramsName[edcaZ] = "dcaZ"; + ph.fParticleHistogramsName[ePDG] = "PDG"; + for (int t = 0; t < eParticleHistograms_N; t++) { + if (ph.fParticleHistogramsName[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : name of fParticleHistogramsName[%d] is not set \033[0m", __FUNCTION__, __LINE__, t); + } + } + + // *) Particle histograms 2D (for QA see below): + ph.fParticleHistogramsName2D[ePhiPt] = Form("%s_vs_%s", ph.fParticleHistogramsName[ePhi].Data(), ph.fParticleHistogramsName[ePt].Data()), + ph.fParticleHistogramsName2D[ePhiEta] = Form("%s_vs_%s", ph.fParticleHistogramsName[ePhi].Data(), ph.fParticleHistogramsName[eEta].Data()); + for (int t = 0; t < eParticleHistograms2D_N; t++) { + if (ph.fParticleHistogramsName2D[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : name of fParticleHistogramsName2D[%d] is not set \033[0m", __FUNCTION__, __LINE__, t); + } } - // Configurable cfRandomSeed{ ... ) - tc.fRandomSeed = cfRandomSeed; + // *) Particle cuts: + pc.fUseParticleCutCounterAbsolute = cf_pc.cfUseParticleCutCounterAbsolute; + pc.fUseParticleCutCounterSequential = cf_pc.cfUseParticleCutCounterSequential; + + // Set names of all particle cuts: + pc.fParticleCutName[ePhi] = "Phi"; + pc.fParticleCutName[ePt] = "Pt"; + pc.fParticleCutName[eEta] = "Eta"; + pc.fParticleCutName[eCharge] = "Charge"; + pc.fParticleCutName[etpcNClsFindable] = "tpcNClsFindable"; + pc.fParticleCutName[etpcNClsShared] = "tpcNClsShared"; + pc.fParticleCutName[eitsChi2NCl] = "itsChi2NCl"; + pc.fParticleCutName[etpcNClsFound] = "tpcNClsFound"; + pc.fParticleCutName[etpcNClsCrossedRows] = "tpcNClsCrossedRows"; + pc.fParticleCutName[eitsNCls] = "itsNCls"; + pc.fParticleCutName[eitsNClsInnerBarrel] = "itsNClsInnerBarrel"; + pc.fParticleCutName[etpcCrossedRowsOverFindableCls] = "tpcCrossedRowsOverFindableCls"; + pc.fParticleCutName[etpcFoundOverFindableCls] = "tpcFoundOverFindableCls"; + pc.fParticleCutName[etpcFractionSharedCls] = "tpcFractionSharedCls"; + pc.fParticleCutName[etpcChi2NCl] = "tpcChi2NCl"; + pc.fParticleCutName[edcaXY] = "dcaXY"; + pc.fParticleCutName[edcaZ] = "dcaZ"; + pc.fParticleCutName[ePDG] = "PDG"; + pc.fParticleCutName[etrackCutFlag] = "trackCutFlag"; + pc.fParticleCutName[etrackCutFlagFb1] = "trackCutFlagFb1"; + pc.fParticleCutName[etrackCutFlagFb2] = "trackCutFlagFb2"; + pc.fParticleCutName[eisQualityTrack] = "isQualityTrack"; + pc.fParticleCutName[eisPrimaryTrack] = "isPrimaryTrack"; + pc.fParticleCutName[eisInAcceptanceTrack] = "isInAcceptanceTrack"; + pc.fParticleCutName[eisGlobalTrack] = "isGlobalTrack"; + pc.fParticleCutName[eisPVContributor] = "isPVContributor"; + pc.fParticleCutName[ePtDependentDCAxyParameterization] = "PtDependentDCAxyParameterization"; + for (int t = 0; t < eParticleCuts_N; t++) { + if (pc.fParticleCutName[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : particle cut name is not set for pc.fParticleCutName[%d] \033[0m", __FUNCTION__, __LINE__, t); + } + } - // Configurable cfUseFisherYates{ ... } - tc.fUseFisherYates = cfUseFisherYates; + // *) Q-vectors: + qv.fCalculateQvectors = cf_qv.cfCalculateQvectors; + + // *) Multiparticle correlations: + mupa.fCalculateCorrelations = cf_mupa.cfCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_INTEGRATED] = cf_mupa.cfCalculateCorrelationsAsFunctionOfIntegrated && mupa.fCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_MULTIPLICITY] = cf_mupa.cfCalculateCorrelationsAsFunctionOfMultiplicity && mupa.fCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_CENTRALITY] = cf_mupa.cfCalculateCorrelationsAsFunctionOfCentrality && mupa.fCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_PT] = cf_mupa.cfCalculateCorrelationsAsFunctionOfPt && mupa.fCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_ETA] = cf_mupa.cfCalculateCorrelationsAsFunctionOfEta && mupa.fCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_OCCUPANCY] = cf_mupa.cfCalculateCorrelationsAsFunctionOfOccupancy && mupa.fCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_INTERACTIONRATE] = cf_mupa.cfCalculateCorrelationsAsFunctionOfInteractionRate && mupa.fCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_CURRENTRUNDURATION] = cf_mupa.cfCalculateCorrelationsAsFunctionOfCurrentRunDuration && mupa.fCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_VZ] = cf_mupa.cfCalculateCorrelationsAsFunctionOfVz && mupa.fCalculateCorrelations; - // Configurable cfFixedNumberOfRandomlySelectedTracks{ ... } - tc.fFixedNumberOfRandomlySelectedTracks = cfFixedNumberOfRandomlySelectedTracks; + // *) Test0: + t0.fCalculateTest0 = cf_t0.cfCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_INTEGRATED] = cf_t0.cfCalculateTest0AsFunctionOfIntegrated && t0.fCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_MULTIPLICITY] = cf_t0.cfCalculateTest0AsFunctionOfMultiplicity && t0.fCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_CENTRALITY] = cf_t0.cfCalculateTest0AsFunctionOfCentrality && t0.fCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_PT] = cf_t0.cfCalculateTest0AsFunctionOfPt && t0.fCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_ETA] = cf_t0.cfCalculateTest0AsFunctionOfEta && t0.fCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_OCCUPANCY] = cf_t0.cfCalculateTest0AsFunctionOfOccupancy && t0.fCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_INTERACTIONRATE] = cf_t0.cfCalculateTest0AsFunctionOfInteractionRate && t0.fCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_CURRENTRUNDURATION] = cf_t0.cfCalculateTest0AsFunctionOfCurrentRunDuration && t0.fCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_VZ] = cf_t0.cfCalculateTest0AsFunctionOfVz && t0.fCalculateTest0; - // Configurable cfUseStopwatch{ ... } - tc.fUseStopwatch = cfUseStopwatch; + if (t0.fCalculateTest0) { + t0.fFileWithLabels = TString(cf_t0.cfFileWithLabels); + t0.fUseDefaultLabels = cf_t0.cfUseDefaultLabels; + t0.fWhichDefaultLabels = TString(cf_t0.cfWhichDefaultLabels); + } - // *) Event cuts: - // Configurable cfTrigger{ ... ) - ec.fTrigger = TString(cfTrigger); - // Configurable cfUseSel7{ ... } - ec.fUseSel7 = cfUseSel7; - // Configurable cfUseSel8{ ... } - ec.fUseSel8 = cfUseSel8; - // Configurable cfCentralityEstimator{ ... ) - ec.fCentralityEstimator = cfCentralityEstimator; - // ... + // *) Particle weights: + pw.fUseWeights[wPHI] = cf_pw.cfUsePhiWeights; + pw.fUseWeights[wPT] = cf_pw.cfUsePtWeights; + pw.fUseWeights[wETA] = cf_pw.cfUseEtaWeights; + pw.fUseDiffWeights[wPHIPT] = cf_pw.cfUseDiffPhiPtWeights; // TBI 20250222 obsolete + pw.fUseDiffWeights[wPHIETA] = cf_pw.cfUseDiffPhiEtaWeights; // TBI 20250222 obsolete + + // **) Differential phi weights: + auto lWhichDiffPhiWeights = cf_pw.cfWhichDiffPhiWeights.value; + if (lWhichDiffPhiWeights.size() != eDiffPhiWeights_N) { + LOGF(info, "\033[1;31m lWhichDiffPhiWeights.size() = %d\033[0m", lWhichDiffPhiWeights.size()); + LOGF(info, "\033[1;31m eDiffPhiWeights_N = %d\033[0m", static_cast(eDiffPhiWeights_N)); + LOGF(fatal, "\033[1;31m%s at line %d : Mismatch in the number of flags in configurable cfWhichDiffPhiWeights, and number of entries in enum eDiffPhiWeights_N \n \033[0m", __FUNCTION__, __LINE__); + } + for (int dpw = 0; dpw < eDiffPhiWeights_N; dpw++) { // "differential phi weight" + if (TString(lWhichDiffPhiWeights[dpw]).Contains("wPhi")) { + pw.fUseDiffPhiWeights[wPhiPhiAxis] = Alright(lWhichDiffPhiWeights[dpw]); // if I pass "1-Phi" => true, "0-Phi" => false + } else if (TString(lWhichDiffPhiWeights[dpw]).Contains("wPt")) { + pw.fUseDiffPhiWeights[wPhiPtAxis] = Alright(lWhichDiffPhiWeights[dpw]) && pw.fUseDiffPhiWeights[wPhiPhiAxis]; // I chain here with wPhiPhiAxis , so that I can switch off all differential phi weights, if phi itself is not set to true + } else if (TString(lWhichDiffPhiWeights[dpw]).Contains("wEta")) { + pw.fUseDiffPhiWeights[wPhiEtaAxis] = Alright(lWhichDiffPhiWeights[dpw]) && pw.fUseDiffPhiWeights[wPhiPhiAxis]; + } else if (TString(lWhichDiffPhiWeights[dpw]).Contains("wCharge")) { + pw.fUseDiffPhiWeights[wPhiChargeAxis] = Alright(lWhichDiffPhiWeights[dpw]) && pw.fUseDiffPhiWeights[wPhiPhiAxis]; + } else if (TString(lWhichDiffPhiWeights[dpw]).Contains("wCentrality")) { + pw.fUseDiffPhiWeights[wPhiCentralityAxis] = Alright(lWhichDiffPhiWeights[dpw]) && pw.fUseDiffPhiWeights[wPhiPhiAxis]; + } else if (TString(lWhichDiffPhiWeights[dpw]).Contains("wVertexZ") || TString(lWhichDiffPhiWeights[dpw]).Contains("wVertex_z")) { // TBI 20250402 I keep "wVertex_z" here just in case I still have somewhere dependency on it, remove eventually + pw.fUseDiffPhiWeights[wPhiVertexZAxis] = Alright(lWhichDiffPhiWeights[dpw]) && pw.fUseDiffPhiWeights[wPhiPhiAxis]; + } else { + LOGF(fatal, "\033[1;31m%s at line %d : The setting %s in configurable cfWhichDiffPhiWeights is not supported yet. See enum eDiffPhiWeights . \n \033[0m", __FUNCTION__, __LINE__, TString(lWhichDiffPhiWeights[dpw]).Data()); + } + } + + // **) Differential pt weights: + auto lWhichDiffPtWeights = cf_pw.cfWhichDiffPtWeights.value; + if (lWhichDiffPtWeights.size() != eDiffPtWeights_N) { + LOGF(info, "\033[1;31m lWhichDiffPtWeights.size() = %d\033[0m", lWhichDiffPtWeights.size()); + LOGF(info, "\033[1;31m eDiffPtWeights_N = %d\033[0m", static_cast(eDiffPtWeights_N)); + LOGF(fatal, "\033[1;31m%s at line %d : Mismatch in the number of flags in configurable cfWhichDiffPtWeights, and number of entries in enum eDiffPtWeights_N \n \033[0m", __FUNCTION__, __LINE__); + } + for (int dpw = 0; dpw < eDiffPtWeights_N; dpw++) { // "differential pt weight" + if (TString(lWhichDiffPtWeights[dpw]).Contains("wPt")) { + pw.fUseDiffPtWeights[wPtPtAxis] = Alright(lWhichDiffPtWeights[dpw]); // if I pass "1-Pt" => true, "0-Pt" => false + } else { // ... TBI 20250222 add support for other dimensions of differential pt weights, in the same spirit i did it for differential phi weights + LOGF(fatal, "\033[1;31m%s at line %d : The setting %s in configurable cfWhichDiffPtWeights is not supported yet. See enum eDiffPtWeights . \n \033[0m", __FUNCTION__, __LINE__, TString(lWhichDiffPtWeights[dpw]).Data()); + } + } + + // **) Differential eta weights: + auto lWhichDiffEtaWeights = cf_pw.cfWhichDiffEtaWeights.value; + if (lWhichDiffEtaWeights.size() != eDiffEtaWeights_N) { + LOGF(info, "\033[1;31m lWhichDiffEtaWeights.size() = %d\033[0m", lWhichDiffEtaWeights.size()); + LOGF(info, "\033[1;31m eDiffEtaWeights_N = %d\033[0m", static_cast(eDiffEtaWeights_N)); + LOGF(fatal, "\033[1;31m%s at line %d : Mismatch in the number of flags in configurable cfWhichDiffEtaWeights, and number of entries in enum eDiffEtaWeights_N \n \033[0m", __FUNCTION__, __LINE__); + } + for (int dpw = 0; dpw < eDiffEtaWeights_N; dpw++) { // "differential eta weight" + if (TString(lWhichDiffEtaWeights[dpw]).Contains("wEta")) { + pw.fUseDiffEtaWeights[wEtaEtaAxis] = Alright(lWhichDiffEtaWeights[dpw]); // if I pass "1-Eta" => true, "0-Eta" => false + } else { // ... TBI 20250222 add support for other dimensions of differential eta weights, in the same spirit i did it for differential phi weights + LOGF(fatal, "\033[1;31m%s at line %d : The setting %s in configurable cfWhichDiffEtaWeights is not supported yet. See enum eDiffEtaWeights . \n \033[0m", __FUNCTION__, __LINE__, TString(lWhichDiffEtaWeights[dpw]).Data()); + } + } + + // **) File holding all particle weights: + pw.fFileWithWeights = cf_pw.cfFileWithWeights; - // Configurable cfCalculateQvectors{ ... } - qv.fCalculateQvectors = cfCalculateQvectors; + // *) Centrality weights: + cw.fUseCentralityWeights = cf_cw.cfUseCentralityWeights; + cw.fFileWithCentralityWeights = cf_cw.cfFileWithCentralityWeights; + + // ... - // Configurable cfCalculateCorrelations{ ... }; - mupa.fCalculateCorrelations = cfCalculateCorrelations; + // *) Nested loops: + nl.fCalculateNestedLoops = cf_nl.cfCalculateNestedLoops; + nl.fCalculateCustomNestedLoops = cf_nl.cfCalculateCustomNestedLoops; + nl.fCalculateKineCustomNestedLoops = cf_nl.cfCalculateKineCustomNestedLoops; + nl.fMaxNestedLoop = cf_nl.cfMaxNestedLoop; // ... - // Configurable cfCalculateTest0{ ... }; - t0.fCalculateTest0 = cfCalculateTest0; // + see below, how it's automatically set via other Test0 flags + // *) Toy NUA: + auto lApplyNUAPDF = (std::vector)cf_nua.cfApplyNUAPDF; + if (lApplyNUAPDF.size() != eNUAPDF_N) { + LOGF(info, "\033[1;31m lApplyNUAPDF.size() = %d\033[0m", lApplyNUAPDF.size()); + LOGF(info, "\033[1;31m eNUAPDF_N = %d\033[0m", static_cast(eNUAPDF_N)); + LOGF(fatal, "\033[1;31m%s at line %d : Mismatch in the number of flags in configurable cfApplyNUAPDF, and number of entries in enum eNUAPDF \n \033[0m", __FUNCTION__, __LINE__); + } + nua.fApplyNUAPDF[ePhiNUAPDF] = static_cast(lApplyNUAPDF[ePhiNUAPDF]); + nua.fApplyNUAPDF[ePtNUAPDF] = static_cast(lApplyNUAPDF[ePtNUAPDF]); + nua.fApplyNUAPDF[eEtaNUAPDF] = static_cast(lApplyNUAPDF[eEtaNUAPDF]); + + // **) Execute the lines below, only if toy NUA (either default or custom) is requested for at least one kine variable: + if (nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF]) { + + auto lUseDefaultNUAPDF = (std::vector)cf_nua.cfUseDefaultNUAPDF; + if (lUseDefaultNUAPDF.size() != eNUAPDF_N) { + LOGF(info, "\033[1;31m lUseDefaultNUAPDF.size() = %d\033[0m", lUseDefaultNUAPDF.size()); + LOGF(info, "\033[1;31m eNUAPDF_N = %d\033[0m", static_cast(eNUAPDF_N)); + LOGF(fatal, "\033[1;31m%s at line %d : Mismatch in the number of flags in configurable cfUseDefaultNUAPDF, and number of entries in enum eNUAPDF \n \033[0m", __FUNCTION__, __LINE__); + } + nua.fUseDefaultNUAPDF[ePhiNUAPDF] = static_cast(lUseDefaultNUAPDF[ePhiNUAPDF]); + nua.fUseDefaultNUAPDF[ePtNUAPDF] = static_cast(lUseDefaultNUAPDF[ePtNUAPDF]); + nua.fUseDefaultNUAPDF[eEtaNUAPDF] = static_cast(lUseDefaultNUAPDF[eEtaNUAPDF]); + + // **) Execute the lines below, only if custom toy NUA is requested in at least one kine variable: + if (!((nua.fApplyNUAPDF[ePhiNUAPDF] && nua.fUseDefaultNUAPDF[ePhiNUAPDF]) || + (nua.fApplyNUAPDF[ePtNUAPDF] && nua.fUseDefaultNUAPDF[ePtNUAPDF]) || + (nua.fApplyNUAPDF[eEtaNUAPDF] && nua.fUseDefaultNUAPDF[eEtaNUAPDF]))) { + // If the above conditon is true, as least one NUA is requested and is not default, i.e. it's custom NUA obtained from external file, which was requested to be used. + // TBI 20240501 Can I simplify the logic above, it's a bit cryptic... + + // *) external file path with custom NUA histos: + nua.fFileWithCustomNUA = TString(cf_nua.cfFileWithCustomNUA); + + // *) histogram names with custom NUA distributions in that file + get those histograms immediately here: + auto lCustomNUAPDFHistNames = (std::vector)cf_nua.cfCustomNUAPDFHistNames; + // TBI 20241115 For some reason, the default values of configurable "cfCustomNUAPDFHistNames" are not correctly propagated in the local variables, but I can circumvent that with JSON settings for the time being + if (lCustomNUAPDFHistNames.size() != eNUAPDF_N) { + LOGF(info, "\033[1;31m lCustomNUAPDFHistNames.size() = %d\033[0m", lCustomNUAPDFHistNames.size()); + LOGF(info, "\033[1;31m eNUAPDF_N = %d\033[0m", static_cast(eNUAPDF_N)); + LOGF(fatal, "\033[1;31m%s at line %d : Mismatch in the number of flags in configurable cfCustomNUAPDFHistNames, and number of entries in enum eNUAPDF \n \033[0m", __FUNCTION__, __LINE__); + } + + if (!nua.fUseDefaultNUAPDF[ePhiNUAPDF]) { + nua.fCustomNUAPDFHistNames[ePhiNUAPDF] = new TString(lCustomNUAPDFHistNames[ePhiNUAPDF]); + this->GetHistogramWithCustomNUA(nua.fFileWithCustomNUA.Data(), ePhiNUAPDF); + if (!nua.fCustomNUAPDF[ePhiNUAPDF]) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } + + if (!nua.fUseDefaultNUAPDF[ePtNUAPDF]) { + nua.fCustomNUAPDFHistNames[ePtNUAPDF] = new TString(lCustomNUAPDFHistNames[ePtNUAPDF]); + this->GetHistogramWithCustomNUA(nua.fFileWithCustomNUA.Data(), ePtNUAPDF); + if (!nua.fCustomNUAPDF[ePtNUAPDF]) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } + if (!nua.fUseDefaultNUAPDF[eEtaNUAPDF]) { + nua.fCustomNUAPDFHistNames[eEtaNUAPDF] = new TString(lCustomNUAPDFHistNames[eEtaNUAPDF]); + this->GetHistogramWithCustomNUA(nua.fFileWithCustomNUA.Data(), eEtaNUAPDF); + if (!nua.fCustomNUAPDF[eEtaNUAPDF]) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } + } // if (!(nua.fUseDefaultNUAPDF[ePhiNUAPDF] || nua.fUseDefaultNUAPDF[ePtNUAPDF] || nua.fUseDefaultNUAPDF[eEtaNUAPDF])) { + + } // if ( nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF] ) { - // Configurable cfCalculateTest0AsFunctionOfIntegrated{ ... } + analogous configurables for other ones: - t0.fCalculateTest0AsFunctionOf[AFO_INTEGRATED] = cfCalculateTest0AsFunctionOfIntegrated; - t0.fCalculateTest0AsFunctionOf[AFO_MULTIPLICITY] = cfCalculateTest0AsFunctionOfMultiplicity; - t0.fCalculateTest0AsFunctionOf[AFO_CENTRALITY] = cfCalculateTest0AsFunctionOfCentrality; - t0.fCalculateTest0AsFunctionOf[AFO_PT] = cfCalculateTest0AsFunctionOfPt; - t0.fCalculateTest0AsFunctionOf[AFO_ETA] = cfCalculateTest0AsFunctionOfEta; - // Use above Test0 flags to automatically set the main Test0 flag: - for (Int_t v = 0; v < eAsFunctionOf_N; v++) { - if (t0.fCalculateTest0AsFunctionOf[v]) { - t0.fCalculateTest0 = true; - break; // yes, it suffices one diff. flag to be true, for the main Test0 flag to be true + // *) Internal validation: + iv.fUseInternalValidation = cf_iv.cfUseInternalValidation; + iv.fInternalValidationForceBailout = cf_iv.cfInternalValidationForceBailout; + iv.fnEventsInternalValidation = cf_iv.cfnEventsInternalValidation; + iv.fRescaleWithTheoreticalInput = cf_iv.cfRescaleWithTheoreticalInput; + iv.fHarmonicsOptionInternalValidation = new TString(cf_iv.cfHarmonicsOptionInternalValidation); + + // *) Results histograms: + // Define axis titles: + // Remark: keep ordering in sync with enum eAsFunctionOf + res.fResultsProXaxisTitle[AFO_INTEGRATED] = "integrated"; + res.fResultsProRawName[AFO_INTEGRATED] = "int"; // this is how it appears simplified in the hist name when saved to the file + res.fResultsProXaxisTitle[AFO_MULTIPLICITY] = "multiplicity"; + res.fResultsProRawName[AFO_MULTIPLICITY] = "mult"; + res.fResultsProXaxisTitle[AFO_CENTRALITY] = "centrality"; + res.fResultsProRawName[AFO_CENTRALITY] = "cent"; + res.fResultsProXaxisTitle[AFO_PT] = "pt"; + res.fResultsProRawName[AFO_PT] = "pt"; + res.fResultsProXaxisTitle[AFO_ETA] = "eta"; + res.fResultsProRawName[AFO_ETA] = "eta"; + res.fResultsProXaxisTitle[AFO_OCCUPANCY] = "occupancy"; + res.fResultsProRawName[AFO_OCCUPANCY] = "occu"; + res.fResultsProXaxisTitle[AFO_INTERACTIONRATE] = "interaction rate"; + res.fResultsProRawName[AFO_INTERACTIONRATE] = "ir"; + res.fResultsProXaxisTitle[AFO_CURRENTRUNDURATION] = "current run duration"; + res.fResultsProRawName[AFO_CURRENTRUNDURATION] = "crd"; + res.fResultsProXaxisTitle[AFO_VZ] = "vertex z position"; + res.fResultsProRawName[AFO_VZ] = "vz"; + res.fSaveResultsHistograms = cf_res.cfSaveResultsHistograms; + + // *) QA: + // Remark: I keep it on the bottom, because here I define some names in temrs of names defined above. + qa.fCheckUnderflowAndOverflow = cf_qa.cfCheckUnderflowAndOverflow; + qa.fRebin = cf_qa.cfRebin; + + // **) Reference multiplicity estimators: + qa.fReferenceMultiplicityEstimatorName[eMultTPC] = "MultTPC"; + qa.fReferenceMultiplicityEstimatorName[eMultFV0M] = "MultFV0M"; + qa.fReferenceMultiplicityEstimatorName[eMultFT0C] = "MultFT0C"; + qa.fReferenceMultiplicityEstimatorName[eMultFT0M] = "MultFT0M"; + qa.fReferenceMultiplicityEstimatorName[eMultNTracksPV] = "MultNTracksPV"; + qa.fReferenceMultiplicityEstimatorName[eMultNTracksGlobal] = "MultNTracksGlobal"; + qa.fReferenceMultiplicityEstimatorName[eMultTracklets] = "MultTracklets"; + + // **) Centrality estimators: + qa.fCentralityEstimatorName[eCentFT0C] = "CentFT0C"; + qa.fCentralityEstimatorName[eCentFT0CVariant1] = "CentFT0CVariant1"; + qa.fCentralityEstimatorName[eCentFT0M] = "CentFT0M"; + qa.fCentralityEstimatorName[eCentFV0A] = "CentFV0A"; + qa.fCentralityEstimatorName[eCentNTPV] = "CentNTPV"; + qa.fCentralityEstimatorName[eCentNGlobal] = "CentNGlobal"; + qa.fCentralityEstimatorName[eCentRun2V0M] = "CentRun2V0M"; + qa.fCentralityEstimatorName[eCentRun2SPDTracklets] = "CentRun2SPDTracklets"; + + // **) Occupancy estimators: + qa.fOccupancyEstimatorName[eTrackOccupancyInTimeRange] = "TrackOccupancyInTimeRange"; + qa.fOccupancyEstimatorName[eFT0COccupancyInTimeRange] = "FT0COccupancyInTimeRange"; + + // **) Names of QA 2D event histograms: + // Remark: Do NOT use FancyFormatting here, only later in BookQAHistograms() for axis titles! + qa.fEventHistogramsName2D[eMultiplicity_vs_ReferenceMultiplicity] = Form("%s_vs_%s", eh.fEventHistogramsName[eMultiplicity].Data(), eh.fEventHistogramsName[eReferenceMultiplicity].Data()); + qa.fEventHistogramsName2D[eMultiplicity_vs_NContributors] = Form("%s_vs_%s", eh.fEventHistogramsName[eMultiplicity].Data(), eh.fEventHistogramsName[eNContributors].Data()); + qa.fEventHistogramsName2D[eMultiplicity_vs_Centrality] = Form("%s_vs_%s", eh.fEventHistogramsName[eMultiplicity].Data(), eh.fEventHistogramsName[eCentrality].Data()); + qa.fEventHistogramsName2D[eMultiplicity_vs_VertexZ] = Form("%s_vs_%s", eh.fEventHistogramsName[eMultiplicity].Data(), eh.fEventHistogramsName[eVertexZ].Data()); + qa.fEventHistogramsName2D[eMultiplicity_vs_Occupancy] = Form("%s_vs_%s", eh.fEventHistogramsName[eMultiplicity].Data(), eh.fEventHistogramsName[eOccupancy].Data()); + qa.fEventHistogramsName2D[eMultiplicity_vs_InteractionRate] = Form("%s_vs_%s", eh.fEventHistogramsName[eMultiplicity].Data(), eh.fEventHistogramsName[eInteractionRate].Data()); + qa.fEventHistogramsName2D[eReferenceMultiplicity_vs_NContributors] = Form("%s_vs_%s", eh.fEventHistogramsName[eReferenceMultiplicity].Data(), eh.fEventHistogramsName[eNContributors].Data()); + qa.fEventHistogramsName2D[eReferenceMultiplicity_vs_Centrality] = Form("%s_vs_%s", eh.fEventHistogramsName[eReferenceMultiplicity].Data(), eh.fEventHistogramsName[eCentrality].Data()); + qa.fEventHistogramsName2D[eReferenceMultiplicity_vs_VertexZ] = Form("%s_vs_%s", eh.fEventHistogramsName[eReferenceMultiplicity].Data(), eh.fEventHistogramsName[eVertexZ].Data()); + qa.fEventHistogramsName2D[eReferenceMultiplicity_vs_Occupancy] = Form("%s_vs_%s", eh.fEventHistogramsName[eReferenceMultiplicity].Data(), eh.fEventHistogramsName[eOccupancy].Data()); + qa.fEventHistogramsName2D[eReferenceMultiplicity_vs_InteractionRate] = Form("%s_vs_%s", eh.fEventHistogramsName[eReferenceMultiplicity].Data(), eh.fEventHistogramsName[eInteractionRate].Data()); + qa.fEventHistogramsName2D[eNContributors_vs_Centrality] = Form("%s_vs_%s", eh.fEventHistogramsName[eNContributors].Data(), eh.fEventHistogramsName[eCentrality].Data()); + qa.fEventHistogramsName2D[eNContributors_vs_VertexZ] = Form("%s_vs_%s", eh.fEventHistogramsName[eNContributors].Data(), eh.fEventHistogramsName[eVertexZ].Data()); + qa.fEventHistogramsName2D[eNContributors_vs_Occupancy] = Form("%s_vs_%s", eh.fEventHistogramsName[eNContributors].Data(), eh.fEventHistogramsName[eOccupancy].Data()); + qa.fEventHistogramsName2D[eNContributors_vs_InteractionRate] = Form("%s_vs_%s", eh.fEventHistogramsName[eNContributors].Data(), eh.fEventHistogramsName[eInteractionRate].Data()); + qa.fEventHistogramsName2D[eCentrality_vs_VertexZ] = Form("%s_vs_%s", eh.fEventHistogramsName[eCentrality].Data(), eh.fEventHistogramsName[eVertexZ].Data()); + qa.fEventHistogramsName2D[eCentrality_vs_Occupancy] = Form("%s_vs_%s", eh.fEventHistogramsName[eCentrality].Data(), eh.fEventHistogramsName[eOccupancy].Data()); + qa.fEventHistogramsName2D[eCentrality_vs_ImpactParameter] = Form("%s_vs_%s", eh.fEventHistogramsName[eCentrality].Data(), eh.fEventHistogramsName[eImpactParameter].Data()); + qa.fEventHistogramsName2D[eCentrality_vs_InteractionRate] = Form("%s_vs_%s", eh.fEventHistogramsName[eCentrality].Data(), eh.fEventHistogramsName[eInteractionRate].Data()); + qa.fEventHistogramsName2D[eVertexZ_vs_Occupancy] = Form("%s_vs_%s", eh.fEventHistogramsName[eVertexZ].Data(), eh.fEventHistogramsName[eOccupancy].Data()); + qa.fEventHistogramsName2D[eVertexZ_vs_InteractionRate] = Form("%s_vs_%s", eh.fEventHistogramsName[eVertexZ].Data(), eh.fEventHistogramsName[eInteractionRate].Data()); + qa.fEventHistogramsName2D[eMultiplicity_vs_FT0CAmplitudeOnFoundBC] = Form("%s_vs_%s", eh.fEventHistogramsName[eMultiplicity].Data(), "FT0CAmplitudeOnFoundBC"); // TBI 20250331 hardwired string + qa.fEventHistogramsName2D[eCentFT0C_vs_FT0CAmplitudeOnFoundBC] = Form("%s_vs_%s", qa.fCentralityEstimatorName[eCentFT0C].Data(), "FT0CAmplitudeOnFoundBC"); // TBI 20250331 hardwired string + qa.fEventHistogramsName2D[eMultNTracksPV_vs_MultNTracksGlobal] = Form("%s_vs_%s", qa.fReferenceMultiplicityEstimatorName[eMultNTracksPV].Data(), qa.fReferenceMultiplicityEstimatorName[eMultNTracksGlobal].Data()); + qa.fEventHistogramsName2D[eCentFT0C_vs_CentFT0CVariant1] = Form("%s_vs_%s", qa.fCentralityEstimatorName[eCentFT0C].Data(), qa.fCentralityEstimatorName[eCentFT0CVariant1].Data()); + qa.fEventHistogramsName2D[eCentFT0C_vs_CentFT0M] = Form("%s_vs_%s", qa.fCentralityEstimatorName[eCentFT0C].Data(), qa.fCentralityEstimatorName[eCentFT0M].Data()); + qa.fEventHistogramsName2D[eCentFT0C_vs_CentFV0A] = Form("%s_vs_%s", qa.fCentralityEstimatorName[eCentFT0C].Data(), qa.fCentralityEstimatorName[eCentFV0A].Data()); + qa.fEventHistogramsName2D[eCentFT0C_vs_CentNTPV] = Form("%s_vs_%s", qa.fCentralityEstimatorName[eCentFT0C].Data(), qa.fCentralityEstimatorName[eCentNTPV].Data()); + qa.fEventHistogramsName2D[eCentFT0C_vs_CentNGlobal] = Form("%s_vs_%s", qa.fCentralityEstimatorName[eCentFT0C].Data(), qa.fCentralityEstimatorName[eCentNGlobal].Data()); + qa.fEventHistogramsName2D[eCentFT0M_vs_CentNTPV] = Form("%s_vs_%s", qa.fCentralityEstimatorName[eCentFT0M].Data(), qa.fCentralityEstimatorName[eCentNTPV].Data()); + qa.fEventHistogramsName2D[eCentRun2V0M_vs_CentRun2SPDTracklets] = Form("%s_vs_%s", qa.fCentralityEstimatorName[eCentRun2V0M].Data(), qa.fCentralityEstimatorName[eCentRun2SPDTracklets].Data()); + qa.fEventHistogramsName2D[eTrackOccupancyInTimeRange_vs_FT0COccupancyInTimeRange] = Form("%s_vs_%s", qa.fOccupancyEstimatorName[eTrackOccupancyInTimeRange].Data(), qa.fOccupancyEstimatorName[eFT0COccupancyInTimeRange].Data()); + qa.fEventHistogramsName2D[eCurrentRunDuration_vs_InteractionRate] = Form("%s_vs_%s", ec.fEventCutName[eCurrentRunDuration].Data(), ec.fEventCutName[eInteractionRate].Data()); + + // ***) Quick insanity check that all names are set: + for (int t = 0; t < eQAEventHistograms2D_N; t++) { + if (qa.fEventHistogramsName2D[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : qa.fEventHistogramsName2D[%d] is not set, check corresponding enum eQAEventHistograms2D \033[0m", __FUNCTION__, __LINE__, t); } } - // Configurable cfFileWithLabels{ ... } - t0.fFileWithLabels = TString(cfFileWithLabels); + // **) Names of QA 2D particle histograms: + qa.fParticleHistogramsName2D[ePt_vs_dcaXY] = Form("%s_vs_%s", ph.fParticleHistogramsName[ePt].Data(), ph.fParticleHistogramsName[edcaXY].Data()); - // Configurable cfUsePhiWeights{ ... }; - pw.fUseWeights[wPHI] = cfUsePhiWeights; + // ***) Quick insanity check that all names are set: + for (int t = 0; t < eQAParticleHistograms2D_N; t++) { + if (qa.fParticleHistogramsName2D[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : qa.fParticleHistogramsName2D[%d] is not set, check corresponding enum eQAParticleHistograms2D \033[0m", __FUNCTION__, __LINE__, t); + } + } - // Configurable cfUsePtWeights{ ... }; - pw.fUseWeights[wPT] = cfUsePtWeights; + // **) Names of QA 2D particle event histograms: + qa.fQAParticleEventHistogramsName2D[eCurrentRunDuration_vs_itsNClsEbyE] = TString::Format("%s_vs_%s", eh.fEventHistogramsName[eCurrentRunDuration].Data(), ph.fParticleHistogramsName[eitsNCls].Data()).Data(); + qa.fQAParticleEventHistogramsName2D[eCurrentRunDuration_vs_itsNClsNegEtaEbyE] = TString::Format("%s_vs_%s", eh.fEventHistogramsName[eCurrentRunDuration].Data(), TString(ph.fParticleHistogramsName[eitsNCls].Data()).Append("NegEtaEbyE").Data()).Data(); // TBI 20241214 time will tell if this Append() is safe enough... Remember that Append works in-place + qa.fQAParticleEventHistogramsName2D[eCurrentRunDuration_vs_itsNClsPosEtaEbyE] = TString::Format("%s_vs_%s", eh.fEventHistogramsName[eCurrentRunDuration].Data(), TString(ph.fParticleHistogramsName[eitsNCls].Data()).Append("PosEtaEbyE").Data()).Data(); // TBI 20241214 time will tell if this Append() is safe enough... Remember that Append works in-place + qa.fQAParticleEventHistogramsName2D[eCurrentRunDuration_vs_Eta0804EbyE] = TString::Format("%s_vs_%s", eh.fEventHistogramsName[eCurrentRunDuration].Data(), TString(ph.fParticleHistogramsName[eEta].Data()).Append("0804EbyE").Data()).Data(); // TBI 20241214 time will tell if this Append() is safe enough... Remember that Append works in-place + qa.fQAParticleEventHistogramsName2D[eCurrentRunDuration_vs_Eta0400EbyE] = TString::Format("%s_vs_%s", eh.fEventHistogramsName[eCurrentRunDuration].Data(), TString(ph.fParticleHistogramsName[eEta].Data()).Append("0400EbyE").Data()).Data(); // TBI 20241214 time will tell if this Append() is safe enough... Remember that Append works in-place + qa.fQAParticleEventHistogramsName2D[eCurrentRunDuration_vs_Eta0004EbyE] = TString::Format("%s_vs_%s", eh.fEventHistogramsName[eCurrentRunDuration].Data(), TString(ph.fParticleHistogramsName[eEta].Data()).Append("0004EbyE").Data()).Data(); // TBI 20241214 time will tell if this Append() is safe enough... Remember that Append works in-place + qa.fQAParticleEventHistogramsName2D[eCurrentRunDuration_vs_Eta0408EbyE] = TString::Format("%s_vs_%s", eh.fEventHistogramsName[eCurrentRunDuration].Data(), TString(ph.fParticleHistogramsName[eEta].Data()).Append("0408EbyE").Data()).Data(); // TBI 20241214 time will tell if this Append() is safe enough... Remember that Append works in-place + qa.fQAParticleEventHistogramsName2D[eCurrentRunDuration_vs_Pt0005EbyE] = TString::Format("%s_vs_%s", eh.fEventHistogramsName[eCurrentRunDuration].Data(), TString(ph.fParticleHistogramsName[ePt].Data()).Append("0005EbyE").Data()).Data(); // TBI 20241214 time will tell if this Append() is safe enough... Remember that Append works in-place + qa.fQAParticleEventHistogramsName2D[eCurrentRunDuration_vs_Pt0510EbyE] = TString::Format("%s_vs_%s", eh.fEventHistogramsName[eCurrentRunDuration].Data(), TString(ph.fParticleHistogramsName[ePt].Data()).Append("0510EbyE").Data()).Data(); // TBI 20241214 time will tell if this Append() is safe enough... Remember that Append works in-place + qa.fQAParticleEventHistogramsName2D[eCurrentRunDuration_vs_Pt1050EbyE] = TString::Format("%s_vs_%s", eh.fEventHistogramsName[eCurrentRunDuration].Data(), TString(ph.fParticleHistogramsName[ePt].Data()).Append("1050EbyE").Data()).Data(); // TBI 20241214 time will tell if this Append() is safe enough... Remember that Append works in-place + + // ***) Quick insanity check that all names are set: + for (int t = 0; t < eQAParticleEventHistograms2D_N; t++) { + if (qa.fQAParticleEventHistogramsName2D[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : qa.fQAParticleEventHistogramsName2D[%d] is not set, check corresponding enum eQAParticleEventHistograms2D \033[0m", __FUNCTION__, __LINE__, t); + } + } - // Configurable cfUseEtaWeights{ ... }; - pw.fUseWeights[wETA] = cfUseEtaWeights; + // **) Names of QA 2D "correlations vs." histograms: + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_Multiplicity] = TString::Format("%s_vs_%s", "Correlations", eh.fEventHistogramsName[eMultiplicity].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_ReferenceMultiplicity] = TString::Format("%s_vs_%s", "Correlations", eh.fEventHistogramsName[eReferenceMultiplicity].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_Centrality] = TString::Format("%s_vs_%s", "Correlations", eh.fEventHistogramsName[eCentrality].Data()).Data(); + // ... + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_MeanPhi] = TString::Format("%s_vs_%s", "Correlations", ph.fParticleHistogramsName[ePhi].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_MeanPt] = TString::Format("%s_vs_%s", "Correlations", ph.fParticleHistogramsName[ePt].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_MeanEta] = TString::Format("%s_vs_%s", "Correlations", ph.fParticleHistogramsName[eEta].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_MeanCharge] = TString::Format("%s_vs_%s", "Correlations", ph.fParticleHistogramsName[eCharge].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_MeantpcNClsFindable] = TString::Format("%s_vs_%s", "Correlations", ph.fParticleHistogramsName[etpcNClsFindable].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_MeantpcNClsShared] = TString::Format("%s_vs_%s", "Correlations", ph.fParticleHistogramsName[etpcNClsShared].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_MeanitsChi2NCl] = TString::Format("%s_vs_%s", "Correlations", ph.fParticleHistogramsName[eitsChi2NCl].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_MeantpcNClsFound] = TString::Format("%s_vs_%s", "Correlations", ph.fParticleHistogramsName[etpcNClsFound].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_MeantpcNClsCrossedRows] = TString::Format("%s_vs_%s", "Correlations", ph.fParticleHistogramsName[etpcNClsCrossedRows].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_MeanitsNCls] = TString::Format("%s_vs_%s", "Correlations", ph.fParticleHistogramsName[eitsNCls].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_MeanitsNClsInnerBarrel] = TString::Format("%s_vs_%s", "Correlations", ph.fParticleHistogramsName[eitsNClsInnerBarrel].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_MeantpcCrossedRowsOverFindableCls] = TString::Format("%s_vs_%s", "Correlations", ph.fParticleHistogramsName[etpcCrossedRowsOverFindableCls].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_MeantpcFoundOverFindableCls] = TString::Format("%s_vs_%s", "Correlations", ph.fParticleHistogramsName[etpcFoundOverFindableCls].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_MeantpcFractionSharedCls] = TString::Format("%s_vs_%s", "Correlations", ph.fParticleHistogramsName[etpcFractionSharedCls].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_MeantpcChi2NCl] = TString::Format("%s_vs_%s", "Correlations", ph.fParticleHistogramsName[etpcChi2NCl].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_MeandcaXY] = TString::Format("%s_vs_%s", "Correlations", ph.fParticleHistogramsName[edcaXY].Data()).Data(); + qa.fQACorrelationsVsHistogramsName2D[eCorrelations_vs_MeandcaZ] = TString::Format("%s_vs_%s", "Correlations", ph.fParticleHistogramsName[edcaZ].Data()).Data(); - // Configurable cfUseDiffPhiPtWeights{ ... }; - pw.fUseDiffWeights[wPHIPT] = cfUseDiffPhiPtWeights; + // ... - // Configurable cfUseDiffPhiEtaWeights{ ... }; - pw.fUseDiffWeights[wPHIETA] = cfUseDiffPhiEtaWeights; + // ***) Quick insanity check that all names are set: + for (int t = 0; t < eQACorrelationsVsHistograms2D_N; t++) { + if (qa.fQACorrelationsVsHistogramsName2D[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : qa.fQACorrelationsVsHistogramsName2D[%d] is not set, check corresponding enum eQACorrelationsVsHistograms2D \033[0m", __FUNCTION__, __LINE__, t); + } + } - // Configurable cfFileWithWeights{ ... } - pw.fFileWithWeights = TString(cfFileWithWeights); + // **) Names of QA 2D "correlations vs. IR vs. " profiles: + qa.fQACorrelationsVsInteractionRateVsProfilesName2D[eCorrelationsVsInteractionRate_vs_CurrentRunDuration] = TString::Format("%s_vs_%s", "CorrVsIR", eh.fEventHistogramsName[eCurrentRunDuration].Data()).Data(); + qa.fQACorrelationsVsInteractionRateVsProfilesName2D[eCorrelationsVsInteractionRate_vs_Multiplicity] = TString::Format("%s_vs_%s", "CorrVsIR", eh.fEventHistogramsName[eMultiplicity].Data()).Data(); + qa.fQACorrelationsVsInteractionRateVsProfilesName2D[eCorrelationsVsInteractionRate_vs_ReferenceMultiplicity] = TString::Format("%s_vs_%s", "CorrVsIR", eh.fEventHistogramsName[eReferenceMultiplicity].Data()).Data(); + qa.fQACorrelationsVsInteractionRateVsProfilesName2D[eCorrelationsVsInteractionRate_vs_Centrality] = TString::Format("%s_vs_%s", "CorrVsIR", eh.fEventHistogramsName[eCentrality].Data()).Data(); + // ... + qa.fQACorrelationsVsInteractionRateVsProfilesName2D[eCorrelationsVsInteractionRate_vs_MeanPhi] = TString::Format("%s_vs_Mean%s", "CorrVsIR", ph.fParticleHistogramsName[ePhi].Data()).Data(); + qa.fQACorrelationsVsInteractionRateVsProfilesName2D[eCorrelationsVsInteractionRate_vs_SigmaMeanPhi] = TString::Format("%s_vs_SigmaMean%s", "CorrVsIR", ph.fParticleHistogramsName[ePhi].Data()).Data(); + qa.fQACorrelationsVsInteractionRateVsProfilesName2D[eCorrelationsVsInteractionRate_vs_MeanPt] = TString::Format("%s_vs_Mean%s", "CorrVsIR", ph.fParticleHistogramsName[ePt].Data()).Data(); + qa.fQACorrelationsVsInteractionRateVsProfilesName2D[eCorrelationsVsInteractionRate_vs_SigmaMeanPt] = TString::Format("%s_vs_SigmaMean%s", "CorrVsIR", ph.fParticleHistogramsName[ePt].Data()).Data(); + qa.fQACorrelationsVsInteractionRateVsProfilesName2D[eCorrelationsVsInteractionRate_vs_MeanEta] = TString::Format("%s_vs_Mean%s", "CorrVsIR", ph.fParticleHistogramsName[eEta].Data()).Data(); + qa.fQACorrelationsVsInteractionRateVsProfilesName2D[eCorrelationsVsInteractionRate_vs_SigmaMeanEta] = TString::Format("%s_vs_SigmaMean%s", "CorrVsIR", ph.fParticleHistogramsName[eEta].Data()).Data(); // ... - // *) Nested loops: - // Configurable cfCalculateNestedLoops{ ... } - nl.fCalculateNestedLoops = cfCalculateNestedLoops; + // ***) Quick insanity check that all names are set: + for (int t = 0; t < eQACorrelationsVsInteractionRateVsProfiles2D_N; t++) { + if (qa.fQACorrelationsVsInteractionRateVsProfilesName2D[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : qa.fQACorrelationsVsInteractionRateVsProfilesName2D[%d] is not set, check corresponding enum eQACorrelationsVsInteractionRateVsProfiles2D \033[0m", __FUNCTION__, __LINE__, t); + } + } - // Configurable cfCalculateCustomNestedLoops{ ... } - nl.fCalculateCustomNestedLoop = cfCalculateCustomNestedLoops; + // **) Names and titles of all categories of sparse histograms: + ph.fParticleSparseHistogramsName[eDWPhi] = "fParticleSparseHistograms_DWPhi"; + ph.fParticleSparseHistogramsTitle[eDWPhi] = "sparse histogram for differential #phi weights,"; - // *) Results histograms: - res.fSaveResultsHistograms = cfSaveResultsHistograms; + ph.fParticleSparseHistogramsName[eDWPt] = "fParticleSparseHistograms_DWPt"; + ph.fParticleSparseHistogramsTitle[eDWPt] = "sparse histogram for differential p_{T} weights,"; + + ph.fParticleSparseHistogramsName[eDWEta] = "fParticleSparseHistograms_DWEta"; + ph.fParticleSparseHistogramsTitle[eDWEta] = "sparse histogram for differential #eta weights,"; + + // ... + + // ** Eta separations: + es.fCalculateEtaSeparations = cf_es.cfCalculateEtaSeparations; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_INTEGRATED] = cf_es.cfCalculateEtaSeparationsAsFunctionOfIntegrated && es.fCalculateEtaSeparations; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_MULTIPLICITY] = cf_es.cfCalculateEtaSeparationsAsFunctionOfMultiplicity && es.fCalculateEtaSeparations; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_CENTRALITY] = cf_es.cfCalculateEtaSeparationsAsFunctionOfCentrality && es.fCalculateEtaSeparations; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_PT] = cf_es.cfCalculateEtaSeparationsAsFunctionOfPt && es.fCalculateEtaSeparations; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_ETA] = false; // this one doesn't make sense in this context, obviously + es.fCalculateEtaSeparationsAsFunctionOf[AFO_OCCUPANCY] = cf_es.cfCalculateEtaSeparationsAsFunctionOfOccupancy && es.fCalculateEtaSeparations; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_INTERACTIONRATE] = cf_es.cfCalculateEtaSeparationsAsFunctionOfInteractionRate && es.fCalculateEtaSeparations; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_CURRENTRUNDURATION] = cf_es.cfCalculateEtaSeparationsAsFunctionOfCurrentRunDuration && es.fCalculateEtaSeparations; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_VZ] = cf_es.cfCalculateEtaSeparationsAsFunctionOfVz && es.fCalculateEtaSeparations; + + if (es.fCalculateEtaSeparations) { + auto lEtaSeparationsValues = cf_es.cfEtaSeparationsValues.value; + if (lEtaSeparationsValues.size() != gMaxNumberEtaSeparations) { + LOGF(info, "\033[1;31m%s at line %d : lEtaSeparationsValues.size() = %d\n \033[0m", __FUNCTION__, __LINE__, lEtaSeparationsValues.size()); + LOGF(fatal, "\033[1;31m%s at line %d : Provide in configurable cfEtaSeparationsValues precisely %d entries\n \033[0m", __FUNCTION__, __LINE__, static_cast(gMaxNumberEtaSeparations)); + } + for (int e = 0; e < gMaxNumberEtaSeparations; e++) { + if (lEtaSeparationsValues[e] < 0.) { + LOGF(fatal, "\033[1;31m%s at line %d : lEtaSeparationsValues[%d] = %f is not >= 0. \n \033[0m", __FUNCTION__, __LINE__, e, static_cast(lEtaSeparationsValues[e])); + } + es.fEtaSeparationsValues[e] = lEtaSeparationsValues[e]; + } + + auto lEtaSeparationsSkipHarmonics = cf_es.cfEtaSeparationsSkipHarmonics.value; + if (lEtaSeparationsSkipHarmonics.size() != gMaxHarmonic) { + LOGF(info, "\033[1;31m lEtaSeparationsSkipHarmonics.size() = %d\033[0m", lEtaSeparationsSkipHarmonics.size()); + LOGF(info, "\033[1;31m gMaxHarmonic) = %d\033[0m", static_cast(gMaxHarmonic)); + LOGF(fatal, "\033[1;31m%s at line %d : Mismatch in the number of flags in configurable cfEtaSeparationsSkipHarmonics, and max number of supported harmonics \n \033[0m", __FUNCTION__, __LINE__); + } + + for (int h = 0; h < static_cast(lEtaSeparationsSkipHarmonics.size()); h++) { + es.fEtaSeparationsSkipHarmonics[h] = Alright(lEtaSeparationsSkipHarmonics[h]); + } + + } // if(es.fCalculateEtaSeparations) { + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } } // void DefaultConfiguration() //============================================================ +bool Alright(TString s) +{ + // Simple utility function, which for a string formatted "0-someName" returns false, and for "1-someName" returns true. + + // a) Insanity check on the format; + // b) Do the thing. + + if (tc.fVerboseUtility) { + StartFunction(__FUNCTION__); + LOGF(info, "\033[1;32m TString s = %s\033[0m", s.Data()); + } + + bool returnValue = false; + + // a) Insanity check on the format: + TObjArray* oa = s.Tokenize("-"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL , s = %s\033[0m", __FUNCTION__, __LINE__, s.Data()); + } + int nEntries = oa->GetEntries(); + if (2 != nEntries) { + LOGF(fatal, "\033[1;31m%s at line %d : string expected in this function must be formatted as \"someName-0\" or \"someName-1\" => s = %s\033[0m", __FUNCTION__, __LINE__, s.Data()); + } + + // b) Do the thing: + // Algorithm: I split "0-someName" or "1-someName" with respect to "-" as a field separator, and check what is in the 1st field. + if (TString(oa->At(0)->GetName()).EqualTo("0")) { + delete oa; + returnValue = false; + } else if (TString(oa->At(0)->GetName()).EqualTo("1")) { + delete oa; + returnValue = true; + } else { + LOGF(fatal, "\033[1;31m%s at line %d : string expected in this function must be formatted as \"0-someName\" or \"1-someName\" => s = %s\033[0m", __FUNCTION__, __LINE__, s.Data()); + } + + if (tc.fVerboseUtility) { + ExitFunction(__FUNCTION__); + } + + return returnValue; + +} // bool Alright(const char* name) + +//============================================================ + void DefaultBooking() { // Set here which histograms are booked by default. - // a) Event histograms; - // b) Particle histograms; - // c) QA; + // a) Event histograms 1D; + // b) Event histograms 2D; + // c) Particle histograms 1D; + // d) Particle histograms 2D; + // e) Particle sparse histograms; + // f) QA. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); } - // a) Event histograms: - // By default all event histograms are booked. If you do not want particular event histogram to be booked, - // use configurable array cfBookEventHistograms, where you can specify flags 1 (book) or 0 (do not book). - // Ordering of the flags in that array is interpreted through ordering of enums in enum eEventHistograms. // TBI 20240124 is this safe enough? - auto lBookEventHistograms = (vector)cfBookEventHistograms; // this is now the local version of that int array from configurable. + // a) Event histograms 1D: + // By default all event histograms are booked. Set this flag to false to switch off booking of all event histograms: + eh.fFillEventHistograms = cf_eh.cfFillEventHistograms; + + // *) By default all event histograms are booked. If you do not want particular event histogram to be booked, + // use configurable array cfBookEventHistograms, where you can specify name of the histogram accompanied with flags 1 (book) or 0 (do not book). + // Supported format: "someName-0" and "someName-1", where "-" is a field separator. + // Ordering of the flags in that array is interpreted through ordering of enums in enum eEventHistograms. + auto lBookEventHistograms = cf_eh.cfBookEventHistograms.value; // this is now the local version of that string array from configurable. if (lBookEventHistograms.size() != eEventHistograms_N) { - LOGF(fatal, "in function \033[1;31m%s at line %d Mismatch in the number of flags in configurable cfBookEventHistograms, and number of entries in enum eEventHistograms \n \033[0m", __PRETTY_FUNCTION__, __LINE__); - } - - eh.fBookEventHistograms[eNumberOfEvents] = static_cast(lBookEventHistograms[eNumberOfEvents]); - eh.fBookEventHistograms[eTotalMultiplicity] = static_cast(lBookEventHistograms[eTotalMultiplicity]); - eh.fBookEventHistograms[eSelectedTracks] = static_cast(lBookEventHistograms[eSelectedTracks]); - eh.fBookEventHistograms[eMultFV0M] = static_cast(lBookEventHistograms[eMultFV0M]); - eh.fBookEventHistograms[eMultFT0M] = static_cast(lBookEventHistograms[eMultFT0M]); - eh.fBookEventHistograms[eMultTPC] = static_cast(lBookEventHistograms[eMultTPC]); - eh.fBookEventHistograms[eMultNTracksPV] = static_cast(lBookEventHistograms[eMultNTracksPV]); - eh.fBookEventHistograms[eCentrality] = static_cast(lBookEventHistograms[eCentrality]); - eh.fBookEventHistograms[eVertex_x] = static_cast(lBookEventHistograms[eVertex_x]); - eh.fBookEventHistograms[eVertex_y] = static_cast(lBookEventHistograms[eVertex_y]); - eh.fBookEventHistograms[eVertex_z] = static_cast(lBookEventHistograms[eVertex_z]); - eh.fBookEventHistograms[eNContributors] = static_cast(lBookEventHistograms[eNContributors]); - eh.fBookEventHistograms[eImpactParameter] = static_cast(lBookEventHistograms[eImpactParameter]); - - // b) Particle histograms: - // By default all particle histograms are booked. If you do not want particular particle histogram to be booked, - // use configurable array cfBookParticleHistograms, where you can specify flags 1 (book) or 0 (do not book). + LOGF(info, "\033[1;31m lBookEventHistograms.size() = %d\033[0m", lBookEventHistograms.size()); + LOGF(info, "\033[1;31m eEventHistograms_N) = %d\033[0m", static_cast(eEventHistograms_N)); + LOGF(fatal, "\033[1;31m%s at line %d : Mismatch in the number of flags in configurable cfBookEventHistograms, and number of entries in enum eEventHistograms \n \033[0m", __FUNCTION__, __LINE__); + } + + // *) Insanity check on the content and ordering of histogram names in the initialization in configurable cfBookEventHistograms: + // TBI 20240518 I do not need this in fact, I can automate initialization even without ordering in configurable, but it feels with the ordering enforced, it's much safer. + for (int name = 0; name < eEventHistograms_N; name++) { + // TBI 20240518 I could implement even a strickter EqualTo instead of EndsWith, but then I need to tokenize, etc., etc. This shall be safe enough. + if (!TString(lBookEventHistograms[name]).EndsWith(eh.fEventHistogramsName[name].Data())) { + LOGF(fatal, "\033[1;31m%s at line %d : Wrong content or ordering of contents in configurable cfBookEventHistograms => name = %d, lBookEventHistograms[%d] = \"%s\", eh.fEventHistogramsName[%d] = \"%s\" \n Check if you are using an up to date tag. \033[0m", __FUNCTION__, __LINE__, name, name, TString(lBookEventHistograms[name]).Data(), name, eh.fEventHistogramsName[name].Data()); + } + } + + // I append "&& eh.fFillEventHistograms" below, to switch off booking of all event histograms with one common flag: + eh.fBookEventHistograms[eNumberOfEvents] = Alright(lBookEventHistograms[eNumberOfEvents]) && eh.fFillEventHistograms; + eh.fBookEventHistograms[eTotalMultiplicity] = Alright(lBookEventHistograms[eTotalMultiplicity]) && eh.fFillEventHistograms; + eh.fBookEventHistograms[eMultiplicity] = Alright(lBookEventHistograms[eMultiplicity]) && eh.fFillEventHistograms; + eh.fBookEventHistograms[eReferenceMultiplicity] = Alright(lBookEventHistograms[eReferenceMultiplicity]) && eh.fFillEventHistograms; + eh.fBookEventHistograms[eCentrality] = Alright(lBookEventHistograms[eCentrality]) && eh.fFillEventHistograms; + eh.fBookEventHistograms[eVertexX] = Alright(lBookEventHistograms[eVertexX]) && eh.fFillEventHistograms; + eh.fBookEventHistograms[eVertexY] = Alright(lBookEventHistograms[eVertexY]) && eh.fFillEventHistograms; + eh.fBookEventHistograms[eVertexZ] = Alright(lBookEventHistograms[eVertexZ]) && eh.fFillEventHistograms; + eh.fBookEventHistograms[eNContributors] = Alright(lBookEventHistograms[eNContributors]) && eh.fFillEventHistograms; + eh.fBookEventHistograms[eImpactParameter] = Alright(lBookEventHistograms[eImpactParameter]) && eh.fFillEventHistograms; + eh.fBookEventHistograms[eEventPlaneAngle] = Alright(lBookEventHistograms[eEventPlaneAngle]) && eh.fFillEventHistograms; + eh.fBookEventHistograms[eOccupancy] = Alright(lBookEventHistograms[eOccupancy]) && eh.fFillEventHistograms; + eh.fBookEventHistograms[eInteractionRate] = Alright(lBookEventHistograms[eInteractionRate]) && eh.fFillEventHistograms; + eh.fBookEventHistograms[eCurrentRunDuration] = Alright(lBookEventHistograms[eCurrentRunDuration]) && eh.fFillEventHistograms; + eh.fBookEventHistograms[eMultMCNParticlesEta08] = Alright(lBookEventHistograms[eMultMCNParticlesEta08]) && eh.fFillEventHistograms; + + // b) Event histograms 2D: + // TBI 20240515 Ideally, all 2D shall go to QA group, see below + // ... + + // c) Particle histograms 1D: + // By default all 1D particle histograms are booked. Set this flag to false to switch off booking of all 1D particle histograms: + ph.fFillParticleHistograms = cf_ph.cfFillParticleHistograms; + + // *) If you do not want particular particle histogram to be booked, use configurable array cfBookParticleHistograms, where you can specify flags 1 (book) or 0 (do not book). // Ordering of the flags in that array is interpreted through ordering of enums in enum eParticleHistograms. // TBI 20240124 is this safe enough? - auto lBookParticleHistograms = (vector)cfBookParticleHistograms; // this is now the local version of that int array from configurable. TBI 20240124 why is this casting mandatory? + auto lBookParticleHistograms = cf_ph.cfBookParticleHistograms.value; // this is now the local version of that string array from configurable. if (lBookParticleHistograms.size() != eParticleHistograms_N) { - LOGF(fatal, "in function \033[1;31m%s at line %d Mismatch in the number of flags in configurable cfBookParticleHistograms, and number of entries in enum eParticleHistograms \n \033[0m", __PRETTY_FUNCTION__, __LINE__); + LOGF(info, "\033[1;31m lBookParticleHistograms.size() = %d\033[0m", lBookParticleHistograms.size()); + LOGF(info, "\033[1;31m eParticleHistograms_N) = %d\033[0m", static_cast(eParticleHistograms_N)); + LOGF(fatal, "in function \033[1;31m%s at line %d Mismatch in the number of flags in configurable cfBookParticleHistograms, and number of entries in enum eParticleHistograms \n \033[0m", __FUNCTION__, __LINE__); + } + + // *) Insanity check on the content and ordering of particle histograms in the initialization in configurable cfBookParticleHistograms: + // TBI 20240518 I do not need this in fact, I can automate initialization even without ordering in configurable, but it feels with the ordering enforced, it's much safer. + for (int name = 0; name < eParticleHistograms_N; name++) { + // TBI 20240518 I could implement even a strickter EqualTo instead of EndsWith, but then I need to tokenize, etc., etc. This shall be safe enough. + if (!TString(lBookParticleHistograms[name]).EndsWith(ph.fParticleHistogramsName[name].Data())) { + LOGF(fatal, "\033[1;31m%s at line %d : Wrong content or ordering of contents in configurable cfBookParticleHistograms => name = %d, lBookParticleHistograms[name] = \"%s\", ph.fParticleHistogramsName[name] = \"%s\" \n Check if you are using an up to date tag. \033[0m", __FUNCTION__, __LINE__, name, TString(lBookParticleHistograms[name]).Data(), ph.fParticleHistogramsName[name].Data()); + } + } + + // I append "&& ph.fFillParticleHistograms" below, to switch off booking of all 1D particle histograms with one common flag: + ph.fBookParticleHistograms[ePhi] = Alright(lBookParticleHistograms[ePhi]) && ph.fFillParticleHistograms; + ph.fBookParticleHistograms[ePt] = Alright(lBookParticleHistograms[ePt]) && ph.fFillParticleHistograms; + ph.fBookParticleHistograms[eEta] = Alright(lBookParticleHistograms[eEta]) && ph.fFillParticleHistograms; + ph.fBookParticleHistograms[eCharge] = Alright(lBookParticleHistograms[eCharge]) && ph.fFillParticleHistograms; + ph.fBookParticleHistograms[etpcNClsFindable] = Alright(lBookParticleHistograms[etpcNClsFindable]) && ph.fFillParticleHistograms; + ph.fBookParticleHistograms[etpcNClsShared] = Alright(lBookParticleHistograms[etpcNClsShared]) && ph.fFillParticleHistograms; + ph.fBookParticleHistograms[eitsChi2NCl] = Alright(lBookParticleHistograms[eitsChi2NCl]) && ph.fFillParticleHistograms; + ph.fBookParticleHistograms[etpcNClsFound] = Alright(lBookParticleHistograms[etpcNClsFound]) && ph.fFillParticleHistograms; + ph.fBookParticleHistograms[etpcNClsCrossedRows] = Alright(lBookParticleHistograms[etpcNClsCrossedRows]) && ph.fFillParticleHistograms; + ph.fBookParticleHistograms[eitsNCls] = Alright(lBookParticleHistograms[eitsNCls]) && ph.fFillParticleHistograms; + ph.fBookParticleHistograms[eitsNClsInnerBarrel] = Alright(lBookParticleHistograms[eitsNClsInnerBarrel]) && ph.fFillParticleHistograms; + ph.fBookParticleHistograms[etpcCrossedRowsOverFindableCls] = Alright(lBookParticleHistograms[etpcCrossedRowsOverFindableCls]) && ph.fFillParticleHistograms; + ph.fBookParticleHistograms[etpcFoundOverFindableCls] = Alright(lBookParticleHistograms[etpcFoundOverFindableCls]) && ph.fFillParticleHistograms; + ph.fBookParticleHistograms[etpcFractionSharedCls] = Alright(lBookParticleHistograms[etpcFractionSharedCls]) && ph.fFillParticleHistograms; + ph.fBookParticleHistograms[etpcChi2NCl] = Alright(lBookParticleHistograms[etpcChi2NCl]) && ph.fFillParticleHistograms; + ph.fBookParticleHistograms[edcaXY] = Alright(lBookParticleHistograms[edcaXY]) && ph.fFillParticleHistograms; + ph.fBookParticleHistograms[edcaZ] = Alright(lBookParticleHistograms[edcaZ]) && ph.fFillParticleHistograms; + ph.fBookParticleHistograms[ePDG] = Alright(lBookParticleHistograms[ePDG]) && ph.fFillParticleHistograms; + // Remark #1: I do not need here anythig for etrackCutFlagFb1, etrackCutFlagFb2, ... eisGlobalTrack, because they are booleans + // Remark #2: Nothing special here for ePtDependentDCAxyParameterization, because that is a string. + + // d) Particle histograms 2D: + // By default all 2D particle histograms are booked. Set this flag to false to switch off booking of all 2D particle histograms: + ph.fFillParticleHistograms2D = cf_ph.cfFillParticleHistograms2D; + + // If you do not want particular 2D particle histogram to be booked, use configurable array cfBookParticleHistograms2D, where you can specify flags 1 (book) or 0 (do not book). + // *) Ordering of the flags in that array is interpreted through ordering of enums in enum eParticleHistograms2D. + auto lBookParticleHistograms2D = cf_ph.cfBookParticleHistograms2D.value; // this is now the local version of that string array from configurable + // TBI 20241113 For some reason, the default values of configurable "cfBookParticleHistograms2D" are not correctly propagated in the local variables, but I can circumvent that with JSON settings for the time being + if (lBookParticleHistograms2D.size() != eParticleHistograms2D_N) { + LOGF(info, "\033[1;31m lBookParticleHistograms2D.size() = %d\033[0m", lBookParticleHistograms2D.size()); + LOGF(info, "\033[1;31m eParticleHistograms2D_N) = %d\033[0m", static_cast(eParticleHistograms2D_N)); + LOGF(fatal, "in function \033[1;31m%s at line %d Mismatch in the number of flags in configurable cfBookParticleHistograms2D, and number of entries in enum eParticleHistograms2D \n \033[0m", __FUNCTION__, __LINE__); + } + + // *) Insanity check on the content and ordering of 2D particle histograms in the initialization in configurable cfBookParticleHistograms2D: + // TBI 20241109 I do not need this in fact, I can automate initialization even without ordering in configurable, but it feels with the ordering enforced, it's much safer. + for (int name = 0; name < eParticleHistograms2D_N; name++) { + // TBI 20241109 I could implement even a strickter EqualTo instead of EndsWith, but then I need to tokenize, etc., etc. This shall be safe enough. + if (!TString(lBookParticleHistograms2D[name]).EndsWith(ph.fParticleHistogramsName2D[name].Data())) { + LOGF(fatal, "\033[1;31m%s at line %d : Wrong content or ordering of contents in configurable cfBookParticleHistograms2D => name = %d, lBookParticleHistograms2D[name] = \"%s\", ph.fParticleHistogramsName2D[name] = \"%s\" \n Check if you are using an up to date tag. \033[0m", __FUNCTION__, __LINE__, name, TString(lBookParticleHistograms2D[name]).Data(), ph.fParticleHistogramsName2D[name].Data()); + } + } + + // I append "&& ph.fFillParticleHistograms2D" below, to switch off booking of all 2D particle histograms with one common flag: + ph.fBookParticleHistograms2D[ePhiPt] = Alright(lBookParticleHistograms2D[ePhiPt]) && ph.fFillParticleHistograms2D; + ph.fBookParticleHistograms2D[ePhiEta] = Alright(lBookParticleHistograms2D[ePhiEta]) && ph.fFillParticleHistograms2D; + + // e) Particle sparse histograms: + ph.fRebinSparse = cf_ph.cfRebinSparse; + + // *) Categories of sparse histograms: + auto lBookParticleSparseHistograms = cf_ph.cfBookParticleSparseHistograms.value; // fill or not particulat category of sparse histograms + if (lBookParticleSparseHistograms.size() != eDiffWeightCategory_N) { + LOGF(info, "\033[1;31m lBookParticleSparseHistograms.size() = %d\033[0m", lBookParticleSparseHistograms.size()); + LOGF(info, "\033[1;31m eDiffWeightCategory_N) = %d\033[0m", static_cast(eDiffWeightCategory_N)); + LOGF(fatal, "in function \033[1;31m%s at line %d Mismatch in the number of flags in configurable cfBookParticleSparseHistograms, and number of entries in enum eDiffWeightCategory_N \n \033[0m", __FUNCTION__, __LINE__); + } + + // *) Insanity check on the content and ordering in the initialization in configurable cfBookParticleSparseHistograms: + // TBI 20241109 I do not need this in fact, I can automate initialization even without ordering in configurable, but it feels with the ordering enforced, it's much safer. + // Algorithm: From [01]-DWPhi I tokenize with respect to "-" the 2nd field, and check if e.g. fParticleSparseHistogramsName_DWPhi ends with it. + for (int name = 0; name < eDiffWeightCategory_N; name++) { + TObjArray* oa = TString(lBookParticleSparseHistograms[name]).Tokenize("-"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : name = %s\033[0m", __FUNCTION__, __LINE__, TString(lBookParticleSparseHistograms[name]).Data()); + } + if (!ph.fParticleSparseHistogramsName[name].EndsWith(oa->At(1)->GetName())) { + LOGF(fatal, "\033[1;31m%s at line %d : Wrong content or ordering of contents in configurable cfBookParticleSparseHistograms => name = %d, lBookParticleSparseHistograms[name] = \"%s\", ph.fParticleSparseHistogramsName[name] = \"%s\" \n Check if you are using an up to date tag. \033[0m", __FUNCTION__, __LINE__, name, TString(lBookParticleSparseHistograms[name]).Data(), ph.fParticleSparseHistogramsName[name].Data()); + } + delete oa; + } + // Remark: below exceptionally I do not append the common flag with &&, since each of these flags already stands for one category + ph.fBookParticleSparseHistograms[eDWPhi] = Alright(lBookParticleSparseHistograms[eDWPhi]); + ph.fBookParticleSparseHistograms[eDWPt] = Alright(lBookParticleSparseHistograms[eDWPt]); + ph.fBookParticleSparseHistograms[eDWEta] = Alright(lBookParticleSparseHistograms[eDWEta]); + + // f) QA: + + // **) QA 2D event histograms: + qa.fFillQAEventHistograms2D = cf_qa.cfFillQAEventHistograms2D; + + // *) If you do not want particular 2D event histogram to be booked, use configurable array cfBookQAEventHistograms2D, where you can specify flags 1 (book) or 0 (do not book). + // Ordering of the flags in that array is interpreted through ordering of enums in enum eQAEventHistograms2D + auto lBookQAEventHistograms2D = cf_qa.cfBookQAEventHistograms2D.value; // this is now the local version of that string array from configurable + // TBI 20241115 For some reason, the default values of configurable "cfBookQAEventHistograms2D" are not correctly propagated in the local variables, but I can circumvent that with JSON settings for the time being + if (lBookQAEventHistograms2D.size() != eQAEventHistograms2D_N) { + LOGF(info, "\033[1;31m lBookQAEventHistograms2D.size() = %d\033[0m", lBookQAEventHistograms2D.size()); + LOGF(info, "\033[1;31m eQAEventHistograms2D_N = %d\033[0m", static_cast(eQAEventHistograms2D_N)); + LOGF(fatal, "in function \033[1;31m%s at line %d Mismatch in the number of flags in configurable cfBookQAEventHistograms2D, and number of entries in enum eQAEventHistograms2D \n \033[0m", __FUNCTION__, __LINE__); + } + + // *) Insanity check on the content and ordering of QA 2D event histograms in the initialization in configurable cfBookQAEventHistograms2D: + // TBI 20240518 I do not need this in fact, I can automate initialization even without ordering in configurable, but it feels with the ordering enforced, it's much safer. + for (int name = 0; name < eQAEventHistograms2D_N; name++) { + // TBI 20240518 I could implement even a strickter EqualTo instead of EndsWith, but then I need to tokenize, etc., etc. This shall be safe enough. + if (!TString(lBookQAEventHistograms2D[name]).EndsWith(qa.fEventHistogramsName2D[name].Data())) { + LOGF(fatal, "\033[1;31m%s at line %d : Wrong content or ordering of contents in configurable cfBookQAEventHistograms2D => name = %d, lBookQAEventHistograms2D[name] = \"%s\", qa.fEventHistogramsName2D[name] = \"%s\" \n Check if you are using an up to date tag. \033[0m", __FUNCTION__, __LINE__, name, TString(lBookQAEventHistograms2D[name]).Data(), qa.fEventHistogramsName2D[name].Data()); + } + } + + // I append "&& qa.fFillQAEventHistograms2D" below, to switch off booking of all 2D event histograms with one common flag: + qa.fBookQAEventHistograms2D[eMultiplicity_vs_ReferenceMultiplicity] = Alright(lBookQAEventHistograms2D[eMultiplicity_vs_ReferenceMultiplicity]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eMultiplicity_vs_NContributors] = Alright(lBookQAEventHistograms2D[eMultiplicity_vs_NContributors]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eMultiplicity_vs_Centrality] = Alright(lBookQAEventHistograms2D[eMultiplicity_vs_Centrality]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eMultiplicity_vs_VertexZ] = Alright(lBookQAEventHistograms2D[eMultiplicity_vs_VertexZ]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eMultiplicity_vs_Occupancy] = Alright(lBookQAEventHistograms2D[eMultiplicity_vs_Occupancy]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eMultiplicity_vs_InteractionRate] = Alright(lBookQAEventHistograms2D[eMultiplicity_vs_InteractionRate]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eReferenceMultiplicity_vs_NContributors] = Alright(lBookQAEventHistograms2D[eReferenceMultiplicity_vs_NContributors]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eReferenceMultiplicity_vs_Centrality] = Alright(lBookQAEventHistograms2D[eReferenceMultiplicity_vs_Centrality]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eReferenceMultiplicity_vs_VertexZ] = Alright(lBookQAEventHistograms2D[eReferenceMultiplicity_vs_VertexZ]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eReferenceMultiplicity_vs_Occupancy] = Alright(lBookQAEventHistograms2D[eReferenceMultiplicity_vs_Occupancy]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eReferenceMultiplicity_vs_InteractionRate] = Alright(lBookQAEventHistograms2D[eReferenceMultiplicity_vs_InteractionRate]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eNContributors_vs_Centrality] = Alright(lBookQAEventHistograms2D[eNContributors_vs_Centrality]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eNContributors_vs_VertexZ] = Alright(lBookQAEventHistograms2D[eNContributors_vs_VertexZ]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eNContributors_vs_Occupancy] = Alright(lBookQAEventHistograms2D[eNContributors_vs_Occupancy]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eNContributors_vs_InteractionRate] = Alright(lBookQAEventHistograms2D[eNContributors_vs_InteractionRate]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eCentrality_vs_VertexZ] = Alright(lBookQAEventHistograms2D[eCentrality_vs_VertexZ]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eCentrality_vs_Occupancy] = Alright(lBookQAEventHistograms2D[eCentrality_vs_Occupancy]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eCentrality_vs_ImpactParameter] = Alright(lBookQAEventHistograms2D[eCentrality_vs_ImpactParameter]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eCentrality_vs_InteractionRate] = Alright(lBookQAEventHistograms2D[eCentrality_vs_InteractionRate]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eVertexZ_vs_Occupancy] = Alright(lBookQAEventHistograms2D[eVertexZ_vs_Occupancy]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eVertexZ_vs_InteractionRate] = Alright(lBookQAEventHistograms2D[eVertexZ_vs_InteractionRate]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eMultiplicity_vs_FT0CAmplitudeOnFoundBC] = Alright(lBookQAEventHistograms2D[eMultiplicity_vs_FT0CAmplitudeOnFoundBC]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eCentFT0C_vs_FT0CAmplitudeOnFoundBC] = Alright(lBookQAEventHistograms2D[eCentFT0C_vs_FT0CAmplitudeOnFoundBC]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eMultNTracksPV_vs_MultNTracksGlobal] = Alright(lBookQAEventHistograms2D[eMultNTracksPV_vs_MultNTracksGlobal]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eCentFT0C_vs_CentFT0CVariant1] = Alright(lBookQAEventHistograms2D[eCentFT0C_vs_CentFT0CVariant1]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eCentFT0C_vs_CentFT0M] = Alright(lBookQAEventHistograms2D[eCentFT0C_vs_CentFT0M]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eCentFT0C_vs_CentFV0A] = Alright(lBookQAEventHistograms2D[eCentFT0C_vs_CentFV0A]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eCentFT0C_vs_CentNTPV] = Alright(lBookQAEventHistograms2D[eCentFT0C_vs_CentNTPV]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eCentFT0C_vs_CentNGlobal] = Alright(lBookQAEventHistograms2D[eCentFT0C_vs_CentNGlobal]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eCentFT0M_vs_CentNTPV] = Alright(lBookQAEventHistograms2D[eCentFT0M_vs_CentNTPV]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eCentRun2V0M_vs_CentRun2SPDTracklets] = Alright(lBookQAEventHistograms2D[eCentRun2V0M_vs_CentRun2SPDTracklets]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eTrackOccupancyInTimeRange_vs_FT0COccupancyInTimeRange] = Alright(lBookQAEventHistograms2D[eTrackOccupancyInTimeRange_vs_FT0COccupancyInTimeRange]) && qa.fFillQAEventHistograms2D; + qa.fBookQAEventHistograms2D[eCurrentRunDuration_vs_InteractionRate] = Alright(lBookQAEventHistograms2D[eCurrentRunDuration_vs_InteractionRate]) && qa.fFillQAEventHistograms2D; + + // **) QA 2D particle histograms: + qa.fFillQAParticleHistograms2D = cf_qa.cfFillQAParticleHistograms2D; + + // *) If you do not want particular 2D particle histogram to be booked, use configurable array cfBookQAParticleHistograms2D, where you can specify flags 1 (book) or 0 (do not book). + // Ordering of the flags in that array is interpreted through ordering of enums in enum eQAParticleHistograms2D. + auto lBookQAParticleHistograms2D = cf_qa.cfBookQAParticleHistograms2D.value; // this is now the local version of that string array from configurable + if (lBookQAParticleHistograms2D.size() != eQAParticleHistograms2D_N) { + LOGF(info, "\033[1;31m lBookQAParticleHistograms2D.size() = %d\033[0m", lBookQAParticleHistograms2D.size()); + LOGF(info, "\033[1;31m eQAParticleHistograms2D_N = %d\033[0m", static_cast(eQAParticleHistograms2D_N)); + LOGF(fatal, "in function \033[1;31m%s at line %d Mismatch in the number of flags in configurable cfBookQAParticleHistograms2D, and number of entries in enum eParticleHistograms2D \n \033[0m", __FUNCTION__, __LINE__); + } + + // *) Insanity check on the content and ordering of QA 2D particle histograms in the initialization in configurable cfBookQAParticleHistograms2D: + // TBI 20240518 I do not need this in fact, I can automate initialization even without ordering in configurable, but it feels with the ordering enforced, it's much safer. + for (int name = 0; name < eQAParticleHistograms2D_N; name++) { + // TBI 20240518 I could implement even a strickter EqualTo instead of EndsWith, but then I need to tokenize, etc., etc. This shall be safe enough. + if (!TString(lBookQAParticleHistograms2D[name]).EndsWith(qa.fParticleHistogramsName2D[name].Data())) { + LOGF(fatal, "\033[1;31m%s at line %d : Wrong content or ordering of contents in configurable cfBookQAParticleHistograms2D => name = %d, lBookQAParticleHistograms2D[name] = \"%s\", qa.fParticleHistogramsName2D[name] = \"%s\" \n Check if you are using an up to date tag. \033[0m", __FUNCTION__, __LINE__, name, TString(lBookQAParticleHistograms2D[name]).Data(), qa.fParticleHistogramsName2D[name].Data()); + } + } + + // I append "&& qa.fFillQAParticleHistograms2D" below, to switch off booking of all 2D particle histograms with one common flag: + qa.fBookQAParticleHistograms2D[ePt_vs_dcaXY] = Alright(lBookQAParticleHistograms2D[ePt_vs_dcaXY]) && qa.fFillQAParticleHistograms2D; + + // **) QA 2D particle event histograms: + qa.fFillQAParticleEventHistograms2D = cf_qa.cfFillQAParticleEventHistograms2D; + + // *) If you do not want particular 2D particle event histogram to be booked, use configurable array cfBookQAParticleEventHistograms2D, where you can specify flags 1 (book) or 0 (do not book). + // Ordering of the flags in that array is interpreted through ordering of enums in enum eQAParticleEventHistograms2D. + auto lBookQAParticleEventHistograms2D = cf_qa.cfBookQAParticleEventHistograms2D.value; // this is now the local version of that string array from configurable + if (lBookQAParticleEventHistograms2D.size() != eQAParticleEventHistograms2D_N) { + LOGF(info, "\033[1;31m lBookQAParticleEventHistograms2D.size() = %d\033[0m", lBookQAParticleEventHistograms2D.size()); + LOGF(info, "\033[1;31m eQAParticleEventHistograms2D_N = %d\033[0m", static_cast(eQAParticleEventHistograms2D_N)); + LOGF(fatal, "in function \033[1;31m%s at line %d Mismatch in the number of flags in configurable cfBookQAParticleEventHistograms2D, and number of entries in enum eParticleEventHistograms2D \n \033[0m", __FUNCTION__, __LINE__); + } + + // *) Insanity check on the content and ordering of QA 2D particle event histograms in the initialization in configurable cfBookQAParticleEventHistograms2D: + // TBI 20240518 I do not need this in fact, I can automate initialization even without ordering in configurable, but it feels with the ordering enforced, it's much safer. + for (int name = 0; name < eQAParticleEventHistograms2D_N; name++) { + // TBI 20240518 I could implement even a strickter EqualTo instead of EndsWith, but then I need to tokenize, etc., etc. This shall be safe enough. + if (!TString(lBookQAParticleEventHistograms2D[name]).EndsWith(qa.fQAParticleEventHistogramsName2D[name].Data())) { + LOGF(fatal, "\033[1;31m%s at line %d : Wrong content or ordering of contents in configurable cfBookQAParticleEventHistograms2D => name = %d, lBookQAParticleEventHistograms2D[name] = \"%s\", qa.fParticleEventHistogramsName2D[name] = \"%s\" \n Check if you are using an up to date tag. \033[0m", __FUNCTION__, __LINE__, name, TString(lBookQAParticleEventHistograms2D[name]).Data(), qa.fQAParticleEventHistogramsName2D[name].Data()); + } + } + + // I append "&& qa.fFillQAParticleEventHistograms2D" below, to switch off booking of all 2D particle event histograms with one common flag: + qa.fBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_itsNClsEbyE] = Alright(lBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_itsNClsEbyE]) && qa.fFillQAParticleEventHistograms2D; + qa.fBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_itsNClsNegEtaEbyE] = Alright(lBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_itsNClsNegEtaEbyE]) && qa.fFillQAParticleEventHistograms2D; + qa.fBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_itsNClsPosEtaEbyE] = Alright(lBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_itsNClsPosEtaEbyE]) && qa.fFillQAParticleEventHistograms2D; + qa.fBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_Eta0804EbyE] = Alright(lBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_Eta0804EbyE]) && qa.fFillQAParticleEventHistograms2D; + qa.fBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_Eta0400EbyE] = Alright(lBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_Eta0400EbyE]) && qa.fFillQAParticleEventHistograms2D; + qa.fBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_Eta0004EbyE] = Alright(lBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_Eta0004EbyE]) && qa.fFillQAParticleEventHistograms2D; + qa.fBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_Eta0408EbyE] = Alright(lBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_Eta0408EbyE]) && qa.fFillQAParticleEventHistograms2D; + qa.fBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_Pt0005EbyE] = Alright(lBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_Pt0005EbyE]) && qa.fFillQAParticleEventHistograms2D; + qa.fBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_Pt0510EbyE] = Alright(lBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_Pt0510EbyE]) && qa.fFillQAParticleEventHistograms2D; + qa.fBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_Pt1050EbyE] = Alright(lBookQAParticleEventHistograms2D[eCurrentRunDuration_vs_Pt1050EbyE]) && qa.fFillQAParticleEventHistograms2D; + + // **) QA 2D "correlations vs." histograms: + qa.fFillQACorrelationsVsHistograms2D = cf_qa.cfFillQACorrelationsVsHistograms2D; + + // *) If you do not want particular 2D "correlations vs." histogram to be booked, use configurable array cfBookQACorrelationsVsHistograms2D, where you can specify flags 1 (book) or 0 (do not book). + // Ordering of the flags in that array is interpreted through ordering of enums in enum eQACorrelationsVsHistograms2D. + auto lBookQACorrelationsVsHistograms2D = cf_qa.cfBookQACorrelationsVsHistograms2D.value; // this is now the local version of that string array from configurable + if (lBookQACorrelationsVsHistograms2D.size() != eQACorrelationsVsHistograms2D_N) { + LOGF(info, "\033[1;31m lBookQACorrelationsVsHistograms2D.size() = %d\033[0m", lBookQACorrelationsVsHistograms2D.size()); + LOGF(info, "\033[1;31m eQACorrelationsVsHistograms2D_N = %d\033[0m", static_cast(eQACorrelationsVsHistograms2D_N)); + LOGF(fatal, "in function \033[1;31m%s at line %d Mismatch in the number of flags in configurable cfBookQACorrelationsVsHistograms2D, and number of entries in enum eCorrelationsVsHistograms2D \n \033[0m", __FUNCTION__, __LINE__); + } + + // *) Insanity check on the content and ordering of QA 2D "correlations vs." histograms in the initialization in configurable cfBookQACorrelationsVsHistograms2D: + // TBI 20240518 I do not need this in fact, I can automate initialization even without ordering in configurable, but it feels with the ordering enforced, it's much safer. + for (int name = 0; name < eQACorrelationsVsHistograms2D_N; name++) { + // TBI 20240518 I could implement even a strickter EqualTo instead of EndsWith, but then I need to tokenize, etc., etc. This shall be safe enough. + if (!TString(lBookQACorrelationsVsHistograms2D[name]).EndsWith(qa.fQACorrelationsVsHistogramsName2D[name].Data())) { + LOGF(fatal, "\033[1;31m%s at line %d : Wrong content or ordering of contents in configurable cfBookQACorrelationsVsHistograms2D => name = %d, lBookQACorrelationsVsHistograms2D[name] = \"%s\", qa.fCorrelationsVsHistogramsName2D[name] = \"%s\" \n Check if you are using an up to date tag. \033[0m", __FUNCTION__, __LINE__, name, TString(lBookQACorrelationsVsHistograms2D[name]).Data(), qa.fQACorrelationsVsHistogramsName2D[name].Data()); + } + } + + // I append "&& qa.fFillQACorrelationsVsHistograms2D" below, to switch off booking of all 2D "correlations vs." histograms with one common flag: + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_Multiplicity] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_Multiplicity]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_ReferenceMultiplicity] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_ReferenceMultiplicity]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_Centrality] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_Centrality]) && qa.fFillQACorrelationsVsHistograms2D; + // ..... + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeanPhi] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeanPhi]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeanPt] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeanPt]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeanEta] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeanEta]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeanCharge] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeanCharge]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcNClsFindable] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcNClsFindable]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcNClsShared] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcNClsShared]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeanitsChi2NCl] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeanitsChi2NCl]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcNClsFound] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcNClsFound]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcNClsCrossedRows] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcNClsCrossedRows]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeanitsNCls] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeanitsNCls]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeanitsNClsInnerBarrel] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeanitsNClsInnerBarrel]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcCrossedRowsOverFindableCls] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcCrossedRowsOverFindableCls]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcFoundOverFindableCls] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcFoundOverFindableCls]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcFractionSharedCls] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcFractionSharedCls]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcChi2NCl] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcChi2NCl]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeandcaXY] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeandcaXY]) && qa.fFillQACorrelationsVsHistograms2D; + qa.fBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeandcaZ] = Alright(lBookQACorrelationsVsHistograms2D[eCorrelations_vs_MeandcaZ]) && qa.fFillQACorrelationsVsHistograms2D; + // ..... + + // *) min and max harmonics for which this series of histograms will be booked: + auto lQACorrelationsVsHistogramsMinMaxHarmonic = cf_qa.cfQACorrelationsVsHistogramsMinMaxHarmonic.value; + qa.fQACorrelationsVsHistogramsMinMaxHarmonic[eMin] = lQACorrelationsVsHistogramsMinMaxHarmonic[eMin]; + qa.fQACorrelationsVsHistogramsMinMaxHarmonic[eMax] = lQACorrelationsVsHistogramsMinMaxHarmonic[eMax]; + // **) insanity check: + if (!(qa.fQACorrelationsVsHistogramsMinMaxHarmonic[eMin] <= qa.fQACorrelationsVsHistogramsMinMaxHarmonic[eMax])) { + LOGF(fatal, "\033[1;31m%s at line %d : wrong setting for min and max harmonics: min = %d, max = %d \033[0m", __FUNCTION__, __LINE__, qa.fQACorrelationsVsHistogramsMinMaxHarmonic[eMin], qa.fQACorrelationsVsHistogramsMinMaxHarmonic[eMax]); + } + + // **) QA 2D "correlations vs. IR vs. " profiles: + qa.fFillQACorrelationsVsInteractionRateVsProfiles2D = cf_qa.cfFillQACorrelationsVsInteractionRateVsProfiles2D; + + // *) If you do not want particular 2D correlations vs. IR vs. " profile to be booked, use configurable array cfBookQACorrelationsVsInteractionRateVsProfiles2D, where you can specify flags 1 (book) or 0 (do not book). + // Ordering of the flags in that array is interpreted through ordering of enums in enum eQACorrelationsVsInteractionRateVsProfiles2D. + auto lBookQACorrelationsVsInteractionRateVsProfiles2D = cf_qa.cfBookQACorrelationsVsInteractionRateVsProfiles2D.value; // this is now the local version of that string array from configurable + if (lBookQACorrelationsVsInteractionRateVsProfiles2D.size() != eQACorrelationsVsInteractionRateVsProfiles2D_N) { + LOGF(info, "\033[1;31m lBookQACorrelationsVsInteractionRateVsProfiles2D.size() = %d\033[0m", lBookQACorrelationsVsInteractionRateVsProfiles2D.size()); + LOGF(info, "\033[1;31m eQACorrelationsVsInteractionRateVsProfiles2D_N = %d\033[0m", static_cast(eQACorrelationsVsInteractionRateVsProfiles2D_N)); + LOGF(fatal, "in function \033[1;31m%s at line %d Mismatch in the number of flags in configurable cfBookQACorrelationsVsInteractionRateVsProfiles2D, and number of entries in enum eCorrelationsVsInteractionRateVsProfiles2D \n \033[0m", __FUNCTION__, __LINE__); + } + + // *) Insanity check on the content and ordering of QA 2D "correlations vs. IR vs. " profiles in the initialization in configurable cfBookQACorrelationsVsInteractionRateVsProfiles2D: + // TBI 20240518 I do not need this in fact, I can automate initialization even without ordering in configurable, but it feels with the ordering enforced, it's much safer. + for (int name = 0; name < eQACorrelationsVsInteractionRateVsProfiles2D_N; name++) { + // TBI 20240518 I could implement even a strickter EqualTo instead of EndsWith, but then I need to tokenize, etc., etc. This shall be safe enough. + if (!TString(lBookQACorrelationsVsInteractionRateVsProfiles2D[name]).EndsWith(qa.fQACorrelationsVsInteractionRateVsProfilesName2D[name].Data())) { + LOGF(fatal, "\033[1;31m%s at line %d : Wrong content or ordering of contents in configurable cfBookQACorrelationsVsInteractionRateVsProfiles2D => name = %d, lBookQACorrelationsVsInteractionRateVsProfiles2D[name] = \"%s\", qa.fCorrelationsVsInteractionRateVsProfilesName2D[name] = \"%s\" \n Check if you are using an up to date tag. \033[0m", __FUNCTION__, __LINE__, name, TString(lBookQACorrelationsVsInteractionRateVsProfiles2D[name]).Data(), qa.fQACorrelationsVsInteractionRateVsProfilesName2D[name].Data()); + } } - ph.fBookParticleHistograms[ePhi] = static_cast(lBookParticleHistograms[ePhi]); - ph.fBookParticleHistograms[ePt] = static_cast(lBookParticleHistograms[ePt]); - ph.fBookParticleHistograms[eEta] = static_cast(lBookParticleHistograms[eEta]); - ph.fBookParticleHistograms[etpcNClsCrossedRows] = static_cast(lBookParticleHistograms[etpcNClsCrossedRows]); - ph.fBookParticleHistograms[eDCA_xy] = static_cast(lBookParticleHistograms[eDCA_xy]); - ph.fBookParticleHistograms[eDCA_z] = static_cast(lBookParticleHistograms[eDCA_z]); + // I append "&& qa.fFillQACorrelationsVsInteractionRateVsProfiles2D" below, to switch off booking of all 2D "correlations vs. IR vs. " profiles with one common flag: + qa.fBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_CurrentRunDuration] = Alright(lBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_CurrentRunDuration]) && qa.fFillQACorrelationsVsInteractionRateVsProfiles2D; + qa.fBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_Multiplicity] = Alright(lBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_Multiplicity]) && qa.fFillQACorrelationsVsInteractionRateVsProfiles2D; + qa.fBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_ReferenceMultiplicity] = Alright(lBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_ReferenceMultiplicity]) && qa.fFillQACorrelationsVsInteractionRateVsProfiles2D; + qa.fBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_Centrality] = Alright(lBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_Centrality]) && qa.fFillQACorrelationsVsInteractionRateVsProfiles2D; + // ..... + qa.fBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_MeanPhi] = Alright(lBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_MeanPhi]) && qa.fFillQACorrelationsVsInteractionRateVsProfiles2D; + qa.fBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_SigmaMeanPhi] = Alright(lBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_SigmaMeanPhi]) && qa.fFillQACorrelationsVsInteractionRateVsProfiles2D; + qa.fBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_MeanPt] = Alright(lBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_MeanPt]) && qa.fFillQACorrelationsVsInteractionRateVsProfiles2D; + qa.fBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_SigmaMeanPt] = Alright(lBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_SigmaMeanPt]) && qa.fFillQACorrelationsVsInteractionRateVsProfiles2D; + qa.fBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_MeanEta] = Alright(lBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_MeanEta]) && qa.fFillQACorrelationsVsInteractionRateVsProfiles2D; + qa.fBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_SigmaMeanEta] = Alright(lBookQACorrelationsVsInteractionRateVsProfiles2D[eCorrelationsVsInteractionRate_vs_SigmaMeanEta]) && qa.fFillQACorrelationsVsInteractionRateVsProfiles2D; + + // ..... + + // *) min and max harmonics for which this series of histograms will be booked: + auto lQACorrelationsVsInteractionRateVsProfilesMinMaxHarmonic = cf_qa.cfQACorrelationsVsInteractionRateVsProfilesMinMaxHarmonic.value; + qa.fQACorrelationsVsInteractionRateVsProfilesMinMaxHarmonic[eMin] = lQACorrelationsVsInteractionRateVsProfilesMinMaxHarmonic[eMin]; + qa.fQACorrelationsVsInteractionRateVsProfilesMinMaxHarmonic[eMax] = lQACorrelationsVsInteractionRateVsProfilesMinMaxHarmonic[eMax]; + // **) insanity check: + if (!(qa.fQACorrelationsVsInteractionRateVsProfilesMinMaxHarmonic[eMin] < qa.fQACorrelationsVsInteractionRateVsProfilesMinMaxHarmonic[eMax])) { + LOGF(fatal, "\033[1;31m%s at line %d : wrong setting for min and max harmonics: min = %d, max = %d \033[0m", __FUNCTION__, __LINE__, qa.fQACorrelationsVsInteractionRateVsProfilesMinMaxHarmonic[eMin], qa.fQACorrelationsVsInteractionRateVsProfilesMinMaxHarmonic[eMax]); + } - // c) QA: // ... + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + } // void DefaultBooking() //============================================================ @@ -330,1706 +1240,8213 @@ void DefaultBinning() // TBI 20240114 If some of these values are going to change frequently, add support for them in MuPa-Configurables.h, // in the same way I did it for DefaultCuts(). + // At the moment, I added to configurables support only for binning of sparse histograms, because there memory managment is critical. // a) Default binning for event histograms; - // b) Default binning for particle histograms; - // c) Default binning for results histograms; - // d) Variable-length binning set via MuPa-Configurables.h. + // b) Default binning for particle histograms 1D; + // c) Default binning for particle histograms 2D; + // d) Default binning for results histograms; + // e) Variable-length binning for results histograms set via MuPa-Configurables.h. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); } // a) Default binning for event histograms: - // task->SetEventHistogramsBins("NumberOfEvents",1,0.,1.); eh.fEventHistogramsBins[eNumberOfEvents][0] = 1; eh.fEventHistogramsBins[eNumberOfEvents][1] = 0.; eh.fEventHistogramsBins[eNumberOfEvents][2] = 1.; - // task->SetEventHistogramsBins("TotalMultiplicity",1000,0.,1000.); - eh.fEventHistogramsBins[eTotalMultiplicity][0] = 10000; + + eh.fEventHistogramsBins[eTotalMultiplicity][0] = 10000.; eh.fEventHistogramsBins[eTotalMultiplicity][1] = 0.; - eh.fEventHistogramsBins[eTotalMultiplicity][2] = 10000.; - // task->SetEventHistogramsBins("SelectedTracks",1000,0.,1000.); - eh.fEventHistogramsBins[eSelectedTracks][0] = 10000; - eh.fEventHistogramsBins[eSelectedTracks][1] = 0.; - eh.fEventHistogramsBins[eSelectedTracks][2] = 10000.; - // ... TBI 20240120 - eh.fEventHistogramsBins[eMultFV0M][0] = 10000; - eh.fEventHistogramsBins[eMultFV0M][1] = 0.; - eh.fEventHistogramsBins[eMultFV0M][2] = 10000.; - // ... TBI 20240120 - eh.fEventHistogramsBins[eMultFT0M][0] = 10000; - eh.fEventHistogramsBins[eMultFT0M][1] = 0.; - eh.fEventHistogramsBins[eMultFT0M][2] = 10000.; - // ... TBI 20240120 - eh.fEventHistogramsBins[eMultTPC][0] = 10000; - eh.fEventHistogramsBins[eMultTPC][1] = 0.; - eh.fEventHistogramsBins[eMultTPC][2] = 10000.; - // ... TBI 20240120 - eh.fEventHistogramsBins[eMultNTracksPV][0] = 10000; - eh.fEventHistogramsBins[eMultNTracksPV][1] = 0.; - eh.fEventHistogramsBins[eMultNTracksPV][2] = 10000.; - // task->SetEventHistogramsBins("Centrality",100,0.,100.); + eh.fEventHistogramsBins[eTotalMultiplicity][2] = 100000.; + + eh.fEventHistogramsBins[eMultiplicity][0] = 500.; + eh.fEventHistogramsBins[eMultiplicity][1] = 0.; + eh.fEventHistogramsBins[eMultiplicity][2] = 5000.; + + eh.fEventHistogramsBins[eReferenceMultiplicity][0] = 700.; // bin width is 100 + eh.fEventHistogramsBins[eReferenceMultiplicity][1] = 0.; + eh.fEventHistogramsBins[eReferenceMultiplicity][2] = 70000.; + eh.fEventHistogramsBins[eCentrality][0] = 110; // intentionally, because if centrality is not determined, it's set to 105.0 at the moment eh.fEventHistogramsBins[eCentrality][1] = 0.; eh.fEventHistogramsBins[eCentrality][2] = 110.; - // task->SetEventHistogramsBins("Vertex_x",1000,-20.,20.); - eh.fEventHistogramsBins[eVertex_x][0] = 1000; - eh.fEventHistogramsBins[eVertex_x][1] = -20.; - eh.fEventHistogramsBins[eVertex_x][2] = 20.; - // task->SetEventHistogramsBins("Vertex_y",1000,-20.,20.); - eh.fEventHistogramsBins[eVertex_y][0] = 1000; - eh.fEventHistogramsBins[eVertex_y][1] = -20.; - eh.fEventHistogramsBins[eVertex_y][2] = 20.; - // task->SetEventHistogramsBins("Vertex_z",1000,-20.,20.); - eh.fEventHistogramsBins[eVertex_z][0] = 1000; - eh.fEventHistogramsBins[eVertex_z][1] = -20.; - eh.fEventHistogramsBins[eVertex_z][2] = 20.; - // task->SetEventHistogramsBins("NContributors",1000,0.,1000.); - eh.fEventHistogramsBins[eNContributors][0] = 1000; + + eh.fEventHistogramsBins[eVertexX][0] = 1600; + eh.fEventHistogramsBins[eVertexX][1] = -0.8; + eh.fEventHistogramsBins[eVertexX][2] = 0.8; + + eh.fEventHistogramsBins[eVertexY][0] = 1600; + eh.fEventHistogramsBins[eVertexY][1] = -0.8; + eh.fEventHistogramsBins[eVertexY][2] = 0.8; + + eh.fEventHistogramsBins[eVertexZ][0] = 800; + eh.fEventHistogramsBins[eVertexZ][1] = -40.; + eh.fEventHistogramsBins[eVertexZ][2] = 40.; + + eh.fEventHistogramsBins[eNContributors][0] = 600.; // bin width is 20 eh.fEventHistogramsBins[eNContributors][1] = 0.; - eh.fEventHistogramsBins[eNContributors][2] = 1000.; - // task->SetEventHistogramsBins("ImpactParameter",1000,0.,1000.); - eh.fEventHistogramsBins[eImpactParameter][0] = 1000000; + eh.fEventHistogramsBins[eNContributors][2] = 12000.; + + eh.fEventHistogramsBins[eImpactParameter][0] = 1000; eh.fEventHistogramsBins[eImpactParameter][1] = 0.; - eh.fEventHistogramsBins[eImpactParameter][2] = 1.; // TBI 20231031 check this, i do not know in which units IP is stored + eh.fEventHistogramsBins[eImpactParameter][2] = 100.; + + eh.fEventHistogramsBins[eEventPlaneAngle][0] = 720; + eh.fEventHistogramsBins[eEventPlaneAngle][1] = -o2::constants::math::PI; // just in case somebody uses the convention -Pi < EP < Pi, instead of 0 < EP < 2Pi + eh.fEventHistogramsBins[eEventPlaneAngle][2] = o2::constants::math::TwoPI; - // b) Default binning for particle histograms: - // task->SetParticleHistogramsBins("Phi",360,0.,TMath::TwoPi()); + eh.fEventHistogramsBins[eOccupancy][0] = 1000; + eh.fEventHistogramsBins[eOccupancy][1] = 0.; + eh.fEventHistogramsBins[eOccupancy][2] = 100000.; + + eh.fEventHistogramsBins[eInteractionRate][0] = 1000; + eh.fEventHistogramsBins[eInteractionRate][1] = 0.; + eh.fEventHistogramsBins[eInteractionRate][2] = 100.; + + eh.fEventHistogramsBins[eCurrentRunDuration][0] = 10000; + eh.fEventHistogramsBins[eCurrentRunDuration][1] = 0.; + eh.fEventHistogramsBins[eCurrentRunDuration][2] = 10000.; + + // b) Default binning for particle histograms 1D: ph.fParticleHistogramsBins[ePhi][0] = 360; ph.fParticleHistogramsBins[ePhi][1] = 0.; - ph.fParticleHistogramsBins[ePhi][2] = TMath::TwoPi(); - // task->SetParticleHistogramsBins("Pt",1000,0.,20.); - ph.fParticleHistogramsBins[ePt][0] = 1000; + ph.fParticleHistogramsBins[ePhi][2] = o2::constants::math::TwoPI; + + ph.fParticleHistogramsBins[ePt][0] = 2000; ph.fParticleHistogramsBins[ePt][1] = 0.; - ph.fParticleHistogramsBins[ePt][2] = 20.; - // task->SetParticleHistogramsBins("Eta",200,-1.,1.); - ph.fParticleHistogramsBins[eEta][0] = 200; - ph.fParticleHistogramsBins[eEta][1] = -2.; - ph.fParticleHistogramsBins[eEta][2] = 2.; + ph.fParticleHistogramsBins[ePt][2] = 200.; - ph.fParticleHistogramsBins[etpcNClsCrossedRows][0] = 200; - ph.fParticleHistogramsBins[etpcNClsCrossedRows][1] = 0.; - ph.fParticleHistogramsBins[etpcNClsCrossedRows][2] = 200.; + ph.fParticleHistogramsBins[eEta][0] = 500; + ph.fParticleHistogramsBins[eEta][1] = -5.; + ph.fParticleHistogramsBins[eEta][2] = 5.; + + ph.fParticleHistogramsBins[eCharge][0] = 7; + ph.fParticleHistogramsBins[eCharge][1] = -3.5; // anticipating I might be storing charge of Delta++, etc. + ph.fParticleHistogramsBins[eCharge][2] = 3.5; - ph.fParticleHistogramsBins[eDCA_xy][0] = 2000; - ph.fParticleHistogramsBins[eDCA_xy][1] = -10.; - ph.fParticleHistogramsBins[eDCA_xy][2] = 10.; + ph.fParticleHistogramsBins[etpcNClsFindable][0] = 300; + ph.fParticleHistogramsBins[etpcNClsFindable][1] = 0.; + ph.fParticleHistogramsBins[etpcNClsFindable][2] = 300.; - ph.fParticleHistogramsBins[eDCA_z][0] = 2000; - ph.fParticleHistogramsBins[eDCA_z][1] = -10.; - ph.fParticleHistogramsBins[eDCA_z][2] = 10.; + ph.fParticleHistogramsBins[etpcNClsShared][0] = 200; + ph.fParticleHistogramsBins[etpcNClsShared][1] = 0.; + ph.fParticleHistogramsBins[etpcNClsShared][2] = 200.; - ph.fParticleHistogramsBins[ePDG][0] = 10000; - ph.fParticleHistogramsBins[ePDG][1] = -5000.; - ph.fParticleHistogramsBins[ePDG][2] = 5000.; + ph.fParticleHistogramsBins[eitsChi2NCl][0] = 200; + ph.fParticleHistogramsBins[eitsChi2NCl][1] = 0.; + ph.fParticleHistogramsBins[eitsChi2NCl][2] = 200.; + + ph.fParticleHistogramsBins[etpcNClsFound][0] = 200; + ph.fParticleHistogramsBins[etpcNClsFound][1] = 0.; + ph.fParticleHistogramsBins[etpcNClsFound][2] = 200.; + + ph.fParticleHistogramsBins[etpcNClsCrossedRows][0] = 200; + ph.fParticleHistogramsBins[etpcNClsCrossedRows][1] = 0.; + ph.fParticleHistogramsBins[etpcNClsCrossedRows][2] = 200.; - // c) Default binning for results histograms: + ph.fParticleHistogramsBins[eitsNCls][0] = 10; + ph.fParticleHistogramsBins[eitsNCls][1] = 0.; + ph.fParticleHistogramsBins[eitsNCls][2] = 10.; + + ph.fParticleHistogramsBins[eitsNClsInnerBarrel][0] = 10; + ph.fParticleHistogramsBins[eitsNClsInnerBarrel][1] = 0.; + ph.fParticleHistogramsBins[eitsNClsInnerBarrel][2] = 10.; + + ph.fParticleHistogramsBins[etpcCrossedRowsOverFindableCls][0] = 1000; + ph.fParticleHistogramsBins[etpcCrossedRowsOverFindableCls][1] = 0.; + ph.fParticleHistogramsBins[etpcCrossedRowsOverFindableCls][2] = 10; + + ph.fParticleHistogramsBins[etpcFoundOverFindableCls][0] = 1000; + ph.fParticleHistogramsBins[etpcFoundOverFindableCls][1] = 0.; + ph.fParticleHistogramsBins[etpcFoundOverFindableCls][2] = 10.; + + ph.fParticleHistogramsBins[etpcFractionSharedCls][0] = 110; + ph.fParticleHistogramsBins[etpcFractionSharedCls][1] = -1.; // yes, I saw here entries with negative values TBI 20240507 check what are these values + ph.fParticleHistogramsBins[etpcFractionSharedCls][2] = 10.; + + ph.fParticleHistogramsBins[etpcChi2NCl][0] = 2500; + ph.fParticleHistogramsBins[etpcChi2NCl][1] = 0.; + ph.fParticleHistogramsBins[etpcChi2NCl][2] = 250.; + + ph.fParticleHistogramsBins[edcaXY][0] = 2000; + ph.fParticleHistogramsBins[edcaXY][1] = -10.; + ph.fParticleHistogramsBins[edcaXY][2] = 10.; + + ph.fParticleHistogramsBins[edcaZ][0] = 2000; + ph.fParticleHistogramsBins[edcaZ][1] = -10.; + ph.fParticleHistogramsBins[edcaZ][2] = 10.; + + ph.fParticleHistogramsBins[ePDG][0] = 2000; + ph.fParticleHistogramsBins[ePDG][1] = -1000.; + ph.fParticleHistogramsBins[ePDG][2] = 1000.; + + // c) Default binning for particle histograms 2D: + // At the moment, for fixed binning, I just re-use the binning of corresponding 1D histograms. + // For variable-length binning, I use binning from fResultsPro[], as for other histograms. + ph.fParticleHistogramsBins2D[ePhiPt][eX][0] = ph.fParticleHistogramsBins[ePhi][0]; + ph.fParticleHistogramsBins2D[ePhiPt][eX][1] = ph.fParticleHistogramsBins[ePhi][1]; + ph.fParticleHistogramsBins2D[ePhiPt][eX][2] = ph.fParticleHistogramsBins[ePhi][2]; + ph.fParticleHistogramsBins2D[ePhiPt][eY][0] = ph.fParticleHistogramsBins[ePt][0]; + ph.fParticleHistogramsBins2D[ePhiPt][eY][1] = ph.fParticleHistogramsBins[ePt][1]; + ph.fParticleHistogramsBins2D[ePhiPt][eY][2] = ph.fParticleHistogramsBins[ePt][2]; + + ph.fParticleHistogramsBins2D[ePhiEta][eX][0] = ph.fParticleHistogramsBins[ePhi][0]; + ph.fParticleHistogramsBins2D[ePhiEta][eX][1] = ph.fParticleHistogramsBins[ePhi][1]; + ph.fParticleHistogramsBins2D[ePhiEta][eX][2] = ph.fParticleHistogramsBins[ePhi][2]; + ph.fParticleHistogramsBins2D[ePhiEta][eY][0] = ph.fParticleHistogramsBins[eEta][0]; + ph.fParticleHistogramsBins2D[ePhiEta][eY][1] = ph.fParticleHistogramsBins[eEta][1]; + ph.fParticleHistogramsBins2D[ePhiEta][eY][2] = ph.fParticleHistogramsBins[eEta][2]; + + // d) Default binning for results histograms: // Remark: These bins apply to following categories fCorrelationsPro, fNestedLoopsPro, fTest0Pro, and fResultsPro. // *) For integrated resullts, binning is always the same: res.fResultsProFixedLengthBins[AFO_INTEGRATED][0] = 1; res.fResultsProFixedLengthBins[AFO_INTEGRATED][1] = 0.; res.fResultsProFixedLengthBins[AFO_INTEGRATED][2] = 1.; - // *) Fixed-length binning vs. multiplicity: - auto lFixedLength_mult_bins = (vector)cFixedLength_mult_bins; // this is now the local version of that float array from configurable. - if (lFixedLength_mult_bins.size() != 3) { - LOGF(fatal, "in function \033[1;31m%s at line %d => The array cFixedLength_mult_bins must have 3 entries: {nBins, min, max} \n \033[0m", __PRETTY_FUNCTION__, __LINE__); - } - res.fResultsProFixedLengthBins[AFO_MULTIPLICITY][0] = lFixedLength_mult_bins[0]; - res.fResultsProFixedLengthBins[AFO_MULTIPLICITY][1] = lFixedLength_mult_bins[1]; - res.fResultsProFixedLengthBins[AFO_MULTIPLICITY][2] = lFixedLength_mult_bins[2]; - + this->InitializeFixedLengthBins(AFO_MULTIPLICITY); // *) Fixed-length binning vs. centrality: - auto lFixedLength_cent_bins = (vector)cFixedLength_cent_bins; // this is now the local version of that float array from configurable. - if (lFixedLength_cent_bins.size() != 3) { - LOGF(fatal, "in function \033[1;31m%s at line %d => The array cFixedLength_cent_bins must have 3 entries: {nBins, min, max} \n \033[0m", __PRETTY_FUNCTION__, __LINE__); - } - res.fResultsProFixedLengthBins[AFO_CENTRALITY][0] = lFixedLength_cent_bins[0]; - res.fResultsProFixedLengthBins[AFO_CENTRALITY][1] = lFixedLength_cent_bins[1]; - res.fResultsProFixedLengthBins[AFO_CENTRALITY][2] = lFixedLength_cent_bins[2]; - + this->InitializeFixedLengthBins(AFO_CENTRALITY); // *) Fixed-length binning vs. pt: - auto lFixedLength_pt_bins = (vector)cFixedLength_pt_bins; // this is now the local version of that float array from configurable. - if (lFixedLength_pt_bins.size() != 3) { - LOGF(fatal, "in function \033[1;31m%s at line %d => The array cFixedLength_pt_bins must have 3 entries: {nBins, min, max} \n \033[0m", __PRETTY_FUNCTION__, __LINE__); - } - res.fResultsProFixedLengthBins[AFO_PT][0] = lFixedLength_pt_bins[0]; - res.fResultsProFixedLengthBins[AFO_PT][1] = lFixedLength_pt_bins[1]; - res.fResultsProFixedLengthBins[AFO_PT][2] = lFixedLength_pt_bins[2]; - + this->InitializeFixedLengthBins(AFO_PT); // *) Fixed-length binning vs. eta: - auto lFixedLength_eta_bins = (vector)cFixedLength_eta_bins; // this is now the local version of that float array from configurable. - if (lFixedLength_eta_bins.size() != 3) { - LOGF(fatal, "in function \033[1;31m%s at line %d => The array cFixedLength_eta_bins must have 3 entries: {nBins, min, max} \n \033[0m", __PRETTY_FUNCTION__, __LINE__); - } - res.fResultsProFixedLengthBins[AFO_ETA][0] = lFixedLength_eta_bins[0]; - res.fResultsProFixedLengthBins[AFO_ETA][1] = lFixedLength_eta_bins[1]; - res.fResultsProFixedLengthBins[AFO_ETA][2] = lFixedLength_eta_bins[2]; - - // d) Variable-length binning set via MuPa-Configurables.h: + this->InitializeFixedLengthBins(AFO_ETA); + // *) Fixed-length binning vs. occupancy: + this->InitializeFixedLengthBins(AFO_OCCUPANCY); + // *) Fixed-length binning vs. interaction rate: + this->InitializeFixedLengthBins(AFO_INTERACTIONRATE); + // *) Fixed-length binning vs. run duration: + this->InitializeFixedLengthBins(AFO_CURRENTRUNDURATION); + // *) Vertex z position: + this->InitializeFixedLengthBins(AFO_VZ); + + // e) Variable-length binning set via MuPa-Configurables.h: // *) Variable-length binning vs. multiplicity: - if (cUseVariableLength_mult_bins) { - res.fUseResultsProVariableLengthBins[AFO_MULTIPLICITY] = kTRUE; - res.fResultsProVariableLengthBinsString[AFO_MULTIPLICITY] = cVariableLength_mult_bins; - this->CastStringIntoArray(AFO_MULTIPLICITY); + if (cf_res.cfUseVariableLength_mult_bins) { + this->InitializeVariableLengthBins(AFO_MULTIPLICITY); } // *) Variable-length binning vs. centrality: - if (cUseVariableLength_cent_bins) { - res.fUseResultsProVariableLengthBins[AFO_CENTRALITY] = kTRUE; - res.fResultsProVariableLengthBinsString[AFO_CENTRALITY] = cVariableLength_cent_bins; - this->CastStringIntoArray(AFO_CENTRALITY); + if (cf_res.cfUseVariableLength_cent_bins) { + this->InitializeVariableLengthBins(AFO_CENTRALITY); } // *) Variable-length binning vs. pt: - if (cUseVariableLength_pt_bins) { - res.fUseResultsProVariableLengthBins[AFO_PT] = kTRUE; - res.fResultsProVariableLengthBinsString[AFO_PT] = cVariableLength_pt_bins; - this->CastStringIntoArray(AFO_PT); + if (cf_res.cfUseVariableLength_pt_bins) { + this->InitializeVariableLengthBins(AFO_PT); } // *) Variable-length binning vs. eta: - if (cUseVariableLength_eta_bins) { - res.fUseResultsProVariableLengthBins[AFO_ETA] = kTRUE; - res.fResultsProVariableLengthBinsString[AFO_ETA] = cVariableLength_eta_bins; - this->CastStringIntoArray(AFO_ETA); + if (cf_res.cfUseVariableLength_eta_bins) { + this->InitializeVariableLengthBins(AFO_ETA); + } + // *) Variable-length binning vs. occupancy: + if (cf_res.cfUseVariableLength_occu_bins) { + this->InitializeVariableLengthBins(AFO_OCCUPANCY); + } + // *) Variable-length binning vs. interaction rate: + if (cf_res.cfUseVariableLength_ir_bins) { + this->InitializeVariableLengthBins(AFO_INTERACTIONRATE); + } + // *) Variable-length binning vs. run duration: + if (cf_res.cfUseVariableLength_crd_bins) { + this->InitializeVariableLengthBins(AFO_CURRENTRUNDURATION); + } + // *) Variable-length binning vs. vertex z position: + if (cf_res.cfUseVariableLength_vz_bins) { + this->InitializeVariableLengthBins(AFO_VZ); + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); } } // void DefaultBinning() //============================================================ -void CastStringIntoArray(Int_t AFO) +void InitializeFixedLengthBins(eAsFunctionOf AFO) { - // Temporary function, to be removed eventually. Here temporarily I am casting e.g. a string "1.0,2.0,5.0" into corresponding TArrayD. - // TBI 20240114 This function is used until I figure out how to pass array directly via configurable. - - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); - } + // This is a helper function to suppress code bloat in DefaultBinning(). + // It merely initalizes res.fResultsProFixedLengthBins[...] from corresponding configurables + a few other minor thingies. if (tc.fVerbose) { - LOGF(info, "\033[1;32m Casting a string %s into TArrayD .... \033[0m", res.fResultsProVariableLengthBinsString[AFO].Data()); + StartFunction(__FUNCTION__); } - TObjArray* oa = res.fResultsProVariableLengthBinsString[AFO].Tokenize(","); - if (!oa) { - LOGF(fatal, "in function \033[1;31m%s at line %d \n fResultsProVariableLengthBinsString[AFO] = %s\033[0m", __PRETTY_FUNCTION__, __LINE__, res.fResultsProVariableLengthBinsString[AFO].Data()); - } - Int_t nEntries = oa->GetEntries(); - res.fResultsProVariableLengthBins[AFO] = new TArrayD(nEntries); - for (Int_t i = 0; i < nEntries; i++) { - // cout<< TString(oa->At(i)->GetName()).Atof() <AddAt(TString(oa->At(i)->GetName()).Atof(), i); - } - delete oa; // yes, otherwise it's a memory leak + // Common local vector for all fixed-length bins: + std::vector lFixedLength_bins; - if (tc.fVerbose) { - for (Int_t i = 0; i < res.fResultsProVariableLengthBins[AFO]->GetSize(); i++) { - LOGF(info, "\033[1;32m [%d] : %f \033[0m", i, res.fResultsProVariableLengthBins[AFO]->At(i)); + switch (AFO) { + case AFO_MULTIPLICITY: { + lFixedLength_bins = cf_res.cfFixedLength_mult_bins.value; + break; + } + case AFO_CENTRALITY: { + lFixedLength_bins = cf_res.cfFixedLength_cent_bins.value; + break; + } + case AFO_PT: { + lFixedLength_bins = cf_res.cfFixedLength_pt_bins.value; + break; + } + case AFO_ETA: { + lFixedLength_bins = cf_res.cfFixedLength_eta_bins.value; + break; + } + case AFO_OCCUPANCY: { + lFixedLength_bins = cf_res.cfFixedLength_occu_bins.value; + break; + } + case AFO_INTERACTIONRATE: { + lFixedLength_bins = cf_res.cfFixedLength_ir_bins.value; + break; + } + case AFO_CURRENTRUNDURATION: { + lFixedLength_bins = cf_res.cfFixedLength_crd_bins.value; + break; + } + case AFO_VZ: { + lFixedLength_bins = cf_res.cfFixedLength_vz_bins.value; + break; + } + // ... + default: { + LOGF(fatal, "\033[1;31m%s at line %d : This enum AFO = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, static_cast(AFO)); + break; } + } // switch(AFO) + + // From this point onward, the code is the same for any AFO variable: + if (lFixedLength_bins.size() != 3) { + LOGF(fatal, "in function \033[1;31m%s at line %d => The array cfFixedLength_bins must have have 3 entries: {nBins, min, max} \n \033[0m", __FUNCTION__, __LINE__); } + res.fResultsProFixedLengthBins[AFO][0] = lFixedLength_bins[0]; + res.fResultsProFixedLengthBins[AFO][1] = lFixedLength_bins[1]; + res.fResultsProFixedLengthBins[AFO][2] = lFixedLength_bins[2]; if (tc.fVerbose) { - LOGF(info, "\033[1;32m Done! \033[0m"); + LOGF(info, "\033[1;32m %s : fixed-length %s bins \033[0m", __FUNCTION__, res.fResultsProXaxisTitle[AFO].Data()); + LOGF(info, "\033[1;32m [0] : %f \033[0m", res.fResultsProFixedLengthBins[AFO][0]); + LOGF(info, "\033[1;32m [1] : %f \033[0m", res.fResultsProFixedLengthBins[AFO][1]); + LOGF(info, "\033[1;32m [2] : %f \033[0m", res.fResultsProFixedLengthBins[AFO][2]); + ExitFunction(__FUNCTION__); } -} // void CastStringIntoArray(Int_t AFO) +} // void InitializeFixedLengthBins(eAsFunctionOf AFO) //============================================================ -void DefaultCuts() +void InitializeVariableLengthBins(eAsFunctionOf AFO) { - // Define default cuts. Default cuts are hardwired in MuPa-Configurables.h. - - // a) Default event cuts; - // b) Default particle cuts. + // This is a helper function to suppress code bloat in DefaultBinning(). + // It merely initalizes res.fResultsProVariableLengthBins[...] from corresponding configurables + a few other minor thingies. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); } - // a) Default event cuts: - eh.fEventCuts[eNumberOfEvents][eMin] = - cNumberOfEvents_min; // Configurable - // cNumberOfEvents_min{"cNumberOfEvents_min", ... - eh.fEventCuts[eNumberOfEvents][eMax] = - cNumberOfEvents_max; // Configurable - // cNumberOfEvents_max{"cNumberOfEvents_max", ... - - eh.fEventCuts[eTotalMultiplicity][eMin] = cTotalMultiplicity_min; // Configurable - // cTotalMultiplicity_min{"cTotalMultiplicity_min", - // ... - eh.fEventCuts[eTotalMultiplicity][eMax] = cTotalMultiplicity_max; // Configurable - // cTotalMultiplicity_max{"cTotalMultiplicity_max", - // ... - - eh.fEventCuts[eSelectedTracks][eMin] = - cSelectedTracks_min; // Configurable - // cSelectedTracks_min{"cSelectedTracks_min", ... - eh.fEventCuts[eSelectedTracks][eMax] = - cSelectedTracks_max; // Configurable - // cSelectedTracks_max{"cSelectedTracks_max", ... - - eh.fEventCuts[eCentrality][eMin] = - cCentrality_min; // Configurable cCentrality_min{"cCentrality_min", - // ... - eh.fEventCuts[eCentrality][eMax] = - cCentrality_max; // Configurable cCentrality_max{"cCentrality_max", - // ... - - eh.fEventCuts[eVertex_x][eMin] = - cVertex_x_min; // Configurable cVertex_x_min{"cVertex_x_min", ... - eh.fEventCuts[eVertex_x][eMax] = - cVertex_x_max; // Configurable cVertex_x_max{"cVertex_x_max", ... - - eh.fEventCuts[eVertex_y][eMin] = - cVertex_y_min; // Configurable cVertex_y_min{"cVertex_y_min", ... - eh.fEventCuts[eVertex_y][eMax] = - cVertex_y_max; // Configurable cVertex_y_max{"cVertex_y_max", ... - - eh.fEventCuts[eVertex_z][eMin] = - cVertex_z_min; // Configurable cVertex_z_min{"cVertex_z_min", ... - eh.fEventCuts[eVertex_z][eMax] = - cVertex_z_max; // Configurable cVertex_z_max{"cVertex_z_max", ... - - eh.fEventCuts[eNContributors][eMin] = - cNContributors_min; // Configurable - // cNContributors_min{"cNContributors_min", ... - eh.fEventCuts[eNContributors][eMax] = - cNContributors_max; // Configurable - // cNContributors_max{"cNContributors_max", ... - - eh.fEventCuts[eImpactParameter][eMin] = - cImpactParameter_min; // Configurable - // cImpactParameter_min{"cImpactParameter_min", ... - eh.fEventCuts[eImpactParameter][eMax] = - cImpactParameter_max; // Configurable - // cImpactParameter_max{"cImpactParameter_max", ... - - // ... - - // b) Default particle cuts: - -} // void DefaultCuts() - -//============================================================ + // Common local vector for all variable-length bins: + std::vector lVariableLength_bins; -void InsanityChecks() -{ - // Do insanity checks on configuration, booking, binning and cuts. + switch (AFO) { + case AFO_MULTIPLICITY: { + lVariableLength_bins = cf_res.cfVariableLength_mult_bins.value; + break; + } + case AFO_CENTRALITY: { + lVariableLength_bins = cf_res.cfVariableLength_cent_bins.value; + break; + } + case AFO_PT: { + lVariableLength_bins = cf_res.cfVariableLength_pt_bins.value; + break; + } + case AFO_ETA: { + lVariableLength_bins = cf_res.cfVariableLength_eta_bins.value; + break; + } + case AFO_OCCUPANCY: { + lVariableLength_bins = cf_res.cfVariableLength_occu_bins.value; + break; + } + case AFO_INTERACTIONRATE: { + lVariableLength_bins = cf_res.cfVariableLength_ir_bins.value; + break; + } + case AFO_CURRENTRUNDURATION: { + lVariableLength_bins = cf_res.cfVariableLength_crd_bins.value; + break; + } + case AFO_VZ: { + lVariableLength_bins = cf_res.cfVariableLength_vz_bins.value; + break; + } + // ... + default: { + LOGF(fatal, "\033[1;31m%s at line %d : This enum AFO = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, static_cast(AFO)); + break; + } + } // switch(AFO) - // a) Insanity checks on configuration; - // b) Insanity checks on event cuts; - // c) Insanity checks on booking; - // d) Insanity checks on binning; - // e) Insanity checks on cuts. + // From this point onward, the code is the same for any AFO variable: + res.fUseResultsProVariableLengthBins[AFO] = true; + if (lVariableLength_bins.size() < 2) { + LOGF(fatal, "in function \033[1;31m%s at line %d => The array cfVariableLength_bins must have at least 2 entries \n \033[0m", __FUNCTION__, __LINE__); + } + res.fResultsProVariableLengthBins[AFO] = new TArrayF(lVariableLength_bins.size(), lVariableLength_bins.data()); + if (tc.fVerbose) { + LOGF(info, "\033[1;32m %s : variable-length %s bins \033[0m", __FUNCTION__, res.fResultsProXaxisTitle[AFO].Data()); + for (int i = 0; i < res.fResultsProVariableLengthBins[AFO]->GetSize(); i++) { + LOGF(info, "\033[1;32m [%d] : %f \033[0m", i, res.fResultsProVariableLengthBins[AFO]->GetAt(i)); + } + } if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + ExitFunction(__FUNCTION__); } - // a) Insanity checks on configuration: +} // void InitializeVariableLengthBins(eAsFunctionOf AFO) + +//============================================================ + +void CastStringIntoArray(int AFO) +{ + // Temporary function, to be removed eventually. Here temporarily I am casting e.g. a string "1.0,2.0,5.0" into corresponding TArrayD. - // *) Insanity check on individual flags: Make sure that only one process is set to kTRUE. - // If 2 or more are kTRUE, then corresponding process function is executed over ALL data, then another process(...) function, etc. - // Re-think this if it's possible to run different process(...)'s concurently over the same data. - if ((Int_t)tc.fProcessRec + (Int_t)tc.fProcessRecSim + (Int_t)tc.fProcessSim + (Int_t)tc.fProcessRec_Run2 + (Int_t)tc.fProcessRecSim_Run2 + (Int_t)tc.fProcessSim_Run2 + (Int_t)tc.fProcessRec_Run1 + (Int_t)tc.fProcessRecSim_Run1 + (Int_t)tc.fProcessSim_Run1 > 1) { - LOGF(info, "\033[1;31m Only one flag can be kTRUE: tc.fProcessRec = %d, tc.fProcessRecSim = %d, tc.fProcessSim = %d, tc.fProcessRec_Run2 = %d, tc.fProcessRecSim_Run2 = %d, tc.fProcessSim_Run2 = %d, tc.fProcessRec_Run1 = %d, tc.fProcessRecSim_Run1 = %d, tc.fProcessSim_Run1 = %d \033[0m", (Int_t)tc.fProcessRec, (Int_t)tc.fProcessRecSim, (Int_t)tc.fProcessSim, (Int_t)tc.fProcessRec_Run2, (Int_t)tc.fProcessRecSim_Run2, (Int_t)tc.fProcessSim_Run2, (Int_t)tc.fProcessRec_Run1, (Int_t)tc.fProcessRecSim_Run1, (Int_t)tc.fProcessSim_Run1); - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); + // TBI 20241019 This function is not needed any longer, remove eventually. + + if (tc.fVerbose) { + LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); } - // *) Seed for random number generator must be non-negative integer: - // if (tc.fRandomSeed < 0) { - // LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); - // } + if (tc.fVerbose) { + LOGF(info, "\033[1;32m Casting a string %s into TArrayD .... \033[0m", res.fResultsProVariableLengthBinsString[AFO].Data()); + } - // *) Insanity checks on event cuts: - if (tc.fProcessRec_Run2 || tc.fProcessRec_Run1) { // From documentation: Bypass this check if you analyse MC or continuous Run3 data. - if (!(ec.fTrigger.EqualTo("kINT7"))) { // TBI 20240223 expand this list with other supported triggers eventually in this category (see if(...) above) - LOGF(info, "in function \033[1;32m%s at line %d : trigger \"%s\" is not internally supported yet. Add it to the list of supported triggers, if you really want to use that one.\033[0m", __PRETTY_FUNCTION__, __LINE__, ec.fTrigger.Data()); - ec.fUseTrigger = kFALSE; - } else { - ec.fUseTrigger = kTRUE; // I am analyzing converted Run 1 or Run 2 real data (not MC!), and the trigger is supported, so let's use it - } + TObjArray* oa = res.fResultsProVariableLengthBinsString[AFO].Tokenize(","); + if (!oa) { + LOGF(fatal, "in function \033[1;31m%s at line %d \n fResultsProVariableLengthBinsString[AFO] = %s\033[0m", __FUNCTION__, __LINE__, res.fResultsProVariableLengthBinsString[AFO].Data()); + } + int nEntries = oa->GetEntries(); + res.fResultsProVariableLengthBins[AFO] = new TArrayF(nEntries); + for (int i = 0; i < nEntries; i++) { + res.fResultsProVariableLengthBins[AFO]->AddAt(TString(oa->At(i)->GetName()).Atof(), i); } + delete oa; // yes, otherwise it's a memory leak - if (ec.fUseSel7) { // from doc: for Run 2 data and MC - if (!(tc.fProcessRec_Run2 || tc.fProcessRecSim_Run2 || tc.fProcessSim_Run2 || tc.fProcessRec_Run1 || tc.fProcessRecSim_Run1 || tc.fProcessSim_Run1)) { - LOGF(fatal, "in function \033[1;31m%s at line %d use fUseSel7 for Run 2 data and MC\033[0m", __PRETTY_FUNCTION__, __LINE__); + if (tc.fVerbose) { + for (int i = 0; i < res.fResultsProVariableLengthBins[AFO]->GetSize(); i++) { + LOGF(info, "\033[1;32m [%d] : %f \033[0m", i, res.fResultsProVariableLengthBins[AFO]->At(i)); } } - if (ec.fUseSel8) { // from doc: for Run 3 data and MC - if (!(tc.fProcessRec || tc.fProcessRecSim || tc.fProcessSim)) { - LOGF(fatal, "in function \033[1;31m%s at line %d use fUseSel8 for Run 3 data and MC\033[0m", __PRETTY_FUNCTION__, __LINE__); - } + if (tc.fVerbose) { + LOGF(info, "\033[1;32m Done! \033[0m"); } - if (tc.fFixedNumberOfRandomlySelectedTracks > 0 && !tc.fUseFisherYates) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); +} // void CastStringIntoArray(int AFO) + +//============================================================ + +void DefaultCuts() +{ + // Define default cuts. Default cuts are hardwired in MuPa-Configurables.h. + + // a) Default event cuts; + // b) Default particle cuts. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); } - if (tc.fProcessRec || tc.fProcessRecSim || tc.fProcessSim) { - // Supported centrality estimators for Run 3 are enlisted here: - if (!(ec.fCentralityEstimator.EqualTo("centFT0M", TString::kIgnoreCase) || - ec.fCentralityEstimator.EqualTo("centFV0A", TString::kIgnoreCase) || - ec.fCentralityEstimator.EqualTo("centNTPV", TString::kIgnoreCase))) { - LOGF(fatal, "in function \033[1;31m%s at line %d. centrality estimator = %d is not supported yet for Run 3 analysis. \033[0m", __PRETTY_FUNCTION__, __LINE__, ec.fCentralityEstimator.Data()); + // a) Default event cuts: + + // *) Use or do not use a cut enumerated in eEventHistograms + eEventCuts. + // Default cuts are set in configurable cfUseEventCuts + auto lUseEventCuts = (std::vector)cf_ec.cfUseEventCuts; + if (lUseEventCuts.size() != eEventCuts_N) { + LOGF(info, "\033[1;31m lUseEventCuts.size() = %d\033[0m", lUseEventCuts.size()); + LOGF(info, "\033[1;31m eEventCuts_N = %d\033[0m", static_cast(eEventCuts_N)); + LOGF(fatal, "\033[1;31m%s at line %d : Mismatch in the number of flags in configurable cfUseEventCuts, and number of entries in enum eEventHistograms + eEventCuts \n \033[0m", __FUNCTION__, __LINE__); + } + + // *) Insanity check on the content and ordering of event cuts in the initialization in configurable cfUseEventCuts: + // TBI 20240518 I do not need this in fact, I can automate initialization even without ordering in configurable, but it feels with the ordering enforced, it's much safer. + for (int name = 0; name < eEventCuts_N; name++) { + // TBI 20240518 I could implement even a strickter EqualTo instead of EndsWith, but then I need to tokenize, etc., etc. This shall be safe enough. + if (!TString(lUseEventCuts[name]).EndsWith(ec.fEventCutName[name].Data())) { + LOGF(fatal, "\033[1;31m%s at line %d : Wrong content or ordering of contents in configurable cfUseEventCuts => name = %d, lUseEventCuts[name] = \"%s\", ec.fEventCutName[name] = \"%s\" \033[0m", __FUNCTION__, __LINE__, name, TString(lUseEventCuts[name]).Data(), ec.fEventCutName[name].Data()); } } - if (tc.fProcessRec_Run2 || tc.fProcessRecSim_Run2 || tc.fProcessSim_Run2 || tc.fProcessRec_Run1 || tc.fProcessRecSim_Run1 || tc.fProcessSim_Run1) { - // Supported centrality estimators for Run 3 are enlisted here: - if (!(ec.fCentralityEstimator.EqualTo("centRun2V0M", TString::kIgnoreCase) || - ec.fCentralityEstimator.EqualTo("centRun2SPDTracklets", TString::kIgnoreCase))) { - LOGF(fatal, "in function \033[1;31m%s at line %d. centrality estimator = %d is not supported yet for converted Run 2 and Run 1 analysis. \033[0m", __PRETTY_FUNCTION__, __LINE__, ec.fCentralityEstimator.Data()); + // *) from enum eEventHistograms: + ec.fUseEventCuts[eNumberOfEvents] = Alright(lUseEventCuts[eNumberOfEvents]); // total number of events (before event cuts) + ec.fUseEventCuts[eTotalMultiplicity] = Alright(lUseEventCuts[eTotalMultiplicity]); + ec.fUseEventCuts[eMultiplicity] = Alright(lUseEventCuts[eMultiplicity]); + ec.fUseEventCuts[eReferenceMultiplicity] = Alright(lUseEventCuts[eReferenceMultiplicity]); + ec.fUseEventCuts[eCentrality] = Alright(lUseEventCuts[eCentrality]); + ec.fUseEventCuts[eVertexX] = Alright(lUseEventCuts[eVertexX]); + ec.fUseEventCuts[eVertexY] = Alright(lUseEventCuts[eVertexY]); + ec.fUseEventCuts[eVertexZ] = Alright(lUseEventCuts[eVertexZ]); + ec.fUseEventCuts[eNContributors] = Alright(lUseEventCuts[eNContributors]); + ec.fUseEventCuts[eImpactParameter] = Alright(lUseEventCuts[eImpactParameter]); + ec.fUseEventCuts[eEventPlaneAngle] = Alright(lUseEventCuts[eEventPlaneAngle]); + ec.fUseEventCuts[eOccupancy] = Alright(lUseEventCuts[eOccupancy]); + ec.fUseEventCuts[eInteractionRate] = Alright(lUseEventCuts[eInteractionRate]); + ec.fUseEventCuts[eCurrentRunDuration] = Alright(lUseEventCuts[eCurrentRunDuration]); + ec.fUseEventCuts[eMultMCNParticlesEta08] = Alright(lUseEventCuts[eMultMCNParticlesEta08]); + + // *) from enum eEventCuts: + ec.fUseEventCuts[eTrigger] = Alright(lUseEventCuts[eTrigger]); + ec.fUseEventCuts[eSel7] = Alright(lUseEventCuts[eSel7]); + ec.fUseEventCuts[eSel8] = Alright(lUseEventCuts[eSel8]); + ec.fUseEventCuts[eMultiplicityEstimator] = Alright(lUseEventCuts[eMultiplicityEstimator]); + ec.fUseEventCuts[eCentralityEstimator] = Alright(lUseEventCuts[eCentralityEstimator]); + ec.fUseEventCuts[eReferenceMultiplicityEstimator] = Alright(lUseEventCuts[eReferenceMultiplicityEstimator]); + ec.fUseEventCuts[eSelectedEvents] = Alright(lUseEventCuts[eSelectedEvents]); // selected number of events (after all event cuts) + ec.fUseEventCuts[eNoSameBunchPileup] = Alright(lUseEventCuts[eNoSameBunchPileup]); + ec.fUseEventCuts[eIsGoodZvtxFT0vsPV] = Alright(lUseEventCuts[eIsGoodZvtxFT0vsPV]); + ec.fUseEventCuts[eIsVertexITSTPC] = Alright(lUseEventCuts[eIsVertexITSTPC]); + ec.fUseEventCuts[eIsVertexTOFmatched] = Alright(lUseEventCuts[eIsVertexTOFmatched]); + ec.fUseEventCuts[eIsVertexTRDmatched] = Alright(lUseEventCuts[eIsVertexTRDmatched]); + ec.fUseEventCuts[eNoCollInTimeRangeStrict] = Alright(lUseEventCuts[eNoCollInTimeRangeStrict]); + ec.fUseEventCuts[eNoCollInTimeRangeStandard] = Alright(lUseEventCuts[eNoCollInTimeRangeStandard]); + ec.fUseEventCuts[eNoCollInRofStrict] = Alright(lUseEventCuts[eNoCollInRofStrict]); + ec.fUseEventCuts[eNoCollInRofStandard] = Alright(lUseEventCuts[eNoCollInRofStandard]); + ec.fUseEventCuts[eNoHighMultCollInPrevRof] = Alright(lUseEventCuts[eNoHighMultCollInPrevRof]); + ec.fUseEventCuts[eIsGoodITSLayer3] = Alright(lUseEventCuts[eIsGoodITSLayer3]); + ec.fUseEventCuts[eIsGoodITSLayer0123] = Alright(lUseEventCuts[eIsGoodITSLayer0123]); + ec.fUseEventCuts[eIsGoodITSLayersAll] = Alright(lUseEventCuts[eIsGoodITSLayersAll]); + ec.fUseEventCuts[eOccupancyEstimator] = Alright(lUseEventCuts[eOccupancyEstimator]); + ec.fUseEventCuts[eMinVertexDistanceFromIP] = Alright(lUseEventCuts[eMinVertexDistanceFromIP]); + ec.fUseEventCuts[eNoPileupTPC] = Alright(lUseEventCuts[eNoPileupTPC]); + ec.fUseEventCuts[eNoPileupFromSPD] = Alright(lUseEventCuts[eNoPileupFromSPD]); + ec.fUseEventCuts[eNoSPDOnVsOfPileup] = Alright(lUseEventCuts[eNoSPDOnVsOfPileup]); + ec.fUseEventCuts[eRefMultVsNContrUp] = Alright(lUseEventCuts[eRefMultVsNContrUp]); + ec.fUseEventCuts[eRefMultVsNContrLow] = Alright(lUseEventCuts[eRefMultVsNContrLow]); + ec.fUseEventCuts[eCentralityCorrelationsCut] = Alright(lUseEventCuts[eCentralityCorrelationsCut]); + ec.fUseEventCuts[eCentralityWeights] = Alright(lUseEventCuts[eCentralityWeights]); + + // **) event cuts defined via booleans: + ec.fUseEventCuts[eSel7] = ec.fUseEventCuts[eSel7] && cf_ec.cfUseSel7; + ec.fUseEventCuts[eSel8] = ec.fUseEventCuts[eSel8] && cf_ec.cfUseSel8; + ec.fUseEventCuts[eNoSameBunchPileup] = ec.fUseEventCuts[eNoSameBunchPileup] && cf_ec.cfUseNoSameBunchPileup; + ec.fUseEventCuts[eIsGoodZvtxFT0vsPV] = ec.fUseEventCuts[eIsGoodZvtxFT0vsPV] && cf_ec.cfUseIsGoodZvtxFT0vsPV; + ec.fUseEventCuts[eIsVertexITSTPC] = ec.fUseEventCuts[eIsVertexITSTPC] && cf_ec.cfUseIsVertexITSTPC; + ec.fUseEventCuts[eIsVertexTOFmatched] = ec.fUseEventCuts[eIsVertexTOFmatched] && cf_ec.cfUseIsVertexTOFmatched; + ec.fUseEventCuts[eIsVertexTRDmatched] = ec.fUseEventCuts[eIsVertexTRDmatched] && cf_ec.cfUseIsVertexTRDmatched; + ec.fUseEventCuts[eNoCollInTimeRangeStrict] = ec.fUseEventCuts[eNoCollInTimeRangeStrict] && cf_ec.cfUseNoCollInTimeRangeStrict; + ec.fUseEventCuts[eNoCollInTimeRangeStandard] = ec.fUseEventCuts[eNoCollInTimeRangeStandard] && cf_ec.cfUseNoCollInTimeRangeStandard; + ec.fUseEventCuts[eNoCollInRofStrict] = ec.fUseEventCuts[eNoCollInRofStrict] && cf_ec.cfUseNoCollInRofStrict; + ec.fUseEventCuts[eNoCollInRofStandard] = ec.fUseEventCuts[eNoCollInRofStandard] && cf_ec.cfUseNoCollInRofStandard; + ec.fUseEventCuts[eNoHighMultCollInPrevRof] = ec.fUseEventCuts[eNoHighMultCollInPrevRof] && cf_ec.cfUseNoHighMultCollInPrevRof; + ec.fUseEventCuts[eIsGoodITSLayer3] = ec.fUseEventCuts[eIsGoodITSLayer3] && cf_ec.cfUseIsGoodITSLayer3; + ec.fUseEventCuts[eIsGoodITSLayer0123] = ec.fUseEventCuts[eIsGoodITSLayer0123] && cf_ec.cfUseIsGoodITSLayer0123; + ec.fUseEventCuts[eIsGoodITSLayersAll] = ec.fUseEventCuts[eIsGoodITSLayersAll] && cf_ec.cfUseIsGoodITSLayersAll; + ec.fUseEventCuts[eNoPileupTPC] = ec.fUseEventCuts[eNoPileupTPC] && cf_ec.cfUseNoPileupTPC; + ec.fUseEventCuts[eNoPileupFromSPD] = ec.fUseEventCuts[eNoPileupFromSPD] && cf_ec.cfUseNoPileupFromSPD; + ec.fUseEventCuts[eNoSPDOnVsOfPileup] = ec.fUseEventCuts[eNoSPDOnVsOfPileup] && cf_ec.cfUseNoSPDOnVsOfPileup; + ec.fUseEventCuts[eCentralityWeights] = ec.fUseEventCuts[eCentralityWeights] && cf_cw.cfUseCentralityWeights; + + // **) event cuts defined via [min, max): + // Remark: I use this one also for events cuts set only via min or via max. + // In this case, I set either min or max intentionally to some value which never can be met (see below example for "MinVertexDistanceFromIP") + auto lNumberOfEvents = (std::vector)cf_ec.cfNumberOfEvents; + ec.fdEventCuts[eNumberOfEvents][eMin] = lNumberOfEvents[eMin]; + ec.fdEventCuts[eNumberOfEvents][eMax] = lNumberOfEvents[eMax]; + + auto lTotalMultiplicity = (std::vector)cf_ec.cfTotalMultiplicity; + ec.fdEventCuts[eTotalMultiplicity][eMin] = lTotalMultiplicity[eMin]; + ec.fdEventCuts[eTotalMultiplicity][eMax] = lTotalMultiplicity[eMax]; + + auto lMultiplicity = (std::vector)cf_ec.cfMultiplicity; + ec.fdEventCuts[eMultiplicity][eMin] = lMultiplicity[eMin]; + ec.fdEventCuts[eMultiplicity][eMax] = lMultiplicity[eMax]; + // If I have requested fFixedNumberOfRandomlySelectedTracks, then I do not care about events with smaller number of particles: + if (tc.fFixedNumberOfRandomlySelectedTracks > 0) { + ec.fdEventCuts[eMultiplicity][eMin] = tc.fFixedNumberOfRandomlySelectedTracks; + } + + auto lReferenceMultiplicity = (std::vector)cf_ec.cfReferenceMultiplicity; + ec.fdEventCuts[eReferenceMultiplicity][eMin] = lReferenceMultiplicity[eMin]; + ec.fdEventCuts[eReferenceMultiplicity][eMax] = lReferenceMultiplicity[eMax]; + + auto lCentrality = (std::vector)cf_ec.cfCentrality; + ec.fdEventCuts[eCentrality][eMin] = lCentrality[eMin]; + ec.fdEventCuts[eCentrality][eMax] = lCentrality[eMax]; + + auto lVertexX = (std::vector)cf_ec.cfVertexX; + ec.fdEventCuts[eVertexX][eMin] = lVertexX[eMin]; + ec.fdEventCuts[eVertexX][eMax] = lVertexX[eMax]; + + auto lVertexY = (std::vector)cf_ec.cfVertexY; + ec.fdEventCuts[eVertexY][eMin] = lVertexY[eMin]; + ec.fdEventCuts[eVertexY][eMax] = lVertexY[eMax]; + + auto lVertexZ = (std::vector)cf_ec.cfVertexZ; + ec.fdEventCuts[eVertexZ][eMin] = lVertexZ[eMin]; + ec.fdEventCuts[eVertexZ][eMax] = lVertexZ[eMax]; + + auto lNContributors = (std::vector)cf_ec.cfNContributors; + ec.fdEventCuts[eNContributors][eMin] = lNContributors[eMin]; + ec.fdEventCuts[eNContributors][eMax] = lNContributors[eMax]; + + auto lImpactParameter = (std::vector)cf_ec.cfImpactParameter; + ec.fdEventCuts[eImpactParameter][eMin] = lImpactParameter[eMin]; + ec.fdEventCuts[eImpactParameter][eMax] = lImpactParameter[eMax]; + + auto lEventPlaneAngle = (std::vector)cf_ec.cfEventPlaneAngle; + ec.fdEventCuts[eEventPlaneAngle][eMin] = lEventPlaneAngle[eMin]; + ec.fdEventCuts[eEventPlaneAngle][eMax] = lEventPlaneAngle[eMax]; + + auto lOccupancy = (std::vector)cf_ec.cfOccupancy; + ec.fdEventCuts[eOccupancy][eMin] = lOccupancy[eMin]; + ec.fdEventCuts[eOccupancy][eMax] = lOccupancy[eMax]; + + auto lInteractionRate = (std::vector)cf_ec.cfInteractionRate; + ec.fdEventCuts[eInteractionRate][eMin] = lInteractionRate[eMin]; + ec.fdEventCuts[eInteractionRate][eMax] = lInteractionRate[eMax]; + + auto lCurrentRunDuration = (std::vector)cf_ec.cfCurrentRunDuration; + ec.fdEventCuts[eCurrentRunDuration][eMin] = lCurrentRunDuration[eMin]; + ec.fdEventCuts[eCurrentRunDuration][eMax] = lCurrentRunDuration[eMax]; + + auto lMultMCNParticlesEta08 = (std::vector)cf_ec.cfMultMCNParticlesEta08; + ec.fdEventCuts[eMultMCNParticlesEta08][eMin] = lMultMCNParticlesEta08[eMin]; + ec.fdEventCuts[eMultMCNParticlesEta08][eMax] = lMultMCNParticlesEta08[eMax]; + + auto lSelectedEvents = (std::vector)cf_ec.cfSelectedEvents; + ec.fdEventCuts[eSelectedEvents][eMin] = lSelectedEvents[eMin]; + ec.fdEventCuts[eSelectedEvents][eMax] = lSelectedEvents[eMax]; + + ec.fdEventCuts[eMinVertexDistanceFromIP][eMin] = cf_ec.cfMinVertexDistanceFromIP; // if vertex is closer to IP than this value, the event is rejected + ec.fdEventCuts[eMinVertexDistanceFromIP][eMax] = -1; // this value is never checked in any case + + // **) event cuts defined via string: + ec.fsEventCuts[eMultiplicityEstimator] = cf_ec.cfMultiplicityEstimator; + ec.fsEventCuts[eReferenceMultiplicityEstimator] = cf_ec.cfReferenceMultiplicityEstimator; + ec.fsEventCuts[eCentralityEstimator] = cf_ec.cfCentralityEstimator; + ec.fsEventCuts[eTrigger] = cf_ec.cfTrigger; + ec.fsEventCuts[eOccupancyEstimator] = cf_ec.cfOccupancyEstimator; + ec.fsEventCuts[eRefMultVsNContrUp] = cf_ec.cfRefMultVsNContrUp; + ec.fsEventCuts[eRefMultVsNContrLow] = cf_ec.cfRefMultVsNContrLow; + ec.fsEventCuts[eCentralityCorrelationsCut] = cf_ec.cfCentralityCorrelationsCut; + + // **) additional info for some specific event cuts, which I didn't enumerate in enum eEventCuts, to trim down bookeeping: + ec.fCentralityCorrelationsCutTreshold = cf_ec.cfCentralityCorrelationsCutTreshold; + ec.fCentralityCorrelationsCutVersion = cf_ec.cfCentralityCorrelationsCutVersion; + + // ---------------------------------------------------------------------- + + // b) Default particle cuts: + + // *) Use or do not use a cut enumerated in eParticleHistograms + eParticleCuts. + // Default cuts are set in configurable cfUseParticleCuts + auto lUseParticleCuts = (std::vector)cf_pc.cfUseParticleCuts; + if (lUseParticleCuts.size() != eParticleCuts_N) { + LOGF(info, "\033[1;31m lUseParticleCuts.size() = %d\033[0m", lUseParticleCuts.size()); + LOGF(info, "\033[1;31m eParticleCuts_N = %d\033[0m", static_cast(eParticleCuts_N)); + LOGF(fatal, "\033[1;31m%s at line %d : Mismatch in the number of flags in configurable cfUseParticleCuts, and number of entries in enum eParticleHistograms + eParticleCuts \n \033[0m", __FUNCTION__, __LINE__); + } + + // *) Insanity check on the content and ordering of particle cuts in the initialization in configurable cfUseParticleCuts: + // TBI 20240518 I do not need this in fact, I can automate initialization even without ordering in configurable, but it feels with the ordering enforced, it's much safer. + for (int name = 0; name < eParticleCuts_N; name++) { + // TBI 20240518 I could implement even a strickter EqualTo instead of EndsWith, but then I need to tokenize, etc., etc. This shall be safe enough. + if (!TString(lUseParticleCuts[name]).EndsWith(pc.fParticleCutName[name].Data())) { + LOGF(fatal, "\033[1;31m%s at line %d : Wrong content or ordering of contents in configurable cfUseParticleCuts => name = %d, lUseParticleCuts[name] = \"%s\", pc.fParticleCutName[name] = \"%s\" \033[0m", __FUNCTION__, __LINE__, name, TString(lUseParticleCuts[name]).Data(), pc.fParticleCutName[name].Data()); } } - // *) Insanity checks on booking: - // ... - - // *) Insanity checks on binning: - // ... + // *) from enum eParticleHistograms: + pc.fUseParticleCuts[ePhi] = Alright(lUseParticleCuts[ePhi]); + pc.fUseParticleCuts[ePt] = Alright(lUseParticleCuts[ePt]); + pc.fUseParticleCuts[eEta] = Alright(lUseParticleCuts[eEta]); + pc.fUseParticleCuts[eCharge] = Alright(lUseParticleCuts[eCharge]); + pc.fUseParticleCuts[etpcNClsFindable] = Alright(lUseParticleCuts[etpcNClsFindable]); + pc.fUseParticleCuts[etpcNClsShared] = Alright(lUseParticleCuts[etpcNClsShared]); + pc.fUseParticleCuts[eitsChi2NCl] = Alright(lUseParticleCuts[eitsChi2NCl]); + pc.fUseParticleCuts[etpcNClsFound] = Alright(lUseParticleCuts[etpcNClsFound]); + pc.fUseParticleCuts[etpcNClsCrossedRows] = Alright(lUseParticleCuts[etpcNClsCrossedRows]); + pc.fUseParticleCuts[eitsNCls] = Alright(lUseParticleCuts[eitsNCls]); + pc.fUseParticleCuts[eitsNClsInnerBarrel] = Alright(lUseParticleCuts[eitsNClsInnerBarrel]); + pc.fUseParticleCuts[etpcCrossedRowsOverFindableCls] = Alright(lUseParticleCuts[etpcCrossedRowsOverFindableCls]); + pc.fUseParticleCuts[etpcFoundOverFindableCls] = Alright(lUseParticleCuts[etpcFoundOverFindableCls]); + pc.fUseParticleCuts[etpcFractionSharedCls] = Alright(lUseParticleCuts[etpcFractionSharedCls]); + pc.fUseParticleCuts[etpcChi2NCl] = Alright(lUseParticleCuts[etpcChi2NCl]); + pc.fUseParticleCuts[edcaXY] = Alright(lUseParticleCuts[edcaXY]); + pc.fUseParticleCuts[edcaZ] = Alright(lUseParticleCuts[edcaZ]); + pc.fUseParticleCuts[ePDG] = Alright(lUseParticleCuts[ePDG]); + pc.fUseParticleCuts[etrackCutFlag] = Alright(lUseParticleCuts[etrackCutFlag]); + pc.fUseParticleCuts[etrackCutFlagFb1] = Alright(lUseParticleCuts[etrackCutFlagFb1]); + pc.fUseParticleCuts[etrackCutFlagFb2] = Alright(lUseParticleCuts[etrackCutFlagFb2]); + pc.fUseParticleCuts[eisQualityTrack] = Alright(lUseParticleCuts[eisQualityTrack]); + pc.fUseParticleCuts[eisPrimaryTrack] = Alright(lUseParticleCuts[eisPrimaryTrack]); + pc.fUseParticleCuts[eisInAcceptanceTrack] = Alright(lUseParticleCuts[eisInAcceptanceTrack]); + pc.fUseParticleCuts[eisGlobalTrack] = Alright(lUseParticleCuts[eisGlobalTrack]); + pc.fUseParticleCuts[eisPVContributor] = Alright(lUseParticleCuts[eisPVContributor]); + pc.fUseParticleCuts[ePtDependentDCAxyParameterization] = Alright(lUseParticleCuts[ePtDependentDCAxyParameterization]); + + // **) particles cuts defined via booleans: + pc.fUseParticleCuts[etrackCutFlag] = pc.fUseParticleCuts[etrackCutFlag] && cf_pc.cftrackCutFlag; + pc.fUseParticleCuts[etrackCutFlagFb1] = pc.fUseParticleCuts[etrackCutFlagFb1] && cf_pc.cftrackCutFlagFb1; + pc.fUseParticleCuts[etrackCutFlagFb2] = pc.fUseParticleCuts[etrackCutFlagFb2] && cf_pc.cftrackCutFlagFb2; + pc.fUseParticleCuts[eisQualityTrack] = pc.fUseParticleCuts[eisQualityTrack] && cf_pc.cfisQualityTrack; + pc.fUseParticleCuts[eisPrimaryTrack] = pc.fUseParticleCuts[eisPrimaryTrack] && cf_pc.cfisPrimaryTrack; + pc.fUseParticleCuts[eisInAcceptanceTrack] = pc.fUseParticleCuts[eisInAcceptanceTrack] && cf_pc.cfisInAcceptanceTrack; + pc.fUseParticleCuts[eisGlobalTrack] = pc.fUseParticleCuts[eisGlobalTrack] && cf_pc.cfisGlobalTrack; + pc.fUseParticleCuts[eisPVContributor] = pc.fUseParticleCuts[eisPVContributor] && cf_pc.cfisPVContributor; + + // **) particles cuts defined via [min, max): + auto lPhi = (std::vector)cf_pc.cfPhi; + pc.fdParticleCuts[ePhi][eMin] = lPhi[eMin]; + pc.fdParticleCuts[ePhi][eMax] = lPhi[eMax]; + + auto lPt = (std::vector)cf_pc.cfPt; + pc.fdParticleCuts[ePt][eMin] = lPt[eMin]; + pc.fdParticleCuts[ePt][eMax] = lPt[eMax]; + + auto lEta = (std::vector)cf_pc.cfEta; + pc.fdParticleCuts[eEta][eMin] = lEta[eMin]; + pc.fdParticleCuts[eEta][eMax] = lEta[eMax]; + + auto lCharge = (std::vector)cf_pc.cfCharge; + pc.fdParticleCuts[eCharge][eMin] = lCharge[eMin]; + pc.fdParticleCuts[eCharge][eMax] = lCharge[eMax]; + + auto ltpcNClsFindable = (std::vector)cf_pc.cftpcNClsFindable; + pc.fdParticleCuts[etpcNClsFindable][eMin] = ltpcNClsFindable[eMin]; + pc.fdParticleCuts[etpcNClsFindable][eMax] = ltpcNClsFindable[eMax]; + + auto ltpcNClsShared = (std::vector)cf_pc.cftpcNClsShared; + pc.fdParticleCuts[etpcNClsShared][eMin] = ltpcNClsShared[eMin]; + pc.fdParticleCuts[etpcNClsShared][eMax] = ltpcNClsShared[eMax]; + + auto litsChi2NCl = (std::vector)cf_pc.cfitsChi2NCl; + pc.fdParticleCuts[eitsChi2NCl][eMin] = litsChi2NCl[eMin]; + pc.fdParticleCuts[eitsChi2NCl][eMax] = litsChi2NCl[eMax]; + + auto ltpcNClsFound = (std::vector)cf_pc.cftpcNClsFound; + pc.fdParticleCuts[etpcNClsFound][eMin] = ltpcNClsFound[eMin]; + pc.fdParticleCuts[etpcNClsFound][eMax] = ltpcNClsFound[eMax]; + + auto ltpcNClsCrossedRows = (std::vector)cf_pc.cftpcNClsCrossedRows; + pc.fdParticleCuts[etpcNClsCrossedRows][eMin] = ltpcNClsCrossedRows[eMin]; + pc.fdParticleCuts[etpcNClsCrossedRows][eMax] = ltpcNClsCrossedRows[eMax]; + + auto litsNCls = (std::vector)cf_pc.cfitsNCls; + pc.fdParticleCuts[eitsNCls][eMin] = litsNCls[eMin]; + pc.fdParticleCuts[eitsNCls][eMax] = litsNCls[eMax]; + + auto litsNClsInnerBarrel = (std::vector)cf_pc.cfitsNClsInnerBarrel; + pc.fdParticleCuts[eitsNClsInnerBarrel][eMin] = litsNClsInnerBarrel[eMin]; + pc.fdParticleCuts[eitsNClsInnerBarrel][eMax] = litsNClsInnerBarrel[eMax]; + + auto ltpcCrossedRowsOverFindableCls = (std::vector)cf_pc.cftpcCrossedRowsOverFindableCls; + pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMin] = ltpcCrossedRowsOverFindableCls[eMin]; + pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMax] = ltpcCrossedRowsOverFindableCls[eMax]; + + auto ltpcFoundOverFindableCls = (std::vector)cf_pc.cftpcFoundOverFindableCls; + pc.fdParticleCuts[etpcFoundOverFindableCls][eMin] = ltpcFoundOverFindableCls[eMin]; + pc.fdParticleCuts[etpcFoundOverFindableCls][eMax] = ltpcFoundOverFindableCls[eMax]; + + auto ltpcFractionSharedCls = (std::vector)cf_pc.cftpcFractionSharedCls; + pc.fdParticleCuts[etpcFractionSharedCls][eMin] = ltpcFractionSharedCls[eMin]; + pc.fdParticleCuts[etpcFractionSharedCls][eMax] = ltpcFractionSharedCls[eMax]; + + auto ltpcChi2NCl = (std::vector)cf_pc.cftpcChi2NCl; + pc.fdParticleCuts[etpcChi2NCl][eMin] = ltpcChi2NCl[eMin]; + pc.fdParticleCuts[etpcChi2NCl][eMax] = ltpcChi2NCl[eMax]; + + auto ldcaXY = (std::vector)cf_pc.cfdcaXY; + pc.fdParticleCuts[edcaXY][eMin] = ldcaXY[eMin]; + pc.fdParticleCuts[edcaXY][eMax] = ldcaXY[eMax]; + + auto ldcaZ = (std::vector)cf_pc.cfdcaZ; + pc.fdParticleCuts[edcaZ][eMin] = ldcaZ[eMin]; + pc.fdParticleCuts[edcaZ][eMax] = ldcaZ[eMax]; + + auto lPDG = (std::vector)cf_pc.cfPDG; + pc.fdParticleCuts[ePDG][eMin] = lPDG[eMin]; + pc.fdParticleCuts[ePDG][eMax] = lPDG[eMax]; + + // **) particles cuts defined via string: + pc.fsParticleCuts[ePtDependentDCAxyParameterization] = cf_pc.cfPtDependentDCAxyParameterization; - // *) Insanity checks on cuts: - // ... + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } -} // void InsanityChecks() +} // void DefaultCuts() //============================================================ -void BookAndNestAllLists() +void SpecificCuts(TString whichSpecificCuts) { - // *) QA; - // *) Control event histograms; - // *) Control particle histograms; - // *) Correlations; - // *) Q-vectors; - // *) Particle weights; - // *) Nested loops; - // *) Test0; - // *) Results. + // After default cuts are applied, on top of them apply analysis-specific cuts. Has to be called after DefaultBinning() and DefaultCuts(). + // Here I hardwire defalt cuts and settings for a given period which will overwrite whatever is set in configurables. + // When I do systematic checks, this option shall NOT be used, because values for some cuts which I plan to vary, are also hardwired here. + // Both event and particle cuts are hardwired here. As well as some other settings. + // For the time being, all specific cuts are defaulted and tuned for the latest reconstruction pass. + + // a) Mapping; + // b) Implementation of analysis-specific cuts. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); - } + StartFunction(__FUNCTION__); + } + + // a) Mapping: + // I need this mapping, for the switch statement below. TBI 20241120 I could introduce a utility function for this as well... + eSpecificCuts specificCuts = eSpecificCuts_N; + if (whichSpecificCuts.EqualTo("LHC23zzh")) { + specificCuts = eLHC23zzh; + } else if (whichSpecificCuts.EqualTo("LHC24ar")) { + specificCuts = eLHC24ar; + } else if (whichSpecificCuts.EqualTo("LHC24as")) { + specificCuts = eLHC24as; + } else if (whichSpecificCuts.EqualTo("LHC15o")) { + specificCuts = eLHC15o; + } else if (whichSpecificCuts.EqualTo("Test")) { + specificCuts = eTestCuts; + } else { + LOGF(fatal, "\033[1;31m%s at line %d : whichSpecificCuts = %s is not supported \033[0m", __FUNCTION__, __LINE__, whichSpecificCuts.Data()); + } + + // b) Implementation of analysis-specific cuts: + // Remark #1: Whichever cuts start to repeat below across different case statements, promote them into DefaultCuts(), i.e. hardwire those values in configurables. + // The idea is to keep here cuts only which are specific for particular analysis, and which are unlikely ever to change as a default cut for that particular analysis. + // Remark #2: Remember that the values for the cuts hardwired here overwrite the ones set as default values in configurables. + // If you want to reconfigure all cuts below manually via configurables, simply do not call SpecificCuts, i.e. set in JSON "cfUseSpecificCuts": "false" + // Therefore, if I want to vary some of these cuts via configurables as a part of systematics, I must set in JSON "cfUseSpecificCuts": "false" + // Remark #3: Most up-to-date documentation of each cut is in enum file. + switch (specificCuts) { + + case eLHC23zzh: { + + // In this branch I implement default cuts and settings for PbPb Run 3 datasets collected in 2023. + // If I change some cut here, keep in sync. with other branches (e.g. for 2024 data). + + // Event cuts: + ec.fUseEventCuts[eSel7] = false; + ec.fUseEventCuts[eSel8] = true; + ec.fUseEventCuts[eNoSameBunchPileup] = true; + ec.fUseEventCuts[eIsVertexITSTPC] = true; + ec.fUseEventCuts[eNoCollInTimeRangeStandard] = true; + ec.fUseEventCuts[eNoCollInTimeRangeStrict] = false; + ec.fUseEventCuts[eNoCollInRofStandard] = true; + ec.fUseEventCuts[eNoCollInRofStrict] = false; + ec.fUseEventCuts[eNoPileupTPC] = false; // Run 2 + ec.fUseEventCuts[eNoPileupFromSPD] = false; // Run 2 + ec.fUseEventCuts[eNoSPDOnVsOfPileup] = false; // Run 2 + + ec.fUseEventCuts[eInteractionRate] = true; + ec.fdEventCuts[eInteractionRate][eMin] = 0.1; // there are some pathological non-physical events with IR = 0. See eCorrelationsVsInteractionRate_vs_ReferenceMultiplicity + ec.fdEventCuts[eInteractionRate][eMax] = 1000000000.; + + ec.fUseEventCuts[eRefMultVsNContrUp] = true; + ec.fUseEventCuts[eRefMultVsNContrLow] = true; + if (ec.fsEventCuts[eReferenceMultiplicityEstimator].EqualTo("MultFT0C")) { + ec.fsEventCuts[eRefMultVsNContrUp] = "1200. + 0.20*x"; // TBI 20250401 not fine-tune, just an example + ec.fsEventCuts[eRefMultVsNContrLow] = "-650. + 0.08*x"; // TBI 20250401 not fine-tune, just an example + // TBI 20250331 fine-tune this cut in the same spirit for other ref. mult. estimators + } - // *) QA: - qa.fQAList = new TList(); - qa.fQAList->SetName("QA"); - qa.fQAList->SetOwner(kTRUE); - fBaseList->Add(qa.fQAList); + ec.fUseEventCuts[eCentralityCorrelationsCut] = true; + ec.fsEventCuts[eCentralityCorrelationsCut] = "CentFT0C_CentFT0M"; + ec.fCentralityCorrelationsCutTreshold = 10.0; + ec.fCentralityCorrelationsCutVersion = "Absolute"; - // *) Control event histograms: - eh.fEventHistogramsList = new TList(); - eh.fEventHistogramsList->SetName("EventHistograms"); - eh.fEventHistogramsList->SetOwner(kTRUE); - fBaseList->Add(eh.fEventHistogramsList); + // Particle cuts: + pc.fUseParticleCuts[eitsNCls] = true; + pc.fdParticleCuts[eitsNCls][eMin] = 5.; + pc.fdParticleCuts[eitsNCls][eMax] = 1000.; - // *) Event cuts: - ec.fEventCutsList = new TList(); - ec.fEventCutsList->SetName("EventCuts"); - ec.fEventCutsList->SetOwner(kTRUE); - fBaseList->Add(ec.fEventCutsList); + pc.fUseParticleCuts[etpcNClsFound] = true; + pc.fdParticleCuts[etpcNClsFound][eMin] = 70.; + pc.fdParticleCuts[etpcNClsFound][eMax] = 1000.; - // *) Control particle histograms: - ph.fParticleHistogramsList = new TList(); - ph.fParticleHistogramsList->SetName("ParticleHistograms"); - ph.fParticleHistogramsList->SetOwner(kTRUE); - fBaseList->Add(ph.fParticleHistogramsList); + pc.fUseParticleCuts[etpcNClsCrossedRows] = true; + pc.fdParticleCuts[etpcNClsCrossedRows][eMin] = 70.; + pc.fdParticleCuts[etpcNClsCrossedRows][eMax] = 1000.; - // *) Particle cuts: - pc.fParticleCutsList = new TList(); - pc.fParticleCutsList->SetName("ParticleCuts"); - pc.fParticleCutsList->SetOwner(kTRUE); - fBaseList->Add(pc.fParticleCutsList); + pc.fUseParticleCuts[etpcCrossedRowsOverFindableCls] = true; + pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMin] = 0.8; + pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMax] = 1000.; - // *) Q-vectors: - qv.fQvectorList = new TList(); - qv.fQvectorList->SetName("Q-vectors"); - qv.fQvectorList->SetOwner(kTRUE); - fBaseList->Add(qv.fQvectorList); + pc.fUseParticleCuts[etpcFoundOverFindableCls] = true; + pc.fdParticleCuts[etpcFoundOverFindableCls][eMin] = 0.8; + pc.fdParticleCuts[etpcFoundOverFindableCls][eMax] = 1000.; - // *) Correlations: - mupa.fCorrelationsList = new TList(); - mupa.fCorrelationsList->SetName("Correlations"); - mupa.fCorrelationsList->SetOwner(kTRUE); - fBaseList->Add(mupa.fCorrelationsList); + pc.fUseParticleCuts[etpcFractionSharedCls] = true; + pc.fdParticleCuts[etpcFractionSharedCls][eMin] = -1000.; + pc.fdParticleCuts[etpcFractionSharedCls][eMax] = 0.4; - // *) Particle weights: - pw.fWeightsList = new TList(); - pw.fWeightsList->SetName("Weights"); - pw.fWeightsList->SetOwner(kTRUE); - fBaseList->Add(pw.fWeightsList); + pc.fUseParticleCuts[etpcChi2NCl] = true; + pc.fdParticleCuts[etpcChi2NCl][eMin] = -1000.; + pc.fdParticleCuts[etpcChi2NCl][eMax] = 4.0; - // *) Nested loops: - nl.fNestedLoopsList = new TList(); - nl.fNestedLoopsList->SetName("NestedLoops"); - nl.fNestedLoopsList->SetOwner(kTRUE); - fBaseList->Add(nl.fNestedLoopsList); + pc.fUseParticleCuts[edcaXY] = true; + pc.fdParticleCuts[edcaXY][eMin] = -2.4; // TBI 20250401 check further + pc.fdParticleCuts[edcaXY][eMax] = 2.4; // TBI 20250401 check further - // *) Test0: - t0.fTest0List = new TList(); - t0.fTest0List->SetName("Test0"); - t0.fTest0List->SetOwner(kTRUE); - fBaseList->Add(t0.fTest0List); + pc.fUseParticleCuts[edcaZ] = true; + pc.fdParticleCuts[edcaZ][eMin] = -3.2; // TBI 20250401 check further + pc.fdParticleCuts[edcaZ][eMax] = 3.2; // TBI 20250401 check further - // *) Results: - res.fResultsList = new TList(); - res.fResultsList->SetName("Results"); - res.fResultsList->SetOwner(kTRUE); - fBaseList->Add(res.fResultsList); + pc.fUseParticleCuts[eisInAcceptanceTrack] = false; // see enum + pc.fUseParticleCuts[eisGlobalTrack] = false; // only for Run 2 + pc.fUseParticleCuts[eisPVContributor] = true; -} // void BookAndNestAllLists() + break; + } -//============================================================ + case eLHC24ar: + case eLHC24as: { + + // In this branch I implement default cuts and settings for PbPb Run 3 datasets collected in 2024: + // If I change some cut here, keep in sync. with other branches (e.g. for 2023 data). + // As of 20250207, all cuts are the same as for 2023, expect that here I do NOT use eIsGoodZvtxFT0vsPV and eNoHighMultCollInPrevRof + + // Event cuts: + ec.fUseEventCuts[eSel7] = false; + ec.fUseEventCuts[eSel8] = true; + ec.fUseEventCuts[eNoSameBunchPileup] = true; + ec.fUseEventCuts[eIsVertexITSTPC] = true; + ec.fUseEventCuts[eNoCollInTimeRangeStandard] = true; + ec.fUseEventCuts[eNoCollInTimeRangeStrict] = false; + ec.fUseEventCuts[eNoCollInRofStandard] = true; + ec.fUseEventCuts[eNoCollInRofStrict] = false; + ec.fUseEventCuts[eIsGoodZvtxFT0vsPV] = false; // diff commpared to 2023 + ec.fUseEventCuts[eNoHighMultCollInPrevRof] = false; // diff commpared to 2023 + ec.fUseEventCuts[eNoPileupTPC] = false; // Run 2 + ec.fUseEventCuts[eNoPileupFromSPD] = false; // Run 2 + ec.fUseEventCuts[eNoSPDOnVsOfPileup] = false; // Run 2 + + ec.fUseEventCuts[eInteractionRate] = true; + ec.fdEventCuts[eInteractionRate][eMin] = 0.1; // there are some pathological non-physical events with IR = 0. See eCorrelationsVsInteractionRate_vs_ReferenceMultiplicity + ec.fdEventCuts[eInteractionRate][eMax] = 1000000000.; + + ec.fUseEventCuts[eRefMultVsNContrUp] = false; // TBI 20250331 set to true only when I fine-tune + ec.fUseEventCuts[eRefMultVsNContrLow] = false; // TBI 20250331 set to true only when I fine-tune + if (ec.fsEventCuts[eReferenceMultiplicityEstimator].EqualTo("MultFT0C")) { + ec.fsEventCuts[eRefMultVsNContrUp] = "..."; // TBI 20250329 I need to tune and validate for this dataset, and estimator + ec.fsEventCuts[eRefMultVsNContrLow] = "..."; // TBI 20250329 I need to tune and validate for this dataset, and estimator + // TBI 20250331 fine-tune this cut in the same spirit for other ref. mult. estimators + } -void BookEventHistograms() -{ - // Book all event histograms. + ec.fUseEventCuts[eCentralityCorrelationsCut] = false; // TBI 20250104 yes, because in 2024 I can use only FT0C at the moment + ec.fsEventCuts[eCentralityCorrelationsCut] = "CentFT0C_CentFT0M"; + ec.fCentralityCorrelationsCutTreshold = 10.0; + ec.fCentralityCorrelationsCutVersion = "Absolute"; - // a) Book the profile holding flags; - // b) Book specific event histograms. + // Particle cuts: + pc.fUseParticleCuts[eitsNCls] = true; + pc.fdParticleCuts[eitsNCls][eMin] = 5.; + pc.fdParticleCuts[eitsNCls][eMax] = 1000.; - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); - } + pc.fUseParticleCuts[etpcNClsFound] = true; + pc.fdParticleCuts[etpcNClsFound][eMin] = 70.; + pc.fdParticleCuts[etpcNClsFound][eMax] = 1000.; - // a) Book the profile holding flags: - eh.fEventHistogramsPro = new TProfile("fEventHistogramsPro", - "flags for event histograms", 25, 0., 25.); - eh.fEventHistogramsPro->SetStats(kFALSE); - eh.fEventHistogramsPro->SetLineColor(eColor); - eh.fEventHistogramsPro->SetFillColor(eFillColor); - // ... - eh.fEventHistogramsList->Add(eh.fEventHistogramsPro); + pc.fUseParticleCuts[etpcNClsCrossedRows] = true; + pc.fdParticleCuts[etpcNClsCrossedRows][eMin] = 70.; + pc.fdParticleCuts[etpcNClsCrossedRows][eMax] = 1000.; - Int_t fBeforeAfterColor[2] = { - kRed, - kGreen}; //! [0 = kRed,1 = kGreen] TBI 20220713 only temporarily here + pc.fUseParticleCuts[etpcCrossedRowsOverFindableCls] = true; + pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMin] = 0.8; + pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMax] = 1000.; - // b) Book specific control event histograms: - TString stype[eEventHistograms_N] = { - "NumberOfEvents", "TotalMultiplicity", "SelectedTracks", "MultFV0M", "MultFT0M", "MultTPC", "MultNTracksPV", - "Centrality", "Vertex_x", "Vertex_y", - "Vertex_z", "NContributors", "ImpactParameter"}; // keep in sync. with enum eEventHistograms - TString srs[2] = {"rec", "sim"}; - TString sba[2] = {"before", "after"}; + pc.fUseParticleCuts[etpcFoundOverFindableCls] = true; + pc.fdParticleCuts[etpcFoundOverFindableCls][eMin] = 0.8; + pc.fdParticleCuts[etpcFoundOverFindableCls][eMax] = 1000.; - for (Int_t t = 0; t < eEventHistograms_N; - t++) // type, see enum eEventHistograms - { - if (!eh.fBookEventHistograms[t]) { - continue; + pc.fUseParticleCuts[etpcFractionSharedCls] = true; + pc.fdParticleCuts[etpcFractionSharedCls][eMin] = -1000.; + pc.fdParticleCuts[etpcFractionSharedCls][eMax] = 0.4; + + pc.fUseParticleCuts[etpcChi2NCl] = true; + pc.fdParticleCuts[etpcChi2NCl][eMin] = -1000.; + pc.fdParticleCuts[etpcChi2NCl][eMax] = 4.0; + + pc.fUseParticleCuts[edcaXY] = true; + pc.fdParticleCuts[edcaXY][eMin] = -2.4; // TBI 20250401 check further + pc.fdParticleCuts[edcaXY][eMax] = 2.4; // TBI 20250401 check further + + pc.fUseParticleCuts[edcaZ] = true; + pc.fdParticleCuts[edcaZ][eMin] = -3.2; // TBI 20250401 check further + pc.fdParticleCuts[edcaZ][eMax] = 3.2; // TBI 20250401 check further + + pc.fUseParticleCuts[eisInAcceptanceTrack] = false; // see enum + pc.fUseParticleCuts[eisGlobalTrack] = false; // only for Run 2 + pc.fUseParticleCuts[eisPVContributor] = true; + + break; } - for (Int_t rs = 0; rs < 2; rs++) // reco/sim - { - // If I am analyzing only reconstructed data, do not book histos for simulated, and vice versa. - // TBI 20240223 tc.fProcessTest is treated as tc.fProcessRec, for the time being - if ((tc.fGenericRec && rs == eSim) || (tc.fGenericSim && rs == eRec)) { - continue; + + case eLHC15o: { + + // In this branch I implement default cuts and settings for Run 2 datasets: + + // Event cuts: + ec.fUseEventCuts[eOccupancy] = false; + ec.fUseEventCuts[eInteractionRate] = false; + ec.fUseEventCuts[eCurrentRunDuration] = false; + // ec.fUseEventCuts[eSel7] = true; // TBI 20250115 ehen i procees in "Rec" some converted Run 2 MC, it removes 99% of events, see enum + ec.fUseEventCuts[eSel8] = false; + ec.fUseEventCuts[eNoSameBunchPileup] = false; + ec.fUseEventCuts[eIsGoodZvtxFT0vsPV] = false; + ec.fUseEventCuts[eIsVertexITSTPC] = false; + ec.fUseEventCuts[eNoCollInTimeRangeStrict] = false; + ec.fUseEventCuts[eNoCollInRofStrict] = false; + ec.fUseEventCuts[eNoHighMultCollInPrevRof] = false; + ec.fUseEventCuts[eNoCollInTimeRangeStandard] = false; + ec.fUseEventCuts[eNoCollInRofStrict] = false; + ec.fUseEventCuts[eNoCollInRofStandard] = false; + ec.fUseEventCuts[eNoCollInRofStandard] = false; + ec.fUseEventCuts[eIsGoodITSLayer3] = false; + ec.fUseEventCuts[eIsGoodITSLayer0123] = false; + ec.fUseEventCuts[eIsGoodITSLayersAll] = false; + + ec.fUseEventCuts[eTrigger] = true; + ec.fsEventCuts[eTrigger] = "kINT7"; // TBI 20250115 remember that it cannot be used when i procees in "Rec" some converted Run 2 MC, see enum + + ec.fsEventCuts[eReferenceMultiplicityEstimator] = "MultTracklets"; // default ref. mult. estimator in Run 2 + ec.fsEventCuts[eCentralityEstimator] = "CentRun2V0M"; // default centrality estimator in Run 2 + + ec.fUseEventCuts[eRefMultVsNContrUp] = true; + ec.fUseEventCuts[eRefMultVsNContrLow] = true; + if (ec.fsEventCuts[eReferenceMultiplicityEstimator].EqualTo("MultTracklets")) { + ec.fsEventCuts[eRefMultVsNContrUp] = "700. + 0.95*x"; // TBI 20250401 not fine-tune, just an example + ec.fsEventCuts[eRefMultVsNContrLow] = "-400. + 0.5*x"; // TBI 20250401 not fine-tune, just an example + // TBI 20250331 fine-tune this cut in the same spirit for other ref. mult. estimators } - for (Int_t ba = 0; ba < 2; ba++) // before/after cuts - { - eh.fEventHistograms[t][rs][ba] = new TH1D( - Form("fEventHistograms[%s][%s][%s]", stype[t].Data(), - srs[rs].Data(), sba[ba].Data()), - Form("%s, %s, %s", stype[t].Data(), srs[rs].Data(), sba[ba].Data()), - (Int_t)eh.fEventHistogramsBins[t][0], - eh.fEventHistogramsBins[t][1], eh.fEventHistogramsBins[t][2]); - eh.fEventHistograms[t][rs][ba]->SetLineColor(fBeforeAfterColor[ba]); - eh.fEventHistograms[t][rs][ba]->SetFillColor(fBeforeAfterColor[ba] - - 10); - eh.fEventHistogramsList->Add(eh.fEventHistograms[t][rs][ba]); - } // for(Int_t ba=0;ba<2;ba++) - } // for(Int_t rs=0;rs<2;rs++) // reco/sim - } // for(Int_t t=0;tSetStats(kFALSE); - ec.fEventCutsPro->SetLineColor(eColor); - ec.fEventCutsPro->SetFillColor(eFillColor); + // ec.fUseEventCuts[eTrigger] = true; + // ec.fsEventCuts[eTrigger] = "kINT7"; // TBI 20250115 cannot be used when i procees in "Rec" some converted Run 2 MC, see enum - ec.fEventCutsPro->GetXaxis()->SetBinLabel(eTrigger, Form("fTrigger = %s", ec.fTrigger.Data())); - ec.fEventCutsPro->GetXaxis()->SetBinLabel(eUseTrigger, "fUseTrigger"); - ec.fEventCutsPro->Fill(+eUseTrigger - 0.5, (Int_t)ec.fUseTrigger); - ec.fEventCutsPro->GetXaxis()->SetBinLabel(eUseSel7, "fUseSel7"); - ec.fEventCutsPro->Fill(+eUseSel7 - 0.5, (Int_t)ec.fUseSel7); - ec.fEventCutsPro->GetXaxis()->SetBinLabel(eUseSel8, "fUseSel8"); - ec.fEventCutsPro->Fill(+eUseSel8 - 0.5, (Int_t)ec.fUseSel8); - ec.fEventCutsPro->GetXaxis()->SetBinLabel(eCentralityEstimator, Form("fCentralityEstimator = %s", ec.fCentralityEstimator.Data())); + // ... - ec.fEventCutsList->Add(ec.fEventCutsPro); + // Particle cuts: + pc.fUseParticleCuts[eisInAcceptanceTrack] = false; // see enum + pc.fUseParticleCuts[etrackCutFlagFb1] = false; // only for Run 3 + pc.fUseParticleCuts[etrackCutFlagFb2] = false; // only for Run 3 + pc.fUseParticleCuts[eisPVContributor] = false; // only for Run 3 -} // void BookEventCutsHistograms() + // ... + + // The rest: + mupa.fCalculateCorrelationsAsFunctionOf[AFO_OCCUPANCY] = false; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_INTERACTIONRATE] = false; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_CURRENTRUNDURATION] = false; + + t0.fCalculateTest0AsFunctionOf[AFO_OCCUPANCY] = false; + t0.fCalculateTest0AsFunctionOf[AFO_INTERACTIONRATE] = false; + t0.fCalculateTest0AsFunctionOf[AFO_CURRENTRUNDURATION] = false; + + es.fCalculateEtaSeparationsAsFunctionOf[AFO_OCCUPANCY] = false; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_INTERACTIONRATE] = false; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_CURRENTRUNDURATION] = false; + + // ... + + break; + } + + default: { + LOGF(fatal, "\033[1;31m%s at line %d : specificCuts = %d is not supported yet \033[0m", __FUNCTION__, __LINE__, static_cast(specificCuts)); + break; + } + } // switch (specificCuts) + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void SpecificCuts(const char* specificCutsName) //============================================================ -void BookParticleHistograms() +void InsanityChecksOnDefinitionsOfConfigurables() { - // Book all particle histograms. - - // a) Book the profile holding flags; - // b) Book specific particle histograms. + // Do insanity checks on values obtained from configurables before using them in the remaining function. + // This is really important, because one misconfigured configurable (e.g. boolean set to string), causes the whole json config to die silently, and + // only default values from MuPa-Configurables.h are used. + // Here I only check if configurables are correctly defined, I do NOT here initialize local variables with configurables, that is done later. + // Example misconfiguration in JSON: + // "var": "true", => var = 1 + other configurables are processed correctly + // "var": "truee", => var = 0 + all settings in JSON for configurables are ingored silently + + // TBI 20241127 finalize this function eventually. This is not urgent, though, as only a check below on cfTaskIsConfiguredFromJson covers most cases already. + + // Remark: Ordering below reflects the ordering in Configurables.h, not in DataMembers.h + // a) Task configuration; + // b) QA; + // c) Event histograms; + // d) Event cuts; + // e) Particle histograms; + // f) Particle cuts; + // g) Q-vectors; + // h) Multiparticle correlations; + // i) Test0; + // j) Particle weights; + // k) Centrality weights; + // l) Nested loops; + // m) Toy NUA; + // n) Internal validation; + // o) Results histograms. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); } - // a) Book the profile holding flags: - ph.fParticleHistogramsPro = new TProfile( - "fParticleHistogramsPro", "flags for particle histograms", 25, 0., 25.); - ph.fParticleHistogramsPro->SetStats(kFALSE); - ph.fParticleHistogramsPro->SetLineColor(eColor); - ph.fParticleHistogramsPro->SetFillColor(eFillColor); + // a) Task configuration: + if (!TString(cf_tc.cfTaskIsConfiguredFromJson).EqualTo("yes")) { + LOGF(fatal, "\033[1;31m%s at line %d : configurable cfTaskIsConfiguredFromJson = \"%s\", but it has to be set to \"yes\" in JSON => most likely some other configurable is misconfigured and all remaining settings in JSON are ignored silently\033[0m", __FUNCTION__, __LINE__, TString(cf_tc.cfTaskIsConfiguredFromJson).Data()); + } + + // b) QA: // ... - ph.fParticleHistogramsList->Add(ph.fParticleHistogramsPro); - Int_t fBeforeAfterColor[2] = { - kRed, - kGreen}; //! [0 = kRed,1 = kGreen] TBI 20220713 only temporarily here + // c) Event histograms: + // ... - // b) Book specific control particle histograms: - TString stype[eParticleHistograms_N] = { - "Phi", "Pt", "Eta", "tpcNClsCrossedRows", - "DCA_xy", "DCA_z", "PDG"}; // keep in sync. with enum eParticleHistograms - TString srs[2] = {"rec", "sim"}; - TString sba[2] = {"before", "after"}; + // d) Event cuts: + // ... - for (Int_t t = 0; t < eParticleHistograms_N; - t++) // type, see enum eParticleHistograms - { - if (!ph.fBookParticleHistograms[t]) { - continue; - } - for (Int_t rs = 0; rs < 2; rs++) // reco/sim - { - if ((tc.fGenericRec && rs == eSim) || (tc.fGenericSim && rs == eRec)) { - continue; // if I am analyzing only reconstructed data, do not book histos for simulated, and vice versa. - } - for (Int_t ba = 0; ba < 2; ba++) // before/after cuts - { - ph.fParticleHistograms[t][rs][ba] = new TH1D( - Form("fParticleHistograms[%s][%s][%s]", stype[t].Data(), - srs[rs].Data(), sba[ba].Data()), - Form("%s, %s, %s", stype[t].Data(), srs[rs].Data(), sba[ba].Data()), - (Int_t)ph.fParticleHistogramsBins[t][0], - ph.fParticleHistogramsBins[t][1], - ph.fParticleHistogramsBins[t][2]); - ph.fParticleHistograms[t][rs][ba]->SetLineColor( - fBeforeAfterColor[ba]); - ph.fParticleHistograms[t][rs][ba]->SetFillColor( - fBeforeAfterColor[ba] - 10); - ph.fParticleHistogramsList->Add(ph.fParticleHistograms[t][rs][ba]); - } // for(Int_t ba=0;ba<2;ba++) - } // for(Int_t rs=0;rs<2;rs++) // reco/sim - } // for(Int_t t=0;tSetStats(kFALSE); - pc.fParticleCutsPro->SetLineColor(eColor); - pc.fParticleCutsPro->SetFillColor(eFillColor); + // k) Centrality weights: + // ... - pc.fParticleCutsPro->GetXaxis()->SetBinLabel(eTBI, "TBI"); + // l) Nested loops: // ... - pc.fParticleCutsList->Add(pc.fParticleCutsPro); + // m) Toy NUA: + // ... -} // void BookParticleCutsHistograms() + // n) Internal validation: + // ... + + // o) Results histograms: + // ... + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // InsanityChecksOnDefinitionsOfConfigurables() //============================================================ -void BookQvectorHistograms() +void InsanityChecksBeforeBooking() { - // Book all Q-vector histograms. + // Do insanity checks on configuration, binning and cuts. Values obtained from configurables are checked before being used in InsanityChecksOnDefinitionsOfConfigurables(). + // Remember that here I cannot do insanity checks on local histograms, etc., because they are not booked yet. + // For those additional checks, use InsanityChecksAfterBooking(). - // a) Book the profile holding flags; - // b) ... + // a) Insanity checks on configuration; + // b) Ensure that Run 1/2 specific cuts and flags are used only in Run 1/2 (both data and sim); + // c) Ensure that Run 3 specific cuts and flags are used only in Run 3 (both data and sim); + // d) Insanity checks on binning; + // e) Insanity checks on events cuts; + // f) Insanity checks on Toy NUA; + // g) Insanity checks on internal validation; + // h) Insanity checks on results histograms. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); } - // a) Book the profile holding flags: - qv.fQvectorFlagsPro = - new TProfile("fQvectorFlagsPro", "flags for Q-vector objects", 3, 0., 3.); - qv.fQvectorFlagsPro->SetStats(kFALSE); - qv.fQvectorFlagsPro->SetLineColor(eColor); - qv.fQvectorFlagsPro->SetFillColor(eFillColor); - qv.fQvectorFlagsPro->GetXaxis()->SetLabelSize(0.05); - qv.fQvectorFlagsPro->GetXaxis()->SetBinLabel(1, "fCalculateQvectors"); - qv.fQvectorFlagsPro->Fill(0.5, qv.fCalculateQvectors); - qv.fQvectorFlagsPro->GetXaxis()->SetBinLabel(2, "gMaxHarmonic"); - qv.fQvectorFlagsPro->Fill(1.5, gMaxHarmonic); - qv.fQvectorFlagsPro->GetXaxis()->SetBinLabel(3, "gMaxCorrelator"); - qv.fQvectorFlagsPro->Fill(2.5, gMaxCorrelator); - qv.fQvectorList->Add(qv.fQvectorFlagsPro); + // a) Insanity checks on configuration: - // b) ... + // **) Dry run and internal validation are not meant to be run together: + if (tc.fDryRun && iv.fUseInternalValidation) { + LOGF(fatal, "\033[1;31m%s at line %d : Dry run and internal validation are not meant to be run together\033[0m", __FUNCTION__, __LINE__); + } -} // void BookQvectorHistograms() + // **) Cannot calculate multiparticle correlations, in case Q-vectors are not filled: + if (mupa.fCalculateCorrelations && !qv.fCalculateQvectors) { + LOGF(fatal, "\033[1;31m%s at line %d : Cannot calculate multiparticle correlations, in case Q-vectors are not calculated \033[0m", __FUNCTION__, __LINE__); + } -//============================================================ + // **) If some differential "correlations" flag is set to true, but the main fCalculateCorrelations is false, only print the warning that that differential correlations won't be calculated. + // This is not fatal, because this way I can turn off all differential "correlations" flags, just by setting fCalculateCorrelations to false, e.g. when I want to fill only control histograms. + for (int v = 0; v < eAsFunctionOf_N; v++) { + if (mupa.fCalculateCorrelationsAsFunctionOf[v] && !mupa.fCalculateCorrelations) { + LOGF(warning, "\033[1;33m%s at line %d : mupa.fCalculateCorrelationsAsFunctionOf[%d] is true, but mupa.fCalculateCorrelations is false. This differential correlations won't be calculated.\033[0m", __FUNCTION__, __LINE__, v); + } + } -void BookCorrelationsHistograms() -{ - // Book all correlations histograms. + // **) Cannot calculate Test0, in case Q-vectors are not filled: + if (t0.fCalculateTest0 && !qv.fCalculateQvectors) { + LOGF(fatal, "\033[1;31m%s at line %d : Cannot calculate Test0, in case Q-vectors are not filled \033[0m", __FUNCTION__, __LINE__); + } - // a) Book the profile holding flags; - // b) Common local labels; - // c) Histograms; - // d) Few quick insanity checks on booking. + // **) If some differential Test0 flag is set to true, but the main fCalculateTest0 is false, only print the warning that that differential Test0 won't be calculated. + // This is not fatal, because this way I can turn off all differential Test0 flags, just by setting fCalculateTest0 to false, e.g. when I want to fill only control histograms. + for (int v = 0; v < eAsFunctionOf_N; v++) { + if (t0.fCalculateTest0AsFunctionOf[v] && !t0.fCalculateTest0) { + LOGF(warning, "\033[1;33m%s at line %d : t0.fCalculateTest0AsFunctionOf[%d] is true, but t0.fCalculateTest0 is false. This differential Test0 won't be calculated.\033[0m", __FUNCTION__, __LINE__, v); + } + } - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + // **) Enforce that if the fixed number of randomly selected tracks is used in the analysis, that Fisher-Yates algorithm is enabled: + if (tc.fFixedNumberOfRandomlySelectedTracks > 0 && !tc.fUseFisherYates) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m : Did you forget to enable Fisher-Yates algorithm?", __FUNCTION__, __LINE__); } - // a) Book the profile holding flags: - mupa.fCorrelationsFlagsPro = new TProfile("fCorrelationsFlagsPro", - "flags for correlations", 1, 0., 31); - mupa.fCorrelationsFlagsPro->SetStats(kFALSE); - mupa.fCorrelationsFlagsPro->SetLineColor(eColor); - mupa.fCorrelationsFlagsPro->SetFillColor(eFillColor); - mupa.fCorrelationsFlagsPro->GetXaxis()->SetLabelSize(0.05); - mupa.fCorrelationsFlagsPro->GetXaxis()->SetBinLabel(1, "fCalculateCorrelations"); - mupa.fCorrelationsFlagsPro->Fill(0.5, mupa.fCalculateCorrelations); - // ... - mupa.fCorrelationsList->Add(mupa.fCorrelationsFlagsPro); + // **) Enforce that if the fixed number of randomly selected tracks is used that Toy NUA is disabled: + if (tc.fFixedNumberOfRandomlySelectedTracks > 0 && (nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF])) { + LOGF(fatal, "\033[1;31m%s at line %d : Not supported at the moment: use FixedNumberOfRandomlySelectedTracks + Toy NUA enabled.\nI cannot in an easy way ensure that ParticleCuts behave exactly the same in the Main and Banishment loops, because e.g. I call consequtively for same partcile gRandom->Uniform(...) in ParticleCuts, and that can't work.\033[0m", __FUNCTION__, __LINE__); + } - if (!mupa.fCalculateCorrelations) { - return; + // **) When it comes to DCAxy cut, ensure that either flat or pt-dependent cut is used, but not both: + if (pc.fUseParticleCuts[edcaXY] && pc.fUseParticleCuts[ePtDependentDCAxyParameterization]) { + LOGF(fatal, "\033[1;31m%s at line %d : use either flat or pt-dependent DCAxy cut, but not both \033[0m", __FUNCTION__, __LINE__); } - // b) Common local labels: - TString oVariable[4] = { - "#varphi_{1}-#varphi_{2}", - "#varphi_{1}+#varphi_{2}-#varphi_{3}-#varphi_{4}", - "#varphi_{1}+#varphi_{2}+#varphi_{3}-#varphi_{4}-#varphi_{5}-#varphi_{6}", - "#varphi_{1}+#varphi_{2}+#varphi_{3}+#varphi_{4}-#varphi_{5}-#varphi_{6}-" - "#varphi_{7}-#varphi_{8}"}; + // **) Insanity check on individual flags: Make sure that only one process is set to true. + // If 2 or more are true, then corresponding process function is executed over ALL data, then another process(...) function, etc. + // Re-think this if it's possible to run different process(...)'s concurently over the same data. + if (static_cast(tc.fProcess[eProcessRec]) + static_cast(tc.fProcess[eProcessRecSim]) + static_cast(tc.fProcess[eProcessSim]) + static_cast(tc.fProcess[eProcessRec_Run2]) + static_cast(tc.fProcess[eProcessRecSim_Run2]) + static_cast(tc.fProcess[eProcessSim_Run2]) + static_cast(tc.fProcess[eProcessRec_Run1]) + static_cast(tc.fProcess[eProcessRecSim_Run1]) + static_cast(tc.fProcess[eProcessSim_Run1]) > 1) { + LOGF(info, "\033[1;31m Only one flag can be true: tc.fProcess[eProcessRec] = %d, tc.fProcess[eProcessRecSim] = %d, tc.fProcess[eProcessSim] = %d, tc.fProcess[eProcessRec_Run2] = %d, tc.fProcess[eProcessRecSim_Run2] = %d, tc.fProcess[eProcessSim_Run2] = %d, tc.fProcess[eProcessRec_Run1] = %d, tc.fProcess[eProcessRecSim_Run1] = %d, tc.fProcess[eProcessSim_Run1] = %d \033[0m", static_cast(tc.fProcess[eProcessRec]), static_cast(tc.fProcess[eProcessRecSim]), static_cast(tc.fProcess[eProcessSim]), static_cast(tc.fProcess[eProcessRec_Run2]), static_cast(tc.fProcess[eProcessRecSim_Run2]), static_cast(tc.fProcess[eProcessSim_Run2]), static_cast(tc.fProcess[eProcessRec_Run1]), static_cast(tc.fProcess[eProcessRecSim_Run1]), static_cast(tc.fProcess[eProcessSim_Run1])); + LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } - // c) Histograms: - for (Int_t k = 0; k < 4; k++) // order [2p=0,4p=1,6p=2,8p=3] - { - for (Int_t n = 0; n < gMaxHarmonic; n++) // harmonic - { - for (Int_t v = 0; v < eAsFunctionOf_N; - v++) // variable [0=integrated,1=vs. multiplicity,2=vs. centrality,3=pt,4=eta] - { - if (!res.fResultsPro[v]) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); - } - mupa.fCorrelationsPro[k][n][v] = reinterpret_cast(res.fResultsPro[v]->Clone(Form("fCorrelationsPro[%d][%d][%s]", k, n, res.fResultsProRawName[v].Data()))); // yes - mupa.fCorrelationsPro[k][n][v]->SetStats(kFALSE); - mupa.fCorrelationsPro[k][n][v]->Sumw2(); - mupa.fCorrelationsPro[k][n][v]->GetXaxis()->SetTitle(res.fResultsProXaxisTitle[v].Data()); - mupa.fCorrelationsPro[k][n][v]->GetYaxis()->SetTitle(Form("#LT#LTcos[%s(%s)]#GT#GT", 1 == n + 1 ? "" : Form("%d", n + 1), oVariable[k].Data())); - mupa.fCorrelationsList->Add(mupa.fCorrelationsPro[k][n][v]); - } - } // for (Int_t n = 0; n < gMaxHarmonic; n++) // harmonic - } // for (Int_t k = 0; k < 4; k++) // order [2p=0,4p=1,6p=2,8p=3] + // **) Insanity checks on event cuts: - // d) Few quick insanity checks on booking: - if (mupa.fCorrelationsPro[0][0][AFO_INTEGRATED] && !TString(mupa.fCorrelationsPro[0][0][AFO_INTEGRATED]->GetXaxis()->GetTitle()).EqualTo("integrated")) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); // ordering in enum eAsFunctionOf is not the same as in TString fResultsProXaxisTitle[eAsFunctionOf_N] - } - if (mupa.fCorrelationsPro[0][0][AFO_PT] && !TString(mupa.fCorrelationsPro[0][0][AFO_PT]->GetXaxis()->GetTitle()).EqualTo("p_{T}")) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); // ordering in enum eAsFunctionOf is not the same as in TString fResultsProXaxisTitle[eAsFunctionOf_N] + // **) This check is meant to prevent the case when I want to bailout for max number of events, but I do not fill event histograms: + if (ec.fdEventCuts[eNumberOfEvents][eMax] < 1e6) { // TBI 20241011 Do I need to tune 1000000000 + // If I do not want to bail out when max number of events is reached, then in the configurable I have e.g. cfNumberOfEvents{"cfNumberOfEvents", {-1, 1000000000} + // So if the upper limit is set to some number < 1e6, I want to bail out for that number of events. + // TBI 20241011 this is a bit shaky, but nevermind now... + if (!eh.fBookEventHistograms[eNumberOfEvents]) { + LOGF(fatal, "\033[1;31m%s at line %d : Bailout for max number of events cannot be done, unless eh.fBookEventHistograms[eNumberOfEvents] is true.\033[0m", __FUNCTION__, __LINE__); + } } -} // BookCorrelationsHistograms() - -//============================================================ + // **) Check if the trigger makes sense or was validated for this dataset: + if (ec.fUseEventCuts[eTrigger]) { -void BookWeightsHistograms() -{ - // Book all objects for particle weights. + // Validated and supported Run 3 triggers: + if (tc.fProcess[eProcessRec]) { + if (!ec.fsEventCuts[eTrigger].EqualTo("kTVXinTRD")) { + LOGF(fatal, "\033[1;31m%s at line %d : trigger \"%s\" is not internally validated or supported for Run 3. Add it to the list of supported triggers, if you really want to use that one.\033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eTrigger].Data()); + } + } - // a) Book the profile holding flags; - // b) Histograms; - // c) Histograms for differential weights. + // Validated and supported Run 2 triggers: + if (tc.fProcess[eProcessRec_Run2]) { + if (!ec.fsEventCuts[eTrigger].EqualTo("kINT7")) { + // LOGF(fatal, "\033[1;31m%s at line %d : trigger \"%s\" is not internally validated/supported yet for Run 2. Add it to the list of supported triggers, if you really want to use that one.\033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eTrigger].Data()); + } + } - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); - } + // Validated and supported Run 1 triggers: + // ... - // a) Book the profile holding flags: - pw.fWeightsFlagsPro = - new TProfile("fWeightsFlagsPro", "flags for particle weights", 5, 0., 5.); - pw.fWeightsFlagsPro->SetStats(kFALSE); - pw.fWeightsFlagsPro->SetLineColor(eColor); - pw.fWeightsFlagsPro->SetFillColor(eFillColor); - pw.fWeightsFlagsPro->GetXaxis()->SetLabelSize(0.05); - pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(1, "w_{#varphi}"); - pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(2, "w_{p_{t}}"); - pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(3, "w_{#eta}"); - pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(4, "w_{#varphi}(p_{t})"); - pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(5, "w_{#varphi}(#eta)"); + } // if (ec.fUseEventCuts[eTrigger]) { - for (Int_t w = 0; w < eWeights_N; w++) // use weights [phi,pt,eta] - { - if (pw.fUseWeights[w]) - pw.fWeightsFlagsPro->Fill(w + 0.5, 1.); - } - for (Int_t w = 0; w < eDiffWeights_N; w++) // use differential weights [phipt,phieta,...] - { - if (pw.fUseDiffWeights[w]) - pw.fWeightsFlagsPro->Fill(w + 3.5, 1.); // TBI 20231026 This hadrwired offset of +3.5 will bite me sooner or later, but nevermind now... + // **) Check if the cut on MinVertexDistanceFromIP makes sense: + if (ec.fUseEventCuts[eMinVertexDistanceFromIP]) { + if (!(ec.fdEventCuts[eMinVertexDistanceFromIP][eMin] > 0.)) { + LOGF(fatal, "\033[1;31m%s at line %d : trigger ec.fdEventCuts[eMinVertexDistanceFromIP][eMin] = %f must be positive. Check the setting of configurable cfMinVertexDistanceFromIP\033[0m", __FUNCTION__, __LINE__, ec.fdEventCuts[eMinVertexDistanceFromIP][eMin]); + } } - pw.fWeightsList->Add(pw.fWeightsFlagsPro); - // b) Histograms: - // As of 20240216, I have abandoned the idea to generate integrated weights internally, weights - // are always fetched and cloned from external files, in any case (local, AliEn, CCDB). - // Therefore, add histos with weights to this list only after they are cloned from external files. + // **) Enforce the usage of particular trigger for this dataset: + if (tc.fProcess[eProcessRec_Run2]) { + // TBI 20250115 Not really sure I need this - if I want to run only "Rec" over Monte Carlo, then obviously the condition below is pointless. + // Also here I need to be able automaticaly to determine whether I am processing real data or Monte Carlo, from the dataset itself. + // TBI 20240517 for the time being, here I am enforcing that "kINT7" is mandatory for Run 2 + // TBI 20241209 I still have to validate it for Run 1 converted real data => then expand if(...) statement above - // c) Histograms for differential weights: - // Same comment applies as for c) => add histograms to the list, only after they are cloned from external files. + /* commented out temporariy, see TBI 20250115 above + if (!(ec.fUseEventCuts[eTrigger] && ec.fsEventCuts[eTrigger].EqualTo("kINT7"))) { + LOGF(fatal, "\033[1;31m%s at line %d : trigger \"%s\" is not internally validated/supported yet. Add it to the list of supported triggers, if you really want to use that one.\033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eTrigger].Data()); + } else { + LOGF(info, "\033[1;32m%s at line %d : WARNING => trigger \"%s\" can be used only on real converted Run 2 and Run 1 data. For MC converted Run 2 and Run 1 data, this trigger shouldn't be used.\033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eTrigger].Data()); + // TBI 20240517 I need here programmatic access to "event-selection-task" flags "isMC and "isRunMC" . Then I can directly bail out. + } + */ + } -} // void BookWeightsHistograms() + // **) Ensure that fFloatingPointPrecision makes sense: + if (!(tc.fFloatingPointPrecision > 0.)) { + LOGF(fatal, "\033[1;31m%s at line %d : set fFloatingPointPrecision = %f to some small positive value, which will determine if two floats are the same \033[0m", __FUNCTION__, __LINE__, tc.fFloatingPointPrecision); + } -//============================================================ + // **) Ensure that fSequentialBailout makes sense: + if (!(tc.fSequentialBailout >= 0)) { + LOGF(fatal, "\033[1;31m%s at line %d : set fSequentialBailout = %d either to 0 (not used), or to positive integer.\033[0m", __FUNCTION__, __LINE__, tc.fSequentialBailout); + } -void BookNestedLoopsHistograms() -{ - // Book all nested loops histograms. + // **) Ensure that I do not spill over with number of dimensions in sparse histograms: + if (eDiffPhiWeights_N > gMaxNumberSparseDimensions) { + LOGF(fatal, "\033[1;31m%s at line %d : set eDiffPhiWeights_N = %d is bigger than gMaxNumberSparseDimensions = %d\033[0m", __FUNCTION__, __LINE__, static_cast(eDiffPhiWeights_N), gMaxNumberSparseDimensions); + } + if (eDiffPtWeights_N > gMaxNumberSparseDimensions) { + LOGF(fatal, "\033[1;31m%s at line %d : set eDiffPtWeights_N = %d is bigger than gMaxNumberSparseDimensions = %d\033[0m", __FUNCTION__, __LINE__, static_cast(eDiffPtWeights_N), gMaxNumberSparseDimensions); + } + if (eDiffEtaWeights_N > gMaxNumberSparseDimensions) { + LOGF(fatal, "\033[1;31m%s at line %d : set eDiffEtaWeights_N = %d is bigger than gMaxNumberSparseDimensions = %d\033[0m", __FUNCTION__, __LINE__, static_cast(eDiffEtaWeights_N), gMaxNumberSparseDimensions); + } - // a) Book the profile holding flags; - // b) Common local labels (keep 'em in sync with BookCorrelationsHistograms()); - // c) Book what needs to be booked; - // d) Few quick insanity checks on booking. + // b) Ensure that Run 1/2 specific cuts and flags are used only in Run 1/2 (both data and sim): + // **) Ensure that eSel7 is used only for converted Run 2 and Run 1 (both data and sim): + if (ec.fUseEventCuts[eSel7]) { + if (!(tc.fProcess[eProcessRec_Run2] || tc.fProcess[eProcessRecSim_Run2] || tc.fProcess[eProcessSim_Run2] || tc.fProcess[eProcessRec_Run1] || tc.fProcess[eProcessRecSim_Run1] || tc.fProcess[eProcessSim_Run1])) { + LOGF(fatal, "\033[1;31m%s at line %d : use fSel7 for Run 2 data and MC\033[0m", __FUNCTION__, __LINE__); + } + } - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + // **) Supported reference multiplicity estimators for Run 1 and 2 are enlisted here: + if (tc.fProcess[eProcessRec_Run2] || tc.fProcess[eProcessRecSim_Run2] || tc.fProcess[eProcessRec_Run1] || tc.fProcess[eProcessRecSim_Run1]) { + if (!(ec.fsEventCuts[eReferenceMultiplicityEstimator].EqualTo("MultTracklets", TString::kIgnoreCase))) { + LOGF(fatal, "\033[1;31m%s at line %d : reference multiplicity estimator = %s is not supported for Run 1 and 2 analysis.\nUse \"MultTracklets\"\033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eReferenceMultiplicityEstimator].Data()); + } + } else if (tc.fProcess[eProcessSim_Run2] || tc.fProcess[eProcessSim_Run1]) { + LOGF(fatal, "\033[1;31m%s at line %d : eProcessSim is not validated yet \033[0m", __FUNCTION__, __LINE__); } - // a) Book the profile holding flags: - nl.fNestedLoopsFlagsPro = - new TProfile("fNestedLoopsFlagsPro", "flags for nested loops", 2, 0., 2.); - nl.fNestedLoopsFlagsPro->SetStats(kFALSE); - nl.fNestedLoopsFlagsPro->GetXaxis()->SetLabelSize(0.05); - nl.fNestedLoopsFlagsPro->GetXaxis()->SetBinLabel(1, "fCalculateNestedLoops"); - nl.fNestedLoopsFlagsPro->Fill(0.5, nl.fCalculateNestedLoops); - nl.fNestedLoopsFlagsPro->Fill(1.5, nl.fCalculateCustomNestedLoop); - nl.fNestedLoopsList->Add(nl.fNestedLoopsFlagsPro); + // **) Supported centrality estimators for Run 1 and 2 are enlisted here: + if (tc.fProcess[eProcessRec_Run2] || tc.fProcess[eProcessRecSim_Run2] || tc.fProcess[eProcessSim_Run2] || tc.fProcess[eProcessRec_Run1] || tc.fProcess[eProcessRecSim_Run1] || tc.fProcess[eProcessSim_Run1]) { + if (!(ec.fsEventCuts[eCentralityEstimator].EqualTo("centRun2V0M", TString::kIgnoreCase) || + ec.fsEventCuts[eCentralityEstimator].EqualTo("centRun2SPDTracklets", TString::kIgnoreCase))) { + LOGF(fatal, "\033[1;31m%s at line %d : centrality estimator = %s is not supported for converted Run 2 and Run 1 analysis.\nUse either \"centRun2V0M\" or \"centRun2SPDTracklets\" (case sensitive!) \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eCentralityEstimator].Data()); + } + } - if (!(nl.fCalculateNestedLoops || nl.fCalculateCustomNestedLoop)) { - return; + // **) Protection against particle cuts which are available, but not yet validated, or are meaningless, in Run 2 and 1: + if (tc.fProcess[eProcessRec_Run2] || tc.fProcess[eProcessRecSim_Run2] || tc.fProcess[eProcessSim_Run2] || tc.fProcess[eProcessRec_Run1] || tc.fProcess[eProcessRecSim_Run1] || tc.fProcess[eProcessSim_Run1]) { + if (pc.fUseParticleCuts[etrackCutFlag]) { + LOGF(fatal, "\033[1;31m%s at line %d : particle cut etrackCutFlag is not validated, as of 20250113 it has no effect in Run 2 and Run 1 \033[0m", __FUNCTION__, __LINE__); + } + if (pc.fUseParticleCuts[etrackCutFlagFb1]) { + LOGF(fatal, "\033[1;31m%s at line %d : particle cut etrackCutFlagFb1 is not validated, as of 20250113 it kills all reconstructed tracks in Run 2 and Run 1 \033[0m", __FUNCTION__, __LINE__); + } + if (pc.fUseParticleCuts[etrackCutFlagFb2]) { + LOGF(fatal, "\033[1;31m%s at line %d : particle cut etrackCutFlagFb2 is not validated, as of 20250113 it kills all reconstructed tracks in Run 2 and Run 1 \033[0m", __FUNCTION__, __LINE__); + } } - const Int_t iMaxSize = 2e4; - nl.ftaNestedLoops[0] = - new TArrayD(iMaxSize); // ebe container for azimuthal angles - nl.ftaNestedLoops[1] = new TArrayD( - iMaxSize); // ebe container for particle weights (product of all) + // **) Print a warning if kINT7 trigger is not used in reconstructed Run 2: + // TBI 20250318 shall I expand the check also to Run 1? In 2011 there were dedicated kCentral and kSemiCentral triggers only... + // TBI 20250318 shall I make it fatal instead? Without this trigger, a lot of histos are just meaningles (e.g. nContributores vs centrality, etc.) + if (tc.fProcess[eProcessRec_Run2]) { + if (!(ec.fUseEventCuts[eTrigger] && ec.fsEventCuts[eTrigger].EqualTo("kINT7"))) { + LOGF(warning, "\033[1;31m%s at line %d : kINT7 trigger in Run 2 is not selected - by default it should be used.\033[0m", __FUNCTION__, __LINE__); + } + } - // TBI 20220823 port here if(fCalculatePtCorrelations) { ... } and - // if(fCalculateEtaCorrelations) { ... } + // **) Bail out if kINT7 trigger is used in Run 2 Monte Carlo: + // TBI 20250318 shall I expand the check also to Run 1? In 2011 there were dedicated kCentral and kSemiCentral triggers only... + if (tc.fProcess[eProcessRecSim_Run2] || tc.fProcess[eProcessSim_Run2]) { + if (ec.fUseEventCuts[eTrigger] && ec.fsEventCuts[eTrigger].EqualTo("kINT7")) { + LOGF(fatal, "\033[1;31m%s at line %d : kINT7 trigger in Run 2 Monte Carlo is not validated - use it at your own peril.\033[0m", __FUNCTION__, __LINE__); + } + } - if (!nl.fCalculateNestedLoops) { - return; + if (ec.fUseEventCuts[eNoPileupTPC]) { + if (tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim]) { + LOGF(fatal, "\033[1;31m%s at line %d : cannot use NoPileupTPC in Run 3\033[0m", __FUNCTION__, __LINE__); + } } - // b) Common local labels (keep 'em in sync with BookCorrelationsHistograms()) - TString oVariable[4] = { - "#varphi_{1}-#varphi_{2}", - "#varphi_{1}+#varphi_{2}-#varphi_{3}-#varphi_{4}", - "#varphi_{1}+#varphi_{2}+#varphi_{3}-#varphi_{4}-#varphi_{5}-#varphi_{6}", - "#varphi_{1}+#varphi_{2}+#varphi_{3}+#varphi_{4}-#varphi_{5}-#varphi_{6}-" - "#varphi_{7}-#varphi_{8}"}; + if (ec.fUseEventCuts[eNoPileupFromSPD]) { + if (tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim]) { + LOGF(fatal, "\033[1;31m%s at line %d : cannot use NoPileupFromSPD in Run 3\033[0m", __FUNCTION__, __LINE__); + } + } - // c) Book what needs to be booked: - for (Int_t k = 0; k < 4; k++) // order [2p=0,4p=1,6p=2,8p=3] - { - for (Int_t n = 0; n < gMaxHarmonic; n++) // harmonic - { - for (Int_t v = 0; v < eAsFunctionOf_N; - v++) // variable [0=integrated,1=vs. multiplicity,2=vs. centrality,3=pt,4=eta] - { + if (ec.fUseEventCuts[eNoSPDOnVsOfPileup]) { + if (tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim]) { + LOGF(fatal, "\033[1;31m%s at line %d : cannot use NoSPDOnVsOfPileup in Run 3\033[0m", __FUNCTION__, __LINE__); + } + } - // if(PTKINE == v && !fCalculatePtCorrelations){continue;} - // if(ETAKINE == v && !fCalculateEtaCorrelations){continue;} + // ... - if (!res.fResultsPro[v]) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); - } - nl.fNestedLoopsPro[k][n][v] = reinterpret_cast(res.fResultsPro[v]->Clone(Form("fNestedLoopsPro[%d][%d][%d]", k, n, v))); // yes - nl.fNestedLoopsPro[k][n][v]->SetTitle(Form("#LT#LTcos[%s(%s)]#GT#GT", 1 == n + 1 ? "" : Form("%d", n + 1), oVariable[k].Data())); - nl.fNestedLoopsPro[k][n][v]->SetStats(kFALSE); - nl.fNestedLoopsPro[k][n][v]->Sumw2(); - nl.fNestedLoopsPro[k][n][v]->GetXaxis()->SetTitle( - res.fResultsProXaxisTitle[v].Data()); + // c) Ensure that Run 3 specific cuts and flags are used only in Run 3 (both data and sim): + // **) Ensure that eSel8 is used only in Run 3 (both data and sim): + if (ec.fUseEventCuts[eSel8]) { + if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA])) { + LOGF(fatal, "\033[1;31m%s at line %d : use eSel8 only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); + } + } - /* - if(fUseFixedNumberOfRandomlySelectedTracks && 1==v) // just a warning - for the meaning of multiplicity in this special case - { - nl.fNestedLoopsPro[k][n][1]->GetXaxis()->SetTitle("WARNING: for each - multiplicity, fFixedNumberOfRandomlySelectedTracks is selected randomly - in Q-vector"); - } - */ + if (ec.fUseEventCuts[eNoSameBunchPileup]) { + if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA])) { + LOGF(fatal, "\033[1;31m%s at line %d : use eNoSameBunchPileup only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); + } + } - nl.fNestedLoopsList->Add(nl.fNestedLoopsPro[k][n][v]); - } // for(Int_t v=0;v<5;v++) // variable [0=integrated,1=vs. - // multiplicity,2=vs. centrality] - } // for (Int_t n = 0; n < gMaxHarmonic; n++) // harmonic - } // for (Int_t k = 0; k < 4; k++) // order [2p=0,4p=1,6p=2,8p=3] + if (ec.fUseEventCuts[eIsGoodZvtxFT0vsPV]) { + if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA])) { + LOGF(fatal, "\033[1;31m%s at line %d : use eIsGoodZvtxFT0vsPV only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); + } + } - // d) Few quick insanity checks on booking: - if (nl.fNestedLoopsPro[0][0][AFO_INTEGRATED] && !TString(nl.fNestedLoopsPro[0][0][AFO_INTEGRATED]->GetXaxis()->GetTitle()).EqualTo("integrated")) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); // ordering in enum eAsFunctionOf is not the same as in TString fResultsProXaxisTitle[eAsFunctionOf_N] + if (ec.fUseEventCuts[eIsVertexITSTPC]) { + if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA])) { + LOGF(fatal, "\033[1;31m%s at line %d : use eIsVertexITSTPC only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); + } } - if (nl.fNestedLoopsPro[0][0][AFO_PT] && !TString(nl.fNestedLoopsPro[0][0][AFO_PT]->GetXaxis()->GetTitle()).EqualTo("p_{T}")) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); // ordering in enum eAsFunctionOf is not the same as in TString fResultsProXaxisTitle[eAsFunctionOf_N] + + if (ec.fUseEventCuts[eIsVertexTOFmatched]) { + if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA])) { + LOGF(fatal, "\033[1;31m%s at line %d : use eIsVertexTOFmatched only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); + } } -} // void BookNestedLoopsHistograms() + if (ec.fUseEventCuts[eIsVertexTRDmatched]) { + if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA])) { + LOGF(fatal, "\033[1;31m%s at line %d : use eIsVertexTRDmatched only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); + } + } -//============================================================ + if (ec.fUseEventCuts[eNoCollInTimeRangeStrict]) { + if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA])) { + LOGF(fatal, "\033[1;31m%s at line %d : use eNoCollInTimeRangeStrict only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); + } + } -void BookTest0Histograms() -{ - // Book all Test0 histograms. + if (ec.fUseEventCuts[eNoCollInTimeRangeStandard]) { + if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA])) { + LOGF(fatal, "\033[1;31m%s at line %d : use eNoCollInTimeRangeStandard only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); + } + } - // a) Book the profile holding flags; - // b) Book placeholder and make sure all labels are stored in the placeholder; - // c) Retrieve labels from placeholder; - // d) Book what needs to be booked; - // e) Few quick insanity checks on booking. + if (ec.fUseEventCuts[eNoCollInRofStrict]) { + if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA])) { + LOGF(fatal, "\033[1;31m%s at line %d : use eNoCollInRofStrict only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); + } + } - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + if (ec.fUseEventCuts[eNoCollInRofStandard]) { + if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA])) { + LOGF(fatal, "\033[1;31m%s at line %d : use eNoCollInRofStandard only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); + } } - // a) Book the profile holding flags: - t0.fTest0FlagsPro = new TProfile("fTest0FlagsPro", "flags for Test0", 1, 0., 1.); - t0.fTest0FlagsPro->SetStats(kFALSE); - t0.fTest0FlagsPro->GetXaxis()->SetLabelSize(0.04); - t0.fTest0FlagsPro->GetXaxis()->SetBinLabel(1, "fCalculateTest0"); - t0.fTest0FlagsPro->Fill(0.5, t0.fCalculateTest0); - t0.fTest0List->Add(t0.fTest0FlagsPro); + if (ec.fUseEventCuts[eNoHighMultCollInPrevRof]) { + if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA])) { + LOGF(fatal, "\033[1;31m%s at line %d : use eNoHighMultCollInPrevRof only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); + } + } - if (!t0.fCalculateTest0) { - return; + if (ec.fUseEventCuts[eIsGoodITSLayer3]) { + if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA])) { + LOGF(fatal, "\033[1;31m%s at line %d : use eIsGoodITSLayer3 only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); + } } - // b) Book placeholder and make sure all labels are stored in the placeholder: - this->StoreLabelsInPlaceholder(); - if (t0.fTest0LabelsPlaceholder) { - t0.fTest0List->Add(t0.fTest0LabelsPlaceholder); + if (ec.fUseEventCuts[eIsGoodITSLayer0123]) { + if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA])) { + LOGF(fatal, "\033[1;31m%s at line %d : use eIsGoodITSLayer0123 only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); + } } - // c) Retrieve labels from placeholder: - if (!(this->RetrieveCorrelationsLabels())) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + if (ec.fUseEventCuts[eIsGoodITSLayersAll]) { + if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA])) { + LOGF(fatal, "\033[1;31m%s at line %d : use eIsGoodITSLayersAll only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); + } } - // d) Book what needs to be booked: - for (Int_t mo = 0; mo < gMaxCorrelator; mo++) { - for (Int_t mi = 0; mi < gMaxIndex; mi++) { - if (!t0.fTest0Labels[mo][mi]) { - continue; - } - { - for (Int_t v = 0; v < eAsFunctionOf_N; v++) { - // decide what is booked, then later valid pointer to fCorrelationsPro[k][n][v] is used as a boolean, in the standard way: - if (AFO_INTEGRATED == v && !t0.fCalculateTest0AsFunctionOf[AFO_INTEGRATED]) { - continue; - } - if (AFO_MULTIPLICITY == v && !t0.fCalculateTest0AsFunctionOf[AFO_MULTIPLICITY]) { - continue; - } - if (AFO_CENTRALITY == v && !t0.fCalculateTest0AsFunctionOf[AFO_CENTRALITY]) { - continue; - } - if (AFO_PT == v && !t0.fCalculateTest0AsFunctionOf[AFO_PT]) { - continue; - } - if (AFO_ETA == v && !t0.fCalculateTest0AsFunctionOf[AFO_ETA]) { - continue; - } + // **) Supported reference multiplicity estimators for Run 3 are enlisted here: + if (tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessQA]) { + if (!(ec.fsEventCuts[eReferenceMultiplicityEstimator].EqualTo("MultTPC", TString::kIgnoreCase) || + ec.fsEventCuts[eReferenceMultiplicityEstimator].EqualTo("MultFV0M", TString::kIgnoreCase) || + ec.fsEventCuts[eReferenceMultiplicityEstimator].EqualTo("MultFT0C", TString::kIgnoreCase) || + ec.fsEventCuts[eReferenceMultiplicityEstimator].EqualTo("MultFT0M", TString::kIgnoreCase) || + ec.fsEventCuts[eReferenceMultiplicityEstimator].EqualTo("MultNTracksPV", TString::kIgnoreCase))) { + LOGF(fatal, "\033[1;31m%s at line %d : reference multiplicity estimator = %s is not supported yet for Run 3 analysis.\nUse \"MultTPC\", \"MultFV0M\", \"MultFT0C\", \"MultFT0M\" or \"MultNTracksPV\"\033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eReferenceMultiplicityEstimator].Data()); + } + } else if (tc.fProcess[eProcessSim]) { + LOGF(fatal, "\033[1;31m%s at line %d : eProcessSim is not validated yet \033[0m", __FUNCTION__, __LINE__); + } + + // **) Supported centrality estimators for Run 3 are enlisted here: + if (tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessQA]) { + if (!(ec.fsEventCuts[eCentralityEstimator].EqualTo("centFT0C", TString::kIgnoreCase) || + ec.fsEventCuts[eCentralityEstimator].EqualTo("centFT0CVariant1", TString::kIgnoreCase) || + ec.fsEventCuts[eCentralityEstimator].EqualTo("centFT0M", TString::kIgnoreCase) || + ec.fsEventCuts[eCentralityEstimator].EqualTo("centFV0A", TString::kIgnoreCase) || + ec.fsEventCuts[eCentralityEstimator].EqualTo("centNTPV", TString::kIgnoreCase) || + ec.fsEventCuts[eCentralityEstimator].EqualTo("centNGlobal", TString::kIgnoreCase))) { + LOGF(fatal, "\033[1;31m%s at line %d : centrality estimator = %s is not supported yet for Run 3 analysis.\nUse \"centFT0C\", \"centFT0CVariant1\", \"centFT0M\", \"centFV0A\", \"centNTPV\", pr , \"centNGlobal\"\033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eCentralityEstimator].Data()); + } + } else if (tc.fProcess[eProcessSim]) { + LOGF(fatal, "\033[1;31m%s at line %d : eProcessSim is not validated yet \033[0m", __FUNCTION__, __LINE__); + } - if (!res.fResultsPro[v]) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); - } + // **) Supported occupancy estimators for Run 3 are enlisted here: + if (tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessQA]) { + if (!(ec.fsEventCuts[eOccupancyEstimator].EqualTo("TrackOccupancyInTimeRange", TString::kIgnoreCase) || + ec.fsEventCuts[eOccupancyEstimator].EqualTo("FT0COccupancyInTimeRange", TString::kIgnoreCase))) { + LOGF(fatal, "\033[1;31m%s at line %d : occupancy estimator = %s is not supported yet for Run 3 analysis. \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eOccupancyEstimator].Data()); + } + } - t0.fTest0Pro[mo][mi][v] = reinterpret_cast(res.fResultsPro[v]->Clone(Form("fTest0Pro[%d][%d][%s]", mo, mi, res.fResultsProRawName[v].Data()))); // yes - t0.fTest0Pro[mo][mi][v]->SetStats(kFALSE); - t0.fTest0Pro[mo][mi][v]->Sumw2(); - t0.fTest0Pro[mo][mi][v]->SetTitle(t0.fTest0Labels[mo][mi]->Data()); - t0.fTest0Pro[mo][mi][v]->GetXaxis()->SetTitle(res.fResultsProXaxisTitle[v].Data()); - /* - if(fUseFixedNumberOfRandomlySelectedParticles && 1==v) // just a warning for the meaning of multiplicity in this special case - { - fTest0Pro[mo][mi][1]->GetXaxis()->SetTitle("WARNING: for each multiplicity, fFixedNumberOfRandomlySelectedParticles is selected randomly in Q-vector"); - } - */ - t0.fTest0List->Add(t0.fTest0Pro[mo][mi][v]); // yes, this has to be here - } // for(Int_t v=0;v it has no effect\033[0m", __FUNCTION__, __LINE__); + } + if (pc.fUseParticleCuts[eisQualityTrack]) { + LOGF(fatal, "\033[1;31m%s at line %d : particle cut isQualityTrack is not validated in Run 3 as of 20250113 => it kills all reconstructed tracks \033[0m", __FUNCTION__, __LINE__); + } + if (pc.fUseParticleCuts[eisGlobalTrack]) { + LOGF(fatal, "\033[1;31m%s at line %d : particle cut isGlobalTrack cannot be used in Run 3 => it kills all reconstructed tracks.\n To select global track in Run 3, use etrackCutFlagFb1 or etrackCutFlagFb2, see documentation in enum\033[0m", __FUNCTION__, __LINE__); + } + } - // e) Few quick insanity checks on booking: - if (t0.fTest0Pro[0][0][AFO_INTEGRATED] && !TString(t0.fTest0Pro[0][0][AFO_INTEGRATED]->GetXaxis()->GetTitle()).EqualTo("integrated")) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); // ordering in enum eAsFunctionOf is not the same as in TString fResultsProXaxisTitle[eAsFunctionOf_N] + // **) Protection on particle cuts which can be used only in Run 3: + // trackCutFlag, trackCutFlagFb1, trackCutFlagFb2 => use only one at the time + if (static_cast(pc.fUseParticleCuts[etrackCutFlag]) + static_cast(pc.fUseParticleCuts[etrackCutFlagFb1]) + static_cast(pc.fUseParticleCuts[etrackCutFlagFb2]) >= 2) { + LOGF(fatal, "\033[1;31m%s at line %d : use only one of trackCutFlag, trackCutFlagFb1, trackCutFlagFb2 at time. \033[0m", __FUNCTION__, __LINE__); } - if (t0.fTest0Pro[0][0][AFO_PT] && !TString(t0.fTest0Pro[0][0][AFO_PT]->GetXaxis()->GetTitle()).EqualTo("p_{T}")) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); // ordering in enum eAsFunctionOf is not the same as in TString fResultsProXaxisTitle[eAsFunctionOf_N] + + // isPVContributor: + if (pc.fUseParticleCuts[eisPVContributor]) { + if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA])) { + LOGF(fatal, "\033[1;31m%s at line %d : particle cut isPVContributor can be used only in Run 3\033[0m", __FUNCTION__, __LINE__); + } } -} // void BookTest0Histograms() - -//============================================================ + // **) Protection for histograms which are meaningfull only in Run 3: + // ***) interaction rate is available only in Run 3: + if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA])) { + if (qa.fFillQACorrelationsVsInteractionRateVsProfiles2D) { + LOGF(fatal, "\033[1;31m%s at line %d : fFillQACorrelationsVsInteractionRateVsProfiles2D can be used only in Run 3, because only there ir is available.\033[0m", __FUNCTION__, __LINE__); + } + if (qa.fFillQAParticleEventHistograms2D) { + LOGF(fatal, "\033[1;31m%s at line %d : qa.fFillQAParticleEventHistograms2D can be used only in Run 3, because only there crd is available.\033[0m", __FUNCTION__, __LINE__); + } + // ... + } // if (! (tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim])) { -void BookResultsHistograms() -{ - // Book all results histograms. + // ... - // a) Book the profile holding flags; - // b) Book results histograms, which in addition act as a sort of "abstract" interface, which defines common binning, etc., for other groups of histograms. + // d) Insanity checks on binning: + // ... - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + // e) Insanity checks on events cuts: + if (ec.fsEventCuts[eMultiplicityEstimator].EqualTo("ReferenceMultiplicity", TString::kIgnoreCase) && ec.fUseEventCuts[eMultiplicity]) { + LOGF(fatal, "\033[1;31m%s at line %d : use ec.fUseEventCuts[eMultiplicity] only when eMultiplicityEstimator = SelectedTracks. Otherwise, things can happen... \033[0m", __FUNCTION__, __LINE__); } + // ... - // a) Book the profile holding flags: - res.fResultsFlagsPro = new TProfile("fResultsFlagsPro", - "flags for results histograms", 1, 0., 1.); - res.fResultsFlagsPro->SetStats(kFALSE); - res.fResultsFlagsPro->SetLineColor(eColor); - res.fResultsFlagsPro->SetFillColor(eFillColor); - res.fResultsFlagsPro->GetXaxis()->SetBinLabel(1, "fSaveResultsHistograms"); - res.fResultsFlagsPro->Fill(0.5, res.fSaveResultsHistograms); + // f) Insanity checks on Toy NUA: // ... - res.fResultsList->Add(res.fResultsFlagsPro); - // b) Book results histograms, which in addition act as a sort of "abstract" interface, which defines common binning, etc., for other groups of histograms: - for (Int_t v = 0; v < eAsFunctionOf_N; v++) { - if (res.fUseResultsProVariableLengthBins[v]) { - // per demand, variable-length binning: - res.fResultsPro[v] = new TProfile(Form("fResultsPro[%s]", res.fResultsProRawName[v].Data()), "...", res.fResultsProVariableLengthBins[v]->GetSize() - 1, res.fResultsProVariableLengthBins[v]->GetArray()); - } else { - // the default fixed-length binning: - res.fResultsPro[v] = new TProfile(Form("fResultsPro[%s]", res.fResultsProRawName[v].Data()), "...", (Int_t)res.fResultsProFixedLengthBins[v][0], res.fResultsProFixedLengthBins[v][1], res.fResultsProFixedLengthBins[v][2]); + // g) Insanity checks on internal validation: + // Remark: I check here only in the settings I could define in DefaultConfiguration(). + // The other insanity checks are in BookInternalValidationHistograms() or in InsanityChecksAfterBooking() + if (iv.fUseInternalValidation) { + if (iv.fnEventsInternalValidation <= 0) { + LOGF(fatal, "\033[1;31m%s at line %d : iv.fnEventsInternalValidation <= 0 => Set number of events to positive integer\033[0m", __FUNCTION__, __LINE__); } - // Optionally, save these histograms. Or just use them as an "abstract" interface for the booking of other group of histograms: - if (res.fSaveResultsHistograms) { - res.fResultsList->Add(res.fResultsPro[v]); + if (!(iv.fHarmonicsOptionInternalValidation->EqualTo("constant", TString::kIgnoreCase) || + iv.fHarmonicsOptionInternalValidation->EqualTo("correlated", TString::kIgnoreCase) || + iv.fHarmonicsOptionInternalValidation->EqualTo("persistent", TString::kIgnoreCase))) { + LOGF(fatal, "\033[1;31m%s at line %d : fHarmonicsOptionInternalValidation = %s is not supported. \033[0m", __FUNCTION__, __LINE__, iv.fHarmonicsOptionInternalValidation->Data()); } - } // for (Int_t v = 0; v < eAsFunctionOf_N; v++) { -} // void BookResultsHistograms() + if (iv.fRescaleWithTheoreticalInput && (nl.fCalculateNestedLoops || nl.fCalculateCustomNestedLoops || nl.fCalculateKineCustomNestedLoops)) { + LOGF(fatal, "\033[1;31m%s at line %d : rescaling with theoretical input is not supported when cross-check is done with nested loops. \033[0m", __FUNCTION__, __LINE__); + } -//============================================================ + if (ec.fsEventCuts[eMultiplicityEstimator].EqualTo("ReferenceMultiplicity", TString::kIgnoreCase)) { + LOGF(fatal, "\033[1;31m%s at line %d : in IV eMultiplicityEstimator cannot be set to \"ReferenceMultiplicity\" (yet) \033[0m", __FUNCTION__, __LINE__); + } -void BookTheRest() -{ - // Here I book everything not sorted (yes) in specific functions above. + } // if (iv.fUseInternalValidation) { - // a) Book the timer; - // *) ... + // h) Insanity checks on results histograms: + // **) Check if all arrays are initialized until the end: + for (int afo = 0; afo < eAsFunctionOf_N; afo++) { + if (res.fResultsProXaxisTitle[afo].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsProXaxisTitle[%d] is empty.\033[0m", __FUNCTION__, __LINE__, afo); + } - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); - } + if (res.fResultsProRawName[afo].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsProRawName[%d] is empty.\033[0m", __FUNCTION__, __LINE__, afo); + } + } // for(int afo = 0; afo < eAsFunctionOf_N; afo++) { - // a) Book the timer: - if (tc.fUseStopwatch) { - tc.fTimer[eGlobal] = new TStopwatch(); - tc.fTimer[eGlobal]->Start(); - tc.fTimer[eLocal] = new TStopwatch(); + // ... + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); } -} // void BookTheRest() +} // void InsanityChecksBeforeBooking() //============================================================ -template -void Preprocess(T const& collision) +void InsanityChecksAfterBooking() { - // Do all thingies before starting to process data (e.g. count number of events, fetch the run number, get the weights for this run number, etc.). + // Do insanity checks on all booked histograms, etc., + // Configuration, binning and cuts are checked already before booking in InsanityChecksBeforeBooking(). + + // a) Insanity checks on booking; + // b) Insanity checks on internal validation; + // ... if (tc.fVerbose) { - // LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); // full function signature (including arguments, etc.), too verbose here... - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); // just a bare function name + StartFunction(__FUNCTION__); } - // *) If I reached max number of events, ignore the remaining collisions: - if (MaxNumberOfEvents()) { - BailOut(); - } + // a) Insanity checks on booking: - // *) Determine and propagate run number info to already booked objects: - if (!tc.fRunNumberIsDetermined) { - DetermineAndPropagateRunNumber(collision); + // **) Check that the last bin is not empty in fBasePro, and that there is no underflow or overflow bins: + if (TString(fBasePro->GetXaxis()->GetBinLabel(eConfiguration_N - 1)).EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : The very last bin of \"fBasePro\" doesn't have the title, check the booking of this hostogram. \033[0m", __FUNCTION__, __LINE__); } - if (tc.fDoAdditionalInsanityChecks && tc.fRunNumberIsDetermined) { - CheckCurrentRunNumber(collision); + if (TMath::Abs(fBasePro->GetBinContent(0)) > 0.) { + LOGF(fatal, "\033[1;31m%s at line %d : In \"fBasePro\" something was filled in the underflow, check the booking of this hostogram. \033[0m", __FUNCTION__, __LINE__); + } + if (TMath::Abs(fBasePro->GetBinContent(eConfiguration_N)) > 0.) { + LOGF(fatal, "\033[1;31m%s at line %d : In \"fBasePro\" something was filled in the overflow, check the booking of this hostogram. \033[0m", __FUNCTION__, __LINE__); } - // *) Fetch the weights for this particular run number. Do it only once. - // TBI 20231012 If eventualy I can access programatically run number in init(...) at run time, this shall go there. - if (!pw.fParticleWeightsAreFetched) { - if (pw.fUseWeights[wPHI] || pw.fUseWeights[wPT] || pw.fUseWeights[wETA] || pw.fUseDiffWeights[wPHIPT] || pw.fUseDiffWeights[wPHIETA]) { - GetParticleWeights(); - pw.fParticleWeightsAreFetched = kTRUE; + // ... + + // b) Insanity checks on internal validation: + if (iv.fUseInternalValidation) { + + // **) Check that rescaling is used only when it makes sense: + if (iv.fRescaleWithTheoreticalInput && iv.fHarmonicsOptionInternalValidation->EqualTo("correlated")) { + LOGF(fatal, "\033[1;31m%s at line %d : rescaling with theoretical input doesn't make sanse for fHarmonicsOptionInternalValidation = \"correlated\". \033[0m", __FUNCTION__, __LINE__); + } + if (iv.fRescaleWithTheoreticalInput && iv.fHarmonicsOptionInternalValidation->EqualTo("persistent")) { + LOGF(fatal, "\033[1;31m%s at line %d : rescaling with theoretical input doesn't make sanse for fHarmonicsOptionInternalValidation = \"persistent\". \033[0m", __FUNCTION__, __LINE__); + } + + // **) Print a warning if this histogram is not booked: + if (!eh.fEventHistograms[eNumberOfEvents][eSim][eAfter]) { + LOGF(warning, "\033[1;31m%s at line %d : eh.fEventHistograms[eNumberOfEvents][eSim][eAfter] is not booked => no info on the total number of events in internal validation can be provided \033[0m", __FUNCTION__, __LINE__); } + + } // end of if (iv.fUseInternalValidation) { + + // ... + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); } -} // template void Preprocess(T const& collision) +} // void InsanityChecksAfterBooking() //============================================================ -template -void DetermineAndPropagateRunNumber(T const& collision) +bool Skip(int recOrSim) { - // Determine and propagate run number info to already booked objects, wherever it's relevant. - // Make sure in process(...) that this function is called only once. + // Decide here whether a certain histogram, etc., will be booked and used both for eRec and eSim. + // Same for cuts. - // TBI 20231018 At the moment I can access run number info only in process(...) via collision->bc().runNumber(), but not in init(...) - // Once I can access run number info in init(...), this function shall be called in init(...), not in process(...) + if (tc.fVerboseUtility) { + StartFunction(__FUNCTION__); + } - // a) Determine run number; - // b) Propagate run number to all booked objects, wherever that info is relevant. + // *) Insanity check: + if (!(recOrSim == eRec || recOrSim == eSim)) { + LOGF(fatal, "\033[1;31m%s at line %d : recOrSim = %d \033[0m", __FUNCTION__, __LINE__, recOrSim); + } - if (tc.fVerbose) { - // LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); // full function signature (including arguments, etc.), too verbose here... - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); // just a bare function name + // *) If I am doing internal validation, I book and fill only eSim: + if (iv.fUseInternalValidation) { + if (recOrSim == eRec) { + return true; // yes, skip + } else { + return false; // this is eSim, do not skip + } } - // a) Determine run number for reconstructed data: - tc.fRunNumber = Form("%d", collision.bc().runNumber()); // implemented for both aod::Collision and aod::McCollision, so I can use it straight, as long as I have subscribed to aod::BCs - if (tc.fRunNumber.EqualTo("")) { - LOGF(error, "\033[1;33m%s fRunNumber is empty, collision->bc().runNumber() failed...\033[0m", __PRETTY_FUNCTION__); - LOGF(fatal, "collision->bc().runNumber() = %d", collision.bc().runNumber()); + // *) If I am analyzing only reconstructed data, do not book histos for simulated, and vice versa. + // TBI 20240223 tc.fProcess[eProcessTest] is treated as tc.fProcess[eProcessRec], for the time being + if ((tc.fProcess[eGenericRec] && recOrSim == eSim) || (tc.fProcess[eGenericSim] && recOrSim == eRec)) { + return true; // yes, skip } - tc.fRunNumberIsDetermined = kTRUE; - // b) Propagate run number to all booked objects, wherever that info is relevant: - fBasePro->GetXaxis()->SetBinLabel(eRunNumber, Form("tc.fRunNumber = %s", tc.fRunNumber.Data())); - // ... + return false; // by default, I do not skip anything -} // template void DetermineAndPropagateRunNumber(T const& collision) +} // bool Skip(int recOrSim) //============================================================ -template -void CheckCurrentRunNumber(T const& collision) +void BookAndNestAllLists() { - // Insanity check for the current run number. + // *) QA; + // **) QA event histograms; + // **) QA particle histograms; + // **) QA particle event histograms; + // **) QA "correlations vs." histograms: + // **) QA "correlations vs. IR vs. " profiles; + // *) Control event histograms; + // *) Control particle histograms; + // *) Correlations; + // *) Q-vectors; + // *) Particle weights; + // *) Centrality weights; + // *) Nested loops; + // *) Toy NUA; + // *) Internal validation; + // *) Test0; + // *) Eta separations; + // *) Results. - if (!tc.fRunNumber.EqualTo(Form("%d", collision.bc().runNumber()))) { - LOGF(error, "\033[1;33m%s Run number changed within process(). This most likely indicates that a given masterjob is processing 2 or more different runs in one go.\033[0m", __PRETTY_FUNCTION__); - LOGF(fatal, "tc.fRunNumber = %s, collision.bc().runNumber() = %d", tc.fRunNumber.Data(), collision.bc().runNumber()); + if (tc.fVerbose) { + StartFunction(__FUNCTION__); } -} // template void CheckCurrentRunNumber(T const& collision) + // *) QA: + qa.fQAList = new TList(); + qa.fQAList->SetName("QA"); + qa.fQAList->SetOwner(true); + fBaseList->Add(qa.fQAList); -//============================================================ + // **) QA event histograms: + if (qa.fFillQAEventHistograms2D) { + qa.fQAEventList = new TList(); + qa.fQAEventList->SetName("QAEvent"); + qa.fQAEventList->SetOwner(true); + qa.fQAList->Add(qa.fQAEventList); // yes, this one is nested within base QA TList + } -void ResetEventByEventQuantities() -{ - // Reset all global event-by-event quantities here: + // **) QA particle histograms: + if (qa.fFillQAParticleHistograms2D) { + qa.fQAParticleList = new TList(); + qa.fQAParticleList->SetName("QAParticle"); + qa.fQAParticleList->SetOwner(true); + qa.fQAList->Add(qa.fQAParticleList); // yes, this one is nested within base QA TList + } - // a) Event-by-event quantities; - // b) Q-vectors; - // c) Reset ebe containers for nested loops; - // d) Fisher-Yates algorithm. + // **) QA particle event histograms: + if (qa.fFillQAParticleEventHistograms2D) { + qa.fQAParticleEventList = new TList(); + qa.fQAParticleEventList->SetName("QAParticleEvent"); + qa.fQAParticleEventList->SetOwner(true); + qa.fQAList->Add(qa.fQAParticleEventList); // yes, this one is nested within base QA TList + } - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + // **) QA "correlations vs." histograms: + if (qa.fFillQACorrelationsVsHistograms2D) { + qa.fQACorrelationsVsList = new TList(); + qa.fQACorrelationsVsList->SetName("QACorrelationsVs"); + qa.fQACorrelationsVsList->SetOwner(true); + qa.fQAList->Add(qa.fQACorrelationsVsList); // yes, this one is nested within base QA TList } - // a) Event-by-event quantities: - ebye.fSelectedTracks = 0; - ebye.fCentrality = 0; + // **) QA "correlations vs. IR vs. " profiles: + if (qa.fFillQACorrelationsVsInteractionRateVsProfiles2D) { + qa.fQACorrelationsVsInteractionRateVsList = new TList(); + qa.fQACorrelationsVsInteractionRateVsList->SetName("QACorrelationsVsInteractionRateVsList"); + qa.fQACorrelationsVsInteractionRateVsList->SetOwner(true); + qa.fQAList->Add(qa.fQACorrelationsVsInteractionRateVsList); // yes, this one is nested within base QA TList + } - // b) Q-vectors: - if (qv.fCalculateQvectors) { - // b0) generic Q-vector: - ResetQ(); - // b1) integrated Q-vector: - for (Int_t h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { - for (Int_t wp = 0; wp < gMaxCorrelator + 1; wp++) // weight power - { - qv.fQvector[h][wp] = TComplex(0., 0.); - } - } - // b2) diff. Q-vector: - for (Int_t bin = 1; bin <= gMaxNoBinsKine; bin++) { - qv.fqVectorEntries[PTq][bin - 1] = 0; // TBI 20240214 shall I loop also over enum's PTq and ETAq? If yes, fix it also below for qv.fqvector[PTq][bin - 1][... - qv.fqVectorEntries[ETAq][bin - 1] = 0; - for (Int_t h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { - for (Int_t wp = 0; wp < gMaxCorrelator + 1; wp++) { // weight power - qv.fqvector[PTq][bin - 1][h][wp] = TComplex(0., 0.); - qv.fqvector[ETAq][bin - 1][h][wp] = TComplex(0., 0.); - } // for (Int_t wp = 0; wp < gMaxCorrelator + 1; wp++) { // weight power - } // for (Int_t h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { - } // for (Int_t b = 0; b < gMaxNoBinsKine; b++ ) { - } // if(qv.fCalculateQvectors) + // *) Event cuts: + ec.fEventCutsList = new TList(); + ec.fEventCutsList->SetName("EventCuts"); + ec.fEventCutsList->SetOwner(true); + fBaseList->Add(ec.fEventCutsList); - // c) Reset ebe containers for nested loops: - if (nl.fCalculateNestedLoops || nl.fCalculateCustomNestedLoop) { - if (nl.ftaNestedLoops[0]) { - nl.ftaNestedLoops[0]->Reset(); - } - if (nl.ftaNestedLoops[1]) { - nl.ftaNestedLoops[1]->Reset(); - } + // *) Control event histograms: + eh.fEventHistogramsList = new TList(); + eh.fEventHistogramsList->SetName("EventHistograms"); + eh.fEventHistogramsList->SetOwner(true); + fBaseList->Add(eh.fEventHistogramsList); - // TBI 20220803 port still if(fCalculatePtCorrelations){...} and - // if(fCalculateEtaCorrelations){...} + // *) Particle cuts: + pc.fParticleCutsList = new TList(); + pc.fParticleCutsList->SetName("ParticleCuts"); + pc.fParticleCutsList->SetOwner(true); + fBaseList->Add(pc.fParticleCutsList); - } // if(nl.fCalculateNestedLoops||nl.fCalculateCustomNestedLoop) + // *) Control particle histograms: + ph.fParticleHistogramsList = new TList(); + ph.fParticleHistogramsList->SetName("ParticleHistograms"); + ph.fParticleHistogramsList->SetOwner(true); + fBaseList->Add(ph.fParticleHistogramsList); - // *) TBI 20240208 add here support for differential nested loops - /* - if(nl.fCalculateCustomNestedLoop) - { - ftaNestedLoopsKine[PTq][bin-1][0]->AddAt(dPhi,fqVectorEntries[PTq][bin-1]); - ftaNestedLoopsKine[PTq][bin-1][1]->AddAt(wPhi*wPt*wEta,fqVectorEntries[PTq][bin-1]); - } - */ + // *) Q-vectors: + qv.fQvectorList = new TList(); + qv.fQvectorList->SetName("Q-vectors"); + qv.fQvectorList->SetOwner(true); + fBaseList->Add(qv.fQvectorList); - // d) Fisher-Yates algorithm: - if (tc.fUseFisherYates) { - delete tc.fRandomIndices; - tc.fRandomIndices = NULL; - } + // *) Correlations: + mupa.fCorrelationsList = new TList(); + mupa.fCorrelationsList->SetName("Correlations"); + mupa.fCorrelationsList->SetOwner(true); + fBaseList->Add(mupa.fCorrelationsList); + + // *) Particle weights: + pw.fWeightsList = new TList(); + pw.fWeightsList->SetName("Weights"); + pw.fWeightsList->SetOwner(true); + fBaseList->Add(pw.fWeightsList); - // ... TBI 20240117 port the rest ... + // *) Centrality weights: + cw.fCentralityWeightsList = new TList(); + cw.fCentralityWeightsList->SetName("CentralityWeights"); + cw.fCentralityWeightsList->SetOwner(true); + fBaseList->Add(cw.fCentralityWeightsList); -} // void ResetEventByEventQuantities() + // *) Nested loops: + nl.fNestedLoopsList = new TList(); + nl.fNestedLoopsList->SetName("NestedLoops"); + nl.fNestedLoopsList->SetOwner(true); + fBaseList->Add(nl.fNestedLoopsList); + + // *) Toy NUA: + nua.fNUAList = new TList(); + nua.fNUAList->SetName("ToyNUA"); + nua.fNUAList->SetOwner(true); + fBaseList->Add(nua.fNUAList); + + // *) Internal validation: + iv.fInternalValidationList = new TList(); + iv.fInternalValidationList->SetName("InternalValidation"); + iv.fInternalValidationList->SetOwner(true); + fBaseList->Add(iv.fInternalValidationList); + + // *) Test0: + t0.fTest0List = new TList(); + t0.fTest0List->SetName("Test0"); + t0.fTest0List->SetOwner(true); + fBaseList->Add(t0.fTest0List); + + // *) Eta separations: + es.fEtaSeparationsList = new TList(); + es.fEtaSeparationsList->SetName("EtaSeparations"); + es.fEtaSeparationsList->SetOwner(true); + fBaseList->Add(es.fEtaSeparationsList); + + // *) Results: + res.fResultsList = new TList(); + res.fResultsList->SetName("Results"); + res.fResultsList->SetOwner(true); + fBaseList->Add(res.fResultsList); + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void BookAndNestAllLists() //============================================================ -template -Bool_t EventCuts(T1 const& collision, T2 const& tracks) +void BookQAHistograms() { - // Event cuts on reconstructed and simulated data. + // Book all QA histograms and other related objects. + + // TBI 20240520 There is a bit of code bloat here - I could introduce a new enum eEventParticle, and then use eEvent = 0 and eParticle = 1 - // *) Offline trigger; - // *) sel7() and sel8(); TBI 20240223 sort out eventualy; - // *) Specific direct event cuts on info available in reconstructed (and corresponding MC truth simulated); - // *) Specific direct event cuts on info available only in simulated data; - // *) Test case. + // a) Book the profile holding flags; + // b) Common local variables; + // c) Book specific QA 2D event histograms; + // d) Book specific QA 2D particle histograms; + // e) Book specific QA 2D particle event histograms; + // f) Book specific QA 2D "correlations vs." histograms; + // g) Book specific QA 2D "correlations vs. IR vs. " profiles. if (tc.fVerbose) { - // LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); // full function signature (including arguments, etc.), too verbose here... - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); // just a bare function name + StartFunction(__FUNCTION__); } - // *) Offline trigger: - // From documentation: Bypass this check if you analyse MC or continuous Run3 data. - // In addition: remember that I can use it only for process cases where I have joined aod::Collisions with aod::EvSels - if constexpr (rs == eRec_Run2 || rs == eRec_Run1) { - if (ec.fUseTrigger) { - if (ec.fTrigger.EqualTo("kINT7")) { - if (!collision.alias_bit(kINT7)) { - if (tc.fVerbose) { - LOGF(info, "\033[1;31m%s collision.alias_bit(kINT7)\033[0m", __FUNCTION__); // just a bare function name - LOGF(info, "\033[1;31m%s Bypass this check if you analyse MC or continuous Run3 data.\033[0m", __FUNCTION__); // just a bare function name - } - return kFALSE; - } - } - } + // *) Print the warning message, because with too many 2D histograms with double precision, the code crashes in terminate, due to: + /* + [1450742:multiparticle-correlations-a-b]: [13:30:27][STATE] Exiting FairMQ state machine + [1450742:multiparticle-correlations-a-b]: [13:30:27][FATAL] error while setting up workflow in o2-analysis-cf-multiparticle-correlations-ab: shmem: could not create a message of size 1282720912, alignment: 64, free memory: 1358639296 + [1450742:multiparticle-correlations-a-b]: terminate called after throwing an instance of 'o2::framework::RuntimeErrorRef' + [1450742:multiparticle-correlations-a-b]: *** Program crashed (Aborted) + [1450742:multiparticle-correlations-a-b]: Backtrace by DPL: + */ + if (tc.fVerbose) { + LOGF(info, "\033[1;33m%s: !!!! WARNING !!!! With too many 2D histograms with double precision, the code will crash in terminate (\"... shmem: could not create a message of size ...\") . Locally, you can circumvent this while testing by calling Bailout() explicitly. !!!! WARNING !!!! \033[0m", __FUNCTION__); } - // *) sel7() and sel8(); TBI 20240223 sort out eventualy: - // if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1 || rs == eSim_Run1) { - if constexpr (rs == eRec_Run2 || rs == eRec_Run1) { // TBI 20240223 use the line above, after I join aod::Collisions with aod::EvSels also for RecSim and Sim cases for Run 2 and Run 1 - if (ec.fUseSel7) { // from doc: for Run 2 data and MC - if (!collision.sel7()) { - if (tc.fVerbose) { - LOGF(info, "\033[1;31m%s collision.sel7()\033[0m", __FUNCTION__); // just a bare function name - } - return kFALSE; - } - } - } - // if constexpr (rs == eRec || rs == eRecAndSim || rs == eSim) { - if constexpr (rs == eRec || rs == eRecAndSim) { // TBI 20240223 use the line above, after I join aod::Collisions with aod::EvSels also for Sim case for Run 3 - if (ec.fUseSel8) { // from doc: for Run 3 data and MC - if (!collision.sel8()) { - if (tc.fVerbose) { - LOGF(info, "\033[1;31m%s collision.sel8()\033[0m", __FUNCTION__); // just a bare function name - } - return kFALSE; - } - } - } + // a) Book the profile holding flags: + qa.fQAHistogramsPro = new TProfile("fQAHistogramsPro", "flags for QA histograms", 7, 0., 7.); + qa.fQAHistogramsPro->SetStats(false); + qa.fQAHistogramsPro->SetLineColor(eColor); + qa.fQAHistogramsPro->SetFillColor(eFillColor); + qa.fQAHistogramsPro->GetXaxis()->SetBinLabel(1, "fCheckUnderflowAndOverflow"); + qa.fQAHistogramsPro->Fill(0.5, static_cast(qa.fCheckUnderflowAndOverflow)); + qa.fQAHistogramsPro->GetXaxis()->SetBinLabel(2, "fFillQAEventHistograms2D"); + qa.fQAHistogramsPro->Fill(1.5, static_cast(qa.fFillQAEventHistograms2D)); + qa.fQAHistogramsPro->GetXaxis()->SetBinLabel(3, "fFillQAParticleHistograms2D"); + qa.fQAHistogramsPro->Fill(2.5, static_cast(qa.fFillQAParticleHistograms2D)); + qa.fQAHistogramsPro->GetXaxis()->SetBinLabel(4, "fFillQAParticleEventHistograms2D"); + qa.fQAHistogramsPro->Fill(3.5, static_cast(qa.fFillQAParticleEventHistograms2D)); + qa.fQAHistogramsPro->GetXaxis()->SetBinLabel(5, "fFillQACorrelationsVsHistograms2D"); + qa.fQAHistogramsPro->Fill(4.5, static_cast(qa.fFillQACorrelationsVsHistograms2D)); + qa.fQAHistogramsPro->GetXaxis()->SetBinLabel(6, "fFillQACorrelationsVsInteractionRateVsProfiles2D"); + qa.fQAHistogramsPro->Fill(5.5, static_cast(qa.fFillQACorrelationsVsInteractionRateVsProfiles2D)); + qa.fQAHistogramsPro->GetXaxis()->SetBinLabel(7, "fRebin"); + qa.fQAHistogramsPro->Fill(6.5, static_cast(qa.fRebin)); - // *) Specific direct event cuts on info available in reconstructed ...: - if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { - // *) NumberOfEvents: => cut directly in void process( ... ) - // *) TotalMultiplicity: - if ((tracks.size() < eh.fEventCuts[eTotalMultiplicity][eMin]) || - (tracks.size() > eh.fEventCuts[eTotalMultiplicity][eMax])) { - if (tc.fVerbose) { - LOGF(info, "\033[1;31m%s eTotalMultiplicity\033[0m", __FUNCTION__); // just a bare function name - } - return kFALSE; - } - // *) SelectedTracks: => cut directly in void process( ... ) + // ... - // *) Centrtality: - if ((ebye.fCentrality < eh.fEventCuts[eCentrality][eMin]) || (ebye.fCentrality > eh.fEventCuts[eCentrality][eMax])) { - if (tc.fVerbose) { - LOGF(info, "\033[1;31m%s eCentrality\033[0m", __FUNCTION__); // just a bare function name - } - return kFALSE; + qa.fQAList->Add(qa.fQAHistogramsPro); + + // b) Common local variables: + // ... + + // c) Book specific QA 2D event histograms: + // Binning of 2D event histos: TBI 20240503 see if you can automate all this + int nBins_x_Event[eQAEventHistograms2D_N] = {0}; + double min_x_Event[eQAEventHistograms2D_N] = {0.}; + double max_x_Event[eQAEventHistograms2D_N] = {0.}; + TString title_x_Event[eQAEventHistograms2D_N] = {""}; + int nBins_y_Event[eQAEventHistograms2D_N] = {0}; + double min_y_Event[eQAEventHistograms2D_N] = {0.}; + double max_y_Event[eQAEventHistograms2D_N] = {0.}; + TString title_y_Event[eQAEventHistograms2D_N] = {""}; + + // *) "Multiplicity_vs_ReferenceMultiplicity": + nBins_x_Event[eMultiplicity_vs_ReferenceMultiplicity] = static_cast(eh.fEventHistogramsBins[eMultiplicity][0] / qa.fRebin); + min_x_Event[eMultiplicity_vs_ReferenceMultiplicity] = eh.fEventHistogramsBins[eMultiplicity][1]; + max_x_Event[eMultiplicity_vs_ReferenceMultiplicity] = eh.fEventHistogramsBins[eMultiplicity][2]; + title_x_Event[eMultiplicity_vs_ReferenceMultiplicity] = FancyFormatting(eh.fEventHistogramsName[eMultiplicity].Data()); + nBins_y_Event[eMultiplicity_vs_ReferenceMultiplicity] = static_cast(eh.fEventHistogramsBins[eReferenceMultiplicity][0] / qa.fRebin); + min_y_Event[eMultiplicity_vs_ReferenceMultiplicity] = eh.fEventHistogramsBins[eReferenceMultiplicity][1]; + max_y_Event[eMultiplicity_vs_ReferenceMultiplicity] = eh.fEventHistogramsBins[eReferenceMultiplicity][2]; + title_y_Event[eMultiplicity_vs_ReferenceMultiplicity] = FancyFormatting(eh.fEventHistogramsName[eReferenceMultiplicity].Data()); + + // *) "Multiplicity_vs_NContributors": + nBins_x_Event[eMultiplicity_vs_NContributors] = static_cast(eh.fEventHistogramsBins[eMultiplicity][0] / qa.fRebin); + min_x_Event[eMultiplicity_vs_NContributors] = eh.fEventHistogramsBins[eMultiplicity][1]; + max_x_Event[eMultiplicity_vs_NContributors] = eh.fEventHistogramsBins[eMultiplicity][2]; + title_x_Event[eMultiplicity_vs_NContributors] = FancyFormatting(eh.fEventHistogramsName[eMultiplicity].Data()); + nBins_y_Event[eMultiplicity_vs_NContributors] = static_cast(eh.fEventHistogramsBins[eNContributors][0] / qa.fRebin); + min_y_Event[eMultiplicity_vs_NContributors] = eh.fEventHistogramsBins[eNContributors][1]; + max_y_Event[eMultiplicity_vs_NContributors] = eh.fEventHistogramsBins[eNContributors][2]; + title_y_Event[eMultiplicity_vs_NContributors] = FancyFormatting(eh.fEventHistogramsName[eNContributors].Data()); + + // *) "Multiplicity_vs_Centrality": + nBins_x_Event[eMultiplicity_vs_Centrality] = static_cast(eh.fEventHistogramsBins[eMultiplicity][0] / qa.fRebin); + min_x_Event[eMultiplicity_vs_Centrality] = eh.fEventHistogramsBins[eMultiplicity][1]; + max_x_Event[eMultiplicity_vs_Centrality] = eh.fEventHistogramsBins[eMultiplicity][2]; + title_x_Event[eMultiplicity_vs_Centrality] = FancyFormatting(eh.fEventHistogramsName[eMultiplicity].Data()); + nBins_y_Event[eMultiplicity_vs_Centrality] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_y_Event[eMultiplicity_vs_Centrality] = eh.fEventHistogramsBins[eCentrality][1]; + max_y_Event[eMultiplicity_vs_Centrality] = eh.fEventHistogramsBins[eCentrality][2]; + title_y_Event[eMultiplicity_vs_Centrality] = FancyFormatting(eh.fEventHistogramsName[eCentrality].Data()); + + // *) "Multiplicity_vs_VertexZ": + nBins_x_Event[eMultiplicity_vs_VertexZ] = static_cast(eh.fEventHistogramsBins[eMultiplicity][0] / qa.fRebin); + min_x_Event[eMultiplicity_vs_VertexZ] = eh.fEventHistogramsBins[eMultiplicity][1]; + max_x_Event[eMultiplicity_vs_VertexZ] = eh.fEventHistogramsBins[eMultiplicity][2]; + title_x_Event[eMultiplicity_vs_VertexZ] = FancyFormatting(eh.fEventHistogramsName[eMultiplicity].Data()); + nBins_y_Event[eMultiplicity_vs_VertexZ] = static_cast(eh.fEventHistogramsBins[eVertexZ][0]); + min_y_Event[eMultiplicity_vs_VertexZ] = eh.fEventHistogramsBins[eVertexZ][1]; + max_y_Event[eMultiplicity_vs_VertexZ] = eh.fEventHistogramsBins[eVertexZ][2]; + title_y_Event[eMultiplicity_vs_VertexZ] = FancyFormatting(eh.fEventHistogramsName[eVertexZ].Data()); + + // *) "Multiplicity_vs_Occupancy": + nBins_x_Event[eMultiplicity_vs_Occupancy] = static_cast(eh.fEventHistogramsBins[eMultiplicity][0] / qa.fRebin); + min_x_Event[eMultiplicity_vs_Occupancy] = eh.fEventHistogramsBins[eMultiplicity][1]; + max_x_Event[eMultiplicity_vs_Occupancy] = eh.fEventHistogramsBins[eMultiplicity][2]; + title_x_Event[eMultiplicity_vs_Occupancy] = FancyFormatting(eh.fEventHistogramsName[eMultiplicity].Data()); + nBins_y_Event[eMultiplicity_vs_Occupancy] = static_cast(eh.fEventHistogramsBins[eOccupancy][0] / qa.fRebin); + min_y_Event[eMultiplicity_vs_Occupancy] = eh.fEventHistogramsBins[eOccupancy][1]; + max_y_Event[eMultiplicity_vs_Occupancy] = eh.fEventHistogramsBins[eOccupancy][2]; + title_y_Event[eMultiplicity_vs_Occupancy] = FancyFormatting(eh.fEventHistogramsName[eOccupancy].Data()); + + // *) "Multiplicity_vs_InteractionRate": + nBins_x_Event[eMultiplicity_vs_InteractionRate] = static_cast(eh.fEventHistogramsBins[eMultiplicity][0] / qa.fRebin); + min_x_Event[eMultiplicity_vs_InteractionRate] = eh.fEventHistogramsBins[eMultiplicity][1]; + max_x_Event[eMultiplicity_vs_InteractionRate] = eh.fEventHistogramsBins[eMultiplicity][2]; + title_x_Event[eMultiplicity_vs_InteractionRate] = FancyFormatting(eh.fEventHistogramsName[eMultiplicity].Data()); + nBins_y_Event[eMultiplicity_vs_InteractionRate] = static_cast(eh.fEventHistogramsBins[eInteractionRate][0] / qa.fRebin); + min_y_Event[eMultiplicity_vs_InteractionRate] = eh.fEventHistogramsBins[eInteractionRate][1]; + max_y_Event[eMultiplicity_vs_InteractionRate] = eh.fEventHistogramsBins[eInteractionRate][2]; + title_y_Event[eMultiplicity_vs_InteractionRate] = FancyFormatting(eh.fEventHistogramsName[eInteractionRate].Data()); + + // *) "ReferenceMultiplicity_vs_NContributors": // TBI 20250401 I use this one to calculate quantiles for HMO cut, therefore I keep it refined for the time being + nBins_x_Event[eReferenceMultiplicity_vs_NContributors] = static_cast(eh.fEventHistogramsBins[eReferenceMultiplicity][0]); + min_x_Event[eReferenceMultiplicity_vs_NContributors] = eh.fEventHistogramsBins[eReferenceMultiplicity][1]; + max_x_Event[eReferenceMultiplicity_vs_NContributors] = eh.fEventHistogramsBins[eReferenceMultiplicity][2]; + title_x_Event[eReferenceMultiplicity_vs_NContributors] = FancyFormatting(eh.fEventHistogramsName[eReferenceMultiplicity].Data()); + nBins_y_Event[eReferenceMultiplicity_vs_NContributors] = static_cast(eh.fEventHistogramsBins[eNContributors][0]); + min_y_Event[eReferenceMultiplicity_vs_NContributors] = eh.fEventHistogramsBins[eNContributors][1]; + max_y_Event[eReferenceMultiplicity_vs_NContributors] = eh.fEventHistogramsBins[eNContributors][2]; + title_y_Event[eReferenceMultiplicity_vs_NContributors] = FancyFormatting(eh.fEventHistogramsName[eNContributors].Data()); + + // *) "ReferenceMultiplicity_vs_Centrality": + nBins_x_Event[eReferenceMultiplicity_vs_Centrality] = static_cast(eh.fEventHistogramsBins[eReferenceMultiplicity][0] / qa.fRebin); + min_x_Event[eReferenceMultiplicity_vs_Centrality] = eh.fEventHistogramsBins[eReferenceMultiplicity][1]; + max_x_Event[eReferenceMultiplicity_vs_Centrality] = eh.fEventHistogramsBins[eReferenceMultiplicity][2]; + title_x_Event[eReferenceMultiplicity_vs_Centrality] = FancyFormatting(eh.fEventHistogramsName[eReferenceMultiplicity].Data()); + nBins_y_Event[eReferenceMultiplicity_vs_Centrality] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_y_Event[eReferenceMultiplicity_vs_Centrality] = eh.fEventHistogramsBins[eCentrality][1]; + max_y_Event[eReferenceMultiplicity_vs_Centrality] = eh.fEventHistogramsBins[eCentrality][2]; + title_y_Event[eReferenceMultiplicity_vs_Centrality] = FancyFormatting(eh.fEventHistogramsName[eCentrality].Data()); + + // *) "ReferenceMultiplicity_vs_VertexZ": + nBins_x_Event[eReferenceMultiplicity_vs_VertexZ] = static_cast(eh.fEventHistogramsBins[eReferenceMultiplicity][0] / qa.fRebin); + min_x_Event[eReferenceMultiplicity_vs_VertexZ] = eh.fEventHistogramsBins[eReferenceMultiplicity][1]; + max_x_Event[eReferenceMultiplicity_vs_VertexZ] = eh.fEventHistogramsBins[eReferenceMultiplicity][2]; + title_x_Event[eReferenceMultiplicity_vs_VertexZ] = FancyFormatting(eh.fEventHistogramsName[eReferenceMultiplicity].Data()); + nBins_y_Event[eReferenceMultiplicity_vs_VertexZ] = static_cast(eh.fEventHistogramsBins[eVertexZ][0]); + min_y_Event[eReferenceMultiplicity_vs_VertexZ] = eh.fEventHistogramsBins[eVertexZ][1]; + max_y_Event[eReferenceMultiplicity_vs_VertexZ] = eh.fEventHistogramsBins[eVertexZ][2]; + title_y_Event[eReferenceMultiplicity_vs_VertexZ] = FancyFormatting(eh.fEventHistogramsName[eVertexZ].Data()); + + // *) "ReferenceMultiplicity_vs_Occupancy": + nBins_x_Event[eReferenceMultiplicity_vs_Occupancy] = static_cast(eh.fEventHistogramsBins[eReferenceMultiplicity][0] / qa.fRebin); + min_x_Event[eReferenceMultiplicity_vs_Occupancy] = eh.fEventHistogramsBins[eReferenceMultiplicity][1]; + max_x_Event[eReferenceMultiplicity_vs_Occupancy] = eh.fEventHistogramsBins[eReferenceMultiplicity][2]; + title_x_Event[eReferenceMultiplicity_vs_Occupancy] = FancyFormatting(eh.fEventHistogramsName[eReferenceMultiplicity].Data()); + nBins_y_Event[eReferenceMultiplicity_vs_Occupancy] = static_cast(eh.fEventHistogramsBins[eOccupancy][0] / qa.fRebin); + min_y_Event[eReferenceMultiplicity_vs_Occupancy] = eh.fEventHistogramsBins[eOccupancy][1]; + max_y_Event[eReferenceMultiplicity_vs_Occupancy] = eh.fEventHistogramsBins[eOccupancy][2]; + title_y_Event[eReferenceMultiplicity_vs_Occupancy] = FancyFormatting(eh.fEventHistogramsName[eOccupancy].Data()); + + // *) "ReferenceMultiplicity_vs_InteractionRate": + nBins_x_Event[eReferenceMultiplicity_vs_InteractionRate] = static_cast(eh.fEventHistogramsBins[eReferenceMultiplicity][0] / qa.fRebin); + min_x_Event[eReferenceMultiplicity_vs_InteractionRate] = eh.fEventHistogramsBins[eReferenceMultiplicity][1]; + max_x_Event[eReferenceMultiplicity_vs_InteractionRate] = eh.fEventHistogramsBins[eReferenceMultiplicity][2]; + title_x_Event[eReferenceMultiplicity_vs_InteractionRate] = FancyFormatting(eh.fEventHistogramsName[eReferenceMultiplicity].Data()); + nBins_y_Event[eReferenceMultiplicity_vs_InteractionRate] = static_cast(eh.fEventHistogramsBins[eInteractionRate][0] / qa.fRebin); + min_y_Event[eReferenceMultiplicity_vs_InteractionRate] = eh.fEventHistogramsBins[eInteractionRate][1]; + max_y_Event[eReferenceMultiplicity_vs_InteractionRate] = eh.fEventHistogramsBins[eInteractionRate][2]; + title_y_Event[eReferenceMultiplicity_vs_InteractionRate] = FancyFormatting(eh.fEventHistogramsName[eInteractionRate].Data()); + + // *) "NContributors_vs_Centrality": + nBins_x_Event[eNContributors_vs_Centrality] = static_cast(eh.fEventHistogramsBins[eNContributors][0] / qa.fRebin); + min_x_Event[eNContributors_vs_Centrality] = eh.fEventHistogramsBins[eNContributors][1]; + max_x_Event[eNContributors_vs_Centrality] = eh.fEventHistogramsBins[eNContributors][2]; + title_x_Event[eNContributors_vs_Centrality] = FancyFormatting(eh.fEventHistogramsName[eNContributors].Data()); + nBins_y_Event[eNContributors_vs_Centrality] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_y_Event[eNContributors_vs_Centrality] = eh.fEventHistogramsBins[eCentrality][1]; + max_y_Event[eNContributors_vs_Centrality] = eh.fEventHistogramsBins[eCentrality][2]; + title_y_Event[eNContributors_vs_Centrality] = FancyFormatting(eh.fEventHistogramsName[eCentrality].Data()); + + // *) "NContributors_vs_VertexZ": + nBins_x_Event[eNContributors_vs_VertexZ] = static_cast(eh.fEventHistogramsBins[eNContributors][0] / qa.fRebin); + min_x_Event[eNContributors_vs_VertexZ] = eh.fEventHistogramsBins[eNContributors][1]; + max_x_Event[eNContributors_vs_VertexZ] = eh.fEventHistogramsBins[eNContributors][2]; + title_x_Event[eNContributors_vs_VertexZ] = FancyFormatting(eh.fEventHistogramsName[eNContributors].Data()); + nBins_y_Event[eNContributors_vs_VertexZ] = static_cast(eh.fEventHistogramsBins[eVertexZ][0]); + min_y_Event[eNContributors_vs_VertexZ] = eh.fEventHistogramsBins[eVertexZ][1]; + max_y_Event[eNContributors_vs_VertexZ] = eh.fEventHistogramsBins[eVertexZ][2]; + title_y_Event[eNContributors_vs_VertexZ] = FancyFormatting(eh.fEventHistogramsName[eVertexZ].Data()); + + // *) "NContributors_vs_Occupancy": + nBins_x_Event[eNContributors_vs_Occupancy] = static_cast(eh.fEventHistogramsBins[eNContributors][0] / qa.fRebin); + min_x_Event[eNContributors_vs_Occupancy] = eh.fEventHistogramsBins[eNContributors][1]; + max_x_Event[eNContributors_vs_Occupancy] = eh.fEventHistogramsBins[eNContributors][2]; + title_x_Event[eNContributors_vs_Occupancy] = FancyFormatting(eh.fEventHistogramsName[eNContributors].Data()); + nBins_y_Event[eNContributors_vs_Occupancy] = static_cast(eh.fEventHistogramsBins[eOccupancy][0] / qa.fRebin); + min_y_Event[eNContributors_vs_Occupancy] = eh.fEventHistogramsBins[eOccupancy][1]; + max_y_Event[eNContributors_vs_Occupancy] = eh.fEventHistogramsBins[eOccupancy][2]; + title_y_Event[eNContributors_vs_Occupancy] = FancyFormatting(eh.fEventHistogramsName[eOccupancy].Data()); + + // *) "NContributors_vs_InteractionRate": + nBins_x_Event[eNContributors_vs_InteractionRate] = static_cast(eh.fEventHistogramsBins[eNContributors][0] / qa.fRebin); + min_x_Event[eNContributors_vs_InteractionRate] = eh.fEventHistogramsBins[eNContributors][1]; + max_x_Event[eNContributors_vs_InteractionRate] = eh.fEventHistogramsBins[eNContributors][2]; + title_x_Event[eNContributors_vs_InteractionRate] = FancyFormatting(eh.fEventHistogramsName[eNContributors].Data()); + nBins_y_Event[eNContributors_vs_InteractionRate] = static_cast(eh.fEventHistogramsBins[eInteractionRate][0] / qa.fRebin); + min_y_Event[eNContributors_vs_InteractionRate] = eh.fEventHistogramsBins[eInteractionRate][1]; + max_y_Event[eNContributors_vs_InteractionRate] = eh.fEventHistogramsBins[eInteractionRate][2]; + title_y_Event[eNContributors_vs_InteractionRate] = FancyFormatting(eh.fEventHistogramsName[eInteractionRate].Data()); + + // *) "Centrality_vs_VertexZ": + nBins_x_Event[eCentrality_vs_VertexZ] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_x_Event[eCentrality_vs_VertexZ] = eh.fEventHistogramsBins[eCentrality][1]; + max_x_Event[eCentrality_vs_VertexZ] = eh.fEventHistogramsBins[eCentrality][2]; + title_x_Event[eCentrality_vs_VertexZ] = FancyFormatting(eh.fEventHistogramsName[eCentrality].Data()); + nBins_y_Event[eCentrality_vs_VertexZ] = static_cast(eh.fEventHistogramsBins[eVertexZ][0]); + min_y_Event[eCentrality_vs_VertexZ] = eh.fEventHistogramsBins[eVertexZ][1]; + max_y_Event[eCentrality_vs_VertexZ] = eh.fEventHistogramsBins[eVertexZ][2]; + title_y_Event[eCentrality_vs_VertexZ] = FancyFormatting(eh.fEventHistogramsName[eVertexZ].Data()); + + // *) "Centrality_vs_Occupancy": + nBins_x_Event[eCentrality_vs_Occupancy] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_x_Event[eCentrality_vs_Occupancy] = eh.fEventHistogramsBins[eCentrality][1]; + max_x_Event[eCentrality_vs_Occupancy] = eh.fEventHistogramsBins[eCentrality][2]; + title_x_Event[eCentrality_vs_Occupancy] = FancyFormatting(eh.fEventHistogramsName[eCentrality].Data()); + nBins_y_Event[eCentrality_vs_Occupancy] = static_cast(eh.fEventHistogramsBins[eOccupancy][0] / qa.fRebin); + min_y_Event[eCentrality_vs_Occupancy] = eh.fEventHistogramsBins[eOccupancy][1]; + max_y_Event[eCentrality_vs_Occupancy] = eh.fEventHistogramsBins[eOccupancy][2]; + title_y_Event[eCentrality_vs_Occupancy] = FancyFormatting(eh.fEventHistogramsName[eOccupancy].Data()); + + // *) "Centrality_vs_ImpactParameter": + nBins_x_Event[eCentrality_vs_ImpactParameter] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_x_Event[eCentrality_vs_ImpactParameter] = eh.fEventHistogramsBins[eCentrality][1]; + max_x_Event[eCentrality_vs_ImpactParameter] = eh.fEventHistogramsBins[eCentrality][2]; + title_x_Event[eCentrality_vs_ImpactParameter] = FancyFormatting(eh.fEventHistogramsName[eCentrality].Data()); + nBins_y_Event[eCentrality_vs_ImpactParameter] = static_cast(eh.fEventHistogramsBins[eImpactParameter][0] / qa.fRebin); + min_y_Event[eCentrality_vs_ImpactParameter] = eh.fEventHistogramsBins[eImpactParameter][1]; + max_y_Event[eCentrality_vs_ImpactParameter] = eh.fEventHistogramsBins[eImpactParameter][2]; + title_y_Event[eCentrality_vs_ImpactParameter] = FancyFormatting(eh.fEventHistogramsName[eImpactParameter].Data()); + + // *) "Centrality_vs_InteractionRate": + nBins_x_Event[eCentrality_vs_InteractionRate] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_x_Event[eCentrality_vs_InteractionRate] = eh.fEventHistogramsBins[eCentrality][1]; + max_x_Event[eCentrality_vs_InteractionRate] = eh.fEventHistogramsBins[eCentrality][2]; + title_x_Event[eCentrality_vs_InteractionRate] = FancyFormatting(eh.fEventHistogramsName[eCentrality].Data()); + nBins_y_Event[eCentrality_vs_InteractionRate] = static_cast(eh.fEventHistogramsBins[eInteractionRate][0] / qa.fRebin); + min_y_Event[eCentrality_vs_InteractionRate] = eh.fEventHistogramsBins[eInteractionRate][1]; + max_y_Event[eCentrality_vs_InteractionRate] = eh.fEventHistogramsBins[eInteractionRate][2]; + title_y_Event[eCentrality_vs_InteractionRate] = FancyFormatting(eh.fEventHistogramsName[eInteractionRate].Data()); + + // *) "VertexZ_vs_Occupancy": + nBins_x_Event[eVertexZ_vs_Occupancy] = static_cast(eh.fEventHistogramsBins[eVertexZ][0]); + min_x_Event[eVertexZ_vs_Occupancy] = eh.fEventHistogramsBins[eVertexZ][1]; + max_x_Event[eVertexZ_vs_Occupancy] = eh.fEventHistogramsBins[eVertexZ][2]; + title_x_Event[eVertexZ_vs_Occupancy] = FancyFormatting(eh.fEventHistogramsName[eVertexZ].Data()); + nBins_y_Event[eVertexZ_vs_Occupancy] = static_cast(eh.fEventHistogramsBins[eOccupancy][0] / qa.fRebin); + min_y_Event[eVertexZ_vs_Occupancy] = eh.fEventHistogramsBins[eOccupancy][1]; + max_y_Event[eVertexZ_vs_Occupancy] = eh.fEventHistogramsBins[eOccupancy][2]; + title_y_Event[eVertexZ_vs_Occupancy] = FancyFormatting(eh.fEventHistogramsName[eOccupancy].Data()); + + // *) "VertexZ_vs_InteractionRate": + nBins_x_Event[eVertexZ_vs_InteractionRate] = static_cast(eh.fEventHistogramsBins[eVertexZ][0]); + min_x_Event[eVertexZ_vs_InteractionRate] = eh.fEventHistogramsBins[eVertexZ][1]; + max_x_Event[eVertexZ_vs_InteractionRate] = eh.fEventHistogramsBins[eVertexZ][2]; + title_x_Event[eVertexZ_vs_InteractionRate] = FancyFormatting(eh.fEventHistogramsName[eVertexZ].Data()); + nBins_y_Event[eVertexZ_vs_InteractionRate] = static_cast(eh.fEventHistogramsBins[eInteractionRate][0] / qa.fRebin); + min_y_Event[eVertexZ_vs_InteractionRate] = eh.fEventHistogramsBins[eInteractionRate][1]; + max_y_Event[eVertexZ_vs_InteractionRate] = eh.fEventHistogramsBins[eInteractionRate][2]; + title_y_Event[eVertexZ_vs_InteractionRate] = FancyFormatting(eh.fEventHistogramsName[eInteractionRate].Data()); + + // *) "Multiplicity_vs_FT0CAmplitudeOnFoundBC": + // nBins_x_Event[eMultiplicity_vs_FT0CAmplitudeOnFoundBC] = static_cast(eh.fEventHistogramsBins[eMultiplicity][0]); + nBins_x_Event[eMultiplicity_vs_FT0CAmplitudeOnFoundBC] = 2000.; // TBI 20250331 hardwired value + min_x_Event[eMultiplicity_vs_FT0CAmplitudeOnFoundBC] = eh.fEventHistogramsBins[eMultiplicity][1]; + max_x_Event[eMultiplicity_vs_FT0CAmplitudeOnFoundBC] = eh.fEventHistogramsBins[eMultiplicity][2]; + title_x_Event[eMultiplicity_vs_FT0CAmplitudeOnFoundBC] = FancyFormatting(eh.fEventHistogramsName[eMultiplicity].Data()); + nBins_y_Event[eMultiplicity_vs_FT0CAmplitudeOnFoundBC] = 1000; // TBI 20250331 hardwired value + min_y_Event[eMultiplicity_vs_FT0CAmplitudeOnFoundBC] = 0.; // TBI 20250331 hardwired value + max_y_Event[eMultiplicity_vs_FT0CAmplitudeOnFoundBC] = 100000.; // TBI 20250331 hardwired value + title_y_Event[eMultiplicity_vs_FT0CAmplitudeOnFoundBC] = "FT0CAmplitudeOnFoundBC"; // TBI 20250331 hardwired string + + // *) "CentFT0C_vs_FT0CAmplitudeOnFoundBC": + nBins_x_Event[eCentFT0C_vs_FT0CAmplitudeOnFoundBC] = eh.fEventHistogramsBins[eCentrality][0]; // yes, eCentrality, not eCentFT0C, just think of it ! + min_x_Event[eCentFT0C_vs_FT0CAmplitudeOnFoundBC] = eh.fEventHistogramsBins[eCentrality][1]; + max_x_Event[eCentFT0C_vs_FT0CAmplitudeOnFoundBC] = eh.fEventHistogramsBins[eCentrality][2]; + title_x_Event[eCentFT0C_vs_FT0CAmplitudeOnFoundBC] = FancyFormatting(qa.fCentralityEstimatorName[eCentFT0C].Data()); + nBins_y_Event[eCentFT0C_vs_FT0CAmplitudeOnFoundBC] = 1000; // TBI 20250331 hardwired value + min_y_Event[eCentFT0C_vs_FT0CAmplitudeOnFoundBC] = 0.; // TBI 20250331 hardwired value + max_y_Event[eCentFT0C_vs_FT0CAmplitudeOnFoundBC] = 100000.; // TBI 20250331 hardwired value + title_y_Event[eCentFT0C_vs_FT0CAmplitudeOnFoundBC] = "FT0CAmplitudeOnFoundBC"; // TBI 20250331 hardwired string + + // *) "MultNTracksPV_vs_MultNTracksGlobal": + nBins_x_Event[eMultNTracksPV_vs_MultNTracksGlobal] = static_cast(eh.fEventHistogramsBins[eMultiplicity][0] / qa.fRebin); + min_x_Event[eMultNTracksPV_vs_MultNTracksGlobal] = eh.fEventHistogramsBins[eMultiplicity][1]; + max_x_Event[eMultNTracksPV_vs_MultNTracksGlobal] = eh.fEventHistogramsBins[eMultiplicity][2]; + title_x_Event[eMultNTracksPV_vs_MultNTracksGlobal] = FancyFormatting(qa.fReferenceMultiplicityEstimatorName[eMultNTracksPV].Data()); + nBins_y_Event[eMultNTracksPV_vs_MultNTracksGlobal] = static_cast(eh.fEventHistogramsBins[eMultiplicity][0] / qa.fRebin); + min_y_Event[eMultNTracksPV_vs_MultNTracksGlobal] = eh.fEventHistogramsBins[eMultiplicity][1]; + max_y_Event[eMultNTracksPV_vs_MultNTracksGlobal] = eh.fEventHistogramsBins[eMultiplicity][2]; + title_y_Event[eMultNTracksPV_vs_MultNTracksGlobal] = FancyFormatting(qa.fReferenceMultiplicityEstimatorName[eMultNTracksGlobal].Data()); + + // *) "CentFT0C_vs_CentFT0CVariant1": + nBins_x_Event[eCentFT0C_vs_CentFT0CVariant1] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_x_Event[eCentFT0C_vs_CentFT0CVariant1] = eh.fEventHistogramsBins[eCentrality][1]; + max_x_Event[eCentFT0C_vs_CentFT0CVariant1] = eh.fEventHistogramsBins[eCentrality][2]; + title_x_Event[eCentFT0C_vs_CentFT0CVariant1] = FancyFormatting(qa.fCentralityEstimatorName[eCentFT0C].Data()); + nBins_y_Event[eCentFT0C_vs_CentFT0CVariant1] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_y_Event[eCentFT0C_vs_CentFT0CVariant1] = eh.fEventHistogramsBins[eCentrality][1]; + max_y_Event[eCentFT0C_vs_CentFT0CVariant1] = eh.fEventHistogramsBins[eCentrality][2]; + title_y_Event[eCentFT0C_vs_CentFT0CVariant1] = FancyFormatting(qa.fCentralityEstimatorName[eCentFT0CVariant1].Data()); + + // *) "CentFT0C_vs_CentFT0M": + nBins_x_Event[eCentFT0C_vs_CentFT0M] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_x_Event[eCentFT0C_vs_CentFT0M] = eh.fEventHistogramsBins[eCentrality][1]; + max_x_Event[eCentFT0C_vs_CentFT0M] = eh.fEventHistogramsBins[eCentrality][2]; + title_x_Event[eCentFT0C_vs_CentFT0M] = FancyFormatting(qa.fCentralityEstimatorName[eCentFT0C].Data()); + nBins_y_Event[eCentFT0C_vs_CentFT0M] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_y_Event[eCentFT0C_vs_CentFT0M] = eh.fEventHistogramsBins[eCentrality][1]; + max_y_Event[eCentFT0C_vs_CentFT0M] = eh.fEventHistogramsBins[eCentrality][2]; + title_y_Event[eCentFT0C_vs_CentFT0M] = FancyFormatting(qa.fCentralityEstimatorName[eCentFT0M].Data()); + + // *) "CentFT0C_vs_CentFV0A": + nBins_x_Event[eCentFT0C_vs_CentFV0A] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_x_Event[eCentFT0C_vs_CentFV0A] = eh.fEventHistogramsBins[eCentrality][1]; + max_x_Event[eCentFT0C_vs_CentFV0A] = eh.fEventHistogramsBins[eCentrality][2]; + title_x_Event[eCentFT0C_vs_CentFV0A] = FancyFormatting(qa.fCentralityEstimatorName[eCentFT0C].Data()); + nBins_y_Event[eCentFT0C_vs_CentFV0A] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_y_Event[eCentFT0C_vs_CentFV0A] = eh.fEventHistogramsBins[eCentrality][1]; + max_y_Event[eCentFT0C_vs_CentFV0A] = eh.fEventHistogramsBins[eCentrality][2]; + title_y_Event[eCentFT0C_vs_CentFV0A] = FancyFormatting(qa.fCentralityEstimatorName[eCentFV0A].Data()); + + // *) "CentFT0C_vs_CentNTPV": + nBins_x_Event[eCentFT0C_vs_CentNTPV] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_x_Event[eCentFT0C_vs_CentNTPV] = eh.fEventHistogramsBins[eCentrality][1]; + max_x_Event[eCentFT0C_vs_CentNTPV] = eh.fEventHistogramsBins[eCentrality][2]; + title_x_Event[eCentFT0C_vs_CentNTPV] = FancyFormatting(qa.fCentralityEstimatorName[eCentFT0C].Data()); + nBins_y_Event[eCentFT0C_vs_CentNTPV] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_y_Event[eCentFT0C_vs_CentNTPV] = eh.fEventHistogramsBins[eCentrality][1]; + max_y_Event[eCentFT0C_vs_CentNTPV] = eh.fEventHistogramsBins[eCentrality][2]; + title_y_Event[eCentFT0C_vs_CentNTPV] = FancyFormatting(qa.fCentralityEstimatorName[eCentNTPV].Data()); + + // *) "CentFT0C_vs_CentNGlobal": + nBins_x_Event[eCentFT0C_vs_CentNGlobal] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_x_Event[eCentFT0C_vs_CentNGlobal] = eh.fEventHistogramsBins[eCentrality][1]; + max_x_Event[eCentFT0C_vs_CentNGlobal] = eh.fEventHistogramsBins[eCentrality][2]; + title_x_Event[eCentFT0C_vs_CentNGlobal] = FancyFormatting(qa.fCentralityEstimatorName[eCentFT0C].Data()); + nBins_y_Event[eCentFT0C_vs_CentNGlobal] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_y_Event[eCentFT0C_vs_CentNGlobal] = eh.fEventHistogramsBins[eCentrality][1]; + max_y_Event[eCentFT0C_vs_CentNGlobal] = eh.fEventHistogramsBins[eCentrality][2]; + title_y_Event[eCentFT0C_vs_CentNGlobal] = FancyFormatting(qa.fCentralityEstimatorName[eCentNGlobal].Data()); + + // *) "CentFT0M_vs_CentNTPV": + nBins_x_Event[eCentFT0M_vs_CentNTPV] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_x_Event[eCentFT0M_vs_CentNTPV] = eh.fEventHistogramsBins[eCentrality][1]; + max_x_Event[eCentFT0M_vs_CentNTPV] = eh.fEventHistogramsBins[eCentrality][2]; + title_x_Event[eCentFT0M_vs_CentNTPV] = FancyFormatting(qa.fCentralityEstimatorName[eCentFT0M].Data()); + nBins_y_Event[eCentFT0M_vs_CentNTPV] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_y_Event[eCentFT0M_vs_CentNTPV] = eh.fEventHistogramsBins[eCentrality][1]; + max_y_Event[eCentFT0M_vs_CentNTPV] = eh.fEventHistogramsBins[eCentrality][2]; + title_y_Event[eCentFT0M_vs_CentNTPV] = FancyFormatting(qa.fCentralityEstimatorName[eCentNTPV].Data()); + + // *) "CentRun2V0M_vs_CentRun2SPDTracklets": + nBins_x_Event[eCentRun2V0M_vs_CentRun2SPDTracklets] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_x_Event[eCentRun2V0M_vs_CentRun2SPDTracklets] = eh.fEventHistogramsBins[eCentrality][1]; + max_x_Event[eCentRun2V0M_vs_CentRun2SPDTracklets] = eh.fEventHistogramsBins[eCentrality][2]; + title_x_Event[eCentRun2V0M_vs_CentRun2SPDTracklets] = FancyFormatting(qa.fCentralityEstimatorName[eCentRun2V0M].Data()); + nBins_y_Event[eCentRun2V0M_vs_CentRun2SPDTracklets] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_y_Event[eCentRun2V0M_vs_CentRun2SPDTracklets] = eh.fEventHistogramsBins[eCentrality][1]; + max_y_Event[eCentRun2V0M_vs_CentRun2SPDTracklets] = eh.fEventHistogramsBins[eCentrality][2]; + title_y_Event[eCentRun2V0M_vs_CentRun2SPDTracklets] = FancyFormatting(qa.fCentralityEstimatorName[eCentRun2SPDTracklets].Data()); + + // *) "TrackOccupancyInTimeRange_vs_FT0COccupancyInTimeRange": + nBins_x_Event[eTrackOccupancyInTimeRange_vs_FT0COccupancyInTimeRange] = static_cast(eh.fEventHistogramsBins[eOccupancy][0] / qa.fRebin); + min_x_Event[eTrackOccupancyInTimeRange_vs_FT0COccupancyInTimeRange] = eh.fEventHistogramsBins[eOccupancy][1]; + max_x_Event[eTrackOccupancyInTimeRange_vs_FT0COccupancyInTimeRange] = eh.fEventHistogramsBins[eOccupancy][2]; + title_x_Event[eTrackOccupancyInTimeRange_vs_FT0COccupancyInTimeRange] = FancyFormatting(qa.fOccupancyEstimatorName[eTrackOccupancyInTimeRange].Data()); + nBins_y_Event[eTrackOccupancyInTimeRange_vs_FT0COccupancyInTimeRange] = static_cast(eh.fEventHistogramsBins[eOccupancy][0] / qa.fRebin); + min_y_Event[eTrackOccupancyInTimeRange_vs_FT0COccupancyInTimeRange] = eh.fEventHistogramsBins[eOccupancy][1]; + max_y_Event[eTrackOccupancyInTimeRange_vs_FT0COccupancyInTimeRange] = eh.fEventHistogramsBins[eOccupancy][2]; + title_y_Event[eTrackOccupancyInTimeRange_vs_FT0COccupancyInTimeRange] = FancyFormatting(qa.fOccupancyEstimatorName[eFT0COccupancyInTimeRange].Data()); + + // *) "CurrentRunDuration_vs_InteractionRate": + nBins_x_Event[eCurrentRunDuration_vs_InteractionRate] = static_cast(eh.fEventHistogramsBins[eCurrentRunDuration][0] / qa.fRebin); + min_x_Event[eCurrentRunDuration_vs_InteractionRate] = eh.fEventHistogramsBins[eCurrentRunDuration][1]; + max_x_Event[eCurrentRunDuration_vs_InteractionRate] = eh.fEventHistogramsBins[eCurrentRunDuration][2]; + title_x_Event[eCurrentRunDuration_vs_InteractionRate] = FancyFormatting(eh.fEventHistogramsName[eCurrentRunDuration].Data()); + nBins_y_Event[eCurrentRunDuration_vs_InteractionRate] = static_cast(eh.fEventHistogramsBins[eInteractionRate][0] / qa.fRebin); + min_y_Event[eCurrentRunDuration_vs_InteractionRate] = eh.fEventHistogramsBins[eInteractionRate][1]; + max_y_Event[eCurrentRunDuration_vs_InteractionRate] = eh.fEventHistogramsBins[eInteractionRate][2]; + title_y_Event[eCurrentRunDuration_vs_InteractionRate] = FancyFormatting(eh.fEventHistogramsName[eInteractionRate].Data()); + + // ... + + // *) Quick insanity check on title_x_Event and title_y_Event: + for (int t = 0; t < eQAEventHistograms2D_N; t++) { + + // **) title_x_Event: + if (tc.fVerbose) { + LOGF(info, "\033[1;32m title_x_Event[%d] = %s \033[0m", t, title_x_Event[t].Data()); } - // *) Vertex_x: - if ((collision.posX() < eh.fEventCuts[eVertex_x][eMin]) || - (collision.posX() > eh.fEventCuts[eVertex_x][eMax])) { - if (tc.fVerbose) { - LOGF(info, "\033[1;31m%s eVertex_x\033[0m", __FUNCTION__); // just a bare function name - } - return kFALSE; + if (title_x_Event[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : title_x_Event[%d] is not set, check corresponding enum \033[0m", __FUNCTION__, __LINE__, t); } - // *) Vertex_y: - if ((collision.posY() < eh.fEventCuts[eVertex_y][eMin]) || - (collision.posY() > eh.fEventCuts[eVertex_y][eMax])) { - if (tc.fVerbose) { - LOGF(info, "\033[1;31m%s eVertex_y\033[0m", __FUNCTION__); // just a bare function name - } - return kFALSE; + + // **) title_y_Event: + if (tc.fVerbose) { + LOGF(info, "\033[1;32m title_y_Event[%d] = %s \033[0m", t, title_y_Event[t].Data()); } - // *) Vertex_z: - if ((collision.posZ() < eh.fEventCuts[eVertex_z][eMin]) || - (collision.posZ() > eh.fEventCuts[eVertex_z][eMax])) { - if (tc.fVerbose) { - LOGF(info, "\033[1;31m%s eVertex_z\033[0m", __FUNCTION__); // just a bare function name - } - return kFALSE; + if (title_y_Event[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : title_y_Event[%d] is not set, check corresponding enum \033[0m", __FUNCTION__, __LINE__, t); } - // *) NContributors: - if ((collision.numContrib() < eh.fEventCuts[eNContributors][eMin]) || - (collision.numContrib() > eh.fEventCuts[eNContributors][eMax])) { - if (tc.fVerbose) { - LOGF(info, "\033[1;31m%s eNContributors\033[0m", __FUNCTION__); // just a bare function name - } - return kFALSE; + + } // for (int t = 0; t < eQAEventHistograms2D_N; t++) { + + // Okay, let's book 'em all: + for (int t = 0; t < eQAEventHistograms2D_N; t++) // type, see enum eQAEventHistograms2D + { + if (!qa.fBookQAEventHistograms2D[t]) { + continue; } - // TBI 20231106 continue here with other event cuts on reconstructed info + for (int rs = 0; rs < 2; rs++) // reco/sim + { - // ... and corresponding MC truth simulated ( see https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx ): - if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { - if (!collision.has_mcCollision()) { - LOGF(warning, "No MC collision for this collision, skip..."); // TBI 20231106 re-think. I shouldn't probably get to this point, if MC truth info doesn't exist for this collision - return kFALSE; + if (Skip(rs)) { + continue; } - // TBI 20231106 here I cat cut directly on corresponding MC truth simulated, e.g. on collision.mcCollision().posZ(), if necessary - - } // if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + for (int ba = 0; ba < 2; ba++) // before/after cuts + { - } // if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { + // Special treatment for eMultiplicity => I will never fill this one before the cuts, if Multiplicity = SelectedTracks, obviously: + if (ba == eBefore && (title_x_Event[t].BeginsWith("Multiplicity") || title_y_Event[t].BeginsWith("Multiplicity")) && ec.fsEventCuts[eMultiplicityEstimator].EqualTo("SelectedTracks", TString::kIgnoreCase)) { + // TBI 20241123 what remains ill-defined is the case when Multiplicity != SelectedTracks , check that further + // TBI 20241123 not sure if checking with BeginsWith(...) x2 is robust enough + // TBI 20241123 just like I have Skip(rs), introduce the same thingie for "ba" counter + propagate to other member functions + // TBI 20241124 there is a corner case when eMultiplicityEstimator itself is "ReferenceMultiplicity" => all 2D QA booked both before and after cuts, + // but it's filled trivially before the cuts, because Multiplicity is always 0. Re-think this at some point. + continue; + } - // *) Specific direct event cuts on info available only in simulated data: - if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { - // *) Impact parameter: - if ((collision.impactParameter() < eh.fEventCuts[eImpactParameter][eMin]) || - (collision.impactParameter() > eh.fEventCuts[eImpactParameter][eMax])) { - if (tc.fVerbose) { - LOGF(info, "\033[1;31m%s eImpactParameter\033[0m", __FUNCTION__); // just a bare function name - } - return kFALSE; - } - // ... - } // if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { + // valgrind --tool=massif => ~9.8 MiB (Last check: 20250315) + qa.fQAEventHistograms2D[t][rs][ba] = new TH2F( + TString::Format("fQAEventHistograms2D[%s][%s][%s]", qa.fEventHistogramsName2D[t].Data(), gc.srs[rs].Data(), gc.sba[ba].Data()), + TString::Format("%s, %s, %s", "__RUN_NUMBER__", gc.srs_long[rs].Data(), gc.sba_long[ba].Data()), // __RUN_NUMBER__ is handled in PropagateRunNumber(...) + nBins_x_Event[t], min_x_Event[t], max_x_Event[t], nBins_y_Event[t], min_y_Event[t], max_y_Event[t]); + qa.fQAEventHistograms2D[t][rs][ba]->GetXaxis()->SetTitle(title_x_Event[t].Data()); + qa.fQAEventHistograms2D[t][rs][ba]->GetYaxis()->SetTitle(title_y_Event[t].Data()); + qa.fQAEventHistograms2D[t][rs][ba]->SetLineColor(ec.fBeforeAfterColor[ba]); + qa.fQAEventHistograms2D[t][rs][ba]->SetFillColor(ec.fBeforeAfterColor[ba] - 10); + qa.fQAEventHistograms2D[t][rs][ba]->SetOption("col"); + qa.fQAEventList->Add(qa.fQAEventHistograms2D[t][rs][ba]); + } // for(int ba=0;ba<2;ba++) + } // for(int rs=0;rs<2;rs++) // reco/sim + } // for(int t=0;t eh.fEventCuts[eTotalMultiplicity][eMax])) { - if (tc.fVerbose) { - LOGF(info, "\033[1;31m%s eTotalMultiplicity\033[0m", __FUNCTION__); // just a bare function name - } - return kFALSE; + // c) Book specific QA 2D particle histograms: + // Binning of 2D particle histos: TBI 20240503 see if you can automate all this + int nBins_x_Particle[eQAParticleHistograms2D_N] = {0}; + double min_x_Particle[eQAParticleHistograms2D_N] = {0.}; + double max_x_Particle[eQAParticleHistograms2D_N] = {0.}; + TString title_x_Particle[eQAParticleHistograms2D_N] = {""}; + int nBins_y_Particle[eQAParticleHistograms2D_N] = {0}; + double min_y_Particle[eQAParticleHistograms2D_N] = {0.}; + double max_y_Particle[eQAParticleHistograms2D_N] = {0.}; + TString title_y_Particle[eQAParticleHistograms2D_N] = {""}; + + // *) "pt_vs_dcaXY": + nBins_x_Particle[ePt_vs_dcaXY] = static_cast(ph.fParticleHistogramsBins[ePt][0]); // TBI 20240702 add support for rebinning + min_x_Particle[ePt_vs_dcaXY] = ph.fParticleHistogramsBins[ePt][1]; + max_x_Particle[ePt_vs_dcaXY] = ph.fParticleHistogramsBins[ePt][2]; + title_x_Particle[ePt_vs_dcaXY] = FancyFormatting(ph.fParticleHistogramsName[ePt].Data()); + nBins_y_Particle[ePt_vs_dcaXY] = static_cast(ph.fParticleHistogramsBins[edcaXY][0]); // TBI 20240702 add support for rebinning + min_y_Particle[ePt_vs_dcaXY] = ph.fParticleHistogramsBins[edcaXY][1]; + max_y_Particle[ePt_vs_dcaXY] = ph.fParticleHistogramsBins[edcaXY][2]; + title_y_Particle[ePt_vs_dcaXY] = FancyFormatting(ph.fParticleHistogramsName[edcaXY].Data()); + + // ... + + // *) Quick insanity check on title_x_Particle and title_y_Particle: + for (int t = 0; t < eQAParticleHistograms2D_N; t++) { + if (title_x_Particle[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : title_x_Particle[%d] is not set, check corresponding enum \033[0m", __FUNCTION__, __LINE__, t); } + if (title_y_Particle[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : title_y_Particle[%d] is not set, check corresponding enum \033[0m", __FUNCTION__, __LINE__, t); + } + } - // *) Vertex_z: - if ((collision.posZ() < eh.fEventCuts[eVertex_z][eMin]) || - (collision.posZ() > eh.fEventCuts[eVertex_z][eMax])) { - if (tc.fVerbose) { - LOGF(info, "\033[1;31m%s eVertex_z\033[0m", __FUNCTION__); // just a bare function name - } - return kFALSE; + // Okay, let's book 'em all: + for (int t = 0; t < eQAParticleHistograms2D_N; t++) // type, see enum eQAParticleHistograms2D + { + if (!qa.fBookQAParticleHistograms2D[t]) { + continue; } + for (int rs = 0; rs < 2; rs++) // reco/sim + { - // *) Centrality: - if ((ebye.fCentrality < eh.fEventCuts[eCentrality][eMin]) || (ebye.fCentrality > eh.fEventCuts[eCentrality][eMax])) { - if (tc.fVerbose) { - LOGF(info, "\033[1;31m%s eCentrality\033[0m", __FUNCTION__); // just a bare function name + if (Skip(rs)) { + continue; } - return kFALSE; + + for (int ba = 0; ba < 2; ba++) // before/after cuts + { + // valgrind --tool=massif => ~30.6 MiB (Last check: 20250315) + qa.fQAParticleHistograms2D[t][rs][ba] = new TH2F( + TString::Format("fQAParticleHistograms2D[%s][%s][%s]", qa.fParticleHistogramsName2D[t].Data(), gc.srs[rs].Data(), gc.sba[ba].Data()), + TString::Format("%s, %s, %s", "__RUN_NUMBER__", gc.srs_long[rs].Data(), gc.sba_long[ba].Data()), // __RUN_NUMBER__ is handled in PropagateRunNumber(...) + nBins_x_Particle[t], min_x_Particle[t], max_x_Particle[t], nBins_y_Particle[t], min_y_Particle[t], max_y_Particle[t]); + + qa.fQAParticleHistograms2D[t][rs][ba]->GetXaxis()->SetTitle(title_x_Particle[t].Data()); + qa.fQAParticleHistograms2D[t][rs][ba]->GetYaxis()->SetTitle(title_y_Particle[t].Data()); + qa.fQAParticleHistograms2D[t][rs][ba]->SetLineColor(ec.fBeforeAfterColor[ba]); + qa.fQAParticleHistograms2D[t][rs][ba]->SetFillColor(ec.fBeforeAfterColor[ba] - 10); + qa.fQAParticleHistograms2D[t][rs][ba]->SetOption("col"); + qa.fQAParticleList->Add(qa.fQAParticleHistograms2D[t][rs][ba]); + } // for(int ba=0;ba<2;ba++) + } // for(int rs=0;rs<2;rs++) // reco/sim + } // for(int t=0;t(eh.fEventHistogramsBins[eCurrentRunDuration][0]); + min_x_ParticleEvent[eCurrentRunDuration_vs_itsNClsEbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][1]; + max_x_ParticleEvent[eCurrentRunDuration_vs_itsNClsEbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][2]; + title_x_ParticleEvent[eCurrentRunDuration_vs_itsNClsEbyE] = FancyFormatting(eh.fEventHistogramsName[eCurrentRunDuration].Data()); + // nBins_y_ParticleEvent[eCurrentRunDuration_vs_itsNClsEbyE] = static_cast(ph.fParticleHistogramsBins[eitsNCls][0]); + nBins_y_ParticleEvent[eCurrentRunDuration_vs_itsNClsEbyE] = 100; + min_y_ParticleEvent[eCurrentRunDuration_vs_itsNClsEbyE] = ph.fParticleHistogramsBins[eitsNCls][1]; + max_y_ParticleEvent[eCurrentRunDuration_vs_itsNClsEbyE] = ph.fParticleHistogramsBins[eitsNCls][2]; + title_y_ParticleEvent[eCurrentRunDuration_vs_itsNClsEbyE] = TString::Format("#LT%s#GT", FancyFormatting(ph.fParticleHistogramsName[eitsNCls].Data())); + + // *) "eCurrentRunDuration_vs_itsNClsNegEtaEbyE": + nBins_x_ParticleEvent[eCurrentRunDuration_vs_itsNClsNegEtaEbyE] = static_cast(eh.fEventHistogramsBins[eCurrentRunDuration][0]); + min_x_ParticleEvent[eCurrentRunDuration_vs_itsNClsNegEtaEbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][1]; + max_x_ParticleEvent[eCurrentRunDuration_vs_itsNClsNegEtaEbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][2]; + title_x_ParticleEvent[eCurrentRunDuration_vs_itsNClsNegEtaEbyE] = FancyFormatting(eh.fEventHistogramsName[eCurrentRunDuration].Data()); + nBins_y_ParticleEvent[eCurrentRunDuration_vs_itsNClsNegEtaEbyE] = 100; + min_y_ParticleEvent[eCurrentRunDuration_vs_itsNClsNegEtaEbyE] = ph.fParticleHistogramsBins[eitsNCls][1]; + max_y_ParticleEvent[eCurrentRunDuration_vs_itsNClsNegEtaEbyE] = ph.fParticleHistogramsBins[eitsNCls][2]; + title_y_ParticleEvent[eCurrentRunDuration_vs_itsNClsNegEtaEbyE] = TString::Format("#LT%s#GT, #eta < 0", FancyFormatting(ph.fParticleHistogramsName[eitsNCls].Data())); + + // *) "eCurrentRunDuration_vs_itsNClsPosEtaEbyE": + nBins_x_ParticleEvent[eCurrentRunDuration_vs_itsNClsPosEtaEbyE] = static_cast(eh.fEventHistogramsBins[eCurrentRunDuration][0]); + min_x_ParticleEvent[eCurrentRunDuration_vs_itsNClsPosEtaEbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][1]; + max_x_ParticleEvent[eCurrentRunDuration_vs_itsNClsPosEtaEbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][2]; + title_x_ParticleEvent[eCurrentRunDuration_vs_itsNClsPosEtaEbyE] = FancyFormatting(eh.fEventHistogramsName[eCurrentRunDuration].Data()); + nBins_y_ParticleEvent[eCurrentRunDuration_vs_itsNClsPosEtaEbyE] = 100; + min_y_ParticleEvent[eCurrentRunDuration_vs_itsNClsPosEtaEbyE] = ph.fParticleHistogramsBins[eitsNCls][1]; + max_y_ParticleEvent[eCurrentRunDuration_vs_itsNClsPosEtaEbyE] = ph.fParticleHistogramsBins[eitsNCls][2]; + title_y_ParticleEvent[eCurrentRunDuration_vs_itsNClsPosEtaEbyE] = TString::Format("#LT%s#GT, #eta > 0", FancyFormatting(ph.fParticleHistogramsName[eitsNCls].Data())); + + // *) "eCurrentRunDuration_vs_Eta0804EbyE": + nBins_x_ParticleEvent[eCurrentRunDuration_vs_Eta0804EbyE] = static_cast(eh.fEventHistogramsBins[eCurrentRunDuration][0]); + min_x_ParticleEvent[eCurrentRunDuration_vs_Eta0804EbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][1]; + max_x_ParticleEvent[eCurrentRunDuration_vs_Eta0804EbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][2]; + title_x_ParticleEvent[eCurrentRunDuration_vs_Eta0804EbyE] = FancyFormatting(eh.fEventHistogramsName[eCurrentRunDuration].Data()); + nBins_y_ParticleEvent[eCurrentRunDuration_vs_Eta0804EbyE] = 80; + min_y_ParticleEvent[eCurrentRunDuration_vs_Eta0804EbyE] = -1.0; // TBI 20241214 intentionally temporarily overshooting, to trace down overflow and underflow, if any + max_y_ParticleEvent[eCurrentRunDuration_vs_Eta0804EbyE] = 1.0; // TBI 20241214 intentionally temporarily overshooting, to trace down overflow and underflow, if any + title_y_ParticleEvent[eCurrentRunDuration_vs_Eta0804EbyE] = TString::Format("#LT%s#GT, -0.8 < #eta < -0.4", FancyFormatting(ph.fParticleHistogramsName[eEta].Data())); + + // *) "eCurrentRunDuration_vs_Eta0400EbyE": + nBins_x_ParticleEvent[eCurrentRunDuration_vs_Eta0400EbyE] = static_cast(eh.fEventHistogramsBins[eCurrentRunDuration][0]); + min_x_ParticleEvent[eCurrentRunDuration_vs_Eta0400EbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][1]; + max_x_ParticleEvent[eCurrentRunDuration_vs_Eta0400EbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][2]; + title_x_ParticleEvent[eCurrentRunDuration_vs_Eta0400EbyE] = FancyFormatting(eh.fEventHistogramsName[eCurrentRunDuration].Data()); + nBins_y_ParticleEvent[eCurrentRunDuration_vs_Eta0400EbyE] = 80; + min_y_ParticleEvent[eCurrentRunDuration_vs_Eta0400EbyE] = -1.0; + max_y_ParticleEvent[eCurrentRunDuration_vs_Eta0400EbyE] = 1.0; + title_y_ParticleEvent[eCurrentRunDuration_vs_Eta0400EbyE] = TString::Format("#LT%s#GT, -0.4 < #eta < 0.0", FancyFormatting(ph.fParticleHistogramsName[eEta].Data())); + + // *) "eCurrentRunDuration_vs_Eta0004EbyE": + nBins_x_ParticleEvent[eCurrentRunDuration_vs_Eta0004EbyE] = static_cast(eh.fEventHistogramsBins[eCurrentRunDuration][0]); + min_x_ParticleEvent[eCurrentRunDuration_vs_Eta0004EbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][1]; + max_x_ParticleEvent[eCurrentRunDuration_vs_Eta0004EbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][2]; + title_x_ParticleEvent[eCurrentRunDuration_vs_Eta0004EbyE] = FancyFormatting(eh.fEventHistogramsName[eCurrentRunDuration].Data()); + nBins_y_ParticleEvent[eCurrentRunDuration_vs_Eta0004EbyE] = 80; + min_y_ParticleEvent[eCurrentRunDuration_vs_Eta0004EbyE] = -1.0; + max_y_ParticleEvent[eCurrentRunDuration_vs_Eta0004EbyE] = 1.0; + title_y_ParticleEvent[eCurrentRunDuration_vs_Eta0004EbyE] = TString::Format("#LT%s#GT, 0.0 < #eta < 0.4", FancyFormatting(ph.fParticleHistogramsName[eEta].Data())); + + // *) "eCurrentRunDuration_vs_Eta0408EbyE": + nBins_x_ParticleEvent[eCurrentRunDuration_vs_Eta0408EbyE] = static_cast(eh.fEventHistogramsBins[eCurrentRunDuration][0]); + min_x_ParticleEvent[eCurrentRunDuration_vs_Eta0408EbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][1]; + max_x_ParticleEvent[eCurrentRunDuration_vs_Eta0408EbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][2]; + title_x_ParticleEvent[eCurrentRunDuration_vs_Eta0408EbyE] = FancyFormatting(eh.fEventHistogramsName[eCurrentRunDuration].Data()); + nBins_y_ParticleEvent[eCurrentRunDuration_vs_Eta0408EbyE] = 80; + min_y_ParticleEvent[eCurrentRunDuration_vs_Eta0408EbyE] = -1.0; + max_y_ParticleEvent[eCurrentRunDuration_vs_Eta0408EbyE] = 1.0; + title_y_ParticleEvent[eCurrentRunDuration_vs_Eta0408EbyE] = TString::Format("#LT%s#GT, 0.4 < #eta < 0.8", FancyFormatting(ph.fParticleHistogramsName[eEta].Data())); + + // *) "eCurrentRunDuration_vs_Pt0005EbyE": + nBins_x_ParticleEvent[eCurrentRunDuration_vs_Pt0005EbyE] = static_cast(eh.fEventHistogramsBins[eCurrentRunDuration][0]); + min_x_ParticleEvent[eCurrentRunDuration_vs_Pt0005EbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][1]; + max_x_ParticleEvent[eCurrentRunDuration_vs_Pt0005EbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][2]; + title_x_ParticleEvent[eCurrentRunDuration_vs_Pt0005EbyE] = FancyFormatting(eh.fEventHistogramsName[eCurrentRunDuration].Data()); + nBins_y_ParticleEvent[eCurrentRunDuration_vs_Pt0005EbyE] = 400; + min_y_ParticleEvent[eCurrentRunDuration_vs_Pt0005EbyE] = 0.0; // TBI 20241214 intentionally temporarilyovershooting, to trace down overflow and underflow, if any + max_y_ParticleEvent[eCurrentRunDuration_vs_Pt0005EbyE] = 10.0; // TBI 20241214 intentionally temporarily overshooting, to trace down overflow and underflow, if any + title_y_ParticleEvent[eCurrentRunDuration_vs_Pt0005EbyE] = TString::Format("#LT%s#GT, 0.0 < p_{T} < 0.5 GeV/c", FancyFormatting(ph.fParticleHistogramsName[ePt].Data())); + + // *) "eCurrentRunDuration_vs_Pt0510EbyE": + nBins_x_ParticleEvent[eCurrentRunDuration_vs_Pt0510EbyE] = static_cast(eh.fEventHistogramsBins[eCurrentRunDuration][0]); + min_x_ParticleEvent[eCurrentRunDuration_vs_Pt0510EbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][1]; + max_x_ParticleEvent[eCurrentRunDuration_vs_Pt0510EbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][2]; + title_x_ParticleEvent[eCurrentRunDuration_vs_Pt0510EbyE] = FancyFormatting(eh.fEventHistogramsName[eCurrentRunDuration].Data()); + nBins_y_ParticleEvent[eCurrentRunDuration_vs_Pt0510EbyE] = 400; + min_y_ParticleEvent[eCurrentRunDuration_vs_Pt0510EbyE] = 0.0; + max_y_ParticleEvent[eCurrentRunDuration_vs_Pt0510EbyE] = 10.0; + title_y_ParticleEvent[eCurrentRunDuration_vs_Pt0510EbyE] = TString::Format("#LT%s#GT, 0.5 < p_{T} < 1.0 GeV/c", FancyFormatting(ph.fParticleHistogramsName[ePt].Data())); + + // *) "eCurrentRunDuration_vs_Pt1050EbyE": + nBins_x_ParticleEvent[eCurrentRunDuration_vs_Pt1050EbyE] = static_cast(eh.fEventHistogramsBins[eCurrentRunDuration][0]); + min_x_ParticleEvent[eCurrentRunDuration_vs_Pt1050EbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][1]; + max_x_ParticleEvent[eCurrentRunDuration_vs_Pt1050EbyE] = eh.fEventHistogramsBins[eCurrentRunDuration][2]; + title_x_ParticleEvent[eCurrentRunDuration_vs_Pt1050EbyE] = FancyFormatting(eh.fEventHistogramsName[eCurrentRunDuration].Data()); + nBins_y_ParticleEvent[eCurrentRunDuration_vs_Pt1050EbyE] = 400; + min_y_ParticleEvent[eCurrentRunDuration_vs_Pt1050EbyE] = 0.0; + max_y_ParticleEvent[eCurrentRunDuration_vs_Pt1050EbyE] = 10.0; + title_y_ParticleEvent[eCurrentRunDuration_vs_Pt1050EbyE] = TString::Format("#LT%s#GT, 1.0 < p_{T} < 5.0 GeV/c", FancyFormatting(ph.fParticleHistogramsName[ePt].Data())); + + // ... + + // *) Quick insanity check on title_x_ParticleEvent and title_y_ParticleEvent: + for (int t = 0; t < eQAParticleEventHistograms2D_N; t++) { + if (title_x_ParticleEvent[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : title_x_ParticleEvent[%d] is not set, check corresponding enum \033[0m", __FUNCTION__, __LINE__, t); } - } // if constexpr (rs == eTest) { + if (title_y_ParticleEvent[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : title_y_ParticleEvent[%d] is not set, check corresponding enum \033[0m", __FUNCTION__, __LINE__, t); + } + } - return kTRUE; + // Okay, let's book 'em all: + for (int t = 0; t < eQAParticleEventHistograms2D_N; t++) // type, see enum eQAParticleEventHistograms2D + { + if (!qa.fBookQAParticleEventHistograms2D[t]) { + continue; + } + for (int rs = 0; rs < 2; rs++) // reco/sim + { -} // template Bool_t EventCuts(T1 const& collision, T2 const& tracks) + if (Skip(rs)) { + continue; + } -//============================================================ + for (int ba = 0; ba < 2; ba++) // before/after cuts + { -template -void FillEventHistograms(T1 const& collision, T2 const& tracks, eBeforeAfter ba) -{ - // Fill all event histograms for reconstructed or simulated data. + if (ba == eBefore) { // TBI 20241214 re-think if I need these additional QA particle event histos before cuts + continue; + } - // a) Fill reconstructed, and corresponding MC truth simulated (common to Run 3, Run 2 and Run 1); - // b) Fill only simulated (common to Run 3, Run 2 and Run 1); - // c) Fill reconstructed (Run 3 specific); - // d) Fill only simulated (Run 3 specific); - // e) Fill reconstructed (Run 2 specific); - // f) Fill only simulated (Run 2 specific); - // g) Fill reconstructed (Run 1 specific); - // h) Fill only simulated (Run 1 specific); - // i) Test case. + // valgrind --tool=massif => ~70.2 MiB (Last check: 20250315) + qa.fQAParticleEventHistograms2D[t][rs][ba] = new TH2F( + TString::Format("fQAParticleEventHistograms2D[%s][%s][%s]", qa.fQAParticleEventHistogramsName2D[t].Data(), gc.srs[rs].Data(), gc.sba[ba].Data()), + TString::Format("%s, %s, %s", "__RUN_NUMBER__", gc.srs_long[rs].Data(), gc.sba_long[ba].Data()), // __RUN_NUMBER__ is handled in PropagateRunNumber(...) + nBins_x_ParticleEvent[t], min_x_ParticleEvent[t], max_x_ParticleEvent[t], nBins_y_ParticleEvent[t], min_y_ParticleEvent[t], max_y_ParticleEvent[t]); + + qa.fQAParticleEventHistograms2D[t][rs][ba]->GetXaxis()->SetTitle(title_x_ParticleEvent[t].Data()); + qa.fQAParticleEventHistograms2D[t][rs][ba]->GetYaxis()->SetTitle(title_y_ParticleEvent[t].Data()); + qa.fQAParticleEventHistograms2D[t][rs][ba]->SetLineColor(ec.fBeforeAfterColor[ba]); + qa.fQAParticleEventHistograms2D[t][rs][ba]->SetFillColor(ec.fBeforeAfterColor[ba] - 10); + qa.fQAParticleEventHistograms2D[t][rs][ba]->SetOption("col"); + qa.fQAParticleEventList->Add(qa.fQAParticleEventHistograms2D[t][rs][ba]); + } // for(int ba=0;ba<2;ba++) + } // for(int rs=0;rs<2;rs++) // reco/sim + } // for(int t=0;tFill(0.5); // basically, if histogram is not booked, do nothing. 'true' is a placeholder, for the time being - !eh.fEventHistograms[eVertex_x][eRec][ba] ? true : eh.fEventHistograms[eVertex_x][eRec][ba]->Fill(collision.posX()); - !eh.fEventHistograms[eVertex_y][eRec][ba] ? true : eh.fEventHistograms[eVertex_y][eRec][ba]->Fill(collision.posY()); - !eh.fEventHistograms[eVertex_z][eRec][ba] ? true : eh.fEventHistograms[eVertex_z][eRec][ba]->Fill(collision.posZ()); - !eh.fEventHistograms[eNContributors][eRec][ba] ? true : eh.fEventHistograms[eNContributors][eRec][ba]->Fill(collision.numContrib()); - !eh.fEventHistograms[eTotalMultiplicity][eRec][ba] ? true : eh.fEventHistograms[eTotalMultiplicity][eRec][ba]->Fill(tracks.size()); // TBI 20231106 check and validate further - !eh.fEventHistograms[eSelectedTracks][eRec][ba] ? true : eh.fEventHistograms[eSelectedTracks][eRec][ba]->Fill(ebye.fSelectedTracks); // TBI 20240108 this one makes sense only for eAfter - !eh.fEventHistograms[eMultTPC][eRec][ba] ? true : eh.fEventHistograms[eMultTPC][eRec][ba]->Fill(collision.multTPC()); - !eh.fEventHistograms[eMultNTracksPV][eRec][ba] ? true : eh.fEventHistograms[eMultNTracksPV][eRec][ba]->Fill(collision.multNTracksPV()); - !eh.fEventHistograms[eCentrality][eRec][ba] ? true : eh.fEventHistograms[eCentrality][eRec][ba]->Fill(ebye.fCentrality); + for (int ba = 0; ba < 2; ba++) // before/after cuts + { - // ... and corresponding MC truth simulated (common to Run 3, Run 2 and Run 1) ( see https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx ): - if constexpr (rs == eRecAndSim) { - if (!collision.has_mcCollision()) { - LOGF(warning, "No MC collision for this collision, skip..."); - return; + if (ba == eBefore) { // TBI 20241214 re-think if I need these additional QA particle event histos before cuts + continue; } - !eh.fEventHistograms[eNumberOfEvents][eSim][ba] ? true : eh.fEventHistograms[eNumberOfEvents][eSim][ba]->Fill(0.5); - !eh.fEventHistograms[eVertex_x][eSim][ba] ? true : eh.fEventHistograms[eVertex_x][eSim][ba]->Fill(collision.mcCollision().posX()); - !eh.fEventHistograms[eVertex_y][eSim][ba] ? true : eh.fEventHistograms[eVertex_y][eSim][ba]->Fill(collision.mcCollision().posY()); - !eh.fEventHistograms[eVertex_z][eSim][ba] ? true : eh.fEventHistograms[eVertex_z][eSim][ba]->Fill(collision.mcCollision().posZ()); - // eh.fEventHistograms[eTotalMultiplicity][eSim][ba]->Fill(tracks.size()); // TBI 20231106 check how to get corresponding MC truth info, and validate further - // eh.fEventHistograms[eSelectedTracks][eSim][ba]->Fill(ebye.fSelectedTracks); // TBI 20240108 this one makes sense only for eAfter + re-think if I really need it here - // TBI 20240120 eMultFT0M, ..., eMultNTracksPV are not needed here - // eh.fEventHistograms[eCentrality][eSim][ba]->Fill(ebye.fCentrality); // TBI 20240120 this case is still not supported in DetermineCentrality() - } // if constexpr (rs == eRecAndSim) { - } // if constexpr (rs == eRec || rs == eRecAndSim) { - // b) Fill only simulated (common to Run 3, Run 2 and Run 1): - if constexpr (rs == eSim) { - !eh.fEventHistograms[eImpactParameter][eSim][ba] ? true : eh.fEventHistograms[eImpactParameter][eSim][ba]->Fill(collision.impactParameter()); // yes, because in this branch 'collision' is always aod::McCollision - !eh.fEventHistograms[eSelectedTracks][eSim][ba] ? true : eh.fEventHistograms[eSelectedTracks][eSim][ba]->Fill(ebye.fSelectedTracks); // TBI 20240108 this one makes sense only for eAfter - // eh.fEventHistograms[eCentrality][eSim][ba]->Fill(ebye.fCentrality); // TBI 20240120 this case is still not supported in DetermineCentrality() - // eh.fEventHistograms[eTotalMultiplicity][eSim][ba]->Fill(tracks.size()); // TBI 20231030 check further how to use the same thing for 'sim' - } // if constexpr (rs == eSim) { + qa.fQAParticleEventProEbyE[rs][ba] = new TProfile( + TString::Format("fParticleEventProEbyE[%s][%s]", gc.srs[rs].Data(), gc.sba[ba].Data()), + TString::Format("%s, %s", gc.srs_long[rs].Data(), gc.sba_long[ba].Data()), + eQAParticleEventProEbyE_N, 0., eQAParticleEventProEbyE_N); + qa.fQAParticleEventProEbyE[rs][ba]->GetXaxis()->SetBinLabel(eitsNClsEbyE, "#LTitsNCls#GT"); // TBI 20241214 this bin labeling is not really needed, as I never save this TProfile persistently + qa.fQAParticleEventProEbyE[rs][ba]->GetXaxis()->SetBinLabel(eitsNClsNegEtaEbyE, "#LTitsNClsNegEta#GT"); + qa.fQAParticleEventProEbyE[rs][ba]->GetXaxis()->SetBinLabel(eitsNClsPosEtaEbyE, "#LTitsNClsPosEta#GT"); + qa.fQAParticleEventProEbyE[rs][ba]->GetXaxis()->SetBinLabel(eEta0804EbyE, "#LTEta0804EbyE#GT"); + qa.fQAParticleEventProEbyE[rs][ba]->GetXaxis()->SetBinLabel(eEta0400EbyE, "#LTEta0400EbyE#GT"); + qa.fQAParticleEventProEbyE[rs][ba]->GetXaxis()->SetBinLabel(eEta0004EbyE, "#LTEta0004EbyE#GT"); + qa.fQAParticleEventProEbyE[rs][ba]->GetXaxis()->SetBinLabel(eEta0408EbyE, "#LTEta0408EbyE#GT"); + qa.fQAParticleEventProEbyE[rs][ba]->GetXaxis()->SetBinLabel(ePt0005EbyE, "#LTPt0005EbyE#GT"); + qa.fQAParticleEventProEbyE[rs][ba]->GetXaxis()->SetBinLabel(ePt0510EbyE, "#LTPt0510EbyE#GT"); + qa.fQAParticleEventProEbyE[rs][ba]->GetXaxis()->SetBinLabel(ePt1050EbyE, "#LTPt1050EbyE#GT"); + } + } - // ----------------------------------------------------------------------------- + // f) Book specific QA 2D "correlations vs." histograms: + + // Binning of 2D "correlations vs." histos: + // Remark: I use the same binning for x axis for all 2D QA histos in this category, therefore here implementation in shorter. + int nBins_x_CorrelationsVs = 2000; + double min_x_CorrelationsVs = -1.; + double max_x_CorrelationsVs = 1.; + TString title_x_CorrelationsVs = "#LT2#GT"; // harmonic I store elsewhere TBI-today document here where + int nBins_y_CorrelationsVs[eQACorrelationsVsHistograms2D_N] = {0}; + double min_y_CorrelationsVs[eQACorrelationsVsHistograms2D_N] = {0.}; + double max_y_CorrelationsVs[eQACorrelationsVsHistograms2D_N] = {0.}; + TString title_y_CorrelationsVs[eQACorrelationsVsHistograms2D_N] = {""}; + + // *) "eCorrelations_vs_Multiplicity": + nBins_y_CorrelationsVs[eCorrelations_vs_Multiplicity] = static_cast(eh.fEventHistogramsBins[eMultiplicity][0] / 10); // TBI 20250331 here I have temporarily hardwired rebin value + min_y_CorrelationsVs[eCorrelations_vs_Multiplicity] = eh.fEventHistogramsBins[eMultiplicity][1]; + max_y_CorrelationsVs[eCorrelations_vs_Multiplicity] = eh.fEventHistogramsBins[eMultiplicity][2]; + title_y_CorrelationsVs[eCorrelations_vs_Multiplicity] = FancyFormatting(eh.fEventHistogramsName[eMultiplicity].Data()); + + // *) "eCorrelations_vs_ReferenceMultiplicity": + nBins_y_CorrelationsVs[eCorrelations_vs_ReferenceMultiplicity] = static_cast(eh.fEventHistogramsBins[eReferenceMultiplicity][0] / 10); // TBI 20250331 here I have temporarily hardwired rebin value + min_y_CorrelationsVs[eCorrelations_vs_ReferenceMultiplicity] = eh.fEventHistogramsBins[eReferenceMultiplicity][1]; + max_y_CorrelationsVs[eCorrelations_vs_ReferenceMultiplicity] = eh.fEventHistogramsBins[eReferenceMultiplicity][2]; + title_y_CorrelationsVs[eCorrelations_vs_ReferenceMultiplicity] = FancyFormatting(eh.fEventHistogramsName[eReferenceMultiplicity].Data()); + + // *) "eCorrelations_vs_Centrality": + nBins_y_CorrelationsVs[eCorrelations_vs_Centrality] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_y_CorrelationsVs[eCorrelations_vs_Centrality] = eh.fEventHistogramsBins[eCentrality][1]; + max_y_CorrelationsVs[eCorrelations_vs_Centrality] = eh.fEventHistogramsBins[eCentrality][2]; + title_y_CorrelationsVs[eCorrelations_vs_Centrality] = FancyFormatting(eh.fEventHistogramsName[eCentrality].Data()); + + // ..... + + // *) "eCorrelations_vs_MeanPhi": + nBins_y_CorrelationsVs[eCorrelations_vs_MeanPhi] = 200; + min_y_CorrelationsVs[eCorrelations_vs_MeanPhi] = 2.; + max_y_CorrelationsVs[eCorrelations_vs_MeanPhi] = 4.; + title_y_CorrelationsVs[eCorrelations_vs_MeanPhi] = FancyFormatting(ph.fParticleHistogramsName[ePhi].Data()); + + // *) "eCorrelations_vs_MeanPt": + nBins_y_CorrelationsVs[eCorrelations_vs_MeanPt] = 100; + min_y_CorrelationsVs[eCorrelations_vs_MeanPt] = 0.0; + max_y_CorrelationsVs[eCorrelations_vs_MeanPt] = 2.0; + title_y_CorrelationsVs[eCorrelations_vs_MeanPt] = FancyFormatting(ph.fParticleHistogramsName[ePt].Data()); + + // *) "eCorrelations_vs_MeanEta": + nBins_y_CorrelationsVs[eCorrelations_vs_MeanEta] = 200; + min_y_CorrelationsVs[eCorrelations_vs_MeanEta] = -0.3; + max_y_CorrelationsVs[eCorrelations_vs_MeanEta] = 0.3; + title_y_CorrelationsVs[eCorrelations_vs_MeanEta] = FancyFormatting(ph.fParticleHistogramsName[eEta].Data()); + + // *) "eCorrelations_vs_MeanCharge": + nBins_y_CorrelationsVs[eCorrelations_vs_MeanCharge] = 200; + min_y_CorrelationsVs[eCorrelations_vs_MeanCharge] = -1.; + max_y_CorrelationsVs[eCorrelations_vs_MeanCharge] = 1.; + title_y_CorrelationsVs[eCorrelations_vs_MeanCharge] = FancyFormatting(ph.fParticleHistogramsName[eCharge].Data()); + + // *) "eCorrelations_vs_MeantpcNClsFindable": + nBins_y_CorrelationsVs[eCorrelations_vs_MeantpcNClsFindable] = 400; + min_y_CorrelationsVs[eCorrelations_vs_MeantpcNClsFindable] = 50.; + max_y_CorrelationsVs[eCorrelations_vs_MeantpcNClsFindable] = 250.; + title_y_CorrelationsVs[eCorrelations_vs_MeantpcNClsFindable] = FancyFormatting(ph.fParticleHistogramsName[etpcNClsFindable].Data()); + + // *) "eCorrelations_vs_MeantpcNClsShared": + nBins_y_CorrelationsVs[eCorrelations_vs_MeantpcNClsShared] = 500; + min_y_CorrelationsVs[eCorrelations_vs_MeantpcNClsShared] = 0.; + max_y_CorrelationsVs[eCorrelations_vs_MeantpcNClsShared] = 100.; + title_y_CorrelationsVs[eCorrelations_vs_MeantpcNClsShared] = FancyFormatting(ph.fParticleHistogramsName[etpcNClsShared].Data()); + + // *) "eCorrelations_vs_MeanitsChi2NCl": + nBins_y_CorrelationsVs[eCorrelations_vs_MeanitsChi2NCl] = 200; + min_y_CorrelationsVs[eCorrelations_vs_MeanitsChi2NCl] = 0.; + max_y_CorrelationsVs[eCorrelations_vs_MeanitsChi2NCl] = 4.; + title_y_CorrelationsVs[eCorrelations_vs_MeanitsChi2NCl] = FancyFormatting(ph.fParticleHistogramsName[eitsChi2NCl].Data()); + + // *) "eCorrelations_vs_MeantpcNClsFound": + nBins_y_CorrelationsVs[eCorrelations_vs_MeantpcNClsFound] = 400; + min_y_CorrelationsVs[eCorrelations_vs_MeantpcNClsFound] = 50.; + max_y_CorrelationsVs[eCorrelations_vs_MeantpcNClsFound] = 250.; + title_y_CorrelationsVs[eCorrelations_vs_MeantpcNClsFound] = FancyFormatting(ph.fParticleHistogramsName[etpcNClsFound].Data()); + + // *) "eCorrelations_vs_MeantpcNClsCrossedRows": + nBins_y_CorrelationsVs[eCorrelations_vs_MeantpcNClsCrossedRows] = 400; + min_y_CorrelationsVs[eCorrelations_vs_MeantpcNClsCrossedRows] = 50.; + max_y_CorrelationsVs[eCorrelations_vs_MeantpcNClsCrossedRows] = 250.; + title_y_CorrelationsVs[eCorrelations_vs_MeantpcNClsCrossedRows] = FancyFormatting(ph.fParticleHistogramsName[etpcNClsCrossedRows].Data()); + + // *) "eCorrelations_vs_MeanitsNCls": + nBins_y_CorrelationsVs[eCorrelations_vs_MeanitsNCls] = 500; + min_y_CorrelationsVs[eCorrelations_vs_MeanitsNCls] = 0.; + max_y_CorrelationsVs[eCorrelations_vs_MeanitsNCls] = 10.; + title_y_CorrelationsVs[eCorrelations_vs_MeanitsNCls] = FancyFormatting(ph.fParticleHistogramsName[eitsNCls].Data()); + + // *) "eCorrelations_vs_MeanitsNClsInnerBarrel": + nBins_y_CorrelationsVs[eCorrelations_vs_MeanitsNClsInnerBarrel] = 400; + min_y_CorrelationsVs[eCorrelations_vs_MeanitsNClsInnerBarrel] = 0.; + max_y_CorrelationsVs[eCorrelations_vs_MeanitsNClsInnerBarrel] = 4.; + title_y_CorrelationsVs[eCorrelations_vs_MeanitsNClsInnerBarrel] = FancyFormatting(ph.fParticleHistogramsName[eitsNClsInnerBarrel].Data()); + + // *) "eCorrelations_vs_MeantpcCrossedRowsOverFindableCls": + nBins_y_CorrelationsVs[eCorrelations_vs_MeantpcCrossedRowsOverFindableCls] = 200; + min_y_CorrelationsVs[eCorrelations_vs_MeantpcCrossedRowsOverFindableCls] = 0.; + max_y_CorrelationsVs[eCorrelations_vs_MeantpcCrossedRowsOverFindableCls] = 2.; + title_y_CorrelationsVs[eCorrelations_vs_MeantpcCrossedRowsOverFindableCls] = FancyFormatting(ph.fParticleHistogramsName[etpcCrossedRowsOverFindableCls].Data()); + + // *) "eCorrelations_vs_MeantpcFoundOverFindableCls": + nBins_y_CorrelationsVs[eCorrelations_vs_MeantpcFoundOverFindableCls] = 200; + min_y_CorrelationsVs[eCorrelations_vs_MeantpcFoundOverFindableCls] = 0.8; + max_y_CorrelationsVs[eCorrelations_vs_MeantpcFoundOverFindableCls] = 1.2; + title_y_CorrelationsVs[eCorrelations_vs_MeantpcFoundOverFindableCls] = FancyFormatting(ph.fParticleHistogramsName[etpcFoundOverFindableCls].Data()); + + // *) "eCorrelations_vs_MeantpcFractionSharedCls": + nBins_y_CorrelationsVs[eCorrelations_vs_MeantpcFractionSharedCls] = 500; + min_y_CorrelationsVs[eCorrelations_vs_MeantpcFractionSharedCls] = 0.; + max_y_CorrelationsVs[eCorrelations_vs_MeantpcFractionSharedCls] = 1.; + title_y_CorrelationsVs[eCorrelations_vs_MeantpcFractionSharedCls] = FancyFormatting(ph.fParticleHistogramsName[etpcFractionSharedCls].Data()); + + // *) "eCorrelations_vs_MeantpcChi2NCl": + nBins_y_CorrelationsVs[eCorrelations_vs_MeantpcChi2NCl] = 200; + min_y_CorrelationsVs[eCorrelations_vs_MeantpcChi2NCl] = 0.; + max_y_CorrelationsVs[eCorrelations_vs_MeantpcChi2NCl] = 2.; + title_y_CorrelationsVs[eCorrelations_vs_MeantpcChi2NCl] = FancyFormatting(ph.fParticleHistogramsName[etpcChi2NCl].Data()); + + // *) "eCorrelations_vs_MeandcaXY": + nBins_y_CorrelationsVs[eCorrelations_vs_MeandcaXY] = 200; + min_y_CorrelationsVs[eCorrelations_vs_MeandcaXY] = -0.2; + max_y_CorrelationsVs[eCorrelations_vs_MeandcaXY] = 0.2; + title_y_CorrelationsVs[eCorrelations_vs_MeandcaXY] = FancyFormatting(ph.fParticleHistogramsName[edcaXY].Data()); + + // *) "eCorrelations_vs_MeandcaZ": + nBins_y_CorrelationsVs[eCorrelations_vs_MeandcaZ] = 200; + min_y_CorrelationsVs[eCorrelations_vs_MeandcaZ] = -0.2; + max_y_CorrelationsVs[eCorrelations_vs_MeandcaZ] = 0.2; + title_y_CorrelationsVs[eCorrelations_vs_MeandcaZ] = FancyFormatting(ph.fParticleHistogramsName[edcaZ].Data()); + + // ..... + + // *) Quick insanity check on title_x_CorrelationsVs and title_y_CorrelationsVs: + if (title_x_CorrelationsVs.EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : title_x_CorrelationsVs is not set, check corresponding enum \033[0m", __FUNCTION__, __LINE__); + } + for (int t = 0; t < eQACorrelationsVsHistograms2D_N; t++) { + if (title_y_CorrelationsVs[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : title_y_CorrelationsVs[%d] is not set, check corresponding enum \033[0m", __FUNCTION__, __LINE__, t); + } + } - // c) Fill reconstructed (Run 3 specific): - if constexpr (rs == eRec || rs == eRecAndSim) { - !eh.fEventHistograms[eMultFT0M][eRec][ba] ? true : eh.fEventHistograms[eMultFT0M][eRec][ba]->Fill(collision.multFT0M()); - !eh.fEventHistograms[eMultFV0M][eRec][ba] ? true : eh.fEventHistograms[eMultFV0M][eRec][ba]->Fill(collision.multFV0M()); + // Okay, let's book 'em all: + for (int t = 0; t < eQACorrelationsVsHistograms2D_N; t++) // type, see enum eQACorrelationsVsHistograms2D + { + if (!qa.fBookQACorrelationsVsHistograms2D[t]) { + continue; + } - // ... and corresponding MC truth simulated (Run 3 specific1) ( see https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx ): - if constexpr (rs == eRecAndSim) { - if (!collision.has_mcCollision()) { - LOGF(warning, "No MC collision for this collision, skip..."); - return; + for (int h = 0; h < gMaxHarmonic; h++) { + + if (h + 1 < qa.fQACorrelationsVsHistogramsMinMaxHarmonic[eMin] || h + 1 >= qa.fQACorrelationsVsHistogramsMinMaxHarmonic[eMax]) { + continue; } - // !eh.fEventHistograms[eNumberOfEvents][eSim][ba] ? true : eh.fEventHistograms[eNumberOfEvents][eSim][ba]->Fill(0.5); - } // if constexpr (rs == eRecAndSim) { - } // if constexpr (rs == eRec || rs == eRecAndSim) { - // d) Fill only simulated(Run 3 specific): - if constexpr (rs == eSim) { - // !eh.fEventHistograms[eImpactParameter][eSim][ba] ? true : eh.fEventHistograms[eImpactParameter][eSim][ba]->Fill(collision.impactParameter()); // yes, because in this branch 'collision' is always aod::McCollision - } // if constexpr (rs == eSim) { + for (int rs = 0; rs < 2; rs++) // reco/sim + { - // ----------------------------------------------------------------------------- + if (Skip(rs)) { + continue; + } - // e) Fill reconstructed (Run 2 specific): - if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2) { - //! eh.fEventHistograms[eMultFT0M][eRec][ba] ? true : eh.fEventHistograms[eMultFT0M][eRec][ba]->Fill(collision.multFT0M()); + // valgrind --tool=massif => ~58.7 MiB (Last check: 20250315) + qa.fQACorrelationsVsHistograms2D[t][h][rs] = new TH2F( + TString::Format("fQACorrelationsVsHistograms2D[%s][%d][%s]", qa.fQACorrelationsVsHistogramsName2D[t].Data(), h, gc.srs[rs].Data()), + TString::Format("%s, %s", "__RUN_NUMBER__", gc.srs_long[rs].Data()), // __RUN_NUMBER__ is handled in PropagateRunNumber(...) + nBins_x_CorrelationsVs, min_x_CorrelationsVs, max_x_CorrelationsVs, nBins_y_CorrelationsVs[t], min_y_CorrelationsVs[t], max_y_CorrelationsVs[t]); + + qa.fQACorrelationsVsHistograms2D[t][h][rs]->GetXaxis()->SetTitle(TString::Format("%s (harmonic = %d)", title_x_CorrelationsVs.Data(), h + 1)); + qa.fQACorrelationsVsHistograms2D[t][h][rs]->GetYaxis()->SetTitle(title_y_CorrelationsVs[t].Data()); + qa.fQACorrelationsVsHistograms2D[t][h][rs]->SetLineColor(ec.fBeforeAfterColor[eAfter]); + qa.fQACorrelationsVsHistograms2D[t][h][rs]->SetFillColor(ec.fBeforeAfterColor[eAfter] - 10); + qa.fQACorrelationsVsHistograms2D[t][h][rs]->SetOption("col"); + qa.fQACorrelationsVsList->Add(qa.fQACorrelationsVsHistograms2D[t][h][rs]); + } // for(int rs=0;rs<2;rs++) // reco/sim + + } // for (int h = 0; h < gMaxHarmonic; h++) { + + } // for(int t=0;t(eh.fEventHistogramsBins[eInteractionRate][0] / qa.fRebin); + double min_x_CorrelationsVsInteractionRateVs = eh.fEventHistogramsBins[eInteractionRate][1]; + double max_x_CorrelationsVsInteractionRateVs = eh.fEventHistogramsBins[eInteractionRate][2]; + TString title_x_CorrelationsVsInteractionRateVs = "interaction rate"; + int nBins_y_CorrelationsVsInteractionRateVs[eQACorrelationsVsInteractionRateVsProfiles2D_N] = {0}; + double min_y_CorrelationsVsInteractionRateVs[eQACorrelationsVsInteractionRateVsProfiles2D_N] = {0.}; + double max_y_CorrelationsVsInteractionRateVs[eQACorrelationsVsInteractionRateVsProfiles2D_N] = {0.}; + TString title_y_CorrelationsVsInteractionRateVs[eQACorrelationsVsInteractionRateVsProfiles2D_N] = {""}; + + // *) "eCorrelationsVsInteractionRate_vs_CurrentRunDuration": + nBins_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_CurrentRunDuration] = static_cast(eh.fEventHistogramsBins[eCurrentRunDuration][0] / qa.fRebin); + min_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_CurrentRunDuration] = eh.fEventHistogramsBins[eCurrentRunDuration][1]; + max_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_CurrentRunDuration] = eh.fEventHistogramsBins[eCurrentRunDuration][2]; + title_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_CurrentRunDuration] = FancyFormatting(eh.fEventHistogramsName[eCurrentRunDuration].Data()); + + // *) "eCorrelationsVsInteractionRate_vs_Multiplicity": + nBins_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_Multiplicity] = static_cast(eh.fEventHistogramsBins[eMultiplicity][0] / qa.fRebin); + min_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_Multiplicity] = eh.fEventHistogramsBins[eMultiplicity][1]; + max_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_Multiplicity] = eh.fEventHistogramsBins[eMultiplicity][2]; + title_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_Multiplicity] = FancyFormatting(eh.fEventHistogramsName[eMultiplicity].Data()); + + // *) "eCorrelationsVsInteractionRate_vs_ReferenceMultiplicity": + nBins_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_ReferenceMultiplicity] = static_cast(eh.fEventHistogramsBins[eReferenceMultiplicity][0] / qa.fRebin); + min_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_ReferenceMultiplicity] = eh.fEventHistogramsBins[eReferenceMultiplicity][1]; + max_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_ReferenceMultiplicity] = eh.fEventHistogramsBins[eReferenceMultiplicity][2]; + title_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_ReferenceMultiplicity] = FancyFormatting(eh.fEventHistogramsName[eReferenceMultiplicity].Data()); + + // *) "eCorrelationsVsInteractionRate_vs_Centrality": + nBins_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_Centrality] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); + min_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_Centrality] = eh.fEventHistogramsBins[eCentrality][1]; + max_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_Centrality] = eh.fEventHistogramsBins[eCentrality][2]; + title_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_Centrality] = FancyFormatting(eh.fEventHistogramsName[eCentrality].Data()); + + // ..... + + // *) "eCorrelationsVsInteractionRate_vs_MeanPhi": + nBins_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_MeanPhi] = 200; + min_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_MeanPhi] = 0.; + max_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_MeanPhi] = o2::constants::math::TwoPI; + title_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_MeanPhi] = FancyFormatting(ph.fParticleHistogramsName[ePhi].Data()); + + // *) "eCorrelationsVsInteractionRate_vs_SigmaMeanPhi": + nBins_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_SigmaMeanPhi] = 200; + min_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_SigmaMeanPhi] = 0.; + max_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_SigmaMeanPhi] = 1.0; + title_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_SigmaMeanPhi] = TString::Format("#sigma_{%s}", FancyFormatting(ph.fParticleHistogramsName[ePhi].Data())); + + // *) "eCorrelationsVsInteractionRate_vs_MeanPt": + nBins_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_MeanPt] = 200; + min_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_MeanPt] = 0.0; + max_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_MeanPt] = 2.0; + title_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_MeanPt] = FancyFormatting(ph.fParticleHistogramsName[ePt].Data()); + + // *) "eCorrelationsVsInteractionRate_vs_SigmaMeanPt": + nBins_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_SigmaMeanPt] = 200; + min_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_SigmaMeanPt] = 0.; + max_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_SigmaMeanPt] = 1.0; + title_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_SigmaMeanPt] = TString::Format("#sigma_{%s}", FancyFormatting(ph.fParticleHistogramsName[ePt].Data())); + + // *) "eCorrelationsVsInteractionRate_vs_MeanEta": + nBins_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_MeanEta] = 600; + min_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_MeanEta] = -0.5; + max_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_MeanEta] = 0.5; + title_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_MeanEta] = FancyFormatting(ph.fParticleHistogramsName[eEta].Data()); + + // *) "eCorrelationsVsInteractionRate_vs_SigmaMeanEta": + nBins_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_SigmaMeanEta] = 200; + min_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_SigmaMeanEta] = 0.; + max_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_SigmaMeanEta] = 1.0; + title_y_CorrelationsVsInteractionRateVs[eCorrelationsVsInteractionRate_vs_SigmaMeanEta] = TString::Format("#sigma_{%s}", FancyFormatting(ph.fParticleHistogramsName[eEta].Data())); + + // ..... + + // *) Quick insanity check on title_x_CorrelationsVsInteractionRateVs and title_y_CorrelationsVsInteractionRateVs: + if (title_x_CorrelationsVsInteractionRateVs.EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : title_x_CorrelationsVsInteractionRateVs is not set, check corresponding enum \033[0m", __FUNCTION__, __LINE__); + } + for (int t = 0; t < eQACorrelationsVsInteractionRateVsProfiles2D_N; t++) { + if (title_y_CorrelationsVsInteractionRateVs[t].EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : title_y_CorrelationsVsInteractionRateVs[%d] is not set, check corresponding enum \033[0m", __FUNCTION__, __LINE__, t); + } + } - // ... and corresponding MC truth simulated (Run 3 specific1) ( see https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx ): - if constexpr (rs == eRecAndSim_Run2) { - if (!collision.has_mcCollision()) { - LOGF(warning, "No MC collision for this collision, skip..."); - return; + // Okay, let's book 'em all: + for (int t = 0; t < eQACorrelationsVsInteractionRateVsProfiles2D_N; t++) // type, see enum eQACorrelationsVsInteractionRateVsProfiles2D + { + if (!qa.fBookQACorrelationsVsInteractionRateVsProfiles2D[t]) { + continue; + } + + for (int h = 0; h < gMaxHarmonic; h++) { + + if (h + 1 < qa.fQACorrelationsVsInteractionRateVsProfilesMinMaxHarmonic[eMin] || h + 1 >= qa.fQACorrelationsVsInteractionRateVsProfilesMinMaxHarmonic[eMax]) { + continue; } - // !eh.fEventHistograms[eNumberOfEvents][eSim][ba] ? true : eh.fEventHistograms[eNumberOfEvents][eSim][ba]->Fill(0.5); - } // if constexpr (rs == eRecAndSim_Run2) { - } // if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2) { - // f) Fill only simulated(Run 2 specific): - if constexpr (rs == eSim_Run2) { - // !eh.fEventHistograms[eImpactParameter][eSim][ba] ? true : eh.fEventHistograms[eImpactParameter][eSim][ba]->Fill(collision.impactParameter()); // yes, because in this branch 'collision' is always aod::McCollision - } // if constexpr (rs == eSim_Run2) { + for (int rs = 0; rs < 2; rs++) // reco/sim + { - // ----------------------------------------------------------------------------- + if (Skip(rs)) { + continue; + } - // g) Fill reconstructed (Run 1 specific): - if constexpr (rs == eRec_Run1 || rs == eRecAndSim_Run1) { - //! eh.fEventHistograms[eMultFT0M][eRec][ba] ? true : eh.fEventHistograms[eMultFT0M][eRec][ba]->Fill(collision.multFT0M()); + // TBI 20250317 documet here the output of profiling using valgrind --tool=massif + qa.fQACorrVsIRVsProfiles2D[t][h][rs] = new TProfile2D( + TString::Format("fQACorrVsIRVsProfiles2D[%s][%d][%s]", qa.fQACorrelationsVsInteractionRateVsProfilesName2D[t].Data(), h, gc.srs[rs].Data()), + TString::Format("%s, %s", "__RUN_NUMBER__", gc.srs_long[rs].Data()), // __RUN_NUMBER__ is handled in PropagateRunNumber(...) + nBins_x_CorrelationsVsInteractionRateVs, min_x_CorrelationsVsInteractionRateVs, max_x_CorrelationsVsInteractionRateVs, nBins_y_CorrelationsVsInteractionRateVs[t], min_y_CorrelationsVsInteractionRateVs[t], max_y_CorrelationsVsInteractionRateVs[t]); - // ... and corresponding MC truth simulated (Run 3 specific1) ( see https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx ): - if constexpr (rs == eRecAndSim_Run1) { - if (!collision.has_mcCollision()) { - LOGF(warning, "No MC collision for this collision, skip..."); - return; - } - // !eh.fEventHistograms[eNumberOfEvents][eSim][ba] ? true : eh.fEventHistograms[eNumberOfEvents][eSim][ba]->Fill(0.5); - } // if constexpr (rs == eRecAndSim_Run1) { - } // if constexpr (rs == eRec_Run1 || rs == eRecAndSim_Run1) { + TString tmp = qa.fQACorrVsIRVsProfiles2D[t][h][rs]->GetTitle(); // translating e.g. "544114, reconstructed" into "<<2>> (harmonic = 2), 544114, reconstructed" + qa.fQACorrVsIRVsProfiles2D[t][h][rs]->SetTitle(TString::Format("#LT#LT2#GT#GT (harmonic = %d), %s", h + 1, tmp.Data())); + qa.fQACorrVsIRVsProfiles2D[t][h][rs]->GetXaxis()->SetTitle(title_x_CorrelationsVsInteractionRateVs.Data()); + qa.fQACorrVsIRVsProfiles2D[t][h][rs]->GetYaxis()->SetTitle(title_y_CorrelationsVsInteractionRateVs[t].Data()); + qa.fQACorrVsIRVsProfiles2D[t][h][rs]->SetLineColor(ec.fBeforeAfterColor[eAfter]); + qa.fQACorrVsIRVsProfiles2D[t][h][rs]->SetFillColor(ec.fBeforeAfterColor[eAfter] - 10); + qa.fQACorrVsIRVsProfiles2D[t][h][rs]->SetOption("col"); + qa.fQACorrelationsVsInteractionRateVsList->Add(qa.fQACorrVsIRVsProfiles2D[t][h][rs]); + } // for(int rs=0;rs<2;rs++) // reco/sim - // h) Fill only simulated(Run 1 specific): - if constexpr (rs == eSim_Run1) { - // !eh.fEventHistograms[eImpactParameter][eSim][ba] ? true : eh.fEventHistograms[eImpactParameter][eSim][ba]->Fill(collision.impactParameter()); // yes, because in this branch 'collision' is always aod::McCollision - } // if constexpr (rs == eSim_Run1) { + } // for (int h = 0; h < gMaxHarmonic; h++) { - // ----------------------------------------------------------------------------- + } // for(int t=0;tFill(collision.posZ()); - !eh.fEventHistograms[eTotalMultiplicity][eRec][ba] ? true : eh.fEventHistograms[eTotalMultiplicity][eRec][ba]->Fill(tracks.size()); - !eh.fEventHistograms[eCentrality][eRec][ba] ? true : eh.fEventHistograms[eCentrality][eRec][ba]->Fill(ebye.fCentrality); - } // if constexpr (rs == eTest) { + // ... -} // template void FillEventHistograms(...) + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void BookQAHistograms() //============================================================ -template -Bool_t ValidTrack(T const& track) +void BookEventHistograms() { - // Before I start applying any particle tracks, check if this is a valid track. - // For instance, Run 2 or Run 1 tracklets are NOT valid tracks, as they carry no pt information, and in this function they are filtered out. - - // See enum TrackTypeEnum in O2/Framework/Core/include/Framework/DataTypes.h for further info. + // Book all event histograms. - // a) Validity checks for tracks in Run 3; - // b) Validity checks for tracks in Run 2 and 1. + // a) Book the profile holding flags; + // b) Book specific event histograms 1D; + // c) Book specific event histograms 2D. - if (tc.fVerboseForEachParticle) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + if (tc.fVerbose) { + StartFunction(__FUNCTION__); } - // a) Validity checks for tracks in Run 3; - // *) Ensure that I am taking into account propagated tracks (and not e.g. track evaluated at innermost update): - if constexpr (rs == eRec || rs == eRecAndSim) { - if (!(track.trackType() == o2::aod::track::TrackTypeEnum::Track)) { - return kFALSE; - } - } + // a) Book the profile holding flags: + eh.fEventHistogramsPro = new TProfile("fEventHistogramsPro", "flags for event histograms", 1, 0., 1.); + eh.fEventHistogramsPro->SetStats(false); + eh.fEventHistogramsPro->SetLineColor(eColor); + eh.fEventHistogramsPro->SetFillColor(eFillColor); + eh.fEventHistogramsPro->GetXaxis()->SetBinLabel(1, "fFillEventHistograms"); + eh.fEventHistogramsPro->Fill(0.5, static_cast(eh.fFillEventHistograms)); + // ... + eh.fEventHistogramsList->Add(eh.fEventHistogramsPro); - // b) Validity checks for tracks in Run 2 and 1: - // *) Ensure that tracklets (no pt information) are skipped: - // if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { - if constexpr (rs == eRec_Run2 || rs == eRec_Run1) { // TBI 20240226 the check below is crashing for eRecAndSim_Run2 , disabling that case here temporarily. Use eventually the above line - if (!(track.trackType() == o2::aod::track::TrackTypeEnum::Run2Track)) { - return kFALSE; + // b) Book specific control event histograms 1D: + // ... + + for (int t = 0; t < eEventHistograms_N; t++) // type, see enum eEventHistograms + { + if (!eh.fBookEventHistograms[t]) { + continue; } - } - // *) Temporary here, until I cover also these cases: - if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { - LOGF(fatal, "in function \033[1;31m%s at line %d : add support for TrackTypeEnum here also for cases eSim, eSim_Run2 and eSim_Run1\033[0m", __PRETTY_FUNCTION__, __LINE__); - } + for (int rs = 0; rs < 2; rs++) // reco/sim + { + if (Skip(rs)) { + continue; + } - // *) In case there are still some pathological cases with one of kine variable being "nan", treat 'em here: - // TBI 20240228 disable eventually this check, or add a flag to switch it on/off - if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { - if (isnan(track.phi()) || isnan(track.pt()) || isnan(track.eta())) { - LOGF(error, "\033[1;33m%s nan hit, skipping this track \033[0m", __PRETTY_FUNCTION__); - LOGF(error, "dPhi = %f\ndPt = %f\ndEta = %f\ntrackType() = %d", track.phi(), track.pt(), track.eta(), static_cast(track.trackType())); // TBI 20240226 check if I need this cast here - return kFALSE; - } - } + for (int ba = 0; ba < 2; ba++) // before/after cuts + { - // *) All checks above survived, then it's a valid track: - return kTRUE; + // Special treatment for eMultiplicity => I will never fill this one before the cuts, if Multiplicity = SelectedTracks, obviously: + if (ba == eBefore && eh.fEventHistogramsName[t].EqualTo("Multiplicity") && ec.fsEventCuts[eMultiplicityEstimator].EqualTo("SelectedTracks", TString::kIgnoreCase)) { + // TBI 20241123 what remains ill-defined is the case when Multiplicity != SelectedTracks , check that further + continue; + } + eh.fEventHistograms[t][rs][ba] = new TH1F( + TString::Format("fEventHistograms[%s][%s][%s]", eh.fEventHistogramsName[t].Data(), gc.srs[rs].Data(), gc.sba[ba].Data()), + TString::Format("%s, %s, %s", "__RUN_NUMBER__", gc.srs_long[rs].Data(), gc.sba_long[ba].Data()), // __RUN_NUMBER__ is handled in PropagateRunNumber(...) + static_cast(eh.fEventHistogramsBins[t][0]), + eh.fEventHistogramsBins[t][1], eh.fEventHistogramsBins[t][2]); + eh.fEventHistograms[t][rs][ba]->GetXaxis()->SetTitle(FancyFormatting(eh.fEventHistogramsName[t].Data())); + eh.fEventHistograms[t][rs][ba]->SetLineColor(ec.fBeforeAfterColor[ba]); + eh.fEventHistograms[t][rs][ba]->SetFillColor(ec.fBeforeAfterColor[ba] - 10); + eh.fEventHistogramsList->Add(eh.fEventHistograms[t][rs][ba]); + } // for(int ba=0;ba<2;ba++) + } // for(int rs=0;rs<2;rs++) // reco/sim + } // for(int t=0;t Bool_t ValidTrack(T const& track) +} // void BookEventHistograms() //============================================================ -template -Bool_t ParticleCuts(T const& track) +void BookEventCutsHistograms() { - // Particles cuts. + // Book all event cuts objects. - // a) Particle cuts on info available in reconstructed (and corresponding MC truth simulated); - // b) Particle cuts on info available only in simulated data; - // c) Test case. + // a) Book the profile holding event cuts flags; + // b) Book event cut counter maps; + // c) Book event cut counter histograms; + // d) Book the formulas for all event cuts defined via mathematical expressions. - // TBI 20240213 at the moment, I take that there is nothing specific for Run 3, 2, 1 here. Otherwise, see what I did in EventCuts + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } - if (tc.fVerboseForEachParticle) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + // a) Book the profile holding flags: + ec.fEventCutsPro = new TProfile("fEventCutsPro", "flags for event cuts", eEventCuts_N, -0.5, static_cast(eEventCuts_N) - 0.5); + if (tc.fUseSpecificCuts) { + ec.fEventCutsPro->SetTitle(TString::Format("%s (hardwired analysis-specific cuts = %s)", ec.fEventCutsPro->GetTitle(), tc.fWhichSpecificCuts.Data()).Data()); + } else { + ec.fEventCutsPro->SetTitle(TString::Format("%s (hardwired analysis-specific cuts not used)", ec.fEventCutsPro->GetTitle()).Data()); + } + ec.fEventCutsPro->SetStats(false); + ec.fEventCutsPro->SetLineColor(eColor); + ec.fEventCutsPro->SetFillColor(eFillColor); + ec.fEventCutsPro->GetXaxis()->SetLabelSize(0.020); + for (int cut = 0; cut < eEventCuts_N; cut++) { + ec.fEventCutsPro->GetXaxis()->SetBinLabel(1 + cut, ec.fEventCutName[cut].Data()); // Remark: check always if bin labels here correspond to ordering in enum eEventCuts + ec.fEventCutsPro->Fill(cut, static_cast(ec.fUseEventCuts[cut])); } + ec.fEventCutsList->Add(ec.fEventCutsPro); - // a) Particle cuts on info available in reconstructed ...: - if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { - if ((track.pt() < pt_min) || (track.pt() > pt_max)) { - return kFALSE; + // b) Book event cut counter maps: + for (int rs = 0; rs < 2; rs++) // reco/sim + { + // If I am analyzing only reconstructed data, do not book maps for simulated, and vice versa. + if ((tc.fProcess[eGenericRec] && rs == eSim) || (tc.fProcess[eGenericSim] && rs == eRec)) { + continue; } + ec.fEventCutCounterMap[rs] = new TExMap(); + ec.fEventCutCounterMapInverse[rs] = new TExMap(); + } - // TBI 20231107 other cuts on reconstructed track ... + // c) Book event cut counter histograms: + // ... + for (int rs = 0; rs < 2; rs++) // reco/sim + { - // ... and corresponding MC truth simulated ( see https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx ): - if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { - if (!track.has_mcParticle()) { - LOGF(warning, "No MC particle for this track, skip..."); - return kFALSE; // TBI 20231107 re-think. I shouldn't probably get to this point, if MC truth info doesn't exist for this particle - } - auto mcparticle = track.mcParticle(); // corresponding MC truth simulated particle - if ((mcparticle.pt() < pt_min) || (mcparticle.pt() > pt_max)) { // TBI 20231107 re-thing if i really cut directly on MC truth, keep it in sync with what I did in AliPhysics - return kFALSE; + if (Skip(rs)) { + continue; + } + + for (int cc = 0; cc < eCutCounter_N; cc++) // cut counter + { + + if ((!ec.fUseEventCutCounterAbsolute && cc == eAbsolute) || (!ec.fUseEventCutCounterSequential && cc == eSequential)) { + continue; } - // TBI 20231107 other cuts on corresponding MC truth particle ... + ec.fEventCutCounterHist[rs][cc] = new TH1F(TString::Format("fEventCutCounterHist[%s][%s]", gc.srs[rs].Data(), gc.scc[cc].Data()), TString::Format("%s, %s, event cut counter (%s)", "__RUN_NUMBER__", gc.srs_long[rs].Data(), gc.scc_long[cc].Data()), eEventCuts_N, 0.5, static_cast(eEventCuts_N) + 0.5); // I cast in double the last argument, because that's what this particular TH1I constructor expects. And yes, +0.5, because eEventCuts kicks off from 0 + ec.fEventCutCounterHist[rs][cc]->SetStats(false); + ec.fEventCutCounterHist[rs][cc]->SetLineColor(eColor); + ec.fEventCutCounterHist[rs][cc]->SetFillColor(eFillColor); + ec.fEventCutCounterHist[rs][cc]->GetXaxis()->SetLabelSize(0.025); - } // if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { - } // if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { + // Remark: Bin labels are set later in a dry call to EventCuts, to accomodate sequential event cut counting + ec.fEventCutsList->Add(ec.fEventCutCounterHist[rs][cc]); - // b) Particle cuts on info available only in simulated data: - if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { - // Remark: in this branch, 'track' is always TracksSim = aod::McParticles - if ((track.pt() < pt_min) || (track.pt() > pt_max)) { - return kFALSE; - } + } // for (int cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter - // TBI 20231107 other cuts on simulated ... + } // for (int rs = 0; rs < 2; rs++) // reco/sim - } // if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { + // d) Book the formulas for all event cuts defined via mathematical expressions: - // c) Test case: - // TBI 2024023 for the time being, eTest cuts only on eRec info. - if constexpr (rs == eTest) { - if ((track.pt() < pt_min) || (track.pt() > pt_max)) { - return kFALSE; + // **) eRefMultVsNContrUp: + if (ec.fUseEventCuts[eRefMultVsNContrUp]) { + ec.fEventCutsFormulas[eRefMultVsNContrUp_Formula] = new TFormula("RefMultVsNContrUp_Formula", ec.fsEventCuts[eRefMultVsNContrUp].Data()); + // As a quick insanity check, try immediately to evaluate something from this formula: + if (std::isnan(ec.fEventCutsFormulas[eRefMultVsNContrUp_Formula]->Eval(1.44))) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - } // if constexpr (rs == eTest) { + } - return kTRUE; + // **) eRefMultVsNContrLow: + if (ec.fUseEventCuts[eRefMultVsNContrLow]) { + ec.fEventCutsFormulas[eRefMultVsNContrLow_Formula] = new TFormula("RefMultVsNContrLow_Formula", ec.fsEventCuts[eRefMultVsNContrLow].Data()); + // As a quick insanity check, try immediately to evaluate something from this formula: + if (std::isnan(ec.fEventCutsFormulas[eRefMultVsNContrLow_Formula]->Eval(1.44))) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } -} // template Bool_t ParticleCuts(T const& track) +} // void BookEventCutsHistograms() //============================================================ -template -void FillParticleHistograms(T const& track, eBeforeAfter ba) +void BookParticleHistograms() { - // Fill all particle histograms for reconstructed and simulated data. + // Book all particle histograms. - // a) Fill reconstructed (and corresponding MC truth simulated); - // b) Fill only simulated; - // c) Test case. + // a) Book the profile holding flags; + // b) Book specific particle histograms 1D; + // c) Book specific particle histograms 2D; + // e) Default binning for particle sparse histograms (yes, here, see comments below); + // d) Book specific particle sparse histograms (n-dimensions). - if (tc.fVerboseForEachParticle) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + if (tc.fVerbose) { + StartFunction(__FUNCTION__); } - // a) Fill reconstructed ...: - if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { - !ph.fParticleHistograms[ePhi][eRec][ba] ? true : ph.fParticleHistograms[ePhi][eRec][ba]->Fill(track.phi()); // basically, if hist is not booked, do nothing. 'true' is a placeholder, for the time being - !ph.fParticleHistograms[ePt][eRec][ba] ? true : ph.fParticleHistograms[ePt][eRec][ba]->Fill(track.pt()); - !ph.fParticleHistograms[eEta][eRec][ba] ? true : ph.fParticleHistograms[eEta][eRec][ba]->Fill(track.eta()); + // a) Book the profile holding flags: + ph.fParticleHistogramsPro = new TProfile( + "fParticleHistogramsPro", "flags for particle histograms", 1, 0., 1.); + ph.fParticleHistogramsPro->SetStats(false); + ph.fParticleHistogramsPro->SetLineColor(eColor); + ph.fParticleHistogramsPro->SetFillColor(eFillColor); + ph.fParticleHistogramsPro->GetXaxis()->SetLabelSize(0.025); + ph.fParticleHistogramsPro->GetXaxis()->SetBinLabel(1, "fFillParticleHistograms"); + ph.fParticleHistogramsPro->Fill(0.5, static_cast(ph.fFillParticleHistograms)); + // ... + ph.fParticleHistogramsList->Add(ph.fParticleHistogramsPro); - // ... and corresponding MC truth simulated ( see https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx ): - if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { - if (!track.has_mcParticle()) { - LOGF(warning, "No MC particle for this track, skip..."); - return; + // b) Book specific particle histograms 1D: + // ... + for (int t = 0; t < eParticleHistograms_N; t++) // type, see enum eParticleHistograms + { + if (!ph.fBookParticleHistograms[t]) { + continue; + } + for (int rs = 0; rs < 2; rs++) // reco/sim + { + + if (Skip(rs)) { + continue; } - auto mcparticle = track.mcParticle(); // corresponding MC truth simulated particle - !ph.fParticleHistograms[ePhi][eSim][ba] ? true : ph.fParticleHistograms[ePhi][eSim][ba]->Fill(mcparticle.phi()); - !ph.fParticleHistograms[ePt][eSim][ba] ? true : ph.fParticleHistograms[ePt][eSim][ba]->Fill(mcparticle.pt()); - !ph.fParticleHistograms[eEta][eSim][ba] ? true : ph.fParticleHistograms[eEta][eSim][ba]->Fill(mcparticle.eta()); - !ph.fParticleHistograms[ePDG][eSim][ba] ? true : ph.fParticleHistograms[ePDG][eSim][ba]->Fill(mcparticle.pdgCode()); - } // if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { - } // if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { - // b) Fill only simulated: - if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { - // Remark: in this branch, 'track' is always TracksSim = aod::McParticles - !ph.fParticleHistograms[ePhi][eSim][ba] ? true : ph.fParticleHistograms[ePhi][eSim][ba]->Fill(track.phi()); - !ph.fParticleHistograms[ePt][eSim][ba] ? true : ph.fParticleHistograms[ePt][eSim][ba]->Fill(track.pt()); - !ph.fParticleHistograms[eEta][eSim][ba] ? true : ph.fParticleHistograms[eEta][eSim][ba]->Fill(track.eta()); - !ph.fParticleHistograms[ePDG][eSim][ba] ? true : ph.fParticleHistograms[ePDG][eSim][ba]->Fill(track.pdgCode()); - } // if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { + // **) PDG makes sense only for Sim: + if ((tc.fProcess[eGenericRec] || tc.fProcess[eGenericRecSim]) && rs == eRec) { + if (t == ePDG) { + continue; + } + } - /* TBI 20231019 use also these + check further - // From aod::TracksExtra - ph.fParticleHistograms[etpcNClsCrossedRows][rs][ba]->Fill(track.tpcNClsCrossedRows()); + for (int ba = 0; ba < 2; ba++) // before/after cuts + { + ph.fParticleHistograms[t][rs][ba] = new TH1F(TString::Format("fParticleHistograms[%s][%s][%s]", ph.fParticleHistogramsName[t].Data(), gc.srs[rs].Data(), gc.sba[ba].Data()), + TString::Format("%s, %s, %s", "__RUN_NUMBER__", gc.srs_long[rs].Data(), gc.sba_long[ba].Data()), + static_cast(ph.fParticleHistogramsBins[t][0]), ph.fParticleHistogramsBins[t][1], ph.fParticleHistogramsBins[t][2]); + ph.fParticleHistograms[t][rs][ba]->SetLineColor(ec.fBeforeAfterColor[ba]); + ph.fParticleHistograms[t][rs][ba]->SetFillColor(ec.fBeforeAfterColor[ba] - 10); + ph.fParticleHistograms[t][rs][ba]->GetXaxis()->SetTitle(FancyFormatting(ph.fParticleHistogramsName[t].Data())); + ph.fParticleHistograms[t][rs][ba]->SetMinimum(1.e-4); // so that I can switch to log scale, even if some bins are empty + // Remark: For empty histograms, when plotting interactively, because of this line, I will get + // E-TCanvas::Range: illegal world coordinates range .... + // But it's harmless, because in any case I do not care about the content of empty histogram... + ph.fParticleHistograms[t][rs][ba]->SetOption("hist"); // do not plot marker and error (see BanishmentLoopOverParticles why errors are not reliable) for each bin, only content + filled area. + ph.fParticleHistogramsList->Add(ph.fParticleHistograms[t][rs][ba]); + } // for(int ba=0;ba<2;ba++) + } // for(int rs=0;rs<2;rs++) // reco/sim + } // for(int t=0;tFill(track.dcaXY()); - ph.fParticleHistograms[eDCA_z][rs][ba]->Fill(track.dcaZ()); - */ + // c) Book specific particle histograms 2D: + // keep ordering in sync. with enum eParticleHistograms2D + TString stitleX2D[] = {FancyFormatting(ph.fParticleHistogramsName[ePhi].Data()), FancyFormatting(ph.fParticleHistogramsName[ePhi].Data())}; + TString stitleY2D[] = {FancyFormatting(ph.fParticleHistogramsName[ePt].Data()), FancyFormatting(ph.fParticleHistogramsName[eEta].Data())}; + + if (sizeof(stitleX2D) / sizeof(stitleX2D[0]) != eParticleHistograms2D_N) { + LOGF(info, "\033[1;31m mismatch - add same number of names for 2D particle histograms as you have data members \033[0m"); + LOGF(info, "\033[1;31m sizeof(stitleX2D)/sizeof(stitleX2D[0]) = %d \033[0m", sizeof(stitleX2D) / sizeof(stitleX2D[0])); + LOGF(info, "\033[1;31m eParticleHistograms2D_N = %d \033[0m", static_cast(eParticleHistograms2D_N)); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + if (sizeof(stitleY2D) / sizeof(stitleY2D[0]) != eParticleHistograms2D_N) { + LOGF(info, "\033[1;31m mismatch - add same number of names for 2D particle histograms as you have data members \033[0m"); + LOGF(info, "\033[1;31m sizeof(stitleY2D)/sizeof(stitleY2D[0]) = %d \033[0m", sizeof(stitleY2D) / sizeof(stitleY2D[0])); + LOGF(info, "\033[1;31m eParticleHistograms2D_N = %d \033[0m", static_cast(eParticleHistograms2D_N)); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + for (int t = 0; t < eParticleHistograms2D_N; t++) // type, see enum eParticleHistograms2D + { + if (!ph.fBookParticleHistograms2D[t]) { + continue; + } + for (int rs = 0; rs < 2; rs++) // reco/sim + { + + if (Skip(rs)) { + continue; + } + + for (int ba = 0; ba < 2; ba++) // before/after cuts + { + + // optional variable-length binning for y-axis (for supported observables): + if (ph.fParticleHistogramsName2D[t].EqualTo("Phi_vs_Pt") && res.fUseResultsProVariableLengthBins[AFO_PT]) { + + // Remark: placeholder __RUN_NUMBER__ is handled in PropagateRunNumber(...) + + // *) variable-length binning for phi vs pt, but only in pt axis: + ph.fParticleHistograms2D[t][rs][ba] = new TH2D(TString::Format("fParticleHistograms2D[%s][%s][%s]", ph.fParticleHistogramsName2D[t].Data(), gc.srs[rs].Data(), gc.sba[ba].Data()), + TString::Format("%s, %s, %s", "__RUN_NUMBER__", gc.srs_long[rs].Data(), gc.sba_long[ba].Data()), + static_cast(ph.fParticleHistogramsBins2D[t][eX][0]), ph.fParticleHistogramsBins2D[t][eX][1], ph.fParticleHistogramsBins2D[t][eX][2], + res.fResultsPro[AFO_PT]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_PT]->GetXaxis()->GetXbins()->GetArray()); // yes, x-axis of "results vs pt" hist is y-axis here for 2D. + } else if (ph.fParticleHistogramsName2D[t].EqualTo("Phi_vs_Eta") && res.fUseResultsProVariableLengthBins[AFO_ETA]) { + + // *) variable-length binning for phi vs eta, but only in eta axis: + ph.fParticleHistograms2D[t][rs][ba] = new TH2D(TString::Format("fParticleHistograms2D[%s][%s][%s]", ph.fParticleHistogramsName2D[t].Data(), gc.srs[rs].Data(), gc.sba[ba].Data()), + TString::Format("%s, %s, %s", "__RUN_NUMBER__", gc.srs_long[rs].Data(), gc.sba_long[ba].Data()), + static_cast(ph.fParticleHistogramsBins2D[t][eX][0]), ph.fParticleHistogramsBins2D[t][eX][1], ph.fParticleHistogramsBins2D[t][eX][2], + res.fResultsPro[AFO_ETA]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_ETA]->GetXaxis()->GetXbins()->GetArray()); // yes, x-axis of "results vs pt" hist is y-axis here for 2D + } else { + // default fixed-length binning: + // Remark: Remember that I cannot use here GetXaxis()->GetXbins()->GetArray() as for variable-width case, because for fixed-width case, this is always 0 + // See https://root-forum.cern.ch/t/get-bin-array/7276/9 + ph.fParticleHistograms2D[t][rs][ba] = new TH2D(TString::Format("fParticleHistograms2D[%s][%s][%s]", ph.fParticleHistogramsName2D[t].Data(), gc.srs[rs].Data(), gc.sba[ba].Data()), + TString::Format("%s, %s, %s", "__RUN_NUMBER__", gc.srs_long[rs].Data(), gc.sba_long[ba].Data()), + static_cast(ph.fParticleHistogramsBins2D[t][eX][0]), ph.fParticleHistogramsBins2D[t][eX][1], ph.fParticleHistogramsBins2D[t][eX][2], + static_cast(ph.fParticleHistogramsBins2D[t][eY][0]), ph.fParticleHistogramsBins2D[t][eY][1], ph.fParticleHistogramsBins2D[t][eY][2]); + } + ph.fParticleHistograms2D[t][rs][ba]->SetLineColor(ec.fBeforeAfterColor[ba]); + ph.fParticleHistograms2D[t][rs][ba]->SetFillColor(ec.fBeforeAfterColor[ba] - 10); + ph.fParticleHistograms2D[t][rs][ba]->GetXaxis()->SetTitle(stitleX2D[t].Data()); + ph.fParticleHistograms2D[t][rs][ba]->GetYaxis()->SetTitle(stitleY2D[t].Data()); + ph.fParticleHistogramsList->Add(ph.fParticleHistograms2D[t][rs][ba]); + } // for(int ba=0;ba<2;ba++) + } // for(int rs=0;rs<2;rs++) // reco/sim + } // for(int t=0;t(180. / ph.fRebinSparse); + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiPhiAxis], 0., o2::constants::math::TwoPI); + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiPhiAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiPhiAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiPhiAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); + } + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiPhiAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin + delete lAxis; + ph.fParticleSparseHistogramsAxisTitle[eDWPhi][wPhiPhiAxis] = FancyFormatting("Phi"); + + // ***) pt-axis for diff phi weights: I re-use binning from results histograms + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiPtAxis] = res.fResultsPro[AFO_PT]->GetNbinsX(); + lAxis = res.fResultsPro[AFO_PT]->GetXaxis(); + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiPtAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiPtAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiPtAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); + } + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiPtAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin + // delete lAxis; // I do not need to delete here, only when new TAxis(...) + ph.fParticleSparseHistogramsAxisTitle[eDWPhi][wPhiPtAxis] = FancyFormatting("Pt"); + + // ***) eta-axis for diff phi weights: I re-use binning from results histograms + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiEtaAxis] = res.fResultsPro[AFO_ETA]->GetNbinsX(); + lAxis = res.fResultsPro[AFO_ETA]->GetXaxis(); + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiEtaAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiEtaAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiEtaAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); + } + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiEtaAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin + // delete lAxis; // I do not need to delete here, only when new TAxis(...) + ph.fParticleSparseHistogramsAxisTitle[eDWPhi][wPhiEtaAxis] = FancyFormatting("Eta"); + + // ***) charge-axis for diff phi weights: I support only fixed-length binning, nothing really to ever change here: + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiChargeAxis] = 2; + lAxis = new TAxis(ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiChargeAxis], -1.5, 1.5); + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiChargeAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiChargeAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiChargeAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); + } + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiChargeAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin + // delete lAxis; // I do not need to delete here, only when new TAxis(...) + ph.fParticleSparseHistogramsAxisTitle[eDWPhi][wPhiChargeAxis] = FancyFormatting("Charge"); + + // ***) centrality-axis for diff phi weights: I re-use binning from results histograms + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiCentralityAxis] = res.fResultsPro[AFO_CENTRALITY]->GetNbinsX(); + lAxis = res.fResultsPro[AFO_CENTRALITY]->GetXaxis(); + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiCentralityAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiCentralityAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiCentralityAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); + } + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiCentralityAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin + // delete lAxis; // I do not need to delete here, only when new TAxis(...) + ph.fParticleSparseHistogramsAxisTitle[eDWPhi][wPhiCentralityAxis] = "Centrality"; // TBI 20250222 I cannot call here FancyFormatting for "Centrality", because ec.fsEventCuts[eCentralityEstimator] is still not fetched and set from configurable. Re-think how to proceed for this specific case. + + // ***) VertexZ-axis for diff phi weights: I re-use binning from results histograms + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiVertexZAxis] = res.fResultsPro[AFO_VZ]->GetNbinsX(); + lAxis = res.fResultsPro[AFO_VZ]->GetXaxis(); + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiVertexZAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiVertexZAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiVertexZAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); + } + ph.fParticleSparseHistogramsBinEdges[eDWPhi][wPhiVertexZAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin + // delete lAxis; // I do not need to delete here, only when new TAxis(...) + ph.fParticleSparseHistogramsAxisTitle[eDWPhi][wPhiVertexZAxis] = "VertexZ"; // TBI 20250222 I cannot call here FancyFormatting for "Centrality", because ec.fsEventCuts[eCentralityEstimator] + + // ... + + // **) eDiffWeightCategory = eDWPt: + + // ***) pt-axis for diff pt weights: I re-use binning from results histograms + ph.fParticleSparseHistogramsNBins[eDWPt][wPtPtAxis] = res.fResultsPro[AFO_PT]->GetNbinsX(); + lAxis = res.fResultsPro[AFO_PT]->GetXaxis(); + ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtPtAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPt][wPtPtAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtPtAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); + } + ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtPtAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin + // delete lAxis; // I do not need to delete here, only when new TAxis(...) + ph.fParticleSparseHistogramsAxisTitle[eDWPt][wPtPtAxis] = FancyFormatting("Pt"); + + // ... + + // **) eDiffWeightCategory = eDWEta: + + // ***) eta-axis for diff eta weights: I re-use binning from results histograms + ph.fParticleSparseHistogramsNBins[eDWEta][wEtaEtaAxis] = res.fResultsPro[AFO_ETA]->GetNbinsX(); + lAxis = res.fResultsPro[AFO_ETA]->GetXaxis(); + ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaEtaAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWEta][wEtaEtaAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaEtaAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); + } + ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaEtaAxis]->AddAt(lAxis->GetBinLowEdge(1 + lAxis->GetNbins()), lAxis->GetNbins()); // special treatment for last bin + // delete lAxis; // I do not need to delete here, only when new TAxis(...) + ph.fParticleSparseHistogramsAxisTitle[eDWEta][wEtaEtaAxis] = FancyFormatting("Eta"); + + // ... + + // e) Book specific particle sparse histograms (n-dimensions): + if (ph.fBookParticleSparseHistograms[eDWPhi]) { + BookParticleSparseHistograms(eDWPhi); + } + + if (ph.fBookParticleSparseHistograms[eDWPt]) { + BookParticleSparseHistograms(eDWPt); + } + + if (ph.fBookParticleSparseHistograms[eDWEta]) { + BookParticleSparseHistograms(eDWEta); + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void BookParticleHistograms() + +//============================================================ + +void BookParticleSparseHistograms(eDiffWeightCategory dwc) +{ + // This is a helper function for BookParticleHistograms(), merely to reduce code bloat. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // *) Determine number of dimensions for sparse histogram for this differential weight category: + int nDimensions = -1; + switch (dwc) { + case eDWPhi: { + nDimensions = static_cast(eDiffPhiWeights_N); + break; + } + case eDWPt: { + nDimensions = static_cast(eDiffPtWeights_N); + break; + } + case eDWEta: { + nDimensions = static_cast(eDiffEtaWeights_N); + break; + } + default: { + LOGF(fatal, "\033[1;31m%s at line %d : This differential weight category, dwc = %d, is not supported yet. \033[0m", __FUNCTION__, __LINE__, static_cast(dwc)); + break; + } + } // switch(dwc) + + // *) Determine binning for all dimensions: + TArrayI* nBins = new TArrayI(nDimensions); + for (int d = 0; d < nDimensions; d++) { + nBins->AddAt(static_cast(ph.fParticleSparseHistogramsNBins[dwc][d]), d); + } + + // *) Book THnSparse with correct number of bins for each dimension, but void bin edges: + for (int rs = 0; rs < 2; rs++) // reco/sim + { + if (Skip(rs)) { + continue; + } + // Remark: Here I have a bit unusual convention for the name and title, but okay... + ph.fParticleSparseHistograms[dwc][rs] = new THnSparseF(TString::Format("%s[%s]", ph.fParticleSparseHistogramsName[dwc].Data(), gc.srs[rs].Data()), TString::Format("__RUN_NUMBER__, %s, %s", gc.srs_long[rs].Data(), ph.fParticleSparseHistogramsTitle[dwc].Data()), nDimensions, nBins->GetArray(), NULL, NULL); + + // *) For each dimension set bin edges, axis title, etc.: + for (int d = 0; d < nDimensions; d++) { + ph.fParticleSparseHistograms[dwc][rs]->SetBinEdges(d, ph.fParticleSparseHistogramsBinEdges[dwc][d]->GetArray()); + ph.fParticleSparseHistograms[dwc][rs]->GetAxis(d)->SetTitle(ph.fParticleSparseHistogramsAxisTitle[dwc][d].Data()); + } + + // *) Finally, add the fully configured THnSparse to its TList: + ph.fParticleHistogramsList->Add(ph.fParticleSparseHistograms[dwc][rs]); + } // for (int rs = 0; rs < 2; rs++) // reco/sim + + // *) Clean up: + delete nBins; + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void BookParticleSparseHistograms() + +//============================================================ + +void BookParticleCutsHistograms() +{ + // Book all particle cuts objects. + + // a) Book the profile holding flags; + // b) Book particle cut counter maps; + // c) Book the particle cut counter (absolute); + // d) Book the formula for pt-dependent DCAxy cut. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Book the profile holding flags: + pc.fParticleCutsPro = new TProfile("fParticleCutsPro", "flags for particle cuts", eParticleCuts_N, -0.5, static_cast(eParticleCuts_N) - 0.5); + if (tc.fUseSpecificCuts) { + pc.fParticleCutsPro->SetTitle(TString::Format("%s (hardwired analysis-specific cuts = %s)", pc.fParticleCutsPro->GetTitle(), tc.fWhichSpecificCuts.Data()).Data()); + } else { + pc.fParticleCutsPro->SetTitle(TString::Format("%s (hardwired analysis-specific cuts not used)", pc.fParticleCutsPro->GetTitle()).Data()); + } + pc.fParticleCutsPro->SetStats(false); + pc.fParticleCutsPro->SetLineColor(eColor); + pc.fParticleCutsPro->SetFillColor(eFillColor); + for (int cut = 0; cut < eParticleCuts_N; cut++) { + pc.fParticleCutsPro->GetXaxis()->SetBinLabel(1 + cut, pc.fParticleCutName[cut].Data()); // Remark: check always if bin labels here correspond to ordering in enum eParticleCuts + pc.fParticleCutsPro->Fill(cut, static_cast(pc.fUseParticleCuts[cut])); + } + pc.fParticleCutsList->Add(pc.fParticleCutsPro); + + // b) Book particle cut counter maps: + for (int rs = 0; rs < 2; rs++) // reco/sim + { + // If I am analyzing only reconstructed data, do not book maps for simulated, and vice versa. + if ((tc.fProcess[eGenericRec] && rs == eSim) || (tc.fProcess[eGenericSim] && rs == eRec)) { + continue; + } + pc.fParticleCutCounterMap[rs] = new TExMap(); + pc.fParticleCutCounterMapInverse[rs] = new TExMap(); + } + + // c) Book the particle cut counter (absolute): + // ... + for (int rs = 0; rs < 2; rs++) // reco/sim + { + + if (Skip(rs)) { + continue; + } + + for (int cc = 0; cc < eCutCounter_N; cc++) // cut counter + { + + if ((!pc.fUseParticleCutCounterAbsolute && cc == eAbsolute) || (!pc.fUseParticleCutCounterSequential && cc == eSequential)) { + continue; + } + + pc.fParticleCutCounterHist[rs][cc] = new TH1I(TString::Format("fParticleCutCounterHist[%s][%s]", gc.srs[rs].Data(), gc.scc[cc].Data()), TString::Format("%s, %s, particle cut counter (%s)", "__RUN_NUMBER__", gc.srs_long[rs].Data(), gc.scc_long[cc].Data()), eParticleCuts_N, 0.5, static_cast(eParticleCuts_N) + 0.5); + // I cast in double the last argument, because that's what this particular TH1I constructor expects + // Yes, +0.5, because eParticleCuts kicks off from 0 + pc.fParticleCutCounterHist[rs][cc]->SetStats(false); + pc.fParticleCutCounterHist[rs][cc]->SetLineColor(eColor); + pc.fParticleCutCounterHist[rs][cc]->SetFillColor(eFillColor); + pc.fParticleCutCounterHist[rs][cc]->GetXaxis()->SetLabelSize(0.025); + // Remark: Bin labels are set later in a dry call to ParticleCuts, to accomodate sequential particle cut counting + pc.fParticleCutsList->Add(pc.fParticleCutCounterHist[rs][cc]); + + } // for (int cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter + + } // for (int rs = 0; rs < 2; rs++) // reco/sim + + // d) Book the formula for pt-dependent DCAxy cut: + if (pc.fUseParticleCuts[ePtDependentDCAxyParameterization]) { + pc.fPtDependentDCAxyFormula = new TFormula("fPtDependentDCAxyFormula", pc.fsParticleCuts[ePtDependentDCAxyParameterization].Data()); + // As a quick insanity check, try immediately to evaluate something from this formula: + if (std::isnan(pc.fPtDependentDCAxyFormula->Eval(1.44))) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } // if(pc.fUseParticleCuts[ePtDependentDCAxyParameterization]) { + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void BookParticleCutsHistograms() + +//============================================================ + +void BookQvectorHistograms() +{ + // Book all Q-vector histograms. + + // a) Book the profile holding flags; + // b) Book multiplicity distributions in A and B, for each eta separation; + // c) ... + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Book the profile holding flags: + qv.fQvectorFlagsPro = + new TProfile("fQvectorFlagsPro", "flags for Q-vector objects", 3, 0., 3.); + qv.fQvectorFlagsPro->SetStats(false); + qv.fQvectorFlagsPro->SetLineColor(eColor); + qv.fQvectorFlagsPro->SetFillColor(eFillColor); + qv.fQvectorFlagsPro->GetXaxis()->SetLabelSize(0.05); + qv.fQvectorFlagsPro->GetXaxis()->SetBinLabel(1, "fCalculateQvectors"); + qv.fQvectorFlagsPro->Fill(0.5, qv.fCalculateQvectors); + qv.fQvectorFlagsPro->GetXaxis()->SetBinLabel(2, "gMaxHarmonic"); + qv.fQvectorFlagsPro->Fill(1.5, gMaxHarmonic); + qv.fQvectorFlagsPro->GetXaxis()->SetBinLabel(3, "gMaxCorrelator"); + qv.fQvectorFlagsPro->Fill(2.5, gMaxCorrelator); + qv.fQvectorList->Add(qv.fQvectorFlagsPro); + + // b) Book multiplicity distributions in A and B, for each eta separation: + if (es.fCalculateEtaSeparations) { + TString sEtaSep[2] = {"A", "B"}; // A <=> -eta , B <=> + eta + TString sEtaSep_long[2] = {TString::Format("%.2f < #eta <", pc.fdParticleCuts[eEta][eMin]), TString::Format("< #eta < %.2f", pc.fdParticleCuts[eEta][eMax])}; + // yes, here I define first the part of intervals as etaCutMin < eta < "subevent boundary", and "subevent" boundary < eta < etaCutMax + // Then below in the loop, I inject for "subevent boundary" the corresponding fEtaSeparationsValues (divided by 2, becaus it's symmetric round 0) + for (int ab = 0; ab < 2; ab++) { // ab = 0 <=> -eta , ab = 1 <=> + eta + for (int rs = 0; rs < 2; rs++) { // reco/sim + if (Skip(rs)) { + continue; + } + for (int ba = 0; ba < 2; ba++) { // before/after cuts + if (eBefore == ba) { + continue; // it make sense to fill these histos only for "eAfter", because Q-vectors are not filled for "eBefore" + } + for (int e = 0; e < gMaxNumberEtaSeparations; e++) { // eta separation + qv.fMabDist[ab][rs][ba][e] = new TH1F(Form("fMabDist[%s][%s][%s][%d]", sEtaSep[ab].Data(), gc.srs[rs].Data(), gc.sba[ba].Data(), e), + Form("%s, %s, %s, %s", "__RUN_NUMBER__", + 0 == ab ? Form("%s -%.2f", sEtaSep_long[ab].Data(), es.fEtaSeparationsValues[e] / 2.) : Form("%.2f %s", es.fEtaSeparationsValues[e] / 2., sEtaSep_long[ab].Data()), gc.srs_long[rs].Data(), gc.sba_long[ba].Data()), + static_cast(eh.fEventHistogramsBins[eMultiplicity][0]), eh.fEventHistogramsBins[eMultiplicity][1], eh.fEventHistogramsBins[eMultiplicity][2]); // TBI 20241207 I have hardwired in this constructor "0 == ab", this can backfire... + qv.fMabDist[ab][rs][ba][e]->SetLineColor(ec.fBeforeAfterColor[ba]); + qv.fMabDist[ab][rs][ba][e]->SetFillColor(ec.fBeforeAfterColor[ba] - 10); + qv.fMabDist[ab][rs][ba][e]->GetXaxis()->SetTitle("subevent multiplicity (sum of particle weights)"); + qv.fMabDist[ab][rs][ba][e]->SetMinimum(1.e-4); // so that I can switch to log scale, even if some bins are empty + // Remark: For empty histograms, when plotting interactively, because of this line, I will get + // E-TCanvas::Range: illegal world coordinates range .... + // But it's harmless, because in any case I do not care about the content of empty histogram... + qv.fMabDist[ab][rs][ba][e]->SetOption("hist"); // do not plot marker and error (see BanishmentLoopOverParticles why errors are not reliable) for each bin, only content + filled area. + qv.fQvectorList->Add(qv.fMabDist[ab][rs][ba][e]); + } + } + } + } + } // if (es.fCalculateEtaSeparations) { + + // c) ... + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void BookQvectorHistograms() + +//============================================================ + +void BookCorrelationsHistograms() +{ + // Book all correlations histograms. + + // a) Book the profile holding flags; + // b) Common local labels; + // c) Histograms; + // d) Few quick insanity checks on booking. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Book the profile holding flags: + mupa.fCorrelationsFlagsPro = new TProfile("fCorrelationsFlagsPro", + "flags for correlations", 1, 0., 1.); + mupa.fCorrelationsFlagsPro->SetStats(false); + mupa.fCorrelationsFlagsPro->SetLineColor(eColor); + mupa.fCorrelationsFlagsPro->SetFillColor(eFillColor); + mupa.fCorrelationsFlagsPro->GetXaxis()->SetLabelSize(0.05); + mupa.fCorrelationsFlagsPro->GetXaxis()->SetBinLabel(1, "fCalculateCorrelations"); + mupa.fCorrelationsFlagsPro->Fill(0.5, mupa.fCalculateCorrelations); + // ... + mupa.fCorrelationsList->Add(mupa.fCorrelationsFlagsPro); + + if (!mupa.fCalculateCorrelations) { + return; + } + + // b) Common local labels: + TString oVariable[4] = { + "#varphi_{1}-#varphi_{2}", + "#varphi_{1}+#varphi_{2}-#varphi_{3}-#varphi_{4}", + "#varphi_{1}+#varphi_{2}+#varphi_{3}-#varphi_{4}-#varphi_{5}-#varphi_{6}", + "#varphi_{1}+#varphi_{2}+#varphi_{3}+#varphi_{4}-#varphi_{5}-#varphi_{6}-" + "#varphi_{7}-#varphi_{8}"}; + + // c) Histograms: + for (int k = 0; k < 4; k++) // order [2p=0,4p=1,6p=2,8p=3] + { + for (int n = 0; n < gMaxHarmonic; n++) // harmonic + { + for (int v = 0; v < eAsFunctionOf_N; v++) { + + // decide what is booked, then later valid pointer to fCorrelationsPro[k][n][v] is used as a boolean, in the standard way: + if (AFO_INTEGRATED == v && !mupa.fCalculateCorrelationsAsFunctionOf[AFO_INTEGRATED]) { + continue; + } + if (AFO_MULTIPLICITY == v && !mupa.fCalculateCorrelationsAsFunctionOf[AFO_MULTIPLICITY]) { + continue; + } + if (AFO_CENTRALITY == v && !mupa.fCalculateCorrelationsAsFunctionOf[AFO_CENTRALITY]) { + continue; + } + if (AFO_PT == v && !mupa.fCalculateCorrelationsAsFunctionOf[AFO_PT]) { + continue; + } + if (AFO_ETA == v && !mupa.fCalculateCorrelationsAsFunctionOf[AFO_ETA]) { + continue; + } + if (AFO_OCCUPANCY == v && !mupa.fCalculateCorrelationsAsFunctionOf[AFO_OCCUPANCY]) { + continue; + } + if (AFO_INTERACTIONRATE == v && !mupa.fCalculateCorrelationsAsFunctionOf[AFO_INTERACTIONRATE]) { + continue; + } + if (AFO_CURRENTRUNDURATION == v && !mupa.fCalculateCorrelationsAsFunctionOf[AFO_CURRENTRUNDURATION]) { + continue; + } + if (AFO_VZ == v && !mupa.fCalculateCorrelationsAsFunctionOf[AFO_VZ]) { + continue; + } + + if (!res.fResultsPro[v]) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + mupa.fCorrelationsPro[k][n][v] = reinterpret_cast(res.fResultsPro[v]->Clone(Form("fCorrelationsPro[%d][%d][%s]", k, n, res.fResultsProRawName[v].Data()))); // yes + mupa.fCorrelationsPro[k][n][v]->SetStats(false); + mupa.fCorrelationsPro[k][n][v]->Sumw2(); + mupa.fCorrelationsPro[k][n][v]->GetXaxis()->SetTitle(FancyFormatting(res.fResultsProXaxisTitle[v].Data())); + mupa.fCorrelationsPro[k][n][v]->GetYaxis()->SetTitle(Form("#LT#LTcos[%s(%s)]#GT#GT", 1 == n + 1 ? "" : Form("%d", n + 1), oVariable[k].Data())); + mupa.fCorrelationsList->Add(mupa.fCorrelationsPro[k][n][v]); + } + } // for (int n = 0; n < gMaxHarmonic; n++) // harmonic + } // for (int k = 0; k < 4; k++) // order [2p=0,4p=1,6p=2,8p=3] + + // d) Few quick insanity checks on booking: + if (mupa.fCorrelationsPro[0][0][AFO_INTEGRATED] && !TString(mupa.fCorrelationsPro[0][0][AFO_INTEGRATED]->GetXaxis()->GetTitle()).EqualTo("integrated")) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); // ordering in enum eAsFunctionOf is not the same as in TString fResultsProXaxisTitle[eAsFunctionOf_N] + } + if (mupa.fCorrelationsPro[0][0][AFO_PT] && !TString(mupa.fCorrelationsPro[0][0][AFO_PT]->GetXaxis()->GetTitle()).EqualTo("p_{T}")) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); // ordering in enum eAsFunctionOf is not the same as in TString fResultsProXaxisTitle[eAsFunctionOf_N] + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // BookCorrelationsHistograms() + +//============================================================ + +void BookWeightsHistograms() +{ + // Book all objects for particle weights. + + // a) Book the profile holding flags; + // b) Histograms for integrated weights; + // c) Histograms for differential weights; + // d) Sparse histograms for differential phi weights. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Book the profile holding flags: + pw.fWeightsFlagsPro = new TProfile("fWeightsFlagsPro", "flags for particle weights", 13, 0., 13.); + pw.fWeightsFlagsPro->SetStats(false); + pw.fWeightsFlagsPro->SetLineColor(eColor); + pw.fWeightsFlagsPro->SetFillColor(eFillColor); + pw.fWeightsFlagsPro->GetXaxis()->SetLabelSize(0.035); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(1, "w_{#varphi}"); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(2, "w_{p_{t}}"); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(3, "w_{#eta}"); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(4, "(w_{#varphi})_{| p_{T}}"); // TBI 20241019 not sure if this is the final notation, keep in sync with void SetDiffWeightsHist(...) + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(5, "(w_{#varphi})_{| #eta}"); // TBI 20241019 not sure if this is the final notation, keep in sync with void SetDiffWeightsHist(...) + + // **) differential phi weights using sparse: + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(6, "(w_{#varphi})_{phi axis (sparse)}"); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(7, "(w_{#varphi})_{p_{T} axis (sparse)}"); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(8, "(w_{#varphi})_{#eta axis (sparse)}"); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(9, "(w_{#varphi})_{charge axis (sparse)}"); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(10, "(w_{#varphi})_{centrality axis (sparse)}"); + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(11, "(w_{#varphi})_{VertexZ axis (sparse)}"); + + // **) differential pt weights using sparse: + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(12, "(w_{p_{T}})_{pt axis (sparse)}"); + + // **) differential eta weights using sparse: + pw.fWeightsFlagsPro->GetXaxis()->SetBinLabel(13, "(w_{#eta})_{eta axis (sparse)}"); + + for (int w = 0; w < eWeights_N; w++) // use weights [phi,pt,eta] + { + if (pw.fUseWeights[w]) { + pw.fWeightsFlagsPro->Fill(w + 0.5, 1.); + } + } + + // **) use differential weights [phipt,phieta,...] TBI 20250514 obsolete + if (pw.fUseDiffWeights[wPHIPT]) { + pw.fWeightsFlagsPro->Fill(3.5, 1.); + } + if (pw.fUseDiffWeights[wPHIETA]) { + pw.fWeightsFlagsPro->Fill(4.5, 1.); + } + + // **) differential phi weights using sparse: + if (pw.fUseDiffPhiWeights[wPhiPhiAxis]) { + pw.fWeightsFlagsPro->Fill(5.5, 1.); + } + if (pw.fUseDiffPhiWeights[wPhiPtAxis]) { + pw.fWeightsFlagsPro->Fill(6.5, 1.); + } + if (pw.fUseDiffPhiWeights[wPhiEtaAxis]) { + pw.fWeightsFlagsPro->Fill(7.5, 1.); + } + if (pw.fUseDiffPhiWeights[wPhiChargeAxis]) { + pw.fWeightsFlagsPro->Fill(8.5, 1.); + } + if (pw.fUseDiffPhiWeights[wPhiCentralityAxis]) { + pw.fWeightsFlagsPro->Fill(9.5, 1.); + } + if (pw.fUseDiffPhiWeights[wPhiVertexZAxis]) { + pw.fWeightsFlagsPro->Fill(10.5, 1.); + } + + // **) differential pt weights using sparse: + if (pw.fUseDiffPtWeights[wPtPtAxis]) { + pw.fWeightsFlagsPro->Fill(11.5, 1.); + } + + // **) differential eta weights using sparse: + if (pw.fUseDiffEtaWeights[wEtaEtaAxis]) { + pw.fWeightsFlagsPro->Fill(12.5, 1.); + } + + pw.fWeightsList->Add(pw.fWeightsFlagsPro); + + // b) Histograms for integrated weights: + // As of 20240216, I have abandoned the idea to generate integrated weights internally, weights + // are always fetched and cloned from external files, in any case (local, AliEn, CCDB). + // Therefore, add histos with weights to this list only after they are cloned from external files. + + // c) Histograms for differential weights: + // Same comment applies as for b) => add histograms to the list, only after they are cloned from external files. + + // d) Sparse histograms for differential phi weights: + // Same comment applies as for b) => add sparse histograms to the list, only after they are cloned from external files. + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void BookWeightsHistograms() + +//============================================================ + +void BookCentralityWeightsHistograms() +{ + // Book all objects for centrality weights. + + // a) Book the profile holding flags; + // b) Histograms for centrality weights. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Book the profile holding flags: + cw.fCentralityWeightsFlagsPro = + new TProfile("fCentralityWeightsFlagsPro", "flags for centrality weights", 1, 0., 1.); + cw.fCentralityWeightsFlagsPro->SetStats(false); + cw.fCentralityWeightsFlagsPro->SetLineColor(eColor); + cw.fCentralityWeightsFlagsPro->SetFillColor(eFillColor); + cw.fCentralityWeightsFlagsPro->GetXaxis()->SetLabelSize(0.05); + cw.fCentralityWeightsFlagsPro->GetXaxis()->SetBinLabel(1, TString::Format("Use centrality weights for estimator %s", ec.fsEventCuts[eCentralityEstimator].Data())); + if (cw.fUseCentralityWeights) { + cw.fCentralityWeightsFlagsPro->Fill(0.5, 1.); // TBI 20241118 shall I automate this? + } + cw.fCentralityWeightsList->Add(cw.fCentralityWeightsFlagsPro); + + // b) Histograms for centrality weights: + // As of 20240216, I have abandoned the idea to generate centrality weights internally, centrality weights + // are always fetched and cloned from external files, in any case (local, AliEn, CCDB). + // Therefore, add histos with centrality weights to this list only after they are cloned from external files. + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void BookCentralityWeightsHistograms() + +//============================================================ + +void BookNestedLoopsHistograms() +{ + // Book all nested loops histograms. + + // a) Book the profile holding flags; + // b) Common local labels (keep 'em in sync with BookCorrelationsHistograms()); + // c) Book what needs to be booked; + // d) Few quick insanity checks on booking. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Book the profile holding flags: + nl.fNestedLoopsFlagsPro = + new TProfile("fNestedLoopsFlagsPro", "flags for nested loops", 4, 0., 4.); + nl.fNestedLoopsFlagsPro->SetStats(false); + nl.fNestedLoopsFlagsPro->SetLineColor(eColor); + nl.fNestedLoopsFlagsPro->SetFillColor(eFillColor); + nl.fNestedLoopsFlagsPro->GetXaxis()->SetLabelSize(0.03); + nl.fNestedLoopsFlagsPro->GetXaxis()->SetBinLabel(1, "fCalculateNestedLoops"); + nl.fNestedLoopsFlagsPro->Fill(0.5, nl.fCalculateNestedLoops); + nl.fNestedLoopsFlagsPro->GetXaxis()->SetBinLabel(2, "fCalculateCustomNestedLoops"); + nl.fNestedLoopsFlagsPro->Fill(1.5, nl.fCalculateCustomNestedLoops); + nl.fNestedLoopsFlagsPro->GetXaxis()->SetBinLabel(3, "fCalculateKineCustomNestedLoops"); + nl.fNestedLoopsFlagsPro->Fill(2.5, nl.fCalculateKineCustomNestedLoops); + nl.fNestedLoopsFlagsPro->GetXaxis()->SetBinLabel(4, "fMaxNestedLoop"); + nl.fNestedLoopsFlagsPro->Fill(3.5, nl.fMaxNestedLoop); + nl.fNestedLoopsList->Add(nl.fNestedLoopsFlagsPro); + + if (!(nl.fCalculateNestedLoops || nl.fCalculateCustomNestedLoops || nl.fCalculateKineCustomNestedLoops)) { + // TBI 20240326 I have to keep all 3 flags above, because for instance TArrayD* ftaNestedLoops[2] is used as a storage both for nl.fCalculateNestedLoops and nl.fCalculateCustomNestedLoops + return; + } + + // *) Book containers for integrated nested loops: + if (nl.fCalculateNestedLoops || nl.fCalculateCustomNestedLoops) { + const int iMaxSize = 2e4; + nl.ftaNestedLoops[0] = new TArrayD(iMaxSize); // ebe container for azimuthal angles + nl.ftaNestedLoops[1] = new TArrayD(iMaxSize); // ebe container for particle weights (product of all) + } + + // *) Book containers for differential nested loops: + if (nl.fCalculateKineCustomNestedLoops) { + const int iMaxSize = 2e4; + for (int b = 0; b < res.fResultsPro[AFO_PT]->GetNbinsX(); b++) { + nl.ftaNestedLoopsKine[PTq][b][0] = new TArrayD(iMaxSize); + nl.ftaNestedLoopsKine[PTq][b][1] = new TArrayD(iMaxSize); + } + for (int b = 0; b < res.fResultsPro[AFO_ETA]->GetNbinsX(); b++) { + nl.ftaNestedLoopsKine[ETAq][b][0] = new TArrayD(iMaxSize); + nl.ftaNestedLoopsKine[ETAq][b][1] = new TArrayD(iMaxSize); + } + } + + // b) Common local labels (keep 'em in sync with BookCorrelationsHistograms()) + TString oVariable[4] = { + "#varphi_{1}-#varphi_{2}", + "#varphi_{1}+#varphi_{2}-#varphi_{3}-#varphi_{4}", + "#varphi_{1}+#varphi_{2}+#varphi_{3}-#varphi_{4}-#varphi_{5}-#varphi_{6}", + "#varphi_{1}+#varphi_{2}+#varphi_{3}+#varphi_{4}-#varphi_{5}-#varphi_{6}-" + "#varphi_{7}-#varphi_{8}"}; + + // c) Book what needs to be booked: + if (!(nl.fCalculateNestedLoops)) { // TBI 20240404 for the time being, I can keep it here, but eventualy it will have to go elsewhere + return; + } + for (int k = 0; k < 4; k++) // order [2p=0,4p=1,6p=2,8p=3] + { + // TBI 20240405 I could break here, with respect to what nl.fMaxNestedLoop was set to + + for (int n = 0; n < gMaxHarmonic; n++) // harmonic + { + for (int v = 0; v < eAsFunctionOf_N; v++) { + + if (!res.fResultsPro[v]) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + nl.fNestedLoopsPro[k][n][v] = reinterpret_cast(res.fResultsPro[v]->Clone(Form("fNestedLoopsPro[%d][%d][%d]", k, n, v))); // yes + nl.fNestedLoopsPro[k][n][v]->SetTitle(Form("#LT#LTcos[%s(%s)]#GT#GT", 1 == n + 1 ? "" : Form("%d", n + 1), oVariable[k].Data())); + nl.fNestedLoopsPro[k][n][v]->SetStats(false); + nl.fNestedLoopsPro[k][n][v]->Sumw2(); + nl.fNestedLoopsPro[k][n][v]->GetXaxis()->SetTitle(res.fResultsProXaxisTitle[v].Data()); + + /* + if(fUseFixedNumberOfRandomlySelectedTracks && 1==v) // just a warning + for the meaning of multiplicity in this special case + { + nl.fNestedLoopsPro[k][n][1]->GetXaxis()->SetTitle("WARNING: for each + multiplicity, fFixedNumberOfRandomlySelectedTracks is selected randomly + in Q-vector"); + } + */ + + nl.fNestedLoopsList->Add(nl.fNestedLoopsPro[k][n][v]); + } // for(int v=0;v<5;v++) // variable [0=integrated,1=vs. + // multiplicity,2=vs. centrality] + } // for (int n = 0; n < gMaxHarmonic; n++) // harmonic + } // for (int k = 0; k < 4; k++) // order [2p=0,4p=1,6p=2,8p=3] + + // d) Few quick insanity checks on booking: + if (nl.fNestedLoopsPro[0][0][AFO_INTEGRATED] && !TString(nl.fNestedLoopsPro[0][0][AFO_INTEGRATED]->GetXaxis()->GetTitle()).EqualTo("integrated")) { + LOGF(info, "\033[1;33mnl.fNestedLoopsPro[0][0][AFO_INTEGRATED]->GetXaxis()->GetTitle() = %s \033[0m", nl.fNestedLoopsPro[0][0][AFO_INTEGRATED]->GetXaxis()->GetTitle()); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); // ordering in enum eAsFunctionOf is not the same as in TString fResultsProXaxisTitle[eAsFunctionOf_N] + } + if (nl.fNestedLoopsPro[0][0][AFO_PT] && !TString(nl.fNestedLoopsPro[0][0][AFO_PT]->GetXaxis()->GetTitle()).EqualTo("pt")) { // I do not need here fancy formatting + LOGF(info, "\033[1;33mnl.fNestedLoopsPro[0][0][AFO_PT]->GetXaxis()->GetTitle() = %s \033[0m", nl.fNestedLoopsPro[0][0][AFO_PT]->GetXaxis()->GetTitle()); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); // ordering in enum eAsFunctionOf is not the same as in TString fResultsProXaxisTitle[eAsFunctionOf_N] + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void BookNestedLoopsHistograms() + +//============================================================ + +void BookNUAHistograms() +{ + // Book all objects for Toy NUA. + + // a) Book the profile holding flags; + // b) Common local labels; + // c) Histograms. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Book the profile holding flags: + nua.fNUAFlagsPro = new TProfile("fNUAFlagsPro", "flags for Toy NUA", 6, 0.5, 6.5); + nua.fNUAFlagsPro->SetStats(false); + nua.fNUAFlagsPro->SetLineColor(eColor); + nua.fNUAFlagsPro->SetFillColor(eFillColor); + nua.fNUAFlagsPro->GetXaxis()->SetLabelSize(0.03); + // TBI 20240429 the binning below is a bit fragile, but ok... + nua.fNUAFlagsPro->GetXaxis()->SetBinLabel(static_cast(1 + ePhiNUAPDF), "fApplyNUAPDF[phi]"); + nua.fNUAFlagsPro->GetXaxis()->SetBinLabel(static_cast(1 + ePtNUAPDF), "fApplyNUAPDF[pt]"); + nua.fNUAFlagsPro->GetXaxis()->SetBinLabel(static_cast(1 + eEtaNUAPDF), "fApplyNUAPDF[eta]"); + if (nua.fApplyNUAPDF[ePhiNUAPDF]) { + nua.fNUAFlagsPro->Fill(static_cast(1 + ePhiNUAPDF), 1.); + } + if (nua.fApplyNUAPDF[ePtNUAPDF]) { + nua.fNUAFlagsPro->Fill(static_cast(1 + ePtNUAPDF), 1.); + } + if (nua.fApplyNUAPDF[eEtaNUAPDF]) { + nua.fNUAFlagsPro->Fill(static_cast(1 + eEtaNUAPDF), 1.); + } + nua.fNUAFlagsPro->GetXaxis()->SetBinLabel(static_cast(4 + ePhiNUAPDF), "fUseDefaultNUAPDF[phi]"); + nua.fNUAFlagsPro->GetXaxis()->SetBinLabel(static_cast(4 + ePtNUAPDF), "fUseDefaultNUAPDF[pt]"); + nua.fNUAFlagsPro->GetXaxis()->SetBinLabel(static_cast(4 + eEtaNUAPDF), "fUseDefaultNUAPDF[eta]"); + if (nua.fUseDefaultNUAPDF[ePhiNUAPDF]) { + nua.fNUAFlagsPro->Fill(static_cast(4 + ePhiNUAPDF), 1.); + } + if (nua.fUseDefaultNUAPDF[ePtNUAPDF]) { + nua.fNUAFlagsPro->Fill(static_cast(4 + ePtNUAPDF), 1.); + } + if (nua.fUseDefaultNUAPDF[eEtaNUAPDF]) { + nua.fNUAFlagsPro->Fill(static_cast(4 + eEtaNUAPDF), 1.); + } + nua.fNUAList->Add(nua.fNUAFlagsPro); + + if (!(nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF])) { + return; + } + + // b) Common local labels: + TString sVariable[eNUAPDF_N] = {"#varphi", "p_{t}", "#eta"}; // has to be in sync with the ordering of enum eNUAPDF + + // c) Histograms: + for (int pdf = 0; pdf < eNUAPDF_N; pdf++) // use pdfs for NUA in (phi, pt, eta, ...) + { + if (!nua.fCustomNUAPDF[pdf]) // yes, because these histos are cloned from the external ones, see void SetNUAPDF(TH1D* const hist, const char* variable); + { + // otherwise, book here TF1 objects with default pdfs for NUA: + + // *) default NUA for azimuthal angle pdf: + if (sVariable[pdf].EqualTo("#varphi")) { + if (!nua.fApplyNUAPDF[ePhiNUAPDF]) { + continue; + } + // Define default detector acceptance in azimuthal angle: Two sectors, with different probabilities. + double dFirstSector[2] = {-(3. / 4.) * o2::constants::math::PI, -(1. / 4.) * o2::constants::math::PI}; // first sector is defined as [-3Pi/4,Pi/4] + double dSecondSector[2] = {(1. / 3.) * o2::constants::math::PI, (2. / 3.) * o2::constants::math::PI}; // second sector is defined as [Pi/3,2Pi/3] + double dProbability[2] = {0.3, 0.5}; // probabilities + nua.fDefaultNUAPDF[ePhiNUAPDF] = new TF1(TString::Format("fDefaultNUAPDF[%d]", ePhiNUAPDF), "1.-(x>=[0])*(1.-[4]) + (x>=[1])*(1.-[4]) - (x>=[2])*(1.-[5]) + (x>=[3])*(1.-[5]) ", + ph.fParticleHistogramsBins[ePhi][1], ph.fParticleHistogramsBins[ePhi][2]); + nua.fDefaultNUAPDF[ePhiNUAPDF]->SetParameter(0, dFirstSector[0]); + nua.fDefaultNUAPDF[ePhiNUAPDF]->SetParameter(1, dFirstSector[1]); + nua.fDefaultNUAPDF[ePhiNUAPDF]->SetParameter(2, dSecondSector[0]); + nua.fDefaultNUAPDF[ePhiNUAPDF]->SetParameter(3, dSecondSector[1]); + nua.fDefaultNUAPDF[ePhiNUAPDF]->SetParameter(4, dProbability[0]); + nua.fDefaultNUAPDF[ePhiNUAPDF]->SetParameter(5, dProbability[1]); + nua.fNUAList->Add(nua.fDefaultNUAPDF[ePhiNUAPDF]); + + } else if (sVariable[pdf].EqualTo("p_{t}")) { + + // *) default NUA for transverse momentum pdf: + if (!nua.fApplyNUAPDF[ePtNUAPDF]) { + continue; + } + // Define default detector acceptance in transverse momentum: One sectors, with probability < 1. + double dSector[2] = {0.4, 0.8}; // sector is defined as 0.8 < pT < 1.2 + double dProbability = 0.3; // probability, so after being set this way, only 30% of particles in that sector are reconstructed + nua.fDefaultNUAPDF[ePtNUAPDF] = new TF1(TString::Format("fDefaultNUAPDF[%d]", ePtNUAPDF), "1.-(x>=[0])*(1.-[2]) + (x>=[1])*(1.-[2])", + ph.fParticleHistogramsBins[ePt][1], ph.fParticleHistogramsBins[ePt][2]); + nua.fDefaultNUAPDF[ePtNUAPDF]->SetParameter(0, dSector[0]); + nua.fDefaultNUAPDF[ePtNUAPDF]->SetParameter(1, dSector[1]); + nua.fDefaultNUAPDF[ePtNUAPDF]->SetParameter(2, dProbability); + nua.fNUAList->Add(nua.fDefaultNUAPDF[ePtNUAPDF]); + + } else if (sVariable[pdf].EqualTo("#eta")) { + + // *) default NUA for pseudorapidity pdf: + if (!nua.fApplyNUAPDF[eEtaNUAPDF]) { + continue; + } + // Define default detector acceptance in pseudorapidity: One sectors, with probability < 1. + double dSector[2] = {2.0, 2.5}; // sector is defined as 0.5 < eta < 1.0 + double dProbability = 0.5; // probability, so after being set this way, only 50% of particles in that sector are reconstructed + nua.fDefaultNUAPDF[eEtaNUAPDF] = new TF1(TString::Format("fDefaultNUAPDF[%d]", eEtaNUAPDF), "1.-(x>=[0])*(1.-[2]) + (x>=[1])*(1.-[2])", + ph.fParticleHistogramsBins[eEta][1], ph.fParticleHistogramsBins[eEta][2]); + nua.fDefaultNUAPDF[eEtaNUAPDF]->SetParameter(0, dSector[0]); + nua.fDefaultNUAPDF[eEtaNUAPDF]->SetParameter(1, dSector[1]); + nua.fDefaultNUAPDF[eEtaNUAPDF]->SetParameter(2, dProbability); + nua.fNUAList->Add(nua.fDefaultNUAPDF[eEtaNUAPDF]); + } else { + LOGF(fatal, "\033[1;31m%s at line %d : pdf = %s is not supported (yet)\n \033[0m", __FUNCTION__, __LINE__, sVariable[pdf].Data()); + } + + } else { // if(!nua.fCustomNUAPDF[pdf]) + // generic cosmetics for custom user-supplied pdfs via histograms: + nua.fCustomNUAPDF[pdf]->SetTitle(TString::Format("Custom user-provided NUA for %s", sVariable[pdf].Data())); + nua.fCustomNUAPDF[pdf]->SetStats(false); + nua.fCustomNUAPDF[pdf]->GetXaxis()->SetTitle(sVariable[pdf].Data()); + nua.fCustomNUAPDF[pdf]->SetFillColor(eFillColor); + nua.fCustomNUAPDF[pdf]->SetLineColor(eColor); + nua.fNUAList->Add(nua.fCustomNUAPDF[pdf]); + } // if(!nua.fCustomNUAPDF[pdf]) + + // Get the max values of pdfs, so that later in Accept(...) there is no loss of efficiency, when would need to calculate the same thing for each particle: + if (!nua.fUseDefaultNUAPDF[pdf] && nua.fCustomNUAPDF[pdf]) { // pdf is a loop variable + // custom, user-provided pdf via TH1D object: + nua.fMaxValuePDF[pdf] = nua.fCustomNUAPDF[pdf]->GetMaximum(); + } else if (nua.fUseDefaultNUAPDF[pdf] && nua.fDefaultNUAPDF[pdf]) { + // default pdf implemented as TF1 object: + nua.fMaxValuePDF[pdf] = nua.fDefaultNUAPDF[pdf]->GetMaximum(ph.fParticleHistogramsBins[pdf][1], ph.fParticleHistogramsBins[pdf][2]); + } + + } // for(int pdf=0;pdfSetStats(false); + iv.fInternalValidationFlagsPro->SetLineColor(eColor); + iv.fInternalValidationFlagsPro->SetFillColor(eFillColor); + iv.fInternalValidationFlagsPro->GetXaxis()->SetLabelSize(0.04); + iv.fInternalValidationList->Add(iv.fInternalValidationFlagsPro); + + iv.fInternalValidationFlagsPro->GetXaxis()->SetBinLabel(1, "fUseInternalValidation"); + iv.fInternalValidationFlagsPro->Fill(0.5, iv.fUseInternalValidation); + iv.fInternalValidationFlagsPro->GetXaxis()->SetBinLabel(2, "fnEventsInternalValidation"); + iv.fInternalValidationFlagsPro->Fill(1.5, iv.fnEventsInternalValidation); + iv.fInternalValidationFlagsPro->GetXaxis()->SetBinLabel(3, "fRescaleWithTheoreticalInput"); + iv.fInternalValidationFlagsPro->Fill(2.5, iv.fRescaleWithTheoreticalInput); + iv.fInternalValidationFlagsPro->GetXaxis()->SetBinLabel(4, TString::Format("option = %s", iv.fHarmonicsOptionInternalValidation->Data())); + iv.fInternalValidationFlagsPro->Fill(3.5, 1); // redundant, because here I only care about bin label, but preserves symmetry in this code snippet... + + // *) Book object beyond this line only if internal validation was requested: + if (!iv.fUseInternalValidation) { + return; + } + + // b) Book and fill container vn amplitudes: + iv.fInternalValidationVnPsin[eVn] = new TArrayD(gMaxHarmonic); + auto lInternalValidationAmplitudes = (std::vector)cf_iv.cfInternalValidationAmplitudes; // this is now the local version of that array from configurable + if (lInternalValidationAmplitudes.size() < 1) { + LOGF(fatal, "\033[1;31m%s at line %d : set at least one vn amplitude in array cfInternalValidationAmplitudes\n \033[0m", __FUNCTION__, __LINE__); + } + if (lInternalValidationAmplitudes.size() > gMaxHarmonic) { + LOGF(fatal, "\033[1;31m%s at line %d : lInternalValidationAmplitudes.size() > gMaxHarmonic \n \033[0m", __FUNCTION__, __LINE__); + } + for (int i = 0; i < static_cast(lInternalValidationAmplitudes.size()); i++) { + iv.fInternalValidationVnPsin[eVn]->SetAt(lInternalValidationAmplitudes[i], i); + } + + // c) Book and fill container for Psin planes: + iv.fInternalValidationVnPsin[ePsin] = new TArrayD(gMaxHarmonic); + auto lInternalValidationPlanes = (std::vector)cf_iv.cfInternalValidationPlanes; + if (lInternalValidationPlanes.size() < 1) { + LOGF(fatal, "\033[1;31m%s at line : %d set at least one Psi plane in array cfInternalValidationPlanes\n \033[0m", __FUNCTION__, __LINE__); + } + if (lInternalValidationPlanes.size() > gMaxHarmonic) { + LOGF(fatal, "\033[1;31m%s at line %d : lInternalValidationPlanes.size() > gMaxHarmonic \n \033[0m", __FUNCTION__, __LINE__); + } + if (lInternalValidationAmplitudes.size() != lInternalValidationPlanes.size()) { + LOGF(fatal, "\033[1;31m%s at line %d : lInternalValidationAmplitudes.size() != lInternalValidationPlanes.size() \n \033[0m", __FUNCTION__, __LINE__); + } + for (int i = 0; i < static_cast(lInternalValidationPlanes.size()); i++) { + iv.fInternalValidationVnPsin[ePsin]->SetAt(lInternalValidationPlanes[i], i); + } + + // d) Handle multiplicity for internal validation: + auto lMultRangeInternalValidation = (std::vector)cf_iv.cfMultRangeInternalValidation; + iv.fMultRangeInternalValidation[eMin] = lMultRangeInternalValidation[eMin]; + iv.fMultRangeInternalValidation[eMax] = lMultRangeInternalValidation[eMax]; + if (iv.fMultRangeInternalValidation[eMin] >= iv.fMultRangeInternalValidation[eMax]) { + LOGF(fatal, "\033[1;31m%s at line %d : iv.fMultRangeInternalValidation[eMin] >= iv.fMultRangeInternalValidation[eMax] \n \033[0m", __FUNCTION__, __LINE__); + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // BookInternalValidationHistograms() + +//============================================================ + +TComplex TheoreticalValue(TArrayI* harmonics, TArrayD* amplitudes, TArrayD* planes) +{ + // For the specified harmonics, from available amplitudes and symmetry planes, return the theoretical value of correlator. + // See Eq. (2) in MVC, originally derived in R. S. Bhalerao, M. Luzum, and J.-Y. Ollitrault, Phys. Rev. C 84, 034910 (2011), arXiv:1104.4740 [nucl-th]. + + // a) Insanity checks; + // b) Main calculus; + // c) Return value. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Insanity checks: + if (!harmonics) { + LOGF(fatal, "\033[1;31m%s at line %d : !harmonics \n \033[0m", __FUNCTION__, __LINE__); + } + if (!amplitudes) { + LOGF(fatal, "\033[1;31m%s at line %d : !amplitudes \n \033[0m", __FUNCTION__, __LINE__); + } + if (!planes) { + LOGF(fatal, "\033[1;31m%s at line %d : !planes \n \033[0m", __FUNCTION__, __LINE__); + } + if (amplitudes->GetSize() != planes->GetSize()) { + LOGF(fatal, "\033[1;31m%s at line %d : amplitudes->GetSize() != planes->GetSize() \n \033[0m", __FUNCTION__, __LINE__); + } + + // b) Main calculus: + TComplex value = TComplex(1., 0., true); // yes, polar representation + for (int h = 0; h < harmonics->GetSize(); h++) { + // Using polar form of TComplex (double re, double im=0, bool polar=false): + value *= TComplex(amplitudes->GetAt(TMath::Abs(harmonics->GetAt(h)) - 1), 1. * harmonics->GetAt(h) * planes->GetAt(TMath::Abs(harmonics->GetAt(h)) - 1), true); + } // for(int h=0;hGetSize();h++) + + // c) Return value: + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + return value; + +} // TComplex TheoreticalValue(TArrayI *harmonics, TArrayD *amplitudes, TArrayD *planes) + +//============================================================ + +void InternalValidation() +{ + // Internal validation against theoretical values in on-the-fly study for all implemented correlators. + + // Last update: 20250121 + + // To do: + // 20250121 At the moment, I do not support here differential phi weights. If I decide to add that feature, basically I need to generalize Accept() for 2D case, + // where e.g. phi(pt) weights will be given with some toy 2D pdf. + + // *) Set and propagate some fake run number; + // *) Fetch the weights for this particular run number. Do it only once; + // a) Fourier like p.d.f. for azimuthal angles and flow amplitudes; + // b) Loop over on-the-fly events. + // b0) Reset ebye quantities; + // b1) Determine multiplicity, centrality, reaction plane and configure p.d.f. for azimuthal angles if harmonics are not constant e-by-e; + // b2) Fill event histograms before cuts; + // b3) Loop over particles; + // b4) Fill event histograms after cuts; + // b5) Calculate everything for selected events and particles; + // c) Delete persistent objects. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // *) Set and propagate some fake run number: + tc.fRunNumber = "123456"; + PropagateRunNumber(); + + // *) Fetch the weights for this particular run number. Do it only once. + // TBI 20231012 If eventualy I can access programatically run number in init(...) at run time, this shall go there. + if (!pw.fParticleWeightsAreFetched) { + if (pw.fUseWeights[wPHI] || pw.fUseWeights[wPT] || pw.fUseWeights[wETA] || pw.fUseDiffWeights[wPHIPT] || pw.fUseDiffWeights[wPHIETA]) { + GetParticleWeights(); + pw.fParticleWeightsAreFetched = true; + } + // differential phi weights: + if (pw.fUseDiffPhiWeights[wPhiPhiAxis]) { // Yes, I check only the first flag. This way, I can switch off all differential phi weights by setting 0-wPhi in config. + // On the other hand, it doesn't make sense to calculate differential phi weights without having phi axis. + // At any point I shall be able to fall back to integrated phi weights, that corresponds to the case wheh "1-wPhi" and all others are "0-w..." + GetParticleWeights(); + pw.fParticleWeightsAreFetched = true; + } + } // if (!pw.fParticleWeightsAreFetched) { + + // a) Fourier like p.d.f. for azimuthal angles and flow amplitudes: + TF1* fPhiPDF = NULL; + TF3* fvnPDF = NULL; + + if (iv.fHarmonicsOptionInternalValidation->EqualTo("constant")) { + // For this option, vn's and psin's are constant for all simulated events, therefore I can configure fPhiPDF outside of loop over events. + // Remark: The last parameter [18] is a random reaction plane, keep in sync with fPhiPDF->SetParameter(18,fReactionPlane); below + // Keep also in sync with const int gMaxHarmonic = 9; in *GlobalConstants.h + fPhiPDF = new TF1("fPhiPDF", "1 + 2.*[0]*TMath::Cos(x-[1]-[18]) + 2.*[2]*TMath::Cos(2.*(x-[3]-[18])) + 2.*[4]*TMath::Cos(3.*(x-[5]-[18])) + 2.*[6]*TMath::Cos(4.*(x-[7]-[18])) + 2.*[8]*TMath::Cos(5.*(x-[9]-[18])) + 2.*[10]*TMath::Cos(6.*(x-[11]-[18])) + 2.*[12]*TMath::Cos(7.*(x-[13]-[18])) + 2.*[14]*TMath::Cos(8.*(x-[15]-[18])) + 2.*[16]*TMath::Cos(9.*(x-[17]-[18]))", 0., o2::constants::math::TwoPI); + for (int h = 0; h < gMaxHarmonic; h++) { + fPhiPDF->SetParName(2 * h, TString::Format("v_{%d}", h + 1)); // set name v_n + fPhiPDF->SetParName(2 * h + 1, TString::Format("Psi_{%d}", h + 1)); // set name psi_n + // initialize v_n: + if (iv.fInternalValidationVnPsin[eVn] && h + 1 <= iv.fInternalValidationVnPsin[eVn]->GetSize()) { + fPhiPDF->SetParameter(2 * h, iv.fInternalValidationVnPsin[eVn]->GetAt(h)); + } else { + fPhiPDF->SetParameter(2 * h, 0.); + } + // initialize psi_n: + if (iv.fInternalValidationVnPsin[ePsin] && h + 1 <= iv.fInternalValidationVnPsin[ePsin]->GetSize()) { + fPhiPDF->SetParameter(2 * h + 1, iv.fInternalValidationVnPsin[ePsin]->GetAt(h)); + } else { + fPhiPDF->SetParameter(2 * h + 1, 0.); + } + } // for(int h=0;h This is initial configuration for p.d.f. used in internal validation:"); + for (int h = 0; h < 2 * gMaxHarmonic; h++) { + LOGF(info, Form("%d %s = %f", h, fPhiPDF->GetParName(h), fPhiPDF->GetParameter(h))); + } + LOGF(info, "Remark: Parameter [18] at the moment is reaction plane.\n"); + } // if (tc.fVerbose) { + + } else if (iv.fHarmonicsOptionInternalValidation->EqualTo("correlated")) { // if(iv.fHarmonicsOptionInternalValidation->EqualTo("constant")) + // For this option, three selected vn's (v1,v2,v3) are correlated, and all psin's are set to zero, for simplicity. + // Remark: The last parameter [3] is a random reaction plane, keep in sync with fPhiPDF->SetParameter(3,fReactionPlane); below + // Keep also in sync with const int gMaxHarmonic = 9; in *GlobalConstants.h + + // Azimuthal angles are sampled from this pdf: + fPhiPDF = new TF1("fPhiPDF", "1 + 2.*[0]*TMath::Cos(x-[3]) + 2.*[1]*TMath::Cos(2.*(x-[3])) + 2.*[2]*TMath::Cos(3.*(x-[3]))", 0., o2::constants::math::TwoPI); + // With this parameterization, I have: + // [0] => v1 + // [1] => v2 + // [2] => v3 + // [3] => RP + fPhiPDF->SetParName(0, "v_{1}"); + fPhiPDF->SetParName(1, "v_{2}"); + fPhiPDF->SetParName(2, "v_{3}"); + fPhiPDF->SetParName(3, "RP"); + + // vn amplitudes are sampled e-b-e from this pdf: + fvnPDF = new TF3("fvnPDF", "x + 2.*y - 3.*z", 0.07, 0.08, 0.06, 0.07, 0.05, 0.06); // v1 \in [0.07,0.08], v2 \in [0.06,0.07], v3 \in [0.05,0.06] + // check for example message 'W-TF3::GetRandom3: function:fvnPDF has 27000 negative values: abs assumed' in the log file + // All the amplitudes v1, v2 and v3, and RP are determined e-b-e, and then set in fPhiPDF below + + } else if (iv.fHarmonicsOptionInternalValidation->EqualTo("persistent")) { // if(iv.fHarmonicsOptionInternalValidation->EqualTo("persistent")) + // For this option, three selected vn's (v1,v2,v3) are correlated in the same way as in "correlated" case, but in addition, the persistent + // non-vanishing correlation among SPCs Psi1, Psi2 and Psi3 is introduced, in the same way as in arXiv:1901.06968, Sec. II D. + + // Remark: In this example, there is no Reaction Plane, instead Psi1 and Psi2 are sampled uniformly, and the equation for Psi3 is hardwired, + // to introduce strong and persistent SPC correlation, see arXiv:1901.06968, Sec. II D. + // Keep also in sync with const int gMaxHarmonic = 9; in *GlobalConstants.h + + // Azimuthal angles are sampled from this pdf: + fPhiPDF = new TF1("fPhiPDF", "1 + 2.*[0]*TMath::Cos(x-[3]) + 2.*[1]*TMath::Cos(2.*(x-[4])) + 2.*[2]*TMath::Cos(3.*(x-[5]))", 0., o2::constants::math::TwoPI); + // With this parameterization, I have: + // [0] => v1 + // [1] => v2 + // [2] => v3 + // [3] => Psi1 + // [4] => Psi2 + // [5] => Psi3 + fPhiPDF->SetParName(0, "v_{1}"); + fPhiPDF->SetParName(1, "v_{2}"); + fPhiPDF->SetParName(2, "v_{3}"); + fPhiPDF->SetParName(3, "Psi_{1}"); + fPhiPDF->SetParName(4, "Psi_{2}"); + fPhiPDF->SetParName(5, "Psi_{3}"); + + // vn amplitudes are sampled e-b-e from this pdf (yes, for simplicity, I keep it the same as in "correlated" case): + fvnPDF = new TF3("fvnPDF", "x + 2.*y - 3.*z", 0.07, 0.08, 0.06, 0.07, 0.05, 0.06); // v1 \in [0.07,0.08], v2 \in [0.06,0.07], v3 \in [0.05,0.06] + // check for example message 'W-TF3::GetRandom3: function:fvnPDF has 27000 negative values: abs assumed' in the log file + // All the amplitudes v1, v2 and v3, and symmetry planes Psi_{1}, Psi_{2} and Psi_{3} are determined e-b-e, and then set in fPhiPDF below + } // else if(fHarmonicsOptionInternalValidation->EqualTo("persistent")) + + // b) Loop over on-the-fly events: + double v1 = 0., v2 = 0., v3 = 0.; + for (int e = 0; e < static_cast(iv.fnEventsInternalValidation); e++) { + + // b0) Reset ebye quantities: + ResetEventByEventQuantities(); + + // b1) Determine multiplicity, centrality, reaction plane and configure p.d.f. for azimuthal angles if harmonics are not constant e-by-e: + int nMult = static_cast(gRandom->Uniform(iv.fMultRangeInternalValidation[eMin], iv.fMultRangeInternalValidation[eMax])); + + double fReactionPlane = gRandom->Uniform(0., o2::constants::math::TwoPI); // no cast is needed, since Uniform(...) returns double + if (iv.fHarmonicsOptionInternalValidation->EqualTo("constant")) { + fPhiPDF->SetParameter(18, fReactionPlane); + } else if (iv.fHarmonicsOptionInternalValidation->EqualTo("correlated")) { + fPhiPDF->SetParameter(3, fReactionPlane); + } // Remark: I do not need here anything for option "persistent", because RP is not used for that case. See below how 3 symmetry planes are introduced with persistent correlation + + ebye.fCentrality = static_cast(gRandom->Uniform(0., 100.)); // this is perfectly fine for this exercise + ebye.fOccupancy = static_cast(gRandom->Uniform(0., 10000.)); // this is perfectly fine for this exercise + ebye.fInteractionRate = static_cast(gRandom->Uniform(0., 10000.)); // this is perfectly fine for this exercise + ebye.fCurrentRunDuration = static_cast(gRandom->Uniform(0., 86400.)); // this is perfectly fine for this exercise + ebye.fVz = static_cast(gRandom->Uniform(-20., 20.)); // this is perfectly fine for this exercise + ebye.fFT0CAmplitudeOnFoundBC = static_cast(gRandom->Uniform(0., 100000.)); // this is perfectly fine for this exercise + + // b2) Fill event histograms before cuts: + if (eh.fFillEventHistograms) { + !eh.fEventHistograms[eNumberOfEvents][eSim][eBefore] ? true : eh.fEventHistograms[eNumberOfEvents][eSim][eBefore]->Fill(0.5); + !eh.fEventHistograms[eTotalMultiplicity][eSim][eBefore] ? true : eh.fEventHistograms[eTotalMultiplicity][eSim][eBefore]->Fill(nMult); + !eh.fEventHistograms[eCentrality][eSim][eBefore] ? true : eh.fEventHistograms[eCentrality][eSim][eBefore]->Fill(ebye.fCentrality); + !eh.fEventHistograms[eOccupancy][eSim][eBefore] ? true : eh.fEventHistograms[eOccupancy][eSim][eBefore]->Fill(ebye.fOccupancy); + !eh.fEventHistograms[eInteractionRate][eSim][eBefore] ? true : eh.fEventHistograms[eInteractionRate][eSim][eBefore]->Fill(ebye.fInteractionRate); + !eh.fEventHistograms[eCurrentRunDuration][eSim][eBefore] ? true : eh.fEventHistograms[eCurrentRunDuration][eSim][eBefore]->Fill(ebye.fCurrentRunDuration); + !eh.fEventHistograms[eVertexZ][eSim][eBefore] ? true : eh.fEventHistograms[eVertexZ][eSim][eBefore]->Fill(ebye.fVz); + !eh.fEventHistograms[eEventPlaneAngle][eSim][eBefore] ? true : eh.fEventHistograms[eEventPlaneAngle][eSim][eBefore]->Fill(fReactionPlane); + } + + // ... here I could implement some event cuts, if necessary ... + + // configure p.d.f. for azimuthal angles if harmonics are not constant e-by-e, for option "correlated": + if (iv.fHarmonicsOptionInternalValidation->EqualTo("correlated")) { + // Sample 3 correlated vn's from TF3 fvnPDF, and with them initialize fPhiPDF: + fvnPDF->GetRandom3(v1, v2, v3); + fPhiPDF->SetParameter(0, v1); + fPhiPDF->SetParameter(1, v2); + fPhiPDF->SetParameter(2, v3); + // reaction plane is set above already + } // if(fHarmonicsOptionInternalValidation->EqualTo("correlated")) + + // configure p.d.f. for azimuthal angles if harmonics are not constant e-by-e, for option "persistent": + if (iv.fHarmonicsOptionInternalValidation->EqualTo("persistent")) { + + // Sample 3 correlated vn's from TF3 fvnPDF, and with them initialize fPhiPDF: + fvnPDF->GetRandom3(v1, v2, v3); + fPhiPDF->SetParameter(0, v1); + fPhiPDF->SetParameter(1, v2); + fPhiPDF->SetParameter(2, v3); + + // Persistent symmetry plane correlation: + double Psi1 = gRandom->Uniform(0., o2::constants::math::TwoPI); + double Psi2 = gRandom->Uniform(0., o2::constants::math::TwoPI); + double Psi3 = (1. / 3.) * ((o2::constants::math::PI / 4.) + 2. * Psi2 + Psi1); // see arXiv:1901.06968, Sec. II D. + fPhiPDF->SetParameter(3, Psi1); + fPhiPDF->SetParameter(4, Psi2); + fPhiPDF->SetParameter(5, Psi3); + + // Remark: reaction plane is not needed for case "persistent" + + } // if(fHarmonicsOptionInternalValidation->EqualTo("persistent")) + + // b3) Loop over particles: + double dPhi = 0.; + double dPt = 0.; + double dEta = 0.; + + // *) Define min and max ranges for sampling: + double dPt_min = res.fResultsPro[AFO_PT]->GetXaxis()->GetBinLowEdge(1); // yes, low edge of first bin is pt min + double dPt_max = res.fResultsPro[AFO_PT]->GetXaxis()->GetBinLowEdge(1 + res.fResultsPro[AFO_PT]->GetNbinsX()); // yes, low edge of overflow bin is max pt + double dEta_min = res.fResultsPro[AFO_ETA]->GetXaxis()->GetBinLowEdge(1); // yes, low edge of first bin is eta min + double dEta_max = res.fResultsPro[AFO_ETA]->GetXaxis()->GetBinLowEdge(1 + res.fResultsPro[AFO_ETA]->GetNbinsX()); // yes, low edge of overflow bin is max eta + + for (int p = 0; p < nMult; p++) { + // Particle angle: + dPhi = fPhiPDF->GetRandom(); + + // *) To increase performance, sample pt or eta only if requested: + if (mupa.fCalculateCorrelationsAsFunctionOf[AFO_PT] || t0.fCalculateTest0AsFunctionOf[AFO_PT] || es.fCalculateEtaSeparationsAsFunctionOf[AFO_PT]) { + dPt = gRandom->Uniform(dPt_min, dPt_max); + } + + if (mupa.fCalculateCorrelationsAsFunctionOf[AFO_ETA] || t0.fCalculateTest0AsFunctionOf[AFO_ETA] || es.fCalculateEtaSeparations) { + // Yes, I have to use here es.fCalculateEtaSeparations , and not some differential flag, like for pt case above + dEta = gRandom->Uniform(dEta_min, dEta_max); + } + + // *) Fill few selected particle histograms before cuts here directly: + // Remark: I do not call FillParticleHistograms(track, eBefore), as I do not want to bother to make here full 'track' object, etc., just to fill simple kine info: + if (ph.fFillParticleHistograms || ph.fFillParticleHistograms2D) { + // 1D: + !ph.fParticleHistograms[ePhi][eSim][eBefore] ? true : ph.fParticleHistograms[ePhi][eSim][eBefore]->Fill(dPhi); + !ph.fParticleHistograms[ePt][eSim][eBefore] ? true : ph.fParticleHistograms[ePt][eSim][eBefore]->Fill(dPt); + !ph.fParticleHistograms[eEta][eSim][eBefore] ? true : ph.fParticleHistograms[eEta][eSim][eBefore]->Fill(dEta); + // 2D: + !ph.fParticleHistograms2D[ePhiPt][eSim][eBefore] ? true : ph.fParticleHistograms2D[ePhiPt][eSim][eBefore]->Fill(dPhi, dPt); + !ph.fParticleHistograms2D[ePhiEta][eSim][eBefore] ? true : ph.fParticleHistograms2D[ePhiEta][eSim][eBefore]->Fill(dPhi, dEta); + } + + // *) Particle cuts (only support for Toy NUA is provided, for the time being): + // NUA: + if (nua.fApplyNUAPDF[ePhiNUAPDF] && !Accept(dPhi, ePhiNUAPDF)) { + continue; + } + if (nua.fApplyNUAPDF[ePtNUAPDF] && !Accept(dPt, ePtNUAPDF)) { + continue; + } + if (nua.fApplyNUAPDF[eEtaNUAPDF] && !Accept(dEta, eEtaNUAPDF)) { + continue; + } + + // *) Fill few selected particle histograms after cuts here directly here: + // Remark: I do not call FillParticleHistograms(track, eAfter), as I do not want to bother to make here full 'track' object, etc., just to fill simple kine info: + if (ph.fFillParticleHistograms || ph.fFillParticleHistograms2D) { + // 1D: + !ph.fParticleHistograms[ePhi][eSim][eAfter] ? true : ph.fParticleHistograms[ePhi][eSim][eAfter]->Fill(dPhi); + !ph.fParticleHistograms[ePt][eSim][eAfter] ? true : ph.fParticleHistograms[ePt][eSim][eAfter]->Fill(dPt); + !ph.fParticleHistograms[eEta][eSim][eAfter] ? true : ph.fParticleHistograms[eEta][eSim][eAfter]->Fill(dEta); + // 2D: + !ph.fParticleHistograms2D[ePhiPt][eSim][eAfter] ? true : ph.fParticleHistograms2D[ePhiPt][eSim][eAfter]->Fill(dPhi, dPt); + !ph.fParticleHistograms2D[ePhiEta][eSim][eAfter] ? true : ph.fParticleHistograms2D[ePhiEta][eSim][eAfter]->Fill(dPhi, dEta); + } + + // Remark: Keep in sync all calls and flags below with the ones in MainLoopOverParticles(). + // *) Integrated Q-vectors: + if (qv.fCalculateQvectors || es.fCalculateEtaSeparations) { + this->FillQvector(dPhi, dPt, dEta); // all 3 arguments are passed by reference + } + + // *) Differential q-vectors: + // **) pt-dependence: + if (qv.fCalculateQvectors && (mupa.fCalculateCorrelationsAsFunctionOf[AFO_PT] || t0.fCalculateTest0AsFunctionOf[AFO_PT]) && !es.fCalculateEtaSeparations) { + // In this branch I do not need eta separation, so the lighter call can be executed: + this->Fillqvector(dPhi, dPt, PTq); // first 2 arguments are passed by reference, 3rd argument is enum + } else if (es.fCalculateEtaSeparations && es.fCalculateEtaSeparationsAsFunctionOf[AFO_PT]) { + // In this branch I do need eta separation, so the heavier call must be executed: + // Remark: Within Fillqvector() I check again all the relevant flags. + this->Fillqvector(dPhi, dPt, PTq, dEta); // first 2 arguments and the last one are passed by reference, 3rd argument is enum. "kine" variable is the 2nd argument + } + // **) eta-dependence: + if (qv.fCalculateQvectors && (mupa.fCalculateCorrelationsAsFunctionOf[AFO_ETA] || t0.fCalculateTest0AsFunctionOf[AFO_ETA])) { + // Remark: For eta dependence I do not consider es.fCalculateEtaSeparations, because in this context that calculation is meaningless. + this->Fillqvector(dPhi, dEta, ETAq); // first 2 arguments are passed by reference, 3rd argument is enum + } + + // *) Fill nested loops containers: + if (nl.fCalculateNestedLoops || nl.fCalculateCustomNestedLoops) { + this->FillNestedLoopsContainers(ebye.fSelectedTracks, dPhi, dPt, dEta); // all 4 arguments are passed by reference + } + + // *) Counter of selected tracks in the current event: + // Remark: This has to go after FillNestedLoopsContainers(...), because ebye.fSelectedTracks is used as a particle index there. + ebye.fSelectedTracks++; + if (ebye.fSelectedTracks >= ec.fdEventCuts[eMultiplicity][eMax]) { + break; + } + + } // for(int p=0;pFill(0.5); + !eh.fEventHistograms[eTotalMultiplicity][eSim][eAfter] ? true : eh.fEventHistograms[eTotalMultiplicity][eSim][eAfter]->Fill(nMult); + !eh.fEventHistograms[eMultiplicity][eSim][eAfter] ? true : eh.fEventHistograms[eMultiplicity][eSim][eAfter]->Fill(ebye.fMultiplicity); + !eh.fEventHistograms[eCentrality][eSim][eAfter] ? true : eh.fEventHistograms[eCentrality][eSim][eAfter]->Fill(ebye.fCentrality); + !eh.fEventHistograms[eOccupancy][eSim][eAfter] ? true : eh.fEventHistograms[eOccupancy][eSim][eAfter]->Fill(ebye.fOccupancy); + !eh.fEventHistograms[eInteractionRate][eSim][eAfter] ? true : eh.fEventHistograms[eCentrality][eSim][eAfter]->Fill(ebye.fInteractionRate); + !eh.fEventHistograms[eCurrentRunDuration][eSim][eAfter] ? true : eh.fEventHistograms[eCurrentRunDuration][eSim][eAfter]->Fill(ebye.fCurrentRunDuration); + !eh.fEventHistograms[eVertexZ][eSim][eAfter] ? true : eh.fEventHistograms[eVertexZ][eSim][eAfter]->Fill(ebye.fVz); + !eh.fEventHistograms[eEventPlaneAngle][eSim][eAfter] ? true : eh.fEventHistograms[eEventPlaneAngle][eSim][eAfter]->Fill(fReactionPlane); + } + + // *) Fill subevent multiplicities: + // Remark: I can call this one only after Qa and Qb vectors are filled: + if (es.fCalculateEtaSeparations) { + FillSubeventMultiplicities(); + } + + // b5) Calculate everything for selected events and particles: + CalculateEverything(); + + // *) Reset event-by-event quantities: + ResetEventByEventQuantities(); + + // *) Print info on the current event number (within current real event): + LOGF(info, " Event # %d/%d (within current real event) ....", e + 1, static_cast(iv.fnEventsInternalValidation)); + + // *) Determine all event counters: + DetermineEventCounters(); + + // *) Sequential bailout: After each tc.fSequentialBailout events, I bail out: + if (iv.fInternalValidationForceBailout && tc.fSequentialBailout > 0 && eh.fEventCounter[eProcessed] > 0 && 0 == eh.fEventCounter[eProcessed] % tc.fSequentialBailout) { + BailOut(); + } + + // *) If I reached max number of events, ignore the remaining collisions: + if (MaxNumberOfEvents(eAfter)) { + if (iv.fInternalValidationForceBailout) { + BailOut(true); + } + } + + } // for(int e=0;e(iv.fnEventsInternalValidation);e++) + + // *) Print info on the current event number (total): + if (tc.fVerboseEventCounter) { + PrintEventCounter(eAfter); + } + + // c) Delete persistent objects: + if (fPhiPDF) { + delete fPhiPDF; + } + if (fvnPDF) { + delete fvnPDF; + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void InternalValidation() + +//============================================================ + +bool Accept(const double& value, int var) +{ + // Given the acceptance profile for this observable, accept or not that observable for the analysis. + // Use in Toy NUA studies. + + // Remark: var corresponds to the field in enum eNUAPDF { ePhiNUAPDF, ePtNUAPDF, eEtaNUAPDF }; + // Therefore, always call this function as e.g. Accept(someAngle, ePhiNUAPDF) or Accept(somePt, ePtNUAPDF) + + if (tc.fVerboseForEachParticle) { + LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + } + + // Basic protection: + if (nua.fUseDefaultNUAPDF[var] && !nua.fDefaultNUAPDF[var]) { + LOGF(info, "\033[1;33m%s var = %d\033[0m", static_cast(var)); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } else if (!nua.fUseDefaultNUAPDF[var] && !nua.fCustomNUAPDF[var]) { + LOGF(info, "\033[1;33m%s var = %d\033[0m", static_cast(var)); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + bool bAccept = true; // return value + + double acceptanceProbability = 1.; + double correspondingAcceptance = -44.; + if (!nua.fUseDefaultNUAPDF[var]) { + correspondingAcceptance = nua.fCustomNUAPDF[var]->GetBinContent(nua.fCustomNUAPDF[var]->FindBin(value)); + } else { + correspondingAcceptance = nua.fDefaultNUAPDF[var]->Eval(value); + } + + // Probability to accept: + acceptanceProbability = 1. - (nua.fMaxValuePDF[var] - correspondingAcceptance) / nua.fMaxValuePDF[var]; + + // Accept or not: + (gRandom->Uniform(0, 1) < acceptanceProbability) ? bAccept = true : bAccept = false; + + return bAccept; + +} // bool Accept(const double &value, int var) + +//============================================================ + +void BookTest0Histograms() +{ + // Book all Test0 histograms. + + // a) Book the profile holding flags; + // b) Book placeholder and make sure all labels are stored in the placeholder; + // c) Retrieve labels from placeholder; + // d) Book what needs to be booked; + // e) Few quick insanity checks on booking. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Book the profile holding flags: + t0.fTest0FlagsPro = new TProfile("fTest0FlagsPro", "flags for Test0", 1, 0., 1.); + t0.fTest0FlagsPro->SetStats(false); + t0.fTest0FlagsPro->GetXaxis()->SetLabelSize(0.04); + t0.fTest0FlagsPro->GetXaxis()->SetBinLabel(1, "fCalculateTest0"); + t0.fTest0FlagsPro->Fill(0.5, t0.fCalculateTest0); + t0.fTest0List->Add(t0.fTest0FlagsPro); + + if (!t0.fCalculateTest0) { + return; + } + + // b) Book placeholder and make sure all labels are stored in the placeholder: + this->StoreLabelsInPlaceholder(); + if (t0.fTest0LabelsPlaceholder) { + t0.fTest0List->Add(t0.fTest0LabelsPlaceholder); + } + + // c) Retrieve labels from placeholder: + if (!(this->RetrieveCorrelationsLabels())) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + // d) Book what needs to be booked: + for (int mo = 0; mo < gMaxCorrelator; mo++) { + for (int mi = 0; mi < gMaxIndex; mi++) { + if (!t0.fTest0Labels[mo][mi]) { + continue; + } + { + for (int v = 0; v < eAsFunctionOf_N; v++) { + // decide what is booked, then later valid pointer to fCorrelationsPro[k][n][v] is used as a boolean, in the standard way: + if (AFO_INTEGRATED == v && !t0.fCalculateTest0AsFunctionOf[AFO_INTEGRATED]) { + continue; + } + if (AFO_MULTIPLICITY == v && !t0.fCalculateTest0AsFunctionOf[AFO_MULTIPLICITY]) { + continue; + } + if (AFO_CENTRALITY == v && !t0.fCalculateTest0AsFunctionOf[AFO_CENTRALITY]) { + continue; + } + if (AFO_PT == v && !t0.fCalculateTest0AsFunctionOf[AFO_PT]) { + continue; + } + if (AFO_ETA == v && !t0.fCalculateTest0AsFunctionOf[AFO_ETA]) { + continue; + } + if (AFO_OCCUPANCY == v && !t0.fCalculateTest0AsFunctionOf[AFO_OCCUPANCY]) { + continue; + } + if (AFO_INTERACTIONRATE == v && !t0.fCalculateTest0AsFunctionOf[AFO_INTERACTIONRATE]) { + continue; + } + if (AFO_CURRENTRUNDURATION == v && !t0.fCalculateTest0AsFunctionOf[AFO_CURRENTRUNDURATION]) { + continue; + } + if (AFO_VZ == v && !t0.fCalculateTest0AsFunctionOf[AFO_VZ]) { + continue; + } + + if (!res.fResultsPro[v]) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + t0.fTest0Pro[mo][mi][v] = reinterpret_cast(res.fResultsPro[v]->Clone(Form("fTest0Pro[%d][%d][%s]", mo, mi, res.fResultsProRawName[v].Data()))); // yes + t0.fTest0Pro[mo][mi][v]->SetStats(false); + t0.fTest0Pro[mo][mi][v]->Sumw2(); + t0.fTest0Pro[mo][mi][v]->SetTitle(t0.fTest0Labels[mo][mi]->Data()); + t0.fTest0Pro[mo][mi][v]->GetXaxis()->SetTitle(FancyFormatting(res.fResultsProXaxisTitle[v].Data())); + /* + if(fUseFixedNumberOfRandomlySelectedParticles && 1==v) // just a warning for the meaning of multiplicity in this special case + { + fTest0Pro[mo][mi][1]->GetXaxis()->SetTitle("WARNING: for each multiplicity, fFixedNumberOfRandomlySelectedParticles is selected randomly in Q-vector"); + } + */ + t0.fTest0List->Add(t0.fTest0Pro[mo][mi][v]); // yes, this has to be here + } // for(int v=0;vGetXaxis()->GetTitle()).EqualTo("integrated")) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); // ordering in enum eAsFunctionOf is not the same as in TString fResultsProXaxisTitle[eAsFunctionOf_N] + } + if (t0.fTest0Pro[0][0][AFO_PT] && !TString(t0.fTest0Pro[0][0][AFO_PT]->GetXaxis()->GetTitle()).EqualTo("p_{T}")) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); // ordering in enum eAsFunctionOf is not the same as in TString fResultsProXaxisTitle[eAsFunctionOf_N] + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void BookTest0Histograms() + +//============================================================ + +void BookEtaSeparationsHistograms() +{ + // Book all eta separations histograms. + + // a) Book the profile holding flags; + // b) Book what needs to be booked; + // c) Few quick insanity checks on booking. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Book the profile holding flags: + es.fEtaSeparationsFlagsPro = new TProfile("fEtaSeparationsFlagsPro", "flags for eta separations", 1, 0., 1.); + es.fEtaSeparationsFlagsPro->SetStats(false); + es.fEtaSeparationsFlagsPro->SetLineColor(eColor); + es.fEtaSeparationsFlagsPro->SetFillColor(eFillColor); + es.fEtaSeparationsFlagsPro->GetXaxis()->SetLabelSize(0.04); + es.fEtaSeparationsFlagsPro->GetXaxis()->SetBinLabel(1, "fCalculateEtaSeparations"); + es.fEtaSeparationsFlagsPro->Fill(0.5, es.fCalculateEtaSeparations); + es.fEtaSeparationsList->Add(es.fEtaSeparationsFlagsPro); + + if (!es.fCalculateEtaSeparations) { + return; + } + + // b) Book what needs to be booked: + for (int h = 0; h < gMaxHarmonic; h++) { + if (es.fEtaSeparationsSkipHarmonics[h]) { + continue; + } + for (int e = 0; e < gMaxNumberEtaSeparations; e++) { + for (int v = 0; v < eAsFunctionOf_N; v++) { + // decide what is booked, then later valid pointer to es.fEtaSeparationsPro[h][e][v] is used as a boolean, in the standard way: + if (AFO_INTEGRATED == v && !es.fCalculateEtaSeparationsAsFunctionOf[AFO_INTEGRATED]) { + continue; + } + if (AFO_MULTIPLICITY == v && !es.fCalculateEtaSeparationsAsFunctionOf[AFO_MULTIPLICITY]) { + continue; + } + if (AFO_CENTRALITY == v && !es.fCalculateEtaSeparationsAsFunctionOf[AFO_CENTRALITY]) { + continue; + } + if (AFO_PT == v && !es.fCalculateEtaSeparationsAsFunctionOf[AFO_PT]) { + continue; + } + if (AFO_ETA == v && !es.fCalculateEtaSeparationsAsFunctionOf[AFO_ETA]) { + continue; + } + if (AFO_OCCUPANCY == v && !es.fCalculateEtaSeparationsAsFunctionOf[AFO_OCCUPANCY]) { + continue; + } + if (AFO_INTERACTIONRATE == v && !es.fCalculateEtaSeparationsAsFunctionOf[AFO_INTERACTIONRATE]) { + continue; + } + if (AFO_CURRENTRUNDURATION == v && !es.fCalculateEtaSeparationsAsFunctionOf[AFO_CURRENTRUNDURATION]) { + continue; + } + if (AFO_VZ == v && !es.fCalculateEtaSeparationsAsFunctionOf[AFO_VZ]) { + continue; + } + + if (!res.fResultsPro[v]) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + es.fEtaSeparationsPro[h][e][v] = reinterpret_cast(res.fResultsPro[v]->Clone(Form("fEtaSeparationsPro[%d][%d][%s]", h, e, res.fResultsProRawName[v].Data()))); // yes + es.fEtaSeparationsPro[h][e][v]->SetStats(false); + es.fEtaSeparationsPro[h][e][v]->Sumw2(); + es.fEtaSeparationsPro[h][e][v]->SetTitle(Form("%d -%d, |#Delta#eta| > %.2f", h + 1, h + 1, es.fEtaSeparationsValues[e])); + es.fEtaSeparationsPro[h][e][v]->GetXaxis()->SetTitle(FancyFormatting(res.fResultsProXaxisTitle[v].Data())); + es.fEtaSeparationsList->Add(es.fEtaSeparationsPro[h][e][v]); // yes, this has to be here + } // for(int v=0;vGetXaxis()->GetTitle()).EqualTo("integrated")) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); // ordering in enum eAsFunctionOf is not the same as in TString fResultsProXaxisTitle[eAsFunctionOf_N] + } + if (es.fEtaSeparationsPro[0][0][AFO_PT] && !TString(es.fEtaSeparationsPro[0][0][AFO_PT]->GetXaxis()->GetTitle()).EqualTo("p_{T}")) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); // ordering in enum eAsFunctionOf is not the same as in TString fResultsProXaxisTitle[eAsFunctionOf_N] + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void BookEtaSeparationsHistograms() + +//============================================================ + +void BookResultsHistograms() +{ + // Book all results histograms. + + // a) Book the profile holding flags; + // b) Book results histograms, which in addition act as a sort of "abstract" interface, which defines common binning, etc., for other groups of histograms. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Book the profile holding flags: + res.fResultsFlagsPro = new TProfile("fResultsFlagsPro", "flags for results histograms", 1, 0., 1.); + res.fResultsFlagsPro->SetStats(false); + res.fResultsFlagsPro->SetLineColor(eColor); + res.fResultsFlagsPro->SetFillColor(eFillColor); + res.fResultsFlagsPro->GetXaxis()->SetBinLabel(1, "fSaveResultsHistograms"); + res.fResultsFlagsPro->Fill(0.5, res.fSaveResultsHistograms); + // ... + res.fResultsList->Add(res.fResultsFlagsPro); + + // b) Book results histograms, which in addition act as a sort of "abstract" interface, which defines common binning, etc., for other groups of histograms: + for (int v = 0; v < eAsFunctionOf_N; v++) { + if (res.fUseResultsProVariableLengthBins[v]) { + // per demand, variable-length binning: + res.fResultsPro[v] = new TProfile(Form("fResultsPro[%s]", res.fResultsProRawName[v].Data()), "...", res.fResultsProVariableLengthBins[v]->GetSize() - 1, res.fResultsProVariableLengthBins[v]->GetArray()); + } else { + // the default fixed-length binning: + res.fResultsPro[v] = new TProfile(Form("fResultsPro[%s]", res.fResultsProRawName[v].Data()), "...", static_cast(res.fResultsProFixedLengthBins[v][0]), res.fResultsProFixedLengthBins[v][1], res.fResultsProFixedLengthBins[v][2]); + } + + // Optionally, save these histograms. Or just use them as an "abstract" interface for the booking of other group of histograms: + if (res.fSaveResultsHistograms) { + res.fResultsList->Add(res.fResultsPro[v]); + } + } // for (int v = 0; v < eAsFunctionOf_N; v++) { + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void BookResultsHistograms() + +//============================================================ + +void BookTheRest() +{ + // Here I book everything not sorted (yes) in specific functions above. + + // a) Book the timer; + // *) ... + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Book the timer: + if (tc.fUseStopwatch) { + tc.fTimer[eGlobal] = new TStopwatch(); + tc.fTimer[eGlobal]->Start(); + tc.fTimer[eLocal] = new TStopwatch(); + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void BookTheRest() + +//============================================================ + +template +void Preprocess(T1 const& collision, T2 const& bcs) +{ + // Do all thingies before starting to process data (e.g. count number of events, fetch the run number, get the weights for this run number, etc.). + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // *) Determine all event counters: + DetermineEventCounters(); + + // *) Sequential bailout: After each tc.fSequentialBailout events, I bail out: + if (tc.fSequentialBailout > 0 && eh.fEventCounter[eProcessed] > 0 && 0 == eh.fEventCounter[eProcessed] % tc.fSequentialBailout) { + BailOut(); + } + + // *) If I reached max number of events, ignore the remaining collisions: + if (MaxNumberOfEvents(eAfter) || MaxNumberOfEvents(eBefore)) { // TBI 20240510 this is a bit confusing, implemented this way. Shall I split off? + BailOut(true); + } + + // *) Determine and propagate run number info to already booked objects: + if (!tc.fRunNumberIsDetermined) { + DetermineRunNumber(collision, bcs); + PropagateRunNumber(); + } + if (tc.fDoAdditionalInsanityChecks && tc.fRunNumberIsDetermined) { + CheckCurrentRunNumber(collision, bcs); + } + + // *) Check whether this run shall be skipped later from further processing in Steer(): + if (!tc.fSkipTheseRuns.EqualTo("")) { + // If tc.fSkipTheseRuns is not empty, that means it holds comma-separated list of runs to be skipped. Let's check it out... + SkipThisRun(); // I set inside the data member tc.fSkipRun , which serves then as a switch later all over the place + if (tc.fSkipRun) { + return; // yes, I bail out immediately from Preprocess, so that I do not waste time on fetching weights for this run + } + // TBI 20250316 Same comment here: At the moment I can access run number info only in process(...), but not in init(...) + // Once I can access run number info in init(...), this function shall be called in init(...), not in process(...) + } // if (!tc.fSkipTheseRuns.EqualTo("")) + + // *) Fetch the weights for this particular run number. Do it only once. + // TBI 20231012 If eventualy I can access programatically run number in init(...) at run time, this shall go there. + if (!pw.fParticleWeightsAreFetched) { + + // integrated weights and differentials weights without sparse histograms (the latter is becoming obsolete): + if (pw.fUseWeights[wPHI] || pw.fUseWeights[wPT] || pw.fUseWeights[wETA] || pw.fUseDiffWeights[wPHIPT] || pw.fUseDiffWeights[wPHIETA]) { + pw.fParticleWeightsAreFetched = true; + } + + // differential particle weights using sparse histogreams: + if (pw.fUseDiffPhiWeights[wPhiPhiAxis] || pw.fUseDiffPtWeights[wPtPtAxis] || pw.fUseDiffPtWeights[wEtaEtaAxis]) { + // Yes, I check only the first flag. This way, I can e.g. switch off all differential phi weights by setting 0-wPhi in config. + // On the other hand, it doesn't make sense to calculate differential phi weights without having phi axis. + // At any point I shall be able to fall back e.g. to integrated phi weights, that corresponds to the case wheh "1-wPhi" and all others are "0-w..." + // Same for differential pt or eta weights. + GetParticleWeights(); + pw.fParticleWeightsAreFetched = true; + } + + } // if (!pw.fParticleWeightsAreFetched) { + + // *) Fetch the centrality weights for this particular run number. Do it only once. + // TBI 20231012 If eventualy I can access programatically run number in init(...) at run time, this shall go there. + if (!cw.fCentralityWeightsAreFetched) { + if (cw.fUseCentralityWeights) { + GetCentralityWeights(); + cw.fCentralityWeightsAreFetched = true; + } + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // template void Preprocess(T1 const& collision, T2 const& bcs) + +//============================================================ + +template +void DetermineRunNumber(T1 const& collision, T2 const&) +{ + // Determine run number and all related thingies. + // Make sure in process(...) that this function is called only once. + + // TBI 20231018 At the moment I can access run number info only in process(...), but not in init(...) + // Once I can access run number info in init(...), this function shall be called in init(...), not in process(...) + + // a) Determine run number for Run 3 and Run 2 real data; + // b) Determine run number for the rest. TBI 20241126 differentiate this support as well, e.g. for eRecSim and eSim. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Determine run number for Run 3 and Run 2 real data; + if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eQA) { + + // **) Determine run number: + // Get start timestamp and end timemstamp for this run in miliseconds, and convert both of them in seconds: + // o see O2/CCDB/src/BasicCCDBManager.cxx, O2/CCDB/include/CCDB/BasicCCDBManager.h + // o example usage in O2Physics/PWGLF/TableProducer/Common/zdcSP.cxx + auto bc = collision.template foundBC_as(); // I have the same code snippet at other places, keep in sync. + tc.fRunNumber = Form("%d", bc.runNumber()); + if (tc.fRunNumber.EqualTo("")) { + LOGF(error, "\033[1;33m%fRunNumber is empty, bc.runNumber() failed...\033[0m"); + LOGF(fatal, "\033[1;31m%s at line %d : bc.runNumber() = %d \033[0m", __FUNCTION__, __LINE__, bc.runNumber()); + } + + // **) Determine SoR, EoR, and run duration: + auto runDuration = ccdb->getRunDuration(bc.runNumber()); // this is total run duration, not the current one (see below) + tc.fRunTime[eStartOfRun] = std::floor(runDuration.first * 0.001); // in seconds since Unix epoch + tc.fRunTime[eEndOfRun] = std::ceil(runDuration.second * 0.001); // in seconds since Unix epoch + tc.fRunTime[eDurationInSec] = tc.fRunTime[eEndOfRun] - tc.fRunTime[eStartOfRun]; // yes, this is now run duration in seconds + + if (!(tc.fRunTime[eStartOfRun] > 0)) { + LOGF(fatal, "\033[1;31m%s at line %d : tc.fRunTime[eStartOfRun] = %d is not positive\033[0m", __FUNCTION__, __LINE__, tc.fRunTime[eStartOfRun]); + } + if (!(tc.fRunTime[eEndOfRun] > 0)) { + LOGF(fatal, "\033[1;31m%s at line %d : tc.fRunTime[eEndOfRun] = %d is not positive\033[0m", __FUNCTION__, __LINE__, tc.fRunTime[eEndOfRun]); + } + if (!(tc.fRunTime[eDurationInSec] > 0)) { + LOGF(fatal, "\033[1;31m%s at line %d : tc.fRunTime[eDurationInSec] = %d is not positive\033[0m", __FUNCTION__, __LINE__, tc.fRunTime[eDurationInSec]); + } + + } else if constexpr (rs == eTest) { + LOGF(warning, "\033[1;33m%s at line %d : RunNumber cannot be determined for eTest mode, due to minimal subscription. Setting run number manually to some dummy value. If you do not like this, extend subscription to more tables.\033[0m", __FUNCTION__, __LINE__); + tc.fRunNumber = "123456"; + } else { + // b) Determine run number for the rest. + // TBI 20241126 differentiate this support as well, e.g. for eRecSim and eSim. + LOGF(fatal, "\033[1;31m%s at line %d : bc.runNumber() is not validated yet for this case\033[0m", __FUNCTION__, __LINE__); + } + tc.fRunNumberIsDetermined = true; + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // template void DetermineRunNumber(T1 const& collision, T2 const&) + +//============================================================ + +void PropagateRunNumber() +{ + // Propagate run number info to already booked objects, wherever it's relevant. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // Do some local insanity checks: + if (tc.fRunNumber.EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : tc.fRunNumber is empty \033[0m", __FUNCTION__, __LINE__); + } + + // *) base: + fBasePro->GetXaxis()->SetBinLabel(eRunNumber, Form("fRunNumber = %s", tc.fRunNumber.Data())); + + // *) common title var: + TString histTitle = ""; + + // *) event cuts: + for (int rs = 0; rs < 2; rs++) // reco/sim + { + for (int cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter + { + if (!ec.fEventCutCounterHist[rs][cc]) { + continue; + } + histTitle = ec.fEventCutCounterHist[rs][cc]->GetTitle(); + if (histTitle.Contains("__RUN_NUMBER__")) { + histTitle.ReplaceAll("__RUN_NUMBER__", tc.fRunNumber.Data()); // it replaces in-place + ec.fEventCutCounterHist[rs][cc]->SetTitle(histTitle.Data()); + } + } + } + + // *) event histograms 1D: + for (int t = 0; t < eEventHistograms_N; t++) // type, see enum eEventHistograms + { + for (int rs = 0; rs < 2; rs++) // reco/sim + { + for (int ba = 0; ba < 2; ba++) // before/after cuts + { + if (!eh.fEventHistograms[t][rs][ba]) { + continue; + } + histTitle = eh.fEventHistograms[t][rs][ba]->GetTitle(); + if (histTitle.Contains("__RUN_NUMBER__")) { + histTitle.ReplaceAll("__RUN_NUMBER__", tc.fRunNumber.Data()); // it replaces in-place + eh.fEventHistograms[t][rs][ba]->SetTitle(histTitle.Data()); + } + } // for(int ba=0;ba<2;ba++) + } // for(int rs=0;rs<2;rs++) // reco/sim + } // for(int t=0;tGetTitle(); + if (histTitle.Contains("__RUN_NUMBER__")) { + histTitle.ReplaceAll("__RUN_NUMBER__", tc.fRunNumber.Data()); // it replaces in-place + qa.fQAEventHistograms2D[t][rs][ba]->SetTitle(histTitle.Data()); + } + } // for(int ba=0;ba<2;ba++) + } // for(int rs=0;rs<2;rs++) // reco/sim + } // for (int t = 0; t < eQAEventHistograms2D_N; t++) // type, see enum eEventHistograms2D + + // *) particle histograms 2D: + for (int t = 0; t < eQAParticleHistograms2D_N; t++) // type, see enum eParticleHistograms2D + { + for (int rs = 0; rs < 2; rs++) // reco/sim + { + for (int ba = 0; ba < 2; ba++) // before/after cuts + { + if (!qa.fQAParticleHistograms2D[t][rs][ba]) { + continue; + } + histTitle = qa.fQAParticleHistograms2D[t][rs][ba]->GetTitle(); + if (histTitle.Contains("__RUN_NUMBER__")) { + histTitle.ReplaceAll("__RUN_NUMBER__", tc.fRunNumber.Data()); // it replaces in-place + qa.fQAParticleHistograms2D[t][rs][ba]->SetTitle(histTitle.Data()); + } + } // for(int ba=0;ba<2;ba++) + } // for(int rs=0;rs<2;rs++) // reco/sim + } // for (int t = 0; t < eQAParticleHistograms2D_N; t++) // type, see enum eParticleHistograms2D + + // *) particle event histograms 2D: + for (int t = 0; t < eQAParticleEventHistograms2D_N; t++) // type, see enum eParticleEventHistograms2D + { + for (int rs = 0; rs < 2; rs++) // reco/sim + { + for (int ba = 0; ba < 2; ba++) // before/after cuts + { + if (!qa.fQAParticleEventHistograms2D[t][rs][ba]) { + continue; + } + histTitle = qa.fQAParticleEventHistograms2D[t][rs][ba]->GetTitle(); + if (histTitle.Contains("__RUN_NUMBER__")) { + histTitle.ReplaceAll("__RUN_NUMBER__", tc.fRunNumber.Data()); // it replaces in-place + qa.fQAParticleEventHistograms2D[t][rs][ba]->SetTitle(histTitle.Data()); + } + } // for(int ba=0;ba<2;ba++) + } // for(int rs=0;rs<2;rs++) // reco/sim + } // for (int t = 0; t < eQAParticleEventHistograms2D_N; t++) // type, see enum eParticleEventHistograms2D + + // *) particle sparse histograms: + for (int t = 0; t < eDiffWeightCategory_N; t++) // category, see enum eDiffWeightCategory + { + for (int rs = 0; rs < 2; rs++) // reco/sim + { + if (!ph.fParticleSparseHistograms[t][rs]) { + continue; + } + histTitle = ph.fParticleSparseHistograms[t][rs]->GetTitle(); + if (histTitle.Contains("__RUN_NUMBER__")) { + histTitle.ReplaceAll("__RUN_NUMBER__", tc.fRunNumber.Data()); // it replaces in-place + ph.fParticleSparseHistograms[t][rs]->SetTitle(histTitle.Data()); + } + } // for(int rs=0;rs<2;rs++) // reco/sim + } // for (int t = 0; t < eDiffWeightCategory; t++) // category, see enum eDiffWeightCategory + + // *) "correlations vs." histograms 2D: + for (int t = 0; t < eQACorrelationsVsHistograms2D_N; t++) // type, see enum eCorrelationsVsHistograms2D + { + for (int h = 0; h < gMaxHarmonic; h++) { + for (int rs = 0; rs < 2; rs++) // reco/sim + { + if (!qa.fQACorrelationsVsHistograms2D[t][h][rs]) { + continue; + } + histTitle = qa.fQACorrelationsVsHistograms2D[t][h][rs]->GetTitle(); + if (histTitle.Contains("__RUN_NUMBER__")) { + histTitle.ReplaceAll("__RUN_NUMBER__", tc.fRunNumber.Data()); // it replaces in-place + qa.fQACorrelationsVsHistograms2D[t][h][rs]->SetTitle(histTitle.Data()); + } + } // for(int rs=0;rs<2;rs++) // reco/sim + } // for (int h = 0; h < gMaxHarmonic; h++) + } // for (int t = 0; t < eQACorrelationsVsHistograms2D_N; t++) // type, see enum eCorrelationsVsHistograms2D + + // *) "correlations vs. IR vs. " profiles 2D: + for (int t = 0; t < eQACorrelationsVsInteractionRateVsProfiles2D_N; t++) // type, see enum eCorrelationsVsInteractionRateVsProfiles2D + { + for (int h = 0; h < gMaxHarmonic; h++) { + for (int rs = 0; rs < 2; rs++) // reco/sim + { + if (!qa.fQACorrVsIRVsProfiles2D[t][h][rs]) { + continue; + } + histTitle = qa.fQACorrVsIRVsProfiles2D[t][h][rs]->GetTitle(); + if (histTitle.Contains("__RUN_NUMBER__")) { + histTitle.ReplaceAll("__RUN_NUMBER__", tc.fRunNumber.Data()); // it replaces in-place + qa.fQACorrVsIRVsProfiles2D[t][h][rs]->SetTitle(histTitle.Data()); + } + } // for(int rs=0;rs<2;rs++) // reco/sim + } // for (int h = 0; h < gMaxHarmonic; h++) + } // for (int t = 0; t < eQACorrelationsVsInteractionRateVsProfiles2D_N; t++) // type, see enum eCorrelationsVsInteractionRateVsProfiles2D + + // *) particle cuts: + for (int rs = 0; rs < 2; rs++) // reco/sim + { + for (int cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter + { + if (!pc.fParticleCutCounterHist[rs][cc]) { + continue; + } + histTitle = pc.fParticleCutCounterHist[rs][cc]->GetTitle(); + if (histTitle.Contains("__RUN_NUMBER__")) { + histTitle.ReplaceAll("__RUN_NUMBER__", tc.fRunNumber.Data()); // it replaces in-place + pc.fParticleCutCounterHist[rs][cc]->SetTitle(histTitle.Data()); + } + } + } + + // *) particle histograms 1D: + for (int t = 0; t < eParticleHistograms_N; t++) // type, see enum eParticleHistograms + { + for (int rs = 0; rs < 2; rs++) // reco/sim + { + for (int ba = 0; ba < 2; ba++) // before/after cuts + { + if (!ph.fParticleHistograms[t][rs][ba]) { + continue; + } + histTitle = ph.fParticleHistograms[t][rs][ba]->GetTitle(); + if (histTitle.Contains("__RUN_NUMBER__")) { + histTitle.ReplaceAll("__RUN_NUMBER__", tc.fRunNumber.Data()); // it replaces in-place + ph.fParticleHistograms[t][rs][ba]->SetTitle(histTitle.Data()); + } + } // for(int ba=0;ba<2;ba++) + } // for(int rs=0;rs<2;rs++) // reco/sim + } // for(int t=0;tGetTitle(); + if (histTitle.Contains("__RUN_NUMBER__")) { + histTitle.ReplaceAll("__RUN_NUMBER__", tc.fRunNumber.Data()); // it replaces in-place + ph.fParticleHistograms2D[t][rs][ba]->SetTitle(histTitle.Data()); + } + } // for(int ba=0;ba<2;ba++) + } // for(int rs=0;rs<2;rs++) // reco/sim + } // for(int t=0;t -eta , ab = 1 <=> + eta + for (int rs = 0; rs < 2; rs++) { // reco/sim + for (int ba = 0; ba < 2; ba++) { // before/after cuts + for (int e = 0; e < gMaxNumberEtaSeparations; e++) { // eta separation + if (!qv.fMabDist[ab][rs][ba][e]) { + continue; + } + histTitle = qv.fMabDist[ab][rs][ba][e]->GetTitle(); + if (histTitle.Contains("__RUN_NUMBER__")) { + histTitle.ReplaceAll("__RUN_NUMBER__", tc.fRunNumber.Data()); // it replaces in-place + qv.fMabDist[ab][rs][ba][e]->SetTitle(histTitle.Data()); + } + } + } + } + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // PropagateRunNumber() + +//============================================================ + +template +void CheckCurrentRunNumber(T1 const& collision, T2 const&) +{ + // Insanity check for the current run number and related thingies. + // Used only during validation. + + // a) Support for Run 3 and Run 2 real data; + // b) The rest. TBI 20241126 differentiate this support as well, e.g. for eRecSim and eSim. But Run 2 and Run 1 most likely will stay as before + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Support for Run 3 and Run 2 real data: + // TBI 20250112 enable other cases, after validating them + // TBI 20250112 Remember that I can get total run duration in converted data, but not current run duration. + if constexpr (rs == eRec || rs == eRec_Run2 || rs == eQA) { + + // **) Check run number: + auto bc = collision.template foundBC_as(); // I have the same code snippet at other places, keep in sync. + if (!tc.fRunNumber.EqualTo(Form("%d", bc.runNumber()))) { + LOGF(error, "\033[1;33m%s Run number changed within process(). This most likely indicates that a given masterjob is processing 2 or more different runs in one go.\033[0m", __FUNCTION__); + LOGF(fatal, "tc.fRunNumber = %s, bc.runNumber() = %d", tc.fRunNumber.Data(), bc.runNumber()); + } + + // **) Check SoR, EoR, and run duration: + auto runDuration = ccdb->getRunDuration(bc.runNumber()); // this is total run duration, not the current one (see below) + int64_t startOfRun = std::floor(runDuration.first * 0.001); // in seconds since Unix epoch + int64_t endOfRun = std::ceil(runDuration.second * 0.001); // in seconds since Unix epoch + int64_t durationInSec = endOfRun - startOfRun; // yes, this is now run duration in seconds + + // **) Insanity check on SoR: + if (!(tc.fRunTime[eStartOfRun] == startOfRun)) { + LOGF(error, "\033[1;33m%s tc.fRunTime[eStartOfRun] changed within process(). This most likely indicates that a given masterjob is processing 2 or more different runs in one go.\033[0m", __FUNCTION__); + LOGF(fatal, "tc.fRunTime[eStartOfRun] = %d, startOfRun = %d", tc.fRunTime[eStartOfRun], startOfRun); + } + + // **) Insanity check on EoR: + if (!(tc.fRunTime[eEndOfRun] == endOfRun)) { + LOGF(error, "\033[1;33m%s tc.fRunTime[eEndOfRun] changed within process(). This most likely indicates that a given masterjob is processing 2 or more different runs in one go.\033[0m", __FUNCTION__); + LOGF(fatal, "tc.fRunTime[eEndOfRun] = %d, endOfRun = %d", tc.fRunTime[eEndOfRun], endOfRun); + } + + // **) Insanity check on run duration: + if (!(tc.fRunTime[eDurationInSec] == durationInSec)) { + LOGF(error, "\033[1;33m%s tc.fRunTime[eDurationInSec] changed within process(). This most likely indicates that a given masterjob is processing 2 or more different runs in one go.\033[0m", __FUNCTION__); + LOGF(fatal, "tc.fRunTime[eDurationInSec] = %d, durationInSec = %d", tc.fRunTime[eDurationInSec], durationInSec); + } + + } else if constexpr (rs == eTest) { + LOGF(warning, "\033[1;33m%s at line %d : RunNumber cannot be checked in eTest mode, due to minimal subscription. Simply skipping this check. If you do not like this, extend subscription to more tables.\033[0m", __FUNCTION__, __LINE__); + } else { + // b) The rest: + + if (!tc.fRunNumber.EqualTo(Form("%d", collision.bc().runNumber()))) { + LOGF(error, "\033[1;33m%s Run number changed within process(). This most likely indicates that a given masterjob is processing 2 or more different runs in one go.\033[0m", __FUNCTION__); + LOGF(fatal, "tc.fRunNumber = %s, collision.bc().runNumber() = %d", tc.fRunNumber.Data(), collision.bc().runNumber()); + } + + } // to else + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // template void CheckCurrentRunNumber(T1 const& collision, T2 const&) + +//============================================================ + +void ResetEventByEventQuantities() +{ + // Reset all global event-by-event quantities here: + + // a) Event-by-event quantities; + // b) Q-vectors; + // c) Reset ebe containers for nested loops; + // d) Fisher-Yates algorithm; + // e) QA. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Event-by-event quantities: + ebye.fSelectedTracks = 0; + ebye.fMultiplicity = 0.; + ebye.fReferenceMultiplicity = 0.; + ebye.fCentrality = 0.; + ebye.fOccupancy = 0.; + ebye.fInteractionRate = 0.; + ebye.fCurrentRunDuration = 0.; + ebye.fVz = 0.; + ebye.fFT0CAmplitudeOnFoundBC = 0.; + + // b) Q-vectors: + if (qv.fCalculateQvectors) { + + // b0) generic Q-vector: + ResetQ(); + // b1) integrated Q-vector: + for (int h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { + for (int wp = 0; wp < gMaxCorrelator + 1; wp++) // weight power + { + qv.fQvector[h][wp] = TComplex(0., 0.); + } + } + + // b2) diff. Q-vector: + for (int bin = 1; bin <= gMaxNoBinsKine; bin++) { + qv.fqVectorEntries[PTq][bin - 1] = 0; // TBI 20240214 shall I loop also over enum's PTq and ETAq? If yes, fix it also below for qv.fqvector[PTq][bin - 1][... + qv.fqVectorEntries[ETAq][bin - 1] = 0; + for (int h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { + for (int wp = 0; wp < gMaxCorrelator + 1; wp++) { // weight power + qv.fqvector[PTq][bin - 1][h][wp] = TComplex(0., 0.); + qv.fqvector[ETAq][bin - 1][h][wp] = TComplex(0., 0.); + } // for (int wp = 0; wp < gMaxCorrelator + 1; wp++) { // weight power + } // for (int h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { + } // for (int b = 0; b < gMaxNoBinsKine; b++ ) { + } // if(qv.fCalculateQvectors) + + // b3) integrated Q-vector needed for calculations with eta separations: + if (es.fCalculateEtaSeparations) { + for (int ab = 0; ab < 2; ab++) { // ab = 0 <=> -eta , ab = 1 <=> + eta + for (int h = 0; h < gMaxHarmonic; h++) { + if (es.fEtaSeparationsSkipHarmonics[h]) { + continue; + } + for (int e = 0; e < gMaxNumberEtaSeparations; e++) { // eta separation + qv.fQabVector[ab][h][e] = TComplex(0., 0.); + } + } + } + for (int ab = 0; ab < 2; ab++) { // ab = 0 <=> -eta , ab = 1 <=> + eta + for (int e = 0; e < gMaxNumberEtaSeparations; e++) { // eta separation + qv.fMab[ab][e] = 0.; + } + } + } + + // b4) diff. q-vector in pt needed for calculations with eta separations: + if (es.fCalculateEtaSeparationsAsFunctionOf[AFO_PT]) { // yes, for the time being, only as a function of pt makes sense if eta separation is used + for (int ab = 0; ab < 2; ab++) { // ab = 0 <=> -eta , ab = 1 <=> + eta + for (int bin = 1; bin <= gMaxNoBinsKine; bin++) { + for (int h = 0; h < gMaxHarmonic; h++) { + if (es.fEtaSeparationsSkipHarmonics[h]) { + continue; + } + for (int e = 0; e < gMaxNumberEtaSeparations; e++) { + qv.fqabVector[ab][bin - 1][h][e] = TComplex(0., 0.); // yes, bin - 1 here + } + } + } + } + + for (int ab = 0; ab < 2; ab++) { // ab = 0 <=> -eta , ab = 1 <=> + eta + for (int bin = 1; bin <= gMaxNoBinsKine; bin++) { + for (int e = 0; e < gMaxNumberEtaSeparations; e++) { + qv.fmab[ab][bin - 1][e] = 0.; // yes, bin - 1 here + } + } + } + } + + // c) Reset ebe containers for nested loops: + if (nl.fCalculateNestedLoops || nl.fCalculateCustomNestedLoops) { + if (nl.ftaNestedLoops[0]) { + nl.ftaNestedLoops[0]->Reset(); + } + if (nl.ftaNestedLoops[1]) { + nl.ftaNestedLoops[1]->Reset(); + } + + } // if(nl.fCalculateNestedLoops || nl.fCalculateCustomNestedLoops) + + if (nl.fCalculateKineCustomNestedLoops) { + for (int b = 0; b < res.fResultsPro[AFO_PT]->GetNbinsX(); b++) { + nl.ftaNestedLoopsKine[PTq][b][0]->Reset(); + nl.ftaNestedLoopsKine[PTq][b][1]->Reset(); + } + for (int b = 0; b < res.fResultsPro[AFO_ETA]->GetNbinsX(); b++) { + nl.ftaNestedLoopsKine[ETAq][b][0]->Reset(); + nl.ftaNestedLoopsKine[ETAq][b][1]->Reset(); + } + } // if(nl.fCalculateKineCustomNestedLoops) { + + // d) Fisher-Yates algorithm: + if (tc.fUseFisherYates) { + delete tc.fRandomIndices; + tc.fRandomIndices = NULL; + } + + // e) QA: + for (int rs = 0; rs < 2; rs++) // reco/sim + { + for (int ba = 0; ba < 2; ba++) // before/after cuts + { + if (qa.fQAParticleEventProEbyE[rs][ba]) { + qa.fQAParticleEventProEbyE[rs][ba]->Reset(); + } + } + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void ResetEventByEventQuantities() + +//============================================================ + +template +void EventCutsCounters(T1 const& collision, T2 const& tracks) +{ + // Use this function to fill absolute and sequential event cut counters. Use only during QA, as this is computationally heavy. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // *) Establish ordering of binning in event cut counters histograms, which resembles ordering of event cuts implementation: + if (!ec.fEventCutCounterBinLabelingIsDone) { + ec.fEventCutCounterBinNumber[eRec] = 1; // remember that I cannot use 'rs' here as an index, because the enum eRecSim covers separately Run 1 and Run 2, etc. + ec.fEventCutCounterBinNumber[eSim] = 1; + EventCuts(collision, tracks, eCutCounterBinning); // dry call, to establish the map fEventCutCounterMap and its inverse + + // **) Special treatment for event cuts implemented outside of EventCuts(), like eMultiplicity: + // Algorithm: I simply add eMultiplicity at the end of what was esatablished by now in the above call EventCuts(collision, tracks, eCutCounterBinning) + // unless proven it shall be done some other way. + if (ec.fEventCutCounterMap[eRec]) { // TBI 20240414 also here have to hardcode 'eRec', because 'rs' spans over all enums in eRecSim => I definitely need 'generic Rec' case, perhaps via TExMap ? + // But I have already tc.fProcess[eGenericRec] and tc.fProcess[eGenericRecSim], available, shall I simply re-use them? + ec.fEventCutCounterMap[eRec]->Add(ec.fEventCutCounterBinNumber[eRec], eMultiplicity); + ec.fEventCutCounterMapInverse[eRec]->Add(eMultiplicity, ec.fEventCutCounterBinNumber[eRec]); + ec.fEventCutCounterBinNumber[eRec]++; // yes + } + if (ec.fEventCutCounterMap[eSim]) { // TBI 20240414 also here have to hardcode 'eSim', because 'rs' spans over all enums in eRecSim => I definitely need 'generic Rec' case, perhaps via TExMap ? + // But I have already tc.fProcess[eGenericRec] and tc.fProcess[eGenericRecSim], available, shall I simply re-use them? + ec.fEventCutCounterMap[eSim]->Add(ec.fEventCutCounterBinNumber[eSim], eMultiplicity); + ec.fEventCutCounterMapInverse[eSim]->Add(eMultiplicity, ec.fEventCutCounterBinNumber[eSim]); + ec.fEventCutCounterBinNumber[eSim]++; // yes + } + + // **) Map this ordering into bin labels of actual histograms for event cut counters: + for (int rec_sim = 0; rec_sim < 2; rec_sim++) // reco/sim => I use here exceptionally different var 'rec_sim', not the shadow 'rs' in the template parameter + { + for (int cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter + { + if (!ec.fEventCutCounterHist[rec_sim][cc]) { + continue; + } + for (int bin = 1; bin < ec.fEventCutCounterBinNumber[rec_sim]; bin++) // implemented and used cuts in this analysis + { + ec.fEventCutCounterHist[rec_sim][cc]->GetXaxis()->SetBinLabel(bin, FancyFormatting(ec.fEventCutName[ec.fEventCutCounterMap[rec_sim]->GetValue(bin)].Data())); + } + for (int bin = ec.fEventCutCounterBinNumber[rec_sim]; bin <= eEventCuts_N; bin++) // implemented, but unused cuts in this analysis + { + ec.fEventCutCounterHist[rec_sim][cc]->GetXaxis()->SetBinLabel(bin, Form("binNo = %d (unused cut)", bin)); + // Remark: I have to write here something concrete as a bin label, if I leave "TBI" for all bin labels here for cuts which were not used, + // I get this harmless but annoying warning during merging: + // Warning in : Histogram fEventCutCounterHist[rec][seq] has duplicate labels in the x axis. Bin contents will be merged in a single bin + // TBI 20241130 as a better solution, I shall re-define this histogram with the narower range on x-axis... + } + // All cuts which were implemeted, but not used I simply do not show (i can always UnZoom x-axis in TBrowser, if I want to see 'em): + ec.fEventCutCounterHist[rec_sim][cc]->GetXaxis()->SetRangeUser(ec.fEventCutCounterHist[rec_sim][cc]->GetBinLowEdge(1), ec.fEventCutCounterHist[rec_sim][cc]->GetBinLowEdge(ec.fEventCutCounterBinNumber[rec_sim])); + } + } + + ec.fEventCutCounterBinLabelingIsDone = true; // this flag ensures that this specific binning is performed only once, for the first processed event + // delete ec.fEventCutCounterMap[eRec]; // TBI 20240508 if i do not need them later, I could delete here + // delete ec.fEventCutCounterMap[eSim]; + // delete ec.fEventCutCounterMapInverse[eRec]; + // delete ec.fEventCutCounterMapInverse[eSim]; + } // if (!ec.fEventCutCounterBinLabelingIsDone) { + + // *) Event cut counter (absolute): + if (ec.fUseEventCutCounterAbsolute) { + ec.fEventCutCounterBinNumber[eRec] = 1; + ec.fEventCutCounterBinNumber[eSim] = 1; + EventCuts(collision, tracks, eCutCounterAbsolute); + + // **) Special treatments: + // a) eMultiplicity: It doesn't make sense to treat this one in eCutCounterAbsolute + } + + // *) Event cut counter (sequential): + if (ec.fUseEventCutCounterSequential) { + ec.fEventCutCounterBinNumber[eRec] = 1; + ec.fEventCutCounterBinNumber[eSim] = 1; + EventCuts(collision, tracks, eCutCounterSequential); + + // **) Special treatments: + // a) eMultiplicity: Since cut on eMultiplicity is implenented outside of EventCuts + // I call EventCut(rs, eMultiplicity, eCutCounterSequential) directly where its implemented. + // Add same treatment for other special cases, but do not forget above to expand **) Special treatment for event cuts ... + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // template void EventCutsCounters(T1 const& collision, T2 const& tracks, eCutModus cutModus) + +//============================================================ + +template +bool EventCuts(T1 const& collision, T2 const& tracks, eCutModus cutModus) +{ + // Event cuts on reconstructed and simulated data. Supports event cut counters, both absolute and sequential. + // There is also a related enum eEventCuts. + // Remark: I have added to all if statemets below which deals with floats, e.g. TMath::Abs(ebye.fCentrality - ec.fdEventCuts[eCentrality][eMax]) < tc.fFloatingPointPrecision , + // to enforce the ROOT convention: "lower boundary included, upper boundary excluded" + + // a) Event cuts on reconstructed, and corresponding MC truth simulated (common to Run 3, Run 2 and Run 1); + // b) Event cuts only on simulated (common to Run 3, Run 2 and Run 1); + // c) Event cuts on reconstructed, and corresponding MC truth simulated (Run 3 specific); + // d) Event cuts on simulated (Run 3 specific); + // e) Event cuts on reconstructed, and corresponding MC truth simulated (Run 1 and 2 specific); // In case there is some corner case between Run 1 and Run 2, simply branch further this one + // f) Event cuts on simulated (Run 1 and 2 specific); // In case there is some corner case between Run 1 and Run 2, simply branch further this one + // *) Event cuts for Test case. + + // 44:EventCuts + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Event cuts on reconstructed, and corresponding MC truth simulated (common to Run 3, Run 2 and Run 1) ... + if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1 || rs == eQA) { + + // *) NumberOfEvents: => this event cut is implemented directly in Steer(...) + + // *) SelectedEvents: => this event cut is implemented directly in Steer(...) + + // *) Offline trigger: + // Remark from documentation: Bypass this check if you analyse MC or continuous Run3 data. + // Documentation: + // a) O2Physics/Common/CCDB/TriggerAliases.h => available trigger aliases + // b) O2Physics/Common/CCDB/macros/upload_trigger_aliases.C => definitions of each trigger alias + // In addition: remember that I can use it only for process cases where I have joined aod::Collisions with aod::EvSels + // TBI 20240517 I didn't validate this trigger on Run 1, in fact, I have added protection against its usage in InsanityChecks. + if (ec.fUseEventCuts[eTrigger]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eTrigger, eCutCounterBinning); + } else if (ec.fsEventCuts[eTrigger].EqualTo("kINT7") && !collision.alias_bit(kINT7)) { // Validated only for Run 2 + if (!EventCut(eRec, eTrigger, cutModus)) { + return false; + } + } else if (ec.fsEventCuts[eTrigger].EqualTo("kTVXinTRD") && !collision.alias_bit(kTVXinTRD)) { // Validated only for Run 3 + if (!EventCut(eRec, eTrigger, cutModus)) { + return false; + } + } + // ... + } + + // collision.alias_bit(kTVXinTRD); + + // *) Sel8: // see definition in Common/TableProducer/eventSelection.cxx + if (ec.fUseEventCuts[eSel8]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eSel8, eCutCounterBinning); + } else if (!collision.sel8()) { + if (!EventCut(eRec, eSel8, cutModus)) { + return false; + } + } + } + + // *) TotalMultiplicity: + if (ec.fUseEventCuts[eTotalMultiplicity]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eTotalMultiplicity, eCutCounterBinning); + } else if (tracks.size() < ec.fdEventCuts[eTotalMultiplicity][eMin] || tracks.size() > ec.fdEventCuts[eTotalMultiplicity][eMax] || TMath::Abs(tracks.size() - ec.fdEventCuts[eTotalMultiplicity][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eRec, eTotalMultiplicity, cutModus)) { + return false; + } + } + } + + // *) Multiplicity: + // Remark: This cut is implemented directly in Steer(...), because I allow the possibility that ebye.fMultiplicity = ebye.fSelectedTracks . + // In fact, that will be true in most cases of practical interest. + + // *) Reference multiplicity: + // Remark: In this member function, reference multiplicity is just a number, and any specific setting for Run 3, 2, or 1 is already done in DetermineReferenceMultiplicity(...) + if (ec.fUseEventCuts[eReferenceMultiplicity]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eReferenceMultiplicity, eCutCounterBinning); + } else if (ebye.fReferenceMultiplicity < ec.fdEventCuts[eReferenceMultiplicity][eMin] || ebye.fReferenceMultiplicity > ec.fdEventCuts[eReferenceMultiplicity][eMax] || TMath::Abs(ebye.fReferenceMultiplicity - ec.fdEventCuts[eReferenceMultiplicity][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eRec, eReferenceMultiplicity, cutModus)) { + return false; + } + } + } + + // *) Centrality: + // Remark: In this member function, centrality is just a number, and any specific setting for Run 3, 2, or 1 is already done in DetermineCentrality(...) + if (ec.fUseEventCuts[eCentrality]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eCentrality, eCutCounterBinning); + } else if (ebye.fCentrality < ec.fdEventCuts[eCentrality][eMin] || ebye.fCentrality > ec.fdEventCuts[eCentrality][eMax] || TMath::Abs(ebye.fCentrality - ec.fdEventCuts[eCentrality][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eRec, eCentrality, cutModus)) { + return false; + } + } + } + + // *) VertexX: + if (ec.fUseEventCuts[eVertexX]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eVertexX, eCutCounterBinning); + } else if (collision.posX() < ec.fdEventCuts[eVertexX][eMin] || collision.posX() > ec.fdEventCuts[eVertexX][eMax] || TMath::Abs(collision.posX() - ec.fdEventCuts[eVertexX][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eRec, eVertexX, cutModus)) { + return false; + } + } + } + + // *) VertexY: + if (ec.fUseEventCuts[eVertexY]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eVertexY, eCutCounterBinning); + } else if (collision.posY() < ec.fdEventCuts[eVertexY][eMin] || collision.posY() > ec.fdEventCuts[eVertexY][eMax] || TMath::Abs(collision.posY() - ec.fdEventCuts[eVertexY][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eRec, eVertexY, cutModus)) { + return false; + } + } + } + + // *) VertexZ: + if (ec.fUseEventCuts[eVertexZ]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eVertexZ, eCutCounterBinning); + } else if (collision.posZ() < ec.fdEventCuts[eVertexZ][eMin] || collision.posZ() > ec.fdEventCuts[eVertexZ][eMax] || TMath::Abs(collision.posZ() - ec.fdEventCuts[eVertexZ][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eRec, eVertexZ, cutModus)) { + return false; + } + } + } + + // *) MinVertexDistanceFromIP (minimal vertex distance from nominal Interaction Point). If vertex is closer that this value, this event is rejected: + if (ec.fUseEventCuts[eMinVertexDistanceFromIP]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eMinVertexDistanceFromIP, eCutCounterBinning); + } else if (sqrt(pow(collision.posX(), 2.) + pow(collision.posY(), 2.) + pow(collision.posZ(), 2.)) < ec.fdEventCuts[eMinVertexDistanceFromIP][eMin]) { + if (!EventCut(eRec, eMinVertexDistanceFromIP, cutModus)) { + return false; + } + } + } + + // *) NContributors: + if (ec.fUseEventCuts[eNContributors]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eNContributors, eCutCounterBinning); + } else if (collision.numContrib() < ec.fdEventCuts[eNContributors][eMin] || collision.numContrib() > ec.fdEventCuts[eNContributors][eMax] || TMath::Abs(collision.numContrib() - ec.fdEventCuts[eNContributors][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eRec, eNContributors, cutModus)) { + return false; + } + } + } + + // *) RefMultVsNContrUp: + if (ec.fUseEventCuts[eRefMultVsNContrUp]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eRefMultVsNContrUp, eCutCounterBinning); + } else if (collision.numContrib() > ec.fEventCutsFormulas[eRefMultVsNContrUp_Formula]->Eval(ebye.fReferenceMultiplicity)) { + if (!EventCut(eRec, eRefMultVsNContrUp, cutModus)) { + return false; + } + } + } + + // *) RefMultVsNContrLow: + if (ec.fUseEventCuts[eRefMultVsNContrLow]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eRefMultVsNContrLow, eCutCounterBinning); + } else if (collision.numContrib() < ec.fEventCutsFormulas[eRefMultVsNContrLow_Formula]->Eval(ebye.fReferenceMultiplicity)) { + if (!EventCut(eRec, eRefMultVsNContrLow, cutModus)) { + return false; + } + } + } + + // *) CentralityCorrelationsCut: + if (ec.fUseEventCuts[eCentralityCorrelationsCut]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eCentralityCorrelationsCut, eCutCounterBinning); + } else if (!CentralityCorrelationCut()) { + if (!EventCut(eRec, eCentralityCorrelationsCut, cutModus)) { + return false; + } + } + } + + // ... + + // ... and corresponding MC truth simulated: + // See https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx + // See https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + if (!collision.has_mcCollision()) { + LOGF(warning, "No MC collision for this collision, skip..."); // TBI 20231106 re-think. I shouldn't probably get to this point, if MC truth info doesn't exist for this collision + return false; + } + + // In this branch I can cut additionally and directly on corresponding MC truth simulated, e.g. on collision.mcCollision().posZ(). + // In case I implement something here, remember to switch from eRec to eSim when calling e.g. EventCut(...) + + // ... + + } // if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + + } // if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { + + // ------------------------------------------------------------------------- + + // b) Event cuts only on simulated (common to Run 3, Run 2 and Run 1): + // Remark #1: This branch is relevant when processing ONLY simulated data at generator level. + // Remark #2: In this branch 'collision' is always o2::aod::McCollision, see https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { + + // *) NumberOfEvents: => this event cut is implemented directly in Steer(...) + + // *) Impact parameter: + if (ec.fUseEventCuts[eImpactParameter]) { + if (cutModus == eCutCounterBinning) { + EventCut(eSim, eImpactParameter, eCutCounterBinning); + } else if (collision.impactParameter() < ec.fdEventCuts[eImpactParameter][eMin] || collision.impactParameter() > ec.fdEventCuts[eImpactParameter][eMax] || TMath::Abs(collision.impactParameter() - ec.fdEventCuts[eImpactParameter][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eSim, eImpactParameter, cutModus)) { + return false; + } + } + } + + // *) Event plane angle: + if (ec.fUseEventCuts[eEventPlaneAngle]) { + if (cutModus == eCutCounterBinning) { + EventCut(eSim, eEventPlaneAngle, eCutCounterBinning); + } else if (collision.eventPlaneAngle() < ec.fdEventCuts[eEventPlaneAngle][eMin] || collision.eventPlaneAngle() > ec.fdEventCuts[eEventPlaneAngle][eMax] || TMath::Abs(collision.eventPlaneAngle() - ec.fdEventCuts[eEventPlaneAngle][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eSim, eEventPlaneAngle, cutModus)) { + return false; + } + } + } + + // *) TotalMultiplicity: + // TBI 20240509 check what is the Monte Carlo analogy for tracks.size() + + // *) Multiplicity: + // Remark: This cut is implemented directly in Steer(...) TBI 20240508 check how to implement this one with the current re-write + + // *) Centrality: this is related to eImpactParameter. TBI 20240509 How do I proceed here? Shall i calculate it in void DetermineCentrality( ... ), from IP, and store it in ebye.fCentrality? + + // *) VertexX: + if (ec.fUseEventCuts[eVertexX]) { + if (cutModus == eCutCounterBinning) { + EventCut(eSim, eVertexX, eCutCounterBinning); + } else if (collision.posX() < ec.fdEventCuts[eVertexX][eMin] || collision.posX() > ec.fdEventCuts[eVertexX][eMax] || TMath::Abs(collision.posX() - ec.fdEventCuts[eVertexX][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eSim, eVertexX, cutModus)) { + return false; + } + } + } + + // *) VertexY: + if (ec.fUseEventCuts[eVertexY]) { + if (cutModus == eCutCounterBinning) { + EventCut(eSim, eVertexY, eCutCounterBinning); + } else if (collision.posY() < ec.fdEventCuts[eVertexY][eMin] || collision.posY() > ec.fdEventCuts[eVertexY][eMax] || TMath::Abs(collision.posY() - ec.fdEventCuts[eVertexY][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eSim, eVertexY, cutModus)) { + return false; + } + } + } + + // *) VertexZ: + if (ec.fUseEventCuts[eVertexZ]) { + if (cutModus == eCutCounterBinning) { + EventCut(eSim, eVertexZ, eCutCounterBinning); + } else if (collision.posZ() < ec.fdEventCuts[eVertexZ][eMin] || collision.posZ() > ec.fdEventCuts[eVertexZ][eMax] || TMath::Abs(collision.posZ() - ec.fdEventCuts[eVertexZ][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eSim, eVertexZ, cutModus)) { + return false; + } + } + } + + // *) MinVertexDistanceFromIP (minimal vertex distance from nominal Interaction Point). If vertex is closer that this value, this event is rejected: + if (ec.fUseEventCuts[eMinVertexDistanceFromIP]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eMinVertexDistanceFromIP, eCutCounterBinning); + } else if (sqrt(pow(collision.posX(), 2.) + pow(collision.posY(), 2.) + pow(collision.posZ(), 2.)) < ec.fdEventCuts[eMinVertexDistanceFromIP][eMin]) { + if (!EventCut(eRec, eMinVertexDistanceFromIP, cutModus)) { + return false; + } + } + } + + // *) Sel8: TBI 20240509 + + // *) SelectedEvents: => this event cut is implemented directly in Steer(...) + + // ... + + } // if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { + + // ------------------------------------------------------------------------- + + // c) Event cuts on reconstructed, and corresponding MC truth simulated (Run 3 specific): + // Remark: I implement here only the event cuts which are not already in group a) above, and which make sense only for Run 3 data. + if constexpr (rs == eRec || rs == eRecAndSim || rs == eQA) { + + // For Run 3 multiplicities, I subscribe to o2::aod::Mults + // See how it is defined as Joined table at https://aliceo2group.github.io/analysis-framework/docs/datamodel/helperTaskTables.html#o2-analysis-multiplicity-table + // Therefore, I need always a header Common/DataModel/Multiplicity.h and o2-analysis-multiplicity-table in the workflow + // TBI 20240509 check also o2::aod::MultExtra + + // *) Occupancy: + if (ec.fUseEventCuts[eOccupancy]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eOccupancy, eCutCounterBinning); + } else if (ebye.fOccupancy < ec.fdEventCuts[eOccupancy][eMin] || ebye.fOccupancy > ec.fdEventCuts[eOccupancy][eMax] || TMath::Abs(ebye.fOccupancy - ec.fdEventCuts[eOccupancy][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eRec, eOccupancy, cutModus)) { + return false; + } + } + } + + // *) InteractionRate: + if (ec.fUseEventCuts[eInteractionRate]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eInteractionRate, eCutCounterBinning); + } else if (ebye.fInteractionRate < ec.fdEventCuts[eInteractionRate][eMin] || ebye.fInteractionRate > ec.fdEventCuts[eInteractionRate][eMax] || TMath::Abs(ebye.fInteractionRate - ec.fdEventCuts[eInteractionRate][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eRec, eInteractionRate, cutModus)) { + return false; + } + } + } + + // *) CurrentRunDuration: // TBI 20241128 check if I can use this one also on Run 2 and Run 1, most likely not + if (ec.fUseEventCuts[eCurrentRunDuration]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eCurrentRunDuration, eCutCounterBinning); + } else if (ebye.fCurrentRunDuration < ec.fdEventCuts[eCurrentRunDuration][eMin] || ebye.fCurrentRunDuration > ec.fdEventCuts[eCurrentRunDuration][eMax] || TMath::Abs(ebye.fCurrentRunDuration - ec.fdEventCuts[eCurrentRunDuration][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eRec, eCurrentRunDuration, cutModus)) { + return false; + } + } + } + + // *) NoSameBunchPileup: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eNoSameBunchPileup]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eNoSameBunchPileup, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + if (!EventCut(eRec, eNoSameBunchPileup, cutModus)) { + return false; + } + } + } + + // *) IsGoodZvtxFT0vsPV: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eIsGoodZvtxFT0vsPV]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eIsGoodZvtxFT0vsPV, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + if (!EventCut(eRec, eIsGoodZvtxFT0vsPV, cutModus)) { + return false; + } + } + } + + // *) IsVertexITSTPC: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eIsVertexITSTPC]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eIsVertexITSTPC, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + if (!EventCut(eRec, eIsVertexITSTPC, cutModus)) { + return false; + } + } + } + + // *) IsVertexTOFmatched: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eIsVertexTOFmatched]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eIsVertexTOFmatched, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + if (!EventCut(eRec, eIsVertexTOFmatched, cutModus)) { + return false; + } + } + } + + // *) IsVertexTRDmatched: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eIsVertexTRDmatched]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eIsVertexTRDmatched, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + if (!EventCut(eRec, eIsVertexTRDmatched, cutModus)) { + return false; + } + } + } + + // *) NoCollInTimeRangeStrict: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eNoCollInTimeRangeStrict]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eNoCollInTimeRangeStrict, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + if (!EventCut(eRec, eNoCollInTimeRangeStrict, cutModus)) { + return false; + } + } + } + + // *) NoCollInTimeRangeStandard: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eNoCollInTimeRangeStandard]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eNoCollInTimeRangeStandard, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + if (!EventCut(eRec, eNoCollInTimeRangeStandard, cutModus)) { + return false; + } + } + } + + // *) NoCollInRofStrict: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eNoCollInRofStrict]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eNoCollInRofStrict, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + if (!EventCut(eRec, eNoCollInRofStrict, cutModus)) { + return false; + } + } + } + + // *) NoCollInRofStandard: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eNoCollInRofStandard]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eNoCollInRofStandard, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + if (!EventCut(eRec, eNoCollInRofStandard, cutModus)) { + return false; + } + } + } + + // *) NoHighMultCollInPrevRof: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eNoHighMultCollInPrevRof]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eNoHighMultCollInPrevRof, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + if (!EventCut(eRec, eNoHighMultCollInPrevRof, cutModus)) { + return false; + } + } + } + + // *) IsGoodITSLayer3: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eIsGoodITSLayer3]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eIsGoodITSLayer3, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer3)) { + if (!EventCut(eRec, eIsGoodITSLayer3, cutModus)) { + return false; + } + } + } + + // *) IsGoodITSLayer0123: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eIsGoodITSLayer0123]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eIsGoodITSLayer0123, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)) { + if (!EventCut(eRec, eIsGoodITSLayer0123, cutModus)) { + return false; + } + } + } + + // *) IsGoodITSLayersAll: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eIsGoodITSLayersAll]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eIsGoodITSLayersAll, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + if (!EventCut(eRec, eIsGoodITSLayersAll, cutModus)) { + return false; + } + } + } + + // ... + + // *) Centrality weights (flattening): + // Remark 1: Since I am getting centrality weights from centrality distribution AFTER all the events cuts, flattening must be applied here after all other event cuts: + // Remark 2: Whatever I change here, change also in the corresponding branch for Run 2 and Run 1. + // Yes, I have to replicate for this special event cut the same code, since in each case it has to be applied at the very end. + if (ec.fUseEventCuts[eCentralityWeights]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eCentralityWeights, eCutCounterBinning); + } else if (gRandom->Uniform(0, 1) > CentralityWeight(ebye.fCentrality)) { // yes, since centralityWeight is normalized probability (see CentralityWeight(...)) + if (!EventCut(eRec, eCentralityWeights, cutModus)) { + return false; + } + } + } + + // Remark: If I need any further event cut, implement it BEFORE event cut "Centrality weights (flattening)", which must be implemented last. + + // ... and corresponding MC truth simulated (Run 3 specific): + // See https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx + // See https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + if constexpr (rs == eRecAndSim) { + if (!collision.has_mcCollision()) { + LOGF(warning, "No MC collision for this collision, skip..."); // TBI 20231106 re-think. I shouldn't probably get to this point, if MC truth info doesn't exist for this collision + return false; + } + + // In this branch I can cut additionally and directly on corresponding MC truth simulated. + // Remark: I implement here only the event cuts which are not already in group a) above, and which make sense only for Run 3 data. + // In case I implement something here, remember to switch from eRec to eSim when calling e.g. EventCut(...) + + // ... + + } // if constexpr (rs == eRecAndSim) { + + } // if constexpr (rs == eRec || rs == eRecAndSim) { + + // ------------------------------------------------------------------------- + + // d) Event cuts on simulated (Run 3 specific): + // Remark #1: I implement here only the event cuts which are not already in group b) above, and which make sense only for Run 3 data. + // Remark #2: In this branch 'collision' is always o2::aod::McCollision, see https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + // See how I handled the case b) above. + if constexpr (rs == eSim) { + + // ... + + } // if constexpr (rs == eSim) { + + // ------------------------------------------------------------------------- + + // e) Event cuts on reconstructed, and corresponding MC truth simulated (Run 1 and 2 specific): + // Remark: I implement here only the event cuts which are not already in group a) above, and which make sense only for Run 1 and 2 data. + if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { + + // *) Sel7: + if (ec.fUseEventCuts[eSel7]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eSel7, eCutCounterBinning); + } else if (!collision.sel7()) { + if (!EventCut(eRec, eSel7, cutModus)) { + return false; + } + } + } + + // *) NoPileupTPC: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eNoPileupTPC]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eNoPileupTPC, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kNoPileupTPC)) { + if (!EventCut(eRec, eNoPileupTPC, cutModus)) { + return false; + } + } + } + + // *) NoPileupFromSPD: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eNoPileupFromSPD]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eNoPileupFromSPD, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kNoPileupFromSPD)) { + if (!EventCut(eRec, eNoPileupFromSPD, cutModus)) { + return false; + } + } + } + + // *) NoSPDOnVsOfPileup: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eNoSPDOnVsOfPileup]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eNoSPDOnVsOfPileup, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kNoSPDOnVsOfPileup)) { + if (!EventCut(eRec, eNoSPDOnVsOfPileup, cutModus)) { + return false; + } + } + } + + // ... + + // *) Centrality weights (flattening): + // Remark 1: Since I am getting centrality weights from centrality distribution AFTER all the events cuts, flattening must be applied here after all other event cuts: + // Remark 2: Whatever I change here, change also in the corresponding branch for Run 3. + // Yes, I have to replicate for this special event cut the same code, since in each case it has to be applied at the very end. + if (ec.fUseEventCuts[eCentralityWeights]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eCentralityWeights, eCutCounterBinning); + } else if (gRandom->Uniform(0, 1) > CentralityWeight(ebye.fCentrality)) { // yes, since centralityWeight is normalized probability (see CentralityWeight(...)) + if (!EventCut(eRec, eCentralityWeights, cutModus)) { + return false; + } + } + } + + // Remark: If I need any further event cut, implement it BEFORE event cut "Centrality weights (flattening)", which must be implemented last. + + // ... and corresponding MC truth simulated: + // See https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx + // See https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + if constexpr (rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + if (!collision.has_mcCollision()) { + LOGF(warning, "No MC collision for this collision, skip..."); // TBI 20231106 re-think. I shouldn't probably get to this point, if MC truth info doesn't exist for this collision + return false; + } + + // In this branch I can cut additionally and directly on corresponding MC truth simulated. + // Remark: I implement here only the event cuts which are not already in group a) above, and which make sense only for Run 1 and 2 data. + // In case I implement something here, remember to switch from eRec to eSim when calling e.g. EventCut(...) + + // ... + + } // if constexpr (rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + + } // if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { + + // ------------------------------------------------------------------------- + + // f) Event cuts on simulated (Run 1 and 2 specific) + // Remark #1: I implement here only the event cuts which are not already in group b) above, and which make sense only for Run 1 and 2 data. + // Remark #2: In this branch 'collision' is always o2::aod::McCollision, see https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + // See how I handled the case b) above. + if constexpr (rs == eSim_Run2 || rs == eSim_Run1) { + + // ... + + } // if constexpr (rs == eSim_Run2 || rs == eSim_Run1) { + + // ------------------------------------------------------------------------- + + // *) Test case: + if constexpr (rs == eTest) { + // This branch corresponds to process with minimal subscription - I implement just a few example cuts, just for testing purposes. + // Only eRec is support in Test for the time being. + + // *) TotalMultiplicity: + if (ec.fUseEventCuts[eTotalMultiplicity]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eTotalMultiplicity, eCutCounterBinning); + } else if (tracks.size() < ec.fdEventCuts[eTotalMultiplicity][eMin] || tracks.size() > ec.fdEventCuts[eTotalMultiplicity][eMax] || TMath::Abs(tracks.size() - ec.fdEventCuts[eTotalMultiplicity][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eRec, eTotalMultiplicity, cutModus)) { + return false; + } + } + } + + // *) VertexZ: + if (ec.fUseEventCuts[eVertexZ]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eVertexZ, eCutCounterBinning); + } else if (collision.posZ() < ec.fdEventCuts[eVertexZ][eMin] || collision.posZ() > ec.fdEventCuts[eVertexZ][eMax] || TMath::Abs(collision.posZ() - ec.fdEventCuts[eVertexZ][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eRec, eVertexZ, cutModus)) { + return false; + } + } + } + + // *) Centrality: + if (ec.fUseEventCuts[eCentrality]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eCentrality, eCutCounterBinning); + } else if (ebye.fCentrality < ec.fdEventCuts[eCentrality][eMin] || ebye.fCentrality > ec.fdEventCuts[eCentrality][eMax] || TMath::Abs(ebye.fCentrality - ec.fdEventCuts[eCentrality][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eRec, eCentrality, cutModus)) { + return false; + } + } + } + + // ... + + } // if constexpr (rs == eTest) { + + return true; + +} // template bool EventCuts(T1 const& collision, T2 const& tracks) + +//============================================================ + +bool EventCut(int rs, int eventCut, eCutModus cutModus) +{ + // Helper function to reduce code bloat in EventCuts(). It's meant to be used only in EventCuts(). + // It can be used also in exceptional cases outside of EventCuts(), like for eMultiplicity, but use with care. + // For instance, I can call EventCut(eRec, eCentrality, eCutCounterSequential) directly, only if I have checked that + // fUseEventCutCounterSequential is true, etc. + + // Remark: Remember that as a second argument I cannot use enum eEventCuts, because here in one go I take both enum eEventCuts and enum eEventHistograms . + + // *) Insanity checks on arguments: + if (!(0 == rs || 1 == rs)) { + LOGF(fatal, "\033[1;31m%s at line %d : 'rs' must be generic Rec or Sim index, rs = %d \033[0m", __FUNCTION__, __LINE__, rs); + } + if (eventCut >= eEventCuts_N) { + LOGF(fatal, "\033[1;31m%s at line %d : eventCut >= eEventCuts_N, eventCut = %d , eEventCuts_N = %d \033[0m", __FUNCTION__, __LINE__, eventCut, static_cast(eEventCuts_N)); + } + + // *) Do the thing: + switch (cutModus) { + case eCut: { + if (tc.fVerboseEventCut) { + LOGF(info, "\033[1;31mEvent didn't survive the cut: %s\033[0m", ec.fEventCutName[eventCut].Data()); + } + return false; + break; + } + case eCutCounterBinning: { + ec.fEventCutCounterMap[rs]->Add(ec.fEventCutCounterBinNumber[rs], eventCut); + ec.fEventCutCounterMapInverse[rs]->Add(eventCut, ec.fEventCutCounterBinNumber[rs]); + ec.fEventCutCounterBinNumber[rs]++; // yes + return true; + break; + } + case eCutCounterAbsolute: { + ec.fEventCutCounterHist[rs][eAbsolute]->Fill(ec.fEventCutCounterMapInverse[rs]->GetValue(eventCut)); + return true; // yes, so that I can proceed with another cut in EventCuts + break; + } + case eCutCounterSequential: { + ec.fEventCutCounterHist[rs][eSequential]->Fill(ec.fEventCutCounterMapInverse[rs]->GetValue(eventCut)); + return false; // yes, so that I bail out from EventCuts + break; + } + default: { + LOGF(fatal, "\033[1;31m%s at line %d : This cutModus = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, static_cast(cutModus)); + break; + } + } // switch(cutModus) + + return false; // obsolete, but it suppresses the warning... + +} // bool EventCut(int rs, int eventCut, eCutModus cutModus) + +//============================================================ + +bool RemainingEventCuts() +{ + // Remaining event cuts which can be applied ONLY after the main loop over particles. + // For instance, cut on total number of selected particles (eMultiplicity). + // Remark #1: Whichever cut I implement here, update EventCutsCounters(...) for that cut (like I did for eMultiplicity, as a sort of template). + // Remark #2: I do not have here templated arguments like in EventCuts(), because I do not anticipate using any getter from the framework directly here. + // Remark #3: With the current implementation, I support here only eCutCounterSequential, i.e. eCutCounterAbsolute is not supported for cuts applied here. + + // a) Determine if this function was called for generic rec or generic sim: + // *) eMultiplicity; + // ... + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Determine if this function was called for generic rec or generic sim: + // Remark: I can do it in this simplified way, because I do not anticipate I will call here any getters from the framework. + int rs = -1; + if (tc.fProcess[eGenericRec] || tc.fProcess[eGenericRecSim]) { + rs = eRec; // yes, I do not count in RecSim mode separately particles and rec and sim level which survived particle cuts + } else if (tc.fProcess[eGenericSim]) { + rs = eSim; + } + + // *) Multiplicity: (see documentation for ebye.fMultiplicity for its definition) + if (ec.fUseEventCuts[eMultiplicity]) { + if (ebye.fMultiplicity < ec.fdEventCuts[eMultiplicity][eMin] || ebye.fMultiplicity > ec.fdEventCuts[eMultiplicity][eMax] || TMath::Abs(ebye.fMultiplicity - ec.fdEventCuts[eMultiplicity][eMax]) < tc.fFloatingPointPrecision) { + // Remark: I have to implement RemainingEventCuts() in a slightly different way as EventCuts() + EventCut(rs, eMultiplicity, eCut); // just a printout that this event didn't survive this cut + if (ec.fUseEventCutCounterSequential) { // yes, this is important. Otherwise fEventCutCounterHist can be used in EventCut(...), even though it's NULL + EventCut(rs, eMultiplicity, eCutCounterSequential); + } + return false; + } + } + + return true; + +} // bool RemainingEventCuts() + +//============================================================ + +template +void FillSubeventMultiplicities() +{ + // Fill subevent (defined via eta separation) multiplicities. + + // a) Fill reconstructed (common to Run 3, Run 2 and Run 1 + Test mode); + // b) Fill only simulated (common to Run 3, Run 2 and Run 1). + + // Remark: This function has to be called after Q-vectors are filled. It makes sense to fill these histograms only for "eAfter", + // becase Q-vectors are not filled before the event cuts. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Fill reconstructed (common to Run 3, Run 2 and Run 1 + Test mode): + if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1 || rs == eTest || rs == eQA) { + for (int ab = 0; ab < 2; ab++) { // ab = 0 <=> -eta , ab = 1 <=> + eta + for (int e = 0; e < gMaxNumberEtaSeparations; e++) { // eta separation + !qv.fMabDist[ab][eRec][eAfter][e] ? true : qv.fMabDist[ab][eRec][eAfter][e]->Fill(qv.fMab[ab][e]); + } + } + } + + // b) Fill only simulated (common to Run 3, Run 2 and Run 1): + if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { + for (int ab = 0; ab < 2; ab++) { // ab = 0 <=> -eta , ab = 1 <=> + eta + for (int e = 0; e < gMaxNumberEtaSeparations; e++) { // eta separation + !qv.fMabDist[ab][eSim][eAfter][e] ? true : qv.fMabDist[ab][eSim][eAfter][e]->Fill(qv.fMab[ab][e]); + } + } + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void FillSubeventMultiplicities() + +//============================================================ + +template +void FillEventHistograms(T1 const& collision, T2 const& tracks, eBeforeAfter ba) +{ + // Fill all event histograms for reconstructed or simulated data. QA event histograms are also filled here. + + // a) Fill reconstructed, and corresponding MC truth simulated (common to Run 3, Run 2 and Run 1); + // b) Fill only simulated (common to Run 3, Run 2 and Run 1); + // c) Fill reconstructed (Run 3 specific); + // d) Fill only simulated (Run 3 specific); + // e) Fill reconstructed (Run 1 and 2 specific); // In case there is some corner case between Run 1 and Run 2, simply branch further this one + // f) Fill only simulated (Run 1 and 2 specific); // In case there is some corner case between Run 1 and Run 2, simply branch further this one + // g) Test case. + + // Remark: in most cases, all histogram which depend on eMultiplicity are booked only for "after", because by default, Multiplicity = SelectedTracks. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Fill reconstructed ... (common to Run 3, Run 2 and Run 1): + if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1 || rs == eQA) { + if (eh.fFillEventHistograms) { + !eh.fEventHistograms[eNumberOfEvents][eRec][ba] ? true : eh.fEventHistograms[eNumberOfEvents][eRec][ba]->Fill(0.5); // basically, if histogram is not booked, do nothing. 'true' is a placeholder, for the time being + !eh.fEventHistograms[eVertexX][eRec][ba] ? true : eh.fEventHistograms[eVertexX][eRec][ba]->Fill(collision.posX()); + !eh.fEventHistograms[eVertexY][eRec][ba] ? true : eh.fEventHistograms[eVertexY][eRec][ba]->Fill(collision.posY()); + !eh.fEventHistograms[eVertexZ][eRec][ba] ? true : eh.fEventHistograms[eVertexZ][eRec][ba]->Fill(collision.posZ()); + !eh.fEventHistograms[eNContributors][eRec][ba] ? true : eh.fEventHistograms[eNContributors][eRec][ba]->Fill(collision.numContrib()); + !eh.fEventHistograms[eTotalMultiplicity][eRec][ba] ? true : eh.fEventHistograms[eTotalMultiplicity][eRec][ba]->Fill(tracks.size()); // TBI 20231106 check and validate further + !eh.fEventHistograms[eMultiplicity][eRec][ba] ? true : eh.fEventHistograms[eMultiplicity][eRec][ba]->Fill(ebye.fMultiplicity); + !eh.fEventHistograms[eReferenceMultiplicity][eRec][ba] ? true : eh.fEventHistograms[eReferenceMultiplicity][eRec][ba]->Fill(ebye.fReferenceMultiplicity); + !eh.fEventHistograms[eCentrality][eRec][ba] ? true : eh.fEventHistograms[eCentrality][eRec][ba]->Fill(ebye.fCentrality); + } + + // QA: + if (qa.fFillQAEventHistograms2D) { + !qa.fQAEventHistograms2D[eMultiplicity_vs_ReferenceMultiplicity][eRec][ba] ? true : qa.fQAEventHistograms2D[eMultiplicity_vs_ReferenceMultiplicity][eRec][ba]->Fill(ebye.fMultiplicity, ebye.fReferenceMultiplicity); + !qa.fQAEventHistograms2D[eMultiplicity_vs_NContributors][eRec][ba] ? true : qa.fQAEventHistograms2D[eMultiplicity_vs_NContributors][eRec][ba]->Fill(ebye.fMultiplicity, collision.numContrib()); + !qa.fQAEventHistograms2D[eMultiplicity_vs_Centrality][eRec][ba] ? true : qa.fQAEventHistograms2D[eMultiplicity_vs_Centrality][eRec][ba]->Fill(ebye.fMultiplicity, ebye.fCentrality); + !qa.fQAEventHistograms2D[eMultiplicity_vs_VertexZ][eRec][ba] ? true : qa.fQAEventHistograms2D[eMultiplicity_vs_VertexZ][eRec][ba]->Fill(ebye.fMultiplicity, collision.posZ()); + !qa.fQAEventHistograms2D[eReferenceMultiplicity_vs_NContributors][eRec][ba] ? true : qa.fQAEventHistograms2D[eReferenceMultiplicity_vs_NContributors][eRec][ba]->Fill(ebye.fReferenceMultiplicity, collision.numContrib()); + !qa.fQAEventHistograms2D[eReferenceMultiplicity_vs_Centrality][eRec][ba] ? true : qa.fQAEventHistograms2D[eReferenceMultiplicity_vs_Centrality][eRec][ba]->Fill(ebye.fReferenceMultiplicity, ebye.fCentrality); + !qa.fQAEventHistograms2D[eReferenceMultiplicity_vs_VertexZ][eRec][ba] ? true : qa.fQAEventHistograms2D[eReferenceMultiplicity_vs_VertexZ][eRec][ba]->Fill(ebye.fReferenceMultiplicity, collision.posZ()); + !qa.fQAEventHistograms2D[eNContributors_vs_Centrality][eRec][ba] ? true : qa.fQAEventHistograms2D[eNContributors_vs_Centrality][eRec][ba]->Fill(collision.numContrib(), ebye.fCentrality); + !qa.fQAEventHistograms2D[eNContributors_vs_VertexZ][eRec][ba] ? true : qa.fQAEventHistograms2D[eNContributors_vs_VertexZ][eRec][ba]->Fill(collision.numContrib(), collision.posZ()); + !qa.fQAEventHistograms2D[eCentrality_vs_VertexZ][eRec][ba] ? true : qa.fQAEventHistograms2D[eCentrality_vs_VertexZ][eRec][ba]->Fill(ebye.fCentrality, collision.posZ()); + } + + if (qa.fFillQACorrelationsVsHistograms2D && qa.fQAParticleEventProEbyE[eRec][ba] && ba == eAfter) { // fill only for eAfter, because I do not calculate Q-vectors before cuts + + // Calculate quickly 2-p correlation in harmonic h for this event: TBI 20250114 shall I add this also to some EbyE variable? There is no really much of a code bloat for the time being... + + // Flush 'n' fill the generic Q-vectors: + ResetQ(); + int lMaxCorrelator = 2; // used only here locally + for (int h = 0; h < gMaxHarmonic * lMaxCorrelator + 1; h++) { + for (int wp = 0; wp < lMaxCorrelator + 1; wp++) // weight power + { + qv.fQ[h][wp] = qv.fQvector[h][wp]; + } + } + + for (int h = 1; h <= gMaxHarmonic; h++) { + TComplex two = Two(h, -h); + double twoC = two.Re(); // cos + // double twoS = two.Im(); // sin + double wTwo = Two(0, 0).Re(); // Weight is 'number of combinations' by default TBI + // 20220809 add support for other weights + if (!(wTwo > 0.0)) { + LOGF(fatal, "In function \033[1;31m%s at line %d : wTwo = %f <=0. ebye.fSelectedTracks = %d.\nDid you forget to enable fCalculateQvectors = true?\033[0m", __FUNCTION__, __LINE__, wTwo, ebye.fSelectedTracks); + } + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_Multiplicity][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_Multiplicity][h - 1][eRec]->Fill(twoC / wTwo, ebye.fMultiplicity, wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_ReferenceMultiplicity][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_ReferenceMultiplicity][h - 1][eRec]->Fill(twoC / wTwo, ebye.fReferenceMultiplicity, wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_Centrality][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_Centrality][h - 1][eRec]->Fill(twoC / wTwo, ebye.fCentrality, wTwo); + // ..... + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeanPhi][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeanPhi][h - 1][eRec]->Fill(twoC / wTwo, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeanPhi), wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeanPt][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeanPt][h - 1][eRec]->Fill(twoC / wTwo, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeanPt), wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeanEta][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeanEta][h - 1][eRec]->Fill(twoC / wTwo, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeanEta), wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeanCharge][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeanCharge][h - 1][eRec]->Fill(twoC / wTwo, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeanCharge), wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcNClsFindable][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcNClsFindable][h - 1][eRec]->Fill(twoC / wTwo, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeantpcNClsFindable), wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcNClsShared][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcNClsShared][h - 1][eRec]->Fill(twoC / wTwo, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeantpcNClsShared), wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeanitsChi2NCl][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeanitsChi2NCl][h - 1][eRec]->Fill(twoC / wTwo, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeanitsChi2NCl), wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcNClsFound][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcNClsFound][h - 1][eRec]->Fill(twoC / wTwo, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeantpcNClsFound), wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcNClsCrossedRows][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcNClsCrossedRows][h - 1][eRec]->Fill(twoC / wTwo, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeantpcNClsCrossedRows), wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeanitsNCls][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeanitsNCls][h - 1][eRec]->Fill(twoC / wTwo, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeanitsNCls), wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeanitsNClsInnerBarrel][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeanitsNClsInnerBarrel][h - 1][eRec]->Fill(twoC / wTwo, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeanitsNClsInnerBarrel), wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcCrossedRowsOverFindableCls][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcCrossedRowsOverFindableCls][h - 1][eRec]->Fill(twoC / wTwo, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeantpcCrossedRowsOverFindableCls), wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcFoundOverFindableCls][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcFoundOverFindableCls][h - 1][eRec]->Fill(twoC / wTwo, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeantpcFoundOverFindableCls), wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcFractionSharedCls][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcFractionSharedCls][h - 1][eRec]->Fill(twoC / wTwo, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeantpcFractionSharedCls), wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcChi2NCl][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeantpcChi2NCl][h - 1][eRec]->Fill(twoC / wTwo, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeantpcChi2NCl), wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeandcaXY][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeandcaXY][h - 1][eRec]->Fill(twoC / wTwo, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeandcaXY), wTwo); + !qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeandcaZ][h - 1][eRec] ? true : qa.fQACorrelationsVsHistograms2D[eCorrelations_vs_MeandcaZ][h - 1][eRec]->Fill(twoC / wTwo, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeandcaZ), wTwo); + // ..... + } + + // Flush the generic Q-vectors: + ResetQ(); + + } // if (qa.fFillQACorrelationsVsHistograms2D && qa.fQAParticleEventProEbyE[eRec][ba] && ba == eAfter) + + // ... + + // ... and corresponding MC truth simulated (common to Run 3, Run 2 and Run 1) ( see https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx ): + if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + if (!collision.has_mcCollision()) { + LOGF(warning, "No MC collision for this collision, skip..."); + return; + } + if (eh.fFillEventHistograms) { + !eh.fEventHistograms[eNumberOfEvents][eSim][ba] ? true : eh.fEventHistograms[eNumberOfEvents][eSim][ba]->Fill(0.5); + !eh.fEventHistograms[eVertexX][eSim][ba] ? true : eh.fEventHistograms[eVertexX][eSim][ba]->Fill(collision.mcCollision().posX()); + !eh.fEventHistograms[eVertexY][eSim][ba] ? true : eh.fEventHistograms[eVertexY][eSim][ba]->Fill(collision.mcCollision().posY()); + !eh.fEventHistograms[eVertexZ][eSim][ba] ? true : eh.fEventHistograms[eVertexZ][eSim][ba]->Fill(collision.mcCollision().posZ()); + !eh.fEventHistograms[eImpactParameter][eSim][ba] ? true : eh.fEventHistograms[eImpactParameter][eSim][ba]->Fill(collision.mcCollision().impactParameter()); + !eh.fEventHistograms[eEventPlaneAngle][eSim][ba] ? true : eh.fEventHistograms[eEventPlaneAngle][eSim][ba]->Fill(collision.mcCollision().eventPlaneAngle()); + // eh.fEventHistograms[eTotalMultiplicity][eSim][ba]->Fill(tracks.size()); // TBI 20231106 check how to get corresponding MC truth info, and validate further + // eh.fEventHistograms[eMultiplicity][eSim][ba]->Fill(ebye.fMultiplicity); // TBI 20241123 re-think if I really need it here. If yes, most likely I will have to + // generalize fSelectedTracks to an array, to counter separately selected sim particles + // eh.fEventHistograms[eCentrality][eSim][ba]->Fill(ebye.fCentrality); // TBI 20240120 this case is still not supported in DetermineCentrality() + } + + // QA: + if (qa.fFillQAEventHistograms2D) { + !qa.fQAEventHistograms2D[eCentrality_vs_ImpactParameter][eSim][ba] ? true : qa.fQAEventHistograms2D[eCentrality_vs_ImpactParameter][eSim][ba]->Fill(ebye.fCentrality, collision.mcCollision().impactParameter()); + // ... + } + } // if constexpr (rs == eRecAndSim) { + } // if constexpr (rs == eRec || rs == eRecAndSim) { + + // ----------------------------------------------------------------------------- + + // b) Fill only simulated (common to Run 3, Run 2 and Run 1): + if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { + if (eh.fFillEventHistograms) { + !eh.fEventHistograms[eImpactParameter][eSim][ba] ? true : eh.fEventHistograms[eImpactParameter][eSim][ba]->Fill(collision.impactParameter()); // yes, because in this branch 'collision' is always aod::McCollision + !eh.fEventHistograms[eEventPlaneAngle][eSim][ba] ? true : eh.fEventHistograms[eEventPlaneAngle][eSim][ba]->Fill(collision.eventPlaneAngle()); // yes, because in this branch 'collision' is always aod::McCollision + !eh.fEventHistograms[eMultiplicity][eSim][ba] ? true : eh.fEventHistograms[eMultiplicity][eSim][ba]->Fill(ebye.fMultiplicity); + // eh.fEventHistograms[eCentrality][eSim][ba]->Fill(ebye.fCentrality); // TBI 20240120 this case is still not supported in DetermineCentrality() + // eh.fEventHistograms[eReferenceMultiplicity][eSim][ba]->Fill(ebye.fReferenceMultiplicity); // TBI 20241123 this case is still not supported in DetermineReferenceMultiplicity() + // eh.fEventHistograms[eTotalMultiplicity][eSim][ba]->Fill(tracks.size()); // TBI 20231030 check further how to use the same thing for 'sim' + } + + // Eta separations: + if (es.fCalculateEtaSeparations) { + for (int ab = 0; ab < 2; ab++) { // ab = 0 <=> -eta , ab = 1 <=> + eta + for (int e = 0; e < gMaxNumberEtaSeparations; e++) { // eta separation + !qv.fMabDist[ab][eSim][ba][e] ? true : qv.fMabDist[ab][eSim][ba][e]->Fill(qv.fMab[ab][e]); + } + } + } + } + + // ----------------------------------------------------------------------------- + + // c) Fill reconstructed (Run 3 specific): + if constexpr (rs == eRec || rs == eRecAndSim || rs == eQA) { + if (eh.fFillEventHistograms) { + !eh.fEventHistograms[eOccupancy][eRec][ba] ? true : eh.fEventHistograms[eOccupancy][eRec][ba]->Fill(ebye.fOccupancy); + !eh.fEventHistograms[eInteractionRate][eRec][ba] ? true : eh.fEventHistograms[eInteractionRate][eRec][ba]->Fill(ebye.fInteractionRate); + !eh.fEventHistograms[eCurrentRunDuration][eRec][ba] ? true : eh.fEventHistograms[eCurrentRunDuration][eRec][ba]->Fill(ebye.fCurrentRunDuration); + } + // QA: + if (qa.fFillQAEventHistograms2D) { + // General (estimators can be chosen via configurables): + + // **) vs occupancy: + !qa.fQAEventHistograms2D[eMultiplicity_vs_Occupancy][eRec][ba] ? true : qa.fQAEventHistograms2D[eMultiplicity_vs_Occupancy][eRec][ba]->Fill(ebye.fMultiplicity, ebye.fOccupancy); + !qa.fQAEventHistograms2D[eReferenceMultiplicity_vs_Occupancy][eRec][ba] ? true : qa.fQAEventHistograms2D[eReferenceMultiplicity_vs_Occupancy][eRec][ba]->Fill(ebye.fReferenceMultiplicity, ebye.fOccupancy); + !qa.fQAEventHistograms2D[eNContributors_vs_Occupancy][eRec][ba] ? true : qa.fQAEventHistograms2D[eNContributors_vs_Occupancy][eRec][ba]->Fill(collision.numContrib(), ebye.fOccupancy); + !qa.fQAEventHistograms2D[eCentrality_vs_Occupancy][eRec][ba] ? true : qa.fQAEventHistograms2D[eCentrality_vs_Occupancy][eRec][ba]->Fill(ebye.fCentrality, ebye.fOccupancy); + !qa.fQAEventHistograms2D[eVertexZ_vs_Occupancy][eRec][ba] ? true : qa.fQAEventHistograms2D[eVertexZ_vs_Occupancy][eRec][ba]->Fill(collision.posZ(), ebye.fOccupancy); + + // **) vs interaction rate: + !qa.fQAEventHistograms2D[eMultiplicity_vs_InteractionRate][eRec][ba] ? true : qa.fQAEventHistograms2D[eMultiplicity_vs_InteractionRate][eRec][ba]->Fill(ebye.fMultiplicity, ebye.fInteractionRate); + !qa.fQAEventHistograms2D[eReferenceMultiplicity_vs_InteractionRate][eRec][ba] ? true : qa.fQAEventHistograms2D[eReferenceMultiplicity_vs_InteractionRate][eRec][ba]->Fill(ebye.fReferenceMultiplicity, ebye.fInteractionRate); + !qa.fQAEventHistograms2D[eNContributors_vs_InteractionRate][eRec][ba] ? true : qa.fQAEventHistograms2D[eNContributors_vs_InteractionRate][eRec][ba]->Fill(collision.numContrib(), ebye.fInteractionRate); + !qa.fQAEventHistograms2D[eCentrality_vs_InteractionRate][eRec][ba] ? true : qa.fQAEventHistograms2D[eCentrality_vs_InteractionRate][eRec][ba]->Fill(ebye.fCentrality, ebye.fInteractionRate); + !qa.fQAEventHistograms2D[eVertexZ_vs_InteractionRate][eRec][ba] ? true : qa.fQAEventHistograms2D[eVertexZ_vs_InteractionRate][eRec][ba]->Fill(collision.posZ(), ebye.fInteractionRate); + + // **) unsorted TBI 20250331 sort at some point + !qa.fQAEventHistograms2D[eMultiplicity_vs_FT0CAmplitudeOnFoundBC][eRec][ba] ? true : qa.fQAEventHistograms2D[eMultiplicity_vs_FT0CAmplitudeOnFoundBC][eRec][ba]->Fill(ebye.fMultiplicity, ebye.fFT0CAmplitudeOnFoundBC); + !qa.fQAEventHistograms2D[eCentFT0C_vs_FT0CAmplitudeOnFoundBC][eRec][ba] ? true : qa.fQAEventHistograms2D[eCentFT0C_vs_FT0CAmplitudeOnFoundBC][eRec][ba]->Fill(qa.fCentrality[eCentFT0C], ebye.fFT0CAmplitudeOnFoundBC); + + // ... + + // Specific (estimators are hardwired): + !qa.fQAEventHistograms2D[eMultNTracksPV_vs_MultNTracksGlobal][eRec][ba] ? true : qa.fQAEventHistograms2D[eMultNTracksPV_vs_MultNTracksGlobal][eRec][ba]->Fill(qa.fReferenceMultiplicity[eMultNTracksPV], qa.fReferenceMultiplicity[eMultNTracksGlobal]); // TBI 20241209 check if I can use this one for Run 2 and 1 + !qa.fQAEventHistograms2D[eCentFT0C_vs_CentFT0CVariant1][eRec][ba] ? true : qa.fQAEventHistograms2D[eCentFT0C_vs_CentFT0CVariant1][eRec][ba]->Fill(qa.fCentrality[eCentFT0C], qa.fCentrality[eCentFT0CVariant1]); + !qa.fQAEventHistograms2D[eCentFT0C_vs_CentFT0M][eRec][ba] ? true : qa.fQAEventHistograms2D[eCentFT0C_vs_CentFT0M][eRec][ba]->Fill(qa.fCentrality[eCentFT0C], qa.fCentrality[eCentFT0M]); + !qa.fQAEventHistograms2D[eCentFT0C_vs_CentFV0A][eRec][ba] ? true : qa.fQAEventHistograms2D[eCentFT0C_vs_CentFV0A][eRec][ba]->Fill(qa.fCentrality[eCentFT0C], qa.fCentrality[eCentFV0A]); + !qa.fQAEventHistograms2D[eCentFT0C_vs_CentNTPV][eRec][ba] ? true : qa.fQAEventHistograms2D[eCentFT0C_vs_CentNTPV][eRec][ba]->Fill(qa.fCentrality[eCentFT0C], qa.fCentrality[eCentNTPV]); + !qa.fQAEventHistograms2D[eCentFT0C_vs_CentNGlobal][eRec][ba] ? true : qa.fQAEventHistograms2D[eCentFT0C_vs_CentNGlobal][eRec][ba]->Fill(qa.fCentrality[eCentFT0C], qa.fCentrality[eCentNGlobal]); + !qa.fQAEventHistograms2D[eCentFT0M_vs_CentNTPV][eRec][ba] ? true : qa.fQAEventHistograms2D[eCentFT0M_vs_CentNTPV][eRec][ba]->Fill(qa.fCentrality[eCentFT0M], qa.fCentrality[eCentNTPV]); + !qa.fQAEventHistograms2D[eTrackOccupancyInTimeRange_vs_FT0COccupancyInTimeRange][eRec][ba] ? true : qa.fQAEventHistograms2D[eTrackOccupancyInTimeRange_vs_FT0COccupancyInTimeRange][eRec][ba]->Fill(collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + !qa.fQAEventHistograms2D[eCurrentRunDuration_vs_InteractionRate][eRec][ba] ? true : qa.fQAEventHistograms2D[eCurrentRunDuration_vs_InteractionRate][eRec][ba]->Fill(ebye.fCurrentRunDuration, ebye.fInteractionRate); + } + + if (qa.fFillQAParticleEventHistograms2D && qa.fQAParticleEventProEbyE[eRec][ba]) { + // This is a special category, where I do correlation vs. some-event-property. + // I use 'number of combinations' as a weight, which here reduces simply to the 'number of entries' weight. + !qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_itsNClsEbyE][eRec][ba] ? true : qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_itsNClsEbyE][eRec][ba]->Fill(ebye.fCurrentRunDuration, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eitsNClsEbyE), qa.fQAParticleEventProEbyE[eRec][ba]->GetBinEntries(eitsNClsEbyE)); + !qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_itsNClsNegEtaEbyE][eRec][ba] ? true : qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_itsNClsNegEtaEbyE][eRec][ba]->Fill(ebye.fCurrentRunDuration, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eitsNClsNegEtaEbyE), qa.fQAParticleEventProEbyE[eRec][ba]->GetBinEntries(eitsNClsNegEtaEbyE)); + !qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_itsNClsPosEtaEbyE][eRec][ba] ? true : qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_itsNClsPosEtaEbyE][eRec][ba]->Fill(ebye.fCurrentRunDuration, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eitsNClsPosEtaEbyE), qa.fQAParticleEventProEbyE[eRec][ba]->GetBinEntries(eitsNClsPosEtaEbyE)); + !qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_Eta0804EbyE][eRec][ba] ? true : qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_Eta0804EbyE][eRec][ba]->Fill(ebye.fCurrentRunDuration, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eEta0804EbyE), qa.fQAParticleEventProEbyE[eRec][ba]->GetBinEntries(eEta0804EbyE)); + !qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_Eta0400EbyE][eRec][ba] ? true : qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_Eta0400EbyE][eRec][ba]->Fill(ebye.fCurrentRunDuration, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eEta0400EbyE), qa.fQAParticleEventProEbyE[eRec][ba]->GetBinEntries(eEta0400EbyE)); + !qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_Eta0004EbyE][eRec][ba] ? true : qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_Eta0004EbyE][eRec][ba]->Fill(ebye.fCurrentRunDuration, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eEta0004EbyE), qa.fQAParticleEventProEbyE[eRec][ba]->GetBinEntries(eEta0004EbyE)); + !qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_Eta0408EbyE][eRec][ba] ? true : qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_Eta0408EbyE][eRec][ba]->Fill(ebye.fCurrentRunDuration, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eEta0408EbyE), qa.fQAParticleEventProEbyE[eRec][ba]->GetBinEntries(eEta0408EbyE)); + !qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_Pt0005EbyE][eRec][ba] ? true : qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_Pt0005EbyE][eRec][ba]->Fill(ebye.fCurrentRunDuration, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(ePt0005EbyE), qa.fQAParticleEventProEbyE[eRec][ba]->GetBinEntries(ePt0005EbyE)); + !qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_Pt0510EbyE][eRec][ba] ? true : qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_Pt0510EbyE][eRec][ba]->Fill(ebye.fCurrentRunDuration, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(ePt0510EbyE), qa.fQAParticleEventProEbyE[eRec][ba]->GetBinEntries(ePt0510EbyE)); + !qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_Pt1050EbyE][eRec][ba] ? true : qa.fQAParticleEventHistograms2D[eCurrentRunDuration_vs_Pt1050EbyE][eRec][ba]->Fill(ebye.fCurrentRunDuration, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(ePt1050EbyE), qa.fQAParticleEventProEbyE[eRec][ba]->GetBinEntries(ePt1050EbyE)); + } // if (qa.fFillQAParticleEventHistograms2D && qa.fQAParticleEventProEbyE[eRec][ba]) { + + if (qa.fFillQACorrelationsVsInteractionRateVsProfiles2D && qa.fQAParticleEventProEbyE[eRec][ba] && ba == eAfter) { // fill only for eAfter, because I do not calculate Q-vectors before cuts + + // Calculate quickly 2-p correlation in harmonic h for this event: TBI 20250114 shall I add this also to some EbyE variable? There is no really much of a code bloat for the time being... + + // Flush 'n' fill the generic Q-vectors: + ResetQ(); + int lMaxCorrelator = 2; // used only here locally + for (int h = 0; h < gMaxHarmonic * lMaxCorrelator + 1; h++) { + for (int wp = 0; wp < lMaxCorrelator + 1; wp++) // weight power + { + qv.fQ[h][wp] = qv.fQvector[h][wp]; + } + } + + for (int h = 1; h <= gMaxHarmonic; h++) { + TComplex two = Two(h, -h); + double twoC = two.Re(); // cos + // double twoS = two.Im(); // sin + double wTwo = Two(0, 0).Re(); // Weight is 'number of combinations' by default TBI + // 20220809 add support for other weights + if (!(wTwo > 0.0)) { + LOGF(fatal, "In function \033[1;31m%s at line %d : wTwo = %f <=0. ebye.fSelectedTracks = %d.\nDid you forget to enable fCalculateQvectors = true?\033[0m", __FUNCTION__, __LINE__, wTwo, ebye.fSelectedTracks); + } + + !qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_CurrentRunDuration][h - 1][eRec] ? true : qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_CurrentRunDuration][h - 1][eRec]->Fill(ebye.fInteractionRate, ebye.fCurrentRunDuration, twoC / wTwo, wTwo); + !qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_Multiplicity][h - 1][eRec] ? true : qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_Multiplicity][h - 1][eRec]->Fill(ebye.fInteractionRate, ebye.fMultiplicity, twoC / wTwo, wTwo); + !qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_ReferenceMultiplicity][h - 1][eRec] ? true : qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_ReferenceMultiplicity][h - 1][eRec]->Fill(ebye.fInteractionRate, ebye.fReferenceMultiplicity, twoC / wTwo, wTwo); + !qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_Centrality][h - 1][eRec] ? true : qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_Centrality][h - 1][eRec]->Fill(ebye.fInteractionRate, ebye.fCentrality, twoC / wTwo, wTwo); + // ..... + !qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_MeanPhi][h - 1][eRec] ? true : qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_MeanPhi][h - 1][eRec]->Fill(ebye.fInteractionRate, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeanPhi), twoC / wTwo, wTwo); + !qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_SigmaMeanPhi][h - 1][eRec] ? true : qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_SigmaMeanPhi][h - 1][eRec]->Fill(ebye.fInteractionRate, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinError(eMeanPhi), twoC / wTwo, wTwo); + !qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_MeanPt][h - 1][eRec] ? true : qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_MeanPt][h - 1][eRec]->Fill(ebye.fInteractionRate, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeanPt), twoC / wTwo, wTwo); + !qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_SigmaMeanPt][h - 1][eRec] ? true : qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_SigmaMeanPt][h - 1][eRec]->Fill(ebye.fInteractionRate, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinError(eMeanPt), twoC / wTwo, wTwo); + !qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_MeanEta][h - 1][eRec] ? true : qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_MeanEta][h - 1][eRec]->Fill(ebye.fInteractionRate, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinContent(eMeanEta), twoC / wTwo, wTwo); + !qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_SigmaMeanEta][h - 1][eRec] ? true : qa.fQACorrVsIRVsProfiles2D[eCorrelationsVsInteractionRate_vs_SigmaMeanEta][h - 1][eRec]->Fill(ebye.fInteractionRate, qa.fQAParticleEventProEbyE[eRec][ba]->GetBinError(eMeanEta), twoC / wTwo, wTwo); + // ..... + } + + // Flush the generic Q-vectors: + ResetQ(); + + } // if (qa.fFillQACorrelationsVsInteractionRateVsProfiles2D && qa.fQAParticleEventProEbyE[eRec][ba] && ba == eAfter) { + + // ... + + // ... and corresponding MC truth simulated (Run 3 specific) + // See https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx + if constexpr (rs == eRecAndSim) { + if (!collision.has_mcCollision()) { + LOGF(warning, "No MC collision for this collision, skip..."); + return; + } + + // !eh.fEventHistograms[eMultMCNParticlesEta08][eSim][ba] ? true : eh.fEventHistograms[eMultMCNParticlesEta08][eSim][ba]->Fill(collision.multMCNParticlesEta08()); + + // !eh.fEventHistograms[eNumberOfEvents][eSim][ba] ? true : eh.fEventHistograms[eNumberOfEvents][eSim][ba]->Fill(0.5); + } // if constexpr (rs == eRecAndSim) { + } // if constexpr (rs == eRec || rs == eRecAndSim) { + + // ----------------------------------------------------------------------------- + + // d) Fill only simulated (Run 3 specific): + if constexpr (rs == eSim) { + // !eh.fEventHistograms[eImpactParameter][eSim][ba] ? true : eh.fEventHistograms[eImpactParameter][eSim][ba]->Fill(collision.impactParameter()); // yes, because in this branch 'collision' is always aod::McCollision + // !eh.fEventHistograms[eEventPlaneAngle][eSim][ba] ? true : eh.fEventHistograms[eEventPlaneAngle][eSim][ba]->Fill(collision.eventPlaneAngle()); // yes, because in this branch 'collision' is always aod::McCollision + } // if constexpr (rs == eSim) { + + // ----------------------------------------------------------------------------- + + // e) Fill reconstructed (Run 1 and 2 specific): // In case there is some corner case between Run 1 and Run 2, simply branch further this one + if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { + if (eh.fFillEventHistograms) { + // ... + } + // QA: + if (qa.fFillQAEventHistograms2D) { + !qa.fQAEventHistograms2D[eCentRun2V0M_vs_CentRun2SPDTracklets][eRec][ba] ? true : qa.fQAEventHistograms2D[eCentRun2V0M_vs_CentRun2SPDTracklets][eRec][ba]->Fill(qa.fCentrality[eCentRun2V0M], qa.fCentrality[eCentRun2SPDTracklets]); + } + + // ... and corresponding MC truth simulated (Run 1 and Run 2 specific): + // See https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx + if constexpr (rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + if (!collision.has_mcCollision()) { + LOGF(warning, "No MC collision for this collision, skip..."); + return; + } + // !eh.fEventHistograms[eNumberOfEvents][eSim][ba] ? true : eh.fEventHistograms[eNumberOfEvents][eSim][ba]->Fill(0.5); + + } // if constexpr (rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + } // if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { + + // ----------------------------------------------------------------------------- + + // f) Fill only simulated (Run 1 and 2 specific): // In case there is some corner case between Run 1 and Run 2, simply branch further this one + if constexpr (rs == eSim_Run2 || rs == eSim_Run1) { + // !eh.fEventHistograms[eImpactParameter][eSim][ba] ? true : eh.fEventHistograms[eImpactParameter][eSim][ba]->Fill(collision.impactParameter()); // yes, because in this branch 'collision' is always aod::McCollision + // !eh.fEventHistograms[eEventPlaneAngle][eSim][ba] ? true : eh.fEventHistograms[eEventPlaneAngle][eSim][ba]->Fill(collision.eventPlaneAngle()); // yes, because in this branch 'collision' is always aod::McCollision + } // if constexpr (rs == eSim_Run2 || rs == eSim_Run1) { + + // ----------------------------------------------------------------------------- + + // g) Test case: + if constexpr (rs == eTest) { + // TBI 20240223 for the time being, eTest fills only eRec histos: + // A few example histograms, just to check if I access corresponding tables: + if (eh.fFillEventHistograms) { + !eh.fEventHistograms[eNumberOfEvents][eRec][ba] ? true : eh.fEventHistograms[eNumberOfEvents][eRec][ba]->Fill(0.5); + !eh.fEventHistograms[eVertexZ][eRec][ba] ? true : eh.fEventHistograms[eVertexZ][eRec][ba]->Fill(collision.posZ()); + !eh.fEventHistograms[eTotalMultiplicity][eRec][ba] ? true : eh.fEventHistograms[eTotalMultiplicity][eRec][ba]->Fill(tracks.size()); + !eh.fEventHistograms[eCentrality][eRec][ba] ? true : eh.fEventHistograms[eCentrality][eRec][ba]->Fill(ebye.fCentrality); + } + } // if constexpr (rs == eTest) { + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // template void FillEventHistograms(...) + +//============================================================ + +void CheckUnderflowAndOverflow() +{ + // Check and bail out if in event and particle histograms there are entries which went to underflow or overflow bins. + + // a) Event histograms 1D; + // b) Event histograms 2D; + // c) Particle histograms 1D; + // d) Particle histograms 2D; + // e) QA Event histograms 2D; + // f) QA Particle histograms 2D; + // g) QA Particle event histograms 2D. + + if (tc.fVerboseForEachParticle) { + StartFunction(__FUNCTION__); + } + + // a) Event histograms 1D: + for (int t = 0; t < eEventHistograms_N; t++) // type, see enum eEventHistograms + { + for (int rs = 0; rs < 2; rs++) // reco/sim + { + for (int ba = 0; ba < 2; ba++) // before/after cuts + { + if (!eh.fEventHistograms[t][rs][ba]) { + continue; + } else if (eh.fEventHistograms[t][rs][ba]->GetBinContent(0) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : underflow in fEventHistograms[%d][%d][%d] => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba); + } else if (eh.fEventHistograms[t][rs][ba]->GetBinContent(eh.fEventHistograms[t][rs][ba]->GetNbinsX() + 1) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : overflow in fEventHistograms[%d][%d][%d] => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba); + } + } + } + } + + // b) Event histograms 2D: + // ... + + // c) Particle histograms 1D: + for (int t = 0; t < eParticleHistograms_N; t++) // type, see enum eParticleHistograms + { + for (int rs = 0; rs < 2; rs++) // reco/sim + { + for (int ba = 0; ba < 2; ba++) // before/after cuts + { + if (!ph.fParticleHistograms[t][rs][ba]) { + continue; + } else if (ph.fParticleHistograms[t][rs][ba]->GetBinContent(0) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : underflow in fParticleHistograms[%d][%d][%d] => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba); + } else if (ph.fParticleHistograms[t][rs][ba]->GetBinContent(ph.fParticleHistograms[t][rs][ba]->GetNbinsX() + 1) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : overflow in fParticleHistograms[%d][%d][%d] => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba); + } + } + } + } + + // d) Particle histograms 2D: + for (int t = 0; t < eParticleHistograms2D_N; t++) // type, see enum eParticleHistograms2D + { + for (int rs = 0; rs < 2; rs++) // reco/sim + { + for (int ba = 0; ba < 2; ba++) // before/after cuts + { + if (!ph.fParticleHistograms2D[t][rs][ba]) { + continue; + } + + // Underflow and overflow in x: + for (int binY = 0; binY <= ph.fParticleHistograms2D[t][rs][ba]->GetNbinsY(); binY++) { + if (ph.fParticleHistograms2D[t][rs][ba]->GetBinContent(ph.fParticleHistograms2D[t][rs][ba]->GetBin(0, binY)) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : underflow in x variable in fParticleHistograms2D[%d][%d][%d], for binY = %d => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba, binY); + } + if (ph.fParticleHistograms2D[t][rs][ba]->GetBinContent(ph.fParticleHistograms2D[t][rs][ba]->GetBin(ph.fParticleHistograms2D[t][rs][ba]->GetNbinsX() + 1, binY)) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : overflow in x variable in fParticleHistograms2D[%d][%d][%d], for binY = %d => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba, binY); + } + } // for (int binY = 0; binY <= ph.fParticleHistograms2D[t][rs][ba]->GetNbinsY(); binY++) { + + // Underflow and overflow in y: + for (int binX = 0; binX <= ph.fParticleHistograms2D[t][rs][ba]->GetNbinsX(); binX++) { + if (ph.fParticleHistograms2D[t][rs][ba]->GetBinContent(ph.fParticleHistograms2D[t][rs][ba]->GetBin(binX, 0)) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : underflow in y variable in fParticleHistograms2D[%d][%d][%d], for binX = %d => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba, binX); + } + + if (ph.fParticleHistograms2D[t][rs][ba]->GetBinContent(ph.fParticleHistograms2D[t][rs][ba]->GetBin(binX, ph.fParticleHistograms2D[t][rs][ba]->GetNbinsY() + 1)) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : overflow in y variable in fParticleHistograms2D[%d][%d][%d], for binX = %d => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba, binX); + } + } // for (int binX = 0; binX <= ph.fParticleHistograms2D[t][rs][ba]->GetNbinsX(); binX++) { + } // for (int ba = 0; ba < 2; ba++) // before/after cuts + } // for (int rs = 0; rs < 2; rs++) // reco/sim + } // for (int t = 0; t < eParticleHistograms2D_N; t++) // type, see enum eParticleHistograms2D + + // e) QA Event histograms 2D: + for (int t = 0; t < eQAEventHistograms2D_N; t++) // type, see enum eQAEventHistograms2D + { + for (int rs = 0; rs < 2; rs++) // reco/sim + { + for (int ba = 0; ba < 2; ba++) // before/after cuts + { + if (!qa.fQAEventHistograms2D[t][rs][ba]) { + continue; + } + + // Underflow and overflow in x: + for (int binY = 0; binY <= qa.fQAEventHistograms2D[t][rs][ba]->GetNbinsY(); binY++) { + if (qa.fQAEventHistograms2D[t][rs][ba]->GetBinContent(qa.fQAEventHistograms2D[t][rs][ba]->GetBin(0, binY)) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : underflow in x variable in fEventHistograms2D[%d][%d][%d], for binY = %d => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba, binY); + } + if (qa.fQAEventHistograms2D[t][rs][ba]->GetBinContent(qa.fQAEventHistograms2D[t][rs][ba]->GetBin(qa.fQAEventHistograms2D[t][rs][ba]->GetNbinsX() + 1, binY)) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : overflow in x variable in fEventHistograms2D[%d][%d][%d], for binY = %d => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba, binY); + } + } // for (int binY = 0; binY <= qa.fQAEventHistograms2D[t][rs][ba]->GetNbinsY(); binY++) { + + // Underflow and overflow in y: + for (int binX = 0; binX <= qa.fQAEventHistograms2D[t][rs][ba]->GetNbinsX(); binX++) { + if (qa.fQAEventHistograms2D[t][rs][ba]->GetBinContent(qa.fQAEventHistograms2D[t][rs][ba]->GetBin(binX, 0)) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : underflow in y variable in fEventHistograms2D[%d][%d][%d], for binX = %d => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba, binX); + } + + if (qa.fQAEventHistograms2D[t][rs][ba]->GetBinContent(qa.fQAEventHistograms2D[t][rs][ba]->GetBin(binX, qa.fQAEventHistograms2D[t][rs][ba]->GetNbinsY() + 1)) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : overflow in y variable in fEventHistograms2D[%d][%d][%d], for binX = %d => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba, binX); + } + } // for (int binX = 0; binX <= qa.fQAEventHistograms2D[t][rs][ba]->GetNbinsX(); binX++) { + } // for (int ba = 0; ba < 2; ba++) // before/after cuts + } // for (int rs = 0; rs < 2; rs++) // reco/sim + } // for (int t = 0; t < eQAEventHistograms2D_N; t++) // type, see enum eQAEventHistograms2D + + // f) QA Particle histograms 2D: + for (int t = 0; t < eQAParticleHistograms2D_N; t++) // type, see enum eQAParticleHistograms2D + { + for (int rs = 0; rs < 2; rs++) // reco/sim + { + for (int ba = 0; ba < 2; ba++) // before/after cuts + { + if (!qa.fQAParticleHistograms2D[t][rs][ba]) { + continue; + } + + // Underflow and overflow in x: + for (int binY = 0; binY <= qa.fQAParticleHistograms2D[t][rs][ba]->GetNbinsY(); binY++) { + if (qa.fQAParticleHistograms2D[t][rs][ba]->GetBinContent(qa.fQAParticleHistograms2D[t][rs][ba]->GetBin(0, binY)) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : underflow in x variable in fParticleHistograms2D[%d][%d][%d], for binY = %d => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba, binY); + } + if (qa.fQAParticleHistograms2D[t][rs][ba]->GetBinContent(qa.fQAParticleHistograms2D[t][rs][ba]->GetBin(qa.fQAParticleHistograms2D[t][rs][ba]->GetNbinsX() + 1, binY)) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : overflow in x variable in fParticleHistograms2D[%d][%d][%d], for binY = %d => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba, binY); + } + } // for (int binY = 0; binY <= qa.fQAParticleHistograms2D[t][rs][ba]->GetNbinsY(); binY++) { + + // Underflow and overflow in y: + for (int binX = 0; binX <= qa.fQAParticleHistograms2D[t][rs][ba]->GetNbinsX(); binX++) { + if (qa.fQAParticleHistograms2D[t][rs][ba]->GetBinContent(qa.fQAParticleHistograms2D[t][rs][ba]->GetBin(binX, 0)) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : underflow in y variable in fParticleHistograms2D[%d][%d][%d], for binX = %d => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba, binX); + } + + if (qa.fQAParticleHistograms2D[t][rs][ba]->GetBinContent(qa.fQAParticleHistograms2D[t][rs][ba]->GetBin(binX, qa.fQAParticleHistograms2D[t][rs][ba]->GetNbinsY() + 1)) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : overflow in y variable in fParticleHistograms2D[%d][%d][%d], for binX = %d => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba, binX); + } + } // for (int binX = 0; binX <= qa.fQAParticleHistograms2D[t][rs][ba]->GetNbinsX(); binX++) { + } // for (int ba = 0; ba < 2; ba++) // before/after cuts + } // for (int rs = 0; rs < 2; rs++) // reco/sim + } // for (int t = 0; t < eQAParticleHistograms2D_N; t++) // type, see enum eParticleHistograms2D + + // g) QA Particle event histograms 2D: + // TBI 20241212 I never validated this code block + for (int t = 0; t < eQAParticleEventHistograms2D_N; t++) // type, see enum eQAParticleEventHistograms2D + { + for (int rs = 0; rs < 2; rs++) // reco/sim + { + for (int ba = 0; ba < 2; ba++) // before/after cuts + { + if (!qa.fQAParticleEventHistograms2D[t][rs][ba]) { + continue; + } + + // Underflow and overflow in x: + for (int binY = 0; binY <= qa.fQAParticleEventHistograms2D[t][rs][ba]->GetNbinsY(); binY++) { + if (qa.fQAParticleEventHistograms2D[t][rs][ba]->GetBinContent(qa.fQAParticleEventHistograms2D[t][rs][ba]->GetBin(0, binY)) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : underflow in x variable in fParticleEventHistograms2D[%d][%d][%d], for binY = %d => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba, binY); + } + if (qa.fQAParticleEventHistograms2D[t][rs][ba]->GetBinContent(qa.fQAParticleEventHistograms2D[t][rs][ba]->GetBin(qa.fQAParticleEventHistograms2D[t][rs][ba]->GetNbinsX() + 1, binY)) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : overflow in x variable in fParticleEventHistograms2D[%d][%d][%d], for binY = %d => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba, binY); + } + } // for (int binY = 0; binY <= qa.fQAParticleEventHistograms2D[t][rs][ba]->GetNbinsY(); binY++) { + + // Underflow and overflow in y: + for (int binX = 0; binX <= qa.fQAParticleEventHistograms2D[t][rs][ba]->GetNbinsX(); binX++) { + if (qa.fQAParticleEventHistograms2D[t][rs][ba]->GetBinContent(qa.fQAParticleEventHistograms2D[t][rs][ba]->GetBin(binX, 0)) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : underflow in y variable in fParticleEventHistograms2D[%d][%d][%d], for binX = %d => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba, binX); + } + + if (qa.fQAParticleEventHistograms2D[t][rs][ba]->GetBinContent(qa.fQAParticleEventHistograms2D[t][rs][ba]->GetBin(binX, qa.fQAParticleEventHistograms2D[t][rs][ba]->GetNbinsY() + 1)) > 0) { + LOGF(fatal, "\033[1;31m%s at line %d : overflow in y variable in fParticleEventHistograms2D[%d][%d][%d], for binX = %d => optimize default binning for this histogram\033[0m", __FUNCTION__, __LINE__, t, rs, ba, binX); + } + } // for (int binX = 0; binX <= qa.fQAParticleEventHistograms2D[t][rs][ba]->GetNbinsX(); binX++) { + } // for (int ba = 0; ba < 2; ba++) // before/after cuts + } // for (int rs = 0; rs < 2; rs++) // reco/sim + } // for (int t = 0; t < eQAParticleEventHistograms2D_N; t++) // type, see enum eParticleEventHistograms2D + + if (tc.fVerboseForEachParticle) { + ExitFunction(__FUNCTION__); + } + +} // void CheckUnderflowAndOverflow() + +//============================================================ + +template +bool ValidTrack(T const& track) +{ + // Before I start applying any track cuts, check if this is a valid track. + // For instance, Run 2 or Run 1 tracklets are NOT valid tracks, as they carry no pt information, and in this function they are filtered out. + + // See enum TrackTypeEnum in O2/Framework/Core/include/Framework/DataTypes.h for further info. + + // a) Validity checks for tracks in Run 3; + // b) Validity checks for tracks in Run 2 and 1; + // c) Additional validity checks for all tracks (in Run 3, 2 and 1), use only during debugging. + + if (tc.fVerboseForEachParticle) { + StartFunction(__FUNCTION__); + LOGF(info, " track.phi() = %f", track.phi()); + LOGF(info, " track.pt() = %f", track.pt()); + LOGF(info, " track.eta() = %f", track.eta()); + // LOGF(info, "track.trackType() = %d", static_cast(track.trackType())); TBI 20240404 this is not supported for MC particles + } + + // a) Validity checks for tracks in Run 3: + // *) Ensure that I am taking into account propagated tracks (and not e.g. track evaluated at innermost update): + if constexpr (rs == eRec || rs == eRecAndSim || rs == eQA) { + if (!(track.trackType() == o2::aod::track::TrackTypeEnum::Track)) { + if (tc.fVerboseForEachParticle) { + LOGF(info, "\033[1;31m%s track.trackType() == o2::aod::track::TrackTypeEnum::Trac\033[0m", __FUNCTION__); + } + return false; + } + } + + // b) Validity checks for tracks in Run 2 and 1: + // *) Ensure that tracklets (no pt information) are skipped: + if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { + if (!(track.trackType() == o2::aod::track::TrackTypeEnum::Run2Track)) { + if (tc.fVerboseForEachParticle) { + LOGF(info, "\033[1;31m%s track.trackType() == o2::aod::track::TrackTypeEnum::Run2Track\033[0m", __FUNCTION__); + } + return false; + } + } + + // *) Temporary here, until I cover also these cases: + if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { + LOGF(fatal, "\033[1;31m%s at line %d : add support for TrackTypeEnum here also for cases eSim, eSim_Run2 and eSim_Run1\033[0m", __FUNCTION__, __LINE__); + } + + // c) Additional validity checks for all tracks (in Run 3, 2 and 1), use only during debugging: + if (tc.fInsanityCheckForEachParticle) { + + // *) std::isnan() check (remember that 'nan' is 0./0., inf-inf, etc. However 'inf' itself is NOT a 'nan', therefore std::isnan(1./0.) is false, std::isnan(0./0.) is true, etc.): + if (std::isnan(track.phi()) || std::isnan(track.pt()) || std::isnan(track.eta())) { + if (tc.fVerboseForEachParticle) { + LOGF(info, "\033[1;31m%s std::isnan(track.phi()) || std::isnan(track.pt()) || std::isnan(track.eta())\033[0m", __FUNCTION__); + LOGF(error, "track.phi() = %f\ntrack.pt() = %f\ntrack.eta() = %f", track.phi(), track.pt(), track.eta()); + } + return false; + } + + // *) ... + // ... + + } // if(tc.fInsanityCheckForEachParticle) { + + // *) All checks above survived, then it's a valid track: + return true; + +} // template bool ValidTrack(T const& track) + +//============================================================ + +float GetCentralityPercentile(TString ce) +{ + // Helper function for CentralityCorrelationCut(), to reduce the code bloat there. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // TBI 20250331 shall I add some insanity check on centrality estimator "ce" + + float centralityPercentile = -1.; + + // Run 3: + if (ce.EqualTo("centFT0C", TString::kIgnoreCase)) { + centralityPercentile = qa.fCentrality[eCentFT0C]; + } else if (ce.EqualTo("centFT0CVariant1", TString::kIgnoreCase)) { + centralityPercentile = qa.fCentrality[eCentFT0CVariant1]; + } else if (ce.EqualTo("centFT0M", TString::kIgnoreCase)) { + centralityPercentile = qa.fCentrality[eCentFT0M]; + } else if (ce.EqualTo("centFV0A", TString::kIgnoreCase)) { + centralityPercentile = qa.fCentrality[eCentFV0A]; + } else if (ce.EqualTo("centNTPV", TString::kIgnoreCase)) { + centralityPercentile = qa.fCentrality[eCentNTPV]; + } else if (ce.EqualTo("centNGlobal", TString::kIgnoreCase)) { + // centralityPercentile = qa.fCentrality[eCentNGlobal]; // TBI 20250331 enable eventually + + // ... ctd here with Run 3 estimators ... + + // Run 1 and Run 2: + } else if (ce.EqualTo("centRun2V0M", TString::kIgnoreCase)) { + centralityPercentile = qa.fCentrality[eCentRun2V0M]; + } else if (ce.EqualTo("centRun2SPDTracklets", TString::kIgnoreCase)) { + centralityPercentile = qa.fCentrality[eCentRun2SPDTracklets]; + + // ... ctd here with Run 1 and Run 2 estimators ... + + } else { + LOGF(fatal, "\033[1;31m%s at line %d : centrality estimator = %s is not supported yet. \033[0m", __FUNCTION__, __LINE__, ce.Data()); + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + + return centralityPercentile; + +} // float GetCentralityPercentile(TString ce) + +//============================================================ + +bool CentralityCorrelationCut() +{ + // If centrality correlation cut was requested, in this function i decide whether the current event survives it or not. + // This function is called only in EventCuts(...). I implemented it here separately merely to keep code in EventCuts(...) as clean as possible. + // If makes sense to call this function, only if in DetermineCentrality(...) I have filled in qa.Centrality . + + // TBI 20250331 There is a bit of performance loss, because I need 2 centrality estimators to calculate correlation cut, and I fill in qa.Centrality values + // for all centrality estimators. But this way I can chain several centrality correlation cuts in the future with AND condition, if necessary. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + bool alright = true; // this local variable holds the return value for this function + + // Algorithm: I extract e.g. from "CentFT0C_CentFT0M" that the first estimator is "CentFT0C" and second "CentFT0M", and for each estimator I fetch the corresponding centrality percentile: + TObjArray* oa = ec.fsEventCuts[eCentralityCorrelationsCut].Tokenize("_"); // TBI 20250331 let's see for how long I can use "_" safely as IFS ... + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL , s = %s. Example format is e.g. \"CentFT0C_CentFT0M\"\033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eCentralityCorrelationsCut].Data()); + } + ec.fCentralityValues[0] = GetCentralityPercentile(oa->At(0)->GetName()); + ec.fCentralityValues[1] = GetCentralityPercentile(oa->At(1)->GetName()); + delete oa; // yes + + // Okay, do the thing: + // *) "Relative" <=> |(firstEstimator-secondEstimator)/(firstEstimator+secondEstimator)| > treshold => reject the event => alright = false + // *) "Absolute" <=> |firstEstimator-secondEstimator| > treshold => reject the event => alright = false + // *) ... + if (ec.fCentralityValues[0] > 0. && ec.fCentralityValues[1] > 0.) { + if (ec.fCentralityCorrelationsCutVersion.EqualTo("Relative")) { + if (TMath::Abs((ec.fCentralityValues[0] - ec.fCentralityValues[1]) / (ec.fCentralityValues[0] + ec.fCentralityValues[1])) > ec.fCentralityCorrelationsCutTreshold) { + alright = false; + } + } else if (ec.fCentralityCorrelationsCutVersion.EqualTo("Absolute")) { + if (TMath::Abs((ec.fCentralityValues[0] - ec.fCentralityValues[1])) > ec.fCentralityCorrelationsCutTreshold) { + alright = false; + } + } else { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } // if(ec.fCentralityValues[0] > 0. && ec.fCentralityValues[1] > 0.) + + if (tc.fVerbose) { + LOGF(info, "\033[1;33m%s at line %d : %f, %f, %f, %d \033[0m", __FUNCTION__, __LINE__, ec.fCentralityValues[0], ec.fCentralityValues[1], ec.fCentralityCorrelationsCutTreshold, static_cast(alright)); + ExitFunction(__FUNCTION__); + } + + return alright; + +} // bool CentralityCorrelationCut() + +//============================================================ + +template +void ParticleCutsCounters(T const& track) +{ + // Use this function to fill absolute and sequential particle cut counters. Use only during QA, as this is computationally heavy (I mean really). + + if (tc.fVerboseForEachParticle) { + StartFunction(__FUNCTION__); + } + + // *) Establish ordering of binning in particle cut counters histograms, which resembles ordering of particle cuts implementation: + if (!pc.fParticleCutCounterBinLabelingIsDone) { + pc.fParticleCutCounterBinNumber[eRec] = 1; // remember that I cannot use 'rs' here as an index, because the enum eRecSim covers separately Run 1 and Run 2, etc. + pc.fParticleCutCounterBinNumber[eSim] = 1; + ParticleCuts(track, eCutCounterBinning); // dry call, to establish the map fParticleCutCounterMap and its inverse + + // **) Map this ordering into bin labels of actual histograms for particle cut counters: + for (int rec_sim = 0; rec_sim < 2; rec_sim++) // reco/sim => I use here exceptionally different var 'rec_sim', not the shadow 'rs' in the template parameter + { + for (int cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter + { + if (!pc.fParticleCutCounterHist[rec_sim][cc]) { + continue; + } + for (int bin = 1; bin < pc.fParticleCutCounterBinNumber[rec_sim]; bin++) // implemented and used particle cuts in this analysis + { + pc.fParticleCutCounterHist[rec_sim][cc]->GetXaxis()->SetBinLabel(bin, FancyFormatting(pc.fParticleCutName[pc.fParticleCutCounterMap[rec_sim]->GetValue(bin)].Data())); + } + for (int bin = pc.fParticleCutCounterBinNumber[rec_sim]; bin <= eParticleCuts_N; bin++) // implemented, but unused particle cuts in this analysis + { + pc.fParticleCutCounterHist[rec_sim][cc]->GetXaxis()->SetBinLabel(bin, Form("binNo = %d (unused cut)", bin)); + // Remark: I have to write here something concrete as a bin label, if I leave "TBI" for all bin labels here for cuts which were not used, + // I get this harmless but annoying warning during merging: + // Warning in : Histogram fParticleCutCounterHist[rec][seq] has duplicate labels in the x axis. Bin contents will be merged in a single bin + // TBI 20241130 as a better solution, I shall re-define this histogram with the narower range on x-axis... + } + // All cuts which were implemeted, but not used I simply do not show (i can always UnZoom x-axis in TBrowser, if I want to see 'em). + pc.fParticleCutCounterHist[rec_sim][cc]->GetXaxis()->SetRangeUser(pc.fParticleCutCounterHist[rec_sim][cc]->GetBinLowEdge(1), pc.fParticleCutCounterHist[rec_sim][cc]->GetBinLowEdge(pc.fParticleCutCounterBinNumber[rec_sim])); + } + } + pc.fParticleCutCounterBinLabelingIsDone = true; // this flag ensures that this specific binning is performed only once, for the first processed particle + // delete pc.fParticleCutCounterMap[eRec]; // TBI 20240508 if i do not need them later, I could delete here + // delete pc.fParticleCutCounterMap[eSim]; + // delete pc.fParticleCutCounterMapInverse[eRec]; + // delete pc.fParticleCutCounterMapInverse[eSim]; + } // if (!pc.fParticleCutCounterBinLabelingIsDone) { + + // *) Particle cut counter (absolute): + if (pc.fUseParticleCutCounterAbsolute) { + pc.fParticleCutCounterBinNumber[eRec] = 1; + pc.fParticleCutCounterBinNumber[eSim] = 1; + ParticleCuts(track, eCutCounterAbsolute); + } + + // *) Particle cut counter (sequential): + if (pc.fUseParticleCutCounterSequential) { + pc.fParticleCutCounterBinNumber[eRec] = 1; + pc.fParticleCutCounterBinNumber[eSim] = 1; + ParticleCuts(track, eCutCounterSequential); + } + +} // template void ParticleCutsCounters(T const& track) + +//============================================================ + +template +bool ParticleCuts(T const& track, eCutModus cutModus) +{ + // Particle cuts on reconstructed and simulated data. Supports particle cut counters, both absolute and sequential. + // There is also a related enum eParticleCuts. + // Remark: I have added to all if statemets below which deals with floats, e.g. TMath::Abs(track.eta() - pc.fdParticleCuts[eEta][eMax]) < tc.fFloatingPointPrecision , + // to enforce the ROOT convention: "lower boundary included, upper boundary excluded" + + // a) Particle cuts on reconstructed, and corresponding MC truth simulated (common to Run 3, Run 2 and Run 1); + // b) Particle cuts only on simulated (common to Run 3, Run 2 and Run 1); + // c) Particle cuts on reconstructed, and corresponding MC truth simulated (Run 3 specific); + // d) Particle cuts on simulated (Run 3 specific); + // e) Particle cuts on reconstructed, and corresponding MC truth simulated (Run 1 and 2 specific); // In case there is some corner case between Run 1 and Run 2, simply branch further this one + // f) Particle cuts on simulated (Run 1 and 2 specific); // In case there is some corner case between Run 1 and Run 2, simply branch further this one + // *) Particle cuts on Test case; + // *) Toy NUA. + + // 44:ParticleCuts + + if (tc.fVerboseForEachParticle) { + StartFunction(__FUNCTION__); + } + + // a) Particle cuts on reconstructed, and corresponding MC truth simulated (common to Run 3, Run 2 and Run 1) ... + if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1 || rs == eQA) { + + // *) Phi: + if (pc.fUseParticleCuts[ePhi]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, ePhi, eCutCounterBinning); + } else if (track.phi() < pc.fdParticleCuts[ePhi][eMin] || track.phi() > pc.fdParticleCuts[ePhi][eMax] || TMath::Abs(track.phi() - pc.fdParticleCuts[ePhi][eMax]) < tc.fFloatingPointPrecision) { + if (!ParticleCut(eRec, ePhi, cutModus)) { + return false; + } + } + } + + // *) Pt: + if (pc.fUseParticleCuts[ePt]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, ePt, eCutCounterBinning); + } else if (track.pt() < pc.fdParticleCuts[ePt][eMin] || track.pt() > pc.fdParticleCuts[ePt][eMax] || TMath::Abs(track.pt() - pc.fdParticleCuts[ePt][eMax]) < tc.fFloatingPointPrecision) { + if (!ParticleCut(eRec, ePt, cutModus)) { + return false; + } + } + } + + // *) Eta: + if (pc.fUseParticleCuts[eEta]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, eEta, eCutCounterBinning); + } else if (track.eta() < pc.fdParticleCuts[eEta][eMin] || track.eta() > pc.fdParticleCuts[eEta][eMax] || TMath::Abs(track.eta() - pc.fdParticleCuts[eEta][eMax]) < tc.fFloatingPointPrecision) { + if (!ParticleCut(eRec, eEta, cutModus)) { + return false; + } + } + } + + // *) Charge: + if (pc.fUseParticleCuts[eCharge]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, eCharge, eCutCounterBinning); + } else if (0 == track.sign() || track.sign() < pc.fdParticleCuts[eCharge][eMin] || track.sign() > pc.fdParticleCuts[eCharge][eMax]) { + // With first condition, I always throw away neutral particles. + // I can use safely == here, because track.sign() returns short int. + if (!ParticleCut(eRec, eCharge, cutModus)) { + return false; + } + } + } + + // *) tpcNClsFindable: + if (pc.fUseParticleCuts[etpcNClsFindable]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, etpcNClsFindable, eCutCounterBinning); + } else if (track.tpcNClsFindable() < pc.fdParticleCuts[etpcNClsFindable][eMin] || track.tpcNClsFindable() > pc.fdParticleCuts[etpcNClsFindable][eMax]) { + if (!ParticleCut(eRec, etpcNClsFindable, cutModus)) { + return false; + } + } + } + + // *) tpcNClsShared: + if (pc.fUseParticleCuts[etpcNClsShared]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, etpcNClsShared, eCutCounterBinning); + } else if (track.tpcNClsShared() < pc.fdParticleCuts[etpcNClsShared][eMin] || track.tpcNClsShared() > pc.fdParticleCuts[etpcNClsShared][eMax]) { + if (!ParticleCut(eRec, etpcNClsShared, cutModus)) { + return false; + } + } + } + + // *) itsChi2NCl + if (pc.fUseParticleCuts[eitsChi2NCl]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, eitsChi2NCl, eCutCounterBinning); + } else if (track.itsChi2NCl() < pc.fdParticleCuts[eitsChi2NCl][eMin] || track.itsChi2NCl() > pc.fdParticleCuts[eitsChi2NCl][eMax]) { + if (!ParticleCut(eRec, eitsChi2NCl, cutModus)) { + return false; + } + } + } + + // *) tpcNClsFound: + if (pc.fUseParticleCuts[etpcNClsFound]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, etpcNClsFound, eCutCounterBinning); + } else if (track.tpcNClsFound() < pc.fdParticleCuts[etpcNClsFound][eMin] || track.tpcNClsFound() > pc.fdParticleCuts[etpcNClsFound][eMax]) { + if (!ParticleCut(eRec, etpcNClsFound, cutModus)) { + return false; + } + } + } + + // *) tpcNClsCrossedRows: + if (pc.fUseParticleCuts[etpcNClsCrossedRows]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, etpcNClsCrossedRows, eCutCounterBinning); + } else if (track.tpcNClsCrossedRows() < pc.fdParticleCuts[etpcNClsCrossedRows][eMin] || track.tpcNClsCrossedRows() > pc.fdParticleCuts[etpcNClsCrossedRows][eMax]) { + if (!ParticleCut(eRec, etpcNClsCrossedRows, cutModus)) { + return false; + } + } + } + + // *) itsNCls: + if (pc.fUseParticleCuts[eitsNCls]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, eitsNCls, eCutCounterBinning); + } else if (track.itsNCls() < pc.fdParticleCuts[eitsNCls][eMin] || track.itsNCls() > pc.fdParticleCuts[eitsNCls][eMax]) { + if (!ParticleCut(eRec, eitsNCls, cutModus)) { + return false; + } + } + } + + // *) itsNClsInnerBarrel: + if (pc.fUseParticleCuts[eitsNClsInnerBarrel]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, eitsNClsInnerBarrel, eCutCounterBinning); + } else if (track.itsNClsInnerBarrel() < pc.fdParticleCuts[eitsNClsInnerBarrel][eMin] || track.itsNClsInnerBarrel() > pc.fdParticleCuts[eitsNClsInnerBarrel][eMax]) { + if (!ParticleCut(eRec, eitsNClsInnerBarrel, cutModus)) { + return false; + } + } + } + + // *) tpcCrossedRowsOverFindableCls: + if (pc.fUseParticleCuts[etpcCrossedRowsOverFindableCls]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, etpcCrossedRowsOverFindableCls, eCutCounterBinning); + } else if (track.tpcCrossedRowsOverFindableCls() < pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMin] || track.tpcCrossedRowsOverFindableCls() > pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMax] || TMath::Abs(track.tpcCrossedRowsOverFindableCls() - pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMax]) < tc.fFloatingPointPrecision) { + if (!ParticleCut(eRec, etpcCrossedRowsOverFindableCls, cutModus)) { + return false; + } + } + } + + // *) tpcFoundOverFindableCls: + if (pc.fUseParticleCuts[etpcFoundOverFindableCls]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, etpcFoundOverFindableCls, eCutCounterBinning); + } else if (track.tpcFoundOverFindableCls() < pc.fdParticleCuts[etpcFoundOverFindableCls][eMin] || track.tpcFoundOverFindableCls() > pc.fdParticleCuts[etpcFoundOverFindableCls][eMax] || TMath::Abs(track.tpcFoundOverFindableCls() - pc.fdParticleCuts[etpcFoundOverFindableCls][eMax]) < tc.fFloatingPointPrecision) { + if (!ParticleCut(eRec, etpcFoundOverFindableCls, cutModus)) { + return false; + } + } + } + + // *) tpcFractionSharedCls: + if (pc.fUseParticleCuts[etpcFractionSharedCls]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, etpcFractionSharedCls, eCutCounterBinning); + } else if (track.tpcFractionSharedCls() < pc.fdParticleCuts[etpcFractionSharedCls][eMin] || track.tpcFractionSharedCls() > pc.fdParticleCuts[etpcFractionSharedCls][eMax] || TMath::Abs(track.tpcFractionSharedCls() - pc.fdParticleCuts[etpcFractionSharedCls][eMax]) < tc.fFloatingPointPrecision) { + if (!ParticleCut(eRec, etpcFractionSharedCls, cutModus)) { + return false; + } + } + } + + // *) tpcChi2NCl: + if (pc.fUseParticleCuts[etpcChi2NCl]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, etpcChi2NCl, eCutCounterBinning); + } else if (track.tpcChi2NCl() < pc.fdParticleCuts[etpcChi2NCl][eMin] || track.tpcChi2NCl() > pc.fdParticleCuts[etpcChi2NCl][eMax] || TMath::Abs(track.tpcChi2NCl() - pc.fdParticleCuts[etpcChi2NCl][eMax]) < tc.fFloatingPointPrecision) { + if (!ParticleCut(eRec, etpcChi2NCl, cutModus)) { + return false; + } + } + } + + // *) dcaXY: + if (pc.fUseParticleCuts[edcaXY]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, edcaXY, eCutCounterBinning); + } else if (track.dcaXY() < pc.fdParticleCuts[edcaXY][eMin] || track.dcaXY() > pc.fdParticleCuts[edcaXY][eMax] || TMath::Abs(track.dcaXY() - pc.fdParticleCuts[edcaXY][eMax]) < tc.fFloatingPointPrecision) { + if (!ParticleCut(eRec, edcaXY, cutModus)) { + return false; + } + } + } + + // *) dcaZ: + if (pc.fUseParticleCuts[edcaZ]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, edcaZ, eCutCounterBinning); + } else if (track.dcaZ() < pc.fdParticleCuts[edcaZ][eMin] || track.dcaZ() > pc.fdParticleCuts[edcaZ][eMax] || TMath::Abs(track.dcaZ() - pc.fdParticleCuts[edcaZ][eMax]) < tc.fFloatingPointPrecision) { + if (!ParticleCut(eRec, edcaZ, cutModus)) { + return false; + } + } + } + + // *) trackCutFlag: + if (pc.fUseParticleCuts[etrackCutFlag]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, etrackCutFlag, eCutCounterBinning); + } else if (!track.trackCutFlag()) { + if (!ParticleCut(eRec, etrackCutFlag, cutModus)) { + return false; + } + } + } + + // *) trackCutFlagFb1: + if (pc.fUseParticleCuts[etrackCutFlagFb1]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, etrackCutFlagFb1, eCutCounterBinning); + } else if (!track.trackCutFlagFb1()) { + if (!ParticleCut(eRec, etrackCutFlagFb1, cutModus)) { + return false; + } + } + } + + // *) trackCutFlagFb2: + if (pc.fUseParticleCuts[etrackCutFlagFb2]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, etrackCutFlagFb2, eCutCounterBinning); + } else if (!track.trackCutFlagFb2()) { + if (!ParticleCut(eRec, etrackCutFlagFb2, cutModus)) { + return false; + } + } + } + + // *) isQualityTrack: + if (pc.fUseParticleCuts[eisQualityTrack]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, eisQualityTrack, eCutCounterBinning); + } else if (!track.isQualityTrack()) { + if (!ParticleCut(eRec, eisQualityTrack, cutModus)) { + return false; + } + } + } + + // *) isPrimaryTrack: + if (pc.fUseParticleCuts[eisPrimaryTrack]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, eisPrimaryTrack, eCutCounterBinning); + } else if (!track.isPrimaryTrack()) { + if (!ParticleCut(eRec, eisPrimaryTrack, cutModus)) { + return false; + } + } + } + + // *) isInAcceptanceTrack: + if (pc.fUseParticleCuts[eisInAcceptanceTrack]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, eisInAcceptanceTrack, eCutCounterBinning); + } else if (!track.isInAcceptanceTrack()) { + if (!ParticleCut(eRec, eisInAcceptanceTrack, cutModus)) { + return false; + } + } + } + + // *) isGlobalTrack: + if (pc.fUseParticleCuts[eisGlobalTrack]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, eisGlobalTrack, eCutCounterBinning); + } else if (!track.isGlobalTrack()) { + if (!ParticleCut(eRec, eisGlobalTrack, cutModus)) { + return false; + } + } + } + + // *) isPVContributor: + if (pc.fUseParticleCuts[eisPVContributor]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, eisPVContributor, eCutCounterBinning); + } else if (!track.isPVContributor()) { + if (!ParticleCut(eRec, eisPVContributor, cutModus)) { + return false; + } + } + } + + // *) PtDependentDCAxyParameterization: + if (pc.fUseParticleCuts[ePtDependentDCAxyParameterization]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, ePtDependentDCAxyParameterization, eCutCounterBinning); + } else if (TMath::Abs(track.dcaXY()) > pc.fPtDependentDCAxyFormula->Eval(track.pt())) { + if (!ParticleCut(eRec, ePtDependentDCAxyParameterization, cutModus)) { + return false; + } + } + } + + // ... + + // ... and corresponding MC truth simulated: + // See https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx + // See https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + + if (!track.has_mcParticle()) { + LOGF(warning, "No MC particle for this track, skip..."); + return false; // TBI 20231107 re-think. I shouldn't probably get to this point, if MC truth info doesn't exist for this track + } + // auto mcparticle = track.mcParticle(); // corresponding MC truth simulated particle + + // In this branch I can cut additionally and directly on corresponding MC truth simulated, e.g. on mcparticle.pt() + // In case I implement something here, remember to switch from eRec to eSim when calling e.g. ParticleCut(...) + + /* + // *) Phi: TBI 2024-511 re-think if i really cut directly on MC truth kine and other info and keep it in sync with what I did in AliPhysics + if (pc.fUseParticleCuts[ePhi]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eSim, ePhi, eCutCounterBinning); + } else if (mcparticle.phi() < pc.fdParticleCuts[ePhi][eMin] || mcparticle.phi() > pc.fdParticleCuts[ePhi][eMax]) { + if (!ParticleCut(eSim, ePhi, cutModus)) { + return false; + } + } + } + */ + // *) Charge: TBI 20240511 mcparticle.sign() doesn't exist, here most likely i need to cut on the signature of mcparticle.pdg() but check further, because e is negative charge, but PDG is 11, etc. + /* + if (pc.fUseParticleCuts[eCharge]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eSim, eCharge, eCutCounterBinning); + } else if (0 == mcparticle.sign() || mcparticle.sign() < pc.fdParticleCuts[eCharge][eMin] || mcparticle.sign() > pc.fdParticleCuts[eCharge][eMax]) { + // TBI 20240511 with first condition, I always throw away neutral particles, so for the time being that is hardcoded + if (!ParticleCut(eSim, eCharge, cutModus)) { + return false; + } + } + } + */ + // TBI 20240511 add cut on PDG + + // ... + + } // if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + + } // if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { + + // ------------------------------------------------------------------------- + + // b) Particle cuts only on simulated (common to Run 3, Run 2 and Run 1): + // Remark #1: This branch is relevant when processing ONLY simulated data at generator level. + // Remark #2: In this branch, 'track' is always TracksSim = aod::McParticles, see https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { + + // *) Phi: + if (pc.fUseParticleCuts[ePhi]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eSim, ePhi, eCutCounterBinning); + } else if (track.phi() < pc.fdParticleCuts[ePhi][eMin] || track.phi() > pc.fdParticleCuts[ePhi][eMax] || TMath::Abs(track.phi() - pc.fdParticleCuts[ePhi][eMax]) < tc.fFloatingPointPrecision) { + if (!ParticleCut(eSim, ePhi, cutModus)) { + return false; + } + } + } + + // *) Pt: + if (pc.fUseParticleCuts[ePt]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eSim, ePt, eCutCounterBinning); + } else if (track.pt() < pc.fdParticleCuts[ePt][eMin] || track.pt() > pc.fdParticleCuts[ePt][eMax] || TMath::Abs(track.pt() - pc.fdParticleCuts[ePt][eMax]) < tc.fFloatingPointPrecision) { + if (!ParticleCut(eSim, ePt, cutModus)) { + return false; + } + } + } + + // *) Eta: + if (pc.fUseParticleCuts[eEta]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eSim, eEta, eCutCounterBinning); + } else if (track.eta() < pc.fdParticleCuts[eEta][eMin] || track.eta() > pc.fdParticleCuts[eEta][eMax] || TMath::Abs(track.eta() - pc.fdParticleCuts[eEta][eMax]) < tc.fFloatingPointPrecision) { + if (!ParticleCut(eSim, eEta, cutModus)) { + return false; + } + } + } + + /* + // *) Charge: + if (pc.fUseParticleCuts[eCharge]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eSim, eCharge, eCutCounterBinning); + } else if (0 == track.sign() || track.sign() < pc.fdParticleCuts[eCharge][eMin] || track.sign() > pc.fdParticleCuts[eCharge][eMax]) { + // TBI 20240511 with first condition, I always throw away neutral particles, so for the time being that is hardcoded + if (!ParticleCut(eSim, eCharge, cutModus)) { + return false; + } + } + } + */ + // TBI 20240511 add cut on PDG + + // ... + + } // if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { + + // ------------------------------------------------------------------------- + + // c) Particle cuts on reconstructed, and corresponding MC truth simulated (Run 3 specific): + // Remark: I implement here only the particle cuts which are not already in group a) above, and which make sense only for Run 3 data. + if constexpr (rs == eRec || rs == eRecAndSim || rs == eQA) { + + // ... + + // ... and corresponding MC truth simulated (Run 3 specific): + if constexpr (rs == eRecAndSim) { + + if (!track.has_mcParticle()) { + LOGF(warning, "No MC particle for this track, skip..."); + return false; // TBI 20231107 re-think. I shouldn't probably get to this point, if MC truth info doesn't exist for this track + } + // auto mcparticle = track.mcParticle(); // corresponding MC truth simulated particle + + // ... + + } // if constexpr (rs == eRecAndSim) { + + } // if constexpr (rs == eRec || rs == eRecAndSim) { + + // ------------------------------------------------------------------------- + + // d) Particle cuts on simulated (Run 3 specific): + // Remark #1: I implement here only the particle cuts which are not already in group b) above, and which make sense only for Run 3 data. + // Remark #2: In this branch, 'track' is always TracksSim = aod::McParticles, see https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + // See how I handled the case b) above. + if constexpr (rs == eSim) { + + // ... + + } // if constexpr (rs == eSim) { + + // ------------------------------------------------------------------------- + + // e) Particle cuts on reconstructed, and corresponding MC truth simulated (Run 1 and 2 specific): + // Remark: I implement here only the particle cuts which are not already in group a) above, and which make sense only for Run 1 and 2 data. + if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { + + // ... + + // ... and corresponding MC truth simulated: + // See https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx + // See https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + if constexpr (rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + + if (!track.has_mcParticle()) { + LOGF(warning, "No MC particle for this track, skip..."); + return false; // TBI 20231107 re-think. I shouldn't probably get to this point, if MC truth info doesn't exist for this track + } + // auto mcparticle = track.mcParticle(); // corresponding MC truth simulated particle + + // ... + + } // if constexpr (rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + + } // if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { + + // ------------------------------------------------------------------------- + + // f) Event cuts on simulated (Run 1 and 2 specific) + // Remark #1: I implement here only the event cuts which are not already in group b) above, and which make sense only for Run 1 and 2 data. + // Remark #2: In this branch, 'track' is always TracksSim = aod::McParticles, see https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + // See how I handled the case b) above. + if constexpr (rs == eSim_Run2 || rs == eSim_Run1) { + + // ... + + } // if constexpr (rs == eSim_Run2 || rs == eSim_Run1) { + + // ------------------------------------------------------------------------- + + // *) Test case: + if constexpr (rs == eTest) { + // This branch corresponds to process with minimal subscription - I implement just a few example cuts, just for testing purposes. + // Only eRec is support in Test for the time being. + + // *) Phi: + if (pc.fUseParticleCuts[ePhi]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, ePhi, eCutCounterBinning); + } else if (track.phi() < pc.fdParticleCuts[ePhi][eMin] || track.phi() > pc.fdParticleCuts[ePhi][eMax] || TMath::Abs(track.phi() - pc.fdParticleCuts[ePhi][eMax]) < tc.fFloatingPointPrecision) { + if (!ParticleCut(eRec, ePhi, cutModus)) { + return false; + } + } + } + + // *) Pt: + if (pc.fUseParticleCuts[ePt]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, ePt, eCutCounterBinning); + } else if (track.pt() < pc.fdParticleCuts[ePt][eMin] || track.pt() > pc.fdParticleCuts[ePt][eMax] || TMath::Abs(track.pt() - pc.fdParticleCuts[ePt][eMax]) < tc.fFloatingPointPrecision) { + if (!ParticleCut(eRec, ePt, cutModus)) { + return false; + } + } + } + + // *) Eta: + if (pc.fUseParticleCuts[eEta]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eRec, eEta, eCutCounterBinning); + } else if (track.eta() < pc.fdParticleCuts[eEta][eMin] || track.eta() > pc.fdParticleCuts[eEta][eMax] || TMath::Abs(track.eta() - pc.fdParticleCuts[eEta][eMax]) < tc.fFloatingPointPrecision) { + if (!ParticleCut(eRec, eEta, cutModus)) { + return false; + } + } + } + + // ... + + } // if constexpr (rs == eTest) { + + // ------------------------------------------------------------------------- + + // *) Toy NUA: + if (nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF]) { + + // Remark: I do not for the time being add Toy NUA cuts to particle cut counters, since in this case I can inspect direcly from phi, pt and eta distributions. + + // Local kine variables on which support for Toy NUA is implemented and applied: + double dPhi = 0.; + double dPt = 0.; + double dEta = 0.; + + // *) Apply Toy NUA on info available in reconstructed (and the corresponding MC truth simulated track); + if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { + dPhi = track.phi(); + dPt = track.pt(); + dEta = track.eta(); + + // Apply NUA on these kine variables: + if (nua.fApplyNUAPDF[ePhiNUAPDF] && !Accept(dPhi, ePhiNUAPDF)) { + return false; + } + if (nua.fApplyNUAPDF[ePtNUAPDF] && !Accept(dPt, ePtNUAPDF)) { + return false; + } + if (nua.fApplyNUAPDF[eEtaNUAPDF] && !Accept(dEta, eEtaNUAPDF)) { + return false; + } + + // ... and corresponding MC truth simulated ( see https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx ): + if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + if (!track.has_mcParticle()) { + LOGF(warning, "No MC particle for this track, skip..."); + return false; // TBI 20231107 re-think. I shouldn't probably get to this point, if MC truth info doesn't exist for this particle + } + auto mcparticle = track.mcParticle(); // corresponding MC truth simulated particle + dPhi = mcparticle.phi(); + dPt = mcparticle.pt(); + dEta = mcparticle.eta(); + + // Apply NUA on these kine variables: + if (nua.fApplyNUAPDF[ePhiNUAPDF] && !Accept(dPhi, ePhiNUAPDF)) { + return false; + } + if (nua.fApplyNUAPDF[ePtNUAPDF] && !Accept(dPt, ePtNUAPDF)) { + return false; + } + if (nua.fApplyNUAPDF[eEtaNUAPDF] && !Accept(dEta, eEtaNUAPDF)) { + return false; + } + + } // if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + } // if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { + + // *) Apply Toy NUA on info available only in simulated data: + if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { + // Remark: in this branch, 'track' is always TracksSim = aod::McParticles + dPhi = track.phi(); + dPt = track.pt(); + dEta = track.eta(); + + // Apply NUA on these kine variables: + if (nua.fApplyNUAPDF[ePhiNUAPDF] && !Accept(dPhi, ePhiNUAPDF)) { + return false; + } + if (nua.fApplyNUAPDF[ePtNUAPDF] && !Accept(dPt, ePtNUAPDF)) { + return false; + } + if (nua.fApplyNUAPDF[eEtaNUAPDF] && !Accept(dEta, eEtaNUAPDF)) { + return false; + } + } // if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { + + } // if(nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF]) { + + return true; + +} // template bool ParticleCuts(T const& track, eCutModus cutModus) + +//============================================================ + +bool ParticleCut(int rs, int particleCut, eCutModus cutModus) +{ + // Helper function to reduce code bloat in ParticleCuts(). It's meant to be used only in ParticleCuts(). + + // Remark: Remember that as a second argument I cannot use enum eParticleCuts, because here in one go I take both enum eParticleCuts and enum eParticleHistograms . + + switch (cutModus) { + case eCut: { + if (tc.fVerboseForEachParticle) { + LOGF(info, "\033[1;31mParticle didn't pass the cut: %s\033[0m", pc.fParticleCutName[particleCut].Data()); + } + return false; + break; + } + case eCutCounterBinning: { + pc.fParticleCutCounterMap[rs]->Add(pc.fParticleCutCounterBinNumber[rs], particleCut); + pc.fParticleCutCounterMapInverse[rs]->Add(particleCut, pc.fParticleCutCounterBinNumber[rs]); + pc.fParticleCutCounterBinNumber[rs]++; // yes + return true; + break; + } + case eCutCounterAbsolute: { + pc.fParticleCutCounterHist[rs][eAbsolute]->Fill(pc.fParticleCutCounterMapInverse[rs]->GetValue(particleCut)); + return true; // yes, so that I can proceed with another cut in ParticleCuts + break; + } + case eCutCounterSequential: { + pc.fParticleCutCounterHist[rs][eSequential]->Fill(pc.fParticleCutCounterMapInverse[rs]->GetValue(particleCut)); + return false; // yes, so that I bail out from ParticleCuts + break; + } + default: { + LOGF(fatal, "\033[1;31m%s at line %d : This cutModus = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, static_cast(cutModus)); + break; + } + } // switch(cutModus) + + return false; // obsolete, but it suppresses the warning... + +} // bool ParticleCut(int rs, int particleCut, eCutModus cutModus) + +//============================================================ + +template +void FillParticleHistograms(T const& track, eBeforeAfter ba, int weight = 1) +{ + // Fill all particle histograms for reconstructed and simulated data. + + // a) Fill reconstructed, and corresponding MC truth simulated (common to Run 3, Run 2 and Run 1); + // b) Fill only simulated (common to Run 3, Run 2 and Run 1); + // c) Fill reconstructed, and corresponding MC truth simulated (Run 3 specific); + // d) Fill only simulated (Run 3 specific); + // e) Fill reconstructed, and corresponding MC truth simulated (Run 1 and 2 specific); // In case there is some corner case between Run 1 and Run 2, simply branch further this one + // f) Fill only simulated (Run 1 and 2 specific); // In case there is some corner case between Run 1 and Run 2, simply branch further this one + // i) Test case. + + // Remark #1: Why weight is introduced as 3rd argument, see explanation in BanishmentLoopOverParticles. + // The efficiency loss for default fill between weight = 1 and previous implementation with no weight, is negligible. + // Remark #2: After calling BanishmentLoopOverParticles, the GetMean(), GetRMS(), GetStdDev(), skewness, kurtosis, etc., of histogram are unaffected. + // But GetMeanErorr(), GetRMSError(), etc. are affected. + // For instance, GetMean() remains the same, because (x+y)/(1+1) = (x+y+z-z)(1+1+1-1). But whenever weight in the formula is taken directly to some higher power, + // like in the calculation of GetMeanError(), this idea with BanishmentLoopOverParticles is not applicable (also when I enable Setw2() in histograms). + // Since from particle histograms I only care about the number of entries, I rarely need even GetMean(), and basically never GetMeanError(), + // I use BanishmentLoopOverParticles . Alternatively, I would need new set of histograms, fill them separately, etc. + + if (tc.fVerboseForEachParticle) { + StartFunction(__FUNCTION__); + } + + if (tc.fInsanityCheckForEachParticle) { + if (1 != TMath::Abs(weight)) { + LOGF(fatal, "\033[1;31m%s at line %d : in the current implementation, weight for particle histograms can be only +1 or -1, weight = %d\033[0m", __FUNCTION__, __LINE__, weight); + } + } + + // a) Fill reconstructed ... (common to Run 3, Run 2 and Run 1): + if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1 || rs == eQA) { + // Remark: Remember to use only eRec and eSim as array indices in histos, also for rs == eRecAndSim, etc. TBI 20240504 shall I introduce generic enum egRec and egSim for this sake? + // TBI 20240414 also here have to hardcode 'eRec', because 'rs' spans over all enums in eRecSim => I definitely need 'generic Rec' case, perhaps via TExMap ? + // But I have already tc.fProcess[eGenericRec] and tc.fProcess[eGenericRecSim], available, shall I simply re-use them? + + // 1D: + if (ph.fFillParticleHistograms) { + // From o2::aod::Tracks + !ph.fParticleHistograms[ePhi][eRec][ba] ? true : ph.fParticleHistograms[ePhi][eRec][ba]->Fill(track.phi(), weight); + !ph.fParticleHistograms[ePt][eRec][ba] ? true : ph.fParticleHistograms[ePt][eRec][ba]->Fill(track.pt(), weight); + !ph.fParticleHistograms[eEta][eRec][ba] ? true : ph.fParticleHistograms[eEta][eRec][ba]->Fill(track.eta(), weight); + !ph.fParticleHistograms[eCharge][eRec][ba] ? true : ph.fParticleHistograms[eCharge][eRec][ba]->Fill(track.sign(), weight); + + // From o2::aod::TracksExtra_001 + !ph.fParticleHistograms[etpcNClsFindable][eRec][ba] ? true : ph.fParticleHistograms[etpcNClsFindable][eRec][ba]->Fill(track.tpcNClsFindable(), weight); + !ph.fParticleHistograms[etpcNClsShared][eRec][ba] ? true : ph.fParticleHistograms[etpcNClsShared][eRec][ba]->Fill(track.tpcNClsShared(), weight); + !ph.fParticleHistograms[eitsChi2NCl][eRec][ba] ? true : ph.fParticleHistograms[eitsChi2NCl][eRec][ba]->Fill(track.itsChi2NCl(), weight); + !ph.fParticleHistograms[etpcNClsFound][eRec][ba] ? true : ph.fParticleHistograms[etpcNClsFound][eRec][ba]->Fill(track.tpcNClsFound(), weight); + !ph.fParticleHistograms[etpcNClsCrossedRows][eRec][ba] ? true : ph.fParticleHistograms[etpcNClsCrossedRows][eRec][ba]->Fill(track.tpcNClsCrossedRows(), weight); + !ph.fParticleHistograms[eitsNCls][eRec][ba] ? true : ph.fParticleHistograms[eitsNCls][eRec][ba]->Fill(track.itsNCls(), weight); + !ph.fParticleHistograms[eitsNClsInnerBarrel][eRec][ba] ? true : ph.fParticleHistograms[eitsNClsInnerBarrel][eRec][ba]->Fill(track.itsNClsInnerBarrel(), weight); + !ph.fParticleHistograms[etpcCrossedRowsOverFindableCls][eRec][ba] ? true : ph.fParticleHistograms[etpcCrossedRowsOverFindableCls][eRec][ba]->Fill(track.tpcCrossedRowsOverFindableCls(), weight); + !ph.fParticleHistograms[etpcFoundOverFindableCls][eRec][ba] ? true : ph.fParticleHistograms[etpcFoundOverFindableCls][eRec][ba]->Fill(track.tpcFoundOverFindableCls(), weight); + !ph.fParticleHistograms[etpcFractionSharedCls][eRec][ba] ? true : ph.fParticleHistograms[etpcFractionSharedCls][eRec][ba]->Fill(track.tpcFractionSharedCls(), weight); + !ph.fParticleHistograms[etpcChi2NCl][eRec][ba] ? true : ph.fParticleHistograms[etpcChi2NCl][eRec][ba]->Fill(track.tpcChi2NCl(), weight); + + // From o2::aod::TracksDCA + // Remark: For this one, in Run 3 workflow I need helper task o2-analysis-track-propagation, while in Run 2 and 1 I need o2-analysis-trackextension . + !ph.fParticleHistograms[edcaXY][eRec][ba] ? true : ph.fParticleHistograms[edcaXY][eRec][ba]->Fill(track.dcaXY(), weight); + !ph.fParticleHistograms[edcaZ][eRec][ba] ? true : ph.fParticleHistograms[edcaZ][eRec][ba]->Fill(track.dcaZ(), weight); + } + + // 2D: + if (ph.fFillParticleHistograms2D) { + !ph.fParticleHistograms2D[ePhiPt][eRec][ba] ? true : ph.fParticleHistograms2D[ePhiPt][eRec][ba]->Fill(track.phi(), track.pt(), weight); + !ph.fParticleHistograms2D[ePhiEta][eRec][ba] ? true : ph.fParticleHistograms2D[ePhiEta][eRec][ba]->Fill(track.phi(), track.eta(), weight); + } // if (ph.fFillParticleHistograms2D) { + + // nD (THnSparse): + if (ba == eAfter) { // yes, I feel sparse histograms only AFTER cuts for the time being + // **) eDWPhi : here the fundamental 0-th axis never to be projected out is "phi" + if (ph.fBookParticleSparseHistograms[eDWPhi]) { + // Remark: It is mandatory that ordering in initialization here resembles the ordering in enum eDiffPhiWeights + double vector[eDiffPhiWeights_N] = {track.phi(), track.pt(), track.eta(), static_cast(track.sign()), ebye.fCentrality, ebye.fVz}; + ph.fParticleSparseHistograms[eDWPhi][eRec]->Fill(vector, weight); + } + // **) eDWPt : here the fundamental 0-th axis never to be projected out is "pt" + if (ph.fBookParticleSparseHistograms[eDWPt]) { + // Remark: It is mandatory that ordering in initialization here resembles the ordering in enum eDiffPtWeights + double vector[eDiffPtWeights_N] = {track.pt()}; + ph.fParticleSparseHistograms[eDWPt][eRec]->Fill(vector, weight); + } + // **) eDWEta : here the fundamental 0-th axis never to be projected out is "eta" + if (ph.fBookParticleSparseHistograms[eDWEta]) { + // Remark: It is mandatory that ordering in initialization here resembles the ordering in enum eDiffEtaWeights + double vector[eDiffEtaWeights_N] = {track.eta()}; + ph.fParticleSparseHistograms[eDWEta][eRec]->Fill(vector, weight); + } + } // if (ba == eAfter) { + + // QA: + if (qa.fFillQAParticleHistograms2D) { + !qa.fQAParticleHistograms2D[ePt_vs_dcaXY][eRec][ba] ? true : qa.fQAParticleHistograms2D[ePt_vs_dcaXY][eRec][ba]->Fill(track.pt(), track.dcaXY(), weight); + } + if ((qa.fFillQAParticleEventHistograms2D || qa.fFillQACorrelationsVsHistograms2D || qa.fFillQACorrelationsVsInteractionRateVsProfiles2D) && qa.fQAParticleEventProEbyE[eRec][ba]) { + // Here I only fill the helper profile to get average of requested particle variable for current event: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eitsNClsEbyE) - 0.5, track.itsNCls(), weight); + + if (track.eta() < 0.) { + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eitsNClsNegEtaEbyE) - 0.5, track.itsNCls(), weight); + } else if (track.eta() > 0.) { // TBI 20241214 for the time being, I do not care about the corner case eta = 0. + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eitsNClsPosEtaEbyE) - 0.5, track.itsNCls(), weight); + } + + if (-0.8 < track.eta() && track.eta() < -0.4) { + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eEta0804EbyE) - 0.5, track.eta(), weight); + } else if (-0.4 < track.eta() && track.eta() < 0.0) { + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eEta0400EbyE) - 0.5, track.eta(), weight); + } else if (0.0 < track.eta() && track.eta() < 0.4) { + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eEta0004EbyE) - 0.5, track.eta(), weight); + } else if (0.4 < track.eta() && track.eta() < 0.8) { + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eEta0408EbyE) - 0.5, track.eta(), weight); + } + + if (0.0 < track.pt() && track.pt() < 0.5) { + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(ePt0005EbyE) - 0.5, track.pt(), weight); + } else if (0.5 < track.pt() && track.pt() < 1.0) { + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(ePt0510EbyE) - 0.5, track.pt(), weight); + } else if (1.0 < track.pt() && track.pt() < 5.0) { + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(ePt1050EbyE) - 0.5, track.pt(), weight); + } + + // eMeanPhi: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eMeanPhi) - 0.5, track.phi(), weight); + + // eMeanPt: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eMeanPt) - 0.5, track.pt(), weight); + + // eMeanEta: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eMeanEta) - 0.5, track.eta(), weight); + + // eMeanCharge: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eMeanCharge) - 0.5, track.sign(), weight); + + // eMeantpcNClsFindable: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eMeantpcNClsFindable) - 0.5, track.tpcNClsFindable(), weight); + + // eMeantpcNClsShared: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eMeantpcNClsShared) - 0.5, track.tpcNClsShared(), weight); + + // eMeanitsChi2NCl: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eMeanitsChi2NCl) - 0.5, track.itsChi2NCl(), weight); + + // eMeantpcNClsFound: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eMeantpcNClsFound) - 0.5, track.tpcNClsFound(), weight); + + // eMeantpcNClsCrossedRow: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eMeantpcNClsCrossedRows) - 0.5, track.tpcNClsCrossedRows(), weight); + + // eMeanitsNCls: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eMeanitsNCls) - 0.5, track.itsNCls(), weight); + + // eMeanitsNClsInnerBarrel: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eMeanitsNClsInnerBarrel) - 0.5, track.itsNClsInnerBarrel(), weight); + + // eMeantpcCrossedRowsOverFindableCl: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eMeantpcCrossedRowsOverFindableCls) - 0.5, track.tpcCrossedRowsOverFindableCls(), weight); + + // eMeantpcFoundOverFindableCl: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eMeantpcFoundOverFindableCls) - 0.5, track.tpcFoundOverFindableCls(), weight); + + // eMeantpcFractionSharedCls: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eMeantpcFractionSharedCls) - 0.5, track.tpcFractionSharedCls(), weight); + + // eMeantpcChi2NCl: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eMeantpcChi2NCl) - 0.5, track.tpcChi2NCl(), weight); + + // eMeandcaXY: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eMeandcaXY) - 0.5, track.dcaXY(), weight); + + // eMeandcaZ: + qa.fQAParticleEventProEbyE[eRec][ba]->Fill(static_cast(eMeandcaZ) - 0.5, track.dcaZ(), weight); + + // ... + + } // if ... + + // ... and corresponding MC truth simulated (common to Run 3, Run 2 and Run 1) + // See https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx + // See https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + + if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + if (!track.has_mcParticle()) { + LOGF(warning, " No MC particle for this track, skip..."); + return; + } + auto mcparticle = track.mcParticle(); // corresponding MC truth simulated particle + + // 1D: + if (ph.fFillParticleHistograms) { + !ph.fParticleHistograms[ePhi][eSim][ba] ? true : ph.fParticleHistograms[ePhi][eSim][ba]->Fill(mcparticle.phi(), weight); + !ph.fParticleHistograms[ePt][eSim][ba] ? true : ph.fParticleHistograms[ePt][eSim][ba]->Fill(mcparticle.pt(), weight); + !ph.fParticleHistograms[eEta][eSim][ba] ? true : ph.fParticleHistograms[eEta][eSim][ba]->Fill(mcparticle.eta(), weight); + // !ph.fParticleHistograms[eCharge][eSim][ba] ? true : ph.fParticleHistograms[eCharge][eSim][ba]->Fill( ... ); // TBI 20240511 there is no mcparticle.sign()) + !ph.fParticleHistograms[ePDG][eSim][ba] ? true : ph.fParticleHistograms[ePDG][eSim][ba]->Fill(mcparticle.pdgCode(), weight); // TBI 20240512 this one gets filles correctly, deduce from it charge signature + } + + // 2D: + if (ph.fFillParticleHistograms2D) { + !ph.fParticleHistograms2D[ePhiPt][eSim][ba] ? true : ph.fParticleHistograms2D[ePhiPt][eSim][ba]->Fill(mcparticle.phi(), mcparticle.pt(), weight); + !ph.fParticleHistograms2D[ePhiEta][eSim][ba] ? true : ph.fParticleHistograms2D[ePhiEta][eSim][ba]->Fill(mcparticle.phi(), mcparticle.eta(), weight); + } // if(ph.fFillParticleHistograms2D) { + + // nD (THnSparse): + if (ba == eAfter) { // yes, I feel sparse histograms only AFTER cuts for the time being + // **) eDWPhi : here the fundamental 0-th axis never to be projected out is "phi" + if (ph.fBookParticleSparseHistograms[eDWPhi]) { + // Remark: It is mandatory that ordering in initialization here resembles the ordering in enum eDiffPhiWeights + double vector[eDiffPhiWeights_N] = {mcparticle.phi(), mcparticle.pt(), mcparticle.eta(), 0., 0., 0.}; + // TBI 20250223 I do not have access to particle charge signature here => I set it to 0 temporarily. + // Then, I did not calculate and store centrality for "sim" => I set it to 0 temporarily. + // Same for vertex z, I could trivially extend ebye.fVz also for "sim" dimension => I set it to 0 temporarily here, until that's done. + ph.fParticleSparseHistograms[eDWPhi][eSim]->Fill(vector, weight); + } + // **) eDWPt : here the fundamental 0-th axis never to be projected out is "pt" + if (ph.fBookParticleSparseHistograms[eDWPt]) { + // Remark: It is mandatory that ordering in initialization here resembles the ordering in enum eDiffPtWeights + double vector[eDiffPtWeights_N] = {mcparticle.pt()}; + ph.fParticleSparseHistograms[eDWPt][eSim]->Fill(vector, weight); + } + // **) eDWEta : here the fundamental 0-th axis never to be projected out is "eta" + if (ph.fBookParticleSparseHistograms[eDWEta]) { + // Remark: It is mandatory that ordering in initialization here resembles the ordering in enum eDiffEtaWeights + double vector[eDiffEtaWeights_N] = {mcparticle.eta()}; + ph.fParticleSparseHistograms[eDWEta][eSim]->Fill(vector, weight); + } + } // if (ba == eAfter) { + + } // if constexpr (rs == eRecAndSim || rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + } // if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { + + // ----------------------------------------------------------------------------- + + // b) Fill only simulated (common to Run 3, Run 2 and Run 1): + // Remark #1: This branch is relevant when processing ONLY simulated data at generator level. + // Remark #2: In this branch, 'track' is always TracksSim = aod::McParticles, see https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { + // 1D: + if (ph.fFillParticleHistograms) { + !ph.fParticleHistograms[ePhi][eSim][ba] ? true : ph.fParticleHistograms[ePhi][eSim][ba]->Fill(track.phi(), weight); + !ph.fParticleHistograms[ePt][eSim][ba] ? true : ph.fParticleHistograms[ePt][eSim][ba]->Fill(track.pt(), weight); + !ph.fParticleHistograms[eEta][eSim][ba] ? true : ph.fParticleHistograms[eEta][eSim][ba]->Fill(track.eta(), weight); + // !ph.fParticleHistograms[eCharge][eSim][ba] ? true : ph.fParticleHistograms[eCharge][eSim][ba]->Fill( ... ); // TBI 20240511 there is no mcparticle.sign()) + !ph.fParticleHistograms[ePDG][eSim][ba] ? true : ph.fParticleHistograms[ePDG][eSim][ba]->Fill(track.pdgCode(), weight); + } // if(ph.fFillParticleHistograms) { + + // 2D: + if (ph.fFillParticleHistograms2D) { + !ph.fParticleHistograms2D[ePhiPt][eSim][ba] ? true : ph.fParticleHistograms2D[ePhiPt][eSim][ba]->Fill(track.phi(), track.pt(), weight); + !ph.fParticleHistograms2D[ePhiEta][eSim][ba] ? true : ph.fParticleHistograms2D[ePhiEta][eSim][ba]->Fill(track.phi(), track.eta(), weight); + } // if(ph.fFillParticleHistograms2D) { + } // if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { + + // ----------------------------------------------------------------------------- + + // c) Fill reconstructed ... (Run 3 specific): + if constexpr (rs == eRec || rs == eRecAndSim || rs == eQA) { + // TBI 20240511 check If I can use them for Run 2 and Run 1, but extending TracksRecSim_Run2 to Tracks_extra, etc. + // Remark: Remember to use only eRec and eSim as array indices in histos, also for rs == eRecAndSim, etc. TBI 20240504 shall I introduce generic enum egRec and egSim for this sake? + + // ... + + // ... and corresponding MC truth simulated (Run 3 specific): + // See https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx ): + if constexpr (rs == eRecAndSim) { + if (!track.has_mcParticle()) { + LOGF(warning, " No MC particle for this track, skip..."); + return; + } + + // auto mcparticle = track.mcParticle(); // corresponding MC truth simulated particle + + // ... + + } // if constexpr (rs == eRecAndSim) { + } // if constexpr (rs == eRec || rs == eRecAndSim) { + + // ----------------------------------------------------------------------------- + + // d) Fill only simulated (Run 3 specific): + // Remark #1: I fill here only the histograms which are not already filled in group b) above, and which make sense only for Run 3 data. + // Remark #2: In this branch 'track' is always TracksSim = aod::McParticles, see https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + // See how I handled the case b) above. + if constexpr (rs == eSim) { + + // ... + + } // if constexpr (rs == eSim) { + + // ----------------------------------------------------------------------------- + + // e) Fill reconstructed ... (Run 1 and 2 specific): + // Remark: I fill here only the histograms which are not already filled in group a) above, and which make sense only for Run 1 and 2 data. + if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { + + // ... + + // ... and corresponding MC truth simulated (Run 1 and 2 specific): + // See https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx ): + if constexpr (rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + if (!track.has_mcParticle()) { + LOGF(warning, " No MC particle for this track, skip..."); + return; + } - // c) Test case: + // auto mcparticle = track.mcParticle(); // corresponding MC truth simulated particle + + // ... + + } // if constexpr (rs == eRecAndSim_Run2 || rs == eRecAndSim_Run1) { + } // if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { + + // ----------------------------------------------------------------------------- + + // f) Fill only simulated (Run 1 and 2 specific): + // Remark #1: I fill here only histograms which are not already filled in group b) above, and which make sense only for Run 1 and 2 data. + // Remark #2: In this branch In this branch 'track' is always TracksSim = aod::McParticles, see https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + // See how I handled the case b) above. + if constexpr (rs == eSim_Run2 || rs == eSim_Run1) { + + // ... + + } // if constexpr (rs == eSim_Run2 || rs == eSim_Run1) { + + // ----------------------------------------------------------------------------- + + // *) Test case: if constexpr (rs == eTest) { - // TBI 20240223 for the time being, eTest fills eRec histos: - !ph.fParticleHistograms[ePhi][eRec][ba] ? true : ph.fParticleHistograms[ePhi][eRec][ba]->Fill(track.phi()); - !ph.fParticleHistograms[ePt][eRec][ba] ? true : ph.fParticleHistograms[ePt][eRec][ba]->Fill(track.pt()); - !ph.fParticleHistograms[eEta][eRec][ba] ? true : ph.fParticleHistograms[eEta][eRec][ba]->Fill(track.eta()); - } // if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { + // This branch corresponds to process with minimal subscription - I implement just a few example cuts, just for testing purposes. + // Only eRec is support in Test for the time being. + // 1D: + if (ph.fFillParticleHistograms) { + !ph.fParticleHistograms[ePhi][eRec][ba] ? true : ph.fParticleHistograms[ePhi][eRec][ba]->Fill(track.phi(), weight); + !ph.fParticleHistograms[ePt][eRec][ba] ? true : ph.fParticleHistograms[ePt][eRec][ba]->Fill(track.pt(), weight); + !ph.fParticleHistograms[eEta][eRec][ba] ? true : ph.fParticleHistograms[eEta][eRec][ba]->Fill(track.eta(), weight); + } + // 2D: + if (ph.fFillParticleHistograms2D) { + !ph.fParticleHistograms2D[ePhiPt][eRec][ba] ? true : ph.fParticleHistograms2D[ePhiPt][eRec][ba]->Fill(track.phi(), track.pt(), weight); + !ph.fParticleHistograms2D[ePhiEta][eRec][ba] ? true : ph.fParticleHistograms2D[ePhiEta][eRec][ba]->Fill(track.phi(), track.eta(), weight); + } + } // if constexpr (rs == eTest) { } // template void FillParticleHistograms(...) @@ -2046,62 +9463,58 @@ void CalculateCorrelations() // c) Flush the generic Q-vectors. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); } // a) Flush 'n' fill the generic Q-vectors: ResetQ(); - for (Int_t h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { - for (Int_t wp = 0; wp < gMaxCorrelator + 1; wp++) // weight power + for (int h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { + for (int wp = 0; wp < gMaxCorrelator + 1; wp++) // weight power { qv.fQ[h][wp] = qv.fQvector[h][wp]; } } // b) Calculate correlations: - for (Int_t h = 1; h <= gMaxHarmonic; h++) // harmonic + for (int h = 1; h <= gMaxHarmonic; h++) // harmonic { // 2p: if (ebye.fSelectedTracks < 2) { return; } if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s => calculating 2-particle correlations....\033[0m", __PRETTY_FUNCTION__); + LOGF(info, " calculating 2-particle correlations ...."); } TComplex two = Two(h, -h); - Double_t twoC = two.Re(); // cos - // Double_t twoS = two.Im(); // sin - Double_t wTwo = Two(0, 0).Re(); // Weight is 'number of combinations' by default TBI - // 20220809 add support for other weights + double twoC = two.Re(); // cos + // double twoS = two.Im(); // sin + double wTwo = Two(0, 0).Re(); // Weight is 'number of combinations' by default TBI + // 20220809 add support for other weights if (wTwo > 0.0) { twoC /= wTwo; } else { - LOGF(fatal, "In function \033[1;31m%s at line %d, wTwo = %f <=0. ebye.fSelectedTracks = %d\033[0m", __PRETTY_FUNCTION__, __LINE__, wTwo, ebye.fSelectedTracks); + LOGF(fatal, "In function \033[1;31m%s at line %d, wTwo = %f <=0. ebye.fSelectedTracks = %d\033[0m", __FUNCTION__, __LINE__, wTwo, ebye.fSelectedTracks); } - if (nl.fCalculateCustomNestedLoop) { + if (nl.fCalculateCustomNestedLoops) { // e-b-e sanity check: TArrayI* harmonics = new TArrayI(2); harmonics->SetAt(h, 0); harmonics->SetAt(-h, 1); - Double_t nestedLoopValue = this->CalculateCustomNestedLoop(harmonics); - if (TMath::Abs(nestedLoopValue) > 0. && TMath::Abs(twoC - nestedLoopValue) > 1.e-5) { - LOGF(fatal, "in function \033[1;31m%s at line %d, nestedLoopValue = %f is not the same as twoC = %f\033[0m", __PRETTY_FUNCTION__, __LINE__, nestedLoopValue, twoC); + double nestedLoopValue = this->CalculateCustomNestedLoops(harmonics); + if (TMath::Abs(nestedLoopValue) > 0. && TMath::Abs(twoC - nestedLoopValue) > tc.fFloatingPointPrecision) { + LOGF(fatal, "\033[1;31m%s at line %d : nestedLoopValue = %f is not the same as twoC = %f\033[0m", __FUNCTION__, __LINE__, nestedLoopValue, twoC); } else { - LOGF(info, "=> e-b-e check with CustomNestedLoop is OK for isotropic 2-p, harmonic %d", h); + LOGF(info, "\033[1;32m ebye check (integrated) with CustomNestedLoops is OK for isotropic 2-p, harmonic %d\033[0m", h); } delete harmonics; harmonics = NULL; - } // if(nl.fCalculateCustomNestedLoop) + } // if(nl.fCalculateCustomNestedLoops) - /* - // for on-the-fly and internal validation, rescale results with theoretical value: if(fCalculateOnTheFly && fOnTheFlyFlowAmplitudes && - fRescaleWithTheoreticalInput && - TMath::Abs(fOnTheFlyFlowAmplitudes->GetAt(h-1))>0.){twoC/=pow(fOnTheFlyFlowAmplitudes->GetAt(h-1),2.);} - else if(fUseInternalValidation && fInternalValidationAmplitudes && - fRescaleWithTheoreticalInput && - TMath::Abs(fInternalValidationAmplitudes->GetAt(h-1))>0.){twoC/=pow(fInternalValidationAmplitudes->GetAt(h-1),2.);} - */ + // for on-the-fly and internal validation, rescale results with theoretical value: + if (iv.fUseInternalValidation && iv.fRescaleWithTheoreticalInput && iv.fInternalValidationVnPsin[eVn] && TMath::Abs(iv.fInternalValidationVnPsin[eVn]->GetAt(h - 1)) > 0.) { + twoC /= pow(iv.fInternalValidationVnPsin[eVn]->GetAt(h - 1), 2.); + } // integrated: if (mupa.fCorrelationsPro[0][h - 1][AFO_INTEGRATED]) { @@ -2115,44 +9528,62 @@ void CalculateCorrelations() if (mupa.fCorrelationsPro[0][h - 1][AFO_CENTRALITY]) { mupa.fCorrelationsPro[0][h - 1][AFO_CENTRALITY]->Fill(ebye.fCentrality, twoC, wTwo); } + // vs. occupancy: + if (mupa.fCorrelationsPro[0][h - 1][AFO_OCCUPANCY]) { + mupa.fCorrelationsPro[0][h - 1][AFO_OCCUPANCY]->Fill(ebye.fOccupancy, twoC, wTwo); + } + // vs. interaction rate: + if (mupa.fCorrelationsPro[0][h - 1][AFO_INTERACTIONRATE]) { + mupa.fCorrelationsPro[0][h - 1][AFO_INTERACTIONRATE]->Fill(ebye.fInteractionRate, twoC, wTwo); + } + // vs. current run duration: + if (mupa.fCorrelationsPro[0][h - 1][AFO_CURRENTRUNDURATION]) { + mupa.fCorrelationsPro[0][h - 1][AFO_CURRENTRUNDURATION]->Fill(ebye.fCurrentRunDuration, twoC, wTwo); + } + // vs. vertex z position: + if (mupa.fCorrelationsPro[0][h - 1][AFO_VZ]) { + mupa.fCorrelationsPro[0][h - 1][AFO_VZ]->Fill(ebye.fVz, twoC, wTwo); + } // 4p: if (ebye.fSelectedTracks < 4) { continue; } // yes, continue, because I can still calculate 2-p in other harmonics! if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s => calculating 4-particle correlations....\033[0m", __PRETTY_FUNCTION__); + LOGF(info, " calculating 4-particle correlations ...."); } TComplex four = Four(h, h, -h, -h); - Double_t fourC = four.Re(); // cos - // Double_t fourS = four.Im(); // sin - Double_t wFour = Four(0, 0, 0, 0).Re(); // Weight is 'number of combinations' by default TBI_20210515 add support for other weights + double fourC = four.Re(); // cos + // double fourS = four.Im(); // sin + double wFour = Four(0, 0, 0, 0).Re(); // Weight is 'number of combinations' by default TBI_20210515 add support for other weights if (wFour > 0.0) { fourC /= wFour; } else { - LOGF(fatal, "In function \033[1;31m%s at line %d, wFour = %f <=0. ebye.fSelectedTracks = %d\033[0m", __PRETTY_FUNCTION__, __LINE__, wFour, ebye.fSelectedTracks); + LOGF(fatal, "In function \033[1;31m%s at line %d, wFour = %f <=0. ebye.fSelectedTracks = %d\033[0m", __FUNCTION__, __LINE__, wFour, ebye.fSelectedTracks); // TBI 20240110 shall I 'continue' here, instead of bailing out? } - if (nl.fCalculateCustomNestedLoop) { + if (nl.fCalculateCustomNestedLoops) { // e-b-e sanity check: TArrayI* harmonics = new TArrayI(4); harmonics->SetAt(h, 0); harmonics->SetAt(h, 1); harmonics->SetAt(-h, 2); harmonics->SetAt(-h, 3); - Double_t nestedLoopValue = this->CalculateCustomNestedLoop(harmonics); - if (TMath::Abs(nestedLoopValue) > 0. && TMath::Abs(fourC - nestedLoopValue) > 1.e-5) { - LOGF(fatal, "in function \033[1;31m%s at line %d, nestedLoopValue = %f is not the same as fourC = %f\033[0m", __PRETTY_FUNCTION__, __LINE__, nestedLoopValue, fourC); + double nestedLoopValue = this->CalculateCustomNestedLoops(harmonics); + if (TMath::Abs(nestedLoopValue) > 0. && TMath::Abs(fourC - nestedLoopValue) > tc.fFloatingPointPrecision) { + LOGF(fatal, "\033[1;31m%s at line %d : nestedLoopValue = %f is not the same as fourC = %f\033[0m", __FUNCTION__, __LINE__, nestedLoopValue, fourC); } else { - LOGF(info, "=> e-b-e check with CustomNestedLoop is OK for isotropic 4-p, harmonic %d", h); + LOGF(info, "\033[1;32m ebye check (integrated) with CustomNestedLoops is OK for isotropic 4-p, harmonic %d\033[0m", h); } delete harmonics; harmonics = NULL; - } // if(nl.fCalculateCustomNestedLoop) + } // if(nl.fCalculateCustomNestedLoops) - // if(fUseInternalValidation && fInternalValidationAmplitudes && fRescaleWithTheoreticalInput && - // TMath::Abs(fInternalValidationAmplitudes->GetAt(h-1))>0.){fourC/=pow(fInternalValidationAmplitudes->GetAt(h-1),4.);} + // for on-the-fly and internal validation, rescale results with theoretical value: + if (iv.fUseInternalValidation && iv.fRescaleWithTheoreticalInput && iv.fInternalValidationVnPsin[eVn] && TMath::Abs(iv.fInternalValidationVnPsin[eVn]->GetAt(h - 1)) > 0.) { + fourC /= pow(iv.fInternalValidationVnPsin[eVn]->GetAt(h - 1), 4.); + } // integrated: if (mupa.fCorrelationsPro[1][h - 1][AFO_INTEGRATED]) { @@ -2166,26 +9597,42 @@ void CalculateCorrelations() if (mupa.fCorrelationsPro[1][h - 1][AFO_CENTRALITY]) { mupa.fCorrelationsPro[1][h - 1][AFO_CENTRALITY]->Fill(ebye.fCentrality, fourC, wFour); } + // vs. occupancy: + if (mupa.fCorrelationsPro[1][h - 1][AFO_OCCUPANCY]) { + mupa.fCorrelationsPro[1][h - 1][AFO_OCCUPANCY]->Fill(ebye.fOccupancy, fourC, wFour); + } + // vs. interaction rate: + if (mupa.fCorrelationsPro[1][h - 1][AFO_INTERACTIONRATE]) { + mupa.fCorrelationsPro[1][h - 1][AFO_INTERACTIONRATE]->Fill(ebye.fInteractionRate, fourC, wFour); + } + // vs. current run duration: + if (mupa.fCorrelationsPro[1][h - 1][AFO_CURRENTRUNDURATION]) { + mupa.fCorrelationsPro[1][h - 1][AFO_CURRENTRUNDURATION]->Fill(ebye.fCurrentRunDuration, fourC, wFour); + } + // vs. vertex z position: + if (mupa.fCorrelationsPro[1][h - 1][AFO_VZ]) { + mupa.fCorrelationsPro[1][h - 1][AFO_VZ]->Fill(ebye.fVz, fourC, wFour); + } // 6p: if (ebye.fSelectedTracks < 6) { continue; } // yes, continue, because I can still calculate 2-p and 4-p in other harmonics! if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s => calculating 6-particle correlations....\033[0m", __PRETTY_FUNCTION__); + LOGF(info, " calculating 6-particle correlations ...."); } TComplex six = Six(h, h, h, -h, -h, -h); - Double_t sixC = six.Re(); // cos - // Double_t sixS = six.Im(); // sin - Double_t wSix = Six(0, 0, 0, 0, 0, 0).Re(); // Weight is 'number of combinations' by default TBI_20210515 add support for other weights + double sixC = six.Re(); // cos + // double sixS = six.Im(); // sin + double wSix = Six(0, 0, 0, 0, 0, 0).Re(); // Weight is 'number of combinations' by default TBI_20210515 add support for other weights if (wSix > 0.0) { sixC /= wSix; } else { - LOGF(fatal, "In function \033[1;31m%s at line %d, wSix = %f <=0. ebye.fSelectedTracks = %d\033[0m", __PRETTY_FUNCTION__, __LINE__, wSix, ebye.fSelectedTracks); + LOGF(fatal, "In function \033[1;31m%s at line %d, wSix = %f <=0. ebye.fSelectedTracks = %d\033[0m", __FUNCTION__, __LINE__, wSix, ebye.fSelectedTracks); // TBI 20240110 shall I 'continue' here, instead of bailing out? } - if (nl.fCalculateCustomNestedLoop) { + if (nl.fCalculateCustomNestedLoops) { // e-b-e sanity check: TArrayI* harmonics = new TArrayI(6); harmonics->SetAt(h, 0); @@ -2194,18 +9641,20 @@ void CalculateCorrelations() harmonics->SetAt(-h, 3); harmonics->SetAt(-h, 4); harmonics->SetAt(-h, 5); - Double_t nestedLoopValue = this->CalculateCustomNestedLoop(harmonics); - if (TMath::Abs(nestedLoopValue) > 0. && TMath::Abs(sixC - nestedLoopValue) > 1.e-5) { - LOGF(fatal, "in function \033[1;31m%s at line %d, nestedLoopValue = %f is not the same as sixC = %f\033[0m", __PRETTY_FUNCTION__, __LINE__, nestedLoopValue, sixC); + double nestedLoopValue = this->CalculateCustomNestedLoops(harmonics); + if (TMath::Abs(nestedLoopValue) > 0. && TMath::Abs(sixC - nestedLoopValue) > tc.fFloatingPointPrecision) { + LOGF(fatal, "\033[1;31m%s at line %d : nestedLoopValue = %f is not the same as sixC = %f\033[0m", __FUNCTION__, __LINE__, nestedLoopValue, sixC); } else { - LOGF(info, "=> e-b-e check with CustomNestedLoop is OK for isotropic 6-p, harmonic %d", h); + LOGF(info, "\033[1;32m ebye check (integrated) with CustomNestedLoops is OK for isotropic 6-p, harmonic %d\033[0m", h); } delete harmonics; harmonics = NULL; - } // if(nl.fCalculateCustomNestedLoop) + } // if(nl.fCalculateCustomNestedLoops) - // if(fUseInternalValidation && fInternalValidationAmplitudes && fRescaleWithTheoreticalInput && - // TMath::Abs(fInternalValidationAmplitudes->GetAt(h-1))>0.){sixC/=pow(fInternalValidationAmplitudes->GetAt(h-1),4.);} + // for on-the-fly and internal validation, rescale results with theoretical value: + if (iv.fUseInternalValidation && iv.fRescaleWithTheoreticalInput && iv.fInternalValidationVnPsin[eVn] && TMath::Abs(iv.fInternalValidationVnPsin[eVn]->GetAt(h - 1)) > 0.) { + sixC /= pow(iv.fInternalValidationVnPsin[eVn]->GetAt(h - 1), 6.); + } // integrated: if (mupa.fCorrelationsPro[2][h - 1][AFO_INTEGRATED]) { @@ -2219,26 +9668,42 @@ void CalculateCorrelations() if (mupa.fCorrelationsPro[2][h - 1][AFO_CENTRALITY]) { mupa.fCorrelationsPro[2][h - 1][AFO_CENTRALITY]->Fill(ebye.fCentrality, sixC, wSix); } + // vs. occupancy: + if (mupa.fCorrelationsPro[2][h - 1][AFO_OCCUPANCY]) { + mupa.fCorrelationsPro[2][h - 1][AFO_OCCUPANCY]->Fill(ebye.fOccupancy, sixC, wSix); + } + // vs. interaction rate: + if (mupa.fCorrelationsPro[2][h - 1][AFO_INTERACTIONRATE]) { + mupa.fCorrelationsPro[2][h - 1][AFO_INTERACTIONRATE]->Fill(ebye.fInteractionRate, sixC, wSix); + } + // vs. current run duration: + if (mupa.fCorrelationsPro[2][h - 1][AFO_CURRENTRUNDURATION]) { + mupa.fCorrelationsPro[2][h - 1][AFO_CURRENTRUNDURATION]->Fill(ebye.fCurrentRunDuration, sixC, wSix); + } + // vs. vertex z position: + if (mupa.fCorrelationsPro[2][h - 1][AFO_VZ]) { + mupa.fCorrelationsPro[2][h - 1][AFO_VZ]->Fill(ebye.fVz, sixC, wSix); + } // 8p: if (ebye.fSelectedTracks < 8) { continue; } // yes, continue, because I can still calculate 2-p, 4-p and 6-p in other harmonics! if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s => calculating 8-particle correlations....\033[0m", __PRETTY_FUNCTION__); + LOGF(info, " calculating 8-particle correlations ...."); } TComplex eight = Eight(h, h, h, h, -h, -h, -h, -h); - Double_t eightC = eight.Re(); // cos - // Double_t eightS = eight.Im(); // sin - Double_t wEight = Eight(0, 0, 0, 0, 0, 0, 0, 0).Re(); // Weight is 'number of combinations' by default TBI_20210515 add support for other weights + double eightC = eight.Re(); // cos + // double eightS = eight.Im(); // sin + double wEight = Eight(0, 0, 0, 0, 0, 0, 0, 0).Re(); // Weight is 'number of combinations' by default TBI_20210515 add support for other weights if (wEight > 0.0) { eightC /= wEight; } else { - LOGF(fatal, "In function \033[1;31m%s at line %d, wEight = %f <=0. ebye.fSelectedTracks = %d\033[0m", __PRETTY_FUNCTION__, __LINE__, wEight, ebye.fSelectedTracks); + LOGF(fatal, "In function \033[1;31m%s at line %d, wEight = %f <=0. ebye.fSelectedTracks = %d\033[0m", __FUNCTION__, __LINE__, wEight, ebye.fSelectedTracks); // TBI 20240110 shall I 'continue' here, instead of bailing out? } - if (nl.fCalculateCustomNestedLoop) { + if (nl.fCalculateCustomNestedLoops) { // e-b-e sanity check: TArrayI* harmonics = new TArrayI(8); harmonics->SetAt(h, 0); @@ -2249,18 +9714,20 @@ void CalculateCorrelations() harmonics->SetAt(-h, 5); harmonics->SetAt(-h, 6); harmonics->SetAt(-h, 7); - Double_t nestedLoopValue = this->CalculateCustomNestedLoop(harmonics); - if (TMath::Abs(nestedLoopValue) > 0. && TMath::Abs(eightC - nestedLoopValue) > 1.e-5) { - LOGF(fatal, "in function \033[1;31m%s at line %d, nestedLoopValue = %f is not the same as eightC = %f\033[0m", __PRETTY_FUNCTION__, __LINE__, nestedLoopValue, eightC); + double nestedLoopValue = this->CalculateCustomNestedLoops(harmonics); + if (TMath::Abs(nestedLoopValue) > 0. && TMath::Abs(eightC - nestedLoopValue) > tc.fFloatingPointPrecision) { + LOGF(fatal, "\033[1;31m%s at line %d : nestedLoopValue = %f is not the same as eightC = %f\033[0m", __FUNCTION__, __LINE__, nestedLoopValue, eightC); } else { - LOGF(info, "=> e-b-e check with CustomNestedLoop is OK for isotropic 8-p, harmonic %d", h); + LOGF(info, "\033[1;32m ebye check (integrated) with CustomNestedLoops is OK for isotropic 8-p, harmonic %d\033[0m", h); } delete harmonics; harmonics = NULL; - } // if(nl.fCalculateCustomNestedLoop) + } // if(nl.fCalculateCustomNestedLoops) - // if(fUseInternalValidation && fInternalValidationAmplitudes && fRescaleWithTheoreticalInput && - // TMath::Abs(fInternalValidationAmplitudes->GetAt(h-1))>0.){eightC/=pow(fInternalValidationAmplitudes->GetAt(h-1),4.);} + // for on-the-fly and internal validation, rescale results with theoretical value: + if (iv.fUseInternalValidation && iv.fRescaleWithTheoreticalInput && iv.fInternalValidationVnPsin[eVn] && TMath::Abs(iv.fInternalValidationVnPsin[eVn]->GetAt(h - 1)) > 0.) { + eightC /= pow(iv.fInternalValidationVnPsin[eVn]->GetAt(h - 1), 8.); + } // integrated: if (mupa.fCorrelationsPro[3][h - 1][AFO_INTEGRATED]) { @@ -2274,15 +9741,83 @@ void CalculateCorrelations() if (mupa.fCorrelationsPro[3][h - 1][AFO_CENTRALITY]) { mupa.fCorrelationsPro[3][h - 1][AFO_CENTRALITY]->Fill(ebye.fCentrality, eightC, wEight); } - } // for(Int_t h=1;h<=gMaxHarmonic;h++) // harmonic + // vs. occupancy: + if (mupa.fCorrelationsPro[3][h - 1][AFO_OCCUPANCY]) { + mupa.fCorrelationsPro[3][h - 1][AFO_OCCUPANCY]->Fill(ebye.fOccupancy, eightC, wEight); + } + // vs. interaction rate: + if (mupa.fCorrelationsPro[3][h - 1][AFO_INTERACTIONRATE]) { + mupa.fCorrelationsPro[3][h - 1][AFO_INTERACTIONRATE]->Fill(ebye.fInteractionRate, eightC, wEight); + } + // vs. current run duration: + if (mupa.fCorrelationsPro[3][h - 1][AFO_CURRENTRUNDURATION]) { + mupa.fCorrelationsPro[3][h - 1][AFO_CURRENTRUNDURATION]->Fill(ebye.fCurrentRunDuration, eightC, wEight); + } + // vs. vertex z position: + if (mupa.fCorrelationsPro[3][h - 1][AFO_VZ]) { + mupa.fCorrelationsPro[3][h - 1][AFO_VZ]->Fill(ebye.fVz, eightC, wEight); + } + } // for(int h=1;h<=gMaxHarmonic;h++) // harmonic // c) Flush the generic Q-vectors: ResetQ(); + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + } // void CalculateCorrelations() //============================================================ +void CalculateKineCorrelations(eAsFunctionOf AFO_variable) +{ + // Calculate analytically differential multiparticle correlations from Q-vectors. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // *) ... + eqvectorKine qvKine = eqvectorKine_N; // which eqvectorKine enum + // int nBins = -1; // TBI 20241111 temporarily commented out just to suppress warnings + + switch (AFO_variable) { + case AFO_PT: { + qvKine = PTq; + // nBins = res.fResultsPro[AFO_PT]->GetNbinsX(); // TBI 20241111 temporarily commented out just to suppress warnings + break; + } + case AFO_ETA: { + qvKine = ETAq; + // nBins = res.fResultsPro[AFO_ETA]->GetNbinsX(); // TBI 20241111 temporarily commented out just to suppress warnings + break; + } + default: { + LOGF(fatal, "\033[1;31m%s at line %d : This AFO_variable = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, static_cast(AFO_variable)); + break; + } + } // switch(AFO_variable) + + // *) Insanity checks on above settings: + if (qvKine == eqvectorKine_N) { + LOGF(fatal, "\033[1;31m%s at line %d : qvKine == eqvectorKine_N => add some more entries to the case statement \033[0m", __FUNCTION__, __LINE__); + } + + // ... + + LOGF(warning, "\033[1;33m%s at line %d : Not implemented yet, this is just a placeholder for future implementation.\033[0m", __FUNCTION__, __LINE__); + + // ... + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void CalculateKineCorrelations(eAsFunctionOf AFO_variable) + +//============================================================ + void CalculateTest0() { // Calculate Test0. @@ -2292,31 +9827,31 @@ void CalculateTest0() // c) Flush the generic Q-vectors. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); } // a) Flush 'n' fill the generic Q-vectors: ResetQ(); - for (Int_t h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { - for (Int_t wp = 0; wp < gMaxCorrelator + 1; wp++) // weight power + for (int h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { + for (int wp = 0; wp < gMaxCorrelator + 1; wp++) // weight power { qv.fQ[h][wp] = qv.fQvector[h][wp]; } } // b) Calculate correlations: - Double_t correlation = 0.; // still has to be divided with 'weight' later, to get average correlation - Double_t weight = 0.; - Int_t n[gMaxCorrelator] = {0}; // array holding harmonics + double correlation = 0.; // still has to be divided with 'weight' later, to get average correlation + double weight = 0.; + int n[gMaxCorrelator] = {0}; // array holding harmonics - for (Int_t mo = 0; mo < gMaxCorrelator; mo++) { - for (Int_t mi = 0; mi < gMaxIndex; mi++) { + for (int mo = 0; mo < gMaxCorrelator; mo++) { + for (int mi = 0; mi < gMaxIndex; mi++) { // TBI 20210913 I do not have to loop each time all the way up to gMaxCorrelator and gMaxIndex, but nevermind now, it's not a big efficiency loss. // Sanitize the labels (If necessary. Locally this is irrelevant): if (!t0.fTest0Labels[mo][mi]) // I do not stream them. { - for (Int_t v = 0; v < eAsFunctionOf_N; v++) { + for (int v = 0; v < eAsFunctionOf_N; v++) { if (t0.fTest0Pro[mo][mi][v]) { t0.fTest0Labels[mo][mi] = new TString(t0.fTest0Pro[mo][mi][v]->GetTitle()); // there is no memory leak here, since this is executed only once due to if(!fTest0Labels[mo][mi]) break; // yes, since for all v they are the same, so I just need to fetch it from one @@ -2326,11 +9861,10 @@ void CalculateTest0() if (t0.fTest0Labels[mo][mi]) { // Extract harmonics from TString, FS is " ": - for (Int_t h = 0; h <= mo; h++) { + for (int h = 0; h <= mo; h++) { TObjArray* oa = t0.fTest0Labels[mo][mi]->Tokenize(" "); if (!oa) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } n[h] = TString(oa->At(h)->GetName()).Atoi(); delete oa; // yes, otherwise it's a memory leak @@ -2435,47 +9969,46 @@ void CalculateTest0() break; default: - LOGF(fatal, "in function \033[1;31m%s at line %d\n Not supported yet: %s \n\n\033[0m", __PRETTY_FUNCTION__, __LINE__, t0.fTest0Labels[mo][mi]->Data()); + LOGF(fatal, "\033[1;31m%s at line %d : Not supported yet: t0.fTest0Labels[mo][mi]->Data() = %s\033[0m", __FUNCTION__, __LINE__, t0.fTest0Labels[mo][mi]->Data()); } // switch(mo+1) // Insanity check on weight: if (!(weight > 0.)) { - LOGF(fatal, "in function \033[1;31m%s at line %d\n Is perhaps order of correlator bigger than the number of particles? %s \n\n\033[0m", __PRETTY_FUNCTION__, __LINE__, t0.fTest0Labels[mo][mi]->Data()); + LOGF(fatal, "\033[1;31m%s at line %d : weight = %f => Is perhaps order of correlator bigger than the number of particles? t0.fTest0Labels[mo][mi]->Data() = %s \033[0m", __FUNCTION__, __LINE__, weight, t0.fTest0Labels[mo][mi]->Data()); } // e-b-e sanity check: - if (nl.fCalculateCustomNestedLoop) { + if (nl.fCalculateCustomNestedLoops) { TArrayI* harmonics = new TArrayI(mo + 1); - for (Int_t i = 0; i < mo + 1; i++) { + for (int i = 0; i < mo + 1; i++) { harmonics->SetAt(n[i], i); } - Double_t nestedLoopValue = this->CalculateCustomNestedLoop(harmonics); - if (TMath::Abs(nestedLoopValue) > 0. && TMath::Abs(correlation / weight - nestedLoopValue) > 1.e-5) { - LOGF(fatal, "in function \033[1;31m%s at line %d, nestedLoopValue = %f is not the same as correlation/weight = %f, for correlator %s\033[0m", __PRETTY_FUNCTION__, __LINE__, nestedLoopValue, correlation / weight, t0.fTest0Labels[mo][mi]->Data()); + double nestedLoopValue = this->CalculateCustomNestedLoops(harmonics); + if (!(TMath::Abs(nestedLoopValue) > 0.)) { + LOGF(info, " ebye check (integrated) with CustomNestedLoops was NOT calculated for %d-p Test0 corr. %s", mo + 1, t0.fTest0Labels[mo][mi]->Data()); + } else if (TMath::Abs(nestedLoopValue) > 0. && TMath::Abs(correlation / weight - nestedLoopValue) > tc.fFloatingPointPrecision) { + LOGF(fatal, "\033[1;31m%s at line %d : nestedLoopValue = %f is not the same as correlation/weight = %f, for correlator %s\033[0m", __FUNCTION__, __LINE__, nestedLoopValue, correlation / weight, t0.fTest0Labels[mo][mi]->Data()); } else { - LOGF(info, "=> e-b-e check with CustomNestedLoop is OK for %d-p Test0 corr. %s", mo + 1, t0.fTest0Labels[mo][mi]->Data()); + LOGF(info, "\033[1;32m ebye check (integrated) with CustomNestedLoops is OK for %d-p Test0 corr. %s\033[0m", mo + 1, t0.fTest0Labels[mo][mi]->Data()); } delete harmonics; harmonics = NULL; - } // if(nl.fCalculateCustomNestedLoop) + } // if(nl.fCalculateCustomNestedLoops) - /* - // To ease comparison, rescale with theoretical value. Now all Test0 results shall be at 1: - if(fUseInternalValidation && fInternalValidationAmplitudes && fInternalValidationPlanes && fRescaleWithTheoreticalInput) - { - TArrayI *harmonics = new TArrayI(mo+1); - for(Int_t i=0;iSetAt(n[i],i); - } - TComplex theoreticalValue = TheoreticalValue(harmonics,fInternalValidationAmplitudes,fInternalValidationPlanes); - if(TMath::Abs(theoreticalValue.Re()) > 0.) - { - correlation /= theoreticalValue.Re(); - } - delete harmonics; harmonics = NULL; - } // if(fUseInternalValidation && fRescaleWithTheoreticalInput) - */ + // To ease comparison, rescale with theoretical value. Now all Test0 results shall be at 1. Remember that contribution from symmetry planes is here also relevant (in general): + if (iv.fUseInternalValidation && iv.fRescaleWithTheoreticalInput && iv.fInternalValidationVnPsin[eVn] && iv.fInternalValidationVnPsin[ePsin]) { + TArrayI* harmonics = new TArrayI(mo + 1); + for (int i = 0; i < mo + 1; i++) { + harmonics->SetAt(n[i], i); + } + TComplex theoreticalValue = this->TheoreticalValue(harmonics, iv.fInternalValidationVnPsin[eVn], iv.fInternalValidationVnPsin[ePsin]); + if (TMath::Abs(theoreticalValue.Re()) > 0.) { + correlation /= theoreticalValue.Re(); + } + // TBI 20240424 for the time being, I do not do anything with imaginary part, but I could eventually... + delete harmonics; + harmonics = NULL; + } // if(fUseInternalValidation && fRescaleWithTheoreticalInput) // Finally, fill: // integrated: @@ -2484,87 +10017,116 @@ void CalculateTest0() } // vs. multiplicity: if (t0.fTest0Pro[mo][mi][AFO_MULTIPLICITY]) { - t0.fTest0Pro[mo][mi][AFO_MULTIPLICITY]->Fill(ebye.fSelectedTracks + 0.5, correlation / weight, weight); + t0.fTest0Pro[mo][mi][AFO_MULTIPLICITY]->Fill(ebye.fMultiplicity + 0.5, correlation / weight, weight); } // vs. centrality: if (t0.fTest0Pro[mo][mi][AFO_CENTRALITY]) { t0.fTest0Pro[mo][mi][AFO_CENTRALITY]->Fill(ebye.fCentrality, correlation / weight, weight); } + // vs. occupancy: + if (t0.fTest0Pro[mo][mi][AFO_OCCUPANCY]) { + t0.fTest0Pro[mo][mi][AFO_OCCUPANCY]->Fill(ebye.fOccupancy, correlation / weight, weight); + } + // vs. interaction rate: + if (t0.fTest0Pro[mo][mi][AFO_INTERACTIONRATE]) { + t0.fTest0Pro[mo][mi][AFO_INTERACTIONRATE]->Fill(ebye.fInteractionRate, correlation / weight, weight); + } + // vs. current run duration: + if (t0.fTest0Pro[mo][mi][AFO_CURRENTRUNDURATION]) { + t0.fTest0Pro[mo][mi][AFO_CURRENTRUNDURATION]->Fill(ebye.fCurrentRunDuration, correlation / weight, weight); + } + // vs. vertex z position: + if (t0.fTest0Pro[mo][mi][AFO_VZ]) { + t0.fTest0Pro[mo][mi][AFO_VZ]->Fill(ebye.fVz, correlation / weight, weight); + } } // if(t0.fTest0Labels[mo][mi]) - } // for(Int_t mi=0;miGetNbinsX(); - } else if (TString(kc).EqualTo("eta")) { - kb = AFO_ETA; - qvKine_var = ETAq; - // nBins = fKinematicsBins[ETA][0]; - nBins = res.fResultsPro[AFO_ETA]->GetNbinsX(); + eqvectorKine qvKine = eqvectorKine_N; // which eqvectorKine enum + int nBins = -1; + + switch (AFO_variable) { + case AFO_PT: { + qvKine = PTq; + nBins = res.fResultsPro[AFO_PT]->GetNbinsX(); + break; + } + case AFO_ETA: { + qvKine = ETAq; + nBins = res.fResultsPro[AFO_ETA]->GetNbinsX(); + break; + } + default: { + LOGF(fatal, "\033[1;31m%s at line %d : This AFO_variable = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, static_cast(AFO_variable)); + break; + } + } // switch(AFO_variable) + + // *) Insanity checks on above settings: + if (qvKine == eqvectorKine_N) { + LOGF(fatal, "\033[1;31m%s at line %d : qvKine == eqvectorKine_N => add some more entries to the case statement \033[0m", __FUNCTION__, __LINE__); } // *) Uniform loop over bin for all kine variables: - for (Int_t b = 0; b < nBins; b++) { - // Ensures that in each bin of interest, I have the same cut on number of particles, like in integrated analysis: - /* TBI 20240221 enable eventually - if(fUseSelectedTracksCuts) { - if(fqVectorEntries[qvKine_var][b] < fSelectedTracksCuts[0]){continue;} - if(fqVectorEntries[qvKine_var][b] > fSelectedTracksCuts[1]){continue;} - } - */ + for (int b = 0; b < nBins; b++) { + + // *) Ensures that in each bin of interest, I have the same cut on number of particles, like in integrated analysis: + if ((qv.fqVectorEntries[qvKine][b] < ec.fdEventCuts[eMultiplicity][eMin]) || (qv.fqVectorEntries[qvKine][b] > ec.fdEventCuts[eMultiplicity][eMax] || TMath::Abs(qv.fqVectorEntries[qvKine][b] - ec.fdEventCuts[eMultiplicity][eMax]) < tc.fFloatingPointPrecision)) { + if (tc.fVerbose) { + LOGF(info, "\033[1;31m%s eMultiplicity cut in bin = %d, for qvKine = %d\033[0m", __FUNCTION__, b, static_cast(qvKine)); + } + } // *) Re-initialize Q-vector to be q-vector in this bin: // After that, I can call all standard Q-vector functions again: - for (Int_t h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { - for (Int_t wp = 0; wp < gMaxCorrelator + 1; wp++) { // weight power - qv.fQ[h][wp] = qv.fqvector[qvKine_var][b][h][wp]; + for (int h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { + for (int wp = 0; wp < gMaxCorrelator + 1; wp++) { // weight power + qv.fQ[h][wp] = qv.fqvector[qvKine][b][h][wp]; } } // *) Okay, let's do the differential calculus: - Double_t correlation = 0.; - Double_t weight = 0.; - Int_t n[gMaxCorrelator] = {0}; // array holding harmonics + double correlation = 0.; + double weight = 0.; + int n[gMaxCorrelator] = {0}; // array holding harmonics - for (Int_t mo = 0; mo < gMaxCorrelator; mo++) { - for (Int_t mi = 0; mi < gMaxIndex; mi++) { + for (int mo = 0; mo < gMaxCorrelator; mo++) { + for (int mi = 0; mi < gMaxIndex; mi++) { // TBI 20240221 I do not have to loop each time all the way up to gMaxCorrelator and gMaxIndex, but nevermind now, it's not a big efficiency loss. if (t0.fTest0Labels[mo][mi]) { // Extract harmonics from TString, FS is " ": - for (Int_t h = 0; h <= mo; h++) { + for (int h = 0; h <= mo; h++) { // cout<At(h)->GetName()).Atoi(); delete oa; // yes, otherwise it's a memory leak } - if (qv.fqVectorEntries[qvKine_var][b] < mo + 1) { + if (qv.fqVectorEntries[qvKine][b] < mo + 1) { continue; } @@ -2631,89 +10193,296 @@ void CalculateKineTest0(const char* kc) break; default: - LOGF(fatal, "in function \033[1;31m%s at line %d\n Not supported yet: %s \n\n\033[0m", __PRETTY_FUNCTION__, __LINE__, t0.fTest0Labels[mo][mi]->Data()); + LOGF(fatal, "\033[1;31m%s at line %d : not supported yet: %s \n\n\033[0m", __FUNCTION__, __LINE__, t0.fTest0Labels[mo][mi]->Data()); } // switch(mo+1) - /* - // e-b-e sanity check: - if(fCalculateCustomNestedLoop) - { - TArrayI *harmonics = new TArrayI(mo+1); - for(Int_t i=0;iSetAt(n[i],i); - } - if(!(weight>0.)) - { - cout<Data()<CalculateKineCustomNestedLoop(harmonics,kc,b); - if(TMath::Abs(nestedLoopValue)>0. && TMath::Abs(correlation/weight - nestedLoopValue)>1.e-5) - { - cout<Data()<CalculateCustomNestedLoop(harmonics)< e-b-e check with CustomNestedLoop is OK for %d-p Test0 corr. %s, bin = %d",mo+1,fTest0Labels[mo][mi]->Data(),b+1)<SetAt(n[i],i); - } - TComplex theoreticalValue = TheoreticalValue(harmonics,fInternalValidationAmplitudes,fInternalValidationPlanes); - if(TMath::Abs(theoreticalValue.Re()) > 0.) - { - correlation /= theoreticalValue.Re(); - } - delete harmonics; harmonics = NULL; - } // if(fUseInternalValidation && fRescaleWithTheoreticalInput) - */ - - /* - // Insanity check for the event weight: - if(!(weight > 0.)) - { - // If it's negative, that means that sum of particle weights is smaller than "number of particles - 1" - // In that case, you can simply rescale all particle weights, so that each of them is > 1, basically recalculate weights.root files with such a rescaling. - cout<GetTitle() = %s",fTest0Pro[mo][mi][kb]->GetTitle())<SetAt(n[i], i); + } + if (!(weight > 0.)) { + LOGF(fatal, "\033[1;31m%s at line %d : is perhaps order of some requested correlator bigger than the number of particles? Correlator = %s \033[0m", __FUNCTION__, __LINE__, t0.fTest0Labels[mo][mi]->Data()); + } + double nestedLoopValue = this->CalculateKineCustomNestedLoops(harmonics, AFO_variable, b); + if (!(TMath::Abs(nestedLoopValue) > 0.)) { + LOGF(info, " e-b-e check with CalculateKineCustomNestedLoops was NOT calculated for %d-p Test0 corr. %s, bin = %d", mo + 1, t0.fTest0Labels[mo][mi]->Data(), b + 1); + } else if (TMath::Abs(nestedLoopValue) > 0. && TMath::Abs(correlation / weight - nestedLoopValue) > tc.fFloatingPointPrecision) { + LOGF(fatal, "\033[1;31m%s at line %d : correlator: %s \n correlation: %f \n custom loop: %f \033[0m", __FUNCTION__, __LINE__, t0.fTest0Labels[mo][mi]->Data(), correlation / weight, nestedLoopValue); + } else { + LOGF(info, "\033[1;32m ebye check (differential) with CalculateKineCustomNestedLoops is OK for %d-p Test0 corr. %s, bin = %d\033[0m", mo + 1, t0.fTest0Labels[mo][mi]->Data(), b + 1); + } + delete harmonics; + harmonics = NULL; + } // if(nl.fCalculateKineCustomNestedLoops) + + // To ease comparison, rescale with theoretical value. Now all Test0 results shall be at 1: + if (iv.fUseInternalValidation && iv.fRescaleWithTheoreticalInput && iv.fInternalValidationVnPsin[eVn] && iv.fInternalValidationVnPsin[ePsin]) { + TArrayI* harmonics = new TArrayI(mo + 1); + for (int i = 0; i < mo + 1; i++) { + harmonics->SetAt(n[i], i); + } + TComplex theoreticalValue = TheoreticalValue(harmonics, iv.fInternalValidationVnPsin[eVn], iv.fInternalValidationVnPsin[ePsin]); + if (TMath::Abs(theoreticalValue.Re()) > 0.) { + correlation /= theoreticalValue.Re(); + } + // TBI 20240424 for the time being, I do not do anything with imaginary part, but I could eventually... + delete harmonics; + harmonics = NULL; + } // if(fUseInternalValidation && fRescaleWithTheoreticalInput) + + // Insanity check for the event weight: + if (!(weight > 0.)) { + // If it's negative, that means that sum of particle weights is smaller than "number of particles - 1" + // In that case, you can simply rescale all particle weights, so that each of them is > 1, basically recalculate weights.root files with such a rescaling. + LOGF(info, "\n\033[1;33m b = %d \033[0m\n", b); + LOGF(info, "\n\033[1;33m qvKine = %d \033[0m\n", static_cast(qvKine)); + LOGF(info, "\n\033[1;33m event weight = %e \033[0m\n", weight); + LOGF(info, "\n\033[1;33m sum of particle weights = %e \033[0m\n", One(0).Re()); + LOGF(info, "\n\033[1;33m correlation = %f \033[0m\n", correlation); + LOGF(info, "\n\033[1;33m t0.fTest0Pro[mo][mi][AFO_variable]->GetTitle() = %s \033[0m\n", t0.fTest0Pro[mo][mi][AFO_variable]->GetTitle()); + LOGF(info, "\n\033[1;33m [mo][mi][AFO_variable] = [%d][%d][%d] \033[0m\n", mo, mi, static_cast(AFO_variable)); + LOGF(info, "\n\033[1;33m ebye.fSelectedTracks = %d \033[0m\n", ebye.fSelectedTracks); + LOGF(info, "\n\033[1;33m qv.fqVectorEntries[qvKine][b] = %d \033[0m\n", qv.fqVectorEntries[qvKine][b]); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } // Finally, fill: - if (t0.fTest0Pro[mo][mi][kb]) { - t0.fTest0Pro[mo][mi][kb]->Fill(t0.fTest0Pro[mo][mi][kb]->GetXaxis()->GetBinCenter(b + 1), correlation / weight, weight); + if (t0.fTest0Pro[mo][mi][AFO_variable]) { + t0.fTest0Pro[mo][mi][AFO_variable]->Fill(t0.fTest0Pro[mo][mi][AFO_variable]->GetXaxis()->GetBinCenter(b + 1), correlation / weight, weight); } // fill in the bin center } // if(fTest0Labels[mo][mi]) - } // for(Int_t mi=0;mi 0. && qv.fQabVector[1][h][e].Rho() > 0.)) { + continue; + } + if (!(qv.fMab[0][e] > 0. && qv.fMab[1][e] > 0.)) { + continue; + } + + // calculate correlation and weights with particular eta separation: + correlation = TComplex(qv.fQabVector[0][h][e] * TComplex::Conjugate(qv.fQabVector[1][h][e])).Re(); + weight = qv.fMab[0][e] * qv.fMab[1][e]; + + // for on-the-fly and internal validation, rescale results with theoretical value: + if (iv.fUseInternalValidation && iv.fRescaleWithTheoreticalInput && iv.fInternalValidationVnPsin[eVn] && TMath::Abs(iv.fInternalValidationVnPsin[eVn]->GetAt(h)) > 0.) { + correlation /= pow(iv.fInternalValidationVnPsin[eVn]->GetAt(h), 2.); + } + + // integrated: + if (es.fEtaSeparationsPro[h][e][AFO_INTEGRATED]) { + es.fEtaSeparationsPro[h][e][AFO_INTEGRATED]->Fill(0.5, correlation / weight, weight); + } + + // vs. multiplicity: + if (es.fEtaSeparationsPro[h][e][AFO_MULTIPLICITY]) { + es.fEtaSeparationsPro[h][e][AFO_MULTIPLICITY]->Fill(ebye.fMultiplicity + 0.5, correlation / weight, weight); + } + + // vs. centrality: + if (es.fEtaSeparationsPro[h][e][AFO_CENTRALITY]) { + es.fEtaSeparationsPro[h][e][AFO_CENTRALITY]->Fill(ebye.fCentrality, correlation / weight, weight); + } + + // vs. occupancy: + if (es.fEtaSeparationsPro[h][e][AFO_OCCUPANCY]) { + es.fEtaSeparationsPro[h][e][AFO_OCCUPANCY]->Fill(ebye.fOccupancy, correlation / weight, weight); + } + + // vs. interaction rate: + if (es.fEtaSeparationsPro[h][e][AFO_INTERACTIONRATE]) { + es.fEtaSeparationsPro[h][e][AFO_INTERACTIONRATE]->Fill(ebye.fInteractionRate, correlation / weight, weight); + } + + // vs. current run duration: + if (es.fEtaSeparationsPro[h][e][AFO_CURRENTRUNDURATION]) { + es.fEtaSeparationsPro[h][e][AFO_CURRENTRUNDURATION]->Fill(ebye.fCurrentRunDuration, correlation / weight, weight); + } + + // vs. vertex z position: + if (es.fEtaSeparationsPro[h][e][AFO_VZ]) { + es.fEtaSeparationsPro[h][e][AFO_VZ]->Fill(ebye.fVz, correlation / weight, weight); + } + + } // for (int e = 0; e < gMaxNumberEtaSeparations; e++) { + } // for (int h = 0; h < gMaxHarmonic; h++) { + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void CalculateEtaSeparations() + +//============================================================ + +void CalculateKineEtaSeparations(eAsFunctionOf AFO_variable) +{ + // Calculate differential correlations with pseudorapidity separations. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // *) ... + eqvectorKine qvKine = eqvectorKine_N; // which eqvectorKine enum + int nBins = -1; + + switch (AFO_variable) { + case AFO_PT: { + qvKine = PTq; + nBins = res.fResultsPro[AFO_PT]->GetNbinsX(); + break; + } + case AFO_ETA: { + LOGF(fatal, "\033[1;31m%s at line %d : It doesn't make sense (i.e. AFO_ETA cannot be used here). \033[0m", __FUNCTION__, __LINE__, static_cast(AFO_variable)); + break; // obsolete, but it supresses the warning + } + default: { + LOGF(fatal, "\033[1;31m%s at line %d : This AFO_variable = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, static_cast(AFO_variable)); + break; + } + } // switch(AFO_variable) + + // *) Insanity checks on above settings: + if (qvKine == eqvectorKine_N) { + LOGF(fatal, "\033[1;31m%s at line %d : qvKine == eqvectorKine_N => add some more entries to the case statement \033[0m", __FUNCTION__, __LINE__); + } + + // *) Uniform loop over bin for all kine variables: + for (int b = 0; b < nBins; b++) { + + /* TBI 20241206 Do I need to adapt and apply this cut, also for Qa and Qb? If so, most likely I would need to apply it on sum, i.e. on entries in Qa + Qb + + // *) Ensures that in each bin of interest, I have the same cut on number of particles, like in integrated analysis: + if ((qv.fqVectorEntries[qvKine][b] < ec.fdEventCuts[eMultiplicity][eMin]) || (qv.fqVectorEntries[qvKine][b] > ec.fdEventCuts[eMultiplicity][eMax] || TMath::Abs(qv.fqVectorEntries[qvKine][b] - ec.fdEventCuts[eMultiplicity][eMax]) < tc.fFloatingPointPrecision)) { + if (tc.fVerbose) { + LOGF(info, "\033[1;31m%s eMultiplicity cut in bin = %d, for qvKine = %d\033[0m", __FUNCTION__, b, static_cast(qvKine)); + } + } + */ + + // Calculate differential 2-p correlations with eta separations from Qa (-eta, index [0]) and Qb (+eta, index [1]) vectors: + double correlation = 0.; + double weight = 0.; + for (int h = 0; h < gMaxHarmonic; h++) { + if (es.fEtaSeparationsSkipHarmonics[h]) { + continue; + } + + for (int e = 0; e < gMaxNumberEtaSeparations; e++) { + if (!(qv.fqabVector[0][b][h][e].Rho() > 0. && qv.fqabVector[1][b][h][e].Rho() > 0.)) { + continue; + } + if (!(qv.fmab[0][b][e] > 0. && qv.fmab[1][b][e] > 0.)) { + continue; + } + + // calculate correlation and weights with particular eta separation: + correlation = TComplex(qv.fqabVector[0][b][h][e] * TComplex::Conjugate(qv.fqabVector[1][b][h][e])).Re(); + weight = qv.fmab[0][b][e] * qv.fmab[1][b][e]; + + // for on-the-fly and internal validation, rescale results with theoretical value: + if (iv.fUseInternalValidation && iv.fRescaleWithTheoreticalInput && iv.fInternalValidationVnPsin[eVn] && TMath::Abs(iv.fInternalValidationVnPsin[eVn]->GetAt(h)) > 0.) { + correlation /= pow(iv.fInternalValidationVnPsin[eVn]->GetAt(h), 2.); + } + + // finally, fill: + if (es.fEtaSeparationsPro[h][e][AFO_variable]) { + es.fEtaSeparationsPro[h][e][AFO_variable]->Fill(es.fEtaSeparationsPro[h][e][AFO_variable]->GetXaxis()->GetBinCenter(b + 1), correlation / weight, weight); + } + } + } + } // for (int b = 0; b < nBins; b++) { + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void CalculateKineEtaSeparations() + +//============================================================ + +void FillNestedLoopsContainers(const int& particleIndex, const double& dPhi, const double& dPt, const double& dEta) +{ + // Fill into the nested loop containers the current particle. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + if (tc.fInsanityCheckForEachParticle) { + if (particleIndex < 0) { + LOGF(fatal, "\033[1;31m%s at line %d : particleIndex = %d\033[0m", __FUNCTION__, __LINE__, particleIndex); + } + if (!(TMath::Abs(nl.ftaNestedLoops[0]->GetAt(particleIndex - 1)) > 0.)) { + LOGF(fatal, "\033[1;31m%s at line %d : there are empty elements in nl.ftaNestedLoops[0] \033[0m", __FUNCTION__, __LINE__); + // I need this protection, to ensure that all array entries are filled. If not, most likely a particle passed all + // selection criteria, and it wasn't added to the nested loops containers + } + } + + // *) Fill container for angles: + if (nl.ftaNestedLoops[0]) { + nl.ftaNestedLoops[0]->AddAt(dPhi, particleIndex); // remember that the 2nd argument here must start from 0 + } + + // *) Fill container for weights: + if (nl.ftaNestedLoops[1]) { + // TBI 20240501 there is a bit of efficiency loss here, because I access Weight() again here. + // But it doesn't matter really, in any case I evaluate nested loops only for small M during debugging. + // Otherwise, just promote weights to data members, and initialize them only once for a given particle. + double wPhi = 1.; + double wPt = 1.; + double wEta = 1.; + if (pw.fUseWeights[wPHI]) { + wPhi = Weight(dPhi, wPHI); + } + if (pw.fUseWeights[wPT]) { + wPt = Weight(dPt, wPT); + } + if (pw.fUseWeights[wETA]) { + wEta = Weight(dEta, wETA); + } + nl.ftaNestedLoops[1]->AddAt(wPhi * wPt * wEta, particleIndex); // remember that the 2nd argument here must start from 0 + } - } // for(Int_t b=0;bGetSize();i++) + for(int i=0;iGetSize();i++) { if(TMath::Abs(ftaNestedLoops[0]->GetAt(i)) > 0. && TMath::Abs(ftaNestedLoops[1]->GetAt(i)) > 0.){nParticles++;} @@ -2750,16 +10519,19 @@ void CalculateNestedLoops() if (nParticles < 2) { return; } - LOGF(info, "\033[1;32m CalculateNestedLoops(void), 2-p correlations .... \033[0m"); + if (nl.fMaxNestedLoop > 0 && nl.fMaxNestedLoop < 2) { + return; + } + LOGF(info, " Calculating 2-p correlations with nested loops .... "); for (int i1 = 0; i1 < nParticles; i1++) { - Double_t dPhi1 = nl.ftaNestedLoops[0]->GetAt(i1); - Double_t dW1 = nl.ftaNestedLoops[1]->GetAt(i1); + double dPhi1 = nl.ftaNestedLoops[0]->GetAt(i1); + double dW1 = nl.ftaNestedLoops[1]->GetAt(i1); for (int i2 = 0; i2 < nParticles; i2++) { if (i2 == i1) { continue; } - Double_t dPhi2 = nl.ftaNestedLoops[0]->GetAt(i2); - Double_t dW2 = nl.ftaNestedLoops[1]->GetAt(i2); + double dPhi2 = nl.ftaNestedLoops[0]->GetAt(i2); + double dW2 = nl.ftaNestedLoops[1]->GetAt(i2); for (int h = 0; h < gMaxHarmonic; h++) { // fill cos, 2p, integreated: if (nl.fNestedLoopsPro[0][h][AFO_INTEGRATED]) { @@ -2769,7 +10541,7 @@ void CalculateNestedLoops() // fill cos, 2p, vs. multiplicity: if (nl.fNestedLoopsPro[0][h][AFO_MULTIPLICITY]) { nl.fNestedLoopsPro[0][h][AFO_MULTIPLICITY]->Fill( - ebye.fSelectedTracks + 0.5, TMath::Cos((h + 1.) * (dPhi1 - dPhi2)), + ebye.fMultiplicity + 0.5, TMath::Cos((h + 1.) * (dPhi1 - dPhi2)), dW1 * dW2); } // fill cos, 2p, vs. centrality: @@ -2777,36 +10549,61 @@ void CalculateNestedLoops() nl.fNestedLoopsPro[0][h][AFO_CENTRALITY]->Fill( ebye.fCentrality, TMath::Cos((h + 1.) * (dPhi1 - dPhi2)), dW1 * dW2); } + // fill cos, 2p, vs. occupancy: + if (nl.fNestedLoopsPro[0][h][AFO_OCCUPANCY]) { + nl.fNestedLoopsPro[0][h][AFO_OCCUPANCY]->Fill( + ebye.fOccupancy, TMath::Cos((h + 1.) * (dPhi1 - dPhi2)), dW1 * dW2); + } + // fill cos, 2p, vs. interaction rate: + if (nl.fNestedLoopsPro[0][h][AFO_INTERACTIONRATE]) { + nl.fNestedLoopsPro[0][h][AFO_INTERACTIONRATE]->Fill( + ebye.fInteractionRate, TMath::Cos((h + 1.) * (dPhi1 - dPhi2)), dW1 * dW2); + } + // fill cos, 2p, vs. current run duration: + if (nl.fNestedLoopsPro[0][h][AFO_CURRENTRUNDURATION]) { + nl.fNestedLoopsPro[0][h][AFO_CURRENTRUNDURATION]->Fill( + ebye.fCurrentRunDuration, TMath::Cos((h + 1.) * (dPhi1 - dPhi2)), dW1 * dW2); + } + // fill cos, 2p, vs. vertex z position: + if (nl.fNestedLoopsPro[0][h][AFO_VZ]) { + nl.fNestedLoopsPro[0][h][AFO_VZ]->Fill( + ebye.fVz, TMath::Cos((h + 1.) * (dPhi1 - dPhi2)), dW1 * dW2); + } + } // for(int h=1; h<=6; h++) - } // for(int i2=0; i2 0 && nl.fMaxNestedLoop < 4) { + return; + } + LOGF(info, " Calculating 4-p correlations with nested loops .... "); for (int i1 = 0; i1 < nParticles; i1++) { - Double_t dPhi1 = nl.ftaNestedLoops[0]->GetAt(i1); - Double_t dW1 = nl.ftaNestedLoops[1]->GetAt(i1); + double dPhi1 = nl.ftaNestedLoops[0]->GetAt(i1); + double dW1 = nl.ftaNestedLoops[1]->GetAt(i1); for (int i2 = 0; i2 < nParticles; i2++) { if (i2 == i1) { continue; } - Double_t dPhi2 = nl.ftaNestedLoops[0]->GetAt(i2); - Double_t dW2 = nl.ftaNestedLoops[1]->GetAt(i2); + double dPhi2 = nl.ftaNestedLoops[0]->GetAt(i2); + double dW2 = nl.ftaNestedLoops[1]->GetAt(i2); for (int i3 = 0; i3 < nParticles; i3++) { if (i3 == i1 || i3 == i2) { continue; } - Double_t dPhi3 = nl.ftaNestedLoops[0]->GetAt(i3); - Double_t dW3 = nl.ftaNestedLoops[1]->GetAt(i3); + double dPhi3 = nl.ftaNestedLoops[0]->GetAt(i3); + double dW3 = nl.ftaNestedLoops[1]->GetAt(i3); for (int i4 = 0; i4 < nParticles; i4++) { if (i4 == i1 || i4 == i2 || i4 == i3) { continue; } - Double_t dPhi4 = nl.ftaNestedLoops[0]->GetAt(i4); - Double_t dW4 = nl.ftaNestedLoops[1]->GetAt(i4); + double dPhi4 = nl.ftaNestedLoops[0]->GetAt(i4); + double dW4 = nl.ftaNestedLoops[1]->GetAt(i4); for (int h = 0; h < gMaxHarmonic; h++) { // fill cos, 4p, integreated: if (nl.fNestedLoopsPro[1][h][AFO_INTEGRATED]) { @@ -2814,56 +10611,76 @@ void CalculateNestedLoops() } // fill cos, 4p, all harmonics, vs. M: if (nl.fNestedLoopsPro[1][h][AFO_MULTIPLICITY]) { - nl.fNestedLoopsPro[1][h][AFO_MULTIPLICITY]->Fill(ebye.fSelectedTracks + 0.5, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 - dPhi3 - dPhi4)), dW1 * dW2 * dW3 * dW4); + nl.fNestedLoopsPro[1][h][AFO_MULTIPLICITY]->Fill(ebye.fMultiplicity + 0.5, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 - dPhi3 - dPhi4)), dW1 * dW2 * dW3 * dW4); } // fill cos, 4p, all harmonics, vs. centrality: if (nl.fNestedLoopsPro[1][h][AFO_CENTRALITY]) { nl.fNestedLoopsPro[1][h][AFO_CENTRALITY]->Fill(ebye.fCentrality, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 - dPhi3 - dPhi4)), dW1 * dW2 * dW3 * dW4); } + // fill cos, 4p, all harmonics, vs. occupancy: + if (nl.fNestedLoopsPro[1][h][AFO_OCCUPANCY]) { + nl.fNestedLoopsPro[1][h][AFO_OCCUPANCY]->Fill(ebye.fOccupancy, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 - dPhi3 - dPhi4)), dW1 * dW2 * dW3 * dW4); + } + // fill cos, 4p, all harmonics, vs. interaction rate: + if (nl.fNestedLoopsPro[1][h][AFO_INTERACTIONRATE]) { + nl.fNestedLoopsPro[1][h][AFO_INTERACTIONRATE]->Fill(ebye.fInteractionRate, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 - dPhi3 - dPhi4)), dW1 * dW2 * dW3 * dW4); + } + // fill cos, 4p, all harmonics, vs. current run duratione: + if (nl.fNestedLoopsPro[1][h][AFO_CURRENTRUNDURATION]) { + nl.fNestedLoopsPro[1][h][AFO_CURRENTRUNDURATION]->Fill(ebye.fCurrentRunDuration, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 - dPhi3 - dPhi4)), dW1 * dW2 * dW3 * dW4); + } + // fill cos, 4p, all harmonics, vs. vertex z position: + if (nl.fNestedLoopsPro[1][h][AFO_VZ]) { + nl.fNestedLoopsPro[1][h][AFO_VZ]->Fill(ebye.fVz, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 - dPhi3 - dPhi4)), dW1 * dW2 * dW3 * dW4); + } } // for(int h=0; h 0 && nl.fMaxNestedLoop < 6) { + return; + } + LOGF(info, " Calculating 6-p correlations with nested loops .... "); for (int i1 = 0; i1 < nParticles; i1++) { - Double_t dPhi1 = nl.ftaNestedLoops[0]->GetAt(i1); - Double_t dW1 = nl.ftaNestedLoops[1]->GetAt(i1); + double dPhi1 = nl.ftaNestedLoops[0]->GetAt(i1); + double dW1 = nl.ftaNestedLoops[1]->GetAt(i1); for (int i2 = 0; i2 < nParticles; i2++) { if (i2 == i1) { continue; } - Double_t dPhi2 = nl.ftaNestedLoops[0]->GetAt(i2); - Double_t dW2 = nl.ftaNestedLoops[1]->GetAt(i2); + double dPhi2 = nl.ftaNestedLoops[0]->GetAt(i2); + double dW2 = nl.ftaNestedLoops[1]->GetAt(i2); for (int i3 = 0; i3 < nParticles; i3++) { if (i3 == i1 || i3 == i2) { continue; } - Double_t dPhi3 = nl.ftaNestedLoops[0]->GetAt(i3); - Double_t dW3 = nl.ftaNestedLoops[1]->GetAt(i3); + double dPhi3 = nl.ftaNestedLoops[0]->GetAt(i3); + double dW3 = nl.ftaNestedLoops[1]->GetAt(i3); for (int i4 = 0; i4 < nParticles; i4++) { if (i4 == i1 || i4 == i2 || i4 == i3) { continue; } - Double_t dPhi4 = nl.ftaNestedLoops[0]->GetAt(i4); - Double_t dW4 = nl.ftaNestedLoops[1]->GetAt(i4); + double dPhi4 = nl.ftaNestedLoops[0]->GetAt(i4); + double dW4 = nl.ftaNestedLoops[1]->GetAt(i4); for (int i5 = 0; i5 < nParticles; i5++) { if (i5 == i1 || i5 == i2 || i5 == i3 || i5 == i4) { continue; } - Double_t dPhi5 = nl.ftaNestedLoops[0]->GetAt(i5); - Double_t dW5 = nl.ftaNestedLoops[1]->GetAt(i5); + double dPhi5 = nl.ftaNestedLoops[0]->GetAt(i5); + double dW5 = nl.ftaNestedLoops[1]->GetAt(i5); for (int i6 = 0; i6 < nParticles; i6++) { if (i6 == i1 || i6 == i2 || i6 == i3 || i6 == i4 || i6 == i5) { continue; } - Double_t dPhi6 = nl.ftaNestedLoops[0]->GetAt(i6); - Double_t dW6 = nl.ftaNestedLoops[1]->GetAt(i6); + double dPhi6 = nl.ftaNestedLoops[0]->GetAt(i6); + double dW6 = nl.ftaNestedLoops[1]->GetAt(i6); for (int h = 0; h < gMaxHarmonic; h++) { // fill cos, 6p, integreated: if (nl.fNestedLoopsPro[2][h][AFO_INTEGRATED]) { @@ -2871,70 +10688,90 @@ void CalculateNestedLoops() } // fill cos, 6p, all harmonics, vs. M: if (nl.fNestedLoopsPro[2][h][AFO_MULTIPLICITY]) { - nl.fNestedLoopsPro[2][h][AFO_MULTIPLICITY]->Fill(ebye.fSelectedTracks + 0.5, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 - dPhi4 - dPhi5 - dPhi6)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6); + nl.fNestedLoopsPro[2][h][AFO_MULTIPLICITY]->Fill(ebye.fMultiplicity + 0.5, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 - dPhi4 - dPhi5 - dPhi6)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6); + } + // fill cos, 6p, all harmonics, vs. centrality: + if (nl.fNestedLoopsPro[2][h][AFO_CENTRALITY]) { + nl.fNestedLoopsPro[2][h][AFO_CENTRALITY]->Fill(ebye.fCentrality, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 - dPhi4 - dPhi5 - dPhi6)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6); + } + // fill cos, 6p, all harmonics, vs. occupancy: + if (nl.fNestedLoopsPro[2][h][AFO_OCCUPANCY]) { + nl.fNestedLoopsPro[2][h][AFO_OCCUPANCY]->Fill(ebye.fOccupancy, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 - dPhi4 - dPhi5 - dPhi6)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6); + } + // fill cos, 6p, all harmonics, vs. interaction rate: + if (nl.fNestedLoopsPro[2][h][AFO_INTERACTIONRATE]) { + nl.fNestedLoopsPro[2][h][AFO_INTERACTIONRATE]->Fill(ebye.fInteractionRate, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 - dPhi4 - dPhi5 - dPhi6)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6); + } + // fill cos, 6p, all harmonics, vs. current run duration: + if (nl.fNestedLoopsPro[2][h][AFO_CURRENTRUNDURATION]) { + nl.fNestedLoopsPro[2][h][AFO_CURRENTRUNDURATION]->Fill(ebye.fCurrentRunDuration, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 - dPhi4 - dPhi5 - dPhi6)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6); } - // fill cos, 6p, all harmonics, vs. M: - if (nl.fNestedLoopsPro[2][h][AFO_CENTRALITY]) { - nl.fNestedLoopsPro[2][h][AFO_CENTRALITY]->Fill(ebye.fCentrality, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 - dPhi4 - dPhi5 - dPhi6)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6); + // fill cos, 6p, all harmonics, vs. vertex z position: + if (nl.fNestedLoopsPro[2][h][AFO_VZ]) { + nl.fNestedLoopsPro[2][h][AFO_VZ]->Fill(ebye.fVz, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 - dPhi4 - dPhi5 - dPhi6)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6); } } // for(int h=0; h 0 && nl.fMaxNestedLoop < 8) { + return; + } + LOGF(info, " Calculating 8-p correlations with nested loops .... "); for (int i1 = 0; i1 < nParticles; i1++) { - Double_t dPhi1 = nl.ftaNestedLoops[0]->GetAt(i1); - Double_t dW1 = nl.ftaNestedLoops[1]->GetAt(i1); + double dPhi1 = nl.ftaNestedLoops[0]->GetAt(i1); + double dW1 = nl.ftaNestedLoops[1]->GetAt(i1); for (int i2 = 0; i2 < nParticles; i2++) { if (i2 == i1) { continue; } - Double_t dPhi2 = nl.ftaNestedLoops[0]->GetAt(i2); - Double_t dW2 = nl.ftaNestedLoops[1]->GetAt(i2); + double dPhi2 = nl.ftaNestedLoops[0]->GetAt(i2); + double dW2 = nl.ftaNestedLoops[1]->GetAt(i2); for (int i3 = 0; i3 < nParticles; i3++) { if (i3 == i1 || i3 == i2) { continue; } - Double_t dPhi3 = nl.ftaNestedLoops[0]->GetAt(i3); - Double_t dW3 = nl.ftaNestedLoops[1]->GetAt(i3); + double dPhi3 = nl.ftaNestedLoops[0]->GetAt(i3); + double dW3 = nl.ftaNestedLoops[1]->GetAt(i3); for (int i4 = 0; i4 < nParticles; i4++) { if (i4 == i1 || i4 == i2 || i4 == i3) { continue; } - Double_t dPhi4 = nl.ftaNestedLoops[0]->GetAt(i4); - Double_t dW4 = nl.ftaNestedLoops[1]->GetAt(i4); + double dPhi4 = nl.ftaNestedLoops[0]->GetAt(i4); + double dW4 = nl.ftaNestedLoops[1]->GetAt(i4); for (int i5 = 0; i5 < nParticles; i5++) { if (i5 == i1 || i5 == i2 || i5 == i3 || i5 == i4) { continue; } - Double_t dPhi5 = nl.ftaNestedLoops[0]->GetAt(i5); - Double_t dW5 = nl.ftaNestedLoops[1]->GetAt(i5); + double dPhi5 = nl.ftaNestedLoops[0]->GetAt(i5); + double dW5 = nl.ftaNestedLoops[1]->GetAt(i5); for (int i6 = 0; i6 < nParticles; i6++) { if (i6 == i1 || i6 == i2 || i6 == i3 || i6 == i4 || i6 == i5) { continue; } - Double_t dPhi6 = nl.ftaNestedLoops[0]->GetAt(i6); - Double_t dW6 = nl.ftaNestedLoops[1]->GetAt(i6); + double dPhi6 = nl.ftaNestedLoops[0]->GetAt(i6); + double dW6 = nl.ftaNestedLoops[1]->GetAt(i6); for (int i7 = 0; i7 < nParticles; i7++) { if (i7 == i1 || i7 == i2 || i7 == i3 || i7 == i4 || i7 == i5 || i7 == i6) { continue; } - Double_t dPhi7 = nl.ftaNestedLoops[0]->GetAt(i7); - Double_t dW7 = nl.ftaNestedLoops[1]->GetAt(i7); + double dPhi7 = nl.ftaNestedLoops[0]->GetAt(i7); + double dW7 = nl.ftaNestedLoops[1]->GetAt(i7); for (int i8 = 0; i8 < nParticles; i8++) { if (i8 == i1 || i8 == i2 || i8 == i3 || i8 == i4 || i8 == i5 || i8 == i6 || i8 == i7) { continue; } - Double_t dPhi8 = nl.ftaNestedLoops[0]->GetAt(i8); - Double_t dW8 = nl.ftaNestedLoops[1]->GetAt(i8); + double dPhi8 = nl.ftaNestedLoops[0]->GetAt(i8); + double dW8 = nl.ftaNestedLoops[1]->GetAt(i8); for (int h = 0; h < gMaxHarmonic; h++) { // fill cos, 8p, integreated: if (nl.fNestedLoopsPro[3][h][AFO_INTEGRATED]) { @@ -2942,21 +10779,41 @@ void CalculateNestedLoops() } // fill cos, 8p, all harmonics, vs. M: if (nl.fNestedLoopsPro[3][h][AFO_MULTIPLICITY]) { - nl.fNestedLoopsPro[3][h][AFO_MULTIPLICITY]->Fill(ebye.fSelectedTracks + 0.5, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 + dPhi4 - dPhi5 - dPhi6 - dPhi7 - dPhi8)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7 * dW8); + nl.fNestedLoopsPro[3][h][AFO_MULTIPLICITY]->Fill(ebye.fMultiplicity + 0.5, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 + dPhi4 - dPhi5 - dPhi6 - dPhi7 - dPhi8)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7 * dW8); } - // fill cos, 8p, all harmonics, vs. M: + // fill cos, 8p, all harmonics, vs. centrality: if (nl.fNestedLoopsPro[3][h][AFO_CENTRALITY]) { nl.fNestedLoopsPro[3][h][AFO_CENTRALITY]->Fill(ebye.fCentrality, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 + dPhi4 - dPhi5 - dPhi6 - dPhi7 - dPhi8)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7 * dW8); } + // fill cos, 8p, all harmonics, vs. occupancy: + if (nl.fNestedLoopsPro[3][h][AFO_OCCUPANCY]) { + nl.fNestedLoopsPro[3][h][AFO_OCCUPANCY]->Fill(ebye.fOccupancy, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 + dPhi4 - dPhi5 - dPhi6 - dPhi7 - dPhi8)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7 * dW8); + } + // fill cos, 8p, all harmonics, vs. interaction rate: + if (nl.fNestedLoopsPro[3][h][AFO_INTERACTIONRATE]) { + nl.fNestedLoopsPro[3][h][AFO_INTERACTIONRATE]->Fill(ebye.fInteractionRate, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 + dPhi4 - dPhi5 - dPhi6 - dPhi7 - dPhi8)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7 * dW8); + } + // fill cos, 8p, all harmonics, vs. current run duration: + if (nl.fNestedLoopsPro[3][h][AFO_CURRENTRUNDURATION]) { + nl.fNestedLoopsPro[3][h][AFO_CURRENTRUNDURATION]->Fill(ebye.fCurrentRunDuration, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 + dPhi4 - dPhi5 - dPhi6 - dPhi7 - dPhi8)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7 * dW8); + } + // fill cos, 8p, all harmonics, vs. vertex z position: + if (nl.fNestedLoopsPro[3][h][AFO_VZ]) { + nl.fNestedLoopsPro[3][h][AFO_VZ]->Fill(ebye.fVz, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 + dPhi4 - dPhi5 - dPhi6 - dPhi7 - dPhi8)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7 * dW8); + } } // for(int h=0; hGetNbinsX(); nBinsNL = nl.fNestedLoopsPro[0][0][v]->GetNbinsX(); if (nBinsQV != nBinsNL) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } LOGF(info, "\033[1;32m [%d] : %s\033[0m", v, res.fResultsProXaxisTitle[v].Data()); - for (Int_t o = 0; o < 4; o++) { + for (int o = 0; o < 4; o++) { LOGF(info, "\033[1;32m ==== <<%d>>-particle correlations ====\033[0m", 2 * (o + 1)); - for (Int_t h = 0; h < gMaxHarmonic; h++) { - for (Int_t b = 1; b <= nBinsQV; b++) { + for (int h = 0; h < gMaxHarmonic; h++) { + for (int b = 1; b <= nBinsQV; b++) { if (mupa.fCorrelationsPro[o][h][v]) { valueQV = mupa.fCorrelationsPro[o][h][v]->GetBinContent(b); } @@ -2999,23 +10857,26 @@ void ComparisonNestedLoopsVsCorrelations() if (TMath::Abs(valueQV) > 0. && TMath::Abs(valueNL) > 0.) { LOGF(info, " bin=%d, h=%d, Q-vectors: %f", b, h + 1, valueQV); LOGF(info, " bin=%d, h=%d, Nested loops: %f", b, h + 1, valueNL); - if (TMath::Abs(valueQV - valueNL) > 1.e-5) { + if (TMath::Abs(valueQV - valueNL) > tc.fFloatingPointPrecision) { LOGF(info, "\n\033[1;33m[%d][%d][%d] \033[0m\n", o, h, v); - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - } // if(TMath::Abs(valueQV)>0. && TMath::Abs(valueNL)>0.) - } // for(Int_t b=1;b<=nBinsQV;b++) - } // for(Int_t h=0;h<6;h++) + } // if(TMath::Abs(valueQV)>0. && TMath::Abs(valueNL)>0.) + } // for(int b=1;b<=nBinsQV;b++) + } // for (int h = 0; h < gMaxHarmonic; h++) { LOGF(info, ""); // new line - } // for(Int_t o=0;o<4;o++) - } // for (Int_t v = 0; v < 3; v++) + } // for(int o=0;o<4;o++) + } // for (int v = 0; v < 3; v++) + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } } // void ComparisonNestedLoopsVsCorrelations() //============================================================ -TComplex Q(Int_t n, Int_t wp) +TComplex Q(int n, int wp) { // Using the fact that Q{-n,p} = Q{n,p}^*. @@ -3024,11 +10885,11 @@ TComplex Q(Int_t n, Int_t wp) } return TComplex::Conjugate(qv.fQ[-n][wp]); -} // TComplex FlowWithMultiparticleCorrelationsTask::Q(Int_t n, Int_t wp) +} // TComplex FlowWithMultiparticleCorrelationsTask::Q(int n, int wp) //============================================================ -TComplex One(Int_t n1) +TComplex One(int n1) { // Generic expression . @@ -3036,11 +10897,11 @@ TComplex One(Int_t n1) return one; -} // TComplex FlowWithMultiparticleCorrelationsTask::One(Int_t n1) +} // TComplex FlowWithMultiparticleCorrelationsTask::One(int n1) //============================================================ -TComplex Two(Int_t n1, Int_t n2) +TComplex Two(int n1, int n2) { // Generic two-particle correlation . @@ -3048,11 +10909,11 @@ TComplex Two(Int_t n1, Int_t n2) return two; -} // TComplex FlowWithMultiparticleCorrelationsTask::Two(Int_t n1, Int_t n2) +} // TComplex FlowWithMultiparticleCorrelationsTask::Two(int n1, int n2) //============================================================ -TComplex Three(Int_t n1, Int_t n2, Int_t n3) +TComplex Three(int n1, int n2, int n3) { // Generic three-particle correlation . @@ -3062,11 +10923,11 @@ TComplex Three(Int_t n1, Int_t n2, Int_t n3) return three; -} // TComplex Three(Int_t n1, Int_t n2, Int_t n3) +} // TComplex Three(int n1, int n2, int n3) //============================================================ -TComplex Four(Int_t n1, Int_t n2, Int_t n3, Int_t n4) +TComplex Four(int n1, int n2, int n3, int n4) { // Generic four-particle correlation // . @@ -3084,11 +10945,11 @@ TComplex Four(Int_t n1, Int_t n2, Int_t n3, Int_t n4) return four; -} // TComplex Four(Int_t n1, Int_t n2, Int_t n3, Int_t n4) +} // TComplex Four(int n1, int n2, int n3, int n4) //============================================================ -TComplex Five(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5) +TComplex Five(int n1, int n2, int n3, int n4, int n5) { // Generic five-particle correlation . @@ -3096,11 +10957,11 @@ TComplex Five(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5) return five; -} // TComplex Five(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5) +} // TComplex Five(int n1, int n2, int n3, int n4, int n5) //============================================================ -TComplex Six(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6) +TComplex Six(int n1, int n2, int n3, int n4, int n5, int n6) { // Generic six-particle correlation . @@ -3108,302 +10969,941 @@ TComplex Six(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6) return six; -} // TComplex Six(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6) +} // TComplex Six(int n1, int n2, int n3, int n4, int n5, int n6) + +//============================================================ + +TComplex Seven(int n1, int n2, int n3, int n4, int n5, int n6, int n7) +{ + // Generic seven-particle correlation . + + int harmonic[7] = {n1, n2, n3, n4, n5, n6, n7}; + + TComplex seven = Recursion(7, harmonic); + + return seven; + +} // end of TComplex Seven(int n1, int n2, int n3, int n4, int n5, int n6, int n7) + +//============================================================ + +TComplex Eight(int n1, int n2, int n3, int n4, int n5, int n6, int n7, int n8) +{ + // Generic eight-particle correlation . + + int harmonic[8] = {n1, n2, n3, n4, n5, n6, n7, n8}; + + TComplex eight = Recursion(8, harmonic); + + return eight; + +} // end of Eight(int n1, int n2, int n3, int n4, int n5, int n6, int n7, int n8) + +//============================================================ + +TComplex Nine(int n1, int n2, int n3, int n4, int n5, int n6, int n7, int n8, int n9) +{ + // Generic nine-particle correlation . + + int harmonic[9] = {n1, n2, n3, n4, n5, n6, n7, n8, n9}; + + TComplex nine = Recursion(9, harmonic); + + return nine; + +} // end of TComplex Nine(int n1, int n2, int n3, int n4, int n5, int n6, int n7, int n8, int n9) + +//============================================================ + +TComplex Ten(int n1, int n2, int n3, int n4, int n5, int n6, int n7, int n8, int n9, int n10) +{ + // Generic ten-particle correlation . + + int harmonic[10] = {n1, n2, n3, n4, n5, n6, n7, n8, n9, n10}; + + TComplex ten = Recursion(10, harmonic); + + return ten; + +} // end of TComplex Ten(int n1, int n2, int n3, int n4, int n5, int n6, int n7, int n8, int n9, int n10) + +//============================================================ + +TComplex Eleven(int n1, int n2, int n3, int n4, int n5, int n6, int n7, int n8, int n9, int n10, int n11) +{ + // Generic eleven-particle correlation . + + int harmonic[11] = {n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11}; + + TComplex eleven = Recursion(11, harmonic); + + return eleven; + +} // end of TComplex Eleven(int n1, int n2, int n3, int n4, int n5, int n6, int n7, int n8, int n9, int n10, int n11) + +//============================================================ + +TComplex Twelve(int n1, int n2, int n3, int n4, int n5, int n6, int n7, int n8, int n9, int n10, int n11, int n12) +{ + // Generic twelve-particle correlation . + + int harmonic[12] = {n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12}; + + TComplex twelve = Recursion(12, harmonic); + + return twelve; + +} // end of TComplex Twelve(int n1, int n2, int n3, int n4, int n5, int n6, int n7, int n8, int n9, int n10, int n11, int n12) + +//============================================================ + +TComplex Recursion(int n, int* harmonic, int mult = 1, int skip = 0) +{ + // Calculate multi-particle correlators by using recursion (an improved faster version) originally developed by + // Kristjan Gulbrandsen (gulbrand@nbi.dk). + + int nm1 = n - 1; + TComplex c(Q(harmonic[nm1], mult)); + if (nm1 == 0) + return c; + c *= Recursion(nm1, harmonic); + if (nm1 == skip) + return c; + + int multp1 = mult + 1; + int nm2 = n - 2; + int counter1 = 0; + int hhold = harmonic[counter1]; + harmonic[counter1] = harmonic[nm2]; + harmonic[nm2] = hhold + harmonic[nm1]; + TComplex c2(Recursion(nm1, harmonic, multp1, nm2)); + int counter2 = n - 3; + while (counter2 >= skip) { + harmonic[nm2] = harmonic[counter1]; + harmonic[counter1] = hhold; + ++counter1; + hhold = harmonic[counter1]; + harmonic[counter1] = harmonic[nm2]; + harmonic[nm2] = hhold + harmonic[nm1]; + c2 += Recursion(nm1, harmonic, multp1, counter2); + --counter2; + } + harmonic[nm2] = harmonic[counter1]; + harmonic[counter1] = hhold; + + if (mult == 1) + return c - c2; + return c - static_cast(mult) * c2; + +} // TComplex Recursion(int n, int* harmonic, int mult = 1, int skip = 0) + +//============================================================ + +void ResetQ() +{ + // Reset the components of generic Q-vectors. Use it whenever you call the + // standard functions for correlations, for some custom Q-vectors. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + for (int h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { + for (int wp = 0; wp < gMaxCorrelator + 1; wp++) // weight power + { + qv.fQ[h][wp] = TComplex(0., 0.); + } + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void ResetQ() + +//============================================================ + +void SetWeightsHist(TH1D* const hist, eWeights whichWeight) +{ + // Copy histogram holding weights from an external file to the corresponding data member. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // Finally: + hist->SetDirectory(0); + pw.fWeightsHist[whichWeight] = reinterpret_cast(hist); + + if (!pw.fWeightsHist[whichWeight]) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + // Cosmetics: TBI 20240216 do I really want to overwrite initial cosmetics, perhaps this shall go better into MakeWeights.C ? + // Or I could move all this to GetHistogramWithWeights, where in any case I am setting e.g. histogram title, etc. + TString sVariable[eWeights_N] = {"#varphi", "p_{t}", "#eta"}; // [phi,pt,eta] + TString sWeights[eWeights_N] = {"w_{#varphi}", "w_{p_{t}}", "w_{#eta}"}; + pw.fWeightsHist[whichWeight]->SetStats(false); + pw.fWeightsHist[whichWeight]->GetXaxis()->SetTitle(sVariable[whichWeight].Data()); + pw.fWeightsHist[whichWeight]->GetYaxis()->SetTitle(sWeights[whichWeight].Data()); + pw.fWeightsHist[whichWeight]->SetFillColor(eFillColor); + pw.fWeightsHist[whichWeight]->SetLineColor(eColor); + if (!pw.fWeightsList) { + LOGF(fatal, "\033[1;31m%s at line %d: fWeightsList is NULL. That means that you have called SetWeightsHist(...) in init(), before this TList was booked.\033[0m", __FUNCTION__, __LINE__); + } + pw.fWeightsList->Add(pw.fWeightsHist[whichWeight]); // This is working at the moment, because I am fetching all weights in Preprocess(), which is called after init() + // But if eventually it will be possible to fetch run number programatically in init(), I will have to re-think this line. + + // Flag: + pw.fUseWeights[whichWeight] = true; + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void SetWeightsHist(TH1D* const hist, eWeights whichWeight) + +//============================================================ + +void SetDiffWeightsHist(TH1D* const hist, eDiffWeights whichDiffWeight, int bin) +{ + // Copy histogram holding differential weights from an external file to the corresponding data member. + + // Remark: Do not edit histogram title here, because that's done in GetHistogramWithWeights(), because I have "filePath" info there locally. + // Only if I promote "filePath" to data members, re-think the design of this function, and what goes where. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // Finally: + hist->SetDirectory(0); + pw.fDiffWeightsHist[whichDiffWeight][bin] = reinterpret_cast(hist); + + if (!pw.fDiffWeightsHist[whichDiffWeight][bin]) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + // Cosmetics: TBI 20240216 do I really want to overwrite initial cosmetics, perhaps this shall go better into MakeWeights.C ? + // Or I could move all this to GetHistogramWithWeights, where in any case I am setting e.g. histogram title, etc. + TString sVariable[eDiffWeights_N] = {"#varphi", "#varphi"}; // yes, for the time being, x-axis is always phi + TString sWeights[eDiffWeights_N] = {"(w_{#varphi})_{| p_{T}}", "(w_{#varphi})_{| #eta}"}; + pw.fDiffWeightsHist[whichDiffWeight][bin]->SetStats(false); + pw.fDiffWeightsHist[whichDiffWeight][bin]->GetXaxis()->SetTitle(sVariable[whichDiffWeight].Data()); + pw.fDiffWeightsHist[whichDiffWeight][bin]->GetYaxis()->SetTitle(sWeights[whichDiffWeight].Data()); + pw.fDiffWeightsHist[whichDiffWeight][bin]->SetFillColor(eFillColor); + pw.fDiffWeightsHist[whichDiffWeight][bin]->SetLineColor(eColor); + pw.fWeightsList->Add(pw.fDiffWeightsHist[whichDiffWeight][bin]); // This is working at the moment, because I am fetching all weights in Preprocess(), which is called after init() + // But if eventually it will be possible to fetch run number programatically in init(), I will have to re-think this line. + + // Flag: + if (!pw.fUseDiffWeights[whichDiffWeight]) // yes, set it only once to true, for all bins + { + pw.fUseDiffWeights[whichDiffWeight] = true; + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // SetDiffWeightsHist(TH1D* const hist, const char *variable, int bin) + +//============================================================ + +void SetDiffWeightsSparse(THnSparseF* const sparse, eDiffWeightCategory dwc) +{ + // Copy sparse histogram holding differential phi, pt, eta, etc., weights from an external file to the corresponding data member. + + // Remark: Do not edit sparse histogram title here, because that's done in GetHistogramWithWeights(), because I have "filePath" info there locally. + // Only if I promote "filePath" to data members, re-think the design of this function, and what goes where. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // Finally: + // sparse->SetDirectory(0); I cannot use this for sparse + pw.fDiffWeightsSparse[dwc] = reinterpret_cast(sparse); + + if (!pw.fDiffWeightsSparse[dwc]) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + // Within current analysis the dimension of weight for each category won't change, therefore I store it permanently: + pw.fDWdimension[dwc] = pw.fDiffWeightsSparse[dwc]->GetNdimensions(); + + // I book here immediately vectors needed to fetch the weight from the right bin of THnSparse: + pw.fFindBinVector[dwc] = new TArrayD(pw.fDWdimension[dwc]); + + // Finally, add to corresponding TList: + pw.fWeightsList->Add(pw.fDiffWeightsSparse[dwc]); + + /* + +TBI-today + + // Cosmetics: TBI 20240216 do I really want to overwrite initial cosmetics, perhaps this shall go better into MakeWeights.C ? + // Or I could move all this to GetHistogramWithWeights, where in any case I am setting e.g. histogram title, etc. + TString sVariable[eDiffWeights_N] = {"#varphi", "#varphi"}; // yes, for the time being, x-axis is always phi + TString sWeights[eDiffWeights_N] = {"(w_{#varphi})_{| p_{T}}", "(w_{#varphi})_{| #eta}"}; + pw.fDiffWeightsSparse[whichDiffWeight][bin]->SetStats(false); + pw.fDiffWeightsSparse[whichDiffWeight][bin]->GetXaxis()->SetTitle(sVariable[whichDiffWeight].Data()); + pw.fDiffWeightsSparse[whichDiffWeight][bin]->GetYaxis()->SetTitle(sWeights[whichDiffWeight].Data()); + pw.fDiffWeightsSparse[whichDiffWeight][bin]->SetFillColor(eFillColor); + pw.fDiffWeightsSparse[whichDiffWeight][bin]->SetLineColor(eColor); + pw.fWeightsList->Add(pw.fDiffWeightsSparse[whichDiffWeight][bin]); // This is working at the moment, because I am fetching all weights in Preprocess(), which is called after init() + // But if eventually it will be possible to fetch run number programatically in init(), I will have to re-think this line. + + // Flag: + if (!pw.fUseDiffWeights[whichDiffWeight]) // yes, set it only once to true, for all bins + { + pw.fUseDiffWeights[whichDiffWeight] = true; + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + + */ + +} // void SetDiffWeightsSparse(THnSparseF* const sparse) + +//============================================================ + +void SetCentralityWeightsHist(TH1D* const hist) +{ + // Copy histogram holding weights from an external file to the corresponding data member. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // Finally: + hist->SetDirectory(0); + cw.fCentralityWeightsHist = reinterpret_cast(hist); + + if (!cw.fCentralityWeightsHist) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + // Cosmetics: TBI 20240216 do I really want to overwrite initial cosmetics, perhaps this shall go better into MakeCentralityWeights.C ? + // Or I could move all this to GetHistogramWithCentralityWeights, where in any case I am setting e.g. histogram title, etc. + cw.fCentralityWeightsHist->SetStats(false); + cw.fCentralityWeightsHist->GetXaxis()->SetTitle("Centrality percentile"); + cw.fCentralityWeightsHist->GetYaxis()->SetTitle(Form("Centrality weight (%s)", ec.fsEventCuts[eCentralityEstimator].Data())); + cw.fCentralityWeightsHist->SetFillColor(eFillColor); + cw.fCentralityWeightsHist->SetLineColor(eColor); + if (!cw.fCentralityWeightsList) { + LOGF(fatal, "\033[1;31m%s at line %d: fCentralityWeightsList is NULL. That means that you have called SetCentralityWeightsHist(...) in init(), before this TList was booked.\033[0m", __FUNCTION__, __LINE__); + } + cw.fCentralityWeightsList->Add(cw.fCentralityWeightsHist); // This is working at the moment, because I am fetching all centrality weights in Preprocess(), which is called after init() + // But if eventually it will be possible to fetch run number programatically in init(), I will have to re-think this line. + + // Flag: + cw.fUseCentralityWeights = true; + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void SetCentralityWeightsHist(TH1D* const hist) + +//============================================================ + +TH1D* GetWeightsHist(eWeights whichWeight) +{ + // The standard getter. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // ... + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + + // Finally: + return pw.fWeightsHist[whichWeight]; + +} // TH1D* GetWeightsHist(eWeights whichWeigh) + +//============================================================ + +TH1D* GetHistogramWithWeights(const char* filePath, const char* runNumber, const char* variable, int bin = -1) +{ + // Get and return histogram with weights from an external file. + // If bin > 0, differential weights for that bin are searched for. + // If bin = -1, integrated weights are searched for, i.e. in this case "bin" variable has no effect. + // I do it this way, so as to condense GetHistogramWithWeights(...) and GetHistogramWithDiffWeights(...) from MuPa class in + // one routine here, so that I do not duplicate code related to CCDB access, etc. + + // TBI 20240504: Here I can keep const char* variable , i.e. no need to switch to enums, because this function is called only once, at init. + // Nevertheless, I could switch to enums and make it more general, i.e. I could introduce additional data members and configurables, + // for the names of histograms with weights. Like I did it in void GetHistogramWithCustomNUA(const char* filePath, eNUAPDF variable) -//============================================================ + // TBI 20241021 Strictly speaking, I do not need to pass here first 2 arguments, "filePath" and "runNumber", because they are initialized at call from data members. + // But since this function is called only once, it's not an important performance loss. But re-think the design here eventually. + // If I decide to promote filePath to data member, implement it as an array, to allow possibility that different catagories of weights are fetched from different external files. -TComplex Seven(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6, Int_t n7) -{ - // Generic seven-particle correlation . + // a) Return value; + // b) Basic protection for arguments; + // c) Determine from filePath if the file in on a local machine, or in AliEn, or in CCDB; + // d) Handle the AliEn case; + // e) Handle the CCDB case; + // f) Handle the local case; + // g) The final touch on histogram with weights; + // h) Clone histogram and delete baseList (realising back the memory). - Int_t harmonic[7] = {n1, n2, n3, n4, n5, n6, n7}; + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + LOGF(info, "\033[1;33m filePath = %s\033[0m", filePath); + LOGF(info, "\033[1;33m runNumber = %s\033[0m", runNumber); + LOGF(info, "\033[1;33m variable = %s\033[0m", variable); + LOGF(info, "\033[1;33m bin = %d (if bin = -1, integrated weights are searched for)\033[0m", bin); + LOGF(info, "\033[1;33m fTaskName = %s\033[0m", tc.fTaskName.Data()); + } - TComplex seven = Recursion(7, harmonic); + // a) Return value: + TH1D* hist = NULL; + TList* baseList = NULL; // base top-level list in the TFile, e.g. named "ccdb_object" + TList* listWithRuns = NULL; // nested list with run-wise TList's holding run-specific weights - return seven; + // b) Basic protection for arguments: + // Remark: below I do one more specific check. + if (!(TString(variable).EqualTo("phi") || TString(variable).EqualTo("pt") || TString(variable).EqualTo("eta") || + TString(variable).EqualTo("phipt") || TString(variable).EqualTo("phieta"))) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } -} // end of TComplex Seven(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6, Int_t n7) + // c) Determine from filePath if the file in on a local machine, or in home + // dir AliEn, or in CCDB: + // Algorithm: If filePath begins with "/alice/cern.ch/" then it's in home + // dir AliEn. If filePath begins with "/alice-ccdb.cern.ch/" then it's in + // CCDB. Therefore, files in AliEn and CCDB must be specified with abs path, + // for local files both abs and relative paths are just fine. + bool bFileIsInAliEn = false; + bool bFileIsInCCDB = false; + if (TString(filePath).BeginsWith("/alice/cern.ch/")) { + bFileIsInAliEn = true; + } else { + if (TString(filePath).BeginsWith("/alice-ccdb.cern.ch/")) { + bFileIsInCCDB = true; + } // else { + } // if (TString(filePath).BeginsWith("/alice/cern.ch/")) { -//============================================================ + if (bFileIsInAliEn) { + // d) Handle the AliEn case: + TGrid* alien = TGrid::Connect("alien", gSystem->Getenv("USER"), "", ""); + if (!alien) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + TFile* weightsFile = TFile::Open(Form("alien://%s", filePath), "READ"); + if (!weightsFile) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } -TComplex Eight(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6, Int_t n7, Int_t n8) -{ - // Generic eight-particle correlation . + weightsFile->GetObject( + "ccdb_object", baseList); // TBI 20231008 for simplicity, hardwired name + // of base TList is "ccdb_object" also for + // AliEn case, see if I need to change this + if (!baseList) { + // weightsFile->ls(); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } - Int_t harmonic[8] = {n1, n2, n3, n4, n5, n6, n7, n8}; + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumber)); + if (!listWithRuns) { + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } - TComplex eight = Recursion(8, harmonic); + } else if (bFileIsInCCDB) { - return eight; + // e) Handle the CCDB case: Remember that here I do not access the file, + // instead directly object in that file. + // My home dir in CCDB: https://alice-ccdb.cern.ch/browse/Users/a/abilandz/ + // Inspired by: + // 1. Discussion at: + // https://alice-talk.web.cern.ch/t/access-to-lhc-filling-scheme/1073/17 + // 2. See also: + // https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/efficiencyGlobal.cxx + // https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/efficiencyPerRun.cxx + // 3. O2 Analysis Tutorial 2.0: + // https://indico.cern.ch/event/1267433/timetable/#20230417.detailed -} // end of Eight(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6, Int_t n7, Int_t n8) + ccdb->setURL("http://alice-ccdb.cern.ch"); + if (tc.fVerbose) { + LOGF(info, "\033[1;32mAccessing in CCDB %s\033[0m", TString(filePath).ReplaceAll("/alice-ccdb.cern.ch/", "").Data()); + } -//============================================================ + baseList = reinterpret_cast(ccdb->get(TString(filePath).ReplaceAll("/alice-ccdb.cern.ch/", "").Data())); -TComplex Nine(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6, Int_t n7, Int_t n8, Int_t n9) -{ - // Generic nine-particle correlation . + if (!baseList) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } - Int_t harmonic[9] = {n1, n2, n3, n4, n5, n6, n7, n8, n9}; + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumber)); + if (!listWithRuns) { + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } - TComplex nine = Recursion(9, harmonic); + } else { - return nine; + // f) Handle the local case: + // TBI 20231008 In principle, also for the local case in O2, I could + // maintain the same local structure of weights as it was in AliPhysics. + // But for simplicity, in O2 I organize local weights in the + // same way as in AliEn or CCDB. -} // end of TComplex Nine(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6, Int_t n7, Int_t n8, Int_t n9) + // Check if the external ROOT file exists at specified path: + if (gSystem->AccessPathName(filePath, kFileExists)) { + LOGF(info, "\033[1;33m if(gSystem->AccessPathName(filePath,kFileExists)), filePath = %s \033[0m", filePath); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } -//============================================================ + TFile* weightsFile = TFile::Open(filePath, "READ"); + if (!weightsFile) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } -TComplex Ten(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6, Int_t n7, Int_t n8, Int_t n9, Int_t n10) -{ - // Generic ten-particle correlation . + weightsFile->GetObject("ccdb_object", baseList); // TBI 20231008 for simplicity, hardwired name + // of base TList is "ccdb_object" also for + // local case, see if I need to change this + if (!baseList) { + // weightsFile->ls(); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } - Int_t harmonic[10] = {n1, n2, n3, n4, n5, n6, n7, n8, n9, n10}; + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumber)); + if (!listWithRuns) { + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + // baseList->ls(); + LOGF(fatal, "\033[1;31m%s at line %d : this crash can happen if in the output file there is no list with weights for the current run number = %s\033[0m", __FUNCTION__, __LINE__, tc.fRunNumber.Data()); + } + } - TComplex ten = Recursion(10, harmonic); + } // else { - return ten; + // g) The final touch on histogram with weights: + TString histName = ""; + if (-1 == bin) { + // Integrated weights: + if (!(TString(variable).EqualTo("phi") || TString(variable).EqualTo("pt") || TString(variable).EqualTo("eta"))) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } -} // end of TComplex Ten(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6, Int_t n7, Int_t n8, Int_t n9, Int_t n10) + // fetch histogram directly from this list: + histName = TString::Format("%s_%s", variable, tc.fTaskName.Data()); + LOGF(info, "\033[1;33m%s at line %d : fetching directly hist with name = %s\033[0m", __FUNCTION__, __LINE__, histName.Data()); + hist = reinterpret_cast(listWithRuns->FindObject(histName.Data())); + // if the previous search failed, descend recursively also into the nested lists: + if (!hist) { + LOGF(info, "\033[1;33m%s at line %d : previous attempt failed, fetching instead recursively hist with name = %s\033[0m", __FUNCTION__, __LINE__, histName.Data()); + hist = reinterpret_cast(GetObjectFromList(listWithRuns, histName.Data())); + } + if (!hist) { + histName = TString::Format("%s", variable); // yes, for some simple tests I can have only histogram named e.g. 'phi' + LOGF(info, "\033[1;33m%s at line %d : last attempt, fetching instead hist with trivial name = %s\033[0m", __FUNCTION__, __LINE__, histName.Data()); + hist = reinterpret_cast(GetObjectFromList(listWithRuns, histName.Data())); + } + if (!hist) { + listWithRuns->ls(); + LOGF(fatal, "\033[1;31m%s at line %d : couldn't fetch hist with name = %s\033[0m", __FUNCTION__, __LINE__, histName.Data()); + } + hist->SetDirectory(0); + hist->SetTitle(Form("%s, %s", filePath, runNumber)); // I have to do it here, because only here I have "filePath" av -//============================================================ + } else { + // Differential weights: + if (!(TString(variable).EqualTo("phipt") || TString(variable).EqualTo("phieta"))) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + // fetch histogram directly from this list: + histName = TString::Format("%s[%d]_%s", variable, bin, tc.fTaskName.Data()); + LOGF(info, "\033[1;33m%s at line %d : fetching directly hist with name = %s\033[0m", __FUNCTION__, __LINE__, histName.Data()); + hist = reinterpret_cast(listWithRuns->FindObject(histName.Data())); + // if the previous search failed, descend recursively also into the nested lists: + if (!hist) { + LOGF(info, "\033[1;33m%s at line %d : previous attempt failed, fetching instead recursively hist with name = %s\033[0m", __FUNCTION__, __LINE__, histName.Data()); + hist = reinterpret_cast(GetObjectFromList(listWithRuns, Form("%s[%d]_%s", variable, bin, tc.fTaskName.Data()))); + } + if (!hist) { + histName = TString::Format("%s[%d]", variable, bin); // yes, for some simple tests I can have only histogram named e.g. 'phipt[0]' + LOGF(info, "\033[1;33m%s at line %d : last attempt, fetching instead hist with trivial name = %s\033[0m", __FUNCTION__, __LINE__, histName.Data()); + hist = reinterpret_cast(GetObjectFromList(listWithRuns, histName.Data())); + } + if (!hist) { + listWithRuns->ls(); + LOGF(fatal, "\033[1;31m%s at line %d : couldn't fetch hist with name = %s\033[0m", __FUNCTION__, __LINE__, histName.Data()); + } -TComplex Eleven(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6, Int_t n7, Int_t n8, Int_t n9, Int_t n10, Int_t n11) -{ - // Generic eleven-particle correlation . + // *) insanity check for differential weights => check if boundaries of current bin are the same as bin boundaries for which these weights were calculated. + // This way I ensure that weights correspond to same kinematic cuts and binning as in current analysis. + // Current example format which was set in MakeWeights.C: someString(s), min < kinematic-variable-name < max + // Algorithm: IFS is " " and I take (N-1)th and (N-5)th entry: + TObjArray* oa = TString(hist->GetTitle()).Tokenize(" "); + if (!oa) { + LOGF(fatal, "in function \033[1;31m%s at line %d \n hist->GetTitle() = %s\033[0m", __FUNCTION__, __LINE__, hist->GetTitle()); + } + int nEntries = oa->GetEntries(); - Int_t harmonic[11] = {n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11}; + // I need to figure out corresponding variable from results histograms and its formatting: + eAsFunctionOf AFO = eAsFunctionOf_N; + const char* lVariableName = ""; + if (TString(variable).EqualTo("phipt")) { + AFO = AFO_PT; + lVariableName = FancyFormatting("Pt"); + } else if (TString(variable).EqualTo("phieta")) { + AFO = AFO_ETA; + lVariableName = FancyFormatting("Eta"); + } else { + LOGF(fatal, "\033[1;31m%s at line %d : name = %s is not supported yet. \033[0m", __FUNCTION__, __LINE__, static_cast(variable)); + } - TComplex eleven = Recursion(11, harmonic); + // Get min and max value for bin, stored locally: + float min = res.fResultsPro[AFO]->GetBinLowEdge(bin + 1); + float max = res.fResultsPro[AFO]->GetBinLowEdge(bin + 2); + if (min > max) { + LOGF(fatal, "\033[1;33m min = %f, max = %f, res.fResultsPro[AFO]->GetName() = %s\033[0m", min, max, res.fResultsPro[AFO]->GetName()); + } - return eleven; + // Compare with min and max value stored in external weights.root file using MakeWeights.C: + if (!(TMath::Abs(TString(oa->At(nEntries - 1)->GetName()).Atof() - max) < tc.fFloatingPointPrecision)) { + LOGF(info, "\033[1;33m hist->GetTitle() = %s, res.fResultsPro[AFO]->GetName() = %s\033[0m", hist->GetTitle(), res.fResultsPro[AFO]->GetName()); + LOGF(fatal, "in function \033[1;31m%s at line %d : mismatch in upper bin boundaries \n from title = %f , local = %f\033[0m", __FUNCTION__, __LINE__, TString(oa->At(nEntries - 1)->GetName()).Atof(), max); + } + if (!(TMath::Abs(TString(oa->At(nEntries - 5)->GetName()).Atof() - min) < tc.fFloatingPointPrecision)) { + LOGF(info, "\033[1;33m hist->GetTitle() = %s, res.fResultsPro[AFO]->GetName() = %s\033[0m", hist->GetTitle(), res.fResultsPro[AFO]->GetName()); + LOGF(fatal, "in function \033[1;31m%s at line %d : mismatch in lower bin boundaries \n from title = %f , local = %f\033[0m", __FUNCTION__, __LINE__, TString(oa->At(nEntries - 5)->GetName()).Atof(), min); + } + delete oa; // yes, otherwise it's a memory leak -} // end of TComplex Eleven(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6, Int_t n7, Int_t n8, Int_t n9, Int_t n10, Int_t n11) + // *) final settings and cosmetics: + hist->SetDirectory(0); + hist->SetTitle(Form("%s, %.2f < %s < %.2f", filePath, min, lVariableName, max)); -//============================================================ + } // else -TComplex Twelve(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6, Int_t n7, Int_t n8, Int_t n9, Int_t n10, Int_t n11, Int_t n12) -{ - // Generic twelve-particle correlation . + // TBI 20241021 if I need to split hist title across two lines, use this technique: + // hist->SetTitle(Form("#splitline{#scale[0.6]{%s}}{#scale[0.4]{%s}}",hist->GetTitle(),filePath)); - Int_t harmonic[12] = {n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12}; + // h) Clone histogram and delete baseList (realising back the memory): + // Remark: Yes, I have to clone here. + TH1D* histClone = reinterpret_cast(hist->Clone()); + delete baseList; // release back the memory - TComplex twelve = Recursion(12, harmonic); + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } - return twelve; + return histClone; -} // end of TComplex Twelve(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6, Int_t n7, Int_t n8, Int_t n9, Int_t n10, Int_t n11, Int_t n12) +} // TH1D* GetHistogramWithWeights(const char* filePath, const char* runNumber, const char* variable, int bin = -1) //============================================================ -TComplex Recursion(Int_t n, Int_t* harmonic, Int_t mult = 1, Int_t skip = 0) +THnSparseF* GetSparseHistogramWithWeights(const char* filePath, const char* runNumber, const char* whichCategory, const char* whichDimensions) { - // Calculate multi-particle correlators by using recursion (an improved faster version) originally developed by - // Kristjan Gulbrandsen (gulbrand@nbi.dk). + // Get and return sparse histogram with weights from an external file. - Int_t nm1 = n - 1; - TComplex c(Q(harmonic[nm1], mult)); - if (nm1 == 0) - return c; - c *= Recursion(nm1, harmonic); - if (nm1 == skip) - return c; + // Remark 1: "whichCategory" always indicates the default x-axis (0th dimension), for instance for "differential phi weights" it's "phi" - Int_t multp1 = mult + 1; - Int_t nm2 = n - 2; - Int_t counter1 = 0; - Int_t hhold = harmonic[counter1]; - harmonic[counter1] = harmonic[nm2]; - harmonic[nm2] = hhold + harmonic[nm1]; - TComplex c2(Recursion(nm1, harmonic, multp1, nm2)); - Int_t counter2 = n - 3; - while (counter2 >= skip) { - harmonic[nm2] = harmonic[counter1]; - harmonic[counter1] = hhold; - ++counter1; - hhold = harmonic[counter1]; - harmonic[counter1] = harmonic[nm2]; - harmonic[nm2] = hhold + harmonic[nm1]; - c2 += Recursion(nm1, harmonic, multp1, counter2); - --counter2; - } - harmonic[nm2] = harmonic[counter1]; - harmonic[counter1] = hhold; + // Remark 2: "whichDimensions" is formatted as follows: __..., for instance "pt_cent", if weights are calculated differentially as a function of pt and centrality + // If empty, that is also fine, I am fetching integrated weights, for instance integrated phi-weights. - if (mult == 1) - return c - c2; - return c - Double_t(mult) * c2; + // Remark 3: The nameing convention for sparse histogram in the output file is: __multiparticle-correlations-a-b_ + // a) I allow possibility that "multiparticle-correlations-a-b_" is not present in the name + // b) In HL, fTaskName is typically subwagon name. Therefoere, it's mandatory that for a given subwagon in HL, BOTH subwagon name and fTaskName are set to the same name + // TBI 20250215 If I can get within my task at run time subwagon name, I can automate this step. Check if that is possible -} // TComplex Recursion(Int_t n, Int_t* harmonic, Int_t mult = 1, Int_t skip = 0) + // TBI 20240504: Here I can keep const char* variable , i.e. no need to switch to enums, because this function is called only once, at init. + // Nevertheless, I could switch to enums and make it more general, i.e. I could introduce additional data members and configurables, + // for the names of histograms with weights. Like I did it in void GetHistogramWithCustomNUA(const char* filePath, eNUAPDF variable) -//============================================================ + // TBI 20241021 Strictly speaking, I do not need to pass here first 2 arguments, "filePath" and "runNumber", because they are initialized at call from data members. + // But since this function is called only once, it's not an important performance loss. But re-think the design here eventually. + // If I decide to promote filePath to data member, implement it as an array, to allow possibility that different catagories of weights are fetched from different external files. -void ResetQ() -{ - // Reset the components of generic Q-vectors. Use it whenever you call the - // standard functions for correlations, for some custom Q-vectors. + // a) Return value; + // b) Basic protection for arguments; + // c) Determine from filePath if the file in on a local machine, or in AliEn, or in CCDB; + // d) Handle the AliEn case; + // e) Handle the CCDB case; + // f) Handle the local case; + // g) The final touch on sparse histogram with weights; + // h) Clone histogram and delete baseList (realising back the memory). if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); + LOGF(info, "\033[1;33m filePath = %s\033[0m", filePath); + LOGF(info, "\033[1;33m runNumber = %s\033[0m", runNumber); + LOGF(info, "\033[1;33m whichDimensions = %s\033[0m", whichDimensions); } - for (Int_t h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { - for (Int_t wp = 0; wp < gMaxCorrelator + 1; wp++) // weight power - { - qv.fQ[h][wp] = TComplex(0., 0.); - } + // a) Return value: + THnSparseF* sparseHist = NULL; + TList* baseList = NULL; // base top-level list in the TFile, e.g. named "ccdb_object" + TList* listWithRuns = NULL; // nested list with run-wise TList's holding run-specific weights + + // b) Basic protection for arguments: + // Remark: below I do one more specific check. + if (!(TString(whichCategory).EqualTo("phi"))) { // TBI 20250215 I could in the future extend support to differential pT weights, etc. + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + if (TString(whichDimensions).EqualTo("")) { + LOGF(warning, "\033[1;33m%s at line %d : whichDimensions is empty, accessing only integrated %s weights\033[0m", __FUNCTION__, __LINE__, whichCategory); } -} // void ResetQ() + // c) Determine from filePath if the file in on a local machine, or in home + // dir AliEn, or in CCDB: + // Algorithm: If filePath begins with "/alice/cern.ch/" then it's in home + // dir AliEn. If filePath begins with "/alice-ccdb.cern.ch/" then it's in + // CCDB. Therefore, files in AliEn and CCDB must be specified with abs path, + // for local files both abs and relative paths are just fine. + bool bFileIsInAliEn = false; + bool bFileIsInCCDB = false; + if (TString(filePath).BeginsWith("/alice/cern.ch/")) { + bFileIsInAliEn = true; + } else { + if (TString(filePath).BeginsWith("/alice-ccdb.cern.ch/")) { + bFileIsInCCDB = true; + } // else { + } // if (TString(filePath).BeginsWith("/alice/cern.ch/")) { -//============================================================ + if (bFileIsInAliEn) { + // d) Handle the AliEn case: + TGrid* alien = TGrid::Connect("alien", gSystem->Getenv("USER"), "", ""); + if (!alien) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + TFile* weightsFile = TFile::Open(Form("alien://%s", filePath), "READ"); + if (!weightsFile) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } -void SetWeightsHist(TH1D* const hist, const char* variable) -{ - // Copy histogram holding weights from an external file to the corresponding - // data member. + weightsFile->GetObject("ccdb_object", baseList); // TBI 20231008 for simplicity, hardwired name + // of base TList is "ccdb_object" also for + // AliEn case, see if I need to change this + if (!baseList) { + // weightsFile->ls(); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); - } + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumber)); + if (!listWithRuns) { + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } - // Basic protection: - if (!(TString(variable).EqualTo("phi") || TString(variable).EqualTo("pt") || - TString(variable).EqualTo("eta"))) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); - } + } else if (bFileIsInCCDB) { + + // e) Handle the CCDB case: Remember that here I do not access the file, + // instead directly object in that file. + // My home dir in CCDB: https://alice-ccdb.cern.ch/browse/Users/a/abilandz/ + // Inspired by: + // 1. Discussion at: + // https://alice-talk.web.cern.ch/t/access-to-lhc-filling-scheme/1073/17 + // 2. See also: + // https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/efficiencyGlobal.cxx + // https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/efficiencyPerRun.cxx + // 3. O2 Analysis Tutorial 2.0: + // https://indico.cern.ch/event/1267433/timetable/#20230417.detailed + + ccdb->setURL("http://alice-ccdb.cern.ch"); + if (tc.fVerbose) { + LOGF(info, "\033[1;32mAccessing in CCDB %s\033[0m", TString(filePath).ReplaceAll("/alice-ccdb.cern.ch/", "").Data()); + } - Int_t ppe = -1; - if (TString(variable).EqualTo("phi")) { - ppe = 0; - } - if (TString(variable).EqualTo("pt")) { - ppe = 1; - } - if (TString(variable).EqualTo("eta")) { - ppe = 2; - } + baseList = reinterpret_cast(ccdb->get(TString(filePath).ReplaceAll("/alice-ccdb.cern.ch/", "").Data())); - // Finally: - hist->SetDirectory(0); - pw.fWeightsHist[ppe] = reinterpret_cast(hist->Clone()); + if (!baseList) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } - if (!pw.fWeightsHist[ppe]) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); - } + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumber)); + if (!listWithRuns) { + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } - // Cosmetics: TBI 20240216 do I really want to overwrite initial cosmetics, perhaps this shall go better into MakeWeights.C ? - // Or I could move all this to GetHistogramWithWeights, where in any case I am setting e.g. histogram title, etc. - TString sVariable[eWeights_N] = {"#varphi", "p_{t}", "#eta"}; // [phi,pt,eta] - TString sWeights[eWeights_N] = {"w_{#varphi}", "w_{p_{t}}", "w_{#eta}"}; - pw.fWeightsHist[ppe]->SetStats(kFALSE); - pw.fWeightsHist[ppe]->GetXaxis()->SetTitle(sVariable[ppe].Data()); - pw.fWeightsHist[ppe]->GetYaxis()->SetTitle(sWeights[ppe].Data()); - pw.fWeightsHist[ppe]->SetFillColor(eFillColor); - pw.fWeightsHist[ppe]->SetLineColor(eColor); - pw.fWeightsList->Add(pw.fWeightsHist[ppe]); + } else { - // Flag: - pw.fUseWeights[ppe] = kTRUE; + // f) Handle the local case: + // TBI 20231008 In principle, also for the local case in O2, I could + // maintain the same local structure of weights as it was in AliPhysics. + // But for simplicity, in O2 I organize local weights in the + // same way as in AliEn or CCDB. -} // void SetWeightsHist(TH1D* const hist, const char *variable) + // Check if the external ROOT file exists at specified path: + if (gSystem->AccessPathName(filePath, kFileExists)) { + LOGF(info, "\033[1;33m if(gSystem->AccessPathName(filePath,kFileExists)), filePath = %s \033[0m", filePath); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } -//============================================================ + TFile* weightsFile = TFile::Open(filePath, "READ"); + if (!weightsFile) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } -void SetDiffWeightsHist(TH1D* const hist, const char* variable, Int_t bin) -{ - // Copy histogram holding differential weights from an external file to the corresponding data member. + weightsFile->GetObject("ccdb_object", baseList); // TBI 20231008 for simplicity, hardwired name + // of base TList is "ccdb_object" also for + // local case, see if I need to change this + if (!baseList) { + // weightsFile->ls(); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); - } + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumber)); + if (!listWithRuns) { + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + // baseList->ls(); + LOGF(fatal, "\033[1;31m%s at line %d : this crash can happen if in the output file there is no list with weights for the current run number = %s\033[0m", __FUNCTION__, __LINE__, tc.fRunNumber.Data()); + } + } - // Basic protection: - if (!(TString(variable).EqualTo("phipt") || TString(variable).EqualTo("phieta"))) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); - } + } // else { - Int_t ppe = -1; // TBI 20240215 use enum's instead - if (TString(variable).EqualTo("phipt")) { - ppe = 0; + // g) The final touch on sparse histogram with weights: + TString sparseHistName = ""; + if (TString(whichDimensions).EqualTo("")) { + sparseHistName = TString::Format("%s_multiparticle-correlations-a-b", whichCategory); + } else if (TString(whichDimensions).BeginsWith("_")) { // TBI 20250215 alternativelly, I can remove leading "_" before calling this function + sparseHistName = TString::Format("%s%s_multiparticle-correlations-a-b", whichCategory, whichDimensions); + } else { + sparseHistName = TString::Format("%s_%s_multiparticle-correlations-a-b", whichCategory, whichDimensions); + } + // *) If not empty, I still need to appent TaskName (i.e. the cut name): + if (!TString(tc.fTaskName).EqualTo("")) { + sparseHistName += tc.fTaskName.Data(); + } + + // 1. fetch histogram directly from this list: const char* whichCategory, const char* whichDimensions + LOGF(info, "\033[1;33m%s at line %d : fetching directly from the list sparse histogram with name = %s\033[0m", __FUNCTION__, __LINE__, sparseHistName.Data()); + sparseHist = reinterpret_cast(listWithRuns->FindObject(sparseHistName.Data())); + if (!sparseHist) { + // try once again by chopping off "multiparticle-correlations-a-b_" from name: + TString tmp = sparseHistName; // yes, because "ReplaceAll" below replaces in-place, and I will need sparseHistName unmodified still later + sparseHist = reinterpret_cast(listWithRuns->FindObject(tmp.ReplaceAll("multiparticle-correlations-a-b_", ""))); + } + + // 2. if the previous search failed, descend recursively into the nested lists: + if (!sparseHist) { + LOGF(info, "\033[1;33m%s at line %d : previous attempt failed, fetching instead recursively sparse histogram with name = %s\033[0m", __FUNCTION__, __LINE__, sparseHistName.Data()); + sparseHist = reinterpret_cast(GetObjectFromList(listWithRuns, sparseHistName.Data())); + if (!sparseHist) { + // try once again by chopping off "multiparticle-correlations-a-b_" from name: + TString tmp = sparseHistName; // yes, because "ReplaceAll" below replaces in-place, and I will need sparseHistName unmodified still later + sparseHist = reinterpret_cast(GetObjectFromList(listWithRuns, tmp.ReplaceAll("multiparticle-correlations-a-b_", ""))); + } } - if (TString(variable).EqualTo("phieta")) { - ppe = 1; + + if (!sparseHist) { + listWithRuns->ls(); + LOGF(fatal, "\033[1;31m%s at line %d : couldn't fetch sparse histogram with name = %s from this list\033[0m", __FUNCTION__, __LINE__, sparseHistName.Data()); } - // Finally: - hist->SetDirectory(0); - pw.fDiffWeightsHist[ppe][bin] = reinterpret_cast(hist->Clone()); + sparseHist->SetTitle(Form("%s, %s", filePath, runNumber)); // I have to do it here, because only here I have "filePath" available - if (!pw.fDiffWeightsHist[ppe][bin]) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); - } + // hist->SetTitle(Form("%s, %.2f < %s < %.2f", filePath, min, lVariableName, max)); - // Cosmetics: TBI 20240216 do I really want to overwrite initial cosmetics, perhaps this shall go better into MakeWeights.C ? - // Or I could move all this to GetHistogramWithWeights, where in any case I am setting e.g. histogram title, etc. - TString sVariable[eWeights_N] = {"#varphi", "p_{t}", "#eta"}; // [phi,pt,eta] - TString sWeights[eWeights_N] = {"w_{#varphi}", "w_{p_{t}}", "w_{#eta}"}; - pw.fDiffWeightsHist[ppe][bin]->SetStats(kFALSE); - pw.fDiffWeightsHist[ppe][bin]->GetXaxis()->SetTitle(sVariable[ppe].Data()); - pw.fDiffWeightsHist[ppe][bin]->GetYaxis()->SetTitle(sWeights[ppe].Data()); - pw.fDiffWeightsHist[ppe][bin]->SetFillColor(eFillColor); - pw.fDiffWeightsHist[ppe][bin]->SetLineColor(eColor); - pw.fWeightsList->Add(pw.fDiffWeightsHist[ppe][bin]); + /* + // *) insanity check for differential weights => check if boundaries of current bin are the same as bin boundaries for which these weights were calculated. + // This way I ensure that weights correspond to same kinematic cuts and binning as in current analysis. + // Current example format which was set in MakeWeights.C: someString(s), min < kinematic-variable-name < max + // Algorithm: IFS is " " and I take (N-1)th and (N-5)th entry: + TObjArray* oa = TString(hist->GetTitle()).Tokenize(" "); + if (!oa) { + LOGF(fatal, "in function \033[1;31m%s at line %d \n hist->GetTitle() = %s\033[0m", __FUNCTION__, __LINE__, hist->GetTitle()); + } + int nEntries = oa->GetEntries(); + + // I need to figure out corresponding variable from results histograms and its formatting: + eAsFunctionOf AFO = eAsFunctionOf_N; + const char* lVariableName = ""; + if (TString(variable).EqualTo("phipt")) { + AFO = AFO_PT; + lVariableName = FancyFormatting("Pt"); + } else if (TString(variable).EqualTo("phieta")) { + AFO = AFO_ETA; + lVariableName = FancyFormatting("Eta"); + } else { + LOGF(fatal, "\033[1;31m%s at line %d : name = %s is not supported yet. \033[0m", __FUNCTION__, __LINE__, static_cast(variable)); + } - // Flag: - if (!pw.fUseDiffWeights[ppe]) // yes, set it only once to kTRUE, for all bins - { - pw.fUseDiffWeights[ppe] = kTRUE; - } + // Get min and max value for bin, stored locally: + float min = res.fResultsPro[AFO]->GetBinLowEdge(bin + 1); + float max = res.fResultsPro[AFO]->GetBinLowEdge(bin + 2); + if (min > max) { + LOGF(fatal, "\033[1;33m min = %f, max = %f, res.fResultsPro[AFO]->GetName() = %s\033[0m", min, max, res.fResultsPro[AFO]->GetName()); + } -} // SetDiffWeightsHist(TH1D* const hist, const char *variable, Int_t bin) + // Compare with min and max value stored in external weights.root file using MakeWeights.C: + if (!(TMath::Abs(TString(oa->At(nEntries - 1)->GetName()).Atof() - max) < tc.fFloatingPointPrecision)) { + LOGF(info, "\033[1;33m hist->GetTitle() = %s, res.fResultsPro[AFO]->GetName() = %s\033[0m", hist->GetTitle(), res.fResultsPro[AFO]->GetName()); + LOGF(fatal, "in function \033[1;31m%s at line %d : mismatch in upper bin boundaries \n from title = %f , local = %f\033[0m", __FUNCTION__, __LINE__, TString(oa->At(nEntries - 1)->GetName()).Atof(), max); + } + if (!(TMath::Abs(TString(oa->At(nEntries - 5)->GetName()).Atof() - min) < tc.fFloatingPointPrecision)) { + LOGF(info, "\033[1;33m hist->GetTitle() = %s, res.fResultsPro[AFO]->GetName() = %s\033[0m", hist->GetTitle(), res.fResultsPro[AFO]->GetName()); + LOGF(fatal, "in function \033[1;31m%s at line %d : mismatch in lower bin boundaries \n from title = %f , local = %f\033[0m", __FUNCTION__, __LINE__, TString(oa->At(nEntries - 5)->GetName()).Atof(), min); + } + delete oa; // yes, otherwise it's a memory leak -//============================================================ + // *) final settings and cosmetics: + hist->SetDirectory(0); -TH1D* GetWeightsHist(const char* variable) -{ - // The standard getter. + */ - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); - } + // TBI 20241021 if I need to split hist title across two lines, use this technique: + // hist->SetTitle(Form("#splitline{#scale[0.6]{%s}}{#scale[0.4]{%s}}",hist->GetTitle(),filePath)); - // Basic protection: - if (!(TString(variable).EqualTo("phi") || TString(variable).EqualTo("pt") || - TString(variable).EqualTo("eta"))) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); - } + // h) Clone histogram and delete baseList (realising back the memory): + // Remark: Yes, I have to clone here. + THnSparseF* sparseHistClone = reinterpret_cast(sparseHist->Clone()); + delete baseList; // release back the memory - Int_t ppe = -1; - if (TString(variable).EqualTo("phi")) { - ppe = 0; - } - if (TString(variable).EqualTo("pt")) { - ppe = 1; - } - if (TString(variable).EqualTo("eta")) { - ppe = 2; + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); } - // Finally: - return pw.fWeightsHist[ppe]; + return sparseHistClone; -} // TH1D* GetWeightsHist(const char *variable) +} // THnSparseF* GetSparseHistogramWithWeights(const char* filePath, const char* runNumber, const char* whichCategory, const char* whichDimensions) //============================================================ -TH1D* GetHistogramWithWeights(const char* filePath, const char* runNumber, const char* variable, Int_t bin = -1) +TH1D* GetHistogramWithCentralityWeights(const char* filePath, const char* runNumber) { - // Get and return histogram with weights from an external file. - // If bin > 0, differential weights for that bin are searched for. - // If bin = -1, integrated weights are searched for, i.e. in this case "bin" variable has no effect. - // I do it this way, so as to condense GetHistogramWithWeights(...) and GetHistogramWithDiffWeights(...) from MuPa class in - // one routine here, so that I do not duplicate code related to CCDB access, etc. + // Get and return histogram with centrality weights from an external file. + + // TBI 20241118 Shall I merge this function with GetHistogramWithWeights(...) as there is a bit of code bloat? + + // TBI 20241021 Strictly speaking, I do not need to pass here 2 arguments, "filePath" and "runNumber", because they are initialized at call from data members. + // But since this function is called only once, it's not an important performance loss. But re-think the design here eventually. // a) Return value; // b) Basic protection for arguments; @@ -3411,14 +11911,13 @@ TH1D* GetHistogramWithWeights(const char* filePath, const char* runNumber, const // d) Handle the AliEn case; // e) Handle the CCDB case; // f) Handle the local case; - // g) The final touch on histogram with weights. + // g) The final touch on histogram with centrality weights; + // h) Clone histogram and delete baseList (realising back the memory). if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); LOGF(info, "\033[1;33m filePath = %s\033[0m", filePath); LOGF(info, "\033[1;33m runNumber = %s\033[0m", runNumber); - LOGF(info, "\033[1;33m variable = %s\033[0m", variable); - LOGF(info, "\033[1;33m bin = %d\033[0m", bin); LOGF(info, "\033[1;33m fTaskName = %s\033[0m", tc.fTaskName.Data()); } @@ -3428,56 +11927,50 @@ TH1D* GetHistogramWithWeights(const char* filePath, const char* runNumber, const TList* listWithRuns = NULL; // nested list with run-wise TList's holding run-specific weights // b) Basic protection for arguments: - // Remark: below I do one more specific check. - if (!(TString(variable).EqualTo("phi") || TString(variable).EqualTo("pt") || TString(variable).EqualTo("eta") || - TString(variable).EqualTo("phipt") || TString(variable).EqualTo("phieta"))) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); - } + // ... - // c) Determine from filePath if the file in on a local machine, or in home - // dir AliEn, or in CCDB: + // c) Determine from filePath if the file in on a local machine, or in home dir AliEn, or in CCDB: // Algorithm: If filePath begins with "/alice/cern.ch/" then it's in home // dir AliEn. If filePath begins with "/alice-ccdb.cern.ch/" then it's in // CCDB. Therefore, files in AliEn and CCDB must be specified with abs path, // for local files both abs and relative paths are just fine. - Bool_t bFileIsInAliEn = kFALSE; - Bool_t bFileIsInCCDB = kFALSE; + bool bFileIsInAliEn = false; + bool bFileIsInCCDB = false; if (TString(filePath).BeginsWith("/alice/cern.ch/")) { - bFileIsInAliEn = kTRUE; + bFileIsInAliEn = true; } else { if (TString(filePath).BeginsWith("/alice-ccdb.cern.ch/")) { - bFileIsInCCDB = kTRUE; + bFileIsInCCDB = true; } // else { - } // if (TString(filePath).BeginsWith("/alice/cern.ch/")) { + } // if (TString(filePath).BeginsWith("/alice/cern.ch/")) { if (bFileIsInAliEn) { // d) Handle the AliEn case: TGrid* alien = TGrid::Connect("alien", gSystem->Getenv("USER"), "", ""); if (!alien) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - TFile* weightsFile = TFile::Open(Form("alien://%s", filePath), "READ"); - if (!weightsFile) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + TFile* centralityWeightsFile = TFile::Open(Form("alien://%s", filePath), "READ"); + if (!centralityWeightsFile) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - weightsFile->GetObject( - "ccdb_object", baseList); // TBI 20231008 for simplicity, harwired name - // of base TList is "ccdb_object" also for - // AliEn case, see if I need to change this + centralityWeightsFile->GetObject("ccdb_object", baseList); // TBI 20231008 for simplicity, hardwired name + // of base TList is "ccdb_object" also for + // AliEn case, see if I need to change this if (!baseList) { - // weightsFile->ls(); - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + // centralityWeightsFile->ls(); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumber)); if (!listWithRuns) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } } } else if (bFileIsInCCDB) { @@ -3496,25 +11989,23 @@ TH1D* GetHistogramWithWeights(const char* filePath, const char* runNumber, const ccdb->setURL("http://alice-ccdb.cern.ch"); if (tc.fVerbose) { - LOGF(info, "\033[1;32mAccessing in CCDB %s\033[0m", - TString(filePath).ReplaceAll("/alice-ccdb.cern.ch/", "").Data()); + LOGF(info, "\033[1;32mAccessing in CCDB %s\033[0m", TString(filePath).ReplaceAll("/alice-ccdb.cern.ch/", "").Data()); } - baseList = - reinterpret_cast(ccdb->get(TString(filePath) - .ReplaceAll("/alice-ccdb.cern.ch/", "") - .Data())); + baseList = reinterpret_cast(ccdb->get(TString(filePath).ReplaceAll("/alice-ccdb.cern.ch/", "").Data())); if (!baseList) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - listWithRuns = - reinterpret_cast(GetObjectFromList(baseList, runNumber)); + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumber)); if (!listWithRuns) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } } } else { @@ -3522,101 +12013,195 @@ TH1D* GetHistogramWithWeights(const char* filePath, const char* runNumber, const // f) Handle the local case: // TBI 20231008 In principle, also for the local case in O2, I could // maintain the same local structure of weights as it was in AliPhysics. - // But for simplicity, in O2 I organize local weights in the - // same way as in AliEn or CCDB. + // But for simplicity, in O2 I organize local weights in the same way as in AliEn or CCDB. // Check if the external ROOT file exists at specified path: if (gSystem->AccessPathName(filePath, kFileExists)) { - LOGF(info, - "\033[1;33m if(gSystem->AccessPathName(filePath,kFileExists)), " - "filePath = %s \033[0m", - filePath); - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + LOGF(info, "\033[1;33m if(gSystem->AccessPathName(filePath,kFileExists)), filePath = %s \033[0m", filePath); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - TFile* weightsFile = TFile::Open(filePath, "READ"); - if (!weightsFile) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + TFile* centralityWeightsFile = TFile::Open(filePath, "READ"); + if (!centralityWeightsFile) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - weightsFile->GetObject( - "ccdb_object", baseList); // TBI 20231008 for simplicity, harwired name - // of base TList is "ccdb_object" also for - // local case, see if I need to change this + /* + // xxxxxxxxxxxx TBI 20241124 remove this code + + hist = reinterpret_cast(centralityWeightsFile->Get("FT0C_Default list name")); // TBI 20241122 temporary workaround + if (!hist) { + Exit(); + } + hist->SetDirectory(0); + hist->SetTitle(Form("%s, %s", filePath, runNumber)); // I have to do it here, because only here I have "filePath" available + return hist; + + // xxxxxxxxxxxx + */ + + centralityWeightsFile->GetObject("ccdb_object", baseList); // TBI 20231008 for simplicity, hardwired name + // of base TList is "ccdb_object" also for + // local case, see if I need to change this + if (!baseList) { - // weightsFile->ls(); - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + // centralityWeightsFile->ls(); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - listWithRuns = - reinterpret_cast(GetObjectFromList(baseList, runNumber)); + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumber)); if (!listWithRuns) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } } } // else { - // g) The final touch on histogram with weights: - if (-1 == bin) { - // Integrated weights: - if (!(TString(variable).EqualTo("phi") || TString(variable).EqualTo("pt") || TString(variable).EqualTo("eta"))) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); - } - hist = reinterpret_cast(GetObjectFromList(listWithRuns, Form("%s_%s", variable, tc.fTaskName.Data()))); - if (!hist) { - hist = reinterpret_cast(GetObjectFromList(listWithRuns, Form("%s", variable))); // yes, for some simple tests I can have only histogram named e.g. 'phi' - } - if (!hist) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); - listWithRuns->ls(); - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); - } - hist->SetDirectory(0); - hist->SetTitle(Form("%s, %s", filePath, runNumber)); + // g) The final touch on histogram with centrality weights: + TString histName = ""; + + // fetch histogram directly from this list: + // Remark: histName must be formated as e.g. "FT0C_multiparticle-correlations-a-b" for default analysis, or "FT0C_multiparticle-correlations-a-b_someCut" + // Isolate short centrality estimator name, e.g. "FT0C" or "V0M" TBI 20250122 move this to utility function, because I have the same code in FancyFormatting() + TString tmp = ec.fsEventCuts[eCentralityEstimator]; // I have to introduce local TString tmp, because ReplaceAll replaces in-place + if (tmp.BeginsWith("CentRun2")) { + tmp.ReplaceAll("CentRun2", ""); // "CentRun2V0M" => "V0M" + } else if (tmp.BeginsWith("Cent")) { + tmp.ReplaceAll("Cent", ""); // "CentFT0C" => FT0C" } else { - // Differential weights: - if (!(TString(variable).EqualTo("phipt") || TString(variable).EqualTo("phieta"))) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d : the case tmp = %s is not supported yet\033[0m", __FUNCTION__, __LINE__, tmp.Data()); + } + + histName = TString::Format("%s_multiparticle-correlations-a-b", tmp.Data()); // I can hardwire here the name, as long as my main task name is struct MultiparticleCorrelationsAB + if (!tc.fTaskName.EqualTo("")) { + // for non-default analysis (e.g. in subwagon), append still "_someName", where "someName" is subwagon = taskname + histName += "_"; + histName += tc.fTaskName; + } + + LOGF(info, "\033[1;33m%s at line %d : fetching directly hist with name = %s\033[0m", __FUNCTION__, __LINE__, histName.Data()); + hist = reinterpret_cast(listWithRuns->FindObject(histName.Data())); + // if the previous search failed, descend recursively also into the nested lists: + if (!hist) { + LOGF(info, "\033[1;33m%s at line %d : previous attempt failed, fetching instead recursively hist with name = %s\033[0m", __FUNCTION__, __LINE__, histName.Data()); + hist = reinterpret_cast(GetObjectFromList(listWithRuns, histName.Data())); + } + if (!hist) { + histName = tmp; // yes, for some simple tests I can have only histogram named e.g. 'FT0C' + LOGF(info, "\033[1;33m%s at line %d : last attempt, fetching instead hist with trivial name = %s\033[0m", __FUNCTION__, __LINE__, histName.Data()); + hist = reinterpret_cast(GetObjectFromList(listWithRuns, histName.Data())); + } + if (!hist) { + listWithRuns->ls(); + LOGF(fatal, "\033[1;31m%s at line %d : couldn't fetch hist with name = %s\033[0m", __FUNCTION__, __LINE__, histName.Data()); + } + hist->SetDirectory(0); + hist->SetTitle(Form("%s, %s", filePath, runNumber)); // I have to do it here, because only here I have "filePath" av + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + + // h) Clone histogram and delete baseList (realising back the memory): + // Remark: Yes, I have to clone here. + TH1D* histClone = reinterpret_cast(hist->Clone()); + delete baseList; // release back the memory + + return histClone; + +} // TH1D* GetHistogramWithCentralityWeights(const char* filePath, const char* runNumber) + +//============================================================ + +TObjArray* GetDefaultObjArrayWithLabels(const char* whichDefaultLabels) +{ + // To speed up testing, I hardwire here some labels and use them directly as they are. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // Define TObjArray: + TObjArray* arr = new TObjArray(); + arr->SetOwner(); + + // Define some labels, depending on the chosen option for whichDefaultLabels: + if (TString(whichDefaultLabels).EqualTo("trivial")) { + const int nLabels = 1; + TString labels[nLabels] = {"2 -2"}; + for (int l = 0; l < nLabels; l++) { + TObjString* objstr = new TObjString(labels[l].Data()); + arr->Add(objstr); } - hist = reinterpret_cast(GetObjectFromList(listWithRuns, Form("%s[%d]_%s", variable, bin, tc.fTaskName.Data()))); - if (!hist) { - hist = reinterpret_cast(GetObjectFromList(listWithRuns, Form("%s[%d]", variable, bin))); // yes, for some simple tests I can have only histogram named e.g. 'phipt[0]' + } else if (TString(whichDefaultLabels).EqualTo("scan2p")) { + const int nLabels = 6; + TString labels[nLabels] = {"1 -1", "2 -2", "3 -3", "4 -4", "5 -5", "6 -6"}; + for (int l = 0; l < nLabels; l++) { + TObjString* objstr = new TObjString(labels[l].Data()); + arr->Add(objstr); } - if (!hist) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); - listWithRuns->ls(); - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); + } else if (TString(whichDefaultLabels).EqualTo("standard")) { + const int nLabels = 7; + TString labels[nLabels] = {"1 -1", "2 -2", "3 -3", "2 1 -1 -2", "3 1 -1 -3", "3 2 -2 -3", "3 2 1 -1 -2 -3"}; + for (int l = 0; l < nLabels; l++) { + TObjString* objstr = new TObjString(labels[l].Data()); + arr->Add(objstr); } - hist->SetDirectory(0); - - if (TString(variable).EqualTo("phipt")) { - hist->SetTitle(Form("%s, %.2f < p_{T} < %.2f", filePath, res.fResultsProVariableLengthBins[AFO_PT]->At(bin), res.fResultsProVariableLengthBins[AFO_PT]->At(bin + 1))); + } else if (TString(whichDefaultLabels).EqualTo("isotropic")) { + const int nLabels = 8; + TString labels[nLabels] = {"1 -1", "2 -2", "3 -3", "4 -4", "1 1 -1 -1", "2 2 -2 -2", "3 3 -3 -3", "4 4 -4 -4"}; + for (int l = 0; l < nLabels; l++) { + TObjString* objstr = new TObjString(labels[l].Data()); + arr->Add(objstr); + } + } else if (TString(whichDefaultLabels).EqualTo("upto8th")) { + const int nLabels = 7; // yes, because I do not care about 1-p + TString labels[nLabels] = {"1 -1", "1 1 -1", "1 1 -1 -1", "1 1 -1 -1 -1", "1 1 1 -1 -1 -1", "1 1 1 1 -1 -1 -1", "1 1 1 1 -1 -1 -1 -1"}; + for (int l = 0; l < nLabels; l++) { + TObjString* objstr = new TObjString(labels[l].Data()); + arr->Add(objstr); } - if (TString(variable).EqualTo("phieta")) { - hist->SetTitle(Form("%s, %.2f < #eta < %.2f", filePath, res.fResultsProVariableLengthBins[AFO_ETA]->At(bin), res.fResultsProVariableLengthBins[AFO_ETA]->At(bin + 1))); + } else if (TString(whichDefaultLabels).EqualTo("upto10th")) { + const int nLabels = 9; // yes, because I do not care about 1-p + TString labels[nLabels] = {"1 -1", "1 1 -1", "1 1 -1 -1", "1 1 -1 -1 -1", "1 1 1 -1 -1 -1", "1 1 1 1 -1 -1 -1", "1 1 1 1 -1 -1 -1 -1", "1 1 1 1 -1 -1 -1 -1 -1", "1 1 1 1 1 -1 -1 -1 -1 -1"}; + for (int l = 0; l < nLabels; l++) { + TObjString* objstr = new TObjString(labels[l].Data()); + arr->Add(objstr); } + } else if (TString(whichDefaultLabels).EqualTo("upto12th")) { + const int nLabels = 11; // yes, because I do not care about 1-p + TString labels[nLabels] = {"1 -1", "1 1 -1", "1 1 -1 -1", "1 1 -1 -1 -1", "1 1 1 -1 -1 -1", "1 1 1 1 -1 -1 -1", "1 1 1 1 -1 -1 -1 -1", "1 1 1 1 -1 -1 -1 -1 -1", "1 1 1 1 1 -1 -1 -1 -1 -1", "1 1 1 1 1 1 -1 -1 -1 -1 -1", "1 1 1 1 1 1 -1 -1 -1 -1 -1 -1"}; + for (int l = 0; l < nLabels; l++) { + TObjString* objstr = new TObjString(labels[l].Data()); + arr->Add(objstr); + } + } else { + LOGF(fatal, "\033[1;31m%s at line %d : whichDefaultLabels = %s is not supported yet \033[0m", __FUNCTION__, __LINE__, whichDefaultLabels); + } - } // else + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } - return hist; + return arr; -} // TH1D* GetHistogramWithWeights(const char* filePath, const char* runNumber, const char* variable, Int_t bin = -1) +} // TObjArray* GetDefaultObjArrayWithLabels(const char* whichDefaultLabels) //============================================================ TObjArray* GetObjArrayWithLabels(const char* filePath) { // This function extracts from an external file TObjArray named "labels", and - // returns it. External file can be: 1) on a local computer; 2) in home - // directory AliEn => configurable "cfFileWithLabels" must begin with - // "/alice/cern.ch/" 3) in CCDB => configurable "cfFileWithLabels" must begin - // with "/alice-ccdb.cern.ch/" For all CCDB wisdom, see toggle "CCDB" in page - // "O2" + // returns it. External file can be: + // 1) on a local computer; + // 2) in home directory AliEn => configurable "cfFileWithLabels" must begin with "/alice/cern.ch/" + // 3) in CCDB => configurable "cfFileWithLabels" must begin with "/alice-ccdb.cern.ch/" + // For all CCDB wisdom, see toggle "CCDB" in page "O2" // a) Return value; // b) Determine from filePath if the file in on a local machine, or in AliEn; @@ -3625,7 +12210,7 @@ TObjArray* GetObjArrayWithLabels(const char* filePath) // e) Handle the local case. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); } // a) Return value: @@ -3639,37 +12224,34 @@ TObjArray* GetObjArrayWithLabels(const char* filePath) // CCDB. Therefore, files in AliEn and CCDB must be specified // with abs path, for local files both abs and relative paths // are just fine. - Bool_t bFileIsInAliEn = kFALSE; - Bool_t bFileIsInCCDB = kFALSE; + bool bFileIsInAliEn = false; + bool bFileIsInCCDB = false; if (TString(filePath).BeginsWith("/alice/cern.ch/")) { - bFileIsInAliEn = kTRUE; + bFileIsInAliEn = true; } else { if (TString(filePath).BeginsWith("/alice-ccdb.cern.ch/")) { - bFileIsInCCDB = kTRUE; + bFileIsInCCDB = true; } // else { - } // if (TString(filePath).BeginsWith("/alice/cern.ch/")) { + } // if (TString(filePath).BeginsWith("/alice/cern.ch/")) { TFile* oaFile = NULL; // file holding TObjArray with all labels if (bFileIsInAliEn) { // c) Handle the AliEn case: TGrid* alien = TGrid::Connect("alien", gSystem->Getenv("USER"), "", ""); if (!alien) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } oaFile = TFile::Open(Form("alien://%s", filePath), "READ"); if (!oaFile) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } // Fetch TObjArray from external file (keep in sync with local file case below): TList* lok = oaFile->GetListOfKeys(); if (!lok) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - for (Int_t l = 0; l < lok->GetEntries(); l++) { + for (int l = 0; l < lok->GetEntries(); l++) { oaFile->GetObject(lok->At(l)->GetName(), oa); if (oa && TString(oa->ClassName()).EqualTo("TObjArray")) { break; // TBI 20231107 the working assumption is that in an external file there is only one TObjArray object, @@ -3678,11 +12260,10 @@ TObjArray* GetObjArrayWithLabels(const char* filePath) // TObjArray in an external file, this shall be alright. With the current implementation, // if there are multiple TObjArray objects in the same ROOT file, the first one will be fetched. } - } // for(Int_t l=0;lGetEntries();l++) + } // for(int l=0;lGetEntries();l++) if (!oa) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } } else if (bFileIsInCCDB) { @@ -3699,62 +12280,204 @@ TObjArray* GetObjArrayWithLabels(const char* filePath) // https://indico.cern.ch/event/1267433/timetable/#20230417.detailed ccdb->setURL("http://alice-ccdb.cern.ch"); - oa = reinterpret_cast(ccdb->get( - TString(filePath) - .ReplaceAll("/alice-ccdb.cern.ch/", "") - .Data())); + oa = reinterpret_cast(ccdb->get( + TString(filePath) + .ReplaceAll("/alice-ccdb.cern.ch/", "") + .Data())); + + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } else { + + // e) Handle the local case: + // Check if the external ROOT file exists at specified path: + if (gSystem->AccessPathName(filePath, kFileExists)) { + LOGF(info, "\033[1;33m if(gSystem->AccessPathName(filePath,kFileExists)), filePath = %s \033[0m", filePath); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + oaFile = TFile::Open(filePath, "READ"); + if (!oaFile) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + // Fetch TObjArray from external file (keep in sync with AliEn file case above): + TList* lok = oaFile->GetListOfKeys(); + if (!lok) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + for (int l = 0; l < lok->GetEntries(); l++) { + oaFile->GetObject(lok->At(l)->GetName(), oa); + if (oa && TString(oa->ClassName()).EqualTo("TObjArray")) { + break; // TBI 20231107 the working assumption is that in an external file there is only one TObjArray object, + // and here I fetch it, whatever its name is. The advantage is that I do not have to do + // any additional work for TObjArray's name. Since I do not anticipate ever having more than 1 + // TObjArray in an external file, this shall be alright. With the current implementation, + // if there are multiple TObjArray objects in the same ROOT file, the first one will be fetched. + } + } // for(int l=0;lGetEntries();l++) + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + } // else { + + if (tc.fVerbose) { + LOGF(info, "\033[1;32m%s => Fetched TObjArray named \"%s\" from file %s\033[0m", __FUNCTION__, oa->GetName(), filePath); + ExitFunction(__FUNCTION__); + } + + return oa; + +} // TObjArray* GetObjArrayWithLabels(const char *filePath) + +//============================================================ + +void GetHistogramWithCustomNUA(const char* filePath, eNUAPDF variable) +{ + // Get and set immediately histogram with custom NUA for specified variable, from an external file. + // This structure of an external file is mandatory at the moment: + // *) There is a TList named "ccdb_object", which holds all histograms for custom NUA; + // *) These histograms are TH1D objects. + // This is a port of void FlowWithMultiparticleCorrelationsTask::SetNUAPDF(TH1D* const hist, const char* variable) + + // Remark: Unlike for weights and labels, here I am trying to do everythign in the same function, that's why here return type is void, instead of TH1D*. + + // TBI 20240501 there is a bit of code repetition below, add with analogous functions GetHistogramWithWeights(...) and GetObjArrayWithLabels(...) + + // a) Local objects; + // b) Basic protection for arguments; + // c) Determine from filePath if the file in on a local machine, or in AliEn, or in CCDB; + // d) Handle the AliEn case; + // e) Handle the CCDB case; + // f) Handle the local case; + // g) The final touch; + // h) Clone histogram and delete baseList (realising back the memory). + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + LOGF(info, "\033[1;32m filePath = %s\033[0m", filePath); + LOGF(info, "\033[1;32m variable = %d\033[0m", static_cast(variable)); + LOGF(info, "\033[1;32m nua.fCustomNUAPDFHistNames[variable]->Data() = %s\033[0m", nua.fCustomNUAPDFHistNames[variable]->Data()); + LOGF(info, "\033[1;32m fTaskName = %s\033[0m", tc.fTaskName.Data()); + } + + // *) Basic protection: + if (nua.fCustomNUAPDFHistNames[variable] && nua.fCustomNUAPDFHistNames[variable]->EqualTo("")) { + LOGF(info, "\033[1;32m empty TString, variable = %d\033[0m", static_cast(variable)); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + // a) Local objects: + TH1D* hist = NULL; + TList* baseList = NULL; // base top-level list in the TFile, always named "ccdb_object" + + // b) Basic protection for arguments: + // ... + + // c) Determine from filePath if the file in on a local machine, or in home dir AliEn, or in CCDB: + // Algorithm: + // *) If filePath begins with "/alice/cern.ch/" then it's in home dir AliEn. + // *) If filePath begins with "/alice-ccdb.cern.ch/" then it's in CCDB. + // *) It's a local file otherwise. + // Therefore, files in AliEn and CCDB must be specified with abs path, for local files both abs and relative paths are just fine. + bool bFileIsInAliEn = false; + bool bFileIsInCCDB = false; + if (TString(filePath).BeginsWith("/alice/cern.ch/")) { + bFileIsInAliEn = true; + } else { + if (TString(filePath).BeginsWith("/alice-ccdb.cern.ch/")) { + bFileIsInCCDB = true; + } // else { + } // if (TString(filePath).BeginsWith("/alice/cern.ch/")) { + + if (bFileIsInAliEn) { + // d) Handle the AliEn case: + TGrid* alien = TGrid::Connect("alien", gSystem->Getenv("USER"), "", ""); + if (!alien) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + TFile* customNUAFile = TFile::Open(Form("alien://%s", filePath), "READ"); + if (!customNUAFile) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + customNUAFile->GetObject("ccdb_object", baseList); + if (!baseList) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + } else if (bFileIsInCCDB) { + + // e) Handle the CCDB case: Remember that here I do not access the file, instead directly object in that file. + // My home dir in CCDB: https://alice-ccdb.cern.ch/browse/Users/a/abilandz/ + // Inspired by: + // 1. Discussion at: + // https://alice-talk.web.cern.ch/t/access-to-lhc-filling-scheme/1073/17 + // 2. See also: + // https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/efficiencyGlobal.cxx + // https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/efficiencyPerRun.cxx + // 3. O2 Analysis Tutorial 2.0: + // https://indico.cern.ch/event/1267433/timetable/#20230417.detailed + + ccdb->setURL("http://alice-ccdb.cern.ch"); + if (tc.fVerbose) { + LOGF(info, "\033[1;32mAccessing in CCDB %s\033[0m", TString(filePath).ReplaceAll("/alice-ccdb.cern.ch/", "").Data()); + } - if (!oa) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + baseList = reinterpret_cast(ccdb->get(TString(filePath).ReplaceAll("/alice-ccdb.cern.ch/", "").Data())); + + if (!baseList) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } + } else { - // e) Handle the local case: + // f) Handle the local case: + // Check if the external ROOT file exists at specified path: if (gSystem->AccessPathName(filePath, kFileExists)) { - LOGF(info, - "\033[1;33m if(gSystem->AccessPathName(filePath,kFileExists)), " - "filePath = %s \033[0m", - filePath); - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); - } - oaFile = TFile::Open(filePath, "READ"); - if (!oaFile) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + LOGF(info, "\033[1;33m if(gSystem->AccessPathName(filePath,kFileExists)), filePath = %s \033[0m", filePath); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - // Fetch TObjArray from external file (keep in sync with AliEn file case above): - TList* lok = oaFile->GetListOfKeys(); - if (!lok) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + TFile* customNUAFile = TFile::Open(filePath, "READ"); + if (!customNUAFile) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - for (Int_t l = 0; l < lok->GetEntries(); l++) { - oaFile->GetObject(lok->At(l)->GetName(), oa); - if (oa && TString(oa->ClassName()).EqualTo("TObjArray")) { - break; // TBI 20231107 the working assumption is that in an external file there is only one TObjArray object, - // and here I fetch it, whatever its name is. The advantage is that I do not have to do - // any additional work for TObjArray's name. Since I do not anticipate ever having more than 1 - // TObjArray in an external file, this shall be alright. With the current implementation, - // if there are multiple TObjArray objects in the same ROOT file, the first one will be fetched. - } - } // for(Int_t l=0;lGetEntries();l++) - if (!oa) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); + customNUAFile->GetObject("ccdb_object", baseList); + if (!baseList) { + // customNUAFile->ls(); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } + // hist = reinterpret_cast(GetObjectFromList(baseList, nua.fCustomNUAPDFHistNames[variable]->Data())); + } // else { - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s => Fetched TObjArray named \"%s\" from file %s\033[0m", __PRETTY_FUNCTION__, oa->GetName(), filePath); + // g) The final touch: + hist = reinterpret_cast(GetObjectFromList(baseList, nua.fCustomNUAPDFHistNames[variable]->Data())); + if (!hist) { + LOGF(info, "\033[1;31m hist is NULL \033[0m"); + LOGF(info, "\033[1;31m variable = %d\033[0m", static_cast(variable)); + LOGF(info, "\033[1;31m nua.fCustomNUAPDFHistNames[variable]->Data() = %s\033[0m", nua.fCustomNUAPDFHistNames[variable]->Data()); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - return oa; + // h) Clone histogram and delete baseList (realising back the memory). + // TBI 20250315 here I did it a bit differently than e.g. in GetHistogramWithWeights or in GetSparseHistogramWithWeights . + // If it's failing here, redo it in exactly the same way as I did it there. + hist->SetDirectory(0); + nua.fCustomNUAPDF[variable] = reinterpret_cast(hist->Clone()); + nua.fCustomNUAPDF[variable]->SetTitle(Form("%s", filePath)); + delete baseList; -} // TObjArray* GetObjArrayWithLabels(const char *filePath) + // TBI 20240501 if additional cosmetics is needed, it can be implemented here + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void GetHistogramWithCustomNUA(const char* filePath, eNUAPDF variable) //============================================================ @@ -3766,43 +12489,46 @@ void StoreLabelsInPlaceholder() // b) Fetch TObjArray with labels from an external file; // c) Book the placeholder fTest0LabelsPlaceholder for all labels; // d) Finally, store the labels from external source into placeholder; - // e) Insantity check on labels. + // e) Insanity check on labels. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); } // a) Initialize all counters; - Int_t counter[gMaxCorrelator] = {0}; // is this safe? - for (Int_t o = 0; o < gMaxCorrelator; o++) { + int counter[gMaxCorrelator] = {0}; // is this safe? + for (int o = 0; o < gMaxCorrelator; o++) { counter[o] = 0; } // now it's safe :-) // b) Fetch TObjArray with labels from an external file: - TObjArray* oa = GetObjArrayWithLabels(t0.fFileWithLabels.Data()); + TObjArray* oa = NULL; + if (t0.fUseDefaultLabels) { + oa = GetDefaultObjArrayWithLabels(t0.fWhichDefaultLabels.Data()); + } else { + oa = GetObjArrayWithLabels(t0.fFileWithLabels.Data()); + } if (!oa) { LOGF(info, "\033[1;33m fFileWithLabels = %s \033[0m", t0.fFileWithLabels.Data()); - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } // c) Book the placeholder fTest0LabelsPlaceholder for all labels: - Int_t nLabels = oa->GetEntries(); + int nLabels = oa->GetEntries(); t0.fTest0LabelsPlaceholder = new TH1I("fTest0LabelsPlaceholder", Form("placeholder for all labels, %d in total", nLabels), nLabels, 0, nLabels); - t0.fTest0LabelsPlaceholder->SetStats(kFALSE); + t0.fTest0LabelsPlaceholder->SetStats(false); // d) Finally, store the labels from external source into placeholder: - Int_t bin = 1; // used only for fTest0LabelsPlaceholder - Int_t order = -44; - for (Int_t e = 0; e < nLabels; e++) { + int bin = 1; // used only for fTest0LabelsPlaceholder + int order = -44; + for (int e = 0; e < nLabels; e++) { TObjArray* temp = TString(oa->At(e)->GetName()).Tokenize(" "); if (!temp) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } order = temp->GetEntries(); delete temp; // yes, otherwise it's a memory leak @@ -3819,48 +12545,51 @@ void StoreLabelsInPlaceholder() counter[order - 1]++; // cout<GetEntries()<GetXaxis()->GetNbins(); b++) { + for (int b = 1; b <= t0.fTest0LabelsPlaceholder->GetXaxis()->GetNbins(); b++) { TObjArray* temp = TString(t0.fTest0LabelsPlaceholder->GetXaxis()->GetBinLabel(b)).Tokenize(" "); - for (Int_t h = 0; h < temp->GetEntries(); h++) { + for (int h = 0; h < temp->GetEntries(); h++) { if (TMath::Abs(TString(temp->At(h)->GetName()).Atoi()) > gMaxHarmonic) { - LOGF(info, "\033[1;31m bin = %d, label = %s, gMaxHarmonic = %d\033[0m", b, t0.fTest0LabelsPlaceholder->GetXaxis()->GetBinLabel(b), (Int_t)gMaxHarmonic); - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); - } // if(TString(temp->At(h)->GetName()).Atoi() > gMaxHarmonic) { - } // for(Int_t h = 0; h < temp->GetEntries(); h++) { + LOGF(info, "\033[1;31m bin = %d, label = %s, gMaxHarmonic = %d\033[0m", b, t0.fTest0LabelsPlaceholder->GetXaxis()->GetBinLabel(b), static_cast(gMaxHarmonic)); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } // if(TString(temp->At(h)->GetName()).Atoi() > gMaxHarmonic) { + } // for(int h = 0; h < temp->GetEntries(); h++) { delete temp; // yes, otherwise it's a memory leak - } // for(Int_t b = 1; b <= t0.fTest0LabelsPlaceholder->GetXaxis()->GetNbins(); b++) { + } // for(int b = 1; b <= t0.fTest0LabelsPlaceholder->GetXaxis()->GetNbins(); b++) { + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } } // void StoreLabelsInPlaceholder() //============================================================ -Bool_t RetrieveCorrelationsLabels() +bool RetrieveCorrelationsLabels() { // Generate the labels of all correlations of interest, i.e. retrieve them // from TH1I *t0.fTest0LabelsPlaceholder if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); } - Int_t counter[gMaxCorrelator] = {0}; // is this safe? - for (Int_t o = 0; o < gMaxCorrelator; o++) { + int counter[gMaxCorrelator] = {0}; // is this safe? + for (int o = 0; o < gMaxCorrelator; o++) { counter[o] = 0; } // now it's safe :-) - Int_t nBins = t0.fTest0LabelsPlaceholder->GetXaxis()->GetNbins(); + int nBins = t0.fTest0LabelsPlaceholder->GetXaxis()->GetNbins(); - Int_t order = -44; - for (Int_t b = 1; b <= nBins; b++) { + int order = -44; + for (int b = 1; b <= nBins; b++) { TObjArray* oa = TString(t0.fTest0LabelsPlaceholder->GetXaxis()->GetBinLabel(b)) .Tokenize(" "); if (!oa) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } order = oa->GetEntries(); delete oa; // yes, otherwise it's a memory leak @@ -3868,21 +12597,21 @@ Bool_t RetrieveCorrelationsLabels() continue; } // empty lines, or the label format which is not supported // 1-p => 0, 2-p => 1, etc.: - t0.fTest0Labels[order - 1][counter[order - 1]] = new TString( - t0.fTest0LabelsPlaceholder->GetXaxis()->GetBinLabel(b)); // okay... - // cout<<__LINE__<<": - // "<Data()<GetXaxis()->GetBinLabel(b)); // okay... counter[order - 1]++; - } // for(Int_t b=1;b<=nBins;b++) + } // for(int b=1;b<=nBins;b++) + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } - return kTRUE; + return true; -} // Bool_t RetrieveCorrelationsLabels() +} // bool RetrieveCorrelationsLabels() //============================================================ -TObject* GetObjectFromList(TList* list, - const Char_t* objectName) // Last update: 20210918 +TObject* GetObjectFromList(TList* list, const char* objectName) // Last update: 20210918 { // Get TObject pointer from TList, even if it's in some nested TList. Foreseen // to be used to fetch histograms or profiles from files directly. Some ideas @@ -3902,14 +12631,16 @@ TObject* GetObjectFromList(TList* list, // a) Check if I can make it working in compiled mode. // b) If I have objects with same name, nested in different TLists, what then? + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + // Insanity checks: if (!list) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } if (!objectName) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } if (0 == list->GetEntries()) { return NULL; @@ -3934,118 +12665,220 @@ TObject* GetObjectFromList(TList* list, } } // while(objectIter = next()) + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + return NULL; -} // TObject* GetObjectFromList(TList *list, Char_t *objectName) +} // TObject* GetObjectFromList(TList *list, char *objectName) //============================================================ -Double_t Weight(const Double_t& value, - const char* variable) // value, [phi,pt,eta] +double Weight(const double& value, eWeights whichWeight) // value, integrated [phi,pt,eta] weight { // Determine particle weight. - // Basic protection: - if (!(TString(variable).EqualTo("phi") || TString(variable).EqualTo("pt") || - TString(variable).EqualTo("eta"))) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); - } - - Int_t ppe = 0; // [phi,pt,eta] - if (TString(variable).EqualTo("pt")) { - ppe = 1; - } - if (TString(variable).EqualTo("eta")) { - ppe = 2; + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + LOGF(info, "\033[1;32m value = %f\033[0m", value); + LOGF(info, "\033[1;32m variable = %d\033[0m", static_cast(whichWeight)); } - if (!pw.fWeightsHist[ppe]) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", - __PRETTY_FUNCTION__, __LINE__); + if (!pw.fWeightsHist[whichWeight]) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - Int_t bin = pw.fWeightsHist[ppe]->FindBin(value); - Double_t weight = 0.; - if (bin > pw.fWeightsHist[ppe]->GetNbinsX()) { + int bin = pw.fWeightsHist[whichWeight]->FindBin(value); + double weight = 0.; + if (bin > pw.fWeightsHist[whichWeight]->GetNbinsX()) { weight = 0.; // we are in the overflow, ignore this particle TBI_20210524 is // this really the correct procedure? } else { - weight = pw.fWeightsHist[ppe]->GetBinContent(bin); + weight = pw.fWeightsHist[whichWeight]->GetBinContent(bin); + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + + return weight; + +} // Weight(const double &value, eWeights whichWeight) // value, integrated [phi,pt,eta] weight + +//============================================================ + +double WeightFromSparse(const double& dPhi, const double& dPt, const double& dEta, const double& dCharge, eDiffWeightCategory dwc) +{ + // Determine differential multidimensional particle weight using sparse histograms. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // *) Reduce dimensionality is possible, i.e. look up only the dimensions in THnSparse which were requested in this analysis: + Int_t dim = 1; // yes, because dimension 0 is always reserved for each category + switch (dwc) { + case eDWPhi: { + // Remember that ordering here has to resemble ordering in eDiffPhiWeights + pw.fFindBinVector[dwc]->AddAt(dPhi, 0); // special treatment for phi in eDWPhi category + if (pw.fUseDiffPhiWeights[wPhiPtAxis]) { + pw.fFindBinVector[dwc]->AddAt(dPt, dim++); + } + if (pw.fUseDiffPhiWeights[wPhiEtaAxis]) { + pw.fFindBinVector[dwc]->AddAt(dEta, dim++); + } + if (pw.fUseDiffPhiWeights[wPhiChargeAxis]) { + pw.fFindBinVector[dwc]->AddAt(dCharge, dim++); + } + if (pw.fUseDiffPhiWeights[wPhiCentralityAxis]) { + pw.fFindBinVector[dwc]->AddAt(ebye.fCentrality, dim++); + } + if (pw.fUseDiffPhiWeights[wPhiVertexZAxis]) { + pw.fFindBinVector[dwc]->AddAt(ebye.fVz, dim++); + } + // ... + break; + } + case eDWPt: { + pw.fFindBinVector[dwc]->AddAt(dPt, 0); // special treatment for pt in eDWPt category + // Remember that ordering here has to resemble ordering in eDiffPtWeights + // if(pw.fUseDiffPtWeights[...]) { + // pw.fFindBinVector[dwc]->AddAt(..., dim++); // skeleton for next dimension + // } + // ... + break; + } + case eDWEta: { + pw.fFindBinVector[dwc]->AddAt(dEta, 0); // special treatment for eta in eDWEta category + // Remember that ordering here has to resemble ordering in eDiffEtaWeights + // if(pw.fUseDiffEtaWeights[...]) { + // pw.fFindBinVector[dwc]->AddAt(..., dim++); // skeleton for next dimension + // } + // ... + break; + } + default: { + LOGF(fatal, "\033[1;31m%s at line %d : This differential weight category, dwc = %d, is not supported yet. \033[0m", __FUNCTION__, __LINE__, static_cast(dwc)); + break; + } + } // switch(dwc) + + // *) Insanity check: + // **) ... + if (!pw.fDiffWeightsSparse[dwc]) { + LOGF(fatal, "\033[1;31m dwc = %d\033[0m", static_cast(dwc)); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + // **) Check that dimensions of vector I will use to fetch the right bin content and sparse histogram with weights do match: + if (tc.fInsanityCheckForEachParticle) { + if (pw.fFindBinVector[dwc]->GetSize() != pw.fDiffWeightsSparse[dwc]->GetNdimensions()) { + LOGF(fatal, "\033[1;31m dwc = %d\033[0m", static_cast(dwc)); + LOGF(fatal, "\033[1;31m pw.fFindBinVector[dwc]->GetSize() = %d\033[0m", pw.fFindBinVector[dwc]->GetSize()); + LOGF(fatal, "\033[1;31m pw.fDiffWeightsSparse[dwc]->GetNdimensions() = %d\033[0m", pw.fDiffWeightsSparse[dwc]->GetNdimensions()); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } // if(tc.fInsanityCheckForEachParticle) + + // *) okay, let's fetch the weight: + int bin = pw.fDiffWeightsSparse[dwc]->GetBin(pw.fFindBinVector[dwc]->GetArray()); // this is the general bin, corresponding to the actual multidimensional bin + // TBI 20250224 do I need some insanity check here, e.g. that bin is neither in overflow nor in underflow? + double weight = pw.fDiffWeightsSparse[dwc]->GetBinContent(bin); + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); } return weight; -} // Weight(const Double_t &value, const char *variable) // value, [phi,pt,eta] +} // double WeightFromSparse(...) //============================================================ -Double_t DiffWeight(const Double_t& valueY, const Double_t& valueX, const char* variableX) +double DiffWeight(const double& valueY, const double& valueX, eqvectorKine variableX) { // Determine differential particle weight y(x). For the time being, "y = phi" always, but this can be generalized. + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + // *) Determine first to which bin the 'valueX' corresponds to. // Based on that, I decide from which histogram I fetch weight for y. See MakeWeights.C - // TBI 20240208 I need to add support below also for fixed binning case, using fResultsProFixedLengthBins, not only for fResultsProVariableLengthBins - // TBI 20231026 I do it at the moment this way just to move on, but this can be optimized clearly. - - // *) Mapping between enum's "variableX" on one side, and enum "eAsFunctionOf" on the other: - Int_t AFO_var = -1; // this local variable determines the enum "eAsFunctionOf" which corresponds to enum "eqvectorKine" - Int_t AFO_weight = -1; // this local variable determines the enum "eDiffWeights" which corresponds to enum "eqvectorKine" - if (TString(variableX).EqualTo("pt")) { // TBI 20240215 check if I can optimize here, i.e. by using strcmp + // *) Mapping between enums "eqvectorKine" on one side, and enums "eAsFunctionOf" and "eDiffWeights" on the other: + eAsFunctionOf AFO_var = eAsFunctionOf_N; // this local variable determines the enum "eAsFunctionOf" which corresponds to enum "eqvectorKine" + eDiffWeights AFO_diffWeight = eDiffWeights_N; // this local variable determines the enum "eDiffWeights" which corresponds to enum "eqvectorKine" + if (variableX == PTq) { AFO_var = AFO_PT; - AFO_weight = wPHIPT; - } else if (TString(variableX).EqualTo("eta")) { + AFO_diffWeight = wPHIPT; + } else if (variableX == ETAq) { AFO_var = AFO_ETA; - AFO_weight = wPHIETA; + AFO_diffWeight = wPHIETA; } - // *) Okay, let's do it: - Int_t binX = 1; - // if(fInsanityChecksForEachParticle) { - if (true) { // TBI 20240208 add support to switch on and off this check, which is computationally heavy + // *) Insanity checks on above settings: + if (AFO_var == eAsFunctionOf_N) { + LOGF(fatal, "\033[1;31m%s at line %d : AFO_var == eAsFunctionOf_N => add some more entries to the case statement \033[0m", __FUNCTION__, __LINE__); + } + if (AFO_diffWeight == eDiffWeights_N) { + LOGF(fatal, "\033[1;31m%s at line %d : AFO_diffWeight == eDiffWeights_N => add some more entries to the case statement \033[0m", __FUNCTION__, __LINE__); + } - if (valueX < res.fResultsProVariableLengthBins[AFO_var]->At(0)) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); + // *) Determine first to which bin the 'valueX' corresponds to. + // Based on that, I decide from which histogram I fetch weight for y. See MakeWeights.C + int binX = res.fResultsPro[AFO_var]->FindBin(valueX); + if (tc.fInsanityCheckForEachParticle) // enable only during debugging, as this check is computationally heavy. + { + if (binX < 1) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); // underflow. this means that I didn't use the same cuts now, and I was using when making the particle weights. Adjust the cuts. } - if (valueX >= res.fResultsProVariableLengthBins[AFO_var]->At(res.fResultsProVariableLengthBins[AFO_var]->GetSize() - 1)) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); + if (binX > res.fResultsPro[AFO_var]->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); // overflow. this means that I didn't use the same cuts now, and I was using when making the particle weights. Adjust the cuts. } - } // fInsanityChecksForEachParticle - - // *) TBI add some comment... - for (Int_t e = 1; e < res.fResultsProVariableLengthBins[AFO_var]->GetSize(); e++) { - // Since I set binX = 1, intentionally I skip the first element in the loop, and start from e = 1, instead of e = 0. - if (valueX < res.fResultsProVariableLengthBins[AFO_var]->At(e)) { - binX = e; - break; - } // gotcha - } + } // if(tc.fInsanityCheckForEachParticle) // *) Finally, determine weight for y(x): - if (!pw.fDiffWeightsHist[AFO_weight][binX - 1]) { + if (!pw.fDiffWeightsHist[AFO_diffWeight][binX - 1]) { LOGF(info, "\033[1;32mvalueY = %f\033[0m", valueY); LOGF(info, "\033[1;32mvalueX = %f\033[0m", valueX); - LOGF(info, "\033[1;32mvariableX = %s\033[0m", variableX); - LOGF(info, "\033[1;32mAFO_weight = %d\033[0m", AFO_weight); + LOGF(info, "\033[1;32mvariableX = %d\033[0m", static_cast(variableX)); + LOGF(info, "\033[1;32mAFO_diffWeight = %d\033[0m", static_cast(AFO_diffWeight)); LOGF(info, "\033[1;32mbinX = %d\033[0m", binX); - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - Int_t bin = pw.fDiffWeightsHist[AFO_weight][binX - 1]->FindBin(valueY); // binX - 1, because I histogram for first bin in X is labeled with "[0]", etc. - Double_t weight = 0.; - if (bin > pw.fDiffWeightsHist[AFO_weight][binX - 1]->GetNbinsX()) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); // TBI 20240208 re-think what to do here - } else { - weight = pw.fDiffWeightsHist[AFO_weight][binX - 1]->GetBinContent(bin); + int bin = pw.fDiffWeightsHist[AFO_diffWeight][binX - 1]->FindBin(valueY); // binX - 1, because I histogram for first bin in X is labeled with "[0]", etc. + if (tc.fInsanityCheckForEachParticle) // enable only during debugging, as this check is computationally heavy. + { + if (bin < 1) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + // underflow. this means that I didn't use the same cuts now, and I was using when making the particle weights. Adjust the cuts. + } + if (bin > pw.fDiffWeightsHist[AFO_diffWeight][binX - 1]->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + // overflow. this means that I didn't use the same cuts now, and I was using when making the particle weights. Adjust the cuts. + } + } // if(tc.fInsanityCheckForEachParticle) + + double diffWeight = pw.fDiffWeightsHist[AFO_diffWeight][binX - 1]->GetBinContent(bin); + if (tc.fInsanityCheckForEachParticle) // enable only during debugging, as this check is computationally heavy. + { + if (diffWeight < 0.) { // or <= 0 ? TBI 20240324 rethink + LOGF(fatal, "\033[1;31m%s at line %d : diffWeight < 0\033[0m", __FUNCTION__, __LINE__); + } } - return weight; + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + + return diffWeight; -} // DiffWeight(const Double_t &valueY, const Double_t &valueX, const char* variableX) +} // DiffWeight(const double &valueY, const double &valueX, eqvectorKine variableX) //============================================================ @@ -4059,10 +12892,13 @@ void GetParticleWeights() // If any of these 2 assumptions are violated, this code will have to be modified. // a) Integrated weights; - // b) Differential weights. + // b) Differential weights; => TBI 20250225 this is now obsolete and superseeded with c), where I use more general approach with sparse histograms + // c) Differential phi weights using sparse histograms; + // d) Differential pt weights using sparse histograms; + // e) Differential eta weights using sparse histograms. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); } // a) Integrated weights: @@ -4070,94 +12906,461 @@ void GetParticleWeights() if (pw.fUseWeights[wPHI]) { TH1D* phiWeights = GetHistogramWithWeights(pw.fFileWithWeights.Data(), tc.fRunNumber.Data(), "phi"); if (!phiWeights) { - LOGF(fatal, "in function \033[1;31m%s at line %d, phiWeights is NULL. Check the external file %s with particle weights\033[0m", __PRETTY_FUNCTION__, __LINE__, pw.fFileWithWeights.Data()); + LOGF(fatal, "in function \033[1;31m%s at line %d, phiWeights is NULL. Check the external file %s with particle weights\033[0m", __FUNCTION__, __LINE__, pw.fFileWithWeights.Data()); } - SetWeightsHist(phiWeights, "phi"); + SetWeightsHist(phiWeights, wPHI); } // integrated pt weights: if (pw.fUseWeights[wPT]) { TH1D* ptWeights = GetHistogramWithWeights(pw.fFileWithWeights.Data(), tc.fRunNumber.Data(), "pt"); if (!ptWeights) { - LOGF(fatal, "in function \033[1;31m%s at line %d, ptWeights is NULL. Check the external file %s with particle weights\033[0m", __PRETTY_FUNCTION__, __LINE__, pw.fFileWithWeights.Data()); + LOGF(fatal, "\033[1;31m%s at line %d : ptWeights is NULL. Check the external file %s with particle weights\033[0m", __FUNCTION__, __LINE__, pw.fFileWithWeights.Data()); } - SetWeightsHist(ptWeights, "pt"); + SetWeightsHist(ptWeights, wPT); } // integrated eta weights: if (pw.fUseWeights[wETA]) { TH1D* etaWeights = GetHistogramWithWeights(pw.fFileWithWeights.Data(), tc.fRunNumber.Data(), "eta"); if (!etaWeights) { - LOGF(fatal, "in function \033[1;31m%s at line %d, etaWeights is NULL. Check the external file %s with particle weights\033[0m", __PRETTY_FUNCTION__, __LINE__, pw.fFileWithWeights.Data()); + LOGF(fatal, "\033[1;31m%s at line %d : etaWeights is NULL. Check the external file %s with particle weights\033[0m", __FUNCTION__, __LINE__, pw.fFileWithWeights.Data()); } - SetWeightsHist(etaWeights, "eta"); + SetWeightsHist(etaWeights, wETA); } // b) Differential weights: // differential phi(pt) weights: if (pw.fUseDiffWeights[wPHIPT]) { TH1D* phiptWeights = NULL; - Int_t nPtBins = res.fResultsPro[AFO_PT]->GetXaxis()->GetNbins(); - for (Int_t b = 0; b < nPtBins; b++) { + int nPtBins = res.fResultsPro[AFO_PT]->GetXaxis()->GetNbins(); + for (int b = 0; b < nPtBins; b++) { + + // *) check if particles in this pt bin survive particle cuts in pt. If not, skip this bin, because for that pt bin weights are simply not available: + if (!(res.fResultsPro[AFO_PT]->GetBinLowEdge(b + 2) > pc.fdParticleCuts[ePt][eMin])) { + // this branch protects against the case when I am e.g. in pt bin [0.0,0.2], and pt cut is 0.2 < pt < 5.0 + LOGF(info, "\033[1;33m%s at line %d : you are requesting phi(pt) weight for pt bin = %d from (%f,%f), which is outside (below) pt phase space = (%f,%f). Skipping this bin. \033[0m", __FUNCTION__, __LINE__, b, res.fResultsPro[AFO_PT]->GetBinLowEdge(b + 1), res.fResultsPro[AFO_PT]->GetBinLowEdge(b + 2), pc.fdParticleCuts[ePt][eMin], pc.fdParticleCuts[ePt][eMax]); + continue; + } + if (!(res.fResultsPro[AFO_PT]->GetBinLowEdge(b + 1) < pc.fdParticleCuts[ePt][eMax])) { + // this branch protects against the case when I am e.g. in pt bin [5.0,10.0], and pt cut is 0.2 < pt < 5.0 + LOGF(info, "\033[1;33m%s at line %d : you are requesting phi(pt) weight for pt bin = %d from (%f,%f), which is outside (above) pt phase space = (%f,%f). Skipping this bin. \033[0m", __FUNCTION__, __LINE__, b, res.fResultsPro[AFO_PT]->GetBinLowEdge(b + 1), res.fResultsPro[AFO_PT]->GetBinLowEdge(b + 2), pc.fdParticleCuts[ePt][eMin], pc.fdParticleCuts[ePt][eMax]); + continue; + } + + // *) okay, this pt bin is within pt phase-space window, defined by pt cut: phiptWeights = GetHistogramWithWeights(pw.fFileWithWeights.Data(), tc.fRunNumber.Data(), "phipt", b); if (!phiptWeights) { - LOGF(fatal, "in function \033[1;31m%s at line %d, phiptWeights is NULL. Check the external file %s with particle weights\033[0m", __PRETTY_FUNCTION__, __LINE__, pw.fFileWithWeights.Data()); + LOGF(fatal, "\033[1;31m%s at line %d : phiptWeights is NULL. Check the external file %s with particle weights\033[0m", __FUNCTION__, __LINE__, pw.fFileWithWeights.Data()); } - SetDiffWeightsHist(phiptWeights, "phipt", b); + + // *) okay, just use this histogram with weights: + SetDiffWeightsHist(phiptWeights, wPHIPT, b); } } // if (pw.fUseDiffWeights[wPHIPT]) { // differential phi(eta) weights: if (pw.fUseDiffWeights[wPHIETA]) { TH1D* phietaWeights = NULL; - Int_t nEtaBins = res.fResultsPro[AFO_ETA]->GetXaxis()->GetNbins(); - for (Int_t b = 0; b < nEtaBins; b++) { - GetHistogramWithWeights(pw.fFileWithWeights.Data(), tc.fRunNumber.Data(), "phieta", b); + int nEtaBins = res.fResultsPro[AFO_ETA]->GetXaxis()->GetNbins(); + for (int b = 0; b < nEtaBins; b++) { + + // *) check if particles in this eta bin survive particle cuts in eta. If not, skip this bin, because for that eta bin weights are simply not available: + if (!(res.fResultsPro[AFO_ETA]->GetBinLowEdge(b + 2) > pc.fdParticleCuts[eEta][eMin])) { + // this branch protects against the case when I am e.g. in eta bin [-1.0,-0.8], and eta cut is -0.8 < eta < 0.8 + LOGF(info, "\033[1;33m%s at line %d : you are requesting phi(eta) weight for eta bin = %d from (%f,%f), which is outside (below) eta phase space = (%f,%f). Skipping this bin. \033[0m", __FUNCTION__, __LINE__, b, res.fResultsPro[AFO_ETA]->GetBinLowEdge(b + 1), res.fResultsPro[AFO_ETA]->GetBinLowEdge(b + 2), pc.fdParticleCuts[eEta][eMin], pc.fdParticleCuts[eEta][eMax]); + continue; + } + if (!(res.fResultsPro[AFO_ETA]->GetBinLowEdge(b + 1) < pc.fdParticleCuts[eEta][eMax])) { + // this branch protects against the case when I am e.g. in eta bin [0.8,1.0], and eta cut is 0.8 < eta < 1.0 + LOGF(info, "\033[1;33m%s at line %d : you are requesting phi(eta) weight for eta bin = %d from (%f,%f), which is outside (above) eta phase space = (%f,%f). Skipping this bin. \033[0m", __FUNCTION__, __LINE__, b, res.fResultsPro[AFO_ETA]->GetBinLowEdge(b + 1), res.fResultsPro[AFO_ETA]->GetBinLowEdge(b + 2), pc.fdParticleCuts[eEta][eMin], pc.fdParticleCuts[eEta][eMax]); + continue; + } + + // *) okay, this eta bin is within eta phase-space window, defined by eta cut: + phietaWeights = GetHistogramWithWeights(pw.fFileWithWeights.Data(), tc.fRunNumber.Data(), "phieta", b); if (!phietaWeights) { - LOGF(fatal, "in function \033[1;31m%s at line %d, phietaWeights is NULL. Check the external file %s with particle weights\033[0m", __PRETTY_FUNCTION__, __LINE__, pw.fFileWithWeights.Data()); + LOGF(fatal, "\033[1;31m%s at line %d : phietaWeights is NULL. Check the external file %s with particle weights\033[0m", __FUNCTION__, __LINE__, pw.fFileWithWeights.Data()); + } + + // *) okay, just use this histogram with weights: + SetDiffWeightsHist(phietaWeights, wPHIETA, b); + } // for(int b=0; bFindBin(value); + double weight = 0.; + if (bin > cw.fCentralityWeightsHist->GetNbinsX()) { + weight = 0.; // we are in the overflow, ignore this case + } else { + weight = cw.fCentralityWeightsHist->GetBinContent(bin) * cw.fCentralityWeightsHist->GetBinWidth(bin); // yes, since fCentralityWeightsHist is normalized p.d.f. + // (I ensure that with the macro which makes centrality weights) + } + + // In this context, it is assumed that centrality weight is a normalized probability (I ensure that with the macro which makes centrality weights): + if (weight < 0. || weight > 1.) { + LOGF(fatal, "\033[1;31m%s at line %d : weight = %f \033[0m", __FUNCTION__, __LINE__, weight); + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + + return weight; + +} // double CentralityWeight(const double& value) + +//============================================================ + +bool MaxNumberOfEvents(eBeforeAfter ba) +{ + // Check if max number of events was reached. Can be used for cut eNumberOfEvents (= total events, with ba = eBefore), and eSelectedEvents (ba = eAfter). + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // *) Return value: + bool reachedMaxNumberOfEvents = false; + + // *) Internal validation case (special treatment): + if (iv.fUseInternalValidation) { + if (eh.fEventHistograms[eNumberOfEvents][eSim][eAfter] && (eh.fEventHistograms[eNumberOfEvents][eSim][eAfter]->GetBinContent(1) == ec.fdEventCuts[eNumberOfEvents][eMax] || eh.fEventHistograms[eNumberOfEvents][eSim][eAfter]->GetBinContent(1) == ec.fdEventCuts[eSelectedEvents][eMax])) { + return true; + } else { + return false; + } + } + + // *) Determine from which histogram the relevant info will be taken: + int rs = -44; // reconstructed or simulated + if (tc.fProcess[eGenericRec] || tc.fProcess[eGenericRecSim]) { // yes, for tc.fProcess[eGenericRecSim] I take info from Rec part + rs = eRec; + } else if (tc.fProcess[eGenericSim]) { + rs = eSim; + } else { + LOGF(fatal, "\033[1;31m%s at line %d : not a single flag gProcess* is true \033[0m", __FUNCTION__, __LINE__); + } + + // *) Okay, do the thing: + switch (ba) { + case eBefore: { + if (eh.fEventHistograms[eNumberOfEvents][rs][eBefore] && eh.fEventHistograms[eNumberOfEvents][rs][eBefore]->GetBinContent(1) == ec.fdEventCuts[eNumberOfEvents][eMax]) { + reachedMaxNumberOfEvents = true; + } + break; + } + case eAfter: { + if (eh.fEventHistograms[eNumberOfEvents][rs][eAfter] && eh.fEventHistograms[eNumberOfEvents][rs][eAfter]->GetBinContent(1) == ec.fdEventCuts[eSelectedEvents][eMax]) { + reachedMaxNumberOfEvents = true; + } + break; + } + default: { + LOGF(fatal, "\033[1;31m%s at line %d : enum ba = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, static_cast(ba)); + break; + } + } // switch (ba) + + // *) Hasta la vista: + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + return reachedMaxNumberOfEvents; + +} // void MaxNumberOfEvents(eBeforeAfter ba) + +//============================================================ + +void PrintEventCounter(eBeforeAfter ba) +{ + // Print how many events were processed by now. + // Remark: If I am processing RecSim, the counter is corresponding to Rec. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // *) Print or die: + switch (ba) { + case eBefore: { + if (!tc.fPlainPrintout) { + LOGF(info, "\033[1;32m%s : processing event %d ....\033[0m", __FUNCTION__, eh.fEventCounter[eTotal]); + } else { + LOGF(info, "%s : processing event %d ....", __FUNCTION__, eh.fEventCounter[eTotal]); + } + break; + } + case eAfter: { + if (!tc.fPlainPrintout) { + LOGF(info, "\033[1;32m%s : event passed all cuts %d/%d\033[0m", __FUNCTION__, eh.fEventCounter[eProcessed], eh.fEventCounter[eTotal]); + } else { + LOGF(info, "%s : event passed all cuts %d/%d", __FUNCTION__, eh.fEventCounter[eProcessed], eh.fEventCounter[eTotal]); } - SetDiffWeightsHist(phietaWeights, "phieta", b); - } // for(Int_t b=0; b(ba)); + break; + } + } // switch (ba) -} // void GetParticleWeights() + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void PrintEventCounter(eBeforeAfter ba) //============================================================ -Bool_t MaxNumberOfEvents() +void EventCounterForDryRun(eEventCounterForDryRun eVar) { - // Check if max number of events was reached. See also configurable cNumberOfEvents_max. + // Simple utility function which either fills histogram with event count, or prints its current content. + // Remark: Use only in combination with tc.fDryRun = true, otherwise I might be filling the same histogram in different member functions, there is a protection below. + // It fills or prints per call, therefore I do not have to pass 'collision' objects, etc. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); } - // *) Return value: - Bool_t reachedMaxNumberOfEvents = kFALSE; + if (!tc.fDryRun) { + LOGF(fatal, "\033[1;31m%s at line %d : for the time being, function EventCounterForDryRun(...) can be safely used only for tc.fDryRun = true \033[0m", __FUNCTION__, __LINE__); + } - // *) Determine from which histogram the relevant info will be taken: - Int_t rs = -44; // reconstructed or simulated - if (tc.fGenericRec || tc.fGenericRecSim) { // yes, for tc.fGenericRecSim I take info from Rec part - rs = eRec; - } else if (tc.fGenericSim) { - rs = eSim; - } else { - LOGF(fatal, "in function \033[1;31m%s at line %d, not a single flag gProcess* is true \033[0m", __PRETTY_FUNCTION__, __LINE__); + switch (eVar) { + case eFill: { + // Fill event counter: + !eh.fEventHistograms[eNumberOfEvents][eRec][eAfter] ? true : eh.fEventHistograms[eNumberOfEvents][eRec][eAfter]->Fill(0.5); + !eh.fEventHistograms[eNumberOfEvents][eSim][eAfter] ? true : eh.fEventHistograms[eNumberOfEvents][eSim][eAfter]->Fill(0.5); + break; + } + case ePrint: { + // Print current status of event counter: + // Remark: if I am processing RecSim, the counter is corresponding to Rec. + if (eh.fEventHistograms[eNumberOfEvents][eRec][eAfter]) { + LOGF(info, "Processing event %d (dry run) ....", static_cast(eh.fEventHistograms[eNumberOfEvents][eRec][eAfter]->GetBinContent(1))); + } else if (eh.fEventHistograms[eNumberOfEvents][eSim][eAfter]) { + LOGF(info, "Processing event %d (dry run) ....", static_cast(eh.fEventHistograms[eNumberOfEvents][eSim][eAfter]->GetBinContent(1))); + } + break; + } + default: { + LOGF(fatal, "\033[1;31m%s at line %d : enum eVar = %d is not supported yet in eEventCounter. \033[0m", __FUNCTION__, __LINE__, static_cast(eVar)); + break; + } + } // switch(eVar) + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); } - // *) Okay, do the thing: - if (eh.fEventHistograms[eNumberOfEvents][rs][eAfter] && eh.fEventHistograms[eNumberOfEvents][rs][eAfter]->GetBinContent(1) == eh.fEventCuts[eNumberOfEvents][eMax]) { - reachedMaxNumberOfEvents = kTRUE; +} // void EventCounterForDryRun(eEventCounterForDryRun eVar) + +//============================================================ + +const char* FancyFormatting(const char* name) +{ + // Simple utility function to convert ordinary name into fancier formatting. + + // Examples: + // 1. use LaTeX syntax (as supported by ROOT!), for the case when it's possible (e.g. "Phi" => "#{varphi}"); + // 2. add additional information to defalt name (e.g. "Centrality" => "Centrality (V0M)" + // 3. ... + + if (tc.fVerboseUtility) { + StartFunction(__FUNCTION__); + LOGF(info, "\033[1;32m const char* name = %s\033[0m", name); + } + + // By default, do nothing and return the same thing: + const char* fancyFormatting = name; + + // Special cases supported by now: + if (TString(name).EqualTo("Phi", TString::kIgnoreCase)) { + fancyFormatting = "#varphi"; + } else if (TString(name).EqualTo("Pt", TString::kIgnoreCase)) { + fancyFormatting = "p_{T}"; + } else if (TString(name).EqualTo("Eta", TString::kIgnoreCase)) { + fancyFormatting = "#eta"; + } else if (TString(name).EqualTo("VertexX")) { + fancyFormatting = "V_{x}"; + } else if (TString(name).EqualTo("VertexY")) { + fancyFormatting = "V_{y}"; + } else if (TString(name).EqualTo("VertexZ")) { + fancyFormatting = "V_{z}"; + } else if (TString(name).EqualTo("TotalMultiplicity")) { + fancyFormatting = "TotalMultiplicity (tracks.size())"; + } else if (TString(name).EqualTo("Multiplicity", TString::kIgnoreCase)) { + fancyFormatting = Form("Multiplicity (%s)", ec.fsEventCuts[eMultiplicityEstimator].Data()); + } else if (TString(name).EqualTo("ReferenceMultiplicity")) { + fancyFormatting = Form("ReferenceMultiplicity (%s)", ec.fsEventCuts[eReferenceMultiplicityEstimator].Data()); + } else if (TString(name).EqualTo("Centrality", TString::kIgnoreCase)) { + TString tmp = ec.fsEventCuts[eCentralityEstimator]; // I have to introduce local TString tmp, because ReplaceAll replaces in-place + if (tmp.BeginsWith("CentRun2")) { + fancyFormatting = Form("Centrality (%s)", tmp.ReplaceAll("CentRun2", "").Data()); // "CentRun2V0M" => "Centrality (V0M)" + } else if (tmp.BeginsWith("Cent")) { + fancyFormatting = Form("Centrality (%s)", tmp.ReplaceAll("Cent", "").Data()); // "CentFT0C" => "Centrality (FT0C)" + } else { + LOGF(fatal, "\033[1;31m%s at line %d : the case tmp = \"%s\" is not supported yet\033[0m", __FUNCTION__, __LINE__, tmp.Data()); + } + } else if (TString(name).EqualTo("Trigger")) { + fancyFormatting = Form("Trigger (%s)", ec.fsEventCuts[eTrigger].Data()); + } else if (TString(name).EqualTo("TrackOccupancyInTimeRange")) { + fancyFormatting = "trackOccupancyInTimeRange()"; + } else if (TString(name).EqualTo("FT0COccupancyInTimeRange")) { + fancyFormatting = "ft0cOccupancyInTimeRange()"; + } else if (TString(name).EqualTo("Occupancy", TString::kIgnoreCase)) { + fancyFormatting = Form("Occupancy (%s)", ec.fsEventCuts[eOccupancyEstimator].Data()); + } else if (TString(name).EqualTo("InteractionRate", TString::kIgnoreCase) || TString(name).EqualTo("Interaction Rate", TString::kIgnoreCase)) { + fancyFormatting = "Interaction Rate [kHz]"; // TBI 20241127 do I leave kHz hardwired here? + } else if (TString(name).EqualTo("CurrentRunDuration", TString::kIgnoreCase) || TString(name).EqualTo("Current Run Duration", TString::kIgnoreCase)) { + fancyFormatting = "Current run duration [s] (i.e. time in seconds since start of run)"; } - // *) Hasta la vista: - return reachedMaxNumberOfEvents; + if (tc.fVerboseUtility) { + ExitFunction(__FUNCTION__); + } + + return fancyFormatting; -} // void MaxNumberOfEvents() +} // const char* FancyFormatting(const char *name) //============================================================ -Double_t CalculateCustomNestedLoop(TArrayI* harmonics) +double CalculateCustomNestedLoops(TArrayI* harmonics) { // For the specified harmonics, get the correlation from nested loops. // Order of correlator is the number of harmonics, i.e. the number of elements in an array. @@ -4167,19 +13370,19 @@ Double_t CalculateCustomNestedLoop(TArrayI* harmonics) // c) Return value. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); } if (!harmonics) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - Int_t nParticles = ebye.fSelectedTracks; + int nParticles = ebye.fSelectedTracks; /* TBI 20231108 enable eventually if(fUseFixedNumberOfRandomlySelectedParticles) { nParticles = 0; - for(Int_t i=0;iGetSize();i++) + for(int i=0;iGetSize();i++) { if(TMath::Abs(nl.ftaNestedLoops[0]->GetAt(i)) > 0. && TMath::Abs(nl.ftaNestedLoops[1]->GetAt(i)) > 0.){nParticles++;} } @@ -4187,19 +13390,274 @@ Double_t CalculateCustomNestedLoop(TArrayI* harmonics) */ // a) Determine the order of correlator; - Int_t order = harmonics->GetSize(); + int order = harmonics->GetSize(); + if (0 == order || order > gMaxCorrelator) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + if (nl.fMaxNestedLoop > 0 && nl.fMaxNestedLoop < order) { + LOGF(info, " nl.fMaxNestedLoop > 0 && nl.fMaxNestedLoop < order, where nl.fMaxNestedLoop = %d, order = %d", nl.fMaxNestedLoop, order); + return 0.; // TBI 20240405 Is this really safe here? Re-think... + } + + // b) Custom nested loop: + TProfile* profile = new TProfile("profile", "", 1, 0., 1.); // helper profile to get all averages automatically + // profile->Sumw2(); + double value = 0.; // cos of current multiplet + double weight = 1.; // weight of current multiplet + for (int i1 = 0; i1 < nParticles; i1++) { + double dPhi1 = nl.ftaNestedLoops[0]->GetAt(i1); + double dW1 = nl.ftaNestedLoops[1]->GetAt(i1); + if (1 == order) { + value = TMath::Cos(harmonics->GetAt(0) * dPhi1); + weight = dW1; + profile->Fill(0.5, value, weight); + continue; + } + for (int i2 = 0; i2 < nParticles; i2++) { + if (i2 == i1) { + continue; + } + double dPhi2 = nl.ftaNestedLoops[0]->GetAt(i2); + double dW2 = nl.ftaNestedLoops[1]->GetAt(i2); + if (2 == order) { + value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2); + weight = dW1 * dW2; + profile->Fill(0.5, value, weight); + continue; + } + for (int i3 = 0; i3 < nParticles; i3++) { + if (i3 == i1 || i3 == i2) { + continue; + } + double dPhi3 = nl.ftaNestedLoops[0]->GetAt(i3); + double dW3 = nl.ftaNestedLoops[1]->GetAt(i3); + if (3 == order) { + value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3); + weight = dW1 * dW2 * dW3; + profile->Fill(0.5, value, weight); + continue; + } + for (int i4 = 0; i4 < nParticles; i4++) { + if (i4 == i1 || i4 == i2 || i4 == i3) { + continue; + } + double dPhi4 = nl.ftaNestedLoops[0]->GetAt(i4); + double dW4 = nl.ftaNestedLoops[1]->GetAt(i4); + if (4 == order) { + value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4); + weight = dW1 * dW2 * dW3 * dW4; + profile->Fill(0.5, value, weight); + continue; + } + for (int i5 = 0; i5 < nParticles; i5++) { + if (i5 == i1 || i5 == i2 || i5 == i3 || i5 == i4) { + continue; + } + double dPhi5 = nl.ftaNestedLoops[0]->GetAt(i5); + double dW5 = nl.ftaNestedLoops[1]->GetAt(i5); + if (5 == order) { + value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4 + harmonics->GetAt(4) * dPhi5); + weight = dW1 * dW2 * dW3 * dW4 * dW5; + profile->Fill(0.5, value, weight); + continue; + } + for (int i6 = 0; i6 < nParticles; i6++) { + if (i6 == i1 || i6 == i2 || i6 == i3 || i6 == i4 || i6 == i5) { + continue; + } + double dPhi6 = nl.ftaNestedLoops[0]->GetAt(i6); + double dW6 = nl.ftaNestedLoops[1]->GetAt(i6); + if (6 == order) { + value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4 + harmonics->GetAt(4) * dPhi5 + harmonics->GetAt(5) * dPhi6); + weight = dW1 * dW2 * dW3 * dW4 * dW5 * dW6; + profile->Fill(0.5, value, weight); + continue; + } + for (int i7 = 0; i7 < nParticles; i7++) { + if (i7 == i1 || i7 == i2 || i7 == i3 || i7 == i4 || i7 == i5 || i7 == i6) { + continue; + } + double dPhi7 = nl.ftaNestedLoops[0]->GetAt(i7); + double dW7 = nl.ftaNestedLoops[1]->GetAt(i7); + if (7 == order) { + value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4 + harmonics->GetAt(4) * dPhi5 + harmonics->GetAt(5) * dPhi6 + harmonics->GetAt(6) * dPhi7); + weight = dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7; + profile->Fill(0.5, value, weight); + continue; + } + for (int i8 = 0; i8 < nParticles; i8++) { + if (i8 == i1 || i8 == i2 || i8 == i3 || i8 == i4 || i8 == i5 || i8 == i6 || i8 == i7) { + continue; + } + double dPhi8 = nl.ftaNestedLoops[0]->GetAt(i8); + double dW8 = nl.ftaNestedLoops[1]->GetAt(i8); + if (8 == order) { + value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4 + harmonics->GetAt(4) * dPhi5 + harmonics->GetAt(5) * dPhi6 + harmonics->GetAt(6) * dPhi7 + harmonics->GetAt(7) * dPhi8); + weight = dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7 * dW8; + profile->Fill(0.5, value, weight); + continue; + } + for (int i9 = 0; i9 < nParticles; i9++) { + if (i9 == i1 || i9 == i2 || i9 == i3 || i9 == i4 || i9 == i5 || i9 == i6 || i9 == i7 || i9 == i8) { + continue; + } + double dPhi9 = nl.ftaNestedLoops[0]->GetAt(i9); + double dW9 = nl.ftaNestedLoops[1]->GetAt(i9); + if (9 == order) { + value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4 + harmonics->GetAt(4) * dPhi5 + harmonics->GetAt(5) * dPhi6 + harmonics->GetAt(6) * dPhi7 + harmonics->GetAt(7) * dPhi8 + harmonics->GetAt(8) * dPhi9); + weight = dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7 * dW8 * dW9; + profile->Fill(0.5, value, weight); + continue; + } + for (int i10 = 0; i10 < nParticles; i10++) { + if (i10 == i1 || i10 == i2 || i10 == i3 || i10 == i4 || i10 == i5 || i10 == i6 || i10 == i7 || i10 == i8 || i10 == i9) { + continue; + } + double dPhi10 = nl.ftaNestedLoops[0]->GetAt(i10); + double dW10 = nl.ftaNestedLoops[1]->GetAt(i10); + if (10 == order) { + value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4 + harmonics->GetAt(4) * dPhi5 + harmonics->GetAt(5) * dPhi6 + harmonics->GetAt(6) * dPhi7 + harmonics->GetAt(7) * dPhi8 + harmonics->GetAt(8) * dPhi9 + harmonics->GetAt(9) * dPhi10); + weight = dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7 * dW8 * dW9 * dW10; + profile->Fill(0.5, value, weight); + continue; + } + for (int i11 = 0; i11 < nParticles; i11++) { + if (i11 == i1 || i11 == i2 || i11 == i3 || i11 == i4 || i11 == i5 || i11 == i6 || i11 == i7 || i11 == i8 || i11 == i9 || i11 == i10) { + continue; + } + double dPhi11 = nl.ftaNestedLoops[0]->GetAt(i11); + double dW11 = nl.ftaNestedLoops[1]->GetAt(i11); + if (11 == order) { + value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4 + harmonics->GetAt(4) * dPhi5 + harmonics->GetAt(5) * dPhi6 + harmonics->GetAt(6) * dPhi7 + harmonics->GetAt(7) * dPhi8 + harmonics->GetAt(8) * dPhi9 + harmonics->GetAt(9) * dPhi10 + harmonics->GetAt(10) * dPhi11); + weight = dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7 * dW8 * dW9 * dW10 * dW11; + profile->Fill(0.5, value, weight); + continue; + } + for (int i12 = 0; i12 < nParticles; i12++) { + if (i12 == i1 || i12 == i2 || i12 == i3 || i12 == i4 || i12 == i5 || i12 == i6 || i12 == i7 || i12 == i8 || i12 == i9 || i12 == i10 || i12 == i11) { + continue; + } + double dPhi12 = nl.ftaNestedLoops[0]->GetAt(i12); + double dW12 = nl.ftaNestedLoops[1]->GetAt(i12); + if (12 == order) { + value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4 + harmonics->GetAt(4) * dPhi5 + harmonics->GetAt(5) * dPhi6 + harmonics->GetAt(6) * dPhi7 + harmonics->GetAt(7) * dPhi8 + harmonics->GetAt(8) * dPhi9 + harmonics->GetAt(9) * dPhi10 + harmonics->GetAt(10) * dPhi11 + harmonics->GetAt(11) * dPhi12); + weight = dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7 * dW8 * dW9 * dW10 * dW11 * dW12; + profile->Fill(0.5, value, weight); + continue; + } + + // ... it's easy to continue the above pattern here + + } // for(int i12=0; i12GetBinContent(1); + delete profile; + profile = NULL; + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + return finalValue; + +} // double CalculateCustomNestedLoops(TArrayI *harmonics) + +//============================================================ + +double CalculateKineCustomNestedLoops(TArrayI* harmonics, eAsFunctionOf AFO_variable, int bin) +{ + // For the specified harmonics, kine variable, and bin, get the correlation from nested loops. + // Order of correlator is the number of harmonics, i.e. the number of elements in an array. + + // a) Determine the order of correlator; + // b) Custom nested loop; + // c) Return value. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + if (!harmonics) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + // *) ... + eqvectorKine qvKine = eqvectorKine_N; // which component of q-vector + TString kineVarName = ""; + switch (AFO_variable) { + case AFO_PT: { + qvKine = PTq; + kineVarName = "pt"; + break; + } + case AFO_ETA: { + qvKine = ETAq; + kineVarName = "eta"; + break; + } + default: { + LOGF(fatal, "\033[1;31m%s at line %d : This AFO_variable = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, static_cast(AFO_variable)); + break; + } + } // switch(AFO_variable) + + // *) Insanity checks on above settings: + if (qvKine == eqvectorKine_N) { + LOGF(fatal, "\033[1;31m%s at line %d : qvKine == eqvectorKine_N => add some more entries to the case statement \033[0m", __FUNCTION__, __LINE__); + } + + if (0 > bin || res.fResultsPro[AFO_variable]->GetNbinsX() < bin) { // this 'bin' starts from 0, i.e. this is an array bin + // either underflow or overflow is hit, meaning that histogram is booked in narrower range than cuts + LOGF(fatal, "\033[1;31m%s at line %d => AFO_variable = %d, bin = %d\033[0m", __FUNCTION__, __LINE__, static_cast(AFO_variable), bin); + } + + // Get the number of particles in this kine bin: + int nParticles = 0; + for (int i = 0; i < nl.ftaNestedLoopsKine[qvKine][bin][0]->GetSize(); i++) { + if (TMath::Abs(nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i)) > 0.) { + nParticles++; + } + } + + // 'qvKine' is enum eqvectorKine: + if (!res.fResultsPro[AFO_variable]) { + LOGF(fatal, "\033[1;31m%s at line %d : AFO_variable = %d, bin = %d \033[0m", __FUNCTION__, __LINE__, static_cast(AFO_variable), bin); + } + + LOGF(info, " Processing qvKine = %d (vs. %s), nParticles in this kine bin = %d, bin range = [%f,%f) ....", static_cast(qvKine), kineVarName.Data(), nParticles, res.fResultsPro[AFO_variable]->GetBinLowEdge(bin + 1), res.fResultsPro[AFO_variable]->GetBinLowEdge(bin + 2)); + + // a) Determine the order of correlator; + int order = harmonics->GetSize(); if (0 == order || order > gMaxCorrelator) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + if (order > nParticles) { + LOGF(info, " There is no enough particles in this bin to calculate the requested correlator"); + return 0.; // TBI 20240405 Is this really safe here? Re-think... + } + if (nl.fMaxNestedLoop > 0 && nl.fMaxNestedLoop < order) { + LOGF(info, " nl.fMaxNestedLoop > 0 && nl.fMaxNestedLoop < order, where nl.fMaxNestedLoop = %d, order = %d", nl.fMaxNestedLoop, order); + return 0.; // TBI 20240405 Is this really safe here? Re-think... } // b) Custom nested loop: TProfile* profile = new TProfile("profile", "", 1, 0., 1.); // helper profile to get all averages automatically // profile->Sumw2(); - Double_t value = 0.; // cos of current multiplet - Double_t weight = 1.; // weight of current multiplet + double value = 0.; // cos of current multiplet + double weight = 1.; // weight of current multiplet for (int i1 = 0; i1 < nParticles; i1++) { - Double_t dPhi1 = nl.ftaNestedLoops[0]->GetAt(i1); - Double_t dW1 = nl.ftaNestedLoops[1]->GetAt(i1); + double dPhi1 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i1); + double dW1 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i1); if (1 == order) { value = TMath::Cos(harmonics->GetAt(0) * dPhi1); weight = dW1; @@ -4210,8 +13668,8 @@ Double_t CalculateCustomNestedLoop(TArrayI* harmonics) if (i2 == i1) { continue; } - Double_t dPhi2 = nl.ftaNestedLoops[0]->GetAt(i2); - Double_t dW2 = nl.ftaNestedLoops[1]->GetAt(i2); + double dPhi2 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i2); + double dW2 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i2); if (2 == order) { value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2); weight = dW1 * dW2; @@ -4222,8 +13680,8 @@ Double_t CalculateCustomNestedLoop(TArrayI* harmonics) if (i3 == i1 || i3 == i2) { continue; } - Double_t dPhi3 = nl.ftaNestedLoops[0]->GetAt(i3); - Double_t dW3 = nl.ftaNestedLoops[1]->GetAt(i3); + double dPhi3 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i3); + double dW3 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i3); if (3 == order) { value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3); weight = dW1 * dW2 * dW3; @@ -4234,8 +13692,8 @@ Double_t CalculateCustomNestedLoop(TArrayI* harmonics) if (i4 == i1 || i4 == i2 || i4 == i3) { continue; } - Double_t dPhi4 = nl.ftaNestedLoops[0]->GetAt(i4); - Double_t dW4 = nl.ftaNestedLoops[1]->GetAt(i4); + double dPhi4 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i4); + double dW4 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i4); if (4 == order) { value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4); weight = dW1 * dW2 * dW3 * dW4; @@ -4246,8 +13704,8 @@ Double_t CalculateCustomNestedLoop(TArrayI* harmonics) if (i5 == i1 || i5 == i2 || i5 == i3 || i5 == i4) { continue; } - Double_t dPhi5 = nl.ftaNestedLoops[0]->GetAt(i5); - Double_t dW5 = nl.ftaNestedLoops[1]->GetAt(i5); + double dPhi5 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i5); + double dW5 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i5); if (5 == order) { value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4 + harmonics->GetAt(4) * dPhi5); weight = dW1 * dW2 * dW3 * dW4 * dW5; @@ -4258,8 +13716,8 @@ Double_t CalculateCustomNestedLoop(TArrayI* harmonics) if (i6 == i1 || i6 == i2 || i6 == i3 || i6 == i4 || i6 == i5) { continue; } - Double_t dPhi6 = nl.ftaNestedLoops[0]->GetAt(i6); - Double_t dW6 = nl.ftaNestedLoops[1]->GetAt(i6); + double dPhi6 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i6); + double dW6 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i6); if (6 == order) { value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4 + harmonics->GetAt(4) * dPhi5 + harmonics->GetAt(5) * dPhi6); weight = dW1 * dW2 * dW3 * dW4 * dW5 * dW6; @@ -4270,8 +13728,8 @@ Double_t CalculateCustomNestedLoop(TArrayI* harmonics) if (i7 == i1 || i7 == i2 || i7 == i3 || i7 == i4 || i7 == i5 || i7 == i6) { continue; } - Double_t dPhi7 = nl.ftaNestedLoops[0]->GetAt(i7); - Double_t dW7 = nl.ftaNestedLoops[1]->GetAt(i7); + double dPhi7 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i7); + double dW7 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i7); if (7 == order) { value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4 + harmonics->GetAt(4) * dPhi5 + harmonics->GetAt(5) * dPhi6 + harmonics->GetAt(6) * dPhi7); weight = dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7; @@ -4282,8 +13740,8 @@ Double_t CalculateCustomNestedLoop(TArrayI* harmonics) if (i8 == i1 || i8 == i2 || i8 == i3 || i8 == i4 || i8 == i5 || i8 == i6 || i8 == i7) { continue; } - Double_t dPhi8 = nl.ftaNestedLoops[0]->GetAt(i8); - Double_t dW8 = nl.ftaNestedLoops[1]->GetAt(i8); + double dPhi8 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i8); + double dW8 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i8); if (8 == order) { value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4 + harmonics->GetAt(4) * dPhi5 + harmonics->GetAt(5) * dPhi6 + harmonics->GetAt(6) * dPhi7 + harmonics->GetAt(7) * dPhi8); weight = dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7 * dW8; @@ -4294,8 +13752,8 @@ Double_t CalculateCustomNestedLoop(TArrayI* harmonics) if (i9 == i1 || i9 == i2 || i9 == i3 || i9 == i4 || i9 == i5 || i9 == i6 || i9 == i7 || i9 == i8) { continue; } - Double_t dPhi9 = nl.ftaNestedLoops[0]->GetAt(i9); - Double_t dW9 = nl.ftaNestedLoops[1]->GetAt(i9); + double dPhi9 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i9); + double dW9 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i9); if (9 == order) { value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4 + harmonics->GetAt(4) * dPhi5 + harmonics->GetAt(5) * dPhi6 + harmonics->GetAt(6) * dPhi7 + harmonics->GetAt(7) * dPhi8 + harmonics->GetAt(8) * dPhi9); weight = dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7 * dW8 * dW9; @@ -4306,8 +13764,8 @@ Double_t CalculateCustomNestedLoop(TArrayI* harmonics) if (i10 == i1 || i10 == i2 || i10 == i3 || i10 == i4 || i10 == i5 || i10 == i6 || i10 == i7 || i10 == i8 || i10 == i9) { continue; } - Double_t dPhi10 = nl.ftaNestedLoops[0]->GetAt(i10); - Double_t dW10 = nl.ftaNestedLoops[1]->GetAt(i10); + double dPhi10 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i10); + double dW10 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i10); if (10 == order) { value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4 + harmonics->GetAt(4) * dPhi5 + harmonics->GetAt(5) * dPhi6 + harmonics->GetAt(6) * dPhi7 + harmonics->GetAt(7) * dPhi8 + harmonics->GetAt(8) * dPhi9 + harmonics->GetAt(9) * dPhi10); weight = dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7 * dW8 * dW9 * dW10; @@ -4318,8 +13776,8 @@ Double_t CalculateCustomNestedLoop(TArrayI* harmonics) if (i11 == i1 || i11 == i2 || i11 == i3 || i11 == i4 || i11 == i5 || i11 == i6 || i11 == i7 || i11 == i8 || i11 == i9 || i11 == i10) { continue; } - Double_t dPhi11 = nl.ftaNestedLoops[0]->GetAt(i11); - Double_t dW11 = nl.ftaNestedLoops[1]->GetAt(i11); + double dPhi11 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i11); + double dW11 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i11); if (11 == order) { value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4 + harmonics->GetAt(4) * dPhi5 + harmonics->GetAt(5) * dPhi6 + harmonics->GetAt(6) * dPhi7 + harmonics->GetAt(7) * dPhi8 + harmonics->GetAt(8) * dPhi9 + harmonics->GetAt(9) * dPhi10 + harmonics->GetAt(10) * dPhi11); weight = dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7 * dW8 * dW9 * dW10 * dW11; @@ -4330,8 +13788,8 @@ Double_t CalculateCustomNestedLoop(TArrayI* harmonics) if (i12 == i1 || i12 == i2 || i12 == i3 || i12 == i4 || i12 == i5 || i12 == i6 || i12 == i7 || i12 == i8 || i12 == i9 || i12 == i10 || i12 == i11) { continue; } - Double_t dPhi12 = nl.ftaNestedLoops[0]->GetAt(i12); - Double_t dW12 = nl.ftaNestedLoops[1]->GetAt(i12); + double dPhi12 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i12); + double dW12 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i12); if (12 == order) { value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3 + harmonics->GetAt(3) * dPhi4 + harmonics->GetAt(4) * dPhi5 + harmonics->GetAt(5) * dPhi6 + harmonics->GetAt(6) * dPhi7 + harmonics->GetAt(7) * dPhi8 + harmonics->GetAt(8) * dPhi9 + harmonics->GetAt(9) * dPhi10 + harmonics->GetAt(10) * dPhi11 + harmonics->GetAt(11) * dPhi12); weight = dW1 * dW2 * dW3 * dW4 * dW5 * dW6 * dW7 * dW8 * dW9 * dW10 * dW11 * dW12; @@ -4342,25 +13800,141 @@ Double_t CalculateCustomNestedLoop(TArrayI* harmonics) // ... it's easy to continue the above pattern here } // for(int i12=0; i12GetBinContent(1); + double finalValue = profile->GetBinContent(1); delete profile; profile = NULL; + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } return finalValue; -} // Double_t CalculateCustomNestedLoop(TArrayI *harmonics) +} // double CalculateKineCustomNestedLoops(TArrayI *harmonics, eAsFunctionOf AFO_variable, int bin) + +//============================================================ + +void DetermineMultiplicity() +{ + // Determine multiplicity for "vs. mult" results. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + if (ec.fsEventCuts[eMultiplicityEstimator].EqualTo("SelectedTracks", TString::kIgnoreCase)) { + ebye.fMultiplicity = static_cast(ebye.fSelectedTracks); + } else if (ec.fsEventCuts[eMultiplicityEstimator].EqualTo("ReferenceMultiplicity", TString::kIgnoreCase)) { + ebye.fMultiplicity = ebye.fReferenceMultiplicity; + } else { + LOGF(fatal, "\033[1;31m%s at line %d : multiplicity estimator = %s is not supported yet. \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eMultiplicityEstimator].Data()); + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void DetermineMultiplicity() + +//============================================================ + +template +void DetermineReferenceMultiplicity(T const& collision) +{ + // Determine collision reference multiplicity. + + // a) Determine reference multiplicity for real Run 3 data; + // b) Determine reference multiplicity for simulated Run 3 data; + // c) Same as a), just for converted Run 2 and Run 1 data; + // d) Same as b), just for converted Run 2 and Run 1 data; + // e) Test case; + // f) Print reference multiplicity for the audience... + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Determine reference multiplicity for real Run 3 data: + if constexpr (rs == eRec || rs == eRecAndSim || rs == eQA) { + // Local convention for name of reference multiplicity estimator: use the same name as the getter, case insensitive. + if (ec.fsEventCuts[eReferenceMultiplicityEstimator].EqualTo("multTPC", TString::kIgnoreCase)) { + ebye.fReferenceMultiplicity = collision.multTPC(); + } else if (ec.fsEventCuts[eReferenceMultiplicityEstimator].EqualTo("multFV0M", TString::kIgnoreCase)) { + ebye.fReferenceMultiplicity = collision.multFV0M(); + } else if (ec.fsEventCuts[eReferenceMultiplicityEstimator].EqualTo("multFT0C", TString::kIgnoreCase)) { + ebye.fReferenceMultiplicity = collision.multFT0C(); + } else if (ec.fsEventCuts[eReferenceMultiplicityEstimator].EqualTo("multFT0M", TString::kIgnoreCase)) { + ebye.fReferenceMultiplicity = collision.multFT0M(); + } else if (ec.fsEventCuts[eReferenceMultiplicityEstimator].EqualTo("multNTracksPV", TString::kIgnoreCase)) { + ebye.fReferenceMultiplicity = collision.multNTracksPV(); + } else if (ec.fsEventCuts[eReferenceMultiplicityEstimator].EqualTo("multNTracksGlobal", TString::kIgnoreCase)) { + // ebye.fReferenceMultiplicity = collision.multNTracksGlobal(); // TBI 20241209 not validated yet + } else { + LOGF(fatal, "\033[1;31m%s at line %d : reference multiplicity estimator = %d is not supported yet for Run 3. \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eReferenceMultiplicityEstimator].Data()); + } + // QA: + if (qa.fFillQAEventHistograms2D) { // TBI 20240515 this flag is too general here, I need to make it more specific + qa.fReferenceMultiplicity[eMultTPC] = collision.multTPC(); + qa.fReferenceMultiplicity[eMultFV0M] = collision.multFV0M(); + qa.fReferenceMultiplicity[eMultFT0C] = collision.multFT0C(); + qa.fReferenceMultiplicity[eMultFT0M] = collision.multFT0M(); + qa.fReferenceMultiplicity[eMultNTracksPV] = collision.multNTracksPV(); + // qa.fReferenceMultiplicity[eMultNTracksGlobal] = collision.multNTracksGlobal(); // TBI 20241209 not validated yet + } + + // TBI 20241123 check if corresponding simulated ref. mult. is available through collision.has_mcCollision() + // ... + } + + // b) Determine reference multiplicity for simulated Run 3 data: + if constexpr (rs == eSim) { + ebye.fReferenceMultiplicity = -44.; // TBI 20241123 check what to use here and add support eventualy + } + + // c) Same as a), just for converted Run 2 and Run 1 data: + if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { + if (ec.fsEventCuts[eReferenceMultiplicityEstimator].EqualTo("multTracklets", TString::kIgnoreCase)) { + ebye.fReferenceMultiplicity = collision.multTracklets(); + } else { + LOGF(fatal, "\033[1;31m%s at line %d : reference multiplicity estimator = %d is not supported yet for Run 2. \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eReferenceMultiplicityEstimator].Data()); + } + // QA: + if (qa.fFillQAEventHistograms2D) { // TBI 20240515 this flag is too general here, I need to make it more specific + // ... + } + + // TBI 20241123 check if corresponding simulated ref. mult. is available through collision.has_mcCollision() + // ... + } + + // d) Same as b), just for converted Run 2 and Run 1 data: + if constexpr (rs == eSim_Run2 || rs == eSim_Run1) { + ebye.fReferenceMultiplicity = -44.; // TBI 20241123 check what to use here and add support eventualy + } + + // e) Test case: + if constexpr (rs == eTest) { + ebye.fReferenceMultiplicity = static_cast(gRandom->Uniform(0., 5000.)); // TBI 20241123 I could implement here a getter, if there is one available both for Run 3 and Run 2/1 + } + + // f) Print centrality for the audience...: + if (tc.fVerbose) { + LOGF(info, "\033[1;32m ebye.fReferenceMultiplicity = %f\033[0m", ebye.fReferenceMultiplicity); + ExitFunction(__FUNCTION__); + } + +} // template void DetermineReferenceMultiplicity(T const& collision) //============================================================ @@ -4375,25 +13949,44 @@ void DetermineCentrality(T const& collision) // d) Same as b), just for converted Run 2 data; // e) Same as a), just for converted Run 1 data; // f) Same as b), just for converted Run 1 data; - // g) Test case. + // g) Test case; + // h) Print centrality for the audience... if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); // just a bare function name + StartFunction(__FUNCTION__); } // a) For real data, determine centrality from default centrality estimator: - if constexpr (rs == eRec || rs == eRecAndSim) { - if (ec.fCentralityEstimator.EqualTo("centFT0M", TString::kIgnoreCase)) { + if constexpr (rs == eRec || rs == eRecAndSim || rs == eQA) { + // Local convention for name of centrality estimator: use the same name as the getter, case insensitive. + if (ec.fsEventCuts[eCentralityEstimator].EqualTo("centFT0C", TString::kIgnoreCase)) { + ebye.fCentrality = collision.centFT0C(); + } else if (ec.fsEventCuts[eCentralityEstimator].EqualTo("centFT0CVariant1", TString::kIgnoreCase)) { + ebye.fCentrality = collision.centFT0CVariant1(); + } else if (ec.fsEventCuts[eCentralityEstimator].EqualTo("centFT0M", TString::kIgnoreCase)) { ebye.fCentrality = collision.centFT0M(); - } else if (ec.fCentralityEstimator.EqualTo("CentFV0A", TString::kIgnoreCase)) { + } else if (ec.fsEventCuts[eCentralityEstimator].EqualTo("centFV0A", TString::kIgnoreCase)) { ebye.fCentrality = collision.centFV0A(); - } else if (ec.fCentralityEstimator.EqualTo("CentNTPV", TString::kIgnoreCase)) { + } else if (ec.fsEventCuts[eCentralityEstimator].EqualTo("centNTPV", TString::kIgnoreCase)) { ebye.fCentrality = collision.centNTPV(); + } else if (ec.fsEventCuts[eCentralityEstimator].EqualTo("centNGlobal", TString::kIgnoreCase)) { + // ebye.fCentrality = collision.centNGlobal(); // TBI 20250128 enable eventually } else { - LOGF(fatal, "in function \033[1;31m%s at line %d. centrality estimator = %d is not supported yet. \033[0m", __PRETTY_FUNCTION__, __LINE__, ec.fCentralityEstimator.Data()); + LOGF(fatal, "\033[1;31m%s at line %d : centrality estimator = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eCentralityEstimator].Data()); + } + // QA: + if (qa.fFillQAEventHistograms2D || ec.fUseEventCuts[eCentralityCorrelationsCut]) { // TBI 20250331 I re-use here qa.fCentrality for CentralityCorrelationsCut, why not... + qa.fCentrality[eCentFT0C] = collision.centFT0C(); + qa.fCentrality[eCentFT0CVariant1] = collision.centFT0CVariant1(); + qa.fCentrality[eCentFT0M] = collision.centFT0M(); + qa.fCentrality[eCentFV0A] = collision.centFV0A(); + qa.fCentrality[eCentNTPV] = collision.centNTPV(); + // qa.fCentrality[eCentNGlobal] = collision.centNGlobal(); // TBI 20250128 enable eventually } + // TBI 20240120 I could also here access also corresponding simulated centrality from impact parameter, if available through collision.has_mcCollision() - } + + } // if constexpr (rs == eRec || rs == eRecAndSim) // b) For simulated data, determine centrality directly from impact parameter: if constexpr (rs == eSim) { @@ -4402,13 +13995,19 @@ void DetermineCentrality(T const& collision) // c) Same as a), just for converted Run 2 data: if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2) { - if (ec.fCentralityEstimator.EqualTo("centRun2V0M", TString::kIgnoreCase)) { + if (ec.fsEventCuts[eCentralityEstimator].EqualTo("centRun2V0M", TString::kIgnoreCase)) { ebye.fCentrality = collision.centRun2V0M(); - } else if (ec.fCentralityEstimator.EqualTo("CentRun2SPDTracklets", TString::kIgnoreCase)) { + } else if (ec.fsEventCuts[eCentralityEstimator].EqualTo("centRun2SPDTracklets", TString::kIgnoreCase)) { ebye.fCentrality = collision.centRun2SPDTracklets(); } else { - LOGF(fatal, "in function \033[1;31m%s at line %d. centrality estimator = %d is not supported yet. \033[0m", __PRETTY_FUNCTION__, __LINE__, ec.fCentralityEstimator.Data()); + LOGF(fatal, "\033[1;31m%s at line %d : centrality estimator = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eCentralityEstimator].Data()); + } + // QA: + if (qa.fFillQAEventHistograms2D || ec.fUseEventCuts[eCentralityCorrelationsCut]) { // TBI 20250331 I re-use here qa.fCentrality for CentralityCorrelationsCut, why not... + qa.fCentrality[eCentRun2V0M] = collision.centRun2V0M(); + qa.fCentrality[eCentRun2SPDTracklets] = collision.centRun2SPDTracklets(); } + // TBI 20240120 I could also here access also corresponding simulated centrality from impact parameter, if available through collision.has_mcCollision() } @@ -4419,41 +14018,236 @@ void DetermineCentrality(T const& collision) // e) Same as a), just for converted Run 1 data: if constexpr (rs == eRec_Run1 || rs == eRecAndSim_Run1) { - if (ec.fCentralityEstimator.EqualTo("centRun2V0M", TString::kIgnoreCase)) { + if (ec.fsEventCuts[eCentralityEstimator].EqualTo("centRun2V0M", TString::kIgnoreCase)) { // ebye.fCentrality = collision.centRun2V0M(); // TBI 20240224 enable when I add support for RecAndSim_Run1 - } else if (ec.fCentralityEstimator.EqualTo("CentRun2SPDTracklets", TString::kIgnoreCase)) { + } else if (ec.fsEventCuts[eCentralityEstimator].EqualTo("CentRun2SPDTracklets", TString::kIgnoreCase)) { // ebye.fCentrality = collision.centRun2SPDTracklets(); // TBI 20240224 enable when I add support for RecAndSim_Run1 } else { - LOGF(fatal, "in function \033[1;31m%s at line %d. centrality estimator = %d is not supported yet. \033[0m", __PRETTY_FUNCTION__, __LINE__, ec.fCentralityEstimator.Data()); + LOGF(fatal, "\033[1;31m%s at line %d : centrality estimator = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eCentralityEstimator].Data()); } // TBI 20240120 I could also here access also corresponding simulated centrality from impact parameter, if available through collision.has_mcCollision() } // f) Same as b), just for converted Run 1 data: if constexpr (rs == eSim_Run1) { - ebye.fCentrality = -44.; // TBI 20240120 add support eventualy + ebye.fCentrality = -44.; // TBI 20240515 add support eventualy, or merge with Run 2 branch. It seems that in converted Run 1 there is no centrality. } // g) Test case: if constexpr (rs == eTest) { - ebye.fCentrality = gRandom->Uniform(0., 100.); + ebye.fCentrality = static_cast(gRandom->Uniform(0., 100.)); } - // *) Print centrality for the audience...: + // h) Print centrality for the audience...: if (tc.fVerbose) { LOGF(info, "\033[1;32m ebye.fCentrality = %f\033[0m", ebye.fCentrality); + ExitFunction(__FUNCTION__); } } // template void DetermineCentrality(T const& collision) //============================================================ -void RandomIndices(Int_t nTracks) +template +void DetermineOccupancy(T const& collision) +{ + // Determine collision occupancy. + + // a) Determine occupancy from default occupancy estimator, only for eRec and eRecAndSim; + // b) For all other cases, set occupancy to -1 (not defined). + // c) Print occupancy for the audience... + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Determine occupancy from default occupancy estimator, only for eRec and eRecAndSim: + if constexpr (rs == eRec || rs == eRecAndSim || rs == eQA) { + if (ec.fsEventCuts[eOccupancyEstimator].EqualTo("TrackOccupancyInTimeRange", TString::kIgnoreCase)) { + ebye.fOccupancy = collision.trackOccupancyInTimeRange(); + } else if (ec.fsEventCuts[eOccupancyEstimator].EqualTo("FT0COccupancyInTimeRange", TString::kIgnoreCase)) { + ebye.fOccupancy = collision.ft0cOccupancyInTimeRange(); + } else { + LOGF(fatal, "\033[1;31m%s at line %d : occupancy estimator = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eOccupancyEstimator].Data()); + } + // QA: + if (qa.fFillQAEventHistograms2D) { // TBI 20240515 this flag is too general here, I need to make it more specific + qa.fOccupancy[eTrackOccupancyInTimeRange] = collision.trackOccupancyInTimeRange(); + qa.fOccupancy[eFT0COccupancyInTimeRange] = collision.ft0cOccupancyInTimeRange(); + } + } else { + // b) For all other cases, set occupancy to -1 (not defined): + ebye.fOccupancy = -1.; + // QA: + if (qa.fFillQAEventHistograms2D) { // TBI 20240515 this flag is too general here, I need to make it more specific + for (int oe = 0; oe < eOccupancyEstimators_N; oe++) { + qa.fOccupancy[oe] = -1.; + } + } + } + + // c) Print occupancy for the audience...: + if (tc.fVerbose) { + LOGF(info, "\033[1;32m ebye.fOccupancy = %f\033[0m", ebye.fOccupancy); + ExitFunction(__FUNCTION__); + } + +} // template void DetermineOccupancy(T const& collision) + +//============================================================ + +template +void DetermineInteractionRateAndCurrentRunDuration(T1 const& collision, T2 const&) +{ + // Determine interaction rate and current run duration in Run 3. + + // Cannot be used in converted Run 2 and Run 1, because mRateFetcher.fetch... line below crashes with example line: + // [228607:multiparticle-correlations-a-b]: [10:02:38][ERROR] Requested resource does not exist: http://alice-ccdb.cern.ch//GLO/Config/GRPLHCIF/1449947476529/ + // [228607:multiparticle-correlations-a-b]: [10:02:38][FATAL] Got nullptr from CCDB for path GLO/Config/GRPLHCIF and timestamp 1449947476529 + + // a) Determine interaction rate and current run duration only for eRec; + // b) For all other cases, set interaction rate to -1 for the time being; + // c) Print interaction rate and current run duration for the audience... + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a1) Determine interaction rate only for eRec: + if constexpr (rs == eRec || rs == eQA) { // TBI 20250112 check still eRecSim mode here + auto bc = collision.template foundBC_as(); // I have the same code snippet at other places, keep in sync. + double hadronicRate = mRateFetcher.fetch(ccdb.service, static_cast(bc.timestamp()), static_cast(bc.runNumber()), "ZNC hadronic") * 1.e-3; + if (hadronicRate > 0.) { + ebye.fInteractionRate = static_cast(hadronicRate); + } else { + LOGF(warning, "\033[1;31m%s at line %d : hadronicRate = %f is meaningless \033[0m", __FUNCTION__, __LINE__, hadronicRate); + // I hit indeed at negative hadronic rate in LHC24ar/559545/apass1 dataset. But I do not really need to bail out here, because that collision in + // any case will not pass a cut in configurable cfInteractionRate . Therefore, I print a warning, and then can grep it from the log, if necessary. + } + + // a2) Determine the current run duration: + // TBI 20250107 I could move this to a separate function? + ebye.fCurrentRunDuration = std::floor(bc.timestamp() * 0.001) - tc.fRunTime[eStartOfRun]; + if (ebye.fCurrentRunDuration > tc.fRunTime[eDurationInSec]) { + LOGF(fatal, "\033[1;31m%s at line %d : ebye.fCurrentRunDuration = %d is bigger than tc.fRunTime[eDurationInSec] = %d, which is meaningless \033[0m", __FUNCTION__, __LINE__, static_cast(ebye.fCurrentRunDuration), static_cast(tc.fRunTime[eDurationInSec])); + } + + } else { + // b) For all other cases, set interaction rate to -1: + ebye.fInteractionRate = -1.; + ebye.fCurrentRunDuration = -1.; + ebye.fFT0CAmplitudeOnFoundBC = -1.; + } + + // c) Print interaction rate and run duration for the audience...: + if (tc.fVerbose) { + LOGF(info, "\033[1;32m ebye.fInteractionRate = %f kHz\033[0m", ebye.fInteractionRate); + if (qa.fBookQAEventHistograms2D[eCurrentRunDuration_vs_InteractionRate]) { // TBI 20241127 do I check this flag, or pointer, like in FillEventHistograms(...) ? + LOGF(info, "\033[1;32m ebye.fCurrentRunDuration = %f s (in seconds after SOR)\033[0m", ebye.fCurrentRunDuration); + } + ExitFunction(__FUNCTION__); + } + +} // template void DetermineInteractionRateAndCurrentRunDuration(T1 const& collision, T2 const&) + +//============================================================ + +template +void DetermineVertexZ(T const& collision) +{ + // Determine vetex z position. + + // TBI 20250108 I could use ebye.fVz determined here to fill event histograms, but it's not a big deal to fetch it there also via collision.posZ() + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + ebye.fVz = collision.posZ(); + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void DetermineVertexZ(T const& collision) + +//============================================================ + +template +void DetermineQAThingies(T1 const& collision, T2 const&) +{ + // Remark: I implement ideally here only the getters for which the subscription to additional non-standard tables was needed for QA purposes. + // Support only for Run 3 data is provided, because in the "processQA" switch the starting point are tables used in "processRec", and I join to them + // some non-standard tables only for QA purposes. + + // a) Determine FT0CAmplitudeOnFoundBC; + // ... + // *) Print something for the audience... . + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + if constexpr (rs == eQA) { + auto bc = collision.template foundBC_as(); // I have the same code snippet at other places, keep in sync. + + // a) Determine FT0CAmplitudeOnFoundBC; + if (bc.has_foundFT0()) { + ebye.fFT0CAmplitudeOnFoundBC = bc.foundFT0().sumAmpC(); // see more details in rofOccupancyQa.cxx + } + + // ... + + // *) Print something for the audience...: + if (tc.fVerbose) { + LOGF(info, "\033[1;32m ebye.fFT0CAmplitudeOnFoundBC = %f\033[0m", ebye.fFT0CAmplitudeOnFoundBC); + } // if (tc.fVerbose) { + + } else { + // For all other cases, set all QA-specific variables calculated here to -1. TBI 20250401 shall I really do it this way, in a sense that for all other cases, this function should never be called? + ebye.fFT0CAmplitudeOnFoundBC = -1.; + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } // if (tc.fVerbose) { + +} // template void DetermineQAThingies(T1 const& collision, T2 const&) + +//============================================================ + +void DetermineEventCounters() +{ + // Determine all event counters. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // Remark: For "RecSim", the total number of events is taken from eRec. + if (eh.fEventHistograms[eNumberOfEvents][eRec][eBefore] && eh.fEventHistograms[eNumberOfEvents][eRec][eAfter]) { + eh.fEventCounter[eTotal] = static_cast(eh.fEventHistograms[eNumberOfEvents][eRec][eBefore]->GetBinContent(1)); + eh.fEventCounter[eProcessed] = static_cast(eh.fEventHistograms[eNumberOfEvents][eRec][eAfter]->GetBinContent(1)); + } else if (eh.fEventHistograms[eNumberOfEvents][eSim][eBefore] && eh.fEventHistograms[eNumberOfEvents][eSim][eAfter]) { + // Remark: This branch covers automatically also internal validation, because I book and fill there only eSim. + eh.fEventCounter[eTotal] = static_cast(eh.fEventHistograms[eNumberOfEvents][eSim][eBefore]->GetBinContent(1)); + eh.fEventCounter[eProcessed] = static_cast(eh.fEventHistograms[eNumberOfEvents][eSim][eAfter]->GetBinContent(1)); + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void DetermineEventCounters() + +//============================================================ + +void RandomIndices(int nTracks) { // Randomize indices using Fisher-Yates algorithm. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); } if (nTracks < 1) { @@ -4463,160 +14257,653 @@ void RandomIndices(Int_t nTracks) // Fisher-Yates algorithm: tc.fRandomIndices = new TArrayI(nTracks); tc.fRandomIndices->Reset(); // just in case there is some random garbage in memory at init - for (Int_t i = 0; i < nTracks; i++) { + for (int i = 0; i < nTracks; i++) { tc.fRandomIndices->AddAt(i, i); } - for (Int_t i = nTracks - 1; i >= 1; i--) { - Int_t j = gRandom->Integer(i + 1); - Int_t temp = tc.fRandomIndices->GetAt(j); + for (int i = nTracks - 1; i >= 1; i--) { + int j = gRandom->Integer(i + 1); + int temp = tc.fRandomIndices->GetAt(j); tc.fRandomIndices->AddAt(tc.fRandomIndices->GetAt(i), j); tc.fRandomIndices->AddAt(temp, i); - } // end of for(Int_t i=nTracks-1;i>=1;i--) + } // end of for(int i=nTracks-1;i>=1;i--) + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void RandomIndices(int nTracks) + +//============================================================ + +template +void BanishmentLoopOverParticles(T const& tracks) +{ + // This is the quick banishment loop over particles, as a support for eSelectedTracks cut (used through eMultiplicity, see comments for ebye.fMultiplicity). + // This is particularly relevant to get all efficiency corrections right. + // The underlying problem is that particle histograms got filled before eSelectedTracks could be applied in Steer. + // Therefore, particle histograms got filled even for events which were rejected by eSelectedTracks cut. + // In this loop, for those few specific events (typically low-multiplicity outliers), particle histograms are re-filled again with weight -1, + // which in effect cancels the previos fill in the MainLoopOverParticles. + + // Remark: I have to use here all additional checks, like ValidTrack, as in the MainLoopOverParticles. + // Therefore, it's important to have local variable lSelectedTracks, so that I can cross-compare + // at the end with central data member ebye.fSelectedTracks + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // *) If random access of tracks from collection is requested, use Fisher-Yates algorithm to generate random indices: + // Remark: It is very important that I use exactly the same random sequence from FY already generated in the MainLoop + if (tc.fUseFisherYates) { + if (!tc.fRandomIndices) { + LOGF(fatal, "\033[1;31m%s at line %d : I have to use here exactly the same random sequence from FY already generated in the MainLoopOverParticles, but it's not available \033[0m", __FUNCTION__, __LINE__); + } + } + + // *) Counter of selected tracks in the current event: + int lSelectedTracks = 0; // I could reset and reuse here ebye.fSelectedTracks, but it's safer to use separate local variable, as I can do additional insanity checks here + + // *) Banishment loop over particles: + // for (auto& track : tracks) { // default standard way of looping of tracks + auto track = tracks.iteratorAt(0); // set the type and scope from one instance + for (int64_t i = 0; i < tracks.size(); i++) { + + // *) Access track sequentially from collection of tracks (default), or randomly using Fisher-Yates algorithm: + if (!tc.fUseFisherYates) { + track = tracks.iteratorAt(i); + } else { + track = tracks.iteratorAt(static_cast(tc.fRandomIndices->GetAt(i))); + } + + // *) Skip track objects which are not valid tracks (e.g. Run 2 and 1 tracklets, etc.): + if (!ValidTrack(track)) { + continue; + } + + // *) Banish particle histograms before particle cuts: + // TBI 20240515 I banish for the time being only particle histograms AFTER particle cuts. + // If I start to banish here also particle histograms BEFORE particle cuts, then see if I have to do it also for event histograms BEFORE cuts. + // Event histograms AFTER cuts are not affected. + // if (ph.fFillParticleHistograms || ph.fFillParticleHistograms2D) { + // FillParticleHistograms(track, eBefore, -1); + // } + + // *) Particle cuts: + if (!ParticleCuts(track, eCut)) { // Main call for particle cuts. + continue; // not return!! + } + + // *) Banish particle histograms after particle cuts: + if (ph.fFillParticleHistograms || ph.fFillParticleHistograms2D || qa.fFillQAParticleHistograms2D) { + FillParticleHistograms(track, eAfter, -1); // with negative weight -1, I effectively remove the previous fill for this track + } + + // *) Increase the local selected particle counter: + lSelectedTracks++; + if (lSelectedTracks >= ec.fdEventCuts[eMultiplicity][eMax]) { + break; + } + + // *) Break the loop if fixed number of particles is taken randomly from each event (use always in combination with tc.fUseFisherYates = true): + if (tc.fFixedNumberOfRandomlySelectedTracks > 0 && tc.fFixedNumberOfRandomlySelectedTracks == lSelectedTracks) { + LOGF(info, "%s : Breaking the loop over particles, since requested fixed number of %d particles was reached", __FUNCTION__, tc.fFixedNumberOfRandomlySelectedTracks); + break; + } + + } // for (auto& track : tracks) + + // *) Quick insanity checks (mandatory!): + if (lSelectedTracks != ebye.fSelectedTracks) { + LOGF(fatal, "\033[1;31m%s at line %d : lSelectedTracks != ebye.fSelectedTracks , lSelectedTracks = %d, ebye.fSelectedTracks = %d\nDid you accidentally enable Toy NUA? \033[0m", __FUNCTION__, __LINE__, lSelectedTracks, ebye.fSelectedTracks); + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // template void BanishmentLoopOverParticles(T const& tracks) { + +//============================================================ + +void PrintCutCounterContent() +{ + // Prints on the screen content of fEventCutCounterHist[][] (all which were booked). + + // a) Insanity checks; + // b) Print or die. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Insanity checks: + if (!(ec.fUseEventCutCounterAbsolute || ec.fUseEventCutCounterSequential)) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + // b) Print or die: + for (int rs = 0; rs < 2; rs++) // reco/sim + { + for (int cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter + { + if (!(ec.fEventCutCounterHist[rs][cc])) { + continue; + } + LOGF(info, "\033[1;32m\nPrinting the content of event cut counter histogram %s\033[0m", ec.fEventCutCounterHist[rs][cc]->GetName()); + for (int bin = 1; bin <= ec.fEventCutCounterHist[rs][cc]->GetNbinsX(); bin++) { + if (TString(ec.fEventCutCounterHist[rs][cc]->GetXaxis()->GetBinLabel(bin)).EqualTo("TBI")) { // TBI 20240514 temporary workaround, "TBI" can't persist here + continue; + } + LOGF(info, "bin = %d => %s : %d", bin, ec.fEventCutCounterHist[rs][cc]->GetXaxis()->GetBinLabel(bin), static_cast(ec.fEventCutCounterHist[rs][cc]->GetBinContent(bin))); + } + } // for (int cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter + } // for (int rs = 0; rs < 2; rs++) // reco/sim + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void PrintCutCounterContent() + +//============================================================ + +void Trace(const char* functionName, int lineNumber) +{ + // A simple utility wrapper. Use only during debugging, sprinkle calls to this function here and there, as follows + // Trace(__FUNCTION__, __LINE__); + + LOGF(info, "\033[1;32m%s .... line %d\033[0m", functionName, lineNumber); + +} // void Trace(const char* functionName, int lineNumber) + +//============================================================ + +void Exit() +{ + // A simple utility wrapper. Used only during debugging. + // Use directly as: Exit(); + // Line number, function name, formatting, etc, are determinad automatically. + + LOGF(info, "\n\n\n\n\n\n\n\n\n\n"); + exit(1); + +} // void Exit() -} // void RandomIndices(Int_t nTracks) +//============================================================ + +void StartFunction(const char* functionName) +{ + // A simple utility wrapper, used when tc.fVerbose = true. It merely ensures uniform formatting of notification when the function starts. + + LOGF(info, "\033[1;32mStart %s\033[0m", functionName); // prints in green + +} // void StartFunction(const char* functionName) + +//============================================================ + +void ExitFunction(const char* functionName) +{ + // A simple utility wrapper, used when tc.fVerbose = true. It merely ensures uniform formatting of notification when the function exits. + + LOGF(info, "\033[1;32mExit %s\033[0m", functionName); // prints in green + +} // void ExitFunction(const char* functionName) //============================================================ -void BailOut() +void BailOut(bool finalBailout = false) { // Use only locally - bail out if maximum number of events was reached, and dump all results by that point in a local ROOT file. + // If fSequentialBailout > 0, bail out is performed each fSequentialBailout events, each time in a new local ROOT file. + // For sequential bailout, the naming scheme of ROOT files is AnalysisResultsBailOut_eh.fEventCounter[eProcessed].root . + // If ROOT file with the same name already exists, BailOut is not performed, since the argument is that + // it's pointless to perform Bailout for same eh.fEventCounter[eProcessed], even if eh.fEventCounter[eTotal] changed. + // Only if finalBailout = true, I will overwrite the existing file with the same name. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); } // *) Local variables: TBI 20240130 shall I promote 'em to data members + add support for configurables? TString sBailOutFile = "AnalysisResultsBailOut.root"; TString sDirectoryFile = "multiparticle-correlations-a-b"; + // *) For sequential bailout, I need to adapt the ROOT file name each time this function is called: + if (tc.fSequentialBailout > 0) { + sBailOutFile.ReplaceAll(".root", Form("_%d.root", eh.fEventCounter[eProcessed])); // replaces in-place + // basically, at 1st call "AnalysisResultsBailOut.root" => "AnalysisResultsBailOut_1*eh.fEventCounter[eProcessed].root", + // at 2nd call "AnalysisResultsBailOut.root" => "AnalysisResultsBailOut_2*eh.fEventCounter[eProcessed].root", etc. + if (!finalBailout && !gSystem->AccessPathName(sBailOutFile.Data(), kFileExists)) { // only for finalBailout = true, I will overwrite the existing file with the same name. + LOGF(info, "\033[1;33m\nsBailOutFile = %s already exits, that means that eh.fEventCounter[eProcessed] is the same as in the previous call of BailOut.\nJust skipping and waiting more events to pass selection criteria... \033[0m", sBailOutFile.Data()); + return; + } + } + // *) Info message: if (eh.fEventHistograms[eNumberOfEvents][eRec][eAfter]) { - LOGF(info, "\033[1;32m=> Per request, bailing out after %d selected events in the local file %s .\n\033[0m", (Int_t)eh.fEventHistograms[eNumberOfEvents][eRec][eAfter]->GetBinContent(1), sBailOutFile.Data()); + LOGF(info, "\033[1;32m=> Per request, bailing out after %d selected events in the local file %s .\n\033[0m", static_cast(eh.fEventHistograms[eNumberOfEvents][eRec][eAfter]->GetBinContent(1)), sBailOutFile.Data()); } // *) Okay, let's bail out intentionally: TFile* f = new TFile(sBailOutFile.Data(), "recreate"); TDirectoryFile* dirFile = new TDirectoryFile(sDirectoryFile.Data(), sDirectoryFile.Data()); - // TBI 20240130 I cannot add here fBaseList directtly, since that one is declared as OutputObj + // TBI 20240130 I cannot add here fBaseList directly, since that one is declared as OutputObj // Therefore, adding one-by-one nested TList's I want to bail out. // Keep in sync with BookAndNestAllLists(). TList* bailOutList = new TList(); // this is sort of 'fake' fBaseList - bailOutList->SetOwner(kTRUE); + bailOutList->SetOwner(false); // yes, beacause for sequential bailout, with SetOwner(true) the code is crashing after 1st sequential bailout is done bailOutList->SetName(sBaseListName.Data()); bailOutList->Add(fBasePro); // yes, this one needs a special treatment bailOutList->Add(qa.fQAList); - bailOutList->Add(eh.fEventHistogramsList); bailOutList->Add(ec.fEventCutsList); - bailOutList->Add(ph.fParticleHistogramsList); + bailOutList->Add(eh.fEventHistogramsList); bailOutList->Add(pc.fParticleCutsList); + bailOutList->Add(ph.fParticleHistogramsList); bailOutList->Add(qv.fQvectorList); bailOutList->Add(mupa.fCorrelationsList); bailOutList->Add(pw.fWeightsList); + bailOutList->Add(cw.fCentralityWeightsList); bailOutList->Add(nl.fNestedLoopsList); + bailOutList->Add(nua.fNUAList); + bailOutList->Add(iv.fInternalValidationList); bailOutList->Add(t0.fTest0List); + bailOutList->Add(es.fEtaSeparationsList); bailOutList->Add(res.fResultsList); - // *) Add list with nested list to TDirectoryFile: - dirFile->Add(bailOutList, kTRUE); - dirFile->Write(dirFile->GetName(), TObject::kSingleKey + TObject::kOverwrite); - delete dirFile; - dirFile = NULL; - f->Close(); + // *) Add list with nested list to TDirectoryFile: + dirFile->Add(bailOutList, true); + dirFile->Write(dirFile->GetName(), TObject::kSingleKey + TObject::kOverwrite); + delete dirFile; + dirFile = NULL; + f->Close(); + + if (tc.fVerbose && !(tc.fSequentialBailout > 0)) { // then it will be called only once, for the only and permanent bailout + ExitFunction(__FUNCTION__); + } + + // *) Hasta la vista: + if (finalBailout) { + LOGF(fatal, "\033[1;31mHasta la vista - bailed out permanently in function %s at line %d\n The output file is: %s\n\n\033[0m", __FUNCTION__, __LINE__, sBailOutFile.Data()); + } else { + LOGF(info, "\033[1;32mBailed out sequentially in function %s at line %d\n The output file is: %s\n\n\033[0m", __FUNCTION__, __LINE__, sBailOutFile.Data()); + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + } + +} // void BailOut(bool finalBailout = false) + +//============================================================ + +void FillQvector(const double& dPhi, const double& dPt, const double& dEta) +{ + // Fill integrated Q-vector. + // Example usage: this->FillQvector(dPhi, dPt, dEta); + + // TBI 20240430 I could optimize further, and have a bare version of this function when weights are NOT used. + // But since usage of weights amounts to checking a few simple booleans here, I do not anticipate any big gain in efficiency... + + if (tc.fVerboseForEachParticle) { + StartFunction(__FUNCTION__); + LOGF(info, "\033[1;32m dPhi = %f\033[0m", dPhi); + LOGF(info, "\033[1;32m dPt = %f\033[0m", dPt); + LOGF(info, "\033[1;32m dEta = %f\033[0m", dEta); + } + + // Particle weights: + double wPhi = 1.; // integrated phi weight + double wPt = 1.; // integrated pt weight + double wEta = 1.; // integrated eta weight + double wToPowerP = 1.; // weight raised to power p + + if (pw.fUseWeights[wPHI]) { + wPhi = Weight(dPhi, wPHI); + if (!(wPhi > 0.)) { + LOGF(error, "\033[1;33m%s wPhi is not positive\033[0m", __FUNCTION__); + LOGF(fatal, "dPhi = %f\nwPhi = %f", dPhi, wPhi); + } + } // if(pw.fUseWeights[wPHI]) + + if (pw.fUseWeights[wPT]) { + wPt = Weight(dPt, wPT); // corresponding pt weight + if (!(wPt > 0.)) { + LOGF(error, "\033[1;33m%s wPt is not positive\033[0m", __FUNCTION__); + LOGF(fatal, "dPt = %f\nwPt = %f", dPt, wPt); + } + } // if(pw.fUseWeights[wPT]) + + if (pw.fUseWeights[wETA]) { + wEta = Weight(dEta, wETA); // corresponding eta weight + if (!(wEta > 0.)) { + LOGF(error, "\033[1;33m%s wEta is not positive\033[0m", __FUNCTION__); + LOGF(fatal, "dEta = %f\nwEta = %f", dEta, wEta); + } + } // if(pw.fUseWeights[wETA]) + + if (qv.fCalculateQvectors) { + for (int h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { + for (int wp = 0; wp < gMaxCorrelator + 1; wp++) { // weight power + if (pw.fUseWeights[wPHI] || pw.fUseWeights[wPT] || pw.fUseWeights[wETA]) { + wToPowerP = pow(wPhi * wPt * wEta, wp); + qv.fQvector[h][wp] += TComplex(wToPowerP * TMath::Cos(h * dPhi), wToPowerP * TMath::Sin(h * dPhi)); // Q-vector with weights + } else { + qv.fQvector[h][wp] += TComplex(TMath::Cos(h * dPhi), TMath::Sin(h * dPhi)); // bare Q-vector without weights + } + } // for(int wp=0;wp 0.) { + for (int e = 0; e < gMaxNumberEtaSeparations; e++) { + if (dEta > es.fEtaSeparationsValues[e] / 2.) { // yes, if eta separation is 0.2, then separation interval runs from -0.1 to 0.1 + qv.fMab[1][e] += wPhi * wPt * wEta; + for (int h = 0; h < gMaxHarmonic; h++) { + { + if (es.fEtaSeparationsSkipHarmonics[h]) { + continue; + } + qv.fQabVector[1][h][e] += TComplex(wPhi * wPt * wEta * TMath::Cos((h + 1) * dPhi), wPhi * wPt * wEta * TMath::Sin((h + 1) * dPhi)); + } + } // for (int h = 0; h < gMaxHarmonic; h++) { + } // for (int e = 0; e < gMaxNumberEtaSeparations; e++) { // eta separation + } + } + } // if(es.fCalculateEtaSeparations) { + + if (tc.fVerboseForEachParticle) { + ExitFunction(__FUNCTION__); + } - // *) Hasta la vista: - LOGF(fatal, "\n\nHasta la vista - bailed out intentionally in function \033[1;31m%s at line %d\n The output file is: %s\n\n\033[0m", __PRETTY_FUNCTION__, __LINE__, sBailOutFile.Data()); +} // void FillQvector(const double& dPhi, const double& dPt, const double& dEta) + +//============================================================ + +void FillQvectorFromSparse(const double& dPhi, const double& dPt, const double& dEta, const double& dCharge) +{ + // Fill integrated Q-vector using sparse histograms. + + // Remark: I pass by reference particle quantities, while event quantities (centrality, vertex z, ...) I fetch from data members (or from global variables in a macro). + + // To do: + // 20250224 do I need to switch to this function also in InternalValidation()? I still use simple FillQvector() there. + // That would really make sense only after I add support for usage of particle weights in InternalValidation() + + if (tc.fVerboseForEachParticle) { + StartFunction(__FUNCTION__); + LOGF(info, "\033[1;32m dPhi = %f\033[0m", dPhi); + LOGF(info, "\033[1;32m dPt = %f\033[0m", dPt); + LOGF(info, "\033[1;32m dEta = %f\033[0m", dEta); + LOGF(info, "\033[1;32m dCharge = %f\033[0m", dCharge); + } + + // Particle weights from sparse histograms: + double wPhi = 1.; // differential multidimensional phi weight, its dimensions are defined via enum eDiffPhiWeights + double wPt = 1.; // differential multidimensional pt weight, its dimensions are defined via enum eDiffPtWeights + double wEta = 1.; // differential multidimensional eta weight, its dimensions are defined via enum eDiffEtaWeights + double wToPowerP = 1.; // weight raised to power p + + // *) Multidimensional phi weights: + if (pw.fUseDiffPhiWeights[wPhiPhiAxis]) { // yes, 0th axis serves as a comon boolean for this category + wPhi = WeightFromSparse(dPhi, dPt, dEta, dCharge, eDWPhi); + // last argument is enum eDiffWeightCategory. Event quantities, e.g. centraliy and vz, I do not need to pass, because + // for them I have ebye data members + if (!(wPhi > 0.)) { + LOGF(error, "\033[1;33m%s wPhi is not positive\033[0m", __FUNCTION__); + LOGF(error, "dPhi = %f", dPhi); + if (pw.fUseDiffPhiWeights[wPhiPtAxis]) { + LOGF(fatal, "dPt = %f", dPt); + } + if (pw.fUseDiffPhiWeights[wPhiEtaAxis]) { + LOGF(fatal, "dEta = %f", dEta); + } + if (pw.fUseDiffPhiWeights[wPhiChargeAxis]) { + LOGF(fatal, "dCharge = %f", dCharge); + } + if (pw.fUseDiffPhiWeights[wPhiCentralityAxis]) { + LOGF(fatal, "ebye.Centrality = %f", ebye.fCentrality); + } + if (pw.fUseDiffPhiWeights[wPhiVertexZAxis]) { + LOGF(fatal, "ebye.Vz = %f", ebye.fVz); + } + LOGF(fatal, "Multidimensional weight for enabled dimensions is wPhi = %f", wPhi); + } + } // if(pw.fUseDiffPhiWeights[wPhiPhiAxis]) + + // *) Multidimensional pt weights: + if (pw.fUseDiffPtWeights[wPtPtAxis]) { // yes, 0th axis serves as a comon boolean for this category + wPt = WeightFromSparse(dPhi, dPt, dEta, dCharge, eDWPt); // TBI 20250224 not sure if this is the right/best approach + // last argument is enum eDiffWeightCategory. Event quantities, e.g. centraliy and vz, I do not need to pass, because + // for them I have ebye data members + if (!(wPt > 0.)) { + LOGF(error, "\033[1;33m%s wPt is not positive\033[0m", __FUNCTION__); + LOGF(error, "dPt = %f", dPt); + if (pw.fUseDiffPtWeights[wPtPtAxis]) { + LOGF(fatal, "dPt = %f", dPt); + } + LOGF(fatal, "Multidimensional weight for enabled dimensions is wPt = %f", wPt); + } + } // if(pw.fUseDiffPtWeights[wPtPtAxis]) + + // *) Multidimensional eta weights: + if (pw.fUseDiffEtaWeights[wEtaEtaAxis]) { // yes, 0th axis serves as a comon boolean for this category + wEta = WeightFromSparse(dPhi, dPt, dEta, dCharge, eDWEta); // TBI 20250224 not sure if this is the right/best approach + // last argument is enum eDiffWeightCategory. Event quantities, e.g. centraliy and vz, I do not need to pass, because + // for them I have ebye data members + if (!(wEta > 0.)) { + LOGF(error, "\033[1;33m%s wEta is not positive\033[0m", __FUNCTION__); + LOGF(error, "dEta = %f", dEta); + if (pw.fUseDiffEtaWeights[wEtaEtaAxis]) { + LOGF(fatal, "dEta = %f", dEta); + } + LOGF(fatal, "Multidimensional weight for enabled dimensions is wEta = %f", wEta); + } + } // if(pw.fUseDiffEtaWeights[wEtaEtaAxis]) + + if (qv.fCalculateQvectors) { + for (int h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { + for (int wp = 0; wp < gMaxCorrelator + 1; wp++) { // weight power + if (pw.fUseDiffPhiWeights[wPhiPhiAxis] || pw.fUseDiffPtWeights[wPtPtAxis] || pw.fUseDiffEtaWeights[wEtaEtaAxis]) { + wToPowerP = pow(wPhi * wPt * wEta, wp); + qv.fQvector[h][wp] += TComplex(wToPowerP * TMath::Cos(h * dPhi), wToPowerP * TMath::Sin(h * dPhi)); // Q-vector with weights + } else { + qv.fQvector[h][wp] += TComplex(TMath::Cos(h * dPhi), TMath::Sin(h * dPhi)); // bare Q-vector without weights + } + } // for(int wp=0;wp 0.) { + for (int e = 0; e < gMaxNumberEtaSeparations; e++) { + if (dEta > es.fEtaSeparationsValues[e] / 2.) { // yes, if eta separation is 0.2, then separation interval runs from -0.1 to 0.1 + qv.fMab[1][e] += wPhi * wPt * wEta; + for (int h = 0; h < gMaxHarmonic; h++) { + { + if (es.fEtaSeparationsSkipHarmonics[h]) { + continue; + } + qv.fQabVector[1][h][e] += TComplex(wPhi * wPt * wEta * TMath::Cos((h + 1) * dPhi), wPhi * wPt * wEta * TMath::Sin((h + 1) * dPhi)); + } + } // for (int h = 0; h < gMaxHarmonic; h++) { + } // for (int e = 0; e < gMaxNumberEtaSeparations; e++) { // eta separation + } + } + } // if(es.fCalculateEtaSeparations) { + + if (tc.fVerboseForEachParticle) { + ExitFunction(__FUNCTION__); + } -} // void BailOut() +} // void FillQvectorFromSparse(const double& dPhi, const double& dPt, const double& dEta, const double& dCharge) //============================================================ -void Fillqvector(const Double_t& dPhi, const Double_t& kineVarValue, eqvectorKine kineVarChoice) +void Fillqvector(const double& dPhi, const double& kineVarValue, eqvectorKine kineVarChoice, const double& dEta = 0.) { // Fill differential q-vector, in generic kinematic variable. Here "kine" originally meant vs. pt or vs. eta, now it's general. - // Example usage: this->Fillqvector(dPhi, dPt, PTq); + // Example usage #1: this->Fillqvector(dPhi, dPt, PTq); // differential q-vectors without using eta separations + // Example usage #2: this->Fillqvector(dPhi, dPt, PTq, dEta); // differential q-vectors with using eta separations (I need dEta of particle to decide whether particle is added to qa or qb) if (tc.fVerboseForEachParticle) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); + StartFunction(__FUNCTION__); } // *) Mapping between enum's "eqvectorKine" on one side, and "eAsFunctionOf", "eWeights" and "eDiffWeights" on the other: // TBI 20240212 I could promote this also to a member function, if I need it elsewhere. Or I could use TExMap? - Int_t AFO_var = -1; // this local variable determines the enum "eAsFunctionOf" which corresponds to enum "eqvectorKine" - Int_t AFO_weight = -1; // this local variable determined the enum "eWeights" which corresponds to enum "eqvectorKine" - Int_t AFO_diffWeight = -1; // this local variable determines the enum "eDiffWeights" which corresponds to enum "eqvectorKine" - TString AFO_name = ""; // TBI 20240212 most likely, I won't need this one in the final version + eAsFunctionOf AFO_var = eAsFunctionOf_N; // this local variable determines the enum "eAsFunctionOf" which corresponds to enum "eqvectorKine" + eWeights AFO_weight = eWeights_N; // this local variable determines the enum "eWeights" which corresponds to enum "eqvectorKine" + eDiffWeights AFO_diffWeight = eDiffWeights_N; // this local variable determines the enum "eDiffWeights" which corresponds to enum "eqvectorKine" switch (kineVarChoice) { - case PTq: + case PTq: { AFO_var = AFO_PT; AFO_weight = wPT; AFO_diffWeight = wPHIPT; - AFO_name = "pt"; break; - case ETAq: + } + case ETAq: { AFO_var = AFO_ETA; AFO_weight = wETA; AFO_diffWeight = wPHIETA; - AFO_name = "eta"; break; - default: - LOGF(fatal, "in function \033[1;31m%s at line %d. This kineVarChoice = %d is not supported yet. \033[0m", __PRETTY_FUNCTION__, __LINE__, (Int_t)kineVarChoice); + } + default: { + LOGF(fatal, "\033[1;31m%s at line %d : this kineVarChoice = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, static_cast(kineVarChoice)); break; + } } // switch(kineVarChoice) + // *) Insanity checks on above settings: + if (AFO_var == eAsFunctionOf_N) { + LOGF(fatal, "\033[1;31m%s at line %d : AFO_var == eAsFunctionOf_N => add some more entries to the case statement \033[0m", __FUNCTION__, __LINE__); + } + if (AFO_weight == eWeights_N) { + LOGF(fatal, "\033[1;31m%s at line %d : AFO_weight == eWeights_N => add some more entries to the case statement \033[0m", __FUNCTION__, __LINE__); + } + if (AFO_diffWeight == eDiffWeights_N) { + LOGF(fatal, "\033[1;31m%s at line %d : AFO_diffWeight == eDiffWeights_N => add some more entries to the case statement \033[0m", __FUNCTION__, __LINE__); + } + // *) Get the desired bin number: - Int_t bin = -1; + int bin = -1; if (res.fResultsPro[AFO_var]) { - bin = res.fResultsPro[AFO_var]->FindBin(kineVarValue); + bin = res.fResultsPro[AFO_var]->FindBin(kineVarValue); // this 'bin' starts from 1, i.e. this is genuine histogram bin if (0 >= bin || res.fResultsPro[AFO_var]->GetNbinsX() < bin) { // either underflow or overflow is hit, meaning that histogram is booked in narrower range than cuts - LOGF(fatal, "in function \033[1;31m%s at line %d => kineVarChoice = %d, bin = %d, kineVarValue = %f \033[0m", __PRETTY_FUNCTION__, __LINE__, (Int_t)kineVarChoice, bin, kineVarValue); + LOGF(fatal, "\033[1;31m%s at line %d : kineVarChoice = %d, bin = %d, kineVarValue = %f \033[0m", __FUNCTION__, __LINE__, static_cast(kineVarChoice), bin, kineVarValue); } } // *) Get all integrated kinematic weights: - Double_t wToPowerP = 1.; // weight raised to power p - Double_t kineVarWeight = 1.; // e.g. this can be integrated pT or eta weight + double wToPowerP = 1.; // weight raised to power p + double kineVarWeight = 1.; // e.g. this can be integrated pT or eta weight if (pw.fUseWeights[AFO_weight]) { - kineVarWeight = Weight(kineVarValue, AFO_name.Data()); // corresponding e.g. pt or eta weight + kineVarWeight = Weight(kineVarValue, AFO_weight); // corresponding e.g. pt or eta weight if (!(kineVarWeight > 0.)) { - LOGF(fatal, "in function \033[1;31m%s at line %d. kineVarWeight is not positive \033[0m", __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d : kineVarWeight is not positive \033[0m", __FUNCTION__, __LINE__); // TBI 20240212 or could I just skip this particle? } } // if(fUseWeights[AFO_weight]) { // *) Get all differential phi-weights for this kinematic variable: // Remark: special treatment is justified for phi-weights, because q-vector is defined in terms of phi-weights. - Double_t diffPhiWeightsForThisKineVar = 1.; + double diffPhiWeightsForThisKineVar = 1.; if (pw.fUseDiffWeights[AFO_diffWeight]) { - diffPhiWeightsForThisKineVar = DiffWeight(dPhi, kineVarValue, AFO_name.Data()); // corresponding differential phi weight as a function of e.g. pt or eta + diffPhiWeightsForThisKineVar = DiffWeight(dPhi, kineVarValue, kineVarChoice); // corresponding differential phi weight as a function of e.g. pt or eta if (!(diffPhiWeightsForThisKineVar > 0.)) { - LOGF(fatal, "in function \033[1;31m%s at line %d. diffPhiWeightsForThisKineVar is not positive \033[0m", __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d : diffPhiWeightsForThisKineVar is not positive \033[0m", __FUNCTION__, __LINE__); // TBI 20240212 or could I just skip this particle? } } // if(pw.fUseDiffWeights[AFO_diffWeight]) { // *) Finally, fill differential q-vector in that bin: - for (Int_t h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { - for (Int_t wp = 0; wp < gMaxCorrelator + 1; wp++) { // weight power + for (int h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { + for (int wp = 0; wp < gMaxCorrelator + 1; wp++) { // weight power if (pw.fUseWeights[AFO_weight] || pw.fUseDiffWeights[AFO_diffWeight]) { - wToPowerP = pow(diffPhiWeightsForThisKineVar * kineVarWeight, wp); // TBI 20240212 supported at the moment: e.g. q-vector vs pt can be weighted only with diff. phi(pt) and integrated pt weights. It cannot be weighted in addition with eta weights, since in any case I anticipate I will do always 1-D analysis, by integrating out all other dependencies + // TBI 20240212 supported at the moment: e.g. q-vector vs pt can be weighted only with diff. phi(pt) and integrated pt weights. + // It cannot be weighted in addition with eta weights, since in any case I anticipate I will do always 1-D analysis, by integrating out all other dependencies + wToPowerP = pow(diffPhiWeightsForThisKineVar * kineVarWeight, wp); + qv.fqvector[kineVarChoice][bin - 1][h][wp] += TComplex(wToPowerP * TMath::Cos(h * dPhi), wToPowerP * TMath::Sin(h * dPhi)); // q-vector with weights + } else { + qv.fqvector[kineVarChoice][bin - 1][h][wp] += TComplex(TMath::Cos(h * dPhi), TMath::Sin(h * dPhi)); // bare q-vector without weights } - qv.fqvector[kineVarChoice][bin - 1][h][wp] += TComplex(wToPowerP * TMath::Cos(h * dPhi), wToPowerP * TMath::Sin(h * dPhi)); - } // for(Int_t wp=0;wpAddAt(dPhi,fqVectorEntries[PTq][bin-1]); - ftaNestedLoopsKine[PTq][bin-1][1]->AddAt(wPhi*wPt*wEta,fqVectorEntries[PTq][bin-1]); + // *) Differential nested loops: + if (nl.fCalculateKineCustomNestedLoops) { + nl.ftaNestedLoopsKine[kineVarChoice][bin - 1][0]->AddAt(dPhi, qv.fqVectorEntries[kineVarChoice][bin - 1]); + nl.ftaNestedLoopsKine[kineVarChoice][bin - 1][1]->AddAt(diffPhiWeightsForThisKineVar * kineVarWeight, qv.fqVectorEntries[kineVarChoice][bin - 1]); } - */ // *) Multiplicity counter in this bin: qv.fqVectorEntries[kineVarChoice][bin - 1]++; // count number of particles in this pt bin in this event -} // void Fillqvector(const Double_t &dPhi, const Double_t &kineVarValue, eqvectorKine kineVarChoice) + // *) Usage of eta separations in differential correlations: + if (es.fCalculateEtaSeparations && es.fCalculateEtaSeparationsAsFunctionOf[AFO_var]) { // yes, I can decouple this one from if (qv.fCalculateQvectors) + + if (AFO_var == AFO_ETA) { + LOGF(fatal, "\033[1;31m%s at line %d : AFO_var == AFO_ETA . This doesn't make any sense in this context. \033[0m", __FUNCTION__, __LINE__); + } + + if (dEta < 0.) { + for (int e = 0; e < gMaxNumberEtaSeparations; e++) { + if (dEta < -1. * es.fEtaSeparationsValues[e] / 2.) { // yes, if eta separation is 0.2, then separation interval runs from -0.1 to 0.1 + qv.fmab[0][bin - 1][e] += diffPhiWeightsForThisKineVar * kineVarWeight; // Remark: I can hardwire linear weight like this only for 2-p correlation + for (int h = 0; h < gMaxHarmonic; h++) { + if (es.fEtaSeparationsSkipHarmonics[h]) { + continue; + } + qv.fqabVector[0][bin - 1][h][e] += TComplex(diffPhiWeightsForThisKineVar * kineVarWeight * TMath::Cos((h + 1) * dPhi), diffPhiWeightsForThisKineVar * kineVarWeight * TMath::Sin((h + 1) * dPhi)); // Remark: I can hardwire linear weight like this only for 2-p correlation + } + } // for (int h = 0; h < gMaxHarmonic; h++) { + } // for (int e = 0; e < gMaxNumberEtaSeparations; e++) { // eta separation + } else if (dEta > 0.) { + for (int e = 0; e < gMaxNumberEtaSeparations; e++) { + if (dEta > es.fEtaSeparationsValues[e] / 2.) { // yes, if eta separation is 0.2, then separation interval runs from -0.1 to 0.1 + qv.fmab[1][bin - 1][e] += diffPhiWeightsForThisKineVar * kineVarWeight; // Remark: I can hardwire linear weight like this only for 2-p correlation + for (int h = 0; h < gMaxHarmonic; h++) { + { + if (es.fEtaSeparationsSkipHarmonics[h]) { + continue; + } + qv.fqabVector[1][bin - 1][h][e] += TComplex(diffPhiWeightsForThisKineVar * kineVarWeight * TMath::Cos((h + 1) * dPhi), diffPhiWeightsForThisKineVar * kineVarWeight * TMath::Sin((h + 1) * dPhi)); // Remark: I can hardwire linear weight like this only for 2-p correlation + } + } // for (int h = 0; h < gMaxHarmonic; h++) { + } // for (int e = 0; e < gMaxNumberEtaSeparations; e++) { // eta separation + } + } + } // if(es.fCalculateEtaSeparations) { + + if (tc.fVerboseForEachParticle) { + ExitFunction(__FUNCTION__); + } + +} // void Fillqvector(const double& dPhi, const double& kineVarValue, eqvectorKine kineVarChoice) //============================================================ @@ -4626,134 +14913,102 @@ void CalculateEverything() // Remark: Data members for Q-vectors, containers for nested loops, etc., must all be filled when this function is called. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); - } - - // *) Progress info: - if (eh.fEventHistograms[eNumberOfEvents][eRec][eBefore] && eh.fEventHistograms[eNumberOfEvents][eRec][eAfter]) { - LOGF(info, "\033[1;32m=> Processing event %d/%d (selected/total) .... \033[0m", (Int_t)eh.fEventHistograms[eNumberOfEvents][eRec][eAfter]->GetBinContent(1), (Int_t)eh.fEventHistograms[eNumberOfEvents][eRec][eBefore]->GetBinContent(1)); + StartFunction(__FUNCTION__); } // *) Calculate multiparticle correlations (standard, isotropic, same harmonic): - if (mupa.fCalculateCorrelations) { + if (qv.fCalculateQvectors && mupa.fCalculateCorrelations) { this->CalculateCorrelations(); } + // *) Calculate differential ("kine") multiparticle correlations: + // Remark: vs. pt, vs. eta, etc., are all calculated here + if (qv.fCalculateQvectors && mupa.fCalculateCorrelationsAsFunctionOf[AFO_PT]) { + this->CalculateKineCorrelations(AFO_PT); + } + if (qv.fCalculateQvectors && mupa.fCalculateCorrelationsAsFunctionOf[AFO_ETA]) { + this->CalculateKineCorrelations(AFO_ETA); + } + // *) Calculate Test0: TBI 20240110 name convention // Remark: integrated, vs. M and vs. centrality are all calculated here - if (t0.fCalculateTest0) { + if (qv.fCalculateQvectors && t0.fCalculateTest0) { this->CalculateTest0(); } // *) Calculate kine Test0: TBI 20240110 name convention // Remark: vs. pt, vs. eta, etc., are all calculated here - if (t0.fCalculateTest0AsFunctionOf[AFO_PT]) { - this->CalculateKineTest0("pt"); + if (qv.fCalculateQvectors && t0.fCalculateTest0AsFunctionOf[AFO_PT]) { + this->CalculateKineTest0(AFO_PT); } - if (t0.fCalculateTest0AsFunctionOf[AFO_ETA]) { - this->CalculateKineTest0("eta"); + if (qv.fCalculateQvectors && t0.fCalculateTest0AsFunctionOf[AFO_ETA]) { + this->CalculateKineTest0(AFO_ETA); } // *) Calculate nested loops: if (nl.fCalculateNestedLoops) { this->CalculateNestedLoops(); - this->ComparisonNestedLoopsVsCorrelations(); // I call it here, so comparison is performed cumulatively after each event. The final printout corresponds to all events. + if (mupa.fCalculateCorrelations) { + // I do not have option here for Test0, because in Test0 I cross-check either e-by-e with CustomNestedLoops or + // for all events with IV + fRescaleWithTheoreticalInput = true + this->ComparisonNestedLoopsVsCorrelations(); // I call it here, so comparison is performed cumulatively after each event. The final printout corresponds to all events. + } } -} // void CalculateEverything() - -//============================================================ - -template -void Steer(T1 const& collision, T2 const& tracks) -{ - // This is the only function to be called in processRec(...), processRecSim(...), and processSim(...). - // All analysis workflow is defined step-by-step here, via dedicated function calls. - // The order of function calls obviously matters. - - if (tc.fDryRun) { - LOGF(info, "\033[1;32m%s => This is a dry run, bailing out immediately from Steer(...)\033[0m", __FUNCTION__); - return; + // *) Calculate correlations with eta separations: + if (es.fCalculateEtaSeparations) { + this->CalculateEtaSeparations(); + if (es.fCalculateEtaSeparationsAsFunctionOf[AFO_PT]) { + this->CalculateKineEtaSeparations(AFO_PT); // The implementation of CalculateKineEtaSeparations( ... ) is generic and can be used for any other "kine" variable, for which it makes sense + } } if (tc.fVerbose) { - // LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); // full function signature (including arguments, etc.), too verbose here... - LOGF(info, "\033[1;32m%s starting ...\033[0m", __FUNCTION__); // just a bare function name + ExitFunction(__FUNCTION__); } - // *) Global timestamp: - if (tc.fUseStopwatch) { - LOGF(info, "\033[1;32m\n\n=> Global timer: Steer begins ... %.6f\n\n\033[0m", tc.fTimer[eGlobal]->RealTime()); - tc.fTimer[eGlobal]->Continue(); // yes - } +} // void CalculateEverything() - // *) Do all thingies before starting to process data from this collision (e.g. count number of events, fetch the run number, etc.): - Preprocess(collision); +//============================================================ - // *) Determine collision centrality: - DetermineCentrality(collision); +void SkipThisRun() +{ + // Skip or not the current run from furher processing. - // *) Fill event histograms before event cuts: - FillEventHistograms(collision, tracks, eBefore); + // a) Insanity checks; + // b) Do the check. - // *) Print info on the current event number (total, before cuts): if (tc.fVerbose) { - if (eh.fEventHistograms[eNumberOfEvents][eRec][eBefore]) { - LOGF(info, "\033[1;32m%s : processing event %d\033[0m", __FUNCTION__, (Int_t)eh.fEventHistograms[eNumberOfEvents][eRec][eBefore]->GetBinContent(1)); - } else if (eh.fEventHistograms[eNumberOfEvents][eSim][eBefore]) { - LOGF(info, "\033[1;32m%s : processing event %d\033[0m", __FUNCTION__, (Int_t)eh.fEventHistograms[eNumberOfEvents][eSim][eBefore]->GetBinContent(1)); - } + StartFunction(__FUNCTION__); } - - // *) Event cuts: - if (!EventCuts(collision, tracks)) { - return; + // a) Insanity checks: + if (tc.fRunNumber.EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : tc.fRunNumber is empty. In case you are running something on-the-fly, empty the string fSkipTheseRuns .\033[0m", __FUNCTION__, __LINE__); } - // *) Main loop over particles: - MainLoopOverParticles(tracks); + // TBI 20250516 Shall I implement some insanity check on fSkipTheseRuns? I commented in configurable that the format is comma-separated list of runs, + // but I am nowhere really enforcing that... - // *) Remaining event cuts which can be applied only after the loop over particles is performed: - if ((ebye.fSelectedTracks < eh.fEventCuts[eSelectedTracks][eMin]) || (ebye.fSelectedTracks > eh.fEventCuts[eSelectedTracks][eMax])) { - if (tc.fVerbose) { - LOGF(info, "\033[1;31m%s eSelectedTracks\033[0m", __FUNCTION__); // just a bare function name - } - ResetEventByEventQuantities(); - return; + // b) Do the check: + if (tc.fSkipTheseRuns.Contains(tc.fRunNumber.Data())) { + // TBI 20250316 I think this check is safe enough. If not, tokenize fSkipTheseRuns with respect to "," etc. + tc.fSkipRun = true; + } else { + tc.fSkipRun = false; } - // *) Fill event histograms after event AND particle cuts: // TBI 20240110 not sure still if this one is called here, or it has to be moved above - FillEventHistograms(collision, tracks, eAfter); - - // *) Calculate everything for selected events and particles: - CalculateEverything(); - - // *) Reset event-by-event quantities: - ResetEventByEventQuantities(); - - // *) Print info on the current event number after cuts: if (tc.fVerbose) { - if (eh.fEventHistograms[eNumberOfEvents][eRec][eBefore]) { - LOGF(info, "\033[1;32m%s : this event passed all cuts %d/%d\033[0m", __FUNCTION__, (Int_t)eh.fEventHistograms[eNumberOfEvents][eRec][eAfter]->GetBinContent(1), (Int_t)eh.fEventHistograms[eNumberOfEvents][eRec][eBefore]->GetBinContent(1)); - } else if (eh.fEventHistograms[eNumberOfEvents][eSim][eBefore]) { - LOGF(info, "\033[1;32m%s : this event passed all cuts %d/%d\033[0m", __FUNCTION__, (Int_t)eh.fEventHistograms[eNumberOfEvents][eSim][eAfter]->GetBinContent(1), (Int_t)eh.fEventHistograms[eNumberOfEvents][eSim][eBefore]->GetBinContent(1)); - } - } - - // *) Global timestamp: - if (tc.fUseStopwatch) { - LOGF(info, "\033[1;32m\n\n=> Global timer: Steer ends ... %.6f\n\n\033[0m", tc.fTimer[eGlobal]->RealTime()); - tc.fTimer[eGlobal]->Continue(); // yes + ExitFunction(__FUNCTION__); } -} // template void Steer(T1 const* collision, T2 const* tracks) +} // void SkipThisRun() //============================================================ template void MainLoopOverParticles(T const& tracks) { - // This is the main loop over particles, in which Q-vectors and particle histograms are filled, particle cuts applied, etc. + // This is the main loop over particles, in which Q-vectors (both integrated and differential) and particle histograms are filled, particle cuts applied, etc. // Remark #1: // *) To process only reconstructed Run 3, use processRec(...), i.e. set field "processRec": "true" in json config @@ -4766,32 +15021,32 @@ void MainLoopOverParticles(T const& tracks) // Remark #3: // *) There is also processTest(...), to process data with minimum subscription to the tables. To use it, set field "processTest": "true" in json config + // Remark #4: + // *) There is also processQA(...), to process data with maximum subscription to the tables (use for Run 3 only). To use it, set field "processQA: "true" in json config + if (tc.fVerbose) { - // LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__); // full function signature (including arguments, etc.), too verbose here... - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); // just a bare function name + StartFunction(__FUNCTION__); } - // *) Local kinematic variables and corresponding particle weights: - Double_t dPhi = 0., wPhi = 1.; // azimuthal angle and corresponding phi weight - Double_t dPt = 0., wPt = 1.; // transverse momentum and corresponding pt weight - Double_t dEta = 0., wEta = 1.; // pseudorapidity and corresponding eta weight - Double_t wToPowerP = 1.; // weight raised to power p - ebye.fSelectedTracks = 0; // reset number of selected tracks + // *) Declare local kinematic variables: + double dPhi = 0.; // azimuthal angle + double dPt = 0.; // transverse momentum + double dEta = 0.; // pseudorapidity // *) If random access of tracks from collection is requested, use Fisher-Yates algorithm to generate random indices: if (tc.fUseFisherYates) { if (tc.fRandomIndices) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } this->RandomIndices(tracks.size()); if (!tc.fRandomIndices) { - LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } } // *) Local timestamp: - if (tc.fUseStopwatch) { - LOGF(info, "\033[1;32m\n\n=> Local timer starts at line %d\n\n\033[0m", __LINE__); + if (tc.fUseStopwatch && tc.fVerboseUtility) { + LOGF(info, " Local timer starts at line %d", __LINE__); tc.fTimer[eLocal]->Reset(); tc.fTimer[eLocal]->Start(); } @@ -4801,107 +15056,96 @@ void MainLoopOverParticles(T const& tracks) auto track = tracks.iteratorAt(0); // set the type and scope from one instance for (int64_t i = 0; i < tracks.size(); i++) { - // *) Skip track objects which are not valid tracks (e.g. Run 2 and 1 tracklets, etc.): - if (!ValidTrack(track)) { - continue; - } - // *) Access track sequentially from collection of tracks (default), or randomly using Fisher-Yates algorithm: if (!tc.fUseFisherYates) { track = tracks.iteratorAt(i); } else { - track = tracks.iteratorAt((int64_t)tc.fRandomIndices->GetAt(i)); + track = tracks.iteratorAt(static_cast(tc.fRandomIndices->GetAt(i))); + } + + // *) Skip track objects which are not valid tracks (e.g. Run 2 and 1 tracklets, etc.): + if (!ValidTrack(track)) { + continue; } // *) Fill particle histograms before particle cuts: - FillParticleHistograms(track, eBefore); + if (ph.fFillParticleHistograms || ph.fFillParticleHistograms2D || qa.fFillQAParticleHistograms2D) { + FillParticleHistograms(track, eBefore); + } + + // *) Particle cuts counters (use only during QA, as this is computationally heavy): + if (pc.fUseParticleCutCounterAbsolute || pc.fUseParticleCutCounterSequential) { + ParticleCutsCounters(track); + } // *) Particle cuts: - if (!ParticleCuts(track)) { - continue; + if (!ParticleCuts(track, eCut)) { // Main call for event cuts. + continue; // not return!! } // *) Fill particle histograms after particle cuts: - FillParticleHistograms(track, eAfter); + if (ph.fFillParticleHistograms || ph.fFillParticleHistograms2D || qa.fFillQAParticleHistograms2D) { + FillParticleHistograms(track, eAfter); + } - // *) Fill Q-vectors: - // Kinematics (Remark: for "eRecSim" processing, kinematics is taken from "reconstructed"): + // *) Intitialize local kinematic variables: + // Remark: for "eRecSim" processing, kinematics is taken from "reconstructed". dPhi = track.phi(); dPt = track.pt(); dEta = track.eta(); - // Particle weights: - if (pw.fUseWeights[wPHI]) { - wPhi = Weight(dPhi, "phi"); // corresponding phi weight - if (!(wPhi > 0.)) { - LOGF(error, "\033[1;33m%s wPhi is not positive, skipping this particle for the time being...\033[0m", __PRETTY_FUNCTION__); - LOGF(error, "dPhi = %f\nwPhi = %f", dPhi, wPhi); - continue; - } - } // if(pw.fUseWeights[wPHI]) - if (pw.fUseWeights[wPT]) { - wPt = Weight(dPt, "pt"); // corresponding pt weight - if (!(wPt > 0.)) { - LOGF(error, "\033[1;33m%s wPt is not positive, skipping this particle for the time being...\033[0m", __PRETTY_FUNCTION__); - LOGF(error, "dPt = %f\nwPt = %f", dPt, wPt); - continue; - } - } // if(pw.fUseWeights[wPT]) - if (pw.fUseWeights[wETA]) { - wEta = Weight(dEta, "eta"); // corresponding eta weight - if (!(wEta > 0.)) { - LOGF(error, "\033[1;33m%s wEta is not positive, skipping this particle for the time being...\033[0m", __PRETTY_FUNCTION__); - LOGF(error, "dEta = %f\nwEta = %f", dEta, wEta); - continue; + // Remark: Keep in sync all calls and flags below with the ones in InternalValidation(). + // *) Integrated Q-vectors: + if (qv.fCalculateQvectors || es.fCalculateEtaSeparations) { + if (!(pw.fUseDiffPhiWeights[wPhiPhiAxis] || pw.fUseDiffPtWeights[wPtPtAxis] || pw.fUseDiffPtWeights[wEtaEtaAxis])) { + // legacy integrated weights: + this->FillQvector(dPhi, dPt, dEta); // all 3 arguments are passed by reference + } else { + // this is now the new approach, with sparse histograms: + this->FillQvectorFromSparse(dPhi, dPt, dEta, track.sign()); // particle arguments are passed by reference. + // Event observables (centrality, vertex z, ...), I do not need to pass as arguments, + // as I have data members for them (ebye.fCentrality, ebye.Vz, ...) } - } // if(pw.fUseWeights[wETA]) - - if (qv.fCalculateQvectors) { - for (Int_t h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { - for (Int_t wp = 0; wp < gMaxCorrelator + 1; wp++) { // weight power - if (pw.fUseWeights[wPHI] || pw.fUseWeights[wPT] || pw.fUseWeights[wETA]) { - wToPowerP = pow(wPhi * wPt * wEta, wp); - } - qv.fQvector[h][wp] += TComplex(wToPowerP * TMath::Cos(h * dPhi), wToPowerP * TMath::Sin(h * dPhi)); - } // for(Int_t wp=0;wpAddAt(dPhi, ebye.fSelectedTracks); - } // remember that the 2nd argument here must start from 0 - if (nl.ftaNestedLoops[1]) { - nl.ftaNestedLoops[1]->AddAt(wPhi * wPt * wEta, ebye.fSelectedTracks); - } // remember that the 2nd argument here must start from 0 - } // if(nl.fCalculateNestedLoops || nl.fCalculateCustomNestedLoop) + } // *) Differential q-vectors: - if (qv.fCalculateQvectors && t0.fCalculateTest0AsFunctionOf[AFO_PT]) { + // **) pt-dependence: + if (qv.fCalculateQvectors && (mupa.fCalculateCorrelationsAsFunctionOf[AFO_PT] || t0.fCalculateTest0AsFunctionOf[AFO_PT]) && !es.fCalculateEtaSeparations) { + // In this branch I do not need eta separation, so the lighter call can be executed: this->Fillqvector(dPhi, dPt, PTq); // first 2 arguments are passed by reference, 3rd argument is enum + } else if (es.fCalculateEtaSeparations && es.fCalculateEtaSeparationsAsFunctionOf[AFO_PT]) { + // In this branch I do need eta separation, so the heavier call must be executed: + // Remark: Within Fillqvector() I check again all the relevant flags. + this->Fillqvector(dPhi, dPt, PTq, dEta); // first 2 arguments and the last one are passed by reference, 3rd argument is enum. "kine" variable is the 2nd argument } - if (qv.fCalculateQvectors && t0.fCalculateTest0AsFunctionOf[AFO_ETA]) { + // **) eta-dependence: + if (qv.fCalculateQvectors && (mupa.fCalculateCorrelationsAsFunctionOf[AFO_ETA] || t0.fCalculateTest0AsFunctionOf[AFO_ETA])) { + // Remark: For eta dependence I do not consider es.fCalculateEtaSeparations, because in this context that calculation is meaningless. this->Fillqvector(dPhi, dEta, ETAq); // first 2 arguments are passed by reference, 3rd argument is enum } + // *) Fill nested loops containers: + if (nl.fCalculateNestedLoops || nl.fCalculateCustomNestedLoops) { + this->FillNestedLoopsContainers(ebye.fSelectedTracks, dPhi, dPt, dEta); // all 4 arguments are passed by reference + } + // *) Counter of selected tracks in the current event: ebye.fSelectedTracks++; - if (ebye.fSelectedTracks >= cSelectedTracks_max) { + if (ebye.fSelectedTracks >= ec.fdEventCuts[eMultiplicity][eMax]) { break; } - // *) Break the loop if fixed number of particles is taken randomly from each event (use always in combination with tc.fUseFisherYates = kTRUE): + // *) Break the loop if fixed number of particles is taken randomly from each event (use always in combination with tc.fUseFisherYates = true): if (tc.fFixedNumberOfRandomlySelectedTracks > 0 && tc.fFixedNumberOfRandomlySelectedTracks == ebye.fSelectedTracks) { - LOGF(info, "\033[1;32mBreaking the loop over particles, since requested fixed number of %d particles was reached\033[0m", tc.fFixedNumberOfRandomlySelectedTracks); + LOGF(info, "%s : Breaking the loop over particles, since requested fixed number of %d particles was reached", __FUNCTION__, tc.fFixedNumberOfRandomlySelectedTracks); break; } } // for (auto& track : tracks) // *) Local timestamp: - if (tc.fUseStopwatch) { - LOGF(info, "\033[1;32m\n\n=> Local timer ends at line %d, time elapsed ... %.6f\n\n\033[0m", __LINE__, tc.fTimer[eLocal]->RealTime()); + if (tc.fUseStopwatch && tc.fVerboseUtility) { + LOGF(info, " Local timer ends at line %d, time elapsed ... %.6f", __LINE__, tc.fTimer[eLocal]->RealTime()); tc.fTimer[eLocal]->Continue(); } @@ -4910,6 +15154,154 @@ void MainLoopOverParticles(T const& tracks) LOGF(fatal, "\033[1;31mIn this event there are too few particles (ebye.fSelectedTracks = %d), and requested number of fixed number randomly selected tracks %d couldn't be reached\033[0m", ebye.fSelectedTracks, tc.fFixedNumberOfRandomlySelectedTracks); } + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } } // template void MainLoopOverParticles(T const& tracks) { +//============================================================ + +template +void Steer(T1 const& collision, T2 const& bcs, T3 const& tracks) +{ + // This is the only function to be called in processRec(...), processRecSim(...), and processSim(...). + // All analysis workflow is defined step-by-step here, via dedicated function calls. + // The order of function calls obviously matters. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // *) Dry run: + if (tc.fDryRun) { + EventCounterForDryRun(eFill); + EventCounterForDryRun(ePrint); + Preprocess(collision, bcs); // yes, so that e.g. I can only test if the particle and centrality weights were correctly fetched from external file and initialized locally into data members + return; + } + + // *) Reset event-by-event quantities: TBI 20240430 I do not need this call also here really, but it doesn't hurt either... + ResetEventByEventQuantities(); + + // *) Only do internal validation for all implemented correlators against the theoretical values: + if (iv.fUseInternalValidation) { + InternalValidation(); + return; + } + + // *) Global timestamp: + if (tc.fUseStopwatch) { + LOGF(info, "\033[1;32m=> Global timer: Steer begins ... %.6f\033[0m", tc.fTimer[eGlobal]->RealTime()); + tc.fTimer[eGlobal]->Continue(); // yes + } + + // *) Do all thingies before starting to process data from this collision (e.g. cut on number of events (both total and selected), fetch the run number, etc.): + Preprocess(collision, bcs); + + // *) It was explicitly requested, skip this particular run: + if (tc.fSkipRun) { + LOGF(info, "\033[1;33mPer exlicit request via configurable cfSkipTheseRuns, skipping run %s from further processing.\033[0m", tc.fRunNumber.Data()); + return; + } + + // *) Determine collision reference multiplicity: + DetermineReferenceMultiplicity(collision); + + // *) Determine collision centrality: + DetermineCentrality(collision); + + // *) Determine collision occupancy: + DetermineOccupancy(collision); + + // *) Determine collision interaction rate and current run duration: + DetermineInteractionRateAndCurrentRunDuration(collision, bcs); + + // *) Determine vertex z position: + DetermineVertexZ(collision); + + // *) Determine additional QA thingies: + if (qa.fFillQAEventHistograms2D || qa.fFillQAParticleHistograms2D || qa.fFillQAParticleEventHistograms2D || qa.fFillQACorrelationsVsHistograms2D || qa.fFillQACorrelationsVsInteractionRateVsProfiles2D) { + // Remark: I implement ideally here only the getters for which the subsription to additional non-standard tables was needed for QA purposes. + DetermineQAThingies(collision, bcs); + } + + // *) Fill event histograms before event cuts: + if (eh.fFillEventHistograms || qa.fFillQAEventHistograms2D || qa.fFillQAParticleEventHistograms2D) { + // Remark: I do not above the flag fFillQACorrelationsVsHistograms2D, because as a part of QA I calculate <2> only after cuts in any case + FillEventHistograms(collision, tracks, eBefore); + } + + // *) Print info on the current event number (total, before cuts): + if (tc.fVerboseEventCounter) { + PrintEventCounter(eBefore); + } + + // *) Event cuts counters (use only during QA, as this is computationally heavy): + if (ec.fUseEventCutCounterAbsolute || ec.fUseEventCutCounterSequential) { + EventCutsCounters(collision, tracks); + } + + // *) Event cuts: + if (!EventCuts(collision, tracks, eCut)) { // Main call for event cuts + return; + } + + // *) Main loop over particles: + MainLoopOverParticles(tracks); + + // *) Determine multiplicity of this event, for all "vs. mult" results: + DetermineMultiplicity(); + + // *) Remaining event cuts which can be applied only after the loop over particles is performed: + if (!RemainingEventCuts()) { + // yes, I need to remove particles from ParticleHistograms, which were filled in the MainLoopOverParticles also for events which didn't survive RemainingEventCuts + BanishmentLoopOverParticles(tracks); + ResetEventByEventQuantities(); + return; + } + + // *) Fill event histograms after event AND particle cuts: + if (eh.fFillEventHistograms || qa.fFillQAEventHistograms2D || qa.fFillQAParticleEventHistograms2D || qa.fFillQACorrelationsVsHistograms2D) { + FillEventHistograms(collision, tracks, eAfter); + } + + // *) Fill subevent multiplicities: + // Remark: I can call this one only after Qa and Qb vectors are filled, and after all particle and event cuts: + if (es.fCalculateEtaSeparations) { + FillSubeventMultiplicities(); + } + + // *) Calculate everything for selected events and particles: + CalculateEverything(); + + // *) Reset event-by-event quantities: + ResetEventByEventQuantities(); + + // *) QA: + if (qa.fCheckUnderflowAndOverflow) { // TBI 20240507 introduce eventualy common function QA(), within which I will call all specific QA functions + CheckUnderflowAndOverflow(); + } + + // *) Print info on the current event number after cuts: + if (tc.fVerboseEventCounter) { + PrintEventCounter(eAfter); + } + + // *) Per request, print content of event cut counters: + if (ec.fPrintCutCounterContent) { + PrintCutCounterContent(); + } + + // *) Global timestamp: + if (tc.fUseStopwatch) { + LOGF(info, "\033[1;32m=> Global timer: Steer ends ... %.6f\033[0m\n", tc.fTimer[eGlobal]->RealTime()); + tc.fTimer[eGlobal]->Continue(); // yes + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // template void Steer(T1 const* collision, T2 const* tracks) + #endif // PWGCF_MULTIPARTICLECORRELATIONS_CORE_MUPA_MEMBERFUNCTIONS_H_ diff --git a/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt b/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt index 397e25796c1..05bb4edb850 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt +++ b/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt @@ -11,10 +11,15 @@ o2physics_add_dpl_workflow(multiparticle-correlations-ab SOURCES multiparticle-correlations-ab.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(multiparticle-correlations-ar SOURCES multiparticle-correlations-ar.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(three-particle-correlations + SOURCES threeParticleCorrelations.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/MultiparticleCorrelations/Tasks/multiparticle-correlations-ab.cxx b/PWGCF/MultiparticleCorrelations/Tasks/multiparticle-correlations-ab.cxx index 06a6017f980..f88933d8450 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/multiparticle-correlations-ab.cxx +++ b/PWGCF/MultiparticleCorrelations/Tasks/multiparticle-correlations-ab.cxx @@ -11,6 +11,7 @@ // O2: #include +#include "Common/CCDB/ctpRateFetcher.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -24,40 +25,65 @@ using namespace o2; using namespace o2::framework; // *) Run 3: -using EventSelection = soa::Join; -using CollisionRec = soa::Join::iterator; +using BCs_Run3 = soa::Join; // TBI 20241126 under testing +// Remark 1: I have already timestamp in workflow, due to track-propagation. +// Remark 2: For consistency with notation below, drop _Run3 and instead use _Run2 and _Run1 TBI 20250401 not sure any longer what I wanted to say here... + +// using EventSelection = soa::Join; // TBI 20241209 validating "MultsGlobal" +// for using collision.multNTracksGlobal() TBI 20250128 do i still need this? +using EventSelection = soa::Join; +// TBI 20250128 I can't join here directly aod::CentNGlobals, see email from DDC from 20250127 if this one requires a special treatment +// See in https://github.com/AliceO2Group/O2Physics/blob/master/Common/DataModel/Centrality.h how centrality tables are named exactly +using CollisionRec = soa::Join::iterator; // use in json "isMC": "true" for "event-selection-task" using CollisionRecSim = soa::Join::iterator; -using CollisionSim = aod::McCollision; // TBI 20240120 add support for centrality also for this case -using TracksRec = soa::Join; -using TrackRec = soa::Join::iterator; -using TracksRecSim = soa::Join; -using TrackRecSim = soa::Join::iterator; +// using CollisionRecSim = soa::Join::iterator; // TBI 20241210 validating "MultsExtraMC" for multMCNParticlesEta08 +using CollisionSim = aod::McCollision; +using TracksRec = soa::Join; +// using TrackRec = soa::Join::iterator; +using TracksRecSim = soa::Join; // + use in json "isMC" : "true" +using TrackRecSim = soa::Join::iterator; using TracksSim = aod::McParticles; using TrackSim = aod::McParticles::iterator; -// *) Converted Run 2: -using EventSelection_Run2 = soa::Join; -using CollisionRec_Run2 = soa::Join::iterator; +// *) Run 2: +using EventSelection_Run2 = soa::Join; // TBI 20240517 do not subscribe to CentRun2CL0s and CentRun2CL1s => see enum +using CollisionRec_Run2 = soa::Join::iterator; // use in json "isRun2MC" : "true" for "event-selection-task" using CollisionRecSim_Run2 = soa::Join::iterator; -using TracksRecSim_Run2 = soa::Join; -using TrackRecSim_Run2 = soa::Join::iterator; +// Remark: For tracks, I can use everything same as in Run 3 -// *) Converted Run 1: +// *) Run 1: // TBI 20240205 Since centrality calibration is not available in converted Run 1 data, I cannot treat it for the time being in the same way as converted Run 2. // Once calibration is available, just use Run 2 above both for Run 2 and Run 1 using EventSelection_Run1 = soa::Join; // TBI 20240205 no calibration for centrality in converted LHC10h and LHC11h, at the time of writing using CollisionRec_Run1 = soa::Join::iterator; +using CollisionRecSim_Run1 = soa::Join::iterator; +// Remark: For tracks, I can use everything same as in Run 3 + +// *) QA: +// Remark: This is Run 3 "Rec" + subscription to additional few tables (otherwise unnecessary in my analysis, e.g. some specific detector tables), used only for QA purposes. +// Therefore, I start all definitions from what I have defined for Run 3 "Rec", and on top of it join these additional tables for QA. +using BCs_QA = soa::Join; +// *) BcSels => bc.has_foundFT0(), etc. +// *) Run3MatchedToBCSparse => bc.has_zdc(), etc. TBI 20250401 at the moment, I do not use this one +using Collision_QA = CollisionRec; // if I would need additional tables for QA, just join 'em here with CollisionRec +using TracksRec_QA = TracksRec; // if I would need additional tables for QA, just join 'em here with TracksRec // *) ROOT: -#include "TList.h" -#include "TSystem.h" -#include "TFile.h" -#include "TH1D.h" -#include "TGrid.h" -#include "Riostream.h" -#include "TRandom3.h" +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include +#include +#include +#include using namespace std; // *) Enums: @@ -72,6 +98,7 @@ struct MultiparticleCorrelationsAB // this name is used in lower-case format to // *) CCDB: Service ccdb; + ctpRateFetcher mRateFetcher; // see email from MP on 20240508 and example usage in O2Physics/PWGLF/TableProducer/Common/zdcSP.cxx // *) Configurables (cuts): #include "PWGCF/MultiparticleCorrelations/Core/MuPa-Configurables.h" @@ -89,28 +116,32 @@ struct MultiparticleCorrelationsAB // this name is used in lower-case format to { // *) Trick to avoid name clashes, part 1; // *) Default configuration, booking, binning and cuts; - // *) Insanity checks; + // *) Insanity checks before booking; // *) Book random generator; // *) Book base list; // *) Book all remaining objects; - // ... + // *) Insanity checks after booking; // *) Trick to avoid name clashes, part 2; // *) Trick to avoid name clashes, part 1: - Bool_t oldHistAddStatus = TH1::AddDirectoryStatus(); + bool oldHistAddStatus = TH1::AddDirectoryStatus(); TH1::AddDirectory(kFALSE); // *) Default configuration, booking, binning and cuts: - DefaultConfiguration(); - DefaultBooking(); - DefaultBinning(); - DefaultCuts(); // Remark: has to be called after DefaultBinning(), since some default cuts are defined through default binning, to ease bookeeping - - // *) Set what to process - only rec, both rec and sim, only sim: - // WhatToProcess(); // yes, this can be called here, after calling all Default* member functions above, because this has an effect only on Book* members functions, and the ones called afterward - - // *) Insanity checks: - InsanityChecks(); + InsanityChecksOnDefinitionsOfConfigurables(); // values passed via configurables are insanitized here. Nothing is initialized yet via configurables in this method + DefaultConfiguration(); // here default values from configurables are taken into account + DefaultBooking(); // here I decide only which histograms are booked, not details like binning, etc. + DefaultBinning(); // here default values for bins are either hardwired, or values for bins provided via configurables are taken into account + DefaultCuts(); // here default values for cuts are either hardwired, or defined through default binning to ease bookeeping, + // or values for cuts provided via configurables are taken into account + // Remark: DefaultCuts() has to be called after DefaultBinning() + // *) Specific cuts: + if (tc.fUseSpecificCuts) { + SpecificCuts(tc.fWhichSpecificCuts); // after default cuts are applied, on top of them apply analysis-specific cuts. Has to be called after DefaultBinning() and DefaultCuts() + } + + // *) Insanity checks before booking: + InsanityChecksBeforeBooking(); // check only hardwired values and the ones obtained from configurables // *) Book random generator: delete gRandom; @@ -122,6 +153,7 @@ struct MultiparticleCorrelationsAB // this name is used in lower-case format to // *) Book all remaining objects; BookAndNestAllLists(); BookResultsHistograms(); // yes, this one has to be booked first, because it defines the commong binning for other groups of histograms + BookQAHistograms(); BookEventHistograms(); BookEventCutsHistograms(); BookParticleHistograms(); @@ -129,10 +161,17 @@ struct MultiparticleCorrelationsAB // this name is used in lower-case format to BookQvectorHistograms(); BookCorrelationsHistograms(); BookWeightsHistograms(); + BookCentralityWeightsHistograms(); BookNestedLoopsHistograms(); + BookNUAHistograms(); + BookInternalValidationHistograms(); BookTest0Histograms(); + BookEtaSeparationsHistograms(); BookTheRest(); // here I book everything that was not sorted (yet) in the specific functions above + // *) Insanity checks after booking: + InsanityChecksAfterBooking(); // pointers of all local histograms, etc., are available, so I can do insanity checks directly on all booked objects + // *) Trick to avoid name clashes, part 2: TH1::AddDirectory(oldHistAddStatus); @@ -161,97 +200,111 @@ struct MultiparticleCorrelationsAB // this name is used in lower-case format to // ------------------------------------------- // A) Process only reconstructed data: - void processRec(CollisionRec const& collision, aod::BCs const&, TracksRec const& tracks) + void processRec(CollisionRec const& collision, BCs_Run3 const& bcs, TracksRec const& tracks) { // Remark: Do not use here LOGF(fatal, ...) or LOGF(info, ...), because their stdout/stderr is suppressed. Use them in regular member functions instead. // *) Steer all analysis steps: - Steer(collision, tracks); + Steer(collision, bcs, tracks); } PROCESS_SWITCH(MultiparticleCorrelationsAB, processRec, "process only reconstructed data", true); // yes, keep always one process switch "true", so that I have default running version // ------------------------------------------- // B) Process both reconstructed and corresponding MC truth simulated data: - void processRecSim(CollisionRecSim const& collision, aod::BCs const&, TracksRecSim const& tracks, aod::McParticles const&, aod::McCollisions const&) + void processRecSim(CollisionRecSim const& collision, aod::BCs const& bcs, TracksRecSim const& tracks, aod::McParticles const&, aod::McCollisions const&) { - Steer(collision, tracks); + Steer(collision, bcs, tracks); } PROCESS_SWITCH(MultiparticleCorrelationsAB, processRecSim, "process both reconstructed and corresponding MC truth simulated data", false); // ------------------------------------------- // C) Process only simulated data: - void processSim(CollisionSim const& collision, aod::BCs const&, TracksSim const& tracks) + void processSim(CollisionSim const& /*collision*/, aod::BCs const& /*bcs*/, TracksSim const& /*tracks*/) { - Steer(collision, tracks); + // Steer(collision, bcs, tracks); // TBI 20240517 not ready yet, but I do not really need this one urgently, since RecSim is working, and I need that one for efficiencies... } PROCESS_SWITCH(MultiparticleCorrelationsAB, processSim, "process only simulated data", false); // ------------------------------------------- // D) Process only converted reconstructed Run 2 data: - void processRec_Run2(CollisionRec_Run2 const& collision, aod::BCs const&, aod::Tracks const& tracks) + void processRec_Run2(CollisionRec_Run2 const& collision, aod::BCs const& bcs, TracksRec const& tracks) { - Steer(collision, tracks); + Steer(collision, bcs, tracks); } PROCESS_SWITCH(MultiparticleCorrelationsAB, processRec_Run2, "process only converted reconstructed Run 2 data", false); // ------------------------------------------- // E) Process both converted reconstructed and corresponding MC truth simulated Run 2 data: - void processRecSim_Run2(CollisionRecSim_Run2 const& collision, aod::BCs const&, TracksRecSim_Run2 const& tracks, aod::McParticles const&, aod::McCollisions const&) + void processRecSim_Run2(CollisionRecSim_Run2 const& collision, aod::BCs const& bcs, TracksRecSim const& tracks, aod::McParticles const&, aod::McCollisions const&) { - Steer(collision, tracks); + Steer(collision, bcs, tracks); } PROCESS_SWITCH(MultiparticleCorrelationsAB, processRecSim_Run2, "process both converted reconstructed and simulated Run 2 data", false); // ------------------------------------------- // F) Process only converted simulated Run 2 data: - void processSim_Run2(aod::Collision const&) // TBI 20240224 not ready yet, this is just dummy to version to get later "doprocess..." variable + void processSim_Run2(CollisionSim const& /*collision*/) // TBI 20240517 extend this subscription eventually { - // Steer(collision, tracks); + // Steer(collision, tracks); // TBI 20240517 not ready yet, but I do not really need this one urgently, since RecSim_Run2 is working, and I need that one for efficiencies... } - PROCESS_SWITCH(MultiparticleCorrelationsAB, processSim_Run2, "process converted only simulated Run 2 data", false); + PROCESS_SWITCH(MultiparticleCorrelationsAB, processSim_Run2, "process only converted simulated Run 2 data", false); // ------------------------------------------- // G) Process only converted reconstructed Run 1 data: - void processRec_Run1(CollisionRec_Run1 const& collision, aod::BCs const&, aod::Tracks const& tracks) + void processRec_Run1(CollisionRec_Run1 const& collision, aod::BCs const& bcs, TracksRec const& tracks) { - Steer(collision, tracks); + Steer(collision, bcs, tracks); } - PROCESS_SWITCH(MultiparticleCorrelationsAB, processRec_Run1, "process only converted reconstructed Run 1 data", false); // ------------------------------------------- // H) Process both converted reconstructed and corresponding MC truth simulated Run 1 data; - void processRecSim_Run1(aod::Collision const&) // TBI 20240224 not ready yet, this is just dummy to version to get later "doprocess..." variable + void processRecSim_Run1(CollisionRecSim_Run1 const& /*collision*/, aod::BCs const& /*bcs*/, TracksRecSim const& /*tracks*/, aod::McParticles const&, aod::McCollisions const&) { - // Steer(collision, tracks); + // Steer(collision, bcs, tracks); // TBI 20240517 not ready yet, but for benchmarking in any case I need only "Rec" } PROCESS_SWITCH(MultiparticleCorrelationsAB, processRecSim_Run1, "process both converted reconstructed and simulated Run 1 data", false); // ------------------------------------------- // I) Process only converted simulated Run 1 data. - void processSim_Run1(aod::Collision const&) // TBI 20240224 not ready yet, this is just dummy to version to get later "doprocess..." variable + void processSim_Run1(aod::Collision const&) // TBI 20240424 not ready yet, just a dummy to version to get later "doprocess..." variable. { - // Steer(collision, tracks); + // Steer(collision, tracks); // TBI 20240517 not ready yet, but for benchmarking in any case I need only "Rec" } PROCESS_SWITCH(MultiparticleCorrelationsAB, processSim_Run1, "process only converted simulated Run 1 data", false); // ------------------------------------------- // J) Process data with minimum subscription to the tables, for testing purposes: - void processTest(aod::Collision const& collision, aod::BCs const&, aod::Tracks const& tracks) + // Remark: To keep this branch as simple as possible, I do not subscribe to centrality table. Therefore, when running with "processTest": "true" in JSON, + // I have to remove "| o2-analysis-centrality-table $JsonFile \" from workflow (yes, remove, not comment out!) + void processTest(aod::Collision const& collision, aod::BCs const& bcs, aod::Tracks const& tracks) { - Steer(collision, tracks); + Steer(collision, bcs, tracks); } PROCESS_SWITCH(MultiparticleCorrelationsAB, processTest, "test processing", false); + // ------------------------------------------- + + // K) Process data with more than necessary subscriptions to the tables, only for QA purposes: + // Remark 1: This is basically the main "processRec" switch, merely enhanced with subscription to few more tables (e.g. detector specific), only for QA purposes. + // Remark 2: Ideally, i use the same workflow for "processRec" and "processQA", but most likely at some point I will have to establish separate workflow for "processQA" + void processQA(Collision_QA const& collision, BCs_QA const& bcs, TracksRec_QA const& tracks, aod::FT0s const&) + { + // Summary for additional tables subscribed to directly here: + // *) FT0s => bc.foundFT0().sumAmpC(), etc. + Steer(collision, bcs, tracks); + } + PROCESS_SWITCH(MultiparticleCorrelationsAB, processQA, "QA processing", false); + }; // struct MultiparticleCorrelationsAB // ------------------------------------------- diff --git a/PWGCF/MultiparticleCorrelations/Tasks/threeParticleCorrelations.cxx b/PWGCF/MultiparticleCorrelations/Tasks/threeParticleCorrelations.cxx new file mode 100644 index 00000000000..a9ae8ac562c --- /dev/null +++ b/PWGCF/MultiparticleCorrelations/Tasks/threeParticleCorrelations.cxx @@ -0,0 +1,868 @@ +// 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 threeParticleCorrelations.cxx +/// \brief Task for producing particle correlations +/// \author Joey Staa + +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "CCDB/BasicCCDBManager.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/PIDResponse.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "RecoDecay.h" +#include "TPDGCode.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace constants::physics; + +struct ThreeParticleCorrelations { + Service ccdb; + + // Analysis parameters + float centMin = 0.0, centMax = 90.0; + float zvtxMax = 7.0; + float v0PtMin = 0.6, v0PtMax = 12.0; + float v0EtaMax = 0.72; + float trackPtMin = 0.2, trackPtMax = 3.0; + float trackEtaMax = 0.8; + + double pionID = 0.0, kaonID = 1.0, protonID = 2.0; + float nSigma0 = 0.0, nSigma2 = 2.0, nSigma4 = 4.0; + + float pionPtMin = 0.3, pionPtMax = 2.3, kaonPtMin = 0.5, kaonPtMax = 2.5, protonPtMin = 0.5, protonPtMax = 2.5; + float pionPtMid = 1.5, kaonPtMid1 = 1.5, kaonPtMid2 = 2.0, protonPtMid = 0.7; + + float dEtaMin = 0.02, dPhiStarMin = 0.1; + float rMin = 0.8, rMax = 2.5; + + // Lambda invariant mass fit + double dGaussSigma = 0.0021; + + // Histogram registry + HistogramRegistry rMECorrRegistry{"MECorrRegistry", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry rSECorrRegistry{"SECorrRegistry", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry rMCRegistry{"MCRegistry", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry rPhiStarRegistry{"PhiStarRegistry", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry rQARegistry{"QARegistry", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + + // Collision & Event filters + Filter collCent = aod::cent::centFT0C > centMin&& aod::cent::centFT0C < centMax; + Filter collZvtx = nabs(aod::collision::posZ) < zvtxMax; + Filter mcCollZvtx = nabs(aod::mccollision::posZ) < zvtxMax; + Filter evSelect = aod::evsel::sel8 == true; + + // V0 filters + Filter v0Pt = aod::v0data::pt > v0PtMin&& aod::v0data::pt < v0PtMax; + Filter v0Eta = nabs(aod::v0data::eta) < v0EtaMax; + + // Track filters + Filter trackPt = aod::track::pt > trackPtMin&& aod::track::pt < trackPtMax; + Filter trackEta = nabs(aod::track::eta) < trackEtaMax; + Filter globalTracks = requireGlobalTrackInFilter(); + + // Particle filters + Filter particleEta = nabs(aod::mcparticle::eta) < trackEtaMax; + + // Table aliases - Data + using MyFilteredCollisions = soa::Filtered>; + using MyFilteredCollision = MyFilteredCollisions::iterator; + using MyFilteredV0s = soa::Filtered; + using MyFilteredTracks = soa::Filtered>; + + // Table aliases - MC + using MyFilteredMCGenCollisions = soa::Filtered>; + using MyFilteredMCGenCollision = MyFilteredMCGenCollisions::iterator; + using MyFilteredMCParticles = soa::Filtered; + using MyFilteredMCRecCollision = soa::Filtered>::iterator; + using MyFilteredMCTracks = soa::Filtered>; + + // Partitions + Partition mcParticles = aod::mcparticle::pt > trackPtMin&& aod::mcparticle::pt < trackPtMax; + Partition mcTriggers = ((aod::mcparticle::pdgCode == static_cast(kLambda0) || aod::mcparticle::pdgCode == static_cast(kLambda0Bar)) && + aod::mcparticle::pt > v0PtMin && aod::mcparticle::pt < v0PtMax && nabs(aod::mcparticle::eta) < v0EtaMax); + Partition mcAssociates = (((aod::mcparticle::pdgCode == static_cast(kPiPlus) || aod::mcparticle::pdgCode == static_cast(kPiMinus)) && aod::mcparticle::pt > pionPtMin && aod::mcparticle::pt < pionPtMax) || + ((aod::mcparticle::pdgCode == static_cast(kKPlus) || aod::mcparticle::pdgCode == static_cast(kKMinus)) && aod::mcparticle::pt > kaonPtMin && aod::mcparticle::pt < kaonPtMax) || + ((aod::mcparticle::pdgCode == static_cast(kProton) || aod::mcparticle::pdgCode == static_cast(kProtonBar)) && aod::mcparticle::pt > protonPtMin)); + + // Mixed-events binning policy + SliceCache cache; + Preslice perCol = aod::mcparticle::mcCollisionId; + + ConfigurableAxis confCentBins{"confCentBins", {VARIABLE_WIDTH, 0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f}, "ME Centrality binning"}; + ConfigurableAxis confZvtxBins{"confZvtxBins", {VARIABLE_WIDTH, -7.0f, -5.0f, -3.0f, -1.0f, 0.0f, 1.0f, 3.0f, 5.0f, 7.0f}, "ME Zvtx binning"}; + using BinningType = ColumnBinningPolicy; + using BinningTypeMC = ColumnBinningPolicy; + + BinningType collBinning{{confCentBins, confZvtxBins}, true}; + BinningTypeMC collBinningMC{{confCentBins, confZvtxBins}, true}; + Pair pairData{collBinning, 5, -1, &cache}; + SameKindPair pairMC{collBinningMC, 5, -1, &cache}; + + // Process configurables + Configurable confFilterSwitch{"confFilterSwitch", false, "Switch for the fakeV0Filter function"}; + + // Efficiency histograms + TH2D** hEffPions = new TH2D*[2]; + TH2D** hEffKaons = new TH2D*[2]; + TH2D** hEffProtons = new TH2D*[2]; + + // Correlation variables + int triggSign, assocSign; + double candMass; + double* assocPID; + + double deltaPhi, deltaEta; + + //========================================================================================================================================================================================================================================================================== + + void init(InitContext const&) + { + + // Histograms axes + const AxisSpec centralityAxis{confCentBins}; + const AxisSpec zvtxAxis{confZvtxBins}; + const AxisSpec phiAxis{36, (-1. / 2) * constants::math::PI, (3. / 2) * constants::math::PI}; + const AxisSpec etaAxis{32, -1.52, 1.52}; + const AxisSpec v0PtAxis{114, 0.6, 12}; + const AxisSpec trackPtAxis{28, 0.2, 3}; + const AxisSpec trackEtaAxis{32, -0.8, 0.8}; + const AxisSpec lambdaInvMassAxis{100, 1.08, 1.16}; + + // QA & PID + rQARegistry.add("hTrackPt", "hTrackPt", {HistType::kTH1D, {{100, 0, 4}}}); + rQARegistry.add("hTrackEta", "hTrackEta", {HistType::kTH1D, {{100, -1, 1}}}); + rQARegistry.add("hTrackPhi", "hTrackPhi", {HistType::kTH1D, {{100, (-1. / 2) * constants::math::PI, (5. / 2) * constants::math::PI}}}); + rQARegistry.add("hEventCentrality", "hEventCentrality", {HistType::kTH1D, {{centralityAxis}}}); + rQARegistry.add("hEventCentrality_MC", "hEventCentrality_MC", {HistType::kTH1D, {{centralityAxis}}}); + rQARegistry.add("hEventZvtx", "hEventZvtx", {HistType::kTH1D, {{zvtxAxis}}}); + + rQARegistry.add("hPtPion", "hPtPion", {HistType::kTH1D, {{trackPtAxis}}}); + rQARegistry.add("hPtKaon", "hPtKaon", {HistType::kTH1D, {{trackPtAxis}}}); + rQARegistry.add("hPtProton", "hPtProton", {HistType::kTH1D, {{trackPtAxis}}}); + rQARegistry.add("hPtV0", "hPtV0", {HistType::kTH1D, {{v0PtAxis}}}); + rQARegistry.add("hdEdx", "hdEdx", {HistType::kTH2D, {{56, 0.2, 3.0}, {180, 20, 200}}}); + rQARegistry.add("hdEdxPion", "hdEdxPion", {HistType::kTH2D, {{56, 0.2, 3.0}, {180, 20, 200}}}); + rQARegistry.add("hdEdxKaon", "hdEdxKaon", {HistType::kTH2D, {{56, 0.2, 3.0}, {180, 20, 200}}}); + rQARegistry.add("hdEdxProton", "hdEdxProton", {HistType::kTH2D, {{56, 0.2, 3.0}, {180, 20, 200}}}); + rQARegistry.add("hBeta", "hBeta", {HistType::kTH2D, {{56, 0.2, 3.0}, {70, 0.4, 1.1}}}); + rQARegistry.add("hBetaPion", "hBetaPion", {HistType::kTH2D, {{56, 0.2, 3.0}, {70, 0.4, 1.1}}}); + rQARegistry.add("hBetaKaon", "hBetaKaon", {HistType::kTH2D, {{56, 0.2, 3.0}, {70, 0.4, 1.1}}}); + rQARegistry.add("hBetaProton", "hBetaProton", {HistType::kTH2D, {{56, 0.2, 3.0}, {70, 0.4, 1.1}}}); + + rQARegistry.add("hTPCPion", "hTPCPion", {HistType::kTH2D, {{trackPtAxis}, {241, -6, 6}}}); + rQARegistry.add("hTPCKaon", "hTPCKaon", {HistType::kTH2D, {{trackPtAxis}, {241, -6, 6}}}); + rQARegistry.add("hTPCProton", "hTPCProton", {HistType::kTH2D, {{trackPtAxis}, {241, -6, 6}}}); + rQARegistry.add("hTOFPion", "hTOFPion", {HistType::kTH2D, {{trackPtAxis}, {1000, -50, 50}}}); + rQARegistry.add("hTOFKaon", "hTOFKaon", {HistType::kTH2D, {{trackPtAxis}, {1000, -50, 50}}}); + rQARegistry.add("hTOFProton", "hTOFProton", {HistType::kTH2D, {{trackPtAxis}, {1000, -50, 50}}}); + + rQARegistry.add("hInvMassLambda", "hInvMassLambda", {HistType::kTH3D, {{lambdaInvMassAxis}, {v0PtAxis}, {centralityAxis}}}); + rQARegistry.add("hInvMassAntiLambda", "hInvMassAntiLambda", {HistType::kTH3D, {{lambdaInvMassAxis}, {v0PtAxis}, {centralityAxis}}}); + rQARegistry.add("hNLambdas", "hNLambdas", {HistType::kTH3D, {{2, -2, 2}, {v0PtAxis}, {centralityAxis}}}); + + // PhiStar + rPhiStarRegistry.add("hSEProtonPreCut", "hSEProtonPreCut", {HistType::kTH2D, {{80, -0.2, 0.2}, {40, -0.1, 0.1}}}); + rPhiStarRegistry.add("hSEProtonPostCut", "hSEProtonPostCut", {HistType::kTH2D, {{80, -0.2, 0.2}, {40, -0.1, 0.1}}}); + rPhiStarRegistry.add("hMEProtonPreCut", "hMEProtonPreCut", {HistType::kTH2D, {{80, -0.2, 0.2}, {40, -0.1, 0.1}}}); + rPhiStarRegistry.add("hMEProtonPostCut", "hMEProtonPostCut", {HistType::kTH2D, {{80, -0.2, 0.2}, {40, -0.1, 0.1}}}); + + // Efficiency + rMCRegistry.add("hGenerated", "hGenerated", {HistType::kTH2D, {{trackPtAxis}, {trackEtaAxis}}}); + rMCRegistry.add("hGenPionP", "hGenPionP", {HistType::kTH2D, {{trackPtAxis}, {trackEtaAxis}}}); + rMCRegistry.add("hGenPionN", "hGenPionN", {HistType::kTH2D, {{trackPtAxis}, {trackEtaAxis}}}); + rMCRegistry.add("hGenKaonP", "hGenKaonP", {HistType::kTH2D, {{trackPtAxis}, {trackEtaAxis}}}); + rMCRegistry.add("hGenKaonN", "hGenKaonN", {HistType::kTH2D, {{trackPtAxis}, {trackEtaAxis}}}); + rMCRegistry.add("hGenProtonP", "hGenProtonP", {HistType::kTH2D, {{trackPtAxis}, {trackEtaAxis}}}); + rMCRegistry.add("hGenProtonN", "hGenProtonN", {HistType::kTH2D, {{trackPtAxis}, {trackEtaAxis}}}); + rMCRegistry.add("hReconstructed", "hReconstructed", {HistType::kTH2D, {{trackPtAxis}, {trackEtaAxis}}}); + rMCRegistry.add("hRecPionP", "hRecPionP", {HistType::kTH2D, {{trackPtAxis}, {trackEtaAxis}}}); + rMCRegistry.add("hRecPionN", "hRecPionN", {HistType::kTH2D, {{trackPtAxis}, {trackEtaAxis}}}); + rMCRegistry.add("hRecKaonP", "hRecKaonP", {HistType::kTH2D, {{trackPtAxis}, {trackEtaAxis}}}); + rMCRegistry.add("hRecKaonN", "hRecKaonN", {HistType::kTH2D, {{trackPtAxis}, {trackEtaAxis}}}); + rMCRegistry.add("hRecProtonP", "hRecProtonP", {HistType::kTH2D, {{trackPtAxis}, {trackEtaAxis}}}); + rMCRegistry.add("hRecProtonN", "hRecProtonN", {HistType::kTH2D, {{trackPtAxis}, {trackEtaAxis}}}); + + // Purity + rMCRegistry.add("hSelectPionP", "hSelectPionP", {HistType::kTH1D, {trackPtAxis}}); + rMCRegistry.add("hSelectPionN", "hSelectPionN", {HistType::kTH1D, {trackPtAxis}}); + rMCRegistry.add("hSelectKaonP", "hSelectKaonP", {HistType::kTH1D, {trackPtAxis}}); + rMCRegistry.add("hSelectKaonN", "hSelectKaonN", {HistType::kTH1D, {trackPtAxis}}); + rMCRegistry.add("hSelectProtonP", "hSelectProtonP", {HistType::kTH1D, {trackPtAxis}}); + rMCRegistry.add("hSelectProtonN", "hSelectProtonN", {HistType::kTH1D, {trackPtAxis}}); + rMCRegistry.add("hTrueSelectPionP", "hTrueSelectPionP", {HistType::kTH1D, {trackPtAxis}}); + rMCRegistry.add("hTrueSelectPionN", "hTrueSelectPionN", {HistType::kTH1D, {trackPtAxis}}); + rMCRegistry.add("hTrueSelectKaonP", "hTrueSelectKaonP", {HistType::kTH1D, {trackPtAxis}}); + rMCRegistry.add("hTrueSelectKaonN", "hTrueSelectKaonN", {HistType::kTH1D, {trackPtAxis}}); + rMCRegistry.add("hTrueSelectProtonP", "hTrueSelectProtonP", {HistType::kTH1D, {trackPtAxis}}); + rMCRegistry.add("hTrueSelectProtonN", "hTrueSelectProtonN", {HistType::kTH1D, {trackPtAxis}}); + + // Correlations + rSECorrRegistry.add("hSameLambdaPion_SGNL", "Same-event #Lambda - #pi correlator (SGNL region)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaPion_SB", "Same-event #Lambda - #pi correlator (SB region)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaKaon_SGNL", "Same-event #Lambda - K correlator (SGNL region)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaKaon_SB", "Same-event #Lambda - K correlator (SB region)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaProton_SGNL", "Same-event #Lambda - p correlator (SGNL region)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaProton_SB", "Same-event #Lambda - p correlator (SB region)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaPion_MC", "Same-event #Lambda - #pi correlator (MC)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaKaon_MC", "Same-event #Lambda - K correlator (MC)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaProton_MC", "Same-event #Lambda - p correlator (MC)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + + rMECorrRegistry.add("hMixLambdaPion_SGNL", "Mixed-event #Lambda - #pi correlator (SGNL region)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaPion_SB", "Mixed-event #Lambda - #pi correlator (SB region)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaKaon_SGNL", "Mixed-event #Lambda - K correlator (SGNL region)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaKaon_SB", "Mixed-event #Lambda - K correlator (SB region)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaProton_SGNL", "Mixed-event #Lambda - p correlator (SGNL region)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaProton_SB", "Mixed-event #Lambda - p correlator (SB region)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaPion_MC", "Mixed-event #Lambda - #pi correlator (MC)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaKaon_MC", "Mixed-event #Lambda - K correlator (MC)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaProton_MC", "Mixed-event #Lambda - p correlator (MC)", {HistType::kTHnSparseF, {{phiAxis}, {etaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + TList* efficiencyList = ccdb->getForTimeStamp("Users/j/jstaa/Efficiency/ChargedParticles", 1); + hEffPions[0] = static_cast(efficiencyList->FindObject("hEfficiencyPionP")); + hEffPions[1] = static_cast(efficiencyList->FindObject("hEfficiencyPionN")); + hEffKaons[0] = static_cast(efficiencyList->FindObject("hEfficiencyKaonP")); + hEffKaons[1] = static_cast(efficiencyList->FindObject("hEfficiencyKaonN")); + hEffProtons[0] = static_cast(efficiencyList->FindObject("hEfficiencyProtonP")); + hEffProtons[1] = static_cast(efficiencyList->FindObject("hEfficiencyProtonN")); + } + + //========================================================================================================================================================================================================================================================================== + + void processSame(MyFilteredCollision const& collision, MyFilteredV0s const& v0s, MyFilteredTracks const& tracks, aod::BCsWithTimestamps const&) + { + + auto bc = collision.bc_as(); + auto bField = getMagneticField(bc.timestamp()); + rQARegistry.fill(HIST("hEventCentrality"), collision.centFT0C()); + rQARegistry.fill(HIST("hEventZvtx"), collision.posZ()); + + // Start of the Track QA + for (const auto& track : tracks) { + rQARegistry.fill(HIST("hTPCPion"), track.pt(), track.tpcNSigmaPi()); + rQARegistry.fill(HIST("hTPCKaon"), track.pt(), track.tpcNSigmaKa()); + rQARegistry.fill(HIST("hTPCProton"), track.pt(), track.tpcNSigmaPr()); + if (track.hasTOF()) { + rQARegistry.fill(HIST("hTOFPion"), track.pt(), track.tofNSigmaPi()); + rQARegistry.fill(HIST("hTOFKaon"), track.pt(), track.tofNSigmaKa()); + rQARegistry.fill(HIST("hTOFProton"), track.pt(), track.tofNSigmaPr()); + } + + if (trackFilters(track)) { + assocPID = trackPID(track); + rQARegistry.fill(HIST("hTrackPt"), track.pt()); + rQARegistry.fill(HIST("hTrackEta"), track.eta()); + rQARegistry.fill(HIST("hTrackPhi"), track.phi()); + rQARegistry.fill(HIST("hdEdx"), track.pt(), track.tpcSignal()); + rQARegistry.fill(HIST("hBeta"), track.pt(), track.beta()); + if (assocPID[0] == pionID) { // Pions + rQARegistry.fill(HIST("hPtPion"), track.pt(), 1. / trackEff(hEffPions, track)); + rQARegistry.fill(HIST("hdEdxPion"), track.pt(), track.tpcSignal()); + rQARegistry.fill(HIST("hBetaPion"), track.pt(), track.beta()); + } else if (assocPID[0] == kaonID) { // Kaons + rQARegistry.fill(HIST("hPtKaon"), track.pt(), 1. / trackEff(hEffKaons, track)); + rQARegistry.fill(HIST("hdEdxKaon"), track.pt(), track.tpcSignal()); + rQARegistry.fill(HIST("hBetaKaon"), track.pt(), track.beta()); + } else if (assocPID[0] == protonID) { // Protons + rQARegistry.fill(HIST("hPtProton"), track.pt(), 1. / trackEff(hEffProtons, track)); + rQARegistry.fill(HIST("hdEdxProton"), track.pt(), track.tpcSignal()); + rQARegistry.fill(HIST("hBetaProton"), track.pt(), track.beta()); + } + } + } + // End of the Track QA + + // Start of the Same-Event correlations + for (const auto& trigger : v0s) { + if (v0Filters(trigger)) { + + rQARegistry.fill(HIST("hPtV0"), trigger.pt()); + triggSign = v0Sign(trigger); + if (triggSign == 1) { + candMass = trigger.mLambda(); + rQARegistry.fill(HIST("hInvMassLambda"), trigger.mLambda(), trigger.pt(), collision.centFT0C()); + } else if (triggSign == -1) { + candMass = trigger.mAntiLambda(); + rQARegistry.fill(HIST("hInvMassAntiLambda"), trigger.mAntiLambda(), trigger.pt(), collision.centFT0C()); + } + + for (const auto& associate : tracks) { + if (trackFilters(associate)) { + if (correlationFilters(trigger, associate) && radialDistanceFilter(trigger, associate, bField, false) && fakeV0Filter(trigger, associate)) { + + assocPID = trackPID(associate); + deltaPhi = RecoDecay::constrainAngle(trigger.phi() - associate.phi(), -constants::math::PIHalf); + deltaEta = trigger.eta() - associate.eta(); + + if (candMass >= MassLambda0 - 4 * dGaussSigma && candMass <= MassLambda0 + 4 * dGaussSigma) { + if (assocPID[0] == pionID) { // Pions + rSECorrRegistry.fill(HIST("hSameLambdaPion_SGNL"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), 1. / trackEff(hEffPions, associate)); + } else if (assocPID[0] == kaonID) { // Kaons + rSECorrRegistry.fill(HIST("hSameLambdaKaon_SGNL"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), 1. / trackEff(hEffKaons, associate)); + } else if (assocPID[0] == protonID) { // Protons + rSECorrRegistry.fill(HIST("hSameLambdaProton_SGNL"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), 1. / trackEff(hEffProtons, associate)); + } + } else if (candMass >= MassLambda0 - 8 * dGaussSigma && candMass <= MassLambda0 + 8 * dGaussSigma) { + if (assocPID[0] == pionID) { // Pions + rSECorrRegistry.fill(HIST("hSameLambdaPion_SB"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), 1. / trackEff(hEffPions, associate)); + } else if (assocPID[0] == kaonID) { // Kaons + rSECorrRegistry.fill(HIST("hSameLambdaKaon_SB"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), 1. / trackEff(hEffKaons, associate)); + } else if (assocPID[0] == protonID) { // Protons + rSECorrRegistry.fill(HIST("hSameLambdaProton_SB"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), 1. / trackEff(hEffProtons, associate)); + } + } + } + } + } + } + } + // End of the Same-Event correlations + } + + void processMixed(MyFilteredCollisions const&, MyFilteredV0s const&, MyFilteredTracks const&, aod::BCsWithTimestamps const&) + { + + // Start of the Mixed-Event correlations + for (const auto& [coll_1, v0_1, coll_2, track_2] : pairData) { + + auto bc = coll_1.bc_as(); + auto bField = getMagneticField(bc.timestamp()); + for (const auto& [trigger, associate] : soa::combinations(soa::CombinationsFullIndexPolicy(v0_1, track_2))) { + if (v0Filters(trigger) && trackFilters(associate)) { + if (radialDistanceFilter(trigger, associate, bField, true) && fakeV0Filter(trigger, associate)) { + + triggSign = v0Sign(trigger); + if (triggSign == 1) { + candMass = trigger.mLambda(); + } else if (triggSign == -1) { + candMass = trigger.mAntiLambda(); + } + + assocPID = trackPID(associate); + deltaPhi = RecoDecay::constrainAngle(trigger.phi() - associate.phi(), -constants::math::PIHalf); + deltaEta = trigger.eta() - associate.eta(); + + if (candMass >= MassLambda0 - 4 * dGaussSigma && candMass <= MassLambda0 + 4 * dGaussSigma) { + if (assocPID[0] == pionID) { // Pions + rMECorrRegistry.fill(HIST("hMixLambdaPion_SGNL"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), 1. / trackEff(hEffPions, associate)); + } else if (assocPID[0] == kaonID) { // Kaons + rMECorrRegistry.fill(HIST("hMixLambdaKaon_SGNL"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), 1. / trackEff(hEffKaons, associate)); + } else if (assocPID[0] == protonID) { // Protons + rMECorrRegistry.fill(HIST("hMixLambdaProton_SGNL"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), 1. / trackEff(hEffProtons, associate)); + } + } else if (candMass >= MassLambda0 - 8 * dGaussSigma && candMass <= MassLambda0 + 8 * dGaussSigma) { + if (assocPID[0] == pionID) { // Pions + rMECorrRegistry.fill(HIST("hMixLambdaPion_SB"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), 1. / trackEff(hEffPions, associate)); + } else if (assocPID[0] == kaonID) { // Kaons + rMECorrRegistry.fill(HIST("hMixLambdaKaon_SB"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), 1. / trackEff(hEffKaons, associate)); + } else if (assocPID[0] == protonID) { // Protons + rMECorrRegistry.fill(HIST("hMixLambdaProton_SB"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), 1. / trackEff(hEffProtons, associate)); + } + } + } + } + } + } + // End of the Mixed-Event Correlations + } + + void processMCSame(MyFilteredMCGenCollision const& collision, MyFilteredMCParticles const&) + { + + rQARegistry.fill(HIST("hEventCentrality_MC"), collision.bestCollisionCentFT0C()); + auto groupMCTriggers = mcTriggers->sliceByCached(aod::mcparticle::mcCollisionId, collision.globalIndex(), cache); + auto groupMCAssociates = mcAssociates->sliceByCached(aod::mcparticle::mcCollisionId, collision.globalIndex(), cache); + + // Start of the MC Same-Event correlations + for (const auto& trigger : groupMCTriggers) { + if (trigger.isPhysicalPrimary()) { + + if (trigger.pdgCode() > 0) { + triggSign = 1; + } else if (trigger.pdgCode() < 0) { + triggSign = -1; + } + rQARegistry.fill(HIST("hNLambdas"), triggSign, trigger.pt(), collision.bestCollisionCentFT0C()); + + for (const auto& associate : groupMCAssociates) { + if (associate.isPhysicalPrimary()) { + + if (associate.pdgCode() > 0) { + assocSign = 1; + } else if (associate.pdgCode() < 0) { + assocSign = -1; + } + + deltaPhi = RecoDecay::constrainAngle(trigger.phi() - associate.phi(), -constants::math::PIHalf); + deltaEta = trigger.eta() - associate.eta(); + + if (std::abs(associate.pdgCode()) == kPiPlus) { + rSECorrRegistry.fill(HIST("hSameLambdaPion_MC"), deltaPhi, deltaEta, collision.bestCollisionCentFT0C(), collision.posZ(), triggSign, assocSign); + } else if (std::abs(associate.pdgCode()) == kKPlus) { + rSECorrRegistry.fill(HIST("hSameLambdaKaon_MC"), deltaPhi, deltaEta, collision.bestCollisionCentFT0C(), collision.posZ(), triggSign, assocSign); + } else if (std::abs(associate.pdgCode()) == kProton) { + rSECorrRegistry.fill(HIST("hSameLambdaProton_MC"), deltaPhi, deltaEta, collision.bestCollisionCentFT0C(), collision.posZ(), triggSign, assocSign); + } + } + } + } + } + // End of the MC Same-Event Correlations + } + + void processMCMixed(MyFilteredMCGenCollisions const&, MyFilteredMCParticles const&) + { + + // Start of the MC Mixed-events Correlations + for (const auto& [coll_1, v0_1, coll_2, particle_2] : pairMC) { + auto groupMCTriggers = mcTriggers->sliceByCached(aod::mcparticle::mcCollisionId, coll_1.globalIndex(), cache); + auto groupMCAssociates = mcAssociates->sliceByCached(aod::mcparticle::mcCollisionId, coll_2.globalIndex(), cache); + + for (const auto& [trigger, associate] : soa::combinations(soa::CombinationsFullIndexPolicy(groupMCTriggers, groupMCAssociates))) { + if (trigger.isPhysicalPrimary() && associate.isPhysicalPrimary()) { + + if (trigger.pdgCode() > 0) { + triggSign = 1; + } else if (trigger.pdgCode() < 0) { + triggSign = -1; + } + if (associate.pdgCode() > 0) { + assocSign = 1; + } else if (associate.pdgCode() < 0) { + assocSign = -1; + } + + deltaPhi = RecoDecay::constrainAngle(trigger.phi() - associate.phi(), -constants::math::PIHalf); + deltaEta = trigger.eta() - associate.eta(); + + if (std::abs(associate.pdgCode()) == kPiPlus) { + rMECorrRegistry.fill(HIST("hMixLambdaPion_MC"), deltaPhi, deltaEta, coll_1.bestCollisionCentFT0C(), coll_1.posZ(), triggSign, assocSign); + } else if (std::abs(associate.pdgCode()) == kKPlus) { + rMECorrRegistry.fill(HIST("hMixLambdaKaon_MC"), deltaPhi, deltaEta, coll_1.bestCollisionCentFT0C(), coll_1.posZ(), triggSign, assocSign); + } else if (std::abs(associate.pdgCode()) == kProton) { + rMECorrRegistry.fill(HIST("hMixLambdaProton_MC"), deltaPhi, deltaEta, coll_1.bestCollisionCentFT0C(), coll_1.posZ(), triggSign, assocSign); + } + } + } + } + // End of the MC Mixed-events Correlations + } + + void processMCGen(MyFilteredMCGenCollision const& collision, MyFilteredMCParticles const&) + { + + auto groupMCParticles = mcParticles->sliceByCached(aod::mcparticle::mcCollisionId, collision.globalIndex(), cache); + + // Start of the Monte-Carlo generated QA + for (const auto& particle : groupMCParticles) { + if (particle.isPhysicalPrimary()) { + + // Efficiency - Generated + rMCRegistry.fill(HIST("hGenerated"), particle.pt(), particle.eta()); + if (particle.pdgCode() == kPiPlus) { // Pos pions + rMCRegistry.fill(HIST("hGenPionP"), particle.pt(), particle.eta()); + } else if (particle.pdgCode() == kPiMinus) { // Neg pions + rMCRegistry.fill(HIST("hGenPionN"), particle.pt(), particle.eta()); + } else if (particle.pdgCode() == kKPlus) { // Pos kaons + rMCRegistry.fill(HIST("hGenKaonP"), particle.pt(), particle.eta()); + } else if (particle.pdgCode() == kKMinus) { // Neg kaons + rMCRegistry.fill(HIST("hGenKaonN"), particle.pt(), particle.eta()); + } else if (particle.pdgCode() == kProton) { // Pos protons + rMCRegistry.fill(HIST("hGenProtonP"), particle.pt(), particle.eta()); + } else if (particle.pdgCode() == kProtonBar) { // Neg protons + rMCRegistry.fill(HIST("hGenProtonN"), particle.pt(), particle.eta()); + } + } + } + // End of the Monte-Carlo generated QA + } + + void processMCRec(MyFilteredMCRecCollision const& collision, MyFilteredMCTracks const& tracks, aod::McCollisions const&, aod::McParticles const&) + { + + if (!collision.has_mcCollision()) { + return; + } + + // Start of the Monte-Carlo reconstructed QA + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + continue; + } + + if (trackFilters(track)) { + auto particle = track.mcParticle(); + if (particle.isPhysicalPrimary()) { + + // Efficiency - Reconstructed + rMCRegistry.fill(HIST("hReconstructed"), track.pt(), track.eta()); + if (particle.pdgCode() == kPiPlus) { // Pos pions + rMCRegistry.fill(HIST("hRecPionP"), track.pt(), track.eta()); + } else if (particle.pdgCode() == kPiMinus) { // Neg pions + rMCRegistry.fill(HIST("hRecPionN"), track.pt(), track.eta()); + } else if (particle.pdgCode() == kKPlus) { // Pos kaons + rMCRegistry.fill(HIST("hRecKaonP"), track.pt(), track.eta()); + } else if (particle.pdgCode() == kKMinus) { // Neg kaons + rMCRegistry.fill(HIST("hRecKaonN"), track.pt(), track.eta()); + } else if (particle.pdgCode() == kProton) { // Pos protons + rMCRegistry.fill(HIST("hRecProtonP"), track.pt(), track.eta()); + } else if (particle.pdgCode() == kProtonBar) { // Neg protons + rMCRegistry.fill(HIST("hRecProtonN"), track.pt(), track.eta()); + } + + // Purity (PID) + assocPID = trackPID(track); + + if (track.sign() > 0) { // Positive tracks + if (assocPID[0] == pionID) { // Pions + rMCRegistry.fill(HIST("hSelectPionP"), track.pt()); + if (particle.pdgCode() == kPiPlus) { + rMCRegistry.fill(HIST("hTrueSelectPionP"), track.pt()); + } + } else if (assocPID[0] == kaonID) { // Kaons + rMCRegistry.fill(HIST("hSelectKaonP"), track.pt()); + if (particle.pdgCode() == kKPlus) { + rMCRegistry.fill(HIST("hTrueSelectKaonP"), track.pt()); + } + } else if (assocPID[0] == protonID) { // Protons + rMCRegistry.fill(HIST("hSelectProtonP"), track.pt()); + if (particle.pdgCode() == kProton) { + rMCRegistry.fill(HIST("hTrueSelectProtonP"), track.pt()); + } + } + } else if (track.sign() < 0) { // Negative tracks + if (assocPID[0] == pionID) { // Pions + rMCRegistry.fill(HIST("hSelectPionN"), track.pt()); + if (particle.pdgCode() == kPiMinus) { + rMCRegistry.fill(HIST("hTrueSelectPionN"), track.pt()); + } + } else if (assocPID[0] == kaonID) { // Kaons + rMCRegistry.fill(HIST("hSelectKaonN"), track.pt()); + if (particle.pdgCode() == kKMinus) { + rMCRegistry.fill(HIST("hTrueSelectKaonN"), track.pt()); + } + } else if (assocPID[0] == protonID) { // Protons + rMCRegistry.fill(HIST("hSelectProtonN"), track.pt()); + if (particle.pdgCode() == kProtonBar) { + rMCRegistry.fill(HIST("hTrueSelectProtonN"), track.pt()); + } + } + } + } + } + } + // End of the Monte-Carlo reconstructed QA + } + + PROCESS_SWITCH(ThreeParticleCorrelations, processSame, "Process same-event correlations", true); + PROCESS_SWITCH(ThreeParticleCorrelations, processMixed, "Process mixed-event correlations", true); + PROCESS_SWITCH(ThreeParticleCorrelations, processMCSame, "Process MC same-event correlations", false); + PROCESS_SWITCH(ThreeParticleCorrelations, processMCMixed, "Process MC mixed-event correlations", false); + PROCESS_SWITCH(ThreeParticleCorrelations, processMCGen, "Process Monte-Carlo, generator level", false); + PROCESS_SWITCH(ThreeParticleCorrelations, processMCRec, "Process Monte-Carlo, reconstructed level", false); + + //========================================================================================================================================================================================================================================================================== + + double getMagneticField(uint64_t timestamp) + { + static parameters::GRPMagField* grpo = nullptr; + if (grpo == nullptr) { + grpo = ccdb->getForTimeStamp("GLO/Config/GRPMagField", timestamp); + if (grpo == nullptr) { + LOGF(fatal, "GRP object not found for timestamp %llu", timestamp); + return 0; + } + LOGF(info, "Retrieved GRP for timestamp %llu with magnetic field of %d kG", timestamp, grpo->getNominalL3Field()); + } + + return 0.1 * (grpo->getNominalL3Field()); // 1 T = 10 kG + } + + template + double trackEff(TH2D** efficiencies, const TrackCand& track) + { + + int index = -999; + if (track.sign() > 0) { + index = 0; + } else if (track.sign() < 0) { + index = 1; + } + + double efficiency = efficiencies[index]->GetBinContent(efficiencies[index]->FindBin(track.pt(), track.eta())); + if (efficiency > 0) { + return efficiency; + } else { + return 1.0; + } + } + + template + int v0Sign(const V0Cand& v0) + { + + if (std::abs(v0.mLambda() - MassLambda0) <= std::abs(v0.mAntiLambda() - MassLambda0)) { + return 1; + } else if (std::abs(v0.mLambda() - MassLambda0) > std::abs(v0.mAntiLambda() - MassLambda0)) { + return -1; + } + + return 0; + } + + template + double* trackPID(const TrackCand& track) + { + + static double pid[2]; // {PID, NSigma} + + double nSigma[3]; + double nSigmaTOF[3]; + nSigmaTOF[0] = track.tofNSigmaPi(); + nSigmaTOF[1] = track.tofNSigmaKa(); + nSigmaTOF[2] = track.tofNSigmaPr(); + + nSigma[0] = std::abs(nSigmaTOF[0]); + nSigma[1] = std::abs(nSigmaTOF[1]); + nSigma[2] = std::abs(nSigmaTOF[2]); + + if (nSigma[0] <= std::min(nSigma[1], nSigma[2])) { // Pions + pid[0] = pionID; + pid[1] = nSigmaTOF[0]; + } else if (nSigma[1] <= std::min(nSigma[0], nSigma[2])) { // Kaons + pid[0] = kaonID; + pid[1] = nSigmaTOF[1]; + } else if (nSigma[2] < std::min(nSigma[0], nSigma[1])) { // Protons + pid[0] = protonID; + pid[1] = nSigmaTOF[2]; + } + + return pid; + } + + //========================================================================================================================================================================================================================================================================== + + template + bool v0Filters(const V0Cand& v0) + { + + if (v0Sign(v0) == 1) { + const auto& posDaughter = v0.template posTrack_as(); + if (std::abs(posDaughter.tpcNSigmaPr()) > nSigma4) { + return kFALSE; + } + } else if (v0Sign(v0) == -1) { + const auto& negDaughter = v0.template negTrack_as(); + if (std::abs(negDaughter.tpcNSigmaPr()) > nSigma4) { + return kFALSE; + } + } + + return kTRUE; + } + + template + bool trackFilters(const TrackCand& track) + { + + if (!track.hasTOF()) { + return kFALSE; + } + + if (trackPID(track)[0] == pionID) { // Pions + if (std::abs(track.tpcNSigmaPi()) > nSigma4) { + return kFALSE; + } + if (track.pt() < pionPtMin) { + return kFALSE; + } else if (track.pt() > pionPtMin && track.pt() < pionPtMid) { + if (std::abs(track.tofNSigmaPi()) > nSigma4) { + return kFALSE; + } + } else if (track.pt() > pionPtMid && track.pt() < pionPtMax) { + if (track.tofNSigmaPi() < -nSigma4 || track.tofNSigmaPi() > nSigma0) { + return kFALSE; + } + } else if (track.pt() > pionPtMax) { + return kFALSE; + } + + } else if (trackPID(track)[0] == kaonID) { // Kaons + if (std::abs(track.tpcNSigmaKa()) > nSigma4) { + return kFALSE; + } + if (track.pt() < kaonPtMin) { + return kFALSE; + } else if (track.pt() > kaonPtMin && track.pt() < kaonPtMid1) { + if (std::abs(track.tofNSigmaKa()) > nSigma4) { + return kFALSE; + } + } else if (track.pt() > kaonPtMid1 && track.pt() < kaonPtMid2) { + if (track.tofNSigmaKa() < -nSigma2 || track.tofNSigmaKa() > nSigma4) { + return kFALSE; + } + } else if (track.pt() > kaonPtMid2 && track.pt() < kaonPtMax) { + if (track.tofNSigmaKa() < nSigma0 || track.tofNSigmaKa() > nSigma4) { + return kFALSE; + } + } else if (track.pt() > kaonPtMax) { + return kFALSE; + } + + } else if (trackPID(track)[0] == protonID) { // Protons + if (std::abs(track.tpcNSigmaPr()) > nSigma4) { + return kFALSE; + } + if (track.pt() < protonPtMin) { + return kFALSE; + } else if (track.pt() > protonPtMin && track.pt() < protonPtMid) { + if (track.tofNSigmaPr() < -nSigma2 || track.tofNSigmaPr() > nSigma4) { + return kFALSE; + } + } else if (track.pt() > protonPtMid && track.pt() < protonPtMax) { + if (std::abs(track.tofNSigmaPr()) > nSigma4) { + return kFALSE; + } + } else if (track.pt() > protonPtMax) { + if (track.tofNSigmaPr() < -nSigma2 || track.tofNSigmaPr() > nSigma4) { + return kFALSE; + } + } + } + + return kTRUE; + } + + template + bool correlationFilters(const V0Cand& v0, const TrackCand& track) + { + + if (track.globalIndex() == v0.posTrackId() || track.globalIndex() == v0.negTrackId()) { + return kFALSE; + } + + return kTRUE; + } + + template + bool fakeV0Filter(const V0Cand& v0, const TrackCand& track) + { + + if (confFilterSwitch) { + + if (trackPID(track)[0] == kaonID) { // Kaons + return kTRUE; + } + + std::array massArray; + std::array dMomArray; + std::array aMomArray = track.pVector(); + if (trackPID(track)[0] == pionID) { + massArray = {MassProton, MassPionCharged}; + + if (v0Sign(v0) == 1 && track.sign() == -1) { // Lambda - Pi_min + const auto& dTrack = v0.template posTrack_as(); + dMomArray = dTrack.pVector(); + } else if (v0Sign(v0) == -1 && track.sign() == 1) { // Antilambda - Pi_plus + const auto& dTrack = v0.template negTrack_as(); + dMomArray = dTrack.pVector(); + } + } else if (trackPID(track)[0] == protonID) { + massArray = {MassPionCharged, MassProton}; + + if (v0Sign(v0) == 1 && track.sign() == 1) { // Lambda - Proton + const auto& dTrack = v0.template negTrack_as(); + dMomArray = dTrack.pVector(); + } else if (v0Sign(v0) == -1 && track.sign() == -1) { // Antilambda - Antiproton + const auto& dTrack = v0.template posTrack_as(); + dMomArray = dTrack.pVector(); + } + } + + double invMass = RecoDecay::m(std::array{dMomArray, aMomArray}, massArray); + if (invMass >= MassLambda0 - 4 * dGaussSigma && invMass <= MassLambda0 + 4 * dGaussSigma) { + return kFALSE; + } + } + + return kTRUE; + } + + template + bool radialDistanceFilter(const V0Cand& v0, const TrackCand& track, double B, bool Mix) + { + + auto proton = v0.template posTrack_as(); + if (v0Sign(v0) == -1) { + proton = v0.template negTrack_as(); + } + + double dEta = proton.eta() - track.eta(); + if (std::abs(dEta) > dEtaMin) { + return kTRUE; + } + + double dPhiStar; + double dPhi = proton.phi() - track.phi(); + double phaseProton = (-0.3 * B * proton.sign()) / (2 * proton.pt()); + double phaseTrack = (-0.3 * B * track.sign()) / (2 * track.pt()); + + for (double r = rMin; r <= rMax; r += 0.01) { + dPhiStar = RecoDecay::constrainAngle(dPhi + std::asin(phaseProton * r) - std::asin(phaseTrack * r), -constants::math::PIHalf); + + if (r == rMin) { + if (!Mix) { + rPhiStarRegistry.fill(HIST("hSEProtonPreCut"), dPhiStar, dEta); + } else { + rPhiStarRegistry.fill(HIST("hMEProtonPreCut"), dPhiStar, dEta); + } + } + + if (std::abs(dPhiStar) < dPhiStarMin) { + return kFALSE; + } + + if (r == rMin) { + if (!Mix) { + rPhiStarRegistry.fill(HIST("hSEProtonPostCut"), dPhiStar, dEta); + } else { + rPhiStarRegistry.fill(HIST("hMEProtonPostCut"), dPhiStar, dEta); + } + } + } + + return kTRUE; + } +}; + +//============================================================================================================================================================================================================================================================================ + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} + +//============================================================================================================================================================================================================================================================================ diff --git a/PWGCF/TableProducer/dptdptfilter.cxx b/PWGCF/TableProducer/dptdptfilter.cxx index 924edaf13f6..93de67eff5c 100644 --- a/PWGCF/TableProducer/dptdptfilter.cxx +++ b/PWGCF/TableProducer/dptdptfilter.cxx @@ -9,12 +9,19 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file dptdptfilter.cxx +/// \brief Filters collisions and tracks according to selection criteria +/// \author victor.gonzalez.sebastian@gmail.com + #include #include +#include +#include #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" +#include "CommonConstants/PhysicsConstants.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Centrality.h" #include "Common/Core/TableHelper.h" @@ -25,10 +32,11 @@ #include "PWGCF/DataModel/DptDptFiltered.h" #include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/CollisionAssociationTables.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/runDataProcessing.h" #include "Framework/RunningWorkflowInfo.h" #include -#include +#include #include #include #include @@ -67,6 +75,7 @@ using DptDptFullTracksFullPIDDetLevel = soa::Join; bool fullDerivedData = false; /* produce full derived data for its external storage */ +TpcExcludeTrack tpcExcluder; ///< the TPC excluder object instance /// \enum MatchRecoGenSpecies /// \brief The species considered by the matching test @@ -85,10 +94,32 @@ const char* speciesName[kDptDptNoOfSpecies] = {"h", "e", "mu", "pi", "ka", "p"}; const char* speciesTitle[kDptDptNoOfSpecies] = {"", "e", "#mu", "#pi", "K", "p"}; +const char* eventSelectionSteps[knCollisionSelectionFlags] = { + "IN", + "MB", + "INT7", + "SEL7", + "SEL8", + "NOSAMEBUNCHPUP", + "ISGOODZVTXFT0VSPV", + "ISVERTEXITSTPC", + "ISVERTEXTOFMATCHED", + "ISVERTEXTRDMATCHED", + "NOCOLLINTIMERANGE", + "NOCOLLINROF", + "OCCUPANCY", + "ISGOODITSLAYER3", + "ISGOODITSLAYER0123", + "ISGOODITSLAYERALL", + "CENTRALITY", + "ZVERTEX", + "SELECTED"}; + //============================================================================================ // The DptDptFilter histogram objects // TODO: consider registering in the histogram registry //============================================================================================ +TH1D* fhEventSelection = nullptr; TH1F* fhCentMultB = nullptr; TH1F* fhCentMultA = nullptr; TH1F* fhVertexZB = nullptr; @@ -163,6 +194,169 @@ std::vector partMultNeg; // multiplicity of negative particles using namespace dptdptfilter; +////////////////////////////////////////////////////////////////////////////// +// Multiplicity in principle for on the fly generated events +////////////////////////////////////////////////////////////////////////////// + +struct Multiplicity { + enum MultEst { + kV0M, + kCL1, + kCL1GAP + }; + + float getMultiplicityClass() { return multiplicityClass; } + float getMultiplicity() { return multiplicity; } + + MultEst classestimator = kV0M; + + float multiplicityClass = -1.0; + float multiplicity = 0.0; + bool inelgth0 = false; + int v0am = 0; + int v0cm = 0; + int cl1m = 0; + int cl1EtaGapM = 0; + int dNchdEta = 0; + int nPart = 0; + TH1F* fhNPartTot = nullptr; ///< total number of particles analyzed + TH1F* fhMultiplicity; ///< the multiplicity distribution + TH2F* fhV0Multiplicity; ///< the V0M multiplicity histogram + TH2F* fhCL1Multiplicity; ///< the CL1 multiplicity histogram + TH2F* fhCL1EtaGapMultiplicity; ///< the CL1 with an eta gap multiplicity histogram + const TH1* fhV0MMultPercentile; ///< the V0M Centrality / Multiplicity percentile estimation histogram + const TH1* fhCL1MultPercentile; ///< the CL1 Centrality / Multiplicity percentile estimation histogram + const TH1* fhCL1EtaGapMultPercentile; ///< the CL1 with an eta gap Centrality / Multiplicity percentile estimation histogram + + void init(TList* hlist) + { + fhNPartTot = new TH1F("CollisionNpart", "Collision analyzed particles;number of particles;counts", 8000, -0.5, 8000 - 0.5); + fhMultiplicity = new TH1F("CollisionMultiplicity", "Event multiplicity;multiplicity (%);counts", 101, -0.5, 101 - 0.5); + fhV0Multiplicity = new TH2F("V0Multiplicity", "V0M;V0M;d#it{N}/d#eta;counts", 3000, -9.5, 3000 - 9.5, 2500, -9.5, 2500 - 9.5); + fhCL1Multiplicity = new TH2F("CL1Multiplicity", "CL1M;CL1M;d#it{N}/d#eta;counts", 3000, -9.5, 3000 - 9.5, 2500, -9.5, 2500 - 9.5); + fhCL1EtaGapMultiplicity = new TH2F("CL1EtaGapMultiplicity", "CL1M (excl |#eta|<0.8);CL1M;d#it{N}/d#eta;counts", 3000, -9.5, 3000 - 9.5, 2500, -9.5, 2500 - 9.5); + + hlist->Add(fhNPartTot); + hlist->Add(fhMultiplicity); + hlist->Add(fhV0Multiplicity); + hlist->Add(fhCL1Multiplicity); + hlist->Add(fhCL1EtaGapMultiplicity); + } + + void setMultiplicityPercentiles(TList* list) + { + LOGF(info, "setMultiplicityPercentiles()", "From list %s", list->GetName()); + fhV0MMultPercentile = reinterpret_cast(list->FindObject("V0MCentMult")); + fhCL1MultPercentile = reinterpret_cast(list->FindObject("CL1MCentMult")); + fhCL1EtaGapMultPercentile = reinterpret_cast(list->FindObject("CL1EtaGapMCentMult")); + + if (fhV0MMultPercentile == nullptr || fhCL1MultPercentile == nullptr || fhCL1EtaGapMultPercentile == nullptr) { + LOGF(fatal, "setMultiplicityPercentiles()", "Percentiles histograms not correctly loaded. ABORTING!!!"); + return; + } + } + + template + bool addParticleToMultiplicity(const Particle& p) + { + /* on the fly MC production */ + /* get event multiplicity according to the passed eta range */ + /* event multiplicity as number of primary charged particles */ + /* based on AliAnalysisTaskPhiCorrelations implementation */ + int pdgcode = std::abs(p.pdgCode()); + auto addTo = [](const Particle& p, int& est, float etamin, float etamax) { + if (p.eta() < etamax && etamin < p.eta()) { + est = est + 1; + } + }; + + /* pdg checks */ + switch (pdgcode) { + case kPiPlus: + case kKPlus: + case kProton: + /* not clear if we should use IsPhysicalPrimary here */ + /* TODO: adapt to FT0M Run 3 and other estimators */ + if (0.001 < p.pt() && p.pt() < 50.0) { + if (p.eta() < 1.0 && -1.0 < p.eta()) { + inelgth0 = true; + } + addTo(p, v0am, 2.8, 5.1); + addTo(p, v0cm, -3.7, -1.7); + addTo(p, cl1m, -1.4, 1.4); + addTo(p, cl1EtaGapM, -1.4, -0.8); + addTo(p, cl1EtaGapM, 0.8, 1.4); + addTo(p, dNchdEta, -0.5, 0.5); + nPart++; + } + break; + default: + break; + } + return true; + } + + template + void extractMultiplicity(const CollisionParticles& particles) + { + multiplicityClass = 105; + multiplicity = 0; + inelgth0 = false; + nPart = 0; + v0am = 0; + v0cm = 0; + cl1m = 0; + cl1EtaGapM = 0; + dNchdEta = 0; + + for (auto const& particle : particles) { + addParticleToMultiplicity(particle); + } + + if (inelgth0) { + if (fhNPartTot != nullptr) { + fhNPartTot->Fill(nPart); + } + if (fhV0Multiplicity != nullptr) { + fhV0Multiplicity->Fill(v0am + v0cm, dNchdEta); + } + if (fhCL1Multiplicity != nullptr) { + fhCL1Multiplicity->Fill(cl1m, dNchdEta); + } + if (fhCL1EtaGapMultiplicity != nullptr) { + fhCL1EtaGapMultiplicity->Fill(cl1EtaGapM, dNchdEta); + } + switch (classestimator) { + case kV0M: + if (fhV0MMultPercentile != nullptr) { + multiplicityClass = fhV0MMultPercentile->GetBinContent(fhV0MMultPercentile->FindFixBin(v0am + v0cm)); + multiplicity = v0am + v0cm; + } + break; + case kCL1: + if (fhCL1MultPercentile != nullptr) { + multiplicityClass = fhCL1MultPercentile->GetBinContent(fhCL1MultPercentile->FindFixBin(cl1m)); + multiplicity = cl1m; + } + break; + case kCL1GAP: + if (fhCL1EtaGapMultPercentile != nullptr) { + multiplicityClass = fhCL1EtaGapMultPercentile->GetBinContent(fhCL1EtaGapMultPercentile->FindFixBin(cl1EtaGapM)); + multiplicity = cl1EtaGapM; + } + break; + default: + break; + } + fhMultiplicity->Fill(multiplicityClass); + } + } +}; + +////////////////////////////////////////////////////////////////////////////// +// The filter class +////////////////////////////////////////////////////////////////////////////// + struct DptDptFilter { struct : ConfigurableGroup { Configurable cfgCCDBUrl{"input_ccdburl", "http://ccdb-test.cern.ch:8080", "The CCDB url for the input file"}; @@ -172,11 +366,32 @@ struct DptDptFilter { } cfginputfile; Configurable cfgFullDerivedData{"fullderiveddata", false, "Produce the full derived data for external storage. Default false"}; Configurable cfgCentMultEstimator{"centmultestimator", "V0M", "Centrality/multiplicity estimator detector: V0M,CL0,CL1,FV0A,FT0M,FT0A,FT0C,NTPV,NOCM: none. Default V0M"}; + + struct : ConfigurableGroup { + std::string prefix = "cfgEventSelection"; + Configurable itsDeadMaps{"itsDeadMaps", "", "Level of inactive chips: nocheck(empty), goodIts3, goodIts0123, goodItsAll. Default empty"}; + Configurable minOrbit{"minOrbit", -1, "Lowest orbit to track"}; + Configurable maxOrbit{"maxOrbit", INT64_MAX, "Highest orbit to track"}; + struct : ConfigurableGroup { + std::string prefix = "cfgOccupancySelection"; + Configurable cfgOccupancyEstimation{"cfgOccupancyEstimation", "None", "Occupancy estimation: None, Tracks, FT0C. Default None"}; + Configurable cfgMinOccupancy{"cfgMinOccupancy", 0.0f, "Minimum allowed occupancy. Depends on the occupancy estimation"}; + Configurable cfgMaxOccupancy{"cfgMaxOccupancy", 1e6f, "Maximum allowed occupancy. Depends on the occupancy estimation"}; + } cfgOccupancySelection; + } cfgEventSelection; Configurable cfgSystem{"syst", "PbPb", "System: pp, PbPb, Pbp, pPb, XeXe, ppRun3, PbPbRun3. Default PbPb"}; Configurable cfgDataType{"datatype", "data", "Data type: data, datanoevsel, MC, FastMC, OnTheFlyMC. Default data"}; Configurable cfgTriggSel{"triggsel", "MB", "Trigger selection: MB,VTXTOFMATCHED,VTXTRDMATCHED,VTXTRDTOFMATCHED,None. Default MB"}; Configurable cfgCentSpec{"centralities", "00-10,10-20,20-30,30-40,40-50,50-60,60-70,70-80", "Centrality/multiplicity ranges in min-max separated by commas"}; Configurable cfgOverallMinP{"overallminp", 0.0f, "The overall minimum momentum for the analysis. Default: 0.0"}; + struct : ConfigurableGroup { + std::string prefix = "cfgTpcExclusion"; + Configurable method{"method", 0, "The method for excluding tracks within the TPC. 0: no exclusion; 1: static; 2: dynamic. Default: 0"}; + Configurable positiveLowCut{"positiveLowCut", "0.0787/x - 0.0236", "The lower cut function for positive tracks"}; + Configurable positiveUpCut{"positiveUpCut", "0.0892/x + 0.0251", "The upper cut function for positive tracks"}; + Configurable negativeLowCut{"negativeLowCut", "pi/9.0 - (0.0892/x + 0.0251)", "The lower cut function for negative tracks"}; + Configurable negativeUpCut{"negativeUpCut", "pi/9 - (0.0787/x - 0.0236)", "The upper cut function for negative tracks"}; + } cfgTpcExclusion; Configurable cfgBinning{"binning", {28, -7.0, 7.0, 18, 0.2, 2.0, 16, -0.8, 0.8, 72, 0.5}, "triplets - nbins, min, max - for z_vtx, pT, eta and phi, binning plus bin fraction of phi origin shift"}; @@ -189,6 +404,8 @@ struct DptDptFilter { Produces acceptedtrueevents; Produces gencollisionsinfo; + Multiplicity multiplicity; + void init(InitContext const&) { using namespace dptdptfilter; @@ -212,9 +429,18 @@ struct DptDptFilter { /* the centrality/multiplicity estimation */ if (doprocessWithoutCent || doprocessWithoutCentDetectorLevel || doprocessWithoutCentGeneratorLevel) { fCentMultEstimator = kNOCM; + } else if (doprocessOnTheFlyGeneratorLevel) { + fCentMultEstimator = kFV0A; } else { fCentMultEstimator = getCentMultEstimator(cfgCentMultEstimator); } + /* the occupancy selection */ + fOccupancyEstimation = getOccupancyEstimator(cfgEventSelection.cfgOccupancySelection.cfgOccupancyEstimation); + fMinOccupancy = cfgEventSelection.cfgOccupancySelection.cfgMinOccupancy; + fMaxOccupancy = cfgEventSelection.cfgOccupancySelection.cfgMaxOccupancy; + /* the ITS dead map check */ + fItsDeadMapCheck = getItsDeadMapCheck(cfgEventSelection.itsDeadMaps); + /* the trigger selection */ fTriggerSelection = getTriggerSelection(cfgTriggSel); traceCollId0 = cfgTraceCollId0; @@ -230,6 +456,10 @@ struct DptDptFilter { if ((fDataType == kData) || (fDataType == kDataNoEvtSel) || (fDataType == kMC)) { /* create the reconstructed data histograms */ + fhEventSelection = new TH1D("EventSelection", ";;counts", knCollisionSelectionFlags, -0.5f, static_cast(knCollisionSelectionFlags) - 0.5f); + for (int ix = 0; ix < knCollisionSelectionFlags; ++ix) { + fhEventSelection->GetXaxis()->SetBinLabel(ix + 1, eventSelectionSteps[ix]); + } /* TODO: proper axes and axes titles according to the system; still incomplete */ std::string multestimator = getCentMultEstimatorName(fCentMultEstimator); if (fSystem > kPbp) { @@ -249,6 +479,7 @@ struct DptDptFilter { fhVertexZA = new TH1F("VertexZA", "Vertex Z; z_{vtx}", zvtxbins, zvtxlow, zvtxup); /* add the hstograms to the output list */ + fOutputList->Add(fhEventSelection); fOutputList->Add(fhCentMultB); fOutputList->Add(fhCentMultA); fOutputList->Add(fhMultB); @@ -271,40 +502,46 @@ struct DptDptFilter { fhTrueVertexZB = new TH1F("TrueVertexZB", "Vertex Z before (truth); z_{vtx}", 60, -15, 15); fhTrueVertexZA = new TH1F("TrueVertexZA", "Vertex Z (truth); z_{vtx}", zvtxbins, zvtxlow, zvtxup); - fhTrueVertexZAA = new TH1F("TrueVertexZAA", "Vertex Z (truth rec associated); z_{vtx}", zvtxbins, zvtxlow, zvtxup); + if (!doprocessOnTheFlyGeneratorLevel) { + fhTrueVertexZAA = new TH1F("TrueVertexZAA", "Vertex Z (truth rec associated); z_{vtx}", zvtxbins, zvtxlow, zvtxup); + } /* add the hstograms to the output list */ fOutputList->Add(fhTrueCentMultB); fOutputList->Add(fhTrueCentMultA); fOutputList->Add(fhTrueVertexZB); fOutputList->Add(fhTrueVertexZA); - fOutputList->Add(fhTrueVertexZAA); + if (doprocessOnTheFlyGeneratorLevel) { + multiplicity.init(fOutputList); + } else { + fOutputList->Add(fhTrueVertexZAA); + } } } template void processReconstructed(CollisionObject const& collision, TracksObject const& ftracks, float centormult); - void processWithCent(aod::CollisionEvSelCent const& collision, DptDptFullTracks const& ftracks); + void processWithCent(aod::CollisionEvSelCent const& collision, DptDptFullTracks const& ftracks, const aod::BCsWithTimestamps&); PROCESS_SWITCH(DptDptFilter, processWithCent, "Process reco with centrality", false); - void processWithRun2Cent(aod::CollisionEvSelRun2Cent const& collision, DptDptFullTracks const& ftracks); + void processWithRun2Cent(aod::CollisionEvSelRun2Cent const& collision, DptDptFullTracks const& ftracks, const aod::BCsWithTimestamps&); PROCESS_SWITCH(DptDptFilter, processWithRun2Cent, "Process reco with Run !/2 centrality", false); - void processWithoutCent(aod::CollisionEvSel const& collision, DptDptFullTracks const& ftracks); + void processWithoutCent(aod::CollisionEvSel const& collision, DptDptFullTracks const& ftracks, const aod::BCsWithTimestamps&); PROCESS_SWITCH(DptDptFilter, processWithoutCent, "Process reco without centrality", false); - void processWithCentDetectorLevel(aod::CollisionEvSelCent const& collision, DptDptFullTracksDetLevel const& ftracks, aod::McParticles const&); + void processWithCentDetectorLevel(aod::CollisionEvSelCent const& collision, DptDptFullTracksDetLevel const& ftracks, aod::McParticles const&, const aod::BCsWithTimestamps&); PROCESS_SWITCH(DptDptFilter, processWithCentDetectorLevel, "Process MC detector level with centrality", false); - void processWithRun2CentDetectorLevel(aod::CollisionEvSelRun2Cent const& collision, DptDptFullTracksDetLevel const& ftracks, aod::McParticles const&); + void processWithRun2CentDetectorLevel(aod::CollisionEvSelRun2Cent const& collision, DptDptFullTracksDetLevel const& ftracks, aod::McParticles const&, const aod::BCsWithTimestamps&); PROCESS_SWITCH(DptDptFilter, processWithRun2CentDetectorLevel, "Process MC detector level with centrality", false); - void processWithoutCentDetectorLevel(aod::CollisionEvSel const& collision, DptDptFullTracksDetLevel const& ftracks, aod::McParticles const&); + void processWithoutCentDetectorLevel(aod::CollisionEvSel const& collision, DptDptFullTracksDetLevel const& ftracks, aod::McParticles const&, const aod::BCsWithTimestamps&); PROCESS_SWITCH(DptDptFilter, processWithoutCentDetectorLevel, "Process MC detector level without centrality", false); template - void processGenerated(CollisionObject const& mccollision, ParticlesList const& mcparticles, float centormult); + bool processGenerated(CollisionObject const& mccollision, ParticlesList const& mcparticles, float centormult); template void processGeneratorLevel(aod::McCollision const& mccollision, @@ -331,6 +568,10 @@ struct DptDptFilter { aod::CollisionsEvSel const& allcollisions); PROCESS_SWITCH(DptDptFilter, processWithoutCentGeneratorLevel, "Process generated without centrality", false); + void processOnTheFlyGeneratorLevel(aod::McCollision const& mccollision, + aod::McParticles const& mcparticles); + PROCESS_SWITCH(DptDptFilter, processOnTheFlyGeneratorLevel, "Process on the fly generated events", false); + void processVertexGenerated(aod::McCollisions const&); PROCESS_SWITCH(DptDptFilter, processVertexGenerated, "Process vertex generator level", false); }; @@ -343,13 +584,16 @@ void DptDptFilter::processReconstructed(CollisionObject const& collision, Tracks LOGF(DPTDPTFILTERLOGCOLLISIONS, "DptDptFilterTask::processReconstructed(). New collision with %d tracks", ftracks.size()); float mult = extractMultiplicity(collision, fCentMultEstimator); + static const int32_t nBCsPerOrbit = o2::constants::lhc::LHCMaxBunches; fhCentMultB->Fill(tentativecentmult); fhMultB->Fill(mult); fhVertexZB->Fill(collision.posZ()); uint8_t acceptedevent = uint8_t(false); float centormult = tentativecentmult; - if (IsEvtSelected(collision, centormult)) { + int64_t orbit = collision.template bc_as().globalBC() / nBCsPerOrbit; + bool withinOrbitOfInterest = (cfgEventSelection.minOrbit <= orbit) && (orbit < cfgEventSelection.maxOrbit); + if (withinOrbitOfInterest && isEventSelected(collision, centormult)) { acceptedevent = true; fhCentMultA->Fill(centormult); fhMultA->Fill(mult); @@ -365,45 +609,51 @@ void DptDptFilter::processReconstructed(CollisionObject const& collision, Tracks collisionsinfo(uint8_t(false), 105.0); } } + /* report the event selection */ + for (int iflag = 0; iflag < knCollisionSelectionFlags; ++iflag) { + if (collisionFlags.test(iflag)) { + fhEventSelection->Fill(iflag); + } + } } -void DptDptFilter::processWithCent(aod::CollisionEvSelCent const& collision, DptDptFullTracks const& ftracks) +void DptDptFilter::processWithCent(aod::CollisionEvSelCent const& collision, DptDptFullTracks const& ftracks, aod::BCsWithTimestamps const&) { processReconstructed(collision, ftracks, getCentMultPercentile(collision)); } -void DptDptFilter::processWithRun2Cent(aod::CollisionEvSelRun2Cent const& collision, DptDptFullTracks const& ftracks) +void DptDptFilter::processWithRun2Cent(aod::CollisionEvSelRun2Cent const& collision, DptDptFullTracks const& ftracks, aod::BCsWithTimestamps const&) { processReconstructed(collision, ftracks, getCentMultPercentile(collision)); } -void DptDptFilter::processWithoutCent(aod::CollisionEvSel const& collision, DptDptFullTracks const& ftracks) +void DptDptFilter::processWithoutCent(aod::CollisionEvSel const& collision, DptDptFullTracks const& ftracks, aod::BCsWithTimestamps const&) { processReconstructed(collision, ftracks, 50.0); } -void DptDptFilter::processWithCentDetectorLevel(aod::CollisionEvSelCent const& collision, DptDptFullTracksDetLevel const& ftracks, aod::McParticles const&) +void DptDptFilter::processWithCentDetectorLevel(aod::CollisionEvSelCent const& collision, DptDptFullTracksDetLevel const& ftracks, aod::McParticles const&, aod::BCsWithTimestamps const&) { processReconstructed(collision, ftracks, getCentMultPercentile(collision)); } -void DptDptFilter::processWithRun2CentDetectorLevel(aod::CollisionEvSelRun2Cent const& collision, DptDptFullTracksDetLevel const& ftracks, aod::McParticles const&) +void DptDptFilter::processWithRun2CentDetectorLevel(aod::CollisionEvSelRun2Cent const& collision, DptDptFullTracksDetLevel const& ftracks, aod::McParticles const&, aod::BCsWithTimestamps const&) { processReconstructed(collision, ftracks, getCentMultPercentile(collision)); } -void DptDptFilter::processWithoutCentDetectorLevel(aod::CollisionEvSel const& collision, DptDptFullTracksDetLevel const& ftracks, aod::McParticles const&) +void DptDptFilter::processWithoutCentDetectorLevel(aod::CollisionEvSel const& collision, DptDptFullTracksDetLevel const& ftracks, aod::McParticles const&, aod::BCsWithTimestamps const&) { processReconstructed(collision, ftracks, 50.0); } template -void DptDptFilter::processGenerated(CollisionObject const& mccollision, ParticlesList const&, float centormult) +bool DptDptFilter::processGenerated(CollisionObject const& mccollision, ParticlesList const&, float centormult) { using namespace dptdptfilter; uint8_t acceptedevent = uint8_t(false); - if (IsEvtSelected(mccollision, centormult)) { + if (isEventSelected(mccollision, centormult)) { acceptedevent = uint8_t(true); } if (fullDerivedData) { @@ -411,6 +661,7 @@ void DptDptFilter::processGenerated(CollisionObject const& mccollision, Particle } else { gencollisionsinfo(acceptedevent, centormult); } + return static_cast(acceptedevent); } template @@ -429,13 +680,14 @@ void DptDptFilter::processGeneratorLevel(aod::McCollision const& mccollision, } bool processed = false; - for (auto& tmpcollision : collisions) { + for (auto const& tmpcollision : collisions) { if (tmpcollision.has_mcCollision()) { if (tmpcollision.mcCollisionId() == mccollision.globalIndex()) { typename AllCollisions::iterator const& collision = allcollisions.iteratorAt(tmpcollision.globalIndex()); - if (IsEvtSelected(collision, defaultcent)) { - fhTrueVertexZAA->Fill((mccollision.posZ())); - processGenerated(mccollision, mcparticles, defaultcent); + if (isEventSelected(collision, defaultcent)) { + if (processGenerated(mccollision, mcparticles, defaultcent)) { + fhTrueVertexZAA->Fill((mccollision.posZ())); + } processed = true; break; /* TODO: only processing the first reconstructed accepted collision */ } @@ -471,13 +723,33 @@ void DptDptFilter::processWithoutCentGeneratorLevel(aod::McCollision const& mcco processGeneratorLevel(mccollision, collisions, mcparticles, allcollisions, 50.0); } +void DptDptFilter::processOnTheFlyGeneratorLevel(aod::McCollision const& mccollision, + aod::McParticles const& mcparticles) +{ + uint8_t acceptedEvent = uint8_t(false); + fhTrueVertexZB->Fill(mccollision.posZ()); + /* we assign a default value for the time being */ + float centormult = 50.0f; + if (isEventSelected(mccollision, centormult)) { + acceptedEvent = true; + multiplicity.extractMultiplicity(mcparticles); + fhTrueVertexZA->Fill((mccollision.posZ())); + centormult = multiplicity.getMultiplicityClass(); + } + if (fullDerivedData) { + acceptedtrueevents(mccollision.bcId(), mccollision.posZ(), acceptedEvent, centormult); + } else { + gencollisionsinfo(acceptedEvent, centormult); + } +} + void DptDptFilter::processVertexGenerated(aod::McCollisions const& mccollisions) { for (aod::McCollision const& mccollision : mccollisions) { fhTrueVertexZB->Fill(mccollision.posZ()); /* we assign a default value */ float centmult = 50.0f; - if (IsEvtSelected(mccollision, centmult)) { + if (isEventSelected(mccollision, centmult)) { fhTrueVertexZA->Fill((mccollision.posZ())); } } @@ -493,10 +765,10 @@ T computeRMS(std::vector& vec) std::vector diff(vec.size()); std::transform(vec.begin(), vec.end(), diff.begin(), [mean](T x) { return x - mean; }); - T sq_sum = std::inner_product(diff.begin(), diff.end(), diff.begin(), 0.0); - T stdev = std::sqrt(sq_sum / vec.size()); + T sqSum = std::inner_product(diff.begin(), diff.end(), diff.begin(), 0.0); + T stdDev = std::sqrt(sqSum / vec.size()); - return stdev; + return stdDev; } struct DptDptFilterTracks { @@ -514,12 +786,14 @@ struct DptDptFilterTracks { std::string cfgCCDBDate{"20220307"}; std::string cfgCCDBPeriod{"LHC22o"}; + Configurable cfgOutDebugInfo{"outdebuginfo", false, "Out detailed debug information per track into a text file. Default false"}; Configurable cfgFullDerivedData{"fullderiveddata", false, "Produce the full derived data for external storage. Default false"}; Configurable cfgTrackType{"trktype", 4, "Type of selected tracks: 0 = no selection;1 = Run2 global tracks FB96;3 = Run3 tracks;4 = Run3 tracks MM sel;5 = Run2 TPC only tracks;7 = Run 3 TPC only tracks;30-33 = any/two on 3 ITS,any/all in 7 ITS;40-43 same as 30-33 w tighter DCAxy;50-53 w tighter pT DCAz. Default 4"}; + Configurable cfgOnlyInOneSide{"onlyinoneside", false, "select tracks that don't cross the TPC central membrane. Default false"}; Configurable cfgTraceDCAOutliers{"trackdcaoutliers", {false, 0.0, 0.0}, "Track the generator level DCAxy outliers: false/true, low dcaxy, up dcaxy. Default {false,0.0,0.0}"}; Configurable cfgTraceOutOfSpeciesParticles{"trackoutparticles", false, "Track the particles which are not e,mu,pi,K,p: false/true. Default false"}; Configurable cfgRecoIdMethod{"recoidmethod", 0, "Method for identifying reconstructed tracks: 0 No PID, 1 PID, 2 mcparticle, 3 mcparticle only primaries, 4 mcparticle only sec, 5 mcparicle only sec from decays, 6 mcparticle only sec from material. Default 0"}; - Configurable cfgTuneTrackSelection{"tunetracksel", {}, "Track selection: {useit: true/false, tpccls-useit, tpcxrws-useit, tpcxrfc-useit, dcaxy-useit, dcaz-useit}. Default {false,0.70,false,0.8,false,2.4,false,3.2,false}"}; + Configurable cfgTuneTrackSelection{"tunetracksel", {}, "Track selection: {useit: true/false, tpccls-useit, tpcxrws-useit, tpcxrfc-useit, tpcshcls-useit, dcaxy-useit, dcaz-useit}. Default {false,0.70,false,0.8,false,0.4,false,2.4,false,3.2,false}"}; Configurable cfgPionPIDSelection{"pipidsel", {}, "PID criteria for pions"}; @@ -537,9 +811,12 @@ struct DptDptFilterTracks { "PID criteria for muons"}; OutputObj fOutput{"DptDptFilterTracksInfo", OutputObjHandlingPolicy::AnalysisObject}; + Service fPDG; PIDSpeciesSelection pidselector; bool checkAmbiguousTracks = false; + std::vector particleReconstructed; + void init(InitContext& initContext) { LOGF(info, "DptDptFilterTracks::init()"); @@ -558,19 +835,51 @@ struct DptDptFilterTracks { getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mEtabins", etabins, false); getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mEtamin", etalow, false); getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mEtamax", etaup, false); - + getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mPhibins", phibins, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mPhibinshift", phibinshift, false); + + TpcExclusionMethod tpcExclude = kNOEXCLUSION; ///< exclude tracks within the TPC according to this method + std::string pLowCut; + std::string pUpCut; + std::string nLowCut; + std::string nUpCut; + { + int tmpTpcExclude = 0; + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgTpcExclusion.method", tmpTpcExclude, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgTpcExclusion.positiveLowCut", pLowCut, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgTpcExclusion.positiveUpCut", pUpCut, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgTpcExclusion.negativeLowCut", nLowCut, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgTpcExclusion.negativeUpCut", nUpCut, false); + tpcExclude = static_cast(tmpTpcExclude); + } /* self configure the CCDB access to the input file */ getTaskOptionValue(initContext, "dpt-dpt-filter", "input_ccdburl", cfgCCDBUrl, false); getTaskOptionValue(initContext, "dpt-dpt-filter", "input_ccdbpath", cfgCCDBPathName, false); getTaskOptionValue(initContext, "dpt-dpt-filter", "input_ccdbdate", cfgCCDBDate, false); getTaskOptionValue(initContext, "dpt-dpt-filter", "input_ccdbperiod", cfgCCDBPeriod, false); + /* create the output list which will own the task histograms */ + TList* fOutputList = new TList(); + fOutputList->SetOwner(true); + fOutput.setObject(fOutputList); + /* the track types and combinations */ tracktype = cfgTrackType.value; - initializeTrackSelection(cfgTuneTrackSelection); + + /* incorporate configuration parameters to the output */ + fOutputList->Add(new TParameter("TrackType", cfgTrackType, 'f')); + fOutputList->Add(new TParameter("TrackOneCharge", 1, 'f')); + fOutputList->Add(new TParameter("TrackTwoCharge", -1, 'f')); + + DptDptTrackSelection::initializeTrackSelection(cfgTuneTrackSelection.value, fOutputList); traceDCAOutliers = cfgTraceDCAOutliers; traceOutOfSpeciesParticles = cfgTraceOutOfSpeciesParticles; recoIdMethod = cfgRecoIdMethod; + onlyInOneSide = cfgOnlyInOneSide.value; + + /* the TPC excluder object instance */ + tpcExcluder = TpcExcludeTrack(tpcExclude); + tpcExcluder.setCuts(pLowCut, pUpCut, nLowCut, nUpCut); /* self configure system type and data type */ /* if the system type is not known at this time, we have to put the initialization somewhere else */ @@ -579,10 +888,10 @@ struct DptDptFilterTracks { fSystem = getSystemType(tmpstr); getTaskOptionValue(initContext, "dpt-dpt-filter", "datatype", tmpstr, false); fDataType = getDataType(tmpstr); - fPDG = TDatabasePDG::Instance(); /* required ambiguous tracks checks? */ - if (dofilterDetectorLevelWithoutPIDAmbiguous || dofilterDetectorLevelWithPIDAmbiguous || dofilterRecoWithoutPIDAmbiguous || dofilterRecoWithPIDAmbiguous) { + if (dofilterDetectorLevelWithoutPIDAmbiguous || dofilterDetectorLevelWithPIDAmbiguous || dofilterDetectorLevelWithFullPIDAmbiguous || + dofilterRecoWithoutPIDAmbiguous || dofilterRecoWithPIDAmbiguous || dofilterRecoWithFullPIDAmbiguous) { checkAmbiguousTracks = true; } @@ -590,10 +899,10 @@ struct DptDptFilterTracks { auto insertInPIDselector = [&](auto cfg, uint sp) { if (cfg.value.mUseIt) { if (cfg.value.mExclude) { - pidselector.AddExclude(sp, &(cfg.value)); + pidselector.addExcludedSpecies(sp, &(cfg.value)); LOGF(info, "Incorporated species: %s to PID selection for exclusion", pidselector.spnames[sp].data()); } else { - pidselector.Add(sp, &(cfg.value)); + pidselector.addSpecies(sp, &(cfg.value)); LOGF(info, "Incorporated species: %s to PID selection", pidselector.spnames[sp].data()); } } @@ -604,16 +913,6 @@ struct DptDptFilterTracks { insertInPIDselector(cfgKaonPIDSelection, 3); insertInPIDselector(cfgProtonPIDSelection, 4); - /* create the output list which will own the task histograms */ - TList* fOutputList = new TList(); - fOutputList->SetOwner(true); - fOutput.setObject(fOutputList); - - /* incorporate configuration parameters to the output */ - fOutputList->Add(new TParameter("TrackType", cfgTrackType, 'f')); - fOutputList->Add(new TParameter("TrackOneCharge", 1, 'f')); - fOutputList->Add(new TParameter("TrackTwoCharge", -1, 'f')); - if ((fDataType == kData) || (fDataType == kDataNoEvtSel) || (fDataType == kMC)) { /* create the reconstructed data histograms */ fhPB = new TH1F("fHistPB", "p distribution for reconstructed before;p (GeV/c);dN/dp (c/GeV)", 100, 0.0, 15.0); @@ -811,6 +1110,12 @@ struct DptDptFilterTracks { ccdb->setURL(cfgCCDBUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); + /* the debug info output file if required */ + if (cfgOutDebugInfo) { + debugstream.open("tracings.csv"); + debugstream << "p,piw,pt,hastof,dEdx,beta,tpcnEl,tpcnMu,tpcnPi,tpcnKa,tpcnPr,tofnEl,tofnMu,tofnPi,tofnKa,tofnPr,tpcnElSft,tpcnMuSft,tpcnPiSft,tpcnKaSft,tpcnPrSft,tofnElSft,tofnMuSft,tofnPiSft,tofnKaSft,tofnPrSft,idcode,pid,pid2,truepid,phprim,process\n"; + debugstream.close(); + } } void getCCDBInformation() @@ -828,11 +1133,11 @@ struct DptDptFilterTracks { } } - template + template int8_t trackIdentification(TrackObject const& track); - template + template int8_t selectTrack(TrackObject const& track); - template + template int8_t selectTrackAmbiguousCheck(CollisionObjects const& collisions, TrackObject const& track); template int8_t identifyParticle(ParticleObject const& particle); @@ -862,7 +1167,7 @@ struct DptDptFilterTracks { /* TODO: as it is now when the derived data is stored (fullDerivedData = true) */ /* the collision index stored with the track is wrong. This has to be fixed */ - template + template void filterTracks(soa::Join const& collisions, passedtracks const& tracks) { @@ -874,15 +1179,15 @@ struct DptDptFilterTracks { if (!fullDerivedData) { tracksinfo.reserve(tracks.size()); } - for (auto collision : collisions) { + for (auto const& collision : collisions) { if (collision.collisionaccepted()) { ncollaccepted++; } } - for (auto track : tracks) { + for (auto const& track : tracks) { int8_t pid = -1; if (track.has_collision() && (track.template collision_as>()).collisionaccepted()) { - pid = selectTrackAmbiguousCheck(collisions, track); + pid = selectTrackAmbiguousCheck(collisions, track); if (!(pid < 0)) { naccepted++; if (fullDerivedData) { @@ -913,6 +1218,26 @@ struct DptDptFilterTracks { tracks.size()); } + /* filter the tracks but not creating the filtered tracks table */ + /* the aim is to fill the structure of the generated particles */ + /* that were reconstructed */ + template + void filterTracksSpecial(soa::Join const&, passedtracks const& tracks) + { + /* do check for special adjustments */ + getCCDBInformation(); + + for (auto const& track : tracks) { + int8_t pid = -1; + if (track.has_collision() && (track.template collision_as>()).collisionaccepted()) { + pid = selectTrack>(track); + if (!(pid < 0)) { + particleReconstructed[track.mcParticleId()] = true; + } + } + } + } + /* TODO: for the time being the full derived data is still not supported */ /* for doing that we need to get the index of the associated mc collision */ void filterParticles(soa::Join const& gencollisions, aod::McParticles const& particles) @@ -925,16 +1250,17 @@ struct DptDptFilterTracks { gentracksinfo.reserve(particles.size()); } - for (auto gencoll : gencollisions) { + for (auto const& gencoll : gencollisions) { if (gencoll.collisionaccepted()) { acceptedcollisions++; } } - for (auto& particle : particles) { - float charge = getCharge(particle); - + for (auto const& particle : particles) { int8_t pid = -1; + auto pdgpart = fPDG->GetParticle(particle.pdgCode()); + float charge = pdgpart != nullptr ? getCharge(pdgpart->Charge()) : 0; + if (charge != 0) { if (particle.has_mcCollision() && (particle.template mcCollision_as>()).collisionaccepted()) { auto mccollision = particle.template mcCollision_as>(); @@ -961,75 +1287,140 @@ struct DptDptFilterTracks { particles.size()); } + /* we produce the derived particle table incoporating only the particles that were accepted but not were reconstructed */ + void filterParticlesSpecial(soa::Join const& gencollisions, aod::McParticles const& particles) + { + using namespace dptdptfilter; + + int acceptedparticles = 0; + int acceptedcollisions = 0; + if (!fullDerivedData) { + gentracksinfo.reserve(particles.size()); + } + + for (auto const& gencoll : gencollisions) { + if (gencoll.collisionaccepted()) { + acceptedcollisions++; + } + } + + for (auto const& particle : particles) { + int8_t pid = -1; + auto pdgpart = fPDG->GetParticle(particle.pdgCode()); + float charge = pdgpart != nullptr ? getCharge(pdgpart->Charge()) : 0; + + if (charge != 0) { + if (particle.has_mcCollision() && (particle.template mcCollision_as>()).collisionaccepted()) { + auto mccollision = particle.template mcCollision_as>(); + pid = selectParticle(particle, mccollision); + if (!(pid < 0)) { + if (particleReconstructed[particle.globalIndex()]) { + /* the particle was reconstructed and accepted, reject it */ + pid = -1; + } else { + acceptedparticles++; + } + } + } + } else { + if ((particle.mcCollisionId() == 0) && traceCollId0) { + LOGF(DPTDPTFILTERLOGTRACKS, "Particle %d with fractional charge or equal to zero", particle.globalIndex()); + } + } + if (!fullDerivedData) { + gentracksinfo(pid); + } + } + LOGF(DPTDPTFILTERLOGCOLLISIONS, + "Processed %d accepted generated collisions out of a total of %d with %d accepted particles out of a " + "total of %d", + acceptedcollisions, + gencollisions.size(), + acceptedparticles, + particles.size()); + } + + template + void doFilterTracks(soa::Join const& collisions, passedtracks const& tracks) + { + if (cfgOutDebugInfo) { + debugstream.open("tracings.csv", std::ios::app); + filterTracks(collisions, tracks); + debugstream.close(); + } else { + filterTracks(collisions, tracks); + } + } + void filterRecoWithPID(soa::Join& collisions, DptDptFullTracksPID const& tracks) { - filterTracks(collisions, tracks); + doFilterTracks(collisions, tracks); } PROCESS_SWITCH(DptDptFilterTracks, filterRecoWithPID, "Not stored derived data track filtering", false) void filterRecoWithFullPID(soa::Join& collisions, DptDptFullTracksFullPID const& tracks) { - filterTracks(collisions, tracks); + doFilterTracks(collisions, tracks); } PROCESS_SWITCH(DptDptFilterTracks, filterRecoWithFullPID, "Not stored derived data track filtering", false) void filterRecoWithPIDAmbiguous(soa::Join& collisions, DptDptFullTracksPIDAmbiguous const& tracks) { - filterTracks(collisions, tracks); + doFilterTracks(collisions, tracks); } PROCESS_SWITCH(DptDptFilterTracks, filterRecoWithPIDAmbiguous, "Not stored derived data track filtering with ambiguous tracks check", false) void filterRecoWithFullPIDAmbiguous(soa::Join& collisions, DptDptFullTracksFullPIDAmbiguous const& tracks) { - filterTracks(collisions, tracks); + doFilterTracks(collisions, tracks); } PROCESS_SWITCH(DptDptFilterTracks, filterRecoWithFullPIDAmbiguous, "Not stored derived data track filtering with ambiguous tracks check", false) void filterDetectorLevelWithPID(soa::Join& collisions, DptDptFullTracksPIDDetLevel const& tracks, aod::McParticles const&) { - filterTracks(collisions, tracks); + doFilterTracks(collisions, tracks); } PROCESS_SWITCH(DptDptFilterTracks, filterDetectorLevelWithPID, "Not stored derived data detector level track filtering", false) void filterDetectorLevelWithFullPID(soa::Join& collisions, DptDptFullTracksFullPIDDetLevel const& tracks, aod::McParticles const&) { - filterTracks(collisions, tracks); + doFilterTracks(collisions, tracks); } PROCESS_SWITCH(DptDptFilterTracks, filterDetectorLevelWithFullPID, "Not stored derived data detector level track filtering", false) void filterDetectorLevelWithPIDAmbiguous(soa::Join& collisions, DptDptFullTracksPIDDetLevelAmbiguous const& tracks, aod::McParticles const&) { - filterTracks(collisions, tracks); + doFilterTracks(collisions, tracks); } PROCESS_SWITCH(DptDptFilterTracks, filterDetectorLevelWithPIDAmbiguous, "Not stored derived data detector level track filtering with ambiguous tracks check", false) void filterDetectorLevelWithFullPIDAmbiguous(soa::Join& collisions, DptDptFullTracksFullPIDDetLevelAmbiguous const& tracks, aod::McParticles const&) { - filterTracks(collisions, tracks); + doFilterTracks(collisions, tracks); } PROCESS_SWITCH(DptDptFilterTracks, filterDetectorLevelWithFullPIDAmbiguous, "Not stored derived data detector level track filtering with ambiguous tracks check", false) void filterRecoWithoutPID(soa::Join const& collisions, DptDptFullTracks const& tracks) { - filterTracks(collisions, tracks); + doFilterTracks(collisions, tracks); } PROCESS_SWITCH(DptDptFilterTracks, filterRecoWithoutPID, "Track filtering without PID information", true) void filterRecoWithoutPIDAmbiguous(soa::Join const& collisions, DptDptFullTracksAmbiguous const& tracks) { - filterTracks(collisions, tracks); + doFilterTracks(collisions, tracks); } PROCESS_SWITCH(DptDptFilterTracks, filterRecoWithoutPIDAmbiguous, "Track filtering without PID information with ambiguous tracks check", false) void filterDetectorLevelWithoutPID(soa::Join const& collisions, DptDptFullTracksDetLevel const& tracks, aod::McParticles const&) { - filterTracks(collisions, tracks); + doFilterTracks(collisions, tracks); } PROCESS_SWITCH(DptDptFilterTracks, filterDetectorLevelWithoutPID, "Detector level track filtering without PID information", false) void filterDetectorLevelWithoutPIDAmbiguous(soa::Join const& collisions, DptDptFullTracksDetLevelAmbiguous const& tracks, aod::McParticles const&) { - filterTracks(collisions, tracks); + doFilterTracks(collisions, tracks); } PROCESS_SWITCH(DptDptFilterTracks, filterDetectorLevelWithoutPIDAmbiguous, "Detector level track filtering without PID information with ambiguous tracks check", false) @@ -1038,9 +1429,29 @@ struct DptDptFilterTracks { filterParticles(gencollisions, particles); } PROCESS_SWITCH(DptDptFilterTracks, filterGenerated, "Generated particles filtering", true) + + void filterGeneratedNotReconstructed(soa::Join const& gencollisions, aod::McParticles const& particles, + soa::Join& collisions, DptDptFullTracksPIDDetLevel const& tracks) + { + particleReconstructed.resize(particles.size()); + filterTracksSpecial(collisions, tracks); + filterParticlesSpecial(gencollisions, particles); + particleReconstructed.clear(); + } + PROCESS_SWITCH(DptDptFilterTracks, filterGeneratedNotReconstructed, "Generated particles filtering selecting not reconstructed using PID", false) + + void filterGeneratedNotReconstructedWithoutPID(soa::Join const& gencollisions, aod::McParticles const& particles, + soa::Join& collisions, DptDptFullTracksDetLevel const& tracks) + { + particleReconstructed.resize(particles.size()); + filterTracksSpecial(collisions, tracks); + filterParticlesSpecial(gencollisions, particles); + particleReconstructed.clear(); + } + PROCESS_SWITCH(DptDptFilterTracks, filterGeneratedNotReconstructedWithoutPID, "Generated particles filtering selecting not reconstructed inclusive", false) }; -template +template int8_t DptDptFilterTracks::trackIdentification(TrackObject const& track) { using namespace dptdptfilter; @@ -1050,7 +1461,7 @@ int8_t DptDptFilterTracks::trackIdentification(TrackObject const& track) sp = 0; } else if (recoIdMethod == 1) { if constexpr (framework::has_type_v || framework::has_type_v) { - sp = pidselector.whichSpecies(track); + sp = pidselector.whichSpecies(track); } else { LOGF(fatal, "Track identification required but PID information not present"); } @@ -1082,7 +1493,7 @@ int8_t DptDptFilterTracks::trackIdentification(TrackObject const& track) return sp; } -template +template int8_t DptDptFilterTracks::selectTrack(TrackObject const& track) { using namespace dptdptfilter; @@ -1092,10 +1503,10 @@ int8_t DptDptFilterTracks::selectTrack(TrackObject const& track) /* track selection */ int8_t sp = -127; - if (AcceptTrack(track)) { + if (acceptTrack(track)) { /* the track has been accepted */ /* let's identify it */ - sp = trackIdentification(track); + sp = trackIdentification(track); if (!(sp < 0)) { /* fill the species histograms */ fillTrackHistosAfterSelection(track, sp); @@ -1114,7 +1525,7 @@ int8_t DptDptFilterTracks::selectTrack(TrackObject const& track) return sp; } -template +template int8_t DptDptFilterTracks::selectTrackAmbiguousCheck(CollisionObjects const& collisions, TrackObject const& track) { bool ambiguoustrack = false; @@ -1147,24 +1558,24 @@ int8_t DptDptFilterTracks::selectTrackAmbiguousCheck(CollisionObjects const& col } } - float multiplicityclass = (track.template collision_as>()).centmult(); + float multiplicityClass = (track.template collision_as()).centmult(); if (ambiguoustrack) { /* keep track of ambiguous tracks */ - fhAmbiguousTrackType->Fill(ambtracktype, multiplicityclass); - fhAmbiguousTrackPt->Fill(track.pt(), multiplicityclass); - fhAmbiguityDegree->Fill(zvertexes.size(), multiplicityclass); + fhAmbiguousTrackType->Fill(ambtracktype, multiplicityClass); + fhAmbiguousTrackPt->Fill(track.pt(), multiplicityClass); + fhAmbiguityDegree->Fill(zvertexes.size(), multiplicityClass); if (ambtracktype == 2) { - fhCompatibleCollisionsZVtxRms->Fill(-computeRMS(zvertexes), multiplicityclass); + fhCompatibleCollisionsZVtxRms->Fill(-computeRMS(zvertexes), multiplicityClass); } else { - fhCompatibleCollisionsZVtxRms->Fill(computeRMS(zvertexes), multiplicityclass); + fhCompatibleCollisionsZVtxRms->Fill(computeRMS(zvertexes), multiplicityClass); } return -1; } else { if (checkAmbiguousTracks) { /* feedback of no ambiguous tracks only if checks required */ - fhAmbiguousTrackType->Fill(ambtracktype, multiplicityclass); + fhAmbiguousTrackType->Fill(ambtracktype, multiplicityClass); } - return selectTrack(track); + return selectTrack(track); } } @@ -1244,14 +1655,15 @@ inline int8_t DptDptFilterTracks::identifySecFromMaterialParticle(ParticleObject template inline int8_t DptDptFilterTracks::selectParticle(ParticleObject const& particle, MCCollisionObject const& mccollision) { - float charge = getCharge(particle); int8_t sp = -127; + auto pdgpart = fPDG->GetParticle(particle.pdgCode()); + float charge = pdgpart != nullptr ? getCharge(pdgpart->Charge()) : 0; if (charge != 0) { /* before particle selection */ fillParticleHistosBeforeSelection(particle, mccollision, charge); /* track selection */ - if (AcceptParticle(particle, mccollision)) { + if (acceptParticle(particle, mccollision)) { /* the particle has been accepted */ /* the particle is only accepted if it is a primary particle */ /* let's identify the particle */ @@ -1288,14 +1700,14 @@ void DptDptFilterTracks::fillParticleHistosBeforeSelection(ParticleObject const& fhTruePtNegB->Fill(particle.pt()); } - float dcaxy = TMath::Sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + - (particle.vy() - collision.posY()) * (particle.vy() - collision.posY())); + float dcaxy = std::sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + + (particle.vy() - collision.posY()) * (particle.vy() - collision.posY())); if (traceDCAOutliers.mDoIt && (traceDCAOutliers.mLowValue < dcaxy) && (dcaxy < traceDCAOutliers.mUpValue)) { fhTrueDCAxyBid->Fill(TString::Format("%d", particle.pdgCode()).Data(), 1.0); } - fhTrueDCAxyB->Fill(TMath::Sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + - (particle.vy() - collision.posY()) * (particle.vy() - collision.posY()))); + fhTrueDCAxyB->Fill(std::sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + + (particle.vy() - collision.posY()) * (particle.vy() - collision.posY()))); fhTrueDCAzB->Fill((particle.vz() - collision.posZ())); } @@ -1304,16 +1716,16 @@ void DptDptFilterTracks::fillParticleHistosAfterSelection(ParticleObject const& { fhTrueEtaA->Fill(particle.eta()); fhTruePhiA->Fill(particle.phi()); - float dcaxy = TMath::Sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + - (particle.vy() - collision.posY()) * (particle.vy() - collision.posY())); + float dcaxy = std::sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + + (particle.vy() - collision.posY()) * (particle.vy() - collision.posY())); if (traceDCAOutliers.mDoIt && (traceDCAOutliers.mLowValue < dcaxy) && (dcaxy < traceDCAOutliers.mUpValue)) { LOGF(info, "DCAxy outlier: Particle with index %d and pdg code %d assigned to MC collision %d, pT: %f, phi: %f, eta: %f", particle.globalIndex(), particle.pdgCode(), particle.mcCollisionId(), particle.pt(), particle.phi(), particle.eta()); LOGF(info, " With status %d and flags %0X", particle.statusCode(), particle.flags()); } - fhTrueDCAxyA->Fill(TMath::Sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + - (particle.vy() - collision.posY()) * (particle.vy() - collision.posY()))); + fhTrueDCAxyA->Fill(std::sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + + (particle.vy() - collision.posY()) * (particle.vy() - collision.posY()))); fhTrueDCAzA->Fill((particle.vz() - collision.posZ())); fhTruePA[sp]->Fill(particle.p()); fhTruePtA[sp]->Fill(particle.pt()); diff --git a/PWGCF/TableProducer/dptdptfilter.h b/PWGCF/TableProducer/dptdptfilter.h index afcd9f0df6c..474e341907d 100644 --- a/PWGCF/TableProducer/dptdptfilter.h +++ b/PWGCF/TableProducer/dptdptfilter.h @@ -8,17 +8,25 @@ // 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 dptdptfilter.h +/// \brief Filters collisions and tracks according to selection criteria +/// \author victor.gonzalez.sebastian@gmail.com + #ifndef PWGCF_TABLEPRODUCER_DPTDPTFILTER_H_ #define PWGCF_TABLEPRODUCER_DPTDPTFILTER_H_ #include +#include #include #include +#include #include #include -#include +#include #include #include +#include #include #include @@ -29,10 +37,10 @@ #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" #include "PWGCF/Core/AnalysisConfigurableCuts.h" -#include namespace o2 { @@ -93,19 +101,94 @@ enum CentMultEstimatorType { /// \enum TriggerSelectionType /// \brief The type of trigger to apply for event selection enum TriggerSelectionType { - kNONE = 0, ///< do not use trigger selection - kMB, ///< Minimum bias trigger - kVTXTOFMATCHED, ///< at least one vertex contributor is matched to TOF - kVTXTRDMATCHED, ///< at least one vertex contributor is matched to TRD - kVTXTRDTOFMATCHED, ///< at least one vertex contributor is matched to TRD and TOF - knEventSelection ///< number of triggers for event selection + kNONE = 0, ///< do not use trigger selection + kMB, ///< Minimum bias trigger + kMBEXTRA, ///< Additional Run3 event quality + kVTXTOFMATCHED, ///< at least one vertex contributor is matched to TOF + kVTXTRDMATCHED, ///< at least one vertex contributor is matched to TRD + kVTXTRDTOFMATCHED, ///< at least one vertex contributor is matched to TRD and TOF + kEXTRAVTXTOFMATCHED, ///< Additional Run3 event quality and at least one vertex contributor is matched to TOF + kEXTRAVTXTRDMATCHED, ///< Additional Run3 event quality and at least one vertex contributor is matched to TRD + kEXTRAVTXTRDTOFMATCHED, ///< Additional Run3 event quality and at least one vertex contributor is matched to TRD and TOF + knEventSelection ///< number of triggers for event selection +}; + +/// \enum OccupancyEstimationType +/// \brief The type of occupancy estimation +enum OccupancyEstimationType { + kNOOCC = 0, ///< do not use occupancy estimation + kTRACKSOCC, ///< occupancy estimated using tracks + kFT0COCC, ///< occupancy estimated using the FT0C + knOccupancyEstimators ///< the number of occupancy estimators +}; + +/// \enum CollisionSelectionFlags +/// \brief The different criteria for selecting/rejecting collisions +enum CollisionSelectionFlags { + kIN = 0, ///< new unhandled, yet, event + kMBBIT, ///< minimum bias + kINT7BIT, ///< INT7 Run 1/2 + kSEL7BIT, ///< Sel7 Run 1/2 + kSEL8BIT, ///< Sel8 + kNOSAMEBUNCHPUPBIT, ///< no same bunch pile up + kISGOODZVTXFT0VSPVBIT, ///< good zvtx FT0 vs PV + kISVERTEXITSTPCBIT, ///< is vertex TPC and ITS + kISVERTEXTOFMATCHEDBIT, ///< vertex contributor with TOF matched + kISVERTEXTRDMATCHEDBIT, ///< vertex contributor with TRD matche + kNOCOLLINTIMERANGEBIT, ///< no collision in time range + kNOCOLLINROFBIT, ///< no collision in readout + kOCCUPANCYBIT, ///< occupancy within limits + kISGOODITSLAYER3BIT, ///< right level of inactive chips for ITS layer 3 + kISGOODITSLAYER0123BIT, ///< right level of inactive chips for ITS layers 0,1,2, and 3 + kISGOODITSLAYERALLBIT, ///< right level of inactive chips for all seven ITS layers + kCENTRALITYBIT, ///< centrality cut passed + kZVERTEXBIT, ///< zvtx cut passed + kSELECTED, ///< the event has passed all selections + knCollisionSelectionFlags ///< number of flags +}; + +/// \enum StrongDebugging +/// \brief Enable a per track information debugging. Only for local analyses +enum StrongDebugging { + kNODEBUG = 0, ///< do not debug + kDEBUG ///< output debugging information on a per track basis to a text file +}; + +/// \enum TpcExclusionMethod +/// \brief Methods for excluding tracks witin the TPC +enum TpcExclusionMethod { + kNOEXCLUSION = 0, ///< do not exclude tracks within the TPC + kSTATIC, ///< exclude tracks statically on the bins of the TPC sector borders; only valid if 72 bins and origin shifted by 0.5 + kDYNAMIC ///< pT dependent exclusion matching the sector borders a la Alex Dobrin +}; + +/// \enum ItsDeadMapsCheckType +/// \brief Check for the right level of ITS dead chips +enum ItsDeadMapsCheckType { + kNOCHECK = 0, ///< no check + kGOODITSLAYER3, ///< check good the 3 ITS layer + kGOODITSLAYER0123, ///< check good the 0,1,2,and 3 ITS layers + kGOODITSLAYERALL, ///< check good all ITS layers + kNOGOODITSLAYER3, ///< check no good the 3 ITS layer + kNOGOODITSLAYER0123, ///< check no good the 0,1,2,and 3 ITS layers + kNOGOODITSLAYERALL ///< check no good all ITS layers }; +//============================================================================================ +// The debug output stream +//============================================================================================ +std::ofstream debugstream; + //============================================================================================ // The overall minimum momentum //============================================================================================ float overallminp = 0.0f; +//============================================================================================ +// The collision selection flags and configuration objects +//============================================================================================ +std::bitset<32> collisionFlags; + //============================================================================================ // The DptDptFilter configuration objects //============================================================================================ @@ -116,32 +199,294 @@ float etalow = -0.8, etaup = 0.8; int zvtxbins = 40; float zvtxlow = -10.0, zvtxup = 10.0; int phibins = 72; -float philow = 0.0; +float philow = 0.0f; float phiup = constants::math::TwoPI; +float phibinshift = 0.0f; + +struct TpcExcludeTrack; ///< forward declaration of the excluder object +bool onlyInOneSide = false; ///< select only tracks that don't cross the TPC central membrane +extern TpcExcludeTrack tpcExcluder; ///< the TPC excluder object instance /* selection criteria from PWGMM */ // default quality criteria for tracks with ITS contribution -static constexpr o2::aod::track::TrackSelectionFlags::flagtype trackSelectionITS = +static constexpr o2::aod::track::TrackSelectionFlags::flagtype TrackSelectionITS = o2::aod::track::TrackSelectionFlags::kITSNCls | o2::aod::track::TrackSelectionFlags::kITSChi2NDF | o2::aod::track::TrackSelectionFlags::kITSHits; // default quality criteria for tracks with TPC contribution -static constexpr o2::aod::track::TrackSelectionFlags::flagtype trackSelectionTPC = +static constexpr o2::aod::track::TrackSelectionFlags::flagtype TrackSelectionTPC = o2::aod::track::TrackSelectionFlags::kTPCNCls | o2::aod::track::TrackSelectionFlags::kTPCCrossedRowsOverNCls | o2::aod::track::TrackSelectionFlags::kTPCChi2NDF; // default standard DCA cuts -static constexpr o2::aod::track::TrackSelectionFlags::flagtype trackSelectionDCA = +static constexpr o2::aod::track::TrackSelectionFlags::flagtype TrackSelectionDCA = o2::aod::track::TrackSelectionFlags::kDCAz | o2::aod::track::TrackSelectionFlags::kDCAxy; +struct DptDptTrackSelection; // forward struct declaration int tracktype = 1; -std::function maxDcaZPtDep{}; // max dca in z axis as function of pT +std::vector trackFilters = {}; // the vector of track selectors + +struct DptDptTrackSelection { + DptDptTrackSelection(TrackSelection* stdTs, TList* outputList, const char* name) : stdTrackSelection(stdTs) + { + passedHistogram = new TH1F(name, name, ptbins, ptlow, ptup); + outputList->Add(passedHistogram); + } + DptDptTrackSelection(TrackSelection* stdTs, std::function ptDepCut, TList* outputList, const char* name) + : stdTrackSelection(stdTs), + maxDcazPtDep(ptDepCut) + { + passedHistogram = new TH1F(name, name, ptbins, ptlow, ptup); + outputList->Add(passedHistogram); + } + void setMaxDcaXY(float max) + { + maxDCAxy = max; + stdTrackSelection->SetMaxDcaXY(max); + } + void setMaxDcaZ(float max) + { + maxDCAz = max; + stdTrackSelection->SetMaxDcaZ(max); + } + void setMaxDcazPtDep(std::function ptDepCut) + { + maxDcazPtDep = ptDepCut; + } + void setRequirePvContributor(bool pvc = true) + { + requirePvContributor = pvc; + } + + template + bool isSelected(TrackObject const& track) const + { + if (stdTrackSelection->IsSelected(track)) { + auto checkDca2Dcut = [&](auto const& track) { + if (dca2Dcut) { + if (track.dcaXY() * track.dcaXY() / maxDCAxy / maxDCAxy + track.dcaZ() * track.dcaZ() / maxDCAz / maxDCAz > 1) { + return false; + } else { + return true; + } + } else { + return true; + } + }; + auto checkDcaZcut = [&](auto const& track) { + return ((maxDcazPtDep) ? std::fabs(track.dcaZ()) <= maxDcazPtDep(track.pt()) : true); + }; + + /* tight pT dependent DCAz cut */ + if (!checkDcaZcut(track)) { + return false; + } + /* 2D DCA xy-o-z cut */ + if (!checkDca2Dcut(track)) { + return false; + } + /* primary vertex contributor */ + if (requirePvContributor) { + if (!track.isPVContributor()) { + return false; + } + } + passedHistogram->Fill(track.pt()); + return true; + } else { + return false; + } + } + + static void initializeTrackSelection(TrackSelectionTuneCfg& tune, TList* outputList) + { + auto addTrackFilter = [](auto filter) { + trackFilters.push_back(filter); + }; + auto highQualityTpcTrack = [](TList* outList, const char* name) { + DptDptTrackSelection* tpcTrack = new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelection()), outList, name); + tpcTrack->stdTrackSelection->ResetITSRequirements(); + tpcTrack->stdTrackSelection->SetRequireITSRefit(false); + tpcTrack->stdTrackSelection->SetMinNClustersTPC(120); + tpcTrack->stdTrackSelection->SetMaxTPCFractionSharedCls(0.2f); + return tpcTrack; + }; + auto highQualityItsOnlyTrack = [](TList* outList, const char* name) { + DptDptTrackSelection* itsTrack = new DptDptTrackSelection(new TrackSelection(), [](float pt) { return 0.004f + 0.013f / pt; }, outList, name); + itsTrack->stdTrackSelection->SetTrackType(o2::aod::track::TrackTypeEnum::Track); + itsTrack->stdTrackSelection->SetRequireITSRefit(true); + itsTrack->stdTrackSelection->SetRequireHitsInITSLayers(2, {0, 1, 2}); + itsTrack->stdTrackSelection->SetMaxChi2PerClusterITS(36.0f); + itsTrack->stdTrackSelection->SetMaxDcaXYPtDep([](float pt) { return 0.004f + 0.013f / pt; }); + return itsTrack; + }; + switch (tracktype) { + case 1: { /* Run2 global track */ + DptDptTrackSelection* globalRun2 = new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelection()), outputList, "TType1Global"); + globalRun2->stdTrackSelection->SetTrackType(o2::aod::track::Run2Track); // Run 2 track asked by default + globalRun2->stdTrackSelection->SetMaxChi2PerClusterTPC(2.5f); + DptDptTrackSelection* globalSDDRun2 = new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionSDD()), outputList, "TType1Sdd"); + globalSDDRun2->stdTrackSelection->SetTrackType(o2::aod::track::Run2Track); // Run 2 track asked by default + globalSDDRun2->stdTrackSelection->SetMaxChi2PerClusterTPC(2.5f); + addTrackFilter(globalRun2); + addTrackFilter(globalSDDRun2); + } break; + case 3: { /* Run3 track */ + DptDptTrackSelection* globalRun3 = new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelection()), outputList, "TType3Global"); + globalRun3->stdTrackSelection->SetTrackType(o2::aod::track::TrackTypeEnum::Track); + globalRun3->stdTrackSelection->ResetITSRequirements(); + globalRun3->stdTrackSelection->SetRequireHitsInITSLayers(1, {0, 1, 2}); + DptDptTrackSelection* globalSDDRun3 = new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelection()), outputList, "TType3Sdd"); + globalSDDRun3->stdTrackSelection->SetTrackType(o2::aod::track::TrackTypeEnum::Track); + globalSDDRun3->stdTrackSelection->ResetITSRequirements(); + globalSDDRun3->stdTrackSelection->SetRequireNoHitsInITSLayers({0, 1, 2}); + globalSDDRun3->stdTrackSelection->SetRequireHitsInITSLayers(1, {3}); + addTrackFilter(globalRun3); + addTrackFilter(globalSDDRun3); + } break; + case 5: { /* Run2 TPC only track */ + DptDptTrackSelection* tpcOnly = new DptDptTrackSelection(new TrackSelection, outputList, "TType5"); + tpcOnly->stdTrackSelection->SetTrackType(o2::aod::track::Run2Track); // Run 2 track asked by default + tpcOnly->stdTrackSelection->SetMinNClustersTPC(50); + tpcOnly->stdTrackSelection->SetMaxChi2PerClusterTPC(4); + tpcOnly->setMaxDcaZ(3.2f); + tpcOnly->setMaxDcaXY(2.4f); + tpcOnly->dca2Dcut = true; + addTrackFilter(tpcOnly); + } break; + case 7: { /* Run3 TPC only track */ + DptDptTrackSelection* tpcOnly = new DptDptTrackSelection(new TrackSelection, outputList, "TType7"); + tpcOnly->stdTrackSelection->SetTrackType(o2::aod::track::TrackTypeEnum::Track); + tpcOnly->stdTrackSelection->SetMinNClustersTPC(50); + tpcOnly->stdTrackSelection->SetMaxChi2PerClusterTPC(4); + tpcOnly->setMaxDcaZ(3.2f); + tpcOnly->setMaxDcaXY(2.4f); + tpcOnly->dca2Dcut = true; + addTrackFilter(tpcOnly); + } break; + case 10: { /* Run3 track primary vertex contributor */ + DptDptTrackSelection* globalRun3 = new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelection()), outputList, "TType10Global"); + globalRun3->stdTrackSelection->SetTrackType(o2::aod::track::TrackTypeEnum::Track); + globalRun3->stdTrackSelection->ResetITSRequirements(); + globalRun3->stdTrackSelection->SetRequireHitsInITSLayers(1, {0, 1, 2}); + globalRun3->setRequirePvContributor(true); + DptDptTrackSelection* globalSDDRun3 = new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelection()), outputList, "TType10Sdd"); + globalSDDRun3->stdTrackSelection->SetTrackType(o2::aod::track::TrackTypeEnum::Track); + globalSDDRun3->stdTrackSelection->ResetITSRequirements(); + globalSDDRun3->stdTrackSelection->SetRequireNoHitsInITSLayers({0, 1, 2}); + globalSDDRun3->stdTrackSelection->SetRequireHitsInITSLayers(1, {3}); + globalSDDRun3->setRequirePvContributor(true); + addTrackFilter(globalRun3); + addTrackFilter(globalSDDRun3); + } break; + case 30: { /* Run 3 default global track: kAny on 3 IB layers of ITS */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::Default)), outputList, "TType30")); + } break; + case 31: { /* Run 3 global track: kTwo on 3 IB layers of ITS */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibTwo, TrackSelection::GlobalTrackRun3DCAxyCut::Default)), outputList, "TType31")); + } break; + case 32: { /* Run 3 global track: kAny on all 7 layers of ITS */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSallAny, TrackSelection::GlobalTrackRun3DCAxyCut::Default)), outputList, "TType32")); + } break; + case 33: { /* Run 3 global track: kAll on all 7 layers of ITS */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSall7Layers, TrackSelection::GlobalTrackRun3DCAxyCut::Default)), outputList, "TType33")); + } break; + case 40: { /* Run 3 global track: kAny on 3 IB layers of ITS, tighter DCAxy */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3)), outputList, "TType40")); + } break; + case 41: { /* Run 3 global track: kTwo on 3 IB layers of ITS, tighter DCAxy */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibTwo, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3)), outputList, "TType41")); + } break; + case 42: { /* Run 3 global track: kAny on all 7 layers of ITS, tighter DCAxy */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSallAny, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3)), outputList, "TType42")); + } break; + case 43: { /* Run 3 global track: kAll on all 7 layers of ITS, tighter DCAxy */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSall7Layers, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3)), outputList, "TType43")); + } break; + case 50: { /* Run 3 global track: kAny on 3 IB layers of ITS, tighter DCAxy, tighter pT dep DCAz */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3)), [](float pt) { return 0.004f + 0.013f / pt; }, outputList, "TType50")); + } break; + case 51: { /* Run 3 global track: kTwo on 3 IB layers of ITS, tighter DCAxy, tighter pT dep DCAz */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibTwo, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3)), [](float pt) { return 0.004f + 0.013f / pt; }, outputList, "TType51")); + } break; + case 52: { /* Run 3 global track: kAny on all 7 layers of ITS, tighter DCAxy, tighter pT dep DCAz */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSallAny, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3)), [](float pt) { return 0.004f + 0.013f / pt; }, outputList, "TType52")); + } break; + case 53: { /* Run 3 global track: kAll on all 7 layers of ITS, tighter DCAxy, tighter pT dep DCAz */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSall7Layers, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3)), [](float pt) { return 0.004f + 0.013f / pt; }, outputList, "TType53")); + } break; + case 60: { /* Run 3 global track: kAny on 3 IB layers of ITS, tighter DCAxy, tighter pT dep DCAz, plus TPC+TOF only tracks */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3)), [](float pt) { return 0.004f + 0.013f / pt; }, outputList, "TType60Global")); + addTrackFilter(highQualityTpcTrack(outputList, "TType60Tpc")); + } break; + case 61: { /* Run 3 global track: kTwo on 3 IB layers of ITS, tighter DCAxy, tighter pT dep DCAz, plus TPC+TOF only tracks */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibTwo, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3)), [](float pt) { return 0.004f + 0.013f / pt; }, outputList, "TType61Global")); + addTrackFilter(highQualityTpcTrack(outputList, "TType61Tpc")); + } break; + case 62: { /* Run 3 global track: kAny on all 7 layers of ITS, tighter DCAxy, tighter pT dep DCAz, plus TPC+TOF only tracks */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSallAny, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3)), [](float pt) { return 0.004f + 0.013f / pt; }, outputList, "TType62Global")); + addTrackFilter(highQualityTpcTrack(outputList, "TType62Tpc")); + } break; + case 63: { /* Run 3 global track: kAll on all 7 layers of ITS, tighter DCAxy, tighter pT dep DCAz, plus TPC+TOF only tracks */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSall7Layers, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3)), [](float pt) { return 0.004f + 0.013f / pt; }, outputList, "TType63Global")); + addTrackFilter(highQualityTpcTrack(outputList, "TType63Tpc")); + } break; + case 70: { /* Run 3 global track: kAny on 3 IB layers of ITS, tighter DCAxy, tighter pT dep DCAz, plus ITS only tracks */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3)), [](float pt) { return 0.004f + 0.013f / pt; }, outputList, "TType70Global")); + addTrackFilter(highQualityItsOnlyTrack(outputList, "TType70Its")); + } break; + case 71: { /* Run 3 global track: kTwo on 3 IB layers of ITS, tighter DCAxy, tighter pT dep DCAz, plus ITS only tracks */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibTwo, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3)), [](float pt) { return 0.004f + 0.013f / pt; }, outputList, "TType71Global")); + addTrackFilter(highQualityItsOnlyTrack(outputList, "TType71Its")); + } break; + case 72: { /* Run 3 global track: kAny on all 7 layers of ITS, tighter DCAxy, tighter pT dep DCAz, plus ITS only tracks */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSallAny, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3)), [](float pt) { return 0.004f + 0.013f / pt; }, outputList, "TType72Global")); + addTrackFilter(highQualityItsOnlyTrack(outputList, "TType72Its")); + } break; + case 73: { /* Run 3 global track: kAll on all 7 layers of ITS, tighter DCAxy, tighter pT dep DCAz, plus ITS only tracks */ + addTrackFilter(new DptDptTrackSelection(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSall7Layers, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3)), [](float pt) { return 0.004f + 0.013f / pt; }, outputList, "TType73Global")); + addTrackFilter(highQualityItsOnlyTrack(outputList, "TType73Its")); + } break; + default: + break; + } + if (tune.mUseIt) { + for (auto const& filter : trackFilters) { + if (tune.mUseTPCclusters) { + filter->stdTrackSelection->SetMinNClustersTPC(tune.mTPCclusters); + } + if (tune.mUseTPCxRows) { + filter->stdTrackSelection->SetMinNCrossedRowsTPC(tune.mTPCxRows); + } + if (tune.mUseTPCXRoFClusters) { + filter->stdTrackSelection->SetMinNCrossedRowsOverFindableClustersTPC(tune.mTPCXRoFClusters); + } + if (tune.mUseDCAxy) { + /* DCAxy is tricky due to how the pT dependence is implemented */ + filter->stdTrackSelection->SetMaxDcaXYPtDep([&tune](float) { return tune.mDCAxy; }); + filter->setMaxDcaXY(tune.mDCAxy); + } + if (tune.mUseDCAz) { + /* DCAz is tricky due to how the pT dependence is implemented */ + filter->setMaxDcazPtDep([&tune](float) { return tune.mDCAz; }); + filter->setMaxDcaZ(tune.mDCAz); + } + if (tune.mUseFractionTpcSharedClusters) { + filter->stdTrackSelection->SetMaxTPCFractionSharedCls(tune.mFractionTpcSharedClusters); + } + } + } + } -std::vector trackFilters = {}; -bool dca2Dcut = false; -float maxDCAz = 1e6f; -float maxDCAxy = 1e6f; + float maxDCAxy = 1e6; + float maxDCAz = 1e6; + TrackSelection* stdTrackSelection = nullptr; + std::function maxDcazPtDep = {}; + TH1* passedHistogram = nullptr; + bool dca2Dcut = false; + bool requirePvContributor = false; +}; inline TList* getCCDBInput(auto& ccdb, const char* ccdbpath, const char* ccdbdate, const char* period = "") { @@ -166,124 +511,15 @@ inline TList* getCCDBInput(auto& ccdb, const char* ccdbpath, const char* ccdbdat return lst; } -inline void initializeTrackSelection(const TrackSelectionTuneCfg& tune) -{ - switch (tracktype) { - case 1: { /* Run2 global track */ - TrackSelection* globalRun2 = new TrackSelection(getGlobalTrackSelection()); - globalRun2->SetTrackType(o2::aod::track::Run2Track); // Run 2 track asked by default - globalRun2->SetMaxChi2PerClusterTPC(2.5f); - TrackSelection* globalSDDRun2 = new TrackSelection(getGlobalTrackSelectionSDD()); - globalSDDRun2->SetTrackType(o2::aod::track::Run2Track); // Run 2 track asked by default - globalSDDRun2->SetMaxChi2PerClusterTPC(2.5f); - trackFilters.push_back(globalRun2); - trackFilters.push_back(globalSDDRun2); - } break; - case 3: { /* Run3 track */ - TrackSelection* globalRun3 = new TrackSelection(getGlobalTrackSelection()); - globalRun3->SetTrackType(o2::aod::track::TrackTypeEnum::Track); - globalRun3->ResetITSRequirements(); - globalRun3->SetRequireHitsInITSLayers(1, {0, 1, 2}); - TrackSelection* globalSDDRun3 = new TrackSelection(getGlobalTrackSelection()); - globalSDDRun3->SetTrackType(o2::aod::track::TrackTypeEnum::Track); - globalSDDRun3->ResetITSRequirements(); - globalSDDRun3->SetRequireNoHitsInITSLayers({0, 1, 2}); - globalSDDRun3->SetRequireHitsInITSLayers(1, {3}); - trackFilters.push_back(globalRun3); - trackFilters.push_back(globalSDDRun3); - } break; - case 5: { /* Run2 TPC only track */ - TrackSelection* tpcOnly = new TrackSelection; - tpcOnly->SetTrackType(o2::aod::track::Run2Track); // Run 2 track asked by default - tpcOnly->SetMinNClustersTPC(50); - tpcOnly->SetMaxChi2PerClusterTPC(4); - tpcOnly->SetMaxDcaZ(3.2f); - maxDCAz = 3.2; - tpcOnly->SetMaxDcaXY(2.4f); - maxDCAxy = 2.4; - dca2Dcut = true; - trackFilters.push_back(tpcOnly); - } break; - case 7: { /* Run3 TPC only track */ - TrackSelection* tpcOnly = new TrackSelection; - tpcOnly->SetTrackType(o2::aod::track::TrackTypeEnum::Track); - tpcOnly->SetMinNClustersTPC(50); - tpcOnly->SetMaxChi2PerClusterTPC(4); - tpcOnly->SetMaxDcaZ(3.2f); - maxDCAz = 3.2; - tpcOnly->SetMaxDcaXY(2.4f); - maxDCAxy = 2.4; - dca2Dcut = true; - trackFilters.push_back(tpcOnly); - } break; - case 30: { /* Run 3 default global track: kAny on 3 IB layers of ITS */ - trackFilters.push_back(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::Default))); - } break; - case 31: { /* Run 3 global track: kTwo on 3 IB layers of ITS */ - trackFilters.push_back(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibTwo, TrackSelection::GlobalTrackRun3DCAxyCut::Default))); - } break; - case 32: { /* Run 3 global track: kAny on all 7 layers of ITS */ - trackFilters.push_back(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSallAny, TrackSelection::GlobalTrackRun3DCAxyCut::Default))); - } break; - case 33: { /* Run 3 global track: kAll on all 7 layers of ITS */ - trackFilters.push_back(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSall7Layers, TrackSelection::GlobalTrackRun3DCAxyCut::Default))); - } break; - case 40: { /* Run 3 global track: kAny on 3 IB layers of ITS, tighter DCAxy */ - trackFilters.push_back(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3))); - } break; - case 41: { /* Run 3 global track: kTwo on 3 IB layers of ITS, tighter DCAxy */ - trackFilters.push_back(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibTwo, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3))); - } break; - case 42: { /* Run 3 global track: kAny on all 7 layers of ITS, tighter DCAxy */ - trackFilters.push_back(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSallAny, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3))); - } break; - case 43: { /* Run 3 global track: kAll on all 7 layers of ITS, tighter DCAxy */ - trackFilters.push_back(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSall7Layers, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3))); - } break; - case 50: { /* Run 3 global track: kAny on 3 IB layers of ITS, tighter DCAxy, tighter pT dep DCAz */ - trackFilters.push_back(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3))); - maxDcaZPtDep = [](float pt) { return 0.004f + 0.013f / pt; }; - } break; - case 51: { /* Run 3 global track: kTwo on 3 IB layers of ITS, tighter DCAxy, tighter pT dep DCAz */ - trackFilters.push_back(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibTwo, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3))); - maxDcaZPtDep = [](float pt) { return 0.004f + 0.013f / pt; }; - } break; - case 52: { /* Run 3 global track: kAny on all 7 layers of ITS, tighter DCAxy, tighter pT dep DCAz */ - trackFilters.push_back(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSallAny, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3))); - maxDcaZPtDep = [](float pt) { return 0.004f + 0.013f / pt; }; - } break; - case 53: { /* Run 3 global track: kAll on all 7 layers of ITS, tighter DCAxy, tighter pT dep DCAz */ - trackFilters.push_back(new TrackSelection(getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSall7Layers, TrackSelection::GlobalTrackRun3DCAxyCut::ppPass3))); - maxDcaZPtDep = [](float pt) { return 0.004f + 0.013f / pt; }; - } break; - default: - break; - } - if (tune.mUseIt) { - for (auto filter : trackFilters) { - if (tune.mUseTPCclusters) { - filter->SetMinNClustersTPC(tune.mTPCclusters); - } - if (tune.mUseTPCxRows) { - filter->SetMinNCrossedRowsTPC(tune.mTPCxRows); - } - if (tune.mUseTPCXRoFClusters) { - filter->SetMinNCrossedRowsOverFindableClustersTPC(tune.mTPCXRoFClusters); - } - if (tune.mUseDCAxy) { - filter->SetMaxDcaXY(tune.mDCAxy); - } - if (tune.mUseDCAz) { - filter->SetMaxDcaZ(tune.mDCAz); - } - } - } -} - SystemType fSystem = kNoSystem; DataType fDataType = kData; CentMultEstimatorType fCentMultEstimator = kV0M; TriggerSelectionType fTriggerSelection = kMB; +OccupancyEstimationType fOccupancyEstimation = kNOOCC; /* the occupancy estimator to use */ +ItsDeadMapsCheckType fItsDeadMapCheck = kNOCHECK; /* the check of the ITS dead maps to use */ + +float fMinOccupancy = 0.0f; /* the minimum allowed occupancy */ +float fMaxOccupancy = 1e6f; /* the maximum allowed occupancy */ /* adaptations for the pp nightly checks */ analysis::CheckRangeCfg traceDCAOutliers; @@ -293,18 +529,24 @@ float particleMaxDCAxy = 999.9f; float particleMaxDCAZ = 999.9f; bool traceCollId0 = false; -TDatabasePDG* fPDG = nullptr; - inline TriggerSelectionType getTriggerSelection(std::string const& triggstr) { if (triggstr.empty() || triggstr == "MB") { return kMB; + } else if (triggstr == "MBEXTRA") { + return kMBEXTRA; } else if (triggstr == "VTXTOFMATCHED") { return kVTXTOFMATCHED; } else if (triggstr == "VTXTRDMATCHED") { return kVTXTRDMATCHED; } else if (triggstr == "VTXTRDTOFMATCHED") { return kVTXTRDTOFMATCHED; + } else if (triggstr == "EXTRAVTXTOFMATCHED") { + return kEXTRAVTXTOFMATCHED; + } else if (triggstr == "EXTRAVTXTRDMATCHED") { + return kEXTRAVTXTRDMATCHED; + } else if (triggstr == "EXTRAVTXTRDTOFMATCHED") { + return kEXTRAVTXTRDTOFMATCHED; } else if (triggstr == "None") { return kNONE; } else { @@ -423,6 +665,42 @@ inline std::string getCentMultEstimatorName(CentMultEstimatorType est) } } +inline OccupancyEstimationType getOccupancyEstimator(const std::string& estimator) +{ + if (estimator == "None") { + return kNOOCC; + } else if (estimator == "Tracks") { + return kTRACKSOCC; + } else if (estimator == "FT0C") { + return kFT0COCC; + } else { + LOGF(fatal, "Occupancy estimator %s not supported yet", estimator.c_str()); + return kNOOCC; + } +} + +inline ItsDeadMapsCheckType getItsDeadMapCheck(const std::string& check) +{ + if (check.length() == 0 || check == "None") { + return kNOCHECK; + } else if (check == "goodIts3") { + return kGOODITSLAYER3; + } else if (check == "goodIts0123") { + return kGOODITSLAYER0123; + } else if (check == "goodItsAll") { + return kGOODITSLAYERALL; + } else if (check == "noGoodIts3") { + return kNOGOODITSLAYER3; + } else if (check == "noGoodIts0123") { + return kNOGOODITSLAYER0123; + } else if (check == "noGoodItsAll") { + return kNOGOODITSLAYERALL; + } else { + LOGF(fatal, "ITS dead map check %s not implemented", check.c_str()); + return kNOCHECK; + } +} + ////////////////////////////////////////////////////////////////////////////////// /// Trigger selection ////////////////////////////////////////////////////////////////////////////////// @@ -443,17 +721,21 @@ inline bool triggerSelectionReco(CollisionObject const& collision) switch (fDataType) { case kData: if (collision.alias_bit(kINT7)) { + collisionFlags.set(kINT7BIT); if (collision.sel7()) { trigsel = true; + collisionFlags.set(kSEL7BIT); } } break; case kMC: if (collision.sel7()) { trigsel = true; + collisionFlags.set(kSEL7BIT); } break; default: + collisionFlags.set(kMBBIT); trigsel = true; break; } @@ -469,18 +751,39 @@ inline bool triggerSelectionReco(CollisionObject const& collision) case kPbPbRun3: { auto run3Accepted = [](auto const& coll) { return coll.sel8() && - coll.selection_bit(aod::evsel::kNoITSROFrameBorder) && - coll.selection_bit(aod::evsel::kNoTimeFrameBorder) && + coll.selection_bit(aod::evsel::kNoCollInTimeRangeStandard) && + coll.selection_bit(aod::evsel::kNoCollInRofStandard); + }; + auto run3ExtraAccepted = [](auto const& coll) { + return coll.sel8() && coll.selection_bit(aod::evsel::kNoSameBunchPileup) && coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && coll.selection_bit(aod::evsel::kIsVertexITSTPC); }; + auto setCollisionFlags = [](auto& flags, auto const& coll) { + flags.set(kSEL8BIT, coll.sel8() != 0); + flags.set(kNOSAMEBUNCHPUPBIT, coll.selection_bit(aod::evsel::kNoSameBunchPileup)); + flags.set(kISGOODZVTXFT0VSPVBIT, coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)); + flags.set(kISVERTEXITSTPCBIT, coll.selection_bit(aod::evsel::kIsVertexITSTPC)); + flags.set(kISVERTEXTOFMATCHEDBIT, coll.selection_bit(aod::evsel::kIsVertexTOFmatched)); + flags.set(kISVERTEXTRDMATCHEDBIT, coll.selection_bit(aod::evsel::kIsVertexTRDmatched)); + flags.set(kNOCOLLINTIMERANGEBIT, coll.selection_bit(aod::evsel::kNoCollInTimeRangeStandard)); + flags.set(kNOCOLLINROFBIT, coll.selection_bit(aod::evsel::kNoCollInRofStandard)); + flags.set(kISGOODITSLAYER3BIT, coll.selection_bit(aod::evsel::kIsGoodITSLayer3)); + flags.set(kISGOODITSLAYER0123BIT, coll.selection_bit(aod::evsel::kIsGoodITSLayer0123)); + flags.set(kISGOODITSLAYERALLBIT, coll.selection_bit(aod::evsel::kIsGoodITSLayersAll)); + }; switch (fTriggerSelection) { case kMB: if (run3Accepted(collision)) { trigsel = true; } break; + case kMBEXTRA: + if (run3ExtraAccepted(collision)) { + trigsel = true; + } + break; case kVTXTOFMATCHED: if (run3Accepted(collision) && collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { trigsel = true; @@ -496,12 +799,28 @@ inline bool triggerSelectionReco(CollisionObject const& collision) trigsel = true; } break; + case kEXTRAVTXTOFMATCHED: + if (run3ExtraAccepted(collision) && collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { + trigsel = true; + } + break; + case kEXTRAVTXTRDMATCHED: + if (run3ExtraAccepted(collision) && collision.selection_bit(aod::evsel::kIsVertexTRDmatched)) { + trigsel = true; + } + break; + case kEXTRAVTXTRDTOFMATCHED: + if (run3ExtraAccepted(collision) && collision.selection_bit(aod::evsel::kIsVertexTRDmatched) && collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { + trigsel = true; + } + break; case kNONE: trigsel = true; break; default: break; } + setCollisionFlags(collisionFlags, collision); } break; default: break; @@ -615,51 +934,38 @@ inline float extractMultiplicity(CollisionObject const& collision, CentMultEstim /// \brief Centrality/multiplicity percentile template + requires(o2::aod::HasRun2Centrality) float getCentMultPercentile(CollisionObject collision) { - if constexpr (framework::has_type_v || - framework::has_type_v || - framework::has_type_v) { - switch (fCentMultEstimator) { - case kV0M: - return collision.centRun2V0M(); - break; - case kCL0: - return collision.centRun2CL0(); - break; - case kCL1: - return collision.centRun2CL1(); - break; - default: - return 105.0; - break; - } + switch (fCentMultEstimator) { + case kV0M: + return collision.centRun2V0M(); + case kCL0: + return collision.centRun2CL0(); + case kCL1: + return collision.centRun2CL1(); + default: + return 105.0; } - if constexpr (framework::has_type_v || - framework::has_type_v || - framework::has_type_v || - framework::has_type_v || - framework::has_type_v) { - switch (fCentMultEstimator) { - case kFV0A: - return collision.centFV0A(); - break; - case kFT0M: - return collision.centFT0M(); - break; - case kFT0A: - return collision.centFT0A(); - break; - case kFT0C: - return collision.centFT0C(); - break; - case kNTPV: - return collision.centNTPV(); - break; - default: - return 105.0; - break; - } +} + +template + requires(o2::aod::HasCentrality) +float getCentMultPercentile(CollisionObject collision) +{ + switch (fCentMultEstimator) { + case kFV0A: + return collision.centFV0A(); + case kFT0M: + return collision.centFT0M(); + case kFT0A: + return collision.centFT0A(); + case kFT0C: + return collision.centFT0C(); + case kNTPV: + return collision.centNTPV(); + default: + return 105.0; } } @@ -670,6 +976,7 @@ inline bool centralitySelectionMult(CollisionObject collision, float& centmult) float mult = getCentMultPercentile(collision); if (mult < 100 && 0 < mult) { centmult = mult; + collisionFlags.set(kCENTRALITYBIT); return true; } return false; @@ -684,6 +991,7 @@ inline bool centralitySelectionNoMult(CollisionObject const&, float& centmult) case kNOCM: centmult = 50.0; centmultsel = true; + collisionFlags.set(kCENTRALITYBIT); break; default: break; @@ -752,30 +1060,317 @@ inline bool centralitySelection(aod::McCollision const&, float } } +////////////////////////////////////////////////////////////////////////////////// +/// Occupancy selection +////////////////////////////////////////////////////////////////////////////////// + +/// \brief select on the collision occupancy +/// \return true if collison passes the occupancy cut false otherwise +template +inline bool selectOnOccupancy(CollisionObject collision) +{ + switch (fOccupancyEstimation) { + case kNOOCC: + collisionFlags.set(kOCCUPANCYBIT); + return true; + case kTRACKSOCC: + if ((fMinOccupancy <= collision.trackOccupancyInTimeRange()) && (collision.trackOccupancyInTimeRange() < fMaxOccupancy)) { + collisionFlags.set(kOCCUPANCYBIT); + return true; + } else { + return false; + } + case kFT0COCC: + if ((fMinOccupancy <= collision.ft0cOccupancyInTimeRange()) && (collision.ft0cOccupancyInTimeRange() < fMaxOccupancy)) { + collisionFlags.set(kOCCUPANCYBIT); + return true; + } else { + return false; + } + default: + return false; + } +} + +/// \brief Occupancy selection by default: unknown subscribed collision table +template +inline bool occupancySelection(CollisionObject const&) +{ + LOGF(fatal, "Occupancy selection not implemented for this kind of collisions"); + return false; +} + +/// \brief Occupancy selection for reconstructed and detector level collision tables with centrality/multiplicity information +template <> +inline bool occupancySelection(aod::CollisionEvSelCent const& collision) +{ + return selectOnOccupancy(collision); +} + +/// \brief Occupancy selection for reconstructed and detector level collision tables with Run 2 centrality/multiplicity information +template <> +inline bool occupancySelection(aod::CollisionEvSelRun2Cent const&) +{ + return true; +} + +/// \brief Occupancy selection for reconstructed and detector level collision tables without centrality/multiplicity information +template <> +inline bool occupancySelection(aod::CollisionEvSel const& collision) +{ + return selectOnOccupancy(collision); +} + +/// \brief Occupancy selection for detector level collision tables without centrality/multiplicity +template <> +inline bool occupancySelection::iterator>(soa::Join::iterator const& collision) +{ + return selectOnOccupancy(collision); +} + +/// \brief Occupancy selection for detector level collision tables with centrality/multiplicity +template <> +inline bool occupancySelection::iterator>(soa::Join::iterator const& collision) +{ + return selectOnOccupancy(collision); +} + +/// \brief Occupancy selection for detector level collision tables with Run 2 centrality/multiplicity +template <> +inline bool occupancySelection::iterator>(soa::Join::iterator const&) +{ + return true; +} + +/// \brief Occupancy selection for generator level collision table +template <> +inline bool occupancySelection(aod::McCollision const&) +{ + return true; +} + +////////////////////////////////////////////////////////////////////////////////// +/// ITS dead maps selection +////////////////////////////////////////////////////////////////////////////////// + +/// \brief select on the ITS dead maps +/// \return true if the collision passes the ITS dead maps check false otherwise +template +inline bool selectOnItsDeadMaps(CollisionObject coll) +{ + auto checkFlag = [](auto flag, bool invert = false) { + return invert ? !flag : flag; + }; + switch (fItsDeadMapCheck) { + case kNOCHECK: + return true; + case kGOODITSLAYER3: + return checkFlag(coll.selection_bit(aod::evsel::kIsGoodITSLayer3)); + case kGOODITSLAYER0123: + return checkFlag(coll.selection_bit(aod::evsel::kIsGoodITSLayer0123)); + case kGOODITSLAYERALL: + return checkFlag(coll.selection_bit(aod::evsel::kIsGoodITSLayersAll)); + case kNOGOODITSLAYER3: + return checkFlag(coll.selection_bit(aod::evsel::kIsGoodITSLayer3), true); + case kNOGOODITSLAYER0123: + return checkFlag(coll.selection_bit(aod::evsel::kIsGoodITSLayer0123), true); + case kNOGOODITSLAYERALL: + return checkFlag(coll.selection_bit(aod::evsel::kIsGoodITSLayersAll), true); + default: + return false; + } +} + +/// \brief Occupancy selection by default: unknown subscribed collision table +template +inline bool itsDeadMapsSelection(CollisionObject const&) +{ + LOGF(fatal, "Occupancy selection not implemented for this kind of collisions"); + return false; +} + +/// \brief Occupancy selection for reconstructed and detector level collision tables with centrality/multiplicity information +template <> +inline bool itsDeadMapsSelection(aod::CollisionEvSelCent const& collision) +{ + return selectOnItsDeadMaps(collision); +} + +/// \brief Occupancy selection for reconstructed and detector level collision tables with Run 2 centrality/multiplicity information +template <> +inline bool itsDeadMapsSelection(aod::CollisionEvSelRun2Cent const&) +{ + return true; +} + +/// \brief Occupancy selection for reconstructed and detector level collision tables without centrality/multiplicity information +template <> +inline bool itsDeadMapsSelection(aod::CollisionEvSel const& collision) +{ + return selectOnItsDeadMaps(collision); +} + +/// \brief Occupancy selection for detector level collision tables without centrality/multiplicity +template <> +inline bool itsDeadMapsSelection::iterator>(soa::Join::iterator const& collision) +{ + return selectOnItsDeadMaps(collision); +} + +/// \brief Occupancy selection for detector level collision tables with centrality/multiplicity +template <> +inline bool itsDeadMapsSelection::iterator>(soa::Join::iterator const& collision) +{ + return selectOnItsDeadMaps(collision); +} + +/// \brief Occupancy selection for detector level collision tables with Run 2 centrality/multiplicity +template <> +inline bool itsDeadMapsSelection::iterator>(soa::Join::iterator const&) +{ + return true; +} + +/// \brief Occupancy selection for generator level collision table +template <> +inline bool itsDeadMapsSelection(aod::McCollision const&) +{ + return true; +} + ////////////////////////////////////////////////////////////////////////////////// /// Event selection ////////////////////////////////////////////////////////////////////////////////// template -inline bool IsEvtSelected(CollisionObject const& collision, float& centormult) +inline bool isEventSelected(CollisionObject const& collision, float& centormult) { + collisionFlags.reset(); + collisionFlags.set(kIN); + bool trigsel = triggerSelection(collision); + bool occupancysel = occupancySelection(collision); + + bool itsdeadmapssel = itsDeadMapsSelection(collision); + bool zvtxsel = false; /* TODO: vertex quality checks */ if (zvtxlow < collision.posZ() && collision.posZ() < zvtxup) { - zvtxsel = true; + if (onlyInOneSide) { + if (collision.posZ() != 0.0) { + /* if only one side, we accept collisions which have zvtx different than zero */ + zvtxsel = true; + collisionFlags.set(kZVERTEXBIT); + } + } else { + zvtxsel = true; + collisionFlags.set(kZVERTEXBIT); + } } bool centmultsel = centralitySelection(collision, centormult); - return trigsel && zvtxsel && centmultsel; + bool accepted = trigsel && occupancysel && itsdeadmapssel && zvtxsel && centmultsel; + + if (accepted) { + collisionFlags.set(kSELECTED); + } + + return accepted; } ////////////////////////////////////////////////////////////////////////////////// /// Track selection ////////////////////////////////////////////////////////////////////////////////// +struct TpcExcludeTrack { + TpcExcludeTrack() + { + method = kNOEXCLUSION; + } + explicit TpcExcludeTrack(TpcExclusionMethod m) + { + switch (m) { + case kNOEXCLUSION: + method = m; + break; + case kSTATIC: + if (phibinshift == 0.5f && phibins == 72) { + method = m; + } else { + LOGF(fatal, "Static TPC exclusion method with bin shift: %.2f and number of bins %d. Please fix it", phibinshift, phibins); + } + break; + case kDYNAMIC: + method = m; + break; + default: + LOGF(fatal, "Wrong TPC tracks exclusion method %d. Please, fix it", static_cast(m)); + } + philow = 0.0f; + phiup = constants::math::TwoPI; + phibinwidth = (phiup - philow) / static_cast(phibins); + phiup = phiup - phibinwidth * phibinshift; + philow = philow - phibinwidth * phibinshift; + } + + template + int getPhiBinIx(TrackObject const& track) + { + float phi = RecoDecay::constrainAngle(track.phi(), philow); + return static_cast((phi - philow) / phibinwidth); + } + + template + bool exclude(TrackObject const& track) + { + constexpr int kNoOfTpcSectors = 18; + constexpr float kTpcPhiSectorWidth = (constants::math::TwoPI) / kNoOfTpcSectors; + + switch (method) { + case kNOEXCLUSION: { + return false; + } break; + case kSTATIC: { + int phiBinIx = getPhiBinIx(track); + /* bins multiple of four have got sector border */ + if ((phiBinIx % 4) != 0) { + return false; + } else { + return true; + } + } break; + case kDYNAMIC: { + float phiInTpcSector = std::fmod(track.phi(), kTpcPhiSectorWidth); + if (track.sign() > 0) { + return (phiInTpcSector < positiveUpCut->Eval(track.pt())) && (positiveLowCut->Eval(track.pt()) < phiInTpcSector); + } else { + return (phiInTpcSector < negativeUpCut->Eval(track.pt())) && (negativeLowCut->Eval(track.pt()) < phiInTpcSector); + } + } break; + default: + return false; + } + } + + void setCuts(std::string pLowCut, std::string pUpCut, std::string nLowCut, std::string nUpCut) + { + LOGF(info, "Setting the TPC exclusion cuts: pLow=%s, pUp=%s, nLow=%s, nUp=%s", pLowCut, pUpCut, nLowCut, nUpCut); + positiveLowCut = new TF1("posLowCut", pLowCut.c_str(), ptlow, ptup); + positiveUpCut = new TF1("posUpCut", pUpCut.c_str(), ptlow, ptup); + negativeLowCut = new TF1("negLowCut", nLowCut.c_str(), ptlow, ptup); + negativeUpCut = new TF1("negUpCut", nUpCut.c_str(), ptlow, ptup); + } + + TpcExclusionMethod method = kNOEXCLUSION; + float phibinwidth = 0.0; + TF1* positiveLowCut = nullptr; + TF1* positiveUpCut = nullptr; + TF1* negativeLowCut = nullptr; + TF1* negativeUpCut = nullptr; +}; + template inline bool matchTrackType(TrackObject const& track) { @@ -788,36 +1383,12 @@ inline bool matchTrackType(TrackObject const& track) // (track.passedDCAxy && track.passedDCAz && track.passedGoldenChi2) && // (track.passedITSNCls && track.passedITSChi2NDF && track.passedITSHits) && // (!track.hasTPC || (track.passedTPCNCls && track.passedTPCChi2NDF && track.passedTPCCrossedRowsOverNCls)); - return track.hasITS() && ((track.trackCutFlag() & trackSelectionITS) == trackSelectionITS) && - (!track.hasTPC() || ((track.trackCutFlag() & trackSelectionTPC) == trackSelectionTPC)) && - ((track.trackCutFlag() & trackSelectionDCA) == trackSelectionDCA); + return track.hasITS() && ((track.trackCutFlag() & TrackSelectionITS) == TrackSelectionITS) && + (!track.hasTPC() || ((track.trackCutFlag() & TrackSelectionTPC) == TrackSelectionTPC)) && + ((track.trackCutFlag() & TrackSelectionDCA) == TrackSelectionDCA); } else { - for (auto filter : trackFilters) { - if (filter->IsSelected(track)) { - /* additional track cuts if needed */ - auto checkDca2Dcut = [&](auto const& track) { - if (dca2Dcut) { - if (track.dcaXY() * track.dcaXY() / maxDCAxy / maxDCAxy + track.dcaZ() * track.dcaZ() / maxDCAz / maxDCAz > 1) { - return false; - } else { - return true; - } - } else { - return true; - } - }; - auto checkDcaZcut = [&](auto const& track) { - return ((maxDcaZPtDep) ? abs(track.dcaZ()) <= maxDcaZPtDep(track.pt()) : true); - }; - - /* tight pT dependent DCAz cut */ - if (!checkDcaZcut(track)) { - return false; - } - /* 2D DCA xy-o-z cut */ - if (!checkDca2Dcut(track)) { - return false; - } + for (auto const& filter : trackFilters) { + if (filter->isSelected(track)) { return true; } } @@ -828,9 +1399,12 @@ inline bool matchTrackType(TrackObject const& track) /// \brief Checks if the passed track is within the acceptance conditions of the analysis /// \param track the track of interest /// \return true if the track is in the acceptance, otherwise false -template -inline bool InTheAcceptance(TrackObject const& track) +template +inline bool inTheAcceptance(TrackObject const& track) { + /* the side on which the collision happened */ + float side = track.template collision_as().posZ(); + /* overall minimum momentum cut for the analysis */ if (!(overallminp < track.p())) { return false; @@ -842,8 +1416,24 @@ inline bool InTheAcceptance(TrackObject const& track) } } + /* check the side of the collision and decide if one side */ + if (onlyInOneSide) { + if (side < 0) { + if (track.eta() >= 0.0) { + return false; + } + } else if (side > 0) { + if (track.eta() <= 0.0) { + return false; + } + } else { + /* if only one side we should not have collisions with zvtx = 0 */ + LOGF(fatal, "Selecting one side tracks with a zvtx zero collision"); + } + } + if (ptlow < track.pt() && track.pt() < ptup && etalow < track.eta() && track.eta() < etaup) { - return true; + return !tpcExcluder.exclude(track); } return false; } @@ -851,10 +1441,10 @@ inline bool InTheAcceptance(TrackObject const& track) /// \brief Accepts or not the passed track /// \param track the track of interest /// \return true if the track is accepted, otherwise false -template -inline bool AcceptTrack(TrackObject const& track) +template +inline bool acceptTrack(TrackObject const& track) { - if (InTheAcceptance(track)) { + if (inTheAcceptance(track)) { if (matchTrackType(track)) { return true; } @@ -865,7 +1455,7 @@ inline bool AcceptTrack(TrackObject const& track) template void exploreMothers(ParticleObject& particle, MCCollisionObject& collision) { - for (auto& m : particle.template mothers_as()) { + for (const auto& m : particle.template mothers_as()) { LOGF(info, " mother index: %d", m.globalIndex()); LOGF(info, " Tracking back mother"); LOGF(info, " assigned collision Id: %d, looping on collision Id: %d", m.mcCollisionId(), collision.globalIndex()); @@ -876,14 +1466,9 @@ void exploreMothers(ParticleObject& particle, MCCollisionObject& collision) } } -template -inline float getCharge(ParticleObject& particle) +inline float getCharge(float pdgCharge) { - float charge = 0.0; - TParticlePDG* pdgparticle = fPDG->GetParticle(particle.pdgCode()); - if (pdgparticle != nullptr) { - charge = (pdgparticle->Charge() / 3 >= 1) ? 1.0 : ((pdgparticle->Charge() / 3 <= -1) ? -1.0 : 0); - } + float charge = (pdgCharge / 3 >= 1) ? 1.0 : ((pdgCharge / 3 <= -1) ? -1.0 : 0); return charge; } @@ -891,22 +1476,20 @@ inline float getCharge(ParticleObject& particle) /// \param track the particle of interest /// \return `true` if the particle is accepted, `false` otherwise template -inline bool AcceptParticle(ParticleObject& particle, MCCollisionObject const&) +inline bool acceptParticle(ParticleObject& particle, MCCollisionObject const&) { /* overall momentum cut */ if (!(overallminp < particle.p())) { return false; } - float charge = getCharge(particle); - if (particle.isPhysicalPrimary()) { if ((particle.mcCollisionId() == 0) && traceCollId0) { LOGF(info, "Particle %d passed isPhysicalPrimary", particle.globalIndex()); } if (ptlow < particle.pt() && particle.pt() < ptup && etalow < particle.eta() && particle.eta() < etaup) { - return (charge != 0) ? true : false; + return true; } } else { if ((particle.mcCollisionId() == 0) && traceCollId0) { @@ -926,6 +1509,7 @@ struct PIDSpeciesSelection { const std::vector sptitles = {"e", "#mu", "#pi", "K", "p"}; const std::vector spfnames = {"E", "Mu", "Pi", "Ka", "Pr"}; const std::vector spadjnames = {"Electron", "Muon", "Pion", "Kaon", "Proton"}; + const std::vector spmasses = {o2::constants::physics::MassElectron, o2::constants::physics::MassMuon, o2::constants::physics::MassPionCharged, o2::constants::physics::MassKaonCharged, o2::constants::physics::MassProton}; const std::vector chadjnames = {"P", "M"}; const char* hadname = "h"; const char* hadtitle = "h"; @@ -934,6 +1518,7 @@ struct PIDSpeciesSelection { const char* getSpeciesName(uint8_t ix) { return spnames[species[ix]].data(); } const char* getSpeciesTitle(uint8_t ix) { return sptitles[species[ix]].data(); } const char* getSpeciesFName(uint8_t ix) { return spfnames[species[ix]].data(); } + double getSpeciesMass(uint8_t ix) { return spmasses[species[ix]]; } const char* getHadName() { return hadname; } const char* getHadTitle() { return hadtitle; } const char* getHadFName() { return hadfname; } @@ -964,7 +1549,7 @@ struct PIDSpeciesSelection { reportadjdetectorwithcharge(tpcnsigmasshiftneg, "TPC", "M"); reportadjdetectorwithcharge(tofnsigmasshiftneg, "TOF", "M"); } - void Add(uint8_t sp, o2::analysis::TrackSelectionPIDCfg* incfg) + void addSpecies(uint8_t sp, o2::analysis::TrackSelectionPIDCfg* incfg) { o2::analysis::TrackSelectionPIDCfg* cfg = new o2::analysis::TrackSelectionPIDCfg(*incfg); config.push_back(cfg); @@ -977,8 +1562,9 @@ struct PIDSpeciesSelection { LOGF(info, " maxTPC nsigmas: el: %.2f, mu: %.2f, pi: %.2f, ka: %.2f, pr: %.2f", last->mMaxNSigmasTPC[0], last->mMaxNSigmasTPC[1], last->mMaxNSigmasTPC[2], last->mMaxNSigmasTPC[3], last->mMaxNSigmasTPC[4]); LOGF(info, " minTOF nsigmas: el: %.2f, mu: %.2f, pi: %.2f, ka: %.2f, pr: %.2f", last->mMinNSigmasTOF[0], last->mMinNSigmasTOF[1], last->mMinNSigmasTOF[2], last->mMinNSigmasTOF[3], last->mMinNSigmasTOF[4]); LOGF(info, " maxTOF nsigmas: el: %.2f, mu: %.2f, pi: %.2f, ka: %.2f, pr: %.2f", last->mMaxNSigmasTOF[0], last->mMaxNSigmasTOF[1], last->mMaxNSigmasTOF[2], last->mMaxNSigmasTOF[3], last->mMaxNSigmasTOF[4]); + LOGF(info, " %.1f < pT < %.1f", last->mPtMin, last->mPtMax); } - void AddExclude(uint8_t sp, const o2::analysis::TrackSelectionPIDCfg* incfg) + void addExcludedSpecies(uint8_t sp, const o2::analysis::TrackSelectionPIDCfg* incfg) { o2::analysis::TrackSelectionPIDCfg* cfg = new o2::analysis::TrackSelectionPIDCfg(*incfg); configexclude.push_back(cfg); @@ -991,13 +1577,36 @@ struct PIDSpeciesSelection { LOGF(info, " maxTPC nsigmas: el: %.2f, mu: %.2f, pi: %.2f, ka: %.2f, pr: %.2f", last->mMaxNSigmasTPC[0], last->mMaxNSigmasTPC[1], last->mMaxNSigmasTPC[2], last->mMaxNSigmasTPC[3], last->mMaxNSigmasTPC[4]); LOGF(info, " minTOF nsigmas: el: %.2f, mu: %.2f, pi: %.2f, ka: %.2f, pr: %.2f", last->mMinNSigmasTOF[0], last->mMinNSigmasTOF[1], last->mMinNSigmasTOF[2], last->mMinNSigmasTOF[3], last->mMinNSigmasTOF[4]); LOGF(info, " maxTOF nsigmas: el: %.2f, mu: %.2f, pi: %.2f, ka: %.2f, pr: %.2f", last->mMaxNSigmasTOF[0], last->mMaxNSigmasTOF[1], last->mMaxNSigmasTOF[2], last->mMaxNSigmasTOF[3], last->mMaxNSigmasTOF[4]); + LOGF(info, " %.1f < pT < %.1f", last->mPtMin, last->mPtMax); } - template + template int8_t whichSpecies(TrackObject const& track) { + TString debuginfo; std::vector tpcnsigmas = {track.tpcNSigmaEl(), track.tpcNSigmaMu(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; std::vector tofnsigmas = {track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()}; + auto outmomentumdebug = [&]() { + if constexpr (outdebug != 0) { + debuginfo += TString::Format("%.5f,%.5f,%.5f,%d,%.2f,%.4f,", track.p(), track.tpcInnerParam(), track.pt(), track.hasTOF() ? 1 : 0, track.tpcSignal(), track.beta()); + } + }; + auto outnsigmasdebug = [&]() { + if constexpr (outdebug != 0) { + for (auto const& tpcn : tpcnsigmas) { + debuginfo += TString::Format("%.4f,", tpcn); + } + for (auto const& tofn : tofnsigmas) { + debuginfo += TString::Format("%.4f,", tofn); + } + } + }; + + /* out debug if needed */ + outmomentumdebug(); + /* out debug if needed */ + outnsigmasdebug(); + auto closeTo = [](auto& values, auto& mindet, auto& maxdet, uint8_t sp) { if (mindet[sp] <= values[sp] && values[sp] < maxdet[sp]) { return true; @@ -1097,12 +1706,34 @@ struct PIDSpeciesSelection { } }; + auto outpiddebug = [&](int code, int pid, int pid2) { + if constexpr (outdebug != 0) { + int truepid = -1; + int isphysicalprimary = -1; + int process = -1; + if constexpr (framework::has_type_v) { + if (!(track.mcParticleId() < 0)) { + auto particle = track.template mcParticle_as(); + truepid = particle.pdgCode(); + isphysicalprimary = particle.isPhysicalPrimary() ? 1 : 0; + process = particle.getProcess(); + } + } + debuginfo += TString::Format("%d,%d,%d,%d,%d,%d\n", code, pid, pid2, truepid, isphysicalprimary, process); + debugstream << debuginfo; + } + }; + /* adjust the nsigmas values if appropriate */ adjustnsigmas(); + /* out debug info if needed */ + outnsigmasdebug(); /* let's first check the exclusion from the analysis */ for (uint8_t ix = 0; ix < configexclude.size(); ++ix) { if (isA(configexclude[ix], speciesexclude[ix])) { + /* out debug info if needed */ + outpiddebug(1, speciesexclude[ix], -1); return -(ix + 1); } } @@ -1114,13 +1745,33 @@ struct PIDSpeciesSelection { if (id < 0) { id = ix; } else { + /* out debug info if needed */ + outpiddebug(2, species[id], species[ix]); /* already identified once */ return -127; } } } + /* check a species transverse momentum cut */ + if (!(id < 0)) { + /* identified */ + if ((track.pt() < config[id]->mPtMin) || config[id]->mPtMax < track.pt()) { + /* rejected */ + outpiddebug(4, species[id], -1); + return -127; + } + } + /* out debug info if needed */ + if (id < 0) { + /* not identified */ + outpiddebug(3, -1, -1); + } else { + /* identified */ + outpiddebug(0, species[id], -1); + } return id; } else { + outpiddebug(0, 0, -1); /* charged hadron */ return 0; } @@ -1139,6 +1790,11 @@ struct PIDSpeciesSelection { if (config.size() > 0) { for (uint8_t ix = 0; ix < config.size(); ++ix) { if (pdgcode == pdgcodes[species[ix]]) { + /* check a species transverse momentum cut */ + if ((part.pt() < config[ix]->mPtMin) || config[ix]->mPtMax < part.pt()) { + /* rejected */ + return -127; + } return ix; } } diff --git a/PWGCF/TableProducer/filter2Prong.cxx b/PWGCF/TableProducer/filter2Prong.cxx index d4353ca9150..4be15f1a295 100644 --- a/PWGCF/TableProducer/filter2Prong.cxx +++ b/PWGCF/TableProducer/filter2Prong.cxx @@ -8,6 +8,11 @@ // 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. +#include +#include +#include +#include + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -21,6 +26,8 @@ #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -32,12 +39,41 @@ using namespace o2::math_utils::detail; struct Filter2Prong { O2_DEFINE_CONFIGURABLE(cfgVerbosity, int, 0, "Verbosity level (0 = major, 1 = per collision)") O2_DEFINE_CONFIGURABLE(cfgYMax, float, -1.0f, "Maximum candidate rapidity") + // + O2_DEFINE_CONFIGURABLE(cfgImPart1Mass, float, o2::constants::physics::MassKPlus, "Daughter particle 1 mass in GeV") + O2_DEFINE_CONFIGURABLE(cfgImPart2Mass, float, o2::constants::physics::MassKMinus, "Daughter particle 2 mass in GeV") + O2_DEFINE_CONFIGURABLE(cfgImPart1PID, float, o2::track::PID::Kaon, "PID of daughter particle 1 (O2 PID ID)") + O2_DEFINE_CONFIGURABLE(cfgImPart2PID, float, o2::track::PID::Kaon, "PID of daughter particle 1 (O2 PID ID)") + O2_DEFINE_CONFIGURABLE(cfgImCutPt, float, 0.2f, "Minimal pT for candidates") + O2_DEFINE_CONFIGURABLE(cfgImMinInvMass, float, 0.95f, "Minimum invariant mass (GeV)") + O2_DEFINE_CONFIGURABLE(cfgImMaxInvMass, float, 1.07f, "Maximum invariant mass (GeV)") + O2_DEFINE_CONFIGURABLE(cfgImSigmaFormula, std::string, "(z < 0.5 && x < 3.0) || (z >= 0.5 && x < 2.5 && y < 3.0)", "pT dependent daughter track sigma pass condition (x = TPC sigma, y = TOF sigma, z = pT)") HfHelper hfHelper; Produces output2ProngTracks; + Produces output2ProngTrackmls; + + Produces output2ProngMcParts; + + std::vector mlvecd{}; + std::vector mlvecdbar{}; using HFCandidates = soa::Join; - void processData(aod::Collisions::iterator const&, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, HFCandidates const& candidates) + using HFCandidatesML = soa::Join; + + template + using HasMLProb = decltype(std::declval().mlProbD0()); + + std::unique_ptr sigmaFormula; + + void init(InitContext&) + { + if (doprocessDataInvMass) + sigmaFormula = std::make_unique("sigmaFormula", cfgImSigmaFormula.value.c_str()); + } + + template + void processDataT(aod::Collisions::iterator const&, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, HFCandidatesType const& candidates) { if (cfcollisions.size() <= 0 || cftracks.size() <= 0) return; // rejected collision @@ -62,15 +98,105 @@ struct Filter2Prong { continue; if (cfgYMax >= 0.0f && std::abs(hfHelper.yD0(c)) > cfgYMax) continue; - if (c.isSelD0() > 0) + + if (c.isSelD0() > 0) { output2ProngTracks(cfcollisions.begin().globalIndex(), prongCFId[0], prongCFId[1], c.pt(), c.eta(), c.phi(), hfHelper.invMassD0ToPiK(c), aod::cf2prongtrack::D0ToPiK); - if (c.isSelD0bar() > 0) + if constexpr (std::experimental::is_detected::value) { + mlvecd.clear(); + for (float val : c.mlProbD0()) + mlvecd.push_back(val); + mlvecdbar.clear(); + for (float val : c.mlProbD0bar()) + mlvecdbar.push_back(val); + output2ProngTrackmls(cfcollisions.begin().globalIndex(), mlvecd, mlvecdbar); + } + } + + if (c.isSelD0bar() > 0) { output2ProngTracks(cfcollisions.begin().globalIndex(), prongCFId[0], prongCFId[1], c.pt(), c.eta(), c.phi(), hfHelper.invMassD0barToKPi(c), aod::cf2prongtrack::D0barToKPi); + if constexpr (std::experimental::is_detected::value) { + mlvecd.clear(); + for (float val : c.mlProbD0()) + mlvecd.push_back(val); + mlvecdbar.clear(); + for (float val : c.mlProbD0bar()) + mlvecdbar.push_back(val); + output2ProngTrackmls(cfcollisions.begin().globalIndex(), mlvecd, mlvecdbar); + } + } } } + + void processDataML(aod::Collisions::iterator const& col, aod::BCsWithTimestamps const& bcs, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, HFCandidatesML const& candidates) + { + processDataT(col, bcs, cfcollisions, cftracks, candidates); + } + PROCESS_SWITCH(Filter2Prong, processDataML, "Process data D0 candidates with ML", false); + + void processData(aod::Collisions::iterator const& col, aod::BCsWithTimestamps const& bcs, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, HFCandidates const& candidates) + { + processDataT(col, bcs, cfcollisions, cftracks, candidates); + } PROCESS_SWITCH(Filter2Prong, processData, "Process data D0 candidates", true); + + void processMC(aod::McCollisions::iterator const&, aod::CFMcParticleRefs const& cfmcparticles, aod::McParticles const& mcparticles) + { + // The main filter outputs the primary MC particles. Here we just resolve the daughter indices that are needed for the efficiency matching. + for (auto& r : cfmcparticles) { + const auto& mcParticle = mcparticles.iteratorAt(r.mcParticleId()); + if (mcParticle.daughtersIds().size() != 2) { + output2ProngMcParts(-1, -1); + continue; + } + int prongCFId[2] = {-1, -1}; + for (uint i = 0; i < 2; ++i) { + for (auto& cfmcpart : cfmcparticles) { + if (mcParticle.daughtersIds()[i] == cfmcpart.mcParticleId()) { + prongCFId[i] = cfmcpart.globalIndex(); + break; + } + } + } + output2ProngMcParts(prongCFId[0], prongCFId[1]); + } + } + PROCESS_SWITCH(Filter2Prong, processMC, "Process MC 2-prong daughters", false); + + // Generic 2-prong invariant mass method candidate finder. Only works for non-identical daughters of opposite charge for now. + using PIDTrack = soa::Join; + void processDataInvMass(aod::Collisions::iterator const&, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, PIDTrack const& tracks) + { + if (cfcollisions.size() <= 0 || cftracks.size() <= 0) + return; // rejected collision + for (auto& cftrack1 : cftracks) { + auto p1 = tracks.iteratorAt(cftrack1.trackId()); + if (p1.sign() != 1) + continue; + if (sigmaFormula->Eval(o2::aod::pidutils::tpcNSigma(cfgImPart1PID, p1), o2::aod::pidutils::tofNSigma(cfgImPart1PID, p1)) <= 0.0f) + continue; + for (auto& cftrack2 : cftracks) { + if (cftrack2.globalIndex() == cftrack1.globalIndex()) + continue; + auto p2 = tracks.iteratorAt(cftrack2.trackId()); + if (p2.sign() != -1) + continue; + if (sigmaFormula->Eval(o2::aod::pidutils::tpcNSigma(cfgImPart2PID, p2), o2::aod::pidutils::tofNSigma(cfgImPart2PID, p2)) <= 0.0f) + continue; + ROOT::Math::PtEtaPhiMVector vec1(p1.pt(), p1.eta(), p1.phi(), cfgImPart1Mass); + ROOT::Math::PtEtaPhiMVector vec2(p2.pt(), p2.eta(), p2.phi(), cfgImPart2Mass); + ROOT::Math::PtEtaPhiMVector s = vec1 + vec2; + if (s.pt() < cfgImCutPt || s.M() < cfgImMinInvMass || s.M() > cfgImMaxInvMass) + continue; + + float phi = RecoDecay::constrainAngle(s.Phi(), 0.0f); + output2ProngTracks(cfcollisions.begin().globalIndex(), + cftrack1.globalIndex(), cftrack2.globalIndex(), s.pt(), s.eta(), phi, s.M(), aod::cf2prongtrack::Generic2Prong); + } + } + } + PROCESS_SWITCH(Filter2Prong, processDataInvMass, "Process data generic 2-prong candidates with invariant mass method", false); }; // struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGCF/TableProducer/filterCorrelations.cxx b/PWGCF/TableProducer/filterCorrelations.cxx index 33d6691a75c..7d5e0b17c38 100644 --- a/PWGCF/TableProducer/filterCorrelations.cxx +++ b/PWGCF/TableProducer/filterCorrelations.cxx @@ -8,6 +8,8 @@ // 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. +#include + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -22,7 +24,6 @@ #include "Common/DataModel/Centrality.h" #include -#include using namespace o2; using namespace o2::framework; @@ -46,6 +47,12 @@ using CFMultiplicity = CFMultiplicities::iterator; struct FilterCF { Service pdg; + enum TrackSelectionCuts : uint8_t { + kTrackSelected = BIT(0), + kITS5Clusters = BIT(1), + kTPC90CrossedRows = BIT(2) + }; + // Configuration O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 7.0f, "Accepted z-vertex range") O2_DEFINE_CONFIGURABLE(cfgCutPt, float, 0.5f, "Minimal pT for tracks") @@ -53,9 +60,14 @@ struct FilterCF { O2_DEFINE_CONFIGURABLE(cfgCutMCPt, float, 0.5f, "Minimal pT for particles") O2_DEFINE_CONFIGURABLE(cfgCutMCEta, float, 0.8f, "Eta range for particles") O2_DEFINE_CONFIGURABLE(cfgVerbosity, int, 1, "Verbosity level (0 = major, 1 = per collision)") - O2_DEFINE_CONFIGURABLE(cfgTrigger, int, 7, "Trigger choice: (0 = none, 7 = sel7, 8 = sel8)") + O2_DEFINE_CONFIGURABLE(cfgTrigger, int, 7, "Trigger choice: (0 = none, 7 = sel7, 8 = sel8, 9 = sel8 + kNoSameBunchPileup + kIsGoodZvtxFT0vsPV, 10 = sel8 before April, 2024, 11 = sel8 for MC, 12 = sel8 with low occupancy cut)") + O2_DEFINE_CONFIGURABLE(cfgMinOcc, int, 0, "minimum occupancy selection") + O2_DEFINE_CONFIGURABLE(cfgMaxOcc, int, 3000, "maximum occupancy selection") O2_DEFINE_CONFIGURABLE(cfgCollisionFlags, uint16_t, aod::collision::CollisionFlagsRun2::Run2VertexerTracks, "Request collision flags if non-zero (0 = off, 1 = Run2VertexerTracks)") - O2_DEFINE_CONFIGURABLE(cfgTransientTables, bool, false, "Output transient tables for collision and track IDs") + O2_DEFINE_CONFIGURABLE(cfgTransientTables, bool, false, "Output transient tables for collision and track IDs to enable successive filtering tasks") + O2_DEFINE_CONFIGURABLE(cfgTrackSelection, int, 0, "Type of track selection (0 = Run 2/3 without systematics | 1 = Run 3 with systematics)") + O2_DEFINE_CONFIGURABLE(cfgMinMultiplicity, float, -1, "Minimum multiplicity considered for filtering (if value positive)") + O2_DEFINE_CONFIGURABLE(cfgMcSpecialPDGs, std::vector, {}, "Special MC PDG codes to include in the MC primary particle output (additional to charged particles). Empty = charged particles only.") // needed for some neutral particles // Filters and input definitions Filter collisionZVtxFilter = nabs(aod::collision::posZ) < cfgCutVertex; @@ -81,21 +93,69 @@ struct FilterCF { Produces outputCollRefs; Produces outputTrackRefs; + Produces outputMcParticleRefs; + + // persistent caches + std::vector mcReconstructedCache; + std::vector mcParticleLabelsCache; template bool keepCollision(TCollision& collision) { + bool isMultSelected = false; + if (collision.multiplicity() >= cfgMinMultiplicity) + isMultSelected = true; + if (cfgTrigger == 0) { return true; } else if (cfgTrigger == 7) { - return collision.alias_bit(kINT7) && collision.sel7(); + return isMultSelected && collision.alias_bit(kINT7) && collision.sel7(); } else if (cfgTrigger == 8) { - return collision.sel8(); + return isMultSelected && collision.sel8(); + } else if (cfgTrigger == 9) { // relevant only for Pb-Pb + return isMultSelected && collision.sel8() && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && collision.selection_bit(aod::evsel::kIsGoodITSLayersAll); + } else if (cfgTrigger == 10) { // TVX trigger only (sel8 selection before April, 2024) + return isMultSelected && collision.selection_bit(aod::evsel::kIsTriggerTVX); + } else if (cfgTrigger == 11) { // sel8 selection for MC + return isMultSelected && collision.selection_bit(aod::evsel::kIsTriggerTVX) && collision.selection_bit(aod::evsel::kNoTimeFrameBorder); + } else if (cfgTrigger == 12) { // relevant only for Pb-Pb with occupancy cuts and rejection of the collisions which have other events nearby + int occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy >= cfgMinOcc && occupancy < cfgMaxOcc) + return isMultSelected && collision.sel8() && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && collision.selection_bit(aod::evsel::kNoCollInTimeRangeStandard) && collision.selection_bit(aod::evsel::kIsGoodITSLayersAll); + else + return false; } return false; } - void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks) + template + uint8_t getTrackType(TTrack& track) + { + if (cfgTrackSelection == 0) { + if (track.isGlobalTrack()) { + return 1; + } else if (track.isGlobalTrackSDD()) { + return 2; + } + return 0; + } else if (cfgTrackSelection == 1) { + uint8_t trackType = 0; + if (track.isGlobalTrack()) { + trackType |= kTrackSelected; + if (track.itsNCls() >= 5) { + trackType |= kITS5Clusters; + } + if (track.tpcNClsCrossedRows() >= 90) { + trackType |= kTPC90CrossedRows; + } + } + return trackType; + } + LOGF(fatal, "Invalid setting for cfgTrackSelection: %d", cfgTrackSelection.value); + return 0; + } + + void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks) { if (cfgVerbosity > 0) { LOGF(info, "processData: Tracks for collision: %d | Vertex: %.1f (%d) | INT7: %d | Multiplicity: %.1f", tracks.size(), collision.posZ(), collision.flags(), collision.sel7(), collision.multiplicity()); @@ -112,14 +172,7 @@ struct FilterCF { outputCollRefs(collision.globalIndex()); for (auto& track : tracks) { - uint8_t trackType = 0; - if (track.isGlobalTrack()) { - trackType = 1; - } else if (track.isGlobalTrackSDD()) { - trackType = 2; - } - - outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), trackType); + outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), getTrackType(track)); if (cfgTransientTables) outputTrackRefs(collision.globalIndex(), track.globalIndex()); @@ -134,14 +187,16 @@ struct FilterCF { Preslice perCollision = aod::track::collisionId; void processMC(aod::McCollisions const& mcCollisions, aod::McParticles const& allParticles, soa::Join const& allCollisions, - soa::Filtered> const& tracks, + soa::Filtered> const& tracks, aod::BCsWithTimestamps const&) { - bool* reconstructed = new bool[allParticles.size()]; - int* mcParticleLabels = new int[allParticles.size()]; + mcReconstructedCache.reserve(allParticles.size()); + mcParticleLabelsCache.reserve(allParticles.size()); + mcReconstructedCache.clear(); + mcParticleLabelsCache.clear(); for (int i = 0; i < allParticles.size(); i++) { - reconstructed[i] = false; - mcParticleLabels[i] = -1; + mcReconstructedCache.push_back(false); + mcParticleLabelsCache.push_back(-1); } // PASS 1 on collisions: check which particles are kept @@ -157,7 +212,7 @@ struct FilterCF { for (auto& track : groupedTracks) { if (track.has_mcParticle()) { - reconstructed[track.mcParticleId()] = true; + mcReconstructedCache[track.mcParticleId()] = true; } } } @@ -177,25 +232,29 @@ struct FilterCF { if (pdgparticle != nullptr) { sign = (pdgparticle->Charge() > 0) ? 1.0 : ((pdgparticle->Charge() < 0) ? -1.0 : 0.0); } + + bool special = !cfgMcSpecialPDGs->empty() && std::find(cfgMcSpecialPDGs->begin(), cfgMcSpecialPDGs->end(), particle.pdgCode()) != cfgMcSpecialPDGs->end(); bool primary = particle.isPhysicalPrimary() && sign != 0 && std::abs(particle.eta()) < cfgCutMCEta && particle.pt() > cfgCutMCPt; if (primary) { multiplicity++; } - if (reconstructed[particle.globalIndex()] || primary) { + if (mcReconstructedCache[particle.globalIndex()] || primary || special) { // keep particle // use highest bit to flag if it is reconstructed uint8_t flags = particle.flags() & ~aod::cfmcparticle::kReconstructed; // clear bit in case of clashes in the future - if (reconstructed[particle.globalIndex()]) { + if (mcReconstructedCache[particle.globalIndex()]) { flags |= aod::cfmcparticle::kReconstructed; } // NOTE using "outputMcCollisions.lastIndex()+1" here to allow filling of outputMcCollisions *after* the loop outputMcParticles(outputMcCollisions.lastIndex() + 1, truncateFloatFraction(particle.pt(), FLOAT_PRECISION), truncateFloatFraction(particle.eta(), FLOAT_PRECISION), truncateFloatFraction(particle.phi(), FLOAT_PRECISION), sign, particle.pdgCode(), flags); + if (cfgTransientTables) + outputMcParticleRefs(outputMcCollisions.lastIndex() + 1, particle.globalIndex()); // relabeling array - mcParticleLabels[particle.globalIndex()] = outputMcParticles.lastIndex(); + mcParticleLabelsCache[particle.globalIndex()] = outputMcParticles.lastIndex(); } } outputMcCollisions(mcCollision.posZ(), multiplicity); @@ -216,35 +275,48 @@ struct FilterCF { // NOTE works only when we store all MC collisions (as we do here) outputCollisions(bc.runNumber(), collision.posZ(), collision.multiplicity(), bc.timestamp()); outputMcCollisionLabels(collision.mcCollisionId()); + if (cfgTransientTables) + outputCollRefs(collision.globalIndex()); for (auto& track : groupedTracks) { - uint8_t trackType = 0; - if (track.isGlobalTrack()) { - trackType = 1; - } else if (track.isGlobalTrackSDD()) { - trackType = 2; - } - int mcParticleId = track.mcParticleId(); if (mcParticleId >= 0) { - mcParticleId = mcParticleLabels[track.mcParticleId()]; + mcParticleId = mcParticleLabelsCache[track.mcParticleId()]; if (mcParticleId < 0) { - LOGP(fatal, "processMC: Track {} is referring to a MC particle which we do not store {} {} (reco flag {})", track.index(), track.mcParticleId(), mcParticleId, reconstructed[track.mcParticleId()]); + LOGP(fatal, "processMC: Track {} is referring to a MC particle which we do not store {} {} (reco flag {})", track.index(), track.mcParticleId(), mcParticleId, static_cast(mcReconstructedCache[track.mcParticleId()])); } } outputTracks(outputCollisions.lastIndex(), - truncateFloatFraction(track.pt()), truncateFloatFraction(track.eta()), truncateFloatFraction(track.phi()), track.sign(), trackType); + truncateFloatFraction(track.pt()), truncateFloatFraction(track.eta()), truncateFloatFraction(track.phi()), track.sign(), getTrackType(track)); outputTrackLabels(mcParticleId); + if (cfgTransientTables) + outputTrackRefs(collision.globalIndex(), track.globalIndex()); yields->Fill(collision.multiplicity(), track.pt(), track.eta()); etaphi->Fill(collision.multiplicity(), track.eta(), track.phi()); } } - - delete[] reconstructed; - delete[] mcParticleLabels; } PROCESS_SWITCH(FilterCF, processMC, "Process MC", false); + + void processMCGen(aod::McCollisions::iterator const& mcCollision, aod::McParticles const& particles) + { + float multiplicity = 0.0f; + for (auto& particle : particles) { + if (!particle.isPhysicalPrimary() || std::abs(particle.eta()) > cfgCutMCEta || particle.pt() < cfgCutMCPt) + continue; + int8_t sign = 0; + if (TParticlePDG* pdgparticle = pdg->GetParticle(particle.pdgCode())) + if ((sign = pdgparticle->Charge()) != 0) + multiplicity += 1.0f; + outputMcParticles(outputMcCollisions.lastIndex() + 1, truncateFloatFraction(particle.pt(), FLOAT_PRECISION), + truncateFloatFraction(particle.eta(), FLOAT_PRECISION), + truncateFloatFraction(particle.phi(), FLOAT_PRECISION), + sign, particle.pdgCode(), particle.flags()); + } + outputMcCollisions(mcCollision.posZ(), multiplicity); + } + PROCESS_SWITCH(FilterCF, processMCGen, "Process MCGen", false); }; struct MultiplicitySelector { @@ -271,9 +343,18 @@ struct MultiplicitySelector { if (doprocessFT0C) { enabledFunctions++; } + if (doprocessFT0CVariant1) { + enabledFunctions++; + } if (doprocessFT0A) { enabledFunctions++; } + if (doprocessCentNGlobal) { + enabledFunctions++; + } + if (doprocessMCGen) { + enabledFunctions++; + } if (enabledFunctions != 1) { LOGP(fatal, "{} multiplicity selectors enabled but we need exactly 1.", enabledFunctions); @@ -302,6 +383,14 @@ struct MultiplicitySelector { } PROCESS_SWITCH(MultiplicitySelector, processFT0C, "Select FT0C centrality as multiplicity", false); + void processFT0CVariant1(aod::CentFT0CVariant1s const& centralities) + { + for (auto& c : centralities) { + output(c.centFT0CVariant1()); + } + } + PROCESS_SWITCH(MultiplicitySelector, processFT0CVariant1, "Select FT0CVariant1 centrality as multiplicity", false); + void processFT0A(aod::CentFT0As const& centralities) { for (auto& c : centralities) { @@ -310,6 +399,14 @@ struct MultiplicitySelector { } PROCESS_SWITCH(MultiplicitySelector, processFT0A, "Select FT0A centrality as multiplicity", false); + void processCentNGlobal(aod::CentNGlobals const& centralities) + { + for (auto& c : centralities) { + output(c.centNGlobal()); + } + } + PROCESS_SWITCH(MultiplicitySelector, processCentNGlobal, "Select CentNGlobal centrality as multiplicity", false); + void processRun2V0M(aod::CentRun2V0Ms const& centralities) { for (auto& c : centralities) { @@ -317,6 +414,12 @@ struct MultiplicitySelector { } } PROCESS_SWITCH(MultiplicitySelector, processRun2V0M, "Select V0M centrality as multiplicity", true); + + void processMCGen(aod::McCollision const&, aod::McParticles const& particles) + { + output(particles.size()); + } + PROCESS_SWITCH(MultiplicitySelector, processMCGen, "Select MC particle count as multiplicity", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGCF/Tasks/CMakeLists.txt b/PWGCF/Tasks/CMakeLists.txt index fdc35cf2ef6..233cb351d13 100644 --- a/PWGCF/Tasks/CMakeLists.txt +++ b/PWGCF/Tasks/CMakeLists.txt @@ -14,13 +14,13 @@ o2physics_add_dpl_workflow(dptdptcorrelations PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(dptdpt-filter-qa - SOURCES dptdptfilterqa.cxx +o2physics_add_dpl_workflow(dpt-dpt-filter-qa + SOURCES dptDptFilterQa.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(match-reco-gen - SOURCES match-reco-gen.cxx + SOURCES matchRecoGen.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) diff --git a/PWGCF/Tasks/correlations.cxx b/PWGCF/Tasks/correlations.cxx index 4a6be921bf9..7461cc4b671 100644 --- a/PWGCF/Tasks/correlations.cxx +++ b/PWGCF/Tasks/correlations.cxx @@ -8,12 +8,21 @@ // 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 correlations.cxx +/// \brief task for the correlation calculations with CF-filtered tracks for O2 analysis +/// \author Jan Fiete Grosse-Oetringhaus , Jasper Parkkila + #include +#include +#include #include #include #include #include +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -24,6 +33,7 @@ #include "Framework/HistogramRegistry.h" #include "Framework/RunningWorkflowInfo.h" #include "CommonConstants/MathConstants.h" +#include "Common/Core/RecoDecay.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -52,7 +62,7 @@ using namespace constants::math; // cfcorreff::Correction); // } // namespace o2::aod -static constexpr float cfgPairCutDefaults[1][5] = {{-1, -1, -1, -1, -1}}; +static constexpr float kCfgPairCutDefaults[1][5] = {{-1, -1, -1, -1, -1}}; struct CorrelationTask { SliceCache cache; @@ -66,12 +76,15 @@ struct CorrelationTask { O2_DEFINE_CONFIGURABLE(cfgTriggerCharge, int, 0, "Select on charge of trigger particle: 0 = all; 1 = positive; -1 = negative"); O2_DEFINE_CONFIGURABLE(cfgAssociatedCharge, int, 0, "Select on charge of associated particle: 0 = all; 1 = positive; -1 = negative"); O2_DEFINE_CONFIGURABLE(cfgPairCharge, int, 0, "Select on charge of particle pair: 0 = all; 1 = like sign; -1 = unlike sign"); + O2_DEFINE_CONFIGURABLE(cfgCorrelationMethod, int, 0, "Correlation method, 0 = all, 1 = dd, 2 = ddbar"); O2_DEFINE_CONFIGURABLE(cfgTwoTrackCut, float, -1, "Two track cut: -1 = off; >0 otherwise distance value (suggested: 0.02)"); O2_DEFINE_CONFIGURABLE(cfgTwoTrackCutMinRadius, float, 0.8f, "Two track cut: radius in m from which two track cuts are applied"); - + O2_DEFINE_CONFIGURABLE(cfgLocalEfficiency, int, 0, "0 = OFF and 1 = ON for local efficiency"); + O2_DEFINE_CONFIGURABLE(cfgCentBinsForMC, int, 0, "0 = OFF and 1 = ON for data like multiplicity/centrality bins for MC steps"); + O2_DEFINE_CONFIGURABLE(cfgTrackBitMask, uint8_t, 0, "BitMask for track selection systematics; refer to the enum TrackSelectionCuts in filtering task"); // Suggested values: Photon: 0.004; K0 and Lambda: 0.005 - Configurable> cfgPairCut{"cfgPairCut", {cfgPairCutDefaults[0], 5, {"Photon", "K0", "Lambda", "Phi", "Rho"}}, "Pair cuts on various particles"}; + Configurable> cfgPairCut{"cfgPairCut", {kCfgPairCutDefaults[0], 5, {"Photon", "K0", "Lambda", "Phi", "Rho"}}, "Pair cuts on various particles"}; O2_DEFINE_CONFIGURABLE(cfgEfficiencyTrigger, std::string, "", "CCDB path to efficiency object for trigger particles") O2_DEFINE_CONFIGURABLE(cfgEfficiencyAssociated, std::string, "", "CCDB path to efficiency object for associated particles") @@ -82,6 +95,10 @@ struct CorrelationTask { O2_DEFINE_CONFIGURABLE(cfgDecayParticleMask, int, 0, "Selection bitmask for the decay particles: 0 = no selection") O2_DEFINE_CONFIGURABLE(cfgMassAxis, int, 0, "Use invariant mass axis (0 = OFF, 1 = ON)") + O2_DEFINE_CONFIGURABLE(cfgMcTriggerPDGs, std::vector, {}, "MC PDG codes to use exclusively as trigger particles and exclude from associated particles. Empty = no selection.") + + O2_DEFINE_CONFIGURABLE(cfgPtDepMLbkg, std::vector, {}, "pT interval for ML training") + O2_DEFINE_CONFIGURABLE(cfgPtCentDepMLbkgSel, std::vector, {}, "Bkg ML selection") ConfigurableAxis axisVertex{"axisVertex", {7, -7, 7}, "vertex axis for histograms"}; ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {72, -PIHalf, PIHalf * 3}, "delta phi axis for histograms"}; @@ -100,11 +117,11 @@ struct CorrelationTask { // This filter is applied to AOD and derived data (column names are identical) Filter collisionZVtxFilter = nabs(aod::collision::posZ) < cfgCutVertex; // This filter is only applied to AOD - Filter collisionVertexTypeFilter = (aod::collision::flags & (uint16_t)aod::collision::CollisionFlagsRun2::Run2VertexerTracks) == (uint16_t)aod::collision::CollisionFlagsRun2::Run2VertexerTracks; + Filter collisionVertexTypeFilter = (aod::collision::flags & static_cast(aod::collision::CollisionFlagsRun2::Run2VertexerTracks)) == static_cast(aod::collision::CollisionFlagsRun2::Run2VertexerTracks); // Track filters Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPt) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)); - Filter cfTrackFilter = (nabs(aod::cftrack::eta) < cfgCutEta) && (aod::cftrack::pt > cfgCutPt); + Filter cfTrackFilter = (nabs(aod::cftrack::eta) < cfgCutEta) && (aod::cftrack::pt > cfgCutPt) && ((aod::track::trackType & (uint8_t)cfgTrackBitMask) == (uint8_t)cfgTrackBitMask); // MC filters Filter cfMCCollisionFilter = nabs(aod::mccollision::posZ) < cfgCutVertex; @@ -117,7 +134,9 @@ struct CorrelationTask { OutputObj same{"sameEvent"}; OutputObj mixed{"mixedEvent"}; + // persistent caches std::vector efficiencyAssociatedCache; + std::vector p2indexCache; struct Config { bool mPairCuts = false; @@ -131,21 +150,26 @@ struct CorrelationTask { Service ccdb; - using aodCollisions = soa::Filtered>; - using aodTracks = soa::Filtered>; + using AodCollisions = soa::Filtered>; + using AodTracks = soa::Filtered>; - using derivedTracks = soa::Filtered; - using derivedCollisions = soa::Filtered; + using DerivedCollisions = soa::Filtered; + using DerivedTracks = soa::Filtered; void init(o2::framework::InitContext&) { registry.add("yields", "multiplicity/centrality vs pT vs eta", {HistType::kTH3F, {{100, 0, 100, "/multiplicity/centrality"}, {40, 0, 20, "p_{T}"}, {100, -2, 2, "#eta"}}}); - registry.add("etaphi", "multiplicity/centrality vs eta vs phi", {HistType::kTH3F, {{100, 0, 100, "multiplicity/centrality"}, {100, -2, 2, "#eta"}, {200, 0, 2 * M_PI, "#varphi"}}}); - if (doprocessSame2ProngDerived || doprocessMixed2ProngDerived) { + registry.add("etaphi", "multiplicity/centrality vs eta vs phi", {HistType::kTH3F, {{100, 0, 100, "multiplicity/centrality"}, {100, -2, 2, "#eta"}, {200, 0, o2::constants::math::TwoPI, "#varphi"}}}); + if (doprocessSame2ProngDerived || doprocessSame2ProngDerivedML || doprocessSame2Prong2Prong || doprocessSame2Prong2ProngML) { registry.add("yieldsTrigger", "multiplicity/centrality vs pT vs eta (triggers)", {HistType::kTH3F, {{100, 0, 100, "/multiplicity/centrality"}, {40, 0, 20, "p_{T}"}, {100, -2, 2, "#eta"}}}); - registry.add("etaphiTrigger", "multiplicity/centrality vs eta vs phi (triggers)", {HistType::kTH3F, {{100, 0, 100, "multiplicity/centrality"}, {100, -2, 2, "#eta"}, {200, 0, 2 * M_PI, "#varphi"}}}); + registry.add("etaphiTrigger", "multiplicity/centrality vs eta vs phi (triggers)", {HistType::kTH3F, {{100, 0, 100, "multiplicity/centrality"}, {100, -2, 2, "#eta"}, {200, 0, o2::constants::math::TwoPI, "#varphi"}}}); registry.add("invMass", "2-prong invariant mass (GeV/c^2)", {HistType::kTH3F, {axisInvMassHistogram, axisPtTrigger, axisMultiplicity}}); + if (doprocessSame2Prong2Prong || doprocessSame2Prong2ProngML) { + registry.add("invMassTwoPart", "2D 2-prong invariant mass (GeV/c^2)", {HistType::kTHnSparseF, {axisInvMassHistogram, axisInvMassHistogram, axisPtTrigger, axisPtAssoc, axisMultiplicity}}); + registry.add("invMassTwoPartDPhi", "2D 2-prong invariant mass (GeV/c^2)", {HistType::kTHnSparseF, {axisInvMassHistogram, axisInvMassHistogram, axisPtTrigger, axisPtAssoc, axisDeltaPhi}}); + } } + registry.add("multiplicity", "event multiplicity", {HistType::kTH1F, {{1000, 0, 100, "/multiplicity/centrality"}}}); const int maxMixBin = AxisSpec(axisMultiplicity).getNbins() * AxisSpec(axisVertex).getNbins(); registry.add("eventcount_same", "bin", {HistType::kTH1F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}}}); @@ -178,15 +202,30 @@ struct CorrelationTask { {axisPtEfficiency, "p_{T} (GeV/c)"}, {axisVertexEfficiency, "z-vtx (cm)"}}; std::vector userAxis; - if (cfgMassAxis != 0) + std::vector userMixingAxis; + + if (cfgMassAxis != 0) { userAxis.emplace_back(axisInvMass, "m (GeV/c^2)"); + userMixingAxis.emplace_back(axisInvMass, "m (GeV/c^2)"); + } + if (doprocessSame2Prong2Prong || doprocessSame2Prong2ProngML) + userAxis.emplace_back(axisInvMass, "m (GeV/c^2)"); + if (doprocessMixed2Prong2Prong || doprocessMixed2Prong2ProngML) + userMixingAxis.emplace_back(axisInvMass, "m (GeV/c^2)"); + same.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, userAxis)); - mixed.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, userAxis)); + mixed.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, userMixingAxis)); same->setTrackEtaCut(cfgCutEta); mixed->setTrackEtaCut(cfgCutEta); - efficiencyAssociatedCache.reserve(512); + if (!cfgEfficiencyAssociated.value.empty()) + efficiencyAssociatedCache.reserve(512); + if (doprocessMCEfficiency2Prong) { + p2indexCache.reserve(16); + if (cfgMcTriggerPDGs->empty()) + LOGF(fatal, "At least one PDG code in {} is to be selected to process 2-prong efficiency.", cfgMcTriggerPDGs.name); + } // o2-ccdb-upload -p Users/jgrosseo/correlations/LHC15o -f /tmp/correction_2011_global.root -k correction @@ -215,28 +254,90 @@ struct CorrelationTask { return grpo->getNominalL3Field(); } + template + bool passMLScore(const p2typeIterator& track) + { + auto it = std::lower_bound(cfgPtDepMLbkg->begin(), cfgPtDepMLbkg->end(), track.pt()); + int idx = std::distance(cfgPtDepMLbkg->begin(), it) - 1; + return !((track.decay() == 0 && track.mlProbD0()[0] > cfgPtCentDepMLbkgSel->at(idx)) || (track.decay() == 1 && track.mlProbD0bar()[0] > cfgPtCentDepMLbkgSel->at(idx))); + } + template void fillQA(const TCollision& /*collision*/, float multiplicity, const TTracks& tracks) { - for (auto& track1 : tracks) { + registry.fill(HIST("multiplicity"), multiplicity); + for (const auto& track1 : tracks) { registry.fill(HIST("yields"), multiplicity, track1.pt(), track1.eta()); registry.fill(HIST("etaphi"), multiplicity, track1.eta(), track1.phi()); } } template - using hasInvMass = decltype(std::declval().invMass()); + using HasInvMass = decltype(std::declval().invMass()); + template + using HasPDGCode = decltype(std::declval().pdgCode()); template void fillQA(const TCollision& collision, float multiplicity, const TTracks1& tracks1, const TTracks2& tracks2) { - for (auto& track1 : tracks1) { - if constexpr (std::experimental::is_detected::value) { - if constexpr (std::experimental::is_detected::value) { - if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << (uint32_t)track1.decay())) == 0u) + for (const auto& track1 : tracks1) { + if constexpr (std::experimental::is_detected::value && std::experimental::is_detected::value) { + if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << static_cast(track1.decay()))) == 0u) + continue; + if constexpr (std::experimental::is_detected::value) { + if (!passMLScore(track1)) continue; } registry.fill(HIST("invMass"), track1.invMass(), track1.pt(), multiplicity); + for (const auto& track2 : tracks2) { + if constexpr (std::experimental::is_detected::value && std::experimental::is_detected::value) { + if (doprocessSame2Prong2Prong || doprocessMixed2Prong2Prong || doprocessSame2Prong2ProngML || doprocessMixed2Prong2ProngML) { + if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << static_cast(track1.decay()))) == 0u) + continue; + if constexpr (std::experimental::is_detected::value) { + if (!passMLScore(track2)) + continue; + } + + if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { + if (track1.cfTrackProng0Id() == track2.cfTrackProng0Id()) { + continue; + } + } + if constexpr (std::experimental::is_detected::value) { + if (track1.cfTrackProng0Id() == track2.cfTrackProng1Id()) { + continue; + } + } + } + + if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { + if (track1.cfTrackProng1Id() == track2.cfTrackProng0Id()) { + continue; + } + } + if constexpr (std::experimental::is_detected::value) { + if (track1.cfTrackProng1Id() == track2.cfTrackProng1Id()) { + continue; + } + } + } // no shared prong for two mothers + + if (cfgCorrelationMethod == 1 && track1.decay() != track2.decay()) + continue; + if (cfgCorrelationMethod == 2 && track1.decay() == track2.decay()) + continue; + registry.fill(HIST("invMassTwoPart"), track1.invMass(), track2.invMass(), track1.pt(), track2.pt(), multiplicity); + registry.fill(HIST("invMassTwoPartDPhi"), track1.invMass(), track2.invMass(), track1.pt(), track2.pt(), TVector2::Phi_0_2pi(track1.phi() - track2.phi() + TMath::Pi() / 2.0) - TMath::Pi() / 2.0); + } + } + } + } + if constexpr (std::experimental::is_detected::value) { + if (!cfgMcTriggerPDGs->empty() && std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), track1->pdgCode()) == cfgMcTriggerPDGs->end()) + continue; } registry.fill(HIST("yieldsTrigger"), multiplicity, track1.pt(), track1.eta()); registry.fill(HIST("etaphiTrigger"), multiplicity, track1.eta(), track1.phi()); @@ -273,13 +374,15 @@ struct CorrelationTask { } template - using hasSign = decltype(std::declval().sign()); + using HasSign = decltype(std::declval().sign()); + template + using HasDecay = decltype(std::declval().decay()); template - using hasDecay = decltype(std::declval().decay()); + using HasProng0Id = decltype(std::declval().cfTrackProng0Id()); template - using hasProng0Id = decltype(std::declval().cfTrackProng0Id()); + using HasProng1Id = decltype(std::declval().cfTrackProng1Id()); template - using hasProng1Id = decltype(std::declval().cfTrackProng1Id()); + using HasMlProbD0 = decltype(std::declval().mlProbD0()); template void fillCorrelations(TTarget target, TTracks1& tracks1, TTracks2& tracks2, float multiplicity, float posZ, int magField, float eventWeight) @@ -289,13 +392,13 @@ struct CorrelationTask { if (cfg.mEfficiencyAssociated) { efficiencyAssociatedCache.clear(); efficiencyAssociatedCache.reserve(tracks2.size()); - for (auto& track : tracks2) { + for (const auto& track : tracks2) { efficiencyAssociatedCache.push_back(getEfficiencyCorrection(cfg.mEfficiencyAssociated, track.eta(), track.pt(), multiplicity, posZ)); } } } - for (auto& track1 : tracks1) { + for (const auto& track1 : tracks1) { // LOGF(info, "Track %f | %f | %f %d %d", track1.eta(), track1.phi(), track1.pt(), track1.isGlobalTrack(), track1.isGlobalTrackSDD()); if constexpr (step <= CorrelationContainer::kCFStepTracked) { @@ -304,12 +407,17 @@ struct CorrelationTask { } } - if constexpr (std::experimental::is_detected::value) { - if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << (uint32_t)track1.decay())) == 0u) + if constexpr (std::experimental::is_detected::value) { + if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << static_cast(track1.decay()))) == 0u) continue; } - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { + if (!cfgMcTriggerPDGs->empty() && std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), track1.pdgCode()) == cfgMcTriggerPDGs->end()) + continue; + } + + if constexpr (std::experimental::is_detected::value) { if (cfgTriggerCharge != 0 && cfgTriggerCharge * track1.sign() < 0) { continue; } @@ -322,20 +430,37 @@ struct CorrelationTask { } } - target->getTriggerHist()->Fill(step, track1.pt(), multiplicity, posZ, triggerWeight); + if constexpr (std::experimental::is_detected::value) { + if ((doprocessSame2ProngDerivedML || doprocessSame2Prong2ProngML || doprocessMixed2ProngDerivedML || doprocessMixed2Prong2ProngML) && !passMLScore(track1)) + continue; + } // ML selection + + if (cfgMassAxis) { + if constexpr (std::experimental::is_detected::value) + target->getTriggerHist()->Fill(step, track1.pt(), multiplicity, posZ, track1.invMass(), triggerWeight); + else + LOGF(fatal, "Can not fill mass axis without invMass column. Disable cfgMassAxis."); + } else { + target->getTriggerHist()->Fill(step, track1.pt(), multiplicity, posZ, triggerWeight); + } - for (auto& track2 : tracks2) { + for (const auto& track2 : tracks2) { if constexpr (std::is_same::value) { if (track1.globalIndex() == track2.globalIndex()) { // LOGF(info, "Track identical: %f | %f | %f || %f | %f | %f", track1.eta(), track1.phi(), track1.pt(), track2.eta(), track2.phi(), track2.pt()); continue; } } - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { + if (!cfgMcTriggerPDGs->empty() && std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), track2.pdgCode()) != cfgMcTriggerPDGs->end()) + continue; + } + + if constexpr (std::experimental::is_detected::value) { if (track2.globalIndex() == track1.cfTrackProng0Id()) // do not correlate daughter tracks of the same event continue; } - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { if (track2.globalIndex() == track1.cfTrackProng1Id()) // do not correlate daughter tracks of the same event continue; } @@ -346,15 +471,55 @@ struct CorrelationTask { } } + if constexpr (std::experimental::is_detected::value) { + if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << static_cast(track2.decay()))) == 0u) + continue; + } + + if constexpr (std::experimental::is_detected::value && std::experimental::is_detected::value) { + if (cfgCorrelationMethod == 1 && track1.decay() != track2.decay()) + continue; + if (cfgCorrelationMethod == 2 && track1.decay() == track2.decay()) + continue; + } + + if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { + if (track1.cfTrackProng0Id() == track2.cfTrackProng0Id()) { + continue; + } + } + if constexpr (std::experimental::is_detected::value) { + if (track1.cfTrackProng0Id() == track2.cfTrackProng1Id()) { + continue; + } + } + } + + if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { + if (track1.cfTrackProng1Id() == track2.cfTrackProng0Id()) { + continue; + } + } + if constexpr (std::experimental::is_detected::value) { + if (track1.cfTrackProng1Id() == track2.cfTrackProng1Id()) { + continue; + } + } + } // no shared prong for two mothers + if (cfgPtOrder != 0 && track2.pt() >= track1.pt()) { continue; } - if (cfgAssociatedCharge != 0 && cfgAssociatedCharge * track2.sign() < 0) { - continue; + if constexpr (std::experimental::is_detected::value) { + if (cfgAssociatedCharge != 0 && cfgAssociatedCharge * track2.sign() < 0) { + continue; + } } - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value && std::experimental::is_detected::value) { if (cfgPairCharge != 0 && cfgPairCharge * track1.sign() * track2.sign() < 0) { continue; } @@ -362,12 +527,13 @@ struct CorrelationTask { if constexpr (std::is_same::value) { if constexpr (step >= CorrelationContainer::kCFStepReconstructed) { - if (cfg.mPairCuts && mPairCuts.conversionCuts(track1, track2)) { - continue; - } - - if (cfgTwoTrackCut > 0 && mPairCuts.twoTrackCut(track1, track2, magField)) { - continue; + if constexpr (std::experimental::is_detected::value && std::experimental::is_detected::value) { + if (cfg.mPairCuts && mPairCuts.conversionCuts(track1, track2)) { + continue; + } + if (cfgTwoTrackCut > 0 && mPairCuts.twoTrackCut(track1, track2, magField)) { + continue; + } } } } @@ -379,17 +545,21 @@ struct CorrelationTask { } } - float deltaPhi = track1.phi() - track2.phi(); - if (deltaPhi > 1.5f * PI) { - deltaPhi -= TwoPI; - } - if (deltaPhi < -PIHalf) { - deltaPhi += TwoPI; - } + float deltaPhi = RecoDecay::constrainAngle(track1.phi() - track2.phi(), -o2::constants::math::PIHalf); + + if constexpr (std::experimental::is_detected::value) { + if ((doprocessSame2ProngDerivedML || doprocessSame2Prong2ProngML || doprocessMixed2ProngDerivedML || doprocessMixed2Prong2ProngML) && !passMLScore(track2)) + continue; + } // ML selection // last param is the weight - if (cfgMassAxis) { - if constexpr (std::experimental::is_detected::value) + if (cfgMassAxis && (doprocessSame2Prong2Prong || doprocessMixed2Prong2Prong || doprocessSame2Prong2ProngML || doprocessMixed2Prong2ProngML) && !(doprocessSame2ProngDerived || doprocessSame2ProngDerivedML || doprocessMixed2ProngDerived || doprocessMixed2ProngDerivedML)) { + if constexpr (std::experimental::is_detected::value && std::experimental::is_detected::value) + target->getPairHist()->Fill(step, track1.eta() - track2.eta(), track2.pt(), track1.pt(), multiplicity, deltaPhi, posZ, track2.invMass(), track1.invMass(), associatedWeight); + else + LOGF(fatal, "Can not fill mass axis without invMass column. \n no mass for two particles"); + } else if (cfgMassAxis) { + if constexpr (std::experimental::is_detected::value) target->getPairHist()->Fill(step, track1.eta() - track2.eta(), track2.pt(), track1.pt(), multiplicity, deltaPhi, posZ, track1.invMass(), associatedWeight); else LOGF(fatal, "Can not fill mass axis without invMass column. Disable cfgMassAxis."); @@ -406,14 +576,24 @@ struct CorrelationTask { return; } if (cfgEfficiencyTrigger.value.empty() == false) { - cfg.mEfficiencyTrigger = ccdb->getForTimeStamp>(cfgEfficiencyTrigger, timestamp); + if (cfgLocalEfficiency > 0) { + TFile* fEfficiencyTrigger = TFile::Open(cfgEfficiencyTrigger.value.c_str(), "READ"); + cfg.mEfficiencyTrigger = reinterpret_cast(fEfficiencyTrigger->Get("ccdb_object")); + } else { + cfg.mEfficiencyTrigger = ccdb->getForTimeStamp>(cfgEfficiencyTrigger, timestamp); + } if (cfg.mEfficiencyTrigger == nullptr) { LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgEfficiencyTrigger.value.c_str()); } LOGF(info, "Loaded efficiency histogram for trigger particles from %s (%p)", cfgEfficiencyTrigger.value.c_str(), (void*)cfg.mEfficiencyTrigger); } if (cfgEfficiencyAssociated.value.empty() == false) { - cfg.mEfficiencyAssociated = ccdb->getForTimeStamp>(cfgEfficiencyAssociated, timestamp); + if (cfgLocalEfficiency > 0) { + TFile* fEfficiencyAssociated = TFile::Open(cfgEfficiencyAssociated.value.c_str(), "READ"); + cfg.mEfficiencyAssociated = reinterpret_cast(fEfficiencyAssociated->Get("ccdb_object")); + } else { + cfg.mEfficiencyAssociated = ccdb->getForTimeStamp>(cfgEfficiencyAssociated, timestamp); + } if (cfg.mEfficiencyAssociated == nullptr) { LOGF(fatal, "Could not load efficiency histogram for associated particles from %s", cfgEfficiencyAssociated.value.c_str()); } @@ -433,7 +613,7 @@ struct CorrelationTask { } // Version with explicit nested loop - void processSameAOD(aodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, aodTracks const& tracks) + void processSameAOD(AodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, AodTracks const& tracks) { // NOTE legacy function for O2 integration tests. Full version needs derived data @@ -456,8 +636,9 @@ struct CorrelationTask { } PROCESS_SWITCH(CorrelationTask, processSameAOD, "Process same event on AOD", true); - void processSameDerived(derivedCollisions::iterator const& collision, soa::Filtered const& tracks) + void processSameDerived(DerivedCollisions::iterator const& collision, soa::Filtered const& tracks) { + BinningTypeDerived configurableBinningDerived{{axisVertex, axisMultiplicity}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. if (cfgVerbosity > 0) { LOGF(info, "processSameDerived: Tracks for collision: %d | Vertex: %.1f | Multiplicity/Centrality: %.1f", tracks.size(), collision.posZ(), collision.multiplicity()); } @@ -483,8 +664,10 @@ struct CorrelationTask { } PROCESS_SWITCH(CorrelationTask, processSameDerived, "Process same event on derived data", false); - void processSame2ProngDerived(derivedCollisions::iterator const& collision, soa::Filtered const& tracks, soa::Filtered const& p2tracks) + template + void processSame2ProngDerivedT(DerivedCollisions::iterator const& collision, soa::Filtered const& tracks, p2type const& p2tracks) { + BinningTypeDerived configurableBinningDerived{{axisVertex, axisMultiplicity}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. if (cfgVerbosity > 0) { LOGF(info, "processSame2ProngDerived: Tracks for collision: %d | 2-prong candidates: %d | Vertex: %.1f | Multiplicity/Centrality: %.1f", tracks.size(), p2tracks.size(), collision.posZ(), collision.multiplicity()); } @@ -504,17 +687,64 @@ struct CorrelationTask { fillCorrelations(same, p2tracks, tracks, multiplicity, collision.posZ(), 0, 1.0f); } } + + void processSame2ProngDerived(DerivedCollisions::iterator const& collision, soa::Filtered const& tracks, soa::Filtered const& p2tracks) + { + processSame2ProngDerivedT(collision, tracks, p2tracks); + } PROCESS_SWITCH(CorrelationTask, processSame2ProngDerived, "Process same event on derived data", false); + void processSame2ProngDerivedML(DerivedCollisions::iterator const& collision, soa::Filtered const& tracks, soa::Filtered> const& p2tracks) + { + processSame2ProngDerivedT(collision, tracks, p2tracks); + } + PROCESS_SWITCH(CorrelationTask, processSame2ProngDerivedML, "Process same event on derived data with ML scores", false); + + template + void processSame2Prong2ProngT(DerivedCollisions::iterator const& collision, p2type const& p2tracks) + { + BinningTypeDerived configurableBinningDerived{{axisVertex, axisMultiplicity}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. + if (cfgVerbosity > 0) { + LOGF(info, "processSame2ProngDerived: 2-prong candidates: %d | Vertex: %.1f | Multiplicity/Centrality: %.1f", p2tracks.size(), collision.posZ(), collision.multiplicity()); + } + loadEfficiency(collision.timestamp()); + + const auto multiplicity = collision.multiplicity(); + + int bin = configurableBinningDerived.getBin({collision.posZ(), collision.multiplicity()}); + registry.fill(HIST("eventcount_same"), bin); + fillQA(collision, multiplicity, p2tracks, p2tracks); + + same->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelations(same, p2tracks, p2tracks, multiplicity, collision.posZ(), 0, 1.0f); + + if (cfg.mEfficiencyAssociated || cfg.mEfficiencyTrigger) { + same->fillEvent(multiplicity, CorrelationContainer::kCFStepCorrected); + fillCorrelations(same, p2tracks, p2tracks, multiplicity, collision.posZ(), 0, 1.0f); + } + } + + void processSame2Prong2Prong(DerivedCollisions::iterator const& collision, soa::Filtered const& p2tracks) + { + processSame2Prong2ProngT(collision, p2tracks); + } + PROCESS_SWITCH(CorrelationTask, processSame2Prong2Prong, "Process same event on derived data", false); + + void processSame2Prong2ProngML(DerivedCollisions::iterator const& collision, soa::Filtered> const& p2tracks) + { + processSame2Prong2ProngT(collision, p2tracks); + } + PROCESS_SWITCH(CorrelationTask, processSame2Prong2ProngML, "Process same event on derived data with ML scores", false); + using BinningTypeAOD = ColumnBinningPolicy; - void processMixedAOD(aodCollisions& collisions, aodTracks const& tracks, aod::BCsWithTimestamps const&) + void processMixedAOD(AodCollisions const& collisions, AodTracks const& tracks, aod::BCsWithTimestamps const&) { // NOTE legacy function for O2 integration tests. Full version needs derived data // Strictly upper categorised collisions, for cfgNoMixedEvents combinations per bin, skipping those in entry -1 BinningTypeAOD configurableBinning{{axisVertex, axisMultiplicity}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. auto tracksTuple = std::make_tuple(tracks); - SameKindPair pairs{configurableBinning, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + SameKindPair pairs{configurableBinning, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip int skipID = -1; for (auto it = pairs.begin(); it != pairs.end(); it++) { @@ -550,12 +780,12 @@ struct CorrelationTask { PROCESS_SWITCH(CorrelationTask, processMixedAOD, "Process mixed events on AOD", false); using BinningTypeDerived = ColumnBinningPolicy; - BinningTypeDerived configurableBinningDerived{{axisVertex, axisMultiplicity}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. - void processMixedDerived(derivedCollisions& collisions, derivedTracks const& tracks) + void processMixedDerived(DerivedCollisions const& collisions, DerivedTracks const& tracks) { + BinningTypeDerived configurableBinningDerived{{axisVertex, axisMultiplicity}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. // Strictly upper categorised collisions, for cfgNoMixedEvents combinations per bin, skipping those in entry -1 auto tracksTuple = std::make_tuple(tracks); - SameKindPair pairs{configurableBinningDerived, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + SameKindPair pairs{configurableBinningDerived, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip for (auto it = pairs.begin(); it != pairs.end(); it++) { auto& [collision1, tracks1, collision2, tracks2] = *it; @@ -591,11 +821,13 @@ struct CorrelationTask { } PROCESS_SWITCH(CorrelationTask, processMixedDerived, "Process mixed events on derived data", false); - void processMixed2ProngDerived(derivedCollisions& collisions, derivedTracks const& tracks, soa::Filtered const& p2tracks) + template + void processMixed2ProngDerivedT(DerivedCollisions const& collisions, DerivedTracks const& tracks, p2type const& p2tracks) { + BinningTypeDerived configurableBinningDerived{{axisVertex, axisMultiplicity}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. // Strictly upper categorised collisions, for cfgNoMixedEvents combinations per bin, skipping those in entry -1 auto tracksTuple = std::make_tuple(p2tracks, tracks); - Pair, derivedTracks, BinningTypeDerived> pairs{configurableBinningDerived, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + Pair pairs{configurableBinningDerived, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip for (auto it = pairs.begin(); it != pairs.end(); it++) { auto& [collision1, tracks1, collision2, tracks2] = *it; @@ -627,8 +859,70 @@ struct CorrelationTask { } } } + + void processMixed2ProngDerived(DerivedCollisions const& collisions, DerivedTracks const& tracks, soa::Filtered const& p2tracks) + { + processMixed2ProngDerivedT(collisions, tracks, p2tracks); + } PROCESS_SWITCH(CorrelationTask, processMixed2ProngDerived, "Process mixed events on derived data", false); + void processMixed2ProngDerivedML(DerivedCollisions const& collisions, DerivedTracks const& tracks, soa::Filtered> const& p2tracks) + { + processMixed2ProngDerivedT(collisions, tracks, p2tracks); + } + PROCESS_SWITCH(CorrelationTask, processMixed2ProngDerivedML, "Process mixed events on derived data with ML scores", false); + + template + void processMixed2Prong2ProngT(DerivedCollisions const& collisions, p2type const& p2tracks) + { + BinningTypeDerived configurableBinningDerived{{axisVertex, axisMultiplicity}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. + // Strictly upper categorised collisions, for cfgNoMixedEvents combinations per bin, skipping those in entry -1 + auto tracksTuple = std::make_tuple(p2tracks); + SameKindPair pairs{configurableBinningDerived, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + + for (auto it = pairs.begin(); it != pairs.end(); it++) { + auto& [collision1, tracks1, collision2, tracks2] = *it; + int bin = configurableBinningDerived.getBin({collision1.posZ(), collision1.multiplicity()}); + float eventWeight = 1.0f / it.currentWindowNeighbours(); + int field = 0; + if (cfgTwoTrackCut > 0) { + field = getMagneticField(collision1.timestamp()); + } + + if (cfgVerbosity > 0) { + LOGF(info, "processMixedDerived: Mixed collisions bin: %d pair: [%d, %d] %d (%.3f, %.3f), %d (%.3f, %.3f)", bin, it.isNewWindow(), it.currentWindowNeighbours(), collision1.globalIndex(), collision1.posZ(), collision1.multiplicity(), collision2.globalIndex(), collision2.posZ(), collision2.multiplicity()); + } + + if (it.isNewWindow()) { + loadEfficiency(collision1.timestamp()); + mixed->fillEvent(collision1.multiplicity(), CorrelationContainer::kCFStepReconstructed); + } + + // LOGF(info, "Tracks: %d and %d entries", tracks1.size(), tracks2.size()); + + registry.fill(HIST("eventcount_mixed"), bin); + fillCorrelations(mixed, tracks1, tracks2, collision1.multiplicity(), collision1.posZ(), field, eventWeight); + if (cfg.mEfficiencyAssociated || cfg.mEfficiencyTrigger) { + if (it.isNewWindow()) { + mixed->fillEvent(collision1.multiplicity(), CorrelationContainer::kCFStepCorrected); + } + fillCorrelations(mixed, tracks1, tracks2, collision1.multiplicity(), collision1.posZ(), field, eventWeight); + } + } + } + + void processMixed2Prong2Prong(DerivedCollisions const& collisions, soa::Filtered const& p2tracks) + { + processMixed2Prong2ProngT(collisions, p2tracks); + } + PROCESS_SWITCH(CorrelationTask, processMixed2Prong2Prong, "Process mixed events on derived data", false); + + void processMixed2Prong2ProngML(DerivedCollisions const& collisions, soa::Filtered> const& p2tracks) + { + processMixed2Prong2ProngT(collisions, p2tracks); + } + PROCESS_SWITCH(CorrelationTask, processMixed2Prong2ProngML, "Process mixed events on derived data with ML scores", false); + // Version with combinations /*void processWithCombinations(soa::Join::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered const& tracks) { @@ -651,7 +945,7 @@ struct CorrelationTask { // mixed->getTriggerHist()->Fill(eventValues, CorrelationContainer::kCFStepReconstructed); } - for (auto& [track1, track2] : combinations(tracks, tracks)) { + for (const auto& [track1, track2] : combinations(tracks, tracks)) { // LOGF(info, "Combination %d %d", track1.index(), track2.index()); if (cfgTriggerCharge != 0 && cfgTriggerCharge * track1.sign() < 0) { @@ -672,14 +966,7 @@ struct CorrelationTask { continue; } - float deltaPhi = track1.phi() - track2.phi(); - if (deltaPhi > 1.5f * PI) { - deltaPhi -= TwoPI; - } - if (deltaPhi < -PIHalf) { - deltaPhi += TwoPI; - } - + float deltaPhi = RecoDecay::constrainAngle(track1.phi() - track2.phi(), -o2::constants::math: :PIHalf); same->getPairHist()->Fill(CorrelationContainer::kCFStepReconstructed, track1.eta() - track2.eta(), track2.pt(), track1.pt(), multiplicity, deltaPhi, collision.posZ()); // mixed->getPairHist()->Fill(values, CorrelationContainer::kCFStepReconstructed); @@ -687,7 +974,7 @@ struct CorrelationTask { } PROCESS_SWITCH(CorrelationTask, processWithCombinations, "Process same event on AOD with combinations", false);*/ - int GetSpecies(int pdgCode) + int getSpecies(int pdgCode) { switch (pdgCode) { case 211: // pion @@ -699,7 +986,7 @@ struct CorrelationTask { case 2212: // proton case -2212: return 2; - default: + default: // NOTE. The efficiency histogram is hardcoded to contain 4 species. Anything special will have the last slot. return 3; } } @@ -712,28 +999,35 @@ struct CorrelationTask { LOGF(info, "MC collision at vtx-z = %f with %d mc particles and %d reconstructed collisions", mcCollision.posZ(), mcParticles.size(), collisions.size()); } - // Primaries auto multiplicity = mcCollision.multiplicity(); - for (auto& mcParticle : mcParticles) { + if (cfgCentBinsForMC > 0) { + if (collisions.size() == 0) { + return; + } + for (const auto& collision : collisions) { + multiplicity = collision.multiplicity(); + } + } + // Primaries + for (const auto& mcParticle : mcParticles) { if (mcParticle.isPhysicalPrimary() && mcParticle.sign() != 0) { - same->getTrackHistEfficiency()->Fill(CorrelationContainer::MC, mcParticle.eta(), mcParticle.pt(), GetSpecies(mcParticle.pdgCode()), multiplicity, mcCollision.posZ()); + same->getTrackHistEfficiency()->Fill(CorrelationContainer::MC, mcParticle.eta(), mcParticle.pt(), getSpecies(mcParticle.pdgCode()), multiplicity, mcCollision.posZ()); } } - - for (auto& collision : collisions) { + for (const auto& collision : collisions) { auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex()); if (cfgVerbosity > 0) { LOGF(info, " Reconstructed collision at vtx-z = %f", collision.posZ()); LOGF(info, " which has %d tracks", groupedTracks.size()); } - for (auto& track : groupedTracks) { + for (const auto& track : groupedTracks) { if (track.has_cfMCParticle()) { const auto& mcParticle = track.cfMCParticle(); if (mcParticle.isPhysicalPrimary()) { - same->getTrackHistEfficiency()->Fill(CorrelationContainer::RecoPrimaries, mcParticle.eta(), mcParticle.pt(), GetSpecies(mcParticle.pdgCode()), multiplicity, mcCollision.posZ()); + same->getTrackHistEfficiency()->Fill(CorrelationContainer::RecoPrimaries, mcParticle.eta(), mcParticle.pt(), getSpecies(mcParticle.pdgCode()), multiplicity, mcCollision.posZ()); } - same->getTrackHistEfficiency()->Fill(CorrelationContainer::RecoAll, mcParticle.eta(), mcParticle.pt(), GetSpecies(mcParticle.pdgCode()), multiplicity, mcCollision.posZ()); + same->getTrackHistEfficiency()->Fill(CorrelationContainer::RecoAll, mcParticle.eta(), mcParticle.pt(), getSpecies(mcParticle.pdgCode()), multiplicity, mcCollision.posZ()); // LOGF(info, "Filled track %d", track.globalIndex()); } else { // fake track @@ -744,6 +1038,57 @@ struct CorrelationTask { } PROCESS_SWITCH(CorrelationTask, processMCEfficiency, "MC: Extract efficiencies", false); + Preslice perCollision2Prong = aod::cftrack::cfCollisionId; + void processMCEfficiency2Prong(soa::Filtered::iterator const& mcCollision, soa::Join const& mcParticles, soa::SmallGroups const& collisions, aod::CFTracksWithLabel const&, aod::CF2ProngTracks const& p2tracks) + { + auto multiplicity = mcCollision.multiplicity(); + if (cfgCentBinsForMC > 0) { + if (collisions.size() == 0) { + return; + } + for (const auto& collision : collisions) { + multiplicity = collision.multiplicity(); + } + } + // Primaries + p2indexCache.clear(); + for (const auto& mcParticle : mcParticles) { + if (mcParticle.isPhysicalPrimary() && std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), mcParticle.pdgCode()) != cfgMcTriggerPDGs->end()) { + same->getTrackHistEfficiency()->Fill(CorrelationContainer::MC, mcParticle.eta(), mcParticle.pt(), getSpecies(mcParticle.pdgCode()), multiplicity, mcCollision.posZ()); + if (mcParticle.cfParticleDaugh0Id() < 0 || mcParticle.cfParticleDaugh1Id() < 0) + continue; + p2indexCache.push_back(mcParticle.globalIndex()); + } + } + for (const auto& collision : collisions) { + auto grouped2ProngTracks = p2tracks.sliceBy(perCollision2Prong, collision.globalIndex()); + + for (const auto& p2track : grouped2ProngTracks) { + // Check if the mc particles of the prongs are found. + const auto& p0 = p2track.cfTrackProng0_as(); + const auto& p1 = p2track.cfTrackProng1_as(); + if (p0.has_cfMCParticle() && p1.has_cfMCParticle()) { + // find the 2-prong MC particle by the daughter MC particle IDs + auto m = std::find_if(p2indexCache.begin(), p2indexCache.end(), [&](const auto& t) -> bool { + const auto& mcParticle = mcParticles.iteratorAt(t); + return p0.cfMCParticleId() == mcParticle.cfParticleDaugh0Id() && p1.cfMCParticleId() == mcParticle.cfParticleDaugh1Id(); + }); + if (m == p2indexCache.end()) + continue; + const auto& mcParticle = mcParticles.iteratorAt(*m); + if (mcParticle.isPhysicalPrimary()) { + same->getTrackHistEfficiency()->Fill(CorrelationContainer::RecoPrimaries, mcParticle.eta(), mcParticle.pt(), getSpecies(mcParticle.pdgCode()), multiplicity, mcCollision.posZ()); + } + same->getTrackHistEfficiency()->Fill(CorrelationContainer::RecoAll, mcParticle.eta(), mcParticle.pt(), getSpecies(mcParticle.pdgCode()), multiplicity, mcCollision.posZ()); + } else { + // fake track + same->getTrackHistEfficiency()->Fill(CorrelationContainer::Fake, p2track.eta(), p2track.pt(), 0, multiplicity, mcCollision.posZ()); + } + } + } + } + PROCESS_SWITCH(CorrelationTask, processMCEfficiency2Prong, "MC: Extract efficiencies for 2-prong particles", false); + // NOTE SmallGroups includes soa::Filtered always void processMCSameDerived(soa::Filtered::iterator const& mcCollision, soa::Filtered const& mcParticles, soa::SmallGroups const& collisions) { @@ -751,33 +1096,60 @@ struct CorrelationTask { LOGF(info, "processMCSameDerived. MC collision: %d, particles: %d, collisions: %d", mcCollision.globalIndex(), mcParticles.size(), collisions.size()); } - same->fillEvent(mcCollision.multiplicity(), CorrelationContainer::kCFStepAll); - fillCorrelations(same, mcParticles, mcParticles, mcCollision.multiplicity(), mcCollision.posZ(), 0, 1.0f); + auto multiplicity = mcCollision.multiplicity(); + if (cfgCentBinsForMC > 0) { + if (collisions.size() == 0) { + return; + } + for (const auto& collision : collisions) { + multiplicity = collision.multiplicity(); + } + if (cfgVerbosity > 0) { + LOGF(info, " Data multiplicity: %f", multiplicity); + } + } + + fillQA(mcCollision, multiplicity, mcParticles); + + same->fillEvent(multiplicity, CorrelationContainer::kCFStepAll); + fillCorrelations(same, mcParticles, mcParticles, multiplicity, mcCollision.posZ(), 0, 1.0f); if (collisions.size() == 0) { return; } - same->fillEvent(mcCollision.multiplicity(), CorrelationContainer::kCFStepVertex); - fillCorrelations(same, mcParticles, mcParticles, mcCollision.multiplicity(), mcCollision.posZ(), 0, 1.0f); + same->fillEvent(multiplicity, CorrelationContainer::kCFStepVertex); + fillCorrelations(same, mcParticles, mcParticles, multiplicity, mcCollision.posZ(), 0, 1.0f); - same->fillEvent(mcCollision.multiplicity(), CorrelationContainer::kCFStepTrackedOnlyPrim); - fillCorrelations(same, mcParticles, mcParticles, mcCollision.multiplicity(), mcCollision.posZ(), 0, 1.0f); + same->fillEvent(multiplicity, CorrelationContainer::kCFStepTrackedOnlyPrim); + fillCorrelations(same, mcParticles, mcParticles, multiplicity, mcCollision.posZ(), 0, 1.0f); - same->fillEvent(mcCollision.multiplicity(), CorrelationContainer::kCFStepTracked); - fillCorrelations(same, mcParticles, mcParticles, mcCollision.multiplicity(), mcCollision.posZ(), 0, 1.0f); + same->fillEvent(multiplicity, CorrelationContainer::kCFStepTracked); + fillCorrelations(same, mcParticles, mcParticles, multiplicity, mcCollision.posZ(), 0, 1.0f); // NOTE kCFStepReconstructed and kCFStepCorrected are filled in processSameDerived // This also means that if a MC collision had several reconstructed vertices (collisions), all of them are filled } PROCESS_SWITCH(CorrelationTask, processMCSameDerived, "Process MC same event on derived data", false); - using BinningTypeMCDerived = ColumnBinningPolicy; PresliceUnsorted collisionPerMCCollision = aod::cfcollision::cfMcCollisionId; - void processMCMixedDerived(soa::Filtered& mcCollisions, soa::Filtered const& mcParticles, soa::Filtered const& collisions) + void processMCMixedDerived(soa::Filtered const& mcCollisions, soa::Filtered const& mcParticles, soa::Filtered const& collisions) { + bool useMCMultiplicity = (cfgCentBinsForMC == 0); + auto getMultiplicity = + [&collisions, &useMCMultiplicity, this](auto& col) { + if (useMCMultiplicity) + return col.multiplicity(); + auto groupedCollisions = collisions.sliceBy(collisionPerMCCollision, col.globalIndex()); + if (groupedCollisions.size() == 0) + return -1.0f; + return groupedCollisions.begin().multiplicity(); + }; + + using BinningTypeMCDerived = FlexibleBinningPolicy, aod::mccollision::PosZ, decltype(getMultiplicity)>; + BinningTypeMCDerived configurableBinning{{getMultiplicity}, {axisVertex, axisMultiplicity}, true}; + // Strictly upper categorised collisions, for cfgNoMixedEvents combinations per bin, skipping those in entry -1 - BinningTypeMCDerived configurableBinning{{axisVertex, axisMultiplicity}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. auto tuple = std::make_tuple(mcParticles); SameKindPair, soa::Filtered, BinningTypeMCDerived> pairs{configurableBinning, cfgNoMixedEvents, -1, mcCollisions, tuple, &cache}; // -1 is the number of the bin to skip @@ -785,17 +1157,17 @@ struct CorrelationTask { auto& [collision1, tracks1, collision2, tracks2] = *it; float eventWeight = 1.0f / it.currentWindowNeighbours(); + float multiplicity = getMultiplicity(collision1); if (cfgVerbosity > 0) { - int bin = configurableBinning.getBin({collision1.posZ(), collision1.multiplicity()}); - LOGF(info, "processMCMixedDerived: Mixed collisions bin: %d pair: [%d, %d] %d (%.3f, %.3f), %d (%.3f, %.3f)", bin, it.isNewWindow(), it.currentWindowNeighbours(), collision1.globalIndex(), collision1.posZ(), collision1.multiplicity(), collision2.globalIndex(), collision2.posZ(), collision2.multiplicity()); + int bin = configurableBinning.getBin(std::tuple(collision1.posZ(), multiplicity)); + LOGF(info, "processMCMixedDerived: Mixed collisions bin: %d pair: [%d, %d] %d (%.3f, %.3f), %d (%.3f, %.3f)", bin, it.isNewWindow(), it.currentWindowNeighbours(), collision1.globalIndex(), collision1.posZ(), getMultiplicity(collision1), collision2.globalIndex(), collision2.posZ(), getMultiplicity(collision2)); } // STEP 0 if (it.isNewWindow()) { - mixed->fillEvent(collision1.multiplicity(), CorrelationContainer::kCFStepAll); + mixed->fillEvent(multiplicity, CorrelationContainer::kCFStepAll); } - fillCorrelations(mixed, tracks1, tracks2, collision1.multiplicity(), collision1.posZ(), 0, eventWeight); - + fillCorrelations(mixed, tracks1, tracks2, multiplicity, collision1.posZ(), 0, eventWeight); // check if collision1 has at least one reconstructed collision auto groupedCollisions = collisions.sliceBy(collisionPerMCCollision, collision1.globalIndex()); if (cfgVerbosity > 0) { @@ -807,13 +1179,13 @@ struct CorrelationTask { // STEP 2, 4, 5 if (it.isNewWindow()) { - mixed->fillEvent(collision1.multiplicity(), CorrelationContainer::kCFStepVertex); - mixed->fillEvent(collision1.multiplicity(), CorrelationContainer::kCFStepTrackedOnlyPrim); - mixed->fillEvent(collision1.multiplicity(), CorrelationContainer::kCFStepTracked); + mixed->fillEvent(multiplicity, CorrelationContainer::kCFStepVertex); + mixed->fillEvent(multiplicity, CorrelationContainer::kCFStepTrackedOnlyPrim); + mixed->fillEvent(multiplicity, CorrelationContainer::kCFStepTracked); } - fillCorrelations(mixed, tracks1, tracks2, collision1.multiplicity(), collision1.posZ(), 0, eventWeight); - fillCorrelations(mixed, tracks1, tracks2, collision1.multiplicity(), collision1.posZ(), 0, eventWeight); - fillCorrelations(mixed, tracks1, tracks2, collision1.multiplicity(), collision1.posZ(), 0, eventWeight); + fillCorrelations(mixed, tracks1, tracks2, multiplicity, collision1.posZ(), 0, eventWeight); + fillCorrelations(mixed, tracks1, tracks2, multiplicity, collision1.posZ(), 0, eventWeight); + fillCorrelations(mixed, tracks1, tracks2, multiplicity, collision1.posZ(), 0, eventWeight); // NOTE kCFStepReconstructed and kCFStepCorrected are filled in processMixedDerived // This also means that if a MC collision had several reconstructed vertices (collisions), all of them are filled diff --git a/PWGCF/Tasks/dptdptfilterqa.cxx b/PWGCF/Tasks/dptDptFilterQa.cxx similarity index 69% rename from PWGCF/Tasks/dptdptfilterqa.cxx rename to PWGCF/Tasks/dptDptFilterQa.cxx index a8479d20d1a..ebb50785a61 100644 --- a/PWGCF/Tasks/dptdptfilterqa.cxx +++ b/PWGCF/Tasks/dptDptFilterQa.cxx @@ -9,7 +9,12 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file dptDptFilterQa.cxx +/// \brief basic checks for the behavior of the filter task +/// \author victor.gonzalez.sebastian@gmail.com + #include +#include #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" @@ -30,12 +35,12 @@ namespace o2::analysis::dptdptfilterqa { typedef enum { kRECO = 0, kGEN } innerdatatype; -static constexpr std::string_view dirname[] = {"reconstructed/", "generated/"}; +static constexpr std::string_view Dirname[] = {"reconstructed/", "generated/"}; } // namespace o2::analysis::dptdptfilterqa // Checking the filtered tables -struct DptDptFilterQA { - Configurable cfgDataType{"datatype", "data", "Data type: data, MC, FastMC, OnTheFlyMC. Default data"}; +struct DptDptFilterQa { + Configurable cfgDataType{"cfgDataType", "data", "Data type: data, MC, FastMC, OnTheFlyMC. Default data"}; HistogramRegistry histos{"DptDptFilterQA", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; o2::analysis::dptdptfilter::DataType datatype; @@ -45,17 +50,17 @@ struct DptDptFilterQA { using namespace o2::analysis::dptdptfilterqa; - histos.add(TString::Format("%s%s", dirname[dir].data(), "TracksOne").Data(), "Tracks as track one", kTH1F, {{1500, 0.0, 1500.0, "number of tracks"}}); - histos.add(TString::Format("%s%s", dirname[dir].data(), "TracksTwo").Data(), "Tracks as track two", kTH1F, {{1500, 0.0, 1500.0, "number of tracks"}}); - histos.add(TString::Format("%s%s", dirname[dir].data(), "TracksOneAndTwo").Data(), "Tracks as track one and as track two", kTH1F, {{1500, 0.0, 1500.0, "number of tracks"}}); - histos.add(TString::Format("%s%s", dirname[dir].data(), "TracksNone").Data(), "Not selected tracks", kTH1F, {{1500, 0.0, 1500.0, "number of tracks"}}); - histos.add(TString::Format("%s%s", dirname[dir].data(), "TracksOneUnsel").Data(), "Tracks as track one", kTH1F, {{1500, 0.0, 1500.0, "number of tracks"}}); - histos.add(TString::Format("%s%s", dirname[dir].data(), "TracksTwoUnsel").Data(), "Tracks as track two", kTH1F, {{1500, 0.0, 1500.0, "number of tracks"}}); - histos.add(TString::Format("%s%s", dirname[dir].data(), "TracksOneAndTwoUnsel").Data(), "Tracks as track one and as track two", kTH1F, {{1500, 0.0, 1500.0, "number of tracks"}}); - histos.add(TString::Format("%s%s", dirname[dir].data(), "TracksNoneUnsel").Data(), "Not selected tracks", kTH1F, {{1500, 0.0, 1500.0}}); - histos.add(TString::Format("%s%s", dirname[dir].data(), "SelectedEvents").Data(), "Selected events", kTH1F, {{2, 0.0, 2.0}}); - histos.get(HIST(dirname[dir]) + HIST("SelectedEvents"))->GetXaxis()->SetBinLabel(1, "Not selected events"); - histos.get(HIST(dirname[dir]) + HIST("SelectedEvents"))->GetXaxis()->SetBinLabel(2, "Selected events"); + histos.add(TString::Format("%s%s", Dirname[dir].data(), "TracksOne").Data(), "Tracks as track one", kTH1F, {{1500, 0.0, 1500.0, "number of tracks"}}); + histos.add(TString::Format("%s%s", Dirname[dir].data(), "TracksTwo").Data(), "Tracks as track two", kTH1F, {{1500, 0.0, 1500.0, "number of tracks"}}); + histos.add(TString::Format("%s%s", Dirname[dir].data(), "TracksOneAndTwo").Data(), "Tracks as track one and as track two", kTH1F, {{1500, 0.0, 1500.0, "number of tracks"}}); + histos.add(TString::Format("%s%s", Dirname[dir].data(), "TracksNone").Data(), "Not selected tracks", kTH1F, {{1500, 0.0, 1500.0, "number of tracks"}}); + histos.add(TString::Format("%s%s", Dirname[dir].data(), "TracksOneUnsel").Data(), "Tracks as track one", kTH1F, {{1500, 0.0, 1500.0, "number of tracks"}}); + histos.add(TString::Format("%s%s", Dirname[dir].data(), "TracksTwoUnsel").Data(), "Tracks as track two", kTH1F, {{1500, 0.0, 1500.0, "number of tracks"}}); + histos.add(TString::Format("%s%s", Dirname[dir].data(), "TracksOneAndTwoUnsel").Data(), "Tracks as track one and as track two", kTH1F, {{1500, 0.0, 1500.0, "number of tracks"}}); + histos.add(TString::Format("%s%s", Dirname[dir].data(), "TracksNoneUnsel").Data(), "Not selected tracks", kTH1F, {{1500, 0.0, 1500.0}}); + histos.add(TString::Format("%s%s", Dirname[dir].data(), "SelectedEvents").Data(), "Selected events", kTH1F, {{2, 0.0, 2.0}}); + histos.get(HIST(Dirname[dir]) + HIST("SelectedEvents"))->GetXaxis()->SetBinLabel(1, "Not selected events"); + histos.get(HIST(Dirname[dir]) + HIST("SelectedEvents"))->GetXaxis()->SetBinLabel(2, "Selected events"); }; void init(InitContext const&) @@ -88,40 +93,40 @@ struct DptDptFilterQA { using namespace o2::analysis::dptdptfilterqa; if (collision.collisionaccepted() != uint8_t(true)) { - histos.fill(HIST(dirname[dir]) + HIST("SelectedEvents"), 0.5); + histos.fill(HIST(Dirname[dir]) + HIST("SelectedEvents"), 0.5); } else { - histos.fill(HIST(dirname[dir]) + HIST("SelectedEvents"), 1.5); + histos.fill(HIST(Dirname[dir]) + HIST("SelectedEvents"), 1.5); } - int ntracks_one = 0; - int ntracks_two = 0; - int ntracks_one_and_two = 0; - int ntracks_none = 0; - for (auto& track : tracks) { + int nTracksOne = 0; + int nTracksTwo = 0; + int nTracksOneAndTwo = 0; + int nTracksNone = 0; + for (auto const& track : tracks) { if (!(track.trackacceptedid() < 0) && !(track.trackacceptedid() < 2)) { LOGF(fatal, "Task not prepared for identified particles"); } if (track.trackacceptedid() != 0 && track.trackacceptedid() != 1) { - ntracks_none++; + nTracksNone++; } if (track.trackacceptedid() == 0) { - ntracks_one++; + nTracksOne++; } if (track.trackacceptedid() == 1) { - ntracks_two++; + nTracksTwo++; } } if (collision.collisionaccepted() != uint8_t(true)) { /* control for non selected events */ - histos.fill(HIST(dirname[dir]) + HIST("TracksOneUnsel"), ntracks_one); - histos.fill(HIST(dirname[dir]) + HIST("TracksTwoUnsel"), ntracks_two); - histos.fill(HIST(dirname[dir]) + HIST("TracksNoneUnsel"), ntracks_none); - histos.fill(HIST(dirname[dir]) + HIST("TracksOneAndTwoUnsel"), ntracks_one_and_two); + histos.fill(HIST(Dirname[dir]) + HIST("TracksOneUnsel"), nTracksOne); + histos.fill(HIST(Dirname[dir]) + HIST("TracksTwoUnsel"), nTracksTwo); + histos.fill(HIST(Dirname[dir]) + HIST("TracksNoneUnsel"), nTracksNone); + histos.fill(HIST(Dirname[dir]) + HIST("TracksOneAndTwoUnsel"), nTracksOneAndTwo); } else { - histos.fill(HIST(dirname[dir]) + HIST("TracksOne"), ntracks_one); - histos.fill(HIST(dirname[dir]) + HIST("TracksTwo"), ntracks_two); - histos.fill(HIST(dirname[dir]) + HIST("TracksNone"), ntracks_none); - histos.fill(HIST(dirname[dir]) + HIST("TracksOneAndTwo"), ntracks_one_and_two); + histos.fill(HIST(Dirname[dir]) + HIST("TracksOne"), nTracksOne); + histos.fill(HIST(Dirname[dir]) + HIST("TracksTwo"), nTracksTwo); + histos.fill(HIST(Dirname[dir]) + HIST("TracksNone"), nTracksNone); + histos.fill(HIST(Dirname[dir]) + HIST("TracksOneAndTwo"), nTracksOneAndTwo); } } @@ -134,7 +139,7 @@ struct DptDptFilterQA { LOGF(DPTDPTFILTERLOGCOLLISIONS, "New filtered generated collision with BC id %d and with %d accepted tracks", collision.bcId(), tracks.size()); processQATask(collision, tracks); } - PROCESS_SWITCH(DptDptFilterQA, processGeneratorLevel, "Process generator level filter task QA", true); + PROCESS_SWITCH(DptDptFilterQa, processGeneratorLevel, "Process generator level filter task QA", true); void processDetectorLevel(soa::Filtered::iterator const& collision, soa::Filtered const& tracks) { @@ -142,11 +147,11 @@ struct DptDptFilterQA { LOGF(DPTDPTFILTERLOGCOLLISIONS, "New filtered collision with BC id %d and with %d accepted tracks", collision.bcId(), tracks.size()); processQATask(collision, tracks); } - PROCESS_SWITCH(DptDptFilterQA, processDetectorLevel, "Process detector level filter task QA", true); + PROCESS_SWITCH(DptDptFilterQa, processDetectorLevel, "Process detector level filter task QA", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; return workflow; } diff --git a/PWGCF/Tasks/dptdptcorrelations.cxx b/PWGCF/Tasks/dptdptcorrelations.cxx index d8c11906e85..10849b9901b 100644 --- a/PWGCF/Tasks/dptdptcorrelations.cxx +++ b/PWGCF/Tasks/dptdptcorrelations.cxx @@ -9,8 +9,11 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file dptdptcorrelations.cxx +/// \brief implements two-particle correlations base data collection +/// \author victor.gonzalez.sebastian@gmail.com + #include -#include #include #include #include @@ -21,6 +24,9 @@ #include #include #include +#include +#include +#include #include #include @@ -51,7 +57,6 @@ using namespace o2::framework::expressions; namespace correlationstask { using namespace o2::analysis::dptdptfilter; -float phibinshift = 0.5; float etabinwidth = (etaup - etalow) / static_cast(etabins); float phibinwidth = (phiup - philow) / static_cast(phibins); int deltaetabins = etabins * 2 - 1; @@ -62,9 +67,12 @@ float deltaphibinwidth = constants::math::TwoPI / deltaphibins; float deltaphilow = 0.0 - deltaphibinwidth / 2.0; float deltaphiup = constants::math::TwoPI - deltaphibinwidth / 2.0; -bool processpairs = false; -bool processmixedevents = false; -bool ptorder = false; +int nNoOfDimensions = 1; // number of dimensions for the NUA & NUE corrections +bool processpairs = false; // process pairs analysis +bool processmixedevents = false; // process mixed events +bool ptorder = false; // consider pt ordering +bool invmass = false; // produce the invariant mass histograms +bool corrana = false; // produce the correlation analysis histograms PairCuts fPairCuts; // pair suppression engine bool fUseConversionCuts = false; // suppress resonances and conversions @@ -72,6 +80,7 @@ bool fUseTwoTrackCut = false; // suppress too close tracks std::vector poinames; ///< the species of interest names std::vector tnames; ///< the track names +std::vector poimass; ///< the species of interest mass std::vector> trackPairsNames; ///< the track pairs names } // namespace correlationstask @@ -87,32 +96,35 @@ struct DptDptCorrelationsTask { // The DptDptCorrelationsAnalysisTask output objects //============================================================================================ /* histograms */ - TH1F* fhVertexZA; //! fhN1_vsPt{nch, nullptr}; //! fhN1_vsEtaPhi{nch, nullptr}; //! fhSum1Pt_vsEtaPhi{nch, nullptr}; //! fhN1_vsZEtaPhiPt{nch, nullptr}; //! fhSum1Pt_vsZEtaPhiPt{nch, nullptr}; //! fhNuaNue_vsZEtaPhiPt{nch, nullptr}; //! fhPtAvg_vsEtaPhi{nch, nullptr}; //!> fhN2_vsPtPt{nch, {nch, nullptr}}; //!> fhN2_vsDEtaDPhi{nch, {nch, nullptr}}; //!> fhN2cont_vsDEtaDPhi{nch, {nch, nullptr}}; //!> fhSum2PtPt_vsDEtaDPhi{nch, {nch, nullptr}}; //!> fhSum2DptDpt_vsDEtaDPhi{nch, {nch, nullptr}}; //!) ({p_T}_2 - <{p_T}_2>) \f$ distribution vs \f$\Delta\eta,\;\Delta\phi\f$ for the different species combinations - std::vector> fhSupN1N1_vsDEtaDPhi{nch, {nch, nullptr}}; //!> fhSupPt1Pt1_vsDEtaDPhi{nch, {nch, nullptr}}; //! fhN1VsPt{nch, nullptr}; //! fhN1VsPtEta{nch, nullptr}; //! fhN1VsEtaPhi{nch, nullptr}; //! fhSum1PtVsEtaPhi{nch, nullptr}; //! fhN1VsZEtaPhiPt{nch, nullptr}; //! fhSum1PtVsZEtaPhiPt{nch, nullptr}; //! fhNuaNue{nch, nullptr}; //! fhPtAvgVsEtaPhi{nch, nullptr}; //!> fhN2VsPtPt{nch, {nch, nullptr}}; //!> fhN2VsDEtaDPhi{nch, {nch, nullptr}}; //!> fhN2contVsDEtaDPhi{nch, {nch, nullptr}}; //!> fhSum2PtPtVsDEtaDPhi{nch, {nch, nullptr}}; //!> fhSum2DptDptVsDEtaDPhi{nch, {nch, nullptr}}; //!) ({p_T}_2 - <{p_T}_2>) \f$ distribution vs \f$\Delta\eta,\;\Delta\phi\f$ for the different species combinations + std::vector> fhSupN1N1VsDEtaDPhi{nch, {nch, nullptr}}; //!> fhSupPt1Pt1VsDEtaDPhi{nch, {nch, nullptr}}; //!> fhInvMassDEta{nch, {nch, nullptr}}; //!> fhInvMassDPhi{nch, {nch, nullptr}}; //! fhN1_vsC{nch, nullptr}; //! fhSum1Pt_vsC{nch, nullptr}; //! fhN1nw_vsC{nch, nullptr}; //! fhSum1Ptnw_vsC{nch, nullptr}; //!> fhN2_vsC{nch, {nch, nullptr}}; //!> fhSum2PtPt_vsC{nch, {nch, nullptr}}; //!> fhSum2DptDpt_vsC{nch, {nch, nullptr}}; //!) ({p_T}_2 - <{p_T}_2>) \f$ distribution vs event centrality/multiplicity 1-1,1-2,2-1,2-2, combinations - std::vector> fhN2nw_vsC{nch, {nch, nullptr}}; //!> fhSum2PtPtnw_vsC{nch, {nch, nullptr}}; //!> fhSum2DptDptnw_vsC{nch, {nch, nullptr}}; //!) ({p_T}_2 - <{p_T}_2>) \f$ distribution vs \f$\Delta\eta,\;\Delta\phi\f$ distribution vs event centrality/multiplicity 1-1,1-2,2-1,2-2, combinations + std::vector fhN1VsC{nch, nullptr}; //! fhSum1PtVsC{nch, nullptr}; //! fhN1nwVsC{nch, nullptr}; //! fhSum1PtnwVsC{nch, nullptr}; //!> fhN2VsC{nch, {nch, nullptr}}; //!> fhSum2PtPtVsC{nch, {nch, nullptr}}; //!> fhSum2DptDptVsC{nch, {nch, nullptr}}; //!) ({p_T}_2 - <{p_T}_2>) \f$ distribution vs event centrality/multiplicity 1-1,1-2,2-1,2-2, combinations + std::vector> fhN2nwVsC{nch, {nch, nullptr}}; //!> fhSum2PtPtnwVsC{nch, {nch, nullptr}}; //!> fhSum2DptDptnwVsC{nch, {nch, nullptr}}; //!) ({p_T}_2 - <{p_T}_2>) \f$ distribution vs \f$\Delta\eta,\;\Delta\phi\f$ distribution vs event centrality/multiplicity 1-1,1-2,2-1,2-2, combinations bool ccdbstored = false; @@ -124,7 +136,7 @@ struct DptDptCorrelationsTask { /// \brief Returns the potentially phi origin shifted phi /// \param phi the track azimuthal angle /// \return the track phi origin shifted azimuthal angle - float GetShiftedPhi(float phi) + float getShiftedPhi(float phi) { using namespace correlationstask; using namespace o2::analysis::dptdptfilter; @@ -148,19 +160,76 @@ struct DptDptCorrelationsTask { /// the track has been accepted and it is within that ranges /// IF THAT IS NOT THE CASE THE ROUTINE WILL PRODUCE NONSENSE RESULTS template - int GetEtaPhiIndex(TrackObject const& t) + int getEtaPhiIndex(TrackObject const& t) { using namespace correlationstask; using namespace o2::analysis::dptdptfilter; int etaix = static_cast((t.eta() - etalow) / etabinwidth); /* consider a potential phi origin shift */ - float phi = GetShiftedPhi(t.phi()); + float phi = getShiftedPhi(t.phi()); int phiix = static_cast((phi - philow) / phibinwidth); return etaix * phibins + phiix; } - /// \brief Returns the TH2 global index for the differential histograms + /// \brief Returns the delta eta value for the differential eta + /// \param t1 the intended track one + /// \param t2 the intended track two + /// \return the delta eta value for delta eta + /// + /// WARNING: for performance reasons no checks are done about the consistency + /// of tracks' eta and phi within the corresponding ranges so, it is suppossed + /// the tracks have been accepted and they are within that ranges + /// IF THAT IS NOT THE CASE THE ROUTINE WILL PRODUCE NONSENSE RESULTS + template + float getDEtaValue(TrackObject const& t1, TrackObject const& t2) + { + using namespace correlationstask; + using namespace o2::analysis::dptdptfilter; + + /* rule: ix are always zero based while bins are always one based */ + int etaIx1 = static_cast((t1.eta() - etalow) / etabinwidth); + int etaIx2 = static_cast((t2.eta() - etalow) / etabinwidth); + + int deltaEtaIx = etaIx1 - etaIx2 + etabins - 1; + + return deltaetalow + (deltaEtaIx + 0.5) * deltaetabinwidth; + } + + /// \brief Returns the delta phi value for the differential phi + /// \param t1 the intended track one + /// \param t2 the intended track two + /// \return the delta phi value within [-pi,pi] for delta phi + /// + /// WARNING: for performance reasons no checks are done about the consistency + /// of tracks' eta and phi within the corresponding ranges so, it is suppossed + /// the tracks have been accepted and they are within that ranges + /// IF THAT IS NOT THE CASE THE ROUTINE WILL PRODUCE NONSENSE RESULTS + template + float getDPhiValue(TrackObject const& t1, TrackObject const& t2) + { + using namespace correlationstask; + using namespace o2::analysis::dptdptfilter; + + /* rule: ix are always zero based while bins are always one based */ + /* consider a potential phi origin shift */ + float phi = getShiftedPhi(t1.phi()); + int phiIx1 = static_cast((phi - philow) / phibinwidth); + /* consider a potential phi origin shift */ + phi = getShiftedPhi(t2.phi()); + int phiIx2 = static_cast((phi - philow) / phibinwidth); + + int deltaPhiIx = phiIx1 - phiIx2; + if (deltaPhiIx < 0) { + deltaPhiIx += phibins; + } + + float value = deltaphilow + (deltaPhiIx + 0.5) * deltaphibinwidth; + + return (value < (deltaphiup - constants::math::PI)) ? value : value - constants::math::TwoPI; + } + + /// \brief Returns the TH2 global bin for the differential histograms /// \param t1 the intended track one /// \param t2 the intended track two /// \return the globl TH2 bin for delta eta delta phi @@ -170,48 +239,100 @@ struct DptDptCorrelationsTask { /// the tracks have been accepted and they are within that ranges /// IF THAT IS NOT THE CASE THE ROUTINE WILL PRODUCE NONSENSE RESULTS template - int GetDEtaDPhiGlobalIndex(TrackObject const& t1, TrackObject const& t2) + int getDEtaDPhiGlobalBin(TrackObject const& t1, TrackObject const& t2) { using namespace correlationstask; using namespace o2::analysis::dptdptfilter; /* rule: ix are always zero based while bins are always one based */ - int etaix_1 = static_cast((t1.eta() - etalow) / etabinwidth); + int etaIx1 = static_cast((t1.eta() - etalow) / etabinwidth); /* consider a potential phi origin shift */ - float phi = GetShiftedPhi(t1.phi()); - int phiix_1 = static_cast((phi - philow) / phibinwidth); - int etaix_2 = static_cast((t2.eta() - etalow) / etabinwidth); + float phi = getShiftedPhi(t1.phi()); + int phiIx1 = static_cast((phi - philow) / phibinwidth); + int etaIx2 = static_cast((t2.eta() - etalow) / etabinwidth); /* consider a potential phi origin shift */ - phi = GetShiftedPhi(t2.phi()); - int phiix_2 = static_cast((phi - philow) / phibinwidth); + phi = getShiftedPhi(t2.phi()); + int phiIx2 = static_cast((phi - philow) / phibinwidth); - int deltaeta_ix = etaix_1 - etaix_2 + etabins - 1; - int deltaphi_ix = phiix_1 - phiix_2; - if (deltaphi_ix < 0) { - deltaphi_ix += phibins; + int deltaEtaIx = etaIx1 - etaIx2 + etabins - 1; + int deltaPhiIx = phiIx1 - phiIx2; + if (deltaPhiIx < 0) { + deltaPhiIx += phibins; } - return fhN2_vsDEtaDPhi[0][0]->GetBin(deltaeta_ix + 1, deltaphi_ix + 1); + return fhN2VsDEtaDPhi[0][0]->GetBin(deltaEtaIx + 1, deltaPhiIx + 1); } - void storeTrackCorrections(std::vector corrs) + /* taken from PWGCF/Core/PairCuts.h implemented by JFGO */ + template + double getInvMassSquared(TrackObject const& track1, double m0_1, TrackObject const& track2, double m0_2) { - LOGF(info, "Stored NUA&NUE corrections for %d track ids", corrs.size()); + // calculate inv mass squared + // same can be achieved, but with more computing time with + /*TLorentzVector photon, p1, p2; + p1.SetPtEtaPhiM(triggerParticle->Pt(), triggerEta, triggerParticle->Phi(), 0.510e-3); + p2.SetPtEtaPhiM(particle->Pt(), eta[j], particle->Phi(), 0.510e-3); + photon = p1+p2; + photon.M()*/ + + float tantheta1 = 1e10; + + if (track1.eta() < -1e-10 || track1.eta() > 1e-10) { + float expTmp = std::exp(-track1.eta()); + tantheta1 = 2.0 * expTmp / (1.0 - expTmp * expTmp); + } + + float tantheta2 = 1e10; + if (track2.eta() < -1e-10 || track2.eta() > 1e-10) { + float expTmp = std::exp(-track2.eta()); + tantheta2 = 2.0 * expTmp / (1.0 - expTmp * expTmp); + } + + float e1squ = m0_1 * m0_1 + track1.pt() * track1.pt() * (1.0 + 1.0 / tantheta1 / tantheta1); + float e2squ = m0_2 * m0_2 + track2.pt() * track2.pt() * (1.0 + 1.0 / tantheta2 / tantheta2); + + float mass2 = m0_1 * m0_1 + m0_2 * m0_2 + 2 * (std::sqrt(e1squ * e2squ) - (track1.pt() * track2.pt() * (std::cos(track1.phi() - track2.phi()) + 1.0 / tantheta1 / tantheta2))); + + return mass2; + } + + void storeTrackCorrections(std::vector corrs) + { + using namespace correlationstask; + + LOGF(info, "Storing NUA&NUE corrections for %d track ids", corrs.size()); for (uint i = 0; i < corrs.size(); ++i) { - LOGF(info, " Stored NUA&NUE corrections %s for track id %d %s", corrs[i] != nullptr ? corrs[i]->GetName() : "nullptr", i, corrs[i] != nullptr ? "yes" : "no"); - fhNuaNue_vsZEtaPhiPt[i] = corrs[i]; - if (fhNuaNue_vsZEtaPhiPt[i] != nullptr) { + if (corrs[i] != nullptr) { + if (nNoOfDimensions != corrs[i]->GetDimension()) { + LOGF(fatal, " Corrections received dimensions %d for track id %d different than expected %d", corrs[i]->GetDimension(), i, nNoOfDimensions); + } else { + LOGF(info, " Storing NUA&NUE corrections %s for track id %d with %d dimensions %s", + corrs[i] != nullptr ? corrs[i]->GetName() : "nullptr", i, nNoOfDimensions, corrs[i] != nullptr ? "yes" : "no"); + } + } + fhNuaNue[i] = corrs[i]; + if (fhNuaNue[i] != nullptr) { int nbins = 0; double avg = 0.0; - for (int ix = 0; ix < fhNuaNue_vsZEtaPhiPt[i]->GetNbinsX(); ++ix) { - for (int iy = 0; iy < fhNuaNue_vsZEtaPhiPt[i]->GetNbinsY(); ++iy) { - for (int iz = 0; iz < fhNuaNue_vsZEtaPhiPt[i]->GetNbinsZ(); ++iz) { - nbins++; - avg += fhNuaNue_vsZEtaPhiPt[i]->GetBinContent(ix + 1, iy + 1, iz + 1); + for (int ix = 0; ix < fhNuaNue[i]->GetNbinsX(); ++ix) { + if (nNoOfDimensions == 1) { + nbins++; + avg += fhNuaNue[i]->GetBinContent(ix + 1); + } else { + for (int iy = 0; iy < fhNuaNue[i]->GetNbinsY(); ++iy) { + if (nNoOfDimensions == 2) { + nbins++; + avg += fhNuaNue[i]->GetBinContent(ix + 1, iy + 1); + } else if (nNoOfDimensions == 3 || nNoOfDimensions == 4) { + for (int iz = 0; iz < fhNuaNue[i]->GetNbinsZ(); ++iz) { + nbins++; + avg += fhNuaNue[i]->GetBinContent(ix + 1, iy + 1, iz + 1); + } + } } } } - LOGF(info, "Average NUA&NUE correction for track id %d: %f", i, avg / nbins); + LOGF(info, " Average NUA&NUE correction for track id %d: %f", i, avg / nbins); } } ccdbstored = true; @@ -222,33 +343,54 @@ struct DptDptCorrelationsTask { LOGF(info, "Stored pT average for %d track ids", ptavgs.size()); for (uint i = 0; i < ptavgs.size(); ++i) { LOGF(info, " Stored pT average for track id %d %s", i, ptavgs[i] != nullptr ? "yes" : "no"); - fhPtAvg_vsEtaPhi[i] = ptavgs[i]; + fhPtAvgVsEtaPhi[i] = ptavgs[i]; } ccdbstored = true; } - template + template std::vector* getTrackCorrections(TrackListObject const& tracks, float zvtx) { std::vector* corr = new std::vector(tracks.size(), 1.0f); int index = 0; - for (auto& t : tracks) { - if (fhNuaNue_vsZEtaPhiPt[t.trackacceptedid()] != nullptr) { - (*corr)[index] = fhNuaNue_vsZEtaPhiPt[t.trackacceptedid()]->GetBinContent(fhNuaNue_vsZEtaPhiPt[t.trackacceptedid()]->FindFixBin(zvtx, GetEtaPhiIndex(t) + 0.5, t.pt())); + for (const auto& t : tracks) { + if (fhNuaNue[t.trackacceptedid()] != nullptr) { + if constexpr (nDim == 1) { + (*corr)[index] = fhNuaNue[t.trackacceptedid()]->GetBinContent(fhNuaNue[t.trackacceptedid()]->FindFixBin(t.pt())); + } else if constexpr (nDim == 2) { + (*corr)[index] = fhNuaNue[t.trackacceptedid()]->GetBinContent(fhNuaNue[t.trackacceptedid()]->FindFixBin(t.eta(), t.pt())); + } else if constexpr (nDim == 3) { + (*corr)[index] = fhNuaNue[t.trackacceptedid()]->GetBinContent(fhNuaNue[t.trackacceptedid()]->FindFixBin(zvtx, getEtaPhiIndex(t) + 0.5, t.pt())); + } } index++; } return corr; } + template + std::vector* getTrackCorrections(TrackListObject const& tracks, float zvtx) + { + using namespace correlationstask; + + if (nNoOfDimensions == 1) { + return getTrackCorrections<1>(tracks, zvtx); + } else if (nNoOfDimensions == 2) { + return getTrackCorrections<2>(tracks, zvtx); + } else if (nNoOfDimensions == 3) { + return getTrackCorrections<3>(tracks, zvtx); + } + return getTrackCorrections<4>(tracks, zvtx); + } + template std::vector* getPtAvg(TrackListObject const& tracks) { std::vector* ptavg = new std::vector(tracks.size(), 0.0f); int index = 0; - for (auto& t : tracks) { - if (fhPtAvg_vsEtaPhi[t.trackacceptedid()] != nullptr) { - (*ptavg)[index] = fhPtAvg_vsEtaPhi[t.trackacceptedid()]->GetBinContent(fhPtAvg_vsEtaPhi[t.trackacceptedid()]->FindFixBin(t.eta(), t.phi())); + for (auto const& t : tracks) { + if (fhPtAvgVsEtaPhi[t.trackacceptedid()] != nullptr) { + (*ptavg)[index] = fhPtAvgVsEtaPhi[t.trackacceptedid()]->GetBinContent(fhPtAvgVsEtaPhi[t.trackacceptedid()]->FindFixBin(t.eta(), t.phi())); index++; } } @@ -262,15 +404,16 @@ struct DptDptCorrelationsTask { void processSingles(TrackListObject const& passedtracks, std::vector* corrs, float zvtx) { int index = 0; - for (auto& track : passedtracks) { + for (auto const& track : passedtracks) { float corr = (*corrs)[index]; - fhN1_vsPt[track.trackacceptedid()]->Fill(track.pt(), corr); + fhN1VsPt[track.trackacceptedid()]->Fill(track.pt(), corr); if constexpr (smallsingles) { - fhN1_vsEtaPhi[track.trackacceptedid()]->Fill(track.eta(), GetShiftedPhi(track.phi()), corr); - fhSum1Pt_vsEtaPhi[track.trackacceptedid()]->Fill(track.eta(), GetShiftedPhi(track.phi()), track.pt() * corr); + fhN1VsPtEta[track.trackacceptedid()]->Fill(track.eta(), track.pt(), corr); + fhN1VsEtaPhi[track.trackacceptedid()]->Fill(track.eta(), getShiftedPhi(track.phi()), corr); + fhSum1PtVsEtaPhi[track.trackacceptedid()]->Fill(track.eta(), getShiftedPhi(track.phi()), track.pt() * corr); } else { - fhN1_vsZEtaPhiPt[track.trackacceptedid()]->Fill(zvtx, GetEtaPhiIndex(track) + 0.5, track.pt(), corr); - fhSum1Pt_vsZEtaPhiPt[track.trackacceptedid()]->Fill(zvtx, GetEtaPhiIndex(track) + 0.5, track.pt(), track.pt() * corr); + fhN1VsZEtaPhiPt[track.trackacceptedid()]->Fill(zvtx, getEtaPhiIndex(track) + 0.5, track.pt(), corr); + fhSum1PtVsZEtaPhiPt[track.trackacceptedid()]->Fill(zvtx, getEtaPhiIndex(track) + 0.5, track.pt(), track.pt() * corr); } index++; } @@ -291,22 +434,23 @@ struct DptDptCorrelationsTask { std::vector n1nw(nch, 0.0); ///< not weighted number of single tracks for current collision std::vector sum1Ptnw(nch, 0.0); ///< accumulated sum of not weighted single \f$p_T\f$ for current collision int index = 0; - for (auto& track : passedtracks) { + for (auto const& track : passedtracks) { float corr = (*corrs)[index]; n1[track.trackacceptedid()] += corr; sum1Pt[track.trackacceptedid()] += track.pt() * corr; n1nw[track.trackacceptedid()] += 1; sum1Ptnw[track.trackacceptedid()] += track.pt(); - fhN1_vsEtaPhi[track.trackacceptedid()]->Fill(track.eta(), GetShiftedPhi(track.phi()), corr); - fhSum1Pt_vsEtaPhi[track.trackacceptedid()]->Fill(track.eta(), GetShiftedPhi(track.phi()), track.pt() * corr); + fhN1VsPtEta[track.trackacceptedid()]->Fill(track.eta(), track.pt(), corr); + fhN1VsEtaPhi[track.trackacceptedid()]->Fill(track.eta(), getShiftedPhi(track.phi()), corr); + fhSum1PtVsEtaPhi[track.trackacceptedid()]->Fill(track.eta(), getShiftedPhi(track.phi()), track.pt() * corr); index++; } for (uint tid = 0; tid < nch; ++tid) { - fhN1_vsC[tid]->Fill(cmul, n1[tid]); - fhSum1Pt_vsC[tid]->Fill(cmul, sum1Pt[tid]); - fhN1nw_vsC[tid]->Fill(cmul, n1nw[tid]); - fhSum1Ptnw_vsC[tid]->Fill(cmul, sum1Ptnw[tid]); + fhN1VsC[tid]->Fill(cmul, n1[tid]); + fhSum1PtVsC[tid]->Fill(cmul, sum1Pt[tid]); + fhN1nwVsC[tid]->Fill(cmul, n1nw[tid]); + fhSum1PtnwVsC[tid]->Fill(cmul, sum1Ptnw[tid]); } } @@ -315,7 +459,7 @@ struct DptDptCorrelationsTask { /// \param trks2 filtered table with the tracks associated to the second track in the pair /// \param cmul centrality - multiplicity for the collision being analyzed /// Be aware that in most of the cases traks1 and trks2 will have the same content (exception: mixed events) - template + template void processTrackPairs(TrackOneListObject const& trks1, TrackTwoListObject const& trks2, std::vector* corrs1, std::vector* corrs2, std::vector* ptavgs1, std::vector* ptavgs2, float cmul, int bfield) { using namespace correlationstask; @@ -329,32 +473,38 @@ struct DptDptCorrelationsTask { std::vector> sum2PtPtnw(nch, std::vector(nch, 0.0)); ///< accumulated sum of not weighted track 1 track 2 \f${p_T}_1 {p_T}_2\f$ for current collision std::vector> sum2DptDptnw(nch, std::vector(nch, 0.0)); ///< accumulated sum of not weighted number of track 1 tracks times not weighted track 2 \f$p_T\f$ for current collision int index1 = 0; + int globalbin = 0; + LOGF(debug, "Initializing globalbin to ", globalbin); - for (auto& track1 : trks1) { - double ptavg_1 = (*ptavgs1)[index1]; + for (auto const& track1 : trks1) { + double ptAvg1 = (*ptavgs1)[index1]; double corr1 = (*corrs1)[index1]; int index2 = 0; - for (auto& track2 : trks2) { + for (auto const& track2 : trks2) { /* checking the same track id condition */ if (track1 == track2) { /* exclude autocorrelations */ + index2++; continue; } if constexpr (doptorder) { if (track2.pt() >= track1.pt()) { + index2++; continue; } } /* process pair magnitudes */ - double ptavg_2 = (*ptavgs2)[index2]; + double ptAvg2 = (*ptavgs2)[index2]; double corr2 = (*corrs2)[index2]; double corr = corr1 * corr2; - double dptdptnw = (track1.pt() - ptavg_1) * (track2.pt() - ptavg_2); - double dptdptw = (corr1 * track1.pt() - ptavg_1) * (corr2 * track2.pt() - ptavg_2); + double dptdptnw = (track1.pt() - ptAvg1) * (track2.pt() - ptAvg2); + double dptdptw = (corr1 * track1.pt() - ptAvg1) * (corr2 * track2.pt() - ptAvg2); /* get the global bin for filling the differential histograms */ - int globalbin = GetDEtaDPhiGlobalIndex(track1, track2); + if constexpr (docorrelations) { + globalbin = getDEtaDPhiGlobalBin(track1, track2); + } float deltaeta = track1.eta() - track2.eta(); float deltaphi = track1.phi() - track2.phi(); while (deltaphi >= deltaphiup) { @@ -365,8 +515,10 @@ struct DptDptCorrelationsTask { } if ((fUseConversionCuts && fPairCuts.conversionCuts(track1, track2)) || (fUseTwoTrackCut && fPairCuts.twoTrackCut(track1, track2, bfield))) { /* suppress the pair */ - fhSupN1N1_vsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, corr); - fhSupPt1Pt1_vsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, track1.pt() * track2.pt() * corr); + if constexpr (docorrelations) { + fhSupN1N1VsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, corr); + fhSupPt1Pt1VsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, track1.pt() * track2.pt() * corr); + } n2sup[track1.trackacceptedid()][track2.trackacceptedid()] += corr; } else { /* count the pair */ @@ -377,30 +529,42 @@ struct DptDptCorrelationsTask { sum2PtPtnw[track1.trackacceptedid()][track2.trackacceptedid()] += track1.pt() * track2.pt(); sum2DptDptnw[track1.trackacceptedid()][track2.trackacceptedid()] += dptdptnw; - fhN2_vsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, corr); - fhN2cont_vsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->Fill(deltaeta, deltaphi, corr); - fhSum2DptDpt_vsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, dptdptw); - fhSum2PtPt_vsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, track1.pt() * track2.pt() * corr); + if constexpr (docorrelations) { + fhN2VsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, corr); + fhN2contVsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->Fill(deltaeta, deltaphi, corr); + fhSum2DptDptVsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, dptdptw); + fhSum2PtPtVsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, track1.pt() * track2.pt() * corr); + fhN2VsPtPt[track1.trackacceptedid()][track2.trackacceptedid()]->Fill(track1.pt(), track2.pt(), corr); + } + if constexpr (doinvmass) { + if (!(track2.trackacceptedid() < track1.trackacceptedid())) { + /* only 12 combinations, 21 are exactly the same */ + double invariantMass = std::sqrt(getInvMassSquared(track1, poimass[static_cast(track1.trackacceptedid() / 2)], track2, poimass[static_cast(track2.trackacceptedid() / 2)])) * 1000.0f; + fhInvMassDEta[track1.trackacceptedid()][track2.trackacceptedid()]->Fill(getDEtaValue(track1, track2), invariantMass); + fhInvMassDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->Fill(getDPhiValue(track1, track2), invariantMass); + } + } } - fhN2_vsPtPt[track1.trackacceptedid()][track2.trackacceptedid()]->Fill(track1.pt(), track2.pt(), corr); index2++; } index1++; } for (uint pid1 = 0; pid1 < nch; ++pid1) { for (uint pid2 = 0; pid2 < nch; ++pid2) { - fhN2_vsC[pid1][pid2]->Fill(cmul, n2[pid1][pid2]); - fhSum2PtPt_vsC[pid1][pid2]->Fill(cmul, sum2PtPt[pid1][pid2]); - fhSum2DptDpt_vsC[pid1][pid2]->Fill(cmul, sum2DptDpt[pid1][pid2]); - fhN2nw_vsC[pid1][pid2]->Fill(cmul, n2nw[pid1][pid2]); - fhSum2PtPtnw_vsC[pid1][pid2]->Fill(cmul, sum2PtPtnw[pid1][pid2]); - fhSum2DptDptnw_vsC[pid1][pid2]->Fill(cmul, sum2DptDptnw[pid1][pid2]); + fhN2VsC[pid1][pid2]->Fill(cmul, n2[pid1][pid2]); + fhSum2PtPtVsC[pid1][pid2]->Fill(cmul, sum2PtPt[pid1][pid2]); + fhSum2DptDptVsC[pid1][pid2]->Fill(cmul, sum2DptDpt[pid1][pid2]); + fhN2nwVsC[pid1][pid2]->Fill(cmul, n2nw[pid1][pid2]); + fhSum2PtPtnwVsC[pid1][pid2]->Fill(cmul, sum2PtPtnw[pid1][pid2]); + fhSum2DptDptnwVsC[pid1][pid2]->Fill(cmul, sum2DptDptnw[pid1][pid2]); /* let's also update the number of entries in the differential histograms */ - fhN2_vsDEtaDPhi[pid1][pid2]->SetEntries(fhN2_vsDEtaDPhi[pid1][pid2]->GetEntries() + n2[pid1][pid2]); - fhSum2DptDpt_vsDEtaDPhi[pid1][pid2]->SetEntries(fhSum2DptDpt_vsDEtaDPhi[pid1][pid2]->GetEntries() + n2[pid1][pid2]); - fhSum2PtPt_vsDEtaDPhi[pid1][pid2]->SetEntries(fhSum2PtPt_vsDEtaDPhi[pid1][pid2]->GetEntries() + n2[pid1][pid2]); - fhSupN1N1_vsDEtaDPhi[pid1][pid2]->SetEntries(fhSupN1N1_vsDEtaDPhi[pid1][pid2]->GetEntries() + n2sup[pid1][pid2]); - fhSupPt1Pt1_vsDEtaDPhi[pid1][pid2]->SetEntries(fhSupPt1Pt1_vsDEtaDPhi[pid1][pid2]->GetEntries() + n2sup[pid1][pid2]); + if constexpr (docorrelations) { + fhN2VsDEtaDPhi[pid1][pid2]->SetEntries(fhN2VsDEtaDPhi[pid1][pid2]->GetEntries() + n2[pid1][pid2]); + fhSum2DptDptVsDEtaDPhi[pid1][pid2]->SetEntries(fhSum2DptDptVsDEtaDPhi[pid1][pid2]->GetEntries() + n2[pid1][pid2]); + fhSum2PtPtVsDEtaDPhi[pid1][pid2]->SetEntries(fhSum2PtPtVsDEtaDPhi[pid1][pid2]->GetEntries() + n2[pid1][pid2]); + fhSupN1N1VsDEtaDPhi[pid1][pid2]->SetEntries(fhSupN1N1VsDEtaDPhi[pid1][pid2]->GetEntries() + n2sup[pid1][pid2]); + fhSupPt1Pt1VsDEtaDPhi[pid1][pid2]->SetEntries(fhSupPt1Pt1VsDEtaDPhi[pid1][pid2]->GetEntries() + n2sup[pid1][pid2]); + } } } } @@ -440,15 +604,40 @@ struct DptDptCorrelationsTask { /* process pair magnitudes */ if constexpr (mixed) { if (ptorder) { - processTrackPairs(Tracks1, Tracks2, corrs1, corrs2, ptavgs1, ptavgs2, centmult, bfield); + /* no invariant mass analysis on a mixed event data collection */ + processTrackPairs(Tracks1, Tracks2, corrs1, corrs2, ptavgs1, ptavgs2, centmult, bfield); } else { - processTrackPairs(Tracks1, Tracks2, corrs1, corrs2, ptavgs1, ptavgs2, centmult, bfield); + processTrackPairs(Tracks1, Tracks2, corrs1, corrs2, ptavgs1, ptavgs2, centmult, bfield); } } else { if (ptorder) { - processTrackPairs(Tracks1, Tracks1, corrs1, corrs1, ptavgs1, ptavgs1, centmult, bfield); + if (invmass) { + if (corrana) { + processTrackPairs(Tracks1, Tracks1, corrs1, corrs1, ptavgs1, ptavgs1, centmult, bfield); + } else { + processTrackPairs(Tracks1, Tracks1, corrs1, corrs1, ptavgs1, ptavgs1, centmult, bfield); + } + } else { + if (corrana) { + processTrackPairs(Tracks1, Tracks1, corrs1, corrs1, ptavgs1, ptavgs1, centmult, bfield); + } else { + processTrackPairs(Tracks1, Tracks1, corrs1, corrs1, ptavgs1, ptavgs1, centmult, bfield); + } + } } else { - processTrackPairs(Tracks1, Tracks1, corrs1, corrs1, ptavgs1, ptavgs1, centmult, bfield); + if (invmass) { + if (corrana) { + processTrackPairs(Tracks1, Tracks1, corrs1, corrs1, ptavgs1, ptavgs1, centmult, bfield); + } else { + processTrackPairs(Tracks1, Tracks1, corrs1, corrs1, ptavgs1, ptavgs1, centmult, bfield); + } + } else { + if (corrana) { + processTrackPairs(Tracks1, Tracks1, corrs1, corrs1, ptavgs1, ptavgs1, centmult, bfield); + } else { + processTrackPairs(Tracks1, Tracks1, corrs1, corrs1, ptavgs1, ptavgs1, centmult, bfield); + } + } } } @@ -463,13 +652,16 @@ struct DptDptCorrelationsTask { } } + template void init(TList* fOutputList) { using namespace correlationstask; using namespace o2::analysis::dptdptfilter; + LOGF(info, "Do invariant mass: %s; do correlation histograms: %s", doinvmass ? "yes" : "no", docorrelations ? "yes" : "no"); + /* create the histograms */ - Bool_t oldstatus = TH1::AddDirectoryStatus(); + bool oldstatus = TH1::AddDirectoryStatus(); TH1::AddDirectory(kFALSE); if (!processpairs) { @@ -477,23 +669,26 @@ struct DptDptCorrelationsTask { fOutputList->Add(fhVertexZA); for (uint i = 0; i < nch; ++i) { /* histograms for each track, one and two */ - fhN1_vsPt[i] = new TH1F(TString::Format("n1_%s_vsPt", tnames[i].c_str()).Data(), - TString::Format("#LT n_{1} #GT;p_{t,%s} (GeV/c);#LT n_{1} #GT", tnames[i].c_str()).Data(), - ptbins, ptlow, ptup); + fhN1VsPt[i] = new TH1F(TString::Format("n1_%s_vsPt", tnames[i].c_str()).Data(), + TString::Format("#LT n_{1} #GT;p_{t,%s} (GeV/c);#LT n_{1} #GT", tnames[i].c_str()).Data(), + ptbins, ptlow, ptup); /* we don't want the Sumw2 structure being created here */ bool defSumw2 = TH1::GetDefaultSumw2(); if constexpr (smallsingles) { - fhN1_vsEtaPhi[i] = new TH2F(TString::Format("n1_%s_vsEtaPhi", tnames[i].c_str()).Data(), - TString::Format("#LT n_{1} #GT;#eta_{%s};#varphi_{%s} (radian);#LT n_{1} #GT", tnames[i].c_str(), tnames[i].c_str()).Data(), - etabins, etalow, etaup, phibins, philow, phiup); - fhSum1Pt_vsEtaPhi[i] = new TH2F(TString::Format("sumPt_%s_vsEtaPhi", tnames[i].c_str()).Data(), - TString::Format("#LT #Sigma p_{t,%s} #GT;#eta_{%s};#varphi_{%s} (radian);#LT #Sigma p_{t,%s} #GT (GeV/c)", - tnames[i].c_str(), tnames[i].c_str(), tnames[i].c_str(), tnames[i].c_str()) - .Data(), - etabins, etalow, etaup, phibins, philow, phiup); + fhN1VsPtEta[i] = new TH2F(TString::Format("n1_%s_vsPtEta", tnames[i].c_str()).Data(), + TString::Format("#LT n_{1_{%s}} #GT;#eta;#it{p}_{T}", tnames[i].c_str()).Data(), + etabins, etalow, etaup, ptbins, ptlow, ptup); + fhN1VsEtaPhi[i] = new TH2F(TString::Format("n1_%s_vsEtaPhi", tnames[i].c_str()).Data(), + TString::Format("#LT n_{1} #GT;#eta_{%s};#varphi_{%s} (radian);#LT n_{1} #GT", tnames[i].c_str(), tnames[i].c_str()).Data(), + etabins, etalow, etaup, phibins, philow, phiup); + fhSum1PtVsEtaPhi[i] = new TH2F(TString::Format("sumPt_%s_vsEtaPhi", tnames[i].c_str()).Data(), + TString::Format("#LT #Sigma p_{t,%s} #GT;#eta_{%s};#varphi_{%s} (radian);#LT #Sigma p_{t,%s} #GT (GeV/c)", + tnames[i].c_str(), tnames[i].c_str(), tnames[i].c_str(), tnames[i].c_str()) + .Data(), + etabins, etalow, etaup, phibins, philow, phiup); } else { TH1::SetDefaultSumw2(false); - fhN1_vsZEtaPhiPt[i] = new TH3F( + fhN1VsZEtaPhiPt[i] = new TH3F( TString::Format("n1_%s_vsZ_vsEtaPhi_vsPt", tnames[i].c_str()).Data(), TString::Format("#LT n_{1} #GT;vtx_{z};#eta_{%s}#times#varphi_{%s};p_{t,%s} (GeV/c)", tnames[i].c_str(), @@ -509,7 +704,7 @@ struct DptDptCorrelationsTask { ptbins, ptlow, ptup); - fhSum1Pt_vsZEtaPhiPt[i] = new TH3F( + fhSum1PtVsZEtaPhiPt[i] = new TH3F( TString::Format("sumPt1_%s_vsZ_vsEtaPhi_vsPt", tnames[i].c_str()).Data(), TString::Format( "#LT #Sigma p_{t,%s}#GT;vtx_{z};#eta_{%s}#times#varphi_{%s};p_{t,%s} (GeV/c)", @@ -533,58 +728,65 @@ struct DptDptCorrelationsTask { /* the statistical uncertainties will be estimated by the subsamples method so let's get rid of the error tracking */ if constexpr (smallsingles) { - fhN1_vsEtaPhi[i]->SetBit(TH1::kIsNotW); - fhN1_vsEtaPhi[i]->Sumw2(false); - fhSum1Pt_vsEtaPhi[i]->SetBit(TH1::kIsNotW); - fhSum1Pt_vsEtaPhi[i]->Sumw2(false); + fhN1VsPtEta[i]->SetBit(TH1::kIsNotW); + fhN1VsPtEta[i]->Sumw2(false); + fhN1VsEtaPhi[i]->SetBit(TH1::kIsNotW); + fhN1VsEtaPhi[i]->Sumw2(false); + fhSum1PtVsEtaPhi[i]->SetBit(TH1::kIsNotW); + fhSum1PtVsEtaPhi[i]->Sumw2(false); } else { - fhN1_vsZEtaPhiPt[i]->SetBit(TH1::kIsNotW); - fhN1_vsZEtaPhiPt[i]->Sumw2(false); - fhSum1Pt_vsZEtaPhiPt[i]->SetBit(TH1::kIsNotW); - fhSum1Pt_vsZEtaPhiPt[i]->Sumw2(false); + fhN1VsZEtaPhiPt[i]->SetBit(TH1::kIsNotW); + fhN1VsZEtaPhiPt[i]->Sumw2(false); + fhSum1PtVsZEtaPhiPt[i]->SetBit(TH1::kIsNotW); + fhSum1PtVsZEtaPhiPt[i]->Sumw2(false); } - fhNuaNue_vsZEtaPhiPt[i] = nullptr; - fhPtAvg_vsEtaPhi[i] = nullptr; + fhNuaNue[i] = nullptr; + fhPtAvgVsEtaPhi[i] = nullptr; - fOutputList->Add(fhN1_vsPt[i]); + fOutputList->Add(fhN1VsPt[i]); if constexpr (smallsingles) { - fOutputList->Add(fhN1_vsEtaPhi[i]); - fOutputList->Add(fhSum1Pt_vsEtaPhi[i]); + fOutputList->Add(fhN1VsPtEta[i]); + fOutputList->Add(fhN1VsEtaPhi[i]); + fOutputList->Add(fhSum1PtVsEtaPhi[i]); } else { - fOutputList->Add(fhN1_vsZEtaPhiPt[i]); - fOutputList->Add(fhSum1Pt_vsZEtaPhiPt[i]); + fOutputList->Add(fhN1VsZEtaPhiPt[i]); + fOutputList->Add(fhSum1PtVsZEtaPhiPt[i]); } } } else { for (uint i = 0; i < nch; ++i) { /* histograms for each track species */ - fhN1_vsEtaPhi[i] = new TH2F(TString::Format("n1_%s_vsEtaPhi", tnames[i].c_str()).Data(), - TString::Format("#LT n_{1} #GT;#eta_{%s};#varphi_{%s} (radian);#LT n_{1} #GT", tnames[i].c_str(), tnames[i].c_str()).Data(), - etabins, etalow, etaup, phibins, philow, phiup); - fhSum1Pt_vsEtaPhi[i] = new TH2F(TString::Format("sumPt_%s_vsEtaPhi", tnames[i].c_str()).Data(), - TString::Format("#LT #Sigma p_{t,%s} #GT;#eta_{%s};#varphi_{%s} (radian);#LT #Sigma p_{t,%s} #GT (GeV/c)", - tnames[i].c_str(), tnames[i].c_str(), tnames[i].c_str(), tnames[i].c_str()) - .Data(), - etabins, etalow, etaup, phibins, philow, phiup); - fhN1_vsC[i] = new TProfile(TString::Format("n1_%s_vsM", tnames[i].c_str()).Data(), - TString::Format("#LT n_{1} #GT (weighted);Centrality/Multiplicity (%%);#LT n_{1} #GT").Data(), - 100, 0.0, 100.0); - fhSum1Pt_vsC[i] = new TProfile(TString::Format("sumPt_%s_vsM", tnames[i].c_str()), - TString::Format("#LT #Sigma p_{t,%s} #GT (weighted);Centrality/Multiplicity (%%);#LT #Sigma p_{t,%s} #GT (GeV/c)", tnames[i].c_str(), tnames[i].c_str()).Data(), - 100, 0.0, 100.0); - fhN1nw_vsC[i] = new TProfile(TString::Format("n1Nw_%s_vsM", tnames[i].c_str()).Data(), - TString::Format("#LT n_{1} #GT;Centrality/Multiplicity (%%);#LT n_{1} #GT").Data(), - 100, 0.0, 100.0); - fhSum1Ptnw_vsC[i] = new TProfile(TString::Format("sumPtNw_%s_vsM", tnames[i].c_str()).Data(), - TString::Format("#LT #Sigma p_{t,%s} #GT;Centrality/Multiplicity (%%);#LT #Sigma p_{t,%s} #GT (GeV/c)", tnames[i].c_str(), tnames[i].c_str()).Data(), 100, 0.0, 100.0); - fhNuaNue_vsZEtaPhiPt[i] = nullptr; - fhPtAvg_vsEtaPhi[i] = nullptr; - fOutputList->Add(fhN1_vsEtaPhi[i]); - fOutputList->Add(fhSum1Pt_vsEtaPhi[i]); - fOutputList->Add(fhN1_vsC[i]); - fOutputList->Add(fhSum1Pt_vsC[i]); - fOutputList->Add(fhN1nw_vsC[i]); - fOutputList->Add(fhSum1Ptnw_vsC[i]); + fhN1VsPtEta[i] = new TH2F(TString::Format("n1_%s_vsPtEta", tnames[i].c_str()).Data(), + TString::Format("#LT n_{1_{%s}} #GT;#eta;#it{p}_{T}", tnames[i].c_str()).Data(), + etabins, etalow, etaup, ptbins, ptlow, ptup); + fhN1VsEtaPhi[i] = new TH2F(TString::Format("n1_%s_vsEtaPhi", tnames[i].c_str()).Data(), + TString::Format("#LT n_{1} #GT;#eta_{%s};#varphi_{%s} (radian);#LT n_{1} #GT", tnames[i].c_str(), tnames[i].c_str()).Data(), + etabins, etalow, etaup, phibins, philow, phiup); + fhSum1PtVsEtaPhi[i] = new TH2F(TString::Format("sumPt_%s_vsEtaPhi", tnames[i].c_str()).Data(), + TString::Format("#LT #Sigma p_{t,%s} #GT;#eta_{%s};#varphi_{%s} (radian);#LT #Sigma p_{t,%s} #GT (GeV/c)", + tnames[i].c_str(), tnames[i].c_str(), tnames[i].c_str(), tnames[i].c_str()) + .Data(), + etabins, etalow, etaup, phibins, philow, phiup); + fhN1VsC[i] = new TProfile(TString::Format("n1_%s_vsM", tnames[i].c_str()).Data(), + TString::Format("#LT n_{1} #GT (weighted);Centrality/Multiplicity (%%);#LT n_{1} #GT").Data(), + 100, 0.0, 100.0); + fhSum1PtVsC[i] = new TProfile(TString::Format("sumPt_%s_vsM", tnames[i].c_str()), + TString::Format("#LT #Sigma p_{t,%s} #GT (weighted);Centrality/Multiplicity (%%);#LT #Sigma p_{t,%s} #GT (GeV/c)", tnames[i].c_str(), tnames[i].c_str()).Data(), + 100, 0.0, 100.0); + fhN1nwVsC[i] = new TProfile(TString::Format("n1Nw_%s_vsM", tnames[i].c_str()).Data(), + TString::Format("#LT n_{1} #GT;Centrality/Multiplicity (%%);#LT n_{1} #GT").Data(), + 100, 0.0, 100.0); + fhSum1PtnwVsC[i] = new TProfile(TString::Format("sumPtNw_%s_vsM", tnames[i].c_str()).Data(), + TString::Format("#LT #Sigma p_{t,%s} #GT;Centrality/Multiplicity (%%);#LT #Sigma p_{t,%s} #GT (GeV/c)", tnames[i].c_str(), tnames[i].c_str()).Data(), 100, 0.0, 100.0); + fhNuaNue[i] = nullptr; + fhPtAvgVsEtaPhi[i] = nullptr; + fOutputList->Add(fhN1VsPtEta[i]); + fOutputList->Add(fhN1VsEtaPhi[i]); + fOutputList->Add(fhSum1PtVsEtaPhi[i]); + fOutputList->Add(fhN1VsC[i]); + fOutputList->Add(fhSum1PtVsC[i]); + fOutputList->Add(fhN1nwVsC[i]); + fOutputList->Add(fhSum1PtnwVsC[i]); } for (uint i = 0; i < nch; ++i) { @@ -594,58 +796,88 @@ struct DptDptCorrelationsTask { bool defSumw2 = TH1::GetDefaultSumw2(); TH1::SetDefaultSumw2(false); const char* pname = trackPairsNames[i][j].c_str(); - fhN2_vsDEtaDPhi[i][j] = new TH2F(TString::Format("n2_12_vsDEtaDPhi_%s", pname), TString::Format("#LT n_{2} #GT (%s);#Delta#eta;#Delta#varphi;#LT n_{2} #GT", pname), - deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); - fhN2cont_vsDEtaDPhi[i][j] = new TH2F(TString::Format("n2_12cont_vsDEtaDPhi_%s", pname), TString::Format("#LT n_{2} #GT (%s);#Delta#eta;#Delta#varphi;#LT n_{2} #GT", pname), - deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); - fhSum2PtPt_vsDEtaDPhi[i][j] = new TH2F(TString::Format("sumPtPt_12_vsDEtaDPhi_%s", pname), TString::Format("#LT #Sigma p_{t,1}p_{t,2} #GT (%s);#Delta#eta;#Delta#varphi;#LT #Sigma p_{t,1}p_{t,2} #GT (GeV^{2})", pname), - deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); - fhSum2DptDpt_vsDEtaDPhi[i][j] = new TH2F(TString::Format("sumDptDpt_12_vsDEtaDPhi_%s", pname), TString::Format("#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (%s);#Delta#eta;#Delta#varphi;#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (GeV^{2})", pname), - deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); - fhSupN1N1_vsDEtaDPhi[i][j] = new TH2F(TString::Format("suppn1n1_12_vsDEtaDPhi_%s", pname), TString::Format("Suppressed #LT n_{1} #GT#LT n_{1} #GT (%s);#Delta#eta;#Delta#varphi;#LT n_{1} #GT#LT n_{1} #GT", pname), + if constexpr (docorrelations) { + fhN2VsDEtaDPhi[i][j] = new TH2F(TString::Format("n2_12_vsDEtaDPhi_%s", pname), TString::Format("#LT n_{2} #GT (%s);#Delta#eta;#Delta#varphi;#LT n_{2} #GT", pname), + deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); + fhN2contVsDEtaDPhi[i][j] = new TH2F(TString::Format("n2_12cont_vsDEtaDPhi_%s", pname), TString::Format("#LT n_{2} #GT (%s);#Delta#eta;#Delta#varphi;#LT n_{2} #GT", pname), deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); - fhSupPt1Pt1_vsDEtaDPhi[i][j] = new TH2F(TString::Format("suppPtPt_12_vsDEtaDPhi_%s", pname), TString::Format("Suppressed #LT p_{t,1} #GT#LT p_{t,2} #GT (%s);#Delta#eta;#Delta#varphi;#LT p_{t,1} #GT#LT p_{t,2} #GT (GeV^{2})", pname), + fhSum2PtPtVsDEtaDPhi[i][j] = new TH2F(TString::Format("sumPtPt_12_vsDEtaDPhi_%s", pname), TString::Format("#LT #Sigma p_{t,1}p_{t,2} #GT (%s);#Delta#eta;#Delta#varphi;#LT #Sigma p_{t,1}p_{t,2} #GT (GeV^{2})", pname), deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); + fhSum2DptDptVsDEtaDPhi[i][j] = new TH2F(TString::Format("sumDptDpt_12_vsDEtaDPhi_%s", pname), TString::Format("#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (%s);#Delta#eta;#Delta#varphi;#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (GeV^{2})", pname), + deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); + fhSupN1N1VsDEtaDPhi[i][j] = new TH2F(TString::Format("suppn1n1_12_vsDEtaDPhi_%s", pname), TString::Format("Suppressed #LT n_{1} #GT#LT n_{1} #GT (%s);#Delta#eta;#Delta#varphi;#LT n_{1} #GT#LT n_{1} #GT", pname), + deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); + fhSupPt1Pt1VsDEtaDPhi[i][j] = new TH2F(TString::Format("suppPtPt_12_vsDEtaDPhi_%s", pname), TString::Format("Suppressed #LT p_{t,1} #GT#LT p_{t,2} #GT (%s);#Delta#eta;#Delta#varphi;#LT p_{t,1} #GT#LT p_{t,2} #GT (GeV^{2})", pname), + deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); + fhN2VsPtPt[i][j] = new TH2F(TString::Format("n2_12_vsPtVsPt_%s", pname), TString::Format("#LT n_{2} #GT (%s);p_{t,1} (GeV/c);p_{t,2} (GeV/c);#LT n_{2} #GT", pname), + ptbins, ptlow, ptup, ptbins, ptlow, ptup); + } + if constexpr (doinvmass) { + if (!(j < i)) { + /* only 12 combinations, 21 are exactly the same */ + fhInvMassDEta[i][j] = new TH2D(TString::Format("n2_invMassDeta_%s", pname), TString::Format("%s invariant mass;#Delta#eta;Mass (MeV/#it{c}^{2})", pname), + deltaetabins, deltaetalow, deltaetaup, 5000, 0, 5000); + fhInvMassDPhi[i][j] = new TH2D(TString::Format("n2_invMassDphi_%s", pname), TString::Format("%s invariant mass;#Delta#varphi;Mass (MeV/#it{c}^{2})", pname), + deltaphibins, deltaphilow - constants::math::PI, deltaphiup - constants::math::PI, 5000, 0, 5000); + } + } /* we return it back to previuos state */ TH1::SetDefaultSumw2(defSumw2); - fhN2_vsPtPt[i][j] = new TH2F(TString::Format("n2_12_vsPtVsPt_%s", pname), TString::Format("#LT n_{2} #GT (%s);p_{t,1} (GeV/c);p_{t,2} (GeV/c);#LT n_{2} #GT", pname), - ptbins, ptlow, ptup, ptbins, ptlow, ptup); - - fhN2_vsC[i][j] = new TProfile(TString::Format("n2_12_vsM_%s", pname), TString::Format("#LT n_{2} #GT (%s) (weighted);Centrality/Multiplicity (%%);#LT n_{2} #GT", pname), 100, 0.0, 100.0); - fhSum2PtPt_vsC[i][j] = new TProfile(TString::Format("sumPtPt_12_vsM_%s", pname), TString::Format("#LT #Sigma p_{t,1}p_{t,2} #GT (%s) (weighted);Centrality/Multiplicity (%%);#LT #Sigma p_{t,1}p_{t,2} #GT (GeV^{2})", pname), 100, 0.0, 100.0); - fhSum2DptDpt_vsC[i][j] = new TProfile(TString::Format("sumDptDpt_12_vsM_%s", pname), TString::Format("#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (%s) (weighted);Centrality/Multiplicity (%%);#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (GeV^{2})", pname), 100, 0.0, 100.0); - fhN2nw_vsC[i][j] = new TProfile(TString::Format("n2Nw_12_vsM_%s", pname), TString::Format("#LT n_{2} #GT (%s);Centrality/Multiplicity (%%);#LT n_{2} #GT", pname), 100, 0.0, 100.0); - fhSum2PtPtnw_vsC[i][j] = new TProfile(TString::Format("sumPtPtNw_12_vsM_%s", pname), TString::Format("#LT #Sigma p_{t,1}p_{t,2} #GT (%s);Centrality/Multiplicity (%%);#LT #Sigma p_{t,1}p_{t,2} #GT (GeV^{2})", pname), 100, 0.0, 100.0); - fhSum2DptDptnw_vsC[i][j] = new TProfile(TString::Format("sumDptDptNw_12_vsM_%s", pname), TString::Format("#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (%s);Centrality/Multiplicity (%%);#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (GeV^{2})", pname), 100, 0.0, 100.0); + fhN2VsC[i][j] = new TProfile(TString::Format("n2_12_vsM_%s", pname), TString::Format("#LT n_{2} #GT (%s) (weighted);Centrality/Multiplicity (%%);#LT n_{2} #GT", pname), 100, 0.0, 100.0); + fhSum2PtPtVsC[i][j] = new TProfile(TString::Format("sumPtPt_12_vsM_%s", pname), TString::Format("#LT #Sigma p_{t,1}p_{t,2} #GT (%s) (weighted);Centrality/Multiplicity (%%);#LT #Sigma p_{t,1}p_{t,2} #GT (GeV^{2})", pname), 100, 0.0, 100.0); + fhSum2DptDptVsC[i][j] = new TProfile(TString::Format("sumDptDpt_12_vsM_%s", pname), TString::Format("#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (%s) (weighted);Centrality/Multiplicity (%%);#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (GeV^{2})", pname), 100, 0.0, 100.0); + fhN2nwVsC[i][j] = new TProfile(TString::Format("n2Nw_12_vsM_%s", pname), TString::Format("#LT n_{2} #GT (%s);Centrality/Multiplicity (%%);#LT n_{2} #GT", pname), 100, 0.0, 100.0); + fhSum2PtPtnwVsC[i][j] = new TProfile(TString::Format("sumPtPtNw_12_vsM_%s", pname), TString::Format("#LT #Sigma p_{t,1}p_{t,2} #GT (%s);Centrality/Multiplicity (%%);#LT #Sigma p_{t,1}p_{t,2} #GT (GeV^{2})", pname), 100, 0.0, 100.0); + fhSum2DptDptnwVsC[i][j] = new TProfile(TString::Format("sumDptDptNw_12_vsM_%s", pname), TString::Format("#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (%s);Centrality/Multiplicity (%%);#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (GeV^{2})", pname), 100, 0.0, 100.0); /* the statistical uncertainties will be estimated by the subsamples method so let's get rid of the error tracking */ - fhN2_vsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); - fhN2_vsDEtaDPhi[i][j]->Sumw2(false); - fhN2cont_vsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); - fhN2cont_vsDEtaDPhi[i][j]->Sumw2(false); - fhSum2PtPt_vsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); - fhSum2PtPt_vsDEtaDPhi[i][j]->Sumw2(false); - fhSum2DptDpt_vsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); - fhSum2DptDpt_vsDEtaDPhi[i][j]->Sumw2(false); - fhSupN1N1_vsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); - fhSupN1N1_vsDEtaDPhi[i][j]->Sumw2(false); - fhSupPt1Pt1_vsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); - fhSupPt1Pt1_vsDEtaDPhi[i][j]->Sumw2(false); - - fOutputList->Add(fhN2_vsDEtaDPhi[i][j]); - fOutputList->Add(fhN2cont_vsDEtaDPhi[i][j]); - fOutputList->Add(fhSum2PtPt_vsDEtaDPhi[i][j]); - fOutputList->Add(fhSum2DptDpt_vsDEtaDPhi[i][j]); - fOutputList->Add(fhSupN1N1_vsDEtaDPhi[i][j]); - fOutputList->Add(fhSupPt1Pt1_vsDEtaDPhi[i][j]); - fOutputList->Add(fhN2_vsPtPt[i][j]); - fOutputList->Add(fhN2_vsC[i][j]); - fOutputList->Add(fhSum2PtPt_vsC[i][j]); - fOutputList->Add(fhSum2DptDpt_vsC[i][j]); - fOutputList->Add(fhN2nw_vsC[i][j]); - fOutputList->Add(fhSum2PtPtnw_vsC[i][j]); - fOutputList->Add(fhSum2DptDptnw_vsC[i][j]); + if constexpr (docorrelations) { + fhN2VsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); + fhN2VsDEtaDPhi[i][j]->Sumw2(false); + fhN2contVsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); + fhN2contVsDEtaDPhi[i][j]->Sumw2(false); + fhSum2PtPtVsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); + fhSum2PtPtVsDEtaDPhi[i][j]->Sumw2(false); + fhSum2DptDptVsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); + fhSum2DptDptVsDEtaDPhi[i][j]->Sumw2(false); + fhSupN1N1VsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); + fhSupN1N1VsDEtaDPhi[i][j]->Sumw2(false); + fhSupPt1Pt1VsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); + fhSupPt1Pt1VsDEtaDPhi[i][j]->Sumw2(false); + } + if constexpr (doinvmass) { + if (!(j < i)) { + /* only 12 combinations, 21 are exactly the same */ + fhInvMassDEta[i][j]->SetBit(TH1::kIsNotW); + fhInvMassDEta[i][j]->Sumw2(false); + fhInvMassDPhi[i][j]->SetBit(TH1::kIsNotW); + fhInvMassDPhi[i][j]->Sumw2(false); + } + } + + if constexpr (docorrelations) { + fOutputList->Add(fhN2VsDEtaDPhi[i][j]); + fOutputList->Add(fhN2contVsDEtaDPhi[i][j]); + fOutputList->Add(fhSum2PtPtVsDEtaDPhi[i][j]); + fOutputList->Add(fhSum2DptDptVsDEtaDPhi[i][j]); + fOutputList->Add(fhSupN1N1VsDEtaDPhi[i][j]); + fOutputList->Add(fhSupPt1Pt1VsDEtaDPhi[i][j]); + fOutputList->Add(fhN2VsPtPt[i][j]); + } + if constexpr (doinvmass) { + if (!(j < i)) { + /* only 12 combinations, 21 are exactly the same */ + fOutputList->Add(fhInvMassDEta[i][j]); + fOutputList->Add(fhInvMassDPhi[i][j]); + } + } + fOutputList->Add(fhN2VsC[i][j]); + fOutputList->Add(fhSum2PtPtVsC[i][j]); + fOutputList->Add(fhSum2DptDptVsC[i][j]); + fOutputList->Add(fhN2nwVsC[i][j]); + fOutputList->Add(fhSum2PtPtnwVsC[i][j]); + fOutputList->Add(fhSum2DptDptnwVsC[i][j]); } } } @@ -663,7 +895,7 @@ struct DptDptCorrelationsTask { /* the data collecting engine instances */ DataCollectingEngine** dataCE; - DataCollectingEngine** dataCE_small; + DataCollectingEngine** dataCEsmall; DataCollectingEngine** dataCEME; /* the input file structure from CCDB */ @@ -675,16 +907,19 @@ struct DptDptCorrelationsTask { std::string cfgCCDBPeriod{"LHC22o"}; /* pair conversion suppression defaults */ - static constexpr float cfgPairCutDefaults[1][5] = {{-1, -1, -1, -1, -1}}; - Configurable> cfgPairCut{"paircut", {cfgPairCutDefaults[0], 5, {"Photon", "K0", "Lambda", "Phi", "Rho"}}, "Conversion suppressions"}; + static constexpr float kCfgPairCutDefaults[1][5] = {{-1, -1, -1, -1, -1}}; + Configurable> cfgPairCut{"paircut", {kCfgPairCutDefaults[0], 5, {"Photon", "K0", "Lambda", "Phi", "Rho"}}, "Conversion suppressions"}; /* two tracks cut */ Configurable cfgTwoTrackCut{"twotrackcut", -1, "Two-tracks cut: -1 = off; >0 otherwise distance value (suggested: 0.02"}; Configurable cfgTwoTrackCutMinRadius{"twotrackcutminradius", 0.8f, "Two-tracks cut: radius in m from which two-tracks cut is applied"}; Configurable cfgSmallDCE{"smalldce", true, "Use small data collecting engine for singles processing, true = yes. Default = true"}; + Configurable cfgDoInvMass{"doinvmass", false, "Do the invariant mass analyis, true = yes. Default = false"}; + Configurable cfgDoCorrelations{"docorrelations", true, "Do the correlations analysis, true = yes. Default = true"}; Configurable cfgProcessPairs{"processpairs", false, "Process pairs: false = no, just singles, true = yes, process pairs"}; Configurable cfgProcessME{"processmixedevents", false, "Process mixed events: false = no, just same event, true = yes, also process mixed events"}; Configurable cfgPtOrder{"ptorder", false, "enforce pT_1 < pT_2. Defalut: false"}; + Configurable cfgNoOfDimensions{"cfgNoOfDimensions", 1, "Number of dimensions for the NUA&NUE corrections. Default 1"}; OutputObj fOutput{"DptDptCorrelationsData", OutputObjHandlingPolicy::AnalysisObject, OutputObjSourceType::OutputObjSource}; void init(InitContext& initContext) @@ -725,6 +960,9 @@ struct DptDptCorrelationsTask { processpairs = cfgProcessPairs.value; processmixedevents = cfgProcessME.value; ptorder = cfgPtOrder.value; + invmass = cfgDoInvMass.value; + corrana = cfgDoCorrelations.value; + nNoOfDimensions = cfgNoOfDimensions.value; /* self configure the CCDB access to the input file */ getTaskOptionValue(initContext, "dpt-dpt-filter", "input_ccdburl", cfgCCDBUrl, false); @@ -783,7 +1021,7 @@ struct DptDptCorrelationsTask { auto cfg = new o2::analysis::TrackSelectionPIDCfg(); cfg->mUseIt = true; cfg->mExclude = false; - pidselector.Add(spid, cfg); + pidselector.addSpecies(spid, cfg); } } }; @@ -801,7 +1039,8 @@ struct DptDptCorrelationsTask { poinames.push_back(std::string(pidselector.getSpeciesFName(ix))); tnames.push_back(std::string(TString::Format("%sP", pidselector.getSpeciesFName(ix)).Data())); tnames.push_back(std::string(TString::Format("%sM", pidselector.getSpeciesFName(ix)).Data())); - LOGF(info, "Incorporated species name %s to the analysis", poinames[ix].c_str()); + poimass.push_back(pidselector.getSpeciesMass(ix)); + LOGF(info, "Incorporated species name %s with mass %f to the analysis", poinames[ix].c_str(), poimass[ix]); } } uint ntracknames = tnames.size(); @@ -837,9 +1076,8 @@ struct DptDptCorrelationsTask { fCentMultMin[0] = 0.0f; fCentMultMax[0] = 100.0f; } - dataCE = new DataCollectingEngine*[ncmranges]; if (cfgSmallDCE) { - dataCE_small = new DataCollectingEngine*[ncmranges]; + dataCEsmall = new DataCollectingEngine*[ncmranges]; } else { dataCE = new DataCollectingEngine*[ncmranges]; } @@ -848,23 +1086,36 @@ struct DptDptCorrelationsTask { } for (int i = 0; i < ncmranges; ++i) { - auto initializeCEInstance = [&fGlobalOutputList](auto dce, auto name) { + auto initializeCEInstance = [&fGlobalOutputList](auto dce, auto name, bool im, bool corr) { /* crete the output list for the passed centrality/multiplicity range */ TList* fOutputList = new TList(); fOutputList->SetName(name); fOutputList->SetOwner(true); /* init the data collection instance */ - dce->init(fOutputList); + if (im) { + if (corr) { + dce->template init(fOutputList); + } else { + dce->template init(fOutputList); + } + } else { + if (corr) { + dce->template init(fOutputList); + } else { + dce->template init(fOutputList); + } + } fGlobalOutputList->Add(fOutputList); }; auto builSmallDCEInstance = [&initializeCEInstance](auto rg, bool me = false) { + /* only for singles analysis, no sense of inv mass nor no correlations */ DataCollectingEngine* dce = new DataCollectingEngine(); - initializeCEInstance(dce, TString::Format("DptDptCorrelationsData%s-%s", me ? "ME" : "", rg)); + initializeCEInstance(dce, TString::Format("DptDptCorrelationsData%s-%s", me ? "ME" : "", rg), false, false); return dce; }; - auto buildCEInstance = [&initializeCEInstance](auto rg, bool me = false) { + auto buildCEInstance = [&initializeCEInstance](auto rg, bool im, bool corr, bool me = false) { DataCollectingEngine* dce = new DataCollectingEngine(); - initializeCEInstance(dce, TString::Format("DptDptCorrelationsData%s-%s", me ? "ME" : "", rg)); + initializeCEInstance(dce, TString::Format("DptDptCorrelationsData%s-%s", me ? "ME" : "", rg), im, corr); return dce; }; TString range = TString::Format("%d-%d", static_cast(fCentMultMin[i]), static_cast(fCentMultMax[i])); @@ -872,16 +1123,30 @@ struct DptDptCorrelationsTask { if (processpairs) { LOGF(fatal, "Processing pairs cannot be used with the small DCE, please configure properly!!"); } - dataCE_small[i] = builSmallDCEInstance(range.Data()); + if (invmass) { + LOGF(fatal, "Invariant mass cannot be used with singles in the small DCE mode, please configure properly!!"); + } + dataCEsmall[i] = builSmallDCEInstance(range.Data()); } else { - dataCE[i] = buildCEInstance(range.Data()); + if (invmass) { + if (!processpairs) { + LOGF(fatal, "Invariant mass cannot be used in processing singles, please configure properly!!"); + } + } + dataCE[i] = buildCEInstance(range.Data(), invmass, corrana); } if (processmixedevents) { /* consistency check */ if (cfgSmallDCE.value) { LOGF(fatal, "Mixed events cannot be used with the small DCE, please configure properly!!"); } - dataCEME[i] = buildCEInstance(range.Data(), true); + if (invmass) { + LOGF(warning, "Invariant mass will not be used with Mixed events!!"); + } + if (!corrana) { + LOGF(fatal, "Mixed events makes not sense to run it without correlations, please configure properly!!"); + } + dataCEME[i] = buildCEInstance(range.Data(), false, true, true); } } for (int i = 0; i < ncmranges; ++i) { @@ -944,6 +1209,14 @@ struct DptDptCorrelationsTask { return grpo->getNominalL3Field(); } + const char* getDimensionStr() + { + using namespace correlationstask; + + static constexpr std::string_view kStrDim[] = {"", "", "2D", "3D", "4D"}; + return kStrDim[nNoOfDimensions].data(); + } + template void processSame(FilterdCollision const& collision, FilteredTracks const& tracks, uint64_t timestamp = 0) { @@ -960,21 +1233,21 @@ struct DptDptCorrelationsTask { if (!(ixDCE < 0)) { auto isCCDBstored = [&]() { if (cfgSmallDCE.value) { - return dataCE_small[ixDCE]->isCCDBstored(); + return dataCEsmall[ixDCE]->isCCDBstored(); } else { return dataCE[ixDCE]->isCCDBstored(); } }; auto storePtAverages = [&](auto& ptavgs) { if (cfgSmallDCE.value) { - dataCE_small[ixDCE]->storePtAverages(ptavgs); + dataCEsmall[ixDCE]->storePtAverages(ptavgs); } else { dataCE[ixDCE]->storePtAverages(ptavgs); } }; auto storeTrackCorrections = [&](auto& corrs) { if (cfgSmallDCE.value) { - dataCE_small[ixDCE]->storeTrackCorrections(corrs); + dataCEsmall[ixDCE]->storeTrackCorrections(corrs); } else { dataCE[ixDCE]->storeTrackCorrections(corrs); } @@ -992,14 +1265,15 @@ struct DptDptCorrelationsTask { } storePtAverages(ptavgs); } else { - std::vector corrs{tnames.size(), nullptr}; + std::vector corrs{tnames.size(), nullptr}; for (uint isp = 0; isp < tnames.size(); ++isp) { - corrs[isp] = reinterpret_cast(ccdblst->FindObject( - TString::Format("correction_%02d-%02d_%s", - static_cast(fCentMultMin[ixDCE]), - static_cast(fCentMultMax[ixDCE]), - tnames[isp].c_str()) - .Data())); + auto hName = TString::Format("correction%s_%02d-%02d_%s", getDimensionStr(), static_cast(fCentMultMin[ixDCE]), static_cast(fCentMultMax[ixDCE]), tnames[isp].c_str()); + corrs[isp] = reinterpret_cast(ccdblst->FindObject(hName.Data())); + if (corrs[isp] != nullptr) { + LOGF(info, "Loaded %s", corrs[isp]->GetName()); + } else { + LOGF(warning, "No correction histogram for species %d with name %s", isp, hName.Data()); + } } storeTrackCorrections(corrs); std::vector ptavgs{tnames.size(), nullptr}; @@ -1032,7 +1306,7 @@ struct DptDptCorrelationsTask { bfield = (fUseConversionCuts || fUseTwoTrackCut) ? getMagneticField(timestamp) : 0; } if (cfgSmallDCE.value) { - dataCE_small[ixDCE]->processCollision(tracks, tracks, collision.posZ(), collision.centmult(), bfield); + dataCEsmall[ixDCE]->processCollision(tracks, tracks, collision.posZ(), collision.centmult(), bfield); } else { dataCE[ixDCE]->processCollision(tracks, tracks, collision.posZ(), collision.centmult(), bfield); } @@ -1066,14 +1340,15 @@ struct DptDptCorrelationsTask { } dataCEME[ixDCE]->storePtAverages(ptavgs); } else { - std::vector corrs{tnames.size(), nullptr}; + std::vector corrs{tnames.size(), nullptr}; for (uint isp = 0; isp < tnames.size(); ++isp) { - corrs[isp] = reinterpret_cast(ccdblst->FindObject( - TString::Format("correction_%02d-%02d_%s", - static_cast(fCentMultMin[ixDCE]), - static_cast(fCentMultMax[ixDCE]), - tnames[isp].c_str()) - .Data())); + auto hName = TString::Format("correction%s_%02d-%02d_%s", getDimensionStr(), static_cast(fCentMultMin[ixDCE]), static_cast(fCentMultMax[ixDCE]), tnames[isp].c_str()); + corrs[isp] = reinterpret_cast(ccdblst->FindObject(hName.Data())); + if (corrs[isp] != nullptr) { + LOGF(info, "Loaded %s", corrs[isp]->GetName()); + } else { + LOGF(warning, "No correction histogram for species %d with name %s", isp, hName.Data()); + } } dataCEME[ixDCE]->storeTrackCorrections(corrs); std::vector ptavgs{tnames.size(), nullptr}; @@ -1114,20 +1389,20 @@ struct DptDptCorrelationsTask { Filter onlyacceptedcollisions = (aod::dptdptfilter::collisionaccepted == uint8_t(true)); Filter onlyacceptedtracks = (aod::dptdptfilter::trackacceptedid >= int8_t(0)); - void processRecLevel(soa::Filtered::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered& tracks) + void processRecLevel(soa::Filtered::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered const& tracks) { processSame(collision, tracks, collision.bc_as().timestamp()); } PROCESS_SWITCH(DptDptCorrelationsTask, processRecLevel, "Process reco level correlations", false); - void processRecLevelCheck(aod::Collisions const& collisions, aod::Tracks& tracks) + void processRecLevelCheck(aod::Collisions const& collisions, aod::Tracks const& tracks) { int nAssignedTracks = 0; int nNotAssignedTracks = 0; int64_t firstNotAssignedIndex = -1; int64_t lastNotAssignedIndex = -1; - for (auto track : tracks) { + for (auto const& track : tracks) { if (track.has_collision()) { nAssignedTracks++; } else { @@ -1147,14 +1422,14 @@ struct DptDptCorrelationsTask { } PROCESS_SWITCH(DptDptCorrelationsTask, processRecLevelCheck, "Process reco level checks", true); - void processGenLevelCheck(aod::McCollisions const& mccollisions, aod::McParticles& particles) + void processGenLevelCheck(aod::McCollisions const& mccollisions, aod::McParticles const& particles) { int nAssignedParticles = 0; int nNotAssignedParticles = 0; int64_t firstNotAssignedIndex = -1; int64_t lastNotAssignedIndex = -1; - for (auto particle : particles) { + for (auto const& particle : particles) { if (particle.has_mcCollision()) { nAssignedParticles++; } else { @@ -1177,18 +1452,15 @@ struct DptDptCorrelationsTask { void processRecLevelNotStored( soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, - soa::Filtered>& tracks) + soa::Filtered> const& tracks) { processSame(collision, tracks, collision.bc_as().timestamp()); } - PROCESS_SWITCH(DptDptCorrelationsTask, - processRecLevelNotStored, - "Process reco level correlations for not stored derived data", - true); + PROCESS_SWITCH(DptDptCorrelationsTask, processRecLevelNotStored, "Process reco level correlations for not stored derived data", true); void processGenLevel( soa::Filtered::iterator const& collision, - soa::Filtered>& tracks) + soa::Filtered> const& tracks) { processSame(collision, tracks); } @@ -1196,14 +1468,11 @@ struct DptDptCorrelationsTask { void processGenLevelNotStored( soa::Filtered>::iterator const& collision, - soa::Filtered>& particles) + soa::Filtered> const& particles) { processSame(collision, particles); } - PROCESS_SWITCH(DptDptCorrelationsTask, - processGenLevelNotStored, - "Process generator level correlations for not stored derived data", - false); + PROCESS_SWITCH(DptDptCorrelationsTask, processGenLevelNotStored, "Process generator level correlations for not stored derived data", false); std::vector vtxBinsEdges{VARIABLE_WIDTH, -7.0f, -5.0f, -3.0f, -1.0f, 1.0f, 3.0f, 5.0f, 7.0f}; @@ -1212,14 +1481,14 @@ struct DptDptCorrelationsTask { using BinningZVtxMultRec = ColumnBinningPolicy; BinningZVtxMultRec bindingOnVtxAndMultRec{{vtxBinsEdges, multBinsEdges}, true}; // true is for 'ignore overflows' (true by default) - void processRecLevelMixed(soa::Filtered& collisions, aod::BCsWithTimestamps const&, soa::Filtered& tracks) + void processRecLevelMixed(soa::Filtered const& collisions, aod::BCsWithTimestamps const&, soa::Filtered const& tracks) { auto tracksTuple = std::make_tuple(tracks); SameKindPair, soa::Filtered, BinningZVtxMultRec> pairreco{bindingOnVtxAndMultRec, 5, -1, collisions, tracksTuple, &cache}; // indicates that 5 events should be mixed and under/overflow (-1) to be ignored LOGF(DPTDPTLOGCOLLISIONS, "Received %d collisions", collisions.size()); int logcomb = 0; - for (auto& [collision1, tracks1, collision2, tracks2] : pairreco) { + for (auto const& [collision1, tracks1, collision2, tracks2] : pairreco) { if (logcomb < 10) { LOGF(DPTDPTLOGCOLLISIONS, "Received collision pair: %ld (%f, %f): %s, %ld (%f, %f): %s", collision1.globalIndex(), collision1.posZ(), collision1.centmult(), collision1.collisionaccepted() ? "accepted" : "not accepted", @@ -1237,9 +1506,9 @@ struct DptDptCorrelationsTask { PROCESS_SWITCH(DptDptCorrelationsTask, processRecLevelMixed, "Process reco level mixed events correlations", false); void processRecLevelMixedNotStored( - soa::Filtered>& collisions, + soa::Filtered> const& collisions, aod::BCsWithTimestamps const&, - soa::Filtered>& tracks) + soa::Filtered> const& tracks) { auto tracksTuple = std::make_tuple(tracks); SameKindPair>, @@ -1254,7 +1523,7 @@ struct DptDptCorrelationsTask { LOGF(DPTDPTLOGCOLLISIONS, "Received %d collisions", collisions.size()); int logcomb = 0; - for (auto& [collision1, tracks1, collision2, tracks2] : pairreco) { + for (auto const& [collision1, tracks1, collision2, tracks2] : pairreco) { if (logcomb < 10) { LOGF(DPTDPTLOGCOLLISIONS, "Received collision pair: %ld (%f, %f): %s, %ld (%f, %f): %s", @@ -1286,22 +1555,19 @@ struct DptDptCorrelationsTask { collision1.bc_as().timestamp()); } } - PROCESS_SWITCH(DptDptCorrelationsTask, - processRecLevelMixedNotStored, - "Process reco level mixed events correlations for not stored derived data", - false); + PROCESS_SWITCH(DptDptCorrelationsTask, processRecLevelMixedNotStored, "Process reco level mixed events correlations for not stored derived data", false); using BinningZVtxMultGen = ColumnBinningPolicy; BinningZVtxMultGen bindingOnVtxAndMultGen{{vtxBinsEdges, multBinsEdges}, true}; // true is for 'ignore overflows' (true by default) - void processGenLevelMixed(soa::Filtered& collisions, soa::Filtered& tracks) + void processGenLevelMixed(soa::Filtered const& collisions, soa::Filtered const& tracks) { auto tracksTuple = std::make_tuple(tracks); SameKindPair, soa::Filtered, BinningZVtxMultGen> pairgen{bindingOnVtxAndMultGen, 5, -1, collisions, tracksTuple, &cache}; // indicates that 5 events should be mixed and under/overflow (-1) to be ignored LOGF(DPTDPTLOGCOLLISIONS, "Received %d generated collisions", collisions.size()); int logcomb = 0; - for (auto& [collision1, tracks1, collision2, tracks2] : pairgen) { + for (auto const& [collision1, tracks1, collision2, tracks2] : pairgen) { if (logcomb < 10) { LOGF(DPTDPTLOGCOLLISIONS, "Received generated collision pair: %ld (%f, %f): %s, %ld (%f, %f): %s", collision1.globalIndex(), collision1.posZ(), collision1.centmult(), collision1.collisionaccepted() ? "accepted" : "not accepted", @@ -1317,9 +1583,7 @@ struct DptDptCorrelationsTask { } PROCESS_SWITCH(DptDptCorrelationsTask, processGenLevelMixed, "Process generator level mixed events correlations", false); - void processGenLevelMixedNotStored( - soa::Filtered>& collisions, - soa::Filtered>& tracks) + void processGenLevelMixedNotStored(soa::Filtered> const& collisions, soa::Filtered> const& tracks) { auto tracksTuple = std::make_tuple(tracks); SameKindPair>, @@ -1334,7 +1598,7 @@ struct DptDptCorrelationsTask { LOGF(DPTDPTLOGCOLLISIONS, "Received %d generated collisions", collisions.size()); int logcomb = 0; - for (auto& [collision1, tracks1, collision2, tracks2] : pairgen) { + for (auto const& [collision1, tracks1, collision2, tracks2] : pairgen) { if (logcomb < 10) { LOGF(DPTDPTLOGCOLLISIONS, "Received generated collision pair: %ld (%f, %f): %s, %ld (%f, %f): %s", @@ -1362,10 +1626,7 @@ struct DptDptCorrelationsTask { processMixed(collision1, tracks1, tracks2); } } - PROCESS_SWITCH(DptDptCorrelationsTask, - processGenLevelMixedNotStored, - "Process generator level mixed events correlations for not stored derived data", - false); + PROCESS_SWITCH(DptDptCorrelationsTask, processGenLevelMixedNotStored, "Process generator level mixed events correlations for not stored derived data", false); /// cleans the output object when the task is not used void processCleaner(soa::Filtered const& colls) @@ -1379,7 +1640,7 @@ struct DptDptCorrelationsTask { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow{ - adaptAnalysisTask(cfgc, TaskName{"DptDptCorrelationsTaskRec"}, SetDefaultProcesses{{{"processRecLevel", true}, {"processRecLevelMixed", false}, {"processCleaner", false}}}), - adaptAnalysisTask(cfgc, TaskName{"DptDptCorrelationsTaskGen"}, SetDefaultProcesses{{{"processGenLevel", false}, {"processGenLevelMixed", false}, {"processCleaner", true}}})}; + adaptAnalysisTask(cfgc, TaskName{"DptDptCorrelationsTaskRec"}, SetDefaultProcesses{{{"processRecLevel", true}, {"processRecLevelMixed", false}, {"processCleaner", false}}}), // o2-linter: disable=name/o2-task + adaptAnalysisTask(cfgc, TaskName{"DptDptCorrelationsTaskGen"}, SetDefaultProcesses{{{"processGenLevel", false}, {"processGenLevelMixed", false}, {"processCleaner", true}}})}; // o2-linter: disable=name/o2-task return workflow; } diff --git a/PWGCF/Tasks/match-reco-gen.cxx b/PWGCF/Tasks/matchRecoGen.cxx similarity index 65% rename from PWGCF/Tasks/match-reco-gen.cxx rename to PWGCF/Tasks/matchRecoGen.cxx index 3cba78997b2..486eae85e37 100644 --- a/PWGCF/Tasks/match-reco-gen.cxx +++ b/PWGCF/Tasks/matchRecoGen.cxx @@ -9,10 +9,17 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file matchRecoGen.cxx +/// \brief basic check for the matching between generator level and detector level +/// \author victor.gonzalez.sebastian@gmail.com + #include +#include +#include #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" +#include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/PIDResponse.h" @@ -20,11 +27,11 @@ #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/runDataProcessing.h" #include "PWGCF/Core/AnalysisConfigurableCuts.h" #include "PWGCF/DataModel/DptDptFiltered.h" #include "PWGCF/TableProducer/dptdptfilter.h" -#include #include #include #include @@ -50,25 +57,15 @@ std::vector> mclabelneg[2]; } // namespace o2::analysis::recogenmap /// \brief Checks the correspondence generator level <=> detector level -struct CheckGeneratorLevelVsDetectorLevel { - Configurable cfgTrackType{"trktype", 1, "Type of selected tracks: 0 = no selection, 1 = global tracks FB96"}; - Configurable cfgCentMultEstimator{"centmultestimator", "V0M", "Centrality/multiplicity estimator detector: V0M, NOCM: none. Default V0M"}; - Configurable cfgSystem{"syst", "PbPb", "System: pp, PbPb, Pbp, pPb, XeXe, ppRun3. Default PbPb"}; - Configurable cfgDataType{"datatype", "data", "Data type: data, datanoevsel, MC, FastMC, OnTheFlyMC. Default data"}; - Configurable cfgTriggSel{"triggsel", "MB", "Trigger selection: MB, None. Default MB"}; - Configurable cfgOverallMinP{"overallminp", 0.0f, "The overall minimum momentum for the analysis. Default: 0.0"}; - Configurable cfgBinning{"binning", - {28, -7.0, 7.0, 18, 0.2, 2.0, 16, -0.8, 0.8, 72, 0.5}, - "triplets - nbins, min, max - for z_vtx, pT, eta and phi, binning plus bin fraction of phi origin shift"}; - Configurable cfgTraceDCAOutliers{"trackdcaoutliers", {false, 0.0, 0.0}, "Track the generator level DCAxy outliers: false/true, low dcaxy, up dcaxy. Default {false,0.0,0.0}"}; - Configurable cfgTraceOutOfSpeciesParticles{"trackoutparticles", false, "Track the particles which are not e,mu,pi,K,p: false/true. Default false"}; - Configurable cfgRecoIdMethod{"recoidmethod", 0, "Method for identifying reconstructed tracks: 0 PID, 1 mcparticle. Default 0"}; - Configurable cfgTuneTrackSelection{"tunetracksel", {}, "Track selection: {useit: true/false, tpccls-useit, tpcxrws-useit, tpcxrfc-useit, dcaxy-useit, dcaz-useit}. Default {false,0.70,false,0.8,false,2.4,false,3.2,false}"}; - Configurable cfgTraceCollId0{"tracecollid0", false, "Trace particles in collisions id 0. Default false"}; - Configurable cfgTrackMultiRec{"trackmultirec", false, "Track muli-reconstructed particles: true, false. Default false"}; - Configurable cfgTrackCollAssoc{"trackcollassoc", false, "Track collision id association, track-mcparticle-mccollision vs. track-collision-mccollision: true, false. Default false"}; +struct MatchRecoGen { + Configurable cfgTraceDCAOutliers{"cfgTraceDCAOutliers", {false, 0.0, 0.0}, "Track the generator level DCAxy outliers: false/true, low dcaxy, up dcaxy. Default {false,0.0,0.0}"}; + Configurable cfgTraceOutOfSpeciesParticles{"cfgTraceOutOfSpeciesParticles", false, "Track the particles which are not e,mu,pi,K,p: false/true. Default false"}; + Configurable cfgTraceCollId0{"cfgTraceCollId0", false, "Trace particles in collisions id 0. Default false"}; + Configurable cfgTrackMultiRec{"cfgTrackMultiRec", false, "Track muli-reconstructed particles: true, false. Default false"}; + Configurable cfgTrackCollAssoc{"cfgTrackCollAssoc", false, "Track collision id association, track-mcparticle-mccollision vs. track-collision-mccollision: true, false. Default false"}; HistogramRegistry histos{"RecoGenHistograms", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + Service fPDG; typedef enum { kBEFORE = 0, kAFTER } beforeafterselection; typedef enum { kPOSITIVE = 0, @@ -82,44 +79,20 @@ struct CheckGeneratorLevelVsDetectorLevel { using namespace o2::analysis::dptdptfilter; /* update with the configurable values */ - overallminp = cfgOverallMinP.value; - /* the binning */ - ptbins = cfgBinning->mPTbins; - ptlow = cfgBinning->mPTmin; - ptup = cfgBinning->mPTmax; - etabins = cfgBinning->mEtabins; - etalow = cfgBinning->mEtamin; - etaup = cfgBinning->mEtamax; - zvtxbins = cfgBinning->mZVtxbins; - zvtxlow = cfgBinning->mZVtxmin; - zvtxup = cfgBinning->mZVtxmax; - /* the track types and combinations */ - tracktype = cfgTrackType.value; - initializeTrackSelection(cfgTuneTrackSelection); - /* the centrality/multiplicity estimation */ - fCentMultEstimator = getCentMultEstimator(cfgCentMultEstimator); - /* the trigger selection */ - fTriggerSelection = getTriggerSelection(cfgTriggSel); traceDCAOutliers = cfgTraceDCAOutliers; traceOutOfSpeciesParticles = cfgTraceOutOfSpeciesParticles; - recoIdMethod = cfgRecoIdMethod; traceCollId0 = cfgTraceCollId0; - /* if the system type is not known at this time, we have to put the initialization somewhere else */ - fSystem = getSystemType(cfgSystem); - fDataType = getDataType(cfgDataType); - fPDG = TDatabasePDG::Instance(); - AxisSpec deltaEta = {100, -2, 2, "#Delta#eta"}; AxisSpec deltaPhi = {100, 0, constants::math::TwoPI, "#Delta#varphi (rad)"}; AxisSpec deltaPt = {1000, 0, 4, "#Delta#it{p}_{T} (GeV/#it{c})"}; AxisSpec mrectimes = {11, -0.5f, 10.5f, "##/particle"}; AxisSpec detectors = {32, -0.5, 31.5, "Detectors"}; - std::vector detectorlbls = {"", "ITS", "TPC", "ITS+TPC", "TRD", "ITS+TRD", "TPC+TRD", "ITS+TPC+TRD", - "TOF", "ITS+TOF", "TPC+TOF", "ITS+TPC+TOF", "TRD+TOF", "ITS+TRD+TOF", "TPC+TRD+TOF", "ITS+TPC+TRD+TOF", - "UNKN", "ITS+UNKN", "TPC+UNKN", "ITS+TPC+UNKN", "TRD+UNKN", "ITS+TRD+UNKN", "TPC+TRD+UNKN", "ITS+TPC+TRD+UNKN", - "TOF+UNKN", "ITS+TOF+UNKN", "TPC+TOF+UNKN", "ITS+TPC+TOF+UNKN", "TRD+TOF+UNKN", "ITS+TRD+TOF+UNKN", "TPC+TRD+TOF+UNKN", "ITS+TPC+TRD+TOF+UNKN"}; - std::vector matchlbs = {"match", "don't match"}; + std::vector detectorLabels = {"", "ITS", "TPC", "ITS+TPC", "TRD", "ITS+TRD", "TPC+TRD", "ITS+TPC+TRD", + "TOF", "ITS+TOF", "TPC+TOF", "ITS+TPC+TOF", "TRD+TOF", "ITS+TRD+TOF", "TPC+TRD+TOF", "ITS+TPC+TRD+TOF", + "UNKN", "ITS+UNKN", "TPC+UNKN", "ITS+TPC+UNKN", "TRD+UNKN", "ITS+TRD+UNKN", "TPC+TRD+UNKN", "ITS+TPC+TRD+UNKN", + "TOF+UNKN", "ITS+TOF+UNKN", "TPC+TOF+UNKN", "ITS+TPC+TOF+UNKN", "TRD+TOF+UNKN", "ITS+TRD+TOF+UNKN", "TPC+TRD+TOF+UNKN", "ITS+TPC+TRD+TOF+UNKN"}; + std::vector matchLabels = {"match", "don't match"}; histos.add("before/positivecolid/mrDeltaEta", "#Delta#eta multirec tracks", kTH1F, {deltaEta}); histos.add("before/positivecolid/mrDeltaPhi", "#Delta#varphi multirec tracks", kTH1F, {deltaPhi}); @@ -146,13 +119,13 @@ struct CheckGeneratorLevelVsDetectorLevel { histos.add("before/positivecolid/dcazmr", "DCA_{z} Reconstructed (mr)", kTH1F, {{1000, -4.0, 4.0, "DCA_{z} (cm)"}}); histos.add("before/positivecolid/finedcaxymr", "DCA_{xy} Reconstructed (mr)", kTH1F, {{2000, -1.0, 1.0, "DCA_{xy} (cm)"}}); histos.add("before/positivecolid/finedcazmr", "DCA_{z} Reconstructed (mr)", kTH1F, {{2000, -1.0, 1.0, "DCA_{z} (cm)"}}); - for (unsigned int i = 0; i < detectorlbls.size(); ++i) { - histos.get(HIST("before/positivecolid/detectormap"))->GetXaxis()->SetBinLabel(i + 1, detectorlbls[i].c_str()); - histos.get(HIST("before/positivecolid/detectormapmr"))->GetXaxis()->SetBinLabel(i + 1, detectorlbls[i].c_str()); + for (unsigned int i = 0; i < detectorLabels.size(); ++i) { + histos.get(HIST("before/positivecolid/detectormap"))->GetXaxis()->SetBinLabel(i + 1, detectorLabels[i].c_str()); + histos.get(HIST("before/positivecolid/detectormapmr"))->GetXaxis()->SetBinLabel(i + 1, detectorLabels[i].c_str()); } - for (unsigned int i = 0; i < matchlbs.size(); ++i) { - histos.get(HIST("before/positivecolid/matchcollid"))->GetXaxis()->SetBinLabel(i + 1, matchlbs[i].c_str()); - histos.get(HIST("before/positivecolid/matchcollidmr"))->GetXaxis()->SetBinLabel(i + 1, matchlbs[i].c_str()); + for (unsigned int i = 0; i < matchLabels.size(); ++i) { + histos.get(HIST("before/positivecolid/matchcollid"))->GetXaxis()->SetBinLabel(i + 1, matchLabels[i].c_str()); + histos.get(HIST("before/positivecolid/matchcollidmr"))->GetXaxis()->SetBinLabel(i + 1, matchLabels[i].c_str()); } /* clone the set for the other cases */ @@ -167,23 +140,23 @@ struct CheckGeneratorLevelVsDetectorLevel { { using namespace o2::analysis::recogenmap; - static constexpr std::string_view dir[] = {"before/", "after/"}; - static constexpr std::string_view colldir[] = {"positivecolid/", "negativecolid/"}; + static constexpr std::string_view Dir[] = {"before/", "after/"}; + static constexpr std::string_view Colldir[] = {"positivecolid/", "negativecolid/"}; - int nrec_poslabel = 0; - int nrec_neglabel = 0; - int nrec_poslabel_crosscoll = 0; + int nRecPosLabel = 0; + int nRecNegLabel = 0; + int nRecPosLabelCrossColl = 0; for (int ixpart = 0; ixpart < mcParticles.size(); ++ixpart) { auto particle = mcParticles.iteratorAt(ixpart); /* multireconstructed tracks only for positive labels */ int nrec = mclabelpos[collsign][ixpart].size(); - nrec_poslabel += mclabelpos[collsign][ixpart].size(); - nrec_neglabel += mclabelneg[collsign][ixpart].size(); + nRecPosLabel += mclabelpos[collsign][ixpart].size(); + nRecNegLabel += mclabelneg[collsign][ixpart].size(); if (nrec > 1) { /* multireconstruction only from positive labels */ - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("multirec"), nrec); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("multirec"), nrec); if (collsign == kPOSITIVE) { /* check the cross collision reconstruction */ @@ -197,7 +170,7 @@ struct CheckGeneratorLevelVsDetectorLevel { auto track2 = tracks.iteratorAt(mclabelpos[collsign][ixpart][j]); if (track1.collisionId() != track2.collisionId()) { - nrec_poslabel_crosscoll++; + nRecPosLabelCrossColl++; crosscollfound = true; } } @@ -236,8 +209,7 @@ struct CheckGeneratorLevelVsDetectorLevel { "END multi-reconstructed: " "=================================================================="); } - histos.get(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("pdgcodemr")) - ->Fill(TString::Format("%d", particle.pdgCode()).Data(), 1.0); + histos.get(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("pdgcodemr"))->Fill(TString::Format("%d", particle.pdgCode()).Data(), 1.0); } } @@ -248,52 +220,47 @@ struct CheckGeneratorLevelVsDetectorLevel { float deltaeta = track1.eta() - track2.eta(); float deltaphi = track1.phi() - track2.phi(); - if (deltaphi < 0) { - deltaphi += constants::math::TwoPI; - } - if (deltaphi > constants::math::TwoPI) { - deltaphi -= constants::math::TwoPI; - } + deltaphi = RecoDecay::constrainAngle(deltaphi, 0.0f); float deltapt = (track1.pt() > track2.pt()) ? track1.pt() - track2.pt() : track2.pt() - track1.pt(); - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("mrDeltaEta"), deltaeta); - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("mrDeltaPhi"), deltaphi); - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("mrDeltaPt"), deltapt); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("mrDeltaEta"), deltaeta); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("mrDeltaPhi"), deltaphi); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("mrDeltaPt"), deltapt); } - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("recomreta"), track1.eta()); - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("recomrphi"), track1.phi()); - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("recomrpt"), track1.pt()); - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("detectormapmr"), track1.detectorMap()); - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("dcaxymr"), track1.dcaXY()); - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("dcazmr"), track1.dcaZ()); - if (track1.dcaXY() < 1.0) { - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("finedcaxymr"), track1.dcaXY()); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("recomreta"), track1.eta()); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("recomrphi"), track1.phi()); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("recomrpt"), track1.pt()); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("detectormapmr"), track1.detectorMap()); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("dcaxymr"), track1.dcaXY()); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("dcazmr"), track1.dcaZ()); + if (std::fabs(track1.dcaXY()) < 1.0) { + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("finedcaxymr"), track1.dcaXY()); } - if (track1.dcaZ() < 1.0) { - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("finedcazmr"), track1.dcaZ()); + if (std::fabs(track1.dcaZ()) < 1.0) { + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("finedcazmr"), track1.dcaZ()); } - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("genrecomreta"), track1.eta(), particle.eta()); - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("genrecomrphi"), track1.phi(), particle.phi()); - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("genrecomrpt"), track1.pt(), particle.pt()); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("genrecomreta"), track1.eta(), particle.eta()); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("genrecomrphi"), track1.phi(), particle.phi()); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("genrecomrpt"), track1.pt(), particle.pt()); if (particle.mcCollisionId() != colls.iteratorAt(track1.collisionId()).mcCollisionId()) { - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("matchcollidmr"), static_cast(kDONTMATCH) + 0.5f); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("matchcollidmr"), static_cast(kDONTMATCH) + 0.5f); } else { - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("matchcollidmr"), static_cast(kMATCH) + 0.5f); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("matchcollidmr"), static_cast(kMATCH) + 0.5f); } } } else if (nrec > 0) { auto track = tracks.iteratorAt(mclabelpos[collsign][ixpart][0]); - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("genrecoeta"), track.eta(), particle.eta()); - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("genrecophi"), track.phi(), particle.phi()); - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("genrecopt"), track.pt(), particle.pt()); - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("detectormap"), track.detectorMap()); - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("dcaxy"), track.dcaXY()); - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("dcaz"), track.dcaZ()); - if (track.dcaXY() < 1.0) { - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("finedcaxy"), track.dcaXY()); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("genrecoeta"), track.eta(), particle.eta()); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("genrecophi"), track.phi(), particle.phi()); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("genrecopt"), track.pt(), particle.pt()); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("detectormap"), track.detectorMap()); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("dcaxy"), track.dcaXY()); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("dcaz"), track.dcaZ()); + if (std::fabs(track.dcaXY()) < 1.0) { + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("finedcaxy"), track.dcaXY()); } - if (track.dcaZ() < 1.0) { - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("finedcaz"), track.dcaZ()); + if (std::fabs(track.dcaZ()) < 1.0) { + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("finedcaz"), track.dcaZ()); } if (particle.mcCollisionId() != colls.iteratorAt(track.collisionId()).mcCollisionId()) { if ((ba == kAFTER) && (collsign == kPOSITIVE) && cfgTrackCollAssoc) { @@ -303,19 +270,19 @@ struct CheckGeneratorLevelVsDetectorLevel { LOGF(info, " associated to track with index %d and label %d assigned to collision %d, with associated MC collision %d", track.globalIndex(), ixpart, track.collisionId(), colls.iteratorAt(track.collisionId()).mcCollisionId()); } - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("matchcollid"), static_cast(kDONTMATCH) + 0.5f); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("matchcollid"), static_cast(kDONTMATCH) + 0.5f); } else { - histos.fill(HIST(dir[ba]) + HIST(colldir[collsign]) + HIST("matchcollid"), static_cast(kMATCH) + 0.5f); + histos.fill(HIST(Dir[ba]) + HIST(Colldir[collsign]) + HIST("matchcollid"), static_cast(kMATCH) + 0.5f); } } } if (collsign == kPOSITIVE) { LOGF(info, "Reconstructed tracks (%s) with positive collision ID: %d with positive label, %d with negative label, %d with cross collision", - ba == kAFTER ? "after" : "before", nrec_poslabel, nrec_neglabel, nrec_poslabel_crosscoll); + ba == kAFTER ? "after" : "before", nRecPosLabel, nRecNegLabel, nRecPosLabelCrossColl); } else { LOGF(info, "Reconstructed tracks (%s) with negative collision ID: %d with positive label, %d with negative label", - ba == kAFTER ? "after" : "before", nrec_poslabel, nrec_neglabel); + ba == kAFTER ? "after" : "before", nRecPosLabel, nRecNegLabel); } } @@ -335,10 +302,10 @@ struct CheckGeneratorLevelVsDetectorLevel { size_t nreco = tracks.size(); size_t ngen = 0; - for (auto& part : mcParticles) { + for (auto const& part : mcParticles) { auto pdgpart = fPDG->GetParticle(part.pdgCode()); if (pdgpart != nullptr) { - float charge = (pdgpart->Charge() >= 3) ? 1.0 : ((pdgpart->Charge() <= -3) ? -1.0 : 0.0); + float charge = getCharge(pdgpart->Charge()); if (charge != 0.0) { ngen++; } @@ -349,7 +316,7 @@ struct CheckGeneratorLevelVsDetectorLevel { // For the time being we are only interested in the information based on the reconstructed tracks LOGF(info, "New dataframe (DF) with %d generated charged particles and %d reconstructed tracks", ngen, nreco); - for (auto& track : tracks) { + for (auto const& track : tracks) { int64_t recix = track.globalIndex(); int32_t label = track.mcParticleId(); @@ -389,10 +356,10 @@ struct CheckGeneratorLevelVsDetectorLevel { size_t nreco = 0; size_t ngen = 0; - for (auto& part : mcParticles) { + for (auto const& part : mcParticles) { auto pdgpart = fPDG->GetParticle(part.pdgCode()); if (pdgpart != nullptr) { - float charge = (pdgpart->Charge() >= 3) ? 1.0 : ((pdgpart->Charge() <= -3) ? -1.0 : 0.0); + float charge = getCharge(pdgpart->Charge()); if (charge != 0.0) { ngen++; } @@ -400,16 +367,15 @@ struct CheckGeneratorLevelVsDetectorLevel { } // Let's go through the reco-gen mapping to detect multi-reconstructed particles - for (auto& track : tracks) { + for (auto const& track : tracks) { int64_t recix = track.globalIndex(); int32_t label = track.mcParticleId(); if (!(label < 0)) { if (!(track.collisionId() < 0)) { typename CollisionsObject::iterator coll = collisions.iteratorAt(track.collisionId()); - float centormult = -100.0f; - if (IsEvtSelected(coll, centormult)) { + if (coll.collisionaccepted() == uint8_t(true)) { /* TODO: AcceptTrack does not consider PID */ - if (AcceptTrack(track)) { + if (!(track.trackacceptedid() < 0)) { /* the track has been accepted */ nreco++; LOGF(MATCHRECGENLOGTRACKS, "Accepted track with global Id %d and collision Id %d has label %d associated to MC collision %d", recix, track.collisionId(), label, track.template mcParticle_as().mcCollisionId()); @@ -424,27 +390,18 @@ struct CheckGeneratorLevelVsDetectorLevel { collectData(tracks, mcParticles, collisions); } - void processMapChecksWithCent(soa::Join const& tracks, - soa::Join const& collisions, - aod::McParticles const& mcParticles) - { - processMapChecksBeforeCuts(tracks, collisions, mcParticles); - processMapChecksAfterCuts(tracks, collisions, mcParticles); - } - PROCESS_SWITCH(CheckGeneratorLevelVsDetectorLevel, processMapChecksWithCent, "Process detector <=> generator levels with centrality/multiplicity information", false); - - void processMapChecksWithoutCent(soa::Join const& tracks, - soa::Join const& collisions, - aod::McParticles const& mcParticles) + void processMapChecks(soa::Join const& tracks, + soa::Join const& collisions, + aod::McParticles const& mcParticles) { processMapChecksBeforeCuts(tracks, collisions, mcParticles); processMapChecksAfterCuts(tracks, collisions, mcParticles); } - PROCESS_SWITCH(CheckGeneratorLevelVsDetectorLevel, processMapChecksWithoutCent, "Process detector <=> generator levels without centrality/multiplicity information", true); + PROCESS_SWITCH(MatchRecoGen, processMapChecks, "Process detector <=> generator levels", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; return workflow; } diff --git a/PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.cxx b/PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.cxx index b6528975ee7..5eda3450473 100644 --- a/PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.cxx +++ b/PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.cxx @@ -8,10 +8,17 @@ // 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 identifiedBfFilter.cxx +/// \brief Filters collisions and tracks according to selection criteria +/// \author bghanley1995@gmail.com + #include "PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.h" #include #include +#include +#include #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -26,9 +33,10 @@ #include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Framework/runDataProcessing.h" +#include "Framework/O2DatabasePDGPlugin.h" #include -#include #include +#include #include #include #include @@ -50,16 +58,28 @@ namespace o2::analysis::identifiedbffilter { using IdBfFullTracks = soa::Join; using IdBfFullTracksAmbiguous = soa::Join; -using IdBfTracksPID = soa::Join; +using IdBfTracksPID = soa::Join; +using IdBfTracksFullPID = soa::Join; using IdBfFullTracksPID = soa::Join; +using IdBfFullTracksFullPID = soa::Join; using IdBfFullTracksPIDAmbiguous = soa::Join; +using IdBfFullTracksFullPIDAmbiguous = soa::Join; using IdBfFullTracksDetLevel = soa::Join; using IdBfFullTracksDetLevelAmbiguous = soa::Join; using IdBfFullTracksPIDDetLevel = soa::Join; +using IdBfFullTracksFullPIDDetLevel = soa::Join; using IdBfFullTracksPIDDetLevelAmbiguous = soa::Join; +using IdBfFullTracksFullPIDDetLevelAmbiguous = soa::Join; bool fullDerivedData = false; /* produce full derived data for its external storage */ +TList* ccdblst = nullptr; +bool loadfromccdb = false; + +std::vector recoIdMethods = {0, 1, 2}; // Reconstructed PID Methods, 0 is no PID, 1 is calculated PID, 2 is MC PID +std::vector trackTypes = {0, 1, 2, 3}; +const int twoDenom = 2; // Used to test if a value is even or odd + //============================================================================================ // The IdentifiedBfFilter histogram objects // TODO: consider registering in the histogram registry @@ -70,16 +90,42 @@ TH1F* fhVertexZB = nullptr; TH1F* fhVertexZA = nullptr; TH1F* fhMultB = nullptr; TH1F* fhMultA = nullptr; +TH2F* fhYZB = nullptr; +TH2F* fhXYB = nullptr; +TH2F* fhYZA = nullptr; +TH2F* fhXYA = nullptr; TH1F* fhPB = nullptr; -TH1F* fhPA[kIdBfNoOfSpecies] = {nullptr}; +TH1F* fhPA[kIdBfNoOfSpecies + 1] = {nullptr}; TH1F* fhPtB = nullptr; -TH1F* fhPtA[kIdBfNoOfSpecies] = {nullptr}; +TH1F* fhPtA[kIdBfNoOfSpecies + 1] = {nullptr}; TH1F* fhPtPosB = nullptr; -TH1F* fhPtPosA[kIdBfNoOfSpecies] = {nullptr}; +TH1F* fhPtPosA[kIdBfNoOfSpecies + 1] = {nullptr}; TH1F* fhPtNegB = nullptr; -TH1F* fhPtNegA[kIdBfNoOfSpecies] = {nullptr}; -TH2F* fhNPosNegA[kIdBfNoOfSpecies] = {nullptr}; -TH1F* fhDeltaNA[kIdBfNoOfSpecies] = {nullptr}; +TH1F* fhPtNegA[kIdBfNoOfSpecies + 1] = {nullptr}; +TH2F* fhNPosNegA[kIdBfNoOfSpecies + 1] = {nullptr}; +TH1F* fhDeltaNA[kIdBfNoOfSpecies + 1] = {nullptr}; + +TH2F* fhPtEtaPosA[kIdBfNoOfSpecies + 1] = {nullptr}; +TH2F* fhPtEtaNegA[kIdBfNoOfSpecies + 1] = {nullptr}; + +TH1I* fhNClustersB = nullptr; +TH2F* fhPhiYB = nullptr; +TH2F* fhPtYB = nullptr; +TH1F* fhChi2B = nullptr; +TH1I* fhITSNclB = nullptr; + +TH1I* fhNClustersA = nullptr; +TH2F* fhPhiYA = nullptr; +TH2F* fhPtYA = nullptr; +TH1F* fhChi2A = nullptr; +TH1I* fhITSNclA = nullptr; + +TH2F* fhNSigmaTPC[kIdBfNoOfSpecies] = {nullptr}; +TH2F* fhNSigmaTOF[kIdBfNoOfSpecies] = {nullptr}; +TH2F* fhNSigmaCombo[kIdBfNoOfSpecies] = {nullptr}; +TH2F* fhNSigmaTPCIdTrks[kIdBfNoOfSpecies] = {nullptr}; + +TH1F* fhNSigmaCorrection[kIdBfNoOfSpecies] = {nullptr}; TH1F* fhEtaB = nullptr; TH1F* fhEtaA = nullptr; @@ -88,35 +134,67 @@ TH1F* fhPhiB = nullptr; TH1F* fhPhiA = nullptr; TH2F* fhdEdxB = nullptr; -TH2F* fhdEdxA[kIdBfNoOfSpecies] = {nullptr}; +TH2F* fhdEdxIPTPCB = nullptr; +TH2F* fhdEdxA[kIdBfNoOfSpecies + 2] = {nullptr}; +TH2F* fhdEdxIPTPCA[kIdBfNoOfSpecies + 2] = {nullptr}; +TH2F* fhTrackTimeA[kIdBfNoOfSpecies + 2] = {nullptr}; +TH2F* fhTrackBetaA[kIdBfNoOfSpecies + 2] = {nullptr}; + +TH1F* fhMassB = nullptr; +TH1F* fhMassA[kIdBfNoOfSpecies + 1] = {nullptr}; + +TH2S* fhDoublePID = nullptr; TH1F* fhDCAxyB = nullptr; TH1F* fhDCAxyA = nullptr; TH1F* fhFineDCAxyA = nullptr; TH1F* fhDCAzB = nullptr; +TH2F* fhDCAxyzB = nullptr; TH1F* fhDCAzA = nullptr; TH1F* fhFineDCAzA = nullptr; +TH2F* fhDCAxyzA = nullptr; + +TH1F* fhWrongTrackID = nullptr; TH2D* fhAmbiguousTrackType = nullptr; TH2F* fhAmbiguousTrackPt = nullptr; TH2F* fhAmbiguityDegree = nullptr; TH2F* fhCompatibleCollisionsZVtxRms = nullptr; +TH2S* fhTruePIDMismatch = nullptr; +TH1S* fhTruePIDCorrect = nullptr; + +std::vector> fhTrueNSigmaTPC = {o2::analysis::identifiedbffilter::kIdBfNoOfSpecies, {o2::analysis::identifiedbffilter::kIdBfNoOfSpecies, nullptr}}; +std::vector> fhTrueNSigmaTOF = {o2::analysis::identifiedbffilter::kIdBfNoOfSpecies, {o2::analysis::identifiedbffilter::kIdBfNoOfSpecies, nullptr}}; + TH1F* fhTrueCentMultB = nullptr; TH1F* fhTrueCentMultA = nullptr; TH1F* fhTrueVertexZB = nullptr; TH1F* fhTrueVertexZA = nullptr; TH1F* fhTrueVertexZAA = nullptr; TH1F* fhTruePB = nullptr; -TH1F* fhTruePA[kIdBfNoOfSpecies] = {nullptr}; +TH1F* fhTrueCharge = nullptr; +TH1F* fhTruePA[kIdBfNoOfSpecies + 1] = {nullptr}; TH1F* fhTruePtB = nullptr; -TH1F* fhTruePtA[kIdBfNoOfSpecies] = {nullptr}; +TH1F* fhTruePtA[kIdBfNoOfSpecies + 1] = {nullptr}; TH1F* fhTruePtPosB = nullptr; -TH1F* fhTruePtPosA[kIdBfNoOfSpecies] = {nullptr}; +TH1F* fhTruePtPosA[kIdBfNoOfSpecies + 1] = {nullptr}; TH1F* fhTruePtNegB = nullptr; -TH1F* fhTruePtNegA[kIdBfNoOfSpecies] = {nullptr}; -TH2F* fhTrueNPosNegA[kIdBfNoOfSpecies] = {nullptr}; -TH1F* fhTrueDeltaNA[kIdBfNoOfSpecies] = {nullptr}; +TH1F* fhTruePtNegA[kIdBfNoOfSpecies + 1] = {nullptr}; +TH2F* fhTrueNPosNegA[kIdBfNoOfSpecies + 1] = {nullptr}; +TH1F* fhTrueDeltaNA[kIdBfNoOfSpecies + 1] = {nullptr}; + +TH2F* fhTruedEdx[kIdBfNoOfSpecies + 1] = {nullptr}; +TH2F* fhTrueTrackTime[kIdBfNoOfSpecies + 1] = {nullptr}; + +TH2F* fhTruePtEtaPosA[kIdBfNoOfSpecies + 1] = {nullptr}; +TH2F* fhTruePtEtaNegA[kIdBfNoOfSpecies + 1] = {nullptr}; + +TH2F* fhTruePhiYB = nullptr; +TH2F* fhTruePtYB = nullptr; + +TH2F* fhTruePhiYA = nullptr; +TH2F* fhTruePtYA = nullptr; TH1F* fhTrueEtaB = nullptr; TH1F* fhTrueEtaA = nullptr; @@ -129,28 +207,30 @@ TH1F* fhTrueDCAxyA = nullptr; TH1F* fhTrueDCAzB = nullptr; TH1F* fhTrueDCAxyBid = nullptr; TH1F* fhTrueDCAzA = nullptr; +TH2F* fhTrueDCAxyzB = nullptr; +TH2F* fhTrueDCAxyzA = nullptr; //============================================================================================ // The IdentifiedBfFilter multiplicity counters //============================================================================================ -int trkMultPos[kIdBfNoOfSpecies]; // multiplicity of positive tracks -int trkMultNeg[kIdBfNoOfSpecies]; // multiplicity of negative tracks -int partMultPos[kIdBfNoOfSpecies]; // multiplicity of positive particles -int partMultNeg[kIdBfNoOfSpecies]; // multiplicity of negative particles +int trkMultPos[kIdBfNoOfSpecies + 1]; // multiplicity of positive tracks +int trkMultNeg[kIdBfNoOfSpecies + 1]; // multiplicity of negative tracks +int partMultPos[kIdBfNoOfSpecies + 1]; // multiplicity of positive particles +int partMultNeg[kIdBfNoOfSpecies + 1]; // multiplicity of negative particles } // namespace o2::analysis::identifiedbffilter using namespace identifiedbffilter; struct IdentifiedBfFilter { - Configurable cfgFullDerivedData{"fullderiveddata", false, "Produce the full derived data for external storage. Default false"}; - Configurable cfgCentMultEstimator{"centmultestimator", "V0M", "Centrality/multiplicity estimator detector: V0M,CL0,CL1,FV0A,FT0M,FT0A,FT0C,NTPV,NOCM: none. Default V0M"}; - Configurable cfgSystem{"syst", "PbPb", "System: pp, PbPb, Pbp, pPb, XeXe, ppRun3, PbPbRun3. Default PbPb"}; - Configurable cfgDataType{"datatype", "data", "Data type: data, datanoevsel, MC, FastMC, OnTheFlyMC. Default data"}; - Configurable cfgTriggSel{"triggsel", "MB", "Trigger selection: MB, None. Default MB"}; - Configurable cfgBinning{"binning", + Configurable cfgFullDerivedData{"cfgFullDerivedData", false, "Produce the full derived data for external storage. Default false"}; + Configurable cfgCentMultEstimator{"cfgCentMultEstimator", "V0M", "Centrality/multiplicity estimator detector: V0M,CL0,CL1,FV0A,FT0M,FT0A,FT0C,NTPV,NOCM: none. Default V0M"}; + Configurable cfgSystem{"cfgSystem", "PbPb", "System: pp, PbPb, Pbp, pPb, XeXe, ppRun3, PbPbRun3. Default PbPb"}; + Configurable cfgDataType{"cfgDataType", "data", "Data type: data, datanoevsel, MC, FastMC, OnTheFlyMC. Default data"}; + Configurable cfgTriggSel{"cfgTriggSel", "MB", "Trigger selection: MB, None. Default MB"}; + Configurable cfgBinning{"cfgBinning", {28, -7.0, 7.0, 18, 0.2, 2.0, 16, -0.8, 0.8, 72, 0.5}, "triplets - nbins, min, max - for z_vtx, pT, eta and phi, binning plus bin fraction of phi origin shift"}; - Configurable cfgTraceCollId0{"tracecollid0", false, "Trace particles in collisions id 0. Default false"}; + Configurable cfgTraceCollId0{"cfgTraceCollId0", false, "Trace particles in collisions id 0. Default false"}; OutputObj fOutput{"IdentifiedBfFilterCollisionsInfo", OutputObjHandlingPolicy::AnalysisObject}; @@ -269,6 +349,15 @@ struct IdentifiedBfFilter { void processWithoutCentPID(aod::CollisionEvSel const& collision, IdBfFullTracksPID const& ftracks); PROCESS_SWITCH(IdentifiedBfFilter, processWithoutCentPID, "Process PID reco without centrality", false); + void processWithCentFullPID(aod::CollisionEvSelCent const& collision, IdBfFullTracksFullPID const& ftracks); + PROCESS_SWITCH(IdentifiedBfFilter, processWithCentFullPID, "Process Full PID reco with centrality", false); + + void processWithRun2CentFullPID(aod::CollisionEvSelRun2Cent const& collision, IdBfFullTracksFullPID const& ftracks); + PROCESS_SWITCH(IdentifiedBfFilter, processWithRun2CentFullPID, "Process Full PID reco with centrality", false); + + void processWithoutCentFullPID(aod::CollisionEvSel const& collision, IdBfFullTracksFullPID const& ftracks); + PROCESS_SWITCH(IdentifiedBfFilter, processWithoutCentFullPID, "Process Full PID reco without centrality", false); + void processWithCentDetectorLevel(aod::CollisionEvSelCent const& collision, IdBfFullTracksDetLevel const& ftracks, aod::McParticles const&); PROCESS_SWITCH(IdentifiedBfFilter, processWithCentDetectorLevel, "Process MC detector level with centrality", false); @@ -287,6 +376,15 @@ struct IdentifiedBfFilter { void processWithoutCentPIDDetectorLevel(aod::CollisionEvSel const& collision, IdBfFullTracksPIDDetLevel const& ftracks, aod::McParticles const&); PROCESS_SWITCH(IdentifiedBfFilter, processWithoutCentPIDDetectorLevel, "Process PID MC detector level without centrality", false); + void processWithCentFullPIDDetectorLevel(aod::CollisionEvSelCent const& collision, IdBfFullTracksFullPIDDetLevel const& ftracks, aod::McParticles const&); + PROCESS_SWITCH(IdentifiedBfFilter, processWithCentFullPIDDetectorLevel, "Process Full PID MC detector level with centrality", false); + + void processWithRun2CentFullPIDDetectorLevel(aod::CollisionEvSelRun2Cent const& collision, IdBfFullTracksFullPIDDetLevel const& ftracks, aod::McParticles const&); + PROCESS_SWITCH(IdentifiedBfFilter, processWithRun2CentFullPIDDetectorLevel, "Process Full PID MC detector level with centrality", false); + + void processWithoutCentFullPIDDetectorLevel(aod::CollisionEvSel const& collision, IdBfFullTracksFullPIDDetLevel const& ftracks, aod::McParticles const&); + PROCESS_SWITCH(IdentifiedBfFilter, processWithoutCentFullPIDDetectorLevel, "Process Full PID MC detector level without centrality", false); + template void processGenerated(CollisionObject const& mccollision, ParticlesList const& mcparticles, float centormult); @@ -333,7 +431,7 @@ void IdentifiedBfFilter::processReconstructed(CollisionObject const& collision, fhVertexZB->Fill(collision.posZ()); uint8_t acceptedevent = uint8_t(false); float centormult = tentativecentmult; - if (IsEvtSelected(collision, centormult)) { + if (isEvtSelected(collision, centormult)) { acceptedevent = true; fhCentMultA->Fill(centormult); fhMultA->Fill(mult); @@ -381,6 +479,21 @@ void IdentifiedBfFilter::processWithoutCentPID(aod::CollisionEvSel const& collis processReconstructed(collision, ftracks, 50.0); } +void IdentifiedBfFilter::processWithCentFullPID(aod::CollisionEvSelCent const& collision, IdBfFullTracksFullPID const& ftracks) +{ + processReconstructed(collision, ftracks, getCentMultPercentile(collision)); +} + +void IdentifiedBfFilter::processWithRun2CentFullPID(aod::CollisionEvSelRun2Cent const& collision, IdBfFullTracksFullPID const& ftracks) +{ + processReconstructed(collision, ftracks, getCentMultPercentile(collision)); +} + +void IdentifiedBfFilter::processWithoutCentFullPID(aod::CollisionEvSel const& collision, IdBfFullTracksFullPID const& ftracks) +{ + processReconstructed(collision, ftracks, 50.0); +} + void IdentifiedBfFilter::processWithCentDetectorLevel(aod::CollisionEvSelCent const& collision, IdBfFullTracksDetLevel const& ftracks, aod::McParticles const&) { processReconstructed(collision, ftracks, getCentMultPercentile(collision)); @@ -411,13 +524,28 @@ void IdentifiedBfFilter::processWithoutCentPIDDetectorLevel(aod::CollisionEvSel processReconstructed(collision, ftracks, 50.0); } +void IdentifiedBfFilter::processWithCentFullPIDDetectorLevel(aod::CollisionEvSelCent const& collision, IdBfFullTracksFullPIDDetLevel const& ftracks, aod::McParticles const&) +{ + processReconstructed(collision, ftracks, getCentMultPercentile(collision)); +} + +void IdentifiedBfFilter::processWithRun2CentFullPIDDetectorLevel(aod::CollisionEvSelRun2Cent const& collision, IdBfFullTracksFullPIDDetLevel const& ftracks, aod::McParticles const&) +{ + processReconstructed(collision, ftracks, getCentMultPercentile(collision)); +} + +void IdentifiedBfFilter::processWithoutCentFullPIDDetectorLevel(aod::CollisionEvSel const& collision, IdBfFullTracksFullPIDDetLevel const& ftracks, aod::McParticles const&) +{ + processReconstructed(collision, ftracks, 50.0); +} + template void IdentifiedBfFilter::processGenerated(CollisionObject const& mccollision, ParticlesList const&, float centormult) { using namespace identifiedbffilter; uint8_t acceptedevent = uint8_t(false); - if (IsEvtSelected(mccollision, centormult)) { + if (isEvtSelected(mccollision, centormult)) { acceptedevent = uint8_t(true); } if (fullDerivedData) { @@ -443,12 +571,12 @@ void IdentifiedBfFilter::processGeneratorLevel(aod::McCollision const& mccollisi } bool processed = false; - for (auto& tmpcollision : collisions) { + for (const auto& tmpcollision : collisions) { if (tmpcollision.has_mcCollision()) { if (tmpcollision.mcCollisionId() == mccollision.globalIndex()) { typename AllCollisions::iterator const& collision = allcollisions.iteratorAt(tmpcollision.globalIndex()); - if (IsEvtSelected(collision, defaultcent)) { - fhTrueVertexZAA->Fill((mccollision.posZ())); + if (isEvtSelected(collision, defaultcent)) { + fhTrueVertexZAA->Fill(mccollision.posZ()); processGenerated(mccollision, mcparticles, defaultcent); processed = true; break; /* TODO: only processing the first reconstructed accepted collision */ @@ -491,7 +619,7 @@ void IdentifiedBfFilter::processVertexGenerated(aod::McCollisions const& mccolli fhTrueVertexZB->Fill(mccollision.posZ()); /* we assign a default value */ float centmult = 50.0f; - if (IsEvtSelected(mccollision, centmult)) { + if (isEvtSelected(mccollision, centmult)) { fhTrueVertexZA->Fill((mccollision.posZ())); } } @@ -507,29 +635,72 @@ T computeRMS(std::vector& vec) std::vector diff(vec.size()); std::transform(vec.begin(), vec.end(), diff.begin(), [mean](T x) { return x - mean; }); - T sq_sum = std::inner_product(diff.begin(), diff.end(), diff.begin(), 0.0); - T stdev = std::sqrt(sq_sum / vec.size()); + T sqSum = std::inner_product(diff.begin(), diff.end(), diff.begin(), 0.0); + T stdev = std::sqrt(sqSum / vec.size()); return stdev; } struct IdentifiedBfFilterTracks { + + struct : ConfigurableGroup { + Configurable inputCCDBUrl{"inputCCDBUrl", "http://ccdb-test.cern.ch:8080", "The CCDB url for the input file"}; + Configurable inputCCDBPathName{"inputCCDBPathName", "", "The CCDB path for the input file. Default \"\", i.e. don't load from CCDB"}; + Configurable inputCCDBDate{"inputCCDBDate", "20220307", "The CCDB date for the input file"}; + } cfgcentersinputfile; + Service ccdb; + + TList* getCCDBInput(const char* ccdbpath, const char* ccdbdate) + { + + std::tm cfgtm = {}; + std::stringstream ss(ccdbdate); + ss >> std::get_time(&cfgtm, "%Y%m%d"); + cfgtm.tm_hour = 12; + int64_t timestamp = std::mktime(&cfgtm) * 1000; + + TList* lst = ccdb->getForTimeStamp(ccdbpath, timestamp); + if (lst != nullptr) { + LOGF(info, "Correctly loaded CCDB input object"); + } else { + LOGF(error, "CCDB input object could not be loaded"); + } + return lst; + } + + Service fPDG; Produces scannedtracks; Produces tracksinfo; Produces scannedgentracks; Produces gentracksinfo; - Configurable cfgFullDerivedData{"fullderiveddata", false, "Produce the full derived data for external storage. Default false"}; - Configurable cfgTrackType{"trktype", 1, "Type of selected tracks: 0 = no selection, 1 = Run2 global tracks FB96, 3 = Run3 tracks, 5 = Run2 TPC only tracks, 7 = Run 3 TPC only tracks. Default 1"}; - Configurable cfgSystem{"syst", "PbPb", "System: pp, PbPb, Pbp, pPb, XeXe, ppRun3, PbPbRun3. Default PbPb"}; - Configurable cfgDataType{"datatype", "data", "Data type: data, datanoevsel, MC, FastMC, OnTheFlyMC. Default data"}; - Configurable cfgBinning{"binning", + Configurable cfgFullDerivedData{"cfgFullDerivedData", false, "Produce the full derived data for external storage. Default false"}; + Configurable cfgTrackType{"cfgTrackType", 1, "Type of selected tracks: 0 = no selection, 1 = Run2 global tracks FB96, 3 = Run3 tracks, 5 = Run2 TPC only tracks, 7 = Run 3 TPC only tracks. Default 1"}; + Configurable cfgSystem{"cfgSystem", "PbPb", "System: pp, PbPb, Pbp, pPb, XeXe, ppRun3, PbPbRun3. Default PbPb"}; + Configurable cfgDataType{"cfgDataType", "data", "Data type: data, datanoevsel, MC, FastMC, OnTheFlyMC. Default data"}; + Configurable cfgBinning{"cfgBinning", {28, -7.0, 7.0, 18, 0.2, 2.0, 16, -0.8, 0.8, 72, 0.5}, "triplets - nbins, min, max - for z_vtx, pT, eta and phi, binning plus bin fraction of phi origin shift"}; - Configurable cfgTraceDCAOutliers{"trackdcaoutliers", {false, 0.0, 0.0}, "Track the generator level DCAxy outliers: false/true, low dcaxy, up dcaxy. Default {false,0.0,0.0}"}; - Configurable cfgTraceOutOfSpeciesParticles{"trackoutparticles", false, "Track the particles which are not e,mu,pi,K,p: false/true. Default false"}; - Configurable cfgRecoIdMethod{"recoidmethod", 0, "Method for identifying reconstructed tracks: 0 No PID, 1 PID, 2 mcparticle. Default 0"}; - Configurable cfgTrackSelection{"tracksel", {false, false, 0, 70, 0.8, 2.4, 3.2}, "Track selection: {useit: true/false, ongen: true/false, tpccls, tpcxrws, tpcxrfc, dcaxy, dcaz}. Default {false,0.70.0.8,2.4,3.2}"}; + Configurable cfgTraceDCAOutliers{"cfgTraceDCAOutliers", {false, 0.0, 0.0}, "Track the generator level DCAxy outliers: false/true, low dcaxy, up dcaxy. Default {false,0.0,0.0}"}; + Configurable cfgTraceOutOfSpeciesParticles{"cfgTraceOutOfSpeciesParticles", false, "Track the particles which are not e,mu,pi,K,p: false/true. Default false"}; + Configurable cfgRecoIdMethod{"cfgRecoIdMethod", 0, "Method for identifying reconstructed tracks: 0 No PID, 1 PID, 2 mcparticle. Default 0"}; + Configurable cfgTrackSelection{"cfgTrackSelection", {false, false, 0, 70, 0.8, 2.4, 3.2}, "Track selection: {useit: true/false, ongen: true/false, tpccls, tpcxrws, tpcxrfc, dcaxy, dcaz}. Default {false,0.70.0.8,2.4,3.2}"}; + Configurable reqTOF{"reqTOF", false, "Require TOF data for PID. Default false"}; + Configurable onlyTOF{"onlyTOF", false, "Only use TOF data for PID. Default false"}; + + Configurable pidEl{"pidEl", -1, "Identify Electron Tracks"}; + Configurable pidPi{"pidPi", -1, "Identify Pion Tracks"}; + Configurable pidKa{"pidKa", -1, "Identify Kaon Tracks"}; + Configurable pidPr{"pidPr", -1, "Identify Proton Tracks"}; + + Configurable minPIDSigma{"minPIDSigma", -3.0, "Minimum required sigma for PID Acceptance"}; + Configurable maxPIDSigma{"maxPIDSigma", 3.0, "Maximum required sigma for PID Acceptance"}; + + Configurable minRejectSigma{"minRejectSigma", -1.0, "Minimum required sigma for PID double match rejection"}; + Configurable maxRejectSigma{"maxRejectSigma", 1.0, "Maximum required sigma for PID double match rejection"}; + + Configurable tofCut{"tofCut", 0.8, "Momentum under which we don't use TOF PID data"}; + Configurable makeNSigmaPlots{"makeNSigmaPlots", false, "Produce the N Sigma Plots for external storage. Default false"}; OutputObj fOutput{"IdentifiedBfFilterTracksInfo", OutputObjHandlingPolicy::AnalysisObject}; bool checkAmbiguousTracks = false; @@ -538,6 +709,26 @@ struct IdentifiedBfFilterTracks { { LOGF(info, "IdentifiedBfFilterTracks::init()"); + // ccdb info + ccdb->setURL(cfgcentersinputfile.inputCCDBUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + LOGF(info, "Initizalized CCDB"); + + loadfromccdb = cfgcentersinputfile.inputCCDBPathName->length() > 0; + + if (ccdblst == nullptr) { + if (loadfromccdb) { + LOGF(info, "Loading CCDB Objects"); + + ccdblst = getCCDBInput(cfgcentersinputfile.inputCCDBPathName->c_str(), cfgcentersinputfile.inputCCDBDate->c_str()); + for (int i = 0; i < kIdBfNoOfSpecies; i++) { + fhNSigmaCorrection[i] = reinterpret_cast(ccdblst->FindObject(Form("centerBin_%s", speciesName[i]))); + } + } + } + LOGF(info, "Loaded CCDB Objects"); + fullDerivedData = cfgFullDerivedData; /* update with the configurable values */ @@ -590,7 +781,6 @@ struct IdentifiedBfFilterTracks { /* if the system type is not known at this time, we have to put the initialization somewhere else */ fSystem = getSystemType(cfgSystem); fDataType = getDataType(cfgDataType); - fPDG = TDatabasePDG::Instance(); /* required ambiguous tracks checks? */ if (dofilterDetectorLevelWithoutPIDAmbiguous || dofilterDetectorLevelWithPIDAmbiguous || dofilterRecoWithoutPIDAmbiguous || dofilterRecoWithPIDAmbiguous) { @@ -603,12 +793,16 @@ struct IdentifiedBfFilterTracks { fOutput.setObject(fOutputList); /* incorporate configuration parameters to the output */ - fOutputList->Add(new TParameter("TrackType", cfgTrackType, 'f')); - fOutputList->Add(new TParameter("TrackOneCharge", 1, 'f')); - fOutputList->Add(new TParameter("TrackTwoCharge", -1, 'f')); + fOutputList->Add(new TParameter("TrackType", cfgTrackType, 'f')); + fOutputList->Add(new TParameter("TrackOneCharge", 1, 'f')); + fOutputList->Add(new TParameter("TrackTwoCharge", -1, 'f')); if ((fDataType == kData) || (fDataType == kDataNoEvtSel) || (fDataType == kMC)) { /* create the reconstructed data histograms */ + fhXYB = new TH2F("fHistXYB", "x and y distribution for reconstructed before", 1000, -10.0, 10.0, 1000, -10.0, 10.0); + fhYZB = new TH2F("fHistYZB", "y and z distribution for reconstructed before", 1000, -10.0, 10.0, 1000, -10.0, 10.0); + fhXYA = new TH2F("fHistXYA", "x and y distribution for reconstructed after", 1000, -10.0, 10.0, 1000, -10.0, 10.0); + fhYZA = new TH2F("fHistYZA", "y and z distribution for reconstructed after", 1000, -10.0, 10.0, 1000, -10.0, 10.0); fhPB = new TH1F("fHistPB", "p distribution for reconstructed before;p (GeV/c);dN/dp (c/GeV)", 100, 0.0, 15.0); fhPtB = new TH1F("fHistPtB", "p_{T} distribution for reconstructed before;p_{T} (GeV/c);dN/dP_{T} (c/GeV)", 100, 0.0, 15.0); fhPtPosB = new TH1F("fHistPtPosB", "P_{T} distribution for reconstructed (#plus) before;P_{T} (GeV/c);dN/dP_{T} (c/GeV)", 100, 0.0, 15.0); @@ -616,15 +810,33 @@ struct IdentifiedBfFilterTracks { fhEtaB = new TH1F("fHistEtaB", "#eta distribution for reconstructed before;#eta;counts", 40, -2.0, 2.0); fhEtaA = new TH1F("fHistEtaA", "#eta distribution for reconstructed;#eta;counts", etabins, etalow, etaup); fhPhiB = new TH1F("fHistPhiB", "#phi distribution for reconstructed before;#phi;counts", 360, 0.0, constants::math::TwoPI); - fhdEdxB = new TH2F("fHistdEdxB", "dE/dx vs P before; dE/dx (a.u.); P (GeV/c)", 1000, 0.0, 1000.0, 100, 0.0, 15.0); + fhdEdxB = new TH2F("fHistdEdxB", "dE/dx vs P before; P (GeV/c); dE/dx (a.u.)", ptbins, ptlow, ptup, 1000, 0.0, 1000.0); + fhdEdxIPTPCB = new TH2F("fHistdEdxIPTPCB", "dE/dx vs P_{IP} before; P (GeV/c); dE/dx (a.u.)", ptbins, ptlow, ptup, 1000, 0.0, 1000.0); fhPhiA = new TH1F("fHistPhiA", "#phi distribution for reconstructed;#phi;counts", 360, 0.0, constants::math::TwoPI); fhDCAxyB = new TH1F("DCAxyB", "DCA_{xy} distribution for reconstructed before;DCA_{xy} (cm);counts", 1000, -4.0, 4.0); fhDCAxyA = new TH1F("DCAxyA", "DCA_{xy} distribution for reconstructed;DCA_{xy} (cm);counts", 1000, -4., 4.0); + fhDCAxyzB = new TH2F("DCAxyzB", "DCA_{xy} vs DCA_{z} distribution for reconstructed before;DCA_{xy} (cm); DCA_{z} (cm);counts", 1000, -4.0, 4.0, 1000, -4.0, 4.0); fhFineDCAxyA = new TH1F("FineDCAxyA", "DCA_{xy} distribution for reconstructed;DCA_{xy} (cm);counts", 4000, -1.0, 1.0); fhDCAzB = new TH1F("DCAzB", "DCA_{z} distribution for reconstructed before;DCA_{z} (cm);counts", 1000, -4.0, 4.0); fhDCAzA = new TH1F("DCAzA", "DCA_{z} distribution for reconstructed;DCA_{z} (cm);counts", 1000, -4.0, 4.0); fhFineDCAzA = new TH1F("FineDCAzA", "DCA_{z} distribution for reconstructed;DCA_{z} (cm);counts", 4000, -1.0, 1.0); + fhDCAxyzA = new TH2F("DCAxyzA", "DCA_{xy} vs DCA_{z} distribution for reconstructed;DCA_{xy} (cm); DCA_{z} (cm);counts", 1000, -4.0, 4.0, 1000, -4.0, 4.0); + + fhNClustersB = new TH1I("fHistNClB", "TPC NClusters distribution for reconstructed before;counts", 201, 0, 200); + fhPhiYB = new TH2F("fHistPhiYB", "#phi vs #eta distribution for reconstructed before;#phi;#eta;counts", 360, 0.0, constants::math::TwoPI, 40, -2.0, 2.0); + fhPtYB = new TH2F("fHistPtYB", "p_{T} vs #eta distribution for reconstructed before;p_{T} (GeV/c);#eta;counts", 100, 0.0, 15.0, 40, -2.0, 2.0); + fhChi2B = new TH1F("fHistChi2B", "#chi^{2}/Ncl TPC distribution for reconstructed before;", 100, 0.0, 20.0); + fhITSNclB = new TH1I("fHistITSNClB", "ITS NClusters distribution for reconstructed before;counts", 21, 0, 20); + + fhNClustersA = new TH1I("fHistNClA", "TPC NClusters distribution for reconstructed after;counts", 201, 0, 200); + fhPhiYA = new TH2F("fHistPhiYA", "#phi vs #eta distribution for reconstructed after;#phi;#eta;counts", 360, 0.0, constants::math::TwoPI, 40, -2.0, 2.0); + fhPtYA = new TH2F("fHistPtYA", "p_{T} vs #eta distribution for reconstructed after;p_{T} (GeV/c);#eta;counts", 100, 0.0, 15.0, 40, -2.0, 2.0); + fhChi2A = new TH1F("fHistChi2A", "#chi^{2}/Ncl TPC distribution for reconstructed after;", 100, 0.0, 20.0); + fhITSNclA = new TH1I("fHistITSNClA", "ITS NClusters distribution for reconstructed after;counts", 21, 0, 20); + fhDoublePID = new TH2S("DoublePID", "PIDs for double match;Original Species;Secondary Species", kIdBfNoOfSpecies, 0, kIdBfNoOfSpecies, kIdBfNoOfSpecies, 0, kIdBfNoOfSpecies); + + fhWrongTrackID = new TH1F("WrongTrackId", "Wrong Tracks From Double Track Id distribution in p", ptbins, ptlow, ptup); if (checkAmbiguousTracks) { /* let's allocate the ambigous tracks tracking histograms*/ fhAmbiguousTrackType = new TH2D("fHistAmbiguousTracksType", "Ambiguous tracks type vs. multiplicity class;Ambiguous track type;Multiplicity (%);counts", 4, -0.5, 3.5, 101, -0.5, 100.5); @@ -634,6 +846,25 @@ struct IdentifiedBfFilterTracks { } for (int sp = 0; sp < kIdBfNoOfSpecies; ++sp) { + fhNSigmaTPC[sp] = new TH2F(TString::Format("fhNSigmaTPC_%s", speciesName[sp]).Data(), + TString::Format("N Sigma from TPC vs P for %s;N #sigma;p (GeV/c)", speciesTitle[sp]).Data(), + 48, -6, 6, + ptbins, ptlow, ptup); + fhNSigmaTOF[sp] = new TH2F(TString::Format("fhNSigmaTOF_%s", speciesName[sp]).Data(), + TString::Format("N Sigma from TOF vs P for %s;N #sigma;p (GeV/c)", speciesTitle[sp]).Data(), + 48, -6, 6, + ptbins, ptlow, ptup); + fhNSigmaCombo[sp] = new TH2F(TString::Format("fhNSigmaCombo_%s", speciesName[sp]).Data(), + TString::Format("N Sigma from Combo vs P for %s;N #sigma;p (GeV/c)", speciesTitle[sp]).Data(), + 48, -6, 6, + ptbins, ptlow, ptup); + fhNSigmaTPCIdTrks[sp] = new TH2F(TString::Format("fhNSigmaTPC_IdTrks_%s", speciesName[sp]).Data(), + TString::Format("N Sigma from TPC vs P for Identified %s;N #sigma;p (GeV/c)", speciesTitle[sp]).Data(), + 48, -6, 6, + ptbins, ptlow, ptup); + } + + for (int sp = 0; sp < kIdBfNoOfSpecies + 1; ++sp) { fhPA[sp] = new TH1F(TString::Format("fHistPA_%s", speciesName[sp]).Data(), TString::Format("p distribution for reconstructed %s;p (GeV/c);dN/dp (c/GeV)", speciesTitle[sp]).Data(), ptbins, ptlow, ptup); @@ -646,6 +877,14 @@ struct IdentifiedBfFilterTracks { fhPtNegA[sp] = new TH1F(TString::Format("fHistPtNegA_%s", speciesName[sp]), TString::Format("P_{T} distribution for reconstructed %s^{#minus};P_{T} (GeV/c);dN/dP_{T} (c/GeV)", speciesTitle[sp]).Data(), ptbins, ptlow, ptup); + fhPtEtaPosA[sp] = new TH2F(TString::Format("fHistPtEtaPosA_%s", speciesName[sp]), + TString::Format("P_{T} vs #eta distribution for reconstructed %s^{#plus};P_{T} (GeV/c);#eta;dN/dP_{T} (c/GeV)", speciesTitle[sp]).Data(), + ptbins, ptlow, ptup, + etabins, etalow, etaup); + fhPtEtaNegA[sp] = new TH2F(TString::Format("fHistPtEtaNegA_%s", speciesName[sp]), + TString::Format("P_{T} vs #eta distribution for reconstructed %s^{#minus};P_{T} (GeV/c);#eta;dN/dP_{T} (c/GeV)", speciesTitle[sp]).Data(), + ptbins, ptlow, ptup, + etabins, etalow, etaup); fhNPosNegA[sp] = new TH2F(TString::Format("fhNPosNegA_%s", speciesName[sp]).Data(), TString::Format("N(%s^{#plus}) N(%s^{#minus}) distribution for reconstructed;N(%s^{#plus});N(%s^{#minus})", speciesTitle[sp], speciesTitle[sp], speciesTitle[sp], speciesTitle[sp]).Data(), 40, -0.5, 39.5, 40, -0.5, 39.5); @@ -653,11 +892,46 @@ struct IdentifiedBfFilterTracks { TString::Format("N(%s^{#plus}) #minus N(%s^{#minus}) distribution for reconstructed;N(%s^{#plus}) #minus N(%s^{#minus})", speciesTitle[sp], speciesTitle[sp], speciesTitle[sp], speciesTitle[sp]).Data(), 79, -39.5, 39.5); fhdEdxA[sp] = new TH2F(TString::Format("fhdEdxA_%s", speciesName[sp]).Data(), - TString::Format("dE/dx vs P reconstructed %s; dE/dx (a.u.); P (GeV/c)", speciesTitle[sp]).Data(), - 1000, 0.0, 1000.0, ptbins, ptlow, ptup); + TString::Format("dE/dx vs P reconstructed %s; P (GeV/c); dE/dx (a.u.)", speciesTitle[sp]).Data(), + ptbins, ptlow, ptup, 1000, 0.0, 1000.0); + fhdEdxIPTPCA[sp] = new TH2F(TString::Format("fhdEdxIPTPCA_%s", speciesName[sp]).Data(), + TString::Format("dE/dx vs P_{IP} reconstructed %s; P (GeV/c); dE/dx (a.u.)", speciesTitle[sp]).Data(), + ptbins, ptlow, ptup, 1000, 0.0, 1000.0); + fhTrackTimeA[sp] = new TH2F(TString::Format("fhTrackTimeA_%s", speciesName[sp]).Data(), + TString::Format("Track Time vs P_{IP} reconstructed %s; P (GeV/c); Track Time(ns)", speciesTitle[sp]).Data(), + ptbins, ptlow, ptup, 1000, 0.0, 10.0); + fhTrackBetaA[sp] = new TH2F(TString::Format("fhTrackBetaA_%s", speciesName[sp]).Data(), + TString::Format("1/#Beta vs P_{IP} reconstructed %s; P (GeV/c); 1/#Beta(ns/m)", speciesTitle[sp]).Data(), + ptbins, ptlow, ptup, 1000, 0.0, 10.0); } + fhdEdxA[kIdBfNoOfSpecies + 1] = new TH2F(TString::Format("fhdEdxA_WrongSpecies").Data(), + TString::Format("dE/dx vs P reconstructed Wrong Species; P (GeV/c); dE/dx (a.u.)").Data(), + ptbins, ptlow, ptup, 1000, 0.0, 1000.0); + fhdEdxIPTPCA[kIdBfNoOfSpecies + 1] = new TH2F(TString::Format("fhdEdxIPTPCA_WrongSpecies").Data(), + TString::Format("dE/dx vs P_{IP} reconstructed Wrong Species; P (GeV/c); dE/dx (a.u.)").Data(), + ptbins, ptlow, ptup, 1000, 0.0, 1000.0); + fhTrackTimeA[kIdBfNoOfSpecies + 1] = new TH2F(TString::Format("fhTrackTimeA_WrongSpecies").Data(), + TString::Format("Track Time vs P_{IP} reconstructed Wrong Species; P (GeV/c); Track Time(ns)").Data(), + ptbins, ptlow, ptup, 1000, 0.0, 10.0); + fhTrackBetaA[kIdBfNoOfSpecies + 1] = new TH2F(TString::Format("fhTrackBetaA_WrongSpecies").Data(), + TString::Format("1/#Beta vs P_{IP} reconstructed Wrong Species; P (GeV/c); 1/#Beta(ns/m)").Data(), + ptbins, ptlow, ptup, 1000, 0.0, 10.0); /* add the hstograms to the output list */ + fOutputList->Add(fhXYB); + fOutputList->Add(fhYZB); + fOutputList->Add(fhXYA); + fOutputList->Add(fhYZA); + fOutputList->Add(fhNClustersB); + fOutputList->Add(fhNClustersA); + fOutputList->Add(fhPhiYB); + fOutputList->Add(fhPhiYA); + fOutputList->Add(fhPtYB); + fOutputList->Add(fhPtYA); + fOutputList->Add(fhChi2B); + fOutputList->Add(fhChi2A); + fOutputList->Add(fhITSNclB); + fOutputList->Add(fhITSNclA); fOutputList->Add(fhPB); fOutputList->Add(fhPtB); fOutputList->Add(fhPtPosB); @@ -667,12 +941,18 @@ struct IdentifiedBfFilterTracks { fOutputList->Add(fhPhiB); fOutputList->Add(fhPhiA); fOutputList->Add(fhdEdxB); + fOutputList->Add(fhdEdxIPTPCB); fOutputList->Add(fhDCAxyB); fOutputList->Add(fhDCAxyA); + fOutputList->Add(fhDCAxyzB); + fOutputList->Add(fhDCAxyzA); + fOutputList->Add(fhWrongTrackID); + fOutputList->Add(fhDoublePID); fOutputList->Add(fhFineDCAxyA); fOutputList->Add(fhDCAzB); fOutputList->Add(fhDCAzA); fOutputList->Add(fhFineDCAzA); + if (checkAmbiguousTracks) { fOutputList->Add(fhAmbiguousTrackType); fOutputList->Add(fhAmbiguousTrackPt); @@ -681,19 +961,47 @@ struct IdentifiedBfFilterTracks { } for (int sp = 0; sp < kIdBfNoOfSpecies; ++sp) { + fOutputList->Add(fhNSigmaTPC[sp]); + fOutputList->Add(fhNSigmaTOF[sp]); + fOutputList->Add(fhNSigmaCombo[sp]); + fOutputList->Add(fhNSigmaTPCIdTrks[sp]); + } + + for (int sp = 0; sp < kIdBfNoOfSpecies + 1; ++sp) { fOutputList->Add(fhPA[sp]); fOutputList->Add(fhPtA[sp]); fOutputList->Add(fhPtPosA[sp]); fOutputList->Add(fhPtNegA[sp]); + fOutputList->Add(fhPtEtaPosA[sp]); + fOutputList->Add(fhPtEtaNegA[sp]); fOutputList->Add(fhNPosNegA[sp]); fOutputList->Add(fhDeltaNA[sp]); fOutputList->Add(fhdEdxA[sp]); + fOutputList->Add(fhdEdxIPTPCA[sp]); + fOutputList->Add(fhTrackTimeA[sp]); + fOutputList->Add(fhTrackBetaA[sp]); } + fOutputList->Add(fhdEdxA[kIdBfNoOfSpecies + 1]); + fOutputList->Add(fhdEdxIPTPCA[kIdBfNoOfSpecies + 1]); + fOutputList->Add(fhTrackTimeA[kIdBfNoOfSpecies + 1]); + fOutputList->Add(fhTrackBetaA[kIdBfNoOfSpecies + 1]); } if ((fDataType != kData) && (fDataType != kDataNoEvtSel)) { /* create the true data histograms */ + + fhTruePIDMismatch = new TH2S("fHistTruePIDMismatch", "Mismatched Generated and Reconstructed PID;Generated Species;Reconstructed Species", kIdBfNoOfSpecies, 0, kIdBfNoOfSpecies, kIdBfNoOfSpecies, 0, kIdBfNoOfSpecies); + fhTruePIDCorrect = new TH1S("fHistTruePIDCorrect", "Correct PID between Generated and Reconstructed PID;Species", kIdBfNoOfSpecies, 0, kIdBfNoOfSpecies); + fhTruePB = new TH1F("fTrueHistPB", "p distribution before (truth);p (GeV/c);dN/dp (c/GeV)", 100, 0.0, 15.0); + fhTrueCharge = new TH1F("fTrueHistCharge", "Charge distribution before (truth);charge;count", 3, -1.0, 1.0); + + fhTruePhiYB = new TH2F("fTrueHistPhiYB", "#phi vs #eta distribution before (truth);#phi;#eta;counts", 360, 0.0, constants::math::TwoPI, 40, -2.0, 2.0); + fhTruePtYB = new TH2F("fTrueHistPtYB", "p_{T} vs #eta distribution before (truth);p_{T} (GeV/c);#eta;counts", 100, 0.0, 15.0, 40, -2.0, 2.0); + + fhTruePhiYA = new TH2F("fTrueHistPhiYA", "#phi vs #eta distribution after (truth);#phi;#eta;counts", 360, 0.0, constants::math::TwoPI, 40, -2.0, 2.0); + fhTruePtYA = new TH2F("fTrueHistPtYA", "p_{T} vs #eta distribution after (truth);p_{T} (GeV/c);#eta;counts", 100, 0.0, 15.0, 40, -2.0, 2.0); + fhTruePtB = new TH1F("fTrueHistPtB", "p_{T} distribution before (truth);p_{T} (GeV/c);dN/dP_{T} (c/GeV)", 100, 0.0, 15.0); fhTruePtPosB = new TH1F("fTrueHistPtPosB", "P_{T} distribution (#plus) before (truth);P_{T} (GeV/c);dN/dP_{T} (c/GeV)", 100, 0.0, 15.0); fhTruePtNegB = new TH1F("fTrueHistPtNegB", "P_{T} distribution (#minus) before (truth);P_{T} (GeV/c);dN/dP_{T} (c/GeV)", 100, 0.0, 15.0); @@ -710,8 +1018,10 @@ struct IdentifiedBfFilterTracks { fhTrueDCAxyA = new TH1F("TrueDCAxyA", "DCA_{xy} distribution for generated;DCA_{xy};counts (cm)", 1000, -4., 4.0); fhTrueDCAzB = new TH1F("TrueDCAzB", "DCA_{z} distribution for generated before;DCA_{z} (cm);counts", 1000, -4.0, 4.0); fhTrueDCAzA = new TH1F("TrueDCAzA", "DCA_{z} distribution for generated;DCA_{z} (cm);counts", 1000, -4.0, 4.0); + fhTrueDCAxyzB = new TH2F("TrueDCAxyzB", "DCA_{xy} vs DCA_{z} distribution for generated before;DCA_{xy} (cm);DCA_{z} (cm);counts", 1000, -4.0, 4.0, 1000, -4.0, 4.0); + fhTrueDCAxyzA = new TH2F("TrueDCAxyzA", "DCA_{xy} vs DCA_{z} distribution for generated after;DCA_{xy} (cm);DCA_{z} (cm);counts", 1000, -4.0, 4.0, 1000, -4.0, 4.0); - for (int sp = 0; sp < kIdBfNoOfSpecies; ++sp) { + for (int sp = 0; sp < kIdBfNoOfSpecies + 1; ++sp) { fhTruePA[sp] = new TH1F(TString::Format("fTrueHistPA_%s", speciesName[sp]).Data(), TString::Format("p distribution %s (truth);p (GeV/c);dN/dp (c/GeV)", speciesTitle[sp]).Data(), ptbins, ptlow, ptup); @@ -724,6 +1034,14 @@ struct IdentifiedBfFilterTracks { fhTruePtNegA[sp] = new TH1F(TString::Format("fTrueHistPtNegA_%s", speciesName[sp]), TString::Format("P_{T} distribution %s^{#minus} (truth);P_{T} (GeV/c);dN/dP_{T} (c/GeV)", speciesTitle[sp]).Data(), ptbins, ptlow, ptup); + fhTruePtEtaPosA[sp] = new TH2F(TString::Format("fTrueHistPtEtaPosA_%s", speciesName[sp]), + TString::Format("P_{T} vs #eta distribution %s^{#plus} (truth);P_{T} (GeV/c);#eta;dN/dP_{T} (c/GeV)", speciesTitle[sp]).Data(), + ptbins, ptlow, ptup, + etabins, etalow, etaup); + fhTruePtEtaNegA[sp] = new TH2F(TString::Format("fTrueHistPtEtaNegA_%s", speciesName[sp]), + TString::Format("P_{T} vs #eta distribution %s^{#minus} (truth);P_{T} (GeV/c);#eta;dN/dP_{T} (c/GeV)", speciesTitle[sp]).Data(), + ptbins, ptlow, ptup, + etabins, etalow, etaup); fhTrueNPosNegA[sp] = new TH2F(TString::Format("fhTrueNPosNegA_%s", speciesName[sp]).Data(), TString::Format("N(%s^{#plus}) N(%s^{#minus}) distribution (truth);N(%s^{#plus});N(%s^{#minus})", speciesTitle[sp], speciesTitle[sp], speciesTitle[sp], speciesTitle[sp]).Data(), 40, -0.5, 39.5, 40, -0.5, 39.5); @@ -731,12 +1049,34 @@ struct IdentifiedBfFilterTracks { TString::Format("N(%s^{#plus}) #minus N(%s^{#minus}) distribution (truth);N(%s^{#plus}) #minus N(%s^{#minus})", speciesTitle[sp], speciesTitle[sp], speciesTitle[sp], speciesTitle[sp]).Data(), 79, -39.5, 39.5); } + if (makeNSigmaPlots) { + for (int sp1 = 0; sp1 < kIdBfNoOfSpecies; ++sp1) { + for (int sp2 = 0; sp2 < kIdBfNoOfSpecies; ++sp2) { + fhTrueNSigmaTPC[sp1][sp2] = new TH2F(TString::Format("fhTrueNSigmaTPC%s_%s", speciesName[sp1], speciesName[sp2]).Data(), + TString::Format("N #sigma %s from TPC vs P for generated %s;N #sigma;p (GeV/c)", speciesTitle[sp1], speciesTitle[sp2]).Data(), + 48, -6, 6, + ptbins, ptlow, ptup); + + fhTrueNSigmaTOF[sp1][sp2] = new TH2F(TString::Format("fhTrueNSigmaTOF%s_%s", speciesName[sp1], speciesName[sp2]).Data(), + TString::Format("N #sigma %s from TOF vs P for generated %s;N #sigma;p (GeV/c)", speciesTitle[sp1], speciesTitle[sp2]).Data(), + 48, -6, 6, + ptbins, ptlow, ptup); + } + } + } /* add the hstograms to the output list */ + fOutputList->Add(fhTruePIDMismatch); + fOutputList->Add(fhTruePIDCorrect); + fOutputList->Add(fhTruePhiYB); + fOutputList->Add(fhTruePtYB); + fOutputList->Add(fhTruePhiYA); + fOutputList->Add(fhTruePtYA); fOutputList->Add(fhTruePB); fOutputList->Add(fhTruePtB); fOutputList->Add(fhTruePtPosB); fOutputList->Add(fhTruePtNegB); + fOutputList->Add(fhTrueCharge); fOutputList->Add(fhTrueEtaB); fOutputList->Add(fhTrueEtaA); fOutputList->Add(fhTruePhiB); @@ -748,30 +1088,45 @@ struct IdentifiedBfFilterTracks { fOutputList->Add(fhTrueDCAxyA); fOutputList->Add(fhTrueDCAzB); fOutputList->Add(fhTrueDCAzA); + fOutputList->Add(fhTrueDCAxyzB); + fOutputList->Add(fhTrueDCAxyzA); - for (int sp = 0; sp < kIdBfNoOfSpecies; ++sp) { + for (int sp = 0; sp < kIdBfNoOfSpecies + 1; ++sp) { fOutputList->Add(fhTruePA[sp]); fOutputList->Add(fhTruePtA[sp]); fOutputList->Add(fhTruePtPosA[sp]); fOutputList->Add(fhTruePtNegA[sp]); + fOutputList->Add(fhTruePtEtaPosA[sp]); + fOutputList->Add(fhTruePtEtaNegA[sp]); fOutputList->Add(fhTrueNPosNegA[sp]); fOutputList->Add(fhTrueDeltaNA[sp]); } + if (makeNSigmaPlots) { + for (int sp1 = 0; sp1 < kIdBfNoOfSpecies; ++sp1) { + for (int sp2 = 0; sp2 < kIdBfNoOfSpecies; ++sp2) { + fOutputList->Add(fhTrueNSigmaTPC[sp1][sp2]); + fOutputList->Add(fhTrueNSigmaTOF[sp1][sp2]); + } + } + } } + /* initialize access to the CCDB */ } template - inline MatchRecoGenSpecies IdentifyTrack(TrackObject const& track); - template - MatchRecoGenSpecies trackIdentification(TrackObject const& track); + inline MatchRecoGenSpecies identifyTrack(TrackObject const& track); template - int8_t AcceptTrack(TrackObject const& track); - template - int8_t selectTrack(TrackObject const& track); + int8_t acceptTrack(TrackObject const& track); + template + int8_t acceptParticle(ParticleObject& particle, MCCollisionObject const& mccollision); template int8_t selectTrackAmbiguousCheck(CollisionObjects const& collisions, TrackObject const& track); template - inline MatchRecoGenSpecies IdentifyParticle(ParticleObject const& particle); + inline void identifyPIDMismatch(ParticleObject const& particle, MatchRecoGenSpecies const& trkId); + template + inline void identifyRealNSigma(ParticleObject const& particle, std::vector tpcNSigma, std::vector tofNSigma, float tpcInnerParam); + template + inline MatchRecoGenSpecies identifyParticle(ParticleObject const& particle); template void fillTrackHistosBeforeSelection(TrackObject const& track); template @@ -797,17 +1152,24 @@ struct IdentifiedBfFilterTracks { if (!fullDerivedData) { tracksinfo.reserve(tracks.size()); } - for (auto collision : collisions) { + for (const auto& collision : collisions) { if (collision.collisionaccepted()) { ncollaccepted++; } } - for (auto track : tracks) { + for (const auto& track : tracks) { int8_t pid = -1; if (track.has_collision() && (track.template collision_as>()).collisionaccepted()) { pid = selectTrackAmbiguousCheck(collisions, track); if (!(pid < 0)) { naccepted++; + /* update charged multiplicities */ + if (pid % twoDenom == trackTypes[0]) { + trkMultPos[kIdBfCharged]++; + } + if (pid % twoDenom == trackTypes[1]) { + trkMultNeg[kIdBfCharged]++; + } if (fullDerivedData) { LOGF(fatal, "Stored derived data not prepared for saving the proper new collision id"); scannedtracks((track.template collision_as>()).globalIndex(), pid, track.pt(), track.eta(), track.phi()); @@ -841,79 +1203,56 @@ struct IdentifiedBfFilterTracks { void filterParticles(soa::Join const& gencollisions, aod::McParticles const& particles) { using namespace identifiedbffilter; - int acceptedparticles = 0; int acceptedcollisions = 0; if (!fullDerivedData) { gentracksinfo.reserve(particles.size()); } - for (auto gencoll : gencollisions) { + for (const auto& gencoll : gencollisions) { if (gencoll.collisionaccepted()) { acceptedcollisions++; } } - for (auto& particle : particles) { - float charge = 0.0; - TParticlePDG* pdgparticle = fPDG->GetParticle(particle.pdgCode()); - if (pdgparticle != nullptr) { - charge = (pdgparticle->Charge() / 3 >= 1) ? 1.0 : ((pdgparticle->Charge() / 3 <= -1) ? -1.0 : 0.0); - } - + for (const auto& particle : particles) { int8_t pid = -1; - - if (charge != 0) { - if (particle.has_mcCollision() && (particle.template mcCollision_as>()).collisionaccepted()) { - auto mccollision = particle.template mcCollision_as>(); - /* before particle selection */ - fillParticleHistosBeforeSelection(particle, mccollision, charge); - - /* track selection */ - /* TODO: at some point the pid has to be substituted by the identified species */ - pid = AcceptParticle(particle, mccollision); - if (!(pid < 0)) { - /* the particle has been accepted */ - /* let's identify the particle */ - /* TODO: probably this needs to go to AcceptParticle */ - MatchRecoGenSpecies sp = IdentifyParticle(particle); - if (sp != kWrongSpecies) { - if (sp != kIdBfCharged) { - /* fill the charged particle histograms */ - fillParticleHistosAfterSelection(particle, mccollision, charge, kIdBfCharged); - /* update charged multiplicities */ - if (pid % 2 == 0) { - partMultPos[kIdBfCharged]++; - } - if (pid % 2 == 1) { - partMultNeg[kIdBfCharged]++; - } - } - /* fill the species histograms */ - fillParticleHistosAfterSelection(particle, mccollision, charge, sp); - /* update species multiplicities */ - if (pid % 2 == 0) { - partMultPos[sp]++; - } - if (pid % 2 == 1) { - partMultNeg[sp]++; - } + if (particle.isPhysicalPrimary()) { + TParticlePDG* pdgpart = fPDG->GetParticle(particle.pdgCode()); + float charge = 0; + if (pdgpart != nullptr) { + charge = getCharge(pdgpart->Charge()); + // print charge + } + fhTrueCharge->Fill(charge); + if (charge != 0) { + if (particle.has_mcCollision() && (particle.template mcCollision_as>()).collisionaccepted()) { + auto mccollision = particle.template mcCollision_as>(); + /* before particle selection */ + fillParticleHistosBeforeSelection(particle, mccollision, charge); + + /* track selection */ + pid = acceptParticle(particle, mccollision); + if (!(pid < 0)) { // if PID isn't negative acceptedparticles++; - } else { - pid = -1; } } + } else { + if ((particle.mcCollisionId() == 0) && traceCollId0) { + LOGF(IDENTIFIEDBFFILTERLOGTRACKS, "Particle %d with fractional charge or equal to zero", particle.globalIndex()); + } } + } else { if ((particle.mcCollisionId() == 0) && traceCollId0) { - LOGF(IDENTIFIEDBFFILTERLOGTRACKS, "Particle %d with fractional charge or equal to zero", particle.globalIndex()); + LOGF(IDENTIFIEDBFFILTERLOGTRACKS, "Particle %d not Physical Primary", particle.globalIndex()); } } if (!fullDerivedData) { gentracksinfo(pid); } } - LOGF(IDENTIFIEDBFFILTERLOGCOLLISIONS, + LOGF(info, "Processed %d accepted generated collisions out of a total of %d with %d accepted particles out of a " "total of %d", acceptedcollisions, @@ -934,18 +1273,42 @@ struct IdentifiedBfFilterTracks { } PROCESS_SWITCH(IdentifiedBfFilterTracks, filterRecoWithPIDAmbiguous, "Not stored derived data track filtering with ambiguous tracks check", false) - void filterDetectorLevelWithPID(soa::Join& collisions, IdBfFullTracksPIDDetLevel const& tracks) + void filterDetectorLevelWithPID(soa::Join& collisions, IdBfFullTracksPIDDetLevel const& tracks, aod::McParticles const&) { filterTracks(collisions, tracks); } PROCESS_SWITCH(IdentifiedBfFilterTracks, filterDetectorLevelWithPID, "Not stored derived data detector level track filtering", false) - void filterDetectorLevelWithPIDAmbiguous(soa::Join& collisions, IdBfFullTracksPIDDetLevelAmbiguous const& tracks) + void filterDetectorLevelWithPIDAmbiguous(soa::Join& collisions, IdBfFullTracksPIDDetLevelAmbiguous const& tracks, aod::McParticles const&) { filterTracks(collisions, tracks); } PROCESS_SWITCH(IdentifiedBfFilterTracks, filterDetectorLevelWithPIDAmbiguous, "Not stored derived data detector level track filtering with ambiguous tracks check", false) + void filterRecoWithFullPID(soa::Join& collisions, IdBfFullTracksFullPID const& tracks, aod::McParticles const&) + { + filterTracks(collisions, tracks); + } + PROCESS_SWITCH(IdentifiedBfFilterTracks, filterRecoWithFullPID, "Not stored derived data track filtering", false) + + void filterRecoWithFullPIDAmbiguous(soa::Join& collisions, IdBfFullTracksFullPIDAmbiguous const& tracks) + { + filterTracks(collisions, tracks); + } + PROCESS_SWITCH(IdentifiedBfFilterTracks, filterRecoWithFullPIDAmbiguous, "Not stored derived data track filtering with ambiguous tracks check", false) + + void filterDetectorLevelWithFullPID(soa::Join& collisions, IdBfFullTracksFullPIDDetLevel const& tracks, aod::McParticles const&) + { + filterTracks(collisions, tracks); + } + PROCESS_SWITCH(IdentifiedBfFilterTracks, filterDetectorLevelWithFullPID, "Not stored derived data detector level track filtering", false) + + void filterDetectorLevelWithFullPIDAmbiguous(soa::Join& collisions, IdBfFullTracksFullPIDDetLevelAmbiguous const& tracks, aod::McParticles const&) + { + filterTracks(collisions, tracks); + } + PROCESS_SWITCH(IdentifiedBfFilterTracks, filterDetectorLevelWithFullPIDAmbiguous, "Not stored derived data detector level track filtering with ambiguous tracks check", false) + void filterRecoWithoutPID(soa::Join const& collisions, IdBfFullTracks const& tracks) { filterTracks(collisions, tracks); @@ -958,13 +1321,13 @@ struct IdentifiedBfFilterTracks { } PROCESS_SWITCH(IdentifiedBfFilterTracks, filterRecoWithoutPIDAmbiguous, "Track filtering without PID information with ambiguous tracks check", false) - void filterDetectorLevelWithoutPID(soa::Join const& collisions, IdBfFullTracksDetLevel const& tracks) + void filterDetectorLevelWithoutPID(soa::Join const& collisions, IdBfFullTracksDetLevel const& tracks, aod::McParticles const&) { filterTracks(collisions, tracks); } PROCESS_SWITCH(IdentifiedBfFilterTracks, filterDetectorLevelWithoutPID, "Detector level track filtering without PID information", false) - void filterDetectorLevelWithoutPIDAmbiguous(soa::Join const& collisions, IdBfFullTracksDetLevelAmbiguous const& tracks) + void filterDetectorLevelWithoutPIDAmbiguous(soa::Join const& collisions, IdBfFullTracksDetLevelAmbiguous const& tracks, aod::McParticles const&) { filterTracks(collisions, tracks); } @@ -974,36 +1337,28 @@ struct IdentifiedBfFilterTracks { { filterParticles(gencollisions, particles); } - PROCESS_SWITCH(IdentifiedBfFilterTracks, filterGenerated, "Generated particles filering", true) + PROCESS_SWITCH(IdentifiedBfFilterTracks, filterGenerated, "Generated particles filtering", true) }; template -inline MatchRecoGenSpecies IdentifiedBfFilterTracks::IdentifyParticle(ParticleObject const& particle) +inline MatchRecoGenSpecies IdentifiedBfFilterTracks::identifyParticle(ParticleObject const& particle) { using namespace identifiedbffilter; - constexpr int pdgcodeEl = 11; - constexpr int pdgcodeMu = 13; - constexpr int pdgcodePi = 211; - constexpr int pdgcodeKa = 321; - constexpr int pdgcodePr = 2212; - - int pdgcode = abs(particle.pdgCode()); + int pdgcode = std::fabs(particle.pdgCode()); switch (pdgcode) { - case pdgcodeEl: + case kPositron: return kIdBfElectron; break; - case pdgcodeMu: - return kIdBfMuon; - break; - case pdgcodePi: + + case kPiPlus: return kIdBfPion; break; - case pdgcodeKa: + case kKPlus: return kIdBfKaon; break; - case pdgcodePr: + case kProton: return kIdBfProton; break; @@ -1016,118 +1371,244 @@ inline MatchRecoGenSpecies IdentifiedBfFilterTracks::IdentifyParticle(ParticleOb } } +template +inline void IdentifiedBfFilterTracks::identifyPIDMismatch(ParticleObject const& particle, MatchRecoGenSpecies const& trkId) +{ + MatchRecoGenSpecies realPID = kWrongSpecies; + int pdgcode = std::fabs(particle.pdgCode()); + + switch (pdgcode) { + case kPositron: + realPID = kIdBfElectron; + break; + case kPiPlus: + realPID = kIdBfPion; + break; + case kKPlus: + realPID = kIdBfKaon; + break; + case kProton: + realPID = kIdBfProton; + break; + default: + if (traceOutOfSpeciesParticles) { + LOGF(info, "Wrong particle passed selection cuts. PDG code: %d", pdgcode); + } + realPID = kWrongSpecies; + break; + } + if (!(realPID < 0)) { + if (realPID == trkId) { + fhTruePIDCorrect->Fill(realPID); + } else { + fhTruePIDMismatch->Fill(realPID, trkId); + } + } +} + +template +inline void IdentifiedBfFilterTracks::identifyRealNSigma(ParticleObject const& particle, std::vector tpcNSigma, std::vector tofNSigma, float tpcInnerParam) +{ + + MatchRecoGenSpecies realPID = kWrongSpecies; + int pdgcode = std::fabs(particle.pdgCode()); + switch (pdgcode) { + case kPositron: + realPID = kIdBfElectron; + break; + case kPiPlus: + realPID = kIdBfPion; + break; + case kKPlus: + realPID = kIdBfKaon; + break; + case kProton: + realPID = kIdBfProton; + break; + default: + if (traceOutOfSpeciesParticles) { + LOGF(info, "Wrong particle passed selection cuts. PDG code: %d", pdgcode); + } + realPID = kWrongSpecies; + break; + } + if (!(realPID < 0)) { + fhTrueNSigmaTPC[kIdBfElectron][realPID]->Fill(tpcNSigma[kIdBfElectron], tpcInnerParam); + fhTrueNSigmaTOF[kIdBfElectron][realPID]->Fill(tofNSigma[kIdBfElectron], tpcInnerParam); + fhTrueNSigmaTPC[kIdBfPion][realPID]->Fill(tpcNSigma[kIdBfPion], tpcInnerParam); + fhTrueNSigmaTOF[kIdBfPion][realPID]->Fill(tofNSigma[kIdBfPion], tpcInnerParam); + fhTrueNSigmaTPC[kIdBfKaon][realPID]->Fill(tpcNSigma[kIdBfKaon], tpcInnerParam); + fhTrueNSigmaTOF[kIdBfKaon][realPID]->Fill(tofNSigma[kIdBfKaon], tpcInnerParam); + fhTrueNSigmaTPC[kIdBfProton][realPID]->Fill(tpcNSigma[kIdBfProton], tpcInnerParam); + fhTrueNSigmaTOF[kIdBfProton][realPID]->Fill(tofNSigma[kIdBfProton], tpcInnerParam); + } +} + +template +void fillNSigmaHistos(TrackObject const& track) +{ + + float actualTPCNSigma[kIdBfNoOfSpecies]; + + actualTPCNSigma[kIdBfElectron] = track.tpcNSigmaEl(); + actualTPCNSigma[kIdBfPion] = track.tpcNSigmaPi(); + actualTPCNSigma[kIdBfKaon] = track.tpcNSigmaKa(); + actualTPCNSigma[kIdBfProton] = track.tpcNSigmaPr(); + + float actualTOFNSigma[kIdBfNoOfSpecies]; + + actualTOFNSigma[kIdBfElectron] = track.tofNSigmaEl(); + actualTOFNSigma[kIdBfPion] = track.tofNSigmaPi(); + actualTOFNSigma[kIdBfKaon] = track.tofNSigmaKa(); + actualTOFNSigma[kIdBfProton] = track.tofNSigmaPr(); + + if (loadfromccdb) { + actualTPCNSigma[kIdBfElectron] = actualTPCNSigma[kIdBfElectron] - fhNSigmaCorrection[kIdBfElectron]->GetBinContent(fhNSigmaCorrection[kIdBfElectron]->FindBin(track.tpcInnerParam())); + actualTPCNSigma[kIdBfPion] = actualTPCNSigma[kIdBfPion] - fhNSigmaCorrection[kIdBfPion]->GetBinContent(fhNSigmaCorrection[kIdBfPion]->FindBin(track.tpcInnerParam())); + actualTPCNSigma[kIdBfKaon] = actualTPCNSigma[kIdBfKaon] - fhNSigmaCorrection[kIdBfKaon]->GetBinContent(fhNSigmaCorrection[kIdBfKaon]->FindBin(track.tpcInnerParam())); + actualTPCNSigma[kIdBfProton] = actualTPCNSigma[kIdBfProton] - fhNSigmaCorrection[kIdBfProton]->GetBinContent(fhNSigmaCorrection[kIdBfProton]->FindBin(track.tpcInnerParam())); + } + + fhNSigmaTPC[kIdBfElectron]->Fill(actualTPCNSigma[kIdBfElectron], track.tpcInnerParam()); + fhNSigmaTPC[kIdBfPion]->Fill(actualTPCNSigma[kIdBfPion], track.tpcInnerParam()); + fhNSigmaTPC[kIdBfKaon]->Fill(actualTPCNSigma[kIdBfKaon], track.tpcInnerParam()); + fhNSigmaTPC[kIdBfProton]->Fill(actualTPCNSigma[kIdBfProton], track.tpcInnerParam()); + + fhNSigmaTOF[kIdBfElectron]->Fill(actualTOFNSigma[kIdBfElectron], track.tpcInnerParam()); + fhNSigmaTOF[kIdBfPion]->Fill(actualTOFNSigma[kIdBfPion], track.tpcInnerParam()); + fhNSigmaTOF[kIdBfKaon]->Fill(actualTOFNSigma[kIdBfKaon], track.tpcInnerParam()); + fhNSigmaTOF[kIdBfProton]->Fill(actualTOFNSigma[kIdBfProton], track.tpcInnerParam()); + + fhNSigmaCombo[kIdBfElectron]->Fill(sqrtf(actualTOFNSigma[kIdBfElectron] * actualTOFNSigma[kIdBfElectron] + actualTPCNSigma[kIdBfElectron] * actualTPCNSigma[kIdBfElectron]), track.tpcInnerParam()); + fhNSigmaCombo[kIdBfPion]->Fill(sqrtf(actualTOFNSigma[kIdBfPion] * actualTOFNSigma[kIdBfPion] + actualTPCNSigma[kIdBfPion] * actualTPCNSigma[kIdBfPion]), track.tpcInnerParam()); + fhNSigmaCombo[kIdBfKaon]->Fill(sqrtf(actualTOFNSigma[kIdBfKaon] * actualTOFNSigma[kIdBfKaon] + actualTPCNSigma[kIdBfKaon] * actualTPCNSigma[kIdBfKaon]), track.tpcInnerParam()); + fhNSigmaCombo[kIdBfProton]->Fill(sqrtf(actualTOFNSigma[kIdBfProton] * actualTOFNSigma[kIdBfProton] + actualTPCNSigma[kIdBfProton] * actualTPCNSigma[kIdBfProton]), track.tpcInnerParam()); +} + +/// \brief Identifies the passed track with TPC and TOF data +/// \param track the track of interest +/// \return the internal track id, -1 if not accepted + template -inline MatchRecoGenSpecies IdentifiedBfFilterTracks::IdentifyTrack(TrackObject const& track) +inline MatchRecoGenSpecies IdentifiedBfFilterTracks::identifyTrack(TrackObject const& track) { using namespace o2::analysis::identifiedbffilter; + fillNSigmaHistos(track); + + std::vector actualTPCNSigma(kIdBfNoOfSpecies, 0.); + + actualTPCNSigma[kIdBfElectron] = track.tpcNSigmaEl(); + actualTPCNSigma[kIdBfPion] = track.tpcNSigmaPi(); + actualTPCNSigma[kIdBfKaon] = track.tpcNSigmaKa(); + actualTPCNSigma[kIdBfProton] = track.tpcNSigmaPr(); + + std::vector actualTOFNSigma(kIdBfNoOfSpecies, 0.); + + actualTOFNSigma[kIdBfElectron] = track.tofNSigmaEl(); + actualTOFNSigma[kIdBfPion] = track.tofNSigmaPi(); + actualTOFNSigma[kIdBfKaon] = track.tofNSigmaKa(); + actualTOFNSigma[kIdBfProton] = track.tofNSigmaPr(); + float nsigmas[kIdBfNoOfSpecies]; - if (track.p() < 0.8) { - nsigmas[kIdBfCharged] = 999.0f; - nsigmas[kIdBfElectron] = track.tpcNSigmaEl(); - nsigmas[kIdBfMuon] = track.tpcNSigmaMu(); - nsigmas[kIdBfPion] = track.tpcNSigmaPi(); - nsigmas[kIdBfKaon] = track.tpcNSigmaKa(); - nsigmas[kIdBfProton] = track.tpcNSigmaPr(); + + if constexpr (framework::has_type_v) { + if (makeNSigmaPlots) { + identifyRealNSigma(track.template mcParticle_as(), actualTPCNSigma, actualTOFNSigma, track.tpcInnerParam()); + } + } + + if (loadfromccdb) { + for (int iSp = 0; iSp < kIdBfNoOfSpecies; iSp++) { + actualTPCNSigma[iSp] = actualTPCNSigma[iSp] - fhNSigmaCorrection[iSp]->GetBinContent(fhNSigmaCorrection[iSp]->FindBin(track.tpcInnerParam())); + } + } + + if (track.tpcInnerParam() < tofCut && !onlyTOF) { + + for (int iSp = 0; iSp < kIdBfNoOfSpecies; iSp++) { + nsigmas[iSp] = actualTPCNSigma[iSp]; + } } else { /* introduce require TOF flag */ - if (track.hasTOF()) { - nsigmas[kIdBfCharged] = 999.0f; - nsigmas[kIdBfElectron] = sqrtf(track.tpcNSigmaEl() * track.tpcNSigmaEl() + track.tofNSigmaEl() * track.tofNSigmaEl()); - nsigmas[kIdBfMuon] = sqrtf(track.tpcNSigmaMu() * track.tpcNSigmaMu() + track.tofNSigmaMu() * track.tofNSigmaMu()); - nsigmas[kIdBfPion] = sqrtf(track.tpcNSigmaPi() * track.tpcNSigmaPi() + track.tofNSigmaPi() * track.tofNSigmaPi()); - nsigmas[kIdBfKaon] = sqrtf(track.tpcNSigmaKa() * track.tpcNSigmaKa() + track.tofNSigmaKa() * track.tofNSigmaKa()); - nsigmas[kIdBfProton] = sqrtf(track.tpcNSigmaPr() * track.tpcNSigmaPr() + track.tofNSigmaPr() * track.tofNSigmaPr()); + if (track.hasTOF() && !onlyTOF) { + // TODO: Add an output that tells if TOF was used for PID and at what momentum + for (int iSp = 0; iSp < kIdBfNoOfSpecies; iSp++) { + nsigmas[iSp] = sqrtf(actualTPCNSigma[iSp] * actualTPCNSigma[iSp] + actualTOFNSigma[iSp] * actualTOFNSigma[iSp]); + } + } else if (!track.hasTOF() && !reqTOF && !onlyTOF) { + for (int iSp = 0; iSp < kIdBfNoOfSpecies; iSp++) { + nsigmas[iSp] = actualTPCNSigma[iSp]; + } + + } else if (track.hasTOF() && onlyTOF) { + for (int iSp = 0; iSp < kIdBfNoOfSpecies; iSp++) { + nsigmas[iSp] = actualTOFNSigma[iSp]; + } } else { - nsigmas[kIdBfCharged] = 999.0f; - nsigmas[kIdBfElectron] = track.tpcNSigmaEl(); - nsigmas[kIdBfMuon] = track.tpcNSigmaMu(); - nsigmas[kIdBfPion] = track.tpcNSigmaPi(); - nsigmas[kIdBfKaon] = track.tpcNSigmaKa(); - nsigmas[kIdBfProton] = track.tpcNSigmaPr(); + return kWrongSpecies; } } - float min_nsigma = 999.0f; - MatchRecoGenSpecies sp_min_nsigma = kWrongSpecies; + + if (!pidEl) { + nsigmas[kIdBfElectron] = 999.0f; + } + if (!pidPi) { + nsigmas[kIdBfPion] = 999.0f; + } + if (!pidKa) { + nsigmas[kIdBfKaon] = 999.0f; + } + if (!pidPr) { + nsigmas[kIdBfProton] = 999.0f; + } + + float minNSigma = 999.0f; + MatchRecoGenSpecies spMinNSigma = kWrongSpecies; for (int sp = 0; sp < kIdBfNoOfSpecies; ++sp) { - if (nsigmas[sp] < min_nsigma) { - min_nsigma = nsigmas[sp]; - sp_min_nsigma = MatchRecoGenSpecies(sp); + if (std::fabs(nsigmas[sp]) < std::fabs(minNSigma)) { // Check if species nsigma is less than current nsigma + minNSigma = nsigmas[sp]; // If yes, set species nsigma to current nsigma + spMinNSigma = MatchRecoGenSpecies(sp); // set current species sp number to current sp } } bool doublematch = false; - if (min_nsigma < minPIDSigma) { - for (int sp = 0; (sp < kIdBfNoOfSpecies) && !doublematch; ++sp) { - if (sp != sp_min_nsigma) { - if (nsigmas[sp] < minPIDSigma) { - doublematch = true; + MatchRecoGenSpecies spDouble = kWrongSpecies; + if (minNSigma < maxPIDSigma && minNSigma > minPIDSigma) { // Check that current nsigma is in accpetance range + for (int sp = 0; (sp < kIdBfNoOfSpecies) && !doublematch; ++sp) { // iterate over all species while there's no double match and we're in the list + if (sp != spMinNSigma) { // for species not current minimum nsigma species + if (nsigmas[sp] < maxRejectSigma && nsigmas[sp] > minRejectSigma) { // If secondary species is in rejection range + doublematch = true; // Set double match true + spDouble = MatchRecoGenSpecies(sp); } } } - if (doublematch) { - return kWrongSpecies; + if (doublematch) { // if double match true + fhWrongTrackID->Fill(track.p()); + fhdEdxA[kIdBfNoOfSpecies]->Fill(track.p(), track.tpcSignal()); + fhdEdxIPTPCA[kIdBfNoOfSpecies]->Fill(track.tpcInnerParam(), track.tpcSignal()); + fhTrackTimeA[kIdBfNoOfSpecies]->Fill(track.tpcInnerParam(), track.trackTime()); + fhTrackBetaA[kIdBfNoOfSpecies]->Fill(track.tpcInnerParam(), track.trackTime() / track.length()); + fhDoublePID->Fill(spMinNSigma, spDouble); + return kWrongSpecies; // Return wrong species value } else { - return sp_min_nsigma; + fhNSigmaTPCIdTrks[spMinNSigma]->Fill(actualTPCNSigma[spMinNSigma], track.tpcInnerParam()); + + if constexpr (framework::has_type_v) { + identifyPIDMismatch(track.template mcParticle_as(), spMinNSigma); + } + return spMinNSigma; } } else { return kWrongSpecies; } } -template -MatchRecoGenSpecies IdentifiedBfFilterTracks::trackIdentification(TrackObject const& track) -{ - using namespace identifiedbffilter; - - MatchRecoGenSpecies sp = kWrongSpecies; - if (recoIdMethod == 0) { - sp = kIdBfCharged; - } else if (recoIdMethod == 1) { - if constexpr (framework::has_type_v) { - sp = IdentifyTrack(track); - } else { - LOGF(fatal, "Track identification required but PID information not present"); - } - } else if (recoIdMethod == 2) { - if constexpr (framework::has_type_v) { - sp = IdentifyParticle(track.template mcParticle_as()); - } else { - LOGF(fatal, "Track identification required from MC particle but MC information not present"); - } - } - return sp; -} - -template -int8_t IdentifiedBfFilterTracks::selectTrack(TrackObject const& track) -{ - using namespace identifiedbffilter; - - /* before track selection */ - - /* track selection */ - int8_t pid = AcceptTrack(track); - if (!(pid < 0)) { - /* the track has been accepted */ - /* let's identify it */ - if (pid > 1) { - /* fill the charged histograms */ - fillTrackHistosAfterSelection(track, kIdBfCharged); - } - } - return pid; -} - /// \brief Accepts or not the passed track /// \param track the track of interest /// \return the internal track id, -1 if not accepted -/// TODO: the PID implementation -/// For the time being we keep the convention -/// - positive track pid even -/// - negative track pid odd -/// - charged hadron 0/1 + template -inline int8_t IdentifiedBfFilterTracks::AcceptTrack(TrackObject const& track) +inline int8_t IdentifiedBfFilterTracks::acceptTrack(TrackObject const& track) { fillTrackHistosBeforeSelection(track); // || framework::has_type_v) { + sp = identifyTrack(track); + } else { + LOGF(fatal, "Track identification required but PID information not present"); + } + } else if (recoIdMethod == recoIdMethods[2]) { + if constexpr (framework::has_type_v) { + sp = identifyParticle(track.template mcParticle_as()); + } else { + LOGF(fatal, "Track identification required from MC particle but MC information not present"); + } + } if (sp == kWrongSpecies) { return -1; } if (!(sp < 0)) { fillTrackHistosAfterSelection(track, sp); // 0) { + if (track.sign() > 0) { // if positive trkMultPos[sp]++; //<< Update Particle Multiplicity return speciesChargeValue1[sp]; } - if (track.sign() < 0) { + if (track.sign() < 0) { // if negative trkMultNeg[sp]++; //<< Update Particle Multiplicity return speciesChargeValue1[sp] + 1; } @@ -1160,6 +1657,76 @@ inline int8_t IdentifiedBfFilterTracks::AcceptTrack(TrackObject const& track) return -1; } +/// \brief Accepts or not the passed generated particle +/// \param track the particle of interest +/// \return `true` if the particle is accepted, `false` otherwise +template +inline int8_t IdentifiedBfFilterTracks::acceptParticle(ParticleObject& particle, MCCollisionObject const& mccollision) +{ + /* overall momentum cut */ + if (!(overallminp < particle.p())) { + return kWrongSpecies; + } + TParticlePDG* pdgpart = fPDG->GetParticle(particle.pdgCode()); + float charge = 0; + if (pdgpart != nullptr) { + charge = getCharge(pdgpart->Charge()); + } + if ((particle.flags() & 0x8) != 0x8) { + if (particle.isPhysicalPrimary() && std::fabs(charge) > 0.0) { + if ((particle.mcCollisionId() == 0) && traceCollId0) { + LOGF(info, "Particle %d passed isPhysicalPrimary", particle.globalIndex()); + } + + if (ptlow < particle.pt() && particle.pt() < ptup && etalow < particle.eta() && particle.eta() < etaup) { + MatchRecoGenSpecies sp = kWrongSpecies; + if (recoIdMethod == recoIdMethods[0]) { + sp = kIdBfCharged; + } + if (recoIdMethod == recoIdMethods[1] || recoIdMethod == recoIdMethods[2]) { + sp = identifyParticle(particle); + } + + if (sp != kWrongSpecies) { + if (sp != kIdBfCharged) { + /* fill the charged particle histograms */ + fillParticleHistosAfterSelection(particle, mccollision, charge, kIdBfCharged); + /* update charged multiplicities */ + if (charge == 1) { + partMultPos[kIdBfCharged]++; + } else if (charge == -1) { + partMultNeg[kIdBfCharged]++; + } + } + /* fill the species histograms */ + fillParticleHistosAfterSelection(particle, mccollision, charge, sp); + /* update species multiplicities */ + if (charge == 1) { + partMultPos[sp]++; + } else if (charge == -1) { + partMultNeg[sp]++; + } + } + if (charge == 1) { + return speciesChargeValue1[sp]; + + } else if (charge == -1) { + return speciesChargeValue1[sp] + 1; + } + } + } else { + if ((particle.mcCollisionId() == 0) && traceCollId0) { + LOGF(info, "Particle %d NOT passed isPhysicalPrimary", particle.globalIndex()); + } + } + } else { + if ((particle.mcCollisionId() == 0) && traceCollId0) { + LOGF(info, "Particle %d Out of Bunch Pileup", particle.globalIndex()); + } + } + return kWrongSpecies; +} + template int8_t IdentifiedBfFilterTracks::selectTrackAmbiguousCheck(CollisionObjects const& collisions, TrackObject const& track) { @@ -1199,7 +1766,7 @@ int8_t IdentifiedBfFilterTracks::selectTrackAmbiguousCheck(CollisionObjects cons fhAmbiguousTrackType->Fill(tracktype, multiplicityclass); fhAmbiguousTrackPt->Fill(track.pt(), multiplicityclass); fhAmbiguityDegree->Fill(zvertexes.size(), multiplicityclass); - if (tracktype == 2) { + if (tracktype == trackTypes[2]) { fhCompatibleCollisionsZVtxRms->Fill(-computeRMS(zvertexes), multiplicityclass); } else { fhCompatibleCollisionsZVtxRms->Fill(computeRMS(zvertexes), multiplicityclass); @@ -1210,18 +1777,27 @@ int8_t IdentifiedBfFilterTracks::selectTrackAmbiguousCheck(CollisionObjects cons /* feedback of no ambiguous tracks only if checks required */ fhAmbiguousTrackType->Fill(tracktype, multiplicityclass); } - return selectTrack(track); + return acceptTrack(track); } } template void IdentifiedBfFilterTracks::fillTrackHistosBeforeSelection(TrackObject const& track) { + fhXYB->Fill(track.x(), track.y()); + fhYZB->Fill(track.y(), track.z()); + fhNClustersB->Fill(track.tpcNClsFound()); + fhPhiYB->Fill(track.phi(), track.eta()); + fhPtYB->Fill(track.pt(), track.eta()); + fhChi2B->Fill(track.tpcChi2NCl()); + fhITSNclB->Fill(track.itsNCls()); + fhPB->Fill(track.p()); fhPtB->Fill(track.pt()); fhEtaB->Fill(track.eta()); fhPhiB->Fill(track.phi()); - fhdEdxB->Fill(track.tpcSignal(), track.p()); + fhdEdxB->Fill(track.p(), track.tpcSignal()); + fhdEdxIPTPCB->Fill(track.tpcInnerParam(), track.tpcSignal()); if (track.sign() > 0) { fhPtPosB->Fill(track.pt()); } else { @@ -1229,6 +1805,7 @@ void IdentifiedBfFilterTracks::fillTrackHistosBeforeSelection(TrackObject const& } fhDCAxyB->Fill(track.dcaXY()); fhDCAzB->Fill(track.dcaZ()); + fhDCAxyzB->Fill(track.dcaXY(), track.dcaZ()); } template @@ -1238,8 +1815,16 @@ void IdentifiedBfFilterTracks::fillTrackHistosAfterSelection(TrackObject const& if (sp == kIdBfCharged) { fhEtaA->Fill(track.eta()); fhPhiA->Fill(track.phi()); + fhXYA->Fill(track.x(), track.y()); + fhYZA->Fill(track.y(), track.z()); + fhNClustersA->Fill(track.tpcNClsFound()); + fhPhiYA->Fill(track.phi(), track.eta()); + fhPtYA->Fill(track.pt(), track.eta()); + fhChi2A->Fill(track.tpcChi2NCl()); + fhITSNclA->Fill(track.itsNCls()); fhDCAxyA->Fill(track.dcaXY()); fhDCAzA->Fill(track.dcaZ()); + fhDCAxyzA->Fill(track.dcaXY(), track.dcaZ()); if (track.dcaXY() < 1.0) { fhFineDCAxyA->Fill(track.dcaXY()); @@ -1250,17 +1835,24 @@ void IdentifiedBfFilterTracks::fillTrackHistosAfterSelection(TrackObject const& } fhPA[sp]->Fill(track.p()); fhPtA[sp]->Fill(track.pt()); - fhdEdxA[sp]->Fill(track.tpcSignal(), track.p()); + fhdEdxA[sp]->Fill(track.p(), track.tpcSignal()); + fhdEdxIPTPCA[sp]->Fill(track.tpcInnerParam(), track.tpcSignal()); + fhTrackTimeA[sp]->Fill(track.tpcInnerParam(), track.trackTime()); + fhTrackBetaA[sp]->Fill(track.tpcInnerParam(), track.trackTime() / track.length()); if (track.sign() > 0) { fhPtPosA[sp]->Fill(track.pt()); + fhPtEtaPosA[sp]->Fill(track.pt(), track.eta()); } else { fhPtNegA[sp]->Fill(track.pt()); + fhPtEtaNegA[sp]->Fill(track.pt(), track.eta()); } } template void IdentifiedBfFilterTracks::fillParticleHistosBeforeSelection(ParticleObject const& particle, MCCollisionObject const& collision, float charge) { + fhTruePhiYB->Fill(particle.phi(), particle.eta()); + fhTruePtYB->Fill(particle.pt(), particle.eta()); fhTruePB->Fill(particle.p()); fhTruePtB->Fill(particle.pt()); fhTrueEtaB->Fill(particle.eta()); @@ -1271,14 +1863,17 @@ void IdentifiedBfFilterTracks::fillParticleHistosBeforeSelection(ParticleObject fhTruePtNegB->Fill(particle.pt()); } - float dcaxy = TMath::Sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + - (particle.vy() - collision.posY()) * (particle.vy() - collision.posY())); + float dcaxy = std::sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + + (particle.vy() - collision.posY()) * (particle.vy() - collision.posY())); if (traceDCAOutliers.mDoIt && (traceDCAOutliers.mLowValue < dcaxy) && (dcaxy < traceDCAOutliers.mUpValue)) { fhTrueDCAxyBid->Fill(TString::Format("%d", particle.pdgCode()).Data(), 1.0); } - fhTrueDCAxyB->Fill(TMath::Sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + - (particle.vy() - collision.posY()) * (particle.vy() - collision.posY()))); + fhTrueDCAxyB->Fill(std::sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + + (particle.vy() - collision.posY()) * (particle.vy() - collision.posY()))); + fhTrueDCAxyzB->Fill(std::sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + + (particle.vy() - collision.posY()) * (particle.vy() - collision.posY())), + (particle.vz() - collision.posZ())); fhTrueDCAzB->Fill((particle.vz() - collision.posZ())); } @@ -1287,26 +1882,33 @@ void IdentifiedBfFilterTracks::fillParticleHistosAfterSelection(ParticleObject c { /* the charged species should have been called first so avoid double counting */ if (sp == kIdBfCharged) { + fhTruePhiYA->Fill(particle.phi(), particle.eta()); + fhTruePtYA->Fill(particle.pt(), particle.eta()); fhTrueEtaA->Fill(particle.eta()); fhTruePhiA->Fill(particle.phi()); - float dcaxy = TMath::Sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + - (particle.vy() - collision.posY()) * (particle.vy() - collision.posY())); + float dcaxy = std::sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + + (particle.vy() - collision.posY()) * (particle.vy() - collision.posY())); if (traceDCAOutliers.mDoIt && (traceDCAOutliers.mLowValue < dcaxy) && (dcaxy < traceDCAOutliers.mUpValue)) { LOGF(info, "DCAxy outlier: Particle with index %d and pdg code %d assigned to MC collision %d, pT: %f, phi: %f, eta: %f", particle.globalIndex(), particle.pdgCode(), particle.mcCollisionId(), particle.pt(), particle.phi(), particle.eta()); LOGF(info, " With status %d and flags %0X", particle.statusCode(), particle.flags()); } - fhTrueDCAxyA->Fill(TMath::Sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + - (particle.vy() - collision.posY()) * (particle.vy() - collision.posY()))); + fhTrueDCAxyA->Fill(std::sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + + (particle.vy() - collision.posY()) * (particle.vy() - collision.posY()))); fhTrueDCAzA->Fill((particle.vz() - collision.posZ())); + fhTrueDCAxyzA->Fill(std::sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + + (particle.vy() - collision.posY()) * (particle.vy() - collision.posY())), + (particle.vz() - collision.posZ())); } fhTruePA[sp]->Fill(particle.p()); fhTruePtA[sp]->Fill(particle.pt()); if (charge > 0) { fhTruePtPosA[sp]->Fill(particle.pt()); + fhTruePtEtaPosA[sp]->Fill(particle.pt(), particle.eta()); } else { fhTruePtNegA[sp]->Fill(particle.pt()); + fhTruePtEtaNegA[sp]->Fill(particle.pt(), particle.eta()); } } @@ -1315,7 +1917,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec workflow{adaptAnalysisTask(cfgc, SetDefaultProcesses{ {{"processWithoutCent", true}, - {"processWithoutCentMC", true}}}), + {"processWithoutCentGeneratorLevel", true}}}), adaptAnalysisTask(cfgc)}; return workflow; } diff --git a/PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.h b/PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.h index d47394b8767..f92ecbd813f 100644 --- a/PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.h +++ b/PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.h @@ -9,14 +9,22 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file identifiedBfFilter.h +/// \brief Filters collisions and tracks according to selection criteria +/// \author bghanley1995@gmail.com + #ifndef PWGCF_TWOPARTICLECORRELATIONS_TABLEPRODUCER_IDENTIFIEDBFFILTER_H_ #define PWGCF_TWOPARTICLECORRELATIONS_TABLEPRODUCER_IDENTIFIEDBFFILTER_H_ +#include + #include #include #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" +#include "Framework/runDataProcessing.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Centrality.h" @@ -24,16 +32,17 @@ #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" #include "PWGCF/Core/AnalysisConfigurableCuts.h" -#include +#include "MathUtils/Utils.h" namespace o2 + { namespace aod { using CollisionsEvSelCent = soa::Join; using CollisionEvSelCent = soa::Join::iterator; -using CollisionsEvSelRun2Cent = soa::Join; -using CollisionEvSelRun2Cent = soa::Join::iterator; +using CollisionsEvSelRun2Cent = soa::Join; +using CollisionEvSelRun2Cent = soa::Join::iterator; using CollisionsEvSel = soa::Join; using CollisionEvSel = soa::Join::iterator; using TrackData = soa::Join::iterator; @@ -43,16 +52,17 @@ namespace analysis namespace identifiedbffilter { +const std::vector pdgcodes = {11, 211, 321, 2212}; + /// \enum MatchRecoGenSpecies /// \brief The species considered by the matching test enum MatchRecoGenSpecies { - kIdBfCharged = 0, ///< charged particle/track - kIdBfElectron, ///< electron - kIdBfMuon, ///< muon - kIdBfPion, ///< pion - kIdBfKaon, ///< kaon - kIdBfProton, ///< proton - kIdBfNoOfSpecies, ///< the number of considered species + kIdBfElectron = 0, ///< electron + kIdBfPion, ///< pion + kIdBfKaon, ///< kaon + kIdBfProton, ///< proton + kIdBfNoOfSpecies, ///< the number of considered species + kIdBfCharged = 4, kWrongSpecies = -1 }; @@ -76,17 +86,15 @@ enum SpeciesPairMatch { kIdBfProtonProton ///< Proton-Proton }; -const char* speciesName[kIdBfNoOfSpecies] = {"h", "e", "mu", "pi", "ka", "p"}; +const char* speciesName[kIdBfNoOfSpecies + 1] = {"e", "pi", "ka", "p", "ha"}; -const char* speciesTitle[kIdBfNoOfSpecies] = {"", "e", "#mu", "#pi", "K", "p"}; +const char* speciesTitle[kIdBfNoOfSpecies + 1] = {"e", "#pi", "K", "p", "ha"}; const int speciesChargeValue1[kIdBfNoOfSpecies] = { - 0, // float getCentMultPercentile(CollisionObject collision) @@ -533,10 +538,19 @@ float getCentMultPercentile(CollisionObject collision) return collision.centRun2V0M(); break; case kCL0: - return collision.centRun2CL0(); + if constexpr (framework::has_type_v) { + return collision.centRun2CL0(); + } else { + return 105.0; + } break; + case kCL1: - return collision.centRun2CL1(); + if constexpr (framework::has_type_v) { + return collision.centRun2CL1(); + } else { + return 105.0; + } break; default: return 105.0; @@ -670,7 +684,7 @@ inline bool centralitySelection(aod::McCollision const&, float ////////////////////////////////////////////////////////////////////////////////// template -inline bool IsEvtSelected(CollisionObject const& collision, float& centormult) +inline bool isEvtSelected(CollisionObject const& collision, float& centormult) { bool trigsel = triggerSelection(collision); @@ -681,6 +695,7 @@ inline bool IsEvtSelected(CollisionObject const& collision, float& centormult) } bool centmultsel = centralitySelection(collision, centormult); + return trigsel && zvtxsel && centmultsel; } @@ -694,7 +709,7 @@ inline bool matchTrackType(TrackObject const& track) if (useOwnTrackSelection) { return ownTrackSelection.IsSelected(track); } else { - for (auto filter : trackFilters) { + for (const auto& filter : trackFilters) { if (filter->IsSelected(track)) { if (dca2Dcut) { if (track.dcaXY() * track.dcaXY() / maxDCAxy / maxDCAxy + track.dcaZ() * track.dcaZ() / maxDCAz / maxDCAz > 1) { @@ -722,7 +737,7 @@ inline bool matchTrackType(TrackObject const& track) template void exploreMothers(ParticleObject& particle, MCCollisionObject& collision) { - for (auto& m : particle.template mothers_as()) { + for (const auto& m : particle.template mothers_as()) { LOGF(info, " mother index: %d", m.globalIndex()); LOGF(info, " Tracking back mother"); LOGF(info, " assigned collision Id: %d, looping on collision Id: %d", m.mcCollisionId(), collision.globalIndex()); @@ -733,54 +748,10 @@ void exploreMothers(ParticleObject& particle, MCCollisionObject& collision) } } -/// \brief Accepts or not the passed generated particle -/// \param track the particle of interest -/// \return the internal particle id, -1 if not accepted -/// TODO: the PID implementation -/// For the time being we keep the convention -/// - positive particle pid even -/// - negative particle pid odd -/// - charged hadron 0/1 -template -inline int8_t AcceptParticle(ParticleObject& particle, MCCollisionObject const& collision) +inline float getCharge(float pdgCharge) { - float charge = (fPDG->GetParticle(particle.pdgCode())->Charge() / 3 >= 1) ? 1.0 : ((fPDG->GetParticle(particle.pdgCode())->Charge() / 3 <= -1) ? -1.0 : 0.0); - - if (particle.isPhysicalPrimary()) { - if ((particle.mcCollisionId() == 0) && traceCollId0) { - LOGF(info, "Particle %d passed isPhysicalPrimary", particle.globalIndex()); - } - if (useOwnParticleSelection) { - float dcaxy = TMath::Sqrt((particle.vx() - collision.posX()) * (particle.vx() - collision.posX()) + - (particle.vy() - collision.posY()) * (particle.vy() - collision.posY())); - float dcaz = TMath::Abs(particle.vz() - collision.posZ()); - if (!((dcaxy < particleMaxDCAxy) && (dcaz < particleMaxDCAZ))) { - if ((particle.mcCollisionId() == 0) && traceCollId0) { - LOGF(info, "Rejecting particle with dcaxy: %.2f and dcaz: %.2f", dcaxy, dcaz); - LOGF(info, " assigned collision Id: %d, looping on collision Id: %d", particle.mcCollisionId(), collision.globalIndex()); - LOGF(info, " Collision x: %.5f, y: %.5f, z: %.5f", collision.posX(), collision.posY(), collision.posZ()); - LOGF(info, " Particle x: %.5f, y: %.5f, z: %.5f", particle.vx(), particle.vy(), particle.vz()); - LOGF(info, " index: %d, pdg code: %d", particle.globalIndex(), particle.pdgCode()); - - exploreMothers(particle, collision); - } - return -1; - } - } - if (ptlow < particle.pt() && particle.pt() < ptup && etalow < particle.eta() && particle.eta() < etaup) { - if (charge > 0) { - return 0; - } - if (charge < 0) { - return 1; - } - } - } else { - if ((particle.mcCollisionId() == 0) && traceCollId0) { - LOGF(info, "Particle %d NOT passed isPhysicalPrimary", particle.globalIndex()); - } - } - return -1; + float charge = (pdgCharge / 3 >= 1) ? 1.0 : ((pdgCharge / 3 <= -1) ? -1.0 : 0); + return charge; } } // namespace identifiedbffilter diff --git a/PWGCF/TwoParticleCorrelations/Tasks/CMakeLists.txt b/PWGCF/TwoParticleCorrelations/Tasks/CMakeLists.txt index e471ed3f07f..653d6173930 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/CMakeLists.txt +++ b/PWGCF/TwoParticleCorrelations/Tasks/CMakeLists.txt @@ -18,6 +18,11 @@ o2physics_add_dpl_workflow(r2p24id PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(lambdacorr + SOURCES lambdaR2Correlation.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(identifiedbf SOURCES identifiedbf.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore @@ -28,7 +33,31 @@ o2physics_add_dpl_workflow(identifiedbf-filter-qa PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(twopartcorr-efficiency-qc - SOURCES efficiencyAndQc.cxx +o2physics_add_dpl_workflow(dpt-dpt-efficiency-and-qc + SOURCES dptDptEfficiencyAndQc.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(dpt-dpt-per-run-qc + SOURCES dptDptPerRunQc.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore O2Physics::AnalysisCCDB + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(dpt-dpt-per-run-extra-qc + SOURCES dptDptPerRunExtraQc.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore O2Physics::AnalysisCCDB + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(corr-sparse + SOURCES corrSparse.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(neutron-proton-corr-zdc + SOURCES neutronProtonCorrZdc.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + + + + diff --git a/PWGCF/TwoParticleCorrelations/Tasks/corrSparse.cxx b/PWGCF/TwoParticleCorrelations/Tasks/corrSparse.cxx new file mode 100644 index 00000000000..33cee50dbca --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/Tasks/corrSparse.cxx @@ -0,0 +1,382 @@ +// 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 corrSparse.cxx +/// \brief Provides a sparse with usefull two particle correlation info +/// \author Thor Jensen (thor.kjaersgaard.jensen@cern.ch) and Debojit Sarkar (debojit.sarkar@cern.ch) + +#include +#include "TRandom3.h" +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/StepTHn.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "CommonConstants/MathConstants.h" +#include "Common/Core/RecoDecay.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "PWGCF/DataModel/CorrelationsDerived.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "PWGCF/Core/CorrelationContainer.h" +#include "PWGCF/Core/PairCuts.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +namespace o2::aod +{ +namespace corrsparse +{ +DECLARE_SOA_COLUMN(Multiplicity, multiplicity, int); +} +DECLARE_SOA_TABLE(Multiplicity, "AOD", "MULTIPLICITY", + corrsparse::Multiplicity); + +} // namespace o2::aod + +// define the filtered collisions and tracks +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct CalcNch { + O2_DEFINE_CONFIGURABLE(cfgZVtxCut, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgPtCutMin, float, 0.2f, "minimum accepted track pT") + O2_DEFINE_CONFIGURABLE(cfgPtCutMax, float, 10.0f, "maximum accepted track pT") + O2_DEFINE_CONFIGURABLE(cfgEtaCut, float, 10.0f, "Eta cut") + O2_DEFINE_CONFIGURABLE(cfgMinMixEventNum, int, 5, "Minimum number of events to mix") + + Filter trackFilter = (nabs(aod::track::eta) < cfgEtaCut) && (aod::track::pt > cfgPtCutMin) && (aod::track::pt < cfgPtCutMax) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)); + + using AodCollisions = soa::Join; // aod::CentFT0Cs + using AodTracks = soa::Filtered>; + + Produces multiplicityNch; + + HistogramRegistry registry{"registry"}; + + void init(InitContext&) + { + AxisSpec axisNch = {100, 0, 100}; + AxisSpec axisVrtx = {10, -10, 10}; + + registry.add("Ncharge", "N_{charge}", {HistType::kTH1D, {axisNch}}); + registry.add("zVtx_all", "zVtx_all", {HistType::kTH1D, {axisVrtx}}); + } + + void process(AodCollisions::iterator const& collision, AodTracks const& tracks) + { + multiplicityNch(tracks.size()); + registry.fill(HIST("Ncharge"), tracks.size()); + registry.fill(HIST("zVtx_all"), collision.posZ()); + } +}; + +struct CorrSparse { + Service ccdb; + + O2_DEFINE_CONFIGURABLE(cfgZVtxCut, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgPtCutMin, float, 0.2f, "minimum accepted track pT") + O2_DEFINE_CONFIGURABLE(cfgPtCutMax, float, 10.0f, "maximum accepted track pT") + O2_DEFINE_CONFIGURABLE(cfgEtaCut, float, 0.8f, "Eta cut") + O2_DEFINE_CONFIGURABLE(cfgMinMixEventNum, int, 5, "Minimum number of events to mix") + O2_DEFINE_CONFIGURABLE(cfgMinMult, int, 0, "Minimum multiplicity for collision") + O2_DEFINE_CONFIGURABLE(cfgMaxMult, int, 10, "Maximum multiplicity for collision") + O2_DEFINE_CONFIGURABLE(cfgMergingCut, float, 0.0, "Merging cut on track merge") + O2_DEFINE_CONFIGURABLE(cfgRadiusLow, float, 0.8, "Low radius for merging cut") + O2_DEFINE_CONFIGURABLE(cfgRadiusHigh, float, 2.5, "High radius for merging cut") + O2_DEFINE_CONFIGURABLE(etaMftTrackMin, float, -5.0, "Minimum eta for MFT track") + O2_DEFINE_CONFIGURABLE(etaMftTrackMax, float, 0.0, "Maximum eta for MFT track") + O2_DEFINE_CONFIGURABLE(nClustersMftTrack, int, 5, "Minimum number of clusters for MFT track") + O2_DEFINE_CONFIGURABLE(cfgSampleSize, double, 10, "Sample size for mixed event") + + Configurable processMFT{"processMFT", true, "Associate particle from MFT"}; + + ConfigurableAxis axisVertex{"axisVertex", {10, -10, 10}, "vertex axis for histograms"}; + ConfigurableAxis axisEta{"axisEta", {40, -1., 1.}, "eta axis for histograms"}; + ConfigurableAxis axisPhi{"axisPhi", {72, 0.0, constants::math::TwoPI}, "phi axis for histograms"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 10.0}, "pt axis for histograms"}; + ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {72, -PIHalf, PIHalf * 3}, "delta phi axis for histograms"}; + ConfigurableAxis axisDeltaEta{"axisDeltaEta", {48, -2.4, 2.4}, "delta eta axis for histograms"}; + ConfigurableAxis axisPtTrigger{"axisPtTrigger", {VARIABLE_WIDTH, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 10.0}, "pt trigger axis for histograms"}; + ConfigurableAxis axisPtAssoc{"axisPtAssoc", {VARIABLE_WIDTH, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 10.0}, "pt associated axis for histograms"}; + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 15, 20, 25, 30, 35, 40, 50, 60, 80, 100}, "multiplicity / centrality axis for histograms"}; + ConfigurableAxis vtxMix{"vtxMix", {VARIABLE_WIDTH, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "vertex axis for mixed event histograms"}; + ConfigurableAxis multMix{"multMix", {VARIABLE_WIDTH, 0, 5, 10, 15, 20, 25, 30, 35, 40, 50, 60, 80, 100}, "multiplicity / centrality axis for mixed event histograms"}; + ConfigurableAxis axisSample{"axisSample", {cfgSampleSize, 0, cfgSampleSize}, "sample axis for histograms"}; + + ConfigurableAxis axisVertexEfficiency{"axisVertexEfficiency", {10, -10, 10}, "vertex axis for efficiency histograms"}; + ConfigurableAxis axisEtaEfficiency{"axisEtaEfficiency", {20, -1.0, 1.0}, "eta axis for efficiency histograms"}; + ConfigurableAxis axisPtEfficiency{"axisPtEfficiency", {VARIABLE_WIDTH, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0}, "pt axis for efficiency histograms"}; + + // make the filters and cuts. + Filter collisionFilter = (nabs(aod::collision::posZ) < cfgZVtxCut) && (aod::corrsparse::multiplicity) > cfgMinMult && (aod::corrsparse::multiplicity) < cfgMaxMult && (aod::evsel::sel8) == true; + Filter trackFilter = (nabs(aod::track::eta) < cfgEtaCut) && (aod::track::pt > cfgPtCutMin) && (aod::track::pt < cfgPtCutMax) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)); + + // Define the outputs + OutputObj same{Form("sameEvent_%i_%i", static_cast(cfgMinMult), static_cast(cfgMaxMult))}; + OutputObj mixed{Form("mixedEvent_%i_%i", static_cast(cfgMinMult), static_cast(cfgMaxMult))}; + + HistogramRegistry registry{"registry"}; + + using AodCollisions = soa::Filtered>; // aod::CentFT0Cs + using AodTracks = soa::Filtered>; + + void init(InitContext&) + { + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); + + LOGF(info, "Starting init"); + + // Make histograms to check the distributions after cuts + registry.add("deltaEta_deltaPhi_same", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEta}}); // check to see the delta eta and delta phi distribution + registry.add("deltaEta_deltaPhi_mixed", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEta}}); + registry.add("Phi", "Phi", {HistType::kTH1D, {axisPhi}}); + registry.add("Eta", "Eta", {HistType::kTH1D, {axisEta}}); + registry.add("pT", "pT", {HistType::kTH1D, {axisPtTrigger}}); + registry.add("Nch", "N_{ch}", {HistType::kTH1D, {axisMultiplicity}}); + registry.add("zVtx", "zVtx", {HistType::kTH1D, {axisVertex}}); + + registry.add("Trig_hist", "", {HistType::kTHnSparseF, {{axisMultiplicity, axisVertex, axisPtTrigger}}}); + + registry.add("eventcount", "bin", {HistType::kTH1F, {{3, 0, 3, "bin"}}}); // histogram to see how many events are in the same and mixed event + + std::vector corrAxis = {{axisSample, "Sample"}, + {axisVertex, "z-vtx (cm)"}, + {axisPtTrigger, "p_{T} (GeV/c)"}, + {axisPtAssoc, "p_{T} (GeV/c)"}, + {axisDeltaPhi, "#Delta#varphi (rad)"}, + {axisDeltaEta, "#Delta#eta"}}; + std::vector effAxis = { + {axisVertexEfficiency, "z-vtx (cm)"}, + {axisPtEfficiency, "p_{T} (GeV/c)"}, + {axisEtaEfficiency, "#eta"}, + }; + std::vector userAxis; + + same.setObject(new CorrelationContainer(Form("sameEvent_%i_%i", static_cast(cfgMinMult), static_cast(cfgMaxMult)), Form("sameEvent_%i_%i", static_cast(cfgMinMult), static_cast(cfgMaxMult)), corrAxis, effAxis, userAxis)); + mixed.setObject(new CorrelationContainer(Form("mixedEvent_%i_%i", static_cast(cfgMinMult), static_cast(cfgMaxMult)), Form("mixedEvent_%i_%i", static_cast(cfgMinMult), static_cast(cfgMaxMult)), corrAxis, effAxis, userAxis)); + } + enum EventType { + SameEvent = 1, + MixedEvent = 3 + }; + + TRandom3* gRandom = new TRandom3(); + + template + bool isAcceptedMftTrack(TTrackAssoc const& mftTrack) + { + // cut on the eta of MFT tracks + if (mftTrack.eta() > etaMftTrackMax || mftTrack.eta() < etaMftTrackMin) { + return false; + } + + // cut on the number of clusters of the reconstructed MFT track + if (mftTrack.nClusters() < nClustersMftTrack) { + return false; + } + + return true; + } + + int getMagneticField(uint64_t timestamp) + { + // Get the magnetic field + static o2::parameters::GRPMagField* grpo = nullptr; + if (grpo == nullptr) { + grpo = ccdb->getForTimeStamp("/GLO/Config/GRPMagField", timestamp); + if (grpo == nullptr) { + LOGF(fatal, "GRP object not found for timestamp %llu", timestamp); + return 0; + } + LOGF(info, "Retrieved GRP for timestamp %llu with magnetic field of %d kG", timestamp, grpo->getNominalL3Field()); + } + return grpo->getNominalL3Field(); + } + + // fill multiple histograms + template + void fillYield(TCollision collision, TTracks tracks) // function to fill the yield and etaphi histograms. + { + registry.fill(HIST("Nch"), tracks.size()); + registry.fill(HIST("zVtx"), collision.posZ()); + + for (auto const& track1 : tracks) { + registry.fill(HIST("Phi"), track1.phi()); + registry.fill(HIST("Eta"), track1.eta()); + registry.fill(HIST("pT"), track1.pt()); + } + } + + template + float getDPhiStar(TTrack const& track1, TTrackAssoc const& track2, float radius, int magField) + { + float charge1 = track1.sign(); + float charge2 = track2.sign(); + + float phi1 = track1.phi(); + float phi2 = track2.phi(); + + float pt1 = track1.pt(); + float pt2 = track2.pt(); + + int fbSign = (magField > 0) ? 1 : -1; + + float dPhiStar = phi1 - phi2 - charge1 * fbSign * std::asin(0.075 * radius / pt1) + charge2 * fbSign * std::asin(0.075 * radius / pt2); + + if (dPhiStar > constants::math::PI) + dPhiStar = constants::math::TwoPI - dPhiStar; + if (dPhiStar < -constants::math::PI) + dPhiStar = -constants::math::TwoPI - dPhiStar; + + return dPhiStar; + } + + // + template + void fillCorrelations(TTracks tracks1, TTracksAssoc tracks2, float posZ, int system, float Nch, int magneticField) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms + { + + int fSampleIndex = gRandom->Uniform(0, cfgSampleSize); + + // loop over all tracks + for (auto const& track1 : tracks1) { + + if (system == SameEvent) { + registry.fill(HIST("Trig_hist"), Nch, posZ, track1.pt()); + } + + for (auto const& track2 : tracks2) { + + if (track1.pt() <= track2.pt()) + continue; // skip if the trigger pt is less than the associate pt + + if (processMFT) { + if constexpr (std::is_same_v) { + if (!isAcceptedMftTrack(track2)) { + continue; + } + } + } + + float deltaPhi = RecoDecay::constrainAngle(track1.phi() - track2.phi(), -PIHalf); + float deltaEta = track1.eta() - track2.eta(); + + if (std::abs(deltaEta) < cfgMergingCut) { + + double dPhiStarHigh = getDPhiStar(track1, track2, cfgRadiusHigh, magneticField); + double dPhiStarLow = getDPhiStar(track1, track2, cfgRadiusLow, magneticField); + + const double kLimit = 3.0 * cfgMergingCut; + + bool bIsBelow = kFALSE; + + if (std::abs(dPhiStarLow) < kLimit || std::abs(dPhiStarHigh) < kLimit || dPhiStarLow * dPhiStarHigh < 0) { + for (double rad(cfgRadiusLow); rad < cfgRadiusHigh; rad += 0.01) { + double dPhiStar = getDPhiStar(track1, track2, rad, magneticField); + if (std::abs(dPhiStar) < kLimit) { + bIsBelow = kTRUE; + break; + } + } + if (bIsBelow) + continue; + } + } + + // fill the right sparse and histograms + if (system == SameEvent) { + + same->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track2.pt(), deltaPhi, deltaEta); + registry.fill(HIST("deltaEta_deltaPhi_same"), deltaPhi, deltaEta); + } else if (system == MixedEvent) { + + mixed->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track2.pt(), deltaPhi, deltaEta); + registry.fill(HIST("deltaEta_deltaPhi_mixed"), deltaPhi, deltaEta); + } + } + } + } + + void processSame(AodCollisions::iterator const& collision, AodTracks const& tracks, aod::MFTTracks const& mfts, aod::BCsWithTimestamps const&) + { + + auto bc = collision.bc_as(); + + registry.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin + fillYield(collision, tracks); + + if (processMFT) { + + fillCorrelations(tracks, mfts, collision.posZ(), SameEvent, tracks.size(), getMagneticField(bc.timestamp())); + + } else { + + fillCorrelations(tracks, tracks, collision.posZ(), SameEvent, tracks.size(), getMagneticField(bc.timestamp())); + } + } + PROCESS_SWITCH(CorrSparse, processSame, "Process same event", true); + + // event mixing + SliceCache cache; + using MixedBinning = ColumnBinningPolicy; + + // the process for filling the mixed events + void processMixed(AodCollisions const& collisions, AodTracks const& tracks, aod::MFTTracks const& MFTtracks, aod::BCsWithTimestamps const&) + { + + if (processMFT) { + MixedBinning binningOnVtxAndMult{{vtxMix, multMix}, true}; // true is for 'ignore overflows' (true by default) + auto tracksTuple = std::make_tuple(tracks, MFTtracks); + SameKindPair pairs{binningOnVtxAndMult, cfgMinMixEventNum, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + + for (auto const& [collision1, tracks1, collision2, tracks2] : pairs) { + registry.fill(HIST("eventcount"), MixedEvent); // fill the mixed event in the 3 bin + auto bc = collision1.bc_as(); + + fillCorrelations(tracks1, tracks2, collision1.posZ(), MixedEvent, tracks1.size(), getMagneticField(bc.timestamp())); + } + } else { + MixedBinning binningOnVtxAndMult{{vtxMix, multMix}, true}; // true is for 'ignore overflows' (true by default) + auto tracksTuple = std::make_tuple(tracks, tracks); + SameKindPair pairs{binningOnVtxAndMult, cfgMinMixEventNum, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + + for (auto const& [collision1, tracks1, collision2, tracks2] : pairs) { + registry.fill(HIST("eventcount"), MixedEvent); // fill the mixed event in the 3 bin + auto bc = collision1.bc_as(); + + fillCorrelations(tracks1, tracks2, collision1.posZ(), MixedEvent, tracks1.size(), getMagneticField(bc.timestamp())); + } + } + } + PROCESS_SWITCH(CorrSparse, processMixed, "Process mixed events", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGCF/TwoParticleCorrelations/Tasks/dptDptEfficiencyAndQc.cxx b/PWGCF/TwoParticleCorrelations/Tasks/dptDptEfficiencyAndQc.cxx new file mode 100644 index 00000000000..1f835ca8db2 --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/Tasks/dptDptEfficiencyAndQc.cxx @@ -0,0 +1,1483 @@ +// 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 dptDptEfficiencyAndQc.cxx +/// \brief Provides efficiency extraction and QC for track cuts and PID +/// \author victor.gonzalez.sebastian@gmail.com + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ReconstructionDataFormats/PID.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TableHelper.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/PIDResponse.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/Expressions.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Math/MatrixFunctions.h" +#include "Math/SMatrix.h" + +#include "PWGCF/Core/AnalysisConfigurableCuts.h" +#include "PWGCF/DataModel/DptDptFiltered.h" +#include "PWGCF/TableProducer/dptdptfilter.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::soa; +using namespace o2::framework::expressions; + +#define ADDHISTOGRAM(thetype, thedirectory, thename, thetitle, thekind, thebinning...) \ + registry.add(TString::Format("%s/%s", thedirectory, thename).Data(), thetitle, thekind, thebinning) +#define FORMATSTRING(theformat, theparams...) TString::Format(theformat, theparams).Data() +#define DIRECTORYSTRING(thedirectoryfmt, thedirectorypars...) FORMATSTRING(thedirectoryfmt, thedirectorypars) +#define HNAMESTRING(thehnamefmt, thehnamepars...) FORMATSTRING(thehnamefmt, thehnamepars) +#define HTITLESTRING(thehtitlefmt, thehtitlepars...) FORMATSTRING(thehtitlefmt, thehtitlepars) + +namespace o2::analysis::dptdptfilter +{ +TpcExcludeTrack tpcExcluder; ///< the TPC excluder object instance +} // namespace o2::analysis::dptdptfilter + +namespace efficiencyandqatask +{ +/// \enum KindOfData +/// \brief The kind of data for templating the procedures +enum KindOfData { + kReco = 0, ///< processing over reconstructed particles/tracks + kGen ///< processing over generated particles +}; + +/// \enum KindOfProcess +/// \brief The kind of processing for templating the procedures and produce histograms +enum KindOfProcess { + kBASIC, ///< produce the basic histograms + kEXTRA, ///< produce the extra pair based histograms + kPID, ///< produce the basic PID histograms + kPIDEXTRA ///< produce the extra PID histograms +}; + +/// \enum BeforeAfter +/// \brief The kind of filling, before or after track selection +enum BeforeAfter { + kBefore = 0, ///< filling before track selection + kAfter ///< filling after track selection +}; + +/* the structures for checking the TPC sector borders impact */ +constexpr int kNoOfTpcSectors = 18; +constexpr float kTpcPhiSectorWidth = (constants::math::TwoPI) / kNoOfTpcSectors; + +/* the configuration of the nsigma axis */ +float minNSigma = -4.05f; +float maxNSigma = 4.05f; +float widthNSigmaBin = 0.1f; +int noOfNSigmaBins = static_cast((maxNSigma - minNSigma) / widthNSigmaBin); + +/* the pT bins of interest for the relative separation within TPC sectors data collection */ +std::vector ptBinsOfInterest{}; + +/* the PID selector object to help with the configuration and the id of the selected particles */ +o2::analysis::dptdptfilter::PIDSpeciesSelection pidselector; + +// initialized during self configuration +std::vector poinames; ///< the species of interest names +std::vector tnames; ///< the track names + +static const std::vector allmainspecies{o2::track::PID::Electron, o2::track::PID::Muon, o2::track::PID::Pion, o2::track::PID::Kaon, o2::track::PID::Proton}; +static const std::vector allmainspnames{"ElectronP", "ElectronM", "MuonP", "MuonM", "PionP", "PionM", "KaonP", "KaonM", "ProtonP", "ProtonM"}; +static const std::vector allmainsptitles{"e^{#plus}", "e^{#minus}", "#mu^{#plus}", "#mu^{#minus}", "#pi^{#plus}", "#pi^{#minus}", "K^{#plus}", "K^{#minus}", "p", "#bar{p}"}; +static const std::vector mainspecies{o2::track::PID::Pion, o2::track::PID::Kaon, o2::track::PID::Proton}; +static const std::vector mainspnames{"PionP", "PionM", "KaonP", "KaonM", "ProtonP", "ProtonM"}; +static const std::vector mainsptitles{"#pi^{#plus}", "#pi^{#minus}", "K^{#plus}", "K^{#minus}", "p", "#bar{p}"}; +static const std::vector pdgcodes = {kElectron, kMuonPlus, kPiPlus, kKPlus, kProton}; +} // namespace efficiencyandqatask + +/* the QA data collecting engine */ +struct QADataCollectingEngine { + uint nsp = static_cast(efficiencyandqatask::tnames.size()); + uint nmainsp = static_cast(efficiencyandqatask::mainspnames.size()); + uint nallmainsp = static_cast(efficiencyandqatask::allmainspnames.size()); + + //=================================================== + // The QA output objects + //=================================================== + /* momentum histograms */ + std::shared_ptr fhPvsInnerP = nullptr; + std::shared_ptr fhTruePvsP = nullptr; + std::shared_ptr fhTruePvsInnerP = nullptr; + /* efficiency histograms histograms */ + /* when two indexes, first index reco and detector level, second index generator level */ + /* when no indexes, reco and detector level */ + std::vector> fhPtB{2, nullptr}; + std::vector> fhPtVsEtaB{2, nullptr}; + std::vector> fhPtVsZvtxB{2, nullptr}; + std::shared_ptr fhPhiVsPtPosB{nullptr}; + std::shared_ptr fhNchVsPhiVsPtPosB{nullptr}; + TH2* fhPerColNchVsPhiVsPtPosB{nullptr}; + std::shared_ptr fhPhiVsInnerWallMomPosB{nullptr}; + std::shared_ptr fhNchVsPhiVsInnerWallMomPosB{nullptr}; + TH2* fhPerColNchVsPhiVsInnerWallMomPosB{nullptr}; + std::shared_ptr fhPhiVsPtNegB{nullptr}; + std::shared_ptr fhNchVsPhiVsPtNegB{nullptr}; + TH2* fhPerColNchVsPhiVsPtNegB{nullptr}; + std::shared_ptr fhPhiVsInnerWallMomNegB{nullptr}; + std::shared_ptr fhNchVsPhiVsInnerWallMomNegB{nullptr}; + TH2* fhPerColNchVsPhiVsInnerWallMomNegB{nullptr}; + std::vector>> fhPtA{2, {nsp, nullptr}}; + std::vector>> fhPtVsEtaA{2, {nsp, nullptr}}; + std::vector>> fhPtVsZvtxA{2, {nsp, nullptr}}; + std::vector> fhPhiVsPtA{nsp, nullptr}; + std::vector> fhNchVsPhiVsPtA{nsp, nullptr}; + std::vector fhPerColNchVsPhiVsPtA{nsp, nullptr}; + std::vector> fhPhiVsInnerWallMomA{nsp, nullptr}; + std::vector> fhNchVsPhiVsInnerWallMomA{nsp, nullptr}; + std::vector fhPerColNchVsPhiVsInnerWallMomA{nsp, nullptr}; + std::vector> fhPhiShiftedVsPtA{nsp, nullptr}; + std::vector> fhPhiShiftedVsInnerWallMomA{nsp, nullptr}; + std::shared_ptr fhPtVsEtaItsAcc{nullptr}; + std::shared_ptr fhPtVsEtaTpcAcc{nullptr}; + std::shared_ptr fhPtVsEtaItsTpcAcc{nullptr}; + std::shared_ptr fhPtVsEtaItsTofAcc{nullptr}; + std::shared_ptr fhPtVsEtaTpcTofAcc{nullptr}; + std::shared_ptr fhPtVsEtaItsTpcTofAcc{nullptr}; + std::vector> fhPtVsEtaItsA{nsp, nullptr}; + std::vector> fhPtVsEtaTpcA{nsp, nullptr}; + std::vector> fhPtVsEtaItsTpcA{nsp, nullptr}; + std::vector> fhPtVsEtaItsTofA{nsp, nullptr}; + std::vector> fhPtVsEtaTpcTofA{nsp, nullptr}; + std::vector> fhPtVsEtaItsTpcTofA{nsp, nullptr}; + /* primaries and secondaries */ + /* overall, first index detector level second index generator level */ + /* detailed, first index detector level, second index associated particle */ + std::shared_ptr fhPtPurityPosPrimA{nullptr}; + std::shared_ptr fhPtPurityNegPrimA{nullptr}; + std::vector> fhPtVsEtaPrimA{nsp, nullptr}; + std::vector>> fhPtVsEtaPrimItsA{2, {nsp, nullptr}}; + std::vector>> fhPtVsEtaPrimItsTpcA{2, {nsp, nullptr}}; + std::vector>> fhPtVsEtaPrimItsTpcTofA{2, {nsp, nullptr}}; + std::shared_ptr fhPtPurityPosSecA{nullptr}; + std::shared_ptr fhPtPurityNegSecA{nullptr}; + std::vector> fhPtVsEtaSecA{nsp, nullptr}; + std::vector>> fhPtVsEtaSecItsA{2, {nsp, nullptr}}; + std::vector>> fhPtVsEtaSecItsTpcA{2, {nsp, nullptr}}; + std::vector>> fhPtVsEtaSecItsTpcTofA{2, {nsp, nullptr}}; + std::shared_ptr fhPtPurityPosMatA{nullptr}; + std::shared_ptr fhPtPurityNegMatA{nullptr}; + std::vector> fhPtVsEtaMatA{nsp, nullptr}; + std::vector>> fhPtVsEtaMatItsA{2, {nsp, nullptr}}; + std::vector>> fhPtVsEtaMatItsTpcA{2, {nsp, nullptr}}; + std::vector>> fhPtVsEtaMatItsTpcTofA{2, {nsp, nullptr}}; + /* QC histograms */ + std::shared_ptr fhItsNClsVsPtB{nullptr}; + std::shared_ptr fhItsChi2NClsVsPtB{nullptr}; + std::shared_ptr fhTpcFindableNClsVsPtB{nullptr}; + std::shared_ptr fhTpcFoundNClsVsPtB{nullptr}; + std::shared_ptr fhTpcSharedNClsVsPtB{nullptr}; + std::shared_ptr fhTpcFractionSharedClsVsPtB{nullptr}; + std::shared_ptr fhTpcCrossedRowsVsPtB{nullptr}; + std::shared_ptr fhTpcCrossedRowsOverFindableClsVsPtB{nullptr}; + std::shared_ptr fhTpcChi2NClsVsPtB{nullptr}; + std::vector> fhItsNClsVsPtA{nsp, nullptr}; + std::vector> fhItsChi2NClsVsPtA{nsp, nullptr}; + std::vector> fhTpcFindableNClsVsPtA{nsp, nullptr}; + std::vector> fhTpcFoundNClsVsPtA{nsp, nullptr}; + std::vector> fhTpcSharedNClsVsPtA{nsp, nullptr}; + std::vector> fhTpcFractionSharedClsVsPtA{nsp, nullptr}; + std::vector> fhTpcCrossedRowsVsPtA{nsp, nullptr}; + std::vector> fhTpcCrossedRowsOverFindableClsVsPtA{nsp, nullptr}; + std::vector> fhTpcChi2NClsVsPtA{nsp, nullptr}; + + template + void init(HistogramRegistry& registry, const char* dirname) + { + using namespace efficiencyandqatask; + using namespace analysis::dptdptfilter; + + AxisSpec pidPtAxis{150, 0.1, 5.0, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec pidPtAxisReduced{50, 0.1, 5.0, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec pidPAxis{150, 0.1, 5.0, "#it{p} (GeV/#it{c})"}; + AxisSpec pidPAxisReduced{50, 0.1, 5.0, "#it{p} (GeV/#it{c})"}; + pidPtAxis.makeLogarithmic(); + pidPAxis.makeLogarithmic(); + const AxisSpec ptAxis{ptbins, ptlow, ptup, "#it{p}_{T} (GeV/c)"}; + const AxisSpec etaAxis{etabins, etalow, etaup, "#eta"}; + const AxisSpec phiAxis{360, 0.0f, constants::math::TwoPI, "#varphi (rad)"}; + const AxisSpec phiSectorAxis{144, 0.0f, 0.36f, "#varphi (mod(2#pi/18) (rad))"}; + const AxisSpec phiSectorAxisReduced{36, 0.0f, 0.36f, "#varphi (mod(2#pi/18) (rad))"}; + const AxisSpec nChargeAxis{100, 0.0f, 100.0f, "#it{N}_{ch}"}; + const AxisSpec phiShiftedSectorAxis{220, -55.0f, 55.0f, "% of the sector"}; + const AxisSpec zvtxAxis{zvtxbins, zvtxlow, zvtxup, "#it{z}_{vtx}"}; + const AxisSpec itsNClsAxis{8, -0.5, 7.5, "ITS n clusters"}; + const AxisSpec itsCh2Axis{100, 0, 40, "#Chi^{2}/Cls ITS"}; + const AxisSpec tpcNClsAxis{165, -0.5, 164.5, "TPC n clusters"}; + const AxisSpec tpcNRowsAxis{165, -0.5, 164.5, "TPC n rows"}; + const AxisSpec tpcFractionAxis{100, 0, 1, "fraction"}; + const AxisSpec tpcXRowsOverFindClsAxis{60, 0.7, 1.3, "fraction"}; + const AxisSpec tpcCh2Axis{100, 0, 10, "#Chi^{2}/Cls TPC"}; + + /* the reconstructed and generated levels histograms */ + std::string recogen = (kindOfData == kReco) ? "Reco" : "Gen"; + fhPtB[kindOfData] = ADDHISTOGRAM(TH1, DIRECTORYSTRING("%s/%s/%s", dirname, recogen.c_str(), "Before"), "Pt", "#it{p}_{T}", kTH1F, {ptAxis}); + fhPtVsEtaB[kindOfData] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, recogen.c_str(), "Before"), "PtVsEta", "#it{p}_T vs #eta", kTH2F, {etaAxis, ptAxis}); + fhPtVsZvtxB[kindOfData] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, recogen.c_str(), "Before"), "PtVsZvtx", "#it{p}_T vs #it{z}_{vtx}", kTH2F, {zvtxAxis, ptAxis}); + for (uint isp = 0; isp < nsp; ++isp) { + fhPtA[kindOfData][isp] = ADDHISTOGRAM(TH1, DIRECTORYSTRING("%s/%s/%s", dirname, recogen.c_str(), "After"), HNAMESTRING("Pt_%s", tnames[isp].c_str()), HTITLESTRING("#it{p}_{T} %s", tnames[isp].c_str()), kTH1F, {ptAxis}); + fhPtVsEtaA[kindOfData][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, recogen.c_str(), "After"), HNAMESTRING("PtVsEta_%s", tnames[isp].c_str()), HTITLESTRING("#it{p}_{T} vs #eta %s", tnames[isp].c_str()), kTH2F, {etaAxis, ptAxis}); + fhPtVsZvtxA[kindOfData][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, recogen.c_str(), "After"), HNAMESTRING("PtVsZvtx_%s", tnames[isp].c_str()), HTITLESTRING("#it{p}_{T} vs #it{z}_{zvtx} %s", tnames[isp].c_str()), kTH2F, {zvtxAxis, ptAxis}); + } + + if constexpr (kindOfData == kReco) { + /* only the reconstructed level histograms*/ + fhPhiVsPtPosB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "PhiVsPtPos", "#varphi (mod(2#pi/18))", kTH2F, {pidPtAxis, phiSectorAxis}); + fhNchVsPhiVsPtPosB = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "NchVsPhiVsPtPos", "#it{N}_{ch}^{#plus} #varphi (mod(2#pi/18))", kTH3F, {pidPtAxisReduced, phiSectorAxisReduced, nChargeAxis}); + fhPhiVsInnerWallMomPosB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "PhiVsIwMomPos", "#varphi (mod(2#pi/18)) TPC_{iw} #it{p}", kTH2F, {pidPAxis, phiSectorAxis}); + fhNchVsPhiVsInnerWallMomPosB = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "NchVsPhiVsIwMomPos", "#it{N}_{ch}^{#plus} #varphi (mod(2#pi/18)) TPC_{iw} #it{p}", kTH3F, {pidPAxisReduced, phiSectorAxisReduced, nChargeAxis}); + fhPhiVsPtNegB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "PhiVsPtNeg", "#varphi (mod(2#pi/18))", kTH2F, {pidPtAxis, phiSectorAxis}); + fhNchVsPhiVsPtNegB = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "NchVsPhiVsPtNeg", "#it{N}_{ch}^{#minus} #varphi (mod(2#pi/18))", kTH3F, {pidPtAxisReduced, phiSectorAxisReduced, nChargeAxis}); + fhPhiVsInnerWallMomNegB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "PhiVsIwMomNeg", "#varphi (mod(2#pi/18)) TPC_{iw} #it{p}", kTH2F, {pidPAxis, phiSectorAxis}); + fhNchVsPhiVsInnerWallMomNegB = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "NchVsPhiVsIwMomNeg", "#it{N}_{ch}^{#minus} #varphi (mod(2#pi/18)) TPC_{iw} #it{p}", kTH3F, {pidPAxisReduced, phiSectorAxisReduced, nChargeAxis}); + fhItsNClsVsPtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "ITSNCls", "ITS clusters", kTH2F, {ptAxis, itsNClsAxis}); + fhItsChi2NClsVsPtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "ITSChi2NCls", "ITS #Chi^{2}", kTH2F, {ptAxis, itsCh2Axis}); + fhTpcFindableNClsVsPtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "TPCFindableNCls", "TPC findable clusters", kTH2F, {ptAxis, tpcNClsAxis}); + fhTpcFoundNClsVsPtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "TPCFoundNCls", "TPC found clusters", kTH2F, {ptAxis, tpcNClsAxis}); + fhTpcSharedNClsVsPtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "TPCSharedNCls", "TPC shared clusters", kTH2F, {ptAxis, tpcNClsAxis}); + fhTpcFractionSharedClsVsPtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "TPCFractionSharedCls", "TPC fraction shared clusters", kTH2F, {ptAxis, tpcFractionAxis}); + fhTpcCrossedRowsVsPtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "TPCXrows", "TPC crossed rows", kTH2F, {ptAxis, tpcNRowsAxis}); + fhTpcCrossedRowsOverFindableClsVsPtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "XRowsOverFindableCls", "TPC xrows over findable clusters", kTH2F, {ptAxis, tpcXRowsOverFindClsAxis}); + fhTpcChi2NClsVsPtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "TPCChi2NCls", "TPC #Chi^{2}", kTH2F, {ptAxis, tpcCh2Axis}); + /* efficiency histograms */ + fhPvsInnerP = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), "pVsInnerP", "#it{p} versus TPC inner wall #it{p}", kTH2F, {pidPAxis, pidPAxis}); + fhPtVsEtaItsAcc = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), "ptItsAcc", "ITS tracks within the acceptance", kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaTpcAcc = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), "ptTpcAcc", "TPC tracks within the acceptance", kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaItsTpcAcc = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), "ptItsTpcAcc", "ITS&TPC tracks within the acceptance", kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaItsTofAcc = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), "ptItsTofAcc", "ITS&TOF tracks within the acceptance", kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaTpcTofAcc = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), "ptTpcTofAcc", "TPC&TOF tracks within the acceptance", kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaItsTpcTofAcc = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), "ptItsTpcTofAcc", "ITS&TPC&TOF tracks within the acceptance", kTH2F, {etaAxis, ptAxis}); + /* per collision histograms not going to the results file */ + int nPtBins = fhNchVsPhiVsPtPosB->GetNbinsX(); + float ptLow = fhNchVsPhiVsPtNegB->GetXaxis()->GetBinLowEdge(1); + float ptHigh = fhNchVsPhiVsPtNegB->GetXaxis()->GetBinUpEdge(nPtBins); + int nTpcIwMomBins = fhNchVsPhiVsInnerWallMomNegB->GetNbinsX(); + float tpcIwMomLow = fhNchVsPhiVsInnerWallMomNegB->GetXaxis()->GetBinLowEdge(1); + float tpcIwMomHigh = fhNchVsPhiVsInnerWallMomNegB->GetXaxis()->GetBinUpEdge(nTpcIwMomBins); + int nPhiSectorBins = fhNchVsPhiVsPtPosB->GetNbinsY(); + float phiSectorLow = fhNchVsPhiVsPtNegB->GetYaxis()->GetBinLowEdge(1); + float phiSectorHigh = fhNchVsPhiVsPtNegB->GetYaxis()->GetBinUpEdge(nPhiSectorBins); + fhPerColNchVsPhiVsPtPosB = new TH2F(TString::Format("%s_PerColNchVsPhiVsPtPosB", dirname), "", nPtBins, ptLow, ptHigh, nPhiSectorBins, phiSectorLow, phiSectorHigh); + fhPerColNchVsPhiVsInnerWallMomPosB = new TH2F(TString::Format("%s_PerColNchVsPhiVsInnerWallMomPosB", dirname), "", nTpcIwMomBins, tpcIwMomLow, tpcIwMomHigh, nPhiSectorBins, phiSectorLow, phiSectorHigh); + fhPerColNchVsPhiVsPtNegB = new TH2F(TString::Format("%s_PerColNchVsPhiVsPtNegB", dirname), "", nPtBins, ptLow, ptHigh, nPhiSectorBins, phiSectorLow, phiSectorHigh); + fhPerColNchVsPhiVsInnerWallMomNegB = new TH2F(TString::Format("%s_PerColNchVsPhiVsInnerWallMomNegB", dirname), "", nTpcIwMomBins, tpcIwMomLow, tpcIwMomHigh, nPhiSectorBins, phiSectorLow, phiSectorHigh); + for (uint isp = 0; isp < nsp; ++isp) { + fhPhiVsPtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("PhiVsPt_%s", tnames[isp].c_str()), HTITLESTRING("#varphi %s (mod(2#pi/18))", tnames[isp].c_str()), kTH2F, {pidPtAxis, phiSectorAxis}); + fhNchVsPhiVsPtA[isp] = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("NchVsPhiVsPt_%s", tnames[isp].c_str()), HTITLESTRING("#it{N}_{ch}^{%s} #varphi (mod(2#pi/18))", tnames[isp].c_str()), kTH3F, {pidPtAxisReduced, phiSectorAxisReduced, nChargeAxis}); + fhPhiVsInnerWallMomA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("PhiVsIwMom_%s", tnames[isp].c_str()), HTITLESTRING("#varphi %s (mod(2#pi/18)) TPC_{iw} #it{p}", tnames[isp].c_str()), kTH2F, {pidPAxis, phiSectorAxis}); + fhNchVsPhiVsInnerWallMomA[isp] = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("NchVsPhiVsIwMom_%s", tnames[isp].c_str()), HTITLESTRING("#it{N}_{ch}^{%s} #varphi (mod(2#pi/18)) TPC_{iw} #it{p}", tnames[isp].c_str()), kTH3F, {pidPAxisReduced, phiSectorAxisReduced, nChargeAxis}); + fhPhiShiftedVsPtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("PhiShiftedVsPt_%s", tnames[isp].c_str()), HTITLESTRING("%s TPC sector %%", tnames[isp].c_str()), kTH2F, {pidPtAxis, phiShiftedSectorAxis}); + fhPhiShiftedVsInnerWallMomA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("PhiShiftedVsIwMom_%s", tnames[isp].c_str()), HTITLESTRING("%s TPC sector %% TPC_{iw} #it{p}", tnames[isp].c_str()), kTH2F, {pidPAxis, phiShiftedSectorAxis}); + fhItsNClsVsPtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("ITSNCls_%s", tnames[isp].c_str()), HTITLESTRING("ITS clusters %s", tnames[isp].c_str()), kTH2F, {ptAxis, itsNClsAxis}); + fhItsChi2NClsVsPtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("ITSChi2NCls_%s", tnames[isp].c_str()), HTITLESTRING("ITS #Chi^{2} %s", tnames[isp].c_str()), kTH2F, {ptAxis, itsCh2Axis}); + fhTpcFindableNClsVsPtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("TPCFindableNCls_%s", tnames[isp].c_str()), HTITLESTRING("TPC findable clusters %s", tnames[isp].c_str()), kTH2F, {ptAxis, tpcNClsAxis}); + fhTpcFoundNClsVsPtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("TPCFoundNCls_%s", tnames[isp].c_str()), HTITLESTRING("TPC found clusters %s", tnames[isp].c_str()), kTH2F, {ptAxis, tpcNClsAxis}); + fhTpcSharedNClsVsPtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("TPCSharedNCls_%s", tnames[isp].c_str()), HTITLESTRING("TPC shared clusters %s", tnames[isp].c_str()), kTH2F, {ptAxis, tpcNClsAxis}); + fhTpcFractionSharedClsVsPtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("TPCFractionSharedCls_%s", tnames[isp].c_str()), HTITLESTRING("TPC fraction shared clusters %s", tnames[isp].c_str()), kTH2F, {ptAxis, tpcFractionAxis}); + fhTpcCrossedRowsVsPtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("TPCXrows_%s", tnames[isp].c_str()), HTITLESTRING("TPC crossed rows %s", tnames[isp].c_str()), kTH2F, {ptAxis, tpcNRowsAxis}); + fhTpcCrossedRowsOverFindableClsVsPtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("XRowsOverFindableCls_%s", tnames[isp].c_str()), HTITLESTRING("TPC xrows over findable clusters %s", tnames[isp].c_str()), kTH2F, {ptAxis, tpcXRowsOverFindClsAxis}); + fhTpcChi2NClsVsPtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("TPCChi2NCls_%s", tnames[isp].c_str()), HTITLESTRING("TPC #Chi^{2} %s", tnames[isp].c_str()), kTH2F, {ptAxis, tpcCh2Axis}); + /* efficiency histograms */ + fhPtVsEtaItsA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), HNAMESTRING("ptIts%s", tnames[isp].c_str()), HTITLESTRING("ITS %s tracks", tnames[isp].c_str()), kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaTpcA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), HNAMESTRING("ptTpc%s", tnames[isp].c_str()), HTITLESTRING("TPC %s tracks", tnames[isp].c_str()), kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaItsTpcA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), HNAMESTRING("ptItsTpc%s", tnames[isp].c_str()), HTITLESTRING("ITS&TPC %s tracks", tnames[isp].c_str()), kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaItsTofA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), HNAMESTRING("ptItsTof_%s", tnames[isp].c_str()), HTITLESTRING("ITS&TOF %s tracks", tnames[isp].c_str()), kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaTpcTofA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), HNAMESTRING("ptTpcTof_%s", tnames[isp].c_str()), HTITLESTRING("TPC&TOF %s tracks", tnames[isp].c_str()), kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaItsTpcTofA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), HNAMESTRING("ptItsTpcTof_%s", tnames[isp].c_str()), HTITLESTRING("ITS&TPC&TOF %s tracks", tnames[isp].c_str()), kTH2F, {etaAxis, ptAxis}); + /* per collision histograms not going to the results file */ + fhPerColNchVsPhiVsPtA[isp] = new TH2F(HNAMESTRING("%s_PerColNchVsPhiVsPt_%s", dirname, tnames[isp].c_str()), "", nPtBins, ptLow, ptHigh, nPhiSectorBins, phiSectorLow, phiSectorHigh); + fhPerColNchVsPhiVsInnerWallMomA[isp] = new TH2F(HNAMESTRING("%s_PerColNchVsPhiVsInnerWallMom_%s", dirname, tnames[isp].c_str()), "", nTpcIwMomBins, tpcIwMomLow, tpcIwMomHigh, nPhiSectorBins, phiSectorLow, phiSectorHigh); + } + } else { + AxisSpec recoSpecies{static_cast(nsp) + 1, -0.5, nsp - 0.5, "reco species"}; + AxisSpec trueSpecies{static_cast(nmainsp) + 1, -0.5, nmainsp + 0.5, "true species"}; + fhTruePvsP = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Gen"), "truePVsP", "#it{p} gen versus reco #it{p}", kTH2F, {pidPAxis, pidPAxis}); + fhTruePvsInnerP = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Gen"), "truePVsInnerP", "#it{p} gen versus reco TPC inner wall #it{p}", kTH2F, {pidPAxis, pidPAxis}); + fhPtPurityPosPrimA = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s", dirname, "Purity"), "ptPurityPosPrim", "Primaries for reconstructed positive", kTH3F, {recoSpecies, trueSpecies, ptAxis}); + fhPtPurityNegPrimA = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s", dirname, "Purity"), "ptPurityNegPrim", "Primaries for reconstructed negative", kTH3F, {recoSpecies, trueSpecies, ptAxis}); + fhPtPurityPosSecA = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s", dirname, "Purity"), "ptPurityPosSec", "Secondaries for reconstructed positive", kTH3F, {recoSpecies, trueSpecies, ptAxis}); + fhPtPurityNegSecA = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s", dirname, "Purity"), "ptPurityNegSec", "Secondaries for reconstructed negative", kTH3F, {recoSpecies, trueSpecies, ptAxis}); + fhPtPurityPosMatA = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s", dirname, "Purity"), "ptPurityPosMat", "Secondaries from material for reconstructed positive", kTH3F, {recoSpecies, trueSpecies, ptAxis}); + fhPtPurityNegMatA = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s", dirname, "Purity"), "ptPurityNegMat", "Secondaries from material for reconstructed negative", kTH3F, {recoSpecies, trueSpecies, ptAxis}); + for (uint isp = 0; isp < nsp; ++isp) { + /* detector level and generator level histograms */ + fhPtVsEtaPrimA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Gen"), + HNAMESTRING("ptPrim%s", tnames[isp].c_str()), + HTITLESTRING("ITS %s tracks (primaries)", tnames[isp].c_str()), + kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaSecA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Gen"), + HNAMESTRING("ptSec%s", tnames[isp].c_str()), + HTITLESTRING("ITS %s tracks (secondaries)", tnames[isp].c_str()), + kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaMatA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Gen"), + HNAMESTRING("ptMat%s", tnames[isp].c_str()), + HTITLESTRING("ITS %s tracks (from material)", tnames[isp].c_str()), + kTH2F, {etaAxis, ptAxis}); + + const std::vector detectedorigin = {"DetReco", "DetAssoc"}; + for (uint ix = 0; ix < detectedorigin.size(); ++ix) { + fhPtVsEtaPrimItsA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), + HNAMESTRING("ptItsPrim_%s", tnames[isp].c_str()), + HTITLESTRING("ITS %s tracks (primaries)", tnames[isp].c_str()), + kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaPrimItsTpcA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), + HNAMESTRING("ptItsTpcPrim_%s", tnames[isp].c_str()), + HTITLESTRING("ITS&TPC %s tracks (primaries)", tnames[isp].c_str()), + kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaPrimItsTpcTofA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), + HNAMESTRING("ptItsTpcTofPrim_%s", tnames[isp].c_str()), + HTITLESTRING("ITS&TPC&TOF %s tracks (primaries)", tnames[isp].c_str()), + kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaSecItsA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), + HNAMESTRING("ptItsSec_%s", tnames[isp].c_str()), + HTITLESTRING("ITS %s tracks (secondaries)", tnames[isp].c_str()), + kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaSecItsTpcA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), + HNAMESTRING("ptItsTpcSec_%s", tnames[isp].c_str()), + HTITLESTRING("ITS&TPC %s tracks (secondaries)", tnames[isp].c_str()), + kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaSecItsTpcTofA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), + HNAMESTRING("ptItsTpcTofSec_%s", tnames[isp].c_str()), + HTITLESTRING("ITS&TPC&TOF %s tracks (secondaries)", tnames[isp].c_str()), + kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaMatItsA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), + HNAMESTRING("ptItsMat_%s", tnames[isp].c_str()), + HTITLESTRING("ITS %s tracks (from material)", tnames[isp].c_str()), + kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaMatItsTpcA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), + HNAMESTRING("ptItsTpcMat_%s", tnames[isp].c_str()), + HTITLESTRING("ITS&TPC %s tracks (from material)", tnames[isp].c_str()), + kTH2F, {etaAxis, ptAxis}); + fhPtVsEtaMatItsTpcTofA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), + HNAMESTRING("ptItsTpcTofMat_%s", tnames[isp].c_str()), + HTITLESTRING("ITS&TPC&TOF %s tracks (from material)", tnames[isp].c_str()), + kTH2F, {etaAxis, ptAxis}); + } + } + } + } + + template + void processTrack(float zvtx, TrackObject const& track) + { + using namespace efficiencyandqatask; + using namespace analysis::dptdptfilter; + using namespace o2::aod::track; + + constexpr float kFiftyPerCent = 50.0f; + constexpr float kHundredPerCent = 100.0f; + + fhPtB[kindOfData]->Fill(track.pt()); + fhPtVsEtaB[kindOfData]->Fill(track.eta(), track.pt()); + fhPtVsZvtxB[kindOfData]->Fill(zvtx, track.pt()); + if (!(track.trackacceptedid() < 0)) { + fhPtA[kindOfData][track.trackacceptedid()]->Fill(track.pt()); + fhPtVsEtaA[kindOfData][track.trackacceptedid()]->Fill(track.eta(), track.pt()); + fhPtVsZvtxA[kindOfData][track.trackacceptedid()]->Fill(zvtx, track.pt()); + } + if constexpr (kindOfData == kReco) { + auto fillhisto = [&track](auto& h, bool cond) { + if (cond) { + h->Fill(track.eta(), track.pt()); + } + }; + bool hasits = track.hasITS() && TrackSelectionFlags::checkFlag(track.trackCutFlag(), TrackSelectionITS); + bool hastpc = track.hasTPC() && TrackSelectionFlags::checkFlag(track.trackCutFlag(), TrackSelectionTPC); + bool hastof = track.hasTOF(); + + float phiInTpcSector = std::fmod(track.phi(), kTpcPhiSectorWidth); + float phiShiftedPercentInTpcSector = phiInTpcSector * 100 / kTpcPhiSectorWidth; + phiShiftedPercentInTpcSector = (phiShiftedPercentInTpcSector > kFiftyPerCent) ? (phiShiftedPercentInTpcSector - kHundredPerCent) : phiShiftedPercentInTpcSector; + if (track.sign() > 0) { + fhPhiVsPtPosB->Fill(track.pt(), phiInTpcSector); + fhPerColNchVsPhiVsPtPosB->Fill(track.pt(), phiInTpcSector); + fhPhiVsInnerWallMomPosB->Fill(track.tpcInnerParam(), phiInTpcSector); + fhPerColNchVsPhiVsInnerWallMomPosB->Fill(track.tpcInnerParam(), phiInTpcSector); + } else { + fhPhiVsPtNegB->Fill(track.pt(), phiInTpcSector); + fhPerColNchVsPhiVsPtNegB->Fill(track.pt(), phiInTpcSector); + fhPhiVsInnerWallMomNegB->Fill(track.tpcInnerParam(), phiInTpcSector); + fhPerColNchVsPhiVsInnerWallMomNegB->Fill(track.tpcInnerParam(), phiInTpcSector); + } + fhItsNClsVsPtB->Fill(track.pt(), track.itsNCls()); + fhItsChi2NClsVsPtB->Fill(track.pt(), track.itsChi2NCl()); + fhTpcFindableNClsVsPtB->Fill(track.pt(), track.tpcNClsFindable()); + fhTpcFoundNClsVsPtB->Fill(track.pt(), track.tpcNClsFound()); + fhTpcSharedNClsVsPtB->Fill(track.pt(), track.tpcNClsShared()); + fhTpcFractionSharedClsVsPtB->Fill(track.pt(), track.tpcFractionSharedCls()); + fhTpcCrossedRowsVsPtB->Fill(track.pt(), track.tpcNClsCrossedRows()); + fhTpcCrossedRowsOverFindableClsVsPtB->Fill(track.pt(), track.tpcCrossedRowsOverFindableCls()); + fhTpcChi2NClsVsPtB->Fill(track.pt(), track.tpcChi2NCl()); + if (inTheAcceptance(track)) { + /* efficiency histograms */ + fillhisto(fhPtVsEtaItsAcc, hasits); + fillhisto(fhPtVsEtaTpcAcc, hastpc); + fillhisto(fhPtVsEtaItsTpcAcc, hasits && hastpc); + fillhisto(fhPtVsEtaItsTofAcc, hasits && hastof); + fillhisto(fhPtVsEtaTpcTofAcc, hastpc && hastof); + fillhisto(fhPtVsEtaItsTpcTofAcc, hasits && hastpc && hastof); + } + if (!(track.trackacceptedid() < 0)) { + fhPhiVsPtA[track.trackacceptedid()]->Fill(track.pt(), phiInTpcSector); + fhPerColNchVsPhiVsPtA[track.trackacceptedid()]->Fill(track.pt(), phiInTpcSector); + fhPhiVsInnerWallMomA[track.trackacceptedid()]->Fill(track.tpcInnerParam(), phiInTpcSector); + fhPerColNchVsPhiVsInnerWallMomA[track.trackacceptedid()]->Fill(track.tpcInnerParam(), phiInTpcSector); + fhPhiShiftedVsPtA[track.trackacceptedid()]->Fill(track.pt(), phiShiftedPercentInTpcSector); + fhPhiShiftedVsInnerWallMomA[track.trackacceptedid()]->Fill(track.tpcInnerParam(), phiShiftedPercentInTpcSector); + fhItsNClsVsPtA[track.trackacceptedid()]->Fill(track.pt(), track.itsNCls()); + fhItsChi2NClsVsPtA[track.trackacceptedid()]->Fill(track.pt(), track.itsChi2NCl()); + fhTpcFindableNClsVsPtA[track.trackacceptedid()]->Fill(track.pt(), track.tpcNClsFindable()); + fhTpcFoundNClsVsPtA[track.trackacceptedid()]->Fill(track.pt(), track.tpcNClsFound()); + fhTpcSharedNClsVsPtA[track.trackacceptedid()]->Fill(track.pt(), track.tpcNClsShared()); + fhTpcFractionSharedClsVsPtA[track.trackacceptedid()]->Fill(track.pt(), track.tpcFractionSharedCls()); + fhTpcCrossedRowsVsPtA[track.trackacceptedid()]->Fill(track.pt(), track.tpcNClsCrossedRows()); + fhTpcCrossedRowsOverFindableClsVsPtA[track.trackacceptedid()]->Fill(track.pt(), track.tpcCrossedRowsOverFindableCls()); + fhTpcChi2NClsVsPtA[track.trackacceptedid()]->Fill(track.pt(), track.tpcChi2NCl()); + /* efficiency histograms */ + fhPvsInnerP->Fill(track.tpcInnerParam(), track.p()); + fillhisto(fhPtVsEtaItsA[track.trackacceptedid()], hasits); + fillhisto(fhPtVsEtaTpcA[track.trackacceptedid()], hastpc); + fillhisto(fhPtVsEtaItsTpcA[track.trackacceptedid()], hasits && hastpc); + fillhisto(fhPtVsEtaItsTofA[track.trackacceptedid()], hasits && hastof); + fillhisto(fhPtVsEtaTpcTofA[track.trackacceptedid()], hastpc && hastof); + fillhisto(fhPtVsEtaItsTpcTofA[track.trackacceptedid()], hasits && hastpc && hastof); + /* the detector / generator combined level */ + if constexpr (framework::has_type_v) { + auto findgenid = [&](auto& part) { + int pdgcode = std::abs(part.pdgCode()); + for (uint ix = 0; ix < pdgcodes.size(); ++ix) { + if (pdgcode == pdgcodes[ix]) { + return ix; + } + } + return static_cast(pdgcodes.size()); + }; + auto fillpurityhistos = [](auto& hpos, auto& hneg, auto& genid, auto& track, bool cond) { + if (cond) { + if (track.sign() > 0) { + hpos->Fill(static_cast(track.trackacceptedid() / 2), genid, track.pt()); + } else { + hneg->Fill(static_cast(track.trackacceptedid() / 2), genid, track.pt()); + } + } + }; + /* get the associated MC particle we are sure it does exist because the track was accepted */ + const auto& mcparticle = track.template mcParticle_as>(); + float genid = findgenid(mcparticle); + + bool isprimary = mcparticle.isPhysicalPrimary(); + bool issecdecay = !isprimary && (mcparticle.getProcess() == TMCProcess::kPDecay); + bool isfrommaterial = !isprimary && !issecdecay; + fillpurityhistos(fhPtPurityPosPrimA, fhPtPurityNegPrimA, genid, track, isprimary); + fillpurityhistos(fhPtPurityPosSecA, fhPtPurityNegSecA, genid, track, issecdecay); + fillpurityhistos(fhPtPurityPosMatA, fhPtPurityNegMatA, genid, track, isfrommaterial); + fhTruePvsP->Fill(track.p(), mcparticle.p()); + fhTruePvsInnerP->Fill(track.tpcInnerParam(), mcparticle.p()); + + auto fillhisto = [](auto& h, float pt, float eta, bool cond1, bool cond2) { + if (cond1 && cond2) { + h->Fill(eta, pt); + } + }; + std::vector tPt = {track.pt(), mcparticle.pt()}; + std::vector tEta = {track.eta(), mcparticle.eta()}; + for (uint ix = 0; ix < tPt.size(); ++ix) { + fillhisto(fhPtVsEtaPrimItsA[ix][track.trackacceptedid()], tPt[ix], tEta[ix], hasits, isprimary); + fillhisto(fhPtVsEtaPrimItsTpcA[ix][track.trackacceptedid()], tPt[ix], tEta[ix], hasits && hastpc, isprimary); + fillhisto(fhPtVsEtaPrimItsTpcTofA[ix][track.trackacceptedid()], tPt[ix], tEta[ix], hasits && hastof, isprimary); + fillhisto(fhPtVsEtaSecItsA[ix][track.trackacceptedid()], tPt[ix], tEta[ix], hasits, issecdecay); + fillhisto(fhPtVsEtaSecItsTpcA[ix][track.trackacceptedid()], tPt[ix], tEta[ix], hasits && hastpc, issecdecay); + fillhisto(fhPtVsEtaSecItsTpcTofA[ix][track.trackacceptedid()], tPt[ix], tEta[ix], hasits && hastof, issecdecay); + fillhisto(fhPtVsEtaMatItsA[ix][track.trackacceptedid()], tPt[ix], tEta[ix], hasits, isfrommaterial); + fillhisto(fhPtVsEtaMatItsTpcA[ix][track.trackacceptedid()], tPt[ix], tEta[ix], hasits && hastpc, isfrommaterial); + fillhisto(fhPtVsEtaMatItsTpcTofA[ix][track.trackacceptedid()], tPt[ix], tEta[ix], hasits && hastof, isfrommaterial); + } + } + } + } + if constexpr (kindOfData == kGen) { + if (!(track.trackacceptedid() < 0)) { + /* pure generator level */ + if (track.isPhysicalPrimary()) { + fhPtVsEtaPrimA[track.trackacceptedid()]->Fill(track.eta(), track.pt()); + } else if (track.getProcess() == TMCProcess::kPDecay) { + fhPtVsEtaSecA[track.trackacceptedid()]->Fill(track.eta(), track.pt()); + } else { + fhPtVsEtaMatA[track.trackacceptedid()]->Fill(track.eta(), track.pt()); + } + } + } + } + + template + void newCollision() + { + using namespace efficiencyandqatask; + if constexpr (kindOfData == kReco) { + fhPerColNchVsPhiVsPtPosB->Reset(); + fhPerColNchVsPhiVsPtNegB->Reset(); + fhPerColNchVsPhiVsInnerWallMomPosB->Reset(); + fhPerColNchVsPhiVsInnerWallMomNegB->Reset(); + for (uint isp = 0; isp < nsp; ++isp) { + fhPerColNchVsPhiVsPtA[isp]->Reset(); + fhPerColNchVsPhiVsInnerWallMomA[isp]->Reset(); + } + } + } + + template + void finishedCollision() + { + using namespace efficiencyandqatask; + if constexpr (kindOfData == kReco) { + auto fillHistogram = [](auto& th, const TH2* sh) { + int nBinsX = sh->GetNbinsX(); + int nBinsY = sh->GetNbinsY(); + for (int ix = 0; ix < nBinsX; ++ix) { + for (int iy = 0; iy < nBinsY; ++iy) { + th->Fill(sh->GetXaxis()->GetBinCenter(ix + 1), sh->GetYaxis()->GetBinCenter(iy + 1), sh->GetBinContent(ix + 1, iy + 1)); + } + } + }; + fillHistogram(fhNchVsPhiVsPtPosB, fhPerColNchVsPhiVsPtPosB); + fillHistogram(fhNchVsPhiVsPtNegB, fhPerColNchVsPhiVsPtNegB); + fillHistogram(fhNchVsPhiVsInnerWallMomPosB, fhPerColNchVsPhiVsInnerWallMomPosB); + fillHistogram(fhNchVsPhiVsInnerWallMomNegB, fhPerColNchVsPhiVsInnerWallMomNegB); + for (uint isp = 0; isp < nsp; ++isp) { + fillHistogram(fhNchVsPhiVsPtA[isp], fhPerColNchVsPhiVsPtA[isp]); + fillHistogram(fhNchVsPhiVsInnerWallMomA[isp], fhPerColNchVsPhiVsInnerWallMomA[isp]); + } + } + } +}; + +/* the QA extra data, pairs, collecting engine */ +struct QAExtraDataCollectingEngine { + uint nsp = static_cast(efficiencyandqatask::tnames.size()); + uint nmainsp = static_cast(efficiencyandqatask::mainspnames.size()); + uint nallmainsp = static_cast(efficiencyandqatask::allmainspnames.size()); + + //=================================================== + // The QA output objects + //=================================================== + /* pairs histograms */ + constexpr static size_t kNoOfOverflowBins = 2; + constexpr static int kBinNotTracked = -1; + std::vector>>> fhPhiPhiA{2, {nsp, {nsp, nullptr}}}; + std::vector>>> fhEtaEtaA{2, {nsp, {nsp, nullptr}}}; + std::vector>>> fhN2VsDeltaEtaVsDeltaPhi{2, {nsp, {nsp, nullptr}}}; + TAxis ptAxis{analysis::dptdptfilter::ptbins, analysis::dptdptfilter::ptlow, analysis::dptdptfilter::ptup}; + std::vector ptOfInterestBinMap; + std::vector>>> fhInSectorDeltaPhiVsPhiPhiPerPtBinA{2, {nsp, {nsp, nullptr}}}; + std::vector>>> fhInSectorDeltaPhiVsEtaEtaPerPtBinA{2, {nsp, {nsp, nullptr}}}; + + QAExtraDataCollectingEngine() + { + using namespace efficiencyandqatask; + using namespace analysis::dptdptfilter; + + /* the mapping between pT bins of interest and internal representation, and histogram title to keep track of them offline */ + /* it is done once for both reco and gen */ + ptOfInterestBinMap = std::vector(static_cast(ptbins + kNoOfOverflowBins), kBinNotTracked); + LOGF(info, "Configuring the pT bins of interest on a map of length %d", ptOfInterestBinMap.size()); + for (size_t ix = 0; ix < ptBinsOfInterest.size(); ++ix) { + /* remember our internal axis starts in 0.5 value, i.e. its first central value is 1 */ + ptOfInterestBinMap[ptBinsOfInterest[ix]] = ix + 1; + LOGF(info, " Added pT bin %d as internal axis value %d", ptBinsOfInterest[ix], ptOfInterestBinMap[ptBinsOfInterest[ix]]); + } + } + + template + void init(HistogramRegistry& registry, const char* dirname) + { + using namespace efficiencyandqatask; + using namespace analysis::dptdptfilter; + + AxisSpec phiAxis = {phibins, 0.0f, constants::math::TwoPI, "#varphi"}; + AxisSpec phiSectorAxis = {72, 0.0f, kTpcPhiSectorWidth, "#varphi (mod(2#pi/18)) (rad)"}; + AxisSpec deltaPhiAxis = {phibins, 0.0f, constants::math::TwoPI, "#Delta#varphi (rad)"}; + AxisSpec deltaEtaAxis = {2 * etabins - 1, etalow - etaup, etaup - etalow, "#Delta#eta"}; + AxisSpec deltaPhiInSectorAxis = {144, -kTpcPhiSectorWidth, kTpcPhiSectorWidth, "#Delta#varphi (rad)"}; + AxisSpec etaAxis = {etabins, etalow, etaup, "#eta"}; + AxisSpec ptOfInterestAxis = {static_cast(ptBinsOfInterest.size()), 0.5f, static_cast(ptBinsOfInterest.size()) + 0.5f, "#it{p}_{T} (GeV/#it{c})"}; + + /* the reconstructed and generated levels histograms */ + std::string recogen = (kindOfData == kReco) ? "Reco" : "Gen"; + + /* the mapping between pT bins of interest and internal representation, and histogram title to keep track of them offline */ + LOGF(info, "Configured at %s level the pT bins of interest on a map of length %d", recogen.c_str(), ptOfInterestBinMap.size()); + std::string hPtRangesOfInterestTitle; + bool firstRange = true; + for (size_t ix = 0; ix < ptOfInterestBinMap.size(); ++ix) { + if (ptOfInterestBinMap[ix] != kBinNotTracked) { + TString ptRange = TString::Format("%s%.2f-%.2f", firstRange ? "" : ",", ptAxis.GetBinLowEdge(ix), ptAxis.GetBinUpEdge(ix)); + hPtRangesOfInterestTitle += ptRange.Data(); + LOGF(info, " Tracking pT bin %d as internal axis value %d", ix, ptOfInterestBinMap[ix]); + firstRange = false; + } + } + LOGF(info, " Final pT bins tilte: %s", hPtRangesOfInterestTitle.c_str()); + + for (uint isp = 0; isp < nsp; ++isp) { + for (uint jsp = 0; jsp < nsp; ++jsp) { + fhPhiPhiA[kindOfData][isp][jsp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, recogen.c_str(), "After"), HNAMESTRING("PhiPhi_%s%s", tnames[isp].c_str(), tnames[jsp].c_str()), + HTITLESTRING("%s%s pairs", tnames[isp].c_str(), tnames[jsp].c_str()), kTH2F, {phiAxis, phiAxis}); + fhEtaEtaA[kindOfData][isp][jsp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, recogen.c_str(), "After"), HNAMESTRING("EtaEta_%s%s", tnames[isp].c_str(), tnames[jsp].c_str()), + HTITLESTRING("%s%s pairs", tnames[isp].c_str(), tnames[jsp].c_str()), kTH2F, {etaAxis, etaAxis}); + fhN2VsDeltaEtaVsDeltaPhi[kindOfData][isp][jsp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, recogen.c_str(), "After"), HNAMESTRING("N2VsDeltaEtaDeltaPhi_%s%s", tnames[isp].c_str(), tnames[jsp].c_str()), + HTITLESTRING("%s%s pairs", tnames[isp].c_str(), tnames[jsp].c_str()), kTH2F, {deltaEtaAxis, deltaPhiAxis}); + fhInSectorDeltaPhiVsPhiPhiPerPtBinA[kindOfData][isp][jsp] = ADDHISTOGRAM(THnSparse, DIRECTORYSTRING("%s/%s/%s", dirname, recogen.c_str(), "After"), HNAMESTRING("DeltaPhiVsPhiPhiPt_%s%s", tnames[isp].c_str(), tnames[jsp].c_str()), + HTITLESTRING("%s%s pairs, #it{p}_{T}: %s", tnames[isp].c_str(), tnames[jsp].c_str(), hPtRangesOfInterestTitle.c_str()), + kTHnSparseF, {phiSectorAxis, phiSectorAxis, deltaPhiInSectorAxis, ptOfInterestAxis, ptOfInterestAxis}); + fhInSectorDeltaPhiVsEtaEtaPerPtBinA[kindOfData][isp][jsp] = ADDHISTOGRAM(THnSparse, DIRECTORYSTRING("%s/%s/%s", dirname, recogen.c_str(), "After"), HNAMESTRING("DeltaPhiVsEtaEtaPt_%s%s", tnames[isp].c_str(), tnames[jsp].c_str()), + HTITLESTRING("%s%s pairs, #it{p}_{T}: %s", tnames[isp].c_str(), tnames[jsp].c_str(), hPtRangesOfInterestTitle.c_str()), + kTHnSparseF, {etaAxis, etaAxis, deltaPhiInSectorAxis, ptOfInterestAxis, ptOfInterestAxis}); + } + } + } + + template + void processTrackPairs(TracksObject const& tracks1, TracksObject const& tracks2) + { + using namespace efficiencyandqatask; + using namespace analysis::dptdptfilter; + float deltaEtaSpan = etaup - etalow; + + /* we should only receive accepted tracks */ + for (auto const& track1 : tracks1) { + auto binForPt = [&](auto const& track) { + return ptOfInterestBinMap[ptAxis.FindFixBin(track.pt())]; + }; + int ptBin1 = binForPt(track1); + if (ptBin1 != kBinNotTracked) { + float inTpcSectorPhi1 = std::fmod(track1.phi(), kTpcPhiSectorWidth); + for (auto const& track2 : tracks2) { + /* checking the same track id condition */ + if (track1 == track2) { + /* exclude autocorrelations */ + continue; + } + int ptBin2 = binForPt(track2); + if (ptBin2 != kBinNotTracked) { + float deltaPhi = RecoDecay::constrainAngle(track1.phi() - track2.phi()); + float deltaEta = track1.eta() - track2.eta(); + float preWeight = 1 - std::abs(deltaEta) / deltaEtaSpan; + float weight = preWeight != 0 ? 1.0f / preWeight : 0.0f; + fhPhiPhiA[kindOfData][track1.trackacceptedid()][track2.trackacceptedid()]->Fill(track1.phi(), track2.phi(), weight); + fhEtaEtaA[kindOfData][track1.trackacceptedid()][track2.trackacceptedid()]->Fill(track1.eta(), track2.eta()); + fhN2VsDeltaEtaVsDeltaPhi[kindOfData][track1.trackacceptedid()][track2.trackacceptedid()]->Fill(deltaEta, deltaPhi, weight); + if (static_cast(track1.phi() / kTpcPhiSectorWidth) == static_cast(track2.phi() / kTpcPhiSectorWidth)) { + /* only if, for sure, both tracks are within the same sector */ + float inTpcSectorPhi2 = std::fmod(track2.phi(), kTpcPhiSectorWidth); + float inTpcSectorDeltaPhi = inTpcSectorPhi1 - inTpcSectorPhi2; + double values[] = {inTpcSectorPhi1, inTpcSectorPhi2, inTpcSectorDeltaPhi, static_cast(ptBin1), static_cast(ptBin2)}; + fhInSectorDeltaPhiVsPhiPhiPerPtBinA[kindOfData][track1.trackacceptedid()][track2.trackacceptedid()]->Fill(values, weight); + values[0] = track1.eta(), values[1] = track2.eta(); + fhInSectorDeltaPhiVsEtaEtaPerPtBinA[kindOfData][track1.trackacceptedid()][track2.trackacceptedid()]->Fill(values, weight); + } + } + } + } + } + } +}; + +/* the PID data collecting engine */ +struct PidDataCollectingEngine { + uint nsp = static_cast(efficiencyandqatask::tnames.size()); + uint nmainsp = static_cast(efficiencyandqatask::mainspnames.size()); + uint nallmainsp = static_cast(efficiencyandqatask::allmainspnames.size()); + + constexpr static uint kNoOfSteps = 2; /* Before and after track selection */ + + /* PID histograms */ + /* before and after */ + std::vector> fhTPCdEdxSignalVsP{kNoOfSteps, nullptr}; + std::vector>> fhTPCdEdxSignalDiffVsP{kNoOfSteps, {nmainsp, nullptr}}; + std::vector>> fhTPCnSigmasVsP{kNoOfSteps, {nallmainsp, nullptr}}; + std::vector> fhTOFSignalVsP{kNoOfSteps, nullptr}; + std::vector>> fhTOFSignalDiffVsP{kNoOfSteps, {nmainsp, nullptr}}; + std::vector>> fhTOFnSigmasVsP{kNoOfSteps, {nallmainsp, nullptr}}; + std::vector> fhPvsTOFSqMass{kNoOfSteps, nullptr}; + std::vector>> fhTPCTOFSigmaVsP{kNoOfSteps, {nmainsp, nullptr}}; + + template + void init(HistogramRegistry& registry, const char* dirname) + { + using namespace efficiencyandqatask; + + const AxisSpec dEdxAxis{200, 0.0, 200.0, "dE/dx (au)"}; + AxisSpec pidPAxis{150, 0.1, 5.0, "#it{p} (GeV/#it{c})"}; + pidPAxis.makeLogarithmic(); + + if constexpr (kindOfData == kReco) { + /* PID histograms */ + std::vector whenname{"Before", "After"}; + constexpr char whenprefix[kNoOfSteps]{'B', 'A'}; + std::vector whentitle{"before", ""}; + for (uint ix = 0; ix < kNoOfSteps; ++ix) { + fhTPCdEdxSignalVsP[ix] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", whenname[ix].c_str()), + HNAMESTRING("tpcSignalVsP%c", whenprefix[ix]), + HTITLESTRING("TPC dE/dx signal %s", whentitle[ix].c_str()), kTH2F, {pidPAxis, dEdxAxis}); + fhTOFSignalVsP[ix] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", whenname[ix].c_str()), + HNAMESTRING("tofSignalVsP%c", whenprefix[ix]), + HTITLESTRING("TOF signal %s", whentitle[ix].c_str()), + kTH2F, {pidPAxis, {200, 0.0, 1.1, "#beta"}}); + fhPvsTOFSqMass[ix] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", whenname[ix].c_str()), + HNAMESTRING("tofPvsMassSq%c", whenprefix[ix]), + HTITLESTRING("Momentum versus #it{m}^{2} %s", whentitle[ix].c_str()), + kTH2F, {{140, 0.0, 1.4, "#it{m}^{2} ((GeV/c^{2})^{2})"}, pidPAxis}); + for (uint isp = 0; isp < nmainsp; ++isp) { + fhTPCdEdxSignalDiffVsP[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", whenname[ix].c_str()), + HNAMESTRING("tpcSignalDiffVsP%c_%s", whenprefix[ix], mainspnames[isp].c_str()), + HTITLESTRING("TPC dE/dx to the %s line %s", mainsptitles[isp].c_str(), whentitle[ix].c_str()), + kTH2F, {pidPAxis, {400, -200.0, 200.0, FORMATSTRING("dE/dx - _{%s}", mainsptitles[isp].c_str())}}); + fhTOFSignalDiffVsP[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", whenname[ix].c_str()), + HNAMESTRING("tofSignalDiffVsP%c_%s", whenprefix[ix], mainspnames[isp].c_str()), + HTITLESTRING("#Delta^{TOF_{%s}} %s", mainsptitles[isp].c_str(), whentitle[ix].c_str()), + kTH2F, {pidPAxis, {200, -1000.0, 1000.0, FORMATSTRING("t-t_{ev}-t_{exp_{%s}} (ps)", mainsptitles[isp].c_str())}}); + fhTPCTOFSigmaVsP[ix][isp] = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", whenname[ix].c_str()), + HNAMESTRING("toftpcNSigmasVsP%c_%s", whenprefix[ix], mainspnames[isp].c_str()), + HTITLESTRING("n#sigma to the %s line %s", mainsptitles[isp].c_str(), whentitle[ix].c_str()), + kTH3F, {pidPAxis, {noOfNSigmaBins, minNSigma, maxNSigma, FORMATSTRING("n#sigma_{TPC}^{%s}", mainsptitles[isp].c_str())}, {120, -6.0, 6.0, FORMATSTRING("n#sigma_{TOF}^{%s}", mainsptitles[isp].c_str())}}); + } + for (uint isp = 0; isp < nallmainsp; ++isp) { + fhTPCnSigmasVsP[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", whenname[ix].c_str()), + HNAMESTRING("tpcNSigmasVsP%c_%s", whenprefix[ix], allmainspnames[isp].c_str()), + HTITLESTRING("TPC n#sigma to the %s line %s", allmainsptitles[isp].c_str(), whentitle[ix].c_str()), + kTH2F, {pidPAxis, {noOfNSigmaBins, minNSigma, maxNSigma, FORMATSTRING("n#sigma_{TPC}^{%s}", allmainsptitles[isp].c_str())}}); + fhTOFnSigmasVsP[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", whenname[ix].c_str()), + HNAMESTRING("tofNSigmasVsP%c_%s", whenprefix[ix], allmainspnames[isp].c_str()), + HTITLESTRING("TOF n#sigma to the %s line %s", allmainsptitles[isp].c_str(), whentitle[ix].c_str()), + kTH2F, {pidPAxis, {noOfNSigmaBins, minNSigma, maxNSigma, FORMATSTRING("n#sigma_{TOF}^{%s}", allmainsptitles[isp].c_str())}}); + } + } + } + } + + template + void fillAllSpeciesPID(uint ix, TrackObject const& track, float tpcmom, float tofmom) + { + if (track.sign() < 0) { + ix = 2 * ix + 1; + } else { + ix = 2 * ix; + } + for (uint when = 0; when < kNoOfSteps; ++when) { + fhTPCnSigmasVsP[when][ix]->Fill(tpcmom, o2::aod::pidutils::tpcNSigma(track)); + fhTOFnSigmasVsP[when][ix]->Fill(tofmom, o2::aod::pidutils::tofNSigma(track)); + if (track.trackacceptedid() < 0) { + /* track not accepted */ + return; + } + } + } + + template + void fillSpeciesPID(uint ix, TrackObject const& track, float tpcmom, float tofmom) + { + if (track.sign() < 0) { + ix = 2 * ix + 1; + } else { + ix = 2 * ix; + } + for (uint when = 0; when < kNoOfSteps; ++when) { + fhTPCdEdxSignalDiffVsP[when][ix]->Fill(tpcmom, o2::aod::pidutils::tpcExpSignalDiff(track)); + fhTOFSignalDiffVsP[when][ix]->Fill(tofmom, o2::aod::pidutils::tofExpSignalDiff(track)); + fhTPCTOFSigmaVsP[when][ix]->Fill(tpcmom, o2::aod::pidutils::tpcNSigma(track), o2::aod::pidutils::tofNSigma(track)); + if (track.trackacceptedid() < 0) { + /* track not accepted */ + return; + } + } + } + + template + void fillPID(TrackObject const& track, float tpcmom, float tofmom) + { + for (uint when = 0; when < kNoOfSteps; ++when) { + if constexpr (framework::has_type_v) { + fhTPCdEdxSignalVsP[when]->Fill(tpcmom, track.mcTunedTPCSignal()); + } else { + fhTPCdEdxSignalVsP[when]->Fill(tpcmom, track.tpcSignal()); + } + fhTOFSignalVsP[when]->Fill(tofmom, track.beta()); + fhPvsTOFSqMass[when]->Fill(track.mass() * track.mass(), tofmom); + if (track.trackacceptedid() < 0) { + /* track not accepted */ + return; + } + } + } + + template + void processTrack(TrackObject const& track, float tpcmom, float tofmom) + { + using namespace efficiencyandqatask; + + if constexpr (kindOfData == kReco) { + fillPID(track, tpcmom, tofmom); + fillSpeciesPID(0, track, tpcmom, tofmom); + fillSpeciesPID(1, track, tpcmom, tofmom); + fillSpeciesPID(2, track, tpcmom, tofmom); + fillAllSpeciesPID(0, track, tpcmom, tofmom); + fillAllSpeciesPID(1, track, tpcmom, tofmom); + fillAllSpeciesPID(2, track, tpcmom, tofmom); + fillAllSpeciesPID(3, track, tpcmom, tofmom); + fillAllSpeciesPID(4, track, tpcmom, tofmom); + } + } +}; + +/* the PID extra data collecting engine */ +struct PidExtraDataCollectingEngine { + uint nsp = static_cast(efficiencyandqatask::tnames.size()); + uint nmainsp = static_cast(efficiencyandqatask::mainspnames.size()); + uint nallmainsp = static_cast(efficiencyandqatask::allmainspnames.size()); + + /* PID histograms */ + /* only after track selection */ + std::vector> fhIdTPCdEdxSignalVsP{nsp, nullptr}; + std::vector> fpIdTPCdEdxSignalVsPSigmas{nsp, nullptr}; + std::vector>> fhIdTPCdEdxSignalDiffVsP{nsp, {nmainsp, nullptr}}; + std::vector>> fhIdTPCnSigmasVsP{nsp, {nallmainsp, nullptr}}; + std::vector> fhIdTOFSignalVsP{nsp, nullptr}; + std::vector> fpIdTOFSignalVsPSigmas{nsp, nullptr}; + std::vector>> fhIdTOFSignalDiffVsP{nsp, {nmainsp, nullptr}}; + std::vector>> fhIdTOFnSigmasVsP{nsp, {nallmainsp, nullptr}}; + std::vector> fhIdPvsTOFSqMass{nsp, nullptr}; + + template + void init(HistogramRegistry& registry, const char* dirname) + { + using namespace efficiencyandqatask; + + const AxisSpec dEdxAxis{200, 0.0, 200.0, "dE/dx (au)"}; + AxisSpec pidPAxis{150, 0.1, 5.0, "#it{p} (GeV/#it{c})"}; + pidPAxis.makeLogarithmic(); + constexpr int kEvenOddBase = 2; + + if constexpr (kindOfData == kReco) { + /* PID histograms */ + for (uint isp = 0; isp < nsp; ++isp) { + fhIdTPCdEdxSignalVsP[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", "Selected"), + HNAMESTRING("tpcSignalVsPSelected_%s", tnames[isp].c_str()), + HTITLESTRING("TPC dE/dx for selected %s", tnames[isp].c_str()), + kTH2F, {pidPAxis, dEdxAxis}); + fpIdTPCdEdxSignalVsPSigmas[isp] = ADDHISTOGRAM(TProfile2D, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", "Selected"), + HNAMESTRING("tpcSignalSigmasVsPSelected_%s", tnames[isp].c_str()), + HTITLESTRING("TPC dE/dx and n#sigma for selected %s", tnames[isp].c_str()), + kTProfile2D, {pidPAxis, dEdxAxis}); + fhIdTOFSignalVsP[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", "Selected"), + HNAMESTRING("tofSignalVsPSelected_%s", tnames[isp].c_str()), + HTITLESTRING("TOF signal for selected %s", tnames[isp].c_str()), + kTH2F, {pidPAxis, {200, 0.0, 1.1, "#beta"}}); + fpIdTOFSignalVsPSigmas[isp] = ADDHISTOGRAM(TProfile2D, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", "Selected"), + HNAMESTRING("tofSignalSigmasVsPSelected_%s", tnames[isp].c_str()), + HTITLESTRING("TOF signal and n#sigma for selected %s", tnames[isp].c_str()), + kTProfile2D, {pidPAxis, {200, 0.0, 1.1, "#beta"}}); + for (uint imainsp = 0; imainsp < nallmainsp; ++imainsp) { + /* only the same charge makes any sense */ + if (isp % kEvenOddBase == imainsp % kEvenOddBase) { + fhIdTPCnSigmasVsP[isp][imainsp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", "Selected"), + HNAMESTRING("tpcNSigmasVsPSelected_%s_to%s", tnames[isp].c_str(), allmainspnames[imainsp].c_str()), + HTITLESTRING("TPC n#sigma for selected %s to the %s line", tnames[isp].c_str(), allmainsptitles[imainsp].c_str()), + kTH2F, {pidPAxis, {noOfNSigmaBins, minNSigma, maxNSigma, FORMATSTRING("n#sigma_{TPC}^{%s}", mainsptitles[isp].c_str())}}); + fhIdTOFnSigmasVsP[isp][imainsp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", "Selected"), + HNAMESTRING("tofNSigmasVsPSelected_%s_to%s", tnames[isp].c_str(), allmainspnames[imainsp].c_str()), + HTITLESTRING("TOF n#sigma for selected %s to the %s line", tnames[isp].c_str(), allmainsptitles[imainsp].c_str()), + kTH2F, {pidPAxis, {noOfNSigmaBins, minNSigma, maxNSigma, FORMATSTRING("n#sigma_{TOF}^{%s}", mainsptitles[isp].c_str())}}); + } + } + } + } + } + + template + void fillAllSpeciesPID(uint ix, TrackObject const& track, float tpcmom, float tofmom) + { + if (track.trackacceptedid() < 0) { + /* track not accepted */ + return; + } + if (track.sign() < 0) { + ix = 2 * ix + 1; + } else { + ix = 2 * ix; + } + fhIdTPCnSigmasVsP[track.trackacceptedid()][ix]->Fill(tpcmom, o2::aod::pidutils::tpcNSigma(track)); + fhIdTOFnSigmasVsP[track.trackacceptedid()][ix]->Fill(tofmom, o2::aod::pidutils::tofNSigma(track)); + if (efficiencyandqatask::pidselector.isGlobalSpecies(track.trackacceptedid() / 2, id)) { + /* only if the species of the selected track matches the target of the number of sigmas */ + if constexpr (framework::has_type_v) { + fpIdTPCdEdxSignalVsPSigmas[track.trackacceptedid()]->Fill(tpcmom, track.mcTunedTPCSignal(), o2::aod::pidutils::tpcNSigma(track)); + } else { + fpIdTPCdEdxSignalVsPSigmas[track.trackacceptedid()]->Fill(tpcmom, track.tpcSignal(), o2::aod::pidutils::tpcNSigma(track)); + } + fpIdTOFSignalVsPSigmas[track.trackacceptedid()]->Fill(tofmom, track.beta(), o2::aod::pidutils::tofNSigma(track)); + } + } + + template + void fillSpeciesPID(uint, TrackObject const&, float, float) + { + } + + template + void fillPID(TrackObject const& track, float tpcmom, float tofmom) + { + if (track.trackacceptedid() < 0) { + /* track not accepted */ + return; + } + if constexpr (framework::has_type_v) { + fhIdTPCdEdxSignalVsP[track.trackacceptedid()]->Fill(tpcmom, track.mcTunedTPCSignal()); + } else { + fhIdTPCdEdxSignalVsP[track.trackacceptedid()]->Fill(tpcmom, track.tpcSignal()); + } + fhIdTOFSignalVsP[track.trackacceptedid()]->Fill(tofmom, track.beta()); + } + + template + void processTrack(TrackObject const& track, float tpcmom, float tofmom) + { + using namespace efficiencyandqatask; + + if constexpr (kindOfData == kReco) { + fillPID(track, tpcmom, tofmom); + fillSpeciesPID(0, track, tpcmom, tofmom); + fillSpeciesPID(1, track, tpcmom, tofmom); + fillSpeciesPID(2, track, tpcmom, tofmom); + fillAllSpeciesPID(0, track, tpcmom, tofmom); + fillAllSpeciesPID(1, track, tpcmom, tofmom); + fillAllSpeciesPID(2, track, tpcmom, tofmom); + fillAllSpeciesPID(3, track, tpcmom, tofmom); + fillAllSpeciesPID(4, track, tpcmom, tofmom); + } + } +}; + +struct DptDptEfficiencyAndQc { + /* the data memebers for this task */ + /* the centrality / multiplicity limits for collecting data in this task instance */ + uint ncmranges = 0; + float* fCentMultMin = nullptr; + float* fCentMultMax = nullptr; + + /* the data collecting engine instances */ + QADataCollectingEngine** qaDataCE; + QAExtraDataCollectingEngine** qaExtraDataCE; + PidDataCollectingEngine** pidDataCE; + PidExtraDataCollectingEngine** pidExtraDataCE; + + /* the histogram registries */ + HistogramRegistry registryOne{"registryOne", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryTwo{"registryTwo", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryThree{"registryThree", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryFour{"registryFour", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryFive{"registryFive", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registrySix{"registrySix", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registrySeven{"registrySeven", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryEight{"registryEight", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryNine{"registryNine", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryTen{"registryTen", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryExtraOne{"extraregistryOne", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryExtraTwo{"extraregistryTwo", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryExtraThree{"extraregistryThree", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryExtraFour{"extraregistryFour", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryExtraFive{"extraregistryFive", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryExtraSix{"extraregistrySix", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryExtraSeven{"extraregistrySeven", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryExtraEight{"extraregistryEight", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryExtraNine{"extraregistryNine", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryExtraTen{"extraregistryTen", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryPidOne{"pidregistryOne", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryPidTwo{"pidregistryTwo", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryPidThree{"pidregistryThree", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryPidFour{"pidregistryFour", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryPidFive{"pidregistryFive", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryPidSix{"pidregistrySix", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryPidSeven{"pidregistrySeven", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryPidEight{"pidregistryEight", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryPidNine{"pidregistryNine", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryPidTen{"pidregistryTen", {}, OutputObjHandlingPolicy::AnalysisObject}; + std::vector registryBank{®istryOne, ®istryTwo, ®istryThree, ®istryFour, ®istryFive, + ®istrySix, ®istrySeven, ®istryEight, ®istryNine, ®istryTen}; + std::vector extraRegistryBank{®istryExtraOne, ®istryExtraTwo, ®istryExtraThree, ®istryExtraFour, ®istryExtraFive, + ®istryExtraSix, ®istryExtraSeven, ®istryExtraEight, ®istryExtraNine, ®istryExtraTen}; + std::vector pidRegistryBank{®istryPidOne, ®istryPidTwo, ®istryPidThree, ®istryPidFour, ®istryPidFive, + ®istryPidSix, ®istryPidSeven, ®istryPidEight, ®istryPidNine, ®istryPidTen}; + + Configurable useCentrality{"useCentrality", false, "Perform the task using centrality/multiplicity classes. Default value: false"}; + Configurable useTPCInnerWallMomentum{"useTPCInnerWallMomentum", false, "Use the TPC inner wall momentum. Default: false"}; + Configurable cfgMinNSigma{"cfgMinNSigma", -4.05f, "nsigma axes lowest value. Default: -4.05"}; + Configurable cfgMaxNSigma{"cfgMaxNSigma", 4.05f, "nsigma axes highest value. Default: 4.05"}; + Configurable cfgWidthNSigmaBin{"cfgWidthNSigmaBin", 0.1, "nsigma axes bin width. Deafault: 0.1"}; + Configurable> cfgPtBinsOfInterest{"cfgPtBinsOfInterest", {1, 2, 3}, "The pt bins of interest"}; + + void init(o2::framework::InitContext& initContext) + { + using namespace efficiencyandqatask; + using namespace analysis::dptdptfilter; + + /* do nothing if not active */ + if (!doprocessDetectorLevelNotStored && + !doprocessExtraDetectorLevelNotStored && + !doprocessDetectorLevelNotStoredPID && + !doprocessDetectorLevelNotStoredTunedOnDataPID && + !doprocessDetectorLevelNotStoredPIDExtra && + !doprocessDetectorLevelNotStoredTunedOnDataPIDExtra && + !doprocessGeneratorLevelNotStored && + !doprocessExtraGeneratorLevelNotStored && + !doprocessReconstructedNotStored && + !doprocessExtraReconstructedNotStored && + !doprocessReconstructedNotStoredPID && + !doprocessReconstructedNotStoredPIDExtra) { + return; + } + + /* Self configuration: requires dptdptfilter task in the workflow */ + { + /* the binning */ + getTaskOptionValue(initContext, "dpt-dpt-filter", "overallminp", overallminp, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mZVtxbins", zvtxbins, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mZVtxmin", zvtxlow, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mZVtxmax", zvtxup, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mPTbins", ptbins, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mPTmin", ptlow, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mPTmax", ptup, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mEtabins", etabins, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mEtamin", etalow, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mEtamax", etaup, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mPhibins", phibins, false); + + /* configuring the involved species */ + std::vector cfgnames = {"elpidsel", "mupidsel", "pipidsel", "kapidsel", "prpidsel"}; + std::vector spids = {0, 1, 2, 3, 4}; + for (uint i = 0; i < cfgnames.size(); ++i) { + auto includeIt = [&initContext](int spid, auto name) { + bool mUseIt = false; + bool mExcludeIt = false; + if (getTaskOptionValue(initContext, "dpt-dpt-filter-tracks", TString::Format("%s.mUseIt", name.c_str()).Data(), mUseIt, false) && + getTaskOptionValue(initContext, "dpt-dpt-filter-tracks", TString::Format("%s.mExclude", name.c_str()).Data(), mExcludeIt, false)) { + if (mUseIt && !mExcludeIt) { + auto cfg = new o2::analysis::TrackSelectionPIDCfg(); + cfg->mUseIt = true; + cfg->mExclude = false; + pidselector.addSpecies(spid, cfg); + } + } + }; + includeIt(spids[i], cfgnames[i]); + } + uint nspecies = pidselector.getNSpecies(); + if (nspecies == 0) { + /* unidentified analysis */ + poinames.push_back(pidselector.getHadFName()); + tnames.push_back(std::string(TString::Format("%sP", pidselector.getHadFName()).Data())); + tnames.push_back(std::string(TString::Format("%sM", pidselector.getHadFName()).Data())); + LOGF(info, "Incorporated species name %s to the analysis", poinames[0].c_str()); + } else { + for (uint8_t ix = 0; ix < nspecies; ++ix) { + poinames.push_back(std::string(pidselector.getSpeciesFName(ix))); + tnames.push_back(std::string(TString::Format("%sP", pidselector.getSpeciesFName(ix)).Data())); + tnames.push_back(std::string(TString::Format("%sM", pidselector.getSpeciesFName(ix)).Data())); + LOGF(info, "Incorporated species name %s to the analysis", poinames[ix].c_str()); + } + } + + /* create the data collecting engine instances according to the configured centrality/multiplicity ranges */ + std::string centspec; + if (useCentrality.value && getTaskOptionValue(initContext, "dpt-dpt-filter", "centralities", centspec, false)) { + LOGF(info, "Got the centralities specification: %s", centspec.c_str()); + auto tokens = TString(centspec.c_str()).Tokenize(","); + ncmranges = tokens->GetEntries(); + fCentMultMin = new float[ncmranges]; + fCentMultMax = new float[ncmranges]; + for (uint i = 0; i < ncmranges; ++i) { + float cmmin = 0.0f; + float cmmax = 0.0f; + sscanf(tokens->At(i)->GetName(), "%f-%f", &cmmin, &cmmax); + fCentMultMin[i] = cmmin; + fCentMultMax[i] = cmmax; + } + delete tokens; + } else { + LOGF(info, "No centralities specification. Setting it to: 0-100"); + ncmranges = 1; + fCentMultMin = new float[ncmranges]; + fCentMultMax = new float[ncmranges]; + fCentMultMin[0] = 0.0f; + fCentMultMax[0] = 100.0f; + } + /* configure nsigma axes */ + minNSigma = cfgMinNSigma.value; + maxNSigma = cfgMaxNSigma.value; + widthNSigmaBin = cfgWidthNSigmaBin.value; + noOfNSigmaBins = static_cast((maxNSigma - minNSigma) / widthNSigmaBin); + + /* configure the pT bins of interest */ + TAxis ptAxis{ptbins, ptlow, ptup}; + for (const int& bin : cfgPtBinsOfInterest.value) { + ptBinsOfInterest.push_back(bin); + LOGF(info, "Inserted pT bin %d: %.2f < pT < %.2f GeV/c", bin, ptAxis.GetBinLowEdge(bin), ptAxis.GetBinUpEdge(bin)); + } + + bool doBasicAnalysis = doprocessDetectorLevelNotStored || doprocessReconstructedNotStored || doprocessGeneratorLevelNotStored; + bool doExtraAnalysis = doprocessExtraDetectorLevelNotStored || doprocessExtraReconstructedNotStored || doprocessExtraGeneratorLevelNotStored; + bool doPidAnalysis = doprocessDetectorLevelNotStoredPID || doprocessDetectorLevelNotStoredTunedOnDataPID || doprocessReconstructedNotStoredPID; + bool doPidExtraAnalysis = doprocessDetectorLevelNotStoredPIDExtra || doprocessDetectorLevelNotStoredTunedOnDataPIDExtra || doprocessReconstructedNotStoredPIDExtra; + + if (doBasicAnalysis) { + qaDataCE = new QADataCollectingEngine*[ncmranges]; + } + if (doExtraAnalysis) { + qaExtraDataCE = new QAExtraDataCollectingEngine*[ncmranges]; + } + if (doPidAnalysis) { + pidDataCE = new PidDataCollectingEngine*[ncmranges]; + } + if (doPidExtraAnalysis) { + pidExtraDataCE = new PidExtraDataCollectingEngine*[ncmranges]; + } + std::string recogen; + if (ncmranges > registryBank.size()) { + LOGF(fatal, "There are more centrality ranges configured than registries in the bank. Please fix it!"); + } + /* in reverse order for proper order in results file */ + for (uint i = 0; i < ncmranges; ++i) { + auto initializeCEInstance = [&](auto dce, auto name, auto& registry, bool reclevel, bool genlevel) { + /* crete the output list for the passed centrality/multiplicity range */ + /* init the data collection instance */ + if (reclevel) { + dce->template init(registry, name.Data()); + } + if (genlevel) { + dce->template init(registry, name.Data()); + } + }; + auto buildQACEInstance = [&](float min, float max) { + auto* dce = new QADataCollectingEngine(); + initializeCEInstance(dce, TString::Format("EfficiencyAndQaData-%d-%d", static_cast(min), static_cast(max)), *registryBank[i], + doprocessReconstructedNotStored || doprocessDetectorLevelNotStored, doprocessGeneratorLevelNotStored); + return dce; + }; + auto buildQACEExtraInstance = [&](float min, float max) { + auto* dce = new QAExtraDataCollectingEngine(); + initializeCEInstance(dce, TString::Format("EfficiencyAndQaExtraData-%d-%d", static_cast(min), static_cast(max)), *extraRegistryBank[i], + doprocessExtraReconstructedNotStored || doprocessExtraDetectorLevelNotStored, doprocessExtraGeneratorLevelNotStored); + return dce; + }; + auto buildPidCEInstance = [&](float min, float max) { + auto* dce = new PidDataCollectingEngine(); + initializeCEInstance(dce, TString::Format("EfficiencyAndPidData-%d-%d", static_cast(min), static_cast(max)), *pidRegistryBank[i], + doprocessReconstructedNotStoredPID || doprocessDetectorLevelNotStoredPID || doprocessDetectorLevelNotStoredTunedOnDataPID, doprocessGeneratorLevelNotStored); + return dce; + }; + auto buildPidExtraCEInstance = [&](float min, float max) { + auto* dce = new PidExtraDataCollectingEngine(); + initializeCEInstance(dce, TString::Format("EfficiencyAndPidData-%d-%d", static_cast(min), static_cast(max)), *pidRegistryBank[i], + doprocessReconstructedNotStoredPIDExtra || doprocessDetectorLevelNotStoredPIDExtra || doprocessDetectorLevelNotStoredTunedOnDataPIDExtra, doprocessGeneratorLevelNotStored); + return dce; + }; + /* in reverse order for proper order in results file */ + if (doBasicAnalysis) { + qaDataCE[ncmranges - i - 1] = buildQACEInstance(fCentMultMin[ncmranges - i - 1], fCentMultMax[ncmranges - i - 1]); + } + if (doExtraAnalysis) { + qaExtraDataCE[ncmranges - i - 1] = buildQACEExtraInstance(fCentMultMin[ncmranges - i - 1], fCentMultMax[ncmranges - i - 1]); + } + if (doPidAnalysis) { + pidDataCE[ncmranges - i - 1] = buildPidCEInstance(fCentMultMin[ncmranges - i - 1], fCentMultMax[ncmranges - i - 1]); + } + if (doPidExtraAnalysis) { + pidExtraDataCE[ncmranges - i - 1] = buildPidExtraCEInstance(fCentMultMin[ncmranges - i - 1], fCentMultMax[ncmranges - i - 1]); + } + } + for (uint i = 0; i < ncmranges; ++i) { + LOGF(info, " centrality/multipliicty range: %d, low limit: %0.2f, up limit: %0.2f", i, fCentMultMin[i], fCentMultMax[i]); + } + } + } + + /// \brief Get the data collecting engine index corresponding to the passed collision + template + int getDCEindex(FilteredCollision collision) + { + if (!useCentrality.value) { + return 0; + } else { + int ixDCE = -1; + float cm = collision.centmult(); + for (uint i = 0; i < ncmranges; ++i) { + if (cm < fCentMultMax[i]) { + ixDCE = i; + break; + } + } + if (!(ixDCE < 0)) { + if (cm < fCentMultMin[ixDCE]) { + ixDCE = -1; + } + } + return ixDCE; + } + } + + template + void processTracks(FilteredCollisions::iterator const& collision, PassedTracks const& tracks) + { + using namespace efficiencyandqatask; + + int ixDCE = getDCEindex(collision); + if (!(ixDCE < 0)) { + if constexpr (kindOfProcess == kBASIC) { + qaDataCE[ixDCE]->newCollision(); + } + if constexpr (kindOfProcess == kEXTRA) { + qaExtraDataCE[ixDCE]->processTrackPairs(tracks, tracks); + } + if constexpr (kindOfProcess == kBASIC || kindOfProcess == kPID || kindOfProcess == kPIDEXTRA) { + for (auto const& track : tracks) { + float tpcmom = track.p(); + float tofmom = track.p(); + if (useTPCInnerWallMomentum.value) { + if constexpr (!framework::has_type_v) { + tpcmom = track.tpcInnerParam(); + } + } + if constexpr (kindOfProcess == kBASIC) { + qaDataCE[ixDCE]->processTrack(collision.posZ(), track); + } + if constexpr (kindOfProcess == kPID) { + pidDataCE[ixDCE]->processTrack(track, tpcmom, tofmom); + } + if constexpr (kindOfProcess == kPIDEXTRA) { + pidExtraDataCE[ixDCE]->processTrack(track, tpcmom, tofmom); + } + } + } + if constexpr (kindOfProcess == kBASIC) { + qaDataCE[ixDCE]->finishedCollision(); + } + } + } + + void process(aod::Collisions const& collisions) + { + /* void function for alow processing the timestamp check task on faulty productions */ + LOGF(debug, "Received %d collisions", collisions.size()); + } + + using TpcPID = soa::Join; + using TofPID = soa::Join; + + Filter onlyacceptedcollisions = (aod::dptdptfilter::collisionaccepted == uint8_t(true)); + Filter onlyacceptedtracks = (aod::dptdptfilter::trackacceptedid >= int8_t(0)); + + void processReconstructedNotStored(soa::Filtered>::iterator const& collision, + soa::Join const& tracks) + { + using namespace efficiencyandqatask; + + processTracks>, kBASIC, kReco>(collision, tracks); + } + PROCESS_SWITCH(DptDptEfficiencyAndQc, processReconstructedNotStored, "Process reconstructed efficiency and QA for not stored derived data", false); + + void processDetectorLevelNotStored(soa::Filtered>::iterator const& collision, + soa::Join const& tracks, + soa::Join const&) + { + using namespace efficiencyandqatask; + + processTracks>, kBASIC, kReco>(collision, tracks); + } + PROCESS_SWITCH(DptDptEfficiencyAndQc, processDetectorLevelNotStored, "Process MC detector level efficiency and QA for not stored derived data", false); + + void processGeneratorLevelNotStored(soa::Filtered>::iterator const& collision, + soa::Join const& particles) + { + using namespace efficiencyandqatask; + + processTracks>, kBASIC, kGen>(collision, particles); + } + PROCESS_SWITCH(DptDptEfficiencyAndQc, processGeneratorLevelNotStored, "Process MC generator level efficiency and QA for not stored derived data", true); + + void processExtraReconstructedNotStored(soa::Filtered>::iterator const& collision, + soa::Filtered> const& tracks) + { + using namespace efficiencyandqatask; + + processTracks>, kEXTRA, kReco>(collision, tracks); + } + PROCESS_SWITCH(DptDptEfficiencyAndQc, processExtraReconstructedNotStored, "Process reconstructed extra efficiency and QA for not stored derived data", false); + + void processExtraDetectorLevelNotStored(soa::Filtered>::iterator const& collision, + soa::Filtered> const& tracks, + soa::Join const&) + { + using namespace efficiencyandqatask; + + processTracks>, kEXTRA, kReco>(collision, tracks); + } + PROCESS_SWITCH(DptDptEfficiencyAndQc, processExtraDetectorLevelNotStored, "Process MC detector level extra efficiency and QA for not stored derived data", false); + + void processExtraGeneratorLevelNotStored(soa::Filtered>::iterator const& collision, + soa::Filtered> const& particles) + { + using namespace efficiencyandqatask; + + processTracks>, kEXTRA, kGen>(collision, particles); + } + PROCESS_SWITCH(DptDptEfficiencyAndQc, processExtraGeneratorLevelNotStored, "Process MC generator level extra efficiency and QA for not stored derived data", true); + + void processReconstructedNotStoredPID(soa::Filtered>::iterator const& collision, + soa::Join const& tracks) + { + using namespace efficiencyandqatask; + + processTracks>, kPID, kReco>(collision, tracks); + } + PROCESS_SWITCH(DptDptEfficiencyAndQc, processReconstructedNotStoredPID, "Process reconstructed PID QA for not stored derived data", false); + + void processReconstructedNotStoredPIDExtra(soa::Filtered>::iterator const& collision, + soa::Join const& tracks) + { + using namespace efficiencyandqatask; + + processTracks>, kPIDEXTRA, kReco>(collision, tracks); + } + PROCESS_SWITCH(DptDptEfficiencyAndQc, processReconstructedNotStoredPIDExtra, "Process reconstructed PID extra QA for not stored derived data", false); + + void processDetectorLevelNotStoredPID(soa::Filtered>::iterator const& collision, + soa::Join const& tracks, + soa::Join const&) + { + using namespace efficiencyandqatask; + + processTracks>, kPID, kReco>(collision, tracks); + } + PROCESS_SWITCH(DptDptEfficiencyAndQc, processDetectorLevelNotStoredPID, "Process MC detector level PID QA for not stored derived data", false); + + void processDetectorLevelNotStoredTunedOnDataPID(soa::Filtered>::iterator const& collision, + soa::Join const& tracks, + soa::Join const&) + { + using namespace efficiencyandqatask; + + processTracks>, kPID, kReco>(collision, tracks); + } + PROCESS_SWITCH(DptDptEfficiencyAndQc, processDetectorLevelNotStoredTunedOnDataPID, "Process MC detector level tuned on data PID QA for not stored derived data", true); + + void processDetectorLevelNotStoredPIDExtra(soa::Filtered>::iterator const& collision, + soa::Join const& tracks, + soa::Join const&) + { + using namespace efficiencyandqatask; + + processTracks>, kPIDEXTRA, kReco>(collision, tracks); + } + PROCESS_SWITCH(DptDptEfficiencyAndQc, processDetectorLevelNotStoredPIDExtra, "Process MC detector level PID extra QA for not stored derived data", false); + + void processDetectorLevelNotStoredTunedOnDataPIDExtra(soa::Filtered>::iterator const& collision, + soa::Join const& tracks, + soa::Join const&) + { + using namespace efficiencyandqatask; + + processTracks>, kPIDEXTRA, kReco>(collision, tracks); + } + PROCESS_SWITCH(DptDptEfficiencyAndQc, processDetectorLevelNotStoredTunedOnDataPIDExtra, "Process MC detector level tuned on data PID extra QA for not stored derived data", true); +}; + +using BCsWithTimestamps = soa::Join; + +struct CheckTimestamp { + + o2::ccdb::CcdbApi ccdbApi; + int mRunNumber; + uint64_t runsor = 0; + uint64_t runeor = 0; + std::shared_ptr hTimeStampDiffNegative = nullptr; + std::shared_ptr hTimeStampDiffPositive = nullptr; + + Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext&) + { + LOG(info) << "Initializing check timestamp task"; + AxisSpec diffAxis{10000, 0.0001, 1000000, "time (s)"}; + diffAxis.makeLogarithmic(); + + hTimeStampDiffNegative = registry.add("DiffNegative", "Time before SOR (s)", kTH2F, {{100, 0.5, 100.5, "Run number"}, diffAxis}); + hTimeStampDiffPositive = registry.add("DiffPositive", "Time after EOR (s)", kTH2F, {{100, 0.5, 100.5, "Run number"}, diffAxis}); + ccdbApi.init(ccdburl); + } + + void process(aod::Collisions const& collisions, BCsWithTimestamps const&) + { + for (auto const& collision : collisions) { + /* check the previous run number */ + auto bc = collision.bc_as(); + if (bc.runNumber() != mRunNumber) { + LOGF(info, "timestamp=%llu, run number=%d", bc.timestamp(), bc.runNumber()); + mRunNumber = bc.runNumber(); + + // read SOR and EOR timestamps from RCT CCDB via utility function + auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, mRunNumber, false); + runeor = soreor.second; + runsor = soreor.first; + } + if (bc.timestamp() < runsor || runeor < bc.timestamp()) { + /* we got a wrong timestamp let's convert the out of run time to seconds */ + if (bc.timestamp() < runsor) { + hTimeStampDiffNegative->Fill(Form("%d", mRunNumber), (runsor - bc.timestamp()) / 1000, 1); + } else { + hTimeStampDiffPositive->Fill(Form("%d", mRunNumber), (bc.timestamp() - runeor) / 1000, 1); + } + } + } + } +}; + +//**************************************************************************************** +/** + * Workflow definition. + */ +//**************************************************************************************** +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/PWGCF/TwoParticleCorrelations/Tasks/dptDptPerRunExtraQc.cxx b/PWGCF/TwoParticleCorrelations/Tasks/dptDptPerRunExtraQc.cxx new file mode 100644 index 00000000000..d6500b88617 --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/Tasks/dptDptPerRunExtraQc.cxx @@ -0,0 +1,101 @@ +// 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 dptDptPerRunExtraQc.cxx +/// \brief basic per run check of the per analyzed species p vs TPC IW momentum +/// \author victor.gonzalez.sebastian@gmail.com + +#include +#include +#include + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "PWGCF/DataModel/DptDptFiltered.h" +#include "PWGCF/TableProducer/dptdptfilter.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +using BCsWithTimestamps = soa::Join; + +namespace perrunextraqc +{ +std::unordered_map gRunMapPvsTpcIwP; +TProfile3D* gCurrentRunPvsPtcIwP; +} // namespace perrunextraqc + +struct DptDptPerRunExtraQc { + int mRunNumber{-1}; + AxisSpec qaPAxis{150, 0.1, 5.0}; + + HistogramRegistry mHistos{"PerRunExtraQcHistograms", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void initRunNumber(aod::BCsWithTimestamps::iterator const& bc) + { + using namespace perrunextraqc; + + if (mRunNumber == bc.runNumber()) { + return; + } else { + mRunNumber = bc.runNumber(); + if (gRunMapPvsTpcIwP.find(mRunNumber) == gRunMapPvsTpcIwP.end()) { + gRunMapPvsTpcIwP[mRunNumber] = mHistos.add(TString::Format("Reco/%d_pVsTpcIwP", mRunNumber).Data(), ";species;p (GeV/#it{c}); p_{tpciw} (GeV/#it{c})", {HistType::kTProfile3D, {{10, -0.5, 9.5}, qaPAxis, qaPAxis}}).get(); + } + gCurrentRunPvsPtcIwP = gRunMapPvsTpcIwP[mRunNumber]; + } + } + + void init(InitContext&) + { + using namespace perrunextraqc; + + qaPAxis.makeLogarithmic(); + } + + template + void processTracks(PassedTracks const& tracks) + { + using namespace perrunextraqc; + + for (const auto& track : tracks) { + gCurrentRunPvsPtcIwP->Fill(track.trackacceptedid(), track.p(), track.tpcInnerParam(), track.pt()); + } + } + + Filter onlyacceptedcollisions = (aod::dptdptfilter::collisionaccepted == uint8_t(true)); + Filter onlyacceptedtracks = (aod::dptdptfilter::trackacceptedid >= int8_t(0)); + + void process(soa::Filtered>::iterator const& collision, soa::Filtered> const& tracks, aod::BCsWithTimestamps const&) + { + using namespace analysis::dptdptfilter; + + if (!collision.collisionaccepted()) { + return; + } + + auto bc = collision.bc_as(); + initRunNumber(bc); + processTracks(tracks); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/TwoParticleCorrelations/Tasks/dptDptPerRunQc.cxx b/PWGCF/TwoParticleCorrelations/Tasks/dptDptPerRunQc.cxx new file mode 100644 index 00000000000..fb179838563 --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/Tasks/dptDptPerRunQc.cxx @@ -0,0 +1,142 @@ +// 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 dptDptPerRunQc.cxx +/// \brief basic per run check of the ITS dead chips and of the hadronic interaction rate +/// \author victor.gonzalez.sebastian@gmail.com + +#include +#include +#include +#include +#include +#include + +#include "CCDB/BasicCCDBManager.h" +#include "Common/CCDB/ctpRateFetcher.h" + +#include "DataFormatsParameters/AggregatedRunInfo.h" +#include "DataFormatsITSMFT/NoiseMap.h" // missing include in TimeDeadMap.h +#include "DataFormatsITSMFT/TimeDeadMap.h" +#include "ITSMFTReconstruction/ChipMappingITS.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "PWGCF/DataModel/DptDptFiltered.h" +#include "PWGCF/TableProducer/dptdptfilter.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using BCsWithTimestamps = soa::Join; + +namespace perrunqctask +{ +static const int32_t nBCsPerOrbit = o2::constants::lhc::LHCMaxBunches; +std::unordered_map gHadronicRate; +std::unordered_map> gCollisionOrbitBefore; +std::unordered_map> gCollisionOrbitAfter; + +TH2* gCurrentHadronicRate; +std::shared_ptr gCurrentCollisionOrbitBefore; +std::shared_ptr gCurrentCollisionOrbitAfter; +} // namespace perrunqctask + +struct DptDptPerRunQc { + + Service ccdb; + + int mRunNumber{-1}; + double mMinSeconds{-1.}; + + ctpRateFetcher mRateFetcher; + HistogramRegistry mHistos{"PerRunQaHistograms", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable cfgInteractionRateSource{"cfgInteractionRateSource", "ZNC hadronic", "The shource for the interaction rate measure.PbPb:ZNC hadronic;pp:T0VTX.Default:ZNC hadronic"}; + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + using namespace perrunqctask; + using namespace analysis::dptdptfilter; + + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + if (gHadronicRate.find(mRunNumber) == gHadronicRate.end()) { + auto runDuration = ccdb->getRunDuration(mRunNumber); + uint64_t mSOR = runDuration.first; + mMinSeconds = std::floor(mSOR * 1.e-3); /// round tsSOR to the highest integer lower than tsSOR + double maxSec = std::ceil(runDuration.second * 1.e-3); /// round tsEOR to the lowest integer higher than tsEOR + const AxisSpec axisSeconds{static_cast(maxSec - mMinSeconds), 0, maxSec - mMinSeconds, "Seconds since SOR"}; + gHadronicRate[mRunNumber] = mHistos.add(Form("%i/hadronicRate", mRunNumber), ";Time since SOR (s);Hadronic rate (kHz)", kTH2D, {{static_cast((maxSec - mMinSeconds) / 20.f), 0, maxSec - mMinSeconds, "Seconds since SOR"}, {1010, 0., 1010.}}).get(); + + /* initializing the ITS chips dead map orbit axis*/ + /* inspired in DPG/Tasks/AOTEvent/eventSelectionQa.cxx */ + auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), mRunNumber); + int64_t tsSOR = runInfo.sor; + int64_t tsEOR = runInfo.eor; + o2::itsmft::TimeDeadMap* itsDeadMap = ccdb->getForTimeStamp("ITS/Calib/TimeDeadMap", (tsSOR + tsEOR) / 2); + auto itsDeadMapOrbits = itsDeadMap->getEvolvingMapKeys(); // roughly every second, ~350 TFs = 350x32 orbits + if (itsDeadMapOrbits.size() > 0) { + std::vector itsDeadMapOrbitsDouble(itsDeadMapOrbits.begin(), itsDeadMapOrbits.end()); + const AxisSpec axisItsDeadMapOrbits{itsDeadMapOrbitsDouble}; + gCollisionOrbitBefore[mRunNumber] = mHistos.add(TString::Format("%d/Before/hCollisionOrbitB", mRunNumber), "Collision orbit before; orbit", kTH1I, {axisItsDeadMapOrbits}); + gCollisionOrbitAfter[mRunNumber] = mHistos.add(TString::Format("%d/After/hCollisionOrbitA", mRunNumber), "Collision orbit; orbit", kTH1I, {axisItsDeadMapOrbits}); + gCurrentCollisionOrbitBefore = gCollisionOrbitBefore[mRunNumber]; + gCurrentCollisionOrbitAfter = gCollisionOrbitAfter[mRunNumber]; + } else { + gCurrentCollisionOrbitBefore = nullptr; + gCurrentCollisionOrbitAfter = nullptr; + } + LOGF(info, "Run number: %d, SOR: %lld, EOR: %lld, prev SOR: %lld, prev EOR: %lld, SOR seconds: %f", mRunNumber, tsSOR, tsEOR, mSOR, runDuration.second, mMinSeconds); + } + gCurrentHadronicRate = gHadronicRate[mRunNumber]; + } + + void init(o2::framework::InitContext&) + { + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); + } + + void process(soa::Join::iterator const& collision, aod::BCsWithTimestamps const&) + { + using namespace perrunqctask; + using namespace analysis::dptdptfilter; + + auto bc = collision.bc_as(); + initCCDB(bc); + int64_t orbit = bc.globalBC() / nBCsPerOrbit; + gCurrentCollisionOrbitBefore->Fill(orbit); + + if (!collision.collisionaccepted()) { + return; + } + + double hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), mRunNumber, cfgInteractionRateSource) * 1.e-3; // + double seconds = bc.timestamp() * 1.e-3 - mMinSeconds; + gCurrentHadronicRate->Fill(seconds, hadronicRate); + gCurrentCollisionOrbitAfter->Fill(orbit); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/TwoParticleCorrelations/Tasks/efficiencyAndQc.cxx b/PWGCF/TwoParticleCorrelations/Tasks/efficiencyAndQc.cxx deleted file mode 100644 index 9f3807be822..00000000000 --- a/PWGCF/TwoParticleCorrelations/Tasks/efficiencyAndQc.cxx +++ /dev/null @@ -1,927 +0,0 @@ -// 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. - -#include -#include -#include -#include "ReconstructionDataFormats/PID.h" -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TableHelper.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/Expressions.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Math/MatrixFunctions.h" -#include "Math/SMatrix.h" - -#include "PWGCF/Core/AnalysisConfigurableCuts.h" -#include "PWGCF/DataModel/DptDptFiltered.h" -#include "PWGCF/TableProducer/dptdptfilter.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::soa; -using namespace o2::framework::expressions; - -#define ADDHISTOGRAM(thetype, thedirectory, thename, thetitle, thekind, thebinning...) \ - registry.add(TString::Format("%s/%s", thedirectory, thename).Data(), thetitle, thekind, thebinning) -#define FORMATSTRING(theformat, theparams...) TString::Format(theformat, theparams).Data() -#define DIRECTORYSTRING(thedirectoryfmt, thedirectorypars...) FORMATSTRING(thedirectoryfmt, thedirectorypars) -#define HNAMESTRING(thehnamefmt, thehnamepars...) FORMATSTRING(thehnamefmt, thehnamepars) -#define HTITLESTRING(thehtitlefmt, thehtitlepars...) FORMATSTRING(thehtitlefmt, thehtitlepars) - -namespace efficiencyandqatask -{ -/// \enum KindOfProcessQA -/// \brief The kind of processing for templating the procedures -enum KindOfProcess { - kReco = 0, ///< processing over reconstructed particles/tracks - kGen ///< processing over generated particles -}; - -/// \enum BeforeAfter -/// \brief The kind of filling, before or after track selection -enum BeforeAfter { - kBefore = 0, ///< filling before track selection - kAfter ///< filling after track selection -}; - -/* the PID selector object to help with the configuration and the id of the selected particles */ -o2::analysis::dptdptfilter::PIDSpeciesSelection pidselector; - -// initialized during self configuration -std::vector poinames; ///< the species of interest names -std::vector tnames; ///< the track names - -static const std::vector allmainspecies{o2::track::PID::Electron, o2::track::PID::Muon, o2::track::PID::Pion, o2::track::PID::Kaon, o2::track::PID::Proton}; -static const std::vector allmainspnames{"ElectronP", "ElectronM", "MuonP", "MuonM", "PionP", "PionM", "KaonP", "KaonM", "ProtonP", "ProtonM"}; -static const std::vector allmainsptitles{"e^{#plus}", "e^{#minus}", "#mu^{#plus}", "#mu^{#minus}", "#pi^{#plus}", "#pi^{#minus}", "K^{#plus}", "K^{#minus}", "p", "#bar{p}"}; -static const std::vector mainspecies{o2::track::PID::Pion, o2::track::PID::Kaon, o2::track::PID::Proton}; -static const std::vector mainspnames{"PionP", "PionM", "KaonP", "KaonM", "ProtonP", "ProtonM"}; -static const std::vector mainsptitles{"#pi^{#plus}", "#pi^{#minus}", "K^{#plus}", "K^{#minus}", "p", "#bar{p}"}; -static const std::vector pdgcodes = {11, 13, 211, 321, 2212}; -} // namespace efficiencyandqatask - -/* the QA data collecting engine */ -struct QADataCollectingEngine { - uint nsp = static_cast(efficiencyandqatask::tnames.size()); - uint nmainsp = static_cast(efficiencyandqatask::mainspnames.size()); - uint nallmainsp = static_cast(efficiencyandqatask::allmainspnames.size()); - - //=================================================== - // The QA output objects - //=================================================== - /* efficiency histograms histograms */ - /* when two indexes, first index reco and detector level, second index generator level */ - /* when no indexes, reco and detector level */ - std::vector> fhPtB{2, nullptr}; - std::vector> fhPt_vs_EtaB{2, nullptr}; - std::vector> fhPt_vs_ZvtxB{2, nullptr}; - std::vector>> fhPtA{2, {nsp, nullptr}}; - std::vector>> fhPt_vs_EtaA{2, {nsp, nullptr}}; - std::vector>> fhPt_vs_ZvtxA{2, {nsp, nullptr}}; - std::shared_ptr fhPt_vs_EtaItsAcc{nullptr}; - std::shared_ptr fhPt_vs_EtaTpcAcc{nullptr}; - std::shared_ptr fhPt_vs_EtaItsTpcAcc{nullptr}; - std::shared_ptr fhPt_vs_EtaItsTofAcc{nullptr}; - std::shared_ptr fhPt_vs_EtaTpcTofAcc{nullptr}; - std::shared_ptr fhPt_vs_EtaItsTpcTofAcc{nullptr}; - std::vector> fhPt_vs_EtaItsA{nsp, nullptr}; - std::vector> fhPt_vs_EtaTpcA{nsp, nullptr}; - std::vector> fhPt_vs_EtaItsTpcA{nsp, nullptr}; - std::vector> fhPt_vs_EtaItsTofA{nsp, nullptr}; - std::vector> fhPt_vs_EtaTpcTofA{nsp, nullptr}; - std::vector> fhPt_vs_EtaItsTpcTofA{nsp, nullptr}; - /* primaries and secondaries */ - /* overall, first index detector level second index generator level */ - /* detailed, first index detector level, second index associated particle */ - std::shared_ptr fhPtPurityPosPrimA{nullptr}; - std::shared_ptr fhPtPurityNegPrimA{nullptr}; - std::vector> fhPt_vs_EtaPrimA{nsp, nullptr}; - std::vector>> fhPt_vs_EtaPrimItsA{2, {nsp, nullptr}}; - std::vector>> fhPt_vs_EtaPrimItsTpcA{2, {nsp, nullptr}}; - std::vector>> fhPt_vs_EtaPrimItsTpcTofA{2, {nsp, nullptr}}; - std::shared_ptr fhPtPurityPosSecA{nullptr}; - std::shared_ptr fhPtPurityNegSecA{nullptr}; - std::vector> fhPt_vs_EtaSecA{nsp, nullptr}; - std::vector>> fhPt_vs_EtaSecItsA{2, {nsp, nullptr}}; - std::vector>> fhPt_vs_EtaSecItsTpcA{2, {nsp, nullptr}}; - std::vector>> fhPt_vs_EtaSecItsTpcTofA{2, {nsp, nullptr}}; - std::shared_ptr fhPtPurityPosMatA{nullptr}; - std::shared_ptr fhPtPurityNegMatA{nullptr}; - std::vector> fhPt_vs_EtaMatA{nsp, nullptr}; - std::vector>> fhPt_vs_EtaMatItsA{2, {nsp, nullptr}}; - std::vector>> fhPt_vs_EtaMatItsTpcA{2, {nsp, nullptr}}; - std::vector>> fhPt_vs_EtaMatItsTpcTofA{2, {nsp, nullptr}}; - /* QC histograms */ - std::shared_ptr fhITS_NCls_vs_PtB{nullptr}; - std::shared_ptr fhITS_Chi2NCls_vs_PtB{nullptr}; - std::shared_ptr fhTPC_FindableNCls_vs_PtB{nullptr}; - std::shared_ptr fhTPC_FoundNCls_vs_PtB{nullptr}; - std::shared_ptr fhTPC_SharedNCls_vs_PtB{nullptr}; - std::shared_ptr fhTPC_FractionSharedCls_vs_PtB{nullptr}; - std::shared_ptr fhTPC_CrossedRows_vs_PtB{nullptr}; - std::shared_ptr fhTPC_CrossedRowsOverFindableCls_vs_PtB{nullptr}; - std::shared_ptr fhTPC_Chi2NCls_vs_PtB{nullptr}; - std::vector> fhITS_NCls_vs_PtA{nsp, nullptr}; - std::vector> fhITS_Chi2NCls_vs_PtA{nsp, nullptr}; - std::vector> fhTPC_FindableNCls_vs_PtA{nsp, nullptr}; - std::vector> fhTPC_FoundNCls_vs_PtA{nsp, nullptr}; - std::vector> fhTPC_SharedNCls_vs_PtA{nsp, nullptr}; - std::vector> fhTPC_FractionSharedCls_vs_PtA{nsp, nullptr}; - std::vector> fhTPC_CrossedRows_vs_PtA{nsp, nullptr}; - std::vector> fhTPC_CrossedRowsOverFindableCls_vs_PtA{nsp, nullptr}; - std::vector> fhTPC_Chi2NCls_vs_PtA{nsp, nullptr}; - - template - void init(HistogramRegistry& registry, const char* dirname) - { - using namespace efficiencyandqatask; - using namespace analysis::dptdptfilter; - - const AxisSpec ptAxis{ptbins, ptlow, ptup, "#it{p}_{T} (GeV/c)"}; - const AxisSpec etaAxis{etabins, etalow, etaup, "#eta"}; - const AxisSpec phiAxis{360, 0.0f, constants::math::TwoPI, "#varphi"}; - const AxisSpec zvtxAxis{zvtxbins, zvtxlow, zvtxup, "#it{z}_{vtx}"}; - const AxisSpec itsNClsAxis{8, -0.5, 7.5, "ITS n clusters"}; - const AxisSpec itsCh2Axis{100, 0, 40, "#Chi^{2}/Cls ITS"}; - const AxisSpec tpcNClsAxis{165, -0.5, 164.5, "TPC n clusters"}; - const AxisSpec tpcNRowsAxis{165, -0.5, 164.5, "TPC n rows"}; - const AxisSpec tpcFractionAxis{100, 0, 1, "fraction"}; - const AxisSpec tpcXRowsOverFindClsAxis{60, 0.7, 1.3, "fraction"}; - const AxisSpec tpcCh2Axis{100, 0, 10, "#Chi^{2}/Cls TPC"}; - - /* the reconstructed and generated levels histograms */ - std::string recogen = (kind == kReco) ? "Reco" : "Gen"; - fhPtB[kind] = ADDHISTOGRAM(TH1, DIRECTORYSTRING("%s/%s/%s", dirname, recogen.c_str(), "Before"), "Pt", "#it{p}_{T}", kTH1F, {ptAxis}); - fhPt_vs_EtaB[kind] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, recogen.c_str(), "Before"), "PtVsEta", "#it{p}_T vs #eta", kTH2F, {etaAxis, ptAxis}); - fhPt_vs_ZvtxB[kind] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, recogen.c_str(), "Before"), "PtVsZvtx", "#it{p}_T vs #it{z}_{vtx}", kTH2F, {zvtxAxis, ptAxis}); - for (uint isp = 0; isp < nsp; ++isp) { - fhPtA[kind][isp] = ADDHISTOGRAM(TH1, DIRECTORYSTRING("%s/%s/%s", dirname, recogen.c_str(), "After"), HNAMESTRING("Pt_%s", tnames[isp].c_str()), HTITLESTRING("#it{p}_{T} %s", tnames[isp].c_str()), kTH1F, {ptAxis}); - fhPt_vs_EtaA[kind][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, recogen.c_str(), "After"), HNAMESTRING("PtVsEta_%s", tnames[isp].c_str()), HTITLESTRING("#it{p}_{T} vs #eta %s", tnames[isp].c_str()), kTH2F, {etaAxis, ptAxis}); - fhPt_vs_ZvtxA[kind][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, recogen.c_str(), "After"), HNAMESTRING("PtVsZvtx_%s", tnames[isp].c_str()), HTITLESTRING("#it{p}_{T} vs #it{z}_{zvtx} %s", tnames[isp].c_str()), kTH2F, {zvtxAxis, ptAxis}); - } - - if constexpr (kind == kReco) { - /* only the reconstructed level histograms*/ - fhITS_NCls_vs_PtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "ITSNCls", "ITS clusters", kTH2F, {ptAxis, itsNClsAxis}); - fhITS_Chi2NCls_vs_PtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "ITSChi2NCls", "ITS #Chi^{2}", kTH2F, {ptAxis, itsCh2Axis}); - fhTPC_FindableNCls_vs_PtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "TPCFindableNCls", "TPC findable clusters", kTH2F, {ptAxis, tpcNClsAxis}); - fhTPC_FoundNCls_vs_PtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "TPCFoundNCls", "TPC found clusters", kTH2F, {ptAxis, tpcNClsAxis}); - fhTPC_SharedNCls_vs_PtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "TPCSharedNCls", "TPC shared clusters", kTH2F, {ptAxis, tpcNClsAxis}); - fhTPC_FractionSharedCls_vs_PtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "TPCFractionSharedCls", "TPC fraction shared clusters", kTH2F, {ptAxis, tpcFractionAxis}); - fhTPC_CrossedRows_vs_PtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "TPCXrows", "TPC crossed rows", kTH2F, {ptAxis, tpcNRowsAxis}); - fhTPC_CrossedRowsOverFindableCls_vs_PtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "XRowsOverFindableCls", "TPC xrows over findable clusters", kTH2F, {ptAxis, tpcXRowsOverFindClsAxis}); - fhTPC_Chi2NCls_vs_PtB = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "Before"), "TPCChi2NCls", "TPC #Chi^{2}", kTH2F, {ptAxis, tpcCh2Axis}); - /* efficiency histograms */ - fhPt_vs_EtaItsAcc = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), "ptItsAcc", "ITS tracks within the acceptance", kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaTpcAcc = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), "ptTpcAcc", "TPC tracks within the acceptance", kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaItsTpcAcc = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), "ptItsTpcAcc", "ITS&TPC tracks within the acceptance", kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaItsTofAcc = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), "ptItsTofAcc", "ITS&TOF tracks within the acceptance", kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaTpcTofAcc = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), "ptTpcTofAcc", "TPC&TOF tracks within the acceptance", kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaItsTpcTofAcc = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), "ptItsTpcTofAcc", "ITS&TPC&TOF tracks within the acceptance", kTH2F, {etaAxis, ptAxis}); - for (uint isp = 0; isp < nsp; ++isp) { - fhITS_NCls_vs_PtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("ITSNCls_%s", tnames[isp].c_str()), HTITLESTRING("ITS clusters %s", tnames[isp].c_str()), kTH2F, {ptAxis, itsNClsAxis}); - fhITS_Chi2NCls_vs_PtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("ITSChi2NCls_%s", tnames[isp].c_str()), HTITLESTRING("ITS #Chi^{2} %s", tnames[isp].c_str()), kTH2F, {ptAxis, itsCh2Axis}); - fhTPC_FindableNCls_vs_PtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("TPCFindableNCls_%s", tnames[isp].c_str()), HTITLESTRING("TPC findable clusters %s", tnames[isp].c_str()), kTH2F, {ptAxis, tpcNClsAxis}); - fhTPC_FoundNCls_vs_PtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("TPCFoundNCls_%s", tnames[isp].c_str()), HTITLESTRING("TPC found clusters %s", tnames[isp].c_str()), kTH2F, {ptAxis, tpcNClsAxis}); - fhTPC_SharedNCls_vs_PtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("TPCSharedNCls_%s", tnames[isp].c_str()), HTITLESTRING("TPC shared clusters %s", tnames[isp].c_str()), kTH2F, {ptAxis, tpcNClsAxis}); - fhTPC_FractionSharedCls_vs_PtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("TPCFractionSharedCls_%s", tnames[isp].c_str()), HTITLESTRING("TPC fraction shared clusters %s", tnames[isp].c_str()), kTH2F, {ptAxis, tpcFractionAxis}); - fhTPC_CrossedRows_vs_PtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("TPCXrows_%s", tnames[isp].c_str()), HTITLESTRING("TPC crossed rows %s", tnames[isp].c_str()), kTH2F, {ptAxis, tpcNRowsAxis}); - fhTPC_CrossedRowsOverFindableCls_vs_PtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("XRowsOverFindableCls_%s", tnames[isp].c_str()), HTITLESTRING("TPC xrows over findable clusters %s", tnames[isp].c_str()), kTH2F, {ptAxis, tpcXRowsOverFindClsAxis}); - fhTPC_Chi2NCls_vs_PtA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Reco", "After"), HNAMESTRING("TPCChi2NCls_%s", tnames[isp].c_str()), HTITLESTRING("TPC #Chi^{2} %s", tnames[isp].c_str()), kTH2F, {ptAxis, tpcCh2Axis}); - /* efficiency histograms */ - fhPt_vs_EtaItsA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), HNAMESTRING("ptIts_%s", tnames[isp].c_str()), HTITLESTRING("ITS %s tracks", tnames[isp].c_str()), kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaTpcA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), HNAMESTRING("ptTpc_%s", tnames[isp].c_str()), HTITLESTRING("TPC %s tracks", tnames[isp].c_str()), kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaItsTpcA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), HNAMESTRING("ptItsTpc_%s", tnames[isp].c_str()), HTITLESTRING("ITS&TPC %s tracks", tnames[isp].c_str()), kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaItsTofA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), HNAMESTRING("ptItsTof_%s", tnames[isp].c_str()), HTITLESTRING("ITS&TOF %s tracks", tnames[isp].c_str()), kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaTpcTofA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), HNAMESTRING("ptTpcTof_%s", tnames[isp].c_str()), HTITLESTRING("TPC&TOF %s tracks", tnames[isp].c_str()), kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaItsTpcTofA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), HNAMESTRING("ptItsTpcTof_%s", tnames[isp].c_str()), HTITLESTRING("ITS&TPC&TOF %s tracks", tnames[isp].c_str()), kTH2F, {etaAxis, ptAxis}); - } - } else { - AxisSpec recoSpecies{static_cast(nsp) + 1, -0.5, nsp - 0.5, "reco species"}; - AxisSpec trueSpecies{static_cast(nmainsp) + 1, -0.5, nmainsp + 0.5, "true species"}; - fhPtPurityPosPrimA = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s", dirname, "Purity"), "ptPurityPosPrim", "Primaries for reconstructed positive", kTH3F, {recoSpecies, trueSpecies, ptAxis}); - fhPtPurityNegPrimA = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s", dirname, "Purity"), "ptPurityNegPrim", "Primaries for reconstructed negative", kTH3F, {recoSpecies, trueSpecies, ptAxis}); - fhPtPurityPosSecA = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s", dirname, "Purity"), "ptPurityPosSec", "Secondaries for reconstructed positive", kTH3F, {recoSpecies, trueSpecies, ptAxis}); - fhPtPurityNegSecA = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s", dirname, "Purity"), "ptPurityNegSec", "Secondaries for reconstructed negative", kTH3F, {recoSpecies, trueSpecies, ptAxis}); - fhPtPurityPosMatA = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s", dirname, "Purity"), "ptPurityPosMat", "Secondaries from material for reconstructed positive", kTH3F, {recoSpecies, trueSpecies, ptAxis}); - fhPtPurityNegMatA = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s", dirname, "Purity"), "ptPurityNegMat", "Secondaries from material for reconstructed negative", kTH3F, {recoSpecies, trueSpecies, ptAxis}); - for (uint isp = 0; isp < nsp; ++isp) { - /* detector level and generator level histograms */ - fhPt_vs_EtaPrimA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Gen"), - HNAMESTRING("ptPrim%s", tnames[isp].c_str()), - HTITLESTRING("ITS %s tracks (primaries)", tnames[isp].c_str()), - kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaSecA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Gen"), - HNAMESTRING("ptSec%s", tnames[isp].c_str()), - HTITLESTRING("ITS %s tracks (secondaries)", tnames[isp].c_str()), - kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaMatA[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Gen"), - HNAMESTRING("ptMat%s", tnames[isp].c_str()), - HTITLESTRING("ITS %s tracks (from material)", tnames[isp].c_str()), - kTH2F, {etaAxis, ptAxis}); - - const std::vector detectedorigin = {"DetReco", "DetAssoc"}; - for (uint ix = 0; ix < detectedorigin.size(); ++ix) { - fhPt_vs_EtaPrimItsA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), - HNAMESTRING("ptItsPrim_%s", tnames[isp].c_str()), - HTITLESTRING("ITS %s tracks (primaries)", tnames[isp].c_str()), - kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaPrimItsTpcA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), - HNAMESTRING("ptItsTpcPrim_%s", tnames[isp].c_str()), - HTITLESTRING("ITS&TPC %s tracks (primaries)", tnames[isp].c_str()), - kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaPrimItsTpcTofA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), - HNAMESTRING("ptItsTpcTofPrim_%s", tnames[isp].c_str()), - HTITLESTRING("ITS&TPC&TOF %s tracks (primaries)", tnames[isp].c_str()), - kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaSecItsA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), - HNAMESTRING("ptItsSec_%s", tnames[isp].c_str()), - HTITLESTRING("ITS %s tracks (secondaries)", tnames[isp].c_str()), - kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaSecItsTpcA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), - HNAMESTRING("ptItsTpcSec_%s", tnames[isp].c_str()), - HTITLESTRING("ITS&TPC %s tracks (secondaries)", tnames[isp].c_str()), - kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaSecItsTpcTofA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), - HNAMESTRING("ptItsTpcTofSec_%s", tnames[isp].c_str()), - HTITLESTRING("ITS&TPC&TOF %s tracks (secondaries)", tnames[isp].c_str()), - kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaMatItsA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), - HNAMESTRING("ptItsMat_%s", tnames[isp].c_str()), - HTITLESTRING("ITS %s tracks (from material)", tnames[isp].c_str()), - kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaMatItsTpcA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), - HNAMESTRING("ptItsTpcMat_%s", tnames[isp].c_str()), - HTITLESTRING("ITS&TPC %s tracks (from material)", tnames[isp].c_str()), - kTH2F, {etaAxis, ptAxis}); - fhPt_vs_EtaMatItsTpcTofA[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", detectedorigin[ix].c_str()), - HNAMESTRING("ptItsTpcTofMat_%s", tnames[isp].c_str()), - HTITLESTRING("ITS&TPC&TOF %s tracks (from material)", tnames[isp].c_str()), - kTH2F, {etaAxis, ptAxis}); - } - } - } - } - - template - void processTrack(float zvtx, TrackObject const& track) - { - using namespace efficiencyandqatask; - using namespace analysis::dptdptfilter; - using namespace o2::aod::track; - - fhPtB[kind]->Fill(track.pt()); - fhPt_vs_EtaB[kind]->Fill(track.eta(), track.pt()); - fhPt_vs_ZvtxB[kind]->Fill(zvtx, track.pt()); - if (!(track.trackacceptedid() < 0)) { - fhPtA[kind][track.trackacceptedid()]->Fill(track.pt()); - fhPt_vs_EtaA[kind][track.trackacceptedid()]->Fill(track.eta(), track.pt()); - fhPt_vs_ZvtxA[kind][track.trackacceptedid()]->Fill(zvtx, track.pt()); - } - if constexpr (kind == kReco) { - auto fillhisto = [&track](auto& h, bool cond) { - if (cond) { - h->Fill(track.eta(), track.pt()); - } - }; - bool hasits = track.hasITS() && TrackSelectionFlags::checkFlag(track.trackCutFlag(), trackSelectionITS) && TrackSelectionFlags::checkFlag(track.trackCutFlag(), trackSelectionDCA); - bool hastpc = track.hasTPC() && TrackSelectionFlags::checkFlag(track.trackCutFlag(), trackSelectionTPC); - bool hastof = track.hasTOF(); - - fhITS_NCls_vs_PtB->Fill(track.pt(), track.itsNCls()); - fhITS_Chi2NCls_vs_PtB->Fill(track.pt(), track.itsChi2NCl()); - fhTPC_FindableNCls_vs_PtB->Fill(track.pt(), track.tpcNClsFindable()); - fhTPC_FoundNCls_vs_PtB->Fill(track.pt(), track.tpcNClsFound()); - fhTPC_SharedNCls_vs_PtB->Fill(track.pt(), track.tpcNClsShared()); - fhTPC_FractionSharedCls_vs_PtB->Fill(track.pt(), track.tpcFractionSharedCls()); - fhTPC_CrossedRows_vs_PtB->Fill(track.pt(), track.tpcNClsCrossedRows()); - fhTPC_CrossedRowsOverFindableCls_vs_PtB->Fill(track.pt(), track.tpcCrossedRowsOverFindableCls()); - fhTPC_Chi2NCls_vs_PtB->Fill(track.pt(), track.tpcChi2NCl()); - if (InTheAcceptance(track)) { - /* efficiency histograms */ - fillhisto(fhPt_vs_EtaItsAcc, hasits); - fillhisto(fhPt_vs_EtaTpcAcc, hastpc); - fillhisto(fhPt_vs_EtaItsTpcAcc, hasits && hastpc); - fillhisto(fhPt_vs_EtaItsTofAcc, hasits && hastof); - fillhisto(fhPt_vs_EtaTpcTofAcc, hastpc && hastof); - fillhisto(fhPt_vs_EtaItsTpcTofAcc, hasits && hastpc && hastof); - } - if (!(track.trackacceptedid() < 0)) { - fhITS_NCls_vs_PtA[track.trackacceptedid()]->Fill(track.pt(), track.itsNCls()); - fhITS_Chi2NCls_vs_PtA[track.trackacceptedid()]->Fill(track.pt(), track.itsChi2NCl()); - fhTPC_FindableNCls_vs_PtA[track.trackacceptedid()]->Fill(track.pt(), track.tpcNClsFindable()); - fhTPC_FoundNCls_vs_PtA[track.trackacceptedid()]->Fill(track.pt(), track.tpcNClsFound()); - fhTPC_SharedNCls_vs_PtA[track.trackacceptedid()]->Fill(track.pt(), track.tpcNClsShared()); - fhTPC_FractionSharedCls_vs_PtA[track.trackacceptedid()]->Fill(track.pt(), track.tpcFractionSharedCls()); - fhTPC_CrossedRows_vs_PtA[track.trackacceptedid()]->Fill(track.pt(), track.tpcNClsCrossedRows()); - fhTPC_CrossedRowsOverFindableCls_vs_PtA[track.trackacceptedid()]->Fill(track.pt(), track.tpcCrossedRowsOverFindableCls()); - fhTPC_Chi2NCls_vs_PtA[track.trackacceptedid()]->Fill(track.pt(), track.tpcChi2NCl()); - /* efficiency histograms */ - fillhisto(fhPt_vs_EtaItsA[track.trackacceptedid()], hasits); - fillhisto(fhPt_vs_EtaTpcA[track.trackacceptedid()], hastpc); - fillhisto(fhPt_vs_EtaItsTpcA[track.trackacceptedid()], hasits && hastpc); - fillhisto(fhPt_vs_EtaItsTofA[track.trackacceptedid()], hasits && hastof); - fillhisto(fhPt_vs_EtaTpcTofA[track.trackacceptedid()], hastpc && hastof); - fillhisto(fhPt_vs_EtaItsTpcTofA[track.trackacceptedid()], hasits && hastpc && hastof); - /* the detector / generator combined level */ - if constexpr (framework::has_type_v) { - auto findgenid = [&](auto& part) { - int pdgcode = std::abs(part.pdgCode()); - for (uint ix = 0; ix < pdgcodes.size(); ++ix) { - if (pdgcode == pdgcodes[ix]) { - return ix; - } - } - return static_cast(pdgcodes.size()); - }; - auto fillpurityhistos = [](auto& hpos, auto& hneg, auto& genid, auto& track, bool cond) { - if (cond) { - if (track.sign() > 0) { - hpos->Fill(static_cast(track.trackacceptedid() / 2), genid, track.pt()); - } else { - hneg->Fill(static_cast(track.trackacceptedid() / 2), genid, track.pt()); - } - } - }; - /* get the associated MC particle we are sure it does exist because the track was accepted */ - const auto& mcparticle = track.template mcParticle_as>(); - float genid = findgenid(mcparticle); - - bool isprimary = mcparticle.isPhysicalPrimary(); - bool issecdecay = !isprimary && (mcparticle.getProcess() == 4); - bool isfrommaterial = !isprimary && !issecdecay; - fillpurityhistos(fhPtPurityPosPrimA, fhPtPurityNegPrimA, genid, track, isprimary); - fillpurityhistos(fhPtPurityPosSecA, fhPtPurityNegSecA, genid, track, issecdecay); - fillpurityhistos(fhPtPurityPosMatA, fhPtPurityNegMatA, genid, track, isfrommaterial); - - auto fillhisto = [](auto& h, float pt, float eta, bool cond1, bool cond2) { - if (cond1 && cond2) { - h->Fill(eta, pt); - } - }; - std::vector t_pt = {track.pt(), mcparticle.pt()}; - std::vector t_eta = {track.eta(), mcparticle.eta()}; - for (uint ix = 0; ix < t_pt.size(); ++ix) { - fillhisto(fhPt_vs_EtaPrimItsA[ix][track.trackacceptedid()], t_pt[ix], t_eta[ix], hasits, isprimary); - fillhisto(fhPt_vs_EtaPrimItsTpcA[ix][track.trackacceptedid()], t_pt[ix], t_eta[ix], hasits && hastpc, isprimary); - fillhisto(fhPt_vs_EtaPrimItsTpcTofA[ix][track.trackacceptedid()], t_pt[ix], t_eta[ix], hasits && hastof, isprimary); - fillhisto(fhPt_vs_EtaSecItsA[ix][track.trackacceptedid()], t_pt[ix], t_eta[ix], hasits, issecdecay); - fillhisto(fhPt_vs_EtaSecItsTpcA[ix][track.trackacceptedid()], t_pt[ix], t_eta[ix], hasits && hastpc, issecdecay); - fillhisto(fhPt_vs_EtaSecItsTpcTofA[ix][track.trackacceptedid()], t_pt[ix], t_eta[ix], hasits && hastof, issecdecay); - fillhisto(fhPt_vs_EtaMatItsA[ix][track.trackacceptedid()], t_pt[ix], t_eta[ix], hasits, isfrommaterial); - fillhisto(fhPt_vs_EtaMatItsTpcA[ix][track.trackacceptedid()], t_pt[ix], t_eta[ix], hasits && hastpc, isfrommaterial); - fillhisto(fhPt_vs_EtaMatItsTpcTofA[ix][track.trackacceptedid()], t_pt[ix], t_eta[ix], hasits && hastof, isfrommaterial); - } - } - } - } - if constexpr (kind == kGen) { - if (!(track.trackacceptedid() < 0)) { - /* pure generator level */ - if (track.isPhysicalPrimary()) { - fhPt_vs_EtaPrimA[track.trackacceptedid()]->Fill(track.eta(), track.pt()); - } else if (track.getProcess() == 4) { - fhPt_vs_EtaSecA[track.trackacceptedid()]->Fill(track.eta(), track.pt()); - } else { - fhPt_vs_EtaMatA[track.trackacceptedid()]->Fill(track.eta(), track.pt()); - } - } - } - } -}; - -/* the PID data collecting engine */ -struct PidDataCollectingEngine { - uint nsp = static_cast(efficiencyandqatask::tnames.size()); - uint nmainsp = static_cast(efficiencyandqatask::mainspnames.size()); - uint nallmainsp = static_cast(efficiencyandqatask::allmainspnames.size()); - - /* PID histograms */ - /* before and after */ - std::vector> fhTPCdEdxSignalVsP{2, nullptr}; - std::vector>> fhTPCdEdxSignalDiffVsP{2, {nmainsp, nullptr}}; - std::vector>> fhTPCnSigmasVsP{2, {nallmainsp, nullptr}}; - std::vector> fhTOFSignalVsP{2, nullptr}; - std::vector>> fhTOFSignalDiffVsP{2, {nmainsp, nullptr}}; - std::vector>> fhTOFnSigmasVsP{2, {nallmainsp, nullptr}}; - std::vector> fhPvsTOFSqMass{2, nullptr}; - std::vector>> fhTPCTOFSigmaVsP{2, {nmainsp, nullptr}}; - /* PID histograms */ - /* only after track selection */ - std::vector> fhIdTPCdEdxSignalVsP{nsp, nullptr}; - std::vector> fpIdTPCdEdxSignalVsPSigmas{nsp, nullptr}; - std::vector>> fhIdTPCdEdxSignalDiffVsP{nsp, {nmainsp, nullptr}}; - std::vector>> fhIdTPCnSigmasVsP{nsp, {nallmainsp, nullptr}}; - std::vector> fhIdTOFSignalVsP{nsp, nullptr}; - std::vector> fpIdTOFSignalVsPSigmas{nsp, nullptr}; - std::vector>> fhIdTOFSignalDiffVsP{nsp, {nmainsp, nullptr}}; - std::vector>> fhIdTOFnSigmasVsP{nsp, {nallmainsp, nullptr}}; - std::vector> fhIdPvsTOFSqMass{nsp, nullptr}; - - template - void init(HistogramRegistry& registry, const char* dirname) - { - using namespace efficiencyandqatask; - - const AxisSpec dEdxAxis{200, 0.0, 200.0, "dE/dx (au)"}; - AxisSpec pidPAxis{150, 0.1, 5.0, "#it{p} (GeV/#it{c})"}; - pidPAxis.makeLogarithmic(); - - if constexpr (kind == kReco) { - /* PID histograms */ - std::vector whenname{"Before", "After"}; - char whenprefix[2]{'B', 'A'}; - std::vector whentitle{"before", ""}; - for (uint ix = 0; ix < whenname.size(); ++ix) { - fhTPCdEdxSignalVsP[ix] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", whenname[ix].c_str()), - HNAMESTRING("tpcSignalVsP%c", whenprefix[ix]), - HTITLESTRING("TPC dE/dx signal %s", whentitle[ix].c_str()), kTH2F, {pidPAxis, dEdxAxis}); - fhTOFSignalVsP[ix] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", whenname[ix].c_str()), - HNAMESTRING("tofSignalVsP%c", whenprefix[ix]), - HTITLESTRING("TOF signal %s", whentitle[ix].c_str()), - kTH2F, {pidPAxis, {200, 0.0, 1.1, "#beta"}}); - fhPvsTOFSqMass[ix] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", whenname[ix].c_str()), - HNAMESTRING("tofPvsMassSq%c", whenprefix[ix]), - HTITLESTRING("Momentum versus #it{m}^{2} %s", whentitle[ix].c_str()), - kTH2F, {{140, 0.0, 1.4, "#it{m}^{2} ((GeV/c^{2})^{2})"}, pidPAxis}); - for (uint isp = 0; isp < nmainsp; ++isp) { - fhTPCdEdxSignalDiffVsP[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", whenname[ix].c_str()), - HNAMESTRING("tpcSignalDiffVsP%c_%s", whenprefix[ix], mainspnames[isp].c_str()), - HTITLESTRING("TPC dE/dx to the %s line %s", mainsptitles[isp].c_str(), whentitle[ix].c_str()), - kTH2F, {pidPAxis, {400, -200.0, 200.0, FORMATSTRING("dE/dx - _{%s}", mainsptitles[isp].c_str())}}); - fhTOFSignalDiffVsP[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", whenname[ix].c_str()), - HNAMESTRING("tofSignalDiffVsP%c_%s", whenprefix[ix], mainspnames[isp].c_str()), - HTITLESTRING("#Delta^{TOF_{%s}} %s", mainsptitles[isp].c_str(), whentitle[ix].c_str()), - kTH2F, {pidPAxis, {200, -1000.0, 1000.0, FORMATSTRING("t-t_{ev}-t_{exp_{%s}} (ps)", mainsptitles[isp].c_str())}}); - fhTPCTOFSigmaVsP[ix][isp] = ADDHISTOGRAM(TH3, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", whenname[ix].c_str()), - HNAMESTRING("toftpcNSigmasVsP%c_%s", whenprefix[ix], mainspnames[isp].c_str()), - HTITLESTRING("n#sigma to the %s line %s", mainsptitles[isp].c_str(), whentitle[ix].c_str()), - kTH3F, {pidPAxis, {120, -6.0, 6.0, FORMATSTRING("n#sigma_{TPC}^{%s}", mainsptitles[isp].c_str())}, {120, -6.0, 6.0, FORMATSTRING("n#sigma_{TOF}^{%s}", mainsptitles[isp].c_str())}}); - } - for (uint isp = 0; isp < nallmainsp; ++isp) { - fhTPCnSigmasVsP[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", whenname[ix].c_str()), - HNAMESTRING("tpcNSigmasVsP%c_%s", whenprefix[ix], allmainspnames[isp].c_str()), - HTITLESTRING("TPC n#sigma to the %s line %s", allmainsptitles[isp].c_str(), whentitle[ix].c_str()), - kTH2F, {pidPAxis, {120, -6.0, 6.0, FORMATSTRING("n#sigma_{TPC}^{%s}", allmainsptitles[isp].c_str())}}); - fhTOFnSigmasVsP[ix][isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", whenname[ix].c_str()), - HNAMESTRING("tofNSigmasVsP%c_%s", whenprefix[ix], allmainspnames[isp].c_str()), - HTITLESTRING("TOF n#sigma to the %s line %s", allmainsptitles[isp].c_str(), whentitle[ix].c_str()), - kTH2F, {pidPAxis, {120, -6.0, 6.0, FORMATSTRING("n#sigma_{TOF}^{%s}", allmainsptitles[isp].c_str())}}); - } - } - for (uint isp = 0; isp < nsp; ++isp) { - fhIdTPCdEdxSignalVsP[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", "Selected"), - HNAMESTRING("tpcSignalVsPSelected_%s", tnames[isp].c_str()), - HTITLESTRING("TPC dE/dx for selected %s", tnames[isp].c_str()), - kTH2F, {pidPAxis, dEdxAxis}); - fpIdTPCdEdxSignalVsPSigmas[isp] = ADDHISTOGRAM(TProfile2D, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", "Selected"), - HNAMESTRING("tpcSignalSigmasVsPSelected_%s", tnames[isp].c_str()), - HTITLESTRING("TPC dE/dx and n#sigma for selected %s", tnames[isp].c_str()), - kTProfile2D, {pidPAxis, dEdxAxis}); - fhIdTOFSignalVsP[isp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", "Selected"), - HNAMESTRING("tofSignalVsPSelected_%s", tnames[isp].c_str()), - HTITLESTRING("TOF signal for selected %s", tnames[isp].c_str()), - kTH2F, {pidPAxis, {200, 0.0, 1.1, "#beta"}}); - fpIdTOFSignalVsPSigmas[isp] = ADDHISTOGRAM(TProfile2D, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", "Selected"), - HNAMESTRING("tofSignalSigmasVsPSelected_%s", tnames[isp].c_str()), - HTITLESTRING("TOF signal and n#sigma for selected %s", tnames[isp].c_str()), - kTProfile2D, {pidPAxis, {200, 0.0, 1.1, "#beta"}}); - for (uint imainsp = 0; imainsp < nallmainsp; ++imainsp) { - /* only the same charge makes any sense */ - if (isp % 2 == imainsp % 2) { - fhIdTPCnSigmasVsP[isp][imainsp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", "Selected"), - HNAMESTRING("tpcNSigmasVsPSelected_%s_to%s", tnames[isp].c_str(), allmainspnames[imainsp].c_str()), - HTITLESTRING("TPC n#sigma for selected %s to the %s line", tnames[isp].c_str(), allmainsptitles[imainsp].c_str()), - kTH2F, {pidPAxis, {120, -6.0, 6.0, FORMATSTRING("n#sigma_{TPC}^{%s}", allmainsptitles[isp].c_str())}}); - fhIdTOFnSigmasVsP[isp][imainsp] = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "PID", "Selected"), - HNAMESTRING("tofNSigmasVsPSelected_%s_to%s", tnames[isp].c_str(), allmainspnames[imainsp].c_str()), - HTITLESTRING("TOF n#sigma for selected %s to the %s line", tnames[isp].c_str(), allmainsptitles[imainsp].c_str()), - kTH2F, {pidPAxis, {120, -6.0, 6.0, FORMATSTRING("n#sigma_{TOF}^{%s}", allmainsptitles[isp].c_str())}}); - } - } - } - } - } - - template - void fillAllSpeciesPID(uint ix, TrackObject const& track) - { - if (track.sign() < 0) { - ix = 2 * ix + 1; - } else { - ix = 2 * ix; - } - for (uint when = 0; when < 2; ++when) { - fhTPCnSigmasVsP[when][ix]->Fill(track.p(), o2::aod::pidutils::tpcNSigma(track)); - fhTOFnSigmasVsP[when][ix]->Fill(track.p(), o2::aod::pidutils::tofNSigma(track)); - if (track.trackacceptedid() < 0) { - /* track not accepted */ - return; - } - } - fhIdTPCnSigmasVsP[track.trackacceptedid()][ix]->Fill(track.p(), o2::aod::pidutils::tpcNSigma(track)); - fhIdTOFnSigmasVsP[track.trackacceptedid()][ix]->Fill(track.p(), o2::aod::pidutils::tofNSigma(track)); - if (efficiencyandqatask::pidselector.isGlobalSpecies(track.trackacceptedid() / 2, id)) { - /* only if the species of the selected track matches the target of the number of sigmas */ - fpIdTPCdEdxSignalVsPSigmas[track.trackacceptedid()]->Fill(track.p(), track.tpcSignal(), o2::aod::pidutils::tpcNSigma(track)); - fpIdTOFSignalVsPSigmas[track.trackacceptedid()]->Fill(track.p(), track.beta(), o2::aod::pidutils::tofNSigma(track)); - } - } - - template - void fillSpeciesPID(uint ix, TrackObject const& track) - { - if (track.sign() < 0) { - ix = 2 * ix + 1; - } else { - ix = 2 * ix; - } - for (uint when = 0; when < 2; ++when) { - fhTPCdEdxSignalDiffVsP[when][ix]->Fill(track.p(), o2::aod::pidutils::tpcExpSignalDiff(track)); - fhTOFSignalDiffVsP[when][ix]->Fill(track.p(), o2::aod::pidutils::tofExpSignalDiff(track)); - fhTPCTOFSigmaVsP[when][ix]->Fill(track.p(), o2::aod::pidutils::tpcNSigma(track), o2::aod::pidutils::tofNSigma(track)); - if (track.trackacceptedid() < 0) { - /* track not accepted */ - return; - } - } - } - - template - void fillPID(TrackObject const& track) - { - for (uint when = 0; when < 2; ++when) { - fhTPCdEdxSignalVsP[when]->Fill(track.p(), track.tpcSignal()); - fhTOFSignalVsP[when]->Fill(track.p(), track.beta()); - fhPvsTOFSqMass[when]->Fill(track.mass() * track.mass(), track.p()); - if (track.trackacceptedid() < 0) { - /* track not accepted */ - return; - } - } - fhIdTPCdEdxSignalVsP[track.trackacceptedid()]->Fill(track.p(), track.tpcSignal()); - fhIdTOFSignalVsP[track.trackacceptedid()]->Fill(track.p(), track.beta()); - } - - template - void processTrack(TrackObject const& track) - { - using namespace efficiencyandqatask; - - if constexpr (kind == kReco) { - fillPID(track); - fillSpeciesPID(0, track); - fillSpeciesPID(1, track); - fillSpeciesPID(2, track); - fillAllSpeciesPID(0, track); - fillAllSpeciesPID(1, track); - fillAllSpeciesPID(2, track); - fillAllSpeciesPID(3, track); - fillAllSpeciesPID(4, track); - } - } -}; - -struct DptDptEfficiencyAndQc { - /* the data memebers for this task */ - /* the centrality / multiplicity limits for collecting data in this task instance */ - uint ncmranges = 0; - float* fCentMultMin = nullptr; - float* fCentMultMax = nullptr; - - /* the data collecting engine instances */ - QADataCollectingEngine** qaDataCE; - PidDataCollectingEngine** pidDataCE; - - /* the histogram registries */ - HistogramRegistry registry_one{"registry_one", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_two{"registry_two", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_three{"registry_three", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_four{"registry_four", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_five{"registry_five", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_six{"registry_six", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_seven{"registry_seven", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_eight{"registry_eight", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_nine{"registry_nine", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_ten{"registry_ten", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_pidone{"pidregistry_one", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_pidtwo{"pidregistry_two", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_pidthree{"pidregistry_three", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_pidfour{"pidregistry_four", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_pidfive{"pidregistry_five", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_pidsix{"pidregistry_six", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_pidseven{"pidregistry_seven", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_pideight{"pidregistry_eight", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_pidnine{"pidregistry_nine", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry_pidten{"pidregistry_ten", {}, OutputObjHandlingPolicy::AnalysisObject}; - std::vector registrybank{®istry_one, ®istry_two, ®istry_three, ®istry_four, ®istry_five, - ®istry_six, ®istry_seven, ®istry_eight, ®istry_nine, ®istry_ten}; - std::vector pidregistrybank{®istry_pidone, ®istry_pidtwo, ®istry_pidthree, ®istry_pidfour, ®istry_pidfive, - ®istry_pidsix, ®istry_pidseven, ®istry_pideight, ®istry_pidnine, ®istry_pidten}; - - Configurable inCentralityClasses{"usecentrality", false, "Perform the task using centrality/multiplicity classes. Default value: false"}; - - void init(o2::framework::InitContext& initContext) - { - using namespace efficiencyandqatask; - using namespace analysis::dptdptfilter; - - /* do nothing if not active */ - if (!doprocessDetectorLevelNotStored && !doprocessDetectorLevelNotStoredNoPID && !doprocessGeneratorLevelNotStored && !doprocessReconstructedNotStored && !doprocessReconstructedNotStoredNoPID) { - return; - } - - fPDG = TDatabasePDG::Instance(); - /* Self configuration: requires dptdptfilter task in the workflow */ - { - /* the binning */ - getTaskOptionValue(initContext, "dpt-dpt-filter", "overallminp", overallminp, false); - getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mZVtxbins", zvtxbins, false); - getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mZVtxmin", zvtxlow, false); - getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mZVtxmax", zvtxup, false); - getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mPTbins", ptbins, false); - getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mPTmin", ptlow, false); - getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mPTmax", ptup, false); - getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mEtabins", etabins, false); - getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mEtamin", etalow, false); - getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mEtamax", etaup, false); - - /* configuring the involved species */ - std::vector cfgnames = {"elpidsel", "mupidsel", "pipidsel", "kapidsel", "prpidsel"}; - std::vector spids = {0, 1, 2, 3, 4}; - for (uint i = 0; i < cfgnames.size(); ++i) { - auto includeIt = [&initContext](int spid, auto name) { - bool mUseIt = false; - bool mExcludeIt = false; - if (getTaskOptionValue(initContext, "dpt-dpt-filter-tracks", TString::Format("%s.mUseIt", name.c_str()).Data(), mUseIt, false) && - getTaskOptionValue(initContext, "dpt-dpt-filter-tracks", TString::Format("%s.mExclude", name.c_str()).Data(), mExcludeIt, false)) { - if (mUseIt && !mExcludeIt) { - auto cfg = new o2::analysis::TrackSelectionPIDCfg(); - cfg->mUseIt = true; - cfg->mExclude = false; - pidselector.Add(spid, cfg); - } - } - }; - includeIt(spids[i], cfgnames[i]); - } - uint nspecies = pidselector.getNSpecies(); - if (nspecies == 0) { - /* unidentified analysis */ - poinames.push_back(pidselector.getHadFName()); - tnames.push_back(std::string(TString::Format("%sP", pidselector.getHadFName()).Data())); - tnames.push_back(std::string(TString::Format("%sM", pidselector.getHadFName()).Data())); - LOGF(info, "Incorporated species name %s to the analysis", poinames[0].c_str()); - } else { - for (uint8_t ix = 0; ix < nspecies; ++ix) { - poinames.push_back(std::string(pidselector.getSpeciesFName(ix))); - tnames.push_back(std::string(TString::Format("%sP", pidselector.getSpeciesFName(ix)).Data())); - tnames.push_back(std::string(TString::Format("%sM", pidselector.getSpeciesFName(ix)).Data())); - LOGF(info, "Incorporated species name %s to the analysis", poinames[ix].c_str()); - } - } - - /* create the data collecting engine instances according to the configured centrality/multiplicity ranges */ - std::string centspec; - if (inCentralityClasses.value && getTaskOptionValue(initContext, "dpt-dpt-filter", "centralities", centspec, false)) { - LOGF(info, "Got the centralities specification: %s", centspec.c_str()); - auto tokens = TString(centspec.c_str()).Tokenize(","); - ncmranges = tokens->GetEntries(); - fCentMultMin = new float[ncmranges]; - fCentMultMax = new float[ncmranges]; - for (uint i = 0; i < ncmranges; ++i) { - float cmmin = 0.0f; - float cmmax = 0.0f; - sscanf(tokens->At(i)->GetName(), "%f-%f", &cmmin, &cmmax); - fCentMultMin[i] = cmmin; - fCentMultMax[i] = cmmax; - } - delete tokens; - } else { - LOGF(info, "No centralities specification. Setting it to: 0-100"); - ncmranges = 1; - fCentMultMin = new float[ncmranges]; - fCentMultMax = new float[ncmranges]; - fCentMultMin[0] = 0.0f; - fCentMultMax[0] = 100.0f; - } - bool doPidAnalysis = doprocessDetectorLevelNotStored || doprocessReconstructedNotStored; - qaDataCE = new QADataCollectingEngine*[ncmranges]; - if (doPidAnalysis) { - pidDataCE = new PidDataCollectingEngine*[ncmranges]; - } - std::string recogen; - if (!(doprocessReconstructedNotStored || doprocessReconstructedNotStoredNoPID) && !(doprocessDetectorLevelNotStored || doprocessDetectorLevelNotStoredNoPID)) { - LOGF(fatal, "Neither reco nor detector level not configured. Please, fix it!"); - } - if (ncmranges > registrybank.size()) { - LOGF(fatal, "There are more centrality ranges configured than registries in the bank. Please fix it!"); - } - /* in reverse order for proper order in results file */ - for (uint i = 0; i < ncmranges; ++i) { - auto initializeCEInstance = [&](auto dce, auto name, auto& registry) { - /* crete the output list for the passed centrality/multiplicity range */ - /* init the data collection instance */ - dce->template init(registry, name.Data()); - if (doprocessGeneratorLevelNotStored) { - dce->template init(registry, name.Data()); - } - }; - auto buildQACEInstance = [&](float min, float max) { - auto* dce = new QADataCollectingEngine(); - initializeCEInstance(dce, TString::Format("EfficiencyAndQaData-%d-%d", static_cast(min), static_cast(max)), *registrybank[i]); - return dce; - }; - auto buildPidCEInstance = [&](float min, float max) { - auto* dce = new PidDataCollectingEngine(); - initializeCEInstance(dce, TString::Format("EfficiencyAndPidData-%d-%d", static_cast(min), static_cast(max)), *pidregistrybank[i]); - return dce; - }; - /* in reverse order for proper order in results file */ - qaDataCE[ncmranges - i - 1] = buildQACEInstance(fCentMultMin[ncmranges - i - 1], fCentMultMax[ncmranges - i - 1]); - if (doPidAnalysis) { - pidDataCE[ncmranges - i - 1] = buildPidCEInstance(fCentMultMin[ncmranges - i - 1], fCentMultMax[ncmranges - i - 1]); - } - } - for (uint i = 0; i < ncmranges; ++i) { - LOGF(info, " centrality/multipliicty range: %d, low limit: %0.2f, up limit: %0.2f", i, fCentMultMin[i], fCentMultMax[i]); - } - } - } - - /// \brief Get the data collecting engine index corresponding to the passed collision - template - int getDCEindex(FilteredCollision collision) - { - if (!inCentralityClasses.value) { - return 0; - } else { - int ixDCE = -1; - float cm = collision.centmult(); - for (uint i = 0; i < ncmranges; ++i) { - if (cm < fCentMultMax[i]) { - ixDCE = i; - break; - } - } - if (!(ixDCE < 0)) { - if (cm < fCentMultMin[ixDCE]) { - ixDCE = -1; - } - } - return ixDCE; - } - } - - template - void processTracks(FilterdCollision const& collision, PassedTracks const& tracks) - { - using namespace efficiencyandqatask; - - int ixDCE = getDCEindex(collision); - if (!(ixDCE < 0)) { - for (auto& track : tracks) { - qaDataCE[ixDCE]->processTrack(collision.posZ(), track); - if constexpr (dopid) { - pidDataCE[ixDCE]->processTrack(track); - } - } - } - } - - void process(aod::Collisions const& collisions) - { - /* void function for alow processing the timestamp check task on faulty productions */ - LOGF(debug, "Received %d collisions", collisions.size()); - } - - using tpcPID = soa::Join; - using tofPID = soa::Join; - - Filter onlyacceptedcollisions = (aod::dptdptfilter::collisionaccepted == uint8_t(true)); - - void processReconstructedNotStored(soa::Filtered>::iterator const& collision, - soa::Join& tracks) - { - using namespace efficiencyandqatask; - - processTracks(collision, tracks); - } - PROCESS_SWITCH(DptDptEfficiencyAndQc, processReconstructedNotStored, "Process reconstructed efficiency and QA for not stored derived data", false); - - void processDetectorLevelNotStored(soa::Filtered>::iterator const& collision, - soa::Join& tracks, - soa::Join const&) - { - using namespace efficiencyandqatask; - - processTracks(collision, tracks); - } - PROCESS_SWITCH(DptDptEfficiencyAndQc, processDetectorLevelNotStored, "Process MC detector level efficiency and QA for not stored derived data", false); - - void processGeneratorLevelNotStored(soa::Filtered>::iterator const& collision, - soa::Join& particles) - { - using namespace efficiencyandqatask; - - processTracks(collision, particles); - } - PROCESS_SWITCH(DptDptEfficiencyAndQc, processGeneratorLevelNotStored, "Process MC generator level efficiency and QA for not stored derived data", true); - - void processReconstructedNotStoredNoPID(soa::Filtered>::iterator const& collision, - soa::Join& tracks) - { - using namespace efficiencyandqatask; - - processTracks(collision, tracks); - } - PROCESS_SWITCH(DptDptEfficiencyAndQc, processReconstructedNotStoredNoPID, "Process reconstructed efficiency and QA for not stored derived data", false); - - void processDetectorLevelNotStoredNoPID(soa::Filtered>::iterator const& collision, - soa::Join& tracks, - soa::Join const&) - { - using namespace efficiencyandqatask; - - processTracks(collision, tracks); - } - PROCESS_SWITCH(DptDptEfficiencyAndQc, processDetectorLevelNotStoredNoPID, "Process MC detector level efficiency and QA for not stored derived data", true); -}; - -using BCsWithTimestamps = soa::Join; - -struct checkTimestamp { - - o2::ccdb::CcdbApi ccdb_api; - int mRunNumber; - ULong64_t runsor = 0; - ULong64_t runeor = 0; - std::shared_ptr hTimeStampDiffNegative = nullptr; - std::shared_ptr hTimeStampDiffPositive = nullptr; - - Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; - - void init(InitContext&) - { - LOG(info) << "Initializing check timestamp task"; - AxisSpec diffAxis{10000, 0.0001, 1000000, "time (s)"}; - diffAxis.makeLogarithmic(); - - hTimeStampDiffNegative = registry.add("DiffNegative", "Time before SOR (s)", kTH2F, {{100, 0.5, 100.5, "Run number"}, diffAxis}); - hTimeStampDiffPositive = registry.add("DiffPositive", "Time after EOR (s)", kTH2F, {{100, 0.5, 100.5, "Run number"}, diffAxis}); - ccdb_api.init(ccdburl); - } - - void process(aod::Collisions const& collisions, BCsWithTimestamps const&) - { - for (auto const& collision : collisions) { - /* check the previous run number */ - auto bc = collision.bc_as(); - if (bc.runNumber() != mRunNumber) { - LOGF(info, "timestamp=%llu, run number=%d", bc.timestamp(), bc.runNumber()); - mRunNumber = bc.runNumber(); - - // read SOR and EOR timestamps from RCT CCDB via utility function - auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdb_api, mRunNumber, false); - runeor = soreor.second; - runsor = soreor.first; - } - if (bc.timestamp() < runsor || runeor < bc.timestamp()) { - /* we got a wrong timestamp let's convert the out of run time to seconds */ - if (bc.timestamp() < runsor) { - hTimeStampDiffNegative->Fill(Form("%d", mRunNumber), (runsor - bc.timestamp()) / 1000, 1); - } else { - hTimeStampDiffPositive->Fill(Form("%d", mRunNumber), (bc.timestamp() - runeor) / 1000, 1); - } - } - } - } -}; - -//**************************************************************************************** -/** - * Workflow definition. - */ -//**************************************************************************************** -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec workflow{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; - return workflow; -} diff --git a/PWGCF/TwoParticleCorrelations/Tasks/identifiedbf.cxx b/PWGCF/TwoParticleCorrelations/Tasks/identifiedbf.cxx index 8fe88041085..b357272c17c 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/identifiedbf.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/identifiedbf.cxx @@ -9,8 +9,10 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file identifiedbf.cxx +/// \brief Fills histograms with particles and tracks to calculate the Balance Function +/// \author bghanley1995@gmail.com #include -#include #include #include #include @@ -23,16 +25,21 @@ #include #include #include +#include +#include +#include #include "Common/Core/TrackSelection.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/RecoDecay.h" #include "DataFormatsParameters/GRPObject.h" #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "PWGCF/Core/AnalysisConfigurableCuts.h" #include "PWGCF/Core/PairCuts.h" #include "PWGCF/TwoParticleCorrelations/DataModel/IdentifiedBfFiltered.h" @@ -60,6 +67,8 @@ float deltaphibinwidth = constants::math::TwoPI / deltaphibins; float deltaphilow = 0.0 - deltaphibinwidth / 2.0; float deltaphiup = constants::math::TwoPI - deltaphibinwidth / 2.0; +int maxLogComb = 10; + bool processpairs = false; bool processmixedevents = false; bool ptorder = false; @@ -68,11 +77,11 @@ PairCuts fPairCuts; // pair suppression engine bool fUseConversionCuts = false; // suppress resonances and conversions bool fUseTwoTrackCut = false; // suppress too close tracks -std::vector tname = {"O", "T", "e+", "e-", "mu+", "mu-", "pi+", "pi-", "K+", "K-", "p+", "p-"}; ///< the track names +std::vector tname = {"e+", "e-", "pi+", "pi-", "K+", "K-", "p+", "p-"}; ///< the track names } // namespace correlationstask // Task for building correlations -struct IdentifiedBfCorrelationsTask { +struct IdentifiedbfTask { /* the data collecting engine */ template @@ -85,45 +94,44 @@ struct IdentifiedBfCorrelationsTask { //============================================================================================ /* histograms */ TH1F* fhVertexZA; //! fhN1_vsPt{nch, nullptr}; //! fhN1_vsEtaPhi{nch, nullptr}; //! fhSum1Pt_vsEtaPhi{nch, nullptr}; //! fhN1_vsZEtaPhiPt{nch, nullptr}; //! fhSum1Pt_vsZEtaPhiPt{nch, nullptr}; //! fhNuaNue_vsZEtaPhiPt{nch, nullptr}; //! fhPtAvg_vsEtaPhi{nch, nullptr}; //!> fhN2_vsPtPt{nch, {nch, nullptr}}; //!> fhN2_vsDEtaDPhi{nch, {nch, nullptr}}; //!> fhN2cont_vsDEtaDPhi{nch, {nch, nullptr}}; //!> fhSum2PtPt_vsDEtaDPhi{nch, {nch, nullptr}}; //!> fhSum2DptDpt_vsDEtaDPhi{nch, {nch, nullptr}}; //!) ({p_T}_2 - <{p_T}_2>) \f$ distribution vs \f$\Delta\eta,\;\Delta\phi\f$ for the different species combinations - std::vector> fhSupN1N1_vsDEtaDPhi{nch, {nch, nullptr}}; //!> fhSupPt1Pt1_vsDEtaDPhi{nch, {nch, nullptr}}; //! fhN1VsPt{nch, nullptr}; //! fhN1VsEtaPhi{nch, nullptr}; //! fhSum1PtVsEtaPhi{nch, nullptr}; //! fhN1VsZEtaPhiPt{nch + 1, nullptr}; //! fhN1VsZEtaPhiPtPrimary{nch, nullptr}; //! fhN1VsZEtaPhiPtSecondary{nch, nullptr}; //! fhN1VsZEtaPhiPtPure{nch + 1, nullptr}; //! fhSum1PtVsZEtaPhiPt{nch, nullptr}; //! fhNuaNueVsZEtaPhiPt{nch, nullptr}; //! fhPtAvgVsEtaPhi{nch, nullptr}; //!> fhN2VsPtPt{nch, {nch, nullptr}}; //!> fhN2VsDEtaDPhi{nch, {nch, nullptr}}; //!> fhN2ContVsDEtaDPhi{nch, {nch, nullptr}}; //!> fhSum2PtPtVsDEtaDPhi{nch, {nch, nullptr}}; //!> fhSum2DptDptVsDEtaDPhi{nch, {nch, nullptr}}; //!) ({p_T}_2 - <{p_T}_2>) \f$ distribution vs \f$\Delta\eta,\;\Delta\phi\f$ for the different species combinations + std::vector> fhSupN1N1VsDEtaDPhi{nch, {nch, nullptr}}; //!> fhSupPt1Pt1VsDEtaDPhi{nch, {nch, nullptr}}; //! fhN1_vsC{nch, nullptr}; //! fhSum1Pt_vsC{nch, nullptr}; //! fhN1nw_vsC{nch, nullptr}; //! fhSum1Ptnw_vsC{nch, nullptr}; //!> fhN2_vsC{nch, {nch, nullptr}}; //!> fhSum2PtPt_vsC{nch, {nch, nullptr}}; //!> fhSum2DptDpt_vsC{nch, {nch, nullptr}}; //!) ({p_T}_2 - <{p_T}_2>) \f$ distribution vs event centrality/multiplicity 1-1,1-2,2-1,2-2, combinations - std::vector> fhN2nw_vsC{nch, {nch, nullptr}}; //!> fhSum2PtPtnw_vsC{nch, {nch, nullptr}}; //!> fhSum2DptDptnw_vsC{nch, {nch, nullptr}}; //!) ({p_T}_2 - <{p_T}_2>) \f$ distribution vs \f$\Delta\eta,\;\Delta\phi\f$ distribution vs event centrality/multiplicity 1-1,1-2,2-1,2-2, combinations + std::vector fhN1VsC{nch, nullptr}; //! fhSum1PtVsC{nch, nullptr}; //! fhN1NWVsC{nch, nullptr}; //! fhSum1PtNWVsC{nch, nullptr}; //!> fhN2VsC{nch, {nch, nullptr}}; //!> fhSum2PtPtVsC{nch, {nch, nullptr}}; //!> fhSum2DptDptVsC{nch, {nch, nullptr}}; //!) ({p_T}_2 - <{p_T}_2>) \f$ distribution vs event centrality/multiplicity 1-1,1-2,2-1,2-2, combinations + std::vector> fhN2NWVsC{nch, {nch, nullptr}}; //!> fhSum2PtPtNWVsC{nch, {nch, nullptr}}; //!> fhSum2DptDptNWVsC{nch, {nch, nullptr}}; //!) ({p_T}_2 - <{p_T}_2>) \f$ distribution vs \f$\Delta\eta,\;\Delta\phi\f$ distribution vs event centrality/multiplicity 1-1,1-2,2-1,2-2, combinations std::vector> chargePairsNames = {{"OO", "OT"}, {"TO", "TT"}}; - std::vector> speciesPairNames = {{"OO", "OT", "OeO", "OeT", "OmuO", "OmuT", "OpiO", "OpiT", "OKO", "OKT", "OpO", "OpT"}, - {"TO", "TT", "TeO", "TeT", "TmuO", "TmuT", "TpiO", "TpiT", "TKO", "TKT", "TpO", "TpT"}, - {"eOO", "eOT", "eOeO", "eOeT", "eOmuO", "eOmuT", "eOpiO", "eOpiT", "eOKO", "eOKT", "eOpO", "eOpT"}, - {"eTO", "eTT", "eTeO", "eTeT", "eTmuO", "eTmuT", "eTpiO", "eTpiT", "eTKO", "eTKT", "eTpO", "eTpT"}, - {"muOO", "muOT", "muOeO", "muOeT", "muOmuO", "muOmuT", "muOpiO", "muOpiT", "muOKO", "muOKT", "muOpO", "muOpT"}, - {"muTO", "muTT", "muTeO", "muTeT", "muTmuO", "muTmuT", "muTpiO", "muTpiT", "muTKO", "muTKT", "muTpO", "muTpT"}, - {"piOO", "piOT", "piOeO", "piOeT", "piOmuO", "piOmuT", "piOpiO", "piOpiT", "piOKO", "piOKT", "piOpO", "piOpT"}, - {"piTO", "piTT", "piTeO", "piTeT", "piTmuO", "piTmuT", "piTpiO", "piTpiT", "piTKO", "piTKT", "piTpO", "piTpT"}, - {"KOO", "KOT", "KOeO", "KOeT", "KOmuO", "KOmuT", "KOpiO", "KOpiT", "KOKO", "KOKT", "KOpO", "KOpT"}, - {"KTO", "KTT", "KTeO", "KTeT", "KTmuO", "KTmuT", "KTpiO", "KTpiT", "KTKO", "KTKT", "KTpO", "KTpT"}, - {"pOO", "pOT", "pOeO", "pOeT", "pOmuO", "pOmuT", "pOpiO", "pOpiT", "pOKO", "pOKT", "pOpO", "pOpT"}, - {"pTO", "pTT", "pTeO", "pTeT", "pTmuO", "pTmuT", "pTpiO", "pTpiT", "pTKO", "pTKT", "pTpO", "pTpT"}}; + std::vector> speciesPairNames = {{"e+e+", "e+e-", "e+pi+", "e+pi-", "e+K+", "e+K-", "e+p+", "e+p-"}, + {"e-e+", "e-e-", "e-pi+", "e-pi-", "e-K+", "e-K-", "e-p+", "e-p-"}, + {"pi+e+", "pi+e-", "pi+pi+", "pi+pi-", "pi+K+", "pi+K-", "pi+p+", "pi+p-"}, + {"pi-e+", "pi-e-", "pi-pi+", "pi-pi-", "pi-K+", "pi-K-", "pi-p+", "pi-p-"}, + {"K+e+", "K+e-", "K+pi+", "K+pi-", "K+K+", "K+K-", "K+p+", "K+p-"}, + {"K-e+", "K-e-", "K-pi+", "K-pi-", "K-K+", "K-K-", "K-p+", "K-p-"}, + {"p+e+", "p+e-", "p+pi+", "p+pi-", "p+K+", "p+K-", "p+p+", "p+p-"}, + {"p-e+", "p-e-", "p-pi+", "p-pi-", "p-K+", "p-K-", "p-p+", "p-p-"}}; bool ccdbstored = false; float isCCDBstored() @@ -134,15 +142,12 @@ struct IdentifiedBfCorrelationsTask { /// \brief Returns the potentially phi origin shifted phi /// \param phi the track azimuthal angle /// \return the track phi origin shifted azimuthal angle - float GetShiftedPhi(float phi) + float getShiftedPhi(float phi) { using namespace correlationstask; using namespace o2::analysis::identifiedbffilter; - if (!(phi < phiup)) { - return phi - constants::math::TwoPI; - } else { - return phi; - } + phi = RecoDecay::constrainAngle(phi, philow, 1U); + return phi; } /// \brief Returns the zero based bin index of the eta phi passed track @@ -158,14 +163,14 @@ struct IdentifiedBfCorrelationsTask { /// the track has been accepted and it is within that ranges /// IF THAT IS NOT THE CASE THE ROUTINE WILL PRODUCE NONSENSE RESULTS template - int GetEtaPhiIndex(TrackObject const& t) + int getEtaPhiIndex(TrackObject const& t) { using namespace correlationstask; using namespace o2::analysis::identifiedbffilter; int etaix = static_cast((t.eta() - etalow) / etabinwidth); /* consider a potential phi origin shift */ - float phi = GetShiftedPhi(t.phi()); + float phi = getShiftedPhi(t.phi()); int phiix = static_cast((phi - philow) / phibinwidth); return etaix * phibins + phiix; } @@ -180,28 +185,28 @@ struct IdentifiedBfCorrelationsTask { /// the tracks have been accepted and they are within that ranges /// IF THAT IS NOT THE CASE THE ROUTINE WILL PRODUCE NONSENSE RESULTS template - int GetDEtaDPhiGlobalIndex(TrackObject const& t1, TrackObject const& t2) + int getDEtaDPhiGlobalIndex(TrackObject const& t1, TrackObject const& t2) { using namespace correlationstask; using namespace o2::analysis::identifiedbffilter; /* rule: ix are always zero based while bins are always one based */ - int etaix_1 = static_cast((t1.eta() - etalow) / etabinwidth); + int etaix1 = static_cast((t1.eta() - etalow) / etabinwidth); /* consider a potential phi origin shift */ - float phi = GetShiftedPhi(t1.phi()); - int phiix_1 = static_cast((phi - philow) / phibinwidth); - int etaix_2 = static_cast((t2.eta() - etalow) / etabinwidth); + float phi = getShiftedPhi(t1.phi()); + int phiix1 = static_cast((phi - philow) / phibinwidth); + int etaix2 = static_cast((t2.eta() - etalow) / etabinwidth); /* consider a potential phi origin shift */ - phi = GetShiftedPhi(t2.phi()); - int phiix_2 = static_cast((phi - philow) / phibinwidth); + phi = getShiftedPhi(t2.phi()); + int phiix2 = static_cast((phi - philow) / phibinwidth); - int deltaeta_ix = etaix_1 - etaix_2 + etabins - 1; - int deltaphi_ix = phiix_1 - phiix_2; - if (deltaphi_ix < 0) { - deltaphi_ix += phibins; + int deltaetaix = etaix1 - etaix2 + etabins - 1; + int deltaphiix = phiix1 - phiix2; + if (deltaphiix < 0) { + deltaphiix += phibins; } - return fhN2_vsDEtaDPhi[0][0]->GetBin(deltaeta_ix + 1, deltaphi_ix + 1); + return fhN2VsDEtaDPhi[0][0]->GetBin(deltaetaix + 1, deltaphiix + 1); } void storeTrackCorrections(std::vector corrs) @@ -209,15 +214,15 @@ struct IdentifiedBfCorrelationsTask { LOGF(info, "Stored NUA&NUE corrections for %d track ids", corrs.size()); for (uint i = 0; i < corrs.size(); ++i) { LOGF(info, " Stored NUA&NUE corrections %s for track id %d %s", corrs[i] != nullptr ? corrs[i]->GetName() : "nullptr", i, corrs[i] != nullptr ? "yes" : "no"); - fhNuaNue_vsZEtaPhiPt[i] = corrs[i]; - if (fhNuaNue_vsZEtaPhiPt[i] != nullptr) { + fhNuaNueVsZEtaPhiPt[i] = corrs[i]; + if (fhNuaNueVsZEtaPhiPt[i] != nullptr) { int nbins = 0; double avg = 0.0; - for (int ix = 0; ix < fhNuaNue_vsZEtaPhiPt[i]->GetNbinsX(); ++ix) { - for (int iy = 0; iy < fhNuaNue_vsZEtaPhiPt[i]->GetNbinsY(); ++iy) { - for (int iz = 0; iz < fhNuaNue_vsZEtaPhiPt[i]->GetNbinsZ(); ++iz) { + for (int ix = 0; ix < fhNuaNueVsZEtaPhiPt[i]->GetNbinsX(); ++ix) { + for (int iy = 0; iy < fhNuaNueVsZEtaPhiPt[i]->GetNbinsY(); ++iy) { + for (int iz = 0; iz < fhNuaNueVsZEtaPhiPt[i]->GetNbinsZ(); ++iz) { nbins++; - avg += fhNuaNue_vsZEtaPhiPt[i]->GetBinContent(ix + 1, iy + 1, iz + 1); + avg += fhNuaNueVsZEtaPhiPt[i]->GetBinContent(ix + 1, iy + 1, iz + 1); } } } @@ -232,7 +237,7 @@ struct IdentifiedBfCorrelationsTask { LOGF(info, "Stored pT average for %d track ids", ptavgs.size()); for (uint i = 0; i < ptavgs.size(); ++i) { LOGF(info, " Stored pT average for track id %d %s", i, ptavgs[i] != nullptr ? "yes" : "no"); - fhPtAvg_vsEtaPhi[i] = ptavgs[i]; + fhPtAvgVsEtaPhi[i] = ptavgs[i]; } ccdbstored = true; } @@ -242,9 +247,9 @@ struct IdentifiedBfCorrelationsTask { { std::vector* corr = new std::vector(tracks.size(), 1.0f); int index = 0; - for (auto& t : tracks) { - if (fhNuaNue_vsZEtaPhiPt[t.trackacceptedid()] != nullptr) { - (*corr)[index] = fhNuaNue_vsZEtaPhiPt[t.trackacceptedid()]->GetBinContent(fhNuaNue_vsZEtaPhiPt[t.trackacceptedid()]->FindFixBin(zvtx, GetEtaPhiIndex(t) + 0.5, t.pt())); + for (const auto& t : tracks) { + if (fhNuaNueVsZEtaPhiPt[t.trackacceptedid()] != nullptr) { + (*corr)[index] = fhNuaNueVsZEtaPhiPt[t.trackacceptedid()]->GetBinContent(fhNuaNueVsZEtaPhiPt[t.trackacceptedid()]->FindFixBin(zvtx, getEtaPhiIndex(t) + 0.5, t.pt())); } index++; } @@ -256,15 +261,93 @@ struct IdentifiedBfCorrelationsTask { { std::vector* ptavg = new std::vector(tracks.size(), 0.0f); int index = 0; - for (auto& t : tracks) { - if (fhPtAvg_vsEtaPhi[t.trackacceptedid()] != nullptr) { - (*ptavg)[index] = fhPtAvg_vsEtaPhi[t.trackacceptedid()]->GetBinContent(fhPtAvg_vsEtaPhi[t.trackacceptedid()]->FindFixBin(t.eta(), t.phi())); + for (const auto& t : tracks) { + if (fhPtAvgVsEtaPhi[t.trackacceptedid()] != nullptr) { + (*ptavg)[index] = fhPtAvgVsEtaPhi[t.trackacceptedid()]->GetBinContent(fhPtAvgVsEtaPhi[t.trackacceptedid()]->FindFixBin(t.eta(), t.phi())); index++; } } return ptavg; } + /// \brief checks whether MC track is a physical primary or secondary + /// \param track passed MC track converted to MCParticle + template + void trackPrimaryCheck(TrackObject const& track, float zvtx, float corr) + { + if constexpr (framework::has_type_v) { + if (isPrimaryCheck(track.template mcParticle_as())) { + fhN1VsZEtaPhiPtPrimary[track.trackacceptedid()]->Fill(zvtx, getEtaPhiIndex(track) + 0.5, track.pt(), corr); + } else { + fhN1VsZEtaPhiPtSecondary[track.trackacceptedid()]->Fill(zvtx, getEtaPhiIndex(track) + 0.5, track.pt(), corr); + } + } else if constexpr (framework::has_type_v) { + if (isPrimaryCheck(track)) { + fhN1VsZEtaPhiPtPrimary[track.trackacceptedid()]->Fill(zvtx, getEtaPhiIndex(track) + 0.5, track.pt(), corr); + } else { + fhN1VsZEtaPhiPtSecondary[track.trackacceptedid()]->Fill(zvtx, getEtaPhiIndex(track) + 0.5, track.pt(), corr); + } + } + } + + /// \brief checks whether MC track is a physical primary or secondary + /// \param particle passed MC track converted to MCParticle + template + bool isPrimaryCheck(ParticleObject const& particle) + { + return particle.isPhysicalPrimary(); + } + + /// \brief checks whether MC track is a physical primary or secondary + /// \param particle passed MC track converted to MCParticle + template + bool isSpeciesCheck(ParticleObject const& particle, int trkId) + { + int pdgcode = particle.pdgCode(); + int realPID = -1; + switch (pdgcode) { + case kPositron: + realPID = 0; + break; + case kElectron: + realPID = 1; + break; + case kPiPlus: + realPID = 2; + break; + case kPiMinus: + realPID = 3; + break; + case kKPlus: + realPID = 4; + break; + case kKMinus: + realPID = 5; + break; + case kProton: + realPID = 6; + break; + case kProtonBar: + realPID = 7; + break; + default: + realPID = -1; + break; + } + return (realPID == trkId); + } + + /// \brief checks whether MC track is a physical primary or secondary + /// \param particle passed MC track converted to MCParticle + template + bool isPrimarySpeciesCheck(TrackObject const& track, int trkId) + { + if constexpr (framework::has_type_v) { + return (isPrimaryCheck(track.template mcParticle_as()) && isSpeciesCheck(track.template mcParticle_as(), trkId)); + } + return false; + } + /// \brief fills the singles histograms in singles execution mode /// \param passedtracks filtered table with the tracks associated to the passed index /// \param tix index, in the singles histogram bank, for the passed filetered track table @@ -272,15 +355,20 @@ struct IdentifiedBfCorrelationsTask { void processSingles(TrackListObject const& passedtracks, std::vector* corrs, float zvtx) { int index = 0; - for (auto& track : passedtracks) { + for (const auto& track : passedtracks) { float corr = (*corrs)[index]; - fhN1_vsPt[track.trackacceptedid()]->Fill(track.pt(), corr); + fhN1VsPt[track.trackacceptedid()]->Fill(track.pt(), corr); if constexpr (smallsingles) { - fhN1_vsEtaPhi[track.trackacceptedid()]->Fill(track.eta(), GetShiftedPhi(track.phi()), corr); - fhSum1Pt_vsEtaPhi[track.trackacceptedid()]->Fill(track.eta(), GetShiftedPhi(track.phi()), track.pt() * corr); + fhN1VsEtaPhi[track.trackacceptedid()]->Fill(track.eta(), getShiftedPhi(track.phi()), corr); + fhSum1PtVsEtaPhi[track.trackacceptedid()]->Fill(track.eta(), getShiftedPhi(track.phi()), track.pt() * corr); } else { - fhN1_vsZEtaPhiPt[track.trackacceptedid()]->Fill(zvtx, GetEtaPhiIndex(track) + 0.5, track.pt(), corr); - fhSum1Pt_vsZEtaPhiPt[track.trackacceptedid()]->Fill(zvtx, GetEtaPhiIndex(track) + 0.5, track.pt(), track.pt() * corr); + fhN1VsZEtaPhiPt[nch]->Fill(zvtx, getEtaPhiIndex(track) + 0.5, track.pt(), corr); + fhN1VsZEtaPhiPt[track.trackacceptedid()]->Fill(zvtx, getEtaPhiIndex(track) + 0.5, track.pt(), corr); + fhSum1PtVsZEtaPhiPt[track.trackacceptedid()]->Fill(zvtx, getEtaPhiIndex(track) + 0.5, track.pt(), track.pt() * corr); + trackPrimaryCheck(track, zvtx, corr); + if (isPrimarySpeciesCheck(track, track.trackacceptedid())) { + fhN1VsZEtaPhiPtPure[track.trackacceptedid()]->Fill(zvtx, getEtaPhiIndex(track) + 0.5, track.pt(), corr); + } } index++; } @@ -301,22 +389,22 @@ struct IdentifiedBfCorrelationsTask { std::vector n1nw(nch, 0.0); ///< not weighted number of single tracks for current collision std::vector sum1Ptnw(nch, 0.0); ///< accumulated sum of not weighted single \f$p_T\f$ for current collision int index = 0; - for (auto& track : passedtracks) { + for (const auto& track : passedtracks) { float corr = (*corrs)[index]; n1[track.trackacceptedid()] += corr; sum1Pt[track.trackacceptedid()] += track.pt() * corr; n1nw[track.trackacceptedid()] += 1; sum1Ptnw[track.trackacceptedid()] += track.pt(); - fhN1_vsEtaPhi[track.trackacceptedid()]->Fill(track.eta(), GetShiftedPhi(track.phi()), corr); - fhSum1Pt_vsEtaPhi[track.trackacceptedid()]->Fill(track.eta(), GetShiftedPhi(track.phi()), track.pt() * corr); + fhN1VsEtaPhi[track.trackacceptedid()]->Fill(track.eta(), getShiftedPhi(track.phi()), corr); + fhSum1PtVsEtaPhi[track.trackacceptedid()]->Fill(track.eta(), getShiftedPhi(track.phi()), track.pt() * corr); index++; } for (uint tid = 0; tid < nch; ++tid) { - fhN1_vsC[tid]->Fill(cmul, n1[tid]); - fhSum1Pt_vsC[tid]->Fill(cmul, sum1Pt[tid]); - fhN1nw_vsC[tid]->Fill(cmul, n1nw[tid]); - fhSum1Ptnw_vsC[tid]->Fill(cmul, sum1Ptnw[tid]); + fhN1VsC[tid]->Fill(cmul, n1[tid]); + fhSum1PtVsC[tid]->Fill(cmul, sum1Pt[tid]); + fhN1NWVsC[tid]->Fill(cmul, n1nw[tid]); + fhSum1PtNWVsC[tid]->Fill(cmul, sum1Ptnw[tid]); } } @@ -340,11 +428,11 @@ struct IdentifiedBfCorrelationsTask { std::vector> sum2DptDptnw(nch, std::vector(nch, 0.0)); ///< accumulated sum of not weighted number of track 1 tracks times not weighted track 2 \f$p_T\f$ for current collision int index1 = 0; - for (auto& track1 : trks1) { - double ptavg_1 = (*ptavgs1)[index1]; + for (const auto& track1 : trks1) { + double ptavg1 = (*ptavgs1)[index1]; double corr1 = (*corrs1)[index1]; int index2 = 0; - for (auto& track2 : trks2) { + for (const auto& track2 : trks2) { /* checking the same track id condition */ if (track1 == track2) { /* exclude autocorrelations */ @@ -357,26 +445,21 @@ struct IdentifiedBfCorrelationsTask { } } /* process pair magnitudes */ - double ptavg_2 = (*ptavgs2)[index2]; + double ptavg2 = (*ptavgs2)[index2]; double corr2 = (*corrs2)[index2]; double corr = corr1 * corr2; - double dptdptnw = (track1.pt() - ptavg_1) * (track2.pt() - ptavg_2); - double dptdptw = (corr1 * track1.pt() - ptavg_1) * (corr2 * track2.pt() - ptavg_2); + double dptdptnw = (track1.pt() - ptavg1) * (track2.pt() - ptavg2); + double dptdptw = (corr1 * track1.pt() - ptavg1) * (corr2 * track2.pt() - ptavg2); /* get the global bin for filling the differential histograms */ - int globalbin = GetDEtaDPhiGlobalIndex(track1, track2); + int globalbin = getDEtaDPhiGlobalIndex(track1, track2); float deltaeta = track1.eta() - track2.eta(); float deltaphi = track1.phi() - track2.phi(); - while (deltaphi >= deltaphiup) { - deltaphi -= constants::math::TwoPI; - } - while (deltaphi < deltaphilow) { - deltaphi += constants::math::TwoPI; - } + deltaphi = RecoDecay::constrainAngle(deltaphi, deltaphilow, 1U); if ((fUseConversionCuts && fPairCuts.conversionCuts(track1, track2)) || (fUseTwoTrackCut && fPairCuts.twoTrackCut(track1, track2, bfield))) { /* suppress the pair */ - fhSupN1N1_vsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, corr); - fhSupPt1Pt1_vsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, track1.pt() * track2.pt() * corr); + fhSupN1N1VsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, corr); + fhSupPt1Pt1VsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, track1.pt() * track2.pt() * corr); n2sup[track1.trackacceptedid()][track2.trackacceptedid()] += corr; } else { /* count the pair */ @@ -387,30 +470,30 @@ struct IdentifiedBfCorrelationsTask { sum2PtPtnw[track1.trackacceptedid()][track2.trackacceptedid()] += track1.pt() * track2.pt(); sum2DptDptnw[track1.trackacceptedid()][track2.trackacceptedid()] += dptdptnw; - fhN2_vsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, corr); - fhN2cont_vsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->Fill(deltaeta, deltaphi, corr); - fhSum2DptDpt_vsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, dptdptw); - fhSum2PtPt_vsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, track1.pt() * track2.pt() * corr); + fhN2VsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, corr); + fhN2ContVsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->Fill(deltaeta, deltaphi, corr); + fhSum2DptDptVsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, dptdptw); + fhSum2PtPtVsDEtaDPhi[track1.trackacceptedid()][track2.trackacceptedid()]->AddBinContent(globalbin, track1.pt() * track2.pt() * corr); } - fhN2_vsPtPt[track1.trackacceptedid()][track2.trackacceptedid()]->Fill(track1.pt(), track2.pt(), corr); + fhN2VsPtPt[track1.trackacceptedid()][track2.trackacceptedid()]->Fill(track1.pt(), track2.pt(), corr); index2++; } index1++; } for (uint pid1 = 0; pid1 < nch; ++pid1) { for (uint pid2 = 0; pid2 < nch; ++pid2) { - fhN2_vsC[pid1][pid2]->Fill(cmul, n2[pid1][pid2]); - fhSum2PtPt_vsC[pid1][pid2]->Fill(cmul, sum2PtPt[pid1][pid2]); - fhSum2DptDpt_vsC[pid1][pid2]->Fill(cmul, sum2DptDpt[pid1][pid2]); - fhN2nw_vsC[pid1][pid2]->Fill(cmul, n2nw[pid1][pid2]); - fhSum2PtPtnw_vsC[pid1][pid2]->Fill(cmul, sum2PtPtnw[pid1][pid2]); - fhSum2DptDptnw_vsC[pid1][pid2]->Fill(cmul, sum2DptDptnw[pid1][pid2]); + fhN2VsC[pid1][pid2]->Fill(cmul, n2[pid1][pid2]); + fhSum2PtPtVsC[pid1][pid2]->Fill(cmul, sum2PtPt[pid1][pid2]); + fhSum2DptDptVsC[pid1][pid2]->Fill(cmul, sum2DptDpt[pid1][pid2]); + fhN2NWVsC[pid1][pid2]->Fill(cmul, n2nw[pid1][pid2]); + fhSum2PtPtNWVsC[pid1][pid2]->Fill(cmul, sum2PtPtnw[pid1][pid2]); + fhSum2DptDptNWVsC[pid1][pid2]->Fill(cmul, sum2DptDptnw[pid1][pid2]); /* let's also update the number of entries in the differential histograms */ - fhN2_vsDEtaDPhi[pid1][pid2]->SetEntries(fhN2_vsDEtaDPhi[pid1][pid2]->GetEntries() + n2[pid1][pid2]); - fhSum2DptDpt_vsDEtaDPhi[pid1][pid2]->SetEntries(fhSum2DptDpt_vsDEtaDPhi[pid1][pid2]->GetEntries() + n2[pid1][pid2]); - fhSum2PtPt_vsDEtaDPhi[pid1][pid2]->SetEntries(fhSum2PtPt_vsDEtaDPhi[pid1][pid2]->GetEntries() + n2[pid1][pid2]); - fhSupN1N1_vsDEtaDPhi[pid1][pid2]->SetEntries(fhSupN1N1_vsDEtaDPhi[pid1][pid2]->GetEntries() + n2sup[pid1][pid2]); - fhSupPt1Pt1_vsDEtaDPhi[pid1][pid2]->SetEntries(fhSupPt1Pt1_vsDEtaDPhi[pid1][pid2]->GetEntries() + n2sup[pid1][pid2]); + fhN2VsDEtaDPhi[pid1][pid2]->SetEntries(fhN2VsDEtaDPhi[pid1][pid2]->GetEntries() + n2[pid1][pid2]); + fhSum2DptDptVsDEtaDPhi[pid1][pid2]->SetEntries(fhSum2DptDptVsDEtaDPhi[pid1][pid2]->GetEntries() + n2[pid1][pid2]); + fhSum2PtPtVsDEtaDPhi[pid1][pid2]->SetEntries(fhSum2PtPtVsDEtaDPhi[pid1][pid2]->GetEntries() + n2[pid1][pid2]); + fhSupN1N1VsDEtaDPhi[pid1][pid2]->SetEntries(fhSupN1N1VsDEtaDPhi[pid1][pid2]->GetEntries() + n2sup[pid1][pid2]); + fhSupPt1Pt1VsDEtaDPhi[pid1][pid2]->SetEntries(fhSupPt1Pt1VsDEtaDPhi[pid1][pid2]->GetEntries() + n2sup[pid1][pid2]); } } } @@ -479,7 +562,7 @@ struct IdentifiedBfCorrelationsTask { using namespace o2::analysis::identifiedbffilter; /* create the histograms */ - Bool_t oldstatus = TH1::AddDirectoryStatus(); + bool oldstatus = TH1::AddDirectoryStatus(); TH1::AddDirectory(kFALSE); if (!processpairs) { @@ -487,23 +570,23 @@ struct IdentifiedBfCorrelationsTask { fOutputList->Add(fhVertexZA); for (uint i = 0; i < nch; ++i) { /* histograms for each track, one and two */ - fhN1_vsPt[i] = new TH1F(TString::Format("n1_%s_vsPt", tname[i].c_str()).Data(), - TString::Format("#LT n_{1} #GT;p_{t,%s} (GeV/c);#LT n_{1} #GT", tname[i].c_str()).Data(), - ptbins, ptlow, ptup); + fhN1VsPt[i] = new TH1F(TString::Format("n1_%s_vsPt", tname[i].c_str()).Data(), + TString::Format("#LT n_{1} #GT;p_{t,%s} (GeV/c);#LT n_{1} #GT", tname[i].c_str()).Data(), + ptbins, ptlow, ptup); /* we don't want the Sumw2 structure being created here */ bool defSumw2 = TH1::GetDefaultSumw2(); if constexpr (smallsingles) { - fhN1_vsEtaPhi[i] = new TH2F(TString::Format("n1_%s_vsEtaPhi", tname[i].c_str()).Data(), - TString::Format("#LT n_{1} #GT;#eta_{%s};#varphi_{%s} (radian);#LT n_{1} #GT", tname[i].c_str(), tname[i].c_str()).Data(), - etabins, etalow, etaup, phibins, philow, phiup); - fhSum1Pt_vsEtaPhi[i] = new TH2F(TString::Format("sumPt_%s_vsEtaPhi", tname[i].c_str()).Data(), - TString::Format("#LT #Sigma p_{t,%s} #GT;#eta_{%s};#varphi_{%s} (radian);#LT #Sigma p_{t,%s} #GT (GeV/c)", - tname[i].c_str(), tname[i].c_str(), tname[i].c_str(), tname[i].c_str()) - .Data(), - etabins, etalow, etaup, phibins, philow, phiup); + fhN1VsEtaPhi[i] = new TH2F(TString::Format("n1_%s_vsEtaPhi", tname[i].c_str()).Data(), + TString::Format("#LT n_{1} #GT;#eta_{%s};#varphi_{%s} (radian);#LT n_{1} #GT", tname[i].c_str(), tname[i].c_str()).Data(), + etabins, etalow, etaup, phibins, philow, phiup); + fhSum1PtVsEtaPhi[i] = new TH2F(TString::Format("sumPt_%s_vsEtaPhi", tname[i].c_str()).Data(), + TString::Format("#LT #Sigma p_{t,%s} #GT;#eta_{%s};#varphi_{%s} (radian);#LT #Sigma p_{t,%s} #GT (GeV/c)", + tname[i].c_str(), tname[i].c_str(), tname[i].c_str(), tname[i].c_str()) + .Data(), + etabins, etalow, etaup, phibins, philow, phiup); } else { TH1::SetDefaultSumw2(false); - fhN1_vsZEtaPhiPt[i] = new TH3F( + fhN1VsZEtaPhiPt[i] = new TH3F( TString::Format("n1_%s_vsZ_vsEtaPhi_vsPt", tname[i].c_str()).Data(), TString::Format("#LT n_{1} #GT;vtx_{z};#eta_{%s}#times#varphi_{%s};p_{t,%s} (GeV/c)", tname[i].c_str(), @@ -519,7 +602,59 @@ struct IdentifiedBfCorrelationsTask { ptbins, ptlow, ptup); - fhSum1Pt_vsZEtaPhiPt[i] = new TH3F( + + fhN1VsZEtaPhiPtPrimary[i] = new TH3F( + TString::Format("n1_%s_Primary_vsZ_vsEtaPhi_vsPt", tname[i].c_str()).Data(), + TString::Format("#LT n_{1} Primary #GT;vtx_{z};#eta_{%s}#times#varphi_{%s};p_{t,%s} (GeV/c)", + tname[i].c_str(), + tname[i].c_str(), + tname[i].c_str()) + .Data(), + zvtxbins, + zvtxlow, + zvtxup, + etabins * phibins, + 0.0, + static_cast(etabins * phibins), + ptbins, + ptlow, + ptup); + + fhN1VsZEtaPhiPtSecondary[i] = new TH3F( + TString::Format("n1_%s_Secondary_vsZ_vsEtaPhi_vsPt", tname[i].c_str()).Data(), + TString::Format("#LT n_{1} Secondary #GT;vtx_{z};#eta_{%s}#times#varphi_{%s};p_{t,%s} (GeV/c)", + tname[i].c_str(), + tname[i].c_str(), + tname[i].c_str()) + .Data(), + zvtxbins, + zvtxlow, + zvtxup, + etabins * phibins, + 0.0, + static_cast(etabins * phibins), + ptbins, + ptlow, + ptup); + + fhN1VsZEtaPhiPtPure[i] = new TH3F( + TString::Format("n1_%s_Pure_vsZ_vsEtaPhi_vsPt", tname[i].c_str()).Data(), + TString::Format("#LT n_{1} Pure #GT;vtx_{z};#eta_{%s}#times#varphi_{%s};p_{t,%s} (GeV/c)", + tname[i].c_str(), + tname[i].c_str(), + tname[i].c_str()) + .Data(), + zvtxbins, + zvtxlow, + zvtxup, + etabins * phibins, + 0.0, + static_cast(etabins * phibins), + ptbins, + ptlow, + ptup); + + fhSum1PtVsZEtaPhiPt[i] = new TH3F( TString::Format("sumPt1_%s_vsZ_vsEtaPhi_vsPt", tname[i].c_str()).Data(), TString::Format( "#LT #Sigma p_{t,%s}#GT;vtx_{z};#eta_{%s}#times#varphi_{%s};p_{t,%s} (GeV/c)", @@ -543,58 +678,88 @@ struct IdentifiedBfCorrelationsTask { /* the statistical uncertainties will be estimated by the subsamples method so let's get rid of the error tracking */ if constexpr (smallsingles) { - fhN1_vsEtaPhi[i]->SetBit(TH1::kIsNotW); - fhN1_vsEtaPhi[i]->Sumw2(false); - fhSum1Pt_vsEtaPhi[i]->SetBit(TH1::kIsNotW); - fhSum1Pt_vsEtaPhi[i]->Sumw2(false); + fhN1VsEtaPhi[i]->SetBit(TH1::kIsNotW); + fhN1VsEtaPhi[i]->Sumw2(false); + fhSum1PtVsEtaPhi[i]->SetBit(TH1::kIsNotW); + fhSum1PtVsEtaPhi[i]->Sumw2(false); } else { - fhN1_vsZEtaPhiPt[i]->SetBit(TH1::kIsNotW); - fhN1_vsZEtaPhiPt[i]->Sumw2(false); - fhSum1Pt_vsZEtaPhiPt[i]->SetBit(TH1::kIsNotW); - fhSum1Pt_vsZEtaPhiPt[i]->Sumw2(false); + fhN1VsZEtaPhiPt[i]->SetBit(TH1::kIsNotW); + fhN1VsZEtaPhiPt[i]->Sumw2(false); + fhN1VsZEtaPhiPtPrimary[i]->SetBit(TH1::kIsNotW); + fhN1VsZEtaPhiPtPrimary[i]->Sumw2(false); + fhN1VsZEtaPhiPtSecondary[i]->SetBit(TH1::kIsNotW); + fhN1VsZEtaPhiPtSecondary[i]->Sumw2(false); + fhN1VsZEtaPhiPtPure[i]->SetBit(TH1::kIsNotW); + fhN1VsZEtaPhiPtPure[i]->Sumw2(false); + fhSum1PtVsZEtaPhiPt[i]->SetBit(TH1::kIsNotW); + fhSum1PtVsZEtaPhiPt[i]->Sumw2(false); } - fhNuaNue_vsZEtaPhiPt[i] = nullptr; - fhPtAvg_vsEtaPhi[i] = nullptr; + fhNuaNueVsZEtaPhiPt[i] = nullptr; + fhPtAvgVsEtaPhi[i] = nullptr; - fOutputList->Add(fhN1_vsPt[i]); + fOutputList->Add(fhN1VsPt[i]); if constexpr (smallsingles) { - fOutputList->Add(fhN1_vsEtaPhi[i]); - fOutputList->Add(fhSum1Pt_vsEtaPhi[i]); + fOutputList->Add(fhN1VsEtaPhi[i]); + fOutputList->Add(fhSum1PtVsEtaPhi[i]); } else { - fOutputList->Add(fhN1_vsZEtaPhiPt[i]); - fOutputList->Add(fhSum1Pt_vsZEtaPhiPt[i]); + fOutputList->Add(fhN1VsZEtaPhiPt[i]); + fOutputList->Add(fhN1VsZEtaPhiPtPrimary[i]); + fOutputList->Add(fhN1VsZEtaPhiPtSecondary[i]); + fOutputList->Add(fhN1VsZEtaPhiPtPure[i]); + fOutputList->Add(fhSum1PtVsZEtaPhiPt[i]); } } + if (!smallsingles) { + TH1::SetDefaultSumw2(false); + fhN1VsZEtaPhiPt[nch] = new TH3F( + TString::Format("n1_%s_vsZ_vsEtaPhi_vsPt", "h"), + TString::Format("#LT n_{1} #GT;vtx_{z};#eta_{%s}#times#varphi_{%s};p_{t,%s} (GeV/c)", + "h", + "h", + "h") + .Data(), + zvtxbins, + zvtxlow, + zvtxup, + etabins * phibins, + 0.0, + static_cast(etabins * phibins), + ptbins, + ptlow, + ptup); + fOutputList->Add(fhN1VsZEtaPhiPt[nch]); + } + } else { for (uint i = 0; i < nch; ++i) { /* histograms for each track species */ - fhN1_vsEtaPhi[i] = new TH2F(TString::Format("n1_%s_vsEtaPhi", tname[i].c_str()).Data(), - TString::Format("#LT n_{1} #GT;#eta_{%s};#varphi_{%s} (radian);#LT n_{1} #GT", tname[i].c_str(), tname[i].c_str()).Data(), - etabins, etalow, etaup, phibins, philow, phiup); - fhSum1Pt_vsEtaPhi[i] = new TH2F(TString::Format("sumPt_%s_vsEtaPhi", tname[i].c_str()).Data(), - TString::Format("#LT #Sigma p_{t,%s} #GT;#eta_{%s};#varphi_{%s} (radian);#LT #Sigma p_{t,%s} #GT (GeV/c)", - tname[i].c_str(), tname[i].c_str(), tname[i].c_str(), tname[i].c_str()) - .Data(), - etabins, etalow, etaup, phibins, philow, phiup); - fhN1_vsC[i] = new TProfile(TString::Format("n1_%s_vsM", tname[i].c_str()).Data(), - TString::Format("#LT n_{1} #GT (weighted);Centrality/Multiplicity (%%);#LT n_{1} #GT").Data(), - 100, 0.0, 100.0); - fhSum1Pt_vsC[i] = new TProfile(TString::Format("sumPt_%s_vsM", tname[i].c_str()), - TString::Format("#LT #Sigma p_{t,%s} #GT (weighted);Centrality/Multiplicity (%%);#LT #Sigma p_{t,%s} #GT (GeV/c)", tname[i].c_str(), tname[i].c_str()).Data(), - 100, 0.0, 100.0); - fhN1nw_vsC[i] = new TProfile(TString::Format("n1Nw_%s_vsM", tname[i].c_str()).Data(), - TString::Format("#LT n_{1} #GT;Centrality/Multiplicity (%%);#LT n_{1} #GT").Data(), - 100, 0.0, 100.0); - fhSum1Ptnw_vsC[i] = new TProfile(TString::Format("sumPtNw_%s_vsM", tname[i].c_str()).Data(), - TString::Format("#LT #Sigma p_{t,%s} #GT;Centrality/Multiplicity (%%);#LT #Sigma p_{t,%s} #GT (GeV/c)", tname[i].c_str(), tname[i].c_str()).Data(), 100, 0.0, 100.0); - fhNuaNue_vsZEtaPhiPt[i] = nullptr; - fhPtAvg_vsEtaPhi[i] = nullptr; - fOutputList->Add(fhN1_vsEtaPhi[i]); - fOutputList->Add(fhSum1Pt_vsEtaPhi[i]); - fOutputList->Add(fhN1_vsC[i]); - fOutputList->Add(fhSum1Pt_vsC[i]); - fOutputList->Add(fhN1nw_vsC[i]); - fOutputList->Add(fhSum1Ptnw_vsC[i]); + fhN1VsEtaPhi[i] = new TH2F(TString::Format("n1_%s_vsEtaPhi", tname[i].c_str()).Data(), + TString::Format("#LT n_{1} #GT;#eta_{%s};#varphi_{%s} (radian);#LT n_{1} #GT", tname[i].c_str(), tname[i].c_str()).Data(), + etabins, etalow, etaup, phibins, philow, phiup); + fhSum1PtVsEtaPhi[i] = new TH2F(TString::Format("sumPt_%s_vsEtaPhi", tname[i].c_str()).Data(), + TString::Format("#LT #Sigma p_{t,%s} #GT;#eta_{%s};#varphi_{%s} (radian);#LT #Sigma p_{t,%s} #GT (GeV/c)", + tname[i].c_str(), tname[i].c_str(), tname[i].c_str(), tname[i].c_str()) + .Data(), + etabins, etalow, etaup, phibins, philow, phiup); + fhN1VsC[i] = new TProfile(TString::Format("n1_%s_vsM", tname[i].c_str()).Data(), + TString::Format("#LT n_{1} #GT (weighted);Centrality/Multiplicity (%%);#LT n_{1} #GT").Data(), + 100, 0.0, 100.0); + fhSum1PtVsC[i] = new TProfile(TString::Format("sumPt_%s_vsM", tname[i].c_str()), + TString::Format("#LT #Sigma p_{t,%s} #GT (weighted);Centrality/Multiplicity (%%);#LT #Sigma p_{t,%s} #GT (GeV/c)", tname[i].c_str(), tname[i].c_str()).Data(), + 100, 0.0, 100.0); + fhN1NWVsC[i] = new TProfile(TString::Format("n1Nw_%s_vsM", tname[i].c_str()).Data(), + TString::Format("#LT n_{1} #GT;Centrality/Multiplicity (%%);#LT n_{1} #GT").Data(), + 100, 0.0, 100.0); + fhSum1PtNWVsC[i] = new TProfile(TString::Format("sumPtNw_%s_vsM", tname[i].c_str()).Data(), + TString::Format("#LT #Sigma p_{t,%s} #GT;Centrality/Multiplicity (%%);#LT #Sigma p_{t,%s} #GT (GeV/c)", tname[i].c_str(), tname[i].c_str()).Data(), 100, 0.0, 100.0); + fhNuaNueVsZEtaPhiPt[i] = nullptr; + fhPtAvgVsEtaPhi[i] = nullptr; + fOutputList->Add(fhN1VsEtaPhi[i]); + fOutputList->Add(fhSum1PtVsEtaPhi[i]); + fOutputList->Add(fhN1VsC[i]); + fOutputList->Add(fhSum1PtVsC[i]); + fOutputList->Add(fhN1NWVsC[i]); + fOutputList->Add(fhSum1PtNWVsC[i]); } for (uint i = 0; i < nch; ++i) { for (uint j = 0; j < nch; ++j) { @@ -604,58 +769,58 @@ struct IdentifiedBfCorrelationsTask { TH1::SetDefaultSumw2(false); // const char* pname = chargePairsNames[i][j].c_str(); const char* pname = speciesPairNames[i][j].c_str(); - fhN2_vsDEtaDPhi[i][j] = new TH2F(TString::Format("n2_12_vsDEtaDPhi_%s", pname), TString::Format("#LT n_{2} #GT (%s);#Delta#eta;#Delta#varphi;#LT n_{2} #GT", pname), - deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); - fhN2cont_vsDEtaDPhi[i][j] = new TH2F(TString::Format("n2_12cont_vsDEtaDPhi_%s", pname), TString::Format("#LT n_{2} #GT (%s);#Delta#eta;#Delta#varphi;#LT n_{2} #GT", pname), - deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); - fhSum2PtPt_vsDEtaDPhi[i][j] = new TH2F(TString::Format("sumPtPt_12_vsDEtaDPhi_%s", pname), TString::Format("#LT #Sigma p_{t,1}p_{t,2} #GT (%s);#Delta#eta;#Delta#varphi;#LT #Sigma p_{t,1}p_{t,2} #GT (GeV^{2})", pname), - deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); - fhSum2DptDpt_vsDEtaDPhi[i][j] = new TH2F(TString::Format("sumDptDpt_12_vsDEtaDPhi_%s", pname), TString::Format("#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (%s);#Delta#eta;#Delta#varphi;#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (GeV^{2})", pname), - deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); - fhSupN1N1_vsDEtaDPhi[i][j] = new TH2F(TString::Format("suppn1n1_12_vsDEtaDPhi_%s", pname), TString::Format("Suppressed #LT n_{1} #GT#LT n_{1} #GT (%s);#Delta#eta;#Delta#varphi;#LT n_{1} #GT#LT n_{1} #GT", pname), + fhN2VsDEtaDPhi[i][j] = new TH2F(TString::Format("n2_12_vsDEtaDPhi_%s", pname), TString::Format("#LT n_{2} #GT (%s);#Delta#eta;#Delta#varphi;#LT n_{2} #GT", pname), + deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); + fhN2ContVsDEtaDPhi[i][j] = new TH2F(TString::Format("n2_12cont_vsDEtaDPhi_%s", pname), TString::Format("#LT n_{2} #GT (%s);#Delta#eta;#Delta#varphi;#LT n_{2} #GT", pname), + deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); + fhSum2PtPtVsDEtaDPhi[i][j] = new TH2F(TString::Format("sumPtPt_12_vsDEtaDPhi_%s", pname), TString::Format("#LT #Sigma p_{t,1}p_{t,2} #GT (%s);#Delta#eta;#Delta#varphi;#LT #Sigma p_{t,1}p_{t,2} #GT (GeV^{2})", pname), deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); - fhSupPt1Pt1_vsDEtaDPhi[i][j] = new TH2F(TString::Format("suppPtPt_12_vsDEtaDPhi_%s", pname), TString::Format("Suppressed #LT p_{t,1} #GT#LT p_{t,2} #GT (%s);#Delta#eta;#Delta#varphi;#LT p_{t,1} #GT#LT p_{t,2} #GT (GeV^{2})", pname), + fhSum2DptDptVsDEtaDPhi[i][j] = new TH2F(TString::Format("sumDptDpt_12_vsDEtaDPhi_%s", pname), TString::Format("#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (%s);#Delta#eta;#Delta#varphi;#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (GeV^{2})", pname), deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); + fhSupN1N1VsDEtaDPhi[i][j] = new TH2F(TString::Format("suppn1n1_12_vsDEtaDPhi_%s", pname), TString::Format("Suppressed #LT n_{1} #GT#LT n_{1} #GT (%s);#Delta#eta;#Delta#varphi;#LT n_{1} #GT#LT n_{1} #GT", pname), + deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); + fhSupPt1Pt1VsDEtaDPhi[i][j] = new TH2F(TString::Format("suppPtPt_12_vsDEtaDPhi_%s", pname), TString::Format("Suppressed #LT p_{t,1} #GT#LT p_{t,2} #GT (%s);#Delta#eta;#Delta#varphi;#LT p_{t,1} #GT#LT p_{t,2} #GT (GeV^{2})", pname), + deltaetabins, deltaetalow, deltaetaup, deltaphibins, deltaphilow, deltaphiup); /* we return it back to previuos state */ TH1::SetDefaultSumw2(defSumw2); - fhN2_vsPtPt[i][j] = new TH2F(TString::Format("n2_12_vsPtVsPt_%s", pname), TString::Format("#LT n_{2} #GT (%s);p_{t,1} (GeV/c);p_{t,2} (GeV/c);#LT n_{2} #GT", pname), - ptbins, ptlow, ptup, ptbins, ptlow, ptup); + fhN2VsPtPt[i][j] = new TH2F(TString::Format("n2_12_vsPtVsPt_%s", pname), TString::Format("#LT n_{2} #GT (%s);p_{t,1} (GeV/c);p_{t,2} (GeV/c);#LT n_{2} #GT", pname), + ptbins, ptlow, ptup, ptbins, ptlow, ptup); - fhN2_vsC[i][j] = new TProfile(TString::Format("n2_12_vsM_%s", pname), TString::Format("#LT n_{2} #GT (%s) (weighted);Centrality/Multiplicity (%%);#LT n_{2} #GT", pname), 100, 0.0, 100.0); - fhSum2PtPt_vsC[i][j] = new TProfile(TString::Format("sumPtPt_12_vsM_%s", pname), TString::Format("#LT #Sigma p_{t,1}p_{t,2} #GT (%s) (weighted);Centrality/Multiplicity (%%);#LT #Sigma p_{t,1}p_{t,2} #GT (GeV^{2})", pname), 100, 0.0, 100.0); - fhSum2DptDpt_vsC[i][j] = new TProfile(TString::Format("sumDptDpt_12_vsM_%s", pname), TString::Format("#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (%s) (weighted);Centrality/Multiplicity (%%);#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (GeV^{2})", pname), 100, 0.0, 100.0); - fhN2nw_vsC[i][j] = new TProfile(TString::Format("n2Nw_12_vsM_%s", pname), TString::Format("#LT n_{2} #GT (%s);Centrality/Multiplicity (%%);#LT n_{2} #GT", pname), 100, 0.0, 100.0); - fhSum2PtPtnw_vsC[i][j] = new TProfile(TString::Format("sumPtPtNw_12_vsM_%s", pname), TString::Format("#LT #Sigma p_{t,1}p_{t,2} #GT (%s);Centrality/Multiplicity (%%);#LT #Sigma p_{t,1}p_{t,2} #GT (GeV^{2})", pname), 100, 0.0, 100.0); - fhSum2DptDptnw_vsC[i][j] = new TProfile(TString::Format("sumDptDptNw_12_vsM_%s", pname), TString::Format("#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (%s);Centrality/Multiplicity (%%);#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (GeV^{2})", pname), 100, 0.0, 100.0); + fhN2VsC[i][j] = new TProfile(TString::Format("n2_12_vsM_%s", pname), TString::Format("#LT n_{2} #GT (%s) (weighted);Centrality/Multiplicity (%%);#LT n_{2} #GT", pname), 100, 0.0, 100.0); + fhSum2PtPtVsC[i][j] = new TProfile(TString::Format("sumPtPt_12_vsM_%s", pname), TString::Format("#LT #Sigma p_{t,1}p_{t,2} #GT (%s) (weighted);Centrality/Multiplicity (%%);#LT #Sigma p_{t,1}p_{t,2} #GT (GeV^{2})", pname), 100, 0.0, 100.0); + fhSum2DptDptVsC[i][j] = new TProfile(TString::Format("sumDptDpt_12_vsM_%s", pname), TString::Format("#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (%s) (weighted);Centrality/Multiplicity (%%);#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (GeV^{2})", pname), 100, 0.0, 100.0); + fhN2NWVsC[i][j] = new TProfile(TString::Format("n2Nw_12_vsM_%s", pname), TString::Format("#LT n_{2} #GT (%s);Centrality/Multiplicity (%%);#LT n_{2} #GT", pname), 100, 0.0, 100.0); + fhSum2PtPtNWVsC[i][j] = new TProfile(TString::Format("sumPtPtNw_12_vsM_%s", pname), TString::Format("#LT #Sigma p_{t,1}p_{t,2} #GT (%s);Centrality/Multiplicity (%%);#LT #Sigma p_{t,1}p_{t,2} #GT (GeV^{2})", pname), 100, 0.0, 100.0); + fhSum2DptDptNWVsC[i][j] = new TProfile(TString::Format("sumDptDptNw_12_vsM_%s", pname), TString::Format("#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (%s);Centrality/Multiplicity (%%);#LT #Sigma (p_{t,1} - #LT p_{t,1} #GT)(p_{t,2} - #LT p_{t,2} #GT) #GT (GeV^{2})", pname), 100, 0.0, 100.0); /* the statistical uncertainties will be estimated by the subsamples method so let's get rid of the error tracking */ - fhN2_vsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); - fhN2_vsDEtaDPhi[i][j]->Sumw2(false); - fhN2cont_vsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); - fhN2cont_vsDEtaDPhi[i][j]->Sumw2(false); - fhSum2PtPt_vsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); - fhSum2PtPt_vsDEtaDPhi[i][j]->Sumw2(false); - fhSum2DptDpt_vsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); - fhSum2DptDpt_vsDEtaDPhi[i][j]->Sumw2(false); - fhSupN1N1_vsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); - fhSupN1N1_vsDEtaDPhi[i][j]->Sumw2(false); - fhSupPt1Pt1_vsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); - fhSupPt1Pt1_vsDEtaDPhi[i][j]->Sumw2(false); - - fOutputList->Add(fhN2_vsDEtaDPhi[i][j]); - fOutputList->Add(fhN2cont_vsDEtaDPhi[i][j]); - fOutputList->Add(fhSum2PtPt_vsDEtaDPhi[i][j]); - fOutputList->Add(fhSum2DptDpt_vsDEtaDPhi[i][j]); - fOutputList->Add(fhSupN1N1_vsDEtaDPhi[i][j]); - fOutputList->Add(fhSupPt1Pt1_vsDEtaDPhi[i][j]); - fOutputList->Add(fhN2_vsPtPt[i][j]); - fOutputList->Add(fhN2_vsC[i][j]); - fOutputList->Add(fhSum2PtPt_vsC[i][j]); - fOutputList->Add(fhSum2DptDpt_vsC[i][j]); - fOutputList->Add(fhN2nw_vsC[i][j]); - fOutputList->Add(fhSum2PtPtnw_vsC[i][j]); - fOutputList->Add(fhSum2DptDptnw_vsC[i][j]); + fhN2VsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); + fhN2VsDEtaDPhi[i][j]->Sumw2(false); + fhN2ContVsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); + fhN2ContVsDEtaDPhi[i][j]->Sumw2(false); + fhSum2PtPtVsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); + fhSum2PtPtVsDEtaDPhi[i][j]->Sumw2(false); + fhSum2DptDptVsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); + fhSum2DptDptVsDEtaDPhi[i][j]->Sumw2(false); + fhSupN1N1VsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); + fhSupN1N1VsDEtaDPhi[i][j]->Sumw2(false); + fhSupPt1Pt1VsDEtaDPhi[i][j]->SetBit(TH1::kIsNotW); + fhSupPt1Pt1VsDEtaDPhi[i][j]->Sumw2(false); + + fOutputList->Add(fhN2VsDEtaDPhi[i][j]); + fOutputList->Add(fhN2ContVsDEtaDPhi[i][j]); + fOutputList->Add(fhSum2PtPtVsDEtaDPhi[i][j]); + fOutputList->Add(fhSum2DptDptVsDEtaDPhi[i][j]); + fOutputList->Add(fhSupN1N1VsDEtaDPhi[i][j]); + fOutputList->Add(fhSupPt1Pt1VsDEtaDPhi[i][j]); + fOutputList->Add(fhN2VsPtPt[i][j]); + fOutputList->Add(fhN2VsC[i][j]); + fOutputList->Add(fhSum2PtPtVsC[i][j]); + fOutputList->Add(fhSum2DptDptVsC[i][j]); + fOutputList->Add(fhN2NWVsC[i][j]); + fOutputList->Add(fhSum2PtPtNWVsC[i][j]); + fOutputList->Add(fhSum2DptDptNWVsC[i][j]); } } } @@ -673,7 +838,7 @@ struct IdentifiedBfCorrelationsTask { /* the data collecting engine instances */ DataCollectingEngine** dataCE; - DataCollectingEngine** dataCE_small; + DataCollectingEngine** dataCESmall; DataCollectingEngine** dataCEME; /* the input file structure from CCDB */ @@ -681,25 +846,25 @@ struct IdentifiedBfCorrelationsTask { bool loadfromccdb = false; /* pair conversion suppression defaults */ - static constexpr float cfgPairCutDefaults[1][5] = {{-1, -1, -1, -1, -1}}; - Configurable> cfgPairCut{"paircut", {cfgPairCutDefaults[0], 5, {"Photon", "K0", "Lambda", "Phi", "Rho"}}, "Conversion suppressions"}; + static constexpr float PairCutDefaults[1][5] = {{-1, -1, -1, -1, -1}}; + Configurable> cfgPairCut{"cfgPairCut", {PairCutDefaults[0], 5, {"Photon", "K0", "Lambda", "Phi", "Rho"}}, "Conversion suppressions"}; /* two tracks cut */ - Configurable cfgTwoTrackCut{"twotrackcut", -1, "Two-tracks cut: -1 = off; >0 otherwise distance value (suggested: 0.02"}; - Configurable cfgTwoTrackCutMinRadius{"twotrackcutminradius", 0.8f, "Two-tracks cut: radius in m from which two-tracks cut is applied"}; + Configurable cfgTwoTrackCut{"cfgTwoTrackCut", -1, "Two-tracks cut: -1 = off; >0 otherwise distance value (suggested: 0.02"}; + Configurable cfgTwoTrackCutMinRadius{"cfgTwoTrackCutMinRadius", 0.8f, "Two-tracks cut: radius in m from which two-tracks cut is applied"}; - Configurable cfgSmallDCE{"smalldce", true, "Use small data collecting engine for singles processing, true = yes. Default = true"}; - Configurable cfgProcessPairs{"processpairs", false, "Process pairs: false = no, just singles, true = yes, process pairs"}; - Configurable cfgProcessME{"processmixedevents", false, "Process mixed events: false = no, just same event, true = yes, also process mixed events"}; - Configurable cfgCentSpec{"centralities", "00-05,05-10,10-20,20-30,30-40,40-50,50-60,60-70,70-80", "Centrality/multiplicity ranges in min-max separated by commas"}; + Configurable cfgSmallDCE{"cfgSmallDCE", true, "Use small data collecting engine for singles processing, true = yes. Default = true"}; + Configurable cfgProcessPairs{"cfgProcessPairs", false, "Process pairs: false = no, just singles, true = yes, process pairs"}; + Configurable cfgProcessME{"cfgProcessME", false, "Process mixed events: false = no, just same event, true = yes, also process mixed events"}; + Configurable cfgCentSpec{"cfgCentSpec", "00-05,05-10,10-20,20-30,30-40,40-50,50-60,60-70,70-80", "Centrality/multiplicity ranges in min-max separated by commas"}; - Configurable cfgBinning{"binning", + Configurable cfgBinning{"cfgBinning", {28, -7.0, 7.0, 18, 0.2, 2.0, 16, -0.8, 0.8, 72, 0.5}, "triplets - nbins, min, max - for z_vtx, pT, eta and phi, binning plus bin fraction of phi origin shift"}; - Configurable cfgPtOrder{"ptorder", false, "enforce pT_1 < pT_2. Defalut: false"}; + Configurable cfgPtOrder{"cfgPtOrder", false, "enforce pT_1 < pT_2. Defalut: false"}; struct : ConfigurableGroup { - Configurable cfgCCDBUrl{"input_ccdburl", "http://ccdb-test.cern.ch:8080", "The CCDB url for the input file"}; - Configurable cfgCCDBPathName{"input_ccdbpath", "", "The CCDB path for the input file. Default \"\", i.e. don't load from CCDB"}; - Configurable cfgCCDBDate{"input_ccdbdate", "20220307", "The CCDB date for the input file"}; + Configurable cfgCCDBUrl{"cfgCCDBUrl", "http://ccdb-test.cern.ch:8080", "The CCDB url for the input file"}; + Configurable cfgCCDBPathName{"cfgCCDBPathName", "", "The CCDB path for the input file. Default \"\", i.e. don't load from CCDB"}; + Configurable cfgCCDBDate{"cfgCCDBDate", "20220307", "The CCDB date for the input file"}; } cfginputfile; OutputObj fOutput{"IdentifiedBfCorrelationsData", OutputObjHandlingPolicy::AnalysisObject, OutputObjSourceType::OutputObjSource}; @@ -774,7 +939,7 @@ struct IdentifiedBfCorrelationsTask { fCentMultMax = new float[ncmranges]; dataCE = new DataCollectingEngine*[ncmranges]; if (cfgSmallDCE) { - dataCE_small = new DataCollectingEngine*[ncmranges]; + dataCESmall = new DataCollectingEngine*[ncmranges]; } else { dataCE = new DataCollectingEngine*[ncmranges]; } @@ -811,7 +976,7 @@ struct IdentifiedBfCorrelationsTask { if (processpairs) { LOGF(fatal, "Processing pairs cannot be used with the small DCE, please configure properly!!"); } - dataCE_small[i] = builSmallDCEInstance(tokens->At(i)->GetName()); + dataCESmall[i] = builSmallDCEInstance(tokens->At(i)->GetName()); } else { dataCE[i] = buildCEInstance(tokens->At(i)->GetName()); } @@ -926,7 +1091,7 @@ struct IdentifiedBfCorrelationsTask { .Data())); } if (cfgSmallDCE.value) { - dataCE_small[ixDCE]->storePtAverages(ptavgs); + dataCESmall[ixDCE]->storePtAverages(ptavgs); } else { dataCE[ixDCE]->storePtAverages(ptavgs); } @@ -941,7 +1106,7 @@ struct IdentifiedBfCorrelationsTask { .Data())); } if (cfgSmallDCE.value) { - dataCE_small[ixDCE]->storeTrackCorrections(corrs); + dataCESmall[ixDCE]->storeTrackCorrections(corrs); } else { dataCE[ixDCE]->storeTrackCorrections(corrs); } @@ -956,7 +1121,7 @@ struct IdentifiedBfCorrelationsTask { .Data())); } if (cfgSmallDCE.value) { - dataCE_small[ixDCE]->storePtAverages(ptavgs); + dataCESmall[ixDCE]->storePtAverages(ptavgs); } else { dataCE[ixDCE]->storePtAverages(ptavgs); } @@ -980,7 +1145,7 @@ struct IdentifiedBfCorrelationsTask { bfield = (fUseConversionCuts || fUseTwoTrackCut) ? getMagneticField(timestamp) : 0; } if (cfgSmallDCE.value) { - dataCE_small[ixDCE]->processCollision(tracks, tracks, collision.posZ(), collision.centmult(), bfield); + dataCESmall[ixDCE]->processCollision(tracks, tracks, collision.posZ(), collision.centmult(), bfield); } else { dataCE[ixDCE]->processCollision(tracks, tracks, collision.posZ(), collision.centmult(), bfield); } @@ -1063,20 +1228,20 @@ struct IdentifiedBfCorrelationsTask { Filter onlyacceptedcollisions = (aod::identifiedbffilter::collisionaccepted == uint8_t(true)); Filter onlyacceptedtracks = (aod::identifiedbffilter::trackacceptedid >= int8_t(0)); - void processRecLevel(soa::Filtered::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered& tracks) + void processRecLevel(soa::Filtered::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered const& tracks) { processSame(collision, tracks, collision.bc_as().timestamp()); } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, processRecLevel, "Process reco level correlations", false); + PROCESS_SWITCH(IdentifiedbfTask, processRecLevel, "Process reco level correlations", false); - void processRecLevelCheck(aod::Collisions const& collisions, aod::Tracks& tracks) + void processRecLevelCheck(aod::Collisions const& collisions, aod::Tracks const& tracks) { int nAssignedTracks = 0; int nNotAssignedTracks = 0; int64_t firstNotAssignedIndex = -1; int64_t lastNotAssignedIndex = -1; - for (auto track : tracks) { + for (const auto& track : tracks) { if (track.has_collision()) { nAssignedTracks++; } else { @@ -1094,16 +1259,16 @@ struct IdentifiedBfCorrelationsTask { LOGF(info, " First not assigned track index %d", firstNotAssignedIndex); LOGF(info, " Last not assigned track index %d", lastNotAssignedIndex); } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, processRecLevelCheck, "Process reco level checks", true); + PROCESS_SWITCH(IdentifiedbfTask, processRecLevelCheck, "Process reco level checks", true); - void processGenLevelCheck(aod::McCollisions const& mccollisions, aod::McParticles& particles) + void processGenLevelCheck(aod::McCollisions const& mccollisions, aod::McParticles const& particles) { int nAssignedParticles = 0; int nNotAssignedParticles = 0; int64_t firstNotAssignedIndex = -1; int64_t lastNotAssignedIndex = -1; - for (auto particle : particles) { + for (const auto& particle : particles) { if (particle.has_mcCollision()) { nAssignedParticles++; } else { @@ -1121,36 +1286,46 @@ struct IdentifiedBfCorrelationsTask { LOGF(info, " First not assigned track index %d", firstNotAssignedIndex); LOGF(info, " Last not assigned track index %d", lastNotAssignedIndex); } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, processGenLevelCheck, "Process generator level checks", true); + PROCESS_SWITCH(IdentifiedbfTask, processGenLevelCheck, "Process generator level checks", true); void processRecLevelNotStored( soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, - soa::Filtered>& tracks) + soa::Filtered> const& tracks) { processSame(collision, tracks, collision.bc_as().timestamp()); } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, - processRecLevelNotStored, + PROCESS_SWITCH(IdentifiedbfTask, processRecLevelNotStored, "Process reco level correlations for not stored derived data", true); + void processDetLevelNotStored( + soa::Filtered>::iterator const& collision, + aod::BCsWithTimestamps const&, + soa::Filtered> const& tracks, + aod::McParticles const&) + { + processSame(collision, tracks, collision.bc_as().timestamp()); + } + PROCESS_SWITCH(IdentifiedbfTask, processDetLevelNotStored, + "Process detecotr level correlations for not stored derived data", + true); + void processGenLevel( soa::Filtered::iterator const& collision, - soa::Filtered>& tracks) + soa::Filtered> const& tracks) { processSame(collision, tracks); } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, processGenLevel, "Process generator level correlations", false); + PROCESS_SWITCH(IdentifiedbfTask, processGenLevel, "Process generator level correlations", false); void processGenLevelNotStored( soa::Filtered>::iterator const& collision, - soa::Filtered>& particles) + soa::Filtered> const& particles) { processSame(collision, particles); } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, - processGenLevelNotStored, + PROCESS_SWITCH(IdentifiedbfTask, processGenLevelNotStored, "Process generator level correlations for not stored derived data", false); @@ -1161,15 +1336,15 @@ struct IdentifiedBfCorrelationsTask { using BinningZVtxMultRec = ColumnBinningPolicy; BinningZVtxMultRec bindingOnVtxAndMultRec{{vtxBinsEdges, multBinsEdges}, true}; // true is for 'ignore overflows' (true by default) - void processRecLevelMixed(soa::Filtered& collisions, aod::BCsWithTimestamps const&, soa::Filtered& tracks) + void processRecLevelMixed(soa::Filtered const& collisions, aod::BCsWithTimestamps const&, soa::Filtered const& tracks) { auto tracksTuple = std::make_tuple(tracks); SameKindPair, soa::Filtered, BinningZVtxMultRec> pairreco{bindingOnVtxAndMultRec, 5, -1, collisions, tracksTuple, &cache}; // indicates that 5 events should be mixed and under/overflow (-1) to be ignored LOGF(IDENTIFIEDBFLOGCOLLISIONS, "Received %d collisions", collisions.size()); int logcomb = 0; - for (auto& [collision1, tracks1, collision2, tracks2] : pairreco) { - if (logcomb < 10) { + for (const auto& [collision1, tracks1, collision2, tracks2] : pairreco) { + if (logcomb < correlationstask::maxLogComb) { LOGF(IDENTIFIEDBFLOGCOLLISIONS, "Received collision pair: %ld (%f, %f): %s, %ld (%f, %f): %s", collision1.globalIndex(), collision1.posZ(), collision1.centmult(), collision1.collisionaccepted() ? "accepted" : "not accepted", collision2.globalIndex(), collision2.posZ(), collision2.centmult(), collision2.collisionaccepted() ? "accepted" : "not accepted"); @@ -1183,12 +1358,12 @@ struct IdentifiedBfCorrelationsTask { processMixed(collision1, tracks1, tracks2, collision1.bc_as().timestamp()); } } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, processRecLevelMixed, "Process reco level mixed events correlations", false); + PROCESS_SWITCH(IdentifiedbfTask, processRecLevelMixed, "Process reco level mixed events correlations", false); void processRecLevelMixedNotStored( - soa::Filtered>& collisions, + soa::Filtered> const& collisions, aod::BCsWithTimestamps const&, - soa::Filtered>& tracks) + soa::Filtered> const& tracks) { auto tracksTuple = std::make_tuple(tracks); SameKindPair>, @@ -1203,8 +1378,8 @@ struct IdentifiedBfCorrelationsTask { LOGF(IDENTIFIEDBFLOGCOLLISIONS, "Received %d collisions", collisions.size()); int logcomb = 0; - for (auto& [collision1, tracks1, collision2, tracks2] : pairreco) { - if (logcomb < 10) { + for (const auto& [collision1, tracks1, collision2, tracks2] : pairreco) { + if (logcomb < correlationstask::maxLogComb) { LOGF(IDENTIFIEDBFLOGCOLLISIONS, "Received collision pair: %ld (%f, %f): %s, %ld (%f, %f): %s", collision1.globalIndex(), @@ -1235,23 +1410,22 @@ struct IdentifiedBfCorrelationsTask { collision1.bc_as().timestamp()); } } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, - processRecLevelMixedNotStored, + PROCESS_SWITCH(IdentifiedbfTask, processRecLevelMixedNotStored, "Process reco level mixed events correlations for not stored derived data", false); using BinningZVtxMultGen = ColumnBinningPolicy; BinningZVtxMultGen bindingOnVtxAndMultGen{{vtxBinsEdges, multBinsEdges}, true}; // true is for 'ignore overflows' (true by default) - void processGenLevelMixed(soa::Filtered& collisions, soa::Filtered& tracks) + void processGenLevelMixed(soa::Filtered const& collisions, soa::Filtered const& tracks) { auto tracksTuple = std::make_tuple(tracks); SameKindPair, soa::Filtered, BinningZVtxMultGen> pairgen{bindingOnVtxAndMultGen, 5, -1, collisions, tracksTuple, &cache}; // indicates that 5 events should be mixed and under/overflow (-1) to be ignored LOGF(IDENTIFIEDBFLOGCOLLISIONS, "Received %d generated collisions", collisions.size()); int logcomb = 0; - for (auto& [collision1, tracks1, collision2, tracks2] : pairgen) { - if (logcomb < 10) { + for (const auto& [collision1, tracks1, collision2, tracks2] : pairgen) { + if (logcomb < correlationstask::maxLogComb) { LOGF(IDENTIFIEDBFLOGCOLLISIONS, "Received generated collision pair: %ld (%f, %f): %s, %ld (%f, %f): %s", collision1.globalIndex(), collision1.posZ(), collision1.centmult(), collision1.collisionaccepted() ? "accepted" : "not accepted", collision2.globalIndex(), collision2.posZ(), collision2.centmult(), collision2.collisionaccepted() ? "accepted" : "not accepted"); @@ -1264,11 +1438,11 @@ struct IdentifiedBfCorrelationsTask { processMixed(collision1, tracks1, tracks2); } } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, processGenLevelMixed, "Process generator level mixed events correlations", false); + PROCESS_SWITCH(IdentifiedbfTask, processGenLevelMixed, "Process generator level mixed events correlations", false); void processGenLevelMixedNotStored( - soa::Filtered>& collisions, - soa::Filtered>& tracks) + soa::Filtered> const& collisions, + soa::Filtered> const& tracks) { auto tracksTuple = std::make_tuple(tracks); SameKindPair>, @@ -1283,8 +1457,8 @@ struct IdentifiedBfCorrelationsTask { LOGF(IDENTIFIEDBFLOGCOLLISIONS, "Received %d generated collisions", collisions.size()); int logcomb = 0; - for (auto& [collision1, tracks1, collision2, tracks2] : pairgen) { - if (logcomb < 10) { + for (const auto& [collision1, tracks1, collision2, tracks2] : pairgen) { + if (logcomb < correlationstask::maxLogComb) { LOGF(IDENTIFIEDBFLOGCOLLISIONS, "Received generated collision pair: %ld (%f, %f): %s, %ld (%f, %f): %s", collision1.globalIndex(), @@ -1311,8 +1485,7 @@ struct IdentifiedBfCorrelationsTask { processMixed(collision1, tracks1, tracks2); } } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, - processGenLevelMixedNotStored, + PROCESS_SWITCH(IdentifiedbfTask, processGenLevelMixedNotStored, "Process generator level mixed events correlations for not stored derived data", false); @@ -1322,13 +1495,13 @@ struct IdentifiedBfCorrelationsTask { LOGF(IDENTIFIEDBFLOGCOLLISIONS, "Got %d new collisions", colls.size()); fOutput->Clear(); } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, processCleaner, "Cleaner process for not used output", false); + PROCESS_SWITCH(IdentifiedbfTask, processCleaner, "Cleaner process for not used output", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow{ - adaptAnalysisTask(cfgc, TaskName{"IdentifiedBfCorrelationsTaskRec"}, SetDefaultProcesses{{{"processRecLevel", true}, {"processRecLevelMixed", false}, {"processCleaner", false}}}), - adaptAnalysisTask(cfgc, TaskName{"IdentifiedBfCorrelationsTaskGen"}, SetDefaultProcesses{{{"processGenLevel", false}, {"processGenLevelMixed", false}, {"processCleaner", true}}})}; + adaptAnalysisTask(cfgc, TaskName{"IdentifiedbfTaskRec"}, SetDefaultProcesses{{{"processRecLevel", true}, {"processRecLevelMixed", false}, {"processCleaner", false}}}), // o2-linter: disable=name/o2-task (Task is adapted multiple times) + adaptAnalysisTask(cfgc, TaskName{"IdentifiedbfTaskGen"}, SetDefaultProcesses{{{"processGenLevel", false}, {"processGenLevelMixed", false}, {"processCleaner", true}}})}; // o2-linter: disable=name/o2-task (Task is adapted multiple times) return workflow; } diff --git a/PWGCF/TwoParticleCorrelations/Tasks/lambdaR2Correlation.cxx b/PWGCF/TwoParticleCorrelations/Tasks/lambdaR2Correlation.cxx new file mode 100644 index 00000000000..19bc4f66d37 --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/Tasks/lambdaR2Correlation.cxx @@ -0,0 +1,1649 @@ +// 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 lambdaR2Correlation.cxx +/// \brief R2 correlation of Lambda baryons. +/// \author Yash Patley + +#include +#include + +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/RecoDecay.h" +#include "CCDB/BasicCCDBManager.h" +#include "TPDGCode.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; +using namespace o2::constants::math; + +namespace o2::aod +{ +namespace lambdacollision +{ +DECLARE_SOA_COLUMN(Cent, cent, float); +} +DECLARE_SOA_TABLE(LambdaCollisions, "AOD", "LAMBDACOLS", o2::soa::Index<>, + lambdacollision::Cent, + aod::collision::PosX, + aod::collision::PosY, + aod::collision::PosZ); +using LambdaCollision = LambdaCollisions::iterator; + +namespace lambdamcgencollision +{ +} +DECLARE_SOA_TABLE(LambdaMcGenCollisions, "AOD", "LMCGENCOLS", o2::soa::Index<>, + lambdacollision::Cent, + o2::aod::mccollision::PosX, + o2::aod::mccollision::PosY, + o2::aod::mccollision::PosZ); +using LambdaMcGenCollision = LambdaMcGenCollisions::iterator; + +namespace lambdatrack +{ +DECLARE_SOA_INDEX_COLUMN(LambdaCollision, lambdaCollision); +DECLARE_SOA_COLUMN(Px, px, float); +DECLARE_SOA_COLUMN(Py, py, float); +DECLARE_SOA_COLUMN(Pz, pz, float); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Rap, rap, float); +DECLARE_SOA_COLUMN(Mass, mass, float); +DECLARE_SOA_COLUMN(PosTrackId, posTrackId, int64_t); +DECLARE_SOA_COLUMN(NegTrackId, negTrackId, int64_t); +DECLARE_SOA_COLUMN(V0Type, v0Type, int8_t); +DECLARE_SOA_COLUMN(CosPA, cosPA, float); +DECLARE_SOA_COLUMN(DcaDau, dcaDau, float); +DECLARE_SOA_COLUMN(CorrFact, corrFact, float); +} // namespace lambdatrack +DECLARE_SOA_TABLE(LambdaTracks, "AOD", "LAMBDATRACKS", o2::soa::Index<>, + lambdatrack::LambdaCollisionId, + lambdatrack::Px, + lambdatrack::Py, + lambdatrack::Pz, + lambdatrack::Pt, + lambdatrack::Eta, + lambdatrack::Phi, + lambdatrack::Rap, + lambdatrack::Mass, + lambdatrack::PosTrackId, + lambdatrack::NegTrackId, + lambdatrack::V0Type, + lambdatrack::CosPA, + lambdatrack::DcaDau, + lambdatrack::CorrFact); +using LambdaTrack = LambdaTracks::iterator; + +namespace lambdatrackext +{ +DECLARE_SOA_COLUMN(LambdaSharingDaughter, lambdaSharingDaughter, bool); +DECLARE_SOA_COLUMN(LambdaSharingDauIds, lambdaSharingDauIds, std::vector); +DECLARE_SOA_COLUMN(TrueLambdaFlag, trueLambdaFlag, bool); +} // namespace lambdatrackext +DECLARE_SOA_TABLE(LambdaTracksExt, "AOD", "LAMBDATRACKSEXT", + lambdatrackext::LambdaSharingDaughter, + lambdatrackext::LambdaSharingDauIds, + lambdatrackext::TrueLambdaFlag); + +using LambdaTrackExt = LambdaTracksExt::iterator; + +namespace lambdamcgentrack +{ +DECLARE_SOA_INDEX_COLUMN(LambdaMcGenCollision, lambdaMcGenCollision); +} +DECLARE_SOA_TABLE(LambdaMcGenTracks, "AOD", "LMCGENTRACKS", o2::soa::Index<>, + lambdamcgentrack::LambdaMcGenCollisionId, + o2::aod::mcparticle::Px, + o2::aod::mcparticle::Py, + o2::aod::mcparticle::Pz, + lambdatrack::Pt, + lambdatrack::Eta, + lambdatrack::Phi, + lambdatrack::Rap, + lambdatrack::Mass, + lambdatrack::PosTrackId, + lambdatrack::NegTrackId, + lambdatrack::V0Type, + lambdatrack::CosPA, + lambdatrack::DcaDau, + lambdatrack::CorrFact); +using LambdaMcGenTrack = LambdaMcGenTracks::iterator; + +} // namespace o2::aod + +enum CollisionLabels { + kTotColBeforeHasMcCollision = 1, + kTotCol, + kPassSelCol +}; + +enum TrackLabels { + kTracksBeforeHasMcParticle = 1, + kAllV0Tracks, + kV0KShortMassRej, + kNotLambdaNotAntiLambda, + kV0IsBothLambdaAntiLambda, + kNotLambdaAfterSel, + kV0IsLambdaOrAntiLambda, + kPassV0DauTrackSel, + kPassV0KinCuts, + kPassV0TopoSel, + kAllSelPassed, + kNotPrimaryLambda, + kNotSecondaryLambda, + kLambdaDauNotMcParticle, + kLambdaNotPrPiMinus, + kAntiLambdaNotAntiPrPiPlus, + kPassTrueLambdaSel, + kEffCorrPt, + kEffCorrPtRap, + kEffCorrPtRapPhi, + kNoEffCorr, + kGenTotAccLambda, + kGenLambdaNoDau, + kGenLambdaToPrPi +}; + +enum RunType { + kRun3 = 0, + kRun2 +}; + +enum ParticleType { + kLambda = 0, + kAntiLambda +}; + +enum ParticlePairType { + kLambdaAntiLambda = 0, + kLambdaLambda, + kAntiLambdaAntiLambda +}; + +enum ShareDauLambda { + kUniqueLambda = 0, + kLambdaShareDau +}; + +enum RecGenType { + kRec = 0, + kGen +}; + +enum DMCType { + kData = 0, + kMC +}; + +enum CorrHistDim { + OneDimCorr = 1, + TwoDimCorr, + ThreeDimCorr +}; + +struct LambdaTableProducer { + + Produces lambdaCollisionTable; + Produces lambdaTrackTable; + Produces lambdaMCGenCollisionTable; + Produces lambdaMCGenTrackTable; + + // Collisions + Configurable cMinZVtx{"cMinZVtx", -10.0, "Min VtxZ cut"}; + Configurable cMaxZVtx{"cMaxZVtx", 10.0, "Max VtxZ cut"}; + Configurable cMinMult{"cMinMult", 0., "Minumum Multiplicity"}; + Configurable cMaxMult{"cMaxMult", 100.0, "Maximum Multiplicity"}; + Configurable cSel8Trig{"cSel8Trig", true, "Sel8 (T0A + T0C) Selection Run3"}; + Configurable cInt7Trig{"cInt7Trig", false, "kINT7 MB Trigger"}; + Configurable cSel7Trig{"cSel7Trig", false, "Sel7 (V0A + V0C) Selection Run2"}; + Configurable cTriggerTvxSel{"cTriggerTvxSel", false, "Trigger Time and Vertex Selection"}; + Configurable cTFBorder{"cTFBorder", false, "Timeframe Border Selection"}; + Configurable cNoItsROBorder{"cNoItsROBorder", false, "No ITSRO Border Cut"}; + Configurable cItsTpcVtx{"cItsTpcVtx", false, "ITS+TPC Vertex Selection"}; + Configurable cPileupReject{"cPileupReject", false, "Pileup rejection"}; + Configurable cZVtxTimeDiff{"cZVtxTimeDiff", false, "z-vtx time diff selection"}; + Configurable cIsGoodITSLayers{"cIsGoodITSLayers", false, "Good ITS Layers All"}; + + // Tracks + Configurable cTrackMinPt{"cTrackMinPt", 0.16, "p_{T} minimum"}; + Configurable cTrackMaxPt{"cTrackMaxPt", 999.0, "p_{T} minimum"}; + Configurable cTrackEtaCut{"cTrackEtaCut", 0.8, "Pseudorapidity cut"}; + Configurable cMinTpcCrossedRows{"cMinTpcCrossedRows", 80, "TPC Min Crossed Rows"}; + Configurable cMinTpcCROverCls{"cMinTpcCROverCls", 0.8, "Tpc Min Crossed Rows Over Findable Clusters"}; + Configurable cMaxTpcSharedClusters{"cMaxTpcSharedClusters", 0.4, "Tpc Max Shared Clusters"}; + Configurable cMaxChi2Tpc{"cMaxChi2Tpc", 4, "Max Chi2 Tpc"}; + Configurable cTpcNsigmaCut{"cTpcNsigmaCut", 5.0, "TPC NSigma Selection Cut"}; + + // V0s + Configurable cMinDcaProtonToPV{"cMinDcaProtonToPV", 0.02, "Minimum Proton DCAr to PV"}; + Configurable cMinDcaPionToPV{"cMinDcaPionToPV", 0.06, "Minimum Pion DCAr to PV"}; + Configurable cMinV0DcaDaughters{"cMinV0DcaDaughters", 0., "Minimum DCA between V0 daughters"}; + Configurable cMaxV0DcaDaughters{"cMaxV0DcaDaughters", 1., "Maximum DCA between V0 daughters"}; + Configurable cMinDcaV0ToPV{"cMinDcaV0ToPV", 0.0, "Minimum DCA V0 to PV"}; + Configurable cMaxDcaV0ToPV{"cMaxDcaV0ToPV", 999.0, "Maximum DCA V0 to PV"}; + Configurable cMinV0TransRadius{"cMinV0TransRadius", 0.5, "Minimum V0 radius from PV"}; + Configurable cMaxV0TransRadius{"cMaxV0TransRadius", 999.0, "Maximum V0 radius from PV"}; + Configurable cMinV0CTau{"cMinV0CTau", 0.0, "Minimum ctau"}; + Configurable cMaxV0CTau{"cMaxV0CTau", 30.0, "Maximum ctau"}; + Configurable cMinV0CosPA{"cMinV0CosPA", 0.995, "Minimum V0 CosPA to PV"}; + Configurable cKshortRejMassWindow{"cKshortRejMassWindow", 0.01, "Reject K0Short Candidates"}; + Configurable cKshortRejFlag{"cKshortRejFlag", true, "K0short Mass Rej Flag"}; + Configurable cLambdaMassWindow{"cLambdaMassWindow", 0.005, "Lambda Mass Window"}; + + // V0s kinmatic acceptance + Configurable cMinV0Mass{"cMinV0Mass", 1.10, "V0 Mass Min"}; + Configurable cMaxV0Mass{"cMaxV0Mass", 1.12, "V0 Mass Min"}; + Configurable cMinV0Pt{"cMinV0Pt", 0.8, "Minimum V0 pT"}; + Configurable cMaxV0Pt{"cMaxV0Pt", 4.2, "Minimum V0 pT"}; + Configurable cMaxV0Rap{"cMaxV0Rap", 0.5, "|rap| cut"}; + Configurable cDoEtaAnalysis{"cDoEtaAnalysis", false, "Do Eta Analysis"}; + + // V0s MC + Configurable cHasMcFlag{"cHasMcFlag", true, "Has Mc Tag"}; + Configurable cSelectTrueLambda{"cSelectTrueLambda", true, "Select True Lambda"}; + Configurable cSelectPrimaryV0{"cSelectPrimaryV0", true, "Select Primary V0"}; + Configurable cRecPrimaryLambda{"cRecPrimaryLambda", true, "Primary Reconstructed Lambda"}; + Configurable cRecSecondaryLambda{"cRecSecondaryLambda", false, "Secondary Reconstructed Lambda"}; + Configurable cCheckRecoDauFlag{"cCheckRecoDauFlag", true, "Check for reco daughter PID"}; + Configurable cGenPrimaryLambda{"cGenPrimaryLambda", true, "Primary Generated Lambda"}; + Configurable cGenSecondaryLambda{"cGenSecondaryLambda", false, "Secondary Generated Lambda"}; + Configurable cGenDecayChannel{"cGenDecayChannel", true, "Gen Level Decay Channel Flag"}; + + // Mc Matching + Configurable cSelMcMatchValue{"cSelMcMatchValue", 0.4, "Mc Matching Percentage"}; + Configurable cDoEventMcMatching{"cDoEventMcMatching", true, "Do Event Mc Matching Flag"}; + Configurable cDoTrackMcMatching{"cDoTrackMcMatching", false, "Do Track Mc Matching Flag"}; + + // Efficiency Correction + Configurable cCorrectionFlag{"cCorrectionFlag", false, "Efficiency Correction Flag"}; + Configurable cCorrFactHist{"cCorrFactHist", 0, "Correction Factor Histogram"}; + Configurable cDoEtaCorr{"cDoEtaCorr", false, "Do Eta Corr"}; + + // CCDB + Configurable cUrlCCDB{"cUrlCCDB", "http://ccdb-test.cern.ch:8080", "url of ccdb"}; + Configurable cPathCCDB{"cPathCCDB", "Users/y/ypatley/lambda_corr_fact", "Path for ccdb-object"}; + + // Initialize CCDB Service + Service ccdb; + + // Histogram Registry. + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // initialize corr_factor objects + std::vector> vCorrFactStrings = {{"hEffVsPtLambda", "hEffVsPtAntiLambda"}, + {"hEffVsPtYLambda", "hEffVsPtYAntiLambda"}, + {"hEffVsPtEtaLambda", "hEffVsPtEtaAntiLambda"}, + {"hEffVsPtYPhiLambda", "hEffVsPtYPhiAntiLambda"}, + {"hEffVsPtEtaPhiLambda", "hEffVsPtEtaPhiAntiLambda"}}; + + // Initialize Global Variables + float cent = 0.; + + void init(InitContext const&) + { + // Set CCDB url + ccdb->setURL(cUrlCCDB.value); + ccdb->setCaching(true); + + // initialize axis specifications + const AxisSpec axisCols(5, 0.5, 5.5, ""); + const AxisSpec axisTrks(25, 0.5, 25.5, ""); + const AxisSpec axisCent(100, 0, 100, "FT0M (%)"); + const AxisSpec axisMult(10, 0, 10, "N_{#Lambda}"); + const AxisSpec axisVz(220, -11, 11, "V_{z} (cm)"); + const AxisSpec axisPID(8000, -4000, 4000, "PdgCode"); + + const AxisSpec axisV0Mass(140, 1.08, 1.15, "M_{p#pi} (GeV/#it{c}^{2})"); + const AxisSpec axisV0Pt(100., 0., 10., "p_{T} (GeV/#it{c})"); + const AxisSpec axisV0Rap(48, -1.2, 1.2, "y"); + const AxisSpec axisV0Eta(48, -1.2, 1.2, "#eta"); + const AxisSpec axisV0Phi(36, 0., TwoPI, "#phi (rad)"); + + const AxisSpec axisRadius(2000, 0, 200, "r(cm)"); + const AxisSpec axisCosPA(500, 0.995, 1.0, "cos(#theta_{PA})"); + const AxisSpec axisDcaV0PV(1000, 0., 10., "dca (cm)"); + const AxisSpec axisDcaProngPV(5000, -50., 50., "dca (cm)"); + const AxisSpec axisDcaDau(75, 0., 1.5, "Daug DCA (#sigma)"); + const AxisSpec axisCTau(2000, 0, 200, "c#tau (cm)"); + const AxisSpec axisGCTau(2000, 0, 200, "#gammac#tau (cm)"); + const AxisSpec axisAlpha(40, -1, 1, "#alpha"); + const AxisSpec axisQtarm(40, 0, 0.4, "q_{T}"); + + const AxisSpec axisTrackPt(40, 0, 4, "p_{T} (GeV/#it{c})"); + const AxisSpec axisTrackDCA(200, -1, 1, "dca_{XY} (cm)"); + const AxisSpec axisMomPID(80, 0, 4, "p (GeV/#it{c})"); + const AxisSpec axisNsigma(401, -10.025, 10.025, {"n#sigma"}); + const AxisSpec axisdEdx(360, 20, 200, "#frac{dE}{dx}"); + + // Create Histograms. + // Event histograms + histos.add("Events/h1f_collisions_info", "# of Collisions", kTH1F, {axisCols}); + histos.add("Events/h1f_collision_posZ", "V_{z}-distribution", kTH1F, {axisVz}); + + // QA + histos.add("Tracks/h1f_tracks_info", "# of tracks", kTH1F, {axisTrks}); + histos.add("Tracks/h2f_armpod_before_sel", "Armentros-Podolanski Plot", kTH2F, {axisAlpha, axisQtarm}); + histos.add("Tracks/h2f_armpod_after_sel", "Armentros-Podolanski Plot", kTH2F, {axisAlpha, axisQtarm}); + histos.add("Tracks/h1f_lambda_pt_vs_invm", "p_{T} vs M_{#Lambda}", kTH2F, {axisV0Mass, axisV0Pt}); + histos.add("Tracks/h1f_antilambda_pt_vs_invm", "p_{T} vs M_{#bar{#Lambda}}", kTH2F, {axisV0Mass, axisV0Pt}); + + // QA Lambda + histos.add("QA/Lambda/h2f_qt_vs_alpha", "Armentros-Podolanski Plot", kTH2F, {axisAlpha, axisQtarm}); + histos.add("QA/Lambda/h1f_dca_V0_daughters", "DCA between V0 daughters", kTH1F, {axisDcaDau}); + histos.add("QA/Lambda/h1f_dca_pos_to_PV", "DCA positive prong to PV", kTH1F, {axisDcaProngPV}); + histos.add("QA/Lambda/h1f_dca_neg_to_PV", "DCA negative prong to PV", kTH1F, {axisDcaProngPV}); + histos.add("QA/Lambda/h1f_dca_V0_to_PV", "DCA V0 to PV", kTH1F, {axisDcaV0PV}); + histos.add("QA/Lambda/h1f_V0_cospa", "cos(#theta_{PA})", kTH1F, {axisCosPA}); + histos.add("QA/Lambda/h1f_V0_radius", "V_{0} Decay Radius in XY plane", kTH1F, {axisRadius}); + histos.add("QA/Lambda/h1f_V0_ctau", "V_{0} c#tau", kTH1F, {axisCTau}); + histos.add("QA/Lambda/h1f_V0_gctau", "V_{0} #gammac#tau", kTH1F, {axisGCTau}); + + histos.add("QA/Lambda/h2f_V0_ptpt", "Rec vs Truth p_{T}", kTH2F, {axisV0Pt, axisV0Pt}); + histos.add("QA/Lambda/h2f_V0_etaeta", "Rec vs Truth #eta", kTH2F, {axisV0Eta, axisV0Eta}); + histos.add("QA/Lambda/h2f_V0_raprap", "Rec vs Truth y", kTH2F, {axisV0Rap, axisV0Rap}); + histos.add("QA/Lambda/h2f_V0_phiphi", "Rec vs Truth #phi", kTH2F, {axisV0Phi, axisV0Phi}); + + histos.add("QA/Lambda/h1f_pos_prong_pt", "Pos-Prong p_{T}", kTH1F, {axisTrackPt}); + histos.add("QA/Lambda/h1f_neg_prong_pt", "Neg-Prong p_{T}", kTH1F, {axisTrackPt}); + histos.add("QA/Lambda/h1f_pos_prong_eta", "Pos-Prong #eta-distribution", kTH1F, {axisV0Eta}); + histos.add("QA/Lambda/h1f_neg_prong_eta", "Neg-Prong #eta-distribution", kTH1F, {axisV0Eta}); + histos.add("QA/Lambda/h1f_pos_prong_phi", "Pos-Prong #phi-distribution", kTH1F, {axisV0Phi}); + histos.add("QA/Lambda/h1f_neg_prong_phi", "Neg-Prong #phi-distribution", kTH1F, {axisV0Phi}); + + histos.add("QA/Lambda/h2f_pos_prong_dcaXY_vs_pt", "DCA vs p_{T}", kTH2F, {axisTrackPt, axisTrackDCA}); + histos.add("QA/Lambda/h2f_neg_prong_dcaXY_vs_pt", "DCA vs p_{T}", kTH2F, {axisTrackPt, axisTrackDCA}); + histos.add("QA/Lambda/h2f_pos_prong_dEdx_vs_p", "TPC Signal Pos-Prong", kTH2F, {axisMomPID, axisdEdx}); + histos.add("QA/Lambda/h2f_neg_prong_dEdx_vs_p", "TPC Signal Neg-Prong", kTH2F, {axisMomPID, axisdEdx}); + histos.add("QA/Lambda/h2f_pos_prong_tpc_nsigma_pr_vs_p", "TPC n#sigma Pos Prong", kTH2F, {axisMomPID, axisNsigma}); + histos.add("QA/Lambda/h2f_neg_prong_tpc_nsigma_pr_vs_p", "TPC n#sigma Neg Prong", kTH2F, {axisMomPID, axisNsigma}); + histos.add("QA/Lambda/h2f_pos_prong_tpc_nsigma_pi_vs_p", "TPC n#sigma Pos Prong", kTH2F, {axisMomPID, axisNsigma}); + histos.add("QA/Lambda/h2f_neg_prong_tpc_nsigma_pi_vs_p", "TPC n#sigma Neg Prong", kTH2F, {axisMomPID, axisNsigma}); + + // Kinematic Histograms + histos.add("McRec/Lambda/hPt", "Transverse Momentum", kTH1F, {axisV0Pt}); + histos.add("McRec/Lambda/hEta", "Pseudorapidity", kTH1F, {axisV0Eta}); + histos.add("McRec/Lambda/hRap", "Rapidity", kTH1F, {axisV0Rap}); + histos.add("McRec/Lambda/hPhi", "Azimuthal Angle", kTH1F, {axisV0Phi}); + + // QA Anti-Lambda + histos.addClone("QA/Lambda/", "QA/AntiLambda/"); + histos.addClone("McRec/Lambda/", "McRec/AntiLambda/"); + + // MC Generated Histograms + if (doprocessMCRun3 || doprocessMCRun2) { + // McReco Histos + histos.add("Tracks/h2f_tracks_pid_before_sel", "PIDs", kTH2F, {axisPID, axisV0Pt}); + histos.add("Tracks/h2f_tracks_pid_after_sel", "PIDs", kTH2F, {axisPID, axisV0Pt}); + histos.add("Tracks/h2f_lambda_from_sigma", "PIDs", kTH2F, {axisPID, axisV0Pt}); + histos.add("Tracks/h2f_lambda_from_cascade", "PIDs", kTH2F, {axisPID, axisV0Pt}); + histos.add("Tracks/h2f_lambda_from_omega", "PIDs", kTH2F, {axisPID, axisV0Pt}); + + // McGen Histos + histos.add("McGen/h1f_collision_recgen", "# of Reco Collision Associated to One Mc Generator Collision", kTH1F, {axisMult}); + histos.add("McGen/h1f_collisions_info", "# of collisions", kTH1F, {axisCols}); + histos.add("McGen/h2f_collision_posZ", "V_{z}-distribution", kTH2F, {axisVz, axisVz}); + histos.add("McGen/h2f_collision_cent", "FT0M Centrality", kTH2F, {axisCent, axisCent}); + histos.add("McGen/h1f_lambda_daughter_PDG", "PDG Daughters", kTH1F, {axisPID}); + histos.add("McGen/h1f_antilambda_daughter_PDG", "PDG Daughters", kTH1F, {axisPID}); + + histos.addClone("McRec/", "McGen/"); + + histos.add("McGen/Lambda/Proton/hPt", "Proton p_{T}", kTH1F, {axisTrackPt}); + histos.add("McGen/Lambda/Proton/hEta", "Proton #eta", kTH1F, {axisV0Eta}); + histos.add("McGen/Lambda/Proton/hRap", "Proton y", kTH1F, {axisV0Rap}); + histos.add("McGen/Lambda/Proton/hPhi", "Proton #phi", kTH1F, {axisV0Phi}); + + histos.addClone("McGen/Lambda/Proton/", "McGen/Lambda/Pion/"); + histos.addClone("McGen/Lambda/Proton/", "McGen/AntiLambda/Proton/"); + histos.addClone("McGen/Lambda/Pion/", "McGen/AntiLambda/Pion/"); + + // set bin lables specific to MC + histos.get(HIST("Events/h1f_collisions_info"))->GetXaxis()->SetBinLabel(CollisionLabels::kTotColBeforeHasMcCollision, "kTotColBeforeHasMcCollision"); + histos.get(HIST("McGen/h1f_collisions_info"))->GetXaxis()->SetBinLabel(CollisionLabels::kTotCol, "kTotCol"); + histos.get(HIST("McGen/h1f_collisions_info"))->GetXaxis()->SetBinLabel(CollisionLabels::kPassSelCol, "kPassSelCol"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kTracksBeforeHasMcParticle, "kTracksBeforeHasMcParticle"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kNotPrimaryLambda, "kNotPrimaryLambda"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kNotSecondaryLambda, "kNotSecondaryLambda"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kLambdaDauNotMcParticle, "kLambdaDauNotMcParticle"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kLambdaNotPrPiMinus, "kLambdaNotPrPiMinus"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kAntiLambdaNotAntiPrPiPlus, "kAntiLambdaNotAntiPrPiPlus"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kPassTrueLambdaSel, "kPassTrueLambdaSel"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kGenTotAccLambda, "kGenTotAccLambda"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kGenLambdaNoDau, "kGenLambdaNoDau"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kGenLambdaToPrPi, "kGenLambdaToPrPi"); + } + + // set bin labels + histos.get(HIST("Events/h1f_collisions_info"))->GetXaxis()->SetBinLabel(CollisionLabels::kTotCol, "kTotCol"); + histos.get(HIST("Events/h1f_collisions_info"))->GetXaxis()->SetBinLabel(CollisionLabels::kPassSelCol, "kPassSelCol"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kAllV0Tracks, "kAllV0Tracks"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kV0KShortMassRej, "kV0KShortMassRej"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kNotLambdaNotAntiLambda, "kNotLambdaNotAntiLambda"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kV0IsBothLambdaAntiLambda, "kV0IsBothLambdaAntiLambda"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kNotLambdaAfterSel, "kNotLambdaAfterSel"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kV0IsLambdaOrAntiLambda, "kV0IsLambdaOrAntiLambda"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kPassV0DauTrackSel, "kPassV0DauTrackSel"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kPassV0KinCuts, "kPassV0KinCuts"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kPassV0TopoSel, "kPassV0TopoSel"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kAllSelPassed, "kAllSelPassed"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kEffCorrPt, "kEffCorrPt"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kEffCorrPtRap, "kEffCorrPtRap"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kEffCorrPtRapPhi, "kEffCorrPtRapPhi"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kNoEffCorr, "kNoEffCorr"); + } + + template + bool selCollision(C const& col) + { + // VtxZ Selection + if (col.posZ() <= cMinZVtx || col.posZ() >= cMaxZVtx) { + return false; + } + + if constexpr (run == kRun3) { // Run3 Min-Bias Trigger + cent = col.centFT0M(); + if (cSel8Trig && !col.sel8()) { + return false; + } + } else { // Run2 Min-Bias Trigger + cent = col.centRun2V0M(); + if (cInt7Trig && !col.alias_bit(kINT7)) { + return false; + } + if (cSel7Trig && !col.sel7()) { + return false; + } + } + + if (cent <= cMinMult || cent >= cMaxMult) { // select centrality + return false; + } + + if (cTriggerTvxSel && !col.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + + if (cTFBorder && !col.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } + + if (cNoItsROBorder && !col.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return false; + } + + if (cItsTpcVtx && !col.selection_bit(aod::evsel::kIsVertexITSTPC)) { + return false; + } + + if (cPileupReject && !col.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + + if (cZVtxTimeDiff && !col.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + + if (cIsGoodITSLayers && !col.selection_bit(aod::evsel::kIsGoodITSLayersAll)) { + return false; + } + + return true; + } + + // Kinematic Selection + bool kinCutSelection(float const& pt, float const& rap, float const& ptMin, float const& ptMax, float const& rapMax) + { + if (pt <= ptMin || pt >= ptMax || rap >= rapMax) { + return false; + } + + return true; + } + + // Track Selection + template + bool selTrack(T const& track) + { + if (!kinCutSelection(track.pt(), std::abs(track.eta()), cTrackMinPt, cTrackMaxPt, cTrackEtaCut)) { + return false; + } + + if (track.tpcNClsCrossedRows() <= cMinTpcCrossedRows) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < cMinTpcCROverCls) { + return false; + } + + if (track.tpcNClsShared() > cMaxTpcSharedClusters) { + return false; + } + + if (track.tpcChi2NCl() > cMaxChi2Tpc) { + return false; + } + + return true; + } + + // Daughter Track Selection + template + bool selDaughterTracks(V const& v0, T const&, ParticleType const& v0Type) + { + auto posTrack = v0.template posTrack_as(); + auto negTrack = v0.template negTrack_as(); + + if (!selTrack(posTrack) || !selTrack(negTrack)) { + return false; + } + + // Apply DCA Selection on Daughter Tracks Based on Lambda/AntiLambda daughters + float dcaProton = 0., dcaPion = 0.; + if (v0Type == kLambda) { + dcaProton = std::abs(v0.dcapostopv()); + dcaPion = std::abs(v0.dcanegtopv()); + } else if (v0Type == kAntiLambda) { + dcaPion = std::abs(v0.dcapostopv()); + dcaProton = std::abs(v0.dcanegtopv()); + } + + if (dcaProton < cMinDcaProtonToPV || dcaPion < cMinDcaPionToPV) { + return false; + } + + return true; + } + + template + bool topoCutSelection(C const& col, V const& v0, T const&) + { + // DCA + if (v0.dcaV0daughters() <= cMinV0DcaDaughters || v0.dcaV0daughters() >= cMaxV0DcaDaughters) { + return false; + } + + if (v0.dcav0topv() <= cMinDcaV0ToPV || v0.dcav0topv() >= cMaxDcaV0ToPV) { + return false; + } + + if (v0.v0radius() <= cMinV0TransRadius || v0.v0radius() >= cMaxV0TransRadius) { + return false; + } + + // ctau + float ctau = v0.distovertotmom(col.posX(), col.posY(), col.posZ()) * MassLambda0; + if (ctau <= cMinV0CTau || ctau >= cMaxV0CTau) { + return false; + } + + // cosine of pointing angle + if (v0.v0cosPA() <= cMinV0CosPA) { + return false; + } + + // all selection criterion passed (Return True) + return true; + } + + template + bool selLambdaDauWithTpcPid(T const& postrack, T const& negtrack) + { + bool returnFlag = false; + float tpcNSigmaPr = 0., tpcNSigmaPi = 0.; + + switch (part) { + // postrack = Proton, negtrack = Pion + case kLambda: + tpcNSigmaPr = postrack.tpcNSigmaPr(); + tpcNSigmaPi = negtrack.tpcNSigmaPi(); + break; + + // negtrack = Proton, postrack = Pion + case kAntiLambda: + tpcNSigmaPr = negtrack.tpcNSigmaPr(); + tpcNSigmaPi = postrack.tpcNSigmaPi(); + break; + } + + if (std::abs(tpcNSigmaPr) < cTpcNsigmaCut && std::abs(tpcNSigmaPi) < cTpcNsigmaCut) { + returnFlag = true; + } + + return returnFlag; + } + + template + bool selLambdaMassWindow(V const& v0, T const&, ParticleType& v0type) + { + // Kshort mass rejection hypothesis + if (cKshortRejFlag && (std::abs(v0.mK0Short() - MassK0Short) <= cKshortRejMassWindow)) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kV0KShortMassRej); + return false; + } + + // initialize daughter tracks + auto postrack = v0.template posTrack_as(); + auto negtrack = v0.template negTrack_as(); + + // initialize selection flags + bool lambdaFlag = false, antiLambdaFlag = false; + + // get v0 track as lambda + if ((v0.mLambda() > cMinV0Mass && v0.mLambda() < cMaxV0Mass) && (selLambdaDauWithTpcPid(postrack, negtrack))) { + lambdaFlag = true; + v0type = kLambda; + } + + // get v0 track as anti-lambda + if ((v0.mAntiLambda() > cMinV0Mass && v0.mAntiLambda() < cMaxV0Mass) && (selLambdaDauWithTpcPid(postrack, negtrack))) { + antiLambdaFlag = true; + v0type = kAntiLambda; + } + + if (!lambdaFlag && !antiLambdaFlag) { // neither Lambda nor Anti-Lambda + histos.fill(HIST("Tracks/h1f_tracks_info"), kNotLambdaNotAntiLambda); + return false; + } else if (lambdaFlag && antiLambdaFlag) { // check if the track is identified as lambda and anti-lambda both (DISCARD THIS TRACK) + histos.fill(HIST("Tracks/h1f_tracks_info"), kV0IsBothLambdaAntiLambda); + return false; + } + + if (lambdaFlag || antiLambdaFlag) { + return true; + } + + histos.fill(HIST("Tracks/h1f_tracks_info"), kNotLambdaAfterSel); + + return false; + } + + template + bool selV0Particle(C const& col, V const& v0, T const& tracks, ParticleType& v0Type) + { + // Apply Lambda Mass Hypothesis + if (!selLambdaMassWindow(v0, tracks, v0Type)) { + return false; + } + + histos.fill(HIST("Tracks/h1f_tracks_info"), kV0IsLambdaOrAntiLambda); + + // Apply Daughter Track Selection + if (!selDaughterTracks(v0, tracks, v0Type)) { + return false; + } + + histos.fill(HIST("Tracks/h1f_tracks_info"), kPassV0DauTrackSel); + + // Apply Kinematic Selection + float rap = 0.; + if (!cDoEtaAnalysis) { + rap = std::abs(v0.yLambda()); + } else { + rap = std::abs(v0.eta()); + } + + if (!kinCutSelection(v0.pt(), rap, cMinV0Pt, cMaxV0Pt, cMaxV0Rap)) { + return false; + } + + histos.fill(HIST("Tracks/h1f_tracks_info"), kPassV0KinCuts); + + // Apply Topological Selection + if (!topoCutSelection(col, v0, tracks)) { + return false; + } + + histos.fill(HIST("Tracks/h1f_tracks_info"), kPassV0TopoSel); + + // All Selection Criterion Passed + return true; + } + + template + bool selPrimaryV0(V const& v0) + { + auto mcpart = v0.template mcParticle_as(); + + // check for primary/secondary lambda + if (cRecPrimaryLambda && !mcpart.isPhysicalPrimary()) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kNotPrimaryLambda); + return false; + } else if (cRecSecondaryLambda && mcpart.isPhysicalPrimary()) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kNotSecondaryLambda); + return false; + } + + return true; + } + + template + bool selTrueMcRecLambda(V const& v0, T const&) + { + auto mcpart = v0.template mcParticle_as(); + + // check if Lambda/AntiLambda + if (std::abs(mcpart.pdgCode()) != kLambda0) { + return false; + } + + // Check for daughters + if (cCheckRecoDauFlag) { + auto postrack = v0.template posTrack_as(); + auto negtrack = v0.template negTrack_as(); + + // check if the daughters have corresponding mcparticle + if (!postrack.has_mcParticle() || !negtrack.has_mcParticle()) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kLambdaDauNotMcParticle); + return false; + } + + auto mcpostrack = postrack.template mcParticle_as(); + auto mcnegtrack = negtrack.template mcParticle_as(); + + if (mcpart.pdgCode() == kLambda0) { + if (mcpostrack.pdgCode() != kProton || mcnegtrack.pdgCode() != kPiMinus) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kLambdaNotPrPiMinus); + return false; + } + } else if (mcpart.pdgCode() == kLambda0Bar) { + if (mcpostrack.pdgCode() != kPiPlus || mcnegtrack.pdgCode() != kProtonBar) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kAntiLambdaNotAntiPrPiPlus); + return false; + } + } + } + + // get information about secondary lambdas + if (cRecSecondaryLambda) { + auto lambdaMothers = mcpart.template mothers_as(); + if (std::abs(lambdaMothers[0].pdgCode()) == kSigmaMinus || std::abs(lambdaMothers[0].pdgCode()) == kSigma0 || std::abs(lambdaMothers[0].pdgCode()) == kSigmaPlus) { + histos.fill(HIST("Tracks/h2f_lambda_from_sigma"), mcpart.pdgCode(), mcpart.pt()); + } else if (std::abs(lambdaMothers[0].pdgCode()) == kXiMinus || std::abs(lambdaMothers[0].pdgCode()) == kXi0) { + histos.fill(HIST("Tracks/h2f_lambda_from_cascade"), mcpart.pdgCode(), mcpart.pt()); + } else if (std::abs(lambdaMothers[0].pdgCode()) == kOmegaMinus) { + histos.fill(HIST("Tracks/h2f_lambda_from_omega"), mcpart.pdgCode(), mcpart.pt()); + } + } + + return true; + } + + template + bool getMcMatch(T const& vrec, T const& vgen) + { + float v = std::abs(1. - (vgen / vrec)); + + if (v >= cSelMcMatchValue) { + return false; + } + + return true; + } + + template + bool passMcMatching(V const& v0) + { + auto mcpart = v0.template mcParticle_as(); + + if (!getMcMatch(v0.pt(), mcpart.pt())) { + return false; + } + + if (!getMcMatch(v0.eta(), mcpart.eta())) { + return false; + } + + if (!getMcMatch(v0.yLambda(), mcpart.y())) { + return false; + } + + if (!getMcMatch(v0.phi(), mcpart.phi())) { + return false; + } + + return true; + } + + template + float getCorrectionFactors(V const& v0) + { + // Check for efficiency correction flag and Rec/Gen Data + if (!cCorrectionFlag) { + return 1.; + } + + // Get from CCDB + auto ccdbObj = ccdb->getForTimeStamp(cPathCCDB.value, -1); + + // Check CCDB Object + if (!ccdbObj) { + LOGF(warning, "CCDB OBJECT NOT FOUND"); + return 1.; + } + + // get ccdb object + TObject* obj = reinterpret_cast(ccdbObj->FindObject(Form("%s", vCorrFactStrings[cCorrFactHist][part].c_str()))); + TH1F* hist = reinterpret_cast(obj->Clone()); + float retVal = 0.; + float rap = (cDoEtaCorr) ? v0.eta() : v0.yLambda(); + + if (hist->GetDimension() == OneDimCorr) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kEffCorrPt); + retVal = hist->GetBinContent(hist->FindBin(v0.pt())); + } else if (hist->GetDimension() == TwoDimCorr) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kEffCorrPtRap); + retVal = hist->GetBinContent(hist->FindBin(v0.pt(), rap)); + } else if (hist->GetDimension() == ThreeDimCorr) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kEffCorrPtRapPhi); + retVal = hist->GetBinContent(hist->FindBin(v0.pt(), rap, v0.phi())); + } else { + histos.fill(HIST("Tracks/h1f_tracks_info"), kNoEffCorr); + LOGF(warning, "CCDB OBJECT IS NOT A HISTOGRAM !!!"); + retVal = 1.; + } + + delete hist; + return retVal; + } + + template + void fillMCMatchingHistos(V const& v0) + { + static constexpr std::string_view SubDir[] = {"QA/Lambda/", "QA/AntiLambda/"}; + auto mcpart = v0.template mcParticle_as(); + + histos.fill(HIST(SubDir[part]) + HIST("h2f_V0_ptpt"), v0.pt(), mcpart.pt()); + histos.fill(HIST(SubDir[part]) + HIST("h2f_V0_etaeta"), v0.eta(), mcpart.eta()); + histos.fill(HIST(SubDir[part]) + HIST("h2f_V0_raprap"), v0.yLambda(), mcpart.y()); + histos.fill(HIST(SubDir[part]) + HIST("h2f_V0_phiphi"), v0.phi(), mcpart.phi()); + } + + template + void fillLambdaQAHistos(C const& col, V const& v0, T const&) + { + static constexpr std::string_view SubDir[] = {"QA/Lambda/", "QA/AntiLambda/"}; + + // daugthers + auto postrack = v0.template posTrack_as(); + auto negtrack = v0.template negTrack_as(); + float mass = 0.; + + if constexpr (part == kLambda) { + mass = v0.mLambda(); + } else { + mass = v0.mAntiLambda(); + } + + // ctau + float e = RecoDecay::e(v0.px(), v0.py(), v0.pz(), mass); + float gamma = e / mass; + float ctau = v0.distovertotmom(col.posX(), col.posY(), col.posZ()) * MassLambda0; + float gctau = ctau * gamma; + + histos.fill(HIST(SubDir[part]) + HIST("h2f_qt_vs_alpha"), v0.alpha(), v0.qtarm()); + histos.fill(HIST(SubDir[part]) + HIST("h1f_dca_V0_daughters"), v0.dcaV0daughters()); + histos.fill(HIST(SubDir[part]) + HIST("h1f_dca_pos_to_PV"), v0.dcapostopv()); + histos.fill(HIST(SubDir[part]) + HIST("h1f_dca_neg_to_PV"), v0.dcanegtopv()); + histos.fill(HIST(SubDir[part]) + HIST("h1f_dca_V0_to_PV"), v0.dcav0topv()); + histos.fill(HIST(SubDir[part]) + HIST("h1f_V0_cospa"), v0.v0cosPA()); + histos.fill(HIST(SubDir[part]) + HIST("h1f_V0_radius"), v0.v0radius()); + histos.fill(HIST(SubDir[part]) + HIST("h1f_V0_ctau"), ctau); + histos.fill(HIST(SubDir[part]) + HIST("h1f_V0_gctau"), gctau); + + histos.fill(HIST(SubDir[part]) + HIST("h1f_pos_prong_pt"), postrack.pt()); + histos.fill(HIST(SubDir[part]) + HIST("h1f_pos_prong_eta"), postrack.eta()); + histos.fill(HIST(SubDir[part]) + HIST("h1f_pos_prong_phi"), postrack.phi()); + histos.fill(HIST(SubDir[part]) + HIST("h1f_neg_prong_pt"), negtrack.pt()); + histos.fill(HIST(SubDir[part]) + HIST("h1f_neg_prong_eta"), negtrack.eta()); + histos.fill(HIST(SubDir[part]) + HIST("h1f_neg_prong_phi"), negtrack.phi()); + + histos.fill(HIST(SubDir[part]) + HIST("h2f_pos_prong_dcaXY_vs_pt"), postrack.pt(), postrack.dcaXY()); + histos.fill(HIST(SubDir[part]) + HIST("h2f_neg_prong_dcaXY_vs_pt"), negtrack.pt(), negtrack.dcaXY()); + histos.fill(HIST(SubDir[part]) + HIST("h2f_pos_prong_dEdx_vs_p"), postrack.tpcInnerParam(), postrack.tpcSignal()); + histos.fill(HIST(SubDir[part]) + HIST("h2f_neg_prong_dEdx_vs_p"), negtrack.tpcInnerParam(), negtrack.tpcSignal()); + histos.fill(HIST(SubDir[part]) + HIST("h2f_pos_prong_tpc_nsigma_pr_vs_p"), postrack.tpcInnerParam(), postrack.tpcNSigmaPr()); + histos.fill(HIST(SubDir[part]) + HIST("h2f_neg_prong_tpc_nsigma_pr_vs_p"), negtrack.tpcInnerParam(), negtrack.tpcNSigmaPr()); + histos.fill(HIST(SubDir[part]) + HIST("h2f_pos_prong_tpc_nsigma_pi_vs_p"), postrack.tpcInnerParam(), postrack.tpcNSigmaPi()); + histos.fill(HIST(SubDir[part]) + HIST("h2f_neg_prong_tpc_nsigma_pi_vs_p"), negtrack.tpcInnerParam(), negtrack.tpcNSigmaPi()); + } + + // Fill Lambda Kinematic Histograms + template + void fillKinematicHists(float const& pt, float const& eta, float const& y, float const& phi) + { + static constexpr std::string_view SubDirRG[] = {"McRec/", "McGen/"}; + static constexpr std::string_view SubDirPart[] = {"Lambda/", "AntiLambda/"}; + + histos.fill(HIST(SubDirRG[rg]) + HIST(SubDirPart[part]) + HIST("hPt"), pt); + histos.fill(HIST(SubDirRG[rg]) + HIST(SubDirPart[part]) + HIST("hEta"), eta); + histos.fill(HIST(SubDirRG[rg]) + HIST(SubDirPart[part]) + HIST("hRap"), y); + histos.fill(HIST(SubDirRG[rg]) + HIST(SubDirPart[part]) + HIST("hPhi"), phi); + } + + // Reconstructed Level Tables + template + void fillLambdaRecoTables(C const& collision, V const& v0tracks, T const& tracks) + { + // Total Collisions + histos.fill(HIST("Events/h1f_collisions_info"), kTotCol); + + // Select Collision (Only for Data... McRec has been selected already !!!) + if constexpr (dmc == kData) { + if (!selCollision(collision)) { + return; + } + } + + histos.fill(HIST("Events/h1f_collisions_info"), kPassSelCol); + histos.fill(HIST("Events/h1f_collision_posZ"), collision.posZ()); + + // Fill Collision Table + lambdaCollisionTable(cent, collision.posX(), collision.posY(), collision.posZ()); + + // initialize v0track objects + ParticleType v0Type = kLambda; + float mass = 0., corr_fact = 1.; + + for (auto const& v0 : v0tracks) { + // check for corresponding MCGen Particle + if constexpr (dmc == kMC) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kTracksBeforeHasMcParticle); + if (!v0.has_mcParticle() || !v0.template posTrack_as().has_mcParticle() || !v0.template negTrack_as().has_mcParticle()) { + continue; + } + } + + histos.fill(HIST("Tracks/h1f_tracks_info"), kAllV0Tracks); + histos.fill(HIST("Tracks/h2f_armpod_before_sel"), v0.alpha(), v0.qtarm()); + + // Select V0 Particle as Lambda/AntiLambda + if (!selV0Particle(collision, v0, tracks, v0Type)) { + continue; + } + + histos.fill(HIST("Tracks/h1f_tracks_info"), kAllSelPassed); + + // we have v0 as lambda + // do MC analysis + if constexpr (dmc == kMC) { + histos.fill(HIST("Tracks/h2f_tracks_pid_before_sel"), v0.mcParticle().pdgCode(), v0.pt()); + if (cSelectPrimaryV0 && !selPrimaryV0(v0)) { // check for Primary V0 + continue; + } + if (cSelectTrueLambda && !selTrueMcRecLambda(v0, tracks)) { // check for true Lambda/Anti-Lambda + continue; + } + if (cDoTrackMcMatching && !passMcMatching(v0)) { // Do Mc Matching + continue; + } + // Fill MC Matching Histos (MC Matching Cuts to be implemented soon...) + if (v0Type == kLambda) { + fillMCMatchingHistos(v0); + } else { + fillMCMatchingHistos(v0); + } + histos.fill(HIST("Tracks/h1f_tracks_info"), kPassTrueLambdaSel); + histos.fill(HIST("Tracks/h2f_tracks_pid_after_sel"), v0.mcParticle().pdgCode(), v0.pt()); + } + + histos.fill(HIST("Tracks/h2f_armpod_after_sel"), v0.alpha(), v0.qtarm()); + + // get correction factors and mass + corr_fact = (v0Type == kLambda) ? getCorrectionFactors(v0) : getCorrectionFactors(v0); + mass = (v0Type == kLambda) ? v0.mLambda() : v0.mAntiLambda(); + + // fill lambda qa + if (v0Type == kLambda) { + histos.fill(HIST("Tracks/h1f_lambda_pt_vs_invm"), mass, v0.pt()); + fillLambdaQAHistos(collision, v0, tracks); + fillKinematicHists(v0.pt(), v0.eta(), v0.yLambda(), v0.phi()); + } else { + histos.fill(HIST("Tracks/h1f_antilambda_pt_vs_invm"), mass, v0.pt()); + fillLambdaQAHistos(collision, v0, tracks); + fillKinematicHists(v0.pt(), v0.eta(), v0.yLambda(), v0.phi()); + } + + // Fill Lambda/AntiLambda Table + lambdaTrackTable(lambdaCollisionTable.lastIndex(), v0.px(), v0.py(), v0.pz(), + v0.pt(), v0.eta(), v0.phi(), v0.yLambda(), mass, + v0.template posTrack_as().index(), v0.template negTrack_as().index(), + (int8_t)v0Type, v0.v0cosPA(), v0.dcaV0daughters(), corr_fact); + } + } + + // MC Generater Level Tables + template + void fillLambdaMcGenTables(C const& mcCollision, M const& mcParticles) + { + // Fill McGen Collision Table + lambdaMCGenCollisionTable(mcCollision.centFT0M(), mcCollision.posX(), mcCollision.posY(), mcCollision.posZ()); + + // initialize track objects + ParticleType v0Type = kLambda; + float rap = 0.; + + for (auto const& mcpart : mcParticles) { + // check for Lambda first + if (mcpart.pdgCode() == kLambda0) { + v0Type = kLambda; + } else if (mcpart.pdgCode() == kLambda0Bar) { + v0Type = kAntiLambda; + } else { + continue; + } + + // check for Primary Lambda/AntiLambda + if (cGenPrimaryLambda && !mcpart.isPhysicalPrimary()) { + continue; + } else if (cGenSecondaryLambda && mcpart.isPhysicalPrimary()) { + continue; + } + + // Decide Eta/Rap + if (!cDoEtaAnalysis) { + rap = mcpart.y(); + } else { + rap = mcpart.eta(); + } + + // Apply Kinematic Acceptance + if (!kinCutSelection(mcpart.pt(), std::abs(rap), cMinV0Pt, cMaxV0Pt, cMaxV0Rap)) { + continue; + } + + histos.fill(HIST("Tracks/h1f_tracks_info"), kGenTotAccLambda); + + // get daughter track info and check for decay channel flag + if (!mcpart.has_daughters()) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kGenLambdaNoDau); + continue; + } + auto dautracks = mcpart.template daughters_as(); + std::vector daughterPDGs, daughterIDs; + std::vector vDauPt, vDauEta, vDauRap, vDauPhi; + for (auto const& dautrack : dautracks) { + daughterPDGs.push_back(dautrack.pdgCode()); + daughterIDs.push_back(dautrack.globalIndex()); + vDauPt.push_back(dautrack.pt()); + vDauEta.push_back(dautrack.eta()); + vDauRap.push_back(dautrack.y()); + vDauPhi.push_back(dautrack.phi()); + } + if (cGenDecayChannel) { // check decay channel + if (v0Type == kLambda) { + if (daughterPDGs[0] != kProton || daughterPDGs[1] != kPiMinus) { + continue; + } + } else if (v0Type == kAntiLambda) { + if (daughterPDGs[0] != kProtonBar || daughterPDGs[1] != kPiPlus) { + continue; + } + } + } + + histos.fill(HIST("Tracks/h1f_tracks_info"), kGenLambdaToPrPi); + + if (v0Type == kLambda) { + histos.fill(HIST("McGen/h1f_lambda_daughter_PDG"), daughterPDGs[0]); + histos.fill(HIST("McGen/h1f_lambda_daughter_PDG"), daughterPDGs[1]); + histos.fill(HIST("McGen/h1f_lambda_daughter_PDG"), mcpart.pdgCode()); + histos.fill(HIST("McGen/Lambda/Proton/hPt"), vDauPt[0]); + histos.fill(HIST("McGen/Lambda/Proton/hEta"), vDauEta[0]); + histos.fill(HIST("McGen/Lambda/Proton/hRap"), vDauRap[0]); + histos.fill(HIST("McGen/Lambda/Proton/hPhi"), vDauPhi[0]); + histos.fill(HIST("McGen/Lambda/Pion/hPt"), vDauPt[1]); + histos.fill(HIST("McGen/Lambda/Pion/hEta"), vDauEta[1]); + histos.fill(HIST("McGen/Lambda/Pion/hRap"), vDauRap[1]); + histos.fill(HIST("McGen/Lambda/Pion/hPhi"), vDauPhi[1]); + fillKinematicHists(mcpart.pt(), mcpart.eta(), mcpart.y(), mcpart.phi()); + } else { + histos.fill(HIST("McGen/h1f_antilambda_daughter_PDG"), daughterPDGs[0]); + histos.fill(HIST("McGen/h1f_antilambda_daughter_PDG"), daughterPDGs[1]); + histos.fill(HIST("McGen/h1f_antilambda_daughter_PDG"), mcpart.pdgCode()); + histos.fill(HIST("McGen/AntiLambda/Pion/hPt"), vDauPt[0]); + histos.fill(HIST("McGen/AntiLambda/Pion/hEta"), vDauEta[0]); + histos.fill(HIST("McGen/AntiLambda/Pion/hRap"), vDauRap[0]); + histos.fill(HIST("McGen/AntiLambda/Pion/hPhi"), vDauPhi[0]); + histos.fill(HIST("McGen/AntiLambda/Proton/hPt"), vDauPt[1]); + histos.fill(HIST("McGen/AntiLambda/Proton/hEta"), vDauEta[1]); + histos.fill(HIST("McGen/AntiLambda/Proton/hRap"), vDauRap[1]); + histos.fill(HIST("McGen/AntiLambda/Proton/hPhi"), vDauPhi[1]); + fillKinematicHists(mcpart.pt(), mcpart.eta(), mcpart.y(), mcpart.phi()); + } + + // Fill Lambda McGen Table + lambdaMCGenTrackTable(lambdaMCGenCollisionTable.lastIndex(), mcpart.px(), mcpart.py(), mcpart.pz(), + mcpart.pt(), mcpart.eta(), mcpart.phi(), mcpart.y(), RecoDecay::m(mcpart.p(), mcpart.e()), + daughterIDs[0], daughterIDs[1], (int8_t)v0Type, -999., -999., 1.); + } + } + + template + void analyzeMcRecoGen(M const& mcCollision, C const& collisions, V const& V0s, T const& tracks, P const& mcParticles) + { + // Number of Rec Collisions Associated to the McGen Collision + int nRecCols = collisions.size(); + if (nRecCols != 0) { + histos.fill(HIST("McGen/h1f_collision_recgen"), nRecCols); + } + // Do not analyze if more than one reco collision is accociated to one mc gen collision + if (nRecCols != 1) { + return; + } + histos.fill(HIST("McGen/h1f_collisions_info"), kTotCol); + // Check the reco collision + if (!collisions.begin().has_mcCollision() || !selCollision(collisions.begin()) || collisions.begin().mcCollisionId() != mcCollision.globalIndex()) { + return; + } + // MC Matching + if (cDoEventMcMatching) { + // Vz Matching + if (!getMcMatch(collisions.begin().posZ(), mcCollision.posZ())) { + return; + } + } + histos.fill(HIST("McGen/h1f_collisions_info"), kPassSelCol); + histos.fill(HIST("McGen/h2f_collision_posZ"), mcCollision.posZ(), collisions.begin().posZ()); + histos.fill(HIST("McGen/h2f_collision_cent"), mcCollision.centFT0M(), cent); + auto v0Tracks = V0s.sliceBy(perCollision, collisions.begin().globalIndex()); + fillLambdaRecoTables(collisions.begin(), v0Tracks, tracks); + fillLambdaMcGenTables(mcCollision, mcParticles); + } + + SliceCache cache; + Preslice> perCollision = aod::track::collisionId; + + using CollisionsRun3 = soa::Join; + using CollisionsRun2 = soa::Join; + using Tracks = soa::Join; + using McV0Tracks = soa::Join; + using TracksMC = soa::Join; + + void processDataRun3(CollisionsRun3::iterator const& collision, aod::V0Datas const& V0s, Tracks const& tracks) + { + fillLambdaRecoTables(collision, V0s, tracks); + } + + PROCESS_SWITCH(LambdaTableProducer, processDataRun3, "Process for Run3 DATA", true); + + void processDataRun2(CollisionsRun2::iterator const& collision, aod::V0Datas const& V0s, Tracks const& tracks) + { + fillLambdaRecoTables(collision, V0s, tracks); + } + + PROCESS_SWITCH(LambdaTableProducer, processDataRun2, "Process for Run2 DATA", false); + + void processMCRun3(soa::Join::iterator const& mcCollision, + soa::SmallGroups> const& collisions, + McV0Tracks const& V0s, TracksMC const& tracks, + aod::McParticles const& mcParticles) + { + analyzeMcRecoGen(mcCollision, collisions, V0s, tracks, mcParticles); + } + + PROCESS_SWITCH(LambdaTableProducer, processMCRun3, "Process for Run3 MC RecoGen", false); + + void processMCRun2(soa::Join::iterator const& mcCollision, + soa::SmallGroups> const& collisions, + McV0Tracks const& V0s, TracksMC const& tracks, + aod::McParticles const& mcParticles) + { + analyzeMcRecoGen(mcCollision, collisions, V0s, tracks, mcParticles); + } + + PROCESS_SWITCH(LambdaTableProducer, processMCRun2, "Process for Run2 MC RecoGen", false); +}; + +struct LambdaTracksExtProducer { + + Produces lambdaTrackExtTable; + + // Configurables + Configurable cAcceptAllLambda{"cAcceptAllLambda", false, "Accept all Lambda"}; + Configurable cRejAllLambdaShaDau{"cRejAllLambdaShaDau", true, "Reject all Lambda sharing daughters"}; + Configurable cSelLambdaMassPdg{"cSelLambdaMassPdg", false, "Select Lambda closest to Pdg Mass"}; + Configurable cSelLambdaTScore{"cSelLambdaTScore", false, "Select Lambda based on t-score"}; + Configurable cA{"cA", 0.6, "a * |lambdaMass - lambdaPdgMass|"}; + Configurable cB{"cB", 0.6, "b * DcaPrPi"}; + Configurable cC{"cC", 0.6, "c * Cos(theta_{PA})"}; + + // Histogram Registry. + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext const&) + { + // Axis Specifications + const AxisSpec axisMult(10, 0, 10); + const AxisSpec axisMass(100, 1.06, 1.16, "Inv Mass (GeV/#it{c}^{2})"); + const AxisSpec axisCPA(100, 0.995, 1.0, "cos(#theta_{PA})"); + const AxisSpec axisDcaDau(75, 0., 1.5, "Daug DCA (#sigma)"); + + // Histograms Booking + histos.add("h1i_totlambda_mult", "Multiplicity", kTH1I, {axisMult}); + histos.add("h1i_totantilambda_mult", "Multiplicity", kTH1I, {axisMult}); + histos.add("h1i_lambda_mult", "Multiplicity", kTH1I, {axisMult}); + histos.add("h1i_antilambda_mult", "Multiplicity", kTH1I, {axisMult}); + + // InvMass, DcaDau and CosPA + histos.add("Reco/h1f_lambda_invmass", "M_{p#pi}", kTH1F, {axisMass}); + histos.add("Reco/h1f_lambda_cospa", "cos(#theta_{PA})", kTH1F, {axisCPA}); + histos.add("Reco/h1f_lambda_dcadau", "DCA_{p#pi} at V0 Decay Vertex", kTH1F, {axisDcaDau}); + histos.add("Reco/h1f_antilambda_invmass", "M_{p#pi}", kTH1F, {axisMass}); + histos.add("Reco/h1f_antilambda_cospa", "cos(#theta_{PA})", kTH1F, {axisCPA}); + histos.add("Reco/h1f_antilambda_dcadau", "DCA_{p#pi} at V0 Decay Vertex", kTH1F, {axisDcaDau}); + + histos.addClone("Reco/", "SharingDau/"); + } + + template + void fillHistos(T const& track) + { + static constexpr std::string_view SubDir[] = {"Reco/", "SharingDau/"}; + + if (track.v0Type() == kLambda) { + histos.fill(HIST(SubDir[sd]) + HIST("h1f_lambda_invmass"), track.mass()); + histos.fill(HIST(SubDir[sd]) + HIST("h1f_lambda_dcadau"), track.dcaDau()); + histos.fill(HIST(SubDir[sd]) + HIST("h1f_lambda_cospa"), track.cosPA()); + } else { + histos.fill(HIST(SubDir[sd]) + HIST("h1f_antilambda_invmass"), track.mass()); + histos.fill(HIST(SubDir[sd]) + HIST("h1f_antilambda_dcadau"), track.dcaDau()); + histos.fill(HIST(SubDir[sd]) + HIST("h1f_antilambda_cospa"), track.cosPA()); + } + } + + void process(aod::LambdaCollisions::iterator const&, aod::LambdaTracks const& tracks) + { + + int nTotLambda = 0, nTotAntiLambda = 0, nSelLambda = 0, nSelAntiLambda = 0; + + for (auto const& lambda : tracks) { + bool lambdaMinDeltaMassFlag = true, lambdaMinTScoreFlag = true; + bool lambdaSharingDauFlag = false, trueLambdaFlag = false; + std::vector vSharedDauLambdaIndex; + float tLambda = 0., tTrack = 0.; + + if (lambda.v0Type() == kLambda) { + ++nTotLambda; + } else if (lambda.v0Type() == kAntiLambda) { + ++nTotAntiLambda; + } + + tLambda = (cA * std::abs(lambda.mass() - MassLambda0)) + (cB * lambda.dcaDau()) + (cC * std::abs(lambda.cosPA() - 1.)); + + for (auto const& track : tracks) { + // check lambda index (don't analyze same lambda track !!!) + if (lambda.index() == track.index()) { + continue; + } + + // check only lambda-lambda || antilambda-antilambda + if (lambda.v0Type() != track.v0Type()) { + continue; + } + + // check if lambda shares daughters with any other track + if (lambda.posTrackId() == track.posTrackId() || lambda.negTrackId() == track.negTrackId()) { + vSharedDauLambdaIndex.push_back(track.index()); + lambdaSharingDauFlag = true; + + // decision based on mass closest to PdgMass of Lambda + if (std::abs(lambda.mass() - MassLambda0) > std::abs(track.mass() - MassLambda0)) { + lambdaMinDeltaMassFlag = false; + } + + // decisions based on t-score + tTrack = (cA * std::abs(track.mass() - MassLambda0)) + (cB * track.dcaDau()) + (cC * std::abs(track.cosPA() - 1.)); + if (tLambda > tTrack) { + lambdaMinTScoreFlag = false; + } + } + } + + // fill QA histograms + if (lambdaSharingDauFlag) { + fillHistos(lambda); + } else { + fillHistos(lambda); + } + + if (cAcceptAllLambda) { // Accept all lambda + trueLambdaFlag = true; + } else if (cRejAllLambdaShaDau && !lambdaSharingDauFlag) { // Reject all lambda sharing daughter + trueLambdaFlag = true; + } else if (cSelLambdaMassPdg && lambdaMinDeltaMassFlag) { // Select lambda closest to pdg mass + trueLambdaFlag = true; + } else if (cSelLambdaTScore && lambdaMinTScoreFlag) { // Select lambda based on t-score + trueLambdaFlag = true; + } + + // Multiplicity of selected lambda + if (trueLambdaFlag) { + if (lambda.v0Type() == kLambda) { + ++nSelLambda; + } else if (lambda.v0Type() == kAntiLambda) { + ++nSelAntiLambda; + } + } + + // fill LambdaTrackExt table + lambdaTrackExtTable(lambdaSharingDauFlag, vSharedDauLambdaIndex, trueLambdaFlag); + } + + // fill multiplicity histograms + if (nTotLambda != 0) { + histos.fill(HIST("h1i_totlambda_mult"), nTotLambda); + } + + if (nTotAntiLambda != 0) { + histos.fill(HIST("h1i_totantilambda_mult"), nTotAntiLambda); + } + + if (nSelLambda != 0) { + histos.fill(HIST("h1i_lambda_mult"), nSelLambda); + } + + if (nSelAntiLambda != 0) { + histos.fill(HIST("h1i_antilambda_mult"), nSelAntiLambda); + } + } +}; + +struct LambdaR2Correlation { + + // Global Configurables + Configurable cNPtBins{"cNPtBins", 10, "N pT Bins"}; + Configurable cMinPt{"cMinPt", 0.8, "pT Min"}; + Configurable cMaxPt{"cMaxPt", 2.8, "pT Max"}; + Configurable cNRapBins{"cNRapBins", 12, "N Rapidity Bins"}; + Configurable cMinRap{"cMinRap", -0.6, "Minimum Rapidity"}; + Configurable cMaxRap{"cMaxRap", 0.6, "Maximum Rapidity"}; + Configurable cNPhiBins{"cNPhiBins", 36, "N Phi Bins"}; + + // Eta/Rap Analysis + Configurable cDoEtaAnalysis{"cDoEtaAnalysis", false, "Eta/Rap Analysis Flag"}; + + // Histogram Registry. + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Initialize global variables + float nrapbins = 0.; + float kminrap = 0.; + float kmaxrap = 0.; + float nphibins = 0.; + float kminphi = 0.; + float kmaxphi = TwoPI; + float rapbinwidth = 0.; + float phibinwidth = 0.; + float q = 0., e = 0., qinv = 0.; + + void init(InitContext const&) + { + // Set Density Histogram Attributes + nrapbins = static_cast(cNRapBins); + kminrap = static_cast(cMinRap); + kmaxrap = static_cast(cMaxRap); + nphibins = static_cast(cNPhiBins); + + rapbinwidth = (kmaxrap - kminrap) / nrapbins; + phibinwidth = (kmaxphi - kminphi) / nphibins; + + int knrapphibins = static_cast(cNRapBins) * static_cast(cNPhiBins); + float kminrapphi = 0.; + float kmaxrapphi = knrapphibins; + + const AxisSpec axisCheck(1, 0, 1, ""); + const AxisSpec axisPosZ(220, -11, 11, "V_{z} (cm)"); + const AxisSpec axisCent(105, 0, 105, "FT0M (%)"); + const AxisSpec axisMult(10, 0, 10, "N_{#Lambda}"); + const AxisSpec axisMass(100, 1.06, 1.16, "Inv Mass (GeV/#it{c}^{2})"); + const AxisSpec axisPt(cNPtBins, cMinPt, cMaxPt, "p_{T} (GeV/#it{c})"); + const AxisSpec axisEta(cNRapBins, cMinRap, cMaxRap, "#eta"); + const AxisSpec axisRap(cNRapBins, cMinRap, cMaxRap, "y"); + const AxisSpec axisPhi(cNPhiBins, 0., TwoPI, "#varphi (rad)"); + const AxisSpec axisRapPhi(knrapphibins, kminrapphi, kmaxrapphi, "y #varphi"); + const AxisSpec axisQinv(100, 0, 10, "q_{inv} (GeV/#it{c})"); + + const AxisSpec axisEfPt(cNPtBins, cMinPt, cMaxPt, "p_{T}"); + const AxisSpec axisEfEta(cNRapBins, cMinRap, cMaxRap, "#eta"); + const AxisSpec axisEfRap(cNRapBins, cMinRap, cMaxRap, "y"); + const AxisSpec axisEfPhi(cNPhiBins, 0., TwoPI, "#varphi"); + + // Create Histograms. + // Event + histos.add("Event/Reco/h1f_collision_posz", "V_{Z} Distribution", kTH1F, {axisPosZ}); + histos.add("Event/Reco/h1f_ft0m_mult_percentile", "FT0M (%)", kTH1F, {axisCent}); + histos.add("Event/Reco/h1i_lambda_mult", "#Lambda - Multiplicity", kTH1I, {axisMult}); + histos.add("Event/Reco/h1i_antilambda_mult", "#bar{#Lambda} - Multiplicity", kTH1I, {axisMult}); + + // Efficiency Histograms + // Single Particle Efficiencies + histos.add("Reco/Efficiency/h1f_n1_pt_LaP", "#rho_{1}^{#Lambda}", kTH1F, {axisEfPt}); + histos.add("Reco/Efficiency/h1f_n1_pt_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH1F, {axisEfPt}); + histos.add("Reco/Efficiency/h3f_n1_ptetaphi_LaP", "#rho_{1}^{#Lambda}", kTH3F, {axisEfPt, axisEfEta, axisEfPhi}); + histos.add("Reco/Efficiency/h3f_n1_ptetaphi_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH3F, {axisEfPt, axisEfEta, axisEfPhi}); + histos.add("Reco/Efficiency/h3f_n1_ptrapphi_LaP", "#rho_{1}^{#Lambda}", kTH3F, {axisEfPt, axisEfRap, axisEfPhi}); + histos.add("Reco/Efficiency/h3f_n1_ptrapphi_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH3F, {axisEfPt, axisEfRap, axisEfPhi}); + + // Single and Two Particle Densities + // 1D Histograms + histos.add("Reco/h1d_n1_mass_LaP", "#rho_{1}^{#Lambda}", kTH1D, {axisMass}); + histos.add("Reco/h1d_n1_mass_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH1D, {axisMass}); + histos.add("Reco/h1d_n1_pt_LaP", "#rho_{1}^{#Lambda}", kTH1D, {axisPt}); + histos.add("Reco/h1d_n1_pt_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH1D, {axisPt}); + histos.add("Reco/h1d_n1_eta_LaP", "#rho_{1}^{#Lambda}", kTH1D, {axisEta}); + histos.add("Reco/h1d_n1_eta_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH1D, {axisEta}); + histos.add("Reco/h1d_n1_rap_LaP", "#rho_{1}^{#Lambda}", kTH1D, {axisRap}); + histos.add("Reco/h1d_n1_rap_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH1D, {axisRap}); + histos.add("Reco/h1d_n1_phi_LaP", "#rho_{1}^{#Lambda}", kTH1D, {axisPhi}); + histos.add("Reco/h1d_n1_phi_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH1D, {axisPhi}); + + // rho1 for R2 RapPhi + histos.add("Reco/h2d_n1_rapphi_LaP", "#rho_{1}^{#Lambda}", kTH2D, {axisRap, axisPhi}); + histos.add("Reco/h2d_n1_rapphi_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH2D, {axisRap, axisPhi}); + + // rho1 for Q_{inv} + histos.add("Reco/h2d_n1_pteta_LaP", "#rho_{1}^{#Lambda}", kTH2D, {axisPt, axisEta}); + histos.add("Reco/h2d_n1_pteta_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH2D, {axisPt, axisEta}); + + // rho2 for numerator of R2 + histos.add("Reco/h2d_n2_ptpt_LaP_LaM", "#rho_{2}^{#Lambda#bar{#Lambda}}", kTH2D, {axisPt, axisPt}); + histos.add("Reco/h2d_n2_ptpt_LaP_LaP", "#rho_{2}^{#Lambda#Lambda}", kTH2D, {axisPt, axisPt}); + histos.add("Reco/h2d_n2_ptpt_LaM_LaM", "#rho_{2}^{#bar{#Lambda}#bar{#Lambda}}", kTH2D, {axisPt, axisPt}); + histos.add("Reco/h2d_n2_etaeta_LaP_LaM", "#rho_{2}^{#Lambda#bar{#Lambda}}", kTH2D, {axisEta, axisEta}); + histos.add("Reco/h2d_n2_etaeta_LaP_LaP", "#rho_{2}^{#Lambda#Lambda}", kTH2D, {axisEta, axisEta}); + histos.add("Reco/h2d_n2_etaeta_LaM_LaM", "#rho_{2}^{#bar{#Lambda}#bar{#Lambda}}", kTH2D, {axisEta, axisEta}); + histos.add("Reco/h2d_n2_raprap_LaP_LaM", "#rho_{2}^{#Lambda#bar{#Lambda}}", kTH2D, {axisRap, axisRap}); + histos.add("Reco/h2d_n2_raprap_LaP_LaP", "#rho_{2}^{#Lambda#Lambda}", kTH2D, {axisRap, axisRap}); + histos.add("Reco/h2d_n2_raprap_LaM_LaM", "#rho_{2}^{#bar{#Lambda}#bar{#Lambda}}", kTH2D, {axisRap, axisRap}); + histos.add("Reco/h2d_n2_phiphi_LaP_LaM", "#rho_{2}^{#Lambda#bar{#Lambda}}", kTH2D, {axisPhi, axisPhi}); + histos.add("Reco/h2d_n2_phiphi_LaP_LaP", "#rho_{2}^{#Lambda#Lambda}", kTH2D, {axisPhi, axisPhi}); + histos.add("Reco/h2d_n2_phiphi_LaM_LaM", "#rho_{2}^{#bar{#Lambda}#bar{#Lambda}}", kTH2D, {axisPhi, axisPhi}); + + // rho2 for R2 Rap1Phi1Rap2Phi2 + histos.add("Reco/h2d_n2_rapphi_LaP_LaM", "#rho_{2}^{#Lambda#bar{#Lambda}}", kTH2D, {axisRapPhi, axisRapPhi}); + histos.add("Reco/h2d_n2_rapphi_LaP_LaP", "#rho_{2}^{#Lambda#Lambda}", kTH2D, {axisRapPhi, axisRapPhi}); + histos.add("Reco/h2d_n2_rapphi_LaM_LaM", "#rho_{2}^{#bar{#Lambda}#bar{#Lambda}}", kTH2D, {axisRapPhi, axisRapPhi}); + + // rho2 for R2 Qinv + histos.add("Reco/h1d_n2_qinv_LaP_LaM", "#rho_{2}^{#Lambda#bar{#Lambda}}", kTH1D, {axisQinv}); + histos.add("Reco/h1d_n2_qinv_LaP_LaP", "#rho_{2}^{#Lambda#Lambda}", kTH1D, {axisQinv}); + histos.add("Reco/h1d_n2_qinv_LaM_LaM", "#rho_{2}^{#bar{#Lambda}#bar{#Lambda}}", kTH1D, {axisQinv}); + + // MCGen + if (doprocessMCGen) { + histos.addClone("Event/Reco/", "Event/McGen/"); + histos.addClone("Reco/", "McGen/"); + } + } + + template + void fillPairHistos(U& p1, U& p2) + { + static constexpr std::string_view SubDirRecGen[] = {"Reco/", "McGen/"}; + static constexpr std::string_view SubDirHist[] = {"LaP_LaM", "LaP_LaP", "LaM_LaM"}; + + float rap1 = (cDoEtaAnalysis) ? p1.eta() : p1.rap(); + float rap2 = (cDoEtaAnalysis) ? p2.eta() : p2.rap(); + + int rapbin1 = static_cast((rap1 - kminrap) / rapbinwidth); + int rapbin2 = static_cast((rap2 - kminrap) / rapbinwidth); + + int phibin1 = static_cast(p1.phi() / phibinwidth); + int phibin2 = static_cast(p2.phi() / phibinwidth); + + float corfac = p1.corrFact() * p2.corrFact(); + + // fill rho2 histograms + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h2d_n2_ptpt_") + HIST(SubDirHist[part_pair]), p1.pt(), p2.pt(), corfac); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h2d_n2_etaeta_") + HIST(SubDirHist[part_pair]), p1.eta(), p2.eta(), corfac); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h2d_n2_raprap_") + HIST(SubDirHist[part_pair]), p1.rap(), p2.rap(), corfac); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h2d_n2_phiphi_") + HIST(SubDirHist[part_pair]), p1.phi(), p2.phi(), corfac); + + if (rapbin1 >= 0 && rapbin2 >= 0 && phibin1 >= 0 && phibin2 >= 0 && rapbin1 < nrapbins && rapbin2 < nrapbins && phibin1 < nphibins && phibin2 < nphibins) { + + int rapphix = rapbin1 * nphibins + phibin1; + int rapphiy = rapbin2 * nphibins + phibin2; + + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h2d_n2_rapphi_") + HIST(SubDirHist[part_pair]), rapphix + 0.5, rapphiy + 0.5, corfac); + } + + // qinv histograms + q = RecoDecay::p((p1.px() - p2.px()), (p1.py() - p2.py()), (p1.pz() - p2.pz())); + e = RecoDecay::e(p1.px(), p1.py(), p1.pz(), MassLambda0) - RecoDecay::e(p2.px(), p2.py(), p2.pz(), MassLambda0); + qinv = std::sqrt(-RecoDecay::m2(q, e)); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h1d_n2_qinv_") + HIST(SubDirHist[part_pair]), qinv, corfac); + } + + template + void analyzeSingles(T const& tracks) + { + static constexpr std::string_view SubDirRecGen[] = {"Reco/", "McGen/"}; + static constexpr std::string_view SubDirHist[] = {"LaP", "LaM"}; + + int ntrk = 0; + + for (auto const& track : tracks) { + // count tracks + ++ntrk; + + // Efficiency Plots + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("Efficiency/h1f_n1_pt_") + HIST(SubDirHist[part]), track.pt()); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("Efficiency/h3f_n1_ptetaphi_") + HIST(SubDirHist[part]), track.pt(), track.eta(), track.phi()); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("Efficiency/h3f_n1_ptrapphi_") + HIST(SubDirHist[part]), track.pt(), track.rap(), track.phi()); + + // QA Plots + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h1d_n1_mass_") + HIST(SubDirHist[part]), track.mass()); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h1d_n1_pt_") + HIST(SubDirHist[part]), track.pt(), track.corrFact()); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h1d_n1_eta_") + HIST(SubDirHist[part]), track.eta(), track.corrFact()); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h1d_n1_phi_") + HIST(SubDirHist[part]), track.phi(), track.corrFact()); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h1d_n1_rap_") + HIST(SubDirHist[part]), track.rap(), track.corrFact()); + + // Rho1 for N1RapPhi + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h2d_n1_rapphi_") + HIST(SubDirHist[part]), track.rap(), track.phi(), track.corrFact()); + + // Rho1 for Q_{inv} Bkg Estimation + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h2d_n1_pteta_") + HIST(SubDirHist[part]), track.pt(), track.eta(), track.corrFact()); + } + + // fill multiplicity histograms + if (ntrk != 0) { + if (part == kLambda) { + histos.fill(HIST("Event/") + HIST(SubDirRecGen[rec_gen]) + HIST("h1i_lambda_mult"), ntrk); + } else { + histos.fill(HIST("Event/") + HIST(SubDirRecGen[rec_gen]) + HIST("h1i_antilambda_mult"), ntrk); + } + } + } + + template + void analyzePairs(T const& trks_1, T const& trks_2) + { + for (auto const& trk_1 : trks_1) { + for (auto const& trk_2 : trks_2) { + // check for same index for Lambda-Lambda / AntiLambda-AntiLambda + if (samelambda && ((trk_1.index() == trk_2.index()))) { + continue; + } + fillPairHistos(trk_1, trk_2); + } + } + } + + using LambdaCollisions = aod::LambdaCollisions; + using LambdaTracks = soa::Join; + + SliceCache cache; + Partition partLambdaTracks = (aod::lambdatrack::v0Type == (int8_t)kLambda) && (aod::lambdatrackext::trueLambdaFlag == true); + Partition partAntiLambdaTracks = (aod::lambdatrack::v0Type == (int8_t)kAntiLambda) && (aod::lambdatrackext::trueLambdaFlag == true); + + void processDataReco(LambdaCollisions::iterator const& collision, LambdaTracks const&) + { + histos.fill(HIST("Event/Reco/h1f_collision_posz"), collision.posZ()); + histos.fill(HIST("Event/Reco/h1f_ft0m_mult_percentile"), collision.cent()); + + auto lambdaTracks = partLambdaTracks->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); + auto antiLambdaTracks = partAntiLambdaTracks->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); + + analyzeSingles(lambdaTracks); + analyzeSingles(antiLambdaTracks); + analyzePairs(lambdaTracks, antiLambdaTracks); + analyzePairs(lambdaTracks, lambdaTracks); + analyzePairs(antiLambdaTracks, antiLambdaTracks); + } + + PROCESS_SWITCH(LambdaR2Correlation, processDataReco, "Process for Data and MCReco", true); + + using LambdaMcGenCollisions = aod::LambdaMcGenCollisions; + using LambdaMcGenTracks = aod::LambdaMcGenTracks; + + SliceCache cachemc; + Partition partLambdaMcGenTracks = aod::lambdatrack::v0Type == (int8_t)kLambda; + Partition partAntiLambdaMcGenTracks = aod::lambdatrack::v0Type == (int8_t)kAntiLambda; + + void processMCGen(LambdaMcGenCollisions::iterator const& mcgencol, LambdaMcGenTracks const&) + { + histos.fill(HIST("Event/McGen/h1f_collision_posz"), mcgencol.posZ()); + histos.fill(HIST("Event/McGen/h1f_ft0m_mult_percentile"), mcgencol.cent()); + + auto lambdaMcGenTracks = partLambdaMcGenTracks->sliceByCached(aod::lambdamcgentrack::lambdaMcGenCollisionId, mcgencol.globalIndex(), cachemc); + auto antiLambdaMcGenTracks = partAntiLambdaMcGenTracks->sliceByCached(aod::lambdamcgentrack::lambdaMcGenCollisionId, mcgencol.globalIndex(), cachemc); + + analyzeSingles(lambdaMcGenTracks); + analyzeSingles(antiLambdaMcGenTracks); + + analyzePairs(lambdaMcGenTracks, antiLambdaMcGenTracks); + analyzePairs(lambdaMcGenTracks, lambdaMcGenTracks); + analyzePairs(antiLambdaMcGenTracks, antiLambdaMcGenTracks); + } + + PROCESS_SWITCH(LambdaR2Correlation, processMCGen, "Process for MC Generated", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/TwoParticleCorrelations/Tasks/neutronProtonCorrZdc.cxx b/PWGCF/TwoParticleCorrelations/Tasks/neutronProtonCorrZdc.cxx new file mode 100644 index 00000000000..b23be4f956c --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/Tasks/neutronProtonCorrZdc.cxx @@ -0,0 +1,322 @@ +// 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 neutronProtonCorrZdc.cxx +/// \brief Correlations between protons and neutrons in the ZDC +/// \author Olaf Massen + +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Framework/StaticFor.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +enum EventCounter { kNoSelection = 0, + kQualitySelection = 1, + kMaxCentralitySelection = 2, + kZDCSelection = 3 }; + +struct NeutronProtonCorrZdc { + // Histogram registry: an object to hold your histograms + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable cfgNBinsZN{"cfgNBinsZN", 100, "N bins for ZNA and ZNC"}; + Configurable cfgNBinsZP{"cfgNBinsZP", 100, "N bins for ZPA and ZPC"}; + Configurable cfgZNmin{"cfgZNmin", -10, "Minimum value for ZN signal"}; + Configurable cfgZNmax{"cfgZNmax", 350, "Maximum value for ZN signal"}; + Configurable cfgZPmin{"cfgZPmin", -10, "Minimum value for ZP signal"}; + Configurable cfgZPmax{"cfgZPmax", 200, "Maximum value for ZP signal"}; + Configurable cfgDiffZmin{"cfgDiffZmin", -30, "Minimum value for the diffZ signal"}; + Configurable cfgDiffZmax{"cfgDiffZmax", 50, "Maximum value for the diffZ signal"}; + Configurable cfgNBinsAlpha{"cfgNBinsAlpha", 100, "Number of bins for ZDC asymmetry"}; + Configurable cfgAlphaZmin{"cfgAlphaZmin", -1, "Minimum value for ZDC asymmetry"}; + Configurable cfgAlphaZmax{"cfgAlphaZmax", 1, "Maximum value for ZDC asymmetry"}; + Configurable cfgMaxCentrality{"cfgMaxCentrality", 80, "Maximum collision centrality"}; + Configurable cfgCentralityEstimator{"cfgCentralityEstimator", 0, "Choice of centrality estimator"}; + Configurable cfgNBinsMultiplicity{"cfgNBinsMultiplicity", 1000, "N bins for multiplicity histograms"}; + + ConfigurableAxis cfgAxisCent{"cfgAxisCent", {VARIABLE_WIDTH, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 33.0, 34.0, 35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0, 47.0, 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0, 56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 72.0, 73.0, 74.0, 75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, 88.0, 89.0, 90.0, 91.0, 92.0, 93.0, 94.0, 95.0, 96.0, 97.0, 98.0, 99.0, 100.0}, "Centrality [%]"}; + + Filter collisionVtxZ = nabs(aod::collision::posZ) < 10.f; + + using CentralitiesRun3 = soa::Join; + using CentralitiesRun2 = aod::CentRun2V0Ms; + using BCsRun3 = soa::Join; + + void init(InitContext const&) + { + // define axes you want to use + const AxisSpec axisCounter{4, -0.5, 3.5, ""}; + const AxisSpec axisZNSectorSignal{cfgNBinsZN, cfgZNmin, cfgZNmax / 3.}; + const AxisSpec axisZPSectorSignal{cfgNBinsZP, cfgZPmin, cfgZPmax / 3.}; + const AxisSpec axisZNASignal{cfgNBinsZN, cfgZNmin, cfgZNmax, "ZNA (a.u.)"}; + const AxisSpec axisZNCSignal{cfgNBinsZN, cfgZNmin, cfgZNmax, "ZNC (a.u.)"}; + const AxisSpec axisZPASignal{cfgNBinsZP, cfgZPmin, cfgZPmax, "ZPA (a.u.)"}; + const AxisSpec axisZPCSignal{cfgNBinsZP, cfgZPmin, cfgZPmax, "ZPC (a.u.)"}; + const AxisSpec axisZNSignal{2 * cfgNBinsZN, cfgZNmin, 1.5 * cfgZNmax, "ZN (a.u.)"}; + const AxisSpec axisZPSignal{2 * cfgNBinsZP, cfgZPmin, 1.5 * cfgZPmax, "ZP (a.u.)"}; + const AxisSpec axisAlphaZ{cfgNBinsAlpha, cfgAlphaZmin, cfgAlphaZmax, "#alpha_{spec}"}; + const AxisSpec axisZDiffSignal{cfgNBinsZN, cfgDiffZmin, cfgDiffZmax, "#Delta E"}; + const AxisSpec axisMultiplicityF0A{cfgNBinsMultiplicity, 0, 200000, "F0A"}; + const AxisSpec axisMultiplicityF0C{cfgNBinsMultiplicity, 0, 100000, "F0C"}; + const AxisSpec axisMultiplicityF0M{cfgNBinsMultiplicity, 0, 300000, "F0M"}; + const AxisSpec axisMultiplicityFDD{cfgNBinsMultiplicity, 0, 50000, "FDD"}; + const AxisSpec axisMultiplicityTPC{cfgNBinsMultiplicity, 0, 100000, "TPC"}; + const AxisSpec axisMultiplicityMultNGlobal{cfgNBinsMultiplicity, 0, 3500, "MultsNGlobal"}; + + HistogramConfigSpec defaultZNSectorHist({HistType::kTH2F, {cfgAxisCent, axisZNSectorSignal}}); + HistogramConfigSpec defaultZPSectorHist({HistType::kTH2F, {cfgAxisCent, axisZPSectorSignal}}); + HistogramConfigSpec defaultZDCDiffHist({HistType::kTH2F, {cfgAxisCent, axisZDiffSignal}}); + + // create histograms + histos.add("eventCounter", "eventCounter", kTH1F, {axisCounter}); + histos.add("CentralityPercentile", "CentralityPercentile", kTH1F, {cfgAxisCent}); + + histos.add("ASide/CentvsZNSector0Signal", "CentvsZNASector0Signal", defaultZNSectorHist); + histos.add("ASide/CentvsZNSector1Signal", "CentvsZNASector1Signal", defaultZNSectorHist); + histos.add("ASide/CentvsZNSector2Signal", "CentvsZNASector2Signal", defaultZNSectorHist); + histos.add("ASide/CentvsZNSector3Signal", "CentvsZNASector3Signal", defaultZNSectorHist); + histos.add("ASide/CentvsZPSector0Signal", "CentvsZPASector0Signal", defaultZPSectorHist); + histos.add("ASide/CentvsZPSector1Signal", "CentvsZPASector1Signal", defaultZPSectorHist); + histos.add("ASide/CentvsZPSector2Signal", "CentvsZPASector2Signal", defaultZPSectorHist); + histos.add("ASide/CentvsZPSector3Signal", "CentvsZPASector3Signal", defaultZPSectorHist); + histos.add("ASide/CentvsZNSignalSum", "CentvsZNASignalSum", kTH2F, {cfgAxisCent, axisZNASignal}); + histos.add("ASide/CentvsZNSignalCommon", "CentvsZNASignalCommon", kTH2F, {cfgAxisCent, axisZNASignal}); + histos.add("ASide/CentvsZPSignalSum", "CentvsZNASignalSum", kTH2F, {cfgAxisCent, axisZPASignal}); + histos.add("ASide/CentvsZPSignalCommon", "CentvsZNASignalCommon", kTH2F, {cfgAxisCent, axisZPASignal}); + histos.add("ASide/CentvsdiffZNSignal", "CentvsdiffZNSignal", defaultZDCDiffHist); + histos.add("ASide/CentvsdiffZPSignal", "CentvsdiffZPSignal", defaultZDCDiffHist); + + // Cloning the folder + histos.addClone("ASide/", "CSide/"); + + histos.add("CentvsZNSignalCommon", "CentvsZNSignalCommon", kTH2F, {cfgAxisCent, axisZNSignal}); + histos.add("CentvsZNSignalSum", "CentvsZNSignalSum", kTH2F, {cfgAxisCent, axisZNSignal}); + histos.add("CentvsZPSignalCommon", "CentvsZPSignalCommon", kTH2F, {cfgAxisCent, axisZPSignal}); + histos.add("CentvsZPSignalSum", "CentvsZPSignalSum", kTH2F, {cfgAxisCent, axisZPSignal}); + histos.add("CentvsAlphaZN", "CentvsAlphaZN", kTH2F, {cfgAxisCent, axisAlphaZ}); + histos.add("CentvsAlphaZP", "CentvsAlphaZP", kTH2F, {cfgAxisCent, axisAlphaZ}); + histos.add("CentvsAlphaZNcommon", "CentvsAlphaZNcommon", kTH2F, {cfgAxisCent, axisAlphaZ}); + histos.add("CentvsAlphaZPcommon", "CentvsAlphaZPcommon", kTH2F, {cfgAxisCent, axisAlphaZ}); + histos.add("CentvsDiffZNSignal", "CentvsDiffZNSignal", defaultZDCDiffHist); + histos.add("CentvsDiffZPSignal", "CentvsDiffZPSignal", defaultZDCDiffHist); + histos.add("CentvsZNAvsZNC", "CentvsZNAvsZNC", kTH3F, {cfgAxisCent, axisZNASignal, axisZNCSignal}); + histos.add("CentvsZNAvsZPA", "CentvsZNAvsZPA", kTH3F, {cfgAxisCent, axisZNASignal, axisZPASignal}); + histos.add("CentvsZNAvsZPC", "CentvsZNAvsZPC", kTH3F, {cfgAxisCent, axisZNASignal, axisZPCSignal}); + histos.add("CentvsZPAvsZNC", "CentvsZPAvsZNC", kTH3F, {cfgAxisCent, axisZPASignal, axisZNCSignal}); + histos.add("CentvsZPAvsZPC", "CentvsZNAvsZPC", kTH3F, {cfgAxisCent, axisZPASignal, axisZPCSignal}); + histos.add("CentvsZNCvsZPC", "CentvsZNCvsZPC", kTH3F, {cfgAxisCent, axisZNCSignal, axisZPCSignal}); + histos.add("CentvsZNvsZP", "CentvsZNvsZP", kTH3F, {cfgAxisCent, axisZNSignal, axisZPSignal}); + + histos.add("MultiplicityHistograms/FV0A", "FV0A", kTH1F, {axisMultiplicityF0A}); + histos.add("MultiplicityHistograms/FT0A", "FT0A", kTH1F, {axisMultiplicityF0A}); + histos.add("MultiplicityHistograms/FT0C", "FT0C", kTH1F, {axisMultiplicityF0C}); + histos.add("MultiplicityHistograms/FDDA", "FDDA", kTH1F, {axisMultiplicityFDD}); + histos.add("MultiplicityHistograms/FDDC", "FDDC", kTH1F, {axisMultiplicityFDD}); + histos.add("MultiplicityHistograms/TPC", "TPC", kTH1F, {axisMultiplicityTPC}); + histos.add("MultiplicityHistograms/NGlobal", "NGlobal", kTH1F, {axisMultiplicityMultNGlobal}); + histos.add("MultiplicityHistograms/CentvsFT0C", "CentvsFT0C", kTH2F, {cfgAxisCent, axisMultiplicityF0C}); + histos.add("MultiplicityHistograms/CentvsFT0CVar1", "CentvsFT0CVar1", kTH2F, {cfgAxisCent, axisMultiplicityF0C}); + histos.add("MultiplicityHistograms/CentvsFT0M", "CentvsFT0M", kTH2F, {cfgAxisCent, axisMultiplicityF0M}); + histos.add("MultiplicityHistograms/CentvsFV0A", "CentvsFV0A", kTH2F, {cfgAxisCent, axisMultiplicityF0A}); + histos.add("MultiplicityHistograms/CentvsNGlobal", "CentvsNGlobal", kTH2F, {cfgAxisCent, axisMultiplicityMultNGlobal}); + } + + template + void fillMultHistosRun3(const C& col) + { + static constexpr std::string_view MultLabels[] = {"FT0C", "FT0A", "FV0A", "FDDC", "FDDA", "TPC", "NGlobal"}; + std::array multarray = {col.multFT0C(), col.multFT0A(), col.multFV0A(), col.multFDDC(), col.multFDDA(), static_cast(col.multTPC()), static_cast(col.multNTracksGlobal())}; + + histos.fill(HIST("MultiplicityHistograms/") + HIST(MultLabels[mult]), multarray[mult]); + } + + template + void fillCentHistosRun3(const C& col) + { + static constexpr std::string_view CentLabels[] = {"CentvsFT0C", "CentvsFT0CVar1", "CentvsFT0M", "CentvsFV0A", "CentvsNGlobal"}; + std::array centarray = {col.centFT0C(), col.centFT0CVariant1(), col.centFT0M(), col.centFV0A(), col.centNGlobal()}; + std::array multarray = {col.multFT0C(), col.multFT0C(), col.multFT0C() + col.multFT0A(), col.multFV0A(), static_cast(col.multNTracksGlobal())}; + + histos.fill(HIST("MultiplicityHistograms/") + HIST(CentLabels[cent]), centarray[cent], multarray[cent]); + } + + template + void fillZDCSideCommonHistos(const float centr, const Z& zdc) + { + static constexpr std::string_view SubDir[] = {"ASide/", "CSide/"}; + + std::array, 2> znEnergyResponse = {zdc.energySectorZNA(), zdc.energySectorZNC()}; + std::array, 2> zpEnergyResponse = {zdc.energySectorZPA(), zdc.energySectorZPC()}; + std::array znEnergyResponseCommon = {zdc.energyCommonZNA(), zdc.energyCommonZNC()}; + std::array zpEnergyResponseCommon = {zdc.energyCommonZPA(), zdc.energyCommonZPC()}; + + float sumZN = znEnergyResponse[side][0] + znEnergyResponse[side][1] + znEnergyResponse[side][2] + znEnergyResponse[side][3]; + float sumZP = zpEnergyResponse[side][0] + zpEnergyResponse[side][1] + zpEnergyResponse[side][2] + zpEnergyResponse[side][3]; + + histos.fill(HIST(SubDir[side]) + HIST("CentvsZNSignalSum"), centr, sumZN); + histos.fill(HIST(SubDir[side]) + HIST("CentvsZNSignalCommon"), centr, znEnergyResponseCommon[side]); + histos.fill(HIST(SubDir[side]) + HIST("CentvsdiffZNSignal"), centr, sumZN - znEnergyResponseCommon[side]); + histos.fill(HIST(SubDir[side]) + HIST("CentvsZPSignalSum"), centr, sumZP); + histos.fill(HIST(SubDir[side]) + HIST("CentvsZPSignalCommon"), centr, zpEnergyResponseCommon[side]); + histos.fill(HIST(SubDir[side]) + HIST("CentvsdiffZPSignal"), centr, sumZP - zpEnergyResponseCommon[side]); + } + + template + void fillZDCSideSectorHistos(const float centr, const Z& zdc) + { + static constexpr std::string_view SubDir[] = {"ASide/", "CSide/"}; + static constexpr std::string_view ZNSector[] = {"CentvsZNSector0Signal", "CentvsZNSector1Signal", "CentvsZNSector2Signal", "CentvsZNSector3Signal"}; + static constexpr std::string_view ZPSector[] = {"CentvsZPSector0Signal", "CentvsZPSector1Signal", "CentvsZPSector2Signal", "CentvsZPSector3Signal"}; + + std::array, 2> znEnergyResponse = {zdc.energySectorZNA(), zdc.energySectorZNC()}; + std::array, 2> zpEnergyResponse = {zdc.energySectorZPA(), zdc.energySectorZPC()}; + + histos.fill(HIST(SubDir[side]) + HIST(ZNSector[sector]), centr, znEnergyResponse[side][sector]); + histos.fill(HIST(SubDir[side]) + HIST(ZPSector[sector]), centr, zpEnergyResponse[side][sector]); + } + + void processRun3(soa::Filtered>::iterator const& collision, BCsRun3 const&, aod::Zdcs const&) + { + histos.fill(HIST("eventCounter"), EventCounter::kNoSelection); + if (!collision.sel8()) { + return; + } + histos.fill(HIST("eventCounter"), EventCounter::kQualitySelection); + + const float centArray[] = {collision.centFT0C(), collision.centFT0CVariant1(), collision.centFT0M(), collision.centFV0A(), collision.centNGlobal()}; + const auto cent = centArray[cfgCentralityEstimator]; + if (cent > cfgMaxCentrality) { + return; + } + histos.fill(HIST("eventCounter"), EventCounter::kMaxCentralitySelection); + + const auto& foundBC = collision.foundBC_as(); + if (foundBC.has_zdc()) { + const auto& zdcread = foundBC.zdc(); + histos.fill(HIST("eventCounter"), EventCounter::kZDCSelection); + histos.fill(HIST("CentralityPercentile"), cent); + + static_for<0, 6>([&](auto i) { + fillMultHistosRun3(collision); // Fill multiplicity histograms + }); + + static_for<0, 4>([&](auto i) { + fillCentHistosRun3(collision); // Fill centrality histograms + }); + + static_for<0, 1>([&](auto i) { + fillZDCSideCommonHistos(cent, zdcread); // Fill i-side common histograms + static_for<0, 3>([&](auto j) { + fillZDCSideSectorHistos(cent, zdcread); // Fill i-side sector j histograms + }); + }); + + float sumZNC = (zdcread.energySectorZNC())[0] + (zdcread.energySectorZNC())[1] + (zdcread.energySectorZNC())[2] + (zdcread.energySectorZNC())[3]; + float sumZNA = (zdcread.energySectorZNA())[0] + (zdcread.energySectorZNA())[1] + (zdcread.energySectorZNA())[2] + (zdcread.energySectorZNA())[3]; + float sumZPC = (zdcread.energySectorZPC())[0] + (zdcread.energySectorZPC())[1] + (zdcread.energySectorZPC())[2] + (zdcread.energySectorZPC())[3]; + float sumZPA = (zdcread.energySectorZPA())[0] + (zdcread.energySectorZPA())[1] + (zdcread.energySectorZPA())[2] + (zdcread.energySectorZPA())[3]; + + float alphaZN = (sumZNA - sumZNC) / (sumZNA + sumZNC); + float alphaZP = (sumZPA - sumZPC) / (sumZPA + sumZPC); + + histos.fill(HIST("CentvsDiffZNSignal"), cent, (sumZNA + sumZNC) - (zdcread.energyCommonZNA() + zdcread.energyCommonZNC())); + histos.fill(HIST("CentvsDiffZPSignal"), cent, (sumZPA + sumZPC) - (zdcread.energyCommonZPA() + zdcread.energyCommonZPC())); + histos.fill(HIST("CentvsZNSignalSum"), cent, sumZNA + sumZNC); + histos.fill(HIST("CentvsZPSignalSum"), cent, sumZPA + sumZPC); + histos.fill(HIST("CentvsZNSignalCommon"), cent, (zdcread.energyCommonZNA() + zdcread.energyCommonZNC())); + histos.fill(HIST("CentvsZPSignalCommon"), cent, (zdcread.energyCommonZPA() + zdcread.energyCommonZPC())); + histos.fill(HIST("CentvsAlphaZN"), cent, alphaZN); + histos.fill(HIST("CentvsAlphaZP"), cent, alphaZP); + histos.fill(HIST("CentvsAlphaZNcommon"), cent, (zdcread.energyCommonZNA() - zdcread.energyCommonZNC()) / (zdcread.energyCommonZNA() + zdcread.energyCommonZNC())); + histos.fill(HIST("CentvsAlphaZPcommon"), cent, (zdcread.energyCommonZPA() - zdcread.energyCommonZPC()) / (zdcread.energyCommonZPA() + zdcread.energyCommonZPC())); + + histos.fill(HIST("CentvsZNAvsZNC"), cent, sumZNA, sumZNC); + histos.fill(HIST("CentvsZNAvsZPA"), cent, sumZNA, sumZPA); + histos.fill(HIST("CentvsZNAvsZPC"), cent, sumZNA, sumZPC); + histos.fill(HIST("CentvsZPAvsZNC"), cent, sumZPA, sumZNC); + histos.fill(HIST("CentvsZPAvsZPC"), cent, sumZPA, sumZPC); + histos.fill(HIST("CentvsZNCvsZPC"), cent, sumZNC, sumZPC); + histos.fill(HIST("CentvsZNvsZP"), cent, sumZNA + sumZNC, sumZPA + sumZPC); + } + } + PROCESS_SWITCH(NeutronProtonCorrZdc, processRun3, "Process analysis for Run 3 data", true); + + void processRun2(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, aod::Zdcs const&) + { + histos.fill(HIST("eventCounter"), EventCounter::kNoSelection); + if (!collision.alias_bit(kINT7)) { + return; + } + histos.fill(HIST("eventCounter"), EventCounter::kQualitySelection); + if (collision.centRun2V0M() > cfgMaxCentrality) { + return; + } + histos.fill(HIST("eventCounter"), EventCounter::kMaxCentralitySelection); + + if (collision.has_zdc()) { + const auto& zdcread = collision.zdc(); + const auto cent = collision.centRun2V0M(); + + histos.fill(HIST("eventCounter"), EventCounter::kZDCSelection); + histos.fill(HIST("CentralityPercentile"), cent); + + static_for<0, 1>([&](auto i) { + fillZDCSideCommonHistos(cent, zdcread); // Fill i-side common channels + static_for<0, 3>([&](auto j) { + fillZDCSideSectorHistos(cent, zdcread); // Fill i-side sector j + }); + }); + + float sumZNC = (zdcread.energySectorZNC())[0] + (zdcread.energySectorZNC())[1] + (zdcread.energySectorZNC())[2] + (zdcread.energySectorZNC())[3]; + float sumZNA = (zdcread.energySectorZNA())[0] + (zdcread.energySectorZNA())[1] + (zdcread.energySectorZNA())[2] + (zdcread.energySectorZNA())[3]; + float sumZPC = (zdcread.energySectorZPC())[0] + (zdcread.energySectorZPC())[1] + (zdcread.energySectorZPC())[2] + (zdcread.energySectorZPC())[3]; + float sumZPA = (zdcread.energySectorZPA())[0] + (zdcread.energySectorZPA())[1] + (zdcread.energySectorZPA())[2] + (zdcread.energySectorZPA())[3]; + + float alphaZN = (sumZNA - sumZNC) / (sumZNA + sumZNC); + float alphaZP = (sumZPA - sumZPC) / (sumZPA + sumZPC); + + histos.fill(HIST("CentvsDiffZNSignal"), cent, (sumZNA + sumZNC) - (zdcread.energyCommonZNA() + zdcread.energyCommonZNC())); + histos.fill(HIST("CentvsDiffZPSignal"), cent, (sumZPA + sumZPC) - (zdcread.energyCommonZPA() + zdcread.energyCommonZPC())); + histos.fill(HIST("CentvsZNSignalSum"), cent, sumZNA + sumZNC); + histos.fill(HIST("CentvsZPSignalSum"), cent, sumZPA + sumZPC); + histos.fill(HIST("CentvsZNSignalCommon"), cent, (zdcread.energyCommonZNA() + zdcread.energyCommonZNC())); + histos.fill(HIST("CentvsZPSignalCommon"), cent, (zdcread.energyCommonZPA() + zdcread.energyCommonZPC())); + histos.fill(HIST("CentvsAlphaZN"), cent, alphaZN); + histos.fill(HIST("CentvsAlphaZP"), cent, alphaZP); + histos.fill(HIST("CentvsAlphaZNcommon"), cent, (zdcread.energyCommonZNA() - zdcread.energyCommonZNC()) / (zdcread.energyCommonZNA() + zdcread.energyCommonZNC())); + histos.fill(HIST("CentvsAlphaZPcommon"), cent, (zdcread.energyCommonZPA() - zdcread.energyCommonZPC()) / (zdcread.energyCommonZPA() + zdcread.energyCommonZPC())); + + histos.fill(HIST("CentvsZNAvsZNC"), cent, sumZNA, sumZNC); + histos.fill(HIST("CentvsZNAvsZPA"), cent, sumZNA, sumZPA); + histos.fill(HIST("CentvsZNAvsZPC"), cent, sumZNA, sumZPC); + histos.fill(HIST("CentvsZPAvsZNC"), cent, sumZPA, sumZNC); + histos.fill(HIST("CentvsZPAvsZPC"), cent, sumZPA, sumZPC); + histos.fill(HIST("CentvsZNCvsZPC"), cent, sumZNC, sumZPC); + histos.fill(HIST("CentvsZNvsZP"), cent, sumZNA + sumZNC, sumZPA + sumZPC); + } + } + PROCESS_SWITCH(NeutronProtonCorrZdc, processRun2, "Process analysis for Run 2 converted data", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/TwoParticleCorrelations/Tasks/r2p2-4-id.cxx b/PWGCF/TwoParticleCorrelations/Tasks/r2p2-4-id.cxx index d7187c49f0c..e6c13fe1318 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/r2p2-4-id.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/r2p2-4-id.cxx @@ -9,6 +9,8 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Common/DataModel/EventSelection.h" @@ -49,12 +51,12 @@ struct FillFlagsTable { auto tpcnsigma = (std::vector>){TPCnsigmacutsPi, TPCnsigmacutsKa, TPCnsigmacutsPr}; auto tofpt = (std::vector>){TOFpTrangesPi, TOFpTrangesKa, TOFpTrangesPr}; auto tofnsigma = (std::vector>){TOFnsigmacutsPi, TOFnsigmacutsKa, TOFnsigmacutsPr}; - for (int8_t i = 0; i < tpcpt[species].size(); i++) + for (std::size_t i = 0; i < tpcpt[species].size(); i++) if (trackpt < tpcpt[species][i]) { tpcindex = i; break; } - for (int8_t i = 0; i < tofpt[species].size(); i++) + for (std::size_t i = 0; i < tofpt[species].size(); i++) if (trackpt >= tofpt[species][i]) { tofindex = i; break; @@ -258,8 +260,8 @@ struct r2p24id { Configurable maxpT{"maxpT", 2.0, "Maximum pT"}; Configurable trackpartition{"trackpartition", 1.0, "where(in pT) to partition"}; - Configurable pid_particle1{"pid_particle1", 1, "Define particle1 type"}; // 1->Pion, 2->Kaon, 3->Proton - Configurable pid_particle2{"pid_particle2", 1, "Define particle2 type"}; + Configurable pid_particle1{"pid_particle1", 1, "Define particle1 type"}; // 1->Pion, 2->Kaon, 3->Proton + Configurable pid_particle2{"pid_particle2", 1, "Define particle2 type"}; Configurable iftrackpartition{"iftrackpartition", false, "If track partition is needed"}; Configurable ifpid{"ifpid", false, "If PID is needed"}; diff --git a/PWGDQ/Core/AnalysisCompositeCut.cxx b/PWGDQ/Core/AnalysisCompositeCut.cxx index cb14bd7afad..5ab08001953 100644 --- a/PWGDQ/Core/AnalysisCompositeCut.cxx +++ b/PWGDQ/Core/AnalysisCompositeCut.cxx @@ -35,6 +35,34 @@ AnalysisCompositeCut::AnalysisCompositeCut(const char* name, const char* title, // } +//____________________________________________________________________________ +AnalysisCompositeCut::AnalysisCompositeCut(const AnalysisCompositeCut& c) : AnalysisCut(c) +{ + // + // copy constructor + // + if (this != &c) { + fOptionUseAND = c.fOptionUseAND; + fCutList = c.fCutList; + fCompositeCutList = c.fCompositeCutList; + } +} + +//____________________________________________________________________________ +AnalysisCompositeCut& AnalysisCompositeCut::operator=(const AnalysisCompositeCut& c) +{ + // + // assignment + // + if (this != &c) { + AnalysisCut::operator=(c); + fOptionUseAND = c.fOptionUseAND; + fCutList = c.fCutList; + fCompositeCutList = c.fCompositeCutList; + } + return (*this); +} + //____________________________________________________________________________ AnalysisCompositeCut::~AnalysisCompositeCut() = default; diff --git a/PWGDQ/Core/AnalysisCompositeCut.h b/PWGDQ/Core/AnalysisCompositeCut.h index f9b00a9ed2e..f3d603909c4 100644 --- a/PWGDQ/Core/AnalysisCompositeCut.h +++ b/PWGDQ/Core/AnalysisCompositeCut.h @@ -26,8 +26,8 @@ class AnalysisCompositeCut : public AnalysisCut public: AnalysisCompositeCut(bool useAND = kTRUE); AnalysisCompositeCut(const char* name, const char* title, bool useAND = kTRUE); - AnalysisCompositeCut(const AnalysisCompositeCut& c) = default; - AnalysisCompositeCut& operator=(const AnalysisCompositeCut& c) = default; + AnalysisCompositeCut(const AnalysisCompositeCut& c); + AnalysisCompositeCut& operator=(const AnalysisCompositeCut& c); ~AnalysisCompositeCut() override; void AddCut(AnalysisCut* cut) diff --git a/PWGDQ/Core/AnalysisCut.cxx b/PWGDQ/Core/AnalysisCut.cxx index f61e38db131..7b5718552ba 100644 --- a/PWGDQ/Core/AnalysisCut.cxx +++ b/PWGDQ/Core/AnalysisCut.cxx @@ -11,6 +11,10 @@ #include "PWGDQ/Core/AnalysisCut.h" +#include +using std::cout; +using std::endl; + ClassImp(AnalysisCut); std::vector AnalysisCut::fgUsedVars = {}; @@ -37,5 +41,22 @@ AnalysisCut& AnalysisCut::operator=(const AnalysisCut& c) return (*this); } +//____________________________________________________________________________ +AnalysisCut::AnalysisCut(const AnalysisCut& c) : TNamed(c) +{ + // + // copy constructor + // + if (this != &c) { + fCuts = c.fCuts; + } +} + //____________________________________________________________________________ AnalysisCut::~AnalysisCut() = default; + +//____________________________________________________________________________ +void AnalysisCut::PrintCuts() +{ + cout << "**************** AnalysisCut::PrintCuts" << endl; +} diff --git a/PWGDQ/Core/AnalysisCut.h b/PWGDQ/Core/AnalysisCut.h index a1a7dfe7461..6c7185b13ec 100644 --- a/PWGDQ/Core/AnalysisCut.h +++ b/PWGDQ/Core/AnalysisCut.h @@ -26,7 +26,7 @@ class AnalysisCut : public TNamed public: AnalysisCut() = default; AnalysisCut(const char* name, const char* title); - AnalysisCut(const AnalysisCut& c) = default; + AnalysisCut(const AnalysisCut& c); AnalysisCut& operator=(const AnalysisCut& c); ~AnalysisCut() override; @@ -42,6 +42,8 @@ class AnalysisCut : public TNamed static std::vector fgUsedVars; //! vector of used variables + void PrintCuts(); + struct CutContainer { short fVar; // variable to be cut upon float fLow; // lower limit for the var diff --git a/PWGDQ/Core/CMakeLists.txt b/PWGDQ/Core/CMakeLists.txt index 5ce05ab82d1..d19a66a68e6 100644 --- a/PWGDQ/Core/CMakeLists.txt +++ b/PWGDQ/Core/CMakeLists.txt @@ -21,7 +21,7 @@ o2physics_add_library(PWGDQCore AnalysisCompositeCut.cxx MCProng.cxx MCSignal.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DCAFitter O2::GlobalTracking O2Physics::AnalysisCore KFParticle::KFParticle) + PUBLIC_LINK_LIBRARIES O2::Framework O2::DCAFitter O2::GlobalTracking O2Physics::AnalysisCore KFParticle::KFParticle) o2physics_target_root_dictionary(PWGDQCore HEADERS AnalysisCut.h diff --git a/PWGDQ/Core/CutsLibrary.cxx b/PWGDQ/Core/CutsLibrary.cxx index 700c2943a50..ff2cfe9298d 100644 --- a/PWGDQ/Core/CutsLibrary.cxx +++ b/PWGDQ/Core/CutsLibrary.cxx @@ -12,6 +12,16 @@ // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // #include "PWGDQ/Core/CutsLibrary.h" +#include +#include +#include +#include +#include +#include "AnalysisCompositeCut.h" +#include "VarManager.h" + +using std::cout; +using std::endl; AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) { @@ -27,6 +37,8 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) // /////////////////////////////////////////////// // These are the Cuts used in the CEFP Task // // to select tracks in the event selection // + // // + // see CutsLubrary.h for the description // // /////////////////////////////////////////////// if (!nameStr.compare("Electron2022")) { cut->AddCut(GetAnalysisCut("jpsiStandardKine")); @@ -35,36 +47,134 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } if (!nameStr.compare("Electron2023")) { - cut->AddCut(GetAnalysisCut("jpsiStandardKine4")); + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug")); - cut->AddCut(GetAnalysisCut("pidCut_lowP_Corr")); + cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug5_noCorr")); + return cut; + } + if (!nameStr.compare("Electron2025_1")) { + AnalysisCut* kineCut = new AnalysisCut("kineCut", "kine cut"); + kineCut->AddCut(VarManager::kP, 1.0, 1000.0); + kineCut->AddCut(VarManager::kEta, -0.9, 0.9); - AnalysisCompositeCut* pidCut_highP = new AnalysisCompositeCut("pidCut_highP", "pidCut_highP", kFALSE); - pidCut_highP->AddCut(GetAnalysisCut("EleInclusion_highP_Corr")); - pidCut_highP->AddCut(GetAnalysisCut("PionExclusion_highP_Corr")); - cut->AddCut(pidCut_highP); + AnalysisCut* qualityCuts = new AnalysisCut("qualityCuts", "quality cuts"); + qualityCuts->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + qualityCuts->AddCut(VarManager::kTPCchi2, 0.0, 5.0); + qualityCuts->AddCut(VarManager::kTPCncls, 60, 161.); + qualityCuts->AddCut(VarManager::kTrackDCAz, -0.5, 0.5); + + AnalysisCut* pidCuts = new AnalysisCut("pidCuts", "pid cuts"); + pidCuts->AddCut(VarManager::kTPCnSigmaEl, -3.0, 4.0, false, VarManager::kPin, 0.0, 5.0); + pidCuts->AddCut(VarManager::kTPCnSigmaEl, -1.5, 4.0, false, VarManager::kPin, 5.0, 1000.0); + pidCuts->AddCut(VarManager::kTPCnSigmaPi, 2.5, 999, false, VarManager::kPin, 0.0, 5.0); + pidCuts->AddCut(VarManager::kTPCnSigmaPr, 2.5, 999, false, VarManager::kPin, 0.0, 5.0); + + cut->AddCut(kineCut); + cut->AddCut(qualityCuts); + cut->AddCut(pidCuts); return cut; } - if (!nameStr.compare("Electron2023_Tight")) { - cut->AddCut(GetAnalysisCut("jpsiStandardKine4")); - cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug")); - cut->AddCut(GetAnalysisCut("pidCut_lowP_Corr")); - AnalysisCompositeCut* pidCut_highP = new AnalysisCompositeCut("pidCut_highP", "pidCut_highP", kFALSE); - pidCut_highP->AddCut(GetAnalysisCut("EleInclusion_highP2_Corr")); - pidCut_highP->AddCut(GetAnalysisCut("PionExclusion_highP_Corr")); - cut->AddCut(pidCut_highP); + if (!nameStr.compare("Electron2025_2")) { + AnalysisCut* kineCut = new AnalysisCut("kineCut", "kine cut"); + kineCut->AddCut(VarManager::kP, 1.0, 1000.0); + kineCut->AddCut(VarManager::kEta, -0.9, 0.9); + + AnalysisCut* qualityCuts = new AnalysisCut("qualityCuts", "quality cuts"); + qualityCuts->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + qualityCuts->AddCut(VarManager::kTPCchi2, 0.0, 5.0); + qualityCuts->AddCut(VarManager::kTPCncls, 60, 161.); + qualityCuts->AddCut(VarManager::kTrackDCAz, -0.5, 0.5); + + AnalysisCut* pidCuts = new AnalysisCut("pidCuts", "pid cuts"); + pidCuts->AddCut(VarManager::kTPCnSigmaEl, -3.0, 4.0, false, VarManager::kPin, 0.0, 5.0); + pidCuts->AddCut(VarManager::kTPCnSigmaEl, -2.0, 4.0, false, VarManager::kPin, 5.0, 1000.0); + pidCuts->AddCut(VarManager::kTPCnSigmaPi, 2.0, 999, false, VarManager::kPin, 0.0, 5.0); + pidCuts->AddCut(VarManager::kTPCnSigmaPr, 2.5, 999, false, VarManager::kPin, 0.0, 5.0); + + cut->AddCut(kineCut); + cut->AddCut(qualityCuts); + cut->AddCut(pidCuts); return cut; } - if (!nameStr.compare("MuonLow2022")) { - cut->AddCut(GetAnalysisCut("muonLowPt2")); - cut->AddCut(GetAnalysisCut("muonQualityCuts")); + + if (!nameStr.compare("Electron2025_3")) { + AnalysisCut* kineCut = new AnalysisCut("kineCut", "kine cut"); + kineCut->AddCut(VarManager::kP, 1.0, 1000.0); + kineCut->AddCut(VarManager::kEta, -0.9, 0.9); + + AnalysisCut* qualityCuts = new AnalysisCut("qualityCuts", "quality cuts"); + qualityCuts->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + qualityCuts->AddCut(VarManager::kTPCchi2, 0.0, 5.0); + qualityCuts->AddCut(VarManager::kTPCncls, 60, 161.); + qualityCuts->AddCut(VarManager::kTrackDCAz, -0.5, 0.5); + + AnalysisCut* pidCuts = new AnalysisCut("pidCuts", "pid cuts"); + pidCuts->AddCut(VarManager::kTPCnSigmaEl, -2.5, 4.0, false, VarManager::kPin, 0.0, 5.0); + pidCuts->AddCut(VarManager::kTPCnSigmaEl, -2.0, 4.0, false, VarManager::kPin, 5.0, 1000.0); + pidCuts->AddCut(VarManager::kTPCnSigmaPr, 2.5, 999, false, VarManager::kPin, 0.0, 5.0); + + cut->AddCut(kineCut); + cut->AddCut(qualityCuts); + cut->AddCut(pidCuts); return cut; } - if (!nameStr.compare("MuonLow2023")) { + + if (!nameStr.compare("Electron2025_4")) { + AnalysisCut* kineCut = new AnalysisCut("kineCut", "kine cut"); + kineCut->AddCut(VarManager::kP, 1.0, 1000.0); + kineCut->AddCut(VarManager::kEta, -0.9, 0.9); + + AnalysisCut* qualityCuts = new AnalysisCut("qualityCuts", "quality cuts"); + qualityCuts->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + qualityCuts->AddCut(VarManager::kTPCchi2, 0.0, 5.0); + qualityCuts->AddCut(VarManager::kTPCncls, 60, 161.); + qualityCuts->AddCut(VarManager::kTrackDCAz, -0.5, 0.5); + + AnalysisCut* pidCuts = new AnalysisCut("pidCuts", "pid cuts"); + pidCuts->AddCut(VarManager::kTPCnSigmaEl, -2.5, 4.0, false, VarManager::kPin, 0.0, 5.0); + pidCuts->AddCut(VarManager::kTPCnSigmaEl, -1.5, 4.0, false, VarManager::kPin, 5.0, 1000.0); + pidCuts->AddCut(VarManager::kTPCnSigmaPi, 2.5, 999, false, VarManager::kPin, 0.0, 5.0); + pidCuts->AddCut(VarManager::kTPCnSigmaPr, 3.0, 999, false, VarManager::kPin, 0.0, 5.0); + + cut->AddCut(kineCut); + cut->AddCut(qualityCuts); + cut->AddCut(pidCuts); + return cut; + } + + if (!nameStr.compare("Electron2025_5")) { + AnalysisCut* kineCut = new AnalysisCut("kineCut", "kine cut"); + kineCut->AddCut(VarManager::kP, 1.0, 1000.0); + kineCut->AddCut(VarManager::kEta, -0.9, 0.9); + + AnalysisCut* qualityCuts = new AnalysisCut("qualityCuts", "quality cuts"); + qualityCuts->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + qualityCuts->AddCut(VarManager::kTPCchi2, 0.0, 5.0); + qualityCuts->AddCut(VarManager::kTPCncls, 60, 161.); + qualityCuts->AddCut(VarManager::kTrackDCAz, -0.5, 0.5); + + AnalysisCut* pidCuts = new AnalysisCut("pidCuts", "pid cuts"); + pidCuts->AddCut(VarManager::kTPCnSigmaEl, -2.25, 4.0, false, VarManager::kPin, 0.0, 5.0); + pidCuts->AddCut(VarManager::kTPCnSigmaEl, -1.5, 4.0, false, VarManager::kPin, 5.0, 1000.0); + pidCuts->AddCut(VarManager::kTPCnSigmaPi, 2.5, 999, false, VarManager::kPin, 0.0, 5.0); + pidCuts->AddCut(VarManager::kTPCnSigmaPr, 3.0, 999, false, VarManager::kPin, 0.0, 5.0); + + cut->AddCut(kineCut); + cut->AddCut(qualityCuts); + cut->AddCut(pidCuts); + return cut; + } + + if (!nameStr.compare("LowMassElectron2023")) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut("LooseGlobalTrackRun3")); + cut->AddCut(GetAnalysisCut("lmee_pp_502TeV_TOFloose_pionrej")); + return cut; + } + if (!nameStr.compare("MuonLow2022")) { cut->AddCut(GetAnalysisCut("muonLowPt2")); cut->AddCut(GetAnalysisCut("muonQualityCuts")); - cut->AddCut(GetAnalysisCut("MCHMID")); return cut; } if (!nameStr.compare("MuonHigh2022")) { @@ -72,12 +182,29 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) cut->AddCut(GetAnalysisCut("muonQualityCuts")); return cut; } + if (!nameStr.compare("MuonLow2023")) { + cut->AddCut(GetAnalysisCut("muonLowPt2")); + cut->AddCut(GetAnalysisCut("muonQualityCuts10SigmaPDCA")); + cut->AddCut(GetAnalysisCut("MCHMID")); + return cut; + } if (!nameStr.compare("MuonHigh2023")) { cut->AddCut(GetAnalysisCut("muonHighPt6")); cut->AddCut(GetAnalysisCut("muonQualityCuts")); cut->AddCut(GetAnalysisCut("MCHMID")); return cut; } + if (!nameStr.compare("ElectronForEMu")) { + cut->AddCut(GetAnalysisCut("jpsiKineSkimmed")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaLoose")); + return cut; + } + if (!nameStr.compare("MuonForEMu")) { + cut->AddCut(GetAnalysisCut("muonLowPt5")); + cut->AddCut(GetAnalysisCut("muonQualityCuts")); + return cut; + } // /////////////////////////////////////////////// // End of Cuts for CEFP // // /////////////////////////////////////////////// @@ -140,6 +267,21 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) cut->AddCut(GetAnalysisCut("electronPIDnsigmaMedium")); return cut; } + if (!nameStr.compare("electronSelection1_ionut_withTOFPID")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaMedium_withLargeTOFPID")); + return cut; + } + if (!nameStr.compare("electronSelection1_idstoreh")) { // same as electronSelection1_ionut, but with kIsSPDAny -> kIsITSibAny + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaMedium")); + return cut; + } + if (!nameStr.compare("electronSelection1pos_ionut")) { cut->AddCut(GetAnalysisCut("posTrack")); cut->AddCut(GetAnalysisCut("jpsiStandardKine")); @@ -358,6 +500,50 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("JpsiPWGSkimmedCuts3")) { + cut->AddCut(GetAnalysisCut("jpsiKineSkimmed")); + cut->AddCut(GetAnalysisCut("electronTrackQualitySkimmed2")); + cut->AddCut(GetAnalysisCut("electronPIDLooseSkimmed2")); + return cut; + } + + if (!nameStr.compare("JpsiPWGSkimmedCuts4")) { + cut->AddCut(GetAnalysisCut("jpsiKineSkimmed")); + cut->AddCut(GetAnalysisCut("electronTrackQualitySkimmed2")); + cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug9")); // loose cut + return cut; + } + + if (!nameStr.compare("JpsiPWGSkimmedCuts5")) { + cut->AddCut(GetAnalysisCut("electronTrackQualitySkimmed3")); + cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug8")); + return cut; + } + + if (!nameStr.compare("pidElectron_ionut")) { + cut->AddCut(GetAnalysisCut("pidcalib_ele")); + cut->AddCut(GetAnalysisCut("jpsiStandardKine3")); + return cut; + } + + if (!nameStr.compare("pidElectron_ionut_posEta")) { + cut->AddCut(GetAnalysisCut("pidcalib_ele")); + cut->AddCut(GetAnalysisCut("jpsiPIDcalibKine_posEta")); + return cut; + } + + if (!nameStr.compare("pidElectron_ionut_negEta")) { + cut->AddCut(GetAnalysisCut("pidcalib_ele")); + cut->AddCut(GetAnalysisCut("jpsiPIDcalibKine_negEta")); + return cut; + } + + if (!nameStr.compare("pidPion_ionut")) { + cut->AddCut(GetAnalysisCut("pidcalib_pion")); + cut->AddCut(GetAnalysisCut("jpsiStandardKine3")); + return cut; + } + if (!nameStr.compare("jpsiO2MCdebugCuts13_Corr")) { cut->AddCut(GetAnalysisCut("jpsiStandardKine")); cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); // no cut on ITS clusters @@ -381,6 +567,36 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("emu_electronCuts")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaSkewed")); + return cut; + } + + if (!nameStr.compare("emu_electronCuts_tof")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaSkewed")); + cut->AddCut(GetAnalysisCut("tof_electron_sigma_2")); + return cut; + } + + if (!nameStr.compare("emu_electronCuts_tightTPC")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaSkewed_2")); + return cut; + } + + if (!nameStr.compare("emu_electronCuts_tof_tightTPC")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaSkewed_2")); + cut->AddCut(GetAnalysisCut("tof_electron_sigma_2")); + return cut; + } + if (!nameStr.compare("jpsiKineAndQuality")) { cut->AddCut(GetAnalysisCut("jpsiStandardKine")); cut->AddCut(GetAnalysisCut("electronStandardQuality")); @@ -418,6 +634,12 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("pionPIDCut2")) { + cut->AddCut(GetAnalysisCut("pionQualityCut2")); + cut->AddCut(GetAnalysisCut("pionPIDnsigma")); + return cut; + } + if (!nameStr.compare("PIDCalibElectron")) { cut->AddCut(GetAnalysisCut("pidcalib_ele")); return cut; @@ -503,6 +725,40 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("singleGapTrackCuts3")) { + cut->AddCut(GetAnalysisCut("PIDStandardKine2")); + cut->AddCut(GetAnalysisCut("SPDany")); + + AnalysisCompositeCut* cut_notpc = new AnalysisCompositeCut("NoTPC", "NoTPC", kTRUE); + cut_notpc->AddCut(GetAnalysisCut("noTPC")); + + AnalysisCompositeCut* cut_tpcpid = new AnalysisCompositeCut("pid_TPC", "pid_TPC", kTRUE); + cut_tpcpid->AddCut(GetAnalysisCut("pionQuality")); + + AnalysisCompositeCut* cut_OR = new AnalysisCompositeCut("OR", "OR", kFALSE); + cut_OR->AddCut(cut_notpc); + cut_OR->AddCut(cut_tpcpid); + cut->AddCut(cut_OR); + return cut; + } + + if (!nameStr.compare("singleGapTrackCuts4")) { + cut->AddCut(GetAnalysisCut("PIDStandardKine2")); + cut->AddCut(GetAnalysisCut("ITSibany")); + + AnalysisCompositeCut* cut_notpc = new AnalysisCompositeCut("NoTPC", "NoTPC", kTRUE); + cut_notpc->AddCut(GetAnalysisCut("noTPC")); + + AnalysisCompositeCut* cut_tpcpid = new AnalysisCompositeCut("pid_TPC", "pid_TPC", kTRUE); + cut_tpcpid->AddCut(GetAnalysisCut("pionQuality")); + + AnalysisCompositeCut* cut_OR = new AnalysisCompositeCut("OR", "OR", kFALSE); + cut_OR->AddCut(cut_notpc); + cut_OR->AddCut(cut_tpcpid); + cut->AddCut(cut_OR); + return cut; + } + if (!nameStr.compare("PIDCalib")) { cut->AddCut(GetAnalysisCut("PIDStandardKine")); // standard kine cuts usually are applied via Filter in the task cut->AddCut(GetAnalysisCut("electronStandardQuality")); @@ -512,9 +768,9 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) } if (!nameStr.compare("NoPID")) { - cut->AddCut(GetAnalysisCut("PIDStandardKine")); // standard kine cuts usually are applied via Filter in the task - cut->AddCut(GetAnalysisCut("electronStandardQuality")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + cut->AddCut(GetAnalysisCut("PIDStandardKine2")); // standard kine cuts usually are applied via Filter in the task + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly2")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); return cut; } @@ -523,6 +779,16 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("KineCutOnly2")) { + cut->AddCut(GetAnalysisCut("PIDStandardKine2")); // standard kine cuts usually are applied via Filter in the task + return cut; + } + + if (!nameStr.compare("KineCutOnly3")) { + cut->AddCut(GetAnalysisCut("PIDStandardKine3")); // standard kine cuts usually are applied via Filter in the task + return cut; + } + if (!nameStr.compare("kaonPID")) { cut->AddCut(GetAnalysisCut("PIDStandardKine")); // standard kine cuts usually are applied via Filter in the task cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug")); @@ -543,395 +809,828 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) cut->AddCut(GetAnalysisCut("kaonPID_TPCnTOF")); return cut; } - // NOTE Below there are several TPC pid cuts used for studies of the Run3 TPC post PID calib. - if (!nameStr.compare("Jpsi_TPCPost_calib_debug1")) { - cut->AddCut(GetAnalysisCut("jpsi_trackCut_debug")); - cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug1")); + + if (!nameStr.compare("kaonPID3_withDCA")) { // same as kaonPID3 but with cut on DCA and SPDAny->ITSAny + cut->AddCut(GetAnalysisCut("AssocKine")); // standard kine cuts usually are applied via Filter in the task + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); + cut->AddCut(GetAnalysisCut("kaonPID_TPCnTOF")); return cut; } - if (!nameStr.compare("Jpsi_TPCPost_calib_debug2")) { - cut->AddCut(GetAnalysisCut("jpsi_trackCut_debug")); - cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug2")); + + if (!nameStr.compare("kaonPID4")) { + cut->AddCut(GetAnalysisCut("kaonPID_TPCnTOF")); return cut; } - if (!nameStr.compare("Jpsi_TPCPost_calib_noITSCuts_debug2")) { - cut->AddCut(GetAnalysisCut("jpsi_trackCut_noITSCuts_debug")); - cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug2")); + + if (!nameStr.compare("kaonPID5")) { + cut->AddCut(GetAnalysisCut("kaonPIDnsigma")); return cut; } - if (!nameStr.compare("Jpsi_TPCPost_calib_debug3")) { - cut->AddCut(GetAnalysisCut("jpsi_trackCut_debug")); - cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug3")); + + if (!nameStr.compare("kaonPID6")) { + cut->AddCut(GetAnalysisCut("kaonPIDnsigma700")); return cut; } - if (!nameStr.compare("Jpsi_TPCPost_calib_debug4")) { - cut->AddCut(GetAnalysisCut("jpsi_trackCut_debug")); - cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug4")); + + if (!nameStr.compare("kaonPIDTPCTOForTPC")) { + AnalysisCompositeCut* cut_tpctof_nSigma = new AnalysisCompositeCut("pid_TPCTOFnSigma", "pid_TPCTOFnSigma", kTRUE); + cut_tpctof_nSigma->AddCut(GetAnalysisCut("hasTOF")); + cut_tpctof_nSigma->AddCut(GetAnalysisCut("kaonPID_TPCnTOF")); + + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut("noTOF")); + cut_tpc_nSigma->AddCut(GetAnalysisCut("kaonPIDnsigma")); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("kaon_nsigma", "kaon_nsigma", kFALSE); + cut_pid_OR->AddCut(cut_tpctof_nSigma); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut->AddCut(cut_pid_OR); return cut; } - if (!nameStr.compare("Jpsi_TPCPost_calib_noITSCuts_debug4")) { - cut->AddCut(GetAnalysisCut("jpsi_trackCut_noITSCuts_debug")); - cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug4")); + + if (!nameStr.compare("kaonPIDTPCTOForTPC700")) { + AnalysisCompositeCut* cut_tpctof_nSigma = new AnalysisCompositeCut("pid_TPCTOFnSigma", "pid_TPCTOFnSigma", kTRUE); + cut_tpctof_nSigma->AddCut(GetAnalysisCut("hasTOF")); + cut_tpctof_nSigma->AddCut(GetAnalysisCut("kaonPID_TPCnTOF")); + + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut("noTOF")); + cut_tpc_nSigma->AddCut(GetAnalysisCut("kaonPIDnsigma700")); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("kaon_nsigma", "kaon_nsigma", kFALSE); + cut_pid_OR->AddCut(cut_tpctof_nSigma); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut->AddCut(cut_pid_OR); return cut; } - if (!nameStr.compare("Jpsi_TPCPost_calib_debug6")) { - cut->AddCut(GetAnalysisCut("jpsi_trackCut_debug2")); - cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug6")); + if (!nameStr.compare("kaonPosPID4")) { + cut->AddCut(GetAnalysisCut("kaonPID_TPCnTOF")); + cut->AddCut(GetAnalysisCut("posTrack")); return cut; } - if (!nameStr.compare("Jpsi_TPCPost_calib_debug7")) { - cut->AddCut(GetAnalysisCut("jpsi_trackCut_debug2")); - cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug7")); + if (!nameStr.compare("kaonPosPID4Pt05")) { + cut->AddCut(GetAnalysisCut("kaonPID_TPCnTOF")); + cut->AddCut(GetAnalysisCut("posTrack")); + cut->AddCut(GetAnalysisCut("muonLowPt")); return cut; } - if (!nameStr.compare("LMee_TPCPost_calib_debug1")) { - cut->AddCut(GetAnalysisCut("lmee_trackCut_debug")); - cut->AddCut(GetAnalysisCut("lmee_TPCPID_debug1")); + if (!nameStr.compare("kaonNegPID4")) { + cut->AddCut(GetAnalysisCut("kaonPID_TPCnTOF")); + cut->AddCut(GetAnalysisCut("negTrack")); return cut; } - if (!nameStr.compare("ITSalone_prefilter")) { - cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + if (!nameStr.compare("kaonNegPID4Pt05")) { + cut->AddCut(GetAnalysisCut("kaonPID_TPCnTOF")); + cut->AddCut(GetAnalysisCut("negTrack")); + cut->AddCut(GetAnalysisCut("muonLowPt")); return cut; } - if (!nameStr.compare("ITSalonebAny_prefilter")) { - cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualitybAnyITSOnly")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + if (!nameStr.compare("pionPID")) { + cut->AddCut(GetAnalysisCut("pionPID_TPCnTOF")); return cut; } - if (!nameStr.compare("TPCalone_prefilter")) { - cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + if (!nameStr.compare("pionPID2")) { + cut->AddCut(GetAnalysisCut("pionPIDnsigma")); return cut; } - if (!nameStr.compare("ITSTPC_prefilter")) { - cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + if (!nameStr.compare("pionPIDTPCTOForTPC")) { + AnalysisCompositeCut* cut_tpctof_nSigma = new AnalysisCompositeCut("pid_TPCTOFnSigma", "pid_TPCTOFnSigma", kTRUE); + cut_tpctof_nSigma->AddCut(GetAnalysisCut("pionPID_TPCnTOF")); + + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut("pionPIDnsigma")); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("pion_nsigma", "pion_nsigma", kFALSE); + cut_pid_OR->AddCut(cut_tpctof_nSigma); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut->AddCut(cut_pid_OR); return cut; } - //--------------------------------------------------------------- - // Cuts for the selection of legs from dalitz decay - // - if (!nameStr.compare("DalitzCut1")) { - cut->AddCut(GetAnalysisCut("dalitzStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut->AddCut(GetAnalysisCut("electronPIDOnly")); + if (!nameStr.compare("pionPosPID")) { + cut->AddCut(GetAnalysisCut("pionPID_TPCnTOF")); + cut->AddCut(GetAnalysisCut("posTrack")); return cut; } - if (!nameStr.compare("DalitzCut2")) { - cut->AddCut(GetAnalysisCut("dalitzStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut->AddCut(GetAnalysisCut("electronPIDPrKaPiRej")); + if (!nameStr.compare("pionPosPID2")) { + cut->AddCut(GetAnalysisCut("pionPIDnsigma")); + cut->AddCut(GetAnalysisCut("posTrack")); return cut; } - if (!nameStr.compare("DalitzCut2_Corr")) { - cut->AddCut(GetAnalysisCut("dalitzStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut->AddCut(GetAnalysisCut("electronPIDPrKaPiRej_Corr")); + if (!nameStr.compare("pionNegPID")) { + cut->AddCut(GetAnalysisCut("pionPID_TPCnTOF")); + cut->AddCut(GetAnalysisCut("negTrack")); return cut; } - if (!nameStr.compare("DalitzCut3")) { - cut->AddCut(GetAnalysisCut("dalitzStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut->AddCut(GetAnalysisCut("electronPIDPrKaPiRejLoose")); + if (!nameStr.compare("pionNegPID2")) { + cut->AddCut(GetAnalysisCut("pionPIDnsigma")); + cut->AddCut(GetAnalysisCut("negTrack")); return cut; } - if (!nameStr.compare("DalitzCut3_Corr")) { - cut->AddCut(GetAnalysisCut("dalitzStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut->AddCut(GetAnalysisCut("electronPIDPrKaPiRejLoose_Corr")); + if (!nameStr.compare("protonPosPID")) { + cut->AddCut(GetAnalysisCut("protonPID_TPCnTOF")); + cut->AddCut(GetAnalysisCut("posTrack")); return cut; } - if (!nameStr.compare("DalitzCut1SPDfirst")) { - cut->AddCut(GetAnalysisCut("dalitzStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut->AddCut(GetAnalysisCut("SPDfirst")); - cut->AddCut(GetAnalysisCut("electronPIDOnly")); + if (!nameStr.compare("protonPosPIDPt05")) { + cut->AddCut(GetAnalysisCut("protonPID_TPCnTOF")); + cut->AddCut(GetAnalysisCut("posTrack")); + cut->AddCut(GetAnalysisCut("muonLowPt")); return cut; } - if (!nameStr.compare("DalitzCut1SPDfirst_Corr")) { - cut->AddCut(GetAnalysisCut("dalitzStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut->AddCut(GetAnalysisCut("SPDfirst")); - cut->AddCut(GetAnalysisCut("electronPIDOnly_Corr")); + if (!nameStr.compare("protonNegPID")) { + cut->AddCut(GetAnalysisCut("protonPID_TPCnTOF")); + cut->AddCut(GetAnalysisCut("negTrack")); return cut; } - if (!nameStr.compare("DalitzCut2SPDfirst")) { - cut->AddCut(GetAnalysisCut("dalitzStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut->AddCut(GetAnalysisCut("SPDfirst")); - cut->AddCut(GetAnalysisCut("electronPIDPrKaPiRej")); + if (!nameStr.compare("protonNegPIDPt05")) { + cut->AddCut(GetAnalysisCut("protonPID_TPCnTOF")); + cut->AddCut(GetAnalysisCut("negTrack")); + cut->AddCut(GetAnalysisCut("muonLowPt")); return cut; } - if (!nameStr.compare("DalitzCut2SPDfirst_Corr")) { - cut->AddCut(GetAnalysisCut("dalitzStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut->AddCut(GetAnalysisCut("SPDfirst")); - cut->AddCut(GetAnalysisCut("electronPIDPrKaPiRej_Corr")); + if (!nameStr.compare("protonPIDPV")) { + cut->AddCut(GetAnalysisCut("protonPID_TPCnTOF2")); + cut->AddCut(GetAnalysisCut("protonPVcut")); return cut; } - if (!nameStr.compare("DalitzCut3SPDfirst")) { - cut->AddCut(GetAnalysisCut("dalitzStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut->AddCut(GetAnalysisCut("SPDfirst")); - cut->AddCut(GetAnalysisCut("electronPIDPrKaPiRejLoose")); + if (!nameStr.compare("protonPIDPV2")) { + cut->AddCut(GetAnalysisCut("protonPID_TPCnTOF2")); return cut; } - if (!nameStr.compare("DalitzCut3SPDfirst_Corr")) { - cut->AddCut(GetAnalysisCut("dalitzStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut->AddCut(GetAnalysisCut("SPDfirst")); - cut->AddCut(GetAnalysisCut("electronPIDPrKaPiRejLoose_Corr")); + if (!nameStr.compare("PrimaryTrack_DCAz")) { + cut->AddCut(GetAnalysisCut("PrimaryTrack_DCAz")); return cut; } - if (!nameStr.compare("Dalitz_WithTOF_SPDfirst")) { - cut->AddCut(GetAnalysisCut("dalitzStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut->AddCut(GetAnalysisCut("SPDfirst")); - - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut("electronPIDPrKaPiRejLoose")); - - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut("electronPID_TOFnsigma")); - - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); + if (!nameStr.compare("posPrimaryTrack_DCAz")) { + cut->AddCut(GetAnalysisCut("PrimaryTrack_DCAz")); + cut->AddCut(GetAnalysisCut("posTrack")); return cut; } - if (!nameStr.compare("Dalitz_WithTOF_SPDfirst_Corr")) { - cut->AddCut(GetAnalysisCut("dalitzStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut->AddCut(GetAnalysisCut("SPDfirst")); - - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut("electronPIDPrKaPiRejLoose_Corr")); - - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut("electronPID_TOFnsigma_Corr")); - - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); + if (!nameStr.compare("negPrimaryTrack_DCAz")) { + cut->AddCut(GetAnalysisCut("PrimaryTrack_DCAz")); + cut->AddCut(GetAnalysisCut("negTrack")); return cut; } - for (int i = 1; i <= 8; i++) { - if (!nameStr.compare(Form("dalitzSelected%d", i))) { - cut->AddCut(GetAnalysisCut(Form("dalitzLeg%d", i))); - return cut; - } + if (!nameStr.compare("posStandardPrimaryTrackDCA")) { + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCA")); + cut->AddCut(GetAnalysisCut("posTrack")); + return cut; } - //--------------------------------------------------------------------------------------- - // NOTE: Below there are several TPC pid cuts used for studies of the dE/dx degradation - // and its impact on the high lumi pp quarkonia triggers - // To be removed when not needed anymore - if (!nameStr.compare("jpsiPID1Randomized")) { - cut->AddCut(GetAnalysisCut("jpsiStandardKine")); // standard kine cuts usually are applied via Filter in the task - cut->AddCut(GetAnalysisCut("electronStandardQuality")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); - cut->AddCut(GetAnalysisCut("electronPID1randomized")); + if (!nameStr.compare("negStandardPrimaryTrackDCA")) { + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCA")); + cut->AddCut(GetAnalysisCut("negTrack")); return cut; } - if (!nameStr.compare("jpsiPID2Randomized")) { - cut->AddCut(GetAnalysisCut("jpsiStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQuality")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); - cut->AddCut(GetAnalysisCut("electronPID2randomized")); + if (!nameStr.compare("posTrack")) { + cut->AddCut(GetAnalysisCut("posTrack")); return cut; } - if (!nameStr.compare("jpsiPIDnsigmaRandomized")) { - cut->AddCut(GetAnalysisCut("jpsiStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQuality")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); - cut->AddCut(GetAnalysisCut("electronPIDnsigmaRandomized")); + if (!nameStr.compare("negTrack")) { + cut->AddCut(GetAnalysisCut("negTrack")); return cut; } - if (!nameStr.compare("jpsiPIDworseRes")) { - cut->AddCut(GetAnalysisCut("jpsiStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQuality")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); - cut->AddCut(GetAnalysisCut("electronPIDworseRes")); + if (!nameStr.compare("posTrackKaonRej")) { + cut->AddCut(GetAnalysisCut("posTrack")); + cut->AddCut(GetAnalysisCut("kaonRejNsigma")); return cut; } - if (!nameStr.compare("jpsiPIDshift")) { - cut->AddCut(GetAnalysisCut("jpsiStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQuality")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); - cut->AddCut(GetAnalysisCut("electronPIDshift")); + if (!nameStr.compare("negTrackKaonRej")) { + cut->AddCut(GetAnalysisCut("negTrack")); + cut->AddCut(GetAnalysisCut("kaonRejNsigma")); return cut; } - if (!nameStr.compare("jpsiPID1shiftUp")) { - cut->AddCut(GetAnalysisCut("jpsiStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQuality")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); - cut->AddCut(GetAnalysisCut("electronPID1shiftUp")); + if (!nameStr.compare("pTLow05")) { + cut->AddCut(GetAnalysisCut("muonLowPt")); return cut; } - if (!nameStr.compare("jpsiPID1shiftDown")) { - cut->AddCut(GetAnalysisCut("jpsiStandardKine")); - cut->AddCut(GetAnalysisCut("electronStandardQuality")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); - cut->AddCut(GetAnalysisCut("electronPID1shiftDown")); + if (!nameStr.compare("pTLow04")) { + cut->AddCut(GetAnalysisCut("pTLow04")); return cut; } - // ------------------------------------------------------------------------------------------------- - // - // LMee cuts - // List of cuts used for low mass dielectron analyses - // - // Skimming cuts: - if (!nameStr.compare("lmee_skimming")) { - cut->AddCut(GetAnalysisCut("lmee_skimming_cuts")); + + if (!nameStr.compare("pTLow03")) { + cut->AddCut(GetAnalysisCut("pTLow03")); return cut; } - // LMee Run2 PID cuts - - if (!nameStr.compare("lmeePID_TPChadrejTOFrec")) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrack")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); - - AnalysisCompositeCut* cut_tpc_hadrej = new AnalysisCompositeCut("pid_TPChadrej", "pid_TPChadrej", kTRUE); - cut_tpc_hadrej->AddCut(GetAnalysisCut("tpc_electron")); - cut_tpc_hadrej->AddCut(GetAnalysisCut("tpc_pion_rejection")); - cut_tpc_hadrej->AddCut(GetAnalysisCut("tpc_kaon_rejection")); - cut_tpc_hadrej->AddCut(GetAnalysisCut("tpc_proton_rejection")); - - AnalysisCompositeCut* cut_tof_rec = new AnalysisCompositeCut("pid_tof_rec", "pid_tof_rec", kTRUE); - cut_tof_rec->AddCut(GetAnalysisCut("tpc_electron")); - cut_tof_rec->AddCut(GetAnalysisCut("tof_electron")); - - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("pid_TPChadrejTOFrec", "pid_TPChadrejTOFrec", kFALSE); - cut_pid_OR->AddCut(cut_tpc_hadrej); - cut_pid_OR->AddCut(cut_tof_rec); - cut->AddCut(cut_pid_OR); + if (!nameStr.compare("pTLow02")) { + cut->AddCut(GetAnalysisCut("pTLow02")); return cut; } - if (!nameStr.compare("lmeePID_TPChadrej")) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrack")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); - - AnalysisCompositeCut* cut_tpc_hadrej = new AnalysisCompositeCut("pid_TPChadrej", "pid_TPChadrej", kTRUE); - cut_tpc_hadrej->AddCut(GetAnalysisCut("tpc_electron")); - cut_tpc_hadrej->AddCut(GetAnalysisCut("tpc_pion_rejection")); - cut_tpc_hadrej->AddCut(GetAnalysisCut("tpc_kaon_rejection")); - cut_tpc_hadrej->AddCut(GetAnalysisCut("tpc_proton_rejection")); - cut->AddCut(cut_tpc_hadrej); + if (!nameStr.compare("pTLow05DCAzHigh03")) { + cut->AddCut(GetAnalysisCut("muonLowPt")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_DCAz")); return cut; } - if (!nameStr.compare("lmee_eNSigmaRun2")) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrack")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); - - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut("electronPID_TPCnsigma")); - - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut("electronPID_TOFnsigma")); - - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); + if (!nameStr.compare("pTLow04DCAzHigh03")) { + cut->AddCut(GetAnalysisCut("pTLow04")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_DCAz")); return cut; } - if (!nameStr.compare("lmeePID_TOFrec")) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrack")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); - - AnalysisCompositeCut* cut_tof_rec = new AnalysisCompositeCut("pid_tof_rec", "pid_tof_rec", kTRUE); - cut_tof_rec->AddCut(GetAnalysisCut("tpc_electron")); - cut_tof_rec->AddCut(GetAnalysisCut("tof_electron")); - - cut->AddCut(cut_tof_rec); + if (!nameStr.compare("pTLow03DCAzHigh03")) { + cut->AddCut(GetAnalysisCut("pTLow03")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_DCAz")); return cut; } - if (!nameStr.compare("lmee_GlobalTrackRun2")) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrack")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + // NOTE Below there are several TPC pid cuts used for studies of the Run3 TPC post PID calib. + if (!nameStr.compare("Jpsi_TPCPost_calib_debug1")) { + cut->AddCut(GetAnalysisCut("jpsi_trackCut_debug")); + cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug1")); return cut; } - - if (!nameStr.compare("lmee_GlobalTrackRun2_lowPt")) { - cut->AddCut(GetAnalysisCut("lmeeLowBKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrack")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + if (!nameStr.compare("Jpsi_TPCPost_calib_debug2")) { + cut->AddCut(GetAnalysisCut("jpsi_trackCut_debug")); + cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug2")); return cut; } - - if (!nameStr.compare("lmee_TPCTrackRun2_lowPt")) { - cut->AddCut(GetAnalysisCut("lmeeLowBKine")); - cut->AddCut(GetAnalysisCut("TightTPCTrack")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + if (!nameStr.compare("Jpsi_TPCPost_calib_noITSCuts_debug2")) { + cut->AddCut(GetAnalysisCut("jpsi_trackCut_noITSCuts_debug")); + cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug2")); return cut; } - - if (!nameStr.compare("lmee_TPCTrackRun2")) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightTPCTrack")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + if (!nameStr.compare("Jpsi_TPCPost_calib_debug3")) { + cut->AddCut(GetAnalysisCut("jpsi_trackCut_debug")); + cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug3")); + return cut; + } + if (!nameStr.compare("Jpsi_TPCPost_calib_debug4")) { + cut->AddCut(GetAnalysisCut("jpsi_trackCut_debug")); + cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug4")); + return cut; + } + if (!nameStr.compare("Jpsi_TPCPost_calib_noITSCuts_debug4")) { + cut->AddCut(GetAnalysisCut("jpsi_trackCut_noITSCuts_debug")); + cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug4")); return cut; } - // LMee Run3 PID cuts + if (!nameStr.compare("Jpsi_TPCPost_calib_debug6")) { + cut->AddCut(GetAnalysisCut("jpsi_trackCut_debug2")); + cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug6")); + return cut; + } + + if (!nameStr.compare("Jpsi_TPCPost_calib_debug7")) { + cut->AddCut(GetAnalysisCut("jpsi_trackCut_debug2")); + cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug7")); + return cut; + } + + if (!nameStr.compare("Jpsi_TPCPost_calib_debug8")) { + cut->AddCut(GetAnalysisCut("jpsi_trackCut_debug5")); + cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug8")); + return cut; + } + + if (!nameStr.compare("Jpsi_TPCPost_calib_debug9")) { + cut->AddCut(GetAnalysisCut("jpsi_trackCut_debug4")); + cut->AddCut(GetAnalysisCut("electronPIDLooseSkimmed3")); + return cut; + } + + if (!nameStr.compare("LMee_TPCPost_calib_debug1")) { + cut->AddCut(GetAnalysisCut("lmee_trackCut_debug")); + cut->AddCut(GetAnalysisCut("lmee_TPCPID_debug1")); + return cut; + } + + if (!nameStr.compare("ITSalone_prefilter")) { + cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + return cut; + } + + if (!nameStr.compare("ITSalonebAny_prefilter")) { + cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualitybAnyITSOnly")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + return cut; + } + + if (!nameStr.compare("TPCalone_prefilter")) { + cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + return cut; + } + + if (!nameStr.compare("ITSTPC_prefilter")) { + cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + return cut; + } + + for (int iCut = 0; iCut < 10; iCut++) { + if (!nameStr.compare(Form("jpsiEleSel%d_ionut", iCut))) { + cut->AddCut(GetAnalysisCut("kineJpsiEle_ionut")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); + cut->AddCut(GetAnalysisCut("trackQuality_ionut")); + cut->AddCut(GetAnalysisCut(Form("pidJpsiEle%d_ionut", iCut))); + return cut; + } + + if (!nameStr.compare(Form("jpsiEleSelTight%d_ionut", iCut))) { + cut->AddCut(GetAnalysisCut("kineJpsiEle_ionut")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); + cut->AddCut(GetAnalysisCut("trackQualityTight_ionut")); + cut->AddCut(GetAnalysisCut(Form("pidJpsiEle%d_ionut", iCut))); + return cut; + } + } + + // Magnus composite cuts ----------------------------------------------------------------------------------------------------------------- + + AnalysisCompositeCut* magnus_PID111 = new AnalysisCompositeCut("magnus_PID111", ""); + magnus_PID111->AddCut(GetAnalysisCut("pidJpsi_magnus_ele1")); + magnus_PID111->AddCut(GetAnalysisCut("pidJpsi_magnus_pion1")); + magnus_PID111->AddCut(GetAnalysisCut("pidJpsi_magnus_prot1")); + if (!nameStr.compare("MagnussOptimization111")) { + cut->AddCut(GetAnalysisCut("kineJpsiEle_ionut")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); + cut->AddCut(GetAnalysisCut("trackQuality_ionut")); + cut->AddCut(magnus_PID111); + return cut; + } + + AnalysisCompositeCut* magnus_PID211 = new AnalysisCompositeCut("magnus_PID211", ""); + magnus_PID211->AddCut(GetAnalysisCut("pidJpsi_magnus_ele2")); + magnus_PID211->AddCut(GetAnalysisCut("pidJpsi_magnus_pion1")); + magnus_PID211->AddCut(GetAnalysisCut("pidJpsi_magnus_prot1")); + if (!nameStr.compare("MagnussOptimization211")) { + cut->AddCut(GetAnalysisCut("kineJpsiEle_ionut")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); + cut->AddCut(GetAnalysisCut("trackQuality_ionut")); + cut->AddCut(magnus_PID211); + return cut; + } + + AnalysisCompositeCut* magnus_PID311 = new AnalysisCompositeCut("magnus_PID311", ""); + magnus_PID311->AddCut(GetAnalysisCut("pidJpsi_magnus_ele3")); + magnus_PID311->AddCut(GetAnalysisCut("pidJpsi_magnus_pion1")); + magnus_PID311->AddCut(GetAnalysisCut("pidJpsi_magnus_prot1")); + if (!nameStr.compare("MagnussOptimization311")) { + cut->AddCut(GetAnalysisCut("kineJpsiEle_ionut")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); + cut->AddCut(GetAnalysisCut("trackQuality_ionut")); + cut->AddCut(magnus_PID311); + return cut; + } + + AnalysisCompositeCut* magnus_PID121 = new AnalysisCompositeCut("magnus_PID121", ""); + magnus_PID121->AddCut(GetAnalysisCut("pidJpsi_magnus_ele1")); + magnus_PID121->AddCut(GetAnalysisCut("pidJpsi_magnus_pion2")); + magnus_PID121->AddCut(GetAnalysisCut("pidJpsi_magnus_prot1")); + if (!nameStr.compare("MagnussOptimization121")) { + cut->AddCut(GetAnalysisCut("kineJpsiEle_ionut")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); + cut->AddCut(GetAnalysisCut("trackQuality_ionut")); + cut->AddCut(magnus_PID121); + return cut; + } + + AnalysisCompositeCut* magnus_PID112 = new AnalysisCompositeCut("magnus_PID112", ""); + magnus_PID112->AddCut(GetAnalysisCut("pidJpsi_magnus_ele1")); + magnus_PID112->AddCut(GetAnalysisCut("pidJpsi_magnus_pion1")); + magnus_PID112->AddCut(GetAnalysisCut("pidJpsi_magnus_prot2")); + if (!nameStr.compare("MagnussOptimization112")) { + cut->AddCut(GetAnalysisCut("kineJpsiEle_ionut")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); + cut->AddCut(GetAnalysisCut("trackQuality_ionut")); + cut->AddCut(magnus_PID112); + return cut; + } + + AnalysisCompositeCut* magnus_PID122 = new AnalysisCompositeCut("magnus_PID122", ""); + magnus_PID122->AddCut(GetAnalysisCut("pidJpsi_magnus_ele1")); + magnus_PID122->AddCut(GetAnalysisCut("pidJpsi_magnus_pion2")); + magnus_PID122->AddCut(GetAnalysisCut("pidJpsi_magnus_prot2")); + if (!nameStr.compare("MagnussOptimization122")) { + cut->AddCut(GetAnalysisCut("kineJpsiEle_ionut")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); + cut->AddCut(GetAnalysisCut("trackQuality_ionut")); + cut->AddCut(magnus_PID122); + return cut; + } + + AnalysisCompositeCut* magnus_PID222 = new AnalysisCompositeCut("magnus_PID222", ""); + magnus_PID222->AddCut(GetAnalysisCut("pidJpsi_magnus_ele2")); + magnus_PID222->AddCut(GetAnalysisCut("pidJpsi_magnus_pion2")); + magnus_PID222->AddCut(GetAnalysisCut("pidJpsi_magnus_prot2")); + if (!nameStr.compare("MagnussOptimization222")) { + cut->AddCut(GetAnalysisCut("kineJpsiEle_ionut")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); + cut->AddCut(GetAnalysisCut("trackQuality_ionut")); + cut->AddCut(magnus_PID222); + return cut; + } + + AnalysisCompositeCut* magnus_PID212 = new AnalysisCompositeCut("magnus_PID212", ""); + magnus_PID212->AddCut(GetAnalysisCut("pidJpsi_magnus_ele2")); + magnus_PID212->AddCut(GetAnalysisCut("pidJpsi_magnus_pion1")); + magnus_PID212->AddCut(GetAnalysisCut("pidJpsi_magnus_prot2")); + if (!nameStr.compare("MagnussOptimization212")) { + cut->AddCut(GetAnalysisCut("kineJpsiEle_ionut")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); + cut->AddCut(GetAnalysisCut("trackQuality_ionut")); + cut->AddCut(magnus_PID212); + return cut; + } + + AnalysisCompositeCut* magnus_PID221 = new AnalysisCompositeCut("magnus_PID221", ""); + magnus_PID221->AddCut(GetAnalysisCut("pidJpsi_magnus_ele2")); + magnus_PID221->AddCut(GetAnalysisCut("pidJpsi_magnus_pion2")); + magnus_PID221->AddCut(GetAnalysisCut("pidJpsi_magnus_prot1")); + if (!nameStr.compare("MagnussOptimization221")) { + cut->AddCut(GetAnalysisCut("kineJpsiEle_ionut")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); + cut->AddCut(GetAnalysisCut("trackQuality_ionut")); + cut->AddCut(magnus_PID221); + return cut; + } + + AnalysisCompositeCut* magnus_PID321 = new AnalysisCompositeCut("magnus_PID321", ""); + magnus_PID321->AddCut(GetAnalysisCut("pidJpsi_magnus_ele3")); + magnus_PID321->AddCut(GetAnalysisCut("pidJpsi_magnus_pion2")); + magnus_PID321->AddCut(GetAnalysisCut("pidJpsi_magnus_prot1")); + if (!nameStr.compare("MagnussOptimization321")) { + cut->AddCut(GetAnalysisCut("kineJpsiEle_ionut")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); + cut->AddCut(GetAnalysisCut("trackQuality_ionut")); + cut->AddCut(magnus_PID321); + return cut; + } + + AnalysisCompositeCut* magnus_PID312 = new AnalysisCompositeCut("magnus_PID312", ""); + magnus_PID312->AddCut(GetAnalysisCut("pidJpsi_magnus_ele3")); + magnus_PID312->AddCut(GetAnalysisCut("pidJpsi_magnus_pion1")); + magnus_PID312->AddCut(GetAnalysisCut("pidJpsi_magnus_prot2")); + if (!nameStr.compare("MagnussOptimization312")) { + cut->AddCut(GetAnalysisCut("kineJpsiEle_ionut")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); + cut->AddCut(GetAnalysisCut("trackQuality_ionut")); + cut->AddCut(magnus_PID312); + return cut; + } + + AnalysisCompositeCut* magnus_PID322 = new AnalysisCompositeCut("magnus_PID322", ""); + magnus_PID322->AddCut(GetAnalysisCut("pidJpsi_magnus_ele1")); + magnus_PID322->AddCut(GetAnalysisCut("pidJpsi_magnus_pion2")); + magnus_PID322->AddCut(GetAnalysisCut("pidJpsi_magnus_prot2")); + if (!nameStr.compare("MagnussOptimization322")) { + cut->AddCut(GetAnalysisCut("kineJpsiEle_ionut")); + cut->AddCut(GetAnalysisCut("dcaCut1_ionut")); + cut->AddCut(GetAnalysisCut("trackQuality_ionut")); + cut->AddCut(magnus_PID322); + return cut; + } + //------------------------------------------------------------------------------------------------------- + + //--------------------------------------------------------------- + // Cuts for the selection of legs from dalitz decay + // + if (!nameStr.compare("DalitzCut1")) { + cut->AddCut(GetAnalysisCut("dalitzStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut->AddCut(GetAnalysisCut("electronPIDOnly")); + return cut; + } + + if (!nameStr.compare("DalitzCut2")) { + cut->AddCut(GetAnalysisCut("dalitzStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut->AddCut(GetAnalysisCut("electronPIDPrKaPiRej")); + return cut; + } + + if (!nameStr.compare("DalitzCut2_Corr")) { + cut->AddCut(GetAnalysisCut("dalitzStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut->AddCut(GetAnalysisCut("electronPIDPrKaPiRej_Corr")); + return cut; + } + + if (!nameStr.compare("DalitzCut3")) { + cut->AddCut(GetAnalysisCut("dalitzStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut->AddCut(GetAnalysisCut("electronPIDPrKaPiRejLoose")); + return cut; + } + + if (!nameStr.compare("DalitzCut3_Corr")) { + cut->AddCut(GetAnalysisCut("dalitzStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut->AddCut(GetAnalysisCut("electronPIDPrKaPiRejLoose_Corr")); + return cut; + } + + if (!nameStr.compare("DalitzCut1SPDfirst")) { + cut->AddCut(GetAnalysisCut("dalitzStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut->AddCut(GetAnalysisCut("SPDfirst")); + cut->AddCut(GetAnalysisCut("electronPIDOnly")); + return cut; + } + + if (!nameStr.compare("DalitzCut1SPDfirst_Corr")) { + cut->AddCut(GetAnalysisCut("dalitzStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut->AddCut(GetAnalysisCut("SPDfirst")); + cut->AddCut(GetAnalysisCut("electronPIDOnly_Corr")); + return cut; + } + + if (!nameStr.compare("DalitzCut2SPDfirst")) { + cut->AddCut(GetAnalysisCut("dalitzStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut->AddCut(GetAnalysisCut("SPDfirst")); + cut->AddCut(GetAnalysisCut("electronPIDPrKaPiRej")); + return cut; + } + + if (!nameStr.compare("DalitzCut2SPDfirst_Corr")) { + cut->AddCut(GetAnalysisCut("dalitzStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut->AddCut(GetAnalysisCut("SPDfirst")); + cut->AddCut(GetAnalysisCut("electronPIDPrKaPiRej_Corr")); + return cut; + } + + if (!nameStr.compare("DalitzCut3SPDfirst")) { + cut->AddCut(GetAnalysisCut("dalitzStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut->AddCut(GetAnalysisCut("SPDfirst")); + cut->AddCut(GetAnalysisCut("electronPIDPrKaPiRejLoose")); + return cut; + } + + if (!nameStr.compare("DalitzCut3SPDfirst_Corr")) { + cut->AddCut(GetAnalysisCut("dalitzStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut->AddCut(GetAnalysisCut("SPDfirst")); + cut->AddCut(GetAnalysisCut("electronPIDPrKaPiRejLoose_Corr")); + return cut; + } + + if (!nameStr.compare("Dalitz_WithTOF_SPDfirst")) { + cut->AddCut(GetAnalysisCut("dalitzStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut->AddCut(GetAnalysisCut("SPDfirst")); + + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut("electronPIDPrKaPiRejLoose")); + + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut("electronPID_TOFnsigma")); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } + + if (!nameStr.compare("Dalitz_WithTOF_SPDfirst_Corr")) { + cut->AddCut(GetAnalysisCut("dalitzStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut->AddCut(GetAnalysisCut("SPDfirst")); + + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut("electronPIDPrKaPiRejLoose_Corr")); + + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut("electronPID_TOFnsigma_Corr")); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } + + for (int i = 1; i <= 8; i++) { + if (!nameStr.compare(Form("dalitzSelected%d", i))) { + cut->AddCut(GetAnalysisCut(Form("dalitzLeg%d", i))); + return cut; + } + } + + //--------------------------------------------------------------------------------------- + // NOTE: Below there are several TPC pid cuts used for studies of the dE/dx degradation + // and its impact on the high lumi pp quarkonia triggers + // To be removed when not needed anymore + if (!nameStr.compare("jpsiPID1Randomized")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); // standard kine cuts usually are applied via Filter in the task + cut->AddCut(GetAnalysisCut("electronStandardQuality")); + cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + cut->AddCut(GetAnalysisCut("electronPID1randomized")); + return cut; + } + + if (!nameStr.compare("jpsiPID2Randomized")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQuality")); + cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + cut->AddCut(GetAnalysisCut("electronPID2randomized")); + return cut; + } + + if (!nameStr.compare("jpsiPIDnsigmaRandomized")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQuality")); + cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaRandomized")); + return cut; + } + + if (!nameStr.compare("jpsiPIDworseRes")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQuality")); + cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + cut->AddCut(GetAnalysisCut("electronPIDworseRes")); + return cut; + } + + if (!nameStr.compare("jpsiPIDshift")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQuality")); + cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + cut->AddCut(GetAnalysisCut("electronPIDshift")); + return cut; + } + + if (!nameStr.compare("jpsiPID1shiftUp")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQuality")); + cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + cut->AddCut(GetAnalysisCut("electronPID1shiftUp")); + return cut; + } + + if (!nameStr.compare("jpsiPID1shiftDown")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQuality")); + cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + cut->AddCut(GetAnalysisCut("electronPID1shiftDown")); + return cut; + } + // ------------------------------------------------------------------------------------------------- + // + // LMee cuts + // List of cuts used for low mass dielectron analyses + // + // Skimming cuts: + if (!nameStr.compare("lmee_skimming")) { + cut->AddCut(GetAnalysisCut("lmee_skimming_cuts")); + return cut; + } + + // LMee Run2 PID cuts + + if (!nameStr.compare("lmeePID_TPChadrejTOFrec")) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut("TightGlobalTrack")); + cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + + AnalysisCompositeCut* cut_tpc_hadrej = new AnalysisCompositeCut("pid_TPChadrej", "pid_TPChadrej", kTRUE); + cut_tpc_hadrej->AddCut(GetAnalysisCut("tpc_electron")); + cut_tpc_hadrej->AddCut(GetAnalysisCut("tpc_pion_rejection")); + cut_tpc_hadrej->AddCut(GetAnalysisCut("tpc_kaon_rejection")); + cut_tpc_hadrej->AddCut(GetAnalysisCut("tpc_proton_rejection")); + + AnalysisCompositeCut* cut_tof_rec = new AnalysisCompositeCut("pid_tof_rec", "pid_tof_rec", kTRUE); + cut_tof_rec->AddCut(GetAnalysisCut("tpc_electron")); + cut_tof_rec->AddCut(GetAnalysisCut("tof_electron")); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("pid_TPChadrejTOFrec", "pid_TPChadrejTOFrec", kFALSE); + cut_pid_OR->AddCut(cut_tpc_hadrej); + cut_pid_OR->AddCut(cut_tof_rec); + cut->AddCut(cut_pid_OR); + return cut; + } + + if (!nameStr.compare("lmeePID_TPChadrej")) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut("TightGlobalTrack")); + cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + + AnalysisCompositeCut* cut_tpc_hadrej = new AnalysisCompositeCut("pid_TPChadrej", "pid_TPChadrej", kTRUE); + cut_tpc_hadrej->AddCut(GetAnalysisCut("tpc_electron")); + cut_tpc_hadrej->AddCut(GetAnalysisCut("tpc_pion_rejection")); + cut_tpc_hadrej->AddCut(GetAnalysisCut("tpc_kaon_rejection")); + cut_tpc_hadrej->AddCut(GetAnalysisCut("tpc_proton_rejection")); + cut->AddCut(cut_tpc_hadrej); + return cut; + } + + if (!nameStr.compare("lmee_eNSigmaRun2")) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut("TightGlobalTrack")); + cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut("electronPID_TPCnsigma")); + + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut("electronPID_TOFnsigma")); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } + + if (!nameStr.compare("lmeePID_TOFrec")) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut("TightGlobalTrack")); + cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + + AnalysisCompositeCut* cut_tof_rec = new AnalysisCompositeCut("pid_tof_rec", "pid_tof_rec", kTRUE); + cut_tof_rec->AddCut(GetAnalysisCut("tpc_electron")); + cut_tof_rec->AddCut(GetAnalysisCut("tof_electron")); + + cut->AddCut(cut_tof_rec); + return cut; + } + + if (!nameStr.compare("lmee_GlobalTrackRun2")) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut("TightGlobalTrack")); + cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + return cut; + } + + if (!nameStr.compare("lmee_GlobalTrackRun2_lowPt")) { + cut->AddCut(GetAnalysisCut("lmeeLowBKine")); + cut->AddCut(GetAnalysisCut("TightGlobalTrack")); + cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + return cut; + } + + if (!nameStr.compare("lmee_TPCTrackRun2_lowPt")) { + cut->AddCut(GetAnalysisCut("lmeeLowBKine")); + cut->AddCut(GetAnalysisCut("TightTPCTrack")); + cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + return cut; + } + + if (!nameStr.compare("lmee_TPCTrackRun2")) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut("TightTPCTrack")); + cut->AddCut(GetAnalysisCut("standardPrimaryTrack")); + return cut; + } + + // LMee Run3 PID cuts if (!nameStr.compare("lmeePID_TPChadrejTOFrecRun3")) { cut->AddCut(GetAnalysisCut("lmeeStandardKine")); @@ -1010,17 +1709,41 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) } std::vector vecTypetrack; - vecTypetrack.emplace_back(""); // default TightGlobalTrackRun3 - vecTypetrack.emplace_back("_7ITSncls"); // default TightGlobalTrackRun3 but with 7 ITS clusters - vecTypetrack.emplace_back("_ITS"); // Ask only for ITS requirements - vecTypetrack.emplace_back("_ITSalone"); // Ask only for ITS requirements + ITSalone (no TPC matching) - vecTypetrack.emplace_back("_TPC"); // Ask only for TPC requirements - vecTypetrack.emplace_back("_TPCalone"); // Ask only for TPC requirements + TPCalone (no ITS matching) - vecTypetrack.emplace_back("_TPCnoTRD"); // Ask only for TPC requirements no TRD matching - vecTypetrack.emplace_back("_TPCstrongncls"); // default TightGlobalTrackRun3 but with 130 TPC clusters + vecTypetrack.emplace_back(""); // default TightGlobalTrackRun3 + vecTypetrack.emplace_back("_7ITSncls"); // default TightGlobalTrackRun3 but with 7 ITS clusters + vecTypetrack.emplace_back("_ITS"); // Ask only for ITS requirements + vecTypetrack.emplace_back("_ITSalone"); // Ask only for ITS requirements + ITSalone (no TPC matching) + vecTypetrack.emplace_back("_TPC"); // Ask only for TPC requirements + vecTypetrack.emplace_back("_TPCalone"); // Ask only for TPC requirements + TPCalone (no ITS matching) + vecTypetrack.emplace_back("_TPCnoTRD"); // Ask only for TPC requirements no TRD matching + vecTypetrack.emplace_back("_TPCstrongncls"); // default TightGlobalTrackRun3 but with 130 TPC clusters + vecTypetrack.emplace_back("_ITSanyfirsttwo"); // default TightGlobalTrackRun3 but with a cluster in any of the first two layers + vecTypetrack.emplace_back("_ITSanyfirstthree"); // default TightGlobalTrackRun3 but with a cluster in any of the first three layers // loop to define PID cuts with and without post calibration for (size_t icase = 0; icase < vecTypetrack.size(); icase++) { + // Tracking cuts of Pb--Pb analysis + if (!nameStr.compare(Form("lmee%s_PbPb_selection", vecTypetrack.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrack.at(icase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + return cut; + } + + if (!nameStr.compare(Form("lmee%s_PbPb_selection_pt04", vecTypetrack.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine_pt04")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrack.at(icase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + return cut; + } + + if (!nameStr.compare(Form("lmee%s_TrackCuts_Resol", vecTypetrack.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("openEtaSel")); // No pt cut and wider eta cut to produce resolution maps + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrack.at(icase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + return cut; + } + // 4 cuts to separate pos & neg tracks in pos & neg eta range if (!nameStr.compare(Form("lmee_posTrack_posEta_selection%s", vecTypetrack.at(icase).Data()))) { cut->AddCut(GetAnalysisCut("posTrack")); @@ -1127,676 +1850,973 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) vecPIDcase.emplace_back("_Corr"); // case of using post calibrated PID spectra vecPIDcase.emplace_back("_CorrWithKaon"); // case of using post calibrated PID spectra with also the kaons - // loop to define PID cuts with and without post calibration - for (size_t icase = 0; icase < vecPIDcase.size(); icase++) { - if (!nameStr.compare(Form("ITSTPC_TPCPIDalone%s_PbPb", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - cut->AddCut(GetAnalysisCut(Form("electronPIDOnly%s", vecPIDcase.at(icase).Data()))); - return cut; - } - if (!nameStr.compare(Form("ITSTPC_TPCPID%s_prefilter", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); - cut->AddCut(GetAnalysisCut(Form("electronPIDOnly%s", vecPIDcase.at(icase).Data()))); - return cut; - } + std::vector vecTypetrackWithPID; + vecTypetrackWithPID.emplace_back(""); // default TightGlobalTrackRun3 + vecTypetrackWithPID.emplace_back("_7ITSncls"); // default TightGlobalTrackRun3 but with 7 ITS clusters + vecTypetrackWithPID.emplace_back("_TPCstrongncls"); // default TightGlobalTrackRun3 but with 130 TPC clusters + vecTypetrackWithPID.emplace_back("_ITSanyfirsttwo"); // default TightGlobalTrackRun3 but with a cluster in any of the first two layers + vecTypetrackWithPID.emplace_back("_ITSanyfirstthree"); // default TightGlobalTrackRun3 but with a cluster in any of the first three layers + + // loop to define PID cuts with and without post calibration + for (size_t icase = 0; icase < vecPIDcase.size(); icase++) { + if (!nameStr.compare(Form("lmee_onlyTPCPID%s", vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut(Form("electronPIDOnly%s", vecPIDcase.at(icase).Data()))); + return cut; + } + + if (!nameStr.compare(Form("ITSTPC_TPCPID%s_prefilter", vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + cut->AddCut(GetAnalysisCut(Form("electronPIDOnly%s", vecPIDcase.at(icase).Data()))); + return cut; + } + + if (!nameStr.compare(Form("ITS_ifTPC_TPCPID%s_prefilter", vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + + AnalysisCompositeCut* cut_notpc = new AnalysisCompositeCut("NoTPC", "NoTPC", kTRUE); + cut_notpc->AddCut(GetAnalysisCut("noTPC")); + + AnalysisCompositeCut* cut_tpcpid = new AnalysisCompositeCut("pid_TPC", "pid_TPC", kTRUE); + cut_tpcpid->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut_tpcpid->AddCut(GetAnalysisCut(Form("electronPIDOnly%s", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_OR = new AnalysisCompositeCut("OR", "OR", kFALSE); + cut_OR->AddCut(cut_notpc); + cut_OR->AddCut(cut_tpcpid); + cut->AddCut(cut_OR); + return cut; + } + + if (!nameStr.compare(Form("ITS_ifTPCStandard_TPCPID%s_prefilter", vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + + AnalysisCompositeCut* cut_notpcstandard = new AnalysisCompositeCut("NoTPCstandard", "NoTPCstandard", kTRUE); + cut_notpcstandard->AddCut(GetAnalysisCut("NoelectronStandardQualityTPCOnly")); + + AnalysisCompositeCut* cut_tpcpid = new AnalysisCompositeCut("pid_TPC", "pid_TPC", kTRUE); + cut_tpcpid->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut_tpcpid->AddCut(GetAnalysisCut(Form("electronPIDOnly%s", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_OR = new AnalysisCompositeCut("OR", "OR", kFALSE); + cut_OR->AddCut(cut_notpcstandard); + cut_OR->AddCut(cut_tpcpid); + cut->AddCut(cut_OR); + return cut; + } + + if (!nameStr.compare(Form("ITSTPCbAny_TPCPID%s_prefilter", vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualitybAnyITSOnly")); + cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + cut->AddCut(GetAnalysisCut(Form("electronPIDOnly%s", vecPIDcase.at(icase).Data()))); + return cut; + } + + if (!nameStr.compare(Form("ITSbAny_ifTPC_TPCPID%s_prefilter", vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualitybAnyITSOnly")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + + AnalysisCompositeCut* cut_notpc = new AnalysisCompositeCut("NoTPC", "NoTPC", kTRUE); + cut_notpc->AddCut(GetAnalysisCut("noTPC")); + + AnalysisCompositeCut* cut_tpcpid = new AnalysisCompositeCut("pid_TPC", "pid_TPC", kTRUE); + cut_tpcpid->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut_tpcpid->AddCut(GetAnalysisCut(Form("electronPIDOnly%s", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_OR = new AnalysisCompositeCut("OR", "OR", kFALSE); + cut_OR->AddCut(cut_notpc); + cut_OR->AddCut(cut_tpcpid); + cut->AddCut(cut_OR); + return cut; + } + + if (!nameStr.compare(Form("ITSbAny_ifTPCStandard_TPCPID%s_prefilter", vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualitybAnyITSOnly")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + + AnalysisCompositeCut* cut_notpcstandard = new AnalysisCompositeCut("NoTPCstandard", "NoTPCstandard", kTRUE); + cut_notpcstandard->AddCut(GetAnalysisCut("NoelectronStandardQualityTPCOnly")); + + AnalysisCompositeCut* cut_tpcpid = new AnalysisCompositeCut("pid_TPC", "pid_TPC", kTRUE); + cut_tpcpid->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); + cut_tpcpid->AddCut(GetAnalysisCut(Form("electronPIDOnly%s", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_OR = new AnalysisCompositeCut("OR", "OR", kFALSE); + cut_OR->AddCut(cut_notpcstandard); + cut_OR->AddCut(cut_tpcpid); + cut->AddCut(cut_OR); + return cut; + } + + for (unsigned int i = 0; i < 30; i++) { + if (!nameStr.compare(Form("ElSelCutVar%s%i", vecPIDcase.at(icase).Data(), i))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeCutVarTrackCuts%i", i))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma_cutVar%s%i", vecPIDcase.at(icase).Data(), i))); + + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma_cutVar%s%i", vecPIDcase.at(icase).Data(), i))); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } + } + + for (size_t jcase = 0; jcase < vecTypetrackWithPID.size(); jcase++) { + // All previous cut with TightGlobalTrackRun3 + if (!nameStr.compare(Form("ITSTPC%s_TPCPIDalone%s_PbPb", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + cut->AddCut(GetAnalysisCut(Form("electronPIDOnly%s", vecPIDcase.at(icase).Data()))); + return cut; + } + + if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_loose", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_loose", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_loose", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } + + if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } + + if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_strongHadRej", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongHadRej", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongHadRej", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } + + if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_strongNSigE", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } + + if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_strongNSigE_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } + + if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_TOFreq", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + cut->AddCut(GetAnalysisCut(Form("electronPID_TPC_TOFnsigma%s", vecPIDcase.at(icase).Data()))); + return cut; + } + + if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_Resol", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("openEtaSel")); // No pt cut and wider eta cut to produce resolution maps + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } + + if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_tightNSigEPbPb_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_tightNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - if (!nameStr.compare(Form("ITS_ifTPC_TPCPID%s_prefilter", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_tightNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_notpc = new AnalysisCompositeCut("NoTPC", "NoTPC", kTRUE); - cut_notpc->AddCut(GetAnalysisCut("noTPC")); + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - AnalysisCompositeCut* cut_tpcpid = new AnalysisCompositeCut("pid_TPC", "pid_TPC", kTRUE); - cut_tpcpid->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut_tpcpid->AddCut(GetAnalysisCut(Form("electronPIDOnly%s", vecPIDcase.at(icase).Data()))); + if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_strongNSigEPbPb_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - AnalysisCompositeCut* cut_OR = new AnalysisCompositeCut("OR", "OR", kFALSE); - cut_OR->AddCut(cut_notpc); - cut_OR->AddCut(cut_tpcpid); - cut->AddCut(cut_OR); - return cut; - } + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - if (!nameStr.compare(Form("ITS_ifTPCStandard_TPCPID%s_prefilter", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualityITSOnly")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_notpcstandard = new AnalysisCompositeCut("NoTPCstandard", "NoTPCstandard", kTRUE); - cut_notpcstandard->AddCut(GetAnalysisCut("NoelectronStandardQualityTPCOnly")); + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - AnalysisCompositeCut* cut_tpcpid = new AnalysisCompositeCut("pid_TPC", "pid_TPC", kTRUE); - cut_tpcpid->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut_tpcpid->AddCut(GetAnalysisCut(Form("electronPIDOnly%s", vecPIDcase.at(icase).Data()))); + if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_tightNSigEPbPb_rejBadTOF_pt04", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine_pt04")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - AnalysisCompositeCut* cut_OR = new AnalysisCompositeCut("OR", "OR", kFALSE); - cut_OR->AddCut(cut_notpcstandard); - cut_OR->AddCut(cut_tpcpid); - cut->AddCut(cut_OR); - return cut; - } + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_tightNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - if (!nameStr.compare(Form("ITSTPCbAny_TPCPID%s_prefilter", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualitybAnyITSOnly")); - cut->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); - cut->AddCut(GetAnalysisCut(Form("electronPIDOnly%s", vecPIDcase.at(icase).Data()))); - return cut; - } + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_tightNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - if (!nameStr.compare(Form("ITSbAny_ifTPC_TPCPID%s_prefilter", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualitybAnyITSOnly")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - AnalysisCompositeCut* cut_notpc = new AnalysisCompositeCut("NoTPC", "NoTPC", kTRUE); - cut_notpc->AddCut(GetAnalysisCut("noTPC")); + if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_strongNSigEPbPb_rejBadTOF_pt04", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine_pt04")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - AnalysisCompositeCut* cut_tpcpid = new AnalysisCompositeCut("pid_TPC", "pid_TPC", kTRUE); - cut_tpcpid->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut_tpcpid->AddCut(GetAnalysisCut(Form("electronPIDOnly%s", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_OR = new AnalysisCompositeCut("OR", "OR", kFALSE); - cut_OR->AddCut(cut_notpc); - cut_OR->AddCut(cut_tpcpid); - cut->AddCut(cut_OR); - return cut; - } + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - if (!nameStr.compare(Form("ITSbAny_ifTPCStandard_TPCPID%s_prefilter", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeePrefilterKine")); - cut->AddCut(GetAnalysisCut("electronStandardQualitybAnyITSOnly")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - AnalysisCompositeCut* cut_notpcstandard = new AnalysisCompositeCut("NoTPCstandard", "NoTPCstandard", kTRUE); - cut_notpcstandard->AddCut(GetAnalysisCut("NoelectronStandardQualityTPCOnly")); + if (!nameStr.compare(Form("lmee%s_lowB_eNSigmaRun3%s_strongNSigE", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeLowBKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); // to reject looper using DCAz - AnalysisCompositeCut* cut_tpcpid = new AnalysisCompositeCut("pid_TPC", "pid_TPC", kTRUE); - cut_tpcpid->AddCut(GetAnalysisCut("electronStandardQualityTPCOnly")); - cut_tpcpid->AddCut(GetAnalysisCut(Form("electronPIDOnly%s", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_OR = new AnalysisCompositeCut("OR", "OR", kFALSE); - cut_OR->AddCut(cut_notpcstandard); - cut_OR->AddCut(cut_tpcpid); - cut->AddCut(cut_OR); - return cut; - } + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - if (!nameStr.compare(Form("lmee_eNSigmaRun3%s_loose", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_loose", vecPIDcase.at(icase).Data()))); + if (!nameStr.compare(Form("lmee%s_lowB_eNSigmaRun3%s_strongNSigE_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeLowBKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); // to reject looper using DCAz - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_loose", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); - if (!nameStr.compare(Form("lmee_eNSigmaRun3%s", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s", vecPIDcase.at(icase).Data()))); + if (!nameStr.compare(Form("lmee%s_TOFreqRun3%s_strongNSigEPbPb_rejBadTOF_pt04", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine_pt04")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + cut->AddCut(GetAnalysisCut(Form("electronPID_TOFreq%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + return cut; + } - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s", vecPIDcase.at(icase).Data()))); + if (!nameStr.compare(Form("lmee%s_TOFreqRun3%s_tightNSigEPbPb_rejBadTOF_pt04", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine_pt04")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + cut->AddCut(GetAnalysisCut(Form("electronPID_TOFreq%s_tightNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + return cut; + } - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + // 8 cuts for QC + if (!nameStr.compare(Form("lmee%s_NSigmaRun3_posEta%s_strongNSigEPbPb_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("pt02Sel")); + cut->AddCut(GetAnalysisCut("posEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - if (!nameStr.compare(Form("lmee_eNSigmaRun3%s_strongTPC", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3_strongTPC")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + if (!nameStr.compare(Form("lmee%s_NSigmaRun3_negEta%s_strongNSigEPbPb_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("pt02Sel")); + cut->AddCut(GetAnalysisCut("negEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - if (!nameStr.compare(Form("lmee_eNSigmaRun3%s_strongHadRej", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongHadRej", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongHadRej", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + if (!nameStr.compare(Form("lmee%s_NSigmaRun3_posEta%s_strongNSigEPbPb_rejBadTOF_pt04", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("pt04Sel")); + cut->AddCut(GetAnalysisCut("posEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - if (!nameStr.compare(Form("lmee_eNSigmaRun3%s_strongNSigE", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + if (!nameStr.compare(Form("lmee%s_NSigmaRun3_negEta%s_strongNSigEPbPb_rejBadTOF_pt04", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("pt04Sel")); + cut->AddCut(GetAnalysisCut("negEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - if (!nameStr.compare(Form("lmee_lowB_eNSigmaRun3%s_strongNSigE", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeLowBKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); // to reject looper using DCAz + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + if (!nameStr.compare(Form("lmee%s_posNSigmaRun3_posEta%s_strongNSigEPbPb_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("posTrack")); + cut->AddCut(GetAnalysisCut("posEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - if (!nameStr.compare(Form("lmee_lowB_eNSigmaRun3%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeLowBKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); // to reject looper using DCAz + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + if (!nameStr.compare(Form("lmee%s_posNSigmaRun3_negEta%s_strongNSigEPbPb_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("posTrack")); + cut->AddCut(GetAnalysisCut("negEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - if (!nameStr.compare(Form("lmee_eNSigmaRun3%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + if (!nameStr.compare(Form("lmee%s_negNSigmaRun3_posEta%s_strongNSigEPbPb_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("negTrack")); + cut->AddCut(GetAnalysisCut("posEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - if (!nameStr.compare(Form("lmee_eNSigmaRun3%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + if (!nameStr.compare(Form("lmee%s_negNSigmaRun3_negEta%s_strongNSigEPbPb_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("negTrack")); + cut->AddCut(GetAnalysisCut("negEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - if (!nameStr.compare(Form("lmee_eNSigmaRun3%s_strongNSigEPbPb_rejBadTOF_pt04", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine_pt04")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + // 6 cuts for QC + if (!nameStr.compare(Form("lmee%s_posTOFreqRun3_posEta%s_strongNSigEPbPb_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("posTrack")); + cut->AddCut(GetAnalysisCut("posEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + cut->AddCut(GetAnalysisCut(Form("electronPID_TOFreq%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + return cut; + } - if (!nameStr.compare(Form("lmee_TOFreqRun3%s_strongNSigEPbPb_rejBadTOF_pt04", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine_pt04")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - cut->AddCut(GetAnalysisCut(Form("electronPID_TOFreq%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - return cut; - } + if (!nameStr.compare(Form("lmee%s_posTOFreqRun3_negEta%s_strongNSigEPbPb_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("posTrack")); + cut->AddCut(GetAnalysisCut("negEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + cut->AddCut(GetAnalysisCut(Form("electronPID_TOFreq%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + return cut; + } - // 4 cuts for QC - if (!nameStr.compare(Form("lmee_posNSigmaRun3_posEta%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("posTrack")); - cut->AddCut(GetAnalysisCut("posEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + if (!nameStr.compare(Form("lmee%s_TOFreqRun3_posEta%s_strongNSigEPbPb_rejBadTOF_pt04", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("pt04Sel")); + cut->AddCut(GetAnalysisCut("posEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + cut->AddCut(GetAnalysisCut(Form("electronPID_TOFreq%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + return cut; + } - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + if (!nameStr.compare(Form("lmee%s_TOFreqRun3_negEta%s_strongNSigEPbPb_rejBadTOF_pt04", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("pt04Sel")); + cut->AddCut(GetAnalysisCut("negEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + cut->AddCut(GetAnalysisCut(Form("electronPID_TOFreq%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + return cut; + } - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + if (!nameStr.compare(Form("lmee%s_negTOFreqRun3_posEta%s_strongNSigEPbPb_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("negTrack")); + cut->AddCut(GetAnalysisCut("posEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + cut->AddCut(GetAnalysisCut(Form("electronPID_TOFreq%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + return cut; + } - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + if (!nameStr.compare(Form("lmee%s_negTOFreqRun3_negEta%s_strongNSigEPbPb_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("negTrack")); + cut->AddCut(GetAnalysisCut("negEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + cut->AddCut(GetAnalysisCut(Form("electronPID_TOFreq%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + return cut; + } - if (!nameStr.compare(Form("lmee_posNSigmaRun3_negEta%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("posTrack")); - cut->AddCut(GetAnalysisCut("negEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_TPC_PID", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + cut->AddCut(cut_tpc_nSigma); + return cut; + } - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_TOF_PID", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); - if (!nameStr.compare(Form("lmee_negNSigmaRun3_posEta%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("negTrack")); - cut->AddCut(GetAnalysisCut("posEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + cut->AddCut(cut_tof_nSigma); + return cut; + } - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_strongNSigE_DCA05", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_DCA05")); - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - if (!nameStr.compare(Form("lmee_negNSigmaRun3_negEta%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("negTrack")); - cut->AddCut(GetAnalysisCut("negEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + // 4 cuts to separate pos & neg tracks in pos & neg eta range applying electron PID + if (!nameStr.compare(Form("lmee%s_posNSigmaRun3_posEta%s_strongNSigE", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("posTrack")); + cut->AddCut(GetAnalysisCut("posEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - // 4 cuts for QC - if (!nameStr.compare(Form("lmee_posTOFreqRun3_posEta%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("posTrack")); - cut->AddCut(GetAnalysisCut("posEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - cut->AddCut(GetAnalysisCut(Form("electronPID_TOFreq%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - return cut; - } + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - if (!nameStr.compare(Form("lmee_posTOFreqRun3_negEta%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("posTrack")); - cut->AddCut(GetAnalysisCut("negEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - cut->AddCut(GetAnalysisCut(Form("electronPID_TOFreq%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - return cut; - } + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - if (!nameStr.compare(Form("lmee_negTOFreqRun3_posEta%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("negTrack")); - cut->AddCut(GetAnalysisCut("posEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - cut->AddCut(GetAnalysisCut(Form("electronPID_TOFreq%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - return cut; - } + if (!nameStr.compare(Form("lmee%s_negNSigmaRun3_posEta%s_strongNSigE", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("negTrack")); + cut->AddCut(GetAnalysisCut("posEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); - if (!nameStr.compare(Form("lmee_negTOFreqRun3_negEta%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("negTrack")); - cut->AddCut(GetAnalysisCut("negEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - cut->AddCut(GetAnalysisCut(Form("electronPID_TOFreq%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); - return cut; - } + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - if (!nameStr.compare(Form("lmee_eNSigmaRun3%s_TPC_PID", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - cut->AddCut(cut_tpc_nSigma); - return cut; - } + if (!nameStr.compare(Form("lmee%s_posNSigmaRun3_negEta%s_strongNSigE", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("posTrack")); + cut->AddCut(GetAnalysisCut("negEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); - if (!nameStr.compare(Form("lmee_eNSigmaRun3%s_TOF_PID", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - cut->AddCut(cut_tof_nSigma); - return cut; - } + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - if (!nameStr.compare(Form("lmee_eNSigmaRun3%s_strongNSigE_DCA05", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_DCA05")); + if (!nameStr.compare(Form("lmee%s_negNSigmaRun3_negEta%s_strongNSigE", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("negTrack")); + cut->AddCut(GetAnalysisCut("negEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - // 4 cuts to separate pos & neg tracks in pos & neg eta range applying electron PID - if (!nameStr.compare(Form("lmee_posNSigmaRun3_posEta%s_strongNSigE", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("posTrack")); - cut->AddCut(GetAnalysisCut("posEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + // 4 cuts to separate pos & neg tracks in pos & neg eta range applying electron PID for low B field + if (!nameStr.compare(Form("lmee%s_lowB_posNSigmaRun3_posEta%s_strongNSigE", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("posTrack")); + cut->AddCut(GetAnalysisCut("posEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - if (!nameStr.compare(Form("lmee_negNSigmaRun3_posEta%s_strongNSigE", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("negTrack")); - cut->AddCut(GetAnalysisCut("posEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + if (!nameStr.compare(Form("lmee%s_lowB_negNSigmaRun3_posEta%s_strongNSigE", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("negTrack")); + cut->AddCut(GetAnalysisCut("posEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - if (!nameStr.compare(Form("lmee_posNSigmaRun3_negEta%s_strongNSigE", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("posTrack")); - cut->AddCut(GetAnalysisCut("negEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + if (!nameStr.compare(Form("lmee%s_lowB_posNSigmaRun3_negEta%s_strongNSigE", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("posTrack")); + cut->AddCut(GetAnalysisCut("negEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - if (!nameStr.compare(Form("lmee_negNSigmaRun3_negEta%s_strongNSigE", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("negTrack")); - cut->AddCut(GetAnalysisCut("negEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + if (!nameStr.compare(Form("lmee%s_lowB_negNSigmaRun3_negEta%s_strongNSigE", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("negTrack")); + cut->AddCut(GetAnalysisCut("negEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - // 4 cuts to separate pos & neg tracks in pos & neg eta range applying electron PID for low B field - if (!nameStr.compare(Form("lmee_lowB_posNSigmaRun3_posEta%s_strongNSigE", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("posTrack")); - cut->AddCut(GetAnalysisCut("posEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + // 4 cuts to separate pos & neg tracks in pos & neg eta range applying electron PID for low B field with bad TOF rejection + if (!nameStr.compare(Form("lmee%s_lowB_posNSigmaRun3_posEta%s_strongNSigE_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("posTrack")); + cut->AddCut(GetAnalysisCut("posEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - if (!nameStr.compare(Form("lmee_lowB_negNSigmaRun3_posEta%s_strongNSigE", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("negTrack")); - cut->AddCut(GetAnalysisCut("posEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + if (!nameStr.compare(Form("lmee%s_lowB_negNSigmaRun3_posEta%s_strongNSigE_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("negTrack")); + cut->AddCut(GetAnalysisCut("posEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - if (!nameStr.compare(Form("lmee_lowB_posNSigmaRun3_negEta%s_strongNSigE", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("posTrack")); - cut->AddCut(GetAnalysisCut("negEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + if (!nameStr.compare(Form("lmee%s_lowB_posNSigmaRun3_negEta%s_strongNSigE_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("posTrack")); + cut->AddCut(GetAnalysisCut("negEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - if (!nameStr.compare(Form("lmee_lowB_negNSigmaRun3_negEta%s_strongNSigE", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("negTrack")); - cut->AddCut(GetAnalysisCut("negEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + if (!nameStr.compare(Form("lmee%s_lowB_negNSigmaRun3_negEta%s_strongNSigE_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("negTrack")); + cut->AddCut(GetAnalysisCut("negEtaSel")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - // 4 cuts to separate pos & neg tracks in pos & neg eta range applying electron PID for low B field with bad TOF rejection - if (!nameStr.compare(Form("lmee_lowB_posNSigmaRun3_posEta%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("posTrack")); - cut->AddCut(GetAnalysisCut("posEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + // some older cuts + if (!nameStr.compare(Form("lmee%s_pp502TeV_PID%s", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("lmee_pp_502TeV_TPC%s", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("lmee_pp_502TeV_TOF%s", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - if (!nameStr.compare(Form("lmee_lowB_negNSigmaRun3_posEta%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("negTrack")); - cut->AddCut(GetAnalysisCut("posEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + for (int i = 1; i <= 8; i++) { + if (!nameStr.compare(Form("lmee%s_pp502TeV_PID%s_UsePrefilter%d", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data(), i))) { + cut->AddCut(GetAnalysisCut(Form("notDalitzLeg%d", i))); + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("lmee_pp_502TeV_TPC%s", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("lmee_pp_502TeV_TOF%s", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } + } - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); + if (!nameStr.compare(Form("lmee%s_pp502TeV_lowB_PID%s", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeLowBKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); // DCAz to reject loopers - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("lmee_pp_502TeV_lowB_TPC%s", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("lmee_pp_502TeV_lowB_TOF%s", vecPIDcase.at(icase).Data()))); - if (!nameStr.compare(Form("lmee_lowB_posNSigmaRun3_negEta%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("posTrack")); - cut->AddCut(GetAnalysisCut("negEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); + if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_pt04", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine_pt04")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s", vecPIDcase.at(icase).Data()))); - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } + + for (int i = 1; i <= 8; i++) { + if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_UsePrefilter%d", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data(), i))) { + cut->AddCut(GetAnalysisCut(Form("notDalitzLeg%d", i))); + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut(Form("lmeeQCTrackCuts%s", vecTypetrackWithPID.at(jcase).Data()))); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s", vecPIDcase.at(icase).Data()))); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + cut->AddCut(cut_pid_OR); + return cut; + } + } } - if (!nameStr.compare(Form("lmee_lowB_negNSigmaRun3_negEta%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("negTrack")); - cut->AddCut(GetAnalysisCut("negEtaSel")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); + if (!nameStr.compare(Form("lmee_eNSigmaRun3%s_strongTPC", vecPIDcase.at(icase).Data()))) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3_strongTPC")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TPCnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s", vecPIDcase.at(icase).Data()))); AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_lowB_TOFnsigma%s_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s", vecPIDcase.at(icase).Data()))); AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); cut_pid_OR->AddCut(cut_tpc_nSigma); @@ -1857,103 +2877,6 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) cut->AddCut(GetAnalysisCut(Form("lmee_pp_502TeV_TOFloose_pionrej%s", vecPIDcase.at(icase).Data()))); return cut; } - - // some older cuts - if (!nameStr.compare(Form("lmee_pp502TeV_PID%s", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); - - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("lmee_pp_502TeV_TPC%s", vecPIDcase.at(icase).Data()))); - - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("lmee_pp_502TeV_TOF%s", vecPIDcase.at(icase).Data()))); - - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } - - for (int i = 1; i <= 8; i++) { - if (!nameStr.compare(Form("lmee_pp502TeV_PID%s_UsePrefilter%d", vecPIDcase.at(icase).Data(), i))) { - cut->AddCut(GetAnalysisCut(Form("notDalitzLeg%d", i))); - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); - - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("lmee_pp_502TeV_TPC%s", vecPIDcase.at(icase).Data()))); - - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("lmee_pp_502TeV_TOF%s", vecPIDcase.at(icase).Data()))); - - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } - } - - if (!nameStr.compare(Form("lmee_pp502TeV_lowB_PID%s", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeLowBKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCAz")); // DCAz to reject loopers - - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("lmee_pp_502TeV_lowB_TPC%s", vecPIDcase.at(icase).Data()))); - - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("lmee_pp_502TeV_lowB_TOF%s", vecPIDcase.at(icase).Data()))); - - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } - - if (!nameStr.compare(Form("lmee_eNSigmaRun3%s_pt04", vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine_pt04")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); - - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s", vecPIDcase.at(icase).Data()))); - - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s", vecPIDcase.at(icase).Data()))); - - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } - - for (int i = 1; i <= 8; i++) { - if (!nameStr.compare(Form("lmee_eNSigmaRun3%s_UsePrefilter%d", vecPIDcase.at(icase).Data(), i))) { - cut->AddCut(GetAnalysisCut(Form("notDalitzLeg%d", i))); - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightGlobalTrackRun3")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); - - AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); - cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s", vecPIDcase.at(icase).Data()))); - - AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); - cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s", vecPIDcase.at(icase).Data()))); - - AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); - cut_pid_OR->AddCut(cut_tpc_nSigma); - cut_pid_OR->AddCut(cut_tof_nSigma); - cut->AddCut(cut_pid_OR); - return cut; - } - } } if (!nameStr.compare("testCut_chic")) { @@ -1984,10 +2907,26 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } - if (!nameStr.compare("lmee_TPCTrackRun3")) { + if (!nameStr.compare("lmee_TPCTrackRun3")) { + cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + cut->AddCut(GetAnalysisCut("TightTPCTrackRun3")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + return cut; + } + + if (!nameStr.compare("trackCut_compareDQEMframework")) { // cut setting to check least common factor between reduced data sets of PWGEM and PWGDQ cut->AddCut(GetAnalysisCut("lmeeStandardKine")); - cut->AddCut(GetAnalysisCut("TightTPCTrackRun3")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_looseDCA")); + cut->AddCut(GetAnalysisCut("trackQuality_compareDQEMframework")); + cut->AddCut(GetAnalysisCut("trackDCA1cm")); + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut("pid_TPCnSigma", "pid_TPCnSigma", kTRUE); + cut_tpc_nSigma->AddCut(GetAnalysisCut("lmee_commonDQEM_PID_TPC")); + + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut("pid_TOFnSigma", "pid_TOFnSigma", kTRUE); + cut_tof_nSigma->AddCut(GetAnalysisCut("lmee_commonDQEM_PID_TOF")); + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); return cut; } @@ -2018,6 +2957,11 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("muonMinimalCuts")) { + cut->AddCut(GetAnalysisCut("muonMinimalCuts")); + return cut; + } + if (!nameStr.compare("muonQualityCuts")) { cut->AddCut(GetAnalysisCut("muonQualityCuts")); return cut; @@ -2028,6 +2972,29 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("matchedQualityCutsMFTeta")) { + cut->AddCut(GetAnalysisCut("matchedQualityCutsMFTeta")); + return cut; + } + + if (!nameStr.compare("muonQualityCuts5SigmaPDCA_Run3")) { + cut->AddCut(GetAnalysisCut("muonQualityCuts5SigmaPDCA_Run3")); + return cut; + } + + if (!nameStr.compare("muonLowPt5SigmaPDCA_Run3")) { + cut->AddCut(GetAnalysisCut("muonLowPt")); + cut->AddCut(GetAnalysisCut("muonQualityCuts5SigmaPDCA_Run3")); + cut->AddCut(GetAnalysisCut("MCHMID")); + return cut; + } + + if (!nameStr.compare("muonQualityCuts10SigmaPDCA_MCHMID")) { + cut->AddCut(GetAnalysisCut("muonQualityCuts10SigmaPDCA")); + cut->AddCut(GetAnalysisCut("MCHMID")); + return cut; + } + if (!nameStr.compare("muonLowPt10SigmaPDCA")) { cut->AddCut(GetAnalysisCut("muonLowPt")); cut->AddCut(GetAnalysisCut("muonQualityCuts10SigmaPDCA")); @@ -2049,6 +3016,13 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("muonLowPt610SigmaPDCA")) { + cut->AddCut(GetAnalysisCut("muonLowPt6")); + cut->AddCut(GetAnalysisCut("muonQualityCuts10SigmaPDCA")); + cut->AddCut(GetAnalysisCut("MCHMID")); + return cut; + } + if (!nameStr.compare("muonLowPt")) { cut->AddCut(GetAnalysisCut("muonLowPt")); cut->AddCut(GetAnalysisCut("muonQualityCuts")); @@ -2241,6 +3215,11 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("pairPtLow5")) { + cut->AddCut(GetAnalysisCut("pairPtLow5")); + return cut; + } + if (!nameStr.compare("pairMassLow3")) { cut->AddCut(GetAnalysisCut("pairMassLow3")); return cut; @@ -2486,6 +3465,11 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("pairJpsi3")) { + cut->AddCut(GetAnalysisCut("pairJpsi3")); + return cut; + } + if (!nameStr.compare("pairPsi2S")) { cut->AddCut(GetAnalysisCut("pairPsi2S")); return cut; @@ -2501,11 +3485,26 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("pairX3872Cut2")) { + cut->AddCut(GetAnalysisCut("pairX3872_2")); + return cut; + } + + if (!nameStr.compare("pairX3872Cut3")) { + cut->AddCut(GetAnalysisCut("pairX3872_3")); + return cut; + } + if (!nameStr.compare("DipionPairCut1")) { cut->AddCut(GetAnalysisCut("DipionMassCut1")); return cut; } + if (!nameStr.compare("DipionPairCut2")) { + cut->AddCut(GetAnalysisCut("DipionMassCut2")); + return cut; + } + if (!nameStr.compare("pairRapidityForward")) { cut->AddCut(GetAnalysisCut("pairRapidityForward")); return cut; @@ -2528,6 +3527,60 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("pairD0HighPt1")) { + cut->AddCut(GetAnalysisCut("pairLxyzProjected3sigma")); + cut->AddCut(GetAnalysisCut("pairPtLow5")); + return cut; + } + + if (!nameStr.compare("pairD0HighPt2")) { + cut->AddCut(GetAnalysisCut("pairTauxyzProjected1")); + cut->AddCut(GetAnalysisCut("pairPtLow5")); + return cut; + } + + if (!nameStr.compare("pairD0HighPt3")) { + cut->AddCut(GetAnalysisCut("pairTauxyzProjected1sigma")); + cut->AddCut(GetAnalysisCut("pairPtLow5")); + return cut; + } + + if (!nameStr.compare("pairTauxyzProjected1")) { + cut->AddCut(GetAnalysisCut("pairTauxyzProjected1")); + return cut; + } + + if (!nameStr.compare("pairLxyProjected3sigmaLambdacCand")) { + cut->AddCut(GetAnalysisCut("pairLxyProjected3sigmaLambdacCand")); + return cut; + } + + if (!nameStr.compare("pairLxyProjected3sigmaDplusCand")) { + cut->AddCut(GetAnalysisCut("pairLxyProjected3sigmaDplusCand")); + return cut; + } + + if (!nameStr.compare("pairCosPointingPos")) { + cut->AddCut(GetAnalysisCut("pairCosPointingPos")); + return cut; + } + + if (!nameStr.compare("pairCosPointingNeg90")) { + cut->AddCut(GetAnalysisCut("pairCosPointingNeg90")); + return cut; + } + + if (!nameStr.compare("pairCosPointingNeg85")) { + cut->AddCut(GetAnalysisCut("pairCosPointingNeg85")); + return cut; + } + + if (!nameStr.compare("pairTauxyzProjectedCosPointing1")) { + cut->AddCut(GetAnalysisCut("pairCosPointingNeg")); + cut->AddCut(GetAnalysisCut("pairTauxyzProjected1")); + return cut; + } + // ------------------------------------------------------------------------------------------------- // // Below are a list of single electron single muon and in order or optimize the trigger @@ -2601,6 +3654,82 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("emu_electron_test1")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaOpen")); + return cut; + } + + if (!nameStr.compare("emu_electron_test2")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine2")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaOpen")); + return cut; + } + + if (!nameStr.compare("emu_electron_test3")) { + cut->AddCut(GetAnalysisCut("jpsiKineSkimmed")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaOpen")); + return cut; + } + + if (!nameStr.compare("emu_electron_test1_loosensigma")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaVeryVeryLoose2")); + return cut; + } + + if (!nameStr.compare("emu_electron_test2_loosensigma")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine2")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaVeryVeryLoose2")); + return cut; + } + + if (!nameStr.compare("emu_electron_test3_loosensigma")) { + cut->AddCut(GetAnalysisCut("jpsiKineSkimmed")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaVeryVeryLoose2")); + return cut; + } + + if (!nameStr.compare("emu_electron_test1_tightnsigma")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaLoose")); + return cut; + } + + if (!nameStr.compare("emu_electron_test2_tightnsigma")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine2")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaLoose")); + return cut; + } + + if (!nameStr.compare("emu_electron_test3_tightnsigma")) { + cut->AddCut(GetAnalysisCut("jpsiKineSkimmed")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaLoose")); + return cut; + } + + if (!nameStr.compare("emu_electron_specialTest")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKineForEMu")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaVeryVeryLoose2")); + return cut; + } + + if (!nameStr.compare("emu_electron_specialTest2")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKineForEMu")); + cut->AddCut(GetAnalysisCut("electronStandardQualityForO2MCdebug4")); + return cut; + } + if (!nameStr.compare("muonLooseTriggerTestCuts")) { cut->AddCut(GetAnalysisCut("muonLooseTriggerTestCuts")); return cut; @@ -2648,7 +3777,7 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) } delete cut; - LOGF(info, Form("Did not find cut %s", cutName)); + LOGF(fatal, Form("Did not find cut %s. Returning nullptr", cutName)); return nullptr; } @@ -2661,6 +3790,10 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) std::string nameStr = cutName; // --------------------------------------------------------------- // Event cuts + if (!nameStr.compare("noEventCut")) { + return cut; + } + if (!nameStr.compare("eventNoTFBorder")) { cut->AddCut(VarManager::kIsNoTFBorder, 0.5, 1.5); return cut; @@ -2682,16 +3815,43 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } - if (!nameStr.compare("eventStandardSel8")) { + if (!nameStr.compare("eventSel8")) { // kIsSel8 = kIsTriggerTVX && kNoITSROFrameBorder && kNoTimeFrameBorder + cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); + return cut; + } + if (!nameStr.compare("eventStandardSel8")) { // kIsSel8 = kIsTriggerTVX && kNoITSROFrameBorder && kNoTimeFrameBorder + cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); + cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); + return cut; + } + if (!nameStr.compare("eventStandardSel8WithITSROFRecomputedCut")) { + cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); + cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoTFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoITSROFBorderRecomputed, 0.5, 1.5); + return cut; + } + + if (!nameStr.compare("eventStandardSel8NoTFBorder")) { // Redundant w.r.t. eventStandardSel8, to be removed cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoTFBorder, 0.5, 1.5); + return cut; + } + + if (!nameStr.compare("eventStandardSel8NoTFBNoITSROFB")) { // Redundant w.r.t. eventStandardSel8, to be removed + cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); + cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoTFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoITSROFBorder, 0.5, 1.5); return cut; } - if (!nameStr.compare("eventStandardSel8NoTFBorder")) { + if (!nameStr.compare("eventStandardSel8NoTFBNoITSROFBrecomp")) { cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); cut->AddCut(VarManager::kIsNoTFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoITSROFBorderRecomputed, 0.5, 1.5); return cut; } @@ -2705,6 +3865,127 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("eventStandardSel8PbPbQualityGoodITSLayersAll")) { // kIsSel8 = kIsTriggerTVX && kNoITSROFrameBorder && kNoTimeFrameBorder + cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); + cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoTFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoITSROFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoSameBunch, 0.5, 1.5); + cut->AddCut(VarManager::kIsGoodZvtxFT0vsPV, 0.5, 1.5); + cut->AddCut(VarManager::kIsGoodITSLayersAll, 0.5, 1.5); + return cut; + } + + if (!nameStr.compare("eventStandardSel8PbPbQualityTightTrackOccupancy")) { + cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); + cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoTFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoITSROFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoSameBunch, 0.5, 1.5); + cut->AddCut(VarManager::kIsGoodZvtxFT0vsPV, 0.5, 1.5); + cut->AddCut(VarManager::kCentFT0C, 0.0, 90.0); + cut->AddCut(VarManager::kTrackOccupancyInTimeRange, 0., 1000); + + return cut; + } + if (!nameStr.compare("eventStandardSel8PbPbQualityFirmTrackOccupancy")) { + cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); + cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoTFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoITSROFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoSameBunch, 0.5, 1.5); + cut->AddCut(VarManager::kIsGoodZvtxFT0vsPV, 0.5, 1.5); + cut->AddCut(VarManager::kCentFT0C, 0.0, 90.0); + cut->AddCut(VarManager::kTrackOccupancyInTimeRange, 0., 2000); + + return cut; + } + + if (!nameStr.compare("eventStandardSel8PbPbQualityLooseTrackOccupancy")) { + cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); + cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoTFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoITSROFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoSameBunch, 0.5, 1.5); + cut->AddCut(VarManager::kIsGoodZvtxFT0vsPV, 0.5, 1.5); + cut->AddCut(VarManager::kCentFT0C, 0.0, 90.0); + cut->AddCut(VarManager::kTrackOccupancyInTimeRange, 0., 5000); + + return cut; + } + + if (!nameStr.compare("eventStandardSel8PbPbQualityTightTrackOccupancyCollInTime")) { + cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); + cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoTFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoITSROFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoSameBunch, 0.5, 1.5); + cut->AddCut(VarManager::kIsGoodZvtxFT0vsPV, 0.5, 1.5); + cut->AddCut(VarManager::kCentFT0C, 0.0, 90.0); + cut->AddCut(VarManager::kTrackOccupancyInTimeRange, 0., 500); + cut->AddCut(VarManager::kNoCollInTimeRangeStandard, 0.5, 1.5); + + return cut; + } + + if (!nameStr.compare("eventStandardSel8PbPbQualityTightTrackOccupancyCollInTime")) { + cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); + cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoTFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoITSROFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoSameBunch, 0.5, 1.5); + cut->AddCut(VarManager::kIsGoodZvtxFT0vsPV, 0.5, 1.5); + cut->AddCut(VarManager::kCentFT0C, 0.0, 90.0); + cut->AddCut(VarManager::kTrackOccupancyInTimeRange, 0., 1000); + cut->AddCut(VarManager::kNoCollInTimeRangeStandard, 0.5, 1.5); + + return cut; + } + + std::vector vecOccupancies = {0., + 250., + 500., + 750., + 1000., + 1500., + 2000., + 3000., + 4500., + 6000., + 8000., + 10000., + 50000.}; + + for (size_t icase = 0; icase < vecOccupancies.size() - 1; icase++) { + if (!nameStr.compare(Form("eventStandardSel8PbPbQualityTrackOccupancySlice%lu", icase))) { + cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); + cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoTFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoITSROFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoSameBunch, 0.5, 1.5); + cut->AddCut(VarManager::kIsGoodZvtxFT0vsPV, 0.5, 1.5); + cut->AddCut(VarManager::kCentFT0C, 0.0, 90.0); + cut->AddCut(VarManager::kTrackOccupancyInTimeRange, vecOccupancies[icase], vecOccupancies[icase + 1]); + + return cut; + } + } + + for (size_t icase = 0; icase < vecOccupancies.size() - 1; icase++) { + if (!nameStr.compare(Form("eventStandardSel8PbPbQualityTrackOccupancySlice_0_%lu", icase))) { + cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); + cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoTFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoITSROFBorder, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoSameBunch, 0.5, 1.5); + cut->AddCut(VarManager::kIsGoodZvtxFT0vsPV, 0.5, 1.5); + cut->AddCut(VarManager::kCentFT0C, 0.0, 90.0); + cut->AddCut(VarManager::kTrackOccupancyInTimeRange, 0, vecOccupancies[icase]); + + return cut; + } + } + if (!nameStr.compare("eventStandardSel8ppQuality")) { cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); @@ -2717,6 +3998,34 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("eventStandardSel8VtxQuality1")) { // kIsSel8 = kIsTriggerTVX && kNoITSROFrameBorder && kNoTimeFrameBorder + cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); + cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoSameBunch, 0.5, 1.5); + cut->AddCut(VarManager::kIsVertexITSTPC, 0.5, 1.5); + cut->AddCut(VarManager::kIsVertexTOFmatched, 0.5, 1.5); + return cut; + } + + if (!nameStr.compare("eventStandardSel8PbPbMultCorr")) { + TF1* fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x - 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); + fMultPVCutLow->SetParameters(3257.29, -121.848, 1.98492, -0.0172128, 6.47528e-05, 154.756, -1.86072, -0.0274713, 0.000633499, -3.37757e-06); + TF1* fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x + 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); + fMultPVCutHigh->SetParameters(3257.29, -121.848, 1.98492, -0.0172128, 6.47528e-05, 154.756, -1.86072, -0.0274713, 0.000633499, -3.37757e-06); + + TF1* fMultCutLow = new TF1("fMultCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultCutLow->SetParameters(1654.46, -47.2379, 0.449833, -0.0014125, 150.773, -3.67334, 0.0530503, -0.000614061, 3.15956e-06); + TF1* fMultCutHigh = new TF1("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 3.*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultCutHigh->SetParameters(1654.46, -47.2379, 0.449833, -0.0014125, 150.773, -3.67334, 0.0530503, -0.000614061, 3.15956e-06); + cut->AddCut(VarManager::kVtxNcontribReal, fMultPVCutLow, fMultPVCutHigh, false, VarManager::kCentFT0C, 0.0, 100.0, false); + cut->AddCut(VarManager::kMultA, fMultCutLow, fMultCutHigh, false, VarManager::kCentFT0C, 0.0, 100.0, false); + cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); + cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoSameBunch, 0.5, 1.5); + cut->AddCut(VarManager::kIsGoodZvtxFT0vsPV, 0.5, 1.5); + return cut; + } + if (!nameStr.compare("eventDimuonStandard")) { cut->AddCut(VarManager::kIsMuonUnlikeLowPt7, 0.5, 1.5); return cut; @@ -2758,21 +4067,68 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } - if (!nameStr.compare("eventSingleGap")) { - cut->AddCut(VarManager::kIsSingleGap, 0.5, 1.5); + if (!nameStr.compare("eventSingleGap")) { + cut->AddCut(VarManager::kIsSingleGap, 0.5, 1.5); + return cut; + } + + if (!nameStr.compare("eventSingleGapA")) { + cut->AddCut(VarManager::kIsSingleGapA, 0.5, 1.5); + return cut; + } + + if (!nameStr.compare("eventSingleGapAZDC")) { + cut->AddCut(VarManager::kIsSingleGapA, 0.5, 1.5); + cut->AddCut(VarManager::kEnergyCommonZNA, -1000., 1.); + cut->AddCut(VarManager::kEnergyCommonZNC, 1., 1000.); + return cut; + } + + if (!nameStr.compare("eventSingleGapC")) { + cut->AddCut(VarManager::kIsSingleGapC, 0.5, 1.5); + return cut; + } + + if (!nameStr.compare("eventSingleGapCZDC")) { + cut->AddCut(VarManager::kIsSingleGapC, 0.5, 1.5); + cut->AddCut(VarManager::kEnergyCommonZNC, -1000., 1.); + cut->AddCut(VarManager::kEnergyCommonZNA, 1., 1000.); return cut; } - if (!nameStr.compare("eventSingleGapA")) { - cut->AddCut(VarManager::kIsSingleGapA, 0.5, 1.5); - return cut; + if (!nameStr.compare("eventSingleGapACZDC")) { + AnalysisCompositeCut* cutA = new AnalysisCompositeCut("singleGapAZDC", "singleGapAZDC", kTRUE); + cutA->AddCut(GetAnalysisCut("eventSingleGapAZDC")); + + AnalysisCompositeCut* cutC = new AnalysisCompositeCut("singleGapCZDC", "singleGapCZDC", kTRUE); + cutC->AddCut(GetAnalysisCut("eventSingleGapCZDC")); + + AnalysisCompositeCut* cutAorC = new AnalysisCompositeCut("singleGapACZDC", "singleGapACZDC", kFALSE); + cutAorC->AddCut(cutA); + cutAorC->AddCut(cutC); + return cutAorC; } - if (!nameStr.compare("eventSingleGapC")) { - cut->AddCut(VarManager::kIsSingleGapC, 0.5, 1.5); + if (!nameStr.compare("eventUPCMode")) { + cut->AddCut(VarManager::kIsITSUPCMode, 0.5, 1.5); return cut; } + if (!nameStr.compare("eventSingleGapACZDC_UPCMode")) { + AnalysisCompositeCut* cutA = new AnalysisCompositeCut("singleGapAZDC", "singleGapAZDC", kTRUE); + cutA->AddCut(GetAnalysisCut("eventSingleGapAZDC")); + cutA->AddCut(GetAnalysisCut("eventUPCMode")); + + AnalysisCompositeCut* cutC = new AnalysisCompositeCut("singleGapCZDC", "singleGapCZDC", kTRUE); + cutC->AddCut(GetAnalysisCut("eventSingleGapCZDC")); + cutC->AddCut(GetAnalysisCut("eventUPCMode")); + + AnalysisCompositeCut* cutAorC = new AnalysisCompositeCut("singleGapACZDC", "singleGapACZDC", kFALSE); + cutAorC->AddCut(cutA); + cutAorC->AddCut(cutC); + return cutAorC; + } + // Event cuts based on centrality if (!nameStr.compare("eventStandardNoINT7Cent090")) { cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); @@ -2837,6 +4193,16 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("pt02Sel")) { + cut->AddCut(VarManager::kPt, 0.2, 20.0); + return cut; + } + + if (!nameStr.compare("pt04Sel")) { + cut->AddCut(VarManager::kPt, 0.4, 20.0); + return cut; + } + if (!nameStr.compare("openEtaSel")) { cut->AddCut(VarManager::kEta, -0.9, 0.9); return cut; @@ -2881,6 +4247,18 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("jpsiPIDcalibKine_posEta")) { + cut->AddCut(VarManager::kPin, 1.0, 1000.0); + cut->AddCut(VarManager::kEta, 0.0, 0.9); + return cut; + } + + if (!nameStr.compare("jpsiPIDcalibKine_negEta")) { + cut->AddCut(VarManager::kPin, 1.0, 1000.0); + cut->AddCut(VarManager::kEta, -0.9, 0.0); + return cut; + } + if (!nameStr.compare("jpsiStandardKine4")) { cut->AddCut(VarManager::kP, 1.5, 1000.0); cut->AddCut(VarManager::kEta, -0.9, 0.9); @@ -2899,6 +4277,12 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("jpsiStandardKineForEMu")) { + cut->AddCut(VarManager::kPt, 5.0, 1000.0); + cut->AddCut(VarManager::kEta, -0.9, 0.9); + return cut; + } + if (!nameStr.compare("lmeePrefilterKine")) { cut->AddCut(VarManager::kPt, 0., 20.0); cut->AddCut(VarManager::kEta, -1.2, 1.2); @@ -2930,12 +4314,38 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) } if (!nameStr.compare("PIDStandardKine")) { - cut->AddCut(VarManager::kPt, 0.1, 1000.0); cut->AddCut(VarManager::kEta, -0.9, 0.9); cut->AddCut(VarManager::kPt, 1.0, 1000.0); return cut; } + if (!nameStr.compare("PIDStandardKine2")) { + cut->AddCut(VarManager::kEta, -0.9, 0.9); + cut->AddCut(VarManager::kPt, 0.1, 1000.0); + return cut; + } + + if (!nameStr.compare("PIDStandardKine3")) { + cut->AddCut(VarManager::kEta, -0.9, 0.9); + cut->AddCut(VarManager::kPt, 0.5, 1000.0); + return cut; + } + + if (!nameStr.compare("pTLow04")) { + cut->AddCut(VarManager::kPt, 0.4, 1000.0); + return cut; + } + + if (!nameStr.compare("pTLow03")) { + cut->AddCut(VarManager::kPt, 0.3, 1000.0); + return cut; + } + + if (!nameStr.compare("pTLow02")) { + cut->AddCut(VarManager::kPt, 0.2, 1000.0); + return cut; + } + // ----------------------------------------------- // Barrel track quality cuts @@ -3011,6 +4421,39 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("jpsi_trackCut_debug3")) { + cut->AddCut(VarManager::kEta, -0.9, 0.9); + cut->AddCut(VarManager::kTPCchi2, 0.0, 4.0); + cut->AddCut(VarManager::kTPCncls, 90., 159); + cut->AddCut(VarManager::kIsTPCrefit, 0.5, 1.5); + cut->AddCut(VarManager::kTPCnclsCR, 70., 159); + cut->AddCut(VarManager::kITSncls, 2.5, 7.5); + cut->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + cut->AddCut(VarManager::kITSchi2, 0.0, 5.0); + cut->AddCut(VarManager::kTrackDCAxy, -0.05, 0.05); + cut->AddCut(VarManager::kTrackDCAz, -1.0, 1.0); + return cut; + } + + if (!nameStr.compare("jpsi_trackCut_debug4")) { + cut->AddCut(VarManager::kEta, -0.9, 0.9); + cut->AddCut(VarManager::kTPCchi2, 0.0, 4.0); + cut->AddCut(VarManager::kTPCncls, 90., 159); + cut->AddCut(VarManager::kITSncls, 2.5, 7.5); + cut->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + cut->AddCut(VarManager::kTrackDCAxy, -1, 1); + cut->AddCut(VarManager::kTrackDCAz, -3.0, 3.0); + return cut; + } + + if (!nameStr.compare("jpsi_trackCut_debug5")) { + cut->AddCut(VarManager::kEta, -0.9, 0.9); + cut->AddCut(VarManager::kTPCchi2, 0.0, 4.0); + cut->AddCut(VarManager::kTPCncls, 70., 159); + cut->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + return cut; + } + if (!nameStr.compare("lmee_trackCut_debug")) { cut->AddCut(VarManager::kEta, -0.9, 0.9); cut->AddCut(VarManager::kTPCchi2, 0.0, 4.0); @@ -3028,6 +4471,17 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("trackQuality_compareDQEMframework")) { // cut setting to check least common factor between reduced data sets of PWGEM and PWGDQ + cut->AddCut(VarManager::kIsSPDfirst, 0.5, 1.5); + cut->AddCut(VarManager::kITSchi2, 0.0, 5.0); + cut->AddCut(VarManager::kITSncls, 4.5, 7.5); + cut->AddCut(VarManager::kTPCchi2, 0.0, 4.0); + cut->AddCut(VarManager::kTPCnclsCR, 80.0, 161.); + cut->AddCut(VarManager::kTPCnCRoverFindCls, 0.8, 1e+10); + cut->AddCut(VarManager::kTPCncls, 90.0, 170.); + return cut; + } + if ((!nameStr.compare("TightGlobalTrackRun3")) || (!nameStr.compare("lmeeQCTrackCuts"))) { cut->AddCut(VarManager::kIsSPDfirst, 0.5, 1.5); cut->AddCut(VarManager::kTPCchi2, 0.0, 4.0); @@ -3039,14 +4493,16 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) } std::vector vecTypetrack; - vecTypetrack.emplace_back(""); // default TightGlobalTrackRun3 as above - vecTypetrack.emplace_back("_7ITSncls"); // default TightGlobalTrackRun3 but with 7 ITS clusters - vecTypetrack.emplace_back("_ITS"); // Ask only for ITS requirements - vecTypetrack.emplace_back("_ITSalone"); // Ask only for ITS requirements + ITSalone (no TPC matching) - vecTypetrack.emplace_back("_TPC"); // Ask only for TPC requirements - vecTypetrack.emplace_back("_TPCalone"); // Ask only for TPC requirements + TPCalone (no ITS matching) - vecTypetrack.emplace_back("_TPCnoTRD"); // Ask only for TPC requirements no TRD matching - vecTypetrack.emplace_back("_TPCstrongncls"); // default TightGlobalTrackRun3 but with 130 TPC clusters + vecTypetrack.emplace_back(""); // default TightGlobalTrackRun3 as above + vecTypetrack.emplace_back("_7ITSncls"); // default TightGlobalTrackRun3 but with 7 ITS clusters + vecTypetrack.emplace_back("_ITS"); // Ask only for ITS requirements + vecTypetrack.emplace_back("_ITSalone"); // Ask only for ITS requirements + ITSalone (no TPC matching) + vecTypetrack.emplace_back("_TPC"); // Ask only for TPC requirements + vecTypetrack.emplace_back("_TPCalone"); // Ask only for TPC requirements + TPCalone (no ITS matching) + vecTypetrack.emplace_back("_TPCnoTRD"); // Ask only for TPC requirements no TRD matching + vecTypetrack.emplace_back("_TPCstrongncls"); // default TightGlobalTrackRun3 but with 130 TPC clusters + vecTypetrack.emplace_back("_ITSanyfirsttwo"); // default TightGlobalTrackRun3 but with a cluster in any of the first two layers + vecTypetrack.emplace_back("_ITSanyfirstthree"); // default TightGlobalTrackRun3 but with a cluster in any of the first three layers // loop to define PID cuts with and without post calibration for (size_t icase = 1; icase < vecTypetrack.size(); icase++) { @@ -3081,13 +4537,27 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) cut->AddCut(VarManager::kTPCnclsCR, 80.0, 161.); cut->AddCut(VarManager::kTPCncls, 90.0, 170.); cut->AddCut(VarManager::kHasTRD, -0.5, 0.5); - } else { + } else if (icase == 7) { cut->AddCut(VarManager::kIsSPDfirst, 0.5, 1.5); cut->AddCut(VarManager::kTPCchi2, 0.0, 4.0); cut->AddCut(VarManager::kITSchi2, 0.0, 5.0); cut->AddCut(VarManager::kITSncls, 4.5, 7.5); cut->AddCut(VarManager::kTPCnclsCR, 80.0, 161.); cut->AddCut(VarManager::kTPCncls, 130.0, 170.); + } else if (icase == 8) { + cut->AddCut(VarManager::kIsSPDany, 0.5, 1.5); + cut->AddCut(VarManager::kTPCchi2, 0.0, 4.0); + cut->AddCut(VarManager::kITSchi2, 0.0, 5.0); + cut->AddCut(VarManager::kITSncls, 4.5, 7.5); + cut->AddCut(VarManager::kTPCnclsCR, 80.0, 161.); + cut->AddCut(VarManager::kTPCncls, 90.0, 170.); + } else { + cut->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + cut->AddCut(VarManager::kTPCchi2, 0.0, 4.0); + cut->AddCut(VarManager::kITSchi2, 0.0, 5.0); + cut->AddCut(VarManager::kITSncls, 4.5, 7.5); + cut->AddCut(VarManager::kTPCnclsCR, 80.0, 161.); + cut->AddCut(VarManager::kTPCncls, 90.0, 170.); } return cut; } @@ -3145,6 +4615,30 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("ITSibany")) { + cut->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + return cut; + } + + // List of 30 variations in ITS and TPC parameters + std::vector cutVar_ITSchi2 = {6., 6., 5., 4., 4., 6., 6., 5., 4., 5., 4., 5., 6., 5., 6., 5., 6., 5., 5., 4., 6., 4., 6., 5., 6., 4., 4., 6., 4., 5.}; + std::vector cutVar_TPCchi2 = {5., 5., 4., 3., 5., 4., 5., 3., 5., 4., 5., 3., 3., 5., 4., 5., 3., 5., 5., 5., 3., 5., 5., 4., 3., 4., 5., 5., 5., 3.}; + std::vector cutVar_ITSnCl = {4.5, 5.5, 5.5, 4.5, 6.5, 4.5, 4.5, 4.5, 4.5, 5.5, 4.5, 5.5, 5.5, 5.5, 5.5, 4.5, 5.5, 6.5, 5.5, 4.5, 4.5, 5.5, 5.5, 5.5, 6.5, 5.5, 4.5, 4.5, 6.5, 6.5}; + std::vector cutVar_TPCnClsCR = {90., 80., 80., 80., 90., 80., 70., 90., 70., 80., 70., 90., 90., 70., 90., 90., 70., 80., 90., 80., 80., 90., 70., 70., 70., 80., 90., 70., 70., 80.}; + std::vector cutVar_TPCnCls = {80., 100., 80., 90., 90., 80., 80., 80., 80., 90., 100., 100., 80., 80., 80., 80., 100., 90., 100., 90., 90., 100., 100., 80., 100., 90., 90., 100., 90., 90.}; + + for (unsigned int i = 0; i < cutVar_ITSchi2.size(); i++) { + if (!nameStr.compare(Form("lmeeCutVarTrackCuts%i", i))) { + cut->AddCut(VarManager::kIsSPDfirst, 0.5, 1.5); + cut->AddCut(VarManager::kITSchi2, 0.0, cutVar_ITSchi2.at(i)); + cut->AddCut(VarManager::kTPCchi2, 0.0, cutVar_TPCchi2.at(i)); + cut->AddCut(VarManager::kITSncls, cutVar_ITSnCl.at(i), 7.5); + cut->AddCut(VarManager::kTPCnclsCR, cutVar_TPCnClsCR.at(i), 161.); + cut->AddCut(VarManager::kTPCncls, cutVar_TPCnCls.at(i), 170.); + return cut; + } + } + if (!nameStr.compare("electronStandardQualityForO2MCdebug")) { cut->AddCut(VarManager::kIsSPDany, 0.5, 1.5); cut->AddCut(VarManager::kTPCchi2, 0.0, 4.0); @@ -3166,6 +4660,13 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("electronStandardQualityForO2MCdebug4")) { + cut->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + cut->AddCut(VarManager::kTPCchi2, 0.0, 4.0); + cut->AddCut(VarManager::kTPCncls, 70, 161.); + return cut; + } + if (!nameStr.compare("electronStandardQualityITSOnly")) { cut->AddCut(VarManager::kIsSPDany, 0.5, 1.5); cut->AddCut(VarManager::kITSchi2, 0.0, 5.0); @@ -3186,6 +4687,12 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("electronStandardQualityTPCOnly2")) { + cut->AddCut(VarManager::kTPCchi2, 0.0, 4.0); + cut->AddCut(VarManager::kTPCncls, 100, 161.); + return cut; + } + if (!nameStr.compare("NoelectronStandardQualityTPCOnly")) { cut->AddCut(VarManager::kTPCchi2, 0.0, 4.0, true, VarManager::kTPCncls, 70, 161.); return cut; @@ -3200,12 +4707,46 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("electronTrackQualitySkimmed2")) { + cut->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + cut->AddCut(VarManager::kITSchi2, 0.0, 5.0); + cut->AddCut(VarManager::kTPCncls, 60, 161); + return cut; + } + + if (!nameStr.compare("electronTrackQualitySkimmed3")) { + cut->AddCut(VarManager::kPt, 1.0, 1000.0); + cut->AddCut(VarManager::kEta, -0.9, 0.9); + cut->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + cut->AddCut(VarManager::kTPCnclsCR, 70, 161); + cut->AddCut(VarManager::kTPCncls, 70, 161); + return cut; + } + if (!nameStr.compare("pionQualityCut1")) { cut->AddCut(VarManager::kPt, 0.15, 1000.0); cut->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); - cut->AddCut(VarManager::kTPCncls, 100, 161); - cut->AddCut(VarManager::kTrackDCAxy, -0.05, 0.05); - cut->AddCut(VarManager::kTrackDCAz, -0.1, 0.1); + cut->AddCut(VarManager::kTPCncls, 70, 161); + return cut; + } + + if (!nameStr.compare("pionQualityCut2")) { + cut->AddCut(VarManager::kPt, 0.15, 1000.0); + cut->AddCut(VarManager::kEta, -0.9, 0.9); + cut->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + cut->AddCut(VarManager::kTPCncls, 90, 161); + cut->AddCut(VarManager::kTPCnclsCR, 70, 161); + return cut; + } + + if (!nameStr.compare("protonPVcut")) { + cut->AddCut(VarManager::kTrackDCAxy, -0.1, 0.1); + cut->AddCut(VarManager::kTrackDCAz, -0.15, 0.15); + cut->AddCut(VarManager::kPt, 0.4, 3); + cut->AddCut(VarManager::kEta, -0.9, 0.9); + cut->AddCut(VarManager::kIsSPDany, 0.5, 1.5); + cut->AddCut(VarManager::kTPCchi2, 0.0, 4.0); + cut->AddCut(VarManager::kTPCncls, 80, 161.); return cut; } @@ -3221,12 +4762,139 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("trackDCA1cm")) { // cut setting to check least common factor between reduced data sets of PWGEM and PWGDQ + cut->AddCut(VarManager::kTrackDCAxy, -1.0, 1.0); + cut->AddCut(VarManager::kTrackDCAz, -1.0, 1.0); + return cut; + } + if (!nameStr.compare("dcaCut1_ionut")) { cut->AddCut(VarManager::kTrackDCAxy, -0.5, 0.5); cut->AddCut(VarManager::kTrackDCAz, -0.5, 0.5); return cut; } + if (!nameStr.compare("trackQuality_ionut")) { + cut->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + cut->AddCut(VarManager::kTPCncls, 70, 161); + cut->AddCut(VarManager::kITSchi2, 0.0, 5.0); + cut->AddCut(VarManager::kTPCchi2, 0.0, 2.0); + return cut; + } + + if (!nameStr.compare("trackQualityTight_ionut")) { + cut->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + cut->AddCut(VarManager::kTPCncls, 100, 161); + cut->AddCut(VarManager::kITSchi2, 0.0, 3.0); + cut->AddCut(VarManager::kTPCchi2, 0.0, 2.0); + cut->AddCut(VarManager::kITSncls, 5.0, 8.0); + return cut; + } + + if (!nameStr.compare("kineJpsiEle_ionut")) { + cut->AddCut(VarManager::kP, 1.0, 15.0); + cut->AddCut(VarManager::kEta, -0.9, 0.9); + return cut; + } + + if (!nameStr.compare("pidJpsiEle0_ionut")) { + cut->AddCut(VarManager::kTPCnSigmaEl, -2.0, 4.0, false, VarManager::kPin, 1.0, 4.0); + cut->AddCut(VarManager::kTPCnSigmaEl, -1.0, 4.0, false, VarManager::kPin, 4.0, 150.0); + cut->AddCut(VarManager::kTPCnSigmaEl, 98.1, 98.11, false, VarManager::kPin, 0.0, 1.0); + cut->AddCut(VarManager::kTPCnSigmaPr, -4.0, 4.0, true); + return cut; + } + + if (!nameStr.compare("pidJpsiEle1_ionut")) { + cut->AddCut(VarManager::kTPCnSigmaEl, -1.5, 4.0, false, VarManager::kPin, 1.0, 4.0); + cut->AddCut(VarManager::kTPCnSigmaEl, -1.0, 4.0, false, VarManager::kPin, 4.0, 150.0); + cut->AddCut(VarManager::kTPCnSigmaEl, 98.1, 98.11, false, VarManager::kPin, 0.0, 1.0); + cut->AddCut(VarManager::kTPCnSigmaPr, -4.0, 4.0, true); + return cut; + } + + if (!nameStr.compare("pidJpsiEle2_ionut")) { + cut->AddCut(VarManager::kTPCnSigmaEl, -1.0, 4.0); + cut->AddCut(VarManager::kTPCnSigmaPr, -4.0, 4.0, true); + return cut; + } + + if (!nameStr.compare("pidJpsiEle3_ionut")) { + cut->AddCut(VarManager::kTPCnSigmaEl, -0.5, 4.0); + cut->AddCut(VarManager::kTPCnSigmaPr, -4.0, 4.0, true); + return cut; + } + + if (!nameStr.compare("pidJpsiEle4_ionut")) { + cut->AddCut(VarManager::kTPCnSigmaEl, 0.0, 4.0); + cut->AddCut(VarManager::kTPCnSigmaPr, -4.0, 4.0, true); + return cut; + } + + if (!nameStr.compare("pidJpsiEle5_ionut")) { + cut->AddCut(VarManager::kTPCnSigmaEl, 0.5, 4.0); + cut->AddCut(VarManager::kTPCnSigmaPr, -4.0, 4.0, true); + return cut; + } + + if (!nameStr.compare("pidJpsiEle6_ionut")) { + cut->AddCut(VarManager::kTPCnSigmaEl, -1.0, 4.0); + cut->AddCut(VarManager::kTOFnSigmaEl, -1.0, 4.0); + cut->AddCut(VarManager::kTPCnSigmaPr, -4.0, 4.0, true); + return cut; + } + + if (!nameStr.compare("pidJpsiEle7_ionut")) { + cut->AddCut(VarManager::kTOFnSigmaEl, -3.0, 4.0); + cut->AddCut(VarManager::kTPCnSigmaEl, -1.0, 4.0); + return cut; + } + + if (!nameStr.compare("pidJpsiEle8_ionut")) { + cut->AddCut(VarManager::kTOFnSigmaEl, -3.0, 4.0); + cut->AddCut(VarManager::kTPCnSigmaEl, -1.5, 4.0); + return cut; + } + + if (!nameStr.compare("pidJpsiEle9_ionut")) { + cut->AddCut(VarManager::kTOFnSigmaEl, -3.0, 4.0); + cut->AddCut(VarManager::kTPCnSigmaEl, -2.0, 4.0); + return cut; + } + + // Magnus cuts ---------------------------------------------------------- + + if (!nameStr.compare("pidJpsi_magnus_ele1")) { + cut->AddCut(VarManager::kTPCnSigmaEl, -3.0, 4.0); + return cut; + } + if (!nameStr.compare("pidJpsi_magnus_ele2")) { + cut->AddCut(VarManager::kTPCnSigmaEl, -2.0, 4.0); + return cut; + } + if (!nameStr.compare("pidJpsi_magnus_ele3")) { + cut->AddCut(VarManager::kTPCnSigmaEl, -1.0, 4.0); + return cut; + } + if (!nameStr.compare("pidJpsi_magnus_prot1")) { + cut->AddCut(VarManager::kTPCnSigmaPr, 3.0, 1000.0); + return cut; + } + if (!nameStr.compare("pidJpsi_magnus_prot2")) { + cut->AddCut(VarManager::kTPCnSigmaPr, 3.5, 1000.0); + return cut; + } + if (!nameStr.compare("pidJpsi_magnus_pion1")) { + cut->AddCut(VarManager::kTPCnSigmaPi, 3.0, 1000.0); + return cut; + } + if (!nameStr.compare("pidJpsi_magnus_pion2")) { + cut->AddCut(VarManager::kTPCnSigmaPi, 3.5, 1000.0); + return cut; + } + + // ---------------------------------------------------------------------------------- + if (!nameStr.compare("standardPrimaryTrackDCAz")) { cut->AddCut(VarManager::kTrackDCAxy, -3.0, 3.0); cut->AddCut(VarManager::kTrackDCAz, -1.0, 1.0); @@ -3267,6 +4935,11 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("noTOF")) { + cut->AddCut(VarManager::kHasTOF, -0.5, 0.5); + return cut; + } + // ----------------------------------------------------- // V0 and Dalitz legs selections @@ -3362,6 +5035,14 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) cut->AddCut(VarManager::kTPCnSigmaPr, 1.5, 999, false, VarManager::kPin, 3.0, 999); return cut; } + + if (!nameStr.compare("electronPIDLooseSkimmed3")) { + cut->AddCut(VarManager::kTPCnSigmaEl, -3.0, 3.0); + cut->AddCut(VarManager::kTPCnSigmaPi, 3.0, 999, false, VarManager::kPin, 0, 3.0); + cut->AddCut(VarManager::kTPCnSigmaPr, 3.0, 999, false, VarManager::kPin, 0, 3.0); + return cut; + } + if (!nameStr.compare("jpsi_TPCPID_debug6")) { cut->AddCut(VarManager::kTPCnSigmaEl, -2.0, 3.0); cut->AddCut(VarManager::kTPCnSigmaPi, 3.0, 999); @@ -3376,6 +5057,22 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("jpsi_TPCPID_debug8")) { + cut->AddCut(VarManager::kTPCnSigmaEl, -2.0, 3.0, false, VarManager::kPin, 0.0, 3.0); + cut->AddCut(VarManager::kTPCnSigmaEl, -3.0, 3.0, false, VarManager::kPin, 3.0, 999.0); + cut->AddCut(VarManager::kTPCnSigmaPi, 3.0, 999, false, VarManager::kPin, 0.0, 3.0); + cut->AddCut(VarManager::kTPCnSigmaPi, 2.0, 999, false, VarManager::kPin, 5.0, 999.0); + cut->AddCut(VarManager::kTPCnSigmaPr, 3.0, 999, false, VarManager::kPin, 3.0, 999.0); + return cut; + } + + if (!nameStr.compare("jpsi_TPCPID_debug9")) { + cut->AddCut(VarManager::kTPCnSigmaEl, -2.5, 4.0); + cut->AddCut(VarManager::kTPCnSigmaPi, 1.0, 999, false, VarManager::kPin, 3.0, 999.0); + cut->AddCut(VarManager::kTPCnSigmaPr, 2.0, 999); + return cut; + } + if (!nameStr.compare("pidCut_lowP_Corr")) { cut->AddCut(VarManager::kTPCnSigmaEl_Corr, -3.0, 3.0, false, VarManager::kP, 0.0, 5.0); cut->AddCut(VarManager::kTPCnSigmaPi_Corr, 3.0, 999, false, VarManager::kP, 0.0, 5.0); @@ -3477,6 +5174,21 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("lmee_commonDQEM_PID_TPC")) { // cut setting to check least common factor between reduced data sets of PWGEM and PWGDQ + cut->AddCut(VarManager::kTPCnSigmaEl, -2.5, 3., false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPi, -1e12, 3.5, true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaKa, -3., 3., true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPr, -3., 3., true, VarManager::kPin, 0.0, 1e+10, false); + return cut; + } + + if (!nameStr.compare("lmee_commonDQEM_PID_TOF")) { // cut setting to check least common factor between reduced data sets of PWGEM and PWGDQ + cut->AddCut(VarManager::kTPCnSigmaEl, -2.5, 3., false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPi, -3., 3.5, true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTOFnSigmaEl, -3., 3., false, VarManager::kPin, 0.3, 1e+10, false); + return cut; + } + std::vector vecPIDcase; vecPIDcase.emplace_back(""); // without post calibration vecPIDcase.emplace_back("_Corr"); // case of using post calibrated PID spectra @@ -3645,17 +5357,39 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) if (!nameStr.compare(Form("electronPID_TPCnsigma%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))) { if (icase == 0) { - cut->AddCut(VarManager::kTPCnSigmaEl, -1., 2., false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaEl, -1., 2., false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPi, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaKa, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPr, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); + } else if (icase == 1) { + cut->AddCut(VarManager::kTPCnSigmaEl_Corr, -1., 2., false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPi_Corr, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaKa, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPr_Corr, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); + } else if (icase == 2) { + cut->AddCut(VarManager::kTPCnSigmaEl_Corr, -1., 2., false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPi_Corr, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaKa_Corr, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPr_Corr, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); + } + cut->AddCut(VarManager::kTOFbeta, 0.0, 0.985, true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTOFbeta, 1.015, 999999999., true, VarManager::kPin, 0.0, 1e+10, false); + return cut; + } + + if (!nameStr.compare(Form("electronPID_TPCnsigma%s_tightNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))) { + if (icase == 0) { + cut->AddCut(VarManager::kTPCnSigmaEl, 0., 3., false, VarManager::kPin, 0.0, 1e+10, false); cut->AddCut(VarManager::kTPCnSigmaPi, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); cut->AddCut(VarManager::kTPCnSigmaKa, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); cut->AddCut(VarManager::kTPCnSigmaPr, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); } else if (icase == 1) { - cut->AddCut(VarManager::kTPCnSigmaEl_Corr, -1., 2., false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaEl_Corr, 0., 3., false, VarManager::kPin, 0.0, 1e+10, false); cut->AddCut(VarManager::kTPCnSigmaPi_Corr, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); cut->AddCut(VarManager::kTPCnSigmaKa, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); cut->AddCut(VarManager::kTPCnSigmaPr_Corr, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); } else if (icase == 2) { - cut->AddCut(VarManager::kTPCnSigmaEl_Corr, -1., 2., false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaEl_Corr, 0., 3., false, VarManager::kPin, 0.0, 1e+10, false); cut->AddCut(VarManager::kTPCnSigmaPi_Corr, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); cut->AddCut(VarManager::kTPCnSigmaKa_Corr, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); cut->AddCut(VarManager::kTPCnSigmaPr_Corr, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); @@ -3665,6 +5399,38 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + // List of nSigma values for lower and upper edge of El, Pi, Ka, Pr, TPC PID selections/rejection + std::vector cutVar_TPCnSigmaEl_low = {-4., -4., -4., -2., -3., -2., -3., -4., -2., -4., -3., -3., -3., -4., -3., -3., -4., -3., -4., -4., -3., -4., -3., -3., -2., -4., -4., -3., -4., -2}; + std::vector cutVar_TPCnSigmaEl_up = {2., 3., 2., 2., 2., 2., 2., 4., 2., 2., 4., 3., 3., 2., 4., 2., 2., 4., 3., 4., 2., 4., 2., 3., 2., 3., 4., 2., 3., 2}; + std::vector cutVar_TPCnSigmaPi_low = {-3., -2., -3., -4., -4., -3., -4., -2., -2., -2., -3., -3., -2., -2., -4., -3., -3., -2., -3., -2., -4., -2., -4., -4., -3., -3., -3., -2., -4., -4}; + std::vector cutVar_TPCnSigmaPi_up = {3., 3., 4., 4., 3., 2., 4., 4., 3., 4., 4., 3., 4., 4., 3., 2., 4., 2., 4., 2., 3., 4., 2., 2., 3., 2., 3., 4., 2., 4}; + std::vector cutVar_TPCnSigmaKa_low = {-4., -2., -2., -2., -4., -3., -2., -4., -3., -3., -4., -2., -3., -3., -4., -2., -4., -2., -3., -4., -4., -2., -2., -3., -2., -2., -3., -3., -2., -4}; + std::vector cutVar_TPCnSigmaKa_up = {4., 3., 2., 3., 4., 3., 4., 4., 4., 4., 4., 4., 4., 4., 2., 4., 4., 2., 2., 4., 3., 3., 2., 4., 2., 4., 3., 3., 3., 3}; + std::vector cutVar_TPCnSigmaPr_low = {-4., -2., -2., -3., -4., -4., -3., -2., -2., -4., -4., -2., -3., -4., -2., -3., -3., -2., -3., -3., -2., -2., -2., -2., -2., -3., -2., -3., -3., -3}; + std::vector cutVar_TPCnSigmaPr_up = {2., 2., 3., 2., 3., 3., 3., 2., 4., 3., 3., 4., 4., 3., 4., 4., 3., 4., 2., 3., 4., 4., 3., 4., 3., 2., 3., 3., 2., 3}; + + for (unsigned int i = 0; i < cutVar_TPCnSigmaEl_low.size(); i++) { + if (!nameStr.compare(Form("electronPID_TPCnsigma_cutVar%s%i", vecPIDcase.at(icase).Data(), i))) { + if (icase == 0) { + cut->AddCut(VarManager::kTPCnSigmaEl, cutVar_TPCnSigmaEl_low.at(i), cutVar_TPCnSigmaEl_up.at(i), false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPi, cutVar_TPCnSigmaPi_low.at(i), cutVar_TPCnSigmaPi_up.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaKa, cutVar_TPCnSigmaKa_low.at(i), cutVar_TPCnSigmaKa_up.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPr, cutVar_TPCnSigmaPr_low.at(i), cutVar_TPCnSigmaPr_up.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + } else if (icase == 1) { + cut->AddCut(VarManager::kTPCnSigmaEl_Corr, cutVar_TPCnSigmaEl_low.at(i), cutVar_TPCnSigmaEl_up.at(i), false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPi_Corr, cutVar_TPCnSigmaPi_low.at(i), cutVar_TPCnSigmaPi_up.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaKa, cutVar_TPCnSigmaKa_low.at(i), cutVar_TPCnSigmaKa_up.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPr_Corr, cutVar_TPCnSigmaPr_low.at(i), cutVar_TPCnSigmaPr_up.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + } else if (icase == 2) { + cut->AddCut(VarManager::kTPCnSigmaEl_Corr, cutVar_TPCnSigmaEl_low.at(i), cutVar_TPCnSigmaEl_up.at(i), false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPi_Corr, cutVar_TPCnSigmaPi_low.at(i), cutVar_TPCnSigmaPi_up.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaKa_Corr, cutVar_TPCnSigmaKa_low.at(i), cutVar_TPCnSigmaKa_up.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPr_Corr, cutVar_TPCnSigmaPr_low.at(i), cutVar_TPCnSigmaPr_up.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + } + return cut; + } + } + if (!nameStr.compare(Form("lmee_pp_502TeV_TPC%s", vecPIDcase.at(icase).Data()))) { if (icase == 0) { cut->AddCut(VarManager::kTPCnSigmaEl, -3., 3., false, VarManager::kPin, 0.0, 1e+10, false); @@ -3765,6 +5531,13 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("electronPIDnsigmaVeryVeryLoose2")) { + cut->AddCut(VarManager::kTPCnSigmaEl, -4.0, 4.0); + cut->AddCut(VarManager::kTPCnSigmaPr, 1.5, 3000.0); + cut->AddCut(VarManager::kTPCnSigmaPi, 1.5, 3000.0); + return cut; + } + if (!nameStr.compare("electronPIDnsigmaVeryLoose")) { cut->AddCut(VarManager::kTPCnSigmaEl, -4.0, 4.0); cut->AddCut(VarManager::kTPCnSigmaPr, 2.5, 3000.0); @@ -3786,7 +5559,13 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) cut->AddCut(VarManager::kTPCnSigmaPi, 2.7, 3000.0); return cut; } - + if (!nameStr.compare("electronPIDnsigmaMedium_withLargeTOFPID")) { + cut->AddCut(VarManager::kTPCnSigmaEl, -3.0, 3.0); + cut->AddCut(VarManager::kTPCnSigmaPr, 2.7, 3000.0); + cut->AddCut(VarManager::kTPCnSigmaPi, 2.7, 3000.0); + cut->AddCut(VarManager::kTOFnSigmaEl, -5.0, 5.0); + return cut; + } if (!nameStr.compare("electronPIDnsigmaSkewed")) { cut->AddCut(VarManager::kTPCnSigmaEl, -2.0, 3.0); cut->AddCut(VarManager::kTPCnSigmaPr, 3.5, 3000.0); @@ -3794,6 +5573,13 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("electronPIDnsigmaSkewed_2")) { + cut->AddCut(VarManager::kTPCnSigmaEl, -0.0, 3.0); + cut->AddCut(VarManager::kTPCnSigmaPr, 3.5, 3000.0); + cut->AddCut(VarManager::kTPCnSigmaPi, 3.5, 3000.0); + return cut; + } + if (!nameStr.compare("electronPIDPrKaPiRej")) { cut->AddCut(VarManager::kTPCnSigmaEl, -3.0, 3.0); cut->AddCut(VarManager::kTPCnSigmaPr, -3.0, 3.0, true); @@ -3833,6 +5619,11 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("kaonRejNsigma")) { + cut->AddCut(VarManager::kTPCnSigmaKa, -3.0, 3.0, true); + return cut; + } + if (!nameStr.compare("kaonPIDnsigma2")) { cut->AddCut(VarManager::kTPCnSigmaKa, -2.0, 2.0); return cut; @@ -3844,6 +5635,12 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("kaonPIDnsigma700")) { + cut->AddCut(VarManager::kTPCnSigmaKa, -3.0, 3.0); + cut->AddCut(VarManager::kPin, 0.0, 0.7); + return cut; + } + if (!nameStr.compare("AssocKine")) { cut->AddCut(VarManager::kPt, 1.0, 1000.0); cut->AddCut(VarManager::kEta, -0.9, 0.9); @@ -3876,6 +5673,23 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("pionPID_TPCnTOF")) { + cut->AddCut(VarManager::kTPCnSigmaPi, -3.0, 3.0); + cut->AddCut(VarManager::kTOFnSigmaPi, -3.0, 3.0); + return cut; + } + + if (!nameStr.compare("protonPID_TPCnTOF")) { + cut->AddCut(VarManager::kTPCnSigmaPr, -3.0, 3.0); + cut->AddCut(VarManager::kTOFnSigmaPr, -3.0, 3.0); + return cut; + } + + if (!nameStr.compare("protonPID_TPCnTOF2")) { + cut->AddCut(VarManager::kTPCnSigmaPr, -2.5, 2.5); + return cut; + } + if (!nameStr.compare("tpc_pion_rejection")) { TF1* f1maxPi = new TF1("f1maxPi", "[0]+[1]*x", 0, 10); f1maxPi->SetParameters(85, -50); @@ -3941,6 +5755,11 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("tof_electron_sigma_2")) { + cut->AddCut(VarManager::kTOFnSigmaEl, -3., 3.); + return cut; + } + if (!nameStr.compare("tof_electron_loose")) { cut->AddCut(VarManager::kTOFbeta, 0.95, 1.05, false, VarManager::kPin, 0.0, 1e+10, false); return cut; @@ -4000,6 +5819,46 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + // List of nSigma values for lower and upper edge of TPC: El, Pi and TOF: El PID selections/rejection + std::vector cutVar_TPCnSigmaEl_low = {-4., -4., -4., -2., -3., -2., -3., -4., -2., -4., -3., -3., -3., -4., -3., -3., -4., -3., -4., -4., -3., -4., -3., -3., -2., -4., -4., -3., -4., -2}; + std::vector cutVar_TPCnSigmaEl_up = {2., 3., 2., 2., 2., 2., 2., 4., 2., 2., 4., 3., 3., 2., 4., 2., 2., 4., 3., 4., 2., 4., 2., 3., 2., 3., 4., 2., 3., 2}; + std::vector cutVar_TPCnSigmaPi_low = {-3., -2., -3., -4., -4., -3., -4., -2., -2., -2., -3., -3., -2., -2., -4., -3., -3., -2., -3., -2., -4., -2., -4., -4., -3., -3., -3., -2., -4., -4}; + std::vector cutVar_TPCnSigmaPi_up = {3., 3., 4., 4., 3., 2., 4., 4., 3., 4., 4., 3., 4., 4., 3., 2., 4., 2., 4., 2., 3., 4., 2., 2., 3., 2., 3., 4., 2., 4}; + std::vector cutVar_TOFnSigmaEl_low = {-4., -2., -4., -4., -3., -2., -4., -4., -4., -2., -2., -4., -3., -3., -4., -4., -4., -2., -4., -4., -2., -2., -3., -4., -4., -2., -4., -2., -3., -3}; + std::vector cutVar_TOFnSigmaEl_up = {4., 2., 4., 2., 4., 3., 2., 3., 3., 3., 4., 3., 2., 3., 4., 3., 3., 3., 4., 4., 2., 2., 2., 3., 3., 3., 2., 3., 2., 4}; + + for (unsigned int i = 0; i < cutVar_TOFnSigmaEl_low.size(); i++) { + if (!nameStr.compare(Form("electronPID_TOFnsigma_cutVar%s%i", vecPIDcase.at(icase).Data(), i))) { + if (icase == 0) { + cut->AddCut(VarManager::kTPCnSigmaEl, cutVar_TPCnSigmaEl_low.at(i), cutVar_TPCnSigmaEl_up.at(i), false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPi, cutVar_TPCnSigmaPi_low.at(i), cutVar_TPCnSigmaPi_up.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTOFnSigmaEl, cutVar_TOFnSigmaEl_low.at(i), cutVar_TOFnSigmaEl_up.at(i), false, VarManager::kPin, 0.3, 1e+10, false); + } else if (icase == 1 || icase == 2) { + cut->AddCut(VarManager::kTPCnSigmaEl_Corr, cutVar_TPCnSigmaEl_low.at(i), cutVar_TPCnSigmaEl_up.at(i), false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPi_Corr, cutVar_TPCnSigmaPi_low.at(i), cutVar_TPCnSigmaPi_up.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTOFnSigmaEl, cutVar_TOFnSigmaEl_low.at(i), cutVar_TOFnSigmaEl_up.at(i), false, VarManager::kPin, 0.3, 1e+10, false); + } + return cut; + } + } + + if (!nameStr.compare(Form("electronPID_TPC_TOFnsigma%s", vecPIDcase.at(icase).Data()))) { + if (icase == 0) { // previously known as electronPID_TOFnsigma_tight + cut->AddCut(VarManager::kTPCnSigmaEl, -3., 2., false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPi, -3., 3.5, true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaKa, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPr, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTOFnSigmaEl, -3., 3., false, VarManager::kPin, 0.0, 1e+10, false); + } else if (icase == 1 || icase == 2) { + cut->AddCut(VarManager::kTPCnSigmaEl_Corr, -3., 2., false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPi_Corr, -3., 3.5, true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaKa, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPr_Corr, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTOFnSigmaEl, -3., 3., false, VarManager::kPin, 0.0, 1e+10, false); + } + return cut; + } + if (!nameStr.compare(Form("electronPID_lowB_TOFnsigma%s_strongNSigE", vecPIDcase.at(icase).Data()))) { if (icase == 0) { cut->AddCut(VarManager::kTPCnSigmaEl, -2., 2., false, VarManager::kPin, 0.0, 1e+10, false); @@ -4062,6 +5921,21 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare(Form("electronPID_TOFnsigma%s_tightNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))) { + if (icase == 0) { + cut->AddCut(VarManager::kTPCnSigmaEl, 0., 3., false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPi, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTOFnSigmaEl, -3., 1., false, VarManager::kPin, 0.3, 1e+10, false); + } else if (icase == 1 || icase == 2) { + cut->AddCut(VarManager::kTPCnSigmaEl_Corr, 0., 3., false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPi_Corr, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTOFnSigmaEl, -3., 1., false, VarManager::kPin, 0.3, 1e+10, false); + } + cut->AddCut(VarManager::kTOFbeta, 0., 0.985, true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTOFbeta, 1.015, 999999999., true, VarManager::kPin, 0.0, 1e+10, false); + return cut; + } + if (!nameStr.compare(Form("electronPID_TOFreq%s_strongNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))) { if (icase == 0) { cut->AddCut(VarManager::kTPCnSigmaEl, -1., 2., false, VarManager::kPin, 0.0, 1e+10, false); @@ -4075,6 +5949,19 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare(Form("electronPID_TOFreq%s_tightNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))) { + if (icase == 0) { + cut->AddCut(VarManager::kTPCnSigmaEl, 0., 3., false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPi, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTOFnSigmaEl, -3., 1., false, VarManager::kPin, 0.0, 1e+10, false); + } else if (icase == 1 || icase == 2) { + cut->AddCut(VarManager::kTPCnSigmaEl_Corr, 0., 3., false, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTPCnSigmaPi_Corr, -3., 4., true, VarManager::kPin, 0.0, 1e+10, false); + cut->AddCut(VarManager::kTOFnSigmaEl, -3., 1., false, VarManager::kPin, 0.0, 1e+10, false); + } + return cut; + } + if (!nameStr.compare(Form("lmee_pp_502TeV_TOF%s", vecPIDcase.at(icase).Data()))) { if (icase == 0) { cut->AddCut(VarManager::kTPCnSigmaEl, -3., 3., false, VarManager::kPin, 0.0, 1e+10, false); @@ -4156,6 +6043,14 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("muonMinimalCuts")) { + cut->AddCut(VarManager::kEta, -4.0, -2.5); + cut->AddCut(VarManager::kMuonRAtAbsorberEnd, 17.6, 89.5); + cut->AddCut(VarManager::kMuonPDca, 0.0, 594.0, false, VarManager::kMuonRAtAbsorberEnd, 17.6, 26.5); + cut->AddCut(VarManager::kMuonPDca, 0.0, 324.0, false, VarManager::kMuonRAtAbsorberEnd, 26.5, 89.5); + return cut; + } + if (!nameStr.compare("muonQualityCuts")) { cut->AddCut(VarManager::kEta, -4.0, -2.5); cut->AddCut(VarManager::kMuonRAtAbsorberEnd, 17.6, 89.5); @@ -4166,6 +6061,16 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("muonQualityCuts5SigmaPDCA_Run3")) { + cut->AddCut(VarManager::kEta, -4.0, -2.5); + cut->AddCut(VarManager::kMuonRAtAbsorberEnd, 17.6, 89.5); + cut->AddCut(VarManager::kMuonPDca, 0.0, 500.0, false, VarManager::kMuonRAtAbsorberEnd, 17.6, 26.5); + cut->AddCut(VarManager::kMuonPDca, 0.0, 335.0, false, VarManager::kMuonRAtAbsorberEnd, 26.5, 89.5); + cut->AddCut(VarManager::kMuonChi2, 0.0, 1e6); + cut->AddCut(VarManager::kMuonChi2MatchMCHMID, 0.0, 1e6); // matching MCH-MID + return cut; + } + if (!nameStr.compare("muonQualityCuts10SigmaPDCA")) { cut->AddCut(VarManager::kEta, -4.0, -2.5); cut->AddCut(VarManager::kMuonRAtAbsorberEnd, 17.6, 89.5); @@ -4187,6 +6092,17 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("matchedQualityCutsMFTeta")) { + cut->AddCut(VarManager::kEta, -3.6, -2.5); + cut->AddCut(VarManager::kMuonRAtAbsorberEnd, 17.6, 89.5); + cut->AddCut(VarManager::kMuonPDca, 0.0, 594.0, false, VarManager::kMuonRAtAbsorberEnd, 17.6, 26.5); + cut->AddCut(VarManager::kMuonPDca, 0.0, 324.0, false, VarManager::kMuonRAtAbsorberEnd, 26.5, 89.5); + cut->AddCut(VarManager::kMuonChi2, 0.0, 1e6); + cut->AddCut(VarManager::kMuonChi2MatchMCHMID, 0.0, 1e6); // matching MCH-MID + cut->AddCut(VarManager::kMuonChi2MatchMCHMFT, 0.0, 1e6); // matching MFT-MCH + return cut; + } + if (!nameStr.compare("muonQualityCutsMatchingOnly")) { cut->AddCut(VarManager::kEta, -4.0, -2.5); cut->AddCut(VarManager::kMuonChi2, 0.0, 1e6); @@ -4497,6 +6413,11 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("DipionMassCut2")) { + cut->AddCut(VarManager::kMass, 0.0, 1.0); + return cut; + } + if (!nameStr.compare("pairMassLow1")) { cut->AddCut(VarManager::kMass, 1.0, 1000.0); return cut; @@ -4597,6 +6518,11 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("pairJpsi3")) { + cut->AddCut(VarManager::kMass, 2.92, 3.14); + return cut; + } + if (!nameStr.compare("pairPsi2S")) { cut->AddCut(VarManager::kMass, 3.4, 3.9); return cut; @@ -4608,7 +6534,23 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) } if (!nameStr.compare("pairX3872")) { - cut->AddCut(VarManager::kCosthetaDileptonDitrack, 0.98, 1); + cut->AddCut(VarManager::kQ, 0.0, 0.3); + return cut; + } + + if (!nameStr.compare("pairX3872_2")) { + cut->AddCut(VarManager::kQuadDefaultDileptonMass, 3.0, 5.0); + cut->AddCut(VarManager::kQ, 0.0, 0.5); + cut->AddCut(VarManager::kDeltaR, 0.0, 5.0); + cut->AddCut(VarManager::kQuadPt, 5.0, 40.0); + return cut; + } + + if (!nameStr.compare("pairX3872_3")) { + cut->AddCut(VarManager::kQuadDefaultDileptonMass, 3.0, 5.0); + cut->AddCut(VarManager::kQ, 0.0, 0.5); + cut->AddCut(VarManager::kDeltaR, 0.0, 5.0); + cut->AddCut(VarManager::kQuadPt, 0.0, 1000.0); return cut; } @@ -4632,6 +6574,11 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("pairPtLow5")) { + cut->AddCut(VarManager::kPt, 0.8, 1000.0); + return cut; + } + if (!nameStr.compare("pairRapidityForward")) { cut->AddCut(VarManager::kRap, 2.5, 4.0); return cut; @@ -4667,6 +6614,48 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("pairLxyzProjected3sigma")) { + cut->AddCut(VarManager::kVertexingLxyzProjected, 0.015, 10.); + return cut; + } + + if (!nameStr.compare("pairTauxyzProjected1")) { + cut->AddCut(VarManager::kVertexingTauxyzProjected, 0.0005, 10.); + return cut; + } + + if (!nameStr.compare("pairTauxyzProjected1sigma")) { + cut->AddCut(VarManager::kVertexingTauxyzProjected, 0.003, 10.); + return cut; + } + + if (!nameStr.compare("pairLxyProjected3sigmaLambdacCand")) { + TF1* f1minLxyProjected = new TF1("f1minLxyProjected", "[0]+[1]*x", 0., 20.); + f1minLxyProjected->SetParameters(0.0065, -0.00023); + cut->AddCut(VarManager::kVertexingLxyProjected, f1minLxyProjected, 1., false, VarManager::kPt, 0., 20.); + return cut; + } + + if (!nameStr.compare("pairLxyProjected3sigmaDplusCand")) { + cut->AddCut(VarManager::kVertexingLxyProjected, 0.009, 10.); + return cut; + } + + if (!nameStr.compare("pairCosPointingPos")) { + cut->AddCut(VarManager::kCosPointingAngle, 0.9, 1000.); + return cut; + } + + if (!nameStr.compare("pairCosPointingNeg90")) { + cut->AddCut(VarManager::kCosPointingAngle, -1000., -0.9); + return cut; + } + + if (!nameStr.compare("pairCosPointingNeg85")) { + cut->AddCut(VarManager::kCosPointingAngle, -1000., -0.85); + return cut; + } + // ------------------------------------------------------------------------------------------------- // // Below are a list of single electron single muon and pair selection in order or optimize the trigger @@ -4736,6 +6725,396 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) } delete cut; - LOGF(info, Form("Did not find cut %s", cutName)); + LOGF(fatal, Form("Did not find cut %s", cutName)); return nullptr; } + +//________________________________________________________________________________________________ +std::vector o2::aod::dqcuts::GetCutsFromJSON(const char* json) +{ + // + // configure cuts using a json file + // + + std::vector cuts; + // AnalysisCut* cuts[100]; + LOG(info) << "========================================== interpreting JSON for analysis cuts"; + LOG(info) << "JSON string: " << json; + + // + // Create a vector of AnalysisCuts from a JSON formatted string + // The JSON is expected to contain a list of objects, with each object containing the fields needed + // to define either an AnalysisCut or an AnalysisCompositeCut + rapidjson::Document document; + + // Check that the json is parsed correctly + rapidjson::ParseResult ok = document.Parse(json); + if (!ok) { + LOG(fatal) << "JSON parse error: " << rapidjson::GetParseErrorFunc(ok.Code()) << " (" << ok.Offset() << ")"; + return cuts; + } + + // The json is expected to contain a list of objects, each of which should provide the configuration of a cut + for (rapidjson::Value::ConstMemberIterator it = document.MemberBegin(); it != document.MemberEnd(); it++) { + + const char* cutName = it->name.GetString(); + LOG(info) << "=================================================== Configuring cut " << cutName; + const auto& cut = it->value; + + // Detect if this is an AnalysisCut or a composite cut + bool isAnalysisCut = false; + bool isAnalysisCompositeCut = false; + if (cut.HasMember("type")) { + TString typeStr = cut.FindMember("type")->value.GetString(); + if (typeStr.CompareTo("AnalysisCut") == 0) { + LOG(debug) << "This is an AnalysisCut"; + isAnalysisCut = true; + } + if (typeStr.CompareTo("AnalysisCompositeCut") == 0) { + LOG(debug) << "This is an AnalysisCompositeCut"; + isAnalysisCompositeCut = true; + } + } + if (!(isAnalysisCut || isAnalysisCompositeCut)) { + LOG(fatal) << "Member is neither an AnalysisCut or AnalysisCompositeCut"; + return cuts; + } + + // Parse the object, construct the cut and add it to the return vector + if (isAnalysisCut) { + AnalysisCut* anaCut = ParseJSONAnalysisCut(&cut, cutName); + if (anaCut != nullptr) { + cuts.push_back(anaCut); + } else { + LOG(fatal) << "Something went wrong in creating the AnalysisCut " << cutName; + return cuts; + } + } + if (isAnalysisCompositeCut) { + AnalysisCompositeCut* anaCut = ParseJSONAnalysisCompositeCut(&cut, cutName); + if (anaCut != nullptr) { + cuts.push_back(anaCut); + } else { + LOG(fatal) << "Something went wrong in creating the AnalysisCompositeCut " << cutName; + return cuts; + } + } + } + + return cuts; +} + +//________________________________________________________________________________________________ +template +bool o2::aod::dqcuts::ValidateJSONAnalysisCut(T cut) +{ + // + // Validate cut definition in JSON file + // + // The type field is compulsory + if (!cut->HasMember("type")) { + LOG(fatal) << "Missing type information"; + return false; + } + TString typeStr = cut->FindMember("type")->value.GetString(); + if (typeStr.CompareTo("AnalysisCut") != 0) { + LOG(fatal) << "Type is not AnalysisCut"; + return false; + } + + return true; +} + +//________________________________________________________________________________________________ +template +bool o2::aod::dqcuts::ValidateJSONAddCut(T addcut, bool isSimple) +{ + // + // Validate AddCut definition in JSON file + // + + // Check if this AddCut is adding an analysis cut (if the mother is a composite cut) + bool isAnalysisCut = false; + if (addcut->HasMember("type")) { + isAnalysisCut = true; + } + // check if this is adding a basic variable range cut + bool isBasicCut = false; + if (addcut->HasMember("var") && addcut->HasMember("cutLow") && addcut->HasMember("cutHigh")) { + isBasicCut = true; + } + + // if neither of the two option is true, then something is wrong + if (!(isBasicCut || isAnalysisCut)) { + LOG(fatal) << "This is neither adding an AnalysisCut nor a basic variable range cut"; + return false; + } + if (isSimple && isAnalysisCut) { + LOG(fatal) << "One cannot call AddCut with an AnalysisCut in this case"; + return false; + } + if (!isSimple && isAnalysisCut) { + return true; + } + + // check that the variable to cut on is a valid one (implemented in the VarManager) + const char* var = addcut->FindMember("var")->value.GetString(); + if (VarManager::fgVarNamesMap.find(var) == VarManager::fgVarNamesMap.end()) { + LOG(fatal) << "Bad cut variable (" << var << ") specified for this AddCut"; + return false; + } + + // check whether the specified cut low and high are numbers or functions + bool cutLow_isNumber = addcut->FindMember("cutLow")->value.IsNumber(); + bool cutHigh_isNumber = addcut->FindMember("cutHigh")->value.IsNumber(); + if (!cutLow_isNumber) { + auto& cutLow = addcut->FindMember("cutLow")->value; + if (!cutLow.HasMember("funcName") || !cutLow.HasMember("funcBody") || + !cutLow.HasMember("xLow") || !cutLow.HasMember("xHigh")) { + LOG(fatal) << "Missing fields for the cutLow TF1 definition"; + return false; + } + } + if (!cutHigh_isNumber) { + auto& cutHigh = addcut->FindMember("cutHigh")->value; + if (!cutHigh.HasMember("funcName") || !cutHigh.HasMember("funcBody") || + !cutHigh.HasMember("xLow") || !cutHigh.HasMember("xHigh")) { + LOG(fatal) << "Missing fields for the cutLow TF1 definition"; + return false; + } + } + if (!cutHigh_isNumber || !cutLow_isNumber) { + if (!addcut->HasMember("dependentVar") || !addcut->HasMember("depCutLow") || !addcut->HasMember("depCutHigh")) { + LOG(fatal) << "For cutLow or cutHigh as a TF1, the definition of the dependentVar and range are also required"; + return false; + } + const char* depVar = addcut->FindMember("dependentVar")->value.GetString(); + if (VarManager::fgVarNamesMap.find(depVar) == VarManager::fgVarNamesMap.end()) { + LOG(fatal) << "Bad cut variable (" << depVar << ") specified for the dependentVar"; + return false; + } + } + if (addcut->HasMember("dependentVar1") && cutLow_isNumber && cutHigh_isNumber) { + const char* depVar1 = addcut->FindMember("dependentVar1")->value.GetString(); + if (VarManager::fgVarNamesMap.find(depVar1) == VarManager::fgVarNamesMap.end()) { + LOG(fatal) << "Bad cut variable (" << depVar1 << ") specified for the dependentVar"; + return false; + } + if (!addcut->HasMember("depCut2Low") || !addcut->HasMember("depCut2High")) { + LOG(fatal) << "dependentVar2 specified, but not its range"; + return false; + } + } + if (addcut->HasMember("dependentVar2")) { + const char* depVar2 = addcut->FindMember("dependentVar2")->value.GetString(); + if (VarManager::fgVarNamesMap.find(depVar2) == VarManager::fgVarNamesMap.end()) { + LOG(fatal) << "Bad cut variable (" << depVar2 << ") specified for the dependentVar2"; + return false; + } + if (!addcut->HasMember("depCut2Low") || !addcut->HasMember("depCut2High")) { + LOG(fatal) << "dependentVar2 specified, but not its range"; + return false; + } + } + + return true; +} + +//_______________________________________________________________________________________________ +template +AnalysisCut* o2::aod::dqcuts::ParseJSONAnalysisCut(T cut, const char* cutName) +{ + + // Parse the json object and build an AnalysisCut + if (!ValidateJSONAnalysisCut(cut)) { + LOG(fatal) << "AnalysisCut not properly defined in the JSON file. Skipping it"; + return nullptr; + } + + // If the analysis cut has the field "library", its just loaded from the preexisting cuts in the library and return + if (cut->HasMember("library")) { + return GetAnalysisCut(cut->FindMember("library")->value.GetString()); + } + + // construct the AnalysisCut object and add the AddCuts + AnalysisCut* retCut = new AnalysisCut(cutName, cut->HasMember("library") ? cut->FindMember("title")->value.GetString() : ""); + + // loop over all the members for this cut and configure the AddCut objects + for (rapidjson::Value::ConstMemberIterator it = cut->MemberBegin(); it != cut->MemberEnd(); it++) { + + TString itName = it->name.GetString(); + + if (itName.Contains("AddCut")) { + + LOG(debug) << "Parsing " << itName.Data(); + const auto& addcut = it->value; + if (!ValidateJSONAddCut(&addcut, true)) { + LOG(fatal) << "AddCut statement not properly defined"; + return nullptr; + } + + const char* var = addcut.FindMember("var")->value.GetString(); + LOG(info) << "var " << var; + bool cutLow_isNumber = addcut.FindMember("cutLow")->value.IsNumber(); + LOG(info) << "cutLow_isNumber " << cutLow_isNumber; + bool cutHigh_isNumber = addcut.FindMember("cutHigh")->value.IsNumber(); + LOG(info) << "cutHigh_isNumber " << cutHigh_isNumber; + + bool exclude = (addcut.HasMember("exclude") ? addcut.FindMember("exclude")->value.GetBool() : false); + LOG(info) << "exclude " << exclude; + const char* dependentVar = (addcut.HasMember("dependentVar") ? addcut.FindMember("dependentVar")->value.GetString() : "kNothing"); + LOG(info) << "dependentVar " << dependentVar; + double depCutLow = (addcut.HasMember("depCutLow") ? addcut.FindMember("depCutLow")->value.GetDouble() : 0.0); + LOG(info) << "depCutLow " << depCutLow; + double depCutHigh = (addcut.HasMember("depCutHigh") ? addcut.FindMember("depCutHigh")->value.GetDouble() : 10.0); + LOG(info) << "depCutHigh " << depCutHigh; + bool depCutExclude = (addcut.HasMember("depCutExclude") ? addcut.FindMember("depCutExclude")->value.GetBool() : false); + LOG(info) << "depCutExclude " << depCutExclude; + const char* dependentVar2 = (addcut.HasMember("dependentVar2") ? addcut.FindMember("dependentVar2")->value.GetString() : "kNothing"); + LOG(info) << "dependentVar2 " << dependentVar2; + double depCut2Low = (addcut.HasMember("depCut2Low") ? addcut.FindMember("depCut2Low")->value.GetDouble() : 0.0); + LOG(info) << "depCut2Low " << depCut2Low; + double depCut2High = (addcut.HasMember("depCut2High") ? addcut.FindMember("depCut2High")->value.GetDouble() : 10.0); + LOG(info) << "depCut2High " << depCut2High; + bool depCut2Exclude = (addcut.HasMember("depCut2Exclude") ? addcut.FindMember("depCut2Exclude")->value.GetBool() : false); + LOG(info) << "depCut2Exclude " << depCut2Exclude; + + TF1* cutLowFunc = nullptr; + TF1* cutHighFunc = nullptr; + double cutLowNumber = 0.0; + double cutHighNumber = 0.0; + if (cutLow_isNumber) { + cutLowNumber = addcut.FindMember("cutLow")->value.GetDouble(); + LOG(info) << "cutLowNumber " << cutLowNumber; + } else { + auto& cutLow = addcut.FindMember("cutLow")->value; + cutLowFunc = new TF1(cutLow.FindMember("funcName")->value.GetString(), cutLow.FindMember("funcBody")->value.GetString(), + cutLow.FindMember("xLow")->value.GetDouble(), cutLow.FindMember("xHigh")->value.GetDouble()); + LOG(info) << "cutLowFunc " << cutLow.FindMember("funcName")->value.GetString() << ", " << cutLow.FindMember("funcBody")->value.GetString() + << ", " << cutLow.FindMember("xLow")->value.GetDouble() << ", " << cutLow.FindMember("xHigh")->value.GetDouble(); + } + if (cutHigh_isNumber) { + cutHighNumber = addcut.FindMember("cutHigh")->value.GetDouble(); + LOG(info) << "cutHighNumber " << cutHighNumber; + } else { + auto& cutHigh = addcut.FindMember("cutHigh")->value; + cutHighFunc = new TF1(cutHigh.FindMember("funcName")->value.GetString(), cutHigh.FindMember("funcBody")->value.GetString(), + cutHigh.FindMember("xLow")->value.GetDouble(), cutHigh.FindMember("xHigh")->value.GetDouble()); + LOG(info) << "cutHighFunc " << cutHigh.FindMember("funcName")->value.GetString() << ", " << cutHigh.FindMember("funcBody")->value.GetString() + << ", " << cutHigh.FindMember("xLow")->value.GetDouble() << ", " << cutHigh.FindMember("xHigh")->value.GetDouble(); + } + if (cutLow_isNumber) { + if (cutHigh_isNumber) { + retCut->AddCut(VarManager::fgVarNamesMap[var], cutLowNumber, cutHighNumber, exclude, + VarManager::fgVarNamesMap[dependentVar], depCutLow, depCutHigh, depCutExclude, + VarManager::fgVarNamesMap[dependentVar2], depCut2Low, depCut2High, depCut2Exclude); + } else { + retCut->AddCut(VarManager::fgVarNamesMap[var], cutLowNumber, cutHighFunc, exclude, + VarManager::fgVarNamesMap[dependentVar], depCutLow, depCutHigh, depCutExclude, + VarManager::fgVarNamesMap[dependentVar2], depCut2Low, depCut2High, depCut2Exclude); + } + } else { + if (cutHigh_isNumber) { + retCut->AddCut(VarManager::fgVarNamesMap[var], cutLowFunc, cutHighNumber, exclude, + VarManager::fgVarNamesMap[dependentVar], depCutLow, depCutHigh, depCutExclude, + VarManager::fgVarNamesMap[dependentVar2], depCut2Low, depCut2High, depCut2Exclude); + } else { + retCut->AddCut(VarManager::fgVarNamesMap[var], cutLowFunc, cutHighFunc, exclude, + VarManager::fgVarNamesMap[dependentVar], depCutLow, depCutHigh, depCutExclude, + VarManager::fgVarNamesMap[dependentVar2], depCut2Low, depCut2High, depCut2Exclude); + } + } + } + } + + return retCut; +} + +//_______________________________________________________________________________________________ +template +bool o2::aod::dqcuts::ValidateJSONAnalysisCompositeCut(T cut) +{ + // + // Validate composite cut definition in JSON file + // + if (!cut->HasMember("type")) { + LOG(fatal) << "Missing type field"; + return false; + } + if (!(cut->HasMember("library") || cut->HasMember("useAND"))) { + LOG(fatal) << "Either library or useAND fields are required in an AnalysisCompositeCut definition"; + } + TString typeStr = cut->FindMember("type")->value.GetString(); + if (typeStr.CompareTo("AnalysisCompositeCut") != 0) { + LOG(fatal) << "Type is not AnalysisCompositeCut"; + return false; + } + + return true; +} + +//_______________________________________________________________________________________________ +template +AnalysisCompositeCut* o2::aod::dqcuts::ParseJSONAnalysisCompositeCut(T cut, const char* cutName) +{ + + // Configure an AnalysisCompositeCut + if (!ValidateJSONAnalysisCompositeCut(cut)) { + LOG(fatal) << "Composite Cut not properly defined in the JSON file. Skipping it"; + return nullptr; + } + + if (cut->HasMember("library")) { + return GetCompositeCut(cut->FindMember("library")->value.GetString()); + } + + AnalysisCompositeCut* retCut = new AnalysisCompositeCut(cutName, cut->HasMember("library") ? cut->FindMember("title")->value.GetString() : "", cut->FindMember("useAND")->value.GetBool()); + + // Loop to find AddCut objects + for (rapidjson::Value::ConstMemberIterator it = cut->MemberBegin(); it != cut->MemberEnd(); it++) { + + TString itName = it->name.GetString(); + + if (itName.Contains("AddCut")) { + + LOG(debug) << "Parsing " << itName.Data(); + const auto& addcut = it->value; + if (!ValidateJSONAddCut(&addcut, false)) { + LOG(fatal) << "AddCut statement not properly defined"; + return nullptr; + } + + // For an AnalysisCompositeCut, one can call AddCut with either an AnalysisCut or another AnalysisCompositeCut + bool isAnalysisCut = false; + bool isAnalysisCompositeCut = false; + TString typeStr = addcut.FindMember("type")->value.GetString(); + if (typeStr.CompareTo("AnalysisCut") == 0) { + isAnalysisCut = true; + } + if (typeStr.CompareTo("AnalysisCompositeCut") == 0) { + isAnalysisCompositeCut = true; + } + + // Add an AnalysisCut + if (isAnalysisCut) { + AnalysisCut* cutMember = ParseJSONAnalysisCut(&addcut, itName.Data()); + if (cutMember != nullptr) { + retCut->AddCut(cutMember); + } else { + return nullptr; + } + } + // Add an AnalysisCompositeCut + if (isAnalysisCompositeCut) { + AnalysisCompositeCut* cutMember = ParseJSONAnalysisCompositeCut(&addcut, itName.Data()); + if (cutMember != nullptr) { + retCut->AddCut(cutMember); + } else { + return nullptr; + } + } + } + } + + return retCut; +} diff --git a/PWGDQ/Core/CutsLibrary.h b/PWGDQ/Core/CutsLibrary.h index 59079166b29..c6ad4caded2 100644 --- a/PWGDQ/Core/CutsLibrary.h +++ b/PWGDQ/Core/CutsLibrary.h @@ -21,12 +21,103 @@ #include "PWGDQ/Core/AnalysisCompositeCut.h" #include "PWGDQ/Core/VarManager.h" +// /////////////////////////////////////////////// +// These are the Cuts used in the CEFP Task // +// to select tracks in the event selection // +// /////////////////////////////////////////////// +// +// Electron 2022 cuts : +// - Single e pT > 1.0 GeV/c +// - Single e eta = [-0.9 ; 0.9] +// - Is SPD Any : yes +// - TPC chi2 < 4.0 +// - TPC N Clusters = [70 ; 160] +// - n-sigma_e = [-4.0 ; 4.0] +// - n-sigma_pi > 2.5 +// - n-sigma_pr > 2.5 +// - PID post-calibration : Yes +// - Track-collision association : No +// For the dielectron Cut : pairNoCut +// mee > 0 GeV/c2 +// +// Electron 2023 & 2024 cuts : +// - Single e pT > 1.0 GeV/c +// - Single e eta = [-0.9 ; 0.9] +// - Is SPD Any : yes +// - TPC chi2 < 4.0 +// - TPC N Clusters = [70 ; 160] +// - n-sigma_e = [-4.0 ; 4.0] +// - n-sigma_pi > 2.5 +// - n-sigma_pr > 2.5 +// - PID post-calibration : No +// - Track-collision association : Yes +// For the dielectron Cut : pairMassLow5 +// mee > 1.8 GeV/c2 +// +// Low Mass electrons 2023 & 2024 cuts : +// - Single e pT > 0.4 GeV/c +// - Single e eta = [-0.8 ; 0.8] +// - Is SPD Any : yes +// - TPC chi2 < 4.0 +// - ITS chi2 < 6.0 +// - TPC N Clusters = [70 ; 170] +// - ITS N Clusters = [3.5 ; 7.5] +// - n-sigma_e = [-4.0 ; 4.0] +// - n-sigma_pi > 3.5 for 0.0 < pIN < 2.0 +// - n-sigma_pr > 2.5 for 2.0 < pIN < 1e+10 +// - n-sigma_e TOF = [-4.0 ; 4.0] for 0.3 < pIN < 1e+10 +// - PID post-calibration : No +// - Track-collision association : Yes +// For the dielectron Cut : +// - Intermediate Mass Range ee trigger : mee > 1.3 GeV/c2 (pairMass1_3) +// - High Mass Range ee trigger : mee > 3.5 GeV/c2 (pairMassLow12) +// +// Muons Cuts 2022 : +// - Single mu Low (High) pT > 0.7 (4.0) GeV/c +// - Single mu eta = [-4.0 ; -2.5] +// - Rabs = [17.6 ; 89.5] +// - p x DCA = ~6 sigma_[p x DCA] +// - Matching MCH-MID : No +// - Track-collision association : No +// For the dimuon cut +// m_mumu > 1.8 GeV/c2 +// +// Muons Cuts 2023 & 2024 : +// - Single mu Low (High) pT > 0.7 (20.0) GeV/c +// - Single mu eta = [-4.0 ; -2.5] +// - Rabs = [17.6 ; 89.5] +// - p x DCA = ~10 sigma_[p x DCA] +// - Matching MCH-MID : Yes +// - Track-collision association : Yes +// For the dimuon cut +// m_mumu > 1.8 GeV/c2 +// +// +// /////////////////////////////////////////////// +// End of Cuts for CEFP // +// /////////////////////////////////////////////// + +#include "rapidjson/document.h" + namespace o2::aod { namespace dqcuts { AnalysisCompositeCut* GetCompositeCut(const char* cutName); AnalysisCut* GetAnalysisCut(const char* cutName); + +std::vector GetCutsFromJSON(const char* json); +// AnalysisCut** GetCutsFromJSON(const char* json); +template +bool ValidateJSONAnalysisCut(T cut); +template +bool ValidateJSONAddCut(T cut, bool isSimple); +template +AnalysisCut* ParseJSONAnalysisCut(T cut, const char* cutName); +template +bool ValidateJSONAnalysisCompositeCut(T cut); +template +AnalysisCompositeCut* ParseJSONAnalysisCompositeCut(T key, const char* cutName); } // namespace dqcuts } // namespace o2::aod diff --git a/PWGDQ/Core/HistogramManager.cxx b/PWGDQ/Core/HistogramManager.cxx index a3834f981a3..fb5ce5f8d65 100644 --- a/PWGDQ/Core/HistogramManager.cxx +++ b/PWGDQ/Core/HistogramManager.cxx @@ -14,6 +14,9 @@ #include #include #include +#include +#include +#include #include "Framework/Logger.h" using namespace std; @@ -121,7 +124,7 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co int nYbins, double ymin, double ymax, int varY, int nZbins, double zmin, double zmax, int varZ, const char* xLabels, const char* yLabels, const char* zLabels, - int varT, int varW) + int varT, int varW, bool isdouble, bool isFillLabelx) { // // add a histogram (this function can define TH1F,TH2F,TH3F,TProfile,TProfile2D, and TProfile3D) @@ -137,7 +140,7 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co } // check whether this histogram name was used before if (hList->FindObject(hname)) { - LOG(warn) << "HistogramManager::AddHistogram(): Histogram " << hname << " already exists"; + LOG(warn) << "HistogramManager::AddHistogram(): Histogram " << hname << " already exists in class " << histClass; return; } @@ -179,7 +182,8 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co varVector.push_back(varX); // variables on each axis varVector.push_back(varY); varVector.push_back(varZ); - varVector.push_back(varT); // variable used for profiling in case of TProfile3D + varVector.push_back(varT); // variable used for profiling in case of TProfile3D + varVector.push_back(isFillLabelx ? 1 : 0); // whether to fill with the x-axis labels std::list varList = fVariablesMap[histClass]; varList.push_back(varVector); fVariablesMap[histClass] = varList; @@ -188,7 +192,11 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co TH1* h = nullptr; switch (dimension) { case 1: // TH1F - h = new TH1F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xmin, xmax); + if (!isdouble) { + h = new TH1F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xmin, xmax); + } else { + h = new TH1D(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xmin, xmax); + } fBinsAllocated += nXbins + 2; // TODO: possibly make the call of Sumw2() optional for all histograms h->Sumw2(); @@ -217,7 +225,11 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co (reinterpret_cast(h))->BuildOptions(0., 0., "s"); } } else { - h = new TH2F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xmin, xmax, nYbins, ymin, ymax); + if (!isdouble) { + h = new TH2F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xmin, xmax, nYbins, ymin, ymax); + } else { + h = new TH2D(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xmin, xmax, nYbins, ymin, ymax); + } fBinsAllocated += (nXbins + 2) * (nYbins + 2); h->Sumw2(); } @@ -268,7 +280,11 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co } } } else { // TH3F - h = new TH3F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xmin, xmax, nYbins, ymin, ymax, nZbins, zmin, zmax); + if (!isdouble) { + h = new TH3F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xmin, xmax, nYbins, ymin, ymax, nZbins, zmin, zmax); + } else { + h = new TH3D(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xmin, xmax, nYbins, ymin, ymax, nZbins, zmin, zmax); + } fBinsAllocated += (nXbins + 2) * (nYbins + 2) * (nZbins + 2); h->Sumw2(); } @@ -318,7 +334,7 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co int nYbins, double* ybins, int varY, int nZbins, double* zbins, int varZ, const char* xLabels, const char* yLabels, const char* zLabels, - int varT, int varW) + int varT, int varW, bool isdouble, bool isFillLabelx) { // // add a histogram @@ -376,7 +392,8 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co varVector.push_back(varX); // variables on each axis varVector.push_back(varY); varVector.push_back(varZ); - varVector.push_back(varT); // variable used for profiling in case of TProfile3D + varVector.push_back(varT); // variable used for profiling in case of TProfile3D + varVector.push_back(isFillLabelx ? 1 : 0); // whether to fill with the x-axis labels std::list varList = fVariablesMap[histClass]; varList.push_back(varVector); fVariablesMap[histClass] = varList; @@ -384,7 +401,11 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co TH1* h = nullptr; switch (dimension) { case 1: - h = new TH1F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xbins); + if (!isdouble) { + h = new TH1F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xbins); + } else { + h = new TH1D(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xbins); + } fBinsAllocated += nXbins + 2; h->Sumw2(); if (fVariableNames[varX][0]) { @@ -410,7 +431,11 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co (reinterpret_cast(h))->BuildOptions(0., 0., "s"); } } else { - h = new TH2F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xbins, nYbins, ybins); + if (!isdouble) { + h = new TH2F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xbins, nYbins, ybins); + } else { + h = new TH2D(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xbins, nYbins, ybins); + } fBinsAllocated += (nXbins + 2) * (nYbins + 2); h->Sumw2(); } @@ -461,7 +486,11 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co } } } else { - h = new TH3F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xbins, nYbins, ybins, nZbins, zbins); + if (!isdouble) { + h = new TH3F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xbins, nYbins, ybins, nZbins, zbins); + } else { + h = new TH3D(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xbins, nYbins, ybins, nZbins, zbins); + } fBinsAllocated += (nXbins + 2) * (nYbins + 2) * (nZbins + 2); h->Sumw2(); } @@ -508,7 +537,7 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co //_________________________________________________________________ void HistogramManager::AddHistogram(const char* histClass, const char* hname, const char* title, int nDimensions, int* vars, int* nBins, double* xmin, double* xmax, - TString* axLabels, int varW, bool useSparse) + TString* axLabels, int varW, bool useSparse, bool isdouble) { // // add a multi-dimensional histogram THnF or THnFSparseF @@ -535,6 +564,13 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co fUsedVars[varW] = kTRUE; } + for (int i = 0; i < nDimensions; i++) { + if (xmax[i] <= xmin[i]) { + LOG(warn) << "HistogramManager::AddHistogram(): Histogram " << hname << " has wrong axes ranges for dimension " << i + << ", (xmin/xmax): " << xmin[i] << " / " << xmax[i]; + } + } + // encode needed variable identifiers in a vector and push it to the std::list corresponding to the current histogram list std::vector varVector; varVector.push_back(0); // whether the histogram is a profile @@ -549,10 +585,18 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co uint32_t nbins = 1; THnBase* h = nullptr; - if (useSparse) { - h = new THnSparseF(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nDimensions, nBins, xmin, xmax); + if (!isdouble) { + if (useSparse) { + h = new THnSparseF(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nDimensions, nBins, xmin, xmax); + } else { + h = new THnF(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nDimensions, nBins, xmin, xmax); + } } else { - h = new THnF(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nDimensions, nBins, xmin, xmax); + if (useSparse) { + h = new THnSparseD(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nDimensions, nBins, xmin, xmax); + } else { + h = new THnD(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nDimensions, nBins, xmin, xmax); + } } h->Sumw2(); @@ -573,10 +617,18 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co fUsedVars[vars[idim]] = kTRUE; } - if (useSparse) { - hList->Add(reinterpret_cast(h)); + if (!isdouble) { + if (useSparse) { + hList->Add(reinterpret_cast(h)); + } else { + hList->Add(reinterpret_cast(h)); + } } else { - hList->Add(reinterpret_cast(h)); + if (useSparse) { + hList->Add(reinterpret_cast(h)); + } else { + hList->Add(reinterpret_cast(h)); + } } fBinsAllocated += nbins; @@ -585,7 +637,7 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co //_________________________________________________________________ void HistogramManager::AddHistogram(const char* histClass, const char* hname, const char* title, int nDimensions, int* vars, TArrayD* binLimits, - TString* axLabels, int varW, bool useSparse) + TString* axLabels, int varW, bool useSparse, bool isdouble) { // // add a multi-dimensional histogram THnF or THnSparseF with equal or variable bin widths @@ -636,10 +688,18 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co // initialize the THn with equal spaced bins THnBase* h = nullptr; - if (useSparse) { - h = new THnSparseF(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nDimensions, nBins, xmin, xmax); + if (!isdouble) { + if (useSparse) { + h = new THnSparseF(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nDimensions, nBins, xmin, xmax); + } else { + h = new THnF(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nDimensions, nBins, xmin, xmax); + } } else { - h = new THnF(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nDimensions, nBins, xmin, xmax); + if (useSparse) { + h = new THnSparseD(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nDimensions, nBins, xmin, xmax); + } else { + h = new THnD(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nDimensions, nBins, xmin, xmax); + } } // rebin the axes according to the user requested binning for (int idim = 0; idim < nDimensions; ++idim) { @@ -664,10 +724,18 @@ void HistogramManager::AddHistogram(const char* histClass, const char* hname, co } fUsedVars[vars[idim]] = kTRUE; } - if (useSparse) { - hList->Add(reinterpret_cast(h)); + if (!isdouble) { + if (useSparse) { + hList->Add(reinterpret_cast(h)); + } else { + hList->Add(reinterpret_cast(h)); + } } else { - hList->Add(reinterpret_cast(h)); + if (useSparse) { + hList->Add(reinterpret_cast(h)); + } else { + hList->Add(reinterpret_cast(h)); + } } fBinsAllocated += bins; } @@ -698,6 +766,7 @@ void HistogramManager::FillHistClass(const char* className, Float_t* values) bool isTHn; int dimension = 0; bool isSparse = kFALSE; + bool isFillLabelx = kFALSE; // TODO: At the moment, maximum 20 dimensions are foreseen for the THn histograms. We should make this more dynamic // But maybe its better to have it like to avoid dynamically allocating this array in the histogram loop double fillValues[20] = {0.0}; @@ -727,6 +796,7 @@ void HistogramManager::FillHistClass(const char* className, Float_t* values) varY = varIter->at(4); varZ = varIter->at(5); varT = varIter->at(6); + isFillLabelx = (varIter->at(7) == 1 ? true : false); } if (!isTHn) { @@ -734,15 +804,31 @@ void HistogramManager::FillHistClass(const char* className, Float_t* values) case 1: if (isProfile) { if (varW > kNothing) { - (reinterpret_cast(h))->Fill(values[varX], values[varY], values[varW]); + if (isFillLabelx) { + (reinterpret_cast(h))->Fill(Form("%d", static_cast(values[varX])), values[varY], values[varW]); + } else { + (reinterpret_cast(h))->Fill(values[varX], values[varY], values[varW]); + } } else { - (reinterpret_cast(h))->Fill(values[varX], values[varY]); + if (isFillLabelx) { + (reinterpret_cast(h))->Fill(Form("%d", static_cast(values[varX])), values[varY]); + } else { + (reinterpret_cast(h))->Fill(values[varX], values[varY]); + } } } else { if (varW > kNothing) { - (reinterpret_cast(h))->Fill(values[varX], values[varW]); + if (isFillLabelx) { + (reinterpret_cast(h))->Fill(Form("%d", static_cast(values[varX])), values[varW]); + } else { + (reinterpret_cast(h))->Fill(values[varX], values[varW]); + } } else { - (reinterpret_cast(h))->Fill(values[varX]); + if (isFillLabelx) { + (reinterpret_cast(h))->Fill(Form("%d", static_cast(values[varX])), 1.); + } else { + (reinterpret_cast(h))->Fill(values[varX]); + } } } break; @@ -755,9 +841,17 @@ void HistogramManager::FillHistClass(const char* className, Float_t* values) } } else { if (varW > kNothing) { - (reinterpret_cast(h))->Fill(values[varX], values[varY], values[varW]); + if (isFillLabelx) { + (reinterpret_cast(h))->Fill(Form("%d", static_cast(values[varX])), values[varY], values[varW]); + } else { + (reinterpret_cast(h))->Fill(values[varX], values[varY], values[varW]); + } } else { - (reinterpret_cast(h))->Fill(values[varX], values[varY]); + if (isFillLabelx) { + (reinterpret_cast(h))->Fill(Form("%d", static_cast(values[varX])), values[varY], 1.); + } else { + (reinterpret_cast(h))->Fill(values[varX], values[varY]); + } } } break; @@ -770,9 +864,9 @@ void HistogramManager::FillHistClass(const char* className, Float_t* values) } } else { if (varW > kNothing) { - (reinterpret_cast(h))->Fill(values[varX], values[varY], values[varZ], values[varW]); + (reinterpret_cast(h))->Fill(values[varX], values[varY], values[varZ], values[varW]); } else { - (reinterpret_cast(h))->Fill(values[varX], values[varY], values[varZ]); + (reinterpret_cast(h))->Fill(values[varX], values[varY], values[varZ]); } } break; @@ -784,19 +878,19 @@ void HistogramManager::FillHistClass(const char* className, Float_t* values) } else { if (varW > kNothing) { if (isSparse) { - (reinterpret_cast(h))->Fill(fillValues, values[varW]); + (reinterpret_cast(h))->Fill(fillValues, values[varW]); } else { - (reinterpret_cast(h))->Fill(fillValues, values[varW]); + (reinterpret_cast(h))->Fill(fillValues, values[varW]); } } else { if (isSparse) { - (reinterpret_cast(h))->Fill(fillValues); + (reinterpret_cast(h))->Fill(fillValues); } else { - (reinterpret_cast(h))->Fill(fillValues); + (reinterpret_cast(h))->Fill(fillValues); } } } // end else - } // end loop over histograms + } // end loop over histograms } //____________________________________________________________________________________ diff --git a/PWGDQ/Core/HistogramManager.h b/PWGDQ/Core/HistogramManager.h index 5cab7d78d6e..4b1393b2eb7 100644 --- a/PWGDQ/Core/HistogramManager.h +++ b/PWGDQ/Core/HistogramManager.h @@ -14,8 +14,8 @@ // Class to define and fill histograms // -#ifndef HistogramManager_H -#define HistogramManager_H +#ifndef PWGDQ_CORE_HISTOGRAMMANAGER_H_ +#define PWGDQ_CORE_HISTOGRAMMANAGER_H_ #include #include @@ -67,32 +67,32 @@ class HistogramManager : public TNamed int nYbins = 0, double ymin = 0, double ymax = 0, int varY = -1, int nZbins = 0, double zmin = 0, double zmax = 0, int varZ = -1, const char* xLabels = "", const char* yLabels = "", const char* zLabels = "", - int varT = -1, int varW = -1); + int varT = -1, int varW = -1, bool isdouble = false, bool isFillLabelx = false); // Similar to the above function, with the difference that the user can specify non-equidistant binning void AddHistogram(const char* histClass, const char* name, const char* title, bool isProfile, int nXbins, double* xbins, int varX, int nYbins = 0, double* ybins = nullptr, int varY = -1, int nZbins = 0, double* zbins = nullptr, int varZ = -1, const char* xLabels = "", const char* yLabels = "", const char* zLabels = "", - int varT = -1, int varW = -1); + int varT = -1, int varW = -1, bool isdouble = false, bool isFillLabelx = false); // Create a THn histogram (either THnF or THnSparse) with equidistant binning void AddHistogram(const char* histClass, const char* name, const char* title, int nDimensions, int* vars, int* nBins, double* xmin, double* xmax, - TString* axLabels = nullptr, int varW = -1, bool useSparse = kFALSE); + TString* axLabels = nullptr, int varW = -1, bool useSparse = kFALSE, bool isdouble = false); // Create a THn histogram (either THnF or THnSparse) with non-equidistant binning void AddHistogram(const char* histClass, const char* name, const char* title, int nDimensions, int* vars, TArrayD* binLimits, - TString* axLabels = nullptr, int varW = -1, bool useSparse = kFALSE); + TString* axLabels = nullptr, int varW = -1, bool useSparse = kFALSE, bool isdouble = false); void FillHistClass(const char* className, float* values); - void SetUseDefaultVariableNames(bool flag) { fUseDefaultVariableNames = flag; }; + void SetUseDefaultVariableNames(bool flag) { fUseDefaultVariableNames = flag; } void SetDefaultVarNames(TString* vars, TString* units); const bool* GetUsedVars() const { return fUsedVars; } THashList* GetMainHistogramList() { return fMainList; } // get a histogram list - unsigned long int GetAllocatedBins() const { return fBinsAllocated; } + uint64_t GetAllocatedBins() const { return fBinsAllocated; } void Print(Option_t*) const override; private: @@ -104,7 +104,7 @@ class HistogramManager : public TNamed // various bool fUseDefaultVariableNames; //! toggle the usage of default variable names and units - unsigned long int fBinsAllocated; //! number of allocated bins + uint64_t fBinsAllocated; //! number of allocated bins TString* fVariableNames; //! variable names TString* fVariableUnits; //! variable units @@ -113,7 +113,7 @@ class HistogramManager : public TNamed HistogramManager& operator=(const HistogramManager& c); HistogramManager(const HistogramManager& c); - ClassDef(HistogramManager, 1) + ClassDef(HistogramManager, 2) }; -#endif +#endif // PWGDQ_CORE_HISTOGRAMMANAGER_H_ diff --git a/PWGDQ/Core/HistogramsLibrary.cxx b/PWGDQ/Core/HistogramsLibrary.cxx index 45860efca9a..d2c662898ce 100644 --- a/PWGDQ/Core/HistogramsLibrary.cxx +++ b/PWGDQ/Core/HistogramsLibrary.cxx @@ -11,14 +11,17 @@ // // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // +#include +#include #include "PWGDQ/Core/HistogramsLibrary.h" +#include "VarManager.h" +#include "CommonConstants/MathConstants.h" void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* histClass, const char* groupName, const char* subGroupName) { // // Add a predefined group of histograms to the HistogramManager hm and histogram class histClass - // NOTE: The groupName and subGroupName arguments may contain several keywords, but the user should take care of - // ambiguities. TODO: fix it! + // NOTE: The subGroupName argument may contain several keywords, but the user should take care of ambiguities. TODO: fix it! // NOTE: All of the histograms which match any of the group or subgroup names will be added to the same histogram class !! // So one has to make sure not to mix e.g. event-wise with track-wise histograms // NOTE: The subgroup name can be empty. In this case just a minimal set of histograms corresponding to the group name will be defined @@ -27,9 +30,12 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h groupStr.ToLower(); TString subGroupStr = subGroupName; subGroupStr.ToLower(); - if (groupStr.Contains("event")) { - hm->AddHistogram(histClass, "VtxZ", "Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ); - hm->AddHistogram(histClass, "VtxZ_Run", "Vtx Z", true, VarManager::GetDummyNRuns(), -0.5 + VarManager::GetDummyFirst(), 0.5 + VarManager::GetDummyLast(), VarManager::kRunNo, 60, -15.0, 15.0, VarManager::kVtxZ, 1, 0, 1, VarManager::kNothing, VarManager::GetRunStr().Data()); + if (!groupStr.CompareTo("event")) { + if (!subGroupStr.Contains("generator")) { + hm->AddHistogram(histClass, "VtxZ", "Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ); + hm->AddHistogram(histClass, "VtxZ_Run", "Vtx Z", true, 1, -0.5, 0.5, VarManager::kRunNo, 60, -15.0, 15.0, VarManager::kVtxZ, 1, 0, 1, VarManager::kNothing, "", "", "", VarManager::kNothing, VarManager::kNothing, false, true); + hm->AddHistogram(histClass, "BC", "Event per BC", false, 3564, 0.0, 3564.0, VarManager::kBCOrbit); + } if (subGroupStr.Contains("trigger")) { hm->AddHistogram(histClass, "IsINT7", "Is INT7", false, 2, -0.5, 1.5, VarManager::kIsINT7); if (subGroupStr.Contains("muon") || subGroupStr.Contains("all")) { @@ -49,10 +55,19 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "IsEMC7", "EMC7", false, 2, -0.5, 1.5, VarManager::kIsEMC7); } } + if (subGroupStr.Contains("time")) { + hm->AddHistogram(histClass, "CollTime", "Coll. time wrt BC", false, 100, 0.0, 100.0, VarManager::kCollisionTime); + hm->AddHistogram(histClass, "CollTimeRes", "Coll. time resolution", false, 100, 0.0, 200.0, VarManager::kCollisionTimeRes); + hm->AddHistogram(histClass, "CollTime_VtxZ", "Coll. time wrt BC vs vtx-z", false, 50, -15.0, 15., VarManager::kVtxZ, 100, 0.0, 100.0, VarManager::kCollisionTime); + hm->AddHistogram(histClass, "CollTimeRes_VtxZ", "Coll. time resolution ", false, 50, -15.0, 15., VarManager::kVtxZ, 100, 0.0, 100.0, VarManager::kCollisionTimeRes); + hm->AddHistogram(histClass, "CollTimeRes_MultTPC", "Coll. time resolution ", false, 50, 0.0, 50000., VarManager::kMultTPC, 100, 0.0, 200.0, VarManager::kCollisionTimeRes); + hm->AddHistogram(histClass, "CollTimeRes_MultPV", "Coll. time resolution ", false, 100, 0.0, 4000., VarManager::kVtxNcontribReal, 100, 0.0, 200.0, VarManager::kCollisionTimeRes); + hm->AddHistogram(histClass, "TimeFromSOR", "Time since SOR", false, 10000, 0.0, 1000.0, VarManager::kTimeFromSOR); + } if (subGroupStr.Contains("vtx")) { hm->AddHistogram(histClass, "VtxX", "Vtx X", false, 200, -0.1, 0.1, VarManager::kVtxX); hm->AddHistogram(histClass, "VtxY", "Vtx Y", false, 200, -0.1, 0.1, VarManager::kVtxY); - hm->AddHistogram(histClass, "VtxYVtxX", "Vtx Y vs Vtx X", false, 100, -0.1, 0.1, VarManager::kVtxX, 100, -0.1, 0.1, VarManager::kVtxY); + hm->AddHistogram(histClass, "VtxYVtxX", "Vtx Y vs Vtx X", false, 200, -0.06, 0.0, VarManager::kVtxX, 200, -0.03, 0.03, VarManager::kVtxY); } if (subGroupStr.Contains("vtxpp")) { hm->AddHistogram(histClass, "VtxNContrib", "Vtx n contributors", false, 100, 0.0, 100.0, VarManager::kVtxNcontrib); @@ -61,37 +76,103 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "VtxNContrib", "Vtx n contributors", false, 100, 0.0, 20000.0, VarManager::kVtxNcontrib); } if (subGroupStr.Contains("cent")) { - hm->AddHistogram(histClass, "CentV0M", "CentV0M", false, 100, 0., 100., VarManager::kCentVZERO); - hm->AddHistogram(histClass, "CentV0M_vtxZ", "CentV0M vs Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ, 20, 0., 100., VarManager::kCentVZERO); hm->AddHistogram(histClass, "CentFT0C", "CentFT0C", false, 100, 0., 100., VarManager::kCentFT0C); hm->AddHistogram(histClass, "CentFT0C_vtxZ", "CentFT0C vs Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ, 20, 0., 100., VarManager::kCentFT0C); - hm->AddHistogram(histClass, "CentFT0C_MultTPC", "CentFT0C vs MultTPC", false, 100, 0., 100., VarManager::kCentFT0C, 50, 0., 50., VarManager::kMultTPC); - hm->AddHistogram(histClass, "CentFT0C_Run", "Cent FT0C", true, VarManager::GetDummyNRuns(), -0.5 + VarManager::GetDummyFirst(), 0.5 + VarManager::GetDummyLast(), VarManager::kRunNo, 100, 0., 100., VarManager::kCentFT0C, 1, 0, 1, VarManager::kNothing, VarManager::GetRunStr().Data()); + hm->AddHistogram(histClass, "CentFT0C_MultTPC", "CentFT0C vs MultTPC", false, 100, 0., 100., VarManager::kCentFT0C, 100, 0., 50000., VarManager::kMultTPC); + hm->AddHistogram(histClass, "CentFT0C_Run", "Cent FT0C", true, 1, -0.5, 0.5, VarManager::kRunNo, 100, 0., 100., VarManager::kCentFT0C, 1, 0, 1, VarManager::kNothing, "", "", "", VarManager::kNothing, VarManager::kNothing, false, true); } if (subGroupStr.Contains("mult")) { - hm->AddHistogram(histClass, "MultTPC", "MultTPC", false, 100, 0.0, 25000.0, VarManager::kMultTPC); - hm->AddHistogram(histClass, "MultTPCLow", "MultTPCLow", false, 50, 0.0, 50.0, VarManager::kMultTPC); - hm->AddHistogram(histClass, "MultFV0A", "MultFV0A", false, 100, 0.0, 25000.0, VarManager::kMultFV0A); - hm->AddHistogram(histClass, "MultFV0ALow", "MultFV0ALow", false, 50, 0.0, 50.0, VarManager::kMultFV0A); - hm->AddHistogram(histClass, "MultFV0C", "MultFV0C", false, 100, 0.0, 25000.0, VarManager::kMultFV0C); - hm->AddHistogram(histClass, "MultFV0CLow", "MultFV0CLow", false, 50, 0.0, 50.0, VarManager::kMultFV0C); - hm->AddHistogram(histClass, "MultFT0A", "MultFT0A", false, 100, 0.0, 25000.0, VarManager::kMultFT0A); - hm->AddHistogram(histClass, "MultFT0ALow", "MultFT0ALow", false, 50, 0.0, 50.0, VarManager::kMultFT0A); - hm->AddHistogram(histClass, "MultFT0C", "MultFT0C", false, 100, 0.0, 25000.0, VarManager::kMultFT0C); - hm->AddHistogram(histClass, "MultFT0CLow", "MultFT0CLow", false, 50, 0.0, 50.0, VarManager::kMultFT0C); - hm->AddHistogram(histClass, "MultFDDA", "MultFDDA", false, 100, 0.0, 25000.0, VarManager::kMultFDDA); - hm->AddHistogram(histClass, "MultFDDALow", "MultFDDALow", false, 50, 0.0, 50.0, VarManager::kMultFDDA); - hm->AddHistogram(histClass, "MultFDDC", "MultFDDC", false, 100, 0.0, 25000.0, VarManager::kMultFDDC); - hm->AddHistogram(histClass, "MultFDDCLow", "MultFDDCLow", false, 50, 0.0, 50.0, VarManager::kMultFDDC); - hm->AddHistogram(histClass, "MultZNA", "MultZNA", false, 100, 0.0, 25000.0, VarManager::kMultZNA); - hm->AddHistogram(histClass, "MultZNC", "MultZNC", false, 100, 0.0, 25000.0, VarManager::kMultZNC); - hm->AddHistogram(histClass, "MultTracklets", "MultTracklets", false, 100, 0.0, 25000.0, VarManager::kMultTracklets); - hm->AddHistogram(histClass, "VtxNContribReal", "Vtx n contributors", false, 100, 0.0, 100.0, VarManager::kVtxNcontribReal); - hm->AddHistogram(histClass, "VtxNContrib", "Vtx n contributors", false, 100, 0.0, 100.0, VarManager::kVtxNcontrib); - hm->AddHistogram(histClass, "MultTPC_MultFV0A", "MultTPC vs MultFV0A", false, 400, 0, 800.0, VarManager::kMultTPC, 100, 0, 20000.0, VarManager::kMultFV0A); - hm->AddHistogram(histClass, "MultTPC_MultFT0A", "MultTPC vs MultFT0A", false, 400, 0, 800.0, VarManager::kMultTPC, 100, 0, 1000.0, VarManager::kMultFT0A); - hm->AddHistogram(histClass, "MultTPC_MultFT0C", "MultTPC vs MultFT0C", false, 400, 0, 800.0, VarManager::kMultTPC, 100, 0, 1000.0, VarManager::kMultFT0C); - hm->AddHistogram(histClass, "MultFT0A_MultFT0C", "MultFT0A vs MultFT0C", false, 100, 0, 1000.0, VarManager::kMultFT0A, 100, 0, 1000.0, VarManager::kMultFT0C); + if (subGroupStr.Contains("pp")) { + hm->AddHistogram(histClass, "MultTPC", "MultTPC", false, 250, 0.0, 500.0, VarManager::kMultTPC); + hm->AddHistogram(histClass, "MultFV0A", "MultFV0A", false, 250, 0.0, 500.0, VarManager::kMultFV0A); + hm->AddHistogram(histClass, "MultFT0A", "MultFT0A", false, 300, 0.0, 300.0, VarManager::kMultFT0A); + hm->AddHistogram(histClass, "MultFT0C", "MultFT0C", false, 300, 0.0, 300.0, VarManager::kMultFT0C); + hm->AddHistogram(histClass, "MultFDDA", "MultFDDA", false, 300, 0.0, 300.0, VarManager::kMultFDDA); + hm->AddHistogram(histClass, "MultFDDC", "MultFDDC", false, 50, 0.0, 50.0, VarManager::kMultFDDC); + hm->AddHistogram(histClass, "MultTracklets", "MultTracklets", false, 250, 0.0, 250.0, VarManager::kMultTracklets); + hm->AddHistogram(histClass, "VtxNContribReal", "Vtx n contributors", false, 200, 0.0, 200.0, VarManager::kVtxNcontribReal); + hm->AddHistogram(histClass, "VtxNContrib", "Vtx n contributors", false, 100, 0.0, 100.0, VarManager::kVtxNcontrib); + hm->AddHistogram(histClass, "MultNTracksPVeta1", "MultNTracksPVeta1", false, 200, 0, 200.0, VarManager::kMultNTracksPVeta1); + hm->AddHistogram(histClass, "MultNTracksPVetaHalf", "MultNTracksPVetaHalf", false, 200, 0, 200.0, VarManager::kMultNTracksPVetaHalf); + hm->AddHistogram(histClass, "MultTPC_MultFV0A", "MultTPC vs MultFV0A", false, 100, 0, 500.0, VarManager::kMultTPC, 100, 0, 500.0, VarManager::kMultFV0A); + hm->AddHistogram(histClass, "MultTPC_MultFT0A", "MultTPC vs MultFT0A", false, 100, 0, 500.0, VarManager::kMultTPC, 100, 0, 200.0, VarManager::kMultFT0A); + hm->AddHistogram(histClass, "MultTPC_MultFT0C", "MultTPC vs MultFT0C", false, 100, 0, 500.0, VarManager::kMultTPC, 100, 0, 300.0, VarManager::kMultFT0C); + hm->AddHistogram(histClass, "MultFT0A_MultFT0C", "MultFT0A vs MultFT0C", false, 100, 0, 200.0, VarManager::kMultFT0A, 100, 0, 300.0, VarManager::kMultFT0C); + hm->AddHistogram(histClass, "MultITSWithPV", "MultITSWithPV", false, 150, 0.0, 150.0, VarManager::kMultNTracksHasITS); + hm->AddHistogram(histClass, "MultTPCWithPV", "MultTPCWithPV", false, 150, 0.0, 150.0, VarManager::kMultNTracksHasTPC); + hm->AddHistogram(histClass, "MultITSTPCWithPV", "MultITSTPCWithPV", false, 150, 0.0, 150.0, VarManager::kMultNTracksITSTPC); + hm->AddHistogram(histClass, "MultITSOnly", "MultITSOnly", false, 150, 0.0, 150.0, VarManager::kMultNTracksITSOnly); + hm->AddHistogram(histClass, "MultITSWithPV_MultTPCWithPV", "MultITSWithPV_MultTPCWithPV", false, 150, 0.0, 150.0, VarManager::kMultNTracksHasITS, 150, 0.0, 150.0, VarManager::kMultNTracksHasTPC); + hm->AddHistogram(histClass, "MultITSWithPV_MultITSTPCWithPV", "MultITSWithPV_MultTPCWithPV", false, 150, 0.0, 150.0, VarManager::kMultNTracksHasITS, 150, 0.0, 150.0, VarManager::kMultNTracksITSTPC); + hm->AddHistogram(histClass, "MultITSWithPV_MultFT0C", "MultITSWithPV_MultFT0C", false, 150, 0.0, 150.0, VarManager::kMultNTracksHasITS, 250, 0.0, 2500.0, VarManager::kMultFT0C); + hm->AddHistogram(histClass, "MultITSWithPV_MultFT0A", "MultITSWithPV_MultFT0A", false, 150, 0.0, 150.0, VarManager::kMultNTracksHasITS, 250, 0.0, 2500.0, VarManager::kMultFT0A); + hm->AddHistogram(histClass, "MultITSTPCWithPV_MultFT0C", "MultITSTPCWithPV_MultFT0C", false, 150, 0.0, 150.0, VarManager::kMultNTracksITSTPC, 250, 0.0, 2500.0, VarManager::kMultFT0C); + hm->AddHistogram(histClass, "MultITSTPCWithPV_MultFT0A", "MultITSTPCWithPV_MultFT0A", false, 150, 0.0, 150.0, VarManager::kMultNTracksITSTPC, 250, 0.0, 2500.0, VarManager::kMultFT0A); + hm->AddHistogram(histClass, "VtxZ_MultITSWithPV", "VtxZ vs MultITSWithPV", false, 240, -12.0, 12.0, VarManager::kVtxZ, 400, 0, 400.0, VarManager::kMultNTracksHasITS); + hm->AddHistogram(histClass, "VtxZ_MultTPCWithPV", "VtxZ vs MultTPCWithPV", false, 240, -12.0, 12.0, VarManager::kVtxZ, 400, 0, 400.0, VarManager::kMultNTracksHasTPC); + hm->AddHistogram(histClass, "VtxZ_MultITSTPCWithPV", "VtxZ vs MultITSTPCWithPV", false, 240, -12.0, 12.0, VarManager::kVtxZ, 400, 0, 400.0, VarManager::kMultNTracksITSTPC); + hm->AddHistogram(histClass, "VtxZ_MultITSOnly", "VtxZ vs MultITSOnly", false, 240, -12.0, 12.0, VarManager::kVtxZ, 400, 0, 400.0, VarManager::kMultNTracksITSOnly); + hm->AddHistogram(histClass, "VtxZ_VtxNcontribReal", "VtxZ vs VtxNcontribReal", false, 240, -12.0, 12.0, VarManager::kVtxZ, 200, 0, 200.0, VarManager::kVtxNcontribReal); + + } else { + hm->AddHistogram(histClass, "MultTPC", "MultTPC", false, 200, 0.0, 50000.0, VarManager::kMultTPC); + hm->AddHistogram(histClass, "MultTPC_vsTimeSOR", "MultTPC vs time from SOR", true, 10000, 0.0, 1000.0, VarManager::kTimeFromSOR, 10, 0.0, 50000.0, VarManager::kMultTPC); + hm->AddHistogram(histClass, "MultFV0A", "MultFV0A", false, 200, 0.0, 300000.0, VarManager::kMultFV0A); + hm->AddHistogram(histClass, "MultFT0A", "MultFT0A", false, 200, 0.0, 300000.0, VarManager::kMultFT0A); + hm->AddHistogram(histClass, "MultFT0C", "MultFT0C", false, 200, 0.0, 100000.0, VarManager::kMultFT0C); + hm->AddHistogram(histClass, "MultFDDA", "MultFDDA", false, 100, 0.0, 100000.0, VarManager::kMultFDDA); + hm->AddHistogram(histClass, "MultFDDC", "MultFDDC", false, 100, 0.0, 100000.0, VarManager::kMultFDDC); + hm->AddHistogram(histClass, "MultZNA", "MultZNA", false, 400, 0.0, 400.0, VarManager::kMultZNA); + hm->AddHistogram(histClass, "MultZNC", "MultZNC", false, 400, 0.0, 400.0, VarManager::kMultZNC); + hm->AddHistogram(histClass, "MultZNA_ZNC", "MultZNA vs ZNC", false, 400, 0.0, 400.0, VarManager::kMultZNA, 400, 0.0, 400.0, VarManager::kMultZNC); + hm->AddHistogram(histClass, "MultTracklets", "MultTracklets", false, 100, 0.0, 25000.0, VarManager::kMultTracklets); + hm->AddHistogram(histClass, "VtxNContribReal", "Vtx n contributors (real)", false, 100, 0.0, 5000.0, VarManager::kVtxNcontribReal); + hm->AddHistogram(histClass, "VtxNContribReal_vsTimeSOR", "VtxNContribReal vs time from SOR", true, 10000, 0.0, 1000.0, VarManager::kTimeFromSOR, 10, 0.0, 5000.0, VarManager::kVtxNcontribReal); + hm->AddHistogram(histClass, "VtxNContrib", "Vtx n contributors", false, 100, 0.0, 20000.0, VarManager::kVtxNcontrib); + hm->AddHistogram(histClass, "MultTPC_MultFV0A", "MultTPC vs MultFV0A", false, 100, 0, 50000.0, VarManager::kMultTPC, 100, 0, 300000.0, VarManager::kMultFV0A); + hm->AddHistogram(histClass, "MultTPC_MultFT0A", "MultTPC vs MultFT0A", false, 100, 0, 50000.0, VarManager::kMultTPC, 100, 0, 300000.0, VarManager::kMultFT0A); + hm->AddHistogram(histClass, "MultTPC_MultFT0C", "MultTPC vs MultFT0C", false, 100, 0, 50000.0, VarManager::kMultTPC, 100, 0, 100000.0, VarManager::kMultFT0C); + hm->AddHistogram(histClass, "MultFT0A_MultFT0C", "MultFT0A vs MultFT0C", false, 100, 0, 100000.0, VarManager::kMultFT0A, 100, 0, 300000.0, VarManager::kMultFT0C); + hm->AddHistogram(histClass, "VtxNContribReal_MultTPC", "Vtx n contributors (real) vs mult TPC", false, 100, 0.0, 5000.0, VarManager::kVtxNcontribReal, 200, 0.0, 50000.0, VarManager::kMultTPC); + hm->AddHistogram(histClass, "VtxNContribReal_ZNA", "Vtx n contributors (real) vs ZNA", false, 100, 0.0, 5000.0, VarManager::kVtxNcontribReal, 200, 0.0, 400.0, VarManager::kMultZNA); + hm->AddHistogram(histClass, "VtxNContribReal_ZNC", "Vtx n contributors (real) vs ZNC", false, 100, 0.0, 5000.0, VarManager::kVtxNcontribReal, 200, 0.0, 400.0, VarManager::kMultZNC); + hm->AddHistogram(histClass, "MultZNA_FT0C", "MultZNA vs FT0C", false, 400, 0.0, 400.0, VarManager::kMultZNA, 200, 0.0, 100000.0, VarManager::kMultFT0C); + hm->AddHistogram(histClass, "MultZNC_FT0C", "MultZNC vs FT0C", false, 400, 0.0, 400.0, VarManager::kMultZNC, 200, 0.0, 100000.0, VarManager::kMultFT0C); + hm->AddHistogram(histClass, "TPCpileupZA", "TPC pileup Z, A-side", false, 200, -50.0, 50.0, VarManager::kNTPCpileupZA); + hm->AddHistogram(histClass, "TPCpileupZC", "TPC pileup Z, C-side", false, 200, -50.0, 50.0, VarManager::kNTPCpileupZC); + hm->AddHistogram(histClass, "TPCpileupNcontribA", "TPC pileup n-contributors, A-side", false, 300, 0.0, 3000.0, VarManager::kNTPCpileupContribA); + hm->AddHistogram(histClass, "TPCpileupNcontribC", "TPC pileup n-contributors, C-side", false, 300, 0.0, 3000.0, VarManager::kNTPCpileupContribC); + hm->AddHistogram(histClass, "TPCoccupContribLongA", "TPC occupancy from pileup, n-contrib, A-side, long time range", false, 100, 0.0, 10000.0, VarManager::kNTPCcontribLongA); + hm->AddHistogram(histClass, "TPCoccupContribLongAvsTime", "TPC occupancy from pileup, n-contrib, A-side, long time range", true, 1000, 0.0, 1000.0, VarManager::kTimeFromSOR, 10, 0.0, 10000.0, VarManager::kNTPCcontribLongA); + hm->AddHistogram(histClass, "TPCoccupContribLongAvsContribPV", "TPC occupancy from pileup, n-contrib, A-side, long time range, vs n.contrib", false, 100, 0.0, 5000.0, VarManager::kVtxNcontribReal, 100, 0.0, 10000.0, VarManager::kNTPCcontribLongA); + hm->AddHistogram(histClass, "TPCoccupContribLongC", "TPC occupancy from pileup, n-contrib, C-side, long time range", false, 100, 0.0, 10000.0, VarManager::kNTPCcontribLongC); + hm->AddHistogram(histClass, "TPCoccupContribLongCvsTime", "TPC occupancy from pileup, n-contrib, C-side, long time range", true, 1000, 0.0, 1000.0, VarManager::kTimeFromSOR, 10, 0.0, 10000.0, VarManager::kNTPCcontribLongC); + hm->AddHistogram(histClass, "TPCoccupContribLongCvsContribPV", "TPC occupancy from pileup, n-contrib, C-side, long time range, vs n.contrib", false, 100, 0.0, 5000.0, VarManager::kVtxNcontribReal, 100, 0.0, 10000.0, VarManager::kNTPCcontribLongC); + hm->AddHistogram(histClass, "TPCoccupContribLongAvsC", "TPC occupancy from pileup, n-contrib, A-side vs C-side, long time range", false, 100, 0.0, 10000.0, VarManager::kNTPCcontribLongA, 100, 0.0, 10000.0, VarManager::kNTPCcontribLongC); + hm->AddHistogram(histClass, "TPCoccupMeanTimeLongA", "TPC occupancy from pileup, mean time, A-side, long time range", false, 100, -100.0, 100.0, VarManager::kNTPCmeanTimeLongA); + hm->AddHistogram(histClass, "TPCoccupMeanTimeLongC", "TPC occupancy from pileup, mean time, C-side, long time range", false, 100, -100.0, 100.0, VarManager::kNTPCmeanTimeLongC); + hm->AddHistogram(histClass, "TPCoccupMeanTimeLongAvsC", "TPC occupancy from pileup, mean time, A-side vs C-side, long time range", false, 100, -100.0, 100.0, VarManager::kNTPCmeanTimeLongA, 100, -100.0, 100.0, VarManager::kNTPCmeanTimeLongC); + hm->AddHistogram(histClass, "TPCoccupMedianTimeLongA", "TPC occupancy from pileup, median time, A-side, long time range", false, 100, -100.0, 100.0, VarManager::kNTPCmedianTimeLongA); + hm->AddHistogram(histClass, "TPCoccupMedianTimeLongC", "TPC occupancy from pileup, median time, C-side, long time range", false, 100, -100.0, 100.0, VarManager::kNTPCmedianTimeLongC); + hm->AddHistogram(histClass, "TPCoccupMedianTimeLongAvsC", "TPC occupancy from pileup, median time, A-side vs C-side, long time range", false, 100, -100.0, 100.0, VarManager::kNTPCmedianTimeLongA, 100, -100.0, 100.0, VarManager::kNTPCmedianTimeLongC); + hm->AddHistogram(histClass, "TPCoccupContribShortA", "TPC occupancy from pileup, n-contrib, A-side, short time range", false, 100, 0.0, 7000.0, VarManager::kNTPCcontribShortA); + hm->AddHistogram(histClass, "TPCoccupContribShortAvsTime", "TPC occupancy from pileup, n-contrib, A-side, short time range", true, 1000, 0.0, 1000.0, VarManager::kTimeFromSOR, 10, 0.0, 10000.0, VarManager::kNTPCcontribShortA); + hm->AddHistogram(histClass, "TPCoccupContribShortAvsContribPV", "TPC occupancy from pileup, n-contrib, A-side, short time range, vs n.contrib", false, 100, 0.0, 5000.0, VarManager::kVtxNcontribReal, 100, 0.0, 7000.0, VarManager::kNTPCcontribShortA); + hm->AddHistogram(histClass, "TPCoccupContribShortC", "TPC occupancy from pileup, n-contrib, C-side, short time range", false, 100, 0.0, 7000.0, VarManager::kNTPCcontribShortC); + hm->AddHistogram(histClass, "TPCoccupContribShortCvsTime", "TPC occupancy from pileup, n-contrib, C-side, short time range", true, 1000, 0.0, 1000.0, VarManager::kTimeFromSOR, 10, 0.0, 10000.0, VarManager::kNTPCcontribShortC); + hm->AddHistogram(histClass, "TPCoccupContribShortAvsC", "TPC occupancy from pileup, n-contrib, A-side vs C-side, short time range", false, 100, 0.0, 7000.0, VarManager::kNTPCcontribShortA, 100, 0.0, 7000.0, VarManager::kNTPCcontribShortC); + hm->AddHistogram(histClass, "TPCoccupContribShortCvsContribPV", "TPC occupancy from pileup, n-contrib, C-side, short time range, vs n.contrib", false, 100, 0.0, 5000.0, VarManager::kVtxNcontribReal, 100, 0.0, 7000.0, VarManager::kNTPCcontribShortC); + hm->AddHistogram(histClass, "TPCoccupMeanTimeShortA", "TPC occupancy from pileup, mean time, A-side, short time range", false, 100, -20.0, 20.0, VarManager::kNTPCmeanTimeShortA); + hm->AddHistogram(histClass, "TPCoccupMeanTimeShortC", "TPC occupancy from pileup, mean time, C-side, short time range", false, 100, -20.0, 20.0, VarManager::kNTPCmeanTimeShortC); + hm->AddHistogram(histClass, "TPCoccupMeanTimeShortAvsC", "TPC occupancy from pileup, mean time, A-side vs C-side, short time range", false, 100, -20.0, 20.0, VarManager::kNTPCmeanTimeShortA, 100, -20.0, 20.0, VarManager::kNTPCmeanTimeShortC); + hm->AddHistogram(histClass, "TPCoccupMedianTimeShortA", "TPC occupancy from pileup, median time, A-side, short time range", false, 100, -20.0, 20.0, VarManager::kNTPCmedianTimeShortA); + hm->AddHistogram(histClass, "TPCoccupMedianTimeShortC", "TPC occupancy from pileup, median time, C-side, short time range", false, 100, -20.0, 20.0, VarManager::kNTPCmedianTimeShortC); + hm->AddHistogram(histClass, "TPCoccupMedianTimeShortAvsC", "TPC occupancy from pileup, median time, A-side vs C-side, short time range", false, 100, -20.0, 20.0, VarManager::kNTPCmedianTimeShortA, 100, -20.0, 20.0, VarManager::kNTPCmedianTimeShortC); + hm->AddHistogram(histClass, "TPCoccupContribLongA_TrackOccup", "TPC occupancy from pileup, n-contrib, A-side, long time range vs common track occup", false, 100, 0.0, 10000.0, VarManager::kNTPCcontribLongA, 100, 0.0, 10000.0, VarManager::kTrackOccupancyInTimeRange); + hm->AddHistogram(histClass, "NcontribReal_centT0C", "Ncontrib vs Cent", false, 100, 0, 100, VarManager::kCentFT0C, 4000, 0, 4000, VarManager::kVtxNcontribReal); + hm->AddHistogram(histClass, "globalTracks_centT0C", "globalTracks vs Cent", false, 100, 0, 100, VarManager::kCentFT0C, 4000, 0, 4000, VarManager::kMultA); + hm->AddHistogram(histClass, "ITSTPCTracks_centT0C", "ITSTPCTracks vs Cent", false, 100, 0, 100, VarManager::kCentFT0C, 4000, 0, 4000, VarManager::kMultAllTracksITSTPC); + } } if (subGroupStr.Contains("ftmulpbpb")) { hm->AddHistogram(histClass, "MultTPC", "MultTPC", false, 100, 0.0, 50000.0, VarManager::kMultTPC); @@ -103,6 +184,10 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "MultFT0C_VtxNContrib", "MultFT0C vs VtxNContrib", false, 100, 0, 60000.0, VarManager::kMultFT0C, 100, 0, 10000.0, VarManager::kVtxNcontrib); hm->AddHistogram(histClass, "MultFT0A_VtxNContrib", "MultFT0A vs VtxNContrib", false, 100, 0, 180000.0, VarManager::kMultFT0A, 100, 0, 10000.0, VarManager::kVtxNcontrib); } + if (subGroupStr.Contains("occupancy")) { + hm->AddHistogram(histClass, "ITStrackOccupancy", "ITStrackOccupancy", false, 200, 0.0, 20000.0, VarManager::kTrackOccupancyInTimeRange); + hm->AddHistogram(histClass, "Ft0cOccupancy", "Ft0cOccupancy", false, 200, 0.0, 20000.0, VarManager::kFT0COccupancyInTimeRange); + } if (subGroupStr.Contains("mc")) { hm->AddHistogram(histClass, "MCVtxX_VtxX", "Vtx X (MC vs rec)", false, 100, -0.5, 0.5, VarManager::kVtxX, 100, -0.5, 0.5, VarManager::kMCVtxX); hm->AddHistogram(histClass, "MCVtxY_VtxY", "Vtx Y (MC vs rec)", false, 100, -0.5, 0.5, VarManager::kVtxY, 100, -0.5, 0.5, VarManager::kMCVtxY); @@ -110,20 +195,50 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "MCVtxZ", "Vtx Z (MC)", false, 75, -15.0, 15.0, VarManager::kMCVtxZ); hm->AddHistogram(histClass, "MCImpPar_CentVZERO", "MC impact param vs CentVZERO", false, 50, 0.0, 100.0, VarManager::kCentVZERO, 20, 0.0, 20.0, VarManager::kMCEventImpParam); } + if (subGroupStr.Contains("generator")) { + hm->AddHistogram(histClass, "MCVtxX", "Vtx X", false, 1000, -0.5, 0.5, VarManager::kMCVtxX); + hm->AddHistogram(histClass, "MCVtxY", "Vtx Y", false, 1000, -0.5, 0.5, VarManager::kMCVtxY); + hm->AddHistogram(histClass, "MCVtxX_VtxY", "Vtx X vs Vtx Y", false, 200, -0.2, 0.2, VarManager::kMCVtxX, 200, -0.2, 0.2, VarManager::kMCVtxY); + hm->AddHistogram(histClass, "MCVtxZ", "Vtx Z", false, 60, -15.0, 15.0, VarManager::kMCVtxZ); + hm->AddHistogram(histClass, "MCVtxZ_VtxX", "Vtx X vs Vtx Z", false, 60, -15.0, 15.0, VarManager::kMCVtxZ, 200, -0.2, 0.2, VarManager::kMCVtxX); + hm->AddHistogram(histClass, "MCVtxX_VtxY", "Vtx X vs Vtx Y", false, 200, 15.0, 15.0, VarManager::kMCVtxZ, 200, -0.2, 0.2, VarManager::kMCVtxY); + hm->AddHistogram(histClass, "MCImpPar", "MC impact param", false, 20, 0.0, 20.0, VarManager::kMCEventImpParam); + } + if (subGroupStr.Contains("subgen")) { + hm->AddHistogram(histClass, "SubGenID", "SubGenerator ID", false, 11, -0.5, 10.5, VarManager::kMCEventSubGeneratorId); + } if (subGroupStr.Contains("qvector")) { - hm->AddHistogram(histClass, "Q2X0A", "", false, 100, -1.0, 1.0, VarManager::kQ2X0A); - hm->AddHistogram(histClass, "Q2Y0A", "", false, 100, -1.0, 1.0, VarManager::kQ2Y0A); + int varZNA[3] = {VarManager::kQ1ZNAX, VarManager::kQ1ZNAY, VarManager::kCentFT0C}; + int varZNC[3] = {VarManager::kQ1ZNCX, VarManager::kQ1ZNCY, VarManager::kCentFT0C}; + + int bins[3] = {500, 500, 18}; + double minBins[3] = {-10, -10, 0}; + double maxBins[3] = {10, 10, 90}; + hm->AddHistogram(histClass, "Q1ZNAX_Q1ZNAY_CentFT0C", "", 3, varZNA, bins, minBins, maxBins, 0, -1, kTRUE); + hm->AddHistogram(histClass, "Q1ZNCX_Q1ZNCY_CentFT0C", "", 3, varZNC, bins, minBins, maxBins, 0, -1, kTRUE); + + hm->AddHistogram(histClass, "IntercalibZNA_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -50.0, 50.0, VarManager::KIntercalibZNA); + hm->AddHistogram(histClass, "IntercalibZNC_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -50.0, 50.0, VarManager::KIntercalibZNC); + + hm->AddHistogram(histClass, "EnergyCommonZNA", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 2000, 0, 2000, VarManager::kEnergyCommonZNA); + hm->AddHistogram(histClass, "EnergyCommonZNC", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 2000, 0, 2000, VarManager::kEnergyCommonZNC); + + hm->AddHistogram(histClass, "EnergyZNA1", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 2000, 0, 2000, VarManager::kEnergyZNA1); + hm->AddHistogram(histClass, "EnergyZNA2", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 2000, 0, 2000, VarManager::kEnergyZNA2); + hm->AddHistogram(histClass, "EnergyZNA3", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 2000, 0, 2000, VarManager::kEnergyZNA3); + hm->AddHistogram(histClass, "EnergyZNA4", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 2000, 0, 2000, VarManager::kEnergyZNA4); + + hm->AddHistogram(histClass, "EnergyZNC1", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 2000, 0, 2000, VarManager::kEnergyZNC1); + hm->AddHistogram(histClass, "EnergyZNC2", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 2000, 0, 2000, VarManager::kEnergyZNC2); + hm->AddHistogram(histClass, "EnergyZNC3", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 2000, 0, 2000, VarManager::kEnergyZNC3); + hm->AddHistogram(histClass, "EnergyZNC4", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 2000, 0, 2000, VarManager::kEnergyZNC4); + + hm->AddHistogram(histClass, "Q2X0A", "", false, 500, -10.0, 10.0, VarManager::kQ2X0A); + hm->AddHistogram(histClass, "Q2Y0A", "", false, 500, -10.0, 10.0, VarManager::kQ2Y0A); hm->AddHistogram(histClass, "Q2X0B", "", false, 500, -10.0, 10.0, VarManager::kQ2X0B); hm->AddHistogram(histClass, "Q2Y0B", "", false, 500, -10.0, 10.0, VarManager::kQ2Y0B); hm->AddHistogram(histClass, "Q2X0C", "", false, 500, -10.0, 10.0, VarManager::kQ2X0C); hm->AddHistogram(histClass, "Q2Y0C", "", false, 500, -10.0, 10.0, VarManager::kQ2Y0C); - hm->AddHistogram(histClass, "Q2X0A_Q2Y0A", "", false, 500, -10.0, 10.0, VarManager::kQ2X0A, 500, -10.0, 10.0, VarManager::kQ2Y0A); - hm->AddHistogram(histClass, "Q2X0B_Q2Y0B", "", false, 500, -10.0, 10.0, VarManager::kQ2X0B, 500, -10.0, 10.0, VarManager::kQ2Y0B); - hm->AddHistogram(histClass, "Q2X0C_Q2Y0C", "", false, 500, -10.0, 10.0, VarManager::kQ2X0C, 500, -10.0, 10.0, VarManager::kQ2Y0C); - hm->AddHistogram(histClass, "Q2X0B_Q2Y0C", "", false, 500, -10.0, 10.0, VarManager::kQ2X0B, 500, -10.0, 10.0, VarManager::kQ2Y0C); - hm->AddHistogram(histClass, "Q2X0C_Q2Y0B", "", false, 500, -10.0, 10.0, VarManager::kQ2X0C, 500, -10.0, 10.0, VarManager::kQ2Y0B); - hm->AddHistogram(histClass, "Q3X0B_Q3Y0C", "", false, 500, -10.0, 10.0, VarManager::kQ3X0B, 500, -10.0, 10.0, VarManager::kQ3Y0C); - hm->AddHistogram(histClass, "Q3X0C_Q3Y0B", "", false, 500, -10.0, 10.0, VarManager::kQ3X0C, 500, -10.0, 10.0, VarManager::kQ3Y0B); hm->AddHistogram(histClass, "Q2X0A_VtxZ", "", true, 60, -15.0, 15.0, VarManager::kVtxZ, 500, -10.0, 10.0, VarManager::kQ2X0A); hm->AddHistogram(histClass, "Q2Y0A_VtxZ", "", true, 60, -15.0, 15.0, VarManager::kVtxZ, 500, -10.0, 10.0, VarManager::kQ2Y0A); hm->AddHistogram(histClass, "Q2X0B_VtxZ", "", true, 60, -15.0, 15.0, VarManager::kVtxZ, 500, -10.0, 10.0, VarManager::kQ2X0B); @@ -165,38 +280,113 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Psi2A", "", false, 100, -2.0, 2.0, VarManager::kPsi2A); hm->AddHistogram(histClass, "Psi2B", "", false, 100, -2.0, 2.0, VarManager::kPsi2B); hm->AddHistogram(histClass, "Psi2C", "", false, 100, -2.0, 2.0, VarManager::kPsi2C); - hm->AddHistogram(histClass, "Psi2A_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 100, -2.0, 2.0, VarManager::kPsi2A); - hm->AddHistogram(histClass, "Psi2B_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 100, -2.0, 2.0, VarManager::kPsi2B); - hm->AddHistogram(histClass, "Psi2C_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 100, -2.0, 2.0, VarManager::kPsi2C); + hm->AddHistogram(histClass, "Psi2A_CentFT0C", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 100, -2.0, 2.0, VarManager::kPsi2A); + hm->AddHistogram(histClass, "Psi2B_CentFT0C", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 100, -2.0, 2.0, VarManager::kPsi2B); + hm->AddHistogram(histClass, "Psi2C_CentFT0C", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 100, -2.0, 2.0, VarManager::kPsi2C); + hm->AddHistogram(histClass, "centrFT0C_Corr2REF_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 250, -1.0, 1.0, VarManager::kCORR2REF, VarManager::kM11REF); + hm->AddHistogram(histClass, "centrFT0C_Corr2REFetagap_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 250, -1.0, 1.0, VarManager::kCORR2REFetagap, VarManager::kM11REFetagap); + hm->AddHistogram(histClass, "centrFT0C_Corr4REF_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 250, -1.0, 1.0, VarManager::kCORR4REF, VarManager::kM1111REF); + hm->AddHistogram(histClass, "centrFT0C_Corr2Corr4REF_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 250, -1.0, 1.0, VarManager::kCORR2CORR4REF, VarManager::kM11M1111REF); + hm->AddHistogram(histClass, "Run2_centrFT0C_Corr2REF_ev", "", true, 9, std::array{0.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0}.data(), VarManager::kCentFT0C, 250, std::array{-1.0, 1.0}.data(), VarManager::kCORR2REF, 0, nullptr, -1, "", "", "", VarManager::kCORR2REF, VarManager::kM11REF); + hm->AddHistogram(histClass, "Run2_centrFT0C_Corr2REFetagap_ev", "", true, 9, std::array{0.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0}.data(), VarManager::kCentFT0C, 250, std::array{-1.0, 1.0}.data(), VarManager::kCORR2REFetagap, 0, nullptr, -1, "", "", "", VarManager::kCORR2REFetagap, VarManager::kM11REFetagap); + hm->AddHistogram(histClass, "Run2_centrFT0C_Corr4REF_ev", "", true, 9, std::array{0.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0}.data(), VarManager::kCentFT0C, 250, std::array{-1.0, 1.0}.data(), VarManager::kCORR4REF, 0, nullptr, -1, "", "", "", VarManager::kCORR4REF, VarManager::kM1111REF); + hm->AddHistogram(histClass, "Run2_centrFT0C_Corr2Corr4REF_ev", "", true, 9, std::array{0.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0}.data(), VarManager::kCentFT0C, 250, std::array{-1.0, 1.0}.data(), VarManager::kCORR2CORR4REF, 0, nullptr, -1, "", "", "", VarManager::kCORR2CORR4REF, VarManager::kM11M1111REF); + hm->AddHistogram(histClass, "centrFT0C_M11REF_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 1000, 0.0, 1000000.0, VarManager::kM11REF); + hm->AddHistogram(histClass, "centrFT0C_M11etagap_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 1000, 0.0, 10000000.0, VarManager::kM11REFetagap); + hm->AddHistogram(histClass, "centrFT0C_M1111REF_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 1000, 0.0, 100000000000000.0, VarManager::kM1111REF); + hm->AddHistogram(histClass, "centrFT0C_M11M1111REF_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 1000, 0.0, 10000000000000000.0, VarManager::kM11M1111REF); + if (subGroupStr.Contains("cross")) { + hm->AddHistogram(histClass, "Q1ZNACXX_CentFT0C", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 4000, -2, 2, VarManager::kQ1ZNACXX); + hm->AddHistogram(histClass, "Q1ZNACYY_CentFT0C", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 4000, -2, 2, VarManager::kQ1ZNACYY); + hm->AddHistogram(histClass, "Q1ZNACYX_CentFT0C", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 4000, -2, 2, VarManager::kQ1ZNACYX); + hm->AddHistogram(histClass, "Q1ZNACXY_CentFT0C", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 4000, -2, 2, VarManager::kQ1ZNACXY); + hm->AddHistogram(histClass, "Q2X0A_Q2Y0A", "", false, 500, -10.0, 10.0, VarManager::kQ2X0A, 500, -10.0, 10.0, VarManager::kQ2Y0A); + hm->AddHistogram(histClass, "Q2X0B_Q2Y0B", "", false, 500, -10.0, 10.0, VarManager::kQ2X0B, 500, -10.0, 10.0, VarManager::kQ2Y0B); + hm->AddHistogram(histClass, "Q2X0C_Q2Y0C", "", false, 500, -10.0, 10.0, VarManager::kQ2X0C, 500, -10.0, 10.0, VarManager::kQ2Y0C); + hm->AddHistogram(histClass, "Q2X0B_Q2Y0C", "", false, 500, -10.0, 10.0, VarManager::kQ2X0B, 500, -10.0, 10.0, VarManager::kQ2Y0C); + hm->AddHistogram(histClass, "Q2X0C_Q2Y0B", "", false, 500, -10.0, 10.0, VarManager::kQ2X0C, 500, -10.0, 10.0, VarManager::kQ2Y0B); + hm->AddHistogram(histClass, "Q3X0B_Q3Y0C", "", false, 500, -10.0, 10.0, VarManager::kQ3X0B, 500, -10.0, 10.0, VarManager::kQ3Y0C); + hm->AddHistogram(histClass, "Q3X0C_Q3Y0B", "", false, 500, -10.0, 10.0, VarManager::kQ3X0C, 500, -10.0, 10.0, VarManager::kQ3Y0B); + hm->AddHistogram(histClass, "Q2YYAB_Cent", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -1.0, 1.0, VarManager::kQ2YYAB); + hm->AddHistogram(histClass, "Q2XXAB_Cent", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -1.0, 1.0, VarManager::kQ2XXAB); + hm->AddHistogram(histClass, "Q2XYAB_Cent", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -1.0, 1.0, VarManager::kQ2XYAB); + hm->AddHistogram(histClass, "Q2YXAB_Cent", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -1.0, 1.0, VarManager::kQ2YXAB); + hm->AddHistogram(histClass, "Q2YYAC_Cent", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -1.0, 1.0, VarManager::kQ2YYAC); + hm->AddHistogram(histClass, "Q2XXAC_Cent", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -1.0, 1.0, VarManager::kQ2XXAC); + hm->AddHistogram(histClass, "Q2XYAC_Cent", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -1.0, 1.0, VarManager::kQ2XYAC); + hm->AddHistogram(histClass, "Q2YXAC_Cent", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -1.0, 1.0, VarManager::kQ2YXAC); + hm->AddHistogram(histClass, "Q2YYBC_Cent", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -1.0, 1.0, VarManager::kQ2YYBC); + hm->AddHistogram(histClass, "Q2XXBC_Cent", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -1.0, 1.0, VarManager::kQ2XXBC); + hm->AddHistogram(histClass, "Q2XYBC_Cent", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -1.0, 1.0, VarManager::kQ2XYBC); + hm->AddHistogram(histClass, "Q2YXBC_Cent", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -1.0, 1.0, VarManager::kQ2YXBC); + hm->AddHistogram(histClass, "Q2YYAB_CentFT0C", "", true, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -1.0, 1.0, VarManager::kQ2YYAB); + hm->AddHistogram(histClass, "Q2XXAB_CentFT0C", "", true, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -1.0, 1.0, VarManager::kQ2XXAB); + hm->AddHistogram(histClass, "Q2XYAB_CentFT0C", "", true, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -1.0, 1.0, VarManager::kQ2XYAB); + hm->AddHistogram(histClass, "Q2YXAB_CentFT0C", "", true, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -1.0, 1.0, VarManager::kQ2YXAB); + hm->AddHistogram(histClass, "Q2YYAC_CentFT0C", "", true, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -1.0, 1.0, VarManager::kQ2YYAC); + hm->AddHistogram(histClass, "Q2XXAC_CentFT0C", "", true, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -1.0, 1.0, VarManager::kQ2XXAC); + hm->AddHistogram(histClass, "Q2XYAC_CentFT0C", "", true, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -1.0, 1.0, VarManager::kQ2XYAC); + hm->AddHistogram(histClass, "Q2YXAC_CentFT0C", "", true, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -1.0, 1.0, VarManager::kQ2YXAC); + hm->AddHistogram(histClass, "Q2YYBC_CentFT0C", "", true, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -1.0, 1.0, VarManager::kQ2YYBC); + hm->AddHistogram(histClass, "Q2XXBC_CentFT0C", "", true, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -1.0, 1.0, VarManager::kQ2XXBC); + hm->AddHistogram(histClass, "Q2XYBC_CentFT0C", "", true, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -1.0, 1.0, VarManager::kQ2XYBC); + hm->AddHistogram(histClass, "Q2YXBC_CentFT0C", "", true, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -1.0, 1.0, VarManager::kQ2YXBC); + } } if (subGroupStr.Contains("res")) { - hm->AddHistogram(histClass, "R2SP_CentV0M", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -10.0, 10.0, VarManager::kR2SP); + hm->AddHistogram(histClass, "R2SP_TPCFT0A_CentV0M", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -10.0, 10.0, VarManager::kR2SP_AB); + hm->AddHistogram(histClass, "R2SP_TPCFT0C_CentV0M", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -10.0, 10.0, VarManager::kR2SP_AC); + hm->AddHistogram(histClass, "R2SP_FT0AFT0C_CentV0M", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -10.0, 10.0, VarManager::kR2SP_BC); hm->AddHistogram(histClass, "R3SP_CentV0M", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -10.0, 10.0, VarManager::kR3SP); - hm->AddHistogram(histClass, "R2EP_CentV0M", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -10.0, 10.0, VarManager::kR2EP); hm->AddHistogram(histClass, "R3EP_CentV0M", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -10.0, 10.0, VarManager::kR3EP); - hm->AddHistogram(histClass, "R2SP_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2SP); - hm->AddHistogram(histClass, "R2SP_FT0CFT0A_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2SP_FT0CFT0A); + hm->AddHistogram(histClass, "R2EP_TPCFT0A_CentV0M", "", false, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -10.0, 10.0, VarManager::kR2EP_AB); + hm->AddHistogram(histClass, "R2EP_TPCFT0C_CentV0M", "", false, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -10.0, 10.0, VarManager::kR2EP_AC); + hm->AddHistogram(histClass, "R2EP_FT0CFT0A_CentV0M", "", false, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -10.0, 10.0, VarManager::kR2EP_BC); + hm->AddHistogram(histClass, "R2SP_TPCFT0A_CentFT0C", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2SP_AB); + hm->AddHistogram(histClass, "R2SP_TPCFT0C_CentFT0C", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2SP_AC); + hm->AddHistogram(histClass, "R2SP_FT0AFT0C_CentFT0C", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2SP_BC); hm->AddHistogram(histClass, "R2SP_FT0CTPCPOS_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2SP_FT0CTPCPOS); hm->AddHistogram(histClass, "R2SP_FT0CTPCNEG_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2SP_FT0CTPCNEG); hm->AddHistogram(histClass, "R2SP_FT0ATPCPOS_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2SP_FT0ATPCPOS); hm->AddHistogram(histClass, "R2SP_FT0ATPCNEG_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2SP_FT0ATPCNEG); hm->AddHistogram(histClass, "R3SP_CentFT0C", "", true, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR3SP); - hm->AddHistogram(histClass, "R2EP_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2EP); - hm->AddHistogram(histClass, "R2EP_FT0CFT0A_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2EP_FT0CFT0A); + hm->AddHistogram(histClass, "R2EP_TPCFT0A_CentFT0C", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2EP_AB); + hm->AddHistogram(histClass, "R2EP_TPCFT0C_CentFT0C", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2EP_AC); + hm->AddHistogram(histClass, "R2EP_FT0CFT0A_CentFT0C", "", false, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2EP_BC); hm->AddHistogram(histClass, "R2EP_FT0CTPCPOS_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2EP_FT0CTPCPOS); hm->AddHistogram(histClass, "R2EP_FT0CTPCNEG_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2EP_FT0CTPCNEG); hm->AddHistogram(histClass, "R2EP_FT0ATPCPOS_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2EP_FT0ATPCPOS); hm->AddHistogram(histClass, "R2EP_FT0ATPCNEG_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2EP_FT0ATPCNEG); hm->AddHistogram(histClass, "R3EP_CentFT0C", "", true, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR3EP); } + if (subGroupStr.Contains("reso-profile")) { + hm->AddHistogram(histClass, "Profile_R2SP_TPCFT0A_CentFT0C", "Profile_R2SP_TPCFT0A_CentFT0C", true, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, 0.0, 5.0, VarManager::kR2SP_AB, 0, 0, 0, -1, "", "", "", -1, VarManager::kWR2SP_AB); + hm->AddHistogram(histClass, "Profile_R2SP_TPCFT0C_CentFT0C", "Profile_R2SP_TPCFT0C_CentFT0C", true, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, 0.0, 5.0, VarManager::kR2SP_AC, 0, 0, 0, -1, "", "", "", -1, VarManager::kWR2SP_AC); + hm->AddHistogram(histClass, "Profile_R2SP_FT0AFT0C_CentFT0C", "Profile_R2SP_FT0AFT0C_CentFT0C", true, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, 0.0, 5.0, VarManager::kR2SP_BC, 0, 0, 0, -1, "", "", "", -1, VarManager::kWR2SP_BC); + hm->AddHistogram(histClass, "Profile_R2EP_TPCFT0A_CentFT0C", "Profile_R2EP_TPCFT0A_CentFT0C", true, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, 0.0, 5.0, VarManager::kR2EP_AB, 0, 0, 0, -1, "", "", "", -1, VarManager::kWR2EP_AB); + hm->AddHistogram(histClass, "Profile_R2EP_TPCFT0C_CentFT0C", "Profile_R2EP_TPCFT0C_CentFT0C", true, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, 0.0, 5.0, VarManager::kR2EP_AC, 0, 0, 0, -1, "", "", "", -1, VarManager::kWR2EP_AC); + hm->AddHistogram(histClass, "Profile_R2EP_FT0AFT0C_CentFT0C", "Profile_R2EP_FT0AFT0C_CentFT0C", true, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, 0.0, 5.0, VarManager::kR2EP_BC, 0, 0, 0, -1, "", "", "", -1, VarManager::kWR2EP_BC); + hm->AddHistogram(histClass, "Profile_R2SP_Im_TPCFT0A_CentFT0C", "Profile_R2SP_Im_TPCFT0A_CentFT0C", true, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, 0.0, 5.0, VarManager::kR2SP_AB_Im, 0, 0, 0, -1, "", "", "", -1, VarManager::kWR2SP_AB_Im); + hm->AddHistogram(histClass, "Profile_R2SP_Im_TPCFT0C_CentFT0C", "Profile_R2SP_Im_TPCFT0C_CentFT0C", true, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, 0.0, 5.0, VarManager::kR2SP_AC_Im, 0, 0, 0, -1, "", "", "", -1, VarManager::kWR2SP_AC_Im); + hm->AddHistogram(histClass, "Profile_R2SP_Im_FT0AFT0C_CentFT0C", "Profile_R2SP_Im_FT0AFT0C_CentFT0C", true, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, 0.0, 5.0, VarManager::kR2SP_BC_Im, 0, 0, 0, -1, "", "", "", -1, VarManager::kWR2SP_BC_Im); + hm->AddHistogram(histClass, "Profile_R2EP_Im_TPCFT0A_CentFT0C", "Profile_R2EP_Im_TPCFT0A_CentFT0C", true, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, 0.0, 5.0, VarManager::kR2EP_AB_Im, 0, 0, 0, -1, "", "", "", -1, VarManager::kWR2EP_AB_Im); + hm->AddHistogram(histClass, "Profile_R2EP_Im_TPCFT0C_CentFT0C", "Profile_R2EP_Im_TPCFT0C_CentFT0C", true, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, 0.0, 5.0, VarManager::kR2EP_AC_Im, 0, 0, 0, -1, "", "", "", -1, VarManager::kWR2EP_AC_Im); + hm->AddHistogram(histClass, "Profile_R2EP_Im_FT0AFT0C_CentFT0C", "Profile_R2EP_Im_FT0AFT0C_CentFT0C", true, 90, 0.0, 90.0, VarManager::kCentFT0C, 500, 0.0, 5.0, VarManager::kR2EP_BC_Im, 0, 0, 0, -1, "", "", "", -1, VarManager::kWR2EP_BC_Im); + } if (subGroupStr.Contains("filter")) { hm->AddHistogram(histClass, "IsDoubleGap", "Is double gap", false, 2, -0.5, 1.5, VarManager::kIsDoubleGap); hm->AddHistogram(histClass, "IsSingleGapA", "Is single gap on side A", false, 2, -0.5, 1.5, VarManager::kIsSingleGapA); hm->AddHistogram(histClass, "IsSingleGapC", "Is single gap on side C", false, 2, -0.5, 1.5, VarManager::kIsSingleGapC); + hm->AddHistogram(histClass, "IsITSUPCMode", "UPC settings used", false, 2, -0.5, 1.5, VarManager::kIsITSUPCMode); + hm->AddHistogram(histClass, "IsITSUPCMode_IsSingleGap", "UPC settings used vs Is single gap", false, 2, -0.5, 1.5, VarManager::kIsITSUPCMode, 2, -0.5, 1.5, VarManager::kIsSingleGap); + } + if (subGroupStr.Contains("zdc")) { + hm->AddHistogram(histClass, "energyCommonZNA_energyCommonZNC", "Common ZNA energy vs common ZNC energy", false, 1050, -10.0, 200.0, VarManager::kEnergyCommonZNA, 1050, -10.0, 200.0, VarManager::kEnergyCommonZNC); + hm->AddHistogram(histClass, "energyCommonZNA_energyCommonZNC_lowRange", "Common ZNA energy vs common ZNC energy", false, 220, -2.0, 20.0, VarManager::kEnergyCommonZNA, 220, -2.0, 20.0, VarManager::kEnergyCommonZNC); } } // end "event" - if (groupStr.CompareTo("two-collisions") == 0) { + if (!groupStr.CompareTo("two-collisions")) { hm->AddHistogram(histClass, "DeltaZ", "z_{1} - z_{2}", false, 400, -20., 20., VarManager::kTwoEvDeltaZ); hm->AddHistogram(histClass, "DeltaZ_Z1", "z_{1} - z_{2} vs z_{1}", false, 24, -12., 12., VarManager::kTwoEvPosZ1, 300, -15., 15., VarManager::kTwoEvDeltaZ); hm->AddHistogram(histClass, "DeltaR", "r_{1} - r_{2}", false, 200, -0.1, 0.1, VarManager::kTwoEvDeltaR); @@ -207,20 +397,26 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "NContrib1vs2", "n.contrib 1 vs 2", false, 100, 0.0, 100.0, VarManager::kTwoEvPVcontrib1, 100, 0.0, 100.0, VarManager::kTwoEvPVcontrib2); } - if (groupStr.Contains("track")) { + if (!groupStr.CompareTo("track")) { hm->AddHistogram(histClass, "Pt", "p_{T} distribution", false, 2000, 0.0, 20.0, VarManager::kPt); hm->AddHistogram(histClass, "Eta", "#eta distribution", false, 500, -5.0, 5.0, VarManager::kEta); - hm->AddHistogram(histClass, "Phi", "#varphi distribution", false, 500, -2. * TMath::Pi(), 2. * TMath::Pi(), VarManager::kPhi); - hm->AddHistogram(histClass, "Phi_Pt", "#varphi distribution", false, 50, 0.0, 10.0, VarManager::kPt, 720, 0.0, TMath::TwoPi(), VarManager::kPhi); + hm->AddHistogram(histClass, "Phi", "#varphi distribution", false, 500, -2. * o2::constants::math::PI, 2. * o2::constants::math::PI, VarManager::kPhi); + hm->AddHistogram(histClass, "Phi_Pt", "#varphi distribution", false, 50, 0.0, 10.0, VarManager::kPt, 720, 0.0, o2::constants::math::TwoPI, VarManager::kPhi); hm->AddHistogram(histClass, "IsPVcontrib_pt", "is PV contributor vs pt", false, 50, 0.0, 50.0, VarManager::kPt, 2, -0.5, 1.5, VarManager::kPVContributor); hm->AddHistogram(histClass, "IsPVcontrib_pt_prof", "is PV contributor vs pt", true, 50, 0.0, 50.0, VarManager::kPt, 2, -0.5, 1.5, VarManager::kPVContributor); + if (subGroupStr.Contains("ambiguity") && !subGroupStr.Contains("muon")) { + hm->AddHistogram(histClass, "AmbiguityInBunch", "in bunch collision ambiguity", false, 10, 0., 10., VarManager::kBarrelNAssocsInBunch); + hm->AddHistogram(histClass, "AmbiguityInBunch_pt", "in bunch collision ambiguity vs p_{T}", false, 50, 0.0, 10.0, VarManager::kPt, 10, 0., 10., VarManager::kBarrelNAssocsInBunch); + hm->AddHistogram(histClass, "AmbiguityOutOfBunch", "out of bunch collision ambiguity", false, 10, 0., 10., VarManager::kBarrelNAssocsOutOfBunch); + hm->AddHistogram(histClass, "AmbiguityOutOfBunch_pt", "out of bunch collision ambiguity vs p_{T}", false, 50, 0.0, 10.0, VarManager::kPt, 10, 0., 10., VarManager::kBarrelNAssocsOutOfBunch); + } if (subGroupStr.Contains("cent")) { hm->AddHistogram(histClass, "Pt_CentFT0C", "p_{T} distribution", false, 2000, 0.0, 20.0, VarManager::kPt, 20, 0.0, 100.0, VarManager::kCentFT0C); hm->AddHistogram(histClass, "Eta_CentFT0C", "#eta distribution", false, 500, -5.0, 5.0, VarManager::kEta, 20, 0.0, 100.0, VarManager::kCentFT0C); - hm->AddHistogram(histClass, "Phi_CentFT0C", "#varphi distribution", false, 500, -2. * TMath::Pi(), 2. * TMath::Pi(), VarManager::kPhi, 20, 0.0, 100.0, VarManager::kCentFT0C); + hm->AddHistogram(histClass, "Phi_CentFT0C", "#varphi distribution", false, 500, -2. * o2::constants::math::PI, 2. * o2::constants::math::PI, VarManager::kPhi, 20, 0.0, 100.0, VarManager::kCentFT0C); } if (subGroupStr.Contains("kine")) { - hm->AddHistogram(histClass, "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kEta, 200, -2. * TMath::Pi(), 2. * TMath::Pi(), VarManager::kPhi); + hm->AddHistogram(histClass, "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kEta, 200, -2. * o2::constants::math::PI, 2. * o2::constants::math::PI, VarManager::kPhi); hm->AddHistogram(histClass, "Eta_Pt", "", false, 20, -1.0, 1.0, VarManager::kEta, 100, 0.0, 20.0, VarManager::kPt); hm->AddHistogram(histClass, "Eta_VtxZ", "", false, 100, -1.0, 1.0, VarManager::kEta, 300, -15.0, 15.0, VarManager::kVtxZ); hm->AddHistogram(histClass, "Px", "p_{x} distribution", false, 200, 0.0, 20.0, VarManager::kPx); @@ -242,17 +438,21 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h } if (subGroupStr.Contains("its")) { hm->AddHistogram(histClass, "ITSncls", "Number of cluster in ITS", false, 8, -0.5, 7.5, VarManager::kITSncls); + hm->AddHistogram(histClass, "ITSncls_vs_BC", "Average Number of cluster in ITS vs BC", true, 3564, 0.0, 3564, VarManager::kBCOrbit, 2, 0.0, 7.0, VarManager::kITSncls); hm->AddHistogram(histClass, "ITSchi2", "ITS chi2", false, 100, 0.0, 50.0, VarManager::kITSchi2); hm->AddHistogram(histClass, "IsITSrefit", "", false, 2, -0.5, 1.5, VarManager::kIsITSrefit); hm->AddHistogram(histClass, "IsSPDany", "", false, 2, -0.5, 1.5, VarManager::kIsSPDany); hm->AddHistogram(histClass, "IsSPDfirst", "", false, 2, -0.5, 1.5, VarManager::kIsSPDfirst); - hm->AddHistogram(histClass, "ITSClusterMap", "", false, 128, -0.5, 127.5, VarManager::kITSClusterMap); - hm->AddHistogram(histClass, "ITSClustermap_vs_pin", "ITSClustermap vs pin", false, 200, 0.0, 20.0, VarManager::kPin, 128, -0.5, 127.5, VarManager::kITSClusterMap); - hm->AddHistogram(histClass, "ITSClustermap_vs_SignedPin", "ITSClustermap vs SignedPin", false, 400, -20.0, 20.0, VarManager::kSignedPin, 128, -0.5, 127.5, VarManager::kITSClusterMap); - hm->AddHistogram(histClass, "ITSClustermap_vs_pt", "ITSClustermap vs pt", false, 200, 0.0, 20.0, VarManager::kPt, 128, -0.5, 127.5, VarManager::kITSClusterMap); - hm->AddHistogram(histClass, "ITSClustermap_vs_eta", "ITSClustermap vs eta", false, 100, -1.0, 1.0, VarManager::kEta, 128, -0.5, 127.5, VarManager::kITSClusterMap); - hm->AddHistogram(histClass, "ITSClustermap_vs_phi", "ITSClustermap vs phi", false, 315, 0.0, 6.3, VarManager::kPhi, 128, -0.5, 127.5, VarManager::kITSClusterMap); - hm->AddHistogram(histClass, "SignedPin_P_ITSMap", "SignedPin vs P vs ITSMap", false, 400, -20.0, 20.0, VarManager::kSignedPin, 200, 0.0, 20.0, VarManager::kP, 2, -0.5, 1.5, VarManager::kHasITS); + hm->AddHistogram(histClass, "ITSncls_vsTimeFromSOR", "Number of cluster in ITS vs time from SOR", true, 10000, 0.0, 1000, VarManager::kTimeFromSOR, 8, -0.5, 7.5, VarManager::kITSncls); + if (subGroupStr.Contains("cluster")) { + hm->AddHistogram(histClass, "ITSClusterMap", "", false, 128, -0.5, 127.5, VarManager::kITSClusterMap); + hm->AddHistogram(histClass, "ITSClustermap_vs_pin", "ITSClustermap vs pin", false, 200, 0.0, 20.0, VarManager::kPin, 128, -0.5, 127.5, VarManager::kITSClusterMap); + hm->AddHistogram(histClass, "ITSClustermap_vs_SignedPin", "ITSClustermap vs SignedPin", false, 400, -20.0, 20.0, VarManager::kSignedPin, 128, -0.5, 127.5, VarManager::kITSClusterMap); + hm->AddHistogram(histClass, "ITSClustermap_vs_pt", "ITSClustermap vs pt", false, 200, 0.0, 20.0, VarManager::kPt, 128, -0.5, 127.5, VarManager::kITSClusterMap); + hm->AddHistogram(histClass, "ITSClustermap_vs_eta", "ITSClustermap vs eta", false, 100, -1.0, 1.0, VarManager::kEta, 128, -0.5, 127.5, VarManager::kITSClusterMap); + hm->AddHistogram(histClass, "ITSClustermap_vs_phi", "ITSClustermap vs phi", false, 315, 0.0, 6.3, VarManager::kPhi, 128, -0.5, 127.5, VarManager::kITSClusterMap); + hm->AddHistogram(histClass, "SignedPin_P_ITSMap", "SignedPin vs P vs ITSMap", false, 400, -20.0, 20.0, VarManager::kSignedPin, 200, 0.0, 20.0, VarManager::kP, 2, -0.5, 1.5, VarManager::kHasITS); + } if (subGroupStr.Contains("cent")) { hm->AddHistogram(histClass, "ITSncls_CentFT0C", "Number of cluster in ITS", false, 8, -0.5, 7.5, VarManager::kITSncls, 20, 0.0, 100.0, VarManager::kCentFT0C); hm->AddHistogram(histClass, "ITSchi2_CentFT0C", "ITS chi2", false, 100, 0.0, 50.0, VarManager::kITSchi2, 20, 0.0, 100.0, VarManager::kCentFT0C); @@ -274,10 +474,9 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h } if (subGroupStr.Contains("tpc")) { hm->AddHistogram(histClass, "TPCncls", "Number of cluster in TPC", false, 160, -0.5, 159.5, VarManager::kTPCncls); - hm->AddHistogram(histClass, "TPCncls_Phi", "Number of cluster in TPC vs #varphi", true, 720, 0.0, TMath::TwoPi(), VarManager::kPhi, 10, 0.0, 200.0, VarManager::kTPCncls); - hm->AddHistogram(histClass, "TPCncls_PhiPt", "Number of cluster in TPC vs p_{T} and #varphi", true, 20, 0.0, 10.0, VarManager::kPt, 720, 0.0, TMath::TwoPi(), VarManager::kPhi, 10, 0.0, 200.0, VarManager::kTPCncls); - hm->AddHistogram(histClass, "TPCncls_Run", "Number of cluster in TPC", true, (VarManager::GetNRuns() > 0 ? VarManager::GetNRuns() : 1), 0.5, 0.5 + VarManager::GetNRuns(), VarManager::kRunId, - 10, -0.5, 159.5, VarManager::kTPCncls, 10, 0., 1., VarManager::kNothing, VarManager::GetRunStr().Data()); + hm->AddHistogram(histClass, "TPCncls_vsTimeFromSOR", "Number of cluster in TPC vs time from SOR", true, 10000, 0.0, 1000., VarManager::kTimeFromSOR, 160, -0.5, 159.5, VarManager::kTPCncls); + hm->AddHistogram(histClass, "TPCncls_Phi", "Number of cluster in TPC vs #varphi", true, 720, 0.0, o2::constants::math::TwoPI, VarManager::kPhi, 10, 0.0, 200.0, VarManager::kTPCncls); + hm->AddHistogram(histClass, "TPCncls_PhiPt", "Number of cluster in TPC vs p_{T} and #varphi", true, 20, 0.0, 10.0, VarManager::kPt, 720, 0.0, o2::constants::math::TwoPI, VarManager::kPhi, 10, 0.0, 200.0, VarManager::kTPCncls); hm->AddHistogram(histClass, "TPCnclsCR", "Number of crossed rows in TPC", false, 160, -0.5, 159.5, VarManager::kTPCnclsCR); hm->AddHistogram(histClass, "TPCncls_TPCnclsCR", "Number of TPC cluster vs Number of crossed rows in TPC", false, 160, -0.5, 159.5, VarManager::kTPCncls, 160, -0.5, 159.5, VarManager::kTPCnclsCR); hm->AddHistogram(histClass, "IsTPCrefit", "", false, 2, -0.5, 1.5, VarManager::kIsTPCrefit); @@ -325,24 +524,48 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "TPCnSigPi_pIN", "TPC n-#sigma(#pi) vs pIN", false, nbins_pIN, pIN_bins, VarManager::kPin, nbins_nSigma, nSigma_bins, VarManager::kTPCnSigmaPi); hm->AddHistogram(histClass, "TPCnSigKa_pIN", "TPC n-#sigma(K) vs pIN", false, nbins_pIN, pIN_bins, VarManager::kPin, nbins_nSigma, nSigma_bins, VarManager::kTPCnSigmaKa); hm->AddHistogram(histClass, "TPCnSigPr_pIN", "TPC n-#sigma(p) vs pIN", false, nbins_pIN, pIN_bins, VarManager::kPin, nbins_nSigma, nSigma_bins, VarManager::kTPCnSigmaPr); - hm->AddHistogram(histClass, "TPCnSigEl_Corr_pIN", "TPC n-#sigma(e) Corr. vs pIN", false, nbins_pIN, pIN_bins, VarManager::kPin, nbins_nSigma, nSigma_bins, VarManager::kTPCnSigmaEl_Corr); - hm->AddHistogram(histClass, "TPCnSigPi_Corr_pIN", "TPC n-#sigma(#pi) Corr. vs pIN", false, nbins_pIN, pIN_bins, VarManager::kPin, nbins_nSigma, nSigma_bins, VarManager::kTPCnSigmaPi_Corr); - hm->AddHistogram(histClass, "TPCnSigPr_Corr_pIN", "TPC n-#sigma(p) Corr. vs pIN", false, nbins_pIN, pIN_bins, VarManager::kPin, nbins_nSigma, nSigma_bins, VarManager::kTPCnSigmaPr_Corr); + if (subGroupStr.Contains("tpcpid_fine_Corr")) { + hm->AddHistogram(histClass, "TPCnSigEl_Corr_pIN", "TPC n-#sigma(e) Corr. vs pIN", false, nbins_pIN, pIN_bins, VarManager::kPin, nbins_nSigma, nSigma_bins, VarManager::kTPCnSigmaEl_Corr); + hm->AddHistogram(histClass, "TPCnSigPi_Corr_pIN", "TPC n-#sigma(#pi) Corr. vs pIN", false, nbins_pIN, pIN_bins, VarManager::kPin, nbins_nSigma, nSigma_bins, VarManager::kTPCnSigmaPi_Corr); + hm->AddHistogram(histClass, "TPCnSigPr_Corr_pIN", "TPC n-#sigma(p) Corr. vs pIN", false, nbins_pIN, pIN_bins, VarManager::kPin, nbins_nSigma, nSigma_bins, VarManager::kTPCnSigmaPr_Corr); + } } else { - hm->AddHistogram(histClass, "TPCdedx_pIN", "TPC dE/dx vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 200, 0.0, 200., VarManager::kTPCsignal); - hm->AddHistogram(histClass, "TPCnSigEle_pIN", "TPC n-#sigma(e) vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 100, -5.0, 5.0, VarManager::kTPCnSigmaEl); + hm->AddHistogram(histClass, "TPCdedx_pIN", "TPC dE/dx vs pIN", false, 100, 0.0, 20.0, VarManager::kPin, 150, 0.0, 150., VarManager::kTPCsignal); + hm->AddHistogram(histClass, "TPCnSigEle_pIN", "TPC n-#sigma(e) vs pIN", false, 100, 0.0, 20.0, VarManager::kPin, 100, -5.0, 5.0, VarManager::kTPCnSigmaEl); + hm->AddHistogram(histClass, "TPCnSigEle_occupancy", "TPC n-#sigma(e) vs occupancy", false, 200, 0., 20000., VarManager::kTrackOccupancyInTimeRange, 100, -5.0, 5.0, VarManager::kTPCnSigmaEl); + hm->AddHistogram(histClass, "TPCnSigEle_timeFromSOR", "TPC n-#sigma(e) vs time from SOR", true, 10000, 0.0, 1000.0, VarManager::kTimeFromSOR, 10, -5.0, 5.0, VarManager::kTPCnSigmaEl); + hm->AddHistogram(histClass, "TPCnSigEle_occupTPCcontribLongA", "TPC n-#sigma(e) vs pileup n-contrib, long time range A-side", false, 20, 0.0, 10000.0, VarManager::kNTPCcontribLongA, 200, -5.0, 5.0, VarManager::kTPCnSigmaEl); + hm->AddHistogram(histClass, "TPCnSigEle_occupTPCmeanTimeLongA", "TPC n-#sigma(e) vs pileup mean time, long time range, A-side", false, 20, -100.0, 100.0, VarManager::kNTPCmeanTimeLongA, 200, -5.0, 5.0, VarManager::kTPCnSigmaEl); + hm->AddHistogram(histClass, "TPCnSigEle_occupTPCmedianTimeLongA", "TPC n-#sigma(e) vs pileup mean time, long time range, A-side", false, 20, -100.0, 100.0, VarManager::kNTPCmedianTimeLongA, 200, -5.0, 5.0, VarManager::kTPCnSigmaEl); + hm->AddHistogram(histClass, "TPCnSigEle_occupTPCcontribShortA", "TPC n-#sigma(e) vs pileup n-contrib, short time range A-side", false, 50, 0.0, 10000.0, VarManager::kNTPCcontribShortA, 200, -5.0, 5.0, VarManager::kTPCnSigmaEl); + hm->AddHistogram(histClass, "TPCnSigEle_occupTPCmeanTimeShortA", "TPC n-#sigma(e) vs pileup mean time, short time range, A-side", false, 20, -15.0, 15.0, VarManager::kNTPCmeanTimeShortA, 200, -5.0, 5.0, VarManager::kTPCnSigmaEl); + hm->AddHistogram(histClass, "TPCnSigEle_occupTPCmedianTimeShortA", "TPC n-#sigma(e) vs pileup mean time, short time range, A-side", false, 20, -15.0, 15.0, VarManager::kNTPCmedianTimeShortA, 200, -5.0, 5.0, VarManager::kTPCnSigmaEl); + hm->AddHistogram(histClass, "TPCnSigEle_occupTPCcontribLongC", "TPC n-#sigma(e) vs pileup n-contrib, long time range C-side", false, 20, 0.0, 10000.0, VarManager::kNTPCcontribLongC, 200, -5.0, 5.0, VarManager::kTPCnSigmaEl); + hm->AddHistogram(histClass, "TPCnSigEle_occupTPCmeanTimeLongC", "TPC n-#sigma(e) vs pileup mean time, long time range, C-side", false, 20, -100.0, 100.0, VarManager::kNTPCmeanTimeLongC, 200, -5.0, 5.0, VarManager::kTPCnSigmaEl); + hm->AddHistogram(histClass, "TPCnSigEle_occupTPCmedianTimeLongC", "TPC n-#sigma(e) vs pileup mean time, long time range, C-side", false, 20, -100.0, 100.0, VarManager::kNTPCmedianTimeLongC, 200, -5.0, 5.0, VarManager::kTPCnSigmaEl); + hm->AddHistogram(histClass, "TPCnSigEle_occupTPCcontribShortC", "TPC n-#sigma(e) vs pileup n-contrib, short time range C-side", false, 50, 0.0, 10000.0, VarManager::kNTPCcontribShortC, 200, -5.0, 5.0, VarManager::kTPCnSigmaEl); + hm->AddHistogram(histClass, "TPCnSigEle_occupTPCmeanTimeShortC", "TPC n-#sigma(e) vs pileup mean time, short time range, C-side", false, 20, -15.0, 15.0, VarManager::kNTPCmeanTimeShortC, 200, -5.0, 5.0, VarManager::kTPCnSigmaEl); + hm->AddHistogram(histClass, "TPCnSigEle_occupTPCmedianTimeShortC", "TPC n-#sigma(e) vs pileup mean time, short time range, C-side", false, 20, -15.0, 15.0, VarManager::kNTPCmedianTimeShortC, 200, -5.0, 5.0, VarManager::kTPCnSigmaEl); hm->AddHistogram(histClass, "TPCnSigPi_pIN", "TPC n-#sigma(#pi) vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 100, -5.0, 5.0, VarManager::kTPCnSigmaPi); + hm->AddHistogram(histClass, "TPCnSigPi_timeFromSOR", "TPC n-#sigma(#pi) vs time from SOR", true, 1000, 0.0, 1000.0, VarManager::kTimeFromSOR, 10, -5.0, 5.0, VarManager::kTPCnSigmaPi); + hm->AddHistogram(histClass, "TPCnSigPi_eta", "TPC n-#sigma(#pi) vs #eta", false, 20, -1.0, 1.0, VarManager::kEta, 200, -5.0, 5.0, VarManager::kTPCnSigmaPi); + hm->AddHistogram(histClass, "TPCnSigPi_etaPin_prof", " vs (#eta,p_{IN}), --s--", true, 20, -1.0, 1.0, VarManager::kEta, 20, 0.0, 10.0, VarManager::kPin, 10, -5.0, 5.0, VarManager::kTPCnSigmaPi); + hm->AddHistogram(histClass, "TPCnSigPi_etaCent_prof", " vs (#eta,cent), --s--", true, 20, -1.0, 1.0, VarManager::kEta, 20, 0.0, 100.0, VarManager::kCentFT0C, 10, -5.0, 5.0, VarManager::kTPCnSigmaPi); + hm->AddHistogram(histClass, "TPCnSigPi_etaContrib_prof", " vs (#eta,n-contrib real), --s--", true, 20, -1.0, 1.0, VarManager::kEta, 20, 0.0, 4000.0, VarManager::kVtxNcontribReal, 10, -5.0, 5.0, VarManager::kTPCnSigmaPi); + hm->AddHistogram(histClass, "TPCnSigPi_centFT0C", "TPC n-#sigma(#pi) vs centrality", false, 20, 0.0, 100.0, VarManager::kCentFT0C, 200, -5.0, 5.0, VarManager::kTPCnSigmaPi); + hm->AddHistogram(histClass, "TPCnSigPi_vtxContrib", "TPC n-#sigma(#pi) vs vtx. contrib real", false, 50, 0.0, 4000.0, VarManager::kVtxNcontribReal, 200, -5.0, 5.0, VarManager::kTPCnSigmaPi); + hm->AddHistogram(histClass, "TPCnSigPi_occupancy", "TPC n-#sigma(#pi) vs occupancy", false, 200, 0., 20000., VarManager::kTrackOccupancyInTimeRange, 100, -5.0, 5.0, VarManager::kTPCnSigmaPi); hm->AddHistogram(histClass, "TPCnSigKa_pIN", "TPC n-#sigma(K) vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 100, -5.0, 5.0, VarManager::kTPCnSigmaKa); hm->AddHistogram(histClass, "TPCnSigPr_pIN", "TPC n-#sigma(p) vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 100, -5.0, 5.0, VarManager::kTPCnSigmaPr); - hm->AddHistogram(histClass, "TPCnSigEl_Corr_pIN", "TPC n-#sigma(e) Corr. vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 100, -5.0, 5.0, VarManager::kTPCnSigmaEl_Corr); - hm->AddHistogram(histClass, "TPCnSigPi_Corr_pIN", "TPC n-#sigma(#pi) Corr. vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 100, -5.0, 5.0, VarManager::kTPCnSigmaPi_Corr); - hm->AddHistogram(histClass, "TPCnSigKa_Corr_pIN", "TPC n-#sigma(K) Corr. vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 100, -5.0, 5.0, VarManager::kTPCnSigmaKa_Corr); - hm->AddHistogram(histClass, "TPCnSigPr_Corr_pIN", "TPC n-#sigma(p) Corr. vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 100, -5.0, 5.0, VarManager::kTPCnSigmaPr_Corr); + hm->AddHistogram(histClass, "TPCnSigPr_timeFromSOR", "TPC n-#sigma(p) vs time from SOR", true, 10000, 0.0, 1000.0, VarManager::kTimeFromSOR, 10, -5.0, 5.0, VarManager::kTPCnSigmaPr); + hm->AddHistogram(histClass, "TPCnSigPr_occupancy", "TPC n-#sigma(p) vs. occupancy", false, 200, 0., 20000., VarManager::kTrackOccupancyInTimeRange, 100, -5.0, 5.0, VarManager::kTPCnSigmaPr); + if (subGroupStr.Contains("tpcpid_Corr")) { + hm->AddHistogram(histClass, "TPCnSigEl_Corr_pIN", "TPC n-#sigma(e) Corr. vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 100, -5.0, 5.0, VarManager::kTPCnSigmaEl_Corr); + hm->AddHistogram(histClass, "TPCnSigPi_Corr_pIN", "TPC n-#sigma(#pi) Corr. vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 100, -5.0, 5.0, VarManager::kTPCnSigmaPi_Corr); + hm->AddHistogram(histClass, "TPCnSigKa_Corr_pIN", "TPC n-#sigma(K) Corr. vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 100, -5.0, 5.0, VarManager::kTPCnSigmaKa_Corr); + hm->AddHistogram(histClass, "TPCnSigPr_Corr_pIN", "TPC n-#sigma(p) Corr. vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 100, -5.0, 5.0, VarManager::kTPCnSigmaPr_Corr); + } } - hm->AddHistogram(histClass, "TPCnSigEl_Corr_Eta", "TPC n-#sigma(e) Corr. vs Eta", false, 20, -1.0, 1.0, VarManager::kEta, 100, -5.0, 5.0, VarManager::kTPCnSigmaEl_Corr); - hm->AddHistogram(histClass, "TPCnSigPi_Corr_Eta", "TPC n-#sigma(#pi) Corr. vs Eta", false, 20, -1.0, 1.0, VarManager::kEta, 100, -5.0, 5.0, VarManager::kTPCnSigmaPi_Corr); - hm->AddHistogram(histClass, "TPCnSigKa_Corr_Eta", "TPC n-#sigma(K) Corr. vs Eta", false, 20, -1.0, 1.0, VarManager::kEta, 100, -5.0, 5.0, VarManager::kTPCnSigmaKa_Corr); - hm->AddHistogram(histClass, "TPCnSigPr_Corr_Eta", "TPC n-#sigma(p) Corr. vs Eta", false, 20, -1.0, 1.0, VarManager::kEta, 100, -5.0, 5.0, VarManager::kTPCnSigmaPr_Corr); } if (subGroupStr.Contains("postcalib")) { const int kNvarsPID = 4; @@ -351,8 +574,8 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h for (int i = 0; i <= kTPCnsigmaNbins; ++i) tpcNsigmaBinLims[i] = -7.0 + 0.2 * i; - const int kPinEleNbins = 18; - double pinEleBinLims[kPinEleNbins + 1] = {0.1, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 8.0, 10.0, 15.0}; + const int kPinEleNbins = 20; + double pinEleBinLims[kPinEleNbins + 1] = {0.1, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 8.0, 10.0, 12.0, 16.0, 20.0}; const int kEtaNbins = 9; double etaBinLimsI[kEtaNbins + 1] = {-0.9, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.7, 0.9}; @@ -511,83 +734,87 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h } } if (subGroupStr.Contains("runbyrun")) { - hm->AddHistogram(histClass, "TPCncls_run", "Number of cluster in TPC vs RunNumber", false, (VarManager::GetNRuns() > 0 ? VarManager::GetNRuns() : 1), -0.5, -0.5 + VarManager::GetNRuns(), VarManager::kRunIndex, - 160, -0.5, 159.5, VarManager::kTPCncls, 10, 0., 1., VarManager::kNothing, VarManager::GetRunStr().Data()); - hm->AddHistogram(histClass, "TPCdEdx_run", "TPCdEdx vs RunNumber", false, (VarManager::GetNRuns() > 0 ? VarManager::GetNRuns() : 1), -0.5, -0.5 + VarManager::GetNRuns(), VarManager::kRunIndex, - 300, 0., 300., VarManager::kTPCsignal, 10, 0., 1., VarManager::kNothing, VarManager::GetRunStr().Data()); - hm->AddHistogram(histClass, "TPCchi2_run", "TPCchi2 vs RunNumber", false, (VarManager::GetNRuns() > 0 ? VarManager::GetNRuns() : 1), -0.5, -0.5 + VarManager::GetNRuns(), VarManager::kRunIndex, - 100, 0., 10., VarManager::kTPCchi2, 10, 0., 1., VarManager::kNothing, VarManager::GetRunStr().Data()); - hm->AddHistogram(histClass, "Pt_Run", "p_{T} distribution", false, VarManager::GetDummyNRuns(), -0.5 + VarManager::GetDummyFirst(), 0.5 + VarManager::GetDummyLast(), VarManager::kRunNo, - 2000, 0.0, 20.0, VarManager::kPt, 1, 0, 1, VarManager::kNothing, VarManager::GetRunStr().Data()); - hm->AddHistogram(histClass, "ITSncls_Run", "Number of cluster in ITS", false, 100, -0.5 + VarManager::GetDummyFirst(), 0.5 + VarManager::GetDummyLast(), VarManager::kRunNo, - 8, -0.5, 7.5, VarManager::kITSncls, 1, 0, 1, VarManager::kNothing, VarManager::GetRunStr().Data()); - hm->AddHistogram(histClass, "ITSchi2_Run", "ITS chi2", false, VarManager::GetDummyNRuns(), -0.5 + VarManager::GetDummyFirst(), 0.5 + VarManager::GetDummyLast(), VarManager::kRunNo, - 100, 0.0, 50.0, VarManager::kITSchi2, 1, 0, 1, VarManager::kNothing, VarManager::GetRunStr().Data()); - hm->AddHistogram(histClass, "TPCncls_Run", "Number of cluster in TPC", false, 100, -0.5 + VarManager::GetDummyFirst(), 0.5 + VarManager::GetDummyLast(), VarManager::kRunNo, - 160, -0.5, 159.5, VarManager::kTPCncls, 1, 0, 1, VarManager::kNothing, VarManager::GetRunStr().Data()); - hm->AddHistogram(histClass, "TPCchi2_Run", "TPC chi2", false, VarManager::GetDummyNRuns(), -0.5 + VarManager::GetDummyFirst(), 0.5 + VarManager::GetDummyLast(), VarManager::kRunNo, - 100, 0.0, 10.0, VarManager::kTPCchi2, 1, 0, 1, VarManager::kNothing, VarManager::GetRunStr().Data()); - hm->AddHistogram(histClass, "TPCdedx_Run", "TPC dE/dx", false, VarManager::GetDummyNRuns(), -0.5 + VarManager::GetDummyFirst(), 0.5 + VarManager::GetDummyLast(), VarManager::kRunNo, - 200, 0.0, 200., VarManager::kTPCsignal, 1, 0, 1, VarManager::kNothing, VarManager::GetRunStr().Data()); - hm->AddHistogram(histClass, "TPCnSigEle_Run", "TPC n-#sigma(e)", false, 100, -0.5 + VarManager::GetDummyFirst(), 0.5 + VarManager::GetDummyLast(), VarManager::kRunNo, - 100, -5.0, 5.0, VarManager::kTPCnSigmaEl, 1, 0, 1, VarManager::kNothing, VarManager::GetRunStr().Data()); - hm->AddHistogram(histClass, "DCAxy_Run", "DCA_{xy}", false, VarManager::GetDummyNRuns(), -0.5 + VarManager::GetDummyFirst(), 0.5 + VarManager::GetDummyLast(), VarManager::kRunNo, - 400, -2.0, 2.0, VarManager::kTrackDCAxy, 1, 0, 1, VarManager::kNothing, VarManager::GetRunStr().Data()); - hm->AddHistogram(histClass, "DCAz_Run", "DCA_{z}", false, VarManager::GetDummyNRuns(), -0.5 + VarManager::GetDummyFirst(), 0.5 + VarManager::GetDummyLast(), VarManager::kRunNo, - 800, -4.0, 4.0, VarManager::kTrackDCAz, 1, 0, 1, VarManager::kNothing, VarManager::GetRunStr().Data()); + hm->AddHistogram(histClass, "TPCncls_Run", "Number of cluster in TPC vs RunNumber", true, 1, -0.5, 0.5, VarManager::kRunNo, 160, -0.5, 159.5, VarManager::kTPCncls, 1, 0., 1., VarManager::kNothing, "", "", "", -1, -1, false, true); + hm->AddHistogram(histClass, "TPCdEdx_Run", "TPCdEdx vs RunNumber", true, 1, -0.5, 0.5, VarManager::kRunNo, 300, 0., 300., VarManager::kTPCsignal, 1, 0., 1., VarManager::kNothing, "", "", "", -1, -1, false, true); + hm->AddHistogram(histClass, "TPCchi2_Run", "TPCchi2 vs RunNumber", true, 1, -0.5, 0.5, VarManager::kRunNo, 100, 0., 10., VarManager::kTPCchi2, 1, 0., 1., VarManager::kNothing, "", "", "", -1, -1, false, true); + hm->AddHistogram(histClass, "Pt_Run", "p_{T} distribution", true, 1, -0.5, 0.5, VarManager::kRunNo, 2000, 0.0, 20.0, VarManager::kPt, 1, 0, 1, VarManager::kNothing, "", "", "", -1, -1, false, true); + hm->AddHistogram(histClass, "ITSncls_Run", "Number of cluster in ITS", true, 1, -0.5, 0.5, VarManager::kRunNo, 8, -0.5, 7.5, VarManager::kITSncls, 1, 0, 1, VarManager::kNothing, "", "", "", -1, -1, false, true); + hm->AddHistogram(histClass, "ITSchi2_Run", "ITS chi2", true, 1, -0.5, 0.5, VarManager::kRunNo, 100, 0.0, 50.0, VarManager::kITSchi2, 1, 0, 1, VarManager::kNothing, "", "", "", -1, -1, false, true); + hm->AddHistogram(histClass, "TPCnSigEle_Run", "TPC n-#sigma(e)", true, 1, -0.5, 0.5, VarManager::kRunNo, 100, -5.0, 5.0, VarManager::kTPCnSigmaEl, 1, 0, 1, VarManager::kNothing, "", "", "", -1, -1, false, true); + hm->AddHistogram(histClass, "DCAxy_Run", "DCA_{xy}", true, 1, -0.5, 0.5, VarManager::kRunNo, 100, -1.0, 1.0, VarManager::kTrackDCAxy, 1, 0, 1, VarManager::kNothing, "", "", "", -1, -1, false, true); + hm->AddHistogram(histClass, "DCAz_Run", "DCA_{z}", true, 1, -0.5, 0.5, VarManager::kRunNo, 100, -1.0, 1.0, VarManager::kTrackDCAz, 1, 0, 1, VarManager::kNothing, "", "", "", -1, -1, false, true); } if (subGroupStr.Contains("dca")) { hm->AddHistogram(histClass, "DCAxy", "DCA_{xy}", false, 400, -2.0, 2.0, VarManager::kTrackDCAxy); + hm->AddHistogram(histClass, "DCAxy_vsTimeFromSOR", "DCA_{xy} vs time from SOR", true, 10000, 0.0, 1000.0, VarManager::kTimeFromSOR, 10, -2.0, 2.0, VarManager::kTrackDCAxy); hm->AddHistogram(histClass, "DCAz", "DCA_{z}", false, 800, -4.0, 4.0, VarManager::kTrackDCAz); - hm->AddHistogram(histClass, "DCAsigXY", "DCA_{XY} [#sigma]", false, 100, -10.0, 10.0, VarManager::kTrackDCAsigXY); - hm->AddHistogram(histClass, "DCAsigZ", "DCA_{Z} [#sigma]", false, 100, -10.0, 10.0, VarManager::kTrackDCAsigZ); - hm->AddHistogram(histClass, "Pt_DCAxy", "p_{T} vs DCA_{xy}", false, 200, 0.0, 20.0, VarManager::kPt, 400, -2.0, 2.0, VarManager::kTrackDCAxy); - hm->AddHistogram(histClass, "Pt_DCAz", "p_{T} vs DCA_{z}", false, 200, 0.0, 20.0, VarManager::kPt, 800, -4.0, 4.0, VarManager::kTrackDCAz); - hm->AddHistogram(histClass, "Eta_DCAxy", "#eta vs DCA_{xy}", false, 20, -1.0, 1.0, VarManager::kEta, 400, -2.0, 2.0, VarManager::kTrackDCAxy); - hm->AddHistogram(histClass, "Eta_DCAz", "#eta vs DCA_{z}", false, 20, -1.0, 1.0, VarManager::kEta, 800, -4.0, 4.0, VarManager::kTrackDCAz); - hm->AddHistogram(histClass, "Pt_DCAsigXY", "p_{T} vs DCA_{XY} [#sigma]", false, 200, 0.0, 20.0, VarManager::kPt, 100, -10.0, 10.0, VarManager::kTrackDCAsigXY); // JJ:edit - hm->AddHistogram(histClass, "Pt_DCAsigZ", "p_{T} vs DCA_{Z} [#sigma]", false, 200, 0.0, 20.0, VarManager::kPt, 100, -10.0, 10.0, VarManager::kTrackDCAsigZ); - hm->AddHistogram(histClass, "Pt_DCAresXY", "p_{T} vs #DeltaDCA_{XY}", false, 200, 0.0, 10.0, VarManager::kPt, 100, -0.03, 0.03, VarManager::kTrackDCAresXY); - hm->AddHistogram(histClass, "Pt_DCAresZ", "p_{T} vs #DeltaDCA_{Z}", false, 200, 0.0, 10.0, VarManager::kPt, 100, -0.03, 0.03, VarManager::kTrackDCAresZ); + hm->AddHistogram(histClass, "DCAz_vsTimeFromSOR", "DCA_{z} vs time from SOR", true, 10000, 0.0, 1000.0, VarManager::kTimeFromSOR, 10, -2.0, 2.0, VarManager::kTrackDCAz); + hm->AddHistogram(histClass, "DCAsigXY", "DCA_{XY} [#sigma]", false, 200, -20.0, 20.0, VarManager::kTrackDCAsigXY); + hm->AddHistogram(histClass, "DCAsigZ", "DCA_{Z} [#sigma]", false, 200, -20.0, 20.0, VarManager::kTrackDCAsigZ); + hm->AddHistogram(histClass, "DCAxy_DCAz", "DCA_{xy} vs DCA_{z}", false, 200, -4.0, 4.0, VarManager::kTrackDCAxy, 200, -4.0, 4.0, VarManager::kTrackDCAz); + hm->AddHistogram(histClass, "DCAsigXY_DCAsigZ", "DCA_{XY} [#sigma] vs DCA_{Z} [#sigma]", false, 200, -20.0, 20.0, VarManager::kTrackDCAsigXY, 200, -20.0, 20.0, VarManager::kTrackDCAsigZ); + if (subGroupStr.Contains("pt")) { + hm->AddHistogram(histClass, "Pt_DCAxy", "p_{T} vs DCA_{xy}", false, 200, 0.0, 20.0, VarManager::kPt, 400, -2.0, 2.0, VarManager::kTrackDCAxy); + hm->AddHistogram(histClass, "Pt_DCAz", "p_{T} vs DCA_{z}", false, 200, 0.0, 20.0, VarManager::kPt, 800, -4.0, 4.0, VarManager::kTrackDCAz); + hm->AddHistogram(histClass, "Pt_DCAsigXY", "p_{T} vs DCA_{XY} [#sigma]", false, 200, 0.0, 20.0, VarManager::kPt, 200, -20.0, 20.0, VarManager::kTrackDCAsigXY); // JJ:edit + hm->AddHistogram(histClass, "Pt_DCAsigZ", "p_{T} vs DCA_{Z} [#sigma]", false, 200, 0.0, 20.0, VarManager::kPt, 200, -20.0, 20.0, VarManager::kTrackDCAsigZ); + hm->AddHistogram(histClass, "Pt_DCAresXY", "p_{T} vs #DeltaDCA_{XY}", false, 200, 0.0, 10.0, VarManager::kPt, 100, -0.03, 0.03, VarManager::kTrackDCAresXY); + hm->AddHistogram(histClass, "Pt_DCAresZ", "p_{T} vs #DeltaDCA_{Z}", false, 200, 0.0, 10.0, VarManager::kPt, 100, -0.03, 0.03, VarManager::kTrackDCAresZ); + } + if (subGroupStr.Contains("eta")) { + hm->AddHistogram(histClass, "Eta_DCAxy", "#eta vs DCA_{xy}", false, 20, -1.0, 1.0, VarManager::kEta, 400, -2.0, 2.0, VarManager::kTrackDCAxy); + hm->AddHistogram(histClass, "Eta_DCAz", "#eta vs DCA_{z}", false, 20, -1.0, 1.0, VarManager::kEta, 800, -4.0, 4.0, VarManager::kTrackDCAz); + } if (subGroupStr.Contains("dca_fine")) { // Fine binning hm->AddHistogram(histClass, "DCAxy_fine", "DCA_{xy}", false, 1000, -0.2, 0.2, VarManager::kTrackDCAxy); hm->AddHistogram(histClass, "DCAz_fine", "DCA_{z}", false, 1000, -0.2, 0.2, VarManager::kTrackDCAz); hm->AddHistogram(histClass, "IsSPDfirst_Pt_DCAxy_fine", "IsSPDfirst vs p_{T} vs DCA_{xy}", false, 200, 0.0, 20.0, VarManager::kPt, 1000, -0.2, 0.2, VarManager::kTrackDCAxy, 2, -0.5, 1.5, VarManager::kIsSPDfirst); hm->AddHistogram(histClass, "IsSPDfirst_Pt_DCAz_fine", "IsSPDfirst vs p_{T} vs DCA_{z}", false, 200, 0.0, 20.0, VarManager::kPt, 1000, -0.2, 0.2, VarManager::kTrackDCAz, 2, -0.5, 1.5, VarManager::kIsSPDfirst); - hm->AddHistogram(histClass, "PtLow_DCAxy_fine", "p_{T} vs DCA_{xy}", false, 100, 0.0, 2.0, VarManager::kPt, 1000, -0.2, 0.2, VarManager::kTrackDCAxy); - hm->AddHistogram(histClass, "PtLow_DCAz_fine", "p_{T} vs DCA_{z}", false, 100, 0.0, 2.0, VarManager::kPt, 1000, -0.2, 0.2, VarManager::kTrackDCAz); - hm->AddHistogram(histClass, "PtHigh_DCAxy_fine", "p_{T} vs DCA_{xy}", false, 200, 0.0, 20.0, VarManager::kPt, 1000, -0.05, 0.05, VarManager::kTrackDCAxy); - hm->AddHistogram(histClass, "PtHigh_DCAz_fine", "p_{T} vs DCA_{z}", false, 200, 0.0, 20.0, VarManager::kPt, 1000, -0.05, 0.05, VarManager::kTrackDCAz); + if (subGroupStr.Contains("pt")) { + hm->AddHistogram(histClass, "PtLow_DCAxy_fine", "p_{T} vs DCA_{xy}", false, 100, 0.0, 2.0, VarManager::kPt, 1000, -0.2, 0.2, VarManager::kTrackDCAxy); + hm->AddHistogram(histClass, "PtLow_DCAz_fine", "p_{T} vs DCA_{z}", false, 100, 0.0, 2.0, VarManager::kPt, 1000, -0.2, 0.2, VarManager::kTrackDCAz); + hm->AddHistogram(histClass, "PtHigh_DCAxy_fine", "p_{T} vs DCA_{xy}", false, 200, 0.0, 20.0, VarManager::kPt, 1000, -0.05, 0.05, VarManager::kTrackDCAxy); + hm->AddHistogram(histClass, "PtHigh_DCAz_fine", "p_{T} vs DCA_{z}", false, 200, 0.0, 20.0, VarManager::kPt, 1000, -0.05, 0.05, VarManager::kTrackDCAz); + } } } if (subGroupStr.Contains("muon")) { - hm->AddHistogram(histClass, "MuonNClusters", "", false, 100, 0.0, 10.0, VarManager::kMuonNClusters); - hm->AddHistogram(histClass, "pdca", "", false, 200, 0.0, 1000., VarManager::kMuonPDca); - hm->AddHistogram(histClass, "RAtAbsorberEnd", "", false, 100, 0.0, 200., VarManager::kMuonRAtAbsorberEnd); - hm->AddHistogram(histClass, "Chi2", "", false, 100, 0.0, 200.0, VarManager::kMuonChi2); - hm->AddHistogram(histClass, "Chi2MCHMID", "", false, 100, 0.0, 200.0, VarManager::kMuonChi2MatchMCHMID); - hm->AddHistogram(histClass, "Chi2MCHMFT", "", false, 100, 0.0, 200.0, VarManager::kMuonChi2MatchMCHMFT); - hm->AddHistogram(histClass, "Chi2MatchScoreMCHMFT", "", false, 100, 0.0, 200.0, VarManager::kMuonMatchScoreMCHMFT); - hm->AddHistogram(histClass, "MuonCXX", "", false, 100, -1.0, 1.0, VarManager::kMuonCXX); - hm->AddHistogram(histClass, "MuonCYY", "", false, 100, -1.0, 1.0, VarManager::kMuonCYY); - hm->AddHistogram(histClass, "MuonCPhiPhi", "", false, 100, -1.0, 1.0, VarManager::kMuonCPhiPhi); - hm->AddHistogram(histClass, "MuonCTglTgl", "", false, 100, -1.0, 1.0, VarManager::kMuonCTglTgl); - hm->AddHistogram(histClass, "MuonC1Pt21Pt2", "", false, 100, -1.0, 1.0, VarManager::kMuonC1Pt21Pt2); - hm->AddHistogram(histClass, "MCHBitMap_vs_pt", "MCH vs pt", false, 1025, 0.0, 1025.0, VarManager::kMCHBitMap, 400, 0, 100, VarManager::kPt); - hm->AddHistogram(histClass, "MuonTime", "", false, 100, -1.0, 1.0, VarManager::kMuonTime); - hm->AddHistogram(histClass, "MuonTimeRes", "", false, 100, -1.0, 1.0, VarManager::kMuonTimeRes); - hm->AddHistogram(histClass, "MuonDcaX_vs_phi", "", false, 2000, -20.0, 20.0, VarManager::kMuonDCAx, 200, -2. * TMath::Pi(), 2. * TMath::Pi(), VarManager::kPhi); - hm->AddHistogram(histClass, "MuonDcaY_vs_phi", "", false, 2000, -20.0, 20.0, VarManager::kMuonDCAy, 200, -2. * TMath::Pi(), 2. * TMath::Pi(), VarManager::kPhi); - hm->AddHistogram(histClass, "MuonDcaX_vs_eta", "", false, 2000, -20.0, 20.0, VarManager::kMuonDCAx, 500, -5.0, 5.0, VarManager::kEta); - hm->AddHistogram(histClass, "MuonDcaY_vs_eta", "", false, 2000, -20.0, 20.0, VarManager::kMuonDCAy, 500, -5.0, 5.0, VarManager::kEta); + if (!subGroupStr.Contains("ambiguity")) { + hm->AddHistogram(histClass, "MuonNClusters", "", false, 100, 0.0, 10.0, VarManager::kMuonNClusters); + hm->AddHistogram(histClass, "pdca", "", false, 200, 0.0, 1000., VarManager::kMuonPDca); + hm->AddHistogram(histClass, "RAtAbsorberEnd", "", false, 100, 0.0, 200., VarManager::kMuonRAtAbsorberEnd); + hm->AddHistogram(histClass, "Chi2", "", false, 100, 0.0, 200.0, VarManager::kMuonChi2); + hm->AddHistogram(histClass, "Chi2MCHMID", "", false, 100, 0.0, 200.0, VarManager::kMuonChi2MatchMCHMID); + hm->AddHistogram(histClass, "Chi2MCHMFT", "", false, 100, 0.0, 200.0, VarManager::kMuonChi2MatchMCHMFT); + hm->AddHistogram(histClass, "Chi2MatchScoreMCHMFT", "", false, 100, 0.0, 200.0, VarManager::kMuonMatchScoreMCHMFT); + hm->AddHistogram(histClass, "MuonCXX", "", false, 100, -1.0, 1.0, VarManager::kMuonCXX); + hm->AddHistogram(histClass, "MuonCYY", "", false, 100, -1.0, 1.0, VarManager::kMuonCYY); + hm->AddHistogram(histClass, "MuonCPhiPhi", "", false, 100, -1.0, 1.0, VarManager::kMuonCPhiPhi); + hm->AddHistogram(histClass, "MuonCTglTgl", "", false, 100, -1.0, 1.0, VarManager::kMuonCTglTgl); + hm->AddHistogram(histClass, "MuonC1Pt21Pt2", "", false, 100, -1.0, 1.0, VarManager::kMuonC1Pt21Pt2); + hm->AddHistogram(histClass, "MCHBitMap_vs_pt", "MCH vs pt", false, 1025, 0.0, 1025.0, VarManager::kMCHBitMap, 400, 0, 100, VarManager::kPt); + hm->AddHistogram(histClass, "MuonTime", "", false, 100, -1.0, 1.0, VarManager::kMuonTime); + hm->AddHistogram(histClass, "MuonTimeRes", "", false, 100, -1.0, 1.0, VarManager::kMuonTimeRes); + hm->AddHistogram(histClass, "MuonDcaX_vs_phi", "", false, 2000, -20.0, 20.0, VarManager::kMuonDCAx, 200, -2. * o2::constants::math::PI, 2. * o2::constants::math::PI, VarManager::kPhi); + hm->AddHistogram(histClass, "MuonDcaY_vs_phi", "", false, 2000, -20.0, 20.0, VarManager::kMuonDCAy, 200, -2. * o2::constants::math::PI, 2. * o2::constants::math::PI, VarManager::kPhi); + hm->AddHistogram(histClass, "MuonDcaX_vs_eta", "", false, 2000, -20.0, 20.0, VarManager::kMuonDCAx, 500, -5.0, 5.0, VarManager::kEta); + hm->AddHistogram(histClass, "MuonDcaY_vs_eta", "", false, 2000, -20.0, 20.0, VarManager::kMuonDCAy, 500, -5.0, 5.0, VarManager::kEta); + } else { + hm->AddHistogram(histClass, "Pt", "p_{T} distribution", false, 2000, 0.0, 20.0, VarManager::kPt); + hm->AddHistogram(histClass, "Eta", "#eta distribution", false, 500, -5.0, 5.0, VarManager::kEta); + hm->AddHistogram(histClass, "Phi", "#varphi distribution", false, 500, -2. * o2::constants::math::PI, 2. * o2::constants::math::PI, VarManager::kPhi); + hm->AddHistogram(histClass, "AmbiguityInBunch", "", false, 10, 0.0, 10., VarManager::kMuonNAssocsInBunch); + hm->AddHistogram(histClass, "AmbiguityOutOfBunch", "", false, 10, 0.0, 10., VarManager::kMuonNAssocsOutOfBunch); + hm->AddHistogram(histClass, "AmbiguityInBunch_pt", "in bunch collision ambiguity vs p_{T}", false, 50, 0.0, 10.0, VarManager::kPt, 10, 0., 10., VarManager::kMuonNAssocsInBunch); + hm->AddHistogram(histClass, "AmbiguityOutOfBunch_pt", "out of bunch collision ambiguity vs p_{T}", false, 50, 0.0, 10.0, VarManager::kPt, 10, 0., 10., VarManager::kMuonNAssocsOutOfBunch); + } } + if (subGroupStr.Contains("muon-pdca")) { hm->AddHistogram(histClass, "p", "p", false, 200, 0.0, 20.0, VarManager::kP); hm->AddHistogram(histClass, "pdca_vs_p", "pDCA vs p", false, 2000, 0.0, 20.0, VarManager::kP, 200, 0.0, 1000., VarManager::kMuonPDca); hm->AddHistogram(histClass, "pdca_vs_pt", "pDCA vs pt", false, 2000, 0.0, 20.0, VarManager::kPt, 200, 0.0, 1000., VarManager::kMuonPDca); hm->AddHistogram(histClass, "pdca_vs_Rabs", "pDCA vs R_{abs}", false, 100, 0., 200., VarManager::kMuonRAtAbsorberEnd, 200, 0.0, 1000., VarManager::kMuonPDca); - hm->AddHistogram(histClass, "pdca_vs_Rabs_vs_p", "pDCA vs R_{abs} vs p", false, 2000, 0.0, 20.0, VarManager::kP, 100, 0., 200., VarManager::kMuonRAtAbsorberEnd, 200, 0.0, 1000., VarManager::kMuonPDca); - hm->AddHistogram(histClass, "pdca_vs_Rabs_vs_pt", "pDCA vs R_{abs} vs pt", false, 2000, 0.0, 20.0, VarManager::kPt, 100, 0., 200., VarManager::kMuonRAtAbsorberEnd, 200, 0.0, 1000., VarManager::kMuonPDca); } if (subGroupStr.Contains("mft-pid")) { hm->AddHistogram(histClass, "hMftTrackEtaVsPt", "", false, 100, -5.f, -2.f, VarManager::kEta, 100, 0.f, 20.f, VarManager::kPt); @@ -598,30 +825,48 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h if (subGroupStr.Contains("mc")) { hm->AddHistogram(histClass, "Pt_vs_PtMC", "pT vs MC pT", false, 200, 0.0, 20.0, VarManager::kPt, 200, 0.0, 20.0, VarManager::kMCPt); hm->AddHistogram(histClass, "Eta_vs_EtaMC", "#eta vs MC #eta", false, 50, -1.0, 1.0, VarManager::kEta, 50, -1.0, 1.0, VarManager::kMCEta); - hm->AddHistogram(histClass, "Phi_vs_PhiMC", "#varphi vs MC #varphi", false, 50, 0.0, 2. * TMath::Pi(), VarManager::kPhi, 50, 0.0, 2. * TMath::Pi(), VarManager::kMCPhi); + hm->AddHistogram(histClass, "Phi_vs_PhiMC", "#varphi vs MC #varphi", false, 50, 0.0, 2. * o2::constants::math::PI, VarManager::kPhi, 50, 0.0, 2. * o2::constants::math::PI, VarManager::kMCPhi); hm->AddHistogram(histClass, "TrackPDGcode", "PDG code of track", false, 10001, -5000, 5000, VarManager::kMCPdgCode); } - if (subGroupStr.Contains("mcMother")) { + if (subGroupStr.Contains("mcmother")) { hm->AddHistogram(histClass, "MotherPDGcode", "PDG code of mother", false, 10001, -5000, 5000, VarManager::kMCMotherPdgCode); } if (subGroupStr.Contains("dmeson")) { hm->AddHistogram(histClass, "Mass", "", false, 500, 0.0, 5.0, VarManager::kMass); hm->AddHistogram(histClass, "Rapidity", "", false, 400, -4.0, 4.0, VarManager::kRap); } - if (subGroupStr.Contains("ambiguity")) { - hm->AddHistogram(histClass, "AmbiguityInBunch", "in bunch collision ambiguity", false, 10, 0., 10., VarManager::kBarrelNAssocsInBunch); - hm->AddHistogram(histClass, "AmbiguityInBunch_pt", "in bunch collision ambiguity vs p_{T}", false, 50, 0.0, 10.0, VarManager::kPt, 10, 0., 10., VarManager::kBarrelNAssocsInBunch); - hm->AddHistogram(histClass, "AmbiguityOutOfBunch", "out of bunch collision ambiguity", false, 10, 0., 10., VarManager::kBarrelNAssocsOutOfBunch); - hm->AddHistogram(histClass, "AmbiguityOutOfBunch_pt", "out of bunch collision ambiguity vs p_{T}", false, 50, 0.0, 10.0, VarManager::kPt, 10, 0., 10., VarManager::kBarrelNAssocsOutOfBunch); + if (subGroupStr.Contains("tpcpidvstofpid")) { + hm->AddHistogram(histClass, "tpcNSigmaKa_tofNSigmaKa", "", false, 200, -10., 10., VarManager::kTPCnSigmaKa, 200, -10., 10., VarManager::kTOFnSigmaKa); + hm->AddHistogram(histClass, "tpcNSigmaPi_tofNSigmaPi", "", false, 200, -10., 10., VarManager::kTPCnSigmaPi, 200, -10., 10., VarManager::kTOFnSigmaPi); + } + if (subGroupStr.Contains("singlemucumulant")) { + double PtBinEdges[67]; // 0-30GeV/c + for (int i = 0; i < 67; i++) { + if (i <= 39) { + PtBinEdges[i] = i / 10.; + } else { + PtBinEdges[i] = (i - 40) * 1. + 4.; + } + } + + double CentBinEdges[19]; // 0-90% + for (int i = 0; i < 19; i++) { + CentBinEdges[i] = i * 5; + } + + hm->AddHistogram(histClass, "Pt_centrFT0C_Corr2REFsingle", "", true, 66, PtBinEdges, VarManager::kPt, 18, CentBinEdges, VarManager::kCentFT0C, 0, nullptr, VarManager::kCORR2REFbysinglemu, "", "", "", VarManager::kNothing, VarManager::kM11REFoverMpsingle); + hm->AddHistogram(histClass, "Pt_centrFT0C_Corr4REFsingle", "", true, 66, PtBinEdges, VarManager::kPt, 18, CentBinEdges, VarManager::kCentFT0C, 0, nullptr, VarManager::kCORR4REFbysinglemu, "", "", "", VarManager::kNothing, VarManager::kM1111REFoverMpsingle); + hm->AddHistogram(histClass, "Pt_centrFT0C_Corr2POIsingle", "", true, 66, PtBinEdges, VarManager::kPt, 18, CentBinEdges, VarManager::kCentFT0C, 0, nullptr, VarManager::kCORR2POIsingle, "", "", "", VarManager::kNothing, VarManager::kM01POIoverMpsingle); + hm->AddHistogram(histClass, "Pt_centrFT0C_Corr4POIsingle", "", true, 66, PtBinEdges, VarManager::kPt, 18, CentBinEdges, VarManager::kCentFT0C, 0, nullptr, VarManager::kCORR4POIsingle, "", "", "", VarManager::kNothing, VarManager::kM0111POIoverMpsingle); } } - if (groupStr.Contains("mctruth_triple")) { + if (!groupStr.CompareTo("mctruth_triple")) { hm->AddHistogram(histClass, "Eta_Pt", "", false, 100, -2.0, 2.0, VarManager::kPairEta, 200, 0.0, 20.0, VarManager::kPairPt); hm->AddHistogram(histClass, "Eta_Pt_lepton1", "", false, 100, -2.0, 2.0, VarManager::kEta1, 200, 0.0, 20.0, VarManager::kPt1); hm->AddHistogram(histClass, "Eta_Pt_lepton2", "", false, 100, -2.0, 2.0, VarManager::kEta2, 200, 0.0, 20.0, VarManager::kPt2); hm->AddHistogram(histClass, "Eta_Pt_Photon", "", false, 100, -2.0, 2.0, VarManager::kEta, 200, 0.0, 20.0, VarManager::kPt); - hm->AddHistogram(histClass, "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kPairEta, 200, -2. * TMath::Pi(), 2. * TMath::Pi(), VarManager::kPairPhi); + hm->AddHistogram(histClass, "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kPairEta, 200, -2. * o2::constants::math::PI, 2. * o2::constants::math::PI, VarManager::kPairPhi); hm->AddHistogram(histClass, "Mass_Dilepton", "", false, 4500, 0.0, 4.5, VarManager::kPairMassDau); hm->AddHistogram(histClass, "Mass_Photon", "", false, 500, 0.0, 0.1, VarManager::kMassDau); hm->AddHistogram(histClass, "Mass_Dilepton_Mass_Photon", "", false, 500, 0.0, 5.0, VarManager::kPairMassDau, 500, 0.0, 5.0, VarManager::kMassDau); @@ -635,53 +880,91 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "DeltaMass_Jpsi", "", false, 1500, 3, 4.5, (VarManager::kDeltaMass_jpsi)); hm->AddHistogram(histClass, "Rapidity", "", false, 400, -4.0, 4.0, VarManager::kRap); } - if (groupStr.Contains("mctruth_pair")) { - hm->AddHistogram(histClass, "Mass_Pt", "", false, 500, 0.0, 5.0, VarManager::kMass, 200, 0.0, 20.0, VarManager::kPt); - hm->AddHistogram(histClass, "Pt", "", false, 2000, 0.0, 20.0, VarManager::kPt); - hm->AddHistogram(histClass, "Pt_Dilepton", "", false, 2000, 0.0, 20.0, VarManager::kPairPtDau); + if (!groupStr.CompareTo("mctruth_pair")) { + hm->AddHistogram(histClass, "Mass_Pt", "", false, 500, 0.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt); + hm->AddHistogram(histClass, "Pt", "", false, 200, 0.0, 20.0, VarManager::kPt); + hm->AddHistogram(histClass, "Pt_Dilepton", "", false, 200, 0.0, 20.0, VarManager::kPairPtDau); hm->AddHistogram(histClass, "Eta_Pt_lepton1", "", false, 100, -2.0, 2.0, VarManager::kEta1, 200, 0.0, 20.0, VarManager::kPt1); hm->AddHistogram(histClass, "Eta_Pt_lepton2", "", false, 100, -2.0, 2.0, VarManager::kEta2, 200, 0.0, 20.0, VarManager::kPt2); hm->AddHistogram(histClass, "Mass", "", false, 500, 0.0, 5.0, VarManager::kMass); hm->AddHistogram(histClass, "Eta_Pt", "", false, 40, -2.0, 2.0, VarManager::kEta, 200, 0.0, 20.0, VarManager::kPt); - hm->AddHistogram(histClass, "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kEta, 200, -2. * TMath::Pi(), 2. * TMath::Pi(), VarManager::kPhi); + hm->AddHistogram(histClass, "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kEta, 200, -2. * o2::constants::math::PI, 2. * o2::constants::math::PI, VarManager::kPhi); } - if (groupStr.Contains("mctruth")) { - hm->AddHistogram(histClass, "PtMC", "MC pT", false, 2000, 0.0, 20.0, VarManager::kMCPt); - hm->AddHistogram(histClass, "PtMC_photon", "MC pT", false, 4500, 0.0, 4.5, VarManager::kMCPt); - hm->AddHistogram(histClass, "MCY", "MC y", false, 50, -5.0, 5.0, VarManager::kMCY); + if (!groupStr.CompareTo("mctruth_quad")) { + hm->AddHistogram(histClass, "hMass_defaultDileptonMass", "", false, 1000, 3.0, 5.0, VarManager::kQuadDefaultDileptonMass); + hm->AddHistogram(histClass, "hPt", "", false, 150, 0.0, 15.0, VarManager::kQuadPt); + hm->AddHistogram(histClass, "hMass_defaultDileptonMass_Pt", "", false, 100, 3.0, 5.0, VarManager::kQuadDefaultDileptonMass, 150, 0.0, 15.0, VarManager::kQuadPt); + hm->AddHistogram(histClass, "hQ", "", false, 150, 0.0, 3.0, VarManager::kQ); + hm->AddHistogram(histClass, "hDeltaR1", "", false, 100, 0.0, 10.0, VarManager::kDeltaR1); + hm->AddHistogram(histClass, "hDeltaR2", "", false, 100, 0.0, 10.0, VarManager::kDeltaR2); + hm->AddHistogram(histClass, "hDeltaR", "", false, 100, 0.0, 10.0, VarManager::kDeltaR); + hm->AddHistogram(histClass, "hDiTrackMass", "", false, 300, 0.0, 3.0, VarManager::kDitrackMass); + hm->AddHistogram(histClass, "hMCPt_MCRap", "", false, 200, 0.0, 20.0, VarManager::kMCPt, 100, -2.0, 2.0, VarManager::kMCY); + hm->AddHistogram(histClass, "hMCPhi", "", false, 100, -TMath::Pi(), TMath::Pi(), VarManager::kMCPhi); + } + if (!groupStr.CompareTo("mctruth_track")) { + hm->AddHistogram(histClass, "PtMC", "MC pT", false, 200, 0.0, 20.0, VarManager::kMCPt); hm->AddHistogram(histClass, "EtaMC", "MC #eta", false, 50, -5.0, 5.0, VarManager::kMCEta); - hm->AddHistogram(histClass, "Eta_Pt", "", false, 40, -2.0, 2.0, VarManager::kMCEta, 200, 0.0, 20.0, VarManager::kMCPt); + hm->AddHistogram(histClass, "PhiMC", "MC #phi", false, 50, -6.3, 6.3, VarManager::kMCPhi); + hm->AddHistogram(histClass, "YMC", "MC y", false, 50, -5.0, 5.0, VarManager::kMCY); + hm->AddHistogram(histClass, "CentFT0CMC", "MC Cent. FT0C", false, 18, 0., 90., VarManager::kCentFT0C); + hm->AddHistogram(histClass, "PtMC_YMC", "MC pT vs MC y", false, 120, 0.0, 30.0, VarManager::kMCPt, 1000, -5.0, 5.0, VarManager::kMCY); + hm->AddHistogram(histClass, "EtaMC_PtMC", "", false, 40, -2.0, 2.0, VarManager::kMCEta, 200, 0.0, 20.0, VarManager::kMCPt); hm->AddHistogram(histClass, "VzMC", "MC vz", false, 100, -15.0, 15.0, VarManager::kMCVz); hm->AddHistogram(histClass, "VzMC_VtxZMC", "MC vz vs MC vtxZ", false, 50, -15.0, 15.0, VarManager::kMCVz, 50, -15.0, 15.0, VarManager::kMCVtxZ); - hm->AddHistogram(histClass, "Mass", "", false, 500, 0.0, 5.0, VarManager::kMCParticleWeight); - hm->AddHistogram(histClass, "Rapidity", "", false, 400, -4.0, 4.0, VarManager::kMCY); + hm->AddHistogram(histClass, "Weight", "", false, 50, 0.0, 5.0, VarManager::kMCParticleWeight); } - if (groupStr.Contains("pair")) { + if (!groupStr.CompareTo("pair")) { + if (subGroupStr.Contains("cepf")) { + hm->AddHistogram(histClass, "Mass", "", false, 300, 0.0, 12.0, VarManager::kMass); + hm->AddHistogram(histClass, "Mass_Pt", "", false, 300, 0.0, 12.0, VarManager::kMass, 10, 0.0, 20.0, VarManager::kPt); + hm->AddHistogram(histClass, "Mass_Y", "", false, 300, 0.0, 12.0, VarManager::kMass, 100, -5.0, 5.0, VarManager::kRap); + hm->AddHistogram(histClass, "Y_Pt", "", false, 100, -5.0, 5.0, VarManager::kRap, 20, 0.0, 20.0, VarManager::kPt); + } + if (subGroupStr.Contains("mult_pvcontrib")) { + hm->AddHistogram(histClass, "Mass_VtxNcontribReal", "Mass vs VtxNcontribReal", false, 200, 2.0, 5.0, VarManager::kMass, 200, 0, 200.0, VarManager::kVtxNcontribReal); + } if (subGroupStr.Contains("barrel")) { hm->AddHistogram(histClass, "Mass", "", false, 500, 0.0, 5.0, VarManager::kMass); hm->AddHistogram(histClass, "Mass_HighRange", "", false, 375, 0.0, 15.0, VarManager::kMass); hm->AddHistogram(histClass, "Pt", "", false, 2000, 0.0, 20., VarManager::kPt); hm->AddHistogram(histClass, "Mass_Pt", "", false, 125, 0.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt); + double massBins[76]; + for (int i = 0; i < 76; i++) { + massBins[i] = 1.5 + i * 0.04; + } + double ptBins[70]; + for (int i = 0; i <= 50; i++) { + ptBins[i] = i * 0.01; + } + for (int i = 1; i <= 19; i++) { + ptBins[50 + i] = 0.5 + i * 0.5; + } + hm->AddHistogram(histClass, "Mass_PtFine", "", false, 75, massBins, VarManager::kMass, 69, ptBins, VarManager::kPt); hm->AddHistogram(histClass, "Eta_Pt", "", false, 40, -2.0, 2.0, VarManager::kEta, 40, 0.0, 20.0, VarManager::kPt); + hm->AddHistogram(histClass, "Y_Pt", "", false, 40, -2.0, 2.0, VarManager::kRap, 40, 0.0, 20.0, VarManager::kPt); hm->AddHistogram(histClass, "Mass_VtxZ", "", true, 30, -15.0, 15.0, VarManager::kVtxZ, 500, 0.0, 5.0, VarManager::kMass); if (subGroupStr.Contains("pbpb")) { - hm->AddHistogram(histClass, "Mass_CentFT0C", "", false, 500, 0.0, 5.0, VarManager::kMass, 20, 0.0, 100.0, VarManager::kCentFT0C); - hm->AddHistogram(histClass, "Pt_CentFT0C", "", false, 500, 0.0, 1.5, VarManager::kPt, 20, 0.0, 100.0, VarManager::kCentFT0C); - hm->AddHistogram(histClass, "Mass_Pt_CentFT0C", "", false, 500, 0.0, 5.0, VarManager::kMass, 400, 0.0, 40.0, VarManager::kPt, 20, 0.0, 100.0, VarManager::kCentFT0C); + hm->AddHistogram(histClass, "Mass_CentFT0C", "", false, 125, 0.0, 5.0, VarManager::kMass, 20, 0.0, 100.0, VarManager::kCentFT0C); + hm->AddHistogram(histClass, "Pt_CentFT0C", "", false, 100, 0.0, 10.0, VarManager::kPt, 20, 0.0, 100.0, VarManager::kCentFT0C); + hm->AddHistogram(histClass, "Mass_Pt_CentFT0C", "", false, 75, 1.5, 4.5, VarManager::kMass, 20, 0.0, 10.0, VarManager::kPt, 10, 0.0, 100.0, VarManager::kCentFT0C); } if (subGroupStr.Contains("mult")) { hm->AddHistogram(histClass, "Mass_Pt_MultFV0A", "", false, 200, 0.0, 5.0, VarManager::kMass, 40, 0.0, 40.0, VarManager::kPt, 100, 0.0, 25000.0, VarManager::kMultFV0A); + hm->AddHistogram(histClass, "Mass_VtxNcontribReal", "Mass vs VtxNcontribReal", false, 200, 0.0, 5.0, VarManager::kMass, 200, 0, 200.0, VarManager::kVtxNcontribReal); + hm->AddHistogram(histClass, "Mass_VtxNcontribReal_VtxZ", "Mass vs VtxNcontribReal vs VtxZ", false, 200, 2.0, 5.0, VarManager::kMass, 150, 0, 150.0, VarManager::kVtxNcontribReal, 20, -10.0, 10.0, VarManager::kVtxZ); + hm->AddHistogram(histClass, "VtxZ_VtxNcontribReal", "VtxZ vs VtxNcontribReal", false, 240, -12.0, 12.0, VarManager::kVtxZ, 200, 0, 200.0, VarManager::kVtxNcontribReal); } if (subGroupStr.Contains("polarization")) { hm->AddHistogram(histClass, "cosThetaHE", "", false, 100, -1., 1., VarManager::kCosThetaHE); hm->AddHistogram(histClass, "cosThetaCS", "", false, 100, -1., 1., VarManager::kCosThetaCS); - hm->AddHistogram(histClass, "PhiHE", "", false, 100, -TMath::Pi(), TMath::Pi(), VarManager::kPhiHE); - hm->AddHistogram(histClass, "PhiCS", "", false, 100, -TMath::Pi(), TMath::Pi(), VarManager::kPhiCS); + hm->AddHistogram(histClass, "PhiHE", "", false, 100, -o2::constants::math::PI, o2::constants::math::PI, VarManager::kPhiHE); + hm->AddHistogram(histClass, "PhiCS", "", false, 100, -o2::constants::math::PI, o2::constants::math::PI, VarManager::kPhiCS); hm->AddHistogram(histClass, "Mass_Pt_cosThetaHE", "", false, 100, 1.0, 5.0, VarManager::kMass, 250, 0.0, 25.0, VarManager::kPt, 40, -1., 1., VarManager::kCosThetaHE); hm->AddHistogram(histClass, "Mass_Pt_cosThetaCS", "", false, 100, 1.0, 5.0, VarManager::kMass, 250, 0.0, 25.0, VarManager::kPt, 40, -1., 1., VarManager::kCosThetaCS); - hm->AddHistogram(histClass, "Mass_Pt_PhiHE", "", false, 100, 1.0, 5.0, VarManager::kMass, 250, 0.0, 25.0, VarManager::kPt, 40, -TMath::Pi(), TMath::Pi(), VarManager::kPhiHE); - hm->AddHistogram(histClass, "Mass_Pt_PhiCS", "", false, 100, 1.0, 5.0, VarManager::kMass, 250, 0.0, 25.0, VarManager::kPt, 40, -TMath::Pi(), TMath::Pi(), VarManager::kPhiCS); + hm->AddHistogram(histClass, "Mass_Pt_PhiHE", "", false, 100, 1.0, 5.0, VarManager::kMass, 250, 0.0, 25.0, VarManager::kPt, 40, -o2::constants::math::PI, o2::constants::math::PI, VarManager::kPhiHE); + hm->AddHistogram(histClass, "Mass_Pt_PhiCS", "", false, 100, 1.0, 5.0, VarManager::kMass, 250, 0.0, 25.0, VarManager::kPt, 40, -o2::constants::math::PI, o2::constants::math::PI, VarManager::kPhiCS); } if (subGroupStr.Contains("upsilon")) { hm->AddHistogram(histClass, "MassUpsilon_Pt", "", false, 500, 7.0, 12.0, VarManager::kMass, 400, 0.0, 40.0, VarManager::kPt); @@ -705,8 +988,13 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "LxyzProj", "", false, 1000, -1.0, 1.0, VarManager::kVertexingLxyzProjected); hm->AddHistogram(histClass, "TauzProj", "", false, 1000, -0.03, 0.03, VarManager::kVertexingTauzProjected); hm->AddHistogram(histClass, "TauxyProj", "", false, 1000, -0.03, 0.03, VarManager::kVertexingTauxyProjected); + hm->AddHistogram(histClass, "TauxyProj_Mass_Pt", "", false, 50, 2.0, 4.0, VarManager::kMass, 10, 0.0, 20.0, VarManager::kPt, 1000, -0.03, 0.03, VarManager::kVertexingTauxyProjected); + hm->AddHistogram(histClass, "TauzProj_Mass_Pt", "", false, 50, 2.0, 4.0, VarManager::kMass, 10, 0.0, 20.0, VarManager::kPt, 1000, -0.03, 0.03, VarManager::kVertexingTauzProjected); + hm->AddHistogram(histClass, "TauxyzProj", "", false, 1000, -0.03, 0.03, VarManager::kVertexingTauxyzProjected); + hm->AddHistogram(histClass, "LxyProj_Pt", "", false, 10, 0.0, 20.0, VarManager::kPt, 1000, -1.0, 1.0, VarManager::kVertexingLxyProjected); hm->AddHistogram(histClass, "LxyProj_Mass_Pt", "", false, 50, 2.0, 4.0, VarManager::kMass, 10, 0.0, 20.0, VarManager::kPt, 1000, -1.0, 1.0, VarManager::kVertexingLxyProjected); hm->AddHistogram(histClass, "LzProj_Mass_Pt", "", false, 50, 2.0, 4.0, VarManager::kMass, 10, 0.0, 20.0, VarManager::kPt, 1000, -1.0, 1.0, VarManager::kVertexingLzProjected); + hm->AddHistogram(histClass, "CosPointingAngle", "", false, 200, -1.0, 1.0, VarManager::kCosPointingAngle); } if (subGroupStr.Contains("kalman-filter")) { @@ -729,7 +1017,17 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "KFTracksDCAxyMax", "", false, 400, -2.0, 2.0, VarManager::kKFTracksDCAxyMax); hm->AddHistogram(histClass, "KFDCAxyBetweenProngs", "", false, 400, -2.0, 2.0, VarManager::kKFDCAxyBetweenProngs); hm->AddHistogram(histClass, "KFChi2OverNDFGeo", "", false, 150, -5, 10, VarManager::kKFChi2OverNDFGeo); + hm->AddHistogram(histClass, "KFTrack0DeviationFromPV", "", false, 150, 0, 15e+6, VarManager::kKFTrack0DeviationFromPV); + hm->AddHistogram(histClass, "KFTrack1DeviationFromPV", "", false, 150, 0, 15e+6, VarManager::kKFTrack1DeviationFromPV); + hm->AddHistogram(histClass, "KFTrack0DeviationxyFromPV", "", false, 150, 0, 15e+6, VarManager::kKFTrack0DeviationxyFromPV); + hm->AddHistogram(histClass, "KFTrack1DeviationxyFromPV", "", false, 150, 0, 15e+6, VarManager::kKFTrack1DeviationxyFromPV); + hm->AddHistogram(histClass, "KFPairDCAxyz", "", false, 400, -2.0, 2.0, VarManager::kKFJpsiDCAxyz); + hm->AddHistogram(histClass, "KFPairDCAxy", "", false, 400, -2.0, 2.0, VarManager::kKFJpsiDCAxy); + hm->AddHistogram(histClass, "KFPairDeviationFromPV", "", false, 150, 0, 15e+6, VarManager::kKFPairDeviationFromPV); + hm->AddHistogram(histClass, "KFPairDeviationxyFromPV", "", false, 150, 0, 15e+6, VarManager::kKFPairDeviationxyFromPV); hm->AddHistogram(histClass, "KFCosPA", "", false, 300, -1.5, 1.5, VarManager::kKFCosPA); + hm->AddHistogram(histClass, "KFMassGeoTop", "", false, 500, 0.0, 5.0, VarManager::kKFMassGeoTop); + hm->AddHistogram(histClass, "KFChi2OverNDFGeoTop", "", false, 150, -5, 10, VarManager::kKFChi2OverNDFGeoTop); hm->AddHistogram(histClass, "KFNTrks2PV", "", false, 210, -10, 200, VarManager::kKFNContributorsPV); hm->AddHistogram(histClass, "Mass_DCAxyzTwoProngs", "", false, 500, 0.0, 5.0, VarManager::kMass, 400, -2.0, 2.0, VarManager::kKFDCAxyzBetweenProngs); hm->AddHistogram(histClass, "Mass_DCAxyTwoProngs", "", false, 500, 0.0, 5.0, VarManager::kMass, 400, -2.0, 2.0, VarManager::kKFDCAxyBetweenProngs); @@ -778,16 +1076,31 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Mass_cos3DeltaPhi", "cos 3(#varphi-#Psi_{3}^{A}) vs m", true, 125, 0.0, 5.0, VarManager::kMass, 100, -1.0, 1.0, VarManager::kCos3DeltaPhi); } } else if (subGroupStr.Contains("dimuon")) { - hm->AddHistogram(histClass, "Mass", "", false, 750, 0.0, 15.0, VarManager::kMass); - hm->AddHistogram(histClass, "Pt", "", false, 120, 0.0, 30.0, VarManager::kPt); - hm->AddHistogram(histClass, "Rapidity", "", false, 200, 2.5, 4.0, VarManager::kRap); - hm->AddHistogram(histClass, "Rapidity", "", false, 400, -4.0, 4.0, VarManager::kRap); hm->AddHistogram(histClass, "Mass_Pt", "", false, 750, 0.0, 15.0, VarManager::kMass, 120, 0.0, 30.0, VarManager::kPt); - hm->AddHistogram(histClass, "Mass_Rapidity", "", false, 750, 0.0, 15.0, VarManager::kMass, 200, 2.5, 4.0, VarManager::kRap); - hm->AddHistogram(histClass, "Mass_VtxZ", "", true, 30, -15.0, 15.0, VarManager::kVtxZ, 750, 0.0, 15.0, VarManager::kMass); - hm->AddHistogram(histClass, "cosThetaHE", "", false, 100, -1., 1., VarManager::kCosThetaHE); - hm->AddHistogram(histClass, "DeltaPtotTracks", "", false, 2000, -100., 100., VarManager::kDeltaPtotTracks); - hm->AddHistogram(histClass, "Mass_DeltaPtotTracks", "", false, 150, 2.0, 5.0, VarManager::kMass, 200, -100., 100., VarManager::kDeltaPtotTracks); + hm->AddHistogram(histClass, "Mass_Rapidity", "", false, 750, 0.0, 15.0, VarManager::kMass, 150, 2.5, 4.0, VarManager::kRap); + hm->AddHistogram(histClass, "Mass_Phi", "", false, 750, 0.0, 15.0, VarManager::kMass, 180, constants::math::PI, 2 * constants::math::PI, VarManager::kPhi); + if (subGroupStr.Contains("dimuon-multi-diff")) { + int varsKine[3] = {VarManager::kMass, VarManager::kPt, VarManager::kRap}; + int binsKine[3] = {250, 120, 60}; + double xminKine[3] = {0.0, 0.0, 2.5}; + double xmaxKine[3] = {5.0, 30.0, 4.0}; + hm->AddHistogram(histClass, "Mass_Pt_Rapidity", "", 3, varsKine, binsKine, xminKine, xmaxKine, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-high-mass-multi-diff")) { + int varsKine[3] = {VarManager::kMass, VarManager::kPt, VarManager::kRap}; + int binsKine[3] = {250, 120, 60}; + double xminKine[3] = {7.0, 0.0, 2.5}; + double xmaxKine[3] = {12.0, 30.0, 4.0}; + hm->AddHistogram(histClass, "Mass_Pt_Rapidity", "", 3, varsKine, binsKine, xminKine, xmaxKine, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-centr")) { + hm->AddHistogram(histClass, "Mass_CentFT0C", "", false, 750, 0.0, 15.0, VarManager::kMass, 100, 0., 100., VarManager::kCentFT0C); + } + if (subGroupStr.Contains("qc")) { + hm->AddHistogram(histClass, "Mass_VtxZ", "", true, 30, -15.0, 15.0, VarManager::kVtxZ, 750, 0.0, 15.0, VarManager::kMass); + hm->AddHistogram(histClass, "DeltaPtotTracks", "", false, 2000, -100., 100., VarManager::kDeltaPtotTracks); + hm->AddHistogram(histClass, "Mass_DeltaPtotTracks", "", false, 150, 2.0, 5.0, VarManager::kMass, 200, -100., 100., VarManager::kDeltaPtotTracks); + } if (subGroupStr.Contains("mixedevent")) { hm->AddHistogram(histClass, "Mass_cos2DeltaPhiMu1", "cos 2(#varphi_{#mu1}-#phi_{#mu#mu}) vs m", false, 125, 0.0, 5.0, VarManager::kMass, 100, -1.0, 1.0, VarManager::kCos2DeltaPhiMu1); hm->AddHistogram(histClass, "Mass_cos2DeltaPhiMu2", "cos 2(#varphi_{#mu2}-#phi_{#mu#mu}) vs m", false, 125, 0.0, 5.0, VarManager::kMass, 100, -1.0, 1.0, VarManager::kCos2DeltaPhiMu2); @@ -798,37 +1111,231 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "U2Q2_CentFT0C_ev1", "mass vs. centrality vs. U2Q2_event1", false, 125, 0.0, 5.0, VarManager::kMass, 9, 0.0, 90.0, VarManager::kCentFT0C, 100, -10.0, 10.0, VarManager::kU2Q2Ev1); hm->AddHistogram(histClass, "U2Q2_CentFT0C_ev2", "mass vs. centrality vs. U2Q2_event2", false, 125, 0.0, 5.0, VarManager::kMass, 9, 0.0, 90.0, VarManager::kCentFT0C, 100, -10.0, 10.0, VarManager::kU2Q2Ev2); } - if (subGroupStr.Contains("dimuon-polarizationHE")) { + if (subGroupStr.Contains("metest")) { + double MassBinEdges[251]; // 0-5GeV/c2 + for (int i = 0; i < 251; i++) { + MassBinEdges[i] = i * 0.02; + } + + double PtBinEdges[49]; // 0-20GeV/c + for (int i = 0; i < 49; i++) { + if (i <= 9) { + PtBinEdges[i] = i / 10.; + } else { + PtBinEdges[i] = (i - 10) * 0.5 + 1.; + } + } + + double CentBinEdges[19]; // 0-90% + for (int i = 0; i < 19; i++) { + CentBinEdges[i] = i * 5; + } + + hm->AddHistogram(histClass, "Mass_Pt_CentFT0C_V2ME_SP", "Mass_Pt_CentFT0C_V2ME_SP", true, 250, MassBinEdges, VarManager::kMass, 48, PtBinEdges, VarManager::kPt, 18, CentBinEdges, VarManager::kCentFT0C, "", "", "", VarManager::kV2ME_SP, VarManager::kWV2ME_SP); + hm->AddHistogram(histClass, "Mass_Pt_CentFT0C_V2ME_EP", "Mass_Pt_CentFT0C_V2ME_EP", true, 250, MassBinEdges, VarManager::kMass, 48, PtBinEdges, VarManager::kPt, 18, CentBinEdges, VarManager::kCentFT0C, "", "", "", VarManager::kV2ME_EP, VarManager::kWV2ME_EP); + } + if (subGroupStr.Contains("cumulantme")) { + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_M11REFoverMpME", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 9, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kM11REFoverMpME); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_M1111REFoverMpME", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 9, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kM1111REFoverMpME); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_M01POIoverMpME", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 9, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kM01POIoverMpME); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_M0111POIoverMpME", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 9, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kM0111POIoverMpME); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2REFME", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 9, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR2REFbydimuonsME, VarManager::kM11REFoverMpME); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr4REFME", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 9, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR4REFbydimuonsME, VarManager::kM1111REFoverMpME); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2POIME", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 9, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR2POIME, VarManager::kM01POIoverMpME); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr4POIME", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 9, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR4POIME, VarManager::kM0111POIoverMpME); + hm->AddHistogram(histClass, "Mass_Pt_CentFT0C_V22ME", "Mass_Pt_CentFT0C_V22ME", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 90, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kV22ME, VarManager::kWV22ME); + hm->AddHistogram(histClass, "Mass_Pt_CentFT0C_V24ME", "Mass_Pt_CentFT0C_V24ME", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 90, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kV24ME, VarManager::kWV24ME); + } + if (subGroupStr.Contains("cumulantme1")) { + double MassBinEdges[251]; // 0-5GeV/c2 + for (int i = 0; i < 251; i++) { + MassBinEdges[i] = i * 0.02; + } + + double PtBinEdges[67]; // 0-30GeV/c + for (int i = 0; i < 67; i++) { + if (i <= 39) { + PtBinEdges[i] = i / 10.; + } else { + PtBinEdges[i] = (i - 40) * 1. + 4.; + } + } + + double CentBinEdges[19]; // 0-90% + for (int i = 0; i < 19; i++) { + CentBinEdges[i] = i * 5; + } + hm->AddHistogram(histClass, "Mass_Pt_CentFT0C_V22ME", "Mass_Pt_CentFT0C_V22ME", true, 250, MassBinEdges, VarManager::kMass, 66, PtBinEdges, VarManager::kPt, 18, CentBinEdges, VarManager::kCentFT0C, "", "", "", VarManager::kV22ME, VarManager::kWV22ME); + hm->AddHistogram(histClass, "Mass_Pt_CentFT0C_V24ME", "Mass_Pt_CentFT0C_V24ME", true, 250, MassBinEdges, VarManager::kMass, 66, PtBinEdges, VarManager::kPt, 18, CentBinEdges, VarManager::kCentFT0C, "", "", "", VarManager::kV24ME, VarManager::kWV24ME); + } + if (subGroupStr.Contains("cumulantme2")) { + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_M11REFoverMpME", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 9, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kM11REFoverMpME); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_M1111REFoverMpME", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 9, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kM1111REFoverMpME); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_M01POIoverMpME", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 9, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kM01POIoverMpME); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_M0111POIoverMpME", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 9, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kM0111POIoverMpME); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2REFME", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 9, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR2REFbydimuonsME, VarManager::kM11REFoverMpME); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr4REFME", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 9, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR4REFbydimuonsME, VarManager::kM1111REFoverMpME); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2POIME", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 9, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR2POIME, VarManager::kM01POIoverMpME); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr4POIME", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 9, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR4POIME, VarManager::kM0111POIoverMpME); + } + if (subGroupStr.Contains("dimuon-polarization-he")) { int varspTHE[4] = {VarManager::kMass, VarManager::kPt, VarManager::kCosThetaHE, VarManager::kPhiHE}; - int varsFV0AMulHE[4] = {VarManager::kMass, VarManager::kMultFV0A, VarManager::kCosThetaHE, VarManager::kPhiHE}; - int varsFT0CMulHE[4] = {VarManager::kMass, VarManager::kMultFT0C, VarManager::kCosThetaHE, VarManager::kPhiHE}; - int varsTPCMulHE[4] = {VarManager::kMass, VarManager::kMultTPC, VarManager::kCosThetaHE, VarManager::kPhiHE}; + int varsrapHE[4] = {VarManager::kMass, VarManager::kRap, VarManager::kCosThetaHE, VarManager::kPhiHE}; int binspT[4] = {100, 20, 20, 20}; - int binsMul[4] = {100, 50, 20, 20}; + int binsy[4] = {100, 10, 20, 20}; double xminpT[4] = {1., 0., -1., -3.14}; double xmaxpT[4] = {5., 20., 1., +3.14}; - double xminMul[4] = {1., 0., -1., -3.14}; - double xmaxMul[4] = {5., 5000., 1., +3.14}; + double xminy[4] = {1., 2.5, -1., -3.14}; + double xmaxy[4] = {5., 4.0, 1., +3.14}; hm->AddHistogram(histClass, "Mass_Pt_cosThetaHE_phiHE", "", 4, varspTHE, binspT, xminpT, xmaxpT, 0, -1, kFALSE); - hm->AddHistogram(histClass, "Mass_MultFV0A_cosThetaHE_phiHE", "", 4, varsFV0AMulHE, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); - hm->AddHistogram(histClass, "Mass_MultFT0C_cosThetaHE_phiHE", "", 4, varsFT0CMulHE, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); - hm->AddHistogram(histClass, "Mass_MultTPC_cosThetaHE_phiHE", "", 4, varsTPCMulHE, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); + hm->AddHistogram(histClass, "Mass_y_cosThetaHE_phiHE", "", 4, varsrapHE, binsy, xminy, xmaxy, 0, -1, kFALSE); } - if (subGroupStr.Contains("dimuon-polarizationCS")) { + if (subGroupStr.Contains("dimuon-polarization-cs")) { int varspTCS[4] = {VarManager::kMass, VarManager::kPt, VarManager::kCosThetaCS, VarManager::kPhiCS}; - int varsFV0AMulCS[4] = {VarManager::kMass, VarManager::kMultFV0A, VarManager::kCosThetaCS, VarManager::kPhiCS}; - int varsFT0CMulCS[4] = {VarManager::kMass, VarManager::kMultFT0C, VarManager::kCosThetaCS, VarManager::kPhiCS}; - int varsTPCMulCS[4] = {VarManager::kMass, VarManager::kMultTPC, VarManager::kCosThetaCS, VarManager::kPhiCS}; + int varsrapCS[4] = {VarManager::kMass, VarManager::kRap, VarManager::kCosThetaCS, VarManager::kPhiCS}; int binspT[4] = {100, 20, 20, 20}; - int binsMul[4] = {100, 50, 20, 20}; + int binsy[4] = {100, 10, 20, 20}; double xminpT[4] = {1., 0., -1., -3.14}; double xmaxpT[4] = {5., 20., 1., +3.14}; - double xminMul[4] = {1., 0., -1., -3.14}; - double xmaxMul[4] = {5., 5000., 1., +3.14}; + double xminy[4] = {1., 2.5, -1., -3.14}; + double xmaxy[4] = {5., 4.0, 1., +3.14}; hm->AddHistogram(histClass, "Mass_Pt_cosThetaCS_phiCS", "", 4, varspTCS, binspT, xminpT, xmaxpT, 0, -1, kFALSE); - hm->AddHistogram(histClass, "Mass_MultFV0A_cosThetaCS_phiCS", "", 4, varsFV0AMulCS, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); - hm->AddHistogram(histClass, "Mass_MultFT0C_cosThetaCS_phiCS", "", 4, varsFT0CMulCS, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); - hm->AddHistogram(histClass, "Mass_MultTPC_cosThetaCS_phiCS", "", 4, varsTPCMulCS, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); + hm->AddHistogram(histClass, "Mass_y_cosThetaCS_phiCS", "", 4, varsrapCS, binsy, xminy, xmaxy, 0, -1, kFALSE); + } + if (subGroupStr.Contains("upsilon-polarization-he")) { + int varspTHE[4] = {VarManager::kMass, VarManager::kPt, VarManager::kCosThetaHE, VarManager::kPhiHE}; + int varsrapHE[4] = {VarManager::kMass, VarManager::kRap, VarManager::kCosThetaHE, VarManager::kPhiHE}; + int binspT[4] = {100, 20, 20, 20}; + int binsy[4] = {100, 10, 20, 20}; + double xminpT[4] = {1., 0., -1., -3.14}; + double xmaxpT[4] = {15., 20., 1., +3.14}; + double xminy[4] = {1., 2.5, -1., -3.14}; + double xmaxy[4] = {15., 4.0, 1., +3.14}; + hm->AddHistogram(histClass, "Mass_Pt_cosThetaHE_phiHE", "", 4, varspTHE, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + hm->AddHistogram(histClass, "Mass_y_cosThetaHE_phiHE", "", 4, varsrapHE, binsy, xminy, xmaxy, 0, -1, kFALSE); + } + if (subGroupStr.Contains("upsilon-polarization-cs")) { + int varspTCS[4] = {VarManager::kMass, VarManager::kPt, VarManager::kCosThetaCS, VarManager::kPhiCS}; + int varsrapCS[4] = {VarManager::kMass, VarManager::kRap, VarManager::kCosThetaCS, VarManager::kPhiCS}; + int binspT[4] = {100, 20, 20, 20}; + int binsy[4] = {100, 10, 20, 20}; + double xminpT[4] = {1., 0., -1., -3.14}; + double xmaxpT[4] = {15., 20., 1., +3.14}; + double xminy[4] = {1., 2.5, -1., -3.14}; + double xmaxy[4] = {15., 4.0, 1., +3.14}; + hm->AddHistogram(histClass, "Mass_Pt_cosThetaCS_phiCS", "", 4, varspTCS, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + hm->AddHistogram(histClass, "Mass_y_cosThetaCS_phiCS", "", 4, varsrapCS, binsy, xminy, xmaxy, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-polarization-vp")) { + int varspTVP[4] = {VarManager::kMass, VarManager::kPt, VarManager::kCosPhiVP, VarManager::kPhiVP}; + int varsrapVP[4] = {VarManager::kMass, VarManager::kRap, VarManager::kCosPhiVP, VarManager::kPhiVP}; + int binspT[4] = {100, 20, 24, 24}; + int binsy[4] = {100, 10, 24, 24}; + double xminpT[4] = {1., 0., -1., 0.}; + double xmaxpT[4] = {5., 20., 1., +3.14}; + double xminy[4] = {1., 2.5, -1., 0.}; + double xmaxy[4] = {5., 4.0, 1., +3.14}; + hm->AddHistogram(histClass, "Mass_Pt_phiVP", "", 4, varspTVP, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + hm->AddHistogram(histClass, "Mass_y_phiVP", "", 4, varsrapVP, binsy, xminy, xmaxy, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-rap")) { + int vars[4] = {VarManager::kMass, VarManager::kPt, VarManager::kCentFT0C, VarManager::kRap}; + int binspT[4] = {300, 200, 10, 6}; + double xminpT[4] = {2., 0., 0, 2.5}; + double xmaxpT[4] = {8., 20., 100, 4.0}; + hm->AddHistogram(histClass, "Mass_Pt_Cent_Rap", "", 4, vars, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-polarization-he-pbpb")) { + int varsHEpbpb[5] = {VarManager::kMass, VarManager::kPt, VarManager::kCentFT0C, VarManager::kCosThetaHE, VarManager::kPhiHE}; + int binspT[5] = {150, 30, 10, 10, 10}; + double xminpT[5] = {2., 0., 0, -1., -3.14}; + double xmaxpT[5] = {5., 3., 100, 1., 3.14}; + hm->AddHistogram(histClass, "Mass_Pt_Cent_cosThetaHE", "", 5, varsHEpbpb, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-polarization-lowmass-he-pbpb")) { + int varsHEpbpb[5] = {VarManager::kMass, VarManager::kPt, VarManager::kCentFT0C, VarManager::kCosThetaHE, VarManager::kPhiHE}; + int binspT[5] = {200, 30, 10, 10, 10}; + double xminpT[5] = {0.2, 0., 0, -1., -3.14}; + double xmaxpT[5] = {1.2, 3., 100, 1., 3.14}; + hm->AddHistogram(histClass, "Mass_Pt_Cent_cosThetaHE_lowmass", "", 5, varsHEpbpb, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-polarization-cs-pbpb")) { + int varsCSpbpb[5] = {VarManager::kMass, VarManager::kPt, VarManager::kCentFT0C, VarManager::kCosThetaCS, VarManager::kPhiCS}; + int binspT[5] = {150, 30, 10, 10, 10}; + double xminpT[5] = {2., 0., 0, -1., -3.14}; + double xmaxpT[5] = {5., 3., 100, 1., 3.14}; + hm->AddHistogram(histClass, "Mass_Pt_Cent_cosThetaCS", "", 5, varsCSpbpb, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-polarization-lowmass-cs-pbpb")) { + int varsCSpbpb[5] = {VarManager::kMass, VarManager::kPt, VarManager::kCentFT0C, VarManager::kCosThetaCS, VarManager::kPhiCS}; + int binspT[5] = {200, 30, 10, 10, 10}; + double xminpT[5] = {0.2, 0., 0, -1., -3.14}; + double xmaxpT[5] = {1.2, 3., 100, 1., 3.14}; + hm->AddHistogram(histClass, "Mass_Pt_Cent_cosThetaCS_lowmass", "", 5, varsCSpbpb, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-polarization-vp-pbpb")) { + int varsVPpbpb[5] = {VarManager::kMass, VarManager::kPt, VarManager::kCentFT0C, VarManager::kCosPhiVP, VarManager::kPhiVP}; + int binspT[5] = {150, 30, 10, 24, 24}; + double xminpT[5] = {2., 0., 0, -1., 0.}; + double xmaxpT[5] = {5., 3., 100, 1., 3.14}; + hm->AddHistogram(histClass, "Mass_Pt_Cent_phiVP", "", 5, varsVPpbpb, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-polarization-lowmass-vp-pbpb")) { + int varsVPpbpb[5] = {VarManager::kMass, VarManager::kPt, VarManager::kCentFT0C, VarManager::kCosPhiVP, VarManager::kPhiVP}; + int binspT[5] = {200, 30, 10, 24, 24}; + double xminpT[5] = {0.2, 0., 0, -1., 0.}; + double xmaxpT[5] = {1.2, 3., 100, 1., 3.14}; + hm->AddHistogram(histClass, "Mass_Pt_Cent_phiVP_lowmass", "", 5, varsVPpbpb, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-rap-polarization-he-pbpb")) { + int varsHEpbpb[5] = {VarManager::kMass, VarManager::kPt, VarManager::kCentFT0C, VarManager::kCosThetaHE, VarManager::kRap}; + int binspT[5] = {150, 30, 10, 10, 6}; + double xminpT[5] = {2., 0., 0, -1., 2.5}; + double xmaxpT[5] = {5., 3., 100, 1., 4.0}; + hm->AddHistogram(histClass, "Mass_Pt_Cent_cosThetaHE_Rap", "", 5, varsHEpbpb, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-rap-polarization-cs-pbpb")) { + int varsCSpbpb[5] = {VarManager::kMass, VarManager::kPt, VarManager::kCentFT0C, VarManager::kCosThetaCS, VarManager::kRap}; + int binspT[5] = {150, 30, 10, 10, 6}; + double xminpT[5] = {2., 0., 0, -1., 2.5}; + double xmaxpT[5] = {5., 3., 100, 1., 4.0}; + hm->AddHistogram(histClass, "Mass_Pt_Cent_cosThetaCS_Rap", "", 5, varsCSpbpb, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-midmult-polarization-he")) { + int varsITSTPCMulHE[4] = {VarManager::kMass, VarManager::kMultNTracksITSTPC, VarManager::kCosThetaHE, VarManager::kPhiHE}; + int varsITSMulHE[4] = {VarManager::kMass, VarManager::kMultNTracksHasITS, VarManager::kCosThetaHE, VarManager::kPhiHE}; + int binsMul[4] = {100, 20, 20, 20}; + double xminMul[4] = {1., 0., -1., -3.14}; + double xmaxMul[4] = {5., 120., 1., +3.14}; + hm->AddHistogram(histClass, "Mass_ITSTPCMult_cosThetaHE_phiHE", "", 4, varsITSTPCMulHE, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); + hm->AddHistogram(histClass, "Mass_ITSMult_cosThetaHE_phiHE", "", 4, varsITSMulHE, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-midmult-polarization-cs")) { + int varsITSTPCMulCS[4] = {VarManager::kMass, VarManager::kMultNTracksITSTPC, VarManager::kCosThetaCS, VarManager::kPhiCS}; + int varsITSMulCS[4] = {VarManager::kMass, VarManager::kMultNTracksHasITS, VarManager::kCosThetaCS, VarManager::kPhiCS}; + int binsMul[4] = {100, 20, 20, 20}; + double xminMul[4] = {1., 0., -1., -3.14}; + double xmaxMul[4] = {5., 120., 1., +3.14}; + hm->AddHistogram(histClass, "Mass_ITSTPCMult_cosThetaCS_phiCS", "", 4, varsITSTPCMulCS, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); + hm->AddHistogram(histClass, "Mass_ITSMult_cosThetaCS_phiCS", "", 4, varsITSMulCS, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-fwdmult-polarization-he")) { + int varsFT0AMulHE[4] = {VarManager::kMass, VarManager::kMultFT0A, VarManager::kCosThetaHE, VarManager::kPhiHE}; + int varsFV0AMulHE[4] = {VarManager::kMass, VarManager::kMultFV0A, VarManager::kCosThetaHE, VarManager::kPhiHE}; + int binsMul[4] = {100, 20, 20, 20}; + double xminMul[4] = {1., 0., -1., -3.14}; + double xmaxMul[4] = {5., 3000., 1., +3.14}; + hm->AddHistogram(histClass, "Mass_FT0AMult_cosThetaHE_phiHE", "", 4, varsFT0AMulHE, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); + hm->AddHistogram(histClass, "Mass_FV0AMult_cosThetaHE_phiHE", "", 4, varsFV0AMulHE, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-fwdmult-polarization-cs")) { + int varsFT0AMulCS[4] = {VarManager::kMass, VarManager::kMultFT0A, VarManager::kCosThetaCS, VarManager::kPhiCS}; + int varsFV0AMulCS[4] = {VarManager::kMass, VarManager::kMultFV0A, VarManager::kCosThetaCS, VarManager::kPhiCS}; + int binsMul[4] = {100, 20, 20, 20}; + double xminMul[4] = {1., 0., -1., -3.14}; + double xmaxMul[4] = {5., 3000., 1., +3.14}; + hm->AddHistogram(histClass, "Mass_FT0AMult_cosThetaCS_phiCS", "", 4, varsFT0AMulCS, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); + hm->AddHistogram(histClass, "Mass_FV0AMult_cosThetaCS_phiCS", "", 4, varsFV0AMulCS, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); } if (subGroupStr.Contains("vertexing-forward")) { hm->AddHistogram(histClass, "Lxyz", "", false, 100, 0.0, 10.0, VarManager::kVertexingLxyz); @@ -854,25 +1361,150 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h if (subGroupStr.Contains("lowmass")) { hm->AddHistogram(histClass, "MassLow", "", false, 400, 0.0, 2.0, VarManager::kMass); } + if (subGroupStr.Contains("lmmumu")) { + hm->AddHistogram(histClass, "Mass_QuadDCAabsXY", "", false, 250, 0.0, 5.0, VarManager::kMass, 900, 0.0, 3, VarManager::kQuadDCAabsXY); + hm->AddHistogram(histClass, "Mass_Lxyz", "", false, 250, 0.0, 5.0, VarManager::kMass, 1000, 0.0, 5, VarManager::kVertexingLxyz); + hm->AddHistogram(histClass, "Mass_OpeningAngle", "", false, 250, 0.0, 5.0, VarManager::kMass, 800, 0, 0.8, VarManager::kOpeningAngle); + } + if (subGroupStr.Contains("flow-dimuon-high-mass")) { + int varV2[6] = {VarManager::kMass, VarManager::kPt, VarManager::kRap, VarManager::kCentFT0C, VarManager::kU2Q2, VarManager::kCos2DeltaPhi}; + + int bins[6] = {50, 30, 6, 18, 200, 40}; + double minBins[6] = {7.0, 0.0, 2.5, 0.0, -10.0, -2.0}; + double maxBins[6] = {12.0, 30.0, 4.0, 90.0, 10.0, 2.0}; + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_V2", "", 6, varV2, bins, minBins, maxBins, 0, -1, kTRUE); + } if (subGroupStr.Contains("flow-dimuon")) { - int varV2[5] = {VarManager::kMass, VarManager::kPt, VarManager::kCentFT0C, VarManager::kU2Q2, VarManager::kCos2DeltaPhi}; - int varV3[5] = {VarManager::kMass, VarManager::kPt, VarManager::kCentFT0C, VarManager::kU3Q3, VarManager::kCos3DeltaPhi}; + int varV2[6] = {VarManager::kMass, VarManager::kPt, VarManager::kRap, VarManager::kCentFT0C, VarManager::kU2Q2, VarManager::kCos2DeltaPhi}; + // int varV3[6] = {VarManager::kMass, VarManager::kPt, VarManager::kRap, VarManager::kCentFT0C, VarManager::kU3Q3, VarManager::kCos3DeltaPhi}; // removed temporarily + + int bins[6] = {250, 60, 6, 18, 200, 40}; + double minBins[6] = {0.0, 0.0, 2.5, 0.0, -10.0, -2.0}; + double maxBins[6] = {5.0, 30.0, 4.0, 90.0, 10.0, 2.0}; + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_V2", "", 6, varV2, bins, minBins, maxBins, 0, -1, kTRUE); + // hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_V3", "", 6, varV3, bins, minBins, maxBins, 0, -1, kTRUE); // removed temporarily + } + if (subGroupStr.Contains("flow-ccdb")) { + double MassBinEdges[251]; // 0-5GeV/c2 + for (int i = 0; i < 251; i++) { + MassBinEdges[i] = i * 0.02; + } + + double PtBinEdges[49]; // 0-20GeV/c + for (int i = 0; i < 49; i++) { + if (i <= 9) { + PtBinEdges[i] = i / 10.; + } else { + PtBinEdges[i] = (i - 10) * 0.5 + 1.; + } + } - int bins[5] = {125, 120, 9, 200, 200}; - double minBins[5] = {0.0, 0.0, 0.0, -10.0, -10.0}; - double maxBins[5] = {5.0, 30.0, 90.0, 10.0, 10.0}; - hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_V2", "", 5, varV2, bins, minBins, maxBins, 0, -1, kTRUE); - hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_V3", "", 5, varV3, bins, minBins, maxBins, 0, -1, kTRUE); + double CentBinEdges[19]; // 0-90% + for (int i = 0; i < 19; i++) { + CentBinEdges[i] = i * 5; + } + + hm->AddHistogram(histClass, "Mass_Pt_CentFT0C_V2SPwR", "Mass_Pt_CentFT0C_V2SPwR", true, 250, MassBinEdges, VarManager::kMass, 48, PtBinEdges, VarManager::kPt, 18, CentBinEdges, VarManager::kCentFT0C, "", "", "", VarManager::kV2SP, VarManager::kWV2SP); + hm->AddHistogram(histClass, "Mass_Pt_CentFT0C_V2EPwR", "Mass_Pt_CentFT0C_V2EPwR", true, 250, MassBinEdges, VarManager::kMass, 48, PtBinEdges, VarManager::kPt, 18, CentBinEdges, VarManager::kCentFT0C, "", "", "", VarManager::kV2EP, VarManager::kWV2EP); + } + if (subGroupStr.Contains("cumulant")) { + int var[4] = {VarManager::kMass, VarManager::kPt, VarManager::kRap, VarManager::kCentFT0C}; + int bins[4] = {250, 60, 6, 18}; + double minBins[4] = {0.0, 0.0, 2.5, 0.0}; + double maxBins[4] = {5.0, 30.0, 4.0, 90.0}; + hm->AddHistogram(histClass, "centrFT0C_M11REFoverMp_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 1000, 0.0, 1000000.0, VarManager::kM11REFoverMp); + hm->AddHistogram(histClass, "centrFT0C_M1111REFoverMp_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 1000, 0.0, 100000000000000.0, VarManager::kM1111REFoverMp); + hm->AddHistogram(histClass, "centrFT0C_M11M1111REFoverMp_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 1000, 0.0, 10000000000000000.0, VarManager::kM11M1111REFoverMp); + hm->AddHistogram(histClass, "centrFT0C_Corr2REF_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 250, -1.0, 1.0, VarManager::kCORR2REFbydimuons, VarManager::kM11REFoverMp); + hm->AddHistogram(histClass, "centrFT0C_Corr4REF_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 250, -1.0, 1.0, VarManager::kCORR4REFbydimuons, VarManager::kM1111REFoverMp); + hm->AddHistogram(histClass, "centrFT0C_Corr2Corr4REF_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 250, -1.0, 1.0, VarManager::kCORR2CORR4REF, VarManager::kM11M1111REFoverMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_M11REFoverMp", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kM11REFoverMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_M1111REFoverMp", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kM1111REFoverMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_M01POIoverMp", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kM01POIoverMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_M0111POIoverMp", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kM0111POIoverMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_M11M1111REFoverMp", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kM11M1111REFoverMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_M01M0111overMp", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kM01M0111overMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_M11M0111overMp", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kM11M0111overMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_M11M01REFoverMp", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kM11M01overMp); + hm->AddHistogram(histClass, "Mass_Pt_Rapidity_CentFT0C", "", 4, var, bins, minBins, maxBins, 0, -1, kTRUE); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2REF", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR2REFbydimuons, VarManager::kM11REFoverMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr4REF", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR4REFbydimuons, VarManager::kM1111REFoverMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2POI", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR2POI, VarManager::kM01POIoverMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr4POI", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR4POI, VarManager::kM0111POIoverMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2REFCorr4REF", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR2CORR4REF, VarManager::kM11M1111REFoverMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2POICorr4POI", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR2POICORR4POI, VarManager::kM01M0111overMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2REFCorr4POI", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR2REFCORR4POI, VarManager::kM11M0111overMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2REFCorr2POI", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR2REFCORR2POI, VarManager::kM11M01overMp); + } + if (subGroupStr.Contains("cumulant1")) { + int var[4] = {VarManager::kMass, VarManager::kPt, VarManager::kRap, VarManager::kCentFT0C}; + int bins[4] = {250, 60, 6, 18}; + double minBins[4] = {0.0, 0.0, 2.5, 0.0}; + double maxBins[4] = {5.0, 30.0, 4.0, 90.0}; + hm->AddHistogram(histClass, "Mass_Pt_Rapidity_CentFT0C", "", 4, var, bins, minBins, maxBins, 0, -1, kTRUE); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2REF", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR2REFbydimuons, VarManager::kM11REFoverMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr4REF", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR4REFbydimuons, VarManager::kM1111REFoverMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2POI", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR2POI, VarManager::kM01POIoverMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr4POI", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR4POI, VarManager::kM0111POIoverMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2REFCorr4REF", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR2CORR4REF, VarManager::kM11M1111REFoverMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2POICorr4POI", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR2POICORR4POI, VarManager::kM01M0111overMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2REFCorr4POI", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR2REFCORR4POI, VarManager::kM11M0111overMp); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2REFCorr2POI", "", true, 250, 0.0, 5.0, VarManager::kMass, 60, 0.0, 30.0, VarManager::kPt, 18, 0.0, 90.0, VarManager::kCentFT0C, "", "", "", VarManager::kCORR2REFCORR2POI, VarManager::kM11M01overMp); + } + if (subGroupStr.Contains("cumulant2")) { + hm->AddHistogram(histClass, "centrFT0C_M11REFoverMp_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 1000, 0.0, 1000000.0, VarManager::kM11REFoverMp); + hm->AddHistogram(histClass, "centrFT0C_M1111REFoverMp_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 1000, 0.0, 100000000000000.0, VarManager::kM1111REFoverMp); + hm->AddHistogram(histClass, "centrFT0C_M11M1111REFoverMp_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 1000, 0.0, 10000000000000000.0, VarManager::kM11M1111REFoverMp); + hm->AddHistogram(histClass, "centrFT0C_Corr2REF_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 250, -1.0, 1.0, VarManager::kCORR2REFbydimuons, VarManager::kM11REFoverMp); + hm->AddHistogram(histClass, "centrFT0C_Corr4REF_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 250, -1.0, 1.0, VarManager::kCORR4REFbydimuons, VarManager::kM1111REFoverMp); + hm->AddHistogram(histClass, "centrFT0C_Corr2Corr4REF_ev", "", true, 100, 0.0, 100.0, VarManager::kCentFT0C, 250, -1.0, 1.0, VarManager::kCORR2CORR4REF, VarManager::kM11M1111REFoverMp); + } + if (subGroupStr.Contains("singlecumulant")) { + int var[4] = {VarManager::kMass, VarManager::kPt, VarManager::kRap, VarManager::kCentFT0C}; + int bins[4] = {250, 60, 6, 18}; + double minBins[4] = {0.0, 0.0, 2.5, 0.0}; + double maxBins[4] = {5.0, 30.0, 4.0, 90.0}; + hm->AddHistogram(histClass, "Mass_Pt_Rapidity_CentFT0C", "", 4, var, bins, minBins, maxBins, 0, -1, kTRUE); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2REFminus", "", true, 60, 0.0, 30.0, VarManager::kPt2, 18, 0.0, 90.0, VarManager::kCentFT0C, 0, 0.0, 1.0, VarManager::kCORR2REFbydimuons, "", "", "", VarManager::kNothing, VarManager::kM11REFoverMpminus); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr4REFminus", "", true, 60, 0.0, 30.0, VarManager::kPt2, 18, 0.0, 90.0, VarManager::kCentFT0C, 0, 0.0, 1.0, VarManager::kCORR4REFbydimuons, "", "", "", VarManager::kNothing, VarManager::kM1111REFoverMpminus); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2REFplus", "", true, 60, 0.0, 30.0, VarManager::kPt1, 18, 0.0, 90.0, VarManager::kCentFT0C, 0, 0.0, 1.0, VarManager::kCORR2REFbydimuons, "", "", "", VarManager::kNothing, VarManager::kM11REFoverMpplus); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr4REFplus", "", true, 60, 0.0, 30.0, VarManager::kPt1, 18, 0.0, 90.0, VarManager::kCentFT0C, 0, 0.0, 1.0, VarManager::kCORR4REFbydimuons, "", "", "", VarManager::kNothing, VarManager::kM1111REFoverMpplus); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2POIminus", "", true, 60, 0.0, 30.0, VarManager::kPt2, 18, 0.0, 90.0, VarManager::kCentFT0C, 0, 0.0, 1.0, VarManager::kCORR2POIminus, "", "", "", VarManager::kNothing, VarManager::kM01POIoverMpminus); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr4POIminus", "", true, 60, 0.0, 30.0, VarManager::kPt2, 18, 0.0, 90.0, VarManager::kCentFT0C, 0, 0.0, 1.0, VarManager::kCORR4POIminus, "", "", "", VarManager::kNothing, VarManager::kM0111POIoverMpminus); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr2POIplus", "", true, 60, 0.0, 30.0, VarManager::kPt1, 18, 0.0, 90.0, VarManager::kCentFT0C, 0, 0.0, 1.0, VarManager::kCORR2POIplus, "", "", "", VarManager::kNothing, VarManager::kM01POIoverMpplus); + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_Corr4POIplus", "", true, 60, 0.0, 30.0, VarManager::kPt1, 18, 0.0, 90.0, VarManager::kCentFT0C, 0, 0.0, 1.0, VarManager::kCORR4POIplus, "", "", "", VarManager::kNothing, VarManager::kM0111POIoverMpplus); + } + if (subGroupStr.Contains("singlecumulant2")) { + double PtBinEdges[67]; // 0-30GeV/c + for (int i = 0; i < 67; i++) { + if (i <= 39) { + PtBinEdges[i] = i / 10.; + } else { + PtBinEdges[i] = (i - 40) * 1. + 4.; + } + } + double CentBinEdges[19]; // 0-90% + for (int i = 0; i < 19; i++) { + CentBinEdges[i] = i * 5; + } + hm->AddHistogram(histClass, "Pt_centrFT0C_Corr2REFminus", "", true, 66, PtBinEdges, VarManager::kPt2, 18, CentBinEdges, VarManager::kCentFT0C, 0, nullptr, VarManager::kCORR2REFbydimuons, "", "", "", VarManager::kNothing, VarManager::kM11REFoverMpminus); + hm->AddHistogram(histClass, "Pt_centrFT0C_Corr4REFminus", "", true, 66, PtBinEdges, VarManager::kPt2, 18, CentBinEdges, VarManager::kCentFT0C, 0, nullptr, VarManager::kCORR4REFbydimuons, "", "", "", VarManager::kNothing, VarManager::kM1111REFoverMpminus); + hm->AddHistogram(histClass, "Pt_centrFT0C_Corr2REFplus", "", true, 66, PtBinEdges, VarManager::kPt1, 18, CentBinEdges, VarManager::kCentFT0C, 0, nullptr, VarManager::kCORR2REFbydimuons, "", "", "", VarManager::kNothing, VarManager::kM11REFoverMpplus); + hm->AddHistogram(histClass, "Pt_centrFT0C_Corr4REFplus", "", true, 66, PtBinEdges, VarManager::kPt1, 18, CentBinEdges, VarManager::kCentFT0C, 0, nullptr, VarManager::kCORR4REFbydimuons, "", "", "", VarManager::kNothing, VarManager::kM1111REFoverMpplus); + hm->AddHistogram(histClass, "Pt_centrFT0C_Corr2POIminus", "", true, 66, PtBinEdges, VarManager::kPt2, 18, CentBinEdges, VarManager::kCentFT0C, 0, nullptr, VarManager::kCORR2POIminus, "", "", "", VarManager::kNothing, VarManager::kM01POIoverMpminus); + hm->AddHistogram(histClass, "Pt_centrFT0C_Corr4POIminus", "", true, 66, PtBinEdges, VarManager::kPt2, 18, CentBinEdges, VarManager::kCentFT0C, 0, nullptr, VarManager::kCORR4POIminus, "", "", "", VarManager::kNothing, VarManager::kM0111POIoverMpminus); + hm->AddHistogram(histClass, "Pt_centrFT0C_Corr2POIplus", "", true, 66, PtBinEdges, VarManager::kPt1, 18, CentBinEdges, VarManager::kCentFT0C, 0, nullptr, VarManager::kCORR2POIplus, "", "", "", VarManager::kNothing, VarManager::kM01POIoverMpplus); + hm->AddHistogram(histClass, "Pt_centrFT0C_Corr4POIplus", "", true, 66, PtBinEdges, VarManager::kPt1, 18, CentBinEdges, VarManager::kCentFT0C, 0, nullptr, VarManager::kCORR4POIplus, "", "", "", VarManager::kNothing, VarManager::kM0111POIoverMpplus); } if (subGroupStr.Contains("res-flow-dimuon")) { - int varV2[5] = {VarManager::kMass, VarManager::kPt, VarManager::kCentFT0C, VarManager::kR2SP, VarManager::kR2EP}; - int varV3[5] = {VarManager::kMass, VarManager::kPt, VarManager::kCentFT0C, VarManager::kR3SP, VarManager::kR3EP}; + int varV2[6] = {VarManager::kMass, VarManager::kPt, VarManager::kRap, VarManager::kCentFT0C, VarManager::kR2SP_AB, VarManager::kR2EP_AB}; + // int varV3[6] = {VarManager::kMass, VarManager::kPt, VarManager::kRap, VarManager::kCentFT0C, VarManager::kR3SP, VarManager::kR3EP}; // removed temporarily - int bins[5] = {125, 120, 9, 200, 200}; - double minBins[5] = {0.0, 0.0, 0.0, -10.0, -10.0}; - double maxBins[5] = {5.0, 30.0, 90.0, 10.0, 10.0}; - hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_R2", "", 5, varV2, bins, minBins, maxBins, 0, -1, kTRUE); - hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_R3", "", 5, varV3, bins, minBins, maxBins, 0, -1, kTRUE); + int bins[6] = {125, 60, 6, 18, 200, 40}; + double minBins[6] = {0.0, 0.0, 2.5, 0.0, -10.0, -2.0}; + double maxBins[6] = {5.0, 30.0, 4.0, 90.0, 10.0, 2.0}; + hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_R2", "", 6, varV2, bins, minBins, maxBins, 0, -1, kTRUE); + // hm->AddHistogram(histClass, "Mass_Pt_centrFT0C_R3", "", 6, varV3, bins, minBins, maxBins, 0, -1, kTRUE); // removed temporarily } if (subGroupStr.Contains("z-boson")) { hm->AddHistogram(histClass, "MassZboson", "", false, 240, 20.0, 140.0, VarManager::kMass); @@ -888,17 +1520,61 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Mass_Pt", "", false, 750, 0.0, 30.0, VarManager::kMass, 120, 0.0, 30.0, VarManager::kPt); hm->AddHistogram(histClass, "Mass_Rapidity", "", false, 750, 0.0, 30.0, VarManager::kMass, 500, -1.0, 4.0, VarManager::kRap); hm->AddHistogram(histClass, "Mass_VtxZ", "", true, 30, -15.0, 15.0, VarManager::kVtxZ, 750, 0.0, 30.0, VarManager::kMass); - hm->AddHistogram(histClass, "DeltaPhiPair", "", false, 130, -6.5, 6.5, VarManager::kDeltaPhiPair); + hm->AddHistogram(histClass, "DeltaPhiPair2", "", false, 600, -o2::constants::math::PIHalf, 1.5 * o2::constants::math::PI, VarManager::kDeltaPhiPair2); + hm->AddHistogram(histClass, "DeltaEtaPair2", "", false, 350, 1.5, 5.0, VarManager::kDeltaEtaPair2); + } + if (subGroupStr.Contains("correlation-emu")) { + hm->AddHistogram(histClass, "DeltaPhiPair2_DeltaEtaPair2", "", false, 600, -o2::constants::math::PIHalf, 1.5 * o2::constants::math::PI, VarManager::kDeltaPhiPair2, 350, 1.5, 5.0, VarManager::kDeltaEtaPair2); + hm->AddHistogram(histClass, "DeltaPhiPair2_Pt", "", false, 600, -o2::constants::math::PIHalf, 1.5 * o2::constants::math::PI, VarManager::kDeltaPhiPair2, 200, 0.0, 20.0, VarManager::kPt); } if (subGroupStr.Contains("dielectrons")) { if (subGroupStr.Contains("prefilter")) { hm->AddHistogram(histClass, "MassLow_OpeningAngle", "", false, 150, 0., 0.15, VarManager::kMass, 80, 0., 0.8, VarManager::kOpeningAngle); } if (subGroupStr.Contains("phiv")) { - hm->AddHistogram(histClass, "Mass_Pt_PhiV", "", false, 20, 0.0, 0.2, VarManager::kMass, 100, 0.0, 10.0, VarManager::kPt, 100, 0.0, TMath::Pi(), VarManager::kPairPhiv); + hm->AddHistogram(histClass, "Mass_Pt_PhiV", "", false, 20, 0.0, 0.2, VarManager::kMass, 100, 0.0, 10.0, VarManager::kPt, 100, 0.0, o2::constants::math::PI, VarManager::kPairPhiv); + } + if (subGroupStr.Contains("double-phi-v")) { + hm->AddHistogram(histClass, "Mass_Pt_PhiV", "", false, 20, 0.0, 0.2, VarManager::kMass, 100, 0.0, 10.0, VarManager::kPt, 100, 0.0, o2::constants::math::PI, VarManager::kPairPhiv, "", "", "", -1, -1, true); + } + if (subGroupStr.Contains("largemass-phi-v")) { + // binning for mee at large scales: + // every 10 MeV from 0 to 0.2 GeV/c2 + // every 100 MeV from 0.2 to 1. GeV/c2 + // every 500 GeV from 1 to 5 GeV/c2 + double mee_bins[37]; + for (int i = 0; i <= 20; i++) + mee_bins[i] = 0.01 * i; + for (int i = 1; i <= 8; i++) + mee_bins[20 + i] = 0.2 + 0.1 * i; + for (int i = 1; i <= 8; i++) + mee_bins[28 + i] = 1. + 0.5 * i; + int nbins_mee = sizeof(mee_bins) / sizeof(*mee_bins) - 1; + + // binning for ptee at large scales: + // every 0.2 GeV/c from 0 to 10 GeV/c + double ptee_bins[51]; + for (int i = 0; i <= 50; i++) + ptee_bins[i] = 0.2 * i; + int nbins_ptee = sizeof(ptee_bins) / sizeof(*ptee_bins) - 1; + + // binning for phiv: + // steps of size pi/100 + double phiv_bins[101]; + for (int i = 0; i <= 100; i++) + phiv_bins[i] = o2::constants::math::PI / 100. * i; + int nbins_phiv = sizeof(phiv_bins) / sizeof(*phiv_bins) - 1; + + // 3D histo + hm->AddHistogram(histClass, "Mass_Pt_PhiV", "", false, nbins_mee, mee_bins, VarManager::kMass, nbins_ptee, ptee_bins, VarManager::kPt, nbins_phiv, phiv_bins, VarManager::kPairPhiv); + } + if (subGroupStr.Contains("meeptee")) { + hm->AddHistogram(histClass, "Mass_Pt", "", false, 500, 0.0, 5.0, VarManager::kMass, 100, 0.0, 10.0, VarManager::kPt); + } + if (subGroupStr.Contains("double-mee-ptee")) { + hm->AddHistogram(histClass, "Mass_Pt", "", false, 500, 0.0, 5.0, VarManager::kMass, 100, 0.0, 10.0, VarManager::kPt, 0, 0, 0, -1, "", "", "", -1, -1, true); } if (subGroupStr.Contains("lmee")) { - hm->AddHistogram(histClass, "Mass_Pt_PhiV", "", false, 20, 0.0, 0.2, VarManager::kMass, 100, 0.0, 10.0, VarManager::kPt, 100, 0.0, TMath::Pi(), VarManager::kPairPhiv); hm->AddHistogram(histClass, "Mass_QuadDCAsigXY", "", false, 50, 0.0, 5.0, VarManager::kMass, 50, 0.0, 20.0, VarManager::kQuadDCAsigXY); hm->AddHistogram(histClass, "Mass_QuadDCAsigZ", "", false, 50, 0.0, 5.0, VarManager::kMass, 50, 0.0, 20.0, VarManager::kQuadDCAsigZ); hm->AddHistogram(histClass, "Mass_Pt_QuadDCAsigXYZ", "", false, 500, 0.0, 5.0, VarManager::kMass, 100, 0.0, 10.0, VarManager::kPt, 50, 0.0, 20.0, VarManager::kQuadDCAsigXYZ); @@ -944,35 +1620,39 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h dca_bins[60 + i] = 10 + 1 * i; int nbins_dca = sizeof(dca_bins) / sizeof(*dca_bins) - 1; - // binning for signed dca at large scales: - // every 2.0 sigma from -40 to -10 sigma - // every 1.0 sigma from -10 to -5 sigma - // every 0.2 sigma from -5 to 5 sigma - // every 1.0 sigma from 5 to 10 sigma - // every 2.0 sigma from 10 to 40 sigma - double signdca_bins[91]; - for (int i = 0; i <= 15; i++) - signdca_bins[i] = -40 + 2 * i; - for (int i = 1; i <= 5; i++) - signdca_bins[15 + i] = -10 + 1 * i; - for (int i = 1; i <= 50; i++) - signdca_bins[20 + i] = -5 + 0.2 * i; - for (int i = 1; i <= 5; i++) - signdca_bins[70 + i] = 5 + 1 * i; - for (int i = 1; i <= 15; i++) - signdca_bins[75 + i] = 10 + 2 * i; - int nbins_signdca = sizeof(signdca_bins) / sizeof(*signdca_bins) - 1; - - hm->AddHistogram(histClass, "Mass_Pt_PhiV", "", false, 20, 0.0, 0.2, VarManager::kMass, 100, 0.0, 10.0, VarManager::kPt, 100, 0.0, TMath::Pi(), VarManager::kPairPhiv); hm->AddHistogram(histClass, "Mass_QuadDCAsigXY", "", false, nbins_mee, mee_bins, VarManager::kMass, nbins_dca, dca_bins, VarManager::kQuadDCAsigXY); hm->AddHistogram(histClass, "Mass_QuadDCAsigZ", "", false, nbins_mee, mee_bins, VarManager::kMass, nbins_dca, dca_bins, VarManager::kQuadDCAsigZ); hm->AddHistogram(histClass, "Mass_Pt_QuadDCAsigXYZ", "", false, nbins_mee, mee_bins, VarManager::kMass, nbins_ptee, ptee_bins, VarManager::kPt, nbins_dca, dca_bins, VarManager::kQuadDCAsigXYZ); - hm->AddHistogram(histClass, "Mass_Pt_SignQuadDCAsigXYZ", "", false, nbins_mee, mee_bins, VarManager::kMass, nbins_ptee, ptee_bins, VarManager::kPt, nbins_signdca, signdca_bins, VarManager::kSignQuadDCAsigXY); + } + } + if (subGroupStr.Contains("opencharm")) { + if (subGroupStr.Contains("dmeson")) { + hm->AddHistogram(histClass, "MassD0region", "", false, 140, 1.5, 2.2, VarManager::kMass); + hm->AddHistogram(histClass, "MassD0region_Pt", "", false, 70, 1.5, 2.2, VarManager::kMass, 160, 0., 20., VarManager::kPt); + hm->AddHistogram(histClass, "MassD0region_Rapidity", "", false, 140, 1.5, 2.2, VarManager::kMass, 10, -0.8, 0.8, VarManager::kRap); + hm->AddHistogram(histClass, "MassD0region_eta", "", false, 140, 1.5, 2.2, VarManager::kMass, 40, -2., 2., VarManager::kEta); + hm->AddHistogram(histClass, "MassD0region_TauxyzProj", "", false, 140, 1.5, 2.2, VarManager::kMass, 200, -0.03, 0.03, VarManager::kVertexingTauxyzProjected); + hm->AddHistogram(histClass, "MassD0region_TauxyProj", "", false, 140, 1.5, 2.2, VarManager::kMass, 200, -0.03, 0.03, VarManager::kVertexingTauxyProjected); + hm->AddHistogram(histClass, "MassD0region_CosPointing", "", false, 140, 1.5, 2.2, VarManager::kMass, 200, -1.0, 1.0, VarManager::kCosPointingAngle); + hm->AddHistogram(histClass, "MassD0region_VtxNContribReal", "", false, 140, 1.5, 2.2, VarManager::kMass, 50, 0, 50, VarManager::kVtxNcontribReal); + } + if (subGroupStr.Contains("3d-mass-histograms")) { + hm->AddHistogram(histClass, "MassD0region_Pt_TauxyzProj", "", false, 140, 1.5, 2.2, VarManager::kMass, 80, 0., 20., VarManager::kPt, 300, 0., 0.03, VarManager::kVertexingTauxyzProjected); + hm->AddHistogram(histClass, "MassD0region_Pt_CosPointing", "", false, 140, 1.5, 2.2, VarManager::kMass, 80, 0., 20., VarManager::kPt, 100, -1., 0., VarManager::kCosPointingAngle); + hm->AddHistogram(histClass, "MassD0region_Rapidity_AveragePt", "", true, 140, 1.5, 2.2, VarManager::kMass, 10, -0.8, 0.8, VarManager::kRap, 150, 0.0, 30.0, VarManager::kPt); + hm->AddHistogram(histClass, "MassD0region_Pt_ITStrackOccupancy", "Pair mass vs pair Pt vs event ITS occupancy", false, 70, 1.5, 2.2, VarManager::kMass, 160, 0., 20., VarManager::kPt, 200, 0., 20000., VarManager::kTrackOccupancyInTimeRange); + hm->AddHistogram(histClass, "MassD0region_TPCnSigKa_pIN", "Pair mass vs kaon cand. pIN vs kaon cand. TPC n-#sigma(K)", false, 140, 1.5, 2.2, VarManager::kMass, 100, 0.0, 10.0, VarManager::kPin_leg1, 20, -5.0, 5.0, VarManager::kTPCnSigmaKa_leg1); + } + if (subGroupStr.Contains("lambdac")) { + hm->AddHistogram(histClass, "MassLambdacRegion", "", false, 50, 2.15, 2.4, VarManager::kMass); + hm->AddHistogram(histClass, "MassLambdacRegion_Pt", "", false, 50, 2.15, 2.4, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt); + hm->AddHistogram(histClass, "MassLambdacRegion_eta", "", false, 50, 2.15, 2.4, VarManager::kMass, 40, -2., 2., VarManager::kEta); + hm->AddHistogram(histClass, "MassLambdacRegion_TauxyzProj", "", false, 50, 2.15, 2.4, VarManager::kMass, 1000, -0.03, 0.03, VarManager::kVertexingTauxyzProjected); } } } - if (groupStr.Contains("dilepton-track")) { + if (!groupStr.CompareTo("dilepton-track")) { if (subGroupStr.Contains("mixedevent")) { // for mixed event hm->AddHistogram(histClass, "Mass_Pt", "", false, 40, 0.0, 20.0, VarManager::kPairMass, 40, 0.0, 20.0, VarManager::kPairPt); hm->AddHistogram(histClass, "Mass", "", false, 750, 0.0, 30.0, VarManager::kPairMass); @@ -981,12 +1661,13 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h if (subGroupStr.Contains("invmass")) { hm->AddHistogram(histClass, "Mass_Dilepton", "", false, 125, 0.0, 5.0, VarManager::kPairMassDau); hm->AddHistogram(histClass, "Mass_Hadron", "", false, 125, 0.0, 5.0, VarManager::kMassDau); + hm->AddHistogram(histClass, "Delta_Mass", "", false, 125, 0.0, 5.0, VarManager::kDeltaMass); hm->AddHistogram(histClass, "Mass_Dilepton_Mass_Hadron", "", false, 125, 0.0, 5.0, VarManager::kPairMassDau, 125, 0.0, 5.0, VarManager::kMassDau); hm->AddHistogram(histClass, "Pt_Dilepton", "", false, 120, 0.0, 30.0, VarManager::kPairPtDau); hm->AddHistogram(histClass, "Pt_Track", "", false, 120, 0.0, 30.0, VarManager::kPt); hm->AddHistogram(histClass, "Mass", "", false, 750, 0.0, 30.0, VarManager::kPairMass); hm->AddHistogram(histClass, "Pt", "", false, 750, 0.0, 30.0, VarManager::kPairPt); - hm->AddHistogram(histClass, "Mass_Pt", "", false, 40, 0.0, 20.0, VarManager::kPairMass, 40, 0.0, 20.0, VarManager::kPairPt); + hm->AddHistogram(histClass, "Mass_Pt", "", false, 100, 0.0, 20.0, VarManager::kPairMass, 40, 0.0, 20.0, VarManager::kPairPt); hm->AddHistogram(histClass, "Pt_Dilepton__Pt", "", false, 40, 0.0, 20.0, VarManager::kPairPtDau, 40, 0.0, 20.0, VarManager::kPairPt); hm->AddHistogram(histClass, "Pt_Track__Pt", "", false, 40, 0.0, 20.0, VarManager::kPt, 40, 0.0, 20.0, VarManager::kPairPt); } @@ -1009,44 +1690,72 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "TauzProj", "", false, 4000, -0.5, 0.5, VarManager::kVertexingTauzProjected); hm->AddHistogram(histClass, "TauxyProj", "", false, 4000, -0.5, 0.5, VarManager::kVertexingTauxyProjected); hm->AddHistogram(histClass, "CosPointingAngle", "", false, 100, 0.0, 1.0, VarManager::kCosPointingAngle); + hm->AddHistogram(histClass, "DCAxyzBetweenProngs", "", false, 100, 0.0, 1.0, VarManager::kKFDCAxyzBetweenProngs); + } + if (subGroupStr.Contains("multidimentional-vertexing-histograms")) { + hm->AddHistogram(histClass, "Mass_Tauxy", "", false, 75, 4.0, 7.0, VarManager::kPairMass, 40, -0.0, 0.02, VarManager::kVertexingTauxy); + hm->AddHistogram(histClass, "Mass_cosPointing", "", false, 75, 4.0, 7.0, VarManager::kPairMass, 40, 0.0, 1.0, VarManager::kCosPointingAngle); + + const int kNvarsTripletCuts = 4; + const int kInvMassNbins = 100; + double InvMassBinLims[kInvMassNbins + 1]; + for (int i = 0; i <= kInvMassNbins; ++i) + InvMassBinLims[i] = 4.0 + 0.02 * i; + + const int kPtNbins = 6; + double PtBinLims[kPtNbins + 1] = {0., 2., 4., 6., 8., 10., 20.}; + const int kCosPointingAngleNbins = 5; + double CosPointingAngleBinLims[kCosPointingAngleNbins + 1] = {0., 0.86, 0.90, 0.94, 0.98, 1.0}; + + const int kTauNBins = 6; + double TauBinLims[kTauNBins + 1] = {0., 0.005, 0.01, 0.015, 0.02, 0.025, 0.3}; + + TArrayD nCutsBinLimits[kNvarsTripletCuts]; + nCutsBinLimits[0] = TArrayD(kInvMassNbins + 1, InvMassBinLims); + nCutsBinLimits[1] = TArrayD(kPtNbins + 1, PtBinLims); + nCutsBinLimits[2] = TArrayD(kCosPointingAngleNbins + 1, CosPointingAngleBinLims); + nCutsBinLimits[3] = TArrayD(kTauNBins + 1, TauBinLims); + + int varsTripletCuts[kNvarsTripletCuts] = {VarManager::kPairMass, VarManager::kPairPt, VarManager::kCosPointingAngle, VarManager::kVertexingTauxyProjected}; + hm->AddHistogram(histClass, "multidimentional-vertexing", "Invariant mass vs. pT vs. cosine of pointing angle vs. tau", kNvarsTripletCuts, varsTripletCuts, nCutsBinLimits); } if (subGroupStr.Contains("correlation")) { hm->AddHistogram(histClass, "DeltaEta_DeltaPhi", "", false, 20, -2.0, 2.0, VarManager::kDeltaEta, 50, -8.0, 8.0, VarManager::kDeltaPhi); hm->AddHistogram(histClass, "DeltaEta_DeltaPhiSym", "", false, 20, -2.0, 2.0, VarManager::kDeltaEta, 50, -8.0, 8.0, VarManager::kDeltaPhiSym); } - } + if (subGroupStr.Contains("dilepton-hadron-array-correlation")) { + const int kInvMassBins = 500; + double InvMassBinLims[kInvMassBins + 1]; + for (int i = 0; i <= kInvMassBins; i++) + InvMassBinLims[i] = 0 + i * 0.01; + + const int kDelEtaBins = 20; + double DelEtaBinLims[kDelEtaBins + 1]; + for (int i = 0; i <= kDelEtaBins; i++) + DelEtaBinLims[i] = -2 + i * 0.2; + + const int kDelPhiBins = 52; + double DelPhiBinLims[] = {-1.69647, -1.57080, -1.44513, -1.31947, -1.19381, -1.06814, -0.94248, -0.81681, -0.69115, -0.56549, -0.43982, -0.31416, -0.18850, -0.06283, 0.06283, 0.18850, 0.31416, 0.43982, 0.56549, 0.69115, 0.81681, 0.94248, 1.06814, 1.19381, 1.31947, 1.44513, 1.57080, 1.69646, 1.82212, 1.94779, 2.07345, 2.19911, 2.32478, 2.45044, 2.57611, 2.70177, 2.82743, 2.95310, 3.07876, 3.20442, 3.33009, 3.45575, 3.58142, 3.70708, 3.83274, 3.95841, 4.08407, 4.20973, 4.33540, 4.46106, 4.58673, 4.71239, 4.8380600}; + + const int kPtBins = 45; + double PtBinLims[kPtBins + 1] = {0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.5, 5, 7.5, 10, 20}; - if (groupStr.Contains("dilepton-hadron-array-correlation")) { - const int kInvMassBins = 500; - double InvMassBinLims[kInvMassBins + 1]; - for (int i = 0; i <= kInvMassBins; i++) - InvMassBinLims[i] = 0 + i * 0.01; - - const int kDelEtaBins = 20; - double DelEtaBinLims[kDelEtaBins + 1]; - for (int i = 0; i <= kDelEtaBins; i++) - DelEtaBinLims[i] = -2 + i * 0.2; - - const int kDelPhiBins = 50; - double DelPhiBinLims[kDelPhiBins + 1]; - for (int i = 0; i <= kDelPhiBins; i++) - DelPhiBinLims[i] = -8 + i * 0.32; - - const int kPtBins = 20; - double PtBinLims[kPtBins + 1]; - for (int i = 0; i <= kPtBins; i++) - PtBinLims[i] = 0 + i * 1; - - TArrayD nJPsiHadCorr[4]; - nJPsiHadCorr[0] = TArrayD(kInvMassBins + 1, InvMassBinLims); - nJPsiHadCorr[1] = TArrayD(kDelEtaBins + 1, DelEtaBinLims); - nJPsiHadCorr[2] = TArrayD(kDelPhiBins + 1, DelPhiBinLims); - nJPsiHadCorr[3] = TArrayD(kPtBins + 1, PtBinLims); - - int varsJPsiHadCorr[4] = {VarManager::kPairMassDau, VarManager::kDeltaEta, VarManager::kDeltaPhi, VarManager::kPairPtDau}; - hm->AddHistogram(histClass, "InvMass_DelEta_DelPhi", "", 4, varsJPsiHadCorr, nJPsiHadCorr); + TArrayD nJPsiHadCorr[4]; + nJPsiHadCorr[0] = TArrayD(kInvMassBins + 1, InvMassBinLims); + nJPsiHadCorr[1] = TArrayD(kDelEtaBins + 1, DelEtaBinLims); + nJPsiHadCorr[2] = TArrayD(kDelPhiBins + 1, DelPhiBinLims); + nJPsiHadCorr[3] = TArrayD(kPtBins + 1, PtBinLims); + + int varsJPsiHadCorr[4] = {VarManager::kPairMassDau, VarManager::kDeltaEta, VarManager::kDeltaPhi, VarManager::kPairPtDau}; + hm->AddHistogram(histClass, "InvMass_DelEta_DelPhi", "", 4, varsJPsiHadCorr, nJPsiHadCorr); // Without efficiency + // hm->AddHistogram(histClass, "InvMass_DelEta_DelPhi", "", 4, varsJPsiHadCorr, nJPsiHadCorr, nullptr, VarManager::kJpsiHadronEff); + } + if (subGroupStr.Contains("opencharm")) { + hm->AddHistogram(histClass, "Delta_Mass_DstarD0region", "", false, 50, 0.14, 0.16, VarManager::kDeltaMass); + } } - if (groupStr.Contains("dilepton-charmhadron")) { + + if (!groupStr.CompareTo("dilepton-charmhadron")) { if (subGroupStr.EqualTo("jpsitomumu")) { hm->AddHistogram(histClass, "hMassVsPtJPsi", "", false, 100, 0.f, 50.f, VarManager::kPt, 300, 2.f, 5.f, VarManager::kMass); hm->AddHistogram(histClass, "hRapVsPtJPsi", "", false, 100, 0.f, 50.f, VarManager::kPt, 50, -4.5f, -2.0f, VarManager::kRap); @@ -1075,17 +1784,43 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "hPhiVsPtVsBdtDmesonWithJPsi", "", false, 100, 0.f, 1.f, VarManager::kBdtCharmHadron, 100, 0.f, 50.f, VarManager::kPtCharmHadron, 180, 0., 2 * constants::math::PI, VarManager::kPhiCharmHadron); } } - if (groupStr.Contains("dilepton-dihadron")) { + if (!groupStr.CompareTo("dilepton-dihadron")) { if (subGroupStr.EqualTo("xtojpsipipi")) { hm->AddHistogram(histClass, "hMass_X3872", "", false, 1000, 3.0, 5.0, VarManager::kQuadMass); - hm->AddHistogram(histClass, "hPt_X3872", "", false, 200, 0.0, 20.0, VarManager::kQuadPt); - hm->AddHistogram(histClass, "hMass_Pt_X3872", "", false, 1000, 3.0, 5.0, VarManager::kQuadMass, 150, 0.0, 15.0, VarManager::kQuadPt); + hm->AddHistogram(histClass, "hMass_defaultDileptonMass_X3872", "", false, 1000, 3.0, 5.0, VarManager::kQuadDefaultDileptonMass); + hm->AddHistogram(histClass, "hPt_X3872", "", false, 150, 0.0, 15.0, VarManager::kQuadPt); + hm->AddHistogram(histClass, "hMass_Pt_X3872", "", false, 100, 3.0, 5.0, VarManager::kQuadMass, 150, 0.0, 15.0, VarManager::kQuadPt); + hm->AddHistogram(histClass, "hMass_defaultDileptonMass_Pt_X3872", "", false, 100, 3.0, 5.0, VarManager::kQuadDefaultDileptonMass, 150, 0.0, 15.0, VarManager::kQuadPt); hm->AddHistogram(histClass, "hCostheta_Jpsi_Dihadron", "", false, 100, -1.0, 1.0, VarManager::kCosthetaDileptonDitrack); - hm->AddHistogram(histClass, "hPtDilepton_PtDihadron", "", false, 200, 0, 20, VarManager::kPairPt, 100, 0, 10, VarManager::kDitrackPt); - hm->AddHistogram(histClass, "hPtDilepton_MassDihadron", "", false, 200, 0, 20, VarManager::kPairPt, 100, 3.0, 5.0, VarManager::kDitrackMass); + hm->AddHistogram(histClass, "hPtDilepton_PtDihadron", "", false, 150, 0, 15.0, VarManager::kPairPt, 100, 0, 10, VarManager::kDitrackPt); + hm->AddHistogram(histClass, "hPtDilepton_MassDihadron", "", false, 150, 0, 15.0, VarManager::kPairPt, 150, 0.0, 3.0, VarManager::kDitrackMass); + hm->AddHistogram(histClass, "hQ_X3872", "", false, 150, 0.0, 3.0, VarManager::kQ); + hm->AddHistogram(histClass, "hDeltaR1_X3872", "", false, 100, 0.0, 10.0, VarManager::kDeltaR1); + hm->AddHistogram(histClass, "hDeltaR2_X3872", "", false, 100, 0.0, 10.0, VarManager::kDeltaR2); + hm->AddHistogram(histClass, "hDeltaR_X3872", "", false, 100, 0.0, 10.0, VarManager::kDeltaR); + hm->AddHistogram(histClass, "hMass_Q_X3872", "", false, 100, 3.0, 5.0, VarManager::kQuadMass, 150, 0.0, 3.0, VarManager::kQ); + hm->AddHistogram(histClass, "hMass_defaultDileptonMass_Q_X3872", "", false, 100, 3.0, 5.0, VarManager::kQuadDefaultDileptonMass, 150, 0.0, 3.0, VarManager::kQ); + hm->AddHistogram(histClass, "hMass_DeltaR1_X3872", "", false, 100, 3.0, 5.0, VarManager::kQuadMass, 100, 0.0, 10.0, VarManager::kDeltaR1); + hm->AddHistogram(histClass, "hMass_defaultDileptonMass_DeltaR1_X3872", "", false, 100, 3.0, 5.0, VarManager::kQuadDefaultDileptonMass, 100, 0.0, 10.0, VarManager::kDeltaR1); + hm->AddHistogram(histClass, "hMass_DeltaR2_X3872", "", false, 100, 3.0, 5.0, VarManager::kQuadMass, 100, 0.0, 10.0, VarManager::kDeltaR2); + hm->AddHistogram(histClass, "hMass_defaultDileptonMass_DeltaR2_X3872", "", false, 100, 3.0, 5.0, VarManager::kQuadDefaultDileptonMass, 100, 0.0, 10.0, VarManager::kDeltaR2); + hm->AddHistogram(histClass, "hMass_X3872_MassDihadron", "", false, 100, 3.0, 5.0, VarManager::kQuadMass, 150, 0.0, 3.0, VarManager::kDitrackMass); + hm->AddHistogram(histClass, "hMass_defaultDileptonMass_X3872_MassDihadron", "", false, 100, 3.0, 5.0, VarManager::kQuadDefaultDileptonMass, 150, 0.0, 3.0, VarManager::kDitrackMass); + hm->AddHistogram(histClass, "hRap_X3872", "", false, 1000, 0.0, 5.0, VarManager::kRap); + hm->AddHistogram(histClass, "hMass_Rap_X3872", "", false, 100, 3.0, 5.0, VarManager::kQuadMass, 1000, 0.0, 5.0, VarManager::kRap); + hm->AddHistogram(histClass, "hMass_defaultDileptonMass_Rap_X3872", "", false, 100, 3.0, 5.0, VarManager::kQuadDefaultDileptonMass, 1000, 0.0, 5.0, VarManager::kRap); + hm->AddHistogram(histClass, "hDCAxyTrack1", "", false, 100, -0.1, 0.1, VarManager::kTrackDCAxy); + hm->AddHistogram(histClass, "hDCAzTrack1", "", false, 100, -0.1, 0.1, VarManager::kTrackDCAz); + hm->AddHistogram(histClass, "hMass_defaultDileptonMass_DCAxyTrack1", "", false, 100, 3.0, 5.0, VarManager::kQuadDefaultDileptonMass, 100, -0.1, 0.1, VarManager::kTrackDCAxy); + hm->AddHistogram(histClass, "hMass_defaultDileptonMass_DCAzTrack1", "", false, 100, 3.0, 5.0, VarManager::kQuadDefaultDileptonMass, 100, -0.1, 0.1, VarManager::kTrackDCAz); + hm->AddHistogram(histClass, "hMass_DCAxyTrack1", "", false, 100, 3.0, 5.0, VarManager::kQuadMass, 100, -0.1, 0.1, VarManager::kTrackDCAxy); + hm->AddHistogram(histClass, "hMass_DCAzTrack1", "", false, 100, 3.0, 5.0, VarManager::kQuadMass, 100, -0.1, 0.1, VarManager::kTrackDCAz); + hm->AddHistogram(histClass, "hPtTrack1", "", false, 100, 0.0, 10.0, VarManager::kPt); + hm->AddHistogram(histClass, "hMass_defaultDileptonMass_PtTrack1", "", false, 100, 3.0, 5.0, VarManager::kQuadDefaultDileptonMass, 100, 0.0, 10.0, VarManager::kPt); + hm->AddHistogram(histClass, "hMass_PtTrack1", "", false, 100, 3.0, 5.0, VarManager::kQuadMass, 100, 0.0, 10.0, VarManager::kPt); } } - if (groupStr.Contains("dilepton-photon-mass")) { + if (!groupStr.CompareTo("dilepton-photon-mass")) { hm->AddHistogram(histClass, "Mass_Dilepton", "", false, 500, 0.0, 5.0, VarManager::kPairMassDau); hm->AddHistogram(histClass, "Mass_Photon", "", false, 500, 0.0, 0.1, VarManager::kMassDau); hm->AddHistogram(histClass, "Mass_Dilepton_Mass_Photon", "", false, 250, 0.0, 5.0, VarManager::kPairMassDau, 250, 0.0, 5.0, VarManager::kMassDau); @@ -1105,13 +1840,443 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Eta_Pt_lepton2", "", false, 100, -2.0, 2.0, VarManager::kEta2, 200, 0.0, 20.0, VarManager::kPt); } - if (groupStr.Contains("photon")) { + if (!groupStr.CompareTo("photon")) { hm->AddHistogram(histClass, "Pt_Photon", "p_{T} distribution", false, 4500, 0.0, 4.5, VarManager::kPt); hm->AddHistogram(histClass, "Eta", "#eta distribution", false, 500, -5.0, 5.0, VarManager::kEta); hm->AddHistogram(histClass, "Eta_Pt", "", false, 100, -2.0, 2.0, VarManager::kEta, 200, 0.0, 20.0, VarManager::kPt); - hm->AddHistogram(histClass, "Phi", "#varphi distribution", false, 500, -2. * TMath::Pi(), 2. * TMath::Pi(), VarManager::kPhi); + hm->AddHistogram(histClass, "Phi", "#varphi distribution", false, 500, -2. * o2::constants::math::PI, 2. * o2::constants::math::PI, VarManager::kPhi); hm->AddHistogram(histClass, "Mass_Photon", "", false, 500, 0.0, 0.1, VarManager::kMassDau); hm->AddHistogram(histClass, "Mass_Pt", "", false, 500, 0.0, 5.0, VarManager::kMassDau, 200, 0.0, 20.0, VarManager::kPt); hm->AddHistogram(histClass, "Rapidity", "", false, 400, -4.0, 4.0, VarManager::kRap); } } + +//__________________________________________________________________ +template +bool o2::aod::dqhistograms::ValidateJSONHistogram(T hist) +{ + // + // Validate JSON entry for this histogram + // + + // The fields histClass, title and type are compulsory + if (!hist->HasMember("histClass") || !hist->HasMember("title") || !hist->HasMember("type")) { + LOG(fatal) << "Missing histClass, title or type fields"; + return false; + } + + TString histTypeStr = hist->FindMember("type")->value.GetString(); + bool isTH1 = (histTypeStr.CompareTo("TH1") == 0); + bool isTH2 = (histTypeStr.CompareTo("TH2") == 0); + bool isTH3 = (histTypeStr.CompareTo("TH3") == 0); + bool isTHn = (histTypeStr.CompareTo("THn") == 0); + if (!(isTH1 || isTH2 || isTH3 || isTHn)) { + LOG(fatal) << "The type field must be one of the TH1, TH2, TH3 or THn"; + return false; + } + // Check if the histogram uses constant binning + bool isConstantBinning = true; + if (!(hist->HasMember("xmin") && hist->HasMember("xmax"))) { + isConstantBinning = false; + } + + if (!isTHn && (!hist->HasMember("isProfile") || !hist->HasMember("nXbins") || !hist->HasMember("varX"))) { + LOG(fatal) << "Missing isProfile, nXbins or varX information for histogram"; + return false; + } + bool isProfile = (hist->HasMember("isProfile") ? hist->FindMember("isProfile")->value.GetBool() : false); + + if (isConstantBinning) { + if (!hist->HasMember("xmin") || !hist->HasMember("xmax")) { + LOG(fatal) << "Missing xmin or xmax information for histogram"; + return false; + } + if (isTHn) { + if (!hist->FindMember("xmin")->value.IsArray()) { + LOG(fatal) << "xmin field should be an array of arrays"; + return false; + } + if (!hist->FindMember("xmax")->value.IsArray()) { + LOG(fatal) << "xmax field should be an array of arrays"; + return false; + } + } + } else { + if (isTHn && !hist->HasMember("binLimits")) { + LOG(fatal) << "Missing binLimits information for histogram"; + return false; + } + if (!isTHn && !hist->HasMember("xbins")) { + LOG(fatal) << "Missing xbins information for histogram"; + return false; + } + if (isTHn && !hist->FindMember("binLimits")->value.IsArray()) { + LOG(fatal) << "binLimits field should be an array of arrays"; + return false; + } + if (!isTHn && !hist->FindMember("xbins")->value.IsArray()) { + LOG(fatal) << "xbins field should be an array"; + return false; + } + } + if (isProfile && !hist->HasMember("varY")) { + LOG(fatal) << "Missing varY information for histogram"; + return false; + } + + if (isTHn) { + if (!hist->HasMember("nDimensions") || !hist->HasMember("vars")) { + LOG(fatal) << "Missing nDimensions or vars fields for histogram"; + return false; + } + if (isConstantBinning) { + if (!hist->HasMember("nBins")) { + LOG(fatal) << "Missing nBins field for histogram"; + return false; + } else { + if (!hist->FindMember("nBins")->value.IsArray()) { + LOG(fatal) << "nBins field should be an array"; + return false; + } + } + } + if (hist->HasMember("axLabels") && !hist->FindMember("axLabels")->value.IsArray()) { + LOG(fatal) << "axLabels field should be an array of strings"; + return false; + } + } + + if (isTH2 || isTH3) { + if (!hist->HasMember("nYbins") || !hist->HasMember("varY")) { + LOG(fatal) << "Missing nYbins or varY information for histogram"; + return false; + } + if (isConstantBinning && (!hist->HasMember("ymin") || !hist->HasMember("ymax"))) { + LOG(fatal) << "Missing ymin or ymax information for histogram"; + return false; + } + if (!isConstantBinning && !hist->HasMember("ybins")) { + LOG(fatal) << "Missing ybins information for histogram"; + return false; + } + if (!isConstantBinning && !hist->FindMember("xbins")->value.IsArray()) { + LOG(fatal) << "ybins field should be an array"; + } + + if (isTH3) { + if (!hist->HasMember("nZbins") || !hist->HasMember("varZ")) { + LOG(fatal) << "Missing nZbins or varZ information for histogram"; + return false; + } + if (isConstantBinning && (!hist->HasMember("zmin") || !hist->HasMember("zmax"))) { + LOG(fatal) << "Missing zmin or zmax information for histogram"; + return false; + } + if (!isConstantBinning && !hist->HasMember("zbins")) { + LOG(fatal) << "Missing zbins information for histogram"; + return false; + } + if (!isConstantBinning && !hist->FindMember("zbins")->value.IsArray()) { + LOG(fatal) << "zbins field should be an array"; + } + } + } + if (isTH2 && isProfile && !hist->HasMember("varZ")) { + LOG(fatal) << "Missing varZ information for histogram"; + return false; + } + if (isTH3 && isProfile && !hist->HasMember("varT")) { + LOG(fatal) << "Missing varT information for histogram"; + return false; + } + + if (!isTHn) { + TString varX = hist->FindMember("varX")->value.GetString(); + if (VarManager::fgVarNamesMap.find(varX) == VarManager::fgVarNamesMap.end()) { + LOG(fatal) << "Bad varX variable (" << hist->FindMember("varX")->value.GetString() << ") specified for histogram"; + return false; + } + if (hist->HasMember("varY") && (VarManager::fgVarNamesMap.find(hist->FindMember("varY")->value.GetString()) == VarManager::fgVarNamesMap.end())) { + LOG(fatal) << "Bad varY variable (" << hist->FindMember("varY")->value.GetString() << ") specified for histogram"; + return false; + } + if (hist->HasMember("varZ") && (VarManager::fgVarNamesMap.find(hist->FindMember("varZ")->value.GetString()) == VarManager::fgVarNamesMap.end())) { + LOG(fatal) << "Bad varZ variable (" << hist->FindMember("varZ")->value.GetString() << ") specified for histogram"; + return false; + } + if (hist->HasMember("varT") && (VarManager::fgVarNamesMap.find(hist->FindMember("varT")->value.GetString()) == VarManager::fgVarNamesMap.end())) { + LOG(fatal) << "Bad varT variable (" << hist->FindMember("varT")->value.GetString() << ") specified for histogram"; + return false; + } + if (hist->HasMember("varW") && (VarManager::fgVarNamesMap.find(hist->FindMember("varW")->value.GetString()) == VarManager::fgVarNamesMap.end())) { + LOG(fatal) << "Bad varW variable (" << hist->FindMember("varW")->value.GetString() << ") specified for histogram"; + return false; + } + } + if (isTHn) { + for (auto& v : hist->FindMember("vars")->value.GetArray()) { + if (VarManager::fgVarNamesMap.find(v.GetString()) == VarManager::fgVarNamesMap.end()) { + LOG(fatal) << "Bad variable in vars (" << v.GetString() << ") specified for histogram"; + return false; + } + } + } + + return true; +} + +//__________________________________________________________________ +void o2::aod::dqhistograms::AddHistogramsFromJSON(HistogramManager* hm, const char* json) +{ + // + // Add histograms to already existing histogram classes from a JSON formatted string + // The JSON is expected to contain a list of objects, with each object containing the fields needed + // to define a histogram via the HistogramManager::AddHistogram() functions + + LOG(info) << "========================================== interpreting JSON for adding histograms"; + LOG(info) << " json string is: " << json; + + TString jsonStr = json; + if (jsonStr == "") { + // No histograms to add + return; + } + + rapidjson::Document document; + rapidjson::ParseResult ok = document.Parse(json); + if (!ok) { + LOG(fatal) << "JSON parse error: " << rapidjson::GetParseErrorFunc(ok.Code()) << " (" << ok.Offset() << ")"; + TString str = ""; + for (int i = ok.Offset() - 30; i < static_cast(ok.Offset()) + 50; i++) { + if ((i >= 0) && (i < static_cast(strlen(json)))) { + str += json[i]; + } + } + LOG(fatal) << "**** Parsing error is somewhere here: " << str.Data() << endl; + return; + } + + for (rapidjson::Value::ConstMemberIterator it = document.MemberBegin(); it != document.MemberEnd(); it++) { + + const char* histName = it->name.GetString(); + LOG(info) << "Configuring histogram " << histName; + const auto& hist = it->value; + if (!ValidateJSONHistogram(&hist)) { + LOG(fatal) << "Histogram not properly defined in the JSON file. Skipping it"; + continue; + } + + TString histTypeStr = hist.FindMember("type")->value.GetString(); + bool isTH2 = (histTypeStr.CompareTo("TH2") == 0); + bool isTH3 = (histTypeStr.CompareTo("TH3") == 0); + bool isTHn = (histTypeStr.CompareTo("THn") == 0); + bool isConstantBinning = true; + if (!(hist.HasMember("xmin") && hist.HasMember("xmax"))) { + isConstantBinning = false; + } + + const char* histClass = hist.FindMember("histClass")->value.GetString(); + const char* title = hist.FindMember("title")->value.GetString(); + + if (isTHn) { + int nDimensions = hist.FindMember("nDimensions")->value.GetInt(); + LOG(debug) << "nDimensions: " << nDimensions; + + int* vars = new int[nDimensions]; + int iDim = 0; + for (auto& v : hist.FindMember("vars")->value.GetArray()) { + LOG(debug) << "iDim " << iDim << ": " << v.GetString(); + vars[iDim++] = VarManager::fgVarNamesMap[v.GetString()]; + } + + int* nBins = nullptr; + double* xmin = nullptr; + double* xmax = nullptr; + TArrayD* binLimits = nullptr; + if (isConstantBinning) { + nBins = new int[nDimensions]; + xmin = new double[nDimensions]; + xmax = new double[nDimensions]; + int iDim = 0; + for (auto& v : hist.FindMember("nBins")->value.GetArray()) { + nBins[iDim++] = v.GetInt(); + LOG(debug) << "nBins " << iDim << ": " << nBins[iDim - 1]; + } + iDim = 0; + for (auto& v : hist.FindMember("xmin")->value.GetArray()) { + xmin[iDim++] = v.GetDouble(); + LOG(debug) << "xmin " << iDim << ": " << xmin[iDim - 1]; + } + iDim = 0; + for (auto& v : hist.FindMember("xmax")->value.GetArray()) { + xmax[iDim++] = v.GetDouble(); + LOG(debug) << "xmax " << iDim << ": " << xmax[iDim - 1]; + } + } else { + int iDim = 0; + binLimits = new TArrayD[nDimensions]; + for (auto& v : hist.FindMember("binLimits")->value.GetArray()) { + double* lims = new double[v.GetArray().Size()]; + int iElem = 0; + for (auto& lim : v.GetArray()) { + lims[iElem++] = lim.GetDouble(); + } + binLimits[iDim++] = TArrayD(v.GetArray().Size(), lims); + } + } + + TString* axLabels = nullptr; + if (hist.HasMember("axLabels")) { + axLabels = new TString[hist.FindMember("axLabels")->value.GetArray().Size()]; + int iDim = 0; + for (auto& v : hist.FindMember("axLabels")->value.GetArray()) { + axLabels[iDim++] = v.GetString(); + } + } + + int varW = (hist.HasMember("varW") ? VarManager::fgVarNamesMap[hist.FindMember("varW")->value.GetString()] : -1); + bool useSparse = (hist.HasMember("useSparse") ? hist.FindMember("useSparse")->value.GetBool() : false); + bool isDouble = (hist.HasMember("isDouble") ? hist.FindMember("isDouble")->value.GetBool() : false); + + if (isConstantBinning) { + hm->AddHistogram(histClass, histName, title, nDimensions, vars, nBins, xmin, xmax, axLabels, varW, useSparse, isDouble); + } else { + hm->AddHistogram(histClass, histName, title, nDimensions, vars, binLimits, axLabels, varW, useSparse, isDouble); + } + + } else { // TH1, TH2 or TH3 + + LOG(debug) << "is TH1, TH2 or TH3 "; + + bool isProfile = hist.FindMember("isProfile")->value.GetBool(); + LOG(debug) << "isProfile: " << isProfile; + + int nXbins = hist.FindMember("nXbins")->value.GetInt(); + LOG(debug) << "nXbins: " << nXbins; + + const char* varX = hist.FindMember("varX")->value.GetString(); + LOG(debug) << "varX: " << varX; + + double xmin = (hist.HasMember("xmin") ? hist.FindMember("xmin")->value.GetDouble() : 0.0); + LOG(debug) << "xmin: " << xmin; + + double xmax = (hist.HasMember("xmax") ? hist.FindMember("xmax")->value.GetDouble() : 0.0); + LOG(debug) << "xmax: " << xmax; + + std::vector xbinsVec; + if (hist.HasMember("xbins")) { + LOG(debug) << "xbins: "; + for (auto& v : hist.FindMember("xbins")->value.GetArray()) { + xbinsVec.push_back(v.GetDouble()); + LOG(debug) << v.GetDouble(); + } + } + + const char* varY = (hist.HasMember("varY") ? hist.FindMember("varY")->value.GetString() : "kNothing"); + LOG(debug) << "varY: " << varY; + + int nYbins = (hist.HasMember("nYbins") ? hist.FindMember("nYbins")->value.GetInt() : 0); + LOG(debug) << "nYbins: " << nYbins; + + double ymin = (hist.HasMember("ymin") ? hist.FindMember("ymin")->value.GetDouble() : 0.0); + LOG(debug) << "ymin: " << ymin; + + double ymax = (hist.HasMember("ymax") ? hist.FindMember("ymax")->value.GetDouble() : 0.0); + LOG(debug) << "ymax: " << ymax; + + std::vector ybinsVec; + if (hist.HasMember("ybins")) { + LOG(debug) << "ybins: "; + for (auto& v : hist.FindMember("ybins")->value.GetArray()) { + ybinsVec.push_back(v.GetDouble()); + LOG(debug) << v.GetDouble(); + } + } + + const char* varZ = (hist.HasMember("varZ") ? hist.FindMember("varZ")->value.GetString() : "kNothing"); + LOG(debug) << "varZ: " << varZ; + + int nZbins = (hist.HasMember("nZbins") ? hist.FindMember("nZbins")->value.GetInt() : 0); + LOG(debug) << "nZbins: " << nZbins; + + double zmin = (hist.HasMember("zmin") ? hist.FindMember("zmin")->value.GetDouble() : 0.0); + LOG(debug) << "zmin: " << zmin; + + double zmax = (hist.HasMember("zmax") ? hist.FindMember("zmax")->value.GetDouble() : 0.0); + LOG(debug) << "zmax: " << zmax; + + std::vector zbinsVec; + if (hist.HasMember("zbins")) { + LOG(debug) << "zbins: "; + for (auto& v : hist.FindMember("zbins")->value.GetArray()) { + zbinsVec.push_back(v.GetDouble()); + LOG(debug) << v.GetDouble(); + } + } + + const char* xLabels = (hist.HasMember("xLabels") ? hist.FindMember("xLabels")->value.GetString() : ""); + LOG(debug) << "xLabels: " << xLabels; + + const char* yLabels = (hist.HasMember("yLabels") ? hist.FindMember("yLabels")->value.GetString() : ""); + LOG(debug) << "yLabels: " << yLabels; + + const char* zLabels = (hist.HasMember("zLabels") ? hist.FindMember("zLabels")->value.GetString() : ""); + LOG(debug) << "zLabels: " << zLabels; + + const char* varT = (hist.HasMember("varT") ? hist.FindMember("varT")->value.GetString() : "kNothing"); + LOG(debug) << "varT: " << varT; + + const char* varW = (hist.HasMember("varW") ? hist.FindMember("varW")->value.GetString() : "kNothing"); + LOG(debug) << "varW: " << varW; + + bool isdouble = (hist.HasMember("isdouble") ? hist.FindMember("isdouble")->value.GetBool() : false); + LOG(debug) << "isdouble: " << isdouble; + + bool isFillLabelx = (hist.HasMember("isFillLabelx") ? hist.FindMember("isFillLabelx")->value.GetBool() : false); + LOG(debug) << "isFillLabelx: " << isFillLabelx; + + if (isConstantBinning) { + hm->AddHistogram(histClass, histName, title, isProfile, + nXbins, xmin, xmax, VarManager::fgVarNamesMap[varX], + nYbins, ymin, ymax, VarManager::fgVarNamesMap[varY], + nZbins, zmin, zmax, VarManager::fgVarNamesMap[varZ], + xLabels, yLabels, zLabels, + VarManager::fgVarNamesMap[varT], VarManager::fgVarNamesMap[varW], isdouble, isFillLabelx); + } else { + int xBinsSize = xbinsVec.size(); + if (xBinsSize != (nXbins + 1)) { + LOG(fatal) << "Histogram not properly defined in the JSON file. Wrong x binning for histogram"; + continue; + } + double* xbins = new double[xbinsVec.size()]; + std::copy(xbinsVec.begin(), xbinsVec.end(), xbins); + + double* ybins = nullptr; + if (isTH2 || isTH3) { + if (static_cast(ybinsVec.size()) != (nYbins + 1)) { + LOG(fatal) << "Histogram not properly defined in the JSON file. Wrong y binning for histogram"; + continue; + } + ybins = new double[ybinsVec.size()]; + std::copy(ybinsVec.begin(), ybinsVec.end(), ybins); + } + + double* zbins = nullptr; + if (isTH3) { + if (static_cast(zbinsVec.size()) != (nZbins + 1)) { + LOG(fatal) << "Histogram not properly defined in the JSON file. Wrong z binning for histogram"; + continue; + } + zbins = new double[zbinsVec.size()]; + std::copy(zbinsVec.begin(), zbinsVec.end(), zbins); + } + hm->AddHistogram(histClass, histName, title, isProfile, + nXbins, xbins, VarManager::fgVarNamesMap[varX], + nYbins, ybins, VarManager::fgVarNamesMap[varY], + nZbins, zbins, VarManager::fgVarNamesMap[varZ], + xLabels, yLabels, zLabels, + VarManager::fgVarNamesMap[varT], VarManager::fgVarNamesMap[varW], isdouble, isFillLabelx); + } // end if (!isTHn) + } + } +} diff --git a/PWGDQ/Core/HistogramsLibrary.h b/PWGDQ/Core/HistogramsLibrary.h index 60fe4cc8714..869fb3a85f3 100644 --- a/PWGDQ/Core/HistogramsLibrary.h +++ b/PWGDQ/Core/HistogramsLibrary.h @@ -18,12 +18,17 @@ #include #include "PWGDQ/Core/HistogramManager.h" #include "PWGDQ/Core/VarManager.h" +#include "CommonConstants/MathConstants.h" +#include "rapidjson/document.h" namespace o2::aod { namespace dqhistograms { void DefineHistograms(HistogramManager* hm, const char* histClass, const char* groupName, const char* subGroupName = ""); +template +bool ValidateJSONHistogram(T hist); +void AddHistogramsFromJSON(HistogramManager* hm, const char* json); } } // namespace o2::aod diff --git a/PWGDQ/Core/MCProng.cxx b/PWGDQ/Core/MCProng.cxx index 14fa645eb77..48f2c52ae36 100644 --- a/PWGDQ/Core/MCProng.cxx +++ b/PWGDQ/Core/MCProng.cxx @@ -11,11 +11,22 @@ #include "PWGDQ/Core/MCProng.h" +#include +#include #include #include ClassImp(MCProng); +std::map MCProng::fgSourceNames = { + {"kNothing", MCProng::kNothing}, + {"kPhysicalPrimary", MCProng::kPhysicalPrimary}, + {"kProducedInTransport", MCProng::kProducedInTransport}, + {"kProducedByGenerator", MCProng::kProducedByGenerator}, + {"kFromBackgroundEvent", MCProng::kFromBackgroundEvent}, + {"kHEPMCFinalState", MCProng::kHEPMCFinalState}, + {"kIsPowhegDYMuon", MCProng::kIsPowhegDYMuon}}; + //________________________________________________________________________________________________________________ MCProng::MCProng() : fNGenerations(0), fPDGcodes({}), @@ -119,9 +130,9 @@ void MCProng::SetSourceBit(int generation, int sourceBit, bool exclude /*=false* if (generation < 0 || generation >= fNGenerations) { return; } - fSourceBits[generation] |= (uint64_t(1) << sourceBit); + fSourceBits[generation] |= (static_cast(1) << sourceBit); if (exclude) { - fExcludeSource[generation] |= (uint64_t(1) << sourceBit); + fExcludeSource[generation] |= (static_cast(1) << sourceBit); } } @@ -146,7 +157,11 @@ void MCProng::Print() const for (int i = 0; i < fNGenerations; i++) { std::cout << "Generation #" << i << " PDGcode(" << fPDGcodes[i] << ") CheckBothCharges(" << fCheckBothCharges[i] << ") ExcludePDG(" << fExcludePDG[i] << ") SourceBits(" << fSourceBits[i] << ") ExcludeSource(" << fExcludeSource[i] - << ") UseANDonSource(" << fUseANDonSourceBitMap[i] << ") CheckGenerationsInTime(" << fCheckGenerationsInTime << ") PDGInHistory(" << fPDGInHistory[i] << ") ExcludePDGInHistory(" << fExcludePDGInHistory[i] << ")" << std::endl; + << ") UseANDonSource(" << fUseANDonSourceBitMap[i] << ") CheckGenerationsInTime(" << fCheckGenerationsInTime << ")"; + for (std::size_t j = 0; j < fPDGInHistory.size(); j++) { + std::cout << " #" << j << " PDGInHistory(" << fPDGInHistory[j] << ") ExcludePDGInHistory(" << fExcludePDGInHistory[j] << ")"; + } + std::cout << std::endl; } } @@ -182,6 +197,13 @@ bool MCProng::ComparePDG(int pdg, int prongPDG, bool checkBothCharges, bool excl decision = (prongPDG > 0 ? pdg >= 100 && pdg <= 199 : pdg >= -199 && pdg <= -100); } break; + case 101: // all light flavoured and strange mesons + if (checkBothCharges) { + decision = absPDG >= 100 && absPDG <= 399; + } else { + decision = (prongPDG > 0 ? pdg >= 100 && pdg <= 399 : pdg >= -399 && pdg <= -100); + } + break; case 1000: // light flavoured baryons if (checkBothCharges) { decision = absPDG >= 1000 && absPDG <= 1999; diff --git a/PWGDQ/Core/MCProng.h b/PWGDQ/Core/MCProng.h index df36f1a316c..cd42965d271 100644 --- a/PWGDQ/Core/MCProng.h +++ b/PWGDQ/Core/MCProng.h @@ -23,6 +23,7 @@ A few non-existent PYTHIA codes are used to select more than one PYTHIA code. 0 - default, accepts all PYTHIA codes 100 - light unflavoured mesons in the code range 100-199 +101 - all light and strange mesons in the code range 100-399 200 - --"-- 200-299 300 - strange mesons in the code range 300-399 400 - charmed mesons in the code range 400-499 @@ -43,6 +44,7 @@ A few non-existent PYTHIA codes are used to select more than one PYTHIA code. 901 - LF mesons for LMEE 111, 221, 331, 113, 223, 333 902 - all open charm open beauty mesons+baryons 400-439, 500-549, 4000-4399, 5000-5499 903 - all hadrons in the code range 100-599, 1000-5999 +904 - chic0, chic1 and chic2 445, 100441, 200443 1000 - light unflavoured baryons in the code range 1000-1999 2000 - --"-- 2000-2999 3000 - strange baryons in the code range 3000-3999 @@ -56,28 +58,35 @@ A few non-existent PYTHIA codes are used to select more than one PYTHIA code. #define PWGDQ_CORE_MCPRONG_H_ #include "TNamed.h" +#include "TString.h" #include #include +#include class MCProng { public: enum Source { // TODO: add more sources, see Run-2 code + kNothing = -1, kPhysicalPrimary = 0, // Physical primary, ALICE definition kProducedInTransport, // Produced during transport through the detector (e.g. GEANT) kProducedByGenerator, // Produced by generator (if not, then produced by GEANT) kFromBackgroundEvent, // Produced in the underlying event + kHEPMCFinalState, // HEPMC code 11 + kIsPowhegDYMuon, // POWHEG muons based on Pythia Status Code (=23) -> Drell-Yan signal kNSources }; + static std::map fgSourceNames; + enum Constants { kPDGCodeNotAssigned = 0 }; MCProng(); - MCProng(int n); + explicit MCProng(int n); MCProng(int n, int m); MCProng(int n, std::vector pdgs, std::vector checkBothCharges, std::vector excludePDG, std::vector sourceBits, std::vector excludeSource, std::vector useANDonSourceBitMap, diff --git a/PWGDQ/Core/MCSignal.cxx b/PWGDQ/Core/MCSignal.cxx index a86b0f8aa8d..7a234b65088 100644 --- a/PWGDQ/Core/MCSignal.cxx +++ b/PWGDQ/Core/MCSignal.cxx @@ -9,6 +9,9 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include +#include + #include "PWGDQ/Core/MCSignal.h" using std::cout; @@ -21,6 +24,10 @@ MCSignal::MCSignal() : TNamed("", ""), fProngs({}), fNProngs(0), fCommonAncestorIdxs({}), + fExcludeCommonAncestor(false), + fDecayChannelIsExclusive(false), + fDecayChannelIsNotExclusive(false), + fNAncestorDirectProngs(0), fTempAncestorLabel(-1) { } @@ -30,22 +37,30 @@ MCSignal::MCSignal(int nProngs, const char* name /*= ""*/, const char* title /*= fProngs({}), fNProngs(nProngs), fCommonAncestorIdxs({}), + fExcludeCommonAncestor(false), + fDecayChannelIsExclusive(false), + fDecayChannelIsNotExclusive(false), + fNAncestorDirectProngs(0), fTempAncestorLabel(-1) { fProngs.reserve(nProngs); } //________________________________________________________________________________________________ -MCSignal::MCSignal(const char* name, const char* title, std::vector prongs, std::vector commonAncestors) : TNamed(name, title), - fProngs(prongs), - fNProngs(prongs.size()), - fCommonAncestorIdxs(commonAncestors), - fTempAncestorLabel(-1) +MCSignal::MCSignal(const char* name, const char* title, std::vector prongs, std::vector commonAncestors, bool excludeCommonAncestor) : TNamed(name, title), + fProngs(prongs), + fNProngs(prongs.size()), + fCommonAncestorIdxs(commonAncestors), + fExcludeCommonAncestor(excludeCommonAncestor), + fDecayChannelIsExclusive(false), + fDecayChannelIsNotExclusive(false), + fNAncestorDirectProngs(0), + fTempAncestorLabel(-1) { } //________________________________________________________________________________________________ -void MCSignal::SetProngs(std::vector prongs, std::vector commonAncestors) +void MCSignal::SetProngs(std::vector prongs, std::vector commonAncestors) { fProngs = prongs; fNProngs = fProngs.size(); @@ -53,7 +68,7 @@ void MCSignal::SetProngs(std::vector prongs, std::vector commonA } //________________________________________________________________________________________________ -void MCSignal::AddProng(MCProng prong, short commonAncestor) +void MCSignal::AddProng(MCProng prong, int8_t commonAncestor) { if (fProngs.size() < fNProngs) { fProngs.push_back(prong); @@ -67,10 +82,14 @@ void MCSignal::AddProng(MCProng prong, short commonAncestor) void MCSignal::PrintConfig() { cout << "Name/Title: " << fName << " / " << fTitle << endl; + cout << "Exclude common ancestor combinations: " << fExcludeCommonAncestor << endl; + cout << "Decay channel is exclusive: " << fDecayChannelIsExclusive << endl; + cout << "Decay channel is not exclusive: " << fDecayChannelIsNotExclusive << endl; + cout << "Decay channel direct prongs for the common ancestor: " << fNAncestorDirectProngs << endl; cout << "Printing " << fNProngs << "/" << fProngs.size() << " prongs:" << endl; int i = 0; for (auto& pr : fProngs) { - cout << "Prong #" << i << " commonAncestor" << fCommonAncestorIdxs[i] << " ================ " << endl; + cout << "Prong #" << i << " commonAncestor: " << fCommonAncestorIdxs[i] << " ================ " << endl; i++; pr.Print(); } diff --git a/PWGDQ/Core/MCSignal.h b/PWGDQ/Core/MCSignal.h index 787aa443b22..42fe0a0a050 100644 --- a/PWGDQ/Core/MCSignal.h +++ b/PWGDQ/Core/MCSignal.h @@ -66,13 +66,23 @@ class MCSignal : public TNamed { public: MCSignal(); - MCSignal(int nProngs, const char* name = "", const char* title = ""); - MCSignal(const char* name, const char* title, std::vector prongs, std::vector commonAncestors); + MCSignal(int nProngs, const char* name = "", const char* title = ""); // NOLINT + MCSignal(const char* name, const char* title, std::vector prongs, std::vector commonAncestors, bool excludeCommonAncestor = false); MCSignal(const MCSignal& c) = default; ~MCSignal() override = default; - void SetProngs(std::vector prongs, std::vector commonAncestors); - void AddProng(MCProng prong, short commonAncestor = -1); + void SetProngs(std::vector prongs, std::vector commonAncestors); + void AddProng(MCProng prong, int8_t commonAncestor = -1); + void SetDecayChannelIsExclusive(int nProngs, bool option = true) + { + fDecayChannelIsExclusive = option; + fNAncestorDirectProngs = nProngs; + } + void SetDecayChannelIsNotExclusive(int nProngs, bool option = true) + { + fDecayChannelIsNotExclusive = option; + fNAncestorDirectProngs = nProngs; + } int GetNProngs() const { @@ -82,6 +92,18 @@ class MCSignal : public TNamed { return fProngs[0].fNGenerations; } + bool GetDecayChannelIsExclusive() const + { + return fDecayChannelIsExclusive; + } + bool GetDecayChannelIsNotExclusive() const + { + return fDecayChannelIsNotExclusive; + } + int GetNAncestorDirectProngs() const + { + return fNAncestorDirectProngs; + } template bool CheckSignal(bool checkSources, const T&... args) @@ -97,9 +119,13 @@ class MCSignal : public TNamed void PrintConfig(); private: - std::vector fProngs; - unsigned int fNProngs; - std::vector fCommonAncestorIdxs; + std::vector fProngs; // vector of MCProng + unsigned int fNProngs; // number of prongs + std::vector fCommonAncestorIdxs; // index of the most recent ancestor, relative to each prong's history + bool fExcludeCommonAncestor; // explicitly request that there is no common ancestor + bool fDecayChannelIsExclusive; // if true, then the indicated mother particle has a number of daughters which is equal to the number of direct prongs defined in this MC signal + bool fDecayChannelIsNotExclusive; // if true, then the indicated mother particle has a number of daughters which is larger than the number of direct prongs defined in this MC signal + int fNAncestorDirectProngs; // number of direct prongs belonging to the common ancestor specified by this signal int fTempAncestorLabel; template @@ -138,15 +164,28 @@ bool MCSignal::CheckProng(int i, bool checkSources, const T& track) if (fNProngs > 1 && fCommonAncestorIdxs[i] == j) { if (i == 0) { fTempAncestorLabel = currentMCParticle.globalIndex(); + // In the case of decay channels marked as being "exclusive", check how many decay daughters this mother has registered + // in the stack and compare to the number of prongs defined for this MCSignal. + // If these numbers are equal, it means this decay MCSignal match is exclusive (there are no additional prongs for this mother besides the + // prongs defined here). + if (currentMCParticle.has_daughters()) { + if (fDecayChannelIsExclusive && currentMCParticle.daughtersIds()[1] - currentMCParticle.daughtersIds()[0] + 1 != fNAncestorDirectProngs) { + return false; + } + if (fDecayChannelIsNotExclusive && currentMCParticle.daughtersIds()[1] - currentMCParticle.daughtersIds()[0] + 1 == fNAncestorDirectProngs) { + return false; + } + } } else { - if (currentMCParticle.globalIndex() != fTempAncestorLabel) { + if (currentMCParticle.globalIndex() != fTempAncestorLabel && !fExcludeCommonAncestor) + return false; + else if (currentMCParticle.globalIndex() == fTempAncestorLabel && fExcludeCommonAncestor) return false; - } } } // Update the currentMCParticle by moving either back in time (towards mothers, grandmothers, etc) - // or in time (towards daughters) depending on how this was configured in the MSignal + // or in time (towards daughters) depending on how this was configured in the MC Signal if (!fProngs[i].fCheckGenerationsInTime) { // make sure that a mother exists in the stack before moving one generation further in history if (!currentMCParticle.has_mothers() && j < fProngs[i].fNGenerations - 1) { @@ -177,41 +216,56 @@ bool MCSignal::CheckProng(int i, bool checkSources, const T& track) currentMCParticle = track; for (int j = 0; j < fProngs[i].fNGenerations; j++) { // check whether sources are required for this generation - if (!fProngs[i].fSourceBits[j]) { - continue; + bool hasSources = false; + if (fProngs[i].fSourceBits[j]) { + hasSources = true; } // check each source uint64_t sourcesDecision = 0; - // Check kPhysicalPrimary - if (fProngs[i].fSourceBits[j] & (uint64_t(1) << MCProng::kPhysicalPrimary)) { - if ((fProngs[i].fExcludeSource[j] & (uint64_t(1) << MCProng::kPhysicalPrimary)) != currentMCParticle.isPhysicalPrimary()) { - sourcesDecision |= (uint64_t(1) << MCProng::kPhysicalPrimary); + if (hasSources) { + // Check kPhysicalPrimary + if (fProngs[i].fSourceBits[j] & (static_cast(1) << MCProng::kPhysicalPrimary)) { + if ((fProngs[i].fExcludeSource[j] & (static_cast(1) << MCProng::kPhysicalPrimary)) != currentMCParticle.isPhysicalPrimary()) { + sourcesDecision |= (static_cast(1) << MCProng::kPhysicalPrimary); + } } - } - // Check kProducedInTransport - if (fProngs[i].fSourceBits[j] & (uint64_t(1) << MCProng::kProducedInTransport)) { - if ((fProngs[i].fExcludeSource[j] & (uint64_t(1) << MCProng::kProducedInTransport)) != (!currentMCParticle.producedByGenerator())) { - sourcesDecision |= (uint64_t(1) << MCProng::kProducedInTransport); + // Check kProducedInTransport + if (fProngs[i].fSourceBits[j] & (static_cast(1) << MCProng::kProducedInTransport)) { + if ((fProngs[i].fExcludeSource[j] & (static_cast(1) << MCProng::kProducedInTransport)) != (!currentMCParticle.producedByGenerator())) { + sourcesDecision |= (static_cast(1) << MCProng::kProducedInTransport); + } } - } - // Check kProducedByGenerator - if (fProngs[i].fSourceBits[j] & (uint64_t(1) << MCProng::kProducedByGenerator)) { - if ((fProngs[i].fExcludeSource[j] & (uint64_t(1) << MCProng::kProducedByGenerator)) != currentMCParticle.producedByGenerator()) { - sourcesDecision |= (uint64_t(1) << MCProng::kProducedByGenerator); + // Check kProducedByGenerator + if (fProngs[i].fSourceBits[j] & (static_cast(1) << MCProng::kProducedByGenerator)) { + if ((fProngs[i].fExcludeSource[j] & (static_cast(1) << MCProng::kProducedByGenerator)) != currentMCParticle.producedByGenerator()) { + sourcesDecision |= (static_cast(1) << MCProng::kProducedByGenerator); + } } - } - // Check kFromBackgroundEvent - if (fProngs[i].fSourceBits[j] & (uint64_t(1) << MCProng::kFromBackgroundEvent)) { - if ((fProngs[i].fExcludeSource[j] & (uint64_t(1) << MCProng::kFromBackgroundEvent)) != currentMCParticle.fromBackgroundEvent()) { - sourcesDecision |= (uint64_t(1) << MCProng::kFromBackgroundEvent); + // Check kFromBackgroundEvent + if (fProngs[i].fSourceBits[j] & (static_cast(1) << MCProng::kFromBackgroundEvent)) { + if ((fProngs[i].fExcludeSource[j] & (static_cast(1) << MCProng::kFromBackgroundEvent)) != currentMCParticle.fromBackgroundEvent()) { + sourcesDecision |= (static_cast(1) << MCProng::kFromBackgroundEvent); + } } - } + // Check HEPMC code 11 (final state) + if (fProngs[i].fSourceBits[j] & (static_cast(1) << MCProng::kHEPMCFinalState)) { + if ((fProngs[i].fExcludeSource[j] & (static_cast(1) << MCProng::kHEPMCFinalState)) != (currentMCParticle.getHepMCStatusCode() == 11)) { + sourcesDecision |= (static_cast(1) << MCProng::kHEPMCFinalState); + } + } + // Check kIsPowhegDYMuon + if (fProngs[i].fSourceBits[j] & (static_cast(1) << MCProng::kIsPowhegDYMuon)) { + if ((fProngs[i].fExcludeSource[j] & (static_cast(1) << MCProng::kIsPowhegDYMuon)) != (currentMCParticle.getGenStatusCode() == 23)) { + sourcesDecision |= (static_cast(1) << MCProng::kIsPowhegDYMuon); + } + } + } // end if(hasSources) // no source bit is fulfilled - if (!sourcesDecision) { + if (hasSources && !sourcesDecision) { return false; } // if fUseANDonSourceBitMap is on, request all bits - if (fProngs[i].fUseANDonSourceBitMap[j] && (sourcesDecision != fProngs[i].fSourceBits[j])) { + if (hasSources && (fProngs[i].fUseANDonSourceBitMap[j] && (sourcesDecision != fProngs[i].fSourceBits[j]))) { return false; } @@ -241,12 +295,12 @@ bool MCSignal::CheckProng(int i, bool checkSources, const T& track) } } } - } - } + } // end loop over generations + } // end if(checkSources) - if (fProngs[i].fPDGInHistory.size() == 0) + if (fProngs[i].fPDGInHistory.size() == 0) { return true; - else { // check if mother pdg is in history + } else { // check if mother pdg is in history std::vector pdgInHistory; // while find mothers, check if the provided PDG codes are included or excluded in the particle decay history @@ -260,43 +314,45 @@ bool MCSignal::CheckProng(int i, bool checkSources, const T& track) // Note: Currently no need to check generation InTime, so disable if case and always check BackInTime (direction of mothers) // The option to check for daughter in decay chain is still implemented but commented out. - // if (!fProngs[i].fCheckGenerationsInTime) { // check generation back in time - while (currentMCParticle.has_mothers()) { - auto mother = currentMCParticle.template mothers_first_as

(); - if (!fProngs[i].fExcludePDGInHistory[k] && fProngs[i].ComparePDG(mother.pdgCode(), fProngs[i].fPDGInHistory[k], true, fProngs[i].fExcludePDGInHistory[k])) { - pdgInHistory.emplace_back(mother.pdgCode()); - break; + if (!fProngs[i].fCheckGenerationsInTime) { // check generation back in time + while (currentMCParticle.has_mothers()) { + auto mother = currentMCParticle.template mothers_first_as

(); + if (!fProngs[i].fExcludePDGInHistory[k] && fProngs[i].ComparePDG(mother.pdgCode(), fProngs[i].fPDGInHistory[k], true, fProngs[i].fExcludePDGInHistory[k])) { + pdgInHistory.emplace_back(mother.pdgCode()); + break; + } + if (fProngs[i].fExcludePDGInHistory[k] && !fProngs[i].ComparePDG(mother.pdgCode(), fProngs[i].fPDGInHistory[k], true, fProngs[i].fExcludePDGInHistory[k])) { + return false; + } + ith++; + currentMCParticle = mother; + if (ith > 10) { // need error message. Given pdg code was not found within 10 generations of the particles decay chain. + break; + } } - if (fProngs[i].fExcludePDGInHistory[k] && !fProngs[i].ComparePDG(mother.pdgCode(), fProngs[i].fPDGInHistory[k], true, fProngs[i].fExcludePDGInHistory[k])) { + } /*else { // check generation in time + if (!currentMCParticle.has_daughters()) { return false; } - ith++; - currentMCParticle = mother; - if (ith > 10) { // need error message. Given pdg code was not found within 10 generations of the particles decay chain. - break; + const auto& daughtersSlice = currentMCParticle.template daughters_as

(); + for (auto& d : daughtersSlice) { + if (!fProngs[i].fExcludePDGInHistory[k] && fProngs[i].ComparePDG(d.pdgCode(), fProngs[i].fPDGInHistory[k], true, fProngs[i].fExcludePDGInHistory[k])) { + pdgInHistory.emplace_back(d.pdgCode()); + break; + } + if (fProngs[i].fExcludePDGInHistory[k] && !fProngs[i].ComparePDG(d.pdgCode(), fProngs[i].fPDGInHistory[k], true, fProngs[i].fExcludePDGInHistory[k])) { + return false; + } + ith++; + if (ith > 10) { // need error message. Given pdg code was not found within 10 generations of the particles decay chain. + break; + } } - } - // } else { // check generation in time - // if (!currentMCParticle.has_daughters()) - // return false; - // const auto& daughtersSlice = currentMCParticle.template daughters_as

(); - // for (auto& d : daughtersSlice) { - // if (!fProngs[i].fExcludePDGInHistory[k] && fProngs[i].ComparePDG(d.pdgCode(), fProngs[i].fPDGInHistory[k], true, fProngs[i].fExcludePDGInHistory[k])) { - // pdgInHistory.emplace_back(d.pdgCode()); - // break; - // } - // if (fProngs[i].fExcludePDGInHistory[k] && !fProngs[i].ComparePDG(d.pdgCode(), fProngs[i].fPDGInHistory[k], true, fProngs[i].fExcludePDGInHistory[k])) { - // return false; - // } - // ith++; - // if (ith > 10) { // need error message. Given pdg code was not found within 10 generations of the particles decay chain. - // break; - // } - // } - // } + }*/ } - if (pdgInHistory.size() != nIncludedPDG) // vector has as many entries as mothers (daughters) defined for prong + if (pdgInHistory.size() != nIncludedPDG) { // vector has as many entries as mothers (daughters) defined for prong return false; + } } return true; } diff --git a/PWGDQ/Core/MCSignalLibrary.cxx b/PWGDQ/Core/MCSignalLibrary.cxx index c45ec9e23d3..614dcc3a2c4 100644 --- a/PWGDQ/Core/MCSignalLibrary.cxx +++ b/PWGDQ/Core/MCSignalLibrary.cxx @@ -11,7 +11,18 @@ // // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // +#include +#include +// #include + +#include +#include "CommonConstants/PhysicsConstants.h" #include "PWGDQ/Core/MCSignalLibrary.h" +#include "Framework/Logger.h" + +using namespace o2::constants::physics; +// using std::cout; +// using std::endl; MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) { @@ -115,6 +126,23 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "Inclusive jpsi", {prong}, {-1}); return signal; } + if (!nameStr.compare("Helium3")) { + MCProng prong(1, {1000020030}, {true}, {false}, {0}, {0}, {false}); + signal = new MCSignal(name, "Helium3", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("Helium3Primary")) { + MCProng prong(1, {1000020030}, {true}, {false}, {0}, {0}, {false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "Helium3Primary", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("Helium3FromTransport")) { + MCProng prong(1, {1000020030}, {true}, {false}, {0}, {0}, {false}); + prong.SetSourceBit(0, MCProng::kProducedInTransport); + signal = new MCSignal(name, "Helium3FromTransport", {prong}, {-1}); + return signal; + } if (!nameStr.compare("nonPromptJpsi")) { MCProng prong(2, {443, 503}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); signal = new MCSignal(name, "Non-prompt jpsi", {prong}, {-1}); @@ -170,16 +198,43 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "Inclusive Chic0, Chic1 and Chic2", {prong}, {-1}); return signal; } + if (!nameStr.compare("Upsilon1S")) { + MCProng prong(1, {553}, {true}, {false}, {0}, {0}, {false}); + signal = new MCSignal(name, "Inclusive Upsilon1S", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("Upsilon2S")) { + MCProng prong(1, {100553}, {true}, {false}, {0}, {0}, {false}); + signal = new MCSignal(name, "Inclusive Upsilon2S", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("Upsilon3S")) { + MCProng prong(1, {200553}, {true}, {false}, {0}, {0}, {false}); + signal = new MCSignal(name, "Inclusive Upsilon3S", {prong}, {-1}); + return signal; + } if (!nameStr.compare("allBeautyHadrons")) { MCProng prong(1, {503}, {true}, {false}, {0}, {0}, {false}); signal = new MCSignal(name, "All beauty hadrons", {prong}, {-1}); return signal; } + if (!nameStr.compare("allBeautyHadronsFS")) { + MCProng prong(1, {503}, {true}, {false}, {0}, {0}, {false}); + prong.SetSourceBit(0, MCProng::kHEPMCFinalState); + signal = new MCSignal(name, "All beauty hadrons", {prong}, {-1}); + return signal; + } if (!nameStr.compare("allOpenBeautyHadrons")) { MCProng prong(1, {502}, {true}, {false}, {0}, {0}, {false}); signal = new MCSignal(name, "All open beauty hadrons", {prong}, {-1}); return signal; } + if (!nameStr.compare("allOpenBeautyHadronsFS")) { + MCProng prong(1, {502}, {true}, {false}, {0}, {0}, {false}); + prong.SetSourceBit(0, MCProng::kHEPMCFinalState); + signal = new MCSignal(name, "All open beauty hadrons", {prong}, {-1}); + return signal; + } if (!nameStr.compare("Bc")) { MCProng prong(1, {541}, {true}, {false}, {0}, {0}, {false}); signal = new MCSignal(name, "Bc", {prong}, {-1}); @@ -206,11 +261,23 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "Everything from beauty", {prong}, {-1}); return signal; } + if (!nameStr.compare("everythingFromBeautyFS")) { + MCProng prong(2, {0, 503}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prong.SetSourceBit(1, MCProng::kHEPMCFinalState); + signal = new MCSignal(name, "Everything from beauty", {prong}, {-1}); + return signal; + } if (!nameStr.compare("everythingFromEverythingFromBeauty")) { MCProng prong(3, {0, 0, 503}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); signal = new MCSignal(name, "Everything from everything from beauty", {prong}, {-1}); return signal; } + if (!nameStr.compare("everythingFromEverythingFromBeautyFS")) { + MCProng prong(3, {0, 0, 503}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + prong.SetSourceBit(2, MCProng::kHEPMCFinalState); + signal = new MCSignal(name, "Everything from everything from beauty", {prong}, {-1}); + return signal; + } if (!nameStr.compare("allCharmHadrons")) { MCProng prong(1, {403}, {true}, {false}, {0}, {0}, {false}); signal = new MCSignal(name, "All charm hadrons", {prong}, {-1}); @@ -294,16 +361,22 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "electron from a photon conversion", {prong}, {-1}); return signal; } + if (!nameStr.compare("PowhegDYMuon1")) { + MCProng prong(1, {13}, {true}, {false}, {0}, {0}, {false}); // selecting muons + prong.SetSourceBit(0, MCProng::kIsPowhegDYMuon); // set source to be Muon from POWHEG + signal = new MCSignal(name, "POWHEG Muon singles", {prong}, {-1}); // define a signal with 1-prong + return signal; + } // 2-prong signals if (!nameStr.compare("dielectron")) { MCProng prong(1, {11}, {true}, {false}, {0}, {0}, {false}); - signal = new MCSignal("dielectron", "Electron pair", {prong, prong}, {-1, -1}); + signal = new MCSignal(name, "Electron pair", {prong, prong}, {-1, -1}); return signal; } if (!nameStr.compare("dimuon")) { MCProng prong(1, {13}, {true}, {false}, {0}, {0}, {false}); - signal = new MCSignal("dielectron", "Electron pair", {prong, prong}, {-1, -1}); + signal = new MCSignal(name, "Muon pair", {prong, prong}, {-1, -1}); return signal; } if (!nameStr.compare("electronMuonPair")) { @@ -317,11 +390,22 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "dielectron from a photon conversion", {prong, prong}, {1, 1}); return signal; } + if (!nameStr.compare("dielectronFromAllPC")) { + MCProng prong(2, {11, 22}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "dielectron from a photon conversion", {prong, prong}, {-1, -1}); + return signal; + } if (!nameStr.compare("dielectronPCPi0")) { MCProng prong(3, {11, 22, 111}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); signal = new MCSignal(name, "dielectron from a photon conversion from a pi0", {prong, prong}, {1, 1}); return signal; } + if (!nameStr.compare("PowhegDYMuon2")) { + MCProng prong(1, {13}, {true}, {false}, {0}, {0}, {false}); // selecting muons + prong.SetSourceBit(0, MCProng::kIsPowhegDYMuon); // set source to be Muon from POWHEG + signal = new MCSignal(name, "POWHEG Muon pair", {prong, prong}, {-1, -1}); // define a signal with 2-prong + return signal; + } // LMEE single signals // electron signals with mother X: e from mother X @@ -376,6 +460,17 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "Electrons from jpsi decays", {prong}, {-1}); return signal; } + if (!nameStr.compare("anythingFromJpsi")) { + MCProng prong(2, {MCProng::kPDGCodeNotAssigned, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Anything from jpsi decays", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("eFromPromptJpsi")) { + MCProng prong(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "Electrons from jpsi decays", {prong}, {-1}); + return signal; + } if (!nameStr.compare("eFromPsi2S")) { MCProng prong(2, {11, 100443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); signal = new MCSignal(name, "Electrons from psi2s decays", {prong}, {-1}); @@ -417,6 +512,48 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "Electrons from any open charm hadron decays", {prong}, {-1}); return signal; } + if (!nameStr.compare("eFromD0")) { + MCProng prong(2, {11, Pdg::kD0}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "Electrons from D0 decays", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("eFromChargedD")) { + MCProng prong(2, {11, Pdg::kDPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "Electrons from D+/- decays", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("eFromDs")) { + MCProng prong(2, {11, Pdg::kDS}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "Electrons from Ds +/- decays", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("eFromLambdaC")) { + MCProng prong(2, {11, Pdg::kLambdaCPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "Electrons from Lambda_c decays", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("eFromXiC0")) { + MCProng prong(2, {11, Pdg::kXiC0}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "Electrons from Xi_c_0 decays", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("eFromXiCPlus")) { + MCProng prong(2, {11, Pdg::kXiCPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "Electrons from Xi_c_+ decays", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("eFromXiCPlusPlus")) { + MCProng prong(2, {11, Pdg::kXiCCPlusPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "Electrons from Xi_c_++ decays", {prong}, {-1}); + return signal; + } if (!nameStr.compare("eFromHb")) { MCProng prong(2, {11, 502}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); prong.SetSourceBit(0, MCProng::kPhysicalPrimary); @@ -462,7 +599,7 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) if (!nameStr.compare("eFromPromptHc")) { MCProng prong(2, {11, 402}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); prong.SetSourceBit(0, MCProng::kPhysicalPrimary); - signal = new MCSignal(name, "Electrons from open charmed hadron decays", {prong}, {-1}); + signal = new MCSignal(name, "Electrons from open charmed hadron decays without beauty in decay history", {prong}, {-1}); return signal; } if (!nameStr.compare("eFromHbtoHc")) { @@ -471,6 +608,39 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "Electrons from open charmed hadron decays with b hadron in decay history", {prong}, {-1}); return signal; } + if (!nameStr.compare("eFromPromptLM")) { + MCProng prong(2, {11, 101}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502, 402}, {true, true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "Electrons from light mesons without B/D in decay history", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("eFromHbtoLM")) { + MCProng prong(2, {11, 101}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "Electrons from light mesons with B hadron in decay history", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("eFromHctoLM")) { + MCProng prong(2, {11, 101, 402}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "Electrons from light mesons from D hadron decays and no B in decay history", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("eFromUpsilon1S")) { + MCProng prong(2, {11, 553}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Electrons from Upsilon1S decays", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("eFromUpsilon2S")) { + MCProng prong(2, {11, 100553}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Electrons from Upsilon2S decays", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("eFromUpsilon3S")) { + MCProng prong(2, {11, 200553}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Electrons from Upsilon3S decays", {prong}, {-1}); + return signal; + } // muon signals with mother X: mu from mother X if (!nameStr.compare("muFromJpsi")) { @@ -483,6 +653,64 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "muons from psi2s decays", {prong}, {-1}); return signal; } + if (!nameStr.compare("muFromHb")) { + MCProng prong(2, {13, 502}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "muons from b->mu", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("muFromPromptHc")) { + MCProng prong(2, {13, 402}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "muons from c->mu, without beauty in decay history", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("muFromHbtoHc")) { + MCProng prong(3, {13, 402, 502}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "muons from b->c->mu", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("secondaryMuon")) { + MCProng prong(1); + prong.SetPDGcode(0, 13, true); + prong.SetSourceBit(0, MCProng::kProducedInTransport); + signal = new MCSignal(name, "muons produced during transport in detector", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("muFromPromptLM")) { + MCProng prong(2, {13, 101}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502, 402}, {true, true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "muons from light mesons without B/D in decay history", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("muFromHbtoLM")) { + MCProng prong(2, {13, 101}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "muons from light mesons with B hadron in decay history", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("muFromHctoLM")) { + MCProng prong(2, {13, 101, 402}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "muons from light mesons from D hadron decays and no B in decay history", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("muFromUpsilon1S")) { + MCProng prong(2, {13, 553}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "muons from Upsilon1S decays", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("muFromUpsilon2S")) { + MCProng prong(2, {13, 100553}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "muons from Upsilon2S decays", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("muFromUpsilon3S")) { + MCProng prong(2, {13, 200553}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "muons from Upsilon3S decays", {prong}, {-1}); + return signal; + } // Decay signal: Mother to electron: X -> e if (!nameStr.compare("AnythingToE")) { @@ -624,6 +852,20 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "ee pairs from j/psi decays", {prong, prong}, {1, 1}); // signal at pair level return signal; } + if (!nameStr.compare("eeFromJpsiExclusive")) { + MCProng prong(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from j/psi decays", {prong, prong}, {1, 1}); // signal at pair level + signal->SetDecayChannelIsExclusive(2, true); + return signal; + } + if (!nameStr.compare("eeFromJpsiNotExclusive")) { + MCProng prong(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from j/psi decays", {prong, prong}, {1, 1}); // signal at pair level + signal->SetDecayChannelIsNotExclusive(2, true); + return signal; + } if (!nameStr.compare("eePrimaryFromPromptJPsi")) { MCProng prong(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {true}); prong.SetSourceBit(0, MCProng::kPhysicalPrimary); @@ -652,6 +894,21 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "mumu pairs from psi2s decays", {prong, prong}, {1, 1}); // signal at pair level return signal; } + if (!nameStr.compare("mumuFromUpsilon1S")) { + MCProng prong(2, {13, 553}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "mumu pairs from upsilon1s decays", {prong, prong}, {1, 1}); // signal at pair level + return signal; + } + if (!nameStr.compare("mumuFromUpsilon2S")) { + MCProng prong(2, {13, 100553}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "mumu pairs from upsilon2s decays", {prong, prong}, {1, 1}); // signal at pair level + return signal; + } + if (!nameStr.compare("mumuFromUpsilon3S")) { + MCProng prong(2, {13, 200553}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "mumu pairs from upsilon3s decays", {prong, prong}, {1, 1}); // signal at pair level + return signal; + } if (!nameStr.compare("eeFromLMeeLFQ")) { MCProng prong(2, {11, 900}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); prong.SetSourceBit(0, MCProng::kPhysicalPrimary); @@ -678,6 +935,150 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) } // LMEE pair signals for HF + // D0->e and D0->e + if (!nameStr.compare("eeFromD0")) { + MCProng prong(2, {kElectron, Pdg::kD0}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from D0 decays, no beauty in history", {prong, prong}, {-1, -1}); + return signal; + } + + // D0->e and D0->e + if (!nameStr.compare("eeFromPi0FromD0")) { + MCProng prong(2, {kElectron, kPi0, Pdg::kD0}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from D0 to Pi0 decays, no beauty in history", {prong, prong}, {1, 1}); + return signal; + } + + // D+/- -> e and D+/- -> e + if (!nameStr.compare("eeFromChargedD")) { + MCProng prong(2, {kElectron, Pdg::kDPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from D+/- decays, no beauty in history", {prong, prong}, {-1, -1}); + return signal; + } + + // D0 -> e and D+/- -> e + if (!nameStr.compare("eeFromD0andChargedD")) { + MCProng prongD0(2, {kElectron, Pdg::kD0}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + MCProng prongDch(2, {kElectron, Pdg::kDPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prongD0.SetSourceBit(0, MCProng::kPhysicalPrimary); + prongDch.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "one e from D0 and one e from D+/- decays, no beauty in history", {prongD0, prongDch}, {-1, -1}); + return signal; + } + + // D+/- -> e and D0 -> e + if (!nameStr.compare("eeFromD0andChargedDBis")) { + MCProng prongD0(2, {kElectron, Pdg::kD0}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + MCProng prongDch(2, {kElectron, Pdg::kDPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prongD0.SetSourceBit(0, MCProng::kPhysicalPrimary); + prongDch.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "one e from D+/- and one e from D0 decays, no beauty in history (inverse signal)", {prongDch, prongD0}, {-1, -1}); + return signal; + } + + // D_s->e and D_s->e + if (!nameStr.compare("eeFromDs")) { + MCProng prong(2, {kElectron, Pdg::kDS}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from Ds +/- decays, no beauty in history", {prong, prong}, {-1, -1}); + return signal; + } + + // Lambda_c->e and Lambda_c->e + if (!nameStr.compare("eeFromLambdaC")) { + MCProng prong(2, {kElectron, Pdg::kLambdaCPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from Lambda_c, no beauty in history", {prong, prong}, {-1, -1}); + return signal; + } + + // Lambda_c->e and D0->e + if (!nameStr.compare("eeFromLambdaCandD0")) { + MCProng prongLc(2, {kElectron, Pdg::kLambdaCPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + MCProng prongD0(2, {kElectron, Pdg::kD0}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prongLc.SetSourceBit(0, MCProng::kPhysicalPrimary); + prongD0.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "one e from Lambda_c and one e from D0 decays, no beauty in history", {prongLc, prongD0}, {-1, -1}); + return signal; + } + + // D0->e and Lambda_c->e + if (!nameStr.compare("eeFromLambdaCandD0Bis")) { + MCProng prongLc(2, {kElectron, Pdg::kLambdaCPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + MCProng prongD0(2, {kElectron, Pdg::kD0}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prongLc.SetSourceBit(0, MCProng::kPhysicalPrimary); + prongD0.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "one e from Lambda_c and one e from D0 decays, no beauty in history (inverse signal)", {prongD0, prongLc}, {-1, -1}); + return signal; + } + + // Lambda_c->e and D+/- -> e + if (!nameStr.compare("eeFromLambdaCandChargedD")) { + MCProng prongLc(2, {kElectron, Pdg::kLambdaCPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + MCProng prongDch(2, {kElectron, Pdg::kDPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prongLc.SetSourceBit(0, MCProng::kPhysicalPrimary); + prongDch.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "one e from Lambda_c and one e from D+/- decays, no beauty in history", {prongLc, prongDch}, {-1, -1}); + return signal; + } + + // D+/- -> e and Lambda_c->e + if (!nameStr.compare("eeFromLambdaCandChargedDBis")) { + MCProng prongLc(2, {kElectron, Pdg::kLambdaCPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + MCProng prongDch(2, {kElectron, Pdg::kDPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prongLc.SetSourceBit(0, MCProng::kPhysicalPrimary); + prongDch.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "one e from Lambda_c and one e from D+/- decays, no beauty in history (inverse signal)", {prongDch, prongLc}, {-1, -1}); + return signal; + } + + // Xic0 ->e and Xic0 ->e + if (!nameStr.compare("eeFromXiC0")) { + MCProng prong(2, {kElectron, Pdg::kXiC0}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from Xi_c0, no beauty in history", {prong, prong}, {-1, -1}); + return signal; + } + + // Xi_c+ ->e and Xi_c+ ->e + if (!nameStr.compare("eeFromXiCPlus")) { + MCProng prong(2, {kElectron, Pdg::kXiCPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from Xi_c+, no beauty in history", {prong, prong}, {-1, -1}); + return signal; + } + + // Xi_c0 ->e and Xi_c+ ->e + if (!nameStr.compare("eeFromXiC0andXiCPlus")) { + MCProng prongXiCPlus(2, {kElectron, Pdg::kXiCPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + MCProng prongXiC0(2, {kElectron, Pdg::kXiC0}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prongXiCPlus.SetSourceBit(0, MCProng::kPhysicalPrimary); + prongXiC0.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "one e from Xi_c+ and one e from Xi_c0 decays, no beauty in history", {prongXiCPlus, prongXiC0}, {-1, -1}); + return signal; + } + + // Xi_c+ ->e and Xi_c0 ->e + if (!nameStr.compare("eeFromXiC0andXiCPlusBis")) { + MCProng prongXiCPlus(2, {kElectron, Pdg::kXiCPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + MCProng prongXiC0(2, {kElectron, Pdg::kXiC0}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prongXiCPlus.SetSourceBit(0, MCProng::kPhysicalPrimary); + prongXiC0.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "one e from Xi_c+ and one e from Xi_c0 decays, no beauty in history (inverse signal)", {prongXiC0, prongXiCPlus}, {-1, -1}); + return signal; + } + + // Xi_cc++ ->e and Xi_cc++ ->e + if (!nameStr.compare("eeFromXiCPlusPlus")) { + MCProng prong(2, {kElectron, Pdg::kXiCCPlusPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from Xi_cc++, no beauty in history", {prong, prong}, {-1, -1}); + return signal; + } + // c->e and c->e (no check) if (!nameStr.compare("eeFromCCNoCheck")) { MCProng prong(2, {11, 402}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); @@ -703,33 +1104,108 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) } // Any b to any c in history b -> c -> e - if (!nameStr.compare("eeFromBtoCandBtoC")) { + if (!nameStr.compare("eeFromAnyBtoCandAnyBtoC")) { MCProng prong(2, {11, 402}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {false}); // check if mother pdg code is in history prong.SetSourceBit(0, MCProng::kPhysicalPrimary); signal = new MCSignal(name, "ee pairs with any beauty to charm in decay chain", {prong, prong}, {-1, -1}); // signal at pair level return signal; } - // Any b->e and Any b->c->e - if (!nameStr.compare("eeFromBandBtoC")) { - MCProng prongB(2, {11, 502}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); // check if mother pdg code is in history + // b->c->e, b->c->e + if (!nameStr.compare("eeFromBtoCandBtoC")) { + MCProng prong(3, {11, 402, 502}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}, false); // check if mother pdg code is in history + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs with any beauty to charm in decay chain", {prong, prong}, {-1, -1}); // signal at pair level + return signal; + } + + // Any b->e and Any b->X->c->e + // Looking at such decays: B -> (e) D -> (e)e and bar{B} -> e + // Signal allows combinations of ee from the same B meson + // + the combination of e fom B and e from bar{B} + if (!nameStr.compare("eeFromBandAnyBtoC")) { + MCProng prongB(2, {11, 502}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); prongB.SetSourceBit(0, MCProng::kPhysicalPrimary); MCProng prongBtoC(2, {11, 402}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {false}); // check if mother pdg code is in history prongBtoC.SetSourceBit(0, MCProng::kPhysicalPrimary); - signal = new MCSignal(name, "ee pairs from b->e and b->c->e", {prongB, prongBtoC}, {-1, -1}); // signal at pair level + signal = new MCSignal(name, "ee pairs from b->e and b->X->c->e", {prongB, prongBtoC}, {-1, -1}); // signal at pair level return signal; } - // Any b->e and Any b->c->e - if (!nameStr.compare("eeFromBandBtoCBis")) { - MCProng prongB(2, {11, 502}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); // check if mother pdg code is in history + // Any b->e and Any b->X->c->e + if (!nameStr.compare("eeFromBandAnyBtoCBis")) { + MCProng prongB(2, {11, 502}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); prongB.SetSourceBit(0, MCProng::kPhysicalPrimary); MCProng prongBtoC(2, {11, 402}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {false}); // check if mother pdg code is in history prongBtoC.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from b->X->c->e and b->e", {prongBtoC, prongB}, {-1, -1}); // signal at pair level + return signal; + } + + // b->e and b->c->e + if (!nameStr.compare("eeFromBandBtoC")) { + MCProng prongB(2, {11, 502}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prongB.SetSourceBit(0, MCProng::kPhysicalPrimary); + MCProng prongBtoC(3, {11, 402, 502}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}, false); // check if mother pdg code is in history + prongBtoC.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "direkt ee pairs from b->e and b->c->e", {prongB, prongBtoC}, {-1, -1}); // signal at pair level + return signal; + } + + // b->e and b->c->e + if (!nameStr.compare("eeFromBandBtoCBis")) { + MCProng prongB(2, {11, 502}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prongB.SetSourceBit(0, MCProng::kPhysicalPrimary); + MCProng prongBtoC(3, {11, 402, 502}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}, false); // check if mother pdg code is in history + prongBtoC.SetSourceBit(0, MCProng::kPhysicalPrimary); signal = new MCSignal(name, "ee pairs from b->c->e and b->e", {prongBtoC, prongB}, {-1, -1}); // signal at pair level return signal; } + // b->e and b->c->e (same mother/grandmother) + // require that the mother is the grandmother of the other electron + if (!nameStr.compare("eeFromBandBtoCsameGM")) { + MCProng prongB(2, {11, 502}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prongB.SetSourceBit(0, MCProng::kPhysicalPrimary); + MCProng prongBtoC(3, {11, 402, 502}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}, false); // check if mother pdg code is in history + prongBtoC.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from b->e and b->c->e, mother = grandmother", {prongB, prongBtoC}, {1, 2}, false); // signal at pair level, accept commonAncestor Pairs + return signal; + } + + // b->e and b->c->e (same mother/grandmother) + // require that the mother is the grandmother of the other electron + if (!nameStr.compare("eeFromBandBtoCsameGMBis")) { + MCProng prongB(2, {11, 502}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prongB.SetSourceBit(0, MCProng::kPhysicalPrimary); + MCProng prongBtoC(3, {11, 402, 502}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}, false); // check if mother pdg code is in history + prongBtoC.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from b->c->e and b->e, mother = grandmother", {prongBtoC, prongB}, {2, 1}, false); // signal at pair level, accept commonAncestor Pairs + return signal; + } + + // b->e and b->c->e (different mother/grandmother) + // require that the mother is not the grandmother of the other electron + if (!nameStr.compare("eeFromBandBtoCdiffGM")) { + MCProng prongB(2, {11, 502}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prongB.SetSourceBit(0, MCProng::kPhysicalPrimary); + MCProng prongBtoC(3, {11, 402, 502}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}, false); // check if mother pdg code is in history + prongBtoC.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from b->e and b->c->e, mother != grandmother", {prongB, prongBtoC}, {1, 2}, true); // signal at pair level, exclude commonAncestor Pairs + return signal; + } + + // b->e and b->c->e (different mother/grandmother) + // require that the mother is not the grandmother of the other electron + if (!nameStr.compare("eeFromBandBtoCdiffGMBis")) { + MCProng prongB(2, {11, 502}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prongB.SetSourceBit(0, MCProng::kPhysicalPrimary); + MCProng prongBtoC(3, {11, 402, 502}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}, false); // check if mother pdg code is in history + prongBtoC.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from b->c->e and b->e, mother != grandmother", {prongBtoC, prongB}, {2, 1}, true); // signal at pair level, exclude commonAncestor Pairs + return signal; + } + // b->e and b->e if (!nameStr.compare("eeFromBB")) { MCProng prong(2, {11, 502}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); @@ -738,6 +1214,14 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) return signal; } + // b->e and b->e (commonAncestors) + if (!nameStr.compare("eeFromSameB")) { + MCProng prong(2, {11, 502}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from b->e and b->e", {prong, prong}, {1, 1}); // signal at pair level + return signal; + } + // b->e and c->e no check if (!nameStr.compare("eeFromBandFromC")) { MCProng prongB(2, {11, 502}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); @@ -776,6 +1260,33 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) return signal; } + if (!nameStr.compare("kaonFromBplusHistory")) { + MCProng prong(1, {321}, {true}, {false}, {0}, {0}, {false}, false, {521}, {false}); + signal = new MCSignal(name, "Kaons from B+ decays", {prong}, {-1}); + return signal; + } + + if (!nameStr.compare("kaonPrimaryFromBplusHistory")) { + MCProng prong(1, {321}, {true}, {false}, {0}, {0}, {false}, false, {521}, {false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "Kaons from B+ decays", {prong}, {-1}); + return signal; + } + + if (!nameStr.compare("kaonPrimaryFromBplusFS")) { + MCProng prong(2, {321, 521}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + prong.SetSourceBit(1, MCProng::kHEPMCFinalState); + signal = new MCSignal(name, "Kaons from B+ decays", {prong}, {-1}); + return signal; + } + + if (!nameStr.compare("kaonFromAnyBHistory")) { + MCProng prong(1, {321}, {true}, {false}, {0}, {0}, {false}, false, {503}, {false}); + signal = new MCSignal(name, "Kaons from B+ decays", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("JpsiFromBplus")) { MCProng prong(2, {443, 521}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); signal = new MCSignal(name, "Jpsi from B+ decays", {prong}, {1}); @@ -788,6 +1299,18 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) return signal; } + if (!nameStr.compare("electronFromJpsiFromBplus")) { + MCProng prong(3, {11, 443, 521}, {false, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + signal = new MCSignal(name, "Electrons from Jpsi from B+ decays", {prong}, {1}); + return signal; + } + + if (!nameStr.compare("positronFromJpsiFromBplus")) { + MCProng prong(3, {-11, 443, 521}, {false, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + signal = new MCSignal(name, "Positrons from Jpsi from B+ decays", {prong}, {1}); + return signal; + } + if (!nameStr.compare("eeFromJpsiFromBplus")) { MCProng prong(3, {11, 443, 521}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); signal = new MCSignal(name, "Electron pair from Jpsi from B+ decays", {prong, prong}, {1, 1}); @@ -801,12 +1324,124 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) return signal; } + if (!nameStr.compare("eeFromJpsiKaonAny")) { + MCProng pronge(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + MCProng prongKaon(1, {321}, {true}, {false}, {0}, {0}, {false}); + signal = new MCSignal(name, "Kaon and electron pair", {pronge, pronge, prongKaon}, {-1, -1, -1}); + return signal; + } + + if (!nameStr.compare("eeKaonFromBplusExclusive")) { + MCProng pronge(3, {11, 443, 521}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongKaon(2, {321, 521}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Kaon and electron pair from B+", {pronge, pronge, prongKaon}, {2, 2, 1}); + signal->SetDecayChannelIsExclusive(2, true); + return signal; + } + + if (!nameStr.compare("eeKaonFromBplusNotExclusive")) { + MCProng pronge(3, {11, 443, 521}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongKaon(2, {321, 521}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Kaon and electron pair from B+", {pronge, pronge, prongKaon}, {2, 2, 1}); + signal->SetDecayChannelIsNotExclusive(2, true); + return signal; + } + + // correlated background + if (!nameStr.compare("eePionFromBplus")) { + MCProng pronge(3, {11, 443, 521}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongPion(2, {211, 521}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Pion and electron pair from B+", {pronge, pronge, prongPion}, {2, 2, 1}); + return signal; + } + + if (!nameStr.compare("eeKaonFromBplusViaEverything")) { + MCProng pronge(3, {11, 443, 521}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongKaon(3, {321, 0, 521}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + signal = new MCSignal(name, "Kaon and electron pair from B+ via everything", {pronge, pronge, prongKaon}, {2, 2, 2}); + return signal; + } + + if (!nameStr.compare("eeKaonFromB0")) { + MCProng pronge(3, {11, 443, 511}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongKaon(2, {321, 511}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Kaon and electron pair from B0", {pronge, pronge, prongKaon}, {2, 2, 1}); + return signal; + } + + if (!nameStr.compare("eePionFromB0ViaEverything")) { // catching feed-down for B0 + MCProng pronge(3, {11, 443, 511}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongPion(3, {211, 0, 511}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + signal = new MCSignal(name, "Pion and electron pair from B0", {pronge, pronge, prongPion}, {2, 2, 1}); + return signal; + } + + if (!nameStr.compare("eeKaonFromOpenBeautyMesons")) { + MCProng pronge(3, {11, 443, 501}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongKaon(2, {321, 501}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Excited kaon and electron pair from B0", {pronge, pronge, prongKaon}, {2, 2, 2}); + return signal; + } + + if (!nameStr.compare("eeKaonFromOpenBeautyHadrons")) { + MCProng pronge(3, {11, 443, 502}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongKaon(2, {321, 502}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Kaon and electron pair from open beauty hadrons", {pronge, pronge, prongKaon}, {2, 2, 1}); + return signal; + } + + if (!nameStr.compare("eeKaonFromLambdaB")) { + MCProng pronge(3, {11, 443, 5122}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongKaon(2, {321, 5122}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Kaon and electron pair from lambda B", {pronge, pronge, prongKaon}, {2, 2, 1}); + return signal; + } + + if (!nameStr.compare("eeKaonPion0FromBplus")) { + MCProng pronge(3, {11, 443, 521}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongKaon(2, {321, 521}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + MCProng prongPion(2, {111, 521}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Kaon, pi0 and electron pair from B+", {pronge, pronge, prongKaon, prongPion}, {2, 2, 1, 1}); + return signal; + } + + if (!nameStr.compare("eeKaonEtaFromBplus")) { + MCProng pronge(3, {11, 443, 521}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongKaon(2, {321, 521}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + MCProng prongEta(2, {221, 521}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Kaon, eta and electron pair from B+", {pronge, pronge, prongKaon, prongEta}, {2, 2, 1, 1}); + return signal; + } + + if (!nameStr.compare("eeKaonOmegaFromBplus")) { + MCProng pronge(3, {11, 443, 521}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongKaon(2, {321, 521}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + MCProng prongOmega(2, {223, 521}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Kaon, omega and electron pair from B+", {pronge, pronge, prongKaon, prongOmega}, {2, 2, 1, 1}); + return signal; + } + + if (!nameStr.compare("eeKaonPionFromBplus")) { + MCProng pronge(3, {11, 443, 521}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongKaon(2, {321, 521}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + MCProng prongPion(2, {211, 521}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Kaon, pion and electron pair from B+", {pronge, pronge, prongKaon, prongPion}, {2, 2, 1, 1}); + return signal; + } + if (!nameStr.compare("Bplus")) { MCProng prong(1, {521}, {true}, {false}, {0}, {0}, {false}); signal = new MCSignal(name, "B+", {prong}, {-1}); return signal; } + if (!nameStr.compare("BplusFS")) { + MCProng prong(1, {521}, {true}, {false}, {0}, {0}, {false}); + prong.SetSourceBit(0, MCProng::kHEPMCFinalState); + signal = new MCSignal(name, "B+", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("beautyPairs")) { MCProng prong(1, {503}, {true}, {false}, {0}, {0}, {false}); signal = new MCSignal("beautyPairs", "Beauty hadron pair", {prong, prong}, {-1, -1}); @@ -829,6 +1464,126 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) return signal; } + //------------------------------------------------------------------------------------ + + if (!nameStr.compare("D0")) { + MCProng prong(1, {Pdg::kD0}, {true}, {false}, {0}, {0}, {false}); + signal = new MCSignal(name, "D0", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("KPiFromD0")) { + MCProng prongKaon(2, {321, Pdg::kD0}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + MCProng prongPion(2, {211, Pdg::kD0}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Kaon and pion pair from D0", {prongKaon, prongPion}, {1, 1}); + return signal; + } + if (!nameStr.compare("Dcharged")) { + MCProng prong(1, {Pdg::kDPlus}, {true}, {false}, {0}, {0}, {false}); + signal = new MCSignal(name, "D+/-", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("Dplus")) { + MCProng prong(1, {Pdg::kDPlus}, {false}, {false}, {0}, {0}, {false}); + signal = new MCSignal(name, "D+", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("Dminus")) { + MCProng prong(1, {-Pdg::kDPlus}, {false}, {false}, {0}, {0}, {false}); + signal = new MCSignal(name, "D+", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("KPiPiFromDcharged")) { + MCProng prongKaon(2, {321, Pdg::kDPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + MCProng prongPion(2, {211, Pdg::kDPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Kaon pion pion triplet from D+/-", {prongKaon, prongPion, prongPion}, {1, 1, 1}); + return signal; + } + if (!nameStr.compare("KPiPiFromDplus")) { + MCProng prongKaon(2, {-321, Pdg::kDPlus}, {false, false}, {false, false}, {0, 0}, {0, 0}, {false, false}); + MCProng prongPion(2, {211, Pdg::kDPlus}, {false, false}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Kaon pion pion triplet from D+", {prongKaon, prongPion, prongPion}, {1, 1, 1}); + return signal; + } + if (!nameStr.compare("KPiPiFromDminus")) { + MCProng prongKaon(2, {321, -Pdg::kDPlus}, {false, false}, {false, false}, {0, 0}, {0, 0}, {false, false}); + MCProng prongPion(2, {-211, -Pdg::kDPlus}, {false, false}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Kaon pion pion triplet from D-", {prongKaon, prongPion, prongPion}, {1, 1, 1}); + return signal; + } + if (!nameStr.compare("Dstar")) { + MCProng prong(1, {Pdg::kDStar}, {true}, {false}, {0}, {0}, {false}); + signal = new MCSignal(name, "D*", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("DstarPlus")) { + MCProng prong(1, {Pdg::kDStar}, {false}, {false}, {0}, {0}, {false}); + signal = new MCSignal(name, "D*+", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("DstarMinus")) { + MCProng prong(1, {-Pdg::kDStar}, {false}, {false}, {0}, {0}, {false}); + signal = new MCSignal(name, "D*-", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("pionFromDstar")) { + MCProng prong(2, {211, Pdg::kDStar}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Pions from D* decays", {prong}, {1}); + return signal; + } + if (!nameStr.compare("D0FromDstar")) { + MCProng prong(2, {Pdg::kD0, Pdg::kDStar}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "D0 from D* decays", {prong}, {1}); + return signal; + } + if (!nameStr.compare("KFromD0FromDstar")) { + MCProng prong(3, {321, Pdg::kD0, Pdg::kDStar}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + signal = new MCSignal(name, "Kaons from D0 from D* decays", {prong}, {1}); + return signal; + } + if (!nameStr.compare("PiFromD0FromDstar")) { + MCProng prong(3, {211, Pdg::kD0, Pdg::kDStar}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + signal = new MCSignal(name, "Pions from D0 from D* decays", {prong}, {1}); + return signal; + } + if (!nameStr.compare("KPiFromD0FromDstar")) { + MCProng prongKaon(3, {321, Pdg::kD0, Pdg::kDStar}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongPion(3, {321, Pdg::kD0, Pdg::kDStar}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + signal = new MCSignal(name, "Kaon and pion pair from D0 from D* decay", {prongKaon, prongPion}, {1, 1}); + return signal; + } + if (!nameStr.compare("KPiPiFromD0FromDstar")) { + MCProng prongKaon(3, {321, Pdg::kD0, Pdg::kDStar}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongPionSecondary(3, {211, Pdg::kD0, Pdg::kDStar}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongPion(2, {211, Pdg::kDStar}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Kaon pion pion triplet from D*", {prongKaon, prongPionSecondary, prongPion}, {2, 2, 1}); + return signal; + } + if (!nameStr.compare("KPiPiFromD0FromDstarPlus")) { + MCProng prongKaon(3, {-321, Pdg::kD0, Pdg::kDStar}, {false, false, false}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongPionSecondary(3, {211, Pdg::kD0, Pdg::kDStar}, {false, false, false}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongPion(2, {211, Pdg::kDStar}, {false, false}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Kaon pion pion triplet from D*+", {prongKaon, prongPionSecondary, prongPion}, {2, 2, 1}); + return signal; + } + if (!nameStr.compare("KPiPiFromD0FromDstarMinus")) { + MCProng prongKaon(3, {321, Pdg::kD0, Pdg::kDStar}, {false, false, false}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongPionSecondary(3, {-211, Pdg::kD0, Pdg::kDStar}, {false, false, false}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongPion(2, {-211, Pdg::kDStar}, {false, false}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Kaon pion pion triplet from D*-", {prongKaon, prongPionSecondary, prongPion}, {2, 2, 1}); + return signal; + } + if (!nameStr.compare("KFromDplus")) { + MCProng prong(2, {321, Pdg::kDPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "Kaons from D+/- decays", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("LambdaC")) { + MCProng prong(1, {Pdg::kLambdaCPlus}, {true}, {false}, {0}, {0}, {false}); + signal = new MCSignal(name, "Lambda_c", {prong}, {-1}); + return signal; + } + //-------------------------------------------------------------------------------- if (!nameStr.compare("JpsiFromChic0")) { @@ -969,5 +1724,504 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "Photon and electron pair from Pi0", {pronge, pronge, prongPhoton}, {1, 1, 1}); return signal; } + + //-------------------------------------------------------------------------------- + + if (!nameStr.compare("X3872")) { + MCProng prong(1, {9920443}, {true}, {false}, {0}, {0}, {false}); + signal = new MCSignal(name, "Inclusive X(3872)", {prong}, {-1}); + return signal; + } + + if (!nameStr.compare("JpsiFromX3872")) { + MCProng prong(1, {443}, {true}, {false}, {0}, {0}, {false}, false, {9920443}, {false}); + signal = new MCSignal(name, "Jpsi from X3872", {prong}, {-1}); + return signal; + } + + if (!nameStr.compare("eFromX3872")) { + MCProng prong(3, {11, 443, 9920443}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + signal = new MCSignal(name, "Electron from Jpsi from X3872", {prong}, {1}); + return signal; + } + + if (!nameStr.compare("PionFromX3872")) { + MCProng prong(1, {211}, {true}, {false}, {0}, {0}, {false}, false, {9920443}, {false}); + signal = new MCSignal(name, "Pion from Jpsi from X3872", {prong}, {-1}); + return signal; + } + + if (!nameStr.compare("JpsiFromPsi2S")) { + MCProng prong(1, {443}, {true}, {false}, {0}, {0}, {false}, false, {100443}, {false}); + signal = new MCSignal(name, "Jpsi from Psi2S", {prong}, {-1}); + return signal; + } + + if (!nameStr.compare("eFromPsi2S")) { + MCProng prong(3, {11, 443, 100443}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + signal = new MCSignal(name, "Electron from Jpsi from Psi2S", {prong}, {1}); + return signal; + } + + if (!nameStr.compare("PionFromPsi2S")) { + MCProng prong(1, {211}, {true}, {false}, {0}, {0}, {false}, false, {100443}, {false}); + signal = new MCSignal(name, "Pion from Jpsi from Psi2S", {prong}, {-1}); + return signal; + } + + if (!nameStr.compare("eeFromJpsiFromX3872")) { + MCProng prong(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {9920443}, {false}); + signal = new MCSignal(name, "Electron pair from Jpsi from X3872", {prong, prong}, {1, 1}); + return signal; + } + + if (!nameStr.compare("JpsiPiPiFromX3872")) { + MCProng prongJpsi(2, {443, 9920443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + MCProng prongPi(2, {211, 9920443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Jpsi and pion pair from X3872", {prongJpsi, prongPi, prongPi}, {1, 1, 1}); + return signal; + } + + if (!nameStr.compare("eePiPiFromX3872")) { + MCProng pronge(3, {11, 443, 9920443}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongPi(2, {211, 9920443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Electron pair and pion pair from X3872", {pronge, pronge, prongPi, prongPi}, {2, 2, 1, 1}); + return signal; + } + + if (!nameStr.compare("eeFromJpsiFromPsi2S")) { + MCProng prong(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {100443}, {false}); + signal = new MCSignal(name, "Electron pair from Jpsi from Psi2S", {prong, prong}, {1, 1}); + return signal; + } + + if (!nameStr.compare("JpsiPiPiFromPsi2S")) { + MCProng prongJpsi(2, {443, 100443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + MCProng prongPi(2, {211, 100443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Jpsi and pion pair from Psi2S", {prongJpsi, prongPi, prongPi}, {1, 1, 1}); + return signal; + } + + if (!nameStr.compare("eePiPiFromPsi2S")) { + MCProng pronge(3, {11, 443, 100443}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prongPi(2, {211, 100443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Electron pair and pion pair from Psi2S", {pronge, pronge, prongPi, prongPi}, {2, 2, 1, 1}); + return signal; + } return nullptr; } + +//_______________________________________________________________________________________________ +std::vector o2::aod::dqmcsignals::GetMCSignalsFromJSON(const char* json) +{ + // + // configure MC signals using a json file + // + std::vector signals; + LOG(info) << "========================================== interpreting JSON for MC signals"; + LOG(info) << "JSON string: " << json; + // + // Create a vector of MCSignal from a JSON formatted string + // The JSON is expected to contain a list of objects, with each object containing the fields needed + // to define an MCSignal + rapidjson::Document document; + + // Check that the json is parsed correctly + rapidjson::ParseResult ok = document.Parse(json); + if (!ok) { + TString str = ""; + for (int i = ok.Offset() - 30; i < static_cast(ok.Offset()) + 50; i++) { + if ((i >= 0) && (i < static_cast(strlen(json)))) { + str += json[i]; + } + } + LOG(fatal) << "JSON parse error: " << rapidjson::GetParseErrorFunc(ok.Code()) << " (" << ok.Offset() << ")" << " **** Parsing error is somewhere here: " << str.Data(); + return signals; + } + + // loop over the top level objects in the json + for (rapidjson::Value::ConstMemberIterator it = document.MemberBegin(); it != document.MemberEnd(); it++) { + + const char* sigName = it->name.GetString(); + LOG(info) << "=================================================== Configuring MC signal " << sigName; + const auto& signal = it->value; + + // Validate the entry for this MCSignal + if (!ValidateJSONMCSignal(&signal, sigName)) { + LOG(fatal) << "MCSignal JSON not properly defined for " << sigName << ". Skipping"; + continue; + } else { + LOG(debug) << "MCSignal validated"; + } + + // Get the signal title + const char* title = (signal.HasMember("title") ? signal.FindMember("title")->value.GetString() : ""); + LOG(info) << "Title is: " << title; + + // Get the exclude common ancestor + bool excludeCommonAncestor = false; + if (signal.HasMember("excludeCommonAncestor")) { + excludeCommonAncestor = signal.FindMember("excludeCommonAncestor")->value.GetBool(); + } + LOG(debug) << "exclude common ancestor " << excludeCommonAncestor; + + // Check for MCProng objects in the json + std::vector prongs; + for (rapidjson::Value::ConstMemberIterator prongIt = signal.MemberBegin(); prongIt != signal.MemberEnd(); prongIt++) { + + // If the name is not MCProng, continue + TString prongName = prongIt->name.GetString(); + if (!prongName.Contains("MCProng")) { + continue; + } + + // Call the function to parse the MCProng object and get the pointer to the created MCProng + MCProng* prong = ParseJSONMCProng(&prongIt->value, prongName.Data()); + if (prong == nullptr) { + LOG(fatal) << "MCProng not built! MCSignal not configured"; + return signals; + } + LOG(debug) << "MCProng defined"; + // Print the contents of the configured prong + prong->Print(); + // push the prong to the vector + prongs.push_back(*prong); + } + + // Get the common ancestors array + std::vector commonAncestors; + if (signal.HasMember("commonAncestors")) { + for (auto& v : signal.FindMember("commonAncestors")->value.GetArray()) { + commonAncestors.push_back(v.GetInt()); + LOG(debug) << "common ancestor " << v.GetInt(); + } + } else { + for (uint32_t i = 0; i < prongs.size(); i++) { + commonAncestors.push_back(-1); + } + } + + if (prongs.size() == 0) { + LOG(fatal) << "No prongs were defined for this MCSignal!"; + return signals; + } + + // Check that we have as many prongs defined as the size of the common ancestors array + if (prongs.size() != commonAncestors.size()) { + LOG(fatal) << "Number of defined prongs and size of commonAncestors array must coincide in MCSignal definition"; + return signals; + } + + // Create the signal and add it to the output vector + MCSignal* mcSignal = new MCSignal(sigName, title, prongs, commonAncestors, excludeCommonAncestor); + LOG(debug) << "MCSignal defined, adding to the output vector"; + mcSignal->PrintConfig(); + signals.push_back(mcSignal); + } + + return signals; +} + +//_______________________________________________________________________________________________ +template +bool o2::aod::dqmcsignals::ValidateJSONMCProng(T prongJSON, const char* prongName) +{ + + // Check that the json entry for this prong is correctly given + LOG(debug) << "Validating the prong " << prongName; + + // The fields for the number of generations, pdg codes and checkBothCharges are required + if (!prongJSON->HasMember("n") || !prongJSON->HasMember("pdgs") || !prongJSON->HasMember("checkBothCharges")) { + LOG(fatal) << "Missing either n, pdgs or checkBothCharges fields in MCProng JSON definition"; + return false; + } + // the size of the pdgs array must be equal to n + int n = prongJSON->FindMember("n")->value.GetInt(); + uint32_t nSigned = static_cast(n); + if (prongJSON->FindMember("pdgs")->value.GetArray().Size() != nSigned) { + LOG(fatal) << "Size of the pdgs array must be equal to n in MCProng JSON definition"; + return false; + } + // the size of the checkBothCharges array must be equal to n + if (prongJSON->FindMember("checkBothCharges")->value.GetArray().Size() != nSigned) { + LOG(fatal) << "Size of the checkBothCharges array must be equal to n in MCProng JSON definition"; + return false; + } + // the size of the exclude pdg array must be equal to n + if (prongJSON->HasMember("excludePDG")) { + if (prongJSON->FindMember("excludePDG")->value.GetArray().Size() != nSigned) { + LOG(fatal) << "Size of the excludePDG array must be equal to n in MCProng JSON definition"; + return false; + } + } + + // Check the corectness of the source bits fields, if these are specified + // The sourceBits field should be an array of size n, with each element being another array containing an array of sources specified as strings + // The source strings have to be the ones specified in MCProng::Source + // If the excludeSource is specified in addition, then this field should be an array of size n, with each element being another array of booleans + // corresponding to each source specified in sourceBits + if (prongJSON->HasMember("sourceBits")) { + if (prongJSON->FindMember("sourceBits")->value.GetArray().Size() != nSigned) { + LOG(fatal) << "Size of the sourceBits array must be equal to n in MCProng JSON definition"; + return false; + } + std::vector nSourceBits; + for (auto& ii : prongJSON->FindMember("sourceBits")->value.GetArray()) { + if (!ii.IsArray()) { + LOG(fatal) << "The sourceBits field should be an array of arrays of MCProng::Source"; + return false; + } + nSourceBits.push_back(ii.GetArray().Size()); + for (auto& iii : ii.GetArray()) { + if (MCProng::fgSourceNames.find(iii.GetString()) == MCProng::fgSourceNames.end()) { + LOG(fatal) << "Source " << iii.GetString() << " not implemented in MCProng"; + return false; + } + } + } + if (prongJSON->HasMember("excludeSource")) { + if (prongJSON->FindMember("excludeSource")->value.GetArray().Size() != nSigned) { + LOG(fatal) << "Size of the excludeSource array must be equal to n in MCProng JSON definition"; + return false; + } + int iElem = 0; + for (auto& ii : prongJSON->FindMember("excludeSource")->value.GetArray()) { + if (!ii.IsArray()) { + LOG(fatal) << "The excludeSource field should be an array of arrays of bool"; + return false; + } + if (ii.GetArray().Size() != nSourceBits[iElem]) { + LOG(fatal) << "The size of excludeSource arrays does not match the size of the arrays in sourceBits"; + return false; + } + iElem++; + } + } + // Check the useAND on source bit map + if (prongJSON->HasMember("useANDonSourceBitMap")) { + if (prongJSON->FindMember("useANDonSourceBitMap")->value.GetArray().Size() != nSigned) { + LOG(fatal) << "Size of the useANDonSourceBitMap array must be equal to n in MCProng JSON definition"; + return false; + } + } + } + + // sourceBits is needed in case the other source related fields are specified + if ((prongJSON->HasMember("excludeSource") || prongJSON->HasMember("useANDonSourceBitMap")) && !prongJSON->HasMember("sourceBits")) { + LOG(fatal) << "Field sourceBits is needed when specifying excludeSource or useANDonSourceBitMap"; + return false; + } + + // check checkGenerationsInTime + if (prongJSON->HasMember("checkGenerationsInTime")) { + if (!prongJSON->FindMember("checkGenerationsInTime")->value.IsBool()) { + LOG(fatal) << "Field checkGeneretionsInTime must be boolean"; + return false; + } + } + + if (prongJSON->HasMember("checkIfPDGInHistory")) { + if (!prongJSON->FindMember("checkIfPDGInHistory")->value.IsArray()) { + LOG(fatal) << "Field checkGeneretionsInTime must be an array of integers"; + return false; + } + uint32_t vecSize = prongJSON->FindMember("checkIfPDGInHistory")->value.GetArray().Size(); + if (prongJSON->HasMember("excludePDGInHistory")) { + if (!prongJSON->FindMember("excludePDGInHistory")->value.IsArray()) { + LOG(fatal) << "Field excludePDGInHistory must be an array of booleans"; + return false; + } + if (prongJSON->FindMember("excludePDGInHistory")->value.GetArray().Size() != vecSize) { + LOG(fatal) << "Field excludePDGInHistory must be an array of equal size with the array specified by checkIfPDGInHistory"; + return false; + } + } + } else { + if (prongJSON->HasMember("excludePDGInHistory")) { + LOG(fatal) << "Field checkIfPDGInHistory is required when excludePDGInHistory is specified"; + return false; + } + } + + return true; +} + +//_______________________________________________________________________________________________ +template +MCProng* o2::aod::dqmcsignals::ParseJSONMCProng(T prongJSON, const char* prongName) +{ + + // Check that the entry for this prong is validated + LOG(debug) << "Parsing the prong " << prongName; + if (!ValidateJSONMCProng(prongJSON, prongName)) { + LOG(fatal) << "MCProng not properly defined in the JSON file."; + return nullptr; + } + + // Get the number of generations + int n = prongJSON->FindMember("n")->value.GetInt(); + LOG(debug) << "n: " << n; + // Get the array of PDG codes + std::vector pdgs; + for (auto& pdg : prongJSON->FindMember("pdgs")->value.GetArray()) { + pdgs.push_back(pdg.GetInt()); + LOG(debug) << "pdgs: " << pdg.GetInt(); + } + // get the array of booleans for check both charges option + std::vector checkBothCharges; + for (auto& ii : prongJSON->FindMember("checkBothCharges")->value.GetArray()) { + checkBothCharges.push_back(ii.GetBool()); + LOG(debug) << "check both charges " << ii.GetBool(); + } + + // get the array of booleans for the excludePDG option, defaults to false + std::vector excludePDG; + if (prongJSON->HasMember("excludePDG")) { + for (auto& ii : prongJSON->FindMember("excludePDG")->value.GetArray()) { + excludePDG.push_back(ii.GetBool()); + LOG(debug) << "exclude pdg " << ii.GetBool(); + } + } else { + for (int i = 0; i < n; i++) { + excludePDG.push_back(false); + } + } + + // get the source bits, and transform from string to int + std::vector> sourceBitsVec; + if (prongJSON->HasMember("sourceBits")) { + for (auto& ii : prongJSON->FindMember("sourceBits")->value.GetArray()) { + std::vector sourceBits; + for (auto& iii : ii.GetArray()) { + sourceBits.push_back(MCProng::fgSourceNames[iii.GetString()]); + LOG(debug) << "source bit " << iii.GetString(); + } + sourceBitsVec.push_back(sourceBits); + } + } + // prepare the exclusion source options if specified + std::vector> excludeSourceVec; + if (prongJSON->HasMember("excludeSource")) { + for (auto& ii : prongJSON->FindMember("excludeSource")->value.GetArray()) { + std::vector excludeSource; + for (auto& iii : ii.GetArray()) { + excludeSource.push_back(iii.GetBool()); + LOG(debug) << "exclude source bit " << iii.GetBool(); + } + excludeSourceVec.push_back(excludeSource); + } + } + + // prepare the useANDonSourceBitMap vector, defaults to true for each generation + std::vector useANDonSourceBitMap; + if (prongJSON->HasMember("useANDonSourceBitMap")) { + for (auto& ii : prongJSON->FindMember("useANDonSourceBitMap")->value.GetArray()) { + useANDonSourceBitMap.push_back(ii.GetBool()); + LOG(debug) << "use AND on source map " << ii.GetBool(); + } + } else { + for (int i = 0; i < n; i++) { + useANDonSourceBitMap.push_back(true); + } + } + + // prepare the bit maps suitable for the MCProng constructor + bool hasExclude = prongJSON->HasMember("excludeSource"); + int igen = 0; + std::vector sBitsVec; + std::vector sBitsExcludeVec; + for (auto& itgen : sourceBitsVec) { + int is = 0; + uint64_t sBits = 0; + uint64_t sBitsExclude = 0; + auto excludeVec = (hasExclude ? excludeSourceVec[igen] : std::vector{}); + for (auto& s : itgen) { + bool exclude = (hasExclude ? excludeVec[is] : false); + if (s != MCProng::kNothing) { + sBits |= (static_cast(1) << s); + if (exclude) { + sBitsExclude |= (static_cast(1) << s); + } + } + is++; + } + sBitsVec.push_back(sBits); + sBitsExcludeVec.push_back(sBitsExclude); + LOG(debug) << "igen " << igen; + LOG(debug) << "igen sBits " << sBits; + LOG(debug) << "igen exclude " << sBitsExclude; + igen++; + } + + // check that the sourceBits has the size of n generations + if (prongJSON->HasMember("sourceBits")) { + if (sBitsVec.size() != static_cast(n)) { + LOG(fatal) << "sourceBits array should have a size equal to n"; + } + } else { + sBitsVec.clear(); + for (int i = 0; i < n; i++) { + sBitsVec.push_back(0); + } + } + // check that the sourceBits exclude has the size of n generations + if (prongJSON->HasMember("excludeSource")) { + if (sBitsExcludeVec.size() != static_cast(n)) { + LOG(fatal) << "sourceBits exclude array should have a size equal to n"; + } + } else { + sBitsExcludeVec.clear(); + for (int i = 0; i < n; i++) { + sBitsExcludeVec.push_back(0); + } + } + + bool checkGenerationsInTime = false; + if (prongJSON->HasMember("checkGenerationsInTime")) { + checkGenerationsInTime = prongJSON->FindMember("checkGenerationsInTime")->value.GetBool(); + } + LOG(debug) << "checkGenerationsInTime: " << checkGenerationsInTime; + + std::vector checkIfPDGInHistory = {}; + if (prongJSON->HasMember("checkIfPDGInHistory")) { + for (auto& ii : prongJSON->FindMember("checkIfPDGInHistory")->value.GetArray()) { + checkIfPDGInHistory.push_back(ii.GetInt()); + LOG(debug) << "checkIfPDGInHistory: " << ii.GetInt(); + } + } + + std::vector excludePDGInHistory = {}; + if (prongJSON->HasMember("excludePDGInHistory")) { + for (auto& ii : prongJSON->FindMember("excludePDGInHistory")->value.GetArray()) { + excludePDGInHistory.push_back(ii.GetBool()); + LOG(debug) << "excludePDGInHistory: " << ii.GetBool(); + } + } + + // Calling the MCProng constructor + MCProng* prong = new MCProng(n, pdgs, checkBothCharges, excludePDG, sBitsVec, sBitsExcludeVec, useANDonSourceBitMap, + checkGenerationsInTime, checkIfPDGInHistory, excludePDGInHistory); + // Print the configuration + prong->Print(); + return prong; +} + +//_______________________________________________________________________________________________ +template +bool o2::aod::dqmcsignals::ValidateJSONMCSignal(T sigJSON, const char* sigName) +{ + + LOG(info) << "Validating MC signal " << sigName; + if (sigJSON->HasMember("commonAncestors")) { + if (!sigJSON->FindMember("commonAncestors")->value.IsArray()) { + LOG(fatal) << "In MCSignal definition, commonAncestors must be an array"; + return false; + } + } + if (sigJSON->HasMember("excludeCommonAncestor") && !sigJSON->HasMember("commonAncestors")) { + LOG(fatal) << "In MCSignal definition, commonAncestors field is needed if excludeCommonAncestor is specified"; + return false; + } + + return true; +} diff --git a/PWGDQ/Core/MCSignalLibrary.h b/PWGDQ/Core/MCSignalLibrary.h index a35ec9f31c9..df01f60c978 100644 --- a/PWGDQ/Core/MCSignalLibrary.h +++ b/PWGDQ/Core/MCSignalLibrary.h @@ -16,6 +16,7 @@ #define PWGDQ_CORE_MCSIGNALLIBRARY_H_ #include +#include "rapidjson/document.h" #include "PWGDQ/Core/MCProng.h" #include "PWGDQ/Core/MCSignal.h" @@ -24,6 +25,17 @@ namespace o2::aod namespace dqmcsignals { MCSignal* GetMCSignal(const char* signalName); + +std::vector GetMCSignalsFromJSON(const char* json); + +template +bool ValidateJSONMCSignal(T sigJSON, const char* sigName); + +template +MCProng* ParseJSONMCProng(T prongJSON, const char* prongName); + +template +bool ValidateJSONMCProng(T prongJSON, const char* prongName); } } // namespace o2::aod diff --git a/PWGDQ/Core/MixingLibrary.cxx b/PWGDQ/Core/MixingLibrary.cxx index def79789b3b..0682a224ad3 100644 --- a/PWGDQ/Core/MixingLibrary.cxx +++ b/PWGDQ/Core/MixingLibrary.cxx @@ -76,4 +76,84 @@ void o2::aod::dqmixing::SetUpMixing(MixingHandler* mh, const char* mixingVarible std::vector fZLimsHashing = {-10.0f, -7.5f, -5.0f, -2.5f, 0.0f, 2.5f, 5.0f, 7.5f, 10.0f}; mh->AddMixingVariable(VarManager::kVtxZ, fZLimsHashing.size(), fZLimsHashing); } + if (!nameStr.compare("Vtx4")) { + std::vector fZLimsHashing = {-10.0f, -8.0f, -6.0f, -4.0f, -2.0f, 0.0f, 2.0f, 4.0f, 6.0f, 8.0f, 10.0f}; + mh->AddMixingVariable(VarManager::kVtxZ, fZLimsHashing.size(), fZLimsHashing); + } + if (!nameStr.compare("Vtx5")) { + std::vector fZLimsHashing = {-10.0f, -9.0f, -8.0f, -7.0f, -6.0f, -5.0f, -4.0f, -3.0f, -2.0f, -1.0f, 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f}; + mh->AddMixingVariable(VarManager::kVtxZ, fZLimsHashing.size(), fZLimsHashing); + } + if (!nameStr.compare("Occupancy1")) { + std::vector fOccLimsHashing = {0.0f, 500.0f, 1000.0f, 2000.0f, 3000.0f, 6000.0f, 50000.0f}; + mh->AddMixingVariable(VarManager::kTrackOccupancyInTimeRange, fOccLimsHashing.size(), fOccLimsHashing); + } + if (!nameStr.compare("Occupancy2")) { + std::vector fOccLimsHashing = {0.0f, 250.0f, 500.0f, 750.0f, 1000.0f, 1500.0f, 2000.0f, 3000.0f, 6000.0f, 50000.0f}; + mh->AddMixingVariable(VarManager::kTrackOccupancyInTimeRange, fOccLimsHashing.size(), fOccLimsHashing); + } + if (!nameStr.compare("Occupancy3")) { + std::vector fOccLimsHashing = {0.0f, 250.0f, 500.0f, 750.0f, 1000.0f, 1500.0f, 2000.0f, 3000.0f, 4500.0f, 6000.0f, 8000.0f, 10000.0f, 50000.0f}; + mh->AddMixingVariable(VarManager::kTrackOccupancyInTimeRange, fOccLimsHashing.size(), fOccLimsHashing); + } + if (!nameStr.compare("Psi2A1")) { + std::vector fPsi2A = {-TMath::Pi() / 2., 0.0f, TMath::Pi() / 2.}; + mh->AddMixingVariable(VarManager::kPsi2A, fPsi2A.size(), fPsi2A); + } + if (!nameStr.compare("Psi2A2")) { + std::vector fPsi2A = {-TMath::Pi() / 2., -TMath::Pi() / 4., 0.0f, TMath::Pi() / 4., TMath::Pi() / 2.}; + mh->AddMixingVariable(VarManager::kPsi2A, fPsi2A.size(), fPsi2A); + } + if (!nameStr.compare("Psi2A3")) { + std::vector fPsi2A = {-4 * TMath::Pi() / 8., -3 * TMath::Pi() / 8., -2 * TMath::Pi() / 8., -TMath::Pi() / 8., 0.0f, TMath::Pi() / 8., 2 * TMath::Pi() / 8., 3 * TMath::Pi() / 8., 4 * TMath::Pi() / 8.}; + mh->AddMixingVariable(VarManager::kPsi2A, fPsi2A.size(), fPsi2A); + } + if (!nameStr.compare("Psi2A4")) { + std::vector fPsi2A = {-8 * TMath::Pi() / 16., -7 * TMath::Pi() / 16., -6 * TMath::Pi() / 16., -5 * TMath::Pi() / 16., -4 * TMath::Pi() / 16., -3 * TMath::Pi() / 16., -2 * TMath::Pi() / 16., -TMath::Pi() / 16., 0.0f, TMath::Pi() / 16., 2 * TMath::Pi() / 16., 3 * TMath::Pi() / 16., 4 * TMath::Pi() / 16., 5 * TMath::Pi() / 16., 6 * TMath::Pi() / 16., 7 * TMath::Pi() / 16., 8 * TMath::Pi() / 16.}; + mh->AddMixingVariable(VarManager::kPsi2A, fPsi2A.size(), fPsi2A); + } + if (!nameStr.compare("Psi2A5")) { + std::vector fPsi2A = {-12 * TMath::Pi() / 24., -11 * TMath::Pi() / 24., -10 * TMath::Pi() / 24., -9 * TMath::Pi() / 24., -8 * TMath::Pi() / 24., -7 * TMath::Pi() / 24., -6 * TMath::Pi() / 24., -5 * TMath::Pi() / 24., -4 * TMath::Pi() / 24., -3 * TMath::Pi() / 24., -2 * TMath::Pi() / 24., -TMath::Pi() / 24., 0.0f, TMath::Pi() / 24., 2 * TMath::Pi() / 24., 3 * TMath::Pi() / 24., 4 * TMath::Pi() / 24., 5 * TMath::Pi() / 24., 6 * TMath::Pi() / 24., 7 * TMath::Pi() / 24., 8 * TMath::Pi() / 24., 9 * TMath::Pi() / 24., 10 * TMath::Pi() / 24., 11 * TMath::Pi() / 24., 12 * TMath::Pi() / 24.}; + mh->AddMixingVariable(VarManager::kPsi2A, fPsi2A.size(), fPsi2A); + } + if (!nameStr.compare("Psi2B1")) { + std::vector fPsi2B = {-TMath::Pi() / 2., 0.0f, TMath::Pi() / 2.}; + mh->AddMixingVariable(VarManager::kPsi2B, fPsi2B.size(), fPsi2B); + } + if (!nameStr.compare("Psi2B2")) { + std::vector fPsi2B = {-TMath::Pi() / 2., -TMath::Pi() / 4., 0.0f, TMath::Pi() / 4., TMath::Pi() / 2.}; + mh->AddMixingVariable(VarManager::kPsi2B, fPsi2B.size(), fPsi2B); + } + if (!nameStr.compare("Psi2B3")) { + std::vector fPsi2B = {-4 * TMath::Pi() / 8., -3 * TMath::Pi() / 8., -2 * TMath::Pi() / 8., -TMath::Pi() / 8., 0.0f, TMath::Pi() / 8., 2 * TMath::Pi() / 8., 3 * TMath::Pi() / 8., 4 * TMath::Pi() / 8.}; + mh->AddMixingVariable(VarManager::kPsi2B, fPsi2B.size(), fPsi2B); + } + if (!nameStr.compare("Psi2B4")) { + std::vector fPsi2B = {-8 * TMath::Pi() / 16., -7 * TMath::Pi() / 16., -6 * TMath::Pi() / 16., -5 * TMath::Pi() / 16., -4 * TMath::Pi() / 16., -3 * TMath::Pi() / 16., -2 * TMath::Pi() / 16., -TMath::Pi() / 16., 0.0f, TMath::Pi() / 16., 2 * TMath::Pi() / 16., 3 * TMath::Pi() / 16., 4 * TMath::Pi() / 16., 5 * TMath::Pi() / 16., 6 * TMath::Pi() / 16., 7 * TMath::Pi() / 16., 8 * TMath::Pi() / 16.}; + mh->AddMixingVariable(VarManager::kPsi2B, fPsi2B.size(), fPsi2B); + } + if (!nameStr.compare("Psi2B5")) { + std::vector fPsi2B = {-12 * TMath::Pi() / 24., -11 * TMath::Pi() / 24., -10 * TMath::Pi() / 24., -9 * TMath::Pi() / 24., -8 * TMath::Pi() / 24., -7 * TMath::Pi() / 24., -6 * TMath::Pi() / 24., -5 * TMath::Pi() / 24., -4 * TMath::Pi() / 24., -3 * TMath::Pi() / 24., -2 * TMath::Pi() / 24., -TMath::Pi() / 24., 0.0f, TMath::Pi() / 24., 2 * TMath::Pi() / 24., 3 * TMath::Pi() / 24., 4 * TMath::Pi() / 24., 5 * TMath::Pi() / 24., 6 * TMath::Pi() / 24., 7 * TMath::Pi() / 24., 8 * TMath::Pi() / 24., 9 * TMath::Pi() / 24., 10 * TMath::Pi() / 24., 11 * TMath::Pi() / 24., 12 * TMath::Pi() / 24.}; + mh->AddMixingVariable(VarManager::kPsi2B, fPsi2B.size(), fPsi2B); + } + if (!nameStr.compare("Psi2C1")) { + std::vector fPsi2C = {-TMath::Pi() / 2., 0.0f, TMath::Pi() / 2.}; + mh->AddMixingVariable(VarManager::kPsi2C, fPsi2C.size(), fPsi2C); + } + if (!nameStr.compare("Psi2C2")) { + std::vector fPsi2C = {-TMath::Pi() / 2., -TMath::Pi() / 4., 0.0f, TMath::Pi() / 4., TMath::Pi() / 2.}; + mh->AddMixingVariable(VarManager::kPsi2C, fPsi2C.size(), fPsi2C); + } + if (!nameStr.compare("Psi2C3")) { + std::vector fPsi2C = {-4 * TMath::Pi() / 8., -3 * TMath::Pi() / 8., -2 * TMath::Pi() / 8., -TMath::Pi() / 8., 0.0f, TMath::Pi() / 8., 2 * TMath::Pi() / 8., 3 * TMath::Pi() / 8., 4 * TMath::Pi() / 8.}; + mh->AddMixingVariable(VarManager::kPsi2C, fPsi2C.size(), fPsi2C); + } + if (!nameStr.compare("Psi2C4")) { + std::vector fPsi2C = {-8 * TMath::Pi() / 16., -7 * TMath::Pi() / 16., -6 * TMath::Pi() / 16., -5 * TMath::Pi() / 16., -4 * TMath::Pi() / 16., -3 * TMath::Pi() / 16., -2 * TMath::Pi() / 16., -TMath::Pi() / 16., 0.0f, TMath::Pi() / 16., 2 * TMath::Pi() / 16., 3 * TMath::Pi() / 16., 4 * TMath::Pi() / 16., 5 * TMath::Pi() / 16., 6 * TMath::Pi() / 16., 7 * TMath::Pi() / 16., 8 * TMath::Pi() / 16.}; + mh->AddMixingVariable(VarManager::kPsi2C, fPsi2C.size(), fPsi2C); + } + if (!nameStr.compare("Psi2C5")) { + std::vector fPsi2C = {-12 * TMath::Pi() / 24., -11 * TMath::Pi() / 24., -10 * TMath::Pi() / 24., -9 * TMath::Pi() / 24., -8 * TMath::Pi() / 24., -7 * TMath::Pi() / 24., -6 * TMath::Pi() / 24., -5 * TMath::Pi() / 24., -4 * TMath::Pi() / 24., -3 * TMath::Pi() / 24., -2 * TMath::Pi() / 24., -TMath::Pi() / 24., 0.0f, TMath::Pi() / 24., 2 * TMath::Pi() / 24., 3 * TMath::Pi() / 24., 4 * TMath::Pi() / 24., 5 * TMath::Pi() / 24., 6 * TMath::Pi() / 24., 7 * TMath::Pi() / 24., 8 * TMath::Pi() / 24., 9 * TMath::Pi() / 24., 10 * TMath::Pi() / 24., 11 * TMath::Pi() / 24., 12 * TMath::Pi() / 24.}; + mh->AddMixingVariable(VarManager::kPsi2C, fPsi2C.size(), fPsi2C); + } } diff --git a/PWGDQ/Core/VarManager.cxx b/PWGDQ/Core/VarManager.cxx index 8231ec6858b..f9a71a28c9b 100644 --- a/PWGDQ/Core/VarManager.cxx +++ b/PWGDQ/Core/VarManager.cxx @@ -9,6 +9,9 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include +#include +#include +#include #include "PWGDQ/Core/VarManager.h" #include "Tools/KFparticle/KFUtilities.h" @@ -20,6 +23,7 @@ ClassImp(VarManager); TString VarManager::fgVariableNames[VarManager::kNVars] = {""}; TString VarManager::fgVariableUnits[VarManager::kNVars] = {""}; +std::map VarManager::fgVarNamesMap; bool VarManager::fgUsedVars[VarManager::kNVars] = {false}; bool VarManager::fgUsedKF = false; float VarManager::fgMagField = 0.5; @@ -30,6 +34,12 @@ std::vector VarManager::fgRunList = {0}; float VarManager::fgCenterOfMassEnergy = 13600; // GeV float VarManager::fgMassofCollidingParticle = 9.382720; // GeV float VarManager::fgTPCInterSectorBoundary = 1.0; // cm +int VarManager::fgITSROFbias = 0; +int VarManager::fgITSROFlength = 100; +int VarManager::fgITSROFBorderMarginLow = 0; +int VarManager::fgITSROFBorderMarginHigh = 0; +uint64_t VarManager::fgSOR = 0; +uint64_t VarManager::fgEOR = 0; o2::vertexing::DCAFitterN<2> VarManager::fgFitterTwoProngBarrel; o2::vertexing::DCAFitterN<3> VarManager::fgFitterThreeProngBarrel; o2::vertexing::FwdDCAFitterN<2> VarManager::fgFitterTwoProngFwd; @@ -224,6 +234,10 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kRunId] = ""; fgVariableNames[kBC] = "Bunch crossing"; fgVariableUnits[kBC] = ""; + fgVariableNames[kTimeFromSOR] = "time since SOR"; + fgVariableUnits[kTimeFromSOR] = "min."; + fgVariableNames[kBCOrbit] = "Bunch crossing"; + fgVariableUnits[kBCOrbit] = ""; fgVariableNames[kIsPhysicsSelection] = "Physics selection"; fgVariableUnits[kIsPhysicsSelection] = ""; fgVariableNames[kVtxX] = "Vtx X "; @@ -232,6 +246,10 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kVtxY] = "cm"; fgVariableNames[kVtxZ] = "Vtx Z "; fgVariableUnits[kVtxZ] = "cm"; + fgVariableNames[kCollisionTime] = "collision time wrt BC"; + fgVariableUnits[kCollisionTime] = "ns"; + fgVariableNames[kCollisionTimeRes] = "collision time resolution"; + fgVariableUnits[kCollisionTimeRes] = "ns"; fgVariableNames[kVtxNcontrib] = "Vtx contrib."; fgVariableUnits[kVtxNcontrib] = ""; fgVariableNames[kVtxNcontribReal] = "Real Vtx contrib."; @@ -276,9 +294,12 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kMultTracklets] = ""; fgVariableNames[kMultDimuons] = "Multiplicity Dimuons Unlike Sign"; fgVariableUnits[kMultDimuons] = ""; + fgVariableNames[kMultDimuonsME] = "Multiplicity Dimuons Unlike Sign Mixed Events"; + fgVariableUnits[kMultDimuonsME] = ""; fgVariableNames[kCentFT0C] = "Centrality FT0C"; fgVariableUnits[kCentFT0C] = "%"; fgVariableNames[kMCEventGeneratorId] = "MC Generator ID"; + fgVariableNames[kMCEventSubGeneratorId] = "MC SubGenerator ID"; fgVariableNames[kMCVtxX] = "MC Vtx X"; fgVariableNames[kMCVtxY] = "MC Vtx Y"; fgVariableNames[kMCVtxZ] = "MC Vtx Z"; @@ -286,6 +307,7 @@ void VarManager::SetDefaultVarNames() fgVariableNames[kMCEventWeight] = "MC event weight"; fgVariableNames[kMCEventImpParam] = "MC impact parameter"; fgVariableUnits[kMCEventGeneratorId] = ""; + fgVariableUnits[kMCEventSubGeneratorId] = ""; fgVariableUnits[kMCVtxX] = "cm"; fgVariableUnits[kMCVtxY] = "cm"; fgVariableUnits[kMCVtxZ] = "cm"; @@ -312,8 +334,92 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kTwoEvPVcontrib1] = ""; fgVariableNames[kTwoEvPVcontrib2] = "n.contrib 2"; fgVariableUnits[kTwoEvPVcontrib2] = ""; + fgVariableNames[kEnergyCommonZNA] = "ZNA common energy"; + fgVariableUnits[kEnergyCommonZNA] = ""; + fgVariableNames[kEnergyCommonZNC] = "ZNC common energy"; + fgVariableUnits[kEnergyCommonZNC] = ""; + fgVariableNames[kEnergyCommonZPA] = "ZPA common energy"; + fgVariableUnits[kEnergyCommonZPA] = ""; + fgVariableNames[kEnergyCommonZPC] = "ZPC common energy"; + fgVariableUnits[kEnergyCommonZPC] = ""; + fgVariableNames[kTimeZNA] = "ZNA time"; + fgVariableUnits[kTimeZNA] = ""; + fgVariableNames[kTimeZNC] = "ZNC time"; + fgVariableUnits[kTimeZNC] = ""; + fgVariableNames[kTimeZPA] = "ZPA time"; + fgVariableUnits[kTimeZPA] = ""; + fgVariableNames[kTimeZPC] = "ZPC time"; + fgVariableUnits[kTimeZPC] = ""; + fgVariableNames[kMultNTracksHasITS] = "#tracks in PV with ITS"; + fgVariableUnits[kMultNTracksHasITS] = ""; + fgVariableNames[kMultNTracksHasTPC] = "#tracks in PV with TPC"; + fgVariableUnits[kMultNTracksHasTPC] = ""; + fgVariableNames[kMultNTracksHasTOF] = "#tracks in PV with TOF"; + fgVariableUnits[kMultNTracksHasTOF] = ""; + fgVariableNames[kMultNTracksHasTRD] = "#tracks in PV with TRD"; + fgVariableUnits[kMultNTracksHasTRD] = ""; + fgVariableNames[kMultNTracksITSOnly] = "# ITS only tracks in PV"; + fgVariableUnits[kMultNTracksITSOnly] = ""; + fgVariableNames[kMultNTracksTPCOnly] = "# TPC only tracks in PV"; + fgVariableUnits[kMultNTracksTPCOnly] = ""; + fgVariableNames[kMultNTracksITSTPC] = "# ITS-TPC tracks in PV"; + fgVariableUnits[kMultNTracksITSTPC] = ""; + fgVariableNames[kMultNTracksPVeta1] = "# Mult Tracks PV |#eta| < 1"; + fgVariableUnits[kMultNTracksPVeta1] = ""; + fgVariableNames[kMultNTracksPVetaHalf] = "# Mult Tracks PV |#eta| < 0.5"; + fgVariableUnits[kMultNTracksPVetaHalf] = ""; + fgVariableNames[kTrackOccupancyInTimeRange] = "track occupancy in TPC drift time (PV tracks)"; + fgVariableUnits[kTrackOccupancyInTimeRange] = ""; + fgVariableNames[kFT0COccupancyInTimeRange] = "FT0C occupancy"; + fgVariableUnits[kFT0COccupancyInTimeRange] = ""; + fgVariableNames[kNoCollInTimeRangeStandard] = "track occupancy in TPC drift standart time"; + fgVariableUnits[kNoCollInTimeRangeStandard] = ""; + fgVariableNames[kMultAllTracksITSTPC] = "# ITS-TPC tracks"; + fgVariableUnits[kMultAllTracksITSTPC] = ""; + fgVariableNames[kMultAllTracksTPCOnly] = "# TPC only tracks"; + fgVariableUnits[kMultAllTracksTPCOnly] = ""; + fgVariableNames[kNTPCpileupContribA] = "# TPC pileup contributors on A side"; + fgVariableUnits[kNTPCpileupContribA] = ""; + fgVariableNames[kNTPCpileupContribC] = "# TPC pileup contributors on C side"; + fgVariableUnits[kNTPCpileupContribC] = ""; + fgVariableNames[kNTPCpileupZA] = "# TPC pileup mean-Z on A side"; + fgVariableUnits[kNTPCpileupZA] = ""; + fgVariableNames[kNTPCpileupZC] = "# TPC pileup mean-Z on C side"; + fgVariableUnits[kNTPCpileupZC] = ""; + fgVariableNames[kNTPCtracksInPast] = "# TPC tracks in past"; + fgVariableUnits[kNTPCtracksInPast] = ""; + fgVariableNames[kNTPCtracksInFuture] = "# TPC tracks in future"; + fgVariableUnits[kNTPCtracksInFuture] = ""; + fgVariableNames[kNTPCcontribLongA] = "# TPC-A pileup, long time range"; + fgVariableUnits[kNTPCcontribLongA] = ""; + fgVariableNames[kNTPCcontribLongC] = "# TPC-C pileup, long time range"; + fgVariableUnits[kNTPCcontribLongC] = ""; + fgVariableNames[kNTPCmeanTimeLongA] = "# TPC-A pileup mean time, long time range"; + fgVariableUnits[kNTPCmeanTimeLongA] = "#mu s"; + fgVariableNames[kNTPCmeanTimeLongC] = "# TPC-C pileup mean time, long time range"; + fgVariableUnits[kNTPCmeanTimeLongC] = "#mu s"; + fgVariableNames[kNTPCmedianTimeLongA] = "# TPC-A pileup median time, long time range"; + fgVariableUnits[kNTPCmedianTimeLongA] = "#mu s"; + fgVariableNames[kNTPCmedianTimeLongC] = "# TPC-C pileup median time, long time range"; + fgVariableUnits[kNTPCmedianTimeLongC] = "#mu s"; + fgVariableNames[kNTPCcontribShortA] = "# TPC-A pileup, short time range"; + fgVariableUnits[kNTPCcontribShortA] = ""; + fgVariableNames[kNTPCcontribShortC] = "# TPC-C pileup, short time range"; + fgVariableUnits[kNTPCcontribShortC] = ""; + fgVariableNames[kNTPCmeanTimeShortA] = "# TPC-A pileup mean time, short time range"; + fgVariableUnits[kNTPCmeanTimeShortA] = "#mu s"; + fgVariableNames[kNTPCmeanTimeShortC] = "# TPC-C pileup mean time, short time range"; + fgVariableUnits[kNTPCmeanTimeShortC] = "#mu s"; + fgVariableNames[kNTPCmedianTimeShortA] = "# TPC-A pileup median time, short time range"; + fgVariableUnits[kNTPCmedianTimeShortA] = "#mu s"; + fgVariableNames[kNTPCmedianTimeShortC] = "# TPC-C pileup median time, short time range"; + fgVariableUnits[kNTPCmedianTimeShortC] = "#mu s"; fgVariableNames[kPt] = "p_{T}"; fgVariableUnits[kPt] = "GeV/c"; + fgVariableNames[kPt1] = "p_{T1}"; + fgVariableUnits[kPt1] = "GeV/c"; + fgVariableNames[kPt2] = "p_{T2}"; + fgVariableUnits[kPt2] = "GeV/c"; fgVariableNames[kInvPt] = "1/p_{T}"; fgVariableUnits[kInvPt] = "1/(GeV/c)"; fgVariableNames[kP] = "p"; @@ -336,8 +442,14 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kDeltaPtotTracks] = "GeV/c"; fgVariableNames[kCharge] = "charge"; fgVariableUnits[kCharge] = ""; + fgVariableNames[kCharge1] = "charge track 1"; + fgVariableUnits[kCharge1] = ""; + fgVariableNames[kCharge2] = "charge track 2"; + fgVariableUnits[kCharge2] = ""; fgVariableNames[kPin] = "p_{IN}"; fgVariableUnits[kPin] = "GeV/c"; + fgVariableNames[kPin_leg1] = "p_{IN}"; + fgVariableUnits[kPin_leg1] = "GeV/c"; fgVariableNames[kSignedPin] = "p_{IN} x charge"; fgVariableUnits[kSignedPin] = "GeV/c"; fgVariableNames[kTOFExpMom] = "TOF expected momentum"; @@ -371,6 +483,8 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kTPCncls] = ""; fgVariableNames[kTPCnclsCR] = "TPC #cls crossed rows"; fgVariableUnits[kTPCnclsCR] = ""; + fgVariableNames[kTPCnCRoverFindCls] = "TPC crossed rows over findable cls"; + fgVariableUnits[kTPCnCRoverFindCls] = ""; fgVariableNames[kTPCchi2] = "TPC chi2"; fgVariableUnits[kTPCchi2] = ""; fgVariableNames[kTPCsignal] = "TPC dE/dx"; @@ -401,6 +515,8 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kTPCnSigmaPi_Corr] = ""; fgVariableNames[kTPCnSigmaKa] = "n #sigma_{K}^{TPC}"; fgVariableUnits[kTPCnSigmaKa] = ""; + fgVariableNames[kTPCnSigmaKa_leg1] = "n #sigma_{K}^{TPC}"; + fgVariableUnits[kTPCnSigmaKa_leg1] = ""; fgVariableNames[kTPCnSigmaKa_Corr] = "n #sigma_{K}^{TPC} Corr."; fgVariableUnits[kTPCnSigmaKa_Corr] = ""; fgVariableNames[kTPCnSigmaPr] = "n #sigma_{p}^{TPC}"; @@ -479,7 +595,7 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kMCPy] = "GeV/c"; fgVariableNames[kMCPz] = "MC pz"; fgVariableUnits[kMCPz] = "GeV/c"; - fgVariableNames[kMCPt] = "MC pt"; + fgVariableNames[kMCPt] = "MC p_{T}"; fgVariableUnits[kMCPt] = "GeV/c"; fgVariableNames[kMCPhi] = "#varphi"; fgVariableUnits[kMCPhi] = "rad"; @@ -489,6 +605,8 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kMCY] = ""; fgVariableNames[kMCE] = "MC Energy"; fgVariableUnits[kMCE] = "GeV"; + fgVariableNames[kMCMass] = "MC Mass"; + fgVariableUnits[kMCMass] = "GeV/c2"; fgVariableNames[kMCVx] = "MC vx"; fgVariableUnits[kMCVx] = "cm"; // TODO: check the unit fgVariableNames[kMCVy] = "MC vy"; @@ -527,6 +645,12 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kVertexingTauzProjected] = "ns"; fgVariableNames[kVertexingTauxyProjected] = "Pair pseudo-proper Tauxy"; fgVariableUnits[kVertexingTauxyProjected] = "ns"; + fgVariableNames[kVertexingTauxyProjectedPoleJPsiMass] = "Pair pseudo-proper Tauxy (with pole JPsi mass)"; + fgVariableUnits[kVertexingTauxyProjectedPoleJPsiMass] = "ns"; + fgVariableNames[kVertexingTauxyzProjected] = "Pair pseudo-proper Tauxyz"; + fgVariableUnits[kVertexingTauxyzProjected] = "ns"; + fgVariableNames[kCosPointingAngle] = "cos(#theta_{pointing})"; + fgVariableUnits[kCosPointingAngle] = ""; fgVariableNames[kVertexingPz] = "Pz Pair"; fgVariableUnits[kVertexingPz] = "GeV/c"; fgVariableNames[kVertexingSV] = "Secondary Vertexing z"; @@ -543,6 +667,8 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kVertexingLzOverErr] = ""; fgVariableNames[kVertexingLxyzOverErr] = "Pair Lxyz/DLxyz"; fgVariableUnits[kVertexingLxyzOverErr] = ""; + fgVariableNames[kCosPointingAngle] = "Cos #theta_{pointing}"; + fgVariableUnits[kCosPointingAngle] = ""; fgVariableNames[kKFTrack0DCAxyz] = "Daughter0 DCAxyz"; fgVariableUnits[kKFTrack0DCAxyz] = "cm"; fgVariableNames[kKFTrack1DCAxyz] = "Daughter1 DCAxyz"; @@ -565,6 +691,26 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kKFCosPA] = ""; fgVariableNames[kKFNContributorsPV] = "Real Number of Trks to PV"; fgVariableUnits[kKFNContributorsPV] = ""; + fgVariableNames[kQ1ZNAX] = "Q_{1,x}^{ZNA} "; + fgVariableUnits[kQ1ZNAX] = ""; + fgVariableNames[kQ1ZNAY] = "Q_{1,y}^{ZNA} "; + fgVariableUnits[kQ1ZNAY] = ""; + fgVariableNames[kQ1ZNCX] = "Q_{1,x}^{ZNC} "; + fgVariableUnits[kQ1ZNCX] = ""; + fgVariableNames[kQ1ZNCY] = "Q_{1,y}^{ZNC} "; + fgVariableUnits[kQ1ZNCY] = ""; + fgVariableNames[KIntercalibZNA] = "ZNA^{common} - (ZNA1 + ZNA2 + ZNA3 + ZNA4)"; + fgVariableUnits[KIntercalibZNA] = ""; + fgVariableNames[KIntercalibZNC] = "ZNC^{common} - (ZNC1 + ZNC2 + ZNC3 + ZNC4)"; + fgVariableUnits[KIntercalibZNC] = ""; + fgVariableNames[kQ1ZNACXX] = "Q_{1,x}^{ZNC} #dot Q_{1,x}^{ZNA} "; + fgVariableUnits[kQ1ZNACXX] = ""; + fgVariableNames[kQ1ZNACYY] = "Q_{1,y}^{ZNC} #dot Q_{1,y}^{ZNA} "; + fgVariableUnits[kQ1ZNACYY] = ""; + fgVariableNames[kQ1ZNACYX] = "Q_{1,y}^{ZNC} #dot Q_{1,x}^{ZNA} "; + fgVariableUnits[kQ1ZNACYX] = ""; + fgVariableNames[kQ1ZNACXY] = "Q_{1,x}^{ZNC} #dot Q_{1,y}^{ZNA} "; + fgVariableUnits[kQ1ZNACXY] = ""; fgVariableNames[kQ1X0A] = "Q_{1,x}^{A} "; fgVariableUnits[kQ1X0A] = ""; fgVariableNames[kQ1Y0A] = "Q_{1,y}^{A} "; @@ -589,6 +735,30 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kQ2X0C] = ""; fgVariableNames[kQ2Y0C] = "Q_{2,y}^{C} "; fgVariableUnits[kQ2Y0C] = ""; + fgVariableNames[kQ2YYAB] = " "; + fgVariableUnits[kQ2YYAB] = ""; + fgVariableNames[kQ2XXAB] = " "; + fgVariableUnits[kQ2XXAB] = ""; + fgVariableNames[kQ2XYAB] = " "; + fgVariableUnits[kQ2XYAB] = ""; + fgVariableNames[kQ2YXAB] = " "; + fgVariableUnits[kQ2YXAB] = ""; + fgVariableNames[kQ2YYAC] = " "; + fgVariableUnits[kQ2YYAC] = ""; + fgVariableNames[kQ2XXAC] = " "; + fgVariableUnits[kQ2XXAC] = ""; + fgVariableNames[kQ2XYAC] = " "; + fgVariableUnits[kQ2XYAC] = ""; + fgVariableNames[kQ2YXAC] = " "; + fgVariableUnits[kQ2YXAC] = ""; + fgVariableNames[kQ2YYBC] = " "; + fgVariableUnits[kQ2YYBC] = ""; + fgVariableNames[kQ2XXBC] = " "; + fgVariableUnits[kQ2XXBC] = ""; + fgVariableNames[kQ2XYBC] = " "; + fgVariableUnits[kQ2XYBC] = ""; + fgVariableNames[kQ2YXBC] = " "; + fgVariableUnits[kQ2YXBC] = ""; fgVariableNames[kMultA] = "N_{ch}^{A} "; fgVariableUnits[kMultA] = ""; fgVariableNames[kMultB] = "N_{ch}^{B} "; @@ -635,36 +805,128 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kS11A] = ""; fgVariableNames[kS12A] = "S_{12}^{A} "; fgVariableUnits[kS12A] = ""; - fgVariableNames[kS21A] = "S_{21}^{A} "; - fgVariableUnits[kS21A] = ""; fgVariableNames[kS13A] = "S_{13}^{A} "; fgVariableUnits[kS13A] = ""; fgVariableNames[kS31A] = "S_{31}^{A} "; fgVariableUnits[kS31A] = ""; - fgVariableNames[kS22A] = "S_{22}^{A} "; - fgVariableUnits[kS22A] = ""; fgVariableNames[kM11REF] = "M_{11}^{REF} "; fgVariableUnits[kM11REF] = ""; - fgVariableNames[kM01POI] = "M_{01}^{POI} "; + fgVariableNames[kM11REFetagap] = "M_{11}^{REF}-etagap "; + fgVariableUnits[kM11REFetagap] = ""; + fgVariableNames[kM01POI] = "M^{'}_{01}^{POI} "; fgVariableUnits[kM01POI] = ""; fgVariableNames[kM1111REF] = "M_{1111}^{REF} "; fgVariableUnits[kM1111REF] = ""; - fgVariableNames[kM0111POI] = "M_{0111}^{POI} "; + fgVariableNames[kM11M1111REF] = "M_{11}_{REF}M_{1111}_{REF}"; + fgVariableUnits[kM11M1111REF] = ""; + fgVariableNames[kM11M1111REFoverMp] = "M_{11}_{REF}M_{1111}_{REF} / M_{p} "; + fgVariableUnits[kM11M1111REFoverMp] = ""; + fgVariableNames[kM01M0111POIoverMp] = "M_{01}_{POI}M_{0111}_{POI} / M_{p}"; + fgVariableUnits[kM01M0111POIoverMp] = ""; + fgVariableNames[kCORR2CORR4REF] = "<2><4>"; + fgVariableUnits[kCORR2CORR4REF] = ""; + fgVariableNames[kCORR2POICORR4POI] = "<2'><4'>"; + fgVariableUnits[kCORR2POICORR4POI] = ""; + fgVariableNames[kCORR2REFCORR4POI] = "<2><4'>"; + fgVariableUnits[kCORR2REFCORR4POI] = ""; + fgVariableNames[kCORR2REFCORR2POI] = "<2><2'>"; + fgVariableUnits[kCORR2REFCORR2POI] = ""; + fgVariableNames[kM01M0111overMp] = "M_{01}_{POI} M_{0111}_{POI} / M_{p} "; + fgVariableUnits[kM01M0111overMp] = ""; + fgVariableNames[kM11M0111overMp] = "M_{11}_{REF}M_{0111}_{POI} / M_{p} "; + fgVariableUnits[kM11M0111overMp] = ""; + fgVariableNames[kM11M01overMp] = "M_{11}_{REF}M_{01}_{POI} / M_{p} "; + fgVariableUnits[kM11M01overMp] = ""; + fgVariableNames[kM0111POI] = "M^{'}_{0111}^{POI} "; fgVariableUnits[kM0111POI] = ""; fgVariableNames[kCORR2REF] = "<2> "; fgVariableUnits[kCORR2REF] = ""; - fgVariableNames[kCORR2POI] = " <2'> "; + fgVariableNames[kCORR2REFbydimuons] = "<2> only for events with dimuons"; + fgVariableUnits[kCORR2REFbydimuons] = ""; + fgVariableNames[kCORR2REFetagap] = "<2-etagap> "; + fgVariableUnits[kCORR2REFetagap] = ""; + fgVariableNames[kCORR2POI] = "<2'> "; fgVariableUnits[kCORR2POI] = ""; - fgVariableNames[kCORR4REF] = " <4>"; + fgVariableNames[kCORR4REF] = "<4> "; fgVariableUnits[kCORR4REF] = ""; + fgVariableNames[kCORR4REFbydimuons] = "<4> only for events with dimuons"; + fgVariableUnits[kCORR4REFbydimuons] = ""; fgVariableNames[kCORR4POI] = "<4'> "; fgVariableUnits[kCORR4POI] = ""; - fgVariableNames[kC4REF] = "c_{2}(4)"; - fgVariableUnits[kC4REF] = ""; - fgVariableNames[kC4POI] = "d_{2}(4)"; - fgVariableUnits[kC4POI] = ""; - fgVariableNames[kV4] = "v_{2}(4)"; - fgVariableUnits[kV4] = ""; + fgVariableNames[kM11REFoverMp] = "M_{11}^{REF}/M_{p} "; + fgVariableUnits[kM11REFoverMp] = ""; + fgVariableNames[kM01POIoverMp] = "M^{'}_{01}^{POI}/M_{p} "; + fgVariableUnits[kM01POIoverMp] = ""; + fgVariableNames[kM1111REFoverMp] = "M_{1111}^{REF}/M_{p} "; + fgVariableUnits[kM1111REFoverMp] = ""; + fgVariableNames[kM0111POIoverMp] = "M^{'}_{0111}^{POI}/M_{p} "; + fgVariableUnits[kM0111POIoverMp] = ""; + fgVariableNames[kCORR2POIMp] = "<2'> M_{p} "; + fgVariableUnits[kCORR2POIMp] = ""; + fgVariableNames[kCORR4POIMp] = "<4'> M_{p} "; + fgVariableUnits[kCORR4POIMp] = ""; + fgVariableNames[kMultMuons] = "Multiplicity muons"; + fgVariableUnits[kMultMuons] = ""; + fgVariableNames[kMultAntiMuons] = "Multiplicity anti-muons"; + fgVariableUnits[kMultAntiMuons] = ""; + fgVariableNames[kM01POIplus] = "M_{01}_{POI}^{+} "; + fgVariableUnits[kM01POIplus] = ""; + fgVariableNames[kM0111POIplus] = "M^{'}_{0111}^{POI+} "; + fgVariableUnits[kM0111POIplus] = ""; + fgVariableNames[kM01POIminus] = "M_{01}_{POI}^{-} "; + fgVariableUnits[kM01POIminus] = ""; + fgVariableNames[kM0111POIminus] = "M^{'}_{0111}^{POI-} "; + fgVariableUnits[kM0111POIminus] = ""; + fgVariableNames[kM01POIoverMpminus] = "M_{01}_{POI}^{-} / M_{p} "; + fgVariableUnits[kM01POIoverMpminus] = ""; + fgVariableNames[kM01POIoverMpplus] = "M_{01}_{POI}^{+} / M_{p} "; + fgVariableUnits[kM01POIoverMpplus] = ""; + fgVariableNames[kM01POIoverMpmoins] = "M_{01}_{POI}^{-} / M_{p} "; + fgVariableUnits[kM01POIoverMpmoins] = ""; + fgVariableNames[kM01POIoverMpplus] = "M_{01}_{POI}^{+} / M_{p} "; + fgVariableUnits[kM01POIoverMpplus] = ""; + fgVariableNames[kM01POIoverMpmoins] = "M_{01}_{POI}^{-} / M_{p} "; + fgVariableUnits[kM01POIoverMpmoins] = ""; + fgVariableNames[kM0111POIoverMpminus] = "M^{'}_{0111}^{POI-} / M_{p} "; + fgVariableUnits[kM0111POIoverMpminus] = ""; + fgVariableNames[kM0111POIoverMpplus] = "M^{'}_{0111}^{POI+} / M_{p} "; + fgVariableUnits[kM0111POIoverMpplus] = ""; + fgVariableNames[kCORR2POIplus] = "<2>_{POI}^{+} "; + fgVariableUnits[kCORR2POIplus] = ""; + fgVariableNames[kCORR2POIminus] = "<2>_{POI}^{-} "; + fgVariableUnits[kCORR2POIminus] = ""; + fgVariableNames[kCORR4POIplus] = "<4>_{POI}^{+} "; + fgVariableUnits[kCORR4POIplus] = ""; + fgVariableNames[kCORR4POIminus] = "<4>_{POI}^{-} "; + fgVariableUnits[kCORR4POIminus] = ""; + fgVariableNames[kM11REFoverMpminus] = "M^{-}_{11}^{REF}/M^{-}_{p} "; + fgVariableUnits[kM11REFoverMpminus] = ""; + fgVariableNames[kM11REFoverMpplus] = "M^{+}_{11}^{REF}/M^{+}_{p} "; + fgVariableUnits[kM11REFoverMpplus] = ""; + fgVariableNames[kM1111REFoverMpplus] = "M^{+}_{1111}^{REF}/M^{+}_{p} "; + fgVariableUnits[kM1111REFoverMpplus] = ""; + fgVariableNames[kM1111REFoverMpminus] = "M^{-}_{1111}^{REF}/M^{-}_{p} "; + fgVariableUnits[kM1111REFoverMpminus] = ""; + fgVariableNames[kM01POIME] = "M_{01}^{POI, ME}"; + fgVariableUnits[kM01POIME] = ""; + fgVariableNames[kM0111POIME] = "M_{0111}^{POI, ME}"; + fgVariableUnits[kM0111POIME] = ""; + fgVariableNames[kCORR2POIME] = "CORR2^{POI, ME}"; + fgVariableUnits[kCORR2POIME] = ""; + fgVariableNames[kCORR4POIME] = "CORR4^{POI, ME}"; + fgVariableUnits[kCORR4POIME] = ""; + fgVariableNames[kM01POIoverMpME] = "M_{01}^{POI, ME} / M_p"; + fgVariableUnits[kM01POIoverMpME] = ""; + fgVariableNames[kM0111POIoverMpME] = "M_{0111}^{POI, ME} / M_p"; + fgVariableUnits[kM0111POIoverMpME] = ""; + fgVariableNames[kM11REFoverMpME] = "M_{11}^{REF} / M_p"; + fgVariableUnits[kM11REFoverMpME] = ""; + fgVariableNames[kM1111REFoverMpME] = "M_{1111}^{REF} / M_p"; + fgVariableUnits[kM1111REFoverMpME] = ""; + fgVariableNames[kCORR2REFbydimuonsME] = "CORR2^{REF} / dimuons ME"; + fgVariableUnits[kCORR2REFbydimuonsME] = ""; + fgVariableNames[kCORR4REFbydimuonsME] = "CORR4^{REF} / dimuons ME"; + fgVariableUnits[kCORR4REFbydimuonsME] = ""; fgVariableNames[kCos2DeltaPhi] = "cos 2(#varphi-#Psi_{2}^{A}) "; fgVariableUnits[kCos2DeltaPhi] = ""; fgVariableNames[kCos3DeltaPhi] = "cos 3(#varphi-#Psi_{3}^{A}) "; @@ -675,10 +937,12 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kPsi2B] = ""; fgVariableNames[kPsi2C] = "#Psi_{2}^{C} "; fgVariableUnits[kPsi2C] = ""; - fgVariableNames[kR2SP] = "R_{2}^{SP} "; - fgVariableUnits[kR2SP] = ""; - fgVariableNames[kR2SP_FT0CFT0A] = "R_{2}^{SP} (FT0C-FT0A) "; - fgVariableUnits[kR2SP_FT0CFT0A] = ""; + fgVariableNames[kR2SP_AB] = "R_{2}^{SP} (AB) "; + fgVariableUnits[kR2SP_AB] = ""; + fgVariableNames[kR2SP_AC] = "R_{2}^{SP} (AC) "; + fgVariableUnits[kR2SP_AC] = ""; + fgVariableNames[kR2SP_BC] = "R_{2}^{SP} (BC) "; + fgVariableUnits[kR2SP_BC] = ""; fgVariableNames[kR2SP_FT0CTPCPOS] = "R_{2}^{SP} (FT0C-TPCpos) "; fgVariableUnits[kR2SP_FT0CTPCPOS] = ""; fgVariableNames[kR2SP_FT0CTPCNEG] = "R_{2}^{SP} (FT0C-TPCneg) "; @@ -687,8 +951,12 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kR2SP_FT0ATPCPOS] = ""; fgVariableNames[kR2SP_FT0ATPCNEG] = "R_{2}^{SP} (FT0A-TPCneg) "; fgVariableUnits[kR2SP_FT0ATPCNEG] = ""; - fgVariableNames[kR2EP_FT0CFT0A] = "R_{2}^{EP} (FT0C-FT0A) "; - fgVariableUnits[kR2EP_FT0CFT0A] = ""; + fgVariableNames[kR2EP_AB] = "R_{2}^{EP} (TPC-FT0A) "; + fgVariableUnits[kR2EP_AB] = ""; + fgVariableNames[kR2EP_AC] = "R_{2}^{EP} (TPC-FT0C) "; + fgVariableUnits[kR2EP_AC] = ""; + fgVariableNames[kR2EP_BC] = "R_{2}^{EP} (FT0C-FT0A) "; + fgVariableUnits[kR2EP_BC] = ""; fgVariableNames[kR2EP_FT0CTPCPOS] = "R_{2}^{EP} (FT0C-TPCpos) "; fgVariableUnits[kR2EP_FT0CTPCPOS] = ""; fgVariableNames[kR2EP_FT0CTPCNEG] = "R_{2}^{EP} (FT0C-TPCneg) "; @@ -699,14 +967,14 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kR2EP_FT0ATPCNEG] = ""; fgVariableNames[kR3SP] = "R_{3}^{SP} "; fgVariableUnits[kR3SP] = ""; - fgVariableNames[kR2EP] = "R_{2}^{EP} "; - fgVariableUnits[kR2EP] = ""; fgVariableNames[kR3EP] = "R_{3}^{EP} "; fgVariableUnits[kR3EP] = ""; fgVariableNames[kPairMass] = "mass"; fgVariableUnits[kPairMass] = "GeV/c2"; fgVariableNames[kPairMassDau] = "mass dilepton"; fgVariableUnits[kPairMassDau] = "GeV/c2"; + fgVariableNames[kDeltaMass] = "mass - dilepton mass"; + fgVariableUnits[kDeltaMass] = "GeV/c2"; fgVariableNames[kMassDau] = "mass HF"; fgVariableUnits[kMassDau] = "GeV/c2"; fgVariableNames[kPairPt] = "p_{T}"; @@ -731,6 +999,14 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kCosThetaCS] = ""; fgVariableNames[kPhiCS] = "#varphi_{CS}"; fgVariableUnits[kPhiCS] = "rad."; + fgVariableNames[kCosPhiVP] = "cos#it{#varphi}_{VP}"; + fgVariableUnits[kCosPhiVP] = ""; + fgVariableNames[kPhiVP] = "#varphi_{VP} - #Psi_{2}"; + fgVariableUnits[kPhiVP] = "rad."; + fgVariableNames[kDeltaPhiPair2] = "#Delta#phi"; + fgVariableUnits[kDeltaPhiPair2] = "rad."; + fgVariableNames[kDeltaEtaPair2] = "#Delta#eta"; + fgVariableUnits[kDeltaEtaPair2] = ""; fgVariableNames[kPsiPair] = "#Psi_{pair}"; fgVariableUnits[kPsiPair] = "rad."; fgVariableNames[kDeltaPhiPair] = "#Delta#phi"; @@ -775,6 +1051,10 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kIsSingleGapA] = ""; fgVariableNames[kIsSingleGapC] = "is single gap event side C"; fgVariableUnits[kIsSingleGapC] = ""; + fgVariableNames[kIsSingleGap] = "is single gap event"; + fgVariableUnits[kIsSingleGap] = ""; + fgVariableNames[kIsITSUPCMode] = "UPC settings used"; + fgVariableUnits[kIsITSUPCMode] = ""; fgVariableNames[kQuadMass] = "mass quadruplet"; fgVariableUnits[kQuadMass] = "GeV/c2"; fgVariableNames[kQuadPt] = "p_{T}"; @@ -789,4 +1069,642 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kDitrackMass] = "GeV/c2"; fgVariableNames[kDitrackPt] = "p_{T}"; fgVariableUnits[kDitrackPt] = "GeV/c"; + fgVariableNames[kQ] = "mass difference"; + fgVariableUnits[kQ] = "GeV/c2"; + fgVariableNames[kDeltaR1] = "angular distance prong 1"; + fgVariableUnits[kDeltaR1] = ""; + fgVariableNames[kDeltaR2] = "angular distance prong 2"; + fgVariableUnits[kDeltaR2] = ""; + fgVariableNames[kV22m] = "v_{2}(2)_{#mu^{-}}"; + fgVariableUnits[kV22m] = ""; + fgVariableNames[kV24m] = "v_{2}(4)_{#mu^{-}}"; + fgVariableUnits[kV24m] = ""; + fgVariableNames[kV22p] = "v_{2}(2)_{#mu^{+}}"; + fgVariableUnits[kV22p] = ""; + fgVariableNames[kV24p] = "v_{2}(4)_{#mu^{+}}"; + fgVariableUnits[kV24p] = ""; + fgVariableNames[kV22ME] = "v_{2}(2)_{ME}"; + fgVariableUnits[kV22ME] = ""; + fgVariableNames[kV24ME] = "v_{2}(4)_{ME}"; + fgVariableUnits[kV24ME] = ""; + fgVariableNames[kWV22ME] = "W_{2}(2)_{ME}"; + fgVariableUnits[kWV22ME] = ""; + fgVariableNames[kWV24ME] = "W_{2}(4)_{ME}"; + fgVariableUnits[kWV24ME] = ""; + + // Set the variables short names map. This is needed for dynamic configuration via JSON files + fgVarNamesMap["kNothing"] = kNothing; + fgVarNamesMap["kRunNo"] = kRunNo; + fgVarNamesMap["kRunId"] = kRunId; + fgVarNamesMap["kRunIndex"] = kRunIndex; + fgVarNamesMap["kNRunWiseVariables"] = kNRunWiseVariables; + fgVarNamesMap["kTimestamp"] = kTimestamp; + fgVarNamesMap["kTimeFromSOR"] = kTimeFromSOR; + fgVarNamesMap["kCollisionTime"] = kCollisionTime; + fgVarNamesMap["kCollisionTimeRes"] = kCollisionTimeRes; + fgVarNamesMap["kBC"] = kBC; + fgVarNamesMap["kBCOrbit"] = kBCOrbit; + fgVarNamesMap["kIsPhysicsSelection"] = kIsPhysicsSelection; + fgVarNamesMap["kIsNoTFBorder"] = kIsNoTFBorder; + fgVarNamesMap["kIsNoITSROFBorder"] = kIsNoITSROFBorder; + fgVarNamesMap["kIsNoITSROFBorderRecomputed"] = kIsNoITSROFBorderRecomputed; + fgVarNamesMap["kIsNoSameBunch"] = kIsNoSameBunch; + fgVarNamesMap["kIsGoodZvtxFT0vsPV"] = kIsGoodZvtxFT0vsPV; + fgVarNamesMap["kIsVertexITSTPC"] = kIsVertexITSTPC; + fgVarNamesMap["kIsVertexTOFmatched"] = kIsVertexTOFmatched; + fgVarNamesMap["kIsSel8"] = kIsSel8; + fgVarNamesMap["kIsGoodITSLayer3"] = kIsGoodITSLayer3; + fgVarNamesMap["kIsGoodITSLayer0123"] = kIsGoodITSLayer0123; + fgVarNamesMap["kIsGoodITSLayersAll"] = kIsGoodITSLayersAll; + fgVarNamesMap["kIsINT7"] = kIsINT7; + fgVarNamesMap["kIsEMC7"] = kIsEMC7; + fgVarNamesMap["kIsINT7inMUON"] = kIsINT7inMUON; + fgVarNamesMap["kIsMuonSingleLowPt7"] = kIsMuonSingleLowPt7; + fgVarNamesMap["kIsMuonSingleHighPt7"] = kIsMuonSingleHighPt7; + fgVarNamesMap["kIsMuonUnlikeLowPt7"] = kIsMuonUnlikeLowPt7; + fgVarNamesMap["kIsMuonLikeLowPt7"] = kIsMuonLikeLowPt7; + fgVarNamesMap["kIsCUP8"] = kIsCUP8; + fgVarNamesMap["kIsCUP9"] = kIsCUP9; + fgVarNamesMap["kIsMUP10"] = kIsMUP10; + fgVarNamesMap["kIsMUP11"] = kIsMUP11; + fgVarNamesMap["kVtxX"] = kVtxX; + fgVarNamesMap["kVtxY"] = kVtxY; + fgVarNamesMap["kVtxZ"] = kVtxZ; + fgVarNamesMap["kVtxNcontrib"] = kVtxNcontrib; + fgVarNamesMap["kVtxNcontribReal"] = kVtxNcontribReal; + fgVarNamesMap["kVtxCovXX"] = kVtxCovXX; + fgVarNamesMap["kVtxCovXY"] = kVtxCovXY; + fgVarNamesMap["kVtxCovXZ"] = kVtxCovXZ; + fgVarNamesMap["kVtxCovYY"] = kVtxCovYY; + fgVarNamesMap["kVtxCovYZ"] = kVtxCovYZ; + fgVarNamesMap["kVtxCovZZ"] = kVtxCovZZ; + fgVarNamesMap["kVtxChi2"] = kVtxChi2; + fgVarNamesMap["kCentVZERO"] = kCentVZERO; + fgVarNamesMap["kCentFT0C"] = kCentFT0C; + fgVarNamesMap["kMultTPC"] = kMultTPC; + fgVarNamesMap["kMultFV0A"] = kMultFV0A; + fgVarNamesMap["kMultFV0C"] = kMultFV0C; + fgVarNamesMap["kMultFT0A"] = kMultFT0A; + fgVarNamesMap["kMultFT0C"] = kMultFT0C; + fgVarNamesMap["kMultFDDA"] = kMultFDDA; + fgVarNamesMap["kMultFDDC"] = kMultFDDC; + fgVarNamesMap["kMultZNA"] = kMultZNA; + fgVarNamesMap["kMultZNC"] = kMultZNC; + fgVarNamesMap["kMultTracklets"] = kMultTracklets; + fgVarNamesMap["kMultDimuons"] = kMultDimuons; + fgVarNamesMap["kMultDimuonsME"] = kMultDimuonsME; + fgVarNamesMap["kMultNTracksHasITS"] = kMultNTracksHasITS; + fgVarNamesMap["kMultNTracksHasTPC"] = kMultNTracksHasTPC; + fgVarNamesMap["kMultNTracksHasTOF"] = kMultNTracksHasTOF; + fgVarNamesMap["kMultNTracksHasTRD"] = kMultNTracksHasTRD; + fgVarNamesMap["kMultNTracksITSOnly"] = kMultNTracksITSOnly; + fgVarNamesMap["kMultNTracksTPCOnly"] = kMultNTracksTPCOnly; + fgVarNamesMap["kMultNTracksITSTPC"] = kMultNTracksITSTPC; + fgVarNamesMap["kMultNTracksPVeta1"] = kMultNTracksPVeta1; + fgVarNamesMap["kMultNTracksPVetaHalf"] = kMultNTracksPVetaHalf; + fgVarNamesMap["kTrackOccupancyInTimeRange"] = kTrackOccupancyInTimeRange; + fgVarNamesMap["kFT0COccupancyInTimeRange"] = kFT0COccupancyInTimeRange; + fgVarNamesMap["kNoCollInTimeRangeStandard"] = kNoCollInTimeRangeStandard; + fgVarNamesMap["kMultAllTracksTPCOnly"] = kMultAllTracksTPCOnly; + fgVarNamesMap["kMultAllTracksITSTPC"] = kMultAllTracksITSTPC; + fgVarNamesMap["kNTPCpileupContribA"] = kNTPCpileupContribA; + fgVarNamesMap["kNTPCpileupContribC"] = kNTPCpileupContribC; + fgVarNamesMap["kNTPCpileupZA"] = kNTPCpileupZA; + fgVarNamesMap["kNTPCpileupZC"] = kNTPCpileupZC; + fgVarNamesMap["kNTPCtracksInPast"] = kNTPCtracksInPast; + fgVarNamesMap["kNTPCtracksInFuture"] = kNTPCtracksInFuture; + fgVarNamesMap["kNTPCcontribLongA"] = kNTPCcontribLongA; + fgVarNamesMap["kNTPCcontribLongC"] = kNTPCcontribLongC; + fgVarNamesMap["kNTPCmeanTimeLongA"] = kNTPCmeanTimeLongA; + fgVarNamesMap["kNTPCmeanTimeLongC"] = kNTPCmeanTimeLongC; + fgVarNamesMap["kNTPCmedianTimeLongA"] = kNTPCmedianTimeLongA; + fgVarNamesMap["kNTPCmedianTimeLongC"] = kNTPCmedianTimeLongC; + fgVarNamesMap["kNTPCcontribShortA"] = kNTPCcontribShortA; + fgVarNamesMap["kNTPCcontribShortC"] = kNTPCcontribShortC; + fgVarNamesMap["kNTPCmeanTimeShortA"] = kNTPCmeanTimeShortA; + fgVarNamesMap["kNTPCmeanTimeShortC"] = kNTPCmeanTimeShortC; + fgVarNamesMap["kNTPCmedianTimeShortA"] = kNTPCmedianTimeShortA; + fgVarNamesMap["kNTPCmedianTimeShortC"] = kNTPCmedianTimeShortC; + fgVarNamesMap["kMCEventGeneratorId"] = kMCEventGeneratorId; + fgVarNamesMap["kMCEventSubGeneratorId"] = kMCEventSubGeneratorId; + fgVarNamesMap["kMCVtxX"] = kMCVtxX; + fgVarNamesMap["kMCVtxY"] = kMCVtxY; + fgVarNamesMap["kMCVtxZ"] = kMCVtxZ; + fgVarNamesMap["kMCEventTime"] = kMCEventTime; + fgVarNamesMap["kMCEventWeight"] = kMCEventWeight; + fgVarNamesMap["kMCEventImpParam"] = kMCEventImpParam; + fgVarNamesMap["kQ1ZNAX"] = kQ1ZNAX; + fgVarNamesMap["kQ1ZNAY"] = kQ1ZNAY; + fgVarNamesMap["kQ1ZNCX"] = kQ1ZNCX; + fgVarNamesMap["kQ1ZNCY"] = kQ1ZNCY; + fgVarNamesMap["KIntercalibZNA"] = KIntercalibZNA; + fgVarNamesMap["KIntercalibZNC"] = KIntercalibZNC; + fgVarNamesMap["kQ1ZNACXX"] = kQ1ZNACXX; + fgVarNamesMap["kQ1ZNACYY"] = kQ1ZNACYY; + fgVarNamesMap["kQ1ZNACYX"] = kQ1ZNACYX; + fgVarNamesMap["kQ1ZNACXY"] = kQ1ZNACXY; + fgVarNamesMap["kQ1X0A"] = kQ1X0A; + fgVarNamesMap["kQ1Y0A"] = kQ1Y0A; + fgVarNamesMap["kQ1X0B"] = kQ1X0B; + fgVarNamesMap["kQ1Y0B"] = kQ1Y0B; + fgVarNamesMap["kQ1X0C"] = kQ1X0C; + fgVarNamesMap["kQ1Y0C"] = kQ1Y0C; + fgVarNamesMap["kQ2X0A"] = kQ2X0A; + fgVarNamesMap["kQ2Y0A"] = kQ2Y0A; + fgVarNamesMap["kQ2X0APOS"] = kQ2X0APOS; + fgVarNamesMap["kQ2Y0APOS"] = kQ2Y0APOS; + fgVarNamesMap["kQ2X0ANEG"] = kQ2X0ANEG; + fgVarNamesMap["kQ2Y0ANEG"] = kQ2Y0ANEG; + fgVarNamesMap["kQ2X0B"] = kQ2X0B; + fgVarNamesMap["kQ2Y0B"] = kQ2Y0B; + fgVarNamesMap["kQ2X0C"] = kQ2X0C; + fgVarNamesMap["kQ2Y0C"] = kQ2Y0C; + fgVarNamesMap["kQ2YYAB"] = kQ2YYAB; + fgVarNamesMap["kQ2XXAB"] = kQ2XXAB; + fgVarNamesMap["kQ2XYAB"] = kQ2XYAB; + fgVarNamesMap["kQ2YXAB"] = kQ2YXAB; + fgVarNamesMap["kQ2YYAC"] = kQ2YYAC; + fgVarNamesMap["kQ2XXAC"] = kQ2XXAC; + fgVarNamesMap["kQ2XYAC"] = kQ2XYAC; + fgVarNamesMap["kQ2YXAC"] = kQ2YXAC; + fgVarNamesMap["kQ2YYBC"] = kQ2YYBC; + fgVarNamesMap["kQ2XXBC"] = kQ2XXBC; + fgVarNamesMap["kQ2XYBC"] = kQ2XYBC; + fgVarNamesMap["kQ2YXBC"] = kQ2YXBC; + fgVarNamesMap["kMultA"] = kMultA; + fgVarNamesMap["kMultAPOS"] = kMultAPOS; + fgVarNamesMap["kMultANEG"] = kMultANEG; + fgVarNamesMap["kMultB"] = kMultB; + fgVarNamesMap["kMultC"] = kMultC; + fgVarNamesMap["kQ3X0A"] = kQ3X0A; + fgVarNamesMap["kQ3Y0A"] = kQ3Y0A; + fgVarNamesMap["kQ3X0B"] = kQ3X0B; + fgVarNamesMap["kQ3Y0B"] = kQ3Y0B; + fgVarNamesMap["kQ3X0C"] = kQ3X0C; + fgVarNamesMap["kQ3Y0C"] = kQ3Y0C; + fgVarNamesMap["kQ4X0A"] = kQ4X0A; + fgVarNamesMap["kQ4Y0A"] = kQ4Y0A; + fgVarNamesMap["kQ4X0B"] = kQ4X0B; + fgVarNamesMap["kQ4Y0B"] = kQ4Y0B; + fgVarNamesMap["kQ4X0C"] = kQ4X0C; + fgVarNamesMap["kQ4Y0C"] = kQ4Y0C; + fgVarNamesMap["kR2SP_AB"] = kR2SP_AB; + fgVarNamesMap["kR2SP_AC"] = kR2SP_AC; + fgVarNamesMap["kR2SP_BC"] = kR2SP_BC; + fgVarNamesMap["kWR2SP_AB"] = kWR2SP_AB; + fgVarNamesMap["kWR2SP_AC"] = kWR2SP_AC; + fgVarNamesMap["kWR2SP_BC"] = kWR2SP_BC; + fgVarNamesMap["kR2SP_AB_Im"] = kR2SP_AB_Im; + fgVarNamesMap["kR2SP_AC_Im"] = kR2SP_AC_Im; + fgVarNamesMap["kR2SP_BC_Im"] = kR2SP_BC_Im; + fgVarNamesMap["kWR2SP_AB_Im"] = kWR2SP_AB_Im; + fgVarNamesMap["kWR2SP_AC_Im"] = kWR2SP_AC_Im; + fgVarNamesMap["kWR2SP_BC_Im"] = kWR2SP_BC_Im; + fgVarNamesMap["kR2SP_FT0CTPCPOS"] = kR2SP_FT0CTPCPOS; + fgVarNamesMap["kR2SP_FT0CTPCNEG"] = kR2SP_FT0CTPCNEG; + fgVarNamesMap["kR2SP_FT0ATPCPOS"] = kR2SP_FT0ATPCPOS; + fgVarNamesMap["kR2SP_FT0ATPCNEG"] = kR2SP_FT0ATPCNEG; + fgVarNamesMap["kR2SP_FT0MTPCPOS"] = kR2SP_FT0MTPCPOS; + fgVarNamesMap["kR2SP_FT0MTPCNEG"] = kR2SP_FT0MTPCNEG; + fgVarNamesMap["kR2SP_FV0ATPCPOS"] = kR2SP_FV0ATPCPOS; + fgVarNamesMap["kR2SP_FV0ATPCNEG"] = kR2SP_FV0ATPCNEG; + fgVarNamesMap["kR3SP"] = kR3SP; + fgVarNamesMap["kR2EP_AB"] = kR2EP_AB; + fgVarNamesMap["kR2EP_AC"] = kR2EP_AC; + fgVarNamesMap["kR2EP_BC"] = kR2EP_BC; + fgVarNamesMap["kWR2EP_AB"] = kWR2EP_AB; + fgVarNamesMap["kWR2EP_AC"] = kWR2EP_AC; + fgVarNamesMap["kWR2EP_BC"] = kWR2EP_BC; + fgVarNamesMap["kR2EP_AB_Im"] = kR2EP_AB_Im; + fgVarNamesMap["kR2EP_AC_Im"] = kR2EP_AC_Im; + fgVarNamesMap["kR2EP_BC_Im"] = kR2EP_BC_Im; + fgVarNamesMap["kWR2EP_AB_Im"] = kWR2EP_AB_Im; + fgVarNamesMap["kWR2EP_AC_Im"] = kWR2EP_AC_Im; + fgVarNamesMap["kWR2EP_BC_Im"] = kWR2EP_BC_Im; + fgVarNamesMap["kR2EP_FT0CTPCPOS"] = kR2EP_FT0CTPCPOS; + fgVarNamesMap["kR2EP_FT0CTPCNEG"] = kR2EP_FT0CTPCNEG; + fgVarNamesMap["kR2EP_FT0ATPCPOS"] = kR2EP_FT0ATPCPOS; + fgVarNamesMap["kR2EP_FT0ATPCNEG"] = kR2EP_FT0ATPCNEG; + fgVarNamesMap["kR2EP_FT0MTPCPOS"] = kR2EP_FT0MTPCPOS; + fgVarNamesMap["kR2EP_FT0MTPCNEG"] = kR2EP_FT0MTPCNEG; + fgVarNamesMap["kR2EP_FV0ATPCPOS"] = kR2EP_FV0ATPCPOS; + fgVarNamesMap["kR2EP_FV0ATPCNEG"] = kR2EP_FV0ATPCNEG; + fgVarNamesMap["kR3EP"] = kR3EP; + fgVarNamesMap["kIsDoubleGap"] = kIsDoubleGap; + fgVarNamesMap["kIsSingleGapA"] = kIsSingleGapA; + fgVarNamesMap["kIsSingleGapC"] = kIsSingleGapC; + fgVarNamesMap["kIsSingleGap"] = kIsSingleGap; + fgVarNamesMap["kIsITSUPCMode"] = kIsITSUPCMode; + fgVarNamesMap["kTwoEvPosZ1"] = kTwoEvPosZ1; + fgVarNamesMap["kTwoEvPosZ2"] = kTwoEvPosZ2; + fgVarNamesMap["kTwoEvPosR1"] = kTwoEvPosR1; + fgVarNamesMap["kTwoEvPosR2"] = kTwoEvPosR2; + fgVarNamesMap["kTwoEvCentFT0C1"] = kTwoEvCentFT0C1; + fgVarNamesMap["kTwoEvCentFT0C2"] = kTwoEvCentFT0C2; + fgVarNamesMap["kTwoEvPVcontrib1"] = kTwoEvPVcontrib1; + fgVarNamesMap["kTwoEvPVcontrib2"] = kTwoEvPVcontrib2; + fgVarNamesMap["kTwoEvDeltaZ"] = kTwoEvDeltaZ; + fgVarNamesMap["kTwoEvDeltaX"] = kTwoEvDeltaX; + fgVarNamesMap["kTwoEvDeltaY"] = kTwoEvDeltaY; + fgVarNamesMap["kTwoEvDeltaR"] = kTwoEvDeltaR; + fgVarNamesMap["kEnergyCommonZNA"] = kEnergyCommonZNA; + fgVarNamesMap["kEnergyCommonZNC"] = kEnergyCommonZNC; + fgVarNamesMap["kEnergyCommonZPA"] = kEnergyCommonZPA; + fgVarNamesMap["kEnergyCommonZPC"] = kEnergyCommonZPC; + fgVarNamesMap["kEnergyZNA1"] = kEnergyZNA1; + fgVarNamesMap["kEnergyZNA2"] = kEnergyZNA2; + fgVarNamesMap["kEnergyZNA3"] = kEnergyZNA3; + fgVarNamesMap["kEnergyZNA4"] = kEnergyZNA4; + fgVarNamesMap["kEnergyZNC1"] = kEnergyZNC1; + fgVarNamesMap["kEnergyZNC2"] = kEnergyZNC2; + fgVarNamesMap["kEnergyZNC3"] = kEnergyZNC3; + fgVarNamesMap["kEnergyZNC4"] = kEnergyZNC4; + fgVarNamesMap["kTimeZNA"] = kTimeZNA; + fgVarNamesMap["kTimeZNC"] = kTimeZNC; + fgVarNamesMap["kTimeZPA"] = kTimeZPA; + fgVarNamesMap["kTimeZPC"] = kTimeZPC; + fgVarNamesMap["kQ2X0A1"] = kQ2X0A1; + fgVarNamesMap["kQ2X0A2"] = kQ2X0A2; + fgVarNamesMap["kQ2Y0A1"] = kQ2Y0A1; + fgVarNamesMap["kQ2Y0A2"] = kQ2Y0A2; + fgVarNamesMap["kU2Q2Ev1"] = kU2Q2Ev1; + fgVarNamesMap["kU2Q2Ev2"] = kU2Q2Ev2; + fgVarNamesMap["kCos2DeltaPhiEv1"] = kCos2DeltaPhiEv1; + fgVarNamesMap["kCos2DeltaPhiEv2"] = kCos2DeltaPhiEv2; + fgVarNamesMap["kV2SP1"] = kV2SP1; + fgVarNamesMap["kV2SP2"] = kV2SP2; + fgVarNamesMap["kV2EP1"] = kV2EP1; + fgVarNamesMap["kV2EP2"] = kV2EP2; + fgVarNamesMap["kV2ME_SP"] = kV2ME_SP; + fgVarNamesMap["kV2ME_EP"] = kV2ME_EP; + fgVarNamesMap["kWV2ME_SP"] = kWV2ME_SP; + fgVarNamesMap["kWV2ME_EP"] = kWV2ME_EP; + fgVarNamesMap["kTwoR2SP1"] = kTwoR2SP1; + fgVarNamesMap["kTwoR2SP2"] = kTwoR2SP2; + fgVarNamesMap["kTwoR2EP1"] = kTwoR2EP1; + fgVarNamesMap["kTwoR2EP2"] = kTwoR2EP2; + fgVarNamesMap["kNEventWiseVariables"] = kNEventWiseVariables; + fgVarNamesMap["kX"] = kX; + fgVarNamesMap["kY"] = kY; + fgVarNamesMap["kZ"] = kZ; + fgVarNamesMap["kPt"] = kPt; + fgVarNamesMap["kSignedPt"] = kSignedPt; + fgVarNamesMap["kInvPt"] = kInvPt; + fgVarNamesMap["kEta"] = kEta; + fgVarNamesMap["kTgl"] = kTgl; + fgVarNamesMap["kPhi"] = kPhi; + fgVarNamesMap["kP"] = kP; + fgVarNamesMap["kPx"] = kPx; + fgVarNamesMap["kPy"] = kPy; + fgVarNamesMap["kPz"] = kPz; + fgVarNamesMap["kRap"] = kRap; + fgVarNamesMap["kMass"] = kMass; + fgVarNamesMap["kCharge"] = kCharge; + fgVarNamesMap["kNBasicTrackVariables"] = kNBasicTrackVariables; + fgVarNamesMap["kUsedKF"] = kUsedKF; + fgVarNamesMap["kKFMass"] = kKFMass; + fgVarNamesMap["kKFMassGeoTop"] = kKFMassGeoTop; + fgVarNamesMap["kPt1"] = kPt1; + fgVarNamesMap["kEta1"] = kEta1; + fgVarNamesMap["kPhi1"] = kPhi1; + fgVarNamesMap["kCharge1"] = kCharge1; + fgVarNamesMap["kPin_leg1"] = kPin_leg1; + fgVarNamesMap["kTPCnSigmaKa_leg1"] = kTPCnSigmaKa_leg1; + fgVarNamesMap["kPt2"] = kPt2; + fgVarNamesMap["kEta2"] = kEta2; + fgVarNamesMap["kPhi2"] = kPhi2; + fgVarNamesMap["kCharge2"] = kCharge2; + fgVarNamesMap["kPin"] = kPin; + fgVarNamesMap["kSignedPin"] = kSignedPin; + fgVarNamesMap["kTOFExpMom"] = kTOFExpMom; + fgVarNamesMap["kTrackTime"] = kTrackTime; + fgVarNamesMap["kTrackTimeRes"] = kTrackTimeRes; + fgVarNamesMap["kTrackTimeResRelative"] = kTrackTimeResRelative; + fgVarNamesMap["kDetectorMap"] = kDetectorMap; + fgVarNamesMap["kHasITS"] = kHasITS; + fgVarNamesMap["kHasTRD"] = kHasTRD; + fgVarNamesMap["kHasTOF"] = kHasTOF; + fgVarNamesMap["kHasTPC"] = kHasTPC; + fgVarNamesMap["kIsGlobalTrack"] = kIsGlobalTrack; + fgVarNamesMap["kIsGlobalTrackSDD"] = kIsGlobalTrackSDD; + fgVarNamesMap["kIsITSrefit"] = kIsITSrefit; + fgVarNamesMap["kIsSPDany"] = kIsSPDany; + fgVarNamesMap["kIsSPDfirst"] = kIsSPDfirst; + fgVarNamesMap["kIsSPDboth"] = kIsSPDboth; + fgVarNamesMap["kIsITSibAny"] = kIsITSibAny; + fgVarNamesMap["kIsITSibFirst"] = kIsITSibFirst; + fgVarNamesMap["kIsITSibAll"] = kIsITSibAll; + fgVarNamesMap["kITSncls"] = kITSncls; + fgVarNamesMap["kITSchi2"] = kITSchi2; + fgVarNamesMap["kITSlayerHit"] = kITSlayerHit; + fgVarNamesMap["kITSmeanClsSize"] = kITSmeanClsSize; + fgVarNamesMap["kIsTPCrefit"] = kIsTPCrefit; + fgVarNamesMap["kTPCncls"] = kTPCncls; + fgVarNamesMap["kITSClusterMap"] = kITSClusterMap; + fgVarNamesMap["kTPCnclsCR"] = kTPCnclsCR; + fgVarNamesMap["kTPCnCRoverFindCls"] = kTPCnCRoverFindCls; + fgVarNamesMap["kTPCchi2"] = kTPCchi2; + fgVarNamesMap["kTPCsignal"] = kTPCsignal; + fgVarNamesMap["kTPCsignalRandomized"] = kTPCsignalRandomized; + fgVarNamesMap["kTPCsignalRandomizedDelta"] = kTPCsignalRandomizedDelta; + fgVarNamesMap["kPhiTPCOuter"] = kPhiTPCOuter; + fgVarNamesMap["kTrackIsInsideTPCModule"] = kTrackIsInsideTPCModule; + fgVarNamesMap["kTRDsignal"] = kTRDsignal; + fgVarNamesMap["kTRDPattern"] = kTRDPattern; + fgVarNamesMap["kTOFbeta"] = kTOFbeta; + fgVarNamesMap["kTrackLength"] = kTrackLength; + fgVarNamesMap["kTrackDCAxy"] = kTrackDCAxy; + fgVarNamesMap["kTrackDCAxyProng1"] = kTrackDCAxyProng1; + fgVarNamesMap["kTrackDCAxyProng2"] = kTrackDCAxyProng2; + fgVarNamesMap["kTrackDCAz"] = kTrackDCAz; + fgVarNamesMap["kTrackDCAzProng1"] = kTrackDCAzProng1; + fgVarNamesMap["kTrackDCAzProng2"] = kTrackDCAzProng2; + fgVarNamesMap["kTrackDCAsigXY"] = kTrackDCAsigXY; + fgVarNamesMap["kTrackDCAsigZ"] = kTrackDCAsigZ; + fgVarNamesMap["kTrackDCAresXY"] = kTrackDCAresXY; + fgVarNamesMap["kTrackDCAresZ"] = kTrackDCAresZ; + fgVarNamesMap["kIsGoldenChi2"] = kIsGoldenChi2; + fgVarNamesMap["kTrackCYY"] = kTrackCYY; + fgVarNamesMap["kTrackCZZ"] = kTrackCZZ; + fgVarNamesMap["kTrackCSnpSnp"] = kTrackCSnpSnp; + fgVarNamesMap["kTrackCTglTgl"] = kTrackCTglTgl; + fgVarNamesMap["kTrackC1Pt21Pt2"] = kTrackC1Pt21Pt2; + fgVarNamesMap["kTPCnSigmaEl"] = kTPCnSigmaEl; + fgVarNamesMap["kTPCnSigmaElRandomized"] = kTPCnSigmaElRandomized; + fgVarNamesMap["kTPCnSigmaElRandomizedDelta"] = kTPCnSigmaElRandomizedDelta; + fgVarNamesMap["kTPCnSigmaMu"] = kTPCnSigmaMu; + fgVarNamesMap["kTPCnSigmaPi"] = kTPCnSigmaPi; + fgVarNamesMap["kTPCnSigmaPiRandomized"] = kTPCnSigmaPiRandomized; + fgVarNamesMap["kTPCnSigmaPiRandomizedDelta"] = kTPCnSigmaPiRandomizedDelta; + fgVarNamesMap["kTPCnSigmaKa"] = kTPCnSigmaKa; + fgVarNamesMap["kTPCnSigmaPr"] = kTPCnSigmaPr; + fgVarNamesMap["kTPCnSigmaEl_Corr"] = kTPCnSigmaEl_Corr; + fgVarNamesMap["kTPCnSigmaPi_Corr"] = kTPCnSigmaPi_Corr; + fgVarNamesMap["kTPCnSigmaKa_Corr"] = kTPCnSigmaKa_Corr; + fgVarNamesMap["kTPCnSigmaPr_Corr"] = kTPCnSigmaPr_Corr; + fgVarNamesMap["kTPCnSigmaPrRandomized"] = kTPCnSigmaPrRandomized; + fgVarNamesMap["kTPCnSigmaPrRandomizedDelta"] = kTPCnSigmaPrRandomizedDelta; + fgVarNamesMap["kTOFnSigmaEl"] = kTOFnSigmaEl; + fgVarNamesMap["kTOFnSigmaMu"] = kTOFnSigmaMu; + fgVarNamesMap["kTOFnSigmaPi"] = kTOFnSigmaPi; + fgVarNamesMap["kTOFnSigmaKa"] = kTOFnSigmaKa; + fgVarNamesMap["kTOFnSigmaPr"] = kTOFnSigmaPr; + fgVarNamesMap["kTrackTimeResIsRange"] = kTrackTimeResIsRange; + fgVarNamesMap["kPVContributor"] = kPVContributor; + fgVarNamesMap["kOrphanTrack"] = kOrphanTrack; + fgVarNamesMap["kIsAmbiguous"] = kIsAmbiguous; + fgVarNamesMap["kIsLegFromGamma"] = kIsLegFromGamma; + fgVarNamesMap["kIsLegFromK0S"] = kIsLegFromK0S; + fgVarNamesMap["kIsLegFromLambda"] = kIsLegFromLambda; + fgVarNamesMap["kIsLegFromAntiLambda"] = kIsLegFromAntiLambda; + fgVarNamesMap["kIsLegFromOmega"] = kIsLegFromOmega; + fgVarNamesMap["kIsProtonFromLambdaAndAntiLambda"] = kIsProtonFromLambdaAndAntiLambda; + fgVarNamesMap["kIsDalitzLeg"] = kIsDalitzLeg; + fgVarNamesMap["kBarrelNAssocsInBunch"] = kBarrelNAssocsInBunch; + fgVarNamesMap["kBarrelNAssocsOutOfBunch"] = kBarrelNAssocsOutOfBunch; + fgVarNamesMap["kNBarrelTrackVariables"] = kNBarrelTrackVariables; + fgVarNamesMap["kMuonNClusters"] = kMuonNClusters; + fgVarNamesMap["kMuonPDca"] = kMuonPDca; + fgVarNamesMap["kMuonRAtAbsorberEnd"] = kMuonRAtAbsorberEnd; + fgVarNamesMap["kMCHBitMap"] = kMCHBitMap; + fgVarNamesMap["kMuonChi2"] = kMuonChi2; + fgVarNamesMap["kMuonChi2MatchMCHMID"] = kMuonChi2MatchMCHMID; + fgVarNamesMap["kMuonChi2MatchMCHMFT"] = kMuonChi2MatchMCHMFT; + fgVarNamesMap["kMuonMatchScoreMCHMFT"] = kMuonMatchScoreMCHMFT; + fgVarNamesMap["kMuonCXX"] = kMuonCXX; + fgVarNamesMap["kMuonCXY"] = kMuonCXY; + fgVarNamesMap["kMuonCYY"] = kMuonCYY; + fgVarNamesMap["kMuonCPhiX"] = kMuonCPhiX; + fgVarNamesMap["kMuonCPhiY"] = kMuonCPhiY; + fgVarNamesMap["kMuonCPhiPhi"] = kMuonCPhiPhi; + fgVarNamesMap["kMuonCTglX"] = kMuonCTglX; + fgVarNamesMap["kMuonCTglY"] = kMuonCTglY; + fgVarNamesMap["kMuonCTglPhi"] = kMuonCTglPhi; + fgVarNamesMap["kMuonCTglTgl"] = kMuonCTglTgl; + fgVarNamesMap["kMuonC1Pt2X"] = kMuonC1Pt2X; + fgVarNamesMap["kMuonC1Pt2Y"] = kMuonC1Pt2Y; + fgVarNamesMap["kMuonC1Pt2Phi"] = kMuonC1Pt2Phi; + fgVarNamesMap["kMuonC1Pt2Tgl"] = kMuonC1Pt2Tgl; + fgVarNamesMap["kMuonC1Pt21Pt2"] = kMuonC1Pt21Pt2; + fgVarNamesMap["kMuonTrackType"] = kMuonTrackType; + fgVarNamesMap["kMuonDCAx"] = kMuonDCAx; + fgVarNamesMap["kMuonDCAy"] = kMuonDCAy; + fgVarNamesMap["kMuonTime"] = kMuonTime; + fgVarNamesMap["kMuonTimeRes"] = kMuonTimeRes; + fgVarNamesMap["kMftNClusters"] = kMftNClusters; + fgVarNamesMap["kMftClusterSize"] = kMftClusterSize; + fgVarNamesMap["kMftMeanClusterSize"] = kMftMeanClusterSize; + fgVarNamesMap["kMuonNAssocsInBunch"] = kMuonNAssocsInBunch; + fgVarNamesMap["kMuonNAssocsOutOfBunch"] = kMuonNAssocsOutOfBunch; + fgVarNamesMap["kNMuonTrackVariables"] = kNMuonTrackVariables; + fgVarNamesMap["kMCPdgCode"] = kMCPdgCode; + fgVarNamesMap["kMCParticleWeight"] = kMCParticleWeight; + fgVarNamesMap["kMCPx"] = kMCPx; + fgVarNamesMap["kMCPy"] = kMCPy; + fgVarNamesMap["kMCPz"] = kMCPz; + fgVarNamesMap["kMCE"] = kMCE; + fgVarNamesMap["kMCVx"] = kMCVx; + fgVarNamesMap["kMCVy"] = kMCVy; + fgVarNamesMap["kMCVz"] = kMCVz; + fgVarNamesMap["kMCPt"] = kMCPt; + fgVarNamesMap["kMCPhi"] = kMCPhi; + fgVarNamesMap["kMCEta"] = kMCEta; + fgVarNamesMap["kMCY"] = kMCY; + fgVarNamesMap["kMCParticleGeneratorId"] = kMCParticleGeneratorId; + fgVarNamesMap["kNMCParticleVariables"] = kNMCParticleVariables; + fgVarNamesMap["kMCMotherPdgCode"] = kMCMotherPdgCode; + fgVarNamesMap["kCandidateId"] = kCandidateId; + fgVarNamesMap["kPairType"] = kPairType; + fgVarNamesMap["kVertexingLxy"] = kVertexingLxy; + fgVarNamesMap["kVertexingLxyErr"] = kVertexingLxyErr; + fgVarNamesMap["kVertexingPseudoCTau"] = kVertexingPseudoCTau; + fgVarNamesMap["kVertexingLxyz"] = kVertexingLxyz; + fgVarNamesMap["kVertexingLxyzErr"] = kVertexingLxyzErr; + fgVarNamesMap["kVertexingLz"] = kVertexingLz; + fgVarNamesMap["kVertexingLzErr"] = kVertexingLzErr; + fgVarNamesMap["kVertexingTauxy"] = kVertexingTauxy; + fgVarNamesMap["kVertexingTauxyErr"] = kVertexingTauxyErr; + fgVarNamesMap["kVertexingLzProjected"] = kVertexingLzProjected; + fgVarNamesMap["kVertexingLxyProjected"] = kVertexingLxyProjected; + fgVarNamesMap["kVertexingLxyzProjected"] = kVertexingLxyzProjected; + fgVarNamesMap["kVertexingTauzProjected"] = kVertexingTauzProjected; + fgVarNamesMap["kVertexingTauxyProjected"] = kVertexingTauxyProjected; + fgVarNamesMap["kVertexingTauxyProjectedPoleJPsiMass"] = kVertexingTauxyProjectedPoleJPsiMass; + fgVarNamesMap["kVertexingTauxyProjectedNs"] = kVertexingTauxyProjectedNs; + fgVarNamesMap["kVertexingTauxyzProjected"] = kVertexingTauxyzProjected; + fgVarNamesMap["kVertexingTauz"] = kVertexingTauz; + fgVarNamesMap["kVertexingTauzErr"] = kVertexingTauzErr; + fgVarNamesMap["kVertexingPz"] = kVertexingPz; + fgVarNamesMap["kVertexingSV"] = kVertexingSV; + fgVarNamesMap["kVertexingProcCode"] = kVertexingProcCode; + fgVarNamesMap["kVertexingChi2PCA"] = kVertexingChi2PCA; + fgVarNamesMap["kCosThetaHE"] = kCosThetaHE; + fgVarNamesMap["kCosThetaCS"] = kCosThetaCS; + fgVarNamesMap["kPhiHE"] = kPhiHE; + fgVarNamesMap["kPhiCS"] = kPhiCS; + fgVarNamesMap["kCosPhiVP"] = kCosPhiVP; + fgVarNamesMap["kPhiVP"] = kPhiVP; + fgVarNamesMap["kDeltaPhiPair2"] = kDeltaPhiPair2; + fgVarNamesMap["kDeltaEtaPair2"] = kDeltaEtaPair2; + fgVarNamesMap["kPsiPair"] = kPsiPair; + fgVarNamesMap["kDeltaPhiPair"] = kDeltaPhiPair; + fgVarNamesMap["kOpeningAngle"] = kOpeningAngle; + fgVarNamesMap["kQuadDCAabsXY"] = kQuadDCAabsXY; + fgVarNamesMap["kQuadDCAsigXY"] = kQuadDCAsigXY; + fgVarNamesMap["kQuadDCAabsZ"] = kQuadDCAabsZ; + fgVarNamesMap["kQuadDCAsigZ"] = kQuadDCAsigZ; + fgVarNamesMap["kQuadDCAsigXYZ"] = kQuadDCAsigXYZ; + fgVarNamesMap["kSignQuadDCAsigXY"] = kSignQuadDCAsigXY; + fgVarNamesMap["kCosPointingAngle"] = kCosPointingAngle; + fgVarNamesMap["kImpParXYJpsi"] = kImpParXYJpsi; + fgVarNamesMap["kImpParXYK"] = kImpParXYK; + fgVarNamesMap["kDCATrackProd"] = kDCATrackProd; + fgVarNamesMap["kDCATrackVtxProd"] = kDCATrackVtxProd; + fgVarNamesMap["kV2SP"] = kV2SP; + fgVarNamesMap["kV2EP"] = kV2EP; + fgVarNamesMap["kWV2SP"] = kWV2SP; + fgVarNamesMap["kWV2EP"] = kWV2EP; + fgVarNamesMap["kU2Q2"] = kU2Q2; + fgVarNamesMap["kU3Q3"] = kU3Q3; + fgVarNamesMap["kQ42XA"] = kQ42XA; + fgVarNamesMap["kQ42YA"] = kQ42YA; + fgVarNamesMap["kQ23XA"] = kQ23XA; + fgVarNamesMap["kQ23YA"] = kQ23YA; + fgVarNamesMap["kS11A"] = kS11A; + fgVarNamesMap["kS12A"] = kS12A; + fgVarNamesMap["kS13A"] = kS13A; + fgVarNamesMap["kS31A"] = kS31A; + fgVarNamesMap["kM11REF"] = kM11REF; + fgVarNamesMap["kM11REFetagap"] = kM11REFetagap; + fgVarNamesMap["kM01POI"] = kM01POI; + fgVarNamesMap["kM1111REF"] = kM1111REF; + fgVarNamesMap["kM11M1111REF"] = kM11M1111REF; + fgVarNamesMap["kM11M1111REFoverMp"] = kM11M1111REFoverMp; + fgVarNamesMap["kM01M0111POIoverMp"] = kM01M0111POIoverMp; + fgVarNamesMap["kM0111POI"] = kM0111POI; + fgVarNamesMap["kCORR2REF"] = kCORR2REF; + fgVarNamesMap["kCORR2REFbydimuons"] = kCORR2REFbydimuons; + fgVarNamesMap["kMultAntiMuons"] = kMultAntiMuons; + fgVarNamesMap["kMultMuons"] = kMultMuons; + fgVarNamesMap["kM01POIplus"] = kM01POIplus; + fgVarNamesMap["kM0111POIplus"] = kM0111POIplus; + fgVarNamesMap["kM01POIminus"] = kM01POIminus; + fgVarNamesMap["kM0111POIminus"] = kM0111POIminus; + fgVarNamesMap["kM01POIoverMpminus"] = kM01POIoverMpminus; + fgVarNamesMap["kM01POIoverMpplus"] = kM01POIoverMpplus; + fgVarNamesMap["kM01POIoverMpmoins"] = kM01POIoverMpmoins; + fgVarNamesMap["kM0111POIoverMpminus"] = kM0111POIoverMpminus; + fgVarNamesMap["kM0111POIoverMpplus"] = kM0111POIoverMpplus; + fgVarNamesMap["kCORR2POIplus"] = kCORR2POIplus; + fgVarNamesMap["kCORR2POIminus"] = kCORR2POIminus; + fgVarNamesMap["kCORR4POIplus"] = kCORR4POIplus; + fgVarNamesMap["kCORR4POIminus"] = kCORR4POIminus; + fgVarNamesMap["kM11REFoverMpminus"] = kM11REFoverMpminus; + fgVarNamesMap["kM11REFoverMpplus"] = kM11REFoverMpplus; + fgVarNamesMap["kM1111REFoverMpplus"] = kM1111REFoverMpplus; + fgVarNamesMap["kM1111REFoverMpminus"] = kM1111REFoverMpminus; + fgVarNamesMap["kCORR2REFetagap"] = kCORR2REFetagap; + fgVarNamesMap["kCORR2POI"] = kCORR2POI; + fgVarNamesMap["kCORR2POICORR4POI"] = kCORR2POICORR4POI; + fgVarNamesMap["kCORR2REFCORR4POI"] = kCORR2REFCORR4POI; + fgVarNamesMap["kCORR2REFCORR2POI"] = kCORR2REFCORR2POI; + fgVarNamesMap["kM01M0111overMp"] = kM01M0111overMp; + fgVarNamesMap["kM11M0111overMp"] = kM11M0111overMp; + fgVarNamesMap["kM11M01overMp"] = kM11M01overMp; + fgVarNamesMap["kCORR2CORR4REF"] = kCORR2CORR4REF; + fgVarNamesMap["kCORR4REF"] = kCORR4REF; + fgVarNamesMap["kCORR4REFbydimuons"] = kCORR4REFbydimuons; + fgVarNamesMap["kCORR4POI"] = kCORR4POI; + fgVarNamesMap["kM11REFoverMp"] = kM11REFoverMp; + fgVarNamesMap["kM01POIoverMp"] = kM01POIoverMp; + fgVarNamesMap["kM1111REFoverMp"] = kM1111REFoverMp; + fgVarNamesMap["kM0111POIoverMp"] = kM0111POIoverMp; + fgVarNamesMap["kCORR2POIMp"] = kCORR2POIMp; + fgVarNamesMap["kCORR4POIMp"] = kCORR4POIMp; + fgVarNamesMap["kM01POIME"] = kM01POIME; + fgVarNamesMap["kMultDimuonsME"] = kMultDimuonsME; + fgVarNamesMap["kM0111POIME"] = kM0111POIME; + fgVarNamesMap["kCORR2POIME"] = kCORR2POIME; + fgVarNamesMap["kCORR4POIME"] = kCORR4POIME; + fgVarNamesMap["kM01POIoverMpME"] = kM01POIoverMpME; + fgVarNamesMap["kM0111POIoverMpME"] = kM0111POIoverMpME; + fgVarNamesMap["kM11REFoverMpME"] = kM11REFoverMpME; + fgVarNamesMap["kM1111REFoverMpME"] = kM1111REFoverMpME; + fgVarNamesMap["kCORR2REFbydimuonsME"] = kCORR2REFbydimuonsME; + fgVarNamesMap["kCORR4REFbydimuonsME"] = kCORR4REFbydimuonsME; + fgVarNamesMap["kR2SP"] = kR2SP; + fgVarNamesMap["kR2EP"] = kR2EP; + fgVarNamesMap["kPsi2A"] = kPsi2A; + fgVarNamesMap["kPsi2APOS"] = kPsi2APOS; + fgVarNamesMap["kPsi2ANEG"] = kPsi2ANEG; + fgVarNamesMap["kPsi2B"] = kPsi2B; + fgVarNamesMap["kPsi2C"] = kPsi2C; + fgVarNamesMap["kCos2DeltaPhi"] = kCos2DeltaPhi; + fgVarNamesMap["kCos2DeltaPhiMu1"] = kCos2DeltaPhiMu1; + fgVarNamesMap["kCos2DeltaPhiMu2"] = kCos2DeltaPhiMu2; + fgVarNamesMap["kCos3DeltaPhi"] = kCos3DeltaPhi; + fgVarNamesMap["kDeltaPtotTracks"] = kDeltaPtotTracks; + fgVarNamesMap["kVertexingLxyOverErr"] = kVertexingLxyOverErr; + fgVarNamesMap["kVertexingLzOverErr"] = kVertexingLzOverErr; + fgVarNamesMap["kVertexingLxyzOverErr"] = kVertexingLxyzOverErr; + fgVarNamesMap["kKFTrack0DCAxyz"] = kKFTrack0DCAxyz; + fgVarNamesMap["kKFTrack1DCAxyz"] = kKFTrack1DCAxyz; + fgVarNamesMap["kKFTracksDCAxyzMax"] = kKFTracksDCAxyzMax; + fgVarNamesMap["kKFDCAxyzBetweenProngs"] = kKFDCAxyzBetweenProngs; + fgVarNamesMap["kKFTrack0DCAxy"] = kKFTrack0DCAxy; + fgVarNamesMap["kKFTrack1DCAxy"] = kKFTrack1DCAxy; + fgVarNamesMap["kKFTracksDCAxyMax"] = kKFTracksDCAxyMax; + fgVarNamesMap["kKFDCAxyBetweenProngs"] = kKFDCAxyBetweenProngs; + fgVarNamesMap["kKFTrack0DeviationFromPV"] = kKFTrack0DeviationFromPV; + fgVarNamesMap["kKFTrack1DeviationFromPV"] = kKFTrack1DeviationFromPV; + fgVarNamesMap["kKFTrack0DeviationxyFromPV"] = kKFTrack0DeviationxyFromPV; + fgVarNamesMap["kKFTrack1DeviationxyFromPV"] = kKFTrack1DeviationxyFromPV; + fgVarNamesMap["kKFChi2OverNDFGeo"] = kKFChi2OverNDFGeo; + fgVarNamesMap["kKFNContributorsPV"] = kKFNContributorsPV; + fgVarNamesMap["kKFCosPA"] = kKFCosPA; + fgVarNamesMap["kKFChi2OverNDFGeoTop"] = kKFChi2OverNDFGeoTop; + fgVarNamesMap["kKFJpsiDCAxyz"] = kKFJpsiDCAxyz; + fgVarNamesMap["kKFJpsiDCAxy"] = kKFJpsiDCAxy; + fgVarNamesMap["kKFPairDeviationFromPV"] = kKFPairDeviationFromPV; + fgVarNamesMap["kKFPairDeviationxyFromPV"] = kKFPairDeviationxyFromPV; + fgVarNamesMap["kNPairVariables"] = kNPairVariables; + fgVarNamesMap["kPairMass"] = kPairMass; + fgVarNamesMap["kPairMassDau"] = kPairMassDau; + fgVarNamesMap["kMassDau"] = kMassDau; + fgVarNamesMap["kPairPt"] = kPairPt; + fgVarNamesMap["kPairPtDau"] = kPairPtDau; + fgVarNamesMap["kPairEta"] = kPairEta; + fgVarNamesMap["kPairPhi"] = kPairPhi; + fgVarNamesMap["kPairPhiv"] = kPairPhiv; + fgVarNamesMap["kDeltaEta"] = kDeltaEta; + fgVarNamesMap["kDeltaPhi"] = kDeltaPhi; + fgVarNamesMap["kDeltaPhiSym"] = kDeltaPhiSym; + fgVarNamesMap["kNCorrelationVariables"] = kNCorrelationVariables; + fgVarNamesMap["kQuadMass"] = kQuadMass; + fgVarNamesMap["kQuadDefaultDileptonMass"] = kQuadDefaultDileptonMass; + fgVarNamesMap["kQuadPt"] = kQuadPt; + fgVarNamesMap["kQuadEta"] = kQuadEta; + fgVarNamesMap["kQuadPhi"] = kQuadPhi; + fgVarNamesMap["kCosthetaDileptonDitrack"] = kCosthetaDileptonDitrack; + fgVarNamesMap["kDitrackMass"] = kDitrackMass; + fgVarNamesMap["kDitrackPt"] = kDitrackPt; + fgVarNamesMap["kQ"] = kQ; + fgVarNamesMap["kDeltaR1"] = kDeltaR1; + fgVarNamesMap["kDeltaR2"] = kDeltaR2; + fgVarNamesMap["kMassCharmHadron"] = kMassCharmHadron; + fgVarNamesMap["kPtCharmHadron"] = kPtCharmHadron; + fgVarNamesMap["kRapCharmHadron"] = kRapCharmHadron; + fgVarNamesMap["kPhiCharmHadron"] = kPhiCharmHadron; + fgVarNamesMap["kBdtCharmHadron"] = kBdtCharmHadron; + fgVarNamesMap["kBitMapIndex"] = kBitMapIndex; + fgVarNamesMap["kDeltaMass"] = kDeltaMass; + fgVarNamesMap["kDeltaMass_jpsi"] = kDeltaMass_jpsi; + fgVarNamesMap["kV22m"] = kV22m; + fgVarNamesMap["kV24m"] = kV24m; + fgVarNamesMap["kV22p"] = kV22p; + fgVarNamesMap["kV24p"] = kV24p; + fgVarNamesMap["kV22ME"] = kV22ME; + fgVarNamesMap["kV24ME"] = kV24ME; + fgVarNamesMap["kWV22ME"] = kWV22ME; + fgVarNamesMap["kWV24ME"] = kWV24ME; } diff --git a/PWGDQ/Core/VarManager.h b/PWGDQ/Core/VarManager.h index 287046f465f..5a193eb0415 100644 --- a/PWGDQ/Core/VarManager.h +++ b/PWGDQ/Core/VarManager.h @@ -17,6 +17,8 @@ #ifndef PWGDQ_CORE_VARMANAGER_H_ #define PWGDQ_CORE_VARMANAGER_H_ +#include +#include #include #ifndef HomogeneousField #define HomogeneousField @@ -28,6 +30,7 @@ #include #include #include +#include #include #include @@ -36,6 +39,7 @@ #include "Math/Vector4D.h" #include "Math/Vector3D.h" #include "Math/GenVector/Boost.h" +#include "Math/VectorUtil.h" #include "Framework/DataTypes.h" #include "TGeoGlobalMagField.h" @@ -54,6 +58,7 @@ #include "DCAFitter/FwdDCAFitterN.h" #include "GlobalTracking/MatchGlobalFwd.h" #include "CommonConstants/PhysicsConstants.h" +#include "CommonConstants/LHCConstants.h" #include "KFParticle.h" #include "KFPTrack.h" @@ -94,6 +99,13 @@ class VarManager : public TObject EventFilter = BIT(12), CollisionQvect = BIT(13), ReducedEventQvectorExtra = BIT(14), + ReducedEventRefFlow = BIT(15), + Zdc = BIT(16), + ReducedZdc = BIT(17), + CollisionMultExtra = BIT(18), + ReducedEventMultExtra = BIT(19), + CollisionQvectCentr = BIT(20), + RapidityGapFilter = BIT(21), Track = BIT(0), TrackCov = BIT(1), TrackExtra = BIT(2), @@ -119,7 +131,9 @@ class VarManager : public TObject TrackTPCPID = BIT(22), TrackMFT = BIT(23), ReducedTrackCollInfo = BIT(24), // TODO: remove it once new reduced data tables are produced for dielectron with ReducedTracksBarrelInfo - ReducedMuonCollInfo = BIT(25) // TODO: remove it once new reduced data tables are produced for dielectron with ReducedTracksBarrelInfo + ReducedMuonCollInfo = BIT(25), // TODO: remove it once new reduced data tables are produced for dielectron with ReducedTracksBarrelInfo + MuonRealign = BIT(26), + MuonCovRealign = BIT(27) }; enum PairCandidateType { @@ -132,7 +146,11 @@ class VarManager : public TObject kBtoJpsiEEK, // e.g. B+ -> e+ e- K+ kXtoJpsiPiPi, // e.g. X(3872) -> J/psi pi+ pi- kChictoJpsiEE, // e.g. Chi_c1 -> J/psi e+ e- + kDstarToD0KPiPi, // e.g. D*+ -> D0 pi+ -> K- pi+ pi+ kTripleCandidateToEEPhoton, // e.g. chi_c -> e+ e- photon or pi0 -> e+ e- photon + kDecayToKPi, // e.g. D0 -> K+ pi- or cc. + kTripleCandidateToKPiPi, // e.g. D+ -> K- pi+ pi+ + kTripleCandidateToPKPi, // e.g. Lambda_c -> p K- pi+ kNMaxCandidateTypes }; @@ -163,17 +181,23 @@ class VarManager : public TObject // Event wise variables kTimestamp, + kTimeFromSOR, // Time since Start of Run (SOR) in minutes kCollisionTime, kCollisionTimeRes, kBC, + kBCOrbit, kIsPhysicsSelection, - kIsNoTFBorder, // No time frame border - kIsNoITSROFBorder, // No ITS read out frame border - kIsNoSameBunch, // No collisions with same T0 BC - kIsGoodZvtxFT0vsPV, // No collisions w/ difference between z_ {PV, tracks} and z_{PV FT0A-C} - kIsVertexITSTPC, // At least one ITS-TPC track - kIsVertexTOFmatched, // At least one TOF-matched track - kIsSel8, // TVX in Run3 + kIsNoTFBorder, // No time frame border + kIsNoITSROFBorder, // No ITS read out frame border (from event selection) + kIsNoITSROFBorderRecomputed, // No ITS read out frame border, computed here + kIsNoSameBunch, // No collisions with same T0 BC + kIsGoodZvtxFT0vsPV, // No collisions w/ difference between z_ {PV, tracks} and z_{PV FT0A-C} + kIsVertexITSTPC, // At least one ITS-TPC track + kIsVertexTOFmatched, // At least one TOF-matched track + kIsSel8, // TVX in Run3 && No time frame border && No ITS read out frame border (from event selection) + kIsGoodITSLayer3, // number of inactive chips on ITS layer 3 is below maximum allowed value + kIsGoodITSLayer0123, // numbers of inactive chips on ITS layers 0-3 are below maximum allowed values + kIsGoodITSLayersAll, // numbers of inactive chips on all ITS layers are below maximum allowed values kIsINT7, kIsEMC7, kIsINT7inMUON, @@ -210,13 +234,59 @@ class VarManager : public TObject kMultZNC, kMultTracklets, kMultDimuons, + kMultAntiMuons, + kMultMuons, + kMultSingleMuons, + kMultNTracksHasITS, + kMultNTracksHasTPC, + kMultNTracksHasTOF, + kMultNTracksHasTRD, + kMultNTracksITSOnly, + kMultNTracksTPCOnly, + kMultNTracksITSTPC, + kMultNTracksPVeta1, + kMultNTracksPVetaHalf, + kTrackOccupancyInTimeRange, + kFT0COccupancyInTimeRange, + kNoCollInTimeRangeStandard, + kMultAllTracksTPCOnly, + kMultAllTracksITSTPC, + kNTPCpileupContribA, + kNTPCpileupContribC, + kNTPCpileupZA, + kNTPCpileupZC, + kNTPCtracksInPast, + kNTPCtracksInFuture, + kNTPCcontribLongA, + kNTPCcontribLongC, + kNTPCmeanTimeLongA, + kNTPCmeanTimeLongC, + kNTPCmedianTimeLongA, + kNTPCmedianTimeLongC, + kNTPCcontribShortA, + kNTPCcontribShortC, + kNTPCmeanTimeShortA, + kNTPCmeanTimeShortC, + kNTPCmedianTimeShortA, + kNTPCmedianTimeShortC, kMCEventGeneratorId, + kMCEventSubGeneratorId, kMCVtxX, kMCVtxY, kMCVtxZ, kMCEventTime, kMCEventWeight, kMCEventImpParam, + kQ1ZNAX, + kQ1ZNAY, + kQ1ZNCX, + kQ1ZNCY, + KIntercalibZNA, + KIntercalibZNC, + kQ1ZNACXX, + kQ1ZNACYY, + kQ1ZNACYX, + kQ1ZNACXY, kQ1X0A, // q-vector (e.g. from TPC) with x component (harmonic 1 and power 0), sub-event A kQ1Y0A, // q-vector (e.g. from TPC) with y component (harmonic 1 and power 0), sub-event A kQ1X0B, @@ -233,6 +303,18 @@ class VarManager : public TObject kQ2Y0B, kQ2X0C, kQ2Y0C, + kQ2YYAB, + kQ2XXAB, + kQ2XYAB, + kQ2YXAB, + kQ2YYAC, + kQ2XXAC, + kQ2XYAC, + kQ2YXAC, + kQ2YYBC, + kQ2XXBC, + kQ2XYBC, + kQ2YXBC, kMultA, // Multiplicity of the sub-event A kMultAPOS, // Multiplicity of the sub-event A kMultANEG, // Multiplicity of the sub-event A @@ -250,8 +332,18 @@ class VarManager : public TObject kQ4Y0B, kQ4X0C, kQ4Y0C, - kR2SP, - kR2SP_FT0CFT0A, + kR2SP_AB, + kR2SP_AC, + kR2SP_BC, + kWR2SP_AB, + kWR2SP_AC, + kWR2SP_BC, + kR2SP_AB_Im, + kR2SP_AC_Im, + kR2SP_BC_Im, + kWR2SP_AB_Im, + kWR2SP_AC_Im, + kWR2SP_BC_Im, kR2SP_FT0CTPCPOS, kR2SP_FT0CTPCNEG, kR2SP_FT0ATPCPOS, @@ -261,8 +353,18 @@ class VarManager : public TObject kR2SP_FV0ATPCPOS, kR2SP_FV0ATPCNEG, kR3SP, - kR2EP, - kR2EP_FT0CFT0A, + kR2EP_AB, + kR2EP_AC, + kR2EP_BC, + kWR2EP_AB, + kWR2EP_AC, + kWR2EP_BC, + kR2EP_AB_Im, + kR2EP_AC_Im, + kR2EP_BC_Im, + kWR2EP_AB_Im, + kWR2EP_AC_Im, + kWR2EP_BC_Im, kR2EP_FT0CTPCPOS, kR2EP_FT0CTPCNEG, kR2EP_FT0ATPCPOS, @@ -276,27 +378,66 @@ class VarManager : public TObject kIsSingleGapA, // Rapidity gap on side A kIsSingleGapC, // Rapidity gap on side C kIsSingleGap, // Rapidity gap on either side + kIsITSUPCMode, // UPC mode used for event kTwoEvPosZ1, // vtx-z for collision 1 in two events correlations kTwoEvPosZ2, // vtx-z for collision 2 in two events correlations kTwoEvPosR1, // vtx-R for collision 1 in two events correlations kTwoEvPosR2, + kTwoEvCentFT0C1, + kTwoEvCentFT0C2, kTwoEvPVcontrib1, // n-contributors for collision 1 in two events correlations kTwoEvPVcontrib2, kTwoEvDeltaZ, // distance in z between collisions kTwoEvDeltaX, // distance in x between collisions kTwoEvDeltaY, // distance in y between collisions kTwoEvDeltaR, // distance in (x,y) plane between collisions - kNEventWiseVariables, + kEnergyCommonZNA, + kEnergyCommonZNC, + kEnergyCommonZPA, + kEnergyCommonZPC, + kEnergyZNA1, + kEnergyZNA2, + kEnergyZNA3, + kEnergyZNA4, + kEnergyZNC1, + kEnergyZNC2, + kEnergyZNC3, + kEnergyZNC4, + kTimeZNA, + kTimeZNC, + kTimeZPA, + kTimeZPC, kQ2X0A1, kQ2X0A2, kQ2Y0A1, kQ2Y0A2, kU2Q2Ev1, kU2Q2Ev2, + kCos2DeltaPhiEv1, + kCos2DeltaPhiEv2, + kV2SP1, + kV2SP2, + kV2EP1, + kV2EP2, + kV2ME_SP, + kV2ME_EP, + kWV2ME_SP, + kWV2ME_EP, kTwoR2SP1, // Scalar product resolution of event1 for ME technique kTwoR2SP2, // Scalar product resolution of event2 for ME technique kTwoR2EP1, // Event plane resolution of event2 for ME technique kTwoR2EP2, // Event plane resolution of event2 for ME technique + kNEventWiseVariables, + + // Variables for event mixing with cumulant + kV22m, + kV24m, + kV22p, + kV24p, + kV22ME, + kV24ME, + kWV22ME, + kWV24ME, // Basic track/muon/pair wise variables kX, @@ -318,11 +459,14 @@ class VarManager : public TObject kNBasicTrackVariables, kUsedKF, kKFMass, + kKFMassGeoTop, kPt1, kEta1, kPhi1, kCharge1, + kPin_leg1, + kTPCnSigmaKa_leg1, kPt2, kEta2, kPhi2, @@ -357,6 +501,7 @@ class VarManager : public TObject kTPCncls, kITSClusterMap, kTPCnclsCR, + kTPCnCRoverFindCls, kTPCchi2, kTPCsignal, kTPCsignalRandomized, @@ -368,7 +513,11 @@ class VarManager : public TObject kTOFbeta, kTrackLength, kTrackDCAxy, + kTrackDCAxyProng1, + kTrackDCAxyProng2, kTrackDCAz, + kTrackDCAzProng1, + kTrackDCAzProng2, kTrackDCAsigXY, kTrackDCAsigZ, kTrackDCAresXY, @@ -446,6 +595,8 @@ class VarManager : public TObject kMftNClusters, kMftClusterSize, kMftMeanClusterSize, + kMuonNAssocsInBunch, + kMuonNAssocsOutOfBunch, kNMuonTrackVariables, // MC particle variables @@ -454,6 +605,7 @@ class VarManager : public TObject kMCPx, kMCPy, kMCPz, + kMCMass, kMCE, kMCVx, kMCVy, @@ -485,7 +637,9 @@ class VarManager : public TObject kVertexingLxyzProjected, kVertexingTauzProjected, kVertexingTauxyProjected, + kVertexingTauxyProjectedPoleJPsiMass, kVertexingTauxyProjectedNs, + kVertexingTauxyzProjected, kVertexingTauz, kVertexingTauzErr, kVertexingPz, @@ -496,6 +650,10 @@ class VarManager : public TObject kCosThetaCS, kPhiHE, kPhiCS, + kCosPhiVP, + kPhiVP, + kDeltaPhiPair2, + kDeltaEtaPair2, kPsiPair, kDeltaPhiPair, kOpeningAngle, @@ -510,6 +668,10 @@ class VarManager : public TObject kImpParXYK, kDCATrackProd, kDCATrackVtxProd, + kV2SP, + kV2EP, + kWV2SP, + kWV2EP, kU2Q2, kU3Q3, kQ42XA, @@ -518,23 +680,76 @@ class VarManager : public TObject kQ23YA, kS11A, kS12A, - kS21A, kS13A, kS31A, - kS22A, - kS41A, - kS14A, kM11REF, + kM11REFetagap, kM01POI, kM1111REF, + kM11M1111REF, + kM11M1111REFoverMp, + kM01M0111POIoverMp, kM0111POI, kCORR2REF, + kCORR2REFbydimuons, + kCORR2REFbysinglemu, + kCORR2REFetagap, kCORR2POI, + kCORR2POICORR4POI, + kCORR2REFCORR4POI, + kCORR2REFCORR2POI, + kM01M0111overMp, + kM11M0111overMp, + kM11M01overMp, + kCORR2CORR4REF, kCORR4REF, + kCORR4REFbydimuons, + kCORR4REFbysinglemu, kCORR4POI, - kC4REF, - kC4POI, - kV4, + kM11REFoverMp, + kM01POIoverMp, + kM1111REFoverMp, + kM0111POIoverMp, + kCORR2POIMp, + kCORR4POIMp, + kM01POIplus, + kM0111POIplus, + kM01POIminus, + kM0111POIminus, + kM01POIsingle, + kM0111POIsingle, + kM01POIoverMpminus, + kM01POIoverMpplus, + kM01POIoverMpsingle, + kM01POIoverMpmoins, + kM0111POIoverMpminus, + kM0111POIoverMpplus, + kM0111POIoverMpsingle, + kCORR2POIplus, + kCORR2POIminus, + kCORR2POIsingle, + kCORR4POIplus, + kCORR4POIminus, + kCORR4POIsingle, + kM11REFoverMpplus, + kM1111REFoverMpplus, + kM11REFoverMpminus, + kM1111REFoverMpminus, + kM11REFoverMpsingle, + kM1111REFoverMpsingle, + kM01POIME, + kMultDimuonsME, + kM0111POIME, + kCORR2POIME, + kCORR4POIME, + kM01POIoverMpME, + kM0111POIoverMpME, + kM11REFoverMpME, + kM1111REFoverMpME, + kCORR2REFbydimuonsME, + kCORR4REFbydimuonsME, + kR2SP, + kR2EP, kPsi2A, kPsi2APOS, kPsi2ANEG, @@ -556,9 +771,18 @@ class VarManager : public TObject kKFTrack1DCAxy, kKFTracksDCAxyMax, kKFDCAxyBetweenProngs, + kKFTrack0DeviationFromPV, + kKFTrack1DeviationFromPV, + kKFTrack0DeviationxyFromPV, + kKFTrack1DeviationxyFromPV, kKFChi2OverNDFGeo, kKFNContributorsPV, kKFCosPA, + kKFChi2OverNDFGeoTop, + kKFJpsiDCAxyz, + kKFJpsiDCAxy, + kKFPairDeviationFromPV, + kKFPairDeviationxyFromPV, kNPairVariables, // Candidate-track correlation variables @@ -577,12 +801,17 @@ class VarManager : public TObject // Dilepton-track-track variables kQuadMass, + kQuadDefaultDileptonMass, kQuadPt, kQuadEta, kQuadPhi, kCosthetaDileptonDitrack, kDitrackMass, kDitrackPt, + kQ, + kDeltaR1, + kDeltaR2, + kDeltaR, // DQ-HF correlation variables kMassCharmHadron, @@ -623,7 +852,8 @@ class VarManager : public TObject enum EventFilters { kDoubleGap = 0, kSingleGapA, - kSingleGapC + kSingleGapC, + kITSUPCMode }; enum MuonExtrapolation { @@ -635,6 +865,7 @@ class VarManager : public TObject static TString fgVariableNames[kNVars]; // variable names static TString fgVariableUnits[kNVars]; // variable units + static std::map fgVarNamesMap; // key: variables short name, value: order in the Variables enum static void SetDefaultVarNames(); static void SetUseVariable(int var) @@ -758,8 +989,14 @@ class VarManager : public TObject } // Setup the 3 prong DCAFitterN - static void SetupThreeProngDCAFitter() + static void SetupThreeProngDCAFitter(float magField, bool propagateToPCA, float maxR, float /*maxDZIni*/, float minParamChange, float minRelChi2Change, bool useAbsDCA) { + fgFitterThreeProngBarrel.setBz(magField); + fgFitterThreeProngBarrel.setPropagateToPCA(propagateToPCA); + fgFitterThreeProngBarrel.setMaxR(maxR); + fgFitterThreeProngBarrel.setMinParamChange(minParamChange); + fgFitterThreeProngBarrel.setMinRelChi2Change(minRelChi2Change); + fgFitterThreeProngBarrel.setUseAbsDCA(useAbsDCA); fgUsedKF = false; } @@ -788,12 +1025,22 @@ class VarManager : public TObject static void FillMuonPDca(const T& muon, const C& collision, float* values = nullptr); template static void FillPropagateMuon(const T& muon, const C& collision, float* values = nullptr); + template + static void FillBC(T const& bc, float* values = nullptr); template static void FillEvent(T const& event, float* values = nullptr); + template + static void FillEventTrackEstimators(TEvent const& collision, TAssoc const& groupedTrackIndices, TTracks const& tracks, float* values = nullptr); + template + static void FillEventFlowResoFactor(T const& hs_sp, T const& hs_ep, float* values = nullptr); template static void FillTwoEvents(T const& event1, T const& event2, float* values = nullptr); template static void FillTwoMixEvents(T1 const& event1, T1 const& event2, T2 const& tracks1, T2 const& tracks2, float* values = nullptr); + template + static void FillTwoMixEventsFlowResoFactor(T const& hs_sp, T const& hs_ep, float* values = nullptr); + template + static void FillTwoMixEventsCumulants(T const& h_v22m, T const& h_v24m, T const& h_v22p, T const& h_v24p, T1 const& t1, T2 const& t2, float* values = nullptr); template static void FillTrack(T const& track, float* values = nullptr); template @@ -806,18 +1053,28 @@ class VarManager : public TObject static void FillTrackMC(const U& mcStack, T const& track, float* values = nullptr); template static void FillPairPropagateMuon(T1 const& muon1, T2 const& muon2, const C& collision, float* values = nullptr); + template + static void FillGlobalMuonRefit(T1 const& muontrack, T2 const& mfttrack, const C& collision, float* values = nullptr); template static void FillPair(T1 const& t1, T2 const& t2, float* values = nullptr); + template + static void FillPairCollision(C const& collision, T1 const& t1, T2 const& t2, float* values = nullptr); + template + static void FillPairCollisionMatCorr(C const& collision, T1 const& t1, T2 const& t2, M const& materialCorr, P const& propagator, float* values = nullptr); template static void FillTriple(T1 const& t1, T2 const& t2, T3 const& t3, float* values = nullptr, PairCandidateType pairType = kTripleCandidateToEEPhoton); - template + template static void FillPairME(T1 const& t1, T2 const& t2, float* values = nullptr); - template - static void FillPairMC(T1 const& t1, T2 const& t2, float* values = nullptr, PairCandidateType pairType = kDecayToEE); + template + static void FillPairMC(T1 const& t1, T2 const& t2, float* values = nullptr); template static void FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* values = nullptr, PairCandidateType pairType = kTripleCandidateToEEPhoton); + template + static void FillQaudMC(T1 const& t1, T2 const& t2, T2 const& t3, float* values = nullptr); template static void FillPairVertexing(C const& collision, T const& t1, T const& t2, bool propToSV = false, float* values = nullptr); + template + static void FillTripletVertexing(C const& collision, T const& t1, T const& t2, T const& t3, PairCandidateType tripletType, float* values = nullptr); template static void FillDileptonTrackVertexing(C const& collision, T1 const& lepton1, T1 const& lepton2, T1 const& track, float* values); template @@ -834,10 +1091,16 @@ class VarManager : public TObject static void FillQVectorFromGFW(C const& collision, A const& compA11, A const& compB11, A const& compC11, A const& compA21, A const& compB21, A const& compC21, A const& compA31, A const& compB31, A const& compC31, A const& compA41, A const& compB41, A const& compC41, A const& compA23, A const& compA42, float S10A = 1.0, float S10B = 1.0, float S10C = 1.0, float S11A = 1.0, float S11B = 1.0, float S11C = 1.0, float S12A = 1.0, float S13A = 1.0, float S14A = 1.0, float S21A = 1.0, float S22A = 1.0, float S31A = 1.0, float S41A = 1.0, float* values = nullptr); template static void FillQVectorFromCentralFW(C const& collision, float* values = nullptr); + template + static void FillNewQVectorFromCentralFW(C const& collision, float* values = nullptr); + template + static void FillSpectatorPlane(C const& collision, float* values = nullptr); template static void FillPairVn(T1 const& t1, T2 const& t2, float* values = nullptr); template static void FillDileptonTrackTrack(T1 const& dilepton, T2 const& hadron1, T3 const& hadron2, float* values = nullptr); + template + static void FillZDC(const T& zdc, float* values = nullptr); static void SetCalibrationObject(CalibObjects calib, TObject* obj) { @@ -869,6 +1132,19 @@ class VarManager : public TObject { fgTPCInterSectorBoundary = boundarySize; } + static void SetITSROFBorderselection(int bias, int length, int marginLow, int marginHigh) + { + fgITSROFbias = bias; + fgITSROFlength = length; + fgITSROFBorderMarginLow = marginLow; + fgITSROFBorderMarginHigh = marginHigh; + } + + static void SetSORandEOR(uint64_t sor, uint64_t eor) + { + fgSOR = sor; + fgEOR = eor; + } public: VarManager(); @@ -889,6 +1165,12 @@ class VarManager : public TObject static float fgCenterOfMassEnergy; // collision energy static float fgMassofCollidingParticle; // mass of the colliding particle static float fgTPCInterSectorBoundary; // TPC inter-sector border size at the TPC outer radius, in cm + static int fgITSROFbias; // ITS ROF bias (from ALPIDE parameters) + static int fgITSROFlength; // ITS ROF length (from ALPIDE parameters) + static int fgITSROFBorderMarginLow; // ITS ROF border low margin + static int fgITSROFBorderMarginHigh; // ITS ROF border high margin + static uint64_t fgSOR; // Timestamp for start of run + static uint64_t fgEOR; // Timestamp for end of run static void FillEventDerived(float* values = nullptr); static void FillTrackDerived(float* values = nullptr); @@ -901,6 +1183,8 @@ class VarManager : public TObject template static KFPVertex createKFPVertexFromCollision(const T& collision); static float calculateCosPA(KFParticle kfp, KFParticle PV); + template + static float calculatePhiV(const T1& t1, const T2& t2); static o2::vertexing::DCAFitterN<2> fgFitterTwoProngBarrel; static o2::vertexing::DCAFitterN<3> fgFitterThreeProngBarrel; @@ -997,8 +1281,8 @@ KFPVertex VarManager::createKFPVertexFromCollision(const T& collision) kfpVertex.SetXYZ(collision.posX(), collision.posY(), collision.posZ()); kfpVertex.SetCovarianceMatrix(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); kfpVertex.SetChi2(collision.chi2()); - kfpVertex.SetNDF(2 * collision.multNTracksPV() - 3); - kfpVertex.SetNContributors(collision.multNTracksPV()); + kfpVertex.SetNDF(2 * collision.numContrib() - 3); + kfpVertex.SetNContributors(collision.numContrib()); return kfpVertex; } @@ -1081,7 +1365,7 @@ void VarManager::FillPropagateMuon(const T& muon, const C& collision, float* val } } - if constexpr ((fillMap & MuonCov) > 0 || (fillMap & ReducedMuonCov) > 0) { + if constexpr ((fillMap & MuonCov) > 0 || (fillMap & ReducedMuonCov) > 0 || (fillMap & MuonCovRealign) > 0) { o2::dataformats::GlobalFwdTrack propmuon = PropagateMuon(muon, collision); values[kPt] = propmuon.getPt(); values[kX] = propmuon.getX(); @@ -1124,6 +1408,43 @@ void VarManager::FillPropagateMuon(const T& muon, const C& collision, float* val } } +template +void VarManager::FillGlobalMuonRefit(T1 const& muontrack, T2 const& mfttrack, const C& collision, float* values) +{ + if (!values) { + values = fgValues; + } + if constexpr ((fillMap & MuonCov) > 0 || (fillMap & ReducedMuonCov) > 0) { + o2::dataformats::GlobalFwdTrack propmuon = PropagateMuon(muontrack, collision); + double px = propmuon.getP() * sin(M_PI / 2 - atan(mfttrack.tgl())) * cos(mfttrack.phi()); + double py = propmuon.getP() * sin(M_PI / 2 - atan(mfttrack.tgl())) * sin(mfttrack.phi()); + double pz = propmuon.getP() * cos(M_PI / 2 - atan(mfttrack.tgl())); + double pt = std::sqrt(std::pow(px, 2) + std::pow(py, 2)); + values[kX] = mfttrack.x(); + values[kY] = mfttrack.y(); + values[kZ] = mfttrack.z(); + values[kTgl] = mfttrack.tgl(); + values[kPt] = pt; + values[kPz] = pz; + values[kEta] = mfttrack.eta(); + values[kPhi] = mfttrack.phi(); + } +} + +template +void VarManager::FillBC(T const& bc, float* values) +{ + if (!values) { + values = fgValues; + } + values[kRunNo] = bc.runNumber(); + values[kBC] = bc.globalBC(); + values[kBCOrbit] = bc.globalBC() % o2::constants::lhc::LHCMaxBunches; + values[kTimestamp] = bc.timestamp(); + values[kTimeFromSOR] = (fgSOR > 0 ? (bc.timestamp() - fgSOR) / 60000. : -1.0); + values[kRunIndex] = GetRunIndex(bc.runNumber()); +} + template void VarManager::FillEvent(T const& event, float* values) { @@ -1142,6 +1463,15 @@ void VarManager::FillEvent(T const& event, float* values) if (fgUsedVars[kIsNoITSROFBorder]) { values[kIsNoITSROFBorder] = event.selection_bit(o2::aod::evsel::kNoITSROFrameBorder); } + if (fgUsedVars[kTrackOccupancyInTimeRange]) { + values[kTrackOccupancyInTimeRange] = event.trackOccupancyInTimeRange(); + } + if (fgUsedVars[kFT0COccupancyInTimeRange]) { + values[kFT0COccupancyInTimeRange] = event.ft0cOccupancyInTimeRange(); + } + if (fgUsedVars[kNoCollInTimeRangeStandard]) { + values[kNoCollInTimeRangeStandard] = event.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard); + } if (fgUsedVars[kIsNoTFBorder]) { values[kIsNoTFBorder] = event.selection_bit(o2::aod::evsel::kNoTimeFrameBorder); } @@ -1158,7 +1488,16 @@ void VarManager::FillEvent(T const& event, float* values) values[kIsVertexTOFmatched] = event.selection_bit(o2::aod::evsel::kIsVertexTOFmatched); } if (fgUsedVars[kIsSel8]) { - values[kIsSel8] = event.selection_bit(o2::aod::evsel::kIsTriggerTVX); + values[kIsSel8] = event.selection_bit(o2::aod::evsel::kIsTriggerTVX) && event.selection_bit(o2::aod::evsel::kNoITSROFrameBorder) && event.selection_bit(o2::aod::evsel::kNoTimeFrameBorder); + } + if (fgUsedVars[kIsGoodITSLayer3]) { + values[kIsGoodITSLayer3] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayer3); + } + if (fgUsedVars[kIsGoodITSLayer0123]) { + values[kIsGoodITSLayer0123] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123); + } + if (fgUsedVars[kIsGoodITSLayersAll]) { + values[kIsGoodITSLayersAll] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll); } if (fgUsedVars[kIsINT7]) { values[kIsINT7] = (event.alias_bit(kINT7) > 0); @@ -1217,18 +1556,57 @@ void VarManager::FillEvent(T const& event, float* values) } if constexpr ((fillMap & CollisionMult) > 0 || (fillMap & ReducedEventExtended) > 0) { + if constexpr ((fillMap & RapidityGapFilter) > 0) { + // UPC: Use the FIT signals from the nearest BC with FIT amplitude above threshold + values[kMultFV0A] = event.newBcMultFV0A(); + values[kMultFT0A] = event.newBcMultFT0A(); + values[kMultFT0C] = event.newBcMultFT0C(); + values[kMultFDDA] = event.newBcMultFDDA(); + values[kMultFDDC] = event.newBcMultFDDC(); + } else { + values[kMultFV0A] = event.multFV0A(); + values[kMultFT0A] = event.multFT0A(); + values[kMultFT0C] = event.multFT0C(); + values[kMultFDDA] = event.multFDDA(); + values[kMultFDDC] = event.multFDDC(); + } values[kMultTPC] = event.multTPC(); - values[kMultFV0A] = event.multFV0A(); values[kMultFV0C] = event.multFV0C(); - values[kMultFT0A] = event.multFT0A(); - values[kMultFT0C] = event.multFT0C(); - values[kMultFDDA] = event.multFDDA(); - values[kMultFDDC] = event.multFDDC(); values[kMultZNA] = event.multZNA(); values[kMultZNC] = event.multZNC(); values[kMultTracklets] = event.multTracklets(); values[kVtxNcontribReal] = event.multNTracksPV(); } + + if constexpr ((fillMap & CollisionMultExtra) > 0 || (fillMap & ReducedEventMultExtra) > 0) { + values[kMultNTracksHasITS] = event.multNTracksHasITS(); + values[kMultNTracksHasTPC] = event.multNTracksHasTPC(); + values[kMultNTracksHasTOF] = event.multNTracksHasTOF(); + values[kMultNTracksHasTRD] = event.multNTracksHasTRD(); + values[kMultNTracksITSOnly] = event.multNTracksITSOnly(); + values[kMultNTracksTPCOnly] = event.multNTracksTPCOnly(); + values[kMultNTracksITSTPC] = event.multNTracksITSTPC(); + values[kMultNTracksPVeta1] = event.multNTracksPVeta1(); + values[kMultNTracksPVetaHalf] = event.multNTracksPVetaHalf(); + values[kMultAllTracksTPCOnly] = event.multAllTracksTPCOnly(); + values[kMultAllTracksITSTPC] = event.multAllTracksITSTPC(); + values[kTrackOccupancyInTimeRange] = event.trackOccupancyInTimeRange(); + values[kFT0COccupancyInTimeRange] = event.ft0cOccupancyInTimeRange(); + if constexpr ((fillMap & ReducedEventMultExtra) > 0) { + values[kNTPCcontribLongA] = event.nTPCoccupContribLongA(); + values[kNTPCcontribLongC] = event.nTPCoccupContribLongC(); + values[kNTPCcontribShortA] = event.nTPCoccupContribShortA(); + values[kNTPCcontribShortC] = event.nTPCoccupContribShortC(); + values[kNTPCmeanTimeLongA] = event.nTPCoccupMeanTimeLongA(); + values[kNTPCmeanTimeLongC] = event.nTPCoccupMeanTimeLongC(); + values[kNTPCmeanTimeShortA] = event.nTPCoccupMeanTimeShortA(); + values[kNTPCmeanTimeShortC] = event.nTPCoccupMedianTimeShortC(); + values[kNTPCmedianTimeLongA] = event.nTPCoccupMedianTimeLongA(); + values[kNTPCmedianTimeLongC] = event.nTPCoccupMedianTimeLongC(); + values[kNTPCmedianTimeShortA] = event.nTPCoccupMedianTimeShortA(); + values[kNTPCmedianTimeShortC] = event.nTPCoccupMedianTimeShortC(); + } + } // TODO: need to add EvSels and Cents tables, etc. in case of the central data model if constexpr ((fillMap & ReducedEvent) > 0) { @@ -1238,12 +1616,41 @@ void VarManager::FillEvent(T const& event, float* values) values[kVtxY] = event.posY(); values[kVtxZ] = event.posZ(); values[kVtxNcontrib] = event.numContrib(); + if (fgUsedVars[kIsDoubleGap]) { + values[kIsDoubleGap] = (event.tag_bit(56 + kDoubleGap) > 0); + } + if (fgUsedVars[kIsSingleGap] || fgUsedVars[kIsSingleGapA] || fgUsedVars[kIsSingleGapC]) { + values[kIsSingleGapA] = (event.tag_bit(56 + kSingleGapA) > 0); + values[kIsSingleGapC] = (event.tag_bit(56 + kSingleGapC) > 0); + values[kIsSingleGap] = values[kIsSingleGapA] || values[kIsSingleGapC]; + } + if (fgUsedVars[kIsITSUPCMode]) { + values[kIsITSUPCMode] = (event.tag_bit(56 + kITSUPCMode) > 0); + } + values[kCollisionTime] = event.collisionTime(); + values[kCollisionTimeRes] = event.collisionTimeRes(); + } + + if constexpr ((fillMap & ReducedEventExtended) > 0) { + values[kBC] = event.globalBC(); + values[kBCOrbit] = event.globalBC() % o2::constants::lhc::LHCMaxBunches; + values[kTimestamp] = event.timestamp(); + values[kTimeFromSOR] = (fgSOR > 0 ? (event.timestamp() - fgSOR) / 60000. : -1.0); + values[kCentVZERO] = event.centRun2V0M(); + values[kCentFT0C] = event.centFT0C(); + if (fgUsedVars[kIsNoITSROFBorderRecomputed]) { + uint16_t bcInITSROF = (event.globalBC() + 3564 - fgITSROFbias) % fgITSROFlength; + values[kIsNoITSROFBorderRecomputed] = bcInITSROF > fgITSROFBorderMarginLow && bcInITSROF < fgITSROFlength - fgITSROFBorderMarginHigh ? 1.0 : 0.0; + } if (fgUsedVars[kIsNoITSROFBorder]) { values[kIsNoITSROFBorder] = (event.selection_bit(o2::aod::evsel::kNoITSROFrameBorder) > 0); } if (fgUsedVars[kIsNoTFBorder]) { values[kIsNoTFBorder] = (event.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) > 0); } + if (fgUsedVars[kNoCollInTimeRangeStandard]) { + values[kNoCollInTimeRangeStandard] = (event.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) > 0); + } if (fgUsedVars[kIsNoSameBunch]) { values[kIsNoSameBunch] = (event.selection_bit(o2::aod::evsel::kNoSameBunchPileup) > 0); } @@ -1257,25 +1664,17 @@ void VarManager::FillEvent(T const& event, float* values) values[kIsVertexTOFmatched] = (event.selection_bit(o2::aod::evsel::kIsVertexTOFmatched) > 0); } if (fgUsedVars[kIsSel8]) { - values[kIsSel8] = (event.selection_bit(o2::aod::evsel::kIsTriggerTVX) > 0); + values[kIsSel8] = event.selection_bit(o2::aod::evsel::kIsTriggerTVX) && event.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && event.selection_bit(o2::aod::evsel::kNoITSROFrameBorder); } - if (fgUsedVars[kIsDoubleGap]) { - values[kIsDoubleGap] = (event.tag_bit(56 + kDoubleGap) > 0); + if (fgUsedVars[kIsGoodITSLayer3]) { + values[kIsGoodITSLayer3] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayer3); } - if (fgUsedVars[kIsSingleGap] || fgUsedVars[kIsSingleGapA] || fgUsedVars[kIsSingleGapC]) { - values[kIsSingleGapA] = (event.tag_bit(56 + kSingleGapA) > 0); - values[kIsSingleGapC] = (event.tag_bit(56 + kSingleGapC) > 0); - values[kIsSingleGap] = values[kIsSingleGapA] || values[kIsSingleGapC]; + if (fgUsedVars[kIsGoodITSLayer0123]) { + values[kIsGoodITSLayer0123] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123); + } + if (fgUsedVars[kIsGoodITSLayersAll]) { + values[kIsGoodITSLayersAll] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll); } - values[kCollisionTime] = event.collisionTime(); - values[kCollisionTimeRes] = event.collisionTimeRes(); - } - - if constexpr ((fillMap & ReducedEventExtended) > 0) { - values[kBC] = event.globalBC(); - values[kTimestamp] = event.timestamp(); - values[kCentVZERO] = event.centRun2V0M(); - values[kCentFT0C] = event.centFT0C(); if (fgUsedVars[kIsINT7]) { values[kIsINT7] = (event.alias_bit(kINT7) > 0); } @@ -1350,6 +1749,15 @@ void VarManager::FillEvent(T const& event, float* values) values[kQ4X0C] = event.q4x0c(); values[kQ4Y0C] = event.q4y0c(); + EventPlaneHelper epHelper; + float Psi2A = epHelper.GetEventPlane(values[kQ2X0A], values[kQ2Y0A], 2); + float Psi2B = epHelper.GetEventPlane(values[kQ2X0B], values[kQ2Y0B], 2); + float Psi2C = epHelper.GetEventPlane(values[kQ2X0C], values[kQ2Y0C], 2); + + values[VarManager::kPsi2A] = Psi2A; + values[VarManager::kPsi2B] = Psi2B; + values[VarManager::kPsi2C] = Psi2C; + if constexpr ((fillMap & ReducedEventQvectorExtra) > 0) { values[kQ42XA] = event.q42xa(); values[kQ42YA] = event.q42ya(); @@ -1361,17 +1769,17 @@ void VarManager::FillEvent(T const& event, float* values) values[kS31A] = event.s31a(); } - values[kR2SP] = (event.q2x0b() * event.q2x0c() + event.q2y0b() * event.q2y0c()); - values[kR3SP] = (event.q3x0b() * event.q3x0c() + event.q3y0b() * event.q3y0c()); - if (event.q2y0b() * event.q2y0c() != 0.0) { - values[kR2EP] = TMath::Cos(2 * (getEventPlane(2, event.q2x0b(), event.q2y0b()) - getEventPlane(2, event.q2x0c(), event.q2y0c()))); + if constexpr ((fillMap & ReducedEventRefFlow) > 0) { + values[kMultA] = event.multa(); + values[kCORR2REFetagap] = event.corr2refetagap(); + values[kM11REFetagap] = event.m11refetagap(); + values[kCORR2REF] = std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : event.corr2ref(); + values[kCORR4REF] = std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : event.corr4ref(); + values[kCORR2CORR4REF] = std::isnan(values[kM11M1111REF]) || std::isinf(values[kM11M1111REF]) || std::isnan(values[kCORR2CORR4REF]) || std::isinf(values[kCORR2CORR4REF]) ? 0 : event.corr2ref() * event.corr4ref(); + values[kM11REF] = !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? event.m11ref() : 0; + values[kM1111REF] = !(std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF])) ? event.m1111ref() : 0; + values[kM11M1111REF] = !(std::isnan(values[kM11M1111REF]) || std::isinf(values[kM11M1111REF]) || std::isnan(values[kCORR2CORR4REF]) || std::isinf(values[kCORR2CORR4REF])) ? event.m11ref() * event.m1111ref() : 0; } - if (event.q3y0b() * event.q3y0c() != 0.0) { - values[kR3EP] = TMath::Cos(3 * (getEventPlane(3, event.q3x0b(), event.q3y0b()) - getEventPlane(3, event.q3x0c(), event.q3y0c()))); - } - values[kPsi2A] = getEventPlane(2, event.q2x0a(), event.q2y0a()); - values[kPsi2B] = getEventPlane(2, event.q2x0b(), event.q2y0b()); - values[kPsi2C] = getEventPlane(2, event.q2x0c(), event.q2y0c()); } if constexpr ((fillMap & CollisionQvect) > 0) { @@ -1381,8 +1789,8 @@ void VarManager::FillEvent(T const& event, float* values) values[kQ1Y0B] = -999; values[kQ1X0C] = -999; values[kQ1Y0C] = -999; - values[kQ2X0A] = event.qvecBPosRe(); - values[kQ2Y0A] = event.qvecBPosIm(); + values[kQ2X0A] = (event.qvecBPosRe() * event.nTrkBPos() + event.qvecBNegRe() * event.nTrkBNeg()) / (event.nTrkBPos() + event.nTrkBNeg()); + values[kQ2Y0A] = (event.qvecBPosIm() * event.nTrkBPos() + event.qvecBNegIm() * event.nTrkBNeg()) / (event.nTrkBPos() + event.nTrkBNeg()); values[kQ2X0APOS] = event.qvecBPosRe(); values[kQ2Y0APOS] = event.qvecBPosIm(); values[kQ2X0ANEG] = event.qvecBNegRe(); @@ -1391,7 +1799,7 @@ void VarManager::FillEvent(T const& event, float* values) values[kQ2Y0B] = event.qvecFT0AIm(); values[kQ2X0C] = event.qvecFT0CRe(); values[kQ2Y0C] = event.qvecFT0CIm(); - values[kMultA] = event.nTrkBPos(); + values[kMultA] = event.nTrkBPos() + event.nTrkBNeg(); values[kMultAPOS] = event.nTrkBPos(); values[kMultANEG] = event.nTrkBNeg(); values[kMultB] = event.sumAmplFT0A(); @@ -1408,10 +1816,62 @@ void VarManager::FillEvent(T const& event, float* values) values[kQ4Y0B] = -999; values[kQ4X0C] = -999; values[kQ4Y0C] = -999; + + EventPlaneHelper epHelper; + float Psi2A = epHelper.GetEventPlane(values[kQ2X0A], values[kQ2Y0A], 2); + float Psi2APOS = epHelper.GetEventPlane(values[kQ2X0APOS], values[kQ2Y0APOS], 2); + float Psi2ANEG = epHelper.GetEventPlane(values[kQ2X0ANEG], values[kQ2Y0ANEG], 2); + float Psi2B = epHelper.GetEventPlane(values[kQ2X0B], values[kQ2Y0B], 2); + float Psi2C = epHelper.GetEventPlane(values[kQ2X0C], values[kQ2Y0C], 2); + + values[kPsi2A] = Psi2A; + values[kPsi2APOS] = Psi2APOS; + values[kPsi2ANEG] = Psi2ANEG; + values[kPsi2B] = Psi2B; + values[kPsi2C] = Psi2C; + + float R2SP_AB = (values[kQ2X0A] * values[kQ2X0B] + values[kQ2Y0A] * values[kQ2Y0B]); + float R2SP_AC = (values[kQ2X0A] * values[kQ2X0C] + values[kQ2Y0A] * values[kQ2Y0C]); + float R2SP_BC = (values[kQ2X0B] * values[kQ2X0C] + values[kQ2Y0B] * values[kQ2Y0C]); + float R2SP_AB_Im = (values[kQ2Y0A] * values[kQ2X0B] - values[kQ2X0A] * values[kQ2Y0B]); + float R2SP_AC_Im = (values[kQ2Y0A] * values[kQ2X0C] - values[kQ2X0A] * values[kQ2Y0C]); + float R2SP_BC_Im = (values[kQ2Y0B] * values[kQ2X0C] - values[kQ2X0B] * values[kQ2Y0C]); + values[kR2SP_AB] = std::isnan(R2SP_AB) || std::isinf(R2SP_AB) ? 0. : R2SP_AB; + values[kWR2SP_AB] = std::isnan(R2SP_AB) || std::isinf(R2SP_AB) ? 0. : 1.0; + values[kR2SP_AC] = std::isnan(R2SP_AC) || std::isinf(R2SP_AC) ? 0. : R2SP_AC; + values[kWR2SP_AC] = std::isnan(R2SP_AC) || std::isinf(R2SP_AC) ? 0. : 1.0; + values[kR2SP_BC] = std::isnan(R2SP_BC) || std::isinf(R2SP_BC) ? 0. : R2SP_BC; + values[kWR2SP_BC] = std::isnan(R2SP_BC) || std::isinf(R2SP_BC) ? 0. : 1.0; + values[kR2SP_AB_Im] = std::isnan(R2SP_AB_Im) || std::isinf(R2SP_AB_Im) ? 0. : R2SP_AB_Im; + values[kWR2SP_AB_Im] = std::isnan(R2SP_AB_Im) || std::isinf(R2SP_AB_Im) ? 0. : 1.0; + values[kR2SP_AC_Im] = std::isnan(R2SP_AC_Im) || std::isinf(R2SP_AC_Im) ? 0. : R2SP_AC_Im; + values[kWR2SP_AC_Im] = std::isnan(R2SP_AC_Im) || std::isinf(R2SP_AC_Im) ? 0. : 1.0; + values[kR2SP_BC_Im] = std::isnan(R2SP_BC_Im) || std::isinf(R2SP_BC_Im) ? 0. : R2SP_BC_Im; + values[kWR2SP_BC_Im] = std::isnan(R2SP_BC_Im) || std::isinf(R2SP_BC_Im) ? 0. : 1.0; + + float R2EP_AB = std::isnan(Psi2A) || std::isinf(Psi2A) || std::isnan(Psi2B) || std::isinf(Psi2B) ? 0. : TMath::Cos(2 * (Psi2A - Psi2B)); + float R2EP_AC = std::isnan(Psi2A) || std::isinf(Psi2A) || std::isnan(Psi2C) || std::isinf(Psi2C) ? 0. : TMath::Cos(2 * (Psi2A - Psi2C)); + float R2EP_BC = std::isnan(Psi2B) || std::isinf(Psi2B) || std::isnan(Psi2C) || std::isinf(Psi2C) ? 0. : TMath::Cos(2 * (Psi2B - Psi2C)); + float R2EP_AB_Im = std::isnan(Psi2A) || std::isinf(Psi2A) || std::isnan(Psi2B) || std::isinf(Psi2B) ? 0. : TMath::Sin(2 * (Psi2A - Psi2B)); + float R2EP_AC_Im = std::isnan(Psi2A) || std::isinf(Psi2A) || std::isnan(Psi2C) || std::isinf(Psi2C) ? 0. : TMath::Sin(2 * (Psi2A - Psi2C)); + float R2EP_BC_Im = std::isnan(Psi2B) || std::isinf(Psi2B) || std::isnan(Psi2C) || std::isinf(Psi2C) ? 0. : TMath::Sin(2 * (Psi2B - Psi2C)); + values[kR2EP_AB] = std::isnan(R2EP_AB) || std::isinf(R2EP_AB) ? 0. : R2EP_AB; + values[kWR2EP_AB] = std::isnan(R2EP_AB) || std::isinf(R2EP_AB) ? 0. : 1.0; + values[kR2EP_AC] = std::isnan(R2EP_AC) || std::isinf(R2EP_AC) ? 0. : R2EP_AC; + values[kWR2EP_AC] = std::isnan(R2EP_AC) || std::isinf(R2EP_AC) ? 0. : 1.0; + values[kR2EP_BC] = std::isnan(R2EP_BC) || std::isinf(R2EP_BC) ? 0. : R2EP_BC; + values[kWR2EP_BC] = std::isnan(R2EP_BC) || std::isinf(R2EP_BC) ? 0. : 1.0; + values[kR2EP_AB_Im] = std::isnan(R2EP_AB_Im) || std::isinf(R2EP_AB_Im) ? 0. : R2EP_AB_Im; + values[kWR2EP_AB_Im] = std::isnan(R2EP_AB_Im) || std::isinf(R2EP_AB_Im) ? 0. : 1.0; + values[kR2EP_AC_Im] = std::isnan(R2EP_AC_Im) || std::isinf(R2EP_AC_Im) ? 0. : R2EP_AC_Im; + values[kWR2EP_AC_Im] = std::isnan(R2EP_AC_Im) || std::isinf(R2EP_AC_Im) ? 0. : 1.0; + values[kR2EP_BC_Im] = std::isnan(R2EP_BC_Im) || std::isinf(R2EP_BC_Im) ? 0. : R2EP_BC_Im; + values[kWR2EP_BC_Im] = std::isnan(R2EP_BC_Im) || std::isinf(R2EP_BC_Im) ? 0. : 1.0; } if constexpr ((fillMap & CollisionMC) > 0) { values[kMCEventGeneratorId] = event.generatorsID(); + values[kMCEventSubGeneratorId] = event.getSubGeneratorId(); values[kMCVtxX] = event.posX(); values[kMCVtxY] = event.posY(); values[kMCVtxZ] = event.posZ(); @@ -1422,6 +1882,7 @@ void VarManager::FillEvent(T const& event, float* values) if constexpr ((fillMap & ReducedEventMC) > 0) { values[kMCEventGeneratorId] = event.generatorsID(); + values[kMCEventGeneratorId] = -999; // to be added in reduced events values[kMCVtxX] = event.mcPosX(); values[kMCVtxY] = event.mcPosY(); values[kMCVtxZ] = event.mcPosZ(); @@ -1430,16 +1891,157 @@ void VarManager::FillEvent(T const& event, float* values) values[kMCEventImpParam] = event.impactParameter(); } - if constexpr ((fillMap & EventFilter) > 0) { - values[kIsDoubleGap] = (event.eventFilter() & (uint64_t(1) << kDoubleGap)) > 0; - values[kIsSingleGapA] = (event.eventFilter() & (uint64_t(1) << kSingleGapA)) > 0; - values[kIsSingleGapC] = (event.eventFilter() & (uint64_t(1) << kSingleGapC)) > 0; + if constexpr ((fillMap & EventFilter) > 0 || (fillMap & RapidityGapFilter) > 0) { + values[kIsDoubleGap] = (event.eventFilter() & (static_cast(1) << kDoubleGap)) > 0; + values[kIsSingleGapA] = (event.eventFilter() & (static_cast(1) << kSingleGapA)) > 0; + values[kIsSingleGapC] = (event.eventFilter() & (static_cast(1) << kSingleGapC)) > 0; values[kIsSingleGap] = values[kIsSingleGapA] || values[kIsSingleGapC]; + values[kIsITSUPCMode] = (event.eventFilter() & (static_cast(1) << kITSUPCMode)) > 0; + } + + if constexpr ((fillMap & ReducedZdc) > 0) { + FillZDC(event, values); } FillEventDerived(values); } +template +void VarManager::FillEventTrackEstimators(TEvent const& collision, TAssoc const& assocs, TTracks const& /*tracks*/, float* values) +{ + // Compute median Z for the large dcaZ tracks in the TPC + // This is for studies of the pileup impact on the TPC + + if (!values) { + values = fgValues; + } + + if constexpr ((fillMap & Track) > 0 && (fillMap & TrackDCA) > 0) { + + std::vector tracksP; + std::vector tracksM; + + for (const auto& assoc : assocs) { + auto track = assoc.template track_as(); + // compute the dca of this track wrt the collision + auto trackPar = getTrackPar(track); + std::array dca{1e10f, 1e10f}; + trackPar.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca); + + // if it is a displaced track longitudinally, add it to the track vector + if (abs(dca[0]) < 3.0 && abs(dca[1]) > 4.0) { + if (track.tgl() > 0.1) { + tracksP.push_back(track.z()); + } + if (track.tgl() < -0.1) { + tracksM.push_back(track.z()); + } + } + } // end loop over associations + + // compute the number of pileup contributors and the median z for pileup + if (tracksP.size() > 0) { + std::sort(tracksP.begin(), tracksP.end()); + auto midP = tracksP.size() / 2; + values[kNTPCpileupContribA] = tracksP.size(); + values[kNTPCpileupZA] = (tracksP.size() % 2 ? (tracksP[midP] + tracksP[midP - 1]) / 2 : tracksP[midP]); + } + + if (tracksM.size() > 0) { + std::sort(tracksM.begin(), tracksM.end()); + values[kNTPCpileupContribC] = tracksM.size(); + auto midM = tracksM.size() / 2; + values[kNTPCpileupZC] = (tracksM.size() % 2 ? (tracksM[midM] + tracksM[midM - 1]) / 2 : tracksM[midM]); + } + } +} + +template +void VarManager::FillEventFlowResoFactor(T const& hs_sp, T const& hs_ep, float* values) +{ + if (!values) { + values = fgValues; + } + + if (values[kCentFT0C] >= 0.) { + int idx_sp = hs_sp->FindBin(values[kCentFT0C]); + int idx_ep = hs_ep->FindBin(values[kCentFT0C]); + + values[kR2SP] = hs_sp->GetBinContent(idx_sp); + values[kR2EP] = hs_ep->GetBinContent(idx_ep); + } +} + +template +void VarManager::FillTwoMixEventsFlowResoFactor(T const& hs_sp, T const& hs_ep, float* values) +{ + if (!values) { + values = fgValues; + } + + if (values[kTwoEvCentFT0C1] >= 0.) { + int idx_sp1 = hs_sp->FindBin(values[kTwoEvCentFT0C1]); + int idx_ep1 = hs_ep->FindBin(values[kTwoEvCentFT0C1]); + + values[kTwoR2SP1] = hs_sp->GetBinContent(idx_sp1); + values[kTwoR2EP1] = hs_ep->GetBinContent(idx_ep1); + } + + if (values[kTwoEvCentFT0C2] >= 0.) { + int idx_sp2 = hs_sp->FindBin(values[kTwoEvCentFT0C2]); + int idx_ep2 = hs_ep->FindBin(values[kTwoEvCentFT0C2]); + + values[kTwoR2SP2] = hs_sp->GetBinContent(idx_sp2); + values[kTwoR2EP2] = hs_ep->GetBinContent(idx_ep2); + } +} + +template +void VarManager::FillTwoMixEventsCumulants(T const& h_v22ev1, T const& h_v24ev1, T const& h_v22ev2, T const& h_v24ev2, T1 const& t1, T2 const& t2, float* values) +{ + if (!values) { + values = fgValues; + } + + int idx_v22ev1; + int idx_v24ev1; + int idx_v22ev2; + int idx_v24ev2; + + if (values[kTwoEvCentFT0C1] >= 0.) { + if (t1.sign() < 0) { + + idx_v22ev1 = h_v22ev1->FindBin(values[kTwoEvCentFT0C1], t1.pt()); + idx_v24ev1 = h_v24ev1->FindBin(values[kTwoEvCentFT0C1], t1.pt()); + values[kV22m] = h_v22ev1->GetBinContent(idx_v22ev1); + values[kV24m] = h_v24ev1->GetBinContent(idx_v24ev1); + + } else { + + idx_v22ev1 = h_v22ev2->FindBin(values[kTwoEvCentFT0C1], t1.pt()); + idx_v24ev1 = h_v24ev2->FindBin(values[kTwoEvCentFT0C1], t1.pt()); + values[kV22m] = h_v22ev2->GetBinContent(idx_v22ev1); + values[kV24m] = h_v24ev2->GetBinContent(idx_v24ev1); + } + } + if (values[kTwoEvCentFT0C2] >= 0.) { + if (t2.sign() < 0) { + + idx_v22ev2 = h_v22ev1->FindBin(values[kTwoEvCentFT0C2], t2.pt()); + idx_v24ev2 = h_v24ev1->FindBin(values[kTwoEvCentFT0C2], t2.pt()); + values[kV22p] = h_v22ev1->GetBinContent(idx_v22ev2); + values[kV24p] = h_v24ev1->GetBinContent(idx_v24ev2); + + } else { + + idx_v22ev2 = h_v22ev2->FindBin(values[kTwoEvCentFT0C2], t2.pt()); + idx_v24ev2 = h_v24ev2->FindBin(values[kTwoEvCentFT0C2], t2.pt()); + values[kV22p] = h_v22ev2->GetBinContent(idx_v22ev2); + values[kV24p] = h_v24ev2->GetBinContent(idx_v24ev2); + } + } +} + template void VarManager::FillTwoEvents(T const& ev1, T const& ev2, float* values) { @@ -1486,29 +2088,23 @@ void VarManager::FillTwoMixEvents(T1 const& ev1, T1 const& ev2, T2 const& /*trac for (auto& track1 : tracks1) { Track1Filter = uint32_t(track1.isMuonSelected());} for (auto& track2 : tracks2) { Track2Filter = uint32_t(track2.isMuonSelected());} */ + if constexpr ((fillMap & CollisionCent) > 0 || (fillMap & ReducedEventExtended) > 0) { + values[kTwoEvCentFT0C1] = ev1.centFT0C(); + values[kTwoEvCentFT0C2] = ev2.centFT0C(); + } if constexpr ((fillMap & ReducedEventQvector) > 0) { - values[kTwoR2SP1] = (ev1.q2x0b() * ev1.q2x0c() + ev1.q2y0b() * ev1.q2y0c()); - values[kTwoR2SP2] = (ev2.q2x0b() * ev2.q2x0c() + ev2.q2y0b() * ev2.q2y0c()); - - if (ev1.q2y0b() * ev1.q2y0c() != 0.0) { - values[kTwoR2EP1] = TMath::Cos(2 * (getEventPlane(2, ev1.q2x0b(), ev1.q2y0b()) - getEventPlane(2, ev1.q2x0c(), ev1.q2y0c()))); - } - - if (ev2.q2y0b() * ev2.q2y0c() != 0.0) { - values[kTwoR2EP2] = TMath::Cos(2 * (getEventPlane(2, ev2.q2x0b(), ev2.q2y0b()) - getEventPlane(2, ev2.q2x0c(), ev2.q2y0c()))); - } // Tobe used for the calculation of u1q1 and u2q2 values[kQ2X0A1] = ev1.q2x0a(); values[kQ2X0A2] = ev2.q2x0a(); values[kQ2Y0A1] = ev1.q2y0a(); values[kQ2Y0A2] = ev2.q2y0a(); } - - if (isnan(VarManager::fgValues[VarManager::kTwoR2SP1]) == true || isnan(VarManager::fgValues[VarManager::kTwoR2EP1]) == true) { - values[kTwoR2SP1] = -999.; - values[kTwoR2SP2] = -999.; - values[kTwoR2EP1] = -999.; - values[kTwoR2EP2] = -999.; + if constexpr ((fillMap & CollisionQvect) > 0) { + // Tobe used for the calculation of u1q1 and u2q2 + values[kQ2X0A1] = (ev1.qvecBPosRe() * ev1.nTrkBPos() + ev1.qvecBNegRe() * ev1.nTrkBNeg()) / (ev1.nTrkBPos() + ev1.nTrkBNeg()); + values[kQ2X0A2] = (ev2.qvecBPosRe() * ev2.nTrkBPos() + ev2.qvecBNegRe() * ev2.nTrkBNeg()) / (ev2.nTrkBPos() + ev2.nTrkBNeg()); + values[kQ2Y0A1] = (ev1.qvecBPosIm() * ev1.nTrkBPos() + ev1.qvecBNegIm() * ev1.nTrkBNeg()) / (ev1.nTrkBPos() + ev1.nTrkBNeg()); + values[kQ2Y0A2] = (ev2.qvecBPosIm() * ev2.nTrkBPos() + ev2.qvecBNegIm() * ev2.nTrkBNeg()) / (ev2.nTrkBPos() + ev2.nTrkBNeg()); } } @@ -1539,7 +2135,7 @@ void VarManager::FillTrack(T const& track, float* values) } // Quantities based on the basic table (contains just kine information and filter bits) - if constexpr ((fillMap & Track) > 0 || (fillMap & Muon) > 0 || (fillMap & ReducedTrack) > 0 || (fillMap & ReducedMuon) > 0) { + if constexpr ((fillMap & Track) > 0 || (fillMap & Muon) > 0 || (fillMap & MuonRealign) > 0 || (fillMap & ReducedTrack) > 0 || (fillMap & ReducedMuon) > 0) { values[kPt] = track.pt(); values[kSignedPt] = track.pt() * track.sign(); if (fgUsedVars[kP]) { @@ -1598,6 +2194,35 @@ void VarManager::FillTrack(T const& track, float* values) values[kIsDalitzLeg + i] = track.filteringFlags_bit(VarManager::kDalitzBits + i); } } + + if constexpr ((fillMap & MuonRealign) > 0) { + values[kMuonChi2] = track.chi2(); + values[kMuonTrackType] = track.trackType(); + } + + if (fgUsedVars[kM11REFoverMpsingle]) { + float m = o2::constants::physics::MassMuon; + ROOT::Math::PtEtaPhiMVector v(track.pt(), track.eta(), track.phi(), m); + complex Q21(values[kQ2X0A] * values[kS11A], values[kQ2Y0A] * values[kS11A]); + complex Q42(values[kQ42XA], values[kQ42YA]); + complex Q23(values[kQ23XA], values[kQ23YA]); + complex P2(TMath::Cos(2 * v.Phi()), TMath::Sin(2 * v.Phi())); + values[kM11REFoverMpsingle] = values[kMultSingleMuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM11REF] / values[kMultSingleMuons] : 0; + values[kM1111REFoverMpsingle] = values[kMultSingleMuons] > 0 && !(std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF])) ? values[kM1111REF] / values[kMultSingleMuons] : 0; + values[kCORR2REFbysinglemu] = std::isnan(values[kM11REFoverMpsingle]) || std::isinf(values[kM11REFoverMpsingle]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REFoverMpsingle]) || std::isinf(values[kM1111REFoverMpsingle]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : values[kCORR2REF]; + values[kCORR4REFbysinglemu] = std::isnan(values[kM1111REFoverMpsingle]) || std::isinf(values[kM1111REFoverMpsingle]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REFoverMpsingle]) || std::isinf(values[kM11REFoverMpsingle]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : values[kCORR4REF]; + values[kCORR2POIsingle] = (P2 * conj(Q21)).real() / values[kM01POI]; + values[kM01POIsingle] = values[kMultSingleMuons] * values[kS11A]; + values[kM0111POIsingle] = values[kMultSingleMuons] * (values[kS31A] - 3. * values[kS11A] * values[kS12A] + 2. * values[kS13A]); + values[kCORR2POIsingle] = (P2 * conj(Q21)).real() / values[kM01POIsingle]; + values[kCORR4POIsingle] = (P2 * Q21 * conj(Q21) * conj(Q21) - P2 * Q21 * conj(Q42) - 2. * values[kS12A] * P2 * conj(Q21) + 2. * P2 * conj(Q23)).real() / values[kM0111POIsingle]; + values[kM01POIsingle] = std::isnan(values[kM01POIsingle]) || std::isinf(values[kM01POIsingle]) || std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) ? 0 : values[kM01POIsingle]; + values[kM0111POIsingle] = std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) ? 0 : values[kM0111POIsingle]; + values[kCORR2POIsingle] = std::isnan(values[kM01POIsingle]) || std::isinf(values[kM01POIsingle]) || std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) ? 0 : values[kCORR2POIsingle]; + values[kCORR4POIsingle] = std::isnan(values[kM01POIsingle]) || std::isinf(values[kM01POIsingle]) || std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) ? 0 : values[kCORR4POIsingle]; + values[kM01POIoverMpsingle] = values[kMultSingleMuons] > 0 && !(std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) || std::isnan(values[kM01POIsingle]) || std::isinf(values[kM01POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle])) ? values[kM01POIsingle] / values[kMultSingleMuons] : 0; + values[kM0111POIoverMpsingle] = values[kMultSingleMuons] > 0 && !(std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) || std::isnan(values[kM01POIsingle]) || std::isinf(values[kM01POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle])) ? values[kM0111POIsingle] / values[kMultSingleMuons] : 0; + } } // Quantities based on the barrel tables @@ -1666,6 +2291,9 @@ void VarManager::FillTrack(T const& track, float* values) values[kHasTPC] = track.hasTPC(); if constexpr ((fillMap & TrackExtra) > 0) { + if (fgUsedVars[kTPCnCRoverFindCls]) { + values[kTPCnCRoverFindCls] = track.tpcCrossedRowsOverFindableCls(); + } if (fgUsedVars[kITSncls]) { values[kITSncls] = track.itsNCls(); // dynamic column } @@ -1921,7 +2549,7 @@ void VarManager::FillTrack(T const& track, float* values) values[kMuonTimeRes] = track.trackTimeRes(); } // Quantities based on the muon covariance table - if constexpr ((fillMap & ReducedMuonCov) > 0 || (fillMap & MuonCov) > 0) { + if constexpr ((fillMap & ReducedMuonCov) > 0 || (fillMap & MuonCov) > 0 || (fillMap & MuonCovRealign) > 0) { values[kX] = track.x(); values[kY] = track.y(); values[kZ] = track.z(); @@ -1978,6 +2606,15 @@ void VarManager::FillTrackCollision(T const& track, C const& collision, float* v } } } + if constexpr ((fillMap & MuonCov) > 0 || (fillMap & MuonCovRealign) > 0 || (fillMap & ReducedMuonCov) > 0) { + + o2::dataformats::GlobalFwdTrack propmuonAtDCA = PropagateMuon(track, collision, kToDCA); + + float dcaX = (propmuonAtDCA.getX() - collision.posX()); + float dcaY = (propmuonAtDCA.getY() - collision.posY()); + float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); + values[kMuonPDca] = track.p() * dcaXY; + } } template @@ -2117,22 +2754,65 @@ void VarManager::FillPair(T1 const& t1, T2 const& t2, float* values) m2 = o2::constants::physics::MassPionCharged; } + if constexpr (pairType == kDecayToKPi) { + m1 = o2::constants::physics::MassKaonCharged; + m2 = o2::constants::physics::MassPionCharged; + // Make the TPC information of the kaon available for pair histograms + values[kPin_leg1] = t1.tpcInnerParam(); + values[kTPCnSigmaKa_leg1] = t1.tpcNSigmaKa(); + } + if constexpr (pairType == kElectronMuon) { m2 = o2::constants::physics::MassMuon; } + values[kCharge] = t1.sign() + t2.sign(); + values[kCharge1] = t1.sign(); + values[kCharge2] = t2.sign(); ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), m1); ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), m2); ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; values[kMass] = v12.M(); values[kPt] = v12.Pt(); values[kEta] = v12.Eta(); - values[kPhi] = v12.Phi(); + // values[kPhi] = v12.Phi(); + values[kPhi] = v12.Phi() > 0 ? v12.Phi() : v12.Phi() + 2. * M_PI; values[kRap] = -v12.Rapidity(); double Ptot1 = TMath::Sqrt(v1.Px() * v1.Px() + v1.Py() * v1.Py() + v1.Pz() * v1.Pz()); double Ptot2 = TMath::Sqrt(v2.Px() * v2.Px() + v2.Py() * v2.Py() + v2.Pz() * v2.Pz()); values[kDeltaPtotTracks] = Ptot1 - Ptot2; + if (t1.sign() > 0) { + values[kPt1] = t1.pt(); + values[kEta1] = t1.eta(); + values[kPhi1] = t1.phi(); + values[kPt2] = t2.pt(); + values[kEta2] = t2.eta(); + values[kPhi2] = t2.phi(); + } else { + values[kPt1] = t2.pt(); + values[kEta1] = t2.eta(); + values[kPhi1] = t2.phi(); + values[kPt2] = t1.pt(); + values[kEta2] = t1.eta(); + values[kPhi2] = t1.phi(); + } + + if (fgUsedVars[kDeltaPhiPair2]) { + double phipair2 = v1.Phi() - v2.Phi(); + if (phipair2 > 3 * TMath::Pi() / 2) { + values[kDeltaPhiPair2] = phipair2 - 2 * TMath::Pi(); + } else if (phipair2 < -TMath::Pi() / 2) { + values[kDeltaPhiPair2] = phipair2 + 2 * TMath::Pi(); + } else { + values[kDeltaPhiPair2] = phipair2; + } + } + + if (fgUsedVars[kDeltaEtaPair2]) { + values[kDeltaEtaPair2] = v1.Eta() - v2.Eta(); + } + if (fgUsedVars[kPsiPair]) { values[kDeltaPhiPair] = (t1.sign() * fgMagField > 0.) ? (v1.Phi() - v2.Phi()) : (v2.Phi() - v1.Phi()); double xipair = TMath::ACos((v1.Px() * v2.Px() + v1.Py() * v2.Py() + v1.Pz() * v2.Pz()) / v1.P() / v2.P()); @@ -2226,122 +2906,157 @@ void VarManager::FillPair(T1 const& t1, T2 const& t2, float* values) } } } - if (fgUsedVars[kPairPhiv]) { - // cos(phiv) = w*a /|w||a| - // with w = u x v - // and a = u x z / |u x z| , unit vector perpendicular to v12 and z-direction (magnetic field) - // u = v12 / |v12| , the unit vector of v12 - // v = v1 x v2 / |v1 x v2| , unit vector perpendicular to v1 and v2 - - float bz = fgFitterTwoProngBarrel.getBz(); - - bool swapTracks = false; - if (v1.Pt() < v2.Pt()) { // ordering of track, pt1 > pt2 - ROOT::Math::PtEtaPhiMVector v3 = v1; - v1 = v2; - v2 = v3; - swapTracks = true; - } - - // momentum of e+ and e- in (ax,ay,az) axis. Note that az=0 by definition. - // vector product of pep X pem - float vpx = 0, vpy = 0, vpz = 0; - if (t1.sign() * t2.sign() > 0) { // Like Sign - if (!swapTracks) { - if (bz * t1.sign() < 0) { - vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); - vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); - vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); - } else { - vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); - vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); - vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); - } - } else { // swaped tracks - if (bz * t2.sign() < 0) { - vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); - vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); - vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); - } else { - vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); - vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); - vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); - } - } - } else { // Unlike Sign - if (!swapTracks) { - if (bz * t1.sign() > 0) { - vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); - vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); - vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); - } else { - vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); - vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); - vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); - } - } else { // swaped tracks - if (bz * t2.sign() > 0) { - vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); - vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); - vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); - } else { - vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); - vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); - vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); - } - } + if constexpr ((pairType == kDecayToMuMu) && ((fillMap & Muon) > 0 || (fillMap & ReducedMuon) > 0)) { + if (fgUsedVars[kQuadDCAabsXY]) { + double dca1X = t1.fwdDcaX(); + double dca1Y = t1.fwdDcaY(); + double dca1XY = std::sqrt(dca1X * dca1X + dca1Y * dca1Y); + double dca2X = t2.fwdDcaX(); + double dca2Y = t2.fwdDcaY(); + double dca2XY = std::sqrt(dca2X * dca2X + dca2Y * dca2Y); + values[kQuadDCAabsXY] = std::sqrt((dca1XY * dca1XY + dca2XY * dca2XY) / 2.); } + } + if (fgUsedVars[kPairPhiv]) { + values[kPairPhiv] = calculatePhiV(t1, t2); + } +} + +template +void VarManager::FillPairCollision(const C& collision, T1 const& t1, T2 const& t2, float* values) +{ + if (!values) { + values = fgValues; + } - // unit vector of pep X pem - float vx = vpx / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); - float vy = vpy / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); - float vz = vpz / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); + if constexpr ((pairType == kDecayToEE) && ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0)) { + + if (fgUsedVars[kQuadDCAabsXY] || fgUsedVars[kQuadDCAsigXY] || fgUsedVars[kQuadDCAabsZ] || fgUsedVars[kQuadDCAsigZ] || fgUsedVars[kQuadDCAsigXYZ] || fgUsedVars[kSignQuadDCAsigXY]) { + + auto trackPart1 = getTrackPar(t1); + std::array dca1{1e10f, 1e10f}; + trackPart1.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca1); + + auto trackPart2 = getTrackPar(t2); + std::array dca2{1e10f, 1e10f}; + trackPart2.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca2); + + // Recalculated quantities + double dca1XY = dca1[0]; + double dca2XY = dca2[0]; + double dca1Z = dca1[1]; + double dca2Z = dca2[1]; + double dca1sigXY = dca1XY / std::sqrt(t1.cYY()); + double dca2sigXY = dca2XY / std::sqrt(t2.cYY()); + double dca1sigZ = dca1Z / std::sqrt(t1.cZZ()); + double dca2sigZ = dca2Z / std::sqrt(t2.cZZ()); + + values[kQuadDCAabsXY] = std::sqrt((dca1XY * dca1XY + dca2XY * dca2XY) / 2); + values[kQuadDCAsigXY] = std::sqrt((dca1sigXY * dca1sigXY + dca2sigXY * dca2sigXY) / 2); + values[kQuadDCAabsZ] = std::sqrt((dca1Z * dca1Z + dca2Z * dca2Z) / 2); + values[kQuadDCAsigZ] = std::sqrt((dca1sigZ * dca1sigZ + dca2sigZ * dca2sigZ) / 2); + values[kSignQuadDCAsigXY] = t1.sign() * t2.sign() * TMath::Sign(1., dca1sigXY) * TMath::Sign(1., dca2sigXY) * std::sqrt((dca1sigXY * dca1sigXY + dca2sigXY * dca2sigXY) / 2); - float px = v12.Px(); - float py = v12.Py(); - float pz = v12.Pz(); + double det1 = t1.cYY() * t1.cZZ() - t1.cZY() * t1.cZY(); + double det2 = t2.cYY() * t2.cZZ() - t2.cZY() * t2.cZY(); + if ((det1 < 0) || (det2 < 0)) { + values[kQuadDCAsigXYZ] = -999; + } else { + double chi2t1 = (dca1XY * dca1XY * t1.cZZ() + dca1Z * dca1Z * t1.cYY() - 2. * dca1XY * dca1Z * t1.cZY()) / det1; + double chi2t2 = (dca2XY * dca2XY * t2.cZZ() + dca2Z * dca2Z * t2.cYY() - 2. * dca2XY * dca2Z * t2.cZY()) / det2; - // unit vector of (pep+pem) - float ux = px / TMath::Sqrt(px * px + py * py + pz * pz); - float uy = py / TMath::Sqrt(px * px + py * py + pz * pz); - float uz = pz / TMath::Sqrt(px * px + py * py + pz * pz); - float ax = uy / TMath::Sqrt(ux * ux + uy * uy); - float ay = -ux / TMath::Sqrt(ux * ux + uy * uy); + double dca1sigXYZ = std::sqrt(std::abs(chi2t1) / 2.); + double dca2sigXYZ = std::sqrt(std::abs(chi2t2) / 2.); - // The third axis defined by vector product (ux,uy,uz)X(vx,vy,vz) - float wx = uy * vz - uz * vy; - float wy = uz * vx - ux * vz; - // by construction, (wx,wy,wz) must be a unit vector. Measure angle between (wx,wy,wz) and (ax,ay,0). - // The angle between them should be small if the pair is conversion. This function then returns values close to pi! - values[kPairPhiv] = TMath::ACos(wx * ax + wy * ay); // phiv in [0,pi] //cosPhiV = wx * ax + wy * ay; + values[kQuadDCAsigXYZ] = std::sqrt((dca1sigXYZ * dca1sigXYZ + dca2sigXYZ * dca2sigXYZ) / 2); + } + } } } -template -void VarManager::FillTriple(T1 const& t1, T2 const& t2, T3 const& t3, float* values, PairCandidateType pairType) +template +void VarManager::FillPairCollisionMatCorr(C const& collision, T1 const& t1, T2 const& t2, M const& materialCorr, P const& propagator, float* values) { - if (!values) { values = fgValues; } - if (pairType == kTripleCandidateToEEPhoton) { - float m1 = o2::constants::physics::MassElectron; - float m3 = o2::constants::physics::MassPhoton; - float m4 = o2::constants::physics::MassJPsi; - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), m1); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), m1); - ROOT::Math::PtEtaPhiMVector v3(t3.pt(), t3.eta(), t3.phi(), m3); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - ROOT::Math::PtEtaPhiMVector v123 = v12 + v3; - values[kPairMass] = v123.M(); - values[kPairPt] = v123.Pt(); - values[kPairEta] = v123.Eta(); - values[kPairPhi] = v123.Phi(); - values[kPairMassDau] = v12.M(); - values[kMassDau] = m3; - values[kPairPtDau] = v12.Pt(); - values[kPt] = t3.pt(); + if constexpr ((pairType == kDecayToEE) && ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0)) { + + if (fgUsedVars[kQuadDCAabsXY] || fgUsedVars[kQuadDCAsigXY] || fgUsedVars[kQuadDCAabsZ] || fgUsedVars[kQuadDCAsigZ] || fgUsedVars[kQuadDCAsigXYZ] || fgUsedVars[kSignQuadDCAsigXY]) { + + auto trackPart1 = getTrackPar(t1); + std::array dca1{1e10f, 1e10f}; + std::array pVect1 = {t1.px(), t1.py(), t1.pz()}; + // trackPar.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca); + propagator->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPart1, 2.f, materialCorr, &dca1); + getPxPyPz(trackPart1, pVect1); + + auto trackPart2 = getTrackPar(t2); + std::array dca2{1e10f, 1e10f}; + std::array pVect2 = {t2.px(), t2.py(), t2.pz()}; + // trackPar.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca); + propagator->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPart2, 2.f, materialCorr, &dca2); + getPxPyPz(trackPart2, pVect2); + + // Recalculated quantities + double dca1XY = dca1[0]; + double dca2XY = dca2[0]; + double dca1Z = dca1[1]; + double dca2Z = dca2[1]; + double dca1sigXY = dca1XY / std::sqrt(t1.cYY()); + double dca2sigXY = dca2XY / std::sqrt(t2.cYY()); + double dca1sigZ = dca1Z / std::sqrt(t1.cZZ()); + double dca2sigZ = dca2Z / std::sqrt(t2.cZZ()); + + values[kQuadDCAabsXY] = std::sqrt((dca1XY * dca1XY + dca2XY * dca2XY) / 2); + values[kQuadDCAsigXY] = std::sqrt((dca1sigXY * dca1sigXY + dca2sigXY * dca2sigXY) / 2); + values[kQuadDCAabsZ] = std::sqrt((dca1Z * dca1Z + dca2Z * dca2Z) / 2); + values[kQuadDCAsigZ] = std::sqrt((dca1sigZ * dca1sigZ + dca2sigZ * dca2sigZ) / 2); + values[kSignQuadDCAsigXY] = t1.sign() * t2.sign() * TMath::Sign(1., dca1sigXY) * TMath::Sign(1., dca2sigXY) * std::sqrt((dca1sigXY * dca1sigXY + dca2sigXY * dca2sigXY) / 2); + + double det1 = t1.cYY() * t1.cZZ() - t1.cZY() * t1.cZY(); + double det2 = t2.cYY() * t2.cZZ() - t2.cZY() * t2.cZY(); + if ((det1 < 0) || (det2 < 0)) { + values[kQuadDCAsigXYZ] = -999; + } else { + double chi2t1 = (dca1XY * dca1XY * t1.cZZ() + dca1Z * dca1Z * t1.cYY() - 2. * dca1XY * dca1Z * t1.cZY()) / det1; + double chi2t2 = (dca2XY * dca2XY * t2.cZZ() + dca2Z * dca2Z * t2.cYY() - 2. * dca2XY * dca2Z * t2.cZY()) / det2; + + double dca1sigXYZ = std::sqrt(std::abs(chi2t1) / 2.); + double dca2sigXYZ = std::sqrt(std::abs(chi2t2) / 2.); + + values[kQuadDCAsigXYZ] = std::sqrt((dca1sigXYZ * dca1sigXYZ + dca2sigXYZ * dca2sigXYZ) / 2); + } + } + } +} + +template +void VarManager::FillTriple(T1 const& t1, T2 const& t2, T3 const& t3, float* values, PairCandidateType pairType) +{ + + if (!values) { + values = fgValues; + } + if (pairType == kTripleCandidateToEEPhoton) { + float m1 = o2::constants::physics::MassElectron; + float m3 = o2::constants::physics::MassPhoton; + float m4 = o2::constants::physics::MassJPsi; + + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), m1); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), m1); + ROOT::Math::PtEtaPhiMVector v3(t3.pt(), t3.eta(), t3.phi(), m3); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + ROOT::Math::PtEtaPhiMVector v123 = v12 + v3; + values[kPairMass] = v123.M(); + values[kPairPt] = v123.Pt(); + values[kPairEta] = v123.Eta(); + values[kPairPhi] = v123.Phi(); + values[kPairMassDau] = v12.M(); + values[kMassDau] = m3; + values[kPairPtDau] = v12.Pt(); + values[kPt] = t3.pt(); values[kEta] = t3.eta(); values[kEta1] = t1.eta(); values[kEta2] = t2.eta(); @@ -2352,9 +3067,41 @@ void VarManager::FillTriple(T1 const& t1, T2 const& t2, T3 const& t3, float* val values[kPt1] = t1.pt(); values[kPt2] = t2.pt(); } + + if (pairType == kTripleCandidateToKPiPi) { + float m1 = o2::constants::physics::MassKaonCharged; + float m2 = o2::constants::physics::MassPionCharged; + + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), m1); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), m2); + ROOT::Math::PtEtaPhiMVector v3(t3.pt(), t3.eta(), t3.phi(), m2); + ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; + values[kMass] = v123.M(); + values[kPt] = v123.Pt(); + values[kEta] = v123.Eta(); + values[kPhi] = v123.Phi(); + values[kRap] = -v123.Rapidity(); + values[kCharge] = t1.sign() + t2.sign() + t3.sign(); + } + + if (pairType == kTripleCandidateToPKPi) { + float m1 = o2::constants::physics::MassProton; + float m2 = o2::constants::physics::MassKaonCharged; + float m3 = o2::constants::physics::MassPionCharged; + + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), m1); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), m2); + ROOT::Math::PtEtaPhiMVector v3(t3.pt(), t3.eta(), t3.phi(), m3); + ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; + values[kMass] = v123.M(); + values[kPt] = v123.Pt(); + values[kEta] = v123.Eta(); + values[kPhi] = v123.Phi(); + values[kRap] = -v123.Rapidity(); + } } -template +template void VarManager::FillPairME(T1 const& t1, T2 const& t2, float* values) { // @@ -2386,19 +3133,97 @@ void VarManager::FillPairME(T1 const& t1, T2 const& t2, float* values) values[kMass] = v12.M(); values[kPt] = v12.Pt(); values[kEta] = v12.Eta(); - values[kPhi] = v12.Phi(); + // values[kPhi] = v12.Phi(); + values[kPhi] = v12.Phi() > 0 ? v12.Phi() : v12.Phi() + 2. * M_PI; values[kRap] = -v12.Rapidity(); - // TODO: provide different computations for vn - // Compute the scalar product UQ for two muon from different event using Q-vector from A, for second and third harmonic - values[kU2Q2Ev1] = values[kQ2X0A1] * std::cos(2 * v1.Phi()) + values[kQ2Y0A1] * std::sin(2 * v1.Phi()); - values[kU2Q2Ev2] = values[kQ2X0A2] * std::cos(2 * v2.Phi()) + values[kQ2Y0A2] * std::sin(2 * v2.Phi()); - values[kCos2DeltaPhiMu1] = std::cos(2 * (v1.Phi() - v12.Phi())); - values[kCos2DeltaPhiMu2] = std::cos(2 * (v2.Phi() - v12.Phi())); + if (fgUsedVars[kDeltaPhiPair2]) { + double phipair2ME = v1.Phi() - v2.Phi(); + if (phipair2ME > 3 * TMath::Pi() / 2) { + values[kDeltaPhiPair2] = phipair2ME - 2 * TMath::Pi(); + } else if (phipair2ME < -TMath::Pi() / 2) { + values[kDeltaPhiPair2] = phipair2ME + 2 * TMath::Pi(); + } else { + values[kDeltaPhiPair2] = phipair2ME; + } + } + + if (fgUsedVars[kDeltaEtaPair2]) { + values[kDeltaEtaPair2] = v1.Eta() - v2.Eta(); + } + + if constexpr ((fillMap & ReducedEventQvector) > 0 || (fillMap & CollisionQvect) > 0) { + // TODO: provide different computations for vn + // Compute the scalar product UQ for two muon from different event using Q-vector from A, for second and third harmonic + float Psi2A1 = getEventPlane(2, values[kQ2X0A1], values[kQ2Y0A1]); + float Psi2A2 = getEventPlane(2, values[kQ2X0A2], values[kQ2Y0A2]); + values[kCos2DeltaPhi] = TMath::Cos(2 * (v12.Phi() - Psi2A1)); // WARNING: using the first event EP + values[kCos2DeltaPhiEv1] = TMath::Cos(2 * (v1.Phi() - Psi2A1)); + values[kCos2DeltaPhiEv2] = TMath::Cos(2 * (v2.Phi() - Psi2A2)); + values[kU2Q2] = values[kQ2X0A1] * TMath::Cos(2 * v12.Phi()) + values[kQ2Y0A1] * TMath::Sin(2 * v12.Phi()); // WARNING: using the first event EP + values[kU2Q2Ev1] = values[kQ2X0A1] * TMath::Cos(2 * v1.Phi()) + values[kQ2Y0A1] * TMath::Sin(2 * v1.Phi()); + values[kU2Q2Ev2] = values[kQ2X0A2] * TMath::Cos(2 * v2.Phi()) + values[kQ2Y0A2] * TMath::Sin(2 * v2.Phi()); + + values[kCos2DeltaPhiMu1] = TMath::Cos(2 * (v1.Phi() - v12.Phi())); + values[kCos2DeltaPhiMu2] = TMath::Cos(2 * (v2.Phi() - v12.Phi())); + + values[kV2SP1] = values[kU2Q2Ev1] / values[kTwoR2SP1]; + values[kV2SP2] = values[kU2Q2Ev2] / values[kTwoR2SP2]; + values[kV2EP1] = values[kCos2DeltaPhiEv1] / values[kTwoR2EP1]; + values[kV2EP2] = values[kCos2DeltaPhiEv2] / values[kTwoR2EP2]; + + float V2ME_SP = values[kV2SP1] * values[kCos2DeltaPhiMu1] + values[kV2SP2] * values[kCos2DeltaPhiMu2]; + float V2ME_EP = values[kV2EP1] * values[kCos2DeltaPhiMu1] + values[kV2EP2] * values[kCos2DeltaPhiMu2]; + values[kV2ME_SP] = std::isnan(V2ME_SP) || std::isinf(V2ME_SP) ? 0. : V2ME_SP; + values[kWV2ME_SP] = std::isnan(V2ME_SP) || std::isinf(V2ME_SP) ? 0. : 1.0; + values[kV2ME_EP] = std::isnan(V2ME_EP) || std::isinf(V2ME_EP) ? 0. : V2ME_EP; + values[kWV2ME_EP] = std::isnan(V2ME_EP) || std::isinf(V2ME_EP) ? 0. : 1.0; + + // Cumulant part + float V22ME = values[kV22m] * values[kCos2DeltaPhiMu1] + values[kV22p] * values[kCos2DeltaPhiMu2]; + float V24ME = values[kV24m] * values[kCos2DeltaPhiMu1] + values[kV24p] * values[kCos2DeltaPhiMu2]; + values[kV22ME] = (std::isnan(V22ME) || std::isinf(V22ME) || std::isnan(V24ME) || std::isinf(V24ME)) ? 0. : V22ME; + values[kWV22ME] = (std::isnan(V22ME) || std::isinf(V22ME) || std::isnan(V24ME) || std::isinf(V24ME)) ? 0. : 1.0; + values[kV24ME] = (std::isnan(V22ME) || std::isinf(V22ME) || std::isnan(V24ME) || std::isinf(V24ME)) ? 0. : V24ME; + values[kWV24ME] = (std::isnan(V22ME) || std::isinf(V22ME) || std::isnan(V24ME) || std::isinf(V24ME)) ? 0. : 1.0; + + if constexpr ((fillMap & ReducedEventQvectorExtra) > 0) { + complex Q21(values[kQ2X0A] * values[kS11A], values[kQ2Y0A] * values[kS11A]); + complex Q42(values[kQ42XA], values[kQ42YA]); + complex Q23(values[kQ23XA], values[kQ23YA]); + complex P2(TMath::Cos(2 * v12.Phi()), TMath::Sin(2 * v12.Phi())); + values[kM01POIME] = values[kMultDimuonsME] * values[kS11A]; + values[kM0111POIME] = values[kMultDimuonsME] * (values[kS31A] - 3. * values[kS11A] * values[kS12A] + 2. * values[kS13A]); + values[kCORR2POIME] = (P2 * conj(Q21)).real() / values[kM01POIME]; + values[kCORR4POIME] = (P2 * Q21 * conj(Q21) * conj(Q21) - P2 * Q21 * conj(Q42) - 2. * values[kS12A] * P2 * conj(Q21) + 2. * P2 * conj(Q23)).real() / values[kM0111POIME]; + values[kM01POIoverMpME] = values[kMultDimuonsME] > 0 && !(std::isnan(values[kM01POIME]) || std::isinf(values[kM01POIME]) || std::isnan(values[kCORR2POIME]) || std::isinf(values[kCORR2POIME]) || std::isnan(values[kM0111POIME]) || std::isinf(values[kM0111POIME]) || std::isnan(values[kCORR4POIME]) || std::isinf(values[kCORR4POIME])) ? values[kM01POIME] / values[kMultDimuonsME] : 0; + values[kM0111POIoverMpME] = values[kMultDimuonsME] > 0 && !(std::isnan(values[kM0111POIME]) || std::isinf(values[kM0111POIME]) || std::isnan(values[kCORR4POIME]) || std::isinf(values[kCORR4POIME]) || std::isnan(values[kM01POIME]) || std::isinf(values[kM01POIME]) || std::isnan(values[kCORR2POIME]) || std::isinf(values[kCORR2POIME])) ? values[kM0111POIME] / values[kMultDimuonsME] : 0; + values[kM11REFoverMpME] = values[kMultDimuonsME] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM11REF] / values[kMultDimuonsME] : 0; + values[kM1111REFoverMpME] = values[kMultDimuonsME] > 0 && !(std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF])) ? values[kM1111REF] / values[kMultDimuonsME] : 0; + values[kCORR2REFbydimuonsME] = std::isnan(values[kM11REFoverMpME]) || std::isinf(values[kM11REFoverMpME]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REFoverMpME]) || std::isinf(values[kM1111REFoverMpME]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : values[kCORR2REF]; + values[kCORR4REFbydimuonsME] = std::isnan(values[kM1111REFoverMpME]) || std::isinf(values[kM1111REFoverMpME]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REFoverMpME]) || std::isinf(values[kM11REFoverMpME]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : values[kCORR4REF]; + values[kCORR2POIME] = std::isnan(values[kCORR2POIME]) || std::isinf(values[kCORR2POIME]) || std::isnan(values[kM01POIME]) || std::isinf(values[kM01POIME]) || std::isnan(values[kCORR4POIME]) || std::isinf(values[kCORR4POIME]) || std::isnan(values[kM0111POIME]) || std::isinf(values[kM0111POIME]) ? 0 : values[kCORR2POIME]; + values[kCORR4POIME] = std::isnan(values[kCORR4POIME]) || std::isinf(values[kCORR4POIME]) || std::isnan(values[kM0111POIME]) || std::isinf(values[kM0111POIME]) || std::isnan(values[kCORR2POIME]) || std::isinf(values[kCORR2POIME]) || std::isnan(values[kM01POIME]) || std::isinf(values[kM01POIME]) ? 0 : values[kCORR4POIME]; + } + } + if constexpr (pairType == kDecayToMuMu) { + if (fgUsedVars[kQuadDCAabsXY]) { + double dca1X = t1.fwdDcaX(); + double dca1Y = t1.fwdDcaY(); + double dca1XY = std::sqrt(dca1X * dca1X + dca1Y * dca1Y); + double dca2X = t2.fwdDcaX(); + double dca2Y = t2.fwdDcaY(); + double dca2XY = std::sqrt(dca2X * dca2X + dca2Y * dca2Y); + values[kQuadDCAabsXY] = std::sqrt((dca1XY * dca1XY + dca2XY * dca2XY) / 2.); + } + } + if (fgUsedVars[kPairPhiv]) { + values[kPairPhiv] = calculatePhiV(t1, t2); + } } -template -void VarManager::FillPairMC(T1 const& t1, T2 const& t2, float* values, PairCandidateType pairType) +template +void VarManager::FillPairMC(T1 const& t1, T2 const& t2, float* values) { if (!values) { values = fgValues; @@ -2416,6 +3241,11 @@ void VarManager::FillPairMC(T1 const& t1, T2 const& t2, float* values, PairCandi m2 = o2::constants::physics::MassPionCharged; } + if (pairType == kDecayToKPi) { + m1 = o2::constants::physics::MassKaonCharged; + m2 = o2::constants::physics::MassPionCharged; + } + if (pairType == kElectronMuon) { m2 = o2::constants::physics::MassMuon; } @@ -2424,11 +3254,11 @@ void VarManager::FillPairMC(T1 const& t1, T2 const& t2, float* values, PairCandi ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), m1); ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), m2); ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - values[kMass] = v12.M(); - values[kPt] = v12.Pt(); - values[kEta] = v12.Eta(); - values[kPhi] = v12.Phi(); - values[kRap] = -v12.Rapidity(); + values[kMCMass] = v12.M(); + values[kMCPt] = v12.Pt(); + values[kMCEta] = v12.Eta(); + values[kMCPhi] = v12.Phi(); + values[kMCY] = -v12.Rapidity(); } template @@ -2466,6 +3296,21 @@ void VarManager::FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* v values[kPt1] = t1.pt(); values[kPt2] = t2.pt(); } + + if (pairType == kTripleCandidateToKPiPi) { + float m1 = o2::constants::physics::MassKaonCharged; + float m2 = o2::constants::physics::MassPionCharged; + + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), m1); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), m2); + ROOT::Math::PtEtaPhiMVector v3(t3.pt(), t3.eta(), t3.phi(), m2); + ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; + values[kMass] = v123.M(); + values[kPt] = v123.Pt(); + values[kEta] = v123.Eta(); + values[kPhi] = v123.Phi(); + values[kRap] = -v123.Rapidity(); + } } template @@ -2481,6 +3326,10 @@ void VarManager::FillPairVertexing(C const& collision, T const& t1, T const& t2, } float m1 = o2::constants::physics::MassElectron; float m2 = o2::constants::physics::MassElectron; + if constexpr (pairType == kDecayToKPi) { + m1 = o2::constants::physics::MassKaonCharged; + m2 = o2::constants::physics::MassPionCharged; + } if constexpr (pairType == kDecayToMuMu && muonHasCov) { m1 = o2::constants::physics::MassMuon; m2 = o2::constants::physics::MassMuon; @@ -2497,7 +3346,7 @@ void VarManager::FillPairVertexing(C const& collision, T const& t1, T const& t2, // auto pars1 = getTrackParCov(t1); // auto pars2 = getTrackParCov(t2); // We need to hide the cov data members from the cases when no cov table is provided - if constexpr ((pairType == kDecayToEE) && trackHasCov) { + if constexpr ((pairType == kDecayToEE || pairType == kDecayToKPi) && trackHasCov) { std::array t1pars = {t1.y(), t1.z(), t1.snp(), t1.tgl(), t1.signed1Pt()}; std::array t1covs = {t1.cYY(), t1.cZY(), t1.cZZ(), t1.cSnpY(), t1.cSnpZ(), t1.cSnpSnp(), t1.cTglY(), t1.cTglZ(), t1.cTglSnp(), t1.cTglTgl(), @@ -2563,7 +3412,7 @@ void VarManager::FillPairVertexing(C const& collision, T const& t1, T const& t2, // auto primaryVertex = getPrimaryVertex(collision); auto covMatrixPV = primaryVertex.getCov(); - if constexpr (pairType == kDecayToEE && trackHasCov) { + if constexpr ((pairType == kDecayToEE || pairType == kDecayToKPi) && trackHasCov) { secondaryVertex = fgFitterTwoProngBarrel.getPCACandidate(); covMatrixPCA = fgFitterTwoProngBarrel.calcPCACovMatrixFlat(); auto chi2PCA = fgFitterTwoProngBarrel.getChi2AtPCACandidate(); @@ -2612,13 +3461,13 @@ void VarManager::FillPairVertexing(C const& collision, T const& t1, T const& t2, values[kVertexingLxyz] = std::sqrt(values[kVertexingLxyz]); values[kVertexingTauz] = (collision.posZ() - secondaryVertex[2]) * v12.M() / (TMath::Abs(v12.Pz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauxy] = values[kVertexingLxy] * v12.M() / (v12.P() * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxy] = values[kVertexingLxy] * v12.M() / (v12.Pt() * o2::constants::physics::LightSpeedCm2NS); values[kVertexingPz] = TMath::Abs(v12.Pz()); values[kVertexingSV] = secondaryVertex[2]; values[kVertexingTauzErr] = values[kVertexingLzErr] * v12.M() / (TMath::Abs(v12.Pz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v12.M() / (v12.P() * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v12.M() / (v12.Pt() * o2::constants::physics::LightSpeedCm2NS); values[kCosPointingAngle] = ((collision.posX() - secondaryVertex[0]) * v12.Px() + (collision.posY() - secondaryVertex[1]) * v12.Py() + @@ -2630,9 +3479,11 @@ void VarManager::FillPairVertexing(C const& collision, T const& t1, T const& t2, values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((v12.Px() * v12.Px()) + (v12.Py() * v12.Py())); values[kVertexingLxyzProjected] = ((secondaryVertex[0] - collision.posX()) * v12.Px()) + ((secondaryVertex[1] - collision.posY()) * v12.Py()) + ((secondaryVertex[2] - collision.posZ()) * v12.Pz()); values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((v12.Px() * v12.Px()) + (v12.Py() * v12.Py()) + (v12.Pz() * v12.Pz())); - values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * v12.M() / (v12.P()); + values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * v12.M() / (v12.Pt()); + values[kVertexingTauxyProjectedPoleJPsiMass] = values[kVertexingLxyProjected] * o2::constants::physics::MassJPsi / (v12.Pt()); values[kVertexingTauxyProjectedNs] = values[kVertexingTauxyProjected] / o2::constants::physics::LightSpeedCm2NS; - values[kVertexingTauzProjected] = values[kVertexingLzProjected] * v12.M() / (v12.P()); + values[kVertexingTauzProjected] = values[kVertexingLzProjected] * v12.M() / TMath::Abs(v12.Pz()); + values[kVertexingTauxyzProjected] = values[kVertexingLxyzProjected] * v12.M() / (v12.P()); } } else { KFParticle trk0KF; @@ -2654,12 +3505,26 @@ void VarManager::FillPairVertexing(C const& collision, T const& t1, T const& t2, KFPTrack kfpTrack1 = createKFPFwdTrackFromFwdTrack(t2); trk1KF = KFParticle(kfpTrack1, -13 * t2.sign()); + KFGeoTwoProng.SetConstructMethod(2); + KFGeoTwoProng.AddDaughter(trk0KF); + KFGeoTwoProng.AddDaughter(trk1KF); + + } else if constexpr ((pairType == kDecayToKPi) && trackHasCov) { + KFPTrack kfpTrack0 = createKFPTrackFromTrack(t1); + trk0KF = KFParticle(kfpTrack0, 321 * t1.sign()); + KFPTrack kfpTrack1 = createKFPTrackFromTrack(t2); + trk1KF = KFParticle(kfpTrack1, 211 * t2.sign()); + KFGeoTwoProng.SetConstructMethod(2); KFGeoTwoProng.AddDaughter(trk0KF); KFGeoTwoProng.AddDaughter(trk1KF); } if (fgUsedVars[kKFMass]) { - values[kKFMass] = KFGeoTwoProng.GetMass(); + float mass = 0., massErr = 0.; + if (!KFGeoTwoProng.GetMass(mass, massErr)) + values[kKFMass] = mass; + else + values[kKFMass] = -999.; } if constexpr (eventHasVtxCov) { @@ -2703,9 +3568,10 @@ void VarManager::FillPairVertexing(C const& collision, T const& t1, T const& t2, values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((KFGeoTwoProng.GetPx() * KFGeoTwoProng.GetPx()) + (KFGeoTwoProng.GetPy() * KFGeoTwoProng.GetPy())); values[kVertexingLxyzProjected] = (dxPair2PV * KFGeoTwoProng.GetPx()) + (dyPair2PV * KFGeoTwoProng.GetPy()) + (dzPair2PV * KFGeoTwoProng.GetPz()); values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((KFGeoTwoProng.GetPx() * KFGeoTwoProng.GetPx()) + (KFGeoTwoProng.GetPy() * KFGeoTwoProng.GetPy()) + (KFGeoTwoProng.GetPz() * KFGeoTwoProng.GetPz())); - values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * KFGeoTwoProng.GetMass() / (KFGeoTwoProng.GetP()); + values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * KFGeoTwoProng.GetMass() / (KFGeoTwoProng.GetPt()); + values[kVertexingTauxyProjectedPoleJPsiMass] = values[kVertexingLxyProjected] * o2::constants::physics::MassJPsi / (KFGeoTwoProng.GetPt()); values[kVertexingTauxyProjectedNs] = values[kVertexingTauxyProjected] / o2::constants::physics::LightSpeedCm2NS; - values[kVertexingTauzProjected] = values[kVertexingLzProjected] * KFGeoTwoProng.GetMass() / (KFGeoTwoProng.GetP()); + values[kVertexingTauzProjected] = values[kVertexingLzProjected] * KFGeoTwoProng.GetMass() / TMath::Abs(KFGeoTwoProng.GetPz()); } if (fgUsedVars[kVertexingLxyOverErr] || fgUsedVars[kVertexingLzOverErr] || fgUsedVars[kVertexingLxyzOverErr]) { @@ -2739,6 +3605,34 @@ void VarManager::FillPairVertexing(C const& collision, T const& t1, T const& t2, if (fgUsedVars[kKFTracksDCAxyMax]) { values[kKFTracksDCAxyMax] = TMath::Abs(values[kKFTrack0DCAxy]) > TMath::Abs(values[kKFTrack1DCAxy]) ? values[kKFTrack0DCAxy] : values[kKFTrack1DCAxy]; } + if (fgUsedVars[kKFTrack0DeviationFromPV] || fgUsedVars[kKFTrack1DeviationFromPV]) { + values[kKFTrack0DeviationFromPV] = trk0KF.GetDeviationFromVertex(KFPV); + values[kKFTrack1DeviationFromPV] = trk1KF.GetDeviationFromVertex(KFPV); + } + if (fgUsedVars[kKFTrack0DeviationxyFromPV] || fgUsedVars[kKFTrack1DeviationxyFromPV]) { + values[kKFTrack0DeviationxyFromPV] = trk0KF.GetDeviationFromVertexXY(KFPV); + values[kKFTrack1DeviationxyFromPV] = trk1KF.GetDeviationFromVertexXY(KFPV); + } + if (fgUsedVars[kKFJpsiDCAxyz]) { + values[kKFJpsiDCAxyz] = KFGeoTwoProng.GetDistanceFromVertex(KFPV); + } + if (fgUsedVars[kKFJpsiDCAxy]) { + values[kKFJpsiDCAxy] = KFGeoTwoProng.GetDistanceFromVertexXY(KFPV); + } + if (fgUsedVars[kKFPairDeviationFromPV] || fgUsedVars[kKFPairDeviationxyFromPV]) { + values[kKFPairDeviationFromPV] = KFGeoTwoProng.GetDeviationFromVertex(KFPV); + values[kKFPairDeviationxyFromPV] = KFGeoTwoProng.GetDeviationFromVertexXY(KFPV); + } + if (fgUsedVars[kKFChi2OverNDFGeoTop] || fgUsedVars[kKFMassGeoTop]) { + KFParticle KFGeoTopTwoProngBarrel = KFGeoTwoProng; + KFGeoTopTwoProngBarrel.SetProductionVertex(KFPV); + values[kKFChi2OverNDFGeoTop] = KFGeoTopTwoProngBarrel.GetChi2() / KFGeoTopTwoProngBarrel.GetNDF(); + float mass = 0., massErr = 0.; + if (!KFGeoTopTwoProngBarrel.GetMass(mass, massErr)) + values[kKFMassGeoTop] = mass; + else + values[kKFMassGeoTop] = -999.; + } if (propToSV) { if constexpr ((pairType == kDecayToMuMu) && muonHasCov) { double chi21 = t1.chi2(); @@ -2804,7 +3698,8 @@ void VarManager::FillPairVertexing(C const& collision, T const& t1, T const& t2, values[kMass] = v12.M(); values[kPt] = v12.Pt(); values[kEta] = v12.Eta(); - values[kPhi] = v12.Phi(); + // values[kPhi] = v12.Phi(); + values[kPhi] = v12.Phi() > 0 ? v12.Phi() : v12.Phi() + 2. * M_PI; } else { values[kPt1] = t1.pt(); values[kEta1] = t1.eta(); @@ -2816,6 +3711,222 @@ void VarManager::FillPairVertexing(C const& collision, T const& t1, T const& t2, } } +template +void VarManager::FillTripletVertexing(C const& collision, T const& t1, T const& t2, T const& t3, VarManager::PairCandidateType tripletType, float* values) +{ + // TODO: Vertexing error variables + constexpr bool eventHasVtxCov = ((collFillMap & Collision) > 0 || (collFillMap & ReducedEventVtxCov) > 0); + bool trackHasCov = ((fillMap & ReducedTrackBarrelCov) > 0); + + if (!values) { + values = fgValues; + } + + float m1, m2, m3; + + if (tripletType == kTripleCandidateToKPiPi) { + m1 = o2::constants::physics::MassKaonCharged; + m2 = o2::constants::physics::MassPionCharged; + m3 = o2::constants::physics::MassPionCharged; + } + if (tripletType == kTripleCandidateToPKPi) { + m1 = o2::constants::physics::MassProton; + m2 = o2::constants::physics::MassKaonCharged; + m3 = o2::constants::physics::MassPionCharged; + } + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), m1); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), m2); + ROOT::Math::PtEtaPhiMVector v3(t3.pt(), t3.eta(), t3.phi(), m3); + ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; + + values[kUsedKF] = fgUsedKF; + if (!fgUsedKF) { + int procCode = 0; + + if (trackHasCov) { + std::array t1pars = {t1.y(), t1.z(), t1.snp(), t1.tgl(), t1.signed1Pt()}; + std::array t1covs = {t1.cYY(), t1.cZY(), t1.cZZ(), t1.cSnpY(), t1.cSnpZ(), + t1.cSnpSnp(), t1.cTglY(), t1.cTglZ(), t1.cTglSnp(), t1.cTglTgl(), + t1.c1PtY(), t1.c1PtZ(), t1.c1PtSnp(), t1.c1PtTgl(), t1.c1Pt21Pt2()}; + o2::track::TrackParCov pars1{t1.x(), t1.alpha(), t1pars, t1covs}; + std::array t2pars = {t2.y(), t2.z(), t2.snp(), t2.tgl(), t2.signed1Pt()}; + std::array t2covs = {t2.cYY(), t2.cZY(), t2.cZZ(), t2.cSnpY(), t2.cSnpZ(), + t2.cSnpSnp(), t2.cTglY(), t2.cTglZ(), t2.cTglSnp(), t2.cTglTgl(), + t2.c1PtY(), t2.c1PtZ(), t2.c1PtSnp(), t2.c1PtTgl(), t2.c1Pt21Pt2()}; + o2::track::TrackParCov pars2{t2.x(), t2.alpha(), t2pars, t2covs}; + std::array t3pars = {t3.y(), t3.z(), t3.snp(), t3.tgl(), t3.signed1Pt()}; + std::array t3covs = {t3.cYY(), t3.cZY(), t3.cZZ(), t3.cSnpY(), t3.cSnpZ(), + t3.cSnpSnp(), t3.cTglY(), t3.cTglZ(), t3.cTglSnp(), t3.cTglTgl(), + t3.c1PtY(), t3.c1PtZ(), t3.c1PtSnp(), t3.c1PtTgl(), t3.c1Pt21Pt2()}; + o2::track::TrackParCov pars3{t3.x(), t3.alpha(), t3pars, t3covs}; + procCode = VarManager::fgFitterThreeProngBarrel.process(pars1, pars2, pars3); + } else { + return; + } + + values[VarManager::kVertexingProcCode] = procCode; + if (procCode == 0) { + // TODO: set the other variables to appropriate values and return + values[kVertexingLxy] = -999.; + values[kVertexingLxyz] = -999.; + values[kVertexingLz] = -999.; + values[kVertexingLxyErr] = -999.; + values[kVertexingLxyzErr] = -999.; + values[kVertexingLzErr] = -999.; + + values[kVertexingTauxy] = -999.; + values[kVertexingTauz] = -999.; + values[kVertexingTauxyErr] = -999.; + values[kVertexingTauzErr] = -999.; + + values[kVertexingLzProjected] = -999.; + values[kVertexingLxyProjected] = -999.; + values[kVertexingLxyzProjected] = -999.; + values[kVertexingTauzProjected] = -999.; + values[kVertexingTauxyProjected] = -999.; + values[kVertexingTauxyzProjected] = -999.; + + return; + } + + Vec3D secondaryVertex; + + if constexpr (eventHasVtxCov) { + secondaryVertex = fgFitterThreeProngBarrel.getPCACandidate(); + + std::array covMatrixPCA = fgFitterThreeProngBarrel.calcPCACovMatrixFlat(); + + o2::math_utils::Point3D vtxXYZ(collision.posX(), collision.posY(), collision.posZ()); + std::array vtxCov{collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}; + o2::dataformats::VertexBase primaryVertex = {std::move(vtxXYZ), std::move(vtxCov)}; + auto covMatrixPV = primaryVertex.getCov(); + + double phi = std::atan2(secondaryVertex[1] - collision.posY(), secondaryVertex[0] - collision.posX()); + double theta = std::atan2(secondaryVertex[2] - collision.posZ(), + std::sqrt((secondaryVertex[0] - collision.posX()) * (secondaryVertex[0] - collision.posX()) + + (secondaryVertex[1] - collision.posY()) * (secondaryVertex[1] - collision.posY()))); + + values[kVertexingLxy] = (collision.posX() - secondaryVertex[0]) * (collision.posX() - secondaryVertex[0]) + + (collision.posY() - secondaryVertex[1]) * (collision.posY() - secondaryVertex[1]); + values[kVertexingLz] = (collision.posZ() - secondaryVertex[2]) * (collision.posZ() - secondaryVertex[2]); + values[kVertexingLxyz] = values[kVertexingLxy] + values[kVertexingLz]; + values[kVertexingLxy] = std::sqrt(values[kVertexingLxy]); + values[kVertexingLz] = std::sqrt(values[kVertexingLz]); + values[kVertexingLxyz] = std::sqrt(values[kVertexingLxyz]); + + values[kVertexingLxyzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); + values[kVertexingLxyErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); + values[kVertexingLzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, 0, theta) + getRotatedCovMatrixXX(covMatrixPCA, 0, theta)); + + values[kVertexingTauz] = (collision.posZ() - secondaryVertex[2]) * v123.M() / (TMath::Abs(v123.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxy] = values[kVertexingLxy] * v123.M() / (v123.Pt() * o2::constants::physics::LightSpeedCm2NS); + + values[kVertexingTauzErr] = values[kVertexingLzErr] * v123.M() / (TMath::Abs(v123.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v123.M() / (v123.Pt() * o2::constants::physics::LightSpeedCm2NS); + + values[kCosPointingAngle] = ((collision.posX() - secondaryVertex[0]) * v123.Px() + + (collision.posY() - secondaryVertex[1]) * v123.Py() + + (collision.posZ() - secondaryVertex[2]) * v123.Pz()) / + (v123.P() * values[VarManager::kVertexingLxyz]); + // run 2 definitions: Decay length projected onto the momentum vector of the candidate + values[kVertexingLzProjected] = (secondaryVertex[2] - collision.posZ()) * v123.Pz(); + values[kVertexingLzProjected] = values[kVertexingLzProjected] / TMath::Sqrt(v123.Pz() * v123.Pz()); + values[kVertexingLxyProjected] = ((secondaryVertex[0] - collision.posX()) * v123.Px()) + ((secondaryVertex[1] - collision.posY()) * v123.Py()); + values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((v123.Px() * v123.Px()) + (v123.Py() * v123.Py())); + values[kVertexingLxyzProjected] = ((secondaryVertex[0] - collision.posX()) * v123.Px()) + ((secondaryVertex[1] - collision.posY()) * v123.Py()) + ((secondaryVertex[2] - collision.posZ()) * v123.Pz()); + values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((v123.Px() * v123.Px()) + (v123.Py() * v123.Py()) + (v123.Pz() * v123.Pz())); + + values[kVertexingTauzProjected] = values[kVertexingLzProjected] * v123.M() / TMath::Abs(v123.Pz()); + values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * v123.M() / (v123.Pt()); + values[kVertexingTauxyzProjected] = values[kVertexingLxyzProjected] * v123.M() / (v123.P()); + } + } else { + KFParticle trk0KF; + KFParticle trk1KF; + KFParticle trk2KF; + KFParticle KFGeoThreeProng; + if ((tripletType == kTripleCandidateToKPiPi) && trackHasCov) { + KFPTrack kfpTrack0 = createKFPTrackFromTrack(t1); + trk0KF = KFParticle(kfpTrack0, 321 * t1.sign()); + KFPTrack kfpTrack1 = createKFPTrackFromTrack(t2); + trk1KF = KFParticle(kfpTrack1, 211 * t2.sign()); + KFPTrack kfpTrack2 = createKFPTrackFromTrack(t3); + trk2KF = KFParticle(kfpTrack2, 211 * t3.sign()); + + KFGeoThreeProng.SetConstructMethod(3); + KFGeoThreeProng.AddDaughter(trk0KF); + KFGeoThreeProng.AddDaughter(trk1KF); + KFGeoThreeProng.AddDaughter(trk2KF); + + } else if ((tripletType == kTripleCandidateToPKPi) && trackHasCov) { + KFPTrack kfpTrack0 = createKFPTrackFromTrack(t1); + trk0KF = KFParticle(kfpTrack0, 2212 * t1.sign()); + KFPTrack kfpTrack1 = createKFPTrackFromTrack(t2); + trk1KF = KFParticle(kfpTrack1, 321 * t2.sign()); + KFPTrack kfpTrack2 = createKFPTrackFromTrack(t3); + trk2KF = KFParticle(kfpTrack2, 211 * t3.sign()); + + KFGeoThreeProng.SetConstructMethod(3); + KFGeoThreeProng.AddDaughter(trk0KF); + KFGeoThreeProng.AddDaughter(trk1KF); + KFGeoThreeProng.AddDaughter(trk2KF); + } + if (fgUsedVars[kKFMass]) { + float mass = 0., massErr = 0.; + if (!KFGeoThreeProng.GetMass(mass, massErr)) + values[kKFMass] = mass; + else + values[kKFMass] = -999.; + } + + if constexpr (eventHasVtxCov) { + KFPVertex kfpVertex = createKFPVertexFromCollision(collision); + values[kKFNContributorsPV] = kfpVertex.GetNContributors(); + KFParticle KFPV(kfpVertex); + double dxTriplet2PV = KFGeoThreeProng.GetX() - KFPV.GetX(); + double dyTriplet2PV = KFGeoThreeProng.GetY() - KFPV.GetY(); + double dzTriplet2PV = KFGeoThreeProng.GetZ() - KFPV.GetZ(); + + values[kVertexingLxy] = std::sqrt(dxTriplet2PV * dxTriplet2PV + dyTriplet2PV * dyTriplet2PV); + values[kVertexingLz] = std::sqrt(dzTriplet2PV * dzTriplet2PV); + values[kVertexingLxyz] = std::sqrt(dxTriplet2PV * dxTriplet2PV + dyTriplet2PV * dyTriplet2PV + dzTriplet2PV * dzTriplet2PV); + + values[kVertexingLxyErr] = (KFPV.GetCovariance(0) + KFGeoThreeProng.GetCovariance(0)) * dxTriplet2PV * dxTriplet2PV + (KFPV.GetCovariance(2) + KFGeoThreeProng.GetCovariance(2)) * dyTriplet2PV * dyTriplet2PV + 2 * ((KFPV.GetCovariance(1) + KFGeoThreeProng.GetCovariance(1)) * dxTriplet2PV * dyTriplet2PV); + values[kVertexingLzErr] = (KFPV.GetCovariance(5) + KFGeoThreeProng.GetCovariance(5)) * dzTriplet2PV * dzTriplet2PV; + values[kVertexingLxyzErr] = (KFPV.GetCovariance(0) + KFGeoThreeProng.GetCovariance(0)) * dxTriplet2PV * dxTriplet2PV + (KFPV.GetCovariance(2) + KFGeoThreeProng.GetCovariance(2)) * dyTriplet2PV * dyTriplet2PV + (KFPV.GetCovariance(5) + KFGeoThreeProng.GetCovariance(5)) * dzTriplet2PV * dzTriplet2PV + 2 * ((KFPV.GetCovariance(1) + KFGeoThreeProng.GetCovariance(1)) * dxTriplet2PV * dyTriplet2PV + (KFPV.GetCovariance(3) + KFGeoThreeProng.GetCovariance(3)) * dxTriplet2PV * dzTriplet2PV + (KFPV.GetCovariance(4) + KFGeoThreeProng.GetCovariance(4)) * dyTriplet2PV * dzTriplet2PV); + if (fabs(values[kVertexingLxy]) < 1.e-8f) + values[kVertexingLxy] = 1.e-8f; + values[kVertexingLxyErr] = values[kVertexingLxyErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyErr]) / values[kVertexingLxy]; + if (fabs(values[kVertexingLz]) < 1.e-8f) + values[kVertexingLz] = 1.e-8f; + values[kVertexingLzErr] = values[kVertexingLzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLzErr]) / values[kVertexingLz]; + if (fabs(values[kVertexingLxyz]) < 1.e-8f) + values[kVertexingLxyz] = 1.e-8f; + values[kVertexingLxyzErr] = values[kVertexingLxyzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyzErr]) / values[kVertexingLxyz]; + + values[kVertexingTauxy] = KFGeoThreeProng.GetPseudoProperDecayTime(KFPV, KFGeoThreeProng.GetMass()) / (o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauz] = -1 * dzTriplet2PV * KFGeoThreeProng.GetMass() / (TMath::Abs(KFGeoThreeProng.GetPz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingPz] = TMath::Abs(KFGeoThreeProng.GetPz()); + values[kVertexingSV] = KFGeoThreeProng.GetZ(); + values[kVertexingTauxyErr] = values[kVertexingLxyErr] * KFGeoThreeProng.GetMass() / (KFGeoThreeProng.GetPt() * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauzErr] = values[kVertexingLzErr] * KFGeoThreeProng.GetMass() / (TMath::Abs(KFGeoThreeProng.GetPz()) * o2::constants::physics::LightSpeedCm2NS); + values[kCosPointingAngle] = (std::sqrt(dxTriplet2PV * dxTriplet2PV) * v123.Px() + + std::sqrt(dyTriplet2PV * dyTriplet2PV) * v123.Py() + + std::sqrt(dzTriplet2PV * dzTriplet2PV) * v123.Pz()) / + (v123.P() * values[VarManager::kVertexingLxyz]); + + values[kVertexingLzProjected] = (dzTriplet2PV * KFGeoThreeProng.GetPz()) / TMath::Sqrt(KFGeoThreeProng.GetPz() * KFGeoThreeProng.GetPz()); + values[kVertexingLxyProjected] = (dxTriplet2PV * KFGeoThreeProng.GetPx()) + (dyTriplet2PV * KFGeoThreeProng.GetPy()); + values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((KFGeoThreeProng.GetPx() * KFGeoThreeProng.GetPx()) + (KFGeoThreeProng.GetPy() * KFGeoThreeProng.GetPy())); + values[kVertexingLxyzProjected] = (dxTriplet2PV * KFGeoThreeProng.GetPx()) + (dyTriplet2PV * KFGeoThreeProng.GetPy()) + (dzTriplet2PV * KFGeoThreeProng.GetPz()); + values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((KFGeoThreeProng.GetPx() * KFGeoThreeProng.GetPx()) + (KFGeoThreeProng.GetPy() * KFGeoThreeProng.GetPy()) + (KFGeoThreeProng.GetPz() * KFGeoThreeProng.GetPz())); + values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * KFGeoThreeProng.GetMass() / (KFGeoThreeProng.GetPt()); + values[kVertexingTauxyProjectedNs] = values[kVertexingTauxyProjected] / o2::constants::physics::LightSpeedCm2NS; + values[kVertexingTauzProjected] = values[kVertexingLzProjected] * KFGeoThreeProng.GetMass() / TMath::Abs(KFGeoThreeProng.GetPz()); + } + } +} + template void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton1, T1 const& lepton2, T1 const& track, float* values) { @@ -2828,7 +3939,7 @@ void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton } float mtrack; - float mlepton; + float mlepton1, mlepton2; int procCode = 0; int procCodeJpsi = 0; @@ -2836,7 +3947,8 @@ void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton values[kUsedKF] = fgUsedKF; if (!fgUsedKF) { if constexpr ((candidateType == kBcToThreeMuons) && muonHasCov) { - mlepton = o2::constants::physics::MassMuon; + mlepton1 = o2::constants::physics::MassMuon; + mlepton2 = o2::constants::physics::MassMuon; mtrack = o2::constants::physics::MassMuon; double chi21 = lepton1.chi2(); @@ -2864,9 +3976,16 @@ void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton o2::track::TrackParCovFwd pars3{track.z(), t3pars, t3covs, chi23}; procCode = VarManager::fgFitterThreeProngFwd.process(pars1, pars2, pars3); procCodeJpsi = VarManager::fgFitterTwoProngFwd.process(pars1, pars2); - } else if constexpr ((candidateType == kBtoJpsiEEK) && trackHasCov) { - mlepton = o2::constants::physics::MassElectron; - mtrack = o2::constants::physics::MassKaonCharged; + } else if constexpr ((candidateType == kBtoJpsiEEK || candidateType == kDstarToD0KPiPi) && trackHasCov) { + if constexpr ((candidateType == kBtoJpsiEEK) && trackHasCov) { + mlepton1 = o2::constants::physics::MassElectron; + mlepton2 = o2::constants::physics::MassElectron; + mtrack = o2::constants::physics::MassKaonCharged; + } else if constexpr ((candidateType == kDstarToD0KPiPi) && trackHasCov) { + mlepton1 = o2::constants::physics::MassKaonCharged; + mlepton2 = o2::constants::physics::MassPionCharged; + mtrack = o2::constants::physics::MassPionCharged; + } std::array lepton1pars = {lepton1.y(), lepton1.z(), lepton1.snp(), lepton1.tgl(), lepton1.signed1Pt()}; std::array lepton1covs = {lepton1.cYY(), lepton1.cZY(), lepton1.cZZ(), lepton1.cSnpY(), lepton1.cSnpZ(), lepton1.cSnpSnp(), lepton1.cTglY(), lepton1.cTglZ(), lepton1.cTglSnp(), lepton1.cTglTgl(), @@ -2888,13 +4007,15 @@ void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton return; } - ROOT::Math::PtEtaPhiMVector v1(lepton1.pt(), lepton1.eta(), lepton1.phi(), mlepton); - ROOT::Math::PtEtaPhiMVector v2(lepton2.pt(), lepton2.eta(), lepton2.phi(), mlepton); + ROOT::Math::PtEtaPhiMVector v1(lepton1.pt(), lepton1.eta(), lepton1.phi(), mlepton1); + ROOT::Math::PtEtaPhiMVector v2(lepton2.pt(), lepton2.eta(), lepton2.phi(), mlepton2); ROOT::Math::PtEtaPhiMVector v3(track.pt(), track.eta(), track.phi(), mtrack); ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; ROOT::Math::PtEtaPhiMVector vdilepton(v12.pt(), v12.eta(), v12.phi(), v12.M()); ROOT::Math::PtEtaPhiMVector v123 = vdilepton + v3; values[VarManager::kPairMass] = v123.M(); + values[VarManager::kMassDau] = mtrack; + values[VarManager::kDeltaMass] = v123.M() - v12.M(); values[VarManager::kPairPt] = v123.Pt(); values[VarManager::kPairEta] = v123.Eta(); if (fgUsedVars[kPairMassDau] || fgUsedVars[kPairPtDau]) { @@ -2935,7 +4056,7 @@ void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton o2::dataformats::VertexBase primaryVertex = {std::move(vtxXYZ), std::move(vtxCov)}; auto covMatrixPV = primaryVertex.getCov(); - if constexpr (candidateType == kBtoJpsiEEK && trackHasCov) { + if constexpr ((candidateType == kBtoJpsiEEK || candidateType == kDstarToD0KPiPi) && trackHasCov) { secondaryVertex = fgFitterThreeProngBarrel.getPCACandidate(); covMatrixPCA = fgFitterThreeProngBarrel.calcPCACovMatrixFlat(); } else if constexpr (candidateType == kBcToThreeMuons && muonHasCov) { @@ -2955,10 +4076,10 @@ void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton values[VarManager::kVertexingLxy] = (collision.posX() - secondaryVertex[0]) * (collision.posX() - secondaryVertex[0]) + (collision.posY() - secondaryVertex[1]) * (collision.posY() - secondaryVertex[1]); - values[VarManager::kVertexingLxy] = std::sqrt(values[VarManager::kVertexingLxy]); values[VarManager::kVertexingLz] = (collision.posZ() - secondaryVertex[2]) * (collision.posZ() - secondaryVertex[2]); - values[VarManager::kVertexingLz] = std::sqrt(values[VarManager::kVertexingLz]); values[VarManager::kVertexingLxyz] = values[VarManager::kVertexingLxy] + values[VarManager::kVertexingLz]; + values[VarManager::kVertexingLxy] = std::sqrt(values[VarManager::kVertexingLxy]); + values[VarManager::kVertexingLz] = std::sqrt(values[VarManager::kVertexingLz]); values[VarManager::kVertexingLxyz] = std::sqrt(values[VarManager::kVertexingLxyz]); } @@ -2969,13 +4090,13 @@ void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton } values[kVertexingTauz] = (collision.posZ() - secondaryVertex[2]) * v123.M() / (TMath::Abs(v123.Pz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauxy] = values[kVertexingLxy] * v123.M() / (v123.P() * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxy] = values[kVertexingLxy] * v123.M() / (v123.Pt() * o2::constants::physics::LightSpeedCm2NS); values[kVertexingPz] = TMath::Abs(v123.Pz()); values[kVertexingSV] = secondaryVertex[2]; values[kVertexingTauzErr] = values[kVertexingLzErr] * v123.M() / (TMath::Abs(v123.Pz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v123.M() / (v123.P() * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v123.M() / (v123.Pt() * o2::constants::physics::LightSpeedCm2NS); if (fgUsedVars[kCosPointingAngle] && fgUsedVars[kVertexingLxyz]) { values[VarManager::kCosPointingAngle] = ((collision.posX() - secondaryVertex[0]) * v123.Px() + @@ -2991,8 +4112,8 @@ void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((v123.Px() * v123.Px()) + (v123.Py() * v123.Py())); values[kVertexingLxyzProjected] = ((secondaryVertex[0] - collision.posX()) * v123.Px()) + ((secondaryVertex[1] - collision.posY()) * v123.Py()) + ((secondaryVertex[2] - collision.posZ()) * v123.Pz()); values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((v123.Px() * v123.Px()) + (v123.Py() * v123.Py()) + (v123.Pz() * v123.Pz())); - values[kVertexingTauzProjected] = values[kVertexingLzProjected] * v123.M() / (v123.P()); - values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * v123.M() / (v123.P()); + values[kVertexingTauzProjected] = values[kVertexingLzProjected] * v123.M() / TMath::Abs(v123.Pz()); + values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * v123.M() / v123.Pt(); } } } else { @@ -3073,13 +4194,13 @@ void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((KFGeoThreeProng.GetPx() * KFGeoThreeProng.GetPx()) + (KFGeoThreeProng.GetPy() * KFGeoThreeProng.GetPy())); values[kVertexingLxyzProjected] = (dxTriplet3PV * KFGeoThreeProng.GetPx()) + (dyTriplet3PV * KFGeoThreeProng.GetPy()) + (dzTriplet3PV * KFGeoThreeProng.GetPz()); values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((KFGeoThreeProng.GetPx() * KFGeoThreeProng.GetPx()) + (KFGeoThreeProng.GetPy() * KFGeoThreeProng.GetPy()) + (KFGeoThreeProng.GetPz() * KFGeoThreeProng.GetPz())); - values[kVertexingTauxyProjected] = (values[kVertexingLxyProjected] * KFGeoThreeProng.GetMass()) / (KFGeoThreeProng.GetP()); + values[kVertexingTauxyProjected] = (values[kVertexingLxyProjected] * KFGeoThreeProng.GetMass()) / (KFGeoThreeProng.GetPt()); values[kVertexingTauxyProjectedNs] = values[kVertexingTauxyProjected] / o2::constants::physics::LightSpeedCm2NS; - values[kVertexingTauzProjected] = (values[kVertexingLzProjected] * KFGeoThreeProng.GetMass()) / KFGeoThreeProng.GetP(); + values[kVertexingTauzProjected] = (values[kVertexingLzProjected] * KFGeoThreeProng.GetMass()) / TMath::Abs(KFGeoThreeProng.GetPz()); } // end Run 2 quantities - } // end eventHasVtxCov - } // end (candidateType == kBtoJpsiEEK) && trackHasCov - } // end KF + } // end eventHasVtxCov + } // end (candidateType == kBtoJpsiEEK) && trackHasCov + } // end KF } template @@ -3121,12 +4242,22 @@ void VarManager::FillQVectorFromGFW(C const& /*collision*/, A const& compA11, A values[kQ23YA] = compA23.imag(); // Only being used by cumulants, no need for normalization values[kS11A] = S11A; values[kS12A] = S12A; - values[kS21A] = S21A; values[kS13A] = S13A; values[kS31A] = S31A; - values[kS22A] = S22A; - values[kS14A] = S14A; - values[kS41A] = S41A; + + // Q-vectors components correlation (A, B, C) + values[kQ2YYAB] = values[kQ2Y0A] * values[kQ2Y0B]; + values[kQ2XXAB] = values[kQ2X0A] * values[kQ2X0B]; + values[kQ2XYAB] = values[kQ2X0A] * values[kQ2Y0B]; + values[kQ2YXAB] = values[kQ2Y0A] * values[kQ2X0B]; + values[kQ2YYAC] = values[kQ2Y0A] * values[kQ2Y0C]; + values[kQ2XXAC] = values[kQ2X0A] * values[kQ2X0C]; + values[kQ2XYAC] = values[kQ2X0A] * values[kQ2Y0C]; + values[kQ2YXAC] = values[kQ2Y0A] * values[kQ2X0C]; + values[kQ2YYBC] = values[kQ2Y0B] * values[kQ2Y0C]; + values[kQ2XXBC] = values[kQ2X0B] * values[kQ2X0C]; + values[kQ2XYBC] = values[kQ2X0B] * values[kQ2Y0C]; + values[kQ2YXBC] = values[kQ2Y0B] * values[kQ2X0C]; // Fill event multiplicities values[kMultA] = S10A; @@ -3137,26 +4268,44 @@ void VarManager::FillQVectorFromGFW(C const& /*collision*/, A const& compA11, A values[kM11REF] = S21A - S12A; values[kM1111REF] = S41A - 6. * S12A * S21A + 8. * S13A * S11A + 3. * S22A - 6. * S14A; values[kCORR2REF] = (norm(compA21) - S12A) / values[kM11REF]; - values[kCORR4REF] = (pow(norm(compA21), 2) + norm(compA42) - 2. * (compA42 * conj(compA21) * conj(compA21)).real() + 8. * (compA23 * conj(compA21)).real() - 4. * S12A * norm(compA21) - 6. * S14A - 2. * S22A) / values[kM1111REF]; + values[kCORR4REF] = (pow(norm(compA21), 2) + norm(compA42) - 2. * (compA42 * conj(compA21) * conj(compA21)).real() + 8. * (compA23 * conj(compA21)).real() - 4. * S12A * norm(compA21) - 6. * S14A + 2. * S22A) / values[kM1111REF]; + values[kCORR2REF] = std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : values[kCORR2REF]; + values[kM11REF] = std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : values[kM11REF]; + values[kCORR4REF] = std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : values[kCORR4REF]; + values[kM1111REF] = std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : values[kM1111REF]; + values[kCORR2CORR4REF] = values[kCORR2REF] * values[kCORR4REF]; + values[kM11M1111REF] = values[kM11REF] * values[kM1111REF]; + + // For cumulants: A = Full TPC, B = Negative TPC, C = Positive TPC + complex QA(values[kQ2X0A] * values[kS11A], values[kQ2Y0A] * values[kS11A]); + complex QB(values[kQ2X0B] * S11B, values[kQ2Y0B] * S11B); + complex QC(values[kQ2X0C] * S11C, values[kQ2Y0C] * S11C); + values[kM11REFetagap] = S11B * S11C; + values[kCORR2REFetagap] = ((QB * conj(QC)).real()) / values[kM11REFetagap]; + values[kCORR2REFetagap] = std::isnan(values[kM11REFetagap]) || std::isinf(values[kM11REFetagap]) || std::isnan(values[kCORR2REFetagap]) || std::isinf(values[kCORR2REFetagap]) ? 0 : values[kCORR2REFetagap]; + values[kM11REFetagap] = std::isnan(values[kM11REFetagap]) || std::isinf(values[kM11REFetagap]) || std::isnan(values[kCORR2REFetagap]) || std::isinf(values[kCORR2REFetagap]) ? 0 : values[kM11REFetagap]; // TODO: provide different computations for R // Compute the R factor using the 2 sub-events technique for second and third harmonic // Compute event planes + auto Psi2A = getEventPlane(2, values[kQ2X0A], values[kQ2Y0A]); auto Psi2B = getEventPlane(2, values[kQ2X0B], values[kQ2Y0B]); auto Psi3B = getEventPlane(3, values[kQ3X0B], values[kQ3Y0B]); auto Psi2C = getEventPlane(2, values[kQ2X0C], values[kQ2Y0C]); auto Psi3C = getEventPlane(3, values[kQ3X0C], values[kQ3Y0C]); - values[kR2SP] = (values[kQ2X0B] * values[kQ2X0C] + values[kQ2Y0B] * values[kQ2Y0C]); + values[kPsi2A] = Psi2A; + values[kPsi2B] = Psi2B; + values[kPsi2C] = Psi2C; + + values[kR2SP_AB] = (values[kQ2X0A] * values[kQ2X0B] + values[kQ2Y0A] * values[kQ2Y0B]); + values[kR2SP_AC] = (values[kQ2X0A] * values[kQ2X0C] + values[kQ2Y0A] * values[kQ2Y0C]); + values[kR2SP_BC] = (values[kQ2X0B] * values[kQ2X0C] + values[kQ2Y0B] * values[kQ2Y0C]); values[kR3SP] = (values[kQ3X0B] * values[kQ3X0C] + values[kQ3Y0B] * values[kQ3Y0C]); - if (values[kQ2Y0B] * values[kQ2Y0C] != 0.0) { - values[kR2EP] = TMath::Cos(2 * (Psi2B - Psi2C)); - } - if (values[kQ3Y0B] * values[kQ3Y0C] != 0.0) { - values[kR3EP] = TMath::Cos(3 * (Psi3B - Psi3C)); - } - values[kPsi2A] = getEventPlane(2, values[kQ2X0A], values[kQ2Y0A]); - values[kPsi2B] = getEventPlane(2, values[kQ2X0B], values[kQ2Y0B]); - values[kPsi2C] = getEventPlane(2, values[kQ2X0C], values[kQ2Y0C]); + + values[kR2EP_AB] = TMath::Cos(2 * (Psi2A - Psi2B)); + values[kR2EP_AC] = TMath::Cos(2 * (Psi2A - Psi2C)); + values[kR2EP_BC] = TMath::Cos(2 * (Psi2B - Psi2C)); + values[kR3EP] = TMath::Cos(3 * (Psi3B - Psi3C)); } template @@ -3166,21 +4315,21 @@ void VarManager::FillQVectorFromCentralFW(C const& collision, float* values) values = fgValues; } - float xQVecFT0a = collision.qvecFT0ARe(); // already normalised - float yQVecFT0a = collision.qvecFT0AIm(); // already normalised - float xQVecFT0c = collision.qvecFT0CRe(); // already normalised - float yQVecFT0c = collision.qvecFT0CIm(); // already normalised - float xQVecFT0m = collision.qvecFT0MRe(); // already normalised - float yQVecFT0m = collision.qvecFT0MIm(); // already normalised - float xQVecFV0a = collision.qvecFV0ARe(); // already normalised - float yQVecFV0a = collision.qvecFV0AIm(); // already normalised - float xQVecBPos = collision.qvecBPosRe(); // already normalised - float yQVecBPos = collision.qvecBPosIm(); // already normalised - float xQVecBNeg = collision.qvecBNegRe(); // already normalised - float yQVecBNeg = collision.qvecBNegIm(); // already normalised - - values[kQ2X0A] = (collision.nTrkBPos() * xQVecBPos + collision.nTrkBNeg() * xQVecBNeg) / (collision.nTrkBPos() + collision.nTrkBNeg()); - values[kQ2Y0A] = (collision.nTrkBPos() * yQVecBPos + collision.nTrkBNeg() * yQVecBNeg) / (collision.nTrkBPos() + collision.nTrkBNeg()); + float xQVecFT0a = collision.qvecFT0ARe(); // already normalised + float yQVecFT0a = collision.qvecFT0AIm(); // already normalised + float xQVecFT0c = collision.qvecFT0CRe(); // already normalised + float yQVecFT0c = collision.qvecFT0CIm(); // already normalised + float xQVecFT0m = collision.qvecFT0MRe(); // already normalised + float yQVecFT0m = collision.qvecFT0MIm(); // already normalised + float xQVecFV0a = collision.qvecFV0ARe(); // already normalised + float yQVecFV0a = collision.qvecFV0AIm(); // already normalised + float xQVecBPos = collision.qvecTPCposRe(); // already normalised + float yQVecBPos = collision.qvecTPCposIm(); // already normalised + float xQVecBNeg = collision.qvecTPCnegRe(); // already normalised + float yQVecBNeg = collision.qvecTPCnegIm(); // already normalised + + values[kQ2X0A] = collision.qvecTPCallRe(); + values[kQ2Y0A] = collision.qvecTPCallIm(); values[kQ2X0APOS] = xQVecBPos; values[kQ2Y0APOS] = yQVecBPos; values[kQ2X0ANEG] = xQVecBNeg; @@ -3189,12 +4338,26 @@ void VarManager::FillQVectorFromCentralFW(C const& collision, float* values) values[kQ2Y0B] = yQVecFT0a; values[kQ2X0C] = xQVecFT0c; values[kQ2Y0C] = yQVecFT0c; - values[kMultA] = collision.nTrkBPos() + collision.nTrkBNeg(); - values[kMultAPOS] = collision.nTrkBPos(); - values[kMultANEG] = collision.nTrkBNeg(); + values[kMultA] = collision.nTrkTPCpos() + collision.nTrkTPCneg(); + values[kMultAPOS] = collision.nTrkTPCpos(); + values[kMultANEG] = collision.nTrkTPCneg(); values[kMultB] = collision.sumAmplFT0A(); // Be careful, this is weighted sum of multiplicity values[kMultC] = collision.sumAmplFT0C(); // Be careful, this is weighted sum of multiplicity + // Q-vectors components correlation (A, B, C) + values[kQ2YYAB] = values[kQ2Y0A] * values[kQ2Y0B]; + values[kQ2XXAB] = values[kQ2X0A] * values[kQ2X0B]; + values[kQ2XYAB] = values[kQ2X0A] * values[kQ2Y0B]; + values[kQ2YXAB] = values[kQ2Y0A] * values[kQ2X0B]; + values[kQ2YYAC] = values[kQ2Y0A] * values[kQ2Y0C]; + values[kQ2XXAC] = values[kQ2X0A] * values[kQ2X0C]; + values[kQ2XYAC] = values[kQ2X0A] * values[kQ2Y0C]; + values[kQ2YXAC] = values[kQ2Y0A] * values[kQ2X0C]; + values[kQ2YYBC] = values[kQ2Y0B] * values[kQ2Y0C]; + values[kQ2XXBC] = values[kQ2X0B] * values[kQ2X0C]; + values[kQ2XYBC] = values[kQ2X0B] * values[kQ2Y0C]; + values[kQ2YXBC] = values[kQ2Y0B] * values[kQ2X0C]; + EventPlaneHelper epHelper; float Psi2A = epHelper.GetEventPlane(values[kQ2X0A], values[kQ2Y0A], 2); float Psi2APOS = epHelper.GetEventPlane(values[kQ2X0APOS], values[kQ2Y0APOS], 2); @@ -3208,8 +4371,9 @@ void VarManager::FillQVectorFromCentralFW(C const& collision, float* values) values[kPsi2B] = Psi2B; values[kPsi2C] = Psi2C; - values[kR2SP] = (xQVecBPos * xQVecBNeg + yQVecBPos * yQVecBNeg); - values[kR2SP_FT0CFT0A] = (xQVecFT0c * xQVecFT0a + yQVecFT0c * yQVecFT0a); + values[kR2SP_AB] = (values[kQ2X0A] * values[kQ2X0B] + values[kQ2Y0A] * values[kQ2Y0B]); + values[kR2SP_AC] = (values[kQ2X0A] * values[kQ2X0C] + values[kQ2Y0A] * values[kQ2Y0C]); + values[kR2SP_BC] = (values[kQ2X0B] * values[kQ2X0C] + values[kQ2Y0B] * values[kQ2Y0C]); values[kR2SP_FT0CTPCPOS] = (xQVecFT0c * xQVecBPos + yQVecFT0c * yQVecBPos); values[kR2SP_FT0CTPCNEG] = (xQVecFT0c * xQVecBNeg + yQVecFT0c * yQVecBNeg); values[kR2SP_FT0ATPCPOS] = (xQVecFT0a * xQVecBPos + yQVecFT0a * yQVecBPos); @@ -3225,18 +4389,126 @@ void VarManager::FillQVectorFromCentralFW(C const& collision, float* values) float epFV0a = epHelper.GetEventPlane(xQVecFV0a, yQVecFV0a, 2); float epBPoss = epHelper.GetEventPlane(xQVecBPos, yQVecBPos, 2); float epBNegs = epHelper.GetEventPlane(xQVecBNeg, yQVecBNeg, 2); - // float epTPCFull = epHelper.GetEventPlane(values[kQ2X0A], values[kQ2Y0A]); - - values[kR2EP] = std::cos(2 * getDeltaPsiInRange(epBPoss, epBNegs, 2)); - values[kR2EP_FT0CFT0A] = std::cos(2 * getDeltaPsiInRange(epFT0c, epFT0a, 2)); - values[kR2EP_FT0CTPCPOS] = std::cos(2 * getDeltaPsiInRange(epFT0c, epBPoss, 2)); - values[kR2EP_FT0CTPCNEG] = std::cos(2 * getDeltaPsiInRange(epFT0c, epBNegs, 2)); - values[kR2EP_FT0ATPCPOS] = std::cos(2 * getDeltaPsiInRange(epFT0a, epBPoss, 2)); - values[kR2EP_FT0ATPCNEG] = std::cos(2 * getDeltaPsiInRange(epFT0a, epBNegs, 2)); - values[kR2EP_FT0MTPCPOS] = std::cos(2 * getDeltaPsiInRange(epFT0m, epBPoss, 2)); - values[kR2EP_FT0MTPCNEG] = std::cos(2 * getDeltaPsiInRange(epFT0m, epBNegs, 2)); - values[kR2EP_FV0ATPCPOS] = std::cos(2 * getDeltaPsiInRange(epFV0a, epBPoss, 2)); - values[kR2EP_FV0ATPCNEG] = std::cos(2 * getDeltaPsiInRange(epFV0a, epBNegs, 2)); + float epTPCFull = epHelper.GetEventPlane(values[kQ2X0A], values[kQ2Y0A], 2); + + values[kR2EP_AB] = TMath::Cos(2 * getDeltaPsiInRange(epTPCFull, epFT0a, 2)); + values[kR2EP_AC] = TMath::Cos(2 * getDeltaPsiInRange(epTPCFull, epFT0c, 2)); + values[kR2EP_BC] = TMath::Cos(2 * getDeltaPsiInRange(epFT0a, epFT0c, 2)); + values[kR2EP_FT0CTPCPOS] = TMath::Cos(2 * getDeltaPsiInRange(epFT0c, epBPoss, 2)); + values[kR2EP_FT0CTPCNEG] = TMath::Cos(2 * getDeltaPsiInRange(epFT0c, epBNegs, 2)); + values[kR2EP_FT0ATPCPOS] = TMath::Cos(2 * getDeltaPsiInRange(epFT0a, epBPoss, 2)); + values[kR2EP_FT0ATPCNEG] = TMath::Cos(2 * getDeltaPsiInRange(epFT0a, epBNegs, 2)); + values[kR2EP_FT0MTPCPOS] = TMath::Cos(2 * getDeltaPsiInRange(epFT0m, epBPoss, 2)); + values[kR2EP_FT0MTPCNEG] = TMath::Cos(2 * getDeltaPsiInRange(epFT0m, epBNegs, 2)); + values[kR2EP_FV0ATPCPOS] = TMath::Cos(2 * getDeltaPsiInRange(epFV0a, epBPoss, 2)); + values[kR2EP_FV0ATPCNEG] = TMath::Cos(2 * getDeltaPsiInRange(epFV0a, epBNegs, 2)); +} + +template +void VarManager::FillSpectatorPlane(C const& collision, float* values) +{ + if (!values) { + values = fgValues; + } + + auto zncEnergy = collision.energySectorZNC(); + auto znaEnergy = collision.energySectorZNA(); + for (int i = 0; i < 4; i++) { // avoid std::numeric_limits::infinity() in the table + if (zncEnergy[i] < -1.e12) { + zncEnergy[i] = -1.f; + } + if (znaEnergy[i] < -1.e12) { + znaEnergy[i] = -1.f; + } + } + float znaCommon = collision.energyCommonZNA() < 0 ? -1.f : collision.energyCommonZNA(); + float zncCommon = collision.energyCommonZNC() < 0 ? -1.f : collision.energyCommonZNC(); + float zpaCommon = collision.energyCommonZPA() < 0 ? -1.f : collision.energyCommonZPA(); + float zpcCommon = collision.energyCommonZPC() < 0 ? -1.f : collision.energyCommonZPC(); + + // Store ZNA and ZNC energies for calibrations + values[kEnergyCommonZNA] = znaCommon; + values[kEnergyCommonZNC] = zncCommon; + values[kEnergyCommonZPA] = zpaCommon; + values[kEnergyCommonZPC] = zpcCommon; + values[kEnergyZNA1] = znaEnergy[0]; + values[kEnergyZNA2] = znaEnergy[1]; + values[kEnergyZNA3] = znaEnergy[2]; + values[kEnergyZNA4] = znaEnergy[3]; + values[kEnergyZNC1] = zncEnergy[0]; + values[kEnergyZNC2] = zncEnergy[1]; + values[kEnergyZNC3] = zncEnergy[2]; + values[kEnergyZNC4] = zncEnergy[3]; + values[kTimeZNA] = collision.timeZNA(); + values[kTimeZNC] = collision.timeZNC(); + values[kTimeZPA] = collision.timeZPA(); + values[kTimeZPC] = collision.timeZPC(); + + constexpr float beamEne = 5.36 * 0.5; + constexpr float x[4] = {-1.75, 1.75, -1.75, 1.75}; + constexpr float y[4] = {-1.75, -1.75, 1.75, 1.75}; + // constexpr float intcalibZNA[4] = {0.7997028, 0.8453715, 0.7879917, 0.7695486}; + // constexpr float intcalibZNC[4] = {0.7631577, 0.8408003, 0.7083920, 0.7731769}; + // constexpr float alpha = 0.395; // WARNING: Run 2 coorection, to be checked + constexpr float alpha = 1.; + float numXZNC = 0., numYZNC = 0., denZNC = 0.; + float numXZNA = 0., numYZNA = 0., denZNA = 0.; + + float sumZNA = 0; + float sumZNC = 0; + + for (int i = 0; i < 4; i++) { + if (zncEnergy[i] > 0.) { + float wZNC = std::pow(zncEnergy[i], alpha); + // sumZNC += intcalibZNC[i] * wZNC; + sumZNC += wZNC; + numXZNC -= x[i] * wZNC; + numYZNC += y[i] * wZNC; + denZNC += wZNC; + } + if (znaEnergy[i] > 0.) { + float wZNA = std::pow(znaEnergy[i], alpha); + // sumZNA += intcalibZNA[i] * wZNA; + sumZNA += wZNA; + numXZNA += x[i] * wZNA; + numYZNA += y[i] * wZNA; + denZNA += wZNA; + } + } + + if (denZNC != 0.) { + float nSpecnC = zncCommon / beamEne; // WARNING: Run 2 coorection, to be checked + float cZNC = 1.89358 - 0.71262 / (nSpecnC + 0.71789); // WARNING: Run 2 coorection, to be checked + cZNC = 1.; + values[kQ1ZNCX] = cZNC * numXZNC / denZNC; + values[kQ1ZNCY] = cZNC * numYZNC / denZNC; + } else { + values[kQ1ZNCX] = values[kQ1ZNCY] = 999.; + } + + if (denZNA != 0.) { + float nSpecnA = znaCommon / beamEne; // WARNING: Run 2 coorection, to be checked + float cZNA = 1.89358 - 0.71262 / (nSpecnA + 0.71789); // WARNING: Run 2 coorection, to be checked + cZNA = 1.; + values[kQ1ZNAX] = cZNA * numXZNA / denZNA; + values[kQ1ZNAY] = cZNA * numYZNA / denZNA; + } else { + values[kQ1ZNAX] = values[kQ1ZNAY] = 999.; + } + + if (denZNA != 0. && denZNC != 0.) { + values[kQ1ZNACXX] = values[kQ1ZNAX] * values[kQ1ZNCX]; + values[kQ1ZNACYY] = values[kQ1ZNAY] * values[kQ1ZNCY]; + values[kQ1ZNACYX] = values[kQ1ZNAY] * values[kQ1ZNCX]; + values[kQ1ZNACXY] = values[kQ1ZNAX] * values[kQ1ZNCY]; + } else { + values[kQ1ZNACXX] = values[kQ1ZNACYY] = values[kQ1ZNACYX] = values[kQ1ZNACXY] = 999.; + } + + if (znaCommon != 0 && sumZNA != 0 && zncCommon != 0 && sumZNC) { + values[KIntercalibZNA] = znaCommon - sumZNA; + values[KIntercalibZNC] = zncCommon - sumZNC; + } } template @@ -3267,38 +4539,58 @@ void VarManager::FillPairVn(T1 const& t1, T2 const& t2, float* values) ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), m1); ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), m2); ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + values[kPt1] = t1.pt(); + values[kPt2] = t2.pt(); // TODO: provide different computations for vn // Compute the scalar product UQ using Q-vector from A, for second and third harmonic // Dilepton vn could be accessible after dividing this product with the R factor - values[kU2Q2] = values[kQ2X0A] * std::cos(2 * v12.Phi()) + values[kQ2Y0A] * std::sin(2 * v12.Phi()); - values[kU3Q3] = values[kQ3X0A] * std::cos(3 * v12.Phi()) + values[kQ3Y0A] * std::sin(3 * v12.Phi()); - values[kCos2DeltaPhi] = std::cos(2 * (v12.Phi() - getEventPlane(2, values[kQ2X0A], values[kQ2Y0A]))); - values[kCos3DeltaPhi] = std::cos(3 * (v12.Phi() - getEventPlane(3, values[kQ3X0A], values[kQ3Y0A]))); + values[kU2Q2] = values[kQ2X0A] * TMath::Cos(2 * v12.Phi()) + values[kQ2Y0A] * TMath::Sin(2 * v12.Phi()); + values[kU3Q3] = values[kQ3X0A] * TMath::Cos(3 * v12.Phi()) + values[kQ3Y0A] * TMath::Sin(3 * v12.Phi()); + values[kR2SP_AB] = (values[kQ2X0A] * values[kQ2X0B] + values[kQ2Y0A] * values[kQ2Y0B]); + values[kR2SP_AC] = (values[kQ2X0A] * values[kQ2X0C] + values[kQ2Y0A] * values[kQ2Y0C]); + values[kR2SP_BC] = (values[kQ2X0B] * values[kQ2X0C] + values[kQ2Y0B] * values[kQ2Y0C]); + values[kR3SP] = (values[kQ3X0B] * values[kQ3X0C] + values[kQ3Y0B] * values[kQ3Y0C]); + float Psi2A = getEventPlane(2, values[kQ2X0A], values[kQ2Y0A]); + float Psi3A = getEventPlane(3, values[kQ3X0A], values[kQ3Y0A]); float Psi2B = getEventPlane(2, values[kQ2X0B], values[kQ2Y0B]); float Psi3B = getEventPlane(3, values[kQ3X0B], values[kQ3Y0B]); float Psi2C = getEventPlane(2, values[kQ2X0C], values[kQ2Y0C]); float Psi3C = getEventPlane(3, values[kQ3X0C], values[kQ3Y0C]); - values[kR2SP] = (values[kQ2X0B] * values[kQ2X0C] + values[kQ2Y0B] * values[kQ2Y0C]); - values[kR3SP] = (values[kQ3X0B] * values[kQ3X0C] + values[kQ3Y0B] * values[kQ3Y0C]); - if (values[kQ2Y0B] * values[kQ2Y0C] != 0.0) { - values[kR2EP] = TMath::Cos(2 * (Psi2B - Psi2C)); - } - if (values[kQ3Y0B] * values[kQ3Y0C] != 0.0) { - values[kR3EP] = TMath::Cos(3 * (Psi3B - Psi3C)); - } - - values[kCos2DeltaPhiMu1] = std::cos(2 * (v1.Phi() - v12.Phi())); - values[kCos2DeltaPhiMu2] = std::cos(2 * (v2.Phi() - v12.Phi())); - if (isnan(VarManager::fgValues[VarManager::kU2Q2]) == true) { + values[kCos2DeltaPhi] = TMath::Cos(2 * (v12.Phi() - Psi2A)); + values[kCos3DeltaPhi] = TMath::Cos(3 * (v12.Phi() - Psi3A)); + values[kR2EP_AB] = TMath::Cos(2 * (Psi2A - Psi2B)); + values[kR2EP_AC] = TMath::Cos(2 * (Psi2A - Psi2C)); + values[kR2EP_BC] = TMath::Cos(2 * (Psi2B - Psi2C)); + values[kR3EP] = TMath::Cos(3 * (Psi3B - Psi3C)); + + float V2SP = values[kU2Q2] / values[kR2SP]; + float V2EP = values[kCos2DeltaPhi] / values[kR2EP]; + values[kV2SP] = std::isnan(V2SP) || std::isinf(V2SP) ? 0. : V2SP; + values[kWV2SP] = std::isnan(V2SP) || std::isinf(V2SP) ? 0. : 1.0; + values[kV2EP] = std::isnan(V2EP) || std::isinf(V2EP) ? 0. : V2EP; + values[kWV2EP] = std::isnan(V2EP) || std::isinf(V2EP) ? 0. : 1.0; + + if (std::isnan(VarManager::fgValues[VarManager::kU2Q2]) == true) { values[kU2Q2] = -999.; + values[kR2SP_AB] = -999.; + values[kR2SP_AC] = -999.; + values[kR2SP_BC] = -999.; + } + if (std::isnan(VarManager::fgValues[VarManager::kU3Q3]) == true) { values[kU3Q3] = -999.; + values[kR3SP] = -999.; + } + if (std::isnan(VarManager::fgValues[VarManager::kCos2DeltaPhi]) == true) { values[kCos2DeltaPhi] = -999.; + values[kR2EP_AB] = -999.; + values[kR2EP_AC] = -999.; + values[kR2EP_BC] = -999.; + } + if (std::isnan(VarManager::fgValues[VarManager::kCos3DeltaPhi]) == true) { values[kCos3DeltaPhi] = -999.; - values[kPsi2A] = -999.; - values[kPsi2B] = -999.; - values[kPsi2C] = -999.; + values[kR3EP] = -999.; } // kV4, kC4POI, kC4REF etc. @@ -3306,16 +4598,85 @@ void VarManager::FillPairVn(T1 const& t1, T2 const& t2, float* values) complex Q21(values[kQ2X0A] * values[kS11A], values[kQ2Y0A] * values[kS11A]); complex Q42(values[kQ42XA], values[kQ42YA]); complex Q23(values[kQ23XA], values[kQ23YA]); - complex P2(std::cos(2 * v12.Phi()), std::sin(2 * v12.Phi())); + complex P2(TMath::Cos(2 * v12.Phi()), TMath::Sin(2 * v12.Phi())); values[kM01POI] = values[kMultDimuons] * values[kS11A]; values[kM0111POI] = values[kMultDimuons] * (values[kS31A] - 3. * values[kS11A] * values[kS12A] + 2. * values[kS13A]); values[kCORR2POI] = (P2 * conj(Q21)).real() / values[kM01POI]; values[kCORR4POI] = (P2 * Q21 * conj(Q21) * conj(Q21) - P2 * Q21 * conj(Q42) - 2. * values[kS12A] * P2 * conj(Q21) + 2. * P2 * conj(Q23)).real() / values[kM0111POI]; - values[kM11REF] = values[kS21A] - values[kS12A]; - values[kM1111REF] = values[kS41A] - 6. * values[kS12A] * values[kS21A] + 8. * values[kS13A] * values[kS11A] + 3. * values[kS22A] - 6. * values[kS14A]; - values[kCORR2REF] = (norm(Q21) - values[kS12A]) / values[kM11REF]; - values[kCORR4REF] = (pow(norm(Q21), 2) + norm(Q42) - 2. * (Q42 * conj(Q21) * conj(Q21)).real() + 8. * (Q23 * conj(Q21)).real() - 4. * values[kS12A] * norm(Q21) - 6. * values[kS14A] - 2. * values[kS22A]) / values[kM1111REF]; + values[kM01POIoverMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI])) ? values[kM01POI] / values[kMultDimuons] : 0; + values[kM0111POIoverMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI])) ? values[kM0111POI] / values[kMultDimuons] : 0; + values[kM11REFoverMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM11REF] / values[kMultDimuons] : 0; + values[kM1111REFoverMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF])) ? values[kM1111REF] / values[kMultDimuons] : 0; + values[kCORR2REFbydimuons] = std::isnan(values[kM11REFoverMp]) || std::isinf(values[kM11REFoverMp]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REFoverMp]) || std::isinf(values[kM1111REFoverMp]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : values[kCORR2REF]; + values[kCORR4REFbydimuons] = std::isnan(values[kM1111REFoverMp]) || std::isinf(values[kM1111REFoverMp]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REFoverMp]) || std::isinf(values[kM11REFoverMp]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : values[kCORR4REF]; + values[kCORR2POI] = std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) ? 0 : values[kCORR2POI]; + values[kCORR4POI] = std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) ? 0 : values[kCORR4POI]; + values[kCORR2CORR4REF] = std::isnan(values[kM11M1111REFoverMp]) || std::isinf(values[kM11M1111REFoverMp]) || std::isnan(values[kCORR2CORR4REF]) || std::isinf(values[kCORR2CORR4REF]) ? 0 : values[kCORR2CORR4REF]; + values[kCORR2POICORR4POI] = std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) ? 0 : values[kCORR2POI] * values[kCORR4POI]; + values[kCORR2REFCORR4POI] = std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) ? 0 : values[kCORR2REF] * values[kCORR4POI]; + values[kCORR2REFCORR2POI] = std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) ? 0 : values[kCORR2REF] * values[kCORR2POI]; + values[kM11M1111REFoverMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM11M1111REF]) || std::isinf(values[kM11M1111REF]) || std::isnan(values[kCORR2CORR4REF]) || std::isinf(values[kCORR2CORR4REF])) ? values[kM11M1111REF] / values[kMultDimuons] : 0; + values[kM01M0111overMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI])) ? (values[kM01POI] * values[kM0111POI]) / values[kMultDimuons] : 0; + values[kM11M0111overMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI])) ? (values[kM11REF] * values[kM0111POI]) / values[kMultDimuons] : 0; + values[kM11M01overMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI])) ? (values[kM11REF] * values[kM01POI]) / values[kMultDimuons] : 0; + + complex P2plus(TMath::Cos(2 * v1.Phi()), TMath::Sin(2 * v1.Phi())); + complex P2minus(TMath::Cos(2 * v2.Phi()), TMath::Sin(2 * v2.Phi())); + values[kM11REFoverMpplus] = values[kMultAntiMuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM11REF] / values[kMultAntiMuons] : 0; + values[kM1111REFoverMpplus] = values[kMultAntiMuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM1111REF] / values[kMultAntiMuons] : 0; + values[kM11REFoverMpminus] = values[kMultMuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM11REF] / values[kMultMuons] : 0; + values[kM1111REFoverMpminus] = values[kMultMuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM1111REF] / values[kMultMuons] : 0; + values[kCORR2POIplus] = (P2plus * conj(Q21)).real() / values[kM01POI]; + values[kCORR2POIminus] = (P2minus * conj(Q21)).real() / values[kM01POI]; + values[kM01POIplus] = values[kMultAntiMuons] * values[kS11A]; + values[kM0111POIplus] = values[kMultAntiMuons] * (values[kS31A] - 3. * values[kS11A] * values[kS12A] + 2. * values[kS13A]); + values[kCORR2POIplus] = (P2plus * conj(Q21)).real() / values[kM01POIplus]; + values[kCORR4POIplus] = (P2plus * Q21 * conj(Q21) * conj(Q21) - P2plus * Q21 * conj(Q42) - 2. * values[kS12A] * P2plus * conj(Q21) + 2. * P2plus * conj(Q23)).real() / values[kM0111POIplus]; + values[kM01POIminus] = values[kMultMuons] * values[kS11A]; + values[kM0111POIminus] = values[kMultMuons] * (values[kS31A] - 3. * values[kS11A] * values[kS12A] + 2. * values[kS13A]); + values[kCORR2POIminus] = (P2minus * conj(Q21)).real() / values[kM01POIminus]; + values[kCORR4POIminus] = (P2minus * Q21 * conj(Q21) * conj(Q21) - P2minus * Q21 * conj(Q42) - 2. * values[kS12A] * P2minus * conj(Q21) + 2. * P2minus * conj(Q23)).real() / values[kM0111POIminus]; + values[kM01POIplus] = std::isnan(values[kM01POIplus]) || std::isinf(values[kM01POIplus]) || std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) ? 0 : values[kM01POIplus]; + values[kM0111POIplus] = std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) ? 0 : values[kM0111POIplus]; + values[kCORR2POIplus] = std::isnan(values[kM01POIplus]) || std::isinf(values[kM01POIplus]) || std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) ? 0 : values[kCORR2POIplus]; + values[kCORR4POIplus] = std::isnan(values[kM01POIplus]) || std::isinf(values[kM01POIplus]) || std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) ? 0 : values[kCORR4POIplus]; + values[kM01POIminus] = std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) ? 0 : values[kM01POIminus]; + values[kM0111POIminus] = std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) ? 0 : values[kM0111POIminus]; + values[kCORR2POIminus] = std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) ? 0 : values[kCORR2POIminus]; + values[kCORR4POIminus] = std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) ? 0 : values[kCORR4POIminus]; + values[kM01POIoverMpminus] = values[kMultMuons] > 0 && !(std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) || std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus])) ? values[kM01POIminus] / values[kMultMuons] : 0; + values[kM0111POIoverMpminus] = values[kMultMuons] > 0 && !(std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) || std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus])) ? values[kM0111POIminus] / values[kMultMuons] : 0; + values[kM01POIoverMpplus] = values[kMultAntiMuons] > 0 && !(std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) || std::isnan(values[kM01POIplus]) || std::isinf(values[kM01POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus])) ? values[kM01POIplus] / values[kMultAntiMuons] : 0; + values[kM0111POIoverMpplus] = values[kMultMuons] > 0 && !(std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) || std::isnan(values[kM01POIplus]) || std::isinf(values[kM01POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus])) ? values[kM0111POIplus] / values[kMultAntiMuons] : 0; + } + + ROOT::Math::PtEtaPhiMVector v1_vp(v1.Pt(), v1.Eta(), v1.Phi() - Psi2B, v1.M()); + ROOT::Math::PtEtaPhiMVector v2_vp(v2.Pt(), v2.Eta(), v2.Phi() - Psi2B, v2.M()); + ROOT::Math::PtEtaPhiMVector v12_vp = v1_vp + v2_vp; + auto p12_vp = ROOT::Math::XYZVectorF(v12_vp.Px(), v12_vp.Py(), v12_vp.Pz()); + auto p12_vp_projXZ = ROOT::Math::XYZVectorF(p12_vp.X(), 0, p12_vp.Z()); + auto vDimu = (t1.sign() > 0 ? ROOT::Math::XYZVectorF(v1_vp.Px(), v1_vp.Py(), v1_vp.Pz()).Cross(ROOT::Math::XYZVectorF(v2_vp.Px(), v2_vp.Py(), v2_vp.Pz())) + : ROOT::Math::XYZVectorF(v2_vp.Px(), v2_vp.Py(), v2_vp.Pz()).Cross(ROOT::Math::XYZVectorF(v1_vp.Px(), v1_vp.Py(), v1_vp.Pz()))); + auto vRef = p12_vp.Cross(p12_vp_projXZ); + values[kCosPhiVP] = vDimu.Dot(vRef) / (vRef.R() * vDimu.R()); + values[kPhiVP] = std::acos(vDimu.Dot(vRef) / (vRef.R() * vDimu.R())); +} + +template +void VarManager::FillZDC(T const& zdc, float* values) +{ + if (!values) { + values = fgValues; } + + values[kEnergyCommonZNA] = (zdc.energyCommonZNA() > 0) ? zdc.energyCommonZNA() : -1.; + values[kEnergyCommonZNC] = (zdc.energyCommonZNC() > 0) ? zdc.energyCommonZNC() : -1.; + values[kEnergyCommonZPA] = (zdc.energyCommonZPA() > 0) ? zdc.energyCommonZPA() : -1.; + values[kEnergyCommonZPC] = (zdc.energyCommonZPC() > 0) ? zdc.energyCommonZPC() : -1.; + values[kTimeZNA] = zdc.timeZNA(); + values[kTimeZNC] = zdc.timeZNC(); + values[kTimeZPA] = zdc.timeZPA(); + values[kTimeZPC] = zdc.timeZPC(); } template @@ -3336,6 +4697,7 @@ void VarManager::FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* values[kPairMassDau] = dilepton.mass(); values[kPairPtDau] = dilepton.pt(); values[kMassDau] = hadronMass; + values[kDeltaMass] = v12.M() - dilepton.mass(); } if (fgUsedVars[kDeltaPhi]) { double delta = dilepton.phi() - hadron.phi(); @@ -3444,16 +4806,16 @@ void VarManager::FillDileptonTrackTrack(T1 const& dilepton, T2 const& hadron1, T values = fgValues; } - double DefaultdileptonMass = 3.096; + double defaultDileptonMass = 3.096; double hadronMass1 = o2::constants::physics::MassPionCharged; double hadronMass2 = o2::constants::physics::MassPionCharged; if (candidateType == kXtoJpsiPiPi) { - DefaultdileptonMass = 3.096; + defaultDileptonMass = 3.096; hadronMass1 = o2::constants::physics::MassPionCharged; hadronMass2 = o2::constants::physics::MassPionCharged; } if (candidateType == kChictoJpsiEE) { - DefaultdileptonMass = 3.096; + defaultDileptonMass = 3.096; hadronMass1 = o2::constants::physics::MassElectron; hadronMass2 = o2::constants::physics::MassElectron; } @@ -3462,19 +4824,183 @@ void VarManager::FillDileptonTrackTrack(T1 const& dilepton, T2 const& hadron1, T ROOT::Math::PtEtaPhiMVector v2(hadron1.pt(), hadron1.eta(), hadron1.phi(), hadronMass1); ROOT::Math::PtEtaPhiMVector v3(hadron2.pt(), hadron2.eta(), hadron2.phi(), hadronMass2); ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; - values[kQuadMass] = v123.M() - v1.M() + DefaultdileptonMass; + values[kQuadMass] = v123.M(); + values[kQuadDefaultDileptonMass] = v123.M() - v1.M() + defaultDileptonMass; values[kQuadPt] = v123.Pt(); values[kQuadEta] = v123.Eta(); values[kQuadPhi] = v123.Phi(); - if (fgUsedVars[kCosthetaDileptonDitrack] || fgUsedVars[kPairMass] || fgUsedVars[kPairPt] || fgUsedVars[kDitrackPt] || fgUsedVars[kDitrackMass]) { + values[kTrackDCAxyProng1] = hadron1.dcaXY(); + values[kTrackDCAzProng1] = hadron1.dcaZ(); + values[kPt1] = hadron1.pt(); + + values[kTrackDCAxyProng2] = hadron2.dcaXY(); + values[kTrackDCAzProng2] = hadron2.dcaZ(); + values[kPt2] = hadron2.pt(); + + if (fgUsedVars[kCosthetaDileptonDitrack] || fgUsedVars[kPairMass] || fgUsedVars[kPairPt] || fgUsedVars[kDitrackPt] || fgUsedVars[kDitrackMass] || fgUsedVars[kQ] || fgUsedVars[kDeltaR1] || fgUsedVars[kDeltaR2] || fgUsedVars[kRap]) { ROOT::Math::PtEtaPhiMVector v23 = v2 + v3; values[kPairMass] = v1.M(); values[kPairPt] = v1.Pt(); values[kDitrackMass] = v23.M(); values[kDitrackPt] = v23.Pt(); values[kCosthetaDileptonDitrack] = (v1.Px() * v123.Px() + v1.Py() * v123.Py() + v1.Pz() * v123.Pz()) / (v1.P() * v123.P()); + values[kQ] = v123.M() - defaultDileptonMass - v23.M(); + values[kDeltaR1] = ROOT::Math::VectorUtil::DeltaR(v1, v2); + values[kDeltaR2] = ROOT::Math::VectorUtil::DeltaR(v1, v3); + values[kDeltaR] = sqrt(pow(values[kDeltaR1], 2) + pow(values[kDeltaR2], 2)); + values[kRap] = v123.Rapidity(); + } +} + +//__________________________________________________________________ +template +void VarManager::FillQaudMC(T1 const& dilepton, T2 const& track1, T2 const& track2, float* values) +{ + if (!values) { + values = fgValues; + } + + double defaultDileptonMass = 3.096; + double hadronMass1 = o2::constants::physics::MassPionCharged; + double hadronMass2 = o2::constants::physics::MassPionCharged; + if (candidateType == kXtoJpsiPiPi) { + defaultDileptonMass = 3.096; + hadronMass1 = o2::constants::physics::MassPionCharged; + hadronMass2 = o2::constants::physics::MassPionCharged; } + + ROOT::Math::PtEtaPhiMVector v1(dilepton.pt(), dilepton.eta(), dilepton.phi(), defaultDileptonMass); + ROOT::Math::PtEtaPhiMVector v2(track1.pt(), track1.eta(), track1.phi(), hadronMass1); + ROOT::Math::PtEtaPhiMVector v3(track2.pt(), track2.eta(), track2.phi(), hadronMass2); + ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; + ROOT::Math::PtEtaPhiMVector v23 = v2 + v3; + values[kQuadMass] = v123.M(); + values[kQuadDefaultDileptonMass] = v123.M(); + values[kQuadPt] = v123.Pt(); + values[kQuadEta] = v123.Eta(); + values[kQuadPhi] = v123.Phi(); + values[kQ] = v123.M() - defaultDileptonMass - v23.M(); + values[kDeltaR1] = ROOT::Math::VectorUtil::DeltaR(v1, v2); + values[kDeltaR2] = ROOT::Math::VectorUtil::DeltaR(v1, v3); + values[kDeltaR] = sqrt(pow(values[kDeltaR1], 2) + pow(values[kDeltaR2], 2)); + values[kDitrackMass] = v23.M(); + values[kDitrackPt] = v23.Pt(); +} + +//__________________________________________________________________ +template +float VarManager::calculatePhiV(T1 const& t1, T2 const& t2) +{ + // cos(phiv) = w*a /|w||a| + // with w = u x v + // and a = u x z / |u x z| , unit vector perpendicular to v12 and z-direction (magnetic field) + // u = v12 / |v12| , the unit vector of v12 + // v = v1 x v2 / |v1 x v2| , unit vector perpendicular to v1 and v2 + + float m1 = o2::constants::physics::MassElectron; + float m2 = o2::constants::physics::MassElectron; + if constexpr (pairType == kDecayToMuMu) { + m1 = o2::constants::physics::MassMuon; + m2 = o2::constants::physics::MassMuon; + } + + if constexpr (pairType == kDecayToPiPi) { + m1 = o2::constants::physics::MassPionCharged; + m2 = o2::constants::physics::MassPionCharged; + } + + if constexpr (pairType == kElectronMuon) { + m2 = o2::constants::physics::MassMuon; + } + + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), m1); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), m2); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + + float pairPhiV = -999; + float bz = fgMagField; + + bool swapTracks = false; + if (v1.Pt() < v2.Pt()) { // ordering of track, pt1 > pt2 + ROOT::Math::PtEtaPhiMVector v3 = v1; + v1 = v2; + v2 = v3; + swapTracks = true; + } + + // momentum of e+ and e- in (ax,ay,az) axis. Note that az=0 by definition. + // vector product of pep X pem + float vpx = 0, vpy = 0, vpz = 0; + if (t1.sign() * t2.sign() > 0) { // Like Sign + if (!swapTracks) { + if (bz * t1.sign() < 0) { + vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); + vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); + vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); + } else { + vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); + vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); + vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); + } + } else { // swaped tracks + if (bz * t2.sign() < 0) { + vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); + vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); + vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); + } else { + vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); + vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); + vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); + } + } + } else { // Unlike Sign + if (!swapTracks) { + if (bz * t1.sign() > 0) { + vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); + vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); + vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); + } else { + vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); + vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); + vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); + } + } else { // swaped tracks + if (bz * t2.sign() > 0) { + vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); + vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); + vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); + } else { + vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); + vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); + vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); + } + } + } + + // unit vector of pep X pem + float vx = vpx / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); + float vy = vpy / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); + float vz = vpz / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); + + float px = v12.Px(); + float py = v12.Py(); + float pz = v12.Pz(); + + // unit vector of (pep+pem) + float ux = px / TMath::Sqrt(px * px + py * py + pz * pz); + float uy = py / TMath::Sqrt(px * px + py * py + pz * pz); + float uz = pz / TMath::Sqrt(px * px + py * py + pz * pz); + float ax = uy / TMath::Sqrt(ux * ux + uy * uy); + float ay = -ux / TMath::Sqrt(ux * ux + uy * uy); + + // The third axis defined by vector product (ux,uy,uz)X(vx,vy,vz) + float wx = uy * vz - uz * vy; + float wy = uz * vx - ux * vz; + // by construction, (wx,wy,wz) must be a unit vector. Measure angle between (wx,wy,wz) and (ax,ay,0). + // The angle between them should be small if the pair is conversion. This function then returns values close to pi! + pairPhiV = TMath::ACos(wx * ax + wy * ay); // phiv in [0,pi] //cosPhiV = wx * ax + wy * ay; + return pairPhiV; } #endif // PWGDQ_CORE_VARMANAGER_H_ diff --git a/PWGDQ/DataModel/ReducedInfoTables.h b/PWGDQ/DataModel/ReducedInfoTables.h index d3e235b206d..ca79b6becb3 100644 --- a/PWGDQ/DataModel/ReducedInfoTables.h +++ b/PWGDQ/DataModel/ReducedInfoTables.h @@ -16,6 +16,7 @@ #define PWGDQ_DATAMODEL_REDUCEDINFOTABLES_H_ #include +#include #include "Framework/ASoA.h" #include "Framework/AnalysisDataModel.h" #include "Common/DataModel/Centrality.h" @@ -25,22 +26,77 @@ #include "Common/DataModel/PIDResponse.h" #include "MathUtils/Utils.h" +#include "PWGHF/Utils/utilsPid.h" + namespace o2::aod { namespace dqppfilter { DECLARE_SOA_COLUMN(EventFilter, eventFilter, uint64_t); //! Bit-field used for the high level event triggering +DECLARE_SOA_COLUMN(NewBcMultFT0A, newBcMultFT0A, float); //! sum of amplitudes on A side of FT0 +DECLARE_SOA_COLUMN(NewBcMultFT0C, newBcMultFT0C, float); //! sum of amplitudes on C side of FT0 +DECLARE_SOA_COLUMN(NewBcMultFDDA, newBcMultFDDA, float); //! sum of amplitudes on A side of FDD +DECLARE_SOA_COLUMN(NewBcMultFDDC, newBcMultFDDC, float); //! sum of amplitudes on C side of FDD +DECLARE_SOA_COLUMN(NewBcMultFV0A, newBcMultFV0A, float); //! sum of amplitudes on A side of FDD } DECLARE_SOA_TABLE(DQEventFilter, "AOD", "EVENTFILTER", //! Store event-level decisions (DQ high level triggers) dqppfilter::EventFilter); +DECLARE_SOA_TABLE(DQRapidityGapFilter, "AOD", "RAPIDITYGAPFILTER", + dqppfilter::EventFilter, + dqppfilter::NewBcMultFT0A, + dqppfilter::NewBcMultFT0C, + dqppfilter::NewBcMultFDDA, + dqppfilter::NewBcMultFDDC, + dqppfilter::NewBcMultFV0A, + zdc::EnergyCommonZNA, + zdc::EnergyCommonZNC, + zdc::EnergyCommonZPA, + zdc::EnergyCommonZPC, + zdc::TimeZNA, + zdc::TimeZNC, + zdc::TimeZPA, + zdc::TimeZPC); + namespace reducedevent { // basic event information +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! DECLARE_SOA_BITMAP_COLUMN(Tag, tag, 64); //! Bit-field for storing event information (e.g. high level info, cut decisions) +DECLARE_SOA_COLUMN(MCPosX, mcPosX, float); //! MC event position X +DECLARE_SOA_COLUMN(MCPosY, mcPosY, float); //! MC event position Y +DECLARE_SOA_COLUMN(MCPosZ, mcPosZ, float); //! MC event position Z +DECLARE_SOA_COLUMN(NTPCoccupContribLongA, nTPCoccupContribLongA, int); //! TPC pileup occupancy on A side (long time range) +DECLARE_SOA_COLUMN(NTPCoccupContribLongC, nTPCoccupContribLongC, int); //! TPC pileup occupancy on C side (long time range) +DECLARE_SOA_COLUMN(NTPCoccupMeanTimeLongA, nTPCoccupMeanTimeLongA, float); //! TPC pileup mean time on A side (long time range) +DECLARE_SOA_COLUMN(NTPCoccupMeanTimeLongC, nTPCoccupMeanTimeLongC, float); //! TPC pileup mean time on C side (long time range) +DECLARE_SOA_COLUMN(NTPCoccupMedianTimeLongA, nTPCoccupMedianTimeLongA, float); //! TPC pileup median time on A side (long time range) +DECLARE_SOA_COLUMN(NTPCoccupMedianTimeLongC, nTPCoccupMedianTimeLongC, float); //! TPC pileup median time on C side (long time range) +DECLARE_SOA_COLUMN(NTPCoccupContribShortA, nTPCoccupContribShortA, int); //! TPC pileup occupancy on A side (short time range) +DECLARE_SOA_COLUMN(NTPCoccupContribShortC, nTPCoccupContribShortC, int); //! TPC pileup occupancy on C side (short time range) +DECLARE_SOA_COLUMN(NTPCoccupMeanTimeShortA, nTPCoccupMeanTimeShortA, float); //! TPC pileup mean time on A side (short time range) +DECLARE_SOA_COLUMN(NTPCoccupMeanTimeShortC, nTPCoccupMeanTimeShortC, float); //! TPC pileup mean time on C side (short time range) +DECLARE_SOA_COLUMN(NTPCoccupMedianTimeShortA, nTPCoccupMedianTimeShortA, float); //! TPC pileup median time on A side (short time range) +DECLARE_SOA_COLUMN(NTPCoccupMedianTimeShortC, nTPCoccupMedianTimeShortC, float); //! TPC pileup median time on C side (short time range) + +// Columns declared to guarantee the backward compatibility of the tables +DECLARE_SOA_COLUMN(QvecBPosRe, qvecBPosRe, float); +DECLARE_SOA_COLUMN(QvecBPosIm, qvecBPosIm, float); +DECLARE_SOA_COLUMN(QvecBNegRe, qvecBNegRe, float); +DECLARE_SOA_COLUMN(QvecBNegIm, qvecBNegIm, float); +DECLARE_SOA_COLUMN(QvecBAllRe, qvecBAllRe, float); +DECLARE_SOA_COLUMN(QvecBAllIm, qvecBAllIm, float); +DECLARE_SOA_COLUMN(NTrkBPos, nTrkBPos, int); +DECLARE_SOA_COLUMN(NTrkBNeg, nTrkBNeg, int); +DECLARE_SOA_COLUMN(NTrkBAll, nTrkBAll, int); + +DECLARE_SOA_COLUMN(Q1ZNAX, q1znax, float); //! Q-vector x component, evaluated with ZNA (harmonic 1 and power 1) +DECLARE_SOA_COLUMN(Q1ZNAY, q1znay, float); //! Q-vector y component, evaluated with ZNA (harmonic 1 and power 1) +DECLARE_SOA_COLUMN(Q1ZNCX, q1zncx, float); //! Q-vector x component, evaluated with ZNC (harmonic 1 and power 1) +DECLARE_SOA_COLUMN(Q1ZNCY, q1zncy, float); //! Q-vector y component, evaluated with ZNC (harmonic 1 and power 1) DECLARE_SOA_COLUMN(Q1X0A, q1x0a, float); //! Q-vector x component, with event eta gap A (harmonic 1 and power 1) DECLARE_SOA_COLUMN(Q1Y0A, q1y0a, float); //! Q-vector y component, with event eta gap A (harmonic 1 and power 1) DECLARE_SOA_COLUMN(Q1X0B, q1x0b, float); //! Q-vector x component, with event eta gap B (harmonic 1 and power 1) @@ -76,24 +132,19 @@ DECLARE_SOA_COLUMN(S11A, s11a, float); //! Weighted multiplicity (p = 1, DECLARE_SOA_COLUMN(S12A, s12a, float); //! Weighted multiplicity (p = 1, k = 2) DECLARE_SOA_COLUMN(S13A, s13a, float); //! Weighted multiplicity (p = 1, k = 3) DECLARE_SOA_COLUMN(S31A, s31a, float); //! Weighted multiplicity (p = 3, k = 1) -DECLARE_SOA_COLUMN(S21A, s21a, float); //! Weighted multiplicity (p = 2, k = 1) -DECLARE_SOA_COLUMN(S22A, s22a, float); //! Weighted multiplicity (p = 2, k = 2) -DECLARE_SOA_COLUMN(S41A, s41a, float); //! Weighted multiplicity (p = 4, k = 1) -DECLARE_SOA_COLUMN(S14A, s14a, float); //! Weighted multiplicity (p = 1, k = 4) DECLARE_SOA_COLUMN(CORR2REF, corr2ref, float); //! Ref Flow correlator <2> +DECLARE_SOA_COLUMN(CORR2REFetagap, corr2refetagap, float); //! Ref Flow correlator <2> DECLARE_SOA_COLUMN(CORR4REF, corr4ref, float); //! Ref Flow correlator <4> DECLARE_SOA_COLUMN(M11REF, m11ref, float); //! Weighted multiplicity of <<2>> for reference flow DECLARE_SOA_COLUMN(M1111REF, m1111ref, float); //! Weighted multiplicity of <<4>> for reference flow -DECLARE_SOA_COLUMN(MCPosX, mcPosX, float); //! -DECLARE_SOA_COLUMN(MCPosY, mcPosY, float); //! -DECLARE_SOA_COLUMN(MCPosZ, mcPosZ, float); //! +DECLARE_SOA_COLUMN(M11REFetagap, m11refetagap, float); //! Weighted multiplicity of <<2>> etagap for reference flow } // namespace reducedevent -DECLARE_SOA_TABLE(ReducedEvents, "AOD", "REDUCEDEVENT", //! Main event information table - o2::soa::Index<>, - reducedevent::Tag, bc::RunNumber, - collision::PosX, collision::PosY, collision::PosZ, collision::NumContrib, - collision::CollisionTime, collision::CollisionTimeRes); +DECLARE_SOA_TABLE_STAGED(ReducedEvents, "REDUCEDEVENT", //! Main event information table + o2::soa::Index<>, + reducedevent::Tag, bc::RunNumber, + collision::PosX, collision::PosY, collision::PosZ, collision::NumContrib, + collision::CollisionTime, collision::CollisionTimeRes); DECLARE_SOA_TABLE(ReducedEventsExtended, "AOD", "REEXTENDED", //! Extended event information bc::GlobalBC, evsel::Alias, evsel::Selection, timestamp::Timestamp, cent::CentRun2V0M, @@ -101,6 +152,27 @@ DECLARE_SOA_TABLE(ReducedEventsExtended, "AOD", "REEXTENDED", //! Extended even mult::MultFDDA, mult::MultFDDC, mult::MultZNA, mult::MultZNC, mult::MultTracklets, mult::MultNTracksPV, cent::CentFT0C); +DECLARE_SOA_TABLE(ReducedEventsMultPV_000, "AOD", "REMULTPV", //! Multiplicity information for primary vertex + mult::MultNTracksHasITS, mult::MultNTracksHasTPC, mult::MultNTracksHasTOF, mult::MultNTracksHasTRD, + mult::MultNTracksITSOnly, mult::MultNTracksTPCOnly, mult::MultNTracksITSTPC, + evsel::NumTracksInTimeRange); + +DECLARE_SOA_TABLE_VERSIONED(ReducedEventsMultPV_001, "AOD", "REMULTPV", 1, //! Multiplicity information for primary vertex + mult::MultNTracksHasITS, mult::MultNTracksHasTPC, mult::MultNTracksHasTOF, mult::MultNTracksHasTRD, + mult::MultNTracksITSOnly, mult::MultNTracksTPCOnly, mult::MultNTracksITSTPC, + mult::MultNTracksPVeta1, mult::MultNTracksPVetaHalf, evsel::NumTracksInTimeRange, evsel::SumAmpFT0CInTimeRange); + +using ReducedEventsMultPV = ReducedEventsMultPV_001; + +DECLARE_SOA_TABLE(ReducedEventsMultAll, "AOD", "REMULTALL", //! Multiplicity information for all tracks in the event + mult::MultAllTracksTPCOnly, mult::MultAllTracksITSTPC, + reducedevent::NTPCoccupContribLongA, reducedevent::NTPCoccupContribLongC, + reducedevent::NTPCoccupMeanTimeLongA, reducedevent::NTPCoccupMeanTimeLongC, + reducedevent::NTPCoccupMedianTimeLongA, reducedevent::NTPCoccupMedianTimeLongC, + reducedevent::NTPCoccupContribShortA, reducedevent::NTPCoccupContribShortC, + reducedevent::NTPCoccupMeanTimeShortA, reducedevent::NTPCoccupMeanTimeShortC, + reducedevent::NTPCoccupMedianTimeShortA, reducedevent::NTPCoccupMedianTimeShortC); + DECLARE_SOA_TABLE(ReducedEventsVtxCov, "AOD", "REVTXCOV", //! Event vertex covariance matrix collision::CovXX, collision::CovXY, collision::CovXZ, collision::CovYY, collision::CovYZ, collision::CovZZ, collision::Chi2); @@ -117,11 +189,20 @@ DECLARE_SOA_TABLE(ReducedEventsQvectorExtra, "AOD", "REQVECTOREXTRA", //! Eve reducedevent::S11A, reducedevent::S12A, reducedevent::S13A, reducedevent::S31A); DECLARE_SOA_TABLE(ReducedEventsQvectorCentr, "AOD", "REQVECTORCTR", //! Event Q-vector information from central framework - qvec::QvecFT0ARe, qvec::QvecFT0AIm, qvec::QvecFT0CRe, qvec::QvecFT0CIm, qvec::QvecFT0MRe, qvec::QvecFT0MIm, qvec::QvecFV0ARe, qvec::QvecFV0AIm, qvec::QvecBPosRe, qvec::QvecBPosIm, qvec::QvecBNegRe, qvec::QvecBNegIm, - qvec::SumAmplFT0A, qvec::SumAmplFT0C, qvec::SumAmplFT0M, qvec::SumAmplFV0A, qvec::NTrkBPos, qvec::NTrkBNeg); + qvec::QvecFT0ARe, qvec::QvecFT0AIm, qvec::QvecFT0CRe, qvec::QvecFT0CIm, qvec::QvecFT0MRe, qvec::QvecFT0MIm, qvec::QvecFV0ARe, qvec::QvecFV0AIm, reducedevent::QvecBPosRe, reducedevent::QvecBPosIm, reducedevent::QvecBNegRe, reducedevent::QvecBNegIm, + qvec::SumAmplFT0A, qvec::SumAmplFT0C, qvec::SumAmplFT0M, qvec::SumAmplFV0A, reducedevent::NTrkBPos, reducedevent::NTrkBNeg); + +DECLARE_SOA_TABLE(ReducedEventsQvectorCentrExtra, "AOD", "REQVECCTREXTA", //! Event Q-vector information from central framework with TPC all + reducedevent::QvecBAllRe, reducedevent::QvecBAllIm, reducedevent::NTrkBAll); DECLARE_SOA_TABLE(ReducedEventsRefFlow, "AOD", "REREFFLOW", //! Event Ref Flow information - reducedevent::M11REF, reducedevent::M1111REF, reducedevent::CORR2REF, reducedevent::CORR4REF, cent::CentFT0C); + reducedevent::M11REF, reducedevent::M11REFetagap, reducedevent::M1111REF, reducedevent::CORR2REF, reducedevent::CORR2REFetagap, reducedevent::CORR4REF, cent::CentFT0C); + +DECLARE_SOA_TABLE(ReducedEventsQvectorZN, "AOD", "REQVECTORZN", //! Event Q-vector information from ZNs detectors + reducedevent::Q1ZNAX, reducedevent::Q1ZNAY, reducedevent::Q1ZNCX, reducedevent::Q1ZNCY); + +DECLARE_SOA_TABLE(ReducedEventsInfo, "AOD", "REDUCEVENTINFO", //! Main event index table + reducedevent::CollisionId); // TODO and NOTE: This table is just an extension of the ReducedEvents table // There is no explicit accounting for MC events which were not reconstructed!!! @@ -133,12 +214,17 @@ DECLARE_SOA_TABLE(ReducedMCEvents, "AOD", "REDUCEDMCEVENT", //! Event level MC mccollision::T, mccollision::Weight, mccollision::ImpactParameter); using ReducedEvent = ReducedEvents::iterator; +using StoredReducedEvent = StoredReducedEvents::iterator; using ReducedEventExtended = ReducedEventsExtended::iterator; using ReducedEventVtxCov = ReducedEventsVtxCov::iterator; +using ReducedEventMultPV = ReducedEventsMultPV::iterator; +using ReducedEventMultAll = ReducedEventsMultAll::iterator; using ReducedEventQvector = ReducedEventsQvector::iterator; using ReducedEventQvectorExtra = ReducedEventsQvectorExtra::iterator; using ReducedEventQvectorCentr = ReducedEventsQvectorCentr::iterator; +using ReducedEventQvectorCentrExtra = ReducedEventsQvectorCentrExtra::iterator; using ReducedEventRefFlow = ReducedEventsRefFlow::iterator; +using ReducedEventQvectorZN = ReducedEventsQvectorZN::iterator; using ReducedMCEvent = ReducedMCEvents::iterator; namespace reducedeventlabel @@ -151,10 +237,44 @@ DECLARE_SOA_TABLE(ReducedMCEventLabels, "AOD", "REMCCOLLBL", //! Table joined to reducedeventlabel::ReducedMCEventId, reducedeventlabel::McMask); using ReducedMCEventLabel = ReducedMCEventLabels::iterator; +namespace reducedzdc +{ +DECLARE_SOA_COLUMN(EnergyCommonZNA, energyCommonZNA, float); //! +DECLARE_SOA_COLUMN(EnergyCommonZNC, energyCommonZNC, float); //! +DECLARE_SOA_COLUMN(EnergyCommonZPA, energyCommonZPA, float); //! +DECLARE_SOA_COLUMN(EnergyCommonZPC, energyCommonZPC, float); //! +DECLARE_SOA_COLUMN(EnergyZNA1, energyZNA1, float); //! +DECLARE_SOA_COLUMN(EnergyZNA2, energyZNA2, float); //! +DECLARE_SOA_COLUMN(EnergyZNA3, energyZNA3, float); //! +DECLARE_SOA_COLUMN(EnergyZNA4, energyZNA4, float); //! +DECLARE_SOA_COLUMN(EnergyZNC1, energyZNC1, float); //! +DECLARE_SOA_COLUMN(EnergyZNC2, energyZNC2, float); //! +DECLARE_SOA_COLUMN(EnergyZNC3, energyZNC3, float); //! +DECLARE_SOA_COLUMN(EnergyZNC4, energyZNC4, float); //! +DECLARE_SOA_COLUMN(TimeZNA, timeZNA, float); //! +DECLARE_SOA_COLUMN(TimeZNC, timeZNC, float); //! +DECLARE_SOA_COLUMN(TimeZPA, timeZPA, float); //! +DECLARE_SOA_COLUMN(TimeZPC, timeZPC, float); //! +} // namespace reducedzdc + +DECLARE_SOA_TABLE(ReducedZdcs, "AOD", "REDUCEDZDC", //! Event ZDC information + reducedzdc::EnergyCommonZNA, reducedzdc::EnergyCommonZNC, + reducedzdc::EnergyCommonZPA, reducedzdc::EnergyCommonZPC, + reducedzdc::TimeZNA, reducedzdc::TimeZNC, + reducedzdc::TimeZPA, reducedzdc::TimeZPC); + +DECLARE_SOA_TABLE(ReducedZdcsExtra, "AOD", "REDUCEDZDCEXTRA", //! Event ZDC extra information + reducedzdc::EnergyZNA1, reducedzdc::EnergyZNA2, reducedzdc::EnergyZNA3, reducedzdc::EnergyZNA4, + reducedzdc::EnergyZNC1, reducedzdc::EnergyZNC2, reducedzdc::EnergyZNC3, reducedzdc::EnergyZNC4); + +using ReducedZdc = ReducedZdcs::iterator; +using ReducedZdcExtra = ReducedZdcsExtra::iterator; + namespace reducedtrack { // basic track information DECLARE_SOA_INDEX_COLUMN(ReducedEvent, reducedevent); //! +DECLARE_SOA_INDEX_COLUMN(Track, track); //! // ---- flags reserved for storing various information during filtering DECLARE_SOA_BITMAP_COLUMN(FilteringFlags, filteringFlags, 64); //! // ----------------------------------------------------- @@ -229,7 +349,7 @@ DECLARE_SOA_TABLE(ReducedTracksBarrelPID, "AOD", "RTBARRELPID", //! // barrel collision information (joined with ReducedTracks) allowing to connect different tables (cross PWGs) DECLARE_SOA_TABLE(ReducedTracksBarrelInfo, "AOD", "RTBARRELINFO", - reducedtrack::CollisionId, collision::PosX, collision::PosY, collision::PosZ); + reducedtrack::CollisionId, collision::PosX, collision::PosY, collision::PosZ, reducedtrack::TrackId); using ReducedTrack = ReducedTracks::iterator; using ReducedTrackBarrel = ReducedTracksBarrel::iterator; @@ -271,24 +391,25 @@ DECLARE_SOA_DYNAMIC_COLUMN(Y, y, //! Particle rapidity } // namespace reducedtrackMC // NOTE: This table is nearly identical to the one from Framework (except that it points to the event ID, not the BC id) // This table contains all MC truth tracks (both barrel and muon) -DECLARE_SOA_TABLE_FULL(ReducedMCTracks, "ReducedMCTracks", "AOD", "REDUCEDMCTRACK", //! MC track information (on disk) - o2::soa::Index<>, reducedtrackMC::ReducedMCEventId, - mcparticle::PdgCode, mcparticle::StatusCode, mcparticle::Flags, - reducedtrackMC::MothersIds, reducedtrackMC::DaughtersIdSlice, - mcparticle::Weight, - reducedtrackMC::Pt, reducedtrackMC::Eta, reducedtrackMC::Phi, reducedtrackMC::E, - mcparticle::Vx, mcparticle::Vy, mcparticle::Vz, mcparticle::Vt, - reducedtrackMC::McReducedFlags, - reducedtrackMC::Px, - reducedtrackMC::Py, - reducedtrackMC::Pz, - reducedtrackMC::P, - reducedtrackMC::Y, - mcparticle::ProducedByGenerator, - mcparticle::FromBackgroundEvent, - mcparticle::GetGenStatusCode, - mcparticle::GetProcess, - mcparticle::IsPhysicalPrimary); +DECLARE_SOA_TABLE(ReducedMCTracks, "AOD", "REDUCEDMCTRACK", //! MC track information (on disk) + o2::soa::Index<>, reducedtrackMC::ReducedMCEventId, + mcparticle::PdgCode, mcparticle::StatusCode, mcparticle::Flags, + reducedtrackMC::MothersIds, reducedtrackMC::DaughtersIdSlice, + mcparticle::Weight, + reducedtrackMC::Pt, reducedtrackMC::Eta, reducedtrackMC::Phi, reducedtrackMC::E, + mcparticle::Vx, mcparticle::Vy, mcparticle::Vz, mcparticle::Vt, + reducedtrackMC::McReducedFlags, + reducedtrackMC::Px, + reducedtrackMC::Py, + reducedtrackMC::Pz, + reducedtrackMC::P, + reducedtrackMC::Y, + mcparticle::ProducedByGenerator, + mcparticle::FromBackgroundEvent, + mcparticle::GetGenStatusCode, + mcparticle::GetProcess, + mcparticle::GetHepMCStatusCode, + mcparticle::IsPhysicalPrimary); using ReducedMCTrack = ReducedMCTracks::iterator; @@ -319,20 +440,28 @@ DECLARE_SOA_COLUMN(FwdDcaX, fwdDcaX, float); DECLARE_SOA_COLUMN(FwdDcaY, fwdDcaY, float); //! DECLARE_SOA_COLUMN(MftClusterSizesAndTrackFlags, mftClusterSizesAndTrackFlags, uint64_t); //! DECLARE_SOA_COLUMN(MftNClusters, mftNClusters, int); //! +DECLARE_SOA_INDEX_COLUMN(ReducedMCTrack, reducedMCTrack); //! +DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); //! +DECLARE_SOA_COLUMN(McReducedFlags, mcReducedFlags, uint16_t); //! } // namespace reducedmft // MFT track kinematics -DECLARE_SOA_TABLE_FULL(ReducedMFTs, "ReducedMFTs", "AOD", "REDUCEDMFT", //! - o2::soa::Index<>, reducedmft::ReducedEventId, reducedmft::FilteringFlags, - reducedmft::Pt, reducedmft::Eta, reducedmft::Phi); +DECLARE_SOA_TABLE(ReducedMFTs, "AOD", "REDUCEDMFT", //! + o2::soa::Index<>, reducedmft::ReducedEventId, reducedmft::FilteringFlags, + reducedmft::Pt, reducedmft::Eta, reducedmft::Phi); // MFT tracks extra info (cluster size, sign) DECLARE_SOA_TABLE(ReducedMFTsExtra, "AOD", "RMFTEXTRA", //! reducedmft::MftClusterSizesAndTrackFlags, reducedmft::Sign, reducedmft::FwdDcaX, reducedmft::FwdDcaY, reducedmft::MftNClusters); +DECLARE_SOA_TABLE(ReducedMFTLabels, "AOD", "RTMFTLABELS", //! + reducedmft::ReducedMCTrackId, reducedmft::McMask, reducedmft::McReducedFlags); + // iterator using ReducedMFT = ReducedMFTs::iterator; +using ReducedMFTExtra = ReducedMFTsExtra::iterator; +using ReducedMFTLabel = ReducedMFTLabels::iterator; // muon quantities namespace reducedmuon @@ -370,15 +499,15 @@ DECLARE_SOA_INDEX_COLUMN(ReducedMFT, matchMFTTrack); //! matching index pointin } // namespace reducedmuon // Muon track kinematics -DECLARE_SOA_TABLE_FULL(ReducedMuons, "ReducedMuons", "AOD", "REDUCEDMUON", //! - o2::soa::Index<>, reducedmuon::ReducedEventId, - reducedmuon::MatchMCHTrackId, reducedmuon::ReducedMFTId, - reducedmuon::FilteringFlags, - reducedmuon::Pt, reducedmuon::Eta, reducedmuon::Phi, reducedmuon::Sign, reducedmuon::IsAmbiguous, - reducedmuon::Px, - reducedmuon::Py, - reducedmuon::Pz, - reducedmuon::P); +DECLARE_SOA_TABLE(ReducedMuons, "AOD", "REDUCEDMUON", //! + o2::soa::Index<>, reducedmuon::ReducedEventId, + reducedmuon::MatchMCHTrackId, reducedmuon::ReducedMFTId, + reducedmuon::FilteringFlags, + reducedmuon::Pt, reducedmuon::Eta, reducedmuon::Phi, reducedmuon::Sign, reducedmuon::IsAmbiguous, + reducedmuon::Px, + reducedmuon::Py, + reducedmuon::Pz, + reducedmuon::P); // Muon track quality details DECLARE_SOA_TABLE(ReducedMuonsExtra, "AOD", "RTMUONEXTRA", //! @@ -437,17 +566,6 @@ DECLARE_SOA_TABLE(ReducedMFTAssoc, "AOD", "RMFTASSOC", //! Table for reducemft-t reducedtrack_association::ReducedEventId, reducedtrack_association::ReducedMFTId); -namespace smearedtrack -{ -DECLARE_SOA_COLUMN(PtSmeared, ptSmeared, float); -DECLARE_SOA_COLUMN(EtaSmeared, etaSmeared, float); -DECLARE_SOA_COLUMN(PhiSmeared, phiSmeared, float); -} // namespace smearedtrack - -DECLARE_SOA_TABLE(SmearedTracks, "AOD", "SMEAREDTRACK", // use like this Join - smearedtrack::PtSmeared, smearedtrack::EtaSmeared, smearedtrack::PhiSmeared); -using SmearedTrack = SmearedTracks::iterator; - namespace dilepton_track_index { DECLARE_SOA_INDEX_COLUMN_FULL(Index0, index0, int, ReducedMuons, "_0"); //! Index to first prong @@ -500,7 +618,48 @@ DECLARE_SOA_COLUMN(FwdDcaX1, fwdDcaX1, float); //! X component of forward DCA DECLARE_SOA_COLUMN(FwdDcaY1, fwdDcaY1, float); //! Y component of forward DCA DECLARE_SOA_COLUMN(FwdDcaX2, fwdDcaX2, float); //! X component of forward DCA DECLARE_SOA_COLUMN(FwdDcaY2, fwdDcaY2, float); //! Y component of forward DCA - +DECLARE_SOA_COLUMN(ITSNCls1, itsNCls1, int); //! Number of ITS clusters +DECLARE_SOA_COLUMN(ITSClusterMap1, itsClusterMap1, uint8_t); //! ITS clusters map +DECLARE_SOA_COLUMN(ITSChi2NCl1, itsChi2NCl1, float); //! ITS chi2/Ncls +DECLARE_SOA_COLUMN(TPCNClsFound1, tpcNClsFound1, float); //! Number of TPC clusters found +DECLARE_SOA_COLUMN(TPCNClsCR1, tpcNClsCR1, float); //! Number of TPC crossed rows +DECLARE_SOA_COLUMN(TPCChi2NCl1, tpcChi2NCl1, float); //! TPC chi2/Ncls +DECLARE_SOA_COLUMN(DcaXY1, dcaXY1, float); //! DCA in XY plane +DECLARE_SOA_COLUMN(DcaZ1, dcaZ1, float); //! DCA in Z +DECLARE_SOA_COLUMN(TPCSignal1, tpcSignal1, float); //! TPC dE/dx signal +DECLARE_SOA_COLUMN(TPCNSigmaEl1, tpcNSigmaEl1, float); //! TPC nSigma electron +DECLARE_SOA_COLUMN(TPCNSigmaPi1, tpcNSigmaPi1, float); //! TPC nSigma pion +DECLARE_SOA_COLUMN(TPCNSigmaPr1, tpcNSigmaPr1, float); //! TPC nSigma proton +DECLARE_SOA_COLUMN(TOFBeta1, tofBeta1, float); //! TOF beta +DECLARE_SOA_COLUMN(TOFNSigmaEl1, tofNSigmaEl1, float); //! TOF nSigma electron +DECLARE_SOA_COLUMN(TOFNSigmaPi1, tofNSigmaPi1, float); //! TOF nSigma pion +DECLARE_SOA_COLUMN(TOFNSigmaPr1, tofNSigmaPr1, float); //! TOF nSigma proton +DECLARE_SOA_COLUMN(ITSNCls2, itsNCls2, int); //! Number of ITS clusters +DECLARE_SOA_COLUMN(ITSClusterMap2, itsClusterMap2, uint8_t); //! ITS clusters map +DECLARE_SOA_COLUMN(ITSChi2NCl2, itsChi2NCl2, float); //! ITS chi2/Ncls +DECLARE_SOA_COLUMN(TPCNClsFound2, tpcNClsFound2, float); //! Number of TPC clusters found +DECLARE_SOA_COLUMN(TPCNClsCR2, tpcNClsCR2, float); //! Number of TPC crossed rows +DECLARE_SOA_COLUMN(TPCChi2NCl2, tpcChi2NCl2, float); //! TPC chi2/Ncls +DECLARE_SOA_COLUMN(DcaXY2, dcaXY2, float); //! DCA in XY plane +DECLARE_SOA_COLUMN(DcaZ2, dcaZ2, float); //! DCA in Z +DECLARE_SOA_COLUMN(TPCSignal2, tpcSignal2, float); //! TPC dE/dx signal +DECLARE_SOA_COLUMN(TPCNSigmaEl2, tpcNSigmaEl2, float); //! TPC nSigma electron +DECLARE_SOA_COLUMN(TPCNSigmaPi2, tpcNSigmaPi2, float); //! TPC nSigma pion +DECLARE_SOA_COLUMN(TPCNSigmaPr2, tpcNSigmaPr2, float); //! TPC nSigma proton +DECLARE_SOA_COLUMN(TOFBeta2, tofBeta2, float); //! TOF beta +DECLARE_SOA_COLUMN(TOFNSigmaEl2, tofNSigmaEl2, float); //! TOF nSigma electron +DECLARE_SOA_COLUMN(TOFNSigmaPi2, tofNSigmaPi2, float); //! TOF nSigma pion +DECLARE_SOA_COLUMN(TOFNSigmaPr2, tofNSigmaPr2, float); //! TOF nSigma proton + +DECLARE_SOA_COLUMN(DCAxyzTrk0KF, dcaxyztrk0KF, float); //! 3D DCA to primary vertex of the first track +DECLARE_SOA_COLUMN(DCAxyzTrk1KF, dcaxyztrk1KF, float); //! 3D DCA to primary vertex of the second track +DECLARE_SOA_COLUMN(DCAxyTrk0KF, dcaxytrk0KF, float); //! 2D DCA to primary vertex of the first track +DECLARE_SOA_COLUMN(DCAxyTrk1KF, dcaxytrk1KF, float); //! 2D DCA to primary vertex of the second track + +DECLARE_SOA_COLUMN(DeviationTrk0KF, deviationTrk0KF, float); //! 3D chi2 deviation to primary vertex of the first track +DECLARE_SOA_COLUMN(DeviationTrk1KF, deviationTrk1KF, float); //! 3D chi2 deviation to primary vertex of the second track +DECLARE_SOA_COLUMN(DeviationxyTrk0KF, deviationxyTrk0KF, float); //! 2D chi2 deviation to primary vertex of the first track +DECLARE_SOA_COLUMN(DeviationxyTrk1KF, deviationxyTrk1KF, float); //! 2D chi2 deviation to primary vertex of the second track } // namespace dilepton_track_index // pair information @@ -509,12 +668,17 @@ namespace reducedpair DECLARE_SOA_INDEX_COLUMN(ReducedEvent, reducedevent); //! DECLARE_SOA_INDEX_COLUMN_FULL(Index0, index0, int, ReducedTracks, "_0"); //! Index to first prong DECLARE_SOA_INDEX_COLUMN_FULL(Index1, index1, int, ReducedTracks, "_1"); //! Index to second prong +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, Tracks, "_0"); //! Index of first prong in Tracks table +DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, Tracks, "_1"); //! Index of second prong in Tracks table +DECLARE_SOA_BITMAP_COLUMN(EventSelection, evSelection, 8); //! Event selection bits (ambiguity, splitting candidate) DECLARE_SOA_COLUMN(Mass, mass, float); //! DECLARE_SOA_COLUMN(Pt, pt, float); //! DECLARE_SOA_COLUMN(Eta, eta, float); //! DECLARE_SOA_COLUMN(Phi, phi, float); //! DECLARE_SOA_COLUMN(Sign, sign, int); //! DECLARE_SOA_BITMAP_COLUMN(FilterMap, filterMap, 32); //! +DECLARE_SOA_BITMAP_COLUMN(PairFilterMap, pairFilterMap, 32); //! +DECLARE_SOA_BITMAP_COLUMN(CommonFilterMap, commonFilterMap, 32); //! DECLARE_SOA_COLUMN(McDecision, mcDecision, uint32_t); //! DECLARE_SOA_COLUMN(Tauz, tauz, float); //! Longitudinal pseudo-proper time of lepton pair (in ns) DECLARE_SOA_COLUMN(TauzErr, tauzErr, float); //! Error on longitudinal pseudo-proper time of lepton pair (in ns) @@ -530,20 +694,40 @@ DECLARE_SOA_COLUMN(U2Q2, u2q2, float); //! Sca DECLARE_SOA_COLUMN(U3Q3, u3q3, float); //! Scalar product between unitary vector with event flow vector (harmonic 3) DECLARE_SOA_COLUMN(Cos2DeltaPhi, cos2deltaphi, float); //! Cosinus term using event plane angle (harmonic 2) DECLARE_SOA_COLUMN(Cos3DeltaPhi, cos3deltaphi, float); //! Cosinus term using event plane angle (harmonic 3) -DECLARE_SOA_COLUMN(R2SP, r2sp, float); //! Event plane resolution for SP method -DECLARE_SOA_COLUMN(R2EP, r2ep, float); //! Event plane resolution for EP method +DECLARE_SOA_COLUMN(R2SP_AB, r2spab, float); //! Event plane resolution for SP method n=2 (A,B) TPC-FT0A +DECLARE_SOA_COLUMN(R2SP_AC, r2spac, float); //! Event plane resolution for SP method n=2 (A,C) TPC-FT0C +DECLARE_SOA_COLUMN(R2SP_BC, r2spbc, float); //! Event plane resolution for SP method n=2 (B,C) FT0A-FT0C +DECLARE_SOA_COLUMN(R3SP, r3sp, float); //! Event plane resolution for SP method n=3 +DECLARE_SOA_COLUMN(R2EP, r2ep, float); //! Event plane resolution for EP method n=2 +DECLARE_SOA_COLUMN(R2EP_AB, r2epab, float); //! Event plane resolution for EP method n=2 (A,B) TPC-FT0A +DECLARE_SOA_COLUMN(R2EP_AC, r2epac, float); //! Event plane resolution for EP method n=2 (A,C) TPC-FT0C +DECLARE_SOA_COLUMN(R2EP_BC, r2epbc, float); //! Event plane resolution for EP method n=2 (B,C) FT0A-FT0C +DECLARE_SOA_COLUMN(R3EP, r3ep, float); //! Event plane resolution for EP method n=3 DECLARE_SOA_COLUMN(CORR2POI, corr2poi, float); //! POI FLOW CORRELATOR <2'> DECLARE_SOA_COLUMN(CORR4POI, corr4poi, float); //! POI FLOW CORRELATOR <4'> -DECLARE_SOA_COLUMN(CORR2REF, corr2ref, float); //! POI FLOW CORRELATOR <2> (by dimuons) -DECLARE_SOA_COLUMN(CORR4REF, corr4ref, float); //! POI FLOW CORRELATOR <4> (by dimuons) -DECLARE_SOA_COLUMN(M11REF, m11ref, float); //! Weighted multiplicity of <<2>> for reference flow (by dimuons) -DECLARE_SOA_COLUMN(M1111REF, m1111ref, float); //! Weighted multiplicity of <<4>> for reference flow (by dimuons) -DECLARE_SOA_COLUMN(MultA, multa, float); //! Multiplicity A of reference flow (by dimuons) DECLARE_SOA_COLUMN(M01POI, m01poi, float); //! POI event weight for <2'> DECLARE_SOA_COLUMN(M0111POI, m0111poi, float); //! POI event weight for <4'> DECLARE_SOA_COLUMN(MultDimuons, multdimuons, int); //! Dimuon multiplicity DECLARE_SOA_COLUMN(CentFT0C, centft0c, float); //! Centrality information from FT0C -DECLARE_SOA_COLUMN(CollisionId, collisionId, int); //! +DECLARE_SOA_COLUMN(CollisionId, collisionId, int32_t); //! +DECLARE_SOA_COLUMN(IsFirst, isfirst, int); //! Flag for the first dilepton in the collision +DECLARE_SOA_COLUMN(DCAxyzBetweenTrksKF, dcaxyzbetweentrksKF, float); //! DCAxyz between the two tracks +DECLARE_SOA_COLUMN(DCAxyBetweenTrksKF, dcaxybetweentrksKF, float); //! DCAxy between the two tracks +DECLARE_SOA_COLUMN(MassKFGeo, massKFGeo, float); //! Pair mass from KFParticle +DECLARE_SOA_COLUMN(CosPAKFGeo, cosPAKFGeo, float); //! Cosine of the pointing angle from KFParticle +DECLARE_SOA_COLUMN(Chi2OverNDFKFGeo, chi2overndfKFGeo, float); //! Chi2 over NDF from KFParticle +DECLARE_SOA_COLUMN(DecayLengthKFGeo, decaylengthKFGeo, float); //! Decay length from KFParticle +DECLARE_SOA_COLUMN(DecayLengthOverErrKFGeo, decaylengthovererrKFGeo, float); //! Decay length over error from KFParticle +DECLARE_SOA_COLUMN(DecayLengthXYKFGeo, decaylengthxyKFGeo, float); //! Decay length XY from KFParticle +DECLARE_SOA_COLUMN(DecayLengthXYOverErrKFGeo, decaylengthxyovererrKFGeo, float); //! Decay length XY over error from KFParticle +DECLARE_SOA_COLUMN(PseudoproperDecayTimeKFGeo, pseudoproperdecaytimeKFGeo, float); //! Pseudoproper decay time from KFParticle +DECLARE_SOA_COLUMN(PseudoproperDecayTimeErrKFGeo, pseudoproperdecaytimeErrKFGeo, float); //! Pseudoproper decay time error from KFParticle +DECLARE_SOA_COLUMN(MassKFGeoTop, massKFGeoTop, float); //! Pair mass after topological constraint from KFParticle +DECLARE_SOA_COLUMN(Chi2OverNDFKFGeoTop, chi2overndfKFGeoTop, float); //! Chi2 over NDF after topological constraint from KFParticle +DECLARE_SOA_COLUMN(PairDCAxyz, pairDCAxyz, float); //! Pair DCAxyz to PV from KFParticle +DECLARE_SOA_COLUMN(PairDCAxy, pairDCAxy, float); //! Pair DCAxy to PV from KFParticle +DECLARE_SOA_COLUMN(DeviationPairKF, deviationPairKF, float); //! Pair chi2 deviation to PV from KFParticle +DECLARE_SOA_COLUMN(DeviationxyPairKF, deviationxyPairKF, float); //! Pair chi2 deviation to PV in XY from KFParticle // DECLARE_SOA_INDEX_COLUMN(ReducedMuon, reducedmuon2); //! DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! [](float pt, float phi) -> float { return pt * std::cos(phi); }); @@ -555,27 +739,31 @@ DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! [](float pt, float eta) -> float { return pt * std::cosh(eta); }); DECLARE_SOA_DYNAMIC_COLUMN(Rap, rap, //! [](float pt, float eta, float m) -> float { return std::log((std::sqrt(m * m + pt * pt * std::cosh(eta) * std::cosh(eta)) + pt * std::sinh(eta)) / std::sqrt(m * m + pt * pt)); }); +DECLARE_SOA_DYNAMIC_COLUMN(Y, y, //! + [](float pt, float eta, float m) -> float { return std::log((std::sqrt(m * m + pt * pt * std::cosh(eta) * std::cosh(eta)) + pt * std::sinh(eta)) / std::sqrt(m * m + pt * pt)); }); } // namespace reducedpair -DECLARE_SOA_TABLE_FULL(Dielectrons, "Dielectrons", "AOD", "RTDIELECTRON", //! - o2::soa::Index<>, reducedpair::ReducedEventId, - reducedpair::Mass, reducedpair::Pt, reducedpair::Eta, reducedpair::Phi, reducedpair::Sign, - reducedpair::FilterMap, reducedpair::McDecision, - reducedpair::Rap, - reducedpair::Px, - reducedpair::Py, - reducedpair::Pz, - reducedpair::P); - -DECLARE_SOA_TABLE_FULL(Dimuons, "Dimuons", "AOD", "RTDIMUON", //! - o2::soa::Index<>, reducedpair::ReducedEventId, - reducedpair::Mass, reducedpair::Pt, reducedpair::Eta, reducedpair::Phi, reducedpair::Sign, - reducedpair::FilterMap, reducedpair::McDecision, - reducedpair::Px, - reducedpair::Py, - reducedpair::Pz, - reducedpair::P, - reducedpair::Rap); +DECLARE_SOA_TABLE_STAGED(Dielectrons, "RTDIELECTRON", //! + o2::soa::Index<>, reducedpair::ReducedEventId, + reducedpair::Mass, reducedpair::Pt, reducedpair::Eta, reducedpair::Phi, reducedpair::Sign, + reducedpair::FilterMap, reducedpair::McDecision, + reducedpair::Rap, + reducedpair::Y, + reducedpair::Px, + reducedpair::Py, + reducedpair::Pz, + reducedpair::P); + +DECLARE_SOA_TABLE(Dimuons, "AOD", "RTDIMUON", //! + o2::soa::Index<>, reducedpair::ReducedEventId, + reducedpair::Mass, reducedpair::Pt, reducedpair::Eta, reducedpair::Phi, reducedpair::Sign, + reducedpair::FilterMap, reducedpair::McDecision, + reducedpair::Px, + reducedpair::Py, + reducedpair::Pz, + reducedpair::P, + reducedpair::Rap, + reducedpair::Y); DECLARE_SOA_TABLE(DielectronsExtra, "AOD", "RTDIELEEXTRA", //! reducedpair::Index0Id, reducedpair::Index1Id, @@ -583,6 +771,9 @@ DECLARE_SOA_TABLE(DielectronsExtra, "AOD", "RTDIELEEXTRA", //! reducedpair::Lz, reducedpair::Lxy); +DECLARE_SOA_TABLE(DielectronsInfo, "AOD", "RTDIELINFO", + reducedpair::CollisionId, reducedpair::Prong0Id, reducedpair::Prong1Id); + DECLARE_SOA_TABLE(DimuonsExtra, "AOD", "RTDIMUEXTRA", //! dilepton_track_index::Index0Id, dilepton_track_index::Index1Id, reducedpair::Tauz, @@ -590,25 +781,39 @@ DECLARE_SOA_TABLE(DimuonsExtra, "AOD", "RTDIMUEXTRA", //! reducedpair::Lxy); DECLARE_SOA_TABLE(DileptonsFlow, "AOD", "RTDILEPTONFLOW", //! - reducedpair::U2Q2, - reducedpair::U3Q3, - reducedpair::Cos2DeltaPhi, - reducedpair::Cos3DeltaPhi); - -DECLARE_SOA_TABLE(RefFlowDimuons, "AOD", "RTREFFLOWDIMUON", //! - reducedpair::CORR2REF, - reducedpair::CORR4REF, - reducedpair::M11REF, - reducedpair::M1111REF, + reducedpair::CollisionId, + reducedpair::Mass, reducedpair::CentFT0C, - reducedpair::MultA); + reducedpair::Pt, reducedpair::Eta, reducedpair::Phi, reducedpair::Sign, + reducedpair::IsFirst, + reducedpair::U2Q2, reducedpair::R2SP_AB, reducedpair::R2SP_AC, reducedpair::R2SP_BC, + reducedpair::U3Q3, reducedpair::R3SP, + reducedpair::Cos2DeltaPhi, reducedpair::R2EP_AB, reducedpair::R2EP_AC, reducedpair::R2EP_BC, + reducedpair::Cos3DeltaPhi, reducedpair::R3EP, + reducedpair::CORR2POI, reducedpair::CORR4POI, reducedpair::M01POI, reducedpair::M0111POI, + reducedevent::CORR2REF, reducedevent::CORR4REF, reducedevent::M11REF, reducedevent::M1111REF, + reducedpair::MultDimuons, reducedevent::MultA); // Dilepton collision information (joined with DileptonsExtra) allowing to connect different tables (cross PWGs) DECLARE_SOA_TABLE(DileptonsInfo, "AOD", "RTDILEPTONINFO", reducedpair::CollisionId, collision::PosX, collision::PosY, collision::PosZ); +DECLARE_SOA_TABLE(DielectronsAll, "AOD", "RTDIELECTRONALL", //! + reducedpair::Mass, + reducedpair::Pt, reducedpair::Eta, reducedpair::Phi, reducedpair::Sign, + reducedpair::FilterMap, + reducedpair::McDecision, + dilepton_track_index::Pt1, dilepton_track_index::Eta1, dilepton_track_index::Phi1, dilepton_track_index::ITSClusterMap1, dilepton_track_index::ITSChi2NCl1, dilepton_track_index::TPCNClsCR1, dilepton_track_index::TPCNClsFound1, dilepton_track_index::TPCChi2NCl1, dilepton_track_index::DcaXY1, dilepton_track_index::DcaZ1, dilepton_track_index::TPCSignal1, dilepton_track_index::TPCNSigmaEl1, dilepton_track_index::TPCNSigmaPi1, dilepton_track_index::TPCNSigmaPr1, dilepton_track_index::TOFBeta1, dilepton_track_index::TOFNSigmaEl1, dilepton_track_index::TOFNSigmaPi1, dilepton_track_index::TOFNSigmaPr1, + dilepton_track_index::Pt2, dilepton_track_index::Eta2, dilepton_track_index::Phi2, dilepton_track_index::ITSClusterMap2, dilepton_track_index::ITSChi2NCl2, dilepton_track_index::TPCNClsCR2, dilepton_track_index::TPCNClsFound2, dilepton_track_index::TPCChi2NCl2, dilepton_track_index::DcaXY2, dilepton_track_index::DcaZ2, dilepton_track_index::TPCSignal2, dilepton_track_index::TPCNSigmaEl2, dilepton_track_index::TPCNSigmaPi2, dilepton_track_index::TPCNSigmaPr2, dilepton_track_index::TOFBeta2, dilepton_track_index::TOFNSigmaEl2, dilepton_track_index::TOFNSigmaPi2, dilepton_track_index::TOFNSigmaPr2, + dilepton_track_index::DCAxyzTrk0KF, dilepton_track_index::DCAxyzTrk1KF, reducedpair::DCAxyzBetweenTrksKF, dilepton_track_index::DCAxyTrk0KF, dilepton_track_index::DCAxyTrk1KF, reducedpair::DCAxyBetweenTrksKF, + dilepton_track_index::DeviationTrk0KF, dilepton_track_index::DeviationTrk1KF, dilepton_track_index::DeviationxyTrk0KF, dilepton_track_index::DeviationxyTrk1KF, + reducedpair::MassKFGeo, reducedpair::Chi2OverNDFKFGeo, reducedpair::DecayLengthKFGeo, reducedpair::DecayLengthOverErrKFGeo, reducedpair::DecayLengthXYKFGeo, reducedpair::DecayLengthXYOverErrKFGeo, reducedpair::PseudoproperDecayTimeKFGeo, reducedpair::PseudoproperDecayTimeErrKFGeo, reducedpair::CosPAKFGeo, reducedpair::PairDCAxyz, reducedpair::PairDCAxy, + reducedpair::DeviationPairKF, reducedpair::DeviationxyPairKF, + reducedpair::MassKFGeoTop, reducedpair::Chi2OverNDFKFGeoTop); + DECLARE_SOA_TABLE(DimuonsAll, "AOD", "RTDIMUONALL", //! collision::PosX, collision::PosY, collision::PosZ, collision::NumContrib, + evsel::Selection, reducedpair::EventSelection, reducedevent::MCPosX, reducedevent::MCPosY, reducedevent::MCPosZ, reducedpair::Mass, reducedpair::McDecision, @@ -630,8 +835,8 @@ DECLARE_SOA_TABLE(DimuonsAll, "AOD", "RTDIMUONALL", //! dilepton_track_index::IsAmbig1, dilepton_track_index::IsAmbig2, reducedpair::U2Q2, reducedpair::U3Q3, - reducedpair::R2EP, - reducedpair::R2SP, + reducedpair::R2EP_AB, + reducedpair::R2SP_AB, reducedpair::CentFT0C, reducedpair::Cos2DeltaPhi, reducedpair::Cos3DeltaPhi, @@ -643,29 +848,71 @@ DECLARE_SOA_TABLE(DimuonsAll, "AOD", "RTDIMUONALL", //! reducedpair::VertexPz, reducedpair::SVertex); +DECLARE_SOA_TABLE(DileptonsMiniTree, "AOD", "RTDILEPTMTREE", //! + reducedpair::Mass, reducedpair::Pt, reducedpair::Eta, reducedpair::CentFT0C, reducedpair::Cos2DeltaPhi, + dilepton_track_index::Pt1, dilepton_track_index::Eta1, dilepton_track_index::Phi1, + dilepton_track_index::Pt2, dilepton_track_index::Eta2, dilepton_track_index::Phi2); + +DECLARE_SOA_TABLE(DileptonsMiniTreeGen, "AOD", "RTDILMTREEGEN", //! + reducedpair::McDecision, mccollision::ImpactParameter, + dilepton_track_index::PtMC1, dilepton_track_index::EtaMC1, dilepton_track_index::PhiMC1, + dilepton_track_index::PtMC2, dilepton_track_index::EtaMC2, dilepton_track_index::PhiMC2); + +DECLARE_SOA_TABLE(DileptonsMiniTreeRec, "AOD", "RTDILMTREEREC", //! + reducedpair::McDecision, reducedpair::Mass, reducedpair::Pt, reducedpair::Eta, reducedpair::Phi, reducedpair::CentFT0C, + dilepton_track_index::PtMC1, dilepton_track_index::EtaMC1, dilepton_track_index::PhiMC1, + dilepton_track_index::PtMC2, dilepton_track_index::EtaMC2, dilepton_track_index::PhiMC2, + dilepton_track_index::Pt1, dilepton_track_index::Eta1, dilepton_track_index::Phi1, + dilepton_track_index::Pt2, dilepton_track_index::Eta2, dilepton_track_index::Phi2); + using Dielectron = Dielectrons::iterator; +using StoredDielectron = StoredDielectrons::iterator; using Dimuon = Dimuons::iterator; using DielectronExtra = DielectronsExtra::iterator; +using DielectronInfo = DielectronsInfo::iterator; using DimuonExtra = DimuonsExtra::iterator; using DileptonFlow = DileptonsFlow::iterator; -using RefFlowDimuon = RefFlowDimuons::iterator; using DileptonInfo = DileptonsInfo::iterator; +using DielectronAll = DielectronsAll::iterator; using DimuonAll = DimuonsAll::iterator; +using DileptonMiniTree = DileptonsMiniTree::iterator; +using DileptonMiniTreeGen = DileptonsMiniTreeGen::iterator; +using DileptonMiniTreeRec = DileptonsMiniTreeRec::iterator; + +// Tables for using analysis-dilepton-track with analysis-asymmetric-pairing +DECLARE_SOA_TABLE(Ditracks, "AOD", "RTDITRACK", //! + o2::soa::Index<>, reducedpair::ReducedEventId, + reducedpair::Mass, reducedpair::Pt, reducedpair::Eta, reducedpair::Phi, reducedpair::Sign, + reducedpair::FilterMap, reducedpair::PairFilterMap, reducedpair::CommonFilterMap, + reducedpair::Rap, + reducedpair::Y, + reducedpair::Px, + reducedpair::Py, + reducedpair::Pz, + reducedpair::P); + +DECLARE_SOA_TABLE(DitracksExtra, "AOD", "RTDITRKEXTRA", //! + reducedpair::Index0Id, reducedpair::Index1Id, + reducedpair::Tauz, + reducedpair::Lz, + reducedpair::Lxy, + o2::soa::Marker<1>); // mft PID reduced data model namespace fwdpid { -DECLARE_SOA_COLUMN(Pt, pt, float); //! -DECLARE_SOA_COLUMN(Eta, eta, float); //! -DECLARE_SOA_COLUMN(Phi, phi, float); //! -DECLARE_SOA_COLUMN(Sign, sign, int); //! +DECLARE_SOA_COLUMN(Pt, pt, float); //! +DECLARE_SOA_COLUMN(Eta, eta, float); //! +DECLARE_SOA_COLUMN(Phi, phi, float); //! +DECLARE_SOA_COLUMN(Sign, sign, int); //! +DECLARE_SOA_COLUMN(McDecision, mcDecision, uint16_t); //! } // namespace fwdpid DECLARE_SOA_TABLE(FwdPidsAll, "AOD", "RTFWDPIDALL", //! fwdtrack::TrackType, collision::PosX, collision::PosY, collision::PosZ, collision::NumContrib, fwdpid::Pt, fwdpid::Eta, fwdpid::Phi, fwdpid::Sign, reducedmft::MftClusterSizesAndTrackFlags, - reducedmft::FwdDcaX, reducedmft::FwdDcaY, fwdtrack::Chi2MatchMCHMID, fwdtrack::Chi2MatchMCHMFT); + reducedmft::FwdDcaX, reducedmft::FwdDcaY, fwdtrack::Chi2MatchMCHMID, fwdtrack::Chi2MatchMCHMFT, fwdpid::McDecision); using FwdPidAll = FwdPidsAll::iterator; @@ -695,6 +942,64 @@ DECLARE_SOA_TABLE(DileptonTrackCandidates, "AOD", "RTDILEPTONTRACK", //! using DileptonTrackCandidate = DileptonTrackCandidates::iterator; +// candidate information +namespace dileptonTrackTrackCandidate +{ +// infotmation about the dilepton-track-track +DECLARE_SOA_COLUMN(Mass, mass, float); //! +DECLARE_SOA_COLUMN(Pt, pt, float); //! +DECLARE_SOA_COLUMN(Eta, eta, float); //! +DECLARE_SOA_COLUMN(Phi, phi, float); //! +DECLARE_SOA_COLUMN(Rap, rap, float); //! +DECLARE_SOA_COLUMN(DeltaQ, deltaQ, float); //! +DECLARE_SOA_COLUMN(R1, r1, float); //! distance between the dilepton and the track1 in theta-phi plane +DECLARE_SOA_COLUMN(R2, r2, float); //! distance between the dilepton and the track2 in theta-phi plane +DECLARE_SOA_COLUMN(R, r, float); //! +DECLARE_SOA_COLUMN(DileptonMass, dileptonMass, float); //! +DECLARE_SOA_COLUMN(DileptonPt, dileptonPt, float); //! +DECLARE_SOA_COLUMN(DileptonEta, dileptonEta, float); //! +DECLARE_SOA_COLUMN(DileptonPhi, dileptonPhi, float); //! +DECLARE_SOA_COLUMN(DileptonSign, dileptonSign, int); //! +DECLARE_SOA_COLUMN(DiTracksMass, diTracksMass, float); //! +DECLARE_SOA_COLUMN(DiTracksPt, diTracksPt, float); //! +DECLARE_SOA_COLUMN(TrackPt1, trackPt1, float); //! +DECLARE_SOA_COLUMN(TrackPt2, trackPt2, float); //! +DECLARE_SOA_COLUMN(TrackEta1, trackEta1, float); //! +DECLARE_SOA_COLUMN(TrackEta2, trackEta2, float); //! +DECLARE_SOA_COLUMN(TrackPhi1, trackPhi1, float); //! +DECLARE_SOA_COLUMN(TrackPhi2, trackPhi2, float); //! +DECLARE_SOA_COLUMN(TrackSign1, trackSign1, int); //! +DECLARE_SOA_COLUMN(TrackSign2, trackSign2, int); //! +} // namespace dileptonTrackTrackCandidate + +DECLARE_SOA_TABLE(DileptonTrackTrackCandidates, "AOD", "RTDQUADPLET", //! + dileptonTrackTrackCandidate::Mass, + dileptonTrackTrackCandidate::Pt, + dileptonTrackTrackCandidate::Eta, + dileptonTrackTrackCandidate::Phi, + dileptonTrackTrackCandidate::Rap, + dileptonTrackTrackCandidate::DeltaQ, + dileptonTrackTrackCandidate::R1, + dileptonTrackTrackCandidate::R2, + dileptonTrackTrackCandidate::R, + dileptonTrackTrackCandidate::DileptonMass, + dileptonTrackTrackCandidate::DileptonPt, + dileptonTrackTrackCandidate::DileptonEta, + dileptonTrackTrackCandidate::DileptonPhi, + dileptonTrackTrackCandidate::DileptonSign, + dileptonTrackTrackCandidate::DiTracksMass, + dileptonTrackTrackCandidate::DiTracksPt, + dileptonTrackTrackCandidate::TrackPt1, + dileptonTrackTrackCandidate::TrackPt2, + dileptonTrackTrackCandidate::TrackEta1, + dileptonTrackTrackCandidate::TrackEta2, + dileptonTrackTrackCandidate::TrackPhi1, + dileptonTrackTrackCandidate::TrackPhi2, + dileptonTrackTrackCandidate::TrackSign1, + dileptonTrackTrackCandidate::TrackSign2); + +using DileptonTrackTrackCandidate = DileptonTrackTrackCandidates::iterator; + namespace v0bits { DECLARE_SOA_COLUMN(PIDBit, pidbit, uint8_t); //! @@ -724,33 +1029,62 @@ DECLARE_SOA_TABLE(RedJpDmColls, "AOD", "REDJPDMCOLL", //! namespace jpsidmescorr { -DECLARE_SOA_INDEX_COLUMN(RedJpDmColl, redJpDmColl); //! -DECLARE_SOA_COLUMN(MassD0, massD0, float); //! -DECLARE_SOA_COLUMN(MassD0bar, massD0bar, float); //! -DECLARE_SOA_COLUMN(Px, px, float); //! -DECLARE_SOA_COLUMN(Py, py, float); //! -DECLARE_SOA_COLUMN(Pz, pz, float); //! -DECLARE_SOA_COLUMN(DecVtxX, decVtxX, float); //! -DECLARE_SOA_COLUMN(DecVtxY, decVtxY, float); //! -DECLARE_SOA_COLUMN(DecVtxZ, decVtxZ, float); //! -DECLARE_SOA_COLUMN(BdtBkgMassHypo0, bdtBkgMassHypo0, float); //! -DECLARE_SOA_COLUMN(BdtPromptMassHypo0, bdtPromptMassHypo0, float); //! -DECLARE_SOA_COLUMN(BdtNonpromptMassHypo0, bdtNonpromptMassHypo0, float); //! -DECLARE_SOA_COLUMN(BdtBkg, bdtBkg, float); //! -DECLARE_SOA_COLUMN(BdtPrompt, bdtPrompt, float); //! -DECLARE_SOA_COLUMN(BdtNonprompt, bdtNonprompt, float); //! -DECLARE_SOA_COLUMN(BdtBkgMassHypo1, bdtBkgMassHypo1, float); //! -DECLARE_SOA_COLUMN(BdtPromptMassHypo1, bdtPromptMassHypo1, float); //! -DECLARE_SOA_COLUMN(BdtNonpromptMassHypo1, bdtNonpromptMassHypo1, float); //! -DECLARE_SOA_COLUMN(NumColls, numColls, uint64_t); //! -DECLARE_SOA_COLUMN(PtD0, ptD0, float); //! -DECLARE_SOA_COLUMN(PtJpsi, ptJpsi, float); //! -DECLARE_SOA_COLUMN(RapD0, rapD0, float); //! -DECLARE_SOA_COLUMN(RapJpsi, rapJpsi, float); //! -DECLARE_SOA_COLUMN(PhiD0, phiD0, float); //! -DECLARE_SOA_COLUMN(PhiJpsi, phiJpsi, float); //! -DECLARE_SOA_COLUMN(DeltaY, deltaY, float); //! -DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); //! +DECLARE_SOA_INDEX_COLUMN(RedJpDmColl, redJpDmColl); //! +DECLARE_SOA_COLUMN(MassDmes, massDmes, float); //! +DECLARE_SOA_COLUMN(MassD0, massD0, float); //! +DECLARE_SOA_COLUMN(MassD0bar, massD0bar, float); //! +DECLARE_SOA_COLUMN(Px, px, float); //! +DECLARE_SOA_COLUMN(Py, py, float); //! +DECLARE_SOA_COLUMN(Pz, pz, float); //! +DECLARE_SOA_COLUMN(DecVtxX, decVtxX, float); //! +DECLARE_SOA_COLUMN(DecVtxY, decVtxY, float); //! +DECLARE_SOA_COLUMN(DecVtxZ, decVtxZ, float); //! +DECLARE_SOA_COLUMN(BdtBkgMassHypo0, bdtBkgMassHypo0, float); //! +DECLARE_SOA_COLUMN(BdtPromptMassHypo0, bdtPromptMassHypo0, float); //! +DECLARE_SOA_COLUMN(BdtNonpromptMassHypo0, bdtNonpromptMassHypo0, float); //! +DECLARE_SOA_COLUMN(BdtBkg, bdtBkg, float); //! +DECLARE_SOA_COLUMN(BdtPrompt, bdtPrompt, float); //! +DECLARE_SOA_COLUMN(BdtNonprompt, bdtNonprompt, float); //! +DECLARE_SOA_COLUMN(BdtBkgMassHypo1, bdtBkgMassHypo1, float); //! +DECLARE_SOA_COLUMN(BdtPromptMassHypo1, bdtPromptMassHypo1, float); //! +DECLARE_SOA_COLUMN(BdtNonpromptMassHypo1, bdtNonpromptMassHypo1, float); //! +DECLARE_SOA_COLUMN(NumColls, numColls, uint64_t); //! +DECLARE_SOA_COLUMN(PtDmes, ptDmes, float); //! +DECLARE_SOA_COLUMN(PtJpsi, ptJpsi, float); //! +DECLARE_SOA_COLUMN(RapDmes, rapDmes, float); //! +DECLARE_SOA_COLUMN(RapJpsi, rapJpsi, float); //! +DECLARE_SOA_COLUMN(PhiDmes, phiDmes, float); //! +DECLARE_SOA_COLUMN(PhiJpsi, phiJpsi, float); //! +DECLARE_SOA_COLUMN(DeltaY, deltaY, float); //! +DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); //! +DECLARE_SOA_COLUMN(NumItsClsDmesProng0, numItsClsDmesProng0, int); //! +DECLARE_SOA_COLUMN(NumItsClsDmesProng1, numItsClsDmesProng1, int); //! +DECLARE_SOA_COLUMN(NumTpcCrossedRowsDmesProng0, numTpcCrossedRowsDmesProng0, int); //! +DECLARE_SOA_COLUMN(NumTpcCrossedRowsDmesProng1, numTpcCrossedRowsDmesProng1, int); //! +DECLARE_SOA_COLUMN(EtaDmesProng0, etaDmesProng0, float); //! +DECLARE_SOA_COLUMN(EtaDmesProng1, etaDmesProng1, float); //! +DECLARE_SOA_COLUMN(PtDmesProng0, ptDmesProng0, float); //! +DECLARE_SOA_COLUMN(PtDmesProng1, ptDmesProng1, float); //! +DECLARE_SOA_COLUMN(MinNumItsClsDmesProng, minNumItsClsDmesProng, int); //! +DECLARE_SOA_COLUMN(MinNumTpcCrossedRowsDmesProng, minNumTpcCrossedRowsDmesProng, int); //! +DECLARE_SOA_COLUMN(MinAbsEtaDmesProng, minAbsEtaDmesProng, float); //! +DECLARE_SOA_COLUMN(MinPtDmesProng, minPtDmesProng, float); //! +DECLARE_SOA_COLUMN(NumSigmaTpcPiProng0, numSigmaTpcPiProng0, float); //! +DECLARE_SOA_COLUMN(NumSigmaTpcPiProng1, numSigmaTpcPiProng1, float); //! +DECLARE_SOA_COLUMN(NumSigmaTofPiProng0, numSigmaTofPiProng0, float); //! +DECLARE_SOA_COLUMN(NumSigmaTofPiProng1, numSigmaTofPiProng1, float); //! +DECLARE_SOA_COLUMN(NumSigmaTpcKaProng0, numSigmaTpcKaProng0, float); //! +DECLARE_SOA_COLUMN(NumSigmaTpcKaProng1, numSigmaTpcKaProng1, float); //! +DECLARE_SOA_COLUMN(NumSigmaTofKaProng0, numSigmaTofKaProng0, float); //! +DECLARE_SOA_COLUMN(NumSigmaTofKaProng1, numSigmaTofKaProng1, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(NumSigmaTpcTofPiProng0, numSigmaTpcTofPiProng0, //! + [](float tpcNSigmaPi0, float tofNSigmaPi0) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi0, tofNSigmaPi0); }); +DECLARE_SOA_DYNAMIC_COLUMN(NumSigmaTpcTofPiProng1, numSigmaTpcTofPiProng1, //! + [](float tpcNSigmaPi1, float tofNSigmaPi1) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi1, tofNSigmaPi1); }); +DECLARE_SOA_DYNAMIC_COLUMN(NumSigmaTpcTofKaProng0, numSigmaTpcTofKaProng0, //! + [](float tpcNSigmaKa0, float tofNSigmaKa0) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaKa0, tofNSigmaKa0); }); +DECLARE_SOA_DYNAMIC_COLUMN(NumSigmaTpcTofKaProng1, numSigmaTpcTofKaProng1, //! + [](float tpcNSigmaKa1, float tofNSigmaKa1) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaKa1, tofNSigmaKa1); }); } // namespace jpsidmescorr DECLARE_SOA_TABLE(RedJpDmDileptons, "AOD", "REDJPDMDILEPTON", //! @@ -781,6 +1115,30 @@ DECLARE_SOA_TABLE(RedJpDmDmesons, "AOD", "REDJPDMDMESON", //! reducedpair::Sign, reducedpair::McDecision); +DECLARE_SOA_TABLE(RedJpDmDmDau0s, "AOD", "REDJPDMDMDAU0", //! + jpsidmescorr::PtDmesProng0, + jpsidmescorr::EtaDmesProng0, + jpsidmescorr::NumItsClsDmesProng0, + jpsidmescorr::NumTpcCrossedRowsDmesProng0, + jpsidmescorr::NumSigmaTpcPiProng0, + jpsidmescorr::NumSigmaTofPiProng0, + jpsidmescorr::NumSigmaTpcKaProng0, + jpsidmescorr::NumSigmaTofKaProng0, + jpsidmescorr::NumSigmaTpcTofPiProng0, + jpsidmescorr::NumSigmaTpcTofKaProng0); + +DECLARE_SOA_TABLE(RedJpDmDmDau1s, "AOD", "REDJPDMDMDAU1", //! + jpsidmescorr::PtDmesProng1, + jpsidmescorr::EtaDmesProng1, + jpsidmescorr::NumItsClsDmesProng1, + jpsidmescorr::NumTpcCrossedRowsDmesProng1, + jpsidmescorr::NumSigmaTpcPiProng1, + jpsidmescorr::NumSigmaTofPiProng1, + jpsidmescorr::NumSigmaTpcKaProng1, + jpsidmescorr::NumSigmaTofKaProng1, + jpsidmescorr::NumSigmaTpcTofPiProng1, + jpsidmescorr::NumSigmaTpcTofKaProng1); + DECLARE_SOA_TABLE(RedJpDmD0Masss, "AOD", "REDJPDMD0MASS", //! jpsidmescorr::MassD0, jpsidmescorr::MassD0bar); @@ -795,18 +1153,73 @@ DECLARE_SOA_TABLE(RedJpDmDmesBdts, "AOD", "REDJPDMDMESBDT", //! DECLARE_SOA_TABLE(RedDleptDmesAll, "AOD", "RTDILPTDMESALL", //! reducedpair::Mass, - jpsidmescorr::MassD0, + jpsidmescorr::MassDmes, jpsidmescorr::PtJpsi, - jpsidmescorr::PtD0, + jpsidmescorr::PtDmes, jpsidmescorr::RapJpsi, - jpsidmescorr::RapD0, + jpsidmescorr::RapDmes, jpsidmescorr::PhiJpsi, - jpsidmescorr::PhiD0, + jpsidmescorr::PhiDmes, jpsidmescorr::DeltaY, jpsidmescorr::DeltaPhi, jpsidmescorr::BdtBkg, jpsidmescorr::BdtPrompt, - jpsidmescorr::BdtNonprompt); + jpsidmescorr::BdtNonprompt, + jpsidmescorr::MinPtDmesProng, + jpsidmescorr::MinAbsEtaDmesProng, + jpsidmescorr::MinNumItsClsDmesProng, + jpsidmescorr::MinNumTpcCrossedRowsDmesProng); + +namespace muondca +{ +DECLARE_SOA_COLUMN(pDCA, pdca, float); //! +DECLARE_SOA_COLUMN(DCA, dca, float); //! +DECLARE_SOA_COLUMN(DCAx, dcax, float); //! +DECLARE_SOA_COLUMN(DCAy, dcay, float); //! +DECLARE_SOA_COLUMN(Rabs, rabs, float); //! +DECLARE_SOA_COLUMN(Px, px, float); //! +DECLARE_SOA_COLUMN(Py, py, float); //! +DECLARE_SOA_COLUMN(Pz, pz, float); //! +} // namespace muondca + +DECLARE_SOA_TABLE(ReducedMuonsDca, "AOD", "RTMUONDCA", + muondca::pDCA, + muondca::DCA, + muondca::DCAx, + muondca::DCAy, + muondca::Rabs, + reducedmuon::Pt, + reducedmuon::Eta, reducedmuon::Phi, + reducedmuon::Sign, reducedmuon::IsAmbiguous, + muondca::Px, + muondca::Py, + muondca::Pz); + +using ReducedMuonDca = ReducedMuonsDca::iterator; + +//______________________________________________________ +namespace generatedquarkoniamc +{ +//______________________________________________________ +// Binned content for generated particles: derived data +DECLARE_SOA_COLUMN(GeneratedEtaC1S, generatedEtaC1S, std::vector); //! Eta(1S) binned generated data +DECLARE_SOA_COLUMN(GeneratedJPsi, generatedJPsi, std::vector); //! J/Psi binned generated data +DECLARE_SOA_COLUMN(GeneratedChiC0, generatedChiC0, std::vector); //! ChiC0(1P) binned generated data +DECLARE_SOA_COLUMN(GeneratedChiC1, generatedChiC1, std::vector); //! ChiC1(1P) binned generated data +DECLARE_SOA_COLUMN(GeneratedHC, generatedHC, std::vector); //! hC binned generated data +DECLARE_SOA_COLUMN(GeneratedChiC2, generatedChiC2, std::vector); //! ChiC2(1P) binned generated data +DECLARE_SOA_COLUMN(GeneratedEtaC2S, generatedEtaC2S, std::vector); //! EtaC(2S) binned generated data +DECLARE_SOA_COLUMN(GeneratedPsi2S, generatedPsi2S, std::vector); //! Psi(2S) binned generated data +} // namespace generatedquarkoniamc + +DECLARE_SOA_TABLE(GeEtaC1S, "AOD", "GEETAC1S", generatedquarkoniamc::GeneratedEtaC1S); +DECLARE_SOA_TABLE(GeJPsi, "AOD", "GEJPSI", generatedquarkoniamc::GeneratedJPsi); +DECLARE_SOA_TABLE(GeChiC0, "AOD", "GECHIC0", generatedquarkoniamc::GeneratedChiC0); +DECLARE_SOA_TABLE(GeChiC1, "AOD", "GECHIC1", generatedquarkoniamc::GeneratedChiC1); +DECLARE_SOA_TABLE(GeHC, "AOD", "GEHC", generatedquarkoniamc::GeneratedHC); +DECLARE_SOA_TABLE(GeChiC2, "AOD", "GECHIC2", generatedquarkoniamc::GeneratedChiC2); +DECLARE_SOA_TABLE(GeEtaC2S, "AOD", "GEETAC2S", generatedquarkoniamc::GeneratedEtaC2S); +DECLARE_SOA_TABLE(GePsi2S, "AOD", "GEPSI2S", generatedquarkoniamc::GeneratedPsi2S); } // namespace o2::aod #endif // PWGDQ_DATAMODEL_REDUCEDINFOTABLES_H_ diff --git a/PWGDQ/Macros/evalMchTrackingEfficiency.cxx b/PWGDQ/Macros/evalMchTrackingEfficiency.cxx new file mode 100644 index 00000000000..34610915850 --- /dev/null +++ b/PWGDQ/Macros/evalMchTrackingEfficiency.cxx @@ -0,0 +1,424 @@ +// 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 evalMchTrackingEfficiency.cxx +/// \brief Macro to evaluate the MCH tracking efficiency using the results from taskMuonTrkEfficiency.cxx +/// +/// \author Zaida Conesa del Valle +/// \author Andrea Tavira García +#include + +#include "TFile.h" +#include "TDirectoryFile.h" +#include "THn.h" +#include "TH1F.h" +#include "TH2F.h" +#include "TAxis.h" +#include "TCanvas.h" +#include "TStyle.h" +#include "TLegend.h" + +double computeEfficiencyPerChamber(THnF* hnf, int iAxis, int iCh, double binLimits[2]); +double computeEfficiencyPerChamber(THnF* hnf, const int iAxis[3], int iCh, double binLimits[3][2]); +double computeStationEfficiency(double effPerChamber[4], int iStation); +double computeTotalEfficiency(double effPerStation[5]); + +void getBinLimits(THnF* hnf, int nBins, int iAxis, std::vector& limits); +void setHistoMinPt(THnF* hnf, int iAxis, float minPt); +void setStyleCanvas(TCanvas* c); +void setHistoStylePerChamber(TH1F* h, int iCh); + +// +// Main function to evaluate the muon tracking efficiency +// +void evalMchTrackingEfficiency(const char* inFile = "AnalysisResults.root", const char* outFileName = "evalMchTrkEff.root", const char* suffix = "", const float minPt = 0.5) +{ + // read ouput from the taskComputeMchEfficiency + TFile* file = TFile::Open(inFile, "read"); + TDirectoryFile* dir = reinterpret_cast(file->Get("task-muon-mch-trk-efficiency")); + THnF* hHitsEtaPtPhi = reinterpret_cast(dir->Get("hHitsEtaPtPhi")); + + // retrieve the eta/pt/phi axis binning configuration + const int etaAx = 1, ptAx = 2, phiAx = 3; + const int listAx[3] = {etaAx, ptAx, phiAx}; + + int nBinsEta = hHitsEtaPtPhi->GetAxis(etaAx)->GetNbins(); + int nBinsPt = hHitsEtaPtPhi->GetAxis(ptAx)->GetNbins(); + int nBinsPhi = hHitsEtaPtPhi->GetAxis(phiAx)->GetNbins(); + + std::vector limitsEta, limitsPt, limitsPhi; + + getBinLimits(hHitsEtaPtPhi, nBinsEta, etaAx, limitsEta); // these are values! + getBinLimits(hHitsEtaPtPhi, nBinsPt, ptAx, limitsPt); // these are values! + getBinLimits(hHitsEtaPtPhi, nBinsPhi, phiAx, limitsPhi); // these are values! + + int nBinMinPt = hHitsEtaPtPhi->GetAxis(ptAx)->FindBin(minPt); + + // Define the output file + TFile* outFile = new TFile(outFileName, "recreate"); + + // define histograms efficiency per chamber + // vs eta, pt, phi + int const kChamber = 10, kStation = 5; + TH1F *hEffPerChamberEta[kChamber], *hEffPerChamberPt[kChamber], *hEffPerChamberPhi[kChamber]; + + for (int iCh = 0; iCh < kChamber; iCh++) { + hEffPerChamberEta[iCh] = new TH1F(Form("hEffPerChamberEta_%d", iCh), Form("hEff Chamber %d vs. #eta; #eta ; Efficiency", iCh), nBinsEta, limitsEta.data()); + hEffPerChamberPt[iCh] = new TH1F(Form("hEffPerChamberPt_%d", iCh), Form("hEff Chamber %d vs. #it{p}_{T}; #it{p}_{T} (GeV/#it{c}) ; Efficiency", iCh), nBinsPt, limitsPt.data()); + hEffPerChamberPhi[iCh] = new TH1F(Form("hEffPerChamberPhi_%d", iCh), Form("hEff Chamber %d vs. #varphi; #varphi (rad.) ; Efficiency", iCh), nBinsPhi, limitsPhi.data()); + } + + // define histogram for integrated efficiency per chamber + // as well as the one per station + // the total integrated value is stored in both histos as last quantity for reference + TH1F* hEffIntegratedChamber = new TH1F("hEffIntegratedChamber", "integrated efficiency per chamber; ;Efficiency", kChamber + 1, -0.5, kChamber + 0.5); + const char* hChNames[kChamber + 1]; + for (int i = 0; i < kChamber; i++) { + hEffIntegratedChamber->GetXaxis()->SetBinLabel(i + 1, Form("Chamber %d", i)); + } + hEffIntegratedChamber->GetXaxis()->SetBinLabel(kChamber + 1, "Total"); + + // Define histogram for integrated efficiency per station + TH1F* hEffIntegratedStation = new TH1F("hEffIntegratedStation", "integrated efficiency per station; ;Efficiency", kStation, -0.5, kStation + 0.5); + const char* hStNames[kStation]; + for (int i = 0; i < 3; i++) { + hEffIntegratedStation->GetXaxis()->SetBinLabel(i + 1, Form("Station %d", i)); + } + hEffIntegratedStation->GetXaxis()->SetBinLabel(4, "Station 3 & 4"); + hEffIntegratedStation->GetXaxis()->SetBinLabel(kStation, "Total"); + + // define also the eta-phi efficiency per chamber + TH2F* hEffPerChamberEtaPhi[kChamber]; + for (int iCh = 0; iCh < kChamber; iCh++) { + hEffPerChamberEtaPhi[iCh] = new TH2F(Form("hEffPerChamberEtaPhi_%d", iCh), Form("hEff Chamber %d vs. #eta vs. #varphi; #eta ; #varphi ; Efficiency", iCh), nBinsEta, limitsEta.data(), nBinsPhi, limitsPhi.data()); + } + + double effIntChamber[kChamber]; + double effIntStation[kStation]; + double effIntegrated = 0.; + + // Calculation of the efficiency per chamber for each variable + for (int iCh = 0; iCh < 10; iCh++) { + double binLimits[2] = {0., 0.}; + + // Calculation vs. eta + // check min pt interval + setHistoMinPt(hHitsEtaPtPhi, ptAx, minPt); + for (int ikBin = 1; ikBin <= nBinsEta; ikBin++) { + binLimits[0] = limitsEta[ikBin - 1]; // these are NOT bins + binLimits[1] = limitsEta[ikBin]; // these are NOT bins + double eff = computeEfficiencyPerChamber(hHitsEtaPtPhi, etaAx, iCh, binLimits); + int hBin = hEffPerChamberEta[iCh]->FindBin(binLimits[0] + (binLimits[1] - binLimits[0]) / 2.); + hEffPerChamberEta[iCh]->SetBinContent(hBin, eff); + } + // Calculation vs pt + for (int ikBin = 1; ikBin <= nBinsPt; ikBin++) { + binLimits[0] = limitsPt[ikBin - 1]; + binLimits[1] = limitsPt[ikBin]; + double eff = computeEfficiencyPerChamber(hHitsEtaPtPhi, ptAx, iCh, binLimits); + int hBin = hEffPerChamberPt[iCh]->FindBin(binLimits[0] + (binLimits[1] - binLimits[0]) / 2.); + hEffPerChamberPt[iCh]->SetBinContent(hBin, eff); + } + // Calculation vs phi + // check min pt interval + setHistoMinPt(hHitsEtaPtPhi, ptAx, minPt); + for (int ikBin = 1; ikBin <= nBinsPhi; ikBin++) { + binLimits[0] = limitsPhi[ikBin - 1]; + binLimits[1] = limitsPhi[ikBin]; + double eff = computeEfficiencyPerChamber(hHitsEtaPtPhi, phiAx, iCh, binLimits); + int hBin = hEffPerChamberPhi[iCh]->FindBin(binLimits[0] + (binLimits[1] - binLimits[0]) / 2.); + hEffPerChamberPhi[iCh]->SetBinContent(hBin, eff); + } + // Calculation of the integrated quantity per chamber + binLimits[0] = limitsEta[0]; + binLimits[1] = limitsEta[nBinsEta]; + effIntChamber[iCh] = computeEfficiencyPerChamber(hHitsEtaPtPhi, etaAx, iCh, binLimits); + hEffIntegratedChamber->SetBinContent(iCh + 1, effIntChamber[iCh]); + + } // end calculation efficiency per chamber + + // Do integrated calculation per station + double tmp[4] = {effIntChamber[0], effIntChamber[1], 0., 0.}; + effIntStation[0] = computeStationEfficiency(tmp, 0); // Station 1 + tmp[0] = effIntChamber[2]; + tmp[1] = effIntChamber[3]; + effIntStation[1] = computeStationEfficiency(tmp, 1); // Station 2 + tmp[0] = effIntChamber[4]; + tmp[1] = effIntChamber[5]; + effIntStation[2] = computeStationEfficiency(tmp, 2); // Station 3 + tmp[0] = effIntChamber[6]; + tmp[1] = effIntChamber[7]; + tmp[2] = effIntChamber[8]; + tmp[3] = effIntChamber[9]; + effIntStation[3] = computeStationEfficiency(tmp, 3); // Station 4 & 5 + + for (int i = 1; i <= 4; i++) { + hEffIntegratedStation->SetBinContent(i, effIntStation[i - 1]); + } + + // Do integrated total calculation + effIntegrated = computeTotalEfficiency(effIntStation); + hEffIntegratedStation->SetBinContent(kStation, effIntegrated); + hEffIntegratedChamber->SetBinContent(kChamber + 1, effIntegrated); + + // Calculation of the 2D eta-phi efficiency per chamber + for (int iCh = 0; iCh < 10; iCh++) { + double binLimits[3][2] = {{0., 0.}, {0., 0.}, {0., 0.}}; + binLimits[ptAx - 1][0] = minPt; // these are values!! + binLimits[ptAx - 1][1] = hHitsEtaPtPhi->GetAxis(ptAx)->GetBinUpEdge(nBinsPt); // these are values!! + // Loop over eta + for (int ikBin = 1; ikBin <= nBinsEta; ikBin++) { + binLimits[etaAx - 1][0] = limitsEta[ikBin - 1]; + binLimits[etaAx - 1][1] = limitsEta[ikBin]; + + // Loop over phi + for (int isbin = 1; isbin <= nBinsPhi; isbin++) { + binLimits[phiAx - 1][0] = limitsPhi[isbin - 1]; + binLimits[phiAx - 1][1] = limitsPhi[isbin]; + double eff = computeEfficiencyPerChamber(hHitsEtaPtPhi, listAx, iCh, binLimits); + int xBin = hEffPerChamberEtaPhi[iCh]->GetXaxis()->FindBin(binLimits[etaAx - 1][0] + (binLimits[etaAx - 1][1] - binLimits[etaAx - 1][0]) / 2.); + int yBin = hEffPerChamberEtaPhi[iCh]->GetYaxis()->FindBin(binLimits[phiAx - 1][0] + (binLimits[phiAx - 1][1] - binLimits[phiAx - 1][0]) / 2.); + hEffPerChamberEtaPhi[iCh]->SetBinContent(xBin, yBin, eff); + } + } + } + + // Drawing output values + double yPlotLimits[2] = {0, 1.1}; + gStyle->SetOptStat(0); + TLegend* legEffChamber = new TLegend(0.6, 0.2, 0.8, 0.7); + + TCanvas* cEffChEta = new TCanvas(Form("cEffChEta%s", suffix), Form("MCH tracking efficiency per chamber vs. eta %s", suffix)); + setStyleCanvas(cEffChEta); + hEffPerChamberEta[0]->GetYaxis()->SetRangeUser(yPlotLimits[0], yPlotLimits[1]); + hEffPerChamberEta[0]->Draw(); + + for (int iCh = 0; iCh < 10; iCh++) { + setHistoStylePerChamber(hEffPerChamberEta[iCh], iCh); + hEffPerChamberEta[iCh]->Draw("hsame"); + legEffChamber->AddEntry(hEffPerChamberEta[iCh], Form("Chamber %d", iCh), "l"); + } + legEffChamber->Draw(); + + TCanvas* cEffChPt = new TCanvas(Form("cEffChPt%s", suffix), Form("MCH tracking efficiency per chamber vs. pT %s", suffix)); + setStyleCanvas(cEffChPt); + hEffPerChamberPt[0]->GetYaxis()->SetRangeUser(yPlotLimits[0], yPlotLimits[1]); + hEffPerChamberPt[0]->Draw(); + for (int iCh = 0; iCh < 10; iCh++) { + setHistoStylePerChamber(hEffPerChamberPt[iCh], iCh); + hEffPerChamberPt[iCh]->Draw("hsame"); + } + legEffChamber->Draw(); + + TCanvas* cEffChPhi = new TCanvas(Form("cEffChPhi%s", suffix), Form("MCH tracking efficiency per chamber vs. phi %s", suffix)); + setStyleCanvas(cEffChPhi); + hEffPerChamberPhi[0]->GetYaxis()->SetRangeUser(yPlotLimits[0], yPlotLimits[1]); + hEffPerChamberPhi[0]->Draw(); + for (int iCh = 0; iCh < 10; iCh++) { + setHistoStylePerChamber(hEffPerChamberPhi[iCh], iCh); + hEffPerChamberPhi[iCh]->Draw("hsame"); + } + legEffChamber->Draw(); + + TCanvas* cEffIntegrated = new TCanvas(Form("cEffIntegrated%s", suffix), Form("MCH tracking integrated efficiency %s", suffix)); + setStyleCanvas(cEffIntegrated); + setHistoStylePerChamber(hEffIntegratedChamber, 10); + setHistoStylePerChamber(hEffIntegratedStation, 10); + cEffIntegrated->Divide(1, 2); + cEffIntegrated->cd(1); + hEffIntegratedChamber->GetYaxis()->SetRangeUser(yPlotLimits[0], yPlotLimits[1]); + hEffIntegratedChamber->SetMarkerSize(1.8); + hEffIntegratedChamber->Draw("h,text"); + cEffIntegrated->cd(2); + hEffIntegratedStation->SetMarkerSize(1.8); + hEffIntegratedStation->Draw("h,text"); + + TCanvas* cEffEtaPhi = new TCanvas(Form("cEffEtaPhi%s", suffix), Form("MCH tracking eta-phi efficiency %s", suffix)); + cEffEtaPhi->Divide(2, 5); + for (int iCh = 0; iCh < 10; iCh++) { + cEffEtaPhi->cd(iCh + 1); + hEffPerChamberEtaPhi[iCh]->Draw("colz"); + } + + outFile->Write(); + file->Close(); +} + +// Function to retrieve the axis limits from the THn +void getBinLimits(THnF* hnf, int nBins, int iAxis, std::vector& limits) +{ + TAxis* ax = hnf->GetAxis(iAxis); + for (int i = 1; i <= nBins; i++) { + limits.push_back(ax->GetBinLowEdge(i)); + } + limits.push_back(ax->GetBinUpEdge(nBins)); + return; +} + +// Evaluate the efficiency per Chamber +// Eff(i) = N(i+j) / ( N(i+j) + N(0+j) ) +double computeEfficiencyPerChamber(THnF* hnf, int iAxis, int iCh, double binLimits[2]) +{ + // Set range of study + hnf->GetAxis(iAxis)->SetRangeUser(binLimits[0], binLimits[1]); + + // Project onto the Nhits axis + TH1F* htmp = reinterpret_cast(hnf->Projection(0)); + double NhitPairing[16]; + for (int i = 0; i < 16; i++) { + NhitPairing[i] = 0; + NhitPairing[i] = htmp->GetBinContent(i + 1); + } + double eff = 0.; + if (iCh == 0 && (NhitPairing[0] + NhitPairing[2]) > 0.) { // Chamber 0 : St 1 + eff = NhitPairing[0] / (NhitPairing[0] + NhitPairing[2]); + } else if (iCh == 1 && NhitPairing[0] > 0.) { // Chamber 1 : St 1 + eff = NhitPairing[0] / (NhitPairing[0] + NhitPairing[1]); + } else if (iCh == 2 && NhitPairing[3] > 0.) { // Chamber 2 : St 2 + eff = NhitPairing[3] / (NhitPairing[3] + NhitPairing[5]); + } else if (iCh == 3 && NhitPairing[3] > 0.) { // Chamber 3 : St 2 + eff = NhitPairing[3] / (NhitPairing[3] + NhitPairing[4]); + } else if (iCh == 4 && NhitPairing[6] > 0.) { // Chamber 4 : St 3 + eff = NhitPairing[6] / (NhitPairing[6] + NhitPairing[8]); + } else if (iCh == 5 && NhitPairing[6] > 0.) { // Chamber 5 : St 3 + eff = NhitPairing[6] / (NhitPairing[6] + NhitPairing[7]); + } else if (iCh == 6 && NhitPairing[9] > 0.) { // Chamber 6 : St 4 + eff = NhitPairing[9] / (NhitPairing[9] + NhitPairing[11]); + } else if (iCh == 7 && NhitPairing[9] > 0.) { // Chamber 7 : St 4 + eff = NhitPairing[9] / (NhitPairing[9] + NhitPairing[10]); + } else if (iCh == 8 && NhitPairing[12] > 0.) { // Chamber 8 : St 5 + eff = NhitPairing[12] / (NhitPairing[12] + NhitPairing[14]); + } else if (iCh == 9 && NhitPairing[12] > 0.) { // Chamber 9 : St 5 + eff = NhitPairing[12] / (NhitPairing[12] + NhitPairing[13]); + } + + delete htmp; + + // reset to full range + int nBins = hnf->GetAxis(iAxis)->GetNbins(); + hnf->GetAxis(iAxis)->SetRange(1, nBins); + + return eff; +} + +// Evaluate the efficiency per Chamber +// Eff(i) = N(i+j) / ( N(i+j) + N(0+j) ) +double computeEfficiencyPerChamber(THnF* hnf, const int iAxis[3], int iCh, double binLimits[3][2]) +{ + // Set range of study + for (int i = 0; i < 3; i++) { + hnf->GetAxis(iAxis[i])->SetRangeUser(binLimits[i][0], binLimits[i][1]); + } + + // Project onto the Nhits axis + TH1F* htmp = reinterpret_cast(hnf->Projection(0)); + double NhitPairing[16]; + for (int i = 0; i < 16; i++) { + NhitPairing[i] = 0; + NhitPairing[i] = htmp->GetBinContent(i + 1); + } + double eff = 0.; + if (iCh == 0 && (NhitPairing[0] + NhitPairing[2]) > 0.) { // Chamber 0 : St 1 + eff = NhitPairing[0] / (NhitPairing[0] + NhitPairing[2]); + } else if (iCh == 1 && NhitPairing[0] > 0.) { // Chamber 1 : St 1 + eff = NhitPairing[0] / (NhitPairing[0] + NhitPairing[1]); + } else if (iCh == 2 && NhitPairing[3] > 0.) { // Chamber 2 : St 2 + eff = NhitPairing[3] / (NhitPairing[3] + NhitPairing[5]); + } else if (iCh == 3 && NhitPairing[3] > 0.) { // Chamber 3 : St 2 + eff = NhitPairing[3] / (NhitPairing[3] + NhitPairing[4]); + } else if (iCh == 4 && NhitPairing[6] > 0.) { // Chamber 4 : St 3 + eff = NhitPairing[6] / (NhitPairing[6] + NhitPairing[8]); + } else if (iCh == 5 && NhitPairing[6] > 0.) { // Chamber 5 : St 3 + eff = NhitPairing[6] / (NhitPairing[6] + NhitPairing[7]); + } else if (iCh == 6 && NhitPairing[9] > 0.) { // Chamber 6 : St 4 + eff = NhitPairing[9] / (NhitPairing[9] + NhitPairing[11]); + } else if (iCh == 7 && NhitPairing[9] > 0.) { // Chamber 7 : St 4 + eff = NhitPairing[9] / (NhitPairing[9] + NhitPairing[10]); + } else if (iCh == 8 && NhitPairing[12] > 0.) { // Chamber 8 : St 5 + eff = NhitPairing[12] / (NhitPairing[12] + NhitPairing[14]); + } else if (iCh == 9 && NhitPairing[12] > 0.) { // Chamber 9 : St 5 + eff = NhitPairing[12] / (NhitPairing[12] + NhitPairing[13]); + } + + delete htmp; + + // reset to full range + for (int i = 0; i < 3; i++) { + int nBins = hnf->GetAxis(iAxis[i])->GetNbins(); + hnf->GetAxis(iAxis[i])->SetRange(1, nBins); + } + + return eff; +} + +// Compute the efficiency per station +// Stations 1, 2, 3: Eff = 1 - ( 1 - E(i) ) * ( 1 - (E(j) ) +// Stations 4 & 5 together: Eff = product(i=6...9) E(i) + sum(i=6...9) [ ( 1 - E(i) )* product(j=6...9, i!=i) E(j) ] +double computeStationEfficiency(double effPerChamber[4], int iStation) +{ + double effSt = 0.; + if (iStation < 3) { // Calculation for Station 1, 2, 3 + effSt = 1. - (1. - effPerChamber[0]) * (1. - effPerChamber[1]); + } else { // Calculation for Station 4 & 5 + double product = 1., sum = 0.; + for (int i = 0; i < 4; i++) { + product *= effPerChamber[i]; + } + for (int i = 0; i < 4; i++) { + double tmpProduct = 1.; + for (int j = 0; j < 4; j++) { + if (i != j) { + tmpProduct *= effPerChamber[j]; + } + } + sum += (1. - effPerChamber[i]) * tmpProduct; + } + effSt = product + sum; + } + return effSt; +} + +// Total efficiency corresponds to the product of the efficiency per station +double computeTotalEfficiency(double effPerStation[5]) +{ + double effTot = 1.; + for (int i = 0; i < 4; i++) { + effTot *= effPerStation[i]; + } + return effTot; +} + +// Set style for histos +void setHistoStylePerChamber(TH1F* h, int iCh) +{ + int iColor[11] = {kRed, kMagenta, kBlue, kAzure + 10, kGreen, kGreen + 3, kOrange + 7, kOrange + 4, kGray + 1, kGray + 3, kBlack}; + h->SetLineColor(iColor[iCh]); + h->SetMarkerColor(iColor[iCh]); +} +// Set style for canvas +void setStyleCanvas(TCanvas* c) +{ + c->SetTickx(); + c->SetTicky(); +} + +void setHistoMinPt(THnF* hnf, int iAxis, float minPt) +{ + // Get the axis and its number of bins + TAxis* axis = hnf->GetAxis(iAxis); + int nBinsPt = axis->GetNbins(); + + // Find the bin corresponding to minPt + int nBinMinPt = axis->FindBin(minPt); // FindBin already gives the correct bin index + + // Set range using bin indices + axis->SetRange(nBinMinPt, nBinsPt); +} diff --git a/PWGDQ/TableProducer/CMakeLists.txt b/PWGDQ/TableProducer/CMakeLists.txt index 27b95688bd6..b8fd20d356d 100644 --- a/PWGDQ/TableProducer/CMakeLists.txt +++ b/PWGDQ/TableProducer/CMakeLists.txt @@ -11,12 +11,12 @@ o2physics_add_dpl_workflow(table-maker SOURCES tableMaker.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2Physics::AnalysisCCDB O2Physics::PWGDQCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2Physics::AnalysisCCDB O2Physics::PWGDQCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(table-maker-with-assoc SOURCES tableMaker_withAssoc.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2Physics::AnalysisCCDB O2Physics::PWGDQCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2Physics::AnalysisCCDB O2Physics::PWGDQCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(table-maker-mc @@ -24,12 +24,22 @@ o2physics_add_dpl_workflow(table-maker-mc PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2Physics::AnalysisCCDB O2Physics::PWGDQCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(table-maker-mc-with-assoc + SOURCES tableMakerMC_withAssoc.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2Physics::AnalysisCCDB O2Physics::PWGDQCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(table-maker-jpsi-hf SOURCES tableMakerJpsiHf.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore KFParticle::KFParticle + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(table-maker-muon-mch-trk-eff SOURCES tableMakerMuonMchTrkEfficiency.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(generated-quarkonia-mc + SOURCES generatedQuarkoniaMC.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase O2Physics::PWGDQCore + COMPONENT_NAME Analysis) diff --git a/PWGDQ/TableProducer/generatedQuarkoniaMC.cxx b/PWGDQ/TableProducer/generatedQuarkoniaMC.cxx new file mode 100644 index 00000000000..737faaaa6b2 --- /dev/null +++ b/PWGDQ/TableProducer/generatedQuarkoniaMC.cxx @@ -0,0 +1,242 @@ +// 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. +// +//__________________________________________________ +// this task provides produces histograms containing +// the number of generated quarkonia per unit of +// percentile and per unit of pT +// It is meant to help with providing auxiliary information +// when dealing with derived data. + +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "DCAFitter/DCAFitterN.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/TableProducer/PID/pidTOFBase.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Qvectors.h" +#include "Framework/StaticFor.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "PWGLF/DataModel/EPCalibrationTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +// simple bit checkers +#define bitset(var, nbit) ((var) |= (1 << (nbit))) +#define bitcheck(var, nbit) ((var) & (1 << (nbit))) + +struct generatedQuarkoniaMC { + SliceCache cache; + //__________________________________________________ + // Generated binned data + // this is a hack while the system does not do better + Produces geEtaC1S; + Produces geJPsi; + Produces geChiC0; + Produces geChiC1; + Produces geHC; + Produces geChiC2; + Produces geEtaC2S; + Produces gePsi2S; + + // histogram registry for bookkeeping + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + static constexpr int nSpecies = 8; + static constexpr int nParameters = 1; + static const std::vector particleNames; + static const std::vector particlePDGCodes; + static const std::vector parameterNames; + static const int defaultParameters[nSpecies][nParameters]; + static constexpr std::string_view particleNamesConstExpr[] = {"EtaC1S", "JPsi", "ChiC0", "ChiC1", + "hC", "ChiC2", "EtaC2S", "Psi2S"}; + + uint32_t enabledBits = 0; + + Configurable> enableGeneratedInfo{"enableGeneratedInfo", + {defaultParameters[0], nSpecies, + nParameters, particleNames, parameterNames}, + "Fill generated particle histograms for each species. 0: no, 1: yes"}; + + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "p_{T} (GeV/c)"}; + ConfigurableAxis axisCentrality{"axisCentrality", {100, 0.0f, 100.0f}, "Centrality"}; + + ConfigurableAxis axisNVertices{"axisNVertices", {10, -0.5f, 9.5f}, "N(vertices)"}; + + std::vector genEtaC1S; + std::vector genJPsi; + std::vector genChiC0; + std::vector genChiC1; + std::vector genHC; + std::vector genChiC2; + std::vector genEtaC2S; + std::vector genPsi2S; + + // Preslice + Preslice mcParticlePerMcCollision = o2::aod::mcparticle::mcCollisionId; + + void init(InitContext&) + { + // setup map for fast checking if enabled + static_for<0, nSpecies - 1>([&](auto i) { + constexpr int index = i.value; + int f = enableGeneratedInfo->get(particleNames[index].c_str(), "Enable"); + if (f == 1) { + bitset(enabledBits, index); + } + }); + + // Creation of histograms: MC generated + for (Int_t i = 0; i < nSpecies; i++) { + histos.add(Form("h2dGenerated%s", particleNames[i].data()), Form("h2dGenerated%s", particleNames[i].data()), kTH2D, {axisCentrality, axisPt}); + } + + histos.add("h2dNVerticesVsCentrality", "h2dNVerticesVsCentrality", kTH2D, {axisCentrality, axisNVertices}); + + // reserve space for generated vectors if that process enabled + auto hBinFinder = histos.get(HIST("h2dGeneratedEtaC1S")); + LOGF(info, "Binned generated processing enabled. Initialising with %i elements...", hBinFinder->GetNcells()); + genEtaC1S.resize(hBinFinder->GetNcells(), 0); + genJPsi.resize(hBinFinder->GetNcells(), 0); + genChiC0.resize(hBinFinder->GetNcells(), 0); + genChiC1.resize(hBinFinder->GetNcells(), 0); + genHC.resize(hBinFinder->GetNcells(), 0); + genChiC2.resize(hBinFinder->GetNcells(), 0); + genEtaC2S.resize(hBinFinder->GetNcells(), 0); + genPsi2S.resize(hBinFinder->GetNcells(), 0); + LOGF(info, "Binned generated processing: init done."); + } + + void processReconstructedSimulation(aod::McCollision const& /*mcCollision*/, soa::SmallGroups> const& collisions, aod::McParticles const& mcParticles) + { + // this process function also checks if a given collision was reconstructed and checks explicitly for splitting, etc + // identify best-of collision + int biggestNContribs = -1; + float bestCentrality = 100.5; + for (auto& collision : collisions) { + if (biggestNContribs < collision.numContrib()) { + biggestNContribs = collision.numContrib(); + bestCentrality = collision.centFT0M(); + } + } + histos.fill(HIST("h2dNVerticesVsCentrality"), bestCentrality, collisions.size()); + + for (auto& mcp : mcParticles) { + if (TMath::Abs(mcp.y()) < 0.5 /* && mcp.isPhysicalPrimary()*/) { + static_for<0, nSpecies - 1>([&](auto i) { + constexpr int index = i.value; + if (mcp.pdgCode() == particlePDGCodes[index] && bitcheck(enabledBits, index)) { + histos.fill(HIST("h2dGenerated") + HIST(particleNamesConstExpr[index]), bestCentrality, mcp.pt()); + } + }); + } + } + } + + void processBinnedGenerated(soa::Join const& mcCollisions, aod::McParticles const& mcParticlesEntireTable) + { + // set to zero + std::fill(genEtaC1S.begin(), genEtaC1S.end(), 0); + std::fill(genJPsi.begin(), genJPsi.end(), 0); + std::fill(genChiC0.begin(), genChiC0.end(), 0); + std::fill(genChiC1.begin(), genChiC1.end(), 0); + std::fill(genHC.begin(), genHC.end(), 0); + std::fill(genChiC2.begin(), genChiC2.end(), 0); + std::fill(genEtaC2S.begin(), genEtaC2S.end(), 0); + std::fill(genPsi2S.begin(), genPsi2S.end(), 0); + + // this process function also checks if a given collision was reconstructed and checks explicitly for splitting, etc + for (auto& mcCollision : mcCollisions) { + const uint64_t mcCollIndex = mcCollision.globalIndex(); + + // use one of the generated histograms as the bin finder + auto hBinFinder = histos.get(HIST("h2dGeneratedEtaC1S")); + + auto mcParticles = mcParticlesEntireTable.sliceBy(mcParticlePerMcCollision, mcCollIndex); + for (auto& mcp : mcParticles) { + if (TMath::Abs(mcp.y()) < 0.5 /* && mcp.isPhysicalPrimary()*/) { + auto binNumber = hBinFinder->FindBin(mcCollision.bestCollisionCentFT0C(), mcp.pt()); // caution: pack + if (mcp.pdgCode() == 441) + genEtaC1S[binNumber]++; + if (mcp.pdgCode() == 443) + genJPsi[binNumber]++; + if (mcp.pdgCode() == 10441) + genChiC0[binNumber]++; + if (mcp.pdgCode() == 20443) + genChiC1[binNumber]++; + if (mcp.pdgCode() == 10443) + genHC[binNumber]++; + if (mcp.pdgCode() == 445) + genChiC2[binNumber]++; + if (mcp.pdgCode() == 100441) + genEtaC2S[binNumber]++; + if (mcp.pdgCode() == 100443) + genPsi2S[binNumber]++; + } + } + } + // at end of data frame + // -> pack information from this DF into a generated histogram, once / DF + geEtaC1S(genEtaC1S); + geJPsi(genJPsi); + geChiC0(genChiC0); + geChiC1(genChiC1); + geHC(genHC); + geChiC2(genChiC2); + geEtaC2S(genEtaC2S); + gePsi2S(genPsi2S); + } + + PROCESS_SWITCH(generatedQuarkoniaMC, processReconstructedSimulation, "Produce reco-ed simulated information", true); + PROCESS_SWITCH(generatedQuarkoniaMC, processBinnedGenerated, "Produce binned generated information", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} + +//__________________________________________________ +// do not over-populate general namespace, keep scope generatedQuarkoniaMC:: +const std::vector generatedQuarkoniaMC::particleNames{"EtaC1S", "JPsi", "ChiC0", "ChiC1", + "hC", "ChiC2", "EtaC2S", "Psi2S"}; +const std::vector generatedQuarkoniaMC::particlePDGCodes{441, 443, 10441, 20443, 10443, 445, 100441, 100443}; +const std::vector generatedQuarkoniaMC::parameterNames{"Enable"}; + +const int generatedQuarkoniaMC::defaultParameters[generatedQuarkoniaMC::nSpecies][generatedQuarkoniaMC::nParameters] = {{1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}}; diff --git a/PWGDQ/TableProducer/tableMaker.cxx b/PWGDQ/TableProducer/tableMaker.cxx index 10f555f5a02..74545704593 100644 --- a/PWGDQ/TableProducer/tableMaker.cxx +++ b/PWGDQ/TableProducer/tableMaker.cxx @@ -17,7 +17,13 @@ // The skimming can optionally produce just the barrel, muon, or both barrel and muon tracks // The event filtering (filterPP), centrality, and V0Bits (from v0-selector) can be switched on/off by selecting one // of the process functions +// C++ includes #include +#include +#include +#include +#include +// other includes #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" @@ -31,6 +37,7 @@ #include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/MftmchMatchingML.h" +#include "Common/DataModel/FwdTrackReAlignTables.h" #include "PWGDQ/DataModel/ReducedInfoTables.h" #include "PWGDQ/Core/VarManager.h" #include "PWGDQ/Core/HistogramManager.h" @@ -55,6 +62,7 @@ #include "TGeoGlobalMagField.h" #include "DetectorsBase/Propagator.h" #include "DetectorsBase/GeometryManager.h" +#include "EventFiltering/Zorro.h" using std::cout; using std::endl; @@ -64,6 +72,8 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::aod; +Zorro zorro; + using MyBarrelTracks = soa::Join; +using MyBarrelTracksWithCovOnlyStdPID = soa::Join; using MyBarrelTracksWithV0Bits = soa::Join; +using MyBarrelTracksForElectronMuon = soa::Join; using MyEvents = soa::Join; -using MyEventsWithMults = soa::Join; +using MyEventsWithMults = soa::Join; using MyEventsWithFilter = soa::Join; -using MyEventsWithMultsAndFilter = soa::Join; +using MyEventsWithMultsAndFilter = soa::Join; using MyEventsWithCent = soa::Join; -using MyEventsWithCentAndMults = soa::Join; +using MyEventsWithCentAndMults = soa::Join; using MyMuons = soa::Join; using MyMuonsWithCov = soa::Join; using MyMuonsColl = soa::Join; using MyMuonsCollWithCov = soa::Join; +using MyMuonsRealignWithCov = soa::Join; using ExtBCs = soa::Join; -namespace o2::aod -{ -DECLARE_SOA_TABLE(AmbiguousTracksMid, "AOD", "AMBIGUOUSTRACK", //! Table for tracks which are not uniquely associated with a collision - o2::soa::Index<>, o2::aod::ambiguous::TrackId, o2::aod::ambiguous::BCIdSlice, o2::soa::Marker<2>); -DECLARE_SOA_TABLE(AmbiguousTracksFwd, "AOD", "AMBIGUOUSFWDTR", //! Table for Fwd tracks which are not uniquely associated with a collision - o2::soa::Index<>, o2::aod::ambiguous::FwdTrackId, o2::aod::ambiguous::BCIdSlice, o2::soa::Marker<2>); -} // namespace o2::aod - constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision; -constexpr static uint32_t gkEventFillMapWithMult = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionMult; -constexpr static uint32_t gkEventFillMapWithMultsAndEventFilter = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionMult | VarManager::ObjTypes::EventFilter; +constexpr static uint32_t gkEventFillMapWithMult = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionMult | VarManager::ObjTypes::CollisionMultExtra; +constexpr static uint32_t gkEventFillMapWithMultsAndEventFilter = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionMult | VarManager::ObjTypes::CollisionMultExtra | VarManager::ObjTypes::EventFilter; constexpr static uint32_t gkEventFillMapWithCent = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCent; -constexpr static uint32_t gkEventFillMapWithCentAndMults = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCent | VarManager::CollisionMult; +constexpr static uint32_t gkEventFillMapWithCentAndMults = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCent | VarManager::CollisionMult | VarManager::ObjTypes::CollisionMultExtra; // constexpr static uint32_t gkEventFillMapWithCentRun2 = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCentRun2; // Unused variable constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackPID | VarManager::ObjTypes::TrackPIDExtra; constexpr static uint32_t gkTrackFillMapWithCov = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackCov | VarManager::ObjTypes::TrackPID | VarManager::ObjTypes::TrackPIDExtra; +constexpr static uint32_t gkTrackFillMapWithCovOnlyStdPID = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackCov | VarManager::ObjTypes::TrackPID; constexpr static uint32_t gkTrackFillMapWithV0Bits = gkTrackFillMap | VarManager::ObjTypes::TrackV0Bits; constexpr static uint32_t gkTrackFillMapWithV0BitsForMaps = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackV0Bits | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackTPCPID; constexpr static uint32_t gkTrackFillMapWithDalitzBits = gkTrackFillMap | VarManager::ObjTypes::DalitzBits; constexpr static uint32_t gkTrackFillMapWithV0AndDalitzBits = gkTrackFillMap | VarManager::ObjTypes::TrackV0Bits | VarManager::ObjTypes::DalitzBits; +constexpr static uint32_t gkTrackFillMapForElectronMuon = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackTPCPID; constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::Muon; constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::Muon | VarManager::ObjTypes::MuonCov; -constexpr static uint32_t gkMuonFillMapWithAmbi = VarManager::ObjTypes::Muon | VarManager::ObjTypes::AmbiMuon; constexpr static uint32_t gkMuonFillMapWithCovAmbi = VarManager::ObjTypes::Muon | VarManager::ObjTypes::MuonCov | VarManager::ObjTypes::AmbiMuon; +constexpr static uint32_t gkMuonRealignFillMapWithCov = VarManager::ObjTypes::MuonRealign | VarManager::ObjTypes::MuonCovRealign; constexpr static uint32_t gkTrackFillMapWithAmbi = VarManager::ObjTypes::Track | VarManager::ObjTypes::AmbiTrack; constexpr static uint32_t gkMFTFillMap = VarManager::ObjTypes::TrackMFT; @@ -136,11 +148,14 @@ struct TableMaker { Produces event; Produces eventExtended; Produces eventVtxCov; + Produces eventInfo; + Produces multPV; + Produces multAll; + Produces trackBarrelInfo; Produces trackBasic; Produces trackBarrel; Produces trackBarrelCov; Produces trackBarrelPID; - Produces trackBarrelInfo; Produces muonBasic; Produces muonExtra; Produces muonCov; @@ -152,23 +167,41 @@ struct TableMaker { OutputObj fStatsList{"Statistics"}; //! skimming statistics HistogramManager* fHistMan; - Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; - Configurable fConfigTrackCuts{"cfgBarrelTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; - Configurable fConfigMuonCuts{"cfgMuonCuts", "muonQualityCuts", "Comma separated list of muon cuts"}; - Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddMuonHistogram{"cfgAddMuonHistogram", "", "Comma separated list of histograms"}; + struct : ConfigurableGroup { + Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; + Configurable fConfigTrackCuts{"cfgBarrelTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; + Configurable fConfigMuonCuts{"cfgMuonCuts", "muonQualityCuts", "Comma separated list of muon cuts"}; + } configCuts; + struct : ConfigurableGroup { + Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddMuonHistogram{"cfgAddMuonHistogram", "", "Comma separated list of histograms"}; + } addHistoConfigurations; Configurable fConfigBarrelTrackPtLow{"cfgBarrelLowPt", 1.0f, "Low pt cut for tracks in the barrel"}; Configurable fConfigBarrelTrackMaxAbsEta{"cfgBarrelMaxAbsEta", 0.9f, "Eta absolute value cut for tracks in the barrel"}; Configurable fConfigMuonPtLow{"cfgMuonLowPt", 1.0f, "Low pt cut for muons"}; - Configurable fConfigMinTpcSignal{"cfgMinTpcSignal", 30.0, "Minimum TPC signal"}; - Configurable fConfigMaxTpcSignal{"cfgMaxTpcSignal", 300.0, "Maximum TPC signal"}; + struct : ConfigurableGroup { + Configurable fConfigMinTpcSignal{"cfgMinTpcSignal", 30.0, "Minimum TPC signal"}; + Configurable fConfigMaxTpcSignal{"cfgMaxTpcSignal", 300.0, "Maximum TPC signal"}; + } configTpcSignal; Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; Configurable fConfigDetailedQA{"cfgDetailedQA", false, "If true, include more QA histograms (BeforeCuts classes)"}; Configurable fIsRun2{"cfgIsRun2", false, "Whether we analyze Run-2 or Run-3 data"}; Configurable fIsAmbiguous{"cfgIsAmbiguous", false, "Whether we enable QA plots for ambiguous tracks"}; - Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable fConfigCcdbPathTPC{"ccdb-path-tpc", "Users/z/zhxiong/TPCPID/PostCalib", "base path to the ccdb object"}; + + struct : ConfigurableGroup { + Configurable fConfigRunZorro{"cfgRunZorro", false, "Enable event selection with zorro"}; + Configurable fConfigZorroTrigMask{"cfgZorroTriggerMask", "fDiMuon", "DQ Trigger masks: fSingleE,fLMeeIMR,fLMeeHMR,fDiElectron,fSingleMuLow,fSingleMuHigh,fDiMuon"}; + Configurable fConfigRunZorroSel{"cfgRunZorroSel", false, "Select events with trigger mask"}; + Configurable fBcTolerance{"cfgBcTolerance", 100, "Number of BCs of margin for software triggers"}; + } useZorro; + + struct : ConfigurableGroup { + Configurable fConfigCcdbUrl{"useCCDBConfigurations.ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable fConfigCcdbPathTPC{"useCCDBConfigurations.ccdb-path-tpc", "Users/z/zhxiong/TPCPID/PostCalib", "base path to the ccdb object"}; + Configurable fConfigCcdbPathZorro{"useCCDBConfigurations.ccdb-path-zorro", "/Users/m/mpuccio/EventFiltering/OTS/", "base path to the ccdb object for zorro"}; + } useCCDBConfigurations; + Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; Configurable fConfigComputeTPCpostCalib{"cfgTPCpostCalib", false, "If true, compute TPC post-calibrated n-sigmas(electrons, pions, protons)"}; Configurable fConfigComputeTPCpostCalibKaon{"cfgTPCpostCalibKaon", false, "If true, compute TPC post-calibrated n-sigmas for kaons"}; @@ -179,11 +212,16 @@ struct TableMaker { Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; Configurable grpmagPathRun2{"grpmagPathRun2", "GLO/GRP/GRP", "CCDB path of the GRPObject (Usage for Run 2)"}; + struct : ConfigurableGroup { + Configurable useMatCorrType{"useMatConfigurations.useMatCorrType", 1, "materialCorrType: 0: none, 1: TGeo, 2: LUT"}; + Configurable lutPath{"useMatConfigurations.lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + } useMatConfigurations; Service fCCDB; o2::parameters::GRPObject* grpmagrun2 = nullptr; // for run 2, we access the GRPObject from GLO/GRP/GRP o2::parameters::GRPMagField* grpmag = nullptr; // for run 3, we access GRPMagField from GLO/Config/GRPMagField + o2::base::MatLayerCylSet* lut = nullptr; AnalysisCompositeCut* fEventCut; //! Event selection cut std::vector fTrackCuts; //! Barrel track cuts @@ -191,25 +229,34 @@ struct TableMaker { Preslice perCollisionTracks = aod::track::collisionId; Preslice perCollisionMuons = aod::fwdtrack::collisionId; + PresliceUnsorted perCollisionMuonsRealign = aod::fwdtrackrealign::collisionId; Preslice trackIndicesPerCollision = aod::track_association::collisionId; Preslice fwdtrackIndicesPerCollision = aod::track_association::collisionId; - + PresliceUnsorted fwdtrackRealignPerMuon = aod::fwdtrackrealign::fwdtrackId; bool fDoDetailedQA = false; // Bool to set detailed QA true, if QA is set true int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. // TODO: filter on TPC dedx used temporarily until electron PID will be improved - Filter barrelSelectedTracks = ifnode(fIsRun2.node() == true, aod::track::trackType == uint8_t(aod::track::Run2Track), aod::track::trackType == uint8_t(aod::track::Track)) && o2::aod::track::pt >= fConfigBarrelTrackPtLow && nabs(o2::aod::track::eta) <= fConfigBarrelTrackMaxAbsEta && o2::aod::track::tpcSignal >= fConfigMinTpcSignal && o2::aod::track::tpcSignal <= fConfigMaxTpcSignal && o2::aod::track::tpcChi2NCl < 4.0f && o2::aod::track::itsChi2NCl < 36.0f; + Filter barrelSelectedTracks = ifnode(fIsRun2.node() == true, aod::track::trackType == uint8_t(aod::track::Run2Track), aod::track::trackType == uint8_t(aod::track::Track)) && o2::aod::track::pt >= fConfigBarrelTrackPtLow && nabs(o2::aod::track::eta) <= fConfigBarrelTrackMaxAbsEta && o2::aod::track::tpcSignal >= configTpcSignal.fConfigMinTpcSignal && o2::aod::track::tpcSignal <= configTpcSignal.fConfigMaxTpcSignal && o2::aod::track::tpcChi2NCl < 4.0f && o2::aod::track::itsChi2NCl < 36.0f; Filter muonFilter = o2::aod::fwdtrack::pt >= fConfigMuonPtLow; void init(o2::framework::InitContext& context) { DefineCuts(); - fCCDB->setURL(fConfigCcdbUrl); + fCCDB->setURL(useCCDBConfigurations.fConfigCcdbUrl); fCCDB->setCaching(true); fCCDB->setLocalObjectValidityChecking(); - if (!o2::base::GeometryManager::isGeometryLoaded()) { - fCCDB->get(geoPath); + if (useMatConfigurations.useMatCorrType == 1) { + LOGF(info, "TGeo correction requested, loading geometry"); + if (!o2::base::GeometryManager::isGeometryLoaded()) { + fCCDB->get(geoPath); + } + } + if (useMatConfigurations.useMatCorrType == 2) { + LOGF(info, "LUT correction requested, loading LUT"); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(fCCDB->get(useMatConfigurations.lutPath)); + LOGF(info, "LUT load done!"); } VarManager::SetDefaultVarNames(); fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); @@ -234,20 +281,16 @@ struct TableMaker { context.mOptions.get("processFullWithCovMultsAndEventFilter") || context.mOptions.get("processBarrelOnly") || context.mOptions.get("processBarrelOnlyWithCent") || context.mOptions.get("processBarrelOnlyWithCovWithCent") || context.mOptions.get("processBarrelOnlyWithMults") || context.mOptions.get("processBarrelOnlyWithCentAndMults") || context.mOptions.get("processBarrelOnlyWithCovWithCentAndMults") || - context.mOptions.get("processBarrelOnlyWithCov") || context.mOptions.get("processBarrelOnlyWithEventFilter") || + context.mOptions.get("processBarrelOnlyWithCov") || context.mOptions.get("processBarrelOnlyWithCovOnlyStdPID") || context.mOptions.get("processBarrelOnlyWithEventFilter") || context.mOptions.get("processBarrelOnlyWithMultsAndEventFilter") || context.mOptions.get("processBarrelOnlyWithCovAndEventFilter") || context.mOptions.get("processBarrelOnlyWithDalitzBits") || context.mOptions.get("processBarrelOnlyWithV0Bits") || context.mOptions.get("processBarrelWithDalitzEvent") || context.mOptions.get("processBarrelOnlyWithV0BitsAndMaps") || context.mOptions.get("processAmbiguousBarrelOnly")) || - context.mOptions.get("processBarrelWithV0AndDalitzEvent"); + context.mOptions.get("processBarrelWithV0AndDalitzEvent") || context.mOptions.get("processBarrelOnlyWithV0BitsAndMults"); bool enableMuonHistos = (context.mOptions.get("processFull") || context.mOptions.get("processFullWithCov") || context.mOptions.get("processFullWithCent") || context.mOptions.get("processFullWithCovAndEventFilter") || - context.mOptions.get("processFullWithCovMultsAndEventFilter") || - context.mOptions.get("processMuonOnly") || context.mOptions.get("processMuonOnlyWithCent") || - context.mOptions.get("processMuonOnlyWithMults") || context.mOptions.get("processMuonOnlyWithCentAndMults") || - context.mOptions.get("processMuonOnlyWithCovAndCent") || - context.mOptions.get("processMuonOnlyWithCov") || context.mOptions.get("processMuonOnlyWithCovAndEventFilter") || context.mOptions.get("processMuonOnlyWithEventFilter") || - context.mOptions.get("processMuonOnlyWithMultsAndEventFilter") || context.mOptions.get("processAmbiguousMuonOnlyWithCov") || context.mOptions.get("processAmbiguousMuonOnly") || - context.mOptions.get("processMuonsAndMFT") || context.mOptions.get("processMuonsAndMFTWithFilter") || context.mOptions.get("processMuonMLOnly")); + context.mOptions.get("processFullWithCovMultsAndEventFilter") || context.mOptions.get("processMuonOnlyWithCovAndCentMults") || + context.mOptions.get("processMuonOnlyWithCov") || context.mOptions.get("processMuonOnlyWithCovAndEventFilter") || context.mOptions.get("processAmbiguousMuonOnlyWithCov") || + context.mOptions.get("processMuonsAndMFT") || context.mOptions.get("processMuonsAndMFTWithFilter") || context.mOptions.get("processMuonMLOnly") || context.mOptions.get("processAssociatedMuonOnlyWithCov") || context.mOptions.get("processAssociatedRealignedMuonOnlyWithCov")); if (enableBarrelHistos) { if (fDoDetailedQA) { @@ -300,7 +343,7 @@ struct TableMaker { fOutputList.setObject(fHistMan->GetMainHistogramList()); // CCDB configuration if (fConfigComputeTPCpostCalib) { - fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setURL(useCCDBConfigurations.fConfigCcdbUrl.value); fCCDB->setCaching(true); fCCDB->setLocalObjectValidityChecking(); // Not later than now objects @@ -312,11 +355,11 @@ struct TableMaker { { // Event cuts fEventCut = new AnalysisCompositeCut(true); - TString eventCutStr = fConfigEventCuts.value; + TString eventCutStr = configCuts.fConfigEventCuts.value; fEventCut->AddCut(dqcuts::GetAnalysisCut(eventCutStr.Data())); // Barrel track cuts - TString cutNamesStr = fConfigTrackCuts.value; + TString cutNamesStr = configCuts.fConfigTrackCuts.value; if (!cutNamesStr.IsNull()) { std::unique_ptr objArray(cutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { @@ -325,7 +368,7 @@ struct TableMaker { } // Muon cuts - cutNamesStr = fConfigMuonCuts.value; + cutNamesStr = configCuts.fConfigMuonCuts.value; if (!cutNamesStr.IsNull()) { std::unique_ptr objArray(cutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { @@ -343,7 +386,7 @@ struct TableMaker { auto bc = collision.template bc_as(); if (fCurrentRun != bc.runNumber()) { if (fConfigComputeTPCpostCalib) { - auto calibList = fCCDB->getForTimeStamp(fConfigCcdbPathTPC.value, bc.timestamp()); + auto calibList = fCCDB->getForTimeStamp(useCCDBConfigurations.fConfigCcdbPathTPC.value, bc.timestamp()); VarManager::SetCalibrationObject(VarManager::kTPCElectronMean, calibList->FindObject("mean_map_electron")); VarManager::SetCalibrationObject(VarManager::kTPCElectronSigma, calibList->FindObject("sigma_map_electron")); VarManager::SetCalibrationObject(VarManager::kTPCPionMean, calibList->FindObject("mean_map_pion")); @@ -368,6 +411,11 @@ struct TableMaker { if (fPropMuon) { VarManager::SetupMuonMagField(); } + if (useMatConfigurations.useMatCorrType == 2) { + // setMatLUT only after magfield has been initalized + // (setMatLUT has implicit and problematic init field call if not) + o2::base::Propagator::Instance()->setMatLUT(lut); + } } fCurrentRun = bc.runNumber(); } @@ -378,11 +426,13 @@ struct TableMaker { // if the BC found by event selection does not coincide with the collision.bc() auto bcEvSel = collision.template foundBC_as(); if (bcEvSel.globalIndex() != bc.globalIndex()) { - tag |= (uint64_t(1) << 0); + tag |= (static_cast(1) << 0); } // Put the 8 first bits of the event filter in the last 8 bits of the tag if constexpr ((TEventFillMap & VarManager::ObjTypes::EventFilter) > 0) { - tag |= (collision.eventFilter() << 56); + if (!useZorro.fConfigRunZorro) { + tag |= (collision.eventFilter() << 56); + } } VarManager::ResetValues(0, VarManager::kNEventWiseVariables); @@ -400,23 +450,37 @@ struct TableMaker { uint32_t triggerAliases = collision.alias_raw(); // fill stats information, before selections for (int i = 0; i < kNaliases; i++) { - if (triggerAliases & (uint32_t(1) << i)) { - (reinterpret_cast(fStatsList->At(0)))->Fill(2.0, static_cast(i)); + if (triggerAliases & (static_cast(1) << i)) { + (reinterpret_cast(fStatsList->At(0)))->Fill(2.0, static_cast(i)); } } - (reinterpret_cast(fStatsList->At(0)))->Fill(2.0, static_cast(kNaliases)); - - if (!fEventCut->IsSelected(VarManager::fgValues)) { - return; + (reinterpret_cast(fStatsList->At(0)))->Fill(2.0, static_cast(kNaliases)); + + if (useZorro.fConfigRunZorro) { + zorro.setBaseCCDBPath(useCCDBConfigurations.fConfigCcdbPathZorro.value); + zorro.setBCtolerance(useZorro.fBcTolerance); + zorro.initCCDB(fCCDB.service, fCurrentRun, bc.timestamp(), useZorro.fConfigZorroTrigMask.value); + zorro.populateExternalHists(fCurrentRun, reinterpret_cast(fStatsList->At(3)), reinterpret_cast(fStatsList->At(4))); + bool zorroSel = zorro.isSelected(bc.globalBC(), useZorro.fBcTolerance, reinterpret_cast(fStatsList->At(4))); + if (zorroSel) { + tag |= (static_cast(true) << 56); // the same bit is used for this zorro selections from ccdb + } + if (useZorro.fConfigRunZorroSel && (!zorroSel || !fEventCut->IsSelected(VarManager::fgValues))) { + return; + } + } else { + if (!fEventCut->IsSelected(VarManager::fgValues)) { + return; + } } // fill stats information, after selections for (int i = 0; i < kNaliases; i++) { - if (triggerAliases & (uint32_t(1) << i)) { - (reinterpret_cast(fStatsList->At(0)))->Fill(3.0, static_cast(i)); + if (triggerAliases & (static_cast(1) << i)) { + (reinterpret_cast(fStatsList->At(0)))->Fill(3.0, static_cast(i)); } } - (reinterpret_cast(fStatsList->At(0)))->Fill(3.0, static_cast(kNaliases)); + (reinterpret_cast(fStatsList->At(0)))->Fill(3.0, static_cast(kNaliases)); fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); @@ -439,15 +503,23 @@ struct TableMaker { eventExtended(bc.globalBC(), collision.alias_raw(), collision.selection_raw(), bc.timestamp(), VarManager::fgValues[VarManager::kCentVZERO], -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); } eventVtxCov(collision.covXX(), collision.covXY(), collision.covXZ(), collision.covYY(), collision.covYZ(), collision.covZZ(), collision.chi2()); + eventInfo(collision.globalIndex()); + if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionMultExtra) > 0) { + multPV(collision.multNTracksHasITS(), collision.multNTracksHasTPC(), collision.multNTracksHasTOF(), collision.multNTracksHasTRD(), + collision.multNTracksITSOnly(), collision.multNTracksTPCOnly(), collision.multNTracksITSTPC(), + collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + multAll(collision.multAllTracksTPCOnly(), collision.multAllTracksITSTPC(), + 0, 0, 0.0, 0.0, 0.0, 0.0, 0, 0, 0.0, 0.0, 0.0, 0.0); + } uint64_t trackFilteringTag = 0; uint8_t fwdFilteringTag = 0; uint8_t trackTempFilterMap = 0; int isAmbiguous = 0; if constexpr (static_cast(TTrackFillMap)) { + trackBarrelInfo.reserve(tracksBarrel.size()); trackBasic.reserve(tracksBarrel.size()); trackBarrel.reserve(tracksBarrel.size()); - trackBarrelInfo.reserve(tracksBarrel.size()); if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackCov)) { trackBarrelCov.reserve(tracksBarrel.size()); } @@ -467,7 +539,7 @@ struct TableMaker { } } - trackFilteringTag = uint64_t(0); + trackFilteringTag = static_cast(0); trackTempFilterMap = uint8_t(0); VarManager::FillTrack(track); if (fDoDetailedQA) { @@ -488,7 +560,7 @@ struct TableMaker { fHistMan->FillHistClass(Form("Ambiguous_TrackBarrel_%s", (*cut).GetName()), VarManager::fgValues); } } - (reinterpret_cast(fStatsList->At(1)))->Fill(static_cast(i)); + (reinterpret_cast(fStatsList->At(1)))->Fill(static_cast(i)); } } if (!trackTempFilterMap) { @@ -503,39 +575,40 @@ struct TableMaker { trackFilteringTag |= (uint64_t(1) << 1); // BIT1: global track SSD }*/ if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackV0Bits)) { // BIT0-4: V0Bits - trackFilteringTag = uint64_t(track.pidbit()); + trackFilteringTag = static_cast(track.pidbit()); for (int iv0 = 0; iv0 < 5; iv0++) { if (track.pidbit() & (uint8_t(1) << iv0)) { - (reinterpret_cast(fStatsList->At(1)))->Fill(fTrackCuts.size() + static_cast(iv0)); + (reinterpret_cast(fStatsList->At(1)))->Fill(fTrackCuts.size() + static_cast(iv0)); } } if (fConfigIsOnlyforMaps) { - if (trackFilteringTag & (uint64_t(1) << VarManager::kIsConversionLeg)) { // for electron + if (trackFilteringTag & (static_cast(1) << VarManager::kIsConversionLeg)) { // for electron fHistMan->FillHistClass("TrackBarrel_PostCalibElectron", VarManager::fgValues); } - if (trackFilteringTag & (uint64_t(1) << VarManager::kIsK0sLeg)) { // for pion + if (trackFilteringTag & (static_cast(1) << VarManager::kIsK0sLeg)) { // for pion fHistMan->FillHistClass("TrackBarrel_PostCalibPion", VarManager::fgValues); } - if ((static_cast(trackFilteringTag & (uint64_t(1) << VarManager::kIsLambdaLeg)) * (track.sign()) > 0)) { // for proton from Lambda + if ((static_cast(trackFilteringTag & (static_cast(1) << VarManager::kIsLambdaLeg)) * (track.sign()) > 0)) { // for proton from Lambda fHistMan->FillHistClass("TrackBarrel_PostCalibProton", VarManager::fgValues); } - if ((static_cast(trackFilteringTag & (uint64_t(1) << VarManager::kIsALambdaLeg)) * (track.sign()) < 0)) { // for proton from AntiLambda + if ((static_cast(trackFilteringTag & (static_cast(1) << VarManager::kIsALambdaLeg)) * (track.sign()) < 0)) { // for proton from AntiLambda fHistMan->FillHistClass("TrackBarrel_PostCalibProton", VarManager::fgValues); } } } if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::DalitzBits)) { - trackFilteringTag |= (uint64_t(track.dalitzBits()) << VarManager::kDalitzBits); // BIT5-12: Dalitz selection bits + trackFilteringTag |= (static_cast(track.dalitzBits()) << VarManager::kDalitzBits); // BIT5-12: Dalitz selection bits } - trackFilteringTag |= (uint64_t(trackTempFilterMap) << VarManager::kBarrelUserCutsBits); // BIT13-20...: user track filters + trackFilteringTag |= (static_cast(trackTempFilterMap) << VarManager::kBarrelUserCutsBits); // BIT13-20...: user track filters if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackPID)) { if (fConfigComputeTPCpostCalib) { - trackFilteringTag |= (uint64_t(1) << VarManager::kIsTPCPostcalibrated); // store the info on whether TPC pid is skimmed as postcalibrated + trackFilteringTag |= (static_cast(1) << VarManager::kIsTPCPostcalibrated); // store the info on whether TPC pid is skimmed as postcalibrated } } // create the track tables + trackBarrelInfo(track.collisionId(), collision.posX(), collision.posY(), collision.posZ(), track.globalIndex()); trackBasic(event.lastIndex(), trackFilteringTag, track.pt(), track.eta(), track.phi(), track.sign(), isAmbiguous); trackBarrel(track.x(), track.alpha(), track.y(), track.z(), track.snp(), track.tgl(), track.signed1Pt(), track.tpcInnerParam(), track.flags(), track.itsClusterMap(), track.itsChi2NCl(), @@ -545,7 +618,6 @@ struct TableMaker { track.length(), track.dcaXY(), track.dcaZ(), track.trackTime(), track.trackTimeRes(), track.tofExpMom(), track.detectorMap()); - trackBarrelInfo(track.collisionId(), collision.posX(), collision.posY(), collision.posZ()); if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackCov)) { trackBarrelCov(track.cYY(), track.cZY(), track.cZZ(), track.cSnpY(), track.cSnpZ(), track.cSnpSnp(), track.cTglY(), track.cTglZ(), track.cTglSnp(), track.cTglTgl(), @@ -557,11 +629,23 @@ struct TableMaker { float nSigmaPi = (fConfigComputeTPCpostCalib ? VarManager::fgValues[VarManager::kTPCnSigmaPi_Corr] : track.tpcNSigmaPi()); float nSigmaKa = ((fConfigComputeTPCpostCalib && fConfigComputeTPCpostCalibKaon) ? VarManager::fgValues[VarManager::kTPCnSigmaKa_Corr] : track.tpcNSigmaKa()); float nSigmaPr = (fConfigComputeTPCpostCalib ? VarManager::fgValues[VarManager::kTPCnSigmaPr_Corr] : track.tpcNSigmaPr()); - trackBarrelPID(track.tpcSignal(), - nSigmaEl, track.tpcNSigmaMu(), nSigmaPi, nSigmaKa, nSigmaPr, - track.beta(), - track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), - track.trdSignal()); + if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackPIDExtra)) { + trackBarrelPID(track.tpcSignal(), + nSigmaEl, track.tpcNSigmaMu(), nSigmaPi, nSigmaKa, nSigmaPr, + track.beta(), + track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), + track.trdSignal()); + } else { + trackBarrelPID(track.tpcSignal(), + nSigmaEl, -1, nSigmaPi, nSigmaKa, nSigmaPr, + -1, + track.tofNSigmaEl(), -1, track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), + -1); + } + } + if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackTPCPID)) { + trackBarrelPID(track.tpcSignal(), track.tpcNSigmaEl(), -1, track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), + -1, -1, -1, -1, -1, -1, -1); } } } // end if constexpr (TTrackFillMap) @@ -622,7 +706,7 @@ struct TableMaker { std::map newMFTMatchIndex; for (auto& muon : tracksMuon) { - fwdFilteringTag = uint64_t(0); + fwdFilteringTag = static_cast(0); VarManager::FillTrack(muon); if (fPropMuon) { VarManager::FillPropagateMuon(muon, collision); @@ -666,12 +750,7 @@ struct TableMaker { VarManager::FillTrack(muon); // recalculte pDca for global muon tracks - if (static_cast(muon.trackType()) < 2) { - auto const& matchMCH = muon.template matchMCHTrack_as(); - VarManager::FillMuonPDca(matchMCH, collision); - } else if (static_cast(muon.trackType()) > 2) { - VarManager::FillMuonPDca(muon, collision); - } + VarManager::FillTrackCollision(muon, collision); if (fPropMuon) { VarManager::FillPropagateMuon(muon, collision); @@ -693,7 +772,7 @@ struct TableMaker { fHistMan->FillHistClass(Form("Ambiguous_Muons_%s", (*cut).GetName()), VarManager::fgValues); } } - (reinterpret_cast(fStatsList->At(2)))->Fill(static_cast(i)); + (reinterpret_cast(fStatsList->At(2)))->Fill(static_cast(i)); } } if (!trackTempFilterMap) { @@ -749,6 +828,12 @@ struct TableMaker { muon.matchScoreMCHMFT(), muon.mchBitMap(), muon.midBitMap(), muon.midBoards(), muon.trackType(), VarManager::fgValues[VarManager::kMuonDCAx], VarManager::fgValues[VarManager::kMuonDCAy], muon.trackTime(), muon.trackTimeRes()); + } else { + muonExtra(muon.nClusters(), muon.pDca(), muon.rAtAbsorberEnd(), + muon.chi2(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), + muon.matchScoreMCHMFT(), muon.mchBitMap(), muon.midBitMap(), + muon.midBoards(), muon.trackType(), muon.fwdDcaX(), muon.fwdDcaY(), + muon.trackTime(), muon.trackTimeRes()); } muonCov(VarManager::fgValues[VarManager::kX], VarManager::fgValues[VarManager::kY], VarManager::fgValues[VarManager::kZ], VarManager::fgValues[VarManager::kPhi], VarManager::fgValues[VarManager::kTgl], muon.sign() / VarManager::fgValues[VarManager::kPt], @@ -764,16 +849,16 @@ struct TableMaker { } } } // end if constexpr (TMuonFillMap) - } // end fullSkimming() + } // end fullSkimming() // Templated function instantianed for all of the process functions - template - void fullSkimmingIndices(TEvent const& collision, aod::BCsWithTimestamps const&, TTracks const& tracksBarrel, TMuons const& tracksMuon, AssocTracks const& trackIndices, AssocMuons const& fwdtrackIndices) + template + void fullSkimmingIndices(TEvent const& collision, aod::BCsWithTimestamps const&, TTracks const& tracksBarrel, TMuons const& tracksMuon, TMuonsRealign const& tracksMuonRealign, AssocTracks const& trackIndices, AssocMuons const& fwdtrackIndices) { auto bc = collision.template bc_as(); if (fCurrentRun != bc.runNumber()) { if (fConfigComputeTPCpostCalib) { - auto calibList = fCCDB->getForTimeStamp(fConfigCcdbPathTPC.value, bc.timestamp()); + auto calibList = fCCDB->getForTimeStamp(useCCDBConfigurations.fConfigCcdbPathTPC.value, bc.timestamp()); VarManager::SetCalibrationObject(VarManager::kTPCElectronMean, calibList->FindObject("mean_map_electron")); VarManager::SetCalibrationObject(VarManager::kTPCElectronSigma, calibList->FindObject("sigma_map_electron")); VarManager::SetCalibrationObject(VarManager::kTPCPionMean, calibList->FindObject("mean_map_pion")); @@ -798,6 +883,11 @@ struct TableMaker { if constexpr (static_cast(TMuonFillMap)) { VarManager::SetupMuonMagField(); } + if (useMatConfigurations.useMatCorrType == 2) { + // setMatLUT only after magfield has been initalized + // (setMatLUT has implicit and problematic init field call if not) + o2::base::Propagator::Instance()->setMatLUT(lut); + } } fCurrentRun = bc.runNumber(); } @@ -810,11 +900,13 @@ struct TableMaker { // if the BC found by event selection does not coincide with the collision.bc() auto bcEvSel = collision.template foundBC_as(); if (bcEvSel.globalIndex() != bc.globalIndex()) { - tag |= (uint64_t(1) << 0); + tag |= (static_cast(1) << 0); } // Put the 8 first bits of the event filter in the last 8 bits of the tag if constexpr ((TEventFillMap & VarManager::ObjTypes::EventFilter) > 0) { - tag |= (collision.eventFilter() << 56); + if (!useZorro.fConfigRunZorro) { + tag |= (collision.eventFilter() << 56); + } } VarManager::ResetValues(0, VarManager::kNEventWiseVariables); @@ -831,23 +923,37 @@ struct TableMaker { // fill stats information, before selections for (int i = 0; i < kNaliases; i++) { - if (triggerAliases & (uint32_t(1) << i)) { - (reinterpret_cast(fStatsList->At(0)))->Fill(2.0, static_cast(i)); + if (triggerAliases & (static_cast(1) << i)) { + (reinterpret_cast(fStatsList->At(0)))->Fill(2.0, static_cast(i)); } } - (reinterpret_cast(fStatsList->At(0)))->Fill(2.0, static_cast(kNaliases)); - - if (!fEventCut->IsSelected(VarManager::fgValues)) { - return; + (reinterpret_cast(fStatsList->At(0)))->Fill(2.0, static_cast(kNaliases)); + + if (useZorro.fConfigRunZorro) { + zorro.setBaseCCDBPath(useCCDBConfigurations.fConfigCcdbPathZorro.value); + zorro.setBCtolerance(useZorro.fBcTolerance); + zorro.initCCDB(fCCDB.service, fCurrentRun, bc.timestamp(), useZorro.fConfigZorroTrigMask.value); + zorro.populateExternalHists(fCurrentRun, reinterpret_cast(fStatsList->At(3)), reinterpret_cast(fStatsList->At(4))); + bool zorroSel = zorro.isSelected(bc.globalBC(), useZorro.fBcTolerance, reinterpret_cast(fStatsList->At(4))); + if (zorroSel) { + tag |= (static_cast(true) << 56); // the same bit is used for this zorro selections from ccdb + } + if (useZorro.fConfigRunZorroSel && (!zorroSel || !fEventCut->IsSelected(VarManager::fgValues))) { + return; + } + } else { + if (!fEventCut->IsSelected(VarManager::fgValues)) { + return; + } } // fill stats information, after selections for (int i = 0; i < kNaliases; i++) { - if (triggerAliases & (uint32_t(1) << i)) { - (reinterpret_cast(fStatsList->At(0)))->Fill(3.0, static_cast(i)); + if (triggerAliases & (static_cast(1) << i)) { + (reinterpret_cast(fStatsList->At(0)))->Fill(3.0, static_cast(i)); } } - (reinterpret_cast(fStatsList->At(0)))->Fill(3.0, static_cast(kNaliases)); + (reinterpret_cast(fStatsList->At(0)))->Fill(3.0, static_cast(kNaliases)); fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); @@ -870,14 +976,22 @@ struct TableMaker { eventExtended(bc.globalBC(), collision.alias_raw(), collision.selection_raw(), bc.timestamp(), VarManager::fgValues[VarManager::kCentVZERO], -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); } eventVtxCov(collision.covXX(), collision.covXY(), collision.covXZ(), collision.covYY(), collision.covYZ(), collision.covZZ(), collision.chi2()); + eventInfo(collision.globalIndex()); + if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionMultExtra) > 0) { + multPV(collision.multNTracksHasITS(), collision.multNTracksHasTPC(), collision.multNTracksHasTOF(), collision.multNTracksHasTRD(), + collision.multNTracksITSOnly(), collision.multNTracksTPCOnly(), collision.multNTracksITSTPC(), + collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + multAll(collision.multAllTracksTPCOnly(), collision.multAllTracksITSTPC(), + 0, 0, 0.0, 0.0, 0.0, 0.0, 0, 0, 0.0, 0.0, 0.0, 0.0); + } uint64_t trackFilteringTag = 0; uint8_t trackTempFilterMap = 0; int isAmbiguous = 0; if constexpr (static_cast(TTrackFillMap)) { + trackBarrelInfo.reserve(tracksBarrel.size()); trackBasic.reserve(tracksBarrel.size()); trackBarrel.reserve(tracksBarrel.size()); - trackBarrelInfo.reserve(tracksBarrel.size()); if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackCov)) { trackBarrelCov.reserve(tracksBarrel.size()); } @@ -891,7 +1005,7 @@ struct TableMaker { isAmbiguous = (track.compatibleCollIds().size() != 1); } } - trackFilteringTag = uint64_t(0); + trackFilteringTag = static_cast(0); trackTempFilterMap = uint8_t(0); VarManager::FillTrack(track); if (fDoDetailedQA) { @@ -912,7 +1026,7 @@ struct TableMaker { fHistMan->FillHistClass(Form("Ambiguous_TrackBarrel_%s", (*cut).GetName()), VarManager::fgValues); } } - (reinterpret_cast(fStatsList->At(1)))->Fill(static_cast(i)); + (reinterpret_cast(fStatsList->At(1)))->Fill(static_cast(i)); } } if (!trackTempFilterMap) { @@ -921,39 +1035,40 @@ struct TableMaker { // store filtering information if (track.isGlobalTrack()) { - trackFilteringTag |= (uint64_t(1) << 0); // BIT0: global track + trackFilteringTag |= (static_cast(1) << 0); // BIT0: global track } if (track.isGlobalTrackSDD()) { - trackFilteringTag |= (uint64_t(1) << 1); // BIT1: global track SSD + trackFilteringTag |= (static_cast(1) << 1); // BIT1: global track SSD } if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackV0Bits)) { // BIT2-6: V0Bits - trackFilteringTag |= (uint64_t(track.pidbit()) << 2); + trackFilteringTag |= (static_cast(track.pidbit()) << 2); for (int iv0 = 0; iv0 < 5; iv0++) { if (track.pidbit() & (uint8_t(1) << iv0)) { - (reinterpret_cast(fStatsList->At(1)))->Fill(fTrackCuts.size() + static_cast(iv0)); + (reinterpret_cast(fStatsList->At(1)))->Fill(fTrackCuts.size() + static_cast(iv0)); } } if (fConfigIsOnlyforMaps) { - if (trackFilteringTag & (uint64_t(1) << 2)) { // for electron + if (trackFilteringTag & (static_cast(1) << 2)) { // for electron fHistMan->FillHistClass("TrackBarrel_PostCalibElectron", VarManager::fgValues); } - if (trackFilteringTag & (uint64_t(1) << 3)) { // for pion + if (trackFilteringTag & (static_cast(1) << 3)) { // for pion fHistMan->FillHistClass("TrackBarrel_PostCalibPion", VarManager::fgValues); } - if ((static_cast(trackFilteringTag & (uint64_t(1) << 4)) * (track.sign()) > 0)) { // for proton from Lambda + if ((static_cast(trackFilteringTag & (static_cast(1) << 4)) * (track.sign()) > 0)) { // for proton from Lambda fHistMan->FillHistClass("TrackBarrel_PostCalibProton", VarManager::fgValues); } - if ((static_cast(trackFilteringTag & (uint64_t(1) << 5)) * (track.sign()) < 0)) { // for proton from AntiLambda + if ((static_cast(trackFilteringTag & (static_cast(1) << 5)) * (track.sign()) < 0)) { // for proton from AntiLambda fHistMan->FillHistClass("TrackBarrel_PostCalibProton", VarManager::fgValues); } } } if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::DalitzBits)) { - trackFilteringTag |= (uint64_t(track.dalitzBits()) << 7); // BIT7-14: Dalitz + trackFilteringTag |= (static_cast(track.dalitzBits()) << 7); // BIT7-14: Dalitz } - trackFilteringTag |= (uint64_t(trackTempFilterMap) << 15); // BIT15-...: user track filters + trackFilteringTag |= (static_cast(trackTempFilterMap) << 15); // BIT15-...: user track filters // create the track tables + trackBarrelInfo(track.collisionId(), collision.posX(), collision.posY(), collision.posZ(), track.globalIndex()); trackBasic(event.lastIndex(), trackFilteringTag, track.pt(), track.eta(), track.phi(), track.sign(), isAmbiguous); trackBarrel(track.tpcInnerParam(), track.flags(), track.itsClusterMap(), track.itsChi2NCl(), track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), @@ -962,7 +1077,6 @@ struct TableMaker { track.length(), track.dcaXY(), track.dcaZ(), track.trackTime(), track.trackTimeRes(), track.tofExpMom(), track.detectorMap()); - trackBarrelInfo(track.collisionId(), collision.posX(), collision.posY(), collision.posZ()); if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackCov)) { trackBarrelCov(track.x(), track.alpha(), track.y(), track.z(), track.snp(), track.tgl(), track.signed1Pt(), track.cYY(), track.cZY(), track.cZZ(), track.cSnpY(), track.cSnpZ(), @@ -974,11 +1088,23 @@ struct TableMaker { float nSigmaEl = (fConfigComputeTPCpostCalib ? VarManager::fgValues[VarManager::kTPCnSigmaEl_Corr] : track.tpcNSigmaEl()); float nSigmaPi = (fConfigComputeTPCpostCalib ? VarManager::fgValues[VarManager::kTPCnSigmaPi_Corr] : track.tpcNSigmaPi()); float nSigmaPr = (fConfigComputeTPCpostCalib ? VarManager::fgValues[VarManager::kTPCnSigmaPr_Corr] : track.tpcNSigmaPr()); - trackBarrelPID(track.tpcSignal(), - nSigmaEl, track.tpcNSigmaMu(), nSigmaPi, track.tpcNSigmaKa(), nSigmaPr, - track.beta(), - track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), - track.trdSignal()); + if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackPIDExtra)) { + trackBarrelPID(track.tpcSignal(), + nSigmaEl, track.tpcNSigmaMu(), nSigmaPi, track.tpcNSigmaKa(), nSigmaPr, + track.beta(), + track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), + track.trdSignal()); + } else { + trackBarrelPID(track.tpcSignal(), + nSigmaEl, -1, nSigmaPi, track.tpcNSigmaKa(), nSigmaPr, + -1, + track.tofNSigmaEl(), -1, track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), + -1); + } + } + if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackTPCPID)) { + trackBarrelPID(track.tpcSignal(), track.tpcNSigmaEl(), -1, track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), + -1, -1, -1, -1, -1, -1, -1); } } } // end if constexpr (TTrackFillMap) @@ -988,7 +1114,7 @@ struct TableMaker { muonBasic.reserve(tracksMuon.size()); muonExtra.reserve(tracksMuon.size()); muonInfo.reserve(tracksMuon.size()); - if constexpr (static_cast(TMuonFillMap & VarManager::ObjTypes::MuonCov)) { + if constexpr (static_cast((TMuonFillMap & VarManager::ObjTypes::MuonCov) || (TMuonRealignFillMap & VarManager::ObjTypes::MuonCovRealign))) { muonCov.reserve(tracksMuon.size()); } // loop over muons @@ -1001,8 +1127,25 @@ struct TableMaker { for (const auto& muonId : fwdtrackIndices) { // start loop over tracks auto muon = muonId.template fwdtrack_as(); - trackFilteringTag = uint64_t(0); - VarManager::FillTrack(muon); + trackFilteringTag = static_cast(0); + if constexpr (static_cast(TMuonRealignFillMap)) { + // Update muon information using realigned tracks + if (static_cast(muon.trackType()) > 2) { + // Update only MCH or MCH-MID tracks with realigned information + auto muonRealignSelected = tracksMuonRealign.sliceBy(fwdtrackRealignPerMuon, muonId.fwdtrackId()); + if (muonRealignSelected.size() == 1) { + for (const auto& muonRealign : muonRealignSelected) { + VarManager::FillTrack(muonRealign); + } + } else { + LOGF(fatal, "Inconsistent size of realigned muon track candidates."); + } + } else { + VarManager::FillTrack(muon); + } + } else { + VarManager::FillTrack(muon); + } if (muon.index() > idxPrev + 1) { // checks if some muons are filtered even before the skimming function nDel += muon.index() - (idxPrev + 1); @@ -1031,21 +1174,51 @@ struct TableMaker { isAmbiguous = (muon.compatibleCollIds().size() != 1); } } - trackFilteringTag = uint64_t(0); + trackFilteringTag = static_cast(0); trackTempFilterMap = uint8_t(0); - VarManager::FillTrack(muon); + if constexpr (static_cast(TMuonRealignFillMap)) { + // Update muon information using realigned tracks + if (static_cast(muon.trackType()) > 2) { + // Update only MCH or MCH-MID tracks with realigned information + auto muonRealignSelected = tracksMuonRealign.sliceBy(fwdtrackRealignPerMuon, muonId.fwdtrackId()); + if (muonRealignSelected.size() == 1) { + for (const auto& muonRealign : muonRealignSelected) { + LOGF(debug, "Muon original - collisionId:%d x:%g y:%g z:%g phi:%g tgl:%g signed1pt:%g pt:%g p:%g eta:%g chi2:%g", muon.collisionId(), muon.x(), muon.y(), muon.z(), muon.phi(), muon.tgl(), muon.signed1Pt(), muon.pt(), muon.p(), muon.eta(), muon.chi2()); + LOGF(debug, "Muon realigned - collisionId:%d x:%g y:%g z:%g phi:%g tgl:%g signed1pt:%g pt:%g p:%g eta:%g chi2:%g", muonRealign.collisionId(), muonRealign.x(), muonRealign.y(), muonRealign.z(), muonRealign.phi(), muonRealign.tgl(), muonRealign.signed1Pt(), muonRealign.pt(), muonRealign.p(), muonRealign.eta(), muonRealign.chi2()); + VarManager::FillTrack(muonRealign); + + // recalculte pDca for global muon tracks + VarManager::FillTrackCollision(muonRealign, collision); + + if (fPropMuon) { + VarManager::FillPropagateMuon(muonRealign, collision); + } + } + } else { + LOGF(fatal, "Inconsistent size of realigned muon track candidates."); + } + } else { + // For global tracks, their matched muon tracks should be updated already - // recalculte pDca for global muon tracks - if (static_cast(muon.trackType()) < 2) { - auto const& matchMCH = tracksMuon.rawIteratorAt(static_cast(muon.matchMCHTrackId())); - VarManager::FillMuonPDca(matchMCH, collision); - } else if (static_cast(muon.trackType()) > 2) { - VarManager::FillMuonPDca(muon, collision); - } + VarManager::FillTrack(muon); - if (fPropMuon) { - VarManager::FillPropagateMuon(muon, collision); + // recalculte pDca for global muon tracks + VarManager::FillTrackCollision(muon, collision); + + if (fPropMuon) { + VarManager::FillPropagateMuon(muon, collision); + } + } + } else { + VarManager::FillTrack(muon); + + // recalculte pDca for global muon tracks + VarManager::FillTrackCollision(muon, collision); + + if (fPropMuon) { + VarManager::FillPropagateMuon(muon, collision); + } } if (fDoDetailedQA) { @@ -1065,7 +1238,7 @@ struct TableMaker { fHistMan->FillHistClass(Form("Ambiguous_Muons_%s", (*cut).GetName()), VarManager::fgValues); } } - (reinterpret_cast(fStatsList->At(2)))->Fill(static_cast(i)); + (reinterpret_cast(fStatsList->At(2)))->Fill(static_cast(i)); } } if (!trackTempFilterMap) { @@ -1100,30 +1273,30 @@ struct TableMaker { muonBasic(event.lastIndex(), newMatchIndex.find(muon.index())->second, -1, trackFilteringTag, VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], muon.sign(), isAmbiguous); muonInfo(muon.collisionId(), collision.posX(), collision.posY(), collision.posZ()); - if constexpr (static_cast(TMuonFillMap & VarManager::ObjTypes::MuonCov)) { + if constexpr (static_cast((TMuonFillMap & VarManager::ObjTypes::MuonCov))) { if (fPropMuon) { muonExtra(muon.nClusters(), VarManager::fgValues[VarManager::kMuonPDca], VarManager::fgValues[VarManager::kMuonRAtAbsorberEnd], - muon.chi2(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), + VarManager::fgValues[VarManager::kMuonChi2], muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), muon.matchScoreMCHMFT(), muon.mchBitMap(), muon.midBitMap(), muon.midBoards(), muon.trackType(), VarManager::fgValues[VarManager::kMuonDCAx], VarManager::fgValues[VarManager::kMuonDCAy], muon.trackTime(), muon.trackTimeRes()); - } else { - muonExtra(muon.nClusters(), muon.pDca(), muon.rAtAbsorberEnd(), - muon.chi2(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), - muon.matchScoreMCHMFT(), muon.mchBitMap(), muon.midBitMap(), - muon.midBoards(), muon.trackType(), muon.fwdDcaX(), muon.fwdDcaY(), - muon.trackTime(), muon.trackTimeRes()); - } + } else { + muonExtra(muon.nClusters(), muon.pDca(), muon.rAtAbsorberEnd(), + VarManager::fgValues[VarManager::kMuonChi2], muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), + muon.matchScoreMCHMFT(), muon.mchBitMap(), muon.midBitMap(), + muon.midBoards(), muon.trackType(), muon.fwdDcaX(), muon.fwdDcaY(), + muon.trackTime(), muon.trackTimeRes()); + } - muonCov(VarManager::fgValues[VarManager::kX], VarManager::fgValues[VarManager::kY], VarManager::fgValues[VarManager::kZ], VarManager::fgValues[VarManager::kPhi], VarManager::fgValues[VarManager::kTgl], muon.sign() / VarManager::fgValues[VarManager::kPt], - VarManager::fgValues[VarManager::kMuonCXX], VarManager::fgValues[VarManager::kMuonCXY], VarManager::fgValues[VarManager::kMuonCYY], VarManager::fgValues[VarManager::kMuonCPhiX], VarManager::fgValues[VarManager::kMuonCPhiY], VarManager::fgValues[VarManager::kMuonCPhiPhi], - VarManager::fgValues[VarManager::kMuonCTglX], VarManager::fgValues[VarManager::kMuonCTglY], VarManager::fgValues[VarManager::kMuonCTglPhi], VarManager::fgValues[VarManager::kMuonCTglTgl], VarManager::fgValues[VarManager::kMuonC1Pt2X], VarManager::fgValues[VarManager::kMuonC1Pt2Y], - VarManager::fgValues[VarManager::kMuonC1Pt2Phi], VarManager::fgValues[VarManager::kMuonC1Pt2Tgl], VarManager::fgValues[VarManager::kMuonC1Pt21Pt2]); + muonCov(VarManager::fgValues[VarManager::kX], VarManager::fgValues[VarManager::kY], VarManager::fgValues[VarManager::kZ], VarManager::fgValues[VarManager::kPhi], VarManager::fgValues[VarManager::kTgl], muon.sign() / VarManager::fgValues[VarManager::kPt], + VarManager::fgValues[VarManager::kMuonCXX], VarManager::fgValues[VarManager::kMuonCXY], VarManager::fgValues[VarManager::kMuonCYY], VarManager::fgValues[VarManager::kMuonCPhiX], VarManager::fgValues[VarManager::kMuonCPhiY], VarManager::fgValues[VarManager::kMuonCPhiPhi], + VarManager::fgValues[VarManager::kMuonCTglX], VarManager::fgValues[VarManager::kMuonCTglY], VarManager::fgValues[VarManager::kMuonCTglPhi], VarManager::fgValues[VarManager::kMuonCTglTgl], VarManager::fgValues[VarManager::kMuonC1Pt2X], VarManager::fgValues[VarManager::kMuonC1Pt2Y], + VarManager::fgValues[VarManager::kMuonC1Pt2Phi], VarManager::fgValues[VarManager::kMuonC1Pt2Tgl], VarManager::fgValues[VarManager::kMuonC1Pt21Pt2]); } } } // end if constexpr (TMuonFillMap) - } // end fullSkimming() + } // end fullSkimming() void DefineHistograms(TString histClasses) { @@ -1147,28 +1320,28 @@ struct TableMaker { } } - TString histEventName = fConfigAddEventHistogram.value; + TString histEventName = addHistoConfigurations.fConfigAddEventHistogram.value; if (classStr.Contains("Event")) { if (fConfigQA) { dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "event", histEventName); } } - TString histTrackName = fConfigAddTrackHistogram.value; + TString histTrackName = addHistoConfigurations.fConfigAddTrackHistogram.value; if (classStr.Contains("Track")) { if (fConfigQA) { dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "track", histTrackName); } } - TString histMuonName = fConfigAddMuonHistogram.value; + TString histMuonName = addHistoConfigurations.fConfigAddMuonHistogram.value; if (classStr.Contains("Muons")) { if (fConfigQA) { dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "track", histMuonName); } } - TString histMftName = fConfigAddMuonHistogram.value; + TString histMftName = addHistoConfigurations.fConfigAddMuonHistogram.value; if (classStr.Contains("Mft")) { if (fConfigDetailedQA) { dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "track", histMftName); @@ -1176,11 +1349,17 @@ struct TableMaker { } } - // create statistics histograms (event, tracks, muons) + // create statistics histograms + // 0: Event statistics + // 1: Track statistics + // 2: Muon statistics + // 3: Zorro information + // 4: Zorro trigger selection + // NOTE: Please keep the order of the histograms in the list fStatsList.setObject(new TList()); fStatsList->SetOwner(kTRUE); std::vector eventLabels{"BCs", "Collisions before filtering", "Before cuts", "After cuts"}; - TH2I* histEvents = new TH2I("EventStats", "Event statistics", eventLabels.size(), -0.5, eventLabels.size() - 0.5, kNaliases + 1, -0.5, +kNaliases + 0.5); + TH2F* histEvents = new TH2F("EventStats", "Event statistics", eventLabels.size(), -0.5, eventLabels.size() - 0.5, kNaliases + 1, -0.5, +kNaliases + 0.5); int ib = 1; for (auto label = eventLabels.begin(); label != eventLabels.end(); label++, ib++) { histEvents->GetXaxis()->SetBinLabel(ib, (*label).Data()); @@ -1189,10 +1368,10 @@ struct TableMaker { histEvents->GetYaxis()->SetBinLabel(ib, aliasLabels[ib - 1].data()); } histEvents->GetYaxis()->SetBinLabel(kNaliases + 1, "Total"); - fStatsList->Add(histEvents); + fStatsList->Add(histEvents); // At index 0 // Track statistics: one bin for each track selection and 5 bins for V0 tags (gamma, K0s, Lambda, anti-Lambda, Omega) - TH1I* histTracks = new TH1I("TrackStats", "Track statistics", fTrackCuts.size() + 5.0, -0.5, fTrackCuts.size() - 0.5 + 5.0); + TH1D* histTracks = new TH1D("TrackStats", "Track statistics", fTrackCuts.size() + 5.0, -0.5, fTrackCuts.size() - 0.5 + 5.0); ib = 1; for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, ib++) { histTracks->GetXaxis()->SetBinLabel(ib, (*cut).GetName()); @@ -1201,13 +1380,19 @@ struct TableMaker { for (ib = 0; ib < 5; ib++) { histTracks->GetXaxis()->SetBinLabel(fTrackCuts.size() + 1 + ib, v0TagNames[ib]); } - fStatsList->Add(histTracks); - TH1I* histMuons = new TH1I("MuonStats", "Muon statistics", fMuonCuts.size(), -0.5, fMuonCuts.size() - 0.5); + fStatsList->Add(histTracks); // At index 1 + TH1D* histMuons = new TH1D("MuonStats", "Muon statistics", fMuonCuts.size(), -0.5, fMuonCuts.size() - 0.5); ib = 1; for (auto cut = fMuonCuts.begin(); cut != fMuonCuts.end(); cut++, ib++) { histMuons->GetXaxis()->SetBinLabel(ib, (*cut).GetName()); } - fStatsList->Add(histMuons); + fStatsList->Add(histMuons); // At index 2 + + TH2D* histZorroInfo = new TH2D("ZorroInfo", "Zorro information", 1, -0.5, 0.5, 1, -0.5, 0.5); + fStatsList->Add(histZorroInfo); // At index 3 + + TH2D* histZorroSel = new TH2D("ZorroSel", "trigger of interested", 1, -0.5, 0.5, 1, -0.5, 0.5); + fStatsList->Add(histZorroSel); // At index 4 } // Produce barrel + muon tables ------------------------------------------------------------------------------------------------------------- @@ -1250,10 +1435,10 @@ struct TableMaker { { for (int i = 0; i < kNaliases; i++) { if (collision.alias_bit(i) > 0) { - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); } } - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(kNaliases)); + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(kNaliases)); if (collision.eventFilter()) { fullSkimming(collision, bcs, tracksBarrel, tracksMuon, nullptr, nullptr); } @@ -1265,15 +1450,22 @@ struct TableMaker { { for (int i = 0; i < kNaliases; i++) { if (collision.alias_bit(i) > 0) { - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); } } - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(kNaliases)); + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(kNaliases)); if (collision.eventFilter()) { fullSkimming(collision, bcs, tracksBarrel, tracksMuon, nullptr, nullptr); } } + // Produce barrel + muon tables for the eletron-muon analysis, without PIDTOF---------------------------------------------------------------------- + void processFullForElectronMuon(MyEvents::iterator const& collision, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksBarrel, soa::Filtered const& tracksMuon) + { + fullSkimming(collision, bcs, tracksBarrel, tracksMuon, nullptr, nullptr); + } + // Produce barrel only tables, with V0Bits ------------------------------------------------------------------------------------------------ void processBarrelOnlyWithV0Bits(MyEvents::iterator const& collision, aod::BCsWithTimestamps const& bcs, soa::Filtered const& tracksBarrel) @@ -1281,6 +1473,13 @@ struct TableMaker { fullSkimming(collision, bcs, tracksBarrel, nullptr, nullptr, nullptr); } + // Produce barrel only tables, with V0Bits and Mults + void processBarrelOnlyWithV0BitsAndMults(MyEventsWithMults::iterator const& collision, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksBarrel) + { + fullSkimming(collision, bcs, tracksBarrel, nullptr, nullptr, nullptr); + } + // Produce barrel only tables, with V0Bits and produce maps ------------------------------------------------------------------------------ void processBarrelOnlyWithV0BitsAndMaps(MyEvents::iterator const& collision, aod::BCsWithTimestamps const& bcs, soa::Filtered const& tracksBarrel) @@ -1331,10 +1530,10 @@ struct TableMaker { { for (int i = 0; i < kNaliases; i++) { if (collision.alias_bit(i) > 0) { - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); } } - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(kNaliases)); + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(kNaliases)); if (collision.eventFilter()) { fullSkimming(collision, bcs, tracksBarrel, nullptr, nullptr, nullptr); } @@ -1353,10 +1552,10 @@ struct TableMaker { { for (int i = 0; i < kNaliases; i++) { if (collision.alias_bit(i) > 0) { - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); } } - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(kNaliases)); + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(kNaliases)); if (collision.eventFilter()) { fullSkimming(collision, bcs, tracksBarrel, nullptr, nullptr, nullptr); } @@ -1368,10 +1567,10 @@ struct TableMaker { { for (int i = 0; i < kNaliases; i++) { if (collision.alias_bit(i) > 0) { - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); } } - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(kNaliases)); + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(kNaliases)); if (collision.eventFilter()) { fullSkimming(collision, bcs, tracksBarrel, nullptr, nullptr, nullptr); } @@ -1412,6 +1611,13 @@ struct TableMaker { fullSkimming(collision, bcs, tracksBarrel, nullptr, nullptr, nullptr); } + // Produce barrel tables only, with track cov matrix , only std PID information used ---------------------------------------------------------------------------------------- + void processBarrelOnlyWithCovOnlyStdPID(MyEventsWithMults::iterator const& collision, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksBarrel) + { + fullSkimming(collision, bcs, tracksBarrel, nullptr, nullptr, nullptr); + } + // Produce barrel tables only ---------------------------------------------------------------------------------------------------------------- void processBarrelOnly(MyEvents::iterator const& collision, aod::BCsWithTimestamps const& bcs, soa::Filtered const& tracksBarrel) @@ -1419,32 +1625,11 @@ struct TableMaker { fullSkimming(collision, bcs, tracksBarrel, nullptr, nullptr, nullptr); } - // Produce muon tables only, with centrality ------------------------------------------------------------------------------------------------- - void processMuonOnlyWithCent(MyEventsWithCent::iterator const& collision, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksMuon) - { - fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); - } - - // Produce muon tables only, with multiplicity --------------------------------------------------------------------------------------------- - void processMuonOnlyWithMults(MyEventsWithMults::iterator const& collision, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksMuon) - { - fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); - } - - // Produce muon tables only, with centrality and multiplicity -------------------------------------------------------------------------------- - void processMuonOnlyWithCentAndMults(MyEventsWithCentAndMults::iterator const& collision, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksMuon) - { - fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); - } - // Produce muon tables only, with centrality and muon cov matrix ------------------------------------------------------------------------------------------------- - void processMuonOnlyWithCovAndCent(MyEventsWithCent::iterator const& collision, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksMuon) + void processMuonOnlyWithCovAndCentMults(MyEventsWithCentAndMults::iterator const& collision, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksMuon) { - fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); + fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); } // Produce muon tables only, with muon cov matrix -------------------------------------------------------------------------------------------- @@ -1454,22 +1639,16 @@ struct TableMaker { fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); } - // Produce muon tables only, with muon cov matrix and multiplicity----------------------------------------------------------------------------------- - void processMuonOnlyWithCovAndMults(MyEventsWithMults::iterator const& collision, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksMuon) - { - fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); - } // Produce muon tables only, with muon cov matrix, with event filtering -------------------------------------------------------------------------------------------- void processMuonOnlyWithCovAndEventFilter(MyEventsWithFilter::iterator const& collision, aod::BCsWithTimestamps const& bcs, soa::Filtered const& tracksMuon) { for (int i = 0; i < kNaliases; i++) { if (collision.alias_bit(i) > 0) { - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); } } - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(kNaliases)); + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(kNaliases)); if (collision.eventFilter()) { fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); } @@ -1482,43 +1661,6 @@ struct TableMaker { fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); } - // Produce muon tables only ------------------------------------------------------------------------------------------------------------------ - void processMuonOnly(MyEvents::iterator const& collision, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksMuon) - { - fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); - } - - // Produce muon tables only, with event filtering -------------------------------------------------------------------------------------------- - void processMuonOnlyWithEventFilter(MyEventsWithFilter::iterator const& collision, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksMuon) - { - for (int i = 0; i < kNaliases; i++) { - if (collision.alias_bit(i) > 0) { - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); - } - } - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(kNaliases)); - if (collision.eventFilter()) { - fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); - } - } - - // Produce muon tables only, with multiplicity and event filtering ---------------------------------------------------------------------------------------- - void processMuonOnlyWithMultsAndEventFilter(MyEventsWithMultsAndFilter::iterator const& collision, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksMuon) - { - for (int i = 0; i < kNaliases; i++) { - if (collision.alias_bit(i) > 0) { - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); - } - } - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(kNaliases)); - if (collision.eventFilter()) { - fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); - } - } - // Produce MFT tracks tables and muons ------------------------------------------------------------------------------------------------------------------ void processMuonsAndMFT(MyEvents::iterator const& collision, aod::BCsWithTimestamps const& bcs, aod::MFTTracks const& tracksMft, soa::Filtered const& tracksMuon) @@ -1536,60 +1678,45 @@ struct TableMaker { } } - // Produce muon tables only based on track-collision association tables -------------------------------------------------------------------------------------- - void processAssociatedMuonOnly(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksMuon, aod::AmbiguousTracksFwd const&, aod::FwdTrackAssoc const& fwdtrackIndices) + void processAssociatedMuonOnlyWithCov(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksMuon, aod::AmbiguousFwdTracks const&, aod::FwdTrackAssoc const& fwdtrackIndices) { for (auto& collision : collisions) { auto muonIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); - fullSkimmingIndices(collision, bcs, nullptr, tracksMuon, nullptr, muonIdsThisCollision); + fullSkimmingIndices(collision, bcs, nullptr, tracksMuon, nullptr, nullptr, muonIdsThisCollision); } } - void processAssociatedMuonOnlyWithCov(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksMuon, aod::AmbiguousTracksFwd const&, aod::FwdTrackAssoc const& fwdtrackIndices) + void processAssociatedRealignedMuonOnlyWithCov(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksMuon, MyMuonsRealignWithCov const& tracksMuonRealign, aod::AmbiguousFwdTracks const&, aod::FwdTrackAssoc const& fwdtrackIndices) { for (auto& collision : collisions) { auto muonIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); - fullSkimmingIndices(collision, bcs, nullptr, tracksMuon, nullptr, muonIdsThisCollision); + auto muonsRealignThisCollision = tracksMuonRealign.sliceBy(perCollisionMuonsRealign, collision.globalIndex()); + fullSkimmingIndices(collision, bcs, nullptr, tracksMuon, muonsRealignThisCollision, nullptr, muonIdsThisCollision); } } - void processAssociatedMuonOnlyWithCovAndCent(MyEventsWithCent const& collisions, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksMuon, aod::AmbiguousTracksFwd const&, aod::FwdTrackAssoc const& fwdtrackIndices) + void processAssociatedMuonOnlyWithCovAndCentMults(MyEventsWithCentAndMults const& collisions, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksMuon, aod::AmbiguousFwdTracks const&, aod::FwdTrackAssoc const& fwdtrackIndices) { for (auto& collision : collisions) { auto muonIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); - fullSkimmingIndices(collision, bcs, nullptr, tracksMuon, nullptr, muonIdsThisCollision); + fullSkimmingIndices(collision, bcs, nullptr, tracksMuon, nullptr, nullptr, muonIdsThisCollision); } } - // Produce muon tables only for ambiguous tracks studies -------------------------------------------------------------------------------------- - void processAmbiguousMuonOnly(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksMuon, aod::AmbiguousTracksFwd const& ambiTracksFwd) + void processAssociatedMuonOnlyWithCovAndMults(MyEventsWithMults const& collisions, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksMuon, aod::AmbiguousFwdTracks const&, aod::FwdTrackAssoc const& fwdtrackIndices) { - // Process orphan tracks - if (fDoDetailedQA && fIsAmbiguous) { - for (auto& ambiTrackFwd : ambiTracksFwd) { - auto muon = ambiTrackFwd.template fwdtrack_as(); - if (muon.collisionId() < 0) { - VarManager::FillTrack(muon); - if ((static_cast(muon.trackType()) == 0)) { - fHistMan->FillHistClass("Orphan_Muons_MFTMCHMID", VarManager::fgValues); - } else if ((static_cast(muon.trackType()) == 3)) { - fHistMan->FillHistClass("Orphan_Muons_MCHMID", VarManager::fgValues); - } - } - } - } for (auto& collision : collisions) { - auto groupedMuons = tracksMuon.sliceBy(perCollisionMuons, collision.globalIndex()); - fullSkimming(collision, bcs, nullptr, groupedMuons, nullptr, ambiTracksFwd); + auto muonIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); + fullSkimmingIndices(collision, bcs, nullptr, tracksMuon, nullptr, nullptr, muonIdsThisCollision); } } void processAmbiguousMuonOnlyWithCov(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksMuon, aod::AmbiguousTracksFwd const& ambiTracksFwd) + soa::Filtered const& tracksMuon, aod::AmbiguousFwdTracks const& ambiTracksFwd) { // Process orphan tracks if (fDoDetailedQA && fIsAmbiguous) { @@ -1613,7 +1740,7 @@ struct TableMaker { // Produce track tables only for ambiguous tracks studies ------------------------------------------------------------------------------------- void processAmbiguousBarrelOnly(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksBarrel, aod::AmbiguousTracksMid const& ambiTracksMid) + soa::Filtered const& tracksBarrel, aod::AmbiguousTracks const& ambiTracksMid) { // Process orphan tracks if (fDoDetailedQA && fIsAmbiguous) { @@ -1636,12 +1763,83 @@ struct TableMaker { { for (int i = 0; i < kNaliases; i++) { if (bc.alias_bit(i) > 0) { - (reinterpret_cast(fStatsList->At(0)))->Fill(0.0, static_cast(i)); + (reinterpret_cast(fStatsList->At(0)))->Fill(0.0, static_cast(i)); } } - (reinterpret_cast(fStatsList->At(0)))->Fill(0.0, static_cast(kNaliases)); + (reinterpret_cast(fStatsList->At(0)))->Fill(0.0, static_cast(kNaliases)); } + // List of process functions removed because they are not using cov matrix + /* + // Produce muon tables only, with centrality ------------------------------------------------------------------------------------------------- + void processMuonOnlyWithCent(MyEventsWithCent::iterator const& collision, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksMuon) + { + fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); + } + + // Produce muon tables only, with multiplicity --------------------------------------------------------------------------------------------- + void processMuonOnlyWithMults(MyEventsWithMults::iterator const& collision, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksMuon) + { + fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); + } + + // Produce muon tables only, with centrality and multiplicity -------------------------------------------------------------------------------- + void processMuonOnlyWithCentAndMults(MyEventsWithCentAndMults::iterator const& collision, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksMuon) + { + fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); + } + + // Produce muon tables only ------------------------------------------------------------------------------------------------------------------ + void processMuonOnly(MyEvents::iterator const& collision, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksMuon) + { + fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); + } + + // Produce muon tables only, with event filtering -------------------------------------------------------------------------------------------- + void processMuonOnlyWithEventFilter(MyEventsWithFilter::iterator const& collision, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksMuon) + { + for (int i = 0; i < kNaliases; i++) { + if (collision.alias_bit(i) > 0) { + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); + } + } + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(kNaliases)); + if (collision.eventFilter()) { + fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); + } + } + + // Produce muon tables only, with multiplicity and event filtering ---------------------------------------------------------------------------------------- + void processMuonOnlyWithMultsAndEventFilter(MyEventsWithMultsAndFilter::iterator const& collision, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksMuon) + { + for (int i = 0; i < kNaliases; i++) { + if (collision.alias_bit(i) > 0) { + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); + } + } + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(kNaliases)); + if (collision.eventFilter()) { + fullSkimming(collision, bcs, nullptr, tracksMuon, nullptr, nullptr); + } + } + + // Produce muon tables only based on track-collision association tables -------------------------------------------------------------------------------------- + void processAssociatedMuonOnly(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksMuon, aod::AmbiguousTracksFwd const&, aod::FwdTrackAssoc const& fwdtrackIndices) + { + for (auto& collision : collisions) { + auto muonIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); + fullSkimmingIndices(collision, bcs, nullptr, tracksMuon, nullptr, muonIdsThisCollision); + } + } + */ + PROCESS_SWITCH(TableMaker, processFull, "Build full DQ skimmed data model, w/o centrality", false); PROCESS_SWITCH(TableMaker, processFullWithCov, "Build full DQ skimmed data model, w/ track and fwdtrack covariance tables", false); PROCESS_SWITCH(TableMaker, processFullWithCovAndEventFilter, "Build full DQ skimmed data model, w/ track and fwdtrack covariance tables, w/ event filter", false); @@ -1649,7 +1847,9 @@ struct TableMaker { PROCESS_SWITCH(TableMaker, processFullWithCent, "Build full DQ skimmed data model, w/ centrality", false); PROCESS_SWITCH(TableMaker, processFullWithCentAndMults, "Build full DQ skimmed data model, w/ centrality and multiplicities", false); PROCESS_SWITCH(TableMaker, processFullWithCovCentAndMults, "Build full DQ skimmed data model, w/ centrality, multiplicities and track covariances", false); + PROCESS_SWITCH(TableMaker, processFullForElectronMuon, "Build full DQ skimmed data model for electron-muon correlation analysis, w/o centrality", false); PROCESS_SWITCH(TableMaker, processBarrelOnlyWithV0Bits, "Build full DQ skimmed data model, w/o centrality, w/ V0Bits", false); + PROCESS_SWITCH(TableMaker, processBarrelOnlyWithV0BitsAndMults, "Build full DQ skimmed data model, w/ multiplicity, w/ V0Bits", false); PROCESS_SWITCH(TableMaker, processBarrelOnlyWithV0BitsAndMaps, "Build full DQ skimmed data model, w/o multiplicity, w/ V0Bits", false); PROCESS_SWITCH(TableMaker, processBarrelOnlyWithDalitzBits, "Build barrel-only DQ skimmed data model, w/o centrality, w/ DalitzBits", false); PROCESS_SWITCH(TableMaker, processBarrelWithDalitzEvent, "Build barrel-only DQ skimmed data model, w/o centrality, w/ DalitzBits", false); @@ -1663,27 +1863,30 @@ struct TableMaker { PROCESS_SWITCH(TableMaker, processBarrelOnlyWithCentAndMults, "Build barrel-only DQ skimmed data model, w/ centrality and multiplicities", false); PROCESS_SWITCH(TableMaker, processBarrelOnlyWithCovWithCentAndMults, "Build barrel-only DQ skimmed data model, w/ centrality and multiplicities and w/ track covariance", false); PROCESS_SWITCH(TableMaker, processBarrelOnlyWithCov, "Build barrel-only DQ skimmed data model, w/ track cov matrix", false); + PROCESS_SWITCH(TableMaker, processBarrelOnlyWithCovOnlyStdPID, "Build barrel-only DQ skimmed data model, w/ track cov matrix, only std PID information used", false); PROCESS_SWITCH(TableMaker, processBarrelOnly, "Build barrel-only DQ skimmed data model, w/o centrality", false); - PROCESS_SWITCH(TableMaker, processMuonOnlyWithCent, "Build muon-only DQ skimmed data model, w/ centrality", false); - PROCESS_SWITCH(TableMaker, processMuonOnlyWithMults, "Build muon-only DQ skimmed data model, w/ multiplicity", false); - PROCESS_SWITCH(TableMaker, processMuonOnlyWithMultsAndEventFilter, "Build muon-only DQ skimmed data model, w/ multiplicity, w/ event filter", false); - PROCESS_SWITCH(TableMaker, processMuonOnlyWithCentAndMults, "Build muon-only DQ skimmed data model, w/ centrality and multiplicities", false); - PROCESS_SWITCH(TableMaker, processMuonOnlyWithCovAndCent, "Build muon-only DQ skimmed data model, w/ centrality and muon cov matrix", false); + PROCESS_SWITCH(TableMaker, processMuonOnlyWithCovAndCentMults, "Build muon-only DQ skimmed data model, w/ centrality and muon cov matrix", false); PROCESS_SWITCH(TableMaker, processMuonOnlyWithCov, "Build muon-only DQ skimmed data model, w/ muon cov matrix", false); - PROCESS_SWITCH(TableMaker, processMuonOnlyWithCovAndMults, "Build muon-only DQ skimmed data model, w/ muon cov matrix and multiplicity", false); PROCESS_SWITCH(TableMaker, processMuonOnlyWithCovAndEventFilter, "Build muon-only DQ skimmed data model, w/ muon cov matrix, w/ event filter", false); - PROCESS_SWITCH(TableMaker, processMuonOnly, "Build muon-only DQ skimmed data model", false); - PROCESS_SWITCH(TableMaker, processMuonOnlyWithEventFilter, "Build muon-only DQ skimmed data model, w/ event filter", false); PROCESS_SWITCH(TableMaker, processMuonMLOnly, "Build muon-only DQ skimmed data model with global muon track by ML matching", false); PROCESS_SWITCH(TableMaker, processOnlyBCs, "Analyze the BCs to store sampled lumi", false); - PROCESS_SWITCH(TableMaker, processAmbiguousMuonOnly, "Build muon-only DQ skimmed data model with QA plots for ambiguous muons", false); PROCESS_SWITCH(TableMaker, processAmbiguousMuonOnlyWithCov, "Build muon-only with cov DQ skimmed data model with QA plots for ambiguous muons", false); PROCESS_SWITCH(TableMaker, processAmbiguousBarrelOnly, "Build barrel-only DQ skimmed data model with QA plots for ambiguous tracks", false); - PROCESS_SWITCH(TableMaker, processAssociatedMuonOnly, "Build muon-only DQ skimmed data model using track-collision association tables", false); PROCESS_SWITCH(TableMaker, processAssociatedMuonOnlyWithCov, "Build muon-only with cov DQ skimmed data model using track-collision association tables", false); - PROCESS_SWITCH(TableMaker, processAssociatedMuonOnlyWithCovAndCent, "Build muon-only with cov DQ skimmed data model using track-collision association tables and centrality", false); + PROCESS_SWITCH(TableMaker, processAssociatedRealignedMuonOnlyWithCov, "Build realigned muon-only with cov DQ skimmed data model using track-collision association tables", false); + PROCESS_SWITCH(TableMaker, processAssociatedMuonOnlyWithCovAndCentMults, "Build muon-only with cov DQ skimmed data model using track-collision association tables and centrality", false); + PROCESS_SWITCH(TableMaker, processAssociatedMuonOnlyWithCovAndMults, "Build muon-only with cov DQ skimmed data model using track-collision association tables and multiplicity", false); PROCESS_SWITCH(TableMaker, processMuonsAndMFT, "Build MFT and muons DQ skimmed data model", false); PROCESS_SWITCH(TableMaker, processMuonsAndMFTWithFilter, "Build MFT and muons DQ skimmed data model, w/ event filter", false); + + // List of process functions removed because they are not using cov matrix + // PROCESS_SWITCH(TableMaker, processMuonOnlyWithCent, "Build muon-only DQ skimmed data model, w/ centrality", false); + // PROCESS_SWITCH(TableMaker, processMuonOnlyWithMults, "Build muon-only DQ skimmed data model, w/ multiplicity", false); + // PROCESS_SWITCH(TableMaker, processMuonOnlyWithMultsAndEventFilter, "Build muon-only DQ skimmed data model, w/ multiplicity, w/ event filter", false); + // PROCESS_SWITCH(TableMaker, processMuonOnlyWithCentAndMults, "Build muon-only DQ skimmed data model, w/ centrality and multiplicities", false); + // PROCESS_SWITCH(TableMaker, processMuonOnly, "Build muon-only DQ skimmed data model", false); + // PROCESS_SWITCH(TableMaker, processMuonOnlyWithEventFilter, "Build muon-only DQ skimmed data model, w/ event filter", false); + // PROCESS_SWITCH(TableMaker, processAssociatedMuonOnly, "Build muon-only DQ skimmed data model using track-collision association tables", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGDQ/TableProducer/tableMakerJpsiHf.cxx b/PWGDQ/TableProducer/tableMakerJpsiHf.cxx index 9c18f0b9fc4..7ae949c40d1 100644 --- a/PWGDQ/TableProducer/tableMakerJpsiHf.cxx +++ b/PWGDQ/TableProducer/tableMakerJpsiHf.cxx @@ -22,12 +22,15 @@ #include "Framework/runDataProcessing.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGDQ/Core/AnalysisCut.h" +#include "PWGDQ/Core/AnalysisCompositeCut.h" +#include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/VarManager.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGDQ/DataModel/ReducedInfoTables.h" -#include "PWGDQ/Core/VarManager.h" -#include "PWGDQ/Core/HistogramManager.h" -#include "PWGDQ/Core/HistogramsLibrary.h" using namespace o2; using namespace o2::analysis; @@ -36,14 +39,48 @@ using namespace o2::framework::expressions; using namespace o2::aod; using namespace o2::aod::hf_cand_2prong; +// bit maps used for the Fill functions of the VarManager +constexpr static uint32_t gkTrackFillMapWithColl = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelPID | VarManager::ObjTypes::ReducedTrackCollInfo; +constexpr static uint32_t gkMuonFillMapWithColl = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra | VarManager::ObjTypes::ReducedMuonCollInfo; + +namespace +{ +struct CandidateDilepton { + float fMass; + float fPt; + float fPhi; + float fEta; + float fTauz; + float fLz; + float fLxy; + int fSign; + uint32_t fMcDecision; + + float pt() const { return fPt; } + float mass() const { return fMass; } + float phi() const { return fPhi; } + float eta() const { return fEta; } + int sign() const { return fSign; } + uint32_t mcDecision() const { return fMcDecision; } + float tauz() const { return fTauz; } + float lz() const { return fLz; } + float lxy() const { return fLxy; } + float px() const { return fPt * std::cos(fPhi); } + float py() const { return fPt * std::sin(fPhi); } + float pz() const { return fPt * std::sinh(fEta); } + float p() const { return fPt * std::cosh(fEta); } + float rap() const { return std::log((std::sqrt(fMass * fMass + fPt * fPt * std::cosh(fEta) * std::cosh(fEta)) + fPt * std::sinh(fEta)) / std::sqrt(fMass * fMass + fPt * fPt)); } +}; +} // namespace + // Declarations of various short names using MyEvents = soa::Join; -using MyDimuonCandidatesSelected = soa::Join; -using MyDimuonCandidatesSelectedWithDca = soa::Join; -using MyDielectronCandidatesSelected = soa::Join; -using MyDielectronCandidatesSelectedWithDca = soa::Join; -using MyD0CandidatesSelected = soa::Join; -using MyD0CandidatesSelectedWithBdt = soa::Join; +using MyD0CandidatesSelected = soa::Join; +using MyD0CandidatesSelectedWithBdt = soa::Join; +using TracksWithExtra = soa::Join; + +using MyBarrelTracksSelectedWithColl = soa::Join; +using MyMuonTracksSelectedWithColl = soa::Join; HfHelper hfHelper; @@ -55,6 +92,8 @@ struct tableMakerJpsiHf { // Produce derived tables Produces redCollisions; Produces redDmesons; + Produces redDmesDau0; + Produces redDmesDau1; Produces redDmesBdts; Produces redD0Masses; Produces redDileptons; @@ -64,32 +103,38 @@ struct tableMakerJpsiHf { // cuts on BDT output scores to be applied only for the histograms Configurable yCandDmesonMax{"yCandDmesonMax", -1., "max. cand. rapidity"}; // DQ configurables - Configurable dileptonDecayChannel{"dileptonDecayChannel", "JPsiToMuMu", "Dilepton decay channel (JPsiToMuMu/JPsiToEE)"}; + Configurable fConfigTrackCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; + // Configurable fConfigPairCuts{"cfgPairCuts", "", "Comma separated list of pair cuts"}; It seems to me that they are not used + Configurable fConfigMuonCuts{"cfgMuonCuts", "muonQualityCuts", "Comma separated list of muon cuts"}; Configurable massDileptonCandMin{"massDileptonCandMin", 1, "minimum dilepton mass"}; Configurable massDileptonCandMax{"massDileptonCandMax", 5, "maximum dilepton mass"}; // General configurables Configurable configDebug{"configDebug", true, "If true, fill D0 - J/psi histograms separately"}; Configurable storeTableForNorm{"storeTableForNorm", true, "If true, store a table with number of processed collisions for normalisation"}; - SliceCache cache; - Partition selectedDimuonCandidates = aod::reducedpair::mass > 1.0f && aod::reducedpair::mass < 5.0f && aod::reducedpair::sign == 0; - Partition selectedDimuonCandidatesWithDca = aod::reducedpair::mass > 1.0f && aod::reducedpair::mass < 5.0f && aod::reducedpair::sign == 0; - Partition selectedDielectronCandidates = aod::reducedpair::mass > 1.0f && aod::reducedpair::mass < 5.0f && aod::reducedpair::sign == 0; - Partition selectedDielectronCandidatesWithDca = aod::reducedpair::mass > 1.0f && aod::reducedpair::mass < 5.0f && aod::reducedpair::sign == 0; - Partition selectedD0Candidates = aod::hf_sel_candidate_d0::isSelD0 >= 1 || aod::hf_sel_candidate_d0::isSelD0bar >= 1; - Partition selectedD0CandidatesWithBdt = aod::hf_sel_candidate_d0::isSelD0 >= 1 || aod::hf_sel_candidate_d0::isSelD0bar >= 1; - Preslice perCollisionDmeson = aod::hf_cand::collisionId; - Preslice perCollisionDimuon = aod::reducedpair::collisionId; - Preslice perCollisionDielectron = aod::reducedpair::collisionId; + Preslice perCollisionDmesonWithBdt = aod::hf_cand::collisionId; + PresliceUnsorted perCollisionMuons = aod::reducedmuon::collisionId; + PresliceUnsorted perCollisionElectrons = aod::reducedtrack::collisionId; + + SliceCache cache; + Filter filterD0Candidates = aod::hf_sel_candidate_d0::isSelD0 >= 1 || aod::hf_sel_candidate_d0::isSelD0bar >= 1; // Define histograms manager float* fValuesDileptonCharmHadron{}; HistogramManager* fHistMan{}; OutputObj fOutputList{"output"}; + std::vector fTrackCuts; + std::vector fMuonCuts; + void init(o2::framework::InitContext&) { + std::array doprocess{doprocessJspiToMuMuD0, doprocessJspiToMuMuD0WithBdt, doprocessJspiToEED0, doprocessJspiToEED0WithBdt}; + if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { + LOGP(fatal, "Only one process function should be enabled! Please check your configuration!"); + } + fValuesDileptonCharmHadron = new float[VarManager::kNVars]; VarManager::SetDefaultVarNames(); fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); @@ -99,28 +144,116 @@ struct tableMakerJpsiHf { fHistMan->AddHistClass("JPsi"); fHistMan->AddHistClass("JPsiDmeson"); dqhistograms::DefineHistograms(fHistMan, "Dmeson", "dilepton-charmhadron", "dmeson"); - if (dileptonDecayChannel.value == "JPsiToMuMu") { + if (doprocessJspiToMuMuD0 || doprocessJspiToMuMuD0WithBdt) { dqhistograms::DefineHistograms(fHistMan, "JPsi", "dilepton-charmhadron", "jpsitomumu"); dqhistograms::DefineHistograms(fHistMan, "JPsiDmeson", "dilepton-charmhadron", "jpsitomumudmeson"); } - if (dileptonDecayChannel.value == "JPsiToEE") { + if (doprocessJspiToEED0 || doprocessJspiToEED0WithBdt) { dqhistograms::DefineHistograms(fHistMan, "JPsi", "dilepton-charmhadron", "jpsitoee"); dqhistograms::DefineHistograms(fHistMan, "JPsiDmeson", "dilepton-charmhadron", "jpsitoeedmeson"); } VarManager::SetUseVars(fHistMan->GetUsedVars()); fOutputList.setObject(fHistMan->GetMainHistogramList()); + + // cut strings + if (doprocessJspiToMuMuD0 || doprocessJspiToMuMuD0WithBdt) { + TString cutNamesMuon = fConfigMuonCuts.value; + if (!cutNamesMuon.IsNull()) { + std::unique_ptr objArray(cutNamesMuon.Tokenize(",")); + for (int iCut{0}; iCut < objArray->GetEntries(); ++iCut) { + fMuonCuts.push_back(*dqcuts::GetCompositeCut(objArray->At(iCut)->GetName())); + } + } + } + if (doprocessJspiToEED0 || doprocessJspiToEED0WithBdt) { + TString cutNamesElectron = fConfigTrackCuts.value; + if (!cutNamesElectron.IsNull()) { // if track cuts + std::unique_ptr objArray(cutNamesElectron.Tokenize(",")); + for (int iCut{0}; iCut < objArray->GetEntries(); ++iCut) { + fTrackCuts.push_back(*dqcuts::GetCompositeCut(objArray->At(iCut)->GetName())); + } + } + } + + // It seems they are not applied when filling the table + // TString cutNamesPair = fConfigPairCuts.value; + // if (!cutNamesPair.IsNull()) { + // std::unique_ptr objArray(cutNamesPair.Tokenize(",")); + // for (int iCut{0}; iCut < objArray->GetEntries(); ++iCut) { + // fPairCuts.push_back(*dqcuts::GetCompositeCut(objArray->At(iCut)->GetName())); + // } + // } + } + + // template function for lepton selection + template + bool isLeptonSelected(TTrack const& lepton) + { + + if constexpr (TPairType == VarManager::kDecayToEE) { + VarManager::FillTrack(lepton); + for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++) { + if (!(*cut).IsSelected(VarManager::fgValues)) { + return false; + } + } + } else if constexpr (TPairType == VarManager::kDecayToMuMu) { + VarManager::FillTrack(lepton); + for (auto cut = fMuonCuts.begin(); cut != fMuonCuts.end(); cut++) { + if (!(*cut).IsSelected(VarManager::fgValues)) { + return false; + } + } + } + + return true; + } + + // template function to compute the dilepton combinatorial + template + std::vector computeDileptonCombinatorial(TTracks const& tracks) + { + std::vector dileptons{}; + uint32_t dileptonMcDecision{0u}; // placeholder, copy of the dqEfficiency.cxx one + + for (auto& [trackFirst, trackSecond] : combinations(tracks, tracks)) { + bool isFirstSelected = isLeptonSelected(trackFirst); + bool isSecondSelected = isLeptonSelected(trackSecond); + + if (!isFirstSelected || !isSecondSelected || (trackFirst.sign() + trackSecond.sign()) != 0) { + continue; + } + + // we fill a struct for the dileptons, which has the same signatures of the DQ tables to be used in the VarManager + VarManager::FillPair(trackFirst, trackSecond); + + if (VarManager::fgValues[VarManager::kMass] < massDileptonCandMin || VarManager::fgValues[VarManager::kMass] > massDileptonCandMax) { + continue; + } + + CandidateDilepton dilepton{}; + dilepton.fMass = VarManager::fgValues[VarManager::kMass]; + dilepton.fPt = VarManager::fgValues[VarManager::kPt]; + dilepton.fEta = VarManager::fgValues[VarManager::kEta]; + dilepton.fPhi = VarManager::fgValues[VarManager::kPhi]; + dilepton.fSign = trackFirst.sign() + trackSecond.sign(); + dilepton.fMcDecision = dileptonMcDecision; + dileptons.push_back(dilepton); + } + + return dileptons; } // Template function to run pair - hadron combinations // TODO: generalise to all charm-hadron species - template - void runDileptonDmeson(TDqTrack const& dileptons, THfTrack const& dmesons, MyEvents::iterator const& collision) + template + void runDileptonDmeson(TDqTrack const& leptons, THfTrack const& dmesons, MyEvents::iterator const& collision, TracksWithExtra const&) { VarManager::ResetValues(0, VarManager::kNVars, fValuesDileptonCharmHadron); bool isCollSel{false}; if (configDebug) { - for (auto& dmeson : dmesons) { + for (auto const& dmeson : dmesons) { if (!TESTBIT(dmeson.hfflag(), DecayType::D0ToPiK)) { continue; } @@ -158,7 +291,11 @@ struct tableMakerJpsiHf { } } + // we compute the dileptons on the fly + auto dileptons = computeDileptonCombinatorial(leptons); + // loop over dileptons + std::vector filledDmesonIds{}; // keep track of the D-mesons filled in the table to avoid repetitions for (auto dilepton : dileptons) { auto massJPsi = dilepton.mass(); bool isJPsiFilled{false}; @@ -175,11 +312,17 @@ struct tableMakerJpsiHf { } // loop over D mesons - for (auto& dmeson : dmesons) { + for (auto const& dmeson : dmesons) { if (!TESTBIT(dmeson.hfflag(), DecayType::D0ToPiK)) { continue; } + int dmesonIdx = dmeson.globalIndex(); + bool isDmesonFilled{false}; + if (std::find(filledDmesonIds.begin(), filledDmesonIds.end(), dmesonIdx) != filledDmesonIds.end()) { // we already included this D meson in the table, skip it + isDmesonFilled = true; + } + auto rapD0 = hfHelper.yD0(dmeson); if (yCandDmesonMax >= 0. && std::abs(rapD0) > yCandDmesonMax) { @@ -203,20 +346,30 @@ struct tableMakerJpsiHf { } isJPsiFilled = true; } - redDmesons(indexRed, dmeson.px(), dmeson.py(), dmeson.pz(), dmeson.xSecondaryVertex(), dmeson.ySecondaryVertex(), dmeson.zSecondaryVertex(), 0, 0); + if (!isDmesonFilled) { + redDmesons(indexRed, dmeson.px(), dmeson.py(), dmeson.pz(), dmeson.xSecondaryVertex(), dmeson.ySecondaryVertex(), dmeson.zSecondaryVertex(), 0, 0); + auto trackProng0 = dmeson.template prong0_as(); + auto trackProng1 = dmeson.template prong1_as(); + // one table for each daughter with single track variables + redDmesDau0(trackProng0.pt(), trackProng0.eta(), trackProng0.itsNCls(), trackProng0.tpcNClsCrossedRows(), dmeson.nSigTpcPi0(), dmeson.nSigTofPi0(), dmeson.nSigTpcKa0(), dmeson.nSigTofKa0()); + redDmesDau1(trackProng1.pt(), trackProng1.eta(), trackProng1.itsNCls(), trackProng1.tpcNClsCrossedRows(), dmeson.nSigTpcPi1(), dmeson.nSigTofPi1(), dmeson.nSigTpcKa1(), dmeson.nSigTofKa1()); + filledDmesonIds.push_back(dmesonIdx); + } std::array scores = {999., -999., -999., 999., -999., -999.}; // D0 + D0bar if constexpr (withBdt) { - if (dmeson.mlProbD0().size() == 3) { - for (auto iScore{0u}; iScore < dmeson.mlProbD0().size(); ++iScore) { - scores[iScore] = dmeson.mlProbD0()[iScore]; + if (!isDmesonFilled) { + if (dmeson.mlProbD0().size() == 3) { + for (auto iScore{0u}; iScore < dmeson.mlProbD0().size(); ++iScore) { + scores[iScore] = dmeson.mlProbD0()[iScore]; + } } - } - if (dmeson.mlProbD0bar().size() == 3) { - for (auto iScore{0u}; iScore < dmeson.mlProbD0bar().size(); ++iScore) { - scores[iScore + 3] = dmeson.mlProbD0bar()[iScore]; + if (dmeson.mlProbD0bar().size() == 3) { + for (auto iScore{0u}; iScore < dmeson.mlProbD0bar().size(); ++iScore) { + scores[iScore + 3] = dmeson.mlProbD0bar()[iScore]; + } } + redDmesBdts(scores[0], scores[1], scores[2], scores[3], scores[4], scores[5]); } - redDmesBdts(scores[0], scores[1], scores[2], scores[3], scores[4], scores[5]); } if (dmeson.isSelD0() >= 1) { @@ -231,61 +384,63 @@ struct tableMakerJpsiHf { fHistMan->FillHistClass("JPsiDmeson", fValuesDileptonCharmHadron); VarManager::ResetValues(0, VarManager::kNVars, fValuesDileptonCharmHadron); } - redD0Masses(massD0, massD0bar); + if (!isDmesonFilled) { + redD0Masses(massD0, massD0bar); + } } } } } // process J/psi(->mumu) - D0 - void processJspiToMuMuD0(MyEvents const& collisions, MyDimuonCandidatesSelected const&, MyD0CandidatesSelected const&) + void processJspiToMuMuD0(MyEvents const& collisions, MyMuonTracksSelectedWithColl const& muonCandidates, soa::Filtered const& selectedD0Candidates, TracksWithExtra const& barrelTracks) { if (storeTableForNorm) { redCollCounter(collisions.size()); } - for (auto& collision : collisions) { - auto groupedDmesonCandidates = selectedD0Candidates->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); - auto groupedDileptonCandidates = selectedDimuonCandidates->sliceByCached(aod::reducedpair::collisionId, collision.globalIndex(), cache); - runDileptonDmeson(groupedDileptonCandidates, groupedDmesonCandidates, collision); + for (auto const& collision : collisions) { + auto groupedDmesonCandidates = selectedD0Candidates.sliceBy(perCollisionDmeson, collision.globalIndex()); + auto groupedLeptonCandidates = muonCandidates.sliceBy(perCollisionMuons, collision.globalIndex()); + runDileptonDmeson(groupedLeptonCandidates, groupedDmesonCandidates, collision, barrelTracks); } } // process J/psi(->ee) - D0 - void processJspiToEED0(MyEvents const& collisions, MyDielectronCandidatesSelected const&, MyD0CandidatesSelected const&) + void processJspiToEED0(MyEvents const& collisions, MyBarrelTracksSelectedWithColl const& electronCandidates, soa::Filtered const& selectedD0Candidates, TracksWithExtra const& barrelTracks) { if (storeTableForNorm) { redCollCounter(collisions.size()); } - for (auto& collision : collisions) { - auto groupedDmesonCandidates = selectedD0Candidates->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); - auto groupedDileptonCandidates = selectedDielectronCandidates->sliceByCached(aod::reducedpair::collisionId, collision.globalIndex(), cache); - runDileptonDmeson(groupedDileptonCandidates, groupedDmesonCandidates, collision); + for (auto const& collision : collisions) { + auto groupedDmesonCandidates = selectedD0Candidates.sliceBy(perCollisionDmeson, collision.globalIndex()); + auto groupedLeptonCandidates = electronCandidates.sliceBy(perCollisionElectrons, collision.globalIndex()); + runDileptonDmeson(groupedLeptonCandidates, groupedDmesonCandidates, collision, barrelTracks); } } // process J/psi(->mumu) - D0 adding the BDT output scores to the D0 table - void processJspiToMuMuD0WithBdt(MyEvents const& collisions, MyDimuonCandidatesSelected const&, MyD0CandidatesSelectedWithBdt const&) + void processJspiToMuMuD0WithBdt(MyEvents const& collisions, MyMuonTracksSelectedWithColl const& muonCandidates, soa::Filtered const& selectedD0CandidatesWithBdt, TracksWithExtra const& barrelTracks) { if (storeTableForNorm) { redCollCounter(collisions.size()); } - for (auto& collision : collisions) { - auto groupedDmesonCandidates = selectedD0CandidatesWithBdt->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); - auto groupedDileptonCandidates = selectedDimuonCandidates->sliceByCached(aod::reducedpair::collisionId, collision.globalIndex(), cache); - runDileptonDmeson(groupedDileptonCandidates, groupedDmesonCandidates, collision); + for (auto const& collision : collisions) { + auto groupedDmesonCandidates = selectedD0CandidatesWithBdt.sliceBy(perCollisionDmesonWithBdt, collision.globalIndex()); + auto groupedLeptonCandidates = muonCandidates.sliceBy(perCollisionMuons, collision.globalIndex()); + runDileptonDmeson(groupedLeptonCandidates, groupedDmesonCandidates, collision, barrelTracks); } } // process J/psi(->ee) - D0 adding the BDT output scores to the D0 table - void processJspiToEED0WithBdt(MyEvents const& collisions, MyDielectronCandidatesSelected const&, MyD0CandidatesSelectedWithBdt const&) + void processJspiToEED0WithBdt(MyEvents const& collisions, MyBarrelTracksSelectedWithColl const& electronCandidates, soa::Filtered const& selectedD0CandidatesWithBdt, TracksWithExtra const& barrelTracks) { if (storeTableForNorm) { redCollCounter(collisions.size()); } - for (auto& collision : collisions) { - auto groupedDmesonCandidates = selectedD0CandidatesWithBdt->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); - auto groupedDileptonCandidates = selectedDielectronCandidates->sliceByCached(aod::reducedpair::collisionId, collision.globalIndex(), cache); - runDileptonDmeson(groupedDileptonCandidates, groupedDmesonCandidates, collision); + for (auto const& collision : collisions) { + auto groupedDmesonCandidates = selectedD0CandidatesWithBdt.sliceBy(perCollisionDmesonWithBdt, collision.globalIndex()); + auto groupedLeptonCandidates = electronCandidates.sliceBy(perCollisionElectrons, collision.globalIndex()); + runDileptonDmeson(groupedLeptonCandidates, groupedDmesonCandidates, collision, barrelTracks); } } diff --git a/PWGDQ/TableProducer/tableMakerMC.cxx b/PWGDQ/TableProducer/tableMakerMC.cxx index 7e73247701b..20634b53b8a 100644 --- a/PWGDQ/TableProducer/tableMakerMC.cxx +++ b/PWGDQ/TableProducer/tableMakerMC.cxx @@ -17,6 +17,10 @@ // and the MC truth particles corresponding to the reconstructed tracks selected by the specified track cuts on reconstructed data. #include +#include +#include +#include +#include #include "TList.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -39,6 +43,7 @@ #include "PWGDQ/Core/MCSignalLibrary.h" #include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/CollisionAssociationTables.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" #include "Field/MagneticField.h" @@ -75,41 +80,42 @@ using MyBarrelTracksWithCov = soa::Join; using MyMuons = soa::Join; using MyMuonsWithCov = soa::Join; +using MyMuonsColl = soa::Join; +using MyMuonsCollWithCov = soa::Join; + +using MyMftTracks = soa::Join; using MyEvents = soa::Join; -using MyEventsWithMults = soa::Join; +using MyEventsWithMults = soa::Join; using MyEventsWithCent = soa::Join; -using MyEventsWithCentAndMults = soa::Join; - -namespace o2::aod -{ -DECLARE_SOA_TABLE(AmbiguousTracksMid, "AOD", "AMBIGUOUSTRACK", //! Table for tracks which are not uniquely associated with a collision - o2::soa::Index<>, o2::aod::ambiguous::TrackId, o2::aod::ambiguous::BCIdSlice, o2::soa::Marker<2>); -DECLARE_SOA_TABLE(AmbiguousTracksFwd, "AOD", "AMBIGUOUSFWDTR", //! Table for Fwd tracks which are not uniquely associated with a collision - o2::soa::Index<>, o2::aod::ambiguous::FwdTrackId, o2::aod::ambiguous::BCIdSlice, o2::soa::Marker<2>); -} // namespace o2::aod +using MyEventsWithCentAndMults = soa::Join; constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision; constexpr static uint32_t gkEventFillMapWithMults = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionMult; constexpr static uint32_t gkEventFillMapWithCent = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCent; constexpr static uint32_t gkEventFillMapWithCentAndMults = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCent | VarManager::CollisionMult; constexpr static uint32_t gkEventMCFillMap = VarManager::ObjTypes::CollisionMC; -constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackPID; -constexpr static uint32_t gkTrackFillMapWithCov = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackCov | VarManager::ObjTypes::TrackPID; +constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackPID | VarManager::ObjTypes::TrackPIDExtra; +constexpr static uint32_t gkTrackFillMapWithCov = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackCov | VarManager::ObjTypes::TrackPID | VarManager::ObjTypes::TrackPIDExtra; constexpr static uint32_t gkTrackFillMapWithDalitzBits = gkTrackFillMap | VarManager::ObjTypes::DalitzBits; constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::Muon; constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::Muon | VarManager::ObjTypes::MuonCov; constexpr static uint32_t gkMuonFillMapWithAmbi = VarManager::ObjTypes::Muon | VarManager::ObjTypes::AmbiMuon; constexpr static uint32_t gkMuonFillMapWithCovAmbi = VarManager::ObjTypes::Muon | VarManager::ObjTypes::MuonCov | VarManager::ObjTypes::AmbiMuon; constexpr static uint32_t gkTrackFillMapWithAmbi = VarManager::ObjTypes::Track | VarManager::ObjTypes::AmbiTrack; +constexpr static uint32_t gkMFTFillMap = VarManager::ObjTypes::TrackMFT; struct TableMakerMC { Produces event; Produces eventExtended; Produces eventVtxCov; + Produces eventInfo; + Produces multPV; + Produces multAll; Produces eventMClabels; Produces eventMC; + Produces trackBarrelInfo; Produces trackBasic; Produces trackBarrel; Produces trackBarrelCov; @@ -120,6 +126,9 @@ struct TableMakerMC { Produces muonExtra; Produces muonCov; Produces muonLabels; // TODO: enable this once we have fwdtrack labels + Produces trackMFT; + Produces trackMFTExtra; + Produces trackMFTLabels; // list of MCsignal objects std::vector fMCSignals; @@ -224,10 +233,13 @@ struct TableMakerMC { bool enableBarrelHistos = (context.mOptions.get("processFull") || context.mOptions.get("processFullWithCov") || context.mOptions.get("processBarrelOnly") || context.mOptions.get("processBarrelOnlyWithDalitzBits") || context.mOptions.get("processBarrelOnlyWithCent") || context.mOptions.get("processBarrelOnlyWithCov") || + context.mOptions.get("processBarrelOnlyWithCovWithCentAndMults") || context.mOptions.get("processBarrelOnlyWithCentAndMults") || context.mOptions.get("processBarrelOnlyWithMults") || context.mOptions.get("processAmbiguousBarrelOnly")); bool enableMuonHistos = (context.mOptions.get("processFull") || context.mOptions.get("processFullWithCov") || context.mOptions.get("processMuonOnlyWithCent") || context.mOptions.get("processMuonOnlyWithCov") || - context.mOptions.get("processAmbiguousMuonOnlyWithCov") || context.mOptions.get("processAmbiguousMuonOnly")); + context.mOptions.get("processAmbiguousMuonOnlyWithCov") || context.mOptions.get("processAmbiguousMuonOnly") || + context.mOptions.get("processAssociatedMuonOnly") || context.mOptions.get("processAssociatedMuonOnlyWithCov") || + context.mOptions.get("processAssociatedMuonOnlyWithCovAndCent") || context.mOptions.get("processAssociatedMuonOnlyWithCovAndMults")); // TODO: switch on/off histogram classes depending on which process function we run if (enableBarrelHistos) { if (fDoDetailedQA) { @@ -302,11 +314,13 @@ struct TableMakerMC { Preslice perMcCollision = aod::mcparticle::mcCollisionId; Preslice perCollisionTracks = aod::track::collisionId; Preslice perCollisionMuons = aod::fwdtrack::collisionId; + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + Preslice fwdtrackIndicesPerCollision = aod::track_association::collisionId; // Templated function instantianed for all of the process functions - template + template void fullSkimming(TEvent const& collisions, aod::BCsWithTimestamps const& /*bcs*/, TTracks const& tracksBarrel, TMuons const& tracksMuon, - aod::McCollisions const& /*mcEvents*/, aod::McParticles_001 const& mcTracks, TAmbiTracks const& ambiTracksMid, TAmbiMuons const& ambiTracksFwd) + aod::McCollisions const& /*mcEvents*/, aod::McParticles_001 const& mcTracks, TAmbiTracks const& ambiTracksMid, TAmbiMuons const& ambiTracksFwd, TMFTTracks const& mftTracks = nullptr) { // Loop over collisions and produce skimmed data tables for: // 1) all selected collisions @@ -387,7 +401,7 @@ struct TableMakerMC { // store the selection decisions uint64_t tag = collision.selection_raw(); if (collision.sel7()) { - tag |= (uint64_t(1) << evsel::kNsel); //! SEL7 stored at position kNsel in the tag bit map + tag |= (static_cast(1) << evsel::kNsel); //! SEL7 stored at position kNsel in the tag bit map } auto mcCollision = collision.mcCollision(); @@ -403,7 +417,7 @@ struct TableMakerMC { } // fill stats information, before selections for (int i = 0; i < kNaliases; i++) { - if (triggerAliases & (uint32_t(1) << i)) { + if (triggerAliases & (static_cast(1) << i)) { (reinterpret_cast(fStatsList->At(0)))->Fill(2.0, static_cast(i)); } } @@ -419,7 +433,7 @@ struct TableMakerMC { // fill stats information, after selections for (int i = 0; i < kNaliases; i++) { - if (triggerAliases & (uint32_t(1) << i)) { + if (triggerAliases & (static_cast(1) << i)) { (reinterpret_cast(fStatsList->At(0)))->Fill(3.0, static_cast(i)); } } @@ -427,22 +441,23 @@ struct TableMakerMC { event(tag, bc.runNumber(), collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), collision.collisionTime(), collision.collisionTimeRes()); if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionMult) > 0 && (TEventFillMap & VarManager::ObjTypes::CollisionCent) > 0) { - eventExtended(collision.bc().globalBC(), collision.bc().triggerMask(), 0, triggerAliases, VarManager::fgValues[VarManager::kCentVZERO], + eventExtended(bc.globalBC(), collision.alias_raw(), collision.selection_raw(), bc.timestamp(), VarManager::fgValues[VarManager::kCentVZERO], collision.multTPC(), collision.multFV0A(), collision.multFV0C(), collision.multFT0A(), collision.multFT0C(), collision.multFDDA(), collision.multFDDC(), collision.multZNA(), collision.multZNC(), collision.multTracklets(), collision.multNTracksPV(), collision.centFT0C()); } else if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionMult) > 0) { - eventExtended(bc.globalBC(), bc.triggerMask(), bc.timestamp(), triggerAliases, VarManager::fgValues[VarManager::kCentVZERO], + eventExtended(bc.globalBC(), collision.alias_raw(), collision.selection_raw(), bc.timestamp(), VarManager::fgValues[VarManager::kCentVZERO], collision.multTPC(), collision.multFV0A(), collision.multFV0C(), collision.multFT0A(), collision.multFT0C(), collision.multFDDA(), collision.multFDDC(), collision.multZNA(), collision.multZNC(), collision.multTracklets(), collision.multNTracksPV(), -1); } else if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionCent) > 0) { - eventExtended(bc.globalBC(), bc.triggerMask(), bc.timestamp(), triggerAliases, VarManager::fgValues[VarManager::kCentVZERO], + eventExtended(bc.globalBC(), collision.alias_raw(), collision.selection_raw(), bc.timestamp(), VarManager::fgValues[VarManager::kCentVZERO], -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, collision.centFT0C()); } else { - eventExtended(bc.globalBC(), bc.triggerMask(), bc.timestamp(), triggerAliases, VarManager::fgValues[VarManager::kCentVZERO], -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); + eventExtended(bc.globalBC(), collision.alias_raw(), collision.selection_raw(), bc.timestamp(), VarManager::fgValues[VarManager::kCentVZERO], -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); } eventVtxCov(collision.covXX(), collision.covXY(), collision.covXZ(), collision.covYY(), collision.covYZ(), collision.covZZ(), collision.chi2()); + eventInfo(collision.globalIndex()); // make an entry for this MC event only if it was not already added to the table if (!(fEventLabels.find(mcCollision.globalIndex()) != fEventLabels.end())) { eventMC(mcCollision.generatorsID(), mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), @@ -451,6 +466,13 @@ struct TableMakerMC { fCounters[1]++; } eventMClabels(fEventLabels.find(mcCollision.globalIndex())->second, collision.mcMask()); + if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionMultExtra) > 0) { + multPV(collision.multNTracksHasITS(), collision.multNTracksHasTPC(), collision.multNTracksHasTOF(), collision.multNTracksHasTRD(), + collision.multNTracksITSOnly(), collision.multNTracksTPCOnly(), collision.multNTracksITSTPC(), + collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + multAll(collision.multAllTracksTPCOnly(), collision.multAllTracksITSTPC(), + 0, 0, 0.0, 0.0, 0.0, 0.0, 0, 0, 0.0, 0.0, 0.0, 0.0); + } // loop over the MC truth tracks and find those that need to be written auto groupedMcTracks = mcTracks.sliceBy(perMcCollision, mcCollision.globalIndex()); @@ -462,12 +484,12 @@ struct TableMakerMC { bool checked = false; if constexpr (soa::is_soa_filtered_v) { auto mctrack_raw = groupedMcTracks.rawIteratorAt(mctrack.globalIndex()); - checked = sig.CheckSignal(false, mctrack_raw); + checked = sig.CheckSignal(true, mctrack_raw); } else { - checked = sig.CheckSignal(false, mctrack); + checked = sig.CheckSignal(true, mctrack); } if (checked) { - mcflags |= (uint16_t(1) << i); + mcflags |= (static_cast(1) << i); } i++; } @@ -488,7 +510,7 @@ struct TableMakerMC { VarManager::FillTrackMC(mcTracks, mctrack); int j = 0; for (auto signal = fMCSignals.begin(); signal != fMCSignals.end(); signal++, j++) { - if (mcflags & (uint16_t(1) << j)) { + if (mcflags & (static_cast(1) << j)) { fHistMan->FillHistClass(Form("MCTruth_%s", (*signal).GetName()), VarManager::fgValues); } } @@ -499,6 +521,7 @@ struct TableMakerMC { int isAmbiguous = 0; // loop over reconstructed tracks if constexpr (static_cast(TTrackFillMap)) { + trackBarrelInfo.reserve(tracksBarrel.size()); trackBasic.reserve(tracksBarrel.size()); trackBarrel.reserve(tracksBarrel.size()); trackBarrelPID.reserve(tracksBarrel.size()); @@ -521,8 +544,8 @@ struct TableMakerMC { } } } - trackFilteringTag = uint64_t(0); - trackTempFilterMap = uint8_t(0); + trackFilteringTag = static_cast(0); + trackTempFilterMap = static_cast(0); VarManager::FillTrack(track); // If no MC particle is found, skip the track if (!track.has_mcParticle()) { @@ -558,23 +581,23 @@ struct TableMakerMC { // store filtering information if (track.isGlobalTrack()) { - trackFilteringTag |= (uint64_t(1) << 0); // BIT0: global track + trackFilteringTag |= (static_cast(1) << 0); // BIT0: global track } if (track.isGlobalTrackSDD()) { - trackFilteringTag |= (uint64_t(1) << 1); // BIT1: global track SSD + trackFilteringTag |= (static_cast(1) << 1); // BIT1: global track SSD } if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackV0Bits)) { // BIT2-6: V0Bits - trackFilteringTag |= (uint64_t(track.pidbit()) << 2); + trackFilteringTag |= (static_cast(track.pidbit()) << 2); for (int iv0 = 0; iv0 < 5; iv0++) { - if (track.pidbit() & (uint8_t(1) << iv0)) { + if (track.pidbit() & (static_cast(1) << iv0)) { (reinterpret_cast(fStatsList->At(1)))->Fill(fTrackCuts.size() + static_cast(iv0)); } } } if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::DalitzBits)) { - trackFilteringTag |= (uint64_t(track.dalitzBits()) << 7); // BIT7-14: Dalitz + trackFilteringTag |= (static_cast(track.dalitzBits()) << 7); // BIT7-14: Dalitz } - trackFilteringTag |= (uint64_t(trackTempFilterMap) << 15); // BIT15-...: user track filters + trackFilteringTag |= (static_cast(trackTempFilterMap) << 15); // BIT15-...: user track filters mcflags = 0; i = 0; // runs over the MC signals @@ -582,7 +605,7 @@ struct TableMakerMC { // check all the specified signals and fill histograms for MC truth matched tracks for (auto& sig : fMCSignals) { if (sig.CheckSignal(true, mctrack)) { - mcflags |= (uint16_t(1) << i); + mcflags |= (static_cast(1) << i); if (fDoDetailedQA) { j = 0; for (auto& cut : fTrackCuts) { @@ -606,6 +629,7 @@ struct TableMakerMC { fCounters[0]++; } + trackBarrelInfo(track.collisionId(), collision.posX(), collision.posY(), collision.posZ(), track.globalIndex()); trackBasic(event.lastIndex(), trackFilteringTag, track.pt(), track.eta(), track.phi(), track.sign(), isAmbiguous); trackBarrel(track.x(), track.alpha(), track.y(), track.z(), track.snp(), track.tgl(), track.signed1Pt(), track.tpcInnerParam(), track.flags(), track.itsClusterMap(), track.itsChi2NCl(), @@ -631,6 +655,71 @@ struct TableMakerMC { } // end loop over reconstructed tracks } // end if constexpr (static_cast(TTrackFillMap)) + // Maps for the MFT-muon matching index + std::map newMFTTableSize; // key : oldMFTIndex, value: size of the table-1 at step key + std::map mftOffsets; // key: mftoldglobalindex, value: mft.offsets + + if constexpr (static_cast(TMFTFillMap)) { + trackMFT.reserve(mftTracks.size()); + trackMFTExtra.reserve(mftTracks.size()); + // TODO add cuts on the MFT tracks + // int nDel = 0; + for (auto& mft : mftTracks) { + if (false) // for now no cuts + { + // nDel++; + } else { // it passes the cuts and will be saved in the tables + newMFTTableSize[mft.index()] = trackMFT.lastIndex(); + } + + // Check MC matching + if (!mft.has_mcParticle()) { + continue; + } + auto mctrack = mft.template mcParticle_as(); + + mcflags = 0; + int i = 0; // runs over the MC signals + // check all the specified signals and fill histograms for MC truth matched tracks + for (auto& sig : fMCSignals) { + if (sig.CheckSignal(true, mctrack)) { + mcflags |= (static_cast(1) << i); + } + i++; + } + + // if the MC truth particle corresponding to this reconstructed track is not already written, + // add it to the skimmed stack + if (!(fNewLabels.find(mctrack.globalIndex()) != fNewLabels.end())) { + fNewLabels[mctrack.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); + fMCFlags[mctrack.globalIndex()] = mcflags; + fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; + fCounters[0]++; + } + + mftOffsets[mft.globalIndex()] = mft.offsets(); + + double chi2 = mft.chi2(); + SMatrix5 tpars(mft.x(), mft.y(), mft.phi(), mft.tgl(), mft.signed1Pt()); + std::vector v1; + SMatrix55 tcovs(v1.begin(), v1.end()); + o2::track::TrackParCovFwd pars1{mft.z(), tpars, tcovs, chi2}; + pars1.propagateToZlinear(collision.posZ()); + + double dcaX = (pars1.getX() - collision.posX()); + double dcaY = (pars1.getY() - collision.posY()); + + VarManager::FillTrack(mft); + fHistMan->FillHistClass("MftTracks", VarManager::fgValues); + + trackMFT(event.lastIndex(), trackFilteringTag, mft.pt(), mft.eta(), mft.phi()); + trackMFTExtra(mft.mftClusterSizesAndTrackFlags(), mft.sign(), dcaX, dcaY, mft.nClusters()); + trackMFTLabels(fNewLabels.find(mctrack.index())->second, mft.mcMask(), mcflags); + } // end of mft : mftTracks + + } // end if constexpr (TMFTFillMap) + if constexpr (static_cast(TMuonFillMap)) { // build the muon tables muonBasic.reserve(tracksMuon.size()); @@ -648,10 +737,11 @@ struct TableMakerMC { int idxPrev = -1; std::map newEntryNb; std::map newMatchIndex; + std::map newMFTMatchIndex; for (auto& muon : groupedMuons) { - trackFilteringTag = uint64_t(0); - trackTempFilterMap = uint8_t(0); + trackFilteringTag = static_cast(0); + trackTempFilterMap = static_cast(0); if (!muon.has_mcParticle()) { continue; @@ -672,10 +762,6 @@ struct TableMakerMC { for (auto& cut : fMuonCuts) { if (cut.IsSelected(VarManager::fgValues)) { trackTempFilterMap |= (uint8_t(1) << i); - if (fConfigQA) { - fHistMan->FillHistClass(Form("Muons_%s", cut.GetName()), VarManager::fgValues); - } - (reinterpret_cast(fStatsList->At(2)))->Fill(static_cast(i)); } i++; } @@ -700,8 +786,8 @@ struct TableMakerMC { } } - trackFilteringTag = uint64_t(0); - trackTempFilterMap = uint8_t(0); + trackFilteringTag = static_cast(0); + trackTempFilterMap = static_cast(0); if (!muon.has_mcParticle()) { continue; @@ -724,7 +810,6 @@ struct TableMakerMC { for (auto& cut : fMuonCuts) { if (cut.IsSelected(VarManager::fgValues)) { trackTempFilterMap |= (uint8_t(1) << i); - fHistMan->FillHistClass(Form("Muons_%s", cut.GetName()), VarManager::fgValues); if (fIsAmbiguous && isAmbiguous == 1) { fHistMan->FillHistClass(Form("Ambiguous_Muons_%s", cut.GetName()), VarManager::fgValues); } @@ -736,7 +821,7 @@ struct TableMakerMC { continue; } // store the cut decisions - trackFilteringTag |= uint64_t(trackTempFilterMap); // BIT0-7: user selection cuts + trackFilteringTag |= static_cast(trackTempFilterMap); // BIT0-7: user selection cuts mcflags = 0; i = 0; // runs over the MC signals @@ -744,7 +829,7 @@ struct TableMakerMC { // check all the specified signals and fill histograms for MC truth matched tracks for (auto& sig : fMCSignals) { if (sig.CheckSignal(true, mctrack)) { - mcflags |= (uint16_t(1) << i); + mcflags |= (static_cast(1) << i); if (fDoDetailedQA) { for (auto& cut : fMuonCuts) { if (trackTempFilterMap & (uint8_t(1) << j)) { @@ -771,9 +856,13 @@ struct TableMakerMC { if (static_cast(muon.trackType()) == 0 || static_cast(muon.trackType()) == 2) { // MCH-MFT or GLB track int matchIdx = muon.matchMCHTrackId() - muon.offsets(); + int matchMFTIdx = muon.matchMFTTrackId() - mftOffsets[muon.matchMFTTrackId()]; + + // first for MCH matching index if (newEntryNb.count(matchIdx) > 0) { // if the key exists which means the match will not get deleted newMatchIndex[muon.index()] = newEntryNb[matchIdx]; // update the match for this muon to the updated entry of the match newMatchIndex[muon.index()] += muonBasic.lastIndex() + 1 - newEntryNb[muon.index()]; // adding the offset of muons, muonBasic.lastIndex() start at -1 + if (static_cast(muon.trackType()) == 0) { // for now only do this to global tracks newMatchIndex[matchIdx] = newEntryNb[muon.index()]; // add the updated index of this muon as a match to mch track newMatchIndex[matchIdx] += muonBasic.lastIndex() + 1 - newEntryNb[muon.index()]; // adding the offset, muonBasic.lastIndex() start at -1 @@ -781,6 +870,14 @@ struct TableMakerMC { } else { newMatchIndex[muon.index()] = -1; } + + // then for MFT match index + if (newMFTTableSize.count(matchMFTIdx) > 0) { // if the key exists i.e the match will not get deleted + newMFTMatchIndex[muon.index()] = newMFTTableSize[matchMFTIdx] + 1; // adding the offset of mfts, newMFTTableSize start at -1 + } else { + newMFTMatchIndex[muon.index()] = -1; + } + } else if (static_cast(muon.trackType() == 4)) { // an MCH track // in this case the matches should be filled from the other types but we need to check if (newMatchIndex.count(muon.index()) == 0) { @@ -788,7 +885,7 @@ struct TableMakerMC { } } - muonBasic(event.lastIndex(), newMatchIndex.find(muon.index())->second, -1, trackFilteringTag, VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], muon.sign(), isAmbiguous); + muonBasic(event.lastIndex(), newMatchIndex.find(muon.index())->second, newMFTMatchIndex.find(muon.index())->second, trackFilteringTag, VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], muon.sign(), isAmbiguous); if constexpr (static_cast(TMuonFillMap & VarManager::ObjTypes::MuonCov)) { if (fPropMuon) { muonExtra(muon.nClusters(), VarManager::fgValues[VarManager::kMuonPDca], VarManager::fgValues[VarManager::kMuonRAtAbsorberEnd], @@ -796,6 +893,12 @@ struct TableMakerMC { muon.matchScoreMCHMFT(), muon.mchBitMap(), muon.midBitMap(), muon.midBoards(), muon.trackType(), VarManager::fgValues[VarManager::kMuonDCAx], VarManager::fgValues[VarManager::kMuonDCAy], muon.trackTime(), muon.trackTimeRes()); + } else { + muonExtra(muon.nClusters(), muon.pDca(), muon.rAtAbsorberEnd(), + muon.chi2(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), + muon.matchScoreMCHMFT(), muon.mchBitMap(), muon.midBitMap(), + muon.midBoards(), muon.trackType(), muon.fwdDcaX(), muon.fwdDcaY(), + muon.trackTime(), muon.trackTimeRes()); } muonCov(VarManager::fgValues[VarManager::kX], VarManager::fgValues[VarManager::kY], VarManager::fgValues[VarManager::kZ], VarManager::fgValues[VarManager::kPhi], VarManager::fgValues[VarManager::kTgl], muon.sign() / VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kMuonCXX], VarManager::fgValues[VarManager::kMuonCXY], VarManager::fgValues[VarManager::kMuonCYY], VarManager::fgValues[VarManager::kMuonCPhiX], VarManager::fgValues[VarManager::kMuonCPhiY], VarManager::fgValues[VarManager::kMuonCPhiPhi], @@ -859,7 +962,7 @@ struct TableMakerMC { mctrack.weight(), mctrack.pt(), mctrack.eta(), mctrack.phi(), mctrack.e(), mctrack.vx(), mctrack.vy(), mctrack.vz(), mctrack.vt(), mcflags); for (unsigned int isig = 0; isig < fMCSignals.size(); isig++) { - if (mcflags & (uint16_t(1) << isig)) { + if (mcflags & (static_cast(1) << isig)) { (reinterpret_cast(fStatsList->At(3)))->Fill(static_cast(isig)); } } @@ -877,114 +980,652 @@ struct TableMakerMC { fEventLabels.clear(); } - void DefineHistograms(TString histClasses) + // Templated function instantianed for all of the process functions + template + void fullSkimmingIndices(TEvent const& collisions, aod::BCsWithTimestamps const&, TTracks const& tracksBarrel, TMuons const& tracksMuon, aod::McCollisions const& /*mcEvents*/, aod::McParticles_001 const& mcTracks, AssocTracks const& trackIndices, AssocMuons const& fwdtrackIndices) { - std::unique_ptr objArray(histClasses.Tokenize(";")); - for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { - TString classStr = objArray->At(iclass)->GetName(); - if (fConfigQA) { - fHistMan->AddHistClass(classStr.Data()); - } + // Loop over collisions and produce skimmed data tables for: + // 1) all selected collisions + // 2) all MC collisions pointed to by selected collisions + // 2.1) MC collision labels + // 3) all selected tracks + // 4) MC track labels + // Maps of indices are stored for all selected MC tracks (selected MC signals + MC truth particles for selected tracks) + // The MC particles table is generated in a separate loop over McParticles, after the indices for all MC particles we want + // to store are fed into the ordered std maps - TString histEventName = fConfigAddEventHistogram.value; - if (classStr.Contains("Event")) { - if (fConfigQA) { - dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "event", histEventName); - } - } + // temporary variables used for the indexing of the skimmed MC stack + std::map fNewLabels; + std::map fNewLabelsReversed; + std::map fMCFlags; + std::map fEventIdx; + std::map fEventLabels; + int fCounters[2] = {0, 0}; //! [0] - particle counter, [1] - event counter - TString histTrackName = fConfigAddTrackHistogram.value; - if (classStr.Contains("Track")) { - if (fConfigQA) { - dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "track", histTrackName); + uint16_t mcflags = 0; + uint64_t trackFilteringTag = 0; + uint8_t trackTempFilterMap = 0; + + for (auto& collision : collisions) { + // TODO: investigate the collisions without corresponding mcCollision + if (!collision.has_mcCollision()) { + continue; + } + auto bc = collision.template bc_as(); + if (fCurrentRun != bc.runNumber()) { + if (fIsRun2 == true) { + grpmagrun2 = fCCDB->getForTimeStamp(grpmagPathRun2, bc.timestamp()); + if (grpmagrun2 != nullptr) { + o2::base::Propagator::initFieldFromGRP(grpmagrun2); + } + } else { + grpmag = fCCDB->getForTimeStamp(grpmagPath, bc.timestamp()); + if (grpmag != nullptr) { + o2::base::Propagator::initFieldFromGRP(grpmag); + } + if (fPropMuon) { + VarManager::SetupMuonMagField(); + } } + fCurrentRun = bc.runNumber(); } - TString histMuonName = fConfigAddMuonHistogram.value; - if (classStr.Contains("Muons")) { - if (fConfigQA) { - dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "track", histMuonName); - } + // get the trigger aliases + uint32_t triggerAliases = collision.alias_raw(); + // store the selection decisions + uint64_t tag = collision.selection_raw(); + if (collision.sel7()) { + tag |= (static_cast(1) << evsel::kNsel); //! SEL7 stored at position kNsel in the tag bit map } - TString histMCTruthName = fConfigAddMCTruthHistogram.value; - if (classStr.Contains("MCTruth")) { - if (fConfigQA) { - dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "mctruth", histMCTruthName); + auto mcCollision = collision.mcCollision(); + VarManager::ResetValues(0, VarManager::kNEventWiseVariables); + VarManager::fgValues[VarManager::kRunNo] = bc.runNumber(); + VarManager::fgValues[VarManager::kBC] = bc.globalBC(); + VarManager::fgValues[VarManager::kTimestamp] = bc.timestamp(); + VarManager::FillEvent(collision); // extract event information and place it in the fValues array + VarManager::FillEvent(mcCollision); + + if (fDoDetailedQA) { + fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); + } + // fill stats information, before selections + for (int i = 0; i < kNaliases; i++) { + if (triggerAliases & (static_cast(1) << i)) { + (reinterpret_cast(fStatsList->At(0)))->Fill(2.0, static_cast(i)); } } - } + (reinterpret_cast(fStatsList->At(0)))->Fill(2.0, static_cast(kNaliases)); - // create statistics histograms (event, tracks, muons, MCsignals) - fStatsList.setObject(new TList()); - fStatsList->SetOwner(kTRUE); - std::vector eventLabels{"BCs", "Collisions before filtering", "Before cuts", "After cuts"}; - TH2I* histEvents = new TH2I("EventStats", "Event statistics", eventLabels.size(), -0.5, eventLabels.size() - 0.5, (float)kNaliases + 1, -0.5, (float)kNaliases + 0.5); - int ib = 1; - for (auto label = eventLabels.begin(); label != eventLabels.end(); label++, ib++) { - histEvents->GetXaxis()->SetBinLabel(ib, (*label).Data()); - } - for (int ib = 1; ib <= kNaliases; ib++) { - histEvents->GetYaxis()->SetBinLabel(ib, aliasLabels[ib - 1].data()); - } - histEvents->GetYaxis()->SetBinLabel(kNaliases + 1, "Total"); - fStatsList->Add(histEvents); + if (!fEventCut->IsSelected(VarManager::fgValues)) { + continue; + } - // Track statistics: one bin for each track selection and 5 bins for V0 tags (gamma, K0s, Lambda, anti-Lambda, Omega) - TH1I* histTracks = new TH1I("TrackStats", "Track statistics", fTrackCuts.size() + 5.0, -0.5, fTrackCuts.size() - 0.5 + 5.0); - ib = 1; - for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, ib++) { - histTracks->GetXaxis()->SetBinLabel(ib, (*cut).GetName()); - } - const char* v0TagNames[5] = {"Photon conversion", "K^{0}_{s}", "#Lambda", "#bar{#Lambda}", "#Omega"}; - for (int ib = 0; ib < 5; ib++) { - histTracks->GetXaxis()->SetBinLabel(fTrackCuts.size() + 1 + ib, v0TagNames[ib]); - } - fStatsList->Add(histTracks); - TH1I* histMuons = new TH1I("MuonStats", "Muon statistics", fMuonCuts.size(), -0.5, fMuonCuts.size() - 0.5); - ib = 1; - for (auto cut = fMuonCuts.begin(); cut != fMuonCuts.end(); cut++, ib++) { - histMuons->GetXaxis()->SetBinLabel(ib, (*cut).GetName()); - } - fStatsList->Add(histMuons); - TH1I* histMCsignals = new TH1I("MCsignals", "MC signals", fMCSignals.size() + 1, -0.5, fMCSignals.size() - 0.5 + 1.0); - ib = 1; - for (auto signal = fMCSignals.begin(); signal != fMCSignals.end(); signal++, ib++) { - histMCsignals->GetXaxis()->SetBinLabel(ib, (*signal).GetName()); - } - histMCsignals->GetXaxis()->SetBinLabel(fMCSignals.size() + 1, "Others (matched to reco tracks)"); - fStatsList->Add(histMCsignals); - } + if (fConfigQA) { + fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); + } - // Produce barrel + muon tables ------------------------------------------------------------------------------------ - void processFull(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksBarrel, soa::Filtered const& tracksMuon, - aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks) - { - fullSkimming(collisions, bcs, tracksBarrel, tracksMuon, mcEvents, mcTracks, nullptr, nullptr); - } + // fill stats information, after selections + for (int i = 0; i < kNaliases; i++) { + if (triggerAliases & (static_cast(1) << i)) { + (reinterpret_cast(fStatsList->At(0)))->Fill(3.0, static_cast(i)); + } + } + (reinterpret_cast(fStatsList->At(0)))->Fill(3.0, static_cast(kNaliases)); - void processFullWithCov(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksBarrel, soa::Filtered const& tracksMuon, - aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks) - { - fullSkimming(collisions, bcs, tracksBarrel, tracksMuon, mcEvents, mcTracks, nullptr, nullptr); - } + event(tag, bc.runNumber(), collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), collision.collisionTime(), collision.collisionTimeRes()); + if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionMult) > 0 && (TEventFillMap & VarManager::ObjTypes::CollisionCent) > 0) { + eventExtended(collision.bc().globalBC(), collision.bc().triggerMask(), 0, triggerAliases, VarManager::fgValues[VarManager::kCentVZERO], + collision.multTPC(), collision.multFV0A(), collision.multFV0C(), collision.multFT0A(), collision.multFT0C(), + collision.multFDDA(), collision.multFDDC(), collision.multZNA(), collision.multZNC(), collision.multTracklets(), collision.multNTracksPV(), + collision.centFT0C()); + } else if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionMult) > 0) { + eventExtended(bc.globalBC(), bc.triggerMask(), bc.timestamp(), triggerAliases, VarManager::fgValues[VarManager::kCentVZERO], + collision.multTPC(), collision.multFV0A(), collision.multFV0C(), collision.multFT0A(), collision.multFT0C(), + collision.multFDDA(), collision.multFDDC(), collision.multZNA(), collision.multZNC(), collision.multTracklets(), collision.multNTracksPV(), + -1); + } else if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionCent) > 0) { + eventExtended(bc.globalBC(), bc.triggerMask(), bc.timestamp(), triggerAliases, VarManager::fgValues[VarManager::kCentVZERO], + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, collision.centFT0C()); + } else { + eventExtended(bc.globalBC(), bc.triggerMask(), bc.timestamp(), triggerAliases, VarManager::fgValues[VarManager::kCentVZERO], -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); + } + eventVtxCov(collision.covXX(), collision.covXY(), collision.covXZ(), collision.covYY(), collision.covYZ(), collision.covZZ(), collision.chi2()); + eventInfo(collision.globalIndex()); + // make an entry for this MC event only if it was not already added to the table + if (!(fEventLabels.find(mcCollision.globalIndex()) != fEventLabels.end())) { + eventMC(mcCollision.generatorsID(), mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), + mcCollision.t(), mcCollision.weight(), mcCollision.impactParameter()); + fEventLabels[mcCollision.globalIndex()] = fCounters[1]; + fCounters[1]++; + } + eventMClabels(fEventLabels.find(mcCollision.globalIndex())->second, collision.mcMask()); - // Produce barrel only tables ------------------------------------------------------------------------------------ - void processBarrelOnly(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksBarrel, - aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks) - { - fullSkimming(collisions, bcs, tracksBarrel, nullptr, mcEvents, mcTracks, nullptr, nullptr); - } + // loop over the MC truth tracks and find those that need to be written + auto groupedMcTracks = mcTracks.sliceBy(perMcCollision, mcCollision.globalIndex()); + for (auto& mctrack : groupedMcTracks) { + // check all the requested MC signals and fill a decision bit map + mcflags = 0; + int i = 0; + for (auto& sig : fMCSignals) { + bool checked = false; + if constexpr (soa::is_soa_filtered_v) { + auto mctrack_raw = groupedMcTracks.rawIteratorAt(mctrack.globalIndex()); + checked = sig.CheckSignal(true, mctrack_raw); + } else { + checked = sig.CheckSignal(true, mctrack); + } + if (checked) { + mcflags |= (static_cast(1) << i); + } + i++; + } + if (mcflags == 0) { + continue; + } - // Produce barrel only tables, with multiplicity ------------------------------------------------------------------------------------ - void processBarrelOnlyWithMults(MyEventsWithMults const& collisions, aod::BCsWithTimestamps const& bcs, + if (!(fNewLabels.find(mctrack.globalIndex()) != fNewLabels.end())) { + fNewLabels[mctrack.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); + fMCFlags[mctrack.globalIndex()] = mcflags; + fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; + fCounters[0]++; + + // if any of the MC signals was matched, then fill histograms and write that MC particle into the new stack + // fill histograms for each of the signals, if found + if (fConfigQA) { + VarManager::FillTrackMC(mcTracks, mctrack); + int j = 0; + for (auto signal = fMCSignals.begin(); signal != fMCSignals.end(); signal++, j++) { + if (mcflags & (static_cast(1) << j)) { + fHistMan->FillHistClass(Form("MCTruth_%s", (*signal).GetName()), VarManager::fgValues); + } + } + } + } + } // end loop over mc stack + + int isAmbiguous = 0; + // loop over reconstructed tracks + if constexpr (static_cast(TTrackFillMap)) { + trackBarrelInfo.reserve(tracksBarrel.size()); + trackBasic.reserve(tracksBarrel.size()); + trackBarrel.reserve(tracksBarrel.size()); + trackBarrelPID.reserve(tracksBarrel.size()); + trackBarrelLabels.reserve(tracksBarrel.size()); + if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackCov)) { + trackBarrelCov.reserve(tracksBarrel.size()); + } + + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + // loop over tracks + for (auto& trackId : trackIdsThisCollision) { + auto track = trackId.template track_as(); + if constexpr ((TTrackFillMap & VarManager::ObjTypes::AmbiTrack) > 0) { + if (fIsAmbiguous) { + isAmbiguous = (track.compatibleCollIds().size() != 1); + } + } + trackFilteringTag = static_cast(0); + trackTempFilterMap = static_cast(0); + VarManager::FillTrack(track); + // If no MC particle is found, skip the track + if (!track.has_mcParticle()) { + continue; + } + auto mctrack = track.template mcParticle_as(); + VarManager::FillTrackMC(mcTracks, mctrack); + + if (fDoDetailedQA) { + fHistMan->FillHistClass("TrackBarrel_BeforeCuts", VarManager::fgValues); + if (fIsAmbiguous && isAmbiguous == 1) { + fHistMan->FillHistClass("Ambiguous_TrackBarrel_BeforeCuts", VarManager::fgValues); + } + } + // apply track cuts and fill stats histogram + int i = 0; + for (auto& cut : fTrackCuts) { + if (cut.IsSelected(VarManager::fgValues)) { + trackTempFilterMap |= (uint8_t(1) << i); + if (fConfigQA) { + fHistMan->FillHistClass(Form("TrackBarrel_%s", cut.GetName()), VarManager::fgValues); // fill the reconstructed truth + if (fIsAmbiguous && isAmbiguous == 1) { + fHistMan->FillHistClass(Form("Ambiguous_TrackBarrel_%s", cut.GetName()), VarManager::fgValues); + } + } + (reinterpret_cast(fStatsList->At(1)))->Fill(static_cast(i)); + } + i++; + } + if (!trackTempFilterMap) { + continue; + } + + // store filtering information + if (track.isGlobalTrack()) { + trackFilteringTag |= (static_cast(1) << 0); // BIT0: global track + } + if (track.isGlobalTrackSDD()) { + trackFilteringTag |= (static_cast(1) << 1); // BIT1: global track SSD + } + if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackV0Bits)) { // BIT2-6: V0Bits + trackFilteringTag |= (static_cast(track.pidbit()) << 2); + for (int iv0 = 0; iv0 < 5; iv0++) { + if (track.pidbit() & (static_cast(1) << iv0)) { + (reinterpret_cast(fStatsList->At(1)))->Fill(fTrackCuts.size() + static_cast(iv0)); + } + } + } + if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::DalitzBits)) { + trackFilteringTag |= (static_cast(track.dalitzBits()) << 7); // BIT7-14: Dalitz + } + trackFilteringTag |= (static_cast(trackTempFilterMap) << 15); // BIT15-...: user track filters + + mcflags = 0; + i = 0; // runs over the MC signals + int j = 0; // runs over the track cuts + // check all the specified signals and fill histograms for MC truth matched tracks + for (auto& sig : fMCSignals) { + if (sig.CheckSignal(true, mctrack)) { + mcflags |= (static_cast(1) << i); + if (fDoDetailedQA) { + j = 0; + for (auto& cut : fTrackCuts) { + if (trackTempFilterMap & (uint8_t(1) << j)) { + fHistMan->FillHistClass(Form("TrackBarrel_%s_%s", cut.GetName(), sig.GetName()), VarManager::fgValues); // fill the reconstructed truth + } + j++; + } + } + } + i++; + } + + // if the MC truth particle corresponding to this reconstructed track is not already written, + // add it to the skimmed stack + if (!(fNewLabels.find(mctrack.globalIndex()) != fNewLabels.end())) { + fNewLabels[mctrack.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); + fMCFlags[mctrack.globalIndex()] = mcflags; + fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; + fCounters[0]++; + } + + trackBarrelInfo(track.collisionId(), collision.posX(), collision.posY(), collision.posZ(), track.globalIndex()); + trackBasic(event.lastIndex(), trackFilteringTag, track.pt(), track.eta(), track.phi(), track.sign(), isAmbiguous); + trackBarrel(track.x(), track.alpha(), track.y(), track.z(), track.snp(), track.tgl(), track.signed1Pt(), + track.tpcInnerParam(), track.flags(), track.itsClusterMap(), track.itsChi2NCl(), + track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), + track.tpcNClsShared(), track.tpcChi2NCl(), + track.trdChi2(), track.trdPattern(), track.tofChi2(), + track.length(), track.dcaXY(), track.dcaZ(), + track.trackTime(), track.trackTimeRes(), track.tofExpMom(), + track.detectorMap()); + trackBarrelPID(track.tpcSignal(), + track.tpcNSigmaEl(), track.tpcNSigmaMu(), + track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), + track.beta(), + track.tofNSigmaEl(), track.tofNSigmaMu(), + track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), + track.trdSignal()); + trackBarrelLabels(fNewLabels.find(mctrack.index())->second, track.mcMask(), mcflags); + if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackCov)) { + trackBarrelCov(track.cYY(), track.cZY(), track.cZZ(), track.cSnpY(), track.cSnpZ(), + track.cSnpSnp(), track.cTglY(), track.cTglZ(), track.cTglSnp(), track.cTglTgl(), + track.c1PtY(), track.c1PtZ(), track.c1PtSnp(), track.c1PtTgl(), track.c1Pt21Pt2()); + } + } // end loop over reconstructed tracks + } // end if constexpr (static_cast(TTrackFillMap)) + + if constexpr (static_cast(TMuonFillMap)) { + // build the muon tables + muonBasic.reserve(tracksMuon.size()); + muonExtra.reserve(tracksMuon.size()); + if constexpr (static_cast(TMuonFillMap & VarManager::ObjTypes::MuonCov)) { + muonCov.reserve(tracksMuon.size()); + } + muonLabels.reserve(tracksMuon.size()); // TODO: enable this once we have fwdtrack labels + + auto fwdtrackIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); + // loop over muons + + // first we need to get the correct indices + int nDel = 0; + int idxPrev = -1; + std::map newEntryNb; + std::map newMatchIndex; + std::map newMFTMatchIndex; + + for (auto& muonId : fwdtrackIdsThisCollision) { + auto muon = muonId.template fwdtrack_as(); + trackFilteringTag = static_cast(0); + trackTempFilterMap = static_cast(0); + + if (!muon.has_mcParticle()) { + continue; + } + + VarManager::FillTrack(muon); + if (fPropMuon) { + VarManager::FillPropagateMuon(muon, collision); + } + + if (muon.index() > idxPrev + 1) { // checks if some muons are filtered even before the skimming function + nDel += muon.index() - (idxPrev + 1); + } + idxPrev = muon.index(); + + // check the cuts and filters + int i = 0; + for (auto& cut : fMuonCuts) { + if (cut.IsSelected(VarManager::fgValues)) { + trackTempFilterMap |= (uint8_t(1) << i); + } + i++; + } + if (!trackTempFilterMap) { // does not pass the cuts + nDel++; + } else { // it passes the cuts and will be saved in the tables + newEntryNb[muon.index()] = muon.index() - nDel; + } + } + + // now let's save the muons with the correct indices and matches + for (auto& muonId : fwdtrackIdsThisCollision) { + auto muon = muonId.template fwdtrack_as(); + if constexpr ((TMuonFillMap & VarManager::ObjTypes::AmbiMuon) > 0) { + if (fIsAmbiguous) { + isAmbiguous = (muon.compatibleCollIds().size() != 1); + } + } + + trackFilteringTag = static_cast(0); + trackTempFilterMap = static_cast(0); + + if (!muon.has_mcParticle()) { + continue; + } + auto mctrack = muon.template mcParticle_as(); + VarManager::FillTrack(muon); + // recalculte DCA and pDca for global muon tracks + VarManager::FillTrackCollision(muon, collision); + if (fPropMuon) { + VarManager::FillPropagateMuon(muon, collision); + } + VarManager::FillTrackMC(mcTracks, mctrack); + + if (fDoDetailedQA) { + fHistMan->FillHistClass("Muons_BeforeCuts", VarManager::fgValues); + if (fIsAmbiguous && isAmbiguous == 1) { + fHistMan->FillHistClass("Ambiguous_Muons_BeforeCuts", VarManager::fgValues); + } + } + // apply the muon selection cuts and fill the stats histogram + int i = 0; + for (auto& cut : fMuonCuts) { + if (cut.IsSelected(VarManager::fgValues)) { + trackTempFilterMap |= (uint8_t(1) << i); + fHistMan->FillHistClass(Form("Muons_%s", cut.GetName()), VarManager::fgValues); + if (fIsAmbiguous && isAmbiguous == 1) { + fHistMan->FillHistClass(Form("Ambiguous_Muons_%s", cut.GetName()), VarManager::fgValues); + } + (reinterpret_cast(fStatsList->At(2)))->Fill(static_cast(i)); + } + i++; + } + if (!trackTempFilterMap) { + continue; + } + // store the cut decisions + trackFilteringTag |= static_cast(trackTempFilterMap); // BIT0-7: user selection cuts + + mcflags = 0; + i = 0; // runs over the MC signals + int j = 0; // runs over the track cuts + // check all the specified signals and fill histograms for MC truth matched tracks + for (auto& sig : fMCSignals) { + if (sig.CheckSignal(true, mctrack)) { + mcflags |= (static_cast(1) << i); + if (fDoDetailedQA) { + for (auto& cut : fMuonCuts) { + if (trackTempFilterMap & (uint8_t(1) << j)) { + fHistMan->FillHistClass(Form("Muons_%s_%s", cut.GetName(), sig.GetName()), VarManager::fgValues); // fill the reconstructed truth + } + j++; + } + } + } + i++; + } + + // if the MC truth particle corresponding to this reconstructed track is not already written, + // add it to the skimmed stack + if (!(fNewLabels.find(mctrack.globalIndex()) != fNewLabels.end())) { + fNewLabels[mctrack.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); + fMCFlags[mctrack.globalIndex()] = mcflags; + fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; + fCounters[0]++; + } + + // update the matching MCH/MFT index + + if (static_cast(muon.trackType()) == 0 || static_cast(muon.trackType()) == 2) { // MCH-MFT or GLB track + int matchIdx = muon.matchMCHTrackId() - muon.offsets(); + if (newEntryNb.count(matchIdx) > 0) { // if the key exists which means the match will not get deleted + newMatchIndex[muon.index()] = newEntryNb[matchIdx]; // update the match for this muon to the updated entry of the match + newMatchIndex[muon.index()] += muonBasic.lastIndex() + 1 - newEntryNb[muon.index()]; // adding the offset of muons, muonBasic.lastIndex() start at -1 + if (static_cast(muon.trackType()) == 0) { // for now only do this to global tracks + newMatchIndex[matchIdx] = newEntryNb[muon.index()]; // add the updated index of this muon as a match to mch track + newMatchIndex[matchIdx] += muonBasic.lastIndex() + 1 - newEntryNb[muon.index()]; // adding the offset, muonBasic.lastIndex() start at -1 + } + } else { + newMatchIndex[muon.index()] = -1; + } + } else if (static_cast(muon.trackType() == 4)) { // an MCH track + // in this case the matches should be filled from the other types but we need to check + if (newMatchIndex.count(muon.index()) == 0) { + newMatchIndex[muon.index()] = -1; + } + } + + muonBasic(event.lastIndex(), newMatchIndex.find(muon.index())->second, -1, trackFilteringTag, VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], muon.sign(), isAmbiguous); + if constexpr (static_cast(TMuonFillMap & VarManager::ObjTypes::MuonCov)) { + if (fPropMuon) { + muonExtra(muon.nClusters(), VarManager::fgValues[VarManager::kMuonPDca], VarManager::fgValues[VarManager::kMuonRAtAbsorberEnd], + muon.chi2(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), + muon.matchScoreMCHMFT(), muon.mchBitMap(), muon.midBitMap(), + muon.midBoards(), muon.trackType(), VarManager::fgValues[VarManager::kMuonDCAx], VarManager::fgValues[VarManager::kMuonDCAy], + muon.trackTime(), muon.trackTimeRes()); + } + muonCov(VarManager::fgValues[VarManager::kX], VarManager::fgValues[VarManager::kY], VarManager::fgValues[VarManager::kZ], VarManager::fgValues[VarManager::kPhi], VarManager::fgValues[VarManager::kTgl], muon.sign() / VarManager::fgValues[VarManager::kPt], + VarManager::fgValues[VarManager::kMuonCXX], VarManager::fgValues[VarManager::kMuonCXY], VarManager::fgValues[VarManager::kMuonCYY], VarManager::fgValues[VarManager::kMuonCPhiX], VarManager::fgValues[VarManager::kMuonCPhiY], VarManager::fgValues[VarManager::kMuonCPhiPhi], + VarManager::fgValues[VarManager::kMuonCTglX], VarManager::fgValues[VarManager::kMuonCTglY], VarManager::fgValues[VarManager::kMuonCTglPhi], VarManager::fgValues[VarManager::kMuonCTglTgl], VarManager::fgValues[VarManager::kMuonC1Pt2X], VarManager::fgValues[VarManager::kMuonC1Pt2Y], + VarManager::fgValues[VarManager::kMuonC1Pt2Phi], VarManager::fgValues[VarManager::kMuonC1Pt2Tgl], VarManager::fgValues[VarManager::kMuonC1Pt21Pt2]); + } else { + muonExtra(muon.nClusters(), muon.pDca(), muon.rAtAbsorberEnd(), + muon.chi2(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), + muon.matchScoreMCHMFT(), muon.mchBitMap(), muon.midBitMap(), + muon.midBoards(), muon.trackType(), muon.fwdDcaX(), muon.fwdDcaY(), + muon.trackTime(), muon.trackTimeRes()); + } + muonLabels(fNewLabels.find(mctrack.index())->second, muon.mcMask(), mcflags); + } + } // end if constexpr (static_cast(TMuonFillMap)) + } // end loop over collisions + + // Loop over the label map, create the mother/daughter relationships if these exist and write the skimmed MC stack + for (const auto& [newLabel, oldLabel] : fNewLabelsReversed) { + auto mctrack = mcTracks.iteratorAt(oldLabel); + uint16_t mcflags = fMCFlags.find(oldLabel)->second; + + std::vector mothers; + if (mctrack.has_mothers()) { + for (auto& m : mctrack.mothersIds()) { + if (m < mcTracks.size()) { // protect against bad mother indices + if (fNewLabels.find(m) != fNewLabels.end()) { + mothers.push_back(fNewLabels.find(m)->second); + } + } else { + cout << "Mother label (" << m << ") exceeds the McParticles size (" << mcTracks.size() << ")" << endl; + cout << " Check the MC generator" << endl; + } + } + } + + // TODO: Check that the daughter slice in the skimmed table works as expected + // Note that not all daughters from the original table are preserved in the skimmed MC stack + std::vector daughters; + if (mctrack.has_daughters()) { + for (int d = mctrack.daughtersIds()[0]; d <= mctrack.daughtersIds()[1]; ++d) { + // TODO: remove this check as soon as issues with MC production are fixed + if (d < mcTracks.size()) { // protect against bad daughter indices + if (fNewLabels.find(d) != fNewLabels.end()) { + daughters.push_back(fNewLabels.find(d)->second); + } + } else { + cout << "Daughter label (" << d << ") exceeds the McParticles size (" << mcTracks.size() << ")" << endl; + cout << " Check the MC generator" << endl; + } + } + } + int daughterRange[2] = {-1, -1}; + if (daughters.size() > 0) { + daughterRange[0] = daughters[0]; + daughterRange[1] = daughters[daughters.size() - 1]; + } + + trackMC(fEventIdx.find(oldLabel)->second, mctrack.pdgCode(), mctrack.statusCode(), mctrack.flags(), + mothers, daughterRange, + mctrack.weight(), mctrack.pt(), mctrack.eta(), mctrack.phi(), mctrack.e(), + mctrack.vx(), mctrack.vy(), mctrack.vz(), mctrack.vt(), mcflags); + for (unsigned int isig = 0; isig < fMCSignals.size(); isig++) { + if (mcflags & (static_cast(1) << isig)) { + (reinterpret_cast(fStatsList->At(3)))->Fill(static_cast(isig)); + } + } + if (mcflags == 0) { + (reinterpret_cast(fStatsList->At(3)))->Fill(static_cast(fMCSignals.size())); + } + } // end loop over labels + + fCounters[0] = 0; + fCounters[1] = 0; + fNewLabels.clear(); + fNewLabelsReversed.clear(); + fMCFlags.clear(); + fEventIdx.clear(); + fEventLabels.clear(); + } + + void DefineHistograms(TString histClasses) + { + std::unique_ptr objArray(histClasses.Tokenize(";")); + for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { + TString classStr = objArray->At(iclass)->GetName(); + if (fConfigQA) { + fHistMan->AddHistClass(classStr.Data()); + } + + TString histEventName = fConfigAddEventHistogram.value; + if (classStr.Contains("Event")) { + if (fConfigQA) { + dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "event", histEventName); + } + } + + TString histTrackName = fConfigAddTrackHistogram.value; + if (classStr.Contains("Track")) { + if (fConfigQA) { + dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "track", histTrackName); + } + } + + TString histMuonName = fConfigAddMuonHistogram.value; + if (classStr.Contains("Muons")) { + if (fConfigQA) { + dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "track", histMuonName); + } + } + + TString histMCTruthName = fConfigAddMCTruthHistogram.value; + if (classStr.Contains("MCTruth")) { + if (fConfigQA) { + dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "mctruth_track", histMCTruthName); + } + } + } + + // create statistics histograms (event, tracks, muons, MCsignals) + fStatsList.setObject(new TList()); + fStatsList->SetOwner(kTRUE); + std::vector eventLabels{"BCs", "Collisions before filtering", "Before cuts", "After cuts"}; + TH2I* histEvents = new TH2I("EventStats", "Event statistics", eventLabels.size(), -0.5, eventLabels.size() - 0.5, (float)kNaliases + 1, -0.5, (float)kNaliases + 0.5); + int ib = 1; + for (auto label = eventLabels.begin(); label != eventLabels.end(); label++, ib++) { + histEvents->GetXaxis()->SetBinLabel(ib, (*label).Data()); + } + for (int ib = 1; ib <= kNaliases; ib++) { + histEvents->GetYaxis()->SetBinLabel(ib, aliasLabels[ib - 1].data()); + } + histEvents->GetYaxis()->SetBinLabel(kNaliases + 1, "Total"); + fStatsList->Add(histEvents); + + // Track statistics: one bin for each track selection and 5 bins for V0 tags (gamma, K0s, Lambda, anti-Lambda, Omega) + TH1I* histTracks = new TH1I("TrackStats", "Track statistics", fTrackCuts.size() + 5.0, -0.5, fTrackCuts.size() - 0.5 + 5.0); + ib = 1; + for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, ib++) { + histTracks->GetXaxis()->SetBinLabel(ib, (*cut).GetName()); + } + const char* v0TagNames[5] = {"Photon conversion", "K^{0}_{s}", "#Lambda", "#bar{#Lambda}", "#Omega"}; + for (int ib = 0; ib < 5; ib++) { + histTracks->GetXaxis()->SetBinLabel(fTrackCuts.size() + 1 + ib, v0TagNames[ib]); + } + fStatsList->Add(histTracks); + TH1I* histMuons = new TH1I("MuonStats", "Muon statistics", fMuonCuts.size(), -0.5, fMuonCuts.size() - 0.5); + ib = 1; + for (auto cut = fMuonCuts.begin(); cut != fMuonCuts.end(); cut++, ib++) { + histMuons->GetXaxis()->SetBinLabel(ib, (*cut).GetName()); + } + fStatsList->Add(histMuons); + TH1I* histMCsignals = new TH1I("MCsignals", "MC signals", fMCSignals.size() + 1, -0.5, fMCSignals.size() - 0.5 + 1.0); + ib = 1; + for (auto signal = fMCSignals.begin(); signal != fMCSignals.end(); signal++, ib++) { + histMCsignals->GetXaxis()->SetBinLabel(ib, (*signal).GetName()); + } + histMCsignals->GetXaxis()->SetBinLabel(fMCSignals.size() + 1, "Others (matched to reco tracks)"); + fStatsList->Add(histMCsignals); + } + + // Produce barrel + muon tables ------------------------------------------------------------------------------------ + void processFull(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksBarrel, soa::Filtered const& tracksMuon, + aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks) + { + fullSkimming(collisions, bcs, tracksBarrel, tracksMuon, mcEvents, mcTracks, nullptr, nullptr, nullptr); + } + + void processFullWithCov(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksBarrel, soa::Filtered const& tracksMuon, + aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks) + { + fullSkimming(collisions, bcs, tracksBarrel, tracksMuon, mcEvents, mcTracks, nullptr, nullptr, nullptr); + } + + // Produce barrel only tables ------------------------------------------------------------------------------------ + void processBarrelOnly(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksBarrel, + aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks) + { + fullSkimming(collisions, bcs, tracksBarrel, nullptr, mcEvents, mcTracks, nullptr, nullptr, nullptr); + } + + // Produce barrel only tables, with multiplicity ------------------------------------------------------------------------------------ + void processBarrelOnlyWithMults(MyEventsWithMults const& collisions, aod::BCsWithTimestamps const& bcs, soa::Filtered const& tracksBarrel, aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks) { - fullSkimming(collisions, bcs, tracksBarrel, nullptr, mcEvents, mcTracks, nullptr, nullptr); + fullSkimming(collisions, bcs, tracksBarrel, nullptr, mcEvents, mcTracks, nullptr, nullptr, nullptr); } // Produce barrel only tables, with centrality ------------------------------------------------------------------------------------ @@ -992,7 +1633,7 @@ struct TableMakerMC { soa::Filtered const& tracksBarrel, aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks) { - fullSkimming(collisions, bcs, tracksBarrel, nullptr, mcEvents, mcTracks, nullptr, nullptr); + fullSkimming(collisions, bcs, tracksBarrel, nullptr, mcEvents, mcTracks, nullptr, nullptr, nullptr); } // Produce barrel only tables, with centrality and multiplicity ------------------------------------------------------------------- @@ -1000,7 +1641,7 @@ struct TableMakerMC { soa::Filtered const& tracksBarrel, aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks) { - fullSkimming(collisions, bcs, tracksBarrel, nullptr, mcEvents, mcTracks, nullptr, nullptr); + fullSkimming(collisions, bcs, tracksBarrel, nullptr, mcEvents, mcTracks, nullptr, nullptr, nullptr); } // Produce barrel only tables, with cov matrix----------------------------------------------------------------------- @@ -1008,7 +1649,15 @@ struct TableMakerMC { soa::Filtered const& tracksBarrel, aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks) { - fullSkimming(collisions, bcs, tracksBarrel, nullptr, mcEvents, mcTracks, nullptr, nullptr); + fullSkimming(collisions, bcs, tracksBarrel, nullptr, mcEvents, mcTracks, nullptr, nullptr, nullptr); + } + + // Produce barrel only tables, with centrality, multiplicity and cov matrix ------------------------------------------------------------------- + void processBarrelOnlyWithCovWithCentAndMults(MyEventsWithCentAndMults const& collisions, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksBarrel, + aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks) + { + fullSkimming(collisions, bcs, tracksBarrel, nullptr, mcEvents, mcTracks, nullptr, nullptr, nullptr); } // Produce barrel only tables, with cov matrix and dalitz bits----------------------------------------------------------------------- @@ -1016,7 +1665,7 @@ struct TableMakerMC { soa::Filtered const& tracksBarrel, aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks) { - fullSkimming(collisions, bcs, tracksBarrel, nullptr, mcEvents, mcTracks, nullptr, nullptr); + fullSkimming(collisions, bcs, tracksBarrel, nullptr, mcEvents, mcTracks, nullptr, nullptr, nullptr); } // Produce muon only tables ------------------------------------------------------------------------------------ @@ -1024,43 +1673,78 @@ struct TableMakerMC { soa::Filtered const& tracksMuon, aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks) { - fullSkimming(collisions, bcs, nullptr, tracksMuon, mcEvents, mcTracks, nullptr, nullptr); + fullSkimming(collisions, bcs, nullptr, tracksMuon, mcEvents, mcTracks, nullptr, nullptr, nullptr); } // Produce muon only tables, with centrality------------------------------------------------------------------------------- void processMuonOnlyWithCent(MyEventsWithCent const& collisions, aod::BCsWithTimestamps const& bcs, soa::Filtered const& tracksMuon, aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks) { - fullSkimming(collisions, bcs, nullptr, tracksMuon, mcEvents, mcTracks, nullptr, nullptr); + fullSkimming(collisions, bcs, nullptr, tracksMuon, mcEvents, mcTracks, nullptr, nullptr, nullptr); } // Produce muon only tables, with cov matrix ------------------------------------------------------------------------------------ void processMuonOnlyWithCov(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, soa::Filtered const& tracksMuon, aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks) { - fullSkimming(collisions, bcs, nullptr, tracksMuon, mcEvents, mcTracks, nullptr, nullptr); + fullSkimming(collisions, bcs, nullptr, tracksMuon, mcEvents, mcTracks, nullptr, nullptr, nullptr); + } + // Produce MFT tracks tables and muons ------------------------------------------------------------------------------------------------------------------ + void processMuonsAndMFT(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, + MyMftTracks const& tracksMft, MyMuonsWithCov const& tracksMuon, + aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks) + { + fullSkimming(collisions, bcs, nullptr, tracksMuon, mcEvents, mcTracks, nullptr, nullptr, tracksMft); + } + // Produce muon tables only based on track-collision association tables -------------------------------------------------------------------------------------- + void processAssociatedMuonOnly(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksMuon, + aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks, aod::FwdTrackAssoc const& fwdtrackIndices) + { + fullSkimmingIndices(collisions, bcs, nullptr, tracksMuon, mcEvents, mcTracks, nullptr, fwdtrackIndices); + } + + void processAssociatedMuonOnlyWithCov(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksMuon, + aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks, aod::FwdTrackAssoc const& fwdtrackIndices) + { + fullSkimmingIndices(collisions, bcs, nullptr, tracksMuon, mcEvents, mcTracks, nullptr, fwdtrackIndices); + } + + void processAssociatedMuonOnlyWithCovAndCent(MyEventsWithCent const& collisions, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksMuon, + aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks, aod::FwdTrackAssoc const& fwdtrackIndices) + { + fullSkimmingIndices(collisions, bcs, nullptr, tracksMuon, mcEvents, mcTracks, nullptr, fwdtrackIndices); + } + + void processAssociatedMuonOnlyWithCovAndMults(MyEventsWithCentAndMults const& collisions, aod::BCsWithTimestamps const& bcs, + soa::Filtered const& tracksMuon, + aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks, aod::FwdTrackAssoc const& fwdtrackIndices) + { + fullSkimmingIndices(collisions, bcs, nullptr, tracksMuon, mcEvents, mcTracks, nullptr, fwdtrackIndices); } // Produce muon tables only for ambiguous tracks studies -------------------------------------------------------------------------------------- void processAmbiguousMuonOnly(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, soa::Filtered const& tracksMuon, - aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks, aod::AmbiguousTracksFwd const& ambiTracksFwd) + aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks, aod::AmbiguousFwdTracks const& ambiTracksFwd) { - fullSkimming(collisions, bcs, nullptr, tracksMuon, mcEvents, mcTracks, nullptr, ambiTracksFwd); + fullSkimming(collisions, bcs, nullptr, tracksMuon, mcEvents, mcTracks, nullptr, ambiTracksFwd, nullptr); } void processAmbiguousMuonOnlyWithCov(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, soa::Filtered const& tracksMuon, - aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks, aod::AmbiguousTracksFwd const& ambiTracksFwd) + aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks, aod::AmbiguousFwdTracks const& ambiTracksFwd) { - fullSkimming(collisions, bcs, nullptr, tracksMuon, mcEvents, mcTracks, nullptr, ambiTracksFwd); + fullSkimming(collisions, bcs, nullptr, tracksMuon, mcEvents, mcTracks, nullptr, ambiTracksFwd, nullptr); } // Produce track tables only for ambiguous tracks studies ------------------------------------------------------------------------------------- void processAmbiguousBarrelOnly(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, soa::Filtered const& tracksBarrel, - aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks, aod::AmbiguousTracksMid const& ambiTracksMid) + aod::McCollisions const& mcEvents, aod::McParticles_001 const& mcTracks, aod::AmbiguousTracks const& ambiTracksMid) { - fullSkimming(collisions, bcs, tracksBarrel, nullptr, mcEvents, mcTracks, ambiTracksMid, nullptr); + fullSkimming(collisions, bcs, tracksBarrel, nullptr, mcEvents, mcTracks, ambiTracksMid, nullptr, nullptr); } // Process the BCs and store stats for luminosity retrieval ----------------------------------------------------------------------------------- void processOnlyBCs(soa::Join::iterator const& bc) @@ -1080,11 +1764,17 @@ struct TableMakerMC { PROCESS_SWITCH(TableMakerMC, processBarrelOnlyWithCent, "Produce barrel skims, w/ centrality", false); PROCESS_SWITCH(TableMakerMC, processBarrelOnlyWithCentAndMults, "Produce barrel skims, w/ centrality and mults", false); PROCESS_SWITCH(TableMakerMC, processBarrelOnlyWithCov, "Produce barrel skims, with track covariance matrix", false); + PROCESS_SWITCH(TableMakerMC, processBarrelOnlyWithCovWithCentAndMults, "Produce barrel skims, w/ centrality and mults, with track covariance matrix", false); PROCESS_SWITCH(TableMakerMC, processBarrelOnlyWithDalitzBits, "Produce barrel skims, and dalitz bits", false); PROCESS_SWITCH(TableMakerMC, processMuonOnly, "Produce muon skims", false); PROCESS_SWITCH(TableMakerMC, processMuonOnlyWithCov, "Produce muon skims, with muon covariance matrix", false); + PROCESS_SWITCH(TableMakerMC, processMuonsAndMFT, "Produce muon and MFT skims", false); PROCESS_SWITCH(TableMakerMC, processMuonOnlyWithCent, "Produce muon skims, w/ centrality", false); PROCESS_SWITCH(TableMakerMC, processOnlyBCs, "Analyze the BCs to store sampled lumi", false); + PROCESS_SWITCH(TableMakerMC, processAssociatedMuonOnly, "Produce muon skims using track-collision association tables", false); + PROCESS_SWITCH(TableMakerMC, processAssociatedMuonOnlyWithCov, "Produce muon skims using track-collision association tables, with muon covariance matrix", false); + PROCESS_SWITCH(TableMakerMC, processAssociatedMuonOnlyWithCovAndCent, "Produce muon skims using track-collision association tables, w/ centrality", false); + PROCESS_SWITCH(TableMakerMC, processAssociatedMuonOnlyWithCovAndMults, "Produce muon skims using track-collision association tables, w/ mults", false); PROCESS_SWITCH(TableMakerMC, processAmbiguousMuonOnly, "Build muon-only DQ skimmed data model with QA plots for ambiguous muons", false); PROCESS_SWITCH(TableMakerMC, processAmbiguousMuonOnlyWithCov, "Build muon-only with cov DQ skimmed data model with QA plots for ambiguous muons", false); PROCESS_SWITCH(TableMakerMC, processAmbiguousBarrelOnly, "Build barrel-only DQ skimmed data model with QA plots for ambiguous tracks", false); diff --git a/PWGDQ/TableProducer/tableMakerMC_withAssoc.cxx b/PWGDQ/TableProducer/tableMakerMC_withAssoc.cxx new file mode 100644 index 00000000000..aa35c36a0ec --- /dev/null +++ b/PWGDQ/TableProducer/tableMakerMC_withAssoc.cxx @@ -0,0 +1,1376 @@ +// 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. +// +// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no +// +// Analysis task for skimming MC AODs +// Similar to tableMaker.cxx. The written skimmed data model includes, besides the reconstructed data tables, a skimmed MC stack. +// The skimmed MC stack includes the MC truth particles corresponding to the list of user specified MC signals (see MCsignal.h) +// and the MC truth particles corresponding to the reconstructed tracks selected by the specified track cuts on reconstructed data. + +#include +#include +#include +#include +#include +#include +#include +#include "TList.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/ASoA.h" +#include "Framework/DataTypes.h" +#include "Framework/runDataProcessing.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/CCDB/TriggerAliases.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/AnalysisCut.h" +#include "PWGDQ/Core/AnalysisCompositeCut.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/MCSignal.h" +#include "PWGDQ/Core/MCSignalLibrary.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Field/MagneticField.h" +#include "TGeoGlobalMagField.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "CCDB/BasicCCDBManager.h" + +using std::cout; +using std::endl; + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod; + +// Declare Joins used in the various process functions +using MyBarrelTracks = soa::Join; +using MyBarrelTracksWithDalitzBits = soa::Join; +using MyBarrelTracksWithCov = soa::Join; +using MyMuons = soa::Join; +using MyMuonsWithCov = soa::Join; + +using MyEvents = soa::Join; +using MyEventsWithMults = soa::Join; +using MyEventsWithCent = soa::Join; +using MyEventsWithCentAndMults = soa::Join; +using MFTTrackLabeled = soa::Join; + +// Declare bit maps containing information on the table joins content (used as argument in templated functions) +constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision; +constexpr static uint32_t gkEventFillMapWithMults = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionMult | VarManager::ObjTypes::CollisionMultExtra; +// constexpr static uint32_t gkEventFillMapWithCent = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCent; +constexpr static uint32_t gkEventFillMapWithCentAndMults = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCent | VarManager::CollisionMult | VarManager::CollisionMultExtra; +// constexpr static uint32_t gkEventMCFillMap = VarManager::ObjTypes::CollisionMC; +// constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackPID; +constexpr static uint32_t gkTrackFillMapWithCov = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackCov | VarManager::ObjTypes::TrackPID; +// constexpr static uint32_t gkTrackFillMapWithDalitzBits = gkTrackFillMap | VarManager::ObjTypes::DalitzBits; +// constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::Muon; +constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::Muon | VarManager::ObjTypes::MuonCov; +// constexpr static uint32_t gkMuonFillMapWithAmbi = VarManager::ObjTypes::Muon | VarManager::ObjTypes::AmbiMuon; +// constexpr static uint32_t gkMuonFillMapWithCovAmbi = VarManager::ObjTypes::Muon | VarManager::ObjTypes::MuonCov | VarManager::ObjTypes::AmbiMuon; +// constexpr static uint32_t gkTrackFillMapWithAmbi = VarManager::ObjTypes::Track | VarManager::ObjTypes::AmbiTrack; +constexpr static uint32_t gkMFTFillMap = VarManager::ObjTypes::TrackMFT; + +template +void PrintBitMap(TMap map, int nbits) +{ + for (int i = 0; i < nbits; i++) { + cout << ((map & (TMap(1) << i)) > 0 ? "1" : "0"); + } +} + +struct TableMakerMC { + + Produces eventMC; + Produces trackMC; + + Produces event; + Produces eventExtended; + Produces eventVtxCov; + Produces eventInfo; + Produces multPV; + Produces multAll; + Produces eventMClabels; + + Produces trackBarrelInfo; + Produces trackBasic; + Produces trackBarrel; + Produces trackBarrelCov; + Produces trackBarrelPID; + Produces trackBarrelAssoc; + Produces trackBarrelLabels; + + Produces muonBasic; + Produces muonExtra; + Produces muonCov; + Produces muonAssoc; + Produces muonLabels; // TODO: enable this once we have fwdtrack labels + + Produces mftTrack; + Produces mftTrackExtra; + Produces mftAssoc; + Produces mftLabels; + + OutputObj fOutputList{"output"}; + OutputObj fStatsList{"Statistics"}; //! skimming statistics + HistogramManager* fHistMan; + + Configurable fIsRun2{"cfgIsRun2", false, "Whether we analyze Run-2 or Run-3 data"}; + + // Event and track AnalysisCut configurables + struct : ConfigurableGroup { + Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; + Configurable fConfigTrackCuts{"cfgBarrelTrackCuts", "jpsiPID1", "barrel track cut"}; + Configurable fConfigMuonCuts{"cfgMuonCuts", "muonQualityCuts", "Comma separated list of muon cuts"}; + Configurable fConfigEventCutsJSON{"cfgEventCutsJSON", "", "Additional event selection in JSON format"}; + Configurable fConfigTrackCutsJSON{"cfgBarrelTrackCutsJSON", "", "Additional list of barrel track cuts in JSON format"}; + Configurable fConfigMuonCutsJSON{"cfgMuonCutsJSON", "", "Additional list of muon cuts in JSON format"}; + } fConfigCuts; + + // MC signals to be skimmed + Configurable fConfigMCSignals{"cfgMCsignals", "", "Comma separated list of MC signals"}; + Configurable fConfigMCSignalsJSON{"cfgMCsignalsJSON", "", "Additional list of MC signals via JSON"}; + + // Steer QA output + struct : ConfigurableGroup { + Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigDetailedQA{"cfgDetailedQA", false, "If true, include more QA histograms (BeforeCuts classes)"}; + Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddMuonHistogram{"cfgAddMuonHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddMCTruthHistogram{"cfgAddMCTruthHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + } fConfigHistOutput; + + // Selections to be applied as Filter on the Track and FwdTrack + /*Configurable fConfigBarrelTrackMaxAbsEta{"cfgBarrelMaxAbsEta", 0.9f, "Eta absolute value cut for tracks in the barrel"}; + Configurable fConfigBarrelTrackMinPt{"cfgBarrelMinPt", 0.5f, "Minimum pt for tracks in the barrel"}; + Configurable fConfigBarrelMinTPCncls{"cfgBarrelMinTPCncls", 50.0f, "Minimum TPC cls for tracks in the barrel"}; + Configurable fConfigBarrelMaxTPCchi2{"cfgBarrelMaxTPCchi2", 10.0f, "Maximum TPC chi2/ndf for tracks in the barrel"}; + Configurable fConfigBarrelMaxITSchi2{"cfgBarrelMaxITSchi2", 36.0f, "Maximum ITS chi2/ndf for tracks in the barrel"}; + Configurable fConfigMuonPtLow{"cfgMuonLowPt", 1.0f, "Low pt cut for muons"}; + */ + + // CCDB connection configurables + struct : ConfigurableGroup { + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable fGeoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable fGrpMagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable fGrpMagPathRun2{"grpmagPathRun2", "GLO/GRP/GRP", "CCDB path of the GRPObject (Usage for Run 2)"}; + } fConfigCCDB; + + struct : ConfigurableGroup { + // Track related options + Configurable fPropTrack{"cfgPropTrack", true, "Propagate tracks to primary vertex"}; + // Muon related options + Configurable fPropMuon{"cfgPropMuon", true, "Propagate muon tracks through absorber (do not use if applying pairing)"}; + Configurable fRefitGlobalMuon{"cfgRefitGlobalMuon", true, "Correct global muon parameters"}; + Configurable fKeepBestMatch{"cfgKeepBestMatch", false, "Keep only the best match global muons in the skimming"}; + Configurable fMuonMatchEtaMin{"cfgMuonMatchEtaMin", -4.0f, "Definition of the acceptance of muon tracks to be matched with MFT"}; + Configurable fMuonMatchEtaMax{"cfgMuonMatchEtaMax", -2.5f, "Definition of the acceptance of muon tracks to be matched with MFT"}; + } fConfigVariousOptions; + + Service fCCDB; + o2::ccdb::CcdbApi fCCDBApi; + + o2::parameters::GRPObject* fGrpMagRun2 = nullptr; // for run 2, we access the GRPObject from GLO/GRP/GRP + o2::parameters::GRPMagField* fGrpMag = nullptr; // for run 3, we access GRPMagField from GLO/Config/GRPMagField + + AnalysisCompositeCut* fEventCut; //! Event selection cut + std::vector fTrackCuts; //! Barrel track cuts + std::vector fMuonCuts; //! Muon track cuts + + bool fDoDetailedQA = false; // Bool to set detailed QA true, if QA is set true + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + + // list of MCsignal objects + std::vector fMCSignals; + std::map fLabelsMap; + std::map fLabelsMapReversed; + std::map fMCFlags; + std::map fCollIndexMap; // key: old collision index, value: skimmed collision index + std::map fTrackIndexMap; // key: old track global index, value: new track global index + std::map fFwdTrackIndexMap; // key: fwd-track global index, value: new fwd-track global index + std::map fFwdTrackIndexMapReversed; // key: new fwd-track global index, value: fwd-track global index + std::map fFwdTrackFilterMap; // key: fwd-track global index, value: fwd-track filter map + std::map fMftIndexMap; // key: MFT tracklet global index, value: new MFT tracklet global index + + std::map fBestMatch; + + void init(o2::framework::InitContext& context) + { + // Check whether barrel or muon are enabled + bool isProcessBCenabled = context.mOptions.get("processPP"); + bool isBarrelEnabled = (context.mOptions.get("processPP") || context.mOptions.get("processPPBarrelOnly") || context.mOptions.get("processPbPbBarrelOnly")); + bool isMuonEnabled = (context.mOptions.get("processPP") || context.mOptions.get("processPPMuonOnlyBasic") || context.mOptions.get("processPPMuonOnly") || context.mOptions.get("processPbPbMuonOnly")); + // Make sure at least one process function is enabled + if (!(isProcessBCenabled || isBarrelEnabled || isMuonEnabled)) { + LOG(fatal) << "No process function was enabled for TableMakerMC. Check it out!!!"; + } + + VarManager::SetDefaultVarNames(); // Important that this is called before DefineCuts() !!! + + // Define user specified cut + DefineCuts(); + + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + // Only use detailed QA when QA is set true + if (fConfigHistOutput.fConfigQA && fConfigHistOutput.fConfigDetailedQA) { + fDoDetailedQA = true; + } + + // Create the histogram class names to be added to the histogram manager + TString histClasses = ""; + // Event histograms before any cuts + if (fDoDetailedQA) { + histClasses += "Event_BeforeCuts;"; + } + // Event histograms after cuts and for MC truth collisions + if (fConfigHistOutput.fConfigQA) { + histClasses += "Event_AfterCuts;"; + histClasses += "Event_MCTruth;"; + } + + if (isBarrelEnabled) { + // Barrel track histograms before cuts + if (fDoDetailedQA) { + histClasses += "TrackBarrel_BeforeCuts;"; + } + // Barrel track histograms after cuts; one directory per cut + if (fConfigHistOutput.fConfigQA) { + for (auto& cut : fTrackCuts) { + histClasses += Form("TrackBarrel_%s;", cut->GetName()); + } + } + } + + if (isMuonEnabled) { + // Muon track histograms before cuts + if (fDoDetailedQA) { + histClasses += "Muons_BeforeCuts;"; + } + // Muon track histograms after cuts; one directory per cut + if (fConfigHistOutput.fConfigQA) { + for (auto& muonCut : fMuonCuts) { + histClasses += Form("Muons_%s;", muonCut->GetName()); + } + } + } + + // Configure user specified MC signals and setup histogram classes + TString configNamesStr = fConfigMCSignals.value; + std::unique_ptr objArray(configNamesStr.Tokenize(",")); + if (objArray->GetEntries() > 0) { + // loop over MC signals and add them to the signals array + for (int isig = 0; isig < objArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objArray->At(isig)->GetName()); + if (sig) { + fMCSignals.push_back(sig); + } + } + } + // Adding additional signals via JSON + TString addMCSignalsStr = fConfigMCSignalsJSON.value; + if (addMCSignalsStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); + for (auto& mcIt : addMCSignals) { + if (mcIt) { + fMCSignals.push_back(mcIt); + } + } + } + + for (auto& mcIt : fMCSignals) { + if (fConfigHistOutput.fConfigQA) { + histClasses += Form("MCTruth_%s;", mcIt->GetName()); + } + if (fDoDetailedQA) { + if (isBarrelEnabled) { + // in case of detailed QA, setup histogram directories for each combination of reconstructed track cuts and MC signals + for (auto& cut : fTrackCuts) { + histClasses += Form("TrackBarrel_%s_%s;", cut->GetName(), mcIt->GetName()); + } + } + if (isMuonEnabled) { + // in case of detailed QA, setup histogram directories for each combination of reconstructed muon cuts and MC signals + for (auto& cut : fMuonCuts) { + histClasses += Form("Muons_%s_%s;", cut->GetName(), mcIt->GetName()); + } + } + } + } + + DefineHistograms(histClasses); // define all histograms + // Additional histogram via the JSON configurable + TString addHistsStr = fConfigHistOutput.fConfigAddJSONHistograms.value; + if (fConfigHistOutput.fConfigQA && addHistsStr != "") { + dqhistograms::AddHistogramsFromJSON(fHistMan, addHistsStr.Data()); + } + + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + + // Setup the CCDB + fCCDB->setURL(fConfigCCDB.fConfigCcdbUrl); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + if (!o2::base::GeometryManager::isGeometryLoaded()) { + fCCDB->get(fConfigCCDB.fGeoPath); + } + fCCDBApi.init(fConfigCCDB.fConfigCcdbUrl.value); + } + + void DefineCuts() + { + // Event cuts + fEventCut = new AnalysisCompositeCut(true); + TString eventCutStr = fConfigCuts.fConfigEventCuts.value; + fEventCut->AddCut(dqcuts::GetAnalysisCut(eventCutStr.Data())); + // Extra event cuts via JSON + TString addEvCutsStr = fConfigCuts.fConfigEventCutsJSON.value; + if (addEvCutsStr != "") { + std::vector addEvCuts = dqcuts::GetCutsFromJSON(addEvCutsStr.Data()); + for (auto& cutIt : addEvCuts) { + fEventCut->AddCut(cutIt); + } + } + + // Barrel track cuts + TString cutNamesStr = fConfigCuts.fConfigTrackCuts.value; + if (!cutNamesStr.IsNull()) { + std::unique_ptr objArray(cutNamesStr.Tokenize(",")); + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + fTrackCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + } + } + // Additional Barrel track cuts via JSON + TString addTrackCutsStr = fConfigCuts.fConfigTrackCutsJSON.value; + if (addTrackCutsStr != "") { + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + for (auto& t : addTrackCuts) { + fTrackCuts.push_back(reinterpret_cast(t)); + } + } + + // Muon cuts + cutNamesStr = fConfigCuts.fConfigMuonCuts.value; + if (!cutNamesStr.IsNull()) { + std::unique_ptr objArray(cutNamesStr.Tokenize(",")); + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + fMuonCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + } + } + // Additional muon cuts via JSON + TString addMuonCutsStr = fConfigCuts.fConfigMuonCutsJSON.value; + if (addMuonCutsStr != "") { + std::vector addMuonCuts = dqcuts::GetCutsFromJSON(addMuonCutsStr.Data()); + for (auto& t : addMuonCuts) { + fMuonCuts.push_back(reinterpret_cast(t)); + } + } + + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill + } + + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + Preslice fwdtrackIndicesPerCollision = aod::track_association::collisionId; + Preslice mfttrackIndicesPerCollision = aod::track_association::collisionId; + + void skimMCCollisions(aod::McCollisions const& mcCollisions) + { + // skim MC collisions + // NOTE: So far, all MC collisions are skimmed. In case there will be filtering based on MC collisions, + // one has to do a mapping of the old vs new indices so that the skimmed labels are properly updated. + VarManager::ResetValues(0, VarManager::kNVars); + + // Loop over MC collisions + for (auto& mcCollision : mcCollisions) { + // Get MC collision information into the VarManager + VarManager::FillEvent(mcCollision); + // Fill histograms + fHistMan->FillHistClass("Event_MCTruth", VarManager::fgValues); + // Create the skimmed table entry for this collision + eventMC(mcCollision.generatorsID(), mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), + mcCollision.t(), mcCollision.weight(), mcCollision.impactParameter()); + } + } + + void skimMCParticles(aod::McParticles const& mcTracks, aod::McCollisions const&) + { + // Select MC particles which fulfill at least one of the user specified MC signals + // In this function we just fill a map with the labels of selected particles, not creating the tables themselves. + // The reason is that in the skims we will additionally add any MC label connected to selected reconstructed tracks + // which were not selected already via the MC signals + + // Clear the label maps + fLabelsMap.clear(); + fLabelsMapReversed.clear(); + fMCFlags.clear(); + + uint16_t mcflags = static_cast(0); // flags which will hold the decisions for each MC signal + int trackCounter = 0; + + for (auto& mctrack : mcTracks) { + // check all the requested MC signals and fill the decision bit map + mcflags = 0; + int i = 0; + for (auto& sig : fMCSignals) { + bool checked = false; + if constexpr (soa::is_soa_filtered_v) { + auto mctrack_raw = mcTracks.rawIteratorAt(mctrack.globalIndex()); + checked = sig->CheckSignal(true, mctrack_raw); + } else { + checked = sig->CheckSignal(true, mctrack); + } + if (checked) { + mcflags |= (static_cast(1) << i); + } + i++; + } + + /*if ((std::abs(mctrack.pdgCode())>400 && std::abs(mctrack.pdgCode())<599) || + (std::abs(mctrack.pdgCode())>4000 && std::abs(mctrack.pdgCode())<5999) || + (mcflags > 0)) { + cout << ">>>>>>>>>>>>>>>>>>>>>>> track idx / pdg / process / status code / HEPMC status / primary : " + << mctrack.globalIndex() << " / " << mctrack.pdgCode() << " / " + << mctrack.getProcess() << " / " << mctrack.getGenStatusCode() << " / " << mctrack.getHepMCStatusCode() << " / " << mctrack.isPhysicalPrimary() << endl; + cout << ">>>>>>>>>>>>>>>>>>>>>>> track bitmap: "; + PrintBitMap(mcflags, 16); + cout << endl; + if (mctrack.has_mothers()) { + for (auto& m : mctrack.mothersIds()) { + if (m < mcTracks.size()) { // protect against bad mother indices + auto aMother = mcTracks.rawIteratorAt(m); + cout << "<<<<<< mother idx / pdg: " << m << " / " << aMother.pdgCode() << endl; + } + } + } + + if (mctrack.has_daughters()) { + for (int d = mctrack.daughtersIds()[0]; d <= mctrack.daughtersIds()[1]; ++d) { + + if (d < mcTracks.size()) { // protect against bad daughter indices + auto aDaughter = mcTracks.rawIteratorAt(d); + cout << "<<<<<< daughter idx / pdg: " << d << " / " << aDaughter.pdgCode() << endl; + } + } + } + }*/ + + // if no MC signals were matched, continue + if (mcflags == 0) { + continue; + } + + // If this MC track was not already added to the map, add it now + if (fLabelsMap.find(mctrack.globalIndex()) == fLabelsMap.end()) { + fLabelsMap[mctrack.globalIndex()] = trackCounter; + fLabelsMapReversed[trackCounter] = mctrack.globalIndex(); + fMCFlags[mctrack.globalIndex()] = mcflags; + trackCounter++; + + // fill histograms for each of the signals, if found + if (fConfigHistOutput.fConfigQA) { + VarManager::FillTrackMC(mcTracks, mctrack); + VarManager::FillEvent(mctrack.mcCollision()); + int j = 0; + for (auto signal = fMCSignals.begin(); signal != fMCSignals.end(); signal++, j++) { + if (mcflags & (static_cast(1) << j)) { + fHistMan->FillHistClass(Form("MCTruth_%s", (*signal)->GetName()), VarManager::fgValues); + } + } + } + } + } // end loop over mc stack + } + + template + void skimCollisions(TEvents const& collisions, BCsWithTimestamps const& /*bcs*/) + { + // Skim reconstructed collisions which are selected by the user specified cuts + + // Create a collision index map to relate between the "old" AO2D indices and the skimmed ones + fCollIndexMap.clear(); + int multTPC = -1.0; + float multFV0A = -1.0; + float multFV0C = -1.0; + float multFT0A = -1.0; + float multFT0C = -1.0; + float multFDDA = -1.0; + float multFDDC = -1.0; + float multZNA = -1.0; + float multZNC = -1.0; + int multTracklets = -1.0; + int multTracksPV = -1.0; + float centFT0C = -1.0; + + // Loop over collisions + for (const auto& collision : collisions) { + + // Fill the stats event histogram with the event selection bits + for (int i = 0; i < o2::aod::evsel::kNsel; i++) { + if (collision.selection_bit(i)) { + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); + } + } + (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(o2::aod::evsel::kNsel)); + + auto bc = collision.template bc_as(); + // store the selection decisions + uint64_t tag = static_cast(0); + // store some more information in the tag + // if the BC found by event selection does not coincide with the collision.bc(), toggle the first bit + auto bcEvSel = collision.template foundBC_as(); + if (bcEvSel.globalIndex() != bc.globalIndex()) { + tag |= (static_cast(1) << 0); + } + + // Compute BC and event quantities and fill histograms + VarManager::ResetValues(0, VarManager::kNEventWiseVariables); + VarManager::FillBC(bc); + VarManager::FillEvent(collision); // extract event information and place it in the fValues array + if (collision.has_mcCollision()) { + VarManager::FillEvent(collision.mcCollision()); + } + if (fDoDetailedQA) { + fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); + } + + // fill stats information, before selections + for (int i = 0; i < o2::aod::evsel::kNsel; i++) { + if (collision.selection_bit(i)) { + (reinterpret_cast(fStatsList->At(0)))->Fill(2.0, static_cast(i)); + } + } + (reinterpret_cast(fStatsList->At(0)))->Fill(2.0, static_cast(o2::aod::evsel::kNsel)); + + // Apply the user specified event selection + if (!fEventCut->IsSelected(VarManager::fgValues)) { + continue; + } + + // fill stats information, after selections + for (int i = 0; i < o2::aod::evsel::kNsel; i++) { + if (collision.selection_bit(i)) { + (reinterpret_cast(fStatsList->At(0)))->Fill(3.0, static_cast(i)); + } + } + (reinterpret_cast(fStatsList->At(0)))->Fill(3.0, static_cast(o2::aod::evsel::kNsel)); + + // Fill historams after event cuts + fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); + + // create the event tables + event(tag, bc.runNumber(), collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), collision.collisionTime(), collision.collisionTimeRes()); + if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionMult) > 0) { + multTPC = collision.multTPC(); + multFV0A = collision.multFV0A(); + multFV0C = collision.multFV0C(); + multFT0A = collision.multFT0A(); + multFT0C = collision.multFT0C(); + multFDDA = collision.multFDDA(); + multFDDC = collision.multFDDC(); + multZNA = collision.multZNA(); + multZNC = collision.multZNC(); + multTracklets = collision.multTracklets(); + multTracksPV = collision.multNTracksPV(); + } + if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionCent) > 0) { + centFT0C = collision.centFT0C(); + } + eventExtended(bc.globalBC(), collision.alias_raw(), collision.selection_raw(), bc.timestamp(), VarManager::fgValues[VarManager::kCentVZERO], + multTPC, multFV0A, multFV0C, multFT0A, multFT0C, multFDDA, multFDDC, multZNA, multZNC, multTracklets, multTracksPV, centFT0C); + eventVtxCov(collision.covXX(), collision.covXY(), collision.covXZ(), collision.covYY(), collision.covYZ(), collision.covZZ(), collision.chi2()); + eventMClabels(collision.mcCollisionId(), collision.mcMask()); + eventInfo(collision.globalIndex()); + if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionMultExtra) > 0) { + multPV(collision.multNTracksHasITS(), collision.multNTracksHasTPC(), collision.multNTracksHasTOF(), collision.multNTracksHasTRD(), + collision.multNTracksITSOnly(), collision.multNTracksTPCOnly(), collision.multNTracksITSTPC(), + collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + multAll(collision.multAllTracksTPCOnly(), collision.multAllTracksITSTPC(), + 0, 0, 0.0, 0.0, 0.0, 0.0, 0, 0, 0.0, 0.0, 0.0, 0.0); + } + + // add an element for this collision into the map + fCollIndexMap[collision.globalIndex()] = event.lastIndex(); + } + } + + template + void skimTracks(TEvent const& collision, TTracks const& /*tracks*/, TrackAssoc const& assocs, aod::McParticles const& mcTracks) + { + // Skim the barrel track associations + // Apply track cuts for each collision association and if it passes the cuts, we skim it. + // NOTE: If selection cuts include conditions on quantities dependent on the associated collision (e.g. DCA), + // one track may pass for some association and fail for others. + // Tracks are written only once in the skims, even if they contribute to more than one association + // so in case of multiple associations, the variables depending on the collision association (e.g. DCA, secondary vertexing, etc) + // have to be recomputed at analysis time for each association. + + uint64_t trackFilteringTag = static_cast(0); + uint32_t trackTempFilterMap = static_cast(0); + uint16_t mcflags = static_cast(0); + int trackCounter = fLabelsMap.size(); + + // Loop over associations + for (const auto& assoc : assocs) { + auto track = assoc.template track_as(); + + // If the original collision of this track was not selected for skimming, then we skip this track. + // Normally, the filter-pp is selecting all collisions which contain the tracks which contributed to the triggering + // of an event, so this is rejecting possibly a few tracks unrelated to the trigger, originally associated with collisions distant in time. + if (fCollIndexMap.find(track.collisionId()) == fCollIndexMap.end()) { + continue; + } + + trackFilteringTag = static_cast(0); + trackTempFilterMap = static_cast(0); + + // Compute track quantities and fill histograms + VarManager::FillTrack(track); + if (fConfigVariousOptions.fPropTrack && (track.collisionId() != collision.globalIndex())) { + VarManager::FillTrackCollision(track, collision); + } + if (fDoDetailedQA) { + fHistMan->FillHistClass("TrackBarrel_BeforeCuts", VarManager::fgValues); + } + + // apply track cuts and fill histograms + int i = 0; + for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, i++) { + if ((*cut)->IsSelected(VarManager::fgValues)) { + trackTempFilterMap |= (static_cast(1) << i); + if (fConfigHistOutput.fConfigQA) { + fHistMan->FillHistClass(Form("TrackBarrel_%s", (*cut)->GetName()), VarManager::fgValues); + } + (reinterpret_cast(fStatsList->At(1)))->Fill(static_cast(i)); + } + } + if (!trackTempFilterMap) { + continue; + } + + // If this track is already present in the index map, it means it was already skimmed, + // so we just store the association and we skip the track + if (fTrackIndexMap.find(track.globalIndex()) != fTrackIndexMap.end()) { + trackBarrelAssoc(fCollIndexMap[collision.globalIndex()], fTrackIndexMap[track.globalIndex()]); + continue; + } + + // store V0 and Dalitz bits selection information in the track tag + if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackV0Bits)) { // BIT0-4: V0Bits + trackFilteringTag |= static_cast(track.pidbit()); + for (int iv0 = 0; iv0 < 5; iv0++) { + if (track.pidbit() & (uint8_t(1) << iv0)) { + (reinterpret_cast(fStatsList->At(1)))->Fill(fTrackCuts.size() + static_cast(iv0)); + } + } + } // end if V0Bits + if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::DalitzBits)) { + trackFilteringTag |= (static_cast(track.dalitzBits()) << VarManager::kDalitzBits); // BIT5-12: Dalitz + } + trackFilteringTag |= (static_cast(trackTempFilterMap) << VarManager::kBarrelUserCutsBits); // BIT13-...: user track filters + + // NOTE: The collision ID that is written in the table is the one originally assigned in the AOD. + // However, in data analysis one should loop over associations, so this one should not be used. + // In the case of Run2-like analysis, there will be no associations, so this ID will be the one originally assigned in the AO2Ds (updated for the skims) + uint32_t reducedEventIdx = fCollIndexMap[track.collisionId()]; + + // NOTE: trackBarrelInfo stores the index of the collision as in AO2D (for use in some cases where the analysis on skims is done + // in workflows where the original AO2Ds are also present) + trackBarrelInfo(track.collisionId(), collision.posX(), collision.posY(), collision.posZ(), track.globalIndex()); + trackBasic(reducedEventIdx, trackFilteringTag, track.pt(), track.eta(), track.phi(), track.sign(), 0); + trackBarrel(track.x(), track.alpha(), track.y(), track.z(), track.snp(), track.tgl(), track.signed1Pt(), + track.tpcInnerParam(), track.flags(), track.itsClusterMap(), track.itsChi2NCl(), + track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), + track.tpcNClsShared(), track.tpcChi2NCl(), + track.trdChi2(), track.trdPattern(), track.tofChi2(), + track.length(), track.dcaXY(), track.dcaZ(), + track.trackTime(), track.trackTimeRes(), track.tofExpMom(), + track.detectorMap()); + if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackCov)) { + trackBarrelCov(track.cYY(), track.cZY(), track.cZZ(), track.cSnpY(), track.cSnpZ(), + track.cSnpSnp(), track.cTglY(), track.cTglZ(), track.cTglSnp(), track.cTglTgl(), + track.c1PtY(), track.c1PtZ(), track.c1PtSnp(), track.c1PtTgl(), track.c1Pt21Pt2()); + } + if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackPID)) { + trackBarrelPID(track.tpcSignal(), + track.tpcNSigmaEl(), track.tpcNSigmaMu(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), + track.beta(), track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), + track.trdSignal()); + } + fTrackIndexMap[track.globalIndex()] = trackBasic.lastIndex(); + + // Check whether the MCParticle corresponding to this reconstructed track was already selected for skimming + // If not, add it to the skimming map + if (!track.has_mcParticle()) { + trackBarrelLabels(-1, 0, 0); // this is the case when there is no matched MCParticle + } else { + auto mctrack = track.template mcParticle_as(); + VarManager::FillTrackMC(mcTracks, mctrack); + + mcflags = 0; + int i = 0; // runs over the MC signals + int j = 0; // runs over the track cuts + // check all the specified signals and fill histograms for MC truth matched tracks + for (auto& sig : fMCSignals) { + if (sig->CheckSignal(true, mctrack)) { + mcflags |= (static_cast(1) << i); + // If detailed QA is on, fill histograms for each MC signal and track cut combination + if (fDoDetailedQA) { + j = 0; + for (auto& cut : fTrackCuts) { + if (trackTempFilterMap & (uint8_t(1) << j)) { + fHistMan->FillHistClass(Form("TrackBarrel_%s_%s", cut->GetName(), sig->GetName()), VarManager::fgValues); // fill the reconstructed truth + } + j++; + } + } + } + i++; + } + + // if the MC truth particle corresponding to this reconstructed track is not already written, + // add it to the skimmed stack + if (!(fLabelsMap.find(mctrack.globalIndex()) != fLabelsMap.end())) { + fLabelsMap[mctrack.globalIndex()] = trackCounter; + fLabelsMapReversed[trackCounter] = mctrack.globalIndex(); + fMCFlags[mctrack.globalIndex()] = mcflags; + trackCounter++; + } + trackBarrelLabels(fLabelsMap.find(mctrack.globalIndex())->second, track.mcMask(), mcflags); + } + // write the skimmed collision - track association + trackBarrelAssoc(fCollIndexMap[collision.globalIndex()], fTrackIndexMap[track.globalIndex()]); + } // end loop over associations + } // end skimTracks + + template + void skimMFT(TEvent const& collision, TMFTTracks const& /*mfts*/, MFTTrackAssoc const& mftAssocs, aod::McParticles const& mcTracks) + { + // Skim MFT tracks + // So far no cuts are applied here + uint16_t mcflags = static_cast(0); + int trackCounter = fLabelsMap.size(); + + for (const auto& assoc : mftAssocs) { + auto track = assoc.template mfttrack_as(); + + if (fConfigHistOutput.fConfigQA) { + VarManager::FillTrack(track); + fHistMan->FillHistClass("MftTracks", VarManager::fgValues); + } + + // write the MFT track global index in the map for skimming (to make sure we have it just once) + if (fMftIndexMap.find(track.globalIndex()) == fMftIndexMap.end()) { + uint32_t reducedEventIdx = fCollIndexMap[collision.globalIndex()]; + mftTrack(reducedEventIdx, static_cast(0), track.pt(), track.eta(), track.phi()); + // TODO: We are not writing the DCA at the moment, because this depends on the collision association + mftTrackExtra(track.mftClusterSizesAndTrackFlags(), track.sign(), 0.0, 0.0, track.nClusters()); + + fMftIndexMap[track.globalIndex()] = mftTrack.lastIndex(); + if (!track.has_mcParticle()) { + mftLabels(-1, 0, 0); // this is the case when there is no matched MCParticle + } else { + auto mctrack = track.template mcParticle_as(); + VarManager::FillTrackMC(mcTracks, mctrack); + + mcflags = 0; + int i = 0; // runs over the MC signals + // check all the specified signals and fill histograms for MC truth matched tracks + for (auto& sig : fMCSignals) { + if (sig->CheckSignal(true, mctrack)) { + mcflags |= (static_cast(1) << i); + // If detailed QA is on, fill histograms for each MC signal and track cut combination + if (fDoDetailedQA) { + fHistMan->FillHistClass(Form("MFTTrack_%s", sig->GetName()), VarManager::fgValues); // fill the reconstructed truth + } + } + i++; + } + + // if the MC truth particle corresponding to this reconstructed track is not already written, + // add it to the skimmed stack + if (!(fLabelsMap.find(mctrack.globalIndex()) != fLabelsMap.end())) { + fLabelsMap[mctrack.globalIndex()] = trackCounter; + fLabelsMapReversed[trackCounter] = mctrack.globalIndex(); + fMCFlags[mctrack.globalIndex()] = mcflags; + trackCounter++; + } + mftLabels(fLabelsMap.find(mctrack.globalIndex())->second, track.mcMask(), mcflags); + } + } + mftAssoc(fCollIndexMap[collision.globalIndex()], fMftIndexMap[track.globalIndex()]); + } + } + + template + void skimBestMuonMatches(TMuons const& muons) + { + std::unordered_map> mCandidates; + for (const auto& muon : muons) { + if (static_cast(muon.trackType()) < 2) { + auto muonID = muon.matchMCHTrackId(); + auto chi2 = muon.chi2MatchMCHMFT(); + if (mCandidates.find(muonID) == mCandidates.end()) { + mCandidates[muonID] = {chi2, muon.globalIndex()}; + } else { + if (chi2 < mCandidates[muonID].first) { + mCandidates[muonID] = {chi2, muon.globalIndex()}; + } + } + } + } + for (auto& pairCand : mCandidates) { + fBestMatch[pairCand.second.second] = true; + } + } + + template + void skimMuons(TEvent const& collision, TMuons const& muons, FwdTrackAssoc const& muonAssocs, aod::McParticles const& mcTracks, TMFTTracks const& /*mftTracks*/) + { + // Skim the fwd-tracks (muons) + // Loop over the collision-track associations, recompute track properties depending on the collision assigned, and apply track cuts for selection + // Muons are written only once, even if they constribute to more than one association, + // which means that in the case of multiple associations, the track parameters are wrong and should be computed again at analysis time. + uint8_t trackFilteringTag = static_cast(0); + uint8_t trackTempFilterMap = static_cast(0); + fFwdTrackIndexMapReversed.clear(); + uint16_t mcflags = static_cast(0); + int trackCounter = fLabelsMap.size(); + + uint32_t offset = muonBasic.lastIndex(); + uint32_t counter = 0; + for (const auto& assoc : muonAssocs) { + // get the muon + auto muon = assoc.template fwdtrack_as(); + if (fConfigVariousOptions.fKeepBestMatch && static_cast(muon.trackType()) < 2) { + if (fBestMatch.find(muon.globalIndex()) == fBestMatch.end()) { + continue; + } + } + + trackFilteringTag = uint8_t(0); + trackTempFilterMap = uint8_t(0); + VarManager::FillTrack(muon); + // NOTE: If a muon is associated to multiple collisions, depending on the selections, + // it may be accepted for some associations and rejected for other + if (fConfigVariousOptions.fPropMuon) { + VarManager::FillPropagateMuon(muon, collision); + } + // recalculte pDca and global muon kinematics + if (static_cast(muon.trackType()) < 2 && fConfigVariousOptions.fRefitGlobalMuon) { + auto muontrack = muon.template matchMCHTrack_as(); + if (muontrack.eta() < fConfigVariousOptions.fMuonMatchEtaMin || muontrack.eta() > fConfigVariousOptions.fMuonMatchEtaMax) { + continue; + } + auto mfttrack = muon.template matchMFTTrack_as(); + VarManager::FillTrackCollision(muontrack, collision); + VarManager::FillGlobalMuonRefit(muontrack, mfttrack, collision); + } else { + VarManager::FillTrackCollision(muon, collision); + } + + if (fDoDetailedQA) { + fHistMan->FillHistClass("Muons_BeforeCuts", VarManager::fgValues); + } + // check the cuts and fill histograms for each fulfilled cut + int i = 0; + for (auto cut = fMuonCuts.begin(); cut != fMuonCuts.end(); cut++, i++) { + if ((*cut)->IsSelected(VarManager::fgValues)) { + trackTempFilterMap |= (uint8_t(1) << i); + if (fConfigHistOutput.fConfigQA) { + fHistMan->FillHistClass(Form("Muons_%s", (*cut)->GetName()), VarManager::fgValues); + } + (reinterpret_cast(fStatsList->At(2)))->Fill(static_cast(i)); + } + } + + // don't skim the muon if no cut has passed + if (!trackTempFilterMap) { + continue; + } + trackFilteringTag = trackTempFilterMap; // BIT0-7: user selection cuts + + // update the index map if this is a new muon (it can already exist in the map from a different collision association) + if (fFwdTrackIndexMap.find(muon.globalIndex()) == fFwdTrackIndexMap.end()) { + counter++; + fFwdTrackIndexMap[muon.globalIndex()] = offset + counter; + fFwdTrackIndexMapReversed[offset + counter] = muon.globalIndex(); + fFwdTrackFilterMap[muon.globalIndex()] = trackFilteringTag; // store here the filtering tag so we don't repeat the cuts in the second iteration + if (muon.has_matchMCHTrack() && (fFwdTrackIndexMap.find(muon.matchMCHTrackId()) == fFwdTrackIndexMap.end())) { // write also the matched MCH track + counter++; + fFwdTrackIndexMap[muon.matchMCHTrackId()] = offset + counter; + fFwdTrackIndexMapReversed[offset + counter] = muon.matchMCHTrackId(); + fFwdTrackFilterMap[muon.matchMCHTrackId()] = trackFilteringTag; // store here the filtering tag so we don't repeat the cuts in the second iteration + } + + if (muon.has_mcParticle()) { + auto mctrack = muon.template mcParticle_as(); + VarManager::FillTrackMC(mcTracks, mctrack); + + mcflags = 0; + int i = 0; // runs over the MC signals + int j = 0; // runs over the track cuts + // check all the specified signals and fill histograms for MC truth matched tracks + for (auto& sig : fMCSignals) { + if (sig->CheckSignal(true, mctrack)) { + mcflags |= (static_cast(1) << i); + if (fDoDetailedQA) { + for (auto& cut : fMuonCuts) { + if (trackTempFilterMap & (uint8_t(1) << j)) { + fHistMan->FillHistClass(Form("Muons_%s_%s", cut->GetName(), sig->GetName()), VarManager::fgValues); // fill the reconstructed truth + } + j++; + } + } // end if do detailed QA + } + i++; + } // end loop over MC signals + + // if the MC truth particle corresponding to this reconstructed muon is not already written, + // add it to the skimmed stack + if (!(fLabelsMap.find(mctrack.globalIndex()) != fLabelsMap.end())) { + fLabelsMap[mctrack.globalIndex()] = trackCounter; + fLabelsMapReversed[trackCounter] = mctrack.globalIndex(); + fMCFlags[mctrack.globalIndex()] = mcflags; + trackCounter++; + } + + } // end if (has_mcParticle) + } else { // if muon already in the map, make a bitwise OR with previous existing cuts + fFwdTrackFilterMap[muon.globalIndex()] |= trackFilteringTag; + } + // write the association table + muonAssoc(fCollIndexMap[collision.globalIndex()], fFwdTrackIndexMap[muon.globalIndex()]); + } // end loop over assocs + + // Now we have the full index map of selected muons so we can proceed with writing the muon tables + // Special care needed for the MCH and MFT indices + for (const auto& [skimIdx, origIdx] : fFwdTrackIndexMapReversed) { + // get the muon + auto muon = muons.rawIteratorAt(origIdx); + uint32_t reducedEventIdx = -1; + if (muon.has_collision() && + fCollIndexMap.find(muon.collisionId()) != fCollIndexMap.end()) { // if the collisionId of this muon was not skimmed, leave the skimmed event index to -1 + reducedEventIdx = fCollIndexMap[muon.collisionId()]; + } + // NOTE: Currently, one writes the original AO2D momentum-vector (pt, eta and phi) in the tables because we write only one instance of the muon track, + // while multiple collision associations (and multiple mom vectors can exist) + // The momentum can be recomputed at the analysis time based on the associations written in the skims + // So all the information which pertains to collision association or MFT associations should not be taken from the skimmed data, but recomputed at analysis time. + uint32_t mchIdx = -1; + uint32_t mftIdx = -1; + if (muon.trackType() == uint8_t(0) || muon.trackType() == uint8_t(2)) { // MCH-MID (2) or global (0) + if (fFwdTrackIndexMap.find(muon.matchMCHTrackId()) != fFwdTrackIndexMap.end()) { + mchIdx = fFwdTrackIndexMap[muon.matchMCHTrackId()]; + } + if (fMftIndexMap.find(muon.matchMFTTrackId()) != fMftIndexMap.end()) { + mftIdx = fMftIndexMap[muon.matchMFTTrackId()]; + } + } + VarManager::FillTrack(muon); + if (fConfigVariousOptions.fPropMuon) { + VarManager::FillPropagateMuon(muon, collision); + } + // recalculte pDca and global muon kinematics + if (static_cast(muon.trackType()) < 2 && fConfigVariousOptions.fRefitGlobalMuon) { + auto muontrack = muon.template matchMCHTrack_as(); + auto mfttrack = muon.template matchMFTTrack_as(); + VarManager::FillTrackCollision(muontrack, collision); + VarManager::FillGlobalMuonRefit(muontrack, mfttrack, collision); + } else { + VarManager::FillTrackCollision(muon, collision); + } + muonBasic(reducedEventIdx, mchIdx, mftIdx, fFwdTrackFilterMap[muon.globalIndex()], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], muon.sign(), 0); + muonExtra(muon.nClusters(), VarManager::fgValues[VarManager::kMuonPDca], VarManager::fgValues[VarManager::kMuonRAtAbsorberEnd], + muon.chi2(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), + muon.matchScoreMCHMFT(), + muon.mchBitMap(), muon.midBitMap(), + muon.midBoards(), muon.trackType(), VarManager::fgValues[VarManager::kMuonDCAx], VarManager::fgValues[VarManager::kMuonDCAy], + muon.trackTime(), muon.trackTimeRes()); + if constexpr (static_cast(TMuonFillMap & VarManager::ObjTypes::MuonCov)) { + muonCov(VarManager::fgValues[VarManager::kX], VarManager::fgValues[VarManager::kY], VarManager::fgValues[VarManager::kZ], VarManager::fgValues[VarManager::kPhi], VarManager::fgValues[VarManager::kTgl], muon.sign() / VarManager::fgValues[VarManager::kPt], + VarManager::fgValues[VarManager::kMuonCXX], VarManager::fgValues[VarManager::kMuonCXY], VarManager::fgValues[VarManager::kMuonCYY], VarManager::fgValues[VarManager::kMuonCPhiX], VarManager::fgValues[VarManager::kMuonCPhiY], VarManager::fgValues[VarManager::kMuonCPhiPhi], + VarManager::fgValues[VarManager::kMuonCTglX], VarManager::fgValues[VarManager::kMuonCTglY], VarManager::fgValues[VarManager::kMuonCTglPhi], VarManager::fgValues[VarManager::kMuonCTglTgl], VarManager::fgValues[VarManager::kMuonC1Pt2X], VarManager::fgValues[VarManager::kMuonC1Pt2Y], + VarManager::fgValues[VarManager::kMuonC1Pt2Phi], VarManager::fgValues[VarManager::kMuonC1Pt2Tgl], VarManager::fgValues[VarManager::kMuonC1Pt21Pt2]); + } + if (muon.has_mcParticle()) { + auto mctrack = muon.template mcParticle_as(); + muonLabels(fLabelsMap.find(mctrack.globalIndex())->second, muon.mcMask(), mcflags); + } else { + muonLabels(-1, 0, 0); + } + } // end loop over selected muons + } // end skimMuons + + template + void fullSkimming(TEvents const& collisions, BCsWithTimestamps const& bcs, + TTracks const& tracksBarrel, TMuons const& muons, TMFTTracks const& mftTracks, + TTrackAssoc const& trackAssocs, TFwdTrackAssoc const& fwdTrackAssocs, TMFTTrackAssoc const& mftAssocs, + aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + // Check whether the run changed and update CCDB if it did + if (bcs.size() > 0 && fCurrentRun != bcs.begin().runNumber()) { + if (fIsRun2 == true) { + fGrpMagRun2 = fCCDB->getForTimeStamp(fConfigCCDB.fGrpMagPathRun2, bcs.begin().timestamp()); + if (fGrpMagRun2 != nullptr) { + o2::base::Propagator::initFieldFromGRP(fGrpMagRun2); + } + } else { + fGrpMag = fCCDB->getForTimeStamp(fConfigCCDB.fGrpMagPath, bcs.begin().timestamp()); + if (fGrpMag != nullptr) { + o2::base::Propagator::initFieldFromGRP(fGrpMag); + } + if (fConfigVariousOptions.fPropMuon) { + VarManager::SetupMuonMagField(); + } + } + std::map metadataRCT, header; + header = fCCDBApi.retrieveHeaders(Form("RCT/Info/RunInformation/%i", bcs.begin().runNumber()), metadataRCT, -1); + uint64_t sor = std::atol(header["SOR"].c_str()); + uint64_t eor = std::atol(header["EOR"].c_str()); + VarManager::SetSORandEOR(sor, eor); + + fCurrentRun = bcs.begin().runNumber(); + } + + // skim MC Collisions + eventMC.reserve(mcCollisions.size()); + skimMCCollisions(mcCollisions); + + // select MC particles to be written using the specified MC signals + // NOTE: tables are not written at this point, only label maps are being created + skimMCParticles(mcParticles, mcCollisions); + + // skim collisions + event.reserve(collisions.size()); + eventExtended.reserve(collisions.size()); + eventVtxCov.reserve(collisions.size()); + eventMClabels.reserve(collisions.size()); + eventInfo.reserve(collisions.size()); + skimCollisions(collisions, bcs); + if (fCollIndexMap.size() == 0) { + return; + } + + // Clear index map and reserve memory for barrel tables + if constexpr (static_cast(TTrackFillMap)) { + fTrackIndexMap.clear(); + trackBarrelInfo.reserve(tracksBarrel.size()); + trackBasic.reserve(tracksBarrel.size()); + trackBarrel.reserve(tracksBarrel.size()); + trackBarrelCov.reserve(tracksBarrel.size()); + trackBarrelPID.reserve(tracksBarrel.size()); + trackBarrelAssoc.reserve(tracksBarrel.size()); + trackBarrelLabels.reserve(tracksBarrel.size()); + } + + // Clear index map and reserve memory for MFT tables + if constexpr (static_cast(TMFTFillMap)) { + fMftIndexMap.clear(); + mftTrack.reserve(mftTracks.size()); + mftTrackExtra.reserve(mftTracks.size()); + mftAssoc.reserve(mftTracks.size()); + mftLabels.reserve(mftTracks.size()); + } + + // Clear index map and reserve memory for muon tables + if constexpr (static_cast(TMuonFillMap)) { + fFwdTrackIndexMap.clear(); + fFwdTrackFilterMap.clear(); + fBestMatch.clear(); + muonBasic.reserve(muons.size()); + muonExtra.reserve(muons.size()); + muonCov.reserve(muons.size()); + muonAssoc.reserve(muons.size()); + muonLabels.reserve(muons.size()); + } + + // loop over selected collisions and select the tracks and fwd tracks to be skimmed + if (fCollIndexMap.size() > 0) { + for (auto const& [origIdx, skimIdx] : fCollIndexMap) { + auto collision = collisions.rawIteratorAt(origIdx); + // group the tracks and muons for this collision + if constexpr (static_cast(TTrackFillMap)) { + auto groupedTrackIndices = trackAssocs.sliceBy(trackIndicesPerCollision, origIdx); + skimTracks(collision, tracksBarrel, groupedTrackIndices, mcParticles); + } + if constexpr (static_cast(TMFTFillMap)) { + auto groupedMFTIndices = mftAssocs.sliceBy(mfttrackIndicesPerCollision, origIdx); + skimMFT(collision, mftTracks, groupedMFTIndices, mcParticles); + } + if constexpr (static_cast(TMuonFillMap)) { + if constexpr (static_cast(TMFTFillMap)) { + auto groupedMuonIndices = fwdTrackAssocs.sliceBy(fwdtrackIndicesPerCollision, origIdx); + if (fConfigVariousOptions.fKeepBestMatch) { + skimBestMuonMatches(muons); + } + skimMuons(collision, muons, groupedMuonIndices, mcParticles, mftTracks); + } else { + auto groupedMuonIndices = fwdTrackAssocs.sliceBy(fwdtrackIndicesPerCollision, origIdx); + skimMuons(collision, muons, groupedMuonIndices, mcParticles, nullptr); + } + } + } // end loop over skimmed collisions + } + + // Loop over the label map, create the mother/daughter relationships if these exist and write the skimmed MC stack + for (const auto& [newLabel, oldLabel] : fLabelsMapReversed) { + auto mctrack = mcParticles.iteratorAt(oldLabel); + uint16_t mcflags = fMCFlags.find(oldLabel)->second; + + std::vector mothers; + if (mctrack.has_mothers()) { + for (auto& m : mctrack.mothersIds()) { + if (m < mcParticles.size()) { // protect against bad mother indices + if (fLabelsMap.find(m) != fLabelsMap.end()) { + mothers.push_back(fLabelsMap.find(m)->second); + } + } else { + cout << "Mother label (" << m << ") exceeds the McParticles size (" << mcParticles.size() << ")" << endl; + cout << " Check the MC generator" << endl; + } + } + } + + // TODO: Check that the daughter slice in the skimmed table works as expected + // Note that not all daughters from the original table are preserved in the skimmed MC stack + std::vector daughters; + if (mctrack.has_daughters()) { + for (int d = mctrack.daughtersIds()[0]; d <= mctrack.daughtersIds()[1]; ++d) { + // TODO: remove this check as soon as issues with MC production are fixed + if (d < mcParticles.size()) { // protect against bad daughter indices + if (fLabelsMap.find(d) != fLabelsMap.end()) { + daughters.push_back(fLabelsMap.find(d)->second); + } + } else { + cout << "Daughter label (" << d << ") exceeds the McParticles size (" << mcParticles.size() << ")" << endl; + cout << " Check the MC generator" << endl; + } + } + } + int daughterRange[2] = {-1, -1}; + if (daughters.size() > 0) { + daughterRange[0] = daughters[0]; + daughterRange[1] = daughters[daughters.size() - 1]; + } + + // NOTE: Here we assume that MC collisions are not filtered, so there is no new vs old index map for translation + trackMC(mctrack.mcCollision().globalIndex(), mctrack.pdgCode(), mctrack.statusCode(), mctrack.flags(), + mothers, daughterRange, + mctrack.weight(), mctrack.pt(), mctrack.eta(), mctrack.phi(), mctrack.e(), + mctrack.vx(), mctrack.vy(), mctrack.vz(), mctrack.vt(), mcflags); + for (unsigned int isig = 0; isig < fMCSignals.size(); isig++) { + if (mcflags & (static_cast(1) << isig)) { + (reinterpret_cast(fStatsList->At(3)))->Fill(static_cast(isig)); + } + } + if (mcflags == 0) { + (reinterpret_cast(fStatsList->At(3)))->Fill(static_cast(fMCSignals.size())); + } + } // end loop over labels + } + + void DefineHistograms(TString histClasses) + { + std::unique_ptr objArray(histClasses.Tokenize(";")); + for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { + TString classStr = objArray->At(iclass)->GetName(); + if (fConfigHistOutput.fConfigQA) { + fHistMan->AddHistClass(classStr.Data()); + } + + TString histEventName = fConfigHistOutput.fConfigAddEventHistogram.value; + if (classStr.Contains("Event")) { + if (fConfigHistOutput.fConfigQA && !classStr.Contains("MCTruth")) { + dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "event", histEventName); + } else { + dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "event", "generator"); + } + } + + TString histTrackName = fConfigHistOutput.fConfigAddTrackHistogram.value; + if (classStr.Contains("Track")) { + if (fConfigHistOutput.fConfigQA) { + dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "track", histTrackName); + } + } + + TString histMuonName = fConfigHistOutput.fConfigAddMuonHistogram.value; + if (classStr.Contains("Muons")) { + if (fConfigHistOutput.fConfigQA) { + dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "track", histMuonName); + } + } + + TString histMCTruthName = fConfigHistOutput.fConfigAddMCTruthHistogram.value; + if (classStr.Contains("MCTruth") && !classStr.Contains("Event")) { + if (fConfigHistOutput.fConfigQA) { + dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "mctruth_track", histMCTruthName); + } + } + } + + // create statistics histograms (event, tracks, muons, MCsignals) + fStatsList.setObject(new TList()); + fStatsList->SetOwner(kTRUE); + std::vector eventLabels{"BCs", "Collisions before filtering", "Before cuts", "After cuts"}; + TH2I* histEvents = new TH2I("EventStats", "Event statistics", eventLabels.size(), -0.5, eventLabels.size() - 0.5, o2::aod::evsel::kNsel + 1, -0.5, (float)o2::aod::evsel::kNsel + 0.5); + int ib = 1; + for (auto label = eventLabels.begin(); label != eventLabels.end(); label++, ib++) { + histEvents->GetXaxis()->SetBinLabel(ib, (*label).Data()); + } + for (int ib = 1; ib <= o2::aod::evsel::kNsel; ib++) { + histEvents->GetYaxis()->SetBinLabel(ib, o2::aod::evsel::selectionLabels[ib - 1]); + } + histEvents->GetYaxis()->SetBinLabel(o2::aod::evsel::kNsel + 1, "Total"); + fStatsList->Add(histEvents); + + // Track statistics: one bin for each track selection and 5 bins for V0 tags (gamma, K0s, Lambda, anti-Lambda, Omega) + TH1I* histTracks = new TH1I("TrackStats", "Track statistics", fTrackCuts.size() + 5.0, -0.5, fTrackCuts.size() - 0.5 + 5.0); + ib = 1; + for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, ib++) { + histTracks->GetXaxis()->SetBinLabel(ib, (*cut)->GetName()); + } + const char* v0TagNames[5] = {"Photon conversion", "K^{0}_{s}", "#Lambda", "#bar{#Lambda}", "#Omega"}; + for (int ib = 0; ib < 5; ib++) { + histTracks->GetXaxis()->SetBinLabel(fTrackCuts.size() + 1 + ib, v0TagNames[ib]); + } + fStatsList->Add(histTracks); + TH1I* histMuons = new TH1I("MuonStats", "Muon statistics", fMuonCuts.size(), -0.5, fMuonCuts.size() - 0.5); + ib = 1; + for (auto cut = fMuonCuts.begin(); cut != fMuonCuts.end(); cut++, ib++) { + histMuons->GetXaxis()->SetBinLabel(ib, (*cut)->GetName()); + } + fStatsList->Add(histMuons); + TH1I* histMCsignals = new TH1I("MCsignals", "MC signals", fMCSignals.size() + 1, -0.5, fMCSignals.size() - 0.5 + 1.0); + ib = 1; + for (auto signal = fMCSignals.begin(); signal != fMCSignals.end(); signal++, ib++) { + histMCsignals->GetXaxis()->SetBinLabel(ib, (*signal)->GetName()); + } + histMCsignals->GetXaxis()->SetBinLabel(fMCSignals.size() + 1, "Others (matched to reco tracks)"); + fStatsList->Add(histMCsignals); + } + + void processPP(MyEventsWithMults const& collisions, aod::BCsWithTimestamps const& bcs, + MyBarrelTracksWithCov const& tracksBarrel, MyMuonsWithCov const& tracksMuon, MFTTrackLabeled const& mftTracks, + aod::TrackAssoc const& trackAssocs, aod::FwdTrackAssoc const& fwdTrackAssocs, aod::MFTTrackAssoc const& mftAssocs, + aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + fullSkimming(collisions, bcs, tracksBarrel, tracksMuon, mftTracks, trackAssocs, fwdTrackAssocs, mftAssocs, mcCollisions, mcParticles); + } + + void processPPBarrelOnly(MyEventsWithMults const& collisions, aod::BCsWithTimestamps const& bcs, + MyBarrelTracksWithCov const& tracksBarrel, aod::TrackAssoc const& trackAssocs, + aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + fullSkimming(collisions, bcs, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr, mcCollisions, mcParticles); + } + + void processPPMuonOnlyBasic(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, + MyMuonsWithCov const& tracksMuon, MFTTrackLabeled const& mftTracks, + aod::FwdTrackAssoc const& fwdTrackAssocs, aod::MFTTrackAssoc const& mftAssocs, + aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + fullSkimming(collisions, bcs, nullptr, tracksMuon, mftTracks, nullptr, fwdTrackAssocs, mftAssocs, mcCollisions, mcParticles); + } + + void processPPMuonOnly(MyEventsWithMults const& collisions, aod::BCsWithTimestamps const& bcs, + MyMuonsWithCov const& tracksMuon, MFTTrackLabeled const& mftTracks, + aod::FwdTrackAssoc const& fwdTrackAssocs, aod::MFTTrackAssoc const& mftAssocs, + aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + fullSkimming(collisions, bcs, nullptr, tracksMuon, mftTracks, nullptr, fwdTrackAssocs, mftAssocs, mcCollisions, mcParticles); + } + + void processPbPb(MyEventsWithCentAndMults const& collisions, aod::BCsWithTimestamps const& bcs, + MyBarrelTracksWithCov const& tracksBarrel, MyMuonsWithCov const& tracksMuon, MFTTrackLabeled const& mftTracks, + aod::TrackAssoc const& trackAssocs, aod::FwdTrackAssoc const& fwdTrackAssocs, aod::MFTTrackAssoc const& mftAssocs, + aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + fullSkimming(collisions, bcs, tracksBarrel, tracksMuon, mftTracks, trackAssocs, fwdTrackAssocs, mftAssocs, mcCollisions, mcParticles); + } + + void processPbPbBarrelOnly(MyEventsWithCentAndMults const& collisions, aod::BCsWithTimestamps const& bcs, + MyBarrelTracksWithCov const& tracksBarrel, aod::TrackAssoc const& trackAssocs, + aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + fullSkimming(collisions, bcs, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr, mcCollisions, mcParticles); + } + + void processPbPbMuonOnly(MyEventsWithCentAndMults const& collisions, aod::BCsWithTimestamps const& bcs, + MyMuonsWithCov const& tracksMuon, MFTTrackLabeled const& mftTracks, + aod::FwdTrackAssoc const& fwdTrackAssocs, aod::MFTTrackAssoc const& mftAssocs, + aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + fullSkimming(collisions, bcs, nullptr, tracksMuon, mftTracks, nullptr, fwdTrackAssocs, mftAssocs, mcCollisions, mcParticles); + } + + // Process the BCs and store stats for luminosity retrieval ----------------------------------------------------------------------------------- + void processOnlyBCs(soa::Join::iterator const& bc) + { + for (int i = 0; i < o2::aod::evsel::kNsel; i++) { + if (bc.alias_bit(i) > 0) { + (reinterpret_cast(fStatsList->At(0)))->Fill(0.0, static_cast(i)); + } + } + (reinterpret_cast(fStatsList->At(0)))->Fill(0.0, static_cast(o2::aod::evsel::kNsel)); + } + + PROCESS_SWITCH(TableMakerMC, processPP, "Produce both barrel and muon skims, pp settings", false); + PROCESS_SWITCH(TableMakerMC, processPPBarrelOnly, "Produce only barrel skims, pp settings ", false); + PROCESS_SWITCH(TableMakerMC, processPPMuonOnlyBasic, "Produce only muon skims, pp settings, no multiplicity", false); + PROCESS_SWITCH(TableMakerMC, processPPMuonOnly, "Produce only muon skims, pp settings", false); + PROCESS_SWITCH(TableMakerMC, processPbPb, "Produce both barrel and muon skims, PbPb settings", false); + PROCESS_SWITCH(TableMakerMC, processPbPbBarrelOnly, "Produce only barrel skims, PbPb settings", false); + PROCESS_SWITCH(TableMakerMC, processPbPbMuonOnly, "Produce only muon skims, PbPb settings", false); + PROCESS_SWITCH(TableMakerMC, processOnlyBCs, "Analyze the BCs to store sampled lumi", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // TODO: For now TableMakerMC works just for PbPb (cent table is present) + // Implement workflow arguments for pp/PbPb and possibly merge the task with tableMaker.cxx + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGDQ/TableProducer/tableMakerMuonMchTrkEfficiency.cxx b/PWGDQ/TableProducer/tableMakerMuonMchTrkEfficiency.cxx index 6fe09efed16..11634be2e0d 100644 --- a/PWGDQ/TableProducer/tableMakerMuonMchTrkEfficiency.cxx +++ b/PWGDQ/TableProducer/tableMakerMuonMchTrkEfficiency.cxx @@ -18,8 +18,10 @@ /// /// \author Zaida Conesa del Valle /// -#include + #include +#include +#include #include #include #include @@ -128,8 +130,8 @@ struct tableMakerMuonMchTrkEfficiency { using myMuons = soa::Join; using myMuonsMC = soa::Join; - using myReducedMuons = soa::Join; - using myReducedMuonsMC = soa::Join; + using myReducedMuons = soa::Join; + using myReducedMuonsMC = soa::Join; // bit maps used for the Fill functions of the VarManager constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision; @@ -638,7 +640,7 @@ struct tableMakerMuonMchTrkEfficiency { auto mcCollision = collision.reducedMCevent(); VarManager::FillEvent(mcCollision); /// event selection - runEventSelection(collision); + runEventSelection(collision); /// Run muon selection and histo filling // VarManager::ResetValues(0, VarManager::kNMCParticleVariables); diff --git a/PWGDQ/TableProducer/tableMaker_withAssoc.cxx b/PWGDQ/TableProducer/tableMaker_withAssoc.cxx index 65854e70614..7adb6fbf23c 100644 --- a/PWGDQ/TableProducer/tableMaker_withAssoc.cxx +++ b/PWGDQ/TableProducer/tableMaker_withAssoc.cxx @@ -17,7 +17,12 @@ // The skimming can optionally produce just the barrel, muon, or both barrel and muon tracks // The event filtering, centrality, and V0Bits (from v0-selector) can be switched on/off by selecting one // of the process functions -#include +// C++ includes +#include +#include +#include +#include +// other includes #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" @@ -31,6 +36,7 @@ #include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/MftmchMatchingML.h" +#include "Common/Core/TableHelper.h" #include "PWGDQ/DataModel/ReducedInfoTables.h" #include "PWGDQ/Core/VarManager.h" #include "PWGDQ/Core/HistogramManager.h" @@ -55,15 +61,16 @@ #include "TGeoGlobalMagField.h" #include "DetectorsBase/Propagator.h" #include "DetectorsBase/GeometryManager.h" - -using std::cout; -using std::endl; +#include "EventFiltering/Zorro.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::aod; +Zorro zorro; + +// Declaration of various Joins used in the different process functions // TODO: Since DCA depends on which collision the track is associated to, we should remove writing and subscribing to DCA tables, to optimize on CPU / memory using MyBarrelTracks = soa::Join; -using MyBarrelTracksWithV0BitsForMaps = soa::Join; +using MyBarrelTracksWithV0BitsNoTOF = soa::Join; using MyBarrelTracksWithDalitzBits = soa::Join; using MyEventsWithMults = soa::Join; using MyEventsWithFilter = soa::Join; -using MyEventsWithMultsAndFilter = soa::Join; +using MyEventsWithMultsAndFilter = soa::Join; +using MyEventsWithMultsAndRapidityGapFilter = soa::Join; using MyEventsWithCent = soa::Join; -using MyEventsWithCentAndMults = soa::Join; +using MyEventsWithCentAndMults = soa::Join; +using MyEventsWithMultsExtra = soa::Join; using MyMuons = soa::Join; using MyMuonsWithCov = soa::Join; using MyMuonsColl = soa::Join; using MyMuonsCollWithCov = soa::Join; +using MyBCs = soa::Join; using ExtBCs = soa::Join; -namespace o2::aod -{ -DECLARE_SOA_TABLE(AmbiguousTracksMid, "AOD", "AMBIGUOUSTRACK", //! Table for tracks which are not uniquely associated with a collision - o2::soa::Index<>, o2::aod::ambiguous::TrackId, o2::aod::ambiguous::BCIdSlice, o2::soa::Marker<2>); -DECLARE_SOA_TABLE(AmbiguousTracksFwd, "AOD", "AMBIGUOUSFWDTR", //! Table for Fwd tracks which are not uniquely associated with a collision - o2::soa::Index<>, o2::aod::ambiguous::FwdTrackId, o2::aod::ambiguous::BCIdSlice, o2::soa::Marker<2>); -} // namespace o2::aod - +// Declaration of various bit maps containing information on which tables are included in a Join +// These are used as template arguments and checked at compile time // constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision; // constexpr static uint32_t gkEventFillMapWithFilter = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::EventFilter; - -// constexpr static uint32_t gkEventFillMapWithMult = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionMult; -constexpr static uint32_t gkEventFillMapWithMultsAndEventFilter = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionMult | VarManager::ObjTypes::EventFilter; +constexpr static uint32_t gkEventFillMapWithMults = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionMult; +constexpr static uint32_t gkEventFillMapWithMultsZdc = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionMult | VarManager::ObjTypes::Zdc; +constexpr static uint32_t gkEventFillMapWithMultsAndEventFilter = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionMult | VarManager::ObjTypes::CollisionMultExtra | VarManager::ObjTypes::EventFilter; +constexpr static uint32_t gkEventFillMapWithMultsEventFilterZdc = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionMult | VarManager::ObjTypes::CollisionMultExtra | VarManager::ObjTypes::EventFilter | VarManager::ObjTypes::Zdc; +constexpr static uint32_t gkEventFillMapWithMultsRapidityGapFilterZdc = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionMult | VarManager::ObjTypes::CollisionMultExtra | VarManager::ObjTypes::RapidityGapFilter | VarManager::ObjTypes::Zdc; // constexpr static uint32_t gkEventFillMapWithCent = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCent; -constexpr static uint32_t gkEventFillMapWithCentAndMults = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCent | VarManager::CollisionMult; +constexpr static uint32_t gkEventFillMapWithCentAndMults = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCent | VarManager::CollisionMult | VarManager::ObjTypes::CollisionMultExtra; +constexpr static uint32_t gkEventFillMapWithMultsExtra = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::CollisionMult | VarManager::ObjTypes::CollisionMultExtra; // constexpr static uint32_t gkEventFillMapWithCentRun2 = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCentRun2; // Unused variable // constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackPID | VarManager::ObjTypes::TrackPIDExtra; constexpr static uint32_t gkTrackFillMapWithCov = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackCov | VarManager::ObjTypes::TrackPID | VarManager::ObjTypes::TrackPIDExtra; -// constexpr static uint32_t gkTrackFillMapWithV0Bits = gkTrackFillMapWithCov | VarManager::ObjTypes::TrackV0Bits; -// constexpr static uint32_t gkTrackFillMapWithV0BitsForMaps = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackV0Bits | VarManager::ObjTypes::TrackTPCPID; +constexpr static uint32_t gkTrackFillMapWithV0Bits = gkTrackFillMapWithCov | VarManager::ObjTypes::TrackV0Bits; +constexpr static uint32_t gkTrackFillMapWithV0BitsNoTOF = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackV0Bits | VarManager::ObjTypes::TrackTPCPID; // constexpr static uint32_t gkTrackFillMapWithDalitzBits = gkTrackFillMap | VarManager::ObjTypes::DalitzBits; // constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::Muon; constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::Muon | VarManager::ObjTypes::MuonCov; @@ -128,16 +135,30 @@ constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::Muon | Va // constexpr static uint32_t gkTrackFillMapWithAmbi = VarManager::ObjTypes::Track | VarManager::ObjTypes::AmbiTrack; constexpr static uint32_t gkMFTFillMap = VarManager::ObjTypes::TrackMFT; +// Enum containing the ordering of statistics histograms to be written in the QA file +enum SkimStatsHists { + kStatsEvent = 0, + kStatsTracks, + kStatsMuons, + kStatsOrphanTracks, + kStatsZorroInfo, + kStatsZorroSel +}; + struct TableMaker { Produces event; Produces eventExtended; Produces eventVtxCov; + Produces eventInfo; + Produces zdc; + Produces multPV; + Produces multAll; + Produces trackBarrelInfo; Produces trackBasic; Produces trackBarrel; Produces trackBarrelCov; Produces trackBarrelPID; - Produces trackBarrelInfo; Produces trackBarrelAssoc; Produces muonBasic; Produces muonExtra; @@ -150,57 +171,99 @@ struct TableMaker { OutputObj fOutputList{"output"}; //! the histogram manager output list OutputObj fStatsList{"Statistics"}; //! skimming statistics + HistogramManager* fHistMan; // Event and track AnalysisCut configurables - Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; - Configurable fConfigTrackCuts{"cfgBarrelTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; - Configurable fConfigMuonCuts{"cfgMuonCuts", "muonQualityCuts", "Comma separated list of muon cuts"}; + struct : ConfigurableGroup { + Configurable fConfigEventCuts{"cfgEventCuts", "eventStandardNoINT7", "Event selection"}; + Configurable fConfigTrackCuts{"cfgBarrelTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; + Configurable fConfigMuonCuts{"cfgMuonCuts", "muonQualityCuts", "Comma separated list of muon cuts"}; + Configurable fConfigEventCutsJSON{"cfgEventCutsJSON", "", "Additional event selection in JSON format"}; + Configurable fConfigTrackCutsJSON{"cfgBarrelTrackCutsJSON", "", "Additional list of barrel track cuts in JSON format"}; + Configurable fConfigMuonCutsJSON{"cfgMuonCutsJSON", "", "Additional list of muon cuts in JSON format"}; + } fConfigCuts; + + // Zorro selection + struct : ConfigurableGroup { + Configurable fConfigRunZorro{"cfgRunZorro", false, "Enable event selection with zorro"}; + Configurable fConfigZorroTrigMask{"cfgZorroTriggerMask", "fDiMuon", "DQ Trigger masks: fSingleE,fLMeeIMR,fLMeeHMR,fDiElectron,fSingleMuLow,fSingleMuHigh,fDiMuon"}; + Configurable fConfigRunZorroSel{"cfgRunZorroSel", false, "Select events with trigger mask"}; + Configurable fBcTolerance{"cfgBcTolerance", 100, "Number of BCs of margin for software triggers"}; + } fConfigZorro; // Steer QA output - Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; - Configurable fConfigDetailedQA{"cfgDetailedQA", false, "If true, include more QA histograms (BeforeCuts classes)"}; - Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddMuonHistogram{"cfgAddMuonHistogram", "", "Comma separated list of histograms"}; + struct : ConfigurableGroup { + Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigDetailedQA{"cfgDetailedQA", false, "If true, include more QA histograms (BeforeCuts classes)"}; + Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddMuonHistogram{"cfgAddMuonHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + } fConfigHistOutput; - // Selections to be applied as Filter on the Track and FwdTrack Configurable fIsRun2{"cfgIsRun2", false, "Whether we analyze Run-2 or Run-3 data"}; - Configurable fConfigBarrelTrackMaxAbsEta{"cfgBarrelMaxAbsEta", 0.9f, "Eta absolute value cut for tracks in the barrel"}; - Configurable fConfigBarrelTrackMinPt{"cfgBarrelMinPt", 0.5f, "Minimum pt for tracks in the barrel"}; - Configurable fConfigBarrelRequireTPC{"cfgBarrelRequireTPC", true, "Require TPC for tracks in the barrel"}; - Configurable fConfigBarrelMinTPCncls{"cfgBarrelMinTPCncls", 50.0f, "Minimum TPC cls for tracks in the barrel"}; - Configurable fConfigBarrelMaxTPCchi2{"cfgBarrelMaxTPCchi2", 10.0f, "Maximum TPC chi2/ndf for tracks in the barrel"}; - Configurable fConfigBarrelRequireITS{"cfgBarrelRequireITS", true, "Require ITS for tracks in the barrel"}; - Configurable fConfigBarrelMaxITSchi2{"cfgBarrelMaxITSchi2", 36.0f, "Maximum ITS chi2/ndf for tracks in the barrel"}; - Configurable fConfigMuonPtLow{"cfgMuonLowPt", 1.0f, "Low pt cut for muons"}; + + // Selections to be applied as Filter on the Track and FwdTrack + /*struct : ConfigurableGroup { + Configurable fConfigBarrelTrackMaxAbsEta{"cfgBarrelMaxAbsEta", 0.9f, "Eta absolute value cut for tracks in the barrel"}; + Configurable fConfigBarrelTrackMinPt{"cfgBarrelMinPt", 0.5f, "Minimum pt for tracks in the barrel"}; + Configurable fConfigBarrelRequireTPC{"cfgBarrelRequireTPC", true, "Require TPC for tracks in the barrel"}; + Configurable fConfigBarrelMinTPCncls{"cfgBarrelMinTPCncls", 50.0f, "Minimum TPC cls for tracks in the barrel"}; + Configurable fConfigBarrelMaxTPCchi2{"cfgBarrelMaxTPCchi2", 10.0f, "Maximum TPC chi2/ndf for tracks in the barrel"}; + Configurable fConfigBarrelRequireITS{"cfgBarrelRequireITS", true, "Require ITS for tracks in the barrel"}; + Configurable fConfigBarrelMaxITSchi2{"cfgBarrelMaxITSchi2", 36.0f, "Maximum ITS chi2/ndf for tracks in the barrel"}; + Configurable fConfigMuonPtLow{"cfgMuonLowPt", 1.0f, "Low pt cut for muons"}; + } fConfigFilter;*/ // CCDB connection configurables - Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable fConfigCcdbPathTPC{"ccdb-path-tpc", "Users/z/zhxiong/TPCPID/PostCalib", "base path to the ccdb object"}; - Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable grpmagPathRun2{"grpmagPathRun2", "GLO/GRP/GRP", "CCDB path of the GRPObject (Usage for Run 2)"}; + struct : ConfigurableGroup { + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable fConfigCcdbPathTPC{"ccdb-path-tpc", "Users/z/zhxiong/TPCPID/PostCalib", "base path to the ccdb object"}; + Configurable fConfigCcdbPathZorro{"ccdb-path-zorro", "/Users/m/mpuccio/EventFiltering/OTS/Chunked/", "base path to the ccdb object for zorro"}; + Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable fConfigGeoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable fConfigGrpMagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable fConfigGrpMagPathRun2{"grpmagPathRun2", "GLO/GRP/GRP", "CCDB path of the GRPObject (Usage for Run 2)"}; + } fConfigCCDB; // TPC postcalibration related options - Configurable fConfigComputeTPCpostCalib{"cfgTPCpostCalib", false, "If true, compute TPC post-calibrated n-sigmas(electrons, pions, protons)"}; - Configurable fConfigComputeTPCpostCalibKaon{"cfgTPCpostCalibKaon", false, "If true, compute TPC post-calibrated n-sigmas for kaons"}; - Configurable fConfigIsOnlyforMaps{"cfgIsforMaps", false, "If true, run for postcalibration maps only"}; - Configurable fConfigSaveElectronSample{"cfgSaveElectronSample", false, "If true, only save electron sample"}; - Configurable fConfigDummyRunlist{"cfgDummyRunlist", false, "If true, use dummy runlist"}; - Configurable fConfigInitRunNumber{"cfgInitRunNumber", 543215, "Initial run number used in run by run checks"}; + struct : ConfigurableGroup { + Configurable fConfigComputeTPCpostCalib{"cfgTPCpostCalib", false, "If true, compute TPC post-calibrated n-sigmas(electrons, pions, protons)"}; + Configurable fConfigComputeTPCpostCalibKaon{"cfgTPCpostCalibKaon", false, "If true, compute TPC post-calibrated n-sigmas for kaons"}; + Configurable fConfigIsOnlyforMaps{"cfgIsforMaps", false, "If true, run for postcalibration maps only"}; + Configurable fConfigSaveElectronSample{"cfgSaveElectronSample", false, "If true, only save electron sample"}; + Configurable fConfigDummyRunlist{"cfgDummyRunlist", false, "If true, use dummy runlist"}; + Configurable fConfigInitRunNumber{"cfgInitRunNumber", 543215, "Initial run number used in run by run checks"}; + } fConfigPostCalibTPC; + + struct : ConfigurableGroup { + // Track related options + Configurable fPropTrack{"cfgPropTrack", true, "Propagate tracks to associated collision to recalculate DCA and momentum vector"}; + // Muon related options + Configurable fPropMuon{"cfgPropMuon", true, "Propagate muon tracks through absorber (do not use if applying pairing)"}; + Configurable fRefitGlobalMuon{"cfgRefitGlobalMuon", true, "Correct global muon parameters"}; + Configurable fMuonMatchEtaMin{"cfgMuonMatchEtaMin", -4.0f, "Definition of the acceptance of muon tracks to be matched with MFT"}; + Configurable fMuonMatchEtaMax{"cfgMuonMatchEtaMax", -2.5f, "Definition of the acceptance of muon tracks to be matched with MFT"}; + + // TPC occupancy related variables + Configurable fTPCShortPast{"cfgTPCShortPast", 8.0f, "Time in short past to look for occupancy (micro-seconds)"}; + Configurable fTPCShortFuture{"cfgTPCShortFuture", 8.0f, "Time in short future to look for occupancy (micro-seconds)"}; + Configurable fTPCLongPast{"cfgTPCLongPast", 100.0f, "Time in long past to look for occupancy (micro-seconds)"}; + Configurable fTPCLongFuture{"cfgTPCLongFuture", 100.0f, "Time in long future to look for occupancy (micro-seconds)"}; + Configurable fExcludeShort{"cfgTPCExcludeShort", true, "Exclude short term from long term occupancy (micro-seconds)"}; + } fConfigVariousOptions; Service fCCDB; + o2::ccdb::CcdbApi fCCDBApi; - o2::parameters::GRPObject* grpmagrun2 = nullptr; // for run 2, we access the GRPObject from GLO/GRP/GRP - o2::parameters::GRPMagField* grpmag = nullptr; // for run 3, we access GRPMagField from GLO/Config/GRPMagField + o2::parameters::GRPObject* fGrpMagRun2 = nullptr; // for run 2, we access the GRPObject from GLO/GRP/GRP + o2::parameters::GRPMagField* fGrpMag = nullptr; // for run 3, we access GRPMagField from GLO/Config/GRPMagField AnalysisCompositeCut* fEventCut; //! Event selection cut - std::vector fTrackCuts; //! Barrel track cuts - std::vector fMuonCuts; //! Muon track cuts + std::vector fTrackCuts; //! Barrel track cuts + std::vector fMuonCuts; //! Muon track cuts - Service ccdb; bool fDoDetailedQA = false; // Bool to set detailed QA true, if QA is set true int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. @@ -216,118 +279,186 @@ struct TableMaker { // our own Filtered tracks. If the filter is very selective, then it may be worth to run the association in this workflow // using the Common/CollisionAssociation class /*Filter barrelSelectedTracks = ifnode(fIsRun2.node() == true, track::trackType == uint8_t(track::Run2Track), track::trackType == uint8_t(track::Track)) - && track::pt > fConfigBarrelTrackMinPt - && nabs(track::eta) <= fConfigBarrelTrackMaxAbsEta - && ifnode(fConfigBarrelRequireITS.node() == true, track::itsChi2NCl < fConfigBarrelMaxITSchi2, true) - && ifnode(fConfigBarrelRequireTPC.node() == true, track::tpcNClsFound > fConfigBarrelMinTPCncls && track::tpcChi2NCl < fConfigBarrelMaxTPCchi2, true); + && track::pt > fConfigFilter.fConfigBarrelTrackMinPt + && nabs(track::eta) <= fConfigFilter.fConfigBarrelTrackMaxAbsEta + && ifnode(fConfigFilter.fConfigBarrelRequireITS.node() == true, track::itsChi2NCl < fConfigFilter.fConfigBarrelMaxITSchi2, true) + && ifnode(fConfigFilter.fConfigBarrelRequireTPC.node() == true, track::tpcNClsFound > fConfigFilter.fConfigBarrelMinTPCncls && track::tpcChi2NCl < fConfigFilter.fConfigBarrelMaxTPCchi2, true); - Filter muonFilter = o2::aod::fwdtrack::pt >= fConfigMuonPtLow;*/ + Filter muonFilter = o2::aod::fwdtrack::pt >= fConfigFilter.fConfigMuonPtLow;*/ Preslice trackIndicesPerCollision = aod::track_association::collisionId; Preslice fwdtrackIndicesPerCollision = aod::track_association::collisionId; Preslice mfttrackIndicesPerCollision = aod::track_association::collisionId; + Preslice preslice = aod::track::collisionId; + Partition tracksPos = (((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)) && (aod::track::tgl > static_cast(0.05))); + Partition tracksNeg = (((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)) && (aod::track::tgl < static_cast(-0.05))); + + Preslice presliceNoTOF = aod::track::collisionId; + Partition tracksPosNoTOF = (((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)) && (aod::track::tgl > static_cast(0.05))); + Partition tracksNegNoTOF = (((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)) && (aod::track::tgl < static_cast(-0.05))); + + struct { + std::map oMeanTimeShortA; + std::map oMeanTimeShortC; + std::map oMeanTimeLongA; + std::map oMeanTimeLongC; + std::map oMedianTimeShortA; + std::map oMedianTimeShortC; + std::map oMedianTimeLongA; + std::map oMedianTimeLongC; + std::map oContribShortA; + std::map oContribShortC; + std::map oContribLongA; + std::map oContribLongC; + } fOccup; + void init(o2::framework::InitContext& context) { - DefineCuts(); - ccdb->setURL(fConfigCcdbUrl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); + // CCDB configuration + if (fConfigPostCalibTPC.fConfigComputeTPCpostCalib) { + fCCDB->setURL(fConfigCCDB.fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + // Not later than now objects + fCCDB->setCreatedNotAfter(fConfigCCDB.fConfigNoLaterThan.value); + } + fCCDBApi.init(fConfigCCDB.fConfigCcdbUrl.value); + if (!o2::base::GeometryManager::isGeometryLoaded()) { - ccdb->get(geoPath); + fCCDB->get(fConfigCCDB.fConfigGeoPath); } + VarManager::SetDefaultVarNames(); // Important that this is called before DefineCuts() !! + + // Define the event, track and muon cuts + DefineCuts(); - VarManager::SetDefaultVarNames(); + // Initialize the histogram manager fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(kTRUE); fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); // Only use detailed QA when QA is set true - if (fConfigQA && fConfigDetailedQA) { + if (fConfigHistOutput.fConfigQA && fConfigHistOutput.fConfigDetailedQA) { fDoDetailedQA = true; } // Create the histogram class names to be added to the histogram manager + // The histogram class names are added into a string and then passed to the DefineHistograms() function which + // actually configures the HistogramManager + // Histograms are defined as histogram classes / groups and filled at specific points in the analysis flow TString histClasses = ""; + // Event-wise histograms, before selection cuts if (fDoDetailedQA) { histClasses += "Event_BeforeCuts;"; } - if (fConfigQA) { + // Event-wise histograms, after selection cuts + if (fConfigHistOutput.fConfigQA) { histClasses += "Event_AfterCuts;"; } - bool enableBarrelHistos = (context.mOptions.get("processPPWithFilter") || context.mOptions.get("processPPWithFilterBarrelOnly") || - context.mOptions.get("processPbPb") || context.mOptions.get("processPbPbBarrelOnly")); - bool enableMuonHistos = (context.mOptions.get("processPPWithFilter") || context.mOptions.get("processPPWithFilterMuonOnly") || context.mOptions.get("processPPWithFilterMuonMFT") || + // Check whether we have to define barrel or muon histograms + bool enableBarrelHistos = (context.mOptions.get("processPPWithFilter") || context.mOptions.get("processPPWithFilterBarrelOnly") || context.mOptions.get("processPPBarrelOnly") || + context.mOptions.get("processPbPb") || context.mOptions.get("processPbPbBarrelOnly") || context.mOptions.get("processPbPbBarrelOnlyWithV0Bits") || context.mOptions.get("processPbPbBarrelOnlyWithV0BitsNoTOF")) || + context.mOptions.get("processPbPbWithFilterBarrelOnly") || context.mOptions.get("processPPBarrelOnlyWithV0s"); + + bool enableMuonHistos = (context.mOptions.get("processPPWithFilter") || context.mOptions.get("processPPWithFilterMuonOnly") || context.mOptions.get("processPPWithFilterMuonMFT") || context.mOptions.get("processPPMuonOnly") || context.mOptions.get("processPPMuonMFT") || context.mOptions.get("processPPMuonMFTWithMultsExtra") || context.mOptions.get("processPbPb") || context.mOptions.get("processPbPbMuonOnly") || context.mOptions.get("processPbPbMuonMFT")); if (enableBarrelHistos) { + // Barrel track histograms, before selections if (fDoDetailedQA) { histClasses += "TrackBarrel_BeforeCuts;"; } - if (fConfigQA) { + if (fConfigHistOutput.fConfigQA) { + // Barrel track histograms after selections; one histogram directory for each user specified selection for (auto& cut : fTrackCuts) { - histClasses += Form("TrackBarrel_%s;", cut.GetName()); + histClasses += Form("TrackBarrel_%s;", cut->GetName()); } } - if (fConfigIsOnlyforMaps) { + // Barrel histograms for clean samples of V0 legs used for post-calibration + if (fConfigPostCalibTPC.fConfigIsOnlyforMaps) { histClasses += "TrackBarrel_PostCalibElectron;"; histClasses += "TrackBarrel_PostCalibPion;"; histClasses += "TrackBarrel_PostCalibProton;"; } } if (enableMuonHistos) { + // Muon tracks before cuts and MFT tracks if (fDoDetailedQA) { histClasses += "Muons_BeforeCuts;"; histClasses += "MftTracks;"; } - if (fConfigQA) { + if (fConfigHistOutput.fConfigQA) { + // Muon tracks after selections; one directory per selection for (auto& muonCut : fMuonCuts) { - histClasses += Form("Muons_%s;", muonCut.GetName()); + histClasses += Form("Muons_%s;", muonCut->GetName()); } } } - if (fConfigDummyRunlist) { - VarManager::SetDummyRunlist(fConfigInitRunNumber); + if (fConfigPostCalibTPC.fConfigDummyRunlist) { + VarManager::SetDummyRunlist(fConfigPostCalibTPC.fConfigInitRunNumber); } DefineHistograms(histClasses); // define all histograms + // Additional histogram via the JSON configurable + TString addHistsStr = fConfigHistOutput.fConfigAddJSONHistograms.value; + if (fConfigHistOutput.fConfigQA && addHistsStr != "") { + dqhistograms::AddHistogramsFromJSON(fHistMan, addHistsStr.Data()); + } VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); - - // CCDB configuration - if (fConfigComputeTPCpostCalib) { - fCCDB->setURL(fConfigCcdbUrl.value); - fCCDB->setCaching(true); - fCCDB->setLocalObjectValidityChecking(); - // Not later than now objects - fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); - } } void DefineCuts() { // Event cuts fEventCut = new AnalysisCompositeCut(true); - TString eventCutStr = fConfigEventCuts.value; - fEventCut->AddCut(dqcuts::GetAnalysisCut(eventCutStr.Data())); + TString eventCutStr = fConfigCuts.fConfigEventCuts.value; + if (eventCutStr != "") { + fEventCut->AddCut(dqcuts::GetAnalysisCut(eventCutStr.Data())); + } + // Extra event cuts via JSON + TString addEvCutsStr = fConfigCuts.fConfigEventCutsJSON.value; + if (addEvCutsStr != "") { + std::vector addEvCuts = dqcuts::GetCutsFromJSON(addEvCutsStr.Data()); + for (auto& cutIt : addEvCuts) { + fEventCut->AddCut(cutIt); + } + } // Barrel track cuts - TString cutNamesStr = fConfigTrackCuts.value; + TString cutNamesStr = fConfigCuts.fConfigTrackCuts.value; if (!cutNamesStr.IsNull()) { std::unique_ptr objArray(cutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - fTrackCuts.push_back(*dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + fTrackCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + } + } + // extra cuts via JSON + TString addTrackCutsStr = fConfigCuts.fConfigTrackCutsJSON.value; + if (addTrackCutsStr != "") { + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + for (auto& t : addTrackCuts) { + fTrackCuts.push_back(reinterpret_cast(t)); } } // Muon cuts - cutNamesStr = fConfigMuonCuts.value; + cutNamesStr = fConfigCuts.fConfigMuonCuts.value; if (!cutNamesStr.IsNull()) { std::unique_ptr objArray(cutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - fMuonCuts.push_back(*dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + fMuonCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + } + } + // Extra cuts via JSON + TString addMuonCutsStr = fConfigCuts.fConfigMuonCutsJSON.value; + if (addMuonCutsStr != "") { + std::vector addMuonCuts = dqcuts::GetCutsFromJSON(addMuonCutsStr.Data()); + for (auto& t : addMuonCuts) { + fMuonCuts.push_back(reinterpret_cast(t)); } } @@ -336,15 +467,16 @@ struct TableMaker { void DefineHistograms(TString histClasses) { + // Create histograms via HistogramManager std::unique_ptr objArray(histClasses.Tokenize(";")); for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { TString classStr = objArray->At(iclass)->GetName(); - if (fConfigQA) { + if (fConfigHistOutput.fConfigQA) { fHistMan->AddHistClass(classStr.Data()); } // fill the THn histograms - if (fConfigIsOnlyforMaps) { + if (fConfigPostCalibTPC.fConfigIsOnlyforMaps) { if (classStr.Contains("PostCalibElectron")) { dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "track", "postcalib_electron"); } @@ -356,40 +488,46 @@ struct TableMaker { } } - TString histEventName = fConfigAddEventHistogram.value; + TString histEventName = fConfigHistOutput.fConfigAddEventHistogram.value; if (classStr.Contains("Event")) { - if (fConfigQA) { + if (fConfigHistOutput.fConfigQA) { dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "event", histEventName); } } - TString histTrackName = fConfigAddTrackHistogram.value; + TString histTrackName = fConfigHistOutput.fConfigAddTrackHistogram.value; if (classStr.Contains("Track")) { - if (fConfigQA) { + if (fConfigHistOutput.fConfigQA) { dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "track", histTrackName); } } - TString histMuonName = fConfigAddMuonHistogram.value; + TString histMuonName = fConfigHistOutput.fConfigAddMuonHistogram.value; if (classStr.Contains("Muons")) { - if (fConfigQA) { + if (fConfigHistOutput.fConfigQA) { dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "track", histMuonName); } } - TString histMftName = fConfigAddMuonHistogram.value; + TString histMftName = fConfigHistOutput.fConfigAddMuonHistogram.value; if (classStr.Contains("Mft")) { - if (fConfigDetailedQA) { + if (fConfigHistOutput.fConfigDetailedQA) { dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "track", histMftName); } } } - // create statistics histograms (event, tracks, muons) + // Create statistics histograms which will be stored in the QA output + // Event statistics: kStatsEvent + // Track statistics: kStatsTracks + // Muon statistics: kStatsMuons + // Orphan track statistics: kStatsOrphanTracks + // Zorro information: kStatsZorroInfo + // Zorro trigger selection: kStatsZorroSel fStatsList.setObject(new TList()); fStatsList->SetOwner(kTRUE); std::vector eventLabels{"BCs", "Collisions before filtering", "Before cuts", "After cuts"}; - TH2I* histEvents = new TH2I("EventStats", "Event statistics", eventLabels.size(), -0.5, eventLabels.size() - 0.5, o2::aod::evsel::kNsel + 1, -0.5, double(o2::aod::evsel::kNsel) + 0.5); + TH2D* histEvents = new TH2D("EventStats", "Event statistics", eventLabels.size(), -0.5, eventLabels.size() - 0.5, o2::aod::evsel::kNsel + 1, -0.5, static_cast(o2::aod::evsel::kNsel) + 0.5); int ib = 1; for (auto label = eventLabels.begin(); label != eventLabels.end(); label++, ib++) { histEvents->GetXaxis()->SetBinLabel(ib, (*label).Data()); @@ -398,32 +536,220 @@ struct TableMaker { histEvents->GetYaxis()->SetBinLabel(ib, o2::aod::evsel::selectionLabels[ib - 1]); } histEvents->GetYaxis()->SetBinLabel(o2::aod::evsel::kNsel + 1, "Total"); - fStatsList->Add(histEvents); + fStatsList->AddAt(histEvents, kStatsEvent); // Track statistics: one bin for each track selection and 5 bins for V0 tags (gamma, K0s, Lambda, anti-Lambda, Omega) - TH1I* histTracks = new TH1I("TrackStats", "Track statistics", fTrackCuts.size() + 5.0, -0.5, fTrackCuts.size() - 0.5 + 5.0); + TH1D* histTracks = new TH1D("TrackStats", "Track statistics", fTrackCuts.size() + 5.0, -0.5, fTrackCuts.size() - 0.5 + 5.0); ib = 1; for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, ib++) { - histTracks->GetXaxis()->SetBinLabel(ib, (*cut).GetName()); + histTracks->GetXaxis()->SetBinLabel(ib, (*cut)->GetName()); } const char* v0TagNames[5] = {"Photon conversion", "K^{0}_{s}", "#Lambda", "#bar{#Lambda}", "#Omega"}; for (ib = 0; ib < 5; ib++) { histTracks->GetXaxis()->SetBinLabel(fTrackCuts.size() + 1 + ib, v0TagNames[ib]); } - fStatsList->Add(histTracks); - TH1I* histMuons = new TH1I("MuonStats", "Muon statistics", fMuonCuts.size(), -0.5, fMuonCuts.size() - 0.5); + fStatsList->AddAt(histTracks, kStatsTracks); + + TH1D* histMuons = new TH1D("MuonStats", "Muon statistics", fMuonCuts.size(), -0.5, fMuonCuts.size() - 0.5); ib = 1; for (auto cut = fMuonCuts.begin(); cut != fMuonCuts.end(); cut++, ib++) { - histMuons->GetXaxis()->SetBinLabel(ib, (*cut).GetName()); + histMuons->GetXaxis()->SetBinLabel(ib, (*cut)->GetName()); } - fStatsList->Add(histMuons); + fStatsList->AddAt(histMuons, kStatsMuons); + + TH1D* histOrphanTracks = new TH1D("histOrphanTracks", "Orphan Track statistics", 2, -1, 1); + histOrphanTracks->GetXaxis()->SetBinLabel(1, "Track w/o collision ID"); + histOrphanTracks->GetXaxis()->SetBinLabel(2, "Track with +ve collision ID"); + fStatsList->AddAt(histOrphanTracks, kStatsOrphanTracks); + + TH2D* histZorroInfo = new TH2D("ZorroInfo", "Zorro information", 1, -0.5, 0.5, 1, -0.5, 0.5); + fStatsList->AddAt(histZorroInfo, kStatsZorroInfo); + + TH2D* histZorroSel = new TH2D("ZorroSel", "trigger of interested", 1, -0.5, 0.5, 1, -0.5, 0.5); + fStatsList->AddAt(histZorroSel, kStatsZorroSel); } - template - void skimCollisions(TEvents const& collisions, BCsWithTimestamps const& /*bcs*/) + template + void computeOccupancyEstimators(TEvents const& collisions, Partition const& tracksPos, Partition const& tracksNeg, Preslice& preslice, TBCs const&) + { + + // clear the occupancy maps for this time frame + fOccup.oMeanTimeLongA.clear(); + fOccup.oMeanTimeLongC.clear(); + fOccup.oMeanTimeShortA.clear(); + fOccup.oMeanTimeShortC.clear(); + fOccup.oMedianTimeLongA.clear(); + fOccup.oMedianTimeLongC.clear(); + fOccup.oMedianTimeShortA.clear(); + fOccup.oMedianTimeShortC.clear(); + fOccup.oContribLongA.clear(); + fOccup.oContribLongC.clear(); + fOccup.oContribShortA.clear(); + fOccup.oContribShortC.clear(); + + std::map oBC; // key: collision index; value: global BC + std::map> oBCreversed; // key: global BC, value: list of collisions attached to this BC + std::map oVtxZ; // key: collision index; value: vtx-z position + std::map collMultPos; // key: collision index; value: tpc multiplicity on the A side + std::map collMultNeg; // key: collision index; value: tpc multiplicity on the C side + + const double bcUS = o2::constants::lhc::LHCBunchSpacingNS / 1000.0; // BC spacing in micro-seconds + const double vdrift = 2.5; // cm / mus + int32_t bcShortPast = std::lrint(fConfigVariousOptions.fTPCShortPast / bcUS); // (close in time collisions) 8 micro-seconds in BC intervals + int32_t bcShortFuture = std::lrint(fConfigVariousOptions.fTPCShortFuture / bcUS); // (close in time collisions) 8 micro-seconds in BC intervals + int32_t bcLongPast = std::lrint(fConfigVariousOptions.fTPCLongPast / bcUS); // (wide time range collisions) past 40 micro-seconds in BC intervals + int32_t bcLongFuture = std::lrint(fConfigVariousOptions.fTPCLongFuture / bcUS); // // (wide time range collisions) future 100 micro-seconds in BC intervals + + // Loop over collisions and extract needed info (BC, vtxZ, multiplicity separately in A and C sides) + for (const auto& collision : collisions) { + + auto bcEvSel = collision.template foundBC_as(); + int64_t bc = bcEvSel.globalBC(); + oBC[collision.globalIndex()] = bc; + oVtxZ[collision.globalIndex()] = collision.posZ(); + + // if more than one collision per bunch, add that collision to the list for that bunch + if (oBCreversed.find(bc) == oBCreversed.end()) { + std::vector evs = {collision.globalIndex()}; + oBCreversed[bc] = evs; + } else { + auto& evs = oBCreversed[bc]; + evs.push_back(collision.globalIndex()); + } + + // make a slice for this collision and get the number of tracks + auto thisCollTrackPos = tracksPos.sliceBy(preslice, collision.globalIndex()); + auto thisCollTrackNeg = tracksNeg.sliceBy(preslice, collision.globalIndex()); + collMultPos[collision.globalIndex()] = thisCollTrackPos.size(); + collMultNeg[collision.globalIndex()] = thisCollTrackNeg.size(); + } + + // loop over collisions and sum the multiplicity in the past and future + for (const auto& [collision, bc] : oBC) { + + int64_t pastShortBC = oBCreversed.lower_bound(bc - bcShortPast)->first; + int64_t futureShortBC = oBCreversed.lower_bound(bc + bcShortFuture)->first; + int64_t pastLongBC = oBCreversed.lower_bound(bc - bcLongPast)->first; + int64_t futureLongBC = oBCreversed.lower_bound(bc + bcLongFuture)->first; + + fOccup.oContribLongA[collision] = 0; + fOccup.oContribLongC[collision] = 0; + fOccup.oMeanTimeLongA[collision] = 0.0; + fOccup.oMeanTimeLongC[collision] = 0.0; + fOccup.oContribShortA[collision] = 0; + fOccup.oContribShortC[collision] = 0; + fOccup.oMeanTimeShortA[collision] = 0.0; + fOccup.oMeanTimeShortC[collision] = 0.0; + std::map oTimeMapShortA; + std::map oTimeMapShortC; + std::map oTimeMapLongA; + std::map oTimeMapLongC; + // loop over the BCs in the past and future wrt this one + for (auto bcIt = oBCreversed.find(pastLongBC); bcIt != oBCreversed.find(futureLongBC); ++bcIt) { + int64_t thisBC = bcIt->first; + auto colls = bcIt->second; + // delta time due to the different BCs + float dt = (thisBC - bc) * bcUS; + // check if this collision is also within the short time range + bool isShort = (thisBC >= pastShortBC && thisBC < futureShortBC); + // loop over all collisions in this BC + for (auto& thisColl : colls) { + // skip if this is the same collision + if (thisColl == collision) { + continue; + } + // compute the delta time due to the difference in longitudinal position + float dtDrift = (oVtxZ[thisColl] - oVtxZ[collision]) / vdrift; + + if (!(fConfigVariousOptions.fExcludeShort && isShort)) { + // sum the collision multiplicity on A and C sides + fOccup.oContribLongA[collision] += collMultPos[thisColl]; + fOccup.oContribLongC[collision] += collMultNeg[thisColl]; + // compute the multiplicity weighted average time + fOccup.oMeanTimeLongA[collision] += collMultPos[thisColl] * (dt + dtDrift); + fOccup.oMeanTimeLongC[collision] += collMultNeg[thisColl] * (dt - dtDrift); + // fill the time map + oTimeMapLongA[dt + dtDrift] = collMultPos[thisColl]; + oTimeMapLongC[dt - dtDrift] = collMultNeg[thisColl]; + } + + if (isShort) { + fOccup.oContribShortA[collision] += collMultPos[thisColl]; + fOccup.oContribShortC[collision] += collMultNeg[thisColl]; + fOccup.oMeanTimeShortA[collision] += collMultPos[thisColl] * (dt + dtDrift); + fOccup.oMeanTimeShortC[collision] += collMultNeg[thisColl] * (dt - dtDrift); + oTimeMapShortA[dt + dtDrift] = collMultPos[thisColl]; + oTimeMapShortC[dt - dtDrift] = collMultNeg[thisColl]; + } + } + } + // normalize to obtain the mean time + if (fOccup.oContribLongA[collision] > 0) { + fOccup.oMeanTimeLongA[collision] /= fOccup.oContribLongA[collision]; + } + if (fOccup.oContribLongC[collision] > 0) { + fOccup.oMeanTimeLongC[collision] /= fOccup.oContribLongC[collision]; + } + if (fOccup.oContribShortA[collision] > 0) { + fOccup.oMeanTimeShortA[collision] /= fOccup.oContribShortA[collision]; + } + if (fOccup.oContribShortC[collision] > 0) { + fOccup.oMeanTimeShortC[collision] /= fOccup.oContribShortC[collision]; + } + // iterate over the time maps to obtain the median time + fOccup.oMedianTimeLongA[collision] = 0.0; + float sumMult = 0.0; + if (oTimeMapLongA.size() > 0) { + for (auto& [dt, mult] : oTimeMapLongA) { + sumMult += mult; + if (sumMult > fOccup.oContribLongA[collision] / 2.0) { + fOccup.oMedianTimeLongA[collision] = dt; + break; + } + } + } + fOccup.oMedianTimeLongC[collision] = 0.0; + sumMult = 0.0; + if (oTimeMapLongC.size() > 0) { + for (auto& [dt, mult] : oTimeMapLongC) { + sumMult += mult; + if (sumMult > fOccup.oContribLongC[collision] / 2.0) { + fOccup.oMedianTimeLongC[collision] = dt; + break; + } + } + } + fOccup.oMedianTimeShortA[collision] = 0.0; + sumMult = 0.0; + if (oTimeMapShortA.size() > 0) { + for (auto& [dt, mult] : oTimeMapShortA) { + sumMult += mult; + if (sumMult > fOccup.oContribShortA[collision] / 2.0) { + fOccup.oMedianTimeShortA[collision] = dt; + break; + } + } + } + fOccup.oMedianTimeShortC[collision] = 0.0; + sumMult = 0.0; + if (oTimeMapShortC.size() > 0) { + for (auto& [dt, mult] : oTimeMapShortC) { + sumMult += mult; + if (sumMult > fOccup.oContribShortC[collision] / 2.0) { + fOccup.oMedianTimeShortC[collision] = dt; + break; + } + } + } + } // end loop over collisions + } + + template + void skimCollisions(TEvents const& collisions, TBCs const& /*bcs*/, TZdcs const& /*zdcs*/, + TTrackAssoc const& trackAssocs, TTracks const& tracks) { // Skim collisions - // NOTE: So far, collisions are filtered based on the user specified analysis cuts and the filterPP event filter. + // NOTE: So far, collisions are filtered based on the user specified analysis cuts AND the filterPP or Zorro event filter. // The collision-track associations which point to an event that is not selected for writing are discarded! fCollIndexMap.clear(); @@ -444,40 +770,63 @@ struct TableMaker { for (int i = 0; i < o2::aod::evsel::kNsel; i++) { if (collision.selection_bit(i)) { - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(i)); + (reinterpret_cast(fStatsList->At(kStatsEvent)))->Fill(1.0, static_cast(i)); } } - (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(o2::aod::evsel::kNsel)); + (reinterpret_cast(fStatsList->At(kStatsEvent)))->Fill(1.0, static_cast(o2::aod::evsel::kNsel)); // apply the event filter computed by filter-PP - if constexpr ((TEventFillMap & VarManager::ObjTypes::EventFilter) > 0) { + if constexpr ((TEventFillMap & VarManager::ObjTypes::EventFilter) > 0 || (TEventFillMap & VarManager::ObjTypes::RapidityGapFilter) > 0) { if (!collision.eventFilter()) { continue; } } - auto bc = collision.template bc_as(); + auto bc = collision.template bc_as(); // store the selection decisions uint64_t tag = 0; // store some more information in the tag // if the BC found by event selection does not coincide with the collision.bc() - auto bcEvSel = collision.template foundBC_as(); + auto bcEvSel = collision.template foundBC_as(); if (bcEvSel.globalIndex() != bc.globalIndex()) { - tag |= (uint64_t(1) << 0); + tag |= (static_cast(1) << 0); } // Put the 8 first bits of the event filter in the last 8 bits of the tag - if constexpr ((TEventFillMap & VarManager::ObjTypes::EventFilter) > 0) { + if constexpr ((TEventFillMap & VarManager::ObjTypes::EventFilter) > 0 || (TEventFillMap & VarManager::ObjTypes::RapidityGapFilter) > 0) { tag |= (collision.eventFilter() << 56); } VarManager::ResetValues(0, VarManager::kNEventWiseVariables); - // TODO: These variables cannot be filled in the VarManager for the moment as long as BCsWithTimestamps are used. - // So temporarily, we filled them here, in order to be available for eventual QA of the skimming - VarManager::fgValues[VarManager::kRunNo] = bc.runNumber(); - VarManager::fgValues[VarManager::kBC] = bc.globalBC(); - VarManager::fgValues[VarManager::kTimestamp] = bc.timestamp(); - VarManager::fgValues[VarManager::kRunIndex] = VarManager::GetRunIndex(bc.runNumber()); + VarManager::FillBC(bc); VarManager::FillEvent(collision); // extract event information and place it in the fValues array + if constexpr ((TEventFillMap & VarManager::ObjTypes::Zdc) > 0) { + if constexpr ((TEventFillMap & VarManager::ObjTypes::RapidityGapFilter) > 0) { + // Collision table already has ZDC info + VarManager::FillZDC(collision); + } else if (bcEvSel.has_zdc()) { + auto bc_zdc = bcEvSel.zdc(); + VarManager::FillZDC(bc_zdc); + } + } + if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionMultExtra) > 0 && (TTrackFillMap & VarManager::ObjTypes::Track) > 0 && (TTrackFillMap & VarManager::ObjTypes::TrackDCA) > 0) { + auto groupedTrackIndices = trackAssocs.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + VarManager::FillEventTrackEstimators(collision, groupedTrackIndices, tracks); + } + // Exceptionally fill the TPC occupancy quantities here + if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionMultExtra) > 0) { + VarManager::fgValues[VarManager::kNTPCcontribLongA] = fOccup.oContribLongA[collision.globalIndex()]; + VarManager::fgValues[VarManager::kNTPCcontribLongC] = fOccup.oContribLongC[collision.globalIndex()]; + VarManager::fgValues[VarManager::kNTPCmeanTimeLongA] = fOccup.oMeanTimeLongA[collision.globalIndex()]; + VarManager::fgValues[VarManager::kNTPCmeanTimeLongC] = fOccup.oMeanTimeLongC[collision.globalIndex()]; + VarManager::fgValues[VarManager::kNTPCmedianTimeLongA] = fOccup.oMedianTimeLongA[collision.globalIndex()]; + VarManager::fgValues[VarManager::kNTPCmedianTimeLongC] = fOccup.oMedianTimeLongC[collision.globalIndex()]; + VarManager::fgValues[VarManager::kNTPCcontribShortA] = fOccup.oContribShortA[collision.globalIndex()]; + VarManager::fgValues[VarManager::kNTPCcontribShortC] = fOccup.oContribShortC[collision.globalIndex()]; + VarManager::fgValues[VarManager::kNTPCmeanTimeShortA] = fOccup.oMeanTimeShortA[collision.globalIndex()]; + VarManager::fgValues[VarManager::kNTPCmeanTimeShortC] = fOccup.oMeanTimeShortC[collision.globalIndex()]; + VarManager::fgValues[VarManager::kNTPCmedianTimeShortA] = fOccup.oMedianTimeShortA[collision.globalIndex()]; + VarManager::fgValues[VarManager::kNTPCmedianTimeShortC] = fOccup.oMedianTimeShortC[collision.globalIndex()]; + } if (fDoDetailedQA) { fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); } @@ -485,39 +834,62 @@ struct TableMaker { // fill stats information, before selections for (int i = 0; i < o2::aod::evsel::kNsel; i++) { if (collision.selection_bit(i)) { - (reinterpret_cast(fStatsList->At(0)))->Fill(2.0, static_cast(i)); + (reinterpret_cast(fStatsList->At(kStatsEvent)))->Fill(2.0, static_cast(i)); } } - (reinterpret_cast(fStatsList->At(0)))->Fill(2.0, static_cast(o2::aod::evsel::kNsel)); - - if (!fEventCut->IsSelected(VarManager::fgValues)) { - continue; + (reinterpret_cast(fStatsList->At(kStatsEvent)))->Fill(2.0, static_cast(o2::aod::evsel::kNsel)); + + if (fConfigZorro.fConfigRunZorro) { + zorro.setBaseCCDBPath(fConfigCCDB.fConfigCcdbPathZorro.value); + zorro.setBCtolerance(fConfigZorro.fBcTolerance); + zorro.initCCDB(fCCDB.service, fCurrentRun, bc.timestamp(), fConfigZorro.fConfigZorroTrigMask.value); + zorro.populateExternalHists(fCurrentRun, reinterpret_cast(fStatsList->At(kStatsZorroInfo)), reinterpret_cast(fStatsList->At(kStatsZorroSel))); + bool zorroSel = zorro.isSelected(bc.globalBC(), fConfigZorro.fBcTolerance, reinterpret_cast(fStatsList->At(kStatsZorroSel))); + if (zorroSel) { + tag |= (static_cast(true) << 56); // the same bit is used for this zorro selections from ccdb + } + if (fConfigZorro.fConfigRunZorroSel && (!zorroSel || !fEventCut->IsSelected(VarManager::fgValues))) { + continue; + } + } else { + if (!fEventCut->IsSelected(VarManager::fgValues)) { + continue; + } } // fill stats information, after selections for (int i = 0; i < o2::aod::evsel::kNsel; i++) { if (collision.selection_bit(i)) { - (reinterpret_cast(fStatsList->At(0)))->Fill(3.0, static_cast(i)); + (reinterpret_cast(fStatsList->At(kStatsEvent)))->Fill(3.0, static_cast(i)); } } - (reinterpret_cast(fStatsList->At(0)))->Fill(3.0, static_cast(o2::aod::evsel::kNsel)); + (reinterpret_cast(fStatsList->At(kStatsEvent)))->Fill(3.0, static_cast(o2::aod::evsel::kNsel)); fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); // create the event tables event(tag, bc.runNumber(), collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), collision.collisionTime(), collision.collisionTimeRes()); if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionMult) > 0) { - multTPC = collision.multTPC(); - multFV0A = collision.multFV0A(); multFV0C = collision.multFV0C(); - multFT0A = collision.multFT0A(); - multFT0C = collision.multFT0C(); - multFDDA = collision.multFDDA(); - multFDDC = collision.multFDDC(); + multTPC = collision.multTPC(); multZNA = collision.multZNA(); multZNC = collision.multZNC(); multTracklets = collision.multTracklets(); multTracksPV = collision.multNTracksPV(); + if constexpr ((TEventFillMap & VarManager::ObjTypes::RapidityGapFilter) > 0) { + // Use the FIT signals from the nearest BC with FIT amplitude above threshold + multFV0A = collision.newBcMultFV0A(); + multFT0A = collision.newBcMultFT0A(); + multFT0C = collision.newBcMultFT0C(); + multFDDA = collision.newBcMultFDDA(); + multFDDC = collision.newBcMultFDDC(); + } else { + multFV0A = collision.multFV0A(); + multFT0A = collision.multFT0A(); + multFT0C = collision.multFT0C(); + multFDDA = collision.multFDDA(); + multFDDC = collision.multFDDC(); + } } if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionCent) > 0) { centFT0C = collision.centFT0C(); @@ -525,28 +897,74 @@ struct TableMaker { eventExtended(bc.globalBC(), collision.alias_raw(), collision.selection_raw(), bc.timestamp(), VarManager::fgValues[VarManager::kCentVZERO], multTPC, multFV0A, multFV0C, multFT0A, multFT0C, multFDDA, multFDDC, multZNA, multZNC, multTracklets, multTracksPV, centFT0C); eventVtxCov(collision.covXX(), collision.covXY(), collision.covXZ(), collision.covYY(), collision.covYZ(), collision.covZZ(), collision.chi2()); + eventInfo(collision.globalIndex()); + if constexpr ((TEventFillMap & VarManager::ObjTypes::Zdc) > 0) { + if constexpr ((TEventFillMap & VarManager::ObjTypes::RapidityGapFilter) > 0) { + // ZDC information is already in the DQRapidityGapFilter + zdc(collision.energyCommonZNA(), collision.energyCommonZNC(), collision.energyCommonZPA(), collision.energyCommonZPC(), + collision.timeZNA(), collision.timeZNC(), collision.timeZPA(), collision.timeZPC()); + } else if (bcEvSel.has_zdc()) { + auto bc_zdc = bcEvSel.zdc(); + zdc(bc_zdc.energyCommonZNA(), bc_zdc.energyCommonZNC(), bc_zdc.energyCommonZPA(), bc_zdc.energyCommonZPC(), + bc_zdc.timeZNA(), bc_zdc.timeZNC(), bc_zdc.timeZPA(), bc_zdc.timeZPC()); + } else { + zdc(-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0); + } + } + if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionMultExtra) > 0) { + multPV(collision.multNTracksHasITS(), collision.multNTracksHasTPC(), collision.multNTracksHasTOF(), collision.multNTracksHasTRD(), + collision.multNTracksITSOnly(), collision.multNTracksTPCOnly(), collision.multNTracksITSTPC(), + collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + + multAll(collision.multAllTracksTPCOnly(), collision.multAllTracksITSTPC(), + fOccup.oContribLongA[collision.globalIndex()], fOccup.oContribLongC[collision.globalIndex()], + fOccup.oMeanTimeLongA[collision.globalIndex()], fOccup.oMeanTimeLongC[collision.globalIndex()], + fOccup.oMedianTimeLongA[collision.globalIndex()], fOccup.oMedianTimeLongC[collision.globalIndex()], + fOccup.oContribShortA[collision.globalIndex()], fOccup.oContribShortC[collision.globalIndex()], + fOccup.oMeanTimeShortA[collision.globalIndex()], fOccup.oMeanTimeShortC[collision.globalIndex()], + fOccup.oMedianTimeShortA[collision.globalIndex()], fOccup.oMedianTimeShortC[collision.globalIndex()]); + } fCollIndexMap[collision.globalIndex()] = event.lastIndex(); } } - template - void skimTracks(TEvent const& collision, BCsWithTimestamps const& /*bcs*/, TTracks const& /*tracks*/, TrackAssoc const& assocs) + template + void skimTracks(TEvent const& collision, TBCs const& /*bcs*/, TTracks const& /*tracks*/, TrackAssoc const& assocs) { // Skim the barrel tracks // Loop over the collision-track associations, retrieve the track, and apply track cuts for selection // One can apply here cuts which depend on the association (e.g. DCA), which will discard (hopefully most) wrong associations. // Tracks are written only once, even if they constribute to more than one association - uint64_t trackFilteringTag = uint64_t(0); - uint64_t trackTempFilterMap = uint8_t(0); + uint64_t trackFilteringTag = static_cast(0); + uint32_t trackTempFilterMap = static_cast(0); + + // material correction for track propagation + // TODO: Do we need a configurable to switch between different material correction options? + // o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; for (const auto& assoc : assocs) { + // get the track auto track = assoc.template track_as(); - trackFilteringTag = uint64_t(0); - trackTempFilterMap = uint8_t(0); + // If the original collision of this track was not selected for skimming, then we skip this track. + // Normally, the filter-pp is selecting all collisions which contain the tracks which contributed to the triggering + // of an event, so this is rejecting possibly a few tracks unrelated to the trigger, originally associated with collisions distant in time. + if (fCollIndexMap.find(track.collisionId()) == fCollIndexMap.end()) { + continue; + } + + trackFilteringTag = static_cast(0); + trackTempFilterMap = static_cast(0); VarManager::FillTrack(track); + + // compute quantities which depend on the associated collision, such as DCA + if (fConfigVariousOptions.fPropTrack && (track.collisionId() != collision.globalIndex())) { + VarManager::FillTrackCollisionMatCorr(track, collision, noMatCorr, o2::base::Propagator::Instance()); + } + if (fDoDetailedQA) { fHistMan->FillHistClass("TrackBarrel_BeforeCuts", VarManager::fgValues); } @@ -554,101 +972,125 @@ struct TableMaker { // apply track cuts and fill stats histogram int i = 0; for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, i++) { - if ((*cut).IsSelected(VarManager::fgValues)) { - trackTempFilterMap |= (uint8_t(1) << i); - // NOTE: the QA is filled here for every (collision,track) association since the results of the track cuts can be different depending on which collision is associated (e.g. DCA cuts) - // TODO: create a statistics histograms with unique tracks - if (fConfigQA) { - fHistMan->FillHistClass(Form("TrackBarrel_%s", (*cut).GetName()), VarManager::fgValues); + if ((*cut)->IsSelected(VarManager::fgValues)) { + trackTempFilterMap |= (static_cast(1) << i); + // NOTE: the QA is filled here just for the first occurence of this track. + // So if there are histograms of quantities which depend on the collision association, these will not be accurate + if (fConfigHistOutput.fConfigQA && (fTrackIndexMap.find(track.globalIndex()) == fTrackIndexMap.end())) { + fHistMan->FillHistClass(Form("TrackBarrel_%s", (*cut)->GetName()), VarManager::fgValues); } - (reinterpret_cast(fStatsList->At(1)))->Fill(static_cast(i)); + (reinterpret_cast(fStatsList->At(kStatsTracks)))->Fill(static_cast(i)); } } if (!trackTempFilterMap) { continue; } + // If this track is already present in the index map, it means it was already skimmed, + // so we just store the association and we skip the track + if (fTrackIndexMap.find(track.globalIndex()) != fTrackIndexMap.end()) { + trackBarrelAssoc(fCollIndexMap[collision.globalIndex()], fTrackIndexMap[track.globalIndex()]); + continue; + } + // store selection information in the track tag if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackV0Bits)) { // BIT0-4: V0Bits - trackFilteringTag |= uint64_t(track.pidbit()); + trackFilteringTag |= static_cast(track.pidbit()); for (int iv0 = 0; iv0 < 5; iv0++) { if (track.pidbit() & (uint8_t(1) << iv0)) { - (reinterpret_cast(fStatsList->At(1)))->Fill(fTrackCuts.size() + static_cast(iv0)); + (reinterpret_cast(fStatsList->At(kStatsTracks)))->Fill(fTrackCuts.size() + static_cast(iv0)); } } - if (fConfigIsOnlyforMaps) { - if (trackFilteringTag & (uint64_t(1) << VarManager::kIsConversionLeg)) { // for electron + if (fConfigPostCalibTPC.fConfigIsOnlyforMaps) { + if (trackFilteringTag & (static_cast(1) << VarManager::kIsConversionLeg)) { // for electron fHistMan->FillHistClass("TrackBarrel_PostCalibElectron", VarManager::fgValues); } - if (trackFilteringTag & (uint64_t(1) << VarManager::kIsK0sLeg)) { // for pion + if (trackFilteringTag & (static_cast(1) << VarManager::kIsK0sLeg)) { // for pion fHistMan->FillHistClass("TrackBarrel_PostCalibPion", VarManager::fgValues); } - if ((static_cast(trackFilteringTag & (uint64_t(1) << VarManager::kIsLambdaLeg)) * (track.sign()) > 0)) { // for proton from Lambda + if ((static_cast(trackFilteringTag & (static_cast(1) << VarManager::kIsLambdaLeg)) * (track.sign()) > 0)) { // for proton from Lambda fHistMan->FillHistClass("TrackBarrel_PostCalibProton", VarManager::fgValues); } - if ((static_cast(trackFilteringTag & (uint64_t(1) << VarManager::kIsALambdaLeg)) * (track.sign()) < 0)) { // for proton from AntiLambda + if ((static_cast(trackFilteringTag & (static_cast(1) << VarManager::kIsALambdaLeg)) * (track.sign()) < 0)) { // for proton from AntiLambda fHistMan->FillHistClass("TrackBarrel_PostCalibProton", VarManager::fgValues); } } - if (fConfigSaveElectronSample) { // only save electron sample - if (!(trackFilteringTag & (uint64_t(1) << VarManager::kIsConversionLeg))) { + if (fConfigPostCalibTPC.fConfigSaveElectronSample) { // only save electron sample + if (!(trackFilteringTag & (static_cast(1) << VarManager::kIsConversionLeg))) { continue; } } } // end if V0Bits if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::DalitzBits)) { - trackFilteringTag |= (uint64_t(track.dalitzBits()) << VarManager::kDalitzBits); // BIT5-12: Dalitz + trackFilteringTag |= (static_cast(track.dalitzBits()) << VarManager::kDalitzBits); // BIT5-12: Dalitz } - trackFilteringTag |= (uint64_t(trackTempFilterMap) << VarManager::kBarrelUserCutsBits); // BIT13-...: user track filters + trackFilteringTag |= (static_cast(trackTempFilterMap) << VarManager::kBarrelUserCutsBits); // BIT13-...: user track filters if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackPID)) { - if (fConfigComputeTPCpostCalib) { - trackFilteringTag |= (uint64_t(1) << VarManager::kIsTPCPostcalibrated); + if (fConfigPostCalibTPC.fConfigComputeTPCpostCalib) { + trackFilteringTag |= (static_cast(1) << VarManager::kIsTPCPostcalibrated); } } - // write the track global index in the map for skimming (to make sure we have it just once) - if (fTrackIndexMap.find(track.globalIndex()) == fTrackIndexMap.end()) { - // NOTE: The collision ID that is written in the table is the one found in the first association for this track. - // However, in data analysis one should loop over associations, so this one should not be used. - // In the case of Run2-like analysis, there will be no associations, so this ID will be the one originally assigned in the AO2Ds (updated for the skims) - uint32_t reducedEventIdx = fCollIndexMap[collision.globalIndex()]; - // NOTE: trackBarrelInfo stores the index of the collision as in AO2D (for use in some cases where the analysis on skims is done - // in workflows where the original AO2Ds are also present) - trackBarrelInfo(collision.globalIndex(), collision.posX(), collision.posY(), collision.posZ()); - trackBasic(reducedEventIdx, trackFilteringTag, track.pt(), track.eta(), track.phi(), track.sign(), 0); - trackBarrel(track.x(), track.alpha(), track.y(), track.z(), track.snp(), track.tgl(), track.signed1Pt(), - track.tpcInnerParam(), track.flags(), track.itsClusterMap(), track.itsChi2NCl(), - track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), - track.tpcNClsShared(), track.tpcChi2NCl(), - track.trdChi2(), track.trdPattern(), track.tofChi2(), - track.length(), track.dcaXY(), track.dcaZ(), - track.trackTime(), track.trackTimeRes(), track.tofExpMom(), - track.detectorMap()); - if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackCov)) { - trackBarrelCov(track.cYY(), track.cZY(), track.cZZ(), track.cSnpY(), track.cSnpZ(), - track.cSnpSnp(), track.cTglY(), track.cTglZ(), track.cTglSnp(), track.cTglTgl(), - track.c1PtY(), track.c1PtZ(), track.c1PtSnp(), track.c1PtTgl(), track.c1Pt21Pt2()); - } - if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackPID)) { - float nSigmaEl = (fConfigComputeTPCpostCalib ? VarManager::fgValues[VarManager::kTPCnSigmaEl_Corr] : track.tpcNSigmaEl()); - float nSigmaPi = (fConfigComputeTPCpostCalib ? VarManager::fgValues[VarManager::kTPCnSigmaPi_Corr] : track.tpcNSigmaPi()); - float nSigmaKa = ((fConfigComputeTPCpostCalib && fConfigComputeTPCpostCalibKaon) ? VarManager::fgValues[VarManager::kTPCnSigmaKa_Corr] : track.tpcNSigmaKa()); - float nSigmaPr = (fConfigComputeTPCpostCalib ? VarManager::fgValues[VarManager::kTPCnSigmaPr_Corr] : track.tpcNSigmaPr()); - trackBarrelPID(track.tpcSignal(), - nSigmaEl, track.tpcNSigmaMu(), nSigmaPi, nSigmaKa, nSigmaPr, - track.beta(), track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), - track.trdSignal()); - } - fTrackIndexMap[track.globalIndex()] = trackBasic.lastIndex(); + // Calculating the percentage of orphan tracks i.e., tracks which have no collisions associated to it + if (!track.has_collision()) { + (reinterpret_cast(fStatsList->At(kStatsOrphanTracks)))->Fill(static_cast(-1)); + } else { + (reinterpret_cast(fStatsList->At(kStatsOrphanTracks)))->Fill(0.9); + } + + // NOTE: The collision ID written in the table is the one of the original collision assigned in the AO2D. + // The reason is that the time associated to the track is wrt that collision. + // If new associations are done with the skimmed data, the track time wrt new collision can then be recomputed based on the + // relative difference in time between the original and the new collision. + uint32_t reducedEventIdx = fCollIndexMap[track.collisionId()]; // This gives the original iD of the track + + // NOTE: trackBarrelInfo stores the index of the collision as in AO2D (for use in some cases where the analysis on skims is done + // in workflows where the original AO2Ds are also present) + trackBarrelInfo(collision.globalIndex(), collision.posX(), collision.posY(), collision.posZ(), track.globalIndex()); + trackBasic(reducedEventIdx, trackFilteringTag, track.pt(), track.eta(), track.phi(), track.sign(), 0); + trackBarrel(track.x(), track.alpha(), track.y(), track.z(), track.snp(), track.tgl(), track.signed1Pt(), + track.tpcInnerParam(), track.flags(), track.itsClusterMap(), track.itsChi2NCl(), + track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), + track.tpcNClsShared(), track.tpcChi2NCl(), + track.trdChi2(), track.trdPattern(), track.tofChi2(), + track.length(), track.dcaXY(), track.dcaZ(), + track.trackTime(), track.trackTimeRes(), track.tofExpMom(), + track.detectorMap()); + if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackCov)) { + trackBarrelCov(track.cYY(), track.cZY(), track.cZZ(), track.cSnpY(), track.cSnpZ(), + track.cSnpSnp(), track.cTglY(), track.cTglZ(), track.cTglSnp(), track.cTglTgl(), + track.c1PtY(), track.c1PtZ(), track.c1PtSnp(), track.c1PtTgl(), track.c1Pt21Pt2()); } + if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackPID)) { + float nSigmaEl = (fConfigPostCalibTPC.fConfigComputeTPCpostCalib ? VarManager::fgValues[VarManager::kTPCnSigmaEl_Corr] : track.tpcNSigmaEl()); + float nSigmaPi = (fConfigPostCalibTPC.fConfigComputeTPCpostCalib ? VarManager::fgValues[VarManager::kTPCnSigmaPi_Corr] : track.tpcNSigmaPi()); + float nSigmaKa = ((fConfigPostCalibTPC.fConfigComputeTPCpostCalib && fConfigPostCalibTPC.fConfigComputeTPCpostCalibKaon) ? VarManager::fgValues[VarManager::kTPCnSigmaKa_Corr] : track.tpcNSigmaKa()); + float nSigmaPr = (fConfigPostCalibTPC.fConfigComputeTPCpostCalib ? VarManager::fgValues[VarManager::kTPCnSigmaPr_Corr] : track.tpcNSigmaPr()); + trackBarrelPID(track.tpcSignal(), + nSigmaEl, track.tpcNSigmaMu(), nSigmaPi, nSigmaKa, nSigmaPr, + track.beta(), track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), + track.trdSignal()); + } else if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackTPCPID)) { + float nSigmaEl = (fConfigPostCalibTPC.fConfigComputeTPCpostCalib ? VarManager::fgValues[VarManager::kTPCnSigmaEl_Corr] : track.tpcNSigmaEl()); + float nSigmaPi = (fConfigPostCalibTPC.fConfigComputeTPCpostCalib ? VarManager::fgValues[VarManager::kTPCnSigmaPi_Corr] : track.tpcNSigmaPi()); + float nSigmaKa = ((fConfigPostCalibTPC.fConfigComputeTPCpostCalib && fConfigPostCalibTPC.fConfigComputeTPCpostCalibKaon) ? VarManager::fgValues[VarManager::kTPCnSigmaKa_Corr] : track.tpcNSigmaKa()); + float nSigmaPr = (fConfigPostCalibTPC.fConfigComputeTPCpostCalib ? VarManager::fgValues[VarManager::kTPCnSigmaPr_Corr] : track.tpcNSigmaPr()); + trackBarrelPID(track.tpcSignal(), + nSigmaEl, -999.0, nSigmaPi, nSigmaKa, nSigmaPr, + -999.0, -999.0, -999.0, -999.0, -999.0, -999.0, + -999.0); + } + + fTrackIndexMap[track.globalIndex()] = trackBasic.lastIndex(); + // write the skimmed collision - track association trackBarrelAssoc(fCollIndexMap[collision.globalIndex()], fTrackIndexMap[track.globalIndex()]); } // end loop over associations - } // end skimTracks + } // end skimTracks - template - void skimMFT(TEvent const& collision, BCsWithTimestamps const& /*bcs*/, MFTTracks const& /*mfts*/, MFTTrackAssoc const& mftAssocs) + template + void skimMFT(TEvent const& collision, TBCs const& /*bcs*/, MFTTracks const& /*mfts*/, MFTTrackAssoc const& mftAssocs) { // Skim MFT tracks // So far no cuts are applied here @@ -656,7 +1098,7 @@ struct TableMaker { for (const auto& assoc : mftAssocs) { auto track = assoc.template mfttrack_as(); - if (fConfigQA) { + if (fConfigHistOutput.fConfigQA) { VarManager::FillTrack(track); fHistMan->FillHistClass("MftTracks", VarManager::fgValues); } @@ -664,7 +1106,7 @@ struct TableMaker { // write the MFT track global index in the map for skimming (to make sure we have it just once) if (fMftIndexMap.find(track.globalIndex()) == fMftIndexMap.end()) { uint32_t reducedEventIdx = fCollIndexMap[collision.globalIndex()]; - mftTrack(reducedEventIdx, uint64_t(0), track.pt(), track.eta(), track.phi()); + mftTrack(reducedEventIdx, static_cast(0), track.pt(), track.eta(), track.phi()); // TODO: We are not writing the DCA at the moment, because this depend on the collision association mftTrackExtra(track.mftClusterSizesAndTrackFlags(), track.sign(), 0.0, 0.0, track.nClusters()); @@ -674,16 +1116,18 @@ struct TableMaker { } } - template - void skimMuons(TEvent const& collision, BCsWithTimestamps const& /*bcs*/, TMuons const& muons, FwdTrackAssoc const& muonAssocs) + template + void skimMuons(TEvent const& collision, TBCs const& /*bcs*/, TMuons const& muons, FwdTrackAssoc const& muonAssocs, TMFTTracks const& /*mftTracks*/) { // Skim the fwd-tracks (muons) // Loop over the collision-track associations, recompute track properties depending on the collision assigned, and apply track cuts for selection // Muons are written only once, even if they constribute to more than one association, // which means that in the case of multiple associations, the track parameters are wrong and should be computed again at analysis time. - uint8_t trackFilteringTag = uint8_t(0); - uint8_t trackTempFilterMap = uint8_t(0); + // TODO: Currently, the TMFTFillMap is not used in this function. Is it needed ? + + uint8_t trackFilteringTag = static_cast(0); + uint8_t trackTempFilterMap = static_cast(0); fFwdTrackIndexMapReversed.clear(); uint32_t offset = muonBasic.lastIndex(); @@ -692,11 +1136,29 @@ struct TableMaker { // get the muon auto muon = assoc.template fwdtrack_as(); - trackFilteringTag = uint8_t(0); + trackFilteringTag = static_cast(0); + trackTempFilterMap = static_cast(0); VarManager::FillTrack(muon); - // NOTE: If a muon is associated to multiple collisions, depending on the selections, + // NOTE: Muons are propagated to the current associated collisions. + // So if a muon is associated to multiple collisions, depending on the selections, // it may be accepted for some associations and rejected for other - VarManager::FillPropagateMuon(muon, collision); + if (fConfigVariousOptions.fPropMuon) { + VarManager::FillPropagateMuon(muon, collision); + } + // recalculate pDca and global muon kinematics + if (static_cast(muon.trackType()) < 2 && fConfigVariousOptions.fRefitGlobalMuon) { + auto muontrack = muon.template matchMCHTrack_as(); + if (muontrack.eta() < fConfigVariousOptions.fMuonMatchEtaMin || muontrack.eta() > fConfigVariousOptions.fMuonMatchEtaMax) { + continue; + } + VarManager::FillTrackCollision(muontrack, collision); + // NOTE: the MFT track originally associated to the MUON track is currently used in the global muon refit + // Should MUON - MFT time ambiguities be taken into account ? + auto mfttrack = muon.template matchMFTTrack_as(); + VarManager::FillGlobalMuonRefit(muontrack, mfttrack, collision); + } else { + VarManager::FillTrackCollision(muon, collision); + } if (fDoDetailedQA) { fHistMan->FillHistClass("Muons_BeforeCuts", VarManager::fgValues); @@ -704,12 +1166,15 @@ struct TableMaker { // check the cuts and filters int i = 0; for (auto cut = fMuonCuts.begin(); cut != fMuonCuts.end(); cut++, i++) { - if ((*cut).IsSelected(VarManager::fgValues)) { - trackTempFilterMap |= (uint8_t(1) << i); - if (fConfigQA) { - fHistMan->FillHistClass(Form("Muons_%s", (*cut).GetName()), VarManager::fgValues); + if ((*cut)->IsSelected(VarManager::fgValues)) { + trackTempFilterMap |= (static_cast(1) << i); + // NOTE: the QA is filled here just for the first occurence of this muon, which means the current association + // will be skipped from histograms if this muon was already filled in the skimming map. + // So if there are histograms of quantities which depend on the collision association, these histograms will not be completely accurate + if (fConfigHistOutput.fConfigQA && (fFwdTrackIndexMap.find(muon.globalIndex()) == fFwdTrackIndexMap.end())) { + fHistMan->FillHistClass(Form("Muons_%s", (*cut)->GetName()), VarManager::fgValues); } - (reinterpret_cast(fStatsList->At(2)))->Fill(static_cast(i)); + (reinterpret_cast(fStatsList->At(kStatsMuons)))->Fill(static_cast(i)); } } @@ -744,13 +1209,13 @@ struct TableMaker { // get the muon auto muon = muons.rawIteratorAt(origIdx); uint32_t reducedEventIdx = fCollIndexMap[collision.globalIndex()]; - // NOTE: Currently, one writes the original AO2D momentum-vector (pt, eta and phi) in the tables because we write only one instance of the muon track, - // while multiple collision associations (and multiple mom vectors can exist) + // NOTE: Currently, one writes in the tables the momentum-vector (pt, eta and phi) of the first collision association for this muon, + // while multiple collision associations (and multiple mom vectors can exist). // The momentum can be recomputed at the analysis time based on the associations written in the skims // So all the information which pertains to collision association or MFT associations should not be taken from the skimmed data, but recomputed at analysis time. uint32_t mchIdx = -1; uint32_t mftIdx = -1; - if (muon.trackType() == uint8_t(0) || muon.trackType() == uint8_t(2)) { // MCH-MID (2) or global (0) + if (muon.trackType() == static_cast(0) || muon.trackType() == static_cast(2)) { // MCH-MID (2) or global (0) if (fFwdTrackIndexMap.find(muon.matchMCHTrackId()) != fFwdTrackIndexMap.end()) { mchIdx = fFwdTrackIndexMap[muon.matchMCHTrackId()]; } @@ -758,70 +1223,97 @@ struct TableMaker { mftIdx = fMftIndexMap[muon.matchMFTTrackId()]; } } - muonBasic(reducedEventIdx, mchIdx, mftIdx, fFwdTrackFilterMap[muon.globalIndex()], muon.pt(), muon.eta(), muon.phi(), muon.sign(), 0); - muonExtra(muon.nClusters(), muon.pDca(), muon.rAtAbsorberEnd(), + VarManager::FillTrack(muon); + if (fConfigVariousOptions.fPropMuon) { + VarManager::FillPropagateMuon(muon, collision); + } + // recalculte pDca and global muon kinematics + if (static_cast(muon.trackType()) < 2 && fConfigVariousOptions.fRefitGlobalMuon) { + auto muontrack = muon.template matchMCHTrack_as(); + auto mfttrack = muon.template matchMFTTrack_as(); + VarManager::FillTrackCollision(muontrack, collision); + VarManager::FillGlobalMuonRefit(muontrack, mfttrack, collision); + } else { + VarManager::FillTrackCollision(muon, collision); + } + muonBasic(reducedEventIdx, mchIdx, mftIdx, fFwdTrackFilterMap[muon.globalIndex()], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], muon.sign(), 0); + muonExtra(muon.nClusters(), VarManager::fgValues[VarManager::kMuonPDca], VarManager::fgValues[VarManager::kMuonRAtAbsorberEnd], muon.chi2(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), muon.matchScoreMCHMFT(), muon.mchBitMap(), muon.midBitMap(), - muon.midBoards(), muon.trackType(), muon.fwdDcaX(), muon.fwdDcaY(), + muon.midBoards(), muon.trackType(), VarManager::fgValues[VarManager::kMuonDCAx], VarManager::fgValues[VarManager::kMuonDCAy], muon.trackTime(), muon.trackTimeRes()); muonInfo(muon.collisionId(), collision.posX(), collision.posY(), collision.posZ()); if constexpr (static_cast(TMuonFillMap & VarManager::ObjTypes::MuonCov)) { - muonCov(muon.x(), muon.y(), muon.z(), muon.phi(), muon.tgl(), muon.sign() / muon.pt(), - muon.cXX(), muon.cXY(), muon.cYY(), muon.cPhiX(), muon.cPhiY(), muon.cPhiPhi(), - muon.cTglX(), muon.cTglY(), muon.cTglPhi(), muon.cTglTgl(), muon.c1PtX(), muon.c1PtY(), - muon.c1PtPhi(), muon.c1PtTgl(), muon.c1Pt21Pt2()); + muonCov(VarManager::fgValues[VarManager::kX], VarManager::fgValues[VarManager::kY], VarManager::fgValues[VarManager::kZ], VarManager::fgValues[VarManager::kPhi], VarManager::fgValues[VarManager::kTgl], muon.sign() / VarManager::fgValues[VarManager::kPt], + VarManager::fgValues[VarManager::kMuonCXX], VarManager::fgValues[VarManager::kMuonCXY], VarManager::fgValues[VarManager::kMuonCYY], VarManager::fgValues[VarManager::kMuonCPhiX], VarManager::fgValues[VarManager::kMuonCPhiY], VarManager::fgValues[VarManager::kMuonCPhiPhi], + VarManager::fgValues[VarManager::kMuonCTglX], VarManager::fgValues[VarManager::kMuonCTglY], VarManager::fgValues[VarManager::kMuonCTglPhi], VarManager::fgValues[VarManager::kMuonCTglTgl], VarManager::fgValues[VarManager::kMuonC1Pt2X], VarManager::fgValues[VarManager::kMuonC1Pt2Y], + VarManager::fgValues[VarManager::kMuonC1Pt2Phi], VarManager::fgValues[VarManager::kMuonC1Pt2Tgl], VarManager::fgValues[VarManager::kMuonC1Pt21Pt2]); } } // end loop over selected muons - } // end skimMuons + } // end skimMuons // Produce standard barrel + muon tables with event filter (typically for pp and p-Pb) ------------------------------------------------------ - template - void fullSkimming(TEvents const& collisions, BCsWithTimestamps const& bcs, + template + void fullSkimming(TEvents const& collisions, TBCs const& bcs, TZdcs const& zdcs, TTracks const& tracksBarrel, TMuons const& muons, TMFTTracks const& mftTracks, TTrackAssoc const& trackAssocs, TFwdTrackAssoc const& fwdTrackAssocs, TMFTTrackAssoc const& mftAssocs) { - if (fCurrentRun != bcs.begin().runNumber()) { - if (fConfigComputeTPCpostCalib) { - auto calibList = fCCDB->getForTimeStamp(fConfigCcdbPathTPC.value, bcs.begin().timestamp()); + if (bcs.size() > 0 && fCurrentRun != bcs.begin().runNumber()) { + if (fConfigPostCalibTPC.fConfigComputeTPCpostCalib) { + auto calibList = fCCDB->getForTimeStamp(fConfigCCDB.fConfigCcdbPathTPC.value, bcs.begin().timestamp()); VarManager::SetCalibrationObject(VarManager::kTPCElectronMean, calibList->FindObject("mean_map_electron")); VarManager::SetCalibrationObject(VarManager::kTPCElectronSigma, calibList->FindObject("sigma_map_electron")); VarManager::SetCalibrationObject(VarManager::kTPCPionMean, calibList->FindObject("mean_map_pion")); VarManager::SetCalibrationObject(VarManager::kTPCPionSigma, calibList->FindObject("sigma_map_pion")); VarManager::SetCalibrationObject(VarManager::kTPCProtonMean, calibList->FindObject("mean_map_proton")); VarManager::SetCalibrationObject(VarManager::kTPCProtonSigma, calibList->FindObject("sigma_map_proton")); - if (fConfigComputeTPCpostCalibKaon) { + if (fConfigPostCalibTPC.fConfigComputeTPCpostCalibKaon) { VarManager::SetCalibrationObject(VarManager::kTPCKaonMean, calibList->FindObject("mean_map_kaon")); VarManager::SetCalibrationObject(VarManager::kTPCKaonSigma, calibList->FindObject("sigma_map_kaon")); } } if (fIsRun2 == true) { - grpmagrun2 = ccdb->getForTimeStamp(grpmagPathRun2, bcs.begin().timestamp()); - if (grpmagrun2 != nullptr) { - o2::base::Propagator::initFieldFromGRP(grpmagrun2); + fGrpMagRun2 = fCCDB->getForTimeStamp(fConfigCCDB.fConfigGrpMagPathRun2, bcs.begin().timestamp()); + if (fGrpMagRun2 != nullptr) { + o2::base::Propagator::initFieldFromGRP(fGrpMagRun2); } } else { - grpmag = ccdb->getForTimeStamp(grpmagPath, bcs.begin().timestamp()); - if (grpmag != nullptr) { - o2::base::Propagator::initFieldFromGRP(grpmag); + fGrpMag = fCCDB->getForTimeStamp(fConfigCCDB.fConfigGrpMagPath, bcs.begin().timestamp()); + if (fGrpMag != nullptr) { + o2::base::Propagator::initFieldFromGRP(fGrpMag); + } + if (fConfigVariousOptions.fPropMuon) { + VarManager::SetupMuonMagField(); } } + std::map metadataRCT, header; + header = fCCDBApi.retrieveHeaders(Form("RCT/Info/RunInformation/%i", bcs.begin().runNumber()), metadataRCT, -1); + uint64_t sor = std::atol(header["SOR"].c_str()); + uint64_t eor = std::atol(header["EOR"].c_str()); + VarManager::SetSORandEOR(sor, eor); + fCurrentRun = bcs.begin().runNumber(); - } + } // end updating the CCDB quantities at change of run // skim collisions - skimCollisions(collisions, bcs); + event.reserve(collisions.size()); + eventExtended.reserve(collisions.size()); + eventVtxCov.reserve(collisions.size()); + + skimCollisions(collisions, bcs, zdcs, trackAssocs, tracksBarrel); if (fCollIndexMap.size() == 0) { return; } if constexpr (static_cast(TTrackFillMap)) { fTrackIndexMap.clear(); + trackBarrelInfo.reserve(tracksBarrel.size()); trackBasic.reserve(tracksBarrel.size()); trackBarrel.reserve(tracksBarrel.size()); - trackBarrelInfo.reserve(tracksBarrel.size()); trackBarrelCov.reserve(tracksBarrel.size()); trackBarrelPID.reserve(tracksBarrel.size()); trackBarrelAssoc.reserve(tracksBarrel.size()); @@ -844,23 +1336,34 @@ struct TableMaker { muonAssoc.reserve(muons.size()); } - // loop over selected collisions and select the tracks and fwd tracks to be skimmed + // loop over selected collisions, group the compatible associations, and run the skimming for (auto const& [origIdx, skimIdx] : fCollIndexMap) { auto collision = collisions.rawIteratorAt(origIdx); - // group the tracks and muons for this collision + // group the barrel track associations for this collision if constexpr (static_cast(TTrackFillMap)) { auto groupedTrackIndices = trackAssocs.sliceBy(trackIndicesPerCollision, origIdx); skimTracks(collision, bcs, tracksBarrel, groupedTrackIndices); } + // group the MFT associations for this collision if constexpr (static_cast(TMFTFillMap)) { auto groupedMFTIndices = mftAssocs.sliceBy(mfttrackIndicesPerCollision, origIdx); skimMFT(collision, bcs, mftTracks, groupedMFTIndices); } + // group the muon associations for this collision if constexpr (static_cast(TMuonFillMap)) { - auto groupedMuonIndices = fwdTrackAssocs.sliceBy(fwdtrackIndicesPerCollision, origIdx); - skimMuons(collision, bcs, muons, groupedMuonIndices); + if constexpr (static_cast(TMFTFillMap)) { + auto groupedMuonIndices = fwdTrackAssocs.sliceBy(fwdtrackIndicesPerCollision, origIdx); + skimMuons(collision, bcs, muons, groupedMuonIndices, mftTracks); + } else { + auto groupedMuonIndices = fwdTrackAssocs.sliceBy(fwdtrackIndicesPerCollision, origIdx); + skimMuons(collision, bcs, muons, groupedMuonIndices, nullptr); + } } } // end loop over skimmed collisions + + // LOG(info) << "Skims in this TF: " << fCollIndexMap.size() << " collisions; " << trackBasic.lastIndex() << " barrel tracks; " + //<< muonBasic.lastIndex() << " muon tracks; " << mftTrack.lastIndex() << " MFT tracks; "; + // LOG(info) << " " << trackBarrelAssoc.lastIndex() << " barrel assocs; " << muonAssoc.lastIndex() << " muon assocs; " << mftAssoc.lastIndex() << " MFT assoc"; } // produce the full DQ skimmed data model typically for pp/p-Pb or UPC Pb-Pb (no centrality), subscribe to the DQ event filter (filter-pp or filter-PbPb) @@ -870,26 +1373,22 @@ struct TableMaker { TrackAssoc const& trackAssocs, FwdTrackAssoc const& fwdTrackAssocs, MFTTrackAssoc const& mftAssocs) { - fullSkimming(collisions, bcs, tracksBarrel, muons, mftTracks, trackAssocs, fwdTrackAssocs, mftAssocs); + fullSkimming(collisions, bcs, nullptr, tracksBarrel, muons, mftTracks, trackAssocs, fwdTrackAssocs, mftAssocs); } // produce the barrel-only DQ skimmed data model typically for pp/p-Pb or UPC Pb-Pb (no centrality), subscribe to the DQ event filter (filter-pp or filter-PbPb) - void processPPWithFilterBarrelOnly(MyEventsWithMultsAndFilter const& collisions, BCsWithTimestamps const& bcs, + void processPPWithFilterBarrelOnly(MyEventsWithMultsAndFilter const& collisions, MyBCs const& bcs, aod::Zdcs& zdcs, MyBarrelTracksWithCov const& tracksBarrel, TrackAssoc const& trackAssocs) { - /*const int& a = 0; - MFTTracks const& mftTracks = 0; - FwdTrackAssoc const& fwdTrackAssocs = 0; - MFTTrackAssoc const& mftAssocs = 0;*/ - fullSkimming(collisions, bcs, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr); + fullSkimming(collisions, bcs, zdcs, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr); } // produce the muon-only DQ skimmed data model typically for pp/p-Pb or UPC Pb-Pb (no centrality), subscribe to the DQ event filter (filter-pp or filter-PbPb) void processPPWithFilterMuonOnly(MyEventsWithMultsAndFilter const& collisions, BCsWithTimestamps const& bcs, MyMuonsWithCov const& muons, FwdTrackAssoc const& fwdTrackAssocs) { - fullSkimming(collisions, bcs, nullptr, muons, nullptr, nullptr, fwdTrackAssocs, nullptr); + fullSkimming(collisions, bcs, nullptr, nullptr, muons, nullptr, nullptr, fwdTrackAssocs, nullptr); } // produce the muon+mft DQ skimmed data model typically for pp/p-Pb or UPC Pb-Pb (no centrality), subscribe to the DQ event filter (filter-pp or filter-PbPb) @@ -897,7 +1396,46 @@ struct TableMaker { MyMuonsWithCov const& muons, MFTTracks const& mftTracks, FwdTrackAssoc const& fwdTrackAssocs, MFTTrackAssoc const& mftAssocs) { - fullSkimming(collisions, bcs, nullptr, muons, mftTracks, nullptr, fwdTrackAssocs, mftAssocs); + fullSkimming(collisions, bcs, nullptr, nullptr, muons, mftTracks, nullptr, fwdTrackAssocs, mftAssocs); + } + + // produce the barrel-only DQ skimmed data model typically for pp/p-Pb or UPC Pb-Pb (no centrality), meant to run on skimmed data + void processPPBarrelOnly(MyEventsWithMults const& collisions, MyBCs const& bcs, aod::Zdcs& zdcs, + MyBarrelTracksWithCov const& tracksBarrel, + TrackAssoc const& trackAssocs) + { + fullSkimming(collisions, bcs, zdcs, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr); + } + + // produce the barrel-only DQ skimmed barrel data model, with V0 tagged tracks + void processPPBarrelOnlyWithV0s(MyEventsWithMults const& collisions, MyBCs const& bcs, + MyBarrelTracksWithV0BitsNoTOF const& tracksBarrel, + TrackAssoc const& trackAssocs) + { + fullSkimming(collisions, bcs, nullptr, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr); + } + + // produce the muon-only DQ skimmed data model typically for pp/p-Pb or UPC Pb-Pb (no centrality), meant to run on skimmed data + void processPPMuonOnly(MyEventsWithMults const& collisions, BCsWithTimestamps const& bcs, + MyMuonsWithCov const& muons, FwdTrackAssoc const& fwdTrackAssocs) + { + fullSkimming(collisions, bcs, nullptr, nullptr, muons, nullptr, nullptr, fwdTrackAssocs, nullptr); + } + + // produce the muon+mft DQ skimmed data model typically for pp/p-Pb or UPC Pb-Pb (no centrality), meant to run on skimmed data + void processPPMuonMFT(MyEventsWithMults const& collisions, BCsWithTimestamps const& bcs, + MyMuonsWithCov const& muons, MFTTracks const& mftTracks, + FwdTrackAssoc const& fwdTrackAssocs, MFTTrackAssoc const& mftAssocs) + { + fullSkimming(collisions, bcs, nullptr, nullptr, muons, mftTracks, nullptr, fwdTrackAssocs, mftAssocs); + } + + // Central barrel multiplicity estimation + void processPPMuonMFTWithMultsExtra(MyEventsWithMultsExtra const& collisions, BCsWithTimestamps const& bcs, + MyMuonsWithCov const& muons, MFTTracks const& mftTracks, + FwdTrackAssoc const& fwdTrackAssocs, MFTTrackAssoc const& mftAssocs) + { + fullSkimming(collisions, bcs, nullptr, nullptr, muons, mftTracks, nullptr, fwdTrackAssocs, mftAssocs); } // produce the full DQ skimmed data model typically for Pb-Pb (with centrality), no subscribtion to the DQ event filter @@ -907,7 +1445,7 @@ struct TableMaker { TrackAssoc const& trackAssocs, FwdTrackAssoc const& fwdTrackAssocs, MFTTrackAssoc const& mftAssocs) { - fullSkimming(collisions, bcs, tracksBarrel, muons, mftTracks, trackAssocs, fwdTrackAssocs, mftAssocs); + fullSkimming(collisions, bcs, nullptr, tracksBarrel, muons, mftTracks, trackAssocs, fwdTrackAssocs, mftAssocs); } // produce the barrel only DQ skimmed data model typically for Pb-Pb (with centrality), no subscribtion to the DQ event filter @@ -915,14 +1453,40 @@ struct TableMaker { MyBarrelTracksWithCov const& tracksBarrel, TrackAssoc const& trackAssocs) { - fullSkimming(collisions, bcs, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr); + fullSkimming(collisions, bcs, nullptr, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr); + } + + // produce the barrel-only DQ skimmed data model typically for UPC Pb-Pb (no centrality), subscribe to the DQ rapidity gap event filter (filter-PbPb) + void processPbPbWithFilterBarrelOnly(MyEventsWithMultsAndRapidityGapFilter const& collisions, MyBCs const& bcs, aod::Zdcs& zdcs, + MyBarrelTracksWithCov const& tracksBarrel, + TrackAssoc const& trackAssocs) + { + fullSkimming(collisions, bcs, zdcs, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr); + } + + // produce the barrel only DQ skimmed data model typically for Pb-Pb (with centrality), no subscribtion to the DQ event filter + void processPbPbBarrelOnlyWithV0Bits(MyEventsWithCentAndMults const& collisions, BCsWithTimestamps const& bcs, + MyBarrelTracksWithV0Bits const& tracksBarrel, + TrackAssoc const& trackAssocs) + { + computeOccupancyEstimators(collisions, tracksPos, tracksNeg, preslice, bcs); + fullSkimming(collisions, bcs, nullptr, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr); + } + + // produce the barrel only DQ skimmed data model typically for Pb-Pb (with centrality), no subscribtion to the DQ event filter + void processPbPbBarrelOnlyWithV0BitsNoTOF(MyEventsWithCentAndMults const& collisions, BCsWithTimestamps const& bcs, + MyBarrelTracksWithV0BitsNoTOF const& tracksBarrel, + TrackAssoc const& trackAssocs) + { + computeOccupancyEstimators(collisions, tracksPosNoTOF, tracksNegNoTOF, presliceNoTOF, bcs); + fullSkimming(collisions, bcs, nullptr, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr); } // produce the muon only DQ skimmed data model typically for Pb-Pb (with centrality), no subscribtion to the DQ event filter void processPbPbMuonOnly(MyEventsWithCentAndMults const& collisions, BCsWithTimestamps const& bcs, MyMuonsWithCov const& muons, FwdTrackAssoc const& fwdTrackAssocs) { - fullSkimming(collisions, bcs, nullptr, muons, nullptr, nullptr, fwdTrackAssocs, nullptr); + fullSkimming(collisions, bcs, nullptr, nullptr, muons, nullptr, nullptr, fwdTrackAssocs, nullptr); } // produce the muon+mft DQ skimmed data model typically for Pb-Pb (with centrality), no subscribtion to the DQ event filter @@ -930,7 +1494,7 @@ struct TableMaker { MyMuonsWithCov const& muons, MFTTracks const& mftTracks, FwdTrackAssoc const& fwdTrackAssocs, MFTTrackAssoc const& mftAssocs) { - fullSkimming(collisions, bcs, nullptr, muons, mftTracks, nullptr, fwdTrackAssocs, mftAssocs); + fullSkimming(collisions, bcs, nullptr, nullptr, muons, mftTracks, nullptr, fwdTrackAssocs, mftAssocs); } // Process the BCs and store stats for luminosity retrieval ----------------------------------------------------------------------------------- @@ -938,18 +1502,26 @@ struct TableMaker { { for (int i = 0; i < o2::aod::evsel::kNsel; i++) { if (bc.selection_bit(i) > 0) { - (reinterpret_cast(fStatsList->At(0)))->Fill(0.0, static_cast(i)); + (reinterpret_cast(fStatsList->At(kStatsEvent)))->Fill(0.0, static_cast(i)); } } - (reinterpret_cast(fStatsList->At(0)))->Fill(0.0, static_cast(o2::aod::evsel::kNsel)); + (reinterpret_cast(fStatsList->At(kStatsEvent)))->Fill(0.0, static_cast(o2::aod::evsel::kNsel)); } PROCESS_SWITCH(TableMaker, processPPWithFilter, "Build full DQ skimmed data model typically for pp/p-Pb and UPC Pb-Pb, w/ event filtering", false); PROCESS_SWITCH(TableMaker, processPPWithFilterBarrelOnly, "Build barrel only DQ skimmed data model typically for pp/p-Pb and UPC Pb-Pb, w/ event filtering", false); PROCESS_SWITCH(TableMaker, processPPWithFilterMuonOnly, "Build muon only DQ skimmed data model typically for pp/p-Pb and UPC Pb-Pb, w/ event filtering", false); PROCESS_SWITCH(TableMaker, processPPWithFilterMuonMFT, "Build muon + mft DQ skimmed data model typically for pp/p-Pb and UPC Pb-Pb, w/ event filtering", false); + PROCESS_SWITCH(TableMaker, processPPBarrelOnly, "Build barrel only DQ skimmed data model typically for pp/p-Pb and UPC Pb-Pb", false); + PROCESS_SWITCH(TableMaker, processPPBarrelOnlyWithV0s, "Build barrel only DQ skimmed data model, pp like, with V0 tagged tracks", false); + PROCESS_SWITCH(TableMaker, processPPMuonOnly, "Build muon only DQ skimmed data model typically for pp/p-Pb and UPC Pb-Pb", false); + PROCESS_SWITCH(TableMaker, processPPMuonMFT, "Build muon + mft DQ skimmed data model typically for pp/p-Pb and UPC Pb-Pb", false); + PROCESS_SWITCH(TableMaker, processPPMuonMFTWithMultsExtra, "Build muon + mft DQ skimmed data model typically for pp/p-Pb and UPC Pb-Pb", false); PROCESS_SWITCH(TableMaker, processPbPb, "Build full DQ skimmed data model typically for Pb-Pb, w/o event filtering", false); PROCESS_SWITCH(TableMaker, processPbPbBarrelOnly, "Build barrel only DQ skimmed data model typically for Pb-Pb, w/o event filtering", false); + PROCESS_SWITCH(TableMaker, processPbPbWithFilterBarrelOnly, "Build barrel only DQ skimmed data model typically for UPC Pb-Pb, w/ event filtering", false); + PROCESS_SWITCH(TableMaker, processPbPbBarrelOnlyWithV0Bits, "Build barrel only DQ skimmed data model typically for Pb-Pb, w/ V0 bits, w/o event filtering", false); + PROCESS_SWITCH(TableMaker, processPbPbBarrelOnlyWithV0BitsNoTOF, "Build barrel only DQ skimmed data model typically for Pb-Pb, w/ V0 bits, no TOF, w/o event filtering", false); PROCESS_SWITCH(TableMaker, processPbPbMuonOnly, "Build muon only DQ skimmed data model typically for Pb-Pb, w/o event filtering", false); PROCESS_SWITCH(TableMaker, processPbPbMuonMFT, "Build muon + mft DQ skimmed data model typically for Pb-Pb, w/o event filtering", false); PROCESS_SWITCH(TableMaker, processOnlyBCs, "Analyze the BCs to store sampled lumi", false); diff --git a/PWGDQ/Tasks/CMakeLists.txt b/PWGDQ/Tasks/CMakeLists.txt index 30500bfdb5f..a10d6bb117d 100644 --- a/PWGDQ/Tasks/CMakeLists.txt +++ b/PWGDQ/Tasks/CMakeLists.txt @@ -24,6 +24,11 @@ o2physics_add_dpl_workflow(efficiency PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(efficiency-with-assoc + SOURCES dqEfficiency_withAssoc.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(filter-pp SOURCES filterPP.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore @@ -36,7 +41,7 @@ o2physics_add_dpl_workflow(filter-pp-with-association o2physics_add_dpl_workflow(filter-pb-pb SOURCES filterPbPb.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore O2Physics::SGCutParHolder COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(v0-selector @@ -64,6 +69,11 @@ o2physics_add_dpl_workflow(task-j-psi-hf PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(task-muon-dca + SOURCES muonDCA.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(correlation SOURCES dqCorrelation.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore O2Physics::GFWCore @@ -92,4 +102,19 @@ o2physics_add_dpl_workflow(task-mch-align-record o2physics_add_dpl_workflow(task-muon-mid-eff SOURCES MIDefficiency.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::MIDBase - COMPONENT_NAME Analysis) \ No newline at end of file + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(task-fwd-track-pid + SOURCES taskFwdTrackPid.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(quarkonia-to-hyperons + SOURCES quarkoniaToHyperons.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(model-converter-mult-pv + SOURCES ModelConverterMultPv.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGDQCore + COMPONENT_NAME Analysis) diff --git a/PWGDQ/Tasks/MIDefficiency.cxx b/PWGDQ/Tasks/MIDefficiency.cxx index 125761e173d..13377e5cc5c 100644 --- a/PWGDQ/Tasks/MIDefficiency.cxx +++ b/PWGDQ/Tasks/MIDefficiency.cxx @@ -16,13 +16,14 @@ /// Struct for writing the table and convert the data /// to MID tracks needed to compute the efficiency of the MID RPCs /// -/// \author Luca Quaglia -/// +/// \author Luca Quaglia // O2 physics classes #include "PWGDQ/DataModel/ReducedInfoTables.h" @@ -41,6 +42,7 @@ using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; +using MyEvents = soa::Join; using MyMuonTracks = soa::Join; struct midEfficiency { @@ -49,31 +51,53 @@ struct midEfficiency { HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; // Configurables for histogram axes - Configurable nBinsLocal{"nBinsLocal", 936, "N bins in local board counts histo"}; - Configurable nBinsRPC{"nBinsRPC", 72, "N bins in RPC counts histo"}; - Configurable nBinsPlane{"nBinsPlane", 4, "N bins in plane counts histo"}; - Configurable createRootFile{"createRootFile", false, "if true it creates the mid-reco.root file for debug purposes"}; + // Centrality + Configurable nBinsCentrality{"nBinsCentrality", 9, "N bins for centrality histo in PbPb"}; + Configurable minCentrality{"minCentrality", 0., "minimum of axis in centrality histo in PbPb"}; + Configurable maxCentrality{"maxCentrality", 90., "maximum of axis in centrality histo in PbPb"}; + Configurable isPbPb{"isPbPb", false, "If true, the task will be used to run on PbPb data and will enable the filling of THnSparse for centrality studies"}; + + // pt + Configurable nBinsPt{"nBinsPt", 2000, "N bins for pt histo"}; + Configurable minPt{"minPt", 0., "minimum of pt axis"}; // GeV/c + Configurable maxPt{"maxPt", 20., "maximum of pt axis"}; + + // eta + Configurable nBinsEta{"nBinsEta", 500, "N bins for eta histo"}; + Configurable minEta{"minEta", -5., "minimum of eta axis"}; // + Configurable maxEta{"maxEta", 5., "maximum of eta axis"}; + + // phi + Configurable nBinsPhi{"nBinsPhi", 500, "N bins for phi histo"}; + Configurable minPhi{"minPhi", -2. * TMath::Pi(), "minimum of phi axis"}; // + Configurable maxPhi{"maxPhi", 2 * TMath::Pi(), "maximum of phi axis"}; - // Vector of MID tracks to pass to the efficiency calculator - std::vector dummyTrack; // MID track placeholder for processing o2::mid::Track trk; // MID mapping for LB calculation o2::mid::Mapping mapping; - void init(o2::framework::InitContext const&) + // Filter only for MCH-MID matched tracks + Filter muonTrackType = aod::fwdtrack::trackType == uint8_t(3); + + void init(o2::framework::InitContext const& /*ic*/) { LOGF(debug, "Initialization starting"); // Axes definition - const AxisSpec axisLocalBoards{nBinsLocal, 0.5, 936.5, "Local board"}; - const AxisSpec axisRPCs{nBinsRPC, -0.5, 71.5, "RPC"}; - const AxisSpec axisPlanes{nBinsPlane, -0.5, 3.5, "Plane"}; + const AxisSpec axisLocalBoards{936, 0.5, 936.5, "Local board"}; // These are not defined as configurable since they are fixed + const AxisSpec axisRPCs{72, -0.5, 71.5, "RPC"}; // These are not defined as configurable since they are fixed + const AxisSpec axisPlanes{4, -0.5, 3.5, "Plane"}; // These are not defined as configurable since they are fixed + const AxisSpec axisTrackType{5, -0.5, 4.5, "Muon track type"}; // These are not defined as configurable since they are fixed + + const AxisSpec axisCent{nBinsCentrality, minCentrality, maxCentrality, "Centrality"}; + const AxisSpec axisPt{nBinsPt, minPt, maxPt, "track p_{t} [GeV/c]"}; + const AxisSpec axisEta{nBinsEta, minEta, maxEta, "track #eta"}; + const AxisSpec axisPhi{nBinsPhi, minPhi, maxPhi, "track #phi"}; LOGF(debug, "Creating histograms"); - // Same names as O2 task // Local boards histos.add("nFiredBPperBoard", "nFiredBPperBoard", kTH1F, {axisLocalBoards}); histos.add("nFiredNBPperBoard", "nFiredNBPperBoard", kTH1F, {axisLocalBoards}); @@ -89,20 +113,69 @@ struct midEfficiency { histos.add("nFiredNBPperPlane", "nFiredNBPperPlane", kTH1F, {axisPlanes}); histos.add("nFiredBothperPlane", "nFiredBothperPlane", kTH1F, {axisPlanes}); histos.add("nTotperPlane", "nTotperPlane", kTH1F, {axisPlanes}); - + // Centrality test + histos.add("hCentr", "hCentr", kTH1F, {axisCent}); + + // Track type + histos.add("hTrackType", "hTrackType", kTH1F, {axisTrackType}); + + // If this is true -> PbPb data, add THnSparse with centrality + if (isPbPb) { + // Local boards + histos.add("hSparseCentFiredBPperBoard", "THn for centrality studies", HistType::kTHnSparseF, {axisLocalBoards, axisCent, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredNBPperBoard", "THn for centrality studies", HistType::kTHnSparseF, {axisLocalBoards, axisCent, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredBothperBoard", "THn for centrality studies", HistType::kTHnSparseF, {axisLocalBoards, axisCent, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredTotperBoard", "THn for centrality studies", HistType::kTHnSparseF, {axisLocalBoards, axisCent, axisPt, axisEta, axisPhi}); + + // RPCs + histos.add("hSparseCentFiredBPperRPC", "THn for centrality studies", HistType::kTHnSparseF, {axisRPCs, axisCent, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredNBPperRPC", "THn for centrality studies", HistType::kTHnSparseF, {axisRPCs, axisCent, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredBothperRPC", "THn for centrality studies", HistType::kTHnSparseF, {axisRPCs, axisCent, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredTotperRPC", "THn for centrality studies", HistType::kTHnSparseF, {axisRPCs, axisCent, axisPt, axisEta, axisPhi}); + + // Planes + histos.add("hSparseCentFiredBPperPlane", "THn for centrality studies", HistType::kTHnSparseF, {axisPlanes, axisCent, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredNBPperPlane", "THn for centrality studies", HistType::kTHnSparseF, {axisPlanes, axisCent, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredBothperPlane", "THn for centrality studies", HistType::kTHnSparseF, {axisPlanes, axisCent, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredTotperPlane", "THn for centrality studies", HistType::kTHnSparseF, {axisPlanes, axisCent, axisPt, axisEta, axisPhi}); + } else { // THnSparse without centrality in pp + // Local boards + histos.add("hSparseCentFiredBPperBoard", "THn for centrality studies", HistType::kTHnSparseF, {axisLocalBoards, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredNBPperBoard", "THn for centrality studies", HistType::kTHnSparseF, {axisLocalBoards, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredBothperBoard", "THn for centrality studies", HistType::kTHnSparseF, {axisLocalBoards, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredTotperBoard", "THn for centrality studies", HistType::kTHnSparseF, {axisLocalBoards, axisPt, axisEta, axisPhi}); + + // RPCs + histos.add("hSparseCentFiredBPperRPC", "THn for centrality studies", HistType::kTHnSparseF, {axisRPCs, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredNBPperRPC", "THn for centrality studies", HistType::kTHnSparseF, {axisRPCs, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredBothperRPC", "THn for centrality studies", HistType::kTHnSparseF, {axisRPCs, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredTotperRPC", "THn for centrality studies", HistType::kTHnSparseF, {axisRPCs, axisPt, axisEta, axisPhi}); + + // Planes + histos.add("hSparseCentFiredBPperPlane", "THn for centrality studies", HistType::kTHnSparseF, {axisPlanes, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredNBPperPlane", "THn for centrality studies", HistType::kTHnSparseF, {axisPlanes, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredBothperPlane", "THn for centrality studies", HistType::kTHnSparseF, {axisPlanes, axisPt, axisEta, axisPhi}); + histos.add("hSparseCentFiredTotperPlane", "THn for centrality studies", HistType::kTHnSparseF, {axisPlanes, axisPt, axisEta, axisPhi}); + } } // end of init template - void runMidEffCounters(TEvent const& /*event*/, Muons const& muons) + void runMidEffCounters(TEvent const& event, Muons const& muons) { LOGF(debug, "Calling process function"); + float cent = event.centFT0C(); + + if (isPbPb) + histos.fill(HIST("hCentr"), cent); // Fill centrality histo + // Loop over all forward tracks - // LOGP(info, "collision index = {} , nTracks = {}", event.globalIndex(), muons.size()); for (auto& track : muons) { LOGF(debug, "Processing a track"); + histos.fill(HIST("hTrackType"), track.trackType()); + trk.setEfficiencyWord(track.midBoards()); auto deIdMT11 = trk.getFiredDEId(); @@ -110,6 +183,10 @@ struct midEfficiency { auto rpcLine = o2::mid::detparams::getRPCLine(deIdMT11); auto effFlag = trk.getEfficiencyFlag(); + float pt = track.pt(); + float eta = track.eta(); + float phi = track.phi(); + if (effFlag < 0) { continue; } @@ -117,17 +194,38 @@ struct midEfficiency { // Loop on the four planes and fill histograms accordingly for (int ich = 0; ich < 4; ++ich) { + // Check if BP/NBP has been fired by the track bool isFiredBP = trk.isFiredChamber(ich, 0); bool isFiredNBP = trk.isFiredChamber(ich, 1); + // Plane - // Fill all counts - plane - histos.fill(HIST("nTotperPlane"), ich); - if (isFiredBP) + histos.fill(HIST("nTotperPlane"), ich); // All counts - plane + if (isPbPb) + histos.fill(HIST("hSparseCentFiredTotperPlane"), ich, cent, pt, eta, phi); + else + histos.fill(HIST("hSparseCentFiredTotperPlane"), ich, pt, eta, phi); + + if (isFiredBP) { histos.fill(HIST("nFiredBPperPlane"), ich); // BP - Plane - if (isFiredNBP) + if (isPbPb) + histos.fill(HIST("hSparseCentFiredBPperPlane"), ich, cent, pt, eta, phi); + else + histos.fill(HIST("hSparseCentFiredBPperPlane"), ich, pt, eta, phi); + } + if (isFiredNBP) { histos.fill(HIST("nFiredNBPperPlane"), ich); // NBP - Plane - if (isFiredBP && isFiredNBP) + if (isPbPb) + histos.fill(HIST("hSparseCentFiredNBPperPlane"), ich, cent, pt, eta, phi); + else + histos.fill(HIST("hSparseCentFiredNBPperPlane"), ich, pt, eta, phi); + } + if (isFiredBP && isFiredNBP) { histos.fill(HIST("nFiredBothperPlane"), ich); // Both planes - plane + if (isPbPb) + histos.fill(HIST("hSparseCentFiredBothperPlane"), ich, cent, pt, eta, phi); + else + histos.fill(HIST("hSparseCentFiredBothperPlane"), ich, pt, eta, phi); + } if (effFlag < 2) { continue; @@ -136,39 +234,80 @@ struct midEfficiency { // Get RPC id auto deId = o2::mid::detparams::getDEId(isRight, ich, rpcLine); - // Fill all counts - RPC - histos.fill(HIST("nTotperRPC"), deId); - if (isFiredBP) + // RPC + histos.fill(HIST("nTotperRPC"), deId); // All counts - RPC + if (isPbPb) + histos.fill(HIST("hSparseCentFiredTotperRPC"), deId, cent, pt, eta, phi); + else + histos.fill(HIST("hSparseCentFiredTotperRPC"), deId, pt, eta, phi); + + if (isFiredBP) { histos.fill(HIST("nFiredBPperRPC"), deId); // BP - RPC - if (isFiredNBP) + if (isPbPb) + histos.fill(HIST("hSparseCentFiredBPperRPC"), deId, cent, pt, eta, phi); + else + histos.fill(HIST("hSparseCentFiredBPperRPC"), deId, pt, eta, phi); + } + if (isFiredNBP) { histos.fill(HIST("nFiredNBPperRPC"), deId); // NBP - RPC - if (isFiredBP && isFiredNBP) + if (isPbPb) + histos.fill(HIST("hSparseCentFiredNBPperRPC"), deId, cent, pt, eta, phi); + else + histos.fill(HIST("hSparseCentFiredNBPperRPC"), deId, pt, eta, phi); + } + if (isFiredBP && isFiredNBP) { histos.fill(HIST("nFiredBothperRPC"), deId); // Both planes - RPC + if (isPbPb) + histos.fill(HIST("hSparseCentFiredBothperRPC"), deId, cent, pt, eta, phi); + else + histos.fill(HIST("hSparseCentFiredBothperRPC"), deId, pt, eta, phi); + } if (effFlag < 3) { continue; } + // Get fired column and line -> needed for LB calculation + auto firedColumn = trk.getFiredColumnId(); + auto firedLine = trk.getFiredLineId(); // Get LB ID - auto firedColumn = trk.getFiredColumnId(); // Get fired column - needed for LB calculation - auto firedLine = trk.getFiredLineId(); // Get fired line - needed for LB calculation - auto LB = ich * o2::mid::detparams::NLocalBoards + mapping.getBoardId(firedLine, firedColumn, deId); - histos.fill(HIST("nTotperBoard"), LB); - - if (isFiredBP) - histos.fill(HIST("nFiredBPperBoard"), LB); - if (isFiredNBP) - histos.fill(HIST("nFiredNBPperBoard"), LB); - if (isFiredBP && isFiredNBP) - histos.fill(HIST("nFiredBothperBoard"), LB); + // LB + histos.fill(HIST("nTotperBoard"), LB); // All counts - LB + if (isPbPb) + histos.fill(HIST("hSparseCentFiredTotperBoard"), LB, cent, pt, eta, phi); + else + histos.fill(HIST("hSparseCentFiredTotperBoard"), LB, pt, eta, phi); + + if (isFiredBP) { + histos.fill(HIST("nFiredBPperBoard"), LB); // BP - LB + if (isPbPb) + histos.fill(HIST("hSparseCentFiredBPperBoard"), LB, cent, pt, eta, phi); + else + histos.fill(HIST("hSparseCentFiredBPperBoard"), LB, pt, eta, phi); + } + if (isFiredNBP) { + histos.fill(HIST("nFiredNBPperBoard"), LB); // NBP - LB + if (isPbPb) + histos.fill(HIST("hSparseCentFiredNBPperBoard"), LB, cent, pt, eta, phi); + else + histos.fill(HIST("hSparseCentFiredNBPperBoard"), LB, pt, eta, phi); + } + if (isFiredBP && isFiredNBP) { + histos.fill(HIST("nFiredBothperBoard"), LB); // Both Planes - LB + if (isPbPb) + histos.fill(HIST("hSparseCentFiredBothperBoard"), LB, cent, pt, eta, phi); + else + histos.fill(HIST("hSparseCentFiredBothperBoard"), LB, pt, eta, phi); + } } } } // end of runMidEffCounters - void processMidEffCounter(aod::ReducedEvents::iterator const& event, MyMuonTracks const& muons) + // void processMidEffCounter(aod::ReducedEvents::iterator const& event, soa::Filtered const& muons) + void processMidEffCounter(MyEvents::iterator const& event, soa::Filtered const& muons) { runMidEffCounters(event, muons); // call efficiency calculator function } @@ -180,4 +319,4 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ adaptAnalysisTask(cfgc)}; -} \ No newline at end of file +} diff --git a/PWGDQ/Tasks/ModelConverterMultPv.cxx b/PWGDQ/Tasks/ModelConverterMultPv.cxx new file mode 100644 index 00000000000..088590435b8 --- /dev/null +++ b/PWGDQ/Tasks/ModelConverterMultPv.cxx @@ -0,0 +1,56 @@ +// 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. +// +// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no +// +// Task used to convert the data model from the old format to the new format. To avoid +// the conflict with the old data model. + +// other includes +#include +#include +#include +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod; + +struct MultPVConverter000_001 { + Produces multPV_001; + void processConverting(aod::ReducedEventsMultPV_000 const& multsPV) + { + for (const auto& r : multsPV) { + multPV_001(r.multNTracksHasITS(), r.multNTracksHasTPC(), r.multNTracksHasTOF(), r.multNTracksHasTRD(), + r.multNTracksITSOnly(), r.multNTracksTPCOnly(), r.multNTracksITSTPC(), -1.0f, -1.0f, r.trackOccupancyInTimeRange(), -999.0f); + } + } + + void processDummy(o2::aod::ReducedEvents&) + { + // do nothing + } + + PROCESS_SWITCH(MultPVConverter000_001, processConverting, "Convert Table MultPV_000 to Table MultPV_001", false); + PROCESS_SWITCH(MultPVConverter000_001, processDummy, "do nothing", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGDQ/Tasks/dqCorrelation.cxx b/PWGDQ/Tasks/dqCorrelation.cxx index 353a7fbf575..950e82364cb 100644 --- a/PWGDQ/Tasks/dqCorrelation.cxx +++ b/PWGDQ/Tasks/dqCorrelation.cxx @@ -116,7 +116,7 @@ struct DqCumulantFlow { ConfigurableAxis axisEta{"axisEta", {40, -6.0, 1.5}, "eta axis for histograms"}; ConfigurableAxis axisPt{"axisPt", {100, 0, 20}, "pt axis for histograms"}; ConfigurableAxis axisMass{"axisMass", {40, 2, 4}, "mass axis for histograms"}; - Configurable fConfigNPow{"cfgNPow", 0, "Power of weights for Q vector"}; + Configurable fConfigNPow{"cfgNPow", 0, "Power of weights for Q vector"}; // Configurables for the reference flow Configurable fConfigTrackCuts{"cfgLeptonCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; Configurable fConfigCutPtMin{"cfgCutPtMin", 1.0f, "Minimal pT for tracks"}; @@ -303,7 +303,7 @@ struct DqCumulantFlow { } weff = 1. / weff; if (cfg.mAcceptance) { - wacc = cfg.mAcceptance->GetNUA(track.phi(), track.eta(), event.posZ()); + wacc = cfg.mAcceptance->getNUA(track.phi(), track.eta(), event.posZ()); } else { wacc = 1.0; } diff --git a/PWGDQ/Tasks/dqEfficiency.cxx b/PWGDQ/Tasks/dqEfficiency.cxx index e661f4f7563..e898e4c4f19 100644 --- a/PWGDQ/Tasks/dqEfficiency.cxx +++ b/PWGDQ/Tasks/dqEfficiency.cxx @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -97,8 +100,12 @@ struct AnalysisEventSelection { HistogramManager* fHistMan; AnalysisCompositeCut* fEventCut; - void init(o2::framework::InitContext&) + void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + fEventCut = new AnalysisCompositeCut(true); TString eventCutStr = fConfigEventCuts.value; fEventCut->AddCut(dqcuts::GetAnalysisCut(eventCutStr.Data())); @@ -167,8 +174,12 @@ struct AnalysisTrackSelection { std::vector fHistNamesReco; std::vector> fHistNamesMCMatched; - void init(o2::framework::InitContext&) + void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + // Setting the cut names TString cutNamesStr = fConfigCuts.value; if (!cutNamesStr.IsNull()) { @@ -256,7 +267,7 @@ struct AnalysisTrackSelection { int i = 0; for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, i++) { if ((*cut).IsSelected(VarManager::fgValues)) { - filterMap |= (uint32_t(1) << i); + filterMap |= (static_cast(1) << i); if (fConfigQA) { fHistMan->FillHistClass(fHistNamesReco[i].Data(), VarManager::fgValues); } @@ -277,19 +288,19 @@ struct AnalysisTrackSelection { for (auto sig = fMCSignals.begin(); sig != fMCSignals.end(); sig++, isig++) { if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedTrack) > 0) { if ((*sig).CheckSignal(false, track.reducedMCTrack())) { - mcDecision |= (uint32_t(1) << isig); + mcDecision |= (static_cast(1) << isig); } } if constexpr ((TTrackFillMap & VarManager::ObjTypes::Track) > 0) { if ((*sig).CheckSignal(false, track.template mcParticle_as())) { - mcDecision |= (uint32_t(1) << isig); + mcDecision |= (static_cast(1) << isig); } } } // fill histograms for (unsigned int i = 0; i < fMCSignals.size(); i++) { - if (!(mcDecision & (uint32_t(1) << i))) { + if (!(mcDecision & (static_cast(1) << i))) { continue; } for (unsigned int j = 0; j < fTrackCuts.size(); j++) { @@ -305,11 +316,16 @@ struct AnalysisTrackSelection { { runSelection(event, tracks, eventsMC, tracksMC); } + void processSkimmedWithCov(MyEventsSelected::iterator const& event, MyBarrelTracksWithCov const& tracks, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) + { + runSelection(event, tracks, eventsMC, tracksMC); + } void processDummy(MyEvents&) { // do nothing } + PROCESS_SWITCH(AnalysisTrackSelection, processSkimmedWithCov, "Run barrel track selection on DQ skimmed tracks with covariance", false); PROCESS_SWITCH(AnalysisTrackSelection, processSkimmed, "Run barrel track selection on DQ skimmed tracks", false); PROCESS_SWITCH(AnalysisTrackSelection, processDummy, "Dummy process function", false); }; @@ -327,8 +343,12 @@ struct AnalysisMuonSelection { std::vector fHistNamesReco; std::vector> fHistNamesMCMatched; - void init(o2::framework::InitContext&) + void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + // Setting the cut names TString cutNamesStr = fConfigCuts.value; if (!cutNamesStr.IsNull()) { @@ -355,14 +375,14 @@ struct AnalysisMuonSelection { // Configure histogram classes for each track cut; // Add histogram classes for each track cut and for each requested MC signal (reconstructed tracks with MC truth) - TString histClasses = "Muon_BeforeCuts;"; + TString histClasses = "TrackMuon_BeforeCuts;"; for (auto& cut : fTrackCuts) { - TString nameStr = Form("Muon_%s", cut.GetName()); + TString nameStr = Form("TrackMuon_%s", cut.GetName()); fHistNamesReco.push_back(nameStr); histClasses += Form("%s;", nameStr.Data()); std::vector mcnames; for (auto& sig : fMCSignals) { - TString nameStr2 = Form("Muon_%s_%s", cut.GetName(), sig.GetName()); + TString nameStr2 = Form("TrackMuon_%s_%s", cut.GetName(), sig.GetName()); printf("Adding my histogram class %s\n", nameStr2.Data()); mcnames.push_back(nameStr2); histClasses += Form("%s;", nameStr2.Data()); @@ -410,14 +430,14 @@ struct AnalysisMuonSelection { } if (fConfigQA) { - fHistMan->FillHistClass("Muon_BeforeCuts", VarManager::fgValues); + fHistMan->FillHistClass("TrackMuon_BeforeCuts", VarManager::fgValues); } // compute the cut selections and publish the filter bit map int i = 0; for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, i++) { if ((*cut).IsSelected(VarManager::fgValues)) { - filterMap |= (uint32_t(1) << i); + filterMap |= (static_cast(1) << i); if (fConfigQA) { fHistMan->FillHistClass(fHistNamesReco[i].Data(), VarManager::fgValues); } @@ -441,19 +461,19 @@ struct AnalysisMuonSelection { for (auto sig = fMCSignals.begin(); sig != fMCSignals.end(); sig++, isig++) { if constexpr ((TMuonFillMap & VarManager::ObjTypes::ReducedMuon) > 0) { if ((*sig).CheckSignal(false, muon.reducedMCTrack())) { - mcDecision |= (uint32_t(1) << isig); + mcDecision |= (static_cast(1) << isig); } } if constexpr ((TMuonFillMap & VarManager::ObjTypes::Muon) > 0) { if ((*sig).CheckSignal(false, muon.template mcParticle_as())) { - mcDecision |= (uint32_t(1) << isig); + mcDecision |= (static_cast(1) << isig); } } } // fill histograms for (unsigned int i = 0; i < fMCSignals.size(); i++) { - if (!(mcDecision & (uint32_t(1) << i))) { + if (!(mcDecision & (static_cast(1) << i))) { continue; } for (unsigned int j = 0; j < fTrackCuts.size(); j++) { @@ -482,7 +502,9 @@ struct AnalysisSameEventPairing { Produces dielectronList; Produces dimuonList; Produces dielectronExtraList; + Produces dielectronInfoList; Produces dimuonExtraList; + Produces dielectronAllList; Produces dimuonAllList; Service ccdb; float mMagField = 0.0; @@ -496,14 +518,16 @@ struct AnalysisSameEventPairing { Filter filterMuonSelected = aod::dqanalysisflags::isMuonSelected > 0; Configurable fConfigTrackCuts{"cfgTrackCuts", "", "Comma separated list of barrel track cuts"}; Configurable fConfigMuonCuts{"cfgMuonCuts", "", "Comma separated list of barrel track cuts"}; - Configurable fConfigMCRecSignals{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; - Configurable fConfigMCGenSignals{"cfgBarrelMCGenSignals", "", "Comma separated list of MC signals (generated)"}; + Configurable fConfigMCRecSignals{"cfgMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; + Configurable fConfigMCGenSignals{"cfgMCGenSignals", "", "Comma separated list of MC signals (generated)"}; + Configurable fConfigSkimSignalOnly{"fConfigSkimSignalOnly", false, "Configurable to select only matched candidates"}; Configurable fConfigFlatTables{"cfgFlatTables", false, "Produce a single flat tables with all relevant information of the pairs and single tracks"}; Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; Configurable fUseRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable fConfigAmbiguousHist{"cfgAmbiHist", false, "Enable Ambiguous histograms for time association studies"}; Configurable fUseAbsDCA{"cfgUseAbsDCA", false, "Use absolute DCA minimization instead of chi^2 minimization in secondary vertexing"}; Configurable fPropToPCA{"cfgPropToPCA", false, "Propagate tracks to secondary vertex"}; Configurable fCorrFullGeo{"cfgCorrFullGeo", false, "Use full geometry to correct for MCS effects in track propagation"}; @@ -528,6 +552,10 @@ struct AnalysisSameEventPairing { void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + fCurrentRun = 0; ccdb->setURL(ccdburl.value); @@ -606,7 +634,11 @@ struct AnalysisSameEventPairing { Form("PairsMuonSEPM_%s", objArray->At(icut)->GetName()), Form("PairsMuonSEPP_%s", objArray->At(icut)->GetName()), Form("PairsMuonSEMM_%s", objArray->At(icut)->GetName())}; - histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); + if (fConfigAmbiguousHist) { + histNames += Form("%s;%s;%s;%s_unambiguous;%s_unambiguous;%s_unambiguous;", names[0].Data(), names[1].Data(), names[2].Data(), names[0].Data(), names[1].Data(), names[2].Data()); + } else { + histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); + } fMuonHistNames.push_back(names); std::vector mcSigClasses; if (!sigNamesStr.IsNull()) { @@ -688,22 +720,22 @@ struct AnalysisSameEventPairing { void runPairing(TEvent const& event, TTracks1 const& tracks1, TTracks2 const& tracks2, TEventsMC const& /*eventsMC*/, TTracksMC const& /*tracksMC*/) { if (fCurrentRun != event.runNumber()) { - if (fUseRemoteField.value) { + if (fUseRemoteField) { grpmag = ccdb->getForTimeStamp(grpmagPath, event.timestamp()); if (grpmag != nullptr) { mMagField = grpmag->getNominalL3Field(); } else { LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", event.timestamp()); } - if (fConfigUseKFVertexing.value) { + if (fConfigUseKFVertexing) { VarManager::SetupTwoProngKFParticle(mMagField); } else { VarManager::SetupTwoProngDCAFitter(mMagField, fPropToPCA.value, 200.0f, 4.0f, 1.0e-3f, 0.9f, fUseAbsDCA.value); // TODO: get these parameters from Configurables VarManager::SetupTwoProngFwdDCAFitter(mMagField, fPropToPCA.value, 200.0f, 1.0e-3f, 0.9f, fUseAbsDCA.value); } } else { - if (fConfigUseKFVertexing.value) { - VarManager::SetupTwoProngKFParticle(fConfigMagField.value); + if (fConfigUseKFVertexing) { + VarManager::SetupTwoProngKFParticle(fConfigMagField); } else { VarManager::SetupTwoProngDCAFitter(fConfigMagField.value, fPropToPCA.value, 200.0f, 4.0f, 1.0e-3f, 0.9f, fUseAbsDCA.value); // TODO: get these parameters from Configurables VarManager::SetupTwoProngFwdDCAFitter(fConfigMagField.value, fPropToPCA.value, 200.0f, 1.0e-3f, 0.9f, fUseAbsDCA.value); @@ -732,22 +764,24 @@ struct AnalysisSameEventPairing { uint32_t dileptonFilterMap = 0; uint32_t dileptonMcDecision = 0; dielectronList.reserve(1); + dielectronInfoList.reserve(1); dimuonList.reserve(1); dielectronExtraList.reserve(1); dimuonExtraList.reserve(1); if (fConfigFlatTables.value) { + dielectronAllList.reserve(1); dimuonAllList.reserve(1); } for (auto& [t1, t2] : combinations(tracks1, tracks2)) { if constexpr (TPairType == VarManager::kDecayToEE) { - twoTrackFilter = uint32_t(t1.isBarrelSelected()) & uint32_t(t2.isBarrelSelected()); + twoTrackFilter = static_cast(t1.isBarrelSelected()) & static_cast(t2.isBarrelSelected()); } if constexpr (TPairType == VarManager::kDecayToMuMu) { - twoTrackFilter = uint32_t(t1.isMuonSelected()) & uint32_t(t2.isMuonSelected()); + twoTrackFilter = static_cast(t1.isMuonSelected()) & static_cast(t2.isMuonSelected()); } if constexpr (TPairType == VarManager::kElectronMuon) { - twoTrackFilter = uint32_t(t1.isBarrelSelected()) & uint32_t(t2.isMuonSelected()); + twoTrackFilter = static_cast(t1.isBarrelSelected()) & static_cast(t2.isMuonSelected()); } if (!twoTrackFilter) { // the tracks must have at least one filter bit in common to continue continue; @@ -764,22 +798,38 @@ struct AnalysisSameEventPairing { for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { if constexpr (TTrackFillMap & VarManager::ObjTypes::ReducedTrack || TTrackFillMap & VarManager::ObjTypes::ReducedMuon) { // for skimmed DQ model if ((*sig).CheckSignal(false, t1.reducedMCTrack(), t2.reducedMCTrack())) { - mcDecision |= (uint32_t(1) << isig); + mcDecision |= (static_cast(1) << isig); } } if constexpr (TTrackFillMap & VarManager::ObjTypes::Track || TTrackFillMap & VarManager::ObjTypes::Muon) { // for Framework data model if ((*sig).CheckSignal(false, t1.template mcParticle_as(), t2.template mcParticle_as())) { - mcDecision |= (uint32_t(1) << isig); + mcDecision |= (static_cast(1) << isig); } } } // end loop over MC signals dileptonFilterMap = twoTrackFilter; dileptonMcDecision = mcDecision; - - if constexpr (TPairType == VarManager::kDecayToEE) { - dielectronList(event, VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), dileptonFilterMap, dileptonMcDecision); - dielectronExtraList(t1.globalIndex(), t2.globalIndex(), VarManager::fgValues[VarManager::kVertexingTauz], VarManager::fgValues[VarManager::kVertexingLz], VarManager::fgValues[VarManager::kVertexingLxy]); + if (!fConfigSkimSignalOnly || (fConfigSkimSignalOnly && mcDecision > 0)) { + if constexpr (TPairType == VarManager::kDecayToEE) { + dielectronList(event, VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), dileptonFilterMap, dileptonMcDecision); + if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedTrackCollInfo) > 0) { + dielectronInfoList(t1.collisionId(), t1.trackId(), t2.trackId()); + } + dielectronExtraList(t1.globalIndex(), t2.globalIndex(), VarManager::fgValues[VarManager::kVertexingTauz], VarManager::fgValues[VarManager::kVertexingLz], VarManager::fgValues[VarManager::kVertexingLxy]); + } + if constexpr ((TPairType == VarManager::kDecayToEE) && (TTrackFillMap & VarManager::ObjTypes::ReducedTrackBarrelPID) > 0) { + if (fConfigFlatTables.value) { + dielectronAllList(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), dileptonFilterMap, dileptonMcDecision, + t1.pt(), t1.eta(), t1.phi(), t1.itsClusterMap(), t1.itsChi2NCl(), t1.tpcNClsCrossedRows(), t1.tpcNClsFound(), t1.tpcChi2NCl(), t1.dcaXY(), t1.dcaZ(), t1.tpcSignal(), t1.tpcNSigmaEl(), t1.tpcNSigmaPi(), t1.tpcNSigmaPr(), t1.beta(), t1.tofNSigmaEl(), t1.tofNSigmaPi(), t1.tofNSigmaPr(), + t2.pt(), t2.eta(), t2.phi(), t2.itsClusterMap(), t2.itsChi2NCl(), t2.tpcNClsCrossedRows(), t2.tpcNClsFound(), t2.tpcChi2NCl(), t2.dcaXY(), t2.dcaZ(), t2.tpcSignal(), t2.tpcNSigmaEl(), t2.tpcNSigmaPi(), t2.tpcNSigmaPr(), t2.beta(), t2.tofNSigmaEl(), t2.tofNSigmaPi(), t2.tofNSigmaPr(), + VarManager::fgValues[VarManager::kKFTrack0DCAxyz], VarManager::fgValues[VarManager::kKFTrack1DCAxyz], VarManager::fgValues[VarManager::kKFDCAxyzBetweenProngs], VarManager::fgValues[VarManager::kKFTrack0DCAxy], VarManager::fgValues[VarManager::kKFTrack1DCAxy], VarManager::fgValues[VarManager::kKFDCAxyBetweenProngs], + VarManager::fgValues[VarManager::kKFTrack0DeviationFromPV], VarManager::fgValues[VarManager::kKFTrack1DeviationFromPV], VarManager::fgValues[VarManager::kKFTrack0DeviationxyFromPV], VarManager::fgValues[VarManager::kKFTrack1DeviationxyFromPV], + VarManager::fgValues[VarManager::kKFMass], VarManager::fgValues[VarManager::kKFChi2OverNDFGeo], VarManager::fgValues[VarManager::kVertexingLxyz], VarManager::fgValues[VarManager::kVertexingLxyzOverErr], VarManager::fgValues[VarManager::kVertexingLxy], VarManager::fgValues[VarManager::kVertexingLxyOverErr], VarManager::fgValues[VarManager::kVertexingTauxy], VarManager::fgValues[VarManager::kVertexingTauxyErr], VarManager::fgValues[VarManager::kKFCosPA], VarManager::fgValues[VarManager::kKFJpsiDCAxyz], VarManager::fgValues[VarManager::kKFJpsiDCAxy], + VarManager::fgValues[VarManager::kKFPairDeviationFromPV], VarManager::fgValues[VarManager::kKFPairDeviationxyFromPV], + VarManager::fgValues[VarManager::kKFMassGeoTop], VarManager::fgValues[VarManager::kKFChi2OverNDFGeoTop]); + } + } } if constexpr (TPairType == VarManager::kDecayToMuMu) { dimuonList(event, VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), dileptonFilterMap, dileptonMcDecision); @@ -790,6 +840,7 @@ struct AnalysisSameEventPairing { if constexpr ((TPairType == VarManager::kDecayToMuMu) && muonHasCov) { if (fConfigFlatTables.value) { dimuonAllList(event.posX(), event.posY(), event.posZ(), event.numContrib(), + event.selection_raw(), 0, event.reducedMCevent().mcPosX(), event.reducedMCevent().mcPosY(), event.reducedMCevent().mcPosZ(), VarManager::fgValues[VarManager::kMass], dileptonMcDecision, @@ -819,16 +870,28 @@ struct AnalysisSameEventPairing { if (twoTrackFilter & (uint8_t(1) << icut)) { if (t1.sign() * t2.sign() < 0) { fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); + if (fConfigAmbiguousHist && !(t1.isAmbiguous() || t2.isAmbiguous())) { + fHistMan->FillHistClass(Form("%s_unambiguous", histNames[icut][0].Data()), VarManager::fgValues); + } for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { - if (mcDecision & (uint32_t(1) << isig)) { + if (mcDecision & (static_cast(1) << isig)) { fHistMan->FillHistClass(histNamesMCmatched[icut][isig].Data(), VarManager::fgValues); + if (fConfigAmbiguousHist && !(t1.isAmbiguous() || t2.isAmbiguous())) { + fHistMan->FillHistClass(Form("%s_unambiguous", histNamesMCmatched[icut][isig].Data()), VarManager::fgValues); + } } } } else { if (t1.sign() > 0) { fHistMan->FillHistClass(histNames[icut][1].Data(), VarManager::fgValues); + if (fConfigAmbiguousHist && !(t1.isAmbiguous() || t2.isAmbiguous())) { + fHistMan->FillHistClass(Form("%s_unambiguous", histNames[icut][1].Data()), VarManager::fgValues); + } } else { fHistMan->FillHistClass(histNames[icut][2].Data(), VarManager::fgValues); + if (fConfigAmbiguousHist && !(t1.isAmbiguous() || t2.isAmbiguous())) { + fHistMan->FillHistClass(Form("%s_unambiguous", histNames[icut][2].Data()), VarManager::fgValues); + } } } } @@ -879,7 +942,7 @@ struct AnalysisSameEventPairing { checked = sig.CheckSignal(false, t1, t2); } if (checked) { - VarManager::FillPairMC(t1, t2); + VarManager::FillPairMC(t1, t2); fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig.GetName()), VarManager::fgValues); } } @@ -1008,6 +1071,10 @@ struct AnalysisDileptonTrack { void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + TString sigNamesStr = fConfigMCRecSignals.value; std::unique_ptr objRecSigArray(sigNamesStr.Tokenize(",")); TString histNames; @@ -1137,13 +1204,13 @@ struct AnalysisDileptonTrack { for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { if constexpr (TTrackFillMap & VarManager::ObjTypes::ReducedTrack || TTrackFillMap & VarManager::ObjTypes::ReducedMuon) { // for skimmed DQ model if ((*sig).CheckSignal(false, lepton1MC, lepton2MC)) { - mcDecision |= (uint32_t(1) << isig); + mcDecision |= (static_cast(1) << isig); } } } // end loop over MC signals for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { - if (mcDecision & (uint32_t(1) << isig)) { + if (mcDecision & (static_cast(1) << isig)) { fHistMan->FillHistClass(Form("DileptonsSelected_matchedMC_%s", fRecMCSignalsNames[isig].Data()), fValuesDilepton); } } @@ -1169,7 +1236,7 @@ struct AnalysisDileptonTrack { for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { if constexpr (TTrackFillMap & VarManager::ObjTypes::ReducedTrack || TTrackFillMap & VarManager::ObjTypes::ReducedMuon || TTrackFillMap & VarManager::ObjTypes::ReducedMuon) { // for skimmed DQ model if ((*sig).CheckSignal(false, lepton1MC, lepton2MC, trackMC)) { - mcDecision |= (uint32_t(1) << isig); + mcDecision |= (static_cast(1) << isig); } } } @@ -1179,7 +1246,7 @@ struct AnalysisDileptonTrack { } for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { - if (mcDecision & (uint32_t(1) << isig)) { + if (mcDecision & (static_cast(1) << isig)) { fHistMan->FillHistClass(Form("DileptonTrackInvMass_matchedMC_%s", fRecMCSignalsNames[isig].Data()), fValuesTrack); } } @@ -1243,6 +1310,297 @@ struct AnalysisDileptonTrack { PROCESS_SWITCH(AnalysisDileptonTrack, processDummy, "Dummy function", false); }; +struct AnalysisDileptonTrackTrack { + OutputObj fOutputList{"output"}; + + Configurable fConfigTrackCut1{"cfgTrackCut1", "pionPIDCut1", "track1 cut"}; // used for select the tracks from SelectedTracks + Configurable fConfigTrackCut2{"cfgTrackCut2", "pionPIDCut2", "track2 cut"}; // used for select the tracks from SelectedTracks + Configurable fConfigDileptonCut{"cfgDileptonCut", "pairJpsi2", "Dilepton cut"}; + Configurable fConfigQuadrupletCuts{"cfgQuadrupletCuts", "pairX3872Cut1", "Comma separated list of Dilepton-Track-Track cut"}; + Configurable fConfigMCRecSignals{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; + Configurable fConfigMCGenSignals{"cfgBarrelMCGenSignals", "", "Comma separated list of MC signals (generated)"}; + Configurable fConfigDileptonMCRecSignal{"cfgDileptonMCRecSignal", "", "Comma separated list of MC signals (reconstructed)"}; + + Produces DileptonTrackTrackTable; + HistogramManager* fHistMan; + + std::vector fRecMCSignalsNames; + std::vector fRecMCSignals; + std::vector fGenMCSignals; + std::vector fDileptonMCRecSignals; + + Filter eventFilter = aod::dqanalysisflags::isEventSelected == 1; + Filter dileptonFilter = aod::reducedpair::sign == 0; + Filter filterBarrelTrackSelected = aod::dqanalysisflags::isBarrelSelected > 0; + + float* fValuesQuadruplet; + + std::vector fQuadrupletCutNames; + AnalysisCompositeCut fDileptonCut; + std::vector fQuadrupletCuts; + TString fTrackCutName1; + TString fTrackCutName2; + bool fIsSameTrackCut = false; + + constexpr static uint32_t fgDileptonFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::Pair; // fill map + + void init(o2::framework::InitContext& context) + { + if (context.mOptions.get("processDummy")) { + return; + } + + fValuesQuadruplet = new float[VarManager::kNVars]; + VarManager::SetDefaultVarNames(); + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + TString histNames; + + // check if the same track cuts are used for both tracks + if (fConfigTrackCut1.value == fConfigTrackCut2.value) { + fIsSameTrackCut = true; + } + fTrackCutName1 = fConfigTrackCut1.value; + fTrackCutName2 = fConfigTrackCut2.value; + + // dilepton cut + TString configDileptonCutNamesStr = fConfigDileptonCut.value; + fDileptonCut = *dqcuts::GetCompositeCut(configDileptonCutNamesStr.Data()); + + // dilepton-track-track cuts + TString configQuadruletCutNamesStr = fConfigQuadrupletCuts.value; + std::unique_ptr objArray(configQuadruletCutNamesStr.Tokenize(",")); + for (Int_t icut = 0; icut < objArray->GetEntries(); ++icut) { + TString cutName = objArray->At(icut)->GetName(); + fQuadrupletCutNames.push_back(cutName); + fQuadrupletCuts.push_back(*dqcuts::GetCompositeCut(cutName.Data())); + } + + // reconstructible MC signals + TString sigNamesStr = fConfigMCRecSignals.value; + std::unique_ptr objRecSigArray(sigNamesStr.Tokenize(",")); + for (int isig = 0; isig < objRecSigArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objRecSigArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() == 3) { + fRecMCSignals.push_back(*sig); + } + } + } + + // fill the histogram names + if (!context.mOptions.get("processDummy")) { + // Title_DileptonTrackTrackCutName + if (!configQuadruletCutNamesStr.IsNull()) { + for (std::size_t icut = 0; icut < fQuadrupletCutNames.size(); ++icut) { + if (fIsSameTrackCut) { + histNames += Form("QuadrupletSEPM_%s;", fQuadrupletCutNames[icut].Data()); + } else { + histNames += Form("QuadrupletSEPM_%s;", fQuadrupletCutNames[icut].Data()); + histNames += Form("QuadrupletSEMP_%s;", fQuadrupletCutNames[icut].Data()); + } + histNames += Form("QuadrupletSEPP_%s;", fQuadrupletCutNames[icut].Data()); + histNames += Form("QuadrupletSEMM_%s;", fQuadrupletCutNames[icut].Data()); + // Reco MC signals + for (int isig = 0; isig < objRecSigArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objRecSigArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() == 4) { + fRecMCSignals.push_back(*sig); + fRecMCSignalsNames.push_back(sig->GetName()); + histNames += Form("MCTruthRecQaud_%s_%s;", fQuadrupletCutNames[icut].Data(), sig->GetName()); + } + } + } + } // loop over dilepton-track-track cuts + } + } + + // Genarate MC signals + TString sigGenNamesStr = fConfigMCGenSignals.value; + std::unique_ptr objGenSigArray(sigGenNamesStr.Tokenize(",")); + for (int isig = 0; isig < objGenSigArray->GetEntries(); isig++) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objGenSigArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() == 1) { // NOTE: 1-prong signals required + fGenMCSignals.push_back(*sig); + histNames += Form("MCTruthGenQaud_%s;", sig->GetName()); // TODO: Add these names to a std::vector to avoid using Form in the process function + } + } + } + + DefineHistograms(fHistMan, histNames.Data()); // define all histograms + VarManager::SetUseVars(fHistMan->GetUsedVars()); + fOutputList.setObject(fHistMan->GetMainHistogramList()); + + // dilepton MC signal + TString configDileptonMCRecSignalStr = fConfigDileptonMCRecSignal.value; + std::unique_ptr objDileptonMCRecSignalArray(configDileptonMCRecSignalStr.Tokenize(",")); + for (int isig = 0; isig < objDileptonMCRecSignalArray->GetEntries(); isig++) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objDileptonMCRecSignalArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() == 2) { + fDileptonMCRecSignals.push_back(*sig); + } + } + } + } + + // Template function to run pair - track - track combinations + template + void runDileptonTrackTrack(TEvent const& event, TTracks const& tracks, TDileptons const& dileptons, TEventsMC const& /*eventsMC*/, TTracksMC const& /*tracksMC*/) + { + VarManager::ResetValues(0, VarManager::kNVars, fValuesQuadruplet); + VarManager::FillEvent(event, fValuesQuadruplet); + + // LOGF(info, "Number of dileptons: %d", dileptons.size()); + int indexOffset = -999; + std::vector trackGlobalIndexes; + + if (dileptons.size() > 0) { + for (auto track : tracks) { + trackGlobalIndexes.push_back(track.globalIndex()); + // std::cout << track.index() << " " << track.globalIndex() << std::endl; + } + } + + // loop over dileptons + for (auto dilepton : dileptons) { + VarManager::FillTrack(dilepton, fValuesQuadruplet); + + // apply the dilepton cut + if (!fDileptonCut.IsSelected(fValuesQuadruplet)) + continue; + + // get the index of the electron legs + int indexLepton1 = dilepton.index0Id(); + int indexLepton2 = dilepton.index1Id(); + + if (indexOffset == -999) { + indexOffset = trackGlobalIndexes.at(0); + } + trackGlobalIndexes.clear(); + + auto lepton1 = tracks.iteratorAt(indexLepton1 - indexOffset); + auto lepton2 = tracks.iteratorAt(indexLepton2 - indexOffset); + + auto lepton1MC = lepton1.reducedMCTrack(); + auto lepton2MC = lepton2.reducedMCTrack(); + + // loop over track - track combinations + for (auto& [t1, t2] : combinations(tracks, tracks)) { + // avoid self-combinations + if (t1.globalIndex() == indexLepton1 || t1.globalIndex() == indexLepton2 || t2.globalIndex() == indexLepton1 || t2.globalIndex() == indexLepton2) { + // LOGF(info, "self-combination: %d=%d %d=%d", t1.globalIndex(), indexLepton1, indexLepton2, t2.globalIndex()); + continue; + } + + // dilepton combinate with two same particles + if ((fIsSameTrackCut && (t1.isBarrelSelected() & (static_cast(1) << 1)) && (t2.isBarrelSelected() & (static_cast(1) << 1))) || + (!fIsSameTrackCut && (t1.isBarrelSelected() & (static_cast(1) << 1)) && (t2.isBarrelSelected() & (static_cast(1) << 2)))) { + } else { + continue; + } + + // Fill the Histograms + VarManager::FillDileptonTrackTrack(dilepton, t1, t2, fValuesQuadruplet); + uint32_t CutDecision = 0; + uint32_t mcDecision = 0; + int iCut = 0; + for (auto cut = fQuadrupletCuts.begin(); cut != fQuadrupletCuts.end(); cut++, iCut++) { + if (cut->IsSelected(fValuesQuadruplet)) { + CutDecision |= (static_cast(1) << iCut); + if (fIsSameTrackCut) { + if (t1.sign() * t2.sign() < 0) { + fHistMan->FillHistClass(Form("QuadrupletSEPM_%s", fQuadrupletCutNames[iCut].Data()), fValuesQuadruplet); + } + } else { + if ((t1.sign() < 0) && (t2.sign() > 0)) { + fHistMan->FillHistClass(Form("QuadrupletSEMP_%s", fQuadrupletCutNames[iCut].Data()), fValuesQuadruplet); + } else if ((t1.sign() > 0) && (t2.sign() < 0)) { + fHistMan->FillHistClass(Form("QuadrupletSEPM_%s", fQuadrupletCutNames[iCut].Data()), fValuesQuadruplet); + } + } + if ((t1.sign() > 0) && (t2.sign() > 0)) { + fHistMan->FillHistClass(Form("QuadrupletSEPP_%s", fQuadrupletCutNames[iCut].Data()), fValuesQuadruplet); + } else if ((t1.sign() < 0) && (t2.sign() < 0)) { + fHistMan->FillHistClass(Form("QuadrupletSEMM_%s", fQuadrupletCutNames[iCut].Data()), fValuesQuadruplet); + } + + // Reco MC signals + if (fRecMCSignals.size() > 0) { + int isig = 0; + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { + if ((*sig).CheckSignal(true, lepton1MC, lepton2MC, t1.reducedMCTrack(), t2.reducedMCTrack())) { + mcDecision |= (static_cast(1) << isig); + } + } + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("MCTruthRecQaud_%s_%s", fQuadrupletCutNames[iCut].Data(), fRecMCSignalsNames[isig].Data()), fValuesQuadruplet); + } + } + } + } + } // end loop over cuts + + // Fill the DileptonTrackTrackCandidates table + if (!CutDecision) + continue; + if (!mcDecision) + continue; + DileptonTrackTrackTable(fValuesQuadruplet[VarManager::kQuadMass], fValuesQuadruplet[VarManager::kQuadPt], fValuesQuadruplet[VarManager::kQuadEta], fValuesQuadruplet[VarManager::kQuadPhi], fValuesQuadruplet[VarManager::kRap], + fValuesQuadruplet[VarManager::kQ], fValuesQuadruplet[VarManager::kDeltaR1], fValuesQuadruplet[VarManager::kDeltaR2], fValuesQuadruplet[VarManager::kDeltaR], + dilepton.mass(), dilepton.pt(), dilepton.eta(), dilepton.phi(), dilepton.sign(), + fValuesQuadruplet[VarManager::kDitrackMass], fValuesQuadruplet[VarManager::kDitrackPt], t1.pt(), t2.pt(), t1.eta(), t2.eta(), t1.phi(), t2.phi(), t1.sign(), t2.sign()); + } // end loop over track - track combinations + } // end loop over dileptons + }; + + template + void runMCGen(ReducedMCTracks const& mcTracks) + { + // loop over mc stack and fill histograms for pure MC truth signals + for (auto& track : mcTracks) { + VarManager::FillTrackMC(mcTracks, track); + for (auto& sig : fGenMCSignals) { + if (sig.CheckSignal(true, track)) { + int daughterIdFirst = track.daughtersIds()[0]; + int daughterIdEnd = track.daughtersIds()[1]; + int Ndaughters = daughterIdEnd - daughterIdFirst + 1; + if (Ndaughters == 3) { + auto dilepton = mcTracks.rawIteratorAt(daughterIdFirst); + auto track1 = mcTracks.rawIteratorAt(daughterIdFirst + 1); + auto track2 = mcTracks.rawIteratorAt(daughterIdFirst + 2); + VarManager::FillQaudMC(dilepton, track1, track2); + } + fHistMan->FillHistClass(Form("MCTruthGenQaud_%s", sig.GetName()), VarManager::fgValues); + } + } + } + }; + + PresliceUnsorted perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; + + void processX3872(soa::Filtered::iterator const& event, MyBarrelTracksSelectedWithCov const& tracks, soa::Join const& dileptons, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) + { + runDileptonTrackTrack(event, tracks, dileptons, eventsMC, tracksMC); + auto groupedMCTracks = tracksMC.sliceBy(perReducedMcEvent, event.reducedMCevent().globalIndex()); + groupedMCTracks.bindInternalIndicesTo(&tracksMC); + runMCGen(groupedMCTracks); + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisDileptonTrackTrack, processX3872, "Run X3872 reconstruction", false); + PROCESS_SWITCH(AnalysisDileptonTrackTrack, processDummy, "Dummy function", false); +}; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ @@ -1250,7 +1608,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; } void DefineHistograms(HistogramManager* histMan, TString histClasses) @@ -1281,25 +1640,28 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses) if (classStr.Contains("Pairs")) { if (classStr.Contains("Barrel")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", "barrel,vertexing-barrel"); + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", "barrel,vertexing-barrel,kalman-filter"); } if (classStr.Contains("Muon")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", "dimuon,vertexing-forward"); + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", "dimuon,dimuon-multi-diff,vertexing-forward"); } } if (classStr.Contains("MCTruthGenPair")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_pair"); - histMan->AddHistogram(objArray->At(iclass)->GetName(), "Pt", "MC generator p_{T} distribution", false, 120, 0.0, 30.0, VarManager::kMCPt); + histMan->AddHistogram(objArray->At(iclass)->GetName(), "Pt_Rapidity", "MC generator p_{T}, y distribution", false, 120, 0.0, 30.0, VarManager::kMCPt, 150, 2.5, 4.0, VarManager::kMCY); histMan->AddHistogram(objArray->At(iclass)->GetName(), "Eta", "MC generator #eta distribution", false, 200, 2.5, 4.0, VarManager::kMCEta); - histMan->AddHistogram(objArray->At(iclass)->GetName(), "Rapidity", "MC generator y distribution", false, 150, 2.5, 4.0, VarManager::kMCY); + // histMan->AddHistogram(objArray->At(iclass)->GetName(), "Rapidity", "MC generator y distribution", false, 150, 2.5, 4.0, VarManager::kMCY); histMan->AddHistogram(objArray->At(iclass)->GetName(), "Phi", "MC generator #varphi distribution", false, 50, 0.0, 2. * TMath::Pi(), VarManager::kMCPhi); } + if (classStr.Contains("MCTruthGenQaud")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_quad"); + } if (classStr.Contains("MCTruthGen")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth"); - histMan->AddHistogram(objArray->At(iclass)->GetName(), "Pt", "MC generator p_{T} distribution", false, 120, 0.0, 30.0, VarManager::kMCPt); + histMan->AddHistogram(objArray->At(iclass)->GetName(), "Pt_Rapidity", "MC generator p_{T}, y distribution", false, 120, 0.0, 30.0, VarManager::kMCPt, 150, 2.5, 4.0, VarManager::kMCY); histMan->AddHistogram(objArray->At(iclass)->GetName(), "Eta", "MC generator #eta distribution", false, 200, 2.5, 4.0, VarManager::kMCEta); - histMan->AddHistogram(objArray->At(iclass)->GetName(), "Rapidity", "MC generator y distribution", false, 150, 2.5, 4.0, VarManager::kMCY); + // histMan->AddHistogram(objArray->At(iclass)->GetName(), "Rapidity", "MC generator y distribution", false, 150, 2.5, 4.0, VarManager::kMCY); histMan->AddHistogram(objArray->At(iclass)->GetName(), "Phi", "MC generator #varphi distribution", false, 50, 0.0, 2. * TMath::Pi(), VarManager::kMCPhi); } if (classStr.Contains("DileptonsSelected")) { @@ -1311,6 +1673,9 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses) if (classStr.Contains("DileptonTrackInvMass")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-hadron-mass"); } + if (classStr.Contains("Quadruplet") || classStr.Contains("MCTruthRecQaud")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-dihadron", "xtojpsipipi"); + } } // end loop over histogram classes } diff --git a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx new file mode 100644 index 00000000000..99f508a8b1e --- /dev/null +++ b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx @@ -0,0 +1,3943 @@ +// 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. +// +// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no +// Configurable workflow for running several DQ or other PWG analyses + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisHelpers.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/MixingHandler.h" +#include "PWGDQ/Core/AnalysisCut.h" +#include "PWGDQ/Core/AnalysisCompositeCut.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/MixingLibrary.h" +#include "PWGDQ/Core/MCSignal.h" +#include "PWGDQ/Core/MCSignalLibrary.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "Field/MagneticField.h" +#include "TGeoGlobalMagField.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "Common/Core/TableHelper.h" + +using std::cout; +using std::endl; +using std::string; + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod; + +// Some definitions +namespace o2::aod +{ +namespace dqanalysisflags +{ +DECLARE_SOA_BITMAP_COLUMN(IsEventSelected, isEventSelected, 32); //! Event decision +DECLARE_SOA_BITMAP_COLUMN(IsBarrelSelected, isBarrelSelected, 32); //! Barrel track decisions +DECLARE_SOA_COLUMN(BarrelAmbiguityInBunch, barrelAmbiguityInBunch, int8_t); //! Barrel track in-bunch ambiguity +DECLARE_SOA_COLUMN(BarrelAmbiguityOutOfBunch, barrelAmbiguityOutOfBunch, int8_t); //! Barrel track out of bunch ambiguity +DECLARE_SOA_BITMAP_COLUMN(IsMuonSelected, isMuonSelected, 32); //! Muon track decisions (joinable to ReducedMuonsAssoc) +DECLARE_SOA_COLUMN(MuonAmbiguityInBunch, muonAmbiguityInBunch, int8_t); //! Muon track in-bunch ambiguity +DECLARE_SOA_COLUMN(MuonAmbiguityOutOfBunch, muonAmbiguityOutOfBunch, int8_t); //! Muon track out of bunch ambiguity +DECLARE_SOA_BITMAP_COLUMN(IsBarrelSelectedPrefilter, isBarrelSelectedPrefilter, 32); //! Barrel prefilter decisions (joinable to ReducedTracksAssoc) +// Bcandidate columns for ML analysis of B->Jpsi+K +DECLARE_SOA_COLUMN(massBcandidate, MBcandidate, float); +DECLARE_SOA_COLUMN(MassDileptonCandidate, massDileptonCandidate, float); +DECLARE_SOA_COLUMN(deltaMassBcandidate, deltaMBcandidate, float); +DECLARE_SOA_COLUMN(pTBcandidate, PtBcandidate, float); +DECLARE_SOA_COLUMN(LxyBcandidate, lxyBcandidate, float); +DECLARE_SOA_COLUMN(LxyzBcandidate, lxyzBcandidate, float); +DECLARE_SOA_COLUMN(LzBcandidate, lzBcandidate, float); +DECLARE_SOA_COLUMN(TauxyBcandidate, tauxyBcandidate, float); +DECLARE_SOA_COLUMN(TauzBcandidate, tauzBcandidate, float); +DECLARE_SOA_COLUMN(CosPBcandidate, cosPBcandidate, float); +DECLARE_SOA_COLUMN(Chi2Bcandidate, chi2Bcandidate, float); +DECLARE_SOA_COLUMN(DCAxyzBetweenProngs, dcaxyzBetweenProngs, float); +DECLARE_SOA_COLUMN(McFlag, mcFlag, int8_t); +DECLARE_SOA_BITMAP_COLUMN(IsJpsiFromBSelected, isJpsiFromBSelected, 32); +// Candidate columns for prompt-non-prompt JPsi separation +DECLARE_SOA_COLUMN(Massee, massee, float); +DECLARE_SOA_COLUMN(Ptee, ptee, float); +DECLARE_SOA_COLUMN(Lxyee, lxyee, float); +DECLARE_SOA_COLUMN(LxyeePoleMass, lxyeepolemass, float); +DECLARE_SOA_COLUMN(Lzee, lzee, float); +DECLARE_SOA_COLUMN(AmbiguousInBunchPairs, AmbiguousJpsiPairsInBunch, bool); +DECLARE_SOA_COLUMN(AmbiguousOutOfBunchPairs, AmbiguousJpsiPairsOutOfBunch, bool); +DECLARE_SOA_COLUMN(Corrassoc, corrassoc, bool); +} // namespace dqanalysisflags + +DECLARE_SOA_TABLE(EventCuts, "AOD", "DQANAEVCUTS", dqanalysisflags::IsEventSelected); //! joinable to ReducedEvents +DECLARE_SOA_TABLE(BarrelTrackCuts, "AOD", "DQANATRKCUTS", dqanalysisflags::IsBarrelSelected); //! joinable to ReducedTracksAssoc +DECLARE_SOA_TABLE(BarrelAmbiguities, "AOD", "DQBARRELAMB", dqanalysisflags::BarrelAmbiguityInBunch, dqanalysisflags::BarrelAmbiguityOutOfBunch); //! joinable to ReducedBarrelTracks +DECLARE_SOA_TABLE(MuonTrackCuts, "AOD", "DQANAMUONCUTS", dqanalysisflags::IsMuonSelected); //! joinable to ReducedMuonsAssoc +DECLARE_SOA_TABLE(MuonAmbiguities, "AOD", "DQMUONAMB", dqanalysisflags::MuonAmbiguityInBunch, dqanalysisflags::MuonAmbiguityOutOfBunch); //! joinable to ReducedMuonTracks +DECLARE_SOA_TABLE(Prefilter, "AOD", "DQPREFILTER", dqanalysisflags::IsBarrelSelectedPrefilter); //! joinable to ReducedTracksAssoc +DECLARE_SOA_TABLE(BmesonCandidates, "AOD", "DQBMESONS", + dqanalysisflags::massBcandidate, dqanalysisflags::MassDileptonCandidate, dqanalysisflags::deltaMassBcandidate, dqanalysisflags::pTBcandidate, + dqanalysisflags::LxyBcandidate, dqanalysisflags::LxyzBcandidate, dqanalysisflags::LzBcandidate, + dqanalysisflags::TauxyBcandidate, dqanalysisflags::TauzBcandidate, dqanalysisflags::DCAxyzBetweenProngs, + dqanalysisflags::CosPBcandidate, dqanalysisflags::Chi2Bcandidate, + dqanalysisflags::IsJpsiFromBSelected, dqanalysisflags::IsBarrelSelected, dqanalysisflags::McFlag); +DECLARE_SOA_TABLE(JPsieeCandidates, "AOD", "DQPSEUDOPROPER", dqanalysisflags::Massee, dqanalysisflags::Ptee, dqanalysisflags::Lxyee, dqanalysisflags::LxyeePoleMass, dqanalysisflags::Lzee, dqanalysisflags::AmbiguousInBunchPairs, dqanalysisflags::AmbiguousOutOfBunchPairs, dqanalysisflags::Corrassoc); +} // namespace o2::aod + +// Declarations of various short names +using MyEvents = soa::Join; +using MyEventsSelected = soa::Join; +using MyEventsVtxCov = soa::Join; +using MyEventsVtxCovSelected = soa::Join; +using MyEventsVtxCovSelectedQvector = soa::Join; +using MyEventsQvector = soa::Join; + +using MyBarrelTracks = soa::Join; +using MyBarrelTracksWithAmbiguities = soa::Join; +using MyBarrelTracksWithCov = soa::Join; +using MyBarrelTracksWithCovWithAmbiguities = soa::Join; +using MyBarrelTracksWithCovWithAmbiguitiesWithColl = soa::Join; +using MyDielectronCandidates = soa::Join; +using MyDitrackCandidates = soa::Join; +using MyDimuonCandidates = soa::Join; +using MyMuonTracks = soa::Join; +using MyMuonTracksWithCov = soa::Join; +using MyMuonTracksWithCovWithAmbiguities = soa::Join; +// using MyMuonTracksSelectedWithColl = soa::Join; + +// bit maps used for the Fill functions of the VarManager +constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended; +constexpr static uint32_t gkEventFillMapWithCov = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov; +// constexpr static uint32_t gkEventFillMapWithQvector = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventQvector; +// constexpr static uint32_t gkEventFillMapWithCovQvector = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov | VarManager::ObjTypes::ReducedEventQvector; +constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelPID; +constexpr static uint32_t gkTrackFillMapWithCov = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID; +constexpr static uint32_t gkTrackFillMapWithCovWithColl = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID | VarManager::ObjTypes::ReducedTrackCollInfo; +// constexpr static uint32_t gkTrackFillMapWithColl = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelPID | VarManager::ObjTypes::ReducedTrackCollInfo; + +constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra; +constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra | VarManager::ObjTypes::ReducedMuonCov; +// constexpr static uint32_t gkMuonFillMapWithColl = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra | VarManager::ObjTypes::ReducedMuonCollInfo; + +// Global function used to define needed histogram classes +void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups); // defines histograms for all tasks + +template +void PrintBitMap(TMap map, int nbits) +{ + for (int i = 0; i < nbits; i++) { + cout << ((map & (TMap(1) << i)) > 0 ? "1" : "0"); + } +} + +// Analysis task that produces event decisions and the Hash table used in event mixing +struct AnalysisEventSelection { + Produces eventSel; + OutputObj fOutputList{"output"}; + + Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; + Configurable fConfigEventCutsJSON{"cfgEventCutsJSON", "", "Additional event cuts specified in JSON format"}; + Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddEventMCHistogram{"cfgAddEventMCHistogram", "generator", "Comma separated list of histograms"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Add event histograms defined via JSON formatting (see HistogramsLibrary)"}; + + Configurable fConfigSplitCollisionsDeltaZ{"splitCollisionsDeltaZ", 1.0, "maximum delta-z (cm) between two collisions to consider them as split candidates"}; + Configurable fConfigSplitCollisionsDeltaBC{"splitCollisionsDeltaBC", 100, "maximum delta-BC between two collisions to consider them as split candidates; do not apply if value is negative"}; + Configurable fConfigCheckSplitCollisions{"checkSplitCollisions", false, "If true, run the split collision check and fill histograms"}; + + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + + HistogramManager* fHistMan = nullptr; + AnalysisCompositeCut* fEventCut; + + Service fCCDB; + o2::ccdb::CcdbApi fCCDBApi; + + std::map fSelMap; // key: reduced event global index, value: event selection decision + std::map> fBCCollMap; // key: global BC, value: vector of reduced event global indices + std::map fMetadataRCT, fHeader; + int fCurrentRun; + + void init(o2::framework::InitContext& context) + { + if (context.mOptions.get("processDummy")) { + return; + } + VarManager::SetDefaultVarNames(); + + fEventCut = new AnalysisCompositeCut(true); + TString eventCutStr = fConfigEventCuts.value; + if (eventCutStr != "") { + AnalysisCut* cut = dqcuts::GetAnalysisCut(eventCutStr.Data()); + if (cut != nullptr) { + fEventCut->AddCut(cut); + } + } + // Additional cuts via JSON + TString eventCutJSONStr = fConfigEventCutsJSON.value; + if (eventCutJSONStr != "") { + std::vector jsonCuts = dqcuts::GetCutsFromJSON(eventCutJSONStr.Data()); + for (auto& cutIt : jsonCuts) { + fEventCut->AddCut(cutIt); + } + } + + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill + + if (fConfigQA) { + fHistMan = new HistogramManager("analysisHistos", "", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + DefineHistograms(fHistMan, "Event_BeforeCuts;Event_AfterCuts;", fConfigAddEventHistogram.value.data()); + if (fConfigCheckSplitCollisions) { + DefineHistograms(fHistMan, "OutOfBunchCorrelations;SameBunchCorrelations;", ""); + } + DefineHistograms(fHistMan, "EventsMC", fConfigAddEventMCHistogram.value.data()); + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // aditional histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } + + fCurrentRun = -1; + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); + fCCDBApi.init(fConfigCcdbUrl.value); + } + + template + void runEventSelection(TEvents const& events, TEventsMC const& mcEvents) + { + if (events.size() > 0 && events.begin().runNumber() != fCurrentRun) { + fHeader = fCCDBApi.retrieveHeaders(Form("RCT/Info/RunInformation/%i", events.begin().runNumber()), fMetadataRCT, -1); + uint64_t sor = std::atol(fHeader["SOR"].c_str()); + uint64_t eor = std::atol(fHeader["EOR"].c_str()); + VarManager::SetSORandEOR(sor, eor); + } + + fSelMap.clear(); + fBCCollMap.clear(); + + for (auto& event : events) { + // Reset the fValues array and fill event observables + VarManager::ResetValues(0, VarManager::kNEventWiseVariables); + VarManager::FillEvent(event); + if (event.has_reducedMCevent()) { + VarManager::FillEvent(event.reducedMCevent()); + } + + bool decision = false; + // if QA is requested fill histograms before event selections + if (fConfigQA) { + fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); // automatically fill all the histograms in the class Event + } + if (fEventCut->IsSelected(VarManager::fgValues)) { + if (fConfigQA) { + fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); + } + decision = true; + } + fSelMap[event.globalIndex()] = decision; + if (fBCCollMap.find(event.globalBC()) == fBCCollMap.end()) { + std::vector evIndices = {event.globalIndex()}; + fBCCollMap[event.globalBC()] = evIndices; + } else { + auto& evIndices = fBCCollMap[event.globalBC()]; + evIndices.push_back(event.globalIndex()); + } + } + + for (auto& event : mcEvents) { + // Reset the fValues array and fill event observables + VarManager::ResetValues(0, VarManager::kNEventWiseVariables); + VarManager::FillEvent(event); + if (fConfigQA) { + fHistMan->FillHistClass("EventsMC", VarManager::fgValues); + } + } + } + + template + void publishSelections(TEvents const& events) + { + std::map collisionSplittingMap; // key: event global index, value: whether pileup event is a possible splitting + + // Reset the fValues array and fill event observables + VarManager::ResetValues(0, VarManager::kNEventWiseVariables); + // loop over the BC map, get the collision vectors and make in-bunch and out of bunch 2-event correlations + for (auto bc1It = fBCCollMap.begin(); bc1It != fBCCollMap.end(); ++bc1It) { + uint64_t bc1 = bc1It->first; + auto bc1Events = bc1It->second; + + // same bunch event correlations, if more than 1 collisions in this bunch + if (bc1Events.size() > 1) { + for (auto ev1It = bc1Events.begin(); ev1It != bc1Events.end(); ++ev1It) { + auto ev1 = events.rawIteratorAt(*ev1It); + for (auto ev2It = std::next(ev1It); ev2It != bc1Events.end(); ++ev2It) { + auto ev2 = events.rawIteratorAt(*ev2It); + // compute 2-event quantities and mark the candidate split collisions + VarManager::FillTwoEvents(ev1, ev2); + if (TMath::Abs(VarManager::fgValues[VarManager::kTwoEvDeltaZ]) < fConfigSplitCollisionsDeltaZ) { // this is a possible collision split + collisionSplittingMap[*ev1It] = true; + collisionSplittingMap[*ev2It] = true; + } + fHistMan->FillHistClass("SameBunchCorrelations", VarManager::fgValues); + } // end second event loop + } // end first event loop + } // end if BC1 events > 1 + + // loop over the following BCs in the TF + for (auto bc2It = std::next(bc1It); bc2It != fBCCollMap.end(); ++bc2It) { + uint64_t bc2 = bc2It->first; + if ((bc2 > bc1 ? bc2 - bc1 : bc1 - bc2) > fConfigSplitCollisionsDeltaBC) { + continue; + } + auto bc2Events = bc2It->second; + + // loop over events in the first BC + for (auto ev1It : bc1Events) { + auto ev1 = events.rawIteratorAt(ev1It); + // loop over events in the second BC + for (auto ev2It : bc2Events) { + auto ev2 = events.rawIteratorAt(ev2It); + // compute 2-event quantities and mark the candidate split collisions + VarManager::FillTwoEvents(ev1, ev2); + if (TMath::Abs(VarManager::fgValues[VarManager::kTwoEvDeltaZ]) < fConfigSplitCollisionsDeltaZ) { // this is a possible collision split + collisionSplittingMap[ev1It] = true; + collisionSplittingMap[ev2It] = true; + } + fHistMan->FillHistClass("OutOfBunchCorrelations", VarManager::fgValues); + } + } + } + } + + // publish the table + uint32_t evSel = static_cast(0); + for (auto& event : events) { + evSel = 0; + if (fSelMap[event.globalIndex()]) { // event passed the user cuts + evSel |= (static_cast(1) << 0); + } + std::vector sameBunchEvents = fBCCollMap[event.globalBC()]; + if (sameBunchEvents.size() > 1) { // event with in-bunch pileup + evSel |= (static_cast(1) << 1); + } + if (collisionSplittingMap.find(event.globalIndex()) != collisionSplittingMap.end()) { // event with possible fake in-bunch pileup (collision splitting) + evSel |= (static_cast(1) << 2); + } + eventSel(evSel); + } + } + + void processSkimmed(MyEvents const& events, aod::ReducedMCEvents const& mcEvents) + { + runEventSelection(events, mcEvents); + publishSelections(events); + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisEventSelection, processSkimmed, "Run event selection on DQ skimmed events", false); + PROCESS_SWITCH(AnalysisEventSelection, processDummy, "Dummy function", false); +}; + +// Produces a table with barrel track decisions (joinable to the ReducedTracksAssociations) +// Here one should add all the track cuts needed through the workflow (e.g. cuts for same-even pairing, electron prefiltering, track for dilepton-track correlations) +struct AnalysisTrackSelection { + Produces trackSel; + Produces trackAmbiguities; + OutputObj fOutputList{"output"}; + + Configurable fConfigCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; + Configurable fConfigCutsJSON{"cfgBarrelTrackCutsJSON", "", "Additional list of barrel track cuts in JSON format"}; + Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + Configurable fConfigPublishAmbiguity{"cfgPublishAmbiguity", true, "If true, publish ambiguity table and fill QA histograms"}; + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable fConfigCcdbPathTPC{"ccdb-path-tpc", "Users/z/zhxiong/TPCPID/PostCalib", "base path to the ccdb object"}; + Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable fConfigComputeTPCpostCalib{"cfgTPCpostCalib", false, "If true, compute TPC post-calibrated n-sigmas"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable fConfigDummyRunlist{"cfgDummyRunlist", false, "If true, use dummy runlist"}; + Configurable fConfigInitRunNumber{"cfgInitRunNumber", 543215, "Initial run number used in run by run checks"}; + + Configurable fConfigMCSignals{"cfgTrackMCSignals", "", "Comma separated list of MC signals"}; + Configurable fConfigMCSignalsJSON{"cfgTrackMCsignalsJSON", "", "Additional list of MC signals via JSON"}; + + Service fCCDB; + + HistogramManager* fHistMan; + std::vector fTrackCuts; + std::vector fMCSignals; // list of signals to be checked + std::vector fHistNamesReco; + std::vector fHistNamesMCMatched; + + int fCurrentRun; // current run (needed to detect run changes for loading CCDB parameters) + + std::map> fNAssocsInBunch; // key: track global index, value: vector of global index for events associated in-bunch (events that have in-bunch pileup or splitting) + std::map> fNAssocsOutOfBunch; // key: track global index, value: vector of global index for events associated out-of-bunch (events that have no in-bunch pileup) + + void init(o2::framework::InitContext& context) + { + if (context.mOptions.get("processDummy")) { + return; + } + VarManager::SetDefaultVarNames(); + + fCurrentRun = 0; + TString cutNamesStr = fConfigCuts.value; + if (!cutNamesStr.IsNull()) { + std::unique_ptr objArray(cutNamesStr.Tokenize(",")); + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + fTrackCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + } + } + // add extra cuts from JSON + TString addTrackCutsStr = fConfigCutsJSON.value; + if (addTrackCutsStr != "") { + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + for (auto& t : addTrackCuts) { + fTrackCuts.push_back((AnalysisCompositeCut*)t); + } + } + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill + + TString configSigNamesStr = fConfigMCSignals.value; + std::unique_ptr sigNamesArray(configSigNamesStr.Tokenize(",")); + // Setting the MC signals + for (int isig = 0; isig < sigNamesArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(sigNamesArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() != 1) { // NOTE: only 1 prong signals + continue; + } + fMCSignals.push_back(sig); + } + } + // Add the MCSignals from the JSON config + TString addMCSignalsStr = fConfigMCSignalsJSON.value; + if (addMCSignalsStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); + for (auto& mcIt : addMCSignals) { + if (mcIt->GetNProngs() != 1) { // NOTE: only 1 prong signals + continue; + } + fMCSignals.push_back(mcIt); + } + } + + if (fConfigQA) { + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + // Configure histogram classes for each track cut; + // Add histogram classes for each track cut and for each requested MC signal (reconstructed tracks with MC truth) + TString histClasses = "AssocsBarrel_BeforeCuts;"; + for (auto& cut : fTrackCuts) { + TString nameStr = Form("AssocsBarrel_%s", cut->GetName()); + fHistNamesReco.push_back(nameStr); + histClasses += Form("%s;", nameStr.Data()); + for (auto& sig : fMCSignals) { + TString nameStr2 = Form("AssocsCorrectBarrel_%s_%s", cut->GetName(), sig->GetName()); + fHistNamesMCMatched.push_back(nameStr2); + histClasses += Form("%s;", nameStr2.Data()); + nameStr2 = Form("AssocsIncorrectBarrel_%s_%s", cut->GetName(), sig->GetName()); + fHistNamesMCMatched.push_back(nameStr2); + histClasses += Form("%s;", nameStr2.Data()); + } + } + + DefineHistograms(fHistMan, histClasses.Data(), fConfigAddTrackHistogram.value.data()); + if (fConfigPublishAmbiguity) { + DefineHistograms(fHistMan, "TrackBarrel_AmbiguityInBunch;TrackBarrel_AmbiguityOutOfBunch;", "ambiguity"); + } + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } + + if (fConfigDummyRunlist) { + VarManager::SetDummyRunlist(fConfigInitRunNumber); + } + if (fConfigComputeTPCpostCalib) { + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); + } + } + + template + void runTrackSelection(ReducedTracksAssoc const& assocs, TEvents const& events, TTracks const& tracks, TEventsMC const& /*eventsMC*/, TTracksMC const& tracksMC) + { + fNAssocsInBunch.clear(); + fNAssocsOutOfBunch.clear(); + + // TODO: Check if postcalibration needed for MC + if (events.size() > 0 && fCurrentRun != events.begin().runNumber()) { + if (fConfigComputeTPCpostCalib) { + auto calibList = fCCDB->getForTimeStamp(fConfigCcdbPathTPC.value, events.begin().timestamp()); + VarManager::SetCalibrationObject(VarManager::kTPCElectronMean, calibList->FindObject("mean_map_electron")); + VarManager::SetCalibrationObject(VarManager::kTPCElectronSigma, calibList->FindObject("sigma_map_electron")); + VarManager::SetCalibrationObject(VarManager::kTPCPionMean, calibList->FindObject("mean_map_pion")); + VarManager::SetCalibrationObject(VarManager::kTPCPionSigma, calibList->FindObject("sigma_map_pion")); + VarManager::SetCalibrationObject(VarManager::kTPCProtonMean, calibList->FindObject("mean_map_proton")); + VarManager::SetCalibrationObject(VarManager::kTPCProtonSigma, calibList->FindObject("sigma_map_proton")); + } + + o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(grpmagPath, events.begin().timestamp()); + if (grpmag != nullptr) { + VarManager::SetMagneticField(grpmag->getNominalL3Field()); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", events.begin().timestamp()); + } + + fCurrentRun = events.begin().runNumber(); + } + + trackSel.reserve(assocs.size()); + trackAmbiguities.reserve(tracks.size()); + + // Loop over associations + for (auto& assoc : assocs) { + auto event = assoc.template reducedevent_as(); + if (!event.isEventSelected_bit(0)) { + trackSel(0); + continue; + } + + VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); + // fill event information which might be needed in histograms/cuts that combine track and event properties + VarManager::FillEvent(event); + ReducedMCEvent* eventMC = nullptr; + if (event.has_reducedMCevent()) { + auto eventMC = event.reducedMCevent(); + VarManager::FillEvent(eventMC); + } + + auto track = assoc.template reducedtrack_as(); + VarManager::FillTrack(track); + // compute quantities which depend on the associated collision, such as DCA + VarManager::FillTrackCollision(track, event); + + bool isCorrectAssoc = false; + if (track.has_reducedMCTrack()) { + auto trackMC = track.reducedMCTrack(); + auto eventMCfromTrack = trackMC.reducedMCevent(); + if (eventMC != nullptr) { + isCorrectAssoc = (eventMCfromTrack.globalIndex() == eventMC->globalIndex()); + } + VarManager::FillTrackMC(tracksMC, trackMC); + } + + if (fConfigQA) { + fHistMan->FillHistClass("AssocsBarrel_BeforeCuts", VarManager::fgValues); + } + + int iCut = 0; + uint32_t filterMap = static_cast(0); + for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, iCut++) { + if ((*cut)->IsSelected(VarManager::fgValues)) { + filterMap |= (static_cast(1) << iCut); + if (fConfigQA) { + fHistMan->FillHistClass(fHistNamesReco[iCut], VarManager::fgValues); + } + } + } // end loop over cuts + trackSel(filterMap); + + // compute MC matching decisions and fill histograms for matched associations + int isig = 0; + if (filterMap > 0 && track.has_reducedMCTrack()) { + // loop over all MC signals + for (auto sig = fMCSignals.begin(); sig != fMCSignals.end(); sig++, isig++) { + // check if this MC signal is matched + if ((*sig)->CheckSignal(true, track.reducedMCTrack())) { + // mcDecision |= (static_cast(1) << isig); + // loop over cuts and fill histograms for the cuts that are fulfilled + for (unsigned int icut = 0; icut < fTrackCuts.size(); icut++) { + if (filterMap & (static_cast(1) << icut)) { + if (isCorrectAssoc) { + fHistMan->FillHistClass(fHistNamesMCMatched[icut * 2 * fMCSignals.size() + 2 * isig].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(fHistNamesMCMatched[icut * 2 * fMCSignals.size() + 2 * isig + 1].Data(), VarManager::fgValues); + } + } + } // end loop over cuts + } + } + + // fill histograms + /*for (unsigned int i = 0; i < fMCSignals.size(); i++) { + if (!(mcDecision & (static_cast(1) << i))) { + continue; + } + for (unsigned int j = 0; j < fTrackCuts.size(); j++) { + if (filterMap & (static_cast(1) << j)) { + if (isCorrectAssoc) { + fHistMan->FillHistClass(fHistNamesMCMatched[j * fMCSignals.size() + 2 * i].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(fHistNamesMCMatched[j * fMCSignals.size() + 2 * i + 1].Data(), VarManager::fgValues); + } + } + } // end loop over cuts + } // end loop over MC signals + */ + } // end if (filterMap > 0) + + // count the number of associations per track + if (fConfigPublishAmbiguity && filterMap > 0) { + if (event.isEventSelected_bit(1)) { + // for this track, count the number of associated collisions with in-bunch pileup and out of bunch associations + if (fNAssocsInBunch.find(track.globalIndex()) == fNAssocsInBunch.end()) { + std::vector evVector = {event.globalIndex()}; + fNAssocsInBunch[track.globalIndex()] = evVector; + } else { + auto& evVector = fNAssocsInBunch[track.globalIndex()]; + evVector.push_back(event.globalIndex()); + } + } else { + if (fNAssocsOutOfBunch.find(track.globalIndex()) == fNAssocsOutOfBunch.end()) { + std::vector evVector = {event.globalIndex()}; + fNAssocsOutOfBunch[track.globalIndex()] = evVector; + } else { + auto& evVector = fNAssocsOutOfBunch[track.globalIndex()]; + evVector.push_back(event.globalIndex()); + } + } + } + } // end loop over associations + + // QA the collision-track associations + // TODO: some tracks can be associated to both collisions that have in bunch pileup and collisions from different bunches + // So one could QA these tracks separately + if (fConfigPublishAmbiguity) { + if (fConfigQA) { + for (auto& [trackIdx, evIndices] : fNAssocsInBunch) { + if (evIndices.size() == 1) { + continue; + } + auto track = tracks.rawIteratorAt(trackIdx); + VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); + VarManager::FillTrack(track); + VarManager::fgValues[VarManager::kBarrelNAssocsInBunch] = static_cast(evIndices.size()); + fHistMan->FillHistClass("TrackBarrel_AmbiguityInBunch", VarManager::fgValues); + } // end loop over in-bunch ambiguous tracks + + for (auto& [trackIdx, evIndices] : fNAssocsOutOfBunch) { + if (evIndices.size() == 1) { + continue; + } + auto track = tracks.rawIteratorAt(trackIdx); + VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); + VarManager::FillTrack(track); + VarManager::fgValues[VarManager::kBarrelNAssocsOutOfBunch] = static_cast(evIndices.size()); + fHistMan->FillHistClass("TrackBarrel_AmbiguityOutOfBunch", VarManager::fgValues); + } // end loop over out-of-bunch ambiguous tracks + } + + // publish the ambiguity table + for (auto& track : tracks) { + int8_t nInBunch = 0; + if (fNAssocsInBunch.find(track.globalIndex()) != fNAssocsInBunch.end()) { + nInBunch = fNAssocsInBunch[track.globalIndex()].size(); + } + int8_t nOutOfBunch = 0; + if (fNAssocsOutOfBunch.find(track.globalIndex()) != fNAssocsOutOfBunch.end()) { + nOutOfBunch = fNAssocsOutOfBunch[track.globalIndex()].size(); + } + trackAmbiguities(nInBunch, nOutOfBunch); + } + } + } // end runTrackSelection() + + void processSkimmed(ReducedTracksAssoc const& assocs, MyEventsSelected const& events, MyBarrelTracks const& tracks, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) + { + runTrackSelection(assocs, events, tracks, eventsMC, tracksMC); + } + void processSkimmedWithCov(ReducedTracksAssoc const& assocs, MyEventsVtxCovSelected const& events, MyBarrelTracksWithCov const& tracks, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) + { + runTrackSelection(assocs, events, tracks, eventsMC, tracksMC); + } + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisTrackSelection, processSkimmed, "Run barrel track selection on DQ skimmed track associations", false); + PROCESS_SWITCH(AnalysisTrackSelection, processSkimmedWithCov, "Run barrel track selection on DQ skimmed tracks w/ cov matrix associations", false); + PROCESS_SWITCH(AnalysisTrackSelection, processDummy, "Dummy function", false); +}; + +// Produces a table with muon decisions (joinable to the ReducedMuonsAssociations) +// Here one should add all the track cuts needed through the workflow (e.g. cuts for same-event pairing, track for dilepton-track correlations) +struct AnalysisMuonSelection { + Produces muonSel; + Produces muonAmbiguities; + OutputObj fOutputList{"output"}; + + Configurable fConfigCuts{"cfgMuonCuts", "muonQualityCuts", "Comma separated list of muon cuts"}; + Configurable fConfigCutsJSON{"cfgMuonCutsJSON", "", "Additional list of muon cuts in JSON format"}; + Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigAddMuonHistogram{"cfgAddMuonHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + Configurable fConfigPublishAmbiguity{"cfgPublishAmbiguity", true, "If true, publish ambiguity table and fill QA histograms"}; + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable fConfigGeoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + + Configurable fConfigMCSignals{"cfgMuonMCSignals", "", "Comma separated list of MC signals"}; + Configurable fConfigMCSignalsJSON{"cfgMuonMCsignalsJSON", "", "Additional list of MC signals via JSON"}; + + Service fCCDB; + + HistogramManager* fHistMan; + std::vector fMuonCuts; + std::vector fHistNamesReco; + std::vector fHistNamesMCMatched; + std::vector fMCSignals; // list of signals to be checked + + int fCurrentRun; // current run kept to detect run changes and trigger loading params from CCDB + + std::map> fNAssocsInBunch; // key: track global index, value: vector of global index for events associated in-bunch (events that have in-bunch pileup or splitting) + std::map> fNAssocsOutOfBunch; // key: track global index, value: vector of global index for events associated out-of-bunch (events that have no in-bunch pileup) + + void init(o2::framework::InitContext& context) + { + if (context.mOptions.get("processDummy")) { + return; + } + VarManager::SetDefaultVarNames(); + + fCurrentRun = 0; + TString cutNamesStr = fConfigCuts.value; + if (!cutNamesStr.IsNull()) { + std::unique_ptr objArray(cutNamesStr.Tokenize(",")); + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + fMuonCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + } + } + // Add cuts configured via JSON + TString addCutsStr = fConfigCutsJSON.value; + if (addCutsStr != "") { + std::vector addCuts = dqcuts::GetCutsFromJSON(addCutsStr.Data()); + for (auto& t : addCuts) { + fMuonCuts.push_back((AnalysisCompositeCut*)t); + } + } + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill + + TString configSigNamesStr = fConfigMCSignals.value; + std::unique_ptr sigNamesArray(configSigNamesStr.Tokenize(",")); + // Setting the MC signals + for (int isig = 0; isig < sigNamesArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(sigNamesArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() != 1) { // NOTE: only 1 prong signals + continue; + } + fMCSignals.push_back(sig); + } + } + // Add the MCSignals from the JSON config + TString addMCSignalsStr = fConfigMCSignalsJSON.value; + if (addMCSignalsStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); + for (auto& mcIt : addMCSignals) { + if (mcIt->GetNProngs() != 1) { // NOTE: only 1 prong signals + continue; + } + fMCSignals.push_back(mcIt); + } + } + + if (fConfigQA) { + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + // Configure histogram classes for each track cut; + // Add histogram classes for each track cut and for each requested MC signal (reconstructed tracks with MC truth) + TString histClasses = "AssocsMuon_BeforeCuts;"; + for (auto& cut : fMuonCuts) { + TString nameStr = Form("AssocsMuon_%s", cut->GetName()); + fHistNamesReco.push_back(nameStr); + histClasses += Form("%s;", nameStr.Data()); + for (auto& sig : fMCSignals) { + TString nameStr2 = Form("AssocsCorrectMuon_%s_%s", cut->GetName(), sig->GetName()); + fHistNamesMCMatched.push_back(nameStr2); + histClasses += Form("%s;", nameStr2.Data()); + nameStr2 = Form("AssocsIncorrectMuon_%s_%s", cut->GetName(), sig->GetName()); + fHistNamesMCMatched.push_back(nameStr2); + histClasses += Form("%s;", nameStr2.Data()); + } + } + if (fConfigPublishAmbiguity) { + histClasses += "Muon_AmbiguityInBunch;Muon_AmbiguityOutOfBunch;"; + } + + DefineHistograms(fHistMan, histClasses.Data(), fConfigAddMuonHistogram.value.data()); // define all histograms + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } + + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); + if (!o2::base::GeometryManager::isGeometryLoaded()) { + fCCDB->get(fConfigGeoPath); + } + } + + template + void runMuonSelection(ReducedMuonsAssoc const& assocs, TEvents const& events, TMuons const& muons, ReducedMCEvents const& /*eventsMC*/, ReducedMCTracks const& muonsMC) + { + if (events.size() > 0 && fCurrentRun != events.begin().runNumber()) { + o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(grpmagPath, events.begin().timestamp()); + if (grpmag != nullptr) { + o2::base::Propagator::initFieldFromGRP(grpmag); + VarManager::SetMagneticField(grpmag->getNominalL3Field()); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", events.begin().timestamp()); + } + fCurrentRun = events.begin().runNumber(); + } + + fNAssocsInBunch.clear(); + fNAssocsOutOfBunch.clear(); + muonSel.reserve(assocs.size()); + + for (auto& assoc : assocs) { + auto event = assoc.template reducedevent_as(); + if (!event.isEventSelected_bit(0)) { + muonSel(0); + continue; + } + VarManager::ResetValues(0, VarManager::kNVars); + // fill event information which might be needed in histograms/cuts that combine track and event properties + VarManager::FillEvent(event); + VarManager::FillEvent(event.reducedMCevent()); + + auto track = assoc.template reducedmuon_as(); + VarManager::FillTrack(track); + + bool isCorrectAssoc = false; + if (track.has_reducedMCTrack()) { + auto trackMC = track.reducedMCTrack(); + auto eventMCfromTrack = trackMC.reducedMCevent(); + isCorrectAssoc = (eventMCfromTrack.globalIndex() == event.reducedMCevent().globalIndex()); + VarManager::FillTrackMC(muonsMC, trackMC); + } + + if (fConfigQA) { + fHistMan->FillHistClass("AssocsMuon_BeforeCuts", VarManager::fgValues); + } + + int iCut = 0; + uint32_t filterMap = static_cast(0); + for (auto cut = fMuonCuts.begin(); cut != fMuonCuts.end(); cut++, iCut++) { + if ((*cut)->IsSelected(VarManager::fgValues)) { + filterMap |= (static_cast(1) << iCut); + if (fConfigQA) { + fHistMan->FillHistClass(fHistNamesReco[iCut].Data(), VarManager::fgValues); + } + } + } // end loop over cuts + muonSel(filterMap); + muonAmbiguities.reserve(muons.size()); + + // if no filter fulfilled, continue + if (!filterMap) { + continue; + } + + // everything below is related to filling QA histograms + if (!fConfigQA) { + continue; + } + + // compute MC matching decisions + uint32_t mcDecision = static_cast(0); + int isig = 0; + for (auto sig = fMCSignals.begin(); sig != fMCSignals.end(); sig++, isig++) { + if constexpr ((TMuonFillMap & VarManager::ObjTypes::ReducedMuon) > 0) { + if (track.has_reducedMCTrack()) { + if ((*sig)->CheckSignal(true, track.reducedMCTrack())) { + mcDecision |= (static_cast(1) << isig); + } + } + } + } + + // fill histograms + for (unsigned int i = 0; i < fMCSignals.size(); i++) { + if (!(mcDecision & (static_cast(1) << i))) { + continue; + } + for (unsigned int j = 0; j < fMuonCuts.size(); j++) { + if (filterMap & (static_cast(1) << j)) { + if (isCorrectAssoc) { + fHistMan->FillHistClass(fHistNamesMCMatched[j * 2 * fMCSignals.size() + 2 * i].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(fHistNamesMCMatched[j * 2 * fMCSignals.size() + 2 * i + 1].Data(), VarManager::fgValues); + } + } + } // end loop over cuts + } // end loop over MC signals + + // count the number of associations per track + if (fConfigPublishAmbiguity && filterMap > 0) { + if (event.isEventSelected_bit(1)) { + if (fNAssocsInBunch.find(track.globalIndex()) == fNAssocsInBunch.end()) { + std::vector evVector = {event.globalIndex()}; + fNAssocsInBunch[track.globalIndex()] = evVector; + } else { + auto& evVector = fNAssocsInBunch[track.globalIndex()]; + evVector.push_back(event.globalIndex()); + } + } else { + if (fNAssocsOutOfBunch.find(track.globalIndex()) == fNAssocsOutOfBunch.end()) { + std::vector evVector = {event.globalIndex()}; + fNAssocsOutOfBunch[track.globalIndex()] = evVector; + } else { + auto& evVector = fNAssocsOutOfBunch[track.globalIndex()]; + evVector.push_back(event.globalIndex()); + } + } + } + } // end loop over assocs + + // QA the collision-track associations + // TODO: some tracks can be associated to both collisions that have in bunch pileup and collisions from different bunches + // So one could QA these tracks separately + if (fConfigPublishAmbiguity) { + for (auto& [trackIdx, evIndices] : fNAssocsInBunch) { + if (evIndices.size() == 1) { + continue; + } + auto track = muons.rawIteratorAt(trackIdx); + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillTrack(track); + VarManager::fgValues[VarManager::kMuonNAssocsInBunch] = static_cast(evIndices.size()); + fHistMan->FillHistClass("Muon_AmbiguityInBunch", VarManager::fgValues); + } // end loop over in-bunch ambiguous tracks + + for (auto& [trackIdx, evIndices] : fNAssocsOutOfBunch) { + if (evIndices.size() == 1) { + continue; + } + auto track = muons.rawIteratorAt(trackIdx); + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillTrack(track); + VarManager::fgValues[VarManager::kMuonNAssocsOutOfBunch] = static_cast(evIndices.size()); + fHistMan->FillHistClass("Muon_AmbiguityOutOfBunch", VarManager::fgValues); + } // end loop over out-of-bunch ambiguous tracks + + // publish the ambiguity table + for (auto& track : muons) { + int8_t nInBunch = 0; + if (fNAssocsInBunch.find(track.globalIndex()) != fNAssocsInBunch.end()) { + nInBunch = fNAssocsInBunch[track.globalIndex()].size(); + } + int8_t nOutOfBunch = 0; + if (fNAssocsOutOfBunch.find(track.globalIndex()) != fNAssocsOutOfBunch.end()) { + nOutOfBunch = fNAssocsOutOfBunch[track.globalIndex()].size(); + } + muonAmbiguities(nInBunch, nOutOfBunch); + } + } + } + + void processSkimmed(ReducedMuonsAssoc const& assocs, MyEventsSelected const& events, MyMuonTracks const& muons, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) + { + runMuonSelection(assocs, events, muons, eventsMC, tracksMC); + } + void processSkimmedWithCov(ReducedMuonsAssoc const& assocs, MyEventsVtxCovSelected const& events, MyMuonTracksWithCov const& muons, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) + { + runMuonSelection(assocs, events, muons, eventsMC, tracksMC); + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisMuonSelection, processSkimmed, "Run muon selection on DQ skimmed muons", false); + PROCESS_SWITCH(AnalysisMuonSelection, processSkimmedWithCov, "Run muon selection on DQ skimmed muons, with event and track covariances", false); + PROCESS_SWITCH(AnalysisMuonSelection, processDummy, "Dummy function", false); +}; + +// Run the prefilter selection (e.g. electron prefiltering for photon conversions) +// This takes uses a sample of tracks selected with loose cuts (fConfigPrefilterTrackCut) and combines them +// with the sample of tracks to be used in downstream analysis (fConfigTrackCuts). If a pair is found to pass +// the pair prefilter cut (cfgPrefilterPairCut), the analysis track is tagged to be removed from analysis. +// TODO: Add optional QA histograms +struct AnalysisPrefilterSelection { + Produces prefilter; // joinable with ReducedTracksAssoc + + // Configurables + Configurable fConfigPrefilterTrackCut{"cfgPrefilterTrackCut", "", "Prefilter track cut"}; + Configurable fConfigPrefilterPairCut{"cfgPrefilterPairCut", "", "Prefilter pair cut"}; + Configurable fConfigTrackCuts{"cfgTrackCuts", "", "Track cuts for which to run the prefilter"}; + // Track related options + Configurable fPropTrack{"cfgPropTrack", false, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; + + std::map fPrefilterMap; + AnalysisCompositeCut* fPairCut; + uint32_t fPrefilterMask; + int fPrefilterCutBit; + + Preslice trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + + void init(o2::framework::InitContext& context) + { + if (context.mOptions.get("processDummy")) { + return; + } + + bool runPrefilter = true; + // get the list of track cuts to be prefiltered + TString trackCutsStr = fConfigTrackCuts.value; + TObjArray* objArrayTrackCuts = nullptr; + if (!trackCutsStr.IsNull()) { + objArrayTrackCuts = trackCutsStr.Tokenize(","); + if (objArrayTrackCuts == nullptr) { + runPrefilter = false; + } + } else { + LOG(warn) << " No track cuts to prefilter! Prefilter will not be run"; + runPrefilter = false; + } + // get the cut to be used as loose selection + TString prefilterTrackCutStr = fConfigPrefilterTrackCut.value; + if (prefilterTrackCutStr.IsNull()) { + LOG(warn) << " No prefilter loose selection specified! Prefilter will not be run"; + runPrefilter = false; + } + + fPrefilterMask = 0; + fPrefilterCutBit = -1; + if (runPrefilter) { + // get the list of cuts that were computed in the barrel track-selection task and create a bit mask + // to mark just the ones we want to apply a prefilter on + string trackCuts; + getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", trackCuts, false); + TString allTrackCutsStr = trackCuts; + // check also the cuts added via JSON and add them to the string of cuts + getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", trackCuts, false); + TString addTrackCutsStr = trackCuts; + if (addTrackCutsStr != "") { + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + for (auto& t : addTrackCuts) { + allTrackCutsStr += Form(",%s", t->GetName()); + } + } + + std::unique_ptr objArray(allTrackCutsStr.Tokenize(",")); + if (objArray == nullptr) { + LOG(fatal) << " Not getting any track cuts from the barrel-track-selection "; + } + if (objArray->FindObject(prefilterTrackCutStr.Data()) == nullptr) { + LOG(fatal) << " Prefilter track cut not among the cuts calculated by the track-selection task! "; + } + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + TString tempStr = objArray->At(icut)->GetName(); + if (objArrayTrackCuts->FindObject(tempStr.Data()) != nullptr) { + fPrefilterMask |= (static_cast(1) << icut); + } + if (tempStr.CompareTo(fConfigPrefilterTrackCut.value) == 0) { + fPrefilterCutBit = icut; + } + } + // setup the prefilter pair cut + fPairCut = new AnalysisCompositeCut(true); + TString pairCutStr = fConfigPrefilterPairCut.value; + if (!pairCutStr.IsNull()) { + fPairCut = dqcuts::GetCompositeCut(pairCutStr.Data()); + } + } + if (fPrefilterMask == static_cast(0) || fPrefilterCutBit < 0) { + LOG(warn) << "No specified loose cut or track cuts for prefiltering. This task will do nothing."; + } + + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill + VarManager::SetDefaultVarNames(); + + VarManager::SetupTwoProngDCAFitter(5.0f, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, true); // TODO: get these parameters from Configurables + VarManager::SetupTwoProngFwdDCAFitter(5.0f, true, 200.0f, 1.0e-3f, 0.9f, true); + } + + template + void runPrefilter(TEvent const& event, soa::Join const& assocs, TTracks const& /*tracks*/) + { + if (fPrefilterCutBit < 0 || fPrefilterMask == 0) { + return; + } + + for (auto& [assoc1, assoc2] : o2::soa::combinations(assocs, assocs)) { + auto track1 = assoc1.template reducedtrack_as(); + auto track2 = assoc2.template reducedtrack_as(); + + // NOTE: here we restrict to just pairs of opposite sign (conversions), but in principle this can be made + // a configurable and check also same-sign pairs (track splitting) + if (track1.sign() * track2.sign() > 0) { + continue; + } + + // here we check the cuts fulfilled by both tracks, for both the tight and loose selections + uint32_t track1Candidate = (assoc1.isBarrelSelected_raw() & fPrefilterMask); + uint32_t track2Candidate = (assoc2.isBarrelSelected_raw() & fPrefilterMask); + bool track1Loose = assoc1.isBarrelSelected_bit(fPrefilterCutBit); + bool track2Loose = assoc2.isBarrelSelected_bit(fPrefilterCutBit); + + if (!((track1Candidate > 0 && track2Loose) || (track2Candidate > 0 && track1Loose))) { + continue; + } + + // compute pair quantities + VarManager::FillPair(track1, track2); + if (fPropTrack) { + VarManager::FillPairCollision(event, track1, track2); + } + // if the pair fullfils the criteria, add an entry into the prefilter map for the two tracks + if (fPairCut->IsSelected(VarManager::fgValues)) { + if (fPrefilterMap.find(track1.globalIndex()) == fPrefilterMap.end() && track1Candidate > 0) { + fPrefilterMap[track1.globalIndex()] = track1Candidate; + } + if (fPrefilterMap.find(track2.globalIndex()) == fPrefilterMap.end() && track2Candidate > 0) { + fPrefilterMap[track2.globalIndex()] = track2Candidate; + } + } + } // end loop over combinations + } + + void processBarrelSkimmed(MyEvents const& events, soa::Join const& assocs, MyBarrelTracks const& tracks) + { + + fPrefilterMap.clear(); + + for (auto& event : events) { + auto groupedAssocs = assocs.sliceBy(trackAssocsPerCollision, event.globalIndex()); + if (groupedAssocs.size() > 1) { + runPrefilter(event, groupedAssocs, tracks); + } + } + + uint32_t mymap = -1; + // If cuts were not configured, then produce a map with all 1's and publish it for all associations + if (fPrefilterCutBit < 0 || fPrefilterMask == 0) { + for (int i = 0; i < assocs.size(); ++i) { + prefilter(mymap); + } + } else { + for (auto& assoc : assocs) { + // TODO: just use the index from the assoc (no need to cast the whole track) + auto track = assoc.template reducedtrack_as(); + mymap = -1; + if (fPrefilterMap.find(track.globalIndex()) != fPrefilterMap.end()) { + // NOTE: publish the bitwise negated bits (~), so there will be zeroes for cuts that failed the prefiltering and 1 everywhere else + mymap = ~fPrefilterMap[track.globalIndex()]; + prefilter(mymap); + } else { + prefilter(mymap); // track did not pass the prefilter selections, so publish just 1's + } + } + } + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisPrefilterSelection, processBarrelSkimmed, "Run Prefilter selection on reduced tracks", false); + PROCESS_SWITCH(AnalysisPrefilterSelection, processDummy, "Do nothing", false); +}; + +// Run the same-event pairing +// This task assumes that both legs of the resonance fulfill the same cuts (symmetric decay channel) +// Runs combinatorics for barrel-barrel, muon-muon and barrel-muon combinations +// TODO: implement properly the barrel-muon combinations +// The task implements also process functions for running event mixing +struct AnalysisSameEventPairing { + + Produces dielectronList; + Produces dimuonList; + Produces dielectronsExtraList; + Produces dielectronInfoList; + Produces dimuonsExtraList; + Produces dimuonAllList; + Produces dileptonMiniTreeGen; + Produces dileptonMiniTreeRec; + Produces dileptonInfoList; + Produces PromptNonPromptSepTable; + + o2::base::MatLayerCylSet* fLUT = nullptr; + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + + OutputObj fOutputList{"output"}; + + struct : ConfigurableGroup { + Configurable track{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; + Configurable muon{"cfgMuonCuts", "", "Comma separated list of muon cuts"}; + Configurable pair{"cfgPairCuts", "", "Comma separated list of pair cuts, !!! Use only if you know what you are doing, otherwise leave empty"}; + // TODO: Add pair cuts via JSON + } fConfigCuts; + + Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigAddSEPHistogram{"cfgAddSEPHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + + struct : ConfigurableGroup { + Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpMagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + } fConfigCCDB; + + struct : ConfigurableGroup { + Configurable useRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; + Configurable magField{"cfgMagField", 5.0f, "Manually set magnetic field"}; + Configurable flatTables{"cfgFlatTables", false, "Produce a single flat tables with all relevant information of the pairs and single tracks"}; + Configurable useKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; + Configurable useAbsDCA{"cfgUseAbsDCA", false, "Use absolute DCA minimization instead of chi^2 minimization in secondary vertexing"}; + Configurable propToPCA{"cfgPropToPCA", false, "Propagate tracks to secondary vertex"}; + Configurable corrFullGeo{"cfgCorrFullGeo", false, "Use full geometry to correct for MCS effects in track propagation"}; + Configurable noCorr{"cfgNoCorrFwdProp", false, "Do not correct for MCS effects in track propagation"}; + Configurable collisionSystem{"syst", "pp", "Collision system, pp or PbPb"}; + Configurable centerMassEnergy{"energy", 13600, "Center of mass energy in GeV"}; + } fConfigOptions; + + struct : ConfigurableGroup { + Configurable genSignals{"cfgBarrelMCGenSignals", "", "Comma separated list of MC signals (generated)"}; + Configurable genSignalsJSON{"cfgMCGenSignalsJSON", "", "Additional list of MC signals (generated) via JSON"}; + Configurable recSignals{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; + Configurable recSignalsJSON{"cfgMCRecSignalsJSON", "", "Comma separated list of MC signals (reconstructed) via JSON"}; + Configurable skimSignalOnly{"cfgSkimSignalOnly", false, "Configurable to select only matched candidates"}; + Configurable runMCGenPair{"cfgRunMCGenPair", false, "Do pairing of true MC particles"}; + } fConfigMC; + + struct : ConfigurableGroup { + Configurable fConfigMiniTree{"useMiniTree.cfgMiniTree", false, "Produce a single flat table with minimal information for analysis"}; + Configurable fConfigMiniTreeMinMass{"useMiniTree.cfgMiniTreeMinMass", 2, "Min. mass cut for minitree"}; + Configurable fConfigMiniTreeMaxMass{"useMiniTree.cfgMiniTreeMaxMass", 5, "Max. mass cut for minitree"}; + } useMiniTree; + + // Track related options + Configurable fPropTrack{"cfgPropTrack", true, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; + + Service fCCDB; + + // Filter filterEventSelected = aod::dqanalysisflags::isEventSelected & uint32_t(1); + + HistogramManager* fHistMan; + + // keep histogram class names in maps, so we don't have to buld their names in the pair loops + std::map> fTrackHistNames; + std::map> fBarrelHistNamesMCmatched; + std::map> fMuonHistNames; + std::map> fMuonHistNamesMCmatched; + std::vector fRecMCSignals; + std::vector fGenMCSignals; + + std::vector fPairCuts; + + uint32_t fTrackFilterMask; // mask for the track cuts required in this task to be applied on the barrel cuts produced upstream + uint32_t fMuonFilterMask; // mask for the muon cuts required in this task to be applied on the muon cuts produced upstream + int fNCutsBarrel; + int fNCutsMuon; + int fNPairCuts; + bool fHasTwoProngGenMCsignals = false; + + bool fEnableBarrelHistos; + bool fEnableMuonHistos; + + Preslice> trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + Preslice> muonAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + + void init(o2::framework::InitContext& context) + { + if (context.mOptions.get("processDummy")) { + return; + } + VarManager::SetDefaultVarNames(); + + fEnableBarrelHistos = context.mOptions.get("processAllSkimmed") || context.mOptions.get("processBarrelOnlySkimmed") || context.mOptions.get("processBarrelOnlyWithCollSkimmed"); + fEnableMuonHistos = context.mOptions.get("processAllSkimmed") || context.mOptions.get("processMuonOnlySkimmed"); + + // Keep track of all the histogram class names to avoid composing strings in the pairing loop + TString histNames = ""; + TString cutNamesStr = fConfigCuts.pair.value; + if (!cutNamesStr.IsNull()) { + std::unique_ptr objArray(cutNamesStr.Tokenize(",")); + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + fPairCuts.push_back(*dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + } + } + + // get the list of cuts for tracks/muons, check that they were played by the barrel/muon selection tasks + // and make a mask for active cuts (barrel and muon selection tasks may run more cuts, needed for other analyses) + TString trackCutsStr = fConfigCuts.track.value; + TObjArray* objArrayTrackCuts = nullptr; + if (!trackCutsStr.IsNull()) { + objArrayTrackCuts = trackCutsStr.Tokenize(","); + } + TString muonCutsStr = fConfigCuts.muon.value; + TObjArray* objArrayMuonCuts = nullptr; + if (!muonCutsStr.IsNull()) { + objArrayMuonCuts = muonCutsStr.Tokenize(","); + } + + // Setting the MC rec signal names + TString sigNamesStr = fConfigMC.recSignals.value; + std::unique_ptr objRecSigArray(sigNamesStr.Tokenize(",")); + for (int isig = 0; isig < objRecSigArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objRecSigArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required + continue; + } + fRecMCSignals.push_back(sig); + } + } + + // Add the MCSignals from the JSON config + TString addMCSignalsStr = fConfigMC.recSignalsJSON.value; + if (addMCSignalsStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); + for (auto& mcIt : addMCSignals) { + if (mcIt->GetNProngs() != 2) { // NOTE: only 2 prong signals + continue; + } + fRecMCSignals.push_back(mcIt); + } + } + + // get the barrel track selection cuts + string tempCuts; + getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", tempCuts, false); + TString tempCutsStr = tempCuts; + // check also the cuts added via JSON and add them to the string of cuts + getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", tempCuts, false); + TString addTrackCutsStr = tempCuts; + if (addTrackCutsStr != "") { + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + for (auto& t : addTrackCuts) { + tempCutsStr += Form(",%s", t->GetName()); + } + } + + // check that the barrel track cuts array required in this task is not empty + if (!trackCutsStr.IsNull()) { + // tokenize and loop over the barrel cuts produced by the barrel track selection task + std::unique_ptr objArray(tempCutsStr.Tokenize(",")); + fNCutsBarrel = objArray->GetEntries(); + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + TString tempStr = objArray->At(icut)->GetName(); + // if the current barrel selection cut is required in this task, then switch on the corresponding bit in the mask + // and assign histogram directories + if (objArrayTrackCuts->FindObject(tempStr.Data()) != nullptr) { + fTrackFilterMask |= (static_cast(1) << icut); + + if (fEnableBarrelHistos) { + // assign the pair hist directories for the current cut + std::vector names = { + Form("PairsBarrelSEPM_%s", objArray->At(icut)->GetName()), + Form("PairsBarrelSEPP_%s", objArray->At(icut)->GetName()), + Form("PairsBarrelSEMM_%s", objArray->At(icut)->GetName())}; + if (fConfigQA) { + // assign separate hist directories for ambiguous tracks + names.push_back(Form("PairsBarrelSEPM_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsBarrelSEPP_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsBarrelSEMM_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsBarrelSEPM_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsBarrelSEPP_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsBarrelSEMM_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + } + for (auto& n : names) { + histNames += Form("%s;", n.Data()); + } + fTrackHistNames[icut] = names; + + // if there are pair cuts specified, assign hist directories for each barrel cut - pair cut combination + // NOTE: This could possibly lead to large histogram outputs. It is strongly advised to use pair cuts only + // if you know what you are doing. + TString cutNamesStr = fConfigCuts.pair.value; + if (!cutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + fNPairCuts = objArrayPair->GetEntries(); + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts + names = { + Form("PairsBarrelSEPM_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName()), + Form("PairsBarrelSEPP_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName()), + Form("PairsBarrelSEMM_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName())}; + histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); + // NOTE: In the numbering scheme for the map key, we use the number of barrel cuts in the barrel-track selection task + fTrackHistNames[fNCutsBarrel + icut * fNPairCuts + iPairCut] = names; + } // end loop (pair cuts) + } // end if (pair cuts) + + // assign hist directories for the MC matched pairs for each (track cut,MCsignal) combination + if (!sigNamesStr.IsNull()) { + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { + auto sig = fRecMCSignals.at(isig); + names = { + Form("PairsBarrelSEPM_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), + Form("PairsBarrelSEPP_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), + Form("PairsBarrelSEMM_%s_%s", objArray->At(icut)->GetName(), sig->GetName())}; + if (fConfigQA) { + names.push_back(Form("PairsBarrelSEPMCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsBarrelSEPMIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsBarrelSEPM_ambiguousInBunch_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsBarrelSEPM_ambiguousInBunchCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsBarrelSEPM_ambiguousInBunchIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsBarrelSEPM_ambiguousOutOfBunch_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsBarrelSEPM_ambiguousOutOfBunchCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsBarrelSEPM_ambiguousOutOfBunchIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + } + for (auto& n : names) { + histNames += Form("%s;", n.Data()); + } + fBarrelHistNamesMCmatched.try_emplace(icut * fRecMCSignals.size() + isig, names); + } // end loop over MC signals + } + } // end if enableBarrelHistos + } + } + } + + // get the muon track selection cuts + getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCuts", tempCuts, false); + tempCutsStr = tempCuts; + // check also the cuts added via JSON and add them to the string of cuts + getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCutsJSON", tempCuts, false); + TString addMuonCutsStr = tempCuts; + if (addMuonCutsStr != "") { + std::vector addMuonCuts = dqcuts::GetCutsFromJSON(addMuonCutsStr.Data()); + for (auto& t : addMuonCuts) { + tempCutsStr += Form(",%s", t->GetName()); + } + } + + // check that in this task we have specified muon cuts + if (!muonCutsStr.IsNull()) { + // loop over the muon cuts computed by the muon selection task and build a filter mask for those required in this task + std::unique_ptr objArray(tempCutsStr.Tokenize(",")); + fNCutsMuon = objArray->GetEntries(); + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + TString tempStr = objArray->At(icut)->GetName(); + if (objArrayMuonCuts->FindObject(tempStr.Data()) != nullptr) { + // update the filter mask + fMuonFilterMask |= (static_cast(1) << icut); + + if (fEnableMuonHistos) { + // assign pair hist directories for each required muon cut + std::vector names = { + Form("PairsMuonSEPM_%s", objArray->At(icut)->GetName()), + Form("PairsMuonSEPP_%s", objArray->At(icut)->GetName()), + Form("PairsMuonSEMM_%s", objArray->At(icut)->GetName())}; + if (fConfigQA) { + // assign separate hist directories for ambiguous tracks + names.push_back(Form("PairsMuonSEPM_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEPP_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEMM_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEPM_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEPP_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEMM_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + } + for (auto& n : names) { + histNames += Form("%s;", n.Data()); + } + fMuonHistNames[icut] = names; + + // if there are specified pair cuts, assign hist dirs for each muon cut - pair cut combination + TString cutNamesStr = fConfigCuts.pair.value; + if (!cutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + fNPairCuts = objArrayPair->GetEntries(); + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts + names = { + Form("PairsMuonSEPM_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName()), + Form("PairsMuonSEPP_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName()), + Form("PairsMuonSEMM_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName())}; + histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); + fMuonHistNames[fNCutsMuon + icut * fNCutsMuon + iPairCut] = names; + } // end loop (pair cuts) + } // end if (pair cuts) + + // assign hist directories for pairs matched to MC signals for each (muon cut, MCrec signal) combination + if (!sigNamesStr.IsNull()) { + for (auto& sig : fRecMCSignals) { + names = { + Form("PairsMuonSEPM_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), + Form("PairsMuonSEPP_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), + Form("PairsMuonSEMM_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), + }; + if (fConfigQA) { + names.push_back(Form("PairsMuonSEPMCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsMuonSEPMIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsMuonSEPM_ambiguousInBunch_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsMuonSEPM_ambiguousInBunchCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsMuonSEPM_ambiguousInBunchIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsMuonSEPM_ambiguousOutOfBunch_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsMuonSEPM_ambiguousOutOfBunchCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsMuonSEPM_ambiguousOutOfBunchIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + } + for (auto& n : names) { + histNames += Form("%s;", n.Data()); + } + } // end loop over MC signals + } + fMuonHistNamesMCmatched[icut] = names; + } + } + } // end loop over cuts + } // end if (muonCutsStr) + + // Add histogram classes for each specified MCsignal at the generator level + // TODO: create a std::vector of hist classes to be used at Fill time, to avoid using Form in the process function + TString sigGenNamesStr = fConfigMC.genSignals.value; + std::unique_ptr objGenSigArray(sigGenNamesStr.Tokenize(",")); + for (int isig = 0; isig < objGenSigArray->GetEntries(); isig++) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objGenSigArray->At(isig)->GetName()); + if (sig) { + fGenMCSignals.push_back(sig); + } + } + + // Add the MCSignals from the JSON config + TString addMCSignalsGenStr = fConfigMC.genSignalsJSON.value; + if (addMCSignalsGenStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsGenStr.Data()); + for (auto& mcIt : addMCSignals) { + if (mcIt->GetNProngs() > 2) { // NOTE: only 2 prong signals + continue; + } + fGenMCSignals.push_back(mcIt); + } + } + + for (auto& sig : fGenMCSignals) { + if (sig->GetNProngs() == 1) { + histNames += Form("MCTruthGen_%s;", sig->GetName()); // TODO: Add these names to a std::vector to avoid using Form in the process function + } else if (sig->GetNProngs() == 2) { + histNames += Form("MCTruthGenPair_%s;", sig->GetName()); + fHasTwoProngGenMCsignals = true; + } + } + + fCurrentRun = 0; + + fCCDB->setURL(fConfigCCDB.url.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + + if (fConfigOptions.noCorr) { + VarManager::SetupFwdDCAFitterNoCorr(); + } else if (fConfigOptions.corrFullGeo || (fConfigOptions.useKFVertexing && fConfigOptions.propToPCA)) { + if (!o2::base::GeometryManager::isGeometryLoaded()) { + fCCDB->get(fConfigCCDB.geoPath); + } + } else { + fLUT = o2::base::MatLayerCylSet::rectifyPtrFromFile(fCCDB->get(fConfigCCDB.lutPath)); + VarManager::SetupMatLUTFwdDCAFitter(fLUT); + } + + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + VarManager::SetCollisionSystem((TString)fConfigOptions.collisionSystem, fConfigOptions.centerMassEnergy); // set collision system and center of mass energy + + DefineHistograms(fHistMan, histNames.Data(), fConfigAddSEPHistogram.value.data()); // define all histograms + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } + + void initParamsFromCCDB(uint64_t timestamp, bool withTwoProngFitter = true) + { + if (fConfigOptions.useRemoteField.value) { + o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(fConfigCCDB.grpMagPath, timestamp); + float magField = 0.0; + if (grpmag != nullptr) { + magField = grpmag->getNominalL3Field(); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", timestamp); + } + if (withTwoProngFitter) { + if (fConfigOptions.useKFVertexing.value) { + VarManager::SetupTwoProngKFParticle(magField); + } else { + VarManager::SetupTwoProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); // TODO: get these parameters from Configurables + VarManager::SetupTwoProngFwdDCAFitter(magField, true, 200.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); + } + } else { + VarManager::SetupTwoProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); // needed because take in varmanager Bz from fgFitterTwoProngBarrel for PhiV calculations + } + } else { + if (withTwoProngFitter) { + if (fConfigOptions.useKFVertexing.value) { + VarManager::SetupTwoProngKFParticle(fConfigOptions.magField.value); + } else { + VarManager::SetupTwoProngDCAFitter(fConfigOptions.magField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); // TODO: get these parameters from Configurables + VarManager::SetupTwoProngFwdDCAFitter(fConfigOptions.magField.value, true, 200.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); + } + } else { + VarManager::SetupTwoProngDCAFitter(fConfigOptions.magField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); // needed because take in varmanager Bz from fgFitterTwoProngBarrel for PhiV calculations + } + } + } + + // Template function to run same event pairing (barrel-barrel, muon-muon, barrel-muon) + template + void runSameEventPairing(TEvents const& events, Preslice& preslice, TTrackAssocs const& assocs, TTracks const& /*tracks*/, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& /*mcTracks*/) + { + if (fCurrentRun != events.begin().runNumber()) { + initParamsFromCCDB(events.begin().timestamp(), TTwoProngFitter); + fCurrentRun = events.begin().runNumber(); + } + + TString cutNames = fConfigCuts.track.value; + std::map> histNames = fTrackHistNames; + std::map> histNamesMC = fBarrelHistNamesMCmatched; + int ncuts = fNCutsBarrel; + if constexpr (TPairType == VarManager::kDecayToMuMu) { + cutNames = fConfigCuts.muon.value; + histNames = fMuonHistNames; + histNamesMC = fMuonHistNamesMCmatched; + ncuts = fNCutsMuon; + } + + uint32_t twoTrackFilter = static_cast(0); + int sign1 = 0; + int sign2 = 0; + uint32_t mcDecision = static_cast(0); + bool isCorrectAssoc_leg1 = false; + bool isCorrectAssoc_leg2 = false; + dielectronList.reserve(1); + dimuonList.reserve(1); + dielectronsExtraList.reserve(1); + dimuonsExtraList.reserve(1); + dielectronInfoList.reserve(1); + dileptonInfoList.reserve(1); + if (fConfigOptions.flatTables.value) { + dimuonAllList.reserve(1); + } + if (useMiniTree.fConfigMiniTree) { + dileptonMiniTreeGen.reserve(1); + dileptonMiniTreeRec.reserve(1); + } + constexpr bool eventHasQvector = ((TEventFillMap & VarManager::ObjTypes::ReducedEventQvector) > 0); + constexpr bool trackHasCov = ((TTrackFillMap & VarManager::ObjTypes::ReducedTrackBarrelCov) > 0); + + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + uint8_t evSel = event.isEventSelected_raw(); + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event, VarManager::fgValues); + VarManager::FillEvent(event.reducedMCevent(), VarManager::fgValues); + + auto groupedAssocs = assocs.sliceBy(preslice, event.globalIndex()); + if (groupedAssocs.size() == 0) { + continue; + } + + for (auto& [a1, a2] : o2::soa::combinations(groupedAssocs, groupedAssocs)) { + + if constexpr (TPairType == VarManager::kDecayToEE) { + twoTrackFilter = a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & a1.isBarrelSelectedPrefilter_raw() & a2.isBarrelSelectedPrefilter_raw() & fTrackFilterMask; + + if (!twoTrackFilter) { // the tracks must have at least one filter bit in common to continue + continue; + } + + auto t1 = a1.template reducedtrack_as(); + auto t2 = a2.template reducedtrack_as(); + sign1 = t1.sign(); + sign2 = t2.sign(); + // store the ambiguity number of the two dilepton legs in the last 4 digits of the two-track filter + if (t1.barrelAmbiguityInBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 28); + } + if (t2.barrelAmbiguityInBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 29); + } + if (t1.barrelAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 30); + } + if (t2.barrelAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 31); + } + + // run MC matching for this pair + int isig = 0; + mcDecision = 0; + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { + if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { + if ((*sig)->CheckSignal(true, t1.reducedMCTrack(), t2.reducedMCTrack())) { + mcDecision |= (static_cast(1) << isig); + } + } + } // end loop over MC signals + if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { + isCorrectAssoc_leg1 = (t1.reducedMCTrack().reducedMCevent() == event.reducedMCevent()); + isCorrectAssoc_leg2 = (t2.reducedMCTrack().reducedMCevent() == event.reducedMCevent()); + } + + VarManager::FillPair(t1, t2); + if (fPropTrack) { + VarManager::FillPairCollision(event, t1, t2); + } + if constexpr (TTwoProngFitter) { + VarManager::FillPairVertexing(event, t1, t2, fConfigOptions.propToPCA); + } + if constexpr (eventHasQvector) { + VarManager::FillPairVn(t1, t2); + } + if (!fConfigMC.skimSignalOnly || (fConfigMC.skimSignalOnly && mcDecision > 0)) { + dielectronList(event.globalIndex(), VarManager::fgValues[VarManager::kMass], + VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], + t1.sign() + t2.sign(), twoTrackFilter, mcDecision); + + if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedTrackCollInfo) > 0) { + dielectronInfoList(t1.collisionId(), t1.trackId(), t2.trackId()); + dileptonInfoList(t1.collisionId(), event.posX(), event.posY(), event.posZ()); + } + if constexpr (trackHasCov && TTwoProngFitter) { + dielectronsExtraList(t1.globalIndex(), t2.globalIndex(), VarManager::fgValues[VarManager::kVertexingTauzProjected], VarManager::fgValues[VarManager::kVertexingLzProjected], VarManager::fgValues[VarManager::kVertexingLxyProjected]); + } + } + } + + if constexpr (TPairType == VarManager::kDecayToMuMu) { + twoTrackFilter = a1.isMuonSelected_raw() & a2.isMuonSelected_raw() & fMuonFilterMask; + if (!twoTrackFilter) { // the tracks must have at least one filter bit in common to continue + continue; + } + auto t1 = a1.template reducedmuon_as(); + auto t2 = a2.template reducedmuon_as(); + if (t1.matchMCHTrackId() == t2.matchMCHTrackId() && t1.matchMCHTrackId() >= 0) + continue; + if (t1.matchMFTTrackId() == t2.matchMFTTrackId() && t1.matchMFTTrackId() >= 0) + continue; + sign1 = t1.sign(); + sign2 = t2.sign(); + // store the ambiguity number of the two dilepton legs in the last 4 digits of the two-track filter + if (t1.muonAmbiguityInBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 28); + } + if (t2.muonAmbiguityInBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 29); + } + if (t1.muonAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 30); + } + if (t2.muonAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 31); + } + + // run MC matching for this pair + int isig = 0; + mcDecision = 0; + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { + if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { + if ((*sig)->CheckSignal(true, t1.reducedMCTrack(), t2.reducedMCTrack())) { + mcDecision |= (static_cast(1) << isig); + } + } + } // end loop over MC signals + + if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { + isCorrectAssoc_leg1 = (t1.reducedMCTrack().reducedMCevent() == event.reducedMCevent()); + isCorrectAssoc_leg2 = (t2.reducedMCTrack().reducedMCevent() == event.reducedMCevent()); + } + + VarManager::FillPair(t1, t2); + if (fPropTrack) { + VarManager::FillPairCollision(event, t1, t2); + } + if constexpr (TTwoProngFitter) { + VarManager::FillPairVertexing(event, t1, t2, fConfigOptions.propToPCA); + } + if constexpr (eventHasQvector) { + VarManager::FillPairVn(t1, t2); + } + + dimuonList(event.globalIndex(), VarManager::fgValues[VarManager::kMass], + VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], + t1.sign() + t2.sign(), twoTrackFilter, mcDecision); + if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedMuonCollInfo) > 0) { + dileptonInfoList(t1.collisionId(), event.posX(), event.posY(), event.posZ()); + } + + if constexpr (TTwoProngFitter) { + dimuonsExtraList(t1.globalIndex(), t2.globalIndex(), VarManager::fgValues[VarManager::kVertexingTauz], VarManager::fgValues[VarManager::kVertexingLz], VarManager::fgValues[VarManager::kVertexingLxy]); + if (fConfigOptions.flatTables.value && t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { + dimuonAllList(event.posX(), event.posY(), event.posZ(), event.numContrib(), + event.selection_raw(), evSel, + event.reducedMCevent().mcPosX(), event.reducedMCevent().mcPosY(), event.reducedMCevent().mcPosZ(), + VarManager::fgValues[VarManager::kMass], + mcDecision, + VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), VarManager::fgValues[VarManager::kVertexingChi2PCA], + VarManager::fgValues[VarManager::kVertexingTauz], VarManager::fgValues[VarManager::kVertexingTauzErr], + VarManager::fgValues[VarManager::kVertexingTauxy], VarManager::fgValues[VarManager::kVertexingTauxyErr], + VarManager::fgValues[VarManager::kCosPointingAngle], + VarManager::fgValues[VarManager::kPt1], VarManager::fgValues[VarManager::kEta1], VarManager::fgValues[VarManager::kPhi1], t1.sign(), + VarManager::fgValues[VarManager::kPt2], VarManager::fgValues[VarManager::kEta2], VarManager::fgValues[VarManager::kPhi2], t2.sign(), + t1.fwdDcaX(), t1.fwdDcaY(), t2.fwdDcaX(), t2.fwdDcaY(), + t1.mcMask(), t2.mcMask(), + t1.chi2MatchMCHMID(), t2.chi2MatchMCHMID(), + t1.chi2MatchMCHMFT(), t2.chi2MatchMCHMFT(), + t1.chi2(), t2.chi2(), + t1.reducedMCTrack().pt(), t1.reducedMCTrack().eta(), t1.reducedMCTrack().phi(), t1.reducedMCTrack().e(), + t2.reducedMCTrack().pt(), t2.reducedMCTrack().eta(), t2.reducedMCTrack().phi(), t2.reducedMCTrack().e(), + t1.reducedMCTrack().vx(), t1.reducedMCTrack().vy(), t1.reducedMCTrack().vz(), t1.reducedMCTrack().vt(), + t2.reducedMCTrack().vx(), t2.reducedMCTrack().vy(), t2.reducedMCTrack().vz(), t2.reducedMCTrack().vt(), + (twoTrackFilter & (static_cast(1) << 28)) || (twoTrackFilter & (static_cast(1) << 29)), (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)), + -999.0, -999.0, -999.0, -999.0, -999.0, + -999.0, -999.0, -999.0, -999.0, -999.0, + -999.0, VarManager::fgValues[VarManager::kMultDimuons], + VarManager::fgValues[VarManager::kVertexingPz], VarManager::fgValues[VarManager::kVertexingSV]); + } + } + } + // TODO: the model for the electron-muon combination has to be thought through + /*if constexpr (TPairType == VarManager::kElectronMuon) { + twoTrackFilter = a1.isBarrelSelected_raw() & a1.isBarrelSelectedPrefilter_raw() & a2.isMuonSelected_raw() & fTwoTrackFilterMask; + }*/ + + // Fill histograms + bool isAmbiInBunch = false; + bool isAmbiOutOfBunch = false; + bool isCorrect_pair = false; + if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) + isCorrect_pair = true; + + for (int icut = 0; icut < ncuts; icut++) { + if (twoTrackFilter & (static_cast(1) << icut)) { + isAmbiInBunch = (twoTrackFilter & (static_cast(1) << 28)) || (twoTrackFilter & (static_cast(1) << 29)); + isAmbiOutOfBunch = (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)); + if (sign1 * sign2 < 0) { // +- pairs + fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); // reconstructed, unmatched + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + PromptNonPromptSepTable(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kVertexingTauxyProjected], VarManager::fgValues[VarManager::kVertexingTauxyProjectedPoleJPsiMass], VarManager::fgValues[VarManager::kVertexingTauzProjected], isAmbiInBunch, isAmbiOutOfBunch, isCorrect_pair); + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][0].Data(), VarManager::fgValues); // matched signal + if (useMiniTree.fConfigMiniTree) { + if constexpr (TPairType == VarManager::kDecayToMuMu) { + twoTrackFilter = a1.isMuonSelected_raw() & a2.isMuonSelected_raw() & fMuonFilterMask; + if (!twoTrackFilter) { // the tracks must have at least one filter bit in common to continue + continue; + } + auto t1 = a1.template reducedmuon_as(); + auto t2 = a2.template reducedmuon_as(); + + float dileptonMass = VarManager::fgValues[VarManager::kMass]; + if (dileptonMass > useMiniTree.fConfigMiniTreeMinMass && dileptonMass < useMiniTree.fConfigMiniTreeMaxMass) { + dileptonMiniTreeRec(mcDecision, + VarManager::fgValues[VarManager::kMass], + VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], VarManager::fgValues[VarManager::kCentFT0C], + t1.reducedMCTrack().pt(), t1.reducedMCTrack().eta(), t1.reducedMCTrack().phi(), + t2.reducedMCTrack().pt(), t2.reducedMCTrack().eta(), t2.reducedMCTrack().phi(), + VarManager::fgValues[VarManager::kPt1], VarManager::fgValues[VarManager::kEta1], VarManager::fgValues[VarManager::kPhi1], + VarManager::fgValues[VarManager::kPt2], VarManager::fgValues[VarManager::kEta2], VarManager::fgValues[VarManager::kPhi2]); + } + } + } + if (fConfigQA) { + if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { // correct track-collision association + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][3].Data(), VarManager::fgValues); + } else { // incorrect track-collision association + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][4].Data(), VarManager::fgValues); + } + if (isAmbiInBunch) { // ambiguous in bunch + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][5].Data(), VarManager::fgValues); + if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][6].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][7].Data(), VarManager::fgValues); + } + } + if (isAmbiOutOfBunch) { // ambiguous out of bunch + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][8].Data(), VarManager::fgValues); + if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][9].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][10].Data(), VarManager::fgValues); + } + } + } + } + if (fConfigQA) { + if (isAmbiInBunch) { + fHistMan->FillHistClass(histNames[icut][3].Data(), VarManager::fgValues); + } + if (isAmbiOutOfBunch) { + fHistMan->FillHistClass(histNames[icut][3 + 3].Data(), VarManager::fgValues); + } + } + } + } else { + if (sign1 > 0) { // ++ pairs + fHistMan->FillHistClass(histNames[icut][1].Data(), VarManager::fgValues); + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][1].Data(), VarManager::fgValues); + } + } + if (fConfigQA) { + if (isAmbiInBunch) { + fHistMan->FillHistClass(histNames[icut][4].Data(), VarManager::fgValues); + } + if (isAmbiOutOfBunch) { + fHistMan->FillHistClass(histNames[icut][4 + 3].Data(), VarManager::fgValues); + } + } + } else { // -- pairs + fHistMan->FillHistClass(histNames[icut][2].Data(), VarManager::fgValues); + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][2].Data(), VarManager::fgValues); + } + } + if (fConfigQA) { + if (isAmbiInBunch) { + fHistMan->FillHistClass(histNames[icut][5].Data(), VarManager::fgValues); + } + if (isAmbiOutOfBunch) { + fHistMan->FillHistClass(histNames[icut][5 + 3].Data(), VarManager::fgValues); + } + } + } + } + for (unsigned int iPairCut = 0; iPairCut < fPairCuts.size(); iPairCut++) { + AnalysisCompositeCut cut = fPairCuts.at(iPairCut); + if (!(cut.IsSelected(VarManager::fgValues))) // apply pair cuts + continue; + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][0].Data(), VarManager::fgValues); + } else { + if (sign1 > 0) { + fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][1].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][2].Data(), VarManager::fgValues); + } + } + } // end loop (pair cuts) + } + } // end loop (cuts) + } // end loop over pairs of track associations + } // end loop over events + } + + // Preslice perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; + PresliceUnsorted perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; + + void runMCGen(ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + // loop over mc stack and fill histograms for pure MC truth signals + // group all the MC tracks which belong to the MC event corresponding to the current reconstructed event + // auto groupedMCTracks = tracksMC.sliceBy(aod::reducedtrackMC::reducedMCeventId, event.reducedMCevent().globalIndex()); + uint32_t mcDecision = 0; + int isig = 0; + for (auto& mctrack : mcTracks) { + VarManager::FillTrackMC(mcTracks, mctrack); + // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. + // NOTE: However, the working model is that the decisions on MC signals are precomputed during skimming and are stored in the mcReducedFlags member. + // TODO: Use the mcReducedFlags to select signals + for (auto& sig : fGenMCSignals) { + if (sig->GetNProngs() != 1) { // NOTE: 1-prong signals required here + continue; + } + bool checked = false; + /*if constexpr (soa::is_soa_filtered_v) { + auto mctrack_raw = groupedMCTracks.rawIteratorAt(mctrack.globalIndex()); + checked = sig.CheckSignal(true, mctrack_raw); + } else {*/ + checked = sig->CheckSignal(true, mctrack); + //} + if (checked) { + mcDecision |= (static_cast(1) << isig); + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + if (useMiniTree.fConfigMiniTree) { + auto mcEvent = mcEvents.rawIteratorAt(mctrack.reducedMCeventId()); + dileptonMiniTreeGen(mcDecision, mcEvent.impactParameter(), mctrack.pt(), mctrack.eta(), mctrack.phi(), -999, -999, -999); + } + } + } + isig++; + } + + if (fHasTwoProngGenMCsignals) { + for (auto& event : mcEvents) { + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.globalIndex()); + groupedMCTracks.bindInternalIndicesTo(&mcTracks); + for (auto& [t1, t2] : combinations(groupedMCTracks, groupedMCTracks)) { + auto t1_raw = groupedMCTracks.rawIteratorAt(t1.globalIndex()); + auto t2_raw = groupedMCTracks.rawIteratorAt(t2.globalIndex()); + for (auto& sig : fGenMCSignals) { + if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here + continue; + } + if (sig->CheckSignal(true, t1_raw, t2_raw)) { + mcDecision |= (static_cast(1) << isig); + VarManager::FillPairMC(t1, t2); + fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), VarManager::fgValues); + if (useMiniTree.fConfigMiniTree) { + // WARNING! To be checked + dileptonMiniTreeGen(mcDecision, event.impactParameter(), t1.pt(), t1.eta(), t1.phi(), t2.pt(), t2.eta(), t2.phi()); + } + } + isig++; + } // end loop over MC signals + } // end loop over pairs + } // end loop over events + } + } // end runMCGen + + void processAllSkimmed(MyEventsVtxCovSelected const& events, + soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, + soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons, + ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); + runSameEventPairing(events, muonAssocsPerCollision, muonAssocs, muons, mcEvents, mcTracks); + if (fConfigMC.runMCGenPair) { + runMCGen(mcEvents, mcTracks); + } + // runSameEventPairing(event, tracks, muons); + } + + void processBarrelOnlySkimmed(MyEventsVtxCovSelected const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); + if (fConfigMC.runMCGenPair) { + runMCGen(mcEvents, mcTracks); + } + } + + void processBarrelOnlyWithCollSkimmed(MyEventsVtxCovSelected const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithCovWithAmbiguitiesWithColl const& barrelTracks, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); + if (fConfigMC.runMCGenPair) { + runMCGen(mcEvents, mcTracks); + } + } + + void processMuonOnlySkimmed(MyEventsVtxCovSelected const& events, + soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + runSameEventPairing(events, muonAssocsPerCollision, muonAssocs, muons, mcEvents, mcTracks); + if (fConfigMC.runMCGenPair) { + runMCGen(mcEvents, mcTracks); + } + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisSameEventPairing, processAllSkimmed, "Run all types of pairing, with skimmed tracks/muons", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processBarrelOnlySkimmed, "Run barrel only pairing, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processBarrelOnlyWithCollSkimmed, "Run barrel only pairing, with skimmed tracks and with collision information", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processMuonOnlySkimmed, "Run muon only pairing, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processDummy, "Dummy function, enabled only if none of the others are enabled", false); +}; + +// Run pairing for resonance with legs fulfilling separate cuts (asymmetric decay channel) +struct AnalysisAsymmetricPairing { + + Produces ditrackList; + Produces ditrackExtraList; + + o2::base::MatLayerCylSet* fLUT = nullptr; + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + + // Output objects + OutputObj fOutputList{"output"}; + + // Configurables + Configurable fConfigLegCuts{"cfgLegCuts", "", ":[:],[:[:],...]"}; + Configurable fConfigLegAFilterMask{"cfgLegAFilterMask", 0, "Filter mask corresponding to cuts in event-selection"}; + Configurable fConfigLegBFilterMask{"cfgLegBFilterMask", 0, "Filter mask corresponding to cuts in event-selection"}; + Configurable fConfigLegCFilterMask{"cfgLegCFilterMask", 0, "Filter mask corresponding to cuts in event-selection"}; + Configurable fConfigCommonTrackCuts{"cfgCommonTrackCuts", "", "Comma separated list of cuts to be applied to all legs"}; + Configurable fConfigPairCuts{"cfgPairCuts", "", "Comma separated list of pair cuts"}; + Configurable fConfigPairCutsJSON{"cfgPairCutsJSON", "", "Additional list of pair cuts in JSON format"}; + Configurable fConfigSkipAmbiguousIdCombinations{"cfgSkipAmbiguousIdCombinations", true, "Choose whether to skip pairs/triples which pass a stricter combination of cuts, e.g. KKPi triplets for D+ -> KPiPi"}; + + Configurable fConfigHistogramSubgroups{"cfgAsymmetricPairingHistogramsSubgroups", "barrel,vertexing", "Comma separated list of asymmetric-pairing histogram subgroups"}; + Configurable fConfigSameSignHistograms{"cfgSameSignHistograms", false, "Include same sign pair histograms for 2-prong decays"}; + // Configurable fConfigAmbiguousHistograms{"cfgAmbiguousHistograms", false, "Include separate histograms for pairs/triplets with ambiguous tracks"}; + Configurable fConfigReflectedHistograms{"cfgReflectedHistograms", false, "Include separate histograms for pairs which are reflections of previously counted pairs"}; + Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable fConfigGRPMagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable fConfigUseRemoteField{"cfgUseRemoteField", false, "Choose whether to fetch the magnetic field from ccdb or set it manually"}; + Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; + + Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; + Configurable fConfigUseAbsDCA{"cfgUseAbsDCA", false, "Use absolute DCA minimization instead of chi^2 minimization in secondary vertexing"}; + Configurable fConfigPropToPCA{"cfgPropToPCA", false, "Propagate tracks to secondary vertex"}; + Configurable fConfigLutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + + Configurable fConfigRunMCGenPair{"cfgRunMCGenPair", false, "Do pairing of true MC particles"}; + Configurable fConfigMCGenSignals{"cfgBarrelMCGenSignals", "", "Comma separated list of MC signals (generated)"}; + Configurable fConfigMCRecSignals{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; + + Service fCCDB; + + HistogramManager* fHistMan; + + std::map> fTrackHistNames; + std::map> fBarrelHistNamesMCmatched; + std::vector fPairCuts; + int fNPairHistPrefixes; + + std::vector fRecMCSignals; + std::vector fGenMCSignals; + + // Filter masks to find legs in BarrelTrackCuts table + uint32_t fLegAFilterMask; + uint32_t fLegBFilterMask; + uint32_t fLegCFilterMask; + // Maps tracking which combination of leg cuts the track cuts participate in + std::map fConstructedLegAFilterMasksMap; + std::map fConstructedLegBFilterMasksMap; + std::map fConstructedLegCFilterMasksMap; + // Filter map for common track cuts + uint32_t fCommonTrackCutMask; + // Map tracking which common track cut the track cuts correspond to + std::map fCommonTrackCutFilterMasks; + + int fNLegCuts; + int fNPairCuts = 0; + int fNCommonTrackCuts; + + Preslice> trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + + // Partitions for triplets and asymmetric pairs + Partition> legACandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegAFilterMask) > static_cast(0); + Partition> legBCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegBFilterMask) > static_cast(0); + Partition> legCCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegCFilterMask) > static_cast(0); + + // Map to track how many times a pair of tracks has been encountered + std::map, int8_t> fPairCount; + + void init(o2::framework::InitContext& context) + { + if (context.mOptions.get("processDummy")) { + return; + } + + VarManager::SetDefaultVarNames(); + + TString histNames = ""; + std::vector names; + + // Get the leg cut filter maps + fLegAFilterMask = fConfigLegAFilterMask.value; + fLegBFilterMask = fConfigLegBFilterMask.value; + fLegCFilterMask = fConfigLegCFilterMask.value; + // Get the pair cuts + TString cutNamesStr = fConfigPairCuts.value; + if (!cutNamesStr.IsNull()) { + std::unique_ptr objArray(cutNamesStr.Tokenize(",")); + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + fPairCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + } + } + // Extra pair cuts via JSON + TString addPairCutsStr = fConfigPairCutsJSON.value; + if (addPairCutsStr != "") { + std::vector addPairCuts = dqcuts::GetCutsFromJSON(addPairCutsStr.Data()); + for (auto& t : addPairCuts) { + fPairCuts.push_back((AnalysisCompositeCut*)t); + cutNamesStr += Form(",%s", t->GetName()); + } + } + + // Setting the MC rec signal names + TString sigNamesStr = fConfigMCRecSignals.value; + std::unique_ptr objRecSigArray(sigNamesStr.Tokenize(",")); + + for (int isig = 0; isig < objRecSigArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objRecSigArray->At(isig)->GetName()); + if (sig) { + fRecMCSignals.push_back(*sig); + } + } + + // Get the barrel track selection cuts + string tempCuts; + getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", tempCuts, false); + TString tempCutsStr = tempCuts; + // check also the cuts added via JSON and add them to the string of cuts + getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", tempCuts, false); + TString addTrackCutsStr = tempCuts; + if (addTrackCutsStr != "") { + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + for (auto& t : addTrackCuts) { + tempCutsStr += Form(",%s", t->GetName()); + } + } + std::unique_ptr objArray(tempCutsStr.Tokenize(",")); + // Get the common leg cuts + int commonCutIdx; + TString commonNamesStr = fConfigCommonTrackCuts.value; + if (!commonNamesStr.IsNull()) { // if common track cuts + std::unique_ptr objArrayCommon(commonNamesStr.Tokenize(",")); + fNCommonTrackCuts = objArrayCommon->GetEntries(); + for (int icut = 0; icut < fNCommonTrackCuts; ++icut) { + commonCutIdx = objArray->IndexOf(objArrayCommon->At(icut)); + if (commonCutIdx >= 0) { + fCommonTrackCutMask |= static_cast(1) << objArray->IndexOf(objArrayCommon->At(icut)); + fCommonTrackCutFilterMasks[icut] = static_cast(1) << objArray->IndexOf(objArrayCommon->At(icut)); + } else { + LOGF(fatal, "Common track cut %s was not calculated upstream. Check the config!", objArrayCommon->At(icut)->GetName()); + } + } + } + // Check that the leg cut masks make sense + if (static_cast(std::floor(TMath::Log2(fLegAFilterMask))) + 1 > objArray->GetEntries()) { + LOGF(fatal, "fConfigLegAFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(TMath::Log2(fLegAFilterMask))) + 1, objArray->GetEntries()); + } + if (static_cast(std::floor(TMath::Log2(fLegBFilterMask))) + 1 > objArray->GetEntries()) { + LOGF(fatal, "fConfigLegBFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(TMath::Log2(fLegBFilterMask))) + 1, objArray->GetEntries()); + } + if (static_cast(std::floor(TMath::Log2(fLegCFilterMask))) + 1 > objArray->GetEntries()) { + LOGF(fatal, "fConfigLegCFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(TMath::Log2(fLegCFilterMask))) + 1, objArray->GetEntries()); + } + + // Get the cuts defining the legs + uint32_t fConstructedLegAFilterMask = 0; + uint32_t fConstructedLegBFilterMask = 0; + uint32_t fConstructedLegCFilterMask = 0; + TString legCutsStr = fConfigLegCuts.value; + std::unique_ptr objArrayLegs(legCutsStr.Tokenize(",")); + if (objArrayLegs->GetEntries() == 0) { + LOG(fatal) << "No cuts defining legs. Check the config!"; + } + fNLegCuts = objArrayLegs->GetEntries(); + std::vector isThreeProng; + int legAIdx; + int legBIdx; + int legCIdx; + // Loop over leg defining cuts + for (int icut = 0; icut < fNLegCuts; ++icut) { + TString legsStr = objArrayLegs->At(icut)->GetName(); + std::unique_ptr legs(legsStr.Tokenize(":")); + if (legs->GetEntries() == 3) { + isThreeProng.push_back(true); + } else if (legs->GetEntries() == 2) { + isThreeProng.push_back(false); + } else { + LOGF(fatal, "Leg cuts %s has the wrong format and could not be parsed!", legsStr.Data()); + continue; + } + // Find leg cuts in the track selection cuts + legAIdx = objArray->IndexOf(legs->At(0)); + if (legAIdx >= 0) { + fConstructedLegAFilterMask |= static_cast(1) << legAIdx; + fConstructedLegAFilterMasksMap[icut] |= static_cast(1) << legAIdx; + } else { + LOGF(fatal, "Leg A cut %s was not calculated upstream. Check the config!", legs->At(0)->GetName()); + continue; + } + legBIdx = objArray->IndexOf(legs->At(1)); + if (legBIdx >= 0) { + fConstructedLegBFilterMask |= static_cast(1) << legBIdx; + fConstructedLegBFilterMasksMap[icut] |= static_cast(1) << legBIdx; + } else { + LOGF(fatal, "Leg B cut %s was not calculated upstream. Check the config!", legs->At(1)->GetName()); + continue; + } + if (isThreeProng[icut]) { + legCIdx = objArray->IndexOf(legs->At(2)); + if (legCIdx >= 0) { + fConstructedLegCFilterMask |= static_cast(1) << legCIdx; + fConstructedLegCFilterMasksMap[icut] |= static_cast(1) << legCIdx; + } else { + LOGF(fatal, "Leg C cut %s was not calculated upstream. Check the config!", legs->At(2)->GetName()); + continue; + } + } + if (isThreeProng[icut]) { + names = { + Form("TripletsBarrelSE_%s", legsStr.Data())}; + histNames += Form("%s;", names[0].Data()); + if (fConfigQA) { + names.push_back(Form("TripletsBarrelSE_ambiguous_%s", legsStr.Data())); + histNames += Form("%s;", names[1].Data()); + } + fTrackHistNames[icut] = names; + + std::unique_ptr objArrayCommon(commonNamesStr.Tokenize(",")); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + names = {}; + names.push_back(Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName())); + histNames += Form("%s;", names[0].Data()); + fTrackHistNames[fNLegCuts + icut * fNCommonTrackCuts + iCommonCut] = names; + } + + TString cutNamesStr = fConfigPairCuts.value; + if (!cutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + fNPairCuts = objArrayPair->GetEntries(); + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts + names = {}; + names.push_back(Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayPair->At(iPairCut)->GetName())); + histNames += Form("%s;", names[0].Data()); + fTrackHistNames[fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut] = names; + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + names = {}; + names.push_back(Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName())); + histNames += Form("%s;", names[0].Data()); + fTrackHistNames[(fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + icut * (fNPairCuts * fNCommonTrackCuts + 1) + iCommonCut * (1 + fNPairCuts) + iPairCut] = names; + } // end loop (common cuts) + } // end loop (pair cuts) + } // end if (pair cuts) + + // TODO: assign hist directories for the MC matched triplets for each (leg cut combo,MCsignal) combination + if (!sigNamesStr.IsNull()) { + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { + auto sig = fRecMCSignals.at(isig); + int offset = fNLegCuts * isig * (1 + fNCommonTrackCuts + fNPairCuts + fNCommonTrackCuts * fNPairCuts); + names = { + Form("TripletsBarrelSE_%s_%s", legsStr.Data(), sig.GetName())}; + histNames += Form("%s;", names[0].Data()); + fBarrelHistNamesMCmatched[offset + icut] = names; + + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + names = {}; + names.push_back(Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), sig.GetName())); + histNames += Form("%s;", names[0].Data()); + fBarrelHistNamesMCmatched[offset + fNLegCuts + icut * fNCommonTrackCuts + iCommonCut] = names; + } + + if (!cutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts + names = {}; + names.push_back(Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayPair->At(iPairCut)->GetName(), sig.GetName())); + histNames += Form("%s;", names[0].Data()); + fBarrelHistNamesMCmatched[offset + fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut] = names; + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + names = {}; + names.push_back(Form("TripletsBarrelSE_%s_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName(), sig.GetName())); + histNames += Form("%s;", names[0].Data()); + fBarrelHistNamesMCmatched[offset + (fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + icut * (fNPairCuts * fNCommonTrackCuts) + iCommonCut * (1 + fNPairCuts) + iPairCut] = names; + } // end loop (common cuts) + } // end loop (pair cuts) + } // end if (pair cuts) + } // end loop over MC signals + } // end if (MC signals) + } else { + names = {}; + std::vector pairHistPrefixes = {"PairsBarrelSEPM"}; + if (fConfigSameSignHistograms.value) { + pairHistPrefixes.push_back("PairsBarrelSEPP"); + pairHistPrefixes.push_back("PairsBarrelSEMM"); + } + fNPairHistPrefixes = pairHistPrefixes.size(); + + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + names.push_back(Form("%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data())); + histNames += Form("%s;", names[iPrefix].Data()); + } + if (fConfigQA) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + names.push_back(Form("%s_ambiguous_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data())); + histNames += Form("%s;", names[fNPairHistPrefixes + iPrefix].Data()); + } + } + if (fConfigReflectedHistograms.value) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + names.push_back(Form("%s_reflected_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data())); + histNames += Form("%s;", names[(1 + fConfigQA.value) * fNPairHistPrefixes + iPrefix].Data()); + } + } + fTrackHistNames[icut] = names; + + std::unique_ptr objArrayCommon(commonNamesStr.Tokenize(",")); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + names = {}; + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + names.push_back(Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName())); + histNames += Form("%s;", names[iPrefix].Data()); + } + fTrackHistNames[fNLegCuts + icut * fNCommonTrackCuts + iCommonCut] = names; + } + + if (!cutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + fNPairCuts = objArrayPair->GetEntries(); + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts + names = {}; + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + names.push_back(Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayPair->At(iPairCut)->GetName())); + histNames += Form("%s;", names[iPrefix].Data()); + } + fTrackHistNames[fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut] = names; + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + names = {}; + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + names.push_back(Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName())); + histNames += Form("%s;", names[iPrefix].Data()); + } + fTrackHistNames[(fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + icut * (fNPairCuts * fNCommonTrackCuts) + iCommonCut * (1 + fNPairCuts) + iPairCut] = names; + } // end loop (common cuts) + } // end loop (pair cuts) + } // end if (pair cuts) + + // assign hist directories for the MC matched triplets for each (leg cut combo,MCsignal) combination + if (!sigNamesStr.IsNull()) { + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { + auto sig = fRecMCSignals.at(isig); + names = {}; + int offset = fNLegCuts * isig * (1 + fNCommonTrackCuts + fNPairCuts + fNCommonTrackCuts * fNPairCuts); + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + names.push_back(Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), sig.GetName())); + histNames += Form("%s;", names[iPrefix].Data()); + } + if (fConfigReflectedHistograms.value) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + names.push_back(Form("%s_reflected_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), sig.GetName())); + histNames += Form("%s;", names[fNPairHistPrefixes + iPrefix].Data()); + } + } + fBarrelHistNamesMCmatched[offset + icut] = names; + + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + names = {}; + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + names.push_back(Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), sig.GetName())); + histNames += Form("%s;", names[iPrefix].Data()); + } + fBarrelHistNamesMCmatched[offset + fNLegCuts + icut * fNCommonTrackCuts + iCommonCut] = names; + } + + if (!cutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts + names = {}; + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + names.push_back(Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayPair->At(iPairCut)->GetName(), sig.GetName())); + histNames += Form("%s;", names[iPrefix].Data()); + } + fBarrelHistNamesMCmatched[offset + fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut] = names; + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + names = {}; + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + names.push_back(Form("%s_%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName(), sig.GetName())); + histNames += Form("%s;", names[iPrefix].Data()); + } + fBarrelHistNamesMCmatched[offset + (fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + icut * (fNPairCuts * fNCommonTrackCuts) + iCommonCut * (1 + fNPairCuts) + iPairCut] = names; + } // end loop (common cuts) + } // end loop (pair cuts) + } // end if (pair cuts) + } // end loop over MC signals + } // end if (MC signals) + } + } + + // Add histogram classes for each specified MCsignal at the generator level + // TODO: create a std::vector of hist classes to be used at Fill time, to avoid using Form in the process function + TString sigGenNamesStr = fConfigMCGenSignals.value; + std::unique_ptr objGenSigArray(sigGenNamesStr.Tokenize(",")); + for (int isig = 0; isig < objGenSigArray->GetEntries(); isig++) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objGenSigArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() == 1) { // NOTE: 1-prong signals required + fGenMCSignals.push_back(*sig); + histNames += Form("MCTruthGen_%s;", sig->GetName()); // TODO: Add these names to a std::vector to avoid using Form in the process function + } + } + } + + // Make sure the leg cuts are covered by the configured filter masks + if (fLegAFilterMask != fConstructedLegAFilterMask) { + LOGF(fatal, "cfgLegAFilterMask (%d) is not equal to the mask constructed by the cuts specified in cfgLegCuts (%d)!", fLegAFilterMask, fConstructedLegAFilterMask); + } + if (fLegBFilterMask != fConstructedLegBFilterMask) { + LOGF(fatal, "cfgLegBFilterMask (%d) is not equal to the mask constructed by the cuts specified in cfgLegCuts (%d)!", fLegBFilterMask, fConstructedLegBFilterMask); + } + if (fLegCFilterMask != fConstructedLegCFilterMask) { + LOGF(fatal, "cfgLegCFilterMask (%d) is not equal to the mask constructed by the cuts specified in cfgLegCuts (%d)!", fLegCFilterMask, fConstructedLegCFilterMask); + } + // Make sure only pairs or only triplets of leg cuts were given + int tripletCheckSum = std::count(isThreeProng.begin(), isThreeProng.end(), true); + if (tripletCheckSum != 0 && tripletCheckSum != fNLegCuts) { + LOGF(fatal, "A mix of pairs and triplets was given as leg cuts. Check your config!"); + } + + fCurrentRun = 0; + + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + + fLUT = o2::base::MatLayerCylSet::rectifyPtrFromFile(fCCDB->get(fConfigLutPath)); + VarManager::SetupMatLUTFwdDCAFitter(fLUT); + + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + DefineHistograms(fHistMan, histNames.Data(), fConfigHistogramSubgroups.value.data()); // define all histograms + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } + + void initParamsFromCCDB(uint64_t timestamp, bool isTriplets) + { + if (fConfigUseRemoteField.value) { + o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(fConfigGRPMagPath, timestamp); + float magField = 0.0; + if (grpmag != nullptr) { + magField = grpmag->getNominalL3Field(); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", timestamp); + } + if (isTriplets) { + if (fConfigUseKFVertexing.value) { + VarManager::SetupThreeProngKFParticle(magField); + } else { + VarManager::SetupThreeProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); + } + } else { + if (fConfigUseKFVertexing.value) { + VarManager::SetupTwoProngKFParticle(magField); + } else { + VarManager::SetupTwoProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); // TODO: get these parameters from Configurables + } + } + } else { + if (isTriplets) { + if (fConfigUseKFVertexing.value) { + VarManager::SetupThreeProngKFParticle(fConfigMagField.value); + } else { + VarManager::SetupThreeProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); + } + } else { + if (fConfigUseKFVertexing.value) { + VarManager::SetupTwoProngKFParticle(fConfigMagField.value); + } else { + VarManager::SetupTwoProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); // TODO: get these parameters from Configurables + } + } + } + } + + // Template function to run same event pairing with asymmetric pairs (e.g. kaon-pion) + template + void runAsymmetricPairing(TEvents const& events, Preslice& preslice, TTrackAssocs const& /*assocs*/, TTracks const& /*tracks*/, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& /*mcTracks*/) + { + fPairCount.clear(); + + if (events.size() > 0) { // Additional protection to avoid crashing of events.begin().runNumber() + if (fCurrentRun != events.begin().runNumber()) { + initParamsFromCCDB(events.begin().timestamp(), false); + fCurrentRun = events.begin().runNumber(); + } + } + + std::map> histNamesMC = fBarrelHistNamesMCmatched; + std::map> histNames = fTrackHistNames; + + int sign1 = 0; + int sign2 = 0; + uint32_t mcDecision = 0; + ditrackList.reserve(1); + ditrackExtraList.reserve(1); + + constexpr bool trackHasCov = ((TTrackFillMap & VarManager::ObjTypes::TrackCov) > 0 || (TTrackFillMap & VarManager::ObjTypes::ReducedTrackBarrelCov) > 0); + + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event, VarManager::fgValues); + + auto groupedLegAAssocs = legACandidateAssocs.sliceBy(preslice, event.globalIndex()); + if (groupedLegAAssocs.size() == 0) { + continue; + } + auto groupedLegBAssocs = legBCandidateAssocs.sliceBy(preslice, event.globalIndex()); + if (groupedLegBAssocs.size() == 0) { + continue; + } + + for (auto& [a1, a2] : combinations(soa::CombinationsFullIndexPolicy(groupedLegAAssocs, groupedLegBAssocs))) { + + uint32_t twoTrackFilter = 0; + uint32_t twoTrackCommonFilter = 0; + uint32_t pairFilter = 0; + bool isPairIdWrong = false; + for (int icut = 0; icut < fNLegCuts; ++icut) { + // Find leg pair definitions both candidates participate in + if ((a1.isBarrelSelected_raw() & fConstructedLegAFilterMasksMap[icut]) && (a2.isBarrelSelected_raw() & fConstructedLegBFilterMasksMap[icut])) { + twoTrackFilter |= static_cast(1) << icut; + // If the supposed pion passes a kaon cut, this is a K+K-. Skip it. + if (TPairType == VarManager::kDecayToKPi && fConfigSkipAmbiguousIdCombinations.value) { + if (a2.isBarrelSelected_raw() & fLegAFilterMask) { + isPairIdWrong = true; + } + } + } + } + + if (!twoTrackFilter || isPairIdWrong) { + continue; + } + + // Find common track cuts both candidates pass + twoTrackCommonFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & fCommonTrackCutMask; + + auto t1 = a1.template reducedtrack_as(); + auto t2 = a2.template reducedtrack_as(); + + // Avoid self-pairs + if (t1.globalIndex() == t2.globalIndex()) { + continue; + } + + bool isReflected = false; + std::pair trackIds(t1.globalIndex(), t2.globalIndex()); + if (fPairCount.find(trackIds) != fPairCount.end()) { + // Double counting is possible due to track-collision ambiguity. Skip pairs which were counted before + fPairCount[trackIds] += 1; + continue; + } + if (fPairCount.find(std::pair(trackIds.second, trackIds.first)) != fPairCount.end()) { + isReflected = true; + } + fPairCount[trackIds] += 1; + + sign1 = t1.sign(); + sign2 = t2.sign(); + // store the ambiguity number of the two dilepton legs in the last 4 digits of the two-track filter + if (t1.barrelAmbiguityInBunch() > 1 || t1.barrelAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= static_cast(1) << 30; + } + if (t2.barrelAmbiguityInBunch() > 1 || t2.barrelAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= static_cast(1) << 31; + } + + // run MC matching for this pair + int isig = 0; + mcDecision = 0; + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { + if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { + VarManager::FillPairMC(t1.reducedMCTrack(), t2.reducedMCTrack()); + if ((*sig).CheckSignal(true, t1.reducedMCTrack(), t2.reducedMCTrack())) { + mcDecision |= static_cast(1) << isig; + } + } + } // end loop over MC signals + + VarManager::FillPair(t1, t2); + if constexpr (TTwoProngFitter) { + VarManager::FillPairVertexing(event, t1, t2, fConfigPropToPCA); + } + + // Fill histograms + bool isAmbi = false; + for (int icut = 0; icut < fNLegCuts; icut++) { + if (twoTrackFilter & (static_cast(1) << icut)) { + isAmbi = (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)); + if (sign1 * sign2 < 0) { // +- pairs + fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); // reconstructed, unmatched + if (isAmbi && fConfigQA) { + fHistMan->FillHistClass(histNames[icut][fNPairHistPrefixes].Data(), VarManager::fgValues); + } + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(histNames[icut][fNPairHistPrefixes * (1 + fConfigQA.value)].Data(), VarManager::fgValues); + } + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { // ++ pairs + fHistMan->FillHistClass(histNames[icut][1].Data(), VarManager::fgValues); + if (isAmbi && fConfigQA) { + fHistMan->FillHistClass(histNames[icut][fNPairHistPrefixes + 1].Data(), VarManager::fgValues); + } + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(histNames[icut][fNPairHistPrefixes * (1 + fConfigQA.value) + 1].Data(), VarManager::fgValues); + } + } else { // -- pairs + fHistMan->FillHistClass(histNames[icut][2].Data(), VarManager::fgValues); + if (isAmbi && fConfigQA) { + fHistMan->FillHistClass(histNames[icut][fNPairHistPrefixes + 2].Data(), VarManager::fgValues); + } + if (isReflected && fConfigReflectedHistograms) { + fHistMan->FillHistClass(histNames[icut][fNPairHistPrefixes * (1 + fConfigQA.value) + 2].Data(), VarManager::fgValues); + } + } + } + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + int offset = fNLegCuts * isig * (1 + fNCommonTrackCuts + fNPairCuts + fNCommonTrackCuts * fNPairCuts); + if (mcDecision & (static_cast(1) << isig)) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(histNamesMC[offset + icut][0].Data(), VarManager::fgValues); + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(histNamesMC[offset + icut][fNPairHistPrefixes].Data(), VarManager::fgValues); + } + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(histNamesMC[offset + icut][1].Data(), VarManager::fgValues); + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(histNamesMC[offset + icut][fNPairHistPrefixes + 1].Data(), VarManager::fgValues); + } + } else { + fHistMan->FillHistClass(histNamesMC[offset + icut][2].Data(), VarManager::fgValues); + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(histNamesMC[offset + icut][fNPairHistPrefixes + 2].Data(), VarManager::fgValues); + } + } + } + } + } + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (twoTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(histNames[fNLegCuts + icut * fNCommonTrackCuts + iCommonCut][0].Data(), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(histNames[fNLegCuts + icut * fNCommonTrackCuts + iCommonCut][1].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNames[fNLegCuts + icut * fNCommonTrackCuts + iCommonCut][2].Data(), VarManager::fgValues); + } + } + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + int offset = fNLegCuts * isig * (1 + fNCommonTrackCuts + fNPairCuts + fNCommonTrackCuts * fNPairCuts); + if (mcDecision & (static_cast(1) << isig)) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(histNamesMC[offset + fNLegCuts + icut * fNCommonTrackCuts + iCommonCut][0].Data(), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(histNamesMC[offset + fNLegCuts + icut * fNCommonTrackCuts + iCommonCut][1].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNamesMC[offset + fNLegCuts + icut * fNCommonTrackCuts + iCommonCut][2].Data(), VarManager::fgValues); + } + } + } + } + } + } // end loop (common cuts) + int iPairCut = 0; + for (auto cut = fPairCuts.begin(); cut != fPairCuts.end(); cut++, iPairCut++) { + if (!((*cut)->IsSelected(VarManager::fgValues))) // apply pair cuts + continue; + pairFilter |= (static_cast(1) << iPairCut); + // Histograms with pair cuts + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(histNames[fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut][0].Data(), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(histNames[fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut][1].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNames[fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut][2].Data(), VarManager::fgValues); + } + } + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + int offset = fNLegCuts * isig * (1 + fNCommonTrackCuts + fNPairCuts + fNCommonTrackCuts * fNPairCuts); + if (mcDecision & (static_cast(1) << isig)) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(histNamesMC[offset + fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut][0].Data(), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(histNamesMC[offset + fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut][1].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNamesMC[offset + fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut][2].Data(), VarManager::fgValues); + } + } + } + } + // Histograms with pair cuts and common track cuts + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + if (twoTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(histNames[(fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + icut * (fNPairCuts * fNCommonTrackCuts) + iCommonCut * (1 + fNPairCuts) + iPairCut][0].Data(), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(histNames[(fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + icut * (fNPairCuts * fNCommonTrackCuts) + iCommonCut * (1 + fNPairCuts) + iPairCut][1].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNames[(fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + icut * (fNPairCuts * fNCommonTrackCuts) + iCommonCut * (1 + fNPairCuts) + iPairCut][2].Data(), VarManager::fgValues); + } + } + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + int offset = fNLegCuts * isig * (1 + fNCommonTrackCuts + fNPairCuts + fNCommonTrackCuts * fNPairCuts); + if (mcDecision & (static_cast(1) << isig)) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(histNamesMC[offset + (fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + icut * (fNPairCuts * fNCommonTrackCuts) + iCommonCut * (1 + fNPairCuts) + iPairCut][0].Data(), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(histNamesMC[offset + (fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + icut * (fNPairCuts * fNCommonTrackCuts) + iCommonCut * (1 + fNPairCuts) + iPairCut][1].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNamesMC[offset + (fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + icut * (fNPairCuts * fNCommonTrackCuts) + iCommonCut * (1 + fNPairCuts) + iPairCut][2].Data(), VarManager::fgValues); + } + } + } + } + } + } + } // end loop (pair cuts) + } + } // end loop (cuts) + ditrackList(event.globalIndex(), VarManager::fgValues[VarManager::kMass], + VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], + t1.sign() + t2.sign(), twoTrackFilter, pairFilter, twoTrackCommonFilter); + if constexpr (trackHasCov && TTwoProngFitter) { + ditrackExtraList(t1.globalIndex(), t2.globalIndex(), VarManager::fgValues[VarManager::kVertexingTauzProjected], VarManager::fgValues[VarManager::kVertexingLzProjected], VarManager::fgValues[VarManager::kVertexingLxyProjected]); + } + } // end inner assoc loop (leg A) + } // end event loop + } + + // Template function to run same event triplets (e.g. D+->K-pi+pi+) + template + void runThreeProng(TEvents const& events, Preslice& preslice, TTrackAssocs const& /*assocs*/, TTracks const& tracks, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& /*mcTracks*/, VarManager::PairCandidateType tripletType) + { + if (events.size() > 0) { // Additional protection to avoid crashing of events.begin().runNumber() + if (fCurrentRun != events.begin().runNumber()) { + initParamsFromCCDB(events.begin().timestamp(), true); + fCurrentRun = events.begin().runNumber(); + } + } + + std::map> histNames = fTrackHistNames; + std::map> histNamesMC = fBarrelHistNamesMCmatched; + + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event, VarManager::fgValues); + + auto groupedLegAAssocs = legACandidateAssocs.sliceBy(preslice, event.globalIndex()); + if (groupedLegAAssocs.size() == 0) { + continue; + } + auto groupedLegBAssocs = legBCandidateAssocs.sliceBy(preslice, event.globalIndex()); + if (groupedLegBAssocs.size() == 0) { + continue; + } + auto groupedLegCAssocs = legCCandidateAssocs.sliceBy(preslice, event.globalIndex()); + if (groupedLegCAssocs.size() == 0) { + continue; + } + + // Based on triplet type, make suitable combinations of the partitions + if (tripletType == VarManager::kTripleCandidateToPKPi) { + for (auto& [a1, a2, a3] : combinations(soa::CombinationsFullIndexPolicy(groupedLegAAssocs, groupedLegBAssocs, groupedLegCAssocs))) { + readTriplet(a1, a2, a3, tracks, event, tripletType, histNames, histNamesMC); + } + } else if (tripletType == VarManager::kTripleCandidateToKPiPi) { + for (auto& a1 : groupedLegAAssocs) { + for (auto& [a2, a3] : combinations(groupedLegBAssocs, groupedLegCAssocs)) { + readTriplet(a1, a2, a3, tracks, event, tripletType, histNames, histNamesMC); + } + } + } else { + LOG(fatal) << "Given tripletType not recognized. Don't know how to make combinations!" << endl; + } + } // end event loop + } + + // Helper function to process triplet + template + void readTriplet(TTrackAssoc const& a1, TTrackAssoc const& a2, TTrackAssoc const& a3, TTracks const& /*tracks*/, TEvent const& event, VarManager::PairCandidateType tripletType, std::map> histNames, std::map> histNamesMC) + { + uint32_t mcDecision = 0; + + uint32_t threeTrackFilter = 0; + uint32_t threeTrackCommonFilter = 0; + for (int icut = 0; icut < fNLegCuts; ++icut) { + // Find out which leg cut combinations the triplet passes + if ((a1.isBarrelSelected_raw() & fConstructedLegAFilterMasksMap[icut]) && (a2.isBarrelSelected_raw() & fConstructedLegBFilterMasksMap[icut]) && (a3.isBarrelSelected_raw() & fConstructedLegCFilterMasksMap[icut])) { + threeTrackFilter |= (static_cast(1) << icut); + if (tripletType == VarManager::kTripleCandidateToPKPi && fConfigSkipAmbiguousIdCombinations.value) { + // Check if the supposed pion passes as a proton or kaon, if so, skip this triplet. It is pKp or pKK. + if ((a3.isBarrelSelected_raw() & fLegAFilterMask) || (a3.isBarrelSelected_raw() & fLegBFilterMask)) { + return; + } + // Check if the supposed kaon passes as a proton, if so, skip this triplet. It is ppPi. + if (a2.isBarrelSelected_raw() & fLegAFilterMask) { + return; + } + } + if (tripletType == VarManager::kTripleCandidateToKPiPi && fConfigSkipAmbiguousIdCombinations.value) { + // Check if one of the supposed pions pass as a kaon, if so, skip this triplet. It is KKPi. + if ((a2.isBarrelSelected_raw() & fLegAFilterMask) || (a3.isBarrelSelected_raw() & fLegAFilterMask)) { + return; + } + } + } + } + if (!threeTrackFilter) { + return; + } + + // Find common track cuts all candidates pass + threeTrackCommonFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & a3.isBarrelSelected_raw() & fCommonTrackCutMask; + + auto t1 = a1.template reducedtrack_as(); + auto t2 = a2.template reducedtrack_as(); + auto t3 = a3.template reducedtrack_as(); + + // Avoid self-pairs + if (t1 == t2 || t1 == t3 || t2 == t3) { + return; + } + // Check charge + if (tripletType == VarManager::kTripleCandidateToKPiPi) { + if (!((t1.sign() == -1 && t2.sign() == 1 && t3.sign() == 1) || (t1.sign() == 1 && t2.sign() == -1 && t3.sign() == -1))) { + return; + } + } + if (tripletType == VarManager::kTripleCandidateToPKPi) { + if (!((t1.sign() == 1 && t2.sign() == -1 && t3.sign() == 1) || (t1.sign() == -1 && t2.sign() == 1 && t3.sign() == -1))) { + return; + } + } + + // store the ambiguity of the three legs in the last 3 digits of the two-track filter + if (t1.barrelAmbiguityInBunch() > 1 || t1.barrelAmbiguityOutOfBunch() > 1) { + threeTrackFilter |= (static_cast(1) << 29); + } + if (t2.barrelAmbiguityInBunch() > 1 || t2.barrelAmbiguityOutOfBunch() > 1) { + threeTrackFilter |= (static_cast(1) << 30); + } + if (t3.barrelAmbiguityInBunch() > 1 || t3.barrelAmbiguityOutOfBunch() > 1) { + threeTrackFilter |= (static_cast(1) << 31); + } + + // run MC matching for this triplet + int isig = 0; + mcDecision = 0; + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { + if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack() && t3.has_reducedMCTrack()) { + if ((*sig).CheckSignal(true, t1.reducedMCTrack(), t2.reducedMCTrack(), t3.reducedMCTrack())) { + mcDecision |= (static_cast(1) << isig); + } + } + } // end loop over MC signals + + VarManager::FillTriple(t1, t2, t3, VarManager::fgValues, tripletType); + if constexpr (TThreeProngFitter) { + VarManager::FillTripletVertexing(event, t1, t2, t3, tripletType); + } + + // Fill histograms + bool isAmbi = false; + for (int icut = 0; icut < fNLegCuts; icut++) { + isAmbi = (threeTrackFilter & (static_cast(1) << 29)) || (threeTrackFilter & (static_cast(1) << 30)) || (threeTrackFilter & (static_cast(1) << 31)); + if (threeTrackFilter & (static_cast(1) << icut)) { + fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); + // TODO: loop over MC signals + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + int offset = fNLegCuts * isig * (1 + fNCommonTrackCuts + fNPairCuts + fNCommonTrackCuts * fNPairCuts); + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(histNamesMC[offset + icut][0].Data(), VarManager::fgValues); // matched signal + } + } // end loop (MC signals) + if (fConfigQA && isAmbi) { + fHistMan->FillHistClass(histNames[icut][1].Data(), VarManager::fgValues); + } + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (threeTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + fHistMan->FillHistClass(histNames[fNLegCuts + icut * fNCommonTrackCuts + iCommonCut][0].Data(), VarManager::fgValues); + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + int offset = fNLegCuts * isig * (1 + fNCommonTrackCuts + fNPairCuts + fNCommonTrackCuts * fNPairCuts); + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(histNamesMC[offset + fNLegCuts + icut * fNCommonTrackCuts + iCommonCut][0].Data(), VarManager::fgValues); // matched signal + } + } // end loop (MC signals) + } + } // end loop (common cuts) + int iPairCut = 0; + for (auto cut = fPairCuts.begin(); cut != fPairCuts.end(); cut++, iPairCut++) { + if (!((*cut)->IsSelected(VarManager::fgValues))) // apply pair cuts + continue; + // Histograms with pair cuts + fHistMan->FillHistClass(histNames[fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut][0].Data(), VarManager::fgValues); + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + int offset = fNLegCuts * isig * (1 + fNCommonTrackCuts + fNPairCuts + fNCommonTrackCuts * fNPairCuts); + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(histNamesMC[offset + fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut][0].Data(), VarManager::fgValues); // matched signal + } + } // end loop (MC signals) + // Histograms with pair cuts and common track cuts + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + if (threeTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + fHistMan->FillHistClass(histNames[(fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + icut * (fNPairCuts * fNCommonTrackCuts + 1) + iCommonCut * (1 + fNPairCuts) + iPairCut][0].Data(), VarManager::fgValues); + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + int offset = fNLegCuts * isig * (1 + fNCommonTrackCuts + fNPairCuts + fNCommonTrackCuts * fNPairCuts); + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(histNamesMC[offset + (fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + icut * (fNPairCuts * fNCommonTrackCuts) + iCommonCut * (1 + fNPairCuts) + iPairCut][0].Data(), VarManager::fgValues); // matched signal + } + } // end loop (MC signals) + } + } + } // end loop (pair cuts) + } + } // end loop (cuts) + } + + PresliceUnsorted perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; + + void runMCGen(ReducedMCTracks const& mcTracks) + { + // loop over mc stack and fill histograms for pure MC truth signals + // group all the MC tracks which belong to the MC event corresponding to the current reconstructed event + for (auto& mctrack : mcTracks) { + VarManager::FillTrackMC(mcTracks, mctrack); + // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. + // NOTE: However, the working model is that the decisions on MC signals are precomputed during skimming and are stored in the mcReducedFlags member. + // TODO: Use the mcReducedFlags to select signals + for (auto& sig : fGenMCSignals) { + if (sig.GetNProngs() != 1) { // NOTE: 1-prong signals required here + continue; + } + bool checked = false; + checked = sig.CheckSignal(true, mctrack); + if (checked) { + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig.GetName()), VarManager::fgValues); + } + } + } + } // end runMCGen + + void processKaonPionSkimmed(MyEventsVtxCovSelected const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, + ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + runAsymmetricPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); + if (fConfigRunMCGenPair) + runMCGen(mcTracks); + } + + void processKaonPionPionSkimmed(MyEventsVtxCovSelected const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, + ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + runThreeProng(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks, VarManager::kTripleCandidateToKPiPi); + if (fConfigRunMCGenPair) + runMCGen(mcTracks); + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisAsymmetricPairing, processKaonPionSkimmed, "Run kaon pion pairing, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisAsymmetricPairing, processKaonPionPionSkimmed, "Run kaon pion pion triplets, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisAsymmetricPairing, processDummy, "Dummy function, enabled only if none of the others are enabled", true); +}; + +// Combines dileptons with barrel or muon tracks for either resonance or correlation analyses +// Dileptons produced with all the selection cuts specified in the same-event pairing task are combined with the +// tracks passing the fConfigTrackCut cut. The dileptons cuts from the same-event pairing task are auto-detected +struct AnalysisDileptonTrack { + Produces BmesonsTable; + OutputObj fOutputList{"output"}; + + Configurable fConfigTrackCuts{"cfgTrackCuts", "kaonPID", "Comma separated list of track cuts to be correlated with the dileptons"}; + Configurable fConfigDileptonLowMass{"cfgDileptonLowMass", 2.8, "Low mass cut for the dileptons used in analysis"}; + Configurable fConfigDileptonHighMass{"cfgDileptonHighMass", 3.2, "High mass cut for the dileptons used in analysis"}; + Configurable fConfigDileptonpTCut{"cfgDileptonpTCut", 0.0, "pT cut for dileptons used in the triplet vertexing"}; + Configurable fConfigDileptonLxyCut{"cfgDileptonLxyCut", 0.0, "Lxy cut for dileptons used in the triplet vertexing"}; + Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; + + Configurable fConfigHistogramSubgroups{"cfgDileptonTrackHistogramsSubgroups", "invmass,vertexing", "Comma separated list of dilepton-track histogram subgroups"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + + Configurable fConfigUseRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; + Configurable fConfigGRPmagPath{"cfgGrpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; + + Configurable fConfigMCRecSignals{"cfgMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; + Configurable fConfigMCGenSignals{"cfgMCGenSignals", "", "Comma separated list of MC signals (generated)"}; + Configurable fConfigMCRecSignalsJSON{"cfgMCRecSignalsJSON", "", "Additional list of MC signals (reconstructed) via JSON"}; + Configurable fConfigMCGenSignalsJSON{"cfgMCGenSignalsJSON", "", "Comma separated list of MC signals (generated) via JSON"}; + Configurable fConfigMCGenSignalDileptonLegPos{"cfgMCGenSignalDileptonLegPos", 0, "generator level positive dilepton leg signal (bit number according to table-maker)"}; + Configurable fConfigMCGenSignalDileptonLegNeg{"cfgMCGenSignalDileptonLegNeg", 0, "generator level negative dilepton leg signal (bit number according to table-maker)"}; + Configurable fConfigMCGenSignalHadron{"cfgMCGenSignalHadron", 0, "generator level associated hadron signal (bit number according to table-maker)"}; + Configurable fConfigMCGenDileptonLegPtMin{"cfgMCGenDileptonLegPtMin", 1.0f, "minimum pt for the dilepton leg"}; + Configurable fConfigMCGenHadronPtMin{"cfgMCGenHadronPtMin", 1.0f, "minimum pt for the hadron"}; + Configurable fConfigMCGenDileptonLegEtaAbs{"cfgMCGenDileptonLegEtaAbs", 0.9f, "eta abs range for the dilepton leg"}; + Configurable fConfigMCGenHadronEtaAbs{"cfgMCGenHadronEtaAbs", 0.9f, "eta abs range for the hadron"}; + + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + int fNCuts; + int fNPairCuts; + int fNCommonTrackCuts; + std::map fCommonTrackCutMap; + uint32_t fTrackCutBitMap; // track cut bit mask to be used in the selection of tracks associated with dileptons + // vector for single-lepton and track cut names for easy access when calling FillHistogramList() + std::vector fTrackCutNames; + // vector for pair cut names, used mainly for pairs built via the asymmetric pairing task + std::vector fPairCutNames; + std::vector fCommonPairCutNames; + + Service fCCDB; + + // TODO: The filter expressions seem to always use the default value of configurables, not the values from the actual configuration file + Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); + Filter dileptonFilter = aod::reducedpair::pt > fConfigDileptonpTCut&& aod::reducedpair::mass > fConfigDileptonLowMass&& aod::reducedpair::mass fConfigDileptonLxyCut; + Filter filterBarrel = aod::dqanalysisflags::isBarrelSelected > static_cast(0); + Filter filterMuon = aod::dqanalysisflags::isMuonSelected > static_cast(0); + + constexpr static uint32_t fgDileptonFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::Pair; // fill map + + // use two values array to avoid mixing up the quantities + float* fValuesDilepton; + float* fValuesHadron; + HistogramManager* fHistMan; + + std::vector fRecMCSignals; + std::vector fGenMCSignals; + + void init(o2::framework::InitContext& context) + { + bool isBarrel = context.mOptions.get("processBarrelSkimmed"); + bool isBarrelAsymmetric = context.mOptions.get("processDstarToD0Pi"); + bool isMuon = context.mOptions.get("processMuonSkimmed"); + bool isMCGen = context.mOptions.get("processMCGen") || context.mOptions.get("processMCGenWithEventSelection"); + bool isDummy = context.mOptions.get("processDummy"); + + if (isDummy) { + if (isBarrel || isMuon || isBarrelAsymmetric || isMCGen) { + LOG(fatal) << "Dummy function is enabled even if there are normal process functions running! Fix your config!" << endl; + } else { + LOG(info) << "Dummy function is enabled. Skipping the rest of the init function" << endl; + return; + } + } + + fCurrentRun = 0; + fValuesDilepton = new float[VarManager::kNVars]; + fValuesHadron = new float[VarManager::kNVars]; + fTrackCutBitMap = 0; + VarManager::SetDefaultVarNames(); + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(true); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + TString sigNamesStr = fConfigMCRecSignals.value; + std::unique_ptr objRecSigArray(sigNamesStr.Tokenize(",")); + if (!sigNamesStr.IsNull()) { + for (int isig = 0; isig < objRecSigArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objRecSigArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() != 3) { + LOG(fatal) << "Signal at reconstructed level requested (" << sig->GetName() << ") " << "does not have 3 prongs! Fix it"; + } + fRecMCSignals.push_back(sig); + } else { + LOG(fatal) << "Signal at reconstructed level requested (" << objRecSigArray->At(isig)->GetName() << ") " << "could not be retrieved from the library! -> skipped"; + } + } + } + + // Add the reco MCSignals from the JSON config + TString addMCSignalsStr = fConfigMCRecSignalsJSON.value; + if (addMCSignalsStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); + for (auto& mcIt : addMCSignals) { + if (mcIt->GetNProngs() != 3) { + LOG(fatal) << "Signal at reconstructed level requested (" << mcIt->GetName() << ") " << "does not have 3 prongs! Fix it"; + } + fRecMCSignals.push_back(mcIt); + } + } + + // Add histogram classes for each specified MCsignal at the generator level + // TODO: create a std::vector of hist classes to be used at Fill time, to avoid using Form in the process function + TString sigGenNamesStr = fConfigMCGenSignals.value; + std::unique_ptr objGenSigArray(sigGenNamesStr.Tokenize(",")); + for (int isig = 0; isig < objGenSigArray->GetEntries(); isig++) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objGenSigArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() == 1) { // NOTE: 1-prong signals required + fGenMCSignals.push_back(sig); + } + } + } + + // Add the gen MCSignals from the JSON config + addMCSignalsStr = fConfigMCGenSignalsJSON.value; + if (addMCSignalsStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); + for (auto& mcIt : addMCSignals) { + if (mcIt->GetNProngs() == 1) { + fGenMCSignals.push_back(mcIt); + } + } + } + + // For each track/muon selection used to produce dileptons, create a separate histogram directory using the + // name of the track/muon cut. + + // Get the list of single track and muon cuts computed in the dedicated tasks upstream + // We need this to know the order in which they were computed, and also to make sure that in this task we do not ask + // for cuts which were not computed (in which case this will trigger a fatal) + string cfgTrackSelection_TrackCuts; + if (isBarrel || isBarrelAsymmetric) { + getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", cfgTrackSelection_TrackCuts, false); + } else { + getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCuts", cfgTrackSelection_TrackCuts, false); + } + TObjArray* cfgTrackSelection_objArrayTrackCuts = nullptr; + if (!cfgTrackSelection_TrackCuts.empty()) { + cfgTrackSelection_objArrayTrackCuts = TString(cfgTrackSelection_TrackCuts).Tokenize(","); + } + // get also the list of cuts specified via the JSON parameters + if (isBarrel || isBarrelAsymmetric) { + getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", cfgTrackSelection_TrackCuts, false); + } else { + getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCutsJSON", cfgTrackSelection_TrackCuts, false); + } + if (!cfgTrackSelection_TrackCuts.empty()) { + if (cfgTrackSelection_objArrayTrackCuts == nullptr) { + cfgTrackSelection_objArrayTrackCuts = new TObjArray(); + } + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(cfgTrackSelection_TrackCuts.data()); + for (auto& t : addTrackCuts) { + TObjString* tempObjStr = new TObjString(t->GetName()); + cfgTrackSelection_objArrayTrackCuts->Add(tempObjStr); + } + } + if (cfgTrackSelection_objArrayTrackCuts->GetEntries() == 0) { + LOG(fatal) << " No track cuts found in the barrel or muon upstream tasks"; + } + // store all the computed track cut names in a vector + for (int icut = 0; icut < cfgTrackSelection_objArrayTrackCuts->GetEntries(); icut++) { + fTrackCutNames.push_back(cfgTrackSelection_objArrayTrackCuts->At(icut)->GetName()); + } + // get the list of associated track cuts to be combined with the dileptons, + // check that these were computed upstream, and create a bit mask + TObjArray* cfgDileptonTrack_objArrayTrackCuts = nullptr; + if (!fConfigTrackCuts.value.empty()) { + cfgDileptonTrack_objArrayTrackCuts = TString(fConfigTrackCuts.value).Tokenize(","); + } else { + LOG(fatal) << " No track cuts specified! Check it out!"; + } + // loop over these cuts and check they were computed upstream (otherwise trigger a fatal) + for (int icut = 0; icut < cfgDileptonTrack_objArrayTrackCuts->GetEntries(); icut++) { + if (!cfgTrackSelection_objArrayTrackCuts->FindObject(cfgDileptonTrack_objArrayTrackCuts->At(icut)->GetName())) { + LOG(fatal) << "Specified track cut (" << cfgDileptonTrack_objArrayTrackCuts->At(icut)->GetName() << ") not found in the list of computed cuts by the single barrel / muon selection tasks"; + } + } + // loop over all the upstream cuts and make a bit mask for the track cuts specified in this task + for (int icut = 0; icut < cfgTrackSelection_objArrayTrackCuts->GetEntries(); icut++) { + if (cfgDileptonTrack_objArrayTrackCuts->FindObject(cfgTrackSelection_objArrayTrackCuts->At(icut)->GetName())) { + fTrackCutBitMap |= (uint32_t(1) << icut); + } + } + // finally, store the total number of upstream tasks, for easy access + fNCuts = fTrackCutNames.size(); + + // get the cuts employed for same-event pairing + // NOTE: The track/muon cuts in analysis-same-event-pairing are used to select electrons/muons to build dielectrons/dimuons + // NOTE: The cfgPairCuts in analysis-same-event-pairing are used to apply an additional selection on top of the already produced dileptons + // but this is only used for histograms, not for the produced dilepton tables + string cfgPairing_TrackCuts; + string cfgPairing_PairCuts; + string cfgPairing_CommonTrackCuts; + if (isBarrel) { + getTaskOptionValue(context, "analysis-same-event-pairing", "cfgTrackCuts", cfgPairing_TrackCuts, false); + getTaskOptionValue(context, "analysis-same-event-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); + } else if (isMuon) { + getTaskOptionValue(context, "analysis-same-event-pairing", "cfgMuonCuts", cfgPairing_TrackCuts, false); + getTaskOptionValue(context, "analysis-same-event-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); + } else if (isBarrelAsymmetric) { + getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgLegCuts", cfgPairing_TrackCuts, false); + getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); + getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgCommonTrackCuts", cfgPairing_CommonTrackCuts, false); + } + if (cfgPairing_TrackCuts.empty()) { + LOG(fatal) << "There are no dilepton cuts specified in the upstream in the same-event-pairing or assymmetric-pairing"; + } + + // If asymmetric pair is used, it may have common track cuts + TString cfgPairing_strCommonTrackCuts = cfgPairing_CommonTrackCuts; + if (!cfgPairing_strCommonTrackCuts.IsNull()) { // if common track cuts + std::unique_ptr objArrayCommon(cfgPairing_strCommonTrackCuts.Tokenize(",")); + fNCommonTrackCuts = objArrayCommon->GetEntries(); + for (int icut = 0; icut < fNCommonTrackCuts; ++icut) { + for (int iicut = 0; iicut < cfgTrackSelection_objArrayTrackCuts->GetEntries(); iicut++) { + if (std::strcmp(cfgTrackSelection_objArrayTrackCuts->At(iicut)->GetName(), objArrayCommon->At(icut)->GetName()) == 0) { + fCommonTrackCutMap[icut] = iicut; + fCommonPairCutNames.push_back(objArrayCommon->At(icut)->GetName()); + } + } + } + } // end if (common cuts) + + std::unique_ptr objArrayPairCuts(TString(cfgPairing_PairCuts).Tokenize(",")); + fNPairCuts = objArrayPairCuts->GetEntries(); + for (int j = 0; j < fNPairCuts; j++) { + fPairCutNames.push_back(objArrayPairCuts->At(j)->GetName()); + } + + // array of single lepton cuts specified in the same-analysis-pairing task + std::unique_ptr cfgPairing_objArrayTrackCuts(TString(cfgPairing_TrackCuts).Tokenize(",")); + + // loop over single lepton cuts + if (isBarrel || isBarrelAsymmetric || isMuon) { + for (int icut = 0; icut < fNCuts; ++icut) { + + // here we check that this cut is one of those used for building the dileptons + if (!cfgPairing_objArrayTrackCuts->FindObject(fTrackCutNames[icut].Data())) { + continue; + } + + TString pairLegCutName = fTrackCutNames[icut].Data(); + // define dilepton histograms + DefineHistograms(fHistMan, Form("DileptonsSelected_%s", pairLegCutName.Data()), "barrel,vertexing"); + // loop over track cuts and create dilepton - track histogram directories + for (int iCutTrack = 0; iCutTrack < fNCuts; iCutTrack++) { + + // here we check that this track cut is one of those required to associate with the dileptons + if (!(fTrackCutBitMap & (uint32_t(1) << iCutTrack))) { + continue; + } + + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s", pairLegCutName.Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); + for (auto& sig : fRecMCSignals) { + DefineHistograms(fHistMan, Form("DileptonTrackMCMatched_%s_%s_%s", pairLegCutName.Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + + if (!cfgPairing_strCommonTrackCuts.IsNull()) { + std::unique_ptr objArrayCommon(cfgPairing_strCommonTrackCuts.Tokenize(",")); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); + for (auto& sig : fRecMCSignals) { + DefineHistograms(fHistMan, Form("DileptonTrackMCMatched_%s_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data()), "barrel,vertexing"); + } + } + + if (fNPairCuts != 0) { + + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s", pairLegCutName.Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); + for (auto& sig : fRecMCSignals) { + DefineHistograms(fHistMan, Form("DileptonTrackMCMatched_%s_%s_%s_%s", pairLegCutName.Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s", pairLegCutName.Data(), fPairCutNames[iPairCut].Data()), "barrel,vertexing"); + + if (!cfgPairing_strCommonTrackCuts.IsNull()) { + std::unique_ptr objArrayCommon(cfgPairing_strCommonTrackCuts.Tokenize(",")); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); + for (auto& sig : fRecMCSignals) { + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), "barrel,vertexing"); + } + } + } + } + } // end loop over track cuts to be combined with dileptons / di-tracks + } // end loop over pair leg track cuts + } // end if (isBarrel || isBarrelAsymmetric || isMuon) + + if (isMCGen) { + for (auto& sig : fGenMCSignals) { + DefineHistograms(fHistMan, Form("MCTruthGen_%s", sig->GetName()), ""); + DefineHistograms(fHistMan, Form("MCTruthGenSel_%s", sig->GetName()), ""); + } + DefineHistograms(fHistMan, "MCTruthGenAccepted", ""); + } + + TString addHistsStr = fConfigAddJSONHistograms.value; + if (addHistsStr != "") { + dqhistograms::AddHistogramsFromJSON(fHistMan, addHistsStr.Data()); + } + VarManager::SetUseVars(fHistMan->GetUsedVars()); + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } + + // init parameters from CCDB + void initParamsFromCCDB(uint64_t timestamp) + { + if (fConfigUseRemoteField.value) { + o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(fConfigGRPmagPath.value, timestamp); + float magField = 0.0; + if (grpmag != nullptr) { + magField = grpmag->getNominalL3Field(); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", timestamp); + } + if (fConfigUseKFVertexing.value) { + VarManager::SetupThreeProngKFParticle(magField); + } else { + VarManager::SetupThreeProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables + } + } else { + if (fConfigUseKFVertexing.value) { + VarManager::SetupThreeProngKFParticle(fConfigMagField.value); + } else { + VarManager::SetupThreeProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables + } + } + } + + // Template function to run pair - hadron combinations + template + void runDileptonHadron(TEvent const& event, TTrackAssocs const& assocs, TTracks const& tracks, TDileptons const& dileptons, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& /*mcTracks*/) + { + VarManager::ResetValues(0, VarManager::kNVars, fValuesHadron); + VarManager::ResetValues(0, VarManager::kNVars, fValuesDilepton); + VarManager::FillEvent(event, fValuesHadron); + VarManager::FillEvent(event.reducedMCevent(), fValuesHadron); + VarManager::FillEvent(event, fValuesDilepton); + VarManager::FillEvent(event.reducedMCevent(), fValuesDilepton); + + uint32_t mcDecision = static_cast(0); + size_t isig = 0; + + for (auto dilepton : dileptons) { + // get full track info of tracks based on the index + auto lepton1 = tracks.rawIteratorAt(dilepton.index0Id()); + auto lepton2 = tracks.rawIteratorAt(dilepton.index1Id()); + auto lepton1MC = lepton1.reducedMCTrack(); + auto lepton2MC = lepton2.reducedMCTrack(); + // Check that the dilepton has zero charge + if (dilepton.sign() != 0) { + continue; + } + + VarManager::FillTrack(dilepton, fValuesDilepton); + + // fill selected dilepton histograms for each specified selection + for (int icut = 0; icut < fNCuts; icut++) { + + if (!dilepton.filterMap_bit(icut)) { + continue; + } + + // regular dileptons + fHistMan->FillHistClass(Form("DileptonsSelected_%s", fTrackCutNames[icut].Data()), fValuesDilepton); + + // other pairs, e.g.: D0s + if constexpr (TCandidateType == VarManager::kDstarToD0KPiPi) { // Dielectrons and Dimuons don't have the PairFilterMap column + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { + fHistMan->FillHistClass(Form("DileptonsSelected_%s_%s", fTrackCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data()), fValuesDilepton); + } + } + for (int iPairCut = 0; iPairCut < fNPairCuts; iPairCut++) { + if (dilepton.pairFilterMap_bit(iPairCut)) { + fHistMan->FillHistClass(Form("DileptonsSelected_%s_%s", fTrackCutNames[icut].Data(), fPairCutNames[icut].Data()), fValuesDilepton); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { + fHistMan->FillHistClass(Form("DileptonsSelected_%s_%s_%s", fTrackCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[icut].Data()), fValuesDilepton); + } + } + } + } + } + } + + // loop over track associations + for (auto& assoc : assocs) { + + uint32_t trackSelection = 0; + if constexpr (TCandidateType == VarManager::kBtoJpsiEEK) { + // check the cuts fulfilled by this candidate track; if none just continue + trackSelection = (assoc.isBarrelSelected_raw() & fTrackCutBitMap); + if (!trackSelection) { + continue; + } + // get the track from this association + auto track = assoc.template reducedtrack_as(); + // check that this track is not included in the current dilepton + if (track.globalIndex() == dilepton.index0Id() || track.globalIndex() == dilepton.index1Id()) { + continue; + } + // compute needed quantities + VarManager::FillDileptonHadron(dilepton, track, fValuesHadron); + VarManager::FillDileptonTrackVertexing(event, lepton1, lepton2, track, fValuesHadron); + + auto trackMC = track.reducedMCTrack(); + mcDecision = 0; + isig = 0; + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { + if ((*sig)->CheckSignal(true, lepton1MC, lepton2MC, trackMC)) { + mcDecision |= (static_cast(1) << isig); + } + } + } + + if constexpr (TCandidateType == VarManager::kDstarToD0KPiPi) { + trackSelection = (assoc.isBarrelSelected_raw() & fTrackCutBitMap); + if (!trackSelection) { + continue; + } + + auto track = assoc.template reducedtrack_as(); + if (track.globalIndex() == dilepton.index0Id() || track.globalIndex() == dilepton.index1Id()) { + continue; + } + // Check that the charge combination makes sense for D*+ -> D0 pi+ or D*- -> D0bar pi- + if (!((track.sign() == 1 && lepton1.sign() == -1 && lepton2.sign() == 1) || (track.sign() == -1 && lepton1.sign() == 1 && lepton2.sign() == -1))) { + continue; + } + VarManager::FillDileptonHadron(dilepton, track, fValuesHadron); + VarManager::FillDileptonTrackVertexing(event, lepton1, lepton2, track, fValuesHadron); + + auto trackMC = track.reducedMCTrack(); + mcDecision = 0; + isig = 0; + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { + if ((*sig)->CheckSignal(true, lepton1MC, lepton2MC, trackMC)) { + mcDecision |= (static_cast(1) << isig); + } + } + } + + if constexpr (TCandidateType == VarManager::kBcToThreeMuons) { + trackSelection = (assoc.isMuonSelected_raw() & fTrackCutBitMap); + if (!trackSelection) { + continue; + } + + auto track = assoc.template reducedmuon_as(); + if (track.globalIndex() == dilepton.index0Id() || track.globalIndex() == dilepton.index1Id()) { + continue; + } + + VarManager::FillDileptonHadron(dilepton, track, fValuesHadron); + VarManager::FillDileptonTrackVertexing(event, lepton1, lepton2, track, fValuesHadron); + + auto trackMC = track.reducedMCTrack(); + mcDecision = 0; + isig = 0; + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { + if ((*sig)->CheckSignal(true, lepton1MC, lepton2MC, trackMC)) { + mcDecision |= (static_cast(1) << isig); + } + } + } + + // Fill histograms for the triplets + // loop over dilepton / ditrack cuts and MC signals + for (int icut = 0; icut < fNCuts; icut++) { + + if (!dilepton.filterMap_bit(icut)) { + continue; + } + + // loop over specified track cuts (the tracks to be combined with the dileptons) + for (int iTrackCut = 0; iTrackCut < fNCuts; iTrackCut++) { + + if (!(trackSelection & (uint32_t(1) << iTrackCut))) { + continue; + } + + fHistMan->FillHistClass(Form("DileptonTrack_%s_%s", fTrackCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { + if (mcDecision & (uint32_t(1) << isig)) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s", fTrackCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), fValuesHadron); + } + } + + if constexpr (TCandidateType == VarManager::kDstarToD0KPiPi) { // Dielectrons and Dimuons don't have the PairFilterMap column + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { + fHistMan->FillHistClass(Form("DileptonTrack_%s_%s_%s", fTrackCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { + if (mcDecision & (uint32_t(1) << isig)) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s", fTrackCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), fValuesHadron); + } + } + } + } + for (int iPairCut = 0; iPairCut < fNPairCuts; iPairCut++) { + if (dilepton.pairFilterMap_bit(iPairCut)) { + fHistMan->FillHistClass(Form("DileptonTrack_%s_%s_%s", fTrackCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { + if (mcDecision & (uint32_t(1) << isig)) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s", fTrackCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), fValuesHadron); + } + } + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { + fHistMan->FillHistClass(Form("DileptonTrack_%s_%s_%s_%s", fTrackCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { + if (mcDecision & (uint32_t(1) << isig)) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s_%s", fTrackCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), fValuesHadron); + } + } + } + } + } + } + } + } // end loop over track cuts + } // end loop over dilepton cuts + // table to be written out for ML analysis + BmesonsTable(fValuesHadron[VarManager::kPairMass], dilepton.mass(), fValuesHadron[VarManager::kDeltaMass], fValuesHadron[VarManager::kPairPt], + fValuesHadron[VarManager::kVertexingLxy], fValuesHadron[VarManager::kVertexingLxyz], fValuesHadron[VarManager::kVertexingLz], + fValuesHadron[VarManager::kVertexingTauxy], fValuesHadron[VarManager::kVertexingTauz], fValuesHadron[VarManager::kKFDCAxyzBetweenProngs], + fValuesHadron[VarManager::kCosPointingAngle], fValuesHadron[VarManager::kVertexingChi2PCA], dilepton.filterMap_raw(), trackSelection, mcDecision); + } // end loop over associations + } // end loop over dileptons + } + + Preslice trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + Preslice dielectronsPerCollision = aod::reducedpair::reducedeventId; + Preslice ditracksPerCollision = aod::reducedpair::reducedeventId; + + void processBarrelSkimmed(soa::Filtered const& events, + soa::Filtered> const& assocs, + MyBarrelTracksWithCov const& tracks, soa::Filtered const& dileptons, + ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + // set up KF or DCAfitter + if (events.size() == 0) { + return; + } + if (fCurrentRun != events.begin().runNumber()) { // start: runNumber + initParamsFromCCDB(events.begin().timestamp()); + fCurrentRun = events.begin().runNumber(); + } // end: runNumber + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + auto groupedBarrelAssocs = assocs.sliceBy(trackAssocsPerCollision, event.globalIndex()); + auto groupedDielectrons = dileptons.sliceBy(dielectronsPerCollision, event.globalIndex()); + runDileptonHadron(event, groupedBarrelAssocs, tracks, groupedDielectrons, mcEvents, mcTracks); + } + } + + void processDstarToD0Pi(soa::Filtered const& events, + soa::Filtered> const& assocs, + MyBarrelTracksWithCov const& tracks, soa::Filtered const& ditracks, + ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + // set up KF or DCAfitter + if (events.size() == 0) { + return; + } + if (fCurrentRun != events.begin().runNumber()) { // start: runNumber + initParamsFromCCDB(events.begin().timestamp()); + fCurrentRun = events.begin().runNumber(); + } // end: runNumber + for (auto& event : events) { + auto groupedBarrelAssocs = assocs.sliceBy(trackAssocsPerCollision, event.globalIndex()); + auto groupedDitracks = ditracks.sliceBy(ditracksPerCollision, event.globalIndex()); + runDileptonHadron(event, groupedBarrelAssocs, tracks, groupedDitracks, mcEvents, mcTracks); + } + } + + Preslice muonAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + Preslice dimuonsPerCollision = aod::reducedpair::reducedeventId; + + void processMuonSkimmed(soa::Filtered const& events, + soa::Filtered> const& assocs, + MyMuonTracksWithCov const& tracks, soa::Filtered const& dileptons, + ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + // set up KF or DCAfitter + if (events.size() == 0) { + return; + } + if (fCurrentRun != events.begin().runNumber()) { // start: runNumber + initParamsFromCCDB(events.begin().timestamp()); + fCurrentRun = events.begin().runNumber(); + } // end: runNumber + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + auto groupedMuonAssocs = assocs.sliceBy(muonAssocsPerCollision, event.globalIndex()); + auto groupedDimuons = dileptons.sliceBy(dimuonsPerCollision, event.globalIndex()); + runDileptonHadron(event, groupedMuonAssocs, tracks, groupedDimuons, mcEvents, mcTracks); + } + } + + void processMCGen(ReducedMCTracks const& mcTracks) + { + // loop over mc stack and fill histograms for pure MC truth signals + // group all the MC tracks which belong to the MC event corresponding to the current reconstructed event + // auto groupedMCTracks = tracksMC.sliceBy(aod::reducedtrackMC::reducedMCeventId, event.reducedMCevent().globalIndex()); + for (auto& mctrack : mcTracks) { + + if ((std::abs(mctrack.pdgCode()) > 400 && std::abs(mctrack.pdgCode()) < 599) || + (std::abs(mctrack.pdgCode()) > 4000 && std::abs(mctrack.pdgCode()) < 5999) || + mctrack.mcReducedFlags() > 0) { + /*cout << ">>>>>>>>>>>>>>>>>>>>>>> track idx / pdg / selections: " << mctrack.globalIndex() << " / " << mctrack.pdgCode() << " / "; + PrintBitMap(mctrack.mcReducedFlags(), 16); + cout << endl; + if (mctrack.has_mothers()) { + for (auto& m : mctrack.mothersIds()) { + if (m < mcTracks.size()) { // protect against bad mother indices + auto aMother = mcTracks.rawIteratorAt(m); + cout << "<<<<<< mother idx / pdg: " << m << " / " << aMother.pdgCode() << endl; + } + } + } + + if (mctrack.has_daughters()) { + for (int d = mctrack.daughtersIds()[0]; d <= mctrack.daughtersIds()[1]; ++d) { + if (d < mcTracks.size()) { // protect against bad daughter indices + auto aDaughter = mcTracks.rawIteratorAt(d); + cout << "<<<<<< daughter idx / pdg: " << d << " / " << aDaughter.pdgCode() << endl; + } + } + }*/ + } + + VarManager::FillTrackMC(mcTracks, mctrack); + // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. + // NOTE: However, the working model is that the decisions on MC signals are precomputed during skimming and are stored in the mcReducedFlags member. + // TODO: Use the mcReducedFlags to select signals + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, mctrack)) { + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + } + } + } + } + + PresliceUnsorted perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; + + void processMCGenWithEventSelection(soa::Filtered const& events, + ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) + { + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); + groupedMCTracks.bindInternalIndicesTo(&mcTracks); + for (auto& track : groupedMCTracks) { + + VarManager::FillTrackMC(mcTracks, track); + + auto track_raw = groupedMCTracks.rawIteratorAt(track.globalIndex()); + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, track_raw)) { + fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); + } + } + } + + /*for (auto& [t1, t2, t3] : combinations(groupedMCTracks, groupedMCTracks, groupedMCTracks)) { + + if (! (t1.mcReducedFlags() & (uint16_t(1) << fConfigMCGenSignalDileptonLegPos.value))) { + continue; + } + if (t1.pt() < fConfigMCGenDileptonLegPtMin.value) { + continue; + } + if (std::abs(t1.eta()) > fConfigMCGenDileptonLegEtaAbs.value) { + continue; + } + + if (! (t2.mcReducedFlags() & (uint16_t(1) << fConfigMCGenSignalDileptonLegNeg.value))) { + continue; + } + if (t2.pt() < fConfigMCGenDileptonLegPtMin.value) { + continue; + } + if (std::abs(t2.eta()) > fConfigMCGenDileptonLegEtaAbs.value) { + continue; + } + + if (! (t3.mcReducedFlags() & (uint16_t(1) << fConfigMCGenSignalHadron.value))) { + continue; + } + if (t3.pt() < fConfigMCGenHadronPtMin.value) { + continue; + } + if (std::abs(t3.eta()) > fConfigMCGenHadronEtaAbs.value) { + continue; + } + + fHistMan->FillHistClass("MCTruthGenSelAccepted", VarManager::fgValues); + }*/ + } // end loop over reconstructed events + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisDileptonTrack, processBarrelSkimmed, "Run barrel dilepton-track pairing, using skimmed data", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processDstarToD0Pi, "Run barrel pairing of D0 daughters with pion candidate, using skimmed data", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMuonSkimmed, "Run muon dilepton-track pairing, using skimmed data", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMCGen, "Loop over MC particle stack and fill generator level histograms", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenWithEventSelection, "Loop over MC particle stack and fill generator level histograms", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processDummy, "Dummy function", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +} + +void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups) +{ + // + // Define here the histograms for all the classes required in analysis. + // The histogram classes are provided in the histClasses string, separated by semicolon ";" + // The histogram classes and their components histograms are defined below depending on the name of the histogram class + // + std::unique_ptr objArray(histClasses.Tokenize(";")); + for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { + TString classStr = objArray->At(iclass)->GetName(); + histMan->AddHistClass(classStr.Data()); + + TString histName = histGroups; + // NOTE: The level of detail for histogramming can be controlled via configurables + if (classStr.Contains("Event")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "event", histName); + } + + if (classStr.Contains("SameBunchCorrelations") || classStr.Contains("OutOfBunchCorrelations")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "two-collisions", histName); + } + + if ((classStr.Contains("Track") || classStr.Contains("Assoc")) && !classStr.Contains("Pairs")) { + if (classStr.Contains("Barrel")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); + if (classStr.Contains("PIDCalibElectron")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "postcalib_electron"); + } + if (classStr.Contains("PIDCalibPion")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "postcalib_pion"); + } + if (classStr.Contains("PIDCalibProton")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "postcalib_proton"); + } + if (classStr.Contains("Ambiguity")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "ambiguity"); + } + } + } + if (classStr.Contains("Muon") && !classStr.Contains("Pairs")) { + if (!classStr.Contains("Ambiguity")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); + } else { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "muon-ambiguity"); + } + } + + if (classStr.Contains("Pairs")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", histName); + } + + if (classStr.Contains("Triplets")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", histName); + } + + if (classStr.Contains("MCTruthGenPair")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_pair"); + } + + if (classStr.Contains("MCTruthGen")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_track"); + } + + if (classStr.Contains("DileptonsSelected")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", "barrel,vertexing"); + } + + if (classStr.Contains("DileptonTrack") && !classStr.Contains("ME")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", histName); + } + + if (classStr.Contains("DileptonTrackME")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", "mixedevent"); + } + + if (classStr.Contains("HadronsSelected")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); + } + + if (classStr.Contains("DileptonHadronInvMass")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-hadron-mass"); + } + + if (classStr.Contains("DileptonHadronCorrelation")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-hadron-correlation"); + } + } // end loop over histogram classes +} diff --git a/PWGDQ/Tasks/dqFlow.cxx b/PWGDQ/Tasks/dqFlow.cxx index 3eb3cde054a..d9210685a2e 100644 --- a/PWGDQ/Tasks/dqFlow.cxx +++ b/PWGDQ/Tasks/dqFlow.cxx @@ -60,18 +60,21 @@ using namespace o2::aod; using namespace o2::analysis; // Declarations of various short names +using MyBcs = soa::Join; + using MyEvents = soa::Join; using MyEventsWithCent = soa::Join; using MyEventsWithCentRun3 = soa::Join; -using MyEventsWithCentQvectRun3 = soa::Join; +// using MyEventsWithCentQvectRun3 = soa::Join; +// using MyEventsWithCentQvectRun3 = soa::Join; +using MyEventsWithCentQvectRun3 = soa::Join; -using MyBarrelTracks = soa::Join; -using MyBarrelTracksWithCov = soa::Join; @@ -81,7 +84,7 @@ using MyMuonsWithCov = soa::Join; constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCentRun2; constexpr static uint32_t gkEventFillMapRun3 = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCent; -constexpr static uint32_t gkEventFillMapRun3Qvect = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCent | VarManager::ObjTypes::CollisionQvect; +constexpr static uint32_t gkEventFillMapRun3Qvect = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCent | VarManager::ObjTypes::CollisionQvectCentr; constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackPID; void DefineHistograms(HistogramManager* histMan, TString histClasses); @@ -97,7 +100,11 @@ struct DQEventQvector { Produces eventQvector; Produces eventQvectorExtra; Produces eventQvectorCentr; + Produces eventQvectorCentrExtra; Produces eventRefFlow; + Produces eventQvectorZN; + Produces eventReducedZdc; + Produces eventReducedZdcExtra; Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; Configurable fConfigQA{"cfgQA", true, "If true, fill QA histograms"}; @@ -107,9 +114,10 @@ struct DQEventQvector { Configurable fConfigCutPtMax{"cfgCutPtMax", 12.0f, "Maximal pT for tracks"}; Configurable fConfigCutEtaMin{"cfgCutEtaMin", -0.8f, "Eta min range for tracks"}; Configurable fConfigCutEtaMax{"cfgCutEtaMax", 0.8f, "Eta max range for tracks"}; + Configurable fConfigCutTPCNClMin{"cfgCutTPCNclMin", 0, "Min requirement for number of TPC clusters"}; Configurable fConfigEtaLimitMin{"cfgEtaLimitMin", -0.4f, "Eta gap min separation, only if using subEvents"}; Configurable fConfigEtaLimitMax{"cfgEtaLimitMax", 0.4f, "Eta gap max separation, only if using subEvents"}; - Configurable fConfigNPow{"cfgNPow", 0, "Power of weights for Q vector"}; + // Configurable fConfigNPow{"cfgNPow", 0, "Power of weights for Q vector"}; // Configurable cfgGFWBinning{"cfgGFWBinning", {40, 16, 72, 300, 0, 3000, 0.2, 10.0, 0.2, 3.0, {0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.2, 2.4, 2.6, 2.8, 3, 3.5, 4, 5, 6, 8, 10}, {0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}}, "Configuration for binning"}; // Access to the efficiencies and acceptances from CCDB @@ -123,7 +131,7 @@ struct DQEventQvector { ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100.1}, "multiplicity / centrality axis for histograms"}; // Define the filter for barrel tracks and forward tracks - Filter trackFilter = (nabs(aod::track::eta) <= fConfigCutEtaMax) && (aod::track::pt > fConfigCutPtMin) && (aod::track::pt < fConfigCutPtMax) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)); + Filter trackFilter = (requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true); Filter fwdFilter = (aod::fwdtrack::eta < -2.45f) && (aod::fwdtrack::eta > -3.6f); // Histograms used for optionnal efficiency and non-uniform acceptance corrections @@ -181,7 +189,7 @@ struct DQEventQvector { fPtAxis = new TAxis(ptbins, &ptbinning[0]); if (fConfigFillWeights) { // fWeights->SetPtBins(ptbins, &ptbinning[0]); // in the default case, it will accept everything - fWeights->Init(true, false); // true for data, false for MC + fWeights->init(true, false); // true for data, false for MC } // Reference flow @@ -205,11 +213,51 @@ struct DQEventQvector { corrconfigs.push_back(fGFW->GetCorrelatorConfig("refP {2 2} refN {-2 -2}", "ChGap24", kFALSE)); corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 2 -2 -2}", "ChFull24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {3 -3}", "ChFull32", kFALSE)); corrconfigs.push_back(fGFW->GetCorrelatorConfig("refP {3} refN {-3}", "ChGap32", kFALSE)); fGFW->CreateRegions(); } + template + bool isTrackSelected(TTrack const& track) + { + constexpr bool isBarrelTrack = ((TTrackFillMap & VarManager::ObjTypes::Track) > 0); + if constexpr (isBarrelTrack) { + if (!(track.pt() > fConfigCutPtMin && track.pt() < fConfigCutPtMax)) { + return false; + } + if (!(track.eta() > fConfigCutEtaMin && track.eta() < fConfigCutEtaMax)) { + return false; + } + if (track.tpcNClsFound() <= fConfigCutTPCNClMin) { + return false; + } + if (!track.passedITSNCls()) { + return false; + } + if (!track.passedITSChi2NDF()) { + return false; + } + if (!track.passedITSHits()) { + return false; + } + if (!track.passedTPCCrossedRowsOverNCls()) { + return false; + } + if (!track.passedTPCChi2NDF()) { + return false; + } + if (!track.passedDCAxy()) { + return false; + } + if (!track.passedDCAz()) { + return false; + } + } + return true; + } + void loadCorrections(uint64_t timestamp) { if (cfg.correctionsLoaded) { @@ -287,14 +335,15 @@ struct DQEventQvector { // Fill the tree for the reduced event table with Q vector quantities if (fEventCut->IsSelected(VarManager::fgValues)) { - eventQvectorCentr(collision.qvecFT0ARe(), collision.qvecFT0AIm(), collision.qvecFT0CRe(), collision.qvecFT0CIm(), collision.qvecFT0MRe(), collision.qvecFT0MIm(), collision.qvecFV0ARe(), collision.qvecFV0AIm(), collision.qvecBPosRe(), collision.qvecBPosIm(), collision.qvecBNegRe(), collision.qvecBNegIm(), - collision.sumAmplFT0A(), collision.sumAmplFT0C(), collision.sumAmplFT0M(), collision.sumAmplFV0A(), collision.nTrkBPos(), collision.nTrkBNeg()); + eventQvectorCentr(collision.qvecFT0ARe(), collision.qvecFT0AIm(), collision.qvecFT0CRe(), collision.qvecFT0CIm(), collision.qvecFT0MRe(), collision.qvecFT0MIm(), collision.qvecFV0ARe(), collision.qvecFV0AIm(), collision.qvecTPCposRe(), collision.qvecTPCposIm(), collision.qvecTPCnegRe(), collision.qvecTPCnegIm(), + collision.sumAmplFT0A(), collision.sumAmplFT0C(), collision.sumAmplFT0M(), collision.sumAmplFV0A(), collision.nTrkTPCpos(), collision.nTrkTPCneg()); + eventQvectorCentrExtra(collision.qvecTPCallRe(), collision.qvecTPCallIm(), collision.nTrkTPCall()); } } // Templated function instantianed for all of the process functions template - void runFillQvector(TEvent const& collision, aod::BCsWithTimestamps const&, TTracks const& tracks1) + void runFillQvector(TEvent const& collision, MyBcs const&, TTracks const& tracks1, aod::Zdcs const&) { // Fill the event properties within the VarManager VarManager::ResetValues(0, VarManager::kNVars); @@ -306,7 +355,8 @@ struct DQEventQvector { fGFW->Clear(); float centrality; - auto bc = collision.template bc_as(); + // auto bc = collision.template bc_as(); + auto bc = collision.template bc_as(); // Load weights from CCDB loadCorrections(bc.timestamp()); constexpr bool eventHasCentRun2 = ((TEventFillMap & VarManager::ObjTypes::CollisionCentRun2) > 0); @@ -326,9 +376,14 @@ struct DQEventQvector { // Fill the GFW object in the track loop for (auto& track : tracks1) { + // Selections for barrel tracks + if (!isTrackSelected(track)) { + continue; + } + // Fill weights for Q-vector correction: this should be enabled for a first run to get weights if (fConfigFillWeights) { - fWeights->Fill(track.phi(), track.eta(), collision.posZ(), track.pt(), centrality, 0); + fWeights->fill(track.phi(), track.eta(), collision.posZ(), track.pt(), centrality, 0); } if (cfg.mEfficiency) { @@ -341,7 +396,7 @@ struct DQEventQvector { } weff = 1. / weff; if (cfg.mAcceptance) { - wacc = cfg.mAcceptance->GetNUA(track.phi(), track.eta(), collision.posZ()); + wacc = cfg.mAcceptance->getNUA(track.phi(), track.eta(), collision.posZ()); } else { wacc = 1.0; } @@ -452,40 +507,60 @@ struct DQEventQvector { if (fEventCut->IsSelected(VarManager::fgValues)) { eventQvector(VarManager::fgValues[VarManager::kQ1X0A], VarManager::fgValues[VarManager::kQ1Y0A], VarManager::fgValues[VarManager::kQ1X0B], VarManager::fgValues[VarManager::kQ1Y0B], VarManager::fgValues[VarManager::kQ1X0C], VarManager::fgValues[VarManager::kQ1Y0C], VarManager::fgValues[VarManager::kQ2X0A], VarManager::fgValues[VarManager::kQ2Y0A], VarManager::fgValues[VarManager::kQ2X0B], VarManager::fgValues[VarManager::kQ2Y0B], VarManager::fgValues[VarManager::kQ2X0C], VarManager::fgValues[VarManager::kQ2Y0C], VarManager::fgValues[VarManager::kMultA], VarManager::fgValues[VarManager::kMultB], VarManager::fgValues[VarManager::kMultC], VarManager::fgValues[VarManager::kQ3X0A], VarManager::fgValues[VarManager::kQ3Y0A], VarManager::fgValues[VarManager::kQ3X0B], VarManager::fgValues[VarManager::kQ3Y0B], VarManager::fgValues[VarManager::kQ3X0C], VarManager::fgValues[VarManager::kQ3Y0C], VarManager::fgValues[VarManager::kQ4X0A], VarManager::fgValues[VarManager::kQ4Y0A], VarManager::fgValues[VarManager::kQ4X0B], VarManager::fgValues[VarManager::kQ4Y0B], VarManager::fgValues[VarManager::kQ4X0C], VarManager::fgValues[VarManager::kQ4Y0C]); eventQvectorExtra(VarManager::fgValues[VarManager::kQ42XA], VarManager::fgValues[VarManager::kQ42YA], VarManager::fgValues[VarManager::kQ23XA], VarManager::fgValues[VarManager::kQ23YA], VarManager::fgValues[VarManager::kS11A], VarManager::fgValues[VarManager::kS12A], VarManager::fgValues[VarManager::kS13A], VarManager::fgValues[VarManager::kS31A]); - eventRefFlow(VarManager::fgValues[VarManager::kM11REF], VarManager::fgValues[VarManager::kM1111REF], VarManager::fgValues[VarManager::kCORR2REF], VarManager::fgValues[VarManager::kCORR4REF], centrality); + eventRefFlow(VarManager::fgValues[VarManager::kM11REF], VarManager::fgValues[VarManager::kM11REFetagap], VarManager::fgValues[VarManager::kM1111REF], VarManager::fgValues[VarManager::kCORR2REF], VarManager::fgValues[VarManager::kCORR2REFetagap], VarManager::fgValues[VarManager::kCORR4REF], centrality); } - if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionQvect) > 0) { + if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionQvectCentr) > 0) { VarManager::FillQVectorFromCentralFW(collision); - if (fConfigQA) { - fHistMan->FillHistClass("Event_BeforeCuts_centralFW", VarManager::fgValues); - if (fEventCut->IsSelected(VarManager::fgValues)) { - fHistMan->FillHistClass("Event_AfterCuts_centralFW", VarManager::fgValues); + + if (bc.has_zdc()) { + auto zdc = bc.zdc(); + VarManager::FillSpectatorPlane(zdc); + } + + if ((tracks1.size() > 0) && (VarManager::fgValues[VarManager::kMultA] * VarManager::fgValues[VarManager::kMultB] * VarManager::fgValues[VarManager::kMultC] != 0.0)) { + if (fConfigQA) { + fHistMan->FillHistClass("Event_BeforeCuts_centralFW", VarManager::fgValues); + if (fEventCut->IsSelected(VarManager::fgValues)) { + fHistMan->FillHistClass("Event_AfterCuts_centralFW", VarManager::fgValues); + } } } if (fEventCut->IsSelected(VarManager::fgValues)) { - eventQvectorCentr(collision.qvecFT0ARe(), collision.qvecFT0AIm(), collision.qvecFT0CRe(), collision.qvecFT0CIm(), collision.qvecFT0MRe(), collision.qvecFT0MIm(), collision.qvecFV0ARe(), collision.qvecFV0AIm(), collision.qvecBPosRe(), collision.qvecBPosIm(), collision.qvecBNegRe(), collision.qvecBNegIm(), - collision.sumAmplFT0A(), collision.sumAmplFT0C(), collision.sumAmplFT0M(), collision.sumAmplFV0A(), collision.nTrkBPos(), collision.nTrkBNeg()); + eventQvectorCentr(collision.qvecFT0ARe(), collision.qvecFT0AIm(), collision.qvecFT0CRe(), collision.qvecFT0CIm(), collision.qvecFT0MRe(), collision.qvecFT0MIm(), collision.qvecFV0ARe(), collision.qvecFV0AIm(), collision.qvecTPCposRe(), collision.qvecTPCposIm(), collision.qvecTPCnegRe(), collision.qvecTPCnegIm(), + collision.sumAmplFT0A(), collision.sumAmplFT0C(), collision.sumAmplFT0M(), collision.sumAmplFV0A(), collision.nTrkTPCpos(), collision.nTrkTPCneg()); + eventQvectorCentrExtra(collision.qvecTPCallRe(), collision.qvecTPCallIm(), collision.nTrkTPCall()); + if (bc.has_zdc()) { + eventQvectorZN(VarManager::fgValues[VarManager::kQ1ZNAX], VarManager::fgValues[VarManager::kQ1ZNAY], VarManager::fgValues[VarManager::kQ1ZNCX], VarManager::fgValues[VarManager::kQ1ZNCY]); + eventReducedZdc(VarManager::fgValues[VarManager::kEnergyCommonZNA], VarManager::fgValues[VarManager::kEnergyCommonZNC], VarManager::fgValues[VarManager::kEnergyCommonZPA], VarManager::fgValues[VarManager::kEnergyCommonZPC], + VarManager::fgValues[VarManager::kTimeZNA], VarManager::fgValues[VarManager::kTimeZNC], VarManager::fgValues[VarManager::kTimeZPA], VarManager::fgValues[VarManager::kTimeZPC]); + eventReducedZdcExtra(VarManager::fgValues[VarManager::kEnergyZNA1], VarManager::fgValues[VarManager::kEnergyZNA2], VarManager::fgValues[VarManager::kEnergyZNA3], VarManager::fgValues[VarManager::kEnergyZNA4], + VarManager::fgValues[VarManager::kEnergyZNC1], VarManager::fgValues[VarManager::kEnergyZNC2], VarManager::fgValues[VarManager::kEnergyZNC3], VarManager::fgValues[VarManager::kEnergyZNC4]); + } else { + eventQvectorZN(-999, -999, -999, -999); + eventReducedZdc(-999, -999, -999, -999, -999, -999, -999, -999); + eventReducedZdcExtra(-999, -999, -999, -999, -999, -999, -999, -999); + } } } } // Process to fill Q vector using barrel tracks in a reduced event table for barrel/muon tracks flow related analyses Run 2 - void processBarrelQvectorRun2(MyEventsWithCent::iterator const& collisions, aod::BCsWithTimestamps const& bcs, soa::Filtered const& tracks) + void processBarrelQvectorRun2(MyEventsWithCent::iterator const& collisions, MyBcs const& bcs, soa::Filtered const& tracks, aod::Zdcs const& zdcs) { - runFillQvector(collisions, bcs, tracks); + runFillQvector(collisions, bcs, tracks, zdcs); } // Process to fill Q vector using barrel tracks in a reduced event table for barrel/muon tracks flow related analyses Run 3 - void processBarrelQvector(MyEventsWithCentRun3::iterator const& collisions, aod::BCsWithTimestamps const& bcs, soa::Filtered const& tracks) + void processBarrelQvector(MyEventsWithCentRun3::iterator const& collisions, MyBcs const& bcs, soa::Filtered const& tracks, aod::Zdcs const& zdcs) { - runFillQvector(collisions, bcs, tracks); + runFillQvector(collisions, bcs, tracks, zdcs); } // Process to fill Q vector using barrel tracks in a reduced event table for barrel/muon tracks flow related analyses Run 3 - void processAllQvector(MyEventsWithCentQvectRun3::iterator const& collisions, aod::BCsWithTimestamps const& bcs, soa::Filtered const& tracks) + void processAllQvector(MyEventsWithCentQvectRun3::iterator const& collisions, MyBcs const& bcs, soa::Filtered const& tracks, aod::Zdcs const& zdcs) { - runFillQvector(collisions, bcs, tracks); + runFillQvector(collisions, bcs, tracks, zdcs); } // Process to fill Q vector using barrel tracks in a reduced event table for barrel/muon tracks flow related analyses Run 3 @@ -495,9 +570,9 @@ struct DQEventQvector { } // Process to fill Q vector using forward tracks in a reduced event table for barrel/muon tracks flow related analyses Run 3 - void processForwardQvector(MyEventsWithCentRun3::iterator const& collisions, aod::BCsWithTimestamps const& bcs, soa::Filtered const& tracks) + void processForwardQvector(MyEventsWithCentRun3::iterator const& collisions, MyBcs const& bcs, soa::Filtered const& tracks, aod::Zdcs const& zdcs) { - runFillQvector(collisions, bcs, tracks); + runFillQvector(collisions, bcs, tracks, zdcs); } // TODO: dummy function for the case when no process function is enabled @@ -531,7 +606,7 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses) histMan->AddHistClass(classStr.Data()); if (classStr.Contains("Event")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "event", "qvector,trigger,cent,res"); + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "event", "qvector,cross,trigger,cent,res"); } if (classStr.Contains("Track")) { diff --git a/PWGDQ/Tasks/filterPP.cxx b/PWGDQ/Tasks/filterPP.cxx index f13392d197f..c9239f8366d 100644 --- a/PWGDQ/Tasks/filterPP.cxx +++ b/PWGDQ/Tasks/filterPP.cxx @@ -13,10 +13,11 @@ // #include #include +#include +#include #include #include -#include -#include +#include #include #include #include "Framework/AnalysisTask.h" @@ -60,6 +61,7 @@ enum DQTriggers { kSingleMuLow, kSingleMuHigh, kDiMuon, + kElectronMuon, kNTriggersDQ }; } // namespace @@ -248,14 +250,14 @@ struct DQBarrelTrackSelection { fCurrentRun = bc.runNumber(); } - uint32_t filterMap = uint32_t(0); + uint32_t filterMap = static_cast(0); trackSel.reserve(tracksBarrel.size()); VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); for (auto& track : tracksBarrel) { - filterMap = uint32_t(0); + filterMap = static_cast(0); if (!track.has_collision()) { - trackSel(uint32_t(0)); + trackSel(static_cast(0)); } else { VarManager::FillTrack(track); if (fConfigQA) { @@ -264,7 +266,7 @@ struct DQBarrelTrackSelection { int i = 0; for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); ++cut, ++i) { if ((*cut).IsSelected(VarManager::fgValues)) { - filterMap |= (uint32_t(1) << i); + filterMap |= (static_cast(1) << i); if (fConfigQA) { fHistMan->FillHistClass(fCutHistNames[i].Data(), VarManager::fgValues); } @@ -332,16 +334,16 @@ struct DQMuonsSelection { template void runMuonSelection(TMuons const& muons) { - uint32_t filterMap = uint32_t(0); + uint32_t filterMap = static_cast(0); trackSel.reserve(muons.size()); VarManager::ResetValues(0, VarManager::kNMuonTrackVariables); // fill event information which might be needed in histograms or cuts that combine track and event properties for (auto& muon : muons) { - filterMap = uint32_t(0); + filterMap = static_cast(0); if (!muon.has_collision()) { - trackSel(uint32_t(0)); + trackSel(static_cast(0)); } else { VarManager::FillTrack(muon); if (fConfigQA) { @@ -350,7 +352,7 @@ struct DQMuonsSelection { int i = 0; for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); ++cut, ++i) { if ((*cut).IsSelected(VarManager::fgValues)) { - filterMap |= (uint32_t(1) << i); + filterMap |= (static_cast(1) << i); if (fConfigQA) { fHistMan->FillHistClass(fCutHistNames[i].Data(), VarManager::fgValues); } @@ -378,7 +380,7 @@ struct DQFilterPPTask { Produces eventFilter; Produces dqtable; OutputObj fOutputList{"output"}; - OutputObj fStats{"Statistics"}; + OutputObj fStats{"Statistics"}; HistogramManager* fHistMan; Configurable fConfigBarrelSelections{"cfgBarrelSels", "jpsiPID1:pairMassLow:1", ":[]:,[:[]:],..."}; @@ -387,8 +389,8 @@ struct DQFilterPPTask { Configurable fConfigFilterLsBarrelTracksPairs{"cfgWithBarrelLS", "false", "Comma separated list of booleans for each trigger, If true, also select like sign (--/++) barrel track pairs"}; Configurable fConfigFilterLsMuonsPairs{"cfgWithMuonLS", "false", "Comma separated list of booleans for each trigger, If true, also select like sign (--/++) muon pairs"}; - Filter filterBarrelTrackSelected = aod::dqppfilter::isDQBarrelSelected > uint32_t(0); - Filter filterMuonTrackSelected = aod::dqppfilter::isDQMuonSelected > uint32_t(0); + Filter filterBarrelTrackSelected = aod::dqppfilter::isDQBarrelSelected > static_cast(0); + Filter filterMuonTrackSelected = aod::dqppfilter::isDQMuonSelected > static_cast(0); int fNBarrelCuts; // number of barrel selections int fNMuonCuts; // number of muon selections @@ -450,7 +452,7 @@ struct DQFilterPPTask { VarManager::SetUseVars(AnalysisCut::fgUsedVars); // setup the Stats histogram - fStats.setObject(new TH1I("Statistics", "Stats for DQ triggers", fNBarrelCuts + fNMuonCuts + 2, -2.5, -0.5 + fNBarrelCuts + fNMuonCuts)); + fStats.setObject(new TH1D("Statistics", "Stats for DQ triggers", fNBarrelCuts + fNMuonCuts + 2, -2.5, -0.5 + fNBarrelCuts + fNMuonCuts)); fStats->GetXaxis()->SetBinLabel(1, "Events inspected"); fStats->GetXaxis()->SetBinLabel(2, "Events selected"); if (fNBarrelCuts) { @@ -497,14 +499,14 @@ struct DQFilterPPTask { // if the event is not selected produce tables and return if (!collision.isDQEventSelected()) { eventFilter(0); - dqtable(false, false, false, false, false, false, false); + dqtable(false, false, false, false, false, false, false, false); return; } fStats->Fill(-1.0); if (tracksBarrel.size() == 0 && muons.size() == 0) { eventFilter(0); - dqtable(false, false, false, false, false, false, false); + dqtable(false, false, false, false, false, false, false, false); return; } @@ -516,7 +518,7 @@ struct DQFilterPPTask { // count the number of barrel tracks fulfilling each cut for (auto track : tracksBarrel) { for (int i = 0; i < fNBarrelCuts; ++i) { - if (track.isDQBarrelSelected() & (uint32_t(1) << i)) { + if (track.isDQBarrelSelected() & (static_cast(1) << i)) { objCountersBarrel[i] += 1; } } @@ -527,7 +529,7 @@ struct DQFilterPPTask { for (int i = 0; i < fNBarrelCuts; i++) { if (fBarrelRunPairing[i]) { if (objCountersBarrel[i] > 1) { // pairing has to be enabled and at least two tracks are needed - pairingMask |= (uint32_t(1) << i); + pairingMask |= (static_cast(1) << i); } objCountersBarrel[i] = 0; // reset counters for selections where pairing is needed (count pairs instead) } @@ -540,7 +542,7 @@ struct DQFilterPPTask { for (int icut = 0; icut < fNBarrelCuts; icut++) { TString objStr = objArrayLS->At(icut)->GetName(); if (!objStr.CompareTo("true")) { - pairingLS |= (uint32_t(1) << icut); + pairingLS |= (static_cast(1) << icut); } } @@ -557,12 +559,12 @@ struct DQFilterPPTask { VarManager::FillPair(t1, t2); // compute pair quantities for (int icut = 0; icut < fNBarrelCuts; icut++) { // select like-sign pairs if trigger has set boolean true within fConfigFilterLsBarrelTracksPairs - if (!(pairingLS & (uint32_t(1) << icut))) { + if (!(pairingLS & (static_cast(1) << icut))) { if (t1.sign() * t2.sign() > 0) { continue; } } - if (!(pairFilter & (uint32_t(1) << icut))) { + if (!(pairFilter & (static_cast(1) << icut))) { continue; } if (!fBarrelPairCuts[icut].IsSelected(VarManager::fgValues)) { @@ -580,7 +582,7 @@ struct DQFilterPPTask { // count the number of muon tracks fulfilling each selection for (auto muon : muons) { for (int i = 0; i < fNMuonCuts; ++i) { - if (muon.isDQMuonSelected() & (uint32_t(1) << i)) { + if (muon.isDQMuonSelected() & (static_cast(1) << i)) { objCountersMuon[i] += 1; } } @@ -591,7 +593,7 @@ struct DQFilterPPTask { for (int i = 0; i < fNMuonCuts; i++) { if (fMuonRunPairing[i]) { // pairing has to be enabled and at least two tracks are needed if (objCountersMuon[i] > 1) { - pairingMask |= (uint32_t(1) << i); + pairingMask |= (static_cast(1) << i); } objCountersMuon[i] = 0; // reset counters for selections where pairing is needed (count pairs instead) } @@ -604,7 +606,7 @@ struct DQFilterPPTask { for (int icut = 0; icut < fNMuonCuts; icut++) { TString objStr = objArrayMuonLS->At(icut)->GetName(); if (!objStr.CompareTo("true")) { - pairingLS |= (uint32_t(1) << icut); + pairingLS |= (static_cast(1) << icut); } } @@ -621,12 +623,12 @@ struct DQFilterPPTask { VarManager::FillPair(t1, t2); // compute pair quantities for (int icut = 0; icut < fNMuonCuts; icut++) { // select like-sign pairs if trigger has set boolean true within fConfigFilterLsMuonsPairs - if (!(pairingLS & (uint32_t(1) << icut))) { + if (!(pairingLS & (static_cast(1) << icut))) { if (t1.sign() * t2.sign() > 0) { continue; } } - if (!(pairFilter & (uint32_t(1) << icut))) { + if (!(pairFilter & (static_cast(1) << icut))) { continue; } if (!fMuonPairCuts[icut].IsSelected(VarManager::fgValues)) { @@ -649,7 +651,7 @@ struct DQFilterPPTask { uint64_t filter = 0; for (int i = 0; i < fNBarrelCuts; i++) { if (objCountersBarrel[i] >= fBarrelNreqObjs[i]) { - filter |= (uint64_t(1) << i); + filter |= (static_cast(1) << i); fStats->Fill(static_cast(i)); if (i < kNTriggersDQ) { decisions[i] = true; @@ -658,7 +660,7 @@ struct DQFilterPPTask { } for (int i = 0; i < fNMuonCuts; i++) { if (objCountersMuon[i] >= fMuonNreqObjs[i]) { - filter |= (uint64_t(1) << (i + fNBarrelCuts)); + filter |= (static_cast(1) << (i + fNBarrelCuts)); fStats->Fill(static_cast(i + fNBarrelCuts)); if (i + fNBarrelCuts < kNTriggersDQ) { decisions[i + fNBarrelCuts] = true; @@ -666,7 +668,7 @@ struct DQFilterPPTask { } } eventFilter(filter); - dqtable(decisions[0], decisions[1], decisions[2], decisions[3], decisions[4], decisions[5], decisions[6]); + dqtable(decisions[0], decisions[1], decisions[2], decisions[3], decisions[4], decisions[5], decisions[6], decisions[7]); } void processFilterPP(MyEventsSelected::iterator const& collision, aod::BCs const& bcs, diff --git a/PWGDQ/Tasks/filterPPwithAssociation.cxx b/PWGDQ/Tasks/filterPPwithAssociation.cxx index a245c2dac0a..532482e641b 100644 --- a/PWGDQ/Tasks/filterPPwithAssociation.cxx +++ b/PWGDQ/Tasks/filterPPwithAssociation.cxx @@ -13,10 +13,11 @@ // #include #include +#include +#include #include #include -#include -#include +#include #include #include #include "Framework/AnalysisTask.h" @@ -69,6 +70,7 @@ enum DQTriggers { kSingleMuLow, kSingleMuHigh, kDiMuon, + kElectronMuon, kNTriggersDQ }; } // namespace @@ -79,6 +81,8 @@ namespace dqppfilter DECLARE_SOA_COLUMN(IsDQEventSelected, isDQEventSelected, int); DECLARE_SOA_COLUMN(IsDQBarrelSelected, isDQBarrelSelected, uint32_t); DECLARE_SOA_COLUMN(IsDQMuonSelected, isDQMuonSelected, uint32_t); +DECLARE_SOA_COLUMN(IsDQEMuBarrelSelected, isDQEMuBarrelSelected, uint32_t); // for electron-muon pair +DECLARE_SOA_COLUMN(IsDQEMuMuonSelected, isDQEMuMuonSelected, uint32_t); // for electron-muon pair DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! Collision index DECLARE_SOA_INDEX_COLUMN(Track, track); //! Track index DECLARE_SOA_INDEX_COLUMN(FwdTrack, fwdtrack); //! FwdTrack index @@ -87,6 +91,8 @@ DECLARE_SOA_INDEX_COLUMN(FwdTrack, fwdtrack); //! FwdTrack index DECLARE_SOA_TABLE(DQEventCuts, "AOD", "DQEVENTCUTS", dqppfilter::IsDQEventSelected); DECLARE_SOA_TABLE(DQBarrelTrackCuts, "AOD", "DQBARRELCUTS", dqppfilter::IsDQBarrelSelected); DECLARE_SOA_TABLE(DQMuonsCuts, "AOD", "DQMUONCUTS", dqppfilter::IsDQMuonSelected); +DECLARE_SOA_TABLE(DQEMuBarrelTrackCuts, "AOD", "DQEMUBARRELCUTS", dqppfilter::IsDQEMuBarrelSelected); // for electron-muon pair +DECLARE_SOA_TABLE(DQEMuMuonsCuts, "AOD", "DQEMUMUONCUTS", dqppfilter::IsDQEMuMuonSelected); // for electron-muon pair } // namespace o2::aod using MyEvents = soa::Join; @@ -99,21 +105,29 @@ using MyBarrelTracks = soa::Join; -using MyBarrelTracksSelected = soa::Join; -using MyBarrelTracksAssocSelected = soa::Join; // As the kinelatic values must be re-computed for the tracks everytime it is associated to a collision, the selection is done not on the tracks, but on the track-collision association +using MyBarrelTracksTPCPID = soa::Join; + +using MyBarrelTracksAssocSelected = soa::Join; // As the kinelatic values must be re-computed for the tracks everytime it is associated to a collision, the selection is done not on the tracks, but on the track-collision association using MyMuons = soa::Join; -using MyMuonsAssocSelected = soa::Join; // As the kinelatic values must be re-computed for the muons tracks everytime it is associated to a collision, the selection is done not on the muon, but on the muon-collision association +using MyMuonsAssocSelected = soa::Join; // As the kinelatic values must be re-computed for the muons tracks everytime it is associated to a collision, the selection is done not on the muon, but on the muon-collision association -constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision; +constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::Collision; constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackPID; +constexpr static uint32_t gkTrackFillMapTPCPID = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackTPCPID; constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::Muon | VarManager::ObjTypes::MuonCov; -void DefineHistograms(HistogramManager* histMan, TString histClasses); +void DefineHistograms(HistogramManager* histMan, TString histClasses, TString subgroups = ""); + +template +void PrintBitMap(TMap map, int nbits) +{ + for (int i = 0; i < nbits; i++) { + cout << ((map & (TMap(1) << i)) > 0 ? "1" : "0"); + } +} struct DQEventSelectionTask { Produces eventSel; @@ -123,6 +137,7 @@ struct DQEventSelectionTask { Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Comma separated list of event cuts; multiple cuts are applied with a logical AND"}; Configurable fConfigQA{"cfgWithQA", false, "If true, fill QA histograms"}; + Configurable fConfigHistClasses{"cfgHistClasses", "vtxpp", "Comma separated list of histogram groups to be filled"}; // TODO: configure the histogram classes to be filled by QA void init(o2::framework::InitContext&) @@ -144,14 +159,14 @@ struct DQEventSelectionTask { fHistMan->SetUseDefaultVariableNames(kTRUE); fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - DefineHistograms(fHistMan, "Event_BeforeCuts;Event_AfterCuts;"); // define all histograms + DefineHistograms(fHistMan, "Event_BeforeCuts;Event_AfterCuts;", fConfigHistClasses.value); // define all histograms VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); } } template - void runEventSelection(TEvent const& collision, aod::BCs const& /*bcs*/) + void runEventSelection(TEvent const& collision) { // Reset the Values array VarManager::ResetValues(0, VarManager::kNEventWiseVariables); @@ -170,9 +185,9 @@ struct DQEventSelectionTask { } } - void processEventSelection(MyEvents::iterator const& collision, aod::BCs const& bcs) + void processEventSelection(MyEvents::iterator const& collision) { - runEventSelection(collision, bcs); + runEventSelection(collision); } void processDummy(MyEvents&) @@ -186,12 +201,15 @@ struct DQEventSelectionTask { struct DQBarrelTrackSelection { Produces trackSel; + Produces emuSel; OutputObj fOutputList{"output"}; HistogramManager* fHistMan; Configurable fConfigCuts{"cfgBarrelTrackCuts", "jpsiPID1", "Comma separated list of barrel track cuts"}; + Configurable fConfigCutsForEMu{"cfgBarrelTrackCutsForEMu", "jpsiPID1", "Comma separated list of barrel track cuts"}; Configurable fConfigQA{"cfgWithQA", false, "If true, fill QA histograms"}; - Configurable fPropTrack{"cfgPropTrack", false, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; + Configurable fConfigHistClasses{"cfgHistClasses", "its,tpcpid,dca", "If true, fill QA histograms"}; + Configurable fPropTrack{"cfgPropTrack", true, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable fConfigCcdbPathTPC{"ccdb-path-tpc", "Users/i/iarsene/Calib/TPCpostCalib", "base path to the ccdb object"}; Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; @@ -202,6 +220,7 @@ struct DQBarrelTrackSelection { Preslice barrelTrackIndicesPerCollision = aod::track_association::collisionId; std::vector fTrackCuts; + std::vector fEMuTrackCuts; std::vector fCutHistNames; int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. @@ -209,6 +228,7 @@ struct DQBarrelTrackSelection { void init(o2::framework::InitContext&) { TString cutNamesStr = fConfigCuts.value; + TString cutEMuNamesStr = fConfigCutsForEMu.value; if (!cutNamesStr.IsNull()) { std::unique_ptr objArray(cutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { @@ -220,6 +240,17 @@ struct DQBarrelTrackSelection { } } } + if (!cutEMuNamesStr.IsNull()) { + std::unique_ptr objArray2(cutEMuNamesStr.Tokenize(",")); + for (int icut = 0; icut < objArray2->GetEntries(); ++icut) { + AnalysisCompositeCut* cut2 = dqcuts::GetCompositeCut(objArray2->At(icut)->GetName()); + if (cut2) { + fEMuTrackCuts.push_back(*cut2); + } else { + LOGF(fatal, "Invalid e-mu cut provided: %s", objArray2->At(icut)->GetName()); + } + } + } VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill if (fConfigQA) { @@ -234,18 +265,15 @@ struct DQBarrelTrackSelection { fCutHistNames.push_back(Form("TrackBarrel_%s", cut.GetName())); } - DefineHistograms(fHistMan, cutNames.Data()); // define all histograms + DefineHistograms(fHistMan, cutNames.Data(), fConfigHistClasses.value); // define all histograms VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); // CCDB configuration - if (fConfigComputeTPCpostCalib) { - fCCDB->setURL(fConfigCcdbUrl.value); - fCCDB->setCaching(true); - fCCDB->setLocalObjectValidityChecking(); - // Not later than now objects - fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); - } + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); } } @@ -256,8 +284,14 @@ struct DQBarrelTrackSelection { auto bc = bcs.begin(); // check just the first bc to get the run number if (fCurrentRun != bc.runNumber()) { fCurrentRun = bc.runNumber(); - o2::parameters::GRPMagField* grpo = fCCDB->getForTimeStamp("GLO/Config/GRPMagField", bc.timestamp()); - o2::base::Propagator::initFieldFromGRP(grpo); + + o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp("GLO/Config/GRPMagField", bc.timestamp()); + if (grpmag != nullptr) { + VarManager::SetMagneticField(grpmag->getNominalL3Field()); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", bc.timestamp()); + } + if (fConfigComputeTPCpostCalib) { auto calibList = fCCDB->getForTimeStamp(fConfigCcdbPathTPC.value, bc.timestamp()); VarManager::SetCalibrationObject(VarManager::kTPCElectronMean, calibList->FindObject("mean_map_electron")); @@ -271,21 +305,24 @@ struct DQBarrelTrackSelection { // material correction for track propagation // o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + // o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - uint32_t filterMap = uint32_t(0); + uint32_t filterMap = static_cast(0); + uint32_t filterMapEMu = static_cast(0); trackSel.reserve(tracksBarrel.size()); + emuSel.reserve(tracksBarrel.size()); VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); for (auto& trackAssoc : trackAssocs) { - filterMap = uint32_t(0); + filterMap = static_cast(0); + filterMapEMu = static_cast(0); auto track = trackAssoc.template track_as(); VarManager::FillTrack(track); // compute quantities which depend on the associated collision, such as DCA if (fPropTrack && (track.collisionId() != collision.globalIndex())) { - VarManager::FillTrackCollisionMatCorr(track, collision, noMatCorr, o2::base::Propagator::Instance()); + VarManager::FillTrackCollision(track, collision); } if (fConfigQA) { fHistMan->FillHistClass("TrackBarrel_BeforeCuts", VarManager::fgValues); @@ -293,13 +330,20 @@ struct DQBarrelTrackSelection { int i = 0; for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); ++cut, ++i) { if ((*cut).IsSelected(VarManager::fgValues)) { - filterMap |= (uint32_t(1) << i); + filterMap |= (static_cast(1) << i); if (fConfigQA) { fHistMan->FillHistClass(fCutHistNames[i].Data(), VarManager::fgValues); } } } + int j = 0; + for (auto cut = fEMuTrackCuts.begin(); cut != fEMuTrackCuts.end(); ++cut, ++j) { + if ((*cut).IsSelected(VarManager::fgValues)) { + filterMapEMu |= (static_cast(1) << j); + } + } trackSel(filterMap); + emuSel(filterMapEMu); } // end loop over tracks } @@ -311,22 +355,34 @@ struct DQBarrelTrackSelection { } } + void processSelectionTPCPID(Collisions const& collisions, aod::BCsWithTimestamps const& bcs, MyBarrelTracksTPCPID const& tracks, aod::TrackAssoc const& trackAssocs) + { + for (auto& collision : collisions) { + auto trackIdsThisCollision = trackAssocs.sliceBy(barrelTrackIndicesPerCollision, collision.globalIndex()); + runTrackSelection(collision, bcs, tracks, trackIdsThisCollision); + } + } + void processDummy(MyBarrelTracks&) { // do nothing } PROCESS_SWITCH(DQBarrelTrackSelection, processSelection, "Run barrel track selection", false); + PROCESS_SWITCH(DQBarrelTrackSelection, processSelectionTPCPID, "Run barrel track selection, just TPC PID (no TOF)", false); PROCESS_SWITCH(DQBarrelTrackSelection, processDummy, "Dummy function", false); }; struct DQMuonsSelection { Produces trackSel; + Produces emuSel; OutputObj fOutputList{"output"}; HistogramManager* fHistMan; Configurable fConfigCuts{"cfgMuonsCuts", "muonQualityCuts", "Comma separated list of ADDITIONAL muon track cuts"}; + Configurable fConfigCutsForEMu{"cfgMuonsCutsForEMu", "muonQualityCuts", "Comma separated list of ADDITIONAL muon track cuts"}; Configurable fConfigQA{"cfgWithQA", false, "If true, fill QA histograms"}; + Configurable fConfigHistClasses{"cfgHistClasses", "muon", "If true, fill QA histograms"}; Configurable fPropMuon{"cfgPropMuon", false, "Propgate muon tracks through absorber"}; Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; @@ -342,6 +398,7 @@ struct DQMuonsSelection { // TODO: configure the histogram classes to be filled by QA std::vector fTrackCuts; + std::vector fEMuTrackCuts; std::vector fCutHistNames; void init(o2::framework::InitContext&) @@ -356,12 +413,19 @@ struct DQMuonsSelection { } TString cutNamesStr = fConfigCuts.value; + TString cutEMuNamesStr = fConfigCutsForEMu.value; if (!cutNamesStr.IsNull()) { std::unique_ptr objArray(cutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { fTrackCuts.push_back(*dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); } } + if (!cutEMuNamesStr.IsNull()) { + std::unique_ptr objArray2(cutEMuNamesStr.Tokenize(",")); + for (int icut = 0; icut < objArray2->GetEntries(); ++icut) { + fEMuTrackCuts.push_back(*dqcuts::GetCompositeCut(objArray2->At(icut)->GetName())); + } + } VarManager::SetUseVars(AnalysisCut::fgUsedVars); if (fConfigQA) { @@ -376,7 +440,7 @@ struct DQMuonsSelection { fCutHistNames.push_back(Form("Muon_%s", fTrackCuts[i].GetName())); } - DefineHistograms(fHistMan, cutNames.Data()); // define all histograms + DefineHistograms(fHistMan, cutNames.Data(), fConfigHistClasses.value); // define all histograms VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); } @@ -397,13 +461,16 @@ struct DQMuonsSelection { } } - uint32_t filterMap = uint32_t(0); + uint32_t filterMap = static_cast(0); + uint32_t filterMapEMu = static_cast(0); trackSel.reserve(muons.size()); + emuSel.reserve(muons.size()); VarManager::ResetValues(0, VarManager::kNMuonTrackVariables); for (auto& muonAssoc : muonAssocs) { - filterMap = uint32_t(0); + filterMap = static_cast(0); + filterMapEMu = static_cast(0); auto muon = muonAssoc.template fwdtrack_as(); VarManager::FillTrack(muon); if (fPropMuon) { @@ -415,13 +482,20 @@ struct DQMuonsSelection { int i = 0; for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); ++cut, ++i) { if ((*cut).IsSelected(VarManager::fgValues)) { - filterMap |= (uint32_t(1) << i); + filterMap |= (static_cast(1) << i); if (fConfigQA) { fHistMan->FillHistClass(fCutHistNames[i].Data(), VarManager::fgValues); } } } + int j = 0; + for (auto cut = fEMuTrackCuts.begin(); cut != fEMuTrackCuts.end(); ++cut, ++j) { + if ((*cut).IsSelected(VarManager::fgValues)) { + filterMapEMu |= (static_cast(1) << j); + } + } trackSel(filterMap); + emuSel(filterMapEMu); } // end loop over muons } @@ -441,80 +515,20 @@ struct DQMuonsSelection { PROCESS_SWITCH(DQMuonsSelection, processDummy, "Dummy function", false); }; -/* -struct DQTrackToCollisionAssociation { - - Produces association; - Produces reverseIndices; - Produces fwdassociation; - Produces fwdreverseIndices; - - // NOTE: the options for the collision associator are common for both the barrel and muon - // We should add separate ones if needed - Configurable nSigmaForTimeCompat{"nSigmaForTimeCompat", 4.f, "number of sigmas for time compatibility"}; - Configurable timeMargin{"timeMargin", 0.f, "time margin in ns added to uncertainty because of uncalibrated TPC"}; - Configurable usePVAssociation{"usePVAssociation", true, "if the track is a PV contributor, use the collision time for it"}; - Configurable includeUnassigned{"includeUnassigned", false, "consider also tracks which are not assigned to any collision"}; - Configurable fillTableOfCollIdsPerTrack{"fillTableOfCollIdsPerTrack", false, "fill additional table with vector of collision ids per track"}; - Configurable bcWindowForOneSigma{"bcWindowForOneSigma", 60, "BC window to be multiplied by the number of sigmas to define maximum window to be considered"}; - - CollisionAssociation collisionAssociatorBarrel; - CollisionAssociation collisionAssociatorMuon; - - Filter filterBarrelTrackSelected = aod::dqppfilter::isDQBarrelSelected > uint32_t(0); - Filter filterMuonTrackSelected = aod::dqppfilter::isDQMuonSelected > uint32_t(0); - - void init(o2::framework::InitContext const&) - { - // set options in track-to-collision association - collisionAssociatorBarrel.setNumSigmaForTimeCompat(nSigmaForTimeCompat); - collisionAssociatorBarrel.setTimeMargin(timeMargin); - collisionAssociatorBarrel.setTrackSelectionOptionForStdAssoc(track_association::TrackSelection::None); - collisionAssociatorBarrel.setUsePvAssociation(usePVAssociation); - collisionAssociatorBarrel.setIncludeUnassigned(includeUnassigned); - collisionAssociatorBarrel.setFillTableOfCollIdsPerTrack(fillTableOfCollIdsPerTrack); - collisionAssociatorBarrel.setBcWindow(bcWindowForOneSigma); - // set options in muon-to-collision association - collisionAssociatorMuon.setNumSigmaForTimeCompat(nSigmaForTimeCompat); - collisionAssociatorMuon.setTimeMargin(timeMargin); - collisionAssociatorMuon.setTrackSelectionOptionForStdAssoc(track_association::TrackSelection::None); - collisionAssociatorMuon.setUsePvAssociation(false); - collisionAssociatorMuon.setIncludeUnassigned(includeUnassigned); - collisionAssociatorMuon.setFillTableOfCollIdsPerTrack(fillTableOfCollIdsPerTrack); - collisionAssociatorMuon.setBcWindow(bcWindowForOneSigma); - } - - void processAssocWithTime(Collisions const& collisions, - MyBarrelTracksSelected const& tracksUnfiltered, soa::Filtered const& tracks, - FwdTracks const& muons, - AmbiguousTracks const& ambiguousTracks, AmbiguousFwdTracks const& ambiguousFwdTracks, BCs const& bcs) - { - collisionAssociatorBarrel.runAssocWithTime(collisions, tracksUnfiltered, tracks, ambiguousTracks, bcs, association, reverseIndices); - collisionAssociatorMuon.runAssocWithTime(collisions, muons, muons, ambiguousFwdTracks, bcs, fwdassociation, fwdreverseIndices); - }; - void processDummy(Collisions&) - { - // do nothing - } - - PROCESS_SWITCH(DQTrackToCollisionAssociation, processAssocWithTime, "Produce track-to-collision associations based on time", false); - PROCESS_SWITCH(DQTrackToCollisionAssociation, processDummy, "Dummy function", false); -}; -*/ - struct DQFilterPPTask { Produces eventFilter; Produces dqtable; OutputObj fOutputList{"output"}; - OutputObj fStats{"Statistics"}; + OutputObj fStats{"Statistics"}; HistogramManager* fHistMan; Configurable fConfigBarrelSelections{"cfgBarrelSels", "jpsiPID1:pairMassLow:1", ":[]:,[:[]:],..."}; Configurable fConfigMuonSelections{"cfgMuonSels", "muonQualityCuts:pairNoCut:1", ":[]:"}; + Configurable fConfigElectronMuonSelections{"cfgElectronMuonSels", "jpsiPID1:muonQualityCuts:pairNoCut:1", "::[]:"}; Configurable fConfigQA{"cfgWithQA", false, "If true, fill QA histograms"}; Configurable fConfigFilterLsBarrelTracksPairs{"cfgWithBarrelLS", "false", "Comma separated list of booleans for each trigger, If true, also select like sign (--/++) barrel track pairs"}; Configurable fConfigFilterLsMuonsPairs{"cfgWithMuonLS", "false", "Comma separated list of booleans for each trigger, If true, also select like sign (--/++) muon pairs"}; - + Configurable fConfigFilterLsElectronMuonsPairs{"cfgWithElectronMuonLS", "false", "Comma separated list of booleans for each trigger, If true, also select like sign (--/++) muon pairs"}; Configurable fPropMuon{"cfgPropMuon", false, "Propgate muon tracks through absorber"}; Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; @@ -527,18 +541,27 @@ struct DQFilterPPTask { int fNBarrelCuts; // number of barrel selections int fNMuonCuts; // number of muon selections + int fNElectronMuonCuts; // number of electron-muon selections std::vector fBarrelRunPairing; // bit map on whether the selections require pairing (barrel) std::vector fMuonRunPairing; // bit map on whether the selections require pairing (muon) + std::vector fElectronMuonRunPairing; // bit map on whether the selections require pairing (e-mu) std::vector fBarrelNreqObjs; // minimal number of tracks/pairs required (barrel) std::vector fMuonNreqObjs; // minimal number of tracks/pairs required (muon) + std::vector fElectronMuonNreqObjs; // minimal number of electron-muon pairs required std::map fBarrelPairCuts; // map of barrel pair cuts std::map fMuonPairCuts; // map of muon pair cuts + std::map fElectronMuonPairCuts; // map of electron-muon pair cuts std::map fBarrelPairHistNames; // map with names of the barrel pairing histogram directories std::map fMuonPairHistNames; // map with names of the muon pairing histogram directories + std::map fElectronMuonPairHistNames; // map with names of the electron-muon pairing histogram directories std::map fFiltersMap; // map of filters for events that passed at least one filter std::map> fCEFPfilters; // map of CEFP filters for events that passed at least one filter + uint32_t fPairingLSBarrel; // used to set in which cut setting LS pairs will be analysed + uint32_t fPairingLSMuon; // used to set in which cut setting LS pairs will be analysed + uint32_t fPairingLSBarrelMuon; // used to set in which cut setting LS pairs will be analysed + void DefineCuts() { TString barrelSelsStr = fConfigBarrelSelections.value; @@ -585,10 +608,32 @@ struct DQFilterPPTask { } } } + // electron-muon pair + TString electronMuonSelsStr = fConfigElectronMuonSelections.value; + std::unique_ptr objArray3(electronMuonSelsStr.Tokenize(",")); + fNElectronMuonCuts = objArray3->GetEntries(); + if (fNElectronMuonCuts) { + for (int icut = 0; icut < fNElectronMuonCuts; ++icut) { + TString selStr = objArray3->At(icut)->GetName(); + std::unique_ptr sel(selStr.Tokenize(":")); + if (sel->GetEntries() < 3 || sel->GetEntries() > 4) { + continue; + } + if (sel->GetEntries() == 4) { + fElectronMuonPairCuts[icut] = (*dqcuts::GetCompositeCut(sel->At(2)->GetName())); + fElectronMuonRunPairing.push_back(true); + fElectronMuonNreqObjs.push_back(std::atoi(sel->At(3)->GetName())); + fElectronMuonPairHistNames[icut] = Form("PairsElectronMuonSEPM_%s_%s_%s", sel->At(0)->GetName(), sel->At(1)->GetName(), sel->At(2)->GetName()); + } else { + fElectronMuonNreqObjs.push_back(std::atoi(sel->At(2)->GetName())); + fElectronMuonRunPairing.push_back(false); + } + } + } VarManager::SetUseVars(AnalysisCut::fgUsedVars); // setup the Stats histogram - fStats.setObject(new TH1F("Statistics", "Stats for DQ triggers", fNBarrelCuts + fNMuonCuts + 2, -2.5, -0.5 + fNBarrelCuts + fNMuonCuts)); + fStats.setObject(new TH1D("Statistics", "Stats for DQ triggers", fNBarrelCuts + fNMuonCuts + fNElectronMuonCuts + 2, -2.5, -0.5 + fNBarrelCuts + fNMuonCuts + fNElectronMuonCuts)); fStats->GetXaxis()->SetBinLabel(1, "Events inspected"); fStats->GetXaxis()->SetBinLabel(2, "Events selected"); if (fNBarrelCuts) { @@ -601,6 +646,11 @@ struct DQFilterPPTask { fStats->GetXaxis()->SetBinLabel(ib, objArray2->At(ib - 3 - fNBarrelCuts)->GetName()); } } + if (fNElectronMuonCuts) { + for (int ib = 3 + fNBarrelCuts + fNMuonCuts; ib < 3 + fNBarrelCuts + fNMuonCuts + fNElectronMuonCuts; ib++) { + fStats->GetXaxis()->SetBinLabel(ib, objArray3->At(ib - 3 - fNBarrelCuts - fNMuonCuts)->GetName()); + } + } } void init(o2::framework::InitContext&) @@ -615,6 +665,39 @@ struct DQFilterPPTask { } DefineCuts(); + // check which selection should use like sign (LS) (--/++) barrel track pairs + fPairingLSBarrel = 0; + TString barrelLSstr = fConfigFilterLsBarrelTracksPairs.value; + std::unique_ptr objArrayLS(barrelLSstr.Tokenize(",")); + for (int icut = 0; icut < fNBarrelCuts; icut++) { + TString objStr = objArrayLS->At(icut)->GetName(); + if (!objStr.CompareTo("true")) { + fPairingLSBarrel |= (static_cast(1) << icut); + } + } + + // check which selection should use like sign (LS) (--/++) muon track pairs + fPairingLSMuon = 0; + TString musonLSstr = fConfigFilterLsMuonsPairs.value; + std::unique_ptr objArrayMuonLS(musonLSstr.Tokenize(",")); + for (int icut = 0; icut < fNMuonCuts; icut++) { + TString objStr = objArrayMuonLS->At(icut)->GetName(); + if (!objStr.CompareTo("true")) { + fPairingLSMuon |= (static_cast(1) << icut); + } + } + + // check which selection should use like sign (LS) (--/++) muon-barrel pairs + fPairingLSBarrelMuon = 0; // reset the decisions for electron-muons + TString electronMuonLSstr = fConfigFilterLsElectronMuonsPairs.value; + std::unique_ptr objArrayElectronMuonLS(electronMuonLSstr.Tokenize(",")); + for (int icut = 0; icut < fNElectronMuonCuts; icut++) { + TString objStr = objArrayElectronMuonLS->At(icut)->GetName(); + if (!objStr.CompareTo("true")) { + fPairingLSBarrelMuon |= (static_cast(1) << icut); + } + } + if (fConfigQA) { // initialize the variable manager VarManager::SetDefaultVarNames(); @@ -630,7 +713,11 @@ struct DQFilterPPTask { histNames += value; histNames += ";"; } - DefineHistograms(fHistMan, histNames.Data()); + for (const auto& [key, value] : fElectronMuonPairHistNames) { + histNames += value; + histNames += ";"; + } + DefineHistograms(fHistMan, histNames.Data(), "cepf"); VarManager::SetUseVars(fHistMan->GetUsedVars()); fOutputList.setObject(fHistMan->GetMainHistogramList()); } @@ -658,161 +745,307 @@ struct DQFilterPPTask { VarManager::ResetValues(0, VarManager::kNVars); VarManager::FillEvent(collision); // event properties could be needed for cuts or histogramming + std::vector> taggedCollisions(fNBarrelCuts + fNMuonCuts + fNElectronMuonCuts); // collisions corresponding to selected associations or to which selected tracks are assigned in AO2D + std::vector objCountersBarrel(fNBarrelCuts, 0); // init all counters to zero + uint32_t pairingMask = 0; // in order to know which of the selections actually require pairing + uint32_t pairFilter = 0; // count the number of barrel tracks fulfilling each cut - for (auto trackAssoc : barrelAssocs) { - for (int i = 0; i < fNBarrelCuts; ++i) { - if (trackAssoc.isDQBarrelSelected() & (uint32_t(1) << i)) { - objCountersBarrel[i] += 1; + if constexpr (static_cast(TTrackFillMap)) { + for (auto trackAssoc : barrelAssocs) { + for (int i = 0; i < fNBarrelCuts; ++i) { + if (trackAssoc.isDQBarrelSelected() & (static_cast(1) << i)) { + objCountersBarrel[i] += 1; + taggedCollisions[i][collision.globalIndex()] = 1; // add the current associated collision to the map + auto t1 = trackAssoc.template track_as(); + if (t1.has_collision()) { + taggedCollisions[i][t1.collisionId()] = 1; // add the originally assigned collision to the map + } + } } } - } - // check which selections require pairing - uint32_t pairingMask = 0; // in order to know which of the selections actually require pairing - for (int i = 0; i < fNBarrelCuts; i++) { - if (fBarrelRunPairing[i]) { - if (objCountersBarrel[i] > 1) { // pairing has to be enabled and at least two tracks are needed - pairingMask |= (uint32_t(1) << i); + // check which selections require pairing + for (int i = 0; i < fNBarrelCuts; i++) { + if (fBarrelRunPairing[i]) { + if (objCountersBarrel[i] > 1) { // pairing has to be enabled and at least two tracks are needed + pairingMask |= (static_cast(1) << i); + } + objCountersBarrel[i] = 0; // reset counters for selections where pairing is needed (count pairs instead) + taggedCollisions[i].clear(); // empty the list of tagged collisions if pairing is needed (so we count just events with pairs or containing selected pair legs) } - objCountersBarrel[i] = 0; // reset counters for selections where pairing is needed (count pairs instead) } - } - // check which selection should use like sign (LS) (--/++) barrel track pairs - uint32_t pairingLS = 0; // used to set in which cut setting LS pairs will be analysed - TString barrelLSstr = fConfigFilterLsBarrelTracksPairs.value; - std::unique_ptr objArrayLS(barrelLSstr.Tokenize(",")); - for (int icut = 0; icut < fNBarrelCuts; icut++) { - TString objStr = objArrayLS->At(icut)->GetName(); - if (!objStr.CompareTo("true")) { - pairingLS |= (uint32_t(1) << icut); - } - } + // run pairing if there is at least one selection that requires it + if (pairingMask > 0) { + // run pairing on the collision grouped associations + for (auto& [a1, a2] : combinations(barrelAssocs, barrelAssocs)) { - // run pairing if there is at least one selection that requires it - uint32_t pairFilter = 0; - if (pairingMask > 0) { - // run pairing on the collision grouped associations - for (auto& [a1, a2] : combinations(barrelAssocs, barrelAssocs)) { + // get the tracks from the index stored in the association + auto t1 = a1.template track_as(); + auto t2 = a2.template track_as(); + + // check the pairing mask and that the tracks share a cut bit + pairFilter = pairingMask & a1.isDQBarrelSelected() & a2.isDQBarrelSelected(); + if (pairFilter == 0) { + continue; + } - // get the tracks from the index stored in the association - auto t1 = a1.template track_as(); - auto t2 = a2.template track_as(); + // construct the pair and apply pair cuts + VarManager::FillPair(t1, t2); // compute pair quantities + for (int icut = 0; icut < fNBarrelCuts; icut++) { + // select like-sign pairs if trigger has set boolean true within fConfigFilterLsBarrelTracksPairs + if (!(fPairingLSBarrel & (static_cast(1) << icut))) { + if (t1.sign() * t2.sign() > 0) { + continue; + } + } - // check the pairing mask and that the tracks share a cut bit - pairFilter = pairingMask & a1.isDQBarrelSelected() & a2.isDQBarrelSelected(); - if (pairFilter == 0) { - continue; - } - // construct the pair and apply pair cuts - VarManager::FillPair(t1, t2); // compute pair quantities - for (int icut = 0; icut < fNBarrelCuts; icut++) { - // select like-sign pairs if trigger has set boolean true within fConfigFilterLsBarrelTracksPairs - if (!(pairingLS & (uint32_t(1) << icut))) { - if (t1.sign() * t2.sign() > 0) { + if (!(pairFilter & (static_cast(1) << icut))) { + continue; + } + if (!fBarrelPairCuts[icut].IsSelected(VarManager::fgValues)) { continue; } - } - if (!(pairFilter & (uint32_t(1) << icut))) { - continue; - } - if (!fBarrelPairCuts[icut].IsSelected(VarManager::fgValues)) { - continue; - } - objCountersBarrel[icut] += 1; // count the pair - if (fConfigQA) { // fill histograms if QA is enabled - fHistMan->FillHistClass(fBarrelPairHistNames[icut].Data(), VarManager::fgValues); + taggedCollisions[icut][collision.globalIndex()] = 1; // add the originally assigned collision to the map + if (t1.has_collision()) { + taggedCollisions[icut][t1.collisionId()] = 1; // add the originally assigned collision to the map + } + if (t2.has_collision()) { + taggedCollisions[icut][t2.collisionId()] = 1; // add the originally assigned collision to the map + } + + objCountersBarrel[icut] += 1; // count the pair + if (fConfigQA) { // fill histograms if QA is enabled + fHistMan->FillHistClass(fBarrelPairHistNames[icut].Data(), VarManager::fgValues); + } } } } } std::vector objCountersMuon(fNMuonCuts, 0); // init all counters to zero - // count the number of muon-collision associations fulfilling each selection - for (auto muon : muonAssocs) { - for (int i = 0; i < fNMuonCuts; ++i) { - if (muon.isDQMuonSelected() & (uint32_t(1) << i)) { - objCountersMuon[i] += 1; + if constexpr (static_cast(TMuonFillMap)) { + // count the number of muon-collision associations fulfilling each selection + for (auto muon : muonAssocs) { + for (int i = 0; i < fNMuonCuts; ++i) { + if (muon.isDQMuonSelected() & (static_cast(1) << i)) { + objCountersMuon[i] += 1; + taggedCollisions[i + fNBarrelCuts][collision.globalIndex()] = 1; // add the current associated collision to the map + auto t1 = muon.template fwdtrack_as(); + if (t1.has_collision()) { + taggedCollisions[i + fNBarrelCuts][t1.collisionId()] = 1; // add the originally assigned collision to the map + } + } } } - } - // check which muon selections require pairing - pairingMask = 0; // reset the mask for the muons - for (int i = 0; i < fNMuonCuts; i++) { - if (fMuonRunPairing[i]) { // pairing has to be enabled and at least two tracks are needed - if (objCountersMuon[i] > 1) { - pairingMask |= (uint32_t(1) << i); + // check which muon selections require pairing + pairingMask = 0; // reset the mask for the muons + for (int i = 0; i < fNMuonCuts; i++) { + if (fMuonRunPairing[i]) { // pairing has to be enabled and at least two tracks are needed + if (objCountersMuon[i] > 1) { + pairingMask |= (static_cast(1) << i); + } + objCountersMuon[i] = 0; // reset counters for selections where pairing is needed (count pairs instead) + taggedCollisions[i + fNBarrelCuts].clear(); // empty the list of tagged collisions if pairing is needed (so we count just events with pairs or containing selected pair legs) } - objCountersMuon[i] = 0; // reset counters for selections where pairing is needed (count pairs instead) } - } - // check which selection should use like sign (LS) (--/++) muon track pairs - pairingLS = 0; // reset the decisions for muons - TString musonLSstr = fConfigFilterLsMuonsPairs.value; - std::unique_ptr objArrayMuonLS(musonLSstr.Tokenize(",")); - for (int icut = 0; icut < fNMuonCuts; icut++) { - TString objStr = objArrayMuonLS->At(icut)->GetName(); - if (!objStr.CompareTo("true")) { - pairingLS |= (uint32_t(1) << icut); - } - } - - // run pairing if there is at least one selection that requires it - pairFilter = 0; - if (pairingMask > 0) { - // pairing is done using the collision grouped muon associations - for (auto& [a1, a2] : combinations(muonAssocs, muonAssocs)) { + // run pairing if there is at least one selection that requires it + pairFilter = 0; + if (pairingMask > 0) { + // pairing is done using the collision grouped muon associations + for (auto& [a1, a2] : combinations(muonAssocs, muonAssocs)) { - // check the pairing mask and that the tracks share a cut bit - pairFilter = pairingMask & a1.isDQMuonSelected() & a2.isDQMuonSelected(); - if (pairFilter == 0) { - continue; - } + // check the pairing mask and that the tracks share a cut bit + pairFilter = pairingMask & a1.isDQMuonSelected() & a2.isDQMuonSelected(); + if (pairFilter == 0) { + continue; + } - // get the real muon tracks - auto t1 = a1.template fwdtrack_as(); - auto t2 = a2.template fwdtrack_as(); + // get the real muon tracks + auto t1 = a1.template fwdtrack_as(); + auto t2 = a2.template fwdtrack_as(); - // construct the pair and apply cuts - VarManager::FillPair(t1, t2); // compute pair quantities - if (fPropMuon) { - VarManager::FillPairPropagateMuon(t1, t2, collision); - } - for (int icut = 0; icut < fNMuonCuts; icut++) { - // select like-sign pairs if trigger has set boolean true within fConfigFilterLsMuonsPairs - if (!(pairingLS & (uint32_t(1) << icut))) { - if (t1.sign() * t2.sign() > 0) { + // construct the pair and apply cuts + VarManager::FillPair(t1, t2); // compute pair quantities + if (fPropMuon) { + VarManager::FillPairPropagateMuon(t1, t2, collision); + } + for (int icut = 0; icut < fNMuonCuts; icut++) { + // select like-sign pairs if trigger has set boolean true within fConfigFilterLsMuonsPairs + if (!(fPairingLSMuon & (static_cast(1) << icut))) { + if (t1.sign() * t2.sign() > 0) { + continue; + } + } + if (!(pairFilter & (static_cast(1) << icut))) { + continue; + } + if (!fMuonPairCuts[icut].IsSelected(VarManager::fgValues)) { continue; } + + taggedCollisions[icut + fNBarrelCuts][collision.globalIndex()] = 1; // add the originally assigned collision to the map + if (t1.has_collision()) { + taggedCollisions[icut + fNBarrelCuts][t1.collisionId()] = 1; // add the originally assigned collision to the map + } + if (t2.has_collision()) { + taggedCollisions[icut + fNBarrelCuts][t2.collisionId()] = 1; // add the originally assigned collision to the map + } + + objCountersMuon[icut] += 1; + if (fConfigQA) { + fHistMan->FillHistClass(fMuonPairHistNames[icut].Data(), VarManager::fgValues); + } } - if (!(pairFilter & (uint32_t(1) << icut))) { - continue; + } + } + } + + // electron-muon pair + std::vector objCountersElectronMuon(fNElectronMuonCuts, 0); // init all counters to zero + if constexpr (static_cast(TTrackFillMap) && static_cast(TMuonFillMap)) { + pairingMask = 0; + for (auto& [trackAssoc, muon] : combinations(barrelAssocs, muonAssocs)) { + for (int i = 0; i < fNElectronMuonCuts; ++i) { + if (trackAssoc.isDQEMuBarrelSelected() & muon.isDQEMuMuonSelected() & (static_cast(1) << i)) { + if (fElectronMuonRunPairing[i]) { + pairingMask |= (static_cast(1) << i); + } } - if (!fMuonPairCuts[icut].IsSelected(VarManager::fgValues)) { + } + } + + // run pairing if there is at least one selection that requires it + pairFilter = 0; + if (pairingMask > 0) { + // pairing is done using the collision grouped electron and muon associations + for (auto& [a1, a2] : combinations(barrelAssocs, muonAssocs)) { + // check the pairing mask and that the tracks share a cut bit + pairFilter = pairingMask & a1.isDQEMuBarrelSelected() & a2.isDQEMuMuonSelected(); + if (pairFilter == 0) { continue; } - objCountersMuon[icut] += 1; - if (fConfigQA) { - fHistMan->FillHistClass(fMuonPairHistNames[icut].Data(), VarManager::fgValues); + // get the real electron and muon tracks + auto t1 = a1.template track_as(); + auto t2 = a2.template fwdtrack_as(); + // construct the pair and apply cuts + VarManager::FillPair(t1, t2); // compute pair quantities + for (int icut = 0; icut < fNElectronMuonCuts; icut++) { + // select like-sign pairs if trigger has set boolean true within fConfigFilterLsElectronMuonsPairs + if (!(fPairingLSBarrelMuon & (static_cast(1) << icut))) { + if (t1.sign() * t2.sign() > 0) { + continue; + } + } + if (!(pairFilter & (static_cast(1) << icut))) { + continue; + } + if (!fElectronMuonPairCuts[icut].IsSelected(VarManager::fgValues)) { + continue; + } + + taggedCollisions[icut + fNBarrelCuts + fNMuonCuts][collision.globalIndex()] = 1; // add the originally assigned collision to the map + if (t1.has_collision()) { + taggedCollisions[icut + fNBarrelCuts + fNMuonCuts][t1.collisionId()] = 1; // add the originally assigned collision to the map + } + if (t2.has_collision()) { + taggedCollisions[icut + fNBarrelCuts + fNMuonCuts][t2.collisionId()] = 1; // add the originally assigned collision to the map + } + + objCountersElectronMuon[icut] += 1; + if (fConfigQA) { + fHistMan->FillHistClass(fElectronMuonPairHistNames[icut].Data(), VarManager::fgValues); + } } } } } - // compute the decisions and publish uint64_t filter = 0; - for (int i = 0; i < fNBarrelCuts; i++) { - if (objCountersBarrel[i] >= fBarrelNreqObjs[i]) { - filter |= (uint64_t(1) << i); + if constexpr (static_cast(TTrackFillMap)) { + for (int i = 0; i < fNBarrelCuts; i++) { + if (objCountersBarrel[i] >= fBarrelNreqObjs[i]) { + filter |= (static_cast(1) << i); + } else { + taggedCollisions[i].clear(); + } } } - for (int i = 0; i < fNMuonCuts; i++) { - if (objCountersMuon[i] >= fMuonNreqObjs[i]) { - filter |= (uint64_t(1) << (i + fNBarrelCuts)); + if constexpr (static_cast(TMuonFillMap)) { + for (int i = 0; i < fNMuonCuts; i++) { + if (objCountersMuon[i] >= fMuonNreqObjs[i]) { + filter |= (static_cast(1) << (i + fNBarrelCuts)); + } else { + taggedCollisions[i + fNBarrelCuts].clear(); + } + } + } + if constexpr (static_cast(TTrackFillMap) && static_cast(TMuonFillMap)) { + for (int i = 0; i < fNElectronMuonCuts; i++) { + if (objCountersElectronMuon[i] >= fElectronMuonNreqObjs[i]) { + filter |= (static_cast(1) << (i + fNBarrelCuts + fNMuonCuts)); + } else { + taggedCollisions[i + fNBarrelCuts + fNMuonCuts].clear(); + } + } + } + + if (filter > 0) { + std::vector decisions(kNTriggersDQ, false); // event decisions to be transmitted to CEFP + for (int i = 0; i < fNBarrelCuts; i++) { + if (filter & (static_cast(1) << i)) { + if (i < kNTriggersDQ) { + decisions[i] = true; + } + } + } + for (int i = fNBarrelCuts; i < fNBarrelCuts + fNMuonCuts; i++) { + if (filter & (static_cast(1) << i)) { + if (i < kNTriggersDQ) { + decisions[i] = true; + } + } + } + for (int i = fNBarrelCuts + fNMuonCuts; i < fNBarrelCuts + fNMuonCuts + fNElectronMuonCuts; i++) { + if (filter & (static_cast(1) << i)) { + if (i < kNTriggersDQ) { + decisions[i] = true; + } + } + } + // if this collision fired at least one input, add it to the map, or if it is there already, update the decisions with a logical OR + // This may happen in the case when some collisions beyond the iterator are added because they contain ambiguous tracks fired on by another collision + if (fFiltersMap.find(collision.globalIndex()) == fFiltersMap.end()) { + fFiltersMap[collision.globalIndex()] = filter; + fCEFPfilters[collision.globalIndex()] = decisions; + } else { // this collision was already fired, possible via collision - track association; add as an OR the new decisions + fFiltersMap[collision.globalIndex()] |= filter; + for (int i = 0; i < kNTriggersDQ; i++) { + if (decisions[i]) { + fCEFPfilters[collision.globalIndex()][i] = true; + } + } + } + + // Go through the list of tagged collisions and add also those to the maps + // The reason is that in the tagged collisions we include also those collisions which did not fired the trigger conditions, but they contain + // tracks which in other associations contributed to fired triggers in other events. + for (int iTrig = 0; iTrig < fNBarrelCuts + fNMuonCuts + fNElectronMuonCuts; iTrig++) { + for (auto& [collId, aValue] : taggedCollisions[iTrig]) { + if (fFiltersMap.find(collId) == fFiltersMap.end()) { + fFiltersMap[collId] = (static_cast(1) << iTrig); + std::vector decisionsAdds(kNTriggersDQ, false); // event decisions to be transmitted to CEFP + decisionsAdds[iTrig] = true; + fCEFPfilters[collId] = decisionsAdds; + } else { // this collision was already fired, possible via collision - track association; add as an OR the new decisions + fFiltersMap[collId] |= (static_cast(1) << iTrig); + fCEFPfilters[collId][iTrig] = true; + } + } } } return filter; @@ -823,24 +1056,81 @@ struct DQFilterPPTask { void processFilterPP(MyEventsSelected const& collisions, aod::BCsWithTimestamps const& bcs, - MyBarrelTracksSelected const& tracks, + MyBarrelTracksTPCPID const& tracks, MyMuons const& muons, MyBarrelTracksAssocSelected const& trackAssocs, MyMuonsAssocSelected const& muonAssocs) { fFiltersMap.clear(); fCEFPfilters.clear(); - cout << "------------------- filterPP, n assocs barrel/muon :: " << trackAssocs.size() << " / " << muonAssocs.size() << endl; + // Loop over collisions + int eventsFired = 0; + for (const auto& collision : collisions) { + // skip those that do not pass our selection + if (!collision.isDQEventSelected()) { + continue; + } + // group the tracks and muons for this collision + auto groupedTrackIndices = trackAssocs.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + auto groupedMuonIndices = muonAssocs.sliceBy(muonIndicesPerCollision, collision.globalIndex()); + + uint64_t filter = 0; + // if there is at least one track or muon, run the filtering function and compute triggers + if (groupedTrackIndices.size() > 0 || groupedMuonIndices.size() > 0) { + filter = runFilterPP(collision, bcs, tracks, muons, groupedTrackIndices, groupedMuonIndices); + } + if (filter == 0) { + continue; + } + eventsFired++; + } + + // At this point, we have all the non-null decisions for all collisions. + // we loop again over collisions and create the decision tables + // NOTE: For the CEFP decisions, decisions are placed in a vector of bool in an ordered way: + // start with all configured barrel selections and then continue with those from muons + // The configured order has to be in sync with that implemented in the cefp task and can be done + // by preparing a dedicated json configuration file + int totalEventsTriggered = 0; + for (const auto& collision : collisions) { + fStats->Fill(-2.0); + if (!collision.isDQEventSelected()) { + eventFilter(0); + dqtable(false, false, false, false, false, false, false, false); + continue; + } + fStats->Fill(-1.0); - uint64_t barrelMask = 0; - for (int i = 0; i < fNBarrelCuts; i++) { - barrelMask |= (uint64_t(1) << i); + if (fFiltersMap.find(collision.globalIndex()) == fFiltersMap.end()) { + eventFilter(0); + dqtable(false, false, false, false, false, false, false, false); + } else { + totalEventsTriggered++; + for (int i = 0; i < fNBarrelCuts + fNMuonCuts + fNElectronMuonCuts; i++) { + if (fFiltersMap[collision.globalIndex()] & (static_cast(1) << i)) + fStats->Fill(static_cast(i)); + } + eventFilter(fFiltersMap[collision.globalIndex()]); + auto dqDecisions = fCEFPfilters[collision.globalIndex()]; + dqtable(dqDecisions[0], dqDecisions[1], dqDecisions[2], dqDecisions[3], dqDecisions[4], dqDecisions[5], dqDecisions[6], dqDecisions[7]); + } } + + cout << "-------------------- In this TF, eventsFired / totalTriggered :: " << eventsFired << "/" << totalEventsTriggered << endl; + } + + void processFilterMuonPP(MyEventsSelected const& collisions, + aod::BCsWithTimestamps const& bcs, + MyMuons const& muons, + MyMuonsAssocSelected const& muonAssocs) + { + fFiltersMap.clear(); + fCEFPfilters.clear(); + uint64_t muonMask = 0; - for (int i = fNBarrelCuts; i < fNBarrelCuts + fNMuonCuts; i++) { - muonMask |= (uint64_t(1) << i); + for (int i = 0; i < fNMuonCuts; i++) { + muonMask |= (static_cast(1) << i); } - // Loop over collisions // int event = 0; int eventsFired = 0; @@ -850,14 +1140,13 @@ struct DQFilterPPTask { // event++; continue; } - // group the tracks and muons for this collision - auto groupedTrackIndices = trackAssocs.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + // group the muons for this collision auto groupedMuonIndices = muonAssocs.sliceBy(muonIndicesPerCollision, collision.globalIndex()); uint64_t filter = 0; // if there is at least one track or muon, run the filtering function and compute triggers - if (groupedTrackIndices.size() > 0 || groupedMuonIndices.size() > 0) { - filter = runFilterPP(collision, bcs, tracks, muons, groupedTrackIndices, groupedMuonIndices); + if (groupedMuonIndices.size() > 0) { + filter = runFilterPP(collision, bcs, nullptr, muons, nullptr, groupedMuonIndices); } if (filter == 0) { // event++; @@ -866,21 +1155,13 @@ struct DQFilterPPTask { eventsFired++; // compute the CEPF decisions (this is done in a spacial setup with exactly kNTriggersDQ configured triggers) std::vector decisions(kNTriggersDQ, false); // event decisions to be transmitted to CEFP - for (int i = 0; i < fNBarrelCuts; i++) { - if (filter & (uint64_t(1) << i)) { + for (int i = 0; i < fNMuonCuts; i++) { + if (filter & (static_cast(1) << i)) { if (i < kNTriggersDQ) { decisions[i] = true; } } } - for (int i = fNBarrelCuts; i < fNBarrelCuts + fNMuonCuts; i++) { - if (filter & (uint64_t(1) << i)) { - if (i < kNTriggersDQ) { - decisions[i] = true; - } - } - } - // if this collision fired at least one input, add it to the map, or if it is there already, update the decisions with a logical OR // This may happen in the case when some collisions beyond the iterator are added because they contain ambiguous tracks fired on by another collision if (fFiltersMap.find(collision.globalIndex()) == fFiltersMap.end()) { @@ -895,33 +1176,6 @@ struct DQFilterPPTask { } } - // Now check through the associated tracks / fwdtracks and assign the same filter to their parent collisions - // This is needed since if a collision was selected because of a track association from a neighbouring collision, - // then one needs to select also that collision in order to be able to redo the pairing at analysis time. - if (filter & barrelMask) { - for (auto& a : groupedTrackIndices) { - auto t = a.template track_as(); - if (!t.has_collision()) { - continue; - } - auto tColl = t.collisionId(); - if (tColl == collision.globalIndex()) { // track from this collision, nothing to do - continue; - } else { - if (fFiltersMap.find(tColl) == fFiltersMap.end()) { - fFiltersMap[tColl] = filter; - fCEFPfilters[tColl] = decisions; - } else { // this collision was already fired, possible via collision - track association; add as an OR the new decisions - fFiltersMap[tColl] |= filter; - for (int i = 0; i < kNTriggersDQ; i++) { - if (decisions[i]) { - fCEFPfilters[tColl][i] = true; - } - } - } - } - } - } // Do the same for muons if (filter & muonMask) { for (auto& a : groupedMuonIndices) { @@ -961,23 +1215,23 @@ struct DQFilterPPTask { fStats->Fill(-2.0); if (!collision.isDQEventSelected()) { eventFilter(0); - dqtable(false, false, false, false, false, false, false); + dqtable(false, false, false, false, false, false, false, false); continue; } fStats->Fill(-1.0); if (fFiltersMap.find(collision.globalIndex()) == fFiltersMap.end()) { eventFilter(0); - dqtable(false, false, false, false, false, false, false); + dqtable(false, false, false, false, false, false, false, false); } else { totalEventsTriggered++; - for (int i = 0; i < fNBarrelCuts + fNMuonCuts; i++) { - if (fFiltersMap[collision.globalIndex()] & (uint32_t(1) << i)) + for (int i = 0; i < fNMuonCuts; i++) { + if (fFiltersMap[collision.globalIndex()] & (static_cast(1) << i)) fStats->Fill(static_cast(i)); } eventFilter(fFiltersMap[collision.globalIndex()]); auto dqDecisions = fCEFPfilters[collision.globalIndex()]; - dqtable(dqDecisions[0], dqDecisions[1], dqDecisions[2], dqDecisions[3], dqDecisions[4], dqDecisions[5], dqDecisions[6]); + dqtable(dqDecisions[0], dqDecisions[1], dqDecisions[2], dqDecisions[3], dqDecisions[4], dqDecisions[5], dqDecisions[6], dqDecisions[7]); } } @@ -991,6 +1245,7 @@ struct DQFilterPPTask { } PROCESS_SWITCH(DQFilterPPTask, processFilterPP, "Run filter task", false); + PROCESS_SWITCH(DQFilterPPTask, processFilterMuonPP, "Run filter task for muons only", false); PROCESS_SWITCH(DQFilterPPTask, processDummy, "Dummy function", false); }; @@ -1004,7 +1259,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses) +void DefineHistograms(HistogramManager* histMan, TString histClasses, TString subgroups) { // // Define here the histograms for all the classes required in analysis. @@ -1015,23 +1270,26 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses) histMan->AddHistClass(classStr.Data()); if (classStr.Contains("Event")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "event", "trigger,vtxPbPb"); + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "event", subgroups.Data()); } if (classStr.Contains("Track")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "its,tpcpid,dca"); + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", subgroups.Data()); } - if (classStr.Contains("Muon")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "muon"); + if (classStr.Contains("Muon") && !classStr.Contains("Electron")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", subgroups.Data()); } if (classStr.Contains("Pairs")) { if (classStr.Contains("Barrel")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", "vertexing-barrel"); + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", subgroups.Data()); } if (classStr.Contains("Forward")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", "dimuon,vertexing-forward"); + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", subgroups.Data()); + } + if (classStr.Contains("ElectronMuon")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", subgroups.Data()); } } } diff --git a/PWGDQ/Tasks/filterPbPb.cxx b/PWGDQ/Tasks/filterPbPb.cxx index a9671f0711e..1544ea14f21 100644 --- a/PWGDQ/Tasks/filterPbPb.cxx +++ b/PWGDQ/Tasks/filterPbPb.cxx @@ -17,6 +17,8 @@ #include "PWGDQ/DataModel/ReducedInfoTables.h" #include "PWGDQ/Core/VarManager.h" #include "CommonConstants/LHCConstants.h" +#include "ReconstructionDataFormats/Vertex.h" +#include "PWGUD/Core/SGSelector.h" using namespace std; @@ -29,11 +31,10 @@ using MyEvents = soa::Join; using MyBCs = soa::Join; struct DQFilterPbPbTask { + Produces eventRapidityGapFilter; Produces eventFilter; - OutputObj fStats{"Statistics"}; - OutputObj fFilterOutcome{"Filter outcome"}; + OutputObj fFilterOutcome{"Filter outcome"}; - Configurable fConfigEventTypes{"cfgEventTypes", "doublegap,singlegap", "Which event types to select. doublegap, singlegap or both, comma separated"}; Configurable fConfigNDtColl{"cfgNDtColl", 4, "Number of standard deviations to consider in BC range"}; Configurable fConfigMinNBCs{"cfgMinNBCs", 7, "Minimum number of BCs to consider in BC range"}; Configurable fConfigMinNPVCs{"cfgMinNPVCs", 2, "Minimum number of PV contributors"}; @@ -51,43 +52,51 @@ struct DQFilterPbPbTask { int eventTypeMap = 0; std::vector eventTypeOptions = {"doublegap", "singlegap"}; // Map for which types of event to select + SGSelector sgSelector; + SGCutParHolder sgCuts = SGCutParHolder(); + void init(o2::framework::InitContext&) { - // setup the Stats histogram - fStats.setObject(new TH1I("Statistics", "Stats for DQ triggers", 2, -2.5, -0.5)); - fStats->GetXaxis()->SetBinLabel(1, "Events inspected"); - fStats->GetXaxis()->SetBinLabel(2, "Events selected"); // setup the FilterOutcome histogram - fFilterOutcome.setObject(new TH1I("Filter outcome", "Filter outcome", 5, -0.5, 4.5)); + fFilterOutcome.setObject(new TH1D("Filter outcome", "Filter outcome", 8, 0.5, 8.5)); fFilterOutcome->GetXaxis()->SetBinLabel(1, "Events inspected"); - fFilterOutcome->GetXaxis()->SetBinLabel(2, "Events selected"); - fFilterOutcome->GetXaxis()->SetBinLabel(3, "Failed FIT veto"); - fFilterOutcome->GetXaxis()->SetBinLabel(4, Form("numContrib not in [%d, %d]", fConfigMinNPVCs.value, fConfigMaxNPVCs.value)); - fFilterOutcome->GetXaxis()->SetBinLabel(5, "BC not found"); + fFilterOutcome->GetXaxis()->SetBinLabel(2, "!A && !C"); + fFilterOutcome->GetXaxis()->SetBinLabel(3, "!A && C"); + fFilterOutcome->GetXaxis()->SetBinLabel(4, "A && !C"); + fFilterOutcome->GetXaxis()->SetBinLabel(5, "A && C"); + fFilterOutcome->GetXaxis()->SetBinLabel(6, Form("numContrib not in [%d, %d]", fConfigMinNPVCs.value, fConfigMaxNPVCs.value)); + fFilterOutcome->GetXaxis()->SetBinLabel(7, "BC not found"); + fFilterOutcome->GetXaxis()->SetBinLabel(8, "ITS UPC settings used"); - TString eventTypesString = fConfigEventTypes.value; - for (std::vector::size_type i = 0; i < eventTypeOptions.size(); i++) { - if (eventTypesString.Contains(eventTypeOptions[i])) { - eventTypeMap |= (uint32_t(1) << i); - LOGF(info, "filterPbPb will select '%s' events", eventTypeOptions[i]); - } - } - if (eventTypeMap == 0) { - LOGF(fatal, "No valid choice of event types to select. Use 'doublegap', 'singlegap' or both"); - } + sgCuts.SetNDtcoll(fConfigNDtColl); + sgCuts.SetMinNBCs(fConfigMinNBCs); + sgCuts.SetNTracks(fConfigMinNPVCs, fConfigMaxNPVCs); + sgCuts.SetMaxFITtime(fConfigMaxFITTime); + sgCuts.SetFITAmpLimits({static_cast((fConfigUseFV0) ? fConfigFV0AmpLimit : -1.), + static_cast((fConfigUseFT0) ? fConfigFT0AAmpLimit : -1.), + static_cast((fConfigUseFT0) ? fConfigFT0CAmpLimit : -1.), + static_cast((fConfigUseFDD) ? fConfigFDDAAmpLimit : -1.), + static_cast((fConfigUseFDD) ? fConfigFDDCAmpLimit : -1.)}); } // Helper function for selecting double gap and single gap events template uint64_t rapidityGapFilter(TEvent const& collision, TBCs const& bcs, aod::FT0s& ft0s, aod::FV0As& fv0as, aod::FDDs& fdds, - int eventTypes, std::vector FITAmpLimits, int nDtColl, int minNBCs, int minNPVCs, int maxNPVCs, float maxFITTime, + std::vector FITAmpLimits, int nDtColl, int minNBCs, int minNPVCs, int maxNPVCs, float maxFITTime, bool useFV0, bool useFT0, bool useFDD) { - fFilterOutcome->Fill(0., 1.); + fFilterOutcome->Fill(1., 1.); + + // Number of primary vertex contributors + if (collision.numContrib() < minNPVCs || collision.numContrib() > maxNPVCs) { + fFilterOutcome->Fill(6, 1); + return 0; + } + // Find BC associated with collision if (!collision.has_foundBC()) { - fFilterOutcome->Fill(4., 1); + fFilterOutcome->Fill(7., 1); return 0; } // foundBCId is stored in EvSels @@ -212,31 +221,24 @@ struct DQFilterPbPbTask { // Compute FIT decision uint64_t FITDecision = 0; - if (eventTypes & (uint32_t(1) << 0)) { - if (isSideAClean && isSideCClean) { - FITDecision |= (uint64_t(1) << VarManager::kDoubleGap); - } - } - if (eventTypes & (uint32_t(1) << 1)) { - if (isSideAClean && !isSideCClean) { - FITDecision |= (uint64_t(1) << VarManager::kSingleGapA); - } else if (!isSideAClean && isSideCClean) { - FITDecision |= (uint64_t(1) << VarManager::kSingleGapC); - } - } - if (!FITDecision) { + if (isSideAClean && isSideCClean) { fFilterOutcome->Fill(2, 1); - return 0; + FITDecision |= (uint64_t(1) << VarManager::kDoubleGap); } - - // Number of primary vertex contributors - if (collision.numContrib() < minNPVCs || collision.numContrib() > maxNPVCs) { + if (isSideAClean && !isSideCClean) { fFilterOutcome->Fill(3, 1); + FITDecision |= (uint64_t(1) << VarManager::kSingleGapA); + } else if (!isSideAClean && isSideCClean) { + fFilterOutcome->Fill(4, 1); + FITDecision |= (uint64_t(1) << VarManager::kSingleGapC); + } else if (!isSideAClean && !isSideCClean) { + fFilterOutcome->Fill(5, 1); + } + + if (!FITDecision) { return 0; } - // If we made it here, the event passed - fFilterOutcome->Fill(1, 1); // Return filter bitmap corresponding to FIT decision return FITDecision; } @@ -244,17 +246,75 @@ struct DQFilterPbPbTask { void processFilterPbPb(MyEvents::iterator const& collision, MyBCs const& bcs, aod::FT0s& ft0s, aod::FV0As& fv0as, aod::FDDs& fdds) { - fStats->Fill(-2.0); - std::vector FITAmpLimits = {fConfigFV0AmpLimit, fConfigFT0AAmpLimit, fConfigFT0CAmpLimit, fConfigFDDAAmpLimit, fConfigFDDCAmpLimit}; uint64_t filter = rapidityGapFilter(collision, bcs, ft0s, fv0as, fdds, - eventTypeMap, FITAmpLimits, fConfigNDtColl, fConfigMinNBCs, fConfigMinNPVCs, fConfigMaxNPVCs, fConfigMaxFITTime, + FITAmpLimits, fConfigNDtColl, fConfigMinNBCs, fConfigMinNPVCs, fConfigMaxNPVCs, fConfigMaxFITTime, fConfigUseFV0, fConfigUseFT0, fConfigUseFDD); - bool isSelected = filter; - fStats->Fill(-1.0, isSelected); + // Record whether UPC settings were used for this event + if (collision.flags() & dataformats::Vertex>::Flags::UPCMode) { + filter |= (uint64_t(1) << VarManager::kITSUPCMode); + fFilterOutcome->Fill(8, 1); + } + + eventRapidityGapFilter(filter, -9999.0, -9999.0, -9999.0, -9999.0, -9999.0, -9999.0, -9999.0, -9999.0, -9999.0, -9999.0, -9999.0, -9999.0, -9999.0); + eventFilter(filter); + } + + void processUDSGSelector(MyEvents::iterator const& collision, MyBCs const& bcs, + aod::FT0s& ft0s, aod::FV0As& fv0as, aod::FDDs& fdds, aod::Zdcs& /*zdcs*/) + { + uint64_t filter = 0; + fFilterOutcome->Fill(1, 1.); + if (!collision.has_foundBC()) { + fFilterOutcome->Fill(7, 1); + return; + } + + auto bc = collision.foundBC_as(); + auto newbc = bc; + auto bcRange = udhelpers::compatibleBCs(collision, fConfigNDtColl, bcs, fConfigMinNBCs); + auto isSGEvent = sgSelector.IsSelected(sgCuts, collision, bcRange, bc); + int issgevent = isSGEvent.value; + // Translate SGSelector values to DQEventFilter values + if (issgevent == 0) { + filter |= (uint64_t(1) << VarManager::kSingleGapA); + fFilterOutcome->Fill(3, 1); + } else if (issgevent == 1) { + filter |= (uint64_t(1) << VarManager::kSingleGapC); + fFilterOutcome->Fill(4, 1); + } else if (issgevent == 2) { + filter |= (uint64_t(1) << VarManager::kDoubleGap); + fFilterOutcome->Fill(2, 1); + } else if (issgevent == 3) { + fFilterOutcome->Fill(5, 1); + } else if (issgevent == 4) { + fFilterOutcome->Fill(6, 1); + } + + // Get closest bc with FIT activity above threshold + if (isSGEvent.bc && issgevent < 2) { + newbc = *(isSGEvent.bc); + } + upchelpers::FITInfo fitInfo{}; + udhelpers::getFITinfo(fitInfo, newbc, bcs, ft0s, fv0as, fdds); + // Record whether UPC settings were used for this event + if (collision.flags() & dataformats::Vertex>::Flags::UPCMode) { + filter |= (uint64_t(1) << VarManager::kITSUPCMode); + fFilterOutcome->Fill(8, 1); + } + + if (newbc.has_zdc()) { + auto zdc = newbc.zdc(); + eventRapidityGapFilter(filter, fitInfo.ampFT0A, fitInfo.ampFT0C, fitInfo.ampFDDA, fitInfo.ampFDDC, fitInfo.ampFV0A, + zdc.energyCommonZNA(), zdc.energyCommonZNC(), zdc.energyCommonZPA(), zdc.energyCommonZPC(), + zdc.timeZNA(), zdc.timeZNC(), zdc.timeZPA(), zdc.timeZPC()); + } else { + eventRapidityGapFilter(filter, fitInfo.ampFT0A, fitInfo.ampFT0C, fitInfo.ampFDDA, fitInfo.ampFDDC, fitInfo.ampFV0A, + -9999.0, -9999.0, -9999.0, -9999.0, -9999.0, -9999.0, -9999.0, -9999.0); + } eventFilter(filter); } @@ -264,6 +324,7 @@ struct DQFilterPbPbTask { } PROCESS_SWITCH(DQFilterPbPbTask, processFilterPbPb, "Run filter task", true); + PROCESS_SWITCH(DQFilterPbPbTask, processUDSGSelector, "Run filter task with SG selector from UD", false); PROCESS_SWITCH(DQFilterPbPbTask, processDummy, "Dummy function", false); }; diff --git a/PWGDQ/Tasks/mchAlignRecord.cxx b/PWGDQ/Tasks/mchAlignRecord.cxx index 633b4b39709..2f612493b6e 100644 --- a/PWGDQ/Tasks/mchAlignRecord.cxx +++ b/PWGDQ/Tasks/mchAlignRecord.cxx @@ -20,6 +20,7 @@ #include #include #include +#include #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -111,6 +112,25 @@ struct mchAlignRecordTask { Configurable fDoNewGeo{"do-realign", false, "Transform to a given new geometry"}; Configurable fDoEvaluation{"do-evaluation", false, "Enable storage of residuals"}; Configurable fConfigNewGeoFile{"new-geo", "o2sim_geometry-aligned.root", "New geometry for transformation"}; + Configurable fAllowedVarX{"variation-x", 2.0, "Allowed variation for x axis in cm"}; + Configurable fAllowedVarY{"variation-y", 0.3, "Allowed variation for y axis in cm"}; + Configurable fAllowedVarPhi{"variation-phi", 0.002, "Allowed variation for phi axis in rad"}; + Configurable fAllowedVarZ{"variation-z", 2.0, "Allowed variation for z axis in cm"}; + Configurable cfgSigmaX{"cfgSigmaX", 1000., "Sigma cut along X"}; + Configurable cfgSigmaY{"cfgSigmaY", 1000., "Sigma cut along Y"}; + Configurable cfgChamberResolutionX{"cfgChamberResolutionX", 0.4, "Chamber resolution along X configuration for refit"}; // 0.4cm pp, 0.2cm PbPb + Configurable cfgChamberResolutionY{"cfgChamberResolutionY", 0.4, "Chamber resolution along Y configuration for refit"}; // 0.4cm pp, 0.2cm PbPb + Configurable cfgSigmaCutImprove{"cfgSigmaCutImprove", 6., "Sigma cut for track improvement"}; + struct : ConfigurableGroup { + Configurable> cfgDetElem{"cfgDetElem", + {}, + "List of DetElem to be fixed"}; + Configurable> cfgParMask{"cfgParMask", + {}, + "List of param mask for d.o.f to be fixed"}; + } fFixDetElem; + + Preslice perMuon = aod::fwdtrkcl::fwdtrackId; void init(InitContext& ic) { @@ -122,27 +142,41 @@ struct mchAlignRecordTask { // Configuration for alignment object mAlign.SetDoEvaluation(fDoEvaluation.value); - mAlign.SetAllowedVariation(0, 2.0); - mAlign.SetAllowedVariation(1, 0.3); - mAlign.SetAllowedVariation(2, 0.002); - mAlign.SetAllowedVariation(3, 2.0); + mAlign.SetAllowedVariation(0, fAllowedVarX.value); + mAlign.SetAllowedVariation(1, fAllowedVarY.value); + mAlign.SetAllowedVariation(2, fAllowedVarPhi.value); + mAlign.SetAllowedVariation(3, fAllowedVarZ.value); + mAlign.SetSigmaXY(cfgSigmaX.value, cfgSigmaY.value); // Configuration for track fitter const auto& trackerParam = o2::mch::TrackerParam::Instance(); trackFitter.setBendingVertexDispersion(trackerParam.bendingVertexDispersion); - trackFitter.setChamberResolution(trackerParam.chamberResolutionX, trackerParam.chamberResolutionY); + trackFitter.setChamberResolution(cfgChamberResolutionX.value, cfgChamberResolutionY.value); trackFitter.smoothTracks(true); trackFitter.useChamberResolution(); - mImproveCutChi2 = 2. * trackerParam.sigmaCutForImprovement * trackerParam.sigmaCutForImprovement; + mImproveCutChi2 = 2. * cfgSigmaCutImprove.value * cfgSigmaCutImprove.value; // Configuration for chamber fixing - auto chambers = fFixChamber.value; - for (int i = 0; i < chambers.length(); ++i) { - if (chambers[i] == ',') - continue; - int chamber = chambers[i] - '0'; - LOG(info) << Form("%s%d", "Fixing chamber: ", chamber); - mAlign.FixChamber(chamber); + TString chambersString = fFixChamber.value; + std::unique_ptr objArray(chambersString.Tokenize(",")); + if (objArray->GetEntries() > 0) { + for (int iVar = 0; iVar < objArray->GetEntries(); ++iVar) { + LOG(info) << Form("%s%d", "Fixing chamber: ", std::stoi(objArray->At(iVar)->GetName())); + mAlign.FixChamber(std::stoi(objArray->At(iVar)->GetName())); + } + } + + // Configuration for DE fixing with given axes + auto DEs = fFixDetElem.cfgDetElem.value; + auto Masks = fFixDetElem.cfgParMask.value; + if (DEs.size() > 0) { + if (DEs.size() != Masks.size()) { + LOG(fatal) << "Inconsistent size of mask list."; + } + for (int i = 0; i < static_cast(DEs.size()); i++) { + LOG(info) << Form("%s%d%s%d", "Fixing DE: ", DEs.at(i), " with mask: ", Masks.at(i)); + mAlign.FixDetElem(DEs.at(i), Masks.at(i)); + } } // Init for output saving @@ -304,13 +338,9 @@ struct mchAlignRecordTask { continue; } + auto clustersSliced = clusters.sliceBy(perMuon, track.globalIndex()); // Slice clusters by muon id // Loop over attached clusters - for (auto const& cluster : clusters) { - - if (cluster.template fwdtrack_as() != track) { - continue; - } - + for (auto const& cluster : clustersSliced) { clIndex += 1; mch::Cluster* mch_cluster = new mch::Cluster(); diff --git a/PWGDQ/Tasks/muonDCA.cxx b/PWGDQ/Tasks/muonDCA.cxx new file mode 100644 index 00000000000..b2031418d5c --- /dev/null +++ b/PWGDQ/Tasks/muonDCA.cxx @@ -0,0 +1,196 @@ +// 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 muonDCA.cxx +/// \brief Task to compute and evaluate DCA quantities +/// \author Nicolas Bizé , SUBATECH +// +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "GlobalTracking/MatchGlobalFwd.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGDQ/Core/VarManager.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::aod; + +using MyMuons = soa::Join; +using MyEvents = soa::Join; +using MyEventsVtxCov = soa::Join; + +// constexpr static uint32_t gkMuonDCAFillMapWithCov = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra | VarManager::ObjTypes::ReducedMuonCov | VarManager::ObjTypes::MuonDCA; + +constexpr static int toVertex = VarManager::kToVertex; +constexpr static int toDCA = VarManager::kToDCA; +constexpr static int toRabs = VarManager::kToRabs; + +static o2::globaltracking::MatchGlobalFwd mExtrap; +template +bool isSelected(const T& muon); + +struct muonExtrap { + Produces dcaTable; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + Service fCCDB; + o2::parameters::GRPMagField* grpmag = nullptr; // for run 3, we access GRPMagField from GLO/Config/GRPMagField + int fCurrentRun; // needed to detect if the run changed and trigger update of magnetic field + + HistogramRegistry registry{ + "registry", + {}}; + + void init(o2::framework::InitContext&) + { + // Load geometry + fCCDB->setURL(fConfigCcdbUrl); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + + if (!o2::base::GeometryManager::isGeometryLoaded()) { + LOGF(info, "Load geometry from CCDB"); + fCCDB->get(geoPath); + } + + AxisSpec pdcaAxis = {5000, 0.0, 5000.0, "p #times DCA"}; + AxisSpec dcaAxis = {200, 0.0, 200.0, "DCA"}; + AxisSpec dcaxAxis = {200, -100.0, 100.0, "DCA_x"}; + AxisSpec dcayAxis = {200, -100.0, 100.0, "DCA_y"}; + AxisSpec rabsAxis = {100, 0., 100.0, "R_{abs}"}; + AxisSpec xAxis = {200, -100., 100.0, "x (cm)"}; + AxisSpec yAxis = {200, -100., 100.0, "y (cm)"}; + AxisSpec zAxis = {200, -100., 100.0, "z (cm)"}; + + HistogramConfigSpec pdcaSpec({HistType::kTH1F, {pdcaAxis}}); + HistogramConfigSpec dcaSpec({HistType::kTH1F, {dcaAxis}}); + HistogramConfigSpec dcaxSpec({HistType::kTH1F, {dcaxAxis}}); + HistogramConfigSpec dcaySpec({HistType::kTH1F, {dcayAxis}}); + HistogramConfigSpec rabsSpec({HistType::kTH1F, {rabsAxis}}); + HistogramConfigSpec xSpec({HistType::kTH1F, {xAxis}}); + HistogramConfigSpec ySpec({HistType::kTH1F, {yAxis}}); + HistogramConfigSpec zSpec({HistType::kTH1F, {zAxis}}); + + registry.add("pdca", "pDCA", pdcaSpec); + registry.add("dca", "DCA", dcaSpec); + registry.add("dcax", "DCA_x", dcaxSpec); + registry.add("dcay", "DCA_y", dcaySpec); + registry.add("rabs", "R_{abs}", rabsSpec); + registry.add("xAtVtx", "x at vertex", xSpec); + registry.add("xAtDCA", "x at DCA", xSpec); + registry.add("xAtRabs", "x at end abs", xSpec); + registry.add("yAtVtx", "y at vertex", ySpec); + registry.add("yAtDCA", "y at DCA", ySpec); + registry.add("yAtRabs", "y at end abs", ySpec); + registry.add("zAtVtx", "z at vertex", zSpec); + registry.add("zAtDCA", "z at DCA", zSpec); + registry.add("zAtRabs", "z at end abs", zSpec); + } + + void processExtrapolation(MyEventsVtxCov::iterator const& collision, MyMuons const& muons) + { + if (fCurrentRun != collision.runNumber()) { + grpmag = fCCDB->getForTimeStamp(grpmagPath, collision.timestamp()); + if (grpmag != nullptr) { + LOGF(info, "Init field from GRP"); + o2::base::Propagator::initFieldFromGRP(grpmag); + } + LOGF(info, "Set field for muons"); + VarManager::SetupMuonMagField(); + fCurrentRun = collision.runNumber(); + } + + for (auto& muon : muons) { + if (static_cast(muon.trackType()) < 2) { + continue; // Make sure to remove global muon tracks + } + // propagate muon track to vertex + o2::dataformats::GlobalFwdTrack muonTrackAtVertex = VarManager::PropagateMuon(muon, collision, toVertex); + + // propagate muon track to DCA + o2::dataformats::GlobalFwdTrack muonTrackAtDCA = VarManager::PropagateMuon(muon, collision, toDCA); + + // propagate to Rabs + o2::dataformats::GlobalFwdTrack muonTrackAtRabs = VarManager::PropagateMuon(muon, collision, toRabs); + + // Calculate DCA quantities (preferable to do it with VarManager) + double dcax = muonTrackAtDCA.getX() - collision.posX(); + double dcay = muonTrackAtDCA.getY() - collision.posY(); + double dca = std::sqrt(dcax * dcax + dcay * dcay); + double pdca = muonTrackAtVertex.getP() * dca; + double xAtVtx = muonTrackAtVertex.getX(); + double yAtVtx = muonTrackAtVertex.getY(); + double zAtVtx = muonTrackAtVertex.getZ(); + double xAtDCA = muonTrackAtDCA.getX(); + double yAtDCA = muonTrackAtDCA.getY(); + double zAtDCA = muonTrackAtDCA.getZ(); + double xAbs = muonTrackAtRabs.getX(); + double yAbs = muonTrackAtRabs.getY(); + double zAbs = muonTrackAtRabs.getZ(); + + double rabs = std::sqrt(xAbs * xAbs + yAbs * yAbs); + + // QA histograms + registry.get(HIST("pdca"))->Fill(pdca); + registry.get(HIST("dca"))->Fill(dca); + registry.get(HIST("dcax"))->Fill(dcax); + registry.get(HIST("dcay"))->Fill(dcay); + registry.get(HIST("rabs"))->Fill(rabs); + + registry.get(HIST("xAtDCA"))->Fill(xAtDCA); + registry.get(HIST("xAtRabs"))->Fill(xAbs); + registry.get(HIST("xAtVtx"))->Fill(xAtVtx); + + registry.get(HIST("yAtDCA"))->Fill(yAtDCA); + registry.get(HIST("yAtRabs"))->Fill(yAbs); + registry.get(HIST("yAtVtx"))->Fill(yAtVtx); + + registry.get(HIST("zAtDCA"))->Fill(zAtDCA); + registry.get(HIST("zAtRabs"))->Fill(zAbs); + registry.get(HIST("zAtVtx"))->Fill(zAtVtx); + + // Fill DCA table + dcaTable(pdca, + dca, + dcax, + dcay, + rabs, + muonTrackAtVertex.getPt(), + muonTrackAtVertex.getEta(), + muonTrackAtVertex.getPhi(), + muon.sign(), + muon.isAmbiguous(), + muonTrackAtVertex.getPx(), + muonTrackAtVertex.getPy(), + muonTrackAtVertex.getPz()); + } + } + + PROCESS_SWITCH(muonExtrap, processExtrapolation, "process extrapolation", false); + + void processDummy(MyEventsVtxCov&) + { + // do nothing + } + + PROCESS_SWITCH(muonExtrap, processDummy, "do nothing", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +}; diff --git a/PWGDQ/Tasks/quarkoniaToHyperons.cxx b/PWGDQ/Tasks/quarkoniaToHyperons.cxx new file mode 100644 index 00000000000..6133ee4e090 --- /dev/null +++ b/PWGDQ/Tasks/quarkoniaToHyperons.cxx @@ -0,0 +1,2262 @@ +// 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 quarkoniaToHyperons.cxx +/// \brief quarkonia --> hyperon antihyperon analysis task +/// +/// \author David Dobrigkeit Chinellato , Austrian Academy of Sciences & SMI +/// \author Romain Schotter , Austrian Academy of Sciences & SMI +// +// V0 analysis task +// ================ +// +// This code loops over a V0Cores table and produces some +// standard analysis output. It is meant to be run over +// derived data. +// +// +// Comments, questions, complaints, suggestions? +// Please write to: +// romain.schotter@cern.ch +// david.dobrigkeit.chinellato@cern.ch +// + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "ReconstructionDataFormats/Track.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessMLTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGUD/Core/SGSelector.h" +#include "Tools/ML/MlResponse.h" +#include "Tools/ML/model.h" + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" + +// constants +const float ctauXiPDG = 4.91; // Xi PDG lifetime +const float ctauOmegaPDG = 2.461; // Omega PDG lifetime + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +using DauTracks = soa::Join; +using DauMCTracks = soa::Join; +using V0Candidates = soa::Join; +// using V0MCCandidates = soa::Join; +using V0MCCandidates = soa::Join; + +using CascadeCandidates = soa::Join; +using CascadeMCCandidates = soa::Join; + +// simple checkers, but ensure 64 bit integers +#define BITSET(var, nbit) ((var) |= (static_cast(1) << static_cast(nbit))) +#define BITCHECK(var, nbit) ((var) & (static_cast(1) << static_cast(nbit))) + +struct QuarkoniaToHyperons { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // master analysis switches + Configurable isPP{"isPP", true, "If running on pp collision, switch it on true"}; + + // for running over skimmed dataset + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "If running over skimmed data, switch it on true"}; + Configurable cfgSkimmedTrigger{"cfgSkimmedTrigger", "fDoubleXi,fTripleXi,fQuadrupleXi", "(std::string) Comma separated list of triggers of interest"}; + + // switch on/off event selections + Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; + Configurable requireTriggerTVX{"requireTriggerTVX", true, "require FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level"}; + Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border"}; + Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "require events with at least one ITS-TPC track"}; + Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "require events with PV position along z consistent (within 1 cm) between PV reconstructed using tracks and PV using FT0 A-C time difference"}; + Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", false, "require events with at least one of vertex contributors matched to TOF"}; + Configurable requireIsVertexTRDmatched{"requireIsVertexTRDmatched", false, "require events with at least one of vertex contributors matched to TRD"}; + Configurable rejectSameBunchPileup{"rejectSameBunchPileup", true, "reject collisions in case of pileup with another collision in the same foundBC"}; + Configurable requireNoCollInTimeRangeStd{"requireNoCollInTimeRangeStd", true, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds"}; + Configurable requireNoCollInTimeRangeNarrow{"requireNoCollInTimeRangeNarrow", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds"}; + + Configurable buildK0sK0sPairs{"buildK0sK0sPairs", false, "Build K0s K0s from charmonia decay"}; + Configurable buildLaLaBarPairs{"buildLaLaBarPairs", false, "Build Lambda antiLambda from charmonia decay"}; + Configurable buildXiXiBarPairs{"buildXiXiBarPairs", false, "Build Xi antiXi from charmonia decay"}; + Configurable buildOmOmBarPairs{"buildOmOmBarPairs", false, "Build Omega antiOmega from charmonia decay"}; + + Configurable buildSameSignPairs{"buildSameSignPairs", false, "If true: build same-sign pairs, otherwise consider only opposite-sign pairs"}; + + // fast check on occupancy + Configurable minOccupancy{"minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; + Configurable maxOccupancy{"maxOccupancy", -1, "maximum occupancy from neighbouring collisions"}; + + // rapidity cut on the hyperon-antiHyperon pair + Configurable rapidityCut{"rapidityCut", 0.5, "rapidity cut on the hyp-antiHyp pair"}; + + struct : ConfigurableGroup { + Configurable v0TypeSelection{"v0Selections.v0TypeSelection", 1, "select on a certain V0 type (leave negative if no selection desired)"}; + + // Selection criteria: acceptance + Configurable rapidityCut{"v0Selections.rapidityCut", 0.5, "rapidity"}; + Configurable daughterEtaCut{"v0Selections.daughterEtaCut", 0.8, "max eta for daughters"}; + + // Standard 6 topological criteria + Configurable v0cospa{"v0Selections.v0cospa", 0.97, "min V0 CosPA"}; + Configurable dcav0dau{"v0Selections.dcav0dau", 1.0, "max DCA V0 Daughters (cm)"}; + Configurable dcav0topv{"v0Selections.dcav0topv", .05, "min DCA V0 to PV (cm)"}; + Configurable dcapiontopv{"v0Selections.dcapiontopv", .05, "min DCA Pion To PV (cm)"}; + Configurable dcaprotontopv{"v0Selections.dcaprotontopv", .05, "min DCA Proton To PV (cm)"}; + Configurable v0radius{"v0Selections.v0radius", 1.2, "minimum V0 radius (cm)"}; + Configurable v0radiusMax{"v0Selections.v0radiusMax", 1E5, "maximum V0 radius (cm)"}; + + // invariant mass selection + Configurable v0MassWindow{"v0Selections.v0MassWindow", 0.008, "#Lambda mass (GeV/#it{c}^{2})"}; + Configurable compMassRejection{"v0Selections.compMassRejection", 0.008, "Competing mass rejection (GeV/#it{c}^{2})"}; + + // Additional selection on the AP plot (exclusive for K0Short) + // original equation: lArmPt*5>TMath::Abs(lArmAlpha) + Configurable armPodCut{"v0Selections.armPodCut", 5.0f, "pT * (cut) > |alpha|, AP cut. Negative: no cut"}; + + // Track quality + Configurable minTPCrows{"v0Selections.minTPCrows", 70, "minimum TPC crossed rows"}; + Configurable minITSclusters{"v0Selections.minITSclusters", -1, "minimum ITS clusters"}; + Configurable skipTPConly{"v0Selections.skipTPConly", false, "skip V0s comprised of at least one TPC only prong"}; + Configurable requirePosITSonly{"v0Selections.requirePosITSonly", false, "require that positive track is ITSonly (overrides TPC quality)"}; + Configurable requireNegITSonly{"v0Selections.requireNegITSonly", false, "require that negative track is ITSonly (overrides TPC quality)"}; + + // PID (TPC/TOF) + Configurable tpcPidNsigmaCut{"v0Selections.tpcPidNsigmaCut", 5, "tpcPidNsigmaCut"}; + Configurable tofPidNsigmaCutLaPr{"v0Selections.tofPidNsigmaCutLaPr", 1e+6, "tofPidNsigmaCutLaPr"}; + Configurable tofPidNsigmaCutLaPi{"v0Selections.tofPidNsigmaCutLaPi", 1e+6, "tofPidNsigmaCutLaPi"}; + Configurable tofPidNsigmaCutK0Pi{"v0Selections.tofPidNsigmaCutK0Pi", 1e+6, "tofPidNsigmaCutK0Pi"}; + + // PID (TOF) + Configurable maxDeltaTimeProton{"v0Selections.maxDeltaTimeProton", 1e+9, "check maximum allowed time"}; + Configurable maxDeltaTimePion{"v0Selections.maxDeltaTimePion", 1e+9, "check maximum allowed time"}; + } v0Selections; + + struct : ConfigurableGroup { + // Selection criteria: acceptance + Configurable rapidityCut{"cascSelections.rapidityCut", 0.5, "rapidity"}; + Configurable daughterEtaCut{"cascSelections.daughterEtaCut", 0.8, "max eta for daughters"}; + + // Standard 6 topological criteria on V0 + Configurable v0cospa{"cascSelections.v0cospa", 0.97, "min V0 CosPA"}; + Configurable dcav0dau{"cascSelections.dcav0dau", 1.0, "max DCA V0 Daughters (cm)"}; + Configurable dcav0topv{"cascSelections.dcav0topv", .05, "min DCA V0 to PV (cm)"}; + Configurable dcapiontopv{"cascSelections.dcapiontopv", .05, "min DCA Pion To PV (cm)"}; + Configurable dcaprotontopv{"cascSelections.dcaprotontopv", .05, "min DCA Proton To PV (cm)"}; + Configurable v0radius{"cascSelections.v0radius", 1.2, "minimum V0 radius (cm)"}; + Configurable v0radiusMax{"cascSelections.v0radiusMax", 1E5, "maximum V0 radius (cm)"}; + + // Standard 6 topological criteria on cascades + Configurable casccospa{"cascSelections.casccospa", 0.97, "min Cascade CosPA"}; + Configurable dcacascdau{"cascSelections.dcacascdau", 1.0, "max DCA Cascade Daughters (cm)"}; + Configurable dcaxybachbaryontopv{"cascSelections.dcaxybachbaryontopv", -1, "DCAxy Bachelor-Baryon to PV (cm)"}; + Configurable bachbaryoncospa{"cascSelections.bachbaryoncospa", -1, "Bachelor-Baryon CosPA"}; + Configurable dcabachtopv{"cascSelections.dcabachtopv", .05, "min DCA Bachelor To PV (cm)"}; + Configurable cascradius{"cascSelections.cascradius", 0.5, "minimum Cascade radius (cm)"}; + Configurable cascradiusMax{"cascSelections.cascradiusMax", 1E5, "maximum Cascade radius (cm)"}; + Configurable cascProperLifeTime{"cascSelections.cascProperLifeTime", 3, "maximum lifetime (ctau)"}; + + // invariant mass selection + Configurable v0MassWindow{"cascSelections.v0MassWindow", 0.008, "#Lambda mass (GeV/#it{c}^{2})"}; + Configurable cascMassWindow{"cascSelections.cascMassWindow", 0.008, "#Lambda mass (GeV/#it{c}^{2})"}; + Configurable compMassRejection{"cascSelections.compMassRejection", 0.008, "Competing mass rejection (GeV/#it{c}^{2})"}; + + // Track quality + Configurable minTPCrows{"cascSelections.minTPCrows", 70, "minimum TPC crossed rows"}; + Configurable minITSclusters{"cascSelections.minITSclusters", -1, "minimum ITS clusters"}; + Configurable skipTPConly{"cascSelections.skipTPConly", false, "skip V0s comprised of at least one TPC only prong"}; + Configurable requireBachITSonly{"cascSelections.requireBachITSonly", false, "require that bachelor track is ITSonly (overrides TPC quality)"}; + Configurable requirePosITSonly{"cascSelections.requirePosITSonly", false, "require that positive track is ITSonly (overrides TPC quality)"}; + Configurable requireNegITSonly{"cascSelections.requireNegITSonly", false, "require that negative track is ITSonly (overrides TPC quality)"}; + + // PID (TPC/TOF) + Configurable tpcPidNsigmaCut{"cascSelections.tpcPidNsigmaCut", 5, "tpcPidNsigmaCut"}; + Configurable tofPidNsigmaCutLaPr{"cascSelections.tofPidNsigmaCutLaPr", 1e+6, "tofPidNsigmaCutLaPr"}; + Configurable tofPidNsigmaCutLaPi{"cascSelections.tofPidNsigmaCutLaPi", 1e+6, "tofPidNsigmaCutLaPi"}; + Configurable tofPidNsigmaCutXiPi{"cascSelections.tofPidNsigmaCutXiPi", 1e+6, "tofPidNsigmaCutXiPi"}; + Configurable tofPidNsigmaCutOmKa{"cascSelections.tofPidNsigmaCutOmKa", 1e+6, "tofPidNsigmaCutOmKa"}; + + // PID (TOF) + Configurable maxDeltaTimeProton{"cascSelections.maxDeltaTimeProton", 1e+9, "check maximum allowed time"}; + Configurable maxDeltaTimePion{"cascSelections.maxDeltaTimePion", 1e+9, "check maximum allowed time"}; + Configurable maxDeltaTimeKaon{"cascSelections.maxDeltaTimeKaon", 1e+9, "check maximum allowed time"}; + } cascSelections; + + Configurable qaCentrality{"qaCentrality", false, "qa centrality flag: check base raw values"}; + + // for MC + Configurable doMCAssociation{"doMCAssociation", true, "if MC, do MC association"}; + + // UPC selections + SGSelector sgSelector; + struct : ConfigurableGroup { + Configurable fv0Cut{"upcCuts.fv0Cut", 100., "FV0A threshold"}; + Configurable ft0aCut{"upcCuts.ft0aCut", 200., "FT0A threshold"}; + Configurable ft0cCut{"upcCuts.ft0cCut", 100., "FT0C threshold"}; + Configurable zdcCut{"upcCuts.zdcCut", 10., "ZDC threshold"}; + // Configurable gapSel{"upcCuts.gapSel", 2, "Gap selection"}; + } upcCuts; + + // Machine learning evaluation for pre-selection and corresponding information generation + o2::ml::OnnxModel mlCustomModelK0Short; + o2::ml::OnnxModel mlCustomModelLambda; + o2::ml::OnnxModel mlCustomModelAntiLambda; + o2::ml::OnnxModel mlCustomModelGamma; + + struct : ConfigurableGroup { + // ML classifiers: master flags to control whether we should use custom ML classifiers or the scores in the derived data + Configurable useK0ShortScores{"mlConfigurations.useK0ShortScores", false, "use ML scores to select K0Short"}; + Configurable useLambdaScores{"mlConfigurations.useLambdaScores", false, "use ML scores to select Lambda"}; + Configurable useAntiLambdaScores{"mlConfigurations.useAntiLambdaScores", false, "use ML scores to select AntiLambda"}; + + Configurable calculateK0ShortScores{"mlConfigurations.calculateK0ShortScores", false, "calculate K0Short ML scores"}; + Configurable calculateLambdaScores{"mlConfigurations.calculateLambdaScores", false, "calculate Lambda ML scores"}; + Configurable calculateAntiLambdaScores{"mlConfigurations.calculateAntiLambdaScores", false, "calculate AntiLambda ML scores"}; + + // ML input for ML calculation + Configurable customModelPathCCDB{"mlConfigurations.customModelPathCCDB", "", "Custom ML Model path in CCDB"}; + Configurable timestampCCDB{"mlConfigurations.timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; + Configurable loadCustomModelsFromCCDB{"mlConfigurations.loadCustomModelsFromCCDB", false, "Flag to enable or disable the loading of custom models from CCDB"}; + Configurable enableOptimizations{"mlConfigurations.enableOptimizations", false, "Enables the ONNX extended model-optimization: sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED)"}; + + // Local paths for test purposes + Configurable localModelPathLambda{"mlConfigurations.localModelPathLambda", "Lambda_BDTModel.onnx", "(std::string) Path to the local .onnx file."}; + Configurable localModelPathAntiLambda{"mlConfigurations.localModelPathAntiLambda", "AntiLambda_BDTModel.onnx", "(std::string) Path to the local .onnx file."}; + Configurable localModelPathK0Short{"mlConfigurations.localModelPathK0Short", "KZeroShort_BDTModel.onnx", "(std::string) Path to the local .onnx file."}; + + // Thresholds for choosing to populate V0Cores tables with pre-selections + Configurable thresholdLambda{"mlConfigurations.thresholdLambda", -1.0f, "Threshold to keep Lambda candidates"}; + Configurable thresholdAntiLambda{"mlConfigurations.thresholdAntiLambda", -1.0f, "Threshold to keep AntiLambda candidates"}; + Configurable thresholdK0Short{"mlConfigurations.thresholdK0Short", -1.0f, "Threshold to keep K0Short candidates"}; + } mlConfigurations; + + // CCDB options + struct : ConfigurableGroup { + Configurable ccdburl{"ccdbConfigurations.ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"ccdbConfigurations.grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"ccdbConfigurations.grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"ccdbConfigurations.lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"ccdbConfigurations.geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable mVtxPath{"ccdbConfigurations.mVtxPath", "GLO/Calib/MeanVertex", "Path of the mean vertex file"}; + } ccdbConfigurations; + + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + int mRunNumber; + std::map metadata; + + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + static constexpr float defaultLifetimeCuts[1][2] = {{30., 20.}}; + Configurable> lifetimecut{"lifetimecut", {defaultLifetimeCuts[0], 2, {"lifetimecutLambda", "lifetimecutK0S"}}, "lifetimecut"}; + + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f, 1.2f, 1.4f, 1.6f, 1.8f, 2.0f, 2.4f, 2.8f, 3.2f, 3.6f, 4.0f, 4.8f, 5.6f, 6.5f, 7.5f, 9.0f, 11.0f, 13.0f, 15.0f, 19.0f, 23.0f, 30.0f, 40.0f, 50.0f}, "pt axis for analysis"}; + ConfigurableAxis axisQuarkoniumMass{"axisQuarkoniumMass", {500, 2.600f, 4.000f}, "M (hyp. #bar{hyp.} ) (GeV/#it{c}^{2})"}; + ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f}, "Centrality"}; + ConfigurableAxis axisNch{"axisNch", {500, 0.0f, +5000.0f}, "Number of charged particles"}; + + ConfigurableAxis axisRawCentrality{"axisRawCentrality", {VARIABLE_WIDTH, 0.000f, 52.320f, 75.400f, 95.719f, 115.364f, 135.211f, 155.791f, 177.504f, 200.686f, 225.641f, 252.645f, 281.906f, 313.850f, 348.302f, 385.732f, 426.307f, 470.146f, 517.555f, 568.899f, 624.177f, 684.021f, 748.734f, 818.078f, 892.577f, 973.087f, 1058.789f, 1150.915f, 1249.319f, 1354.279f, 1465.979f, 1584.790f, 1710.778f, 1844.863f, 1985.746f, 2134.643f, 2291.610f, 2456.943f, 2630.653f, 2813.959f, 3006.631f, 3207.229f, 3417.641f, 3637.318f, 3865.785f, 4104.997f, 4354.938f, 4615.786f, 4885.335f, 5166.555f, 5458.021f, 5762.584f, 6077.881f, 6406.834f, 6746.435f, 7097.958f, 7462.579f, 7839.165f, 8231.629f, 8635.640f, 9052.000f, 9484.268f, 9929.111f, 10389.350f, 10862.059f, 11352.185f, 11856.823f, 12380.371f, 12920.401f, 13476.971f, 14053.087f, 14646.190f, 15258.426f, 15890.617f, 16544.433f, 17218.024f, 17913.465f, 18631.374f, 19374.983f, 20136.700f, 20927.783f, 21746.796f, 22590.880f, 23465.734f, 24372.274f, 25314.351f, 26290.488f, 27300.899f, 28347.512f, 29436.133f, 30567.840f, 31746.818f, 32982.664f, 34276.329f, 35624.859f, 37042.588f, 38546.609f, 40139.742f, 41837.980f, 43679.429f, 45892.130f, 400000.000f}, "raw centrality signal"}; // for QA + + ConfigurableAxis axisOccupancy{"axisOccupancy", {VARIABLE_WIDTH, 0.0f, 250.0f, 500.0f, 750.0f, 1000.0f, 1500.0f, 2000.0f, 3000.0f, 4500.0f, 6000.0f, 8000.0f, 10000.0f, 50000.0f}, "Occupancy"}; + + // topological variable QA axes + ConfigurableAxis axisDCAtoPV{"axisDCAtoPV", {20, 0.0f, 1.0f}, "DCA (cm)"}; + ConfigurableAxis axisDCAdau{"axisDCAdau", {20, 0.0f, 2.0f}, "DCA (cm)"}; + ConfigurableAxis axisDCAV0ToPV{"axisDCAV0ToPV", {20, 0.0f, 2.0f}, "DCA (cm)"}; + ConfigurableAxis axisPointingAngle{"axisPointingAngle", {20, 0.0f, 2.0f}, "pointing angle (rad)"}; + ConfigurableAxis axisRadius{"axisRadius", {20, 0.0f, 60.0f}, "Decay radius (cm)"}; + ConfigurableAxis axisProperLifeTime{"axisV0ProperLifeTime", {100, 0.0f, 50.0f}, "ProperLifeTime 2D radius (cm)"}; + ConfigurableAxis axisMassWindow{"axisMassWindow", {40, -0.020f, 0.020f}, "Inv. mass - PDG mass (GeV/#it{c}^{2})"}; + ConfigurableAxis axisK0Mass{"axisK0Mass", {500, 0.400f, 0.600f}, "K0Short mass (GeV/#it{c}^{2})"}; + ConfigurableAxis axisLambdaMass{"axisLambdaMass", {500, 1.098f, 1.198f}, "Lambda mass (GeV/#it{c}^{2})"}; + ConfigurableAxis axisXiMass{"axisXiMass", {500, 1.318f, 1.370f}, "Xi mass (GeV/#it{c}^{2})"}; + ConfigurableAxis axisOmegaMass{"axisOmegaMass", {500, 1.670f, 1.675f}, "Omega mass (GeV/#it{c}^{2})"}; + ConfigurableAxis axisNsigmaTPC{"axisNsigmaTPC", {200, -10.0f, 10.0f}, "N sigma TPC"}; + + // AP plot axes + ConfigurableAxis axisAPAlpha{"axisAPAlpha", {220, -1.1f, 1.1f}, "V0 AP alpha"}; + ConfigurableAxis axisAPQt{"axisAPQt", {220, 0.0f, 0.5f}, "V0 AP alpha"}; + + // Track quality axes + ConfigurableAxis axisTPCrows{"axisTPCrows", {160, 0.0f, 160.0f}, "N TPC rows"}; + ConfigurableAxis axisITSclus{"axisITSclus", {7, 0.0f, 7.0f}, "N ITS Clusters"}; + + // UPC axes + ConfigurableAxis axisSelGap{"axisSelGap", {4, -1.5, 2.5}, "Gap side"}; + + // PDG database + Service pdgDB; + + // For manual sliceBy + PresliceUnsorted> perMcCollision = aod::v0data::straMCCollisionId; + + enum Selection : uint64_t { selCosPA = 0, + selRadius, + selRadiusMax, + selDCANegToPV, + selDCAPosToPV, + selDCAV0ToPV, + selDCAV0Dau, + selK0ShortRapidity, + selLambdaRapidity, + selK0ShortMassWindow, + selLambdaMassWindow, + selAntiLambdaMassWindow, + selK0ShortMassRejection, + selLambdaMassRejection, + selTPCPIDPositivePion, + selTPCPIDNegativePion, + selTPCPIDPositiveProton, + selTPCPIDNegativeProton, + selTOFDeltaTPositiveProtonLambda, + selTOFDeltaTPositivePionLambda, + selTOFDeltaTPositivePionK0Short, + selTOFDeltaTNegativeProtonLambda, + selTOFDeltaTNegativePionLambda, + selTOFDeltaTNegativePionK0Short, + selTOFNSigmaPositiveProtonLambda, // Nsigma + selTOFNSigmaPositivePionLambda, // Nsigma + selTOFNSigmaPositivePionK0Short, // Nsigma + selTOFNSigmaNegativeProtonLambda, // Nsigma + selTOFNSigmaNegativePionLambda, // Nsigma + selTOFNSigmaNegativePionK0Short, // Nsigma + selK0ShortCTau, + selLambdaCTau, + selK0ShortArmenteros, + selPosGoodTPCTrack, // at least min # TPC rows + selNegGoodTPCTrack, // at least min # TPC rows + selPosGoodITSTrack, // at least min # ITS clusters + selNegGoodITSTrack, // at least min # ITS clusters + selPosItsOnly, + selNegItsOnly, + selPosNotTPCOnly, + selNegNotTPCOnly, + selConsiderK0Short, // for mc tagging + selConsiderLambda, // for mc tagging + selConsiderAntiLambda, // for mc tagging + selPhysPrimK0Short, // for mc tagging + selPhysPrimLambda, // for mc tagging + selPhysPrimAntiLambda, // for mc tagging + }; + + uint64_t maskTopological; + uint64_t maskTopoNoV0Radius; + uint64_t maskTopoNoDCANegToPV; + uint64_t maskTopoNoDCAPosToPV; + uint64_t maskTopoNoCosPA; + uint64_t maskTopoNoDCAV0Dau; + uint64_t maskTopoNoDCAV0ToPV; + uint64_t maskTrackProperties; + + uint64_t maskK0ShortSpecific; + uint64_t maskLambdaSpecific; + uint64_t maskAntiLambdaSpecific; + + uint64_t maskSelectionK0Short; + uint64_t maskSelectionLambda; + uint64_t maskSelectionAntiLambda; + + uint64_t secondaryMaskSelectionLambda; + uint64_t secondaryMaskSelectionAntiLambda; + + void init(InitContext const&) + { + // initialise bit masks + maskTopological = (static_cast(1) << selCosPA) | (static_cast(1) << selRadius) | (static_cast(1) << selDCANegToPV) | (static_cast(1) << selDCAPosToPV) | (static_cast(1) << selDCAV0ToPV) | (static_cast(1) << selDCAV0Dau) | (static_cast(1) << selRadiusMax); + maskTopoNoV0Radius = (static_cast(1) << selCosPA) | (static_cast(1) << selDCANegToPV) | (static_cast(1) << selDCAPosToPV) | (static_cast(1) << selDCAV0ToPV) | (static_cast(1) << selDCAV0Dau) | (static_cast(1) << selRadiusMax); + maskTopoNoDCANegToPV = (static_cast(1) << selCosPA) | (static_cast(1) << selRadius) | (static_cast(1) << selDCAPosToPV) | (static_cast(1) << selDCAV0ToPV) | (static_cast(1) << selDCAV0Dau) | (static_cast(1) << selRadiusMax); + maskTopoNoDCAPosToPV = (static_cast(1) << selCosPA) | (static_cast(1) << selRadius) | (static_cast(1) << selDCANegToPV) | (static_cast(1) << selDCAV0ToPV) | (static_cast(1) << selDCAV0Dau) | (static_cast(1) << selRadiusMax); + maskTopoNoCosPA = (static_cast(1) << selRadius) | (static_cast(1) << selDCANegToPV) | (static_cast(1) << selDCAPosToPV) | (static_cast(1) << selDCAV0ToPV) | (static_cast(1) << selDCAV0Dau) | (static_cast(1) << selRadiusMax); + maskTopoNoDCAV0Dau = (static_cast(1) << selCosPA) | (static_cast(1) << selRadius) | (static_cast(1) << selDCANegToPV) | (static_cast(1) << selDCAPosToPV) | (static_cast(1) << selDCAV0ToPV) | (static_cast(1) << selRadiusMax); + maskTopoNoDCAV0ToPV = (static_cast(1) << selCosPA) | (static_cast(1) << selRadius) | (static_cast(1) << selDCANegToPV) | (static_cast(1) << selDCAPosToPV) | (static_cast(1) << selDCAV0Dau) | (static_cast(1) << selRadiusMax); + + maskK0ShortSpecific = (static_cast(1) << selK0ShortRapidity) | (static_cast(1) << selK0ShortCTau) | (static_cast(1) << selK0ShortArmenteros) | (static_cast(1) << selConsiderK0Short) | (static_cast(1) << selK0ShortMassWindow) | (static_cast(1) << selLambdaMassRejection); + maskLambdaSpecific = (static_cast(1) << selLambdaRapidity) | (static_cast(1) << selLambdaCTau) | (static_cast(1) << selConsiderLambda) | (static_cast(1) << selLambdaMassWindow) | (static_cast(1) << selK0ShortMassRejection); + maskAntiLambdaSpecific = (static_cast(1) << selLambdaRapidity) | (static_cast(1) << selLambdaCTau) | (static_cast(1) << selConsiderAntiLambda) | (static_cast(1) << selAntiLambdaMassWindow) | (static_cast(1) << selK0ShortMassRejection); + + // ask for specific TPC/TOF PID selections + maskTrackProperties = 0; + if (v0Selections.requirePosITSonly) { + maskTrackProperties = maskTrackProperties | (static_cast(1) << selPosItsOnly) | (static_cast(1) << selPosGoodITSTrack); + } else { + maskTrackProperties = maskTrackProperties | (static_cast(1) << selPosGoodTPCTrack) | (static_cast(1) << selPosGoodITSTrack); + // TPC signal is available: ask for positive track PID + if (v0Selections.tpcPidNsigmaCut < 1e+5) { // safeguard for no cut + maskK0ShortSpecific = maskK0ShortSpecific | (static_cast(1) << selTPCPIDPositivePion); + maskLambdaSpecific = maskLambdaSpecific | (static_cast(1) << selTPCPIDPositiveProton); + maskAntiLambdaSpecific = maskAntiLambdaSpecific | (static_cast(1) << selTPCPIDPositivePion); + } + // TOF PID + if (v0Selections.tofPidNsigmaCutK0Pi < 1e+5) // safeguard for no cut + maskK0ShortSpecific = maskK0ShortSpecific | (static_cast(1) << selTOFNSigmaPositivePionK0Short) | (static_cast(1) << selTOFDeltaTPositivePionK0Short); + if (v0Selections.tofPidNsigmaCutLaPr < 1e+5) // safeguard for no cut + maskLambdaSpecific = maskLambdaSpecific | (static_cast(1) << selTOFNSigmaPositiveProtonLambda) | (static_cast(1) << selTOFDeltaTPositiveProtonLambda); + if (v0Selections.tofPidNsigmaCutLaPi < 1e+5) // safeguard for no cut + maskAntiLambdaSpecific = maskAntiLambdaSpecific | (static_cast(1) << selTOFNSigmaPositivePionLambda) | (static_cast(1) << selTOFDeltaTPositivePionLambda); + } + if (v0Selections.requireNegITSonly) { + maskTrackProperties = maskTrackProperties | (static_cast(1) << selNegItsOnly) | (static_cast(1) << selNegGoodITSTrack); + } else { + maskTrackProperties = maskTrackProperties | (static_cast(1) << selNegGoodTPCTrack) | (static_cast(1) << selNegGoodITSTrack); + // TPC signal is available: ask for negative track PID + if (v0Selections.tpcPidNsigmaCut < 1e+5) { // safeguard for no cut + maskK0ShortSpecific = maskK0ShortSpecific | (static_cast(1) << selTPCPIDNegativePion); + maskLambdaSpecific = maskLambdaSpecific | (static_cast(1) << selTPCPIDNegativePion); + maskAntiLambdaSpecific = maskAntiLambdaSpecific | (static_cast(1) << selTPCPIDNegativeProton); + } + // TOF PID + if (v0Selections.tofPidNsigmaCutK0Pi < 1e+5) // safeguard for no cut + maskK0ShortSpecific = maskK0ShortSpecific | (static_cast(1) << selTOFNSigmaNegativePionK0Short) | (static_cast(1) << selTOFDeltaTNegativePionK0Short); + if (v0Selections.tofPidNsigmaCutLaPi < 1e+5) // safeguard for no cut + maskLambdaSpecific = maskLambdaSpecific | (static_cast(1) << selTOFNSigmaNegativePionLambda) | (static_cast(1) << selTOFDeltaTNegativePionLambda); + if (v0Selections.tofPidNsigmaCutLaPr < 1e+5) // safeguard for no cut + maskAntiLambdaSpecific = maskAntiLambdaSpecific | (static_cast(1) << selTOFNSigmaNegativeProtonLambda) | (static_cast(1) << selTOFDeltaTNegativeProtonLambda); + } + + if (v0Selections.skipTPConly) { + maskK0ShortSpecific = maskK0ShortSpecific | (static_cast(1) << selPosNotTPCOnly) | (static_cast(1) << selNegNotTPCOnly); + maskLambdaSpecific = maskLambdaSpecific | (static_cast(1) << selPosNotTPCOnly) | (static_cast(1) << selNegNotTPCOnly); + maskAntiLambdaSpecific = maskAntiLambdaSpecific | (static_cast(1) << selPosNotTPCOnly) | (static_cast(1) << selNegNotTPCOnly); + } + + // Primary particle selection, central to analysis + maskSelectionK0Short = maskTopological | maskTrackProperties | maskK0ShortSpecific; + maskSelectionLambda = maskTopological | maskTrackProperties | maskLambdaSpecific; + maskSelectionAntiLambda = maskTopological | maskTrackProperties | maskAntiLambdaSpecific; + + // No primary requirement for feeddown matrix + secondaryMaskSelectionLambda = maskTopological | maskTrackProperties | maskLambdaSpecific; + secondaryMaskSelectionAntiLambda = maskTopological | maskTrackProperties | maskAntiLambdaSpecific; + + // Event Counters + histos.add("hEventSelection", "hEventSelection", kTH1F, {{20, -0.5f, +19.5f}}); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(3, "kIsTriggerTVX"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(6, "posZ cut"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(7, "kIsVertexITSTPC"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(8, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(9, "kIsVertexTOFmatched"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(10, "kIsVertexTRDmatched"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(11, "kNoSameBunchPileup"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(12, "kNoCollInTimeRangeStd"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(13, "kNoCollInTimeRangeNarrow"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(14, "Below min occup."); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(15, "Above max occup."); + + histos.add("hEventCentrality", "hEventCentrality", kTH1F, {{100, 0.0f, +100.0f}}); + histos.add("hCentralityVsNch", "hCentralityVsNch", kTH2F, {axisCentrality, axisNch}); + + histos.add("hEventOccupancy", "hEventOccupancy", kTH1F, {axisOccupancy}); + histos.add("hCentralityVsOccupancy", "hCentralityVsOccupancy", kTH2F, {axisCentrality, axisOccupancy}); + + if (!isPP) { + histos.add("hGapSide", "Gap side; Entries", kTH1F, {{5, -0.5, 4.5}}); + histos.add("hSelGapSide", "Selected gap side; Entries", kTH1F, {axisSelGap}); + histos.add("hEventCentralityVsSelGapSide", ";Centrality (%); Selected gap side", kTH2F, {{100, 0.0f, +100.0f}, axisSelGap}); + } + + // for QA and test purposes + auto hRawCentrality = histos.add("hRawCentrality", "hRawCentrality", kTH1F, {axisRawCentrality}); + + for (int ii = 1; ii < 101; ii++) { + float value = 100.5f - static_cast(ii); + hRawCentrality->SetBinContent(ii, value); + } + + // histograms versus mass + if (buildK0sK0sPairs) { + histos.add("K0sK0s/h3dMassK0sK0s", "h3dMassK0sK0s", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + if (!isPP) { + // Non-UPC info + histos.add("K0sK0s/h3dMassK0sK0sHadronic", "h3dMassK0sK0sHadronic", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + // UPC info + histos.add("K0sK0s/h3dMassK0sK0sSGA", "h3dMassK0sK0sSGA", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("K0sK0s/h3dMassK0sK0sSGC", "h3dMassK0sK0sSGC", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("K0sK0s/h3dMassK0sK0sDG", "h3dMassK0sK0sDG", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + } + histos.add("K0sK0s/h2dNbrOfK0ShortVsCentrality", "h2dNbrOfK0ShortVsCentrality", kTH2F, {axisCentrality, {10, -0.5f, 9.5f}}); + // QA plot + // Candidates after K0s selections + histos.add("K0sK0s/K0s/hPosDCAToPV", "hPosDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("K0sK0s/K0s/hNegDCAToPV", "hNegDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("K0sK0s/K0s/hDCAV0Daughters", "hDCAV0Daughters", kTH1F, {axisDCAdau}); + histos.add("K0sK0s/K0s/hDCAV0ToPV", "hDCAV0ToPV", kTH1F, {axisDCAV0ToPV}); + histos.add("K0sK0s/K0s/hV0PointingAngle", "hV0PointingAngle", kTH1F, {axisPointingAngle}); + histos.add("K0sK0s/K0s/hV0Radius", "hV0Radius", kTH1F, {axisRadius}); + histos.add("K0sK0s/K0s/hV0DecayLength", "hDecayLength", kTH1F, {axisProperLifeTime}); + histos.add("K0sK0s/K0s/hV0InvMassWindow", "hInvMassWindow", kTH1F, {axisMassWindow}); + histos.add("K0sK0s/K0s/h2dCompetingMassRej", "h2dCompetingMassRej", kTH2F, {axisLambdaMass, axisK0Mass}); + histos.add("K0sK0s/K0s/h2dArmenteros", "h2dArmenteros", kTH2F, {axisAPAlpha, axisAPQt}); + histos.add("K0sK0s/K0s/hPosTPCNsigma", "hPosTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("K0sK0s/K0s/hNegTPCNsigma", "hNegTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("K0sK0s/K0s/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("K0sK0s/K0s/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + if (doMCAssociation) { + histos.add("K0sK0s/h3dInvMassTrueEtaC1S", "h3dInvMassTrueEtaC1S", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("K0sK0s/h3dInvMassTrueJPsi", "h3dInvMassTrueJPsi", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("K0sK0s/h3dInvMassTrueChiC0", "h3dInvMassTrueChiC0", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("K0sK0s/h3dInvMassTrueChiC1", "h3dInvMassTrueChiC1", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("K0sK0s/h3dInvMassTrueHC", "h3dInvMassTrueHC", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("K0sK0s/h3dInvMassTrueChiC2", "h3dInvMassTrueChiC2", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("K0sK0s/h3dInvMassTrueEtaC2S", "h3dInvMassTrueEtaC2S", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("K0sK0s/h3dInvMassTruePsi2S", "h3dInvMassTruePsi2S", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + } + } + if (buildLaLaBarPairs) { + histos.add("LaLaBar/h3dMassLaLabar", "h3dMassLaLabar", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + if (!isPP) { + // Non-UPC info + histos.add("LaLaBar/h3dMassLaLabarHadronic", "h3dMassLaLabarHadronic", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + // UPC info + histos.add("LaLaBar/h3dMassLaLabarSGA", "h3dMassLaLabarSGA", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("LaLaBar/h3dMassLaLabarSGC", "h3dMassLaLabarSGC", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("LaLaBar/h3dMassLaLabarDG", "h3dMassLaLabarDG", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + } + histos.add("LaLaBar/h2dNbrOfLambdaVsCentrality", "h2dNbrOfLambdaVsCentrality", kTH2F, {axisCentrality, {10, -0.5f, 9.5f}}); + histos.add("LaLaBar/h2dNbrOfAntiLambdaVsCentrality", "h2dNbrOfAntiLambdaVsCentrality", kTH2F, {axisCentrality, {10, -0.5f, 9.5f}}); + // QA plot + // Candidates after Lambda selections + histos.add("LaLaBar/Lambda/hPosDCAToPV", "hPosDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("LaLaBar/Lambda/hNegDCAToPV", "hNegDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("LaLaBar/Lambda/hDCAV0Daughters", "hDCAV0Daughters", kTH1F, {axisDCAdau}); + histos.add("LaLaBar/Lambda/hDCAV0ToPV", "hDCAV0ToPV", kTH1F, {axisDCAV0ToPV}); + histos.add("LaLaBar/Lambda/hV0PointingAngle", "hV0PointingAngle", kTH1F, {axisPointingAngle}); + histos.add("LaLaBar/Lambda/hV0Radius", "hV0Radius", kTH1F, {axisRadius}); + histos.add("LaLaBar/Lambda/hV0DecayLength", "hDecayLength", kTH1F, {axisProperLifeTime}); + histos.add("LaLaBar/Lambda/hV0InvMassWindow", "hInvMassWindow", kTH1F, {axisMassWindow}); + histos.add("LaLaBar/Lambda/h2dCompetingMassRej", "h2dCompetingMassRej", kTH2F, {axisLambdaMass, axisK0Mass}); + histos.add("LaLaBar/Lambda/hPosTPCNsigma", "hPosTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("LaLaBar/Lambda/hNegTPCNsigma", "hNegTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("LaLaBar/Lambda/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("LaLaBar/Lambda/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + + // Candidates after AntiLambda selections + histos.add("LaLaBar/AntiLambda/hPosDCAToPV", "hPosDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("LaLaBar/AntiLambda/hNegDCAToPV", "hNegDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("LaLaBar/AntiLambda/hDCAV0Daughters", "hDCADaughters", kTH1F, {axisDCAdau}); + histos.add("LaLaBar/AntiLambda/hDCAV0ToPV", "hDCAV0ToPV", kTH1F, {axisDCAV0ToPV}); + histos.add("LaLaBar/AntiLambda/hV0PointingAngle", "hV0PointingAngle", kTH1F, {axisPointingAngle}); + histos.add("LaLaBar/AntiLambda/hV0Radius", "hV0Radius", kTH1F, {axisRadius}); + histos.add("LaLaBar/AntiLambda/hV0DecayLength", "hDecayLength", kTH1F, {axisProperLifeTime}); + histos.add("LaLaBar/AntiLambda/hV0InvMassWindow", "hInvMassWindow", kTH1F, {axisMassWindow}); + histos.add("LaLaBar/AntiLambda/h2dCompetingMassRej", "h2dCompetingMassRej", kTH2F, {axisLambdaMass, axisK0Mass}); + histos.add("LaLaBar/AntiLambda/hPosTPCNsigma", "hPosTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("LaLaBar/AntiLambda/hNegTPCNsigma", "hNegTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("LaLaBar/AntiLambda/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("LaLaBar/AntiLambda/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + if (doMCAssociation) { + histos.add("LaLaBar/h3dInvMassTrueEtaC1S", "h3dInvMassTrueEtaC1S", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("LaLaBar/h3dInvMassTrueJPsi", "h3dInvMassTrueJPsi", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("LaLaBar/h3dInvMassTrueChiC0", "h3dInvMassTrueChiC0", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("LaLaBar/h3dInvMassTrueChiC1", "h3dInvMassTrueChiC1", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("LaLaBar/h3dInvMassTrueHC", "h3dInvMassTrueHC", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("LaLaBar/h3dInvMassTrueChiC2", "h3dInvMassTrueChiC2", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("LaLaBar/h3dInvMassTrueEtaC2S", "h3dInvMassTrueEtaC2S", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("LaLaBar/h3dInvMassTruePsi2S", "h3dInvMassTruePsi2S", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + } + } + if (buildXiXiBarPairs) { + histos.add("XiXiBar/h3dMassXiXibar", "h3dMassXiXibar", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + if (!isPP) { + // Non-UPC info + histos.add("XiXiBar/h3dMassXiXibarHadronic", "h3dMassXiXibarHadronic", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + // UPC info + histos.add("XiXiBar/h3dMassXiXibarSGA", "h3dMassXiXibarSGA", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("XiXiBar/h3dMassXiXibarSGC", "h3dMassXiXibarSGC", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("XiXiBar/h3dMassXiXibarDG", "h3dMassXiXibarDG", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + } + histos.add("XiXiBar/h2dNbrOfXiVsCentrality", "h2dNbrOfXiVsCentrality", kTH2F, {axisCentrality, {10, -0.5f, 9.5f}}); + histos.add("XiXiBar/h2dNbrOfAntiXiVsCentrality", "h2dNbrOfAntiXiVsCentrality", kTH2F, {axisCentrality, {10, -0.5f, 9.5f}}); + // QA plot + // Candidates after Xi selections + histos.add("XiXiBar/Xi/hBachDCAToPV", "hBachDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("XiXiBar/Xi/hPosDCAToPV", "hPosDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("XiXiBar/Xi/hNegDCAToPV", "hNegDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("XiXiBar/Xi/hDCACascDaughters", "hDCACascDaughters", kTH1F, {axisDCAdau}); + histos.add("XiXiBar/Xi/hDCAV0Daughters", "hDCAV0Daughters", kTH1F, {axisDCAdau}); + histos.add("XiXiBar/Xi/hDCAV0ToPV", "hDCAV0ToPV", kTH1F, {axisDCAV0ToPV}); + histos.add("XiXiBar/Xi/hV0PointingAngle", "hV0PointingAngle", kTH1F, {axisPointingAngle}); + histos.add("XiXiBar/Xi/hV0Radius", "hV0Radius", kTH1F, {axisRadius}); + histos.add("XiXiBar/Xi/hCascPointingAngle", "hCascPointingAngle", kTH1F, {axisPointingAngle}); + histos.add("XiXiBar/Xi/hCascRadius", "hCascRadius", kTH1F, {axisRadius}); + histos.add("XiXiBar/Xi/hCascDecayLength", "hCascDecayLength", kTH1F, {axisProperLifeTime}); + histos.add("XiXiBar/Xi/hV0InvMassWindow", "hV0InvMassWindow", kTH1F, {axisMassWindow}); + histos.add("XiXiBar/Xi/hCascInvMassWindow", "hCascInvMassWindow", kTH1F, {axisMassWindow}); + histos.add("XiXiBar/Xi/h2dCompetingMassRej", "h2dCompetingMassRej", kTH2F, {axisXiMass, axisOmegaMass}); + histos.add("XiXiBar/Xi/hBachTPCNsigma", "hBachTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("XiXiBar/Xi/hPosTPCNsigma", "hPosTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("XiXiBar/Xi/hNegTPCNsigma", "hNegTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("XiXiBar/Xi/h2dBachelorITSvsTPCpts", "h2dBachelorITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("XiXiBar/Xi/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("XiXiBar/Xi/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + // Candidates after AntiXi selections + histos.add("XiXiBar/AntiXi/hBachDCAToPV", "hBachDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("XiXiBar/AntiXi/hPosDCAToPV", "hPosDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("XiXiBar/AntiXi/hNegDCAToPV", "hNegDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("XiXiBar/AntiXi/hDCACascDaughters", "hDCACascDaughters", kTH1F, {axisDCAdau}); + histos.add("XiXiBar/AntiXi/hDCAV0Daughters", "hDCAV0Daughters", kTH1F, {axisDCAdau}); + histos.add("XiXiBar/AntiXi/hDCAV0ToPV", "hDCAV0ToPV", kTH1F, {axisDCAV0ToPV}); + histos.add("XiXiBar/AntiXi/hV0PointingAngle", "hV0PointingAngle", kTH1F, {axisPointingAngle}); + histos.add("XiXiBar/AntiXi/hV0Radius", "hV0Radius", kTH1F, {axisRadius}); + histos.add("XiXiBar/AntiXi/hCascPointingAngle", "hCascPointingAngle", kTH1F, {axisPointingAngle}); + histos.add("XiXiBar/AntiXi/hCascRadius", "hCascRadius", kTH1F, {axisRadius}); + histos.add("XiXiBar/AntiXi/hCascDecayLength", "hCascDecayLength", kTH1F, {axisProperLifeTime}); + histos.add("XiXiBar/AntiXi/hV0InvMassWindow", "hV0InvMassWindow", kTH1F, {axisMassWindow}); + histos.add("XiXiBar/AntiXi/hCascInvMassWindow", "hCascInvMassWindow", kTH1F, {axisMassWindow}); + histos.add("XiXiBar/AntiXi/h2dCompetingMassRej", "h2dCompetingMassRej", kTH2F, {axisXiMass, axisOmegaMass}); + histos.add("XiXiBar/AntiXi/hBachTPCNsigma", "hBachTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("XiXiBar/AntiXi/hPosTPCNsigma", "hPosTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("XiXiBar/AntiXi/hNegTPCNsigma", "hNegTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("XiXiBar/AntiXi/h2dBachelorITSvsTPCpts", "h2dBachelorITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("XiXiBar/AntiXi/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("XiXiBar/AntiXi/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + if (doMCAssociation) { + histos.add("XiXiBar/h3dInvMassTrueEtaC1S", "h3dInvMassTrueEtaC1S", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("XiXiBar/h3dInvMassTrueJPsi", "h3dInvMassTrueJPsi", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("XiXiBar/h3dInvMassTrueChiC0", "h3dInvMassTrueChiC0", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("XiXiBar/h3dInvMassTrueChiC1", "h3dInvMassTrueChiC1", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("XiXiBar/h3dInvMassTrueHC", "h3dInvMassTrueHC", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("XiXiBar/h3dInvMassTrueChiC2", "h3dInvMassTrueChiC2", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("XiXiBar/h3dInvMassTrueEtaC2S", "h3dInvMassTrueEtaC2S", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("XiXiBar/h3dInvMassTruePsi2S", "h3dInvMassTruePsi2S", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + } + } + if (buildOmOmBarPairs) { + histos.add("OmOmBar/h3dMassOmOmbar", "h3dMassOmOmbar", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + if (!isPP) { + // Non-UPC info + histos.add("OmOmBar/h3dMassOmOmbarHadronic", "h3dMassOmOmbarHadronic", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + // UPC info + histos.add("OmOmBar/h3dMassOmOmbarSGA", "h3dMassOmOmbarSGA", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("OmOmBar/h3dMassOmOmbarSGC", "h3dMassOmOmbarSGC", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("OmOmBar/h3dMassOmOmbarDG", "h3dMassOmOmbarDG", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + } + histos.add("OmOmBar/h2dNbrOfOmegaVsCentrality", "h2dNbrOfOmegaVsCentrality", kTH2F, {axisCentrality, {10, -0.5f, 9.5f}}); + histos.add("OmOmBar/h2dNbrOfAntiOmegaVsCentrality", "h2dNbrOfAntiOmegaVsCentrality", kTH2F, {axisCentrality, {10, -0.5f, 9.5f}}); + // QA plot + // Candidates after Omega selections + histos.add("OmOmBar/Omega/hBachDCAToPV", "hBachDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("OmOmBar/Omega/hPosDCAToPV", "hPosDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("OmOmBar/Omega/hNegDCAToPV", "hNegDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("OmOmBar/Omega/hDCACascDaughters", "hDCACascDaughters", kTH1F, {axisDCAdau}); + histos.add("OmOmBar/Omega/hDCAV0Daughters", "hDCAV0Daughters", kTH1F, {axisDCAdau}); + histos.add("OmOmBar/Omega/hDCAV0ToPV", "hDCAV0ToPV", kTH1F, {axisDCAV0ToPV}); + histos.add("OmOmBar/Omega/hV0PointingAngle", "hV0PointingAngle", kTH1F, {axisPointingAngle}); + histos.add("OmOmBar/Omega/hV0Radius", "hV0Radius", kTH1F, {axisRadius}); + histos.add("OmOmBar/Omega/hCascPointingAngle", "hCascPointingAngle", kTH1F, {axisPointingAngle}); + histos.add("OmOmBar/Omega/hCascRadius", "hCascRadius", kTH1F, {axisRadius}); + histos.add("OmOmBar/Omega/hCascDecayLength", "hCascDecayLength", kTH1F, {axisProperLifeTime}); + histos.add("OmOmBar/Omega/hV0InvMassWindow", "hV0InvMassWindow", kTH1F, {axisMassWindow}); + histos.add("OmOmBar/Omega/hCascInvMassWindow", "hCascInvMassWindow", kTH1F, {axisMassWindow}); + histos.add("OmOmBar/Omega/h2dCompetingMassRej", "h2dCompetingMassRej", kTH2F, {axisXiMass, axisOmegaMass}); + histos.add("OmOmBar/Omega/hBachTPCNsigma", "hBachTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("OmOmBar/Omega/hPosTPCNsigma", "hPosTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("OmOmBar/Omega/hNegTPCNsigma", "hNegTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("OmOmBar/Omega/h2dBachelorITSvsTPCpts", "h2dBachelorITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("OmOmBar/Omega/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("OmOmBar/Omega/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + // Candidates after AntiOmega selections + histos.add("OmOmBar/AntiOmega/hBachDCAToPV", "hBachDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("OmOmBar/AntiOmega/hPosDCAToPV", "hPosDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("OmOmBar/AntiOmega/hNegDCAToPV", "hNegDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("OmOmBar/AntiOmega/hDCACascDaughters", "hDCACascDaughters", kTH1F, {axisDCAdau}); + histos.add("OmOmBar/AntiOmega/hDCAV0Daughters", "hDCAV0Daughters", kTH1F, {axisDCAdau}); + histos.add("OmOmBar/AntiOmega/hDCAV0ToPV", "hDCAV0ToPV", kTH1F, {axisDCAV0ToPV}); + histos.add("OmOmBar/AntiOmega/hV0PointingAngle", "hV0PointingAngle", kTH1F, {axisPointingAngle}); + histos.add("OmOmBar/AntiOmega/hV0Radius", "hV0Radius", kTH1F, {axisRadius}); + histos.add("OmOmBar/AntiOmega/hCascPointingAngle", "hCascPointingAngle", kTH1F, {axisPointingAngle}); + histos.add("OmOmBar/AntiOmega/hCascRadius", "hCascRadius", kTH1F, {axisRadius}); + histos.add("OmOmBar/AntiOmega/hCascDecayLength", "hCascDecayLength", kTH1F, {axisProperLifeTime}); + histos.add("OmOmBar/AntiOmega/hV0InvMassWindow", "hV0InvMassWindow", kTH1F, {axisMassWindow}); + histos.add("OmOmBar/AntiOmega/hCascInvMassWindow", "hCascInvMassWindow", kTH1F, {axisMassWindow}); + histos.add("OmOmBar/AntiOmega/h2dCompetingMassRej", "h2dCompetingMassRej", kTH2F, {axisXiMass, axisOmegaMass}); + histos.add("OmOmBar/AntiOmega/hBachTPCNsigma", "hBachTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("OmOmBar/AntiOmega/hPosTPCNsigma", "hPosTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("OmOmBar/AntiOmega/hNegTPCNsigma", "hNegTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("OmOmBar/AntiOmega/h2dBachelorITSvsTPCpts", "h2dBachelorITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("OmOmBar/AntiOmega/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("OmOmBar/AntiOmega/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + if (doMCAssociation) { + histos.add("OmOmBar/h3dInvMassTrueEtaC2S", "h3dInvMassTrueEtaC2S", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + histos.add("OmOmBar/h3dInvMassTruePsi2S", "h3dInvMassTruePsi2S", kTH3F, {axisCentrality, axisPt, axisQuarkoniumMass}); + } + } + + if (cfgSkimmedProcessing) { + zorroSummary.setObject(zorro.getZorroSummary()); + } + + // inspect histogram sizes, please + histos.print(); + } + + template // TCollision should be of the type: soa::Join::iterator or so + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + mRunNumber = collision.runNumber(); + if (cfgSkimmedProcessing) { + ccdb->setURL(ccdbConfigurations.ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + zorro.initCCDB(ccdb.service, collision.runNumber(), collision.timestamp(), cfgSkimmedTrigger.value); + zorro.populateHistRegistry(histos, collision.runNumber()); + } + + // machine learning initialization if requested + if (mlConfigurations.calculateK0ShortScores || + mlConfigurations.calculateLambdaScores || + mlConfigurations.calculateAntiLambdaScores) { + int64_t timeStampML = collision.timestamp(); + if (mlConfigurations.timestampCCDB.value != -1) + timeStampML = mlConfigurations.timestampCCDB.value; + loadMachines(timeStampML); + } + } + + // function to load models for ML-based classifiers + void loadMachines(int64_t timeStampML) + { + if (mlConfigurations.loadCustomModelsFromCCDB) { + ccdbApi.init(ccdbConfigurations.ccdburl); + LOG(info) << "Fetching models for timestamp: " << timeStampML; + + if (mlConfigurations.calculateLambdaScores) { + bool retrieveSuccessLambda = ccdbApi.retrieveBlob(mlConfigurations.customModelPathCCDB, ".", metadata, timeStampML, false, mlConfigurations.localModelPathLambda.value); + if (retrieveSuccessLambda) { + mlCustomModelLambda.initModel(mlConfigurations.localModelPathLambda.value, mlConfigurations.enableOptimizations.value); + } else { + LOG(fatal) << "Error encountered while fetching/loading the Lambda model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; + } + } + + if (mlConfigurations.calculateAntiLambdaScores) { + bool retrieveSuccessAntiLambda = ccdbApi.retrieveBlob(mlConfigurations.customModelPathCCDB, ".", metadata, timeStampML, false, mlConfigurations.localModelPathAntiLambda.value); + if (retrieveSuccessAntiLambda) { + mlCustomModelAntiLambda.initModel(mlConfigurations.localModelPathAntiLambda.value, mlConfigurations.enableOptimizations.value); + } else { + LOG(fatal) << "Error encountered while fetching/loading the AntiLambda model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; + } + } + + if (mlConfigurations.calculateK0ShortScores) { + bool retrieveSuccessKZeroShort = ccdbApi.retrieveBlob(mlConfigurations.customModelPathCCDB, ".", metadata, timeStampML, false, mlConfigurations.localModelPathK0Short.value); + if (retrieveSuccessKZeroShort) { + mlCustomModelK0Short.initModel(mlConfigurations.localModelPathK0Short.value, mlConfigurations.enableOptimizations.value); + } else { + LOG(fatal) << "Error encountered while fetching/loading the K0Short model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; + } + } + } else { + if (mlConfigurations.calculateLambdaScores) + mlCustomModelLambda.initModel(mlConfigurations.localModelPathLambda.value, mlConfigurations.enableOptimizations.value); + if (mlConfigurations.calculateAntiLambdaScores) + mlCustomModelAntiLambda.initModel(mlConfigurations.localModelPathAntiLambda.value, mlConfigurations.enableOptimizations.value); + if (mlConfigurations.calculateK0ShortScores) + mlCustomModelK0Short.initModel(mlConfigurations.localModelPathK0Short.value, mlConfigurations.enableOptimizations.value); + } + LOG(info) << "ML Models loaded."; + } + + template + bool isEventAccepted(TCollision collision, bool fillHists) + // check whether the collision passes our collision selections + { + if (fillHists) + histos.fill(HIST("hEventSelection"), 0. /* all collisions */); + if (requireSel8 && !collision.sel8()) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 1 /* sel8 collisions */); + + if (requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 2 /* FT0 vertex (acceptable FT0C-FT0A time difference) collisions */); + + if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 3 /* Not at ITS ROF border */); + + if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 4 /* Not at TF border */); + + if (std::abs(collision.posZ()) > 10.f) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 5 /* vertex-Z selected */); + + if (requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 6 /* Contains at least one ITS-TPC track */); + + if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 7 /* PV position consistency check */); + + if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 8 /* PV with at least one contributor matched with TOF */); + + if (requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 9 /* PV with at least one contributor matched with TRD */); + + if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 10 /* Not at same bunch pile-up */); + + if (requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 11 /* No other collision within +/- 10 microseconds */); + + if (requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 12 /* No other collision within +/- 4 microseconds */); + + if (minOccupancy > 0 && collision.trackOccupancyInTimeRange() < minOccupancy) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 13 /* Below min occupancy */); + if (maxOccupancy > 0 && collision.trackOccupancyInTimeRange() > maxOccupancy) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 14 /* Above max occupancy */); + + return true; + } + + template + void fillEventHistograms(TCollision collision, float& centrality, int& selGapSide) + { + if (isPP) { // + centrality = collision.centFT0M(); + + if (qaCentrality) { + auto hRawCentrality = histos.get(HIST("hRawCentrality")); + centrality = hRawCentrality->GetBinContent(hRawCentrality->FindBin(collision.multFT0A() + collision.multFT0C())); + } + } else { + centrality = collision.centFT0C(); + + if (qaCentrality) { + auto hRawCentrality = histos.get(HIST("hRawCentrality")); + centrality = hRawCentrality->GetBinContent(hRawCentrality->FindBin(collision.multFT0C())); + } + } + + // in case we want to push the analysis to Pb-Pb UPC + int gapSide = collision.gapSide(); + if (!isPP) { + // -1 --> Hadronic + // 0 --> Single Gap - A side + // 1 --> Single Gap - C side + // 2 --> Double Gap - both A & C sides + selGapSide = sgSelector.trueGap(collision, upcCuts.fv0Cut, upcCuts.ft0aCut, upcCuts.ft0cCut, upcCuts.zdcCut); + histos.fill(HIST("hGapSide"), gapSide); + histos.fill(HIST("hSelGapSide"), selGapSide); + histos.fill(HIST("hEventCentralityVsSelGapSide"), centrality, selGapSide <= 2 ? selGapSide : -1); + } + + histos.fill(HIST("hEventCentrality"), centrality); + + histos.fill(HIST("hCentralityVsNch"), centrality, collision.multNTracksPVeta1()); + + histos.fill(HIST("hEventOccupancy"), collision.trackOccupancyInTimeRange()); + histos.fill(HIST("hCentralityVsOccupancy"), centrality, collision.trackOccupancyInTimeRange()); + + return; + } + + template + uint64_t computeReconstructionBitmap(TV0 v0, TCollision collision, float rapidityLambda, float rapidityK0Short, float /*pT*/) + // precalculate this information so that a check is one mask operation, not many + { + uint64_t bitMap = 0; + + // + // Base topological variables + // + + // v0 radius min/max selections + if (v0.v0radius() > v0Selections.v0radius) + BITSET(bitMap, selRadius); + if (v0.v0radius() < v0Selections.v0radiusMax) + BITSET(bitMap, selRadiusMax); + // DCA proton and pion to PV for Lambda and AntiLambda decay hypotheses + if (std::fabs(v0.dcapostopv()) > v0Selections.dcaprotontopv && + std::fabs(v0.dcanegtopv()) > v0Selections.dcapiontopv) { + BITSET(bitMap, selDCAPosToPV); + BITSET(bitMap, selDCANegToPV); + } else if (std::fabs(v0.dcapostopv()) > v0Selections.dcapiontopv && + std::fabs(v0.dcanegtopv()) > v0Selections.dcaprotontopv) { + BITSET(bitMap, selDCAPosToPV); + BITSET(bitMap, selDCANegToPV); + } + // V0 cosine of pointing angle + if (v0.v0cosPA() > v0Selections.v0cospa) + BITSET(bitMap, selCosPA); + // DCA between v0 daughters + if (v0.dcaV0daughters() < v0Selections.dcav0dau) + BITSET(bitMap, selDCAV0Dau); + // DCA V0 to prim vtx + if (v0.dcav0topv() > v0Selections.dcav0topv) + BITSET(bitMap, selDCAV0ToPV); + + // + // rapidity + // + if (std::fabs(rapidityLambda) < v0Selections.rapidityCut) + BITSET(bitMap, selLambdaRapidity); + if (std::fabs(rapidityK0Short) < v0Selections.rapidityCut) + BITSET(bitMap, selK0ShortRapidity); + + // + // invariant mass window + // + if (std::fabs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0Selections.v0MassWindow) + BITSET(bitMap, selK0ShortMassWindow); + if (std::fabs(v0.mLambda() - o2::constants::physics::MassLambda0) < v0Selections.v0MassWindow) + BITSET(bitMap, selLambdaMassWindow); + if (std::fabs(v0.mAntiLambda() - o2::constants::physics::MassLambda0Bar) < v0Selections.v0MassWindow) + BITSET(bitMap, selAntiLambdaMassWindow); + + // + // competing mass rejection + // + if (std::fabs(v0.mK0Short() - o2::constants::physics::MassK0Short) > v0Selections.compMassRejection) + BITSET(bitMap, selK0ShortMassRejection); + if (std::fabs(v0.mLambda() - o2::constants::physics::MassLambda0) > v0Selections.compMassRejection) + BITSET(bitMap, selLambdaMassRejection); + + auto posTrackExtra = v0.template posTrackExtra_as(); + auto negTrackExtra = v0.template negTrackExtra_as(); + + // + // ITS quality flags + // + if (posTrackExtra.itsNCls() >= v0Selections.minITSclusters) + BITSET(bitMap, selPosGoodITSTrack); + if (negTrackExtra.itsNCls() >= v0Selections.minITSclusters) + BITSET(bitMap, selNegGoodITSTrack); + + // + // TPC quality flags + // + if (posTrackExtra.tpcCrossedRows() >= v0Selections.minTPCrows) + BITSET(bitMap, selPosGoodTPCTrack); + if (negTrackExtra.tpcCrossedRows() >= v0Selections.minTPCrows) + BITSET(bitMap, selNegGoodTPCTrack); + + // + // TPC PID + // + if (std::fabs(posTrackExtra.tpcNSigmaPi()) < v0Selections.tpcPidNsigmaCut) + BITSET(bitMap, selTPCPIDPositivePion); + if (std::fabs(posTrackExtra.tpcNSigmaPr()) < v0Selections.tpcPidNsigmaCut) + BITSET(bitMap, selTPCPIDPositiveProton); + if (std::fabs(negTrackExtra.tpcNSigmaPi()) < v0Selections.tpcPidNsigmaCut) + BITSET(bitMap, selTPCPIDNegativePion); + if (std::fabs(negTrackExtra.tpcNSigmaPr()) < v0Selections.tpcPidNsigmaCut) + BITSET(bitMap, selTPCPIDNegativeProton); + + // + // TOF PID in DeltaT + // Positive track + if (std::fabs(v0.posTOFDeltaTLaPr()) < v0Selections.maxDeltaTimeProton) + BITSET(bitMap, selTOFDeltaTPositiveProtonLambda); + if (std::fabs(v0.posTOFDeltaTLaPi()) < v0Selections.maxDeltaTimePion) + BITSET(bitMap, selTOFDeltaTPositivePionLambda); + if (std::fabs(v0.posTOFDeltaTK0Pi()) < v0Selections.maxDeltaTimePion) + BITSET(bitMap, selTOFDeltaTPositivePionK0Short); + // Negative track + if (std::fabs(v0.negTOFDeltaTLaPr()) < v0Selections.maxDeltaTimeProton) + BITSET(bitMap, selTOFDeltaTNegativeProtonLambda); + if (std::fabs(v0.negTOFDeltaTLaPi()) < v0Selections.maxDeltaTimePion) + BITSET(bitMap, selTOFDeltaTNegativePionLambda); + if (std::fabs(v0.negTOFDeltaTK0Pi()) < v0Selections.maxDeltaTimePion) + BITSET(bitMap, selTOFDeltaTNegativePionK0Short); + + // + // TOF PID in NSigma + // Positive track + if (std::fabs(v0.tofNSigmaLaPr()) < v0Selections.tofPidNsigmaCutLaPr) + BITSET(bitMap, selTOFNSigmaPositiveProtonLambda); + if (std::fabs(v0.tofNSigmaALaPi()) < v0Selections.tofPidNsigmaCutLaPi) + BITSET(bitMap, selTOFNSigmaPositivePionLambda); + if (std::fabs(v0.tofNSigmaK0PiPlus()) < v0Selections.tofPidNsigmaCutK0Pi) + BITSET(bitMap, selTOFNSigmaPositivePionK0Short); + // Negative track + if (std::fabs(v0.tofNSigmaALaPr()) < v0Selections.tofPidNsigmaCutLaPr) + BITSET(bitMap, selTOFNSigmaNegativeProtonLambda); + if (std::fabs(v0.tofNSigmaLaPi()) < v0Selections.tofPidNsigmaCutLaPi) + BITSET(bitMap, selTOFNSigmaNegativePionLambda); + if (std::fabs(v0.tofNSigmaK0PiMinus()) < v0Selections.tofPidNsigmaCutK0Pi) + BITSET(bitMap, selTOFNSigmaNegativePionK0Short); + + // + // ITS only tag + if (posTrackExtra.tpcCrossedRows() < 1) + BITSET(bitMap, selPosItsOnly); + if (negTrackExtra.tpcCrossedRows() < 1) + BITSET(bitMap, selNegItsOnly); + + // + // TPC only tag + if (posTrackExtra.detectorMap() != o2::aod::track::TPC) + BITSET(bitMap, selPosNotTPCOnly); + if (negTrackExtra.detectorMap() != o2::aod::track::TPC) + BITSET(bitMap, selNegNotTPCOnly); + + // + // proper lifetime + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < lifetimecut->get("lifetimecutLambda")) + BITSET(bitMap, selLambdaCTau); + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < lifetimecut->get("lifetimecutK0S")) + BITSET(bitMap, selK0ShortCTau); + + // + // armenteros + if (v0.qtarm() * v0Selections.armPodCut > std::fabs(v0.alpha()) || v0Selections.armPodCut < 1e-4) + BITSET(bitMap, selK0ShortArmenteros); + + return bitMap; + } + + template + bool isCascadeSelected(TCascade casc, TCollision collision, float rapidity, bool isXi) + // precalculate this information so that a check is one mask operation, not many + { + // + // Base topological variables + // + + // v0 radius min/max selections + if (casc.v0radius() < cascSelections.v0radius) + return false; + if (casc.v0radius() > cascSelections.v0radiusMax) + return false; + // DCA proton and pion to PV for Lambda and AntiLambda decay hypotheses + if (casc.sign() < 0) { // Xi- or Omega- --> positive/negative daughter = proton/pion + if (std::fabs(casc.dcapostopv()) < cascSelections.dcaprotontopv) + return false; + if (std::fabs(casc.dcanegtopv()) < cascSelections.dcapiontopv) + return false; + } else { // Xi+ or Omega+ --> positive/negative daughter = pion/proton + if (std::fabs(casc.dcapostopv()) < cascSelections.dcapiontopv) + return false; + if (std::fabs(casc.dcanegtopv()) < cascSelections.dcaprotontopv) + return false; + } + // V0 cosine of pointing angle + if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cascSelections.v0cospa) + return false; + // DCA between v0 daughters + if (casc.dcaV0daughters() > cascSelections.dcav0dau) + return false; + // DCA V0 to prim vtx + if (casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()) < cascSelections.dcav0topv) + return false; + + // casc radius min/max selections + if (casc.cascradius() < cascSelections.cascradius) + return false; + if (casc.cascradius() > cascSelections.cascradiusMax) + return false; + // DCA bachelor selection + if (std::fabs(casc.dcabachtopv()) < cascSelections.dcabachtopv) + return false; + // Bachelor-baryon cosPA selection + if (casc.bachBaryonCosPA() < cascSelections.bachbaryoncospa) + return false; + // DCA bachelor-baryon selection + if (std::fabs(casc.bachBaryonDCAxyToPV()) < cascSelections.dcaxybachbaryontopv) + return false; + // casc cosine of pointing angle + if (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascSelections.casccospa) + return false; + // DCA between casc daughters + if (casc.dcacascdaughters() > cascSelections.dcacascdau) + return false; + + // + // rapidity + // + if (std::fabs(rapidity) > cascSelections.rapidityCut) + return false; + + // + // invariant mass window + // + if (std::fabs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascSelections.v0MassWindow) + return false; + if (isXi && std::fabs(casc.mXi() - o2::constants::physics::MassXiMinus) > cascSelections.cascMassWindow) + return false; + if (!isXi && std::fabs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > cascSelections.cascMassWindow) + return false; + + // + // competing mass rejection + // + if (isXi && std::fabs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) < cascSelections.compMassRejection) + return false; + if (!isXi && std::fabs(casc.mXi() - o2::constants::physics::MassXiMinus) < cascSelections.compMassRejection) + return false; + + auto bachTrackExtra = casc.template bachTrackExtra_as(); + auto posTrackExtra = casc.template posTrackExtra_as(); + auto negTrackExtra = casc.template negTrackExtra_as(); + + // + // ITS quality flags + // + if (bachTrackExtra.itsNCls() < cascSelections.minITSclusters) + return false; + if (posTrackExtra.itsNCls() < cascSelections.minITSclusters) + return false; + if (negTrackExtra.itsNCls() < cascSelections.minITSclusters) + return false; + + // + // TPC quality flags + // + if (bachTrackExtra.tpcCrossedRows() < cascSelections.minTPCrows) + return false; + if (posTrackExtra.tpcCrossedRows() < cascSelections.minTPCrows) + return false; + if (negTrackExtra.tpcCrossedRows() < cascSelections.minTPCrows) + return false; + + // + // TPC PID + // + if (isXi && std::fabs(bachTrackExtra.tpcNSigmaPi()) > cascSelections.tpcPidNsigmaCut) + return false; + if (!isXi && std::fabs(bachTrackExtra.tpcNSigmaKa()) > cascSelections.tpcPidNsigmaCut) + return false; + if (casc.sign() < 0) { // Xi- or Omega- --> positive/negative daughter = proton/pion + if (std::fabs(posTrackExtra.tpcNSigmaPr()) > cascSelections.tpcPidNsigmaCut) + return false; + if (std::fabs(negTrackExtra.tpcNSigmaPi()) > cascSelections.tpcPidNsigmaCut) + return false; + } else { // Xi+ or Omega+ --> positive/negative daughter = pion/proton + if (std::fabs(posTrackExtra.tpcNSigmaPi()) > cascSelections.tpcPidNsigmaCut) + return false; + if (std::fabs(negTrackExtra.tpcNSigmaPr()) > cascSelections.tpcPidNsigmaCut) + return false; + } + + // + // TOF PID in DeltaT + // Bachelor track + if (bachTrackExtra.hasTOF()) { + if (isXi && std::fabs(casc.bachTOFDeltaTXiPi()) > cascSelections.maxDeltaTimePion) + return false; + if (!isXi && std::fabs(casc.bachTOFDeltaTOmKa()) > cascSelections.maxDeltaTimeKaon) + return false; + } + // Positive track + if (posTrackExtra.hasTOF()) { + if (casc.sign() < 0) { // Xi- or Omega- --> positive daughter = proton + if (isXi && std::fabs(casc.posTOFDeltaTXiPr()) > cascSelections.maxDeltaTimeProton) + return false; + if (!isXi && std::fabs(casc.posTOFDeltaTOmPr()) > cascSelections.maxDeltaTimeProton) + return false; + } else { // Xi+ or Omega+ --> positive daughter = pion + if (isXi && std::fabs(casc.posTOFDeltaTXiPi()) > cascSelections.maxDeltaTimePion) + return false; + if (!isXi && std::fabs(casc.posTOFDeltaTOmPi()) > cascSelections.maxDeltaTimePion) + return false; + } + } + // Negative track + if (negTrackExtra.hasTOF()) { + if (casc.sign() < 0) { // Xi- or Omega- --> negative daughter = pion + if (isXi && std::fabs(casc.negTOFDeltaTXiPi()) > cascSelections.maxDeltaTimePion) + return false; + if (!isXi && std::fabs(casc.negTOFDeltaTOmPi()) > cascSelections.maxDeltaTimePion) + return false; + } else { // Xi+ or Omega+ --> negative daughter = proton + if (isXi && std::fabs(casc.negTOFDeltaTXiPr()) > cascSelections.maxDeltaTimeProton) + return false; + if (!isXi && std::fabs(casc.negTOFDeltaTOmPr()) > cascSelections.maxDeltaTimeProton) + return false; + } + } + + // + // TOF PID in NSigma + // Bachelor track + if (bachTrackExtra.hasTOF()) { + if (isXi && std::fabs(casc.tofNSigmaXiPi()) > cascSelections.tofPidNsigmaCutXiPi) + return false; + if (!isXi && std::fabs(casc.tofNSigmaOmKa()) > cascSelections.tofPidNsigmaCutOmKa) + return false; + } + // Positive track + if (posTrackExtra.hasTOF()) { + if (casc.sign() < 0) { // Xi- or Omega- --> positive daughter = proton + if (isXi && std::fabs(casc.tofNSigmaXiLaPr()) > cascSelections.tofPidNsigmaCutLaPr) + return false; + if (!isXi && std::fabs(casc.tofNSigmaOmLaPr()) > cascSelections.tofPidNsigmaCutLaPr) + return false; + } else { // Xi+ or Omega+ --> positive daughter = pion + if (isXi && std::fabs(casc.tofNSigmaXiLaPi()) > cascSelections.tofPidNsigmaCutLaPi) + return false; + if (!isXi && std::fabs(casc.tofNSigmaOmLaPi()) > cascSelections.tofPidNsigmaCutLaPi) + return false; + } + } + // Negative track + if (negTrackExtra.hasTOF()) { + if (casc.sign() < 0) { // Xi- or Omega- --> negative daughter = pion + if (isXi && std::fabs(casc.tofNSigmaXiLaPr()) > cascSelections.tofPidNsigmaCutLaPi) + return false; + if (!isXi && std::fabs(casc.tofNSigmaOmLaPr()) > cascSelections.tofPidNsigmaCutLaPi) + return false; + } else { // Xi+ or Omega+ --> negative daughter = proton + if (isXi && std::fabs(casc.tofNSigmaXiLaPi()) > cascSelections.tofPidNsigmaCutLaPr) + return false; + if (!isXi && std::fabs(casc.tofNSigmaOmLaPi()) > cascSelections.tofPidNsigmaCutLaPr) + return false; + } + } + + // + // proper lifetime + float distOverTotMom = std::sqrt(std::pow(casc.x() - collision.posX(), 2) + std::pow(casc.y() - collision.posY(), 2) + std::pow(casc.z() - collision.posZ(), 2)) / (casc.p() + 1E-10); + if (isXi && distOverTotMom * o2::constants::physics::MassXiMinus / ctauXiPDG > cascSelections.cascProperLifeTime) + return false; + if (!isXi && distOverTotMom * o2::constants::physics::MassOmegaMinus / ctauOmegaPDG > cascSelections.cascProperLifeTime) + return false; + + // + // MC association (if asked) + if (doMCAssociation) { + if constexpr (requires { casc.template cascMCCore_as>(); }) { // check if MC information is available + auto cascMC = casc.template cascMCCore_as>(); + + if (isXi) { + if (casc.sign() < 0) { + if (cascMC.pdgCode() != 3312 || cascMC.pdgCodePositive() != 2212 || cascMC.pdgCodeNegative() != -211 || cascMC.pdgCodeBachelor() != -211) + return false; + } else { + if (cascMC.pdgCode() != -3312 || cascMC.pdgCodePositive() != 211 || cascMC.pdgCodeNegative() != -2212 || cascMC.pdgCodeBachelor() != 211) + return false; + } + } else { + if (casc.sign() < 0) { + if (cascMC.pdgCode() != 3334 || cascMC.pdgCodePositive() != 2212 || cascMC.pdgCodeNegative() != -211 || cascMC.pdgCodeBachelor() != -321) + return false; + } else { + if (cascMC.pdgCode() != -3334 || cascMC.pdgCodePositive() != 211 || cascMC.pdgCodeNegative() != -2212 || cascMC.pdgCodeBachelor() != 321) + return false; + } + } + } + } + + return true; + } + + template + uint64_t computeMCAssociation(TV0 v0) + // precalculate this information so that a check is one mask operation, not many + { + uint64_t bitMap = 0; + // check for specific particle species + + if (v0.pdgCode() == 310 && v0.pdgCodePositive() == 211 && v0.pdgCodeNegative() == -211) { + BITSET(bitMap, selConsiderK0Short); + if (v0.isPhysicalPrimary()) + BITSET(bitMap, selPhysPrimK0Short); + } + if (v0.pdgCode() == 3122 && v0.pdgCodePositive() == 2212 && v0.pdgCodeNegative() == -211) { + BITSET(bitMap, selConsiderLambda); + if (v0.isPhysicalPrimary()) + BITSET(bitMap, selPhysPrimLambda); + } + if (v0.pdgCode() == -3122 && v0.pdgCodePositive() == 211 && v0.pdgCodeNegative() == -2212) { + BITSET(bitMap, selConsiderAntiLambda); + if (v0.isPhysicalPrimary()) + BITSET(bitMap, selPhysPrimAntiLambda); + } + return bitMap; + } + + bool verifyMask(uint64_t bitmap, uint64_t mask) + { + return (bitmap & mask) == mask; + } + + template + void analyseV0Candidate(TV0 v0, float pt, uint64_t selMap, std::vector& selK0ShortIndices, std::vector& selLambdaIndices, std::vector& selAntiLambdaIndices, int v0TableOffset) + // precalculate this information so that a check is one mask operation, not many + { + bool passK0ShortSelections = false; + bool passLambdaSelections = false; + bool passAntiLambdaSelections = false; + + // machine learning is on, go for calculation of thresholds + // FIXME THIS NEEDS ADJUSTING + std::vector inputFeatures{pt, 0.0f, 0.0f, v0.v0radius(), v0.v0cosPA(), v0.dcaV0daughters(), v0.dcapostopv(), v0.dcanegtopv()}; + + if (mlConfigurations.useK0ShortScores) { + float k0shortScore = -1; + if (mlConfigurations.calculateK0ShortScores) { + // evaluate machine-learning scores + float* k0shortProbability = mlCustomModelK0Short.evalModel(inputFeatures); + k0shortScore = k0shortProbability[1]; + } else { + k0shortScore = v0.k0ShortBDTScore(); + } + if (k0shortScore > mlConfigurations.thresholdK0Short.value) { + passK0ShortSelections = true; + } + } else { + passK0ShortSelections = verifyMask(selMap, maskSelectionK0Short); + } + if (mlConfigurations.useLambdaScores) { + float lambdaScore = -1; + if (mlConfigurations.calculateLambdaScores) { + // evaluate machine-learning scores + float* lambdaProbability = mlCustomModelLambda.evalModel(inputFeatures); + lambdaScore = lambdaProbability[1]; + } else { + lambdaScore = v0.lambdaBDTScore(); + } + if (lambdaScore > mlConfigurations.thresholdK0Short.value) { + passLambdaSelections = true; + } + } else { + passLambdaSelections = verifyMask(selMap, maskSelectionLambda); + } + if (mlConfigurations.useLambdaScores) { + float antiLambdaScore = -1; + if (mlConfigurations.calculateAntiLambdaScores) { + // evaluate machine-learning scores + float* antilambdaProbability = mlCustomModelAntiLambda.evalModel(inputFeatures); + antiLambdaScore = antilambdaProbability[1]; + } else { + antiLambdaScore = v0.antiLambdaBDTScore(); + } + if (antiLambdaScore > mlConfigurations.thresholdK0Short.value) { + passAntiLambdaSelections = true; + } + } else { + passAntiLambdaSelections = verifyMask(selMap, maskSelectionAntiLambda); + } + + // need local index because of the grouping of collisions + selK0ShortIndices[v0.globalIndex() - v0TableOffset] = passK0ShortSelections; + selLambdaIndices[v0.globalIndex() - v0TableOffset] = passLambdaSelections; + selAntiLambdaIndices[v0.globalIndex() - v0TableOffset] = passAntiLambdaSelections; + } + + template + void fillQAplot(TCollision collision, THyperon hyperon, THyperon antiHyperon, int type) + { // fill QA information about hyperon - antihyperon pair + if (type == 0) { + if constexpr (requires { hyperon.mK0Short(); antiHyperon.mK0Short(); }) { // check if v0 information is available + auto posTrackExtraHyperon = hyperon.template posTrackExtra_as(); + auto negTrackExtraHyperon = hyperon.template negTrackExtra_as(); + + auto posTrackExtraAntiHyperon = antiHyperon.template posTrackExtra_as(); + auto negTrackExtraAntiHyperon = antiHyperon.template negTrackExtra_as(); + + float hyperonDecayLength = std::sqrt(std::pow(hyperon.x() - collision.posX(), 2) + std::pow(hyperon.y() - collision.posY(), 2) + std::pow(hyperon.z() - collision.posZ(), 2)) * o2::constants::physics::MassKaonNeutral / (hyperon.p() + 1E-10); + float antiHyperonDecayLength = std::sqrt(std::pow(antiHyperon.x() - collision.posX(), 2) + std::pow(antiHyperon.y() - collision.posY(), 2) + std::pow(antiHyperon.z() - collision.posZ(), 2)) * o2::constants::physics::MassKaonNeutral / (antiHyperon.p() + 1E-10); + + // Candidates after K0s selections + histos.fill(HIST("K0sK0s/K0s/hPosDCAToPV"), hyperon.dcapostopv()); + histos.fill(HIST("K0sK0s/K0s/hNegDCAToPV"), hyperon.dcanegtopv()); + histos.fill(HIST("K0sK0s/K0s/hDCAV0Daughters"), hyperon.dcaV0daughters()); + histos.fill(HIST("K0sK0s/K0s/hDCAV0ToPV"), hyperon.dcav0topv()); + histos.fill(HIST("K0sK0s/K0s/hV0PointingAngle"), hyperon.v0cosPA()); + histos.fill(HIST("K0sK0s/K0s/hV0Radius"), hyperon.v0radius()); + histos.fill(HIST("K0sK0s/K0s/hV0DecayLength"), hyperonDecayLength); + histos.fill(HIST("K0sK0s/K0s/hV0InvMassWindow"), hyperon.mK0Short() - o2::constants::physics::MassK0Short); + histos.fill(HIST("K0sK0s/K0s/h2dCompetingMassRej"), hyperon.mLambda(), hyperon.mK0Short()); + histos.fill(HIST("K0sK0s/K0s/h2dArmenteros"), hyperon.alpha(), hyperon.qtarm()); // cross-check + histos.fill(HIST("K0sK0s/K0s/hPosTPCNsigma"), posTrackExtraHyperon.tpcNSigmaPi()); + histos.fill(HIST("K0sK0s/K0s/hNegTPCNsigma"), negTrackExtraHyperon.tpcNSigmaPi()); + histos.fill(HIST("K0sK0s/K0s/h2dPositiveITSvsTPCpts"), posTrackExtraHyperon.tpcCrossedRows(), posTrackExtraHyperon.itsNCls()); + histos.fill(HIST("K0sK0s/K0s/h2dNegativeITSvsTPCpts"), negTrackExtraHyperon.tpcCrossedRows(), negTrackExtraHyperon.itsNCls()); + // Candidates after K0s selections + histos.fill(HIST("K0sK0s/K0s/hPosDCAToPV"), antiHyperon.dcapostopv()); + histos.fill(HIST("K0sK0s/K0s/hNegDCAToPV"), antiHyperon.dcanegtopv()); + histos.fill(HIST("K0sK0s/K0s/hDCAV0Daughters"), antiHyperon.dcaV0daughters()); + histos.fill(HIST("K0sK0s/K0s/hDCAV0ToPV"), antiHyperon.dcav0topv()); + histos.fill(HIST("K0sK0s/K0s/hV0PointingAngle"), antiHyperon.v0cosPA()); + histos.fill(HIST("K0sK0s/K0s/hV0Radius"), antiHyperon.v0radius()); + histos.fill(HIST("K0sK0s/K0s/hV0DecayLength"), antiHyperonDecayLength); + histos.fill(HIST("K0sK0s/K0s/hV0InvMassWindow"), antiHyperon.mK0Short() - o2::constants::physics::MassK0Short); + histos.fill(HIST("K0sK0s/K0s/h2dCompetingMassRej"), antiHyperon.mLambda(), antiHyperon.mK0Short()); + histos.fill(HIST("K0sK0s/K0s/h2dArmenteros"), antiHyperon.alpha(), antiHyperon.qtarm()); // cross-check + histos.fill(HIST("K0sK0s/K0s/hPosTPCNsigma"), posTrackExtraAntiHyperon.tpcNSigmaPi()); + histos.fill(HIST("K0sK0s/K0s/hNegTPCNsigma"), negTrackExtraAntiHyperon.tpcNSigmaPi()); + histos.fill(HIST("K0sK0s/K0s/h2dPositiveITSvsTPCpts"), posTrackExtraAntiHyperon.tpcCrossedRows(), posTrackExtraAntiHyperon.itsNCls()); + histos.fill(HIST("K0sK0s/K0s/h2dNegativeITSvsTPCpts"), negTrackExtraAntiHyperon.tpcCrossedRows(), negTrackExtraAntiHyperon.itsNCls()); + } + } + if (type == 1) { + if constexpr (requires { hyperon.mK0Short(); antiHyperon.mK0Short(); }) { // check if v0 information is available + auto posTrackExtraHyperon = hyperon.template posTrackExtra_as(); + auto negTrackExtraHyperon = hyperon.template negTrackExtra_as(); + + auto posTrackExtraAntiHyperon = antiHyperon.template posTrackExtra_as(); + auto negTrackExtraAntiHyperon = antiHyperon.template negTrackExtra_as(); + + float hyperonDecayLength = std::sqrt(std::pow(hyperon.x() - collision.posX(), 2) + std::pow(hyperon.y() - collision.posY(), 2) + std::pow(hyperon.z() - collision.posZ(), 2)) * o2::constants::physics::MassLambda0 / (hyperon.p() + 1E-10); + float antiHyperonDecayLength = std::sqrt(std::pow(antiHyperon.x() - collision.posX(), 2) + std::pow(antiHyperon.y() - collision.posY(), 2) + std::pow(antiHyperon.z() - collision.posZ(), 2)) * o2::constants::physics::MassLambda0 / (antiHyperon.p() + 1E-10); + + // Candidates after Lambda selections + histos.fill(HIST("LaLaBar/Lambda/hPosDCAToPV"), hyperon.dcapostopv()); + histos.fill(HIST("LaLaBar/Lambda/hNegDCAToPV"), hyperon.dcanegtopv()); + histos.fill(HIST("LaLaBar/Lambda/hDCAV0Daughters"), hyperon.dcaV0daughters()); + histos.fill(HIST("LaLaBar/Lambda/hDCAV0ToPV"), hyperon.dcav0topv()); + histos.fill(HIST("LaLaBar/Lambda/hV0PointingAngle"), hyperon.v0cosPA()); + histos.fill(HIST("LaLaBar/Lambda/hV0Radius"), hyperon.v0radius()); + histos.fill(HIST("LaLaBar/Lambda/hV0DecayLength"), hyperonDecayLength); + histos.fill(HIST("LaLaBar/Lambda/hV0InvMassWindow"), hyperon.mLambda() - o2::constants::physics::MassLambda0); + histos.fill(HIST("LaLaBar/Lambda/h2dCompetingMassRej"), hyperon.mLambda(), hyperon.mK0Short()); + histos.fill(HIST("LaLaBar/Lambda/hPosTPCNsigma"), posTrackExtraHyperon.tpcNSigmaPr()); + histos.fill(HIST("LaLaBar/Lambda/hNegTPCNsigma"), negTrackExtraHyperon.tpcNSigmaPi()); + histos.fill(HIST("LaLaBar/Lambda/h2dPositiveITSvsTPCpts"), posTrackExtraHyperon.tpcCrossedRows(), posTrackExtraHyperon.itsNCls()); + histos.fill(HIST("LaLaBar/Lambda/h2dNegativeITSvsTPCpts"), negTrackExtraHyperon.tpcCrossedRows(), negTrackExtraHyperon.itsNCls()); + // Candidates after AntiLambda selections + histos.fill(HIST("LaLaBar/AntiLambda/hPosDCAToPV"), antiHyperon.dcapostopv()); + histos.fill(HIST("LaLaBar/AntiLambda/hNegDCAToPV"), antiHyperon.dcapostopv()); + histos.fill(HIST("LaLaBar/AntiLambda/hDCAV0Daughters"), antiHyperon.dcaV0daughters()); + histos.fill(HIST("LaLaBar/AntiLambda/hDCAV0ToPV"), antiHyperon.dcav0topv()); + histos.fill(HIST("LaLaBar/AntiLambda/hV0PointingAngle"), antiHyperon.v0cosPA()); + histos.fill(HIST("LaLaBar/AntiLambda/hV0Radius"), antiHyperon.v0radius()); + histos.fill(HIST("LaLaBar/AntiLambda/hV0DecayLength"), antiHyperonDecayLength); + histos.fill(HIST("LaLaBar/AntiLambda/hV0InvMassWindow"), antiHyperon.mLambda() - o2::constants::physics::MassLambda0); + histos.fill(HIST("LaLaBar/AntiLambda/h2dCompetingMassRej"), antiHyperon.mLambda(), antiHyperon.mK0Short()); + histos.fill(HIST("LaLaBar/AntiLambda/hPosTPCNsigma"), posTrackExtraAntiHyperon.tpcNSigmaPi()); + histos.fill(HIST("LaLaBar/AntiLambda/hNegTPCNsigma"), negTrackExtraAntiHyperon.tpcNSigmaPr()); + histos.fill(HIST("LaLaBar/AntiLambda/h2dPositiveITSvsTPCpts"), posTrackExtraAntiHyperon.tpcCrossedRows(), posTrackExtraAntiHyperon.itsNCls()); + histos.fill(HIST("LaLaBar/AntiLambda/h2dNegativeITSvsTPCpts"), negTrackExtraAntiHyperon.tpcCrossedRows(), negTrackExtraAntiHyperon.itsNCls()); + } + } + if (type == 2) { + if constexpr (requires { hyperon.dcabachtopv(); antiHyperon.dcabachtopv(); }) { // check if Cascade information is available + auto bachTrackExtraHyperon = hyperon.template bachTrackExtra_as(); + auto posTrackExtraHyperon = hyperon.template posTrackExtra_as(); + auto negTrackExtraHyperon = hyperon.template negTrackExtra_as(); + + auto bachTrackExtraAntiHyperon = antiHyperon.template bachTrackExtra_as(); + auto posTrackExtraAntiHyperon = antiHyperon.template posTrackExtra_as(); + auto negTrackExtraAntiHyperon = antiHyperon.template negTrackExtra_as(); + + float hyperonDecayLength = std::sqrt(std::pow(hyperon.x() - collision.posX(), 2) + std::pow(hyperon.y() - collision.posY(), 2) + std::pow(hyperon.z() - collision.posZ(), 2)) * o2::constants::physics::MassXiMinus / (hyperon.p() + 1E-10); + float antiHyperonDecayLength = std::sqrt(std::pow(antiHyperon.x() - collision.posX(), 2) + std::pow(antiHyperon.y() - collision.posY(), 2) + std::pow(antiHyperon.z() - collision.posZ(), 2)) * o2::constants::physics::MassXiMinus / (antiHyperon.p() + 1E-10); + + // Candidates after Xi selections + histos.fill(HIST("XiXiBar/Xi/hBachDCAToPV"), hyperon.dcabachtopv()); + histos.fill(HIST("XiXiBar/Xi/hPosDCAToPV"), hyperon.dcapostopv()); + histos.fill(HIST("XiXiBar/Xi/hNegDCAToPV"), hyperon.dcanegtopv()); + histos.fill(HIST("XiXiBar/Xi/hDCACascDaughters"), hyperon.dcacascdaughters()); + histos.fill(HIST("XiXiBar/Xi/hDCAV0Daughters"), hyperon.dcaV0daughters()); + histos.fill(HIST("XiXiBar/Xi/hDCAV0ToPV"), hyperon.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + histos.fill(HIST("XiXiBar/Xi/hV0PointingAngle"), hyperon.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + histos.fill(HIST("XiXiBar/Xi/hV0Radius"), hyperon.v0radius()); + histos.fill(HIST("XiXiBar/Xi/hCascPointingAngle"), hyperon.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + histos.fill(HIST("XiXiBar/Xi/hCascRadius"), hyperon.cascradius()); + histos.fill(HIST("XiXiBar/Xi/hCascDecayLength"), hyperonDecayLength); + histos.fill(HIST("XiXiBar/Xi/hV0InvMassWindow"), hyperon.mLambda() - o2::constants::physics::MassLambda0); + histos.fill(HIST("XiXiBar/Xi/hCascInvMassWindow"), hyperon.mXi() - o2::constants::physics::MassXiMinus); + histos.fill(HIST("XiXiBar/Xi/h2dCompetingMassRej"), hyperon.mXi(), hyperon.mOmega()); + histos.fill(HIST("XiXiBar/Xi/hBachTPCNsigma"), bachTrackExtraHyperon.tpcNSigmaPi()); + histos.fill(HIST("XiXiBar/Xi/hPosTPCNsigma"), posTrackExtraHyperon.tpcNSigmaPr()); + histos.fill(HIST("XiXiBar/Xi/hNegTPCNsigma"), negTrackExtraHyperon.tpcNSigmaPi()); + histos.fill(HIST("XiXiBar/Xi/h2dBachelorITSvsTPCpts"), bachTrackExtraHyperon.tpcCrossedRows(), bachTrackExtraHyperon.itsNCls()); + histos.fill(HIST("XiXiBar/Xi/h2dPositiveITSvsTPCpts"), posTrackExtraHyperon.tpcCrossedRows(), posTrackExtraHyperon.itsNCls()); + histos.fill(HIST("XiXiBar/Xi/h2dNegativeITSvsTPCpts"), negTrackExtraHyperon.tpcCrossedRows(), negTrackExtraHyperon.itsNCls()); + // Candidates after AntiXi selections + histos.fill(HIST("XiXiBar/AntiXi/hBachDCAToPV"), antiHyperon.dcabachtopv()); + histos.fill(HIST("XiXiBar/AntiXi/hPosDCAToPV"), antiHyperon.dcapostopv()); + histos.fill(HIST("XiXiBar/AntiXi/hNegDCAToPV"), antiHyperon.dcanegtopv()); + histos.fill(HIST("XiXiBar/AntiXi/hDCACascDaughters"), antiHyperon.dcacascdaughters()); + histos.fill(HIST("XiXiBar/AntiXi/hDCAV0Daughters"), antiHyperon.dcaV0daughters()); + histos.fill(HIST("XiXiBar/AntiXi/hDCAV0ToPV"), antiHyperon.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + histos.fill(HIST("XiXiBar/AntiXi/hV0PointingAngle"), antiHyperon.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + histos.fill(HIST("XiXiBar/AntiXi/hV0Radius"), antiHyperon.v0radius()); + histos.fill(HIST("XiXiBar/AntiXi/hCascPointingAngle"), antiHyperon.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + histos.fill(HIST("XiXiBar/AntiXi/hCascRadius"), antiHyperon.cascradius()); + histos.fill(HIST("XiXiBar/AntiXi/hCascDecayLength"), antiHyperonDecayLength); + histos.fill(HIST("XiXiBar/AntiXi/hV0InvMassWindow"), antiHyperon.mLambda() - o2::constants::physics::MassLambda0); + histos.fill(HIST("XiXiBar/AntiXi/hCascInvMassWindow"), antiHyperon.mXi() - o2::constants::physics::MassXiMinus); + histos.fill(HIST("XiXiBar/AntiXi/h2dCompetingMassRej"), antiHyperon.mXi(), antiHyperon.mOmega()); + histos.fill(HIST("XiXiBar/AntiXi/hBachTPCNsigma"), bachTrackExtraAntiHyperon.tpcNSigmaPi()); + histos.fill(HIST("XiXiBar/AntiXi/hPosTPCNsigma"), posTrackExtraAntiHyperon.tpcNSigmaPi()); + histos.fill(HIST("XiXiBar/AntiXi/hNegTPCNsigma"), negTrackExtraAntiHyperon.tpcNSigmaPr()); + histos.fill(HIST("XiXiBar/AntiXi/h2dBachelorITSvsTPCpts"), bachTrackExtraAntiHyperon.tpcCrossedRows(), bachTrackExtraAntiHyperon.itsNCls()); + histos.fill(HIST("XiXiBar/AntiXi/h2dPositiveITSvsTPCpts"), posTrackExtraAntiHyperon.tpcCrossedRows(), posTrackExtraAntiHyperon.itsNCls()); + histos.fill(HIST("XiXiBar/AntiXi/h2dNegativeITSvsTPCpts"), negTrackExtraAntiHyperon.tpcCrossedRows(), negTrackExtraAntiHyperon.itsNCls()); + } + } + if (type == 3) { + if constexpr (requires { hyperon.dcabachtopv(); antiHyperon.dcabachtopv(); }) { // check if Cascade information is available + auto bachTrackExtraHyperon = hyperon.template bachTrackExtra_as(); + auto posTrackExtraHyperon = hyperon.template posTrackExtra_as(); + auto negTrackExtraHyperon = hyperon.template negTrackExtra_as(); + + auto bachTrackExtraAntiHyperon = antiHyperon.template bachTrackExtra_as(); + auto posTrackExtraAntiHyperon = antiHyperon.template posTrackExtra_as(); + auto negTrackExtraAntiHyperon = antiHyperon.template negTrackExtra_as(); + + float hyperonDecayLength = std::sqrt(std::pow(hyperon.x() - collision.posX(), 2) + std::pow(hyperon.y() - collision.posY(), 2) + std::pow(hyperon.z() - collision.posZ(), 2)) * o2::constants::physics::MassOmegaMinus / (hyperon.p() + 1E-10); + float antiHyperonDecayLength = std::sqrt(std::pow(antiHyperon.x() - collision.posX(), 2) + std::pow(antiHyperon.y() - collision.posY(), 2) + std::pow(antiHyperon.z() - collision.posZ(), 2)) * o2::constants::physics::MassOmegaMinus / (antiHyperon.p() + 1E-10); + + // Candidates after Omega selections + histos.fill(HIST("OmOmBar/Omega/hBachDCAToPV"), hyperon.dcabachtopv()); + histos.fill(HIST("OmOmBar/Omega/hPosDCAToPV"), hyperon.dcapostopv()); + histos.fill(HIST("OmOmBar/Omega/hNegDCAToPV"), hyperon.dcanegtopv()); + histos.fill(HIST("OmOmBar/Omega/hDCACascDaughters"), hyperon.dcacascdaughters()); + histos.fill(HIST("OmOmBar/Omega/hDCAV0Daughters"), hyperon.dcaV0daughters()); + histos.fill(HIST("OmOmBar/Omega/hDCAV0ToPV"), hyperon.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + histos.fill(HIST("OmOmBar/Omega/hV0PointingAngle"), hyperon.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + histos.fill(HIST("OmOmBar/Omega/hV0Radius"), hyperon.v0radius()); + histos.fill(HIST("OmOmBar/Omega/hCascPointingAngle"), hyperon.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + histos.fill(HIST("OmOmBar/Omega/hCascRadius"), hyperon.cascradius()); + histos.fill(HIST("OmOmBar/Omega/hCascDecayLength"), hyperonDecayLength); + histos.fill(HIST("OmOmBar/Omega/hV0InvMassWindow"), hyperon.mLambda() - o2::constants::physics::MassLambda0); + histos.fill(HIST("OmOmBar/Omega/hCascInvMassWindow"), hyperon.mOmega() - o2::constants::physics::MassOmegaMinus); + histos.fill(HIST("OmOmBar/Omega/h2dCompetingMassRej"), hyperon.mXi(), hyperon.mOmega()); + histos.fill(HIST("OmOmBar/Omega/hBachTPCNsigma"), bachTrackExtraHyperon.tpcNSigmaKa()); + histos.fill(HIST("OmOmBar/Omega/hPosTPCNsigma"), posTrackExtraHyperon.tpcNSigmaPr()); + histos.fill(HIST("OmOmBar/Omega/hNegTPCNsigma"), negTrackExtraHyperon.tpcNSigmaPi()); + histos.fill(HIST("OmOmBar/Omega/h2dBachelorITSvsTPCpts"), bachTrackExtraHyperon.tpcCrossedRows(), bachTrackExtraHyperon.itsNCls()); + histos.fill(HIST("OmOmBar/Omega/h2dPositiveITSvsTPCpts"), posTrackExtraHyperon.tpcCrossedRows(), posTrackExtraHyperon.itsNCls()); + histos.fill(HIST("OmOmBar/Omega/h2dNegativeITSvsTPCpts"), negTrackExtraHyperon.tpcCrossedRows(), negTrackExtraHyperon.itsNCls()); + // Candidates after AntiOmega selections + histos.fill(HIST("OmOmBar/AntiOmega/hBachDCAToPV"), antiHyperon.dcabachtopv()); + histos.fill(HIST("OmOmBar/AntiOmega/hPosDCAToPV"), antiHyperon.dcapostopv()); + histos.fill(HIST("OmOmBar/AntiOmega/hNegDCAToPV"), antiHyperon.dcanegtopv()); + histos.fill(HIST("OmOmBar/AntiOmega/hDCACascDaughters"), antiHyperon.dcacascdaughters()); + histos.fill(HIST("OmOmBar/AntiOmega/hDCAV0Daughters"), antiHyperon.dcaV0daughters()); + histos.fill(HIST("OmOmBar/AntiOmega/hDCAV0ToPV"), antiHyperon.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + histos.fill(HIST("OmOmBar/AntiOmega/hV0PointingAngle"), antiHyperon.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + histos.fill(HIST("OmOmBar/AntiOmega/hV0Radius"), antiHyperon.v0radius()); + histos.fill(HIST("OmOmBar/AntiOmega/hCascPointingAngle"), antiHyperon.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + histos.fill(HIST("OmOmBar/AntiOmega/hCascRadius"), antiHyperon.cascradius()); + histos.fill(HIST("OmOmBar/AntiOmega/hCascDecayLength"), antiHyperonDecayLength); + histos.fill(HIST("OmOmBar/AntiOmega/hV0InvMassWindow"), antiHyperon.mLambda() - o2::constants::physics::MassLambda0); + histos.fill(HIST("OmOmBar/AntiOmega/hCascInvMassWindow"), antiHyperon.mOmega() - o2::constants::physics::MassOmegaMinus); + histos.fill(HIST("OmOmBar/AntiOmega/h2dCompetingMassRej"), antiHyperon.mXi(), antiHyperon.mOmega()); + histos.fill(HIST("OmOmBar/AntiOmega/hBachTPCNsigma"), bachTrackExtraAntiHyperon.tpcNSigmaKa()); + histos.fill(HIST("OmOmBar/AntiOmega/hPosTPCNsigma"), posTrackExtraAntiHyperon.tpcNSigmaPi()); + histos.fill(HIST("OmOmBar/AntiOmega/hNegTPCNsigma"), negTrackExtraAntiHyperon.tpcNSigmaPr()); + histos.fill(HIST("OmOmBar/AntiOmega/h2dBachelorITSvsTPCpts"), bachTrackExtraAntiHyperon.tpcCrossedRows(), bachTrackExtraAntiHyperon.itsNCls()); + histos.fill(HIST("OmOmBar/AntiOmega/h2dPositiveITSvsTPCpts"), posTrackExtraAntiHyperon.tpcCrossedRows(), posTrackExtraAntiHyperon.itsNCls()); + histos.fill(HIST("OmOmBar/AntiOmega/h2dNegativeITSvsTPCpts"), negTrackExtraAntiHyperon.tpcCrossedRows(), negTrackExtraAntiHyperon.itsNCls()); + } + } + } + + template + void analyseHyperonPairCandidate(TCollision collision, THyperon hyperon, THyperon antiHyperon, float centrality, uint8_t gapSide, int type) + // fill information related to the quarkonium mother + // type = 0 (Lambda), 1 (Xi), 2 (Omega) + { + float pt = RecoDecay::pt(hyperon.px() + antiHyperon.px(), hyperon.py() + antiHyperon.py()); + + float invmass = -1; + if (type == 0) + invmass = RecoDecay::m(std::array{std::array{hyperon.px(), hyperon.py(), hyperon.pz()}, std::array{antiHyperon.px(), antiHyperon.py(), antiHyperon.pz()}}, std::array{o2::constants::physics::MassKaonNeutral, o2::constants::physics::MassKaonNeutral}); + if (type == 1) + invmass = RecoDecay::m(std::array{std::array{hyperon.px(), hyperon.py(), hyperon.pz()}, std::array{antiHyperon.px(), antiHyperon.py(), antiHyperon.pz()}}, std::array{o2::constants::physics::MassLambda0, o2::constants::physics::MassLambda0Bar}); + if (type == 2) + invmass = RecoDecay::m(std::array{std::array{hyperon.px(), hyperon.py(), hyperon.pz()}, std::array{antiHyperon.px(), antiHyperon.py(), antiHyperon.pz()}}, std::array{o2::constants::physics::MassXiMinus, o2::constants::physics::MassXiPlusBar}); + if (type == 3) + invmass = RecoDecay::m(std::array{std::array{hyperon.px(), hyperon.py(), hyperon.pz()}, std::array{antiHyperon.px(), antiHyperon.py(), antiHyperon.pz()}}, std::array{o2::constants::physics::MassOmegaMinus, o2::constants::physics::MassOmegaPlusBar}); + + float rapidity = RecoDecay::y(std::array{hyperon.px() + antiHyperon.px(), hyperon.py() + antiHyperon.py(), hyperon.pz() + antiHyperon.pz()}, invmass); + + // rapidity cut on the quarkonium mother + if (!doMCAssociation && std::fabs(rapidity) > rapidityCut) + return; + + // fillV0sInfo(lambda, antiLambda, centrality); + + // __________________________________________ + // main analysis + if (type == 0) { + if (doMCAssociation) { + if constexpr (requires { hyperon.template v0MCCore_as>(); }) { // check if MC information is available + auto hyperonMC = hyperon.template v0MCCore_as>(); + auto antiHyperonMC = antiHyperon.template v0MCCore_as>(); + + if (hyperonMC.pdgCodeMother() != antiHyperonMC.pdgCodeMother()) { + return; + } + + float ptmc = RecoDecay::pt(hyperonMC.pxMC() + antiHyperonMC.pxMC(), hyperonMC.pyMC() + antiHyperonMC.pyMC()); + float rapiditymc = RecoDecay::y(std::array{hyperonMC.pxMC() + antiHyperonMC.pxMC(), hyperonMC.pyMC() + antiHyperonMC.pyMC(), hyperonMC.pzMC() + antiHyperonMC.pzMC()}, pdgDB->Mass(hyperonMC.pdgCodeMother())); + + if (std::fabs(rapiditymc) > rapidityCut) + return; + + if (hyperonMC.pdgCodeMother() == 441 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // EtaC(1S) + histos.fill(HIST("K0sK0s/h3dInvMassTrueEtaC1S"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 443 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // J/psi + histos.fill(HIST("K0sK0s/h3dInvMassTrueJPsi"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 10441 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // ChiC0 + histos.fill(HIST("K0sK0s/h3dInvMassTrueChiC0"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 20443 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // ChiC1 + histos.fill(HIST("K0sK0s/h3dInvMassTrueChiC1"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 10443 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // hC + histos.fill(HIST("K0sK0s/h3dInvMassTrueHC"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 445 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // ChiC2 + histos.fill(HIST("K0sK0s/h3dInvMassTrueChiC2"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 100441 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // EtaC(2S) + histos.fill(HIST("K0sK0s/h3dInvMassTrueEtaC2S"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 100443 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // Psi(2S) + histos.fill(HIST("K0sK0s/h3dInvMassTruePsi2S"), centrality, ptmc, invmass); + } + } + } + + histos.fill(HIST("K0sK0s/h3dMassK0sK0s"), centrality, pt, invmass); + if (!isPP) { // in case of PbPb data + if (gapSide == 0) + histos.fill(HIST("K0sK0s/h3dMassK0sK0sSGA"), centrality, pt, invmass); + else if (gapSide == 1) + histos.fill(HIST("K0sK0s/h3dMassK0sK0sSGC"), centrality, pt, invmass); + else if (gapSide == 2) + histos.fill(HIST("K0sK0s/h3dMassK0sK0sDG"), centrality, pt, invmass); + else + histos.fill(HIST("K0sK0s/h3dMassK0sK0sHadronic"), centrality, pt, invmass); + } + fillQAplot(collision, hyperon, antiHyperon, type); + } + if (type == 1) { + if (doMCAssociation) { + if constexpr (requires { hyperon.template v0MCCore_as>(); }) { // check if MC information is available + auto hyperonMC = hyperon.template v0MCCore_as>(); + auto antiHyperonMC = antiHyperon.template v0MCCore_as>(); + + if (hyperonMC.pdgCodeMother() != antiHyperonMC.pdgCodeMother()) { + return; + } + + float ptmc = RecoDecay::pt(hyperonMC.pxMC() + antiHyperonMC.pxMC(), hyperonMC.pyMC() + antiHyperonMC.pyMC()); + float rapiditymc = RecoDecay::y(std::array{hyperonMC.pxMC() + antiHyperonMC.pxMC(), hyperonMC.pyMC() + antiHyperonMC.pyMC(), hyperonMC.pzMC() + antiHyperonMC.pzMC()}, pdgDB->Mass(hyperonMC.pdgCodeMother())); + + if (std::fabs(rapiditymc) > rapidityCut) + return; + + if (hyperonMC.pdgCodeMother() == 441 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // EtaC(1S) + histos.fill(HIST("LaLaBar/h3dInvMassTrueEtaC1S"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 443 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // J/psi + histos.fill(HIST("LaLaBar/h3dInvMassTrueJPsi"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 10441 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // ChiC0 + histos.fill(HIST("LaLaBar/h3dInvMassTrueChiC0"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 20443 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // ChiC1 + histos.fill(HIST("LaLaBar/h3dInvMassTrueChiC1"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 10443 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // hC + histos.fill(HIST("LaLaBar/h3dInvMassTrueHC"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 445 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // ChiC2 + histos.fill(HIST("LaLaBar/h3dInvMassTrueChiC2"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 100441 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // EtaC(2S) + histos.fill(HIST("LaLaBar/h3dInvMassTrueEtaC2S"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 100443 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // Psi(2S) + histos.fill(HIST("LaLaBar/h3dInvMassTruePsi2S"), centrality, ptmc, invmass); + } + } + } + + histos.fill(HIST("LaLaBar/h3dMassLaLabar"), centrality, pt, invmass); + if (!isPP) { // in case of PbPb data + if (gapSide == 0) + histos.fill(HIST("LaLaBar/h3dMassLaLabarSGA"), centrality, pt, invmass); + else if (gapSide == 1) + histos.fill(HIST("LaLaBar/h3dMassLaLabarSGC"), centrality, pt, invmass); + else if (gapSide == 2) + histos.fill(HIST("LaLaBar/h3dMassLaLabarDG"), centrality, pt, invmass); + else + histos.fill(HIST("LaLaBar/h3dMassLaLabarHadronic"), centrality, pt, invmass); + } + fillQAplot(collision, hyperon, antiHyperon, type); + } + if (type == 2) { + if (doMCAssociation) { + if constexpr (requires { hyperon.template cascMCCore_as>(); }) { // check if MC information is available + auto hyperonMC = hyperon.template cascMCCore_as>(); + auto antiHyperonMC = antiHyperon.template cascMCCore_as>(); + + if (hyperonMC.pdgCodeMother() != antiHyperonMC.pdgCodeMother()) { + return; + } + + float ptmc = RecoDecay::pt(hyperonMC.pxMC() + antiHyperonMC.pxMC(), hyperonMC.pyMC() + antiHyperonMC.pyMC()); + float rapiditymc = RecoDecay::y(std::array{hyperonMC.pxMC() + antiHyperonMC.pxMC(), hyperonMC.pyMC() + antiHyperonMC.pyMC(), hyperonMC.pzMC() + antiHyperonMC.pzMC()}, pdgDB->Mass(hyperonMC.pdgCodeMother())); + + if (std::fabs(rapiditymc) > rapidityCut) + return; + + if (hyperonMC.pdgCodeMother() == 441 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // EtaC(1S) + histos.fill(HIST("XiXiBar/h3dInvMassTrueEtaC1S"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 443 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // J/psi + histos.fill(HIST("XiXiBar/h3dInvMassTrueJPsi"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 10441 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // ChiC0 + histos.fill(HIST("XiXiBar/h3dInvMassTrueChiC0"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 20443 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // ChiC1 + histos.fill(HIST("XiXiBar/h3dInvMassTrueChiC1"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 10443 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // hC + histos.fill(HIST("XiXiBar/h3dInvMassTrueHC"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 445 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // ChiC2 + histos.fill(HIST("XiXiBar/h3dInvMassTrueChiC2"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 100441 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // EtaC(2S) + histos.fill(HIST("XiXiBar/h3dInvMassTrueEtaC2S"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 100443 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // Psi(2S) + histos.fill(HIST("XiXiBar/h3dInvMassTruePsi2S"), centrality, ptmc, invmass); + } + } + } + + histos.fill(HIST("XiXiBar/h3dMassXiXibar"), centrality, pt, invmass); + if (!isPP) { // in case of PbPb data + if (gapSide == 0) + histos.fill(HIST("XiXiBar/h3dMassXiXibarSGA"), centrality, pt, invmass); + else if (gapSide == 1) + histos.fill(HIST("XiXiBar/h3dMassXiXibarSGC"), centrality, pt, invmass); + else if (gapSide == 2) + histos.fill(HIST("XiXiBar/h3dMassXiXibarDG"), centrality, pt, invmass); + else + histos.fill(HIST("XiXiBar/h3dMassXiXibarHadronic"), centrality, pt, invmass); + } + fillQAplot(collision, hyperon, antiHyperon, type); + } + if (type == 3) { + if (doMCAssociation) { + if constexpr (requires { hyperon.template cascMCCore_as>(); }) { // check if MC information is available + auto hyperonMC = hyperon.template cascMCCore_as>(); + auto antiHyperonMC = antiHyperon.template cascMCCore_as>(); + + if (hyperonMC.pdgCodeMother() != antiHyperonMC.pdgCodeMother()) { + return; + } + + float ptmc = RecoDecay::pt(hyperonMC.pxMC() + antiHyperonMC.pxMC(), hyperonMC.pyMC() + antiHyperonMC.pyMC()); + float rapiditymc = RecoDecay::y(std::array{hyperonMC.pxMC() + antiHyperonMC.pxMC(), hyperonMC.pyMC() + antiHyperonMC.pyMC(), hyperonMC.pzMC() + antiHyperonMC.pzMC()}, pdgDB->Mass(hyperonMC.pdgCodeMother())); + + if (std::fabs(rapiditymc) > rapidityCut) + return; + + if (hyperonMC.pdgCodeMother() == 100441 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // EtaC(2S) + histos.fill(HIST("OmOmBar/h3dInvMassTrueEtaC2S"), centrality, ptmc, invmass); + } + if (hyperonMC.pdgCodeMother() == 100443 && hyperonMC.pdgCodeMother() == antiHyperonMC.pdgCodeMother()) { // Psi(2S) + histos.fill(HIST("OmOmBar/h3dInvMassTruePsi2S"), centrality, ptmc, invmass); + } + } + } + + histos.fill(HIST("OmOmBar/h3dMassOmOmbar"), centrality, pt, invmass); + if (!isPP) { // in case of PbPb data + if (gapSide == 0) + histos.fill(HIST("OmOmBar/h3dMassOmOmbarSGA"), centrality, pt, invmass); + else if (gapSide == 1) + histos.fill(HIST("OmOmBar/h3dMassOmOmbarSGC"), centrality, pt, invmass); + else if (gapSide == 2) + histos.fill(HIST("OmOmBar/h3dMassOmOmbarDG"), centrality, pt, invmass); + else + histos.fill(HIST("OmOmBar/h3dMassOmOmbarHadronic"), centrality, pt, invmass); + } + fillQAplot(collision, hyperon, antiHyperon, type); + } + } + + // function to check that the hyperon and antihyperon have different daughter tracks + template + bool checkTrackIndices(THyperon hyperon, THyperon antiHyperon) + { + if constexpr (requires { hyperon.template bachTrackExtra_as(); }) { // cascade case: check if bachelor information is available + // check that bachelor track from hyperon is different from daughter tracks of antiHyperon + if (hyperon.bachTrackExtraId() == antiHyperon.bachTrackExtraId() || + hyperon.bachTrackExtraId() == antiHyperon.posTrackExtraId() || + hyperon.bachTrackExtraId() == antiHyperon.negTrackExtraId()) + return false; + // check that positive track from hyperon is different from daughter tracks of antiHyperon + if (hyperon.posTrackExtraId() == antiHyperon.bachTrackExtraId() || + hyperon.posTrackExtraId() == antiHyperon.posTrackExtraId() || + hyperon.posTrackExtraId() == antiHyperon.negTrackExtraId()) + return false; + // check that negative track from hyperon is different from daughter tracks of antiHyperon + if (hyperon.negTrackExtraId() == antiHyperon.bachTrackExtraId() || + hyperon.negTrackExtraId() == antiHyperon.posTrackExtraId() || + hyperon.negTrackExtraId() == antiHyperon.negTrackExtraId()) + return false; + } else { // v0 case + // check that positive track from hyperon is different from daughter tracks of antiHyperon + if (hyperon.posTrackExtraId() == antiHyperon.posTrackExtraId() || + hyperon.posTrackExtraId() == antiHyperon.negTrackExtraId()) + return false; + // check that negative track from hyperon is different from daughter tracks of antiHyperon + if (hyperon.negTrackExtraId() == antiHyperon.posTrackExtraId() || + hyperon.negTrackExtraId() == antiHyperon.negTrackExtraId()) + return false; + } + return true; + } + + template + void buildHyperonAntiHyperonPairs(TCollision const& collision, THyperons const& fullHyperons, std::vector selHypIndices, std::vector selAntiHypIndices, float centrality, uint8_t gapSide, int type) + { + // 1st loop over all v0s/cascades + for (const auto& hyperon : fullHyperons) { + // select only v0s matching Lambda selections + if (!selHypIndices[hyperon.globalIndex() - fullHyperons.offset()]) { // local index needed due to collisions grouping + continue; + } + + // 2nd loop over all v0s/cascade + for (const auto& antiHyperon : fullHyperons) { + // select only v0s matching Anti-Lambda selections + if (!selAntiHypIndices[antiHyperon.globalIndex() - fullHyperons.offset()]) { // local index needed due to collisions grouping + continue; + } + + // check we don't look at the same v0s/cascades + if (hyperon.globalIndex() == antiHyperon.globalIndex()) { + continue; + } + + // check that the two hyperons have different daughter tracks + if (!checkTrackIndices(hyperon, antiHyperon)) { + continue; + } + + // form V0 pairs and fill histograms + analyseHyperonPairCandidate(collision, hyperon, antiHyperon, centrality, gapSide, type); + } // end antiHyperon loop + } // end hyperon loop + + return; + } + + // ______________________________________________________ + // Real data processing - no MC subscription + void processRealData(soa::Join::iterator const& collision, V0Candidates const& fullV0s, CascadeCandidates const& fullCascades, DauTracks const&) + { + // Fire up CCDB + if (cfgSkimmedProcessing || + (mlConfigurations.useK0ShortScores && mlConfigurations.calculateK0ShortScores) || + (mlConfigurations.useLambdaScores && mlConfigurations.calculateLambdaScores) || + (mlConfigurations.useAntiLambdaScores && mlConfigurations.calculateAntiLambdaScores)) { + initCCDB(collision); + } + + if (!isEventAccepted(collision, true)) { + return; + } + + if (cfgSkimmedProcessing) { + zorro.isSelected(collision.globalBC()); /// Just let Zorro do the accounting + } + + float centrality = -1; + int selGapSide = -1; // only useful in case one wants to use this task in Pb-Pb UPC + fillEventHistograms(collision, centrality, selGapSide); + + // __________________________________________ + // perform main analysis + // + if (buildK0sK0sPairs || buildLaLaBarPairs) { // Look at V0s + std::vector selK0ShortIndices(fullV0s.size()); + std::vector selLambdaIndices(fullV0s.size()); + std::vector selAntiLambdaIndices(fullV0s.size()); + for (const auto& v0 : fullV0s) { + if (std::abs(v0.negativeeta()) > v0Selections.daughterEtaCut || std::abs(v0.positiveeta()) > v0Selections.daughterEtaCut) + continue; // remove acceptance that's badly reproduced by MC / superfluous in future + + if (v0.v0Type() != v0Selections.v0TypeSelection && v0Selections.v0TypeSelection > -1) + continue; // skip V0s that are not standard + + uint64_t selMap = computeReconstructionBitmap(v0, collision, v0.yLambda(), v0.yK0Short(), v0.pt()); + + // consider for histograms for all species + selMap = selMap | (static_cast(1) << selConsiderK0Short) | (static_cast(1) << selConsiderLambda) | (static_cast(1) << selConsiderAntiLambda); + selMap = selMap | (static_cast(1) << selPhysPrimK0Short) | (static_cast(1) << selPhysPrimLambda) | (static_cast(1) << selPhysPrimAntiLambda); + + analyseV0Candidate(v0, v0.pt(), selMap, selK0ShortIndices, selLambdaIndices, selAntiLambdaIndices, fullV0s.offset()); + } // end v0 loop + + // count the number of K0s, Lambda and AntiLambdas passsing the selections + int nK0Shorts = std::count(selK0ShortIndices.begin(), selK0ShortIndices.end(), true); + int nLambdas = std::count(selLambdaIndices.begin(), selLambdaIndices.end(), true); + int nAntiLambdas = std::count(selAntiLambdaIndices.begin(), selAntiLambdaIndices.end(), true); + + if (buildK0sK0sPairs) { + // fill the histograms with the number of reconstructed K0s/Lambda/antiLambda per collision + histos.fill(HIST("K0sK0s/h2dNbrOfK0ShortVsCentrality"), centrality, nK0Shorts); + + // Check the number of K0Short + // needs at least 2 to form K0s-K0s pairs + if (nK0Shorts >= 2) { // consider K0s K0s pairs + buildHyperonAntiHyperonPairs(collision, fullV0s, selK0ShortIndices, selK0ShortIndices, centrality, selGapSide, 0); + } + } + + if (buildLaLaBarPairs) { + // fill the histograms with the number of reconstructed K0s/Lambda/antiLambda per collision + histos.fill(HIST("LaLaBar/h2dNbrOfLambdaVsCentrality"), centrality, nLambdas); + histos.fill(HIST("LaLaBar/h2dNbrOfAntiLambdaVsCentrality"), centrality, nAntiLambdas); + + // Check the number of Lambdas and antiLambdas + // needs at least 1 of each + if (!buildSameSignPairs && nLambdas >= 1 && nAntiLambdas >= 1) { // consider Lambda antiLambda pairs + buildHyperonAntiHyperonPairs(collision, fullV0s, selLambdaIndices, selAntiLambdaIndices, centrality, selGapSide, 1); + } + if (buildSameSignPairs && nLambdas > 1) { // consider Lambda Lambda pairs + buildHyperonAntiHyperonPairs(collision, fullV0s, selLambdaIndices, selLambdaIndices, centrality, selGapSide, 1); + } + if (buildSameSignPairs && nAntiLambdas > 1) { // consider antiLambda antiLambda pairs + buildHyperonAntiHyperonPairs(collision, fullV0s, selAntiLambdaIndices, selAntiLambdaIndices, centrality, selGapSide, 1); + } + } + } + + if (buildXiXiBarPairs || buildOmOmBarPairs) { // Look at Cascades + std::vector selXiIndices(fullCascades.size()); + std::vector selAntiXiIndices(fullCascades.size()); + std::vector selOmIndices(fullCascades.size()); + std::vector selAntiOmIndices(fullCascades.size()); + for (const auto& cascade : fullCascades) { + if (std::abs(cascade.negativeeta()) > cascSelections.daughterEtaCut || + std::abs(cascade.positiveeta()) > cascSelections.daughterEtaCut || + std::abs(cascade.bacheloreta()) > cascSelections.daughterEtaCut) + continue; // remove acceptance that's badly reproduced by MC / superfluous in future + + if (buildXiXiBarPairs) { + if (cascade.sign() < 0) { + selXiIndices[cascade.globalIndex() - fullCascades.offset()] = isCascadeSelected(cascade, collision, cascade.yXi(), true); + } else { + selAntiXiIndices[cascade.globalIndex() - fullCascades.offset()] = isCascadeSelected(cascade, collision, cascade.yXi(), true); + } + } + if (buildOmOmBarPairs) { + if (cascade.sign() < 0) { + selOmIndices[cascade.globalIndex() - fullCascades.offset()] = isCascadeSelected(cascade, collision, cascade.yOmega(), false); + } else { + selAntiOmIndices[cascade.globalIndex() - fullCascades.offset()] = isCascadeSelected(cascade, collision, cascade.yOmega(), false); + } + } + } // end cascade loop + + // count the number of Xi and antiXi passsing the selections + int nXis = std::count(selXiIndices.begin(), selXiIndices.end(), true); + int nAntiXis = std::count(selAntiXiIndices.begin(), selAntiXiIndices.end(), true); + int nOmegas = std::count(selOmIndices.begin(), selOmIndices.end(), true); + int nAntiOmegas = std::count(selAntiOmIndices.begin(), selAntiOmIndices.end(), true); + + // fill the histograms with the number of reconstructed K0s/Lambda/antiLambda per collision + if (buildXiXiBarPairs) { + histos.fill(HIST("XiXiBar/h2dNbrOfXiVsCentrality"), centrality, nXis); + histos.fill(HIST("XiXiBar/h2dNbrOfAntiXiVsCentrality"), centrality, nAntiXis); + + // Check the number of Lambdas and antiLambdas + // needs at least 1 of each + if (!buildSameSignPairs && nXis >= 1 && nAntiXis >= 1) { + buildHyperonAntiHyperonPairs(collision, fullCascades, selXiIndices, selAntiXiIndices, centrality, selGapSide, 2); + } + if (buildSameSignPairs && nXis > 1) { + buildHyperonAntiHyperonPairs(collision, fullCascades, selXiIndices, selXiIndices, centrality, selGapSide, 2); + } + if (buildSameSignPairs && nAntiXis > 1) { + buildHyperonAntiHyperonPairs(collision, fullCascades, selAntiXiIndices, selAntiXiIndices, centrality, selGapSide, 2); + } + } + if (buildOmOmBarPairs) { + histos.fill(HIST("OmOmBar/h2dNbrOfOmegaVsCentrality"), centrality, nOmegas); + histos.fill(HIST("OmOmBar/h2dNbrOfAntiOmegaVsCentrality"), centrality, nAntiOmegas); + + // Check the number of Lambdas and antiLambdas + // needs at least 1 of each + if (!buildSameSignPairs && nOmegas >= 1 && nAntiOmegas >= 1) { + buildHyperonAntiHyperonPairs(collision, fullCascades, selOmIndices, selAntiOmIndices, centrality, selGapSide, 3); + } + if (buildSameSignPairs && nOmegas > 1) { + buildHyperonAntiHyperonPairs(collision, fullCascades, selOmIndices, selOmIndices, centrality, selGapSide, 3); + } + if (buildSameSignPairs && nAntiOmegas > 1) { + buildHyperonAntiHyperonPairs(collision, fullCascades, selAntiOmIndices, selAntiOmIndices, centrality, selGapSide, 3); + } + } + } + } + + // ______________________________________________________ + // Simulated processing (subscribes to MC information too) + void processMonteCarlo(soa::Join::iterator const& collision, V0MCCandidates const& fullV0s, CascadeMCCandidates const& fullCascades, DauTracks const&, aod::MotherMCParts const&, soa::Join const& /*mccollisions*/, soa::Join const&, soa::Join const&) + { + // Fire up CCDB + if (cfgSkimmedProcessing || + (mlConfigurations.useK0ShortScores && mlConfigurations.calculateK0ShortScores) || + (mlConfigurations.useLambdaScores && mlConfigurations.calculateLambdaScores) || + (mlConfigurations.useAntiLambdaScores && mlConfigurations.calculateAntiLambdaScores)) { + initCCDB(collision); + } + + if (!isEventAccepted(collision, true)) { + return; + } + + if (cfgSkimmedProcessing) { + zorro.isSelected(collision.globalBC()); /// Just let Zorro do the accounting + } + + float centrality = -1; + int selGapSide = -1; // only useful in case one wants to use this task in Pb-Pb UPC + fillEventHistograms(collision, centrality, selGapSide); + + // __________________________________________ + // perform main analysis + if (buildK0sK0sPairs || buildLaLaBarPairs) { // Look at V0s + std::vector selK0ShortIndices(fullV0s.size()); + std::vector selLambdaIndices(fullV0s.size()); + std::vector selAntiLambdaIndices(fullV0s.size()); + for (const auto& v0 : fullV0s) { + if (std::abs(v0.negativeeta()) > v0Selections.daughterEtaCut || std::abs(v0.positiveeta()) > v0Selections.daughterEtaCut) + continue; // remove acceptance that's badly reproduced by MC / superfluous in future + + if (!v0.has_v0MCCore()) + continue; + + auto v0MC = v0.v0MCCore_as>(); + + float ptmc = RecoDecay::sqrtSumOfSquares(v0MC.pxPosMC() + v0MC.pxNegMC(), v0MC.pyPosMC() + v0MC.pyNegMC()); + float ymc = 1e-3; + if (v0MC.pdgCode() == 310) + ymc = RecoDecay::y(std::array{v0MC.pxPosMC() + v0MC.pxNegMC(), v0MC.pyPosMC() + v0MC.pyNegMC(), v0MC.pzPosMC() + v0MC.pzNegMC()}, o2::constants::physics::MassKaonNeutral); + else if (std::fabs(v0MC.pdgCode()) == 3122) + ymc = RecoDecay::y(std::array{v0MC.pxPosMC() + v0MC.pxNegMC(), v0MC.pyPosMC() + v0MC.pyNegMC(), v0MC.pzPosMC() + v0MC.pzNegMC()}, o2::constants::physics::MassLambda); + + uint64_t selMap = computeReconstructionBitmap(v0, collision, ymc, ymc, ptmc); + selMap = selMap | computeMCAssociation(v0MC); + + // consider only associated candidates if asked to do so, disregard association + if (!doMCAssociation) { + selMap = selMap | (static_cast(1) << selConsiderK0Short) | (static_cast(1) << selConsiderLambda) | (static_cast(1) << selConsiderAntiLambda); + selMap = selMap | (static_cast(1) << selPhysPrimK0Short) | (static_cast(1) << selPhysPrimLambda) | (static_cast(1) << selPhysPrimAntiLambda); + } + + analyseV0Candidate(v0, ptmc, selMap, selK0ShortIndices, selLambdaIndices, selAntiLambdaIndices, fullV0s.offset()); + } // end v0 loop + + /// count the number of K0s, Lambda and AntiLambdas passsing the selections + int nK0Shorts = std::count(selK0ShortIndices.begin(), selK0ShortIndices.end(), true); + int nLambdas = std::count(selLambdaIndices.begin(), selLambdaIndices.end(), true); + int nAntiLambdas = std::count(selAntiLambdaIndices.begin(), selAntiLambdaIndices.end(), true); + + if (buildK0sK0sPairs) { + // fill the histograms with the number of reconstructed K0s/Lambda/antiLambda per collision + histos.fill(HIST("K0sK0s/h2dNbrOfK0ShortVsCentrality"), centrality, nK0Shorts); + + // Check the number of K0Short + // needs at least 2 to form K0s-K0s pairs + if (nK0Shorts >= 2) { // consider K0s K0s pairs + buildHyperonAntiHyperonPairs(collision, fullV0s, selK0ShortIndices, selK0ShortIndices, centrality, selGapSide, 0); + } + } + + if (buildLaLaBarPairs) { + // fill the histograms with the number of reconstructed Lambda/antiLambda per collision + histos.fill(HIST("LaLaBar/h2dNbrOfLambdaVsCentrality"), centrality, nLambdas); + histos.fill(HIST("LaLaBar/h2dNbrOfAntiLambdaVsCentrality"), centrality, nAntiLambdas); + + if (!buildSameSignPairs && nLambdas >= 1 && nAntiLambdas >= 1) { // consider Lambda antiLambda pairs + buildHyperonAntiHyperonPairs(collision, fullV0s, selLambdaIndices, selAntiLambdaIndices, centrality, selGapSide, 1); + } + if (buildSameSignPairs && nLambdas > 1) { // consider Lambda Lambda pairs + buildHyperonAntiHyperonPairs(collision, fullV0s, selLambdaIndices, selLambdaIndices, centrality, selGapSide, 1); + } + if (buildSameSignPairs && nAntiLambdas > 1) { // consider antiLambda antiLambda pairs + buildHyperonAntiHyperonPairs(collision, fullV0s, selAntiLambdaIndices, selAntiLambdaIndices, centrality, selGapSide, 1); + } + } + } + + if (buildXiXiBarPairs || buildOmOmBarPairs) { // Look at Cascades + std::vector selXiIndices(fullCascades.size()); + std::vector selAntiXiIndices(fullCascades.size()); + std::vector selOmIndices(fullCascades.size()); + std::vector selAntiOmIndices(fullCascades.size()); + for (const auto& cascade : fullCascades) { + if (std::abs(cascade.negativeeta()) > cascSelections.daughterEtaCut || + std::abs(cascade.positiveeta()) > cascSelections.daughterEtaCut || + std::abs(cascade.bacheloreta()) > cascSelections.daughterEtaCut) + continue; // remove acceptance that's badly reproduced by MC / superfluous in future + + if (!cascade.has_cascMCCore()) + continue; + + auto cascadeMC = cascade.cascMCCore_as>(); + + float ymc = 1e-3; + if (std::fabs(cascadeMC.pdgCode()) == 3312) + ymc = RecoDecay::y(std::array{cascadeMC.pxMC(), cascadeMC.pyMC(), cascadeMC.pzMC()}, o2::constants::physics::MassXiMinus); + else if (std::fabs(cascadeMC.pdgCode()) == 3334) + ymc = RecoDecay::y(std::array{cascadeMC.pxMC(), cascadeMC.pyMC(), cascadeMC.pzMC()}, o2::constants::physics::MassOmegaMinus); + + if (buildXiXiBarPairs) { + if (cascade.sign() < 0) { + selXiIndices[cascade.globalIndex() - fullCascades.offset()] = isCascadeSelected(cascade, collision, ymc, true); + } else { + selAntiXiIndices[cascade.globalIndex() - fullCascades.offset()] = isCascadeSelected(cascade, collision, ymc, true); + } + } + if (buildOmOmBarPairs) { + if (cascade.sign() < 0) { + selOmIndices[cascade.globalIndex() - fullCascades.offset()] = isCascadeSelected(cascade, collision, ymc, false); + } else { + selAntiOmIndices[cascade.globalIndex() - fullCascades.offset()] = isCascadeSelected(cascade, collision, ymc, false); + } + } + } // end cascade loop + + // count the number of Xi and antiXi passsing the selections + int nXis = std::count(selXiIndices.begin(), selXiIndices.end(), true); + int nAntiXis = std::count(selAntiXiIndices.begin(), selAntiXiIndices.end(), true); + int nOmegas = std::count(selOmIndices.begin(), selOmIndices.end(), true); + int nAntiOmegas = std::count(selAntiOmIndices.begin(), selAntiOmIndices.end(), true); + + // fill the histograms with the number of reconstructed K0s/Lambda/antiLambda per collision + if (buildXiXiBarPairs) { + histos.fill(HIST("XiXiBar/h2dNbrOfXiVsCentrality"), centrality, nXis); + histos.fill(HIST("XiXiBar/h2dNbrOfAntiXiVsCentrality"), centrality, nAntiXis); + + // Check the number of Lambdas and antiLambdas + // needs at least 1 of each + if (!buildSameSignPairs && nXis >= 1 && nAntiXis >= 1) { + buildHyperonAntiHyperonPairs(collision, fullCascades, selXiIndices, selAntiXiIndices, centrality, selGapSide, 2); + } + if (buildSameSignPairs && nXis > 1) { + buildHyperonAntiHyperonPairs(collision, fullCascades, selXiIndices, selXiIndices, centrality, selGapSide, 2); + } + if (buildSameSignPairs && nAntiXis > 1) { + buildHyperonAntiHyperonPairs(collision, fullCascades, selAntiXiIndices, selAntiXiIndices, centrality, selGapSide, 2); + } + } + if (buildOmOmBarPairs) { + histos.fill(HIST("OmOmBar/h2dNbrOfOmegaVsCentrality"), centrality, nOmegas); + histos.fill(HIST("OmOmBar/h2dNbrOfAntiOmegaVsCentrality"), centrality, nAntiOmegas); + + // Check the number of Lambdas and antiLambdas + // needs at least 1 of each + if (!buildSameSignPairs && nOmegas >= 1 && nAntiOmegas >= 1) { + buildHyperonAntiHyperonPairs(collision, fullCascades, selOmIndices, selAntiOmIndices, centrality, selGapSide, 3); + } + if (buildSameSignPairs && nOmegas > 1) { + buildHyperonAntiHyperonPairs(collision, fullCascades, selOmIndices, selOmIndices, centrality, selGapSide, 3); + } + if (buildSameSignPairs && nAntiOmegas > 1) { + buildHyperonAntiHyperonPairs(collision, fullCascades, selAntiOmIndices, selAntiOmIndices, centrality, selGapSide, 3); + } + } + } + } + + PROCESS_SWITCH(QuarkoniaToHyperons, processRealData, "process as if real data", true); + PROCESS_SWITCH(QuarkoniaToHyperons, processMonteCarlo, "process as if MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGDQ/Tasks/tableReader.cxx b/PWGDQ/Tasks/tableReader.cxx index 054f7233a03..2249aba8163 100644 --- a/PWGDQ/Tasks/tableReader.cxx +++ b/PWGDQ/Tasks/tableReader.cxx @@ -14,6 +14,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -39,6 +42,8 @@ #include "TGeoGlobalMagField.h" #include "DetectorsBase/Propagator.h" #include "DetectorsBase/GeometryManager.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "Common/CCDB/EventSelectionParams.h" using std::cout; using std::endl; @@ -86,18 +91,25 @@ DECLARE_SOA_TABLE(BmesonCandidates, "AOD", "DQBMESONS", dqanalysisflags::massBca // Declarations of various short names using MyEvents = soa::Join; +using MyEventsMultExtra = soa::Join; using MyEventsSelected = soa::Join; using MyEventsHashSelected = soa::Join; using MyEventsVtxCov = soa::Join; using MyEventsVtxCovSelected = soa::Join; +using MyEventsVtxCovSelectedMultExtra = soa::Join; using MyEventsVtxCovSelectedQvector = soa::Join; -using MyEventsVtxCovSelectedQvectorExtra = soa::Join; +using MyEventsVtxCovQvectorExtraWithRefFlow = soa::Join; +using MyEventsVtxCovSelectedQvectorExtraWithRefFlow = soa::Join; using MyEventsVtxCovSelectedQvectorCentr = soa::Join; using MyEventsQvector = soa::Join; +using MyEventsQvectorMultExtra = soa::Join; +using MyEventsQvectorCentr = soa::Join; +using MyEventsQvectorCentrMultExtra = soa::Join; using MyEventsQvectorExtra = soa::Join; using MyEventsHashSelectedQvector = soa::Join; -using MyEventsHashSelectedQvectorExtra = soa::Join; +using MyEventsHashSelectedQvectorExtra = soa::Join; using MyEventsHashSelectedQvectorCentr = soa::Join; +using MyEventsVtxCovQvectorMultExtraWithRefFlow = soa::Join; using MyBarrelTracks = soa::Join; using MyBarrelTracksWithCov = soa::Join; @@ -117,9 +129,13 @@ using MyMftTracks = soa::Join; constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended; constexpr static uint32_t gkEventFillMapWithCov = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov; constexpr static uint32_t gkEventFillMapWithQvector = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventQvector; +constexpr static uint32_t gkEventFillMapWithMultExtra = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventMultExtra; +constexpr static uint32_t gkEventFillMapWithQvectorMultExtra = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventQvector | VarManager::ObjTypes::ReducedEventMultExtra; constexpr static uint32_t gkEventFillMapWithQvectorCentr = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::CollisionQvect; +constexpr static uint32_t gkEventFillMapWithQvectorCentrMultExtra = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::CollisionQvect | VarManager::ObjTypes::ReducedEventMultExtra; constexpr static uint32_t gkEventFillMapWithCovQvector = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov | VarManager::ObjTypes::ReducedEventQvector; -constexpr static uint32_t gkEventFillMapWithCovQvectorExtra = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov | VarManager::ObjTypes::ReducedEventQvector | VarManager::ObjTypes::ReducedEventQvectorExtra; +constexpr static uint32_t gkEventFillMapWithCovQvectorExtraWithRefFlow = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov | VarManager::ObjTypes::ReducedEventQvector | VarManager::ObjTypes::ReducedEventQvectorExtra | VarManager::ObjTypes::ReducedEventRefFlow; +constexpr static uint32_t gkEventFillMapWithCovQvectorMultExtraWithRefFlow = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov | VarManager::ObjTypes::ReducedEventQvector | VarManager::ObjTypes::ReducedEventQvectorExtra | VarManager::ObjTypes::ReducedEventRefFlow | VarManager::ObjTypes::ReducedEventMultExtra; constexpr static uint32_t gkEventFillMapWithCovQvectorCentr = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov | VarManager::ObjTypes::CollisionQvect; constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelPID; constexpr static uint32_t gkTrackFillMapWithCov = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID; @@ -144,14 +160,25 @@ struct AnalysisEventSelection { Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigRunZorro{"cfgRunZorro", false, "Enable event selection with zorro [WARNING: under debug, do not enable!]"}; + Configurable fConfigITSROFrameStartBorderMargin{"ITSROFrameStartBorderMargin", -1, "Number of bcs at the start of ITS RO Frame border. Take from CCDB if -1"}; + Configurable fConfigITSROFrameEndBorderMargin{"ITSROFrameEndBorderMargin", -1, "Number of bcs at the end of ITS RO Frame border. Take from CCDB if -1"}; Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; HistogramManager* fHistMan = nullptr; MixingHandler* fMixHandler = nullptr; AnalysisCompositeCut* fEventCut; + int fLastRun; + + Service fCCDB; - void init(o2::framework::InitContext&) + void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + fEventCut = new AnalysisCompositeCut(true); TString eventCutStr = fConfigEventCuts.value; fEventCut->AddCut(dqcuts::GetAnalysisCut(eventCutStr.Data())); @@ -176,11 +203,29 @@ struct AnalysisEventSelection { dqmixing::SetUpMixing(fMixHandler, objArray->At(iVar)->GetName()); } } + + // CCDB configuration + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + // Not later than now objects + // fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); + + fLastRun = -1; } template void runEventSelection(TEvent const& event) { + if (event.runNumber() != fLastRun) { + auto alppar = fCCDB->getForTimeStamp>("ITS/Config/AlpideParam", event.timestamp()); + EventSelectionParams* par = fCCDB->getForTimeStamp("EventSelection/EventSelectionParams", event.timestamp()); + int itsROFrameStartBorderMargin = fConfigITSROFrameStartBorderMargin < 0 ? par->fITSROFrameStartBorderMargin : fConfigITSROFrameStartBorderMargin; + int itsROFrameEndBorderMargin = fConfigITSROFrameEndBorderMargin < 0 ? par->fITSROFrameEndBorderMargin : fConfigITSROFrameEndBorderMargin; + VarManager::SetITSROFBorderselection(alppar->roFrameBiasInBC, alppar->roFrameLengthInBC, itsROFrameStartBorderMargin, itsROFrameEndBorderMargin); + fLastRun = event.runNumber(); + } + // Reset the fValues array VarManager::ResetValues(0, VarManager::kNEventWiseVariables); @@ -189,13 +234,25 @@ struct AnalysisEventSelection { if (fConfigQA) { fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); // automatically fill all the histograms in the class Event } - if (fEventCut->IsSelected(VarManager::fgValues)) { - if (fConfigQA) { - fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); + + if (!fConfigRunZorro) { + if (fEventCut->IsSelected(VarManager::fgValues)) { + if (fConfigQA) { + fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); + } + eventSel(1); + } else { + eventSel(0); } - eventSel(1); } else { - eventSel(0); + if (fEventCut->IsSelected(VarManager::fgValues) && event.tag_bit(56)) { // This is the bit used for the software trigger event selections [TO BE DONE: find a more clear way to use it] + if (fConfigQA) { + fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); + } + eventSel(1); + } else { + eventSel(0); + } } if (fMixHandler != nullptr) { @@ -208,12 +265,47 @@ struct AnalysisEventSelection { { runEventSelection(event); } + void processSkimmedWithMultPV(MyEventsMultExtra::iterator const& event) + { + runEventSelection(event); + } + void processSkimmedQVector(MyEventsQvector::iterator const& event) + { + runEventSelection(event); + } + void processSkimmedQVectorCentr(MyEventsQvectorCentr::iterator const& event) + { + runEventSelection(event); + } + void processSkimmedQVectorMultExtra(MyEventsQvectorMultExtra::iterator const& event) + { + runEventSelection(event); + } + void processSkimmedQVectorCentrMultExtra(MyEventsQvectorCentrMultExtra::iterator const& event) + { + runEventSelection(event); + } + void processSkimmedQVectorExtraRef(MyEventsVtxCovQvectorExtraWithRefFlow::iterator const& event) + { + runEventSelection(event); + } + void processSkimmedQVectorMultExtraRef(MyEventsVtxCovQvectorMultExtraWithRefFlow::iterator const& event) + { + runEventSelection(event); + } void processDummy(MyEvents&) { // do nothing } PROCESS_SWITCH(AnalysisEventSelection, processSkimmed, "Run event selection on DQ skimmed events", false); + PROCESS_SWITCH(AnalysisEventSelection, processSkimmedWithMultPV, "Run event selection on DQ skimmed events with mult", false); + PROCESS_SWITCH(AnalysisEventSelection, processSkimmedQVector, "Run event selection on DQ skimmed events with Q vector from GFW", false); + PROCESS_SWITCH(AnalysisEventSelection, processSkimmedQVectorCentr, "Run event selection on DQ skimmed events with Q vector from CFW", false); + PROCESS_SWITCH(AnalysisEventSelection, processSkimmedQVectorMultExtra, "Run event selection on DQ skimmed events with Q vector from GFW and MultPV", false); + PROCESS_SWITCH(AnalysisEventSelection, processSkimmedQVectorCentrMultExtra, "Run event selection on DQ skimmed events with Q vector from CFW and MultPV", false); + PROCESS_SWITCH(AnalysisEventSelection, processSkimmedQVectorExtraRef, "Run event selection on DQ skimmed events with Q vector and subscribing to reference flow table", false); + PROCESS_SWITCH(AnalysisEventSelection, processSkimmedQVectorMultExtraRef, "Run event selection on DQ skimmed events with Q vector and subscribing to reference flow table with MultPV", false); PROCESS_SWITCH(AnalysisEventSelection, processDummy, "Dummy function", false); // TODO: Add process functions subscribing to Framework Collision }; @@ -244,8 +336,12 @@ struct AnalysisTrackSelection { int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. - void init(o2::framework::InitContext&) + void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + fCurrentRun = 0; TString cutNamesStr = fConfigCuts.value; @@ -325,7 +421,7 @@ struct AnalysisTrackSelection { for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, iCut++) { if ((*cut).IsSelected(VarManager::fgValues)) { if (iCut != fConfigPrefilterCutId) { - filterMap |= (uint32_t(1) << iCut); + filterMap |= (static_cast(1) << iCut); } if (iCut == fConfigPrefilterCutId) { prefilterSelected = true; @@ -368,8 +464,14 @@ struct AnalysisMuonSelection { HistogramManager* fHistMan; std::vector fMuonCuts; - void init(o2::framework::InitContext&) + Filter filterEventSelected = aod::dqanalysisflags::isEventSelected == 1; + + void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + TString cutNamesStr = fConfigCuts.value; if (!cutNamesStr.IsNull()) { std::unique_ptr objArray(cutNamesStr.Tokenize(",")); @@ -407,6 +509,26 @@ struct AnalysisMuonSelection { uint32_t filterMap = 0; int iCut = 0; + // First loop to get muon multiplicity for single muon cumulants + if constexpr (static_cast(TEventFillMap & VarManager::ObjTypes::ReducedEventQvector)) { + int multMuon = 0; + for (auto& muon : muons) { + filterMap = 0; + VarManager::FillTrack(muon); + + iCut = 0; + for (auto cut = fMuonCuts.begin(); cut != fMuonCuts.end(); cut++, iCut++) { + if ((*cut).IsSelected(VarManager::fgValues)) { + filterMap |= (static_cast(1) << iCut); + } + } + if (static_cast(filterMap) > 0) { + multMuon++; + } + } + VarManager::fgValues[VarManager::kMultSingleMuons] = multMuon; + } + for (auto& muon : muons) { filterMap = 0; VarManager::FillTrack(muon); @@ -417,7 +539,7 @@ struct AnalysisMuonSelection { iCut = 0; for (auto cut = fMuonCuts.begin(); cut != fMuonCuts.end(); cut++, iCut++) { if ((*cut).IsSelected(VarManager::fgValues)) { - filterMap |= (uint32_t(1) << iCut); + filterMap |= (static_cast(1) << iCut); if (fConfigQA) { // TODO: make this compile time fHistMan->FillHistClass(Form("TrackMuon_%s", (*cut).GetName()), VarManager::fgValues); } @@ -431,12 +553,18 @@ struct AnalysisMuonSelection { { runMuonSelection(event, muons); } + void processVnSingleMuonCumulantSkimmed(soa::Filtered::iterator const& event, MyMuonTracks const& muons) + { + VarManager::FillEvent(event, VarManager::fgValues); + runMuonSelection(event, muons); + } void processDummy(MyEvents&) { // do nothing } PROCESS_SWITCH(AnalysisMuonSelection, processSkimmed, "Run muon selection on DQ skimmed muons", false); + PROCESS_SWITCH(AnalysisMuonSelection, processVnSingleMuonCumulantSkimmed, "Run muon selection for single muon cumulant correlators", false); PROCESS_SWITCH(AnalysisMuonSelection, processDummy, "Dummy function", false); }; @@ -447,6 +575,13 @@ struct AnalysisPrefilterSelection { // Configurables Configurable fConfigPrefilterPairCut{"cfgPrefilterPairCut", "", "Prefilter pair cut"}; + Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + + Service ccdb; + + o2::parameters::GRPMagField* grpmag = nullptr; + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. Filter barrelTracksSelectedPrefilter = aod::dqanalysisflags::isBarrelSelectedPrefilter > 0; @@ -455,8 +590,18 @@ struct AnalysisPrefilterSelection { std::map fPrefiltermap; AnalysisCompositeCut* fPairCut; - void init(o2::framework::InitContext&) + void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + + fCurrentRun = 0; + + ccdb->setURL(ccdburl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + fPairCut = new AnalysisCompositeCut(true); TString pairCutStr = fConfigPrefilterPairCut.value; if (!pairCutStr.IsNull()) { @@ -466,6 +611,7 @@ struct AnalysisPrefilterSelection { VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill VarManager::SetDefaultVarNames(); + // Do we need this ? VarManager::SetupTwoProngDCAFitter(5.0f, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, true); // TODO: get these parameters from Configurables VarManager::SetupTwoProngFwdDCAFitter(5.0f, true, 200.0f, 1.0e-3f, 0.9f, true); } @@ -493,6 +639,16 @@ struct AnalysisPrefilterSelection { const int pairType = VarManager::kDecayToEE; fPrefiltermap.clear(); + if (events.size() > 0 && fCurrentRun != events.begin().runNumber()) { + grpmag = ccdb->getForTimeStamp(grpmagPath, events.begin().timestamp()); + if (grpmag != nullptr) { + VarManager::SetMagneticField(grpmag->getNominalL3Field()); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", events.begin().timestamp()); + } + fCurrentRun = events.begin().runNumber(); + } + for (auto& event : events) { if (event.isEventSelected()) { auto groupedPrefilterCandidates = filteredTracks.sliceBy(perCollision, event.globalIndex()); @@ -525,6 +681,24 @@ struct AnalysisEventMixing { Configurable fConfigMuonCuts{"cfgMuonCuts", "", "Comma separated list of muon cuts"}; Configurable fConfigMixingDepth{"cfgMixingDepth", 100, "Number of Events stored for event mixing"}; Configurable fConfigAddEventMixingHistogram{"cfgAddEventMixingHistogram", "", "Comma separated list of histograms"}; + Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable fConfigAmbiguousHist{"cfgAmbiHist", false, "Enable Ambiguous histograms for time association studies"}; + Configurable ccdbPathFlow{"ccdb-path-flow", "Users/c/chizh/FlowResolution", "path to the ccdb object for flow resolution factors"}; + Configurable fConfigFlowReso{"cfgFlowReso", false, "Enable loading of flow resolution factors from CCDB"}; + Configurable fConfigSingleMuCumulants{"cfgSingleMuCumulants", false, "Enable loading of flow resolution factors from CCDB"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + + Service ccdb; + + o2::parameters::GRPMagField* grpmag = nullptr; + TH1D* ResoFlowSP = nullptr; // Resolution factors for flow analysis, this will be loaded from CCDB + TH1D* ResoFlowEP = nullptr; // Resolution factors for flow analysis, this will be loaded from CCDB + TH2D* SingleMuv22m = nullptr; // Single muon v22, loaded from CCDB + TH2D* SingleMuv24m = nullptr; // Single muon v24, loaded from CCDB + TH2D* SingleMuv22p = nullptr; // Single antimuon v22, loaded from CCDB + TH2D* SingleMuv24p = nullptr; // Single antimuon v24, loaded from CCDB + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. Filter filterEventSelected = aod::dqanalysisflags::isEventSelected == 1; Filter filterTrackSelected = aod::dqanalysisflags::isBarrelSelected > 0; @@ -542,6 +716,16 @@ struct AnalysisEventMixing { void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + + fCurrentRun = 0; + + ccdb->setURL(ccdburl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + VarManager::SetDefaultVarNames(); fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(kTRUE); @@ -560,11 +744,11 @@ struct AnalysisEventMixing { Form("PairsBarrelMEMM_%s", objArray->At(icut)->GetName())}; histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); fTrackHistNames.push_back(names); - fTwoTrackFilterMask |= (uint32_t(1) << icut); + fTwoTrackFilterMask |= (static_cast(1) << icut); } } } - if (context.mOptions.get("processMuonSkimmed") || context.mOptions.get("processMuonVnSkimmed") || context.mOptions.get("processMuonVnCentrSkimmed")) { + if (context.mOptions.get("processMuonSkimmed") || context.mOptions.get("processMuonVnSkimmed") || context.mOptions.get("processMuonVnCentrSkimmed") || context.mOptions.get("processMuonVnExtraSkimmed")) { TString cutNames = fConfigMuonCuts.value; if (!cutNames.IsNull()) { std::unique_ptr objArray(cutNames.Tokenize(",")); @@ -573,9 +757,13 @@ struct AnalysisEventMixing { Form("PairsMuonMEPM_%s", objArray->At(icut)->GetName()), Form("PairsMuonMEPP_%s", objArray->At(icut)->GetName()), Form("PairsMuonMEMM_%s", objArray->At(icut)->GetName())}; - histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); + if (fConfigAmbiguousHist) { + histNames += Form("%s;%s;%s;%s_unambiguous;%s_unambiguous;%s_unambiguous;", names[0].Data(), names[1].Data(), names[2].Data(), names[0].Data(), names[1].Data(), names[2].Data()); + } else { + histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); + } fMuonHistNames.push_back(names); - fTwoMuonFilterMask |= (uint32_t(1) << icut); + fTwoMuonFilterMask |= (static_cast(1) << icut); } } } @@ -593,15 +781,17 @@ struct AnalysisEventMixing { Form("PairsEleMuMEMM_%s_%s", objArrayBarrel->At(icut)->GetName(), objArrayMuon->At(icut)->GetName())}; histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); fTrackMuonHistNames.push_back(names); - fTwoTrackFilterMask |= (uint32_t(1) << icut); - fTwoMuonFilterMask |= (uint32_t(1) << icut); + fTwoTrackFilterMask |= (static_cast(1) << icut); + fTwoMuonFilterMask |= (static_cast(1) << icut); } } } } DefineHistograms(fHistMan, histNames.Data(), fConfigAddEventMixingHistogram); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + // Additional histograms via JSON + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); } @@ -621,53 +811,104 @@ struct AnalysisEventMixing { } uint32_t twoTrackFilter = 0; + uint32_t mult_dimuons = 0; + for (auto& track1 : tracks1) { + for (auto& track2 : tracks2) { + if constexpr (TPairType == VarManager::kDecayToMuMu) { + twoTrackFilter = static_cast(track1.isMuonSelected()) & static_cast(track2.isMuonSelected()) & fTwoMuonFilterMask; + } + if (twoTrackFilter && track1.sign() * track2.sign() < 0) { + mult_dimuons++; + } + } // end for (track2) + } // end for (track1) + VarManager::fgValues[VarManager::kMultDimuonsME] = mult_dimuons; + + twoTrackFilter = 0; for (auto& track1 : tracks1) { for (auto& track2 : tracks2) { if constexpr (TPairType == VarManager::kDecayToEE) { - twoTrackFilter = uint32_t(track1.isBarrelSelected()) & uint32_t(track2.isBarrelSelected()) & fTwoTrackFilterMask; + twoTrackFilter = static_cast(track1.isBarrelSelected()) & static_cast(track2.isBarrelSelected()) & fTwoTrackFilterMask; } if constexpr (TPairType == VarManager::kDecayToMuMu) { - twoTrackFilter = uint32_t(track1.isMuonSelected()) & uint32_t(track2.isMuonSelected()) & fTwoMuonFilterMask; + twoTrackFilter = static_cast(track1.isMuonSelected()) & static_cast(track2.isMuonSelected()) & fTwoMuonFilterMask; + if (fConfigSingleMuCumulants) { + VarManager::FillTwoMixEventsCumulants(SingleMuv22m, SingleMuv24m, SingleMuv22p, SingleMuv24p, track1, track2); + } } if constexpr (TPairType == VarManager::kElectronMuon) { - twoTrackFilter = uint32_t(track1.isBarrelSelected()) & uint32_t(track2.isMuonSelected()) & fTwoTrackFilterMask; + twoTrackFilter = static_cast(track1.isBarrelSelected()) & static_cast(track2.isMuonSelected()) & fTwoTrackFilterMask; } if (!twoTrackFilter) { // the tracks must have at least one filter bit in common to continue continue; } - VarManager::FillPairME(track1, track2); - - constexpr bool eventHasQvector = (VarManager::ObjTypes::ReducedEventQvector > 0); - if constexpr (eventHasQvector) { - VarManager::FillPairVn(track1, track2); - } - constexpr bool eventHasQvectorCentr = (VarManager::ObjTypes::CollisionQvect > 0); - if constexpr (eventHasQvectorCentr) { - VarManager::FillPairVn(track1, track2); - } + VarManager::FillPairME(track1, track2); for (unsigned int icut = 0; icut < ncuts; icut++) { - if (twoTrackFilter & (uint32_t(1) << icut)) { + if (twoTrackFilter & (static_cast(1) << icut)) { if (track1.sign() * track2.sign() < 0) { fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); + if (fConfigAmbiguousHist && !(track1.isAmbiguous() || track2.isAmbiguous())) { + fHistMan->FillHistClass(Form("%s_unambiguous", histNames[icut][0].Data()), VarManager::fgValues); + } } else { if (track1.sign() > 0) { fHistMan->FillHistClass(histNames[icut][1].Data(), VarManager::fgValues); + if (fConfigAmbiguousHist && !(track1.isAmbiguous() || track2.isAmbiguous())) { + fHistMan->FillHistClass(Form("%s_unambiguous", histNames[icut][1].Data()), VarManager::fgValues); + } } else { fHistMan->FillHistClass(histNames[icut][2].Data(), VarManager::fgValues); + if (fConfigAmbiguousHist && !(track1.isAmbiguous() || track2.isAmbiguous())) { + fHistMan->FillHistClass(Form("%s_unambiguous", histNames[icut][2].Data()), VarManager::fgValues); + } } } } // end if (filter bits) - } // end for (cuts) - } // end for (track2) - } // end for (track1) + } // end for (cuts) + } // end for (track2) + } // end for (track1) } // barrel-barrel and muon-muon event mixing template void runSameSide(TEvents& events, TTracks const& tracks, Preslice& preSlice) { + if (events.size() > 0 && fCurrentRun != events.begin().runNumber()) { + grpmag = ccdb->getForTimeStamp(grpmagPath, events.begin().timestamp()); + if (grpmag != nullptr) { + VarManager::SetMagneticField(grpmag->getNominalL3Field()); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", events.begin().timestamp()); + } + if (fConfigFlowReso) { + TString PathFlow = ccdbPathFlow.value; + TString ccdbPathFlowSP = Form("%s/ScalarProduct", PathFlow.Data()); + TString ccdbPathFlowEP = Form("%s/EventPlane", PathFlow.Data()); + ResoFlowSP = ccdb->getForTimeStamp(ccdbPathFlowSP.Data(), events.begin().timestamp()); + ResoFlowEP = ccdb->getForTimeStamp(ccdbPathFlowEP.Data(), events.begin().timestamp()); + if (ResoFlowSP == nullptr || ResoFlowEP == nullptr) { + LOGF(fatal, "Resolution factor is not available in CCDB at timestamp=%llu", events.begin().timestamp()); + } + } + if (fConfigSingleMuCumulants) { + TString PathFlow = ccdbPathFlow.value; + TString ccdbPathMuv22m = Form("%s/SingleMuv22m", PathFlow.Data()); + TString ccdbPathMuv24m = Form("%s/SingleMuv24m", PathFlow.Data()); + TString ccdbPathMuv22p = Form("%s/SingleMuv22p", PathFlow.Data()); + TString ccdbPathMuv24p = Form("%s/SingleMuv24p", PathFlow.Data()); + SingleMuv22m = ccdb->getForTimeStamp(ccdbPathMuv22m.Data(), events.begin().timestamp()); + SingleMuv24m = ccdb->getForTimeStamp(ccdbPathMuv24m.Data(), events.begin().timestamp()); + SingleMuv22p = ccdb->getForTimeStamp(ccdbPathMuv22p.Data(), events.begin().timestamp()); + SingleMuv24p = ccdb->getForTimeStamp(ccdbPathMuv24p.Data(), events.begin().timestamp()); + if (SingleMuv22m == nullptr || SingleMuv24m == nullptr || SingleMuv22p == nullptr || SingleMuv24p == nullptr) { + LOGF(fatal, "Single muon cumulants are not available in CCDB at timestamp=%llu", events.begin().timestamp()); + } + } + fCurrentRun = events.begin().runNumber(); + } + events.bindExternalIndices(&tracks); int mixingDepth = fConfigMixingDepth.value; for (auto& [event1, event2] : selfCombinations(hashBin, mixingDepth, -1, events, events)) { @@ -681,6 +922,9 @@ struct AnalysisEventMixing { tracks2.bindExternalIndices(&events); VarManager::FillTwoMixEvents(event1, event2, tracks1, tracks2); + if (fConfigFlowReso) { + VarManager::FillTwoMixEventsFlowResoFactor(ResoFlowSP, ResoFlowEP); + } runMixedPairing(tracks1, tracks2); } // end event loop } @@ -689,6 +933,16 @@ struct AnalysisEventMixing { template void runBarrelMuon(TEvents& events, TTracks const& tracks, TMuons const& muons) { + if (events.size() > 0 && fCurrentRun != events.begin().runNumber()) { + grpmag = ccdb->getForTimeStamp(grpmagPath, events.begin().timestamp()); + if (grpmag != nullptr) { + VarManager::SetMagneticField(grpmag->getNominalL3Field()); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", events.begin().timestamp()); + } + fCurrentRun = events.begin().runNumber(); + } + events.bindExternalIndices(&muons); for (auto& [event1, event2] : selfCombinations(hashBin, 100, -1, events, events)) { @@ -732,6 +986,10 @@ struct AnalysisEventMixing { { runSameSide(events, muons, perEventsSelectedM); } + void processMuonVnExtraSkimmed(soa::Filtered& events, soa::Filtered const& muons) + { + runSameSide(events, muons, perEventsSelectedM); + } // TODO: This is a dummy process function for the case when the user does not want to run any of the process functions (no event mixing) // If there is no process function enabled, the workflow hangs void processDummy(MyEvents&) @@ -745,6 +1003,7 @@ struct AnalysisEventMixing { PROCESS_SWITCH(AnalysisEventMixing, processBarrelVnSkimmed, "Run barrel-barrel vn mixing on skimmed tracks", false); PROCESS_SWITCH(AnalysisEventMixing, processMuonVnSkimmed, "Run muon-muon vn mixing on skimmed tracks", false); PROCESS_SWITCH(AnalysisEventMixing, processMuonVnCentrSkimmed, "Run muon-muon vn mixing on skimmed tracks from central framework", false); + PROCESS_SWITCH(AnalysisEventMixing, processMuonVnExtraSkimmed, "Run muon-muon vn mixing on skimmed tracks from GFW", false); PROCESS_SWITCH(AnalysisEventMixing, processDummy, "Dummy function", false); }; @@ -753,15 +1012,19 @@ struct AnalysisSameEventPairing { Produces dielectronList; Produces dimuonList; Produces dielectronExtraList; + Produces dielectronInfoList; Produces dimuonExtraList; + Produces dielectronAllList; Produces dimuonAllList; Produces dileptonFlowList; - Produces refFlowDimuonList; Produces dileptonInfoList; + Produces dileptonMiniTree; float mMagField = 0.0; o2::parameters::GRPMagField* grpmag = nullptr; o2::base::MatLayerCylSet* lut = nullptr; - int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + TH1D* ResoFlowSP = nullptr; // Resolution factors for flow analysis, this will be loaded from CCDB + TH1D* ResoFlowEP = nullptr; // Resolution factors for flow analysis, this will be loaded from CCDB + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. OutputObj fOutputList{"output"}; Configurable fConfigTrackCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; @@ -769,6 +1032,8 @@ struct AnalysisSameEventPairing { Configurable fConfigPairCuts{"cfgPairCuts", "", "Comma separated list of pair cuts"}; Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable ccdbPath{"ccdb-path", "Users/lm", "base path to the ccdb object"}; + Configurable ccdbPathFlow{"ccdb-path-flow", "Users/c/chizh/FlowResolution", "path to the ccdb object for flow resolution factors"}; + Configurable fConfigFlowReso{"cfgFlowReso", false, "Enable loading of flow resolution factors from CCDB"}; Configurable nolaterthan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; Configurable fConfigAddSEPHistogram{"cfgAddSEPHistogram", "", "Comma separated list of histograms"}; Configurable fConfigFlatTables{"cfgFlatTables", false, "Produce a single flat tables with all relevant information of the pairs and single tracks"}; @@ -787,6 +1052,15 @@ struct AnalysisSameEventPairing { Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; Configurable fCollisionSystem{"syst", "pp", "Collision system, pp or PbPb"}; Configurable fCenterMassEnergy{"energy", 13600, "Center of mass energy in GeV"}; + Configurable fConfigCumulants{"cfgCumulants", false, "If true, fill Cumulants with Weights different than 0"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + + // Configurables to create output tree (flat tables or minitree) + struct : ConfigurableGroup { + Configurable fConfigMiniTree{"useMiniTree.cfgMiniTree", false, "Produce a single flat table with minimal information for analysis"}; + Configurable fConfigMiniTreeMinMass{"useMiniTree.cfgMiniTreeMinMass", 2, "Min. mass cut for minitree"}; + Configurable fConfigMiniTreeMaxMass{"useMiniTree.cfgMiniTreeMaxMass", 5, "Max. mass cut for minitree"}; + } useMiniTree; Service ccdb; Filter filterEventSelected = aod::dqanalysisflags::isEventSelected == 1; @@ -809,6 +1083,10 @@ struct AnalysisSameEventPairing { void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + fCurrentRun = 0; ccdb->setURL(ccdburl.value); @@ -848,7 +1126,7 @@ struct AnalysisSameEventPairing { if (!cutNames.IsNull()) { // if track cuts std::unique_ptr objArray(cutNames.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { // loop over track cuts - fTwoTrackFilterMask |= (uint32_t(1) << icut); + fTwoTrackFilterMask |= (static_cast(1) << icut); // no pair cuts names = { Form("PairsBarrelSEPM_%s", objArray->At(icut)->GetName()), @@ -872,17 +1150,17 @@ struct AnalysisSameEventPairing { } fTrackHistNames.push_back(names); } // end loop (pair cuts) - } // end if (pair cuts) - } // end loop (track cuts) - } // end if (track cuts) + } // end if (pair cuts) + } // end loop (track cuts) + } // end if (track cuts) } - if (context.mOptions.get("processDecayToMuMuSkimmed") || context.mOptions.get("processDecayToMuMuVertexingSkimmed") || context.mOptions.get("processDecayToMuMuSkimmedWithColl") || context.mOptions.get("processVnDecayToMuMuSkimmed") || context.mOptions.get("processVnDecayToMuMuSkimmedWithWeights") || context.mOptions.get("processVnCentrDecayToMuMuSkimmed") || context.mOptions.get("processAllSkimmed")) { + if (context.mOptions.get("processDecayToMuMuSkimmed") || context.mOptions.get("processDecayToMuMuSkimmedWithMult") || context.mOptions.get("processDecayToMuMuVertexingSkimmed") || context.mOptions.get("processDecayToMuMuSkimmedWithColl") || context.mOptions.get("processVnDecayToMuMuSkimmed") || context.mOptions.get("processVnDecayToMuMuSkimmedWithWeights") || context.mOptions.get("processVnDecayToMuMuSkimmedWithWeightsAndColl") || context.mOptions.get("processVnCentrDecayToMuMuSkimmed") || context.mOptions.get("processAllSkimmed")) { TString cutNames = fConfigMuonCuts.value; if (!cutNames.IsNull()) { std::unique_ptr objArray(cutNames.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { // loop over track cuts - fTwoMuonFilterMask |= (uint32_t(1) << icut); + fTwoMuonFilterMask |= (static_cast(1) << icut); // no pair cuts names = { Form("PairsMuonSEPM_%s", objArray->At(icut)->GetName()), @@ -906,9 +1184,9 @@ struct AnalysisSameEventPairing { histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); fMuonHistNames.push_back(names); } // end loop (pair cuts) - } // end if (pair cuts) - } // end loop (track cuts) - } // end if (track cuts) + } // end if (pair cuts) + } // end loop (track cuts) + } // end if (track cuts) } if (context.mOptions.get("processElectronMuonSkimmed") || context.mOptions.get("processAllSkimmed")) { TString cutNamesBarrel = fConfigTrackCuts.value; @@ -918,8 +1196,8 @@ struct AnalysisSameEventPairing { std::unique_ptr objArrayMuon(cutNamesMuon.Tokenize(",")); if (objArrayBarrel->GetEntries() == objArrayMuon->GetEntries()) { // one must specify equal number of barrel and muon cuts for (int icut = 0; icut < objArrayBarrel->GetEntries(); ++icut) { // loop over track cuts - fTwoTrackFilterMask |= (uint32_t(1) << icut); - fTwoMuonFilterMask |= (uint32_t(1) << icut); + fTwoTrackFilterMask |= (static_cast(1) << icut); + fTwoMuonFilterMask |= (static_cast(1) << icut); // no pair cuts names = { Form("PairsEleMuSEPM_%s_%s", objArrayBarrel->At(icut)->GetName(), objArrayMuon->At(icut)->GetName()), @@ -939,10 +1217,10 @@ struct AnalysisSameEventPairing { histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); fTrackMuonHistNames.push_back(names); } // end loop (pair cuts) - } // end if (pair cuts) - } // end loop (track cuts) - } // end if (equal number of cuts) - } // end if (track cuts) + } // end if (pair cuts) + } // end loop (track cuts) + } // end if (equal number of cuts) + } // end if (track cuts) } // Usage example of ccdb @@ -953,8 +1231,9 @@ struct AnalysisSameEventPairing { VarManager::SetCollisionSystem((TString)fCollisionSystem, fCenterMassEnergy); // set collision system and center of mass energy - DefineHistograms(fHistMan, histNames.Data(), fConfigAddSEPHistogram); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + DefineHistograms(fHistMan, histNames.Data(), fConfigAddSEPHistogram); // define all histograms + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); } @@ -962,8 +1241,12 @@ struct AnalysisSameEventPairing { template void runSameEventPairing(TEvent const& event, TTracks1 const& tracks1, TTracks2 const& tracks2) { + if (fConfigCumulants && VarManager::fgValues[VarManager::kM11REF] == 0) { + + return; + } if (fCurrentRun != event.runNumber()) { - if (fUseRemoteField.value) { + if (fUseRemoteField) { grpmag = ccdb->getForTimeStamp(grpmagPath, event.timestamp()); if (grpmag != nullptr) { mMagField = grpmag->getNominalL3Field(); @@ -971,25 +1254,33 @@ struct AnalysisSameEventPairing { LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", event.timestamp()); } if constexpr (TTwoProngFitter == true) { - if (fConfigUseKFVertexing.value) { + if (fConfigUseKFVertexing) { VarManager::SetupTwoProngKFParticle(mMagField); } else { - VarManager::SetupTwoProngDCAFitter(mMagField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fUseAbsDCA.value); // TODO: get these parameters from Configurables + VarManager::SetupTwoProngDCAFitter(mMagField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fUseAbsDCA.value); VarManager::SetupTwoProngFwdDCAFitter(mMagField, true, 200.0f, 1.0e-3f, 0.9f, fUseAbsDCA.value); } - } else { - VarManager::SetupTwoProngDCAFitter(mMagField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fUseAbsDCA.value); // needed because take in varmanager Bz from fgFitterTwoProngBarrel for PhiV calculations } + VarManager::SetMagneticField(mMagField); } else { if constexpr (TTwoProngFitter == true) { - if (fConfigUseKFVertexing.value) { + if (fConfigUseKFVertexing) { VarManager::SetupTwoProngKFParticle(fConfigMagField.value); } else { - VarManager::SetupTwoProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fUseAbsDCA.value); // TODO: get these parameters from Configurables + VarManager::SetupTwoProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fUseAbsDCA.value); VarManager::SetupTwoProngFwdDCAFitter(fConfigMagField.value, true, 200.0f, 1.0e-3f, 0.9f, fUseAbsDCA.value); } - } else { - VarManager::SetupTwoProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fUseAbsDCA.value); // needed because take in varmanager Bz from fgFitterTwoProngBarrel for PhiV calculations + } + VarManager::SetMagneticField(fConfigMagField.value); + } + if (fConfigFlowReso) { + TString PathFlow = ccdbPathFlow.value; + TString ccdbPathFlowSP = Form("%s/ScalarProduct", PathFlow.Data()); + TString ccdbPathFlowEP = Form("%s/EventPlane", PathFlow.Data()); + ResoFlowSP = ccdb->getForTimeStamp(ccdbPathFlowSP.Data(), event.timestamp()); + ResoFlowEP = ccdb->getForTimeStamp(ccdbPathFlowEP.Data(), event.timestamp()); + if (ResoFlowSP == nullptr || ResoFlowEP == nullptr) { + LOGF(fatal, "Resolution factor is not available in CCDB at timestamp=%llu", event.timestamp()); } } fCurrentRun = event.runNumber(); @@ -1014,19 +1305,39 @@ struct AnalysisSameEventPairing { dielectronList.reserve(1); dimuonList.reserve(1); dielectronExtraList.reserve(1); + dielectronInfoList.reserve(1); dimuonExtraList.reserve(1); dileptonInfoList.reserve(1); + dileptonFlowList.reserve(1); if (fConfigFlatTables.value) { + dielectronAllList.reserve(1); dimuonAllList.reserve(1); } + if (useMiniTree.fConfigMiniTree) { + dileptonMiniTree.reserve(1); + } if (fConfigMultDimuons.value) { uint32_t mult_dimuons = 0; + uint32_t mult_antimuons = 0; + uint32_t mult_muons = 0; + + for (auto& t : tracks1) { + if constexpr (TPairType == VarManager::kDecayToMuMu) { + if (static_cast(t.isMuonSelected()) & fTwoMuonFilterMask) { + if (t.sign() < 0) { + mult_muons++; + } else { + mult_antimuons++; + } + } + } + } for (auto& [t1, t2] : combinations(tracks1, tracks2)) { if constexpr (TPairType == VarManager::kDecayToMuMu) { - twoTrackFilter = uint32_t(t1.isMuonSelected()) & uint32_t(t2.isMuonSelected()) & fTwoMuonFilterMask; + twoTrackFilter = static_cast(t1.isMuonSelected()) & static_cast(t2.isMuonSelected()) & fTwoMuonFilterMask; } if (twoTrackFilter && (t1.sign() != t2.sign())) { @@ -1035,17 +1346,24 @@ struct AnalysisSameEventPairing { } VarManager::fgValues[VarManager::kMultDimuons] = mult_dimuons; + VarManager::fgValues[VarManager::kMultMuons] = mult_muons; + VarManager::fgValues[VarManager::kMultAntiMuons] = mult_antimuons; } + if (fConfigFlowReso) { + VarManager::FillEventFlowResoFactor(ResoFlowSP, ResoFlowEP); + } + + bool isFirst = true; for (auto& [t1, t2] : combinations(tracks1, tracks2)) { if constexpr (TPairType == VarManager::kDecayToEE || TPairType == VarManager::kDecayToPiPi) { - twoTrackFilter = uint32_t(t1.isBarrelSelected()) & uint32_t(t2.isBarrelSelected()) & fTwoTrackFilterMask; + twoTrackFilter = static_cast(t1.isBarrelSelected()) & static_cast(t2.isBarrelSelected()) & fTwoTrackFilterMask; } if constexpr (TPairType == VarManager::kDecayToMuMu) { - twoTrackFilter = uint32_t(t1.isMuonSelected()) & uint32_t(t2.isMuonSelected()) & fTwoMuonFilterMask; + twoTrackFilter = static_cast(t1.isMuonSelected()) & static_cast(t2.isMuonSelected()) & fTwoMuonFilterMask; } if constexpr (TPairType == VarManager::kElectronMuon) { - twoTrackFilter = uint32_t(t1.isBarrelSelected()) & uint32_t(t2.isMuonSelected()) & fTwoTrackFilterMask; + twoTrackFilter = static_cast(t1.isBarrelSelected()) & static_cast(t2.isMuonSelected()) & fTwoTrackFilterMask; } if (!twoTrackFilter) { // the tracks must have at least one filter bit in common to continue continue; @@ -1072,6 +1390,21 @@ struct AnalysisSameEventPairing { if constexpr (TPairType == pairTypeEE) { dielectronList(event, VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), dileptonFilterMap, dileptonMcDecision); + if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedTrackCollInfo) > 0) { + dielectronInfoList(t1.collisionId(), t1.trackId(), t2.trackId()); + } + } + if constexpr ((TPairType == pairTypeEE) && (TTrackFillMap & VarManager::ObjTypes::ReducedTrackBarrelPID) > 0) { + if (fConfigFlatTables.value) { + dielectronAllList(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), dileptonFilterMap, dileptonMcDecision, + t1.pt(), t1.eta(), t1.phi(), t1.itsClusterMap(), t1.itsChi2NCl(), t1.tpcNClsCrossedRows(), t1.tpcNClsFound(), t1.tpcChi2NCl(), t1.dcaXY(), t1.dcaZ(), t1.tpcSignal(), t1.tpcNSigmaEl(), t1.tpcNSigmaPi(), t1.tpcNSigmaPr(), t1.beta(), t1.tofNSigmaEl(), t1.tofNSigmaPi(), t1.tofNSigmaPr(), + t2.pt(), t2.eta(), t2.phi(), t2.itsClusterMap(), t2.itsChi2NCl(), t2.tpcNClsCrossedRows(), t2.tpcNClsFound(), t2.tpcChi2NCl(), t2.dcaXY(), t2.dcaZ(), t2.tpcSignal(), t2.tpcNSigmaEl(), t2.tpcNSigmaPi(), t2.tpcNSigmaPr(), t2.beta(), t2.tofNSigmaEl(), t2.tofNSigmaPi(), t2.tofNSigmaPr(), + VarManager::fgValues[VarManager::kKFTrack0DCAxyz], VarManager::fgValues[VarManager::kKFTrack1DCAxyz], VarManager::fgValues[VarManager::kKFDCAxyzBetweenProngs], VarManager::fgValues[VarManager::kKFTrack0DCAxy], VarManager::fgValues[VarManager::kKFTrack1DCAxy], VarManager::fgValues[VarManager::kKFDCAxyBetweenProngs], + VarManager::fgValues[VarManager::kKFTrack0DeviationFromPV], VarManager::fgValues[VarManager::kKFTrack1DeviationFromPV], VarManager::fgValues[VarManager::kKFTrack0DeviationxyFromPV], VarManager::fgValues[VarManager::kKFTrack1DeviationxyFromPV], + VarManager::fgValues[VarManager::kKFMass], VarManager::fgValues[VarManager::kKFChi2OverNDFGeo], VarManager::fgValues[VarManager::kVertexingLxyz], VarManager::fgValues[VarManager::kVertexingLxyzOverErr], VarManager::fgValues[VarManager::kVertexingLxy], VarManager::fgValues[VarManager::kVertexingLxyOverErr], VarManager::fgValues[VarManager::kVertexingTauxy], VarManager::fgValues[VarManager::kVertexingTauxyErr], VarManager::fgValues[VarManager::kKFCosPA], VarManager::fgValues[VarManager::kKFJpsiDCAxyz], VarManager::fgValues[VarManager::kKFJpsiDCAxy], + VarManager::fgValues[VarManager::kKFPairDeviationFromPV], VarManager::fgValues[VarManager::kKFPairDeviationxyFromPV], + VarManager::fgValues[VarManager::kKFMassGeoTop], VarManager::fgValues[VarManager::kKFChi2OverNDFGeoTop]); + } } if constexpr (TPairType == pairTypeMuMu) { dimuonList(event, VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), dileptonFilterMap, dileptonMcDecision); @@ -1089,6 +1422,7 @@ struct AnalysisSameEventPairing { dimuonExtraList(t1.globalIndex(), t2.globalIndex(), VarManager::fgValues[VarManager::kVertexingTauz], VarManager::fgValues[VarManager::kVertexingLz], VarManager::fgValues[VarManager::kVertexingLxy]); if (fConfigFlatTables.value) { dimuonAllList(event.posX(), event.posY(), event.posZ(), event.numContrib(), + event.selection_raw(), 0, -999., -999., -999., VarManager::fgValues[VarManager::kMass], false, @@ -1109,26 +1443,56 @@ struct AnalysisSameEventPairing { -999., -999., -999., -999., t1.isAmbiguous(), t2.isAmbiguous(), VarManager::fgValues[VarManager::kU2Q2], VarManager::fgValues[VarManager::kU3Q3], - VarManager::fgValues[VarManager::kR2EP], VarManager::fgValues[VarManager::kR2SP], VarManager::fgValues[VarManager::kCentFT0C], + VarManager::fgValues[VarManager::kR2EP_AB], VarManager::fgValues[VarManager::kR2SP_AB], VarManager::fgValues[VarManager::kCentFT0C], VarManager::fgValues[VarManager::kCos2DeltaPhi], VarManager::fgValues[VarManager::kCos3DeltaPhi], - VarManager::fgValues[VarManager::kCORR4POI], VarManager::fgValues[VarManager::kCORR2POI], VarManager::fgValues[VarManager::kM01POI], VarManager::fgValues[VarManager::kM0111POI], VarManager::fgValues[VarManager::kMultDimuons], + VarManager::fgValues[VarManager::kCORR2POI], VarManager::fgValues[VarManager::kCORR4POI], VarManager::fgValues[VarManager::kM01POI], VarManager::fgValues[VarManager::kM0111POI], VarManager::fgValues[VarManager::kMultDimuons], VarManager::fgValues[VarManager::kVertexingPz], VarManager::fgValues[VarManager::kVertexingSV]); } - } - - if constexpr (eventHasQvector) { - dileptonFlowList(VarManager::fgValues[VarManager::kU2Q2], VarManager::fgValues[VarManager::kU3Q3], VarManager::fgValues[VarManager::kCos2DeltaPhi], VarManager::fgValues[VarManager::kCos3DeltaPhi]); - refFlowDimuonList(VarManager::fgValues[VarManager::kCORR2REF], VarManager::fgValues[VarManager::kCORR4REF], VarManager::fgValues[VarManager::kM11REF], VarManager::fgValues[VarManager::kM1111REF], VarManager::fgValues[VarManager::kCentFT0C], VarManager::fgValues[VarManager::kMultA]); + auto collId = 0; + if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedMuonCollInfo) > 0) { + collId = t1.collisionId(); + } + if constexpr (eventHasQvector == true || eventHasQvectorCentr == true) { + dileptonFlowList(collId, VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kCentFT0C], + VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), isFirst, + VarManager::fgValues[VarManager::kU2Q2], VarManager::fgValues[VarManager::kR2SP_AB], VarManager::fgValues[VarManager::kR2SP_AC], VarManager::fgValues[VarManager::kR2SP_BC], + VarManager::fgValues[VarManager::kU3Q3], VarManager::fgValues[VarManager::kR3SP], + VarManager::fgValues[VarManager::kCos2DeltaPhi], VarManager::fgValues[VarManager::kR2EP_AB], VarManager::fgValues[VarManager::kR2EP_AC], VarManager::fgValues[VarManager::kR2EP_BC], + VarManager::fgValues[VarManager::kCos3DeltaPhi], VarManager::fgValues[VarManager::kR3EP], + VarManager::fgValues[VarManager::kCORR2POI], VarManager::fgValues[VarManager::kCORR4POI], VarManager::fgValues[VarManager::kM01POI], VarManager::fgValues[VarManager::kM0111POI], + VarManager::fgValues[VarManager::kCORR2REF], VarManager::fgValues[VarManager::kCORR4REF], VarManager::fgValues[VarManager::kM11REF], VarManager::fgValues[VarManager::kM1111REF], + VarManager::fgValues[VarManager::kMultDimuons], VarManager::fgValues[VarManager::kMultA]); + } + if (t1.sign() != t2.sign()) { + isFirst = false; + } } int iCut = 0; for (int icut = 0; icut < ncuts; icut++) { - if (twoTrackFilter & (uint32_t(1) << icut)) { + if (twoTrackFilter & (static_cast(1) << icut)) { if (t1.sign() * t2.sign() < 0) { fHistMan->FillHistClass(histNames[iCut][0].Data(), VarManager::fgValues); if (fConfigAmbiguousHist && !(t1.isAmbiguous() || t2.isAmbiguous())) { fHistMan->FillHistClass(Form("%s_unambiguous", histNames[iCut][0].Data()), VarManager::fgValues); } + if (useMiniTree.fConfigMiniTree) { + // By default (kPt1, kEta1, kPhi1) are for the positive charge + float dileptonMass = VarManager::fgValues[VarManager::kMass]; + if (dileptonMass > useMiniTree.fConfigMiniTreeMinMass && dileptonMass < useMiniTree.fConfigMiniTreeMaxMass) { + dileptonMiniTree(VarManager::fgValues[VarManager::kMass], + VarManager::fgValues[VarManager::kPt], + VarManager::fgValues[VarManager::kRap], + VarManager::fgValues[VarManager::kCentFT0C], + VarManager::fgValues[VarManager::kCos2DeltaPhi], + VarManager::fgValues[VarManager::kPt1], + VarManager::fgValues[VarManager::kEta1], + VarManager::fgValues[VarManager::kPhi1], + VarManager::fgValues[VarManager::kPt2], + VarManager::fgValues[VarManager::kEta2], + VarManager::fgValues[VarManager::kPhi2]); + } + } } else { if (t1.sign() > 0) { fHistMan->FillHistClass(histNames[iCut][1].Data(), VarManager::fgValues); @@ -1165,12 +1529,12 @@ struct AnalysisSameEventPairing { } } } - } // end loop (pair cuts) + } // end loop (pair cuts) } else { // end if (filter bits) iCut = iCut + 1 + fPairCuts.size(); } } // end loop (cuts) - } // end loop over pairs + } // end loop over pairs } void processDecayToEESkimmed(soa::Filtered::iterator const& event, soa::Filtered const& tracks) @@ -1180,6 +1544,13 @@ struct AnalysisSameEventPairing { VarManager::FillEvent(event, VarManager::fgValues); runSameEventPairing(event, tracks, tracks); } + void processDecayToEESkimmedWithMult(soa::Filtered::iterator const& event, soa::Filtered const& tracks) + { + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event, VarManager::fgValues); + runSameEventPairing(event, tracks, tracks); + } void processDecayToEESkimmedNoTwoProngFitter(soa::Filtered::iterator const& event, soa::Filtered const& tracks) { // Reset the fValues array @@ -1243,6 +1614,13 @@ struct AnalysisSameEventPairing { VarManager::FillEvent(event, VarManager::fgValues); runSameEventPairing(event, muons, muons); } + void processDecayToMuMuSkimmedWithMult(soa::Filtered::iterator const& event, soa::Filtered const& muons) + { + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event, VarManager::fgValues); + runSameEventPairing(event, muons, muons); + } void processDecayToMuMuVertexingSkimmed(soa::Filtered::iterator const& event, soa::Filtered const& muons) { // Reset the fValues array @@ -1264,20 +1642,29 @@ struct AnalysisSameEventPairing { VarManager::FillEvent(event, VarManager::fgValues); runSameEventPairing(event, tracks, tracks); } - void processVnDecayToMuMuSkimmed(soa::Filtered::iterator const& event, soa::Filtered const& muons) + void processVnDecayToMuMuSkimmed(soa::Filtered::iterator const& event, soa::Filtered const& muons) { // Reset the fValues array VarManager::ResetValues(0, VarManager::kNVars); - VarManager::FillEvent(event, VarManager::fgValues); - runSameEventPairing(event, muons, muons); + VarManager::FillEvent(event, VarManager::fgValues); + runSameEventPairing(event, muons, muons); } - void processVnDecayToMuMuSkimmedWithWeights(soa::Filtered::iterator const& event, soa::Filtered const& muons) + void processVnDecayToMuMuSkimmedWithWeights(soa::Filtered::iterator const& event, soa::Filtered const& muons) { // Reset the fValues array VarManager::ResetValues(0, VarManager::kNVars); - VarManager::FillEvent(event, VarManager::fgValues); - runSameEventPairing(event, muons, muons); + VarManager::FillEvent(event, VarManager::fgValues); + runSameEventPairing(event, muons, muons); } + + void processVnDecayToMuMuSkimmedWithWeightsAndColl(soa::Filtered::iterator const& event, soa::Filtered const& muons) + { + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event, VarManager::fgValues); + runSameEventPairing(event, muons, muons); + } + void processVnCentrDecayToMuMuSkimmed(soa::Filtered::iterator const& event, soa::Filtered const& muons) { // Reset the fValues array @@ -1315,6 +1702,7 @@ struct AnalysisSameEventPairing { } PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToEESkimmed, "Run electron-electron pairing, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToEESkimmedWithMult, "Run electron-electron pairing, with skimmed tracks and multiplicity", false); PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToEESkimmedNoTwoProngFitter, "Run electron-electron pairing, with skimmed tracks but no two prong fitter", false); PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToEESkimmedWithCov, "Run electron-electron pairing, with skimmed covariant tracks", false); PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToEESkimmedWithCovNoTwoProngFitter, "Run electron-electron pairing, with skimmed covariant tracks but no two prong fitter", false); @@ -1324,11 +1712,13 @@ struct AnalysisSameEventPairing { PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToEESkimmedWithColl, "Run electron-electron pairing, with skimmed tracks and with collision information", false); PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToEESkimmedWithCollNoTwoProngFitter, "Run electron-electron pairing, with skimmed tracks and with collision information but no two prong fitter", false); PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToMuMuSkimmed, "Run muon-muon pairing, with skimmed muons", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToMuMuSkimmedWithMult, "Run muon-muon pairing, with skimmed muons and multiplicity", false); PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToMuMuVertexingSkimmed, "Run muon-muon pairing and vertexing, with skimmed muons", false); PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToMuMuSkimmedWithColl, "Run muon-muon pairing keeping the info of AO2D collision, with skimmed muons", false); PROCESS_SWITCH(AnalysisSameEventPairing, processVnDecayToEESkimmed, "Run electron-electron pairing, with skimmed tracks for vn", false); PROCESS_SWITCH(AnalysisSameEventPairing, processVnDecayToMuMuSkimmed, "Run muon-muon pairing, with skimmed tracks for vn", false); PROCESS_SWITCH(AnalysisSameEventPairing, processVnDecayToMuMuSkimmedWithWeights, "Run muon-muon pairing, with skimmed tracks for vn using weights for Q-vectors", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processVnDecayToMuMuSkimmedWithWeightsAndColl, "Run muon-muon pairing, with skimmed tracks for vn using weights for Q-vectors with collisionId provided", false); PROCESS_SWITCH(AnalysisSameEventPairing, processVnCentrDecayToMuMuSkimmed, "Run muon-muon pairing, with skimmed tracks for vn from central framework", false); PROCESS_SWITCH(AnalysisSameEventPairing, processElectronMuonSkimmed, "Run electron-muon pairing, with skimmed tracks/muons", false); PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToPiPiSkimmed, "Run pion-pion pairing, with skimmed tracks", false); @@ -1336,61 +1726,6 @@ struct AnalysisSameEventPairing { PROCESS_SWITCH(AnalysisSameEventPairing, processDummy, "Dummy function, enabled only if none of the others are enabled", false); }; -struct AnalysisFwdTrackPid { - Produces fwdPidAllList; - - Filter filterEventSelected = aod::dqanalysisflags::isEventSelected == 1; - - Configurable fConfigMaxDCA{"cfgMaxDCA", 0.5f, "Manually set maximum DCA of the track"}; - - void init(o2::framework::InitContext&) - { - } - - // Template function to pair mft tracks and muon tracks - template - void runFwdTrackPid(TEvent const& event, Muons const& muons, MftTracks const& mftTracks) - { - fwdPidAllList.reserve(1); - for (const auto& muon : muons) { - if (muon.has_matchMFTTrack() && muon.trackType() == 0 && TMath::Abs(muon.fwdDcaX()) < fConfigMaxDCA && TMath::Abs(muon.fwdDcaY()) < fConfigMaxDCA) { - auto mftTrack = muon.template matchMFTTrack_as(); - fwdPidAllList(muon.trackType(), event.posX(), event.posY(), event.posZ(), event.numContrib(), muon.pt(), muon.eta(), muon.phi(), muon.sign(), mftTrack.mftClusterSizesAndTrackFlags(), muon.fwdDcaX(), muon.fwdDcaY(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT()); - } - } - if constexpr (TMatchedOnly == false) { - for (const auto& mftTrack : mftTracks) { - if (TMath::Abs(mftTrack.fwdDcaX()) < fConfigMaxDCA && TMath::Abs(mftTrack.fwdDcaY()) < fConfigMaxDCA) { - fwdPidAllList(4, event.posX(), event.posY(), event.posZ(), event.numContrib(), mftTrack.pt(), mftTrack.eta(), mftTrack.phi(), mftTrack.sign(), mftTrack.mftClusterSizesAndTrackFlags(), mftTrack.fwdDcaX(), mftTrack.fwdDcaY(), -999, -999); - } - } - } - } - - void processFwdPidMatchedSkimmed(soa::Filtered::iterator const& event, MyMuonTracks const& muons, MyMftTracks const& mftTracks) - { - if (muons.size() > 0 && mftTracks.size() > 0) { - runFwdTrackPid(event, muons, mftTracks); - } - } - - void processFwdPidMatchedOnlySkimmed(soa::Filtered::iterator const& event, MyMuonTracks const& muons, MyMftTracks const& mftTracks) - { - if (muons.size() > 0) { - runFwdTrackPid(event, muons, mftTracks); - } - } - - void processDummy(MyEvents&) - { - // do nothing - } - - PROCESS_SWITCH(AnalysisFwdTrackPid, processFwdPidMatchedSkimmed, "Run MFT - muon track pairing filling tree with MFT and global tracks", false); - PROCESS_SWITCH(AnalysisFwdTrackPid, processFwdPidMatchedOnlySkimmed, "Run MFT - muon track pairing filling tree with global tracks only", false); - PROCESS_SWITCH(AnalysisFwdTrackPid, processDummy, "Dummy function", false); -}; - struct AnalysisDileptonHadron { // // This task combines dilepton candidates with a track and could be used for example @@ -1443,6 +1778,10 @@ struct AnalysisDileptonHadron { void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + fCurrentRun = 0; fValuesDilepton = new float[VarManager::kNVars]; fValuesHadron = new float[VarManager::kNVars]; @@ -1486,16 +1825,16 @@ struct AnalysisDileptonHadron { } else { LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", event.timestamp()); } - if (fConfigUseKFVertexing.value) { + if (fConfigUseKFVertexing) { VarManager::SetupThreeProngKFParticle(mMagField); } else { - VarManager::SetupThreeProngDCAFitter(); // TODO: get these parameters from Configurables + VarManager::SetupThreeProngDCAFitter(mMagField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables } } else { - if (fConfigUseKFVertexing.value) { + if (fConfigUseKFVertexing) { VarManager::SetupThreeProngKFParticle(fConfigMagField.value); } else { - VarManager::SetupThreeProngDCAFitter(); // TODO: get these parameters from Configurables + VarManager::SetupThreeProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables } } fCurrentRun = event.runNumber(); @@ -1547,7 +1886,7 @@ struct AnalysisDileptonHadron { // loop over hadrons for (auto& hadron : tracks) { - if (!(uint32_t(hadron.isBarrelSelected()) & (uint32_t(1) << fNHadronCutBit))) { + if (!(static_cast(hadron.isBarrelSelected()) & (static_cast(1) << fNHadronCutBit))) { continue; } @@ -1593,7 +1932,7 @@ struct AnalysisDileptonHadron { for (auto dilepton : evDileptons) { for (auto& track : evTracks) { - if (!(uint32_t(track.isBarrelSelected()) & (uint32_t(1) << fNHadronCutBit))) { + if (!(static_cast(track.isBarrelSelected()) & (static_cast(1) << fNHadronCutBit))) { continue; } @@ -1601,7 +1940,7 @@ struct AnalysisDileptonHadron { fHistMan->FillHistClass("DileptonHadronInvMassME", VarManager::fgValues); fHistMan->FillHistClass("DileptonHadronCorrelationME", VarManager::fgValues); } // end for (track) - } // end for (dilepton) + } // end for (dilepton) } // end event loop } @@ -1619,16 +1958,17 @@ struct AnalysisDileptonHadron { struct AnalysisDileptonTrackTrack { OutputObj fOutputList{"output"}; - Configurable fConfigTrackCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; // used for select the tracks from SelectedTracks - Configurable fConfigDileptonCut{"cfgDiLeptonCut", "pairJpsi", "Dilepton cut"}; - Configurable fConfigDitrackCut{"cfgDiTrackCut", "pairNoCut", "Track-Track cut"}; - Configurable fConfigQuadrupletCut{"cfgQuadrupletCut", "pairNoCut", "Dilepton-Track-Track cut"}; - Configurable fConfigAddDileptonHistogram{"cfgAddDileptonHistogram", "berral", "Comma separated list of histograms"}; - Configurable fConfigAddDitrackHistogram{"cfgAddDitrackHistogram", "berral", "Comma separated list of histograms"}; - Configurable fConfigAddQuadrupletHistogram{"cfgAddQuadrupletHistogram", "XtoJpsipipi", "Comma separated list of histograms"}; + Configurable fConfigTrackCut1{"cfgTrackCut1", "pionPIDCut1", "track1 cut"}; // used for select the tracks from SelectedTracks + Configurable fConfigTrackCut2{"cfgTrackCut2", "pionPIDCut2", "track2 cut"}; // used for select the tracks from SelectedTracks + Configurable fConfigDileptonCut{"cfgDiLeptonCut", "pairJpsi2", "Dilepton cut"}; + Configurable fConfigQuadrupletCuts{"cfgQuadrupletCuts", "pairX3872Cut1", "Comma separated list of Dilepton-Track-Track cut"}; + Configurable fConfigAddDileptonHistogram{"cfgAddDileptonHistogram", "barrel", "Comma separated list of histograms"}; + Configurable fConfigAddQuadrupletHistogram{"cfgAddQuadrupletHistogram", "xtojpsipipi", "Comma separated list of histograms"}; + + Produces DileptonTrackTrackTable; Filter eventFilter = aod::dqanalysisflags::isEventSelected == 1; - Filter dileptonFilter = aod::reducedpair::mass > 1.0f && aod::reducedpair::mass < 4.0f; + Filter dileptonFilter = aod::reducedpair::sign == 0; Filter filterBarrelTrackSelected = aod::dqanalysisflags::isBarrelSelected > 0; constexpr static uint32_t fgDileptonFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::Pair; // fill map @@ -1638,18 +1978,20 @@ struct AnalysisDileptonTrackTrack { float* fValuesQuadruplet; HistogramManager* fHistMan; - uint32_t fDileptonFilter = 0; - uint32_t fHadronFilter = 0; - int fIsUnlikeSignDilepton = 0; - int fIsUnlikeSignDitrack = 0; + // cut name setting + TString fTrackCutName1; + TString fTrackCutName2; + bool fIsSameTrackCut = false; AnalysisCompositeCut fDileptonCut; - AnalysisCompositeCut fDitrackCut; - AnalysisCompositeCut fQuadrupletCut; - std::vector fTrackCutNames; + std::vector fQuadrupletCutNames; + std::vector fQuadrupletCuts; void init(o2::framework::InitContext& context) { - fValuesDitrack = new float[VarManager::kNVars]; + if (context.mOptions.get("processDummy")) { + return; + } + fValuesQuadruplet = new float[VarManager::kNVars]; VarManager::SetDefaultVarNames(); fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); @@ -1657,29 +1999,34 @@ struct AnalysisDileptonTrackTrack { fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); // define cuts - TString configTrackCutNamesStr = fConfigTrackCuts.value; + fTrackCutName1 = fConfigTrackCut1.value; + fTrackCutName2 = fConfigTrackCut2.value; + if (fTrackCutName1 == fTrackCutName2) { + fIsSameTrackCut = true; + } TString configDileptonCutNamesStr = fConfigDileptonCut.value; fDileptonCut = *dqcuts::GetCompositeCut(configDileptonCutNamesStr.Data()); - TString configDitrackCutNamesStr = fConfigDitrackCut.value; - fDitrackCut = *dqcuts::GetCompositeCut(configDitrackCutNamesStr.Data()); - TString configQuadruletCutNamesStr = fConfigQuadrupletCut.value; - fQuadrupletCut = *dqcuts::GetCompositeCut(configQuadruletCutNamesStr.Data()); + TString configQuadruletCutNamesStr = fConfigQuadrupletCuts.value; + std::unique_ptr objArray(configQuadruletCutNamesStr.Tokenize(",")); + for (Int_t icut = 0; icut < objArray->GetEntries(); ++icut) { + TString cutName = objArray->At(icut)->GetName(); + fQuadrupletCutNames.push_back(cutName); + fQuadrupletCuts.push_back(*dqcuts::GetCompositeCut(cutName.Data())); + } if (!context.mOptions.get("processDummy")) { - // define histograms for dilepton - DefineHistograms(fHistMan, Form("DileptonsSelectedUS_%s", configDileptonCutNamesStr.Data()), fConfigAddDileptonHistogram); - DefineHistograms(fHistMan, Form("DileptonsSelectedLS_%s", configDileptonCutNamesStr.Data()), fConfigAddDileptonHistogram); - if (!configTrackCutNamesStr.IsNull()) { - std::unique_ptr objArray(configTrackCutNamesStr.Tokenize(",")); - for (Int_t icut = 0; icut < objArray->GetEntries(); ++icut) { - TString cutName = objArray->At(icut)->GetName(); - fTrackCutNames.push_back(cutName); - DefineHistograms(fHistMan, Form("DitrackSelected_%s_%s", configDitrackCutNamesStr.Data(), cutName.Data()), fConfigAddDitrackHistogram); - DefineHistograms(fHistMan, Form("QuadrupletSEUSUS_%s_%s_%s", configDileptonCutNamesStr.Data(), configDitrackCutNamesStr.Data(), cutName.Data()), fConfigAddQuadrupletHistogram); - DefineHistograms(fHistMan, Form("QuadrupletSEUSLS_%s_%s_%s", configDileptonCutNamesStr.Data(), configDitrackCutNamesStr.Data(), cutName.Data()), fConfigAddQuadrupletHistogram); - DefineHistograms(fHistMan, Form("QuadrupletSELSUS_%s_%s_%s", configDileptonCutNamesStr.Data(), configDitrackCutNamesStr.Data(), cutName.Data()), fConfigAddQuadrupletHistogram); - DefineHistograms(fHistMan, Form("QuadrupletSELSLS_%s_%s_%s", configDileptonCutNamesStr.Data(), configDitrackCutNamesStr.Data(), cutName.Data()), fConfigAddQuadrupletHistogram); - } // loop over track cuts + DefineHistograms(fHistMan, Form("Dileptons_%s", configDileptonCutNamesStr.Data()), fConfigAddDileptonHistogram); + if (!configQuadruletCutNamesStr.IsNull()) { + for (std::size_t icut = 0; icut < fQuadrupletCutNames.size(); ++icut) { + if (fIsSameTrackCut) { + DefineHistograms(fHistMan, Form("QuadrupletSEPM_%s", fQuadrupletCutNames[icut].Data()), fConfigAddQuadrupletHistogram); + } else { + DefineHistograms(fHistMan, Form("QuadrupletSEPM_%s", fQuadrupletCutNames[icut].Data()), fConfigAddQuadrupletHistogram); + DefineHistograms(fHistMan, Form("QuadrupletSEMP_%s", fQuadrupletCutNames[icut].Data()), fConfigAddQuadrupletHistogram); + } + DefineHistograms(fHistMan, Form("QuadrupletSEPP_%s", fQuadrupletCutNames[icut].Data()), fConfigAddQuadrupletHistogram); + DefineHistograms(fHistMan, Form("QuadrupletSEMM_%s", fQuadrupletCutNames[icut].Data()), fConfigAddQuadrupletHistogram); + } } } @@ -1690,8 +2037,6 @@ struct AnalysisDileptonTrackTrack { template void runDileptonTrackTrack(TEvent const& event, TTracks const& tracks, soa::Filtered const& dileptons) { - VarManager::ResetValues(0, VarManager::kNVars, fValuesDitrack); - VarManager::FillEvent(event, fValuesDitrack); VarManager::ResetValues(0, VarManager::kNVars, fValuesQuadruplet); VarManager::FillEvent(event, fValuesQuadruplet); @@ -1699,29 +2044,13 @@ struct AnalysisDileptonTrackTrack { // loop over dileptons for (auto dilepton : dileptons) { - fDileptonFilter = 0; - fIsUnlikeSignDilepton = 0; VarManager::FillTrack(dilepton, fValuesQuadruplet); - // Check that the dilepton has zero charge - if (dilepton.sign() == 0) { - fIsUnlikeSignDilepton = 1; - } - // apply the dilepton cut - if (fDileptonCut.IsSelected(fValuesQuadruplet)) { - fDileptonFilter = 1; - if (fIsUnlikeSignDilepton == 1) { - fHistMan->FillHistClass(Form("DileptonsSelectedUS_%s", fDileptonCut.GetName()), fValuesQuadruplet); - } else { - fHistMan->FillHistClass(Form("DileptonsSelectedLS_%s", fDileptonCut.GetName()), fValuesQuadruplet); - } - } - - // pass the dilepton without cut - if (fDileptonFilter == 0) { + if (!fDileptonCut.IsSelected(fValuesQuadruplet)) continue; - } + + fHistMan->FillHistClass(Form("Dileptons_%s", fDileptonCut.GetName()), fValuesQuadruplet); // get the index of the electron legs int indexLepton1 = dilepton.index0Id(); @@ -1734,46 +2063,53 @@ struct AnalysisDileptonTrackTrack { continue; } - // fill variables - VarManager::FillPair(t1, t2, fValuesDitrack); - if constexpr (TCandidateType == VarManager::kChictoJpsiEE) { - VarManager::FillPair(t1, t2, fValuesDitrack); - } - VarManager::FillDileptonTrackTrack(dilepton, t1, t2, fValuesQuadruplet); - - if (t1.sign() * t2.sign() > 0) { - fIsUnlikeSignDitrack = 0; + if (fIsSameTrackCut) { + if (!(static_cast(t1.isBarrelSelected()) & (static_cast(1) << 1)) || !(static_cast(t2.isBarrelSelected()) & (static_cast(1) << 1))) { + continue; + } } else { - fIsUnlikeSignDitrack = 1; + if (!(static_cast(t1.isBarrelSelected()) & (static_cast(1) << 1)) || !(static_cast(t2.isBarrelSelected()) & (static_cast(1) << 2))) { + continue; + } } - int iTrackCut = 0; - for (auto cutname = fTrackCutNames.begin(); cutname != fTrackCutNames.end(); cutname++, iTrackCut++) { - // apply the DiTrack cut - if (fDitrackCut.IsSelected(fValuesDitrack)) { - // apply the Track cut - if (t1.isBarrelSelected() & (uint32_t(1) << (iTrackCut + 1)) && t2.isBarrelSelected() & (uint32_t(1) << (iTrackCut + 1))) { - fHistMan->FillHistClass(Form("DitrackSelected_%s_%s", fDitrackCut.GetName(), (*cutname).Data()), fValuesDitrack); - if (fQuadrupletCut.IsSelected(fValuesQuadruplet)) { - if (fIsUnlikeSignDilepton) { - if (fIsUnlikeSignDitrack) { - fHistMan->FillHistClass(Form("QuadrupletSEUSUS_%s_%s_%s", fDileptonCut.GetName(), fDitrackCut.GetName(), (*cutname).Data()), fValuesQuadruplet); - } else { - fHistMan->FillHistClass(Form("QuadrupletSEUSLS_%s_%s_%s", fDileptonCut.GetName(), fDitrackCut.GetName(), (*cutname).Data()), fValuesQuadruplet); - } - } else { - if (fIsUnlikeSignDitrack) { - fHistMan->FillHistClass(Form("QuadrupletSELSUS_%s_%s_%s", fDileptonCut.GetName(), fDitrackCut.GetName(), (*cutname).Data()), fValuesQuadruplet); - } else { - fHistMan->FillHistClass(Form("QuadrupletSELSLS_%s_%s_%s", fDileptonCut.GetName(), fDitrackCut.GetName(), (*cutname).Data()), fValuesQuadruplet); - } - } + // fill variables + VarManager::FillDileptonTrackTrack(dilepton, t1, t2, fValuesQuadruplet); + + int iCut = 0; + uint32_t CutDecision = 0; + for (auto cutname = fQuadrupletCutNames.begin(); cutname != fQuadrupletCutNames.end(); cutname++, iCut++) { + // apply dilepton-track-track cut + if (fQuadrupletCuts[iCut].IsSelected(fValuesQuadruplet)) { + CutDecision |= (1 << iCut); + if (fIsSameTrackCut) { + if (t1.sign() * t2.sign() < 0) { + fHistMan->FillHistClass(Form("QuadrupletSEPM_%s", fQuadrupletCutNames[iCut].Data()), fValuesQuadruplet); + } + } else { + if ((t1.sign() < 0) && (t2.sign() > 0)) { + fHistMan->FillHistClass(Form("QuadrupletSEMP_%s", fQuadrupletCutNames[iCut].Data()), fValuesQuadruplet); + } else if ((t1.sign() > 0) && (t2.sign() < 0)) { + fHistMan->FillHistClass(Form("QuadrupletSEPM_%s", fQuadrupletCutNames[iCut].Data()), fValuesQuadruplet); } } - } // check if the diTrack cut is selected - } // loop over hadron cuts - } - } + if ((t1.sign() > 0) && (t2.sign() > 0)) { + fHistMan->FillHistClass(Form("QuadrupletSEPP_%s", fQuadrupletCutNames[iCut].Data()), fValuesQuadruplet); + } else if ((t1.sign() < 0) && (t2.sign() < 0)) { + fHistMan->FillHistClass(Form("QuadrupletSEMM_%s", fQuadrupletCutNames[iCut].Data()), fValuesQuadruplet); + } + } + } // loop over dilepton-track-track cuts + + // table to be written out for ML analysis + if (!CutDecision) + continue; + DileptonTrackTrackTable(fValuesQuadruplet[VarManager::kQuadMass], fValuesQuadruplet[VarManager::kQuadPt], fValuesQuadruplet[VarManager::kQuadEta], fValuesQuadruplet[VarManager::kQuadPhi], fValuesQuadruplet[VarManager::kRap], + fValuesQuadruplet[VarManager::kQ], fValuesQuadruplet[VarManager::kDeltaR1], fValuesQuadruplet[VarManager::kDeltaR2], fValuesQuadruplet[VarManager::kDeltaR], + dilepton.mass(), dilepton.pt(), dilepton.eta(), dilepton.phi(), dilepton.sign(), + fValuesQuadruplet[VarManager::kDitrackMass], fValuesQuadruplet[VarManager::kDitrackPt], t1.pt(), t2.pt(), t1.eta(), t2.eta(), t1.phi(), t2.phi(), t1.sign(), t2.sign()); + } // end loop over track-track pairs + } // end loop over dileptons } void processJpsiPiPi(soa::Filtered::iterator const& event, MyBarrelTracksSelectedWithCov const& tracks, soa::Filtered const& dileptons) @@ -1799,7 +2135,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc)}; } diff --git a/PWGDQ/Tasks/tableReader_withAssoc.cxx b/PWGDQ/Tasks/tableReader_withAssoc.cxx index ae4905b2636..5f7912211b2 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc.cxx @@ -12,16 +12,28 @@ // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // Configurable workflow for running several DQ or other PWG analyses +#include +#include +#include #include +#include #include #include +#include +#include +#include +#include #include #include #include #include #include +#include #include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPObject.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/Configurable.h" +#include "Framework/OutputObjHeader.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -41,6 +53,8 @@ #include "DetectorsBase/Propagator.h" #include "DetectorsBase/GeometryManager.h" #include "Common/Core/TableHelper.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "Common/CCDB/EventSelectionParams.h" using std::cout; using std::endl; @@ -57,14 +71,18 @@ namespace o2::aod namespace dqanalysisflags { DECLARE_SOA_COLUMN(MixingHash, mixingHash, int); //! Hash used in event mixing -DECLARE_SOA_BITMAP_COLUMN(IsEventSelected, isEventSelected, 32); //! Event decision +DECLARE_SOA_BITMAP_COLUMN(IsEventSelected, isEventSelected, 8); //! Event decision DECLARE_SOA_BITMAP_COLUMN(IsBarrelSelected, isBarrelSelected, 32); //! Barrel track decisions DECLARE_SOA_COLUMN(BarrelAmbiguityInBunch, barrelAmbiguityInBunch, int8_t); //! Barrel track in-bunch ambiguity DECLARE_SOA_COLUMN(BarrelAmbiguityOutOfBunch, barrelAmbiguityOutOfBunch, int8_t); //! Barrel track out of bunch ambiguity DECLARE_SOA_BITMAP_COLUMN(IsMuonSelected, isMuonSelected, 32); //! Muon track decisions (joinable to ReducedMuonsAssoc) +DECLARE_SOA_COLUMN(MuonAmbiguityInBunch, muonAmbiguityInBunch, int8_t); //! Muon track in-bunch ambiguity +DECLARE_SOA_COLUMN(MuonAmbiguityOutOfBunch, muonAmbiguityOutOfBunch, int8_t); //! Muon track out of bunch ambiguity DECLARE_SOA_BITMAP_COLUMN(IsBarrelSelectedPrefilter, isBarrelSelectedPrefilter, 32); //! Barrel prefilter decisions (joinable to ReducedTracksAssoc) // Bcandidate columns for ML analysis of B->Jpsi+K DECLARE_SOA_COLUMN(massBcandidate, MBcandidate, float); +DECLARE_SOA_COLUMN(MassDileptonCandidate, massDileptonCandidate, float); +DECLARE_SOA_COLUMN(deltamassBcandidate, deltaMBcandidate, float); DECLARE_SOA_COLUMN(pTBcandidate, PtBcandidate, float); DECLARE_SOA_COLUMN(LxyBcandidate, lxyBcandidate, float); DECLARE_SOA_COLUMN(LxyzBcandidate, lxyzBcandidate, float); @@ -73,24 +91,46 @@ DECLARE_SOA_COLUMN(TauxyBcandidate, tauxyBcandidate, float); DECLARE_SOA_COLUMN(TauzBcandidate, tauzBcandidate, float); DECLARE_SOA_COLUMN(CosPBcandidate, cosPBcandidate, float); DECLARE_SOA_COLUMN(Chi2Bcandidate, chi2Bcandidate, float); +DECLARE_SOA_BITMAP_COLUMN(IsJpsiFromBSelected, isJpsiFromBSelected, 32); +// Candidate columns for prompt-non-prompt JPsi separation +DECLARE_SOA_COLUMN(Massee, massJPsi2ee, float); +DECLARE_SOA_COLUMN(Ptee, ptJPsi2ee, float); +DECLARE_SOA_COLUMN(Lxyee, lxyJPsi2ee, float); +DECLARE_SOA_COLUMN(LxyeePoleMass, lxyJPsi2eePoleMass, float); +DECLARE_SOA_COLUMN(Lzee, lzJPsi2ee, float); +DECLARE_SOA_COLUMN(AmbiguousInBunchPairs, AmbiguousJpsiPairsInBunch, bool); +DECLARE_SOA_COLUMN(AmbiguousOutOfBunchPairs, AmbiguousJpsiPairsOutOfBunch, bool); } // namespace dqanalysisflags -DECLARE_SOA_TABLE(EventCuts, "AOD", "DQANAEVCUTS", dqanalysisflags::IsEventSelected); //! joinable to ReducedEvents -DECLARE_SOA_TABLE(MixingHashes, "AOD", "DQANAMIXHASH", dqanalysisflags::MixingHash); //! joinable to ReducedEvents -DECLARE_SOA_TABLE(BarrelTrackCuts, "AOD", "DQANATRKCUTS", dqanalysisflags::IsBarrelSelected); //! joinable to ReducedTracksAssoc -DECLARE_SOA_TABLE(BarrelAmbiguities, "AOD", "DQBARRELAMB", dqanalysisflags::BarrelAmbiguityInBunch, dqanalysisflags::BarrelAmbiguityOutOfBunch); //! joinable to ReducedBarrelTracks -DECLARE_SOA_TABLE(MuonTrackCuts, "AOD", "DQANAMUONCUTS", dqanalysisflags::IsMuonSelected); //! joinable to ReducedMuonsAssoc -DECLARE_SOA_TABLE(Prefilter, "AOD", "DQPREFILTER", dqanalysisflags::IsBarrelSelectedPrefilter); //! joinable to ReducedTracksAssoc -DECLARE_SOA_TABLE(BmesonCandidates, "AOD", "DQBMESONS", dqanalysisflags::massBcandidate, dqanalysisflags::pTBcandidate, dqanalysisflags::LxyBcandidate, dqanalysisflags::LxyzBcandidate, dqanalysisflags::LzBcandidate, dqanalysisflags::TauxyBcandidate, dqanalysisflags::TauzBcandidate, dqanalysisflags::CosPBcandidate, dqanalysisflags::Chi2Bcandidate); +DECLARE_SOA_TABLE(EventCuts, "AOD", "DQANAEVCUTSA", dqanalysisflags::IsEventSelected); //! joinable to ReducedEvents +DECLARE_SOA_TABLE(MixingHashes, "AOD", "DQANAMIXHASHA", dqanalysisflags::MixingHash); //! joinable to ReducedEvents +DECLARE_SOA_TABLE(BarrelTrackCuts, "AOD", "DQANATRKCUTSA", dqanalysisflags::IsBarrelSelected); //! joinable to ReducedTracksAssoc +DECLARE_SOA_TABLE(BarrelAmbiguities, "AOD", "DQBARRELAMBA", dqanalysisflags::BarrelAmbiguityInBunch, dqanalysisflags::BarrelAmbiguityOutOfBunch); //! joinable to ReducedBarrelTracks +DECLARE_SOA_TABLE(MuonTrackCuts, "AOD", "DQANAMUONCUTSA", dqanalysisflags::IsMuonSelected); //! joinable to ReducedMuonsAssoc +DECLARE_SOA_TABLE(MuonAmbiguities, "AOD", "DQMUONAMBA", dqanalysisflags::MuonAmbiguityInBunch, dqanalysisflags::MuonAmbiguityOutOfBunch); //! joinable to ReducedMuonTracks +DECLARE_SOA_TABLE(Prefilter, "AOD", "DQPREFILTERA", dqanalysisflags::IsBarrelSelectedPrefilter); //! joinable to ReducedTracksAssoc +DECLARE_SOA_TABLE(BmesonCandidates, "AOD", "DQBMESONSA", + dqanalysisflags::massBcandidate, dqanalysisflags::MassDileptonCandidate, dqanalysisflags::deltamassBcandidate, dqanalysisflags::pTBcandidate, + dqanalysisflags::LxyBcandidate, dqanalysisflags::LxyzBcandidate, dqanalysisflags::LzBcandidate, + dqanalysisflags::TauxyBcandidate, dqanalysisflags::TauzBcandidate, dqanalysisflags::CosPBcandidate, dqanalysisflags::Chi2Bcandidate, + dqanalysisflags::IsJpsiFromBSelected, dqanalysisflags::IsBarrelSelected); +DECLARE_SOA_TABLE(JPsieeCandidates, "AOD", "DQPSEUDOPROPER", dqanalysisflags::Massee, dqanalysisflags::Ptee, dqanalysisflags::Lxyee, dqanalysisflags::LxyeePoleMass, dqanalysisflags::Lzee, dqanalysisflags::AmbiguousInBunchPairs, dqanalysisflags::AmbiguousOutOfBunchPairs); } // namespace o2::aod // Declarations of various short names using MyEvents = soa::Join; +using MyEventsMultExtra = soa::Join; +using MyEventsZdc = soa::Join; +using MyEventsMultExtraZdc = soa::Join; using MyEventsSelected = soa::Join; +using MyEventsMultExtraSelected = soa::Join; +using MyEventsVtxCovSelectedMultExtra = soa::Join; using MyEventsHashSelected = soa::Join; using MyEventsVtxCov = soa::Join; using MyEventsVtxCovSelected = soa::Join; using MyEventsVtxCovSelectedQvector = soa::Join; +using MyEventsVtxCovZdcSelected = soa::Join; +using MyEventsVtxCovZdcSelectedMultExtra = soa::Join; using MyEventsQvector = soa::Join; using MyEventsHashSelectedQvector = soa::Join; @@ -98,20 +138,28 @@ using MyBarrelTracks = soa::Join; using MyBarrelTracksWithCov = soa::Join; using MyBarrelTracksWithCovWithAmbiguities = soa::Join; +using MyBarrelTracksWithCovWithAmbiguitiesWithColl = soa::Join; using MyDielectronCandidates = soa::Join; +using MyDitrackCandidates = soa::Join; using MyDimuonCandidates = soa::Join; using MyMuonTracks = soa::Join; using MyMuonTracksWithCov = soa::Join; +using MyMuonTracksWithCovWithAmbiguities = soa::Join; using MyMuonTracksSelectedWithColl = soa::Join; // bit maps used for the Fill functions of the VarManager constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended; +constexpr static uint32_t gkEventFillMapWithZdc = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ReducedZdc; constexpr static uint32_t gkEventFillMapWithCov = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov; +constexpr static uint32_t gkEventFillMapWithCovZdc = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov | VarManager::ReducedZdc; +constexpr static uint32_t gkEventFillMapWithMultExtra = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventMultExtra; +constexpr static uint32_t gkEventFillMapWithMultExtraZdc = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventMultExtra | VarManager::ReducedZdc; +constexpr static uint32_t gkEventFillMapWithCovZdcMultExtra = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov | VarManager::ReducedZdc | VarManager::ReducedEventMultExtra; // constexpr static uint32_t gkEventFillMapWithQvector = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventQvector; // constexpr static uint32_t gkEventFillMapWithCovQvector = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov | VarManager::ObjTypes::ReducedEventQvector; constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelPID; constexpr static uint32_t gkTrackFillMapWithCov = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID; -// constexpr static uint32_t gkTrackFillMapWithColl = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelPID | VarManager::ObjTypes::ReducedTrackCollInfo; +constexpr static uint32_t gkTrackFillMapWithCovWithColl = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID | VarManager::ObjTypes::ReducedTrackCollInfo; // constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra; constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra | VarManager::ObjTypes::ReducedMuonCov; @@ -132,17 +180,28 @@ void PrintBitMap(TMap map, int nbits) } } -// Analysis task that produces event decisions and the Hash table used in event mixing +// Analysis task that produces event decisions (analysis cut, in bunch pileup and split collision check) and the Hash table used in event mixing struct AnalysisEventSelection { Produces eventSel; Produces hash; OutputObj fOutputList{"output"}; + // TODO: Provide the mixing variables and binning directly via configurables (e.g. vectors of float) Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; - Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigEventCutsJSON{"cfgEventCutsJSON", "", "Additional event cuts specified in JSON format"}; Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Add event histograms defined via JSON formatting (see HistogramsLibrary)"}; + Configurable fConfigQA{"cfgQA", true, "If true, QA histograms will be created and filled"}; + + Configurable fConfigITSROFrameStartBorderMargin{"cfgITSROFrameStartBorderMargin", -1, "Number of bcs at the start of ITS RO Frame border. Take from CCDB if -1"}; + Configurable fConfigITSROFrameEndBorderMargin{"cfgITSROFrameEndBorderMargin", -1, "Number of bcs at the end of ITS RO Frame border. Take from CCDB if -1"}; + + Configurable fConfigSplitCollisionsDeltaZ{"cfgSplitCollisionsDeltaZ", 1.0, "maximum delta-z (cm) between two collisions to consider them as split candidates"}; + Configurable fConfigSplitCollisionsDeltaBC{"cfgSplitCollisionsDeltaBC", 100, "maximum delta-BC between two collisions to consider them as split candidates; do not apply if value is negative"}; + Configurable fConfigCheckSplitCollisions{"cfgCheckSplitCollisions", false, "If true, run the split collision check and fill histograms"}; + Configurable fConfigRunZorro{"cfgRunZorro", false, "Enable event selection with zorro [WARNING: under debug, do not enable!]"}; Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; @@ -155,23 +214,55 @@ struct AnalysisEventSelection { std::map fSelMap; // key: reduced event global index, value: event selection decision std::map> fBCCollMap; // key: global BC, value: vector of reduced event global indices - std::map fMetadataRCT, fHeader; int fCurrentRun; - void init(o2::framework::InitContext&) + void init(o2::framework::InitContext& context) { + bool isAnyProcessEnabled = context.mOptions.get("processSkimmed") || context.mOptions.get("processSkimmedWithZdc") || context.mOptions.get("processSkimmedWithMultExtra") || context.mOptions.get("processSkimmedWithMultExtraZdc"); + bool isDummyEnabled = context.mOptions.get("processDummy"); + + if (isDummyEnabled) { + if (isAnyProcessEnabled) { + LOG(fatal) << "You have enabled both the dummy process and at least one normal process function! Check your config!"; + } + return; + } + if (!isAnyProcessEnabled) { + return; + } + + VarManager::SetDefaultVarNames(); + fEventCut = new AnalysisCompositeCut(true); TString eventCutStr = fConfigEventCuts.value; - fEventCut->AddCut(dqcuts::GetAnalysisCut(eventCutStr.Data())); + if (eventCutStr != "") { + AnalysisCut* cut = dqcuts::GetAnalysisCut(eventCutStr.Data()); + if (cut != nullptr) { + fEventCut->AddCut(cut); + } + } + // Additional cuts via JSON + TString eventCutJSONStr = fConfigEventCutsJSON.value; + if (eventCutJSONStr != "") { + std::vector jsonCuts = dqcuts::GetCutsFromJSON(eventCutJSONStr.Data()); + for (auto& cutIt : jsonCuts) { + fEventCut->AddCut(cutIt); + } + } + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - VarManager::SetDefaultVarNames(); if (fConfigQA) { fHistMan = new HistogramManager("analysisHistos", "", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(kTRUE); fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - DefineHistograms(fHistMan, "Event_BeforeCuts;Event_AfterCuts;SameBunchCorrelations", fConfigAddEventHistogram.value.data()); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + DefineHistograms(fHistMan, "Event_BeforeCuts;Event_AfterCuts;", fConfigAddEventHistogram.value.data()); + if (fConfigCheckSplitCollisions) { + DefineHistograms(fHistMan, "SameBunchCorrelations;OutOfBunchCorrelations;", ""); + } + // Additional histograms via JSON + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); + VarManager::SetUseVars(fHistMan->GetUsedVars()); fOutputList.setObject(fHistMan->GetMainHistogramList()); } @@ -197,10 +288,18 @@ struct AnalysisEventSelection { void runEventSelection(TEvents const& events) { if (events.size() > 0 && events.begin().runNumber() != fCurrentRun) { - fHeader = fCCDBApi.retrieveHeaders(Form("RCT/Info/RunInformation/%i", events.begin().runNumber()), fMetadataRCT, -1); - uint64_t sor = std::atol(fHeader["SOR"].c_str()); - uint64_t eor = std::atol(fHeader["EOR"].c_str()); - cout << "=========================== SOR / EOR is " << sor << " / " << eor << endl; + std::map metadataRCT, header; + header = fCCDBApi.retrieveHeaders(Form("RCT/Info/RunInformation/%i", events.begin().runNumber()), metadataRCT, -1); + uint64_t sor = std::atol(header["SOR"].c_str()); + uint64_t eor = std::atol(header["EOR"].c_str()); + VarManager::SetSORandEOR(sor, eor); + + auto alppar = fCCDB->getForTimeStamp>("ITS/Config/AlpideParam", events.begin().timestamp()); + EventSelectionParams* par = fCCDB->getForTimeStamp("EventSelection/EventSelectionParams", events.begin().timestamp()); + int itsROFrameStartBorderMargin = fConfigITSROFrameStartBorderMargin < 0 ? par->fITSROFrameStartBorderMargin : fConfigITSROFrameStartBorderMargin; + int itsROFrameEndBorderMargin = fConfigITSROFrameEndBorderMargin < 0 ? par->fITSROFrameEndBorderMargin : fConfigITSROFrameEndBorderMargin; + VarManager::SetITSROFBorderselection(alppar->roFrameBiasInBC, alppar->roFrameLengthInBC, itsROFrameStartBorderMargin, itsROFrameEndBorderMargin); + fCurrentRun = events.begin().runNumber(); } fSelMap.clear(); @@ -212,17 +311,32 @@ struct AnalysisEventSelection { VarManager::FillEvent(event); bool decision = false; - // if QA is requested fill histograms before event selections + // Fill histograms in the class Event, before cuts if (fConfigQA) { - fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); // automatically fill all the histograms in the class Event + fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); } + + // Apply event cuts and fill histograms after selection if (fEventCut->IsSelected(VarManager::fgValues)) { - if (fConfigQA) { - fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); + if (fConfigRunZorro) { + if (event.tag_bit(56)) { // This is the bit used for the software trigger event selections [TO BE DONE: find a more clear way to use it] + if (fConfigQA) { + fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); + } + decision = true; + } + } else { + if (fConfigQA) { + fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); + } + decision = true; } - decision = true; } + + // fill the event decision map fSelMap[event.globalIndex()] = decision; + + // Fill the BC map of events if (fBCCollMap.find(event.globalBC()) == fBCCollMap.end()) { std::vector evIndices = {event.globalIndex()}; fBCCollMap[event.globalBC()] = evIndices; @@ -231,6 +345,7 @@ struct AnalysisEventSelection { evIndices.push_back(event.globalIndex()); } + // create the mixing hash and publish it into the hash table if (fMixHandler != nullptr) { int hh = fMixHandler->FindEventCategory(VarManager::fgValues); hash(hh); @@ -241,49 +356,79 @@ struct AnalysisEventSelection { template void publishSelections(TEvents const& events) { + // Create a map for collisions which are candidate of being split + // key: event global index, value: whether pileup event is a possible splitting + std::map collisionSplittingMap; - std::map collisionSplittingMap; // key: event global index, value: whether pileup event is a possible splitting - - // Reset the fValues array and fill event observables - VarManager::ResetValues(0, VarManager::kNEventWiseVariables); - // loop over the BC map, find BCs with more than one collision and compute 2-event correlation quantities - for (auto& [bc, evIndices] : fBCCollMap) { - if (evIndices.size() < 2) { - continue; - } - for (auto ev1Idx = evIndices.begin(); ev1Idx != evIndices.end(); ++ev1Idx) { - if (!fSelMap[*ev1Idx]) { - continue; - } - auto ev1 = events.rawIteratorAt(*ev1Idx); - for (auto ev2Idx = std::next(ev1Idx); ev2Idx != evIndices.end(); ++ev2Idx) { - if (!fSelMap[*ev2Idx]) { - continue; + if (fConfigCheckSplitCollisions) { + // Reset the fValues array and fill event observables + VarManager::ResetValues(0, VarManager::kNEventWiseVariables); + // loop over the BC map, get the collision vectors and make in-bunch and out of bunch 2-event correlations + for (auto bc1It = fBCCollMap.begin(); bc1It != fBCCollMap.end(); ++bc1It) { + uint64_t bc1 = bc1It->first; + auto bc1Events = bc1It->second; + + // same bunch event correlations, if more than 1 collisions in this bunch + if (bc1Events.size() > 1) { + for (auto ev1It = bc1Events.begin(); ev1It != bc1Events.end(); ++ev1It) { + auto ev1 = events.rawIteratorAt(*ev1It); + for (auto ev2It = std::next(ev1It); ev2It != bc1Events.end(); ++ev2It) { + auto ev2 = events.rawIteratorAt(*ev2It); + // compute 2-event quantities and mark the candidate split collisions + VarManager::FillTwoEvents(ev1, ev2); + if (TMath::Abs(VarManager::fgValues[VarManager::kTwoEvDeltaZ]) < fConfigSplitCollisionsDeltaZ) { // this is a possible collision split + collisionSplittingMap[*ev1It] = true; + collisionSplittingMap[*ev2It] = true; + } + if (fConfigQA) { + fHistMan->FillHistClass("SameBunchCorrelations", VarManager::fgValues); + } + } // end second event loop + } // end first event loop + } // end if BC1 events > 1 + + // loop over the following BCs in the TF + for (auto bc2It = std::next(bc1It); bc2It != fBCCollMap.end(); ++bc2It) { + uint64_t bc2 = bc2It->first; + if ((bc2 > bc1 ? bc2 - bc1 : bc1 - bc2) > fConfigSplitCollisionsDeltaBC) { + break; } - auto ev2 = events.rawIteratorAt(*ev2Idx); - VarManager::FillTwoEvents(ev1, ev2); - if (TMath::Abs(VarManager::fgValues[VarManager::kTwoEvDeltaZ]) < 1.0) { // this is a possible collision split - collisionSplittingMap[*ev1Idx] = true; - collisionSplittingMap[*ev2Idx] = true; + auto bc2Events = bc2It->second; + + // loop over events in the first BC + for (auto ev1It : bc1Events) { + auto ev1 = events.rawIteratorAt(ev1It); + // loop over events in the second BC + for (auto ev2It : bc2Events) { + auto ev2 = events.rawIteratorAt(ev2It); + // compute 2-event quantities and mark the candidate split collisions + VarManager::FillTwoEvents(ev1, ev2); + if (TMath::Abs(VarManager::fgValues[VarManager::kTwoEvDeltaZ]) < fConfigSplitCollisionsDeltaZ) { // this is a possible collision split + collisionSplittingMap[ev1It] = true; + collisionSplittingMap[ev2It] = true; + } + if (fConfigQA) { + fHistMan->FillHistClass("OutOfBunchCorrelations", VarManager::fgValues); + } + } } - fHistMan->FillHistClass("SameBunchCorrelations", VarManager::fgValues); } } } // publish the table - uint32_t evSel = 0; + uint8_t evSel = static_cast(0); for (auto& event : events) { evSel = 0; if (fSelMap[event.globalIndex()]) { // event passed the user cuts - evSel |= (uint32_t(1) << 0); + evSel |= (static_cast(1) << 0); } std::vector sameBunchEvents = fBCCollMap[event.globalBC()]; if (sameBunchEvents.size() > 1) { // event with in-bunch pileup - evSel |= (uint32_t(1) << 1); + evSel |= (static_cast(1) << 1); } if (collisionSplittingMap.find(event.globalIndex()) != collisionSplittingMap.end()) { // event with possible fake in-bunch pileup (collision splitting) - evSel |= (uint32_t(1) << 2); + evSel |= (static_cast(1) << 2); } eventSel(evSel); } @@ -294,12 +439,30 @@ struct AnalysisEventSelection { runEventSelection(events); publishSelections(events); } + void processSkimmedWithZdc(MyEventsZdc const& events) + { + runEventSelection(events); + publishSelections(events); + } + void processSkimmedWithMultExtra(MyEventsMultExtra const& events) + { + runEventSelection(events); + publishSelections(events); + } + void processSkimmedWithMultExtraZdc(MyEventsMultExtraZdc const& events) + { + runEventSelection(events); + publishSelections(events); + } void processDummy(MyEvents&) { // do nothing } PROCESS_SWITCH(AnalysisEventSelection, processSkimmed, "Run event selection on DQ skimmed events", false); + PROCESS_SWITCH(AnalysisEventSelection, processSkimmedWithZdc, "Run event selection on DQ skimmed events, with ZDC", false); + PROCESS_SWITCH(AnalysisEventSelection, processSkimmedWithMultExtra, "Run event selection on DQ skimmed events, with mult extra", false); + PROCESS_SWITCH(AnalysisEventSelection, processSkimmedWithMultExtraZdc, "Run event selection on DQ skimmed events, with mult extra and ZDC", false); PROCESS_SWITCH(AnalysisEventSelection, processDummy, "Dummy function", false); }; @@ -311,42 +474,61 @@ struct AnalysisTrackSelection { OutputObj fOutputList{"output"}; Configurable fConfigCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; - Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigCutsJSON{"cfgBarrelTrackCutsJSON", "", "Additional list of barrel track cuts in JSON format"}; Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigPublishAmbiguity{"cfgPublishAmbiguity", true, "If true, publish ambiguity table and fill QA histograms"}; + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable fConfigCcdbPathTPC{"ccdb-path-tpc", "Users/z/zhxiong/TPCPID/PostCalib", "base path to the ccdb object"}; Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable fConfigComputeTPCpostCalib{"cfgTPCpostCalib", false, "If true, compute TPC post-calibrated n-sigmas"}; Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; Configurable fConfigDummyRunlist{"cfgDummyRunlist", false, "If true, use dummy runlist"}; Configurable fConfigInitRunNumber{"cfgInitRunNumber", 543215, "Initial run number used in run by run checks"}; + // Track related options + Configurable fPropTrack{"cfgPropTrack", true, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; Service fCCDB; + o2::ccdb::CcdbApi fCCDBApi; HistogramManager* fHistMan; - std::vector fTrackCuts; + std::vector fTrackCuts; - int fCurrentRun; // current run (needed to detect run changes for loading CCDB parameters) + int fCurrentRun; // current run kept to detect run changes and trigger loading params from CCDB std::map> fNAssocsInBunch; // key: track global index, value: vector of global index for events associated in-bunch (events that have in-bunch pileup or splitting) std::map> fNAssocsOutOfBunch; // key: track global index, value: vector of global index for events associated out-of-bunch (events that have no in-bunch pileup) - void init(o2::framework::InitContext&) + void init(o2::framework::InitContext& context) { - fCurrentRun = 0; + if (context.mOptions.get("processDummy")) { + return; + } + VarManager::SetDefaultVarNames(); + fCurrentRun = 0; TString cutNamesStr = fConfigCuts.value; if (!cutNamesStr.IsNull()) { std::unique_ptr objArray(cutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - fTrackCuts.push_back(*dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + fTrackCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + } + } + // Extra cuts via JSON + TString addTrackCutsStr = fConfigCutsJSON.value; + if (addTrackCutsStr != "") { + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + for (auto& t : addTrackCuts) { + fTrackCuts.push_back((AnalysisCompositeCut*)t); } } VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill if (fConfigQA) { - VarManager::SetDefaultVarNames(); fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(kTRUE); fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); @@ -354,23 +536,26 @@ struct AnalysisTrackSelection { // set one histogram directory for each defined track cut TString histDirNames = "TrackBarrel_BeforeCuts;"; for (auto& cut : fTrackCuts) { - histDirNames += Form("TrackBarrel_%s;", cut.GetName()); + histDirNames += Form("TrackBarrel_%s;", cut->GetName()); + } + if (fConfigPublishAmbiguity) { + histDirNames += "TrackBarrel_AmbiguityInBunch;TrackBarrel_AmbiguityOutOfBunch;"; } - histDirNames += "TrackBarrel_AmbiguityInBunch;TrackBarrel_AmbiguityOutOfBunch;"; DefineHistograms(fHistMan, histDirNames.Data(), fConfigAddTrackHistogram.value.data()); // define all histograms + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); } if (fConfigDummyRunlist) { VarManager::SetDummyRunlist(fConfigInitRunNumber); } - if (fConfigComputeTPCpostCalib) { - fCCDB->setURL(fConfigCcdbUrl.value); - fCCDB->setCaching(true); - fCCDB->setLocalObjectValidityChecking(); - fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); - } + + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); + fCCDBApi.init(fConfigCcdbUrl.value); } template @@ -379,14 +564,16 @@ struct AnalysisTrackSelection { fNAssocsInBunch.clear(); fNAssocsOutOfBunch.clear(); - if (fConfigComputeTPCpostCalib && events.size() > 0 && fCurrentRun != events.begin().runNumber()) { - auto calibList = fCCDB->getForTimeStamp(fConfigCcdbPathTPC.value, events.begin().timestamp()); - VarManager::SetCalibrationObject(VarManager::kTPCElectronMean, calibList->FindObject("mean_map_electron")); - VarManager::SetCalibrationObject(VarManager::kTPCElectronSigma, calibList->FindObject("sigma_map_electron")); - VarManager::SetCalibrationObject(VarManager::kTPCPionMean, calibList->FindObject("mean_map_pion")); - VarManager::SetCalibrationObject(VarManager::kTPCPionSigma, calibList->FindObject("sigma_map_pion")); - VarManager::SetCalibrationObject(VarManager::kTPCProtonMean, calibList->FindObject("mean_map_proton")); - VarManager::SetCalibrationObject(VarManager::kTPCProtonSigma, calibList->FindObject("sigma_map_proton")); + if (events.size() > 0 && fCurrentRun != events.begin().runNumber()) { + if (fConfigComputeTPCpostCalib) { + auto calibList = fCCDB->getForTimeStamp(fConfigCcdbPathTPC.value, events.begin().timestamp()); + VarManager::SetCalibrationObject(VarManager::kTPCElectronMean, calibList->FindObject("mean_map_electron")); + VarManager::SetCalibrationObject(VarManager::kTPCElectronSigma, calibList->FindObject("sigma_map_electron")); + VarManager::SetCalibrationObject(VarManager::kTPCPionMean, calibList->FindObject("mean_map_pion")); + VarManager::SetCalibrationObject(VarManager::kTPCPionSigma, calibList->FindObject("sigma_map_pion")); + VarManager::SetCalibrationObject(VarManager::kTPCProtonMean, calibList->FindObject("mean_map_proton")); + VarManager::SetCalibrationObject(VarManager::kTPCProtonSigma, calibList->FindObject("sigma_map_proton")); + } o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(grpmagPath, events.begin().timestamp()); if (grpmag != nullptr) { @@ -395,15 +582,23 @@ struct AnalysisTrackSelection { LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", events.begin().timestamp()); } + std::map metadataRCT, header; + header = fCCDBApi.retrieveHeaders(Form("RCT/Info/RunInformation/%i", events.begin().runNumber()), metadataRCT, -1); + uint64_t sor = std::atol(header["SOR"].c_str()); + uint64_t eor = std::atol(header["EOR"].c_str()); + VarManager::SetSORandEOR(sor, eor); + fCurrentRun = events.begin().runNumber(); } trackSel.reserve(assocs.size()); trackAmbiguities.reserve(tracks.size()); - uint32_t filterMap = 0; + uint32_t filterMap = static_cast(0); int iCut = 0; for (auto& assoc : assocs) { + + // if the event from this association is not selected, reject also the association auto event = assoc.template reducedevent_as(); if (!event.isEventSelected_bit(0)) { trackSel(0); @@ -414,27 +609,31 @@ struct AnalysisTrackSelection { VarManager::FillEvent(event); auto track = assoc.template reducedtrack_as(); - filterMap = 0; + filterMap = static_cast(0); VarManager::FillTrack(track); // compute quantities which depend on the associated collision, such as DCA - VarManager::FillTrackCollision(track, event); + if (fPropTrack) { + VarManager::FillTrackCollision(track, event); + } if (fConfigQA) { fHistMan->FillHistClass("TrackBarrel_BeforeCuts", VarManager::fgValues); } iCut = 0; for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, iCut++) { - if ((*cut).IsSelected(VarManager::fgValues)) { - filterMap |= (uint32_t(1) << iCut); + if ((*cut)->IsSelected(VarManager::fgValues)) { + filterMap |= (static_cast(1) << iCut); if (fConfigQA) { - fHistMan->FillHistClass(Form("TrackBarrel_%s", (*cut).GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("TrackBarrel_%s", (*cut)->GetName()), VarManager::fgValues); } } } // end loop over cuts + // publish the decisions trackSel(filterMap); // count the number of associations per track - if (filterMap > 0) { + if (fConfigPublishAmbiguity && filterMap > 0) { + // for this track, count the number of associated collisions with in-bunch pileup and out of bunch associations if (event.isEventSelected_bit(1)) { if (fNAssocsInBunch.find(track.globalIndex()) == fNAssocsInBunch.end()) { std::vector evVector = {event.globalIndex()}; @@ -455,41 +654,47 @@ struct AnalysisTrackSelection { } } // end loop over associations - // QA the collision-track associations - for (auto& [trackIdx, evIndices] : fNAssocsInBunch) { - if (evIndices.size() == 1) { - continue; - } - auto track = tracks.rawIteratorAt(trackIdx); - VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); - VarManager::FillTrack(track); - VarManager::fgValues[VarManager::kBarrelNAssocsInBunch] = static_cast(evIndices.size()); - fHistMan->FillHistClass("TrackBarrel_AmbiguityInBunch", VarManager::fgValues); - } // end loop over in-bunch ambiguous tracks - - for (auto& [trackIdx, evIndices] : fNAssocsOutOfBunch) { - if (evIndices.size() == 1) { - continue; + if (fConfigPublishAmbiguity) { + // QA the collision-track associations + if (fConfigQA) { + for (auto& [trackIdx, evIndices] : fNAssocsInBunch) { + if (evIndices.size() == 1) { + continue; + } + auto track = tracks.rawIteratorAt(trackIdx); + VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); + VarManager::FillTrack(track); + // Exceptionally, set the VarManager ambiguity number here, to be used in histograms + VarManager::fgValues[VarManager::kBarrelNAssocsInBunch] = static_cast(evIndices.size()); + fHistMan->FillHistClass("TrackBarrel_AmbiguityInBunch", VarManager::fgValues); + } // end loop over in-bunch ambiguous tracks + + for (auto& [trackIdx, evIndices] : fNAssocsOutOfBunch) { + if (evIndices.size() == 1) { + continue; + } + auto track = tracks.rawIteratorAt(trackIdx); + VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); + VarManager::FillTrack(track); + // Exceptionally, set the VarManager ambiguity number here + VarManager::fgValues[VarManager::kBarrelNAssocsOutOfBunch] = static_cast(evIndices.size()); + fHistMan->FillHistClass("TrackBarrel_AmbiguityOutOfBunch", VarManager::fgValues); + } // end loop over out-of-bunch ambiguous tracks } - auto track = tracks.rawIteratorAt(trackIdx); - VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); - VarManager::FillTrack(track); - VarManager::fgValues[VarManager::kBarrelNAssocsOutOfBunch] = static_cast(evIndices.size()); - fHistMan->FillHistClass("TrackBarrel_AmbiguityOutOfBunch", VarManager::fgValues); - } // end loop over out-of-bunch ambiguous tracks - // publish the ambiguity table - for (auto& track : tracks) { - int8_t nInBunch = 0; - if (fNAssocsInBunch.find(track.globalIndex()) != fNAssocsInBunch.end()) { - nInBunch = fNAssocsInBunch[track.globalIndex()].size(); - } - int8_t nOutOfBunch = 0; - if (fNAssocsOutOfBunch.find(track.globalIndex()) != fNAssocsOutOfBunch.end()) { - nOutOfBunch = fNAssocsOutOfBunch[track.globalIndex()].size(); + // publish the ambiguity table + for (auto& track : tracks) { + int8_t nInBunch = 0; + if (fNAssocsInBunch.find(track.globalIndex()) != fNAssocsInBunch.end()) { + nInBunch = fNAssocsInBunch[track.globalIndex()].size(); + } + int8_t nOutOfBunch = 0; + if (fNAssocsOutOfBunch.find(track.globalIndex()) != fNAssocsOutOfBunch.end()) { + nOutOfBunch = fNAssocsOutOfBunch[track.globalIndex()].size(); + } + trackAmbiguities(nInBunch, nOutOfBunch); } - trackAmbiguities(nInBunch, nOutOfBunch); - } + } // end if (fConfigPublishAmbiguity) } // end runTrackSelection() @@ -497,6 +702,10 @@ struct AnalysisTrackSelection { { runTrackSelection(assocs, events, tracks); } + void processSkimmedWithMultExtra(ReducedTracksAssoc const& assocs, MyEventsMultExtraSelected const& events, MyBarrelTracks const& tracks) + { + runTrackSelection(assocs, events, tracks); + } void processSkimmedWithCov(ReducedTracksAssoc const& assocs, MyEventsVtxCovSelected const& events, MyBarrelTracksWithCov const& tracks) { runTrackSelection(assocs, events, tracks); @@ -507,6 +716,7 @@ struct AnalysisTrackSelection { } PROCESS_SWITCH(AnalysisTrackSelection, processSkimmed, "Run barrel track selection on DQ skimmed track associations", false); + PROCESS_SWITCH(AnalysisTrackSelection, processSkimmedWithMultExtra, "Run barrel track selection on DQ skimmed track associations, with extra multiplicity tables", false); PROCESS_SWITCH(AnalysisTrackSelection, processSkimmedWithCov, "Run barrel track selection on DQ skimmed tracks w/ cov matrix associations", false); PROCESS_SWITCH(AnalysisTrackSelection, processDummy, "Dummy function", false); }; @@ -515,11 +725,16 @@ struct AnalysisTrackSelection { // Here one should add all the track cuts needed through the workflow (e.g. cuts for same-event pairing, track for dilepton-track correlations) struct AnalysisMuonSelection { Produces muonSel; + Produces muonAmbiguities; OutputObj fOutputList{"output"}; Configurable fConfigCuts{"cfgMuonCuts", "muonQualityCuts", "Comma separated list of muon cuts"}; + Configurable fConfigCutsJSON{"cfgMuonCutsJSON", "", "Additional list of muon cuts in JSON format"}; Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; Configurable fConfigAddMuonHistogram{"cfgAddMuonHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + Configurable fConfigPublishAmbiguity{"cfgPublishAmbiguity", true, "If true, publish ambiguity table and fill QA histograms"}; + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; @@ -528,24 +743,40 @@ struct AnalysisMuonSelection { Service fCCDB; HistogramManager* fHistMan; - std::vector fMuonCuts; + std::vector fMuonCuts; int fCurrentRun; // current run kept to detect run changes and trigger loading params from CCDB - void init(o2::framework::InitContext&) + std::map> fNAssocsInBunch; // key: muon global index, value: vector of global index for events associated in-bunch (events that have in-bunch pileup or splitting) + std::map> fNAssocsOutOfBunch; // key: muon global index, value: vector of global index for events associated out-of-bunch (events that have no in-bunch pileup) + + void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + VarManager::SetDefaultVarNames(); + fCurrentRun = 0; TString cutNamesStr = fConfigCuts.value; if (!cutNamesStr.IsNull()) { std::unique_ptr objArray(cutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - fMuonCuts.push_back(*dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + fMuonCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + } + } + // extra cuts from JSON + TString addCutsStr = fConfigCutsJSON.value; + if (addCutsStr != "") { + std::vector addCuts = dqcuts::GetCutsFromJSON(addCutsStr.Data()); + for (auto& t : addCuts) { + fMuonCuts.push_back((AnalysisCompositeCut*)t); } } + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill if (fConfigQA) { - VarManager::SetDefaultVarNames(); fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(kTRUE); fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); @@ -553,10 +784,14 @@ struct AnalysisMuonSelection { // set one histogram directory for each defined track cut TString histDirNames = "TrackMuon_BeforeCuts;"; for (auto& cut : fMuonCuts) { - histDirNames += Form("TrackMuon_%s;", cut.GetName()); + histDirNames += Form("TrackMuon_%s;", cut->GetName()); + } + if (fConfigPublishAmbiguity) { + histDirNames += "TrackMuon_AmbiguityInBunch;TrackMuon_AmbiguityOutOfBunch;"; } DefineHistograms(fHistMan, histDirNames.Data(), fConfigAddMuonHistogram.value.data()); // define all histograms + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); } @@ -571,8 +806,11 @@ struct AnalysisMuonSelection { } template - void runMuonSelection(ReducedMuonsAssoc const& assocs, TEvents const& events, TMuons const& /*muons*/) + void runMuonSelection(ReducedMuonsAssoc const& assocs, TEvents const& events, TMuons const& muons) { + fNAssocsInBunch.clear(); + fNAssocsOutOfBunch.clear(); + if (events.size() > 0 && fCurrentRun != events.begin().runNumber()) { o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(grpmagPath, events.begin().timestamp()); if (grpmag != nullptr) { @@ -585,7 +823,8 @@ struct AnalysisMuonSelection { } muonSel.reserve(assocs.size()); - uint32_t filterMap = 0; + muonAmbiguities.reserve(muons.size()); + uint32_t filterMap = static_cast(0); int iCut = 0; for (auto& assoc : assocs) { @@ -594,29 +833,88 @@ struct AnalysisMuonSelection { muonSel(0); continue; } - VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); + VarManager::ResetValues(0, VarManager::kNMuonTrackVariables); // fill event information which might be needed in histograms/cuts that combine track and event properties VarManager::FillEvent(event); auto track = assoc.template reducedmuon_as(); - filterMap = 0; + filterMap = static_cast(0); VarManager::FillTrack(track); - // compute quantities which depend on the associated collision - VarManager::FillPropagateMuon(track, event); if (fConfigQA) { fHistMan->FillHistClass("TrackMuon_BeforeCuts", VarManager::fgValues); } iCut = 0; for (auto cut = fMuonCuts.begin(); cut != fMuonCuts.end(); cut++, iCut++) { - if ((*cut).IsSelected(VarManager::fgValues)) { - filterMap |= (uint32_t(1) << iCut); + if ((*cut)->IsSelected(VarManager::fgValues)) { + filterMap |= (static_cast(1) << iCut); if (fConfigQA) { - fHistMan->FillHistClass(Form("TrackMuon_%s", (*cut).GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("TrackMuon_%s", (*cut)->GetName()), VarManager::fgValues); } } } // end loop over cuts muonSel(filterMap); + + // count the number of associations per track + if (fConfigPublishAmbiguity && filterMap > 0) { + if (event.isEventSelected_bit(1)) { + if (fNAssocsInBunch.find(track.globalIndex()) == fNAssocsInBunch.end()) { + std::vector evVector = {event.globalIndex()}; + fNAssocsInBunch[track.globalIndex()] = evVector; + } else { + auto& evVector = fNAssocsInBunch[track.globalIndex()]; + evVector.push_back(event.globalIndex()); + } + } else { + if (fNAssocsOutOfBunch.find(track.globalIndex()) == fNAssocsOutOfBunch.end()) { + std::vector evVector = {event.globalIndex()}; + fNAssocsOutOfBunch[track.globalIndex()] = evVector; + } else { + auto& evVector = fNAssocsOutOfBunch[track.globalIndex()]; + evVector.push_back(event.globalIndex()); + } + } + } // end if (fConfigPublishAmbiguity) } // end loop over assocs + + if (fConfigPublishAmbiguity) { + // QA the collision-track associations + if (fConfigQA) { + for (auto& [trackIdx, evIndices] : fNAssocsInBunch) { + if (evIndices.size() == 1) { + continue; + } + auto track = muons.rawIteratorAt(trackIdx); + VarManager::ResetValues(0, VarManager::kNMuonTrackVariables); + VarManager::FillTrack(track); + VarManager::fgValues[VarManager::kMuonNAssocsInBunch] = static_cast(evIndices.size()); + fHistMan->FillHistClass("TrackMuon_AmbiguityInBunch", VarManager::fgValues); + } // end loop over in-bunch ambiguous tracks + + for (auto& [trackIdx, evIndices] : fNAssocsOutOfBunch) { + if (evIndices.size() == 1) { + continue; + } + auto track = muons.rawIteratorAt(trackIdx); + VarManager::ResetValues(0, VarManager::kNMuonTrackVariables); + VarManager::FillTrack(track); + VarManager::fgValues[VarManager::kMuonNAssocsOutOfBunch] = static_cast(evIndices.size()); + fHistMan->FillHistClass("TrackMuon_AmbiguityOutOfBunch", VarManager::fgValues); + } // end loop over out-of-bunch ambiguous tracks + } + + // publish the ambiguity table + for (auto& track : muons) { + int8_t nInBunch = 0; + if (fNAssocsInBunch.find(track.globalIndex()) != fNAssocsInBunch.end()) { + nInBunch = fNAssocsInBunch[track.globalIndex()].size(); + } + int8_t nOutOfBunch = 0; + if (fNAssocsOutOfBunch.find(track.globalIndex()) != fNAssocsOutOfBunch.end()) { + nOutOfBunch = fNAssocsOutOfBunch[track.globalIndex()].size(); + } + muonAmbiguities(nInBunch, nOutOfBunch); + } + } } void processSkimmed(ReducedMuonsAssoc const& assocs, MyEventsVtxCovSelected const& events, MyMuonTracksWithCov const& muons) @@ -644,6 +942,8 @@ struct AnalysisPrefilterSelection { Configurable fConfigPrefilterPairCut{"cfgPrefilterPairCut", "", "Prefilter pair cut"}; Configurable fConfigTrackCuts{"cfgTrackCuts", "", "Track cuts for which to run the prefilter"}; + // TODO: Add prefilter pair cut via JSON + std::map fPrefilterMap; AnalysisCompositeCut* fPairCut; uint32_t fPrefilterMask; @@ -651,65 +951,89 @@ struct AnalysisPrefilterSelection { Preslice trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; - void init(o2::framework::InitContext& initContext) + void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + VarManager::SetDefaultVarNames(); + + bool runPrefilter = true; // get the list of track cuts to be prefiltered TString trackCutsStr = fConfigTrackCuts.value; TObjArray* objArrayTrackCuts = nullptr; if (!trackCutsStr.IsNull()) { objArrayTrackCuts = trackCutsStr.Tokenize(","); + if (objArrayTrackCuts == nullptr) { + runPrefilter = false; + } + } else { + LOG(warn) << " No track cuts to prefilter! Prefilter will not be run"; + runPrefilter = false; } - if (objArrayTrackCuts->GetEntries() == 0) { - LOG(fatal) << " No track cuts to prefilter!"; + // get the cut to be used as loose selection + TString prefilterTrackCutStr = fConfigPrefilterTrackCut.value; + if (prefilterTrackCutStr.IsNull()) { + LOG(warn) << " No prefilter loose selection specified! Prefilter will not be run"; + runPrefilter = false; } - // get the list of cuts that were computed in the barrel track-selection task and create a bit mask - // to mark just the ones we want to apply a prefilter on - fPrefilterMask = 0; + fPrefilterMask = static_cast(0); fPrefilterCutBit = -1; - string trackCuts; - getTaskOptionValue(initContext, "analysis-track-selection", "cfgTrackCuts", trackCuts, false); - TString allTrackCutsStr = trackCuts; - TString prefilterTrackCutStr = fConfigPrefilterTrackCut.value; - if (!trackCutsStr.IsNull()) { + if (runPrefilter) { + // get the list of cuts that were computed in the barrel track-selection task and create a bit mask + // to mark just the ones we want to apply a prefilter on + string trackCuts; + getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", trackCuts, false); + TString allTrackCutsStr = trackCuts; + // check also the cuts added via JSON and add them to the string of cuts + getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", trackCuts, false); + TString addTrackCutsStr = trackCuts; + if (addTrackCutsStr != "") { + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + for (auto& t : addTrackCuts) { + allTrackCutsStr += Form(",%s", t->GetName()); + } + } + std::unique_ptr objArray(allTrackCutsStr.Tokenize(",")); + if (objArray == nullptr) { + LOG(fatal) << " Not getting any track cuts from the barrel-track-selection "; + } if (objArray->FindObject(prefilterTrackCutStr.Data()) == nullptr) { LOG(fatal) << " Prefilter track cut not among the cuts calculated by the track-selection task! "; } for (int icut = 0; icut < objArray->GetEntries(); ++icut) { TString tempStr = objArray->At(icut)->GetName(); if (objArrayTrackCuts->FindObject(tempStr.Data()) != nullptr) { - fPrefilterMask |= (uint32_t(1) << icut); + fPrefilterMask |= (static_cast(1) << icut); } if (tempStr.CompareTo(fConfigPrefilterTrackCut.value) == 0) { fPrefilterCutBit = icut; } } + // setup the prefilter pair cut + fPairCut = new AnalysisCompositeCut(true); + TString pairCutStr = fConfigPrefilterPairCut.value; + if (!pairCutStr.IsNull()) { + fPairCut = dqcuts::GetCompositeCut(pairCutStr.Data()); + } } - if (fPrefilterMask == 0) { - LOG(fatal) << "No specified track cuts for prefiltering"; - } - if (fPrefilterCutBit < 0) { - LOG(fatal) << "No or incorrectly specified loose track prefilter cut"; - } - - // setup the prefilter pair cut - fPairCut = new AnalysisCompositeCut(true); - TString pairCutStr = fConfigPrefilterPairCut.value; - if (!pairCutStr.IsNull()) { - fPairCut = dqcuts::GetCompositeCut(pairCutStr.Data()); + if (fPrefilterMask == static_cast(0) || fPrefilterCutBit < 0) { + LOG(warn) << "No specified loose cut or track cuts for prefiltering. This task will do nothing."; } - VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - VarManager::SetDefaultVarNames(); - + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill VarManager::SetupTwoProngDCAFitter(5.0f, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, true); // TODO: get these parameters from Configurables - VarManager::SetupTwoProngFwdDCAFitter(5.0f, true, 200.0f, 1.0e-3f, 0.9f, true); + // VarManager::SetupTwoProngFwdDCAFitter(5.0f, true, 200.0f, 1.0e-3f, 0.9f, true); } template void runPrefilter(soa::Join const& assocs, TTracks const& /*tracks*/) { + if (fPrefilterCutBit < 0 || fPrefilterMask == 0) { + return; + } for (auto& [assoc1, assoc2] : o2::soa::combinations(assocs, assocs)) { auto track1 = assoc1.template reducedtrack_as(); @@ -727,6 +1051,7 @@ struct AnalysisPrefilterSelection { bool track1Loose = assoc1.isBarrelSelected_bit(fPrefilterCutBit); bool track2Loose = assoc2.isBarrelSelected_bit(fPrefilterCutBit); + // Here we check if we should apply the prefilter for this pair if (!((track1Candidate > 0 && track2Loose) || (track2Candidate > 0 && track1Loose))) { continue; } @@ -747,7 +1072,6 @@ struct AnalysisPrefilterSelection { void processBarrelSkimmed(MyEvents const& events, soa::Join const& assocs, MyBarrelTracks const& tracks) { - fPrefilterMap.clear(); for (auto& event : events) { @@ -756,15 +1080,26 @@ struct AnalysisPrefilterSelection { runPrefilter(groupedAssocs, tracks); } } + uint32_t mymap = -1; - for (auto& assoc : assocs) { - auto track = assoc.template reducedtrack_as(); - mymap = -1; - if (fPrefilterMap.find(track.globalIndex()) != fPrefilterMap.end()) { - // NOTE: publish the bitwise negated bits (~), so there will be zeroes for cuts that failed the prefiltering and 1 everywhere else - mymap = ~fPrefilterMap[track.globalIndex()]; + // If cuts were not configured, then produce a map with all 1's and publish it for all associations + if (fPrefilterCutBit < 0 || fPrefilterMask == 0) { + for (int i = 0; i < assocs.size(); ++i) { + prefilter(mymap); + } + } else { + for (auto& assoc : assocs) { + // TODO: just use the index from the assoc (no need to cast the whole track) + auto track = assoc.template reducedtrack_as(); + mymap = -1; + if (fPrefilterMap.find(track.globalIndex()) != fPrefilterMap.end()) { + // NOTE: publish the bitwise negated bits (~), so there will be zeroes for cuts that failed the prefiltering and 1 everywhere else + mymap = ~fPrefilterMap[track.globalIndex()]; + prefilter(mymap); + } else { + prefilter(mymap); // track did not pass the prefilter selections, so publish just 1's + } } - prefilter(mymap); } } @@ -787,46 +1122,58 @@ struct AnalysisSameEventPairing { Produces dielectronList; Produces dimuonList; Produces dielectronsExtraList; + Produces dielectronInfoList; Produces dimuonsExtraList; + Produces dielectronAllList; Produces dimuonAllList; Produces dileptonFlowList; - Produces refFlowDimuonList; Produces dileptonInfoList; + Produces PromptNonPromptSepTable; o2::base::MatLayerCylSet* fLUT = nullptr; int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. OutputObj fOutputList{"output"}; - Configurable fConfigTrackCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; - Configurable fConfigMuonCuts{"cfgMuonCuts", "", "Comma separated list of muon cuts"}; - Configurable fConfigPairCuts{"cfgPairCuts", "", "Comma separated list of pair cuts"}; + struct : ConfigurableGroup { + Configurable track{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; + Configurable muon{"cfgMuonCuts", "", "Comma separated list of muon cuts"}; + Configurable pair{"cfgPairCuts", "", "Comma separated list of pair cuts"}; + Configurable event{"cfgRemoveCollSplittingCandidates", false, "If true, remove collision splitting candidates as determined by the event selection task upstream"}; + // TODO: Add pair cuts via JSON + } fConfigCuts; Configurable fConfigMixingDepth{"cfgMixingDepth", 100, "Number of Events stored for event mixing"}; - Configurable fConfigAddEventMixingHistogram{"cfgAddEventMixingHistogram", "", "Comma separated list of histograms"}; - - Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable fConfigCcdbPath{"ccdb-path", "Users/lm", "base path to the ccdb object"}; - Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; - Configurable fConfigGRPMagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable fConfigUseRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; - Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; - + // Configurable fConfigAddEventMixingHistogram{"cfgAddEventMixingHistogram", "", "Comma separated list of histograms"}; Configurable fConfigAddSEPHistogram{"cfgAddSEPHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigFlatTables{"cfgFlatTables", false, "Produce a single flat tables with all relevant information of the pairs and single tracks"}; - Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; - Configurable fConfigUseAbsDCA{"cfgUseAbsDCA", false, "Use absolute DCA minimization instead of chi^2 minimization in secondary vertexing"}; - Configurable fConfigPropToPCA{"cfgPropToPCA", false, "Propagate tracks to secondary vertex"}; - Configurable fConfigCorrFullGeo{"cfgCorrFullGeo", false, "Use full geometry to correct for MCS effects in track propagation"}; - Configurable fConfigNoCorr{"cfgNoCorrFwdProp", false, "Do not correct for MCS effects in track propagation"}; - Configurable fConfigLutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; - Configurable fConfigGeoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - Configurable fConfigCollisionSystem{"syst", "pp", "Collision system, pp or PbPb"}; - Configurable fConfigCenterMassEnergy{"energy", 13600, "Center of mass energy in GeV"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + Configurable fConfigQA{"cfgQA", true, "If true, fill output histograms"}; + + struct : ConfigurableGroup { + Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpMagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + } fConfigCCDB; + + struct : ConfigurableGroup { + Configurable useRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; + Configurable magField{"cfgMagField", 5.0f, "Manually set magnetic field"}; + Configurable flatTables{"cfgFlatTables", false, "Produce a single flat tables with all relevant information of the pairs and single tracks"}; + Configurable useKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; + Configurable useAbsDCA{"cfgUseAbsDCA", false, "Use absolute DCA minimization instead of chi^2 minimization in secondary vertexing"}; + Configurable propToPCA{"cfgPropToPCA", false, "Propagate tracks to secondary vertex"}; + Configurable corrFullGeo{"cfgCorrFullGeo", false, "Use full geometry to correct for MCS effects in track propagation"}; + Configurable noCorr{"cfgNoCorrFwdProp", false, "Do not correct for MCS effects in track propagation"}; + Configurable collisionSystem{"syst", "pp", "Collision system, pp or PbPb"}; + Configurable centerMassEnergy{"energy", 13600, "Center of mass energy in GeV"}; + Configurable propTrack{"cfgPropTrack", true, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; + } fConfigOptions; Service fCCDB; + o2::ccdb::CcdbApi fCCDBApi; - Filter filterEventSelected = aod::dqanalysisflags::isEventSelected == uint32_t(1); + Filter filterEventSelected = aod::dqanalysisflags::isEventSelected > static_cast(0); HistogramManager* fHistMan; @@ -854,25 +1201,25 @@ struct AnalysisSameEventPairing { void init(o2::framework::InitContext& context) { - fEnableBarrelHistos = context.mOptions.get("processAllSkimmed") || context.mOptions.get("processBarrelOnlySkimmed"); - fEnableBarrelMixingHistos = context.mOptions.get("processMixingAllSkimmed"); - fEnableMuonHistos = context.mOptions.get("processAllSkimmed") || context.mOptions.get("processMuonOnlySkimmed"); - fEnableMuonMixingHistos = context.mOptions.get("processMixingAllSkimmed"); - bool isDummy = context.mOptions.get("processDummy"); - if (isDummy) { + fEnableBarrelHistos = context.mOptions.get("processAllSkimmed") || context.mOptions.get("processBarrelOnlySkimmed") || context.mOptions.get("processBarrelOnlyWithCollSkimmed") || context.mOptions.get("processBarrelOnlySkimmedNoCov") || context.mOptions.get("processBarrelOnlySkimmedNoCovWithMultExtra"); + fEnableBarrelMixingHistos = context.mOptions.get("processMixingAllSkimmed") || context.mOptions.get("processMixingBarrelSkimmed"); + fEnableMuonHistos = context.mOptions.get("processAllSkimmed") || context.mOptions.get("processMuonOnlySkimmed") || context.mOptions.get("processMuonOnlySkimmedMultExtra") || context.mOptions.get("processMixingMuonSkimmed"); + fEnableMuonMixingHistos = context.mOptions.get("processMixingAllSkimmed") || context.mOptions.get("processMixingMuonSkimmed"); + + if (context.mOptions.get("processDummy")) { if (fEnableBarrelHistos || fEnableBarrelMixingHistos || fEnableMuonHistos || fEnableMuonMixingHistos) { - LOG(warning) << "The dummy process function is enabled while you have enabled normal process function. Check your configuration file!" << endl; - } else { - LOG(info) << "Dummy function enabled. Skipping the rest of init()" << endl; - return; + LOG(fatal) << "No other processing tasks should be enabled if the processDummy is enabled!!"; } + return; } + VarManager::SetDefaultVarNames(); // Keep track of all the histogram class names to avoid composing strings in the pairing loop TString histNames = ""; std::vector names; - TString cutNamesStr = fConfigPairCuts.value; + // NOTE: Pair cuts are only applied on the histogram output. The produced pair tables do not have these cuts applied + TString cutNamesStr = fConfigCuts.pair.value; if (!cutNamesStr.IsNull()) { std::unique_ptr objArray(cutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { @@ -882,12 +1229,12 @@ struct AnalysisSameEventPairing { // get the list of cuts for tracks/muons, check that they were played by the barrel/muon selection tasks // and make a mask for active cuts (barrel and muon selection tasks may run more cuts, needed for other analyses) - TString trackCutsStr = fConfigTrackCuts.value; + TString trackCutsStr = fConfigCuts.track.value; TObjArray* objArrayTrackCuts = nullptr; if (!trackCutsStr.IsNull()) { objArrayTrackCuts = trackCutsStr.Tokenize(","); } - TString muonCutsStr = fConfigMuonCuts.value; + TString muonCutsStr = fConfigCuts.muon.value; TObjArray* objArrayMuonCuts = nullptr; if (!muonCutsStr.IsNull()) { objArrayMuonCuts = muonCutsStr.Tokenize(","); @@ -897,13 +1244,22 @@ struct AnalysisSameEventPairing { string tempCuts; getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", tempCuts, false); TString tempCutsStr = tempCuts; + // check also the cuts added via JSON and add them to the string of cuts + getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", tempCuts, false); + TString addTrackCutsStr = tempCuts; + if (addTrackCutsStr != "") { + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + for (auto& t : addTrackCuts) { + tempCutsStr += Form(",%s", t->GetName()); + } + } if (!trackCutsStr.IsNull()) { std::unique_ptr objArray(tempCutsStr.Tokenize(",")); fNCutsBarrel = objArray->GetEntries(); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { TString tempStr = objArray->At(icut)->GetName(); if (objArrayTrackCuts->FindObject(tempStr.Data()) != nullptr) { - fTrackFilterMask |= (uint32_t(1) << icut); + fTrackFilterMask |= (static_cast(1) << icut); if (fEnableBarrelHistos) { names = { @@ -927,7 +1283,7 @@ struct AnalysisSameEventPairing { histNames += Form("%s;%s;%s;", names[(fEnableBarrelMixingHistos ? 9 : 6)].Data(), names[(fEnableBarrelMixingHistos ? 10 : 7)].Data(), names[(fEnableBarrelMixingHistos ? 11 : 8)].Data()); fTrackHistNames[icut] = names; - TString cutNamesStr = fConfigPairCuts.value; + TString cutNamesStr = fConfigCuts.pair.value; if (!cutNamesStr.IsNull()) { // if pair cuts std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); fNPairCuts = objArrayPair->GetEntries(); @@ -939,21 +1295,32 @@ struct AnalysisSameEventPairing { histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); fTrackHistNames[fNCutsBarrel + icut * fNPairCuts + iPairCut] = names; } // end loop (pair cuts) - } // end if (pair cuts) - } // end if enableBarrelHistos + } // end if (pair cuts) + } // end if enableBarrelHistos } } } + // get the muon track selection cuts getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCuts", tempCuts, false); tempCutsStr = tempCuts; + // check also the cuts added via JSON and add them to the string of cuts + getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCutsJSON", tempCuts, false); + TString addMuonCutsStr = tempCuts; + if (addMuonCutsStr != "") { + std::vector addMuonCuts = dqcuts::GetCutsFromJSON(addMuonCutsStr.Data()); + for (auto& t : addMuonCuts) { + tempCutsStr += Form(",%s", t->GetName()); + } + } + if (!muonCutsStr.IsNull()) { std::unique_ptr objArray(tempCutsStr.Tokenize(",")); fNCutsMuon = objArray->GetEntries(); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { TString tempStr = objArray->At(icut)->GetName(); if (objArrayMuonCuts->FindObject(tempStr.Data()) != nullptr) { - fMuonFilterMask |= (uint32_t(1) << icut); + fMuonFilterMask |= (static_cast(1) << icut); if (fEnableMuonHistos) { // no pair cuts @@ -968,9 +1335,35 @@ struct AnalysisSameEventPairing { names.push_back(Form("PairsMuonMEMM_%s", objArray->At(icut)->GetName())); histNames += Form("%s;%s;%s;", names[3].Data(), names[4].Data(), names[5].Data()); } + names.push_back(Form("PairsMuonSEPM_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEPP_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEMM_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEPM_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEPP_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEMM_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEPM_unambiguous_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEPP_unambiguous_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEMM_unambiguous_%s", objArray->At(icut)->GetName())); + histNames += Form("%s;%s;%s;", names[(fEnableMuonMixingHistos ? 6 : 3)].Data(), names[(fEnableMuonMixingHistos ? 7 : 4)].Data(), names[(fEnableMuonMixingHistos ? 8 : 5)].Data()); + histNames += Form("%s;%s;%s;", names[(fEnableMuonMixingHistos ? 9 : 6)].Data(), names[(fEnableMuonMixingHistos ? 10 : 7)].Data(), names[(fEnableMuonMixingHistos ? 11 : 8)].Data()); + histNames += Form("%s;%s;%s;", names[(fEnableMuonMixingHistos ? 12 : 9)].Data(), names[(fEnableMuonMixingHistos ? 13 : 10)].Data(), names[(fEnableMuonMixingHistos ? 14 : 11)].Data()); + if (fEnableMuonMixingHistos) { + names.push_back(Form("PairsMuonMEPM_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonMEPP_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonMEMM_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonMEPM_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonMEPP_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonMEMM_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonMEPM_unambiguous_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonMEPP_unambiguous_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonMEMM_unambiguous_%s", objArray->At(icut)->GetName())); + histNames += Form("%s;%s;%s;", names[15].Data(), names[16].Data(), names[17].Data()); + histNames += Form("%s;%s;%s;", names[18].Data(), names[19].Data(), names[20].Data()); + histNames += Form("%s;%s;%s;", names[21].Data(), names[22].Data(), names[23].Data()); + } fMuonHistNames[icut] = names; - TString cutNamesStr = fConfigPairCuts.value; + TString cutNamesStr = fConfigCuts.pair.value; if (!cutNamesStr.IsNull()) { // if pair cuts std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); fNPairCuts = objArrayPair->GetEntries(); @@ -982,7 +1375,7 @@ struct AnalysisSameEventPairing { histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); fMuonHistNames[fNCutsMuon + icut * fNCutsMuon + iPairCut] = names; } // end loop (pair cuts) - } // end if (pair cuts) + } // end if (pair cuts) } } } @@ -990,29 +1383,25 @@ struct AnalysisSameEventPairing { fCurrentRun = 0; - fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setURL(fConfigCCDB.url.value); fCCDB->setCaching(true); fCCDB->setLocalObjectValidityChecking(); + fCCDBApi.init(fConfigCCDB.url.value); - if (fConfigNoCorr) { + if (fConfigOptions.noCorr) { VarManager::SetupFwdDCAFitterNoCorr(); - } else if (fConfigCorrFullGeo || (fConfigUseKFVertexing && fConfigPropToPCA)) { + } else if (fConfigOptions.corrFullGeo || (fConfigOptions.useKFVertexing && fConfigOptions.propToPCA)) { if (!o2::base::GeometryManager::isGeometryLoaded()) { - fCCDB->get(fConfigGeoPath); + fCCDB->get(fConfigCCDB.geoPath); } } else { - fLUT = o2::base::MatLayerCylSet::rectifyPtrFromFile(fCCDB->get(fConfigLutPath)); + fLUT = o2::base::MatLayerCylSet::rectifyPtrFromFile(fCCDB->get(fConfigCCDB.lutPath)); VarManager::SetupMatLUTFwdDCAFitter(fLUT); } - VarManager::SetDefaultVarNames(); - fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - /*if (context.mOptions.get("processElectronMuonSkimmed") || context.mOptions.get("processAllSkimmed")) { - TString cutNamesBarrel = fConfigTrackCuts.value; - TString cutNamesMuon = fConfigMuonCuts.value; + TString cutNamesBarrel = fConfigCuts.track.value; + TString cutNamesMuon = fConfigCuts.muon.value; if (!cutNamesBarrel.IsNull() && !cutNamesMuon.IsNull()) { std::unique_ptr objArrayBarrel(cutNamesBarrel.Tokenize(",")); std::unique_ptr objArrayMuon(cutNamesMuon.Tokenize(",")); @@ -1026,7 +1415,7 @@ struct AnalysisSameEventPairing { histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); fTrackMuonHistNames.push_back(names); - TString cutNamesStr = fConfigPairCuts.value; + TString cutNamesStr = fConfigCuts.pair.value; if (!cutNamesStr.IsNull()) { // if pair cuts std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); for (int iPairCut = 0; iPairCut < objArrayPair->GetEntries(); ++iPairCut) { // loop over pair cuts @@ -1043,18 +1432,23 @@ struct AnalysisSameEventPairing { } // end if (track cuts) }*/ - VarManager::SetCollisionSystem((TString)fConfigCollisionSystem, fConfigCenterMassEnergy); // set collision system and center of mass energy - - DefineHistograms(fHistMan, histNames.Data(), fConfigAddSEPHistogram.value.data()); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill - fOutputList.setObject(fHistMan->GetMainHistogramList()); + if (fConfigQA) { + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(true); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + VarManager::SetCollisionSystem((TString)fConfigOptions.collisionSystem, fConfigOptions.centerMassEnergy); // set collision system and center of mass energy + DefineHistograms(fHistMan, histNames.Data(), fConfigAddSEPHistogram.value.data()); // define all histograms + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } } - void initParamsFromCCDB(uint64_t timestamp, bool withTwoProngFitter = true) + void initParamsFromCCDB(uint64_t timestamp, int runNumber, bool withTwoProngFitter = true) { - if (fConfigUseRemoteField.value) { - o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(fConfigGRPMagPath, timestamp); + if (fConfigOptions.useRemoteField.value) { + o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(fConfigCCDB.grpMagPath, timestamp); float magField = 0.0; if (grpmag != nullptr) { magField = grpmag->getNominalL3Field(); @@ -1062,87 +1456,108 @@ struct AnalysisSameEventPairing { LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", timestamp); } if (withTwoProngFitter) { - if (fConfigUseKFVertexing.value) { + if (fConfigOptions.useKFVertexing.value) { VarManager::SetupTwoProngKFParticle(magField); } else { - VarManager::SetupTwoProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); // TODO: get these parameters from Configurables - VarManager::SetupTwoProngFwdDCAFitter(magField, true, 200.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); + VarManager::SetupTwoProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); // TODO: get these parameters from Configurables + VarManager::SetupTwoProngFwdDCAFitter(magField, true, 200.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); } } else { - VarManager::SetupTwoProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); // needed because take in varmanager Bz from fgFitterTwoProngBarrel for PhiV calculations + VarManager::SetupTwoProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); // needed because take in varmanager Bz from fgFitterTwoProngBarrel for PhiV calculations } } else { if (withTwoProngFitter) { - if (fConfigUseKFVertexing.value) { - VarManager::SetupTwoProngKFParticle(fConfigMagField.value); + if (fConfigOptions.useKFVertexing.value) { + VarManager::SetupTwoProngKFParticle(fConfigOptions.magField.value); } else { - VarManager::SetupTwoProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); // TODO: get these parameters from Configurables - VarManager::SetupTwoProngFwdDCAFitter(fConfigMagField.value, true, 200.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); + VarManager::SetupTwoProngDCAFitter(fConfigOptions.magField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); // TODO: get these parameters from Configurables + VarManager::SetupTwoProngFwdDCAFitter(fConfigOptions.magField.value, true, 200.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); } } else { - VarManager::SetupTwoProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); // needed because take in varmanager Bz from fgFitterTwoProngBarrel for PhiV calculations + VarManager::SetupTwoProngDCAFitter(fConfigOptions.magField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); // needed because take in varmanager Bz from fgFitterTwoProngBarrel for PhiV calculations } } + + std::map metadataRCT, header; + header = fCCDBApi.retrieveHeaders(Form("RCT/Info/RunInformation/%i", runNumber), metadataRCT, -1); + uint64_t sor = std::atol(header["SOR"].c_str()); + uint64_t eor = std::atol(header["EOR"].c_str()); + VarManager::SetSORandEOR(sor, eor); } // Template function to run same event pairing (barrel-barrel, muon-muon, barrel-muon) template void runSameEventPairing(TEvents const& events, Preslice& preslice, TTrackAssocs const& assocs, TTracks const& /*tracks*/) { - if (fCurrentRun != events.begin().runNumber()) { - initParamsFromCCDB(events.begin().timestamp(), TTwoProngFitter); - fCurrentRun = events.begin().runNumber(); + if (events.size() > 0) { // Additional protection to avoid crashing of events.begin().runNumber() + if (fCurrentRun != events.begin().runNumber()) { + initParamsFromCCDB(events.begin().timestamp(), events.begin().runNumber(), TTwoProngFitter); + fCurrentRun = events.begin().runNumber(); + } } - TString cutNames = fConfigTrackCuts.value; + TString cutNames = fConfigCuts.track.value; std::map> histNames = fTrackHistNames; int ncuts = fNCutsBarrel; + int histIdxOffset = 0; if constexpr (TPairType == pairTypeMuMu) { - cutNames = fConfigMuonCuts.value; + cutNames = fConfigCuts.muon.value; histNames = fMuonHistNames; ncuts = fNCutsMuon; + if (fEnableMuonMixingHistos) { + histIdxOffset = 3; + } } - int histIdxOffset = 0; if constexpr (TPairType == pairTypeEE) { if (fEnableBarrelMixingHistos) { histIdxOffset = 3; } } /*if constexpr (TPairType == pairTypeEMu) { - cutNames = fConfigMuonCuts.value; + cutNames = fConfigCuts.muon.value; histNames = fTrackMuonHistNames; }*/ - uint32_t twoTrackFilter = 0; + uint32_t twoTrackFilter = static_cast(0); + uint32_t dileptonMcDecision = static_cast(0); // placeholder, copy of the dqEfficiency.cxx one int sign1 = 0; int sign2 = 0; dielectronList.reserve(1); dimuonList.reserve(1); dielectronsExtraList.reserve(1); + dielectronInfoList.reserve(1); dimuonsExtraList.reserve(1); dileptonInfoList.reserve(1); - if (fConfigFlatTables.value) { + dileptonFlowList.reserve(1); + if (fConfigOptions.flatTables.value) { + dielectronAllList.reserve(1); dimuonAllList.reserve(1); } constexpr bool eventHasQvector = ((TEventFillMap & VarManager::ObjTypes::ReducedEventQvector) > 0); + constexpr bool eventHasQvectorCentr = ((TEventFillMap & VarManager::ObjTypes::CollisionQvect) > 0); constexpr bool trackHasCov = ((TTrackFillMap & VarManager::ObjTypes::TrackCov) > 0 || (TTrackFillMap & VarManager::ObjTypes::ReducedTrackBarrelCov) > 0); for (auto& event : events) { if (!event.isEventSelected_bit(0)) { continue; } + if (fConfigCuts.event && event.isEventSelected_bit(2)) { + continue; + } + uint8_t evSel = event.isEventSelected_raw(); // Reset the fValues array VarManager::ResetValues(0, VarManager::kNVars); - VarManager::FillEvent(event, VarManager::fgValues); + // VarManager::FillEvent(event, VarManager::fgValues); + VarManager::FillEvent(event, VarManager::fgValues); auto groupedAssocs = assocs.sliceBy(preslice, event.globalIndex()); if (groupedAssocs.size() == 0) { continue; } + bool isFirst = true; for (auto& [a1, a2] : o2::soa::combinations(groupedAssocs, groupedAssocs)) { - - if constexpr (TPairType == VarManager::kDecayToEE || TPairType == VarManager::kDecayToPiPi) { + if constexpr (TPairType == VarManager::kDecayToEE) { twoTrackFilter = a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & a1.isBarrelSelectedPrefilter_raw() & a2.isBarrelSelectedPrefilter_raw() & fTrackFilterMask; if (!twoTrackFilter) { // the tracks must have at least one filter bit in common to continue @@ -1154,22 +1569,27 @@ struct AnalysisSameEventPairing { sign1 = t1.sign(); sign2 = t2.sign(); // store the ambiguity number of the two dilepton legs in the last 4 digits of the two-track filter + // TODO: Make sure that we do not work with more than 28 track bits if (t1.barrelAmbiguityInBunch() > 1) { - twoTrackFilter |= (uint32_t(1) << 28); + twoTrackFilter |= (static_cast(1) << 28); } if (t2.barrelAmbiguityInBunch() > 1) { - twoTrackFilter |= (uint32_t(1) << 29); + twoTrackFilter |= (static_cast(1) << 29); } if (t1.barrelAmbiguityOutOfBunch() > 1) { - twoTrackFilter |= (uint32_t(1) << 30); + twoTrackFilter |= (static_cast(1) << 30); } if (t2.barrelAmbiguityOutOfBunch() > 1) { - twoTrackFilter |= (uint32_t(1) << 31); + twoTrackFilter |= (static_cast(1) << 31); } VarManager::FillPair(t1, t2); + // compute quantities which depend on the associated collision, such as DCA + if (fConfigOptions.propTrack) { + VarManager::FillPairCollision(event, t1, t2); + } if constexpr (TTwoProngFitter) { - VarManager::FillPairVertexing(event, t1, t2, fConfigPropToPCA); + VarManager::FillPairVertexing(event, t1, t2, fConfigOptions.propToPCA); } if constexpr (eventHasQvector) { VarManager::FillPairVn(t1, t2); @@ -1180,10 +1600,23 @@ struct AnalysisSameEventPairing { t1.sign() + t2.sign(), twoTrackFilter, 0); if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedTrackCollInfo) > 0) { + dielectronInfoList(t1.collisionId(), t1.trackId(), t2.trackId()); dileptonInfoList(t1.collisionId(), event.posX(), event.posY(), event.posZ()); } if constexpr (trackHasCov && TTwoProngFitter) { dielectronsExtraList(t1.globalIndex(), t2.globalIndex(), VarManager::fgValues[VarManager::kVertexingTauzProjected], VarManager::fgValues[VarManager::kVertexingLzProjected], VarManager::fgValues[VarManager::kVertexingLxyProjected]); + if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedTrackBarrelPID) > 0) { + if (fConfigOptions.flatTables.value) { + dielectronAllList(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), twoTrackFilter, dileptonMcDecision, + t1.pt(), t1.eta(), t1.phi(), t1.itsClusterMap(), t1.itsChi2NCl(), t1.tpcNClsCrossedRows(), t1.tpcNClsFound(), t1.tpcChi2NCl(), t1.dcaXY(), t1.dcaZ(), t1.tpcSignal(), t1.tpcNSigmaEl(), t1.tpcNSigmaPi(), t1.tpcNSigmaPr(), t1.beta(), t1.tofNSigmaEl(), t1.tofNSigmaPi(), t1.tofNSigmaPr(), + t2.pt(), t2.eta(), t2.phi(), t2.itsClusterMap(), t2.itsChi2NCl(), t2.tpcNClsCrossedRows(), t2.tpcNClsFound(), t2.tpcChi2NCl(), t2.dcaXY(), t2.dcaZ(), t2.tpcSignal(), t2.tpcNSigmaEl(), t2.tpcNSigmaPi(), t2.tpcNSigmaPr(), t2.beta(), t2.tofNSigmaEl(), t2.tofNSigmaPi(), t2.tofNSigmaPr(), + VarManager::fgValues[VarManager::kKFTrack0DCAxyz], VarManager::fgValues[VarManager::kKFTrack1DCAxyz], VarManager::fgValues[VarManager::kKFDCAxyzBetweenProngs], VarManager::fgValues[VarManager::kKFTrack0DCAxy], VarManager::fgValues[VarManager::kKFTrack1DCAxy], VarManager::fgValues[VarManager::kKFDCAxyBetweenProngs], + VarManager::fgValues[VarManager::kKFTrack0DeviationFromPV], VarManager::fgValues[VarManager::kKFTrack1DeviationFromPV], VarManager::fgValues[VarManager::kKFTrack0DeviationxyFromPV], VarManager::fgValues[VarManager::kKFTrack1DeviationxyFromPV], + VarManager::fgValues[VarManager::kKFMass], VarManager::fgValues[VarManager::kKFChi2OverNDFGeo], VarManager::fgValues[VarManager::kVertexingLxyz], VarManager::fgValues[VarManager::kVertexingLxyzOverErr], VarManager::fgValues[VarManager::kVertexingLxy], VarManager::fgValues[VarManager::kVertexingLxyOverErr], VarManager::fgValues[VarManager::kVertexingTauxy], VarManager::fgValues[VarManager::kVertexingTauxyErr], VarManager::fgValues[VarManager::kKFCosPA], VarManager::fgValues[VarManager::kKFJpsiDCAxyz], VarManager::fgValues[VarManager::kKFJpsiDCAxy], + VarManager::fgValues[VarManager::kKFPairDeviationFromPV], VarManager::fgValues[VarManager::kKFPairDeviationxyFromPV], + VarManager::fgValues[VarManager::kKFMassGeoTop], VarManager::fgValues[VarManager::kKFChi2OverNDFGeoTop]); + } + } } } @@ -1195,12 +1628,33 @@ struct AnalysisSameEventPairing { auto t1 = a1.template reducedmuon_as(); auto t2 = a2.template reducedmuon_as(); + if (t1.matchMCHTrackId() == t2.matchMCHTrackId() && t1.matchMCHTrackId() >= 0) + continue; + if (t1.matchMFTTrackId() == t2.matchMFTTrackId() && t1.matchMFTTrackId() >= 0) + continue; sign1 = t1.sign(); sign2 = t2.sign(); + // store the ambiguity number of the two dilepton legs in the last 4 digits of the two-track filter + if (t1.muonAmbiguityInBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 28); + } + if (t2.muonAmbiguityInBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 29); + } + if (t1.muonAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 30); + } + if (t2.muonAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 31); + } VarManager::FillPair(t1, t2); + // compute quantities which depend on the associated collision, such as DCA + if (fConfigOptions.propTrack) { + VarManager::FillPairCollision(event, t1, t2); + } if constexpr (TTwoProngFitter) { - VarManager::FillPairVertexing(event, t1, t2, fConfigPropToPCA); + VarManager::FillPairVertexing(event, t1, t2, fConfigOptions.propToPCA); } if constexpr (eventHasQvector) { VarManager::FillPairVn(t1, t2); @@ -1215,8 +1669,9 @@ struct AnalysisSameEventPairing { if constexpr (TTwoProngFitter) { dimuonsExtraList(t1.globalIndex(), t2.globalIndex(), VarManager::fgValues[VarManager::kVertexingTauz], VarManager::fgValues[VarManager::kVertexingLz], VarManager::fgValues[VarManager::kVertexingLxy]); - if (fConfigFlatTables.value) { + if (fConfigOptions.flatTables.value) { dimuonAllList(event.posX(), event.posY(), event.posZ(), event.numContrib(), + event.selection_raw(), evSel, -999., -999., -999., VarManager::fgValues[VarManager::kMass], false, @@ -1235,13 +1690,29 @@ struct AnalysisSameEventPairing { -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., -999., - t1.isAmbiguous(), t2.isAmbiguous(), + (twoTrackFilter & (static_cast(1) << 28)) || (twoTrackFilter & (static_cast(1) << 29)), (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)), VarManager::fgValues[VarManager::kU2Q2], VarManager::fgValues[VarManager::kU3Q3], - VarManager::fgValues[VarManager::kR2EP], VarManager::fgValues[VarManager::kR2SP], VarManager::fgValues[VarManager::kCentFT0C], + VarManager::fgValues[VarManager::kR2EP_AB], VarManager::fgValues[VarManager::kR2SP_AB], VarManager::fgValues[VarManager::kCentFT0C], VarManager::fgValues[VarManager::kCos2DeltaPhi], VarManager::fgValues[VarManager::kCos3DeltaPhi], - VarManager::fgValues[VarManager::kCORR4POI], VarManager::fgValues[VarManager::kCORR2POI], VarManager::fgValues[VarManager::kM01POI], VarManager::fgValues[VarManager::kM0111POI], VarManager::fgValues[VarManager::kMultDimuons], + VarManager::fgValues[VarManager::kCORR2POI], VarManager::fgValues[VarManager::kCORR4POI], VarManager::fgValues[VarManager::kM01POI], VarManager::fgValues[VarManager::kM0111POI], VarManager::fgValues[VarManager::kMultDimuons], VarManager::fgValues[VarManager::kVertexingPz], VarManager::fgValues[VarManager::kVertexingSV]); } + if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedMuonCollInfo) > 0) { + if constexpr (eventHasQvector == true || eventHasQvectorCentr == true) { + dileptonFlowList(t1.collisionId(), VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kCentFT0C], + VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), isFirst, + VarManager::fgValues[VarManager::kU2Q2], VarManager::fgValues[VarManager::kR2SP_AB], VarManager::fgValues[VarManager::kR2SP_AC], VarManager::fgValues[VarManager::kR2SP_BC], + VarManager::fgValues[VarManager::kU3Q3], VarManager::fgValues[VarManager::kR3SP], + VarManager::fgValues[VarManager::kCos2DeltaPhi], VarManager::fgValues[VarManager::kR2EP_AB], VarManager::fgValues[VarManager::kR2EP_AC], VarManager::fgValues[VarManager::kR2EP_BC], + VarManager::fgValues[VarManager::kCos3DeltaPhi], VarManager::fgValues[VarManager::kR3EP], + VarManager::fgValues[VarManager::kCORR2POI], VarManager::fgValues[VarManager::kCORR4POI], VarManager::fgValues[VarManager::kM01POI], VarManager::fgValues[VarManager::kM0111POI], + VarManager::fgValues[VarManager::kCORR2REF], VarManager::fgValues[VarManager::kCORR4REF], VarManager::fgValues[VarManager::kM11REF], VarManager::fgValues[VarManager::kM1111REF], + VarManager::fgValues[VarManager::kMultDimuons], VarManager::fgValues[VarManager::kMultA]); + } + } + } + if (t1.sign() != t2.sign()) { + isFirst = false; } } // TODO: the model for the electron-muon combination has to be thought through @@ -1249,26 +1720,29 @@ struct AnalysisSameEventPairing { twoTrackFilter = a1.isBarrelSelected_raw() & a1.isBarrelSelectedPrefilter_raw() & a2.isMuonSelected_raw() & fTwoTrackFilterMask; }*/ - if constexpr (eventHasQvector) { - dileptonFlowList(VarManager::fgValues[VarManager::kU2Q2], VarManager::fgValues[VarManager::kU3Q3], VarManager::fgValues[VarManager::kCos2DeltaPhi], VarManager::fgValues[VarManager::kCos3DeltaPhi]); - refFlowDimuonList(VarManager::fgValues[VarManager::kCORR2REF], VarManager::fgValues[VarManager::kCORR4REF], VarManager::fgValues[VarManager::kM11REF], VarManager::fgValues[VarManager::kM1111REF], VarManager::fgValues[VarManager::kCentFT0C], VarManager::fgValues[VarManager::kMultA]); - } - // Fill histograms bool isAmbiInBunch = false; bool isAmbiOutOfBunch = false; + bool isUnambiguous = false; for (int icut = 0; icut < ncuts; icut++) { - if (twoTrackFilter & (uint32_t(1) << icut)) { - isAmbiInBunch = (twoTrackFilter & (uint32_t(1) << 28)) || (twoTrackFilter & (uint32_t(1) << 29)); - isAmbiOutOfBunch = (twoTrackFilter & (uint32_t(1) << 30)) || (twoTrackFilter & (uint32_t(1) << 31)); + if (twoTrackFilter & (static_cast(1) << icut)) { + isAmbiInBunch = (twoTrackFilter & (static_cast(1) << 28)) || (twoTrackFilter & (static_cast(1) << 29)); + isAmbiOutOfBunch = (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)); + isUnambiguous = !(isAmbiInBunch || isAmbiOutOfBunch); if (sign1 * sign2 < 0) { fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); + PromptNonPromptSepTable(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kVertexingTauxyProjected], VarManager::fgValues[VarManager::kVertexingTauxyProjectedPoleJPsiMass], VarManager::fgValues[VarManager::kVertexingTauzProjected], isAmbiInBunch, isAmbiOutOfBunch); if (isAmbiInBunch) { fHistMan->FillHistClass(histNames[icut][3 + histIdxOffset].Data(), VarManager::fgValues); } if (isAmbiOutOfBunch) { fHistMan->FillHistClass(histNames[icut][3 + histIdxOffset + 3].Data(), VarManager::fgValues); } + if constexpr (TPairType == VarManager::kDecayToMuMu) { + if (isUnambiguous) { + fHistMan->FillHistClass(histNames[icut][3 + histIdxOffset + 6].Data(), VarManager::fgValues); + } + } } else { if (sign1 > 0) { fHistMan->FillHistClass(histNames[icut][1].Data(), VarManager::fgValues); @@ -1278,6 +1752,11 @@ struct AnalysisSameEventPairing { if (isAmbiOutOfBunch) { fHistMan->FillHistClass(histNames[icut][4 + histIdxOffset + 3].Data(), VarManager::fgValues); } + if constexpr (TPairType == VarManager::kDecayToMuMu) { + if (isUnambiguous) { + fHistMan->FillHistClass(histNames[icut][4 + histIdxOffset + 6].Data(), VarManager::fgValues); + } + } } else { fHistMan->FillHistClass(histNames[icut][2].Data(), VarManager::fgValues); if (isAmbiInBunch) { @@ -1286,6 +1765,11 @@ struct AnalysisSameEventPairing { if (isAmbiOutOfBunch) { fHistMan->FillHistClass(histNames[icut][5 + histIdxOffset + 3].Data(), VarManager::fgValues); } + if constexpr (TPairType == VarManager::kDecayToMuMu) { + if (isUnambiguous) { + fHistMan->FillHistClass(histNames[icut][5 + histIdxOffset + 6].Data(), VarManager::fgValues); + } + } } } for (unsigned int iPairCut = 0; iPairCut < fPairCuts.size(); iPairCut++) { @@ -1304,8 +1788,8 @@ struct AnalysisSameEventPairing { } // end loop (pair cuts) } } // end loop (cuts) - } // end loop over pairs of track associations - } // end loop over events + } // end loop over pairs of track associations + } // end loop over events } template @@ -1314,7 +1798,7 @@ struct AnalysisSameEventPairing { std::map> histNames = fTrackHistNames; int pairSign = 0; int ncuts = 0; - uint32_t twoTrackFilter = 0; + uint32_t twoTrackFilter = static_cast(0); for (auto& a1 : assocs1) { for (auto& a2 : assocs2) { if constexpr (TPairType == VarManager::kDecayToEE) { @@ -1323,10 +1807,10 @@ struct AnalysisSameEventPairing { continue; } auto t1 = a1.template reducedtrack_as(); - auto t2 = a1.template reducedtrack_as(); - VarManager::FillPairME(t1, t2); + auto t2 = a2.template reducedtrack_as(); + VarManager::FillPairME(t1, t2); if constexpr ((TEventFillMap & VarManager::ObjTypes::ReducedEventQvector) > 0) { - VarManager::FillPairVn(t1, t2); + VarManager::FillPairVn(t1, t2); } pairSign = t1.sign() + t2.sign(); ncuts = fNCutsBarrel; @@ -1337,34 +1821,120 @@ struct AnalysisSameEventPairing { continue; } auto t1 = a1.template reducedmuon_as(); - auto t2 = a1.template reducedmuon_as(); - VarManager::FillPairME(t1, t2); + auto t2 = a2.template reducedmuon_as(); + if (t1.matchMCHTrackId() == t2.matchMCHTrackId()) + continue; + if (t1.matchMFTTrackId() == t2.matchMFTTrackId()) + continue; + VarManager::FillPairME(t1, t2); if constexpr ((TEventFillMap & VarManager::ObjTypes::ReducedEventQvector) > 0) { - VarManager::FillPairVn(t1, t2); + VarManager::FillPairVn(t1, t2); + } + pairSign = t1.sign() + t2.sign(); + // store the ambiguity number of the two dilepton legs in the last 4 digits of the two-track filter + if (t1.muonAmbiguityInBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 28); + } + if (t2.muonAmbiguityInBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 29); + } + if (t1.muonAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 30); + } + if (t2.muonAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 31); } ncuts = fNCutsMuon; histNames = fMuonHistNames; + + if (fConfigOptions.flatTables.value) { + dimuonAllList(-999., -999., -999., -999., + 0, 0, + -999., -999., -999., + VarManager::fgValues[VarManager::kMass], + false, + VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), VarManager::fgValues[VarManager::kVertexingChi2PCA], + VarManager::fgValues[VarManager::kVertexingTauz], VarManager::fgValues[VarManager::kVertexingTauzErr], + VarManager::fgValues[VarManager::kVertexingTauxy], VarManager::fgValues[VarManager::kVertexingTauxyErr], + VarManager::fgValues[VarManager::kCosPointingAngle], + t1.pt(), t1.eta(), t1.phi(), t1.sign(), + t2.pt(), t2.eta(), t2.phi(), t2.sign(), + t1.fwdDcaX(), t1.fwdDcaY(), t2.fwdDcaX(), t2.fwdDcaY(), + 0., 0., + t1.chi2MatchMCHMID(), t2.chi2MatchMCHMID(), + t1.chi2MatchMCHMFT(), t2.chi2MatchMCHMFT(), + t1.chi2(), t2.chi2(), + -999., -999., -999., -999., + -999., -999., -999., -999., + -999., -999., -999., -999., + -999., -999., -999., -999., + (twoTrackFilter & (static_cast(1) << 28)) || (twoTrackFilter & (static_cast(1) << 29)), (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)), + VarManager::fgValues[VarManager::kU2Q2], VarManager::fgValues[VarManager::kU3Q3], + VarManager::fgValues[VarManager::kR2EP_AB], VarManager::fgValues[VarManager::kR2SP_AB], VarManager::fgValues[VarManager::kCentFT0C], + VarManager::fgValues[VarManager::kCos2DeltaPhi], VarManager::fgValues[VarManager::kCos3DeltaPhi], + VarManager::fgValues[VarManager::kCORR2POI], VarManager::fgValues[VarManager::kCORR4POI], VarManager::fgValues[VarManager::kM01POI], VarManager::fgValues[VarManager::kM0111POI], VarManager::fgValues[VarManager::kMultDimuons], + VarManager::fgValues[VarManager::kVertexingPz], VarManager::fgValues[VarManager::kVertexingSV]); + } } /*if constexpr (TPairType == VarManager::kElectronMuon) { twoTrackFilter = a1.isBarrelSelected_raw() & a1.isBarrelSelectedPrefilter_raw() & a2.isMuonSelected_raw() & fTrackFilterMask; }*/ + bool isAmbiInBunch = false; + bool isAmbiOutOfBunch = false; + bool isUnambiguous = false; for (int icut = 0; icut < ncuts; icut++) { - if (!(twoTrackFilter & (uint32_t(1) << icut))) { + if (!(twoTrackFilter & (static_cast(1) << icut))) { continue; // cut not passed } + isAmbiInBunch = (twoTrackFilter & (static_cast(1) << 28)) || (twoTrackFilter & (static_cast(1) << 29)); + isAmbiOutOfBunch = (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)); + isUnambiguous = !((twoTrackFilter & (static_cast(1) << 28)) || (twoTrackFilter & (static_cast(1) << 29)) || (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31))); if (pairSign == 0) { fHistMan->FillHistClass(histNames[icut][3].Data(), VarManager::fgValues); + if constexpr (TPairType == VarManager::kDecayToMuMu) { + if (isAmbiInBunch) { + fHistMan->FillHistClass(histNames[icut][15].Data(), VarManager::fgValues); + } + if (isAmbiOutOfBunch) { + fHistMan->FillHistClass(histNames[icut][18].Data(), VarManager::fgValues); + } + if (isUnambiguous) { + fHistMan->FillHistClass(histNames[icut][21].Data(), VarManager::fgValues); + } + } } else { if (pairSign > 0) { fHistMan->FillHistClass(histNames[icut][4].Data(), VarManager::fgValues); + if constexpr (TPairType == VarManager::kDecayToMuMu) { + if (isAmbiInBunch) { + fHistMan->FillHistClass(histNames[icut][16].Data(), VarManager::fgValues); + } + if (isAmbiOutOfBunch) { + fHistMan->FillHistClass(histNames[icut][19].Data(), VarManager::fgValues); + } + if (isUnambiguous) { + fHistMan->FillHistClass(histNames[icut][22].Data(), VarManager::fgValues); + } + } } else { fHistMan->FillHistClass(histNames[icut][5].Data(), VarManager::fgValues); + if constexpr (TPairType == VarManager::kDecayToMuMu) { + if (isAmbiInBunch) { + fHistMan->FillHistClass(histNames[icut][17].Data(), VarManager::fgValues); + } + if (isAmbiOutOfBunch) { + fHistMan->FillHistClass(histNames[icut][20].Data(), VarManager::fgValues); + } + if (isUnambiguous) { + fHistMan->FillHistClass(histNames[icut][23].Data(), VarManager::fgValues); + } + } } } } // end for (cuts) - } // end for (track2) - } // end for (track1) + } // end for (track2) + } // end for (track1) } // barrel-barrel and muon-muon event mixing @@ -1389,7 +1959,7 @@ struct AnalysisSameEventPairing { void processAllSkimmed(MyEventsVtxCovSelected const& events, soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, - soa::Join const& muonAssocs, MyMuonTracksWithCov const& muons) + soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); runSameEventPairing(events, muonAssocsPerCollision, muonAssocs, muons); @@ -1403,17 +1973,56 @@ struct AnalysisSameEventPairing { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); } + void processBarrelOnlySkimmedNoCov(MyEventsSelected const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithAmbiguities const& barrelTracks) + { + runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); + } + + void processBarrelOnlySkimmedNoCovWithMultExtra(MyEventsMultExtraSelected const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithAmbiguities const& barrelTracks) + { + runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); + } + + void processBarrelOnlyWithCollSkimmed(MyEventsVtxCovSelected const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithCovWithAmbiguitiesWithColl const& barrelTracks) + { + runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); + } + void processMuonOnlySkimmed(MyEventsVtxCovSelected const& events, - soa::Join const& muonAssocs, MyMuonTracksWithCov const& muons) + soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) { runSameEventPairing(events, muonAssocsPerCollision, muonAssocs, muons); } + void processMuonOnlySkimmedMultExtra(MyEventsVtxCovSelectedMultExtra const& events, + soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) + { + runSameEventPairing(events, muonAssocsPerCollision, muonAssocs, muons); + } + void processMixingAllSkimmed(soa::Filtered& events, soa::Join const& trackAssocs, MyBarrelTracksWithCov const& tracks, - soa::Join const& muonAssocs, MyMuonTracksWithCov const& muons) + soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) + { + runSameSideMixing(events, trackAssocs, tracks, trackAssocsPerCollision); + runSameSideMixing(events, muonAssocs, muons, muonAssocsPerCollision); + } + + void processMixingBarrelSkimmed(soa::Filtered& events, + soa::Join const& trackAssocs, aod::ReducedTracks const& tracks) { runSameSideMixing(events, trackAssocs, tracks, trackAssocsPerCollision); + } + + void processMixingMuonSkimmed(soa::Filtered& events, + soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) + { runSameSideMixing(events, muonAssocs, muons, muonAssocsPerCollision); } @@ -1424,11 +2033,768 @@ struct AnalysisSameEventPairing { PROCESS_SWITCH(AnalysisSameEventPairing, processAllSkimmed, "Run all types of pairing, with skimmed tracks/muons", false); PROCESS_SWITCH(AnalysisSameEventPairing, processBarrelOnlySkimmed, "Run barrel only pairing, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processBarrelOnlyWithCollSkimmed, "Run barrel only pairing, with skimmed tracks and with collision information", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processBarrelOnlySkimmedNoCov, "Run barrel only pairing (no covariances), with skimmed tracks and with collision information", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processBarrelOnlySkimmedNoCovWithMultExtra, "Run barrel only pairing (no covariances), with skimmed tracks, with collision information, with MultsExtra", false); PROCESS_SWITCH(AnalysisSameEventPairing, processMuonOnlySkimmed, "Run muon only pairing, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processMuonOnlySkimmedMultExtra, "Run muon only pairing, with skimmed tracks", false); PROCESS_SWITCH(AnalysisSameEventPairing, processMixingAllSkimmed, "Run all types of mixed pairing, with skimmed tracks/muons", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processMixingBarrelSkimmed, "Run barrel type mixing pairing, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processMixingMuonSkimmed, "Run muon type mixing pairing, with skimmed muons", false); PROCESS_SWITCH(AnalysisSameEventPairing, processDummy, "Dummy function, enabled only if none of the others are enabled", false); }; +// Run pairing for resonance with legs fulfilling separate cuts (asymmetric decay channel) +struct AnalysisAsymmetricPairing { + + Produces ditrackList; + Produces ditrackExtraList; + + o2::base::MatLayerCylSet* fLUT = nullptr; + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + + // Output objects + OutputObj fOutputList{"output"}; + + // Configurables + Configurable fConfigLegCuts{"cfgLegCuts", "", ":[:],[:[:],...]"}; + Configurable fConfigLegAFilterMask{"cfgLegAFilterMask", 0, "Filter mask corresponding to cuts in track-selection"}; + Configurable fConfigLegBFilterMask{"cfgLegBFilterMask", 0, "Filter mask corresponding to cuts in track-selection"}; + Configurable fConfigLegCFilterMask{"cfgLegCFilterMask", 0, "Filter mask corresponding to cuts in track-selection"}; + Configurable fConfigCommonTrackCuts{"cfgCommonTrackCuts", "", "Comma separated list of cuts to be applied to all legs"}; + Configurable fConfigPairCuts{"cfgPairCuts", "", "Comma separated list of pair cuts"}; + Configurable fConfigPairCutsJSON{"cfgPairCutsJSON", "", "Additional list of pair cuts in JSON format"}; + Configurable fConfigSkipAmbiguousIdCombinations{"cfgSkipAmbiguousIdCombinations", true, "Choose whether to skip pairs/triples which pass a stricter combination of cuts, e.g. KKPi triplets for D+ -> KPiPi"}; + + Configurable fConfigHistogramSubgroups{"cfgAsymmetricPairingHistogramsSubgroups", "barrel,vertexing", "Comma separated list of asymmetric-pairing histogram subgroups"}; + Configurable fConfigSameSignHistograms{"cfgSameSignHistograms", false, "Include same sign pair histograms for 2-prong decays"}; + Configurable fConfigAmbiguousHistograms{"cfgAmbiguousHistograms", false, "Include separate histograms for pairs/triplets with ambiguous tracks"}; + Configurable fConfigReflectedHistograms{"cfgReflectedHistograms", false, "Include separate histograms for pairs which are reflections of previously counted pairs"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable fConfigGRPMagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable fConfigUseRemoteField{"cfgUseRemoteField", false, "Choose whether to fetch the magnetic field from ccdb or set it manually"}; + Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; + + Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; + Configurable fConfigUseAbsDCA{"cfgUseAbsDCA", false, "Use absolute DCA minimization instead of chi^2 minimization in secondary vertexing"}; + Configurable fConfigPropToPCA{"cfgPropToPCA", false, "Propagate tracks to secondary vertex"}; + Configurable fConfigLutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + + Service fCCDB; + + HistogramManager* fHistMan; + + std::map> fTrackHistNames; + std::vector fPairCuts; + int fNPairHistPrefixes; + + // Filter masks to find legs in BarrelTrackCuts table + uint32_t fLegAFilterMask; + uint32_t fLegBFilterMask; + uint32_t fLegCFilterMask; + // Maps tracking which combination of leg cuts the track cuts participate in + std::map fConstructedLegAFilterMasksMap; + std::map fConstructedLegBFilterMasksMap; + std::map fConstructedLegCFilterMasksMap; + // Filter map for common track cuts + uint32_t fCommonTrackCutMask; + // Map tracking which common track cut the track cuts correspond to + std::map fCommonTrackCutFilterMasks; + + int fNLegCuts; + int fNPairCuts; + int fNCommonTrackCuts; + + Preslice> trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + + // Partitions for triplets and asymmetric pairs + Partition> legACandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegAFilterMask) > static_cast(0); + Partition> legBCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegBFilterMask) > static_cast(0); + Partition> legCCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegCFilterMask) > static_cast(0); + + // Map to track how many times a pair of tracks has been encountered + std::map, int8_t> fPairCount; + + void init(o2::framework::InitContext& context) + { + if (context.mOptions.get("processDummy")) { + return; + } + VarManager::SetDefaultVarNames(); + + TString histNames = ""; + std::vector names; + + // Get the leg cut filter maps + fLegAFilterMask = fConfigLegAFilterMask.value; + fLegBFilterMask = fConfigLegBFilterMask.value; + fLegCFilterMask = fConfigLegCFilterMask.value; + // Get the pair cuts + TString cutNamesStr = fConfigPairCuts.value; + if (!cutNamesStr.IsNull()) { + std::unique_ptr objArray(cutNamesStr.Tokenize(",")); + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + fPairCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + } + } + // Extra pair cuts via JSON + TString addPairCutsStr = fConfigPairCutsJSON.value; + if (addPairCutsStr != "") { + std::vector addPairCuts = dqcuts::GetCutsFromJSON(addPairCutsStr.Data()); + for (auto& t : addPairCuts) { + fPairCuts.push_back((AnalysisCompositeCut*)t); + cutNamesStr += Form(",%s", t->GetName()); + } + } + // Get the barrel track selection cuts + string tempCuts; + getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", tempCuts, false); + TString tempCutsStr = tempCuts; + // check also the cuts added via JSON and add them to the string of cuts + getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", tempCuts, false); + TString addTrackCutsStr = tempCuts; + if (addTrackCutsStr != "") { + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + for (auto& t : addTrackCuts) { + tempCutsStr += Form(",%s", t->GetName()); + } + } + std::unique_ptr objArray(tempCutsStr.Tokenize(",")); + // Get the common leg cuts + int commonCutIdx; + TString commonNamesStr = fConfigCommonTrackCuts.value; + if (!commonNamesStr.IsNull()) { // if common track cuts + std::unique_ptr objArrayCommon(commonNamesStr.Tokenize(",")); + fNCommonTrackCuts = objArrayCommon->GetEntries(); + for (int icut = 0; icut < fNCommonTrackCuts; ++icut) { + commonCutIdx = objArray->IndexOf(objArrayCommon->At(icut)); + if (commonCutIdx >= 0) { + fCommonTrackCutMask |= static_cast(1) << objArray->IndexOf(objArrayCommon->At(icut)); + fCommonTrackCutFilterMasks[icut] = static_cast(1) << objArray->IndexOf(objArrayCommon->At(icut)); + } else { + LOGF(fatal, "Common track cut %s was not calculated upstream. Check the config!", objArrayCommon->At(icut)->GetName()); + } + } + } + // Check that the leg cut masks make sense + if (static_cast(std::floor(TMath::Log2(fLegAFilterMask))) + 1 > objArray->GetEntries()) { + LOGF(fatal, "fConfigLegAFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(TMath::Log2(fLegAFilterMask))) + 1, objArray->GetEntries()); + } + if (static_cast(std::floor(TMath::Log2(fLegBFilterMask))) + 1 > objArray->GetEntries()) { + LOGF(fatal, "fConfigLegBFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(TMath::Log2(fLegBFilterMask))) + 1, objArray->GetEntries()); + } + if (static_cast(std::floor(TMath::Log2(fLegCFilterMask))) + 1 > objArray->GetEntries()) { + LOGF(fatal, "fConfigLegCFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(TMath::Log2(fLegCFilterMask))) + 1, objArray->GetEntries()); + } + + // Get the cuts defining the legs + uint32_t fConstructedLegAFilterMask = 0; + uint32_t fConstructedLegBFilterMask = 0; + uint32_t fConstructedLegCFilterMask = 0; + TString legCutsStr = fConfigLegCuts.value; + std::unique_ptr objArrayLegs(legCutsStr.Tokenize(",")); + if (objArrayLegs->GetEntries() == 0) { + LOG(fatal) << "No cuts defining legs. Check the config!"; + } + fNLegCuts = objArrayLegs->GetEntries(); + std::vector isThreeProng; + int legAIdx; + int legBIdx; + int legCIdx; + // Loop over leg defining cuts + for (int icut = 0; icut < fNLegCuts; ++icut) { + TString legsStr = objArrayLegs->At(icut)->GetName(); + std::unique_ptr legs(legsStr.Tokenize(":")); + if (legs->GetEntries() == 3) { + isThreeProng.push_back(true); + } else if (legs->GetEntries() == 2) { + isThreeProng.push_back(false); + } else { + LOGF(fatal, "Leg cuts %s has the wrong format and could not be parsed!", legsStr.Data()); + continue; + } + // Find leg cuts in the track selection cuts + legAIdx = objArray->IndexOf(legs->At(0)); + if (legAIdx >= 0) { + fConstructedLegAFilterMask |= (static_cast(1) << legAIdx); + fConstructedLegAFilterMasksMap[icut] |= static_cast(1) << legAIdx; + } else { + LOGF(fatal, "Leg A cut %s was not calculated upstream. Check the config!", legs->At(0)->GetName()); + continue; + } + legBIdx = objArray->IndexOf(legs->At(1)); + if (legBIdx >= 0) { + fConstructedLegBFilterMask |= (static_cast(1) << legBIdx); + fConstructedLegBFilterMasksMap[icut] |= static_cast(1) << legBIdx; + } else { + LOGF(fatal, "Leg B cut %s was not calculated upstream. Check the config!", legs->At(1)->GetName()); + continue; + } + if (isThreeProng[icut]) { + legCIdx = objArray->IndexOf(legs->At(2)); + if (legCIdx >= 0) { + fConstructedLegCFilterMask |= (static_cast(1) << legCIdx); + fConstructedLegCFilterMasksMap[icut] |= static_cast(1) << legCIdx; + } else { + LOGF(fatal, "Leg C cut %s was not calculated upstream. Check the config!", legs->At(2)->GetName()); + continue; + } + } + if (isThreeProng[icut]) { + names = { + Form("TripletsBarrelSE_%s", legsStr.Data())}; + histNames += Form("%s;", names[0].Data()); + if (fConfigAmbiguousHistograms.value) { + names.push_back(Form("TripletsBarrelSE_ambiguous_%s", legsStr.Data())); + histNames += Form("%s;", names[1].Data()); + } + fTrackHistNames[icut] = names; + + std::unique_ptr objArrayCommon(commonNamesStr.Tokenize(",")); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + names = {}; + names.push_back(Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName())); + histNames += Form("%s;", names[0].Data()); + fTrackHistNames[fNLegCuts + icut * fNCommonTrackCuts + iCommonCut] = names; + } + + if (!cutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + fNPairCuts = objArrayPair->GetEntries(); + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts + names = {}; + names.push_back(Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayPair->At(iPairCut)->GetName())); + histNames += Form("%s;", names[0].Data()); + fTrackHistNames[fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut] = names; + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + names = {}; + names.push_back(Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName())); + histNames += Form("%s;", names[0].Data()); + fTrackHistNames[(fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + (icut * fNPairCuts * fNCommonTrackCuts) + (iCommonCut * fNPairCuts) + iPairCut] = names; + } // end loop (common cuts) + } // end loop (pair cuts) + } // end if (pair cuts) + } else { + names = {}; + std::vector pairHistPrefixes = {"PairsBarrelSEPM"}; + if (fConfigSameSignHistograms.value) { + pairHistPrefixes.push_back("PairsBarrelSEPP"); + pairHistPrefixes.push_back("PairsBarrelSEMM"); + } + fNPairHistPrefixes = pairHistPrefixes.size(); + + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + names.push_back(Form("%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data())); + histNames += Form("%s;", names[iPrefix].Data()); + } + if (fConfigAmbiguousHistograms.value) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + names.push_back(Form("%s_ambiguous_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data())); + histNames += Form("%s;", names[fNPairHistPrefixes + iPrefix].Data()); + } + } + if (fConfigReflectedHistograms.value) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + names.push_back(Form("%s_reflected_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data())); + histNames += Form("%s;", names[(1 + fConfigAmbiguousHistograms.value) * fNPairHistPrefixes + iPrefix].Data()); + } + } + fTrackHistNames[icut] = names; + + std::unique_ptr objArrayCommon(commonNamesStr.Tokenize(",")); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + names = {}; + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + names.push_back(Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName())); + histNames += Form("%s;", names[iPrefix].Data()); + } + fTrackHistNames[fNLegCuts + icut * fNCommonTrackCuts + iCommonCut] = names; + } + + if (!cutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + fNPairCuts = objArrayPair->GetEntries(); + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts + names = {}; + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + names.push_back(Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayPair->At(iPairCut)->GetName())); + histNames += Form("%s;", names[iPrefix].Data()); + } + fTrackHistNames[fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut] = names; + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + names = {}; + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + names.push_back(Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName())); + histNames += Form("%s;", names[iPrefix].Data()); + } + fTrackHistNames[(fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + (icut * fNPairCuts * fNCommonTrackCuts) + (iCommonCut * fNPairCuts) + iPairCut] = names; + } // end loop (common cuts) + } // end loop (pair cuts) + } // end if (pair cuts) + } + } + + // Make sure the leg cuts are covered by the configured filter masks + if (fLegAFilterMask != fConstructedLegAFilterMask) { + LOGF(fatal, "cfgLegAFilterMask (%d) is not equal to the mask constructed by the cuts specified in cfgLegCuts (%d)!", fLegAFilterMask, fConstructedLegAFilterMask); + } + if (fLegBFilterMask != fConstructedLegBFilterMask) { + LOGF(fatal, "cfgLegBFilterMask (%d) is not equal to the mask constructed by the cuts specified in cfgLegCuts (%d)!", fLegBFilterMask, fConstructedLegBFilterMask); + } + if (fLegCFilterMask != fConstructedLegCFilterMask) { + LOGF(fatal, "cfgLegCFilterMask (%d) is not equal to the mask constructed by the cuts specified in cfgLegCuts (%d)!", fLegCFilterMask, fConstructedLegCFilterMask); + } + // Make sure only pairs or only triplets of leg cuts were given + int tripletCheckSum = std::count(isThreeProng.begin(), isThreeProng.end(), true); + if (tripletCheckSum != 0 && tripletCheckSum != fNLegCuts) { + LOGF(fatal, "A mix of pairs and triplets was given as leg cuts. Check your config!"); + } + + fCurrentRun = 0; + + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + + fLUT = o2::base::MatLayerCylSet::rectifyPtrFromFile(fCCDB->get(fConfigLutPath)); + VarManager::SetupMatLUTFwdDCAFitter(fLUT); + + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + DefineHistograms(fHistMan, histNames.Data(), fConfigHistogramSubgroups.value.data()); // define all histograms + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } + + void initParamsFromCCDB(uint64_t timestamp, bool isTriplets) + { + if (fConfigUseRemoteField.value) { + o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(fConfigGRPMagPath, timestamp); + float magField = 0.0; + if (grpmag != nullptr) { + magField = grpmag->getNominalL3Field(); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", timestamp); + } + if (isTriplets) { + if (fConfigUseKFVertexing.value) { + VarManager::SetupThreeProngKFParticle(magField); + } else { + VarManager::SetupThreeProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); + } + } else { + if (fConfigUseKFVertexing.value) { + VarManager::SetupTwoProngKFParticle(magField); + } else { + VarManager::SetupTwoProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); // TODO: get these parameters from Configurables + } + } + } else { + if (isTriplets) { + if (fConfigUseKFVertexing.value) { + VarManager::SetupThreeProngKFParticle(fConfigMagField.value); + } else { + VarManager::SetupThreeProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); + } + } else { + if (fConfigUseKFVertexing.value) { + VarManager::SetupTwoProngKFParticle(fConfigMagField.value); + } else { + VarManager::SetupTwoProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); // TODO: get these parameters from Configurables + } + } + } + } + + // Template function to run same event pairing with asymmetric pairs (e.g. kaon-pion) + template + void runAsymmetricPairing(TEvents const& events, Preslice& preslice, TTrackAssocs const& /*assocs*/, TTracks const& /*tracks*/) + { + fPairCount.clear(); + + if (events.size() > 0) { // Additional protection to avoid crashing of events.begin().runNumber() + if (fCurrentRun != events.begin().runNumber()) { + initParamsFromCCDB(events.begin().timestamp(), false); + fCurrentRun = events.begin().runNumber(); + } + } + + std::map> histNames = fTrackHistNames; + + int sign1 = 0; + int sign2 = 0; + ditrackList.reserve(1); + ditrackExtraList.reserve(1); + + constexpr bool trackHasCov = ((TTrackFillMap & VarManager::ObjTypes::TrackCov) > 0 || (TTrackFillMap & VarManager::ObjTypes::ReducedTrackBarrelCov) > 0); + + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event, VarManager::fgValues); + + auto groupedLegAAssocs = legACandidateAssocs.sliceBy(preslice, event.globalIndex()); + if (groupedLegAAssocs.size() == 0) { + continue; + } + auto groupedLegBAssocs = legBCandidateAssocs.sliceBy(preslice, event.globalIndex()); + if (groupedLegBAssocs.size() == 0) { + continue; + } + + for (auto& [a1, a2] : combinations(soa::CombinationsFullIndexPolicy(groupedLegAAssocs, groupedLegBAssocs))) { + + uint32_t twoTrackFilter = static_cast(0); + uint32_t twoTrackCommonFilter = static_cast(0); + uint32_t pairFilter = static_cast(0); + for (int icut = 0; icut < fNLegCuts; ++icut) { + // Find leg pair definitions both candidates participate in + if ((a1.isBarrelSelected_raw() & fConstructedLegAFilterMasksMap[icut]) && (a2.isBarrelSelected_raw() & fConstructedLegBFilterMasksMap[icut])) { + twoTrackFilter |= (static_cast(1) << icut); + // If the supposed pion passes a kaon cut, this is a K+K-. Skip it. + if (TPairType == VarManager::kDecayToKPi && fConfigSkipAmbiguousIdCombinations.value) { + if (a2.isBarrelSelected_raw() & fConstructedLegAFilterMasksMap[icut]) { + twoTrackFilter &= ~(static_cast(1) << icut); + } + } + } + } + if (!twoTrackFilter) { + continue; + } + + // Find common track cuts both candidates pass + twoTrackCommonFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & fCommonTrackCutMask; + + auto t1 = a1.template reducedtrack_as(); + auto t2 = a2.template reducedtrack_as(); + + // Avoid self-pairs + if (t1.globalIndex() == t2.globalIndex()) { + continue; + } + + bool isReflected = false; + std::pair trackIds(t1.globalIndex(), t2.globalIndex()); + if (fPairCount.find(trackIds) != fPairCount.end()) { + // Double counting is possible due to track-collision ambiguity. Skip pairs which were counted before + fPairCount[trackIds] += 1; + continue; + } + if (fPairCount.find(std::pair(trackIds.second, trackIds.first)) != fPairCount.end()) { + isReflected = true; + } + fPairCount[trackIds] += 1; + + sign1 = t1.sign(); + sign2 = t2.sign(); + // store the ambiguity number of the two dilepton legs in the last 4 digits of the two-track filter + if (t1.barrelAmbiguityInBunch() > 1 || t1.barrelAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 30); + } + if (t2.barrelAmbiguityInBunch() > 1 || t2.barrelAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 31); + } + + VarManager::FillPair(t1, t2); + if constexpr (TTwoProngFitter) { + VarManager::FillPairVertexing(event, t1, t2, fConfigPropToPCA); + } + + // Fill histograms + bool isAmbi = false; + for (int icut = 0; icut < fNLegCuts; icut++) { + if (twoTrackFilter & (static_cast(1) << icut)) { + isAmbi = (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)); + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); + if (isAmbi && fConfigAmbiguousHistograms.value) { + fHistMan->FillHistClass(histNames[icut][fNPairHistPrefixes].Data(), VarManager::fgValues); + } + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(histNames[icut][fNPairHistPrefixes * (1 + fConfigAmbiguousHistograms.value)].Data(), VarManager::fgValues); + } + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(histNames[icut][1].Data(), VarManager::fgValues); + if (isAmbi && fConfigAmbiguousHistograms.value) { + fHistMan->FillHistClass(histNames[icut][fNPairHistPrefixes + 1].Data(), VarManager::fgValues); + } + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(histNames[icut][fNPairHistPrefixes * (1 + fConfigAmbiguousHistograms.value) + 1].Data(), VarManager::fgValues); + } + } else { + fHistMan->FillHistClass(histNames[icut][2].Data(), VarManager::fgValues); + if (isAmbi && fConfigAmbiguousHistograms.value) { + fHistMan->FillHistClass(histNames[icut][fNPairHistPrefixes + 2].Data(), VarManager::fgValues); + } + if (isReflected && fConfigReflectedHistograms) { + fHistMan->FillHistClass(histNames[icut][fNPairHistPrefixes * (1 + fConfigAmbiguousHistograms.value) + 2].Data(), VarManager::fgValues); + } + } + } + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (twoTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(histNames[fNLegCuts + icut * fNCommonTrackCuts + iCommonCut][0].Data(), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(histNames[fNLegCuts + icut * fNCommonTrackCuts + iCommonCut][1].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNames[fNLegCuts + icut * fNCommonTrackCuts + iCommonCut][2].Data(), VarManager::fgValues); + } + } + } + } // end loop (common cuts) + int iPairCut = 0; + for (auto cut = fPairCuts.begin(); cut != fPairCuts.end(); cut++, iPairCut++) { + if (!((*cut)->IsSelected(VarManager::fgValues))) // apply pair cuts + continue; + pairFilter |= (static_cast(1) << iPairCut); + // Histograms with pair cuts + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(histNames[fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut][0].Data(), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(histNames[fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut][1].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNames[fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut][2].Data(), VarManager::fgValues); + } + } + // Histograms with pair cuts and common track cuts + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + if (twoTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(histNames[(fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + (icut * fNPairCuts * fNCommonTrackCuts) + (iCommonCut * fNPairCuts) + iPairCut][0].Data(), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(histNames[(fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + (icut * fNPairCuts * fNCommonTrackCuts) + (iCommonCut * fNPairCuts) + iPairCut][1].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNames[(fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + (icut * fNPairCuts * fNCommonTrackCuts) + (iCommonCut * fNPairCuts) + iPairCut][2].Data(), VarManager::fgValues); + } + } + } + } + } // end loop (pair cuts) + } + } // end loop (cuts) + ditrackList(event.globalIndex(), VarManager::fgValues[VarManager::kMass], + VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], + t1.sign() + t2.sign(), twoTrackFilter, pairFilter, twoTrackCommonFilter); + if constexpr (trackHasCov && TTwoProngFitter) { + ditrackExtraList(t1.globalIndex(), t2.globalIndex(), VarManager::fgValues[VarManager::kVertexingTauzProjected], VarManager::fgValues[VarManager::kVertexingLzProjected], VarManager::fgValues[VarManager::kVertexingLxyProjected]); + } + } // end inner assoc loop (leg A) + } // end event loop + } + + // Template function to run same event triplets (e.g. D+->K-pi+pi+) + template + void runThreeProng(TEvents const& events, Preslice& preslice, TTrackAssocs const& /*assocs*/, TTracks const& tracks, VarManager::PairCandidateType tripletType) + { + if (events.size() > 0) { // Additional protection to avoid crashing of events.begin().runNumber() + if (fCurrentRun != events.begin().runNumber()) { + initParamsFromCCDB(events.begin().timestamp(), true); + fCurrentRun = events.begin().runNumber(); + } + } + + std::map> histNames = fTrackHistNames; + + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event, VarManager::fgValues); + + auto groupedLegAAssocs = legACandidateAssocs.sliceBy(preslice, event.globalIndex()); + if (groupedLegAAssocs.size() == 0) { + continue; + } + auto groupedLegBAssocs = legBCandidateAssocs.sliceBy(preslice, event.globalIndex()); + if (groupedLegBAssocs.size() == 0) { + continue; + } + auto groupedLegCAssocs = legCCandidateAssocs.sliceBy(preslice, event.globalIndex()); + if (groupedLegCAssocs.size() == 0) { + continue; + } + + // Based on triplet type, make suitable combinations of the partitions + if (tripletType == VarManager::kTripleCandidateToPKPi) { + for (auto& [a1, a2, a3] : combinations(soa::CombinationsFullIndexPolicy(groupedLegAAssocs, groupedLegBAssocs, groupedLegCAssocs))) { + readTriplet(a1, a2, a3, tracks, event, tripletType, histNames); + } + } else if (tripletType == VarManager::kTripleCandidateToKPiPi) { + for (auto& a1 : groupedLegAAssocs) { + for (auto& [a2, a3] : combinations(groupedLegBAssocs, groupedLegCAssocs)) { + readTriplet(a1, a2, a3, tracks, event, tripletType, histNames); + } + } + } else { + LOG(fatal) << "Given tripletType not recognized. Don't know how to make combinations!" << endl; + } + } // end event loop + } + + // Helper function to process triplet + template + void readTriplet(TTrackAssoc const& a1, TTrackAssoc const& a2, TTrackAssoc const& a3, TTracks const& /*tracks*/, TEvent const& event, VarManager::PairCandidateType tripletType, std::map> histNames) + { + uint32_t threeTrackFilter = static_cast(0); + uint32_t threeTrackCommonFilter = static_cast(0); + for (int icut = 0; icut < fNLegCuts; ++icut) { + // Find out which leg cut combinations the triplet passes + if ((a1.isBarrelSelected_raw() & fConstructedLegAFilterMasksMap[icut]) && (a2.isBarrelSelected_raw() & fConstructedLegBFilterMasksMap[icut]) && (a3.isBarrelSelected_raw() & fConstructedLegCFilterMasksMap[icut])) { + threeTrackFilter |= (static_cast(1) << icut); + if (tripletType == VarManager::kTripleCandidateToPKPi && fConfigSkipAmbiguousIdCombinations.value) { + // Check if the supposed pion passes as a proton or kaon, if so, skip this triplet. It is pKp or pKK. + if ((a3.isBarrelSelected_raw() & fConstructedLegAFilterMasksMap[icut]) || (a3.isBarrelSelected_raw() & fConstructedLegBFilterMasksMap[icut])) { + return; + } + // Check if the supposed kaon passes as a proton, if so, skip this triplet. It is ppPi. + if (a2.isBarrelSelected_raw() & fConstructedLegAFilterMasksMap[icut]) { + return; + } + } + if (tripletType == VarManager::kTripleCandidateToKPiPi && fConfigSkipAmbiguousIdCombinations.value) { + // Check if one of the supposed pions pass as a kaon, if so, skip this triplet. It is KKPi. + if ((a2.isBarrelSelected_raw() & fConstructedLegAFilterMasksMap[icut]) || (a3.isBarrelSelected_raw() & fConstructedLegAFilterMasksMap[icut])) { + return; + } + } + } + } + if (!threeTrackFilter) { + return; + } + + // Find common track cuts all candidates pass + threeTrackCommonFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & a3.isBarrelSelected_raw() & fCommonTrackCutMask; + + auto t1 = a1.template reducedtrack_as(); + auto t2 = a2.template reducedtrack_as(); + auto t3 = a3.template reducedtrack_as(); + + // Avoid self-pairs + if (t1 == t2 || t1 == t3 || t2 == t3) { + return; + } + // Check charge + if (tripletType == VarManager::kTripleCandidateToKPiPi) { + if (!((t1.sign() == -1 && t2.sign() == 1 && t3.sign() == 1) || (t1.sign() == 1 && t2.sign() == -1 && t3.sign() == -1))) { + return; + } + } + if (tripletType == VarManager::kTripleCandidateToPKPi) { + if (!((t1.sign() == 1 && t2.sign() == -1 && t3.sign() == 1) || (t1.sign() == -1 && t2.sign() == 1 && t3.sign() == -1))) { + return; + } + } + + // store the ambiguity of the three legs in the last 3 digits of the two-track filter + if (t1.barrelAmbiguityInBunch() > 1 || t1.barrelAmbiguityOutOfBunch() > 1) { + threeTrackFilter |= (static_cast(1) << 29); + } + if (t2.barrelAmbiguityInBunch() > 1 || t2.barrelAmbiguityOutOfBunch() > 1) { + threeTrackFilter |= (static_cast(1) << 30); + } + if (t3.barrelAmbiguityInBunch() > 1 || t3.barrelAmbiguityOutOfBunch() > 1) { + threeTrackFilter |= (static_cast(1) << 31); + } + + VarManager::FillTriple(t1, t2, t3, VarManager::fgValues, tripletType); + if constexpr (TThreeProngFitter) { + VarManager::FillTripletVertexing(event, t1, t2, t3, tripletType); + } + + // Fill histograms + for (int icut = 0; icut < fNLegCuts; icut++) { + if (threeTrackFilter & (static_cast(1) << icut)) { + fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); + if (fConfigAmbiguousHistograms.value && ((threeTrackFilter & (static_cast(1) << 29)) || (threeTrackFilter & (static_cast(1) << 30)) || (threeTrackFilter & (static_cast(1) << 31)))) { + fHistMan->FillHistClass(histNames[icut][1].Data(), VarManager::fgValues); + } + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (threeTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + fHistMan->FillHistClass(histNames[fNLegCuts + icut * fNCommonTrackCuts + iCommonCut][0].Data(), VarManager::fgValues); + } + } // end loop (common cuts) + int iPairCut = 0; + for (auto cut = fPairCuts.begin(); cut != fPairCuts.end(); cut++, iPairCut++) { + if (!((*cut)->IsSelected(VarManager::fgValues))) // apply pair cuts + continue; + // Histograms with pair cuts + fHistMan->FillHistClass(histNames[fNLegCuts * (fNCommonTrackCuts + 1) + icut * fNPairCuts + iPairCut][0].Data(), VarManager::fgValues); + // Histograms with pair cuts and common track cuts + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + if (threeTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + fHistMan->FillHistClass(histNames[(fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + (icut * fNPairCuts * fNCommonTrackCuts) + (iCommonCut * fNPairCuts) + iPairCut][0].Data(), VarManager::fgValues); + } + } + } // end loop (pair cuts) + } + } // end loop (cuts) + } + + void processKaonPionSkimmed(MyEventsVtxCovZdcSelected const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithCovWithAmbiguities const& barrelTracks) + { + runAsymmetricPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); + } + + void processKaonPionSkimmedMultExtra(MyEventsVtxCovZdcSelectedMultExtra const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithCovWithAmbiguities const& barrelTracks) + { + runAsymmetricPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); + } + + void processKaonPionPionSkimmed(MyEventsVtxCovZdcSelected const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithCovWithAmbiguities const& barrelTracks) + { + runThreeProng(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, VarManager::kTripleCandidateToKPiPi); + } + + void processKaonPionPionSkimmedMultExtra(MyEventsVtxCovZdcSelectedMultExtra const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithCovWithAmbiguities const& barrelTracks) + { + runThreeProng(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, VarManager::kTripleCandidateToKPiPi); + } + + void processProtonKaonPionSkimmed(MyEventsVtxCovZdcSelected const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithCovWithAmbiguities const& barrelTracks) + { + runThreeProng(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, VarManager::kTripleCandidateToPKPi); + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisAsymmetricPairing, processKaonPionSkimmed, "Run kaon pion pairing, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisAsymmetricPairing, processKaonPionPionSkimmed, "Run kaon pion pion triplets, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisAsymmetricPairing, processKaonPionSkimmedMultExtra, "Run kaon pion pairing, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisAsymmetricPairing, processKaonPionPionSkimmedMultExtra, "Run kaon pion pion triplets, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisAsymmetricPairing, processProtonKaonPionSkimmed, "Run proton kaon pion triplets, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisAsymmetricPairing, processDummy, "Dummy function, enabled only if none of the others are enabled", true); +}; + // Combines dileptons with barrel or muon tracks for either resonance or correlation analyses // Dileptons produced with all the selection cuts specified in the same-event pairing task are combined with the // tracks passing the fConfigTrackCut cut. The dileptons cuts from the same-event pairing task are auto-detected @@ -1436,7 +2802,7 @@ struct AnalysisDileptonTrack { Produces BmesonsTable; OutputObj fOutputList{"output"}; - Configurable fConfigTrackCut{"cfgTrackCut", "kaonPID", "Cut for the track to be correlated with the dileptons"}; + Configurable fConfigTrackCuts{"cfgTrackCuts", "kaonPID", "Comma separated list of cuts for the track to be correlated with the dileptons"}; Configurable fConfigDileptonLowMass{"cfgDileptonLowMass", 2.8, "Low mass cut for the dileptons used in analysis"}; Configurable fConfigDileptonHighMass{"cfgDileptonHighMass", 3.2, "High mass cut for the dileptons used in analysis"}; Configurable fConfigDileptonpTCut{"cfgDileptonpTCut", 0.0, "pT cut for dileptons used in the triplet vertexing"}; @@ -1444,6 +2810,7 @@ struct AnalysisDileptonTrack { Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; Configurable fConfigHistogramSubgroups{"cfgDileptonTrackHistogramsSubgroups", "invmass,vertexing", "Comma separated list of dilepton-track histogram subgroups"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; Configurable fConfigMixingDepth{"cfgMixingDepth", 5, "Event mixing pool depth"}; Configurable fConfigUseRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; @@ -1451,19 +2818,24 @@ struct AnalysisDileptonTrack { Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. - int fNCuts; - int fTrackCutBit; - std::map fHistNamesDileptonTrack; - std::map fHistNamesDileptons; - std::map fHistNamesME; + int fNCuts; // number of dilepton leg cuts + int fNPairCuts; // number of pair cuts + int fNCommonTrackCuts; + std::map fCommonTrackCutMap; + uint32_t fTrackCutBitMap; // track cut bit mask to be used in the selection of tracks associated with dileptons + // vector for single-lepton and track cut names for easy access when calling FillHistogramList() + std::vector fTrackCutNames; + // vector for pair cut names, used mainly for pairs built via the asymmetric pairing task + std::vector fPairCutNames; + std::vector fCommonPairCutNames; Service fCCDB; // TODO: The filter expressions seem to always use the default value of configurables, not the values from the actual configuration file - Filter eventFilter = aod::dqanalysisflags::isEventSelected == uint32_t(1); + Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); Filter dileptonFilter = aod::reducedpair::pt > fConfigDileptonpTCut&& aod::reducedpair::mass > fConfigDileptonLowMass&& aod::reducedpair::mass fConfigDileptonLxyCut; - Filter filterBarrel = aod::dqanalysisflags::isBarrelSelected > uint32_t(0); - Filter filterMuon = aod::dqanalysisflags::isMuonSelected > uint32_t(0); + Filter filterBarrel = aod::dqanalysisflags::isBarrelSelected > static_cast(0); + Filter filterMuon = aod::dqanalysisflags::isMuonSelected > static_cast(0); constexpr static uint32_t fgDileptonFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::Pair; // fill map @@ -1478,84 +2850,190 @@ struct AnalysisDileptonTrack { { bool isBarrel = context.mOptions.get("processBarrelSkimmed"); bool isBarrelME = context.mOptions.get("processBarrelMixedEvent"); + bool isBarrelAsymmetric = context.mOptions.get("processDstarToD0Pi"); bool isMuon = context.mOptions.get("processMuonSkimmed"); bool isMuonME = context.mOptions.get("processMuonMixedEvent"); - bool isAnyProcessEnabled = isBarrel || isBarrelME || isMuon || isMuonME; - bool isDummy = context.mOptions.get("processDummy"); - if (isDummy) { - if (isAnyProcessEnabled) { - LOG(warning) << "Dummy function is enabled even if there are normal process functions running! Fix your config!" << endl; - } else { - LOG(info) << "Dummy function is enabled. Skipping the rest of the init function" << endl; - return; + + // If the dummy process is enabled, skip the entire init + if (context.mOptions.get("processDummy")) { + if (isBarrel || isBarrelME || isBarrelAsymmetric || isMuon || isMuonME) { + LOG(fatal) << "If processDummy is enabled, no other process functions should be enabled! Or switch off the processDummy!"; } + return; } fCurrentRun = 0; + fTrackCutBitMap = 0; fValuesDilepton = new float[VarManager::kNVars]; fValuesHadron = new float[VarManager::kNVars]; - fTrackCutBit = -1; VarManager::SetDefaultVarNames(); fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetUseDefaultVariableNames(true); fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + TString histNames = ""; // For each track/muon selection used to produce dileptons, create a separate histogram directory using the // name of the track/muon cut. - // Also, create a map which will hold the name of the histogram directories so they can be accessed directly in the pairing loop - if (isBarrel || isMuon) { - // get the list of single track and muon cuts computed in the dedicated tasks upstream - string tempCutsSingle; - if (isBarrel) { - getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", tempCutsSingle, false); + if (isBarrel || isMuon || isBarrelAsymmetric) { + // Get the list of single track and muon cuts computed in the dedicated tasks upstream + // We need this to know the order in which they were computed, and also to make sure that in this task we do not ask + // for cuts which were not computed (in which case this will trigger a fatal) + string cfgTrackSelection_TrackCuts; + if (isBarrel || isBarrelAsymmetric) { + getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", cfgTrackSelection_TrackCuts, false); + } else { + getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCuts", cfgTrackSelection_TrackCuts, false); + } + + TObjArray* cfgTrackSelection_objArrayTrackCuts = nullptr; + if (!cfgTrackSelection_TrackCuts.empty()) { + cfgTrackSelection_objArrayTrackCuts = TString(cfgTrackSelection_TrackCuts).Tokenize(","); + } + // get also the list of cuts specified via the JSON parameters + if (isBarrel || isBarrelAsymmetric) { + getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", cfgTrackSelection_TrackCuts, false); + } else { + getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCutsJSON", cfgTrackSelection_TrackCuts, false); + } + if (!cfgTrackSelection_TrackCuts.empty()) { + if (cfgTrackSelection_objArrayTrackCuts == nullptr) { + cfgTrackSelection_objArrayTrackCuts = new TObjArray(); + } + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(cfgTrackSelection_TrackCuts.data()); + for (auto& t : addTrackCuts) { + TObjString* tempObjStr = new TObjString(t->GetName()); + cfgTrackSelection_objArrayTrackCuts->Add(tempObjStr); + } + } + if (cfgTrackSelection_objArrayTrackCuts->GetEntries() == 0) { + LOG(fatal) << " No track cuts found in the barrel or muon upstream tasks"; + } + // store all the computed track cut names in a vector + for (int icut = 0; icut < cfgTrackSelection_objArrayTrackCuts->GetEntries(); icut++) { + fTrackCutNames.push_back(cfgTrackSelection_objArrayTrackCuts->At(icut)->GetName()); + } + + // get the list of associated track cuts to be combined with the dileptons and + // check that these were computed upstream and create a bit mask + TObjArray* cfgDileptonTrack_objArrayTrackCuts = nullptr; + if (!fConfigTrackCuts.value.empty()) { + cfgDileptonTrack_objArrayTrackCuts = TString(fConfigTrackCuts.value).Tokenize(","); } else { - getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCuts", tempCutsSingle, false); + LOG(fatal) << " No track cuts specified! Check it out!"; } - TString tempCutsSingleStr = tempCutsSingle; - TObjArray* objArraySingleCuts = nullptr; - if (!tempCutsSingleStr.IsNull()) { - objArraySingleCuts = tempCutsSingleStr.Tokenize(","); + for (int icut = 0; icut < cfgDileptonTrack_objArrayTrackCuts->GetEntries(); icut++) { + if (!cfgTrackSelection_objArrayTrackCuts->FindObject(cfgDileptonTrack_objArrayTrackCuts->At(icut)->GetName())) { + LOG(fatal) << "Specified track cut (" << cfgDileptonTrack_objArrayTrackCuts->At(icut)->GetName() << ") not found in the list of computed cuts by the single barrel / muon selection tasks"; + } } - if (objArraySingleCuts->FindObject(fConfigTrackCut.value.data()) == nullptr) { - LOG(fatal) << " Track cut chosen for the correlation task was not computed in the single-track task! Check it out!"; + for (int icut = 0; icut < cfgTrackSelection_objArrayTrackCuts->GetEntries(); icut++) { + if (cfgDileptonTrack_objArrayTrackCuts->FindObject(cfgTrackSelection_objArrayTrackCuts->At(icut)->GetName())) { + fTrackCutBitMap |= (uint32_t(1) << icut); + } } + fNCuts = fTrackCutNames.size(); + // get the cuts employed for same-event pairing - string tempCutsPair; + // NOTE: The track/muon cuts in analysis-same-event-pairing are used to select electrons/muons to build dielectrons/dimuons + // NOTE: The cfgPairCuts in analysis-same-event-pairing are used to apply an additional selection on top of the already produced dileptons + // but this is only used for histograms, not for the produced dilepton tables + string cfgPairing_TrackCuts; + string cfgPairing_PairCuts; + string cfgPairing_CommonTrackCuts; if (isBarrel) { - getTaskOptionValue(context, "analysis-same-event-pairing", "cfgTrackCuts", tempCutsPair, false); - } else { - getTaskOptionValue(context, "analysis-same-event-pairing", "cfgMuonCuts", tempCutsPair, false); - } - TString tempCutsPairStr = tempCutsPair; - if (!tempCutsSingleStr.IsNull() && !tempCutsPairStr.IsNull()) { - std::unique_ptr objArray(tempCutsPairStr.Tokenize(",")); - fNCuts = objArray->GetEntries(); - for (int icut = 0; icut < objArraySingleCuts->GetEntries(); ++icut) { - TString tempStr = objArraySingleCuts->At(icut)->GetName(); - if (objArray->FindObject(tempStr.Data()) != nullptr) { - fHistNamesDileptonTrack[icut] = Form("DileptonTrack_%s_%s", tempStr.Data(), fConfigTrackCut.value.data()); - fHistNamesDileptons[icut] = Form("DileptonsSelected_%s", tempStr.Data()); - DefineHistograms(fHistMan, fHistNamesDileptonTrack[icut], fConfigHistogramSubgroups.value.data()); // define dilepton-track histograms - DefineHistograms(fHistMan, fHistNamesDileptons[icut], "barrel,vertexing"); // define dilepton histograms - if (isBarrelME || isMuonME) { - fHistNamesME[icut] = Form("DileptonTrackME_%s", tempStr.Data()); - DefineHistograms(fHistMan, fHistNamesME[icut], "mixedevent"); // define ME histograms + getTaskOptionValue(context, "analysis-same-event-pairing", "cfgTrackCuts", cfgPairing_TrackCuts, false); + getTaskOptionValue(context, "analysis-same-event-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); + } else if (isMuon) { + getTaskOptionValue(context, "analysis-same-event-pairing", "cfgMuonCuts", cfgPairing_TrackCuts, false); + getTaskOptionValue(context, "analysis-same-event-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); + } else if (isBarrelAsymmetric) { + getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgLegCuts", cfgPairing_TrackCuts, false); + getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); + getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgCommonTrackCuts", cfgPairing_CommonTrackCuts, false); + } + + if (cfgPairing_TrackCuts.empty()) { + LOG(fatal) << "There are no dilepton cuts specified in the upstream in the same-event-pairing or assymmetric-pairing"; + } + + // If asymmetric pair is used, it may have common track cuts + TString cfgPairing_strCommonTrackCuts = cfgPairing_CommonTrackCuts; + if (!cfgPairing_strCommonTrackCuts.IsNull()) { // if common track cuts + std::unique_ptr objArrayCommon(cfgPairing_strCommonTrackCuts.Tokenize(",")); + fNCommonTrackCuts = objArrayCommon->GetEntries(); + for (int icut = 0; icut < fNCommonTrackCuts; ++icut) { + for (int iicut = 0; iicut < cfgTrackSelection_objArrayTrackCuts->GetEntries(); iicut++) { + if (std::strcmp(cfgTrackSelection_objArrayTrackCuts->At(iicut)->GetName(), objArrayCommon->At(icut)->GetName()) == 0) { + fCommonTrackCutMap[icut] = iicut; + fCommonPairCutNames.push_back(objArrayCommon->At(icut)->GetName()); } } - if (tempStr.CompareTo(fConfigTrackCut.value.data()) == 0) { - fTrackCutBit = icut; // the bit correspoding to the track to be combined with dileptons - } } + } // end if (common cuts) + + std::unique_ptr objArrayPairCuts(TString(cfgPairing_PairCuts).Tokenize(",")); + fNPairCuts = objArrayPairCuts->GetEntries(); + for (int j = 0; j < fNPairCuts; j++) { + fPairCutNames.push_back(objArrayPairCuts->At(j)->GetName()); } - } - if (fHistNamesDileptons.size() == 0) { - LOG(fatal) << " No valid dilepton cuts "; - } - if (context.mOptions.get("processBarrelMixedEvent")) { - DefineHistograms(fHistMan, "DileptonTrackME", "mixedevent"); // define all histograms + // array of single lepton cuts specified in the same-analysis-pairing task + std::unique_ptr cfgPairing_objArrayTrackCuts(TString(cfgPairing_TrackCuts).Tokenize(",")); + + // loop over single lepton cuts + for (int icut = 0; icut < fNCuts; ++icut) { + + // here we check that this cut is one of those used for building the dileptons + if (!cfgPairing_objArrayTrackCuts->FindObject(fTrackCutNames[icut].Data())) { + continue; + } + + TString pairLegCutName = fTrackCutNames[icut].Data(); + // define dilepton histograms + DefineHistograms(fHistMan, Form("DileptonsSelected_%s", pairLegCutName.Data()), "barrel,vertexing"); + // loop over track cuts and create dilepton - track histogram directories + for (int iCutTrack = 0; iCutTrack < fNCuts; iCutTrack++) { + + // here we check that this track cut is one of those required to associate with the dileptons + if (!(fTrackCutBitMap & (uint32_t(1) << iCutTrack))) { + continue; + } + + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s", pairLegCutName.Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); + + if (!cfgPairing_strCommonTrackCuts.IsNull()) { + std::unique_ptr objArrayCommon(cfgPairing_strCommonTrackCuts.Tokenize(",")); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); + DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data()), "barrel,vertexing"); + } + } + + if (fNPairCuts != 0) { + + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s", pairLegCutName.Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); + DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s", pairLegCutName.Data(), fPairCutNames[iPairCut].Data()), "barrel,vertexing"); + + if (!cfgPairing_strCommonTrackCuts.IsNull()) { + std::unique_ptr objArrayCommon(cfgPairing_strCommonTrackCuts.Tokenize(",")); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); + DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), "barrel,vertexing"); + } + } + } + } + + if (isBarrelME || isMuonME) { + DefineHistograms(fHistMan, Form("DileptonTrackME_%s_%s", pairLegCutName.Data(), fTrackCutNames[iCutTrack].Data()), "mixedevent"); // define ME histograms + } + } // end loop over track cuts to be combined with dileptons / di-tracks + } // end loop over pair leg track cuts } + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); fOutputList.setObject(fHistMan->GetMainHistogramList()); } @@ -1574,13 +3052,13 @@ struct AnalysisDileptonTrack { if (fConfigUseKFVertexing.value) { VarManager::SetupThreeProngKFParticle(magField); } else { - VarManager::SetupThreeProngDCAFitter(); // TODO: get these parameters from Configurables + VarManager::SetupThreeProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables } } else { if (fConfigUseKFVertexing.value) { VarManager::SetupThreeProngKFParticle(fConfigMagField.value); } else { - VarManager::SetupThreeProngDCAFitter(); // TODO: get these parameters from Configurables + VarManager::SetupThreeProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables } } } @@ -1602,29 +3080,78 @@ struct AnalysisDileptonTrack { if (dilepton.sign() != 0) { continue; } - VarManager::FillTrack(dilepton, fValuesDilepton); + + // loop over existing dilepton leg cuts (e.g. electron1, electron2, etc) for (int icut = 0; icut < fNCuts; icut++) { - if (dilepton.filterMap_bit(icut)) { - fHistMan->FillHistClass(fHistNamesDileptons[icut].Data(), fValuesDilepton); + + if (!dilepton.filterMap_bit(icut)) { + continue; } - } + + // regular dileptons + fHistMan->FillHistClass(Form("DileptonsSelected_%s", fTrackCutNames[icut].Data()), fValuesDilepton); + + // other pairs, e.g.: D0s + if constexpr (TCandidateType == VarManager::kDstarToD0KPiPi) { // Dielectrons and Dimuons don't have the PairFilterMap column + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { + fHistMan->FillHistClass(Form("DileptonsSelected_%s_%s", fTrackCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data()), fValuesDilepton); + } + } + for (int iPairCut = 0; iPairCut < fNPairCuts; iPairCut++) { + if (dilepton.pairFilterMap_bit(iPairCut)) { + fHistMan->FillHistClass(Form("DileptonsSelected_%s_%s", fTrackCutNames[icut].Data(), fPairCutNames[icut].Data()), fValuesDilepton); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { + fHistMan->FillHistClass(Form("DileptonsSelected_%s_%s_%s", fTrackCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[icut].Data()), fValuesDilepton); + } + } + } + } + } + } // end loop over single lepton selections // loop over hadrons for (auto& assoc : assocs) { + + uint32_t trackSelection = 0; if constexpr (TCandidateType == VarManager::kBtoJpsiEEK) { - if (!assoc.isBarrelSelected_bit(fTrackCutBit)) { + // check the cuts fulfilled by this candidate track; if none just continue + trackSelection = (assoc.isBarrelSelected_raw() & fTrackCutBitMap); + if (!trackSelection) { + continue; + } + + // get the track from this association + auto track = assoc.template reducedtrack_as(); + // check that this track is not included in the current dilepton + if (track.globalIndex() == dilepton.index0Id() || track.globalIndex() == dilepton.index1Id()) { + continue; + } + // compute needed quantities + VarManager::FillDileptonHadron(dilepton, track, fValuesHadron); + VarManager::FillDileptonTrackVertexing(event, lepton1, lepton2, track, fValuesHadron); + } + if constexpr (TCandidateType == VarManager::kDstarToD0KPiPi) { + trackSelection = (assoc.isBarrelSelected_raw() & fTrackCutBitMap); + if (!trackSelection) { continue; } auto track = assoc.template reducedtrack_as(); if (track.globalIndex() == dilepton.index0Id() || track.globalIndex() == dilepton.index1Id()) { continue; } + // Check that the charge combination makes sense for D*+ -> D0 pi+ or D*- -> D0bar pi- + if (!((track.sign() == 1 && lepton1.sign() == -1 && lepton2.sign() == 1) || (track.sign() == -1 && lepton1.sign() == 1 && lepton2.sign() == -1))) { + continue; + } VarManager::FillDileptonHadron(dilepton, track, fValuesHadron); VarManager::FillDileptonTrackVertexing(event, lepton1, lepton2, track, fValuesHadron); } if constexpr (TCandidateType == VarManager::kBcToThreeMuons) { - if (!assoc.isMuonSelected_bit(fTrackCutBit)) { + trackSelection = (assoc.isMuonSelected_raw() & fTrackCutBitMap); + if (!trackSelection) { continue; } auto track = assoc.template reducedmuon_as(); @@ -1636,19 +3163,53 @@ struct AnalysisDileptonTrack { VarManager::FillDileptonTrackVertexing(event, lepton1, lepton2, track, fValuesHadron); } + // Fill histograms for the triplets + // loop over dilepton / ditrack cuts for (int icut = 0; icut < fNCuts; icut++) { - if (dilepton.filterMap_bit(icut)) { - fHistMan->FillHistClass(fHistNamesDileptonTrack[icut].Data(), fValuesHadron); + + if (!dilepton.filterMap_bit(icut)) { + continue; } - } + + // loop over specified track cuts (the tracks to be combined with the dileptons) + for (int iTrackCut = 0; iTrackCut < fNCuts; iTrackCut++) { + + if (!(trackSelection & (uint32_t(1) << iTrackCut))) { + continue; + } + fHistMan->FillHistClass(Form("DileptonTrack_%s_%s", fTrackCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + + if constexpr (TCandidateType == VarManager::kDstarToD0KPiPi) { // Dielectrons and Dimuons don't have the PairFilterMap column + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { + fHistMan->FillHistClass(Form("DileptonTrack_%s_%s_%s", fTrackCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + } + } + for (int iPairCut = 0; iPairCut < fNPairCuts; iPairCut++) { + if (dilepton.pairFilterMap_bit(iPairCut)) { + fHistMan->FillHistClass(Form("DileptonTrack_%s_%s_%s", fTrackCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { + fHistMan->FillHistClass(Form("DileptonTrack_%s_%s_%s_%s", fTrackCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + } + } + } + } + } + } // end loop over track cuts + } // end loop over dilepton cuts // table to be written out for ML analysis - BmesonsTable(fValuesHadron[VarManager::kPairMass], fValuesHadron[VarManager::kPairPt], fValuesHadron[VarManager::kVertexingLxy], fValuesHadron[VarManager::kVertexingLxyz], fValuesHadron[VarManager::kVertexingLz], fValuesHadron[VarManager::kVertexingTauxy], fValuesHadron[VarManager::kVertexingTauz], fValuesHadron[VarManager::kCosPointingAngle], fValuesHadron[VarManager::kVertexingChi2PCA]); + BmesonsTable(fValuesHadron[VarManager::kPairMass], dilepton.mass(), fValuesHadron[VarManager::kDeltaMass], fValuesHadron[VarManager::kPairPt], + fValuesHadron[VarManager::kVertexingLxy], fValuesHadron[VarManager::kVertexingLxyz], fValuesHadron[VarManager::kVertexingLz], + fValuesHadron[VarManager::kVertexingTauxy], fValuesHadron[VarManager::kVertexingTauz], fValuesHadron[VarManager::kCosPointingAngle], + fValuesHadron[VarManager::kVertexingChi2PCA], dilepton.filterMap_raw(), trackSelection); } } } Preslice trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; Preslice dielectronsPerCollision = aod::reducedpair::reducedeventId; + Preslice ditracksPerCollision = aod::reducedpair::reducedeventId; void processBarrelSkimmed(soa::Filtered const& events, soa::Filtered> const& assocs, @@ -1669,6 +3230,25 @@ struct AnalysisDileptonTrack { } } + void processDstarToD0Pi(soa::Filtered const& events, + soa::Filtered> const& assocs, + MyBarrelTracksWithCov const& tracks, soa::Filtered const& ditracks) + { + // set up KF or DCAfitter + if (events.size() == 0) { + return; + } + if (fCurrentRun != events.begin().runNumber()) { // start: runNumber + initParamsFromCCDB(events.begin().timestamp()); + fCurrentRun = events.begin().runNumber(); + } // end: runNumber + for (auto& event : events) { + auto groupedBarrelAssocs = assocs.sliceBy(trackAssocsPerCollision, event.globalIndex()); + auto groupedDitracks = ditracks.sliceBy(ditracksPerCollision, event.globalIndex()); + runDileptonHadron(event, groupedBarrelAssocs, tracks, groupedDitracks); + } + } + Preslice muonAssocsPerCollision = aod::reducedtrack_association::reducedeventId; Preslice dimuonsPerCollision = aod::reducedpair::reducedeventId; @@ -1701,32 +3281,52 @@ struct AnalysisDileptonTrack { events.bindExternalIndices(&dileptons); events.bindExternalIndices(&assocs); + // loop over two event comibnations for (auto& [event1, event2] : selfCombinations(fHashBin, fConfigMixingDepth.value, -1, events, events)) { + // fill event quantities VarManager::ResetValues(0, VarManager::kNVars); VarManager::FillEvent(event1, VarManager::fgValues); + // get the dilepton slice for event1 auto evDileptons = dileptons.sliceBy(dielectronsPerCollision, event1.globalIndex()); evDileptons.bindExternalIndices(&events); + // get the track associations slice for event2 auto evAssocs = assocs.sliceBy(trackAssocsPerCollision, event2.globalIndex()); evAssocs.bindExternalIndices(&events); + // loop over associations for (auto& assoc : evAssocs) { - if (!assoc.isBarrelSelected_bit(fTrackCutBit)) { + + // check that this track fulfills at least one of the specified cuts + uint32_t trackSelection = (assoc.isBarrelSelected_raw() & fTrackCutBitMap); + if (!trackSelection) { continue; } + + // get the track from this association auto track = assoc.template reducedtrack_as(); + // loop over dileptons for (auto dilepton : evDileptons) { + + // compute dilepton - track quantities VarManager::FillDileptonHadron(dilepton, track, VarManager::fgValues); + + // loop over dilepton leg cuts and track cuts and fill histograms separately for each combination for (int icut = 0; icut < fNCuts; icut++) { - if (dilepton.filterMap_bit(icut)) { - fHistMan->FillHistClass(fHistNamesME[icut].Data(), VarManager::fgValues); + if (!dilepton.filterMap_bit(icut)) { + continue; + } + for (uint32_t iTrackCut = 0; iTrackCut < fTrackCutNames.size(); iTrackCut++) { + if (trackSelection & (uint32_t(1) << iTrackCut)) { + fHistMan->FillHistClass(Form("DileptonTrackME_%s_%s", fTrackCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data()), VarManager::fgValues); + } } } } // end for (dileptons) - } // end for (assocs) - } // end event loop + } // end for (assocs) + } // end event loop } void processMuonMixedEvent(soa::Filtered& events, @@ -1751,7 +3351,8 @@ struct AnalysisDileptonTrack { for (auto& assoc : evAssocs) { - if (!assoc.isMuonSelected_bit(fTrackCutBit)) { + uint32_t muonSelection = assoc.isMuonSelected_raw() & fTrackCutBitMap; + if (!muonSelection) { continue; } auto track = assoc.template reducedmuon_as(); @@ -1759,13 +3360,18 @@ struct AnalysisDileptonTrack { for (auto dilepton : evDileptons) { VarManager::FillDileptonHadron(dilepton, track, VarManager::fgValues); for (int icut = 0; icut < fNCuts; icut++) { - if (dilepton.filterMap_bit(icut)) { - fHistMan->FillHistClass(fHistNamesME[icut].Data(), VarManager::fgValues); + if (!dilepton.filterMap_bit(icut)) { + continue; + } + for (uint32_t iTrackCut = 0; iTrackCut < fTrackCutNames.size(); iTrackCut++) { + if (muonSelection & (uint32_t(1) << iTrackCut)) { + fHistMan->FillHistClass(Form("DileptonTrackME_%s_%s", fTrackCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data()), VarManager::fgValues); + } } } } // end for (dileptons) - } // end for (assocs) - } // end event loop + } // end for (assocs) + } // end event loop } void processDummy(MyEvents&) @@ -1774,6 +3380,7 @@ struct AnalysisDileptonTrack { } PROCESS_SWITCH(AnalysisDileptonTrack, processBarrelSkimmed, "Run barrel dilepton-track pairing, using skimmed data", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processDstarToD0Pi, "Run barrel pairing of D0 daughters with pion candidate, using skimmed data", false); PROCESS_SWITCH(AnalysisDileptonTrack, processMuonSkimmed, "Run muon dilepton-track pairing, using skimmed data", false); PROCESS_SWITCH(AnalysisDileptonTrack, processBarrelMixedEvent, "Run barrel dilepton-hadron mixed event pairing", false); PROCESS_SWITCH(AnalysisDileptonTrack, processMuonMixedEvent, "Run muon dilepton-hadron mixed event pairing", false); @@ -1788,6 +3395,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc)}; } @@ -1809,7 +3417,7 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, const char dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "event", histName); } - if (classStr.Contains("SameBunchCorrelations")) { + if (classStr.Contains("SameBunchCorrelations") || classStr.Contains("OutOfBunchCorrelations")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "two-collisions", histName); } @@ -1826,7 +3434,7 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, const char dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "postcalib_proton"); } if (classStr.Contains("Ambiguity")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", Form("%s,ambiguity", histName.Data())); + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "ambiguity"); } } if (classStr.Contains("Muon")) { @@ -1838,6 +3446,10 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, const char dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", histName); } + if (classStr.Contains("Triplets")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", histName); + } + if (classStr.Contains("DileptonsSelected")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", "barrel,vertexing"); } diff --git a/PWGDQ/Tasks/taskFwdTrackPid.cxx b/PWGDQ/Tasks/taskFwdTrackPid.cxx new file mode 100644 index 00000000000..7fb6e8e3310 --- /dev/null +++ b/PWGDQ/Tasks/taskFwdTrackPid.cxx @@ -0,0 +1,269 @@ +// Copyright 2019-2024 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 taskFwdTrackPid.cxx +/// \brief Task for the analysis of forward PID with MFT +/// \author Luca Micheletti , INFN + +#include +#include +#include +#include +#include +#include +#include +#include +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/MixingHandler.h" +#include "PWGDQ/Core/MCSignal.h" +#include "PWGDQ/Core/MCSignalLibrary.h" +#include "PWGDQ/Core/AnalysisCut.h" +#include "PWGDQ/Core/AnalysisCompositeCut.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/MixingLibrary.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "Field/MagneticField.h" +#include "TGeoGlobalMagField.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "Common/CCDB/EventSelectionParams.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod; + +using MyEvents = soa::Join; +using MyEventsMC = soa::Join; + +using MyMuonTracks = soa::Join; +using MyMuonTracksMC = soa::Join; +using MyMftTracks = soa::Join; +using MyMftTracksMC = soa::Join; + +// bit maps used for the Fill functions of the VarManager +constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended; +constexpr static uint32_t gkMCEventFillMap = VarManager::ObjTypes::ReducedEventMC; +constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra; + +void DefineHistograms(HistogramManager* histMan, TString histClasses); + +struct taskFwdTrackPid { + Produces fwdPidAllList; + + HistogramManager* fHistMan; + OutputObj fOutputList{"output"}; + + Configurable fConfigMaxDCA{"cfgMaxDCA", 0.5f, "Manually set maximum DCA of the track"}; + Configurable downSampleFactor{"downSampleFactor", 1., "Fraction of candidates to keep for ML"}; + Configurable fConfigMCGenSignals{"cfgMCGenSignals", "", "Comma separated list of MC signals (generated)"}; + Configurable fConfigMCRecSignals{"cfgMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; + + std::vector fGenMCSignalsNames; + std::vector fRecMCSignalsNames; + std::vector fGenMCSignals; + std::vector fRecMCSignals; + + void init(o2::framework::InitContext& context) + { + if (context.mOptions.get("processDummy")) { + return; + } + + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + TString histNames = ""; + + TString sigGenNamesStr = fConfigMCGenSignals.value; + std::unique_ptr objGenSigArray(sigGenNamesStr.Tokenize(",")); + for (int isig = 0; isig < objGenSigArray->GetEntries(); isig++) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objGenSigArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() == 1) { // NOTE: 1-prong signals required + fGenMCSignals.push_back(*sig); + histNames += Form("MCTruthGen_%s;", sig->GetName()); // TODO: Add these names to a std::vector to avoid using Form in the process function + } + } + } + + DefineHistograms(fHistMan, histNames.Data()); // define all histograms + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + + TString sigNamesStr = fConfigMCRecSignals.value; + std::unique_ptr objRecSigArray(sigNamesStr.Tokenize(",")); + if (!sigNamesStr.IsNull()) { + for (int isig = 0; isig < objRecSigArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objRecSigArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() == 1) { + fRecMCSignals.push_back(*sig); + fRecMCSignalsNames.push_back(sig->GetName()); + } + } + } + } + // Setting the MC rec signal names + for (int isig = 0; isig < objRecSigArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objRecSigArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() != 1) { // NOTE: 2-prong signals required + continue; + } + fRecMCSignals.push_back(*sig); + } + } + } + + // Template function to pair mft tracks and muon tracks + template + void runFwdTrackPid(TEvent const& event, Muons const& muons, MftTracks const& mftTracks) + { + fwdPidAllList.reserve(1); + for (const auto& muon : muons) { + if (muon.has_matchMFTTrack() && muon.trackType() == 0 && TMath::Abs(muon.fwdDcaX()) < fConfigMaxDCA && TMath::Abs(muon.fwdDcaY()) < fConfigMaxDCA) { + auto mftTrack = muon.template matchMFTTrack_as(); + fwdPidAllList(muon.trackType(), event.posX(), event.posY(), event.posZ(), event.numContrib(), muon.pt(), muon.eta(), muon.phi(), muon.sign(), mftTrack.mftClusterSizesAndTrackFlags(), muon.fwdDcaX(), muon.fwdDcaY(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), 0); + } + } + if constexpr (TMatchedOnly == false) { + for (const auto& mftTrack : mftTracks) { + if (TMath::Abs(mftTrack.fwdDcaX()) < fConfigMaxDCA && TMath::Abs(mftTrack.fwdDcaY()) < fConfigMaxDCA) { + if (downSampleFactor < 1.) { + float pseudoRndm = mftTrack.pt() * 1000. - (int64_t)(mftTrack.pt() * 1000); + if (pseudoRndm >= downSampleFactor) { + continue; + } + } + fwdPidAllList(4, event.posX(), event.posY(), event.posZ(), event.numContrib(), mftTrack.pt(), mftTrack.eta(), mftTrack.phi(), mftTrack.sign(), mftTrack.mftClusterSizesAndTrackFlags(), mftTrack.fwdDcaX(), mftTrack.fwdDcaY(), -999, -999, 0); + } + } + } + } + + // Template function to run over reconstructed tracks + template + void runFwdTrackPidMC(TEvent const& event, Muons const& muons, MftTracks const& mftTracks, TEventsMC const& /*eventsMC*/, TTracksMC const& /*tracksMC*/) + { + fwdPidAllList.reserve(1); + for (const auto& muon : muons) { + if (muon.has_matchMFTTrack() && muon.trackType() == 0 && TMath::Abs(muon.fwdDcaX()) < fConfigMaxDCA && TMath::Abs(muon.fwdDcaY()) < fConfigMaxDCA) { + auto mftTrack = muon.template matchMFTTrack_as(); + fwdPidAllList(muon.trackType(), event.posX(), event.posY(), event.posZ(), event.numContrib(), muon.pt(), muon.eta(), muon.phi(), muon.sign(), mftTrack.mftClusterSizesAndTrackFlags(), muon.fwdDcaX(), muon.fwdDcaY(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), muon.mcReducedFlags()); + } + } + + if constexpr (TMatchedOnly == false) { + for (const auto& mftTrack : mftTracks) { + if (TMath::Abs(mftTrack.fwdDcaX()) < fConfigMaxDCA && TMath::Abs(mftTrack.fwdDcaY()) < fConfigMaxDCA) { + fwdPidAllList(4, event.posX(), event.posY(), event.posZ(), event.numContrib(), mftTrack.pt(), mftTrack.eta(), mftTrack.phi(), mftTrack.sign(), mftTrack.mftClusterSizesAndTrackFlags(), mftTrack.fwdDcaX(), mftTrack.fwdDcaY(), -999, -999, mftTrack.mcReducedFlags()); + } + } + } + } + + // Template function to run over MC tracks + template + void runMCGen(TTracksMC& groupedMCTracks) + { + for (auto& mctrack : groupedMCTracks) { + VarManager::FillTrackMC(groupedMCTracks, mctrack); + + int isig = 0; + for (auto sig = fGenMCSignals.begin(); sig != fGenMCSignals.end(); sig++, isig++) { + if (mctrack.mcReducedFlags() & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + } + } + } + } + + PresliceUnsorted perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; + + void processFwdPidMatched(MyEvents::iterator const& event, MyMuonTracks const& muons, MyMftTracks const& mftTracks) + { + if (muons.size() > 0 && mftTracks.size() > 0) { + runFwdTrackPid(event, muons, mftTracks); + } + } + + void processFwdPidMatchedOnly(MyEvents::iterator const& event, MyMuonTracks const& muons, MyMftTracks const& mftTracks) + { + if (muons.size() > 0) { + runFwdTrackPid(event, muons, mftTracks); + } + } + + void processFwdPidMatchedMC(MyEventsMC::iterator const& event, MyMuonTracksMC const& muons, MyMftTracksMC const& mftTracks, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) + { + if (muons.size() > 0 && mftTracks.size() > 0) { + runFwdTrackPidMC(event, muons, mftTracks, eventsMC, tracksMC); + } + auto groupedMCTracks = tracksMC.sliceBy(perReducedMcEvent, event.reducedMCevent().globalIndex()); + groupedMCTracks.bindInternalIndicesTo(&tracksMC); + runMCGen(groupedMCTracks); + } + void processFwdPidMatchedOnlyMC(MyEventsMC::iterator const& event, MyMuonTracksMC const& muons, MyMftTracksMC const& mftTracks, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) + { + if (muons.size() > 0) { + runFwdTrackPidMC(event, muons, mftTracks, eventsMC, tracksMC); + } + auto groupedMCTracks = tracksMC.sliceBy(perReducedMcEvent, event.reducedMCevent().globalIndex()); + groupedMCTracks.bindInternalIndicesTo(&tracksMC); + runMCGen(groupedMCTracks); + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(taskFwdTrackPid, processFwdPidMatched, "Run MFT - muon track pairing filling tree with MFT and global tracks", false); + PROCESS_SWITCH(taskFwdTrackPid, processFwdPidMatchedOnly, "Run MFT - muon track pairing filling tree with global tracks only", false); + PROCESS_SWITCH(taskFwdTrackPid, processFwdPidMatchedMC, "Run MFT - muon track pairing filling tree with MFT and global tracks and MC info", false); + PROCESS_SWITCH(taskFwdTrackPid, processFwdPidMatchedOnlyMC, "Run MFT - muon track pairing filling tree with global tracks only and MC info", false); + PROCESS_SWITCH(taskFwdTrackPid, processDummy, "Dummy function", false); +}; // End of struct taskFwdTrackPid + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} + +void DefineHistograms(HistogramManager* histMan, TString histClasses) +{ + std::unique_ptr objArray(histClasses.Tokenize(";")); + for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { + TString classStr = objArray->At(iclass)->GetName(); + histMan->AddHistClass(classStr.Data()); + + if (classStr.Contains("MCTruthGen")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth"); + histMan->AddHistogram(objArray->At(iclass)->GetName(), "Pt_Rapidity", "MC generator p_{T}, y distribution", false, 120, 0.0, 30.0, VarManager::kMCPt, 150, 2.5, 4.0, VarManager::kMCY); + histMan->AddHistogram(objArray->At(iclass)->GetName(), "Eta", "MC generator #eta distribution", false, 200, -5.0, 5.0, VarManager::kMCEta); + histMan->AddHistogram(objArray->At(iclass)->GetName(), "Phi", "MC generator #varphi distribution", false, 50, 0.0, 2. * TMath::Pi(), VarManager::kMCPhi); + } + + } // end loop over histogram classes +} diff --git a/PWGDQ/Tasks/taskJpsiHf.cxx b/PWGDQ/Tasks/taskJpsiHf.cxx index 0b00497c3d8..79d9348940a 100644 --- a/PWGDQ/Tasks/taskJpsiHf.cxx +++ b/PWGDQ/Tasks/taskJpsiHf.cxx @@ -48,7 +48,7 @@ static const std::vector labelsCutsBdt = {"BDT background", "BDT pr // Declarations of various short names using MyRedEvents = aod::RedJpDmColls; using MyRedPairCandidatesSelected = aod::RedJpDmDileptons; -using MyRedD0CandidatesSelected = soa::Join; +using MyRedD0CandidatesSelected = soa::Join; struct taskJPsiHf { // @@ -60,7 +60,7 @@ struct taskJPsiHf { // HF configurables Configurable massHfCandMin{"massHfCandMin", 1.5f, "minimum HF mass"}; - Configurable massHfCandMax{"massHfCandMax", 2.1f, "maximum HF mass"}; + Configurable massHfCandMax{"massHfCandMax", 2.3f, "maximum HF mass"}; Configurable> binsPtDmesForBdt{"binsPtDmesForBdt", std::vector{bdtcuts::binsPt, bdtcuts::binsPt + bdtcuts::nBinsPt + 1}, "pT bin limits for BDT cuts"}; Configurable> cutsDmesBdt{"cutsDmesBdt", {bdtcuts::bdtCuts[0], bdtcuts::nBinsPt, 3, bdtcuts::labelsPt, bdtcuts::labelsCutsBdt}, "D-meson BDT selections per pT bin"}; @@ -68,6 +68,10 @@ struct taskJPsiHf { Configurable massDileptonCandMin{"massDileptonCandMin", 1.f, "minimum dilepton mass"}; Configurable massDileptonCandMax{"massDileptonCandMax", 5.f, "maximum dilepton mass"}; + // Preslices for unsorted indexes + PresliceUnsorted perCollisionDilepton = aod::jpsidmescorr::redJpDmCollId; + PresliceUnsorted perCollisionDmeson = aod::jpsidmescorr::redJpDmCollId; + // histogram for normalisation std::shared_ptr hCollisions; HistogramRegistry registry{"registry"}; @@ -95,7 +99,7 @@ struct taskJPsiHf { for (auto& dilepton : dileptons) { ptDilepton = RecoDecay::pt(dilepton.px(), dilepton.py()); - rapDilepton = RecoDecay::y(std::array{dilepton.px(), dilepton.py(), dilepton.pz()}, dilepton.mass()); + rapDilepton = RecoDecay::y(std::array{dilepton.px(), dilepton.py(), dilepton.pz()}, constants::physics::MassJPsi); phiDilepton = RecoDecay::phi(dilepton.px(), dilepton.py()); for (auto& dmeson : dmesons) { @@ -108,35 +112,44 @@ struct taskJPsiHf { continue; } + auto minItsClsDmesDau = (dmeson.numItsClsDmesProng0() < dmeson.numItsClsDmesProng1()) ? dmeson.numItsClsDmesProng0() : dmeson.numItsClsDmesProng1(); + auto minTpcCrossRowsDmesDau = (dmeson.numTpcCrossedRowsDmesProng0() < dmeson.numTpcCrossedRowsDmesProng1()) ? dmeson.numTpcCrossedRowsDmesProng0() : dmeson.numTpcCrossedRowsDmesProng1(); + auto minPtDmesDau = (dmeson.ptDmesProng0() < dmeson.ptDmesProng1()) ? dmeson.ptDmesProng0() : dmeson.ptDmesProng1(); + auto minAbsEtaDmesDau = (std::abs(dmeson.etaDmesProng0()) < std::abs(dmeson.etaDmesProng1())) ? std::abs(dmeson.etaDmesProng0()) : std::abs(dmeson.etaDmesProng1()); + if (dmeson.massD0() > 0) { - rapDmeson = RecoDecay::y(std::array{dmeson.px(), dmeson.py(), dmeson.pz()}, dmeson.massD0()); + rapDmeson = RecoDecay::y(std::array{dmeson.px(), dmeson.py(), dmeson.pz()}, constants::physics::MassD0); deltaRap = rapDilepton - rapDmeson; auto bdtBkg = dmeson.bdtBkgMassHypo0(); auto bdtPrompt = dmeson.bdtPromptMassHypo0(); auto bdtNonPrompt = dmeson.bdtNonpromptMassHypo0(); if ((dilepton.mass() > massDileptonCandMin && dilepton.mass() < massDileptonCandMax) && (dmeson.massD0() > massHfCandMin && dmeson.massD0() < massHfCandMax && bdtBkg < cutsDmesBdt->get(ptBinDmesForBdt, "BDT background") && bdtPrompt > cutsDmesBdt->get(ptBinDmesForBdt, "BDT prompt") && bdtNonPrompt > cutsDmesBdt->get(ptBinDmesForBdt, "BDT nonprompt"))) { - redDileptDimesAll(dilepton.mass(), dmeson.massD0(), ptDilepton, ptDmeson, rapDilepton, rapDmeson, phiDilepton, phiDmeson, deltaRap, deltaPhi, bdtBkg, bdtPrompt, bdtNonPrompt); + redDileptDimesAll(dilepton.mass(), dmeson.massD0(), ptDilepton, ptDmeson, rapDilepton, rapDmeson, phiDilepton, phiDmeson, deltaRap, deltaPhi, bdtBkg, bdtPrompt, bdtNonPrompt, minItsClsDmesDau, minTpcCrossRowsDmesDau, minPtDmesDau, minAbsEtaDmesDau); } } if (dmeson.massD0bar() > 0) { - rapDmeson = RecoDecay::y(std::array{dmeson.px(), dmeson.py(), dmeson.pz()}, dmeson.massD0bar()); + rapDmeson = RecoDecay::y(std::array{dmeson.px(), dmeson.py(), dmeson.pz()}, constants::physics::MassD0); deltaRap = rapDilepton - rapDmeson; auto bdtBkg = dmeson.bdtBkgMassHypo1(); auto bdtPrompt = dmeson.bdtPromptMassHypo1(); auto bdtNonPrompt = dmeson.bdtNonpromptMassHypo1(); - if ((dilepton.mass() > massDileptonCandMin && dilepton.mass() < massDileptonCandMax) && (dmeson.massD0() > massHfCandMin && dmeson.massD0() < massHfCandMax && bdtBkg < cutsDmesBdt->get(ptBinDmesForBdt, "BDT background") && bdtPrompt > cutsDmesBdt->get(ptBinDmesForBdt, "BDT prompt") && bdtNonPrompt > cutsDmesBdt->get(ptBinDmesForBdt, "BDT nonprompt"))) { - redDileptDimesAll(dilepton.mass(), dmeson.massD0bar(), ptDilepton, ptDmeson, rapDilepton, rapDmeson, phiDilepton, phiDmeson, deltaRap, deltaPhi, bdtBkg, bdtPrompt, bdtNonPrompt); + if ((dilepton.mass() > massDileptonCandMin && dilepton.mass() < massDileptonCandMax) && (dmeson.massD0bar() > massHfCandMin && dmeson.massD0bar() < massHfCandMax && bdtBkg < cutsDmesBdt->get(ptBinDmesForBdt, "BDT background") && bdtPrompt > cutsDmesBdt->get(ptBinDmesForBdt, "BDT prompt") && bdtNonPrompt > cutsDmesBdt->get(ptBinDmesForBdt, "BDT nonprompt"))) { + redDileptDimesAll(dilepton.mass(), dmeson.massD0bar(), ptDilepton, ptDmeson, rapDilepton, rapDmeson, phiDilepton, phiDmeson, deltaRap, deltaPhi, bdtBkg, bdtPrompt, bdtNonPrompt, minItsClsDmesDau, minTpcCrossRowsDmesDau, minPtDmesDau, minAbsEtaDmesDau); } } } } } - void processRedJspiD0(MyRedEvents::iterator const& event, MyRedPairCandidatesSelected const& dileptons, MyRedD0CandidatesSelected const& dmesons) + void processRedJspiD0(MyRedEvents const& events, MyRedPairCandidatesSelected const& dileptons, MyRedD0CandidatesSelected const& dmesons) { // Fill the column of collisions with pairs - hCollisions->Fill(1.f); - runDileptonDmeson(event, dileptons, dmesons); + for (auto& event : events) { + hCollisions->Fill(1.f); + auto groupedDileptonCandidates = dileptons.sliceBy(perCollisionDilepton, event.index()); + auto groupedDmesonCandidates = dmesons.sliceBy(perCollisionDmeson, event.index()); + runDileptonDmeson(event, groupedDileptonCandidates, groupedDmesonCandidates); + } } void processNormCounter(RedJpDmColCounts const& normCounters) diff --git a/PWGDQ/Tasks/v0selector.cxx b/PWGDQ/Tasks/v0selector.cxx index 45c352ee386..52068b44958 100644 --- a/PWGDQ/Tasks/v0selector.cxx +++ b/PWGDQ/Tasks/v0selector.cxx @@ -19,6 +19,8 @@ // #include #include +#include +#include #include "Math/Vector4D.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -49,13 +51,39 @@ using namespace o2::framework; using namespace o2::framework::expressions; using std::array; -using FullTracksExt = soa::Join;*/ +using FullTracksExt = soa::Join; constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackTPCPID; struct v0selector { + + // Configurables for curved QT cut + // Gamma cuts + Configurable cutAlphaG{"cutAlphaG", 0.4, "cutAlphaG"}; + Configurable cutQTG{"cutQTG", 0.03, "cutQTG"}; + Configurable cutAlphaGLow{"cutAlphaGLow", 0.4, "cutAlphaGLow"}; + Configurable cutAlphaGHigh{"cutAlphaGHigh", 0.8, "cutAlphaGHigh"}; + Configurable cutQTG2{"cutQTG2", 0.02, "cutQTG2"}; + // K0S cuts + Configurable cutQTK0SLow{"cutQTK0SLow", 0.1075, "cutQTK0SLow"}; + Configurable cutQTK0SHigh{"cutQTK0SHigh", 0.215, "cutQTK0SHigh"}; + Configurable cutAPK0SLow{"cutAPK0SLow", 0.199, "cutAPK0SLow"}; + Configurable cutAPK0SHigh{"cutAPK0SHigh", 0.8, "cutAPK0SHigh"}; + // Lambda & A-Lambda cuts + Configurable cutQTL{"cutQTL", 0.03, "cutQTL"}; + Configurable cutAlphaLLow{"cutAlphaLLow", 0.35, "cutAlphaLLow"}; + Configurable cutAlphaLHigh{"cutAlphaLHigh", 0.7, "cutAlphaLHigh"}; + Configurable cutAlphaALLow{"cutAlphaALow", -0.7, "cutAlphaALow"}; + Configurable cutAlphaALHigh{"cutAlphaAHigh", -0.35, "cutAlphaAHigh"}; + Configurable cutAPL1{"cutAPL1", 0.107, "cutAPL1"}; + Configurable cutAPL2{"cutAPL2", -0.69, "cutAPL2"}; + Configurable cutAPL3{"cutAPL3", 0.5, "cutAPL3"}; + enum { // Reconstructed V0 kUndef = -1, kGamma = 0, @@ -72,24 +100,22 @@ struct v0selector { { // float alpha = alphav0(ppos, pneg); // float qt = qtarmv0(ppos, pneg); + // // Gamma cuts + // const float cutAlphaG = 0.4; + // const float cutQTG = 0.03; + // const float cutAlphaG2[2] = {0.4, 0.8}; + // const float cutQTG2 = 0.02; + + // // K0S cuts + // const float cutQTK0S[2] = {0.1075, 0.215}; + // const float cutAPK0S[2] = {0.199, 0.8}; // parameters for curved QT cut + + // // Lambda & A-Lambda cuts + // const float cutQTL = 0.03; + // const float cutAlphaL[2] = {0.35, 0.7}; + // const float cutAlphaAL[2] = {-0.7, -0.35}; + // const float cutAPL[3] = {0.107, -0.69, 0.5}; // parameters for curved QT cut - // Gamma cuts - const float cutAlphaG = 0.4; - const float cutQTG = 0.03; - const float cutAlphaG2[2] = {0.4, 0.8}; - const float cutQTG2 = 0.02; - - // K0S cuts - const float cutQTK0S[2] = {0.1075, 0.215}; - const float cutAPK0S[2] = {0.199, 0.8}; // parameters for curved QT cut - - // Lambda & A-Lambda cuts - const float cutQTL = 0.03; - const float cutAlphaL[2] = {0.35, 0.7}; - const float cutAlphaAL[2] = {-0.7, -0.35}; - const float cutAPL[3] = {0.107, -0.69, 0.5}; // parameters for curved QT cut - - // Check for Gamma candidates if (qt < cutQTG) { if ((TMath::Abs(alpha) < cutAlphaG)) { return kGamma; @@ -97,26 +123,26 @@ struct v0selector { } if (qt < cutQTG2) { // additional region - should help high pT gammas - if ((TMath::Abs(alpha) > cutAlphaG2[0]) && (TMath::Abs(alpha) < cutAlphaG2[1])) { + if ((TMath::Abs(alpha) > cutAlphaGLow) && (TMath::Abs(alpha) < cutAlphaGHigh)) { return kGamma; } } // Check for K0S candidates - float q = cutAPK0S[0] * TMath::Sqrt(TMath::Abs(1 - alpha * alpha / (cutAPK0S[1] * cutAPK0S[1]))); - if ((qt > cutQTK0S[0]) && (qt < cutQTK0S[1]) && (qt > q)) { + float q = cutAPK0SLow * TMath::Sqrt(TMath::Abs(1 - alpha * alpha / (cutAPK0SHigh * cutAPK0SHigh))); + if ((qt > cutQTK0SLow) && (qt < cutQTK0SHigh) && (qt > q)) { return kK0S; } // Check for Lambda candidates - q = cutAPL[0] * TMath::Sqrt(TMath::Abs(1 - ((alpha + cutAPL[1]) * (alpha + cutAPL[1])) / (cutAPL[2] * cutAPL[2]))); - if ((alpha > cutAlphaL[0]) && (alpha < cutAlphaL[1]) && (qt > cutQTL) && (qt < q)) { + q = cutAPL1 * TMath::Sqrt(TMath::Abs(1 - ((alpha + cutAPL2) * (alpha + cutAPL2)) / (cutAPL3 * cutAPL3))); + if ((alpha > cutAlphaLLow) && (alpha < cutAlphaLHigh) && (qt > cutQTL) && (qt < q)) { return kLambda; } // Check for AntiLambda candidates - q = cutAPL[0] * TMath::Sqrt(TMath::Abs(1 - ((alpha - cutAPL[1]) * (alpha - cutAPL[1])) / (cutAPL[2] * cutAPL[2]))); - if ((alpha > cutAlphaAL[0]) && (alpha < cutAlphaAL[1]) && (qt > cutQTL) && (qt < q)) { + q = cutAPL1 * TMath::Sqrt(TMath::Abs(1 - ((alpha - cutAPL2) * (alpha - cutAPL2)) / (cutAPL3 * cutAPL3))); + if ((alpha > cutAlphaALLow) && (alpha < cutAlphaALHigh) && (qt > cutQTL) && (qt < q)) { return kAntiLambda; } @@ -135,6 +161,10 @@ struct v0selector { Configurable mincrossedrows{"mincrossedrows", 70, "min crossed rows"}; Configurable maxchi2tpc{"maxchi2tpc", 4.0, "max chi2/NclsTPC"}; Configurable fillhisto{"fillhisto", false, "flag to fill histograms"}; + // cutNsigmaElTPC, cutNsigmaPiTPC, cutNsigmaPrTPC + Configurable cutNsigmaElTPC{"cutNsigmaElTPC", 5.0, "cutNsigmaElTPC"}; + Configurable cutNsigmaPiTPC{"cutNsigmaPiTPC", 5.0, "cutNsigmaPiTPC"}; + Configurable cutNsigmaPrTPC{"cutNsigmaPrTPC", 5.0, "cutNsigmaPrTPC"}; HistogramRegistry registry{"registry"}; void init(o2::framework::InitContext&) @@ -144,6 +174,9 @@ struct v0selector { registry.add("hMassGamma", "hMassGamma", HistType::kTH2F, {{900, 0.0f, 90.0f}, {100, 0.0f, 0.1f}}); registry.add("hGammaRxy", "hGammaRxy", HistType::kTH2F, {{1800, -90.0f, 90.0f}, {1800, -90.0f, 90.0f}}); registry.add("hMassK0S", "hMassK0S", HistType::kTH2F, {{900, 0.0f, 90.0f}, {100, 0.45, 0.55}}); + registry.add("hMassK0SPt", "hMassK0SPt", HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.45, 0.55}}); + registry.add("hMassK0SEta", "hMassK0SEta", HistType::kTH2F, {{20, -1, 1}, {100, 0.45, 0.55}}); + registry.add("hMassK0SPhi", "hMassK0SPhi", HistType::kTH2F, {{63, 0, 6.3}, {100, 0.45, 0.55}}); registry.add("hMassLambda", "hMassLambda", HistType::kTH2F, {{900, 0.0f, 90.0f}, {100, 1.05, 1.15f}}); registry.add("hMassAntiLambda", "hAntiMassLambda", HistType::kTH2F, {{900, 0.0f, 90.0f}, {100, 1.05, 1.15f}}); registry.add("hV0Pt", "pT", HistType::kTH1F, {{100, 0.0f, 10}}); @@ -277,7 +310,7 @@ struct v0selector { registry.fill(HIST("hMassGamma"), V0radius, mGamma); registry.fill(HIST("hV0Psi"), psipair, mGamma); } - if (mGamma < v0max_mee && TMath::Abs(V0.posTrack_as().tpcNSigmaEl()) < 5 && TMath::Abs(V0.negTrack_as().tpcNSigmaEl()) < 5 && psipair < maxpsipair) { + if (mGamma < v0max_mee && TMath::Abs(V0.posTrack_as().tpcNSigmaEl()) < cutNsigmaElTPC && TMath::Abs(V0.negTrack_as().tpcNSigmaEl()) < cutNsigmaElTPC && TMath::Abs(psipair) < maxpsipair) { pidmap[V0.posTrackId()] |= (uint8_t(1) << kGamma); pidmap[V0.negTrackId()] |= (uint8_t(1) << kGamma); if (fillhisto) { @@ -287,8 +320,11 @@ struct v0selector { } else if (v0id == kK0S) { // K0S-> pi pi if (fillhisto) { registry.fill(HIST("hMassK0S"), V0radius, mK0S); + registry.fill(HIST("hMassK0SPt"), V0.pt(), mK0S); + registry.fill(HIST("hMassK0SEta"), V0.eta(), mK0S); + registry.fill(HIST("hMassK0SPhi"), V0.phi(), mK0S); } - if ((0.48 < mK0S && mK0S < 0.51) && TMath::Abs(V0.posTrack_as().tpcNSigmaPi()) < 5 && TMath::Abs(V0.negTrack_as().tpcNSigmaPi()) < 5) { + if ((0.48 < mK0S && mK0S < 0.51) && TMath::Abs(V0.posTrack_as().tpcNSigmaPi()) < cutNsigmaPiTPC && TMath::Abs(V0.negTrack_as().tpcNSigmaPi()) < cutNsigmaPiTPC) { pidmap[V0.posTrackId()] |= (uint8_t(1) << kK0S); pidmap[V0.negTrackId()] |= (uint8_t(1) << kK0S); } @@ -296,7 +332,7 @@ struct v0selector { if (fillhisto) { registry.fill(HIST("hMassLambda"), V0radius, mLambda); } - if (v0id == kLambda && (1.110 < mLambda && mLambda < 1.120) && TMath::Abs(V0.posTrack_as().tpcNSigmaPr()) < 5 && TMath::Abs(V0.negTrack_as().tpcNSigmaPi()) < 5) { + if (v0id == kLambda && (1.110 < mLambda && mLambda < 1.120) && TMath::Abs(V0.posTrack_as().tpcNSigmaPr()) < cutNsigmaPrTPC && TMath::Abs(V0.negTrack_as().tpcNSigmaPi()) < cutNsigmaPiTPC) { pidmap[V0.posTrackId()] |= (uint8_t(1) << kLambda); pidmap[V0.negTrackId()] |= (uint8_t(1) << kLambda); } @@ -304,7 +340,7 @@ struct v0selector { if (fillhisto) { registry.fill(HIST("hMassAntiLambda"), V0radius, mAntiLambda); } - if ((1.110 < mAntiLambda && mAntiLambda < 1.120) && TMath::Abs(V0.posTrack_as().tpcNSigmaPi()) < 5 && TMath::Abs(V0.negTrack_as().tpcNSigmaPr()) < 5) { + if ((1.110 < mAntiLambda && mAntiLambda < 1.120) && TMath::Abs(V0.posTrack_as().tpcNSigmaPi()) < cutNsigmaPiTPC && TMath::Abs(V0.negTrack_as().tpcNSigmaPr()) < cutNsigmaPrTPC) { pidmap[V0.posTrackId()] |= (uint8_t(1) << kAntiLambda); pidmap[V0.negTrackId()] |= (uint8_t(1) << kAntiLambda); } diff --git a/PWGEM/Dilepton/CMakeLists.txt b/PWGEM/Dilepton/CMakeLists.txt index 9d96b0b8d33..7ff980baa4f 100644 --- a/PWGEM/Dilepton/CMakeLists.txt +++ b/PWGEM/Dilepton/CMakeLists.txt @@ -9,7 +9,7 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. -# add_subdirectory(Core) +add_subdirectory(Core) # add_subdirectory(DataModel) add_subdirectory(Tasks) add_subdirectory(TableProducer) diff --git a/PWGEM/Dilepton/Core/CMakeLists.txt b/PWGEM/Dilepton/Core/CMakeLists.txt new file mode 100644 index 00000000000..92d06924294 --- /dev/null +++ b/PWGEM/Dilepton/Core/CMakeLists.txt @@ -0,0 +1,22 @@ +# 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_library(PWGEMDileptonCore + SOURCES EMEventCut.cxx + DielectronCut.cxx + DimuonCut.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::MLCore) + +o2physics_target_root_dictionary(PWGEMDileptonCore + HEADERS EMEventCut.h + DielectronCut.h + DimuonCut.h + LINKDEF PWGEMDileptonCoreLinkDef.h) diff --git a/PWGEM/Dilepton/Core/DielectronCut.cxx b/PWGEM/Dilepton/Core/DielectronCut.cxx new file mode 100644 index 00000000000..784e09707bd --- /dev/null +++ b/PWGEM/Dilepton/Core/DielectronCut.cxx @@ -0,0 +1,342 @@ +// 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. + +// +// Class for dielectron Cut +// + +#include +#include + +#include "Framework/Logger.h" +#include "PWGEM/Dilepton/Core/DielectronCut.h" + +ClassImp(DielectronCut); + +const std::pair> DielectronCut::its_ib_any_Requirement = {1, {0, 1, 2}}; // hits on any ITS ib layers. +const std::pair> DielectronCut::its_ib_1st_Requirement = {1, {0}}; // hit on 1st ITS ib layers. + +void DielectronCut::SetPairPtRange(float minPt, float maxPt) +{ + mMinPairPt = minPt; + mMaxPairPt = maxPt; + LOG(info) << "Dielectron Cut, set pair pt range: " << mMinPairPt << " - " << mMaxPairPt; +} +void DielectronCut::SetPairYRange(float minY, float maxY) +{ + mMinPairY = minY; + mMaxPairY = maxY; + LOG(info) << "Dielectron Cut, set pair y range: " << mMinPairY << " - " << mMaxPairY; +} +void DielectronCut::SetPairDCARange(float min, float max) +{ + mMinPairDCA3D = min; + mMaxPairDCA3D = max; + LOG(info) << "Dielectron Cut, set pair 3d dca range: " << mMinPairDCA3D << " - " << mMaxPairDCA3D; +} +void DielectronCut::SetMeeRange(float min, float max) +{ + mMinMee = min; + mMaxMee = max; + LOG(info) << "Dielectron Cut, set mee range: " << mMinMee << " - " << mMaxMee; +} +void DielectronCut::SetPairOpAng(float minOpAng, float maxOpAng) +{ + mMinOpAng = minOpAng; + mMaxOpAng = maxOpAng; + LOG(info) << "Dielectron Cut, set pair opening angle range: " << mMinOpAng << " - " << mMaxOpAng; +} +void DielectronCut::SetMaxMeePhiVDep(std::function phivDepCut, float min_phiv, float max_phiv) +{ + mMaxMeePhiVDep = phivDepCut; + mMinPhivPair = min_phiv; + mMaxPhivPair = max_phiv; + LOG(info) << "Dielectron Cut, set max mee phiv dep: " << mMaxMeePhiVDep(2.5); +} +void DielectronCut::SelectPhotonConversion(bool flag) +{ + mSelectPC = flag; + LOG(info) << "Dielectron Cut, select photon conversion: " << mSelectPC; +} +void DielectronCut::SetMindEtadPhi(bool flag, float min_deta, float min_dphi) +{ + mApplydEtadPhi = flag; + mMinDeltaEta = min_deta; + mMinDeltaPhi = min_dphi; + LOG(info) << "Dielectron Cut, set apply deta-dphi cut: " << mApplydEtadPhi << " min_deta: " << mMinDeltaEta << " min_dphi: " << mMinDeltaPhi; +} +void DielectronCut::SetRequireDifferentSides(bool flag) +{ + mRequireDiffSides = flag; + LOG(info) << "Dielectron Cut, require 2 tracks to be from different sides: " << mRequireDiffSides; +} +void DielectronCut::SetTrackPtRange(float minPt, float maxPt) +{ + mMinTrackPt = minPt; + mMaxTrackPt = maxPt; + LOG(info) << "Dielectron Cut, set track pt range: " << mMinTrackPt << " - " << mMaxTrackPt; +} +void DielectronCut::SetTrackEtaRange(float minEta, float maxEta) +{ + mMinTrackEta = minEta; + mMaxTrackEta = maxEta; + LOG(info) << "Dielectron Cut, set track eta range: " << mMinTrackEta << " - " << mMaxTrackEta; +} +void DielectronCut::SetTrackPhiRange(float minPhi, float maxPhi) +{ + mMinTrackPhi = minPhi; + mMaxTrackPhi = maxPhi; + LOG(info) << "Dielectron Cut, set track phi range (rad.): " << mMinTrackPhi << " - " << mMaxTrackPhi; +} +void DielectronCut::SetMinNClustersTPC(int minNClustersTPC) +{ + mMinNClustersTPC = minNClustersTPC; + LOG(info) << "Dielectron Cut, set min N clusters TPC: " << mMinNClustersTPC; +} +void DielectronCut::SetMinNCrossedRowsTPC(int minNCrossedRowsTPC) +{ + mMinNCrossedRowsTPC = minNCrossedRowsTPC; + LOG(info) << "Dielectron Cut, set min N crossed rows TPC: " << mMinNCrossedRowsTPC; +} +void DielectronCut::SetMinNCrossedRowsOverFindableClustersTPC(float minNCrossedRowsOverFindableClustersTPC) +{ + mMinNCrossedRowsOverFindableClustersTPC = minNCrossedRowsOverFindableClustersTPC; + LOG(info) << "Dielectron Cut, set min N crossed rows over findable clusters TPC: " << mMinNCrossedRowsOverFindableClustersTPC; +} +void DielectronCut::SetMaxFracSharedClustersTPC(float max) +{ + mMaxFracSharedClustersTPC = max; + LOG(info) << "Dielectron Cut, set max fraction of shared clusters in TPC: " << mMaxFracSharedClustersTPC; +} +void DielectronCut::SetRelDiffPin(float min, float max) +{ + mMinRelDiffPin = min; + mMaxRelDiffPin = max; + LOG(info) << "Dielectron Cut, set rel. diff. between Pin and Ppv range: " << mMinRelDiffPin << " - " << mMaxRelDiffPin; +} +void DielectronCut::SetChi2PerClusterTPC(float min, float max) +{ + mMinChi2PerClusterTPC = min; + mMaxChi2PerClusterTPC = max; + LOG(info) << "Dielectron Cut, set chi2 per cluster TPC range: " << mMinChi2PerClusterTPC << " - " << mMaxChi2PerClusterTPC; +} + +void DielectronCut::SetNClustersITS(int min, int max) +{ + mMinNClustersITS = min; + mMaxNClustersITS = max; + LOG(info) << "Dielectron Cut, set N clusters ITS range: " << mMinNClustersITS << " - " << mMaxNClustersITS; +} +void DielectronCut::SetChi2PerClusterITS(float min, float max) +{ + mMinChi2PerClusterITS = min; + mMaxChi2PerClusterITS = max; + LOG(info) << "Dielectron Cut, set chi2 per cluster ITS range: " << mMinChi2PerClusterITS << " - " << mMaxChi2PerClusterITS; +} +void DielectronCut::SetMeanClusterSizeITS(float min, float max, float minP, float maxP) +{ + mMinMeanClusterSizeITS = min; + mMaxMeanClusterSizeITS = max; + mMinP_ITSClusterSize = minP; + mMaxP_ITSClusterSize = maxP; + LOG(info) << "Dielectron Cut, set mean cluster size ITS range: " << mMinMeanClusterSizeITS << " - " << mMaxMeanClusterSizeITS; +} +void DielectronCut::SetChi2TOF(float min, float max) +{ + mMinChi2TOF = min; + mMaxChi2TOF = max; + LOG(info) << "Dielectron Cut, set chi2 TOF range: " << mMinChi2TOF << " - " << mMaxChi2TOF; +} + +void DielectronCut::SetTrackDca3DRange(float min, float max) +{ + mMinDca3D = min; + mMaxDca3D = max; + LOG(info) << "Dielectron Cut, set DCA 3D range in sigma: " << mMinDca3D << " - " << mMaxDca3D; +} +void DielectronCut::SetTrackMaxDcaXY(float maxDcaXY) +{ + mMaxDcaXY = maxDcaXY; + LOG(info) << "Dielectron Cut, set max DCA xy: " << mMaxDcaXY; +} +void DielectronCut::SetTrackMaxDcaZ(float maxDcaZ) +{ + mMaxDcaZ = maxDcaZ; + LOG(info) << "Dielectron Cut, set max DCA z: " << mMaxDcaZ; +} + +void DielectronCut::SetTrackMaxDcaXYPtDep(std::function ptDepCut) +{ + mMaxDcaXYPtDep = ptDepCut; + LOG(info) << "Dielectron Cut, set max DCA xy pt dep: " << mMaxDcaXYPtDep(1.0); +} +void DielectronCut::ApplyPhiV(bool flag) +{ + mApplyPhiV = flag; + LOG(info) << "Dielectron Cut, apply phiv cut: " << mApplyPhiV; +} +void DielectronCut::ApplyPrefilter(bool flag) +{ + mApplyPF = flag; + LOG(info) << "Dielectron Cut, apply prefilter: " << mApplyPF; +} + +void DielectronCut::SetPIDScheme(int scheme) +{ + mPIDScheme = scheme; + LOG(info) << "Dielectron Cut, PID scheme: " << static_cast(mPIDScheme); +} +void DielectronCut::SetMinPinTOF(float min) +{ + mMinPinTOF = min; + LOG(info) << "Dielectron Cut, set min pin for TOF: " << mMinPinTOF; +} + +void DielectronCut::SetMuonExclusionTPC(bool flag) +{ + mMuonExclusionTPC = flag; + LOG(info) << "Dielectron Cut, set flag for muon exclusion in TPC: " << mMuonExclusionTPC; +} + +void DielectronCut::SetTOFbetaRange(float min, float max) +{ + mMinTOFbeta = min; + mMaxTOFbeta = max; + LOG(info) << "Dielectron Cut, set TOF beta range (TOFif): " << mMinTOFbeta << " - " << mMaxTOFbeta; +} + +void DielectronCut::SetTPCNsigmaElRange(float min, float max) +{ + mMinTPCNsigmaEl = min; + mMaxTPCNsigmaEl = max; + LOG(info) << "Dielectron Cut, set TPC n sigma El range: " << mMinTPCNsigmaEl << " - " << mMaxTPCNsigmaEl; +} +void DielectronCut::SetTPCNsigmaMuRange(float min, float max) +{ + mMinTPCNsigmaMu = min; + mMaxTPCNsigmaMu = max; + LOG(info) << "Dielectron Cut, set TPC n sigma Mu range: " << mMinTPCNsigmaMu << " - " << mMaxTPCNsigmaMu; +} +void DielectronCut::SetTPCNsigmaPiRange(float min, float max) +{ + mMinTPCNsigmaPi = min; + mMaxTPCNsigmaPi = max; + LOG(info) << "Dielectron Cut, set TPC n sigma Pi range: " << mMinTPCNsigmaPi << " - " << mMaxTPCNsigmaPi; +} +void DielectronCut::SetTPCNsigmaKaRange(float min, float max) +{ + mMinTPCNsigmaKa = min; + mMaxTPCNsigmaKa = max; + LOG(info) << "Dielectron Cut, set TPC n sigma Ka range: " << mMinTPCNsigmaKa << " - " << mMaxTPCNsigmaKa; +} +void DielectronCut::SetTPCNsigmaPrRange(float min, float max) +{ + mMinTPCNsigmaPr = min; + mMaxTPCNsigmaPr = max; + LOG(info) << "Dielectron Cut, set TPC n sigma Pr range: " << mMinTPCNsigmaPr << " - " << mMaxTPCNsigmaPr; +} + +void DielectronCut::SetTOFNsigmaElRange(float min, float max) +{ + mMinTOFNsigmaEl = min; + mMaxTOFNsigmaEl = max; + LOG(info) << "Dielectron Cut, set TOF n sigma El range: " << mMinTOFNsigmaEl << " - " << mMaxTOFNsigmaEl; +} +void DielectronCut::SetTOFNsigmaMuRange(float min, float max) +{ + mMinTOFNsigmaMu = min; + mMaxTOFNsigmaMu = max; + LOG(info) << "Dielectron Cut, set TOF n sigma Mu range: " << mMinTOFNsigmaMu << " - " << mMaxTOFNsigmaMu; +} +void DielectronCut::SetTOFNsigmaPiRange(float min, float max) +{ + mMinTOFNsigmaPi = min; + mMaxTOFNsigmaPi = max; + LOG(info) << "Dielectron Cut, set TOF n sigma Pi range: " << mMinTOFNsigmaPi << " - " << mMaxTOFNsigmaPi; +} +void DielectronCut::SetTOFNsigmaKaRange(float min, float max) +{ + mMinTOFNsigmaKa = min; + mMaxTOFNsigmaKa = max; + LOG(info) << "Dielectron Cut, set TOF n sigma Ka range: " << mMinTOFNsigmaKa << " - " << mMaxTOFNsigmaKa; +} +void DielectronCut::SetTOFNsigmaPrRange(float min, float max) +{ + mMinTOFNsigmaPr = min; + mMaxTOFNsigmaPr = max; + LOG(info) << "Dielectron Cut, set TOF n sigma Pr range: " << mMinTOFNsigmaPr << " - " << mMaxTOFNsigmaPr; +} + +void DielectronCut::SetITSNsigmaElRange(float min, float max) +{ + mMinITSNsigmaEl = min; + mMaxITSNsigmaEl = max; + LOG(info) << "Dielectron Cut, set ITS n sigma El range: " << mMinITSNsigmaEl << " - " << mMaxITSNsigmaEl; +} +void DielectronCut::SetITSNsigmaMuRange(float min, float max) +{ + mMinITSNsigmaMu = min; + mMaxITSNsigmaMu = max; + LOG(info) << "Dielectron Cut, set ITS n sigma Mu range: " << mMinITSNsigmaMu << " - " << mMaxITSNsigmaMu; +} +void DielectronCut::SetITSNsigmaPiRange(float min, float max) +{ + mMinITSNsigmaPi = min; + mMaxITSNsigmaPi = max; + LOG(info) << "Dielectron Cut, set ITS n sigma Pi range: " << mMinITSNsigmaPi << " - " << mMaxITSNsigmaPi; +} +void DielectronCut::SetITSNsigmaKaRange(float min, float max) +{ + mMinITSNsigmaKa = min; + mMaxITSNsigmaKa = max; + LOG(info) << "Dielectron Cut, set ITS n sigma Ka range: " << mMinITSNsigmaKa << " - " << mMaxITSNsigmaKa; +} +void DielectronCut::SetITSNsigmaPrRange(float min, float max) +{ + mMinITSNsigmaPr = min; + mMaxITSNsigmaPr = max; + LOG(info) << "Dielectron Cut, set ITS n sigma Pr range: " << mMinITSNsigmaPr << " - " << mMaxITSNsigmaPr; +} + +void DielectronCut::SetPRangeForITSNsigmaKa(float min, float max) +{ + mMinP_ITSNsigmaKa = min; + mMaxP_ITSNsigmaKa = max; + LOG(info) << "Dielectron Cut, set p range for ITS n sigma Ka: " << mMinP_ITSNsigmaKa << " - " << mMaxP_ITSNsigmaKa; +} + +void DielectronCut::SetPRangeForITSNsigmaPr(float min, float max) +{ + mMinP_ITSNsigmaPr = min; + mMaxP_ITSNsigmaPr = max; + LOG(info) << "Dielectron Cut, set p range for ITS n sigma Pr: " << mMinP_ITSNsigmaPr << " - " << mMaxP_ITSNsigmaPr; +} + +void DielectronCut::SetMaxPinMuonTPConly(float max) +{ + mMaxPinMuonTPConly = max; + LOG(info) << "Dielectron Cut, set max pin for Muon ID with TPC only: " << mMaxPinMuonTPConly; +} +void DielectronCut::SetMaxPinForPionRejectionTPC(float max) +{ + mMaxPinForPionRejectionTPC = max; + LOG(info) << "Dielectron Cut, set max pin for pion rejection in TPC: " << mMaxPinForPionRejectionTPC; +} +void DielectronCut::RequireITSibAny(bool flag) +{ + mRequireITSibAny = flag; + LOG(info) << "Dielectron Cut, require ITS ib any: " << mRequireITSibAny; +} +void DielectronCut::RequireITSib1st(bool flag) +{ + mRequireITSib1st = flag; + LOG(info) << "Dielectron Cut, require ITS ib 1st: " << mRequireITSib1st; +} diff --git a/PWGEM/Dilepton/Core/DielectronCut.h b/PWGEM/Dilepton/Core/DielectronCut.h new file mode 100644 index 00000000000..d1c305d3d72 --- /dev/null +++ b/PWGEM/Dilepton/Core/DielectronCut.h @@ -0,0 +1,544 @@ +// 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. + +// +// Class for dielectron selection +// + +#ifndef PWGEM_DILEPTON_CORE_DIELECTRONCUT_H_ +#define PWGEM_DILEPTON_CORE_DIELECTRONCUT_H_ + +#include +#include +#include +#include +#include +#include "TNamed.h" +#include "Math/Vector4D.h" + +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" + +#include "Framework/Logger.h" +#include "Framework/DataTypes.h" +#include "CommonConstants/PhysicsConstants.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" + +using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; +using namespace o2::aod::pwgem::dilepton::utils::pairutil; + +class DielectronCut : public TNamed +{ + public: + DielectronCut() = default; + DielectronCut(const char* name, const char* title) : TNamed(name, title) {} + ~DielectronCut() {} + + enum class DielectronCuts : int { + // pair cut + kMee = 0, + kPairPtRange, + kPairYRange, + kPairDCARange, + kPhiV, + // track cut + kTrackPtRange, + kTrackEtaRange, + kTrackPhiRange, + kTPCNCls, + kTPCCrossedRows, + kTPCCrossedRowsOverNCls, + kTPCFracSharedClusters, + kRelDiffPin, + kTPCChi2NDF, + kDCA3Dsigma, + kDCAxy, + kDCAz, + kITSNCls, + kITSChi2NDF, + kITSClusterSize, + kPrefilter, + kNCuts + }; + + enum class PIDSchemes : int { + kUnDef = -1, + kTOFreq = 0, + kTPChadrej = 1, + kTPChadrejORTOFreq = 2, + kTPConly = 3, + kTOFif = 4, + kPIDML = 5, + kTPChadrejORTOFreq_woTOFif = 6 + }; + + template + bool IsSelected(TPair const& pair) const + { + auto t1 = std::get<0>(pair); + auto t2 = std::get<1>(pair); + float bz = std::get<2>(pair); + + if (!IsSelectedTrack(t1) || !IsSelectedTrack(t2)) { + return false; + } + + if (!IsSelectedPair(t1, t2, bz)) { + return false; + } + + return true; + } + + template + bool IsSelectedPair(TTrack1 const& t1, TTrack2 const& t2, const float bz) const + { + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + + float dca_ee_3d = pairDCAQuadSum(dca3DinSigma(t1), dca3DinSigma(t2)); + float phiv = getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), bz); + float opAng = getOpeningAngle(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz()); + + if (v12.M() < mMinMee || mMaxMee < v12.M()) { + return false; + } + + if (!dont_require_rapidity && (v12.Rapidity() < mMinPairY || mMaxPairY < v12.Rapidity())) { + return false; + } + + if (mApplyPhiV) { + if (((mMinPhivPair < phiv && phiv < mMaxPhivPair) && v12.M() < mMaxMeePhiVDep(phiv)) ^ mSelectPC) { + return false; + } + } + + if (dca_ee_3d < mMinPairDCA3D || mMaxPairDCA3D < dca_ee_3d) { // in sigma for pair + return false; + } + + if (opAng < mMinOpAng || mMaxOpAng < opAng) { + return false; + } + + if (mRequireDiffSides && t1.eta() * t2.eta() > 0.0) { + return false; + } + + float deta = v1.Eta() - v2.Eta(); + float dphi = v1.Phi() - v2.Phi(); + o2::math_utils::bringToPMPi(dphi); + if (mApplydEtadPhi && std::pow(deta / mMinDeltaEta, 2) + std::pow(dphi / mMinDeltaPhi, 2) < 1.f) { + return false; + } + + return true; + } + + template + bool IsSelectedTrack(TTrack const& track, TCollision const& collision = 0) const + { + if (!track.hasITS() || !track.hasTPC()) { // track has to be ITS-TPC matched track + return false; + } + + if (!dont_require_pteta) { + if (!IsSelectedTrack(track, DielectronCuts::kTrackPtRange)) { + return false; + } + if (!IsSelectedTrack(track, DielectronCuts::kTrackEtaRange)) { + return false; + } + } + + if (!IsSelectedTrack(track, DielectronCuts::kTrackPhiRange)) { + return false; + } + if (!IsSelectedTrack(track, DielectronCuts::kDCA3Dsigma)) { + return false; + } + if (!IsSelectedTrack(track, DielectronCuts::kDCAxy)) { + return false; + } + if (!IsSelectedTrack(track, DielectronCuts::kDCAz)) { + return false; + } + + // ITS cuts + if (!IsSelectedTrack(track, DielectronCuts::kITSNCls)) { + return false; + } + if (!IsSelectedTrack(track, DielectronCuts::kITSChi2NDF)) { + return false; + } + if (!IsSelectedTrack(track, DielectronCuts::kITSClusterSize)) { + return false; + } + + if (mRequireITSibAny) { + auto hits_ib = std::count_if(its_ib_any_Requirement.second.begin(), its_ib_any_Requirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); + if (hits_ib < its_ib_any_Requirement.first) { + return false; + } + } + + if (mRequireITSib1st) { + auto hits_ib = std::count_if(its_ib_1st_Requirement.second.begin(), its_ib_1st_Requirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); + if (hits_ib < its_ib_1st_Requirement.first) { + return false; + } + } + + // TPC cuts + if (!IsSelectedTrack(track, DielectronCuts::kTPCNCls)) { + return false; + } + if (!IsSelectedTrack(track, DielectronCuts::kTPCCrossedRows)) { + return false; + } + if (!IsSelectedTrack(track, DielectronCuts::kTPCCrossedRowsOverNCls)) { + return false; + } + if (!IsSelectedTrack(track, DielectronCuts::kTPCFracSharedClusters)) { + return false; + } + if (!IsSelectedTrack(track, DielectronCuts::kRelDiffPin)) { + return false; + } + if (!IsSelectedTrack(track, DielectronCuts::kTPCChi2NDF)) { + return false; + } + + if (mApplyPF && !IsSelectedTrack(track, DielectronCuts::kPrefilter)) { + return false; + } + + // PID cuts + if constexpr (isML) { + if (!PassPIDML(track, collision)) { + return false; + } + } else { + if (!PassPID(track)) { + return false; + } + } + + return true; + } + + template + bool PassPIDML(TTrack const& track, TCollision const& collision) const + { + /*if (!PassTOFif(track)) { // Allows for pre-selection. But potentially dangerous if analyzers are not aware of it + return false; + }*/ + std::vector inputFeatures = mPIDMlResponse->getInputFeatures(track, collision); + float binningFeature = mPIDMlResponse->getBinningFeature(track, collision); + return mPIDMlResponse->isSelectedMl(inputFeatures, binningFeature); + } + + template + bool PassPID(T const& track) const + { + switch (mPIDScheme) { + case static_cast(PIDSchemes::kTOFreq): + return PassTOFreq(track); + + case static_cast(PIDSchemes::kTPChadrej): + return PassTPChadrej(track); + + case static_cast(PIDSchemes::kTPChadrejORTOFreq): + return PassTPChadrej(track) || PassTOFreq(track); + + case static_cast(PIDSchemes::kTPConly): + return PassTPConly(track); + + case static_cast(PIDSchemes::kTOFif): + return PassTOFif(track); + + case static_cast(PIDSchemes::kPIDML): + return true; // don't use kPIDML here. + + case static_cast(PIDSchemes::kTPChadrejORTOFreq_woTOFif): + return PassTPConlyhadrej(track) || PassTOFreq(track); + + case static_cast(PIDSchemes::kUnDef): + return true; + + default: + return true; + } + } + + template + bool PassTOFreq(T const& track) const + { + bool is_el_included_TPC = mMinTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < mMaxTPCNsigmaEl; + bool is_pi_excluded_TPC = track.tpcInnerParam() < mMaxPinForPionRejectionTPC ? (track.tpcNSigmaPi() < mMinTPCNsigmaPi || mMaxTPCNsigmaPi < track.tpcNSigmaPi()) : true; + bool is_el_included_TOF = (mMinTOFNsigmaEl < track.tofNSigmaEl() && track.tofNSigmaEl() < mMaxTOFNsigmaEl) && (track.hasTOF() && track.tofChi2() < mMaxChi2TOF); + bool is_ka_excluded_ITS = (mMinP_ITSNsigmaKa < track.p() && track.p() < mMaxP_ITSNsigmaKa) ? (track.itsNSigmaKa() < mMinITSNsigmaKa || mMaxITSNsigmaKa < track.itsNSigmaKa()) : true; + bool is_pr_excluded_ITS = (mMinP_ITSNsigmaPr < track.p() && track.p() < mMaxP_ITSNsigmaPr) ? (track.itsNSigmaPr() < mMinITSNsigmaPr || mMaxITSNsigmaPr < track.itsNSigmaPr()) : true; + return is_el_included_TPC && is_pi_excluded_TPC && is_el_included_TOF && is_ka_excluded_ITS && is_pr_excluded_ITS; + } + + template + bool PassTPChadrej(T const& track) const + { + bool is_el_included_TPC = mMinTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < mMaxTPCNsigmaEl; + bool is_mu_excluded_TPC = mMuonExclusionTPC ? track.tpcNSigmaMu() < mMinTPCNsigmaMu || mMaxTPCNsigmaMu < track.tpcNSigmaMu() : true; + bool is_pi_excluded_TPC = track.tpcInnerParam() < mMaxPinForPionRejectionTPC ? (track.tpcNSigmaPi() < mMinTPCNsigmaPi || mMaxTPCNsigmaPi < track.tpcNSigmaPi()) : true; + bool is_ka_excluded_TPC = track.tpcNSigmaKa() < mMinTPCNsigmaKa || mMaxTPCNsigmaKa < track.tpcNSigmaKa(); + bool is_pr_excluded_TPC = track.tpcNSigmaPr() < mMinTPCNsigmaPr || mMaxTPCNsigmaPr < track.tpcNSigmaPr(); + bool is_el_included_TOF = track.hasTOF() ? (mMinTOFNsigmaEl < track.tofNSigmaEl() && track.tofNSigmaEl() < mMaxTOFNsigmaEl && track.tofChi2() < mMaxChi2TOF) : true; + bool is_ka_excluded_ITS = (mMinP_ITSNsigmaKa < track.p() && track.p() < mMaxP_ITSNsigmaKa) ? (track.itsNSigmaKa() < mMinITSNsigmaKa || mMaxITSNsigmaKa < track.itsNSigmaKa()) : true; + bool is_pr_excluded_ITS = (mMinP_ITSNsigmaPr < track.p() && track.p() < mMaxP_ITSNsigmaPr) ? (track.itsNSigmaPr() < mMinITSNsigmaPr || mMaxITSNsigmaPr < track.itsNSigmaPr()) : true; + return is_el_included_TPC && is_mu_excluded_TPC && is_pi_excluded_TPC && is_ka_excluded_TPC && is_pr_excluded_TPC && is_el_included_TOF && is_ka_excluded_ITS && is_pr_excluded_ITS; + } + + template + bool PassTPConly(T const& track) const + { + bool is_el_included_TPC = mMinTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < mMaxTPCNsigmaEl; + bool is_ka_excluded_ITS = (mMinP_ITSNsigmaKa < track.p() && track.p() < mMaxP_ITSNsigmaKa) ? (track.itsNSigmaKa() < mMinITSNsigmaKa || mMaxITSNsigmaKa < track.itsNSigmaKa()) : true; + bool is_pr_excluded_ITS = (mMinP_ITSNsigmaPr < track.p() && track.p() < mMaxP_ITSNsigmaPr) ? (track.itsNSigmaPr() < mMinITSNsigmaPr || mMaxITSNsigmaPr < track.itsNSigmaPr()) : true; + return is_el_included_TPC && is_ka_excluded_ITS && is_pr_excluded_ITS; + } + + template + bool PassTPConlyhadrej(T const& track) const + { + bool is_el_included_TPC = mMinTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < mMaxTPCNsigmaEl; + bool is_mu_excluded_TPC = mMuonExclusionTPC ? track.tpcNSigmaMu() < mMinTPCNsigmaMu || mMaxTPCNsigmaMu < track.tpcNSigmaMu() : true; + bool is_pi_excluded_TPC = track.tpcInnerParam() < mMaxPinForPionRejectionTPC ? (track.tpcNSigmaPi() < mMinTPCNsigmaPi || mMaxTPCNsigmaPi < track.tpcNSigmaPi()) : true; + bool is_ka_excluded_TPC = track.tpcNSigmaKa() < mMinTPCNsigmaKa || mMaxTPCNsigmaKa < track.tpcNSigmaKa(); + bool is_pr_excluded_TPC = track.tpcNSigmaPr() < mMinTPCNsigmaPr || mMaxTPCNsigmaPr < track.tpcNSigmaPr(); + bool is_ka_excluded_ITS = (mMinP_ITSNsigmaKa < track.p() && track.p() < mMaxP_ITSNsigmaKa) ? (track.itsNSigmaKa() < mMinITSNsigmaKa || mMaxITSNsigmaKa < track.itsNSigmaKa()) : true; + bool is_pr_excluded_ITS = (mMinP_ITSNsigmaPr < track.p() && track.p() < mMaxP_ITSNsigmaPr) ? (track.itsNSigmaPr() < mMinITSNsigmaPr || mMaxITSNsigmaPr < track.itsNSigmaPr()) : true; + return is_el_included_TPC && is_mu_excluded_TPC && is_pi_excluded_TPC && is_ka_excluded_TPC && is_pr_excluded_TPC && is_ka_excluded_ITS && is_pr_excluded_ITS; + } + + template + bool PassTOFif(T const& track) const + { + bool is_el_included_TPC = mMinTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < mMaxTPCNsigmaEl; + bool is_pi_excluded_TPC = track.tpcInnerParam() < mMaxPinForPionRejectionTPC ? (track.tpcNSigmaPi() < mMinTPCNsigmaPi || mMaxTPCNsigmaPi < track.tpcNSigmaPi()) : true; + bool is_el_included_TOF = track.hasTOF() ? (mMinTOFNsigmaEl < track.tofNSigmaEl() && track.tofNSigmaEl() < mMaxTOFNsigmaEl && track.tofChi2() < mMaxChi2TOF) : true; + bool is_ka_excluded_ITS = (mMinP_ITSNsigmaKa < track.p() && track.p() < mMaxP_ITSNsigmaKa) ? (track.itsNSigmaKa() < mMinITSNsigmaKa || mMaxITSNsigmaKa < track.itsNSigmaKa()) : true; + bool is_pr_excluded_ITS = (mMinP_ITSNsigmaPr < track.p() && track.p() < mMaxP_ITSNsigmaPr) ? (track.itsNSigmaPr() < mMinITSNsigmaPr || mMaxITSNsigmaPr < track.itsNSigmaPr()) : true; + return is_el_included_TPC && is_pi_excluded_TPC && is_el_included_TOF && is_ka_excluded_ITS && is_pr_excluded_ITS; + } + + template + bool IsSelectedTrack(T const& track, const DielectronCuts& cut) const + { + switch (cut) { + case DielectronCuts::kTrackPtRange: + return track.pt() >= mMinTrackPt && track.pt() <= mMaxTrackPt; + + case DielectronCuts::kTrackEtaRange: + return track.eta() >= mMinTrackEta && track.eta() <= mMaxTrackEta; + + case DielectronCuts::kTrackPhiRange: + return track.phi() >= mMinTrackPhi && track.phi() <= mMaxTrackPhi; + + case DielectronCuts::kTPCNCls: + return track.tpcNClsFound() >= mMinNClustersTPC; + + case DielectronCuts::kTPCCrossedRows: + return track.tpcNClsCrossedRows() >= mMinNCrossedRowsTPC; + + case DielectronCuts::kTPCCrossedRowsOverNCls: + return track.tpcCrossedRowsOverFindableCls() >= mMinNCrossedRowsOverFindableClustersTPC; + + case DielectronCuts::kTPCFracSharedClusters: + return track.tpcFractionSharedCls() <= mMaxFracSharedClustersTPC; + + case DielectronCuts::kRelDiffPin: + return mMinRelDiffPin < (track.tpcInnerParam() - track.p()) / track.p() && (track.tpcInnerParam() - track.p()) / track.p() < mMaxRelDiffPin; + + case DielectronCuts::kTPCChi2NDF: + return mMinChi2PerClusterTPC < track.tpcChi2NCl() && track.tpcChi2NCl() < mMaxChi2PerClusterTPC; + + case DielectronCuts::kDCA3Dsigma: + return mMinDca3D <= dca3DinSigma(track) && dca3DinSigma(track) <= mMaxDca3D; // in sigma for single leg + + case DielectronCuts::kDCAxy: + return std::fabs(track.dcaXY()) <= ((mMaxDcaXYPtDep) ? mMaxDcaXYPtDep(track.pt()) : mMaxDcaXY); + + case DielectronCuts::kDCAz: + return std::fabs(track.dcaZ()) <= mMaxDcaZ; + + case DielectronCuts::kITSNCls: + return mMinNClustersITS <= track.itsNCls() && track.itsNCls() <= mMaxNClustersITS; + + case DielectronCuts::kITSChi2NDF: + return mMinChi2PerClusterITS < track.itsChi2NCl() && track.itsChi2NCl() < mMaxChi2PerClusterITS; + + case DielectronCuts::kITSClusterSize: + return ((mMinP_ITSClusterSize < track.p() && track.p() < mMaxP_ITSClusterSize) ? (mMinMeanClusterSizeITS < track.meanClusterSizeITS() * std::cos(std::atan(track.tgl())) && track.meanClusterSizeITS() * std::cos(std::atan(track.tgl())) < mMaxMeanClusterSizeITS) : true); + + case DielectronCuts::kPrefilter: + return track.pfb() <= 0; + + default: + return false; + } + } + + // Setters + void SetPairPtRange(float minPt = 0.f, float maxPt = 1e10f); + void SetPairYRange(float minY = -1e10f, float maxY = 1e10f); + void SetPairDCARange(float min = 0.f, float max = 1e10f); // 3D DCA in sigma + void SetMeeRange(float min = 0.f, float max = 0.5); + void SetPairOpAng(float minOpAng = 0.f, float maxOpAng = 1e10f); + void SetMaxMeePhiVDep(std::function phivDepCut, float min_phiv, float max_phiv); + void SelectPhotonConversion(bool flag); + void SetMindEtadPhi(bool flag, float min_deta, float min_dphi); + void SetRequireDifferentSides(bool flag); + + void SetTrackPtRange(float minPt = 0.f, float maxPt = 1e10f); + void SetTrackEtaRange(float minEta = -1e10f, float maxEta = 1e10f); + void SetTrackPhiRange(float minPhi = 0.f, float maxPhi = 2.f * M_PI); + void SetMinNClustersTPC(int minNClustersTPC); + void SetMinNCrossedRowsTPC(int minNCrossedRowsTPC); + void SetMinNCrossedRowsOverFindableClustersTPC(float minNCrossedRowsOverFindableClustersTPC); + void SetMaxFracSharedClustersTPC(float max); + void SetRelDiffPin(float min, float max); + void SetChi2PerClusterTPC(float min, float max); + void SetNClustersITS(int min, int max); + void SetChi2PerClusterITS(float min, float max); + void SetMeanClusterSizeITS(float min, float max, float minP = 0.f, float maxP = 0.f); + void SetChi2TOF(float min, float max); + + void SetPIDScheme(int scheme); + void SetMinPinTOF(float min); + void SetMuonExclusionTPC(bool flag); + void SetTOFbetaRange(float min, float max); + void SetTPCNsigmaElRange(float min, float max); + void SetTPCNsigmaMuRange(float min, float max); + void SetTPCNsigmaPiRange(float min, float max); + void SetTPCNsigmaKaRange(float min, float max); + void SetTPCNsigmaPrRange(float min, float max); + void SetTOFNsigmaElRange(float min, float max); + void SetTOFNsigmaMuRange(float min, float max); + void SetTOFNsigmaPiRange(float min, float max); + void SetTOFNsigmaKaRange(float min, float max); + void SetTOFNsigmaPrRange(float min, float max); + void SetITSNsigmaElRange(float min, float max); + void SetITSNsigmaMuRange(float min, float max); + void SetITSNsigmaPiRange(float min, float max); + void SetITSNsigmaKaRange(float min, float max); + void SetITSNsigmaPrRange(float min, float max); + + void SetPRangeForITSNsigmaKa(float min, float max); + void SetPRangeForITSNsigmaPr(float min, float max); + + void SetMaxPinMuonTPConly(float max); + void SetMaxPinForPionRejectionTPC(float max); + void RequireITSibAny(bool flag); + void RequireITSib1st(bool flag); + + void SetTrackDca3DRange(float min, float max); // in sigma + void SetTrackMaxDcaXY(float maxDcaXY); // in cm + void SetTrackMaxDcaZ(float maxDcaZ); // in cm + void SetTrackMaxDcaXYPtDep(std::function ptDepCut); + void ApplyPrefilter(bool flag); + void ApplyPhiV(bool flag); + + void SetPIDMlResponse(o2::analysis::MlResponseDielectronSingleTrack* mlResponse) + { + mPIDMlResponse = mlResponse; + } + + // Getters + bool IsPhotonConversionSelected() const { return mSelectPC; } + + private: + static const std::pair> its_ib_any_Requirement; + static const std::pair> its_ib_1st_Requirement; + // pair cuts + float mMinMee{0.f}, mMaxMee{1e10f}; + float mMinPairPt{0.f}, mMaxPairPt{1e10f}; // range in pT + float mMinPairY{-1e10f}, mMaxPairY{1e10f}; // range in rapidity + float mMinPairDCA3D{0.f}, mMaxPairDCA3D{1e10f}; // range in 3D DCA in sigma + float mMinPhivPair{0.f}, mMaxPhivPair{+3.2}; + std::function mMaxMeePhiVDep{}; // max mee as a function of phiv + bool mSelectPC{false}; // flag to select photon conversion used in mMaxPhivPairMeeDep + bool mApplydEtadPhi{false}; // flag to apply deta, dphi cut between 2 tracks + float mMinDeltaEta{0.f}; + float mMinDeltaPhi{0.f}; + float mMinOpAng{0.f}, mMaxOpAng{1e10f}; + bool mRequireDiffSides{false}; // flag to require 2 tracks to be from different sides. (A-C combination). If one wants 2 tracks to be in the same side (A-A or C-C), one can simply use track eta cut. + + // kinematic cuts + float mMinTrackPt{0.f}, mMaxTrackPt{1e10f}; // range in pT + float mMinTrackEta{-1e10f}, mMaxTrackEta{1e10f}; // range in eta + float mMinTrackPhi{0.f}, mMaxTrackPhi{2.f * M_PI}; // range in phi + + // track quality cuts + int mMinNClustersTPC{0}; // min number of TPC clusters + int mMinNCrossedRowsTPC{0}; // min number of crossed rows in TPC + float mMinChi2PerClusterTPC{-1e10f}, mMaxChi2PerClusterTPC{1e10f}; // max tpc fit chi2 per TPC cluster + float mMinNCrossedRowsOverFindableClustersTPC{0.f}; // min ratio crossed rows / findable clusters + float mMaxFracSharedClustersTPC{999.f}; // max ratio shared clusters / clusters in TPC + float mMinRelDiffPin{-1e10f}, mMaxRelDiffPin{1e10f}; // max relative difference between p at TPC inner wall and p at PV + int mMinNClustersITS{0}, mMaxNClustersITS{7}; // range in number of ITS clusters + float mMinChi2PerClusterITS{-1e10f}, mMaxChi2PerClusterITS{1e10f}; // max its fit chi2 per ITS cluster + float mMaxPinMuonTPConly{0.2f}; // max pin cut for muon ID with TPConly + float mMaxPinForPionRejectionTPC{1e10f}; // max pin for pion rejection in TPC + bool mRequireITSibAny{true}; + bool mRequireITSib1st{false}; + float mMinChi2TOF{-1e10f}, mMaxChi2TOF{1e10f}; // max tof chi2 per + + float mMinDca3D{0.0f}; // min dca in 3D in units of sigma + float mMaxDca3D{1e+10}; // max dca in 3D in units of sigma + float mMaxDcaXY{1.0f}; // max dca in xy plane + float mMaxDcaZ{1.0f}; // max dca in z direction + std::function mMaxDcaXYPtDep{}; // max dca in xy plane as function of pT + bool mApplyPhiV{true}; + bool mApplyPF{false}; + float mMinMeanClusterSizeITS{-1e10f}, mMaxMeanClusterSizeITS{1e10f}; // max x cos(Lmabda) + float mMinP_ITSClusterSize{0.0}, mMaxP_ITSClusterSize{0.0}; + + // pid cuts + int mPIDScheme{-1}; + float mMinPinTOF{0.0f}; // min pin cut for TOF. + bool mMuonExclusionTPC{false}; // flag to reject muon in TPC for low B + float mMinTOFbeta{-999}, mMaxTOFbeta{999}; + float mMinTPCNsigmaEl{-1e+10}, mMaxTPCNsigmaEl{+1e+10}; + float mMinTPCNsigmaMu{-1e+10}, mMaxTPCNsigmaMu{+1e+10}; + float mMinTPCNsigmaPi{-1e+10}, mMaxTPCNsigmaPi{+1e+10}; + float mMinTPCNsigmaKa{-1e+10}, mMaxTPCNsigmaKa{+1e+10}; + float mMinTPCNsigmaPr{-1e+10}, mMaxTPCNsigmaPr{+1e+10}; + + float mMinTOFNsigmaEl{-1e+10}, mMaxTOFNsigmaEl{+1e+10}; + float mMinTOFNsigmaMu{-1e+10}, mMaxTOFNsigmaMu{+1e+10}; + float mMinTOFNsigmaPi{-1e+10}, mMaxTOFNsigmaPi{+1e+10}; + float mMinTOFNsigmaKa{-1e+10}, mMaxTOFNsigmaKa{+1e+10}; + float mMinTOFNsigmaPr{-1e+10}, mMaxTOFNsigmaPr{+1e+10}; + + float mMinITSNsigmaEl{-1e+10}, mMaxITSNsigmaEl{+1e+10}; + float mMinITSNsigmaMu{-1e+10}, mMaxITSNsigmaMu{+1e+10}; + float mMinITSNsigmaPi{-1e+10}, mMaxITSNsigmaPi{+1e+10}; + float mMinITSNsigmaKa{-1e+10}, mMaxITSNsigmaKa{+1e+10}; + float mMinITSNsigmaPr{-1e+10}, mMaxITSNsigmaPr{+1e+10}; + float mMinP_ITSNsigmaKa{0.0}, mMaxP_ITSNsigmaKa{0.0}; + float mMinP_ITSNsigmaPr{0.0}, mMaxP_ITSNsigmaPr{0.0}; + + o2::analysis::MlResponseDielectronSingleTrack* mPIDMlResponse{nullptr}; + + ClassDef(DielectronCut, 1); +}; + +#endif // PWGEM_DILEPTON_CORE_DIELECTRONCUT_H_ diff --git a/PWGEM/Dilepton/Core/Dilepton.h b/PWGEM/Dilepton/Core/Dilepton.h new file mode 100644 index 00000000000..e9da89a3503 --- /dev/null +++ b/PWGEM/Dilepton/Core/Dilepton.h @@ -0,0 +1,1637 @@ +// 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. +// +// ======================== +// +// This code runs loop over leptons. +// Please write to: daiki.sekihata@cern.ch + +#ifndef PWGEM_DILEPTON_CORE_DILEPTON_H_ +#define PWGEM_DILEPTON_CORE_DILEPTON_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "TH1D.h" +#include "TString.h" +#include "Math/Vector4D.h" + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "CommonConstants/LHCConstants.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "MathUtils/Utils.h" + +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "Tools/ML/MlResponse.h" +#include "Common/CCDB/RCTSelectionFlags.h" + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Core/DielectronCut.h" +#include "PWGEM/Dilepton/Core/DimuonCut.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "PWGEM/Dilepton/Utils/EMTrack.h" +#include "PWGEM/Dilepton/Utils/EMFwdTrack.h" +#include "PWGEM/Dilepton/Utils/EventMixingHandler.h" +#include "PWGEM/Dilepton/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::dilepton::utils; +using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; +using namespace o2::aod::pwgem::dilepton::utils::pairutil; + +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; + +using MyCollisionsWithSWT = soa::Join; +using MyCollisionWithSWT = MyCollisionsWithSWT::iterator; + +using MyElectrons = soa::Join; +using MyElectron = MyElectrons::iterator; +using FilteredMyElectrons = soa::Filtered; +using FilteredMyElectron = FilteredMyElectrons::iterator; + +using MyMuons = soa::Join; +using MyMuon = MyMuons::iterator; +using FilteredMyMuons = soa::Filtered; +using FilteredMyMuon = FilteredMyMuons::iterator; + +using MyEMH_electron = o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, EMTrackWithCov>; +using MyEMH_muon = o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, EMFwdTrack>; + +template +struct Dilepton { + + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + Configurable cfgApplySPresolution{"cfgApplySPresolution", false, "flag to apply resolution correction for flow analysis"}; + Configurable spresoPath{"spresoPath", "Users/d/dsekihat/PWGEM/dilepton/Qvector/resolution/LHC23zzh/pass3/test", "Path to SP resolution file"}; + Configurable spresoHistName{"spresoHistName", "h1_R2_FT0M_BPos_BNeg", "histogram name of SP resolution file"}; + + Configurable cfgAnalysisType{"cfgAnalysisType", static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kQC), "kQC:0, kUPC:1, kFlowV2:2, kFlowV3:3, kPolarization:4, kVM:5, kHFll:6"}; + Configurable cfgEP2Estimator_for_Mix{"cfgEP2Estimator_for_Mix", 3, "FT0M:0, FT0A:1, FT0C:2, BTot:3, BPos:4, BNeg:5"}; + Configurable cfgQvecEstimator{"cfgQvecEstimator", 0, "FT0M:0, FT0A:1, FT0C:2, BTot:3, BPos:4, BNeg:5"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgOccupancyEstimator{"cfgOccupancyEstimator", 0, "FT0C:0, Track:1"}; + Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + Configurable cfgDoMix{"cfgDoMix", true, "flag for event mixing"}; + Configurable ndepth{"ndepth", 100, "depth for event mixing"}; + Configurable ndiff_bc_mix{"ndiff_bc_mix", 5, "difference in global BC required in mixed events"}; + ConfigurableAxis ConfVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis ConfCentBins{"ConfCentBins", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.f, 999.f}, "Mixing bins - centrality"}; + ConfigurableAxis ConfEPBins{"ConfEPBins", {16, -M_PI / 2, +M_PI / 2}, "Mixing bins - event plane angle"}; + ConfigurableAxis ConfOccupancyBins{"ConfOccupancyBins", {VARIABLE_WIDTH, -1, 1e+10}, "Mixing bins - occupancy"}; + Configurable cfg_swt_name{"cfg_swt_name", "fHighTrackMult", "desired software trigger name"}; // 1 trigger name per 1 task. fHighTrackMult, fHighFt0Mult + // Configurable cfgNtracksPV08Min{"cfgNtracksPV08Min", -1, "min. multNTracksPV"}; + // Configurable cfgNtracksPV08Max{"cfgNtracksPV08Max", static_cast(1e+9), "max. multNTracksPV"}; + Configurable cfgApplyWeightTTCA{"cfgApplyWeightTTCA", false, "flag to apply weighting by 1/N"}; + Configurable cfgDCAType{"cfgDCAType", 0, "type of DCA for output. 0:3D, 1:XY, 2:Z, else:3D"}; + Configurable cfgUseSignedDCA{"cfgUseSignedDCA", false, "flag to use signs in the DCA calculation"}; + + ConfigurableAxis ConfMllBins{"ConfMllBins", {VARIABLE_WIDTH, 0.00, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.30, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.40, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.50, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.60, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.70, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.80, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.90, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.00, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.10, 2.20, 2.30, 2.40, 2.50, 2.60, 2.70, 2.75, 2.80, 2.85, 2.90, 2.95, 3.00, 3.05, 3.10, 3.15, 3.20, 3.25, 3.30, 3.35, 3.40, 3.45, 3.50, 3.55, 3.60, 3.65, 3.70, 3.75, 3.80, 3.85, 3.90, 3.95, 4.00}, "mll bins for output histograms"}; + ConfigurableAxis ConfPtllBins{"ConfPtllBins", {VARIABLE_WIDTH, 0.00, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.50, 3.00, 3.50, 4.00, 4.50, 5.00, 6.00, 7.00, 8.00, 9.00, 10.00}, "pTll bins for output histograms"}; + ConfigurableAxis ConfDCAllBins{"ConfDCAllBins", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0}, "DCAll bins for output histograms"}; + + // ConfigurableAxis ConfMmumuBins{"ConfMmumuBins", {VARIABLE_WIDTH, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.30, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.40, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.50, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.60, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.70, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.80, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.90, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.00, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.10, 1.11,1.12,1.13,1.14,1.15,1.16,1.17,1.18,1.19, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.10, 2.20, 2.30, 2.40, 2.50, 2.60, 2.70, 2.75, 2.80, 2.85, 2.90, 2.95, 3.00, 3.05, 3.10, 3.15, 3.20, 3.25, 3.30, 3.35, 3.40, 3.45, 3.50, 3.55, 3.60, 3.65, 3.70, 3.75, 3.80, 3.85, 3.90, 3.95, 4.00, 4.10, 4.20, 4.30, 4.40, 4.50, 4.60, 4.70, 4.80, 4.90, 5.00, 5.10, 5.20, 5.30, 5.40, 5.50, 5.60, 5.70, 5.80, 5.90, 6.00, 6.10, 6.20, 6.30, 6.40, 6.50, 6.60, 6.70, 6.80, 6.90, 7.00, 7.10, 7.20, 7.30, 7.40, 7.50, 7.60, 7.70, 7.80, 7.90, 8.00, 8.10, 8.20, 8.30, 8.40, 8.50, 8.60, 8.70, 8.80, 8.90, 9.00, 9.10, 9.20, 9.30, 9.40, 9.50, 9.60, 9.70, 9.80, 9.90, 10.00, 10.10, 10.20, 10.30, 10.40, 10.50, 10.60, 10.70, 10.80, 10.90, 11.00, 11.50, 12.00}, "mmumu bins for output histograms"}; // for dimuon. one can copy bins here to hyperloop page. + + ConfigurableAxis ConfSPBins{"ConfSPBins", {200, -5, 5}, "SP bins for flow analysis"}; + + EMEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; + Configurable cfgZvtxMax{"cfgZvtxMax", +10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInTimeRangeStrict{"cfgRequireNoCollInTimeRangeStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoCollInITSROFStandard{"cfgRequireNoCollInITSROFStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInITSROFStrict{"cfgRequireNoCollInITSROFStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoHighMultCollInPrevRof{"cfgRequireNoHighMultCollInPrevRof", false, "require no HM collision in previous ITS ROF"}; + Configurable cfgRequireGoodITSLayer3{"cfgRequireGoodITSLayer3", false, "number of inactive chips on ITS layer 3 are below threshold "}; + Configurable cfgRequireGoodITSLayer0123{"cfgRequireGoodITSLayer0123", false, "number of inactive chips on ITS layers 0-3 are below threshold "}; + Configurable cfgRequireGoodITSLayersAll{"cfgRequireGoodITSLayersAll", false, "number of inactive chips on all ITS layers are below threshold "}; + // for RCT + Configurable cfgRequireGoodRCT{"cfgRequireGoodRCT", false, "require good detector flag in run condtion table"}; + Configurable cfgRCTLabel{"cfgRCTLabel", "CBT_hadronPID", "select 1 [CBT, CBT_hadron, CBT_muon_glo] see O2Physics/Common/CCDB/RCTSelectionFlags.h"}; + Configurable cfgCheckZDC{"cfgCheckZDC", false, "set ZDC flag for PbPb"}; + Configurable cfgTreatLimitedAcceptanceAsBad{"cfgTreatLimitedAcceptanceAsBad", false, "reject all events where the detectors relevant for the specified Runlist are flagged as LimitedAcceptance"}; + } eventcuts; + + DielectronCut fDielectronCut; + struct : ConfigurableGroup { + std::string prefix = "dielectroncut_group"; + Configurable cfg_min_mass{"cfg_min_mass", 0.0, "min mass"}; + Configurable cfg_max_mass{"cfg_max_mass", 1e+10, "max mass"}; + Configurable cfg_min_pair_pt{"cfg_min_pair_pt", 0.0, "min pair pT"}; + Configurable cfg_max_pair_pt{"cfg_max_pair_pt", 1e+10, "max pair pT"}; + Configurable cfg_min_pair_y{"cfg_min_pair_y", -0.8, "min pair rapidity"}; + Configurable cfg_max_pair_y{"cfg_max_pair_y", +0.8, "max pair rapidity"}; + Configurable cfg_min_pair_dca3d{"cfg_min_pair_dca3d", 0.0, "min pair dca3d in sigma"}; + Configurable cfg_max_pair_dca3d{"cfg_max_pair_dca3d", 1e+10, "max pair dca3d in sigma"}; + Configurable cfg_apply_phiv{"cfg_apply_phiv", true, "flag to apply phiv cut"}; + Configurable cfg_phiv_slope{"cfg_phiv_slope", 0.0185, "slope for m vs. phiv"}; + Configurable cfg_phiv_intercept{"cfg_phiv_intercept", -0.0280, "intercept for m vs. phiv"}; + Configurable cfg_min_phiv{"cfg_min_phiv", 0.0, "min phiv (constant)"}; + Configurable cfg_max_phiv{"cfg_max_phiv", 3.2, "max phiv (constant)"}; + Configurable cfg_apply_detadphi{"cfg_apply_detadphi", false, "flag to apply deta-dphi elliptic cut"}; + Configurable cfg_min_deta{"cfg_min_deta", 0.02, "min deta between 2 electrons (elliptic cut)"}; + Configurable cfg_min_dphi{"cfg_min_dphi", 0.2, "min dphi between 2 electrons (elliptic cut)"}; + Configurable cfg_min_opang{"cfg_min_opang", 0.0, "min opening angle"}; + Configurable cfg_max_opang{"cfg_max_opang", 6.4, "max opening angle"}; + Configurable cfg_require_diff_sides{"cfg_require_diff_sides", false, "flag to require 2 tracks are from different sides."}; + + Configurable cfg_apply_cuts_from_prefilter{"cfg_apply_cuts_from_prefilter", false, "flag to apply prefilter set when producing derived data"}; + Configurable cfg_prefilter_bits{"cfg_prefilter_bits", 0, "prefilter bits [kNone : 0, kElFromPC : 1, kElFromPi0_1 : 2, kElFromPi0_2 : 4, kElFromPi0_3 : 8] Please consider logical-OR among them."}; // see PairUtilities.h + + Configurable cfg_apply_cuts_from_prefilter_derived{"cfg_apply_cuts_from_prefilter_derived", false, "flag to apply pair cut same as prefilter set in derived data"}; + Configurable cfg_prefilter_bits_derived{"cfg_prefilter_bits_derived", 0, "prefilter bits [kNone : 0, kMee : 1, kPhiV : 2, kSplitOrMergedTrackLS : 4, kSplitOrMergedTrackULS : 8] Please consider logical-OR among them."}; // see PairUtilities.h + + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -0.8, "min eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", +0.8, "max eta for single track"}; + Configurable cfg_min_phi_track{"cfg_min_phi_track", 0.f, "min phi for single track"}; + Configurable cfg_max_phi_track{"cfg_max_phi_track", 6.3, "max phi for single track"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 100, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_chi2tof{"cfg_max_chi2tof", 1e+10, "max chi2 TOF"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 0.2, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 0.2, "max dca Z for single track in cm"}; + Configurable cfg_require_itsib_any{"cfg_require_itsib_any", false, "flag to require ITS ib any hits"}; + Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; + Configurable cfg_min_its_cluster_size{"cfg_min_its_cluster_size", 0.f, "min ITS cluster size"}; + Configurable cfg_max_its_cluster_size{"cfg_max_its_cluster_size", 16.f, "max ITS cluster size"}; + Configurable cfg_min_p_its_cluster_size{"cfg_min_p_its_cluster_size", 0.0, "min p to apply ITS cluster size cut"}; + Configurable cfg_max_p_its_cluster_size{"cfg_max_p_its_cluster_size", 0.0, "max p to apply ITS cluster size cut"}; + Configurable cfg_min_rel_diff_pin{"cfg_min_rel_diff_pin", -1e+10, "min rel. diff. between pin and ppv"}; + Configurable cfg_max_rel_diff_pin{"cfg_max_rel_diff_pin", +1e+10, "max rel. diff. between pin and ppv"}; + + Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DielectronCut::PIDSchemes::kTPChadrejORTOFreq), "pid scheme [kTOFreq : 0, kTPChadrej : 1, kTPChadrejORTOFreq : 2, kTPConly : 3, kTOFif : 4, kPIDML : 5, kTPChadrejORTOFreq_woTOFif : 6]"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + Configurable cfg_min_TPCNsigmaMu{"cfg_min_TPCNsigmaMu", -0.0, "min. TPC n sigma for muon exclusion"}; + Configurable cfg_max_TPCNsigmaMu{"cfg_max_TPCNsigmaMu", +0.0, "max. TPC n sigma for muon exclusion"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -1e+10, "min. TPC n sigma for pion exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +3.0, "max. TPC n sigma for pion exclusion"}; + Configurable cfg_min_TPCNsigmaKa{"cfg_min_TPCNsigmaKa", -3.0, "min. TPC n sigma for kaon exclusion"}; + Configurable cfg_max_TPCNsigmaKa{"cfg_max_TPCNsigmaKa", +3.0, "max. TPC n sigma for kaon exclusion"}; + Configurable cfg_min_TPCNsigmaPr{"cfg_min_TPCNsigmaPr", -3.0, "min. TPC n sigma for proton exclusion"}; + Configurable cfg_max_TPCNsigmaPr{"cfg_max_TPCNsigmaPr", +3.0, "max. TPC n sigma for proton exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; + Configurable cfg_max_pin_pirejTPC{"cfg_max_pin_pirejTPC", 1e+10, "max. pin for pion rejection in TPC"}; + Configurable cfg_min_ITSNsigmaKa{"cfg_min_ITSNsigmaKa", -1.0, "min. ITS n sigma for kaon exclusion"}; + Configurable cfg_max_ITSNsigmaKa{"cfg_max_ITSNsigmaKa", 1e+10, "max. ITS n sigma for kaon exclusion"}; + Configurable cfg_min_ITSNsigmaPr{"cfg_min_ITSNsigmaPr", -1.0, "min. ITS n sigma for proton exclusion"}; + Configurable cfg_max_ITSNsigmaPr{"cfg_max_ITSNsigmaPr", 1e+10, "max. ITS n sigma for proton exclusion"}; + Configurable cfg_min_p_ITSNsigmaKa{"cfg_min_p_ITSNsigmaKa", 0.0, "min p for kaon exclusion in ITS"}; + Configurable cfg_max_p_ITSNsigmaKa{"cfg_max_p_ITSNsigmaKa", 0.0, "max p for kaon exclusion in ITS"}; + Configurable cfg_min_p_ITSNsigmaPr{"cfg_min_p_ITSNsigmaPr", 0.0, "min p for proton exclusion in ITS"}; + Configurable cfg_max_p_ITSNsigmaPr{"cfg_max_p_ITSNsigmaPr", 0.0, "max p for proton exclusion in ITS"}; + Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; + + // configuration for PID ML + Configurable> onnxFileNames{"onnxFileNames", std::vector{"filename"}, "ONNX file names for each bin (if not from CCDB full path)"}; + Configurable> onnxPathsCCDB{"onnxPathsCCDB", std::vector{"path"}, "Paths of models on CCDB"}; + Configurable> binsMl{"binsMl", std::vector{-999999., 999999.}, "Bin limits for ML application"}; + Configurable> cutsMl{"cutsMl", std::vector{0.95}, "ML cuts per bin"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature"}, "Names of ML model input features"}; + Configurable nameBinningFeature{"nameBinningFeature", "pt", "Names of ML model binning feature"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + Configurable enableOptimizations{"enableOptimizations", false, "Enables the ONNX extended model-optimization: sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED)"}; + } dielectroncuts; + + DimuonCut fDimuonCut; + struct : ConfigurableGroup { + std::string prefix = "dimuoncut_group"; + Configurable cfg_min_mass{"cfg_min_mass", 0.0, "min mass"}; + Configurable cfg_max_mass{"cfg_max_mass", 1e+10, "max mass"}; + Configurable cfg_min_pair_pt{"cfg_min_pair_pt", 0.0, "min pair pt"}; + Configurable cfg_max_pair_pt{"cfg_max_pair_pt", 1e+10, "max pair pt"}; + Configurable cfg_min_pair_y{"cfg_min_pair_y", -4.0, "min pair rapidity"}; + Configurable cfg_max_pair_y{"cfg_max_pair_y", -2.5, "max pair rapidity"}; + Configurable cfg_min_pair_dcaxy{"cfg_min_pair_dcaxy", 0.0, "min pair dca3d in sigma"}; + Configurable cfg_max_pair_dcaxy{"cfg_max_pair_dcaxy", 1e+10, "max pair dca3d in sigma"}; + Configurable cfg_apply_detadphi{"cfg_apply_detadphi", false, "flag to apply deta-dphi elliptic cut"}; + Configurable cfg_min_deta{"cfg_min_deta", 0.02, "min deta between 2 muons (elliptic cut)"}; + Configurable cfg_min_dphi{"cfg_min_dphi", 0.02, "min dphi between 2 muons (elliptic cut)"}; + + Configurable cfg_track_type{"cfg_track_type", 3, "muon track type [0: MFT-MCH-MID, 3: MCH-MID]"}; + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -4.0, "min eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", -2.5, "max eta for single track"}; + Configurable cfg_min_phi_track{"cfg_min_phi_track", 0.f, "min phi for single track"}; + Configurable cfg_max_phi_track{"cfg_max_phi_track", 6.3, "max phi for single track"}; + Configurable cfg_min_ncluster_mft{"cfg_min_ncluster_mft", 5, "min ncluster MFT"}; + Configurable cfg_min_ncluster_mch{"cfg_min_ncluster_mch", 5, "min ncluster MCH"}; + Configurable cfg_max_chi2{"cfg_max_chi2", 1e+6, "max chi2"}; + Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 40, "max chi2 for MFT-MCH matching"}; + Configurable cfg_max_matching_chi2_mchmid{"cfg_max_matching_chi2_mchmid", 1e+10, "max chi2 for MCH-MID matching"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1e+10, "max dca XY for single track in cm"}; + Configurable cfg_min_rabs{"cfg_min_rabs", 17.6, "min Radius at the absorber end"}; + Configurable cfg_max_rabs{"cfg_max_rabs", 89.5, "max Radius at the absorber end"}; + Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; + } dimuoncuts; + + o2::aod::rctsel::RCTFlagsChecker rctChecker; + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + int mRunNumber; + float d_bz; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view event_cut_types[2] = {"before/", "after/"}; + static constexpr std::string_view event_pair_types[2] = {"same/", "mix/"}; + + std::vector cent_bin_edges; + std::vector zvtx_bin_edges; + std::vector ep_bin_edges; + std::vector occ_bin_edges; + int nmod = -1; // this is for flow analysis + int subdet2 = -1; // this is for flow analysis + int subdet3 = -1; // this is for flow analysis + float leptonM1 = 0.f; + float leptonM2 = 0.f; + + float beamM1 = o2::constants::physics::MassProton; // mass of beam + float beamM2 = o2::constants::physics::MassProton; // mass of beam + float beamE1 = 0.f; // beam energy + float beamE2 = 0.f; // beam energy + float beamP1 = 0.f; // beam momentum + float beamP2 = 0.f; // beam momentum + TH2D* h2sp_resolution = nullptr; + + void init(InitContext& /*context*/) + { + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + rctChecker.init(eventcuts.cfgRCTLabel.value, eventcuts.cfgCheckZDC.value, eventcuts.cfgTreatLimitedAcceptanceAsBad.value); + + if (ConfVtxBins.value[0] == VARIABLE_WIDTH) { + zvtx_bin_edges = std::vector(ConfVtxBins.value.begin(), ConfVtxBins.value.end()); + zvtx_bin_edges.erase(zvtx_bin_edges.begin()); + for (const auto& edge : zvtx_bin_edges) { + LOGF(info, "VARIABLE_WIDTH: zvtx_bin_edges = %f", edge); + } + } else { + int nbins = static_cast(ConfVtxBins.value[0]); + float xmin = static_cast(ConfVtxBins.value[1]); + float xmax = static_cast(ConfVtxBins.value[2]); + zvtx_bin_edges.resize(nbins + 1); + for (int i = 0; i < nbins + 1; i++) { + zvtx_bin_edges[i] = (xmax - xmin) / (nbins)*i + xmin; + LOGF(info, "FIXED_WIDTH: zvtx_bin_edges[%d] = %f", i, zvtx_bin_edges[i]); + } + } + + if (ConfCentBins.value[0] == VARIABLE_WIDTH) { + cent_bin_edges = std::vector(ConfCentBins.value.begin(), ConfCentBins.value.end()); + cent_bin_edges.erase(cent_bin_edges.begin()); + for (const auto& edge : cent_bin_edges) { + LOGF(info, "VARIABLE_WIDTH: cent_bin_edges = %f", edge); + } + } else { + int nbins = static_cast(ConfCentBins.value[0]); + float xmin = static_cast(ConfCentBins.value[1]); + float xmax = static_cast(ConfCentBins.value[2]); + cent_bin_edges.resize(nbins + 1); + for (int i = 0; i < nbins + 1; i++) { + cent_bin_edges[i] = (xmax - xmin) / (nbins)*i + xmin; + LOGF(info, "FIXED_WIDTH: cent_bin_edges[%d] = %f", i, cent_bin_edges[i]); + } + } + + if (ConfEPBins.value[0] == VARIABLE_WIDTH) { + ep_bin_edges = std::vector(ConfEPBins.value.begin(), ConfEPBins.value.end()); + ep_bin_edges.erase(ep_bin_edges.begin()); + for (const auto& edge : ep_bin_edges) { + LOGF(info, "VARIABLE_WIDTH: ep_bin_edges = %f", edge); + } + } else { + int nbins = static_cast(ConfEPBins.value[0]); + float xmin = static_cast(ConfEPBins.value[1]); + float xmax = static_cast(ConfEPBins.value[2]); + ep_bin_edges.resize(nbins + 1); + for (int i = 0; i < nbins + 1; i++) { + ep_bin_edges[i] = (xmax - xmin) / (nbins)*i + xmin; + LOGF(info, "FIXED_WIDTH: ep_bin_edges[%d] = %f", i, ep_bin_edges[i]); + } + } + + LOGF(info, "cfgOccupancyEstimator = %d", cfgOccupancyEstimator.value); + if (ConfOccupancyBins.value[0] == VARIABLE_WIDTH) { + occ_bin_edges = std::vector(ConfOccupancyBins.value.begin(), ConfOccupancyBins.value.end()); + occ_bin_edges.erase(occ_bin_edges.begin()); + for (const auto& edge : occ_bin_edges) { + LOGF(info, "VARIABLE_WIDTH: occ_bin_edges = %f", edge); + } + } else { + int nbins = static_cast(ConfOccupancyBins.value[0]); + float xmin = static_cast(ConfOccupancyBins.value[1]); + float xmax = static_cast(ConfOccupancyBins.value[2]); + occ_bin_edges.resize(nbins + 1); + for (int i = 0; i < nbins + 1; i++) { + occ_bin_edges[i] = (xmax - xmin) / (nbins)*i + xmin; + LOGF(info, "FIXED_WIDTH: occ_bin_edges[%d] = %f", i, occ_bin_edges[i]); + } + } + + emh_pos = new TEMH(ndepth); + emh_neg = new TEMH(ndepth); + + DefineEMEventCut(); + addhistograms(); + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + DefineDielectronCut(); + leptonM1 = o2::constants::physics::MassElectron; + leptonM2 = o2::constants::physics::MassElectron; + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + DefineDimuonCut(); + leptonM1 = o2::constants::physics::MassMuon; + leptonM2 = o2::constants::physics::MassMuon; + } + + fRegistry.add("Pair/mix/hDiffBC", "diff. global BC in mixed event;|BC_{current} - BC_{mixed}|", kTH1D, {{10001, -0.5, 10000.5}}, true); + + if (doprocessNorm) { + fRegistry.addClone("Event/before/hCollisionCounter", "Event/norm/hCollisionCounter"); + } + if (doprocessTriggerAnalysis) { + fRegistry.add("Event/hNInspectedTVX", "N inspected TVX;run number;N_{TVX}", kTProfile, {{80000, 520000.5, 600000.5}}, true); + } + if (doprocessBC) { + auto hTVXCounter = fRegistry.add("BC/hTVXCounter", "TVX counter", kTH1D, {{6, -0.5f, 5.5f}}); + hTVXCounter->GetXaxis()->SetBinLabel(1, "TVX"); + hTVXCounter->GetXaxis()->SetBinLabel(2, "TVX && NoTFB"); + hTVXCounter->GetXaxis()->SetBinLabel(3, "TVX && NoITSROFB"); + hTVXCounter->GetXaxis()->SetBinLabel(4, "TVX && GoodRCT"); + hTVXCounter->GetXaxis()->SetBinLabel(5, "TVX && NoTFB && NoITSROFB"); + hTVXCounter->GetXaxis()->SetBinLabel(6, "TVX && NoTFB && NoITSROFB && GoodRCT"); + } + } + + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (std::fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + o2::base::Propagator::initFieldFromGRP(&grpmag); + mRunNumber = collision.runNumber(); + return; + } + + auto run3grp_timestamp = collision.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = collision.runNumber(); + + auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", collision.timestamp()); + int beamZ1 = grplhcif->getBeamZ(o2::constants::lhc::BeamC); + int beamZ2 = grplhcif->getBeamZ(o2::constants::lhc::BeamA); + int beamA1 = grplhcif->getBeamA(o2::constants::lhc::BeamC); + int beamA2 = grplhcif->getBeamA(o2::constants::lhc::BeamA); + beamE1 = grplhcif->getBeamEnergyPerNucleonInGeV(o2::constants::lhc::BeamC); + beamE2 = grplhcif->getBeamEnergyPerNucleonInGeV(o2::constants::lhc::BeamA); + beamM1 = o2::constants::physics::MassProton * beamA1; + beamM2 = o2::constants::physics::MassProton * beamA2; + beamP1 = std::sqrt(std::pow(beamE1, 2) - std::pow(beamM1, 2)); + beamP2 = std::sqrt(std::pow(beamE2, 2) - std::pow(beamM2, 2)); + LOGF(info, "beamZ1 = %d, beamZ2 = %d, beamA1 = %d, beamA2 = %d, beamE1 = %f (GeV), beamE2 = %f (GeV), beamM1 = %f (GeV), beamM2 = %f (GeV), beamP1 = %f (GeV), beamP2 = %f (GeV)", beamZ1, beamZ2, beamA1, beamA2, beamE1, beamE2, beamM1, beamM2, beamP1, beamP2); + + if constexpr (isTriggerAnalysis) { + LOGF(info, "Trigger analysis is enabled. Desired trigger name = %s", cfg_swt_name.value); + LOGF(info, "total inspected TVX events = %d in run number %d", collision.nInspectedTVX(), collision.runNumber()); + fRegistry.fill(HIST("Event/hNInspectedTVX"), collision.runNumber(), collision.nInspectedTVX()); + } + + if (cfgApplySPresolution) { + auto list = ccdb->getForTimeStamp(spresoPath, collision.timestamp()); + h2sp_resolution = reinterpret_cast(list->FindObject(spresoHistName.value.data())); + LOGF(info, "h2sp_resolution.GetBinContent(40, 1) = %f", h2sp_resolution->GetBinContent(40, 1)); + } + } + + ~Dilepton() + { + delete emh_pos; + emh_pos = 0x0; + delete emh_neg; + emh_neg = 0x0; + + used_trackIds.clear(); + used_trackIds.shrink_to_fit(); + + delete h2sp_resolution; + } + + void addhistograms() + { + const std::string qvec_det_names[6] = {"FT0M", "FT0A", "FT0C", "BTot", "BPos", "BNeg"}; + + std::string mass_axis_title = "m_{ll} (GeV/c^{2})"; + std::string pair_pt_axis_title = "p_{T,ll} (GeV/c)"; + std::string pair_dca_axis_title = "DCA_{ll} (#sigma)"; + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + mass_axis_title = "m_{ee} (GeV/c^{2})"; + pair_pt_axis_title = "p_{T,ee} (GeV/c)"; + pair_dca_axis_title = "DCA_{ee}^{3D} (#sigma)"; + if (cfgDCAType == 1) { + pair_dca_axis_title = "DCA_{ee}^{XY} (#sigma)"; + } else if (cfgDCAType == 2) { + pair_dca_axis_title = "DCA_{ee}^{Z} (#sigma)"; + } + if (cfgUseSignedDCA) { + pair_dca_axis_title = "Signed " + pair_dca_axis_title; + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + mass_axis_title = "m_{#mu#mu} (GeV/c^{2})"; + pair_pt_axis_title = "p_{T,#mu#mu} (GeV/c)"; + pair_dca_axis_title = "DCA_{#mu#mu}^{XY} (#sigma)"; + } + + // pair info + const AxisSpec axis_mass{ConfMllBins, mass_axis_title}; + const AxisSpec axis_pt{ConfPtllBins, pair_pt_axis_title}; + const AxisSpec axis_dca{ConfDCAllBins, pair_dca_axis_title}; + + if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kQC)) { + fRegistry.add("Pair/same/uls/hs", "dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_dca}, true); + fRegistry.add("Pair/same/uls/hDeltaEtaDeltaPhi", "#Delta#eta-#Delta#varphi between 2 tracks;#Delta#varphi (rad.);#Delta#eta;", kTH2D, {{180, -M_PI, M_PI}, {400, -2, +2}}, true); + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + fRegistry.add("Pair/same/uls/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2D, {{90, 0, M_PI}, {100, 0.0f, 1.0f}}, true); // phiv is only for dielectron + fRegistry.add("Pair/same/uls/hMvsOpAng", "m_{ee} vs. angle between 2 tracks;#omega (rad.);m_{ee} (GeV/c^{2})", kTH2D, {{90, 0, M_PI}, {100, 0.0f, 1.0f}}, true); + fRegistry.add("Pair/same/uls/hDCA1vsDCA2", "DCA of leg1 vs. DCA of leg2;DCA1(#sigma);DCA2 (#sigma)", kTH2D, {{100, 0, 10.0}, {100, 0, 10}}, true); + } + fRegistry.addClone("Pair/same/uls/", "Pair/same/lspp/"); + fRegistry.addClone("Pair/same/uls/", "Pair/same/lsmm/"); + fRegistry.addClone("Pair/same/", "Pair/mix/"); + } else if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kUPC)) { + const AxisSpec axis_aco{10, 0, 1.f, "#alpha = 1 - #frac{|#varphi_{l^{+}} - #varphi_{l^{-}}|}{#pi}"}; + const AxisSpec axis_asym_pt{10, 0, 1.f, "A = #frac{|p_{T,l^{+}} - p_{T,l^{-}}|}{|p_{T,l^{+}} + p_{T,l^{-}}|}"}; + const AxisSpec axis_dphi_e_ee{18, 0, M_PI, "#Delta#varphi = #varphi_{l} - #varphi_{ll} (rad.)"}; + const AxisSpec axis_cos_theta_cs{10, 0.f, 1.f, "|cos(#theta_{CS})|"}; + fRegistry.add("Pair/same/uls/hs", "dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_dca, axis_aco, axis_asym_pt, axis_dphi_e_ee, axis_cos_theta_cs}, true); + fRegistry.addClone("Pair/same/uls/", "Pair/same/lspp/"); + fRegistry.addClone("Pair/same/uls/", "Pair/same/lsmm/"); + fRegistry.addClone("Pair/same/", "Pair/mix/"); + } else if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kFlowV2) || cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kFlowV3)) { + if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kFlowV2)) { + nmod = 2; + } else if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kFlowV3)) { + nmod = 3; + } + + const AxisSpec axis_sp{ConfSPBins, Form("#vec{u}_{%d,ll} #upoint #vec{Q}_{%d}^{%s}", nmod, nmod, qvec_det_names[cfgQvecEstimator].data())}; + + fRegistry.add("Pair/same/uls/hs", "dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_dca, axis_sp}, true); + fRegistry.addClone("Pair/same/uls/", "Pair/same/lspp/"); + fRegistry.addClone("Pair/same/uls/", "Pair/same/lsmm/"); + + fRegistry.add("Pair/mix/uls/hs", "dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_dca}, true); + fRegistry.addClone("Pair/mix/uls/", "Pair/mix/lspp/"); + fRegistry.addClone("Pair/mix/uls/", "Pair/mix/lsmm/"); + + } else if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kPolarization)) { + const AxisSpec axis_cos_theta_cs{10, 0.f, 1.f, "|cos(#theta_{CS})|"}; + const AxisSpec axis_phi_cs{18, 0.f, M_PI, "|#varphi_{CS}| (rad.)"}; + fRegistry.add("Pair/same/uls/hs", "dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_dca, axis_cos_theta_cs, axis_phi_cs}, true); + fRegistry.addClone("Pair/same/uls/", "Pair/same/lspp/"); + fRegistry.addClone("Pair/same/uls/", "Pair/same/lsmm/"); + fRegistry.addClone("Pair/same/", "Pair/mix/"); + } else if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kVM)) { + std::string pair_y_axis_title = "y_{ll}"; + int nbin_y = 20; + float min_y = -1.0; + float max_y = +1.0; + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + pair_y_axis_title = "y_{ee}"; + nbin_y = 20; + min_y = -1.0; + max_y = +1.0; + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + pair_y_axis_title = "y_{#mu#mu}"; + nbin_y = 25; + min_y = -4.5; + max_y = -2.0; + } + const AxisSpec axis_y{nbin_y, min_y, max_y, pair_y_axis_title}; + fRegistry.add("Pair/same/uls/hs", "dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_dca, axis_y}, true); + fRegistry.addClone("Pair/same/uls/", "Pair/same/lspp/"); + fRegistry.addClone("Pair/same/uls/", "Pair/same/lsmm/"); + fRegistry.addClone("Pair/same/", "Pair/mix/"); + } else if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kHFll)) { + const AxisSpec axis_dphi_ee{36, -M_PI / 2., 3. / 2. * M_PI, "#Delta#varphi = #varphi_{l1} - #varphi_{l2} (rad.)"}; // for kHFll + const AxisSpec axis_deta_ee{40, -2., 2., "#Delta#eta = #eta_{l1} - #eta_{l2}"}; + fRegistry.add("Pair/same/uls/hs", "dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_dca, axis_dphi_ee, axis_deta_ee}, true); + fRegistry.addClone("Pair/same/uls/", "Pair/same/lspp/"); + fRegistry.addClone("Pair/same/uls/", "Pair/same/lsmm/"); + fRegistry.addClone("Pair/same/", "Pair/mix/"); + } else { // same as kQC to avoid seg. fault + fRegistry.add("Pair/same/uls/hs", "dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_dca}, true); + fRegistry.addClone("Pair/same/uls/", "Pair/same/lspp/"); + fRegistry.addClone("Pair/same/uls/", "Pair/same/lsmm/"); + fRegistry.addClone("Pair/same/", "Pair/mix/"); + } + + // event info + if (nmod == 2) { + o2::aod::pwgem::dilepton::utils::eventhistogram::addEventHistograms<2>(&fRegistry); + } else if (nmod == 3) { + o2::aod::pwgem::dilepton::utils::eventhistogram::addEventHistograms<3>(&fRegistry); + } else { + o2::aod::pwgem::dilepton::utils::eventhistogram::addEventHistograms<-1>(&fRegistry); + } + fRegistry.add("Event/before/hEP2_CentFT0C_forMix", Form("2nd harmonics event plane for mix;centrality FT0C (%%);#Psi_{2}^{%s} (rad.)", qvec_det_names[cfgEP2Estimator_for_Mix].data()), kTH2F, {{110, 0, 110}, {180, -M_PI_2, +M_PI_2}}, false); + fRegistry.add("Event/after/hEP2_CentFT0C_forMix", Form("2nd harmonics event plane for mix;centrality FT0C (%%);#Psi_{2}^{%s} (rad.)", qvec_det_names[cfgEP2Estimator_for_Mix].data()), kTH2F, {{110, 0, 110}, {180, -M_PI_2, +M_PI_2}}, false); + } + + void DefineEMEventCut() + { + fEMEventCut = EMEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(eventcuts.cfgZvtxMin, eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireNoCollInTimeRangeStandard(eventcuts.cfgRequireNoCollInTimeRangeStandard); + fEMEventCut.SetRequireNoCollInTimeRangeStrict(eventcuts.cfgRequireNoCollInTimeRangeStrict); + fEMEventCut.SetRequireNoCollInITSROFStandard(eventcuts.cfgRequireNoCollInITSROFStandard); + fEMEventCut.SetRequireNoCollInITSROFStrict(eventcuts.cfgRequireNoCollInITSROFStrict); + fEMEventCut.SetRequireNoHighMultCollInPrevRof(eventcuts.cfgRequireNoHighMultCollInPrevRof); + fEMEventCut.SetRequireGoodITSLayer3(eventcuts.cfgRequireGoodITSLayer3); + fEMEventCut.SetRequireGoodITSLayer0123(eventcuts.cfgRequireGoodITSLayer0123); + fEMEventCut.SetRequireGoodITSLayersAll(eventcuts.cfgRequireGoodITSLayersAll); + } + + o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; + void DefineDielectronCut() + { + fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); + + // for pair + fDielectronCut.SetMeeRange(dielectroncuts.cfg_min_mass, dielectroncuts.cfg_max_mass); + fDielectronCut.SetPairPtRange(dielectroncuts.cfg_min_pair_pt, dielectroncuts.cfg_max_pair_pt); + fDielectronCut.SetPairYRange(dielectroncuts.cfg_min_pair_y, dielectroncuts.cfg_max_pair_y); + fDielectronCut.SetPairDCARange(dielectroncuts.cfg_min_pair_dca3d, dielectroncuts.cfg_max_pair_dca3d); // in sigma + fDielectronCut.SetMaxMeePhiVDep([&](float phiv) { return dielectroncuts.cfg_phiv_intercept + phiv * dielectroncuts.cfg_phiv_slope; }, dielectroncuts.cfg_min_phiv, dielectroncuts.cfg_max_phiv); + fDielectronCut.ApplyPhiV(dielectroncuts.cfg_apply_phiv); + fDielectronCut.SetMindEtadPhi(dielectroncuts.cfg_apply_detadphi, dielectroncuts.cfg_min_deta, dielectroncuts.cfg_min_dphi); + fDielectronCut.SetPairOpAng(dielectroncuts.cfg_min_opang, dielectroncuts.cfg_max_opang); + fDielectronCut.SetRequireDifferentSides(dielectroncuts.cfg_require_diff_sides); + + // for track + fDielectronCut.SetTrackPtRange(dielectroncuts.cfg_min_pt_track, dielectroncuts.cfg_max_pt_track); + fDielectronCut.SetTrackEtaRange(dielectroncuts.cfg_min_eta_track, dielectroncuts.cfg_max_eta_track); + fDielectronCut.SetTrackPhiRange(dielectroncuts.cfg_min_phi_track, dielectroncuts.cfg_max_phi_track); + fDielectronCut.SetMinNClustersTPC(dielectroncuts.cfg_min_ncluster_tpc); + fDielectronCut.SetMinNCrossedRowsTPC(dielectroncuts.cfg_min_ncrossedrows); + fDielectronCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fDielectronCut.SetMaxFracSharedClustersTPC(dielectroncuts.cfg_max_frac_shared_clusters_tpc); + fDielectronCut.SetChi2PerClusterTPC(0.0, dielectroncuts.cfg_max_chi2tpc); + fDielectronCut.SetChi2PerClusterITS(0.0, dielectroncuts.cfg_max_chi2its); + fDielectronCut.SetNClustersITS(dielectroncuts.cfg_min_ncluster_its, 7); + fDielectronCut.SetMeanClusterSizeITS(dielectroncuts.cfg_min_its_cluster_size, dielectroncuts.cfg_max_its_cluster_size, dielectroncuts.cfg_min_p_its_cluster_size, dielectroncuts.cfg_max_p_its_cluster_size); + fDielectronCut.SetTrackMaxDcaXY(dielectroncuts.cfg_max_dcaxy); + fDielectronCut.SetTrackMaxDcaZ(dielectroncuts.cfg_max_dcaz); + fDielectronCut.RequireITSibAny(dielectroncuts.cfg_require_itsib_any); + fDielectronCut.RequireITSib1st(dielectroncuts.cfg_require_itsib_1st); + fDielectronCut.SetChi2TOF(0, dielectroncuts.cfg_max_chi2tof); + fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); + + // for eID + fDielectronCut.SetPIDScheme(dielectroncuts.cfg_pid_scheme); + fDielectronCut.SetTPCNsigmaElRange(dielectroncuts.cfg_min_TPCNsigmaEl, dielectroncuts.cfg_max_TPCNsigmaEl); + fDielectronCut.SetTPCNsigmaMuRange(dielectroncuts.cfg_min_TPCNsigmaMu, dielectroncuts.cfg_max_TPCNsigmaMu); + fDielectronCut.SetTPCNsigmaPiRange(dielectroncuts.cfg_min_TPCNsigmaPi, dielectroncuts.cfg_max_TPCNsigmaPi); + fDielectronCut.SetTPCNsigmaKaRange(dielectroncuts.cfg_min_TPCNsigmaKa, dielectroncuts.cfg_max_TPCNsigmaKa); + fDielectronCut.SetTPCNsigmaPrRange(dielectroncuts.cfg_min_TPCNsigmaPr, dielectroncuts.cfg_max_TPCNsigmaPr); + fDielectronCut.SetTOFNsigmaElRange(dielectroncuts.cfg_min_TOFNsigmaEl, dielectroncuts.cfg_max_TOFNsigmaEl); + fDielectronCut.SetMaxPinForPionRejectionTPC(dielectroncuts.cfg_max_pin_pirejTPC); + fDielectronCut.SetITSNsigmaKaRange(dielectroncuts.cfg_min_ITSNsigmaKa, dielectroncuts.cfg_max_ITSNsigmaKa); + fDielectronCut.SetITSNsigmaPrRange(dielectroncuts.cfg_min_ITSNsigmaPr, dielectroncuts.cfg_max_ITSNsigmaPr); + fDielectronCut.SetPRangeForITSNsigmaKa(dielectroncuts.cfg_min_p_ITSNsigmaKa, dielectroncuts.cfg_max_p_ITSNsigmaKa); + fDielectronCut.SetPRangeForITSNsigmaPr(dielectroncuts.cfg_min_p_ITSNsigmaPr, dielectroncuts.cfg_max_p_ITSNsigmaPr); + + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { // please call this at the end of DefineDileptonCut + static constexpr int nClassesMl = 2; + const std::vector cutDirMl = {o2::cuts_ml::CutSmaller, o2::cuts_ml::CutNot}; + const std::vector labelsClasses = {"Signal", "Background"}; + const uint32_t nBinsMl = dielectroncuts.binsMl.value.size() - 1; + const std::vector labelsBins(nBinsMl, "bin"); + double cutsMlArr[nBinsMl][nClassesMl]; + for (uint32_t i = 0; i < nBinsMl; i++) { + cutsMlArr[i][0] = dielectroncuts.cutsMl.value[i]; + cutsMlArr[i][1] = 0.; + } + o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; + + mlResponseSingleTrack.configure(dielectroncuts.binsMl.value, cutsMl, cutDirMl, nClassesMl); + if (dielectroncuts.loadModelsFromCCDB) { + ccdbApi.init(ccdburl); + mlResponseSingleTrack.setModelPathsCCDB(dielectroncuts.onnxFileNames.value, ccdbApi, dielectroncuts.onnxPathsCCDB.value, dielectroncuts.timestampCCDB.value); + } else { + mlResponseSingleTrack.setModelPathsLocal(dielectroncuts.onnxFileNames.value); + } + mlResponseSingleTrack.cacheInputFeaturesIndices(dielectroncuts.namesInputFeatures); + mlResponseSingleTrack.cacheBinningIndex(dielectroncuts.nameBinningFeature); + mlResponseSingleTrack.init(dielectroncuts.enableOptimizations.value); + + fDielectronCut.SetPIDMlResponse(&mlResponseSingleTrack); + } // end of PID ML + } + + void DefineDimuonCut() + { + fDimuonCut = DimuonCut("fDimuonCut", "fDimuonCut"); + + // for pair + fDimuonCut.SetMassRange(dimuoncuts.cfg_min_mass, dimuoncuts.cfg_max_mass); + fDimuonCut.SetPairPtRange(dimuoncuts.cfg_min_pair_pt, dimuoncuts.cfg_max_pair_pt); + fDimuonCut.SetPairYRange(dimuoncuts.cfg_min_pair_y, dimuoncuts.cfg_max_pair_y); + fDimuonCut.SetPairDCAxyRange(dimuoncuts.cfg_min_pair_dcaxy, dimuoncuts.cfg_max_pair_dcaxy); + fDimuonCut.SetMindEtadPhi(dimuoncuts.cfg_apply_detadphi, dimuoncuts.cfg_min_deta, dimuoncuts.cfg_min_dphi); + + // for track + fDimuonCut.SetTrackType(dimuoncuts.cfg_track_type); + fDimuonCut.SetTrackPtRange(dimuoncuts.cfg_min_pt_track, dimuoncuts.cfg_max_pt_track); + fDimuonCut.SetTrackEtaRange(dimuoncuts.cfg_min_eta_track, dimuoncuts.cfg_max_eta_track); + fDimuonCut.SetTrackPhiRange(dimuoncuts.cfg_min_phi_track, dimuoncuts.cfg_max_phi_track); + fDimuonCut.SetNClustersMFT(dimuoncuts.cfg_min_ncluster_mft, 10); + fDimuonCut.SetNClustersMCHMID(dimuoncuts.cfg_min_ncluster_mch, 16); + fDimuonCut.SetChi2(0.f, dimuoncuts.cfg_max_chi2); + fDimuonCut.SetMatchingChi2MCHMFT(0.f, dimuoncuts.cfg_max_matching_chi2_mftmch); + fDimuonCut.SetMatchingChi2MCHMID(0.f, dimuoncuts.cfg_max_matching_chi2_mchmid); + fDimuonCut.SetDCAxy(0.f, dimuoncuts.cfg_max_dcaxy); + fDimuonCut.SetRabs(dimuoncuts.cfg_min_rabs, dimuoncuts.cfg_max_rabs); + fDimuonCut.SetMaxPDCARabsDep([&](float rabs) { return (rabs < 26.5 ? 594.f : 324.f); }); + } + + template + bool isGoodQvector(TQvectors const& qvectors) + { + bool is_good = true; + for (const auto& qn : qvectors[nmod]) { + if (std::fabs(qn[0]) > 20.f || std::fabs(qn[1]) > 20.f) { + is_good = false; + break; + } + } + return is_good; + } + + float getSPresolution(const float centrality, const int occupancy) + { + if (h2sp_resolution == nullptr) { + return 1.f; + } else { + int binId_cen = h2sp_resolution->GetXaxis()->FindBin(centrality); + int binId_occ = h2sp_resolution->GetYaxis()->FindBin(occupancy); + + if (centrality < h2sp_resolution->GetXaxis()->GetXmin()) { + binId_cen = 1; + } + if (h2sp_resolution->GetXaxis()->GetXmax() < centrality) { + binId_cen = h2sp_resolution->GetXaxis()->GetNbins(); + } + + if (occupancy < h2sp_resolution->GetYaxis()->GetXmin()) { + binId_occ = 1; + } + if (h2sp_resolution->GetYaxis()->GetXmax() < occupancy) { + binId_occ = h2sp_resolution->GetYaxis()->GetNbins(); + } + return h2sp_resolution->GetBinContent(binId_cen, binId_occ); + } + } + + template + bool fillPairInfo(TCollision const& collision, TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TAllTracks const& tracks) + { + if constexpr (ev_id == 1) { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + // bool is_found1 = std::find(t2.ambiguousElectronsIds.begin(), t2.ambiguousElectronsIds.end(), t1.globalIndex()) != t2.ambiguousElectronsIds.end(); //this does not work. + // bool is_found2 = std::find(t1.ambiguousElectronsIds.begin(), t1.ambiguousElectronsIds.end(), t2.globalIndex()) != t1.ambiguousElectronsIds.end(); //this does not work. + auto v1ambIds = t1.ambiguousElectronsIds(); + auto v2ambIds = t2.ambiguousElectronsIds(); + + if ((t1.dfId() == t2.dfId()) && std::find(v2ambIds.begin(), v2ambIds.end(), t1.globalIndex()) != v2ambIds.end() && std::find(v1ambIds.begin(), v1ambIds.end(), t2.globalIndex()) != v1ambIds.end()) { + // LOGF(info, "event id = %d: same track is found. t1.globalIndex() = %d, t1.sign() = %d, t1.pt() = %f, t1.eta() = %f, t1.phi() = %f, t2.globalIndex() = %d, t2.sign() = %d, t2.pt() = %f, t2.eta() = %f, t2.phi() = %f, deta = %f, dphi = %f (rad.)", ev_id, t1.globalIndex(), t1.sign(), t1.pt(), t1.eta(), t1.phi(), t2.globalIndex(), t2.sign(), t2.pt(), t2.eta(), t2.phi(), t1.eta() - t2.eta(), t1.phi() - t2.phi()); + return false; // this is protection against pairing 2 identical tracks. This happens, when TTCA is used. TTCA can assign a track to several possible collisions. + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + // bool is_found1 = std::find(t2.ambiguousMuonsIds.begin(), t2.ambiguousMuonsIds.end(), t1.globalIndex()) != t2.ambiguousMuonsIds.end(); //this does not work. + // bool is_found2 = std::find(t1.ambiguousMuonsIds.begin(), t1.ambiguousMuonsIds.end(), t2.globalIndex()) != t1.ambiguousMuonsIds.end(); //this does not work. + auto v1ambIds = t1.ambiguousMuonsIds(); + auto v2ambIds = t2.ambiguousMuonsIds(); + + if ((t1.dfId() == t2.dfId()) && std::find(v2ambIds.begin(), v2ambIds.end(), t1.globalIndex()) != v2ambIds.end() && std::find(v1ambIds.begin(), v1ambIds.end(), t2.globalIndex()) != v1ambIds.end()) { + // LOGF(info, "event id = %d: same track is found. t1.globalIndex() = %d, t1.sign() = %d, t1.pt() = %f, t1.eta() = %f, t1.phi() = %f, t2.globalIndex() = %d, t2.sign() = %d, t2.pt() = %f, t2.eta() = %f, t2.phi() = %f, deta = %f, dphi = %f (rad.)", ev_id, t1.globalIndex(), t1.sign(), t1.pt(), t1.eta(), t1.phi(), t2.globalIndex(), t2.sign(), t2.pt(), t2.eta(), t2.phi(), t1.eta() - t2.eta(), t1.phi() - t2.phi()); + return false; // this is protection against pairing 2 identical tracks. This happens, when TTCA is used. TTCA can assign a track to several possible collisions. + } + } + } + + if constexpr (ev_id == 0) { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { + if (!cut.template IsSelectedTrack(t1, collision) || !cut.template IsSelectedTrack(t2, collision)) { + return false; + } + } else { // cut-based + if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { + return false; + } + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { + return false; + } + + if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t1, cut, tracks)) { + return false; + } + if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t2, cut, tracks)) { + return false; + } + } + } + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (!cut.IsSelectedPair(t1, t2, d_bz)) { + return false; + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (!cut.IsSelectedPair(t1, t2)) { + return false; + } + } + + float weight = 1.f; + if (cfgApplyWeightTTCA) { + weight = map_weight[std::make_pair(t1.globalIndex(), t2.globalIndex())]; + } + if (ev_id == 1) { + weight = 1.f; + } + + // LOGF(info, "ev_id = %d, t1.sign() = %d, t2.sign() = %d, map_weight[std::make_pair(%d, %d)] = %f", ev_id, t1.sign(), t2.sign(), t1.globalIndex(), t2.globalIndex(), weight); + + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), leptonM1); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), leptonM2); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + + float pair_dca = 999.f; + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (cfgUseSignedDCA) { + pair_dca = pairDCASignQuadSum(dca3DinSigma(t1), dca3DinSigma(t2), t1.sign(), t2.sign()); + } else { + pair_dca = pairDCAQuadSum(dca3DinSigma(t1), dca3DinSigma(t2)); + } + if (cfgDCAType == 1) { + if (cfgUseSignedDCA) { + pair_dca = pairDCASignQuadSum(dcaXYinSigma(t1), dcaXYinSigma(t2), t1.sign(), t2.sign()); + } else { + pair_dca = pairDCAQuadSum(dcaXYinSigma(t1), dcaXYinSigma(t2)); + } + } else if (cfgDCAType == 2) { + if (cfgUseSignedDCA) { + pair_dca = pairDCASignQuadSum(dcaZinSigma(t1), dcaZinSigma(t2), t1.sign(), t2.sign()); + } else { + pair_dca = pairDCAQuadSum(dcaZinSigma(t1), dcaZinSigma(t2)); + } + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + pair_dca = pairDCAQuadSum(fwdDcaXYinSigma(t1), fwdDcaXYinSigma(t2)); + } + + if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kQC)) { + float deta = t1.sign() * v1.Pt() > t2.sign() * v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi = t1.sign() * v1.Pt() > t2.sign() * v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + o2::math_utils::bringToPMPi(dphi); + + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), d_bz); + float opAng = o2::aod::pwgem::dilepton::utils::pairutil::getOpeningAngle(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz()); + + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), pair_dca, weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hDeltaEtaDeltaPhi"), dphi, deta, weight); + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hMvsPhiV"), phiv, v12.M(), weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hMvsOpAng"), opAng, v12.M(), weight); + } + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hs"), v12.M(), v12.Pt(), pair_dca, weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hDeltaEtaDeltaPhi"), dphi, deta, weight); + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hMvsPhiV"), phiv, v12.M(), weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hMvsOpAng"), opAng, v12.M(), weight); + } + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hDeltaEtaDeltaPhi"), dphi, deta, weight); + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hMvsPhiV"), phiv, v12.M(), weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hMvsOpAng"), opAng, v12.M(), weight); + } + } + } else if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kUPC)) { + float dphi = v1.Phi() - v2.Phi(); + o2::math_utils::bringToPMPi(dphi); + float aco = 1.f - std::fabs(dphi) / M_PI; + float asym = std::fabs(v1.Pt() - v2.Pt()) / (v1.Pt() + v2.Pt()); + float dphi_e_ee = v1.Phi() - v12.Phi(); + o2::math_utils::bringToPMPi(dphi_e_ee); + + float cos_thetaCS = 999, phiCS = 999.f; + o2::aod::pwgem::dilepton::utils::pairutil::getAngleCS(t1, t2, leptonM1, leptonM2, beamE1, beamE2, beamP1, beamP2, cos_thetaCS, phiCS); + + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), pair_dca, aco, asym, std::fabs(dphi_e_ee), std::fabs(cos_thetaCS), weight); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hs"), v12.M(), v12.Pt(), pair_dca, aco, asym, std::fabs(dphi_e_ee), std::fabs(cos_thetaCS), weight); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, aco, asym, std::fabs(dphi_e_ee), std::fabs(cos_thetaCS), weight); + } + } else if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kFlowV2) || cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kFlowV3)) { + std::array q2ft0m = {collision.q2xft0m(), collision.q2yft0m()}; + std::array q2ft0a = {collision.q2xft0a(), collision.q2yft0a()}; + std::array q2ft0c = {collision.q2xft0c(), collision.q2yft0c()}; + std::array q2btot = {collision.q2xbtot(), collision.q2ybtot()}; + std::array q2bpos = {collision.q2xbpos(), collision.q2ybpos()}; + std::array q2bneg = {collision.q2xbneg(), collision.q2ybneg()}; + std::array q3ft0m = {collision.q3xft0m(), collision.q3yft0m()}; + std::array q3ft0a = {collision.q3xft0a(), collision.q3yft0a()}; + std::array q3ft0c = {collision.q3xft0c(), collision.q3yft0c()}; + std::array q3btot = {collision.q3xbtot(), collision.q3ybtot()}; + std::array q3bpos = {collision.q3xbpos(), collision.q3ybpos()}; + std::array q3bneg = {collision.q3xbneg(), collision.q3ybneg()}; + + std::vector>> qvectors = { + {{999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}}, // 0th harmonics + {{999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}}, // 1st harmonics + {q2ft0m, q2ft0a, q2ft0c, q2btot, q2bpos, q2bneg}, // 2nd harmonics + {q3ft0m, q3ft0a, q3ft0c, q3btot, q3bpos, q3bneg}, // 3rd harmonics + }; + + if constexpr (ev_id == 0) { + // LOGF(info, "collision.centFT0C() = %f, collision.trackOccupancyInTimeRange() = %d, getSPresolution = %f", collision.centFT0C(), collision.trackOccupancyInTimeRange(), getSPresolution(collision.centFT0C(), collision.trackOccupancyInTimeRange())); + + float sp = RecoDecay::dotProd(std::array{static_cast(std::cos(nmod * v12.Phi())), static_cast(std::sin(nmod * v12.Phi()))}, qvectors[nmod][cfgQvecEstimator]) / getSPresolution(collision.centFT0C(), collision.trackOccupancyInTimeRange()); + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), pair_dca, sp, weight); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hs"), v12.M(), v12.Pt(), pair_dca, sp, weight); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, sp, weight); + } + } else if constexpr (ev_id == 1) { + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), pair_dca, weight); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hs"), v12.M(), v12.Pt(), pair_dca, weight); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, weight); + } + } + } else if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kPolarization)) { + float cos_thetaCS = 999, phiCS = 999.f; + o2::aod::pwgem::dilepton::utils::pairutil::getAngleCS(t1, t2, leptonM1, leptonM2, beamE1, beamE2, beamP1, beamP2, cos_thetaCS, phiCS); + o2::math_utils::bringToPMPi(phiCS); + + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), pair_dca, std::fabs(cos_thetaCS), std::fabs(phiCS), weight); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hs"), v12.M(), v12.Pt(), pair_dca, std::fabs(cos_thetaCS), std::fabs(phiCS), weight); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, std::fabs(cos_thetaCS), std::fabs(phiCS), weight); + } + + } else if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kVM)) { + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), weight); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), weight); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), weight); + } + } else if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kHFll)) { + float dphi = v1.Phi() - v2.Phi(); + dphi = RecoDecay::constrainAngle(dphi, -o2::constants::math::PIHalf); + float deta = v1.Eta() - v2.Eta(); + + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), pair_dca, dphi, deta, weight); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hs"), v12.M(), v12.Pt(), pair_dca, dphi, deta, weight); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, dphi, deta, weight); + } + + } else { // same as kQC to avoid seg. fault + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), pair_dca, weight); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hs"), v12.M(), v12.Pt(), pair_dca, weight); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, weight); + } + } + + // store tracks for event mixing without double counting + if constexpr (ev_id == 0) { + std::pair key_df_collision = std::make_pair(ndf, collision.globalIndex()); + std::pair pair_tmp_id1 = std::make_pair(ndf, t1.globalIndex()); + std::pair pair_tmp_id2 = std::make_pair(ndf, t2.globalIndex()); + + std::vector possibleIds1; + std::vector possibleIds2; + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + std::copy(t1.ambiguousElectronsIds().begin(), t1.ambiguousElectronsIds().end(), std::back_inserter(possibleIds1)); + std::copy(t2.ambiguousElectronsIds().begin(), t2.ambiguousElectronsIds().end(), std::back_inserter(possibleIds2)); + + if (std::find(used_trackIds.begin(), used_trackIds.end(), pair_tmp_id1) == used_trackIds.end()) { + used_trackIds.emplace_back(pair_tmp_id1); + if (cfgDoMix) { + if (t1.sign() > 0) { + emh_pos->AddTrackToEventPool(key_df_collision, EMTrackWithCov(ndf, t1.globalIndex(), collision.globalIndex(), t1.trackId(), t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.dcaXY(), t1.dcaZ(), possibleIds1, + t1.x(), t1.y(), t1.z(), t1.alpha(), t1.snp(), t1.tgl(), t1.cYY(), t1.cZY(), t1.cZZ(), + t1.cSnpY(), t1.cSnpZ(), t1.cSnpSnp(), t1.cTglY(), t1.cTglZ(), t1.cTglSnp(), t1.cTglTgl(), t1.c1PtY(), t1.c1PtZ(), t1.c1PtSnp(), t1.c1PtTgl(), t1.c1Pt21Pt2())); + } else { + emh_neg->AddTrackToEventPool(key_df_collision, EMTrackWithCov(ndf, t1.globalIndex(), collision.globalIndex(), t1.trackId(), t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.dcaXY(), t1.dcaZ(), possibleIds1, + t1.x(), t1.y(), t1.z(), t1.alpha(), t1.snp(), t1.tgl(), t1.cYY(), t1.cZY(), t1.cZZ(), + t1.cSnpY(), t1.cSnpZ(), t1.cSnpSnp(), t1.cTglY(), t1.cTglZ(), t1.cTglSnp(), t1.cTglTgl(), t1.c1PtY(), t1.c1PtZ(), t1.c1PtSnp(), t1.c1PtTgl(), t1.c1Pt21Pt2())); + } + } + } + if (std::find(used_trackIds.begin(), used_trackIds.end(), pair_tmp_id2) == used_trackIds.end()) { + used_trackIds.emplace_back(pair_tmp_id2); + if (cfgDoMix) { + if (t2.sign() > 0) { + emh_pos->AddTrackToEventPool(key_df_collision, EMTrackWithCov(ndf, t2.globalIndex(), collision.globalIndex(), t2.trackId(), t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.dcaXY(), t2.dcaZ(), possibleIds2, + t2.x(), t2.y(), t2.z(), t2.alpha(), t2.snp(), t2.tgl(), t2.cYY(), t2.cZY(), t2.cZZ(), + t2.cSnpY(), t2.cSnpZ(), t2.cSnpSnp(), t2.cTglY(), t2.cTglZ(), t2.cTglSnp(), t2.cTglTgl(), t2.c1PtY(), t2.c1PtZ(), t2.c1PtSnp(), t2.c1PtTgl(), t2.c1Pt21Pt2())); + } else { + emh_neg->AddTrackToEventPool(key_df_collision, EMTrackWithCov(ndf, t2.globalIndex(), collision.globalIndex(), t2.trackId(), t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.dcaXY(), t2.dcaZ(), possibleIds2, + t2.x(), t2.y(), t2.z(), t2.alpha(), t2.snp(), t2.tgl(), t2.cYY(), t2.cZY(), t2.cZZ(), + t2.cSnpY(), t2.cSnpZ(), t2.cSnpSnp(), t2.cTglY(), t2.cTglZ(), t2.cTglSnp(), t2.cTglTgl(), t2.c1PtY(), t2.c1PtZ(), t2.c1PtSnp(), t2.c1PtTgl(), t2.c1Pt21Pt2())); + } + } + } + } else if (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + std::copy(t1.ambiguousMuonsIds().begin(), t1.ambiguousMuonsIds().end(), std::back_inserter(possibleIds1)); + std::copy(t2.ambiguousMuonsIds().begin(), t2.ambiguousMuonsIds().end(), std::back_inserter(possibleIds2)); + + if (std::find(used_trackIds.begin(), used_trackIds.end(), pair_tmp_id1) == used_trackIds.end()) { + used_trackIds.emplace_back(pair_tmp_id1); + if (cfgDoMix) { + if (t1.sign() > 0) { + emh_pos->AddTrackToEventPool(key_df_collision, EMFwdTrack(ndf, t1.globalIndex(), collision.globalIndex(), t1.fwdtrackId(), t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassMuon, t1.sign(), t1.fwdDcaX(), t1.fwdDcaY(), possibleIds1, + t1.cXXatDCA(), t1.cXYatDCA(), t1.cYYatDCA())); + } else { + emh_neg->AddTrackToEventPool(key_df_collision, EMFwdTrack(ndf, t1.globalIndex(), collision.globalIndex(), t1.fwdtrackId(), t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassMuon, t1.sign(), t1.fwdDcaX(), t1.fwdDcaY(), possibleIds1, + t1.cXXatDCA(), t1.cXYatDCA(), t1.cYYatDCA())); + } + } + } + if (std::find(used_trackIds.begin(), used_trackIds.end(), pair_tmp_id2) == used_trackIds.end()) { + used_trackIds.emplace_back(pair_tmp_id2); + if (cfgDoMix) { + if (t2.sign() > 0) { + emh_pos->AddTrackToEventPool(key_df_collision, EMFwdTrack(ndf, t2.globalIndex(), collision.globalIndex(), t2.fwdtrackId(), t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassMuon, t2.sign(), t2.fwdDcaX(), t2.fwdDcaY(), possibleIds2, + t2.cXXatDCA(), t2.cXYatDCA(), t2.cYYatDCA())); + } else { + emh_neg->AddTrackToEventPool(key_df_collision, EMFwdTrack(ndf, t2.globalIndex(), collision.globalIndex(), t2.fwdtrackId(), t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassMuon, t2.sign(), t2.fwdDcaX(), t2.fwdDcaY(), possibleIds2, + t2.cXXatDCA(), t2.cXYatDCA(), t2.cYYatDCA())); + } + } + } + } + } + return true; + } + + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + // Filter collisionFilter_multiplicity = cfgNtracksPV08Min <= o2::aod::mult::multNTracksPV && o2::aod::mult::multNTracksPV < cfgNtracksPV08Max; + Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + using FilteredMyCollisions = soa::Filtered; + + SliceCache cache; + Preslice perCollision_electron = aod::emprimaryelectron::emeventId; + Filter trackFilter_electron = dielectroncuts.cfg_min_pt_track < o2::aod::track::pt && dielectroncuts.cfg_min_eta_track < o2::aod::track::eta && o2::aod::track::eta < dielectroncuts.cfg_max_eta_track && dielectroncuts.cfg_min_phi_track < o2::aod::track::phi && o2::aod::track::phi < dielectroncuts.cfg_max_phi_track && o2::aod::track::tpcChi2NCl < dielectroncuts.cfg_max_chi2tpc && o2::aod::track::itsChi2NCl < dielectroncuts.cfg_max_chi2its && nabs(o2::aod::track::dcaXY) < dielectroncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dielectroncuts.cfg_max_dcaz; + Filter pidFilter_electron = dielectroncuts.cfg_min_TPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < dielectroncuts.cfg_max_TPCNsigmaEl; + Filter ttcaFilter_electron = ifnode(dielectroncuts.enableTTCA.node(), o2::aod::emprimaryelectron::isAssociatedToMPC == true || o2::aod::emprimaryelectron::isAssociatedToMPC == false, o2::aod::emprimaryelectron::isAssociatedToMPC == true); + Filter prefilter_derived_electron = ifnode(dielectroncuts.cfg_apply_cuts_from_prefilter_derived.node() && dielectroncuts.cfg_prefilter_bits_derived.node() >= static_cast(1), + ifnode((dielectroncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kMee))) > static_cast(0), (o2::aod::emprimaryelectron::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kMee))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kPhiV))) > static_cast(0), (o2::aod::emprimaryelectron::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kPhiV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS))) > static_cast(0), (o2::aod::emprimaryelectron::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS))) > static_cast(0), (o2::aod::emprimaryelectron::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS))) <= static_cast(0), true), + o2::aod::emprimaryelectron::pfbderived >= static_cast(0)); + + Filter prefilter_electron = ifnode(dielectroncuts.cfg_apply_cuts_from_prefilter.node() && dielectroncuts.cfg_prefilter_bits.node() >= static_cast(1), + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPC))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPC))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_1))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_1))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_2))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_2))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_3))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_3))) <= static_cast(0), true), + o2::aod::emprimaryelectron::pfb >= static_cast(0)); + + Partition positive_electrons = o2::aod::emprimaryelectron::sign > int8_t(0); + Partition negative_electrons = o2::aod::emprimaryelectron::sign < int8_t(0); + + Preslice perCollision_muon = aod::emprimarymuon::emeventId; + Filter trackFilter_muon = o2::aod::fwdtrack::trackType == dimuoncuts.cfg_track_type && dimuoncuts.cfg_min_pt_track < o2::aod::fwdtrack::pt && o2::aod::fwdtrack::pt < dimuoncuts.cfg_max_pt_track && dimuoncuts.cfg_min_eta_track < o2::aod::fwdtrack::eta && o2::aod::fwdtrack::eta < dimuoncuts.cfg_max_eta_track && dimuoncuts.cfg_min_phi_track < o2::aod::fwdtrack::phi && o2::aod::fwdtrack::phi < dimuoncuts.cfg_max_phi_track; + Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), o2::aod::emprimarymuon::isAssociatedToMPC == true || o2::aod::emprimarymuon::isAssociatedToMPC == false, o2::aod::emprimarymuon::isAssociatedToMPC == true); + Partition positive_muons = o2::aod::emprimarymuon::sign > int8_t(0); + Partition negative_muons = o2::aod::emprimarymuon::sign < int8_t(0); + + TEMH* emh_pos = nullptr; + TEMH* emh_neg = nullptr; + std::map, uint64_t> map_mixed_eventId_to_globalBC; + + std::vector> used_trackIds; + int ndf = 0; + + template + void runPairing(TCollisions const& collisions, TLeptons const& posTracks, TLeptons const& negTracks, TPresilce const& perCollision, TCut const& cut, TAllTracks const& tracks) + { + for (const auto& collision : collisions) { + initCCDB(collision); + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + float centrality = centralities[cfgCentEstimator]; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + if constexpr (isTriggerAnalysis) { + if (!collision.swtalias_bit(o2::aod::pwgem::dilepton::swt::aliasLabels.at(cfg_swt_name.value))) { + continue; + } + } + + std::array q2ft0m = {collision.q2xft0m(), collision.q2yft0m()}; + std::array q2ft0a = {collision.q2xft0a(), collision.q2yft0a()}; + std::array q2ft0c = {collision.q2xft0c(), collision.q2yft0c()}; + std::array q2btot = {collision.q2xbtot(), collision.q2ybtot()}; + std::array q2bpos = {collision.q2xbpos(), collision.q2ybpos()}; + std::array q2bneg = {collision.q2xbneg(), collision.q2ybneg()}; + std::array q3ft0m = {collision.q3xft0m(), collision.q3yft0m()}; + std::array q3ft0a = {collision.q3xft0a(), collision.q3yft0a()}; + std::array q3ft0c = {collision.q3xft0c(), collision.q3yft0c()}; + std::array q3btot = {collision.q3xbtot(), collision.q3ybtot()}; + std::array q3bpos = {collision.q3xbpos(), collision.q3ybpos()}; + std::array q3bneg = {collision.q3xbneg(), collision.q3ybneg()}; + const float eventplanes_2_for_mix[6] = {collision.ep2ft0m(), collision.ep2ft0a(), collision.ep2ft0c(), collision.ep2btot(), collision.ep2bpos(), collision.ep2bneg()}; + float ep2 = eventplanes_2_for_mix[cfgEP2Estimator_for_Mix]; + + std::vector>> qvectors = { + {{999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}}, // 0th harmonics + {{999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}}, // 1st harmonics + {q2ft0m, q2ft0a, q2ft0c, q2btot, q2bpos, q2bneg}, // 2nd harmonics + {q3ft0m, q3ft0a, q3ft0c, q3btot, q3bpos, q3bneg}, // 3rd harmonics + }; + + if (nmod == 2) { + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<0, 2>(&fRegistry, collision); + } else if (nmod == 3) { + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<0, 3>(&fRegistry, collision); + } else { + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<0, -1>(&fRegistry, collision); + } + if (nmod < 0 || isGoodQvector(qvectors)) { + fRegistry.fill(HIST("Event/before/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev - 1); // is qvector calibarated + } + fRegistry.fill(HIST("Event/before/hEP2_CentFT0C_forMix"), collision.centFT0C(), ep2); + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + + if (nmod > 0 && !isGoodQvector(qvectors)) { + continue; + } + + if (nmod == 2) { + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<1, 2>(&fRegistry, collision); + } else if (nmod == 3) { + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<1, 3>(&fRegistry, collision); + } else { + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<1, -1>(&fRegistry, collision); + } + fRegistry.fill(HIST("Event/after/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev - 1); // is qvector calibarated + + fRegistry.fill(HIST("Event/before/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted + fRegistry.fill(HIST("Event/after/hEP2_CentFT0C_forMix"), collision.centFT0C(), ep2); + + auto posTracks_per_coll = posTracks.sliceByCached(perCollision, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks.sliceByCached(perCollision, collision.globalIndex(), cache); + // LOGF(info, "collision.globalIndex() = %d , collision.posZ() = %f , collision.numContrib() = %d, centrality = %f , posTracks_per_coll.size() = %d, negTracks_per_coll.size() = %d", collision.globalIndex(), collision.posZ(), collision.numContrib(), centralities[cfgCentEstimator], posTracks_per_coll.size(), negTracks_per_coll.size()); + + int nuls = 0, nlspp = 0, nlsmm = 0; + for (const auto& [pos, neg] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + bool is_pair_ok = fillPairInfo<0>(collision, pos, neg, cut, tracks); + if (is_pair_ok) { + nuls++; + } + } + for (const auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { // LS++ + bool is_pair_ok = fillPairInfo<0>(collision, pos1, pos2, cut, tracks); + if (is_pair_ok) { + nlspp++; + } + } + for (const auto& [neg1, neg2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { // LS-- + bool is_pair_ok = fillPairInfo<0>(collision, neg1, neg2, cut, tracks); + if (is_pair_ok) { + nlsmm++; + } + } + + if (!cfgDoMix || !(nuls > 0 || nlspp > 0 || nlsmm > 0)) { + continue; + } + + // event mixing + int zbin = lower_bound(zvtx_bin_edges.begin(), zvtx_bin_edges.end(), collision.posZ()) - zvtx_bin_edges.begin() - 1; + if (zbin < 0) { + zbin = 0; + } else if (static_cast(zvtx_bin_edges.size()) - 2 < zbin) { + zbin = static_cast(zvtx_bin_edges.size()) - 2; + } + + int centbin = lower_bound(cent_bin_edges.begin(), cent_bin_edges.end(), centrality) - cent_bin_edges.begin() - 1; + if (centbin < 0) { + centbin = 0; + } else if (static_cast(cent_bin_edges.size()) - 2 < centbin) { + centbin = static_cast(cent_bin_edges.size()) - 2; + } + + int epbin = lower_bound(ep_bin_edges.begin(), ep_bin_edges.end(), ep2) - ep_bin_edges.begin() - 1; + if (epbin < 0) { + epbin = 0; + } else if (static_cast(ep_bin_edges.size()) - 2 < epbin) { + epbin = static_cast(ep_bin_edges.size()) - 2; + } + + int occbin = -1; + if (cfgOccupancyEstimator == 0) { + occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.ft0cOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; + } else if (cfgOccupancyEstimator == 1) { + occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.trackOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; + } else { + occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.ft0cOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; + } + + if (occbin < 0) { + occbin = 0; + } else if (static_cast(occ_bin_edges.size()) - 2 < occbin) { + occbin = static_cast(occ_bin_edges.size()) - 2; + } + + // LOGF(info, "collision.globalIndex() = %d, collision.posZ() = %f, centrality = %f, ep2 = %f, collision.trackOccupancyInTimeRange() = %d, zbin = %d, centbin = %d, epbin = %d, occbin = %d", collision.globalIndex(), collision.posZ(), centrality, ep2, collision.trackOccupancyInTimeRange(), zbin, centbin, epbin, occbin); + + std::tuple key_bin = std::make_tuple(zbin, centbin, epbin, occbin); + std::pair key_df_collision = std::make_pair(ndf, collision.globalIndex()); + + // make a vector of selected photons in this collision. + auto selected_posTracks_in_this_event = emh_pos->GetTracksPerCollision(key_df_collision); + auto selected_negTracks_in_this_event = emh_neg->GetTracksPerCollision(key_df_collision); + // LOGF(info, "N selected tracks in current event (%d, %d), zvtx = %f, centrality = %f , npos = %d , nneg = %d, nuls = %d , nlspp = %d, nlsmm = %d", ndf, collision.globalIndex(), collision.posZ(), centralities[cfgCentEstimator], selected_posTracks_in_this_event.size(), selected_negTracks_in_this_event.size(), nuls, nlspp, nlsmm); + + auto collisionIds_in_mixing_pool = emh_pos->GetCollisionIdsFromEventPool(key_bin); // pos/neg does not matter. + // LOGF(info, "collisionIds_in_mixing_pool.size() = %d", collisionIds_in_mixing_pool.size()); + + for (const auto& mix_dfId_collisionId : collisionIds_in_mixing_pool) { + int mix_dfId = mix_dfId_collisionId.first; + int mix_collisionId = mix_dfId_collisionId.second; + if (collision.globalIndex() == mix_collisionId && ndf == mix_dfId) { // this never happens. only protection. + continue; + } + + auto globalBC_mix = map_mixed_eventId_to_globalBC[mix_dfId_collisionId]; + uint64_t diffBC = std::max(collision.globalBC(), globalBC_mix) - std::min(collision.globalBC(), globalBC_mix); + fRegistry.fill(HIST("Pair/mix/hDiffBC"), diffBC); + if (diffBC < ndiff_bc_mix) { + continue; + } + + auto posTracks_from_event_pool = emh_pos->GetTracksPerCollision(mix_dfId_collisionId); + auto negTracks_from_event_pool = emh_neg->GetTracksPerCollision(mix_dfId_collisionId); + // LOGF(info, "Do event mixing: current event (%d, %d) | event pool (%d, %d), npos = %d , nneg = %d", ndf, collision.globalIndex(), mix_dfId, mix_collisionId, posTracks_from_event_pool.size(), negTracks_from_event_pool.size()); + + for (const auto& pos : selected_posTracks_in_this_event) { // ULS mix + for (const auto& neg : negTracks_from_event_pool) { + fillPairInfo<1>(collision, pos, neg, cut, tracks); + } + } + + for (const auto& neg : selected_negTracks_in_this_event) { // ULS mix + for (const auto& pos : posTracks_from_event_pool) { + fillPairInfo<1>(collision, neg, pos, cut, tracks); + } + } + + for (const auto& pos1 : selected_posTracks_in_this_event) { // LS++ mix + for (const auto& pos2 : posTracks_from_event_pool) { + fillPairInfo<1>(collision, pos1, pos2, cut, tracks); + } + } + + for (const auto& neg1 : selected_negTracks_in_this_event) { // LS-- mix + for (const auto& neg2 : negTracks_from_event_pool) { + fillPairInfo<1>(collision, neg1, neg2, cut, tracks); + } + } + } // end of loop over mixed event pool + + if (nuls > 0 || nlspp > 0 || nlsmm > 0) { + map_mixed_eventId_to_globalBC[key_df_collision] = collision.globalBC(); + emh_pos->AddCollisionIdAtLast(key_bin, key_df_collision); + emh_neg->AddCollisionIdAtLast(key_bin, key_df_collision); + } + + } // end of collision loop + + } // end of DF + + template + bool isPairOK(TCollision const& collision, TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TAllTracks const& tracks) + { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { + if (!cut.template IsSelectedTrack(t1, collision) || !cut.template IsSelectedTrack(t2, collision)) { + return false; + } + } else { // cut-based + if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { + return false; + } + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (!cut.IsSelectedTrack(t1) || !cut.IsSelectedTrack(t2)) { + return false; + } + + if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t1, cut, tracks)) { + return false; + } + if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t2, cut, tracks)) { + return false; + } + } + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (!cut.IsSelectedPair(t1, t2, d_bz)) { + return false; + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (!cut.IsSelectedPair(t1, t2)) { + return false; + } + } + return true; + } + + std::map, float> map_weight; // -> float + template + void fillPairWeightMap(TCollisions const& collisions, TLeptons const& posTracks, TLeptons const& negTracks, TPresilce const& perCollision, TCut const& cut, TAllTracks const& tracks) + { + std::vector> passed_pairIds; + passed_pairIds.reserve(posTracks.size() * negTracks.size()); + + for (const auto& collision : collisions) { + initCCDB(collision); + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + if constexpr (isTriggerAnalysis) { + if (!collision.swtalias_bit(o2::aod::pwgem::dilepton::swt::aliasLabels.at(cfg_swt_name.value))) { + continue; + } + } + + std::array q2ft0m = {collision.q2xft0m(), collision.q2yft0m()}; + std::array q2ft0a = {collision.q2xft0a(), collision.q2yft0a()}; + std::array q2ft0c = {collision.q2xft0c(), collision.q2yft0c()}; + std::array q2btot = {collision.q2xbtot(), collision.q2ybtot()}; + std::array q2bpos = {collision.q2xbpos(), collision.q2ybpos()}; + std::array q2bneg = {collision.q2xbneg(), collision.q2ybneg()}; + std::array q3ft0m = {collision.q3xft0m(), collision.q3yft0m()}; + std::array q3ft0a = {collision.q3xft0a(), collision.q3yft0a()}; + std::array q3ft0c = {collision.q3xft0c(), collision.q3yft0c()}; + std::array q3btot = {collision.q3xbtot(), collision.q3ybtot()}; + std::array q3bpos = {collision.q3xbpos(), collision.q3ybpos()}; + std::array q3bneg = {collision.q3xbneg(), collision.q3ybneg()}; + + std::vector>> qvectors = { + {{999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}}, // 0th harmonics + {{999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}}, // 1st harmonics + {q2ft0m, q2ft0a, q2ft0c, q2btot, q2bpos, q2bneg}, // 2nd harmonics + {q3ft0m, q3ft0a, q3ft0c, q3btot, q3bpos, q3bneg}, // 3rd harmonics + }; + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + + if (nmod > 0 && !isGoodQvector(qvectors)) { + continue; + } + + auto posTracks_per_coll = posTracks.sliceByCached(perCollision, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks.sliceByCached(perCollision, collision.globalIndex(), cache); + + for (const auto& [pos, neg] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + if (isPairOK(collision, pos, neg, cut, tracks)) { + passed_pairIds.emplace_back(std::make_pair(pos.globalIndex(), neg.globalIndex())); + } + } + for (const auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { // LS++ + if (isPairOK(collision, pos1, pos2, cut, tracks)) { + passed_pairIds.emplace_back(std::make_pair(pos1.globalIndex(), pos2.globalIndex())); + } + } + for (const auto& [neg1, neg2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { // LS-- + if (isPairOK(collision, neg1, neg2, cut, tracks)) { + passed_pairIds.emplace_back(std::make_pair(neg1.globalIndex(), neg2.globalIndex())); + } + } + } // end of collision loop + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + for (const auto& pairId : passed_pairIds) { + auto t1 = tracks.rawIteratorAt(std::get<0>(pairId)); + auto t2 = tracks.rawIteratorAt(std::get<1>(pairId)); + // LOGF(info, "std::get<0>(pairId) = %d, std::get<1>(pairId) = %d, t1.globalIndex() = %d, t2.globalIndex() = %d", std::get<0>(pairId), std::get<1>(pairId), t1.globalIndex(), t2.globalIndex()); + + float n = 1.f; // include myself. + for (const auto& ambId1 : t1.ambiguousElectronsIds()) { + for (const auto& ambId2 : t2.ambiguousElectronsIds()) { + if (std::find(passed_pairIds.begin(), passed_pairIds.end(), std::make_pair(ambId1, ambId2)) != passed_pairIds.end()) { + n += 1.f; + } + } + } + map_weight[pairId] = 1.f / n; + } // end of passed_pairIds loop + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + for (const auto& pairId : passed_pairIds) { + auto t1 = tracks.rawIteratorAt(std::get<0>(pairId)); + auto t2 = tracks.rawIteratorAt(std::get<1>(pairId)); + + float n = 1.f; // include myself. + for (const auto& ambId1 : t1.ambiguousMuonsIds()) { + for (const auto& ambId2 : t2.ambiguousMuonsIds()) { + if (std::find(passed_pairIds.begin(), passed_pairIds.end(), std::make_pair(ambId1, ambId2)) != passed_pairIds.end()) { + n += 1.f; + } + } + } + map_weight[pairId] = 1.f / n; + } // end of passed_pairIds loop + } + passed_pairIds.clear(); + passed_pairIds.shrink_to_fit(); + } + + void processAnalysis(FilteredMyCollisions const& collisions, Types const&... args) + { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + auto electrons = std::get<0>(std::tie(args...)); + if (cfgApplyWeightTTCA) { + fillPairWeightMap(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, electrons); + } + runPairing(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, electrons); + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + auto muons = std::get<0>(std::tie(args...)); + if (cfgApplyWeightTTCA) { + fillPairWeightMap(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, muons); + } + runPairing(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, muons); + } + map_weight.clear(); + ndf++; + } + PROCESS_SWITCH(Dilepton, processAnalysis, "run dilepton analysis", true); + + using FilteredMyCollisionsWithSWT = soa::Filtered; + void processTriggerAnalysis(FilteredMyCollisionsWithSWT const& collisions, Types const&... args) + { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + auto electrons = std::get<0>(std::tie(args...)); + if (cfgApplyWeightTTCA) { + fillPairWeightMap(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, electrons); + } + runPairing(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, electrons); + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + auto muons = std::get<0>(std::tie(args...)); + if (cfgApplyWeightTTCA) { + fillPairWeightMap(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, muons); + } + runPairing(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, muons); + } + map_weight.clear(); + ndf++; + } + PROCESS_SWITCH(Dilepton, processTriggerAnalysis, "run dilepton analysis on triggered data", false); + + Filter collisionFilter_centrality_norm = cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax; + using FilteredNormInfos = soa::Filtered; + + void processNorm(FilteredNormInfos const& collisions) + { + for (const auto& collision : collisions) { + if (collision.centFT0C() < cfgCentMin || cfgCentMax < collision.centFT0C()) { + continue; + } + + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 1.0); + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 2.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 3.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 4.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 5.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 6.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 7.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 8.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 9.0); + } + if (collision.sel8()) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 10.0); + } + if (std::fabs(collision.posZ()) < 10.0) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 11.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 12.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 13.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 14.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 15.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 16.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer3)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 17.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 18.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 19.0); + } + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted + } // end of collision loop + } + PROCESS_SWITCH(Dilepton, processNorm, "process normalization info", false); + + void processBC(aod::EMBCs const& bcs) + { + for (const auto& bc : bcs) { + if (bc.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 0.f); + + if (bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 1.f); + } + if (bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 2.f); + } + if (rctChecker(bc)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 3.f); + } + if (bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 4.f); + } + if (bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder) && rctChecker(bc)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 5.f); + } + } + } + } + PROCESS_SWITCH(Dilepton, processBC, "process BC counter", false); + + void processDummy(MyCollisions const&) {} + PROCESS_SWITCH(Dilepton, processDummy, "Dummy function", false); +}; + +#endif // PWGEM_DILEPTON_CORE_DILEPTON_H_ diff --git a/PWGEM/Dilepton/Core/DileptonMC.h b/PWGEM/Dilepton/Core/DileptonMC.h new file mode 100644 index 00000000000..952edff0aa3 --- /dev/null +++ b/PWGEM/Dilepton/Core/DileptonMC.h @@ -0,0 +1,2539 @@ +// 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. +// +// ======================== +// +// This code runs loop over leptons in MC +// Please write to: daiki.sekihata@cern.ch + +#ifndef PWGEM_DILEPTON_CORE_DILEPTONMC_H_ +#define PWGEM_DILEPTON_CORE_DILEPTONMC_H_ + +#include +#include +#include +#include + +#include "TString.h" +#include "Math/Vector4D.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "CommonConstants/LHCConstants.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsParameters/GRPECSObject.h" + +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "Tools/ML/MlResponse.h" +#include "Common/CCDB/RCTSelectionFlags.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Core/DielectronCut.h" +#include "PWGEM/Dilepton/Core/DimuonCut.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/Dilepton/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::dilepton::utils::mcutil; +using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; +using namespace o2::aod::pwgem::dilepton::utils::pairutil; + +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; + +using MyMCCollisions = soa::Join; +using MyMCCollision = MyMCCollisions::iterator; + +using MyMCElectrons = soa::Join; +using MyMCElectron = MyMCElectrons::iterator; +using FilteredMyMCElectrons = soa::Filtered; +using FilteredMyMCElectron = FilteredMyMCElectrons::iterator; + +using MyMCMuons = soa::Join; +using MyMCMuon = MyMCMuons::iterator; +using FilteredMyMCMuons = soa::Filtered; +using FilteredMyMCMuon = FilteredMyMCMuons::iterator; + +using MySmearedElectrons = soa::Join; +using MySmearedElectron = MySmearedElectrons::iterator; + +using MySmearedMuons = soa::Join; +using MySmearedMuon = MySmearedMuons::iterator; + +// template +template +struct DileptonMC { + + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + + Configurable cfgEventGeneratorType{"cfgEventGeneratorType", -1, "if positive, select event generator type. i.e. gap or signal"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + // Configurable cfgNtracksPV08Min{"cfgNtracksPV08Min", -1, "min. multNTracksPV"}; + // Configurable cfgNtracksPV08Max{"cfgNtracksPV08Max", static_cast(1e+9), "max. multNTracksPV"}; + Configurable cfgApplyWeightTTCA{"cfgApplyWeightTTCA", false, "flag to apply weighting by 1/N"}; + Configurable cfgDCAType{"cfgDCAType", 0, "type of DCA for output. 0:3D, 1:XY, 2:Z, else:3D"}; + Configurable cfgFillUnfolding{"cfgFillUnfolding", false, "flag to fill histograms for unfolding"}; + Configurable cfgRequireTrueAssociation{"cfgRequireTrueAssociation", false, "flag to require true mc collision association"}; + + ConfigurableAxis ConfMllBins{"ConfMllBins", {VARIABLE_WIDTH, 0.00, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.30, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.40, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.50, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.60, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.70, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.80, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.90, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.00, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.10, 2.20, 2.30, 2.40, 2.50, 2.60, 2.70, 2.75, 2.80, 2.85, 2.90, 2.95, 3.00, 3.05, 3.10, 3.15, 3.20, 3.25, 3.30, 3.35, 3.40, 3.45, 3.50, 3.55, 3.60, 3.65, 3.70, 3.75, 3.80, 3.85, 3.90, 3.95, 4.00}, "mll bins for output histograms"}; + ConfigurableAxis ConfPtllBins{"ConfPtllBins", {VARIABLE_WIDTH, 0.00, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.50, 3.00, 3.50, 4.00, 4.50, 5.00, 6.00, 7.00, 8.00, 9.00, 10.00}, "pTll bins for output histograms"}; + ConfigurableAxis ConfDCAllBins{"ConfDCAllBins", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0}, "DCAll bins for output histograms"}; + + ConfigurableAxis ConfYllBins{"ConfYllBins", {VARIABLE_WIDTH, -10.f, +10.f}, "yll bins for output histograms"}; + + // ConfigurableAxis ConfMmumuBins{"ConfMmumuBins", {VARIABLE_WIDTH, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.30, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.40, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.50, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.60, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.70, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.80, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.90, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.00, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.10, 1.11,1.12,1.13,1.14,1.15,1.16,1.17,1.18,1.19, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.10, 2.20, 2.30, 2.40, 2.50, 2.60, 2.70, 2.75, 2.80, 2.85, 2.90, 2.95, 3.00, 3.05, 3.10, 3.15, 3.20, 3.25, 3.30, 3.35, 3.40, 3.45, 3.50, 3.55, 3.60, 3.65, 3.70, 3.75, 3.80, 3.85, 3.90, 3.95, 4.00, 4.10, 4.20, 4.30, 4.40, 4.50, 4.60, 4.70, 4.80, 4.90, 5.00, 5.10, 5.20, 5.30, 5.40, 5.50, 5.60, 5.70, 5.80, 5.90, 6.00, 6.10, 6.20, 6.30, 6.40, 6.50, 6.60, 6.70, 6.80, 6.90, 7.00, 7.10, 7.20, 7.30, 7.40, 7.50, 7.60, 7.70, 7.80, 7.90, 8.00, 8.10, 8.20, 8.30, 8.40, 8.50, 8.60, 8.70, 8.80, 8.90, 9.00, 9.10, 9.20, 9.30, 9.40, 9.50, 9.60, 9.70, 9.80, 9.90, 10.00, 10.10, 10.20, 10.30, 10.40, 10.50, 10.60, 10.70, 10.80, 10.90, 11.00, 11.50, 12.00}, "mmumu bins for output histograms"}; // for dimuon. one can copy bins here to hyperloop page. + + Configurable cfg_nbin_dphi_ee{"cfg_nbin_dphi_ee", 1, "number of bins for dphi_ee"}; // 36 + Configurable cfg_nbin_deta_ee{"cfg_nbin_deta_ee", 1, "number of bins for deta_ee"}; // 40 + Configurable cfg_nbin_cos_theta_cs{"cfg_nbin_cos_theta_cs", 1, "number of bins for cos theta cs"}; // 10 + Configurable cfg_nbin_phi_cs{"cfg_nbin_phi_cs", 1, "number of bins for phi cs"}; // 18 + Configurable cfg_nbin_aco{"cfg_nbin_aco", 1, "number of bins for acoplanarity"}; // 10 + Configurable cfg_nbin_asym_pt{"cfg_nbin_asym_pt", 1, "number of bins for pt asymmetry"}; // 10 + Configurable cfg_nbin_dphi_e_ee{"cfg_nbin_dphi_e_ee", 1, "number of bins for dphi_ee_e"}; // 18 + + EMEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; + Configurable cfgZvtxMax{"cfgZvtxMax", +10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInTimeRangeStrict{"cfgRequireNoCollInTimeRangeStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoCollInITSROFStandard{"cfgRequireNoCollInITSROFStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInITSROFStrict{"cfgRequireNoCollInITSROFStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoHighMultCollInPrevRof{"cfgRequireNoHighMultCollInPrevRof", false, "require no HM collision in previous ITS ROF"}; + Configurable cfgRequireGoodITSLayer3{"cfgRequireGoodITSLayer3", false, "number of inactive chips on ITS layer 3 are below threshold "}; + Configurable cfgRequireGoodITSLayer0123{"cfgRequireGoodITSLayer0123", false, "number of inactive chips on ITS layers 0-3 are below threshold "}; + Configurable cfgRequireGoodITSLayersAll{"cfgRequireGoodITSLayersAll", false, "number of inactive chips on all ITS layers are below threshold "}; + // for RCT + Configurable cfgRequireGoodRCT{"cfgRequireGoodRCT", false, "require good detector flag in run condtion table"}; + Configurable cfgRCTLabel{"cfgRCTLabel", "CBT_hadronPID", "select 1 [CBT, CBT_hadron, CBT_muon_glo] see O2Physics/Common/CCDB/RCTSelectionFlags.h"}; + Configurable cfgCheckZDC{"cfgCheckZDC", false, "set ZDC flag for PbPb"}; + Configurable cfgTreatLimitedAcceptanceAsBad{"cfgTreatLimitedAcceptanceAsBad", false, "reject all events where the detectors relevant for the specified Runlist are flagged as LimitedAcceptance"}; + } eventcuts; + + DielectronCut fDielectronCut; + struct : ConfigurableGroup { + std::string prefix = "dielectroncut_group"; + Configurable cfg_min_mass{"cfg_min_mass", 0.0, "min mass"}; + Configurable cfg_max_mass{"cfg_max_mass", 1e+10, "max mass"}; + Configurable cfg_min_pair_pt{"cfg_min_pair_pt", 0.0, "min pair pT"}; + Configurable cfg_max_pair_pt{"cfg_max_pair_pt", 1e+10, "max pair pT"}; + Configurable cfg_min_pair_y{"cfg_min_pair_y", -0.8, "min pair rapidity"}; + Configurable cfg_max_pair_y{"cfg_max_pair_y", +0.8, "max pair rapidity"}; + Configurable cfg_min_pair_dca3d{"cfg_min_pair_dca3d", 0.0, "min pair dca3d in sigma"}; + Configurable cfg_max_pair_dca3d{"cfg_max_pair_dca3d", 1e+10, "max pair dca3d in sigma"}; + Configurable cfg_apply_phiv{"cfg_apply_phiv", true, "flag to apply phiv cut"}; + Configurable cfg_phiv_slope{"cfg_phiv_slope", 0.0185, "slope for m vs. phiv"}; + Configurable cfg_phiv_intercept{"cfg_phiv_intercept", -0.0280, "intercept for m vs. phiv"}; + Configurable cfg_min_phiv{"cfg_min_phiv", 0.0, "min phiv (constant)"}; + Configurable cfg_max_phiv{"cfg_max_phiv", 3.2, "max phiv (constant)"}; + Configurable cfg_apply_detadphi{"cfg_apply_detadphi", false, "flag to apply deta-dphi elliptic cut"}; + Configurable cfg_min_deta{"cfg_min_deta", 0.02, "min deta between 2 electrons (elliptic cut)"}; + Configurable cfg_min_dphi{"cfg_min_dphi", 0.2, "min dphi between 2 electrons (elliptic cut)"}; + Configurable cfg_min_opang{"cfg_min_opang", 0.0, "min opening angle"}; + Configurable cfg_max_opang{"cfg_max_opang", 6.4, "max opening angle"}; + Configurable cfg_require_diff_sides{"cfg_require_diff_sides", false, "flag to require 2 tracks are from different sides."}; + + Configurable cfg_apply_cuts_from_prefilter{"cfg_apply_cuts_from_prefilter", false, "flag to apply prefilter set when producing derived data"}; + Configurable cfg_prefilter_bits{"cfg_prefilter_bits", 0, "prefilter bits [kNone : 0, kElFromPC : 1, kElFromPi0_1 : 2, kElFromPi0_2 : 4, kElFromPi0_3 : 8] Please consider logical-OR among them."}; // see PairUtilities.h + + Configurable cfg_apply_cuts_from_prefilter_derived{"cfg_apply_cuts_from_prefilter_derived", false, "flag to apply phiv cut inherited from prefilter"}; + Configurable cfg_prefilter_bits_derived{"cfg_prefilter_bits_derived", 0, "prefilter bits [kNone : 0, kMee : 1, kPhiV : 2, kSplitOrMergedTrackLS : 4, kSplitOrMergedTrackULS : 8] Please consider logical-OR among them."}; // see PairUtilities.h + + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -0.8, "max eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", +0.8, "max eta for single track"}; + Configurable cfg_min_phi_track{"cfg_min_phi_track", 0.f, "max phi for single track"}; + Configurable cfg_max_phi_track{"cfg_max_phi_track", 6.3, "max phi for single track"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 100, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_chi2tof{"cfg_max_chi2tof", 1e+10, "max chi2 TOF"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 0.2, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 0.2, "max dca Z for single track in cm"}; + Configurable cfg_require_itsib_any{"cfg_require_itsib_any", false, "flag to require ITS ib any hits"}; + Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; + Configurable cfg_min_its_cluster_size{"cfg_min_its_cluster_size", 0.f, "min ITS cluster size"}; + Configurable cfg_max_its_cluster_size{"cfg_max_its_cluster_size", 16.f, "max ITS cluster size"}; + Configurable cfg_min_p_its_cluster_size{"cfg_min_p_its_cluster_size", 0.0, "min p to apply ITS cluster size cut"}; + Configurable cfg_max_p_its_cluster_size{"cfg_max_p_its_cluster_size", 0.0, "max p to apply ITS cluster size cut"}; + Configurable cfg_min_rel_diff_pin{"cfg_min_rel_diff_pin", -1e+10, "min rel. diff. between pin and ppv"}; + Configurable cfg_max_rel_diff_pin{"cfg_max_rel_diff_pin", +1e+10, "max rel. diff. between pin and ppv"}; + + Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DielectronCut::PIDSchemes::kTPChadrejORTOFreq), "pid scheme [kTOFreq : 0, kTPChadrej : 1, kTPChadrejORTOFreq : 2, kTPConly : 3, kTOFif = 4, kPIDML = 5]"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + Configurable cfg_min_TPCNsigmaMu{"cfg_min_TPCNsigmaMu", -0.0, "min. TPC n sigma for muon exclusion"}; + Configurable cfg_max_TPCNsigmaMu{"cfg_max_TPCNsigmaMu", +0.0, "max. TPC n sigma for muon exclusion"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -1e+10, "min. TPC n sigma for pion exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +3.0, "max. TPC n sigma for pion exclusion"}; + Configurable cfg_min_TPCNsigmaKa{"cfg_min_TPCNsigmaKa", -3.0, "min. TPC n sigma for kaon exclusion"}; + Configurable cfg_max_TPCNsigmaKa{"cfg_max_TPCNsigmaKa", +3.0, "max. TPC n sigma for kaon exclusion"}; + Configurable cfg_min_TPCNsigmaPr{"cfg_min_TPCNsigmaPr", -3.0, "min. TPC n sigma for proton exclusion"}; + Configurable cfg_max_TPCNsigmaPr{"cfg_max_TPCNsigmaPr", +3.0, "max. TPC n sigma for proton exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; + Configurable cfg_max_pin_pirejTPC{"cfg_max_pin_pirejTPC", 1e+10, "max. pin for pion rejection in TPC"}; + Configurable cfg_min_ITSNsigmaKa{"cfg_min_ITSNsigmaKa", -1.0, "min. ITS n sigma for kaon exclusion"}; + Configurable cfg_max_ITSNsigmaKa{"cfg_max_ITSNsigmaKa", 1e+10, "max. ITS n sigma for kaon exclusion"}; + Configurable cfg_min_ITSNsigmaPr{"cfg_min_ITSNsigmaPr", -1.0, "min. ITS n sigma for proton exclusion"}; + Configurable cfg_max_ITSNsigmaPr{"cfg_max_ITSNsigmaPr", 1e+10, "max. ITS n sigma for proton exclusion"}; + Configurable cfg_min_p_ITSNsigmaKa{"cfg_min_p_ITSNsigmaKa", 0.0, "min p for kaon exclusion in ITS"}; + Configurable cfg_max_p_ITSNsigmaKa{"cfg_max_p_ITSNsigmaKa", 0.0, "max p for kaon exclusion in ITS"}; + Configurable cfg_min_p_ITSNsigmaPr{"cfg_min_p_ITSNsigmaPr", 0.0, "min p for proton exclusion in ITS"}; + Configurable cfg_max_p_ITSNsigmaPr{"cfg_max_p_ITSNsigmaPr", 0.0, "max p for proton exclusion in ITS"}; + Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; + + // configuration for PID ML + Configurable> onnxFileNames{"onnxFileNames", std::vector{"filename"}, "ONNX file names for each bin (if not from CCDB full path)"}; + Configurable> onnxPathsCCDB{"onnxPathsCCDB", std::vector{"path"}, "Paths of models on CCDB"}; + Configurable> binsMl{"binsMl", std::vector{-999999., 999999.}, "Bin limits for ML application"}; + Configurable> cutsMl{"cutsMl", std::vector{0.95}, "ML cuts per bin"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature"}, "Names of ML model input features"}; + Configurable nameBinningFeature{"nameBinningFeature", "pt", "Names of ML model binning feature"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + Configurable enableOptimizations{"enableOptimizations", false, "Enables the ONNX extended model-optimization: sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED)"}; + } dielectroncuts; + + DimuonCut fDimuonCut; + struct : ConfigurableGroup { + std::string prefix = "dimuoncut_group"; + Configurable cfg_min_mass{"cfg_min_mass", 0.0, "min mass"}; + Configurable cfg_max_mass{"cfg_max_mass", 1e+10, "max mass"}; + Configurable cfg_min_pair_pt{"cfg_min_pair_pt", 0.0, "min pair pt"}; + Configurable cfg_max_pair_pt{"cfg_max_pair_pt", 1e+10, "max pair pt"}; + Configurable cfg_min_pair_y{"cfg_min_pair_y", -4.0, "min pair rapidity"}; + Configurable cfg_max_pair_y{"cfg_max_pair_y", -2.5, "max pair rapidity"}; + Configurable cfg_min_pair_dcaxy{"cfg_min_pair_dcaxy", 0.0, "min pair dca3d in sigma"}; + Configurable cfg_max_pair_dcaxy{"cfg_max_pair_dcaxy", 1e+10, "max pair dca3d in sigma"}; + Configurable cfg_apply_detadphi{"cfg_apply_detadphi", false, "flag to apply deta-dphi elliptic cut"}; + Configurable cfg_min_deta{"cfg_min_deta", 0.02, "min deta between 2 muons (elliptic cut)"}; + Configurable cfg_min_dphi{"cfg_min_dphi", 0.02, "min dphi between 2 muons (elliptic cut)"}; + + Configurable cfg_track_type{"cfg_track_type", 3, "muon track type [0: MFT-MCH-MID, 3: MCH-MID]"}; + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -4.0, "min eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", -2.5, "max eta for single track"}; + Configurable cfg_min_phi_track{"cfg_min_phi_track", 0.f, "max phi for single track"}; + Configurable cfg_max_phi_track{"cfg_max_phi_track", 6.3, "max phi for single track"}; + Configurable cfg_min_ncluster_mft{"cfg_min_ncluster_mft", 5, "min ncluster MFT"}; + Configurable cfg_min_ncluster_mch{"cfg_min_ncluster_mch", 5, "min ncluster MCH"}; + Configurable cfg_max_chi2{"cfg_max_chi2", 1e+6, "max chi2"}; + Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 40, "max chi2 for MFT-MCH matching"}; + Configurable cfg_max_matching_chi2_mchmid{"cfg_max_matching_chi2_mchmid", 1e+10, "max chi2 for MCH-MID matching"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1e+10, "max dca XY for single track in cm"}; + Configurable cfg_min_rabs{"cfg_min_rabs", 17.6, "min Radius at the absorber end"}; + Configurable cfg_max_rabs{"cfg_max_rabs", 89.5, "max Radius at the absorber end"}; + Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; + } dimuoncuts; + + o2::aod::rctsel::RCTFlagsChecker rctChecker; + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + int mRunNumber; + float d_bz; + + struct : ConfigurableGroup { + std::string prefix = "mctrackcut_group"; + Configurable min_mcPt{"min_mcPt", 0.1, "min. MC pT for generated single lepton"}; + Configurable max_mcPt{"max_mcPt", 1e+10, "max. MC pT for generated single lepton"}; + Configurable min_mcEta{"min_mcEta", -0.8, "max. MC eta for generated single lepton"}; + Configurable max_mcEta{"max_mcEta", +0.8, "max. MC eta for generated single lepton"}; + } mctrackcuts; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view event_cut_types[2] = {"before/", "after/"}; + + ~DileptonMC() {} + + void addhistograms() + { + // event info + o2::aod::pwgem::dilepton::utils::eventhistogram::addEventHistograms(&fRegistry); + fRegistry.add("MCEvent/before/hZvtx", "mc vertex z; Z_{vtx} (cm)", kTH1F, {{100, -50, +50}}, false); + fRegistry.add("MCEvent/before/hZvtx_rec", "rec. mc vertex z; Z_{vtx} (cm)", kTH1F, {{100, -50, +50}}, false); + fRegistry.addClone("MCEvent/before/", "MCEvent/after/"); + + std::string mass_axis_title = "m_{ll} (GeV/c^{2})"; + std::string pair_pt_axis_title = "p_{T,ll} (GeV/c)"; + std::string pair_y_axis_title = "y_{ll}"; + std::string pair_dca_axis_title = "DCA_{ll} (#sigma)"; + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + mass_axis_title = "m_{ee} (GeV/c^{2})"; + pair_pt_axis_title = "p_{T,ee} (GeV/c)"; + pair_y_axis_title = "y_{ee}"; + pair_dca_axis_title = "DCA_{ee}^{3D} (#sigma)"; + if (cfgDCAType == 1) { + pair_dca_axis_title = "DCA_{ee}^{XY} (#sigma)"; + } else if (cfgDCAType == 2) { + pair_dca_axis_title = "DCA_{ee}^{Z} (#sigma)"; + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + mass_axis_title = "m_{#mu#mu} (GeV/c^{2})"; + pair_pt_axis_title = "p_{T,#mu#mu} (GeV/c)"; + pair_y_axis_title = "y_{#mu#mu}"; + pair_dca_axis_title = "DCA_{#mu#mu}^{XY} (#sigma)"; + } + + // pair info + const AxisSpec axis_mass{ConfMllBins, mass_axis_title}; + const AxisSpec axis_pt{ConfPtllBins, pair_pt_axis_title}; + const AxisSpec axis_y{ConfYllBins, pair_y_axis_title}; + const AxisSpec axis_dca{ConfDCAllBins, pair_dca_axis_title}; + const AxisSpec axis_pt_meson{ConfPtllBins, "p_{T} (GeV/c)"}; // for omega, phi meson pT spectra + const AxisSpec axis_y_meson{ConfYllBins, "y"}; // rapidity of meson + + const AxisSpec axis_dphi_ee{cfg_nbin_dphi_ee, -M_PI / 2., 3. / 2. * M_PI, "#Delta#varphi = #varphi_{l1} - #varphi_{l2} (rad.)"}; // for kHFll + const AxisSpec axis_deta_ee{cfg_nbin_deta_ee, -2., 2., "#Delta#eta = #eta_{l1} - #eta_{l2}"}; // for kHFll + const AxisSpec axis_cos_theta_cs{cfg_nbin_cos_theta_cs, 0.f, 1.f, "|cos(#theta_{CS})|"}; // for kPolarization, kUPC + const AxisSpec axis_phi_cs{cfg_nbin_phi_cs, 0.f, M_PI, "|#varphi_{CS}| (rad.)"}; // for kPolarization + const AxisSpec axis_aco{cfg_nbin_aco, 0, 1.f, "#alpha = 1 - #frac{|#varphi_{l^{+}} - #varphi_{l^{-}}|}{#pi}"}; // for kUPC + const AxisSpec axis_asym_pt{cfg_nbin_asym_pt, 0, 1.f, "A = #frac{|p_{T,l^{+}} - p_{T,l^{-}}|}{|p_{T,l^{+}} + p_{T,l^{-}}|}"}; // for kUPC + const AxisSpec axis_dphi_e_ee{cfg_nbin_dphi_e_ee, 0, M_PI, "#Delta#varphi = #varphi_{l} - #varphi_{ll} (rad.)"}; // for kUPC + + // generated info + fRegistry.add("Generated/sm/PromptPi0/hs", "gen. dilepton signal", kTHnSparseD, {axis_mass, axis_pt, axis_y, axis_dphi_ee, axis_deta_ee, axis_cos_theta_cs, axis_phi_cs, axis_aco, axis_asym_pt, axis_dphi_e_ee}, true); + fRegistry.addClone("Generated/sm/PromptPi0/", "Generated/sm/NonPromptPi0/"); + fRegistry.addClone("Generated/sm/PromptPi0/", "Generated/sm/Eta/"); + fRegistry.addClone("Generated/sm/PromptPi0/", "Generated/sm/EtaPrime/"); + fRegistry.addClone("Generated/sm/PromptPi0/", "Generated/sm/Rho/"); + fRegistry.addClone("Generated/sm/PromptPi0/", "Generated/sm/Omega/"); + fRegistry.addClone("Generated/sm/PromptPi0/", "Generated/sm/Omega2ll/"); + fRegistry.addClone("Generated/sm/PromptPi0/", "Generated/sm/Phi/"); + fRegistry.addClone("Generated/sm/PromptPi0/", "Generated/sm/Phi2ll/"); + fRegistry.addClone("Generated/sm/PromptPi0/", "Generated/sm/PromptJPsi/"); + fRegistry.addClone("Generated/sm/PromptPi0/", "Generated/sm/NonPromptJPsi/"); + fRegistry.addClone("Generated/sm/PromptPi0/", "Generated/sm/PromptPsi2S/"); + fRegistry.addClone("Generated/sm/PromptPi0/", "Generated/sm/NonPromptPsi2S/"); + fRegistry.add("Generated/sm/Omega2ll/hPtY", "pT of #omega meson", kTH2F, {axis_y_meson, axis_pt_meson}, true); + fRegistry.add("Generated/sm/Phi2ll/hPtY", "pT of #phi meson", kTH2F, {axis_y_meson, axis_pt_meson}, true); + + fRegistry.add("Generated/ccbar/c2l_c2l/hadron_hadron/hs", "generated dilepton signal", kTHnSparseD, {axis_mass, axis_pt, axis_y, axis_dphi_ee, axis_deta_ee, axis_cos_theta_cs, axis_phi_cs, axis_aco, axis_asym_pt, axis_dphi_e_ee}, true); + fRegistry.addClone("Generated/ccbar/c2l_c2l/hadron_hadron/", "Generated/ccbar/c2l_c2l/meson_meson/"); + fRegistry.addClone("Generated/ccbar/c2l_c2l/hadron_hadron/", "Generated/ccbar/c2l_c2l/baryon_baryon/"); + fRegistry.addClone("Generated/ccbar/c2l_c2l/hadron_hadron/", "Generated/ccbar/c2l_c2l/meson_baryon/"); + fRegistry.addClone("Generated/ccbar/c2l_c2l/", "Generated/bbbar/b2l_b2l/"); + fRegistry.addClone("Generated/ccbar/c2l_c2l/", "Generated/bbbar/b2c2l_b2c2l/"); + fRegistry.addClone("Generated/ccbar/c2l_c2l/", "Generated/bbbar/b2c2l_b2l_sameb/"); + fRegistry.addClone("Generated/ccbar/c2l_c2l/", "Generated/bbbar/b2c2l_b2l_diffb/"); // LS + + // for charmed hadrons // create 28 combinations + static constexpr std::string_view charmed_mesons[] = {"Dplus", "D0", "Dsplus"}; // 411, 421, 431 + static constexpr std::string_view anti_charmed_mesons[] = {"Dminus", "D0bar", "Dsminus"}; + const int nm = sizeof(charmed_mesons) / sizeof(charmed_mesons[0]); + static constexpr std::string_view charmed_baryons[] = {"Lcplus", "Xicplus", "Xic0", "Omegac0"}; // 4122, 4232, 4132, 4332 + static constexpr std::string_view anti_charmed_baryons[] = {"Lcminus", "Xicminus", "Xic0bar", "Omegac0bar"}; + const int nb = sizeof(charmed_baryons) / sizeof(charmed_baryons[0]); + static constexpr std::string_view sum_charmed_mesons[] = {"Dpm", "D0", "Dspm"}; + static constexpr std::string_view sum_charmed_baryons[] = {"Lcpm", "Xicpm", "Xic0", "Omegac0"}; + + for (int im = 0; im < nm; im++) { + fRegistry.addClone("Generated/ccbar/c2l_c2l/hadron_hadron/", Form("Generated/ccbar/c2l_c2l/%s_%s/", charmed_mesons[im].data(), anti_charmed_mesons[im].data())); + } + for (int ib = 0; ib < nb; ib++) { + fRegistry.addClone("Generated/ccbar/c2l_c2l/hadron_hadron/", Form("Generated/ccbar/c2l_c2l/%s_%s/", charmed_baryons[ib].data(), anti_charmed_baryons[ib].data())); + } + for (int im1 = 0; im1 < nm - 1; im1++) { + for (int im2 = im1 + 1; im2 < nm; im2++) { + fRegistry.addClone("Generated/ccbar/c2l_c2l/hadron_hadron/", Form("Generated/ccbar/c2l_c2l/%s_%s/", sum_charmed_mesons[im1].data(), sum_charmed_mesons[im2].data())); + } + } + for (int ib1 = 0; ib1 < nb - 1; ib1++) { + for (int ib2 = ib1 + 1; ib2 < nb; ib2++) { + fRegistry.addClone("Generated/ccbar/c2l_c2l/hadron_hadron/", Form("Generated/ccbar/c2l_c2l/%s_%s/", sum_charmed_baryons[ib1].data(), sum_charmed_baryons[ib2].data())); + } + } + for (int im = 0; im < nm; im++) { + for (int ib = 0; ib < nb; ib++) { + fRegistry.addClone("Generated/ccbar/c2l_c2l/hadron_hadron/", Form("Generated/ccbar/c2l_c2l/%s_%s/", sum_charmed_mesons[im].data(), sum_charmed_baryons[ib].data())); + } + } + + // reconstructed pair info + fRegistry.add("Pair/sm/Photon/hs", "rec. dilepton signal", kTHnSparseD, {axis_mass, axis_pt, axis_y, axis_dphi_ee, axis_deta_ee, axis_cos_theta_cs, axis_phi_cs, axis_aco, axis_asym_pt, axis_dphi_e_ee, axis_dca}, true); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/PromptPi0/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/NonPromptPi0/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Eta/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/EtaPrime/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Rho/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Omega/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Omega2ll/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Phi/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Phi2ll/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/PromptJPsi/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/NonPromptJPsi/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/PromptPsi2S/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/NonPromptPsi2S/"); + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + fRegistry.add("Pair/sm/Photon/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0, M_PI}, {100, 0.0f, 1.0f}}, true); + fRegistry.add("Pair/sm/Photon/hMvsRxy", "m_{ee} vs. r_{xy};r_{xy}^{true} (cm);m_{ee} (GeV/c^{2})", kTH2F, {{100, 0, 100}, {100, 0.0f, 1.0f}}, true); + fRegistry.add("Pair/sm/PromptPi0/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0, M_PI}, {100, 0.0f, 1.0f}}, true); + fRegistry.add("Pair/sm/NonPromptPi0/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0, M_PI}, {100, 0.0f, 1.0f}}, true); + } + + fRegistry.add("Pair/ccbar/c2l_c2l/hadron_hadron/hs", "hs pair", kTHnSparseD, {axis_mass, axis_pt, axis_y, axis_dphi_ee, axis_deta_ee, axis_cos_theta_cs, axis_phi_cs, axis_aco, axis_asym_pt, axis_dphi_e_ee, axis_dca}, true); + fRegistry.addClone("Pair/ccbar/c2l_c2l/hadron_hadron/", "Pair/ccbar/c2l_c2l/meson_meson/"); + fRegistry.addClone("Pair/ccbar/c2l_c2l/hadron_hadron/", "Pair/ccbar/c2l_c2l/baryon_baryon/"); + fRegistry.addClone("Pair/ccbar/c2l_c2l/hadron_hadron/", "Pair/ccbar/c2l_c2l/meson_baryon/"); + fRegistry.addClone("Pair/ccbar/c2l_c2l/", "Pair/bbbar/b2l_b2l/"); + fRegistry.addClone("Pair/ccbar/c2l_c2l/", "Pair/bbbar/b2c2l_b2c2l/"); + fRegistry.addClone("Pair/ccbar/c2l_c2l/", "Pair/bbbar/b2c2l_b2l_sameb/"); + fRegistry.addClone("Pair/ccbar/c2l_c2l/", "Pair/bbbar/b2c2l_b2l_diffb/"); // LS + + for (int im = 0; im < nm; im++) { + fRegistry.addClone("Pair/ccbar/c2l_c2l/hadron_hadron/", Form("Pair/ccbar/c2l_c2l/%s_%s/", charmed_mesons[im].data(), anti_charmed_mesons[im].data())); + } + for (int ib = 0; ib < nb; ib++) { + fRegistry.addClone("Pair/ccbar/c2l_c2l/hadron_hadron/", Form("Pair/ccbar/c2l_c2l/%s_%s/", charmed_baryons[ib].data(), anti_charmed_baryons[ib].data())); + } + for (int im1 = 0; im1 < nm - 1; im1++) { + for (int im2 = im1 + 1; im2 < nm; im2++) { + fRegistry.addClone("Pair/ccbar/c2l_c2l/hadron_hadron/", Form("Pair/ccbar/c2l_c2l/%s_%s/", sum_charmed_mesons[im1].data(), sum_charmed_mesons[im2].data())); + } + } + for (int ib1 = 0; ib1 < nb - 1; ib1++) { + for (int ib2 = ib1 + 1; ib2 < nb; ib2++) { + fRegistry.addClone("Pair/ccbar/c2l_c2l/hadron_hadron/", Form("Pair/ccbar/c2l_c2l/%s_%s/", sum_charmed_baryons[ib1].data(), sum_charmed_baryons[ib2].data())); + } + } + for (int im = 0; im < nm; im++) { + for (int ib = 0; ib < nb; ib++) { + fRegistry.addClone("Pair/ccbar/c2l_c2l/hadron_hadron/", Form("Pair/ccbar/c2l_c2l/%s_%s/", sum_charmed_mesons[im].data(), sum_charmed_baryons[ib].data())); + } + } + + // for correlated bkg due to mis-identified hadrons, and true combinatorial bkg + fRegistry.add("Pair/corr_bkg_lh/uls/hs", "rec. bkg", kTHnSparseD, {axis_mass, axis_pt, axis_y, axis_dphi_ee, axis_deta_ee, axis_cos_theta_cs, axis_phi_cs, axis_aco, axis_asym_pt, axis_dphi_e_ee, axis_dca}, true); + fRegistry.addClone("Pair/corr_bkg_lh/uls/", "Pair/corr_bkg_lh/lspp/"); + fRegistry.addClone("Pair/corr_bkg_lh/uls/", "Pair/corr_bkg_lh/lsmm/"); + fRegistry.addClone("Pair/corr_bkg_lh/", "Pair/corr_bkg_hh/"); + fRegistry.addClone("Pair/corr_bkg_lh/", "Pair/comb_bkg/"); + + if (cfgFillUnfolding) { + // for 2D unfolding + const AxisSpec axis_mass_gen{ConfMllBins, "m_{ll}^{gen} (GeV/c^{2})"}; + const AxisSpec axis_pt_gen{ConfPtllBins, "p_{T,ll}^{gen} (GeV/c)"}; + const AxisSpec axis_mass_rec{ConfMllBins, "m_{ll}^{rec} (GeV/c^{2})"}; + const AxisSpec axis_pt_rec{ConfPtllBins, "p_{T,ll}^{rec} (GeV/c)"}; + fRegistry.add("Unfold/lf/hsRM", "response matrix for unfolding", kTHnSparseD, {axis_mass_gen, axis_pt_gen, axis_mass_rec, axis_pt_rec}, true); + fRegistry.add("Unfold/lf/hMiss", "missing dilepton for unfolding", kTH2D, {axis_mass_gen, axis_pt_gen}, true); // e.g. true eta is in acceptance, but reconstructed eta is out of acceptance. + fRegistry.add("Unfold/lf/hFake", "fake dilepton for unfolding", kTH2D, {axis_mass_rec, axis_pt_rec}, true); // e.g. true eta is out of acceptance, but reconstructed eta is in acceptance. + fRegistry.addClone("Unfold/lf/", "Unfold/PromptJPsi/"); + fRegistry.addClone("Unfold/lf/", "Unfold/NonPromptJPsi/"); + fRegistry.addClone("Unfold/lf/", "Unfold/PromptPsi2S/"); + fRegistry.addClone("Unfold/lf/", "Unfold/NonPromptPsi2S/"); + fRegistry.addClone("Unfold/lf/", "Unfold/ccbar_uls/"); + fRegistry.addClone("Unfold/lf/", "Unfold/bbbar_uls/"); + fRegistry.addClone("Unfold/lf/", "Unfold/bbbar_ls/"); + } + } + + float beamM1 = o2::constants::physics::MassProton; // mass of beam + float beamM2 = o2::constants::physics::MassProton; // mass of beam + float beamE1 = 0.f; // beam energy + float beamE2 = 0.f; // beam energy + float beamP1 = 0.f; // beam momentum + float beamP2 = 0.f; // beam momentum + + float leptonM1 = 0.f; + float leptonM2 = 0.f; + int pdg_lepton = 0; + void init(InitContext&) + { + if (doprocessAnalysis && doprocessAnalysis_Smeared) { + LOGF(fatal, "Cannot enable doprocessAnalysis and doprocessAnalysis_Smeared at the same time. Please choose one."); + } + + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + rctChecker.init(eventcuts.cfgRCTLabel.value, eventcuts.cfgCheckZDC.value, eventcuts.cfgTreatLimitedAcceptanceAsBad.value); + + DefineEMEventCut(); + addhistograms(); + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + DefineDielectronCut(); + leptonM1 = o2::constants::physics::MassElectron; + leptonM2 = o2::constants::physics::MassElectron; + pdg_lepton = 11; + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + DefineDimuonCut(); + leptonM1 = o2::constants::physics::MassMuon; + leptonM2 = o2::constants::physics::MassMuon; + pdg_lepton = 13; + } + if (doprocessNorm) { + fRegistry.addClone("Event/before/hCollisionCounter", "Event/norm/hCollisionCounter"); + } + if (doprocessBC) { + auto hTVXCounter = fRegistry.add("BC/hTVXCounter", "TVX counter", kTH1D, {{6, -0.5f, 5.5f}}); + hTVXCounter->GetXaxis()->SetBinLabel(1, "TVX"); + hTVXCounter->GetXaxis()->SetBinLabel(2, "TVX && NoTFB"); + hTVXCounter->GetXaxis()->SetBinLabel(3, "TVX && NoITSROFB"); + hTVXCounter->GetXaxis()->SetBinLabel(4, "TVX && GoodRCT"); + hTVXCounter->GetXaxis()->SetBinLabel(5, "TVX && NoTFB && NoITSROFB"); + hTVXCounter->GetXaxis()->SetBinLabel(6, "TVX && NoTFB && NoITSROFB && GoodRCT"); + } + } + + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (std::fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + o2::base::Propagator::initFieldFromGRP(&grpmag); + mRunNumber = collision.runNumber(); + return; + } + + auto run3grp_timestamp = collision.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = collision.runNumber(); + + //// for muon + // o2::base::Propagator::initFieldFromGRP(grpmag); + // if (!o2::base::GeometryManager::isGeometryLoaded()) { + // ccdb->get(geoPath); + // } + // o2::mch::TrackExtrap::setField(); + + auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", collision.timestamp()); + int beamZ1 = grplhcif->getBeamZ(o2::constants::lhc::BeamC); + int beamZ2 = grplhcif->getBeamZ(o2::constants::lhc::BeamA); + int beamA1 = grplhcif->getBeamA(o2::constants::lhc::BeamC); + int beamA2 = grplhcif->getBeamA(o2::constants::lhc::BeamA); + beamE1 = grplhcif->getBeamEnergyPerNucleonInGeV(o2::constants::lhc::BeamC); + beamE2 = grplhcif->getBeamEnergyPerNucleonInGeV(o2::constants::lhc::BeamA); + beamM1 = o2::constants::physics::MassProton * beamA1; + beamM2 = o2::constants::physics::MassProton * beamA2; + beamP1 = std::sqrt(std::pow(beamE1, 2) - std::pow(beamM1, 2)); + beamP2 = std::sqrt(std::pow(beamE2, 2) - std::pow(beamM2, 2)); + LOGF(info, "beamZ1 = %d, beamZ2 = %d, beamA1 = %d, beamA2 = %d, beamE1 = %f (GeV), beamE2 = %f (GeV), beamM1 = %f (GeV), beamM2 = %f (GeV), beamP1 = %f (GeV), beamP2 = %f (GeV)", beamZ1, beamZ2, beamA1, beamA2, beamE1, beamE2, beamM1, beamM2, beamP1, beamP2); + } + + void DefineEMEventCut() + { + fEMEventCut = EMEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(eventcuts.cfgZvtxMin, eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireNoCollInTimeRangeStandard(eventcuts.cfgRequireNoCollInTimeRangeStandard); + fEMEventCut.SetRequireNoCollInTimeRangeStrict(eventcuts.cfgRequireNoCollInTimeRangeStrict); + fEMEventCut.SetRequireNoCollInITSROFStandard(eventcuts.cfgRequireNoCollInITSROFStandard); + fEMEventCut.SetRequireNoCollInITSROFStrict(eventcuts.cfgRequireNoCollInITSROFStrict); + fEMEventCut.SetRequireNoHighMultCollInPrevRof(eventcuts.cfgRequireNoHighMultCollInPrevRof); + fEMEventCut.SetRequireGoodITSLayer3(eventcuts.cfgRequireGoodITSLayer3); + fEMEventCut.SetRequireGoodITSLayer0123(eventcuts.cfgRequireGoodITSLayer0123); + fEMEventCut.SetRequireGoodITSLayersAll(eventcuts.cfgRequireGoodITSLayersAll); + } + + o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; + void DefineDielectronCut() + { + fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); + + // for pair + fDielectronCut.SetMeeRange(dielectroncuts.cfg_min_mass, dielectroncuts.cfg_max_mass); + fDielectronCut.SetPairPtRange(dielectroncuts.cfg_min_pair_pt, dielectroncuts.cfg_max_pair_pt); + fDielectronCut.SetPairYRange(dielectroncuts.cfg_min_pair_y, dielectroncuts.cfg_max_pair_y); + fDielectronCut.SetPairDCARange(dielectroncuts.cfg_min_pair_dca3d, dielectroncuts.cfg_max_pair_dca3d); // in sigma + fDielectronCut.SetMaxMeePhiVDep([&](float phiv) { return dielectroncuts.cfg_phiv_intercept + phiv * dielectroncuts.cfg_phiv_slope; }, dielectroncuts.cfg_min_phiv, dielectroncuts.cfg_max_phiv); + fDielectronCut.ApplyPhiV(dielectroncuts.cfg_apply_phiv); + fDielectronCut.SetMindEtadPhi(dielectroncuts.cfg_apply_detadphi, dielectroncuts.cfg_min_deta, dielectroncuts.cfg_min_dphi); + fDielectronCut.SetPairOpAng(dielectroncuts.cfg_min_opang, dielectroncuts.cfg_max_opang); + fDielectronCut.SetRequireDifferentSides(dielectroncuts.cfg_require_diff_sides); + + // for track + fDielectronCut.SetTrackPtRange(dielectroncuts.cfg_min_pt_track, dielectroncuts.cfg_max_pt_track); + fDielectronCut.SetTrackEtaRange(-dielectroncuts.cfg_max_eta_track, +dielectroncuts.cfg_max_eta_track); + fDielectronCut.SetTrackPhiRange(-dielectroncuts.cfg_max_phi_track, +dielectroncuts.cfg_max_phi_track); + fDielectronCut.SetMinNClustersTPC(dielectroncuts.cfg_min_ncluster_tpc); + fDielectronCut.SetMinNCrossedRowsTPC(dielectroncuts.cfg_min_ncrossedrows); + fDielectronCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fDielectronCut.SetMaxFracSharedClustersTPC(dielectroncuts.cfg_max_frac_shared_clusters_tpc); + fDielectronCut.SetChi2PerClusterTPC(0.0, dielectroncuts.cfg_max_chi2tpc); + fDielectronCut.SetChi2PerClusterITS(0.0, dielectroncuts.cfg_max_chi2its); + fDielectronCut.SetNClustersITS(dielectroncuts.cfg_min_ncluster_its, 7); + fDielectronCut.SetMeanClusterSizeITS(dielectroncuts.cfg_min_its_cluster_size, dielectroncuts.cfg_max_its_cluster_size, dielectroncuts.cfg_min_p_its_cluster_size, dielectroncuts.cfg_max_p_its_cluster_size); + fDielectronCut.SetTrackMaxDcaXY(dielectroncuts.cfg_max_dcaxy); + fDielectronCut.SetTrackMaxDcaZ(dielectroncuts.cfg_max_dcaz); + fDielectronCut.RequireITSibAny(dielectroncuts.cfg_require_itsib_any); + fDielectronCut.RequireITSib1st(dielectroncuts.cfg_require_itsib_1st); + fDielectronCut.SetChi2TOF(0.0, dielectroncuts.cfg_max_chi2tof); + fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); + + // for eID + fDielectronCut.SetPIDScheme(dielectroncuts.cfg_pid_scheme); + fDielectronCut.SetTPCNsigmaElRange(dielectroncuts.cfg_min_TPCNsigmaEl, dielectroncuts.cfg_max_TPCNsigmaEl); + fDielectronCut.SetTPCNsigmaMuRange(dielectroncuts.cfg_min_TPCNsigmaMu, dielectroncuts.cfg_max_TPCNsigmaMu); + fDielectronCut.SetTPCNsigmaPiRange(dielectroncuts.cfg_min_TPCNsigmaPi, dielectroncuts.cfg_max_TPCNsigmaPi); + fDielectronCut.SetTPCNsigmaKaRange(dielectroncuts.cfg_min_TPCNsigmaKa, dielectroncuts.cfg_max_TPCNsigmaKa); + fDielectronCut.SetTPCNsigmaPrRange(dielectroncuts.cfg_min_TPCNsigmaPr, dielectroncuts.cfg_max_TPCNsigmaPr); + fDielectronCut.SetTOFNsigmaElRange(dielectroncuts.cfg_min_TOFNsigmaEl, dielectroncuts.cfg_max_TOFNsigmaEl); + fDielectronCut.SetMaxPinForPionRejectionTPC(dielectroncuts.cfg_max_pin_pirejTPC); + fDielectronCut.SetITSNsigmaKaRange(dielectroncuts.cfg_min_ITSNsigmaKa, dielectroncuts.cfg_max_ITSNsigmaKa); + fDielectronCut.SetITSNsigmaPrRange(dielectroncuts.cfg_min_ITSNsigmaPr, dielectroncuts.cfg_max_ITSNsigmaPr); + fDielectronCut.SetPRangeForITSNsigmaKa(dielectroncuts.cfg_min_p_ITSNsigmaKa, dielectroncuts.cfg_max_p_ITSNsigmaKa); + fDielectronCut.SetPRangeForITSNsigmaPr(dielectroncuts.cfg_min_p_ITSNsigmaPr, dielectroncuts.cfg_max_p_ITSNsigmaPr); + + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { // please call this at the end of DefineDileptonCut + static constexpr int nClassesMl = 2; + const std::vector cutDirMl = {o2::cuts_ml::CutSmaller, o2::cuts_ml::CutNot}; + const std::vector labelsClasses = {"Signal", "Background"}; + const uint32_t nBinsMl = dielectroncuts.binsMl.value.size() - 1; + const std::vector labelsBins(nBinsMl, "bin"); + double cutsMlArr[nBinsMl][nClassesMl]; + for (uint32_t i = 0; i < nBinsMl; i++) { + cutsMlArr[i][0] = dielectroncuts.cutsMl.value[i]; + cutsMlArr[i][1] = 0.; + } + o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; + + mlResponseSingleTrack.configure(dielectroncuts.binsMl.value, cutsMl, cutDirMl, nClassesMl); + if (dielectroncuts.loadModelsFromCCDB) { + ccdbApi.init(ccdburl); + mlResponseSingleTrack.setModelPathsCCDB(dielectroncuts.onnxFileNames.value, ccdbApi, dielectroncuts.onnxPathsCCDB.value, dielectroncuts.timestampCCDB.value); + } else { + mlResponseSingleTrack.setModelPathsLocal(dielectroncuts.onnxFileNames.value); + } + mlResponseSingleTrack.cacheInputFeaturesIndices(dielectroncuts.namesInputFeatures); + mlResponseSingleTrack.cacheBinningIndex(dielectroncuts.nameBinningFeature); + mlResponseSingleTrack.init(dielectroncuts.enableOptimizations.value); + + fDielectronCut.SetPIDMlResponse(&mlResponseSingleTrack); + } // end of PID ML + } + + void DefineDimuonCut() + { + fDimuonCut = DimuonCut("fDimuonCut", "fDimuonCut"); + + // for pair + fDimuonCut.SetMassRange(dimuoncuts.cfg_min_mass, dimuoncuts.cfg_max_mass); + fDimuonCut.SetPairPtRange(dimuoncuts.cfg_min_pair_pt, dimuoncuts.cfg_max_pair_pt); + fDimuonCut.SetPairYRange(dimuoncuts.cfg_min_pair_y, dimuoncuts.cfg_max_pair_y); + fDimuonCut.SetPairDCAxyRange(dimuoncuts.cfg_min_pair_dcaxy, dimuoncuts.cfg_max_pair_dcaxy); // DCAxy in cm + fDimuonCut.SetMindEtadPhi(dimuoncuts.cfg_apply_detadphi, dimuoncuts.cfg_min_deta, dimuoncuts.cfg_min_dphi); + + // for track + fDimuonCut.SetTrackType(dimuoncuts.cfg_track_type); + fDimuonCut.SetTrackPtRange(dimuoncuts.cfg_min_pt_track, dimuoncuts.cfg_max_pt_track); + fDimuonCut.SetTrackEtaRange(dimuoncuts.cfg_min_eta_track, dimuoncuts.cfg_max_eta_track); + fDimuonCut.SetTrackPhiRange(dimuoncuts.cfg_min_phi_track, dimuoncuts.cfg_max_phi_track); + fDimuonCut.SetNClustersMFT(dimuoncuts.cfg_min_ncluster_mft, 10); + fDimuonCut.SetNClustersMCHMID(dimuoncuts.cfg_min_ncluster_mch, 16); + fDimuonCut.SetChi2(0.f, dimuoncuts.cfg_max_chi2); + fDimuonCut.SetMatchingChi2MCHMFT(0.f, dimuoncuts.cfg_max_matching_chi2_mftmch); + fDimuonCut.SetMatchingChi2MCHMID(0.f, dimuoncuts.cfg_max_matching_chi2_mchmid); + fDimuonCut.SetDCAxy(0.f, dimuoncuts.cfg_max_dcaxy); + fDimuonCut.SetRabs(dimuoncuts.cfg_min_rabs, dimuoncuts.cfg_max_rabs); + fDimuonCut.SetMaxPDCARabsDep([&](float rabs) { return (rabs < 26.5 ? 594.f : 324.f); }); + } + + template + int FindLF(TTrack const& posmc, TTrack const& negmc, TMCParticles const& mcparticles) + { + int arr[] = { + FindCommonMotherFrom2Prongs(posmc, negmc, -pdg_lepton, pdg_lepton, 22, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -pdg_lepton, pdg_lepton, 111, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -pdg_lepton, pdg_lepton, 221, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -pdg_lepton, pdg_lepton, 331, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -pdg_lepton, pdg_lepton, 113, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -pdg_lepton, pdg_lepton, 223, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -pdg_lepton, pdg_lepton, 333, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -pdg_lepton, pdg_lepton, 443, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -pdg_lepton, pdg_lepton, 100443, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -pdg_lepton, pdg_lepton, 553, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -pdg_lepton, pdg_lepton, 100553, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -pdg_lepton, pdg_lepton, 200553, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -pdg_lepton, pdg_lepton, 300553, mcparticles)}; + int size = sizeof(arr) / sizeof(*arr); + int max = *std::max_element(arr, arr + size); + return max; + } + + template + bool isInAcceptance(T const& lepton) + { + float pt = 0.f, eta = 0.f; + if constexpr (isSmeared) { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + pt = lepton.ptSmeared(); + eta = lepton.etaSmeared(); + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (dimuoncuts.cfg_track_type == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + pt = lepton.ptSmeared_sa_muon(); + eta = lepton.etaSmeared_sa_muon(); + } else if (dimuoncuts.cfg_track_type == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + pt = lepton.ptSmeared_gl_muon(); + eta = lepton.etaSmeared_gl_muon(); + } else { + pt = lepton.pt(); + eta = lepton.eta(); + } + } + } else { + pt = lepton.pt(); + eta = lepton.eta(); + } + + if ((mctrackcuts.min_mcPt < pt && pt < mctrackcuts.max_mcPt) && (mctrackcuts.min_mcEta < eta && eta < mctrackcuts.max_mcEta)) { + return true; + } else { + return false; + } + } + + template + bool fillTruePairInfo(TCollision const& collision, TMCCollisions const&, TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TAllTracks const& tracks, TMCParticles const& mcparticles) + { + auto t1mc = mcparticles.iteratorAt(t1.emmcparticleId()); + auto t2mc = mcparticles.iteratorAt(t2.emmcparticleId()); + bool is_pair_from_same_mcevent = (t1mc.emmceventId() == t2mc.emmceventId()); + + auto mccollision1 = t1mc.template emmcevent_as(); + auto mccollision2 = t2mc.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision1.getSubGeneratorId() != cfgEventGeneratorType) { + return false; + } + if (cfgEventGeneratorType >= 0 && mccollision2.getSubGeneratorId() != cfgEventGeneratorType) { + return false; + } + if (!isInAcceptance(t1mc) || !isInAcceptance(t2mc)) { + return false; + } + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { + if (!cut.template IsSelectedTrack(t1, collision) || !cut.template IsSelectedTrack(t2, collision)) { + return false; + } + } else { // cut-based + if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { + return false; + } + } + if (!cut.IsSelectedPair(t1, t2, d_bz)) { + return false; + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { + return false; + } + + if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t1, cut, tracks)) { + return false; + } + if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t2, cut, tracks)) { + return false; + } + + if (!cut.IsSelectedPair(t1, t2)) { + return false; + } + } + + float pt1 = 0.f, eta1 = 0.f, phi1 = 0.f, pt2 = 0.f, eta2 = 0.f, phi2 = 0.f; + if constexpr (isSmeared) { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + pt1 = t1mc.ptSmeared(); + eta1 = t1mc.etaSmeared(); + phi1 = t1mc.phiSmeared(); + pt2 = t2mc.ptSmeared(); + eta2 = t2mc.etaSmeared(); + phi2 = t2mc.phiSmeared(); + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (dimuoncuts.cfg_track_type == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + pt1 = t1mc.ptSmeared_sa_muon(); + eta1 = t1mc.etaSmeared_sa_muon(); + phi1 = t1mc.phiSmeared_sa_muon(); + pt2 = t2mc.ptSmeared_sa_muon(); + eta2 = t2mc.etaSmeared_sa_muon(); + phi2 = t2mc.phiSmeared_sa_muon(); + } else if (dimuoncuts.cfg_track_type == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + pt1 = t1mc.ptSmeared_gl_muon(); + eta1 = t1mc.etaSmeared_gl_muon(); + phi1 = t1mc.phiSmeared_gl_muon(); + pt2 = t2mc.ptSmeared_gl_muon(); + eta2 = t2mc.etaSmeared_gl_muon(); + phi2 = t2mc.phiSmeared_gl_muon(); + } else { + pt1 = t1mc.pt(); + eta1 = t1mc.eta(); + phi1 = t1mc.phi(); + pt2 = t2mc.pt(); + eta2 = t2mc.eta(); + phi2 = t2mc.phi(); + } + } + } else { + pt1 = t1mc.pt(); + eta1 = t1mc.eta(); + phi1 = t1mc.phi(); + pt2 = t2mc.pt(); + eta2 = t2mc.eta(); + phi2 = t2mc.phi(); + } + + ROOT::Math::PtEtaPhiMVector v1mc(pt1, eta1, phi1, leptonM1); + ROOT::Math::PtEtaPhiMVector v2mc(pt2, eta2, phi2, leptonM2); + ROOT::Math::PtEtaPhiMVector v12mc = v1mc + v2mc; + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (v12mc.Rapidity() < dielectroncuts.cfg_min_pair_y || dielectroncuts.cfg_max_pair_y < v12mc.Rapidity()) { + return false; + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (v12mc.Rapidity() < dimuoncuts.cfg_min_pair_y || dimuoncuts.cfg_max_pair_y < v12mc.Rapidity()) { + return false; + } + } + + float weight = 1.f; + if (cfgApplyWeightTTCA) { + weight = map_weight[std::make_pair(t1.globalIndex(), t2.globalIndex())]; + } + // LOGF(info, "t1.sign() = %d, t2.sign() = %d, map_weight[std::make_pair(%d, %d)] = %f", t1.sign(), t2.sign(), t1.globalIndex(), t2.globalIndex(), weight); + + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), leptonM1); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), leptonM2); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + + float pair_dca = 999.f; + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + pair_dca = pairDCAQuadSum(dca3DinSigma(t1), dca3DinSigma(t2)); + if (cfgDCAType == 1) { + pair_dca = pairDCAQuadSum(dcaXYinSigma(t1), dcaXYinSigma(t2)); + } else if (cfgDCAType == 2) { + pair_dca = pairDCAQuadSum(dcaZinSigma(t1), dcaZinSigma(t2)); + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + pair_dca = pairDCAQuadSum(fwdDcaXYinSigma(t1), fwdDcaXYinSigma(t2)); + } + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), d_bz); + + float deta = v1.Eta() - v2.Eta(); + float dphi = v1.Phi() - v2.Phi(); + o2::math_utils::bringToPMPi(dphi); + + float aco = 1.f - std::fabs(dphi) / M_PI; + float asym = std::fabs(v1.Pt() - v2.Pt()) / (v1.Pt() + v2.Pt()); + float dphi_e_ee = v1.Phi() - v12.Phi(); + o2::math_utils::bringToPMPi(dphi_e_ee); + dphi = RecoDecay::constrainAngle(dphi, -o2::constants::math::PIHalf, 1); // shift dphi in [-pi/2, +3pi/2] rad. + + float cos_thetaCS = 999, phiCS = 999.f; + o2::aod::pwgem::dilepton::utils::pairutil::getAngleCS(t1, t2, leptonM1, leptonM2, beamE1, beamE2, beamP1, beamP2, cos_thetaCS, phiCS); + o2::math_utils::bringToPMPi(phiCS); + + if ((FindCommonMotherFrom2ProngsWithoutPDG(t1mc, t2mc) > 0 || IsHF(t1mc, t2mc, mcparticles) > 0) && is_pair_from_same_mcevent) { // for bkg study + if (std::abs(t1mc.pdgCode()) != pdg_lepton || std::abs(t2mc.pdgCode()) != pdg_lepton) { // hh or lh correlated bkg + if (std::abs(t1mc.pdgCode()) != pdg_lepton && std::abs(t2mc.pdgCode()) != pdg_lepton) { // hh correlated bkg + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/corr_bkg_hh/uls/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Pair/corr_bkg_hh/lspp/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Pair/corr_bkg_hh/lsmm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } + } else { // lh correlated bkg + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/corr_bkg_lh/uls/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Pair/corr_bkg_lh/lspp/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Pair/corr_bkg_lh/lsmm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } + } + } + } else { // true combinatorial bkg + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/comb_bkg/uls/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Pair/comb_bkg/lspp/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Pair/comb_bkg/lsmm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } + } + + if (std::abs(t1mc.pdgCode()) != pdg_lepton || std::abs(t2mc.pdgCode()) != pdg_lepton) { + return false; + } + + if (!is_pair_from_same_mcevent) { + return false; + } + if (cfgRequireTrueAssociation && (t1mc.emmceventId() != collision.emmceventId() || t2mc.emmceventId() != collision.emmceventId())) { + return false; + } + int mother_id = FindLF(t1mc, t2mc, mcparticles); + int hfee_type = IsHF(t1mc, t2mc, mcparticles); + if (mother_id < 0 && hfee_type < 0) { + return false; + } + + if (mother_id > -1 && t1mc.pdgCode() * t2mc.pdgCode() < 0) { + auto mcmother = mcparticles.iteratorAt(mother_id); + if (mcmother.isPhysicalPrimary() || mcmother.producedByGenerator()) { + if ((t1mc.isPhysicalPrimary() || t1mc.producedByGenerator()) && (t2mc.isPhysicalPrimary() || t2mc.producedByGenerator())) { + switch (std::abs(mcmother.pdgCode())) { + case 111: + if (IsFromCharm(mcmother, mcparticles) < 0 && IsFromBeauty(mcmother, mcparticles) < 0) { // prompt pi0 + fRegistry.fill(HIST("Pair/sm/PromptPi0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + fRegistry.fill(HIST("Pair/sm/PromptPi0/hMvsPhiV"), phiv, v12.M()); + } + } else { // non-prompt pi0 + fRegistry.fill(HIST("Pair/sm/NonPromptPi0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + fRegistry.fill(HIST("Pair/sm/NonPromptPi0/hMvsPhiV"), phiv, v12.M()); + } + } + break; + case 221: + fRegistry.fill(HIST("Pair/sm/Eta/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + break; + case 331: + fRegistry.fill(HIST("Pair/sm/EtaPrime/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + break; + case 113: + fRegistry.fill(HIST("Pair/sm/Rho/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + break; + case 223: + fRegistry.fill(HIST("Pair/sm/Omega/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + if (mcmother.daughtersIds().size() == 2) { // omeag->ee + fRegistry.fill(HIST("Pair/sm/Omega2ll/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } + break; + case 333: + fRegistry.fill(HIST("Pair/sm/Phi/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + if (mcmother.daughtersIds().size() == 2) { // phi->ee + fRegistry.fill(HIST("Pair/sm/Phi2ll/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } + break; + case 443: { + if (IsFromBeauty(mcmother, mcparticles) > 0) { + fRegistry.fill(HIST("Pair/sm/NonPromptJPsi/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else { + fRegistry.fill(HIST("Pair/sm/PromptJPsi/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } + break; + } + case 100443: { + if (IsFromBeauty(mcmother, mcparticles) > 0) { + fRegistry.fill(HIST("Pair/sm/NonPromptPsi2S/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else { + fRegistry.fill(HIST("Pair/sm/PromptPsi2S/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } + break; + } + default: + break; + } + } else if (!(t1mc.isPhysicalPrimary() || t1mc.producedByGenerator()) && !(t2mc.isPhysicalPrimary() || t2mc.producedByGenerator())) { + switch (std::abs(mcmother.pdgCode())) { + case 22: + fRegistry.fill(HIST("Pair/sm/Photon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + fRegistry.fill(HIST("Pair/sm/Photon/hMvsPhiV"), phiv, v12.M()); + float rxy_gen = std::sqrt(std::pow(t1mc.vx(), 2) + std::pow(t1mc.vy(), 2)); + fRegistry.fill(HIST("Pair/sm/Photon/hMvsRxy"), rxy_gen, v12.M()); + } + break; + default: + break; + } + } // end of primary/secondary selection + } // end of primary selection for same mother + } else if (hfee_type > -1) { + if ((t1mc.isPhysicalPrimary() || t1mc.producedByGenerator()) && (t2mc.isPhysicalPrimary() || t2mc.producedByGenerator())) { + auto mp1 = mcparticles.iteratorAt(t1mc.mothersIds()[0]); + auto mp2 = mcparticles.iteratorAt(t2mc.mothersIds()[0]); + if (t1mc.pdgCode() * t2mc.pdgCode() < 0) { // ULS + switch (hfee_type) { + case static_cast(EM_HFeeType::kCe_Ce): { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/hadron_hadron/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + if (isCharmMeson(mp1) && isCharmMeson(mp2)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/meson_meson/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + if (std::abs(mp1.pdgCode()) == 411 && std::abs(mp2.pdgCode()) == 411) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Dplus_Dminus/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if (std::abs(mp1.pdgCode()) == 421 && std::abs(mp2.pdgCode()) == 421) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/D0_D0bar/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if (std::abs(mp1.pdgCode()) == 431 && std::abs(mp2.pdgCode()) == 431) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Dsplus_Dsminus/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 411 && std::abs(mp2.pdgCode()) == 421) || (std::abs(mp2.pdgCode()) == 411 && std::abs(mp1.pdgCode()) == 421)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Dpm_D0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 411 && std::abs(mp2.pdgCode()) == 431) || (std::abs(mp2.pdgCode()) == 411 && std::abs(mp1.pdgCode()) == 431)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Dpm_Dspm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 421 && std::abs(mp2.pdgCode()) == 431) || (std::abs(mp2.pdgCode()) == 421 && std::abs(mp1.pdgCode()) == 431)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/D0_Dspm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } + } else if (isCharmBaryon(mp1) && isCharmBaryon(mp2)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/baryon_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + if (std::abs(mp1.pdgCode()) == 4122 && std::abs(mp2.pdgCode()) == 4122) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Lcplus_Lcminus/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if (std::abs(mp1.pdgCode()) == 4232 && std::abs(mp2.pdgCode()) == 4232) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Xicplus_Xicminus/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if (std::abs(mp1.pdgCode()) == 4132 && std::abs(mp2.pdgCode()) == 4132) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Xic0_Xic0bar/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if (std::abs(mp1.pdgCode()) == 4332 && std::abs(mp2.pdgCode()) == 4332) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Omegac0_Omegac0bar/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 4122 && std::abs(mp2.pdgCode()) == 4232) || (std::abs(mp2.pdgCode()) == 4122 && std::abs(mp1.pdgCode()) == 4232)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Lcpm_Xicpm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 4122 && std::abs(mp2.pdgCode()) == 4132) || (std::abs(mp2.pdgCode()) == 4122 && std::abs(mp1.pdgCode()) == 4132)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Lcpm_Xic0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 4122 && std::abs(mp2.pdgCode()) == 4332) || (std::abs(mp2.pdgCode()) == 4122 && std::abs(mp1.pdgCode()) == 4332)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Lcpm_Omegac0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 4232 && std::abs(mp2.pdgCode()) == 4132) || (std::abs(mp2.pdgCode()) == 4232 && std::abs(mp1.pdgCode()) == 4132)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Xicpm_Xic0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 4232 && std::abs(mp2.pdgCode()) == 4332) || (std::abs(mp2.pdgCode()) == 4232 && std::abs(mp1.pdgCode()) == 4332)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Xicpm_Omegac0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 4132 && std::abs(mp2.pdgCode()) == 4332) || (std::abs(mp2.pdgCode()) == 4132 && std::abs(mp1.pdgCode()) == 4332)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Xic0_Omegac0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } + } else { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + if ((std::abs(mp1.pdgCode()) == 411 && std::abs(mp2.pdgCode()) == 4122) || (std::abs(mp2.pdgCode()) == 411 && std::abs(mp1.pdgCode()) == 4122)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Dpm_Lcpm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 411 && std::abs(mp2.pdgCode()) == 4232) || (std::abs(mp2.pdgCode()) == 411 && std::abs(mp1.pdgCode()) == 4232)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Dpm_Xicpm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 411 && std::abs(mp2.pdgCode()) == 4132) || (std::abs(mp2.pdgCode()) == 411 && std::abs(mp1.pdgCode()) == 4132)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Dpm_Xic0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 411 && std::abs(mp2.pdgCode()) == 4332) || (std::abs(mp2.pdgCode()) == 411 && std::abs(mp1.pdgCode()) == 4332)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Dpm_Omegac0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 421 && std::abs(mp2.pdgCode()) == 4122) || (std::abs(mp2.pdgCode()) == 421 && std::abs(mp1.pdgCode()) == 4122)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/D0_Lcpm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 421 && std::abs(mp2.pdgCode()) == 4232) || (std::abs(mp2.pdgCode()) == 421 && std::abs(mp1.pdgCode()) == 4232)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/D0_Xicpm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 421 && std::abs(mp2.pdgCode()) == 4132) || (std::abs(mp2.pdgCode()) == 421 && std::abs(mp1.pdgCode()) == 4132)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/D0_Xic0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 421 && std::abs(mp2.pdgCode()) == 4332) || (std::abs(mp2.pdgCode()) == 421 && std::abs(mp1.pdgCode()) == 4332)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/D0_Omegac0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 431 && std::abs(mp2.pdgCode()) == 4122) || (std::abs(mp2.pdgCode()) == 431 && std::abs(mp1.pdgCode()) == 4122)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Dspm_Lcpm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 431 && std::abs(mp2.pdgCode()) == 4232) || (std::abs(mp2.pdgCode()) == 431 && std::abs(mp1.pdgCode()) == 4232)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Dspm_Xicpm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 431 && std::abs(mp2.pdgCode()) == 4132) || (std::abs(mp2.pdgCode()) == 431 && std::abs(mp1.pdgCode()) == 4132)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Dspm_Xic0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((std::abs(mp1.pdgCode()) == 431 && std::abs(mp2.pdgCode()) == 4332) || (std::abs(mp2.pdgCode()) == 431 && std::abs(mp1.pdgCode()) == 4332)) { + fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/Dspm_Omegac0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } + } + break; + } + case static_cast(EM_HFeeType::kBe_Be): { + fRegistry.fill(HIST("Pair/bbbar/b2l_b2l/hadron_hadron/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + if (isBeautyMeson(mp1) && isBeautyMeson(mp2)) { + fRegistry.fill(HIST("Pair/bbbar/b2l_b2l/meson_meson/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if (isBeautyBaryon(mp1) && isBeautyBaryon(mp2)) { + fRegistry.fill(HIST("Pair/bbbar/b2l_b2l/baryon_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else { + fRegistry.fill(HIST("Pair/bbbar/b2l_b2l/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } + break; + } + case static_cast(EM_HFeeType::kBCe_BCe): { + fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2c2l/hadron_hadron/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + if (isCharmMeson(mp1) && isCharmMeson(mp2)) { + fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2c2l/meson_meson/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if (isCharmBaryon(mp1) && isCharmBaryon(mp2)) { + fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2c2l/baryon_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else { + fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2c2l/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } + break; + } + case static_cast(EM_HFeeType::kBCe_Be_SameB): { // ULS + fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2l_sameb/hadron_hadron/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + if ((isCharmMeson(mp1) && isBeautyMeson(mp2)) || (isCharmMeson(mp2) && isBeautyMeson(mp1))) { + fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2l_sameb/meson_meson/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((isCharmBaryon(mp1) && isBeautyBaryon(mp2)) || (isCharmBaryon(mp2) && isBeautyBaryon(mp1))) { + fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2l_sameb/baryon_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else { + fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2l_sameb/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } + break; + } + case static_cast(EM_HFeeType::kBCe_Be_DiffB): // LS + LOGF(info, "You should not see kBCe_Be_DiffB in ULS. Good luck."); + break; + default: + break; + } + } else { // LS + switch (hfee_type) { + case static_cast(EM_HFeeType::kCe_Ce): + LOGF(info, "You should not see kCe_Ce in LS. Good luck."); + break; + case static_cast(EM_HFeeType::kBe_Be): + LOGF(info, "You should not see kBe_Be in LS. Good luck."); + break; + case static_cast(EM_HFeeType::kBCe_BCe): + LOGF(info, "You should not see kBCe_BCe in LS. Good luck."); + break; + case static_cast(EM_HFeeType::kBCe_Be_SameB): // ULS + LOGF(info, "You should not see kBCe_Be_SameB in LS. Good luck."); + break; + case static_cast(EM_HFeeType::kBCe_Be_DiffB): { // LS + fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2l_diffb/hadron_hadron/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + if ((isCharmMeson(mp1) && isBeautyMeson(mp2)) || (isCharmMeson(mp2) && isBeautyMeson(mp1))) { + fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2l_diffb/meson_meson/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else if ((isCharmBaryon(mp1) && isBeautyBaryon(mp2)) || (isCharmBaryon(mp2) && isBeautyBaryon(mp1))) { + fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2l_diffb/baryon_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } else { + fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2l_diffb/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); + } + break; + } + default: + break; + } + } + } + } // end of HF evaluation + return true; + } + + SliceCache cache; + Preslice perCollision_electron = aod::emprimaryelectron::emeventId; + Filter trackFilter_electron = dielectroncuts.cfg_min_phi_track < o2::aod::track::phi && o2::aod::track::phi < dielectroncuts.cfg_max_phi_track && o2::aod::track::tpcChi2NCl < dielectroncuts.cfg_max_chi2tpc && o2::aod::track::itsChi2NCl < dielectroncuts.cfg_max_chi2its && nabs(o2::aod::track::dcaXY) < dielectroncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dielectroncuts.cfg_max_dcaz; + Filter pidFilter_electron = dielectroncuts.cfg_min_TPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < dielectroncuts.cfg_max_TPCNsigmaEl; + Filter ttcaFilter_electron = ifnode(dielectroncuts.enableTTCA.node(), o2::aod::emprimaryelectron::isAssociatedToMPC == true || o2::aod::emprimaryelectron::isAssociatedToMPC == false, o2::aod::emprimaryelectron::isAssociatedToMPC == true); + Filter prefilter_derived_electron = ifnode(dielectroncuts.cfg_apply_cuts_from_prefilter_derived.node() && dielectroncuts.cfg_prefilter_bits_derived.node() >= static_cast(1), + ifnode((dielectroncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kMee))) > static_cast(0), (o2::aod::emprimaryelectron::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kMee))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kPhiV))) > static_cast(0), (o2::aod::emprimaryelectron::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kPhiV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS))) > static_cast(0), (o2::aod::emprimaryelectron::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits_derived.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS))) > static_cast(0), (o2::aod::emprimaryelectron::pfbderived & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS))) <= static_cast(0), true), + o2::aod::emprimaryelectron::pfbderived >= static_cast(0)); + + Filter prefilter_electron = ifnode(dielectroncuts.cfg_apply_cuts_from_prefilter.node() && dielectroncuts.cfg_prefilter_bits.node() >= static_cast(1), + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPC))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPC))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_1))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_1))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_2))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_2))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_3))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_3))) <= static_cast(0), true), + o2::aod::emprimaryelectron::pfb >= static_cast(0)); + + Preslice perCollision_muon = aod::emprimarymuon::emeventId; + Filter trackFilter_muon = o2::aod::fwdtrack::trackType == dimuoncuts.cfg_track_type && dimuoncuts.cfg_min_phi_track < o2::aod::fwdtrack::phi && o2::aod::fwdtrack::phi < dimuoncuts.cfg_max_phi_track; + Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), o2::aod::emprimarymuon::isAssociatedToMPC == true || o2::aod::emprimarymuon::isAssociatedToMPC == false, o2::aod::emprimarymuon::isAssociatedToMPC == true); + + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + // Filter collisionFilter_multiplicity = cfgNtracksPV08Min <= o2::aod::mult::multNTracksPV && o2::aod::mult::multNTracksPV < cfgNtracksPV08Max; + Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + using FilteredMyCollisions = soa::Filtered; + + template + void runTruePairing(TCollisions const& collisions, TMCLeptons const& posTracks, TMCLeptons const& negTracks, TPreslice const& perCollision, TCut const& cut, TAllTracks const& tracks, TMCCollisions const& mccollisions, TMCParticles const& mcparticles) + { + for (const auto& collision : collisions) { + initCCDB(collision); + float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<0, -1>(&fRegistry, collision); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<1, -1>(&fRegistry, collision); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted + + auto posTracks_per_coll = posTracks.sliceByCached(perCollision, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks.sliceByCached(perCollision, collision.globalIndex(), cache); + // LOGF(info, "centrality = %f , posTracks_per_coll.size() = %d, negTracks_per_coll.size() = %d", centralities[cfgCentEstimator], posTracks_per_coll.size(), negTracks_per_coll.size()); + + for (const auto& [pos, neg] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + fillTruePairInfo(collision, mccollisions, pos, neg, cut, tracks, mcparticles); + } // end of ULS pair loop + + for (const auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { // LS++ + fillTruePairInfo(collision, mccollisions, pos1, pos2, cut, tracks, mcparticles); + } // end of LS++ pair loop + + for (const auto& [neg1, neg2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { // LS-- + fillTruePairInfo(collision, mccollisions, neg1, neg2, cut, tracks, mcparticles); + } // end of LS-- pair loop + + } // end of collision loop + } + + template + void runGenInfo(TCollisions const& collisions, TMCCollisions const& mccollisions, TMCLeptons const& posTracksMC, TMCLeptons const& negTracksMC, TMCParticles const& mcparticles) + { + for (const auto& mccollision : mccollisions) { + if (cfgEventGeneratorType >= 0 && mccollision.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + fRegistry.fill(HIST("MCEvent/before/hZvtx"), mccollision.posZ()); + if (mccollision.mpemeventId() < 0) { + continue; + } + auto collision = collisions.rawIteratorAt(mccollision.mpemeventId()); + + float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + fRegistry.fill(HIST("MCEvent/before/hZvtx_rec"), mccollision.posZ()); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + fRegistry.fill(HIST("MCEvent/after/hZvtx"), mccollision.posZ()); + + auto posTracks_per_coll = posTracksMC.sliceByCachedUnsorted(aod::emmcparticle::emmceventId, mccollision.globalIndex(), cache); + auto negTracks_per_coll = negTracksMC.sliceByCachedUnsorted(aod::emmcparticle::emmceventId, mccollision.globalIndex(), cache); + + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + // LOGF(info, "pdg1 = %d, pdg2 = %d", t1.pdgCode(), t2.pdgCode()); + + if (!isInAcceptance(t1) || !isInAcceptance(t2)) { + continue; + } + + if (!t1.isPhysicalPrimary() && !t1.producedByGenerator()) { + continue; + } + if (!t2.isPhysicalPrimary() && !t2.producedByGenerator()) { + continue; + } + + int mother_id = FindLF(t1, t2, mcparticles); + int hfee_type = IsHF(t1, t2, mcparticles); + if (mother_id < 0 && hfee_type < 0) { + continue; + } + + float pt1 = 0.f, eta1 = 0.f, phi1 = 0.f, pt2 = 0.f, eta2 = 0.f, phi2 = 0.f; + if constexpr (isSmeared) { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + pt1 = t1.ptSmeared(); + eta1 = t1.etaSmeared(); + phi1 = t1.phiSmeared(); + pt2 = t2.ptSmeared(); + eta2 = t2.etaSmeared(); + phi2 = t2.phiSmeared(); + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (dimuoncuts.cfg_track_type == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + pt1 = t1.ptSmeared_sa_muon(); + eta1 = t1.etaSmeared_sa_muon(); + phi1 = t1.phiSmeared_sa_muon(); + pt2 = t2.ptSmeared_sa_muon(); + eta2 = t2.etaSmeared_sa_muon(); + phi2 = t2.phiSmeared_sa_muon(); + } else if (dimuoncuts.cfg_track_type == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + pt1 = t1.ptSmeared_gl_muon(); + eta1 = t1.etaSmeared_gl_muon(); + phi1 = t1.phiSmeared_gl_muon(); + pt2 = t2.ptSmeared_gl_muon(); + eta2 = t2.etaSmeared_gl_muon(); + phi2 = t2.phiSmeared_gl_muon(); + } else { + pt1 = t1.pt(); + eta1 = t1.eta(); + phi1 = t1.phi(); + pt2 = t2.pt(); + eta2 = t2.eta(); + phi2 = t2.phi(); + } + } + } else { + pt1 = t1.pt(); + eta1 = t1.eta(); + phi1 = t1.phi(); + pt2 = t2.pt(); + eta2 = t2.eta(); + phi2 = t2.phi(); + } + + ROOT::Math::PtEtaPhiMVector v1(pt1, eta1, phi1, leptonM1); + ROOT::Math::PtEtaPhiMVector v2(pt2, eta2, phi2, leptonM2); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + + float deta = v1.Eta() - v2.Eta(); + float dphi = v1.Phi() - v2.Phi(); + o2::math_utils::bringToPMPi(dphi); + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (v12.Rapidity() < dielectroncuts.cfg_min_pair_y || dielectroncuts.cfg_max_pair_y < v12.Rapidity()) { + continue; + } + if (dielectroncuts.cfg_apply_detadphi && std::pow(deta / dielectroncuts.cfg_min_deta, 2) + std::pow(dphi / dielectroncuts.cfg_min_dphi, 2) < 1.f) { + continue; + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (v12.Rapidity() < dimuoncuts.cfg_min_pair_y || dimuoncuts.cfg_max_pair_y < v12.Rapidity()) { + continue; + } + if (dimuoncuts.cfg_apply_detadphi && std::pow(deta / dimuoncuts.cfg_min_deta, 2) + std::pow(dphi / dimuoncuts.cfg_min_dphi, 2) < 1.f) { + continue; + } + } + + float aco = 1.f - std::fabs(dphi) / M_PI; + float asym = std::fabs(v1.Pt() - v2.Pt()) / (v1.Pt() + v2.Pt()); + float dphi_e_ee = v1.Phi() - v12.Phi(); + o2::math_utils::bringToPMPi(dphi_e_ee); + dphi = RecoDecay::constrainAngle(dphi, -o2::constants::math::PIHalf, 1); // shift dphi in [-pi/2, +3pi/2] rad. after deta-dphi cut. + + float cos_thetaCS = 999, phiCS = 999.f; + o2::aod::pwgem::dilepton::utils::pairutil::getAngleCS(t1, t2, leptonM1, leptonM2, beamE1, beamE2, beamP1, beamP2, cos_thetaCS, phiCS); + o2::math_utils::bringToPMPi(phiCS); + + if (mother_id > -1) { + auto mcmother = mcparticles.iteratorAt(mother_id); + if (mcmother.isPhysicalPrimary() || mcmother.producedByGenerator()) { + + switch (std::abs(mcmother.pdgCode())) { + case 111: + if (IsFromCharm(mcmother, mcparticles) < 0 && IsFromBeauty(mcmother, mcparticles) < 0) { // prompt pi0 + fRegistry.fill(HIST("Generated/sm/PromptPi0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else { // non-prompt pi0 + fRegistry.fill(HIST("Generated/sm/NonPromptPi0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } + break; + case 221: + fRegistry.fill(HIST("Generated/sm/Eta/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + break; + case 331: + fRegistry.fill(HIST("Generated/sm/EtaPrime/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + break; + case 113: + fRegistry.fill(HIST("Generated/sm/Rho/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + break; + case 223: + fRegistry.fill(HIST("Generated/sm/Omega/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + if (mcmother.daughtersIds().size() == 2) { // omega->ee + fRegistry.fill(HIST("Generated/sm/Omega2ll/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } + break; + case 333: + fRegistry.fill(HIST("Generated/sm/Phi/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + if (mcmother.daughtersIds().size() == 2) { // phi->ee + fRegistry.fill(HIST("Generated/sm/Phi2ll/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } + break; + case 443: { + if (IsFromBeauty(mcmother, mcparticles) > 0) { + fRegistry.fill(HIST("Generated/sm/NonPromptJPsi/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else { + fRegistry.fill(HIST("Generated/sm/PromptJPsi/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } + break; + } + case 100443: { + if (IsFromBeauty(mcmother, mcparticles) > 0) { + fRegistry.fill(HIST("Generated/sm/NonPromptPsi2S/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else { + fRegistry.fill(HIST("Generated/sm/PromptPsi2S/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } + break; + } + default: + break; + } + } + } else if (hfee_type > -1) { + auto mp1 = mcparticles.iteratorAt(t1.mothersIds()[0]); + auto mp2 = mcparticles.iteratorAt(t2.mothersIds()[0]); + switch (hfee_type) { + case static_cast(EM_HFeeType::kCe_Ce): { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/hadron_hadron/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + if (isCharmMeson(mp1) && isCharmMeson(mp2)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/meson_meson/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + if (std::abs(mp1.pdgCode()) == 411 && std::abs(mp2.pdgCode()) == 411) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Dplus_Dminus/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if (std::abs(mp1.pdgCode()) == 421 && std::abs(mp2.pdgCode()) == 421) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/D0_D0bar/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if (std::abs(mp1.pdgCode()) == 431 && std::abs(mp2.pdgCode()) == 431) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Dsplus_Dsminus/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 411 && std::abs(mp2.pdgCode()) == 421) || (std::abs(mp2.pdgCode()) == 411 && std::abs(mp1.pdgCode()) == 421)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Dpm_D0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 411 && std::abs(mp2.pdgCode()) == 431) || (std::abs(mp2.pdgCode()) == 411 && std::abs(mp1.pdgCode()) == 431)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Dpm_Dspm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 421 && std::abs(mp2.pdgCode()) == 431) || (std::abs(mp2.pdgCode()) == 421 && std::abs(mp1.pdgCode()) == 431)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/D0_Dspm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } + } else if (isCharmBaryon(mp1) && isCharmBaryon(mp2)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/baryon_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + if (std::abs(mp1.pdgCode()) == 4122 && std::abs(mp2.pdgCode()) == 4122) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Lcplus_Lcminus/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if (std::abs(mp1.pdgCode()) == 4232 && std::abs(mp2.pdgCode()) == 4232) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Xicplus_Xicminus/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if (std::abs(mp1.pdgCode()) == 4132 && std::abs(mp2.pdgCode()) == 4132) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Xic0_Xic0bar/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if (std::abs(mp1.pdgCode()) == 4332 && std::abs(mp2.pdgCode()) == 4332) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Omegac0_Omegac0bar/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 4122 && std::abs(mp2.pdgCode()) == 4232) || (std::abs(mp2.pdgCode()) == 4122 && std::abs(mp1.pdgCode()) == 4232)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Lcpm_Xicpm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 4122 && std::abs(mp2.pdgCode()) == 4132) || (std::abs(mp2.pdgCode()) == 4122 && std::abs(mp1.pdgCode()) == 4132)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Lcpm_Xic0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 4122 && std::abs(mp2.pdgCode()) == 4332) || (std::abs(mp2.pdgCode()) == 4122 && std::abs(mp1.pdgCode()) == 4332)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Lcpm_Omegac0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 4232 && std::abs(mp2.pdgCode()) == 4132) || (std::abs(mp2.pdgCode()) == 4232 && std::abs(mp1.pdgCode()) == 4132)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Xicpm_Xic0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 4232 && std::abs(mp2.pdgCode()) == 4332) || (std::abs(mp2.pdgCode()) == 4232 && std::abs(mp1.pdgCode()) == 4332)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Xicpm_Omegac0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 4132 && std::abs(mp2.pdgCode()) == 4332) || (std::abs(mp2.pdgCode()) == 4132 && std::abs(mp1.pdgCode()) == 4332)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Xic0_Omegac0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } + } else { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + if ((std::abs(mp1.pdgCode()) == 411 && std::abs(mp2.pdgCode()) == 4122) || (std::abs(mp2.pdgCode()) == 411 && std::abs(mp1.pdgCode()) == 4122)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Dpm_Lcpm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 411 && std::abs(mp2.pdgCode()) == 4232) || (std::abs(mp2.pdgCode()) == 411 && std::abs(mp1.pdgCode()) == 4232)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Dpm_Xicpm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 411 && std::abs(mp2.pdgCode()) == 4132) || (std::abs(mp2.pdgCode()) == 411 && std::abs(mp1.pdgCode()) == 4132)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Dpm_Xic0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 411 && std::abs(mp2.pdgCode()) == 4332) || (std::abs(mp2.pdgCode()) == 411 && std::abs(mp1.pdgCode()) == 4332)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Dpm_Omegac0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 421 && std::abs(mp2.pdgCode()) == 4122) || (std::abs(mp2.pdgCode()) == 421 && std::abs(mp1.pdgCode()) == 4122)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/D0_Lcpm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 421 && std::abs(mp2.pdgCode()) == 4232) || (std::abs(mp2.pdgCode()) == 421 && std::abs(mp1.pdgCode()) == 4232)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/D0_Xicpm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 421 && std::abs(mp2.pdgCode()) == 4132) || (std::abs(mp2.pdgCode()) == 421 && std::abs(mp1.pdgCode()) == 4132)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/D0_Xic0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 421 && std::abs(mp2.pdgCode()) == 4332) || (std::abs(mp2.pdgCode()) == 421 && std::abs(mp1.pdgCode()) == 4332)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/D0_Omegac0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 431 && std::abs(mp2.pdgCode()) == 4122) || (std::abs(mp2.pdgCode()) == 431 && std::abs(mp1.pdgCode()) == 4122)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Dspm_Lcpm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 431 && std::abs(mp2.pdgCode()) == 4232) || (std::abs(mp2.pdgCode()) == 431 && std::abs(mp1.pdgCode()) == 4232)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Dspm_Xicpm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 431 && std::abs(mp2.pdgCode()) == 4132) || (std::abs(mp2.pdgCode()) == 431 && std::abs(mp1.pdgCode()) == 4132)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Dspm_Xic0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((std::abs(mp1.pdgCode()) == 431 && std::abs(mp2.pdgCode()) == 4332) || (std::abs(mp2.pdgCode()) == 431 && std::abs(mp1.pdgCode()) == 4332)) { + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/Dspm_Omegac0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } + } + break; + } + case static_cast(EM_HFeeType::kBe_Be): { + fRegistry.fill(HIST("Generated/bbbar/b2l_b2l/hadron_hadron/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + if (isBeautyMeson(mp1) && isBeautyMeson(mp2)) { + fRegistry.fill(HIST("Generated/bbbar/b2l_b2l/meson_meson/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if (isBeautyBaryon(mp1) && isBeautyBaryon(mp2)) { + fRegistry.fill(HIST("Generated/bbbar/b2l_b2l/baryon_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else { + fRegistry.fill(HIST("Generated/bbbar/b2l_b2l/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } + break; + } + case static_cast(EM_HFeeType::kBCe_BCe): { + fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2c2l/hadron_hadron/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + if (isCharmMeson(mp1) && isCharmMeson(mp2)) { + fRegistry.fill(HIST("Generated/bbbar/b2l_b2l/meson_meson/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if (isCharmBaryon(mp1) && isCharmBaryon(mp2)) { + fRegistry.fill(HIST("Generated/bbbar/b2l_b2l/baryon_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else { + fRegistry.fill(HIST("Generated/bbbar/b2l_b2l/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } + break; + } + case static_cast(EM_HFeeType::kBCe_Be_SameB): { // ULS + fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2l_sameb/hadron_hadron/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + if ((isCharmMeson(mp1) && isBeautyMeson(mp2)) || (isCharmMeson(mp2) && isBeautyMeson(mp1))) { + fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2l_sameb/meson_meson/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((isCharmBaryon(mp1) && isBeautyBaryon(mp2)) || (isCharmBaryon(mp2) && isBeautyBaryon(mp1))) { + fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2l_sameb/baryon_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else { + fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2l_sameb/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } + break; + } + case static_cast(EM_HFeeType::kBCe_Be_DiffB): // LS + LOGF(info, "You should not see kBCe_Be_DiffB in ULS. Good luck."); + break; + default: + break; + } + } // end of HF evaluation + } // end of true ULS pair loop + + for (const auto& [t1, t2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { + // LOGF(info, "pdg1 = %d, pdg2 = %d", t1.pdgCode(), t2.pdgCode()); + + if (!isInAcceptance(t1) || !isInAcceptance(t2)) { + continue; + } + + if (!t1.isPhysicalPrimary() && !t1.producedByGenerator()) { + continue; + } + if (!t2.isPhysicalPrimary() && !t2.producedByGenerator()) { + continue; + } + + int hfee_type = IsHF(t1, t2, mcparticles); + if (hfee_type < 0) { + continue; + } + + float pt1 = 0.f, eta1 = 0.f, phi1 = 0.f, pt2 = 0.f, eta2 = 0.f, phi2 = 0.f; + if constexpr (isSmeared) { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + pt1 = t1.ptSmeared(); + eta1 = t1.etaSmeared(); + phi1 = t1.phiSmeared(); + pt2 = t2.ptSmeared(); + eta2 = t2.etaSmeared(); + phi2 = t2.phiSmeared(); + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (dimuoncuts.cfg_track_type == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + pt1 = t1.ptSmeared_sa_muon(); + eta1 = t1.etaSmeared_sa_muon(); + phi1 = t1.phiSmeared_sa_muon(); + pt2 = t2.ptSmeared_sa_muon(); + eta2 = t2.etaSmeared_sa_muon(); + phi2 = t2.phiSmeared_sa_muon(); + } else if (dimuoncuts.cfg_track_type == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + pt1 = t1.ptSmeared_gl_muon(); + eta1 = t1.etaSmeared_gl_muon(); + phi1 = t1.phiSmeared_gl_muon(); + pt2 = t2.ptSmeared_gl_muon(); + eta2 = t2.etaSmeared_gl_muon(); + phi2 = t2.phiSmeared_gl_muon(); + } else { + pt1 = t1.pt(); + eta1 = t1.eta(); + phi1 = t1.phi(); + pt2 = t2.pt(); + eta2 = t2.eta(); + phi2 = t2.phi(); + } + } + } else { + pt1 = t1.pt(); + eta1 = t1.eta(); + phi1 = t1.phi(); + pt2 = t2.pt(); + eta2 = t2.eta(); + phi2 = t2.phi(); + } + + ROOT::Math::PtEtaPhiMVector v1(pt1, eta1, phi1, leptonM1); + ROOT::Math::PtEtaPhiMVector v2(pt2, eta2, phi2, leptonM2); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + + float deta = v1.Eta() - v2.Eta(); + float dphi = v1.Phi() - v2.Phi(); + o2::math_utils::bringToPMPi(dphi); + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (v12.Rapidity() < dielectroncuts.cfg_min_pair_y || dielectroncuts.cfg_max_pair_y < v12.Rapidity()) { + continue; + } + if (dielectroncuts.cfg_apply_detadphi && std::pow(deta / dielectroncuts.cfg_min_deta, 2) + std::pow(dphi / dielectroncuts.cfg_min_dphi, 2) < 1.f) { + continue; + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (v12.Rapidity() < dimuoncuts.cfg_min_pair_y || dimuoncuts.cfg_max_pair_y < v12.Rapidity()) { + continue; + } + if (dimuoncuts.cfg_apply_detadphi && std::pow(deta / dimuoncuts.cfg_min_deta, 2) + std::pow(dphi / dimuoncuts.cfg_min_dphi, 2) < 1.f) { + continue; + } + } + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (v12.Rapidity() < dielectroncuts.cfg_min_pair_y || dielectroncuts.cfg_max_pair_y < v12.Rapidity()) { + continue; + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (v12.Rapidity() < dimuoncuts.cfg_min_pair_y || dimuoncuts.cfg_max_pair_y < v12.Rapidity()) { + continue; + } + } + + float aco = 1.f - std::fabs(dphi) / M_PI; + float asym = std::fabs(v1.Pt() - v2.Pt()) / (v1.Pt() + v2.Pt()); + float dphi_e_ee = v1.Phi() - v12.Phi(); + o2::math_utils::bringToPMPi(dphi_e_ee); + dphi = RecoDecay::constrainAngle(dphi, -o2::constants::math::PIHalf, 1); // shift dphi in [-pi/2, +3pi/2] rad. after deta-dphi cut. + + float cos_thetaCS = 999, phiCS = 999.f; + o2::aod::pwgem::dilepton::utils::pairutil::getAngleCS(t1, t2, leptonM1, leptonM2, beamE1, beamE2, beamP1, beamP2, cos_thetaCS, phiCS); + o2::math_utils::bringToPMPi(phiCS); + + if (hfee_type > -1) { + auto mp1 = mcparticles.iteratorAt(t1.mothersIds()[0]); + auto mp2 = mcparticles.iteratorAt(t2.mothersIds()[0]); + switch (hfee_type) { + case static_cast(EM_HFeeType::kCe_Ce): + LOGF(info, "You should not see kCe_Ce in LS++. Good luck."); + break; + case static_cast(EM_HFeeType::kBe_Be): + LOGF(info, "You should not see kBe_Be in LS++. Good luck."); + break; + case static_cast(EM_HFeeType::kBCe_BCe): + LOGF(info, "You should not see kBCe_BCe in LS++. Good luck."); + break; + case static_cast(EM_HFeeType::kBCe_Be_SameB): // ULS + LOGF(info, "You should not see kBCe_Be_SameB in LS++. Good luck."); + break; + case static_cast(EM_HFeeType::kBCe_Be_DiffB): { // LS + fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2l_diffb/hadron_hadron/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + if ((isCharmMeson(mp1) && isBeautyMeson(mp2)) || (isCharmMeson(mp2) && isBeautyMeson(mp1))) { + fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2l_diffb/meson_meson/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((isCharmBaryon(mp1) && isBeautyBaryon(mp2)) || (isCharmBaryon(mp2) && isBeautyBaryon(mp1))) { + fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2l_diffb/baryon_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else { + fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2l_diffb/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } + break; + } + default: + break; + } + } + } // end of true LS++ pair loop + + for (const auto& [t1, t2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { + // LOGF(info, "pdg1 = %d, pdg2 = %d", t1.pdgCode(), t2.pdgCode()); + + if (!isInAcceptance(t1) || !isInAcceptance(t2)) { + continue; + } + + if (!t1.isPhysicalPrimary() && !t1.producedByGenerator()) { + continue; + } + if (!t2.isPhysicalPrimary() && !t2.producedByGenerator()) { + continue; + } + + int hfee_type = IsHF(t1, t2, mcparticles); + if (hfee_type < 0) { + continue; + } + + float pt1 = 0.f, eta1 = 0.f, phi1 = 0.f, pt2 = 0.f, eta2 = 0.f, phi2 = 0.f; + if constexpr (isSmeared) { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + pt1 = t1.ptSmeared(); + eta1 = t1.etaSmeared(); + phi1 = t1.phiSmeared(); + pt2 = t2.ptSmeared(); + eta2 = t2.etaSmeared(); + phi2 = t2.phiSmeared(); + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (dimuoncuts.cfg_track_type == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + pt1 = t1.ptSmeared_sa_muon(); + eta1 = t1.etaSmeared_sa_muon(); + phi1 = t1.phiSmeared_sa_muon(); + pt2 = t2.ptSmeared_sa_muon(); + eta2 = t2.etaSmeared_sa_muon(); + phi2 = t2.phiSmeared_sa_muon(); + } else if (dimuoncuts.cfg_track_type == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + pt1 = t1.ptSmeared_gl_muon(); + eta1 = t1.etaSmeared_gl_muon(); + phi1 = t1.phiSmeared_gl_muon(); + pt2 = t2.ptSmeared_gl_muon(); + eta2 = t2.etaSmeared_gl_muon(); + phi2 = t2.phiSmeared_gl_muon(); + } else { + pt1 = t1.pt(); + eta1 = t1.eta(); + phi1 = t1.phi(); + pt2 = t2.pt(); + eta2 = t2.eta(); + phi2 = t2.phi(); + } + } + } else { + pt1 = t1.pt(); + eta1 = t1.eta(); + phi1 = t1.phi(); + pt2 = t2.pt(); + eta2 = t2.eta(); + phi2 = t2.phi(); + } + + ROOT::Math::PtEtaPhiMVector v1(pt1, eta1, phi1, leptonM1); + ROOT::Math::PtEtaPhiMVector v2(pt2, eta2, phi2, leptonM2); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + + float deta = v1.Eta() - v2.Eta(); + float dphi = v1.Phi() - v2.Phi(); + o2::math_utils::bringToPMPi(dphi); + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (v12.Rapidity() < dielectroncuts.cfg_min_pair_y || dielectroncuts.cfg_max_pair_y < v12.Rapidity()) { + continue; + } + if (dielectroncuts.cfg_apply_detadphi && std::pow(deta / dielectroncuts.cfg_min_deta, 2) + std::pow(dphi / dielectroncuts.cfg_min_dphi, 2) < 1.f) { + continue; + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (v12.Rapidity() < dimuoncuts.cfg_min_pair_y || dimuoncuts.cfg_max_pair_y < v12.Rapidity()) { + continue; + } + if (dimuoncuts.cfg_apply_detadphi && std::pow(deta / dimuoncuts.cfg_min_deta, 2) + std::pow(dphi / dimuoncuts.cfg_min_dphi, 2) < 1.f) { + continue; + } + } + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (v12.Rapidity() < dielectroncuts.cfg_min_pair_y || dielectroncuts.cfg_max_pair_y < v12.Rapidity()) { + continue; + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (v12.Rapidity() < dimuoncuts.cfg_min_pair_y || dimuoncuts.cfg_max_pair_y < v12.Rapidity()) { + continue; + } + } + + float aco = 1.f - std::fabs(dphi) / M_PI; + float asym = std::fabs(v1.Pt() - v2.Pt()) / (v1.Pt() + v2.Pt()); + float dphi_e_ee = v1.Phi() - v12.Phi(); + o2::math_utils::bringToPMPi(dphi_e_ee); + dphi = RecoDecay::constrainAngle(dphi, -o2::constants::math::PIHalf, 1); // shift dphi in [-pi/2, +3pi/2] rad. after deta-dphi cut. + + float cos_thetaCS = 999, phiCS = 999.f; + o2::aod::pwgem::dilepton::utils::pairutil::getAngleCS(t1, t2, leptonM1, leptonM2, beamE1, beamE2, beamP1, beamP2, cos_thetaCS, phiCS); + o2::math_utils::bringToPMPi(phiCS); + + if (hfee_type > -1) { + auto mp1 = mcparticles.iteratorAt(t1.mothersIds()[0]); + auto mp2 = mcparticles.iteratorAt(t2.mothersIds()[0]); + switch (hfee_type) { + case static_cast(EM_HFeeType::kCe_Ce): + LOGF(info, "You should not see kCe_Ce in LS--. Good luck."); + break; + case static_cast(EM_HFeeType::kBe_Be): + LOGF(info, "You should not see kBe_Be in LS--. Good luck."); + break; + case static_cast(EM_HFeeType::kBCe_BCe): + LOGF(info, "You should not see kBCe_BCe in LS--. Good luck."); + break; + case static_cast(EM_HFeeType::kBCe_Be_SameB): // ULS + LOGF(info, "You should not see kBCe_Be_SameB in LS--. Good luck."); + break; + case static_cast(EM_HFeeType::kBCe_Be_DiffB): { // LS + fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2l_diffb/hadron_hadron/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + if ((isCharmMeson(mp1) && isBeautyMeson(mp2)) || (isCharmMeson(mp2) && isBeautyMeson(mp1))) { + fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2l_diffb/meson_meson/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else if ((isCharmBaryon(mp1) && isBeautyBaryon(mp2)) || (isCharmBaryon(mp2) && isBeautyBaryon(mp1))) { + fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2l_diffb/baryon_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } else { + fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2l_diffb/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, std::fabs(cos_thetaCS), std::fabs(phiCS), aco, asym, std::fabs(dphi_e_ee)); + } + break; + } + default: + break; + } + } + } // end of true LS++ pair loop + } // end of collision loop + } + + template + bool isPairOK(TCollision const& collision, TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TAllTracks const& tracks) + { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { + if (!cut.template IsSelectedTrack(t1, collision) || !cut.template IsSelectedTrack(t2, collision)) { + return false; + } + } else { // cut-based + if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { + return false; + } + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { + return false; + } + if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t1, cut, tracks)) { + return false; + } + if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(t2, cut, tracks)) { + return false; + } + } + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (!cut.template IsSelectedPair(t1, t2, d_bz)) { + return false; + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (!cut.template IsSelectedPair(t1, t2)) { + return false; + } + } + return true; + } + + std::map, float> map_weight; // -> float + template + void fillPairWeightMap(TCollisions const& collisions, TTracks1 const& posTracks, TTracks2 const& negTracks, TPresilce const& perCollision, TCut const& cut, TAllTracks const& tracks, TMCCollisions const&, TMCParticles const& mcparticles) + { + std::vector> passed_pairIds; + passed_pairIds.reserve(posTracks.size() * negTracks.size()); + + for (const auto& collision : collisions) { + initCCDB(collision); + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + + // auto mccollision = collision.template emmcevent_as(); + // if (cfgEventGeneratorType >= 0 && mccollision.getSubGeneratorId() != cfgEventGeneratorType) { + // continue; + // } + + auto posTracks_per_coll = posTracks.sliceByCached(perCollision, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks.sliceByCached(perCollision, collision.globalIndex(), cache); + + for (const auto& [pos, neg] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + auto mcpos = mcparticles.iteratorAt(pos.emmcparticleId()); + auto mccollision_from_pos = mcpos.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_pos.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + auto mcneg = mcparticles.iteratorAt(neg.emmcparticleId()); + auto mccollision_from_neg = mcneg.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_neg.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + + if (isPairOK(collision, pos, neg, cut, tracks)) { + passed_pairIds.emplace_back(std::make_pair(pos.globalIndex(), neg.globalIndex())); + } + } + for (const auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { // LS++ + auto mcpos1 = mcparticles.iteratorAt(pos1.emmcparticleId()); + auto mccollision_from_pos1 = mcpos1.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_pos1.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + auto mcpos2 = mcparticles.iteratorAt(pos2.emmcparticleId()); + auto mccollision_from_pos2 = mcpos2.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_pos2.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + + if (isPairOK(collision, pos1, pos2, cut, tracks)) { + passed_pairIds.emplace_back(std::make_pair(pos1.globalIndex(), pos2.globalIndex())); + } + } + for (const auto& [neg1, neg2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { // LS-- + auto mcneg1 = mcparticles.iteratorAt(neg1.emmcparticleId()); + auto mccollision_from_neg1 = mcneg1.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_neg1.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + auto mcneg2 = mcparticles.iteratorAt(neg2.emmcparticleId()); + auto mccollision_from_neg2 = mcneg2.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_neg2.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + if (isPairOK(collision, neg1, neg2, cut, tracks)) { + passed_pairIds.emplace_back(std::make_pair(neg1.globalIndex(), neg2.globalIndex())); + } + } + } // end of collision loop + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + for (const auto& pairId : passed_pairIds) { + auto t1 = tracks.rawIteratorAt(std::get<0>(pairId)); + auto t2 = tracks.rawIteratorAt(std::get<1>(pairId)); + // LOGF(info, "std::get<0>(pairId) = %d, std::get<1>(pairId) = %d, t1.globalIndex() = %d, t2.globalIndex() = %d", std::get<0>(pairId), std::get<1>(pairId), t1.globalIndex(), t2.globalIndex()); + + float n = 1.f; // include myself. + for (const auto& ambId1 : t1.ambiguousElectronsIds()) { + for (const auto& ambId2 : t2.ambiguousElectronsIds()) { + if (std::find(passed_pairIds.begin(), passed_pairIds.end(), std::make_pair(ambId1, ambId2)) != passed_pairIds.end()) { + n += 1.f; + } + } + } + map_weight[pairId] = 1.f / n; + } // end of passed_pairIds loop + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + for (const auto& pairId : passed_pairIds) { + auto t1 = tracks.rawIteratorAt(std::get<0>(pairId)); + auto t2 = tracks.rawIteratorAt(std::get<1>(pairId)); + + float n = 1.f; // include myself. + for (const auto& ambId1 : t1.ambiguousMuonsIds()) { + for (const auto& ambId2 : t2.ambiguousMuonsIds()) { + if (std::find(passed_pairIds.begin(), passed_pairIds.end(), std::make_pair(ambId1, ambId2)) != passed_pairIds.end()) { + n += 1.f; + } + } + } + map_weight[pairId] = 1.f / n; + } // end of passed_pairIds loop + } + passed_pairIds.clear(); + passed_pairIds.shrink_to_fit(); + } + + template + bool isPairInAcc(TTrack const& t1, TTrack const& t2) + { + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), leptonM1); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), leptonM2); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if ((t1.pt() < dielectroncuts.cfg_min_pt_track || dielectroncuts.cfg_max_pt_track < t1.pt()) || (t2.pt() < dielectroncuts.cfg_min_pt_track || dielectroncuts.cfg_max_pt_track < t2.pt())) { + return false; + } + if ((t1.eta() < dielectroncuts.cfg_min_eta_track || dielectroncuts.cfg_max_eta_track < t1.eta()) || (t2.eta() < dielectroncuts.cfg_min_eta_track || dielectroncuts.cfg_max_eta_track < t2.eta())) { + return false; + } + if (v12.Rapidity() < dielectroncuts.cfg_min_pair_y || dielectroncuts.cfg_max_pair_y < v12.Rapidity()) { + return false; + } + return true; + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if ((t1.pt() < dimuoncuts.cfg_min_pt_track || dimuoncuts.cfg_max_pt_track < t1.pt()) || (t2.pt() < dimuoncuts.cfg_min_pt_track || dimuoncuts.cfg_max_pt_track < t2.pt())) { + return false; + } + if ((t1.eta() < dimuoncuts.cfg_min_eta_track || dimuoncuts.cfg_max_eta_track < t1.eta()) || (t2.eta() < dimuoncuts.cfg_min_eta_track || dimuoncuts.cfg_max_eta_track < t2.eta())) { + return false; + } + if (v12.Rapidity() < dimuoncuts.cfg_min_pair_y || dimuoncuts.cfg_max_pair_y < v12.Rapidity()) { + return false; + } + return true; + } else { + return false; + } + return true; + } + + template + void fillUnfolding(TCollisions const& collisions, TTracks1 const& posTracks, TTracks2 const& negTracks, TPresilce const& perCollision, TCut const& cut, TAllTracks const& tracks, TMCCollisions const&, TMCParticles const& mcparticles) + { + for (const auto& collision : collisions) { + initCCDB(collision); + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + + auto posTracks_per_coll = posTracks.sliceByCached(perCollision, collision.globalIndex(), cache); // reconstructed pos tracks + auto negTracks_per_coll = negTracks.sliceByCached(perCollision, collision.globalIndex(), cache); // reconstructed neg tracks + + for (const auto& [pos, neg] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + auto mcpos = mcparticles.iteratorAt(pos.emmcparticleId()); + auto mccollision_from_pos = mcpos.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_pos.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + + auto mcneg = mcparticles.iteratorAt(neg.emmcparticleId()); + auto mccollision_from_neg = mcneg.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_neg.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + + if ((std::abs(mcpos.pdgCode()) != pdg_lepton || std::abs(mcneg.pdgCode()) != pdg_lepton) || (mcpos.emmceventId() != mcneg.emmceventId())) { + continue; + } + if (mcpos.pdgCode() * mcneg.pdgCode() > 0) { // ULS + continue; + } + if (!((mcpos.isPhysicalPrimary() || mcpos.producedByGenerator()) && (mcneg.isPhysicalPrimary() || mcneg.producedByGenerator()))) { + continue; + } + int mother_id = FindLF(mcpos, mcneg, mcparticles); + int hfee_type = IsHF(mcpos, mcneg, mcparticles); + if (mother_id < 0 && hfee_type < 0) { + continue; + } + + if (!isPairOK(collision, pos, neg, cut, tracks)) { // without acceptance + continue; + } + + ROOT::Math::PtEtaPhiMVector v1rec(pos.pt(), pos.eta(), pos.phi(), leptonM1); + ROOT::Math::PtEtaPhiMVector v2rec(neg.pt(), neg.eta(), neg.phi(), leptonM2); + ROOT::Math::PtEtaPhiMVector v12rec = v1rec + v2rec; + + ROOT::Math::PtEtaPhiMVector v1mc(mcpos.pt(), mcpos.eta(), mcpos.phi(), leptonM1); + ROOT::Math::PtEtaPhiMVector v2mc(mcneg.pt(), mcneg.eta(), mcneg.phi(), leptonM2); + ROOT::Math::PtEtaPhiMVector v12mc = v1mc + v2mc; + float weight = 1.f; + if (cfgApplyWeightTTCA) { + weight = map_weight[std::make_pair(pos.globalIndex(), neg.globalIndex())]; + } + + if (mother_id > -1) { + auto mcmother = mcparticles.iteratorAt(mother_id); + if (mcmother.isPhysicalPrimary() || mcmother.producedByGenerator()) { + switch (std::abs(mcmother.pdgCode())) { + case 111: + case 221: + case 331: + case 113: + case 223: + case 333: { + if (isPairInAcc(pos, neg) && isPairInAcc(mcpos, mcneg)) { // both rec and mc info are in acceptance. + fRegistry.fill(HIST("Unfold/lf/hsRM"), v12mc.M(), v12mc.Pt(), v12rec.M(), v12rec.Pt(), weight); + } else if (!isPairInAcc(pos, neg) && isPairInAcc(mcpos, mcneg)) { + fRegistry.fill(HIST("Unfold/lf/hMiss"), v12mc.M(), v12mc.Pt(), weight); + } else if (isPairInAcc(pos, neg) && !isPairInAcc(mcpos, mcneg)) { + fRegistry.fill(HIST("Unfold/lf/hFake"), v12rec.M(), v12rec.Pt(), weight); + } + break; + } + case 443: { + if (IsFromBeauty(mcmother, mcparticles) > 0) { + if (isPairInAcc(pos, neg) && isPairInAcc(mcpos, mcneg)) { // both rec and mc info are in acceptance. + fRegistry.fill(HIST("Unfold/NonPromptJPsi/hsRM"), v12mc.M(), v12mc.Pt(), v12rec.M(), v12rec.Pt(), weight); + } else if (!isPairInAcc(pos, neg) && isPairInAcc(mcpos, mcneg)) { + fRegistry.fill(HIST("Unfold/NonPromptJPsi/hMiss"), v12mc.M(), v12mc.Pt(), weight); + } else if (isPairInAcc(pos, neg) && !isPairInAcc(mcpos, mcneg)) { + fRegistry.fill(HIST("Unfold/NonPromptJPsi/hFake"), v12rec.M(), v12rec.Pt(), weight); + } + } else { + if (isPairInAcc(pos, neg) && isPairInAcc(mcpos, mcneg)) { // both rec and mc info are in acceptance. + fRegistry.fill(HIST("Unfold/PromptJPsi/hsRM"), v12mc.M(), v12mc.Pt(), v12rec.M(), v12rec.Pt(), weight); + } else if (!isPairInAcc(pos, neg) && isPairInAcc(mcpos, mcneg)) { + fRegistry.fill(HIST("Unfold/PromptJPsi/hMiss"), v12mc.M(), v12mc.Pt(), weight); + } else if (isPairInAcc(pos, neg) && !isPairInAcc(mcpos, mcneg)) { + fRegistry.fill(HIST("Unfold/PromptJPsi/hFake"), v12rec.M(), v12rec.Pt(), weight); + } + } + break; + } + case 100443: { + if (IsFromBeauty(mcmother, mcparticles) > 0) { + if (isPairInAcc(pos, neg) && isPairInAcc(mcpos, mcneg)) { // both rec and mc info are in acceptance. + fRegistry.fill(HIST("Unfold/NonPromptPsi2S/hsRM"), v12mc.M(), v12mc.Pt(), v12rec.M(), v12rec.Pt(), weight); + } else if (!isPairInAcc(pos, neg) && isPairInAcc(mcpos, mcneg)) { + fRegistry.fill(HIST("Unfold/NonPromptPsi2S/hMiss"), v12mc.M(), v12mc.Pt(), weight); + } else if (isPairInAcc(pos, neg) && !isPairInAcc(mcpos, mcneg)) { + fRegistry.fill(HIST("Unfold/NonPromptPsi2S/hFake"), v12rec.M(), v12rec.Pt(), weight); + } + } else { + if (isPairInAcc(pos, neg) && isPairInAcc(mcpos, mcneg)) { // both rec and mc info are in acceptance. + fRegistry.fill(HIST("Unfold/PromptPsi2S/hsRM"), v12mc.M(), v12mc.Pt(), v12rec.M(), v12rec.Pt(), weight); + } else if (!isPairInAcc(pos, neg) && isPairInAcc(mcpos, mcneg)) { + fRegistry.fill(HIST("Unfold/PromptPsi2S/hMiss"), v12mc.M(), v12mc.Pt(), weight); + } else if (isPairInAcc(pos, neg) && !isPairInAcc(mcpos, mcneg)) { + fRegistry.fill(HIST("Unfold/PromptPsi2S/hFake"), v12rec.M(), v12rec.Pt(), weight); + } + } + break; + } + default: + break; + } + } + } else if (hfee_type > -1) { + switch (hfee_type) { + case static_cast(EM_HFeeType::kCe_Ce): { + if (isPairInAcc(pos, neg) && isPairInAcc(mcpos, mcneg)) { // both rec and mc info are in acceptance. + fRegistry.fill(HIST("Unfold/ccbar_uls/hsRM"), v12mc.M(), v12mc.Pt(), v12rec.M(), v12rec.Pt(), weight); + } else if (!isPairInAcc(pos, neg) && isPairInAcc(mcpos, mcneg)) { + fRegistry.fill(HIST("Unfold/ccbar_uls/hMiss"), v12mc.M(), v12mc.Pt(), weight); + } else if (isPairInAcc(pos, neg) && !isPairInAcc(mcpos, mcneg)) { + fRegistry.fill(HIST("Unfold/ccbar_uls/hFake"), v12rec.M(), v12rec.Pt(), weight); + } + break; + } + case static_cast(EM_HFeeType::kBe_Be): + case static_cast(EM_HFeeType::kBCe_BCe): + case static_cast(EM_HFeeType::kBCe_Be_SameB): { // ULS + if (isPairInAcc(pos, neg) && isPairInAcc(mcpos, mcneg)) { // both rec and mc info are in acceptance. + fRegistry.fill(HIST("Unfold/bbbar_uls/hsRM"), v12mc.M(), v12mc.Pt(), v12rec.M(), v12rec.Pt(), weight); + } else if (!isPairInAcc(pos, neg) && isPairInAcc(mcpos, mcneg)) { + fRegistry.fill(HIST("Unfold/bbbar_uls/hMiss"), v12mc.M(), v12mc.Pt(), weight); + } else if (isPairInAcc(pos, neg) && !isPairInAcc(mcpos, mcneg)) { + fRegistry.fill(HIST("Unfold/bbbar_uls/hFake"), v12rec.M(), v12rec.Pt(), weight); + } + break; + } + case static_cast(EM_HFeeType::kBCe_Be_DiffB): // LS + LOGF(info, "You should not see kBCe_Be_DiffB in ULS. Good luck."); + break; + default: + break; + } + } + } // end of ULS pairing + + for (const auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { // LS++ + auto mcpos1 = mcparticles.iteratorAt(pos1.emmcparticleId()); + auto mccollision_from_pos1 = mcpos1.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_pos1.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + auto mcpos2 = mcparticles.iteratorAt(pos2.emmcparticleId()); + auto mccollision_from_pos2 = mcpos2.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_pos2.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + + if ((std::abs(mcpos1.pdgCode()) != pdg_lepton || std::abs(mcpos2.pdgCode()) != pdg_lepton) || (mcpos1.emmceventId() != mcpos2.emmceventId())) { + continue; + } + if (mcpos1.pdgCode() * mcpos2.pdgCode() < 0) { // LS + continue; + } + if (!((mcpos1.isPhysicalPrimary() || mcpos1.producedByGenerator()) && (mcpos2.isPhysicalPrimary() || mcpos2.producedByGenerator()))) { + continue; + } + int hfee_type = IsHF(mcpos1, mcpos2, mcparticles); + if (hfee_type < 0) { + continue; + } + + if (!isPairOK(collision, pos1, pos2, cut, tracks)) { // without acceptance + continue; + } + + ROOT::Math::PtEtaPhiMVector v1rec(pos1.pt(), pos1.eta(), pos1.phi(), leptonM1); + ROOT::Math::PtEtaPhiMVector v2rec(pos2.pt(), pos2.eta(), pos2.phi(), leptonM2); + ROOT::Math::PtEtaPhiMVector v12rec = v1rec + v2rec; + + ROOT::Math::PtEtaPhiMVector v1mc(mcpos1.pt(), mcpos1.eta(), mcpos1.phi(), leptonM1); + ROOT::Math::PtEtaPhiMVector v2mc(mcpos2.pt(), mcpos2.eta(), mcpos2.phi(), leptonM2); + ROOT::Math::PtEtaPhiMVector v12mc = v1mc + v2mc; + float weight = 1.f; + if (cfgApplyWeightTTCA) { + weight = map_weight[std::make_pair(pos1.globalIndex(), pos2.globalIndex())]; + } + + if (hfee_type > -1) { + switch (hfee_type) { + case static_cast(EM_HFeeType::kCe_Ce): + LOGF(info, "You should not see kCe_Ce in LS. Good luck."); + break; + case static_cast(EM_HFeeType::kBe_Be): + LOGF(info, "You should not see kBe_Be in LS. Good luck."); + break; + case static_cast(EM_HFeeType::kBCe_BCe): + LOGF(info, "You should not see kBCe_BCe in LS. Good luck."); + break; + case static_cast(EM_HFeeType::kBCe_Be_SameB): // ULS + LOGF(info, "You should not see kBCe_Be_SameB in LS. Good luck."); + break; + case static_cast(EM_HFeeType::kBCe_Be_DiffB): { // LS + if (isPairInAcc(pos1, pos2) && isPairInAcc(mcpos1, mcpos2)) { // both rec and mc info are in acceptance. + fRegistry.fill(HIST("Unfold/bbbar_ls/hsRM"), v12mc.M(), v12mc.Pt(), v12rec.M(), v12rec.Pt(), weight); + } else if (!isPairInAcc(pos1, pos2) && isPairInAcc(mcpos1, mcpos2)) { + fRegistry.fill(HIST("Unfold/bbbar_ls/hMiss"), v12mc.M(), v12mc.Pt(), weight); + } else if (isPairInAcc(pos1, pos2) && !isPairInAcc(mcpos1, mcpos2)) { + fRegistry.fill(HIST("Unfold/bbbar_ls/hFake"), v12rec.M(), v12rec.Pt(), weight); + } + break; + } + default: + break; + } + } + } // end of LS++ pairing + + for (const auto& [neg1, neg2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { // LS-- + auto mcneg1 = mcparticles.iteratorAt(neg1.emmcparticleId()); + auto mccollision_from_neg1 = mcneg1.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_neg1.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + auto mcneg2 = mcparticles.iteratorAt(neg2.emmcparticleId()); + auto mccollision_from_neg2 = mcneg2.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_neg2.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + if (!isPairOK(collision, neg1, neg2, cut, tracks)) { // without acceptance + continue; + } + if ((std::abs(mcneg1.pdgCode()) != pdg_lepton || std::abs(mcneg2.pdgCode()) != pdg_lepton) || (mcneg1.emmceventId() != mcneg2.emmceventId())) { + continue; + } + if (mcneg1.pdgCode() * mcneg2.pdgCode() < 0) { // LS + continue; + } + if (!((mcneg1.isPhysicalPrimary() || mcneg1.producedByGenerator()) && (mcneg2.isPhysicalPrimary() || mcneg2.producedByGenerator()))) { + continue; + } + int hfee_type = IsHF(mcneg1, mcneg2, mcparticles); + if (hfee_type < 0) { + continue; + } + + if (!isPairOK(collision, neg1, neg2, cut, tracks)) { // without acceptance + continue; + } + + ROOT::Math::PtEtaPhiMVector v1rec(neg1.pt(), neg1.eta(), neg1.phi(), leptonM1); + ROOT::Math::PtEtaPhiMVector v2rec(neg2.pt(), neg2.eta(), neg2.phi(), leptonM2); + ROOT::Math::PtEtaPhiMVector v12rec = v1rec + v2rec; + + ROOT::Math::PtEtaPhiMVector v1mc(mcneg1.pt(), mcneg1.eta(), mcneg1.phi(), leptonM1); + ROOT::Math::PtEtaPhiMVector v2mc(mcneg2.pt(), mcneg2.eta(), mcneg2.phi(), leptonM2); + ROOT::Math::PtEtaPhiMVector v12mc = v1mc + v2mc; + float weight = 1.f; + if (cfgApplyWeightTTCA) { + weight = map_weight[std::make_pair(neg1.globalIndex(), neg2.globalIndex())]; + } + + if (hfee_type > -1) { + switch (hfee_type) { + case static_cast(EM_HFeeType::kCe_Ce): + LOGF(info, "You should not see kCe_Ce in LS. Good luck."); + break; + case static_cast(EM_HFeeType::kBe_Be): + LOGF(info, "You should not see kBe_Be in LS. Good luck."); + break; + case static_cast(EM_HFeeType::kBCe_BCe): + LOGF(info, "You should not see kBCe_BCe in LS. Good luck."); + break; + case static_cast(EM_HFeeType::kBCe_Be_SameB): // ULS + LOGF(info, "You should not see kBCe_Be_SameB in LS. Good luck."); + break; + case static_cast(EM_HFeeType::kBCe_Be_DiffB): { // LS + if (isPairInAcc(neg1, neg2) && isPairInAcc(mcneg1, mcneg2)) { // both rec and mc info are in acceptance. + fRegistry.fill(HIST("Unfold/bbbar_ls/hsRM"), v12mc.M(), v12mc.Pt(), v12rec.M(), v12rec.Pt(), weight); + } else if (!isPairInAcc(neg1, neg2) && isPairInAcc(mcneg1, mcneg2)) { + fRegistry.fill(HIST("Unfold/bbbar_ls/hMiss"), v12mc.M(), v12mc.Pt(), weight); + } else if (isPairInAcc(neg1, neg2) && !isPairInAcc(mcneg1, mcneg2)) { + fRegistry.fill(HIST("Unfold/bbbar_ls/hFake"), v12rec.M(), v12rec.Pt(), weight); + } + break; + } + default: + break; + } + } + } // end of LS-- pairing + } // end of collision loop + } + + Partition positive_electrons = o2::aod::emprimaryelectron::sign > int8_t(0); // reconstructed tracks + Partition negative_electrons = o2::aod::emprimaryelectron::sign < int8_t(0); // reconstructed tracks + Partition positive_muons = o2::aod::emprimarymuon::sign > int8_t(0); // reconstructed tracks + Partition negative_muons = o2::aod::emprimarymuon::sign < int8_t(0); // reconstructed tracks + + Partition positive_electronsMC = o2::aod::mcparticle::pdgCode == -11; // e+ + Partition negative_electronsMC = o2::aod::mcparticle::pdgCode == 11; // e- + Partition positive_muonsMC = o2::aod::mcparticle::pdgCode == -13; // mu+ + Partition negative_muonsMC = o2::aod::mcparticle::pdgCode == 13; // mu- + PresliceUnsorted perMcCollision = aod::emmcparticle::emmceventId; + PresliceUnsorted perMcCollision_vm = aod::emmcgenvectormeson::emmceventId; + // PresliceUnsorted recColperMcCollision = aod::emmceventlabel::emmceventId; + + void processAnalysis(FilteredMyCollisions const& collisions, MyMCCollisions const& mccollisions, aod::EMMCParticles const& mcparticles, TLeptons const& leptons) + { + // LOGF(info, "collisions.size() = %d, mccollisions.size() = %d, mcparticles.size() = %d", collisions.size(), mccollisions.size(), mcparticles.size()); + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (cfgApplyWeightTTCA) { + fillPairWeightMap(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, leptons, mccollisions, mcparticles); + } + runTruePairing(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, leptons, mccollisions, mcparticles); + runGenInfo(collisions, mccollisions, positive_electronsMC, negative_electronsMC, mcparticles); + if (cfgFillUnfolding) { + fillUnfolding(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, leptons, mccollisions, mcparticles); + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (cfgApplyWeightTTCA) { + fillPairWeightMap(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, leptons, mccollisions, mcparticles); + } + runTruePairing(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, leptons, mccollisions, mcparticles); + runGenInfo(collisions, mccollisions, positive_muonsMC, negative_muonsMC, mcparticles); + if (cfgFillUnfolding) { + fillUnfolding(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, leptons, mccollisions, mcparticles); + } + } + map_weight.clear(); + } + PROCESS_SWITCH(DileptonMC, processAnalysis, "run dilepton mc analysis", true); + + Partition positive_electronsMC_smeared = o2::aod::mcparticle::pdgCode == -11; // e+ + Partition negative_electronsMC_smeared = o2::aod::mcparticle::pdgCode == 11; // e- + Partition positive_muonsMC_smeared = o2::aod::mcparticle::pdgCode == -13; // mu+ + Partition negative_muonsMC_smeared = o2::aod::mcparticle::pdgCode == 13; // mu- + + void processAnalysis_Smeared(FilteredMyCollisions const& collisions, MyMCCollisions const& mccollisions, TLeptons const& leptons, TSmeardMCParitlces const& mcparticles_smeared) + { + // LOGF(info, "collisions.size() = %d, mccollisions.size() = %d, mcparticles.size() = %d", collisions.size(), mccollisions.size(), mcparticles.size()); + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (cfgApplyWeightTTCA) { + fillPairWeightMap(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, leptons, mccollisions, mcparticles_smeared); + } + runTruePairing(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, leptons, mccollisions, mcparticles_smeared); + runGenInfo(collisions, mccollisions, positive_electronsMC_smeared, negative_electronsMC_smeared, mcparticles_smeared); + if (cfgFillUnfolding) { + fillUnfolding(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, leptons, mccollisions, mcparticles_smeared); + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (cfgApplyWeightTTCA) { + fillPairWeightMap(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, leptons, mccollisions, mcparticles_smeared); + } + runTruePairing(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, leptons, mccollisions, mcparticles_smeared); + runGenInfo(collisions, mccollisions, positive_muonsMC_smeared, negative_muonsMC_smeared, mcparticles_smeared); + if (cfgFillUnfolding) { + fillUnfolding(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, leptons, mccollisions, mcparticles_smeared); + } + } + map_weight.clear(); + } + PROCESS_SWITCH(DileptonMC, processAnalysis_Smeared, "run dilepton mc analysis with smearing", false); + + void processGen_VM(FilteredMyCollisions const& collisions, MyMCCollisions const&, aod::EMMCGenVectorMesons const& mcparticles) + { + // for oemga, phi efficiency + for (const auto& collision : collisions) { + float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + auto mccollision = collision.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + auto mctracks_per_coll = mcparticles.sliceBy(perMcCollision_vm, mccollision.globalIndex()); + + for (const auto& mctrack : mctracks_per_coll) { + + if (!(mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { + continue; + } + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (mctrack.y() < dielectroncuts.cfg_min_pair_y || dielectroncuts.cfg_max_pair_y < mctrack.y()) { + continue; + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (mctrack.y() < dimuoncuts.cfg_min_pair_y || dimuoncuts.cfg_max_pair_y < mctrack.y()) { + continue; + } + } + + switch (std::abs(mctrack.pdgCode())) { + case 223: + fRegistry.fill(HIST("Generated/sm/Omega2ll/hPtY"), mctrack.y(), mctrack.pt(), 1.f / mctrack.dsf()); + break; + case 333: + fRegistry.fill(HIST("Generated/sm/Phi2ll/hPtY"), mctrack.y(), mctrack.pt(), 1.f / mctrack.dsf()); + break; + default: + break; + } + + } // end of mctracks per mccollision + } // end of collision loop + } + PROCESS_SWITCH(DileptonMC, processGen_VM, "process generated info for vector mesons", false); + + void processNorm(aod::EMEventNormInfos const& collisions) + { + for (const auto& collision : collisions) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 1.0); + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 2.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 3.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 4.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 5.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 6.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 7.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 8.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 9.0); + } + if (collision.sel8()) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 10.0); + } + if (std::fabs(collision.posZ()) < 10.0) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 11.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 12.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 13.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 14.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 15.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 16.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer3)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 17.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 18.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 19.0); + } + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted + } // end of collision loop + } + PROCESS_SWITCH(DileptonMC, processNorm, "process normalization info", false); + + void processBC(aod::EMBCs const& bcs) + { + for (const auto& bc : bcs) { + if (bc.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 0.f); + + if (bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 1.f); + } + if (bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 2.f); + } + if (rctChecker(bc)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 3.f); + } + if (bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 4.f); + } + if (bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder) && rctChecker(bc)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 5.f); + } + } + } + } + PROCESS_SWITCH(DileptonMC, processBC, "process BC counter", false); + + void processDummy(FilteredMyCollisions const&) {} + PROCESS_SWITCH(DileptonMC, processDummy, "Dummy function", false); +}; + +#endif // PWGEM_DILEPTON_CORE_DILEPTONMC_H_ diff --git a/PWGEM/Dilepton/Core/DimuonCut.cxx b/PWGEM/Dilepton/Core/DimuonCut.cxx new file mode 100644 index 00000000000..ee18a8e4232 --- /dev/null +++ b/PWGEM/Dilepton/Core/DimuonCut.cxx @@ -0,0 +1,121 @@ +// 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. + +// +// Class for dimuon Cut +// + +#include "Framework/Logger.h" +#include "PWGEM/Dilepton/Core/DimuonCut.h" + +ClassImp(DimuonCut); + +void DimuonCut::SetMassRange(float min, float max) +{ + mMinMass = min; + mMaxMass = max; + LOG(info) << "Dimuon Cut, set mass range: " << mMinMass << " - " << mMaxMass; +} +void DimuonCut::SetPairPtRange(float minPt, float maxPt) +{ + mMinPairPt = minPt; + mMaxPairPt = maxPt; + LOG(info) << "Dimuon Cut, set pair pt range: " << mMinPairPt << " - " << mMaxPairPt; +} +void DimuonCut::SetPairYRange(float minY, float maxY) +{ + mMinPairY = minY; + mMaxPairY = maxY; + LOG(info) << "Dimuon Cut, set pair rapidity range: " << mMinPairY << " - " << mMaxPairY; +} +void DimuonCut::SetPairDCAxyRange(float min, float max) +{ + mMinPairDCAxy = min; + mMaxPairDCAxy = max; + LOG(info) << "Dimuon Cut, set pair 3d dca range: " << mMinPairDCAxy << " - " << mMaxPairDCAxy; +} +void DimuonCut::SetMindEtadPhi(bool flag, float min_deta, float min_dphi) +{ + mApplydEtadPhi = flag; + mMinDeltaEta = min_deta; + mMinDeltaPhi = min_dphi; + LOG(info) << "Dimuon Cut, set apply deta-dphi cut: " << mApplydEtadPhi << " min_deta: " << mMinDeltaEta << " min_dphi: " << mMinDeltaPhi; +} +void DimuonCut::SetTrackType(int track_type) +{ + mTrackType = track_type; + LOG(info) << "Dimuon Cut, set track type: " << mTrackType; +} +void DimuonCut::SetTrackPtRange(float minPt, float maxPt) +{ + mMinTrackPt = minPt; + mMaxTrackPt = maxPt; + LOG(info) << "Dimuon Cut, set track pt range: " << mMinTrackPt << " - " << mMaxTrackPt; +} +void DimuonCut::SetTrackEtaRange(float minEta, float maxEta) +{ + mMinTrackEta = minEta; + mMaxTrackEta = maxEta; + LOG(info) << "Dimuon Cut, set track eta range: " << mMinTrackEta << " - " << mMaxTrackEta; +} +void DimuonCut::SetTrackPhiRange(float minPhi, float maxPhi) +{ + mMinTrackPhi = minPhi; + mMaxTrackPhi = maxPhi; + LOG(info) << "Dimuon Cut, set track phi range (rad.): " << mMinTrackPhi << " - " << mMaxTrackPhi; +} +void DimuonCut::SetChi2(float min, float max) +{ + mMinChi2 = min; + mMaxChi2 = max; + LOG(info) << "Dimuon Cut, set chi2 range: " << mMinChi2 << " - " << mMaxChi2; +} +void DimuonCut::SetMatchingChi2MCHMFT(float min, float max) +{ + mMinMatchingChi2MCHMFT = min; + mMaxMatchingChi2MCHMFT = max; + LOG(info) << "Dimuon Cut, set matching chi2 MFT-MCH range: " << mMinMatchingChi2MCHMFT << " - " << mMaxMatchingChi2MCHMFT; +} +void DimuonCut::SetMatchingChi2MCHMID(float min, float max) +{ + mMinMatchingChi2MCHMID = min; + mMaxMatchingChi2MCHMID = max; + LOG(info) << "Dimuon Cut, set matching chi2 MCH-MID range: " << mMinMatchingChi2MCHMID << " - " << mMaxMatchingChi2MCHMID; +} +void DimuonCut::SetNClustersMFT(int min, int max) +{ + mMinNClustersMFT = min; + mMaxNClustersMFT = max; + LOG(info) << "Dimuon Cut, set N clusters MFT range: " << mMinNClustersMFT << " - " << mMaxNClustersMFT; +} +void DimuonCut::SetNClustersMCHMID(int min, int max) +{ + mMinNClustersMCHMID = min; + mMaxNClustersMCHMID = max; + LOG(info) << "Dimuon Cut, set N clusters MCHMID range: " << mMinNClustersMCHMID << " - " << mMaxNClustersMCHMID; +} +void DimuonCut::SetRabs(float min, float max) +{ + mMinRabs = min; + mMaxRabs = max; + LOG(info) << "Dimuon Cut, set Rabs range: " << mMinRabs << " - " << mMaxRabs; +} +void DimuonCut::SetDCAxy(float min, float max) +{ + mMinDcaXY = min; + mMaxDcaXY = max; + LOG(info) << "Dimuon Cut, set DCAxy range: " << mMinDcaXY << " - " << mMaxDcaXY; +} +void DimuonCut::SetMaxPDCARabsDep(std::function RabsDepCut) +{ + mMaxPDCARabsDep = RabsDepCut; + LOG(info) << "Dimuon Cut, set max pDCA as a function of Rabs: " << mMaxPDCARabsDep(10.0); +} diff --git a/PWGEM/Dilepton/Core/DimuonCut.h b/PWGEM/Dilepton/Core/DimuonCut.h new file mode 100644 index 00000000000..4bb854c6b73 --- /dev/null +++ b/PWGEM/Dilepton/Core/DimuonCut.h @@ -0,0 +1,256 @@ +// 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. + +// +// Class for dimuon selection +// + +#ifndef PWGEM_DILEPTON_CORE_DIMUONCUT_H_ +#define PWGEM_DILEPTON_CORE_DIMUONCUT_H_ + +#include +#include +#include +#include +#include +#include "TNamed.h" +#include "Math/Vector4D.h" + +#include "MathUtils/Utils.h" +#include "Framework/Logger.h" +#include "Framework/DataTypes.h" +#include "CommonConstants/PhysicsConstants.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" + +using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; + +class DimuonCut : public TNamed +{ + public: + DimuonCut() = default; + DimuonCut(const char* name, const char* title) : TNamed(name, title) {} + + ~DimuonCut() {} + + enum class DimuonCuts : int { + // pair cut + kMass = 0, + kPairPtRange, + kPairYRange, + kPairDCARange, + // track cut + kTrackType, + kTrackPtRange, + kTrackEtaRange, + kTrackPhiRange, + kDCAxy, + kMFTNCls, + kMCHMIDNCls, + kChi2, + kMatchingChi2MCHMFT, + kMatchingChi2MCHMID, + kRabs, + kPDCA, + kNCuts + }; + + template + bool IsSelected(TPair const& pair) const + { + auto t1 = std::get<0>(pair); + auto t2 = std::get<1>(pair); + + if (!IsSelectedTrack(t1) || !IsSelectedTrack(t2)) { + return false; + } + + if (!IsSelectedPair(t1, t2)) { + return false; + } + + return true; + } + + template + bool IsSelectedPair(TTrack1 const& t1, TTrack2 const& t2) const + { + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassMuon); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassMuon); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + + float dca_xy_t1 = fwdDcaXYinSigma(t1); + float dca_xy_t2 = fwdDcaXYinSigma(t2); + float pair_dca_xy = std::sqrt((dca_xy_t1 * dca_xy_t1 + dca_xy_t2 * dca_xy_t2) / 2.); + + if (v12.M() < mMinMass || mMaxMass < v12.M()) { + return false; + } + + if (!dont_require_rapidity && (v12.Rapidity() < mMinPairY || mMaxPairY < v12.Rapidity())) { + return false; + } + + if (pair_dca_xy < mMinPairDCAxy || mMaxPairDCAxy < pair_dca_xy) { // in sigma for pair + return false; + } + + float deta = v1.Eta() - v2.Eta(); + float dphi = v1.Phi() - v2.Phi(); + o2::math_utils::bringToPMPi(dphi); + if (mApplydEtadPhi && std::pow(deta / mMinDeltaEta, 2) + std::pow(dphi / mMinDeltaPhi, 2) < 1.f) { + return false; + } + + return true; + } + + template + bool IsSelectedTrack(TTrack const& track) const + { + if (!IsSelectedTrack(track, DimuonCuts::kTrackType)) { + return false; + } + + if (!dont_require_pteta) { + if (!IsSelectedTrack(track, DimuonCuts::kTrackPtRange)) { + return false; + } + if (!IsSelectedTrack(track, DimuonCuts::kTrackEtaRange)) { + return false; + } + } + if (!IsSelectedTrack(track, DimuonCuts::kTrackPhiRange)) { + return false; + } + if (!IsSelectedTrack(track, DimuonCuts::kDCAxy)) { + return false; + } + if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && !IsSelectedTrack(track, DimuonCuts::kMFTNCls)) { + return false; + } + if (!IsSelectedTrack(track, DimuonCuts::kMCHMIDNCls)) { + return false; + } + if (!IsSelectedTrack(track, DimuonCuts::kChi2)) { + return false; + } + if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && !IsSelectedTrack(track, DimuonCuts::kMatchingChi2MCHMFT)) { + return false; + } + if (!IsSelectedTrack(track, DimuonCuts::kMatchingChi2MCHMID)) { + return false; + } + if (!IsSelectedTrack(track, DimuonCuts::kPDCA)) { + return false; + } + if (!IsSelectedTrack(track, DimuonCuts::kRabs)) { + return false; + } + + return true; + } + + template + bool IsSelectedTrack(T const& track, const DimuonCuts& cut) const + { + switch (cut) { + case DimuonCuts::kTrackType: + return track.trackType() == mTrackType; + + case DimuonCuts::kTrackPtRange: + return track.pt() > mMinTrackPt && track.pt() < mMaxTrackPt; + + case DimuonCuts::kTrackEtaRange: + return track.eta() > mMinTrackEta && track.eta() < mMaxTrackEta; + + case DimuonCuts::kTrackPhiRange: + return track.phi() > mMinTrackPhi && track.phi() < mMaxTrackPhi; + + case DimuonCuts::kDCAxy: + return mMinDcaXY < std::sqrt(std::pow(track.fwdDcaX(), 2) + std::pow(track.fwdDcaY(), 2)) && std::sqrt(std::pow(track.fwdDcaX(), 2) + std::pow(track.fwdDcaY(), 2)) < mMaxDcaXY; + + case DimuonCuts::kMFTNCls: + return track.nClustersMFT() >= mMinNClustersMFT; + + case DimuonCuts::kMCHMIDNCls: + return track.nClusters() >= mMinNClustersMCHMID; + + case DimuonCuts::kChi2: + return track.chi2() < mMaxChi2; + + case DimuonCuts::kMatchingChi2MCHMFT: + return track.chi2MatchMCHMFT() < mMaxMatchingChi2MCHMFT; + + case DimuonCuts::kMatchingChi2MCHMID: + return track.chi2MatchMCHMID() < mMaxMatchingChi2MCHMID; + + case DimuonCuts::kPDCA: + return track.pDca() < mMaxPDCARabsDep(track.rAtAbsorberEnd()); + + case DimuonCuts::kRabs: + return mMinRabs < track.rAtAbsorberEnd() && track.rAtAbsorberEnd() < mMaxRabs; + + default: + return false; + } + } + + // Setters + void SetMassRange(float min = 0.f, float max = 1e+10); + void SetPairPtRange(float minPt = 0.f, float maxPt = 1e10f); + void SetPairYRange(float minY = -1e10f, float maxY = 1e10f); + void SetPairDCAxyRange(float min = 0.f, float max = 1e10f); // DCAxy in cm + void SetMindEtadPhi(bool flag, float min_deta, float min_dphi); + + void SetTrackType(int track_type); // 0: MFT-MCH-MID (global muon), 3: MCH-MID (standalone muon) + void SetTrackPtRange(float minPt = 0.f, float maxPt = 1e10f); + void SetTrackEtaRange(float minEta = -1e10f, float maxEta = 1e10f); + void SetTrackPhiRange(float minPhi = 0.f, float maxPhi = 2.f * M_PI); + void SetNClustersMFT(int min, int max); + void SetNClustersMCHMID(int min, int max); + void SetChi2(float min, float max); + void SetMatchingChi2MCHMFT(float min, float max); + void SetMatchingChi2MCHMID(float min, float max); + void SetDCAxy(float min, float max); // in cm + void SetRabs(float min, float max); // in cm + void SetMaxPDCARabsDep(std::function RabsDepCut); + + private: + // pair cuts + float mMinMass{0.f}, mMaxMass{1e10f}; + float mMinPairPt{0.f}, mMaxPairPt{1e10f}; // range in pT + float mMinPairY{-1e10f}, mMaxPairY{1e10f}; // range in rapidity + float mMinPairDCAxy{0.f}, mMaxPairDCAxy{1e10f}; // range in 3D DCA in sigma + bool mApplydEtadPhi{false}; // flag to apply deta, dphi cut between 2 tracks + float mMinDeltaEta{0.f}; + float mMinDeltaPhi{0.f}; + + // kinematic cuts + float mMinTrackPt{0.f}, mMaxTrackPt{1e10f}; // range in pT + float mMinTrackEta{-1e10f}, mMaxTrackEta{1e10f}; // range in eta + float mMinTrackPhi{0.f}, mMaxTrackPhi{2.f * M_PI}; // range in phi + + // track quality cuts + int mTrackType{3}; + int mMinNClustersMFT{0}, mMaxNClustersMFT{10}; // min number of TPC clusters + int mMinNClustersMCHMID{0}, mMaxNClustersMCHMID{16}; // min number of TPC clusters + float mMinChi2{0.f}, mMaxChi2{1e10f}; // max tpc fit chi2 per TPC cluster + float mMinMatchingChi2MCHMFT{0.f}, mMaxMatchingChi2MCHMFT{1e10f}; // max tpc fit chi2 per TPC cluster + float mMinMatchingChi2MCHMID{0.f}, mMaxMatchingChi2MCHMID{1e10f}; // max tpc fit chi2 per TPC cluster + std::function mMaxPDCARabsDep{}; // max pdca in xy plane as function of Rabs + + float mMinRabs{17.6}, mMaxRabs{89.5}; + float mMinDcaXY{0.0f}, mMaxDcaXY{1e10f}; + + ClassDef(DimuonCut, 1); +}; + +#endif // PWGEM_DILEPTON_CORE_DIMUONCUT_H_ diff --git a/PWGEM/PhotonMeson/Core/EMEventCut.cxx b/PWGEM/Dilepton/Core/EMEventCut.cxx similarity index 52% rename from PWGEM/PhotonMeson/Core/EMEventCut.cxx rename to PWGEM/Dilepton/Core/EMEventCut.cxx index 244dc762dc5..a8f085f2646 100644 --- a/PWGEM/PhotonMeson/Core/EMEventCut.cxx +++ b/PWGEM/Dilepton/Core/EMEventCut.cxx @@ -14,12 +14,10 @@ // #include "Framework/Logger.h" -#include "PWGEM/PhotonMeson/Core/EMEventCut.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" ClassImp(EMEventCut); -const char* EMEventCut::mCutNames[static_cast(EMEventCut::EMEventCuts::kNCuts)] = {"Sel8", "FT0AND", "Zvtx", "eNoTFB", "RequireNoITSROFB", "NoSameBunchPileup", "GoodVertexITSTPC", "GoodZvtxFT0vsPV"}; - void EMEventCut::SetRequireSel8(bool flag) { mRequireSel8 = flag; @@ -63,32 +61,55 @@ void EMEventCut::SetRequireVertexITSTPC(bool flag) LOG(info) << "EM Event Cut, require vertex reconstructed by ITS-TPC matched track: " << mRequireVertexITSTPC; } -void EMEventCut::SetRequireIsGoodZvtxFT0vsPV(bool flag) +void EMEventCut::SetRequireGoodZvtxFT0vsPV(bool flag) { mRequireGoodZvtxFT0vsPV = flag; LOG(info) << "EM Event Cut, require good Zvtx between FT0 vs. PV: " << mRequireGoodZvtxFT0vsPV; } -void EMEventCut::print() const -{ - LOG(info) << "EM Event Cut:"; - for (int i = 0; i < static_cast(EMEventCuts::kNCuts); i++) { - switch (static_cast(i)) { - case EMEventCuts::kFT0AND: - LOG(info) << mCutNames[i] << " = " << mRequireFT0AND; - break; - case EMEventCuts::kZvtx: - LOG(info) << mCutNames[i] << " in [" << mMinZvtx << ", " << mMaxZvtx << "]"; - break; - case EMEventCuts::kNoTFB: - LOG(info) << mCutNames[i] << " = " << mRequireNoTFB; - break; - case EMEventCuts::kNoITSROFB: - LOG(info) << mCutNames[i] << " = " << mRequireNoITSROFB; - break; - - default: - LOG(fatal) << "Cut unknown!"; - } - } +void EMEventCut::SetRequireNoCollInTimeRangeStandard(bool flag) +{ + mRequireNoCollInTimeRangeStandard = flag; + LOG(info) << "EM Event Cut, require No collision in time range standard: " << mRequireNoCollInTimeRangeStandard; +} + +void EMEventCut::SetRequireNoCollInTimeRangeStrict(bool flag) +{ + mRequireNoCollInTimeRangeStrict = flag; + LOG(info) << "EM Event Cut, require No collision in time range strict: " << mRequireNoCollInTimeRangeStrict; +} +void EMEventCut::SetRequireNoCollInITSROFStandard(bool flag) +{ + mRequireNoCollInITSROFStandard = flag; + LOG(info) << "EM Event Cut, require No collision in ITS TOF standard: " << mRequireNoCollInITSROFStandard; +} + +void EMEventCut::SetRequireNoCollInITSROFStrict(bool flag) +{ + mRequireNoCollInITSROFStrict = flag; + LOG(info) << "EM Event Cut, require No collision in ITS ROF strict: " << mRequireNoCollInITSROFStrict; +} + +void EMEventCut::SetRequireNoHighMultCollInPrevRof(bool flag) +{ + mRequireNoHighMultCollInPrevRof = flag; + LOG(info) << "EM Event Cut, require No HM collision in previous ITS ROF: " << mRequireNoHighMultCollInPrevRof; +} + +void EMEventCut::SetRequireGoodITSLayer3(bool flag) +{ + mRequireGoodITSLayer3 = flag; + LOG(info) << "EM Event Cut, require GoodITSLayer3: " << mRequireGoodITSLayer3; +} + +void EMEventCut::SetRequireGoodITSLayer0123(bool flag) +{ + mRequireGoodITSLayer0123 = flag; + LOG(info) << "EM Event Cut, require GoodITSLayer0123: " << mRequireGoodITSLayer0123; +} + +void EMEventCut::SetRequireGoodITSLayersAll(bool flag) +{ + mRequireGoodITSLayersAll = flag; + LOG(info) << "EM Event Cut, require GoodITSLayersAll: " << mRequireGoodITSLayersAll; } diff --git a/PWGEM/PhotonMeson/Core/EMEventCut.h b/PWGEM/Dilepton/Core/EMEventCut.h similarity index 51% rename from PWGEM/PhotonMeson/Core/EMEventCut.h rename to PWGEM/Dilepton/Core/EMEventCut.h index cb225ad1c24..7434b6e3f72 100644 --- a/PWGEM/PhotonMeson/Core/EMEventCut.h +++ b/PWGEM/Dilepton/Core/EMEventCut.h @@ -10,11 +10,11 @@ // or submit itself to any jurisdiction. // -// Class for em photon event selection +// Class for em event selection // -#ifndef PWGEM_PHOTONMESON_CORE_EMEVENTCUT_H_ -#define PWGEM_PHOTONMESON_CORE_EMEVENTCUT_H_ +#ifndef PWGEM_DILEPTON_CORE_EMEVENTCUT_H_ +#define PWGEM_DILEPTON_CORE_EMEVENTCUT_H_ #include "TNamed.h" #include "Common/CCDB/EventSelectionParams.h" @@ -27,6 +27,7 @@ class EMEventCut : public TNamed public: EMEventCut() = default; EMEventCut(const char* name, const char* title) : TNamed(name, title) {} + ~EMEventCut() {} enum class EMEventCuts : int { kSel8 = 0, @@ -37,11 +38,17 @@ class EMEventCut : public TNamed kNoSameBunchPileup, kIsVertexITSTPC, kIsGoodZvtxFT0vsPV, + kNoCollInTimeRangeStandard, + kNoCollInTimeRangeStrict, + kNoCollInITSROFStandard, + kNoCollInITSROFStrict, + kNoHighMultCollInPrevRof, + kIsGoodITSLayer3, + kIsGoodITSLayer0123, + kIsGoodITSLayersAll, kNCuts }; - static const char* mCutNames[static_cast(EMEventCuts::kNCuts)]; - template bool IsSelected(T const& collision) const { @@ -69,6 +76,30 @@ class EMEventCut : public TNamed if (mRequireGoodZvtxFT0vsPV && !IsSelected(collision, EMEventCuts::kIsGoodZvtxFT0vsPV)) { return false; } + if (mRequireNoCollInTimeRangeStandard && !IsSelected(collision, EMEventCuts::kNoCollInTimeRangeStandard)) { + return false; + } + if (mRequireNoCollInTimeRangeStrict && !IsSelected(collision, EMEventCuts::kNoCollInTimeRangeStrict)) { + return false; + } + if (mRequireNoCollInITSROFStandard && !IsSelected(collision, EMEventCuts::kNoCollInITSROFStandard)) { + return false; + } + if (mRequireNoCollInITSROFStrict && !IsSelected(collision, EMEventCuts::kNoCollInITSROFStrict)) { + return false; + } + if (mRequireNoHighMultCollInPrevRof && !IsSelected(collision, EMEventCuts::kNoHighMultCollInPrevRof)) { + return false; + } + if (mRequireGoodITSLayer3 && !IsSelected(collision, EMEventCuts::kIsGoodITSLayer3)) { + return false; + } + if (mRequireGoodITSLayer0123 && !IsSelected(collision, EMEventCuts::kIsGoodITSLayer0123)) { + return false; + } + if (mRequireGoodITSLayersAll && !IsSelected(collision, EMEventCuts::kIsGoodITSLayersAll)) { + return false; + } return true; } @@ -100,8 +131,32 @@ class EMEventCut : public TNamed case EMEventCuts::kIsGoodZvtxFT0vsPV: return collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV); + case EMEventCuts::kNoCollInTimeRangeStandard: + return collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard); + + case EMEventCuts::kNoCollInTimeRangeStrict: + return collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict); + + case EMEventCuts::kNoCollInITSROFStandard: + return collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard); + + case EMEventCuts::kNoCollInITSROFStrict: + return collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict); + + case EMEventCuts::kNoHighMultCollInPrevRof: + return collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof); + + case EMEventCuts::kIsGoodITSLayer3: + return collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer3); + + case EMEventCuts::kIsGoodITSLayer0123: + return collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123); + + case EMEventCuts::kIsGoodITSLayersAll: + return collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll); + default: - return false; + return true; } } @@ -113,22 +168,35 @@ class EMEventCut : public TNamed void SetRequireNoITSROFB(bool flag); void SetRequireNoSameBunchPileup(bool flag); void SetRequireVertexITSTPC(bool flag); - void SetRequireIsGoodZvtxFT0vsPV(bool flag); - - /// @brief Print the track selection - void print() const; + void SetRequireGoodZvtxFT0vsPV(bool flag); + void SetRequireNoCollInTimeRangeStandard(bool flag); + void SetRequireNoCollInTimeRangeStrict(bool flag); + void SetRequireNoCollInITSROFStandard(bool flag); + void SetRequireNoCollInITSROFStrict(bool flag); + void SetRequireNoHighMultCollInPrevRof(bool flag); + void SetRequireGoodITSLayer3(bool flag); + void SetRequireGoodITSLayer0123(bool flag); + void SetRequireGoodITSLayersAll(bool flag); private: - bool mRequireSel8{true}; + bool mRequireSel8{false}; bool mRequireFT0AND{true}; float mMinZvtx{-10.f}, mMaxZvtx{+10.f}; - bool mRequireNoTFB{true}; - bool mRequireNoITSROFB{true}; + bool mRequireNoTFB{false}; + bool mRequireNoITSROFB{false}; bool mRequireNoSameBunchPileup{false}; bool mRequireVertexITSTPC{false}; bool mRequireGoodZvtxFT0vsPV{false}; + bool mRequireNoCollInTimeRangeStandard{false}; + bool mRequireNoCollInTimeRangeStrict{false}; + bool mRequireNoCollInITSROFStandard{false}; + bool mRequireNoCollInITSROFStrict{false}; + bool mRequireNoHighMultCollInPrevRof{false}; + bool mRequireGoodITSLayer3{false}; + bool mRequireGoodITSLayer0123{false}; + bool mRequireGoodITSLayersAll{false}; ClassDef(EMEventCut, 1); }; -#endif // PWGEM_PHOTONMESON_CORE_EMEVENTCUT_H_ +#endif // PWGEM_DILEPTON_CORE_EMEVENTCUT_H_ diff --git a/PWGEM/Dilepton/Core/PWGEMDileptonCoreLinkDef.h b/PWGEM/Dilepton/Core/PWGEMDileptonCoreLinkDef.h new file mode 100644 index 00000000000..c1af31aa27b --- /dev/null +++ b/PWGEM/Dilepton/Core/PWGEMDileptonCoreLinkDef.h @@ -0,0 +1,23 @@ +// 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. + +#ifndef PWGEM_DILEPTON_CORE_PWGEMDILEPTONCORELINKDEF_H_ +#define PWGEM_DILEPTON_CORE_PWGEMDILEPTONCORELINKDEF_H_ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class EMEventCut + ; +#pragma link C++ class DielectronCut + ; +#pragma link C++ class DimuonCut + ; + +#endif // PWGEM_DILEPTON_CORE_PWGEMDILEPTONCORELINKDEF_H_ diff --git a/PWGEM/Dilepton/Core/PhotonHBT.h b/PWGEM/Dilepton/Core/PhotonHBT.h new file mode 100644 index 00000000000..b24f22cd5d8 --- /dev/null +++ b/PWGEM/Dilepton/Core/PhotonHBT.h @@ -0,0 +1,1472 @@ +// 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. +// +// ======================== +// +// This code loops over v0 photons and makes pairs for photon HBT analysis. +// Please write to: daiki.sekihata@cern.ch + +#ifndef PWGEM_DILEPTON_CORE_PHOTONHBT_H_ +#define PWGEM_DILEPTON_CORE_PHOTONHBT_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TString.h" +#include "Math/Vector4D.h" +#include "Math/Vector3D.h" +#include "Math/GenVector/Boost.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "Tools/ML/MlResponse.h" + +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "PWGEM/Dilepton/Core/DielectronCut.h" +#include "PWGEM/Dilepton/Utils/EMTrack.h" +#include "PWGEM/Dilepton/Utils/EventMixingHandler.h" +#include "PWGEM/Dilepton/Utils/EventHistograms.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" + +namespace o2::aod::pwgem::dilepton::core::photonhbt +{ +enum class ggHBTPairType : int { + kPCMPCM = 0, + kPCMEE = 1, + kEEEE = 2, +}; +} // namespace o2::aod::pwgem::dilepton::core::photonhbt + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; +using namespace o2::aod::pwgem::dilepton::utils; +using namespace o2::aod::pwgem::dilepton::core::photonhbt; + +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; + +using MyCollisionsWithSWT = soa::Join; +using MyCollisionWithSWT = MyCollisionsWithSWT::iterator; + +using MyV0Photons = soa::Join; +using MyV0Photon = MyV0Photons::iterator; + +using MyTracks = soa::Join; +using MyTrack = MyTracks::iterator; +using FilteredMyTracks = soa::Filtered; +using FilteredMyTrack = FilteredMyTracks::iterator; + +template +struct PhotonHBT { + + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + + Configurable cfgDo3D{"cfgDo3D", false, "enable 3D analysis"}; + Configurable cfgEP2Estimator_for_Mix{"cfgEP2Estimator_for_Mix", 3, "FT0M:0, FT0A:1, FT0C:2, BTot:3, BPos:4, BNeg:5"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgOccupancyEstimator{"cfgOccupancyEstimator", 0, "FT0C:0, Track:1"}; + Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999, "max. centrality"}; + Configurable maxY{"maxY", 0.8, "maximum rapidity for reconstructed particles"}; + Configurable cfgDoMix{"cfgDoMix", true, "flag for event mixing"}; + Configurable ndepth{"ndepth", 100, "depth for event mixing"}; + Configurable ndiff_bc_mix{"ndiff_bc_mix", 198, "difference in global BC required in mixed events"}; + ConfigurableAxis ConfVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis ConfCentBins{"ConfCentBins", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.f, 999.f}, "Mixing bins - centrality"}; + ConfigurableAxis ConfEPBins{"ConfEPBins", {16, -M_PI / 2, +M_PI / 2}, "Mixing bins - event plane angle"}; + ConfigurableAxis ConfOccupancyBins{"ConfOccupancyBins", {VARIABLE_WIDTH, -1, 1e+10}, "Mixing bins - occupancy"}; + Configurable cfg_swt_name{"cfg_swt_name", "fHighTrackMult", "desired software trigger name"}; // 1 trigger name per 1 task. fHighTrackMult, fHighFt0Mult + // Configurable cfgNtracksPV08Min{"cfgNtracksPV08Min", -1, "min. multNTracksPV"}; + // Configurable cfgNtracksPV08Max{"cfgNtracksPV08Max", static_cast(1e+9), "max. multNTracksPV"}; + Configurable cfgApplyWeightTTCA{"cfgApplyWeightTTCA", true, "flag to apply weighting by 1/N"}; + Configurable cfgUseLCMS{"cfgUseLCMS", true, "measure relative momentum in LCMS for 1D"}; // always in LCMS for 3D + + ConfigurableAxis ConfQBins{"ConfQBins", {60, 0, +0.3f}, "q bins for output histograms"}; + ConfigurableAxis ConfKtBins{"ConfKtBins", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0}, "kT bins for output histograms"}; + ConfigurableAxis ConfM1Bins{"ConfM1Bins", {VARIABLE_WIDTH, 0.0, 0.14, 0.5, 1.1, 2.0, 2.7, 3.2, 4.0}, "m1 bins for output histograms"}; + ConfigurableAxis ConfM2Bins{"ConfM2Bins", {VARIABLE_WIDTH, 0.0, 0.14, 0.5, 1.1, 2.0, 2.7, 3.2, 4.0}, "m2 bins for output histograms"}; + + EMEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; + Configurable cfgZvtxMax{"cfgZvtxMax", +10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", true, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", true, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. track occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. track occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInTimeRangeStrict{"cfgRequireNoCollInTimeRangeStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoCollInITSROFStandard{"cfgRequireNoCollInITSROFStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInITSROFStrict{"cfgRequireNoCollInITSROFStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoHighMultCollInPrevRof{"cfgRequireNoHighMultCollInPrevRof", false, "require no HM collision in previous ITS ROF"}; + Configurable cfgRequireGoodITSLayer3{"cfgRequireGoodITSLayer3", false, "number of inactive chips on ITS layer 3 are below threshold "}; + Configurable cfgRequireGoodITSLayer0123{"cfgRequireGoodITSLayer0123", false, "number of inactive chips on ITS layers 0-3 are below threshold "}; + Configurable cfgRequireGoodITSLayersAll{"cfgRequireGoodITSLayersAll", false, "number of inactive chips on all ITS layers are below threshold "}; + } eventcuts; + + V0PhotonCut fV0PhotonCut; + struct : ConfigurableGroup { + std::string prefix = "pcmcut_group"; + Configurable cfg_require_v0_with_itstpc{"cfg_require_v0_with_itstpc", false, "flag to select V0s with ITS-TPC matched tracks"}; + Configurable cfg_require_v0_with_itsonly{"cfg_require_v0_with_itsonly", false, "flag to select V0s with ITSonly tracks"}; + Configurable cfg_require_v0_with_tpconly{"cfg_require_v0_with_tpconly", false, "flag to select V0s with TPConly tracks"}; + Configurable cfg_min_pt_v0{"cfg_min_pt_v0", 0.1, "min pT for v0 photons at PV"}; + Configurable cfg_max_eta_v0{"cfg_max_eta_v0", 0.8, "max eta for v0 photons at PV"}; + Configurable cfg_min_v0radius{"cfg_min_v0radius", 4.0, "min v0 radius"}; + Configurable cfg_max_v0radius{"cfg_max_v0radius", 90.0, "max v0 radius"}; + Configurable cfg_max_alpha_ap{"cfg_max_alpha_ap", 0.95, "max alpha for AP cut"}; + Configurable cfg_max_qt_ap{"cfg_max_qt_ap", 0.01, "max qT for AP cut"}; + Configurable cfg_min_cospa{"cfg_min_cospa", 0.997, "min V0 CosPA"}; + Configurable cfg_max_pca{"cfg_max_pca", 3.0, "max distance btween 2 legs"}; + Configurable cfg_max_chi2kf{"cfg_max_chi2kf", 1e+10, "max chi2/ndf with KF"}; + Configurable cfg_require_v0_with_correct_xz{"cfg_require_v0_with_correct_xz", true, "flag to select V0s with correct xz"}; + Configurable cfg_reject_v0_on_itsib{"cfg_reject_v0_on_itsib", true, "flag to reject V0s on ITSib"}; + + Configurable cfg_disable_itsonly_track{"cfg_disable_itsonly_track", false, "flag to disable ITSonly tracks"}; + Configurable cfg_disable_tpconly_track{"cfg_disable_tpconly_track", false, "flag to disable TPConly tracks"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 10, "min ncluster tpc"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 40, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -3.0, "min. TPC n sigma for electron"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; + } pcmcuts; + + DielectronCut fDielectronCut; + struct : ConfigurableGroup { + std::string prefix = "dielectroncut_group"; + Configurable cfg_min_mass{"cfg_min_mass", 0.0, "min mass"}; + Configurable cfg_max_mass{"cfg_max_mass", 0.015, "max mass"}; // this is valid, because only ULS is used. + Configurable cfg_min_pair_pt{"cfg_min_pair_pt", 0.0, "min pair pT"}; + Configurable cfg_max_pair_pt{"cfg_max_pair_pt", 1e+10, "max pair pT"}; + Configurable cfg_min_pair_y{"cfg_min_pair_y", -0.8, "min pair rapidity"}; + Configurable cfg_max_pair_y{"cfg_max_pair_y", +0.8, "max pair rapidity"}; + Configurable cfg_min_pair_dca3d{"cfg_min_pair_dca3d", 0.0, "min pair dca3d in sigma"}; + Configurable cfg_max_pair_dca3d{"cfg_max_pair_dca3d", 1e+10, "max pair dca3d in sigma"}; + Configurable cfg_apply_phiv{"cfg_apply_phiv", true, "flag to apply phiv cut"}; + Configurable cfg_apply_pf{"cfg_apply_pf", false, "flag to apply phiv prefilter"}; + Configurable cfg_phiv_slope{"cfg_phiv_slope", 0.0185, "slope for m vs. phiv"}; + Configurable cfg_phiv_intercept{"cfg_phiv_intercept", -0.0280, "intercept for m vs. phiv"}; + Configurable cfg_min_phiv{"cfg_min_phiv", 0.0, "min phiv (constant)"}; + Configurable cfg_max_phiv{"cfg_max_phiv", 3.2, "max phiv (constant)"}; + + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -0.8, "max eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", +0.8, "max eta for single track"}; + Configurable cfg_max_dca3dsigma_track{"cfg_max_dca3dsigma_track", 1e+10, "max DCA 3D in sigma"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 100, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_chi2tof{"cfg_max_chi2tof", 1e+10, "max chi2 TOF"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 0.1, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 0.2, "max dca Z for single track in cm"}; + Configurable cfg_min_its_cluster_size{"cfg_min_its_cluster_size", 0.f, "min ITS cluster size"}; + Configurable cfg_max_its_cluster_size{"cfg_max_its_cluster_size", 16.f, "max ITS cluster size"}; + Configurable cfg_min_p_its_cluster_size{"cfg_min_p_its_cluster_size", 0.0, "min p to apply ITS cluster size cut"}; + Configurable cfg_max_p_its_cluster_size{"cfg_max_p_its_cluster_size", 0.0, "max p to apply ITS cluster size cut"}; + Configurable cfg_min_rel_diff_pin{"cfg_min_rel_diff_pin", -1e+10, "min rel. diff. between pin and ppv"}; + Configurable cfg_max_rel_diff_pin{"cfg_max_rel_diff_pin", +1e+10, "max rel. diff. between pin and ppv"}; + Configurable cfg_require_itsib_any{"cfg_require_itsib_any", false, "flag to require ITS ib any hits"}; + Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; + + Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DielectronCut::PIDSchemes::kTPChadrejORTOFreq), "pid scheme [kTOFreq : 0, kTPChadrej : 1, kTPChadrejORTOFreq : 2, kTPConly : 3, kTOFif = 4, kPIDML = 5]"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + Configurable cfg_min_TPCNsigmaMu{"cfg_min_TPCNsigmaMu", -0.0, "min. TPC n sigma for muon exclusion"}; + Configurable cfg_max_TPCNsigmaMu{"cfg_max_TPCNsigmaMu", +0.0, "max. TPC n sigma for muon exclusion"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -3.0, "min. TPC n sigma for pion exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +3.0, "max. TPC n sigma for pion exclusion"}; + Configurable cfg_min_TPCNsigmaKa{"cfg_min_TPCNsigmaKa", -3.0, "min. TPC n sigma for kaon exclusion"}; + Configurable cfg_max_TPCNsigmaKa{"cfg_max_TPCNsigmaKa", +3.0, "max. TPC n sigma for kaon exclusion"}; + Configurable cfg_min_TPCNsigmaPr{"cfg_min_TPCNsigmaPr", -3.0, "min. TPC n sigma for proton exclusion"}; + Configurable cfg_max_TPCNsigmaPr{"cfg_max_TPCNsigmaPr", +3.0, "max. TPC n sigma for proton exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; + Configurable cfg_max_pin_pirejTPC{"cfg_max_pin_pirejTPC", 0.5, "max. pin for pion rejection in TPC"}; + Configurable cfg_min_ITSNsigmaKa{"cfg_min_ITSNsigmaKa", -1.0, "min. ITS n sigma for kaon exclusion"}; + Configurable cfg_max_ITSNsigmaKa{"cfg_max_ITSNsigmaKa", 1e+10, "max. ITS n sigma for kaon exclusion"}; + Configurable cfg_min_ITSNsigmaPr{"cfg_min_ITSNsigmaPr", -1.0, "min. ITS n sigma for proton exclusion"}; + Configurable cfg_max_ITSNsigmaPr{"cfg_max_ITSNsigmaPr", 1e+10, "max. ITS n sigma for proton exclusion"}; + Configurable cfg_min_p_ITSNsigmaKa{"cfg_min_p_ITSNsigmaKa", 0.0, "min p for kaon exclusion in ITS"}; + Configurable cfg_max_p_ITSNsigmaKa{"cfg_max_p_ITSNsigmaKa", 0.0, "max p for kaon exclusion in ITS"}; + Configurable cfg_min_p_ITSNsigmaPr{"cfg_min_p_ITSNsigmaPr", 0.0, "min p for proton exclusion in ITS"}; + Configurable cfg_max_p_ITSNsigmaPr{"cfg_max_p_ITSNsigmaPr", 0.0, "max p for proton exclusion in ITS"}; + Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; + + // configuration for PID ML + Configurable> onnxFileNames{"onnxFileNames", std::vector{"filename"}, "ONNX file names for each bin (if not from CCDB full path)"}; + Configurable> onnxPathsCCDB{"onnxPathsCCDB", std::vector{"path"}, "Paths of models on CCDB"}; + Configurable> binsMl{"binsMl", std::vector{-999999., 999999.}, "Bin limits for ML application"}; + Configurable> cutsMl{"cutsMl", std::vector{0.95}, "ML cuts per bin"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature"}, "Names of ML model input features"}; + Configurable nameBinningFeature{"nameBinningFeature", "pt", "Names of ML model binning feature"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + Configurable enableOptimizations{"enableOptimizations", false, "Enables the ONNX extended model-optimization: sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED)"}; + } dielectroncuts; + + struct : ConfigurableGroup { + std::string prefix = "ggpaircut_group"; + // Configurable applydRdZ{"applydRdZ", false, "apply dr-dz cut to avoid track splitting/merging only for kPCMPCM"}; + // Configurable cfgMinDeltaR{"cfgMinDeltaR", 20.f, "min. delta-r between 2 conversion points only for kPCMPCM"}; + // Configurable cfgMinDeltaZ{"cfgMinDeltaZ", 20.f, "min. delta-z between 2 conversion points only for kPCMPCM"}; + + Configurable applydEtadPhi_Photon{"applydEtadPhi_Photon", false, "apply deta-dphi cut to avoid track splitting/merging"}; + Configurable cfgMinDeltaEta_Photon{"cfgMinDeltaEta_Photon", 0.1f, "min. delta-eta between 2 photons"}; + Configurable cfgMinDeltaPhi_Photon{"cfgMinDeltaPhi_Photon", 0.3f, "min. delta-phi between 2 photons"}; + + // Configurable applydEtadPhi_Leg{"applydEtadPhi_Leg", false, "apply deta-dphi cut to avoid track splitting/merging"}; + // Configurable cfgMinDeltaEta_Leg{"cfgMinDeltaEta_Leg", 0.1f, "min. delta-eta between 2 LS tracks"}; + // Configurable cfgMinDeltaPhi_Leg{"cfgMinDeltaPhi_Leg", 0.3f, "min. delta-phi between 2 LS tracks"}; + } ggpaircuts; + + ~PhotonHBT() + { + delete emh1; + emh1 = 0x0; + delete emh2; + emh2 = 0x0; + + map_mixed_eventId_to_globalBC.clear(); + + used_photonIds.clear(); + used_photonIds.shrink_to_fit(); + used_dileptonIds.clear(); + used_dileptonIds.shrink_to_fit(); + } + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view event_types[2] = {"before", "after"}; + static constexpr std::string_view event_pair_types[2] = {"same/", "mix/"}; + + std::mt19937 engine; + std::uniform_int_distribution dist01; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + int mRunNumber; + float d_bz; + + std::vector zvtx_bin_edges; + std::vector cent_bin_edges; + std::vector ep_bin_edges; + std::vector occ_bin_edges; + + void init(InitContext& /*context*/) + { + if (ConfVtxBins.value[0] == VARIABLE_WIDTH) { + zvtx_bin_edges = std::vector(ConfVtxBins.value.begin(), ConfVtxBins.value.end()); + zvtx_bin_edges.erase(zvtx_bin_edges.begin()); + for (auto& edge : zvtx_bin_edges) { + LOGF(info, "VARIABLE_WIDTH: zvtx_bin_edges = %f", edge); + } + } else { + int nbins = static_cast(ConfVtxBins.value[0]); + float xmin = static_cast(ConfVtxBins.value[1]); + float xmax = static_cast(ConfVtxBins.value[2]); + zvtx_bin_edges.resize(nbins + 1); + for (int i = 0; i < nbins + 1; i++) { + zvtx_bin_edges[i] = (xmax - xmin) / (nbins)*i + xmin; + LOGF(info, "FIXED_WIDTH: zvtx_bin_edges[%d] = %f", i, zvtx_bin_edges[i]); + } + } + + if (ConfCentBins.value[0] == VARIABLE_WIDTH) { + cent_bin_edges = std::vector(ConfCentBins.value.begin(), ConfCentBins.value.end()); + cent_bin_edges.erase(cent_bin_edges.begin()); + for (auto& edge : cent_bin_edges) { + LOGF(info, "VARIABLE_WIDTH: cent_bin_edges = %f", edge); + } + } else { + int nbins = static_cast(ConfCentBins.value[0]); + float xmin = static_cast(ConfCentBins.value[1]); + float xmax = static_cast(ConfCentBins.value[2]); + cent_bin_edges.resize(nbins + 1); + for (int i = 0; i < nbins + 1; i++) { + cent_bin_edges[i] = (xmax - xmin) / (nbins)*i + xmin; + LOGF(info, "FIXED_WIDTH: cent_bin_edges[%d] = %f", i, cent_bin_edges[i]); + } + } + + if (ConfEPBins.value[0] == VARIABLE_WIDTH) { + ep_bin_edges = std::vector(ConfEPBins.value.begin(), ConfEPBins.value.end()); + ep_bin_edges.erase(ep_bin_edges.begin()); + for (auto& edge : ep_bin_edges) { + LOGF(info, "VARIABLE_WIDTH: ep_bin_edges = %f", edge); + } + } else { + int nbins = static_cast(ConfEPBins.value[0]); + float xmin = static_cast(ConfEPBins.value[1]); + float xmax = static_cast(ConfEPBins.value[2]); + ep_bin_edges.resize(nbins + 1); + for (int i = 0; i < nbins + 1; i++) { + ep_bin_edges[i] = (xmax - xmin) / (nbins)*i + xmin; + LOGF(info, "FIXED_WIDTH: ep_bin_edges[%d] = %f", i, ep_bin_edges[i]); + } + } + + LOGF(info, "cfgOccupancyEstimator = %d", cfgOccupancyEstimator.value); + if (ConfOccupancyBins.value[0] == VARIABLE_WIDTH) { + occ_bin_edges = std::vector(ConfOccupancyBins.value.begin(), ConfOccupancyBins.value.end()); + occ_bin_edges.erase(occ_bin_edges.begin()); + for (auto& edge : occ_bin_edges) { + LOGF(info, "VARIABLE_WIDTH: occ_bin_edges = %f", edge); + } + } else { + int nbins = static_cast(ConfOccupancyBins.value[0]); + float xmin = static_cast(ConfOccupancyBins.value[1]); + float xmax = static_cast(ConfOccupancyBins.value[2]); + occ_bin_edges.resize(nbins + 1); + for (int i = 0; i < nbins + 1; i++) { + occ_bin_edges[i] = (xmax - xmin) / (nbins)*i + xmin; + LOGF(info, "FIXED_WIDTH: occ_bin_edges[%d] = %f", i, occ_bin_edges[i]); + } + } + + emh1 = new MyEMH(ndepth); + emh2 = new MyEMH(ndepth); + + DefineEMEventCut(); + DefinePCMCut(); + DefineDileptonCut(); + + addhistograms(); + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + std::random_device seed_gen; + engine = std::mt19937(seed_gen()); + dist01 = std::uniform_int_distribution(0, 1); + + fRegistry.add("Pair/mix/hDiffBC", "diff. global BC in mixed event;|BC_{current} - BC_{mixed}|", kTH1D, {{10001, -0.5, 10000.5}}, true); + if (doprocessTriggerAnalysis) { + fRegistry.add("Event/hNInspectedTVX", "N inspected TVX;run number;N_{TVX}", kTProfile, {{80000, 520000.5, 600000.5}}, true); + } + } + + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (std::fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + mRunNumber = collision.runNumber(); + return; + } + + auto run3grp_timestamp = collision.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = collision.runNumber(); + + if constexpr (isTriggerAnalysis) { + LOGF(info, "Trigger analysis is enabled. Desired trigger name = %s", cfg_swt_name.value); + LOGF(info, "total inspected TVX events = %d in run number %d", collision.nInspectedTVX(), collision.runNumber()); + fRegistry.fill(HIST("Event/hNInspectedTVX"), collision.runNumber(), collision.nInspectedTVX()); + } + } + + void addhistograms() + { + o2::aod::pwgem::dilepton::utils::eventhistogram::addEventHistograms<-1>(&fRegistry); + std::string_view qvec_det_names[6] = {"FT0M", "FT0A", "FT0C", "BTot", "BPos", "BNeg"}; + fRegistry.add("Event/before/hEP2_CentFT0C_forMix", Form("2nd harmonics event plane for mix;centrality FT0C (%%);#Psi_{2}^{%s} (rad.)", qvec_det_names[cfgEP2Estimator_for_Mix].data()), kTH2F, {{110, 0, 110}, {180, -M_PI_2, +M_PI_2}}, false); + fRegistry.add("Event/after/hEP2_CentFT0C_forMix", Form("2nd harmonics event plane for mix;centrality FT0C (%%);#Psi_{2}^{%s} (rad.)", qvec_det_names[cfgEP2Estimator_for_Mix].data()), kTH2F, {{110, 0, 110}, {180, -M_PI_2, +M_PI_2}}, false); + + // pair info + std::string m1_axis_title = "m_{#gamma} (GeV/c^{2})"; + std::string m2_axis_title = "m_{#gamma*} (GeV/c^{2})"; + if constexpr (pairtype == ggHBTPairType::kPCMPCM) { + m1_axis_title = "m_{#gamma} (GeV/c^{2})"; + m2_axis_title = "m_{#gamma} (GeV/c^{2})"; + } else if constexpr (pairtype == ggHBTPairType::kPCMEE) { + m1_axis_title = "m_{#gamma} (GeV/c^{2})"; + m2_axis_title = "m_{#gamma*} (GeV/c^{2})"; + } else if constexpr (pairtype == ggHBTPairType::kEEEE) { + m1_axis_title = "m_{#gamma*} (GeV/c^{2})"; + m2_axis_title = "m_{#gamma*} (GeV/c^{2})"; + } + const AxisSpec axis_m1{ConfM1Bins, m1_axis_title}; + const AxisSpec axis_m2{ConfM2Bins, m2_axis_title}; + + const AxisSpec axis_kt{ConfKtBins, "k_{T} (GeV/c)"}; + const AxisSpec axis_qinv{ConfQBins, "q_{inv} (GeV/c)"}; + const AxisSpec axis_qabs_lcms{ConfQBins, "|#bf{q}|^{LCMS} (GeV/c)"}; + const AxisSpec axis_qout{ConfQBins, "q_{out} (GeV/c)"}; // qout does not change between LAB and LCMS frame + const AxisSpec axis_qside{ConfQBins, "q_{side} (GeV/c)"}; // qside does not change between LAB and LCMS frame + const AxisSpec axis_qlong{ConfQBins, "q_{long} (GeV/c)"}; + + if (cfgDo3D) { // 3D + fRegistry.add("Pair/same/hs_3d", "diphoton correlation 3D LCMS", kTHnSparseD, {axis_qout, axis_qside, axis_qlong, axis_kt, axis_m1, axis_m2}, true); + } else { // 1D + if (cfgUseLCMS) { + fRegistry.add("Pair/same/hs_1d", "diphoton correlation 1D LCMS", kTHnSparseD, {axis_qabs_lcms, axis_kt, axis_m1, axis_m2}, true); + } else { + fRegistry.add("Pair/same/hs_1d", "diphoton correlation 1D", kTHnSparseD, {axis_qinv, axis_kt, axis_m1, axis_m2}, true); + } + } + + fRegistry.add("Pair/same/hDeltaEtaDeltaPhi_Photon", "distance between 2 photons in #eta-#varphi plane;#Delta#varphi (rad.);#Delta#eta", kTH2D, {{180, -M_PI, M_PI}, {400, -2, +2}}, true); // deta, dphi of photon momentum + // fRegistry.add("Pair/same/hDeltaEtaDeltaPhi_Leg", "distance between 2 LS tracks in #eta-#varphi plane;#Delta#varphi (rad.);#Delta#eta", kTH2D, {{180, -M_PI, M_PI}, {400, -2, +2}}, true); // deta, dphi of track momentum + // if constexpr (pairtype == ggHBTPairType::kPCMPCM) { + // fRegistry.add("Pair/same/hDeltaRDeltaZ", "diphoton distance in RZ;#Deltar = #sqrt{(#Deltax)^{2} + (#Deltay)^{2}} (cm);|#Deltaz| (cm)", kTH2D, {{100, 0, 50}, {100, 0, 50}}, true); // dr, dz of conversion points + // } + + fRegistry.addClone("Pair/same/", "Pair/mix/"); + } + + void DefineEMEventCut() + { + fEMEventCut = EMEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(eventcuts.cfgZvtxMin, eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireNoCollInTimeRangeStandard(eventcuts.cfgRequireNoCollInTimeRangeStandard); + fEMEventCut.SetRequireNoCollInTimeRangeStrict(eventcuts.cfgRequireNoCollInTimeRangeStrict); + fEMEventCut.SetRequireNoCollInITSROFStandard(eventcuts.cfgRequireNoCollInITSROFStandard); + fEMEventCut.SetRequireNoCollInITSROFStrict(eventcuts.cfgRequireNoCollInITSROFStrict); + fEMEventCut.SetRequireNoHighMultCollInPrevRof(eventcuts.cfgRequireNoHighMultCollInPrevRof); + fEMEventCut.SetRequireGoodITSLayer3(eventcuts.cfgRequireGoodITSLayer3); + fEMEventCut.SetRequireGoodITSLayer0123(eventcuts.cfgRequireGoodITSLayer0123); + fEMEventCut.SetRequireGoodITSLayersAll(eventcuts.cfgRequireGoodITSLayersAll); + } + + void DefinePCMCut() + { + fV0PhotonCut = V0PhotonCut("fV0PhotonCut", "fV0PhotonCut"); + + // for v0 + fV0PhotonCut.SetV0PtRange(pcmcuts.cfg_min_pt_v0, 1e10f); + fV0PhotonCut.SetV0EtaRange(-pcmcuts.cfg_max_eta_v0, +pcmcuts.cfg_max_eta_v0); + fV0PhotonCut.SetMinCosPA(pcmcuts.cfg_min_cospa); + fV0PhotonCut.SetMaxPCA(pcmcuts.cfg_max_pca); + fV0PhotonCut.SetMaxChi2KF(pcmcuts.cfg_max_chi2kf); + fV0PhotonCut.SetRxyRange(pcmcuts.cfg_min_v0radius, pcmcuts.cfg_max_v0radius); + fV0PhotonCut.SetAPRange(pcmcuts.cfg_max_alpha_ap, pcmcuts.cfg_max_qt_ap); + fV0PhotonCut.RejectITSib(pcmcuts.cfg_reject_v0_on_itsib); + + // for track + fV0PhotonCut.SetMinNClustersTPC(pcmcuts.cfg_min_ncluster_tpc); + fV0PhotonCut.SetMinNCrossedRowsTPC(pcmcuts.cfg_min_ncrossedrows); + fV0PhotonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fV0PhotonCut.SetMaxFracSharedClustersTPC(pcmcuts.cfg_max_frac_shared_clusters_tpc); + fV0PhotonCut.SetChi2PerClusterTPC(0.0, pcmcuts.cfg_max_chi2tpc); + fV0PhotonCut.SetTPCNsigmaElRange(pcmcuts.cfg_min_TPCNsigmaEl, pcmcuts.cfg_max_TPCNsigmaEl); + fV0PhotonCut.SetChi2PerClusterITS(-1e+10, pcmcuts.cfg_max_chi2its); + fV0PhotonCut.SetDisableITSonly(pcmcuts.cfg_disable_itsonly_track); + fV0PhotonCut.SetDisableTPConly(pcmcuts.cfg_disable_tpconly_track); + fV0PhotonCut.SetNClustersITS(0, 7); + fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); + fV0PhotonCut.SetIsWithinBeamPipe(pcmcuts.cfg_require_v0_with_correct_xz); + fV0PhotonCut.SetRequireITSTPC(pcmcuts.cfg_require_v0_with_itstpc); + fV0PhotonCut.SetRequireITSonly(pcmcuts.cfg_require_v0_with_itsonly); + fV0PhotonCut.SetRequireTPConly(pcmcuts.cfg_require_v0_with_tpconly); + } + + o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; + void DefineDileptonCut() + { + fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); + + // for pair + fDielectronCut.SetMeeRange(dielectroncuts.cfg_min_mass, dielectroncuts.cfg_max_mass); + fDielectronCut.SetPairPtRange(dielectroncuts.cfg_min_pair_pt, dielectroncuts.cfg_max_pair_pt); + fDielectronCut.SetPairYRange(dielectroncuts.cfg_min_pair_y, dielectroncuts.cfg_max_pair_y); + fDielectronCut.SetMaxMeePhiVDep([&](float phiv) { return dielectroncuts.cfg_phiv_intercept + phiv * dielectroncuts.cfg_phiv_slope; }, dielectroncuts.cfg_min_phiv, dielectroncuts.cfg_max_phiv); + fDielectronCut.SetPairDCARange(dielectroncuts.cfg_min_pair_dca3d, dielectroncuts.cfg_max_pair_dca3d); // in sigma + fDielectronCut.ApplyPhiV(dielectroncuts.cfg_apply_phiv); + fDielectronCut.ApplyPrefilter(dielectroncuts.cfg_apply_pf); + fDielectronCut.RequireITSibAny(dielectroncuts.cfg_require_itsib_any); + fDielectronCut.RequireITSib1st(dielectroncuts.cfg_require_itsib_1st); + + // for track + fDielectronCut.SetTrackPtRange(dielectroncuts.cfg_min_pt_track, dielectroncuts.cfg_max_pt_track); + fDielectronCut.SetTrackEtaRange(dielectroncuts.cfg_min_eta_track, dielectroncuts.cfg_max_eta_track); + fDielectronCut.SetTrackDca3DRange(0.f, dielectroncuts.cfg_max_dca3dsigma_track); // in sigma + fDielectronCut.SetMinNClustersTPC(dielectroncuts.cfg_min_ncluster_tpc); + fDielectronCut.SetMinNCrossedRowsTPC(dielectroncuts.cfg_min_ncrossedrows); + fDielectronCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fDielectronCut.SetMaxFracSharedClustersTPC(dielectroncuts.cfg_max_frac_shared_clusters_tpc); + fDielectronCut.SetChi2PerClusterTPC(0.0, dielectroncuts.cfg_max_chi2tpc); + fDielectronCut.SetChi2PerClusterITS(0.0, dielectroncuts.cfg_max_chi2its); + fDielectronCut.SetNClustersITS(dielectroncuts.cfg_min_ncluster_its, 7); + fDielectronCut.SetMeanClusterSizeITS(dielectroncuts.cfg_min_its_cluster_size, dielectroncuts.cfg_max_its_cluster_size, dielectroncuts.cfg_min_p_its_cluster_size, dielectroncuts.cfg_max_p_its_cluster_size); + fDielectronCut.SetTrackMaxDcaXY(dielectroncuts.cfg_max_dcaxy); + fDielectronCut.SetTrackMaxDcaZ(dielectroncuts.cfg_max_dcaz); + fDielectronCut.SetChi2TOF(0.0, dielectroncuts.cfg_max_chi2tof); + fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); + + // for eID + fDielectronCut.SetPIDScheme(dielectroncuts.cfg_pid_scheme); + fDielectronCut.SetTPCNsigmaElRange(dielectroncuts.cfg_min_TPCNsigmaEl, dielectroncuts.cfg_max_TPCNsigmaEl); + fDielectronCut.SetTPCNsigmaMuRange(dielectroncuts.cfg_min_TPCNsigmaMu, dielectroncuts.cfg_max_TPCNsigmaMu); + fDielectronCut.SetTPCNsigmaPiRange(dielectroncuts.cfg_min_TPCNsigmaPi, dielectroncuts.cfg_max_TPCNsigmaPi); + fDielectronCut.SetTPCNsigmaKaRange(dielectroncuts.cfg_min_TPCNsigmaKa, dielectroncuts.cfg_max_TPCNsigmaKa); + fDielectronCut.SetTPCNsigmaPrRange(dielectroncuts.cfg_min_TPCNsigmaPr, dielectroncuts.cfg_max_TPCNsigmaPr); + fDielectronCut.SetTOFNsigmaElRange(dielectroncuts.cfg_min_TOFNsigmaEl, dielectroncuts.cfg_max_TOFNsigmaEl); + fDielectronCut.SetMaxPinForPionRejectionTPC(dielectroncuts.cfg_max_pin_pirejTPC); + fDielectronCut.SetITSNsigmaKaRange(dielectroncuts.cfg_min_ITSNsigmaKa, dielectroncuts.cfg_max_ITSNsigmaKa); + fDielectronCut.SetITSNsigmaPrRange(dielectroncuts.cfg_min_ITSNsigmaPr, dielectroncuts.cfg_max_ITSNsigmaPr); + fDielectronCut.SetPRangeForITSNsigmaKa(dielectroncuts.cfg_min_p_ITSNsigmaKa, dielectroncuts.cfg_max_p_ITSNsigmaKa); + fDielectronCut.SetPRangeForITSNsigmaPr(dielectroncuts.cfg_min_p_ITSNsigmaPr, dielectroncuts.cfg_max_p_ITSNsigmaPr); + + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { // please call this at the end of DefineDileptonCut + static constexpr int nClassesMl = 2; + const std::vector cutDirMl = {o2::cuts_ml::CutSmaller, o2::cuts_ml::CutNot}; + const std::vector labelsClasses = {"Signal", "Background"}; + const uint32_t nBinsMl = dielectroncuts.binsMl.value.size() - 1; + const std::vector labelsBins(nBinsMl, "bin"); + double cutsMlArr[nBinsMl][nClassesMl]; + for (uint32_t i = 0; i < nBinsMl; i++) { + cutsMlArr[i][0] = dielectroncuts.cutsMl.value[i]; + cutsMlArr[i][1] = 0.; + } + o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; + + mlResponseSingleTrack.configure(dielectroncuts.binsMl.value, cutsMl, cutDirMl, nClassesMl); + if (dielectroncuts.loadModelsFromCCDB) { + ccdbApi.init(ccdburl); + mlResponseSingleTrack.setModelPathsCCDB(dielectroncuts.onnxFileNames.value, ccdbApi, dielectroncuts.onnxPathsCCDB.value, dielectroncuts.timestampCCDB.value); + } else { + mlResponseSingleTrack.setModelPathsLocal(dielectroncuts.onnxFileNames.value); + } + mlResponseSingleTrack.cacheInputFeaturesIndices(dielectroncuts.namesInputFeatures); + mlResponseSingleTrack.cacheBinningIndex(dielectroncuts.nameBinningFeature); + mlResponseSingleTrack.init(dielectroncuts.enableOptimizations.value); + + fDielectronCut.SetPIDMlResponse(&mlResponseSingleTrack); + } // end of PID ML + } + + template + void fillPairHistogram(TCollision const&, const ROOT::Math::PtEtaPhiMVector v1, const ROOT::Math::PtEtaPhiMVector v2, const float weight = 1.f) + { + float rndm = std::pow(-1, dist01(engine) % 2); // +1 or -1 to randomize order between 1 and 2. + // Lab. frame + ROOT::Math::PtEtaPhiMVector q12 = (v1 - v2) * rndm; + ROOT::Math::PtEtaPhiMVector k12 = 0.5 * (v1 + v2); + float qinv = -q12.M(); // for identical particles -> qinv = 2 x kstar + float kt = k12.Pt(); + + ROOT::Math::XYZVector uv_out(k12.Px() / k12.Pt(), k12.Py() / k12.Pt(), 0); // unit vector for out. i.e. parallel to kt + ROOT::Math::XYZVector uv_long(0, 0, 1); // unit vector for long, beam axis + ROOT::Math::XYZVector uv_side = uv_out.Cross(uv_long); // unit vector for side + + ROOT::Math::PxPyPzEVector v1_cartesian(v1); + ROOT::Math::PxPyPzEVector v2_cartesian(v2); + ROOT::Math::PxPyPzEVector q12_cartesian = (v1_cartesian - v2_cartesian) * rndm; + float beta = (v1 + v2).Beta(); + // float beta_x = beta * std::cos((v1 + v2).Phi()) * std::sin((v1 + v2).Theta()); + // float beta_y = beta * std::sin((v1 + v2).Phi()) * std::sin((v1 + v2).Theta()); + float beta_z = beta * std::cos((v1 + v2).Theta()); + + // longitudinally co-moving system (LCMS) + ROOT::Math::Boost bst_z(0, 0, -beta_z); // Boost supports only PxPyPzEVector + ROOT::Math::PxPyPzEVector q12_lcms = bst_z(q12_cartesian); + ROOT::Math::XYZVector q_3d_lcms = q12_lcms.Vect(); // 3D q vector in LCMS + float qout_lcms = q_3d_lcms.Dot(uv_out); + float qside_lcms = q_3d_lcms.Dot(uv_side); + float qlong_lcms = q_3d_lcms.Dot(uv_long); + float qabs_lcms = q_3d_lcms.R(); + + // float qabs_lcms_tmp = std::sqrt(std::pow(qout_lcms, 2) + std::pow(qside_lcms, 2) + std::pow(qlong_lcms, 2)); + // LOGF(info, "qabs_lcms = %f, qabs_lcms_tmp = %f", qabs_lcms, qabs_lcms_tmp); + + // // pair rest frame (PRF) + // ROOT::Math::Boost boostPRF = ROOT::Math::Boost(-beta_x, -beta_y, -beta_z); + // ROOT::Math::PxPyPzEVector v1_prf = boostPRF(v1_cartesian); + // ROOT::Math::PxPyPzEVector v2_prf = boostPRF(v2_cartesian); + // ROOT::Math::PxPyPzEVector rel_k = (v1_prf - v2_prf) * rndm; + // float kstar = 0.5 * rel_k.P(); + // // LOGF(info, "qabs_lcms = %f, qinv = %f, kstar = %f", qabs_lcms, qinv, kstar); + + // ROOT::Math::PxPyPzEVector v1_lcms_cartesian = bst_z(v1_cartesian); + // ROOT::Math::PxPyPzEVector v2_lcms_cartesian = bst_z(v2_cartesian); + // ROOT::Math::PxPyPzEVector q12_lcms_cartesian = bst_z(q12_cartesian); + // LOGF(info, "q12.Pz() = %f, q12_cartesian.Pz() = %f", q12.Pz(), q12_cartesian.Pz()); + // LOGF(info, "v1.Pz() = %f, v2.Pz() = %f", v1.Pz(), v2.Pz()); + // LOGF(info, "v1_lcms_cartesian.Pz() = %f, v2_lcms_cartesian.Pz() = %f", v1_lcms_cartesian.Pz(), v2_lcms_cartesian.Pz()); + // LOGF(info, "q12_lcms_cartesian.Pz() = %f", q12_lcms_cartesian.Pz()); + // LOGF(info, "q_3d_lcms.Dot(uv_out) = %f, q_3d_lcms.Dot(uv_side) = %f, q_3d.Dot(uv_out) = %f, q_3d.Dot(uv_side) = %f", q_3d_lcms.Dot(uv_out), q_3d_lcms.Dot(uv_side), q_3d.Dot(uv_out), q_3d.Dot(uv_side)); + // LOGF(info, "q12_lcms.Pz() = %f, q_3d_lcms.Dot(uv_long) = %f", q12_lcms.Pz(), q_3d_lcms.Dot(uv_long)); + // ROOT::Math::PxPyPzEVector q12_lcms_tmp = bst_z(v1_cartesian) - bst_z(v2_cartesian); + // LOGF(info, "q12_lcms.Px() = %f, q12_lcms.Py() = %f, q12_lcms.Pz() = %f, q12_lcms_tmp.Px() = %f, q12_lcms_tmp.Py() = %f, q12_lcms_tmp.Pz() = %f", q12_lcms.Px(), q12_lcms.Py(), q12_lcms.Pz(), q12_lcms_tmp.Px(), q12_lcms_tmp.Py(), q12_lcms_tmp.Pz()); + // float qabs_lcms_tmp = q12_lcms.P(); + // LOGF(info, "qabs_lcms = %f, qabs_lcms_tmp = %f", qabs_lcms, qabs_lcms_tmp); + + if (cfgDo3D) { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("hs_3d"), std::fabs(qout_lcms), std::fabs(qside_lcms), std::fabs(qlong_lcms), kt, v1.M(), v2.M(), weight); // qosl can be [-inf, +inf] and CF is symmetric for pos and neg qosl. To reduce stat. unc. absolute value is taken here. + } else { + if (cfgUseLCMS) { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("hs_1d"), qabs_lcms, kt, v1.M(), v2.M(), weight); + } else { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("hs_1d"), qinv, kt, v1.M(), v2.M(), weight); + } + } + } + + template + void runPairing(TCollisions const& collisions, TPhotons1 const& photons1, TPhotons2 const& photons2, TSubInfos1 const&, TSubInfos2 const&, TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, TCut1 const& cut1, TCut2 const& cut2) + { + for (auto& collision : collisions) { + initCCDB(collision); + int ndiphoton = 0; + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + if constexpr (isTriggerAnalysis) { + if (!collision.swtalias_bit(o2::aod::pwgem::dilepton::swt::aliasLabels.at(cfg_swt_name.value))) { + continue; + } + // if (collision.spherocity_ptunweighted() < cfgSpherocityMin || cfgSpherocityMax < collision.spherocity_ptunweighted()) { + // continue; + // } + // fRegistry.fill(HIST("Event/after/hSpherocity"), collision.spherocity_ptunweighted()); + } + const float eventplanes_2_for_mix[6] = {collision.ep2ft0m(), collision.ep2ft0a(), collision.ep2ft0c(), collision.ep2btot(), collision.ep2bpos(), collision.ep2bneg()}; + float ep2 = eventplanes_2_for_mix[cfgEP2Estimator_for_Mix]; + fRegistry.fill(HIST("Event/before/hEP2_CentFT0C_forMix"), collision.centFT0C(), ep2); + + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<0, -1>(&fRegistry, collision); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<1, -1>(&fRegistry, collision); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted + fRegistry.fill(HIST("Event/after/hEP2_CentFT0C_forMix"), collision.centFT0C(), ep2); + + int zbin = lower_bound(zvtx_bin_edges.begin(), zvtx_bin_edges.end(), collision.posZ()) - zvtx_bin_edges.begin() - 1; + if (zbin < 0) { + zbin = 0; + } else if (static_cast(zvtx_bin_edges.size()) - 2 < zbin) { + zbin = static_cast(zvtx_bin_edges.size()) - 2; + } + + float centrality = centralities[cfgCentEstimator]; + int centbin = lower_bound(cent_bin_edges.begin(), cent_bin_edges.end(), centrality) - cent_bin_edges.begin() - 1; + if (centbin < 0) { + centbin = 0; + } else if (static_cast(cent_bin_edges.size()) - 2 < centbin) { + centbin = static_cast(cent_bin_edges.size()) - 2; + } + + int epbin = lower_bound(ep_bin_edges.begin(), ep_bin_edges.end(), ep2) - ep_bin_edges.begin() - 1; + if (epbin < 0) { + epbin = 0; + } else if (static_cast(ep_bin_edges.size()) - 2 < epbin) { + epbin = static_cast(ep_bin_edges.size()) - 2; + } + + int occbin = -1; + if (cfgOccupancyEstimator == 0) { + occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.ft0cOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; + } else if (cfgOccupancyEstimator == 1) { + occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.trackOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; + } else { + occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.ft0cOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; + } + + if (occbin < 0) { + occbin = 0; + } else if (static_cast(occ_bin_edges.size()) - 2 < occbin) { + occbin = static_cast(occ_bin_edges.size()) - 2; + } + + // LOGF(info, "collision.globalIndex() = %d, collision.posZ() = %f, centrality = %f, ep2 = %f, collision.trackOccupancyInTimeRange() = %d, zbin = %d, centbin = %d, epbin = %d, occbin = %d", collision.globalIndex(), collision.posZ(), centrality, ep2, collision.trackOccupancyInTimeRange(), zbin, centbin, epbin, occbin); + + std::tuple key_bin = std::make_tuple(zbin, centbin, epbin, occbin); + std::pair key_df_collision = std::make_pair(ndf, collision.globalIndex()); + + if constexpr (pairtype == ggHBTPairType::kPCMPCM) { + auto photons1_coll = photons1.sliceBy(perCollision1, collision.globalIndex()); + auto photons2_coll = photons2.sliceBy(perCollision2, collision.globalIndex()); + for (auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photons1_coll, photons2_coll))) { + if (!cut1.template IsSelected(g1) || !cut2.template IsSelected(g2)) { + continue; + } + + auto pos1 = g1.template posTrack_as(); + auto ele1 = g1.template negTrack_as(); + auto pos2 = g2.template posTrack_as(); + auto ele2 = g2.template negTrack_as(); + if (pos1.trackId() == pos2.trackId() || ele1.trackId() == ele2.trackId()) { // never happens. only for protection. + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); + + // float dz = g1.vz() - g2.vz(); + // float dr = std::sqrt(std::pow(g1.vx() - g2.vx(), 2) + std::pow(g1.vy() - g2.vy(), 2)); + // if (ggpaircuts.applydRdZ && std::pow(dz / ggpaircuts.cfgMinDeltaZ, 2) + std::pow(dr / ggpaircuts.cfgMinDeltaR, 2) < 1.f) { + // continue; + // } + + // float deta_pos = pos1.sign() * pos1.pt() > pos2.sign() * pos2.pt() ? pos1.eta() - pos2.eta() : pos2.eta() - pos1.eta(); + // float dphi_pos = pos1.sign() * pos1.pt() > pos2.sign() * pos2.pt() ? pos1.phi() - pos2.phi() : pos2.phi() - pos1.phi(); + // o2::math_utils::bringToPMPi(dphi_pos); + // float deta_ele = ele1.sign() * ele1.pt() > ele2.sign() * ele2.pt() ? ele1.eta() - ele2.eta() : ele2.eta() - ele1.eta(); + // float dphi_ele = ele1.sign() * ele1.pt() > ele2.sign() * ele2.pt() ? ele1.phi() - ele2.phi() : ele2.phi() - ele1.phi(); + // o2::math_utils::bringToPMPi(dphi_ele); + // if (ggpaircuts.applydEtadPhi_Leg && std::pow(deta_pos / ggpaircuts.cfgMinDeltaEta_Leg, 2) + std::pow(dphi_pos / ggpaircuts.cfgMinDeltaPhi_Leg, 2) < 1.f) { + // continue; + // } + // if (ggpaircuts.applydEtadPhi_Leg && std::pow(deta_ele / ggpaircuts.cfgMinDeltaEta_Leg, 2) + std::pow(dphi_ele / ggpaircuts.cfgMinDeltaPhi_Leg, 2) < 1.f) { + // continue; + // } + + float deta_photon = v1.Pt() > v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi_photon = v1.Pt() > v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + if (ggpaircuts.applydEtadPhi_Photon && std::pow(deta_photon / ggpaircuts.cfgMinDeltaEta_Photon, 2) + std::pow(dphi_photon / ggpaircuts.cfgMinDeltaPhi_Photon, 2) < 1.f) { + continue; + } + fRegistry.fill(HIST("Pair/same/hDeltaEtaDeltaPhi_Photon"), dphi_photon, deta_photon, 1.f); // distance between 2 photons + + // fRegistry.fill(HIST("Pair/same/hDeltaRDeltaZ"), dr, fabs(dz), 1.f); + // fRegistry.fill(HIST("Pair/same/hDeltaEtaDeltaPhi_Leg"), pos1.phi() - pos2.phi(), pos1.eta() - pos2.eta(), 1.f); // distance between 2 LS tracks + // fRegistry.fill(HIST("Pair/same/hDeltaEtaDeltaPhi_Leg"), ele1.phi() - ele2.phi(), ele1.eta() - ele2.eta(), 1.f); // distance between 2 LS tracks + + fillPairHistogram<0>(collision, v1, v2, 1.f); + ndiphoton++; + + std::pair pair_tmp_id1 = std::make_pair(ndf, g1.globalIndex()); + std::pair pair_tmp_id2 = std::make_pair(ndf, g2.globalIndex()); + if (std::find(used_photonIds.begin(), used_photonIds.end(), pair_tmp_id1) == used_photonIds.end()) { + EMTrack g1tmp = EMTrack(ndf, g1.globalIndex(), collision.globalIndex(), g1.globalIndex(), g1.pt(), g1.eta(), g1.phi(), 0); + g1tmp.setConversionPointXYZ(g1.vx(), g1.vy(), g1.vz()); + g1tmp.setPositiveLegPtEtaPhiM(pos1.pt(), pos1.eta(), pos1.phi(), o2::constants::physics::MassElectron); + g1tmp.setNegativeLegPtEtaPhiM(ele1.pt(), ele1.eta(), ele1.phi(), o2::constants::physics::MassElectron); + emh1->AddTrackToEventPool(key_df_collision, g1tmp); + used_photonIds.emplace_back(pair_tmp_id1); + } + if (std::find(used_photonIds.begin(), used_photonIds.end(), pair_tmp_id2) == used_photonIds.end()) { + EMTrack g2tmp = EMTrack(ndf, g2.globalIndex(), collision.globalIndex(), g2.globalIndex(), g2.pt(), g2.eta(), g2.phi(), 0); + g2tmp.setConversionPointXYZ(g2.vx(), g2.vy(), g2.vz()); + g2tmp.setPositiveLegPtEtaPhiM(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + g2tmp.setNegativeLegPtEtaPhiM(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); + emh1->AddTrackToEventPool(key_df_collision, g2tmp); + used_photonIds.emplace_back(pair_tmp_id2); + } + } // end of pairing loop + } else if constexpr (pairtype == ggHBTPairType::kEEEE) { + auto positrons_per_collision = positrons->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + auto electrons_per_collision = electrons->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + std::vector, std::pair>> used_pairs_per_collision; + used_pairs_per_collision.reserve(std::pow(positrons_per_collision.size() * electrons_per_collision.size(), 2)); + // LOGF(info, "collision.globalIndex() = %d, positrons_per_collision.size() = %d, electrons_per_collision.size() = %d", collision.globalIndex(), positrons_per_collision.size(), electrons_per_collision.size()); + + for (auto& [pos1, ele1] : combinations(CombinationsFullIndexPolicy(positrons_per_collision, electrons_per_collision))) { + if (pos1.trackId() == ele1.trackId()) { // this is protection against pairing identical 2 tracks. // never happens. only for protection. + continue; + } + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { + if (!cut1.template IsSelectedTrack(pos1, collision) || !cut1.template IsSelectedTrack(ele1, collision)) { + continue; + } + } else { // cut-based + if (!cut1.template IsSelectedTrack(pos1, collision) || !cut1.template IsSelectedTrack(ele1, collision)) { + continue; + } + } + if (!cut1.IsSelectedPair(pos1, ele1, d_bz)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v_pos1(pos1.pt(), pos1.eta(), pos1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v_ele1(ele1.pt(), ele1.eta(), ele1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v1_ee = v_pos1 + v_ele1; + float dca_pos1_3d = dca3DinSigma(pos1); + float dca_ele1_3d = dca3DinSigma(ele1); + float dca1_3d = std::sqrt((dca_pos1_3d * dca_pos1_3d + dca_ele1_3d * dca_ele1_3d) / 2.); + float weight1 = 1.f; + if (cfgApplyWeightTTCA) { + weight1 = map_weight[std::make_pair(pos1.globalIndex(), ele1.globalIndex())]; + } + + for (auto& [pos2, ele2] : combinations(CombinationsFullIndexPolicy(positrons_per_collision, electrons_per_collision))) { + if (pos2.trackId() == ele2.trackId()) { // this is protection against pairing identical 2 tracks. // never happens. only for protection. + continue; + } + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { + if (!cut2.template IsSelectedTrack(pos2, collision) || !cut2.template IsSelectedTrack(ele2, collision)) { + continue; + } + } else { // cut-based + if (!cut2.template IsSelectedTrack(pos2, collision) || !cut2.template IsSelectedTrack(ele2, collision)) { + continue; + } + } + if (!cut2.IsSelectedPair(pos2, ele2, d_bz)) { + continue; + } + + if (pos1.trackId() == pos2.trackId() || ele1.trackId() == ele2.trackId()) { // this comparison is valid in the same collision. + continue; + } + + float weight2 = 1.f; + if (cfgApplyWeightTTCA) { + weight2 = map_weight[std::make_pair(pos2.globalIndex(), ele2.globalIndex())]; + } + + float dca_pos2_3d = dca3DinSigma(pos2); + float dca_ele2_3d = dca3DinSigma(ele2); + float dca2_3d = std::sqrt((dca_pos2_3d * dca_pos2_3d + dca_ele2_3d * dca_ele2_3d) / 2.); + + ROOT::Math::PtEtaPhiMVector v_pos2(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v_ele2(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2_ee = v_pos2 + v_ele2; + + std::pair pair_tmp = std::make_pair(std::make_pair(pos1.trackId(), ele1.trackId()), std::make_pair(pos2.trackId(), ele2.trackId())); + if (std::find(used_pairs_per_collision.begin(), used_pairs_per_collision.end(), pair_tmp) == used_pairs_per_collision.end()) { + // float deta_pos = pos1.sign() * pos1.pt() > pos2.sign() * pos2.pt() ? pos1.eta() - pos2.eta() : pos2.eta() - pos1.eta(); + // float dphi_pos = pos1.sign() * pos1.pt() > pos2.sign() * pos2.pt() ? pos1.phi() - pos2.phi() : pos2.phi() - pos1.phi(); + // o2::math_utils::bringToPMPi(dphi_pos); + // float deta_ele = ele1.sign() * ele1.pt() > ele2.sign() * ele2.pt() ? ele1.eta() - ele2.eta() : ele2.eta() - ele1.eta(); + // float dphi_ele = ele1.sign() * ele1.pt() > ele2.sign() * ele2.pt() ? ele1.phi() - ele2.phi() : ele2.phi() - ele1.phi(); + // o2::math_utils::bringToPMPi(dphi_ele); + // if (ggpaircuts.applydEtadPhi_Leg && std::pow(deta_pos / ggpaircuts.cfgMinDeltaEta_Leg, 2) + std::pow(dphi_pos / ggpaircuts.cfgMinDeltaPhi_Leg, 2) < 1.f) { + // continue; + // } + // if (ggpaircuts.applydEtadPhi_Leg && std::pow(deta_ele / ggpaircuts.cfgMinDeltaEta_Leg, 2) + std::pow(dphi_ele / ggpaircuts.cfgMinDeltaPhi_Leg, 2) < 1.f) { + // continue; + // } + + float deta_photon = v1_ee.Pt() > v2_ee.Pt() ? v1_ee.Eta() - v2_ee.Eta() : v2_ee.Eta() - v1_ee.Eta(); + float dphi_photon = v1_ee.Pt() > v2_ee.Pt() ? v1_ee.Phi() - v2_ee.Phi() : v2_ee.Phi() - v1_ee.Phi(); + if (ggpaircuts.applydEtadPhi_Photon && std::pow(deta_photon / ggpaircuts.cfgMinDeltaEta_Photon, 2) + std::pow(dphi_photon / ggpaircuts.cfgMinDeltaPhi_Photon, 2) < 1.f) { + continue; + } + fRegistry.fill(HIST("Pair/same/hDeltaEtaDeltaPhi_Photon"), dphi_photon, deta_photon, weight1 * weight2); // distance between 2 photons + + // fRegistry.fill(HIST("Pair/same/hDeltaEtaDeltaPhi_Leg"), dphi_pos, deta_pos, weight1 * weight2); // distance between 2 LS tracks + // fRegistry.fill(HIST("Pair/same/hDeltaEtaDeltaPhi_Leg"), dphi_ele, deta_ele, weight1 * weight2); // distance between 2 LS tracks + fillPairHistogram<0>(collision, v1_ee, v2_ee, weight1 * weight2); + ndiphoton++; + used_pairs_per_collision.emplace_back(std::make_pair(pair_tmp.first, pair_tmp.second)); + used_pairs_per_collision.emplace_back(std::make_pair(pair_tmp.second, pair_tmp.first)); + // LOGF(info, "collision.globalIndex() = %d, pos1.trackId() = %d, ele1.trackId() = %d, pos2.trackId() = %d, ele2.trackId() = %d", collision.globalIndex(), pos1.trackId(), ele1.trackId(), pos2.trackId(), ele2.trackId()); + + std::tuple tuple_tmp_id1 = std::make_tuple(ndf, collision.globalIndex(), pos1.globalIndex(), ele1.globalIndex()); + std::tuple tuple_tmp_id2 = std::make_tuple(ndf, collision.globalIndex(), pos2.globalIndex(), ele2.globalIndex()); + if (std::find(used_dileptonIds.begin(), used_dileptonIds.end(), tuple_tmp_id1) == used_dileptonIds.end()) { + std::vector possibleIds_pos1; + std::vector possibleIds_ele1; + std::copy(pos1.ambiguousElectronsIds().begin(), pos1.ambiguousElectronsIds().end(), std::back_inserter(possibleIds_pos1)); + std::copy(ele1.ambiguousElectronsIds().begin(), ele1.ambiguousElectronsIds().end(), std::back_inserter(possibleIds_ele1)); + + EMTrack g1pair = EMTrack(ndf, -1, collision.globalIndex(), -1, v1_ee.Pt(), v1_ee.Eta(), v1_ee.Phi(), v1_ee.M()); + g1pair.setGlobalPosId(pos1.globalIndex()); + g1pair.setGlobalNegId(ele1.globalIndex()); + g1pair.setPairDca3DinSigmaOTF(dca1_3d); + g1pair.setPositiveLegPtEtaPhiM(pos1.pt(), pos1.eta(), pos1.phi(), o2::constants::physics::MassElectron); + g1pair.setNegativeLegPtEtaPhiM(ele1.pt(), ele1.eta(), ele1.phi(), o2::constants::physics::MassElectron); + g1pair.setAmbPosLegSelfIds(possibleIds_pos1); + g1pair.setAmbNegLegSelfIds(possibleIds_ele1); + emh1->AddTrackToEventPool(key_df_collision, g1pair); + used_dileptonIds.emplace_back(tuple_tmp_id1); + } + if (std::find(used_dileptonIds.begin(), used_dileptonIds.end(), tuple_tmp_id2) == used_dileptonIds.end()) { + std::vector possibleIds_pos2; + std::vector possibleIds_ele2; + std::copy(pos2.ambiguousElectronsIds().begin(), pos2.ambiguousElectronsIds().end(), std::back_inserter(possibleIds_pos2)); + std::copy(ele2.ambiguousElectronsIds().begin(), ele2.ambiguousElectronsIds().end(), std::back_inserter(possibleIds_ele2)); + + EMTrack g2pair = EMTrack(ndf, -1, collision.globalIndex(), -1, v2_ee.Pt(), v2_ee.Eta(), v2_ee.Phi(), v2_ee.M()); + g2pair.setGlobalPosId(pos2.globalIndex()); + g2pair.setGlobalNegId(ele2.globalIndex()); + g2pair.setPairDca3DinSigmaOTF(dca2_3d); + g2pair.setPositiveLegPtEtaPhiM(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + g2pair.setNegativeLegPtEtaPhiM(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); + g2pair.setAmbPosLegSelfIds(possibleIds_pos2); + g2pair.setAmbNegLegSelfIds(possibleIds_ele2); + emh1->AddTrackToEventPool(key_df_collision, g2pair); + used_dileptonIds.emplace_back(tuple_tmp_id2); + } + } + } // end of g2 loop + } // end of g1 loop + used_pairs_per_collision.clear(); + used_pairs_per_collision.shrink_to_fit(); + } else if constexpr (pairtype == ggHBTPairType::kPCMEE) { + auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); + auto positrons_per_collision = positrons->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + auto electrons_per_collision = electrons->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + + for (auto& g1 : photons1_per_collision) { + if (!cut1.template IsSelected(g1)) { + continue; + } + auto pos1 = g1.template posTrack_as(); + auto ele1 = g1.template negTrack_as(); + ROOT::Math::PtEtaPhiMVector v1_gamma(g1.pt(), g1.eta(), g1.phi(), 0.); + + for (auto& [pos2, ele2] : combinations(CombinationsFullIndexPolicy(positrons_per_collision, electrons_per_collision))) { + if (pos2.trackId() == ele2.trackId()) { // this is protection against pairing identical 2 tracks. // never happens. only for protection. + continue; + } + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { + if (!cut2.template IsSelectedTrack(pos2, collision) || !cut2.template IsSelectedTrack(ele2, collision)) { + continue; + } + } else { // cut-based + if (!cut2.template IsSelectedTrack(pos2, collision) || !cut2.template IsSelectedTrack(ele2, collision)) { + continue; + } + } + if (!cut2.IsSelectedPair(pos2, ele2, d_bz)) { + continue; + } + + if (pos1.trackId() == pos2.trackId() || ele1.trackId() == ele2.trackId()) { // this comparison is valid in the same collision. + continue; + } + + float weight = 1.f; + if (cfgApplyWeightTTCA) { + weight = map_weight[std::make_pair(pos2.globalIndex(), ele2.globalIndex())]; + } + // LOGF(info, "g1.globalIndex() = %d, map_weight[std::make_pair(%d, %d)] = %f", g1.globalIndex(), pos2.globalIndex(), ele2.globalIndex(), weight); + + float dca_pos2_3d = dca3DinSigma(pos2); + float dca_ele2_3d = dca3DinSigma(ele2); + float dca2_3d = std::sqrt((dca_pos2_3d * dca_pos2_3d + dca_ele2_3d * dca_ele2_3d) / 2.); + + ROOT::Math::PtEtaPhiMVector v_pos2(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v_ele2(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2_ee = v_pos2 + v_ele2; + + // float deta_pos = pos1.sign() * pos1.pt() > pos2.sign() * pos2.pt() ? pos1.eta() - pos2.eta() : pos2.eta() - pos1.eta(); + // float dphi_pos = pos1.sign() * pos1.pt() > pos2.sign() * pos2.pt() ? pos1.phi() - pos2.phi() : pos2.phi() - pos1.phi(); + // o2::math_utils::bringToPMPi(dphi_pos); + // float deta_ele = ele1.sign() * ele1.pt() > ele2.sign() * ele2.pt() ? ele1.eta() - ele2.eta() : ele2.eta() - ele1.eta(); + // float dphi_ele = ele1.sign() * ele1.pt() > ele2.sign() * ele2.pt() ? ele1.phi() - ele2.phi() : ele2.phi() - ele1.phi(); + // o2::math_utils::bringToPMPi(dphi_ele); + // if (ggpaircuts.applydEtadPhi_Leg && std::pow(deta_pos / ggpaircuts.cfgMinDeltaEta_Leg, 2) + std::pow(dphi_pos / ggpaircuts.cfgMinDeltaPhi_Leg, 2) < 1.f) { + // continue; + // } + // if (ggpaircuts.applydEtadPhi_Leg && std::pow(deta_ele / ggpaircuts.cfgMinDeltaEta_Leg, 2) + std::pow(dphi_ele / ggpaircuts.cfgMinDeltaPhi_Leg, 2) < 1.f) { + // continue; + // } + + float deta_photon = v1_gamma.Pt() > v2_ee.Pt() ? v1_gamma.Eta() - v2_ee.Eta() : v2_ee.Eta() - v1_gamma.Eta(); + float dphi_photon = v1_gamma.Pt() > v2_ee.Pt() ? v1_gamma.Phi() - v2_ee.Phi() : v2_ee.Phi() - v1_gamma.Phi(); + if (ggpaircuts.applydEtadPhi_Photon && std::pow(deta_photon / ggpaircuts.cfgMinDeltaEta_Photon, 2) + std::pow(dphi_photon / ggpaircuts.cfgMinDeltaPhi_Photon, 2) < 1.f) { + continue; + } + fRegistry.fill(HIST("Pair/same/hDeltaEtaDeltaPhi_Photon"), dphi_photon, deta_photon, weight); // distance between 2 photons + + // fRegistry.fill(HIST("Pair/same/hDeltaEtaDeltaPhi_Leg"), dphi_pos, deta_pos, weight); + // fRegistry.fill(HIST("Pair/same/hDeltaEtaDeltaPhi_Leg"), dphi_ele, deta_ele, weight); + + fillPairHistogram<0>(collision, v1_gamma, v2_ee, weight); + ndiphoton++; + std::pair pair_tmp_id1 = std::make_pair(ndf, g1.globalIndex()); + std::tuple tuple_tmp_id2 = std::make_tuple(ndf, collision.globalIndex(), pos2.globalIndex(), ele2.globalIndex()); + if (std::find(used_photonIds.begin(), used_photonIds.end(), pair_tmp_id1) == used_photonIds.end()) { + EMTrack g1tmp = EMTrack(ndf, g1.globalIndex(), collision.globalIndex(), g1.globalIndex(), g1.pt(), g1.eta(), g1.phi(), 0); + g1tmp.setConversionPointXYZ(g1.vx(), g1.vy(), g1.vz()); + g1tmp.setPositiveLegPtEtaPhiM(pos1.pt(), pos1.eta(), pos1.phi(), o2::constants::physics::MassElectron); + g1tmp.setNegativeLegPtEtaPhiM(ele1.pt(), ele1.eta(), ele1.phi(), o2::constants::physics::MassElectron); + emh1->AddTrackToEventPool(key_df_collision, g1tmp); + used_photonIds.emplace_back(pair_tmp_id1); + } + if (std::find(used_dileptonIds.begin(), used_dileptonIds.end(), tuple_tmp_id2) == used_dileptonIds.end()) { + EMTrack g2pair = EMTrack(ndf, -1, collision.globalIndex(), -1, v2_ee.Pt(), v2_ee.Eta(), v2_ee.Phi(), v2_ee.M()); + g2pair.setPairDca3DinSigmaOTF(dca2_3d); + g2pair.setPositiveLegPtEtaPhiM(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + g2pair.setNegativeLegPtEtaPhiM(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); + emh2->AddTrackToEventPool(key_df_collision, g2pair); + used_dileptonIds.emplace_back(tuple_tmp_id2); + } + } // end of g2 loop + } // end of g1 loop + } + + // event mixing + if (!cfgDoMix || !(ndiphoton > 0)) { + continue; + } + + // make a vector of selected photons in this collision. + auto selected_photons1_in_this_event = emh1->GetTracksPerCollision(key_df_collision); + auto selected_photons2_in_this_event = emh2->GetTracksPerCollision(key_df_collision); + + auto collisionIds1_in_mixing_pool = emh1->GetCollisionIdsFromEventPool(key_bin); + auto collisionIds2_in_mixing_pool = emh2->GetCollisionIdsFromEventPool(key_bin); + + if constexpr (pairtype == ggHBTPairType::kPCMPCM) { + for (auto& mix_dfId_collisionId : collisionIds1_in_mixing_pool) { + int mix_dfId = mix_dfId_collisionId.first; + int64_t mix_collisionId = mix_dfId_collisionId.second; + + if (collision.globalIndex() == mix_collisionId && ndf == mix_dfId) { // this never happens. only protection. + continue; + } + + auto globalBC_mix = map_mixed_eventId_to_globalBC[mix_dfId_collisionId]; + uint64_t diffBC = std::max(collision.globalBC(), globalBC_mix) - std::min(collision.globalBC(), globalBC_mix); + fRegistry.fill(HIST("Pair/mix/hDiffBC"), diffBC); + if (diffBC < ndiff_bc_mix) { + continue; + } + + auto photons1_from_event_pool = emh1->GetTracksPerCollision(mix_dfId_collisionId); + // LOGF(info, "Do event mixing: current event (%d, %d), ngamma = %d | event pool (%d, %d), ngamma = %d", ndf, collision.globalIndex(), selected_photons1_in_this_event.size(), mix_dfId, mix_collisionId, photons1_from_event_pool.size()); + + for (auto& g1 : selected_photons1_in_this_event) { + for (auto& g2 : photons1_from_event_pool) { + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); + + // auto pos1 = g1.getPositiveLeg(); + // auto ele1 = g1.getNegativeLeg(); + // auto pos2 = g2.getPositiveLeg(); + // auto ele2 = g2.getNegativeLeg(); + + // float dz = g1.vz() - g2.vz(); + // float dr = std::sqrt(std::pow(g1.vx() - g2.vx(), 2) + std::pow(g1.vy() - g2.vy(), 2)); + // if (ggpaircuts.applydRdZ && std::pow(dz / ggpaircuts.cfgMinDeltaZ, 2) + std::pow(dr / ggpaircuts.cfgMinDeltaR, 2) < 1.f) { + // continue; + // } + + // float deta_pos = pos1.Pt() > pos2.Pt() ? pos1.Eta() - pos2.Eta() : pos2.Eta() - pos1.Eta(); + // float dphi_pos = pos1.Pt() > pos2.Pt() ? pos1.Phi() - pos2.Phi() : pos2.Phi() - pos1.Phi(); + // o2::math_utils::bringToPMPi(dphi_pos); + // float deta_ele = ele1.Pt() < ele2.Pt() ? ele1.Eta() - ele2.Eta() : ele2.Eta() - ele1.Eta(); // flipped + // float dphi_ele = ele1.Pt() < ele2.Pt() ? ele1.Phi() - ele2.Phi() : ele2.Phi() - ele1.Phi(); // flipped + // o2::math_utils::bringToPMPi(dphi_ele); + // if (ggpaircuts.applydEtadPhi_Leg && std::pow(deta_pos / ggpaircuts.cfgMinDeltaEta_Leg, 2) + std::pow(dphi_pos / ggpaircuts.cfgMinDeltaPhi_Leg, 2) < 1.f) { + // continue; + // } + // if (ggpaircuts.applydEtadPhi_Leg && std::pow(deta_ele / ggpaircuts.cfgMinDeltaEta_Leg, 2) + std::pow(dphi_ele / ggpaircuts.cfgMinDeltaPhi_Leg, 2) < 1.f) { + // continue; + // } + + float deta_photon = v1.Pt() > v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi_photon = v1.Pt() > v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + if (ggpaircuts.applydEtadPhi_Photon && std::pow(deta_photon / ggpaircuts.cfgMinDeltaEta_Photon, 2) + std::pow(dphi_photon / ggpaircuts.cfgMinDeltaPhi_Photon, 2) < 1.f) { + continue; + } + fRegistry.fill(HIST("Pair/mix/hDeltaEtaDeltaPhi_Photon"), dphi_photon, deta_photon, 1.f); // distance between 2 photons + + // fRegistry.fill(HIST("Pair/mix/hDeltaRDeltaZ"), dr, fabs(dz), 1.f); + // fRegistry.fill(HIST("Pair/mix/hDeltaEtaDeltaPhi_Leg"), dphi_pos, deta_pos, 1.f); // distance between 2 LS tracks + // fRegistry.fill(HIST("Pair/mix/hDeltaEtaDeltaPhi_Leg"), dphi_ele, deta_ele, 1.f); // distance between 2 LS tracks + fillPairHistogram<1>(collision, v1, v2, 1.f); + } + } + } // end of loop over mixed event pool + } else if constexpr (pairtype == ggHBTPairType::kEEEE) { + for (auto& mix_dfId_collisionId : collisionIds1_in_mixing_pool) { + int mix_dfId = mix_dfId_collisionId.first; + int64_t mix_collisionId = mix_dfId_collisionId.second; + + if (collision.globalIndex() == mix_collisionId && ndf == mix_dfId) { // this never happens. only protection. + continue; + } + auto globalBC_mix = map_mixed_eventId_to_globalBC[mix_dfId_collisionId]; + uint64_t diffBC = std::max(collision.globalBC(), globalBC_mix) - std::min(collision.globalBC(), globalBC_mix); + fRegistry.fill(HIST("Pair/mix/hDiffBC"), diffBC); + if (diffBC < ndiff_bc_mix) { + continue; + } + + auto photons1_from_event_pool = emh1->GetTracksPerCollision(mix_dfId_collisionId); + // LOGF(info, "Do event mixing: current event (%d, %d), ngamma = %d | event pool (%d, %d), ngamma = %d", ndf, collision.globalIndex(), selected_photons1_in_this_event.size(), mix_dfId, mix_collisionId, photons1_from_event_pool.size()); + + for (auto& g1 : selected_photons1_in_this_event) { + for (auto& g2 : photons1_from_event_pool) { + auto v1amb_pos_Ids = g1.ambiguousPosLegIds(); + auto v1amb_neg_Ids = g1.ambiguousNegLegIds(); + auto v2amb_pos_Ids = g2.ambiguousPosLegIds(); + auto v2amb_neg_Ids = g2.ambiguousNegLegIds(); + + bool is_found_pos1 = std::find(v2amb_pos_Ids.begin(), v2amb_pos_Ids.end(), g1.globalIndexPos()) != v2amb_pos_Ids.end(); + bool is_found_neg1 = std::find(v2amb_neg_Ids.begin(), v2amb_neg_Ids.end(), g1.globalIndexPos()) != v2amb_neg_Ids.end(); + bool is_found_pos2 = std::find(v1amb_pos_Ids.begin(), v1amb_pos_Ids.end(), g2.globalIndexPos()) != v1amb_pos_Ids.end(); + bool is_found_neg2 = std::find(v1amb_neg_Ids.begin(), v1amb_neg_Ids.end(), g2.globalIndexPos()) != v1amb_neg_Ids.end(); + // LOGF(info, "is_found_pos1 = %d, is_found_neg1 = %d, is_found_pos2 = %d, is_found_neg2 = %d", is_found_pos1, is_found_neg1, is_found_pos2, is_found_neg2); + + // auto pos1 = g1.getPositiveLeg(); + // auto ele1 = g1.getNegativeLeg(); + // auto pos2 = g2.getPositiveLeg(); + // auto ele2 = g2.getNegativeLeg(); + + if ((g1.dfId() == g2.dfId()) && ((is_found_pos1 && is_found_pos2) || (is_found_neg1 && is_found_neg2))) { + // LOGF(info, "event id = %d: same track is found. t1.globalIndex() = %d, t1.sign() = %d, t1.pt() = %f, t1.eta() = %f, t1.phi() = %f, t2.globalIndex() = %d, t2.sign() = %d, t2.pt() = %f, t2.eta() = %f, t2.phi() = %f, deta = %f, dphi = %f (rad.)", ev_id, t1.globalIndex(), t1.sign(), t1.pt(), t1.eta(), t1.phi(), t2.globalIndex(), t2.sign(), t2.pt(), t2.eta(), t2.phi(), t1.eta() - t2.eta(), t1.phi() - t2.phi()); + continue; // this is protection against pairing 2 identical tracks. This happens, when TTCA is used. TTCA can assign a track to several possible collisions. + } + + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), g1.mass()); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), g2.mass()); + + // float deta_pos = pos1.Eta() - pos2.Eta(); + // float dphi_pos = pos1.Phi() - pos2.Phi(); + // o2::math_utils::bringToPMPi(dphi_pos); + // float deta_ele = ele1.Eta() - ele2.Eta(); + // float dphi_ele = ele1.Phi() - ele2.Phi(); + // o2::math_utils::bringToPMPi(dphi_ele); + // if (ggpaircuts.applydEtadPhi_Leg && std::pow(deta_pos / ggpaircuts.cfgMinDeltaEta_Leg, 2) + std::pow(dphi_pos / ggpaircuts.cfgMinDeltaPhi_Leg, 2) < 1.f) { + // continue; + // } + // if (ggpaircuts.applydEtadPhi_Leg && std::pow(deta_ele / ggpaircuts.cfgMinDeltaEta_Leg, 2) + std::pow(dphi_ele / ggpaircuts.cfgMinDeltaPhi_Leg, 2) < 1.f) { + // continue; + // } + + float deta_photon = v1.Pt() > v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi_photon = v1.Pt() > v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + if (ggpaircuts.applydEtadPhi_Photon && std::pow(deta_photon / ggpaircuts.cfgMinDeltaEta_Photon, 2) + std::pow(dphi_photon / ggpaircuts.cfgMinDeltaPhi_Photon, 2) < 1.f) { + continue; + } + fRegistry.fill(HIST("Pair/mix/hDeltaEtaDeltaPhi_Photon"), dphi_photon, deta_photon, 1.f); // distance between 2 photons + // fRegistry.fill(HIST("Pair/mix/hDeltaEtaDeltaPhi_Leg"), dphi_pos, deta_pos, 1.f); // distance between 2 LS tracks + // fRegistry.fill(HIST("Pair/mix/hDeltaEtaDeltaPhi_Leg"), dphi_ele, deta_ele, 1.f); // distance between 2 LS tracks + fillPairHistogram<1>(collision, v1, v2, 1.f); + } + } + } // end of loop over mixed event pool + } else if constexpr (pairtype == ggHBTPairType::kPCMEE) { // [photon1 from event1, photon2 from event2] and [photon1 from event2, photon2 from event1] + for (auto& mix_dfId_collisionId : collisionIds1_in_mixing_pool) { + int mix_dfId = mix_dfId_collisionId.first; + int64_t mix_collisionId = mix_dfId_collisionId.second; + + if (collision.globalIndex() == mix_collisionId && ndf == mix_dfId) { // this never happens. only protection. + continue; + } + auto globalBC_mix = map_mixed_eventId_to_globalBC[mix_dfId_collisionId]; + uint64_t diffBC = std::max(collision.globalBC(), globalBC_mix) - std::min(collision.globalBC(), globalBC_mix); + fRegistry.fill(HIST("Pair/mix/hDiffBC"), diffBC); + if (diffBC < ndiff_bc_mix) { + continue; + } + + auto photons2_from_event_pool = emh2->GetTracksPerCollision(mix_dfId_collisionId); + // LOGF(info, "Do event mixing: current event (%d, %d), ngamma = %d | event pool (%d, %d), nll = %d", ndf, collision.globalIndex(), selected_photons1_in_this_event.size(), mix_dfId, mix_collisionId, photons2_from_event_pool.size()); + + for (auto& g1 : selected_photons1_in_this_event) { // PCM + for (auto& g2 : photons2_from_event_pool) { // dielectron + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.0); // keep v1 for PCM + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), g2.mass()); + + // auto pos1 = g1.getPositiveLeg(); + // auto ele1 = g1.getNegativeLeg(); + // auto pos2 = g2.getPositiveLeg(); + // auto ele2 = g2.getNegativeLeg(); + + // float deta_pos = pos1.Eta() - pos2.Eta(); + // float dphi_pos = pos1.Phi() - pos2.Phi(); + // o2::math_utils::bringToPMPi(dphi_pos); + // float deta_ele = ele1.Eta() - ele2.Eta(); + // float dphi_ele = ele1.Phi() - ele2.Phi(); + // o2::math_utils::bringToPMPi(dphi_ele); + // if (ggpaircuts.applydEtadPhi_Leg && std::pow(deta_pos / ggpaircuts.cfgMinDeltaEta_Leg, 2) + std::pow(dphi_pos / ggpaircuts.cfgMinDeltaPhi_Leg, 2) < 1.f) { + // continue; + // } + // if (ggpaircuts.applydEtadPhi_Leg && std::pow(deta_ele / ggpaircuts.cfgMinDeltaEta_Leg, 2) + std::pow(dphi_ele / ggpaircuts.cfgMinDeltaPhi_Leg, 2) < 1.f) { + // continue; + // } + + float deta_photon = v1.Pt() > v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi_photon = v1.Pt() > v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + if (ggpaircuts.applydEtadPhi_Photon && std::pow(deta_photon / ggpaircuts.cfgMinDeltaEta_Photon, 2) + std::pow(dphi_photon / ggpaircuts.cfgMinDeltaPhi_Photon, 2) < 1.f) { + continue; + } + fRegistry.fill(HIST("Pair/mix/hDeltaEtaDeltaPhi_Photon"), dphi_photon, deta_photon, 1.f); // distance between 2 photons + // fRegistry.fill(HIST("Pair/mix/hDeltaEtaDeltaPhi_Leg"), dphi_pos, deta_pos, 1.f); // distance between 2 LS tracks + // fRegistry.fill(HIST("Pair/mix/hDeltaEtaDeltaPhi_Leg"), dphi_ele, deta_ele, 1.f); // distance between 2 LS tracks + fillPairHistogram<1>(collision, v1, v2, 1.f); + } + } + } // end of loop over mixed event pool2 + + for (auto& mix_dfId_collisionId : collisionIds1_in_mixing_pool) { + int mix_dfId = mix_dfId_collisionId.first; + int64_t mix_collisionId = mix_dfId_collisionId.second; + + if (collision.globalIndex() == mix_collisionId && ndf == mix_dfId) { // this never happens. only protection. + continue; + } + auto globalBC_mix = map_mixed_eventId_to_globalBC[mix_dfId_collisionId]; + uint64_t diffBC = std::max(collision.globalBC(), globalBC_mix) - std::min(collision.globalBC(), globalBC_mix); + fRegistry.fill(HIST("Pair/mix/hDiffBC"), diffBC); + if (diffBC < ndiff_bc_mix) { + continue; + } + + auto photons1_from_event_pool = emh1->GetTracksPerCollision(mix_dfId_collisionId); + // LOGF(info, "Do event mixing: current event (%d, %d), nll = %d | event pool (%d, %d), ngamma = %d", ndf, collision.globalIndex(), selected_photons2_in_this_event.size(), mix_dfId, mix_collisionId, photons1_from_event_pool.size()); + + for (auto& g1 : selected_photons2_in_this_event) { // dielectron + for (auto& g2 : photons1_from_event_pool) { // PCM + ROOT::Math::PtEtaPhiMVector v1(g2.pt(), g2.eta(), g2.phi(), 0.0); // keep v1 for PCM + ROOT::Math::PtEtaPhiMVector v2(g1.pt(), g1.eta(), g1.phi(), g1.mass()); + + // auto pos1 = g1.getPositiveLeg(); + // auto ele1 = g1.getNegativeLeg(); + // auto pos2 = g2.getPositiveLeg(); + // auto ele2 = g2.getNegativeLeg(); + + // float deta_pos = pos1.Eta() - pos2.Eta(); + // float dphi_pos = pos1.Phi() - pos2.Phi(); + // o2::math_utils::bringToPMPi(dphi_pos); + // float deta_ele = ele1.Eta() - ele2.Eta(); + // float dphi_ele = ele1.Phi() - ele2.Phi(); + // o2::math_utils::bringToPMPi(dphi_ele); + // if (ggpaircuts.applydEtadPhi_Leg && std::pow(deta_pos / ggpaircuts.cfgMinDeltaEta_Leg, 2) + std::pow(dphi_pos / ggpaircuts.cfgMinDeltaPhi_Leg, 2) < 1.f) { + // continue; + // } + // if (ggpaircuts.applydEtadPhi_Leg && std::pow(deta_ele / ggpaircuts.cfgMinDeltaEta_Leg, 2) + std::pow(dphi_ele / ggpaircuts.cfgMinDeltaPhi_Leg, 2) < 1.f) { + // continue; + // } + float deta_photon = v1.Pt() > v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi_photon = v1.Pt() > v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + if (ggpaircuts.applydEtadPhi_Photon && std::pow(deta_photon / ggpaircuts.cfgMinDeltaEta_Photon, 2) + std::pow(dphi_photon / ggpaircuts.cfgMinDeltaPhi_Photon, 2) < 1.f) { + continue; + } + fRegistry.fill(HIST("Pair/mix/hDeltaEtaDeltaPhi_Photon"), dphi_photon, deta_photon, 1.f); // distance between 2 photons + // fRegistry.fill(HIST("Pair/mix/hDeltaEtaDeltaPhi_Leg"), dphi_pos, deta_pos, 1.f); // distance between 2 LS tracks + // fRegistry.fill(HIST("Pair/mix/hDeltaEtaDeltaPhi_Leg"), dphi_ele, deta_ele, 1.f); // distance between 2 LS tracks + fillPairHistogram<1>(collision, v1, v2, 1.f); + } + } + } // end of loop over mixed event pool1 + } + + if (ndiphoton > 0) { + emh1->AddCollisionIdAtLast(key_bin, key_df_collision); + emh2->AddCollisionIdAtLast(key_bin, key_df_collision); + map_mixed_eventId_to_globalBC[key_df_collision] = collision.globalBC(); + } + } // end of collision loop + } + + std::map, float> map_weight; // -> float + template + void fillDileptonPairWeightMap(TCollisions const& collisions, TTracks const& tracks, TCut const& cut) + { + std::vector> passed_pairIds; + passed_pairIds.reserve(positrons.size() * electrons.size()); + + for (auto& collision : collisions) { + initCCDB(collision); + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + if constexpr (isTriggerAnalysis) { + if (!collision.swtalias_bit(o2::aod::pwgem::dilepton::swt::aliasLabels.at(cfg_swt_name.value))) { + continue; + } + // if (collision.spherocity_ptunweighted() < cfgSpherocityMin || cfgSpherocityMax < collision.spherocity_ptunweighted()) { + // continue; + // } + } + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + + auto positrons_per_collision = positrons->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + auto electrons_per_collision = electrons->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + + for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(positrons_per_collision, electrons_per_collision))) { + if (pos.trackId() == ele.trackId()) { // this is protection against pairing identical 2 tracks. // never happens. only for protection. + continue; + } + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { + if (!cut.template IsSelectedTrack(pos, collision) || !cut.template IsSelectedTrack(ele, collision)) { + continue; + } + } else { // cut-based + if (!cut.template IsSelectedTrack(pos, collision) || !cut.template IsSelectedTrack(ele, collision)) { + continue; + } + } + if (!cut.IsSelectedPair(pos, ele, d_bz)) { + continue; + } + passed_pairIds.emplace_back(std::make_pair(pos.globalIndex(), ele.globalIndex())); + } // end of dielectron pairing loop + } // end of collision loop + + for (auto& pairId : passed_pairIds) { + auto t1 = tracks.rawIteratorAt(std::get<0>(pairId)); + auto t2 = tracks.rawIteratorAt(std::get<1>(pairId)); + // LOGF(info, "std::get<0>(pairId) = %d, std::get<1>(pairId) = %d, t1.globalIndex() = %d, t2.globalIndex() = %d", std::get<0>(pairId), std::get<1>(pairId), t1.globalIndex(), t2.globalIndex()); + + float n = 1.f; // include myself. + for (auto& ambId1 : t1.ambiguousElectronsIds()) { + for (auto& ambId2 : t2.ambiguousElectronsIds()) { + if (std::find(passed_pairIds.begin(), passed_pairIds.end(), std::make_pair(ambId1, ambId2)) != passed_pairIds.end()) { + // LOGF(info, "repeated pair is found. t1.globalIndex() = %d, t2.globalIndex() = %d, ambId1 = %d, ambId2 = %d", t1.globalIndex(), t2.globalIndex(), ambId1, ambId2); + n += 1.f; + } + } + } + map_weight[pairId] = 1.f / n; + + } // end of passed_pairIds loop + + passed_pairIds.clear(); + passed_pairIds.shrink_to_fit(); + } + + Filter trackFilter = dielectroncuts.cfg_min_pt_track < o2::aod::track::pt && dielectroncuts.cfg_min_eta_track < o2::aod::track::eta && o2::aod::track::eta < dielectroncuts.cfg_max_eta_track && o2::aod::track::tpcChi2NCl < dielectroncuts.cfg_max_chi2tpc && o2::aod::track::itsChi2NCl < dielectroncuts.cfg_max_chi2its && nabs(o2::aod::track::dcaXY) < dielectroncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dielectroncuts.cfg_max_dcaz; + Filter pidFilter = dielectroncuts.cfg_min_TPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < dielectroncuts.cfg_max_TPCNsigmaEl; + Filter ttcaFilter = ifnode(dielectroncuts.enableTTCA.node(), o2::aod::emprimaryelectron::isAssociatedToMPC == true || o2::aod::emprimaryelectron::isAssociatedToMPC == false, o2::aod::emprimaryelectron::isAssociatedToMPC == true); + + Partition positrons = o2::aod::emprimaryelectron::sign > int8_t(0); + Partition electrons = o2::aod::emprimaryelectron::sign < int8_t(0); + + using MyEMH = o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, EMTrack>; + MyEMH* emh1 = nullptr; + MyEMH* emh2 = nullptr; + std::vector> used_photonIds; // + std::vector> used_dileptonIds; // + std::map, uint64_t> map_mixed_eventId_to_globalBC; + + SliceCache cache; + Preslice perCollision_pcm = aod::v0photonkf::emeventId; + Preslice perCollision_electron = aod::emprimaryelectron::emeventId; + + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + // Filter collisionFilter_multiplicity = cfgNtracksPV08Min <= o2::aod::mult::multNTracksPV && o2::aod::mult::multNTracksPV < cfgNtracksPV08Max; + Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + using FilteredMyCollisions = soa::Filtered; + + int ndf = 0; + void processAnalysis(FilteredMyCollisions const& collisions, Types const&... args) + { + if constexpr (pairtype == ggHBTPairType::kPCMPCM) { + auto v0photons = std::get<0>(std::tie(args...)); + auto v0legs = std::get<1>(std::tie(args...)); + runPairing(collisions, v0photons, v0photons, v0legs, v0legs, perCollision_pcm, perCollision_pcm, fV0PhotonCut, fV0PhotonCut); + } else if constexpr (pairtype == ggHBTPairType::kPCMEE) { + auto v0photons = std::get<0>(std::tie(args...)); + auto v0legs = std::get<1>(std::tie(args...)); + auto emprimaryelectrons = std::get<2>(std::tie(args...)); + if (cfgApplyWeightTTCA) { + fillDileptonPairWeightMap(collisions, emprimaryelectrons, fDielectronCut); + } + runPairing(collisions, v0photons, emprimaryelectrons, v0legs, emprimaryelectrons, perCollision_pcm, perCollision_electron, fV0PhotonCut, fDielectronCut); + } else if constexpr (pairtype == ggHBTPairType::kEEEE) { + auto emprimaryelectrons = std::get<0>(std::tie(args...)); + if (cfgApplyWeightTTCA) { + fillDileptonPairWeightMap(collisions, emprimaryelectrons, fDielectronCut); + } + runPairing(collisions, nullptr, nullptr, emprimaryelectrons, emprimaryelectrons, perCollision_electron, perCollision_electron, fDielectronCut, fDielectronCut); + } + ndf++; + } + PROCESS_SWITCH(PhotonHBT, processAnalysis, "pairing for analysis", false); + + using FilteredMyCollisionsWithSWT = soa::Filtered; + void processTriggerAnalysis(FilteredMyCollisionsWithSWT const& collisions, Types const&... args) + { + if constexpr (pairtype == ggHBTPairType::kPCMPCM) { + auto v0photons = std::get<0>(std::tie(args...)); + auto v0legs = std::get<1>(std::tie(args...)); + runPairing(collisions, v0photons, v0photons, v0legs, v0legs, perCollision_pcm, perCollision_pcm, fV0PhotonCut, fV0PhotonCut); + } else if constexpr (pairtype == ggHBTPairType::kPCMEE) { + auto v0photons = std::get<0>(std::tie(args...)); + auto v0legs = std::get<1>(std::tie(args...)); + auto emprimaryelectrons = std::get<2>(std::tie(args...)); + if (cfgApplyWeightTTCA) { + fillDileptonPairWeightMap(collisions, emprimaryelectrons, fDielectronCut); + } + runPairing(collisions, v0photons, emprimaryelectrons, v0legs, emprimaryelectrons, perCollision_pcm, perCollision_electron, fV0PhotonCut, fDielectronCut); + } else if constexpr (pairtype == ggHBTPairType::kEEEE) { + auto emprimaryelectrons = std::get<0>(std::tie(args...)); + if (cfgApplyWeightTTCA) { + fillDileptonPairWeightMap(collisions, emprimaryelectrons, fDielectronCut); + } + runPairing(collisions, nullptr, nullptr, emprimaryelectrons, emprimaryelectrons, perCollision_electron, perCollision_electron, fDielectronCut, fDielectronCut); + } + ndf++; + } + PROCESS_SWITCH(PhotonHBT, processTriggerAnalysis, "pairing analysis on trigger data", false); + + void processDummy(MyCollisions const&) {} + PROCESS_SWITCH(PhotonHBT, processDummy, "Dummy function", true); +}; + +#endif // PWGEM_DILEPTON_CORE_PHOTONHBT_H_ diff --git a/PWGEM/Dilepton/Core/SingleTrackQC.h b/PWGEM/Dilepton/Core/SingleTrackQC.h new file mode 100644 index 00000000000..f1ffcbb0963 --- /dev/null +++ b/PWGEM/Dilepton/Core/SingleTrackQC.h @@ -0,0 +1,893 @@ +// 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. +// +// ======================== +// +// This code runs loop over electrons for QC. +// Please write to: daiki.sekihata@cern.ch + +#ifndef PWGEM_DILEPTON_CORE_SINGLETRACKQC_H_ +#define PWGEM_DILEPTON_CORE_SINGLETRACKQC_H_ + +#include +#include +#include +#include + +#include "TString.h" +#include "Math/Vector4D.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" + +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "Tools/ML/MlResponse.h" +#include "Common/CCDB/RCTSelectionFlags.h" + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Core/DielectronCut.h" +#include "PWGEM/Dilepton/Core/DimuonCut.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "PWGEM/Dilepton/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; + +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; + +using MyCollisionsWithSWT = soa::Join; +using MyCollisionWithSWT = MyCollisionsWithSWT::iterator; + +using MyElectrons = soa::Join; +using MyElectron = MyElectrons::iterator; +using FilteredMyElectrons = soa::Filtered; +using FilteredMyElectron = FilteredMyElectrons::iterator; + +using MyMuons = soa::Join; +using MyMuon = MyMuons::iterator; +using FilteredMyMuons = soa::Filtered; +using FilteredMyMuon = FilteredMyMuons::iterator; + +template +struct SingleTrackQC { + + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + Configurable cfg_swt_name{"cfg_swt_name", "fHighTrackMult", "desired software trigger name"}; // 1 trigger name per 1 task. fHighTrackMult, fHighFt0Mult + // Configurable cfgNtracksPV08Min{"cfgNtracksPV08Min", -1, "min. multNTracksPV"}; + // Configurable cfgNtracksPV08Max{"cfgNtracksPV08Max", static_cast(1e+9), "max. multNTracksPV"}; + Configurable cfgApplyWeightTTCA{"cfgApplyWeightTTCA", false, "flag to apply weighting by 1/N"}; + Configurable cfgDCAType{"cfgDCAType", 0, "type of DCA for output. 0:3D, 1:XY, 2:Z, else:3D"}; + + ConfigurableAxis ConfPtlBins{"ConfPtlBins", {VARIABLE_WIDTH, 0.00, 0.05, 0.10, 0.15, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.50, 3.00, 3.50, 4.00, 4.50, 5.00, 6.00, 7.00, 8.00, 9.00, 10.00}, "pTl bins for output histograms"}; + ConfigurableAxis ConfDCABins{"ConfDCABins", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0}, "DCA bins for output histograms"}; + + EMEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; + Configurable cfgZvtxMax{"cfgZvtxMax", +10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", true, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", true, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInTimeRangeStrict{"cfgRequireNoCollInTimeRangeStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoCollInITSROFStandard{"cfgRequireNoCollInITSROFStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInITSROFStrict{"cfgRequireNoCollInITSROFStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoHighMultCollInPrevRof{"cfgRequireNoHighMultCollInPrevRof", false, "require no HM collision in previous ITS ROF"}; + Configurable cfgRequireGoodITSLayer3{"cfgRequireGoodITSLayer3", false, "number of inactive chips on ITS layer 3 are below threshold "}; + Configurable cfgRequireGoodITSLayer0123{"cfgRequireGoodITSLayer0123", false, "number of inactive chips on ITS layers 0-3 are below threshold "}; + Configurable cfgRequireGoodITSLayersAll{"cfgRequireGoodITSLayersAll", false, "number of inactive chips on all ITS layers are below threshold "}; + // for RCT + Configurable cfgRequireGoodRCT{"cfgRequireGoodRCT", false, "require good detector flag in run condtion table"}; + Configurable cfgRCTLabel{"cfgRCTLabel", "CBT_hadronPID", "select 1 [CBT, CBT_hadron, CBT_muon_glo] see O2Physics/Common/CCDB/RCTSelectionFlags.h"}; + Configurable cfgCheckZDC{"cfgCheckZDC", false, "set ZDC flag for PbPb"}; + Configurable cfgTreatLimitedAcceptanceAsBad{"cfgTreatLimitedAcceptanceAsBad", false, "reject all events where the detectors relevant for the specified Runlist are flagged as LimitedAcceptance"}; + } eventcuts; + + DielectronCut fDielectronCut; + struct : ConfigurableGroup { + std::string prefix = "dielectroncut_group"; + + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -0.8, "max eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", +0.8, "max eta for single track"}; + Configurable cfg_min_phi_track{"cfg_min_phi_track", 0.f, "max phi for single track"}; + Configurable cfg_max_phi_track{"cfg_max_phi_track", 6.3, "max phi for single track"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 100, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_chi2tof{"cfg_max_chi2tof", 1e+10, "max chi2 TOF"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 0.2, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 0.2, "max dca Z for single track in cm"}; + Configurable cfg_require_itsib_any{"cfg_require_itsib_any", false, "flag to require ITS ib any hits"}; + Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; + Configurable cfg_min_its_cluster_size{"cfg_min_its_cluster_size", 0.f, "min ITS cluster size"}; + Configurable cfg_max_its_cluster_size{"cfg_max_its_cluster_size", 16.f, "max ITS cluster size"}; + Configurable cfg_min_p_its_cluster_size{"cfg_min_p_its_cluster_size", 0.0, "min p to apply ITS cluster size cut"}; + Configurable cfg_max_p_its_cluster_size{"cfg_max_p_its_cluster_size", 0.0, "max p to apply ITS cluster size cut"}; + Configurable cfg_min_rel_diff_pin{"cfg_min_rel_diff_pin", -1e+10, "min rel. diff. between pin and ppv"}; + Configurable cfg_max_rel_diff_pin{"cfg_max_rel_diff_pin", +1e+10, "max rel. diff. between pin and ppv"}; + + Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DielectronCut::PIDSchemes::kTPChadrejORTOFreq), "pid scheme [kTOFreq : 0, kTPChadrej : 1, kTPChadrejORTOFreq : 2, kTPConly : 3, kTOFif = 4, kPIDML = 5]"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + Configurable cfg_min_TPCNsigmaMu{"cfg_min_TPCNsigmaMu", -0.0, "min. TPC n sigma for muon exclusion"}; + Configurable cfg_max_TPCNsigmaMu{"cfg_max_TPCNsigmaMu", +0.0, "max. TPC n sigma for muon exclusion"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -1e+10, "min. TPC n sigma for pion exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +3.0, "max. TPC n sigma for pion exclusion"}; + Configurable cfg_min_TPCNsigmaKa{"cfg_min_TPCNsigmaKa", -3.0, "min. TPC n sigma for kaon exclusion"}; + Configurable cfg_max_TPCNsigmaKa{"cfg_max_TPCNsigmaKa", +3.0, "max. TPC n sigma for kaon exclusion"}; + Configurable cfg_min_TPCNsigmaPr{"cfg_min_TPCNsigmaPr", -3.0, "min. TPC n sigma for proton exclusion"}; + Configurable cfg_max_TPCNsigmaPr{"cfg_max_TPCNsigmaPr", +3.0, "max. TPC n sigma for proton exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; + Configurable cfg_max_pin_pirejTPC{"cfg_max_pin_pirejTPC", 1e+10, "max. pin for pion rejection in TPC"}; + Configurable cfg_min_ITSNsigmaKa{"cfg_min_ITSNsigmaKa", -1.0, "min. ITS n sigma for kaon exclusion"}; + Configurable cfg_max_ITSNsigmaKa{"cfg_max_ITSNsigmaKa", 1e+10, "max. ITS n sigma for kaon exclusion"}; + Configurable cfg_min_ITSNsigmaPr{"cfg_min_ITSNsigmaPr", -1.0, "min. ITS n sigma for proton exclusion"}; + Configurable cfg_max_ITSNsigmaPr{"cfg_max_ITSNsigmaPr", 1e+10, "max. ITS n sigma for proton exclusion"}; + Configurable cfg_min_p_ITSNsigmaKa{"cfg_min_p_ITSNsigmaKa", 0.0, "min p for kaon exclusion in ITS"}; + Configurable cfg_max_p_ITSNsigmaKa{"cfg_max_p_ITSNsigmaKa", 0.0, "max p for kaon exclusion in ITS"}; + Configurable cfg_min_p_ITSNsigmaPr{"cfg_min_p_ITSNsigmaPr", 0.0, "min p for proton exclusion in ITS"}; + Configurable cfg_max_p_ITSNsigmaPr{"cfg_max_p_ITSNsigmaPr", 0.0, "max p for proton exclusion in ITS"}; + Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; + + // configuration for PID ML + Configurable> onnxFileNames{"onnxFileNames", std::vector{"filename"}, "ONNX file names for each bin (if not from CCDB full path)"}; + Configurable> onnxPathsCCDB{"onnxPathsCCDB", std::vector{"path"}, "Paths of models on CCDB"}; + Configurable> binsMl{"binsMl", std::vector{-999999., 999999.}, "Bin limits for ML application"}; + Configurable> cutsMl{"cutsMl", std::vector{0.95}, "ML cuts per bin"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature"}, "Names of ML model input features"}; + Configurable nameBinningFeature{"nameBinningFeature", "pt", "Names of ML model binning feature"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + Configurable enableOptimizations{"enableOptimizations", false, "Enables the ONNX extended model-optimization: sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED)"}; + } dielectroncuts; + + DimuonCut fDimuonCut; + struct : ConfigurableGroup { + std::string prefix = "dimuoncut_group"; + + Configurable cfg_track_type{"cfg_track_type", 3, "muon track type [0: MFT-MCH-MID, 3: MCH-MID]"}; + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "min pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -4.0, "min eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", -2.5, "max eta for single track"}; + Configurable cfg_min_phi_track{"cfg_min_phi_track", 0.f, "max phi for single track"}; + Configurable cfg_max_phi_track{"cfg_max_phi_track", 6.3, "max phi for single track"}; + Configurable cfg_min_ncluster_mft{"cfg_min_ncluster_mft", 5, "min ncluster MFT"}; + Configurable cfg_min_ncluster_mch{"cfg_min_ncluster_mch", 5, "min ncluster MCH"}; + Configurable cfg_max_chi2{"cfg_max_chi2", 1e+6, "max chi2"}; + Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 40, "max chi2 for MFT-MCH matching"}; + Configurable cfg_max_matching_chi2_mchmid{"cfg_max_matching_chi2_mchmid", 1e+10, "max chi2 for MCH-MID matching"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1e+10, "max dca XY for single track in cm"}; + Configurable cfg_min_rabs{"cfg_min_rabs", 17.6, "min Radius at the absorber end"}; + Configurable cfg_max_rabs{"cfg_max_rabs", 89.5, "max Radius at the absorber end"}; + Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; + } dimuoncuts; + + o2::aod::rctsel::RCTFlagsChecker rctChecker; + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; // 1 HistogramRegistry can keep up to 512 histograms + static constexpr std::string_view event_cut_types[2] = {"before/", "after/"}; + + ~SingleTrackQC() {} + + void addhistograms() + { + // event info + o2::aod::pwgem::dilepton::utils::eventhistogram::addEventHistograms<-1>(&fRegistry); + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + const AxisSpec axis_pt{ConfPtlBins, "p_{T,e} (GeV/c)"}; + const AxisSpec axis_eta{20, -1.0, +1.0, "#eta_{e}"}; + const AxisSpec axis_phi{36, 0.0, 2 * M_PI, "#varphi_{e} (rad.)"}; + std::string dca_axis_title = "DCA_{e}^{3D} (#sigma)"; + if (cfgDCAType == 1) { + dca_axis_title = "DCA_{e}^{XY} (#sigma)"; + } else if (cfgDCAType == 2) { + dca_axis_title = "DCA_{e}^{Z} (#sigma)"; + } + const AxisSpec axis_dca{ConfDCABins, dca_axis_title}; + + // track info + fRegistry.add("Track/positive/hs", "rec. single electron", kTHnSparseD, {axis_pt, axis_eta, axis_phi, axis_dca}, true); + fRegistry.add("Track/positive/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); + fRegistry.add("Track/positive/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -1.0f, 1.0f}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("Track/positive/hDCAxyzSigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/positive/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/positive/hDCAzRes_Pt", "DCA_{z} resolution vs. pT;p_{T} (GeV/c);DCA_{z} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 400}}, false); + fRegistry.add("Track/positive/hDCA3dRes_Pt", "DCA_{3D} resolution vs. pT;p_{T} (GeV/c);DCA_{3D} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/positive/hNclsTPC", "number of TPC clusters;TPC N_{cls}", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/positive/hNcrTPC", "number of TPC crossed rows;TPC N_{CR}", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/positive/hChi2TPC", "chi2/number of TPC clusters;TPC #chi^{2}/N_{CR}", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/positive/hDeltaPin", "p_{in} vs. p_{pv};p_{pv} (GeV/c);(p_{in} - p_{pv})/p_{pv}", kTH2F, {{1000, 0, 10}, {200, -1, +1}}, false); + fRegistry.add("Track/positive/hTPCNcr2Nf", "TPC Ncr/Nfindable;TPC N_{CR}/N_{cls}^{findable}", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/positive/hTPCNcls2Nf", "TPC Ncls/Nfindable;TPC N_{cls}/N_{cls}^{findable}", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/positive/hTPCNclsShared", "TPC Ncls shared/Ncls;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); + fRegistry.add("Track/positive/hNclsITS", "number of ITS clusters;ITS N_{cls}", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("Track/positive/hChi2ITS", "chi2/number of ITS clusters;ITS #chi^{2}/N_{cls}", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/positive/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("Track/positive/hChi2TOF", "TOF Chi2;p_{pv} (GeV/c);TOF #chi^{2}", kTH2F, {{1000, 0, 10}, {100, 0, 10}}, false); + + fRegistry.add("Track/positive/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("Track/positive/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hTPCNsigmaMu", "TPC n sigma mu;p_{in} (GeV/c);n #sigma_{#mu}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hTPCNsigmaKa", "TPC n sigma ka;p_{in} (GeV/c);n #sigma_{K}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hTPCNsigmaPr", "TPC n sigma pr;p_{in} (GeV/c);n #sigma_{p}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + + fRegistry.add("Track/positive/hTOFbeta", "TOF #beta;p_{pv} (GeV/c);#beta", kTH2F, {{1000, 0, 10}, {240, 0, 1.2}}, false); + fRegistry.add("Track/positive/hTOFNsigmaEl", "TOF n sigma el;p_{pv} (GeV/c);n #sigma_{e}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hTOFNsigmaMu", "TOF n sigma mu;p_{pv} (GeV/c);n #sigma_{#mu}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hTOFNsigmaPi", "TOF n sigma pi;p_{pv} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hTOFNsigmaKa", "TOF n sigma ka;p_{pv} (GeV/c);n #sigma_{K}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hTOFNsigmaPr", "TOF n sigma pr;p_{pv} (GeV/c);n #sigma_{p}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + + fRegistry.add("Track/positive/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); on ITS #times cos(#lambda);", kTH2F, {{1000, 0.f, 10.f}, {150, 0, 15}}, false); + fRegistry.add("Track/positive/hMeanClusterSizeITSib", "mean cluster size ITS inner barrel;p_{pv} (GeV/c); on ITS #times cos(#lambda);", kTH2F, {{1000, 0.f, 10.f}, {150, 0, 15}}, false); + fRegistry.add("Track/positive/hMeanClusterSizeITSob", "mean cluster size ITS outer barrel;p_{pv} (GeV/c); on ITS #times cos(#lambda);", kTH2F, {{1000, 0.f, 10.f}, {150, 0, 15}}, false); + fRegistry.add("Track/positive/hITSNsigmaEl", "ITS n sigma el;p_{pv} (GeV/c);n #sigma_{e}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hITSNsigmaMu", "ITS n sigma mu;p_{pv} (GeV/c);n #sigma_{#mu}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hITSNsigmaPi", "ITS n sigma pi;p_{pv} (GeV/c);n #sigma_{#pi}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hITSNsigmaKa", "ITS n sigma ka;p_{pv} (GeV/c);n #sigma_{K}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hITSNsigmaPr", "ITS n sigma pr;p_{pv} (GeV/c);n #sigma_{p}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + + fRegistry.addClone("Track/positive/", "Track/negative/"); + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + const AxisSpec axis_pt{ConfPtlBins, "p_{T,#mu} (GeV/c)"}; + const AxisSpec axis_eta{50, -6, -1, "#eta_{#mu}"}; + const AxisSpec axis_phi{36, 0, 2 * M_PI, "#varphi_{#mu} (rad.)"}; + const AxisSpec axis_dca{ConfDCABins, "DCA_{#mu}^{XY} (#sigma)"}; + + // track info + fRegistry.add("Track/positive/hs", "rec. single muon", kTHnSparseD, {axis_pt, axis_eta, axis_phi, axis_dca}, true); + fRegistry.add("Track/positive/hEtaPhi_MatchMCHMID", "#eta vs. #varphi of matched MCHMID", kTH2F, {{180, 0, 2.f * M_PI}, {100, -6, -1}}, false); + fRegistry.add("Track/positive/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); + fRegistry.add("Track/positive/hTrackType", "track type", kTH1F, {{6, -0.5f, 5.5}}, false); + fRegistry.add("Track/positive/hDCAxy", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", kTH2F, {{200, -0.5f, 0.5f}, {200, -0.5f, 0.5f}}, false); + fRegistry.add("Track/positive/hDCAxySigma", "DCA x vs. y;DCA_{x} (#sigma);DCA_{y} (#sigma)", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/positive/hDCAxRes_Pt", "DCA_{x} resolution vs. pT;p_{T} (GeV/c);DCA_{x} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0, 500}}, false); + fRegistry.add("Track/positive/hDCAyRes_Pt", "DCA_{y} resolution vs. pT;p_{T} (GeV/c);DCA_{y} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0, 500}}, false); + fRegistry.add("Track/positive/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0, 500}}, false); + fRegistry.add("Track/positive/hNclsMCH", "number of MCH clusters", kTH1F, {{21, -0.5, 20.5}}, false); + fRegistry.add("Track/positive/hNclsMFT", "number of MFT clusters", kTH1F, {{11, -0.5, 10.5}}, false); + fRegistry.add("Track/positive/hPDCA", "pDCA;R at absorber end (cm);p #times DCA (GeV/c #upoint cm)", kTH2F, {{100, 0, 100}, {100, 0.0f, 1000}}, false); + fRegistry.add("Track/positive/hChi2", "chi2;chi2", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("Track/positive/hChi2MatchMCHMID", "chi2 match MCH-MID;chi2", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("Track/positive/hChi2MatchMCHMFT", "chi2 match MCH-MFT;chi2", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("Track/positive/hMFTClusterMap", "MFT cluster map", kTH1F, {{1024, -0.5, 1023.5}}, false); + fRegistry.addClone("Track/positive/", "Track/negative/"); + } + } + + int mRunNumber; + void init(InitContext&) + { + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + rctChecker.init(eventcuts.cfgRCTLabel.value, eventcuts.cfgCheckZDC.value, eventcuts.cfgTreatLimitedAcceptanceAsBad.value); + + DefineEMEventCut(); + DefineDielectronCut(); + DefineDimuonCut(); + addhistograms(); + mRunNumber = 0; + + if (doprocessNorm) { + fRegistry.addClone("Event/before/hCollisionCounter", "Event/norm/hCollisionCounter"); + } + if (doprocessQC_TriggeredData) { + fRegistry.add("Event/hNInspectedTVX", "N inspected TVX;run number;N_{TVX}", kTProfile, {{80000, 520000.5, 600000.5}}, true); + } + if (doprocessBC) { + auto hTVXCounter = fRegistry.add("BC/hTVXCounter", "TVX counter", kTH1D, {{6, -0.5f, 5.5f}}); + hTVXCounter->GetXaxis()->SetBinLabel(1, "TVX"); + hTVXCounter->GetXaxis()->SetBinLabel(2, "TVX && NoTFB"); + hTVXCounter->GetXaxis()->SetBinLabel(3, "TVX && NoITSROFB"); + hTVXCounter->GetXaxis()->SetBinLabel(4, "TVX && GoodRCT"); + hTVXCounter->GetXaxis()->SetBinLabel(5, "TVX && NoTFB && NoITSROFB"); + hTVXCounter->GetXaxis()->SetBinLabel(6, "TVX && NoTFB && NoITSROFB && GoodRCT"); + } + } + + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + mRunNumber = collision.runNumber(); + + if constexpr (isTriggerAnalysis) { + LOGF(info, "Trigger analysis is enabled. Desired trigger name = %s", cfg_swt_name.value); + LOGF(info, "total inspected TVX events = %d in run number %d", collision.nInspectedTVX(), collision.runNumber()); + fRegistry.fill(HIST("Event/hNInspectedTVX"), collision.runNumber(), collision.nInspectedTVX()); + } + } + + void DefineEMEventCut() + { + fEMEventCut = EMEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(eventcuts.cfgZvtxMin, eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireNoCollInTimeRangeStandard(eventcuts.cfgRequireNoCollInTimeRangeStandard); + fEMEventCut.SetRequireNoCollInTimeRangeStrict(eventcuts.cfgRequireNoCollInTimeRangeStrict); + fEMEventCut.SetRequireNoCollInITSROFStandard(eventcuts.cfgRequireNoCollInITSROFStandard); + fEMEventCut.SetRequireNoCollInITSROFStrict(eventcuts.cfgRequireNoCollInITSROFStrict); + fEMEventCut.SetRequireNoHighMultCollInPrevRof(eventcuts.cfgRequireNoHighMultCollInPrevRof); + fEMEventCut.SetRequireGoodITSLayer3(eventcuts.cfgRequireGoodITSLayer3); + fEMEventCut.SetRequireGoodITSLayer0123(eventcuts.cfgRequireGoodITSLayer0123); + fEMEventCut.SetRequireGoodITSLayersAll(eventcuts.cfgRequireGoodITSLayersAll); + } + + o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; + void DefineDielectronCut() + { + fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); + + // for track + fDielectronCut.SetTrackPtRange(dielectroncuts.cfg_min_pt_track, dielectroncuts.cfg_max_pt_track); + fDielectronCut.SetTrackEtaRange(dielectroncuts.cfg_min_eta_track, dielectroncuts.cfg_max_eta_track); + fDielectronCut.SetTrackPhiRange(dielectroncuts.cfg_min_phi_track, dielectroncuts.cfg_max_phi_track); + fDielectronCut.SetMinNClustersTPC(dielectroncuts.cfg_min_ncluster_tpc); + fDielectronCut.SetMinNCrossedRowsTPC(dielectroncuts.cfg_min_ncrossedrows); + fDielectronCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fDielectronCut.SetMaxFracSharedClustersTPC(dielectroncuts.cfg_max_frac_shared_clusters_tpc); + fDielectronCut.SetChi2PerClusterTPC(0.0, dielectroncuts.cfg_max_chi2tpc); + fDielectronCut.SetChi2PerClusterITS(0.0, dielectroncuts.cfg_max_chi2its); + fDielectronCut.SetNClustersITS(dielectroncuts.cfg_min_ncluster_its, 7); + fDielectronCut.SetMeanClusterSizeITS(dielectroncuts.cfg_min_its_cluster_size, dielectroncuts.cfg_max_its_cluster_size, dielectroncuts.cfg_min_p_its_cluster_size, dielectroncuts.cfg_max_p_its_cluster_size); + fDielectronCut.SetTrackMaxDcaXY(dielectroncuts.cfg_max_dcaxy); + fDielectronCut.SetTrackMaxDcaZ(dielectroncuts.cfg_max_dcaz); + fDielectronCut.RequireITSibAny(dielectroncuts.cfg_require_itsib_any); + fDielectronCut.RequireITSib1st(dielectroncuts.cfg_require_itsib_1st); + fDielectronCut.SetChi2TOF(0.0, dielectroncuts.cfg_max_chi2tof); + fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); + + // for eID + fDielectronCut.SetPIDScheme(dielectroncuts.cfg_pid_scheme); + fDielectronCut.SetTPCNsigmaElRange(dielectroncuts.cfg_min_TPCNsigmaEl, dielectroncuts.cfg_max_TPCNsigmaEl); + fDielectronCut.SetTPCNsigmaMuRange(dielectroncuts.cfg_min_TPCNsigmaMu, dielectroncuts.cfg_max_TPCNsigmaMu); + fDielectronCut.SetTPCNsigmaPiRange(dielectroncuts.cfg_min_TPCNsigmaPi, dielectroncuts.cfg_max_TPCNsigmaPi); + fDielectronCut.SetTPCNsigmaKaRange(dielectroncuts.cfg_min_TPCNsigmaKa, dielectroncuts.cfg_max_TPCNsigmaKa); + fDielectronCut.SetTPCNsigmaPrRange(dielectroncuts.cfg_min_TPCNsigmaPr, dielectroncuts.cfg_max_TPCNsigmaPr); + fDielectronCut.SetTOFNsigmaElRange(dielectroncuts.cfg_min_TOFNsigmaEl, dielectroncuts.cfg_max_TOFNsigmaEl); + fDielectronCut.SetMaxPinForPionRejectionTPC(dielectroncuts.cfg_max_pin_pirejTPC); + fDielectronCut.SetITSNsigmaKaRange(dielectroncuts.cfg_min_ITSNsigmaKa, dielectroncuts.cfg_max_ITSNsigmaKa); + fDielectronCut.SetITSNsigmaPrRange(dielectroncuts.cfg_min_ITSNsigmaPr, dielectroncuts.cfg_max_ITSNsigmaPr); + fDielectronCut.SetPRangeForITSNsigmaKa(dielectroncuts.cfg_min_p_ITSNsigmaKa, dielectroncuts.cfg_max_p_ITSNsigmaKa); + fDielectronCut.SetPRangeForITSNsigmaPr(dielectroncuts.cfg_min_p_ITSNsigmaPr, dielectroncuts.cfg_max_p_ITSNsigmaPr); + + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { // please call this at the end of DefineDileptonCut + static constexpr int nClassesMl = 2; + const std::vector cutDirMl = {o2::cuts_ml::CutSmaller, o2::cuts_ml::CutNot}; + const std::vector labelsClasses = {"Signal", "Background"}; + const uint32_t nBinsMl = dielectroncuts.binsMl.value.size() - 1; + const std::vector labelsBins(nBinsMl, "bin"); + double cutsMlArr[nBinsMl][nClassesMl]; + for (uint32_t i = 0; i < nBinsMl; i++) { + cutsMlArr[i][0] = dielectroncuts.cutsMl.value[i]; + cutsMlArr[i][1] = 0.; + } + o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; + + mlResponseSingleTrack.configure(dielectroncuts.binsMl.value, cutsMl, cutDirMl, nClassesMl); + if (dielectroncuts.loadModelsFromCCDB) { + ccdbApi.init(ccdburl); + mlResponseSingleTrack.setModelPathsCCDB(dielectroncuts.onnxFileNames.value, ccdbApi, dielectroncuts.onnxPathsCCDB.value, dielectroncuts.timestampCCDB.value); + } else { + mlResponseSingleTrack.setModelPathsLocal(dielectroncuts.onnxFileNames.value); + } + mlResponseSingleTrack.cacheInputFeaturesIndices(dielectroncuts.namesInputFeatures); + mlResponseSingleTrack.cacheBinningIndex(dielectroncuts.nameBinningFeature); + mlResponseSingleTrack.init(dielectroncuts.enableOptimizations.value); + + fDielectronCut.SetPIDMlResponse(&mlResponseSingleTrack); + } // end of PID ML + } + + void DefineDimuonCut() + { + fDimuonCut = DimuonCut("fDimuonCut", "fDimuonCut"); + + // for track + fDimuonCut.SetTrackType(dimuoncuts.cfg_track_type); + fDimuonCut.SetTrackPtRange(dimuoncuts.cfg_min_pt_track, dimuoncuts.cfg_max_pt_track); + fDimuonCut.SetTrackEtaRange(dimuoncuts.cfg_min_eta_track, dimuoncuts.cfg_max_eta_track); + fDimuonCut.SetTrackPhiRange(dimuoncuts.cfg_min_phi_track, dimuoncuts.cfg_max_phi_track); + fDimuonCut.SetNClustersMFT(dimuoncuts.cfg_min_ncluster_mft, 10); + fDimuonCut.SetNClustersMCHMID(dimuoncuts.cfg_min_ncluster_mch, 20); + fDimuonCut.SetChi2(0.f, dimuoncuts.cfg_max_chi2); + fDimuonCut.SetMatchingChi2MCHMFT(0.f, dimuoncuts.cfg_max_matching_chi2_mftmch); + fDimuonCut.SetMatchingChi2MCHMID(0.f, dimuoncuts.cfg_max_matching_chi2_mchmid); + fDimuonCut.SetDCAxy(0.f, dimuoncuts.cfg_max_dcaxy); + fDimuonCut.SetRabs(dimuoncuts.cfg_min_rabs, dimuoncuts.cfg_max_rabs); + fDimuonCut.SetMaxPDCARabsDep([&](float rabs) { return (rabs < 26.5 ? 594.f : 324.f); }); + } + + template + void fillElectronInfo(TTrack const& track) + { + float weight = 1.f; + if (cfgApplyWeightTTCA) { + weight = map_weight[track.globalIndex()]; + } + + float dca = dca3DinSigma(track); + if (cfgDCAType == 1) { + dca = dcaXYinSigma(track); + } else if (cfgDCAType == 2) { + dca = dcaZinSigma(track); + } + + if (track.sign() > 0) { + fRegistry.fill(HIST("Track/positive/hs"), track.pt(), track.eta(), track.phi(), dca, weight); + fRegistry.fill(HIST("Track/positive/hQoverPt"), track.sign() / track.pt()); + fRegistry.fill(HIST("Track/positive/hDCAxyz"), track.dcaXY(), track.dcaZ()); + fRegistry.fill(HIST("Track/positive/hDCAxyzSigma"), track.dcaXY() / std::sqrt(track.cYY()), track.dcaZ() / std::sqrt(track.cZZ())); + fRegistry.fill(HIST("Track/positive/hDCAxyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/positive/hDCAzRes_Pt"), track.pt(), std::sqrt(track.cZZ()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/positive/hDCA3dRes_Pt"), track.pt(), sigmaDca3D(track) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/positive/hNclsITS"), track.itsNCls()); + fRegistry.fill(HIST("Track/positive/hNclsTPC"), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/positive/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("Track/positive/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("Track/positive/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("Track/positive/hTPCNclsShared"), track.pt(), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("Track/positive/hDeltaPin"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + fRegistry.fill(HIST("Track/positive/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("Track/positive/hChi2ITS"), track.itsChi2NCl()); + fRegistry.fill(HIST("Track/positive/hITSClusterMap"), track.itsClusterMap()); + fRegistry.fill(HIST("Track/positive/hChi2TOF"), track.p(), track.tofChi2()); + + fRegistry.fill(HIST("Track/positive/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + fRegistry.fill(HIST("Track/positive/hTOFbeta"), track.p(), track.beta()); + fRegistry.fill(HIST("Track/positive/hMeanClusterSizeITS"), track.p(), track.meanClusterSizeITS() * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/positive/hMeanClusterSizeITSib"), track.p(), track.meanClusterSizeITSib() * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/positive/hMeanClusterSizeITSob"), track.p(), track.meanClusterSizeITSob() * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/positive/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/positive/hTPCNsigmaMu"), track.tpcInnerParam(), track.tpcNSigmaMu()); + fRegistry.fill(HIST("Track/positive/hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); + fRegistry.fill(HIST("Track/positive/hTPCNsigmaKa"), track.tpcInnerParam(), track.tpcNSigmaKa()); + fRegistry.fill(HIST("Track/positive/hTPCNsigmaPr"), track.tpcInnerParam(), track.tpcNSigmaPr()); + fRegistry.fill(HIST("Track/positive/hTOFNsigmaEl"), track.p(), track.tofNSigmaEl()); + fRegistry.fill(HIST("Track/positive/hTOFNsigmaMu"), track.p(), track.tofNSigmaMu()); + fRegistry.fill(HIST("Track/positive/hTOFNsigmaPi"), track.p(), track.tofNSigmaPi()); + fRegistry.fill(HIST("Track/positive/hTOFNsigmaKa"), track.p(), track.tofNSigmaKa()); + fRegistry.fill(HIST("Track/positive/hTOFNsigmaPr"), track.p(), track.tofNSigmaPr()); + fRegistry.fill(HIST("Track/positive/hITSNsigmaEl"), track.p(), track.itsNSigmaEl()); + fRegistry.fill(HIST("Track/positive/hITSNsigmaMu"), track.p(), track.itsNSigmaMu()); + fRegistry.fill(HIST("Track/positive/hITSNsigmaPi"), track.p(), track.itsNSigmaPi()); + fRegistry.fill(HIST("Track/positive/hITSNsigmaKa"), track.p(), track.itsNSigmaKa()); + fRegistry.fill(HIST("Track/positive/hITSNsigmaPr"), track.p(), track.itsNSigmaPr()); + } else { + fRegistry.fill(HIST("Track/negative/hs"), track.pt(), track.eta(), track.phi(), dca, weight); + fRegistry.fill(HIST("Track/negative/hQoverPt"), track.sign() / track.pt()); + fRegistry.fill(HIST("Track/negative/hDCAxyz"), track.dcaXY(), track.dcaZ()); + fRegistry.fill(HIST("Track/negative/hDCAxyzSigma"), track.dcaXY() / std::sqrt(track.cYY()), track.dcaZ() / std::sqrt(track.cZZ())); + fRegistry.fill(HIST("Track/negative/hDCAxyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/negative/hDCAzRes_Pt"), track.pt(), std::sqrt(track.cZZ()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/negative/hDCA3dRes_Pt"), track.pt(), sigmaDca3D(track) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/negative/hNclsITS"), track.itsNCls()); + fRegistry.fill(HIST("Track/negative/hNclsTPC"), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/negative/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("Track/negative/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("Track/negative/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("Track/negative/hTPCNclsShared"), track.pt(), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("Track/negative/hDeltaPin"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + fRegistry.fill(HIST("Track/negative/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("Track/negative/hChi2ITS"), track.itsChi2NCl()); + fRegistry.fill(HIST("Track/negative/hITSClusterMap"), track.itsClusterMap()); + fRegistry.fill(HIST("Track/negative/hChi2TOF"), track.p(), track.tofChi2()); + + fRegistry.fill(HIST("Track/negative/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + fRegistry.fill(HIST("Track/negative/hTOFbeta"), track.p(), track.beta()); + fRegistry.fill(HIST("Track/negative/hMeanClusterSizeITS"), track.p(), track.meanClusterSizeITS() * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/negative/hMeanClusterSizeITSib"), track.p(), track.meanClusterSizeITSib() * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/negative/hMeanClusterSizeITSob"), track.p(), track.meanClusterSizeITSob() * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/negative/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/negative/hTPCNsigmaMu"), track.tpcInnerParam(), track.tpcNSigmaMu()); + fRegistry.fill(HIST("Track/negative/hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); + fRegistry.fill(HIST("Track/negative/hTPCNsigmaKa"), track.tpcInnerParam(), track.tpcNSigmaKa()); + fRegistry.fill(HIST("Track/negative/hTPCNsigmaPr"), track.tpcInnerParam(), track.tpcNSigmaPr()); + fRegistry.fill(HIST("Track/negative/hTOFNsigmaEl"), track.p(), track.tofNSigmaEl()); + fRegistry.fill(HIST("Track/negative/hTOFNsigmaMu"), track.p(), track.tofNSigmaMu()); + fRegistry.fill(HIST("Track/negative/hTOFNsigmaPi"), track.p(), track.tofNSigmaPi()); + fRegistry.fill(HIST("Track/negative/hTOFNsigmaKa"), track.p(), track.tofNSigmaKa()); + fRegistry.fill(HIST("Track/negative/hTOFNsigmaPr"), track.p(), track.tofNSigmaPr()); + fRegistry.fill(HIST("Track/negative/hITSNsigmaEl"), track.p(), track.itsNSigmaEl()); + fRegistry.fill(HIST("Track/negative/hITSNsigmaMu"), track.p(), track.itsNSigmaMu()); + fRegistry.fill(HIST("Track/negative/hITSNsigmaPi"), track.p(), track.itsNSigmaPi()); + fRegistry.fill(HIST("Track/negative/hITSNsigmaKa"), track.p(), track.itsNSigmaKa()); + fRegistry.fill(HIST("Track/negative/hITSNsigmaPr"), track.p(), track.itsNSigmaPr()); + } + } + + template + void fillMuonInfo(TTrack const& track) + { + float weight = 1.f; + if (cfgApplyWeightTTCA) { + weight = map_weight[track.globalIndex()]; + } + float dca_xy = fwdDcaXYinSigma(track); + if (track.sign() > 0) { + fRegistry.fill(HIST("Track/positive/hs"), track.pt(), track.eta(), track.phi(), dca_xy, weight); + fRegistry.fill(HIST("Track/positive/hEtaPhi_MatchMCHMID"), track.phiMatchedMCHMID(), track.etaMatchedMCHMID(), weight); + fRegistry.fill(HIST("Track/positive/hQoverPt"), track.sign() / track.pt()); + fRegistry.fill(HIST("Track/positive/hTrackType"), track.trackType()); + fRegistry.fill(HIST("Track/positive/hDCAxy"), track.fwdDcaX(), track.fwdDcaY()); + fRegistry.fill(HIST("Track/positive/hDCAxySigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); + fRegistry.fill(HIST("Track/positive/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXXatDCA()) * 1e+4); + fRegistry.fill(HIST("Track/positive/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYYatDCA()) * 1e+4); + fRegistry.fill(HIST("Track/positive/hDCAxyRes_Pt"), track.pt(), sigmaFwdDcaXY(track) * 1e+4); + fRegistry.fill(HIST("Track/positive/hNclsMCH"), track.nClusters()); + fRegistry.fill(HIST("Track/positive/hNclsMFT"), track.nClustersMFT()); + fRegistry.fill(HIST("Track/positive/hPDCA"), track.rAtAbsorberEnd(), track.pDca()); + fRegistry.fill(HIST("Track/positive/hChi2"), track.chi2()); + fRegistry.fill(HIST("Track/positive/hChi2MatchMCHMID"), track.chi2MatchMCHMID()); + fRegistry.fill(HIST("Track/positive/hChi2MatchMCHMFT"), track.chi2MatchMCHMFT()); + fRegistry.fill(HIST("Track/positive/hMFTClusterMap"), track.mftClusterMap()); + } else { + fRegistry.fill(HIST("Track/negative/hs"), track.pt(), track.eta(), track.phi(), dca_xy, weight); + fRegistry.fill(HIST("Track/negative/hEtaPhi_MatchMCHMID"), track.phiMatchedMCHMID(), track.etaMatchedMCHMID(), weight); + fRegistry.fill(HIST("Track/negative/hQoverPt"), track.sign() / track.pt()); + fRegistry.fill(HIST("Track/negative/hTrackType"), track.trackType()); + fRegistry.fill(HIST("Track/negative/hDCAxy"), track.fwdDcaX(), track.fwdDcaY()); + fRegistry.fill(HIST("Track/negative/hDCAxySigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); + fRegistry.fill(HIST("Track/negative/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXXatDCA()) * 1e+4); + fRegistry.fill(HIST("Track/negative/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYYatDCA()) * 1e+4); + fRegistry.fill(HIST("Track/negative/hDCAxyRes_Pt"), track.pt(), sigmaFwdDcaXY(track) * 1e+4); + fRegistry.fill(HIST("Track/negative/hNclsMCH"), track.nClusters()); + fRegistry.fill(HIST("Track/negative/hNclsMFT"), track.nClustersMFT()); + fRegistry.fill(HIST("Track/negative/hPDCA"), track.rAtAbsorberEnd(), track.pDca()); + fRegistry.fill(HIST("Track/negative/hChi2"), track.chi2()); + fRegistry.fill(HIST("Track/negative/hChi2MatchMCHMID"), track.chi2MatchMCHMID()); + fRegistry.fill(HIST("Track/negative/hChi2MatchMCHMFT"), track.chi2MatchMCHMFT()); + fRegistry.fill(HIST("Track/negative/hMFTClusterMap"), track.mftClusterMap()); + } + } + + template + void runQC(TCollisions const& collisions, TTracks const& tracks, TPreslice const& perCollision, TCut const& cut) + { + for (const auto& collision : collisions) { + initCCDB(collision); + float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + if constexpr (isTriggerAnalysis) { + if (!collision.swtalias_bit(o2::aod::pwgem::dilepton::swt::aliasLabels.at(cfg_swt_name.value))) { + continue; + } + } + + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<0, -1>(&fRegistry, collision); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<1, -1>(&fRegistry, collision); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted + + auto tracks_per_coll = tracks.sliceBy(perCollision, collision.globalIndex()); + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + for (const auto& track : tracks_per_coll) { + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { + if (!cut.template IsSelectedTrack(track, collision)) { + continue; + } + } else { // cut-based + if (!cut.template IsSelectedTrack(track)) { + continue; + } + } + fillElectronInfo(track); + } // end of track loop + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + for (const auto& track : tracks_per_coll) { + if (!cut.template IsSelectedTrack(track)) { + continue; + } + if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(track, cut, tracks)) { + continue; + } + + fillMuonInfo(track); + } // end of track loop + } + } // end of collision loop + } + + std::unordered_map map_weight; + template + void fillTrackWeightMap(TCollisions const& collisions, TTracks const& tracks, TPreslice const& perCollision, TCut const& cut) + { + std::vector passed_trackIds; + passed_trackIds.reserve(tracks.size()); + for (const auto& collision : collisions) { + initCCDB(collision); + float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + if constexpr (isTriggerAnalysis) { + if (!collision.swtalias_bit(o2::aod::pwgem::dilepton::swt::aliasLabels.at(cfg_swt_name.value))) { + continue; + } + } + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + + auto tracks_per_coll = tracks.sliceBy(perCollision, collision.globalIndex()); + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + for (const auto& track : tracks_per_coll) { + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { + if (!cut.template IsSelectedTrack(track, collision)) { + continue; + } + } else { // cut-based + if (!cut.template IsSelectedTrack(track)) { + continue; + } + } + passed_trackIds.emplace_back(track.globalIndex()); + } // end of track loop + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + for (const auto& track : tracks_per_coll) { + if (!cut.template IsSelectedTrack(track)) { + continue; + } + if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(track, cut, tracks)) { + continue; + } + passed_trackIds.emplace_back(track.globalIndex()); + } // end of track loop + } + } // end of collision loop + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + for (const auto& trackId : passed_trackIds) { + auto track = tracks.rawIteratorAt(trackId); + auto ambIds = track.ambiguousElectronsIds(); + float n = 1.f; // include myself. + for (const auto& ambId : ambIds) { + if (std::find(passed_trackIds.begin(), passed_trackIds.end(), ambId) != passed_trackIds.end()) { + n += 1.f; + } + } + map_weight[trackId] = 1.f / n; + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + for (const auto& trackId : passed_trackIds) { + auto track = tracks.rawIteratorAt(trackId); + auto ambIds = track.ambiguousMuonsIds(); + float n = 1.f; // include myself. + for (const auto& ambId : ambIds) { + if (std::find(passed_trackIds.begin(), passed_trackIds.end(), ambId) != passed_trackIds.end()) { + n += 1.f; + } + } + map_weight[trackId] = 1.f / n; + } + } + + passed_trackIds.clear(); + passed_trackIds.shrink_to_fit(); + } + + SliceCache cache; + Preslice perCollision_electron = aod::emprimaryelectron::emeventId; + Filter trackFilter_electron = dielectroncuts.cfg_min_pt_track < o2::aod::track::pt && dielectroncuts.cfg_min_eta_track < o2::aod::track::eta && o2::aod::track::eta < dielectroncuts.cfg_max_eta_track && dielectroncuts.cfg_min_phi_track < o2::aod::track::phi && o2::aod::track::phi < dielectroncuts.cfg_max_phi_track && o2::aod::track::tpcChi2NCl < dielectroncuts.cfg_max_chi2tpc && o2::aod::track::itsChi2NCl < dielectroncuts.cfg_max_chi2its && nabs(o2::aod::track::dcaXY) < dielectroncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dielectroncuts.cfg_max_dcaz; + Filter pidFilter_electron = dielectroncuts.cfg_min_TPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < dielectroncuts.cfg_max_TPCNsigmaEl; + Filter ttcaFilter_electron = ifnode(dielectroncuts.enableTTCA.node(), o2::aod::emprimaryelectron::isAssociatedToMPC == true || o2::aod::emprimaryelectron::isAssociatedToMPC == false, o2::aod::emprimaryelectron::isAssociatedToMPC == true); + + Preslice perCollision_muon = aod::emprimarymuon::emeventId; + Filter trackFilter_muon = o2::aod::fwdtrack::trackType == dimuoncuts.cfg_track_type && dimuoncuts.cfg_min_pt_track < o2::aod::fwdtrack::pt && o2::aod::fwdtrack::pt < dimuoncuts.cfg_max_pt_track && dimuoncuts.cfg_min_eta_track < o2::aod::fwdtrack::eta && o2::aod::fwdtrack::eta < dimuoncuts.cfg_max_eta_track && dimuoncuts.cfg_min_phi_track < o2::aod::fwdtrack::phi && o2::aod::fwdtrack::phi < dimuoncuts.cfg_max_phi_track; + Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), o2::aod::emprimarymuon::isAssociatedToMPC == true || o2::aod::emprimarymuon::isAssociatedToMPC == false, o2::aod::emprimarymuon::isAssociatedToMPC == true); + + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + // Filter collisionFilter_multiplicity = cfgNtracksPV08Min <= o2::aod::mult::multNTracksPV && o2::aod::mult::multNTracksPV < cfgNtracksPV08Max; + Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + using FilteredMyCollisions = soa::Filtered; + + void processQC(FilteredMyCollisions const& collisions, Types const&... args) + { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + auto electrons = std::get<0>(std::tie(args...)); + if (cfgApplyWeightTTCA) { + fillTrackWeightMap(collisions, electrons, perCollision_electron, fDielectronCut); + } + runQC(collisions, electrons, perCollision_electron, fDielectronCut); + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + auto muons = std::get<0>(std::tie(args...)); + if (cfgApplyWeightTTCA) { + fillTrackWeightMap(collisions, muons, perCollision_muon, fDimuonCut); + } + runQC(collisions, muons, perCollision_muon, fDimuonCut); + } + + map_weight.clear(); + } + PROCESS_SWITCH(SingleTrackQC, processQC, "run single track QC", true); + + using FilteredMyCollisionsWithSWT = soa::Filtered; + void processQC_TriggeredData(FilteredMyCollisionsWithSWT const& collisions, Types const&... args) + { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + auto electrons = std::get<0>(std::tie(args...)); + if (cfgApplyWeightTTCA) { + fillTrackWeightMap(collisions, electrons, perCollision_electron, fDielectronCut); + } + runQC(collisions, electrons, perCollision_electron, fDielectronCut); + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + auto muons = std::get<0>(std::tie(args...)); + if (cfgApplyWeightTTCA) { + fillTrackWeightMap(collisions, muons, perCollision_muon, fDimuonCut); + } + runQC(collisions, muons, perCollision_muon, fDimuonCut); + } + + map_weight.clear(); + } + PROCESS_SWITCH(SingleTrackQC, processQC_TriggeredData, "run single track QC on triggered data", false); + + void processNorm(aod::EMEventNormInfos const& collisions) + { + for (const auto& collision : collisions) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 1.0); + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 2.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 3.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 4.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 5.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 6.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 7.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 8.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 9.0); + } + if (collision.sel8()) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 10.0); + } + if (std::fabs(collision.posZ()) < 10.0) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 11.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 12.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 13.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 14.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 15.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 16.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer3)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 17.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 18.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 19.0); + } + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted + } // end of collision loop + } + PROCESS_SWITCH(SingleTrackQC, processNorm, "process normalization info", false); + + void processBC(aod::EMBCs const& bcs) + { + for (const auto& bc : bcs) { + if (bc.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 0.f); + + if (bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 1.f); + } + if (bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 2.f); + } + if (rctChecker(bc)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 3.f); + } + if (bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 4.f); + } + if (bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder) && rctChecker(bc)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 5.f); + } + } + } + } + PROCESS_SWITCH(SingleTrackQC, processBC, "process BC counter", false); + + void processDummy(MyCollisions const&) {} + PROCESS_SWITCH(SingleTrackQC, processDummy, "Dummy function", false); +}; +#endif // PWGEM_DILEPTON_CORE_SINGLETRACKQC_H_ diff --git a/PWGEM/Dilepton/Core/SingleTrackQCMC.h b/PWGEM/Dilepton/Core/SingleTrackQCMC.h new file mode 100644 index 00000000000..d0239c20298 --- /dev/null +++ b/PWGEM/Dilepton/Core/SingleTrackQCMC.h @@ -0,0 +1,1183 @@ +// 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. +// +// ======================== +// +// This code runs loop over electrons for QC in MC. +// Please write to: daiki.sekihata@cern.ch + +#ifndef PWGEM_DILEPTON_CORE_SINGLETRACKQCMC_H_ +#define PWGEM_DILEPTON_CORE_SINGLETRACKQCMC_H_ + +#include +#include +#include +#include + +#include "TString.h" +#include "Math/Vector4D.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" + +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "Tools/ML/MlResponse.h" +#include "Common/CCDB/RCTSelectionFlags.h" + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Core/DielectronCut.h" +#include "PWGEM/Dilepton/Core/DimuonCut.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/Dilepton/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::dilepton::utils::mcutil; +using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; + +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; + +using MyMCCollisions = soa::Join; +using MyMCCollision = MyMCCollisions::iterator; + +using MyMCElectrons = soa::Join; +using MyMCElectron = MyMCElectrons::iterator; +using FilteredMyMCElectrons = soa::Filtered; + +using MyMCMuons = soa::Join; +using MyMCMuon = MyMCMuons::iterator; +using FilteredMyMCMuons = soa::Filtered; + +using MySmearedElectrons = soa::Join; +using MySmearedElectron = MySmearedElectrons::iterator; + +using MySmearedMuons = soa::Join; +using MySmearedMuon = MySmearedMuons::iterator; + +template +struct SingleTrackQCMC { + + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + Configurable cfgEventGeneratorType{"cfgEventGeneratorType", -1, "if positive, select event generator type. i.e. gap or signal"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + // Configurable cfgNtracksPV08Min{"cfgNtracksPV08Min", -1, "min. multNTracksPV"}; + // Configurable cfgNtracksPV08Max{"cfgNtracksPV08Max", static_cast(1e+9), "max. multNTracksPV"}; + Configurable cfgFillQA{"cfgFillQA", false, "flag to fill QA histograms"}; + Configurable cfgApplyWeightTTCA{"cfgApplyWeightTTCA", false, "flag to apply weighting by 1/N"}; + Configurable cfgDCAType{"cfgDCAType", 0, "type of DCA for output. 0:3D, 1:XY, 2:Z, else:3D"}; + Configurable cfgRequireTrueAssociation{"cfgRequireTrueAssociation", false, "flag to require true mc collision association"}; + + ConfigurableAxis ConfPtlBins{"ConfPtlBins", {VARIABLE_WIDTH, 0.00, 0.05, 0.10, 0.15, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.50, 3.00, 3.50, 4.00, 4.50, 5.00, 6.00, 7.00, 8.00, 9.00, 10.00}, "pTl bins for output histograms"}; + ConfigurableAxis ConfDCABins{"ConfDCABins", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0}, "DCA bins for output histograms"}; + + EMEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; + Configurable cfgZvtxMax{"cfgZvtxMax", +10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", true, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", true, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInTimeRangeStrict{"cfgRequireNoCollInTimeRangeStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoCollInITSROFStandard{"cfgRequireNoCollInITSROFStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInITSROFStrict{"cfgRequireNoCollInITSROFStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoHighMultCollInPrevRof{"cfgRequireNoHighMultCollInPrevRof", false, "require no HM collision in previous ITS ROF"}; + Configurable cfgRequireGoodITSLayer3{"cfgRequireGoodITSLayer3", false, "number of inactive chips on ITS layer 3 are below threshold "}; + Configurable cfgRequireGoodITSLayer0123{"cfgRequireGoodITSLayer0123", false, "number of inactive chips on ITS layers 0-3 are below threshold "}; + Configurable cfgRequireGoodITSLayersAll{"cfgRequireGoodITSLayersAll", false, "number of inactive chips on all ITS layers are below threshold "}; + // for RCT + Configurable cfgRequireGoodRCT{"cfgRequireGoodRCT", false, "require good detector flag in run condtion table"}; + Configurable cfgRCTLabel{"cfgRCTLabel", "CBT_hadronPID", "select 1 [CBT, CBT_hadron, CBT_muon_glo] see O2Physics/Common/CCDB/RCTSelectionFlags.h"}; + Configurable cfgCheckZDC{"cfgCheckZDC", false, "set ZDC flag for PbPb"}; + Configurable cfgTreatLimitedAcceptanceAsBad{"cfgTreatLimitedAcceptanceAsBad", false, "reject all events where the detectors relevant for the specified Runlist are flagged as LimitedAcceptance"}; + } eventcuts; + + DielectronCut fDielectronCut; + struct : ConfigurableGroup { + std::string prefix = "dielectroncut_group"; + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -0.8, "max eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", +0.8, "max eta for single track"}; + Configurable cfg_min_phi_track{"cfg_min_phi_track", 0.f, "max phi for single track"}; + Configurable cfg_max_phi_track{"cfg_max_phi_track", 6.3, "max phi for single track"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 100, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_chi2tof{"cfg_max_chi2tof", 1e+10, "max chi2 TOF"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 0.2, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 0.2, "max dca Z for single track in cm"}; + Configurable cfg_require_itsib_any{"cfg_require_itsib_any", false, "flag to require ITS ib any hits"}; + Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; + Configurable cfg_min_its_cluster_size{"cfg_min_its_cluster_size", 0.f, "min ITS cluster size"}; + Configurable cfg_max_its_cluster_size{"cfg_max_its_cluster_size", 16.f, "max ITS cluster size"}; + Configurable cfg_min_p_its_cluster_size{"cfg_min_p_its_cluster_size", 0.0, "min p to apply ITS cluster size cut"}; + Configurable cfg_max_p_its_cluster_size{"cfg_max_p_its_cluster_size", 0.0, "max p to apply ITS cluster size cut"}; + Configurable cfg_min_rel_diff_pin{"cfg_min_rel_diff_pin", -1e+10, "min rel. diff. between pin and ppv"}; + Configurable cfg_max_rel_diff_pin{"cfg_max_rel_diff_pin", +1e+10, "max rel. diff. between pin and ppv"}; + + Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DielectronCut::PIDSchemes::kTPChadrejORTOFreq), "pid scheme [kTOFreq : 0, kTPChadrej : 1, kTPChadrejORTOFreq : 2, kTPConly : 3, kTOFif = 4, kPIDML = 5]"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + Configurable cfg_min_TPCNsigmaMu{"cfg_min_TPCNsigmaMu", -0.0, "min. TPC n sigma for muon exclusion"}; + Configurable cfg_max_TPCNsigmaMu{"cfg_max_TPCNsigmaMu", +0.0, "max. TPC n sigma for muon exclusion"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -1e+10, "min. TPC n sigma for pion exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +3.0, "max. TPC n sigma for pion exclusion"}; + Configurable cfg_min_TPCNsigmaKa{"cfg_min_TPCNsigmaKa", -3.0, "min. TPC n sigma for kaon exclusion"}; + Configurable cfg_max_TPCNsigmaKa{"cfg_max_TPCNsigmaKa", +3.0, "max. TPC n sigma for kaon exclusion"}; + Configurable cfg_min_TPCNsigmaPr{"cfg_min_TPCNsigmaPr", -3.0, "min. TPC n sigma for proton exclusion"}; + Configurable cfg_max_TPCNsigmaPr{"cfg_max_TPCNsigmaPr", +3.0, "max. TPC n sigma for proton exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; + Configurable cfg_max_pin_pirejTPC{"cfg_max_pin_pirejTPC", 1e+10, "max. pin for pion rejection in TPC"}; + Configurable cfg_min_ITSNsigmaKa{"cfg_min_ITSNsigmaKa", -1.0, "min. ITS n sigma for kaon exclusion"}; + Configurable cfg_max_ITSNsigmaKa{"cfg_max_ITSNsigmaKa", 1e+10, "max. ITS n sigma for kaon exclusion"}; + Configurable cfg_min_ITSNsigmaPr{"cfg_min_ITSNsigmaPr", -1.0, "min. ITS n sigma for proton exclusion"}; + Configurable cfg_max_ITSNsigmaPr{"cfg_max_ITSNsigmaPr", 1e+10, "max. ITS n sigma for proton exclusion"}; + Configurable cfg_min_p_ITSNsigmaKa{"cfg_min_p_ITSNsigmaKa", 0.0, "min p for kaon exclusion in ITS"}; + Configurable cfg_max_p_ITSNsigmaKa{"cfg_max_p_ITSNsigmaKa", 0.0, "max p for kaon exclusion in ITS"}; + Configurable cfg_min_p_ITSNsigmaPr{"cfg_min_p_ITSNsigmaPr", 0.0, "min p for proton exclusion in ITS"}; + Configurable cfg_max_p_ITSNsigmaPr{"cfg_max_p_ITSNsigmaPr", 0.0, "max p for proton exclusion in ITS"}; + Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; + + // configuration for PID ML + Configurable> onnxFileNames{"onnxFileNames", std::vector{"filename"}, "ONNX file names for each bin (if not from CCDB full path)"}; + Configurable> onnxPathsCCDB{"onnxPathsCCDB", std::vector{"path"}, "Paths of models on CCDB"}; + Configurable> binsMl{"binsMl", std::vector{-999999., 999999.}, "Bin limits for ML application"}; + Configurable> cutsMl{"cutsMl", std::vector{0.95}, "ML cuts per bin"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature"}, "Names of ML model input features"}; + Configurable nameBinningFeature{"nameBinningFeature", "pt", "Names of ML model binning feature"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + Configurable enableOptimizations{"enableOptimizations", false, "Enables the ONNX extended model-optimization: sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED)"}; + } dielectroncuts; + + DimuonCut fDimuonCut; + struct : ConfigurableGroup { + std::string prefix = "dimuoncut_group"; + Configurable cfg_track_type{"cfg_track_type", 3, "muon track type [0: MFT-MCH-MID, 3: MCH-MID]"}; + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -4.0, "min eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", -2.5, "max eta for single track"}; + Configurable cfg_min_phi_track{"cfg_min_phi_track", 0.f, "max phi for single track"}; + Configurable cfg_max_phi_track{"cfg_max_phi_track", 6.3, "max phi for single track"}; + Configurable cfg_min_ncluster_mft{"cfg_min_ncluster_mft", 5, "min ncluster MFT"}; + Configurable cfg_min_ncluster_mch{"cfg_min_ncluster_mch", 5, "min ncluster MCH"}; + Configurable cfg_max_chi2{"cfg_max_chi2", 1e+6, "max chi2"}; + Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 40, "max chi2 for MFT-MCH matching"}; + Configurable cfg_max_matching_chi2_mchmid{"cfg_max_matching_chi2_mchmid", 1e+10, "max chi2 for MCH-MID matching"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1e+10, "max dca XY for single track in cm"}; + Configurable cfg_min_rabs{"cfg_min_rabs", 17.6, "min Radius at the absorber end"}; + Configurable cfg_max_rabs{"cfg_max_rabs", 89.5, "max Radius at the absorber end"}; + Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; + } dimuoncuts; + + o2::aod::rctsel::RCTFlagsChecker rctChecker; + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + + struct : ConfigurableGroup { + std::string prefix = "mctrackcut_group"; + Configurable min_mcPt{"min_mcPt", 0.2, "min. MC pT for generated single lepton"}; + Configurable max_mcPt{"max_mcPt", 1e+10, "max. MC pT single lepton"}; + Configurable min_mcEta{"min_mcEta", -0.8, "max. MC eta single lepton"}; + Configurable max_mcEta{"max_mcEta", +0.8, "max. MC eta single lepton"}; + } mctrackcuts; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; // 1 HistogramRegistry can keep up to 512 histograms + static constexpr std::string_view event_cut_types[2] = {"before/", "after/"}; + static constexpr std::string_view lepton_source_types[10] = {"lf/", "lf_prompt/", "Photon/", "PromptJPsi/", "NonPromptJPsi/", "PromptPsi2S/", "NonPromptPsi2S/", "c2l/", "b2l/", "b2c2l/"}; + + ~SingleTrackQCMC() {} + + void addhistograms() + { + // event info + o2::aod::pwgem::dilepton::utils::eventhistogram::addEventHistograms<-1>(&fRegistry); + fRegistry.add("MCEvent/before/hZvtx", "mc vertex z; Z_{vtx} (cm)", kTH1F, {{100, -50, +50}}, false); + fRegistry.add("MCEvent/before/hZvtx_rec", "rec. mc vertex z; Z_{vtx} (cm)", kTH1F, {{100, -50, +50}}, false); + fRegistry.addClone("MCEvent/before/", "MCEvent/after/"); + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + const AxisSpec axis_pt{ConfPtlBins, "p_{T,e} (GeV/c)"}; + const AxisSpec axis_eta{20, -1.0, +1.0, "#eta_{e}"}; + const AxisSpec axis_phi{36, 0.0, 2 * M_PI, "#varphi_{e} (rad.)"}; + const AxisSpec axis_charge_gen{3, -1.5, +1.5, "true charge"}; + std::string dca_axis_title = "DCA_{e}^{3D} (#sigma)"; + if (cfgDCAType == 1) { + dca_axis_title = "DCA_{e}^{XY} (#sigma)"; + } else if (cfgDCAType == 2) { + dca_axis_title = "DCA_{e}^{Z} (#sigma)"; + } + const AxisSpec axis_dca{ConfDCABins, dca_axis_title}; + + // generated info + fRegistry.add("Generated/lf/hs", "gen. single electron", kTHnSparseD, {axis_pt, axis_eta, axis_phi, axis_charge_gen}, true); + fRegistry.addClone("Generated/lf/", "Generated/lf_prompt/"); + fRegistry.addClone("Generated/lf/", "Generated/PromptJPsi/"); + fRegistry.addClone("Generated/lf/", "Generated/NonPromptJPsi/"); + fRegistry.addClone("Generated/lf/", "Generated/PromptPsi2S/"); + fRegistry.addClone("Generated/lf/", "Generated/NonPromptPsi2S/"); + fRegistry.addClone("Generated/lf/", "Generated/c2l/"); + fRegistry.addClone("Generated/lf/", "Generated/b2l/"); + fRegistry.addClone("Generated/lf/", "Generated/b2c2l/"); + + // track info + fRegistry.add("Track/lf/positive/hs", "rec. single electron", kTHnSparseD, {axis_pt, axis_eta, axis_phi, axis_dca, axis_charge_gen}, true); + if (cfgFillQA) { + fRegistry.add("Track/lf/positive/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); + fRegistry.add("Track/lf/positive/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -1.0f, 1.0f}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("Track/lf/positive/hDCAxyzSigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/lf/positive/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/lf/positive/hDCAzRes_Pt", "DCA_{z} resolution vs. pT;p_{T} (GeV/c);DCA_{z} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/lf/positive/hDCA3dRes_Pt", "DCA_{3D} resolution vs. pT;p_{T} (GeV/c);DCA_{3D} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/lf/positive/hNclsTPC", "number of TPC clusters", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/lf/positive/hNcrTPC", "number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/lf/positive/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/lf/positive/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/lf/positive/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/lf/positive/hTPCNclsShared", "TPC Ncls shared/Ncls;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); + fRegistry.add("Track/lf/positive/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("Track/lf/positive/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/lf/positive/hDeltaPin", "p_{in} vs. p_{pv};p_{pv} (GeV/c);(p_{in} - p_{pv})/p_{pv}", kTH2F, {{1000, 0, 10}, {200, -1, +1}}, false); + fRegistry.add("Track/lf/positive/hChi2TOF", "TOF Chi2;p_{pv} (GeV/c);chi2", kTH2F, {{1000, 0, 10}, {100, 0, 10}}, false); + fRegistry.add("Track/lf/positive/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("Track/lf/positive/hPtGen_DeltaPtOverPtGen", "electron p_{T} resolution;p_{T}^{gen} (GeV/c);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{200, 0, 10}, {200, -1.0f, 1.0f}}, true); + fRegistry.add("Track/lf/positive/hPtGen_DeltaEta", "electron #eta resolution;p_{T}^{gen} (GeV/c);#eta^{rec} - #eta^{gen}", kTH2F, {{200, 0, 10}, {100, -0.05f, 0.05f}}, true); + fRegistry.add("Track/lf/positive/hPtGen_DeltaPhi", "electron #varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{200, 0, 10}, {100, -0.05f, 0.05f}}, true); + } + fRegistry.addClone("Track/lf/positive/", "Track/lf/negative/"); + fRegistry.addClone("Track/lf/", "Track/lf_prompt/"); + fRegistry.addClone("Track/lf/", "Track/Photon/"); // this is not for efficiency! only for contamination. We don't store generated photon conversions. + fRegistry.addClone("Track/lf/", "Track/PromptJPsi/"); + fRegistry.addClone("Track/lf/", "Track/NonPromptJPsi/"); + fRegistry.addClone("Track/lf/", "Track/PromptPsi2S/"); + fRegistry.addClone("Track/lf/", "Track/NonPromptPsi2S/"); + fRegistry.addClone("Track/lf/", "Track/c2l/"); + fRegistry.addClone("Track/lf/", "Track/b2l/"); + fRegistry.addClone("Track/lf/", "Track/b2c2l/"); + + if (cfgFillQA) { + fRegistry.add("Track/PID/positive/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("Track/PID/positive/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/PID/positive/hTPCNsigmaMu", "TPC n sigma mu;p_{in} (GeV/c);n #sigma_{#mu}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/PID/positive/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/PID/positive/hTPCNsigmaKa", "TPC n sigma ka;p_{in} (GeV/c);n #sigma_{K}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/PID/positive/hTPCNsigmaPr", "TPC n sigma pr;p_{in} (GeV/c);n #sigma_{p}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/PID/positive/hTOFbeta", "TOF #beta;p_{pv} (GeV/c);#beta", kTH2F, {{1000, 0, 10}, {240, 0, 1.2}}, false); + fRegistry.add("Track/PID/positive/hTOFNsigmaEl", "TOF n sigma el;p_{pv} (GeV/c);n #sigma_{e}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/PID/positive/hTOFNsigmaMu", "TOF n sigma mu;p_{pv} (GeV/c);n #sigma_{#mu}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/PID/positive/hTOFNsigmaPi", "TOF n sigma pi;p_{pv} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/PID/positive/hTOFNsigmaKa", "TOF n sigma ka;p_{pv} (GeV/c);n #sigma_{K}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/PID/positive/hTOFNsigmaPr", "TOF n sigma pr;p_{pv} (GeV/c);n #sigma_{p}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/PID/positive/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); on ITS #times cos(#lambda)", kTH2F, {{1000, 0.f, 10.f}, {150, 0, 15}}, false); + fRegistry.add("Track/PID/positive/hMeanClusterSizeITSib", "mean cluster size ITS inner barrel;p_{pv} (GeV/c); on ITS #times cos(#lambda)", kTH2F, {{1000, 0.f, 10.f}, {150, 0, 15}}, false); + fRegistry.add("Track/PID/positive/hMeanClusterSizeITSob", "mean cluster size ITS outer barrel;p_{pv} (GeV/c); on ITS #times cos(#lambda)", kTH2F, {{1000, 0.f, 10.f}, {150, 0, 15}}, false); + fRegistry.add("Track/PID/positive/hITSNsigmaEl", "ITS n sigma el;p_{pv} (GeV/c);n #sigma_{e}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/PID/positive/hITSNsigmaMu", "ITS n sigma mu;p_{pv} (GeV/c);n #sigma_{#mu}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/PID/positive/hITSNsigmaPi", "ITS n sigma pi;p_{pv} (GeV/c);n #sigma_{#pi}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/PID/positive/hITSNsigmaKa", "ITS n sigma ka;p_{pv} (GeV/c);n #sigma_{K}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/PID/positive/hITSNsigmaPr", "ITS n sigma pr;p_{pv} (GeV/c);n #sigma_{p}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.addClone("Track/PID/positive/", "Track/PID/negative/"); + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + const AxisSpec axis_pt{ConfPtlBins, "p_{T,#mu} (GeV/c)"}; + const AxisSpec axis_eta{50, -6, -1, "#eta_{#mu}"}; + const AxisSpec axis_phi{36, 0.0, 2 * M_PI, "#varphi_{#mu} (rad.)"}; + const AxisSpec axis_dca{ConfDCABins, "DCA_{#mu}^{XY} (#sigma)"}; + const AxisSpec axis_charge_gen{3, -1.5, +1.5, "true charge"}; + + // generated info + fRegistry.add("Generated/lf/hs", "gen. single muon", kTHnSparseD, {axis_pt, axis_eta, axis_phi, axis_charge_gen}, true); + fRegistry.addClone("Generated/lf/", "Generated/lf_prompt/"); + fRegistry.addClone("Generated/lf/", "Generated/PromptJPsi/"); + fRegistry.addClone("Generated/lf/", "Generated/NonPromptJPsi/"); + fRegistry.addClone("Generated/lf/", "Generated/PromptPsi2S/"); + fRegistry.addClone("Generated/lf/", "Generated/NonPromptPsi2S/"); + fRegistry.addClone("Generated/lf/", "Generated/c2l/"); + fRegistry.addClone("Generated/lf/", "Generated/b2l/"); + fRegistry.addClone("Generated/lf/", "Generated/b2c2l/"); + + // track info + fRegistry.add("Track/lf/positive/hs", "rec. single muon", kTHnSparseD, {axis_pt, axis_eta, axis_phi, axis_dca, axis_charge_gen}, true); + if (cfgFillQA) { + fRegistry.add("Track/lf/positive/hEtaPhi_MatchMCHMID", "#eta vs. #varphi of matched MCHMID", kTH2F, {{180, 0, 2.f * M_PI}, {100, -6, -1}}, false); + fRegistry.add("Track/lf/positive/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); + fRegistry.add("Track/lf/positive/hTrackType", "track type", kTH1F, {{6, -0.5f, 5.5}}, false); + fRegistry.add("Track/lf/positive/hDCAxy", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", kTH2F, {{200, -0.5f, 0.5f}, {200, -0.5f, 0.5f}}, false); + fRegistry.add("Track/lf/positive/hDCAxySigma", "DCA x vs. y;DCA_{x} (#sigma);DCA_{y} (#sigma)", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/lf/positive/hDCAxRes_Pt", "DCA_{x} resolution vs. pT;p_{T} (GeV/c);DCA_{x} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0, 500}}, false); + fRegistry.add("Track/lf/positive/hDCAyRes_Pt", "DCA_{y} resolution vs. pT;p_{T} (GeV/c);DCA_{y} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0, 500}}, false); + fRegistry.add("Track/lf/positive/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0, 500}}, false); + fRegistry.add("Track/lf/positive/hNclsMCH", "number of MCH clusters", kTH1F, {{21, -0.5, 20.5}}, false); + fRegistry.add("Track/lf/positive/hNclsMFT", "number of MFT clusters", kTH1F, {{11, -0.5, 10.5}}, false); + fRegistry.add("Track/lf/positive/hPDCA", "pDCA;R at absorber (cm);p #times DCA (GeV/c #upoint cm)", kTH2F, {{100, 0, 100}, {100, 0.0f, 1000}}, false); + fRegistry.add("Track/lf/positive/hChi2", "chi2;chi2", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("Track/lf/positive/hChi2MatchMCHMID", "chi2 match MCH-MID;chi2", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("Track/lf/positive/hChi2MatchMCHMFT", "chi2 match MCH-MFT;chi2", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("Track/lf/positive/hMFTClusterMap", "MFT cluster map", kTH1F, {{1024, -0.5, 1023.5}}, false); + fRegistry.add("Track/lf/positive/hPtGen_DeltaPtOverPtGen", "muon p_{T} resolution;p_{T}^{gen} (GeV/c);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{200, 0, 10}, {200, -1.0f, 1.0f}}, true); + fRegistry.add("Track/lf/positive/hPtGen_DeltaEta", "muon #eta resolution;p_{T}^{gen} (GeV/c);#eta^{rec} - #eta^{gen}", kTH2F, {{200, 0, 10}, {100, -0.05f, 0.05f}}, true); + fRegistry.add("Track/lf/positive/hPtGen_DeltaPhi", "muon #varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{200, 0, 10}, {100, -0.05f, 0.05f}}, true); + } + fRegistry.addClone("Track/lf/positive/", "Track/lf/negative/"); + fRegistry.addClone("Track/lf/", "Track/lf_prompt/"); + fRegistry.addClone("Track/lf/", "Track/Photon/"); // this is not for efficiency! only for contamination. We don't store generated photon conversions. + fRegistry.addClone("Track/lf/", "Track/PromptJPsi/"); + fRegistry.addClone("Track/lf/", "Track/NonPromptJPsi/"); + fRegistry.addClone("Track/lf/", "Track/PromptPsi2S/"); + fRegistry.addClone("Track/lf/", "Track/NonPromptPsi2S/"); + fRegistry.addClone("Track/lf/", "Track/c2l/"); + fRegistry.addClone("Track/lf/", "Track/b2l/"); + fRegistry.addClone("Track/lf/", "Track/b2c2l/"); + } + } + + int pdg_lepton = 0; + void init(InitContext&) + { + if (doprocessQCMC && doprocessQCMC_Smeared) { + LOGF(fatal, "Cannot enable processQCMC and processQCMC_Smeared at the same time. Please choose one."); + } + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + rctChecker.init(eventcuts.cfgRCTLabel.value, eventcuts.cfgCheckZDC.value, eventcuts.cfgTreatLimitedAcceptanceAsBad.value); + + DefineEMEventCut(); + addhistograms(); + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + pdg_lepton = 11; + DefineDielectronCut(); + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + pdg_lepton = 13; + DefineDimuonCut(); + } + if (doprocessNorm) { + fRegistry.addClone("Event/before/hCollisionCounter", "Event/norm/hCollisionCounter"); + } + if (doprocessBC) { + auto hTVXCounter = fRegistry.add("BC/hTVXCounter", "TVX counter", kTH1D, {{6, -0.5f, 5.5f}}); + hTVXCounter->GetXaxis()->SetBinLabel(1, "TVX"); + hTVXCounter->GetXaxis()->SetBinLabel(2, "TVX && NoTFB"); + hTVXCounter->GetXaxis()->SetBinLabel(3, "TVX && NoITSROFB"); + hTVXCounter->GetXaxis()->SetBinLabel(4, "TVX && GoodRCT"); + hTVXCounter->GetXaxis()->SetBinLabel(5, "TVX && NoTFB && NoITSROFB"); + hTVXCounter->GetXaxis()->SetBinLabel(6, "TVX && NoTFB && NoITSROFB && GoodRCT"); + } + } + + void DefineEMEventCut() + { + fEMEventCut = EMEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(eventcuts.cfgZvtxMin, eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireNoCollInTimeRangeStandard(eventcuts.cfgRequireNoCollInTimeRangeStandard); + fEMEventCut.SetRequireNoCollInTimeRangeStrict(eventcuts.cfgRequireNoCollInTimeRangeStrict); + fEMEventCut.SetRequireNoCollInITSROFStandard(eventcuts.cfgRequireNoCollInITSROFStandard); + fEMEventCut.SetRequireNoCollInITSROFStrict(eventcuts.cfgRequireNoCollInITSROFStrict); + fEMEventCut.SetRequireNoHighMultCollInPrevRof(eventcuts.cfgRequireNoHighMultCollInPrevRof); + fEMEventCut.SetRequireGoodITSLayer3(eventcuts.cfgRequireGoodITSLayer3); + fEMEventCut.SetRequireGoodITSLayer0123(eventcuts.cfgRequireGoodITSLayer0123); + fEMEventCut.SetRequireGoodITSLayersAll(eventcuts.cfgRequireGoodITSLayersAll); + } + + o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; + void DefineDielectronCut() + { + fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); + + // for track + fDielectronCut.SetTrackPtRange(dielectroncuts.cfg_min_pt_track, dielectroncuts.cfg_max_pt_track); + fDielectronCut.SetTrackEtaRange(dielectroncuts.cfg_min_eta_track, dielectroncuts.cfg_max_eta_track); + fDielectronCut.SetTrackPhiRange(dielectroncuts.cfg_min_phi_track, dielectroncuts.cfg_max_phi_track); + fDielectronCut.SetMinNClustersTPC(dielectroncuts.cfg_min_ncluster_tpc); + fDielectronCut.SetMinNCrossedRowsTPC(dielectroncuts.cfg_min_ncrossedrows); + fDielectronCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fDielectronCut.SetMaxFracSharedClustersTPC(dielectroncuts.cfg_max_frac_shared_clusters_tpc); + fDielectronCut.SetChi2PerClusterTPC(0.0, dielectroncuts.cfg_max_chi2tpc); + fDielectronCut.SetChi2PerClusterITS(0.0, dielectroncuts.cfg_max_chi2its); + fDielectronCut.SetNClustersITS(dielectroncuts.cfg_min_ncluster_its, 7); + fDielectronCut.SetMeanClusterSizeITS(dielectroncuts.cfg_min_its_cluster_size, dielectroncuts.cfg_max_its_cluster_size, dielectroncuts.cfg_min_p_its_cluster_size, dielectroncuts.cfg_max_p_its_cluster_size); + fDielectronCut.SetTrackMaxDcaXY(dielectroncuts.cfg_max_dcaxy); + fDielectronCut.SetTrackMaxDcaZ(dielectroncuts.cfg_max_dcaz); + fDielectronCut.RequireITSibAny(dielectroncuts.cfg_require_itsib_any); + fDielectronCut.RequireITSib1st(dielectroncuts.cfg_require_itsib_1st); + fDielectronCut.SetChi2TOF(0.0, dielectroncuts.cfg_max_chi2tof); + fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); + + // for eID + fDielectronCut.SetPIDScheme(dielectroncuts.cfg_pid_scheme); + fDielectronCut.SetTPCNsigmaElRange(dielectroncuts.cfg_min_TPCNsigmaEl, dielectroncuts.cfg_max_TPCNsigmaEl); + fDielectronCut.SetTPCNsigmaMuRange(dielectroncuts.cfg_min_TPCNsigmaMu, dielectroncuts.cfg_max_TPCNsigmaMu); + fDielectronCut.SetTPCNsigmaPiRange(dielectroncuts.cfg_min_TPCNsigmaPi, dielectroncuts.cfg_max_TPCNsigmaPi); + fDielectronCut.SetTPCNsigmaKaRange(dielectroncuts.cfg_min_TPCNsigmaKa, dielectroncuts.cfg_max_TPCNsigmaKa); + fDielectronCut.SetTPCNsigmaPrRange(dielectroncuts.cfg_min_TPCNsigmaPr, dielectroncuts.cfg_max_TPCNsigmaPr); + fDielectronCut.SetTOFNsigmaElRange(dielectroncuts.cfg_min_TOFNsigmaEl, dielectroncuts.cfg_max_TOFNsigmaEl); + fDielectronCut.SetMaxPinForPionRejectionTPC(dielectroncuts.cfg_max_pin_pirejTPC); + fDielectronCut.SetITSNsigmaKaRange(dielectroncuts.cfg_min_ITSNsigmaKa, dielectroncuts.cfg_max_ITSNsigmaKa); + fDielectronCut.SetITSNsigmaPrRange(dielectroncuts.cfg_min_ITSNsigmaPr, dielectroncuts.cfg_max_ITSNsigmaPr); + fDielectronCut.SetPRangeForITSNsigmaKa(dielectroncuts.cfg_min_p_ITSNsigmaKa, dielectroncuts.cfg_max_p_ITSNsigmaKa); + fDielectronCut.SetPRangeForITSNsigmaPr(dielectroncuts.cfg_min_p_ITSNsigmaPr, dielectroncuts.cfg_max_p_ITSNsigmaPr); + + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { // please call this at the end of DefineDileptonCut + static constexpr int nClassesMl = 2; + const std::vector cutDirMl = {o2::cuts_ml::CutSmaller, o2::cuts_ml::CutNot}; + const std::vector labelsClasses = {"Signal", "Background"}; + const uint32_t nBinsMl = dielectroncuts.binsMl.value.size() - 1; + const std::vector labelsBins(nBinsMl, "bin"); + double cutsMlArr[nBinsMl][nClassesMl]; + for (uint32_t i = 0; i < nBinsMl; i++) { + cutsMlArr[i][0] = dielectroncuts.cutsMl.value[i]; + cutsMlArr[i][1] = 0.; + } + o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; + + mlResponseSingleTrack.configure(dielectroncuts.binsMl.value, cutsMl, cutDirMl, nClassesMl); + if (dielectroncuts.loadModelsFromCCDB) { + ccdbApi.init(ccdburl); + mlResponseSingleTrack.setModelPathsCCDB(dielectroncuts.onnxFileNames.value, ccdbApi, dielectroncuts.onnxPathsCCDB.value, dielectroncuts.timestampCCDB.value); + } else { + mlResponseSingleTrack.setModelPathsLocal(dielectroncuts.onnxFileNames.value); + } + mlResponseSingleTrack.cacheInputFeaturesIndices(dielectroncuts.namesInputFeatures); + mlResponseSingleTrack.cacheBinningIndex(dielectroncuts.nameBinningFeature); + mlResponseSingleTrack.init(dielectroncuts.enableOptimizations.value); + + fDielectronCut.SetPIDMlResponse(&mlResponseSingleTrack); + } // end of PID ML + } + + void DefineDimuonCut() + { + fDimuonCut = DimuonCut("fDimuonCut", "fDimuonCut"); + + // for track + fDimuonCut.SetTrackType(dimuoncuts.cfg_track_type); + fDimuonCut.SetTrackPtRange(dimuoncuts.cfg_min_pt_track, dimuoncuts.cfg_max_pt_track); + fDimuonCut.SetTrackEtaRange(dimuoncuts.cfg_min_eta_track, dimuoncuts.cfg_max_eta_track); + fDimuonCut.SetTrackPhiRange(dimuoncuts.cfg_min_phi_track, dimuoncuts.cfg_max_phi_track); + fDimuonCut.SetNClustersMFT(dimuoncuts.cfg_min_ncluster_mft, 10); + fDimuonCut.SetNClustersMCHMID(dimuoncuts.cfg_min_ncluster_mch, 20); + fDimuonCut.SetChi2(0.f, dimuoncuts.cfg_max_chi2); + fDimuonCut.SetMatchingChi2MCHMFT(0.f, dimuoncuts.cfg_max_matching_chi2_mftmch); + fDimuonCut.SetMatchingChi2MCHMID(0.f, dimuoncuts.cfg_max_matching_chi2_mchmid); + fDimuonCut.SetDCAxy(0.f, dimuoncuts.cfg_max_dcaxy); + fDimuonCut.SetRabs(dimuoncuts.cfg_min_rabs, dimuoncuts.cfg_max_rabs); + fDimuonCut.SetMaxPDCARabsDep([&](float rabs) { return (rabs < 26.5 ? 594.f : 324.f); }); + } + + template + bool isInAcceptance(T const& lepton) + { + float pt = 0.f, eta = 0.f; + if constexpr (isSmeared) { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + pt = lepton.ptSmeared(); + eta = lepton.etaSmeared(); + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (dimuoncuts.cfg_track_type == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + pt = lepton.ptSmeared_sa_muon(); + eta = lepton.etaSmeared_sa_muon(); + } else if (dimuoncuts.cfg_track_type == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + pt = lepton.ptSmeared_gl_muon(); + eta = lepton.etaSmeared_gl_muon(); + } else { + pt = lepton.pt(); + eta = lepton.eta(); + } + } + } else { + pt = lepton.pt(); + eta = lepton.eta(); + } + + if ((mctrackcuts.min_mcPt < pt && pt < mctrackcuts.max_mcPt) && (mctrackcuts.min_mcEta < eta && eta < mctrackcuts.max_mcEta)) { + return true; + } else { + return false; + } + } + + template + void fillTrackInfo(TTrack const& track) + { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + fillElectronInfo(track); + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + fillMuonInfo(track); + } + } + + template + void fillElectronInfo(TTrack const& track) + { + auto mctrack = track.template emmcparticle_as(); + float dca = dca3DinSigma(track); + if (cfgDCAType == 1) { + dca = dcaXYinSigma(track); + } else if (cfgDCAType == 2) { + dca = dcaZinSigma(track); + } + + float weight = 1.f; + if (cfgApplyWeightTTCA) { + weight = map_weight[track.globalIndex()]; + } + // LOGF(info, "map_weight[%d] = %f", track.globalIndex(), weight); + + if (track.sign() > 0) { + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hs"), track.pt(), track.eta(), track.phi(), dca, -mctrack.pdgCode() / pdg_lepton, weight); + if (cfgFillQA) { + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hQoverPt"), track.sign() / track.pt()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxyz"), track.dcaXY(), track.dcaZ()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxyzSigma"), track.dcaXY() / std::sqrt(track.cYY()), track.dcaZ() / std::sqrt(track.cZZ())); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAzRes_Pt"), track.pt(), std::sqrt(track.cZZ()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCA3dRes_Pt"), track.pt(), sigmaDca3D(track) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hNclsITS"), track.itsNCls()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hNclsTPC"), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hTPCNclsShared"), track.pt(), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hChi2ITS"), track.itsChi2NCl()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hChi2TOF"), track.p(), track.tofChi2()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDeltaPin"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hITSClusterMap"), track.itsClusterMap()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hPtGen_DeltaPtOverPtGen"), mctrack.pt(), (track.pt() - mctrack.pt()) / mctrack.pt()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hPtGen_DeltaEta"), mctrack.pt(), track.eta() - mctrack.eta()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hPtGen_DeltaPhi"), mctrack.pt(), track.phi() - mctrack.phi()); + + fRegistry.fill(HIST("Track/PID/positive/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + fRegistry.fill(HIST("Track/PID/positive/hTOFbeta"), track.p(), track.beta()); + fRegistry.fill(HIST("Track/PID/positive/hMeanClusterSizeITS"), track.p(), track.meanClusterSizeITS() * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/PID/positive/hMeanClusterSizeITSib"), track.p(), track.meanClusterSizeITSib() * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/PID/positive/hMeanClusterSizeITSob"), track.p(), track.meanClusterSizeITSob() * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/PID/positive/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/PID/positive/hTPCNsigmaMu"), track.tpcInnerParam(), track.tpcNSigmaMu()); + fRegistry.fill(HIST("Track/PID/positive/hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); + fRegistry.fill(HIST("Track/PID/positive/hTPCNsigmaKa"), track.tpcInnerParam(), track.tpcNSigmaKa()); + fRegistry.fill(HIST("Track/PID/positive/hTPCNsigmaPr"), track.tpcInnerParam(), track.tpcNSigmaPr()); + fRegistry.fill(HIST("Track/PID/positive/hTOFNsigmaEl"), track.p(), track.tofNSigmaEl()); + fRegistry.fill(HIST("Track/PID/positive/hTOFNsigmaMu"), track.p(), track.tofNSigmaMu()); + fRegistry.fill(HIST("Track/PID/positive/hTOFNsigmaPi"), track.p(), track.tofNSigmaPi()); + fRegistry.fill(HIST("Track/PID/positive/hTOFNsigmaKa"), track.p(), track.tofNSigmaKa()); + fRegistry.fill(HIST("Track/PID/positive/hTOFNsigmaPr"), track.p(), track.tofNSigmaPr()); + fRegistry.fill(HIST("Track/PID/positive/hITSNsigmaEl"), track.p(), track.itsNSigmaEl()); + fRegistry.fill(HIST("Track/PID/positive/hITSNsigmaMu"), track.p(), track.itsNSigmaMu()); + fRegistry.fill(HIST("Track/PID/positive/hITSNsigmaPi"), track.p(), track.itsNSigmaPi()); + fRegistry.fill(HIST("Track/PID/positive/hITSNsigmaKa"), track.p(), track.itsNSigmaKa()); + fRegistry.fill(HIST("Track/PID/positive/hITSNsigmaPr"), track.p(), track.itsNSigmaPr()); + } + } else { + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hs"), track.pt(), track.eta(), track.phi(), dca, -mctrack.pdgCode() / pdg_lepton, weight); + if (cfgFillQA) { + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hQoverPt"), track.sign() / track.pt()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxyz"), track.dcaXY(), track.dcaZ()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxyzSigma"), track.dcaXY() / std::sqrt(track.cYY()), track.dcaZ() / std::sqrt(track.cZZ())); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAzRes_Pt"), track.pt(), std::sqrt(track.cZZ()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCA3dRes_Pt"), track.pt(), sigmaDca3D(track) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hNclsITS"), track.itsNCls()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hNclsTPC"), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hTPCNclsShared"), track.pt(), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hChi2ITS"), track.itsChi2NCl()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hChi2TOF"), track.p(), track.tofChi2()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDeltaPin"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hITSClusterMap"), track.itsClusterMap()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hPtGen_DeltaPtOverPtGen"), mctrack.pt(), (track.pt() - mctrack.pt()) / mctrack.pt()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hPtGen_DeltaEta"), mctrack.pt(), track.eta() - mctrack.eta()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hPtGen_DeltaPhi"), mctrack.pt(), track.phi() - mctrack.phi()); + + fRegistry.fill(HIST("Track/PID/negative/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + fRegistry.fill(HIST("Track/PID/negative/hTOFbeta"), track.p(), track.beta()); + fRegistry.fill(HIST("Track/PID/negative/hMeanClusterSizeITS"), track.p(), track.meanClusterSizeITS() * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/PID/negative/hMeanClusterSizeITSib"), track.p(), track.meanClusterSizeITSib() * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/PID/negative/hMeanClusterSizeITSob"), track.p(), track.meanClusterSizeITSob() * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/PID/negative/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/PID/negative/hTPCNsigmaMu"), track.tpcInnerParam(), track.tpcNSigmaMu()); + fRegistry.fill(HIST("Track/PID/negative/hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); + fRegistry.fill(HIST("Track/PID/negative/hTPCNsigmaKa"), track.tpcInnerParam(), track.tpcNSigmaKa()); + fRegistry.fill(HIST("Track/PID/negative/hTPCNsigmaPr"), track.tpcInnerParam(), track.tpcNSigmaPr()); + fRegistry.fill(HIST("Track/PID/negative/hTOFNsigmaEl"), track.p(), track.tofNSigmaEl()); + fRegistry.fill(HIST("Track/PID/negative/hTOFNsigmaMu"), track.p(), track.tofNSigmaMu()); + fRegistry.fill(HIST("Track/PID/negative/hTOFNsigmaPi"), track.p(), track.tofNSigmaPi()); + fRegistry.fill(HIST("Track/PID/negative/hTOFNsigmaKa"), track.p(), track.tofNSigmaKa()); + fRegistry.fill(HIST("Track/PID/negative/hTOFNsigmaPr"), track.p(), track.tofNSigmaPr()); + fRegistry.fill(HIST("Track/PID/negative/hITSNsigmaEl"), track.p(), track.itsNSigmaEl()); + fRegistry.fill(HIST("Track/PID/negative/hITSNsigmaMu"), track.p(), track.itsNSigmaMu()); + fRegistry.fill(HIST("Track/PID/negative/hITSNsigmaPi"), track.p(), track.itsNSigmaPi()); + fRegistry.fill(HIST("Track/PID/negative/hITSNsigmaKa"), track.p(), track.itsNSigmaKa()); + fRegistry.fill(HIST("Track/PID/negative/hITSNsigmaPr"), track.p(), track.itsNSigmaPr()); + } + } + } + + template + void fillMuonInfo(TTrack const& track) + { + auto mctrack = track.template emmcparticle_as(); + float dca_xy = fwdDcaXYinSigma(track); + + float weight = 1.f; + if (cfgApplyWeightTTCA) { + weight = map_weight[track.globalIndex()]; + } + // LOGF(info, "map_weight[%d] = %f", track.globalIndex(), weight); + + if (track.sign() > 0) { + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hs"), track.pt(), track.eta(), track.phi(), dca_xy, -mctrack.pdgCode() / pdg_lepton, weight); + if (cfgFillQA) { + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hEtaPhi_MatchMCHMID"), track.phiMatchedMCHMID(), track.etaMatchedMCHMID(), weight); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hQoverPt"), track.sign() / track.pt()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hTrackType"), track.trackType()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxy"), track.fwdDcaX(), track.fwdDcaY()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxySigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXXatDCA()) * 1e+4); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYYatDCA()) * 1e+4); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxyRes_Pt"), track.pt(), sigmaFwdDcaXY(track) * 1e+4); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hNclsMCH"), track.nClusters()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hNclsMFT"), track.nClustersMFT()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hPDCA"), track.rAtAbsorberEnd(), track.pDca()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hChi2"), track.chi2()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hChi2MatchMCHMID"), track.chi2MatchMCHMID()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hChi2MatchMCHMFT"), track.chi2MatchMCHMFT()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hMFTClusterMap"), track.mftClusterMap()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hPtGen_DeltaPtOverPtGen"), mctrack.pt(), (track.pt() - mctrack.pt()) / mctrack.pt()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hPtGen_DeltaEta"), mctrack.pt(), track.eta() - mctrack.eta()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hPtGen_DeltaPhi"), mctrack.pt(), track.phi() - mctrack.phi()); + } + } else { + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hs"), track.pt(), track.eta(), track.phi(), dca_xy, -mctrack.pdgCode() / pdg_lepton, weight); + if (cfgFillQA) { + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hEtaPhi_MatchMCHMID"), track.phiMatchedMCHMID(), track.etaMatchedMCHMID(), weight); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hQoverPt"), track.sign() / track.pt()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hTrackType"), track.trackType()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxy"), track.fwdDcaX(), track.fwdDcaY()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxySigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXXatDCA()) * 1e+4); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYYatDCA()) * 1e+4); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxyRes_Pt"), track.pt(), sigmaFwdDcaXY(track) * 1e+4); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hNclsMCH"), track.nClusters()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hNclsMFT"), track.nClustersMFT()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hPDCA"), track.rAtAbsorberEnd(), track.pDca()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hChi2"), track.chi2()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hChi2MatchMCHMID"), track.chi2MatchMCHMID()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hChi2MatchMCHMFT"), track.chi2MatchMCHMFT()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hMFTClusterMap"), track.mftClusterMap()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hPtGen_DeltaPtOverPtGen"), mctrack.pt(), (track.pt() - mctrack.pt()) / mctrack.pt()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hPtGen_DeltaEta"), mctrack.pt(), track.eta() - mctrack.eta()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hPtGen_DeltaPhi"), mctrack.pt(), track.phi() - mctrack.phi()); + } + } + } + + template + void runQCMC(TCollisions const& collisions, TTracks const& tracks, TPreslice const& perCollision, TCut const& cut, TMCCollisions const&, TMCParticles const& mcparticles) + { + for (const auto& collision : collisions) { + float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<0, -1>(&fRegistry, collision); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<1, -1>(&fRegistry, collision); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted + + auto tracks_per_coll = tracks.sliceBy(perCollision, collision.globalIndex()); + + for (const auto& track : tracks_per_coll) { + auto mctrack = track.template emmcparticle_as(); + if (std::abs(mctrack.pdgCode()) != pdg_lepton) { + continue; + } + + if (!isInAcceptance(mctrack)) { + continue; + } + if (!mctrack.has_mothers()) { + continue; + } + + auto mccollision_from_track = mctrack.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_track.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + + if (cfgRequireTrueAssociation && (mctrack.emmceventId() != collision.emmceventId())) { + continue; + } + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { + if (!cut.template IsSelectedTrack(track, collision)) { + continue; + } + } else { // cut-based + if (!cut.template IsSelectedTrack(track)) { + continue; + } + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (!cut.template IsSelectedTrack(track)) { + continue; + } + if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(track, cut, tracks)) { + continue; + } + } + + auto mcmother = mcparticles.iteratorAt(mctrack.mothersIds()[0]); + int pdg_mother = std::abs(mcmother.pdgCode()); + + if (mctrack.isPhysicalPrimary() || mctrack.producedByGenerator()) { + if (pdg_mother == 111 || pdg_mother == 221 || pdg_mother == 331 || pdg_mother == 113 || pdg_mother == 223 || pdg_mother == 333) { + fillTrackInfo<0, TMCParticles>(track); // lf + if (IsFromCharm(mcmother, mcparticles) < 0 && IsFromBeauty(mcmother, mcparticles) < 0) { + fillTrackInfo<1, TMCParticles>(track); // lf_prompt + } + } else if (pdg_mother == 443) { + if (IsFromBeauty(mcmother, mcparticles) > 0) { // b is found in full decay chain. + fillTrackInfo<4, TMCParticles>(track); + } else { + fillTrackInfo<3, TMCParticles>(track); + } + } else if (pdg_mother == 100443) { + if (IsFromBeauty(mcmother, mcparticles) > 0) { // b is found in full decay chain. + fillTrackInfo<6, TMCParticles>(track); + } else { + fillTrackInfo<5, TMCParticles>(track); + } + } else if (IsFromBeauty(mctrack, mcparticles) > 0) { // b is found in full decay chain. + if (IsFromCharm(mctrack, mcparticles) > 0) { // c is found in full decay chain. + fillTrackInfo<9, TMCParticles>(track); + } else { + fillTrackInfo<8, TMCParticles>(track); + } + } else if (IsFromCharm(mctrack, mcparticles) > 0) { // c is found in full decay chain. Not from b. + fillTrackInfo<7, TMCParticles>(track); + } + } else { + fillTrackInfo<2, TMCParticles>(track); + } + } // end of track loop + + } // end of collision loop + + } // end of process + + template + void runGenInfo(TCollisions const& collisions, TMCLeptons const& leptonsMC, TMCCollisions const& mccollisions, TMCParticles const& mcparticles) + { + for (const auto& mccollision : mccollisions) { + if (cfgEventGeneratorType >= 0 && mccollision.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + fRegistry.fill(HIST("MCEvent/before/hZvtx"), mccollision.posZ()); + + if (mccollision.mpemeventId() < 0) { + continue; + } + auto collision = collisions.rawIteratorAt(mccollision.mpemeventId()); + + float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + fRegistry.fill(HIST("MCEvent/before/hZvtx_rec"), mccollision.posZ()); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + fRegistry.fill(HIST("MCEvent/after/hZvtx"), mccollision.posZ()); + + auto leptonsMC_per_coll = leptonsMC.sliceByCachedUnsorted(o2::aod::emmcparticle::emmceventId, mccollision.globalIndex(), cache); + for (const auto& lepton : leptonsMC_per_coll) { + if (!(lepton.isPhysicalPrimary() || lepton.producedByGenerator())) { + continue; + } + if (!isInAcceptance(lepton)) { + continue; + } + if (!lepton.has_mothers()) { + continue; + } + auto mcmother = mcparticles.iteratorAt(lepton.mothersIds()[0]); + int pdg_mother = std::abs(mcmother.pdgCode()); + + float pt = 0.f, eta = 0.f, phi = 0.f; + if constexpr (isSmeared) { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + pt = lepton.ptSmeared(); + eta = lepton.etaSmeared(); + phi = lepton.phiSmeared(); + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (dimuoncuts.cfg_track_type == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + pt = lepton.ptSmeared_sa_muon(); + eta = lepton.etaSmeared_sa_muon(); + phi = lepton.phiSmeared_sa_muon(); + } else if (dimuoncuts.cfg_track_type == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + pt = lepton.ptSmeared_gl_muon(); + eta = lepton.etaSmeared_gl_muon(); + phi = lepton.phiSmeared_gl_muon(); + } else { + pt = lepton.pt(); + eta = lepton.eta(); + phi = lepton.phi(); + } + } + } else { + pt = lepton.pt(); + eta = lepton.eta(); + phi = lepton.phi(); + } + + if (pdg_mother == 111 || pdg_mother == 221 || pdg_mother == 331 || pdg_mother == 113 || pdg_mother == 223 || pdg_mother == 333) { + fRegistry.fill(HIST("Generated/lf/hs"), pt, eta, phi, -lepton.pdgCode() / pdg_lepton); + if (IsFromCharm(mcmother, mcparticles) < 0 && IsFromBeauty(mcmother, mcparticles) < 0) { + fRegistry.fill(HIST("Generated/lf_prompt/hs"), pt, eta, phi, -lepton.pdgCode() / pdg_lepton); + } + } else if (pdg_mother == 443) { + if (IsFromBeauty(mcmother, mcparticles) > 0) { // b is found in full decay chain. + fRegistry.fill(HIST("Generated/NonPromptJPsi/hs"), pt, eta, phi, -lepton.pdgCode() / pdg_lepton); + } else { + fRegistry.fill(HIST("Generated/PromptJPsi/hs"), pt, eta, phi, -lepton.pdgCode() / pdg_lepton); + } + } else if (pdg_mother == 100443) { + if (IsFromBeauty(mcmother, mcparticles) > 0) { // b is found in full decay chain. + fRegistry.fill(HIST("Generated/NonPromptPsi2S/hs"), pt, eta, phi, -lepton.pdgCode() / pdg_lepton); + } else { + fRegistry.fill(HIST("Generated/PromptPsi2S/hs"), pt, eta, phi, -lepton.pdgCode() / pdg_lepton); + } + } else if (IsFromBeauty(lepton, mcparticles) > 0) { // b is found in full decay chain. + if (IsFromCharm(lepton, mcparticles) > 0) { // c is found in full decay chain. + fRegistry.fill(HIST("Generated/b2c2l/hs"), pt, eta, phi, -lepton.pdgCode() / pdg_lepton); + } else { + fRegistry.fill(HIST("Generated/b2l/hs"), pt, eta, phi, -lepton.pdgCode() / pdg_lepton); + } + } else if (IsFromCharm(lepton, mcparticles) > 0) { // c is found in full decay chain. Not from b. + fRegistry.fill(HIST("Generated/c2l/hs"), pt, eta, phi, -lepton.pdgCode() / pdg_lepton); + } + } // end of mc lepton loop per collision + + } // end of mc collision loop + } + + std::unordered_map map_weight; // map of track global index -> weight + template + void fillTrackWeightMap(TCollisions const& collisions, TTracks const& tracks, TPreslice const& perCollision, TCut const& cut, TMCCollisions const&, TMCParticles const&) + { + std::vector passed_trackIds; + passed_trackIds.reserve(tracks.size()); + for (const auto& collision : collisions) { + float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + + // auto mccollision = collision.template emmcevent_as(); + // if (cfgEventGeneratorType >= 0 && mccollision.getSubGeneratorId() != cfgEventGeneratorType) { + // continue; + // } + + auto tracks_per_coll = tracks.sliceBy(perCollision, collision.globalIndex()); + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + for (const auto& track : tracks_per_coll) { + auto mctrack = track.template emmcparticle_as(); + auto mccollision_from_track = mctrack.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_track.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { + if (!cut.template IsSelectedTrack(track, collision)) { + continue; + } + } else { // cut-based + if (!cut.template IsSelectedTrack(track)) { + continue; + } + } + passed_trackIds.emplace_back(track.globalIndex()); + } // end of track loop + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + for (const auto& track : tracks_per_coll) { + auto mctrack = track.template emmcparticle_as(); + auto mccollision_from_track = mctrack.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_track.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + if (!cut.template IsSelectedTrack(track)) { + continue; + } + + if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(track, cut, tracks)) { + continue; + } + passed_trackIds.emplace_back(track.globalIndex()); + } // end of track loop + } + } // end of collision loop + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + for (const auto& trackId : passed_trackIds) { + auto track = tracks.rawIteratorAt(trackId); + auto ambIds = track.ambiguousElectronsIds(); + float n = 1.f; // include myself. + for (const auto& ambId : ambIds) { + if (std::find(passed_trackIds.begin(), passed_trackIds.end(), ambId) != passed_trackIds.end()) { + n += 1.f; + } + } + map_weight[trackId] = 1.f / n; + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + for (const auto& trackId : passed_trackIds) { + auto track = tracks.rawIteratorAt(trackId); + auto ambIds = track.ambiguousMuonsIds(); + float n = 1.f; // include myself. + for (const auto& ambId : ambIds) { + if (std::find(passed_trackIds.begin(), passed_trackIds.end(), ambId) != passed_trackIds.end()) { + n += 1.f; + } + } + map_weight[trackId] = 1.f / n; + } + } + + passed_trackIds.clear(); + passed_trackIds.shrink_to_fit(); + } + + SliceCache cache; + Preslice perCollision_electron = aod::emprimaryelectron::emeventId; + Filter trackFilter_electron = dielectroncuts.cfg_min_phi_track < o2::aod::track::phi && o2::aod::track::phi < dielectroncuts.cfg_max_phi_track && o2::aod::track::tpcChi2NCl < dielectroncuts.cfg_max_chi2tpc && o2::aod::track::itsChi2NCl < dielectroncuts.cfg_max_chi2its && nabs(o2::aod::track::dcaXY) < dielectroncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dielectroncuts.cfg_max_dcaz; + Filter pidFilter_electron = dielectroncuts.cfg_min_TPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < dielectroncuts.cfg_max_TPCNsigmaEl; + Filter ttcaFilter_electron = ifnode(dielectroncuts.enableTTCA.node(), o2::aod::emprimaryelectron::isAssociatedToMPC == true || o2::aod::emprimaryelectron::isAssociatedToMPC == false, o2::aod::emprimaryelectron::isAssociatedToMPC == true); + + Preslice perCollision_muon = aod::emprimarymuon::emeventId; + Filter trackFilter_muon = o2::aod::fwdtrack::trackType == dimuoncuts.cfg_track_type && dimuoncuts.cfg_min_phi_track < o2::aod::fwdtrack::phi && o2::aod::fwdtrack::phi < dimuoncuts.cfg_max_phi_track; + Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), o2::aod::emprimarymuon::isAssociatedToMPC == true || o2::aod::emprimarymuon::isAssociatedToMPC == false, o2::aod::emprimarymuon::isAssociatedToMPC == true); + + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + // Filter collisionFilter_multiplicity = cfgNtracksPV08Min <= o2::aod::mult::multNTracksPV && o2::aod::mult::multNTracksPV < cfgNtracksPV08Max; + Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + using FilteredMyCollisions = soa::Filtered; + + Partition electronsMC = nabs(o2::aod::mcparticle::pdgCode) == 11; // e+, e- + Partition muonsMC = nabs(o2::aod::mcparticle::pdgCode) == 13; // mu+, mu- + PresliceUnsorted perMcCollision = aod::emmcparticle::emmceventId; + + // PresliceUnsorted recColperMcCollision = aod::emmceventlabel::emmceventId; + + void processQCMC(FilteredMyCollisions const& collisions, MyMCCollisions const& mccollisions, aod::EMMCParticles const& mcparticles, TLeptons const& tracks) + { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (cfgApplyWeightTTCA) { + fillTrackWeightMap(collisions, tracks, perCollision_electron, fDielectronCut, mccollisions, mcparticles); + } + runQCMC(collisions, tracks, perCollision_electron, fDielectronCut, mccollisions, mcparticles); + runGenInfo(collisions, electronsMC, mccollisions, mcparticles); + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (cfgApplyWeightTTCA) { + fillTrackWeightMap(collisions, tracks, perCollision_muon, fDimuonCut, mccollisions, mcparticles); + } + runQCMC(collisions, tracks, perCollision_muon, fDimuonCut, mccollisions, mcparticles); + runGenInfo(collisions, muonsMC, mccollisions, mcparticles); + } + map_weight.clear(); + } + PROCESS_SWITCH(SingleTrackQCMC, processQCMC, "run single track QC MC", true); + + Partition electronsMC_smeared = nabs(o2::aod::mcparticle::pdgCode) == 11; // e+, e- + Partition muonsMC_smeared = nabs(o2::aod::mcparticle::pdgCode) == 13; // mu+, mu- + + void processQCMC_Smeared(FilteredMyCollisions const& collisions, MyMCCollisions const& mccollisions, TLeptons const& tracks, TSmearedMCParticles const& mcparticles_smeared) + { + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (cfgApplyWeightTTCA) { + fillTrackWeightMap(collisions, tracks, perCollision_electron, fDielectronCut, mccollisions, mcparticles_smeared); + } + runQCMC(collisions, tracks, perCollision_electron, fDielectronCut, mccollisions, mcparticles_smeared); + runGenInfo(collisions, electronsMC_smeared, mccollisions, mcparticles_smeared); + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (cfgApplyWeightTTCA) { + fillTrackWeightMap(collisions, tracks, perCollision_muon, fDimuonCut, mccollisions, mcparticles_smeared); + } + runQCMC(collisions, tracks, perCollision_muon, fDimuonCut, mccollisions, mcparticles_smeared); + runGenInfo(collisions, muonsMC_smeared, mccollisions, mcparticles_smeared); + } + map_weight.clear(); + } + PROCESS_SWITCH(SingleTrackQCMC, processQCMC_Smeared, "run single track QC MC with smearing", false); + + void processNorm(aod::EMEventNormInfos const& collisions) + { + for (const auto& collision : collisions) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 1.0); + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 2.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 3.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 4.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 5.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 6.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 7.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 8.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 9.0); + } + if (collision.sel8()) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 10.0); + } + if (std::fabs(collision.posZ()) < 10.0) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 11.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 12.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 13.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 14.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 15.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 16.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer3)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 17.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 18.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), 19.0); + } + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + fRegistry.fill(HIST("Event/norm/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted + } // end of collision loop + } + PROCESS_SWITCH(SingleTrackQCMC, processNorm, "process normalization info", false); + + void processBC(aod::EMBCs const& bcs) + { + for (const auto& bc : bcs) { + if (bc.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 0.f); + + if (bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 1.f); + } + if (bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 2.f); + } + if (rctChecker(bc)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 3.f); + } + if (bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 4.f); + } + if (bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder) && rctChecker(bc)) { + fRegistry.fill(HIST("BC/hTVXCounter"), 5.f); + } + } + } + } + PROCESS_SWITCH(SingleTrackQCMC, processBC, "process BC counter", false); + + void processDummy(FilteredMyCollisions const&) {} + PROCESS_SWITCH(SingleTrackQCMC, processDummy, "Dummy function", false); +}; + +#endif // PWGEM_DILEPTON_CORE_SINGLETRACKQCMC_H_ diff --git a/PWGEM/Dilepton/DataModel/dileptonTables.h b/PWGEM/Dilepton/DataModel/dileptonTables.h new file mode 100644 index 00000000000..58710293c0f --- /dev/null +++ b/PWGEM/Dilepton/DataModel/dileptonTables.h @@ -0,0 +1,645 @@ +// 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. + +#include +#include +#include +#include "Common/Core/RecoDecay.h" +#include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Qvectors.h" + +#ifndef PWGEM_DILEPTON_DATAMODEL_DILEPTONTABLES_H_ +#define PWGEM_DILEPTON_DATAMODEL_DILEPTONTABLES_H_ + +namespace o2::aod +{ + +namespace pwgem::dilepton::swt +{ +enum class swtAliases : int { // software trigger aliases for EM + kHighTrackMult = 0, + kHighFt0Mult, + kSingleE, + kLMeeIMR, + kLMeeHMR, + kDiElectron, + kSingleMuLow, + kSingleMuHigh, + kDiMuon, + kNaliases +}; + +const std::unordered_map aliasLabels = { + {"fHighTrackMult", static_cast(o2::aod::pwgem::dilepton::swt::swtAliases::kHighTrackMult)}, + {"fHighFt0Mult", static_cast(o2::aod::pwgem::dilepton::swt::swtAliases::kHighFt0Mult)}, + {"fSingleE", static_cast(o2::aod::pwgem::dilepton::swt::swtAliases::kSingleE)}, + {"fLMeeIMR", static_cast(o2::aod::pwgem::dilepton::swt::swtAliases::kLMeeIMR)}, + {"fLMeeHMR", static_cast(o2::aod::pwgem::dilepton::swt::swtAliases::kLMeeHMR)}, + {"fDiElectron", static_cast(o2::aod::pwgem::dilepton::swt::swtAliases::kDiElectron)}, + {"fSingleMuLow", static_cast(o2::aod::pwgem::dilepton::swt::swtAliases::kSingleMuLow)}, + {"fSingleMuHigh", static_cast(o2::aod::pwgem::dilepton::swt::swtAliases::kSingleMuHigh)}, + {"fDiMuon", static_cast(o2::aod::pwgem::dilepton::swt::swtAliases::kDiMuon)}, +}; +} // namespace pwgem::dilepton::swt + +// namespace embc +// { +// DECLARE_SOA_COLUMN(IsTriggerTVX, isTriggerTVX, bool); //! kIsTriggerTVX +// DECLARE_SOA_COLUMN(IsNoTimeFrameBorder, isNoTimeFrameBorder, bool); //! kIsNoTimeFrameBorder +// DECLARE_SOA_COLUMN(IsNoITSROFrameBorder, isNoITSROFrameBorder, bool); //! kNoITSROFrameBorder +// DECLARE_SOA_COLUMN(IsCollisionFound, isCollisionFound, bool); //! at least 1 collision is found in this BC. +// } // namespace embc +// DECLARE_SOA_TABLE(EMBCs, "AOD", "EMBC", //! bc information for normalization +// o2::soa::Index<>, embc::IsTriggerTVX, embc::IsNoTimeFrameBorder, embc::IsNoITSROFrameBorder, embc::IsCollisionFound); + +DECLARE_SOA_TABLE(EMBCs, "AOD", "EMBC", //! bc information for normalization + o2::soa::Index<>, evsel::Alias, evsel::Selection, evsel::Rct); +using EMBC = EMBCs::iterator; + +namespace emevent +{ +DECLARE_SOA_COLUMN(CollisionId, collisionId, int); +DECLARE_SOA_BITMAP_COLUMN(SWTAliasTmp, swtaliastmp, 16); //! Bitmask of fired trigger aliases (see above for definitions) to be join to aod::Collisions for skimming +DECLARE_SOA_BITMAP_COLUMN(SWTAlias, swtalias, 16); //! Bitmask of fired trigger aliases (see above for definitions) to be join to aod::EMEvents for analysis +DECLARE_SOA_COLUMN(NInspectedTVX, nInspectedTVX, uint64_t); +DECLARE_SOA_COLUMN(NeeULS, neeuls, int); +DECLARE_SOA_COLUMN(NeeLSpp, neelspp, int); +DECLARE_SOA_COLUMN(NeeLSmm, neelsmm, int); +DECLARE_SOA_COLUMN(Bz, bz, float); //! kG +DECLARE_SOA_COLUMN(Q2xFT0M, q2xft0m, float); //! Qx for 2nd harmonics in FT0M +DECLARE_SOA_COLUMN(Q2yFT0M, q2yft0m, float); //! Qy for 2nd harmonics in FT0M +DECLARE_SOA_COLUMN(Q2xFT0A, q2xft0a, float); //! Qx for 2nd harmonics in FT0A (i.e. positive eta) +DECLARE_SOA_COLUMN(Q2yFT0A, q2yft0a, float); //! Qy for 2nd harmonics in FT0A (i.e. positive eta) +DECLARE_SOA_COLUMN(Q2xFT0C, q2xft0c, float); //! Qx for 2nd harmonics in FT0C (i.e. negative eta) +DECLARE_SOA_COLUMN(Q2yFT0C, q2yft0c, float); //! Qy for 2nd harmonics in FT0C (i.e. negative eta) +DECLARE_SOA_COLUMN(Q2xBPos, q2xbpos, float); //! Qx for 2nd harmonics in Barrel positive eta region +DECLARE_SOA_COLUMN(Q2yBPos, q2ybpos, float); //! Qy for 2nd harmonics in Barrel positive eta region +DECLARE_SOA_COLUMN(Q2xBNeg, q2xbneg, float); //! Qx for 2nd harmonics in Barrel negative eta region +DECLARE_SOA_COLUMN(Q2yBNeg, q2ybneg, float); //! Qy for 2nd harmonics in Barrel negative eta region +DECLARE_SOA_COLUMN(Q2xBTot, q2xbtot, float); //! Qx for 2nd harmonics in Barrel full eta region +DECLARE_SOA_COLUMN(Q2yBTot, q2ybtot, float); //! Qy for 2nd harmonics in Barrel full eta region +DECLARE_SOA_COLUMN(Q3xFT0M, q3xft0m, float); //! Qx for 3rd harmonics in FT0M +DECLARE_SOA_COLUMN(Q3yFT0M, q3yft0m, float); //! Qy for 3rd harmonics in FT0M +DECLARE_SOA_COLUMN(Q3xFT0A, q3xft0a, float); //! Qx for 3rd harmonics in FT0A (i.e. positive eta) +DECLARE_SOA_COLUMN(Q3yFT0A, q3yft0a, float); //! Qy for 3rd harmonics in FT0A (i.e. positive eta) +DECLARE_SOA_COLUMN(Q3xFT0C, q3xft0c, float); //! Qx for 3rd harmonics in FT0C (i.e. negative eta) +DECLARE_SOA_COLUMN(Q3yFT0C, q3yft0c, float); //! Qy for 3rd harmonics in FT0C (i.e. negative eta) +DECLARE_SOA_COLUMN(Q3xBPos, q3xbpos, float); //! Qx for 3rd harmonics in Barrel positive eta region +DECLARE_SOA_COLUMN(Q3yBPos, q3ybpos, float); //! Qy for 3rd harmonics in Barrel positive eta region +DECLARE_SOA_COLUMN(Q3xBNeg, q3xbneg, float); //! Qx for 3rd harmonics in Barrel negative eta region +DECLARE_SOA_COLUMN(Q3yBNeg, q3ybneg, float); //! Qy for 3rd harmonics in Barrel negative eta region +DECLARE_SOA_COLUMN(Q3xBTot, q3xbtot, float); //! Qx for 3rd harmonics in Barrel full eta region +DECLARE_SOA_COLUMN(Q3yBTot, q3ybtot, float); //! Qy for 3rd harmonics in Barrel full eta region +DECLARE_SOA_COLUMN(Q4xFT0M, q4xft0m, float); //! Qx for 4th harmonics in FT0M +DECLARE_SOA_COLUMN(Q4yFT0M, q4yft0m, float); //! Qy for 4th harmonics in FT0M +DECLARE_SOA_COLUMN(Q4xFT0A, q4xft0a, float); //! Qx for 4th harmonics in FT0A (i.e. positive eta) +DECLARE_SOA_COLUMN(Q4yFT0A, q4yft0a, float); //! Qy for 4th harmonics in FT0A (i.e. positive eta) +DECLARE_SOA_COLUMN(Q4xFT0C, q4xft0c, float); //! Qx for 4th harmonics in FT0C (i.e. negative eta) +DECLARE_SOA_COLUMN(Q4yFT0C, q4yft0c, float); //! Qy for 4th harmonics in FT0C (i.e. negative eta) +DECLARE_SOA_COLUMN(Q4xBPos, q4xbpos, float); //! Qx for 4th harmonics in Barrel positive eta region +DECLARE_SOA_COLUMN(Q4yBPos, q4ybpos, float); //! Qy for 4th harmonics in Barrel positive eta region +DECLARE_SOA_COLUMN(Q4xBNeg, q4xbneg, float); //! Qx for 4th harmonics in Barrel negative eta region +DECLARE_SOA_COLUMN(Q4yBNeg, q4ybneg, float); //! Qy for 4th harmonics in Barrel negative eta region +DECLARE_SOA_COLUMN(Q4xBTot, q4xbtot, float); //! Qx for 4th harmonics in Barrel full eta region +DECLARE_SOA_COLUMN(Q4yBTot, q4ybtot, float); //! Qy for 4th harmonics in Barrel full eta region +DECLARE_SOA_COLUMN(SpherocityPtWeighted, spherocity_ptweighted, float); //! transverse spherocity +DECLARE_SOA_COLUMN(SpherocityPtUnWeighted, spherocity_ptunweighted, float); //! transverse spherocity +DECLARE_SOA_COLUMN(NtrackSpherocity, ntspherocity, int); +DECLARE_SOA_COLUMN(IsSelected, isSelected, bool); //! MB event selection info +DECLARE_SOA_COLUMN(IsEoI, isEoI, bool); //! lepton or photon exists in MB event (not for CEFP) +DECLARE_SOA_COLUMN(PosZint16, posZint16, int16_t); //! this is only to reduce data size +DECLARE_SOA_DYNAMIC_COLUMN(PosZ, posZ, [](int16_t posZint16) -> float { return static_cast(posZint16) * 0.1f; }); + +DECLARE_SOA_DYNAMIC_COLUMN(Sel8, sel8, [](uint64_t selection_bit) -> bool { return (selection_bit & BIT(o2::aod::evsel::kIsTriggerTVX)) && (selection_bit & BIT(o2::aod::evsel::kNoTimeFrameBorder)) && (selection_bit & BIT(o2::aod::evsel::kNoITSROFrameBorder)); }); +DECLARE_SOA_DYNAMIC_COLUMN(EP2FT0M, ep2ft0m, [](float q2x, float q2y) -> float { return std::atan2(q2y, q2x) / 2.0; }); +DECLARE_SOA_DYNAMIC_COLUMN(EP2FT0A, ep2ft0a, [](float q2x, float q2y) -> float { return std::atan2(q2y, q2x) / 2.0; }); +DECLARE_SOA_DYNAMIC_COLUMN(EP2FT0C, ep2ft0c, [](float q2x, float q2y) -> float { return std::atan2(q2y, q2x) / 2.0; }); +DECLARE_SOA_DYNAMIC_COLUMN(EP2BPos, ep2bpos, [](float q2x, float q2y) -> float { return std::atan2(q2y, q2x) / 2.0; }); +DECLARE_SOA_DYNAMIC_COLUMN(EP2BNeg, ep2bneg, [](float q2x, float q2y) -> float { return std::atan2(q2y, q2x) / 2.0; }); +DECLARE_SOA_DYNAMIC_COLUMN(EP2BTot, ep2btot, [](float q2x, float q2y) -> float { return std::atan2(q2y, q2x) / 2.0; }); +DECLARE_SOA_DYNAMIC_COLUMN(EP3FT0M, ep3ft0m, [](float q3x, float q3y) -> float { return std::atan2(q3y, q3x) / 3.0; }); +DECLARE_SOA_DYNAMIC_COLUMN(EP3FT0A, ep3ft0a, [](float q3x, float q3y) -> float { return std::atan2(q3y, q3x) / 3.0; }); +DECLARE_SOA_DYNAMIC_COLUMN(EP3FT0C, ep3ft0c, [](float q3x, float q3y) -> float { return std::atan2(q3y, q3x) / 3.0; }); +DECLARE_SOA_DYNAMIC_COLUMN(EP3BPos, ep3bpos, [](float q3x, float q3y) -> float { return std::atan2(q3y, q3x) / 3.0; }); +DECLARE_SOA_DYNAMIC_COLUMN(EP3BNeg, ep3bneg, [](float q3x, float q3y) -> float { return std::atan2(q3y, q3x) / 3.0; }); +DECLARE_SOA_DYNAMIC_COLUMN(EP3BTot, ep3btot, [](float q3x, float q3y) -> float { return std::atan2(q3y, q3x) / 3.0; }); +DECLARE_SOA_DYNAMIC_COLUMN(EP4FT0M, ep4ft0m, [](float q4x, float q4y) -> float { return std::atan2(q4y, q4x) / 4.0; }); +DECLARE_SOA_DYNAMIC_COLUMN(EP4FT0A, ep4ft0a, [](float q4x, float q4y) -> float { return std::atan2(q4y, q4x) / 4.0; }); +DECLARE_SOA_DYNAMIC_COLUMN(EP4FT0C, ep4ft0c, [](float q4x, float q4y) -> float { return std::atan2(q4y, q4x) / 4.0; }); +DECLARE_SOA_DYNAMIC_COLUMN(EP4BPos, ep4bpos, [](float q4x, float q4y) -> float { return std::atan2(q4y, q4x) / 4.0; }); +DECLARE_SOA_DYNAMIC_COLUMN(EP4BNeg, ep4bneg, [](float q4x, float q4y) -> float { return std::atan2(q4y, q4x) / 4.0; }); +DECLARE_SOA_DYNAMIC_COLUMN(EP4BTot, ep4btot, [](float q4x, float q4y) -> float { return std::atan2(q4y, q4x) / 4.0; }); +} // namespace emevent + +DECLARE_SOA_TABLE_VERSIONED(EMEvents_001, "AOD", "EMEVENT", 1, //! Main event information table + o2::soa::Index<>, emevent::CollisionId, bc::RunNumber, bc::GlobalBC, evsel::Alias, evsel::Selection, timestamp::Timestamp, + collision::PosX, collision::PosY, collision::PosZ, + collision::NumContrib, evsel::NumTracksInTimeRange, evsel::SumAmpFT0CInTimeRange, emevent::Sel8); + +DECLARE_SOA_TABLE_VERSIONED(EMEvents_002, "AOD", "EMEVENT", 2, //! Main event information table + o2::soa::Index<>, emevent::CollisionId, bc::RunNumber, bc::GlobalBC, evsel::Alias, evsel::Selection, evsel::Rct, timestamp::Timestamp, + collision::PosX, collision::PosY, collision::PosZ, + collision::NumContrib, evsel::NumTracksInTimeRange, evsel::SumAmpFT0CInTimeRange, emevent::Sel8); + +using EMEvents = EMEvents_002; +using EMEvent = EMEvents::iterator; + +DECLARE_SOA_TABLE(EMEventsCov, "AOD", "EMEVENTCOV", //! joinable to EMEvents + collision::CovXX, collision::CovXY, collision::CovXZ, collision::CovYY, collision::CovYZ, collision::CovZZ, collision::Chi2, o2::soa::Marker<1>); +using EMEventCov = EMEventsCov::iterator; + +DECLARE_SOA_TABLE(EMEventsBz, "AOD", "EMEVENTBZ", emevent::Bz); // joinable to EMEvents +using EMEventBz = EMEventsBz::iterator; + +DECLARE_SOA_TABLE(EMEventsMult, "AOD", "EMEVENTMULT", //! event multiplicity table, joinable to EMEvents + mult::MultFT0A, mult::MultFT0C, mult::MultNTracksPV, mult::MultNTracksPVeta1, mult::MultNTracksPVetaHalf, + mult::IsInelGt0, mult::IsInelGt1, mult::MultFT0M); +using EMEventMult = EMEventsMult::iterator; + +DECLARE_SOA_TABLE(EMEventsCent, "AOD", "EMEVENTCENT", //! event centrality table, joinable to EMEvents + cent::CentFT0M, cent::CentFT0A, cent::CentFT0C); +using EMEventCent = EMEventsCent::iterator; + +DECLARE_SOA_TABLE(EMEventsQvec, "AOD", "EMEVENTQVEC", //! event q vector table, joinable to EMEvents + emevent::Q2xFT0M, emevent::Q2yFT0M, emevent::Q2xFT0A, emevent::Q2yFT0A, emevent::Q2xFT0C, emevent::Q2yFT0C, + emevent::Q2xBPos, emevent::Q2yBPos, emevent::Q2xBNeg, emevent::Q2yBNeg, emevent::Q2xBTot, emevent::Q2yBTot, + emevent::Q3xFT0M, emevent::Q3yFT0M, emevent::Q3xFT0A, emevent::Q3yFT0A, emevent::Q3xFT0C, emevent::Q3yFT0C, + emevent::Q3xBPos, emevent::Q3yBPos, emevent::Q3xBNeg, emevent::Q3yBNeg, emevent::Q3xBTot, emevent::Q3yBTot, + // emevent::Q4xFT0M, emevent::Q4yFT0M, emevent::Q4xFT0A, emevent::Q4yFT0A, emevent::Q4xFT0C, emevent::Q4yFT0C, + // emevent::Q4xBPos, emevent::Q4yBPos, emevent::Q4xBNeg, emevent::Q4yBNeg, emevent::Q4xBTot, emevent::Q4yBTot, + + // Dynamic columns + emevent::EP2FT0M, + emevent::EP2FT0A, + emevent::EP2FT0C, + emevent::EP2BPos, + emevent::EP2BNeg, + emevent::EP2BTot, + emevent::EP3FT0M, + emevent::EP3FT0A, + emevent::EP3FT0C, + emevent::EP3BPos, + emevent::EP3BNeg, + emevent::EP3BTot); +// emevent::EP4FT0M, +// emevent::EP4FT0A, +// emevent::EP4FT0C, +// emevent::EP4BPos, +// emevent::EP4BNeg, +// emevent::EP4BTot +using EMEventQvec = EMEventsQvec::iterator; + +DECLARE_SOA_TABLE(EMSWTriggerInfos, "AOD", "EMSWTRIGGERINFO", //! joinable to EMEvents + emevent::SWTAlias, emevent::NInspectedTVX); +using EMSWTriggerInfo = EMSWTriggerInfos::iterator; + +DECLARE_SOA_TABLE(EMSWTriggerInfosTMP, "AOD", "EMSWTTMP", //! joinable to aod::Collisions + emevent::SWTAliasTmp, emevent::NInspectedTVX); +using EMSWTriggerInfoTMP = EMSWTriggerInfosTMP::iterator; + +DECLARE_SOA_TABLE(EMEventsProperty, "AOD", "EMEVENTPROP", //! joinable to EMEvents + emevent::SpherocityPtWeighted, emevent::SpherocityPtUnWeighted, emevent::NtrackSpherocity); +using EMEventProperty = EMEventsProperty::iterator; + +DECLARE_SOA_TABLE(EMEventsNee, "AOD", "EMEVENTNEE", emevent::NeeULS, emevent::NeeLSpp, emevent::NeeLSmm); // joinable to EMEvents or aod::Collisions +using EMEventNee = EMEventsNee::iterator; + +DECLARE_SOA_TABLE(EMEvSels, "AOD", "EMEVSEL", //! joinable to aod::Collisions + emevent::IsSelected); +using EMEvSel = EMEvSels::iterator; + +DECLARE_SOA_TABLE(EMEoIs, "AOD", "EMEOI", //! joinable to aod::Collisions in createEMEventDilepton.cxx + emevent::IsEoI); +using EMEoI = EMEoIs::iterator; + +DECLARE_SOA_TABLE(EMEventNormInfos, "AOD", "EMEVENTNORMINFO", //! event information for normalization + o2::soa::Index<>, evsel::Alias, evsel::Selection, evsel::Rct, emevent::PosZint16, cent::CentFT0C, emevent::PosZ, emevent::Sel8); +using EMEventNormInfo = EMEventNormInfos::iterator; + +namespace emmcevent +{ +DECLARE_SOA_INDEX_COLUMN(EMEvent, mpemevent); //! most propable emeventId +DECLARE_SOA_COLUMN(McCollisionId, mcCollisionId, int); +} // namespace emmcevent + +DECLARE_SOA_TABLE(EMMCEvents, "AOD", "EMMCEVENT", //! MC event information table + o2::soa::Index<>, emmcevent::McCollisionId, mccollision::GeneratorsID, + mccollision::PosX, mccollision::PosY, mccollision::PosZ, + mccollision::ImpactParameter, mccollision::EventPlaneAngle, + + // dynamic column + mccollision::GetGeneratorId, + mccollision::GetSubGeneratorId, + mccollision::GetSourceId); +using EMMCEvent = EMMCEvents::iterator; + +DECLARE_SOA_TABLE(MostProbableEMEventIdsInMC, "AOD", "MPEMEVENTIDINMC", emmcevent::EMEventId); // To be joined with EMMCEvents table at analysis level. +using MostProbableEMEventIdInMC = MostProbableEMEventIdsInMC::iterator; + +namespace emmceventlabel +{ +DECLARE_SOA_INDEX_COLUMN(EMMCEvent, emmcevent); //! MC collision +DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); //! Bit mask to indicate collision mismatches (bit ON means mismatch). Bit 15: indicates negative label +} // namespace emmceventlabel + +DECLARE_SOA_TABLE(EMMCEventLabels, "AOD", "EMMCEVENTLABEL", //! Table joined to the EMEvents table containing the MC index + emmceventlabel::EMMCEventId, emmceventlabel::McMask); +using EMMCEventLabel = EMMCEventLabels::iterator; + +namespace emmcparticle +{ +DECLARE_SOA_INDEX_COLUMN(EMMCEvent, emmcevent); +DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(Mothers, mothers); //! Mother tracks (possible empty) array. Iterate over mcParticle.mothers_as()) +DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(Daughters, daughters); //! Daughter tracks (possibly empty) array. Check for non-zero with mcParticle.has_daughters(). Iterate over mcParticle.daughters_as()) +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float px, float py) -> float { return RecoDecay::sqrtSumOfSquares(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, [](float px, float py, float pz) -> float { return RecoDecay::eta(std::array{px, py, pz}); }); +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, [](float px, float py) -> float { return RecoDecay::phi(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float px, float py, float pz) -> float { return RecoDecay::sqrtSumOfSquares(px, py, pz); }); +DECLARE_SOA_DYNAMIC_COLUMN(Y, y, //! Particle rapidity + [](float pz, float e) -> float { + if ((e - pz) > static_cast(1e-7)) { + return 0.5f * std::log((e + pz) / (e - pz)); + } else { + return -999.0f; + } + }); +} // namespace emmcparticle + +// This table contains all MC truth tracks +DECLARE_SOA_TABLE_FULL(EMMCParticles, "EMMCParticles", "AOD", "EMMCPARTICLE", //! MC track information (on disk) + o2::soa::Index<>, emmcparticle::EMMCEventId, + mcparticle::PdgCode, mcparticle::Flags, + emmcparticle::MothersIds, emmcparticle::DaughtersIds, + mcparticle::Px, mcparticle::Py, mcparticle::Pz, mcparticle::E, + mcparticle::Vx, mcparticle::Vy, mcparticle::Vz, + + // dynamic column + emmcparticle::Pt, + emmcparticle::Eta, + emmcparticle::Phi, + + emmcparticle::P, + emmcparticle::Y, + mcparticle::ProducedByGenerator, + mcparticle::FromBackgroundEvent, + mcparticle::IsPhysicalPrimary); + +using EMMCParticle = EMMCParticles::iterator; + +namespace emmcgenvectormeson +{ +DECLARE_SOA_INDEX_COLUMN(EMMCEvent, emmcevent); +DECLARE_SOA_COLUMN(DownScalingFactor, dsf, float); //! down scaling factor to store this mc particle in reduced AO2D.root +} // namespace emmcgenvectormeson + +DECLARE_SOA_TABLE_FULL(EMMCGenVectorMesons, "EMMCGenVectorMesons", "AOD", "EMMCGENVM", //! generated omega, phi information + o2::soa::Index<>, emmcgenvectormeson::EMMCEventId, + mcparticle::PdgCode, mcparticle::Flags, + mcparticle::Px, mcparticle::Py, mcparticle::Pz, mcparticle::E, + emmcgenvectormeson::DownScalingFactor, + + // dynamic column + emmcparticle::Pt, + emmcparticle::Eta, + emmcparticle::Phi, + + emmcparticle::P, + emmcparticle::Y, + mcparticle::ProducedByGenerator, + mcparticle::FromBackgroundEvent, + mcparticle::IsPhysicalPrimary); + +using EMMCGenVectorMeson = EMMCGenVectorMesons::iterator; + +namespace smearedtrack +{ +DECLARE_SOA_COLUMN(PtSmeared, ptSmeared, float); +DECLARE_SOA_COLUMN(EtaSmeared, etaSmeared, float); +DECLARE_SOA_COLUMN(PhiSmeared, phiSmeared, float); +DECLARE_SOA_COLUMN(Efficiency, efficiency, float); +DECLARE_SOA_COLUMN(DCA, dca, float); + +DECLARE_SOA_COLUMN(PtSmearedSAMuon, ptSmeared_sa_muon, float); +DECLARE_SOA_COLUMN(EtaSmearedSAMuon, etaSmeared_sa_muon, float); +DECLARE_SOA_COLUMN(PhiSmearedSAMuon, phiSmeared_sa_muon, float); +DECLARE_SOA_COLUMN(EfficiencySAMuon, efficiency_sa_muon, float); +DECLARE_SOA_COLUMN(DCASAMuon, dca_sa_muon, float); +DECLARE_SOA_COLUMN(PtSmearedGLMuon, ptSmeared_gl_muon, float); +DECLARE_SOA_COLUMN(EtaSmearedGLMuon, etaSmeared_gl_muon, float); +DECLARE_SOA_COLUMN(PhiSmearedGLMuon, phiSmeared_gl_muon, float); +DECLARE_SOA_COLUMN(EfficiencyGLMuon, efficiency_gl_muon, float); +DECLARE_SOA_COLUMN(DCAGLMuon, dca_gl_muon, float); +} // namespace smearedtrack + +DECLARE_SOA_TABLE(SmearedElectrons, "AOD", "SMEAREDEL", // usage Join + smearedtrack::PtSmeared, smearedtrack::EtaSmeared, smearedtrack::PhiSmeared, smearedtrack::Efficiency, smearedtrack::DCA); +using SmearedElectron = SmearedElectrons::iterator; + +DECLARE_SOA_TABLE(SmearedMuons, "AOD", "SMEAREDMU", // usage Join + smearedtrack::PtSmearedSAMuon, smearedtrack::EtaSmearedSAMuon, smearedtrack::PhiSmearedSAMuon, smearedtrack::EfficiencySAMuon, smearedtrack::DCASAMuon, + smearedtrack::PtSmearedGLMuon, smearedtrack::EtaSmearedGLMuon, smearedtrack::PhiSmearedGLMuon, smearedtrack::EfficiencyGLMuon, smearedtrack::DCAGLMuon); +using SmearedMuon = SmearedMuons::iterator; + +namespace emprimaryelectronmclabel +{ +DECLARE_SOA_INDEX_COLUMN(EMMCParticle, emmcparticle); //! +DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); +} // namespace emprimaryelectronmclabel + +// NOTE: MC labels. This table has one entry for each reconstructed track (joinable with EMPrimaryElectrons table) +DECLARE_SOA_TABLE(EMPrimaryElectronMCLabels, "AOD", "EMPRMELMCLABEL", //! + emprimaryelectronmclabel::EMMCParticleId, emprimaryelectronmclabel::McMask); +using EMPrimaryElectronMCLabel = EMPrimaryElectronMCLabels::iterator; + +namespace emprimarymuonmclabel +{ +DECLARE_SOA_INDEX_COLUMN(EMMCParticle, emmcparticle); //! +DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); +} // namespace emprimarymuonmclabel + +// NOTE: MC labels. This table has one entry for each reconstructed track (joinable with EMPrimaryMuons table) +DECLARE_SOA_TABLE(EMPrimaryMuonMCLabels, "AOD", "EMPRMMUMCLABEL", //! + emprimarymuonmclabel::EMMCParticleId, emprimarymuonmclabel::McMask); +using EMPrimaryMuonMCLabel = EMPrimaryMuonMCLabels::iterator; + +namespace emprimaryelectron +{ +DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! +DECLARE_SOA_COLUMN(CollisionId, collisionId, int); //! +DECLARE_SOA_COLUMN(TrackId, trackId, int); //! +DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(AmbiguousElectrons, ambiguousElectrons); +DECLARE_SOA_COLUMN(IsAssociatedToMPC, isAssociatedToMPC, bool); //! is associated to most probable collision +DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! +DECLARE_SOA_COLUMN(PrefilterBit, pfb, uint8_t); //! +DECLARE_SOA_COLUMN(PrefilterBitDerived, pfbderived, uint16_t); //! +DECLARE_SOA_COLUMN(ITSNSigmaEl, itsNSigmaEl, float); //! +DECLARE_SOA_COLUMN(ITSNSigmaMu, itsNSigmaMu, float); //! +DECLARE_SOA_COLUMN(ITSNSigmaPi, itsNSigmaPi, float); //! +DECLARE_SOA_COLUMN(ITSNSigmaKa, itsNSigmaKa, float); //! +DECLARE_SOA_COLUMN(ITSNSigmaPr, itsNSigmaPr, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(Signed1Pt, signed1Pt, [](float pt, int8_t sign) -> float { return sign * 1. / pt; }); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float pt, float eta) -> float { return pt * std::cosh(eta); }); +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) -> float { return pt * std::cos(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float pt, float phi) -> float { return pt * std::sin(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float pt, float eta) -> float { return pt * std::sinh(eta); }); +DECLARE_SOA_DYNAMIC_COLUMN(Theta, theta, [](float tgl) -> float { return M_PI_2 - std::atan(tgl); }); +DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITS, meanClusterSizeITS, [](uint32_t itsClusterSizes) -> float { + int total_cluster_size = 0, nl = 0; + for (unsigned int layer = 0; layer < 7; layer++) { + int cluster_size_per_layer = (itsClusterSizes >> (layer * 4)) & 0xf; + if (cluster_size_per_layer > 0) { + nl++; + } + total_cluster_size += cluster_size_per_layer; + } + if (nl > 0) { + return static_cast(total_cluster_size) / static_cast(nl); + } else { + return 0; + } +}); +DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITSib, meanClusterSizeITSib, [](uint32_t itsClusterSizes) -> float { + int total_cluster_size = 0, nl = 0; + for (unsigned int layer = 0; layer < 3; layer++) { + int cluster_size_per_layer = (itsClusterSizes >> (layer * 4)) & 0xf; + if (cluster_size_per_layer > 0) { + nl++; + } + total_cluster_size += cluster_size_per_layer; + } + if (nl > 0) { + return static_cast(total_cluster_size) / static_cast(nl); + } else { + return 0; + } +}); +DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITSob, meanClusterSizeITSob, [](uint32_t itsClusterSizes) -> float { + int total_cluster_size = 0, nl = 0; + for (unsigned int layer = 3; layer < 7; layer++) { + int cluster_size_per_layer = (itsClusterSizes >> (layer * 4)) & 0xf; + if (cluster_size_per_layer > 0) { + nl++; + } + total_cluster_size += cluster_size_per_layer; + } + if (nl > 0) { + return static_cast(total_cluster_size) / static_cast(nl); + } else { + return 0; + } +}); +} // namespace emprimaryelectron + +DECLARE_SOA_TABLE_VERSIONED(EMPrimaryElectrons_001, "AOD", "EMPRIMARYEL", 1, //! + o2::soa::Index<>, emprimaryelectron::CollisionId, + emprimaryelectron::TrackId, emprimaryelectron::Sign, + track::Pt, track::Eta, track::Phi, track::DcaXY, track::DcaZ, + track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusCrossedRows, track::TPCNClsShared, + track::TPCChi2NCl, track::TPCInnerParam, + track::TPCSignal, pidtpc::TPCNSigmaEl, pidtpc::TPCNSigmaMu, pidtpc::TPCNSigmaPi, pidtpc::TPCNSigmaKa, pidtpc::TPCNSigmaPr, + pidtofbeta::Beta, pidtof::TOFNSigmaEl, pidtof::TOFNSigmaMu, pidtof::TOFNSigmaPi, pidtof::TOFNSigmaKa, pidtof::TOFNSigmaPr, + track::ITSClusterSizes, track::ITSChi2NCl, track::TOFChi2, track::DetectorMap, + track::X, track::Alpha, track::Y, track::Z, track::Snp, track::Tgl, emprimaryelectron::IsAssociatedToMPC, + + // dynamic column + track::TPCNClsFound, + track::TPCNClsCrossedRows, + track::TPCCrossedRowsOverFindableCls, + track::TPCFoundOverFindableCls, + track::TPCFractionSharedCls, + track::v001::ITSClusterMap, track::v001::ITSNCls, track::v001::ITSNClsInnerBarrel, + track::HasITS, track::HasTPC, track::HasTRD, track::HasTOF, + emprimaryelectron::Signed1Pt, + emprimaryelectron::P, + emprimaryelectron::Px, + emprimaryelectron::Py, + emprimaryelectron::Pz, + emprimaryelectron::Theta, + emprimaryelectron::MeanClusterSizeITS, + emprimaryelectron::MeanClusterSizeITSib, + emprimaryelectron::MeanClusterSizeITSob); + +DECLARE_SOA_TABLE_VERSIONED(EMPrimaryElectrons_002, "AOD", "EMPRIMARYEL", 2, //! + o2::soa::Index<>, emprimaryelectron::CollisionId, + emprimaryelectron::TrackId, emprimaryelectron::Sign, + track::Pt, track::Eta, track::Phi, track::DcaXY, track::DcaZ, + track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusCrossedRows, track::TPCNClsShared, + track::TPCChi2NCl, track::TPCInnerParam, + track::TPCSignal, pidtpc::TPCNSigmaEl, pidtpc::TPCNSigmaMu, pidtpc::TPCNSigmaPi, pidtpc::TPCNSigmaKa, pidtpc::TPCNSigmaPr, + pidtofbeta::Beta, pidtof::TOFNSigmaEl, pidtof::TOFNSigmaMu, pidtof::TOFNSigmaPi, pidtof::TOFNSigmaKa, pidtof::TOFNSigmaPr, + track::ITSClusterSizes, emprimaryelectron::ITSNSigmaEl, emprimaryelectron::ITSNSigmaMu, emprimaryelectron::ITSNSigmaPi, emprimaryelectron::ITSNSigmaKa, emprimaryelectron::ITSNSigmaPr, + track::ITSChi2NCl, track::TOFChi2, track::DetectorMap, + track::X, track::Alpha, track::Y, track::Z, track::Snp, track::Tgl, emprimaryelectron::IsAssociatedToMPC, + + // dynamic column + track::TPCNClsFound, + track::TPCNClsCrossedRows, + track::TPCCrossedRowsOverFindableCls, + track::TPCFoundOverFindableCls, + track::TPCFractionSharedCls, + track::v001::ITSClusterMap, track::v001::ITSNCls, track::v001::ITSNClsInnerBarrel, + track::HasITS, track::HasTPC, track::HasTRD, track::HasTOF, + emprimaryelectron::Signed1Pt, + emprimaryelectron::P, + emprimaryelectron::Px, + emprimaryelectron::Py, + emprimaryelectron::Pz, + emprimaryelectron::Theta, + emprimaryelectron::MeanClusterSizeITS, + emprimaryelectron::MeanClusterSizeITSib, + emprimaryelectron::MeanClusterSizeITSob); + +using EMPrimaryElectrons = EMPrimaryElectrons_002; +// iterators +using EMPrimaryElectron = EMPrimaryElectrons::iterator; + +DECLARE_SOA_TABLE(EMPrimaryElectronsCov, "AOD", "EMPRIMARYELCOV", //! + aod::track::CYY, + aod::track::CZY, + aod::track::CZZ, + aod::track::CSnpY, + aod::track::CSnpZ, + aod::track::CSnpSnp, + aod::track::CTglY, + aod::track::CTglZ, + aod::track::CTglSnp, + aod::track::CTglTgl, + aod::track::C1PtY, + aod::track::C1PtZ, + aod::track::C1PtSnp, + aod::track::C1PtTgl, + aod::track::C1Pt21Pt2, o2::soa::Marker<1>); +// iterators +using EMPrimaryElectronCov = EMPrimaryElectronsCov::iterator; + +DECLARE_SOA_TABLE(EMPrimaryElectronEMEventIds, "AOD", "PRMELMEVENTID", emprimaryelectron::EMEventId); // To be joined with EMPrimaryElectrons table at analysis level. +// iterators +using EMPrimaryElectronEMEventId = EMPrimaryElectronEMEventIds::iterator; + +DECLARE_SOA_TABLE(EMPrimaryElectronsPrefilterBit, "AOD", "PRMELPFB", emprimaryelectron::PrefilterBit); // To be joined with EMPrimaryElectrons table at analysis level. +// iterators +using EMPrimaryElectronPrefilterBit = EMPrimaryElectronsPrefilterBit::iterator; + +DECLARE_SOA_TABLE(EMAmbiguousElectronSelfIds, "AOD", "EMAMBELSELFID", emprimaryelectron::AmbiguousElectronsIds); // To be joined with EMPrimaryElectrons table at analysis level. +// iterators +using EMAmbiguousElectronSelfId = EMAmbiguousElectronSelfIds::iterator; + +DECLARE_SOA_TABLE(EMPrimaryElectronsPrefilterBitDerived, "AOD", "PRMELPFBPI0", emprimaryelectron::PrefilterBitDerived); // To be joined with EMPrimaryElectrons table at analysis level. +// iterators +using EMPrimaryElectronPrefilterBitDerived = EMPrimaryElectronsPrefilterBitDerived::iterator; + +namespace emprimarymuon +{ +DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! +DECLARE_SOA_COLUMN(CollisionId, collisionId, int); //! +DECLARE_SOA_COLUMN(FwdTrackId, fwdtrackId, int); //! +DECLARE_SOA_COLUMN(MFTTrackId, mfttrackId, int); //! +DECLARE_SOA_COLUMN(MCHTrackId, mchtrackId, int); //! +DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(GlobalMuonsWithSameMFT, globalMuonsWithSameMFT); //! self indices to global muons that have the same MFTTrackId +DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(AmbiguousMuons, ambiguousMuons); +DECLARE_SOA_COLUMN(CXXatDCA, cXXatDCA, float); //! DCAx resolution squared at DCA +DECLARE_SOA_COLUMN(CYYatDCA, cYYatDCA, float); //! DCAy resolution squared at DCA +DECLARE_SOA_COLUMN(CXYatDCA, cXYatDCA, float); //! correlation term of DCAx,y resolution at DCA +DECLARE_SOA_COLUMN(EtaMatchedMCHMID, etaMatchedMCHMID, float); //! eta of MCH-MID track in MFT-MCH-MID track at PV +DECLARE_SOA_COLUMN(PhiMatchedMCHMID, phiMatchedMCHMID, float); //! phi of MCH-MID track in MFT-MCH-MID track at PV +DECLARE_SOA_COLUMN(IsAssociatedToMPC, isAssociatedToMPC, bool); //! is associated to most probable collision +DECLARE_SOA_COLUMN(IsAmbiguous, isAmbiguous, bool); //! is ambiguous +DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! +DECLARE_SOA_COLUMN(Chi2MFT, chi2MFT, float); //! chi2 of MFT standalone track +DECLARE_SOA_DYNAMIC_COLUMN(Signed1Pt, signed1Pt, [](float pt, int8_t sign) -> float { return sign * 1. / pt; }); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float pt, float eta) -> float { return pt * std::cosh(eta); }); +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) -> float { return pt * std::cos(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float pt, float phi) -> float { return pt * std::sin(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float pt, float eta) -> float { return pt * std::sinh(eta); }); +DECLARE_SOA_DYNAMIC_COLUMN(NClustersMFT, nClustersMFT, //! Number of MFT clusters + [](uint64_t mftClusterSizesAndTrackFlags) -> uint8_t { + uint8_t nClusters = 0; + for (int layer = 0; layer < 10; layer++) { + if ((mftClusterSizesAndTrackFlags >> (layer * 6)) & 0x3F) { + nClusters++; + } + } + return nClusters; + }); +DECLARE_SOA_DYNAMIC_COLUMN(MFTClusterMap, mftClusterMap, //! MFT cluster map, one bit per a layer, starting from the innermost + [](uint64_t mftClusterSizesAndTrackFlags) -> uint16_t { + uint16_t clmap = 0; + for (unsigned int layer = 0; layer < 10; layer++) { + if ((mftClusterSizesAndTrackFlags >> (layer * 6)) & 0x3f) { + clmap |= (1 << layer); + } + } + return clmap; + }); +} // namespace emprimarymuon +DECLARE_SOA_TABLE(EMPrimaryMuons, "AOD", "EMPRIMARYMU", //! + o2::soa::Index<>, emprimarymuon::CollisionId, + emprimarymuon::FwdTrackId, emprimarymuon::MFTTrackId, emprimarymuon::MCHTrackId, fwdtrack::TrackType, + fwdtrack::Pt, fwdtrack::Eta, fwdtrack::Phi, emprimarymuon::Sign, + fwdtrack::FwdDcaX, fwdtrack::FwdDcaY, emprimarymuon::CXXatDCA, emprimarymuon::CYYatDCA, emprimarymuon::CXYatDCA, + emprimarymuon::EtaMatchedMCHMID, emprimarymuon::PhiMatchedMCHMID, + // fwdtrack::X, fwdtrack::Y, fwdtrack::Z, fwdtrack::Tgl, + + fwdtrack::NClusters, fwdtrack::PDca, fwdtrack::RAtAbsorberEnd, + fwdtrack::Chi2, fwdtrack::Chi2MatchMCHMID, fwdtrack::Chi2MatchMCHMFT, + fwdtrack::MCHBitMap, fwdtrack::MIDBitMap, fwdtrack::MIDBoards, + fwdtrack::MFTClusterSizesAndTrackFlags, emprimarymuon::Chi2MFT, emprimarymuon::IsAssociatedToMPC, emprimarymuon::IsAmbiguous, + + // dynamic column + emprimarymuon::Signed1Pt, + emprimarymuon::NClustersMFT, + emprimarymuon::MFTClusterMap, + emprimarymuon::P, + emprimarymuon::Px, + emprimarymuon::Py, + emprimarymuon::Pz); +// iterators +using EMPrimaryMuon = EMPrimaryMuons::iterator; + +DECLARE_SOA_TABLE(EMPrimaryMuonsCov, "AOD", "EMPRIMARYMUCOV", //! + aod::fwdtrack::CXX, + aod::fwdtrack::CXY, + aod::fwdtrack::CYY, + aod::fwdtrack::CPhiX, + aod::fwdtrack::CPhiY, + aod::fwdtrack::CPhiPhi, + aod::fwdtrack::CTglX, + aod::fwdtrack::CTglY, + aod::fwdtrack::CTglPhi, + aod::fwdtrack::CTglTgl, + aod::fwdtrack::C1PtX, + aod::fwdtrack::C1PtY, + aod::fwdtrack::C1PtPhi, + aod::fwdtrack::C1PtTgl, + aod::fwdtrack::C1Pt21Pt2); +// iterators +using EMPrimaryMuonCov = EMPrimaryMuonsCov::iterator; + +DECLARE_SOA_TABLE(EMPrimaryMuonEMEventIds, "AOD", "PRMMUEMEVENTID", emprimarymuon::EMEventId); // To be joined with EMPrimaryMuons table at analysis level. +// iterators +using EMPrimaryMuonEMEventId = EMPrimaryMuonEMEventIds::iterator; + +DECLARE_SOA_TABLE(EMAmbiguousMuonSelfIds, "AOD", "EMAMBMUSELFID", emprimarymuon::AmbiguousMuonsIds); // To be joined with EMPrimaryMuons table at analysis level. +// iterators +using EMAmbiguousMuonSelfId = EMAmbiguousMuonSelfIds::iterator; + +DECLARE_SOA_TABLE(EMGlobalMuonSelfIds, "AOD", "EMGLMUSELFID", emprimarymuon::GlobalMuonsWithSameMFTIds); // To be joined with EMPrimaryMuons table at analysis level. +// iterators +using EMGlobalMuonSelfId = EMGlobalMuonSelfIds::iterator; + +} // namespace o2::aod + +#endif // PWGEM_DILEPTON_DATAMODEL_DILEPTONTABLES_H_ diff --git a/PWGEM/Dilepton/DataModel/lmeeMLTables.h b/PWGEM/Dilepton/DataModel/lmeeMLTables.h index a42eba65846..9ab6ed32781 100644 --- a/PWGEM/Dilepton/DataModel/lmeeMLTables.h +++ b/PWGEM/Dilepton/DataModel/lmeeMLTables.h @@ -16,7 +16,6 @@ #include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Centrality.h" -#include #ifndef PWGEM_DILEPTON_DATAMODEL_LMEEMLTABLES_H_ #define PWGEM_DILEPTON_DATAMODEL_LMEEMLTABLES_H_ @@ -33,7 +32,7 @@ enum class PID_Label : int { kPion = 2, kKaon = 3, kProton = 4, -}; // this can be used for eID with ITSsa. +}; // this can be used for eID. enum class Track_Type : int { kPrimary = 0, @@ -76,7 +75,7 @@ DECLARE_SOA_TABLE(EMPrimaryTracks, "AOD", "EMPTRACK", //! track::TPCChi2NCl, track::TPCInnerParam, track::TPCSignal, pidtpc::TPCNSigmaEl, pidtpc::TPCNSigmaMu, pidtpc::TPCNSigmaPi, pidtpc::TPCNSigmaKa, pidtpc::TPCNSigmaPr, pidtofbeta::Beta, pidtof::TOFNSigmaEl, pidtof::TOFNSigmaMu, pidtof::TOFNSigmaPi, pidtof::TOFNSigmaKa, pidtof::TOFNSigmaPr, - track::ITSClusterSizes, track::ITSChi2NCl, track::DetectorMap, emprimarytrack::PIDLabel, emprimarytrack::TrackType, + track::ITSClusterSizes, track::ITSChi2NCl, track::TOFChi2, track::DetectorMap, emprimarytrack::PIDLabel, emprimarytrack::TrackType, // dynamic column emprimarytrack::P, diff --git a/PWGEM/Dilepton/TableProducer/CMakeLists.txt b/PWGEM/Dilepton/TableProducer/CMakeLists.txt index e0d34b1f584..c95928b3eb1 100644 --- a/PWGEM/Dilepton/TableProducer/CMakeLists.txt +++ b/PWGEM/Dilepton/TableProducer/CMakeLists.txt @@ -12,16 +12,56 @@ o2physics_add_dpl_workflow(tree-creator-electron-ml SOURCES treeCreatorElectronML.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(tree-creator-electron-ml-dda SOURCES treeCreatorElectronMLDDA.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(dielectron-ml - SOURCES dielectronMl.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore +o2physics_add_dpl_workflow(skimmer-primary-electron + SOURCES skimmerPrimaryElectron.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(skimmer-primary-muon + SOURCES skimmerPrimaryMuon.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::GlobalTracking + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(skimmer-secondary-electron + SOURCES skimmerSecondaryElectron.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(create-emevent-dilepton + SOURCES createEMEventDilepton.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(skimmer-ots + SOURCES skimmerOTS.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(associate-mc-info-dilepton + SOURCES associateMCinfoDilepton.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(filter-dielectron-event + SOURCES filterDielectronEvent.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(event-selection + SOURCES eventSelection.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(filter-eoi + SOURCES filterEoI.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) diff --git a/PWGEM/Dilepton/TableProducer/associateMCinfoDilepton.cxx b/PWGEM/Dilepton/TableProducer/associateMCinfoDilepton.cxx new file mode 100644 index 00000000000..fcccd1cf9c0 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/associateMCinfoDilepton.cxx @@ -0,0 +1,660 @@ +// 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. +// +// ======================== +// +// This code produces reduced events for photon analyses. +// Please write to: daiki.sekihata@cern.ch + +#include +#include +#include + +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/TableHelper.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +using MyCollisionsMC = soa::Join; +using TracksMC = soa::Join; +using FwdTracksMC = soa::Join; + +struct AssociateMCInfoDilepton { + enum SubSystem { + kElectron = 0x1, + kFwdMuon = 0x2, + kPCM = 0x4, + }; + + Produces mcevents; + Produces mceventlabels; + Produces emmcparticles; + Produces emmcgenvms; + Produces v0legmclabels; + Produces emprimaryelectronmclabels; + Produces emprimarymuonmclabels; + + Configurable down_scaling_omega{"down_scaling_omega", 1.1, "down scaling factor to store omega"}; + Configurable down_scaling_phi{"down_scaling_phi", 1.1, "down scaling factor to store phi"}; + Configurable min_eta_gen_primary{"min_eta_gen_primary", -1.5, "min rapidity Y to store generated information"}; // smearing is applied at analysis stage. set wider value. + Configurable max_eta_gen_primary{"max_eta_gen_primary", +1.5, "max rapidity Y to store generated information"}; // smearing is applied at analysis stage. set wider value. + Configurable min_eta_gen_primary_fwd{"min_eta_gen_primary_fwd", -5.0, "min eta to store generated information"}; // smearing is applied at analysis stage. set wider value. + Configurable max_eta_gen_primary_fwd{"max_eta_gen_primary_fwd", -1.5, "max eta to store generated information"}; // smearing is applied at analysis stage. set wider value. + + HistogramRegistry registry{"EMMCEvent"}; + std::mt19937 engine; + std::uniform_real_distribution dist01; + + void init(o2::framework::InitContext&) + { + auto hEventCounter = registry.add("hEventCounter", "hEventCounter", kTH1I, {{6, 0.5f, 6.5f}}); + hEventCounter->GetXaxis()->SetBinLabel(1, "all"); + hEventCounter->GetXaxis()->SetBinLabel(2, "has mc collision"); + + std::random_device seed_gen; + engine = std::mt19937(seed_gen()); + dist01 = std::uniform_real_distribution(0.0f, 1.0f); + } + + template + bool isDecayDielectronInAcceptance(TMCParticle const& mctrack, TMCParticles const& mcTracks) + { + if (!mctrack.has_daughters()) { + return false; + } + + bool is_lepton = false, is_anti_lepton = false; + for (int d = mctrack.daughtersIds()[0]; d <= mctrack.daughtersIds()[1]; ++d) { + auto daughter = mcTracks.iteratorAt(d); + if (daughter.pdgCode() == 11 && (min_eta_gen_primary < daughter.eta() && daughter.eta() < max_eta_gen_primary)) { + is_lepton = true; + } + if (daughter.pdgCode() == -11 && (min_eta_gen_primary < daughter.eta() && daughter.eta() < max_eta_gen_primary)) { + is_anti_lepton = true; + } + } + if (is_lepton && is_anti_lepton) { + return true; + } else { + return false; + } + } + + template + bool isDecayDimuonInAcceptance(TMCParticle const& mctrack, TMCParticles const& mcTracks) + { + if (!mctrack.has_daughters()) { + return false; + } + + bool is_lepton = false, is_anti_lepton = false; + for (int d = mctrack.daughtersIds()[0]; d <= mctrack.daughtersIds()[1]; ++d) { + auto daughter = mcTracks.iteratorAt(d); + if (daughter.pdgCode() == 13 && (min_eta_gen_primary_fwd < daughter.eta() && daughter.eta() < max_eta_gen_primary_fwd)) { + is_lepton = true; + } + if (daughter.pdgCode() == -13 && (min_eta_gen_primary_fwd < daughter.eta() && daughter.eta() < max_eta_gen_primary_fwd)) { + is_anti_lepton = true; + } + } + if (is_lepton && is_anti_lepton) { + return true; + } else { + return false; + } + } + + SliceCache cache; + Preslice perMcCollision = aod::mcparticle::mcCollisionId; + Preslice perCollision_pcm = aod::v0photonkf::collisionId; + Preslice perCollision_el = aod::emprimaryelectron::collisionId; + Preslice perCollision_mu = aod::emprimarymuon::collisionId; + + // apply rapidity cut for electrons + Partition mcelectrons = nabs(o2::aod::mcparticle::pdgCode) == 11 && min_eta_gen_primary < o2::aod::mcparticle::eta && o2::aod::mcparticle::eta < max_eta_gen_primary; + Partition mcmuons = nabs(o2::aod::mcparticle::pdgCode) == 13 && min_eta_gen_primary_fwd < o2::aod::mcparticle::eta && o2::aod::mcparticle::eta < max_eta_gen_primary_fwd; + Partition mcvectormesons = o2::aod::mcparticle::pdgCode == 223 || o2::aod::mcparticle::pdgCode == 333; + + template + void skimmingMC(MyCollisionsMC const& collisions, aod::BCs const&, aod::McCollisions const& mcCollisions, aod::McParticles const& mcTracks, TTracks const& o2tracks, TFwdTracks const& o2fwdtracks, TPCMs const& v0photons, TPCMLegs const& /*v0legs*/, TEMPrimaryElectrons const& emprimaryelectrons, TEMPrimaryMuons const& emprimarymuons) + { + // temporary variables used for the indexing of the skimmed MC stack + std::map fNewLabels; + std::map fNewLabelsReversed; + // std::map fMCFlags; + std::map fEventIdx; + std::map fEventLabels; + int fCounters[2] = {0, 0}; //! [0] - particle counter, [1] - event counter + + // first, run loop over mc collisions to create map between aod::McCollisions and aod::EMMCEvents + for (const auto& mcCollision : mcCollisions) { + // make an entry for this MC event only if it was not already added to the table + if (!(fEventLabels.find(mcCollision.globalIndex()) != fEventLabels.end())) { + mcevents(mcCollision.globalIndex(), mcCollision.generatorsID(), mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.impactParameter(), mcCollision.eventPlaneAngle()); + fEventLabels[mcCollision.globalIndex()] = fCounters[1]; + fCounters[1]++; + } + } // end of mc collision loop + + for (const auto& collision : collisions) { + registry.fill(HIST("hEventCounter"), 1); + + // TODO: investigate the collisions without corresponding mcCollision + if (!collision.has_mcCollision()) { + continue; + } + + if (!collision.isSelected()) { + continue; + } + + registry.fill(HIST("hEventCounter"), 2); + auto mcCollision = collision.mcCollision(); + mceventlabels(fEventLabels.find(mcCollision.globalIndex())->second, collision.mcMask()); + + } // end of reconstructed collision loop + + for (const auto& mcCollision : mcCollisions) { + // store MC true information + auto mcelectrons_per_mccollision = mcelectrons.sliceBy(perMcCollision, mcCollision.globalIndex()); + auto mcmuons_per_mccollision = mcmuons.sliceBy(perMcCollision, mcCollision.globalIndex()); + auto mcvectormesons_per_mccollision = mcvectormesons.sliceBy(perMcCollision, mcCollision.globalIndex()); + + for (const auto& mctrack : mcelectrons_per_mccollision) { // store necessary information for denominator of efficiency + if (!mctrack.isPhysicalPrimary() && !mctrack.producedByGenerator()) { + continue; + } + // auto mcCollision = mcCollisions.iteratorAt(mctrack.mcCollisionId()); + + // only for temporary protection, as of 15.July.2024 (by Daiki Sekihata) + int motherid_tmp = -999; // first mother index tmp + if (mctrack.has_mothers()) { + motherid_tmp = mctrack.mothersIds()[0]; // first mother index + } + auto mp_tmp = mcTracks.iteratorAt(motherid_tmp); + int ndau_tmp = mp_tmp.daughtersIds()[1] - mp_tmp.daughtersIds()[0] + 1; + if (ndau_tmp < 10) { + + if (!(fNewLabels.find(mctrack.globalIndex()) != fNewLabels.end())) { + fNewLabels[mctrack.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); + // fMCFlags[mctrack.globalIndex()] = mcflags; + fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; + fCounters[0]++; + } + + int motherid = -999; // first mother index + if (mctrack.has_mothers()) { + motherid = mctrack.mothersIds()[0]; // first mother index + } + while (motherid > -1) { + if (motherid < mcTracks.size()) { // protect against bad mother indices. why is this needed? + auto mp = mcTracks.iteratorAt(motherid); + + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mp.globalIndex()) != fNewLabels.end())) { + fNewLabels[mp.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); + // fMCFlags[mp.globalIndex()] = mcflags; + fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; + fCounters[0]++; + } + + if (mp.has_mothers()) { + motherid = mp.mothersIds()[0]; // first mother index + } else { + motherid = -999; + } + } else { + motherid = -999; + } + } // end of mother chain loop + } // end of ndau protection + } // end of mc electron loop + + for (const auto& mctrack : mcmuons_per_mccollision) { // store necessary information for denominator of efficiency + if (!mctrack.isPhysicalPrimary() && !mctrack.producedByGenerator()) { + continue; + } + // auto mcCollision = mcCollisions.iteratorAt(mctrack.mcCollisionId()); + + // only for temporary protection, as of 15.July.2024 (by Daiki Sekihata) + int motherid_tmp = -999; // first mother index tmp + if (mctrack.has_mothers()) { + motherid_tmp = mctrack.mothersIds()[0]; // first mother index + } + auto mp_tmp = mcTracks.iteratorAt(motherid_tmp); + int ndau_tmp = mp_tmp.daughtersIds()[1] - mp_tmp.daughtersIds()[0] + 1; + if (ndau_tmp < 10) { + + if (!(fNewLabels.find(mctrack.globalIndex()) != fNewLabels.end())) { + fNewLabels[mctrack.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); + // fMCFlags[mctrack.globalIndex()] = mcflags; + fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; + fCounters[0]++; + } + + int motherid = -999; // first mother index + if (mctrack.has_mothers()) { + motherid = mctrack.mothersIds()[0]; // first mother index + } + while (motherid > -1) { + if (motherid < mcTracks.size()) { // protect against bad mother indices. why is this needed? + auto mp = mcTracks.iteratorAt(motherid); + + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mp.globalIndex()) != fNewLabels.end())) { + fNewLabels[mp.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); + // fMCFlags[mp.globalIndex()] = mcflags; + fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; + fCounters[0]++; + } + + if (mp.has_mothers()) { + motherid = mp.mothersIds()[0]; // first mother index + } else { + motherid = -999; + } + } else { + motherid = -999; + } + } // end of mother chain loop + } // end of ndau protection + } // end of mc muon loop + + for (const auto& mctrack : mcvectormesons_per_mccollision) { // store necessary information for denominator of efficiency + // Be careful!! dilepton rapidity is different from meson rapidity! No acceptance cut here. + + if (!mctrack.isPhysicalPrimary() && !mctrack.producedByGenerator()) { + continue; + } + + if (!isDecayDielectronInAcceptance(mctrack, mcTracks) && !isDecayDimuonInAcceptance(mctrack, mcTracks)) { // acceptance cut to decay dileptons + continue; + } + + // auto mcCollision = mcCollisions.iteratorAt(mctrack.mcCollisionId()); + + int ndau = mctrack.daughtersIds()[1] - mctrack.daughtersIds()[0] + 1; + if (ndau < 10) { + + if (!(fNewLabels.find(mctrack.globalIndex()) != fNewLabels.end())) { + fNewLabels[mctrack.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); + // fMCFlags[mctrack.globalIndex()] = mcflags; + fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; + fCounters[0]++; + } + + // store daughter of vector mesons + if (mctrack.has_daughters()) { + bool is_lepton_involved = false; + for (int d = mctrack.daughtersIds()[0]; d <= mctrack.daughtersIds()[1]; ++d) { + // TODO: remove this check as soon as issues with MC production are fixed + if (d < mcTracks.size()) { // protect against bad daughter indices + auto daughter = mcTracks.iteratorAt(d); + if (std::abs(daughter.pdgCode()) == 11 || std::abs(daughter.pdgCode()) == 13) { + is_lepton_involved = true; + break; + } + } else { + std::cout << "Daughter label (" << d << ") exceeds the McParticles size (" << mcTracks.size() << ")" << std::endl; + std::cout << " Check the MC generator" << std::endl; + } + } + + if (is_lepton_involved) { + // LOGF(info, "daughter range in original MC stack pdg = %d | %d - %d , n dau = %d", mctrack.pdgCode(), mctrack.daughtersIds()[0], mctrack.daughtersIds()[1], mctrack.daughtersIds()[1] -mctrack.daughtersIds()[0] +1); + for (int d = mctrack.daughtersIds()[0]; d <= mctrack.daughtersIds()[1]; ++d) { + // TODO: remove this check as soon as issues with MC production are fixed + if (d < mcTracks.size()) { // protect against bad daughter indices + auto daughter = mcTracks.iteratorAt(d); + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(daughter.globalIndex()) != fNewLabels.end())) { + fNewLabels[daughter.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = daughter.globalIndex(); + // fMCFlags[daughter.globalIndex()] = mcflags; + fEventIdx[daughter.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; + fCounters[0]++; + } + } else { + std::cout << "Daughter label (" << d << ") exceeds the McParticles size (" << mcTracks.size() << ")" << std::endl; + std::cout << " Check the MC generator" << std::endl; + } + } // end of daughter loop + } + } + } // end of ndau protection + } // end of generated vector mesons loop + + } // end of mc collision loop + + if constexpr (static_cast(system & kPCM)) { + for (const auto& v0 : v0photons) { + auto collision_from_v0 = collisions.iteratorAt(v0.collisionId()); + if (!collision_from_v0.has_mcCollision()) { + continue; + } + + auto ele = v0.template negTrack_as(); + auto pos = v0.template posTrack_as(); + + auto o2track_ele = o2tracks.iteratorAt(ele.trackId()); + auto o2track_pos = o2tracks.iteratorAt(pos.trackId()); + + if (!o2track_ele.has_mcParticle() || !o2track_pos.has_mcParticle()) { + continue; // If no MC particle is found, skip the v0 + } + + for (const auto& leg : {pos, ele}) { // be carefull of order {pos, ele}! + auto o2track = o2tracks.iteratorAt(leg.trackId()); + auto mctrack = o2track.template mcParticle_as(); + // LOGF(info, "mctrack.globalIndex() = %d, mctrack.index() = %d", mctrack.globalIndex(), mctrack.index()); // these are exactly the same. + + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mctrack.globalIndex()) != fNewLabels.end())) { + fNewLabels[mctrack.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); + // fMCFlags[mctrack.globalIndex()] = mcflags; + fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mctrack.mcCollisionId())->second; + fCounters[0]++; + } + v0legmclabels(fNewLabels.find(mctrack.index())->second, o2track.mcMask()); + + // Next, store mother-chain of this reconstructed track. + int motherid = -999; // first mother index + if (mctrack.has_mothers()) { + motherid = mctrack.mothersIds()[0]; // first mother index + } + while (motherid > -1) { + if (motherid < mcTracks.size()) { // protect against bad mother indices. why is this needed? + auto mp = mcTracks.iteratorAt(motherid); + + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mp.globalIndex()) != fNewLabels.end())) { + fNewLabels[mp.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); + // fMCFlags[mp.globalIndex()] = mcflags; + fEventIdx[mp.globalIndex()] = fEventLabels.find(mp.mcCollisionId())->second; + fCounters[0]++; + } + + if (mp.has_mothers()) { + motherid = mp.mothersIds()[0]; // first mother index + } else { + motherid = -999; + } + } else { + motherid = -999; + } + } // end of mother chain loop + } // end of leg loop + } // end of v0 loop + } + + if constexpr (static_cast(system & kElectron)) { + // auto emprimaryelectrons_coll = emprimaryelectrons.sliceBy(perCollision_el, collision.globalIndex()); + for (const auto& emprimaryelectron : emprimaryelectrons) { + auto collision_from_el = collisions.iteratorAt(emprimaryelectron.collisionId()); + if (!collision_from_el.has_mcCollision()) { + continue; + } + + auto o2track = o2tracks.iteratorAt(emprimaryelectron.trackId()); + if (!o2track.has_mcParticle()) { + continue; // If no MC particle is found, skip the dilepton + } + auto mctrack = o2track.template mcParticle_as(); + + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mctrack.globalIndex()) != fNewLabels.end())) { + fNewLabels[mctrack.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); + // fMCFlags[mctrack.globalIndex()] = mcflags; + fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mctrack.mcCollisionId())->second; + fCounters[0]++; + } + emprimaryelectronmclabels(fNewLabels.find(mctrack.index())->second, o2track.mcMask()); + + // Next, store mother-chain of this reconstructed track. + int motherid = -999; // first mother index + if (mctrack.has_mothers()) { + motherid = mctrack.mothersIds()[0]; // first mother index + } + while (motherid > -1) { + if (motherid < mcTracks.size()) { // protect against bad mother indices. why is this needed? + auto mp = mcTracks.iteratorAt(motherid); + + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mp.globalIndex()) != fNewLabels.end())) { + fNewLabels[mp.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); + // fMCFlags[mp.globalIndex()] = mcflags; + fEventIdx[mp.globalIndex()] = fEventLabels.find(mp.mcCollisionId())->second; + fCounters[0]++; + } + + if (mp.has_mothers()) { + motherid = mp.mothersIds()[0]; // first mother index + } else { + motherid = -999; + } + } else { + motherid = -999; + } + } // end of mother chain loop + + } // end of em primary electron loop + } + + if constexpr (static_cast(system & kFwdMuon)) { + // auto emprimarymuons_coll = emprimarymuons.sliceBy(perCollision_mu, collision.globalIndex()); + for (const auto& emprimarymuon : emprimarymuons) { + auto collision_from_mu = collisions.iteratorAt(emprimarymuon.collisionId()); + if (!collision_from_mu.has_mcCollision()) { + continue; + } + + auto o2track = o2fwdtracks.iteratorAt(emprimarymuon.fwdtrackId()); + if (!o2track.has_mcParticle()) { + continue; // If no MC particle is found, skip the dilepton + } + auto mctrack = o2track.template mcParticle_as(); + + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mctrack.globalIndex()) != fNewLabels.end())) { + fNewLabels[mctrack.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); + // fMCFlags[mctrack.globalIndex()] = mcflags; + fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mctrack.mcCollisionId())->second; + fCounters[0]++; + } + emprimarymuonmclabels(fNewLabels.find(mctrack.index())->second, o2track.mcMask()); + + // Next, store mother-chain of this reconstructed track. + int motherid = -999; // first mother index + if (mctrack.has_mothers()) { + motherid = mctrack.mothersIds()[0]; // first mother index + } + while (motherid > -1) { + if (motherid < mcTracks.size()) { // protect against bad mother indices. why is this needed? + auto mp = mcTracks.iteratorAt(motherid); + + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mp.globalIndex()) != fNewLabels.end())) { + fNewLabels[mp.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); + // fMCFlags[mp.globalIndex()] = mcflags; + fEventIdx[mp.globalIndex()] = fEventLabels.find(mp.mcCollisionId())->second; + fCounters[0]++; + } + + if (mp.has_mothers()) { + motherid = mp.mothersIds()[0]; // first mother index + } else { + motherid = -999; + } + } else { + motherid = -999; + } + } // end of mother chain loop + + } // end of em primary muon loop + } + + // Loop over the label map, create the mother/daughter relationships if these exist and write the skimmed MC stack + for (const auto& [newLabel, oldLabel] : fNewLabelsReversed) { + auto mctrack = mcTracks.iteratorAt(oldLabel); + // uint16_t mcflags = fMCFlags.find(oldLabel)->second; + + std::vector mothers; + if (mctrack.has_mothers()) { + for (const auto& m : mctrack.mothersIds()) { + if (m < mcTracks.size()) { // protect against bad mother indices + if (fNewLabels.find(m) != fNewLabels.end()) { + mothers.push_back(fNewLabels.find(m)->second); + } + } else { + std::cout << "Mother label (" << m << ") exceeds the McParticles size (" << mcTracks.size() << ")" << std::endl; + std::cout << " Check the MC generator" << std::endl; + } + } + } + + // Note that not all daughters from the original table are preserved in the skimmed MC stack + std::vector daughters; + if (mctrack.has_daughters()) { + // int ndau = mctrack.daughtersIds()[1] - mctrack.daughtersIds()[0] + 1; + // LOGF(info, "daughter range in original MC stack pdg = %d | %d - %d , n dau = %d", mctrack.pdgCode(), mctrack.daughtersIds()[0], mctrack.daughtersIds()[1], mctrack.daughtersIds()[1] -mctrack.daughtersIds()[0] +1); + for (int d = mctrack.daughtersIds()[0]; d <= mctrack.daughtersIds()[1]; ++d) { + // TODO: remove this check as soon as issues with MC production are fixed + if (d < mcTracks.size()) { // protect against bad daughter indices + // auto dau_tmp = mcTracks.iteratorAt(d); + // // LOGF(info, "daughter pdg = %d", dau_tmp.pdgCode()); + // if ((mctrack.pdgCode() == 223 || mctrack.pdgCode() == 333) && (mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { + // if (fNewLabels.find(d) == fNewLabels.end() && (abs(dau_tmp.pdgCode()) == 11 || abs(dau_tmp.pdgCode()) == 13)) { + // LOGF(info, "daughter lepton is not found mctrack.globalIndex() = %d, mctrack.producedByGenerator() == %d, ndau = %d | dau_tmp.globalIndex() = %d, dau_tmp.pdgCode() = %d, dau_tmp.producedByGenerator() = %d, dau_tmp.pt() = %f, dau_tmp.eta() = %f, dau_tmp.phi() = %f", mctrack.globalIndex(), mctrack.producedByGenerator(), ndau, dau_tmp.globalIndex(), dau_tmp.pdgCode(), dau_tmp.producedByGenerator(), dau_tmp.pt(), dau_tmp.eta(), dau_tmp.phi()); + // } + // } + + if (fNewLabels.find(d) != fNewLabels.end()) { + daughters.push_back(fNewLabels.find(d)->second); + } + } else { + std::cout << "Daughter label (" << d << ") exceeds the McParticles size (" << mcTracks.size() << ")" << std::endl; + std::cout << " Check the MC generator" << std::endl; + } + } + } + + emmcparticles(fEventIdx.find(oldLabel)->second, mctrack.pdgCode(), mctrack.flags(), + mothers, daughters, + mctrack.px(), mctrack.py(), mctrack.pz(), mctrack.e(), + mctrack.vx(), mctrack.vy(), mctrack.vz()); + + mothers.clear(); + mothers.shrink_to_fit(); + daughters.clear(); + daughters.shrink_to_fit(); + } // end loop over labels + + // only for omega, phi mesons + for (const auto& mcCollision : mcCollisions) { + auto mcvectormesons_per_mccollision = mcvectormesons.sliceBy(perMcCollision, mcCollision.globalIndex()); + for (const auto& mctrack : mcvectormesons_per_mccollision) { // store necessary information for denominator of efficiency + if (!mctrack.isPhysicalPrimary() && !mctrack.producedByGenerator()) { + continue; + } + + if (mctrack.pdgCode() == 223) { + if (dist01(engine) < down_scaling_omega) { + emmcgenvms(fEventLabels[mcCollision.globalIndex()], mctrack.pdgCode(), mctrack.flags(), mctrack.px(), mctrack.py(), mctrack.pz(), mctrack.e(), down_scaling_omega.value); + } + } else if (mctrack.pdgCode() == 333) { + if (dist01(engine) < down_scaling_phi) { + emmcgenvms(fEventLabels[mcCollision.globalIndex()], mctrack.pdgCode(), mctrack.flags(), mctrack.px(), mctrack.py(), mctrack.pz(), mctrack.e(), down_scaling_phi.value); + } + } + } // end of generated vector meson loop + } // end of reconstructed collision loop + + fNewLabels.clear(); + fNewLabelsReversed.clear(); + // fMCFlags.clear(); + fEventIdx.clear(); + fEventLabels.clear(); + fCounters[0] = 0; + fCounters[1] = 0; + } // end of skimmingMC + + void processMC_Electron(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, aod::EMPrimaryElectrons const& emprimaryelectrons) + { + const uint8_t sysflag = kElectron; + skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, nullptr, nullptr, nullptr, emprimaryelectrons, nullptr); + } + + void processMC_FwdMuon(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, FwdTracksMC const& o2fwdtracks, aod::EMPrimaryMuons const& emprimarymuons) + { + const uint8_t sysflag = kFwdMuon; + skimmingMC(collisions, bcs, mccollisions, mcTracks, nullptr, o2fwdtracks, nullptr, nullptr, nullptr, emprimarymuons); + } + + void processMC_Electron_FwdMuon(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, FwdTracksMC const& o2fwdtracks, aod::EMPrimaryElectrons const& emprimaryelectrons, aod::EMPrimaryMuons const& emprimarymuons) + { + const uint8_t sysflag = kElectron | kFwdMuon; + skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, o2fwdtracks, nullptr, nullptr, emprimaryelectrons, emprimarymuons); + } + + void processMC_Electron_FwdMuon_PCM(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, FwdTracksMC const& o2fwdtracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, aod::EMPrimaryElectrons const& emprimaryelectrons, aod::EMPrimaryMuons const& emprimarymuons) + { + const uint8_t sysflag = kPCM | kElectron | kFwdMuon; + skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, o2fwdtracks, v0photons, v0legs, emprimaryelectrons, emprimarymuons); + } + + void processMC_Electron_PCM(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, aod::EMPrimaryElectrons const& emprimaryelectrons) + { + const uint8_t sysflag = kPCM | kElectron; + skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, nullptr, v0photons, v0legs, emprimaryelectrons, nullptr); + } + + void processMC_PCM(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs) + { + skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, nullptr, v0photons, v0legs, nullptr, nullptr); + } + + void processDummy(MyCollisionsMC const&) {} + + PROCESS_SWITCH(AssociateMCInfoDilepton, processMC_Electron, "create em mc event table for Electron", false); + PROCESS_SWITCH(AssociateMCInfoDilepton, processMC_FwdMuon, "create em mc event table for Forward Muon", false); + PROCESS_SWITCH(AssociateMCInfoDilepton, processMC_Electron_FwdMuon, "create em mc event table for Electron, FwdMuon", false); + PROCESS_SWITCH(AssociateMCInfoDilepton, processMC_Electron_FwdMuon_PCM, "create em mc event table for PCM, Electron, FwdMuon", false); + PROCESS_SWITCH(AssociateMCInfoDilepton, processMC_Electron_PCM, "create em mc event table for PCM, Electron", false); + PROCESS_SWITCH(AssociateMCInfoDilepton, processMC_PCM, "create em mc event table for PCM", false); + PROCESS_SWITCH(AssociateMCInfoDilepton, processDummy, "processDummy", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"associate-mc-info-dilepton"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/createEMEventDilepton.cxx b/PWGEM/Dilepton/TableProducer/createEMEventDilepton.cxx new file mode 100644 index 00000000000..253da4de3a6 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/createEMEventDilepton.cxx @@ -0,0 +1,352 @@ +// 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. +// +// ======================== +// +// This code produces reduced events for photon analyses. +// Please write to: daiki.sekihata@cern.ch + +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" + +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "Common/Core/TableHelper.h" + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +using MyBCs = soa::Join; +using MyQvectors = soa::Join; + +using MyCollisions = soa::Join; +using MyCollisions_Cent = soa::Join; // centrality table has dependency on multiplicity table. +using MyCollisions_Cent_Qvec = soa::Join; + +using MyCollisionsWithSWT = soa::Join; +using MyCollisionsWithSWT_Cent = soa::Join; // centrality table has dependency on multiplicity table. +using MyCollisionsWithSWT_Cent_Qvec = soa::Join; + +using MyCollisionsMC = soa::Join; +using MyCollisionsMC_Cent = soa::Join; // centrality table has dependency on multiplicity table. +using MyCollisionsMC_Cent_Qvec = soa::Join; + +struct CreateEMEventDilepton { + Produces embc; + Produces event; + // Produces eventcov; + Produces event_mult; + Produces event_cent; + Produces event_qvec; + Produces emswtbit; + Produces event_norm_info; + + enum class EMEventType : int { + kEvent = 0, + kEvent_Cent = 1, + kEvent_Cent_Qvec = 2, + }; + + // CCDB options + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; + + HistogramRegistry registry{"registry"}; + void init(o2::framework::InitContext&) + { + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + auto hEventCounter = registry.add("hEventCounter", "hEventCounter", kTH1I, {{7, 0.5f, 7.5f}}); + hEventCounter->GetXaxis()->SetBinLabel(1, "all"); + hEventCounter->GetXaxis()->SetBinLabel(2, "sel8"); + + registry.add("hNInspectedTVX", "N inspected TVX;run number;N_{TVX}", kTProfile, {{80000, 520000.5, 600000.5}}, true); + } + + ~CreateEMEventDilepton() {} + + int mRunNumber; + float d_bz; + Service ccdb; + + template + void initCCDB(TBC const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + mRunNumber = bc.runNumber(); + return; + } + + auto run3grp_timestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = bc.runNumber(); + } + + Preslice perBC = aod::collision::bcId; + // Preslice perCollision_pcm = aod::v0photonkf::collisionId; + // PresliceUnsorted perCollision_el = aod::emprimaryelectron::collisionId; + // PresliceUnsorted perCollision_mu = aod::emprimarymuon::collisionId; + + template + void skimEvent(TCollisions const& collisions, TBCs const& bcs) + { + for (const auto& bc : bcs) { + if (bc.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + // const auto& collisions_perBC = collisions.sliceBy(perBC, bc.globalIndex()); + // embc(bc.selection_bit(o2::aod::evsel::kIsTriggerTVX), bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder), bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder), static_cast(collisions_perBC.size() > 0)); // TVX is fired. + embc(bc.alias_raw(), bc.selection_raw(), bc.rct_raw()); // TVX is fired. + } + } // end of bc loop + + for (const auto& collision : collisions) { + if constexpr (isMC) { + if (!collision.has_mcCollision()) { + continue; + } + } + registry.fill(HIST("hEventCounter"), 1); + + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!collision.isSelected()) { // minimal cut for MB + continue; + } + + if constexpr (eventtype == EMEventType::kEvent) { + event_norm_info(collision.alias_raw(), collision.selection_raw(), collision.rct_raw(), static_cast(10.f * collision.posZ()), 105.f); + } else if constexpr (eventtype == EMEventType::kEvent_Cent || eventtype == EMEventType::kEvent_Cent_Qvec) { + event_norm_info(collision.alias_raw(), collision.selection_raw(), collision.rct_raw(), static_cast(10.f * collision.posZ()), collision.centFT0C()); + } else { + event_norm_info(collision.alias_raw(), collision.selection_raw(), collision.rct_raw(), static_cast(10.f * collision.posZ()), 105.f); + } + + if (!collision.isEoI()) { // events with at least 1 lepton for data reduction. + continue; + } + + if constexpr (isTriggerAnalysis) { + if (collision.swtaliastmp_raw() == 0) { + continue; + } else { + emswtbit(collision.swtaliastmp_raw(), collision.nInspectedTVX()); + } + } + + registry.fill(HIST("hEventCounter"), 2); + + event(collision.globalIndex(), bc.runNumber(), bc.globalBC(), collision.alias_raw(), collision.selection_raw(), collision.rct_raw(), bc.timestamp(), + collision.posX(), collision.posY(), collision.posZ(), + collision.numContrib(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + + // eventcov(collision.covXX(), collision.covXY(), collision.covXZ(), collision.covYY(), collision.covYZ(), collision.covZZ(), collision.chi2()); + + event_mult(collision.multFT0A(), collision.multFT0C(), collision.multNTracksPV(), collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf()); + + if constexpr (eventtype == EMEventType::kEvent) { + event_cent(105.f, 105.f, 105.f); + event_qvec( + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f); + } else if constexpr (eventtype == EMEventType::kEvent_Cent) { + event_cent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C()); + event_qvec( + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f); + } else if constexpr (eventtype == EMEventType::kEvent_Cent_Qvec) { + event_cent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C()); + float q2xft0m = 999.f, q2yft0m = 999.f, q2xft0a = 999.f, q2yft0a = 999.f, q2xft0c = 999.f, q2yft0c = 999.f, q2xbpos = 999.f, q2ybpos = 999.f, q2xbneg = 999.f, q2ybneg = 999.f, q2xbtot = 999.f, q2ybtot = 999.f; + float q3xft0m = 999.f, q3yft0m = 999.f, q3xft0a = 999.f, q3yft0a = 999.f, q3xft0c = 999.f, q3yft0c = 999.f, q3xbpos = 999.f, q3ybpos = 999.f, q3xbneg = 999.f, q3ybneg = 999.f, q3xbtot = 999.f, q3ybtot = 999.f; + + if (collision.qvecFT0CReVec().size() >= 2) { // harmonics 2,3 + q2xft0m = collision.qvecFT0MReVec()[0], q2xft0a = collision.qvecFT0AReVec()[0], q2xft0c = collision.qvecFT0CReVec()[0], q2xbpos = collision.qvecBPosReVec()[0], q2xbneg = collision.qvecBNegReVec()[0], q2xbtot = collision.qvecBTotReVec()[0]; + q2yft0m = collision.qvecFT0MImVec()[0], q2yft0a = collision.qvecFT0AImVec()[0], q2yft0c = collision.qvecFT0CImVec()[0], q2ybpos = collision.qvecBPosImVec()[0], q2ybneg = collision.qvecBNegImVec()[0], q2ybtot = collision.qvecBTotImVec()[0]; + q3xft0m = collision.qvecFT0MReVec()[1], q3xft0a = collision.qvecFT0AReVec()[1], q3xft0c = collision.qvecFT0CReVec()[1], q3xbpos = collision.qvecBPosReVec()[1], q3xbneg = collision.qvecBNegReVec()[1], q3xbtot = collision.qvecBTotReVec()[1]; + q3yft0m = collision.qvecFT0MImVec()[1], q3yft0a = collision.qvecFT0AImVec()[1], q3yft0c = collision.qvecFT0CImVec()[1], q3ybpos = collision.qvecBPosImVec()[1], q3ybneg = collision.qvecBNegImVec()[1], q3ybtot = collision.qvecBTotImVec()[1]; + } else if (collision.qvecFT0CReVec().size() >= 1) { // harmonics 2 + q2xft0m = collision.qvecFT0MReVec()[0], q2xft0a = collision.qvecFT0AReVec()[0], q2xft0c = collision.qvecFT0CReVec()[0], q2xbpos = collision.qvecBPosReVec()[0], q2xbneg = collision.qvecBNegReVec()[0], q2xbtot = collision.qvecBTotReVec()[0]; + q2yft0m = collision.qvecFT0MImVec()[0], q2yft0a = collision.qvecFT0AImVec()[0], q2yft0c = collision.qvecFT0CImVec()[0], q2ybpos = collision.qvecBPosImVec()[0], q2ybneg = collision.qvecBNegImVec()[0], q2ybtot = collision.qvecBTotImVec()[0]; + } + event_qvec( + q2xft0m, q2yft0m, q2xft0a, q2yft0a, q2xft0c, q2yft0c, q2xbpos, q2ybpos, q2xbneg, q2ybneg, q2xbtot, q2ybtot, + q3xft0m, q3yft0m, q3xft0a, q3yft0a, q3xft0c, q3yft0c, q3xbpos, q3ybpos, q3xbneg, q3ybneg, q3xbtot, q3ybtot); + } else { + event_cent(105.f, 105.f, 105.f); + event_qvec( + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f); + } + } // end of collision loop + } // end of skimEvent + + //---------- for data ---------- + + void processEvent(MyCollisions const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(CreateEMEventDilepton, processEvent, "process event info", false); + + void processEvent_Cent(MyCollisions_Cent const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(CreateEMEventDilepton, processEvent_Cent, "process event info", false); + + void processEvent_Cent_Qvec(MyCollisions_Cent_Qvec const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(CreateEMEventDilepton, processEvent_Cent_Qvec, "process event info", false); + + //---------- for data with swt---------- + + void processEvent_SWT(MyCollisionsWithSWT const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(CreateEMEventDilepton, processEvent_SWT, "process event info", false); + + void processEvent_SWT_Cent(MyCollisionsWithSWT_Cent const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(CreateEMEventDilepton, processEvent_SWT_Cent, "process event info", false); + + void processEvent_SWT_Cent_Qvec(MyCollisionsWithSWT_Cent_Qvec const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(CreateEMEventDilepton, processEvent_SWT_Cent_Qvec, "process event info", false); + + //---------- for MC ---------- + + void processEventMC(MyCollisionsMC const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(CreateEMEventDilepton, processEventMC, "process event info", false); + + void processEventMC_Cent(MyCollisionsMC_Cent const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(CreateEMEventDilepton, processEventMC_Cent, "process event info", false); + + void processEventMC_Cent_Qvec(MyCollisionsMC_Cent_Qvec const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(CreateEMEventDilepton, processEventMC_Cent_Qvec, "process event info", false); + + void processDummy(aod::Collisions const&) {} + PROCESS_SWITCH(CreateEMEventDilepton, processDummy, "processDummy", true); +}; +struct AssociateDileptonToEMEvent { + Produces v0kfeventid; + Produces prmeleventid; + Produces prmmueventid; + + Preslice perCollision_pcm = aod::v0photonkf::collisionId; + PresliceUnsorted perCollision_el = aod::emprimaryelectron::collisionId; + PresliceUnsorted perCollision_mu = aod::emprimarymuon::collisionId; + + void init(o2::framework::InitContext&) {} + + template + void fillEventId(TCollisions const& collisions, TLeptons const& leptons, TEventIds& eventIds, TPreslice const& perCollision) + { + for (const auto& collision : collisions) { + auto leptons_coll = leptons.sliceBy(perCollision, collision.collisionId()); + int nl = leptons_coll.size(); + // LOGF(info, "collision.collisionId() = %d , nl = %d", collision.collisionId(), nl); + for (int il = 0; il < nl; il++) { + eventIds(collision.globalIndex()); + } // end of photon loop + } // end of collision loop + } + + // This struct is for both data and MC. + // Note that reconstructed collisions without mc collisions are already rejected in CreateEMEventDilepton in MC. + + void processPCM(aod::EMEvents const& collisions, aod::V0PhotonsKF const& photons) + { + fillEventId(collisions, photons, v0kfeventid, perCollision_pcm); + } + + void processElectron(aod::EMEvents const& collisions, aod::EMPrimaryElectrons const& tracks) + { + fillEventId(collisions, tracks, prmeleventid, perCollision_el); + } + + void processFwdMuon(aod::EMEvents const& collisions, aod::EMPrimaryMuons const& tracks) + { + fillEventId(collisions, tracks, prmmueventid, perCollision_mu); + } + + void processDummy(aod::EMEvents const&) {} + + PROCESS_SWITCH(AssociateDileptonToEMEvent, processPCM, "process pcm-event indexing", false); + PROCESS_SWITCH(AssociateDileptonToEMEvent, processElectron, "process dalitzee-event indexing", false); + PROCESS_SWITCH(AssociateDileptonToEMEvent, processFwdMuon, "process forward muon indexing", false); + PROCESS_SWITCH(AssociateDileptonToEMEvent, processDummy, "process dummy", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"create-emevent-dilepton"}), + adaptAnalysisTask(cfgc, TaskName{"associate-dilepton-to-emevent"}), + }; +} diff --git a/PWGEM/Dilepton/TableProducer/dielectronMl.cxx b/PWGEM/Dilepton/TableProducer/dielectronMl.cxx deleted file mode 100644 index 7ef2a8a4762..00000000000 --- a/PWGEM/Dilepton/TableProducer/dielectronMl.cxx +++ /dev/null @@ -1,361 +0,0 @@ -// 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 dielectronMl.cxx -/// \task for testing ML application for dielectron analyses -/// \author Daniel Samitz, , SMI Vienna -/// Elisa Meninno, , SMI Vienna - -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "PWGDQ/DataModel/ReducedInfoTables.h" -#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" -#include "PWGEM/Dilepton/Utils/MlResponseDielectronPair.h" - -using namespace o2; -using namespace o2::analysis; -using namespace o2::framework; -using namespace o2::aod; - -namespace o2::aod -{ - -namespace dielectronMlSelection -{ -DECLARE_SOA_COLUMN(IsSelMlSingleTrack, isSelMlSingleTrack, bool); -DECLARE_SOA_COLUMN(IsSelMlPair, isSelMlPair, bool); -DECLARE_SOA_COLUMN(MlScoreSingleTrack, mlScoreSingleTrack, std::vector); -DECLARE_SOA_COLUMN(MlScorePair, mlScorePair, std::vector); -} // namespace dielectronMlSelection - -DECLARE_SOA_TABLE(dielectronMlSelectionSingleTrack, "AOD", "DIELEMLSELST", //! - dielectronMlSelection::IsSelMlSingleTrack); -DECLARE_SOA_TABLE(dielectronMlScoreSingleTrack, "AOD", "DIELEMLSCOREST", //! - dielectronMlSelection::MlScoreSingleTrack); -DECLARE_SOA_TABLE(dielectronMlSelectionPair, "AOD", "DIELEMLSELP", //! - dielectronMlSelection::IsSelMlPair); -DECLARE_SOA_TABLE(dielectronMlScorePair, "AOD", "DIELEMLSCOREP", //! - dielectronMlSelection::MlScorePair); -} // namespace o2::aod - -using MySkimmedTracks = soa::Join; -using MySkimmedTracksWithPID = soa::Join; -using MyTracksWithPID = soa::Join; - -// define some default values for single track analysis -namespace dielectron_ml_cuts_single_track -{ -// direction of the cut -enum CutDirection { - CutGreater = 0, // require score < cut value - CutSmaller, // require score > cut value - CutNot // do not cut on score -}; - -static constexpr int nBinsPt = 1; -static constexpr int nCutScores = 2; -// default values for the pT bin edges, offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { - 0., - 999.}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; - -// default values for the ML model paths, one model per pT bin -static const std::vector modelPaths = { - ""}; - -// default values for the cut directions -constexpr int cutDir[nCutScores] = {CutSmaller, CutGreater}; -auto vecCutDir = std::vector{cutDir, cutDir + nCutScores}; - -// default values for the cuts -constexpr double cuts[nBinsPt][nCutScores] = { - {0.5, 0.5}}; - -// row labels -static const std::vector labelsPt = { - "pT bin 0"}; - -// column labels -static const std::vector labelsCutScore = {"Signal", "Background"}; -} // namespace dielectron_ml_cuts_single_track - -// define some default values for pair analysis -namespace dielectron_ml_cuts_pair -{ -// direction of the cut -enum CutDirection { - CutGreater = 0, // require score < cut value - CutSmaller, // require score > cut value - CutNot // do not cut on score -}; - -static constexpr int nBinsM = 1; -static constexpr int nCutScores = 2; -// default values for the mass bin edges, offset by 1 from the bin numbers in cuts array -constexpr double binsM[nBinsM + 1] = { - 0., - 999.}; -auto vecBinsM = std::vector{binsM, binsM + nBinsM + 1}; - -// default values for the ML model paths, one model per mass bin -static const std::vector modelPaths = { - ""}; - -// default values for the cut directions -constexpr int cutDir[nCutScores] = {CutSmaller, CutGreater}; -auto vecCutDir = std::vector{cutDir, cutDir + nCutScores}; - -// default values for the cuts -constexpr double cuts[nBinsM][nCutScores] = { - {0.5, 0.5}}; - -// row labels -static const std::vector labelsM = { - "mass bin 0"}; - -// column labels -static const std::vector labelsCutScore = {"Signal", "Background"}; -} // namespace dielectron_ml_cuts_pair - -struct DielectronMlSingleTrack { - Produces singleTrackSelection; - Produces singleTrackScore; - - // ML inference - Configurable> binsPtMl{"binsPtMl", std::vector{dielectron_ml_cuts_single_track::vecBinsPt}, "pT bin limits for ML application"}; - Configurable> cutDirMl{"cutDirMl", std::vector{dielectron_ml_cuts_single_track::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; - Configurable> cutsMl{"cutsMl", {dielectron_ml_cuts_single_track::cuts[0], dielectron_ml_cuts_single_track::nBinsPt, dielectron_ml_cuts_single_track::nCutScores, dielectron_ml_cuts_single_track::labelsPt, dielectron_ml_cuts_single_track::labelsCutScore}, "ML selections per pT bin"}; - Configurable nClassesMl{"nClassesMl", static_cast(dielectron_ml_cuts_single_track::nCutScores), "Number of classes in ML model"}; - Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; - // CCDB configuration - Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{""}, "Paths of models on CCDB"}; - Configurable> onnxFileNames{"onnxFileNames", std::vector{""}, "ONNX file names for each pT bin (if not from CCDB full path)"}; - Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; - Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; - // preselection cuts (from treeCreatorElectronMl.cxx) - Configurable mincrossedrows{"mincrossedrows", 70, "min. crossed rows"}; - Configurable maxchi2tpc{"maxchi2tpc", 4.0, "max. chi2/NclsTPC"}; - Configurable maxeta{"maxeta", 0.9, "eta acceptance"}; - // table output - Configurable fillScoreTable{"fillScoreTable", false, "fill table with scores from ML model"}; - - o2::analysis::MlResponseDielectronSingleTrack mlResponse; - o2::ccdb::CcdbApi ccdbApi; - std::vector> hModelScore; - std::vector> hModelScoreVsPt; - - HistogramRegistry registry{"registry", {}}; - - void init(InitContext&) - { - if (doprocessSkimmedSingleTrack || doprocessAO2DSingleTrack) { - mlResponse.configure(binsPtMl, cutsMl, cutDirMl, nClassesMl); - if (loadModelsFromCCDB) { - ccdbApi.init(ccdbUrl); - mlResponse.setModelPathsCCDB(onnxFileNames, ccdbApi, modelPathsCCDB, timestampCCDB); - } else { - mlResponse.setModelPathsLocal(onnxFileNames); - } - mlResponse.cacheInputFeaturesIndices(namesInputFeatures); - mlResponse.init(); - - // load histograms for ML score - AxisSpec axisScore = {100, 0, 1, "score"}; - AxisSpec axisBinsPt = {binsPtMl, "#it{p}_{T} (GeV/#it{c})"}; - for (int classMl = 0; classMl < nClassesMl; classMl++) { - hModelScore.push_back(registry.add("hMlScore" + TString(cutsMl->getLabelsCols()[classMl]), "Model score distribution;Model score;counts", HistType::kTH1F, {axisScore})); - hModelScoreVsPt.push_back(registry.add("hMlScore" + TString(cutsMl->getLabelsCols()[classMl]) + "VsPt", "Model score distribution;Model score;counts", HistType::kTH2F, {axisScore, axisBinsPt})); - } - } - } - - template - bool applyPreSelectionCuts(T const& track) - { - // consistent with treeCreatorElectronMl.cxx - if (!track.hasITS()) { - return false; - } - if (!track.hasTPC()) { - return false; - } - if (track.tpcNClsCrossedRows() < mincrossedrows) { - return false; - } - if (track.itsChi2NCl() < -1) { // if tracks are not reconstructed properly, chi2/ITSncls is set to -999; - return false; - } - if (abs(track.eta()) > maxeta) { - return false; - } - if (track.tpcChi2NCl() > maxchi2tpc) { - return false; - } - if (abs(track.dcaXY()) > 1.) { - return false; - } - if (abs(track.dcaZ()) > 1.) { - return false; - } - return true; - } - - template - void runSingleTracks(T const& tracks) - { - for (const auto& track : tracks) { - if (!applyPreSelectionCuts(track)) { - singleTrackSelection(false); - if (fillScoreTable) { - std::vector outputMl(nClassesMl, -1); - singleTrackScore(outputMl); - } - continue; - } - auto pt = track.pt(); - std::vector inputFeatures = mlResponse.getInputFeatures(track); - std::vector outputMl = {}; - - bool isSelected = mlResponse.isSelectedMl(inputFeatures, pt, outputMl); - for (int classMl = 0; classMl < nClassesMl; classMl++) { - hModelScore[classMl]->Fill(outputMl[classMl]); - hModelScoreVsPt[classMl]->Fill(outputMl[classMl], pt); - } - singleTrackSelection(isSelected); - if (fillScoreTable) { - singleTrackScore(outputMl); - } - } - } - - void processSkimmedSingleTrack(MySkimmedTracksWithPID const& tracks) - { - runSingleTracks(tracks); - } - PROCESS_SWITCH(DielectronMlSingleTrack, processSkimmedSingleTrack, "Apply ML selection on skimmed output on single tracks", true); - - void processAO2DSingleTrack(MyTracksWithPID const& tracks) - { - runSingleTracks(tracks); - } - PROCESS_SWITCH(DielectronMlSingleTrack, processAO2DSingleTrack, "Apply ML selection on skimmed output on single tracks", false); - - void processDummy(DielectronsExtra const&) - { - // dummy - } - PROCESS_SWITCH(DielectronMlSingleTrack, processDummy, "Dummy", false); -}; - -struct DielectronMlPair { - Produces pairSelection; - Produces pairScore; - - // ML inference - Configurable> binsMMl{"binsMMl", std::vector{dielectron_ml_cuts_pair::vecBinsM}, "Mass bin limits for ML application"}; - Configurable> cutDirMl{"cutDirMl", std::vector{dielectron_ml_cuts_pair::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; - Configurable> cutsMl{"cutsMl", {dielectron_ml_cuts_pair::cuts[0], dielectron_ml_cuts_pair::nBinsM, dielectron_ml_cuts_pair::nCutScores, dielectron_ml_cuts_pair::labelsM, dielectron_ml_cuts_pair::labelsCutScore}, "ML selections per pT bin"}; - Configurable nClassesMl{"nClassesMl", static_cast(dielectron_ml_cuts_pair::nCutScores), "Number of classes in ML model"}; - Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; - // CCDB configuration - Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{""}, "Paths of models on CCDB"}; - Configurable> onnxFileNames{"onnxFileNames", std::vector{""}, "ONNX file names for each pT bin (if not from CCDB full path)"}; - Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; - Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; - // table output - Configurable fillScoreTable{"fillScoreTable", false, "fill table with scores from ML model"}; - - o2::analysis::MlResponseDielectronPair mlResponse; - o2::ccdb::CcdbApi ccdbApi; - std::vector> hModelScore; - std::vector> hModelScoreVsM; - - HistogramRegistry registry{"registry", {}}; - - void init(InitContext&) - { - if (doprocessPair) { - mlResponse.configure(binsMMl, cutsMl, cutDirMl, nClassesMl); - if (loadModelsFromCCDB) { - ccdbApi.init(ccdbUrl); - mlResponse.setModelPathsCCDB(onnxFileNames, ccdbApi, modelPathsCCDB, timestampCCDB); - } else { - mlResponse.setModelPathsLocal(onnxFileNames); - } - mlResponse.cacheInputFeaturesIndices(namesInputFeatures); - mlResponse.init(); - - // load histograms for ML score - AxisSpec axisScore = {100, 0, 1, "score"}; - AxisSpec axisBinsM = {binsMMl, "#it{M} (GeV/#it{c^{2}})"}; - for (int classMl = 0; classMl < nClassesMl; classMl++) { - hModelScore.push_back(registry.add("hMlScore" + TString(cutsMl->getLabelsCols()[classMl]), "Model score distribution;Model score;counts", HistType::kTH1F, {axisScore})); - hModelScoreVsM.push_back(registry.add("hMlScore" + TString(cutsMl->getLabelsCols()[classMl]) + "VsM", "Model score distribution;Model score;counts", HistType::kTH2F, {axisScore, axisBinsM})); - } - } - } - - void processPair(DielectronsExtra const& dielectrons, MySkimmedTracks const&) - { - // dummy value for magentic field. ToDo: take it from ccdb! - float d_bz = 1.; - mlResponse.setBz(d_bz); - for (const auto& dielectron : dielectrons) { - const auto& track1 = dielectron.index0_as(); - const auto& track2 = dielectron.index1_as(); - if (track1.sign() == track2.sign()) { - continue; - } - ROOT::Math::PtEtaPhiMVector v1(track1.pt(), track1.eta(), track1.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(track2.pt(), track2.eta(), track2.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - auto m = v12.M(); - std::vector inputFeatures = mlResponse.getInputFeatures(track1, track2); - std::vector outputMl = {}; - - bool isSelected = mlResponse.isSelectedMl(inputFeatures, m, outputMl); - for (int classMl = 0; classMl < nClassesMl; classMl++) { - hModelScore[classMl]->Fill(outputMl[classMl]); - hModelScoreVsM[classMl]->Fill(outputMl[classMl], m); - } - pairSelection(isSelected); - if (fillScoreTable) { - pairScore(outputMl); - } - } - } - PROCESS_SWITCH(DielectronMlPair, processPair, "Apply ML selection at pair level", false); - - void processDummyAO2D(MyTracksWithPID const&) - { - // dummy - } - PROCESS_SWITCH(DielectronMlPair, processDummyAO2D, "Dummy", false); - - void processDummySkimmed(MySkimmedTracks const&) - { - // dummy - } - PROCESS_SWITCH(DielectronMlPair, processDummySkimmed, "Dummy", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGEM/Dilepton/TableProducer/eventSelection.cxx b/PWGEM/Dilepton/TableProducer/eventSelection.cxx new file mode 100644 index 00000000000..65eb1a93d53 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/eventSelection.cxx @@ -0,0 +1,147 @@ +// 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. +// +// ======================== +// +// This code produces event selection table for PWG-EM. +// Please write to: daiki.sekihata@cern.ch + +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Common/CCDB/RCTSelectionFlags.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +using MyCollisions = soa::Join; +using MyCollisions_Cent = soa::Join; + +using MyCollisionsMC = soa::Join; +using MyCollisionsMC_Cent = soa::Join; + +struct EMEventSelection { + Produces emevsel; + + // Configurables + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentMin{"cfgCentMin", -1.f, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + + // for RCT + Configurable cfgRequireGoodRCT{"cfgRequireGoodRCT", false, "require good detector flag in run condtion table"}; + Configurable cfgRCTLabel{"cfgRCTLabel", "CBT_hadronPID", "select 1 [CBT, CBT_hadron, CBT_muon_glo] see O2Physics/Common/CCDB/RCTSelectionFlags.h"}; + Configurable cfgCheckZDC{"cfgCheckZDC", false, "set ZDC flag for PbPb"}; + Configurable cfgTreatLimitedAcceptanceAsBad{"cfgTreatLimitedAcceptanceAsBad", false, "reject all events where the detectors relevant for the specified Runlist are flagged as LimitedAcceptance"}; + + Configurable cfgZvtxMin{"cfgZvtxMin", -1e+10, "min. Zvtx"}; + Configurable cfgZvtxMax{"cfgZvtxMax", 1e+10, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", false, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", false, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. track occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. track occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "require no collision in time range standard"}; + + o2::aod::rctsel::RCTFlagsChecker rctChecker; + + void init(InitContext&) + { + rctChecker.init(cfgRCTLabel.value, cfgCheckZDC.value, cfgTreatLimitedAcceptanceAsBad.value); + } + + template + bool isSelectedEvent(TCollision const& collision) + { + if constexpr (std::is_same_v, MyCollisionsMC::iterator> || std::is_same_v, MyCollisionsMC_Cent::iterator>) { + if (!collision.has_mcCollision()) { + return false; + } + } + + if (collision.posZ() < cfgZvtxMin || cfgZvtxMax < collision.posZ()) { + return false; + } + + if (cfgRequireFT0AND && !collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + return false; + } + + if (cfgRequireNoTFB && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + + if (cfgRequireNoITSROFB && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + + if (cfgRequireNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + + if (cfgRequireGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + + if (cfgRequireNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + + if (!(cfgTrackOccupancyMin <= collision.trackOccupancyInTimeRange() && collision.trackOccupancyInTimeRange() < cfgTrackOccupancyMax)) { + return false; + } + + if (!(cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange() && collision.ft0cOccupancyInTimeRange() < cfgFT0COccupancyMax)) { + return false; + } + + if constexpr (std::is_same_v, MyCollisions_Cent::iterator>) { + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + return false; + } + } + + if (cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + // LOGF(info, "rejected by RCT flag"); + return false; + } + + return true; + } + + template + void processEventSelection(TCollisions const& collisions) + { + for (const auto& collision : collisions) { + emevsel(isSelectedEvent(collision)); + } // end of collision loop + } // end of process + + PROCESS_SWITCH_FULL(EMEventSelection, processEventSelection, processEventSelection, "event selection", true); + PROCESS_SWITCH_FULL(EMEventSelection, processEventSelection, processEventSelection_Cent, "event selection with cent", false); + PROCESS_SWITCH_FULL(EMEventSelection, processEventSelection, processEventSelectionMC, "event selection MC", false); + PROCESS_SWITCH_FULL(EMEventSelection, processEventSelection, processEventSelectionMC_Cent, "event selection MC with cent", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"em-event-selection"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/filterDielectronEvent.cxx b/PWGEM/Dilepton/TableProducer/filterDielectronEvent.cxx new file mode 100644 index 00000000000..69dc9ad0b2b --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/filterDielectronEvent.cxx @@ -0,0 +1,1719 @@ +// 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 write relevant information about primary electrons. +/// \author daiki.sekihata@cern.ch + +#include +#include +#include +#include +#include + +#include "Math/Vector4D.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "Common/Core/trackUtilities.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/Core/TableHelper.h" + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" + +using namespace o2; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; + +using MyTracks = soa::Join; +using MyTrack = MyTracks::iterator; +using MyTracksMC = soa::Join; +using MyTrackMC = MyTracksMC::iterator; + +struct filterDielectronEvent { + using MyCollisions = soa::Join; + using MyCollisionsWithSWT = soa::Join; + + SliceCache cache; + Preslice perCol = o2::aod::track::collisionId; + Produces emprimaryelectrons; + Produces emprimaryelectronscov; + Produces filter; + + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + + // Operation and minimisation criteria + Configurable fillQAHistogram{"fillQAHistogram", false, "flag to fill QA histograms"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + Configurable min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable mincrossedrows{"mincrossedrows", 80, "min. crossed rows"}; + Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; + Configurable max_pin_for_pion_rejection{"max_pin_for_pion_rejection", 1e+10, "pion rejection is applied below this pin"}; + Configurable max_frac_shared_clusters_tpc{"max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable min_ncluster_its{"min_ncluster_its", 4, "min ncluster its"}; + Configurable min_ncluster_itsib{"min_ncluster_itsib", 1, "min ncluster itsib"}; + Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max. chi2/NclsTPC"}; + Configurable maxchi2its{"maxchi2its", 6.0, "max. chi2/NclsITS"}; + Configurable minpt{"minpt", 0.15, "min pt for track"}; + Configurable maxeta{"maxeta", 0.9, "eta acceptance"}; + Configurable dca_xy_max{"dca_xy_max", 0.1f, "max DCAxy in cm"}; + Configurable dca_z_max{"dca_z_max", 0.1f, "max DCAz in cm"}; + Configurable dca_3d_sigma_max{"dca_3d_sigma_max", 1.5, "max DCA 3D in sigma"}; + Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -2.5, "min. TPC n sigma for electron inclusion"}; + Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", 3.5, "max. TPC n sigma for electron inclusion"}; + Configurable maxTOFNsigmaEl{"maxTOFNsigmaEl", 3.5, "max. TOF n sigma for electron inclusion"}; + Configurable minTPCNsigmaPi{"minTPCNsigmaPi", -1e+10, "min. TPC n sigma for pion exclusion"}; + Configurable maxTPCNsigmaPi{"maxTPCNsigmaPi", 2.0, "max. TPC n sigma for pion exclusion"}; + Configurable minTPCNsigmaKa{"minTPCNsigmaKa", -3.0, "min. TPC n sigma for kaon exclusion"}; + Configurable maxTPCNsigmaKa{"maxTPCNsigmaKa", +3.0, "max. TPC n sigma for kaon exclusion"}; + Configurable minTPCNsigmaPr{"minTPCNsigmaPr", -3.0, "min. TPC n sigma for proton exclusion"}; + Configurable maxTPCNsigmaPr{"maxTPCNsigmaPr", +3.0, "max. TPC n sigma for proton exclusion"}; + Configurable maxMee{"maxMee", 1e+10, "max mee for virtual photon selection"}; + + Configurable apply_phiv{"apply_phiv", true, "flag to apply phiv cut"}; + Configurable slope{"slope", 0.0181, "slope for mee vs. phiv"}; + Configurable intercept{"intercept", -0.0370, "intercept for mee vs. phiv"}; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + int mRunNumber; + float d_bz; + Service ccdb; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + + void init(InitContext&) + { + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + if (fillQAHistogram) { + fRegistry.add("Track/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); + fRegistry.add("Track/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); + fRegistry.add("Track/hRelSigma1Pt", "relative p_{T} resolution;p_{T} (GeV/c);#sigma_{1/p_{T}} #times p_{T}", kTH2F, {{1000, 0, 10}, {100, 0, 0.1}}, false); + fRegistry.add("Track/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {20, -1.0f, 1.0f}}, false); + fRegistry.add("Track/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -1.0f, 1.0f}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("Track/hDCAxyzSigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {{1000, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/hDCAzRes_Pt", "DCA_{z} resolution vs. pT;p_{T} (GeV/c);DCA_{z} resolution (#mum)", kTH2F, {{1000, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/hNclsTPC", "number of TPC clusters", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hNcrTPC", "number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("Track/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaMu", "TPC n sigma mu;p_{in} (GeV/c);n #sigma_{#mu}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaKa", "TPC n sigma ka;p_{in} (GeV/c);n #sigma_{K}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaPr", "TPC n sigma pr;p_{in} (GeV/c);n #sigma_{p}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFbeta", "TOF beta;p_{pv} (GeV/c);#beta", kTH2F, {{1000, 0, 10}, {240, 0, 1.2}}, false); + fRegistry.add("Track/hTOFNsigmaEl", "TOF n sigma el;p_{pv} (GeV/c);n #sigma_{e}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaMu", "TOF n sigma mu;p_{pv} (GeV/c);n #sigma_{#mu}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaPi", "TOF n sigma pi;p_{pv} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaKa", "TOF n sigma ka;p_{pv} (GeV/c);n #sigma_{K}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaPr", "TOF n sigma pr;p_{pv} (GeV/c);n #sigma_{p}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hTPCNclsShared", "TPC Ncls/Nfindable;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); + fRegistry.add("Track/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("Track/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("Track/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); on ITS #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); + fRegistry.add("Pair/before/hMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{400, 0, 4}, {100, 0, 10}}, false); + fRegistry.add("Pair/before/hMvsPhiV", "mee vs. phiv;#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0, M_PI}, {100, 0, 0.1}}, false); + fRegistry.addClone("Pair/before/", "Pair/after/"); + fRegistry.add("Pair/uls/hM", "m_{ee};m_{ee} (GeV/c^{2})", kTH1F, {{100, 0, 0.1}}, false); + fRegistry.add("Pair/lspp/hM", "m_{ee};m_{ee} (GeV/c^{2})", kTH1F, {{100, 0, 0.1}}, false); + fRegistry.add("Pair/lsmm/hM", "m_{ee};m_{ee} (GeV/c^{2})", kTH1F, {{100, 0, 0.1}}, false); + } + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (std::fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + o2::base::Propagator::initFieldFromGRP(&grpmag); + mRunNumber = bc.runNumber(); + return; + } + + auto run3grp_timestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = bc.runNumber(); + } + + template + bool checkTrack(TCollision const& collision, TTrack const& track) + { + if constexpr (isMC) { + if (!track.has_mcParticle()) { + return false; + } + } + + if (track.tpcChi2NCl() > maxchi2tpc) { + return false; + } + + if (track.itsChi2NCl() > maxchi2its) { + return false; + } + + if (!track.hasITS() || !track.hasTPC()) { + return false; + } + if (track.itsNCls() < min_ncluster_its) { + return false; + } + if (track.itsNClsInnerBarrel() < min_ncluster_itsib) { + return false; + } + + if (track.tpcNClsFound() < min_ncluster_tpc) { + return false; + } + + if (track.tpcNClsCrossedRows() < mincrossedrows) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { + return false; + } + + if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { + return false; + } + + gpu::gpustd::array dcaInfo; + auto track_par_cov_recalc = getTrackParCov(track); + track_par_cov_recalc.setPID(o2::track::PID::Electron); + // std::array pVec_recalc = {0, 0, 0}; // px, py, pz + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, track_par_cov_recalc, 2.f, matCorr, &dcaInfo); + // getPxPyPz(track_par_cov_recalc, pVec_recalc); + float dcaXY = dcaInfo[0]; + float dcaZ = dcaInfo[1]; + + if (std::fabs(dcaXY) > dca_xy_max || std::fabs(dcaZ) > dca_z_max) { + return false; + } + + if (track_par_cov_recalc.getPt() < minpt || std::fabs(track_par_cov_recalc.getEta()) > maxeta) { + return false; + } + + float dca_3d = 999.f; + float det = track_par_cov_recalc.getSigmaY2() * track_par_cov_recalc.getSigmaZ2() - track_par_cov_recalc.getSigmaZY() * track_par_cov_recalc.getSigmaZY(); + if (det < 0) { + dca_3d = 999.f; + } else { + float chi2 = (dcaXY * dcaXY * track_par_cov_recalc.getSigmaZ2() + dcaZ * dcaZ * track_par_cov_recalc.getSigmaY2() - 2. * dcaXY * dcaZ * track_par_cov_recalc.getSigmaZY()) / det; + dca_3d = std::sqrt(std::fabs(chi2) / 2.); + } + if (dca_3d > dca_3d_sigma_max) { + return false; + } + + return true; + } + + template + bool isElectron(TTrack const& track) + { + return isElectron_TPChadrej(track) || isElectron_TOFreq(track); + } + + template + bool isElectron_TPChadrej(TTrack const& track) + { + if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { + return false; + } + if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi && track.tpcInnerParam() < max_pin_for_pion_rejection) { + return false; + } + if (minTPCNsigmaKa < track.tpcNSigmaKa() && track.tpcNSigmaKa() < maxTPCNsigmaKa) { + return false; + } + if (minTPCNsigmaPr < track.tpcNSigmaPr() && track.tpcNSigmaPr() < maxTPCNsigmaPr) { + return false; + } + if (track.hasTOF() && (maxTOFNsigmaEl < std::fabs(track.tofNSigmaEl()))) { + return false; + } + return true; + } + + template + bool isElectron_TOFreq(TTrack const& track) + { + if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi && track.tpcInnerParam() < max_pin_for_pion_rejection) { + return false; + } + return minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl && std::fabs(track.tofNSigmaEl()) < maxTOFNsigmaEl; + } + + template + void fillTrackTable(TCollision const& collision, TTrack const& track) + { + if (std::find(stored_trackIds.begin(), stored_trackIds.end(), std::pair{collision.globalIndex(), track.globalIndex()}) == stored_trackIds.end()) { + gpu::gpustd::array dcaInfo; + auto track_par_cov_recalc = getTrackParCov(track); + track_par_cov_recalc.setPID(o2::track::PID::Electron); + // std::array pVec_recalc = {0, 0, 0}; // px, py, pz + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, track_par_cov_recalc, 2.f, matCorr, &dcaInfo); + // getPxPyPz(track_par_cov_recalc, pVec_recalc); + float dcaXY = dcaInfo[0]; + float dcaZ = dcaInfo[1]; + + float pt_recalc = track_par_cov_recalc.getPt(); + float eta_recalc = track_par_cov_recalc.getEta(); + float phi_recalc = track_par_cov_recalc.getPhi(); + + bool isAssociatedToMPC = collision.globalIndex() == track.collisionId(); + + emprimaryelectrons(collision.globalIndex(), track.globalIndex(), track.sign(), + pt_recalc, eta_recalc, phi_recalc, dcaXY, dcaZ, + track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), track.tpcNClsShared(), + track.tpcChi2NCl(), track.tpcInnerParam(), + track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaMu(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), + track.beta(), track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), + track.itsClusterSizes(), 0, 0, 0, 0, 0, + track.itsChi2NCl(), track.tofChi2(), track.detectorMap(), + track_par_cov_recalc.getX(), track_par_cov_recalc.getAlpha(), track_par_cov_recalc.getY(), track_par_cov_recalc.getZ(), track_par_cov_recalc.getSnp(), track_par_cov_recalc.getTgl(), isAssociatedToMPC); + + emprimaryelectronscov( + track_par_cov_recalc.getSigmaY2(), + track_par_cov_recalc.getSigmaZY(), + track_par_cov_recalc.getSigmaZ2(), + track_par_cov_recalc.getSigmaSnpY(), + track_par_cov_recalc.getSigmaSnpZ(), + track_par_cov_recalc.getSigmaSnp2(), + track_par_cov_recalc.getSigmaTglY(), + track_par_cov_recalc.getSigmaTglZ(), + track_par_cov_recalc.getSigmaTglSnp(), + track_par_cov_recalc.getSigmaTgl2(), + track_par_cov_recalc.getSigma1PtY(), + track_par_cov_recalc.getSigma1PtZ(), + track_par_cov_recalc.getSigma1PtSnp(), + track_par_cov_recalc.getSigma1PtTgl(), + track_par_cov_recalc.getSigma1Pt2()); + + stored_trackIds.emplace_back(std::pair{collision.globalIndex(), track.globalIndex()}); + + if (fillQAHistogram) { + uint32_t itsClusterSizes = track.itsClusterSizes(); + int total_cluster_size = 0, nl = 0; + for (unsigned int layer = 0; layer < 7; layer++) { + int cluster_size_per_layer = (itsClusterSizes >> (layer * 4)) & 0xf; + if (cluster_size_per_layer > 0) { + nl++; + } + total_cluster_size += cluster_size_per_layer; + } + + fRegistry.fill(HIST("Track/hPt"), pt_recalc); + fRegistry.fill(HIST("Track/hQoverPt"), track.sign() / pt_recalc); + fRegistry.fill(HIST("Track/hRelSigma1Pt"), pt_recalc, std::sqrt(track_par_cov_recalc.getSigma1Pt2()) * pt_recalc); + fRegistry.fill(HIST("Track/hEtaPhi"), phi_recalc, eta_recalc); + fRegistry.fill(HIST("Track/hDCAxyz"), dcaXY, dcaZ); + fRegistry.fill(HIST("Track/hDCAxyzSigma"), dcaXY / std::sqrt(track_par_cov_recalc.getSigmaY2()), dcaZ / std::sqrt(track_par_cov_recalc.getSigmaZ2())); + fRegistry.fill(HIST("Track/hDCAxyRes_Pt"), pt_recalc, std::sqrt(track_par_cov_recalc.getSigmaY2()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hDCAzRes_Pt"), pt_recalc, std::sqrt(track_par_cov_recalc.getSigmaZ2()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hNclsITS"), track.itsNCls()); + fRegistry.fill(HIST("Track/hNclsTPC"), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("Track/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("Track/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("Track/hTPCNclsShared"), track.pt(), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("Track/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("Track/hChi2ITS"), track.itsChi2NCl()); + fRegistry.fill(HIST("Track/hITSClusterMap"), track.itsClusterMap()); + fRegistry.fill(HIST("Track/hMeanClusterSizeITS"), track.p(), static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/hTPCNsigmaMu"), track.tpcInnerParam(), track.tpcNSigmaMu()); + fRegistry.fill(HIST("Track/hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); + fRegistry.fill(HIST("Track/hTPCNsigmaKa"), track.tpcInnerParam(), track.tpcNSigmaKa()); + fRegistry.fill(HIST("Track/hTPCNsigmaPr"), track.tpcInnerParam(), track.tpcNSigmaPr()); + fRegistry.fill(HIST("Track/hTOFbeta"), track.p(), track.beta()); + fRegistry.fill(HIST("Track/hTOFNsigmaEl"), track.p(), track.tofNSigmaEl()); + fRegistry.fill(HIST("Track/hTOFNsigmaMu"), track.p(), track.tofNSigmaMu()); + fRegistry.fill(HIST("Track/hTOFNsigmaPi"), track.p(), track.tofNSigmaPi()); + fRegistry.fill(HIST("Track/hTOFNsigmaKa"), track.p(), track.tofNSigmaKa()); + fRegistry.fill(HIST("Track/hTOFNsigmaPr"), track.p(), track.tofNSigmaPr()); + } + } + } + + template + o2::track::TrackParCov propagateTrack(TCollision const& collision, TTrack const& track) + { + gpu::gpustd::array dcaInfo; + auto track_par_cov_recalc = getTrackParCov(track); + track_par_cov_recalc.setPID(o2::track::PID::Electron); + // std::array pVec_recalc = {0, 0, 0}; // px, py, pz + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, track_par_cov_recalc, 2.f, matCorr, &dcaInfo); + // getPxPyPz(track_par_cov_recalc, pVec_recalc); + return track_par_cov_recalc; + } + + std::vector> stored_trackIds; + // std::vector> stored_pairIds; + Filter trackFilter = o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& o2::aod::track::tpcChi2NCl < maxchi2tpc&& o2::aod::track::itsChi2NCl < maxchi2its&& ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true; + Filter pidFilter = minTPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < maxTPCNsigmaEl; + using MyFilteredTracks = soa::Filtered; + + Partition posTracks = o2::aod::track::signed1Pt > 0.f; + Partition negTracks = o2::aod::track::signed1Pt < 0.f; + + // ---------- for data ---------- + + void processRec_SA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const&) + { + stored_trackIds.reserve(posTracks.size() + negTracks.size()); + + for (auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!collision.isSelected()) { + filter(0, 0, 0); + continue; + } + + int nee_uls = 0; + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + + for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { + if (!checkTrack(collision, pos) || !checkTrack(collision, ele)) { + continue; + } + if (!isElectron(pos) || !isElectron(ele)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pos.px(), pos.py(), pos.pz(), ele.px(), ele.py(), ele.pz(), pos.sign(), ele.sign(), d_bz); + + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/uls/hM"), v12.M()); + fRegistry.fill(HIST("Pair/before/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/before/hMvsPhiV"), phiv, v12.M()); + } + if (apply_phiv ? (v12.M() < maxMee && slope * phiv + intercept < v12.M()) : (v12.M() < maxMee)) { + fillTrackTable(collision, pos); + fillTrackTable(collision, ele); + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/after/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/after/hMvsPhiV"), phiv, v12.M()); + } + nee_uls++; + } + + } // end of pairing loop + + if (fillQAHistogram) { + for (auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { + if (!checkTrack(collision, pos1) || !checkTrack(collision, pos2)) { + continue; + } + if (!isElectron(pos1) || !isElectron(pos2)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(pos1.pt(), pos1.eta(), pos1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + fRegistry.fill(HIST("Pair/lspp/hM"), v12.M()); + } // end of pairing loop + + for (auto& [ele1, ele2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { + if (!checkTrack(collision, ele1) || !checkTrack(collision, ele2)) { + continue; + } + if (!isElectron(ele1) || !isElectron(ele2)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(ele1.pt(), ele1.eta(), ele1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + fRegistry.fill(HIST("Pair/lsmm/hM"), v12.M()); + } // end of pairing loop + } + + if (nee_uls < 1) { + filter(nee_uls, 0, 0); + continue; + } + filter(nee_uls, 0, 0); + + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + // stored_pairIds.clear(); + // stored_pairIds.shrink_to_fit(); + } + PROCESS_SWITCH(filterDielectronEvent, processRec_SA, "process reconstructed info only", true); // standalone + + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + void processRec_TTCA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyTracks const& tracks, aod::TrackAssoc const& trackIndices) + { + stored_trackIds.reserve(tracks.size() * 2); + + for (auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!collision.isSelected()) { + filter(0, 0, 0); + continue; + } + + int nee_uls = 0; + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + std::vector posTracks_per_coll; + std::vector negTracks_per_coll; + posTracks_per_coll.reserve(trackIdsThisCollision.size()); + negTracks_per_coll.reserve(trackIdsThisCollision.size()); + + for (auto& trackId : trackIdsThisCollision) { + auto track = trackId.template track_as(); + if (!checkTrack(collision, track) || !isElectron(track)) { + continue; + } + + if (track.sign() > 0) { + posTracks_per_coll.emplace_back(track); + } else { + negTracks_per_coll.emplace_back(track); + } + } // end of track loop + + for (auto& pos : posTracks_per_coll) { + for (auto& ele : negTracks_per_coll) { + + auto pos_prop = propagateTrack(collision, pos); + auto ele_prop = propagateTrack(collision, ele); + + std::array pVec_pos = {0, 0, 0}; // px, py, pz + getPxPyPz(pos_prop, pVec_pos); + std::array pVec_ele = {0, 0, 0}; // px, py, pz + getPxPyPz(ele_prop, pVec_ele); + + ROOT::Math::PtEtaPhiMVector v1(pos_prop.getPt(), pos_prop.getEta(), pos_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele_prop.getPt(), ele_prop.getEta(), ele_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pVec_pos[0], pVec_pos[1], pVec_pos[2], pVec_ele[0], pVec_ele[1], pVec_ele[2], pos.sign(), ele.sign(), d_bz); + + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/uls/hM"), v12.M()); + fRegistry.fill(HIST("Pair/before/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/before/hMvsPhiV"), phiv, v12.M()); + } + if (apply_phiv ? (v12.M() < maxMee && slope * phiv + intercept < v12.M()) : (v12.M() < maxMee)) { + fillTrackTable(collision, pos); + fillTrackTable(collision, ele); + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/after/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/after/hMvsPhiV"), phiv, v12.M()); + } + nee_uls++; + } + + } // end of negative track loop + } // end of postive track loop + + if (fillQAHistogram) { + for (auto& pos1 : posTracks_per_coll) { + for (auto& pos2 : posTracks_per_coll) { + if (pos1.globalIndex() == pos2.globalIndex()) { + continue; + } + + auto pos1_prop = propagateTrack(collision, pos1); + auto pos2_prop = propagateTrack(collision, pos2); + + std::array pVec_pos1 = {0, 0, 0}; // px, py, pz + getPxPyPz(pos1_prop, pVec_pos1); + std::array pVec_pos2 = {0, 0, 0}; // px, py, pz + getPxPyPz(pos2_prop, pVec_pos2); + + ROOT::Math::PtEtaPhiMVector v1(pos1_prop.getPt(), pos1_prop.getEta(), pos1_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(pos2_prop.getPt(), pos2_prop.getEta(), pos2_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + fRegistry.fill(HIST("Pair/lspp/hM"), v12.M()); + } // end of positive track loop + } // end of postive track loop + + for (auto& ele1 : negTracks_per_coll) { + for (auto& ele2 : negTracks_per_coll) { + if (ele1.globalIndex() == ele2.globalIndex()) { + continue; + } + + auto ele1_prop = propagateTrack(collision, ele1); + auto ele2_prop = propagateTrack(collision, ele2); + + std::array pVec_ele1 = {0, 0, 0}; // px, py, pz + getPxPyPz(ele1_prop, pVec_ele1); + std::array pVec_ele2 = {0, 0, 0}; // px, py, pz + getPxPyPz(ele2_prop, pVec_ele2); + + ROOT::Math::PtEtaPhiMVector v1(ele1_prop.getPt(), ele1_prop.getEta(), ele1_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele2_prop.getPt(), ele2_prop.getEta(), ele2_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + fRegistry.fill(HIST("Pair/lsmm/hM"), v12.M()); + } // end of negative track loop + } // end of negative track loop + } + + if (nee_uls < 1) { + filter(nee_uls, 0, 0); + continue; + } + + filter(nee_uls, 0, 0); + + posTracks_per_coll.clear(); + negTracks_per_coll.clear(); + posTracks_per_coll.shrink_to_fit(); + negTracks_per_coll.shrink_to_fit(); + + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + // stored_pairIds.clear(); + // stored_pairIds.shrink_to_fit(); + } + PROCESS_SWITCH(filterDielectronEvent, processRec_TTCA, "process reconstructed info only", false); // with TTCA + + // ---------- for data ---------- + + void processRec_SA_SWT(MyCollisionsWithSWT const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const&) + { + stored_trackIds.reserve(posTracks.size() + negTracks.size()); + + for (auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!collision.isSelected()) { + filter(0, 0, 0); + continue; + } + if (collision.swtaliastmp_raw() == 0) { + filter(0, 0, 0); + continue; + } + + int nee_uls = 0; + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + + for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { + if (!checkTrack(collision, pos) || !checkTrack(collision, ele)) { + continue; + } + if (!isElectron(pos) || !isElectron(ele)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pos.px(), pos.py(), pos.pz(), ele.px(), ele.py(), ele.pz(), pos.sign(), ele.sign(), d_bz); + + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/uls/hM"), v12.M()); + fRegistry.fill(HIST("Pair/before/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/before/hMvsPhiV"), phiv, v12.M()); + } + if (apply_phiv ? (v12.M() < maxMee && slope * phiv + intercept < v12.M()) : (v12.M() < maxMee)) { + fillTrackTable(collision, pos); + fillTrackTable(collision, ele); + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/after/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/after/hMvsPhiV"), phiv, v12.M()); + } + nee_uls++; + } + + } // end of pairing loop + + if (fillQAHistogram) { + for (auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { + if (!checkTrack(collision, pos1) || !checkTrack(collision, pos2)) { + continue; + } + if (!isElectron(pos1) || !isElectron(pos2)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(pos1.pt(), pos1.eta(), pos1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + fRegistry.fill(HIST("Pair/lspp/hM"), v12.M()); + } // end of pairing loop + + for (auto& [ele1, ele2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { + if (!checkTrack(collision, ele1) || !checkTrack(collision, ele2)) { + continue; + } + if (!isElectron(ele1) || !isElectron(ele2)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(ele1.pt(), ele1.eta(), ele1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + fRegistry.fill(HIST("Pair/lsmm/hM"), v12.M()); + } // end of pairing loop + } + + if (nee_uls < 1) { + filter(nee_uls, 0, 0); + continue; + } + filter(nee_uls, 0, 0); + + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + // stored_pairIds.clear(); + // stored_pairIds.shrink_to_fit(); + } + PROCESS_SWITCH(filterDielectronEvent, processRec_SA_SWT, "process reconstructed info only", false); // standalone + + void processRec_TTCA_SWT(MyCollisionsWithSWT const& collisions, aod::BCsWithTimestamps const&, MyTracks const& tracks, aod::TrackAssoc const& trackIndices) + { + stored_trackIds.reserve(tracks.size() * 2); + + for (auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!collision.isSelected()) { + filter(0, 0, 0); + continue; + } + if (collision.swtaliastmp_raw() == 0) { + filter(0, 0, 0); + continue; + } + + int nee_uls = 0; + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + std::vector posTracks_per_coll; + std::vector negTracks_per_coll; + posTracks_per_coll.reserve(trackIdsThisCollision.size()); + negTracks_per_coll.reserve(trackIdsThisCollision.size()); + + for (auto& trackId : trackIdsThisCollision) { + auto track = trackId.template track_as(); + if (!checkTrack(collision, track) || !isElectron(track)) { + continue; + } + + if (track.sign() > 0) { + posTracks_per_coll.emplace_back(track); + } else { + negTracks_per_coll.emplace_back(track); + } + } // end of track loop + + for (auto& pos : posTracks_per_coll) { + for (auto& ele : negTracks_per_coll) { + + auto pos_prop = propagateTrack(collision, pos); + auto ele_prop = propagateTrack(collision, ele); + + std::array pVec_pos = {0, 0, 0}; // px, py, pz + getPxPyPz(pos_prop, pVec_pos); + std::array pVec_ele = {0, 0, 0}; // px, py, pz + getPxPyPz(ele_prop, pVec_ele); + + ROOT::Math::PtEtaPhiMVector v1(pos_prop.getPt(), pos_prop.getEta(), pos_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele_prop.getPt(), ele_prop.getEta(), ele_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pVec_pos[0], pVec_pos[1], pVec_pos[2], pVec_ele[0], pVec_ele[1], pVec_ele[2], pos.sign(), ele.sign(), d_bz); + + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/uls/hM"), v12.M()); + fRegistry.fill(HIST("Pair/before/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/before/hMvsPhiV"), phiv, v12.M()); + } + if (apply_phiv ? (v12.M() < maxMee && slope * phiv + intercept < v12.M()) : (v12.M() < maxMee)) { + fillTrackTable(collision, pos); + fillTrackTable(collision, ele); + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/after/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/after/hMvsPhiV"), phiv, v12.M()); + } + nee_uls++; + } + + } // end of negative track loop + } // end of postive track loop + + if (fillQAHistogram) { + for (auto& pos1 : posTracks_per_coll) { + for (auto& pos2 : posTracks_per_coll) { + if (pos1.globalIndex() == pos2.globalIndex()) { + continue; + } + + auto pos1_prop = propagateTrack(collision, pos1); + auto pos2_prop = propagateTrack(collision, pos2); + + std::array pVec_pos1 = {0, 0, 0}; // px, py, pz + getPxPyPz(pos1_prop, pVec_pos1); + std::array pVec_pos2 = {0, 0, 0}; // px, py, pz + getPxPyPz(pos2_prop, pVec_pos2); + + ROOT::Math::PtEtaPhiMVector v1(pos1_prop.getPt(), pos1_prop.getEta(), pos1_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(pos2_prop.getPt(), pos2_prop.getEta(), pos2_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + fRegistry.fill(HIST("Pair/lspp/hM"), v12.M()); + } // end of positive track loop + } // end of postive track loop + + for (auto& ele1 : negTracks_per_coll) { + for (auto& ele2 : negTracks_per_coll) { + if (ele1.globalIndex() == ele2.globalIndex()) { + continue; + } + + auto ele1_prop = propagateTrack(collision, ele1); + auto ele2_prop = propagateTrack(collision, ele2); + + std::array pVec_ele1 = {0, 0, 0}; // px, py, pz + getPxPyPz(ele1_prop, pVec_ele1); + std::array pVec_ele2 = {0, 0, 0}; // px, py, pz + getPxPyPz(ele2_prop, pVec_ele2); + + ROOT::Math::PtEtaPhiMVector v1(ele1_prop.getPt(), ele1_prop.getEta(), ele1_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele2_prop.getPt(), ele2_prop.getEta(), ele2_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + fRegistry.fill(HIST("Pair/lsmm/hM"), v12.M()); + } // end of negative track loop + } // end of negative track loop + } + + if (nee_uls < 1) { + filter(nee_uls, 0, 0); + continue; + } + + filter(nee_uls, 0, 0); + + posTracks_per_coll.clear(); + negTracks_per_coll.clear(); + posTracks_per_coll.shrink_to_fit(); + negTracks_per_coll.shrink_to_fit(); + + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + // stored_pairIds.clear(); + // stored_pairIds.shrink_to_fit(); + } + PROCESS_SWITCH(filterDielectronEvent, processRec_TTCA_SWT, "process reconstructed info only", false); // with TTCA + + // ---------- for MC ---------- + + using MyFilteredTracksMC = soa::Filtered; + Partition posTracksMC = o2::aod::track::signed1Pt > 0.f; + Partition negTracksMC = o2::aod::track::signed1Pt < 0.f; + void processMC_SA(soa::Join const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyFilteredTracksMC const& tracks) + { + stored_trackIds.reserve(tracks.size()); + + for (auto& collision : collisions) { + if (!collision.has_mcCollision()) { + continue; + } + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!collision.isSelected()) { + filter(0, 0, 0); + continue; + } + + int nee_uls = 0; + auto posTracks_per_coll = posTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + + for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { + if (!checkTrack(collision, pos) || !checkTrack(collision, ele)) { + continue; + } + if (!isElectron(pos) || !isElectron(ele)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pos.px(), pos.py(), pos.pz(), ele.px(), ele.py(), ele.pz(), pos.sign(), ele.sign(), d_bz); + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/uls/hM"), v12.M()); + fRegistry.fill(HIST("Pair/before/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/before/hMvsPhiV"), phiv, v12.M()); + } + if (apply_phiv ? (v12.M() < maxMee && slope * phiv + intercept < v12.M()) : (v12.M() < maxMee)) { + fillTrackTable(collision, pos); + fillTrackTable(collision, ele); + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/after/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/after/hMvsPhiV"), phiv, v12.M()); + } + nee_uls++; + } + + } // end of pairing loop + + if (fillQAHistogram) { + for (auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { + if (!checkTrack(collision, pos1) || !checkTrack(collision, pos2)) { + continue; + } + if (!isElectron(pos1) || !isElectron(pos2)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(pos1.pt(), pos1.eta(), pos1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + fRegistry.fill(HIST("Pair/lspp/hM"), v12.M()); + } // end of pairing loop + + for (auto& [ele1, ele2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { + if (!checkTrack(collision, ele1) || !checkTrack(collision, ele2)) { + continue; + } + if (!isElectron(ele1) || !isElectron(ele2)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(ele1.pt(), ele1.eta(), ele1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + fRegistry.fill(HIST("Pair/lsmm/hM"), v12.M()); + } // end of pairing loop + } + + if (nee_uls < 1) { + filter(nee_uls, 0, 0); + continue; + } + filter(nee_uls, 0, 0); + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + // stored_pairIds.clear(); + // stored_pairIds.shrink_to_fit(); + } + PROCESS_SWITCH(filterDielectronEvent, processMC_SA, "process reconstructed and MC info ", false); + + void processMC_TTCA(soa::Join const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyTracksMC const& tracks, aod::TrackAssoc const& trackIndices) + { + stored_trackIds.reserve(tracks.size() * 2); + + for (auto& collision : collisions) { + if (!collision.has_mcCollision()) { + continue; + } + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!collision.isSelected()) { + filter(0, 0, 0); + continue; + } + + int nee_uls = 0; + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + std::vector posTracks_per_coll; + std::vector negTracks_per_coll; + posTracks_per_coll.reserve(trackIdsThisCollision.size()); + negTracks_per_coll.reserve(trackIdsThisCollision.size()); + + for (auto& trackId : trackIdsThisCollision) { + auto track = trackId.template track_as(); + if (!checkTrack(collision, track) || !isElectron(track)) { + continue; + } + + if (track.sign() > 0) { + posTracks_per_coll.emplace_back(track); + } else { + negTracks_per_coll.emplace_back(track); + } + } // end of track loop + + for (auto& pos : posTracks_per_coll) { + for (auto& ele : negTracks_per_coll) { + auto pos_prop = propagateTrack(collision, pos); + auto ele_prop = propagateTrack(collision, ele); + std::array pVec_pos = {0, 0, 0}; // px, py, pz + getPxPyPz(pos_prop, pVec_pos); + std::array pVec_ele = {0, 0, 0}; // px, py, pz + getPxPyPz(ele_prop, pVec_ele); + + ROOT::Math::PtEtaPhiMVector v1(pos_prop.getPt(), pos_prop.getEta(), pos_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele_prop.getPt(), ele_prop.getEta(), ele_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pVec_pos[0], pVec_pos[1], pVec_pos[2], pVec_ele[0], pVec_ele[1], pVec_ele[2], pos.sign(), ele.sign(), d_bz); + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/uls/hM"), v12.M()); + fRegistry.fill(HIST("Pair/before/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/before/hMvsPhiV"), phiv, v12.M()); + } + if (apply_phiv ? (v12.M() < maxMee && slope * phiv + intercept < v12.M()) : (v12.M() < maxMee)) { + fillTrackTable(collision, pos); + fillTrackTable(collision, ele); + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/after/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/after/hMvsPhiV"), phiv, v12.M()); + } + nee_uls++; + } + + } // end of negative track loop + } // end of postive track loop + + if (fillQAHistogram) { + for (auto& pos1 : posTracks_per_coll) { + for (auto& pos2 : posTracks_per_coll) { + if (pos1.globalIndex() == pos2.globalIndex()) { + continue; + } + + auto pos1_prop = propagateTrack(collision, pos1); + auto pos2_prop = propagateTrack(collision, pos2); + + std::array pVec_pos1 = {0, 0, 0}; // px, py, pz + getPxPyPz(pos1_prop, pVec_pos1); + std::array pVec_pos2 = {0, 0, 0}; // px, py, pz + getPxPyPz(pos2_prop, pVec_pos2); + + ROOT::Math::PtEtaPhiMVector v1(pos1_prop.getPt(), pos1_prop.getEta(), pos1_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(pos2_prop.getPt(), pos2_prop.getEta(), pos2_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + fRegistry.fill(HIST("Pair/lspp/hM"), v12.M()); + } // end of positive track loop + } // end of postive track loop + + for (auto& ele1 : negTracks_per_coll) { + for (auto& ele2 : negTracks_per_coll) { + if (ele1.globalIndex() == ele2.globalIndex()) { + continue; + } + + auto ele1_prop = propagateTrack(collision, ele1); + auto ele2_prop = propagateTrack(collision, ele2); + + std::array pVec_ele1 = {0, 0, 0}; // px, py, pz + getPxPyPz(ele1_prop, pVec_ele1); + std::array pVec_ele2 = {0, 0, 0}; // px, py, pz + getPxPyPz(ele2_prop, pVec_ele2); + + ROOT::Math::PtEtaPhiMVector v1(ele1_prop.getPt(), ele1_prop.getEta(), ele1_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele2_prop.getPt(), ele2_prop.getEta(), ele2_prop.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + fRegistry.fill(HIST("Pair/lsmm/hM"), v12.M()); + } // end of negative track loop + } // end of negative track loop + } + + if (nee_uls < 1) { + filter(nee_uls, 0, 0); + continue; + } + filter(nee_uls, 0, 0); + + posTracks_per_coll.clear(); + negTracks_per_coll.clear(); + posTracks_per_coll.shrink_to_fit(); + negTracks_per_coll.shrink_to_fit(); + + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + // stored_pairIds.clear(); + // stored_pairIds.shrink_to_fit(); + } + PROCESS_SWITCH(filterDielectronEvent, processMC_TTCA, "process reconstructed info only", false); // with TTCA +}; +struct prefilterPrimaryElectron { + using MyCollisions = soa::Join; + using MyCollisionsWithSWT = soa::Join; + + Produces ele_pfb; + + SliceCache cache; + Preslice perCol_track = o2::aod::track::collisionId; + PresliceUnsorted perCol_ele = o2::aod::emprimaryelectron::collisionId; + + // CCDB options + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + + // Operation and minimisation criteria + Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; + + Configurable max_dcaxy{"max_dcaxy", 0.3, "DCAxy To PV for loose track sample"}; + Configurable max_dcaz{"max_dcaz", 0.3, "DCAz To PV for loose track sample"}; + Configurable minpt{"minpt", 0.1, "min pt for track for loose track sample"}; + Configurable maxeta{"maxeta", 0.9, "eta acceptance for loose track sample"}; + Configurable min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable mincrossedrows{"mincrossedrows", 70, "min crossed rows"}; + Configurable max_frac_shared_clusters_tpc{"max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; + Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max chi2/NclsTPC"}; + Configurable maxchi2its{"maxchi2its", 6.0, "max chi2/NclsITS"}; + Configurable min_ncluster_its{"min_ncluster_its", 4, "min ncluster its"}; + Configurable min_ncluster_itsib{"min_ncluster_itsib", 1, "min ncluster itsib"}; + Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -3.0, "min. TPC n sigma for electron inclusion"}; + Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", 3.0, "max. TPC n sigma for electron inclusion"}; + Configurable slope{"slope", 0.0185, "slope for m vs. phiv"}; + Configurable intercept{"intercept", -0.0280, "intercept for m vs. phiv"}; + + Configurable> max_mee_vec{"max_mee_vec", std::vector{0.08, 0.10, 0.12}, "vector fo max mee for prefilter in ULS. Please sort this by increasing order."}; // currently, 3 thoresholds are allowed. + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + int mRunNumber; + float d_bz; + Service ccdb; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + + void init(InitContext&) + { + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + if (!doprocessDummy) { + addHistograms(); + } + } + + void addHistograms() + { + fRegistry.add("Track/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); + fRegistry.add("Track/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {40, -1.0f, 1.0f}}, false); + fRegistry.add("Track/hTPCNsigmaEl", "loose track TPC PID", kTH2F, {{1000, 0.f, 10}, {100, -5, +5}}); + fRegistry.add("Pair/before/uls/hMvsPt", "mass vs. pT;m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{400, 0, 4}, {100, 0, 10}}); + fRegistry.add("Pair/before/uls/hMvsPhiV", "mass vs. phiv;#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0.f, M_PI}, {100, 0, 1.f}}); + fRegistry.addClone("Pair/before/uls/", "Pair/before/lspp/"); + fRegistry.addClone("Pair/before/uls/", "Pair/before/lsmm/"); + fRegistry.addClone("Pair/before/", "Pair/after/"); + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (std::fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + o2::base::Propagator::initFieldFromGRP(&grpmag); + mRunNumber = bc.runNumber(); + return; + } + + auto run3grp_timestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = bc.runNumber(); + } + + o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + + template + bool checkTrack(TCollision const& collision, TTrack const& track) + { + if (!track.hasITS()) { + return false; + } + if (track.itsChi2NCl() > maxchi2its) { + return false; + } + if (track.itsNCls() < min_ncluster_its) { + return false; + } + if (track.itsNClsInnerBarrel() < min_ncluster_itsib) { + return false; + } + + if (!track.hasTPC()) { + return false; + } + if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { + return false; + } + if (track.tpcNClsFound() < min_ncluster_tpc) { + return false; + } + if (track.tpcNClsCrossedRows() < mincrossedrows) { + return false; + } + if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { + return false; + } + if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { + return false; + } + if (track.tpcChi2NCl() > maxchi2its) { + return false; + } + + gpu::gpustd::array dcaInfo; + auto track_par_cov_recalc = getTrackParCov(track); + // std::array pVec_recalc = {0, 0, 0}; // px, py, pz + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, track_par_cov_recalc, 2.f, matCorr, &dcaInfo); + // getPxPyPz(track_par_cov_recalc, pVec_recalc); + + if (std::fabs(dcaInfo[0]) > max_dcaxy || std::fabs(dcaInfo[1]) > max_dcaz) { + return false; + } + + if (track_par_cov_recalc.getPt() < minpt || std::fabs(track_par_cov_recalc.getEta()) > maxeta) { + return false; + } + + return true; + } + + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + + Filter trackFilter = o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true; + using MyFilteredTracks = soa::Filtered; + Partition posTracks = o2::aod::track::signed1Pt > 0.f; + Partition negTracks = o2::aod::track::signed1Pt < 0.f; + + Partition positrons = o2::aod::emprimaryelectron::sign > int8_t(0); + Partition electrons = o2::aod::emprimaryelectron::sign < int8_t(0); + void processSA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const&, aod::EMPrimaryElectrons const& primaryelectrons) + { + std::unordered_map pfb_map; // map track.globalIndex -> prefilter bit + + for (auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + if (!collision.isSelected()) { + continue; + } + + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); // loose track sample + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); // loose track sample + + auto positrons_per_coll = positrons->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache); // signal sample + auto electrons_per_coll = electrons->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache); // signal sample + + for (auto& pos : posTracks_per_coll) { + if (!checkTrack(collision, pos)) { // track cut is applied to loose sample + continue; + } + fRegistry.fill(HIST("Track/hPt"), pos.pt()); + fRegistry.fill(HIST("Track/hEtaPhi"), pos.phi(), pos.eta()); + } + for (auto& neg : negTracks_per_coll) { + if (!checkTrack(collision, neg)) { // track cut is applied to loose sample + continue; + } + fRegistry.fill(HIST("Track/hPt"), neg.pt()); + fRegistry.fill(HIST("Track/hEtaPhi"), neg.phi(), neg.eta()); + } + + for (auto& [ele, empos] : combinations(CombinationsFullIndexPolicy(negTracks_per_coll, positrons_per_coll))) { + // auto pos = tracks.rawIteratorAt(empos.trackId()); // use rawIterator, if the table is filtered. + if (!checkTrack(collision, ele)) { // track cut is applied to loose sample + continue; + } + if (empos.trackId() == ele.globalIndex()) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); // loose track + ROOT::Math::PtEtaPhiMVector v2(empos.pt(), empos.eta(), empos.phi(), o2::constants::physics::MassElectron); // signal track + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(empos.px(), empos.py(), empos.pz(), ele.px(), ele.py(), ele.pz(), empos.sign(), ele.sign(), d_bz); + fRegistry.fill(HIST("Pair/before/uls/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/before/uls/hMvsPt"), v12.M(), v12.Pt()); + if (v12.M() < max_mee_vec->at(static_cast(max_mee_vec->size()) - 1)) { + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), ele.tpcInnerParam(), ele.tpcNSigmaEl()); + } + for (int i = 0; i < static_cast(max_mee_vec->size()); i++) { + if (v12.M() < max_mee_vec->at(i)) { + pfb_map[empos.globalIndex()] |= (uint8_t(1) << (static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_1) + i)); + } + } + + if (v12.M() < slope * phiv + intercept) { + pfb_map[empos.globalIndex()] |= (uint8_t(1) << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPC)); + } + + } // end of ULS pairing + + for (auto& [pos, emele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, electrons_per_coll))) { + // auto ele = tracks.rawIteratorAt(emele.trackId()); // use rawIterator, if the table is filtered. + if (!checkTrack(collision, pos)) { // track cut is applied to loose sample + continue; + } + if (emele.trackId() == pos.globalIndex()) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(emele.pt(), emele.eta(), emele.phi(), o2::constants::physics::MassElectron); // signal track + ROOT::Math::PtEtaPhiMVector v2(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); // loose track + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pos.px(), pos.py(), pos.pz(), emele.px(), emele.py(), emele.pz(), pos.sign(), emele.sign(), d_bz); + fRegistry.fill(HIST("Pair/before/uls/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/before/uls/hMvsPt"), v12.M(), v12.Pt()); + if (v12.M() < max_mee_vec->at(static_cast(max_mee_vec->size()) - 1)) { + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), pos.tpcInnerParam(), pos.tpcNSigmaEl()); + } + for (int i = 0; i < static_cast(max_mee_vec->size()); i++) { + if (v12.M() < max_mee_vec->at(i)) { + pfb_map[emele.globalIndex()] |= (uint8_t(1) << (static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_1) + i)); + } + } + + if (v12.M() < slope * phiv + intercept) { + pfb_map[emele.globalIndex()] |= (uint8_t(1) << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPC)); + } + + } // end of ULS pairing + + for (auto& [pos, empos] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, positrons_per_coll))) { + // auto pos = tracks.rawIteratorAt(empos.trackId()); // use rawIterator, if the table is filtered. + if (!checkTrack(collision, pos)) { // track cut is applied to loose sample + continue; + } + if (empos.trackId() == pos.globalIndex()) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); // loose track + ROOT::Math::PtEtaPhiMVector v2(empos.pt(), empos.eta(), empos.phi(), o2::constants::physics::MassElectron); // signal track + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(empos.px(), empos.py(), empos.pz(), pos.px(), pos.py(), pos.pz(), empos.sign(), pos.sign(), d_bz); + fRegistry.fill(HIST("Pair/before/lspp/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/before/lspp/hMvsPt"), v12.M(), v12.Pt()); + } // end of LS++ pairing + + for (auto& [ele, emele] : combinations(CombinationsFullIndexPolicy(negTracks_per_coll, electrons_per_coll))) { + // auto ele = tracks.rawIteratorAt(emele.trackId()); // use rawIterator, if the table is filtered. + if (!checkTrack(collision, ele)) { // track cut is applied to loose sample + continue; + } + if (emele.trackId() == ele.globalIndex()) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); // loose track + ROOT::Math::PtEtaPhiMVector v2(emele.pt(), emele.eta(), emele.phi(), o2::constants::physics::MassElectron); // signal track + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(emele.px(), emele.py(), emele.pz(), ele.px(), ele.py(), ele.pz(), emele.sign(), ele.sign(), d_bz); + fRegistry.fill(HIST("Pair/before/lsmm/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/before/lsmm/hMvsPt"), v12.M(), v12.Pt()); + } // end of LS-- pairing + + } // end of collision loop + + for (auto& ele : primaryelectrons) { + ele_pfb(pfb_map[ele.globalIndex()]); + } + + // check prefilter + for (auto& collision : collisions) { + auto positrons_per_coll = positrons->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache); // signal sample + auto electrons_per_coll = electrons->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache); // signal sample + + for (auto& [ele, pos] : combinations(CombinationsFullIndexPolicy(electrons_per_coll, positrons_per_coll))) { + if (pfb_map[ele.globalIndex()] != 0 || pfb_map[pos.globalIndex()] != 0) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pos.px(), pos.py(), pos.pz(), ele.px(), ele.py(), ele.pz(), pos.sign(), ele.sign(), d_bz); + fRegistry.fill(HIST("Pair/after/uls/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/after/uls/hMvsPt"), v12.M(), v12.Pt()); + } // end of ULS pairing + } // end of collision loop + + pfb_map.clear(); + } + PROCESS_SWITCH(prefilterPrimaryElectron, processSA, "process SA", false); + + void processDummy(aod::EMPrimaryElectrons const& primaryelectrons) + { + for (int i = 0; i < primaryelectrons.size(); i++) { + ele_pfb(0); + } + } + PROCESS_SWITCH(prefilterPrimaryElectron, processDummy, "processDummy", true); +}; +struct associateAmbiguousElectron { + Produces em_amb_ele_ids; + + SliceCache cache; + PresliceUnsorted perTrack = o2::aod::emprimaryelectron::trackId; + std::vector ambele_self_Ids; + + void process(aod::EMPrimaryElectrons const& electrons) + { + for (auto& electron : electrons) { + auto electrons_with_same_trackId = electrons.sliceBy(perTrack, electron.trackId()); + ambele_self_Ids.reserve(electrons_with_same_trackId.size()); + for (auto& amb_ele : electrons_with_same_trackId) { + if (amb_ele.globalIndex() == electron.globalIndex()) { // don't store myself. + continue; + } + ambele_self_Ids.emplace_back(amb_ele.globalIndex()); + } + em_amb_ele_ids(ambele_self_Ids); + ambele_self_Ids.clear(); + ambele_self_Ids.shrink_to_fit(); + } + } +}; +struct createEMEvent2VP { + using MyBCs = soa::Join; + using MyQvectors = soa::Join; + + using MyCollisions = soa::Join; + using MyCollisions_Cent = soa::Join; // centrality table has dependency on multiplicity table. + using MyCollisions_Cent_Qvec = soa::Join; + + using MyCollisionsWithSWT = soa::Join; + using MyCollisionsWithSWT_Cent = soa::Join; // centrality table has dependency on multiplicity table. + using MyCollisionsWithSWT_Cent_Qvec = soa::Join; + + using MyCollisionsMC = soa::Join; + using MyCollisionsMC_Cent = soa::Join; // centrality table has dependency on multiplicity table. + using MyCollisionsMC_Cent_Qvec = soa::Join; + + Produces event; + // Produces eventcov; + Produces event_mult; + Produces event_cent; + Produces event_qvec; + Produces emswtbit; + + enum class EMEventType : int { + kEvent = 0, + kEvent_Cent = 1, + kEvent_Cent_Qvec = 2, + }; + + HistogramRegistry registry{"registry"}; + void init(o2::framework::InitContext&) + { + auto hEventCounter = registry.add("hEventCounter", "hEventCounter", kTH1I, {{7, 0.5f, 7.5f}}); + hEventCounter->GetXaxis()->SetBinLabel(1, "all"); + hEventCounter->GetXaxis()->SetBinLabel(2, "sel8"); + + registry.add("hNInspectedTVX", "N inspected TVX;run number;N_{TVX}", kTProfile, {{80000, 520000.5, 600000.5}}, true); + } + + ~createEMEvent2VP() + { + swt_names.clear(); + swt_names.shrink_to_fit(); + } + + std::vector mTOIidx; + std::vector swt_names; + uint64_t mNinspectedTVX{0}; + + int mRunNumber; + + template + void skimEvent(TCollisions const& collisions, TBCs const&) + { + for (auto& collision : collisions) { + if constexpr (isMC) { + if (!collision.has_mcCollision()) { + continue; + } + } + + if constexpr (isTriggerAnalysis) { + if (collision.swtaliastmp_raw() == 0) { + continue; + } + } + + auto bc = collision.template foundBC_as(); + + if (!collision.isSelected()) { + continue; + } + + if (!(collision.neeuls() >= 1 || collision.neeuls() + collision.ngpcm() >= 2)) { + continue; + } + + if constexpr (isTriggerAnalysis) { + emswtbit(collision.swtaliastmp_raw(), collision.nInspectedTVX()); + } + + // LOGF(info, "collision.neeuls() = %d, collision.ngpcm() = %d", collision.neeuls(), collision.ngpcm()); + // LOGF(info, "collision.multNTracksPV() = %d, collision.multFT0A() = %f, collision.multFT0C() = %f", collision.multNTracksPV(), collision.multFT0A(), collision.multFT0C()); + + registry.fill(HIST("hEventCounter"), 1); + + event(collision.globalIndex(), bc.runNumber(), bc.globalBC(), collision.alias_raw(), collision.selection_raw(), collision.rct_raw(), bc.timestamp(), + collision.posX(), collision.posY(), collision.posZ(), + collision.numContrib(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + + // eventcov(collision.covXX(), collision.covXY(), collision.covXZ(), collision.covYY(), collision.covYZ(), collision.covZZ(), collision.chi2()); + + event_mult(collision.multFT0A(), collision.multFT0C(), collision.multNTracksPV(), collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf()); + + if constexpr (eventype == EMEventType::kEvent) { + event_cent(105.f, 105.f, 105.f); + event_qvec( + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f); + } else if constexpr (eventype == EMEventType::kEvent_Cent) { + event_cent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C()); + event_qvec( + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f); + } else if constexpr (eventype == EMEventType::kEvent_Cent_Qvec) { + event_cent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C()); + float q2xft0m = 999.f, q2yft0m = 999.f, q2xft0a = 999.f, q2yft0a = 999.f, q2xft0c = 999.f, q2yft0c = 999.f, q2xbpos = 999.f, q2ybpos = 999.f, q2xbneg = 999.f, q2ybneg = 999.f, q2xbtot = 999.f, q2ybtot = 999.f; + float q3xft0m = 999.f, q3yft0m = 999.f, q3xft0a = 999.f, q3yft0a = 999.f, q3xft0c = 999.f, q3yft0c = 999.f, q3xbpos = 999.f, q3ybpos = 999.f, q3xbneg = 999.f, q3ybneg = 999.f, q3xbtot = 999.f, q3ybtot = 999.f; + + if (collision.qvecFT0CReVec().size() >= 2) { // harmonics 2,3 + q2xft0m = collision.qvecFT0MReVec()[0], q2xft0a = collision.qvecFT0AReVec()[0], q2xft0c = collision.qvecFT0CReVec()[0], q2xbpos = collision.qvecBPosReVec()[0], q2xbneg = collision.qvecBNegReVec()[0], q2xbtot = collision.qvecBTotReVec()[0]; + q2yft0m = collision.qvecFT0MImVec()[0], q2yft0a = collision.qvecFT0AImVec()[0], q2yft0c = collision.qvecFT0CImVec()[0], q2ybpos = collision.qvecBPosImVec()[0], q2ybneg = collision.qvecBNegImVec()[0], q2ybtot = collision.qvecBTotImVec()[0]; + q3xft0m = collision.qvecFT0MReVec()[1], q3xft0a = collision.qvecFT0AReVec()[1], q3xft0c = collision.qvecFT0CReVec()[1], q3xbpos = collision.qvecBPosReVec()[1], q3xbneg = collision.qvecBNegReVec()[1], q3xbtot = collision.qvecBTotReVec()[1]; + q3yft0m = collision.qvecFT0MImVec()[1], q3yft0a = collision.qvecFT0AImVec()[1], q3yft0c = collision.qvecFT0CImVec()[1], q3ybpos = collision.qvecBPosImVec()[1], q3ybneg = collision.qvecBNegImVec()[1], q3ybtot = collision.qvecBTotImVec()[1]; + } else if (collision.qvecFT0CReVec().size() >= 1) { // harmonics 2 + q2xft0m = collision.qvecFT0MReVec()[0], q2xft0a = collision.qvecFT0AReVec()[0], q2xft0c = collision.qvecFT0CReVec()[0], q2xbpos = collision.qvecBPosReVec()[0], q2xbneg = collision.qvecBNegReVec()[0], q2xbtot = collision.qvecBTotReVec()[0]; + q2yft0m = collision.qvecFT0MImVec()[0], q2yft0a = collision.qvecFT0AImVec()[0], q2yft0c = collision.qvecFT0CImVec()[0], q2ybpos = collision.qvecBPosImVec()[0], q2ybneg = collision.qvecBNegImVec()[0], q2ybtot = collision.qvecBTotImVec()[0]; + } + event_qvec( + q2xft0m, q2yft0m, q2xft0a, q2yft0a, q2xft0c, q2yft0c, q2xbpos, q2ybpos, q2xbneg, q2ybneg, q2xbtot, q2ybtot, + q3xft0m, q3yft0m, q3xft0a, q3yft0a, q3xft0c, q3yft0c, q3xbpos, q3ybpos, q3xbneg, q3ybneg, q3xbtot, q3ybtot); + } else { + event_cent(105.f, 105.f, 105.f); + event_qvec( + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, + 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f); + } + } // end of collision loop + } // end of skimEvent + + void processEvent(MyCollisions const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(createEMEvent2VP, processEvent, "process event info", false); + + void processEvent_Cent(MyCollisions_Cent const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(createEMEvent2VP, processEvent_Cent, "process event info", false); + + void processEvent_Cent_Qvec(MyCollisions_Cent_Qvec const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(createEMEvent2VP, processEvent_Cent_Qvec, "process event info", false); + + void processEvent_SWT(MyCollisionsWithSWT const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(createEMEvent2VP, processEvent_SWT, "process event info", false); + + void processEvent_SWT_Cent(MyCollisionsWithSWT_Cent const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(createEMEvent2VP, processEvent_SWT_Cent, "process event info", false); + + void processEvent_SWT_Cent_Qvec(MyCollisionsWithSWT_Cent_Qvec const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(createEMEvent2VP, processEvent_SWT_Cent_Qvec, "process event info", false); + + void processEventMC(MyCollisionsMC const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(createEMEvent2VP, processEventMC, "process event info", false); + + void processEventMC_Cent(MyCollisionsMC_Cent const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(createEMEvent2VP, processEventMC_Cent, "process event info", false); + + void processEventMC_Cent_Qvec(MyCollisionsMC_Cent_Qvec const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(createEMEvent2VP, processEventMC_Cent_Qvec, "process event info", false); + + void processDummy(aod::Collisions const&) {} + PROCESS_SWITCH(createEMEvent2VP, processDummy, "processDummy", true); +}; +struct AssociateDileptonToEMEvent2VP { + Produces v0kfeventid; + Produces prmeleventid; + + Preslice perCollision_pcm = aod::v0photonkf::collisionId; + PresliceUnsorted perCollision_el = aod::emprimaryelectron::collisionId; + + void init(o2::framework::InitContext&) {} + + template + void fillEventId(TCollisions const& collisions, TLeptons const& leptons, TEventIds& eventIds, TPreslice const& perCollision) + { + for (auto& collision : collisions) { + auto leptons_coll = leptons.sliceBy(perCollision, collision.collisionId()); + int nl = leptons_coll.size(); + // LOGF(info, "collision.collisionId() = %d , nl = %d", collision.collisionId(), nl); + for (int il = 0; il < nl; il++) { + eventIds(collision.globalIndex()); + } // end of photon loop + } // end of collision loop + } + + // This struct is for both data and MC. + // Note that reconstructed collisions without mc collisions are already rejected in CreateEMEventDilepton in MC. + + void processPCM(aod::EMEvents const& collisions, aod::V0PhotonsKF const& photons) + { + fillEventId(collisions, photons, v0kfeventid, perCollision_pcm); + } + + void processElectron(aod::EMEvents const& collisions, aod::EMPrimaryElectrons const& tracks) + { + fillEventId(collisions, tracks, prmeleventid, perCollision_el); + } + + void processDummy(aod::EMEvents const&) {} + + PROCESS_SWITCH(AssociateDileptonToEMEvent2VP, processPCM, "process pcm-event indexing", false); + PROCESS_SWITCH(AssociateDileptonToEMEvent2VP, processElectron, "process dalitzee-event indexing", false); + PROCESS_SWITCH(AssociateDileptonToEMEvent2VP, processDummy, "process dummy", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"filter-dielectron-event"}), + adaptAnalysisTask(cfgc, TaskName{"prefilter-primary-electron"}), + adaptAnalysisTask(cfgc, TaskName{"associate-ambiguous-electron"}), + adaptAnalysisTask(cfgc, TaskName{"create-emevent-2vp"}), + adaptAnalysisTask(cfgc, TaskName{"associate-dilepton-to-emevent2VP"}), + }; +} diff --git a/PWGEM/Dilepton/TableProducer/filterEoI.cxx b/PWGEM/Dilepton/TableProducer/filterEoI.cxx new file mode 100644 index 00000000000..9edaeb784dc --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/filterEoI.cxx @@ -0,0 +1,119 @@ +// 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. +// +// ======================== +// +// This code filters events that are interesting for dilepton analyses. +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct filterEoI { + enum SubSystem { + kElectron = 0x1, + kFwdMuon = 0x2, + }; + Produces emeoi; + + HistogramRegistry fRegistry{"output"}; + void init(o2::framework::InitContext&) + { + auto hEventCounter = fRegistry.add("hEventCounter", "hEventCounter", kTH1D, {{5, 0.5f, 5.5f}}); + hEventCounter->GetXaxis()->SetBinLabel(1, "all"); + hEventCounter->GetXaxis()->SetBinLabel(2, "event with electron"); + hEventCounter->GetXaxis()->SetBinLabel(3, "event with forward muon"); + hEventCounter->GetXaxis()->SetBinLabel(4, "event with electron or forward muon"); + hEventCounter->GetXaxis()->SetBinLabel(5, "event with electron and forward muon"); + } + + SliceCache cache; + Preslice perCollision_el = aod::emprimaryelectron::collisionId; + Preslice perCollision_mu = aod::emprimarymuon::collisionId; + + template + void selectEoI(TCollisions const& collisions, TElectrons const& electrons, TMuons const& muons) + { + for (const auto& collision : collisions) { + bool does_electron_exist = false; + bool does_fwdmuon_exist = false; + fRegistry.fill(HIST("hEventCounter"), 1); + + if constexpr (static_cast(system & kElectron)) { + auto electrons_coll = electrons.sliceBy(perCollision_el, collision.globalIndex()); + if (electrons_coll.size() > 0) { + does_electron_exist = true; + fRegistry.fill(HIST("hEventCounter"), 2); + } + } + if constexpr (static_cast(system & kFwdMuon)) { + auto muons_coll = muons.sliceBy(perCollision_mu, collision.globalIndex()); + if (muons_coll.size() > 0) { + does_fwdmuon_exist = true; + fRegistry.fill(HIST("hEventCounter"), 3); + } + } + + if (does_electron_exist || does_fwdmuon_exist) { + fRegistry.fill(HIST("hEventCounter"), 4); + } + if (does_electron_exist && does_fwdmuon_exist) { + fRegistry.fill(HIST("hEventCounter"), 5); + } + + emeoi(does_electron_exist || does_fwdmuon_exist); + + } // end of collision loop + + } // end of selectEoI + + void process_Electron(aod::Collisions const& collisions, aod::EMPrimaryElectrons const& electrons) + { + const uint8_t sysflag = kElectron; + selectEoI(collisions, electrons, nullptr); + } + + void process_FwdMuon(aod::Collisions const& collisions, aod::EMPrimaryMuons const& muons) + { + const uint8_t sysflag = kFwdMuon; + selectEoI(collisions, nullptr, muons); + } + + void process_Electron_FwdMuon(aod::Collisions const& collisions, aod::EMPrimaryElectrons const& electrons, aod::EMPrimaryMuons const& muons) + { + const uint8_t sysflag = kElectron | kFwdMuon; + selectEoI(collisions, electrons, muons); + } + + void processDummy(aod::Collisions const& collisions) + { + for (int i = 0; i < collisions.size(); i++) { + emeoi(true); + } + } + + PROCESS_SWITCH(filterEoI, process_Electron, "create filter bit for Electron", false); + PROCESS_SWITCH(filterEoI, process_FwdMuon, "create filter bit for Forward Muon", false); + PROCESS_SWITCH(filterEoI, process_Electron_FwdMuon, "create filter bit for Electron, FwdMuon", false); + PROCESS_SWITCH(filterEoI, processDummy, "processDummy", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"filter-eoi"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/skimmerOTS.cxx b/PWGEM/Dilepton/TableProducer/skimmerOTS.cxx new file mode 100644 index 00000000000..3ea6dc842d8 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/skimmerOTS.cxx @@ -0,0 +1,128 @@ +// 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. +// +// ======================== +// +// This code produces trigger information. OTS = offline trigger selection. +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#include "CCDB/BasicCCDBManager.h" +#include "EventFiltering/Zorro.h" +#include "Common/Core/TableHelper.h" + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct skimmerOTS { + Produces swt_tmp; + + // CCDB options + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable cfg_swt_names{"cfg_swt_names", "fHighTrackMult,fHighFt0Mult", "comma-separated software trigger names"}; // !trigger names have to be pre-registered in dileptonTable.h for bit operation! + + std::vector swt_names; + int mRunNumber; + Service ccdb; + + HistogramRegistry registry{"registry"}; + void init(o2::framework::InitContext&) + { + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + LOGF(info, "enable software triggers : %s", cfg_swt_names.value.data()); + std::stringstream tokenizer(cfg_swt_names.value); + std::string token; + while (std::getline(tokenizer, token, ',')) { + swt_names.emplace_back(token); + } + + const int nbin = swt_names.size(); + auto hEventCounter = registry.add("hEventCounter", "hEventCounter;;Number of Events", kTH1D, {{nbin + 1, 0.5f, nbin + 1 + 0.5f}}); + hEventCounter->GetXaxis()->SetBinLabel(1, "all"); + for (int idx = 0; idx < nbin; idx++) { + hEventCounter->GetXaxis()->SetBinLabel(idx + 2, swt_names[idx].data()); + } + + registry.add("hNInspectedTVX", "N inspected TVX;run number;N_{TVX}", kTProfile, {{80000, 520000.5, 600000.5}}, true); + } + + ~skimmerOTS() + { + swt_names.clear(); + swt_names.shrink_to_fit(); + } + + Zorro zorro; + std::vector mTOIidx; + uint64_t mNinspectedTVX{0}; + + template + void initCCDB(TBC const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + mTOIidx = zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), cfg_swt_names.value); + for (auto& idx : mTOIidx) { + LOGF(info, "Trigger of Interest : index = %d", idx); + } + mNinspectedTVX = zorro.getInspectedTVX()->GetBinContent(1); + LOGF(info, "total inspected TVX events = %d in run number %d", mNinspectedTVX, bc.runNumber()); + registry.fill(HIST("hNInspectedTVX"), bc.runNumber(), mNinspectedTVX); + + mRunNumber = bc.runNumber(); + } + + using MyBCs = soa::Join; + using MyCollisions = soa::Join; + + void process(MyCollisions const& collisions, MyBCs const&) + { + for (auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + uint16_t trigger_bitmap = 0; + registry.fill(HIST("hEventCounter"), 1); // all + if (zorro.isSelected(bc.globalBC())) { // triggered event + auto swt_bitset = zorro.getLastResult(); // this has to be called after zorro::isSelected, or simply call zorro.fetch + // LOGF(info, "swt_bitset.to_string().c_str() = %s", swt_bitset.to_string().c_str()); + for (size_t idx = 0; idx < mTOIidx.size(); idx++) { + if (swt_bitset.test(mTOIidx[idx])) { + auto swtname = swt_names[idx]; + trigger_bitmap |= BIT(o2::aod::pwgem::dilepton::swt::aliasLabels.at(swtname)); + // LOGF(info, "swtname = %s is fired. swt index in original swt table = %d, swt index for EM table = %d", swtname.data(), mTOIidx[idx], o2::aod::pwgem::dilepton::swt::aliasLabels.at(swtname)); + registry.fill(HIST("hEventCounter"), idx + 2); // fired trigger + } + } + } + // LOGF(info, "trigger_bitmap = %d, mNinspectedTVX = %d", trigger_bitmap, mNinspectedTVX); + swt_tmp(trigger_bitmap, mNinspectedTVX); + } // end of collision loop + } +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"skimmer-ots"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectron.cxx b/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectron.cxx new file mode 100644 index 00000000000..26b1106448c --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectron.cxx @@ -0,0 +1,1277 @@ +// 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 write relevant information about primary electrons. +/// \author daiki.sekihata@cern.ch + +#include +#include +#include +#include + +#include "Math/Vector4D.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "CCDB/BasicCCDBManager.h" +#include "Common/Core/trackUtilities.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/Core/TableHelper.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +using namespace o2; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +using MyCollisions = soa::Join; +using MyCollisionsWithSWT = soa::Join; + +using MyTracks = soa::Join; +using MyTrack = MyTracks::iterator; +using MyTracksMC = soa::Join; +using MyTrackMC = MyTracksMC::iterator; + +struct skimmerPrimaryElectron { + SliceCache cache; + Preslice perCol = o2::aod::track::collisionId; + Produces emprimaryelectrons; + Produces emprimaryelectronscov; + + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable mVtxPath{"mVtxPath", "GLO/Calib/MeanVertex", "Path of the mean vertex file"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + + // Operation and minimisation criteria + Configurable fillQAHistogram{"fillQAHistogram", false, "flag to fill QA histograms"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + Configurable min_ncluster_tpc{"min_ncluster_tpc", 10, "min ncluster tpc"}; + Configurable mincrossedrows{"mincrossedrows", 70, "min. crossed rows"}; + Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; + Configurable min_ncluster_its{"min_ncluster_its", 4, "min ncluster its"}; + Configurable min_ncluster_itsib{"min_ncluster_itsib", 1, "min ncluster itsib"}; + Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max. chi2/NclsTPC"}; + Configurable maxchi2its{"maxchi2its", 6.0, "max. chi2/NclsITS"}; + Configurable minpt{"minpt", 0.15, "min pt for track"}; + Configurable maxeta{"maxeta", 0.9, "eta acceptance"}; + Configurable dca_xy_max{"dca_xy_max", 0.3f, "max DCAxy in cm"}; + Configurable dca_z_max{"dca_z_max", 0.3f, "max DCAz in cm"}; + Configurable dca_3d_sigma_max{"dca_3d_sigma_max", 1e+10, "max DCA 3D in sigma"}; + Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -2.5, "min. TPC n sigma for electron inclusion"}; + Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", 3.5, "max. TPC n sigma for electron inclusion"}; + Configurable maxTOFNsigmaEl{"maxTOFNsigmaEl", 3.5, "max. TOF n sigma for electron inclusion"}; + Configurable maxTPCNsigmaPi{"maxTPCNsigmaPi", 2.5, "max. TPC n sigma for pion exclusion"}; + Configurable minTPCNsigmaPi{"minTPCNsigmaPi", -1e+10, "min. TPC n sigma for pion exclusion"}; // set to -2 for lowB, -1e+10 for nominalB + Configurable maxTPCNsigmaKa{"maxTPCNsigmaKa", 2.5, "max. TPC n sigma for kaon exclusion"}; + Configurable minTPCNsigmaKa{"minTPCNsigmaKa", -2.5, "min. TPC n sigma for kaon exclusion"}; + Configurable maxTPCNsigmaPr{"maxTPCNsigmaPr", 2.5, "max. TPC n sigma for proton exclusion"}; + Configurable minTPCNsigmaPr{"minTPCNsigmaPr", -2.5, "min. TPC n sigma for proton exclusion"}; + Configurable requireTOF{"requireTOF", false, "require TOF hit"}; + Configurable max_pin_for_pion_rejection{"max_pin_for_pion_rejection", 1e+10, "pion rejection is applied below this pin"}; + Configurable max_frac_shared_clusters_tpc{"max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + int mRunNumber; + float d_bz; + Service ccdb; + // o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + o2::dataformats::VertexBase mVtx; + const o2::dataformats::MeanVertexObject* mMeanVtx = nullptr; + o2::base::MatLayerCylSet* lut = nullptr; + + void init(InitContext&) + { + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + if (fillQAHistogram) { + fRegistry.add("Track/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); + fRegistry.add("Track/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); + fRegistry.add("Track/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {20, -1.0f, 1.0f}}, false); + fRegistry.add("Track/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -1.0f, 1.0f}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("Track/hDCAxyzSigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {{1000, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/hDCAzRes_Pt", "DCA_{z} resolution vs. pT;p_{T} (GeV/c);DCA_{z} resolution (#mum)", kTH2F, {{1000, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/hNclsTPC", "number of TPC clusters", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hNcrTPC", "number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hChi2TOF", "chi2 of TOF", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hTPCNclsShared", "TPC Ncls shared/Ncls;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); + fRegistry.add("Track/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("Track/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("Track/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("Track/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaMu", "TPC n sigma mu;p_{in} (GeV/c);n #sigma_{#mu}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaKa", "TPC n sigma ka;p_{in} (GeV/c);n #sigma_{K}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaPr", "TPC n sigma pr;p_{in} (GeV/c);n #sigma_{p}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFbeta", "TOF beta;p_{pv} (GeV/c);#beta", kTH2F, {{1000, 0, 10}, {240, 0, 1.2}}, false); + fRegistry.add("Track/hTOFNsigmaEl", "TOF n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaMu", "TOF n sigma mu;p_{in} (GeV/c);n #sigma_{#mu}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaPi", "TOF n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaKa", "TOF n sigma ka;p_{in} (GeV/c);n #sigma_{K}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaPr", "TOF n sigma pr;p_{in} (GeV/c);n #sigma_{p}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); on ITS #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); + fRegistry.add("Track/hITSNsigmaEl", "ITS n sigma el;p_{pv} (GeV/c);n #sigma_{e}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hITSNsigmaMu", "ITS n sigma mu;p_{pv} (GeV/c);n #sigma_{#mu}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hITSNsigmaPi", "ITS n sigma pi;p_{pv} (GeV/c);n #sigma_{#pi}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hITSNsigmaKa", "ITS n sigma ka;p_{pv} (GeV/c);n #sigma_{K}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hITSNsigmaPr", "ITS n sigma pr;p_{pv} (GeV/c);n #sigma_{p}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + } + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + // load matLUT for this timestamp + if (!lut) { + LOG(info) << "Loading material look-up table for timestamp: " << bc.timestamp(); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->getForTimeStamp(lutPath, bc.timestamp())); + } else { + LOG(info) << "Material look-up table already in place. Not reloading."; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (std::fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + o2::base::Propagator::initFieldFromGRP(&grpmag); + o2::base::Propagator::Instance()->setMatLUT(lut); + mMeanVtx = ccdb->getForTimeStamp(mVtxPath, bc.timestamp()); + mRunNumber = bc.runNumber(); + return; + } + + auto run3grp_timestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) { + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + } + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + o2::base::Propagator::Instance()->setMatLUT(lut); + mMeanVtx = ccdb->getForTimeStamp(mVtxPath, bc.timestamp()); + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + o2::base::Propagator::Instance()->setMatLUT(lut); + mMeanVtx = ccdb->getForTimeStamp(mVtxPath, bc.timestamp()); + + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = bc.runNumber(); + } + + template + bool checkTrack(TCollision const& collision, TTrack const& track) + { + if constexpr (isMC) { + if (!track.has_mcParticle()) { + return false; + } + } + + if (requireTOF && !(track.hasTOF() && std::fabs(track.tofNSigmaEl()) < maxTOFNsigmaEl)) { + return false; + } + + if (track.tpcChi2NCl() > maxchi2tpc) { + return false; + } + + if (track.itsChi2NCl() > maxchi2its) { + return false; + } + + if (!track.hasITS() || !track.hasTPC()) { + return false; + } + if (track.itsNCls() < min_ncluster_its) { + return false; + } + if (track.itsNClsInnerBarrel() < min_ncluster_itsib) { + return false; + } + + if (track.tpcNClsFound() < min_ncluster_tpc) { + return false; + } + + if (track.tpcNClsCrossedRows() < mincrossedrows) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { + return false; + } + + if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { + return false; + } + + if (track.hasTOF() && (maxTOFNsigmaEl < std::fabs(track.tofNSigmaEl()))) { + return false; + } + + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto track_par_cov_recalc = getTrackParCov(track); + track_par_cov_recalc.setPID(o2::track::PID::Electron); + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, track_par_cov_recalc, 2.f, matCorr, &mDcaInfoCov); + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + + // LOGF(info, "track_par_cov_recalc.getSigmaY2() = %.16f, mDcaInfoCov.getSigmaY2() = %.16f, track_par_cov_recalc.getSigmaZ2() = %.16f, mDcaInfoCov.getSigmaZ2() = %.16f, track_par_cov_recalc.getSigmaZY() = %.16f, mDcaInfoCov.getSigmaYZ() = %.16f", track_par_cov_recalc.getSigmaY2(), mDcaInfoCov.getSigmaY2(), track_par_cov_recalc.getSigmaZ2(), mDcaInfoCov.getSigmaZ2(), track_par_cov_recalc.getSigmaZY(), mDcaInfoCov.getSigmaYZ()); + + if (std::fabs(dcaXY) > dca_xy_max || std::fabs(dcaZ) > dca_z_max) { + return false; + } + + if (track_par_cov_recalc.getPt() < minpt || std::fabs(track_par_cov_recalc.getEta()) > maxeta) { + return false; + } + + float dca_3d = 999.f; + float det = track_par_cov_recalc.getSigmaY2() * track_par_cov_recalc.getSigmaZ2() - track_par_cov_recalc.getSigmaZY() * track_par_cov_recalc.getSigmaZY(); + if (det < 0) { + dca_3d = 999.f; + } else { + float chi2 = (dcaXY * dcaXY * track_par_cov_recalc.getSigmaZ2() + dcaZ * dcaZ * track_par_cov_recalc.getSigmaY2() - 2. * dcaXY * dcaZ * track_par_cov_recalc.getSigmaZY()) / det; + dca_3d = std::sqrt(std::fabs(chi2) / 2.); + } + if (dca_3d > dca_3d_sigma_max) { + return false; + } + + return true; + } + + template + bool isElectron(TTrack const& track) + { + return isElectron_TPChadrej(track) || isElectron_TOFreq(track); + } + + template + bool isElectron_TPChadrej(TTrack const& track) + { + if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { + return false; + } + if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi && track.tpcInnerParam() < max_pin_for_pion_rejection) { + return false; + } + if (minTPCNsigmaKa < track.tpcNSigmaKa() && track.tpcNSigmaKa() < maxTPCNsigmaKa) { + return false; + } + if (minTPCNsigmaPr < track.tpcNSigmaPr() && track.tpcNSigmaPr() < maxTPCNsigmaPr) { + return false; + } + if (track.hasTOF() && (maxTOFNsigmaEl < std::fabs(track.tofNSigmaEl()))) { + return false; + } + return true; + } + + template + bool isElectron_TOFreq(TTrack const& track) + { + if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi && track.tpcInnerParam() < max_pin_for_pion_rejection) { + return false; + } + return minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl && std::fabs(track.tofNSigmaEl()) < maxTOFNsigmaEl; + } + + template + void fillTrackTable(TCollision const& collision, TTrack const& track) + { + if (std::find(stored_trackIds.begin(), stored_trackIds.end(), std::pair{collision.globalIndex(), track.globalIndex()}) == stored_trackIds.end()) { + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto track_par_cov_recalc = getTrackParCov(track); + track_par_cov_recalc.setPID(o2::track::PID::Electron); + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, track_par_cov_recalc, 2.f, matCorr, &mDcaInfoCov); + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + + float pt_recalc = track_par_cov_recalc.getPt(); + float eta_recalc = track_par_cov_recalc.getEta(); + float phi_recalc = track_par_cov_recalc.getPhi(); + + bool isAssociatedToMPC = collision.globalIndex() == track.collisionId(); + + emprimaryelectrons(collision.globalIndex(), track.globalIndex(), track.sign(), + pt_recalc, eta_recalc, phi_recalc, dcaXY, dcaZ, + track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), track.tpcNClsShared(), + track.tpcChi2NCl(), track.tpcInnerParam(), + track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaMu(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), + track.beta(), track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), + track.itsClusterSizes(), track.itsNSigmaEl(), track.itsNSigmaMu(), track.itsNSigmaPi(), track.itsNSigmaKa(), track.itsNSigmaPr(), + track.itsChi2NCl(), track.tofChi2(), track.detectorMap(), + track_par_cov_recalc.getX(), track_par_cov_recalc.getAlpha(), track_par_cov_recalc.getY(), track_par_cov_recalc.getZ(), track_par_cov_recalc.getSnp(), track_par_cov_recalc.getTgl(), isAssociatedToMPC); + + emprimaryelectronscov( + track_par_cov_recalc.getSigmaY2(), + track_par_cov_recalc.getSigmaZY(), + track_par_cov_recalc.getSigmaZ2(), + track_par_cov_recalc.getSigmaSnpY(), + track_par_cov_recalc.getSigmaSnpZ(), + track_par_cov_recalc.getSigmaSnp2(), + track_par_cov_recalc.getSigmaTglY(), + track_par_cov_recalc.getSigmaTglZ(), + track_par_cov_recalc.getSigmaTglSnp(), + track_par_cov_recalc.getSigmaTgl2(), + track_par_cov_recalc.getSigma1PtY(), + track_par_cov_recalc.getSigma1PtZ(), + track_par_cov_recalc.getSigma1PtSnp(), + track_par_cov_recalc.getSigma1PtTgl(), + track_par_cov_recalc.getSigma1Pt2()); + + stored_trackIds.emplace_back(std::pair{collision.globalIndex(), track.globalIndex()}); + + if (fillQAHistogram) { + uint32_t itsClusterSizes = track.itsClusterSizes(); + int total_cluster_size = 0, nl = 0; + for (unsigned int layer = 0; layer < 7; layer++) { + int cluster_size_per_layer = (itsClusterSizes >> (layer * 4)) & 0xf; + if (cluster_size_per_layer > 0) { + nl++; + } + total_cluster_size += cluster_size_per_layer; + } + + fRegistry.fill(HIST("Track/hPt"), pt_recalc); + fRegistry.fill(HIST("Track/hQoverPt"), track.sign() / pt_recalc); + fRegistry.fill(HIST("Track/hEtaPhi"), phi_recalc, eta_recalc); + fRegistry.fill(HIST("Track/hDCAxyz"), dcaXY, dcaZ); + fRegistry.fill(HIST("Track/hDCAxyzSigma"), dcaXY / std::sqrt(track_par_cov_recalc.getSigmaY2()), dcaZ / std::sqrt(track_par_cov_recalc.getSigmaZ2())); + fRegistry.fill(HIST("Track/hDCAxyRes_Pt"), pt_recalc, std::sqrt(track_par_cov_recalc.getSigmaY2()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hDCAzRes_Pt"), pt_recalc, std::sqrt(track_par_cov_recalc.getSigmaZ2()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hNclsITS"), track.itsNCls()); + fRegistry.fill(HIST("Track/hNclsTPC"), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("Track/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("Track/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("Track/hTPCNclsShared"), track.pt(), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("Track/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("Track/hChi2ITS"), track.itsChi2NCl()); + fRegistry.fill(HIST("Track/hChi2TOF"), track.tofChi2()); + fRegistry.fill(HIST("Track/hITSClusterMap"), track.itsClusterMap()); + fRegistry.fill(HIST("Track/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/hTPCNsigmaMu"), track.tpcInnerParam(), track.tpcNSigmaMu()); + fRegistry.fill(HIST("Track/hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); + fRegistry.fill(HIST("Track/hTPCNsigmaKa"), track.tpcInnerParam(), track.tpcNSigmaKa()); + fRegistry.fill(HIST("Track/hTPCNsigmaPr"), track.tpcInnerParam(), track.tpcNSigmaPr()); + fRegistry.fill(HIST("Track/hTOFbeta"), track.p(), track.beta()); + fRegistry.fill(HIST("Track/hTOFNsigmaEl"), track.tpcInnerParam(), track.tofNSigmaEl()); + fRegistry.fill(HIST("Track/hTOFNsigmaMu"), track.tpcInnerParam(), track.tofNSigmaMu()); + fRegistry.fill(HIST("Track/hTOFNsigmaPi"), track.tpcInnerParam(), track.tofNSigmaPi()); + fRegistry.fill(HIST("Track/hTOFNsigmaKa"), track.tpcInnerParam(), track.tofNSigmaKa()); + fRegistry.fill(HIST("Track/hTOFNsigmaPr"), track.tpcInnerParam(), track.tofNSigmaPr()); + fRegistry.fill(HIST("Track/hMeanClusterSizeITS"), track.p(), static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/hITSNsigmaEl"), track.p(), track.itsNSigmaEl()); + fRegistry.fill(HIST("Track/hITSNsigmaMu"), track.p(), track.itsNSigmaMu()); + fRegistry.fill(HIST("Track/hITSNsigmaPi"), track.p(), track.itsNSigmaPi()); + fRegistry.fill(HIST("Track/hITSNsigmaKa"), track.p(), track.itsNSigmaKa()); + fRegistry.fill(HIST("Track/hITSNsigmaPr"), track.p(), track.itsNSigmaPr()); + } + } + } + + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + std::vector> stored_trackIds; + Filter trackFilter = o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& o2::aod::track::tpcChi2NCl < maxchi2tpc&& o2::aod::track::itsChi2NCl < maxchi2its&& ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true; + Filter pidFilter = minTPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < maxTPCNsigmaEl; + using MyFilteredTracks = soa::Filtered; + + Partition posTracks = o2::aod::track::signed1Pt > 0.f; + Partition negTracks = o2::aod::track::signed1Pt < 0.f; + + // ---------- for data ---------- + + void processRec_SA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const& tracks) + { + auto tracksWithITSPid = soa::Attach(tracks); + stored_trackIds.reserve(tracks.size()); + + for (const auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!collision.isSelected()) { + continue; + } + + auto tracks_per_coll = tracksWithITSPid.sliceBy(perCol, collision.globalIndex()); + for (const auto& track : tracks_per_coll) { + if (!checkTrack(collision, track) || !isElectron(track)) { + continue; + } + fillTrackTable(collision, track); + } + + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryElectron, processRec_SA, "process reconstructed info only", true); // standalone + + void processRec_TTCA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyTracks const& tracks, aod::TrackAssoc const& trackIndices) + { + auto tracksWithITSPid = soa::Attach(tracks); + stored_trackIds.reserve(tracks.size() * 2); + + for (const auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!collision.isSelected()) { + continue; + } + + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + + for (const auto& trackId : trackIdsThisCollision) { + // auto track = trackId.template track_as(); + auto track = tracksWithITSPid.rawIteratorAt(trackId.trackId()); + if (!checkTrack(collision, track) || !isElectron(track)) { + continue; + } + fillTrackTable(collision, track); + } + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryElectron, processRec_TTCA, "process reconstructed info only", false); // with TTCA + + void processRec_SA_SWT(MyCollisionsWithSWT const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const& tracks) + { + auto tracksWithITSPid = soa::Attach(tracks); + stored_trackIds.reserve(tracks.size()); + + for (const auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!collision.isSelected()) { + continue; + } + + if (collision.swtaliastmp_raw() == 0) { + continue; + } + + auto tracks_per_coll = tracksWithITSPid.sliceBy(perCol, collision.globalIndex()); + for (const auto& track : tracks_per_coll) { + if (!checkTrack(collision, track) || !isElectron(track)) { + continue; + } + fillTrackTable(collision, track); + } + + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryElectron, processRec_SA_SWT, "process reconstructed info only", false); // standalone with swt + + void processRec_TTCA_SWT(MyCollisionsWithSWT const& collisions, aod::BCsWithTimestamps const&, MyTracks const& tracks, aod::TrackAssoc const& trackIndices) + { + auto tracksWithITSPid = soa::Attach(tracks); + stored_trackIds.reserve(tracks.size() * 2); + + for (const auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!collision.isSelected()) { + continue; + } + if (collision.swtaliastmp_raw() == 0) { + continue; + } + + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + + for (const auto& trackId : trackIdsThisCollision) { + // auto track = trackId.template track_as(); + auto track = tracksWithITSPid.rawIteratorAt(trackId.trackId()); + if (!checkTrack(collision, track) || !isElectron(track)) { + continue; + } + fillTrackTable(collision, track); + } + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryElectron, processRec_TTCA_SWT, "process reconstructed info only", false); // with TTCA with swt + + // ---------- for MC ---------- + + using MyFilteredTracksMC = soa::Filtered; + Partition posTracksMC = o2::aod::track::signed1Pt > 0.f; + Partition negTracksMC = o2::aod::track::signed1Pt < 0.f; + void processMC_SA(soa::Join const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyFilteredTracksMC const& tracks) + { + auto tracksWithITSPid = soa::Attach(tracks); + stored_trackIds.reserve(tracks.size()); + + for (const auto& collision : collisions) { + if (!collision.has_mcCollision()) { + continue; + } + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!collision.isSelected()) { + continue; + } + + auto tracks_per_coll = tracksWithITSPid.sliceBy(perCol, collision.globalIndex()); + for (const auto& track : tracks_per_coll) { + if (!checkTrack(collision, track) || !isElectron(track)) { + continue; + } + fillTrackTable(collision, track); + } + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryElectron, processMC_SA, "process reconstructed and MC info ", false); + + void processMC_TTCA(soa::Join const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyTracksMC const& tracks, aod::TrackAssoc const& trackIndices) + { + auto tracksWithITSPid = soa::Attach(tracks); + stored_trackIds.reserve(tracks.size() * 2); + + for (const auto& collision : collisions) { + if (!collision.has_mcCollision()) { + continue; + } + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!collision.isSelected()) { + continue; + } + + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + + for (const auto& trackId : trackIdsThisCollision) { + // auto track = trackId.template track_as(); + auto track = tracksWithITSPid.rawIteratorAt(trackId.trackId()); + if (!checkTrack(collision, track) || !isElectron(track)) { + continue; + } + fillTrackTable(collision, track); + } + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryElectron, processMC_TTCA, "process reconstructed info only", false); // with TTCA +}; + +struct prefilterPrimaryElectron { + Produces ele_pfb; + + SliceCache cache; + Preslice perCol_track = o2::aod::track::collisionId; + PresliceUnsorted perCol_ele = o2::aod::emprimaryelectron::collisionId; + + // CCDB options + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable mVtxPath{"mVtxPath", "GLO/Calib/MeanVertex", "Path of the mean vertex file"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + + // Operation and minimisation criteria + Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; + + Configurable max_dcaxy{"max_dcaxy", 0.3, "DCAxy To PV for loose track sample"}; + Configurable max_dcaz{"max_dcaz", 0.3, "DCAz To PV for loose track sample"}; + Configurable minpt{"minpt", 0.1, "min pt for track for loose track sample"}; + Configurable maxeta{"maxeta", 1.2, "eta acceptance for loose track sample"}; + Configurable min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable mincrossedrows{"mincrossedrows", 70, "min crossed rows"}; + Configurable max_frac_shared_clusters_tpc{"max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; + Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max chi2/NclsTPC"}; + Configurable maxchi2its{"maxchi2its", 6.0, "max chi2/NclsITS"}; + Configurable min_ncluster_its{"min_ncluster_its", 4, "min ncluster its"}; + Configurable min_ncluster_itsib{"min_ncluster_itsib", 1, "min ncluster itsib"}; + Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", 3.0, "max. TPC n sigma for electron inclusion"}; + Configurable slope{"slope", 0.0185, "slope for m vs. phiv"}; + Configurable intercept{"intercept", -0.0280, "intercept for m vs. phiv"}; + + Configurable> max_mee_vec{"max_mee_vec", std::vector{0.06, 0.08, 0.10}, "vector fo max mee for prefilter in ULS. Please sort this by increasing order."}; // currently, 3 thoresholds are allowed. + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + int mRunNumber; + float d_bz; + Service ccdb; + // o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + o2::dataformats::VertexBase mVtx; + const o2::dataformats::MeanVertexObject* mMeanVtx = nullptr; + o2::base::MatLayerCylSet* lut = nullptr; + + void init(InitContext&) + { + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + if (!doprocessDummy) { + addHistograms(); + } + } + + void addHistograms() + { + fRegistry.add("Track/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); + fRegistry.add("Track/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{90, 0, 2 * M_PI}, {80, -2.0f, 2.0f}}, false); + fRegistry.add("Track/hTPCNsigmaEl", "loose track TPC PID", kTH2F, {{1000, 0.f, 10}, {100, -5, +5}}); + fRegistry.add("Pair/before/uls/hMvsPt", "mass vs. pT;m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{500, 0, 0.5}, {100, 0, 1}}); + fRegistry.add("Pair/before/uls/hMvsPhiV", "mass vs. phiv;#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0.f, M_PI}, {100, 0, 0.1}}); + fRegistry.addClone("Pair/before/uls/", "Pair/before/lspp/"); + fRegistry.addClone("Pair/before/uls/", "Pair/before/lsmm/"); + fRegistry.addClone("Pair/before/", "Pair/after/"); + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + // load matLUT for this timestamp + if (!lut) { + LOG(info) << "Loading material look-up table for timestamp: " << bc.timestamp(); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->getForTimeStamp(lutPath, bc.timestamp())); + } else { + LOG(info) << "Material look-up table already in place. Not reloading."; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (std::fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + o2::base::Propagator::initFieldFromGRP(&grpmag); + o2::base::Propagator::Instance()->setMatLUT(lut); + mMeanVtx = ccdb->getForTimeStamp(mVtxPath, bc.timestamp()); + mRunNumber = bc.runNumber(); + return; + } + + auto run3grp_timestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + o2::base::Propagator::Instance()->setMatLUT(lut); + mMeanVtx = ccdb->getForTimeStamp(mVtxPath, bc.timestamp()); + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + o2::base::Propagator::Instance()->setMatLUT(lut); + mMeanVtx = ccdb->getForTimeStamp(mVtxPath, bc.timestamp()); + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = bc.runNumber(); + } + + o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + + template + bool checkTrack(TCollision const& collision, TTrack const& track) + { + if (!track.hasITS()) { + return false; + } + if (track.itsChi2NCl() > maxchi2its) { + return false; + } + if (track.itsNCls() < min_ncluster_its) { + return false; + } + if (track.itsNClsInnerBarrel() < min_ncluster_itsib) { + return false; + } + + if (!track.hasTPC()) { + return false; + } + if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { + return false; + } + if (track.tpcNClsFound() < min_ncluster_tpc) { + return false; + } + if (track.tpcNClsCrossedRows() < mincrossedrows) { + return false; + } + if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { + return false; + } + if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { + return false; + } + if (track.tpcChi2NCl() > maxchi2its) { + return false; + } + + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto track_par_cov_recalc = getTrackParCov(track); + track_par_cov_recalc.setPID(o2::track::PID::Electron); + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, track_par_cov_recalc, 2.f, matCorr, &mDcaInfoCov); + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + + if (std::fabs(dcaXY) > max_dcaxy || std::fabs(dcaZ) > max_dcaz) { + return false; + } + + if (track_par_cov_recalc.getPt() < minpt || std::fabs(track_par_cov_recalc.getEta()) > maxeta) { + return false; + } + + return true; + } + + template + bool reconstructPC(TCollision const& collision, TTrack1 const& ele, TTrack2 const& pos) + { + float mee = 0, phiv = 0; + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + std::array pVec_recalc = {0, 0, 0}; // px, py, pz + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + + if constexpr (loose_track_sign > 0) { // positive track is loose track + auto track_par_cov_recalc = getTrackParCov(pos); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, track_par_cov_recalc, 2.f, matCorr, &mDcaInfoCov); + getPxPyPz(track_par_cov_recalc, pVec_recalc); + + ROOT::Math::PtEtaPhiMVector v1(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(track_par_cov_recalc.getPt(), track_par_cov_recalc.getEta(), track_par_cov_recalc.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + mee = v12.M(); + phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pVec_recalc[0], pVec_recalc[1], pVec_recalc[2], ele.px(), ele.py(), ele.pz(), pos.sign(), ele.sign(), d_bz); + } else { + auto track_par_cov_recalc = getTrackParCov(ele); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, track_par_cov_recalc, 2.f, matCorr, &mDcaInfoCov); + getPxPyPz(track_par_cov_recalc, pVec_recalc); + + ROOT::Math::PtEtaPhiMVector v1(track_par_cov_recalc.getPt(), track_par_cov_recalc.getEta(), track_par_cov_recalc.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + mee = v12.M(); + phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pos.px(), pos.py(), pos.pz(), pVec_recalc[0], pVec_recalc[1], pVec_recalc[2], pos.sign(), ele.sign(), d_bz); + } + + if (mee < slope * phiv + intercept) { + return true; + } else { + return false; + } + } + + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + + Filter trackFilter = o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true; + using MyFilteredTracks = soa::Filtered; + Partition posTracks = o2::aod::track::signed1Pt > 0.f; + Partition negTracks = o2::aod::track::signed1Pt < 0.f; + + Partition positrons = o2::aod::emprimaryelectron::sign > int8_t(0); + Partition electrons = o2::aod::emprimaryelectron::sign < int8_t(0); + + void processPrefilter_TTCA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyTracks const&, aod::EMPrimaryElectrons const& primaryelectrons, aod::TrackAssoc const& trackIndices) + { + std::unordered_map pfb_map; // map track.globalIndex -> prefilter bit + + for (const auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + if (!collision.isSelected()) { + continue; + } + + auto positrons_per_coll = positrons->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache); // signal sample + auto electrons_per_coll = electrons->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache); // signal sample + + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + std::vector posTracks_per_coll; + std::vector negTracks_per_coll; + posTracks_per_coll.reserve(trackIdsThisCollision.size()); + negTracks_per_coll.reserve(trackIdsThisCollision.size()); + + for (const auto& trackId : trackIdsThisCollision) { + auto track = trackId.template track_as(); + if (!checkTrack(collision, track)) { + continue; + } + fRegistry.fill(HIST("Track/hPt"), track.pt()); + fRegistry.fill(HIST("Track/hEtaPhi"), track.phi(), track.eta()); + if (track.sign() > 0) { + posTracks_per_coll.emplace_back(track); + } else { + negTracks_per_coll.emplace_back(track); + } + } + + for (const auto& ele : negTracks_per_coll) { + if (!checkTrack(collision, ele)) { + continue; + } + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + std::array pVec_recalc = {0, 0, 0}; // px, py, pz + auto track_par_cov_recalc = getTrackParCov(ele); + track_par_cov_recalc.setPID(o2::track::PID::Electron); + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, track_par_cov_recalc, 2.f, matCorr, &mDcaInfoCov); + getPxPyPz(track_par_cov_recalc, pVec_recalc); + + for (const auto& empos : positrons_per_coll) { + if (empos.trackId() == ele.globalIndex()) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(track_par_cov_recalc.getPt(), track_par_cov_recalc.getEta(), track_par_cov_recalc.getPhi(), o2::constants::physics::MassElectron); // loose track + ROOT::Math::PtEtaPhiMVector v2(empos.pt(), empos.eta(), empos.phi(), o2::constants::physics::MassElectron); // signal track + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(empos.px(), empos.py(), empos.pz(), pVec_recalc[0], pVec_recalc[1], pVec_recalc[2], empos.sign(), ele.sign(), d_bz); + fRegistry.fill(HIST("Pair/before/uls/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/before/uls/hMvsPt"), v12.M(), v12.Pt()); + if (v12.M() < max_mee_vec->at(static_cast(max_mee_vec->size()) - 1)) { + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), ele.tpcInnerParam(), ele.tpcNSigmaEl()); + } + for (int i = 0; i < static_cast(max_mee_vec->size()); i++) { + if (v12.M() < max_mee_vec->at(i)) { + pfb_map[empos.globalIndex()] |= (uint8_t(1) << (static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_1) + i)); + } + } + + if (v12.M() < slope * phiv + intercept) { + pfb_map[empos.globalIndex()] |= (uint8_t(1) << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPC)); + } + + } // end of signal positon loop + } // end of loose electron loop + + for (const auto& pos : posTracks_per_coll) { + if (!checkTrack(collision, pos)) { // track cut is applied to loose sample + continue; + } + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + std::array pVec_recalc = {0, 0, 0}; // px, py, pz + auto track_par_cov_recalc = getTrackParCov(pos); + track_par_cov_recalc.setPID(o2::track::PID::Electron); + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, track_par_cov_recalc, 2.f, matCorr, &mDcaInfoCov); + getPxPyPz(track_par_cov_recalc, pVec_recalc); + for (const auto& emele : electrons_per_coll) { + if (emele.trackId() == pos.globalIndex()) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(emele.pt(), emele.eta(), emele.phi(), o2::constants::physics::MassElectron); // signal track + ROOT::Math::PtEtaPhiMVector v2(track_par_cov_recalc.getPt(), track_par_cov_recalc.getEta(), track_par_cov_recalc.getPhi(), o2::constants::physics::MassElectron); // loose track + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pVec_recalc[0], pVec_recalc[1], pVec_recalc[2], emele.px(), emele.py(), emele.pz(), pos.sign(), emele.sign(), d_bz); + fRegistry.fill(HIST("Pair/before/uls/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/before/uls/hMvsPt"), v12.M(), v12.Pt()); + if (v12.M() < max_mee_vec->at(static_cast(max_mee_vec->size()) - 1)) { + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), pos.tpcInnerParam(), pos.tpcNSigmaEl()); + } + for (int i = 0; i < static_cast(max_mee_vec->size()); i++) { + if (v12.M() < max_mee_vec->at(i)) { + pfb_map[emele.globalIndex()] |= (uint8_t(1) << (static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_1) + i)); + } + } + + if (v12.M() < slope * phiv + intercept) { + pfb_map[emele.globalIndex()] |= (uint8_t(1) << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPC)); + } + } // end of signal electron loop + } // end of loose positon loop + + for (const auto& pos : posTracks_per_coll) { + if (!checkTrack(collision, pos)) { // track cut is applied to loose sample + continue; + } + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + std::array pVec_recalc = {0, 0, 0}; // px, py, pz + auto track_par_cov_recalc = getTrackParCov(pos); + track_par_cov_recalc.setPID(o2::track::PID::Electron); + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, track_par_cov_recalc, 2.f, matCorr, &mDcaInfoCov); + getPxPyPz(track_par_cov_recalc, pVec_recalc); + for (const auto& empos : positrons_per_coll) { + if (empos.trackId() == pos.globalIndex()) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(empos.pt(), empos.eta(), empos.phi(), o2::constants::physics::MassElectron); // signal track + ROOT::Math::PtEtaPhiMVector v2(track_par_cov_recalc.getPt(), track_par_cov_recalc.getEta(), track_par_cov_recalc.getPhi(), o2::constants::physics::MassElectron); // loose track + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pVec_recalc[0], pVec_recalc[1], pVec_recalc[2], empos.px(), empos.py(), empos.pz(), pos.sign(), empos.sign(), d_bz); + fRegistry.fill(HIST("Pair/before/lspp/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/before/lspp/hMvsPt"), v12.M(), v12.Pt()); + } // end of signal positron loop + } // end of loose positon loop + + for (const auto& ele : negTracks_per_coll) { + if (!checkTrack(collision, ele)) { + continue; + } + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + std::array pVec_recalc = {0, 0, 0}; // px, py, pz + auto track_par_cov_recalc = getTrackParCov(ele); + track_par_cov_recalc.setPID(o2::track::PID::Electron); + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, track_par_cov_recalc, 2.f, matCorr, &mDcaInfoCov); + getPxPyPz(track_par_cov_recalc, pVec_recalc); + + for (const auto& emele : electrons_per_coll) { + if (emele.trackId() == ele.globalIndex()) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(track_par_cov_recalc.getPt(), track_par_cov_recalc.getEta(), track_par_cov_recalc.getPhi(), o2::constants::physics::MassElectron); // loose track + ROOT::Math::PtEtaPhiMVector v2(emele.pt(), emele.eta(), emele.phi(), o2::constants::physics::MassElectron); // signal track + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(emele.px(), emele.py(), emele.pz(), pVec_recalc[0], pVec_recalc[1], pVec_recalc[2], emele.sign(), ele.sign(), d_bz); + fRegistry.fill(HIST("Pair/before/lsmm/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/before/lsmm/hMvsPt"), v12.M(), v12.Pt()); + + } // end of signal electron loop + } // end of loose electron loop + + posTracks_per_coll.clear(); + negTracks_per_coll.clear(); + posTracks_per_coll.shrink_to_fit(); + negTracks_per_coll.shrink_to_fit(); + } // end of collision loop + + for (const auto& ele : primaryelectrons) { + ele_pfb(pfb_map[ele.globalIndex()]); + } + + // check prefilter + for (const auto& collision : collisions) { + auto positrons_per_coll = positrons->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache); // signal sample + auto electrons_per_coll = electrons->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache); // signal sample + + for (const auto& [ele, pos] : combinations(CombinationsFullIndexPolicy(electrons_per_coll, positrons_per_coll))) { + if (pfb_map[ele.globalIndex()] != 0 || pfb_map[pos.globalIndex()] != 0) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pos.px(), pos.py(), pos.pz(), ele.px(), ele.py(), ele.pz(), pos.sign(), ele.sign(), d_bz); + fRegistry.fill(HIST("Pair/after/uls/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/after/uls/hMvsPt"), v12.M(), v12.Pt()); + + } // end of ULS pairing + } // end of collision loop + + pfb_map.clear(); + } + PROCESS_SWITCH(prefilterPrimaryElectron, processPrefilter_TTCA, "process prefilter with TTCA", false); + + void processPrefilter_SA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const&, aod::EMPrimaryElectrons const& primaryelectrons) + { + std::unordered_map pfb_map; // map track.globalIndex -> prefilter bit + + for (const auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + if (!collision.isSelected()) { + continue; + } + + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); // loose track sample + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); // loose track sample + + auto positrons_per_coll = positrons->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache); // signal sample + auto electrons_per_coll = electrons->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache); // signal sample + + for (const auto& pos : posTracks_per_coll) { + if (!checkTrack(collision, pos)) { // track cut is applied to loose sample + continue; + } + fRegistry.fill(HIST("Track/hPt"), pos.pt()); + fRegistry.fill(HIST("Track/hEtaPhi"), pos.phi(), pos.eta()); + } + for (const auto& neg : negTracks_per_coll) { + if (!checkTrack(collision, neg)) { // track cut is applied to loose sample + continue; + } + fRegistry.fill(HIST("Track/hPt"), neg.pt()); + fRegistry.fill(HIST("Track/hEtaPhi"), neg.phi(), neg.eta()); + } + + for (const auto& [ele, empos] : combinations(CombinationsFullIndexPolicy(negTracks_per_coll, positrons_per_coll))) { + // auto pos = tracks.rawIteratorAt(empos.trackId()); // use rawIterator, if the table is filtered. + if (!checkTrack(collision, ele)) { // track cut is applied to loose sample + continue; + } + if (empos.trackId() == ele.globalIndex()) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); // loose track + ROOT::Math::PtEtaPhiMVector v2(empos.pt(), empos.eta(), empos.phi(), o2::constants::physics::MassElectron); // signal track + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(empos.px(), empos.py(), empos.pz(), ele.px(), ele.py(), ele.pz(), empos.sign(), ele.sign(), d_bz); + fRegistry.fill(HIST("Pair/before/uls/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/before/uls/hMvsPt"), v12.M(), v12.Pt()); + if (v12.M() < max_mee_vec->at(static_cast(max_mee_vec->size()) - 1)) { + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), ele.tpcInnerParam(), ele.tpcNSigmaEl()); + } + for (int i = 0; i < static_cast(max_mee_vec->size()); i++) { + if (v12.M() < max_mee_vec->at(i)) { + pfb_map[empos.globalIndex()] |= (uint8_t(1) << (static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_1) + i)); + } + } + + if (v12.M() < slope * phiv + intercept) { + pfb_map[empos.globalIndex()] |= (uint8_t(1) << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPC)); + } + + } // end of ULS pairing + + for (const auto& [pos, emele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, electrons_per_coll))) { + // auto ele = tracks.rawIteratorAt(emele.trackId()); // use rawIterator, if the table is filtered. + if (!checkTrack(collision, pos)) { // track cut is applied to loose sample + continue; + } + if (emele.trackId() == pos.globalIndex()) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(emele.pt(), emele.eta(), emele.phi(), o2::constants::physics::MassElectron); // signal track + ROOT::Math::PtEtaPhiMVector v2(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); // loose track + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pos.px(), pos.py(), pos.pz(), emele.px(), emele.py(), emele.pz(), pos.sign(), emele.sign(), d_bz); + fRegistry.fill(HIST("Pair/before/uls/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/before/uls/hMvsPt"), v12.M(), v12.Pt()); + if (v12.M() < max_mee_vec->at(static_cast(max_mee_vec->size()) - 1)) { + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), pos.tpcInnerParam(), pos.tpcNSigmaEl()); + } + for (int i = 0; i < static_cast(max_mee_vec->size()); i++) { + if (v12.M() < max_mee_vec->at(i)) { + pfb_map[emele.globalIndex()] |= (uint8_t(1) << (static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_1) + i)); + } + } + + if (v12.M() < slope * phiv + intercept) { + pfb_map[emele.globalIndex()] |= (uint8_t(1) << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPC)); + } + + } // end of ULS pairing + + for (const auto& [pos, empos] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, positrons_per_coll))) { + // auto pos = tracks.rawIteratorAt(empos.trackId()); // use rawIterator, if the table is filtered. + if (!checkTrack(collision, pos)) { // track cut is applied to loose sample + continue; + } + if (empos.trackId() == pos.globalIndex()) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); // loose track + ROOT::Math::PtEtaPhiMVector v2(empos.pt(), empos.eta(), empos.phi(), o2::constants::physics::MassElectron); // signal track + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(empos.px(), empos.py(), empos.pz(), pos.px(), pos.py(), pos.pz(), empos.sign(), pos.sign(), d_bz); + fRegistry.fill(HIST("Pair/before/lspp/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/before/lspp/hMvsPt"), v12.M(), v12.Pt()); + } // end of LS++ pairing + + for (const auto& [ele, emele] : combinations(CombinationsFullIndexPolicy(negTracks_per_coll, electrons_per_coll))) { + // auto ele = tracks.rawIteratorAt(emele.trackId()); // use rawIterator, if the table is filtered. + if (!checkTrack(collision, ele)) { // track cut is applied to loose sample + continue; + } + if (emele.trackId() == ele.globalIndex()) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); // loose track + ROOT::Math::PtEtaPhiMVector v2(emele.pt(), emele.eta(), emele.phi(), o2::constants::physics::MassElectron); // signal track + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(emele.px(), emele.py(), emele.pz(), ele.px(), ele.py(), ele.pz(), emele.sign(), ele.sign(), d_bz); + fRegistry.fill(HIST("Pair/before/lsmm/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/before/lsmm/hMvsPt"), v12.M(), v12.Pt()); + } // end of LS-- pairing + + } // end of collision loop + + for (const auto& ele : primaryelectrons) { + ele_pfb(pfb_map[ele.globalIndex()]); + } + + // check prefilter + for (const auto& collision : collisions) { + auto positrons_per_coll = positrons->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache); // signal sample + auto electrons_per_coll = electrons->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache); // signal sample + + for (const auto& [ele, pos] : combinations(CombinationsFullIndexPolicy(electrons_per_coll, positrons_per_coll))) { + if (pfb_map[ele.globalIndex()] != 0 || pfb_map[pos.globalIndex()] != 0) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pos.px(), pos.py(), pos.pz(), ele.px(), ele.py(), ele.pz(), pos.sign(), ele.sign(), d_bz); + fRegistry.fill(HIST("Pair/after/uls/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/after/uls/hMvsPt"), v12.M(), v12.Pt()); + } // end of ULS pairing + } // end of collision loop + + pfb_map.clear(); + } + PROCESS_SWITCH(prefilterPrimaryElectron, processPrefilter_SA, "process prefilter standalone", false); + + void processDummy(aod::EMPrimaryElectrons const& primaryelectrons) + { + for (int i = 0; i < primaryelectrons.size(); i++) { + ele_pfb(0); + } + } + PROCESS_SWITCH(prefilterPrimaryElectron, processDummy, "process dummy", true); +}; + +struct associateAmbiguousElectron { + Produces em_amb_ele_ids; + + SliceCache cache; + PresliceUnsorted perTrack = o2::aod::emprimaryelectron::trackId; + std::vector ambele_self_Ids; + + void process(aod::EMPrimaryElectrons const& electrons) + { + for (const auto& electron : electrons) { + auto electrons_with_same_trackId = electrons.sliceBy(perTrack, electron.trackId()); + ambele_self_Ids.reserve(electrons_with_same_trackId.size()); + for (const auto& amb_ele : electrons_with_same_trackId) { + if (amb_ele.globalIndex() == electron.globalIndex()) { // don't store myself. + continue; + } + ambele_self_Ids.emplace_back(amb_ele.globalIndex()); + } + em_amb_ele_ids(ambele_self_Ids); + ambele_self_Ids.clear(); + ambele_self_Ids.shrink_to_fit(); + } + } +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"skimmer-primary-electron"}), + adaptAnalysisTask(cfgc, TaskName{"prefilter-primary-electron"}), + adaptAnalysisTask(cfgc, TaskName{"associate-ambiguous-electron"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx new file mode 100644 index 00000000000..705705bb3e4 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx @@ -0,0 +1,358 @@ +// 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 write relevant information for muons. +/// \author daiki.sekihata@cern.ch + +#include +#include +#include +#include + +#include "Math/Vector4D.h" +#include "Math/SMatrix.h" + +#include "Framework/DataTypes.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/Core/TableHelper.h" +#include "Common/DataModel/PropagatedFwdTrackTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "TGeoGlobalMagField.h" +#include "Field/MagneticField.h" + +#include "DetectorsBase/Propagator.h" +#include "GlobalTracking/MatchGlobalFwd.h" +#include "MCHTracking/TrackExtrap.h" +#include "MCHTracking/TrackParam.h" +#include "ReconstructionDataFormats/TrackFwd.h" + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +using namespace o2; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +struct skimmerPrimaryMuon { + using MyCollisions = soa::Join; + using MyCollisionsWithSWT = soa::Join; + + using MyPropagatedFwdTracks = soa::Join; // muon tracks are repeated. i.e. not exclusive. + using MyPropagatedFwdTrack = MyPropagatedFwdTracks::iterator; + + using MyFwdTracks = soa::Join; // muon tracks are repeated. i.e. not exclusive. + using MyFwdTrack = MyFwdTracks::iterator; + + using MyFwdTracksMC = soa::Join; + using MyFwdTrackMC = MyFwdTracksMC::iterator; + + using MFTTracksMC = soa::Join; + using MFTTrackMC = MFTTracksMC::iterator; + + Produces emprimarymuons; + Produces emprimarymuonscov; + + SliceCache cache; + Preslice perCollision = o2::aod::fwdtrack::collisionId; + Preslice perCollision_mft = o2::aod::fwdtrack::collisionId; + + // Configurables + Configurable fillQAHistogram{"fillQAHistogram", false, "flag to fill QA histograms"}; + // Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + // Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + // Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + // Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable minpt{"minpt", 0.2, "min pt for muon"}; + Configurable mineta{"mineta", -4.0, "eta acceptance"}; + Configurable maxeta{"maxeta", -2.5, "eta acceptance"}; + Configurable mineta_mft{"mineta_mft", -3.6, "eta acceptance"}; + Configurable maxeta_mft{"maxeta_mft", -2.5, "eta acceptance"}; + Configurable minRabs{"minRabs", 17.6, "min. R at absorber end"}; + Configurable maxRabs{"maxRabs", 89.5, "max. R at absorber end"}; + + // o2::ccdb::CcdbApi ccdbApi; + // Service ccdb; + int mRunNumber; + + // o2::globaltracking::MatchGlobalFwd mMatching; + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view muon_types[5] = {"MFTMCHMID/", "MFTMCHMIDOtherMatch/", "MFTMCH/", "MCHMID/", "MCH/"}; + + void init(InitContext&) + { + // ccdb->setURL(ccdburl); + // ccdb->setCaching(true); + // ccdb->setLocalObjectValidityChecking(); + // ccdb->setFatalWhenNull(false); + // ccdbApi.init(ccdburl); + + if (fillQAHistogram) { + addHistograms(); + } + mRunNumber = 0; + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + + // std::map metadata; + // auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, mRunNumber); + // auto ts = soreor.first; + // auto grpmag = ccdbApi.retrieveFromTFileAny(grpmagPath, metadata, ts); + // o2::base::Propagator::initFieldFromGRP(grpmag); + // if (!o2::base::GeometryManager::isGeometryLoaded()) { + // ccdb->get(geoPath); + // } + // o2::mch::TrackExtrap::setField(); + } + + void addHistograms() + { + // for track + auto hMuonType = fRegistry.add("Track/hMuonType", "muon type", kTH1F, {{5, -0.5f, 4.5f}}); + hMuonType->GetXaxis()->SetBinLabel(1, "MFT-MCH-MID (global muon)"); + hMuonType->GetXaxis()->SetBinLabel(2, "MFT-MCH-MID (global muon other match)"); + hMuonType->GetXaxis()->SetBinLabel(3, "MFT-MCH"); + hMuonType->GetXaxis()->SetBinLabel(4, "MCH-MID"); + hMuonType->GetXaxis()->SetBinLabel(5, "MCH standalone"); + + fRegistry.add("Track/MFTMCHMID/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); + fRegistry.add("Track/MFTMCHMID/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{360, 0, 2 * M_PI}, {30, -5.0f, -2.0f}}, false); + fRegistry.add("Track/MFTMCHMID/hNclusters", "Nclusters;Nclusters", kTH1F, {{21, -0.5f, 20.5}}, false); + fRegistry.add("Track/MFTMCHMID/hNclustersMFT", "NclustersMFT;Nclusters MFT", kTH1F, {{11, -0.5f, 10.5}}, false); + fRegistry.add("Track/MFTMCHMID/hRatAbsorberEnd", "R at absorber end;R at absorber end (cm)", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("Track/MFTMCHMID/hPDCA", "pDCA;r at absorber end (cm);p #times DCA (GeV/c #upoint cm)", kTH2F, {{100, 0, 100}, {100, 0.0f, 1000}}, false); + fRegistry.add("Track/MFTMCHMID/hChi2", "chi2;chi2", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("Track/MFTMCHMID/hChi2MatchMCHMID", "chi2 match MCH-MID;chi2", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("Track/MFTMCHMID/hChi2MatchMCHMFT", "chi2 match MCH-MFT;chi2", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("Track/MFTMCHMID/hDCAxy2D", "DCA xy;DCA_{x} (cm);DCA_{y} (cm)", kTH2F, {{200, -10, 10}, {200, -10, +10}}, false); + fRegistry.add("Track/MFTMCHMID/hDCAxy2DinSigma", "DCA xy;DCA_{x} (#sigma);DCA_{y} (#sigma)", kTH2F, {{200, -10, 10}, {200, -10, +10}}, false); + fRegistry.add("Track/MFTMCHMID/hDCAxResolutionvsPt", "DCA_{x} vs. p_{T,#mu};p_{T,#mu} (GeV/c);DCA_{x} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {100, 0, 100}}, false); + fRegistry.add("Track/MFTMCHMID/hDCAyResolutionvsPt", "DCA_{y} vs. p_{T,#mu};p_{T,#mu} (GeV/c);DCA_{y} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {100, 0, 100}}, false); + fRegistry.addClone("Track/MFTMCHMID/", "Track/MCHMID/"); + } + + template + void fillTrackHistogram(TTrack const& track) + { + fRegistry.fill(HIST("Track/hMuonType"), track.trackType()); + fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hPt"), track.pt()); + fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hEtaPhi"), track.phi(), track.eta()); + fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hNclusters"), track.nClusters()); + fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hPDCA"), track.rAtAbsorberEnd(), track.pDca()); + fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hRatAbsorberEnd"), track.rAtAbsorberEnd()); + fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hChi2"), track.chi2()); + fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hChi2MatchMCHMID"), track.chi2MatchMCHMID()); + fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hChi2MatchMCHMFT"), track.chi2MatchMCHMFT()); + fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hDCAxy2D"), track.fwdDcaX(), track.fwdDcaY()); + fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hDCAxy2DinSigma"), track.fwdDcaX() / std::sqrt(track.cXX()), track.fwdDcaY() / std::sqrt(track.cYY())); + fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hDCAxResolutionvsPt"), track.pt(), std::sqrt(track.cXXatDCA()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hDCAyResolutionvsPt"), track.pt(), std::sqrt(track.cYYatDCA()) * 1e+4); // convert cm to um + } + + template + void run(TCollisions const& collisions, TBCs const&, TSAMuons const& saMuons, TGlobalMuons const& glMuons, TFwdTracks const&, TMFTTracks const&) + { + for (const auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + if (!collision.isSelected()) { + continue; + } + + if constexpr (isTriggerAnalysis) { + if (collision.swtaliastmp_raw() == 0) { + continue; + } + } + + if constexpr (isMC) { + if (!collision.has_mcCollision()) { + continue; + } + } + + auto sa_muons_per_coll = saMuons.sliceByCached(o2::aod::fwdtrack::collisionId, collision.globalIndex(), cache); + auto global_muons_per_coll = glMuons.sliceByCached(o2::aod::fwdtrack::collisionId, collision.globalIndex(), cache); + + for (const auto& muon : sa_muons_per_coll) { + if (fillQAHistogram) { + fillTrackHistogram<3>(muon); + } + + const auto& fwdtrack = muon.template fwdtrack_as(); + + if constexpr (isMC) { + if (!fwdtrack.has_mcParticle()) { + continue; + } + } + emprimarymuons(collision.globalIndex(), fwdtrack.globalIndex(), -1, -1, muon.trackType(), + muon.pt(), muon.eta(), muon.phi(), muon.sign(), muon.fwdDcaX(), muon.fwdDcaY(), muon.cXXatDCA(), muon.cYYatDCA(), muon.cXYatDCA(), muon.etaMatchedMCHMID(), muon.phiMatchedMCHMID(), + // muon.x(), muon.y(), muon.z(), muon.tgl(), + muon.nClusters(), muon.pDca(), muon.rAtAbsorberEnd(), muon.chi2(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), + muon.mchBitMap(), muon.midBitMap(), muon.midBoards(), 0, 999999.f, muon.isAssociatedToMPC(), muon.isAmbiguous()); + + emprimarymuonscov( + muon.cXX(), + muon.cXY(), + muon.cYY(), + muon.cPhiX(), + muon.cPhiY(), + muon.cPhiPhi(), + muon.cTglX(), + muon.cTglY(), + muon.cTglPhi(), + muon.cTglTgl(), + muon.c1PtX(), + muon.c1PtY(), + muon.c1PtPhi(), + muon.c1PtTgl(), + muon.c1Pt21Pt2()); + + } // end of standalone muon loop + for (const auto& muon : global_muons_per_coll) { + if (fillQAHistogram) { + fillTrackHistogram<0>(muon); + } + + const auto& fwdtrack = muon.template fwdtrack_as(); + const auto& mfttrack = muon.template matchMFTTrack_as(); + const auto& mchtrack = muon.template matchMCHTrack_as(); + + if constexpr (isMC) { + if (!fwdtrack.has_mcParticle()) { + continue; + } + } + + emprimarymuons(collision.globalIndex(), fwdtrack.globalIndex(), mfttrack.globalIndex(), mchtrack.globalIndex(), muon.trackType(), + muon.pt(), muon.eta(), muon.phi(), muon.sign(), muon.fwdDcaX(), muon.fwdDcaY(), muon.cXXatDCA(), muon.cYYatDCA(), muon.cXYatDCA(), muon.etaMatchedMCHMID(), muon.phiMatchedMCHMID(), + // muon.x(), muon.y(), muon.z(), muon.tgl(), + muon.nClusters(), muon.pDca(), muon.rAtAbsorberEnd(), muon.chi2(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), + muon.mchBitMap(), muon.midBitMap(), muon.midBoards(), mfttrack.mftClusterSizesAndTrackFlags(), mfttrack.chi2(), muon.isAssociatedToMPC(), muon.isAmbiguous()); + + emprimarymuonscov( + muon.cXX(), + muon.cXY(), + muon.cYY(), + muon.cPhiX(), + muon.cPhiY(), + muon.cPhiPhi(), + muon.cTglX(), + muon.cTglY(), + muon.cTglPhi(), + muon.cTglTgl(), + muon.c1PtX(), + muon.c1PtY(), + muon.c1PtPhi(), + muon.c1PtTgl(), + muon.c1Pt21Pt2()); + + } // end of global muon loop + } // end of collision loop + } + + std::map, int> map_new_sa_muon_index; // new standalone muon index + + Partition global_muons = o2::aod::fwdtrack::trackType == uint8_t(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack); // MFT-MCH-MID + Partition sa_muons = o2::aod::fwdtrack::trackType == uint8_t(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack); // MCH-MID + + void processRec(MyCollisions const& collisions, aod::BCsWithTimestamps const& bcs, MyPropagatedFwdTracks const&, MyFwdTracks const& fwdtracks, aod::MFTTracks const& mfttracks) + { + run(collisions, bcs, sa_muons, global_muons, fwdtracks, mfttracks); + } + PROCESS_SWITCH(skimmerPrimaryMuon, processRec, "process reconstructed info", true); + + void processRec_SWT(MyCollisionsWithSWT const& collisions, aod::BCsWithTimestamps const& bcs, MyPropagatedFwdTracks const&, MyFwdTracks const& fwdtracks, aod::MFTTracks const& mfttracks) + { + run(collisions, bcs, sa_muons, global_muons, fwdtracks, mfttracks); + } + PROCESS_SWITCH(skimmerPrimaryMuon, processRec_SWT, "process reconstructed info only with standalone", false); + + void processMC(soa::Join const& collisions, aod::BCsWithTimestamps const& bcs, MyPropagatedFwdTracks const&, MyFwdTracksMC const& fwdtracks, MFTTracksMC const& mfttracks) + { + run(collisions, bcs, sa_muons, global_muons, fwdtracks, mfttracks); + } + PROCESS_SWITCH(skimmerPrimaryMuon, processMC, "process reconstructed and MC info", false); +}; +struct associateAmbiguousMuon { + Produces em_amb_muon_ids; + + SliceCache cache; + PresliceUnsorted perTrack = o2::aod::emprimarymuon::fwdtrackId; + std::vector ambmuon_self_Ids; + + void process(aod::EMPrimaryMuons const& muons) + { + for (const auto& muon : muons) { + auto muons_with_same_trackId = muons.sliceBy(perTrack, muon.fwdtrackId()); + ambmuon_self_Ids.reserve(muons_with_same_trackId.size()); + for (const auto& amb_muon : muons_with_same_trackId) { + if (amb_muon.globalIndex() == muon.globalIndex()) { // don't store myself. + continue; + } + ambmuon_self_Ids.emplace_back(amb_muon.globalIndex()); + } + em_amb_muon_ids(ambmuon_self_Ids); + ambmuon_self_Ids.clear(); + ambmuon_self_Ids.shrink_to_fit(); + } + } +}; +struct associateSameMFT { + Produces em_same_mft_ids; + + SliceCache cache; + PresliceUnsorted perMFTTrack = o2::aod::emprimarymuon::mfttrackId; + std::vector self_Ids; + + void process(aod::EMPrimaryMuons const& muons) + { + for (const auto& muon : muons) { + if (muon.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + auto muons_with_same_mfttrackId = muons.sliceBy(perMFTTrack, muon.mfttrackId()); + self_Ids.reserve(muons_with_same_mfttrackId.size()); + for (const auto& global_muon : muons_with_same_mfttrackId) { + if (global_muon.globalIndex() == muon.globalIndex()) { // don't store myself. + continue; + } + if (global_muon.collisionId() == muon.collisionId()) { + self_Ids.emplace_back(global_muon.globalIndex()); + } + } + em_same_mft_ids(self_Ids); + self_Ids.clear(); + self_Ids.shrink_to_fit(); + } else { // for standalone muons + em_same_mft_ids(std::vector{}); // empty + } + } // end of muon loop + } +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"skimmer-primary-muon"}), + adaptAnalysisTask(cfgc, TaskName{"associate-ambiguous-muon"}), + adaptAnalysisTask(cfgc, TaskName{"associate-same-mft"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/skimmerSecondaryElectron.cxx b/PWGEM/Dilepton/TableProducer/skimmerSecondaryElectron.cxx new file mode 100644 index 00000000000..ecb138b57c9 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/skimmerSecondaryElectron.cxx @@ -0,0 +1,628 @@ +// 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 write relevant information about primary electrons. +/// \author daiki.sekihata@cern.ch + +#include +#include +#include +#include +#include +#include + +#include "Math/Vector4D.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "Common/Core/trackUtilities.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/DataModel/CollisionAssociationTables.h" + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +using namespace o2; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +using MyCollisions = soa::Join; +using MyCollisionsMC = soa::Join; + +using MyTracks = soa::Join; +using MyTrack = MyTracks::iterator; +using MyTracksMC = soa::Join; +using MyTrackMC = MyTracksMC::iterator; + +struct skimmerSecondaryElectron { + // enum class EM_EEPairType : int { + // kULS = 0, + // kLSpp = +1, + // kLSmm = -1, + // }; + + SliceCache cache; + Preslice perCol = o2::aod::track::collisionId; + Produces emprimaryelectrons; + Produces emprimaryelectronscov; + Produces event; + Produces event_mult; + Produces event_cent; + + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + + // Operation and minimisation criteria + Configurable fillQAHistogram{"fillQAHistogram", false, "flag to fill QA histograms"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + Configurable min_ncluster_tpc{"min_ncluster_tpc", 10, "min ncluster tpc"}; + Configurable mincrossedrows{"mincrossedrows", 70, "min. crossed rows"}; + Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; + Configurable minitsncls{"minitsncls", 4, "min. number of ITS clusters"}; + Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max. chi2/NclsTPC"}; + Configurable maxchi2its{"maxchi2its", 6.0, "max. chi2/NclsITS"}; + Configurable minpt{"minpt", 0.15, "min pt for track"}; + Configurable maxeta{"maxeta", 0.9, "eta acceptance"}; + Configurable dca_xy_max{"dca_xy_max", 1.0f, "max DCAxy in cm"}; + Configurable dca_z_max{"dca_z_max", 1.0f, "max DCAz in cm"}; + Configurable dca_3d_sigma_max{"dca_3d_sigma_max", 1e+10, "max DCA 3D in sigma"}; + Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -3.0, "min. TPC n sigma for electron inclusion"}; + Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", +4.0, "max. TPC n sigma for electron inclusion"}; + Configurable slope{"slope", 0.0185, "slope for m vs. phiv"}; + Configurable intercept{"intercept", -0.0280, "intercept for m vs. phiv"}; + Configurable mee_min{"mee_min", 0.0f, "minimum mee to distinguish photon conversion and dalitz decay"}; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + std::pair> itsRequirement = {1, {0, 1, 2}}; // any hits on 3 ITS ib layers. + + int mRunNumber; + float d_bz; + Service ccdb; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + + void init(InitContext&) + { + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + if (fillQAHistogram) { + fRegistry.add("Track/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); + fRegistry.add("Track/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); + fRegistry.add("Track/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {20, -1.0f, 1.0f}}, false); + fRegistry.add("Track/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -1.0f, 1.0f}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("Track/hDCAxyzSigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {{1000, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/hDCAzRes_Pt", "DCA_{z} resolution vs. pT;p_{T} (GeV/c);DCA_{z} resolution (#mum)", kTH2F, {{1000, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/hNclsTPC", "number of TPC clusters", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hNcrTPC", "number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("Track/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaMu", "TPC n sigma mu;p_{in} (GeV/c);n #sigma_{#mu}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaKa", "TPC n sigma ka;p_{in} (GeV/c);n #sigma_{K}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaPr", "TPC n sigma pr;p_{in} (GeV/c);n #sigma_{p}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFbeta", "TOF beta;p_{in} (GeV/c);#beta", kTH2F, {{1000, 0, 10}, {600, 0, 1.2}}, false); + fRegistry.add("Track/h1overTOFbeta", "TOF beta;p_{in} (GeV/c);1/#beta", kTH2F, {{1000, 0, 10}, {1000, 0.8, 1.8}}, false); + fRegistry.add("Track/hTOFNsigmaEl", "TOF n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaMu", "TOF n sigma mu;p_{in} (GeV/c);n #sigma_{#mu}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaPi", "TOF n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaKa", "TOF n sigma ka;p_{in} (GeV/c);n #sigma_{K}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaPr", "TOF n sigma pr;p_{in} (GeV/c);n #sigma_{p}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("Track/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("Track/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); on ITS #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {32, 0, 16}}, false); + fRegistry.add("Pair/hMvsPhiV", "mee vs. phiv;#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0, M_PI}, {100, 0, 0.1}}, false); + } + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + o2::base::Propagator::initFieldFromGRP(&grpmag); + mRunNumber = bc.runNumber(); + return; + } + + auto run3grp_timestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = bc.runNumber(); + } + + template + bool checkTrack(TTrack const& track) + { + if constexpr (isMC) { + if (!track.has_mcParticle()) { + return false; + } + } + + if (track.tpcChi2NCl() > maxchi2tpc) { + return false; + } + + if (track.itsChi2NCl() > maxchi2its) { + return false; + } + + if (!track.hasITS() || !track.hasTPC()) { + return false; + } + if (track.itsNCls() < minitsncls) { + return false; + } + + auto hits = std::count_if(itsRequirement.second.begin(), itsRequirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); + if (hits < itsRequirement.first) { + return false; + } + + if (track.tpcNClsFound() < min_ncluster_tpc) { + return false; + } + + if (track.tpcNClsCrossedRows() < mincrossedrows) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { + return false; + } + + if (abs(track.dcaXY()) > dca_xy_max || abs(track.dcaZ()) > dca_z_max) { + return false; + } + + if (track.pt() < minpt || abs(track.eta()) > maxeta) { + return false; + } + + return true; + } + + template + void fillTrackTable(TCollision const& collision, TTrack const& track) + { + if (std::find(stored_trackIds.begin(), stored_trackIds.end(), std::pair{collision.globalIndex(), track.globalIndex()}) == stored_trackIds.end()) { + gpu::gpustd::array dcaInfo; + auto track_par_cov_recalc = getTrackParCov(track); + track_par_cov_recalc.setPID(o2::track::PID::Electron); + std::array pVec_recalc = {0, 0, 0}; // px, py, pz + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, track_par_cov_recalc, 2.f, matCorr, &dcaInfo); + getPxPyPz(track_par_cov_recalc, pVec_recalc); + float dcaXY = dcaInfo[0]; + float dcaZ = dcaInfo[1]; + + float pt_recalc = track_par_cov_recalc.getPt(); + float eta_recalc = track_par_cov_recalc.getEta(); + float phi_recalc = track_par_cov_recalc.getPhi(); + + bool isAssociatedToMPC = collision.globalIndex() == track.collisionId(); + + emprimaryelectrons(collision.globalIndex(), track.globalIndex(), track.sign(), + pt_recalc, eta_recalc, phi_recalc, dcaXY, dcaZ, + track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), track.tpcNClsShared(), + track.tpcChi2NCl(), track.tpcInnerParam(), + track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaMu(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), + track.beta(), track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), + track.itsClusterSizes(), 0, 0, 0, 0, 0, + track.itsChi2NCl(), track.tofChi2(), track.detectorMap(), + track_par_cov_recalc.getX(), track_par_cov_recalc.getAlpha(), track_par_cov_recalc.getY(), track_par_cov_recalc.getZ(), track_par_cov_recalc.getSnp(), track_par_cov_recalc.getTgl(), isAssociatedToMPC); + + emprimaryelectronscov( + track_par_cov_recalc.getSigmaY2(), + track_par_cov_recalc.getSigmaZY(), + track_par_cov_recalc.getSigmaZ2(), + track_par_cov_recalc.getSigmaSnpY(), + track_par_cov_recalc.getSigmaSnpZ(), + track_par_cov_recalc.getSigmaSnp2(), + track_par_cov_recalc.getSigmaTglY(), + track_par_cov_recalc.getSigmaTglZ(), + track_par_cov_recalc.getSigmaTglSnp(), + track_par_cov_recalc.getSigmaTgl2(), + track_par_cov_recalc.getSigma1PtY(), + track_par_cov_recalc.getSigma1PtZ(), + track_par_cov_recalc.getSigma1PtSnp(), + track_par_cov_recalc.getSigma1PtTgl(), + track_par_cov_recalc.getSigma1Pt2()); + + stored_trackIds.emplace_back(std::pair{collision.globalIndex(), track.globalIndex()}); + + if (fillQAHistogram) { + uint32_t itsClusterSizes = track.itsClusterSizes(); + int total_cluster_size = 0, nl = 0; + for (unsigned int layer = 3; layer < 7; layer++) { + int cluster_size_per_layer = (itsClusterSizes >> (layer * 4)) & 0xf; + if (cluster_size_per_layer > 0) { + nl++; + } + total_cluster_size += cluster_size_per_layer; + } + + fRegistry.fill(HIST("Track/hPt"), pt_recalc); + fRegistry.fill(HIST("Track/hQoverPt"), track.sign() / pt_recalc); + fRegistry.fill(HIST("Track/hEtaPhi"), phi_recalc, eta_recalc); + fRegistry.fill(HIST("Track/hDCAxyz"), dcaXY, dcaZ); + fRegistry.fill(HIST("Track/hDCAxyzSigma"), dcaXY / sqrt(track_par_cov_recalc.getSigmaY2()), dcaZ / sqrt(track_par_cov_recalc.getSigmaZ2())); + fRegistry.fill(HIST("Track/hDCAxyRes_Pt"), pt_recalc, sqrt(track_par_cov_recalc.getSigmaY2()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hDCAzRes_Pt"), pt_recalc, sqrt(track_par_cov_recalc.getSigmaZ2()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hNclsITS"), track.itsNCls()); + fRegistry.fill(HIST("Track/hNclsTPC"), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("Track/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("Track/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("Track/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("Track/hChi2ITS"), track.itsChi2NCl()); + fRegistry.fill(HIST("Track/hITSClusterMap"), track.itsClusterMap()); + fRegistry.fill(HIST("Track/hMeanClusterSizeITS"), track.p(), static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/hTPCNsigmaMu"), track.tpcInnerParam(), track.tpcNSigmaMu()); + fRegistry.fill(HIST("Track/hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); + fRegistry.fill(HIST("Track/hTPCNsigmaKa"), track.tpcInnerParam(), track.tpcNSigmaKa()); + fRegistry.fill(HIST("Track/hTPCNsigmaPr"), track.tpcInnerParam(), track.tpcNSigmaPr()); + fRegistry.fill(HIST("Track/hTOFbeta"), track.tpcInnerParam(), track.beta()); + fRegistry.fill(HIST("Track/h1overTOFbeta"), track.tpcInnerParam(), 1. / track.beta()); + fRegistry.fill(HIST("Track/hTOFNsigmaEl"), track.tpcInnerParam(), track.tofNSigmaEl()); + fRegistry.fill(HIST("Track/hTOFNsigmaMu"), track.tpcInnerParam(), track.tofNSigmaMu()); + fRegistry.fill(HIST("Track/hTOFNsigmaPi"), track.tpcInnerParam(), track.tofNSigmaPi()); + fRegistry.fill(HIST("Track/hTOFNsigmaKa"), track.tpcInnerParam(), track.tofNSigmaKa()); + fRegistry.fill(HIST("Track/hTOFNsigmaPr"), track.tpcInnerParam(), track.tofNSigmaPr()); + } + } + } + + std::vector> stored_trackIds; + Filter trackFilter = o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& o2::aod::track::tpcChi2NCl < maxchi2tpc&& o2::aod::track::itsChi2NCl < maxchi2its&& ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true && nabs(o2::aod::track::dcaXY) < dca_xy_max&& nabs(o2::aod::track::dcaZ) < dca_z_max; + Filter pidFilter = minTPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < maxTPCNsigmaEl; + using MyFilteredTracks = soa::Filtered; + + Partition posTracks = o2::aod::track::signed1Pt > 0.f; + Partition negTracks = o2::aod::track::signed1Pt < 0.f; + + // ---------- for data ---------- + + void processRec(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const& tracks) + { + stored_trackIds.reserve(tracks.size()); + + for (auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + + if (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + continue; + } + + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); // loose track sample + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); // loose track sample + + int npair = 0; + for (auto& [pos, neg] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + + if (!checkTrack(pos) || !checkTrack(neg)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(neg.pt(), neg.eta(), neg.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float mee = v12.M(); + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pos.px(), pos.py(), pos.pz(), neg.px(), neg.py(), neg.pz(), pos.sign(), neg.sign(), d_bz); + + if (mee < mee_min || slope * phiv + intercept < mee) { // select phocon conversions + continue; + } + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/hMvsPhiV"), phiv, mee); + } + fillTrackTable(collision, pos); + fillTrackTable(collision, neg); + npair++; + } + + if (npair < 0.5) { + continue; + } + + event(collision.globalIndex(), bc.runNumber(), bc.globalBC(), collision.alias_raw(), collision.selection_raw(), collision.rct_raw(), bc.timestamp(), + collision.posX(), collision.posY(), collision.posZ(), + collision.numContrib(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + event_mult(collision.multFT0A(), collision.multFT0C(), collision.multNTracksPV(), collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf()); + event_cent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C()); + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerSecondaryElectron, processRec, "process reconstructed info only", true); // standalone + + // ---------- for MC ---------- + using MyFilteredTracksMC = soa::Filtered; + Partition posTracksMC = o2::aod::track::signed1Pt > 0.f; + Partition negTracksMC = o2::aod::track::signed1Pt < 0.f; + void processMC(MyCollisionsMC const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyFilteredTracksMC const& tracks) + { + stored_trackIds.reserve(tracks.size()); + + for (auto& collision : collisions) { + if (!collision.has_mcCollision()) { + continue; + } + auto bc = collision.bc_as(); + initCCDB(bc); + + if (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + continue; + } + + auto posTracks_per_coll = posTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); // loose track sample + auto negTracks_per_coll = negTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); // loose track sample + + int npair = 0; + for (auto& [pos, neg] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + if (!checkTrack(pos) || !checkTrack(neg)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(neg.pt(), neg.eta(), neg.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float mee = v12.M(); + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pos.px(), pos.py(), pos.pz(), neg.px(), neg.py(), neg.pz(), pos.sign(), neg.sign(), d_bz); + + if (mee < mee_min || slope * phiv + intercept < mee) { // select phocon conversions + continue; + } + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/hMvsPhiV"), phiv, mee); + } + fillTrackTable(collision, pos); + fillTrackTable(collision, neg); + npair++; + } + + if (npair < 0.5) { + continue; + } + + event(collision.globalIndex(), bc.runNumber(), bc.globalBC(), collision.alias_raw(), collision.selection_raw(), collision.rct_raw(), bc.timestamp(), + collision.posX(), collision.posY(), collision.posZ(), + collision.numContrib(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + event_mult(collision.multFT0A(), collision.multFT0C(), collision.multNTracksPV(), collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf()); + event_cent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C()); + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerSecondaryElectron, processMC, "process reconstructed and MC info ", false); +}; + +struct AssociateMCInfoSecondaryElectron { + Produces mcevents; + Produces mceventlabels; + Produces emmcparticles; + Produces emprimaryelectronmclabels; + + HistogramRegistry registry{"EMMCEvent"}; + void init(o2::framework::InitContext&) + { + auto hEventCounter = registry.add("hEventCounter", "hEventCounter", kTH1I, {{6, 0.5f, 6.5f}}); + hEventCounter->GetXaxis()->SetBinLabel(1, "all"); + hEventCounter->GetXaxis()->SetBinLabel(2, "has mc collision"); + } + + void processMC(MyCollisionsMC const& collisions, aod::McCollisions const&, aod::McParticles const& mcTracks, MyTracksMC const& o2tracks, aod::EMEvents const& emevents, aod::EMPrimaryElectrons const& emprimaryelectrons) + { + // temporary variables used for the indexing of the skimmed MC stack + std::map fNewLabels; + std::map fNewLabelsReversed; + // std::map fMCFlags; + std::map fEventIdx; + std::map fEventLabels; + int fCounters[2] = {0, 0}; //! [0] - particle counter, [1] - event counter + + for (auto& emevent : emevents) { + registry.fill(HIST("hEventCounter"), 1); + auto collision = collisions.iteratorAt(emevent.collisionId()); + auto mcCollision = collision.mcCollision(); + + if (!(fEventLabels.find(mcCollision.globalIndex()) != fEventLabels.end())) { + mcevents(mcCollision.globalIndex(), mcCollision.generatorsID(), mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.impactParameter(), mcCollision.eventPlaneAngle()); + fEventLabels[mcCollision.globalIndex()] = fCounters[1]; + fCounters[1]++; + } + + mceventlabels(fEventLabels.find(mcCollision.globalIndex())->second, collision.mcMask()); + } // end of reconstructed collision loop + + for (auto& emprimaryelectron : emprimaryelectrons) { + auto collision_from_el = collisions.iteratorAt(emprimaryelectron.collisionId()); + if (!collision_from_el.has_mcCollision()) { + continue; + } + auto mcCollision_from_el = collision_from_el.mcCollision(); + + auto o2track = o2tracks.iteratorAt(emprimaryelectron.trackId()); + if (!o2track.has_mcParticle()) { + continue; // If no MC particle is found, skip the dilepton + } + auto mctrack = o2track.template mcParticle_as(); + + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mctrack.globalIndex()) != fNewLabels.end())) { + fNewLabels[mctrack.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); + // fMCFlags[mctrack.globalIndex()] = mcflags; + fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mcCollision_from_el.globalIndex())->second; + fCounters[0]++; + } + emprimaryelectronmclabels(fNewLabels.find(mctrack.index())->second, o2track.mcMask()); + + // Next, store mother-chain of this reconstructed track. + int motherid = -999; // first mother index + if (mctrack.has_mothers()) { + motherid = mctrack.mothersIds()[0]; // first mother index + } + while (motherid > -1) { + if (motherid < mcTracks.size()) { // protect against bad mother indices. why is this needed? + auto mp = mcTracks.iteratorAt(motherid); + + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mp.globalIndex()) != fNewLabels.end())) { + fNewLabels[mp.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); + // fMCFlags[mp.globalIndex()] = mcflags; + fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollision_from_el.globalIndex())->second; + fCounters[0]++; + } + + if (mp.has_mothers()) { + motherid = mp.mothersIds()[0]; // first mother index + } else { + motherid = -999; + } + } else { + motherid = -999; + } + } // end of mother chain loop + + } // end of em primary electron loop + + // Loop over the label map, create the mother/daughter relationships if these exist and write the skimmed MC stack + for (const auto& [newLabel, oldLabel] : fNewLabelsReversed) { + auto mctrack = mcTracks.iteratorAt(oldLabel); + // uint16_t mcflags = fMCFlags.find(oldLabel)->second; + + std::vector mothers; + if (mctrack.has_mothers()) { + for (auto& m : mctrack.mothersIds()) { + if (m < mcTracks.size()) { // protect against bad mother indices + if (fNewLabels.find(m) != fNewLabels.end()) { + mothers.push_back(fNewLabels.find(m)->second); + } + } else { + std::cout << "Mother label (" << m << ") exceeds the McParticles size (" << mcTracks.size() << ")" << std::endl; + std::cout << " Check the MC generator" << std::endl; + } + } + } + + // Note that not all daughters from the original table are preserved in the skimmed MC stack + std::vector daughters; + if (mctrack.has_daughters()) { + // int ndau = mctrack.daughtersIds()[1] - mctrack.daughtersIds()[0] + 1; + // LOGF(info, "daughter range in original MC stack pdg = %d | %d - %d , n dau = %d", mctrack.pdgCode(), mctrack.daughtersIds()[0], mctrack.daughtersIds()[1], mctrack.daughtersIds()[1] -mctrack.daughtersIds()[0] +1); + for (int d = mctrack.daughtersIds()[0]; d <= mctrack.daughtersIds()[1]; ++d) { + // TODO: remove this check as soon as issues with MC production are fixed + if (d < mcTracks.size()) { // protect against bad daughter indices + // auto dau_tmp = mcTracks.iteratorAt(d); + // // LOGF(info, "daughter pdg = %d", dau_tmp.pdgCode()); + // if ((mctrack.pdgCode() == 223 || mctrack.pdgCode() == 333) && (mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { + // if (fNewLabels.find(d) == fNewLabels.end() && (abs(dau_tmp.pdgCode()) == 11 || abs(dau_tmp.pdgCode()) == 13)) { + // LOGF(info, "daughter lepton is not found mctrack.globalIndex() = %d, mctrack.producedByGenerator() == %d, ndau = %d | dau_tmp.globalIndex() = %d, dau_tmp.pdgCode() = %d, dau_tmp.producedByGenerator() = %d, dau_tmp.pt() = %f, dau_tmp.eta() = %f, dau_tmp.phi() = %f", mctrack.globalIndex(), mctrack.producedByGenerator(), ndau, dau_tmp.globalIndex(), dau_tmp.pdgCode(), dau_tmp.producedByGenerator(), dau_tmp.pt(), dau_tmp.eta(), dau_tmp.phi()); + // } + // } + + if (fNewLabels.find(d) != fNewLabels.end()) { + daughters.push_back(fNewLabels.find(d)->second); + } + } else { + std::cout << "Daughter label (" << d << ") exceeds the McParticles size (" << mcTracks.size() << ")" << std::endl; + std::cout << " Check the MC generator" << std::endl; + } + } + } + + emmcparticles(fEventIdx.find(oldLabel)->second, mctrack.pdgCode(), mctrack.flags(), + mothers, daughters, + mctrack.px(), mctrack.py(), mctrack.pz(), mctrack.e(), + mctrack.vx(), mctrack.vy(), mctrack.vz()); + + mothers.clear(); + mothers.shrink_to_fit(); + daughters.clear(); + daughters.shrink_to_fit(); + } // end loop over labels + + fNewLabels.clear(); + fNewLabelsReversed.clear(); + // fMCFlags.clear(); + fEventIdx.clear(); + fEventLabels.clear(); + fCounters[0] = 0; + fCounters[1] = 0; + } + + void processDummy(MyCollisions const&) {} + + PROCESS_SWITCH(AssociateMCInfoSecondaryElectron, processMC, "create em mc event table for Electron", false); + PROCESS_SWITCH(AssociateMCInfoSecondaryElectron, processDummy, "processDummy", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"skimmer-secondary-electron"}), + adaptAnalysisTask(cfgc, TaskName{"associate-mc-info-secondary-electron"}), + }; +} diff --git a/PWGEM/Dilepton/TableProducer/treeCreatorElectronML.cxx b/PWGEM/Dilepton/TableProducer/treeCreatorElectronML.cxx index 84eb7ef3479..7643f79a984 100644 --- a/PWGEM/Dilepton/TableProducer/treeCreatorElectronML.cxx +++ b/PWGEM/Dilepton/TableProducer/treeCreatorElectronML.cxx @@ -14,6 +14,10 @@ // This code will create data table for inputs to machine learning for electrons. // Please write to: daiki.sekihata@cern.ch +#include +#include +#include +#include #include "Math/Vector4D.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -32,8 +36,11 @@ #include "DetectorsBase/GeometryManager.h" #include "DataFormatsParameters/GRPObject.h" #include "DataFormatsParameters/GRPMagField.h" +#include "DCAFitter/DCAFitterN.h" #include "CCDB/BasicCCDBManager.h" #include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" using namespace o2; using namespace o2::framework; @@ -61,10 +68,9 @@ DECLARE_SOA_COLUMN(MCPosY, mcposY, float); //! DECLARE_SOA_COLUMN(MCPosZ, mcposZ, float); //! } // namespace mycollision DECLARE_SOA_TABLE(MyCollisions, "AOD", "MYCOLLISION", //! vertex information of collision - o2::soa::Index<>, bc::GlobalBC, bc::RunNumber, collision::PosX, collision::PosY, collision::PosZ, collision::NumContrib, evsel::Sel8, mycollision::Bz, - mccollision::GeneratorsID, mycollision::MCPosX, mycollision::MCPosY, mycollision::MCPosZ, - mult::MultTPC, mult::MultFV0A, mult::MultFV0C, mult::MultFT0A, mult::MultFT0C, - mult::MultFDDA, mult::MultFDDC, mult::MultZNA, mult::MultZNC, mult::MultTracklets, mult::MultNTracksPV, mult::MultNTracksPVeta1); + o2::soa::Index<>, bc::GlobalBC, bc::RunNumber, collision::PosX, collision::PosY, collision::PosZ, collision::NumContrib, evsel::NumTracksInTimeRange, evsel::SumAmpFT0CInTimeRange, evsel::Sel8, mycollision::Bz, + mccollision::GeneratorsID, mycollision::MCPosX, mycollision::MCPosY, mycollision::MCPosZ, mult::MultNTracksPV, + cent::CentFT0M, cent::CentFT0A, cent::CentFT0C); using MyCollision = MyCollisions::iterator; namespace mytrack @@ -86,13 +92,13 @@ DECLARE_SOA_COLUMN(MotherPdgCodes, motherpdgCodes, std::vector); //! eta va // reconstructed track information DECLARE_SOA_TABLE(MyTracks, "AOD", "MYTRACK", //! o2::soa::Index<>, mytrack::MyCollisionId, mytrack::Sign, - track::Pt, track::Eta, track::Phi, - track::DcaXY, track::DcaZ, mytrack::DCAresXY, mytrack::DCAresZ, + track::Pt, track::Eta, track::Phi, track::Tgl, + track::DcaXY, track::DcaZ, mytrack::DCAresXY, mytrack::DCAresZ, track::CZY, track::TPCNClsFindable, mytrack::TPCNClsFound, mytrack::TPCNClsCrossedRows, track::TPCChi2NCl, track::TPCInnerParam, track::TPCSignal, pidtpc::TPCNSigmaEl, pidtpc::TPCNSigmaMu, pidtpc::TPCNSigmaPi, pidtpc::TPCNSigmaKa, pidtpc::TPCNSigmaPr, pidtofbeta::Beta, pidtof::TOFNSigmaEl, pidtof::TOFNSigmaMu, pidtof::TOFNSigmaPi, pidtof::TOFNSigmaKa, pidtof::TOFNSigmaPr, - track::ITSClusterMap, track::ITSChi2NCl, + track::TOFChi2, track::ITSChi2NCl, track::ITSClusterSizes, mytrack::MCVx, mytrack::MCVy, mytrack::MCVz, mcparticle::PdgCode, mytrack::IsPhysicalPrimary, mytrack::MotherIds, mytrack::MotherPdgCodes); @@ -112,19 +118,23 @@ DECLARE_SOA_COLUMN(Phi, phi, float); //! DECLARE_SOA_COLUMN(PhiV, phiv, float); //! DECLARE_SOA_COLUMN(PairDCAxy, pairDCAxy, float); //! DECLARE_SOA_COLUMN(PairDCAz, pairDCAz, float); //! - -DECLARE_SOA_COLUMN(IsSM, isSM, bool); //! -DECLARE_SOA_COLUMN(IsHF, isHF, int); //! -DECLARE_SOA_COLUMN(PairType, pairtype, int); //! -DECLARE_SOA_COLUMN(IsPrompt, isPrompt, bool); //! +DECLARE_SOA_COLUMN(CosOpAng, cosOpAng, float); //! +DECLARE_SOA_COLUMN(CosPA, cosPA, float); //! +DECLARE_SOA_COLUMN(Lxy, lxy, float); //! +DECLARE_SOA_COLUMN(Chi2PCA, chi2PCA, float); //! +DECLARE_SOA_COLUMN(IsSM, isSM, bool); //! +DECLARE_SOA_COLUMN(IsHF, isHF, int); //! +DECLARE_SOA_COLUMN(PairType, pairtype, int); //! +DECLARE_SOA_COLUMN(IsPrompt, isPrompt, bool); //! } // namespace mypair // reconstructed track information DECLARE_SOA_TABLE(MyPairs, "AOD", "MYPAIR", //! o2::soa::Index<>, mypair::MyCollisionId, mypair::PosTrackId, mypair::NegTrackId, mypair::Mass, mypair::Pt, mypair::Eta, mypair::Phi, mypair::PhiV, mypair::PairDCAxy, mypair::PairDCAz, + mypair::CosOpAng, mypair::CosPA, mypair::Lxy, mypair::Chi2PCA, mypair::IsSM, mypair::IsHF, mypair::PairType, mypair::IsPrompt, - mcparticle::PdgCode, mcparticle::StatusCode, mcparticle::Flags, + mcparticle::PdgCode, mcparticle::Flags, mcparticle::Vx, mcparticle::Vy, mcparticle::Vz, // dynamic column @@ -155,53 +165,143 @@ struct TreeCreatorElectronML { HistogramRegistry registry{ "registry", { - {"hEventCounter", "hEventCounter", {HistType::kTH1F, {{5, 0.5f, 5.5f}}}}, + {"hEventCounter", "hEventCounter", {HistType::kTH1F, {{2, 0.f, 2.f}}}}, }, }; // Configurables + + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; + Configurable d_UseAbsDCA{"d_UseAbsDCA", true, "Use Abs DCAs"}; + Configurable d_UseWeightedPCA{"d_UseWeightedPCA", false, "Vertices use cov matrices"}; + Configurable useMatCorrType{"useMatCorrType", 0, "0: none, 1: TGeo, 2: LUT"}; + + // collision + Configurable maxVtxZ{"maxVtxZ", 10.0, "max VtxZ [cm]"}; + Configurable maxTrackOccupancy{"maxTrackOccupancy", 999999, "max. track occupancy"}; + Configurable maxFT0Occupancy{"maxFT0Occupancy", 999999., "max. FT0 occupancy"}; + + // track Configurable mincrossedrows{"mincrossedrows", 70, "min. crossed rows"}; + Configurable mintpcclusters{"mintpcclusters", 90, "min. tpc clusters"}; Configurable maxchi2tpc{"maxchi2tpc", 4.0, "max. chi2/NclsTPC"}; + Configurable maxchi2its{"maxchi2its", 5.0, "max. chi2/NclsITS"}; Configurable maxeta{"maxeta", 0.9, "eta acceptance"}; + Configurable minpt{"minpt", 0.2, "min. pT"}; + Configurable maxDcaZ{"maxDcaZ", 1.0, "max DCA Z"}; + Configurable maxDcaXY{"maxDcaXY", 1.0, "max DCA XY"}; + Configurable minITSClusters{"minITSLayers", 5, "min. of ITS clusters"}; + Configurable minITSClustersIB{"minITSClustersIB", 3, "min. number of ITS clusters in inner barrel"}; + Configurable downSampleEl{"downSampleEl", 1.0, "down scaling factor for electrons"}; + Configurable downSamplePi{"downSamplePi", 1.0, "down scaling factor for pions"}; + Configurable downSampleKa{"downSampleKa", 1.0, "down scaling factor for kaons"}; + Configurable downSamplePr{"downSamplePr", 1.0, "down scaling factor for protons"}; + Configurable downSampleMu{"downSampleMu", 1.0, "down scaling factor for muons"}; + Configurable downSampleNucl{"downSampleNucl", 1.0, "down scaling factor for nuclei"}; + + // pid + Configurable maxNSigmaElTPC{"maxNSigmaElTPC", 999, "max nsigma_el for TPC"}; + Configurable maxNSigmaElTOF{"maxNSigmaElTOF", 999, "max nsgima_el for TOF (if available)"}; + + // pair + Configurable minPairPt{"minPairPt", 0.2, "min. pT,ee"}; + Configurable minMass{"minMass", 0.0, "min. pair invariant mass"}; + Configurable maxMass{"maxMass", 9999.0, "max. pair invariant mass"}; Configurable doLS{"doLS", true, "process also LS spectra"}; Configurable combBgReductionFactor{"combBgReductionFactor", 1.0, "reduction factor for combinatorial background"}; - Configurable singleTrackBgReductionFactor{"singleTrackBgReductionFactor", 1.0, "reduction factor for background"}; int mRunNumber; float d_bz; + o2::vertexing::DCAFitterN<2> fitter; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + o2::base::MatLayerCylSet* lut = nullptr; Service ccdb; + + std::mt19937 engine; + std::uniform_real_distribution dist01; + void init(InitContext&) { + + std::random_device seed_gen; + engine = std::mt19937(seed_gen()); + dist01 = std::uniform_real_distribution(0.0f, 1.0f); + mRunNumber = 0; d_bz = 0; ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); + + if (useMatCorrType == 1) { + LOGF(info, "TGeo correction requested, loading geometry"); + if (!o2::base::GeometryManager::isGeometryLoaded()) { + ccdb->get(geoPath); + } + } + if (useMatCorrType == 2) { + LOGF(info, "LUT correction requested, loading LUT"); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); + } + + fitter.setPropagateToPCA(true); + fitter.setMaxR(200.); + fitter.setMinParamChange(1e-3); + fitter.setMinRelChi2Change(0.9); + fitter.setMaxDZIni(1e9); + fitter.setMaxChi2(1e9); + fitter.setUseAbsDCA(d_UseAbsDCA); + fitter.setWeightedFinalPCA(d_UseWeightedPCA); + + if (useMatCorrType == 1) { + matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; + } else if (useMatCorrType == 2) { + matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + } + fitter.setMatCorrType(matCorr); } - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + template + void initCCDB(TBC const& bc) { if (mRunNumber == bc.runNumber()) { return; } + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + fitter.setBz(d_bz); + o2::parameters::GRPMagField grpmag; + if (fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + o2::base::Propagator::initFieldFromGRP(&grpmag); + mRunNumber = bc.runNumber(); + return; + } + auto run3grp_timestamp = bc.timestamp(); - o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp("GLO/GRP/GRP", run3grp_timestamp); + o2::parameters::GRPObject* grpo = 0x0; o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); if (grpo) { o2::base::Propagator::initFieldFromGRP(grpo); // Fetch magnetic field from ccdb for current collision d_bz = grpo->getNominalL3Field(); LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; } else { - grpmag = ccdb->getForTimeStamp("GLO/Config/GRPMagField", run3grp_timestamp); + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " - << "GLO/Config/GRPMagField" - << " of object GRPMagField and " - << "GLO/GRP/GRP" - << " of object GRPObject for timestamp " << run3grp_timestamp; + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; } o2::base::Propagator::initFieldFromGRP(grpmag); // Fetch magnetic field from ccdb for current collision @@ -209,102 +309,13 @@ struct TreeCreatorElectronML { LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; } mRunNumber = bc.runNumber(); - } - - template - float get_phiv(TTrack const& t1, TTrack const& t2) - { - // cos(phiv) = w*a /|w||a| - // with w = u x v - // and a = u x z / |u x z| , unit vector perpendicular to v12 and z-direction (magnetic field) - // u = v12 / |v12| , the unit vector of v12 - // v = v1 x v2 / |v1 x v2| , unit vector perpendicular to v1 and v2 - - // float bz = fgFitterTwoProngBarrel.getBz(); + // Set magnetic field value once known + fitter.setBz(d_bz); - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - - bool swapTracks = false; - if (v1.Pt() < v2.Pt()) { // ordering of track, pt1 > pt2 - ROOT::Math::PtEtaPhiMVector v3 = v1; - v1 = v2; - v2 = v3; - swapTracks = true; - } - - // momentum of e+ and e- in (ax,ay,az) axis. Note that az=0 by definition. - // vector product of pep X pem - float vpx = 0, vpy = 0, vpz = 0; - if (t1.sign() * t2.sign() > 0) { // Like Sign - if (!swapTracks) { - if (d_bz * t1.sign() < 0) { - vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); - vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); - vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); - } else { - vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); - vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); - vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); - } - } else { // swaped tracks - if (d_bz * t2.sign() < 0) { - vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); - vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); - vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); - } else { - vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); - vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); - vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); - } - } - } else { // Unlike Sign - if (!swapTracks) { - if (d_bz * t1.sign() > 0) { - vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); - vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); - vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); - } else { - vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); - vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); - vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); - } - } else { // swaped tracks - if (d_bz * t2.sign() > 0) { - vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); - vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); - vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); - } else { - vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); - vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); - vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); - } - } + if (useMatCorrType == 2) { + // setMatLUT only after magfield has been initalized (setMatLUT has implicit and problematic init field call if not) + o2::base::Propagator::Instance()->setMatLUT(lut); } - - // unit vector of pep X pem - float vx = vpx / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); - float vy = vpy / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); - float vz = vpz / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); - - float px = v12.Px(); - float py = v12.Py(); - float pz = v12.Pz(); - - // unit vector of (pep+pem) - float ux = px / TMath::Sqrt(px * px + py * py + pz * pz); - float uy = py / TMath::Sqrt(px * px + py * py + pz * pz); - float uz = pz / TMath::Sqrt(px * px + py * py + pz * pz); - float ax = uy / TMath::Sqrt(ux * ux + uy * uy); - float ay = -ux / TMath::Sqrt(ux * ux + uy * uy); - - // The third axis defined by vector product (ux,uy,uz)X(vx,vy,vz) - float wx = uy * vz - uz * vy; - float wy = uz * vx - ux * vz; - // by construction, (wx,wy,wz) must be a unit vector. Measure angle between (wx,wy,wz) and (ax,ay,0). - // The angle between them should be small if the pair is conversion. This function then returns values close to pi! - return TMath::ACos(wx * ax + wy * ay); // phiv in [0,pi] //cosPhiV = wx * ax + wy * ay; } template @@ -359,352 +370,456 @@ struct TreeCreatorElectronML { if (track.tpcNClsCrossedRows() < mincrossedrows) { return false; } + if (track.tpcNClsFound() < mintpcclusters) { + return false; + } if (track.itsChi2NCl() < -1) { // if tracks are not reconstructed properly, chi2/ITSncls is set to -999; return false; } + if (track.itsNCls() < minITSClusters) { + return false; + } + if (track.itsNClsInnerBarrel() < minITSClustersIB) { + return false; + } + + if (fabs(track.tpcNSigmaEl()) > maxNSigmaElTPC) { + return false; + } + if (track.hasTOF()) { + if (fabs(track.tofNSigmaEl()) > maxNSigmaElTOF) { + return false; + } + } + return true; + } + + template + bool IsSelectedPair(TMom const& v12) + { + if (v12.Pt() < minPairPt) { + return false; + } + if (v12.M() < minMass) { + return false; + } + if (v12.M() > maxMass) { + return false; + } return true; } - Filter trackFilter = nabs(o2::aod::track::eta) < maxeta && o2::aod::track::tpcChi2NCl < maxchi2tpc && nabs(o2::aod::track::dcaXY) < 1.f && nabs(o2::aod::track::dcaZ) < 1.f; + bool downSample(int pdg) + { // pdg=0: combinatorial background for pairs + float factor = 1.; + switch (pdg) { + case 11: + factor = downSampleEl; + break; + case 211: + factor = downSamplePi; + break; + case 321: + factor = downSampleKa; + break; + case 2212: + factor = downSamplePr; + break; + case 13: + factor = downSampleMu; + break; + case 0: + factor = combBgReductionFactor; + break; + default: + factor = downSampleNucl; + } + if (dist01(engine) <= factor) { + return true; + } + return false; + } + + template + void doPair(TTrack const& t1, TTrack const& t2, int mc1_id, int mc2_id, int pairtype, TMCParticles const& mctracks, TCollision const& collision, std::map& fNewLabels, std::vector& fSelected_old_labels, int& fCounter, uint64_t collisionId, std::vector& collisions_old_labels, int& collisions_counter) + { + if (!IsSelected(t1) || !IsSelected(t2)) { + return; + } + + auto mc1 = mctracks.iteratorAt(mc1_id); + auto mc2 = mctracks.iteratorAt(mc2_id); + + if (abs(mc1.pdgCode()) != 11 || abs(mc2.pdgCode()) != 11) { + return; + } // charge swap is accepted. + + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + + if (!IsSelectedPair(v12)) { + return; + } + + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), d_bz); + float pair_dca_xy = sqrt((pow(t1.dcaXY() / sqrt(t1.cYY()), 2) + pow(t2.dcaXY() / sqrt(t2.cYY()), 2)) / 2.); + float pair_dca_z = sqrt((pow(t1.dcaZ() / sqrt(t1.cZZ()), 2) + pow(t2.dcaZ() / sqrt(t2.cZZ()), 2)) / 2.); + + float cosOpAng = (v1.Px() * v2.Px() + v1.Py() * v2.Py() + v1.Pz() * v2.Pz()) / sqrt((v1.Px() * v1.Px() + v1.Py() * v1.Py() + v1.Pz() * v1.Pz()) * (v2.Px() * v2.Px() + v2.Py() * v2.Py() + v2.Pz() * v2.Pz())); + float pca = 999.f; + float lxy = 999.f; + float cosPA = 999.f; + o2::aod::pwgem::dilepton::utils::pairutil::isSVFound(fitter, collision, t1, t1, pca, lxy, cosPA); + float lxy_proper = lxy * v12.M() / v12.Pt(); + + bool isSM = false; + int isHF = o2::aod::pwgem::dilepton::utils::mcutil::IsHF(mc1, mc2, mctracks); // if isHF == true, pdgCode is set to 0, because this pair is correlated HF ee pair decayed from different 2 mothers. Check pdg code of legs. + + bool is_prompt = false; + int pdgCode = 0; + uint8_t flags = 0; + float vx = 0.f; + float vy = 0.f; + float vz = 0.f; + bool is_comb_bg = false; + if (pairtype == EM_EEPairType::kULS) { + int common_mother_id = FindCommonMotherFrom2Prongs(mc1, mc2, mctracks); + if (common_mother_id > 0) { + isSM = true; + } + if (isSM) { + auto mcpair = mctracks.iteratorAt(common_mother_id); + is_prompt = true; // only relevant for prompt jpsi + pdgCode = mcpair.pdgCode(); + flags = mcpair.flags(); + vx = mcpair.vx(); + vy = mcpair.vy(); + vz = mcpair.vz(); + + int motherid_pair = mcpair.mothersIds()[0]; // first mother index + while (motherid_pair > -1) { + if (motherid_pair < mctracks.size()) { // protect against bad mother indices. why is this needed? + auto mp = mctracks.iteratorAt(motherid_pair); + + if (std::to_string(mp.pdgCode()).find("5") != std::string::npos) { + is_prompt = false; + break; + } + + if (mp.has_mothers()) { + motherid_pair = mp.mothersIds()[0]; + } else { + motherid_pair = -999; + } + } else { + LOGF(info, "Mother label(%d) exceeds the McParticles size(%d)", motherid_pair, mctracks.size()); + } + } + } else if (isHF == static_cast(o2::aod::pwgem::dilepton::utils::mcutil::EM_HFeeType::kUndef)) { + is_comb_bg = true; + } + } else { // LS + if (isHF == static_cast(o2::aod::pwgem::dilepton::utils::mcutil::EM_HFeeType::kUndef)) { + is_comb_bg = true; + } + } + + if (!is_comb_bg || downSample(0)) { + if (!(fNewLabels.find(t1.globalIndex()) != fNewLabels.end())) { + fNewLabels[t1.globalIndex()] = fCounter; + fSelected_old_labels.push_back(t1.globalIndex()); + fCounter++; + } + if (!(fNewLabels.find(t2.globalIndex()) != fNewLabels.end())) { + fNewLabels[t2.globalIndex()] = fCounter; + fSelected_old_labels.push_back(t2.globalIndex()); + fCounter++; + } + if (find(collisions_old_labels.begin(), collisions_old_labels.end(), collisionId) == collisions_old_labels.end()) { + collisions_counter++; + collisions_old_labels.push_back(collisionId); + } + mypair(collisions_counter, fNewLabels[t1.globalIndex()], fNewLabels[t2.globalIndex()], + v12.M(), v12.Pt(), v12.Eta(), v12.Phi(), phiv, pair_dca_xy, pair_dca_z, cosOpAng, cosPA, lxy_proper, pow(pca, 2), + isSM, isHF, pairtype, is_prompt, pdgCode, flags, + vx, vy, vz); + } + } + + template + void doSingleTrack(TTrack& track, TMCParticle& mctrack, TMCParticles& mctracks, uint64_t collisionId, std::vector& collisions_old_labels, int& collisions_counter, bool use_downsample = true) + { + if (!IsSelected(track)) { + return; + } + + if ((!use_downsample) || (downSample(abs(mctrack.pdgCode())))) { + // store all mother relation + std::vector mothers_id; + std::vector mothers_pdg; + if (mctrack.has_mothers()) { + int motherid = mctrack.mothersIds()[0]; // first mother index + while (motherid > -1) { + if (motherid < mctracks.size()) { // protect against bad mother indices. why is this needed? + auto mp = mctracks.iteratorAt(motherid); + mothers_id.emplace_back(motherid); + mothers_pdg.emplace_back(mp.pdgCode()); + + if (mp.has_mothers()) { + motherid = mp.mothersIds()[0]; + } else { + motherid = -999; + } + } else { + LOGF(info, "Mother label(%d) exceeds the McParticles size(%d)", motherid, mctracks.size()); + } + } + } + if (find(collisions_old_labels.begin(), collisions_old_labels.end(), collisionId) == collisions_old_labels.end()) { + collisions_counter++; + collisions_old_labels.push_back(collisionId); + } + mytrack(collisions_counter, + track.sign(), track.pt(), track.eta(), track.phi(), track.tgl(), track.dcaXY(), track.dcaZ(), sqrt(track.cYY()), sqrt(track.cZZ()), track.cZY(), + track.tpcNClsFindable(), track.tpcNClsFound(), track.tpcNClsCrossedRows(), + track.tpcChi2NCl(), track.tpcInnerParam(), + track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaMu(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), + track.beta(), track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), + track.tofChi2(), track.itsChi2NCl(), track.itsClusterSizes(), + mctrack.vx(), mctrack.vy(), mctrack.vz(), + mctrack.pdgCode(), mctrack.isPhysicalPrimary(), mothers_id, mothers_pdg); + + mothers_id.shrink_to_fit(); + mothers_pdg.shrink_to_fit(); + } + } + + template + void doCollision(TCollision& collision, TMCCollision& mccollision, uint64_t globalBC, int runNumber) + { + registry.fill(HIST("hEventCounter"), 1.5); + mycollision(globalBC, runNumber, collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange(), collision.sel8(), d_bz, + mccollision.generatorsID(), mccollision.posX(), mccollision.posY(), mccollision.posZ(), + collision.multNTracksPV(), collision.centFT0M(), collision.centFT0A(), collision.centFT0C()); + } + + template + void doCollision(TCollision& collision, TBC& bc, TMCCollision& mccollision) + { + doCollision(collision, mccollision, bc.globalBC(), bc.runNumber()); + } + + Filter trackFilter = o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& o2::aod::track::itsChi2NCl < maxchi2its&& o2::aod::track::tpcChi2NCl < maxchi2tpc&& nabs(o2::aod::track::dcaXY) < maxDcaXY&& nabs(o2::aod::track::dcaZ) < maxDcaZ; using MyFilteredTracksMC = soa::Filtered; Preslice perCollision = aod::track::collisionId; - void processSingleTrack(soa::Join const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracksMC const& tracks, aod::McParticles const& mctracks, aod::McCollisions const&) + Filter collisionFilter = nabs(o2::aod::collision::posZ) < maxVtxZ && o2::aod::evsel::trackOccupancyInTimeRange < maxTrackOccupancy && o2::aod::evsel::ft0cOccupancyInTimeRange < maxFT0Occupancy; + using MyFilteredCollisions = soa::Filtered>; + + void processSingleTrack(MyFilteredCollisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracksMC const& tracks, aod::McParticles const& mctracks, aod::McCollisions const&) { + int collisions_counter = -1; + std::vector collisions_old_labels; + for (auto& collision : collisions) { - // TODO: investigate the collisions without corresponding mcCollision if (!collision.has_mcCollision()) { continue; } - - registry.fill(HIST("hEventCounter"), 1.0); // all - - auto bc = collision.bc_as(); - auto mccollision = collision.mcCollision(); - mycollision(bc.globalBC(), bc.runNumber(), collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), collision.sel8(), d_bz, - mccollision.generatorsID(), mccollision.posX(), mccollision.posY(), mccollision.posZ(), - collision.multTPC(), collision.multFV0A(), collision.multFV0C(), collision.multFT0A(), collision.multFT0C(), - collision.multFDDA(), collision.multFDDC(), collision.multZNA(), collision.multZNC(), collision.multTracklets(), collision.multNTracksPV(), collision.multNTracksPVeta1()); + registry.fill(HIST("hEventCounter"), 0.5); auto tracks_coll = tracks.sliceBy(perCollision, collision.globalIndex()); for (auto& track : tracks_coll) { - - if (!IsSelected(track)) { - continue; - } - if (!track.has_mcParticle()) { - continue; // If no MC particle is found, skip the track + continue; } auto mctrack = track.mcParticle_as(); + doSingleTrack(track, mctrack, mctracks, collision.globalIndex(), collisions_old_labels, collisions_counter); + } + } - // store all mother relation - std::vector mothers_id; - std::vector mothers_pdg; - if (mctrack.has_mothers()) { - int motherid = mctrack.mothersIds()[0]; // first mother index - while (motherid > -1) { - if (motherid < mctracks.size()) { // protect against bad mother indices. why is this needed? - auto mp = mctracks.iteratorAt(motherid); - mothers_id.emplace_back(motherid); - mothers_pdg.emplace_back(mp.pdgCode()); - - if (mp.has_mothers()) { - motherid = mp.mothersIds()[0]; - } else { - motherid = -999; - } - } else { - LOGF(info, "Mother label(%d) exceeds the McParticles size(%d)", motherid, mctracks.size()); - } - } - } + for (uint64_t collision_label : collisions_old_labels) { + auto collision = collisions.rawIteratorAt(collision_label); + auto bc = collision.bc_as(); + auto mccollision = collision.mcCollision(); + doCollision(collision, bc, mccollision); + } + } + PROCESS_SWITCH(TreeCreatorElectronML, processSingleTrack, "produce ML input for single track level", false); + + using MyFilteredCollisionsSkimmed = soa::Filtered>; + using MyFilteredTracksMCSkimmed = soa::Filtered>; + Preslice perCollisionSkimmed = aod::emprimaryelectron::emeventId; + + void processSingleTrackSkimmed(MyFilteredCollisionsSkimmed const& collisions, MyFilteredTracksMCSkimmed const& tracks, aod::EMMCParticles const& mctracks, aod::EMMCEvents const&) + { + int collisions_counter = -1; + std::vector collisions_old_labels; + + for (auto& collision : collisions) { + if (!collision.has_emmcevent()) { + continue; + } + registry.fill(HIST("hEventCounter"), 0.5); - int pdgCode = mctrack.pdgCode(); - double pt = track.pt(); - double pseudoRndm = pt * 1000. - (int16_t)(pt * 1000); - if (abs(pdgCode) == 11 || pseudoRndm <= singleTrackBgReductionFactor) { - mytrack(mycollision.lastIndex(), - track.sign(), pt, track.eta(), track.phi(), track.dcaXY(), track.dcaZ(), sqrt(track.cYY()), sqrt(track.cZZ()), - track.tpcNClsFindable(), track.tpcNClsFound(), track.tpcNClsCrossedRows(), - track.tpcChi2NCl(), track.tpcInnerParam(), - track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaMu(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), - track.beta(), track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), - track.itsClusterMap(), track.itsChi2NCl(), - mctrack.vx(), mctrack.vy(), mctrack.vz(), - pdgCode, mctrack.isPhysicalPrimary(), mothers_id, mothers_pdg); + auto tracks_coll = tracks.sliceBy(perCollisionSkimmed, collision.globalIndex()); + for (auto& track : tracks_coll) { + if (!track.has_emmcparticle()) { + continue; } - mothers_id.shrink_to_fit(); - mothers_pdg.shrink_to_fit(); + auto mctrack = track.emmcparticle_as(); + doSingleTrack(track, mctrack, mctracks, collision.globalIndex(), collisions_old_labels, collisions_counter); + } + } - } // end of track loop - } // end of collision loop - } // end of process - PROCESS_SWITCH(TreeCreatorElectronML, processSingleTrack, "produce ML input for single track level", false); + for (uint64_t collision_label : collisions_old_labels) { + auto collision = collisions.rawIteratorAt(collision_label); + auto mccollision = collision.emmcevent(); + doCollision(collision, mccollision, collision.globalBC(), collision.runNumber()); + } + } + PROCESS_SWITCH(TreeCreatorElectronML, processSingleTrackSkimmed, "produce ML input for single track level on skimmed data", false); Partition posTracks = o2::aod::track::signed1Pt > 0.f; Partition negTracks = o2::aod::track::signed1Pt < 0.f; - void processPair(soa::Join const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracksMC const& tracks, aod::McParticles const& mctracks, aod::McCollisions const&) + void processPair(MyFilteredCollisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracksMC const& tracks, aod::McParticles const& mctracks, aod::McCollisions const&) { std::map fNewLabels; int fCounter = 0; + std::vector collisions_old_labels; + int collisions_counter = -1; + for (auto& collision : collisions) { - // TODO: investigate the collisions without corresponding mcCollision if (!collision.has_mcCollision()) { continue; } + registry.fill(HIST("hEventCounter"), 0.5); auto bc = collision.bc_as(); - auto mccollision = collision.mcCollision(); initCCDB(bc); - - registry.fill(HIST("hEventCounter"), 1.0); // all - - mycollision(bc.globalBC(), bc.runNumber(), collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), collision.sel8(), d_bz, - mccollision.generatorsID(), mccollision.posX(), mccollision.posY(), mccollision.posZ(), - collision.multTPC(), collision.multFV0A(), collision.multFV0C(), collision.multFT0A(), collision.multFT0C(), - collision.multFDDA(), collision.multFDDC(), collision.multZNA(), collision.multZNC(), collision.multTracklets(), collision.multNTracksPV(), collision.multNTracksPVeta1()); + std::vector fSelected_old_labels; auto negTracks_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); auto posTracks_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - for (auto& track : tracks) { - if (!IsSelected(track)) { + for (auto& [ele, pos] : combinations(CombinationsFullIndexPolicy(negTracks_coll, posTracks_coll))) { + if (!ele.has_mcParticle() || !pos.has_mcParticle()) { continue; } + doPair(pos, ele, pos.mcParticleId(), ele.mcParticleId(), EM_EEPairType::kULS, mctracks, collision, fNewLabels, fSelected_old_labels, fCounter, collision.globalIndex(), collisions_old_labels, collisions_counter); + } - if (!track.has_mcParticle()) { - continue; // If no MC particle is found, skip the track + if (!doLS) { + continue; + } + for (auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_coll, posTracks_coll))) { + if (!pos1.has_mcParticle() || !pos2.has_mcParticle()) { + continue; } + doPair(pos1, pos2, pos1.mcParticleId(), pos2.mcParticleId(), EM_EEPairType::kLSpp, mctracks, collision, fNewLabels, fSelected_old_labels, fCounter, collision.globalIndex(), collisions_old_labels, collisions_counter); + } - auto mctrack = track.mcParticle_as(); - - if (abs(mctrack.pdgCode()) != 11) { + for (auto& [ele1, ele2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_coll, negTracks_coll))) { + if (!ele1.has_mcParticle() || !ele2.has_mcParticle()) { continue; } + doPair(ele1, ele2, ele1.mcParticleId(), ele2.mcParticleId(), EM_EEPairType::kLSnn, mctracks, collision, fNewLabels, fSelected_old_labels, fCounter, collision.globalIndex(), collisions_old_labels, collisions_counter); + } - if (!(fNewLabels.find(track.globalIndex()) != fNewLabels.end())) { - fNewLabels[track.globalIndex()] = fCounter; - - // store all mother relation - std::vector mothers_id; - std::vector mothers_pdg; - if (mctrack.has_mothers()) { - int motherid = mctrack.mothersIds()[0]; // first mother index - while (motherid > -1) { - if (motherid < mctracks.size()) { // protect against bad mother indices. why is this needed? - auto mp = mctracks.iteratorAt(motherid); - mothers_id.emplace_back(motherid); - mothers_pdg.emplace_back(mp.pdgCode()); - - if (mp.has_mothers()) { - motherid = mp.mothersIds()[0]; - } else { - motherid = -999; - } - } else { - LOGF(info, "Mother label(%d) exceeds the McParticles size(%d)", motherid, mctracks.size()); - } - } - } + // single tracks, only if selected in at least one pair + for (uint64_t track_label : fSelected_old_labels) { + auto track = tracks.rawIteratorAt(track_label); + auto mctrack = track.mcParticle_as(); - mytrack(mycollision.lastIndex(), - track.sign(), track.pt(), track.eta(), track.phi(), track.dcaXY(), track.dcaZ(), sqrt(track.cYY()), sqrt(track.cZZ()), - track.tpcNClsFindable(), track.tpcNClsFound(), track.tpcNClsCrossedRows(), - track.tpcChi2NCl(), track.tpcInnerParam(), - track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaMu(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), - track.beta(), track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), - track.itsClusterMap(), track.itsChi2NCl(), - mctrack.vx(), mctrack.vy(), mctrack.vz(), - mctrack.pdgCode(), mctrack.isPhysicalPrimary(), mothers_id, mothers_pdg); - - mothers_id.shrink_to_fit(); - mothers_pdg.shrink_to_fit(); - fCounter++; - } + doSingleTrack(track, mctrack, mctracks, collision.globalIndex(), collisions_old_labels, collisions_counter, false); } // end of track loop - for (auto& [ele, pos] : combinations(CombinationsFullIndexPolicy(negTracks_coll, posTracks_coll))) { - if (!IsSelected(ele) || !IsSelected(pos)) { - continue; - } + } // end of collision loop - if (!ele.has_mcParticle() || !pos.has_mcParticle()) { - continue; - } + for (uint64_t collision_label : collisions_old_labels) { + auto collision = collisions.rawIteratorAt(collision_label); + auto bc = collision.bc_as(); + auto mccollision = collision.mcCollision(); + doCollision(collision, bc, mccollision); + } + + fNewLabels.clear(); + fCounter = 0; + } // end of process + PROCESS_SWITCH(TreeCreatorElectronML, processPair, "produce ML input for pair level", false); - auto mcpos = pos.mcParticle_as(); - auto mcele = ele.mcParticle_as(); + Partition posTracksSkimmed = o2::aod::emprimaryelectron::sign > static_cast(0); + Partition negTracksSkimmed = o2::aod::emprimaryelectron::sign < static_cast(0); - if (abs(mcele.pdgCode()) != 11 || abs(mcpos.pdgCode()) != 11) { - continue; - } // charge swap is accepted. + void processPairSkimmed(MyFilteredCollisionsSkimmed const& collisions, MyFilteredTracksMCSkimmed const& tracks, aod::EMMCParticles const& mctracks, aod::EMMCEvents const&) + { + std::map fNewLabels; + int fCounter = 0; - ROOT::Math::PtEtaPhiMVector v1(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + std::vector collisions_old_labels; + int collisions_counter = -1; + std::vector collisions_old_labels_track = {}; + int collisions_counter_track = -1; - float phiv = get_phiv(ele, pos); - float pair_dca_xy = sqrt((pow(pos.dcaXY() / sqrt(pos.cYY()), 2) + pow(ele.dcaXY() / sqrt(ele.cYY()), 2)) / 2.); - float pair_dca_z = sqrt((pow(pos.dcaZ() / sqrt(pos.cZZ()), 2) + pow(ele.dcaZ() / sqrt(ele.cZZ()), 2)) / 2.); + for (auto& collision : collisions) { + if (!collision.has_emmcevent()) { + continue; + } + registry.fill(HIST("hEventCounter"), 0.5); - bool isSM = false; - int common_mother_id = FindCommonMotherFrom2Prongs(mcpos, mcele, mctracks); - if (common_mother_id > 0) { - isSM = true; - } - int isHF = o2::aod::pwgem::dilepton::mcutil::IsHF(mcpos, mcele, mctracks); // if isHF == true, pdgCode is set to 0, because this pair is correlated HF ee pair decayed from different 2 mothers. Check pdg code of legs. - - if (isSM) { - auto mcpair = mctracks.iteratorAt(common_mother_id); - bool is_prompt = true; // only relevant for prompt jpsi - - int motherid_pair = mcpair.mothersIds()[0]; // first mother index - while (motherid_pair > -1) { - if (motherid_pair < mctracks.size()) { // protect against bad mother indices. why is this needed? - auto mp = mctracks.iteratorAt(motherid_pair); - - if (std::to_string(mp.pdgCode()).find("5") != std::string::npos) { - is_prompt = false; - break; - } - - if (mp.has_mothers()) { - motherid_pair = mp.mothersIds()[0]; - } else { - motherid_pair = -999; - } - } else { - LOGF(info, "Mother label(%d) exceeds the McParticles size(%d)", motherid_pair, mctracks.size()); - } - } + initCCDB(collision); + std::vector fSelected_old_labels; - mypair(mycollision.lastIndex(), fNewLabels[pos.globalIndex()], fNewLabels[ele.globalIndex()], - v12.M(), v12.Pt(), v12.Eta(), v12.Phi(), phiv, pair_dca_xy, pair_dca_z, - isSM, isHF, EM_EEPairType::kULS, is_prompt, mcpair.pdgCode(), mcpair.statusCode(), mcpair.flags(), - mcpair.vx(), mcpair.vy(), mcpair.vz()); - // LOGF(info, "mcpair.pdgCode() = %d", mcpair.pdgCode()); - } else if (isHF > -1) { - // isSM and isHF are not satisfied at the same time. - mypair(mycollision.lastIndex(), fNewLabels[pos.globalIndex()], fNewLabels[ele.globalIndex()], - v12.M(), v12.Pt(), v12.Eta(), v12.Phi(), phiv, pair_dca_xy, pair_dca_z, - isSM, isHF, EM_EEPairType::kULS, false, 0, 0, 0, - 0, 0, 0); - } else { // this is combinatorial bkg - double pt = v12.Pt(); - double pseudoRndm = pt * 1000. - (int16_t)(pt * 1000); - if (pseudoRndm <= combBgReductionFactor) { - mypair(mycollision.lastIndex(), fNewLabels[pos.globalIndex()], fNewLabels[ele.globalIndex()], - v12.M(), pt, v12.Eta(), v12.Phi(), phiv, pair_dca_xy, pair_dca_z, - isSM, isHF, EM_EEPairType::kULS, false, 0, 0, 0, - 0, 0, 0); - } - } + auto negTracks_coll = negTracksSkimmed->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + auto posTracks_coll = posTracksSkimmed->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); - } // end of uls pair loop + for (auto& [ele, pos] : combinations(CombinationsFullIndexPolicy(negTracks_coll, posTracks_coll))) { + if (!ele.has_emmcparticle() || !pos.has_emmcparticle()) { + continue; + } + doPair(pos, ele, pos.emmcparticleId(), ele.emmcparticleId(), EM_EEPairType::kULS, mctracks, collision, fNewLabels, fSelected_old_labels, fCounter, collision.globalIndex(), collisions_old_labels, collisions_counter); + } if (!doLS) { continue; } for (auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_coll, posTracks_coll))) { - if (!IsSelected(pos1) || !IsSelected(pos2)) { - continue; - } - - if (!pos1.has_mcParticle() || !pos2.has_mcParticle()) { + if (!pos1.has_emmcparticle() || !pos2.has_emmcparticle()) { continue; } - - auto mcpos1 = pos1.mcParticle_as(); - auto mcpos2 = pos2.mcParticle_as(); - - if (abs(mcpos1.pdgCode()) != 11 || abs(mcpos2.pdgCode()) != 11) { - continue; - } // charge swap is accepted. - - ROOT::Math::PtEtaPhiMVector v1(pos1.pt(), pos1.eta(), pos1.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - - float phiv = get_phiv(pos1, pos2); - float pair_dca_xy = sqrt((pow(pos2.dcaXY() / sqrt(pos2.cYY()), 2) + pow(pos1.dcaXY() / sqrt(pos1.cYY()), 2)) / 2.); - float pair_dca_z = sqrt((pow(pos2.dcaZ() / sqrt(pos2.cZZ()), 2) + pow(pos1.dcaZ() / sqrt(pos1.cZZ()), 2)) / 2.); - - bool isSM = false; - int isHF = o2::aod::pwgem::dilepton::mcutil::IsHF(mcpos1, mcpos2, mctracks); - if (isHF != static_cast(o2::aod::pwgem::dilepton::mcutil::EM_HFeeType::kUndef)) { - // isSM and isHF are not satisfied at the same time. - mypair(mycollision.lastIndex(), fNewLabels[pos1.globalIndex()], fNewLabels[pos2.globalIndex()], - v12.M(), v12.Pt(), v12.Eta(), v12.Phi(), phiv, pair_dca_xy, pair_dca_z, - isSM, isHF, EM_EEPairType::kLSpp, false, 0, 0, 0, - 0, 0, 0); - } else { // this is combinatorial bkg - double pt = v12.Pt(); - double pseudoRndm = pt * 1000. - (int16_t)(pt * 1000); - if (pseudoRndm <= combBgReductionFactor) { - mypair(mycollision.lastIndex(), fNewLabels[pos1.globalIndex()], fNewLabels[pos2.globalIndex()], - v12.M(), pt, v12.Eta(), v12.Phi(), phiv, pair_dca_xy, pair_dca_z, - isSM, isHF, EM_EEPairType::kLSpp, false, 0, 0, 0, - 0, 0, 0); - } - } - - } // end of lspp pair loop + doPair(pos1, pos2, pos1.emmcparticleId(), pos2.emmcparticleId(), EM_EEPairType::kLSpp, mctracks, collision, fNewLabels, fSelected_old_labels, fCounter, collision.globalIndex(), collisions_old_labels, collisions_counter); + } for (auto& [ele1, ele2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_coll, negTracks_coll))) { - if (!IsSelected(ele1) || !IsSelected(ele2)) { - continue; - } - if (!ele1.has_mcParticle() || !ele2.has_mcParticle()) { + if (!ele1.has_emmcparticle() || !ele2.has_emmcparticle()) { continue; } + doPair(ele1, ele2, ele1.emmcparticleId(), ele2.emmcparticleId(), EM_EEPairType::kLSnn, mctracks, collision, fNewLabels, fSelected_old_labels, fCounter, collision.globalIndex(), collisions_old_labels, collisions_counter); + } - auto mcele1 = ele1.mcParticle_as(); - auto mcele2 = ele2.mcParticle_as(); + // single tracks, only if selected in at least one pair + for (uint64_t track_label : fSelected_old_labels) { + auto track = tracks.rawIteratorAt(track_label); + auto mctrack = track.emmcparticle_as(); - if (abs(mcele1.pdgCode()) != 11 || abs(mcele2.pdgCode()) != 11) { - continue; - } // charge swap is accepted. - - ROOT::Math::PtEtaPhiMVector v1(ele1.pt(), ele1.eta(), ele1.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - - float phiv = get_phiv(ele1, ele2); - float pair_dca_xy = sqrt((pow(ele2.dcaXY() / sqrt(ele2.cYY()), 2) + pow(ele1.dcaXY() / sqrt(ele1.cYY()), 2)) / 2.); - float pair_dca_z = sqrt((pow(ele2.dcaZ() / sqrt(ele2.cZZ()), 2) + pow(ele1.dcaZ() / sqrt(ele1.cZZ()), 2)) / 2.); - - bool isSM = false; - int isHF = o2::aod::pwgem::dilepton::mcutil::IsHF(mcele1, mcele2, mctracks); - if (isHF != static_cast(o2::aod::pwgem::dilepton::mcutil::EM_HFeeType::kUndef)) { - // isSM and isHF are not satisfied at the same time. - mypair(mycollision.lastIndex(), fNewLabels[ele1.globalIndex()], fNewLabels[ele2.globalIndex()], - v12.M(), v12.Pt(), v12.Eta(), v12.Phi(), phiv, pair_dca_xy, pair_dca_z, - isSM, isHF, EM_EEPairType::kLSnn, false, 0, 0, 0, - 0, 0, 0); - } else { // this is combinatorial bkg - double pt = v12.Pt(); - double pseudoRndm = pt * 1000. - (int16_t)(pt * 1000); - if (pseudoRndm <= combBgReductionFactor) { - mypair(mycollision.lastIndex(), fNewLabels[ele1.globalIndex()], fNewLabels[ele2.globalIndex()], - v12.M(), pt, v12.Eta(), v12.Phi(), phiv, pair_dca_xy, pair_dca_z, - isSM, isHF, EM_EEPairType::kLSnn, false, 0, 0, 0, - 0, 0, 0); - } - } + doSingleTrack(track, mctrack, mctracks, collision.globalIndex(), collisions_old_labels_track, collisions_counter_track, false); - } // end of lsnn pair loop + } // end of track loop } // end of collision loop + + for (uint64_t collision_label : collisions_old_labels) { + auto collision = collisions.rawIteratorAt(collision_label); + auto mccollision = collision.emmcevent(); + doCollision(collision, mccollision, collision.globalBC(), collision.runNumber()); + } + fNewLabels.clear(); fCounter = 0; } // end of process - PROCESS_SWITCH(TreeCreatorElectronML, processPair, "produce ML input for pair level", false); - - void processDummy(soa::Join const&) {} - PROCESS_SWITCH(TreeCreatorElectronML, processDummy, "process dummy", true); + PROCESS_SWITCH(TreeCreatorElectronML, processPairSkimmed, "produce ML input for pair level on skimmed data", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGEM/Dilepton/TableProducer/treeCreatorElectronMLDDA.cxx b/PWGEM/Dilepton/TableProducer/treeCreatorElectronMLDDA.cxx index c2d62c17046..16aa791d217 100644 --- a/PWGEM/Dilepton/TableProducer/treeCreatorElectronMLDDA.cxx +++ b/PWGEM/Dilepton/TableProducer/treeCreatorElectronMLDDA.cxx @@ -17,6 +17,7 @@ #include #include #include +#include #include "Math/Vector4D.h" #include "DCAFitter/DCAFitterN.h" #include "Framework/runDataProcessing.h" @@ -36,9 +37,12 @@ #include "DetectorsBase/GeometryManager.h" #include "DataFormatsParameters/GRPObject.h" #include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsCalibration/MeanVertexObject.h" #include "CCDB/BasicCCDBManager.h" #include "PWGEM/Dilepton/DataModel/lmeeMLTables.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" #include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" using namespace o2; using namespace o2::framework; @@ -46,10 +50,10 @@ using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::constants::physics; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; -using MyTracks = soa::Join; using MyTrack = MyTracks::iterator; @@ -71,61 +75,65 @@ struct TreeCreatorElectronMLDDA { "registry", { {"hEventCounter", "hEventCounter", {HistType::kTH1F, {{5, 0.5f, 5.5f}}}}, - {"hAP", "Armenteros Podolanski", {HistType::kTH2F, {{200, -1.f, +1.f}, {250, 0, 0.25}}}}, - {"hXY_Gamma", "photon conversion point in XY;X (cm);Y (cm)", {HistType::kTH2F, {{400, -100, +100}, {400, -100, +100}}}}, - {"hMassGamma_Rxy", "V0 mass gamma", {HistType::kTH2F, {{200, 0, 100}, {100, 0, 0.1}}}}, - {"hCosPA", "V0 cosine of pointing angle", {HistType::kTH1F, {{100, 0.9, 1.f}}}}, - {"hPCA", "V0 distance between 2 legs", {HistType::kTH1F, {{200, 0.f, 2.f}}}}, - {"hMassGamma", "V0 mass gamma", {HistType::kTH1F, {{100, 0, 0.1}}}}, - {"hMassK0Short", "V0 mass K0S", {HistType::kTH1F, {{200, 0.4, 0.6}}}}, - {"hMassLambda", "V0 mass Lambda", {HistType::kTH1F, {{100, 1.05, 1.15}}}}, - {"hMassAntiLambda", "V0 mass AntiLambda", {HistType::kTH1F, {{100, 1.05, 1.15}}}}, + {"V0/hAP", "Armenteros Podolanski", {HistType::kTH2F, {{200, -1.f, +1.f}, {250, 0, 0.25}}}}, + {"V0/hXY_Gamma", "photon conversion point in XY;X (cm);Y (cm)", {HistType::kTH2F, {{400, -100, +100}, {400, -100, +100}}}}, + {"V0/hMassGamma_Rxy", "V0 mass gamma", {HistType::kTH2F, {{200, 0, 100}, {100, 0, 0.1}}}}, + {"V0/hCosPA", "V0 cosine of pointing angle", {HistType::kTH1F, {{100, 0.99, 1.f}}}}, + {"V0/hPCA", "V0 distance between 2 legs", {HistType::kTH1F, {{200, 0.f, 2.f}}}}, + {"V0/hMassGamma", "V0 mass gamma", {HistType::kTH1F, {{100, 0, 0.1}}}}, + {"V0/hMassK0Short", "V0 mass K0S", {HistType::kTH1F, {{200, 0.4, 0.6}}}}, + {"V0/hMassLambda", "V0 mass Lambda", {HistType::kTH1F, {{100, 1.05, 1.15}}}}, + {"V0/hMassAntiLambda", "V0 mass AntiLambda", {HistType::kTH1F, {{100, 1.05, 1.15}}}}, {"hMvsPhiV", "mee vs. phiv", {HistType::kTH2F, {{72, 0, M_PI}, {100, 0, 0.1}}}}, - {"hMvsPhiV_primary", "mee vs. phiv for primary e candidate", {HistType::kTH2F, {{72, 0, M_PI}, {100, 0, 0.1}}}}, - - {"hTPCdEdx_P", "TPC dEdx vs. p;p^{ITS-TPC} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0, 5}, {200, 0, 200}}}}, - {"hTOFbeta_P", "TOF beta vs. p;p^{ITS-TPC} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0, 5}, {220, 0, 1.1}}}}, - {"hTPCdEdx_P_El", "TPC dEdx vs. p;p^{ITS-TPC} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0, 5}, {200, 0, 200}}}}, - {"hTOFbeta_P_El", "TOF beta vs. p;p^{ITS-TPC} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0, 5}, {220, 0, 1.1}}}}, - {"hTPCdEdx_P_Mu", "TPC dEdx vs. p;p^{ITS-TPC} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0, 5}, {200, 0, 200}}}}, - {"hTOFbeta_P_Mu", "TOF beta vs. p;p^{ITS-TPC} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0, 5}, {220, 0, 1.1}}}}, - {"hTPCdEdx_P_Pi", "TPC dEdx vs. p;p^{ITS-TPC} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0, 5}, {200, 0, 200}}}}, - {"hTOFbeta_P_Pi", "TOF beta vs. p;p^{ITS-TPC} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0, 5}, {220, 0, 1.1}}}}, - {"hTPCdEdx_P_Ka", "TPC dEdx vs. p;p^{ITS-TPC} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0, 5}, {200, 0, 200}}}}, - {"hTOFbeta_P_Ka", "TOF beta vs. p;p^{ITS-TPC} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0, 5}, {220, 0, 1.1}}}}, - {"hTPCdEdx_P_Pr", "TPC dEdx vs. p;p^{ITS-TPC} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0, 5}, {200, 0, 200}}}}, - {"hTOFbeta_P_Pr", "TOF beta vs. p;p^{ITS-TPC} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0, 5}, {220, 0, 1.1}}}}, - {"hTPCNsigmaEl_P", "TPC n#sigma_{e} vs. p;p^{ITS-TPC} (GeV/c);n #sigma_{e}^{TPC}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, - {"hTPCNsigmaMu_P", "TPC n#sigma_{#mu} vs. p;p^{ITS-TPC} (GeV/c);n #sigma_{#mu}^{TPC}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, - {"hTPCNsigmaPi_P", "TPC n#sigma_{#pi} vs. p;p^{ITS-TPC} (GeV/c);n #sigma_{#pi}^{TPC}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, - {"hTPCNsigmaKa_P", "TPC n#sigma_{K} vs. p;p^{ITS-TPC} (GeV/c);n #sigma_{K}^{TPC}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, - {"hTPCNsigmaPr_P", "TPC n#sigma_{p} vs. p;p^{ITS-TPC} (GeV/c);n #sigma_{p}^{TPC}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, - {"hTOFNsigmaEl_P", "TOF n#sigma_{e} vs. p;p^{ITS-TOF} (GeV/c);n #sigma_{e}^{TOF}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, - {"hTOFNsigmaMu_P", "TOF n#sigma_{#mu} vs. p;p^{ITS-TOF} (GeV/c);n #sigma_{#mu}^{TOF}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, - {"hTOFNsigmaPi_P", "TOF n#sigma_{#pi} vs. p;p^{ITS-TOF} (GeV/c);n #sigma_{#pi}^{TOF}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, - {"hTOFNsigmaKa_P", "TOF n#sigma_{K} vs. p;p^{ITS-TOF} (GeV/c);n #sigma_{K}^{TOF}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, - {"hTOFNsigmaPr_P", "TOF n#sigma_{p} vs. p;p^{ITS-TOF} (GeV/c);n #sigma_{p}^{TOF}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, + {"V0/hTPCdEdx_P_El", "TPC dEdx vs. p;p^{ITS-TPC} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0, 5}, {200, 0, 200}}}}, + {"V0/hTPCdEdx_P_Mu", "TPC dEdx vs. p;p^{ITS-TPC} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0, 5}, {200, 0, 200}}}}, + {"V0/hTPCdEdx_P_Pi", "TPC dEdx vs. p;p^{ITS-TPC} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0, 5}, {200, 0, 200}}}}, + {"V0/hTPCdEdx_P_Ka", "TPC dEdx vs. p;p^{ITS-TPC} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0, 5}, {200, 0, 200}}}}, + {"V0/hTPCdEdx_P_Pr", "TPC dEdx vs. p;p^{ITS-TPC} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0, 5}, {200, 0, 200}}}}, + + {"V0/hTOFbeta_P_El", "TOF beta vs. p;p^{ITS-TPC} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0, 5}, {220, 0, 1.1}}}}, + {"V0/hTOFbeta_P_Mu", "TOF beta vs. p;p^{ITS-TPC} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0, 5}, {220, 0, 1.1}}}}, + {"V0/hTOFbeta_P_Pi", "TOF beta vs. p;p^{ITS-TPC} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0, 5}, {220, 0, 1.1}}}}, + {"V0/hTOFbeta_P_Ka", "TOF beta vs. p;p^{ITS-TPC} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0, 5}, {220, 0, 1.1}}}}, + {"V0/hTOFbeta_P_Pr", "TOF beta vs. p;p^{ITS-TPC} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0, 5}, {220, 0, 1.1}}}}, + + {"V0/hITSClusterSize_P_El", "mean ITS cluster size vs. p;p^{ITS-TPC} (GeV/c); #times cos(#lambda)", {HistType::kTH2F, {{500, 0.f, 5.f}, {150, 0.0, 15}}}}, + {"V0/hITSClusterSize_P_Mu", "mean ITS cluster size vs. p;p^{ITS-TPC} (GeV/c); #times cos(#lambda)", {HistType::kTH2F, {{500, 0.f, 5.f}, {150, 0.0, 15}}}}, + {"V0/hITSClusterSize_P_Pi", "mean ITS cluster size vs. p;p^{ITS-TPC} (GeV/c); #times cos(#lambda)", {HistType::kTH2F, {{500, 0.f, 5.f}, {150, 0.0, 15}}}}, + {"V0/hITSClusterSize_P_Ka", "mean ITS cluster size vs. p;p^{ITS-TPC} (GeV/c); #times cos(#lambda)", {HistType::kTH2F, {{500, 0.f, 5.f}, {150, 0.0, 15}}}}, + {"V0/hITSClusterSize_P_Pr", "mean ITS cluster size vs. p;p^{ITS-TPC} (GeV/c); #times cos(#lambda)", {HistType::kTH2F, {{500, 0.f, 5.f}, {150, 0.0, 15}}}}, + + // {"PrimaryTrack/hTPCdEdx_P", "TPC dEdx vs. p;p^{ITS-TPC} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0, 5}, {200, 0, 200}}}}, + // {"PrimaryTrack/hTOFbeta_P", "TOF beta vs. p;p^{ITS-TPC} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0, 5}, {220, 0, 1.1}}}}, + // {"PrimaryTrack/hITSClusterSize_P", "mean ITS cluster size vs. p;p^{ITS-TPC} (GeV/c); #times cos(#lambda)", {HistType::kTH2F, {{500, 0.f, 5.f}, {150, 0.0, 15}}}}, + // {"PrimaryTrack/hTPCNsigmaEl_P", "TPC n#sigma_{e} vs. p;p^{ITS-TPC} (GeV/c);n #sigma_{e}^{TPC}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, + // {"PrimaryTrack/hTPCNsigmaMu_P", "TPC n#sigma_{#mu} vs. p;p^{ITS-TPC} (GeV/c);n #sigma_{#mu}^{TPC}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, + // {"PrimaryTrack/hTPCNsigmaPi_P", "TPC n#sigma_{#pi} vs. p;p^{ITS-TPC} (GeV/c);n #sigma_{#pi}^{TPC}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, + // {"PrimaryTrack/hTPCNsigmaKa_P", "TPC n#sigma_{K} vs. p;p^{ITS-TPC} (GeV/c);n #sigma_{K}^{TPC}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, + // {"PrimaryTrack/hTPCNsigmaPr_P", "TPC n#sigma_{p} vs. p;p^{ITS-TPC} (GeV/c);n #sigma_{p}^{TPC}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, + // {"PrimaryTrack/hTOFNsigmaEl_P", "TOF n#sigma_{e} vs. p;p^{ITS-TOF} (GeV/c);n #sigma_{e}^{TOF}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, + // {"PrimaryTrack/hTOFNsigmaMu_P", "TOF n#sigma_{#mu} vs. p;p^{ITS-TOF} (GeV/c);n #sigma_{#mu}^{TOF}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, + // {"PrimaryTrack/hTOFNsigmaPi_P", "TOF n#sigma_{#pi} vs. p;p^{ITS-TOF} (GeV/c);n #sigma_{#pi}^{TOF}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, + // {"PrimaryTrack/hTOFNsigmaKa_P", "TOF n#sigma_{K} vs. p;p^{ITS-TOF} (GeV/c);n #sigma_{K}^{TOF}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, + // {"PrimaryTrack/hTOFNsigmaPr_P", "TOF n#sigma_{p} vs. p;p^{ITS-TOF} (GeV/c);n #sigma_{p}^{TOF}", {HistType::kTH2F, {{500, 0.f, 5.f}, {100, -5, +5}}}}, - {"Cascade/hAP", "Armenteros Podolanski for cascade", {HistType::kTH2F, {{200, -1.f, +1.f}, {250, 0, 0.25}}}}, - {"Cascade/hAP_V0", "Armenteros Podolanski for #Lambda and #bar{#Lambda}", {HistType::kTH2F, {{200, -1.f, +1.f}, {250, 0, 0.25}}}}, - {"Cascade/hRxy", "R_{xy} of cascade vs. in-V0;R_{xy} of V0 (cm);R_{xy} of cascade (cm)", {HistType::kTH2F, {{200, 0, 20.f}, {200, 0, 20.f}}}}, {"Cascade/hRxy_Xi", "R_{xy} of cascade vs. mass;m_{#Lambda#pi};R_{xy} (cm)", {HistType::kTH2F, {{200, 1.2, 1.4}, {200, 0, 20.f}}}}, {"Cascade/hRxy_Omega", "R_{xy} of cascade vs. mass;m_{#LambdaK};R_{xy} (cm)", {HistType::kTH2F, {{200, 1.6, 1.8}, {200, 0, 20.f}}}}, {"Cascade/hCTau_Xi", "c#tau vs. mass;m_{#Lambda#pi};c#tau (cm)", {HistType::kTH2F, {{200, 1.2, 1.4}, {200, 0, 20.f}}}}, {"Cascade/hCTau_Omega", "c#tau vs. mass;m_{#LambdaK};c#tau (cm)", {HistType::kTH2F, {{200, 1.6, 1.8}, {200, 0, 20.f}}}}, - {"Cascade/hV0CosPA", "V0 cosine of pointing angle", {HistType::kTH1F, {{100, 0.9, 1.f}}}}, + {"Cascade/hV0CosPA", "V0 cosine of pointing angle", {HistType::kTH1F, {{50, 0.95, 1.f}}}}, {"Cascade/hV0PCA", "V0 distance between 2 legs", {HistType::kTH1F, {{200, 0.f, 2.f}}}}, - {"Cascade/hCosPA", "cascade cosine of pointing angle", {HistType::kTH1F, {{100, 0.9, 1.f}}}}, + {"Cascade/hCosPA", "cascade cosine of pointing angle", {HistType::kTH1F, {{100, 0.99, 1.f}}}}, {"Cascade/hPCA", "cascade distance between 2 legs", {HistType::kTH1F, {{200, 0.f, 2.f}}}}, {"Cascade/hMassLambda", "V0 mass Lambda in cascade", {HistType::kTH1F, {{100, 1.05, 1.15}}}}, {"Cascade/hMassAntiLambda", "V0 mass AntiLambda in cascade", {HistType::kTH1F, {{100, 1.05, 1.15}}}}, {"Cascade/hMassXi", "cascade mass #Xi", {HistType::kTH1F, {{200, 1.2, 1.4}}}}, {"Cascade/hMassOmega", "cascade mass #Omega", {HistType::kTH1F, {{200, 1.6, 1.8}}}}, - {"Cascade/hMassPt_Xi", "cascade mass #Xi;m_{#Lambda#pi} (GeV/c^{2});p_{T,#Lambda#pi} (GeV/c)", {HistType::kTH2F, {{200, 1.2, 1.4}, {100, 0, 10}}}}, - {"Cascade/hMassPt_Xi_bachelor", "cascade mass #Xi;m_{#Lambda#pi} (GeV/c^{2});p_{T,#pi} (GeV/c)", {HistType::kTH2F, {{200, 1.2, 1.4}, {100, 0, 10}}}}, - {"Cascade/hMassPt_Omega", "cascade mass #Omegam_{#LambdaK} (GeV/c^{2});p_{T,#LambdaK} (GeV/c)", {HistType::kTH2F, {{200, 1.6, 1.8}, {100, 0, 10}}}}, - {"Cascade/hMassPt_Omega_bachelor", "cascade mass #Omega;m_{#LambdaK} (GeV/c^{2});p_{T,K} (GeV/c)", {HistType::kTH2F, {{200, 1.6, 1.8}, {100, 0, 10}}}}, + {"Cascade/hMassPt_Xi", "cascade mass #Xi^{#pm};m_{#Lambda#pi} (GeV/c^{2});p_{T,#Lambda#pi} (GeV/c)", {HistType::kTH2F, {{200, 1.2, 1.4}, {100, 0, 10}}}}, + {"Cascade/hMassPt_Xi_bachelor", "cascade mass #Xi^{#pm};m_{#Lambda#pi} (GeV/c^{2});p_{T,#pi} (GeV/c)", {HistType::kTH2F, {{200, 1.2, 1.4}, {100, 0, 10}}}}, + {"Cascade/hMassPt_Omega", "cascade mass #Omega^{#pm};m_{#LambdaK} (GeV/c^{2});p_{T,#LambdaK} (GeV/c)", {HistType::kTH2F, {{200, 1.6, 1.8}, {100, 0, 10}}}}, + {"Cascade/hMassPt_Omega_bachelor", "cascade mass #Omega^{#pm};m_{#LambdaK} (GeV/c^{2});p_{T,K} (GeV/c)", {HistType::kTH2F, {{200, 1.6, 1.8}, {100, 0, 10}}}}, }, }; @@ -137,77 +145,113 @@ struct TreeCreatorElectronMLDDA { Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable mVtxPath{"mVtxPath", "GLO/Calib/MeanVertex", "Path of the mean vertex file"}; Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; // Operation and minimisation criteria - Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; - Configurable d_UseAbsDCA{"d_UseAbsDCA", true, "Use Abs DCAs"}; - Configurable d_UseWeightedPCA{"d_UseWeightedPCA", false, "Vertices use cov matrices"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field, -999 is automatic"}; Configurable useMatCorrType{"useMatCorrType", 0, "0: none, 1: TGeo, 2: LUT"}; - // TPC-related variables - Configurable mincrossedrows{"mincrossedrows", 40, "min. crossed rows"}; - Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max. chi2/NclsTPC"}; - - // ITS-related variables - Configurable minitsncls{"minitsncls", 2, "min. number of ITS clusters"}; - Configurable maxchi2its{"maxchi2its", 6.0, "max. chi2/NclsITS"}; - - // for v0 - Configurable max_mee_pcm{"max_mee_pcm", 0.02, "max mee to v0 photon"}; - Configurable minv0cospa{"minv0cospa", 0.997, "minimum V0 CosPA"}; - Configurable maxdcav0dau{"maxdcav0dau", 0.2, "max distance between V0 Daughters"}; - Configurable mindcaxytopv_v0leg{"mindcaxytopv_v0leg", -1, "max dcaxy to pv for v0 leg"}; // 0.05 cm Configurable downscaling_electron{"downscaling_electron", 0.005, "down scaling factor to store electron"}; Configurable downscaling_pion{"downscaling_pion", 0.001, "down scaling factor to store pion"}; Configurable downscaling_kaon{"downscaling_kaon", 1.1, "down scaling factor to store kaon"}; Configurable downscaling_proton{"downscaling_proton", 0.01, "down scaling factor to store proton"}; - - // for pion - Configurable minTPCNsigmaPi{"minTPCNsigmaPi", -1e+10, "min. TPC n sigma for pion inclusion"}; // this is only for IsElectronTag - Configurable maxTPCNsigmaPi{"maxTPCNsigmaPi", 3.0, "max. TPC n sigma for pion inclusion"}; - Configurable maxTOFNsigmaPi{"maxTOFNsigmaPi", 3.0, "max. TOF n sigma for pion inclusion"}; - - // for kaon - Configurable maxTPCNsigmaKa{"maxTPCNsigmaKa", 3.0, "max. TPC n sigma for kaon inclusion"}; - Configurable maxTOFNsigmaKa{"maxTOFNsigmaKa", 3.0, "max. TOF n sigma for kaon inclusion"}; - - // for proton - Configurable maxTPCNsigmaPr{"maxTPCNsigmaPr", 3.0, "max. TPC n sigma for proton inclusion"}; - Configurable maxTOFNsigmaPr{"maxTOFNsigmaPr", 3.0, "max. TOF n sigma for proton inclusion"}; - - // for phiv vs. mee - Configurable minpt{"minpt", 0.05, "min pt for global tracks"}; - Configurable maxeta{"maxeta", 0.9, "max. eta for global tracks"}; - Configurable maxdcaXY{"maxdcaXY", 0.5, "max. DCA in XY"}; - Configurable maxdcaZ{"maxdcaZ", 0.5, "max. DCA in Z"}; - Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -3.0, "min. TPC n sigma for electron inclusion"}; - Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", 3.0, "max. TPC n sigma for electron inclusion"}; - Configurable maxTOFNsigmaEl{"maxTOFNsigmaEl", 3.0, "max. TOF n sigma for electron inclusion"}; + Configurable store_v0photons{"store_v0photons", true, "create training data from v0 photons"}; Configurable slope{"slope", 0.0185, "slope for m vs. phiv"}; Configurable intercept{"intercept", -0.0380, "intercept for m vs. phiv"}; - Configurable max_mee_pi0{"max_mee_pi0", -1, "max mee to tag ee from pi0"}; // 0.04 GeV/c2 - Configurable downscaling_primary_electron{"downscaling_primary_electron", 0.1, "down scaling factor to store electron"}; - Configurable downscaling_secondary_electron{"downscaling_secondary_electron", 0.1, "down scaling factor to store electron"}; - - // for cascade - Configurable minv0cospa_casc{"minv0cospa_casc", 0.97, "minimum V0 CosPA in cascade"}; - Configurable maxdcav0dau_casc{"maxdcav0dau_casc", 0.2, "max distance between V0 Daughters in cascade"}; - Configurable min_casc_cospa{"min_casc_cospa", 0.99, "minimum cascade CosPA"}; - Configurable max_casc_dcadau{"max_casc_dcadau", 0.4, "max distance between bachelor and V0"}; - Configurable min_v0rxy_in_cascade{"min_v0rxy_in_cascade", 1.2, "minimum V0 rxy in cascade"}; - Configurable min_cascade_rxy{"min_cascade_rxy", 0.5, "minimum V0 rxy in cascade"}; - Configurable min_dcav0topv_casc{"min_dcav0topv_casc", 0.04, "min 3D dca from V0 in cascade to PV"}; - Configurable mindcaxytopv_v0leg_casc{"mindcaxytopv_v0leg_casc", -1, "max dcaxy to pv for v0 leg in cascade"}; // 0.03 cm - Configurable mindcaxytopv_bach_casc{"mindcaxytopv_bach_casc", -1, "max dcaxy to pv for bachelor in cascade"}; // 0.03 cm + + struct : ConfigurableGroup { + std::string prefix = "trackcut_group"; + Configurable cfg_min_pt{"cfg_min_pt", 0.05, "min pt for v0 legs"}; + Configurable cfg_max_eta{"cfg_max_eta", 0.9, "max. eta for v0 legs"}; + Configurable cfg_min_cr2findable_ratio_tpc{"cfg_min_cr2findable_ratio_tpc", 0.8, "min. TPC Ncr/Nf ratio"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 0.7, "max fraction of shared clusters in TPC"}; + Configurable cfg_min_ncrossedrows_tpc{"cfg_min_ncrossedrows_tpc", 70, "min ncrossed rows"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 2, "min ncluster its"}; + Configurable cfg_min_ncluster_itsib{"cfg_min_ncluster_itsib", 0, "min ncluster itsib"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 5.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 6.0, "max chi2/NclsITS"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 0.3, "max dca XY in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 0.3, "max dca Z in cm"}; + } trackcuts; + + struct : ConfigurableGroup { + std::string prefix = "v0cut_group"; + Configurable cfg_min_pt{"cfg_min_pt", 0.05, "min pt for v0 legs"}; + Configurable cfg_max_eta{"cfg_max_eta", 0.9, "max. eta for v0 legs"}; + Configurable cfg_min_mass_photon{"cfg_min_mass_photon", 0.00, "min mass for photon conversion"}; + Configurable cfg_max_mass_photon{"cfg_max_mass_photon", 0.02, "max mass for photon conversion"}; + Configurable cfg_min_mass_k0s{"cfg_min_mass_k0s", 0.490, "min mass for K0S"}; + Configurable cfg_max_mass_k0s{"cfg_max_mass_k0s", 0.505, "max mass for K0S"}; + Configurable cfg_min_mass_lambda{"cfg_min_mass_lambda", 1.11, "min mass for Lambda rejection"}; + Configurable cfg_max_mass_lambda{"cfg_max_mass_lambda", 1.12, "max mass for Lambda rejection"}; + Configurable cfg_min_cospa{"cfg_min_cospa", 0.999, "min cospa for v0"}; + Configurable cfg_max_dcadau{"cfg_max_dcadau", 0.5, "max distance between 2 legs for v0"}; + Configurable cfg_min_cr2findable_ratio_tpc{"cfg_min_cr2findable_ratio_tpc", 0.8, "min. TPC Ncr/Nf ratio"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 0.7, "max fraction of shared clusters in TPC"}; + Configurable cfg_min_ncrossedrows_tpc{"cfg_min_ncrossedrows_tpc", 70, "min ncrossed rows"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 2, "min ncluster its"}; + Configurable cfg_min_ncluster_itsib{"cfg_min_ncluster_itsib", 0, "min ncluster itsib"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 5.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 6.0, "max chi2/NclsITS"}; + Configurable cfg_min_dcaxy_v0leg{"cfg_min_dcaxy_v0leg", 0.1, "min dca XY for v0 legs in cm"}; + + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -4, "min n sigma e in TPC"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +4, "max n sigma e in TPC"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -4, "min n sigma pi in TPC"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +4, "max n sigma pi in TPC"}; + Configurable cfg_min_TPCNsigmaKa{"cfg_min_TPCNsigmaKa", -4, "min n sigma ka in TPC"}; + Configurable cfg_max_TPCNsigmaKa{"cfg_max_TPCNsigmaKa", +4, "max n sigma ka in TPC"}; + Configurable cfg_min_TPCNsigmaPr{"cfg_min_TPCNsigmaPr", -4, "min n sigma pr in TPC"}; + Configurable cfg_max_TPCNsigmaPr{"cfg_max_TPCNsigmaPr", +4, "max n sigma pr in TPC"}; + + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -4, "min n sigma e in TOF"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +4, "max n sigma e in TOF"}; + Configurable cfg_min_TOFNsigmaPi{"cfg_min_TOFNsigmaPi", -4, "min n sigma pi in TOF"}; + Configurable cfg_max_TOFNsigmaPi{"cfg_max_TOFNsigmaPi", +4, "max n sigma pi in TOF"}; + Configurable cfg_min_TOFNsigmaKa{"cfg_min_TOFNsigmaKa", -4, "min n sigma ka in TOF"}; + Configurable cfg_max_TOFNsigmaKa{"cfg_max_TOFNsigmaKa", +4, "max n sigma ka in TOF"}; + Configurable cfg_min_TOFNsigmaPr{"cfg_min_TOFNsigmaPr", -4, "min n sigma pr in TOF"}; + Configurable cfg_max_TOFNsigmaPr{"cfg_max_TOFNsigmaPr", +4, "max n sigma pr in TOF"}; + + Configurable cfg_min_TPCNsigmaPi_tight{"cfg_min_TPCNsigmaPi_tight", -2, "min n sigma pi in TPC for Lambda and cascade"}; + Configurable cfg_max_TPCNsigmaPi_tight{"cfg_max_TPCNsigmaPi_tight", +2, "max n sigma pi in TPC for Lambda and cascade"}; + Configurable cfg_min_TPCNsigmaPr_tight{"cfg_min_TPCNsigmaPr_tight", -2, "min n sigma pr in TPC for cascade"}; + Configurable cfg_max_TPCNsigmaPr_tight{"cfg_max_TPCNsigmaPr_tight", +2, "max n sigma pr in TPC for cascade"}; + + Configurable cfg_min_TOFNsigmaPi_tight{"cfg_min_TOFNsigmaPi_tight", -2, "min n sigma pi in TOF for Lambda and cascade"}; + Configurable cfg_max_TOFNsigmaPi_tight{"cfg_max_TOFNsigmaPi_tight", +2, "max n sigma pi in TOF for Lambda and cascade"}; + Configurable cfg_min_TOFNsigmaPr_tight{"cfg_min_TOFNsigmaPr_tight", -2, "min n sigma pr in TOF for cascade"}; + Configurable cfg_max_TOFNsigmaPr_tight{"cfg_max_TOFNsigmaPr_tight", +2, "max n sigma pr in TOF for cascade"}; + } v0cuts; + + struct : ConfigurableGroup { + std::string prefix = "cascadecut_group"; + Configurable cfg_min_mass_lambda{"cfg_min_mass_lambda", 1.11, "min mass for lambda in cascade"}; + Configurable cfg_max_mass_lambda{"cfg_max_mass_lambda", 1.12, "max mass for lambda in cascade"}; + Configurable cfg_min_mass_Xi{"cfg_min_mass_Xi", 1.317, "min mass for Xi"}; + Configurable cfg_max_mass_Xi{"cfg_max_mass_Xi", 1.327, "max mass for Xi"}; + Configurable cfg_min_mass_Omega{"cfg_min_mass_Omega", 1.667, "min mass for Omega"}; + Configurable cfg_max_mass_Omega{"cfg_max_mass_Omega", 1.677, "max mass for Omega"}; + Configurable cfg_min_cospa_v0{"cfg_min_cospa_v0", 0.97, "minimum V0 CosPA in cascade"}; + Configurable cfg_max_dcadau_v0{"cfg_max_dcadau_v0", 0.2, "max distance between V0 Daughters in cascade"}; + Configurable cfg_min_cospa{"cfg_min_cospa", 0.999, "minimum cascade CosPA"}; + Configurable cfg_max_dcadau{"cfg_max_dcadau", 0.4, "max distance between bachelor and V0"}; + Configurable cfg_min_rxy_v0{"cfg_min_rxy_v0", 1.2, "minimum V0 rxy in cascade"}; + Configurable cfg_min_rxy{"cfg_min_rxy", 0.5, "minimum V0 rxy in cascade"}; + Configurable cfg_min_dcaxy_v0leg{"cfg_min_dcaxy_v0leg", 0.1, "min dca XY for v0 legs in cm"}; + Configurable cfg_min_dcaxy_bachelor{"cfg_min_dcaxy_bachelor", 0.1, "min dca XY for bachelor in cm"}; + } cascadecuts; int mRunNumber; float d_bz; - float maxSnp; // max sine phi for propagation - float maxStep; // max step size (cm) for propagation Service ccdb; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + o2::dataformats::VertexBase mVtx; + const o2::dataformats::MeanVertexObject* mMeanVtx = nullptr; o2::base::MatLayerCylSet* lut = nullptr; - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - o2::vertexing::DCAFitterN<2> fitter; + o2::dataformats::DCA mDcaInfoCov; std::mt19937 engine; std::uniform_real_distribution dist01; @@ -216,8 +260,6 @@ struct TreeCreatorElectronMLDDA { { mRunNumber = 0; d_bz = 0; - maxSnp = 0.85f; // could be changed later - maxStep = 2.00f; // could be changed later ccdb->setURL(ccdburl); ccdb->setCaching(true); @@ -235,22 +277,6 @@ struct TreeCreatorElectronMLDDA { lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); } - fitter.setPropagateToPCA(true); - fitter.setMaxR(200.); - fitter.setMinParamChange(1e-3); - fitter.setMinRelChi2Change(0.9); - fitter.setMaxDZIni(1e9); - fitter.setMaxChi2(1e9); - fitter.setUseAbsDCA(d_UseAbsDCA); - fitter.setWeightedFinalPCA(d_UseWeightedPCA); - - if (useMatCorrType == 1) { - matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; - } else if (useMatCorrType == 2) { - matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - } - fitter.setMatCorrType(matCorr); - std::random_device seed_gen; engine = std::mt19937(seed_gen()); dist01 = std::uniform_real_distribution(0.0f, 1.0f); @@ -262,15 +288,24 @@ struct TreeCreatorElectronMLDDA { return; } + // load matLUT for this timestamp + if (!lut) { + LOG(info) << "Loading material look-up table for timestamp: " << bc.timestamp(); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->getForTimeStamp(lutPath, bc.timestamp())); + } else { + LOG(info) << "Material look-up table already in place. Not reloading."; + } + // In case override, don't proceed, please - no CCDB access required if (d_bz_input > -990) { d_bz = d_bz_input; - fitter.setBz(d_bz); o2::parameters::GRPMagField grpmag; - if (fabs(d_bz) > 1e-5) { + if (std::fabs(d_bz) > 1e-5) { grpmag.setL3Current(30000.f / (d_bz / 5.0f)); } o2::base::Propagator::initFieldFromGRP(&grpmag); + o2::base::Propagator::Instance()->setMatLUT(lut); + mMeanVtx = ccdb->getForTimeStamp(mVtxPath, bc.timestamp()); mRunNumber = bc.runNumber(); return; } @@ -282,6 +317,8 @@ struct TreeCreatorElectronMLDDA { grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); if (grpo) { o2::base::Propagator::initFieldFromGRP(grpo); + o2::base::Propagator::Instance()->setMatLUT(lut); + mMeanVtx = ccdb->getForTimeStamp(mVtxPath, bc.timestamp()); // Fetch magnetic field from ccdb for current collision d_bz = grpo->getNominalL3Field(); LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; @@ -291,307 +328,271 @@ struct TreeCreatorElectronMLDDA { LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; } o2::base::Propagator::initFieldFromGRP(grpmag); + o2::base::Propagator::Instance()->setMatLUT(lut); + mMeanVtx = ccdb->getForTimeStamp(mVtxPath, bc.timestamp()); // Fetch magnetic field from ccdb for current collision d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; } mRunNumber = bc.runNumber(); - // Set magnetic field value once known - fitter.setBz(d_bz); - - if (useMatCorrType == 2) { - // setMatLUT only after magfield has been initalized (setMatLUT has implicit and problematic init field call if not) - o2::base::Propagator::Instance()->setMatLUT(lut); - } } - float CalculateDCAStraightToPV(float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) + template + float meanClusterSizeITS(TTrack const& track) { - return std::sqrt((std::pow((pvY - Y) * Pz - (pvZ - Z) * Py, 2) + std::pow((pvX - X) * Pz - (pvZ - Z) * Px, 2) + std::pow((pvX - X) * Py - (pvY - Y) * Px, 2)) / (Px * Px + Py * Py + Pz * Pz)); + int total_size = 0; + int nl = 0; + for (int il = il0; il < il1; il++) { + if (track.itsClsSizeInLayer(il) > 0) { + total_size += track.itsClsSizeInLayer(il); + nl++; + } + } + if (nl > 0) { + return static_cast(total_size) / static_cast(nl); + } else { + return 0.f; + } } - EM_V0_Label checkV0(const float alpha, const float qt) + template + bool isSelectedTrack(TCollision const& collision, TTrack const& track) { - // Gamma cuts - const float cutAlphaG = 0.95; - const float cutQTG = 0.01; - - // K0S cuts - const float cutQTK0S[2] = {0.1075, 0.215}; - const float cutAPK0S[2] = {0.199, 0.8}; // parameters for curved QT cut - - // Lambda & A-Lambda cuts - const float cutQTL = 0.03; - const float cutAlphaL[2] = {0.35, 0.7}; - const float cutAlphaAL[2] = {-0.7, -0.35}; - const float cutAPL[3] = {0.107, -0.69, 0.5}; // parameters for curved QT cut - - // Check for Gamma candidates - if (std::pow(alpha / cutAlphaG, 2) + std::pow(qt / cutQTG, 2) < std::pow(1.f, 2)) { - return EM_V0_Label::kGamma; + if (!track.hasITS() || !track.hasTPC()) { + return false; } - // Check for K0S candidates - float q = cutAPK0S[0] * sqrt(abs(1 - alpha * alpha / (cutAPK0S[1] * cutAPK0S[1]))); - if ((qt > cutQTK0S[0]) && (qt < cutQTK0S[1]) && (qt > q)) { - return EM_V0_Label::kK0S; + if (track.itsNCls() < trackcuts.cfg_min_ncluster_its) { + return false; } - - // Check for Lambda candidates - q = cutAPL[0] * sqrt(abs(1 - ((alpha + cutAPL[1]) * (alpha + cutAPL[1])) / (cutAPL[2] * cutAPL[2]))); - if ((alpha > cutAlphaL[0]) && (alpha < cutAlphaL[1]) && (qt > cutQTL) && (qt < q)) { - return EM_V0_Label::kLambda; + if (track.itsNClsInnerBarrel() < trackcuts.cfg_min_ncluster_itsib) { + return false; } - - // Check for AntiLambda candidates - q = cutAPL[0] * sqrt(abs(1 - ((alpha - cutAPL[1]) * (alpha - cutAPL[1])) / (cutAPL[2] * cutAPL[2]))); - if ((alpha > cutAlphaAL[0]) && (alpha < cutAlphaAL[1]) && (qt > cutQTL) && (qt < q)) { - return EM_V0_Label::kAntiLambda; + if (track.itsChi2NCl() > trackcuts.cfg_max_chi2its) { + return false; } - return EM_V0_Label::kUndef; - } - - template - bool IsSelected(TTrack const& track) - { - if (abs(track.eta()) > maxeta || track.pt() < minpt) { + if (track.tpcNClsCrossedRows() < trackcuts.cfg_min_ncrossedrows_tpc) { return false; } - - if (!track.hasITS() || !track.hasTPC()) { + if (track.tpcNClsFound() < trackcuts.cfg_min_ncluster_tpc) { return false; } - - if (track.itsNCls() < minitsncls) { + if (track.tpcChi2NCl() > trackcuts.cfg_max_chi2tpc) { + return false; + } + if (track.tpcCrossedRowsOverFindableCls() < trackcuts.cfg_min_cr2findable_ratio_tpc) { return false; } - if (track.itsChi2NCl() > maxchi2its) { + if (track.tpcFractionSharedCls() > trackcuts.cfg_max_frac_shared_clusters_tpc) { return false; } - if (track.tpcNClsCrossedRows() < mincrossedrows) { + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto track_par_cov_recalc = getTrackParCov(track); + track_par_cov_recalc.setPID(track.pidForTracking()); + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, track_par_cov_recalc, 2.f, matCorr, &mDcaInfoCov); + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + + if (std::fabs(track_par_cov_recalc.getEta()) > trackcuts.cfg_max_eta || track_par_cov_recalc.getPt() < trackcuts.cfg_min_pt) { return false; } - if (track.tpcChi2NCl() > maxchi2tpc) { + + if (std::fabs(dcaXY) > trackcuts.cfg_max_dcaxy) { return false; } - if (track.tpcCrossedRowsOverFindableCls() < 0.8) { + if (std::fabs(dcaZ) > trackcuts.cfg_max_dcaz) { return false; } + return true; } - template - bool IsSelectedTag(TTrack const& track) + template + bool isSelectedV0Leg(TCollision const& collision, TTrack const& track) { - if (abs(track.eta()) > maxeta || track.pt() < minpt) { + if (!track.hasITS() || !track.hasTPC()) { return false; } - if (!track.hasITS() || !track.hasTPC()) { + if (track.itsNCls() < v0cuts.cfg_min_ncluster_its) { return false; } - - if (abs(track.dcaXY()) > 0.1 || abs(track.dcaZ()) > 0.1) { + if (track.itsNClsInnerBarrel() < v0cuts.cfg_min_ncluster_itsib) { + return false; + } + if (track.itsChi2NCl() > v0cuts.cfg_max_chi2its) { return false; } - if (track.itsNCls() < 5) { + if (track.tpcNClsCrossedRows() < v0cuts.cfg_min_ncrossedrows_tpc) { return false; } - if (track.itsChi2NCl() > 5.f) { + if (track.tpcNClsFound() < v0cuts.cfg_min_ncluster_tpc) { return false; } - - if (track.tpcNClsCrossedRows() < 100) { + if (track.tpcChi2NCl() > v0cuts.cfg_max_chi2tpc) { + return false; + } + if (track.tpcCrossedRowsOverFindableCls() < v0cuts.cfg_min_cr2findable_ratio_tpc) { + return false; + } + if (track.tpcFractionSharedCls() > v0cuts.cfg_max_frac_shared_clusters_tpc) { return false; } - if (track.tpcChi2NCl() > 4.f) { + + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto track_par_cov_recalc = getTrackParCov(track); + track_par_cov_recalc.setPID(track.pidForTracking()); + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, track_par_cov_recalc, 2.f, matCorr, &mDcaInfoCov); + float dcaXY = mDcaInfoCov.getY(); + // float dcaZ = mDcaInfoCov.getZ(); + + if (std::fabs(track_par_cov_recalc.getEta()) > v0cuts.cfg_max_eta || track_par_cov_recalc.getPt() < v0cuts.cfg_min_pt) { return false; } - if (track.tpcCrossedRowsOverFindableCls() < 0.8) { + + if (std::fabs(dcaXY) < v0cuts.cfg_min_dcaxy_v0leg) { // this is applied in filter. return false; } + return true; } template - bool IsElectron(TTrack const& track) + bool isElectron(TTrack const& track) { - return (minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl) && (abs(track.tofNSigmaEl()) < maxTOFNsigmaEl || track.beta() < 0.f); + bool is_El_TPC = v0cuts.cfg_min_TPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < v0cuts.cfg_max_TPCNsigmaEl; + bool is_El_TOF = track.hasTOF() ? v0cuts.cfg_min_TOFNsigmaEl < track.tofNSigmaEl() && track.tofNSigmaEl() < v0cuts.cfg_max_TOFNsigmaEl : true; // TOFif + return is_El_TPC && is_El_TOF; } template - bool IsElectronTag(TTrack const& track) + bool isPion(TTrack const& track) { - if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi) { - return false; // reject pion first - } - if (track.p() < 0.4) { - return abs(track.tpcNSigmaEl()) < 2.f; - } else { - return abs(track.tpcNSigmaEl()) < 2.f && abs(track.tofNSigmaEl()) < 2.f; - } + bool is_Pi_TPC = v0cuts.cfg_min_TPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < v0cuts.cfg_max_TPCNsigmaPi; + bool is_Pi_TOF = track.hasTOF() ? v0cuts.cfg_min_TOFNsigmaPi < track.tofNSigmaPi() && track.tofNSigmaPi() < v0cuts.cfg_max_TOFNsigmaPi : true; // TOFif + return is_Pi_TPC && is_Pi_TOF; } template - bool IsPion(TTrack const& track) + bool isKaon(TTrack const& track) { - return abs(track.tpcNSigmaPi()) < maxTPCNsigmaPi && (abs(track.tofNSigmaPi()) < maxTOFNsigmaPi || track.beta() < 0.f); + bool is_Ka_TPC = v0cuts.cfg_min_TPCNsigmaKa < track.tpcNSigmaKa() && track.tpcNSigmaKa() < v0cuts.cfg_max_TPCNsigmaKa; + bool is_Ka_TOF = track.hasTOF() ? v0cuts.cfg_min_TOFNsigmaKa < track.tofNSigmaKa() && track.tofNSigmaKa() < v0cuts.cfg_max_TOFNsigmaKa : true; // TOFif + return is_Ka_TPC && is_Ka_TOF; } template - bool IsKaon(TTrack const& track) + bool isProton(TTrack const& track) { - return abs(track.tpcNSigmaKa()) < maxTPCNsigmaKa && (abs(track.tofNSigmaKa()) < maxTOFNsigmaKa || track.beta() < 0.f); + bool is_Pr_TPC = v0cuts.cfg_min_TPCNsigmaPr < track.tpcNSigmaPr() && track.tpcNSigmaPr() < v0cuts.cfg_max_TPCNsigmaPr; + bool is_Pr_TOF = track.hasTOF() ? v0cuts.cfg_min_TOFNsigmaPr < track.tofNSigmaPr() && track.tofNSigmaPr() < v0cuts.cfg_max_TOFNsigmaPr : true; // TOFif + return is_Pr_TPC && is_Pr_TOF; } template - bool IsProton(TTrack const& track) + bool isPionTight(TTrack const& track) { - return abs(track.tpcNSigmaPr()) < maxTPCNsigmaPr && (abs(track.tofNSigmaPr()) < maxTOFNsigmaPr || track.beta() < 0.f); + bool is_Pi_TPC = v0cuts.cfg_min_TPCNsigmaPi_tight < track.tpcNSigmaPi() && track.tpcNSigmaPi() < v0cuts.cfg_max_TPCNsigmaPi_tight; + bool is_Pi_TOF = track.hasTOF() ? v0cuts.cfg_min_TOFNsigmaPi_tight < track.tofNSigmaPi() && track.tofNSigmaPi() < v0cuts.cfg_max_TOFNsigmaPi_tight : true; // TOFif + return is_Pi_TPC && is_Pi_TOF; + } + + template + bool isProtonTight(TTrack const& track) + { + bool is_Pr_TPC = v0cuts.cfg_min_TPCNsigmaPr_tight < track.tpcNSigmaPr() && track.tpcNSigmaPr() < v0cuts.cfg_max_TPCNsigmaPr_tight; + bool is_Pr_TOF = track.hasTOF() ? v0cuts.cfg_min_TOFNsigmaPr_tight < track.tofNSigmaPr() && track.tofNSigmaPr() < v0cuts.cfg_max_TOFNsigmaPr_tight : true; // TOFif + return is_Pr_TPC && is_Pr_TOF; } template void fillTrackTable(TCollision const& collision, TTrack const& track, const int pidlabel, const int tracktype) { if (std::find(stored_trackIds.begin(), stored_trackIds.end(), track.globalIndex()) == stored_trackIds.end()) { + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto track_par_cov_recalc = getTrackParCov(track); + track_par_cov_recalc.setPID(track.pidForTracking()); + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, track_par_cov_recalc, 2.f, matCorr, &mDcaInfoCov); + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + emprimarytracks(collision.globalIndex(), collision.posZ(), collision.numContrib(), track.pt(), track.eta(), track.phi(), track.tgl(), track.signed1Pt(), - track.dcaXY(), track.dcaZ(), track.cYY(), track.cZZ(), track.cZY(), + dcaXY, dcaZ, track_par_cov_recalc.getSigmaY2(), track_par_cov_recalc.getSigmaZ2(), track_par_cov_recalc.getSigmaZY(), track.tpcNClsFindable(), track.tpcNClsFound(), track.tpcNClsCrossedRows(), track.tpcChi2NCl(), track.tpcInnerParam(), track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaMu(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), track.beta(), track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), - track.itsClusterSizes(), track.itsChi2NCl(), track.detectorMap(), pidlabel, tracktype); + track.itsClusterSizes(), track.itsChi2NCl(), track.tofChi2(), track.detectorMap(), pidlabel, tracktype); stored_trackIds.emplace_back(track.globalIndex()); } } - Filter collisionFilter_common = nabs(o2::aod::collision::posZ) < 10.f && o2::aod::collision::numContrib > (uint16_t)0 && o2::aod::evsel::sel8 == true; + //! type of V0. 0: built solely for cascades (does not pass standard V0 cuts), 1: standard 2, 3: photon-like with TPC-only use. Regular analysis should always use type 1. + Filter v0Filter = o2::aod::v0data::v0Type == uint8_t(1) && o2::aod::v0data::v0cosPA > v0cuts.cfg_min_cospa.value&& o2::aod::v0data::dcaV0daughters v0cuts.cfg_min_dcaxy_v0leg&& nabs(o2::aod::v0data::dcanegtopv) > v0cuts.cfg_min_dcaxy_v0leg; + using filteredV0s = soa::Filtered; + + Filter cascadeFilter = o2::aod::cascdata::dcacascdaughters < cascadecuts.cfg_max_dcadau.value && nabs(o2::aod::cascdata::dcanegtopv) > cascadecuts.cfg_min_dcaxy_v0leg&& nabs(o2::aod::cascdata::dcanegtopv) > cascadecuts.cfg_min_dcaxy_v0leg&& nabs(o2::aod::cascdata::dcabachtopv) > cascadecuts.cfg_min_dcaxy_bachelor; + using filteredCascades = soa::Filtered; + + Filter collisionFilter_common = nabs(o2::aod::collision::posZ) < 10.f && o2::aod::evsel::sel8 == true; using filteredMyCollisions = soa::Filtered; - //! type of V0. 0: built solely for cascades (does not pass standard V0 cuts), 1: standard 2, 3: photon-like with TPC-only use. Regular analysis should always use type 1 or 3. - Preslice perCollision_v0 = o2::aod::v0::collisionId; - Preslice perCollision_cascade = o2::aod::cascade::collisionId; + Preslice perCollision_v0 = o2::aod::v0data::collisionId; + Preslice perCollision_cascade = o2::aod::cascdata::collisionId; Preslice perCollision_track = o2::aod::track::collisionId; - // Don't apply filter to tracks, because posTrack_as<>, negTrack_as<> is used. - Partition posTracks = o2::aod::track::signed1Pt > 0.f && o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& o2::aod::track::tpcChi2NCl < maxchi2tpc&& o2::aod::track::itsChi2NCl < maxchi2its&& nabs(o2::aod::track::dcaXY) < maxdcaXY&& nabs(o2::aod::track::dcaZ) < maxdcaZ&& ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true && (minTPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < maxTPCNsigmaEl); - Partition negTracks = o2::aod::track::signed1Pt < 0.f && o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& o2::aod::track::tpcChi2NCl < maxchi2tpc&& o2::aod::track::itsChi2NCl < maxchi2its&& nabs(o2::aod::track::dcaXY) < maxdcaXY&& nabs(o2::aod::track::dcaZ) < maxdcaZ&& ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true && (minTPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < maxTPCNsigmaEl); + Partition posTracks = o2::aod::track::signed1Pt > 0.f && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true; + Partition negTracks = o2::aod::track::signed1Pt < 0.f && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true; std::vector stored_trackIds; - void processPID(filteredMyCollisions const& collisions, aod::BCsWithTimestamps const&, aod::V0s const& v0s, aod::Cascades const& cascades, MyTracks const& tracks) + void processPID(filteredMyCollisions const& collisions, aod::BCsWithTimestamps const&, filteredV0s const& v0s, filteredCascades const& cascades, MyTracks const& tracks) { stored_trackIds.reserve(tracks.size()); - for (auto& collision : collisions) { + for (const auto& collision : collisions) { registry.fill(HIST("hEventCounter"), 1.0); // all - auto bc = collision.template bc_as(); + auto bc = collision.template foundBC_as(); initCCDB(bc); - if (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { - continue; - } - - std::array pVtx = {collision.posX(), collision.posY(), collision.posZ()}; auto v0s_coll = v0s.sliceBy(perCollision_v0, collision.globalIndex()); - for (auto& v0 : v0s_coll) { - if (v0.v0Type() != 1) { - continue; - } + for (const auto& v0 : v0s_coll) { auto pos = v0.template posTrack_as(); auto neg = v0.template negTrack_as(); - if (!IsSelected(pos) || !IsSelected(neg)) { + if (!isSelectedV0Leg(collision, pos) || !isSelectedV0Leg(collision, neg)) { continue; } if (pos.sign() * neg.sign() > 0) { continue; } - // Calculate DCA with respect to the collision associated to the V0, not individual tracks - gpu::gpustd::array dcaInfo_pos; - auto pTrackPar = getTrackPar(pos); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackPar, 2.f, fitter.getMatCorrType(), &dcaInfo_pos); - if (abs(dcaInfo_pos[0]) < mindcaxytopv_v0leg) { - continue; - } + registry.fill(HIST("V0/hPCA"), v0.dcaV0daughters()); + registry.fill(HIST("V0/hCosPA"), v0.v0cosPA()); + registry.fill(HIST("V0/hAP"), v0.alpha(), v0.qtarm()); - gpu::gpustd::array dcaInfo_neg; - auto nTrackPar = getTrackPar(neg); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackPar, 2.f, fitter.getMatCorrType(), &dcaInfo_neg); - if (abs(dcaInfo_neg[0]) < mindcaxytopv_v0leg) { + if (v0.dcaV0daughters() > v0cuts.cfg_max_dcadau) { continue; } - - // reconstruct V0s - auto pTrack = getTrackParCov(pos); // positive - auto nTrack = getTrackParCov(neg); // negative - std::array svpos = {0.}; // secondary vertex position - std::array pvec0 = {0.}; - std::array pvec1 = {0.}; - - int nCand = fitter.process(pTrack, nTrack); - if (nCand != 0) { - fitter.propagateTracksToVertex(); - const auto& vtx = fitter.getPCACandidate(); - for (int i = 0; i < 3; i++) { - svpos[i] = vtx[i]; - } - fitter.getTrack(0).getPxPyPzGlo(pvec0); // positive - fitter.getTrack(1).getPxPyPzGlo(pvec1); // negative - } else { + if (v0.v0cosPA() < v0cuts.cfg_min_cospa) { continue; } - std::array pvxyz{pvec0[0] + pvec1[0], pvec0[1] + pvec1[1], pvec0[2] + pvec1[2]}; - - float v0dca = std::sqrt(fitter.getChi2AtPCACandidate()); // distance between 2 legs. - float v0CosinePA = RecoDecay::cpa(pVtx, svpos, pvxyz); - registry.fill(HIST("hPCA"), v0dca); - registry.fill(HIST("hCosPA"), v0CosinePA); - if (v0dca > maxdcav0dau) { - continue; - } - if (v0CosinePA < minv0cospa) { - continue; - } - - float alpha = v0_alpha(pvec0[0], pvec0[1], pvec0[2], pvec1[0], pvec1[1], pvec1[2]); - float qt = v0_qt(pvec0[0], pvec0[1], pvec0[2], pvec1[0], pvec1[1], pvec1[2]); - registry.fill(HIST("hAP"), alpha, qt); - - float mGamma = RecoDecay::m(std::array{std::array{pvec0[0], pvec0[1], pvec0[2]}, std::array{pvec1[0], pvec1[1], pvec1[2]}}, std::array{o2::constants::physics::MassElectron, o2::constants::physics::MassElectron}); - float mK0Short = RecoDecay::m(std::array{std::array{pvec0[0], pvec0[1], pvec0[2]}, std::array{pvec1[0], pvec1[1], pvec1[2]}}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged}); - float mLambda = RecoDecay::m(std::array{std::array{pvec0[0], pvec0[1], pvec0[2]}, std::array{pvec1[0], pvec1[1], pvec1[2]}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); - float mAntiLambda = RecoDecay::m(std::array{std::array{pvec0[0], pvec0[1], pvec0[2]}, std::array{pvec1[0], pvec1[1], pvec1[2]}}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton}); - - EM_V0_Label v0id = checkV0(alpha, qt); - if (v0id == EM_V0_Label::kGamma && (IsElectron(pos) && IsElectron(neg))) { - registry.fill(HIST("hMassGamma"), mGamma); - registry.fill(HIST("hXY_Gamma"), svpos[0], svpos[1]); - float rxy = std::sqrt(std::pow(svpos[0], 2) + std::pow(svpos[1], 2)); - registry.fill(HIST("hMassGamma_Rxy"), rxy, mGamma); - if (mGamma < max_mee_pcm && rxy < 38.f) { - if (dist01(engine) < downscaling_electron) { - fillTrackTable(collision, pos, static_cast(o2::aod::pwgem::dilepton::PID_Label::kElectron), static_cast(o2::aod::pwgem::dilepton::Track_Type::kSecondary)); - } - if (dist01(engine) < downscaling_electron) { - fillTrackTable(collision, neg, static_cast(o2::aod::pwgem::dilepton::PID_Label::kElectron), static_cast(o2::aod::pwgem::dilepton::Track_Type::kSecondary)); - } - registry.fill(HIST("hTPCdEdx_P_El"), neg.p(), neg.tpcSignal()); - registry.fill(HIST("hTOFbeta_P_El"), neg.p(), neg.beta()); - registry.fill(HIST("hTPCdEdx_P_El"), pos.p(), pos.tpcSignal()); - registry.fill(HIST("hTOFbeta_P_El"), pos.p(), pos.beta()); - } - } else if (v0id == EM_V0_Label::kK0S && (IsPion(pos) && IsPion(neg))) { - registry.fill(HIST("hMassK0Short"), mK0Short); - if (abs(mK0Short - 0.497) < 0.01) { - registry.fill(HIST("hTPCdEdx_P_Pi"), neg.p(), neg.tpcSignal()); - registry.fill(HIST("hTOFbeta_P_Pi"), neg.p(), neg.beta()); - registry.fill(HIST("hTPCdEdx_P_Pi"), pos.p(), pos.tpcSignal()); - registry.fill(HIST("hTOFbeta_P_Pi"), pos.p(), pos.beta()); + if (isPion(pos) && isPion(neg)) { + registry.fill(HIST("V0/hMassK0Short"), v0.mK0Short()); + if (v0cuts.cfg_min_mass_k0s < v0.mK0Short() && v0.mK0Short() < v0cuts.cfg_max_mass_k0s) { + registry.fill(HIST("V0/hTPCdEdx_P_Pi"), neg.p(), neg.tpcSignal()); + registry.fill(HIST("V0/hTOFbeta_P_Pi"), neg.p(), neg.beta()); + registry.fill(HIST("V0/hTPCdEdx_P_Pi"), pos.p(), pos.tpcSignal()); + registry.fill(HIST("V0/hTOFbeta_P_Pi"), pos.p(), pos.beta()); if (dist01(engine) < downscaling_pion) { fillTrackTable(collision, pos, static_cast(o2::aod::pwgem::dilepton::PID_Label::kPion), static_cast(o2::aod::pwgem::dilepton::Track_Type::kSecondary)); } @@ -599,101 +600,87 @@ struct TreeCreatorElectronMLDDA { fillTrackTable(collision, neg, static_cast(o2::aod::pwgem::dilepton::PID_Label::kPion), static_cast(o2::aod::pwgem::dilepton::Track_Type::kSecondary)); } } - } else if (v0id == EM_V0_Label::kLambda && (IsProton(pos) && IsPion(neg))) { - registry.fill(HIST("hMassLambda"), mLambda); - if (abs(mLambda - 1.115) < 0.005) { + } + if (isProton(pos) && isPionTight(neg)) { + registry.fill(HIST("V0/hMassLambda"), v0.mLambda()); + if (v0cuts.cfg_min_mass_lambda < v0.mLambda() && v0.mLambda() < v0cuts.cfg_max_mass_lambda) { if (dist01(engine) < downscaling_proton) { fillTrackTable(collision, pos, static_cast(o2::aod::pwgem::dilepton::PID_Label::kProton), static_cast(o2::aod::pwgem::dilepton::Track_Type::kSecondary)); } - registry.fill(HIST("hTPCdEdx_P_Pr"), pos.p(), pos.tpcSignal()); - registry.fill(HIST("hTOFbeta_P_Pr"), pos.p(), pos.beta()); - registry.fill(HIST("hTPCdEdx_P_Pi"), neg.p(), neg.tpcSignal()); - registry.fill(HIST("hTOFbeta_P_Pi"), neg.p(), neg.beta()); - if (dist01(engine) < downscaling_pion) { - fillTrackTable(collision, neg, static_cast(o2::aod::pwgem::dilepton::PID_Label::kPion), static_cast(o2::aod::pwgem::dilepton::Track_Type::kSecondary)); - } + registry.fill(HIST("V0/hTPCdEdx_P_Pr"), pos.p(), pos.tpcSignal()); + registry.fill(HIST("V0/hTOFbeta_P_Pr"), pos.p(), pos.beta()); } - } else if (v0id == EM_V0_Label::kAntiLambda && (IsPion(pos) && IsProton(neg))) { - registry.fill(HIST("hMassAntiLambda"), mAntiLambda); - if (abs(mAntiLambda - 1.115) < 0.005) { - if (dist01(engine) < downscaling_pion) { - fillTrackTable(collision, pos, static_cast(o2::aod::pwgem::dilepton::PID_Label::kPion), static_cast(o2::aod::pwgem::dilepton::Track_Type::kSecondary)); - } + } + if (isPionTight(pos) && isProton(neg)) { + registry.fill(HIST("V0/hMassAntiLambda"), v0.mAntiLambda()); + if (v0cuts.cfg_min_mass_lambda < v0.mAntiLambda() && v0.mAntiLambda() < v0cuts.cfg_max_mass_lambda) { if (dist01(engine) < downscaling_proton) { fillTrackTable(collision, neg, static_cast(o2::aod::pwgem::dilepton::PID_Label::kProton), static_cast(o2::aod::pwgem::dilepton::Track_Type::kSecondary)); } - registry.fill(HIST("hTPCdEdx_P_Pr"), neg.p(), neg.tpcSignal()); - registry.fill(HIST("hTOFbeta_P_Pr"), neg.p(), neg.beta()); - registry.fill(HIST("hTPCdEdx_P_Pi"), pos.p(), pos.tpcSignal()); - registry.fill(HIST("hTOFbeta_P_Pi"), pos.p(), pos.beta()); + registry.fill(HIST("V0/hTPCdEdx_P_Pr"), neg.p(), neg.tpcSignal()); + registry.fill(HIST("V0/hTOFbeta_P_Pr"), neg.p(), neg.beta()); } } - } // end of v0 loop - - // extra statistics for electrons tagged by photon conversions - auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { - if (!IsSelected(pos) || !IsSelected(ele)) { - continue; - } - - if (!IsElectron(pos) || !IsElectron(ele)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - float phiv = getPhivPair(pos.px(), pos.py(), pos.pz(), ele.px(), ele.py(), ele.pz(), pos.sign(), ele.sign(), d_bz); - registry.fill(HIST("hMvsPhiV"), phiv, v12.M()); - - if (v12.M() < slope * phiv + intercept) { // photon conversion is found. - if (dist01(engine) < downscaling_electron) { - fillTrackTable(collision, ele, static_cast(o2::aod::pwgem::dilepton::PID_Label::kElectron), static_cast(o2::aod::pwgem::dilepton::Track_Type::kPrimary)); // secondary in primary electron candidates - } - if (dist01(engine) < downscaling_electron) { - fillTrackTable(collision, pos, static_cast(o2::aod::pwgem::dilepton::PID_Label::kElectron), static_cast(o2::aod::pwgem::dilepton::Track_Type::kPrimary)); // secondary in primary electron candidates + if (isElectron(pos) && isElectron(neg) && store_v0photons) { + registry.fill(HIST("V0/hMassGamma"), v0.mGamma()); + registry.fill(HIST("V0/hXY_Gamma"), v0.x(), v0.y()); + registry.fill(HIST("V0/hMassGamma_Rxy"), v0.v0radius(), v0.mGamma()); + if ((v0cuts.cfg_min_mass_photon < v0.mGamma() && v0.mGamma() < v0cuts.cfg_max_mass_photon)) { + if (dist01(engine) < downscaling_electron) { + fillTrackTable(collision, pos, static_cast(o2::aod::pwgem::dilepton::PID_Label::kElectron), static_cast(o2::aod::pwgem::dilepton::Track_Type::kSecondary)); + } + if (dist01(engine) < downscaling_electron) { + fillTrackTable(collision, neg, static_cast(o2::aod::pwgem::dilepton::PID_Label::kElectron), static_cast(o2::aod::pwgem::dilepton::Track_Type::kSecondary)); + } + registry.fill(HIST("V0/hTPCdEdx_P_El"), neg.p(), neg.tpcSignal()); + registry.fill(HIST("V0/hTOFbeta_P_El"), neg.p(), neg.beta()); + registry.fill(HIST("V0/hTPCdEdx_P_El"), pos.p(), pos.tpcSignal()); + registry.fill(HIST("V0/hTOFbeta_P_El"), pos.p(), pos.beta()); } } - if (v12.M() < max_mee_pi0) { // dielectron from pi0 is found. - if (dist01(engine) < downscaling_electron) { - fillTrackTable(collision, ele, static_cast(o2::aod::pwgem::dilepton::PID_Label::kElectron), static_cast(o2::aod::pwgem::dilepton::Track_Type::kPrimary)); + } // end of v0 loop + + if (!store_v0photons) { + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + for (const auto& [pos, neg] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { + if (!isSelectedTrack(collision, pos) || !isSelectedTrack(collision, neg)) { + continue; } - if (dist01(engine) < downscaling_electron) { - fillTrackTable(collision, pos, static_cast(o2::aod::pwgem::dilepton::PID_Label::kElectron), static_cast(o2::aod::pwgem::dilepton::Track_Type::kPrimary)); + + if (!isElectron(pos) || !isElectron(neg)) { + continue; } - } - } // end of ULS pair loop - auto tracks_coll = tracks.sliceBy(perCollision_track, collision.globalIndex()); - for (auto& track : tracks_coll) { - if (!IsSelectedTag(track)) { - continue; - } + ROOT::Math::PtEtaPhiMVector v1(neg.pt(), neg.eta(), neg.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pos.px(), pos.py(), pos.pz(), neg.px(), neg.py(), neg.pz(), pos.sign(), neg.sign(), d_bz); + registry.fill(HIST("hMvsPhiV"), phiv, v12.M()); - registry.fill(HIST("hTPCdEdx_P"), track.p(), track.tpcSignal()); - registry.fill(HIST("hTOFbeta_P"), track.p(), track.beta()); - registry.fill(HIST("hTPCNsigmaEl_P"), track.p(), track.tpcNSigmaEl()); - registry.fill(HIST("hTOFNsigmaEl_P"), track.p(), track.tofNSigmaEl()); - registry.fill(HIST("hTPCNsigmaMu_P"), track.p(), track.tpcNSigmaMu()); - registry.fill(HIST("hTOFNsigmaMu_P"), track.p(), track.tofNSigmaMu()); - registry.fill(HIST("hTPCNsigmaPi_P"), track.p(), track.tpcNSigmaPi()); - registry.fill(HIST("hTOFNsigmaPi_P"), track.p(), track.tofNSigmaPi()); - registry.fill(HIST("hTPCNsigmaKa_P"), track.p(), track.tpcNSigmaKa()); - registry.fill(HIST("hTOFNsigmaKa_P"), track.p(), track.tofNSigmaKa()); - registry.fill(HIST("hTPCNsigmaPr_P"), track.p(), track.tpcNSigmaPr()); - registry.fill(HIST("hTOFNsigmaPr_P"), track.p(), track.tofNSigmaPr()); - } // end of track loop + if (v12.M() < slope * phiv + intercept) { // photon conversion is found. + registry.fill(HIST("V0/hTPCdEdx_P_El"), neg.p(), neg.tpcSignal()); + registry.fill(HIST("V0/hTOFbeta_P_El"), neg.p(), neg.beta()); + registry.fill(HIST("V0/hTPCdEdx_P_El"), pos.p(), pos.tpcSignal()); + registry.fill(HIST("V0/hTOFbeta_P_El"), pos.p(), pos.beta()); + + if (dist01(engine) < downscaling_electron) { + fillTrackTable(collision, neg, static_cast(o2::aod::pwgem::dilepton::PID_Label::kElectron), static_cast(o2::aod::pwgem::dilepton::Track_Type::kPrimary)); // secondary in primary electron candidates + } + if (dist01(engine) < downscaling_electron) { + fillTrackTable(collision, pos, static_cast(o2::aod::pwgem::dilepton::PID_Label::kElectron), static_cast(o2::aod::pwgem::dilepton::Track_Type::kPrimary)); // secondary in primary electron candidates + } + } + } // end of ULS pair loop + } auto cascades_coll = cascades.sliceBy(perCollision_cascade, collision.globalIndex()); - for (auto& cascade : cascades_coll) { + for (const auto& cascade : cascades_coll) { // Track casting auto bachelor = cascade.template bachelor_as(); - auto v0 = cascade.template v0_as(); - auto pos = v0.template posTrack_as(); - auto neg = v0.template negTrack_as(); - if (!IsSelected(pos) || !IsSelected(neg) || !IsSelected(bachelor)) { + auto pos = cascade.template posTrack_as(); + auto neg = cascade.template negTrack_as(); + if (!isSelectedV0Leg(collision, pos) || !isSelectedV0Leg(collision, neg) || !isSelectedV0Leg(collision, bachelor)) { continue; } @@ -701,338 +688,108 @@ struct TreeCreatorElectronMLDDA { continue; } - if (v0.v0Type() != 0 && v0.v0Type() != 1) { - continue; - } - - // Calculate DCA with respect to the collision associated to the V0, not individual tracks - gpu::gpustd::array dcaInfo_pos; - auto pTrackPar = getTrackPar(pos); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackPar, 2.f, fitter.getMatCorrType(), &dcaInfo_pos); - if (abs(dcaInfo_pos[0]) < mindcaxytopv_v0leg) { - continue; - } - - gpu::gpustd::array dcaInfo_neg; - auto nTrackPar = getTrackPar(neg); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackPar, 2.f, fitter.getMatCorrType(), &dcaInfo_neg); - if (abs(dcaInfo_neg[0]) < mindcaxytopv_v0leg) { - continue; - } - - // Calculate DCA with respect to the collision associated to the Cascade, not individual tracks - gpu::gpustd::array dcaInfo_bach; - auto bachTrackPar = getTrackPar(bachelor); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, bachTrackPar, 2.f, fitter.getMatCorrType(), &dcaInfo_bach); - if (abs(dcaInfo_bach[0]) < mindcaxytopv_bach_casc) { - continue; - } - - if (bachelor.sign() < 0) { // omega -> L + K- -> p + pi- + K- - if (abs(pos.tpcNSigmaPr()) > 3.f || abs(neg.tpcNSigmaPi()) > 3.f) { + if (bachelor.sign() < 0) { // Omega- -> L + K- -> p + pi- + K- + if (!isProtonTight(pos) || !isPionTight(neg)) { continue; } - } else { // omegabar -> Lbar + K+ -> pbar + pi+ + K+ - if (abs(pos.tpcNSigmaPi()) > 3.f || abs(neg.tpcNSigmaPr()) > 3.f) { + } else { // Omegabar+ -> Lbar + K+ -> pbar + pi+ + K+ + if (!isProtonTight(neg) || !isPionTight(pos)) { continue; } } - // reconstruct V0s - auto pTrack = getTrackParCov(pos); // positive - auto nTrack = getTrackParCov(neg); // negative - std::array svpos = {0.}; // secondary vertex position - std::array pvec0 = {0.}; - std::array pvec1 = {0.}; - - int nCand = fitter.process(pTrack, nTrack); - if (nCand != 0) { - fitter.propagateTracksToVertex(); - const auto& vtx = fitter.getPCACandidate(); - for (int i = 0; i < 3; i++) { - svpos[i] = vtx[i]; - } - fitter.getTrack(0).getPxPyPzGlo(pvec0); // positive - fitter.getTrack(1).getPxPyPzGlo(pvec1); // negative - } else { - continue; - } - std::array pvxyz{pvec0[0] + pvec1[0], pvec0[1] + pvec1[1], pvec0[2] + pvec1[2]}; - float v0_rxy = std::sqrt(std::pow(svpos[0], 2) + std::pow(svpos[1], 2)); - if (v0_rxy < min_v0rxy_in_cascade) { + registry.fill(HIST("Cascade/hMassLambda"), cascade.mLambda()); + if (!(v0cuts.cfg_min_mass_lambda < cascade.mLambda() && cascade.mLambda() < v0cuts.cfg_max_mass_lambda)) { continue; } - float dcav0topv = CalculateDCAStraightToPV(svpos[0], svpos[1], svpos[2], pvxyz[0], pvxyz[1], pvxyz[2], collision.posX(), collision.posY(), collision.posZ()); - if (dcav0topv < min_dcav0topv_casc) { + if (cascade.cascradius() > cascade.v0radius()) { continue; } - float mLambda = RecoDecay::m(std::array{std::array{pvec0[0], pvec0[1], pvec0[2]}, std::array{pvec1[0], pvec1[1], pvec1[2]}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); - float mAntiLambda = RecoDecay::m(std::array{std::array{pvec0[0], pvec0[1], pvec0[2]}, std::array{pvec1[0], pvec1[1], pvec1[2]}}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton}); - float v0dca_casc = std::sqrt(fitter.getChi2AtPCACandidate()); // distance between 2 legs. - float v0CosinePA_casc = RecoDecay::cpa(pVtx, svpos, pvxyz); - registry.fill(HIST("Cascade/hV0PCA"), v0dca_casc); - registry.fill(HIST("Cascade/hV0CosPA"), v0CosinePA_casc); - registry.fill(HIST("Cascade/hMassLambda"), mLambda); - registry.fill(HIST("Cascade/hMassAntiLambda"), mAntiLambda); + registry.fill(HIST("Cascade/hV0PCA"), cascade.dcaV0daughters()); + registry.fill(HIST("Cascade/hV0CosPA"), cascade.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("Cascade/hPCA"), cascade.dcacascdaughters()); // distance between bachelor and V0. + registry.fill(HIST("Cascade/hCosPA"), cascade.casccosPA(collision.posX(), collision.posY(), collision.posZ())); - if (v0dca_casc > maxdcav0dau_casc) { + if (cascade.dcaV0daughters() > cascadecuts.cfg_max_dcadau_v0) { continue; } - if (v0CosinePA_casc < minv0cospa_casc) { + if (cascade.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadecuts.cfg_min_cospa_v0) { continue; } - if (bachelor.sign() < 0 && abs(mLambda - 1.115) > 0.005) { + if (cascade.v0radius() < cascadecuts.cfg_min_rxy_v0) { continue; } - if (bachelor.sign() > 0 && abs(mAntiLambda - 1.115) > 0.005) { - continue; - } - float alpha = v0_alpha(pvec0[0], pvec0[1], pvec0[2], pvec1[0], pvec1[1], pvec1[2]); - float qt = v0_qt(pvec0[0], pvec0[1], pvec0[2], pvec1[0], pvec1[1], pvec1[2]); - registry.fill(HIST("Cascade/hAP_V0"), alpha, qt); - - // after V0 is found. - pTrack = fitter.getTrack(0); - nTrack = fitter.getTrack(1); - - // Calculate position covariance matrix - auto covVtxV = fitter.calcPCACovMatrix(0); - float positionCovariance[6] = {0.f}; - positionCovariance[0] = covVtxV(0, 0); - positionCovariance[1] = covVtxV(1, 0); - positionCovariance[2] = covVtxV(1, 1); - positionCovariance[3] = covVtxV(2, 0); - positionCovariance[4] = covVtxV(2, 1); - positionCovariance[5] = covVtxV(2, 2); - std::array covTpositive = {0.}; - std::array covTnegative = {0.}; - float momentumCovariance[6] = {0.f}; - pTrack.getCovXYZPxPyPzGlo(covTpositive); - nTrack.getCovXYZPxPyPzGlo(covTnegative); - constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component - for (int i = 0; i < 6; i++) { - momentumCovariance[i] = covTpositive[MomInd[i]] + covTnegative[MomInd[i]]; - } - std::array covV = {0.}; - for (int i = 0; i < 6; i++) { - covV[MomInd[i]] = momentumCovariance[i]; - covV[i] = positionCovariance[i]; - } - auto lV0Track = o2::track::TrackParCov({svpos[0], svpos[1], svpos[2]}, {pvxyz[0], pvxyz[1], pvxyz[2]}, covV, 0, true); - lV0Track.setAbsCharge(0); - lV0Track.setPID(o2::track::PID::Lambda); - auto lBachelorTrack = getTrackParCov(bachelor); - - nCand = fitter.process(lV0Track, lBachelorTrack); - if (nCand != 0) { - fitter.propagateTracksToVertex(); - const auto& vtx = fitter.getPCACandidate(); - for (int i = 0; i < 3; i++) { - svpos[i] = vtx[i]; - } - fitter.getTrack(0).getPxPyPzGlo(pvec0); // v0 - fitter.getTrack(1).getPxPyPzGlo(pvec1); // bachelor - } else { - continue; - } - std::array pvxyz_casc{pvec0[0] + pvec1[0], pvec0[1] + pvec1[1], pvec0[2] + pvec1[2]}; - float casc_rxy = std::sqrt(std::pow(svpos[0], 2) + std::pow(svpos[1], 2)); - if (casc_rxy < min_cascade_rxy) { + if (cascade.cascradius() < cascadecuts.cfg_min_rxy) { continue; } - if (casc_rxy > v0_rxy) { + if (cascade.dcacascdaughters() > cascadecuts.cfg_max_dcadau) { continue; } - - float casc_dca = std::sqrt(fitter.getChi2AtPCACandidate()); // distance between bachelor and V0. - float casc_cpa = RecoDecay::cpa(pVtx, svpos, pvxyz_casc); - registry.fill(HIST("Cascade/hPCA"), casc_dca); - registry.fill(HIST("Cascade/hCosPA"), casc_cpa); - registry.fill(HIST("Cascade/hRxy"), v0_rxy, casc_rxy); - - alpha = v0_alpha(pvec0[0], pvec0[1], pvec0[2], pvec1[0], pvec1[1], pvec1[2]); - qt = v0_qt(pvec0[0], pvec0[1], pvec0[2], pvec1[0], pvec1[1], pvec1[2]); - registry.fill(HIST("Cascade/hAP"), alpha, qt); - - if (casc_dca > max_casc_dcadau) { - continue; - } - if (casc_cpa < min_casc_cospa) { + if (cascade.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadecuts.cfg_min_cospa) { continue; } - float length = std::sqrt(std::pow(svpos[0] - collision.posX(), 2) + std::pow(svpos[1] - collision.posY(), 2) + std::pow(svpos[2] - collision.posZ(), 2)); - float mom = RecoDecay::sqrtSumOfSquares(pvxyz_casc[0], pvxyz_casc[1], pvxyz_casc[2]); - float ctauXi = length / mom * o2::constants::physics::MassXiMinus; - float ctauOmega = length / mom * o2::constants::physics::MassOmegaMinus; - float pt = RecoDecay::sqrtSumOfSquares(pvxyz_casc[0], pvxyz_casc[1]); - - // after DCAFitter - lV0Track = fitter.getTrack(0); - lBachelorTrack = fitter.getTrack(1); - float mXi = RecoDecay::m(std::array{std::array{pvec0[0], pvec0[1], pvec0[2]}, std::array{pvec1[0], pvec1[1], pvec1[2]}}, std::array{o2::constants::physics::MassLambda, o2::constants::physics::MassPionCharged}); // ctau = 4.91 cm - float mOmega = RecoDecay::m(std::array{std::array{pvec0[0], pvec0[1], pvec0[2]}, std::array{pvec1[0], pvec1[1], pvec1[2]}}, std::array{o2::constants::physics::MassLambda, o2::constants::physics::MassKaonCharged}); // ctau 2.46 cm - - if (IsPion(bachelor)) { - registry.fill(HIST("Cascade/hMassXi"), mXi); - registry.fill(HIST("Cascade/hMassPt_Xi"), mXi, pt); - registry.fill(HIST("Cascade/hMassPt_Xi_bachelor"), mXi, bachelor.p()); - registry.fill(HIST("Cascade/hRxy_Xi"), mXi, casc_rxy); - registry.fill(HIST("Cascade/hCTau_Xi"), mXi, ctauXi); - // if (abs(mXi - 1.321) < 0.005) { // select Xi candidates - // if (dist01(engine) < downscaling_pion) { - // fillTrackTable(collision, bachelor, static_cast(o2::aod::pwgem::dilepton::PID_Label::kPion), static_cast(o2::aod::pwgem::dilepton::Track_Type::kPrimary)); - // } - // } + float length = std::sqrt(std::pow(cascade.x() - collision.posX(), 2) + std::pow(cascade.y() - collision.posY(), 2) + std::pow(cascade.z() - collision.posZ(), 2)); + float mom = cascade.p(); + float ctauXi = length / mom * o2::constants::physics::MassXiMinus; // 4.91 cm in PDG + float ctauOmega = length / mom * o2::constants::physics::MassOmegaMinus; // 2.46 cm in PDG + + if (isPion(bachelor)) { + registry.fill(HIST("Cascade/hMassXi"), cascade.mXi()); + registry.fill(HIST("Cascade/hMassPt_Xi"), cascade.mXi(), cascade.pt()); + registry.fill(HIST("Cascade/hMassPt_Xi_bachelor"), cascade.mXi(), bachelor.p()); + registry.fill(HIST("Cascade/hRxy_Xi"), cascade.mXi(), cascade.cascradius()); + registry.fill(HIST("Cascade/hCTau_Xi"), cascade.mXi(), ctauXi); } - if (abs(mXi - 1.322) > 0.01 && IsKaon(bachelor)) { // reject Xi candidates - registry.fill(HIST("Cascade/hMassOmega"), mOmega); - registry.fill(HIST("Cascade/hMassPt_Omega"), mOmega, pt); - registry.fill(HIST("Cascade/hMassPt_Omega_bachelor"), mOmega, bachelor.p()); - registry.fill(HIST("Cascade/hRxy_Omega"), mOmega, casc_rxy); - registry.fill(HIST("Cascade/hCTau_Omega"), mOmega, ctauOmega); - if (abs(mOmega - 1.672) < 0.004) { // select Omega candidates + if (!(cascadecuts.cfg_min_mass_Xi < cascade.mXi() && cascade.mXi() < cascadecuts.cfg_max_mass_Xi) && isKaon(bachelor)) { // reject Xi candidates + registry.fill(HIST("Cascade/hMassOmega"), cascade.mOmega()); + registry.fill(HIST("Cascade/hMassPt_Omega"), cascade.mOmega(), cascade.pt()); + registry.fill(HIST("Cascade/hMassPt_Omega_bachelor"), cascade.mOmega(), bachelor.p()); + registry.fill(HIST("Cascade/hRxy_Omega"), cascade.mOmega(), cascade.cascradius()); + registry.fill(HIST("Cascade/hCTau_Omega"), cascade.mOmega(), ctauOmega); + if (cascadecuts.cfg_min_mass_Omega < cascade.mOmega() && cascade.mOmega() < cascadecuts.cfg_max_mass_Omega) { // select Omega candidates + registry.fill(HIST("V0/hTPCdEdx_P_Ka"), bachelor.p(), bachelor.tpcSignal()); + registry.fill(HIST("V0/hTOFbeta_P_Ka"), bachelor.p(), bachelor.beta()); if (dist01(engine) < downscaling_kaon) { fillTrackTable(collision, bachelor, static_cast(o2::aod::pwgem::dilepton::PID_Label::kKaon), static_cast(o2::aod::pwgem::dilepton::Track_Type::kPrimary)); } } } - } // end of cascade loop - } // end of collision loop - stored_trackIds.clear(); - stored_trackIds.shrink_to_fit(); - } // end of process - - Partition positrons = o2::aod::track::signed1Pt > 0.f && o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& o2::aod::track::tpcChi2NCl < maxchi2tpc&& o2::aod::track::itsChi2NCl < maxchi2its&& nabs(o2::aod::track::dcaXY) < maxdcaXY&& nabs(o2::aod::track::dcaZ) < maxdcaZ&& ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true && (minTPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < maxTPCNsigmaEl); - Partition electrons = o2::aod::track::signed1Pt < 0.f && o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& o2::aod::track::tpcChi2NCl < maxchi2tpc&& o2::aod::track::itsChi2NCl < maxchi2its&& nabs(o2::aod::track::dcaXY) < maxdcaXY&& nabs(o2::aod::track::dcaZ) < maxdcaZ&& ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true && (minTPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < maxTPCNsigmaEl); - std::vector stored_secondary_electronIds; - void processPrimary(filteredMyCollisions const& collisions, aod::BCsWithTimestamps const&, aod::V0s const&, MyTracks const&) - { - stored_trackIds.reserve(positrons.size() + electrons.size()); - stored_secondary_electronIds.reserve(positrons.size() + electrons.size()); - - for (auto& collision : collisions) { - registry.fill(HIST("hEventCounter"), 1.0); // all - - auto bc = collision.template bc_as(); - initCCDB(bc); - - if (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { - continue; - } - - auto positrons_per_coll = positrons->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - auto electrons_per_coll = electrons->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - - for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(positrons_per_coll, electrons_per_coll))) { // electron is tag, positron is probe. - if (!IsSelectedTag(ele) || !IsElectronTag(ele)) { // require tight global track selection - continue; - } - - if (!IsSelected(pos) || !IsElectron(pos)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - float phiv = getPhivPair(pos.px(), pos.py(), pos.pz(), ele.px(), ele.py(), ele.pz(), pos.sign(), ele.sign(), d_bz); - registry.fill(HIST("hMvsPhiV"), phiv, v12.M()); - if (v12.M() < slope * phiv + intercept) { // photon conversion is found. - stored_secondary_electronIds.emplace_back(pos.globalIndex()); - if (dist01(engine) < downscaling_secondary_electron) { - fillTrackTable(collision, pos, static_cast(o2::aod::pwgem::dilepton::PID_Label::kElectron), static_cast(o2::aod::pwgem::dilepton::Track_Type::kSecondary)); - } - } - } // end of pairing loop - - for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(positrons_per_coll, electrons_per_coll))) { // electron is probe, positron is tag. - if (!IsSelectedTag(pos) || !IsElectronTag(pos)) { // require tight global track selection - continue; - } - - if (!IsSelected(ele) || !IsElectron(ele)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - float phiv = getPhivPair(pos.px(), pos.py(), pos.pz(), ele.px(), ele.py(), ele.pz(), pos.sign(), ele.sign(), d_bz); - registry.fill(HIST("hMvsPhiV"), phiv, v12.M()); - if (v12.M() < slope * phiv + intercept) { // photon conversion is found. - stored_secondary_electronIds.emplace_back(ele.globalIndex()); - if (dist01(engine) < downscaling_secondary_electron) { - fillTrackTable(collision, ele, static_cast(o2::aod::pwgem::dilepton::PID_Label::kElectron), static_cast(o2::aod::pwgem::dilepton::Track_Type::kSecondary)); - } - } - } // end of pairing loop - - // apply prefilter to reject photon conversion - for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(positrons_per_coll, electrons_per_coll))) { // electron is tag, positron is probe. - if (!IsSelectedTag(ele) || !IsElectronTag(ele)) { // require tight global track selection - continue; - } - - if (!IsSelected(pos) || !IsElectron(pos)) { - continue; - } - - if (std::find(stored_secondary_electronIds.begin(), stored_secondary_electronIds.end(), pos.globalIndex()) != stored_secondary_electronIds.end()) { - continue; // apply pre-filter to reject secondary electrons - } - - ROOT::Math::PtEtaPhiMVector v1(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - float phiv = getPhivPair(pos.px(), pos.py(), pos.pz(), ele.px(), ele.py(), ele.pz(), pos.sign(), ele.sign(), d_bz); - registry.fill(HIST("hMvsPhiV_primary"), phiv, v12.M()); - if (v12.M() < max_mee_pi0 && dist01(engine) < downscaling_primary_electron) { // e from pi0 dalitz decay is found. - fillTrackTable(collision, pos, static_cast(o2::aod::pwgem::dilepton::PID_Label::kElectron), static_cast(o2::aod::pwgem::dilepton::Track_Type::kPrimary)); - } - } // end of pairing loop - - for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(positrons_per_coll, electrons_per_coll))) { // electron is probe, positron is tag. - if (!IsSelectedTag(pos) || !IsElectronTag(pos)) { // require tight global track selection - continue; - } - - if (!IsSelected(ele) || !IsElectron(ele)) { - continue; - } - - if (std::find(stored_secondary_electronIds.begin(), stored_secondary_electronIds.end(), ele.globalIndex()) != stored_secondary_electronIds.end()) { - continue; // apply pre-filter to reject secondary electrons - } - - ROOT::Math::PtEtaPhiMVector v1(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - float phiv = getPhivPair(pos.px(), pos.py(), pos.pz(), ele.px(), ele.py(), ele.pz(), pos.sign(), ele.sign(), d_bz); - registry.fill(HIST("hMvsPhiV_primary"), phiv, v12.M()); - if (v12.M() < max_mee_pi0 && dist01(engine) < downscaling_primary_electron) { // e from pi0 dalitz decay is found. - fillTrackTable(collision, ele, static_cast(o2::aod::pwgem::dilepton::PID_Label::kElectron), static_cast(o2::aod::pwgem::dilepton::Track_Type::kPrimary)); - } - } // end of pairing loop + // auto tracks_coll = tracks.sliceBy(perCollision_track, collision.globalIndex()); + // for (const auto& track : tracks_coll) { + // if (!isSelectedTrack(collision, track)) { + // continue; + // } + // registry.fill(HIST("PrimaryTrack/hTPCdEdx_P"), track.p(), track.tpcSignal()); + // registry.fill(HIST("PrimaryTrack/hTOFbeta_P"), track.p(), track.beta()); + // registry.fill(HIST("PrimaryTrack/hITSClusterSize_P"), track.p(), meanClusterSizeITS<0, 7>(track) * std::cos(std::atan(track.tgl()))); + // registry.fill(HIST("PrimaryTrack/hTPCNsigmaEl_P"), track.p(), track.tpcNSigmaEl()); + // registry.fill(HIST("PrimaryTrack/hTOFNsigmaEl_P"), track.p(), track.tofNSigmaEl()); + // registry.fill(HIST("PrimaryTrack/hTPCNsigmaMu_P"), track.p(), track.tpcNSigmaMu()); + // registry.fill(HIST("PrimaryTrack/hTOFNsigmaMu_P"), track.p(), track.tofNSigmaMu()); + // registry.fill(HIST("PrimaryTrack/hTPCNsigmaPi_P"), track.p(), track.tpcNSigmaPi()); + // registry.fill(HIST("PrimaryTrack/hTOFNsigmaPi_P"), track.p(), track.tofNSigmaPi()); + // registry.fill(HIST("PrimaryTrack/hTPCNsigmaKa_P"), track.p(), track.tpcNSigmaKa()); + // registry.fill(HIST("PrimaryTrack/hTOFNsigmaKa_P"), track.p(), track.tofNSigmaKa()); + // registry.fill(HIST("PrimaryTrack/hTPCNsigmaPr_P"), track.p(), track.tpcNSigmaPr()); + // registry.fill(HIST("PrimaryTrack/hTOFNsigmaPr_P"), track.p(), track.tofNSigmaPr()); + // } // end of track loop } // end of collision loop stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); - stored_secondary_electronIds.clear(); - stored_secondary_electronIds.shrink_to_fit(); } // end of process // please choose only 1 process function. void processDummy(filteredMyCollisions const&) {} - PROCESS_SWITCH(TreeCreatorElectronMLDDA, processPID, "produce ML input for single track level", false); // this is for eID with ITSsa. e/pi/k/p are selected by TOF, and these can be used for ITS-TPC PID. - PROCESS_SWITCH(TreeCreatorElectronMLDDA, processPrimary, "produce ML input for single track level", false); // this is for selecting electrons from primary or secondary. + PROCESS_SWITCH(TreeCreatorElectronMLDDA, processPID, "produce ML input for single track level", false); // this is for eID with ITSsa. e/pi/k/p are selected by TOF, and these can be used for ITS-TPC PID. PROCESS_SWITCH(TreeCreatorElectronMLDDA, processDummy, "process dummy", true); }; @@ -1068,9 +825,9 @@ struct MLTrackQC { }, }; - void process(aod::EMPrimaryTracks const& tracks) + void processQC(aod::EMPrimaryTracks const& tracks) { - for (auto& track : tracks) { + for (const auto& track : tracks) { registry.fill(HIST("hTPCdEdx_P_All"), track.p(), track.tpcSignal()); registry.fill(HIST("hTOFbeta_P_All"), track.p(), track.beta()); registry.fill(HIST("hITSClusterSize_P_All"), track.p(), track.meanClusterSizeITS() * std::cos(std::atan(track.tgl()))); @@ -1101,6 +858,10 @@ struct MLTrackQC { } } // end of track loop } + PROCESS_SWITCH(MLTrackQC, processQC, "process QC for single track level", false); + + void processDummy(aod::EMPrimaryTracks const&) {} + PROCESS_SWITCH(MLTrackQC, processDummy, "process dummy", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGEM/Dilepton/Tasks/CMakeLists.txt b/PWGEM/Dilepton/Tasks/CMakeLists.txt index a510f2ed684..ad7efb3c065 100644 --- a/PWGEM/Dilepton/Tasks/CMakeLists.txt +++ b/PWGEM/Dilepton/Tasks/CMakeLists.txt @@ -9,23 +9,135 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +add_subdirectory(Converters) o2physics_add_dpl_workflow(efficiency-ee SOURCES emEfficiencyEE.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGDQCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2Physics::PWGDQCore COMPONENT_NAME Analysis) -o2physics_add_executable(lmee-lf-cocktail +o2physics_add_dpl_workflow(lmee-lf-cocktail SOURCES lmeeLFCocktail.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::SimulationDataFormat O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(lmee-hf-cocktail + SOURCES lmeeHFCocktail.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(mc-templates SOURCES MCtemplates.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGDQCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2Physics::PWGDQCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(smearing SOURCES smearing.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGDQCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(create-resolution-map + SOURCES createResolutionMap.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::GlobalTracking + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(table-reader-barrel + SOURCES tableReaderBarrel.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2Physics::PWGDQCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(bc-counter + SOURCES bcCounter.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(event-qc + SOURCES eventQC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(single-electron-qc + SOURCES singleElectronQC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(single-electron-qc-mc + SOURCES singleElectronQCMC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(vp-pair-qc + SOURCES vpPairQC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(vp-pair-qc-mc + SOURCES vpPairQCMC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(single-muon-qc + SOURCES singleMuonQC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMDileptonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(single-muon-qc-mc + SOURCES singleMuonQCMC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMDileptonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(dielectron + SOURCES dielectron.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(dielectron-mc + SOURCES dielectronMC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(dimuon + SOURCES dimuon.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMDileptonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(dimuon-mc + SOURCES dimuonMC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMDileptonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(photon-hbt-pcmpcm + SOURCES PhotonHBTPCMPCM.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(photon-hbt-eeee + SOURCES PhotonHBTEEEE.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(photon-hbt-pcmee + SOURCES PhotonHBTPCMEE.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(prefilter-dielectron + SOURCES prefilterDielectron.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(associate-mccollision-to-collision + SOURCES associateMCcollision.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(study-mc-truth + SOURCES studyMCTruth.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(matching-mft + SOURCES matchingMFT.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::GlobalTracking + COMPONENT_NAME Analysis) + diff --git a/PWGEM/Dilepton/Tasks/Converters/CMakeLists.txt b/PWGEM/Dilepton/Tasks/Converters/CMakeLists.txt new file mode 100644 index 00000000000..503c3aee2ff --- /dev/null +++ b/PWGEM/Dilepton/Tasks/Converters/CMakeLists.txt @@ -0,0 +1,22 @@ +# 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(event-converter2 + SOURCES eventConverter2.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(electron-converter2 + SOURCES electronConverter2.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + diff --git a/PWGEM/Dilepton/Tasks/Converters/electronConverter2.cxx b/PWGEM/Dilepton/Tasks/Converters/electronConverter2.cxx new file mode 100644 index 00000000000..785272dcf3a --- /dev/null +++ b/PWGEM/Dilepton/Tasks/Converters/electronConverter2.cxx @@ -0,0 +1,78 @@ +// 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. +// +// ======================== +// +// This code runs loop over ULS ee pars for virtual photon QC. +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct electronConverter2 { + Produces track_002; + + void process(aod::EMPrimaryElectrons_001 const& tracks) + { + for (auto& track : tracks) { + track_002(track.collisionId(), + track.trackId(), + track.sign(), + track.pt(), + track.eta(), + track.phi(), + track.dcaXY(), + track.dcaZ(), + track.tpcNClsFindable(), + track.tpcNClsFindableMinusFound(), + track.tpcNClsFindableMinusCrossedRows(), + track.tpcNClsShared(), + track.tpcChi2NCl(), + track.tpcInnerParam(), + track.tpcSignal(), + track.tpcNSigmaEl(), + track.tpcNSigmaMu(), + track.tpcNSigmaPi(), + track.tpcNSigmaKa(), + track.tpcNSigmaPr(), + track.beta(), + track.tofNSigmaEl(), + track.tofNSigmaMu(), + track.tofNSigmaPi(), + track.tofNSigmaKa(), + track.tofNSigmaPr(), + track.itsClusterSizes(), 0, 0, 0, 0, 0, + track.itsChi2NCl(), + track.tofChi2(), + track.detectorMap(), + track.x(), + track.alpha(), + track.y(), + track.z(), + track.snp(), + track.tgl(), + track.isAssociatedToMPC()); + } // end of track loop + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"electron-converter2"})}; +} diff --git a/PWGEM/Dilepton/Tasks/Converters/eventConverter2.cxx b/PWGEM/Dilepton/Tasks/Converters/eventConverter2.cxx new file mode 100644 index 00000000000..568cb741d08 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/Converters/eventConverter2.cxx @@ -0,0 +1,55 @@ +// 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. +// +// ======================== +// +// This code runs loop over ULS ee pars for virtual photon QC. +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct eventConverter2 { + Produces event_002; + + void process(aod::EMEvents_001 const& collisions) + { + for (auto& collision : collisions) { + event_002( + collision.globalIndex(), + collision.runNumber(), + collision.globalBC(), + collision.alias_raw(), + collision.selection_raw(), + 0, + collision.timestamp(), + collision.posX(), + collision.posY(), + collision.posZ(), + collision.numContrib(), + collision.trackOccupancyInTimeRange(), + collision.ft0cOccupancyInTimeRange()); + } // end of collision loop + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"event-converter2"})}; +} diff --git a/PWGEM/Dilepton/Tasks/MCtemplates.cxx b/PWGEM/Dilepton/Tasks/MCtemplates.cxx index 893f7c84f6e..3288bd2745e 100644 --- a/PWGEM/Dilepton/Tasks/MCtemplates.cxx +++ b/PWGEM/Dilepton/Tasks/MCtemplates.cxx @@ -189,6 +189,7 @@ struct AnalysisTrackSelection { Configurable fConfigMCSignals{"cfgTrackMCSignals", "", "Comma separated list of MC signals"}; Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigMCTruthGen{"cfgMCTruthGen", false, "If true, fill MCTruthGen histograms"}; HistogramManager* fHistMan; std::vector fTrackCuts; @@ -240,8 +241,23 @@ struct AnalysisTrackSelection { } if (fConfigQA) { + if (fConfigMCTruthGen) { + // Add histogram classes for each MC signal at generated level + // std::vector mcnamesgen; + for (int isig = 0; isig < sigNamesArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(sigNamesArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() == 1) { // NOTE: only 1 prong signals + TString nameStr2 = Form("MCTruthGenTrack_%s", sig->GetName()); + // mcnamesgen.push_back(nameStr2); + histClasses += Form("%s;", nameStr2.Data()); // TODO: Add these names to a std::vector to avoid using Form in the process function + } + } + } + } + VarManager::SetDefaultVarNames(); - fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan = new HistogramManager("SingleElectronQA", "aa", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(kTRUE); fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); DefineHistograms(fHistMan, histClasses.Data(), fConfigAddTrackHistogram); // define all histograms @@ -317,8 +333,36 @@ struct AnalysisTrackSelection { fHistMan->FillHistClass(fHistNamesMCMatched[j][i].Data(), VarManager::fgValues); } } // end loop over cuts - } // end loop over MC signals - } // end loop over tracks + } // end loop over MC signals + } // end loop over tracks + } // end runTrackSelection + + template + void runMCGenTrack(TTracksMC const& groupedMCTracks) + { + for (auto& mctrack : groupedMCTracks) { + if (abs(mctrack.pdgCode()) != 11) + continue; + VarManager::FillTrackMC(groupedMCTracks, mctrack); + // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. + // NOTE: However, the working model is that the decisions on MC signals are precomputed during skimming and are stored in the mcReducedFlags member. + // TODO: Use the mcReducedFlags to select signals + for (auto& sig : fMCSignals) { + if (sig.GetNProngs() != 1) { // NOTE: 1-prong signals required + continue; + } + bool checked = false; + if constexpr (soa::is_soa_filtered_v) { + auto mctrack_raw = groupedMCTracks.rawIteratorAt(mctrack.globalIndex()); + checked = sig.CheckSignal(true, mctrack_raw); + } else { + checked = sig.CheckSignal(true, mctrack); + } + if (checked && fConfigQA) { + fHistMan->FillHistClass(Form("MCTruthGenTrack_%s", sig.GetName()), VarManager::fgValues); + } + } + } } template @@ -329,6 +373,8 @@ struct AnalysisTrackSelection { VarManager::FillEvent(event); runTrackSelection(tracks, tracksMC, true, writeTable); + if (fConfigMCTruthGen) + runMCGenTrack(tracksMC); } void processSkimmed(soa::Filtered::iterator const& event, MyBarrelTracks const& tracks, ReducedMCTracks const& tracksMC) @@ -368,6 +414,7 @@ struct AnalysisSameEventPairing { Configurable fConfigMCRecSignals{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; Configurable fConfigMCGenSignals{"cfgBarrelMCGenSignals", "", "Comma separated list of MC signals (generated)"}; Configurable fConfigAddSEPHistogram{"cfgAddSEPHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigRunMCGenPair{"cfgRunMCGenPair", false, "Do pairing of true MC particles"}; Configurable fPropToPCA{"cfgPropToPCA", false, "Propagate tracks to secondary vertex"}; Configurable fConfigDoSecVtxProp{"cfgDoSecVtxProp", false, "Propagate tracks to secondary vertex"}; // TODO: here we specify signals, however signal decisions are precomputed and stored in mcReducedFlags @@ -383,7 +430,7 @@ struct AnalysisSameEventPairing { void init(o2::framework::InitContext& context) { - bool enableBarrelHistos = context.mOptions.get("processDecayToEESkimmed") || context.mOptions.get("processDecayToEEVertexingSkimmed") || context.mOptions.get("processDecayToEEAOD"); + bool enableBarrelHistos = context.mOptions.get("processDecayToEESkimmed") || context.mOptions.get("processDecayToEESkimmedWithCov") || context.mOptions.get("processDecayToEEAOD"); VarManager::SetDefaultVarNames(); fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); @@ -443,10 +490,7 @@ struct AnalysisSameEventPairing { for (int isig = 0; isig < objGenSigArray->GetEntries(); isig++) { MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objGenSigArray->At(isig)->GetName()); if (sig) { - if (sig->GetNProngs() == 1) { // NOTE: 1-prong signals required - fGenMCSignals.emplace_back(*sig); - histNames += Form("MCTruthGen_%s;", sig->GetName()); // TODO: Add these names to a std::vector to avoid using Form in the process function - } else if (sig->GetNProngs() == 2) { // NOTE: 2-prong signals required + if (sig->GetNProngs() == 2) { // NOTE: 2-prong signals required fGenMCSignals.emplace_back(*sig); histNames += Form("MCTruthGenPair_%s;", sig->GetName()); } @@ -457,6 +501,7 @@ struct AnalysisSameEventPairing { VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); + VarManager::SetMagneticField(5.0f); VarManager::SetupTwoProngDCAFitter(5.0f, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, true); // TODO: get these parameters from Configurables VarManager::SetupTwoProngFwdDCAFitter(5.0f, true, 200.0f, 1.0e-3f, 0.9f, true); } @@ -535,33 +580,8 @@ struct AnalysisSameEventPairing { } // end runPairing template - void runMCGen(TTracksMC const& groupedMCTracks) + void runMCGenPair(TTracksMC const& groupedMCTracks) { - // loop over mc stack and fill histograms for pure MC truth signals - // group all the MC tracks which belong to the MC event corresponding to the current reconstructed event - // auto groupedMCTracks = tracksMC.sliceBy(aod::reducedtrackMC::reducedMCeventId, event.reducedMCevent().globalIndex()); - for (auto& mctrack : groupedMCTracks) { - VarManager::FillTrack(mctrack); - // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. - // NOTE: However, the working model is that the decisions on MC signals are precomputed during skimming and are stored in the mcReducedFlags member. - // TODO: Use the mcReducedFlags to select signals - for (auto& sig : fGenMCSignals) { - if (sig.GetNProngs() != 1) { // NOTE: 1-prong signals required - continue; - } - bool checked = false; - if constexpr (soa::is_soa_filtered_v) { - auto mctrack_raw = groupedMCTracks.rawIteratorAt(mctrack.globalIndex()); - checked = sig.CheckSignal(true, mctrack_raw); - } else { - checked = sig.CheckSignal(true, mctrack); - } - if (checked) { - fHistMan->FillHistClass(Form("MCTruthGen_%s", sig.GetName()), VarManager::fgValues); - } - } - } - // loop over mc stack and fill histograms for pure MC truth signals for (auto& sig : fGenMCSignals) { if (sig.GetNProngs() != 2) { // NOTE: 2-prong signals required @@ -584,7 +604,7 @@ struct AnalysisSameEventPairing { checked = sig.CheckSignal(true, t1, t2); } if (checked) { - VarManager::FillPairMC(t1, t2); + VarManager::FillPairMC(t1, t2); fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig.GetName()), VarManager::fgValues); } } @@ -608,12 +628,13 @@ struct AnalysisSameEventPairing { runPairing(tracks, tracks); auto groupedMCTracks = tracksMC.sliceBy(perReducedMcEvent, event.reducedMCevent().globalIndex()); groupedMCTracks.bindInternalIndicesTo(&tracksMC); - runMCGen(groupedMCTracks); + if (fConfigRunMCGenPair) + runMCGenPair(groupedMCTracks); } - void processDecayToEEVertexingSkimmed(soa::Filtered::iterator const& event, - soa::Filtered const& tracks, - ReducedMCEvents const&, ReducedMCTracks const& tracksMC) + void processDecayToEESkimmedWithCov(soa::Filtered::iterator const& event, + soa::Filtered const& tracks, + ReducedMCEvents const&, ReducedMCTracks const& tracksMC) { // Reset the fValues array VarManager::ResetValues(0, VarManager::kNVars); @@ -623,7 +644,8 @@ struct AnalysisSameEventPairing { runPairing(tracks, tracks); auto groupedMCTracks = tracksMC.sliceBy(perReducedMcEvent, event.reducedMCevent().globalIndex()); groupedMCTracks.bindInternalIndicesTo(&tracksMC); - runMCGen(groupedMCTracks); + if (fConfigRunMCGenPair) + runMCGenPair(groupedMCTracks); } void processDecayToEEAOD(soa::Filtered::iterator const& event, @@ -638,7 +660,8 @@ struct AnalysisSameEventPairing { runPairing(tracks, tracks); auto groupedMCTracks = tracksMC.sliceBy(perMcCollision, event.mcCollision().globalIndex()); groupedMCTracks.bindInternalIndicesTo(&tracksMC); - runMCGen(groupedMCTracks); + if (fConfigRunMCGenPair) + runMCGenPair(groupedMCTracks); } void processDummy(MyEvents&) @@ -651,7 +674,7 @@ struct AnalysisSameEventPairing { } PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToEESkimmed, "Run barrel barrel pairing on DQ skimmed tracks", false); - PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToEEVertexingSkimmed, "Run barrel barrel pairing on DQ skimmed tracks including vertexing", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToEESkimmedWithCov, "Run barrel barrel pairing on DQ skimmed covariant tracks including vertexing", false); PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToEEAOD, "Run barrel barrel pairing on non skimmed tracks", false); PROCESS_SWITCH(AnalysisSameEventPairing, processDummy, "Dummy process function", false); PROCESS_SWITCH(AnalysisSameEventPairing, processDummyAOD, "Dummy process function", false); @@ -705,11 +728,8 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, Configurab if (classStr.Contains("MCTruthGenPair")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_pair"); } - if (classStr.Contains("MCTruthGen")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth"); - histMan->AddHistogram(objArray->At(iclass)->GetName(), "Pt", "MC generator p_{T} distribution", false, 200, 0.0, 20.0, VarManager::kMCPt); - histMan->AddHistogram(objArray->At(iclass)->GetName(), "Eta", "MC generator #eta distribution", false, 500, -5.0, 5.0, VarManager::kMCEta); - histMan->AddHistogram(objArray->At(iclass)->GetName(), "Phi", "MC generator #varphi distribution", false, 500, -6.3, 6.3, VarManager::kMCPhi); + if (classStr.Contains("MCTruthGenTrack")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_track"); } } // end loop over histogram classes } diff --git a/PWGEM/Dilepton/Tasks/PhotonHBTEEEE.cxx b/PWGEM/Dilepton/Tasks/PhotonHBTEEEE.cxx new file mode 100644 index 00000000000..b26a40af6fc --- /dev/null +++ b/PWGEM/Dilepton/Tasks/PhotonHBTEEEE.cxx @@ -0,0 +1,44 @@ +// 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. +// +// ======================== +// +// This code loops over v0 photons and makes pairs for photon HBT analysis. +// Please write to: daiki.sekihata@cern.ch + +#include +#include + +#include "TString.h" +#include "Math/Vector4D.h" +#include "Math/Vector3D.h" +#include "Math/LorentzRotation.h" +#include "Math/GenVector/Boost.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + +#include "PWGEM/Dilepton/Core/PhotonHBT.h" + +using namespace o2; +using namespace o2::aod; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"photon-hbt-eeee"})}; +} diff --git a/PWGEM/Dilepton/Tasks/PhotonHBTPCMEE.cxx b/PWGEM/Dilepton/Tasks/PhotonHBTPCMEE.cxx new file mode 100644 index 00000000000..3e792f9d27a --- /dev/null +++ b/PWGEM/Dilepton/Tasks/PhotonHBTPCMEE.cxx @@ -0,0 +1,44 @@ +// 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. +// +// ======================== +// +// This code loops over v0 photons and makes pairs for photon HBT analysis. +// Please write to: daiki.sekihata@cern.ch + +#include +#include + +#include "TString.h" +#include "Math/Vector4D.h" +#include "Math/Vector3D.h" +#include "Math/LorentzRotation.h" +#include "Math/GenVector/Boost.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + +#include "PWGEM/Dilepton/Core/PhotonHBT.h" + +using namespace o2; +using namespace o2::aod; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"photon-hbt-pcmee"})}; +} diff --git a/PWGEM/Dilepton/Tasks/PhotonHBTPCMPCM.cxx b/PWGEM/Dilepton/Tasks/PhotonHBTPCMPCM.cxx new file mode 100644 index 00000000000..ddcbe423eae --- /dev/null +++ b/PWGEM/Dilepton/Tasks/PhotonHBTPCMPCM.cxx @@ -0,0 +1,44 @@ +// 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. +// +// ======================== +// +// This code loops over v0 photons and makes pairs for photon HBT analysis. +// Please write to: daiki.sekihata@cern.ch + +#include +#include + +#include "TString.h" +#include "Math/Vector4D.h" +#include "Math/Vector3D.h" +#include "Math/LorentzRotation.h" +#include "Math/GenVector/Boost.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + +#include "PWGEM/Dilepton/Core/PhotonHBT.h" + +using namespace o2; +using namespace o2::aod; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"photon-hbt-pcmpcm"})}; +} diff --git a/PWGEM/Dilepton/Tasks/associateMCcollision.cxx b/PWGEM/Dilepton/Tasks/associateMCcollision.cxx new file mode 100644 index 00000000000..eb0e7d3bf5c --- /dev/null +++ b/PWGEM/Dilepton/Tasks/associateMCcollision.cxx @@ -0,0 +1,93 @@ +// 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. +// +// ======================== +// +// This code produces a table with an index between mc collision and rec. collision. +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct associateMCcollision { + Produces mpemeventIds; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + void init(InitContext&) + { + if (doprocessNcontrib && doprocessNcontrib_Derived) { + LOGF(fatal, "Please select only 1 process function."); + } + addhistograms(); + } + + ~associateMCcollision() {} + + void addhistograms() + { + fRegistry.add("hReccollsPerMCcoll", "Rec. colls per MC coll;Rec. colls per MC coll;Number of MC collisions", kTH1D, {{21, -0.5, 20.5}}, false); + } + + template + void runMC(TMCCollisions const& mcCollisions, TCollisions const& collisions, TPreslice const& perMCCollision) + { + + for (auto& mcCollision : mcCollisions) { + auto rec_colls_per_mccoll = collisions.sliceBy(perMCCollision, mcCollision.globalIndex()); + fRegistry.fill(HIST("hReccollsPerMCcoll"), rec_colls_per_mccoll.size()); + uint32_t maxNumContrib = 0; + int rec_col_globalIndex = -999; + for (auto& rec_col : rec_colls_per_mccoll) { + if (rec_col.numContrib() > maxNumContrib) { + rec_col_globalIndex = rec_col.globalIndex(); + maxNumContrib = rec_col.numContrib(); // assign mc collision to collision where the number of contibutors is the lagest. LF/MM recommendation + } + } + // LOGF(info, "rec_col_globalIndex = %d", rec_col_globalIndex); + mpemeventIds(rec_col_globalIndex); + } // end of mc collision + + } // end of runMC + + using MyCollisions = soa::Join; + using MyCollision = MyCollisions::iterator; + PresliceUnsorted recColperMcCollision = aod::mccollisionlabel::mcCollisionId; + + using MyEMCollisions = soa::Join; + using MyEMCollision = MyEMCollisions::iterator; + PresliceUnsorted recColperMcCollision_derived = aod::emmceventlabel::emmceventId; + + void processNcontrib_Derived(aod::EMMCEvents const& mcCollisions, MyEMCollisions const& collisions) + { + runMC(mcCollisions, collisions, recColperMcCollision_derived); + } + PROCESS_SWITCH(associateMCcollision, processNcontrib_Derived, "produce most probable emeventId based on Ncontrib to PV for derived AOD", true); + + void processNcontrib(aod::McCollisions const& mcCollisions, MyCollisions const& collisions) + { + runMC(mcCollisions, collisions, recColperMcCollision); + } + PROCESS_SWITCH(associateMCcollision, processNcontrib, "produce most probable emeventId based on Ncontrib to PV for original AOD", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"associate-mccollision-to-collision"})}; +} diff --git a/PWGEM/Dilepton/Tasks/bcCounter.cxx b/PWGEM/Dilepton/Tasks/bcCounter.cxx new file mode 100644 index 00000000000..1b16c88e89b --- /dev/null +++ b/PWGEM/Dilepton/Tasks/bcCounter.cxx @@ -0,0 +1,142 @@ +// 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. +// +// ======================== +// +// This code is for bc counter. +// Please write to: daiki.sekihata@cern.ch + +#include +#include +#include +#include +#include + +#include "TString.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Common/Core/RecoDecay.h" +#include "MathUtils/Utils.h" +#include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "CCDB/BasicCCDBManager.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +using MyBCs = soa::Join; +using MyCollisions = soa::Join; +using MyMCCollisions = soa::Join; + +struct bcCounter { + // Configurables + // Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + // Service ccdb; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + void init(InitContext&) + { + // ccdb->setURL(ccdburl); + // ccdb->setCaching(true); + // ccdb->setLocalObjectValidityChecking(); + // ccdb->setFatalWhenNull(false); + addhistograms(); + } + + ~bcCounter() {} + + void addhistograms() + { + // event info + + const int nbin_ev = 3; + auto hBCCounter = fRegistry.add("Data/hBCCounter", "bc counter;;Number of bcs", kTH1D, {{nbin_ev, 0.5, nbin_ev + 0.5}}, false); + hBCCounter->GetXaxis()->SetBinLabel(1, "all"); + hBCCounter->GetXaxis()->SetBinLabel(2, "FT0AND"); + hBCCounter->GetXaxis()->SetBinLabel(3, "FT0AND && vertex found"); + fRegistry.add("Data/hNcollsPerBC", "Number of rec. collisions per BC", kTH1D, {{21, -0.5, 20.5}}, false); + + fRegistry.addClone("Data/", "MC/"); + } + + SliceCache cache; + PresliceUnsorted preslice_collisions_per_bc = o2::aod::evsel::foundBCId; + // std::unordered_map map_ncolls_per_bc; + + void processData(MyBCs const& bcs, MyCollisions const& collisions) + { + // first count the number of collisions per bc + for (const auto& bc : bcs) { + auto collisions_per_bc = collisions.sliceBy(preslice_collisions_per_bc, bc.globalIndex()); + // map_ncolls_per_bc[bc.globalIndex()] = collisions_per_bc.size(); + fRegistry.fill(HIST("Data/hNcollsPerBC"), collisions_per_bc.size()); + // LOGF(info, "bc-loop | bc.globalIndex() = %d , collisions_per_bc.size() = %d", bc.globalIndex(), collisions_per_bc.size()); + + fRegistry.fill(HIST("Data/hBCCounter"), 1.0); + if (bc.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + fRegistry.fill(HIST("Data/hBCCounter"), 2.0); + + if (collisions_per_bc.size() > 0) { // at least 1 reconstructed vertex exists. + fRegistry.fill(HIST("Data/hBCCounter"), 3.0); + } + } + } // end of bc loop + + // for (const auto& collision : collisions) { + // auto bc = collision.template foundBC_as(); + // // LOGF(info, "collision-loop | bc.globalIndex() = %d, ncolls_per_bc = %d", bc.globalIndex(), map_ncolls_per_bc[bc.globalIndex()]); + // } // end of collision loop + + // map_ncolls_per_bc.clear(); + } + PROCESS_SWITCH(bcCounter, processData, "process Data", true); + + // void processMC(MyBCs const& bcs, MyMCCollisions const& collisions, aod::McCollisions const& mccollisions) + // { + + // // first count the number of collisions per bc + // for (const auto& bc : bcs) { + // auto collisions_per_bc = collisions.sliceBy(preslice_collisions_per_bc, bc.globalIndex()); + // // map_ncolls_per_bc[bc.globalIndex()] = collisions_per_bc.size(); + // fRegistry.fill(HIST("hNcollsPerBC"), collisions_per_bc.size()); + // // LOGF(info, "bc-loop | bc.globalIndex() = %d , collisions_per_bc.size() = %d", bc.globalIndex(), collisions_per_bc.size()); + + // fRegistry.fill(HIST("hBCCounter"), 1.0); + // if (bc.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + // fRegistry.fill(HIST("hBCCounter"), 2.0); + + // if (collisions_per_bc.size() > 0) { // at least 1 reconstructed vertex exists. + // fRegistry.fill(HIST("hBCCounter"), 3.0); + // } + // } + // } // end of bc loop + // } + // PROCESS_SWITCH(bcCounter, processMC, "process MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"bc-counter"})}; +} diff --git a/PWGEM/Dilepton/Tasks/createResolutionMap.cxx b/PWGEM/Dilepton/Tasks/createResolutionMap.cxx new file mode 100644 index 00000000000..8070c41ac61 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/createResolutionMap.cxx @@ -0,0 +1,782 @@ +// 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. +// +// +// Analysis task to produce resolution mapfor electrons/muons in dilepton analysis +// Please write to: daiki.sekihata@cern.ch + +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/ASoA.h" +#include "Framework/DataTypes.h" +#include "Framework/HistogramRegistry.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/Core/trackUtilities.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "TGeoGlobalMagField.h" +#include "Field/MagneticField.h" + +#include "DetectorsBase/Propagator.h" +#include "GlobalTracking/MatchGlobalFwd.h" +#include "MCHTracking/TrackExtrap.h" +#include "MCHTracking/TrackParam.h" +#include "ReconstructionDataFormats/TrackFwd.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod; +using namespace o2::soa; +using namespace o2::aod::pwgem::dilepton::utils::mcutil; + +struct CreateResolutionMap { + // Index used to set different options for Muon propagation + enum class MuonExtrapolation : int { + kToVertex = 0, // propagtion to vertex by default + kToDCA = 1, + kToRabs = 2, + }; + using SMatrix55 = ROOT::Math::SMatrix>; + using SMatrix5 = ROOT::Math::SVector; + + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable mVtxPath{"mVtxPath", "GLO/Calib/MeanVertex", "Path of the mean vertex file"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + + Configurable cfgEventGeneratorType{"cfgEventGeneratorType", -1, "if positive, select event generator type. i.e. gap or signal"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfg_require_true_mc_collision_association{"cfg_require_true_mc_collision_association", true, "flag to require true mc collision association"}; + Configurable cfg_reject_fake_match_its_tpc{"cfg_reject_fake_match_its_tpc", false, "flag to reject fake match between ITS-TPC"}; + // Configurable cfg_reject_fake_match_its_tpc_tof{"cfg_reject_fake_match_its_tpc_tof", false, "flag to reject fake match between ITS-TPC-TOF"}; + Configurable cfg_reject_fake_match_mft_mch{"cfg_reject_fake_match_mft_mch", false, "flag to reject fake match between MFT-MCH"}; + + ConfigurableAxis ConfPtGenBins{"ConfPtGenBins", {VARIABLE_WIDTH, 0.00, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.30, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.40, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.50, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.60, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.70, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.80, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.90, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.10, 2.20, 2.30, 2.40, 2.50, 2.60, 2.70, 2.80, 2.90, 3.00, 3.10, 3.20, 3.30, 3.40, 3.50, 3.60, 3.70, 3.80, 3.90, 4.00, 4.10, 4.20, 4.30, 4.40, 4.50, 4.60, 4.70, 4.80, 4.90, 5.00, 5.50, 6.00, 6.50, 7.00, 7.50, 8.00, 8.50, 9.00, 9.50, 10.00, 11.00, 12.00, 13.00, 14.00, 15.00, 16.00, 17.00, 18.00, 19.00, 20.00}, "gen. pT bins for output histograms"}; + ConfigurableAxis ConfCentBins{"ConfCentBins", {VARIABLE_WIDTH, 0, 10, 30, 50, 110}, "centrality (%) bins for output histograms"}; + + ConfigurableAxis ConfEtaCBGenBins{"ConfEtaCBGenBins", {30, -1.5, +1.5}, "gen. eta bins at midrapidity for output histograms"}; + ConfigurableAxis ConfEtaFWDGenBins{"ConfEtaFWDGenBins", {40, -5.5, -1.5}, "gen. eta bins at forward rapidity for output histograms"}; + ConfigurableAxis ConfPhiGenBins{"ConfPhiGenBins", {72, 0, 2.f * M_PI}, "gen. eta bins at forward rapidity for output histograms"}; + + ConfigurableAxis ConfRelDeltaPtBins{"ConfRelDeltaPtBins", {200, -1.f, +1.f}, "rel. dpt for output histograms"}; + ConfigurableAxis ConfDeltaEtaBins{"ConfDeltaEtaBins", {100, -0.1f, +0.1f}, "deta bins for output histograms"}; + ConfigurableAxis ConfDeltaPhiBins{"ConfDeltaPhiBins", {100, -0.1f, +0.1f}, "dphi bins for output histograms"}; + + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", false, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. track occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. track occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + // Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "require no collision in time range standard"}; + // Configurable cfgRequireNoCollInTimeRangeStrict{"cfgRequireNoCollInTimeRangeStrict", false, "require no collision in time range strict"}; + // Configurable cfgRequirekNoCollInRofStandard{"cfgRequirekNoCollInRofStandard", false, "require no other collisions in this Readout Frame with per-collision multiplicity above threshold"}; + // Configurable cfgRequirekNoCollInRofStrict{"cfgRequirekNoCollInRofStrict", false, "require no other collisions in this Readout Frame"}; + // Configurable cfgRequirekNoHighMultCollInPrevRof{"cfgRequirekNoHighMultCollInPrevRof", false, "require no HM collision in previous ITS ROF"}; + // Configurable cfgRequireGoodITSLayer3{"cfgRequireGoodITSLayer3", false, "number of inactive chips on ITS layer 3 are below threshold "}; + // Configurable cfgRequireGoodITSLayer0123{"cfgRequireGoodITSLayer0123", false, "number of inactive chips on ITS layers 0-3 are below threshold "}; + // Configurable cfgRequireGoodITSLayersAll{"cfgRequireGoodITSLayersAll", false, "number of inactive chips on all ITS layers are below threshold "}; + } eventcuts; + + struct : ConfigurableGroup { + std::string prefix = "electroncut_group"; + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.01, "min pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -1.5, "min eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", +1.5, "max eta for single track"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 90, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncluster_itsib{"cfg_min_ncluster_itsib", 1, "min ncluster itsib"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 0, "min ncrossed rows"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_min_tpc_cr_findable_ratio{"cfg_min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 0.2, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 0.2, "max dca Z for single track in cm"}; + Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", false, "flag to require ITS ib 1st hit"}; + } electroncuts; + + struct : ConfigurableGroup { + std::string prefix = "muoncut_group"; + Configurable cfg_track_type{"cfg_track_type", 3, "muon track type [0: MFT-MCH-MID, 3: MCH-MID]"}; + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.01, "min pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -5.5, "min eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", -1.5, "max eta for single track"}; + Configurable cfg_min_ncluster_mft{"cfg_min_ncluster_mft", 5, "min ncluster MFT"}; + Configurable cfg_min_ncluster_mch{"cfg_min_ncluster_mch", 5, "min ncluster MCH"}; + Configurable cfg_max_chi2{"cfg_max_chi2", 1e+10, "max chi2/NclsTPC"}; + Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 1e+10, "max chi2 for MFT-MCH matching"}; + Configurable cfg_max_matching_chi2_mchmid{"cfg_max_matching_chi2_mchmid", 1e+10, "max chi2 for MCH-MID matching"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1e+10, "max dca XY for single track in cm"}; + Configurable cfg_min_rabs{"cfg_min_rabs", 17.6, "min Radius at the absorber end"}; + Configurable cfg_max_rabs{"cfg_max_rabs", 89.5, "max Radius at the absorber end"}; + } muoncuts; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + o2::globaltracking::MatchGlobalFwd mMatching; + int mRunNumber = 0; + float d_bz; + // o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + o2::dataformats::VertexBase mVtx; + const o2::dataformats::MeanVertexObject* mMeanVtx = nullptr; + o2::base::MatLayerCylSet* lut = nullptr; + + void init(o2::framework::InitContext&) + { + if (doprocessElectronSA && doprocessElectronTTCA) { + LOGF(fatal, "Cannot enable processElectronSA and processElectronTTCA at the same time. Please choose one."); + } + + if (doprocessMuonSA && doprocessMuonTTCA) { + LOGF(fatal, "Cannot enable processMuonSA and processMuonTTCA at the same time. Please choose one."); + } + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + ccdbApi.init(ccdburl); + + mRunNumber = 0; + d_bz = 0; + + const AxisSpec axis_cent{ConfCentBins, "centrality (%)"}; + const AxisSpec axis_pt_gen{ConfPtGenBins, "p_{T,l}^{gen} (GeV/c)"}; + const AxisSpec axis_eta_cb_gen{ConfEtaCBGenBins, "#eta_{l}^{gen}"}; + const AxisSpec axis_eta_fwd_gen{ConfEtaFWDGenBins, "#eta_{l}^{gen}"}; + const AxisSpec axis_phi_gen{ConfPhiGenBins, "#varphi_{l}^{gen} (rad.)"}; + const AxisSpec axis_dpt{ConfRelDeltaPtBins, "(p_{T,l}^{gen} - p_{T,l}^{rec})/p_{T,l}^{gen}"}; + const AxisSpec axis_deta{ConfDeltaEtaBins, "#eta_{l}^{gen} - #eta_{l}^{rec}"}; + const AxisSpec axis_dphi{ConfDeltaPhiBins, "#varphi_{l}^{gen} - #varphi_{l}^{rec} (rad.)"}; + const AxisSpec axis_charge_gen{3, -1.5, +1.5, "true sign"}; + + registry.add("Event/Electron/hImpPar_Centrality", "true imapact parameter vs. estimated centrality;impact parameter (fm);centrality (%)", kTH2F, {{200, 0, 20}, {110, 0, 110}}, true); + registry.add("Event/Muon/hImpPar_Centrality", "true imapact parameter vs. estimated centrality;impact parameter (fm);centrality (%)", kTH2F, {{200, 0, 20}, {110, 0, 110}}, true); + + registry.add("Electron/hPt", "rec. p_{T,l};p_{T,l} (GeV/c)", kTH1F, {{1000, 0, 10}}, false); + registry.add("Electron/hEtaPhi", "rec. #eta vs. #varphi;#varphi_{l} (rad.);#eta_{l}", kTH2F, {{90, 0, 2 * M_PI}, {80, -2, +2}}, false); + registry.add("Electron/Ptgen_RelDeltaPt", "resolution", kTH2F, {{axis_pt_gen}, {axis_dpt}}, true); + registry.add("Electron/Ptgen_DeltaEta", "resolution", kTH2F, {{axis_pt_gen}, {axis_deta}}, true); + registry.add("Electron/Ptgen_DeltaPhi_Pos", "resolution", kTH2F, {{axis_pt_gen}, {axis_dphi}}, true); + registry.add("Electron/Ptgen_DeltaPhi_Neg", "resolution", kTH2F, {{axis_pt_gen}, {axis_dphi}}, true); + registry.addClone("Electron/", "StandaloneMuon/"); + registry.addClone("Electron/", "GlobalMuon/"); + + registry.add("Electron/hs_reso", "8D resolution positive", kTHnSparseF, {axis_cent, axis_pt_gen, axis_eta_cb_gen, axis_phi_gen, axis_charge_gen, axis_dpt, axis_deta, axis_dphi}, true); + registry.add("StandaloneMuon/hs_reso", "8D resolution positive", kTHnSparseF, {axis_cent, axis_pt_gen, axis_eta_fwd_gen, axis_phi_gen, axis_charge_gen, axis_dpt, axis_deta, axis_dphi}, true); + registry.add("GlobalMuon/hs_reso", "8D resolution positive", kTHnSparseF, {axis_cent, axis_pt_gen, axis_eta_fwd_gen, axis_phi_gen, axis_charge_gen, axis_dpt, axis_deta, axis_dphi}, true); + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + // load matLUT for this timestamp + if (!lut) { + LOG(info) << "Loading material look-up table for timestamp: " << bc.timestamp(); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->getForTimeStamp(lutPath, bc.timestamp())); + } else { + LOG(info) << "Material look-up table already in place. Not reloading."; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (std::fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + o2::base::Propagator::initFieldFromGRP(&grpmag); + o2::base::Propagator::Instance()->setMatLUT(lut); + mMeanVtx = ccdb->getForTimeStamp(mVtxPath, bc.timestamp()); + mRunNumber = bc.runNumber(); + + if (!o2::base::GeometryManager::isGeometryLoaded()) { + ccdb->get(geoPath); + } + o2::mch::TrackExtrap::setField(); + return; + } + + auto run3grp_timestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) { + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + } + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + o2::base::Propagator::Instance()->setMatLUT(lut); + mMeanVtx = ccdb->getForTimeStamp(mVtxPath, bc.timestamp()); + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + o2::base::Propagator::Instance()->setMatLUT(lut); + mMeanVtx = ccdb->getForTimeStamp(mVtxPath, bc.timestamp()); + + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = bc.runNumber(); + + // std::map metadata; + // auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, mRunNumber); + // auto ts = soreor.first; + // auto grpmag = ccdbApi.retrieveFromTFileAny(grpmagPath, metadata, ts); + // o2::base::Propagator::initFieldFromGRP(grpmag); + + if (!o2::base::GeometryManager::isGeometryLoaded()) { + ccdb->get(geoPath); + } + o2::mch::TrackExtrap::setField(); + } + + template + bool isSelectedEvent(TCollision const& collision) + { + if (eventcuts.cfgRequireSel8 && !collision.sel8()) { + return false; + } + + if (collision.posZ() < eventcuts.cfgZvtxMin || eventcuts.cfgZvtxMax < collision.posZ()) { + return false; + } + + if (eventcuts.cfgRequireFT0AND && !collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + return false; + } + + if (eventcuts.cfgRequireNoTFB && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + + if (eventcuts.cfgRequireNoITSROFB && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + + if (eventcuts.cfgRequireNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + + if (eventcuts.cfgRequireGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + + if (!(eventcuts.cfgTrackOccupancyMin <= collision.trackOccupancyInTimeRange() && collision.trackOccupancyInTimeRange() < eventcuts.cfgTrackOccupancyMax)) { + return false; + } + + if (!(eventcuts.cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange() && collision.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) { + return false; + } + + // if (eventcuts.cfgRequireNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // return false; + // } + + // if (eventcuts.cfgRequireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + // return false; + // } + + // if (eventcuts.cfgRequirekNoCollInRofStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + // return false; + // } + + // if (eventcuts.cfgRequirekNoCollInRofStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + // return false; + // } + + // if (eventcuts.cfgRequirekNoHighMultCollInPrevRof && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + // return false; + // } + + // if (eventcuts.cfgRequireGoodITSLayer3 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer3)) { + // return false; + // } + + // if (eventcuts.cfgRequireGoodITSLayer0123 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)) { + // return false; + // } + + // if (eventcuts.cfgRequireGoodITSLayersAll && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + // return false; + // } + + return true; + } + + std::pair> itsRequirement_ibany = {1, {0, 1, 2}}; // any hits on 3 ITS ib layers. + std::pair> itsRequirement_ib1st = {1, {0}}; // first hit on ITS ib layers. + + template + bool isSelectedTrack(TCollision const& collision, TTrack const& track) + { + if (!track.hasITS() || !track.hasTPC()) { + return false; + } + + if (track.tpcChi2NCl() > electroncuts.cfg_max_chi2tpc) { + return false; + } + + if (track.itsChi2NCl() > electroncuts.cfg_max_chi2its) { + return false; + } + + if (track.itsNCls() < electroncuts.cfg_min_ncluster_its) { + return false; + } + if (track.itsNClsInnerBarrel() < electroncuts.cfg_min_ncluster_itsib) { + return false; + } + + auto hits = std::count_if(itsRequirement_ibany.second.begin(), itsRequirement_ibany.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); + if (hits < itsRequirement_ibany.first) { + return false; + } + if (electroncuts.cfg_require_itsib_1st) { + auto hit_ib1st = std::count_if(itsRequirement_ib1st.second.begin(), itsRequirement_ib1st.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); + if (hit_ib1st < itsRequirement_ib1st.first) { + return false; + } + } + + if (track.tpcNClsFound() < electroncuts.cfg_min_ncluster_tpc) { + return false; + } + + if (track.tpcNClsCrossedRows() < electroncuts.cfg_min_ncrossedrows) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < electroncuts.cfg_min_tpc_cr_findable_ratio) { + return false; + } + + if (track.tpcFractionSharedCls() > electroncuts.cfg_max_frac_shared_clusters_tpc) { + return false; + } + + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto track_par_cov_recalc = getTrackParCov(track); + track_par_cov_recalc.setPID(o2::track::PID::Electron); + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, track_par_cov_recalc, 2.f, matCorr, &mDcaInfoCov); + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + + // LOGF(info, "collision.globalIndex() = %d, track.collisionId() = %d, track.pt() = %.16f, track_par_cov_recalc.getPt() = %.16f", collision.globalIndex(), track.collisionId(), track.pt(), track_par_cov_recalc.getPt()); + + if (std::fabs(dcaXY) > electroncuts.cfg_max_dcaxy || std::fabs(dcaZ) > electroncuts.cfg_max_dcaz) { + return false; + } + + if (track_par_cov_recalc.getPt() < electroncuts.cfg_min_pt_track || std::fabs(track_par_cov_recalc.getEta()) > electroncuts.cfg_max_eta_track) { + return false; + } + + return true; + } + + template + o2::dataformats::GlobalFwdTrack PropagateMuon(T const& muon, C const& collision, const CreateResolutionMap::MuonExtrapolation endPoint) + { + double chi2 = muon.chi2(); + SMatrix5 tpars(muon.x(), muon.y(), muon.phi(), muon.tgl(), muon.signed1Pt()); + std::vector v1{muon.cXX(), muon.cXY(), muon.cYY(), muon.cPhiX(), muon.cPhiY(), + muon.cPhiPhi(), muon.cTglX(), muon.cTglY(), muon.cTglPhi(), muon.cTglTgl(), + muon.c1PtX(), muon.c1PtY(), muon.c1PtPhi(), muon.c1PtTgl(), muon.c1Pt21Pt2()}; + SMatrix55 tcovs(v1.begin(), v1.end()); + o2::track::TrackParCovFwd fwdtrack{muon.z(), tpars, tcovs, chi2}; + o2::dataformats::GlobalFwdTrack propmuon; + + if (static_cast(muon.trackType()) > 2) { // MCH-MID or MCH standalone + o2::dataformats::GlobalFwdTrack track; + track.setParameters(tpars); + track.setZ(fwdtrack.getZ()); + track.setCovariances(tcovs); + auto mchTrack = mMatching.FwdtoMCH(track); + + if (endPoint == CreateResolutionMap::MuonExtrapolation::kToVertex) { + o2::mch::TrackExtrap::extrapToVertex(mchTrack, collision.posX(), collision.posY(), collision.posZ(), collision.covXX(), collision.covYY()); + } + if (endPoint == CreateResolutionMap::MuonExtrapolation::kToDCA) { + o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchTrack, collision.posZ()); + } + if (endPoint == CreateResolutionMap::MuonExtrapolation::kToRabs) { + o2::mch::TrackExtrap::extrapToZ(mchTrack, -505.); + } + + auto proptrack = mMatching.MCHtoFwd(mchTrack); + propmuon.setParameters(proptrack.getParameters()); + propmuon.setZ(proptrack.getZ()); + propmuon.setCovariances(proptrack.getCovariances()); + } else if (static_cast(muon.trackType()) < 2) { // MFT-MCH-MID + double centerMFT[3] = {0, 0, -61.4}; + o2::field::MagneticField* field = static_cast(TGeoGlobalMagField::Instance()->GetField()); + auto Bz = field->getBz(centerMFT); // Get field at centre of MFT + auto geoMan = o2::base::GeometryManager::meanMaterialBudget(muon.x(), muon.y(), muon.z(), collision.posX(), collision.posY(), collision.posZ()); + auto x2x0 = static_cast(geoMan.meanX2X0); + fwdtrack.propagateToVtxhelixWithMCS(collision.posZ(), {collision.posX(), collision.posY()}, {collision.covXX(), collision.covYY()}, Bz, x2x0); + propmuon.setParameters(fwdtrack.getParameters()); + propmuon.setZ(fwdtrack.getZ()); + propmuon.setCovariances(fwdtrack.getCovariances()); + } + + v1.clear(); + v1.shrink_to_fit(); + + return propmuon; + } + + template + void fillMuon(TCollision const& collision, TMuon const& muon, const float centrality) + { + auto mcparticle = muon.template mcParticle_as(); + if (std::abs(mcparticle.pdgCode()) != 13 || !(mcparticle.isPhysicalPrimary() || mcparticle.producedByGenerator())) { + return; + } + if (cfg_require_true_mc_collision_association && mcparticle.mcCollisionId() != collision.mcCollisionId()) { + return; + } + if (muon.trackType() != static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) && muon.trackType() != static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + return; + } + + o2::dataformats::GlobalFwdTrack propmuonAtPV = PropagateMuon(muon, collision, CreateResolutionMap::MuonExtrapolation::kToVertex); + float pt = propmuonAtPV.getPt(); + float eta = propmuonAtPV.getEta(); + float phi = propmuonAtPV.getPhi(); + + if (pt < muoncuts.cfg_min_pt_track) { + return; + } + + if (eta < muoncuts.cfg_min_eta_track || muoncuts.cfg_max_eta_track < eta) { + return; + } + + o2::math_utils::bringTo02Pi(phi); + if (phi < 0.f || 2.f * M_PI < phi) { + return; + } + + float rAtAbsorberEnd = muon.rAtAbsorberEnd(); + if (muon.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + o2::dataformats::GlobalFwdTrack propmuonAtRabs = PropagateMuon(muon, collision, CreateResolutionMap::MuonExtrapolation::kToRabs); + float xAbs = propmuonAtRabs.getX(); + float yAbs = propmuonAtRabs.getY(); + rAtAbsorberEnd = std::sqrt(xAbs * xAbs + yAbs * yAbs); // Redo propagation only for muon tracks // propagation of MFT tracks alredy done in reconstruction + } + + if (rAtAbsorberEnd < muoncuts.cfg_min_rabs || muoncuts.cfg_max_rabs < rAtAbsorberEnd) { + return; + } + + if (rAtAbsorberEnd < 26.5) { + if (muon.pDca() > 594.f) { + return; + } + } else { + if (muon.pDca() > 324.f) { + return; + } + } + + if (muon.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && muon.chi2MatchMCHMFT() > muoncuts.cfg_max_matching_chi2_mftmch) { + return; + } + + if (cfg_reject_fake_match_mft_mch && muon.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && o2::aod::pwgem::dilepton::utils::mcutil::hasFakeMatchMFTMCH(muon)) { + return; + } + + if (muon.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + registry.fill(HIST("StandaloneMuon/hPt"), pt); + registry.fill(HIST("StandaloneMuon/hEtaPhi"), phi, eta); + registry.fill(HIST("StandaloneMuon/hs_reso"), centrality, mcparticle.pt(), mcparticle.eta(), mcparticle.phi(), -mcparticle.pdgCode() / 13, (mcparticle.pt() - pt) / mcparticle.pt(), mcparticle.eta() - eta, mcparticle.phi() - phi); + registry.fill(HIST("StandaloneMuon/Ptgen_RelDeltaPt"), mcparticle.pt(), (mcparticle.pt() - pt) / mcparticle.pt()); + registry.fill(HIST("StandaloneMuon/Ptgen_DeltaEta"), mcparticle.pt(), mcparticle.eta() - eta); + if (mcparticle.pdgCode() == -13) { // positive muon + registry.fill(HIST("StandaloneMuon/Ptgen_DeltaPhi_Pos"), mcparticle.pt(), mcparticle.phi() - phi); + } else if (mcparticle.pdgCode() == 13) { // negative muon + registry.fill(HIST("StandaloneMuon/Ptgen_DeltaPhi_Neg"), mcparticle.pt(), mcparticle.phi() - phi); + } + } else if (muon.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + registry.fill(HIST("GlobalMuon/hPt"), pt); + registry.fill(HIST("GlobalMuon/hEtaPhi"), phi, eta); + registry.fill(HIST("GlobalMuon/hs_reso"), centrality, mcparticle.pt(), mcparticle.eta(), mcparticle.phi(), -mcparticle.pdgCode() / 13, (mcparticle.pt() - pt) / mcparticle.pt(), mcparticle.eta() - eta, mcparticle.phi() - phi); + registry.fill(HIST("GlobalMuon/Ptgen_RelDeltaPt"), mcparticle.pt(), (mcparticle.pt() - pt) / mcparticle.pt()); + registry.fill(HIST("GlobalMuon/Ptgen_DeltaEta"), mcparticle.pt(), mcparticle.eta() - eta); + if (mcparticle.pdgCode() == -13) { // positive muon + registry.fill(HIST("GlobalMuon/Ptgen_DeltaPhi_Pos"), mcparticle.pt(), mcparticle.phi() - phi); + } else if (mcparticle.pdgCode() == 13) { // negative muon + registry.fill(HIST("GlobalMuon/Ptgen_DeltaPhi_Neg"), mcparticle.pt(), mcparticle.phi() - phi); + } + } + return; + } + + SliceCache cache; + Preslice perCollision_mid = o2::aod::track::collisionId; + Preslice perCollision_fwd = o2::aod::fwdtrack::collisionId; + + using MyCollisions = Join; + using MyCollision = MyCollisions::iterator; + + using MyTracks = soa::Join; + using MyTrack = MyTracks::iterator; + + using MyFwdTracks = soa::Join; + using MyFwdTrack = MyFwdTracks::iterator; + + template + void fillElectron(TCollision const& collision, TTrack const& track, const float centrality) + { + auto mcparticle = track.template mcParticle_as(); + + if (std::abs(mcparticle.pdgCode()) != 11 || !(mcparticle.isPhysicalPrimary() || mcparticle.producedByGenerator())) { + return; + } + if (cfg_reject_fake_match_its_tpc && o2::aod::pwgem::dilepton::utils::mcutil::hasFakeMatchITSTPC(track)) { + return; + } + if (cfg_require_true_mc_collision_association && mcparticle.mcCollisionId() != collision.mcCollisionId()) { + return; + } + if (!isSelectedTrack(collision, track)) { + return; + } + + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto track_par_cov_recalc = getTrackParCov(track); + track_par_cov_recalc.setPID(o2::track::PID::Electron); + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, track_par_cov_recalc, 2.f, matCorr, &mDcaInfoCov); + // float dcaXY = mDcaInfoCov.getY(); + // float dcaZ = mDcaInfoCov.getZ(); + + float pt = track_par_cov_recalc.getPt(); + float eta = track_par_cov_recalc.getEta(); + float phi = track_par_cov_recalc.getPhi(); + o2::math_utils::bringTo02Pi(phi); + + registry.fill(HIST("Electron/hPt"), pt); + registry.fill(HIST("Electron/hEtaPhi"), phi, eta); + registry.fill(HIST("Electron/hs_reso"), centrality, mcparticle.pt(), mcparticle.eta(), mcparticle.phi(), -mcparticle.pdgCode() / 11, (mcparticle.pt() - pt) / mcparticle.pt(), mcparticle.eta() - eta, mcparticle.phi() - phi); + registry.fill(HIST("Electron/Ptgen_RelDeltaPt"), mcparticle.pt(), (mcparticle.pt() - pt) / mcparticle.pt()); + registry.fill(HIST("Electron/Ptgen_DeltaEta"), mcparticle.pt(), mcparticle.eta() - eta); + if (mcparticle.pdgCode() == -11) { // positron + registry.fill(HIST("Electron/Ptgen_DeltaPhi_Pos"), mcparticle.pt(), mcparticle.phi() - phi); + } else if (mcparticle.pdgCode() == 11) { // electron + registry.fill(HIST("Electron/Ptgen_DeltaPhi_Neg"), mcparticle.pt(), mcparticle.phi() - phi); + } + } + + void processElectronSA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyTracks const& tracks, aod::McCollisions const&, aod::McParticles const&) + { + for (auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!isSelectedEvent(collision)) { + continue; + } + + if (!collision.has_mcCollision()) { + continue; + } + + auto mccollision = collision.template mcCollision_as(); + if (cfgEventGeneratorType >= 0 && mccollision.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + + float centrality = std::array{collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}[cfgCentEstimator]; + registry.fill(HIST("Event/Electron/hImpPar_Centrality"), mccollision.impactParameter(), centrality); + + auto tracks_per_coll = tracks.sliceBy(perCollision_mid, collision.globalIndex()); + for (auto& track : tracks_per_coll) { + if (!track.has_mcParticle()) { + continue; + } + fillElectron(collision, track, centrality); + } // end of track loop + } // end of collision loop + } + PROCESS_SWITCH(CreateResolutionMap, processElectronSA, "create resolution map for electron at midrapidity", true); + + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + void processElectronTTCA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyTracks const&, aod::TrackAssoc const& trackIndices, aod::McCollisions const&, aod::McParticles const&) + { + for (auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!isSelectedEvent(collision)) { + continue; + } + + if (!collision.has_mcCollision()) { + continue; + } + + auto mccollision = collision.template mcCollision_as(); + if (cfgEventGeneratorType >= 0 && mccollision.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + + float centrality = std::array{collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}[cfgCentEstimator]; + registry.fill(HIST("Event/Electron/hImpPar_Centrality"), mccollision.impactParameter(), centrality); + + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + for (auto& trackId : trackIdsThisCollision) { + auto track = trackId.template track_as(); + if (!track.has_mcParticle()) { + continue; + } + fillElectron(collision, track, centrality); + } // end of track loop + } // end of collision loop + } + PROCESS_SWITCH(CreateResolutionMap, processElectronTTCA, "create resolution map for electron at midrapidity", false); + + Partition sa_muons = o2::aod::fwdtrack::trackType == uint8_t(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack); // MCH-MID + Partition global_muons = o2::aod::fwdtrack::trackType == uint8_t(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack); // MFT-MCH-MID + + void processMuonSA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyFwdTracks const&, aod::McCollisions const&, aod::McParticles const&) + { + for (auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!isSelectedEvent(collision)) { + continue; + } + + if (!collision.has_mcCollision()) { + continue; + } + + auto mccollision = collision.template mcCollision_as(); + if (cfgEventGeneratorType >= 0 && mccollision.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + + float centrality = std::array{collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}[cfgCentEstimator]; + registry.fill(HIST("Event/Muon/hImpPar_Centrality"), mccollision.impactParameter(), centrality); + + auto sa_muons_per_coll = sa_muons->sliceByCached(o2::aod::fwdtrack::collisionId, collision.globalIndex(), cache); + auto global_muons_per_coll = global_muons->sliceByCached(o2::aod::fwdtrack::collisionId, collision.globalIndex(), cache); + + for (auto& muon : sa_muons_per_coll) { + if (!muon.has_mcParticle()) { + continue; + } + fillMuon(collision, muon, centrality); + } // end of standalone muon loop + + for (auto& muon : global_muons_per_coll) { + if (!muon.has_mcParticle()) { + continue; + } + fillMuon(collision, muon, centrality); + } // end of global muon loop + + } // end of collision loop + } + PROCESS_SWITCH(CreateResolutionMap, processMuonSA, "create resolution map for muon at forward rapidity", true); + + Preslice fwdtrackIndicesPerCollision = aod::track_association::collisionId; + void processMuonTTCA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyFwdTracks const&, aod::FwdTrackAssoc const& fwdtrackIndices, aod::McCollisions const&, aod::McParticles const&) + { + for (auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!isSelectedEvent(collision)) { + continue; + } + + if (!collision.has_mcCollision()) { + continue; + } + + auto mccollision = collision.template mcCollision_as(); + if (cfgEventGeneratorType >= 0 && mccollision.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + + float centrality = std::array{collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}[cfgCentEstimator]; + registry.fill(HIST("Event/Muon/hImpPar_Centrality"), mccollision.impactParameter(), centrality); + + auto fwdtrackIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); + for (auto& fwdtrackId : fwdtrackIdsThisCollision) { + auto muon = fwdtrackId.template fwdtrack_as(); + if (!muon.has_mcParticle()) { + continue; + } + fillMuon(collision, muon, centrality); + } // end of fwdtrack loop + } // end of collision loop + } + PROCESS_SWITCH(CreateResolutionMap, processMuonTTCA, "create resolution map for muon at forward rapidity", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"create-resolution-map"})}; +} diff --git a/PWGEM/Dilepton/Tasks/dielectron.cxx b/PWGEM/Dilepton/Tasks/dielectron.cxx new file mode 100644 index 00000000000..c8fa31b0e3b --- /dev/null +++ b/PWGEM/Dilepton/Tasks/dielectron.cxx @@ -0,0 +1,27 @@ +// 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. +// +// ======================== +// +// This code is for dielectron analyses. +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" + +#include "PWGEM/Dilepton/Core/Dilepton.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"dielectron"})}; +} diff --git a/PWGEM/Dilepton/Tasks/dielectronMC.cxx b/PWGEM/Dilepton/Tasks/dielectronMC.cxx new file mode 100644 index 00000000000..3c525c29c6e --- /dev/null +++ b/PWGEM/Dilepton/Tasks/dielectronMC.cxx @@ -0,0 +1,27 @@ +// 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. +// +// ======================== +// +// This code runs loop over dalitz ee table for dalitz QC. +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" + +#include "PWGEM/Dilepton/Core/DileptonMC.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"dielectron-mc"})}; +} diff --git a/PWGEM/Dilepton/Tasks/dimuon.cxx b/PWGEM/Dilepton/Tasks/dimuon.cxx new file mode 100644 index 00000000000..51b92ab81b7 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/dimuon.cxx @@ -0,0 +1,27 @@ +// 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. +// +// ======================== +// +// This code is for dimuon analyses. +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" + +#include "PWGEM/Dilepton/Core/Dilepton.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"dimuon"})}; +} diff --git a/PWGEM/Dilepton/Tasks/dimuonMC.cxx b/PWGEM/Dilepton/Tasks/dimuonMC.cxx new file mode 100644 index 00000000000..f505c073dc3 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/dimuonMC.cxx @@ -0,0 +1,27 @@ +// 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. +// +// ======================== +// +// This code runs loop over dalitz ee table for dalitz QC. +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" + +#include "PWGEM/Dilepton/Core/DileptonMC.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"dimuon-mc"})}; +} diff --git a/PWGEM/Dilepton/Tasks/emEfficiencyEE.cxx b/PWGEM/Dilepton/Tasks/emEfficiencyEE.cxx index faed38f5e19..7cc41a190d2 100644 --- a/PWGEM/Dilepton/Tasks/emEfficiencyEE.cxx +++ b/PWGEM/Dilepton/Tasks/emEfficiencyEE.cxx @@ -19,6 +19,8 @@ #include #include #include +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPObject.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -41,6 +43,10 @@ #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Centrality.h" #include "Common/CCDB/TriggerAliases.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "Field/MagneticField.h" +#include "TGeoGlobalMagField.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" using std::cout; using std::endl; @@ -83,11 +89,11 @@ using MyBarrelTracksSelectedNoSkimmed = soa::Join; -using MyMCTrackNoSkimmed = soa::Join; +using MyMCTrackNoSkimmed = soa::Join; constexpr static uint32_t gkEventFillMapNoSkimmed = VarManager::ObjTypes::Collision; constexpr static uint32_t gkMCEventFillMapNoSkimmed = VarManager::ObjTypes::CollisionMC; -constexpr static uint32_t gkTrackFillMapNoSkimmed = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackCov | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackPID; +constexpr static uint32_t gkTrackFillMapNoSkimmed = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackCov | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackPID | VarManager::ObjTypes::TrackPIDExtra; constexpr static uint32_t gkParticleMCFillMapNoSkimmed = VarManager::ObjTypes::ParticleMC; // Skimmed data: works up to dielectron efficiency @@ -96,14 +102,14 @@ using MyEventsSelected = soa::Join; using MyBarrelTracks = soa::Join; using MyBarrelTracksSelected = soa::Join; -using MyMCReducedTracks = soa::Join; +using MyMCReducedTracks = soa::Join; // constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended; constexpr static uint32_t gkMCEventFillMap = VarManager::ObjTypes::ReducedEventMC; constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID; constexpr static uint32_t gkParticleMCFillMap = VarManager::ObjTypes::ParticleMC; -void DefineHistograms(HistogramManager* histMan, TString histClasses); +void DefineHistograms(HistogramManager* histMan, TString histClasses, Configurable configVar); // defines histograms for all tasks void SetBinsLinear(std::vector& fBins, const double min, const double max, const unsigned int steps); struct AnalysisEventSelection { @@ -112,9 +118,13 @@ struct AnalysisEventSelection { OutputObj fOutputList{"QA"}; Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigOnlyInjectedEvents{"cfgOnlyInjectedEvents", false, "Use only on Non-skimmed data! If true, select only injected events"}; + Configurable> fSubGenIDs{"cfgSubGenIDs", {0, 1, 2, 3}, "Use only on Non-skimmed data! Provide a comma separated list of subGenIDs to select, e.g. 0,1,2,3"}; HistogramManager* fHistMan; AnalysisCompositeCut* fEventCut; + HistogramRegistry registry{"HistoAnalysisEvent", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(o2::framework::InitContext&) { @@ -128,9 +138,14 @@ struct AnalysisEventSelection { fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(kTRUE); fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - DefineHistograms(fHistMan, "Event_BeforeCuts;Event_AfterCuts;"); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + DefineHistograms(fHistMan, "Event_BeforeCuts;Event_AfterCuts;", fConfigAddEventHistogram); // define all histograms + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); + + AxisSpec axisSubGen = {4, -0.5, 3.5, "MC SubGenerator ID"}; + registry.add("Generator/SubGenerator_BeforeCuts", "", HistType::kTH1D, {axisSubGen}, true); + registry.add("Generator/SubGenerator_SelectedInjected", "", HistType::kTH1D, {axisSubGen}, true); + registry.add("Generator/SubGenerator_AfterCuts", "", HistType::kTH1D, {axisSubGen}, true); } } @@ -141,23 +156,40 @@ struct AnalysisEventSelection { VarManager::ResetValues(0, VarManager::kNEventWiseVariables); bool pass = true; + int32_t subGeneratorID = -999; VarManager::FillEvent(event); if constexpr ((TEventMCFillMap & VarManager::ObjTypes::ReducedEventMC) > 0) { VarManager::FillEvent(event.reducedMCevent()); + // TODO: Get access to subgenerator ID in skimmed data + // generatorID = event.reducedMCevent().generatorsID(); } if constexpr ((TEventMCFillMap & VarManager::ObjTypes::CollisionMC) > 0) { if (!event.has_mcCollision()) { pass = false; } else { VarManager::FillEvent(event.mcCollision()); + subGeneratorID = event.mcCollision().getSubGeneratorId(); } } + + registry.fill(HIST("Generator/SubGenerator_BeforeCuts"), subGeneratorID); + + // check if SubGeneratorID is part of list: + // if SubGenerator is not part of it, reject event, return + // fill event histos only if event is from SubGenerator + if (fConfigOnlyInjectedEvents && !(std::find(fSubGenIDs->begin(), fSubGenIDs->end(), subGeneratorID) != fSubGenIDs->end())) { + eventSel(0); + return; + } + if (fConfigQA) { fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); // automatically fill all the histograms in the class Event + registry.fill(HIST("Generator/SubGenerator_SelectedInjected"), subGeneratorID); } if (fEventCut->IsSelected(VarManager::fgValues) && pass) { if (fConfigQA) { fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); + registry.fill(HIST("Generator/SubGenerator_AfterCuts"), subGeneratorID); } eventSel(1); } else { @@ -190,6 +222,7 @@ struct AnalysisEventSelection { PROCESS_SWITCH(AnalysisEventSelection, processDummy, "Dummy process function", false); PROCESS_SWITCH(AnalysisEventSelection, processDummyNoSkimmed, "Dummy process function", false); }; + struct AnalysisEventQa { Filter filterEventSelected = aod::emanalysisflags::isEventSelected == 1; @@ -407,22 +440,24 @@ struct AnalysisTrackSelection { // 3D histos for efficiency Configurable fConfigUsePtVec{"cfgUsePtVecEff", true, "If true, non-linear pt bins but vector pt bins"}; - ConfigurableAxis ptBinsVec{"ptBinsVec", {0., 0., 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.155, 0.16, 0.165, 0.17, 0.175, 0.18, 0.185, 0.19, 0.195, 0.20, 0.205, 0.21, 0.215, 0.22, 0.225, 0.23, 0.235, 0.24, 0.245, 0.25, 0.255, 0.26, 0.265, 0.27, 0.275, 0.28, 0.285, 0.29, 0.295, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.43, 0.46, 0.49, 0.52, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.90, 1.00, 1.10, 1.20, 1.40, 1.60, 1.80, 2.00, 2.40, 2.80, 3.20, 3.70, 4.50, 6.00, 8.00, 10.}, "Pt binning vector"}; + ConfigurableAxis ptBinsVec{"ptBinsVec", {0., 0., 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.155, 0.16, 0.165, 0.17, 0.175, 0.18, 0.185, 0.19, 0.195, 0.20, 0.205, 0.21, 0.215, 0.22, 0.225, 0.23, 0.235, 0.24, 0.245, 0.25, 0.255, 0.26, 0.265, 0.27, 0.275, 0.28, 0.285, 0.29, 0.295, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.43, 0.46, 0.49, 0.52, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.90, 1.00, 1.10, 1.20, 1.40, 1.60, 1.80, 2.00, 2.40, 2.80, 3.20, 3.70, 4.50, 6.00, 8.00, 10., 12., 14., 16., 18., 20.}, "Pt binning vector"}; ConfigurableAxis ptBins{"ptBins", {10, 0.f, 10.f}, "Pt binning"}; ConfigurableAxis etaBins{"etaBins", {16, -0.8f, 0.8f}, "Eta binning"}; ConfigurableAxis phiBins{"phiBins", {63, -0.f, 6.3f}, "Phi binning"}; Configurable fConfigRecWithMC{"cfgEffRecWithMCVars", false, "If true, fill also 3D histograms at reconstructed level with mc variables"}; + Configurable fConfigMCCollz{"cfgMCCollz", false, "If true, look only at reconstructed track associated to mc track from a MC collision within 10cm"}; // Resolution histos Configurable fConfigResolutionOn{"cfgResolution", false, "If true, fill resolution histograms"}; Configurable fConfigUsePtVecRes{"cfgUsePtVecRes", true, "If true, non-linear pt bins predefined in res histos"}; - ConfigurableAxis ptResBinsVec{"ptResBinsVec", {0., 0., 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.155, 0.16, 0.165, 0.17, 0.175, 0.18, 0.185, 0.19, 0.195, 0.20, 0.205, 0.21, 0.215, 0.22, 0.225, 0.23, 0.235, 0.24, 0.245, 0.25, 0.255, 0.26, 0.265, 0.27, 0.275, 0.28, 0.285, 0.29, 0.295, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.43, 0.46, 0.49, 0.52, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.90, 1.00, 1.10, 1.20, 1.40, 1.60, 1.80, 2.00, 2.40, 2.80, 3.20, 3.70, 4.50, 6.00, 8.00, 10., 12.0, 14., 16., 18., 20.}, "Pt binning vector for resolution"}; + ConfigurableAxis ptResBinsVec{"ptResBinsVec", {0., 0., 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.155, 0.16, 0.165, 0.17, 0.175, 0.18, 0.185, 0.19, 0.195, 0.20, 0.205, 0.21, 0.215, 0.22, 0.225, 0.23, 0.235, 0.24, 0.245, 0.25, 0.255, 0.26, 0.265, 0.27, 0.275, 0.28, 0.285, 0.29, 0.295, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.43, 0.46, 0.49, 0.52, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.90, 1.00, 1.10, 1.20, 1.40, 1.60, 1.80, 2.00, 2.40, 2.80, 3.20, 3.70, 4.50, 6.00, 8.00, 10., 12., 14., 16., 18., 20.}, "Pt binning vector for resolution"}; ConfigurableAxis ptResBins{"ptResBins", {20, 0.f, 20.f}, "Pt binning for resolution"}; ConfigurableAxis deltaptResBins{"deltaptResBins", {500, -0.5f, 0.5f}, "DeltaPt binning for resolution"}; ConfigurableAxis deltaetaResBins{"deltaetaResBins", {500, -0.5f, 0.5f}, "DeltaEta binning for resolution"}; ConfigurableAxis deltaphiResBins{"deltaphiResBins", {500, -0.5f, 0.5f}, "DeltaPhi binning for resolution"}; Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; // output lists OutputObj fOutputQA{"SingleElectronQA"}; @@ -445,6 +480,13 @@ struct AnalysisTrackSelection { std::vector> fHistRecNegPart; std::vector> fHistRecPosPartMC; std::vector> fHistRecNegPartMC; + // + std::vector> fHistRecPosSingleRecPartMC; + std::vector> fHistRecNegSingleRecPartMC; + std::vector> fHistRecPosClassCollDoubleCountPartMC; + std::vector> fHistRecNegClassCollDoubleCountPartMC; + std::vector> fHistRecPosClassAmbigCollDoubleCountPartMC; + std::vector> fHistRecNegClassAmbigCollDoubleCountPartMC; // Res histos std::vector> fHistRes; @@ -453,7 +495,7 @@ struct AnalysisTrackSelection { HistogramManager* fHistManQA; // histo manager std::vector fHistNamesRecoQA; // list of histo names for all reconstructed tracks in histo manager std::vector> fHistNamesMCMatchedQA; // list of histo names for reconstructed signals in histo manager - std::vector> fHistNamesMCQA; // list of histo names for generated signals in histo manager + std::vector fHistNamesMCQA; // list of histo names for generated signals in histo manager void init(o2::framework::InitContext&) { @@ -467,6 +509,9 @@ struct AnalysisTrackSelection { AxisSpec axisEta{etaBins, "#it{#eta}_{e}"}; AxisSpec axisPhi{phiBins, "#it{#varphi}_{e} (rad)"}; AxisSpec axisPt{ptBins, "#it{p}_{T,e} (GeV/#it{c})"}; + AxisSpec axisMCColl = {3, -0.5, 2.5, "MCcoll info"}; + AxisSpec axisDoubleCount = {2, -0.5, 1.5, "Double count info"}; + AxisSpec axisAmbig = {2, -0.5, 1.5, "Ambiguous info"}; // List of track cuts TString cutNamesStr = fConfigCuts.value; @@ -535,21 +580,51 @@ struct AnalysisTrackSelection { if (fConfigRecWithMC) { for (unsigned int list_i = 0; list_i < fTrackCuts.size(); ++list_i) { for (unsigned int i = 0; i < fMCSignals.size(); ++i) { - if (!fConfigUsePtVec) { fHistRecPosPartMC.push_back(registry.add(Form("SingleElectron/%s_MCVars/Nrec_Pos_%s", fTrackCuts.at(list_i).GetName(), fMCSignals.at(i).GetName()), "", HistType::kTH3D, {axisPt, axisEta, axisPhi}, true)); fHistRecNegPartMC.push_back(registry.add(Form("SingleElectron/%s_MCVars/Nrec_Neg_%s", fTrackCuts.at(list_i).GetName(), fMCSignals.at(i).GetName()), "", HistType::kTH3D, {axisPt, axisEta, axisPhi}, true)); + fHistRecPosSingleRecPartMC.push_back(registry.add(Form("SingleElectron/%s_MCVars/Nrec_Pos_SingleRec_%s", fTrackCuts.at(list_i).GetName(), fMCSignals.at(i).GetName()), "", HistType::kTH3D, {axisPt, axisEta, axisPhi}, true)); + fHistRecNegSingleRecPartMC.push_back(registry.add(Form("SingleElectron/%s_MCVars/Nrec_Neg_SingleRec_%s", fTrackCuts.at(list_i).GetName(), fMCSignals.at(i).GetName()), "", HistType::kTH3D, {axisPt, axisEta, axisPhi}, true)); + fHistRecPosClassCollDoubleCountPartMC.push_back(registry.add(Form("SingleElectron/%s_MCVars/Nrec_Pos_ClassCollDoubleCount_%s", fTrackCuts.at(list_i).GetName(), fMCSignals.at(i).GetName()), "", HistType::kTH3D, {axisPt, axisMCColl, axisDoubleCount}, true)); + fHistRecNegClassCollDoubleCountPartMC.push_back(registry.add(Form("SingleElectron/%s_MCVars/Nrec_Neg_ClassCollDoubleCount_%s", fTrackCuts.at(list_i).GetName(), fMCSignals.at(i).GetName()), "", HistType::kTH3D, {axisPt, axisMCColl, axisDoubleCount}, true)); } else { fHistRecPosPartMC.push_back(registry.add(Form("SingleElectron/%s_MCVars/Nrec_Pos_%s", fTrackCuts.at(list_i).GetName(), fMCSignals.at(i).GetName()), "", HistType::kTH3D, {{ptBinsVec, "#it{p}_{T,e} (GeV/#it{c})"}, axisEta, axisPhi}, true)); fHistRecNegPartMC.push_back(registry.add(Form("SingleElectron/%s_MCVars/Nrec_Neg_%s", fTrackCuts.at(list_i).GetName(), fMCSignals.at(i).GetName()), "", HistType::kTH3D, {{ptBinsVec, "#it{p}_{T,e} (GeV/#it{c})"}, axisEta, axisPhi}, true)); + fHistRecPosSingleRecPartMC.push_back(registry.add(Form("SingleElectron/%s_MCVars/Nrec_Pos_SingleRec_%s", fTrackCuts.at(list_i).GetName(), fMCSignals.at(i).GetName()), "", HistType::kTH3D, {{ptBinsVec, "#it{p}_{T,e} (GeV/#it{c})"}, axisEta, axisPhi}, true)); + fHistRecNegSingleRecPartMC.push_back(registry.add(Form("SingleElectron/%s_MCVars/Nrec_Neg_SingleRec_%s", fTrackCuts.at(list_i).GetName(), fMCSignals.at(i).GetName()), "", HistType::kTH3D, {{ptBinsVec, "#it{p}_{T,e} (GeV/#it{c})"}, axisEta, axisPhi}, true)); + fHistRecPosClassCollDoubleCountPartMC.push_back(registry.add(Form("SingleElectron/%s_MCVars/Nrec_Pos_ClassCollDoubleCount_%s", fTrackCuts.at(list_i).GetName(), fMCSignals.at(i).GetName()), "", HistType::kTH3D, {{ptBinsVec, "#it{p}_{T,e} (GeV/#it{c})"}, axisMCColl, axisDoubleCount}, true)); + fHistRecNegClassCollDoubleCountPartMC.push_back(registry.add(Form("SingleElectron/%s_MCVars/Nrec_Neg_ClassCollDoubleCount_%s", fTrackCuts.at(list_i).GetName(), fMCSignals.at(i).GetName()), "", HistType::kTH3D, {{ptBinsVec, "#it{p}_{T,e} (GeV/#it{c})"}, axisMCColl, axisDoubleCount}, true)); } + fHistRecPosClassAmbigCollDoubleCountPartMC.push_back(registry.add(Form("SingleElectron/%s_MCVars/Nrec_Pos_ClassAmigCollDoubleCount_%s", fTrackCuts.at(list_i).GetName(), fMCSignals.at(i).GetName()), "", HistType::kTH3D, {axisAmbig, axisMCColl, axisDoubleCount}, true)); + fHistRecNegClassAmbigCollDoubleCountPartMC.push_back(registry.add(Form("SingleElectron/%s_MCVars/Nrec_Neg_ClassAmigCollDoubleCount_%s", fTrackCuts.at(list_i).GetName(), fMCSignals.at(i).GetName()), "", HistType::kTH3D, {axisAmbig, axisMCColl, axisDoubleCount}, true)); + } + } + // Histo without track cut + for (unsigned int i = 0; i < fMCSignals.size(); ++i) { + + if (!fConfigUsePtVec) { + fHistRecPosPartMC.push_back(registry.add(Form("SingleElectron/NoCut_MCVars/Nrec_Pos_%s", fMCSignals.at(i).GetName()), "", HistType::kTH3D, {axisPt, axisEta, axisPhi}, true)); + fHistRecNegPartMC.push_back(registry.add(Form("SingleElectron/NoCut_MCVars/Nrec_Neg_%s", fMCSignals.at(i).GetName()), "", HistType::kTH3D, {axisPt, axisEta, axisPhi}, true)); + fHistRecPosSingleRecPartMC.push_back(registry.add(Form("SingleElectron/NoCut_MCVars/Nrec_Pos_SingleRec_%s", fMCSignals.at(i).GetName()), "", HistType::kTH3D, {axisPt, axisEta, axisPhi}, true)); + fHistRecNegSingleRecPartMC.push_back(registry.add(Form("SingleElectron/NoCut_MCVars/Nrec_Neg_SingleRec_%s", fMCSignals.at(i).GetName()), "", HistType::kTH3D, {axisPt, axisEta, axisPhi}, true)); + fHistRecPosClassCollDoubleCountPartMC.push_back(registry.add(Form("SingleElectron/NoCut_MCVars/Nrec_Pos_ClassCollDoubleCount_%s", fMCSignals.at(i).GetName()), "", HistType::kTH3D, {axisPt, axisMCColl, axisDoubleCount}, true)); + fHistRecNegClassCollDoubleCountPartMC.push_back(registry.add(Form("SingleElectron/NoCut_MCVars/Nrec_Neg_ClassCollDoubleCount_%s", fMCSignals.at(i).GetName()), "", HistType::kTH3D, {axisPt, axisMCColl, axisDoubleCount}, true)); + + } else { + fHistRecPosPartMC.push_back(registry.add(Form("SingleElectron/NoCut_MCVars/Nrec_Pos_%s", fMCSignals.at(i).GetName()), "", HistType::kTH3D, {{ptBinsVec, "#it{p}_{T,e} (GeV/#it{c})"}, axisEta, axisPhi}, true)); + fHistRecNegPartMC.push_back(registry.add(Form("SingleElectron/NoCut_MCVars/Nrec_Neg_%s", fMCSignals.at(i).GetName()), "", HistType::kTH3D, {{ptBinsVec, "#it{p}_{T,e} (GeV/#it{c})"}, axisEta, axisPhi}, true)); + fHistRecPosSingleRecPartMC.push_back(registry.add(Form("SingleElectron/NoCut_MCVars/Nrec_Pos_SingleRec_%s", fMCSignals.at(i).GetName()), "", HistType::kTH3D, {{ptBinsVec, "#it{p}_{T,e} (GeV/#it{c})"}, axisEta, axisPhi}, true)); + fHistRecNegSingleRecPartMC.push_back(registry.add(Form("SingleElectron/NoCut_MCVars/Nrec_Neg_SingleRec_%s", fMCSignals.at(i).GetName()), "", HistType::kTH3D, {{ptBinsVec, "#it{p}_{T,e} (GeV/#it{c})"}, axisEta, axisPhi}, true)); + fHistRecPosClassCollDoubleCountPartMC.push_back(registry.add(Form("SingleElectron/NoCut_MCVars/Nrec_Pos_ClassCollDoubleCount_%s", fMCSignals.at(i).GetName()), "", HistType::kTH3D, {{ptBinsVec, "#it{p}_{T,e} (GeV/#it{c})"}, axisMCColl, axisDoubleCount}, true)); + fHistRecNegClassCollDoubleCountPartMC.push_back(registry.add(Form("SingleElectron/NoCut_MCVars/Nrec_Neg_ClassCollDoubleCount_%s", fMCSignals.at(i).GetName()), "", HistType::kTH3D, {{ptBinsVec, "#it{p}_{T,e} (GeV/#it{c})"}, axisMCColl, axisDoubleCount}, true)); } + fHistRecPosClassAmbigCollDoubleCountPartMC.push_back(registry.add(Form("SingleElectron/NoCut_MCVars/Nrec_Pos_ClassAmigCollDoubleCount_%s", fMCSignals.at(i).GetName()), "", HistType::kTH3D, {axisAmbig, axisMCColl, axisDoubleCount}, true)); + fHistRecNegClassAmbigCollDoubleCountPartMC.push_back(registry.add(Form("SingleElectron/NoCut_MCVars/Nrec_Neg_ClassAmigCollDoubleCount_%s", fMCSignals.at(i).GetName()), "", HistType::kTH3D, {axisAmbig, axisMCColl, axisDoubleCount}, true)); } } // Resolution histogramms if (fConfigResolutionOn) { - // Binning for resolution AxisSpec axisPtRes{ptResBins, "#it{p}^{gen}_{T,e} (GeV/#it{c})"}; AxisSpec axisDeltaptRes{deltaptResBins, "(p^{gen}_{T} - p^{rec}_{T}) / p^{gen}_{T} (GeV/c)"}; @@ -591,19 +666,20 @@ struct AnalysisTrackSelection { } // Add histogram classes for each MC signal at generated level - std::vector mcnamesgen; + // std::vector mcnamesgen; for (unsigned int isig = 0; isig < fMCSignals.size(); ++isig) { TString nameStr2 = Form("MCTruthGen_%s", fMCSignals.at(isig).GetName()); - mcnamesgen.push_back(nameStr2); + fHistNamesMCQA.push_back(nameStr2); + // mcnamesgen.push_back(nameStr2); histClassesQA += Form("%s;", nameStr2.Data()); } - fHistNamesMCQA.push_back(mcnamesgen); + // fHistNamesMCQA.push_back(mcnamesgen); fHistManQA = new HistogramManager("SingleElectronQA", "aa", VarManager::kNVars); fHistManQA->SetUseDefaultVariableNames(kTRUE); fHistManQA->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - DefineHistograms(fHistManQA, histClassesQA.Data()); // define all histograms - VarManager::SetUseVars(fHistManQA->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + DefineHistograms(fHistManQA, histClassesQA.Data(), fConfigAddTrackHistogram); // define all histograms + VarManager::SetUseVars(fHistManQA->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fQASingleElectronList = fHistManQA->GetMainHistogramList(); } fOutputQA.setObject(fQASingleElectronList); @@ -693,6 +769,16 @@ struct AnalysisTrackSelection { runRecTrack(tracks, tracksMC, true, write); } + template + void runDataFillMore(TEvents const& events, TEventsMC eventsMC, TTracks const& tracks, TTracksMC const& tracksMC, TAmbigTracks const& ambiTracksMid) + { + + VarManager::ResetValues(0, VarManager::kNEventWiseVariables); + VarManager::ResetValues(0, VarManager::kNMCParticleVariables); + + runRecTrackMore(events, eventsMC, tracks, tracksMC, ambiTracksMid); + } + template void runMCFill(TEventsMC const& eventMC, TTracksMC const& tracksMC) { @@ -701,6 +787,14 @@ struct AnalysisTrackSelection { runMCGenTrack(tracksMC); } + template + void runMCFillMore(TEventsMC const& eventMC, TTracksMC const& tracksMC) + { + VarManager::ResetValues(0, VarManager::kNEventWiseVariables); + VarManager::FillEvent(eventMC); + runMCGenTrackMore(tracksMC, eventMC); + } + template void runDataSelection(TTracks const& tracks, TTracksMC const& tracksMC) { @@ -710,9 +804,53 @@ struct AnalysisTrackSelection { template void runMCGenTrack(TTracksMC const& groupedMCTracks) + { + for (auto& mctrack : groupedMCTracks) { + VarManager::ResetValues(0, VarManager::kNMCParticleVariables); + VarManager::FillTrackMC(groupedMCTracks, mctrack); + int isig = 0; + for (auto sig = fMCSignals.begin(); sig != fMCSignals.end(); sig++, isig++) { + bool checked = false; + if constexpr (soa::is_soa_filtered_v) { + auto mctrack_raw = groupedMCTracks.rawIteratorAt(mctrack.globalIndex()); + checked = (*sig).CheckSignal(true, mctrack_raw); + } else { + checked = (*sig).CheckSignal(true, mctrack); + } + if (checked) { + if (mctrack.pdgCode() > 0) { + fHistGenNegPart[isig]->Fill(mctrack.pt(), mctrack.eta(), mctrack.phi()); + if constexpr (smeared) + fHistGenSmearedNegPart[isig]->Fill(mctrack.ptSmeared(), mctrack.etaSmeared(), mctrack.phiSmeared()); + } else { + fHistGenPosPart[isig]->Fill(mctrack.pt(), mctrack.eta(), mctrack.phi()); + if constexpr (smeared) + fHistGenSmearedPosPart[isig]->Fill(mctrack.ptSmeared(), mctrack.etaSmeared(), mctrack.phiSmeared()); + } + if (fConfigQA) { + fHistManQA->FillHistClass(fHistNamesMCQA[isig].Data(), VarManager::fgValues); + } + } + } + } + } + + template + void runMCGenTrackMore(TTracksMC const& groupedMCTracks, TEventsMC const& /*eventMC*/) { for (auto& mctrack : groupedMCTracks) { + + bool mccollisionwithin10 = false; + auto mccollision = mctrack.mcCollision(); + Double_t zmc = mccollision.posZ(); + if (TMath::Abs(zmc) < 10.) + mccollisionwithin10 = true; + + if (!mccollisionwithin10 && fConfigMCCollz) + continue; + + VarManager::ResetValues(0, VarManager::kNMCParticleVariables); VarManager::FillTrackMC(groupedMCTracks, mctrack); int isig = 0; for (auto sig = fMCSignals.begin(); sig != fMCSignals.end(); sig++, isig++) { @@ -734,7 +872,8 @@ struct AnalysisTrackSelection { fHistGenSmearedPosPart[isig]->Fill(mctrack.ptSmeared(), mctrack.etaSmeared(), mctrack.phiSmeared()); } if (fConfigQA) - fHistManQA->FillHistClass(Form("MCTruthGen_%s", (*sig).GetName()), VarManager::fgValues); + // fHistManQA->FillHistClass(Form("MCTruthGen_%s", (*sig).GetName()), VarManager::fgValues); + fHistManQA->FillHistClass(fHistNamesMCQA[isig].Data(), VarManager::fgValues); } } } @@ -750,6 +889,8 @@ struct AnalysisTrackSelection { for (auto& track : groupedTracks) { filterMap = 0; + VarManager::ResetValues(0, VarManager::kNMCParticleVariables); + VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); VarManager::FillTrack(track); // compute track quantities // compute MC matched quantities @@ -890,6 +1031,254 @@ struct AnalysisTrackSelection { } // end loop over reconstructed track belonging to the events } + template + void runRecTrackMore(TEvents const& events, TEventsMC const& /*eventsMC*/, TTracks const& groupedTracks, TTracksMC const& tracksMC, TAmbigTracks const& ambiTracksMid) + { + + std::map fRecTrackLabels[fTrackCuts.size() + 1]; + + uint32_t filterMap = 0; + trackSel.reserve(groupedTracks.size()); + + for (auto& track : groupedTracks) { + + // How many time the associated MC track was seen for this cut + Int_t fRecCounters[fTrackCuts.size() + 1]; + for (unsigned int k = 0; k < fTrackCuts.size() + 1; k++) { + fRecCounters[k] = 0; + } + + filterMap = 0; + Int_t ambiguousinfo = 0; + Int_t collisioninfo = -1; + Int_t mcCollisionIddmctrack = -999; + Int_t mcCollisionIdrectrack = -999; + bool mccollisionwithin10 = false; + + VarManager::FillTrack(track); // compute track quantities + + // Do ambiguous tracks + for (auto& ambiTrackMid : ambiTracksMid) { + if (ambiTrackMid.trackId() == track.globalIndex()) { + ambiguousinfo = 1; + break; + } + } + + // Do matching + // if (!track.has_collision()) printf("CollisionId %d\n",track.collisionId()); + if (track.has_collision()) { + Int_t reccollisionid = track.collisionId(); + if (ambiguousinfo == 1) + printf("Has reccollision but is ambiguous\n"); + // printf("Look for the reconstructed collision %d\n",reccollisionid); + bool pass = 0; + for (auto& event : events) { + if (event.isEventSelected() == 1) { + VarManager::FillEvent(event); + // printf("Global index of collision %d\n",event.globalIndex()); + if (reccollisionid == event.globalIndex()) { + pass = 1; + // printf("Found a collision with the same id %d and %d\n",reccollisionid,event.globalIndex()); + if (ambiguousinfo == 1) + printf("Has reccollision and found it in the list but is ambiguous\n"); + if (event.has_mcCollision()) { + mcCollisionIdrectrack = event.mcCollisionId(); + if (ambiguousinfo == 1) + printf("Has reccollision with mccollision but is ambiguous\n"); + } else { + if (ambiguousinfo == 1) + printf("Has reccollision but without mccollision and is ambiguous\n"); + } + break; + } + } + } + if (!pass) // rec collision of track is not selected by isSelected + continue; + // else rec collision of track is selected by isSelected + } else { + // printf("Not attached to a reconstructed collision\n"); + } + + if constexpr ((TTrackFillMap & VarManager::ObjTypes::Track) > 0) { + // If no MC particle is found, skip the track + if (track.has_mcParticle()) { + // if (ambiguousinfo == 1) printf("Has mcparticle but is ambiguous\n"); + // printf("Found a mc track\n"); + auto mctrack = track.template mcParticle_as(); + mcCollisionIddmctrack = mctrack.mcCollisionId(); + auto mccollision = mctrack.mcCollision(); + Double_t zmc = mccollision.posZ(); + if (TMath::Abs(zmc) < 10.) + mccollisionwithin10 = true; + VarManager::FillTrackMC(tracksMC, mctrack); + } + } + + // no track cut + if (fConfigQA) { + fHistManQA->FillHistClass("TrackBarrel_BeforeCuts", VarManager::fgValues); + } + + // if (ambiguousinfo == 1) printf("Values are %d and %d\n",mcCollisionIddmctrack,mcCollisionIdrectrack); + // compute collision and mccollision info + if (mcCollisionIddmctrack != -999 && mcCollisionIdrectrack != -999) { + if (mcCollisionIddmctrack == mcCollisionIdrectrack) + collisioninfo = 0; + else + collisioninfo = 1; + } else { + collisioninfo = 2; + } + // printf("collision info %d\n",collisioninfo); + + // compute track selection and publish the bit map + int i = 0; + for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, i++) { + if ((*cut).IsSelected(VarManager::fgValues)) { + filterMap |= (uint32_t(1) << i); + if (fConfigQA) { + fHistManQA->FillHistClass(fHistNamesRecoQA[i].Data(), VarManager::fgValues); + } + } + } + + // compute MC matching decisions + uint32_t mcDecision = 0; + int isig = 0; + Int_t mctrackindex = -999; + Int_t doublereconstructedtrack[fTrackCuts.size() + 1]; + for (unsigned int k = 0; k < fTrackCuts.size() + 1; k++) { + doublereconstructedtrack[k] = 0; + } + for (auto sig = fMCSignals.begin(); sig != fMCSignals.end(); sig++, isig++) { + if constexpr ((TTrackFillMap & VarManager::ObjTypes::Track) > 0) { + if (track.has_mcParticle()) { + auto mctrack = track.template mcParticle_as(); + if ((*sig).CheckSignal(true, mctrack)) { + mcDecision |= (uint32_t(1) << isig); + mctrackindex = mctrack.globalIndex(); + } + } + } + } + + // // Double reconstructed track only for the signal (they should not be redundant or crossing!!) + // for (unsigned int i = 0; i < fMCSignals.size(); i++) { + // if (!(mcDecision & (uint32_t(1) << i))) { + // continue; + // } + + // no track cuts + if (!(fRecTrackLabels[fTrackCuts.size()].find(mctrackindex) != fRecTrackLabels[fTrackCuts.size()].end())) { + fRecTrackLabels[fTrackCuts.size()][mctrackindex] = fRecCounters[fTrackCuts.size()]; + fRecCounters[fTrackCuts.size()]++; + } else { + // printf("For cut %d, found a mc collision track already reconstructed %d for selected collision with the same mc collision %d\n",j,mctrackindex,mcCollisionId); + doublereconstructedtrack[fTrackCuts.size()] = 1; + fRecTrackLabels[fTrackCuts.size()][mctrackindex] = fRecTrackLabels[fTrackCuts.size()].find(mctrackindex)->second + 1; + } + // track cuts + for (unsigned int j = 0; j < fTrackCuts.size(); j++) { + if (filterMap & (uint8_t(1) << j)) { + + if (!(fRecTrackLabels[j].find(mctrackindex) != fRecTrackLabels[j].end())) { + fRecTrackLabels[j][mctrackindex] = fRecCounters[j]; + fRecCounters[j]++; + } else { + // printf("For cut %d, found a mc collision track already reconstructed %d for selected collision with the same mc collision %d\n",j,mctrackindex,mcCollisionId); + doublereconstructedtrack[j] = 1; + fRecTrackLabels[j][mctrackindex] = fRecTrackLabels[j].find(mctrackindex)->second + 1; + } + } + } + // } + + // fill histograms + for (unsigned int i = 0; i < fMCSignals.size(); i++) { + if (!(mcDecision & (uint32_t(1) << i))) { + continue; + } + Double_t mmcpt = -10000.; + Double_t mmceta = -10000.; + Double_t mmcphi = -1000.; + // No track cut + if (fConfigRecWithMC) { + if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedTrack) > 0) { + auto mctrack = track.reducedMCTrack(); + mmcpt = mctrack.pt(); + mmceta = mctrack.eta(); + mmcphi = mctrack.phi(); + } + if constexpr ((TTrackFillMap & VarManager::ObjTypes::Track) > 0) { + if (track.has_mcParticle()) { + auto mctrack = track.template mcParticle_as(); + mmcpt = mctrack.pt(); + mmceta = mctrack.eta(); + mmcphi = mctrack.phi(); + } + } + + if ((mccollisionwithin10 && fConfigMCCollz) || (!fConfigMCCollz)) { + if (track.sign() < 0) { + fHistRecNegPartMC[fTrackCuts.size() * fMCSignals.size() + i]->Fill(mmcpt, mmceta, mmcphi); + if (doublereconstructedtrack[fTrackCuts.size()] == 0) + fHistRecNegSingleRecPartMC[fTrackCuts.size() * fMCSignals.size() + i]->Fill(mmcpt, mmceta, mmcphi); + if (TMath::Abs(mmceta) < 0.8) { + fHistRecNegClassCollDoubleCountPartMC[fTrackCuts.size() * fMCSignals.size() + i]->Fill(mmcpt, collisioninfo, doublereconstructedtrack[fTrackCuts.size()]); + fHistRecNegClassAmbigCollDoubleCountPartMC[fTrackCuts.size() * fMCSignals.size() + i]->Fill(ambiguousinfo, collisioninfo, doublereconstructedtrack[fTrackCuts.size()]); + } + } else { + fHistRecPosPartMC[fTrackCuts.size() * fMCSignals.size() + i]->Fill(mmcpt, mmceta, mmcphi); + if (doublereconstructedtrack[fTrackCuts.size()] == 0) + fHistRecPosSingleRecPartMC[fTrackCuts.size() * fMCSignals.size() + i]->Fill(mmcpt, mmceta, mmcphi); + if (TMath::Abs(mmceta) < 0.8) { + fHistRecPosClassCollDoubleCountPartMC[fTrackCuts.size() * fMCSignals.size() + i]->Fill(mmcpt, collisioninfo, doublereconstructedtrack[fTrackCuts.size()]); + fHistRecPosClassAmbigCollDoubleCountPartMC[fTrackCuts.size() * fMCSignals.size() + i]->Fill(ambiguousinfo, collisioninfo, doublereconstructedtrack[fTrackCuts.size()]); + } + } + } + } + // track cuts + for (unsigned int j = 0; j < fTrackCuts.size(); j++) { + if (filterMap & (uint8_t(1) << j)) { + if (track.sign() < 0) { + fHistRecNegPart[j * fMCSignals.size() + i]->Fill(track.pt(), track.eta(), track.phi()); + } else { + fHistRecPosPart[j * fMCSignals.size() + i]->Fill(track.pt(), track.eta(), track.phi()); + } + + if (fConfigRecWithMC) { + if ((mccollisionwithin10 && fConfigMCCollz) || (!fConfigMCCollz)) { + if (track.sign() < 0) { + fHistRecNegPartMC[j * fMCSignals.size() + i]->Fill(mmcpt, mmceta, mmcphi); + if (doublereconstructedtrack[j] == 0) + fHistRecNegSingleRecPartMC[j * fMCSignals.size() + i]->Fill(mmcpt, mmceta, mmcphi); + if (TMath::Abs(mmceta) < 0.8) { + fHistRecNegClassCollDoubleCountPartMC[j * fMCSignals.size() + i]->Fill(mmcpt, collisioninfo, doublereconstructedtrack[j]); + fHistRecNegClassAmbigCollDoubleCountPartMC[j * fMCSignals.size() + i]->Fill(ambiguousinfo, collisioninfo, doublereconstructedtrack[fTrackCuts.size()]); + } + } else { + fHistRecPosPartMC[j * fMCSignals.size() + i]->Fill(mmcpt, mmceta, mmcphi); + if (doublereconstructedtrack[j] == 0) + fHistRecPosSingleRecPartMC[j * fMCSignals.size() + i]->Fill(mmcpt, mmceta, mmcphi); + if (TMath::Abs(mmceta) < 0.8) { + fHistRecPosClassCollDoubleCountPartMC[j * fMCSignals.size() + i]->Fill(mmcpt, collisioninfo, doublereconstructedtrack[j]); + fHistRecPosClassAmbigCollDoubleCountPartMC[j * fMCSignals.size() + i]->Fill(ambiguousinfo, collisioninfo, doublereconstructedtrack[fTrackCuts.size()]); + } + } + } + } + + if (fConfigQA) + fHistManQA->FillHistClass(fHistNamesMCMatchedQA[j][i].Data(), VarManager::fgValues); + } + } // end loop over cuts + } // end loop over MC signals + } // end loop over reconstructed track belonging to the events + } + void processSkimmed(soa::Filtered const& events, MyBarrelTracks const& tracks, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) { runSelection(events, tracks, eventsMC, tracksMC, true); @@ -915,15 +1304,48 @@ struct AnalysisTrackSelection { } void processMCNoSkimmed(soa::Filtered::iterator const& eventMC, MyMCTrackNoSkimmed const& tracksMC) + // void processMCNoSkimmed(aod::McCollisions::iterator const& eventMC, MyMCTrackNoSkimmed const& tracksMC) { runMCFill(eventMC, tracksMC); } + // void processMCNoSkimmed(MyMCTrackNoSkimmed const& tracksMC) + // { + // runMCGenTrack(tracksMC); + // } + + void processMCNoSkimmedMore(soa::Filtered::iterator const& eventMC, MyMCTrackNoSkimmed const& tracksMC) + // void processMCNoSkimmedMore(aod::McCollisions::iterator const& eventMC, MyMCTrackNoSkimmed const& tracksMC) + { + runMCFillMore(eventMC, tracksMC); + } + + // void processMCNoSkimmedMore(MyMCTrackNoSkimmed const& tracksMC, aod::McCollisions const& eventsMC) + // { + // runMCGenTrackMore(tracksMC, eventsMC); + // } + void processDataNoSkimmed(soa::Filtered::iterator const& event, MyBarrelTracksNoSkimmed const& tracks, aod::McParticles const& tracksMC) { runDataFill(event, tracks, tracksMC, false); } + // void processDataNoSkimmed(MyBarrelTracksNoSkimmed const& tracks, aod::McParticles const& tracksMC) + // { + // runRecTrack(tracks, tracksMC, true, false); + // // runDataFill(event, tracks, tracksMC, false); + // } + + void processDataNoSkimmedMore(soa::Filtered const& events, aod::McCollisions const& eventsMC, MyBarrelTracksNoSkimmed const& tracks, aod::McParticles const& tracksMC, aod::AmbiguousTracks const& ambiTracksMid) + { + runDataFillMore(events, eventsMC, tracks, tracksMC, ambiTracksMid); + } + + // void processDataNoSkimmedMore(MyBarrelTracksNoSkimmed const& tracks, aod::McParticles const& tracksMC, aod::AmbiguousTracks const& ambiTracksMid, MyEventsNoSkimmed const& events, aod::McCollisions const& eventsMC) + // { + // runRecTrackMore(events, eventsMC, tracks, tracksMC, ambiTracksMid); + // } + void processDummy(MyEvents&) { // do nothing @@ -936,7 +1358,9 @@ struct AnalysisTrackSelection { PROCESS_SWITCH(AnalysisTrackSelection, processDataSelectionNoSkimmed, "Run barrel track selection without skimming", false); PROCESS_SWITCH(AnalysisTrackSelection, processMCNoSkimmed, "Run the barrel MC track filling without skimming", false); + PROCESS_SWITCH(AnalysisTrackSelection, processMCNoSkimmedMore, "Run the barrel MC track filling without skimming", false); PROCESS_SWITCH(AnalysisTrackSelection, processDataNoSkimmed, "Run the barrel data track filling without skimming", false); + PROCESS_SWITCH(AnalysisTrackSelection, processDataNoSkimmedMore, "Run the barrel data track filling without skimming", false); PROCESS_SWITCH(AnalysisTrackSelection, processSkimmed, "Run the data and mc barrel data track selection and filling on DQ skimmed tracks", false); PROCESS_SWITCH(AnalysisTrackSelection, processDataSkimmed, "Run the barrel data track selection and filling on DQ skimmed tracks", false); PROCESS_SWITCH(AnalysisTrackSelection, processMCSkimmed, "Run the barrel mc track filling on DQ skimmed tracks", false); @@ -956,6 +1380,10 @@ struct AnalysisSameEventPairing { // Partition mcSkimmedElectrons = nabs(o2::aod::mcparticle::pdgCode) == 11; // Partition mcNotSkimmedElectrons = nabs(o2::aod::mcparticle::pdgCode) == 11; + float mMagField = 0.0; + o2::parameters::GRPMagField* grpmag = nullptr; + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + Configurable fConfigTrackCuts{"cfgTrackCuts", "", "Comma separated list of barrel track cuts"}; Configurable fConfigMCSignals{"cfgBarrelMCSignals", "", "Comma separated list of MC signals"}; Configurable fConfigMinPt{"cfgMinPtFidCut", 0., "Fiducial min Pt for MC signal"}; @@ -965,13 +1393,23 @@ struct AnalysisSameEventPairing { Configurable fConfigRecWithMC{"cfgEffRecWithMCVars", false, "If true, fill also 3D histograms at reconstructed level with mc variables"}; Configurable fConfigFillLS{"cfgEffFillLS", false, "If true, fill LS histograms"}; Configurable fConfigIsPrimary{"cfgIsPrimary", false, "If true, fill only with primary particles"}; + Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigAddSEPHistogram{"cfgAddSEPHistogram", "", "Comma separated list of histograms"}; + Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable fUseRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; + Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + + Service ccdb; // 2D histos: mee and ptee ConfigurableAxis pteeBins{"pteeBins", {100, 0.f, 10.f}, "Ptee binning"}; ConfigurableAxis meeBins{"meeBins", {600, 0.f, 3.5f}, "Mee binning"}; // output lists + OutputObj fOutputQA{"DielectronQA"}; HistogramRegistry registry{"HistoSameEventSelection", {}, OutputObjHandlingPolicy::AnalysisObject}; + THashList* fQADielectronList; // QA in case on with histo from manager outputs // Cuts and signals std::vector fTrackCuts; // list of track cuts to init properly the histos @@ -983,10 +1421,21 @@ struct AnalysisSameEventPairing { std::vector> fHistRecPair; std::vector> fHistRecPairMC; - // QA: to be defined + // QA + HistogramManager* fHistManQA; // histo manager void init(o2::framework::InitContext&) { + fCurrentRun = 0; + + ccdb->setURL(ccdburl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + // Create list output for QA + fQADielectronList = new THashList; + fQADielectronList->SetOwner(kTRUE); + fQADielectronList->SetName("DEQA"); // Binning 2D histos AxisSpec axisPtee{pteeBins, "#it{p}_{T,ee} (GeV/#it{c})"}; @@ -1054,6 +1503,39 @@ struct AnalysisSameEventPairing { } } } + + // Configure QA histogram classes + if (fConfigQA) { + std::vector names; + TString histClassesQA = ""; + for (auto& cut : fTrackCuts) { + + // All passing dileptons + names = { + Form("PairsBarrelSEPM_%s", cut.GetName()), + Form("PairsBarrelSEPP_%s", cut.GetName()), + Form("PairsBarrelSEMM_%s", cut.GetName())}; + histClassesQA += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); + + // All reconstructed dileptons matched to a MC signal + std::vector mcnamesreco; + for (unsigned int isig = 0; isig < fMCSignals.size(); ++isig) { + names = { + Form("PairsBarrelSEPM_%s_%s", cut.GetName(), fMCSignals.at(isig).GetName()), + Form("PairsBarrelSEPP_%s_%s", cut.GetName(), fMCSignals.at(isig).GetName()), + Form("PairsBarrelSEMM_%s_%s", cut.GetName(), fMCSignals.at(isig).GetName())}; + histClassesQA += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); + } + } + + fHistManQA = new HistogramManager("DielectronQA", "aa", VarManager::kNVars); + fHistManQA->SetUseDefaultVariableNames(kTRUE); + fHistManQA->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + DefineHistograms(fHistManQA, histClassesQA.Data(), fConfigAddSEPHistogram); // define all histograms + VarManager::SetUseVars(fHistManQA->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fQADielectronList = fHistManQA->GetMainHistogramList(); + } + fOutputQA.setObject(fQADielectronList); } PresliceUnsorted perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; @@ -1269,8 +1751,30 @@ struct AnalysisSameEventPairing { recfidcut = kFALSE; // + VarManager::ResetValues(0, VarManager::kNPairVariables); VarManager::FillPair(t1, t2); + // Fill the QA for all passing tracks + if (fConfigQA) { + for (unsigned int j = 0; j < fTrackCuts.size(); j++) { + if (twoTrackFilter & (uint8_t(1) << j)) { + if (!fConfigFillLS) { + fHistManQA->FillHistClass(Form("PairsBarrelSEPM_%s", fTrackCuts.at(j).GetName()), VarManager::fgValues); + } else { + if (uls) { + fHistManQA->FillHistClass(Form("PairsBarrelSEPM_%s", fTrackCuts.at(j).GetName()), VarManager::fgValues); + } else { + if (t1.sign() > 0) { + fHistManQA->FillHistClass(Form("PairsBarrelSEPP_%s", fTrackCuts.at(j).GetName()), VarManager::fgValues); + } else { + fHistManQA->FillHistClass(Form("PairsBarrelSEMM_%s", fTrackCuts.at(j).GetName()), VarManager::fgValues); + } + } + } + } + } + } + // run MC matching for this pair uint32_t mcDecision = 0; int isig = 0; @@ -1311,11 +1815,22 @@ struct AnalysisSameEventPairing { if (twoTrackFilter & (uint8_t(1) << j)) { if (!fConfigFillLS) { fHistRecPair[j * fMCSignals.size() + i]->Fill(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt]); + if (fConfigQA) + fHistManQA->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fTrackCuts.at(j).GetName(), fMCSignals.at(i).GetName()), VarManager::fgValues); } else { if (uls) { fHistRecPair[j * (2 * fMCSignals.size()) + 2 * i]->Fill(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt]); + if (fConfigQA) + fHistManQA->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fTrackCuts.at(j).GetName(), fMCSignals.at(i).GetName()), VarManager::fgValues); } else { fHistRecPair[j * (2 * fMCSignals.size()) + 2 * i + 1]->Fill(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt]); + if (fConfigQA) { + if (t1.sign() > 0) { + fHistManQA->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fTrackCuts.at(j).GetName(), fMCSignals.at(i).GetName()), VarManager::fgValues); + } else { + fHistManQA->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fTrackCuts.at(j).GetName(), fMCSignals.at(i).GetName()), VarManager::fgValues); + } + } } } } @@ -1379,6 +1894,21 @@ struct AnalysisSameEventPairing { soa::Filtered const& tracks, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) { + if (events.size() > 0 && fCurrentRun != events.begin().runNumber()) { + if (fUseRemoteField.value) { + grpmag = ccdb->getForTimeStamp(grpmagPath, events.begin().timestamp()); + if (grpmag != nullptr) { + mMagField = grpmag->getNominalL3Field(); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", events.begin().timestamp()); + } + VarManager::SetMagneticField(mMagField); + } else { + VarManager::SetMagneticField(fConfigMagField.value); + } + fCurrentRun = events.begin().runNumber(); + } + runPairing(events, tracks, eventsMC, tracksMC); } @@ -1386,6 +1916,22 @@ struct AnalysisSameEventPairing { soa::Filtered const& tracks, ReducedMCTracks const& tracksMC) { + + if (fCurrentRun != event.runNumber()) { + if (fUseRemoteField.value) { + grpmag = ccdb->getForTimeStamp(grpmagPath, event.timestamp()); + if (grpmag != nullptr) { + mMagField = grpmag->getNominalL3Field(); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", event.timestamp()); + } + VarManager::SetMagneticField(mMagField); + } else { + VarManager::SetMagneticField(fConfigMagField.value); + } + fCurrentRun = event.runNumber(); + } + runDataPairing(event, tracks, tracksMC); } @@ -1400,9 +1946,26 @@ struct AnalysisSameEventPairing { } void processDataToEENoSkimmed(soa::Filtered::iterator const& event, + aod::BCsWithTimestamps const&, soa::Filtered const& tracks, aod::McParticles const& tracksMC) { + auto bc = event.template bc_as(); + if (fCurrentRun != bc.runNumber()) { + if (fUseRemoteField.value) { + grpmag = ccdb->getForTimeStamp(grpmagPath, bc.timestamp()); + if (grpmag != nullptr) { + mMagField = grpmag->getNominalL3Field(); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", bc.timestamp()); + } + VarManager::SetMagneticField(mMagField); + } else { + VarManager::SetMagneticField(fConfigMagField.value); + } + fCurrentRun = bc.runNumber(); + } + runDataPairing(event, tracks, tracksMC); } @@ -1440,7 +2003,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses) +void DefineHistograms(HistogramManager* histMan, TString histClasses, Configurable configVar) { // // Define here the histograms for all the classes required in analysis. @@ -1452,22 +2015,21 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses) TString classStr = objArray->At(iclass)->GetName(); histMan->AddHistClass(classStr.Data()); + TString histName = configVar.value; // NOTE: The level of detail for histogramming can be controlled via configurables if (classStr.Contains("Event")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "event", "trigger,mc"); + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "event", histName); } - if (classStr.Contains("Track")) { + if (classStr.Contains("Track") && !classStr.Contains("Pairs")) { if (classStr.Contains("Barrel")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "kine,its,tpcpid,dca,tofpid,mc"); + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); } } if (classStr.Contains("Pairs")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair_barrel", "vertexing-barrel"); - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair_dimuon", "vertexing-forward"); + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", histName); } - if (classStr.Contains("MCTruthGenPair")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_pair"); histMan->AddHistogram(objArray->At(iclass)->GetName(), "Pt", "MC generator p_{T} distribution", false, 200, 0.0, 20.0, VarManager::kMCPt); @@ -1475,10 +2037,10 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses) histMan->AddHistogram(objArray->At(iclass)->GetName(), "Phi", "MC generator #varphi distribution", false, 500, -6.3, 6.3, VarManager::kMCPhi); } if (classStr.Contains("MCTruthGen")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth"); + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_track"); } if (classStr.Contains("DileptonsSelected")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair_barrel"); } - } -} // end loop over histogram classes + } // end loop over histogram classes +} diff --git a/PWGEM/Dilepton/Tasks/eventQC.cxx b/PWGEM/Dilepton/Tasks/eventQC.cxx new file mode 100644 index 00000000000..4a3ac116cd5 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/eventQC.cxx @@ -0,0 +1,1066 @@ +// 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. +// +// ======================== +// +// This code is for event QC for PWG-EM. +// Please write to: daiki.sekihata@cern.ch + +#include +#include +#include +#include +#include + +#include "TString.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Common/Core/RecoDecay.h" +#include "MathUtils/Utils.h" +#include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "CCDB/BasicCCDBManager.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +using MyBCs = soa::Join; +using MyQvectors = soa::Join; + +using MyCollisions = soa::Join; +using MyCollisions_Qvec = soa::Join; + +using MyTracks = soa::Join; +using MyTrack = MyTracks::iterator; + +struct eventQC { + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + Configurable cfgFillEvent{"cfgFillEvent", false, "fill event histograms"}; + Configurable cfgFillTrack{"cfgFillTrack", false, "fill track histograms"}; + Configurable cfgFillPID{"cfgFillPID", false, "fill PID histograms"}; + Configurable cfgFillPIDITS{"cfgFillPIDITS", false, "fill PID ITS histograms"}; + Configurable> cfgnMods{"cfgnMods", {2, 3}, "Modulation of interest. Please keep increasing order"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgQvecEstimator{"cfgQvecEstimator", 0, "FT0M:0, FT0A:1, FT0C:2, BTot:3, BPos:4, BNeg:5"}; + Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + ConfigurableAxis ConfPtBins{"ConfPtBins", {VARIABLE_WIDTH, 0.00, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.50, 3.00, 3.50, 4.00, 4.50, 5.00, 6.00, 7.00, 8.00, 9.00, 10.00}, "pT bins for output histograms"}; + Configurable cfgNbinsEta{"cfgNbinsEta", 20, "number of eta bins for output histograms"}; + Configurable cfgNbinsPhi{"cfgNbinsPhi", 36, "number of phi bins for output histograms"}; + + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", true, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", true, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. track occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. track occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInTimeRangeStrict{"cfgRequireNoCollInTimeRangeStrict", false, "require no collision in time range strict"}; + Configurable cfgRequirekNoCollInRofStandard{"cfgRequirekNoCollInRofStandard", false, "require no other collisions in this Readout Frame with per-collision multiplicity above threshold"}; + Configurable cfgRequirekNoCollInRofStrict{"cfgRequirekNoCollInRofStrict", false, "require no other collisions in this Readout Frame"}; + Configurable cfgRequirekNoHighMultCollInPrevRof{"cfgRequirekNoHighMultCollInPrevRof", false, "require no HM collision in previous ITS ROF"}; + Configurable cfgRequireGoodITSLayer3{"cfgRequireGoodITSLayer3", false, "number of inactive chips on ITS layer 3 are below threshold "}; + Configurable cfgRequireGoodITSLayer0123{"cfgRequireGoodITSLayer0123", false, "number of inactive chips on ITS layers 0-3 are below threshold "}; + Configurable cfgRequireGoodITSLayersAll{"cfgRequireGoodITSLayersAll", false, "number of inactive chips on all ITS layers are below threshold "}; + } eventcuts; + + struct : ConfigurableGroup { + std::string prefix = "trackcut_group"; + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.15, "min pT for single track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -0.9, "min eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", +0.9, "max eta for single track"}; + Configurable cfg_min_cr2findable_ratio_tpc{"cfg_min_cr2findable_ratio_tpc", 0.8, "min. TPC Ncr/Nf ratio"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_min_ncrossedrows_tpc{"cfg_min_ncrossedrows_tpc", 80, "min ncrossed rows"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncluster_itsib{"cfg_min_ncluster_itsib", 1, "min ncluster itsib"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_chi2tof{"cfg_max_chi2tof", 1e+10, "max chi2/NclsTOF"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 0.2, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 0.2, "max dca Z for single track in cm"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -1e+10, "min n sigma e in TPC"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +1e+10, "max n sigma e in TPC"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", 0.0, "min n sigma pi in TPC for exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", 0.0, "max n sigma pi in TPC for exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -1e+10, "min n sigma e in TOF"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +1e+10, "max n sigma e in TOF"}; + Configurable cfg_requireTOF{"cfg_requireTOF", false, "require TOF hit"}; + } trackcuts; + + struct : ConfigurableGroup { + std::string prefix = "v0cut_group"; + Configurable cfg_min_mass_photon{"cfg_min_mass_photon", 0.0, "min mass for photon rejection"}; + Configurable cfg_max_mass_photon{"cfg_max_mass_photon", 0.1, "max mass for photon rejection"}; + Configurable cfg_min_mass_k0s{"cfg_min_mass_k0s", 0.490, "min mass for K0S"}; + Configurable cfg_max_mass_k0s{"cfg_max_mass_k0s", 0.505, "max mass for K0S"}; + Configurable cfg_min_mass_lambda{"cfg_min_mass_lambda", 1.11, "min mass for Lambda rejection"}; + Configurable cfg_max_mass_lambda{"cfg_max_mass_lambda", 1.12, "max mass for Lambda rejection"}; + Configurable cfg_min_cospa_v0hadron{"cfg_min_cospa_v0hadron", 0.999, "min cospa for v0hadron"}; + Configurable cfg_max_pca_v0hadron{"cfg_max_pca_v0hadron", 0.5, "max distance between 2 legs for v0hadron"}; + Configurable cfg_min_radius_v0hadron{"cfg_min_radius_v0hadron", 1.0, "min rxy for v0hadron"}; + Configurable cfg_max_kfchi2{"cfg_max_kfchi2", 1e+10, "max kfchi2 for PCM"}; + Configurable cfg_min_cr2findable_ratio_tpc{"cfg_min_cr2findable_ratio_tpc", 0.8, "min. TPC Ncr/Nf ratio"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_min_ncrossedrows_tpc{"cfg_min_ncrossedrows_tpc", 40, "min ncrossed rows"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_chi2tof{"cfg_max_chi2tof", 1.0, "max chi2 for TOF"}; + Configurable cfg_min_dcaxy_v0leg{"cfg_min_dcaxy_v0leg", 0.1, "min dca XY for v0 legs in cm"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -4, "min n sigma e in TPC"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +4, "max n sigma e in TPC"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -4, "min n sigma pi in TPC"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +4, "max n sigma pi in TPC"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -2, "min n sigma el in TOF"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +2, "max n sigma el in TOF"}; + Configurable cfg_min_TOFNsigmaPi{"cfg_min_TOFNsigmaPi", -2, "min n sigma pi in TOF"}; + Configurable cfg_max_TOFNsigmaPi{"cfg_max_TOFNsigmaPi", +2, "max n sigma pi in TOF"}; + } v0cuts; + + Service ccdb; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view event_types[2] = {"before/", "after/"}; + + void init(InitContext&) + { + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + addhistograms(); + if (doprocessEventQC_V0_PID) { + addV0histograms(); + } + } + + ~eventQC() {} + + void addhistograms() + { + // event info + + const int nbin_ev = 20; + auto hCollisionCounter = fRegistry.add("Event/before/hCollisionCounter", "collision counter;;Number of events", kTH1F, {{nbin_ev, 0.5, nbin_ev + 0.5}}, false); + hCollisionCounter->GetXaxis()->SetBinLabel(1, "all"); + hCollisionCounter->GetXaxis()->SetBinLabel(2, "FT0AND"); + hCollisionCounter->GetXaxis()->SetBinLabel(3, "No TF border"); + hCollisionCounter->GetXaxis()->SetBinLabel(4, "No ITS ROF border"); + hCollisionCounter->GetXaxis()->SetBinLabel(5, "No Same Bunch Pileup"); + hCollisionCounter->GetXaxis()->SetBinLabel(6, "Is Good Zvtx FT0vsPV"); + hCollisionCounter->GetXaxis()->SetBinLabel(7, "Is Vertex ITS-TPC"); + hCollisionCounter->GetXaxis()->SetBinLabel(8, "Is Vertex ITS-TPC-TRD"); + hCollisionCounter->GetXaxis()->SetBinLabel(9, "Is Vertex ITS-TPC-TOF"); + hCollisionCounter->GetXaxis()->SetBinLabel(10, "sel8"); + hCollisionCounter->GetXaxis()->SetBinLabel(11, "|Z_{vtx}| < 10 cm"); + hCollisionCounter->GetXaxis()->SetBinLabel(12, "NoCollInTimeRangeStandard"); + hCollisionCounter->GetXaxis()->SetBinLabel(13, "NoCollInTimeRangeStrict"); + hCollisionCounter->GetXaxis()->SetBinLabel(14, "NoCollInRofStandard"); + hCollisionCounter->GetXaxis()->SetBinLabel(15, "NoCollInRofStrict"); + hCollisionCounter->GetXaxis()->SetBinLabel(16, "NoHighMultCollInPrevRof"); + hCollisionCounter->GetXaxis()->SetBinLabel(17, "GoodITSLayer3"); + hCollisionCounter->GetXaxis()->SetBinLabel(18, "GoodITSLayer0123"); + hCollisionCounter->GetXaxis()->SetBinLabel(19, "GoodITSLayersAll"); + hCollisionCounter->GetXaxis()->SetBinLabel(nbin_ev, "accepted"); + + if (cfgFillEvent) { + fRegistry.add("Event/before/hZvtx", "vertex z; Z_{vtx} (cm)", kTH1F, {{100, -50, +50}}, false); + fRegistry.add("Event/before/hMultNTracksPV", "hMultNTracksPV; N_{track} to PV", kTH1F, {{6001, -0.5, 6000.5}}, false); + fRegistry.add("Event/before/hMultNTracksPVeta1", "hMultNTracksPVeta1; N_{track} to PV", kTH1F, {{6001, -0.5, 6000.5}}, false); + fRegistry.add("Event/before/hMultFT0", "hMultFT0;mult. FT0A;mult. FT0C", kTH2F, {{200, 0, 200000}, {60, 0, 60000}}, false); + fRegistry.add("Event/before/hCentFT0A", "hCentFT0A;centrality FT0A (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry.add("Event/before/hCentFT0C", "hCentFT0C;centrality FT0C (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry.add("Event/before/hCentFT0M", "hCentFT0M;centrality FT0M (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry.add("Event/before/hCentFT0CvsMultNTracksPV", "hCentFT0CvsMultNTracksPV;centrality FT0C (%);N_{track} to PV", kTH2F, {{100, 0, 100}, {600, 0, 6000}}, false); + fRegistry.add("Event/before/hMultFT0CvsMultNTracksPV", "hMultFT0CvsMultNTracksPV;mult. FT0C;N_{track} to PV", kTH2F, {{60, 0, 60000}, {600, 0, 6000}}, false); + fRegistry.add("Event/before/hMultFT0CvsOccupancy", "hMultFT0CvsOccupancy;mult. FT0C;N_{track} in time range", kTH2F, {{60, 0, 60000}, {200, 0, 20000}}, false); + fRegistry.add("Event/before/hNTracksPVvsOccupancy", "hNTracksPVvsOccupancy;N_{track} to PV;N_{track} in time range", kTH2F, {{600, 0, 6000}, {200, 0, 20000}}, false); + fRegistry.add("Event/before/hNGlobalTracksvsOccupancy", "hNGlobalTracksvsOccupancy;N_{track}^{global};N_{track} in time range", kTH2F, {{600, 0, 6000}, {200, 0, 20000}}, false); + fRegistry.add("Event/before/hNGlobalTracksPVvsOccupancy", "hNGlobalTracksPVvsOccupancy;N_{track}^{global} to PV;N_{track} in time range", kTH2F, {{600, 0, 6000}, {200, 0, 20000}}, false); + fRegistry.add("Event/before/hCorrOccupancy", "occupancy correlation;FT0C occupancy;track-based occupancy", kTH2F, {{200, 0, 200000}, {200, 0, 20000}}, false); + } + fRegistry.addClone("Event/before/", "Event/after/"); + + if (cfgFillEvent) { + fRegistry.add("Event/after/hMultNGlobalTracks", "hMultNGlobalTracks; N_{track}^{global}", kTH1F, {{6001, -0.5, 6000.5}}, false); + fRegistry.add("Event/after/hCentFT0CvsMultNGlobalTracks", "hCentFT0CvsMultNGlobalTracks;centrality FT0C (%);N_{track}^{global}", kTH2F, {{100, 0, 100}, {600, 0, 6000}}, false); + fRegistry.add("Event/after/hMultFT0CvsMultNGlobalTracks", "hMultFT0CvsMultNGlobalTracks;mult. FT0C;N_{track}^{global}", kTH2F, {{60, 0, 60000}, {600, 0, 6000}}, false); + fRegistry.add("Event/after/hMultNGlobalTracksPV", "hMultNGlobalTracksPV; N_{track}^{global} to PV", kTH1F, {{6001, -0.5, 6000.5}}, false); + fRegistry.add("Event/after/hCentFT0CvsMultNGlobalTracksPV", "hCentFT0CvsMultNGlobalTracksPV;centrality FT0C (%);N_{track}^{global} to PV", kTH2F, {{100, 0, 100}, {600, 0, 6000}}, false); + fRegistry.add("Event/after/hMultFT0CvsMultNGlobalTracksPV", "hMultFT0CvsMultNGlobalTracksPV;mult. FT0C;N_{track}^{global} to PV", kTH2F, {{60, 0, 60000}, {600, 0, 6000}}, false); + } + + std::vector tmp_ptbins; + for (int i = 0; i < 100; i++) { + tmp_ptbins.emplace_back(0.01 * i); // every 0.01 GeV/c from 0 to 1 GeV/c + } + for (int i = 0; i < 91; i++) { + tmp_ptbins.emplace_back(0.1 * i + 1.f); // every 0.1 GeV/c from 1 to 10 GeV/c + } + const AxisSpec axis_pt_tmp{tmp_ptbins, "p_{T} (GeV/c)"}; + + const AxisSpec axis_pt{ConfPtBins, "p_{T} (GeV/c)"}; + const AxisSpec axis_eta{cfgNbinsEta, -1.0, +1.0, "#eta"}; + const AxisSpec axis_phi{cfgNbinsPhi, 0.0, 2 * M_PI, "#varphi (rad.)"}; + const AxisSpec axis_sign{3, -1.5, +1.5, "sign"}; + const AxisSpec axis_cent{20, 0, 100, "centrality FT0C (%)"}; + + if (doprocessEventQC_Cent_Qvec) { + for (int i = 0; i < static_cast(cfgnMods->size()); i++) { + int nmod = cfgnMods->at(i); + fRegistry.add(Form("Event/after/Qvector/hQ%dxFT0M_CentFT0C", nmod), Form("hQ%dxFT0M_CentFT0C;centrality FT0C (%%);Q_{%d,x}^{FT0M}", nmod, nmod), kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry.add(Form("Event/after/Qvector/hQ%dyFT0M_CentFT0C", nmod), Form("hQ%dyFT0M_CentFT0C;centrality FT0C (%%);Q_{%d,y}^{FT0M}", nmod, nmod), kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry.add(Form("Event/after/Qvector/hQ%dxFT0A_CentFT0C", nmod), Form("hQ%dxFT0A_CentFT0C;centrality FT0C (%%);Q_{%d,x}^{FT0A}", nmod, nmod), kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry.add(Form("Event/after/Qvector/hQ%dyFT0A_CentFT0C", nmod), Form("hQ%dyFT0A_CentFT0C;centrality FT0C (%%);Q_{%d,y}^{FT0A}", nmod, nmod), kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry.add(Form("Event/after/Qvector/hQ%dxFT0C_CentFT0C", nmod), Form("hQ%dxFT0C_CentFT0C;centrality FT0C (%%);Q_{%d,x}^{FT0C}", nmod, nmod), kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry.add(Form("Event/after/Qvector/hQ%dyFT0C_CentFT0C", nmod), Form("hQ%dyFT0C_CentFT0C;centrality FT0C (%%);Q_{%d,y}^{FT0C}", nmod, nmod), kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry.add(Form("Event/after/Qvector/hQ%dxBPos_CentFT0C", nmod), Form("hQ%dxBPos_CentFT0C;centrality FT0C (%%);Q_{%d,x}^{BPos}", nmod, nmod), kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry.add(Form("Event/after/Qvector/hQ%dyBPos_CentFT0C", nmod), Form("hQ%dyBPos_CentFT0C;centrality FT0C (%%);Q_{%d,y}^{BPos}", nmod, nmod), kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry.add(Form("Event/after/Qvector/hQ%dxBNeg_CentFT0C", nmod), Form("hQ%dxBNeg_CentFT0C;centrality FT0C (%%);Q_{%d,x}^{BNeg}", nmod, nmod), kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry.add(Form("Event/after/Qvector/hQ%dyBNeg_CentFT0C", nmod), Form("hQ%dyBNeg_CentFT0C;centrality FT0C (%%);Q_{%d,y}^{BNeg}", nmod, nmod), kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry.add(Form("Event/after/Qvector/hQ%dxBTot_CentFT0C", nmod), Form("hQ%dxBTot_CentFT0C;centrality FT0C (%%);Q_{%d,x}^{BTot}", nmod, nmod), kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry.add(Form("Event/after/Qvector/hQ%dyBTot_CentFT0C", nmod), Form("hQ%dyBTot_CentFT0C;centrality FT0C (%%);Q_{%d,y}^{BTot}", nmod, nmod), kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + + fRegistry.add(Form("Event/after/Qvector/hPrfQ%dFT0MQ%dBPos_CentFT0C", nmod, nmod), Form("Q_{%d}^{FT0M} #upoint Q_{%d}^{BPos};centrality FT0C (%%);Q_{%d}^{FT0M} #upoint Q_{%d}^{BPos}", nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfQ%dFT0MQ%dBNeg_CentFT0C", nmod, nmod), Form("Q_{%d}^{FT0M} #upoint Q_{%d}^{BNeg};centrality FT0C (%%);Q_{%d}^{FT0M} #upoint Q_{%d}^{BNeg}", nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfQ%dBPosQ%dBNeg_CentFT0C", nmod, nmod), Form("Q_{%d}^{BPos} #upoint Q_{%d}^{BNeg};centrality FT0C (%%);Q_{%d}^{BPos} #upoint Q_{%d}^{BNeg}", nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfQ%dFT0CQ%dBPos_CentFT0C", nmod, nmod), Form("Q_{%d}^{FT0C} #upoint Q_{%d}^{BPos};centrality FT0C (%%);Q_{%d}^{FT0C} #upoint Q_{%d}^{BPos}", nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfQ%dFT0CQ%dBNeg_CentFT0C", nmod, nmod), Form("Q_{%d}^{FT0C} #upoint Q_{%d}^{BNeg};centrality FT0C (%%);Q_{%d}^{FT0C} #upoint Q_{%d}^{BNeg}", nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfQ%dFT0CQ%dBTot_CentFT0C", nmod, nmod), Form("Q_{%d}^{FT0C} #upoint Q_{%d}^{BTot};centrality FT0C (%%);Q_{%d}^{FT0C} #upoint Q_{%d}^{BTot}", nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfQ%dFT0AQ%dBPos_CentFT0C", nmod, nmod), Form("Q_{%d}^{FT0A} #upoint Q_{%d}^{BPos};centrality FT0C (%%);Q_{%d}^{FT0A} #upoint Q_{%d}^{BPos}", nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfQ%dFT0AQ%dBNeg_CentFT0C", nmod, nmod), Form("Q_{%d}^{FT0A} #upoint Q_{%d}^{BNeg};centrality FT0C (%%);Q_{%d}^{FT0A} #upoint Q_{%d}^{BNeg}", nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfQ%dFT0AQ%dBTot_CentFT0C", nmod, nmod), Form("Q_{%d}^{FT0A} #upoint Q_{%d}^{BTot};centrality FT0C (%%);Q_{%d}^{FT0A} #upoint Q_{%d}^{BTot}", nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfQ%dFT0AQ%dFT0C_CentFT0C", nmod, nmod), Form("Q_{%d}^{FT0A} #upoint Q_{%d}^{FT0C};centrality FT0C (%%);Q_{%d}^{FT0A} #upoint Q_{%d}^{FT0C}", nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + + fRegistry.add(Form("Event/after/Qvector/hEP%dFT0M_CentFT0C", nmod), Form("event plane FT0M;centrality FT0C (%%);#Psi_{%d}^{FT0M} (rad.)", nmod), kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + fRegistry.add(Form("Event/after/Qvector/hEP%dFT0A_CentFT0C", nmod), Form("event plane FT0A;centrality FT0C (%%);#Psi_{%d}^{FT0A} (rad.)", nmod), kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + fRegistry.add(Form("Event/after/Qvector/hEP%dFT0C_CentFT0C", nmod), Form("event plane FT0C;centrality FT0C (%%);#Psi_{%d}^{FT0C} (rad.)", nmod), kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + fRegistry.add(Form("Event/after/Qvector/hEP%dBPos_CentFT0C", nmod), Form("event plane BPos;centrality FT0C (%%);#Psi_{%d}^{BPos} (rad.)", nmod), kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + fRegistry.add(Form("Event/after/Qvector/hEP%dBNeg_CentFT0C", nmod), Form("event plane BNeg;centrality FT0C (%%);#Psi_{%d}^{BNeg} (rad.)", nmod), kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + fRegistry.add(Form("Event/after/Qvector/hEP%dBTot_CentFT0C", nmod), Form("event plane BTot;centrality FT0C (%%);#Psi_{%d}^{BTot} (rad.)", nmod), kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + + fRegistry.add(Form("Event/after/Qvector/hPrfCosDiffEP%dFT0MEP%dBPos_CentFT0C", nmod, nmod), Form("cos(%d(#Psi_{%d}^{FT0M} - #Psi_{%d}^{BPos}));centrality FT0C (%%);cos(%d(#Psi_{%d}^{FT0M} - #Psi_{%d}^{BPos}))", nmod, nmod, nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfCosDiffEP%dFT0MEP%dBNeg_CentFT0C", nmod, nmod), Form("cos(%d(#Psi_{%d}^{FT0M} - #Psi_{%d}^{BNeg}));centrality FT0C (%%);cos(%d(#Psi_{%d}^{FT0M} - #Psi_{%d}^{BNeg}))", nmod, nmod, nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfCosDiffEP%dBPosEP%dBNeg_CentFT0C", nmod, nmod), Form("cos(%d(#Psi_{%d}^{BPos} - #Psi_{%d}^{BNeg}));centrality FT0C (%%);cos(%d(#Psi_{%d}^{BPos} - #Psi_{%d}^{BNeg}))", nmod, nmod, nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfCosDiffEP%dFT0CEP%dBPos_CentFT0C", nmod, nmod), Form("cos(%d(#Psi_{%d}^{FT0C} - #Psi_{%d}^{BPos}));centrality FT0C (%%);cos(%d(#Psi_{%d}^{FT0C} - #Psi_{%d}^{BPos}))", nmod, nmod, nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfCosDiffEP%dFT0CEP%dBNeg_CentFT0C", nmod, nmod), Form("cos(%d(#Psi_{%d}^{FT0C} - #Psi_{%d}^{BNeg}));centrality FT0C (%%);cos(%d(#Psi_{%d}^{FT0C} - #Psi_{%d}^{BNeg}))", nmod, nmod, nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfCosDiffEP%dFT0CEP%dBTot_CentFT0C", nmod, nmod), Form("cos(%d(#Psi_{%d}^{FT0C} - #Psi_{%d}^{BTot}));centrality FT0C (%%);cos(%d(#Psi_{%d}^{FT0C} - #Psi_{%d}^{BTot}))", nmod, nmod, nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfCosDiffEP%dFT0AEP%dBPos_CentFT0C", nmod, nmod), Form("cos(%d(#Psi_{%d}^{FT0A} - #Psi_{%d}^{BPos}));centrality FT0C (%%);cos(%d(#Psi_{%d}^{FT0A} - #Psi_{%d}^{BPos}))", nmod, nmod, nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfCosDiffEP%dFT0AEP%dBNeg_CentFT0C", nmod, nmod), Form("cos(%d(#Psi_{%d}^{FT0A} - #Psi_{%d}^{BNeg}));centrality FT0C (%%);cos(%d(#Psi_{%d}^{FT0A} - #Psi_{%d}^{BNeg}))", nmod, nmod, nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfCosDiffEP%dFT0AEP%dBTot_CentFT0C", nmod, nmod), Form("cos(%d(#Psi_{%d}^{FT0A} - #Psi_{%d}^{BTot}));centrality FT0C (%%);cos(%d(#Psi_{%d}^{FT0A} - #Psi_{%d}^{BTot}))", nmod, nmod, nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + fRegistry.add(Form("Event/after/Qvector/hPrfCosDiffEP%dFT0AEP%dFT0C_CentFT0C", nmod, nmod), Form("cos(%d(#Psi_{%d}^{FT0A} - #Psi_{%d}^{FT0C}));centrality FT0C (%%);cos(%d(#Psi_{%d}^{FT0A} - #Psi_{%d}^{FT0C}))", nmod, nmod, nmod, nmod, nmod, nmod), kTProfile, {{100, 0, 100}}, false); + } + + for (int i = 0; i < static_cast(cfgnMods->size()); i++) { + int nmod = cfgnMods->at(i); + const AxisSpec axis_sp{100, -5, +5, Form("#vec{u_{%d}} #upoint #vec{Q_{%d}}", nmod, nmod)}; + const AxisSpec axis_cos{200, -1, +1, Form("cos(%d(#varphi - #Psi_{%d}))", nmod, nmod)}; + fRegistry.add(Form("Track/hV%d", nmod), Form("charged particle v_{%d}", nmod), kTHnSparseD, {axis_cent, axis_pt, axis_sp, axis_cos}, false); + } + } + + if (cfgFillTrack) { + fRegistry.add("Track/hs", "rec. single electron", kTHnSparseD, {axis_pt, axis_eta, axis_phi, axis_sign}, false); + fRegistry.add("Track/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{1000, -50, 50}}, false); + fRegistry.add("Track/hRelSigma1Pt", "relative p_{T} resolution;p_{T} (GeV/c);#sigma_{1/p_{T}} #times p_{T}", kTH2F, {axis_pt_tmp, {100, 0, 0.1}}, false); + fRegistry.add("Track/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -1.0f, 1.0f}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("Track/hDCAxyzSigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {axis_pt_tmp, {500, 0., 500}}, false); + fRegistry.add("Track/hDCAzRes_Pt", "DCA_{z} resolution vs. pT;p_{T} (GeV/c);DCA_{z} resolution (#mum)", kTH2F, {axis_pt_tmp, {500, 0., 500}}, false); + fRegistry.add("Track/hNclsTPC", "number of TPC clusters", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hNcrTPC", "number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hDeltaPin", "p_{in} vs. p_{pv};p_{pv} (GeV/c);(p_{in} - p_{pv})/p_{pv}", kTH2F, {{1000, 0, 10}, {200, -1, +1}}, false); + fRegistry.add("Track/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hTPCNclsShared", "TPC Ncls shared/Ncls;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); + fRegistry.add("Track/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("Track/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("Track/hChi2TOF", "chi2 of TOF", kTH2F, {{1000, 0, 10}, {100, 0, 10}}, false); + } + + if (cfgFillPID) { + fRegistry.add("Track/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("Track/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5.f, +5.f}}, false); + fRegistry.add("Track/hTPCNsigmaMu", "TPC n sigma mu;p_{in} (GeV/c);n #sigma_{#mu}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5.f, +5.f}}, false); + fRegistry.add("Track/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5.f, +5.f}}, false); + fRegistry.add("Track/hTPCNsigmaKa", "TPC n sigma ka;p_{in} (GeV/c);n #sigma_{K}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5.f, +5.f}}, false); + fRegistry.add("Track/hTPCNsigmaPr", "TPC n sigma pr;p_{in} (GeV/c);n #sigma_{p}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5.f, +5.f}}, false); + if (doprocessEventQC_V0_PID) { + fRegistry.add("Track/hsEID", "TPC n sigma el;p_{in} (GeV/c);#eta;n #sigma_{e}^{TPC};", kTHnSparseF, {{200, 0, 10}, {20, -1, +1}, {100, -5, +5}}, false); + } + fRegistry.add("Track/hTOFbeta", "TOF #beta;p_{pv} (GeV/c);#beta", kTH2F, {{1000, 0, 10}, {240, 0, 1.2}}, false); + fRegistry.add("Track/hTOFNsigmaEl", "TOF n sigma el;p_{pv} (GeV/c);n #sigma_{e}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaMu", "TOF n sigma mu;p_{pv} (GeV/c);n #sigma_{#mu}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaPi", "TOF n sigma pi;p_{pv} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaKa", "TOF n sigma ka;p_{pv} (GeV/c);n #sigma_{K}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaPr", "TOF n sigma pr;p_{pv} (GeV/c);n #sigma_{p}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + + if (cfgFillPIDITS) { + fRegistry.add("Track/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); on ITS #times cos(#lambda);", kTH2F, {{1000, 0.f, 10.f}, {150, 0, 15}}, false); + fRegistry.add("Track/hITSNsigmaEl", "ITS n sigma el;p_{pv} (GeV/c);n #sigma_{e}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hITSNsigmaMu", "ITS n sigma mu;p_{pv} (GeV/c);n #sigma_{#mu}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hITSNsigmaPi", "ITS n sigma pi;p_{pv} (GeV/c);n #sigma_{#pi}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hITSNsigmaKa", "ITS n sigma ka;p_{pv} (GeV/c);n #sigma_{K}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hITSNsigmaPr", "ITS n sigma pr;p_{pv} (GeV/c);n #sigma_{p}^{ITS}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + } + } + } + + void addV0histograms() + { + fRegistry.add("V0/hAP", "AP plot", kTH2F, {{200, -1, +1}, {250, 0, 0.25}}, false); + fRegistry.add("V0/hPCA", "distance between 2 legs", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("V0/hCosPA", "cos pointing angle", kTH1F, {{100, 0.99, 1}}, false); + fRegistry.add("V0/hRadius", "radius", kTH1F, {{200, 0, 20}}, false); + fRegistry.add("V0/K0S/pion/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("V0/K0S/pion/hsEID", "TPC n sigma el;p_{in} (GeV/c);#eta;n #sigma_{e}^{TPC};", kTHnSparseF, {{200, 0, 10}, {20, -1, +1}, {100, -5, +5}}, false); + + fRegistry.add("V0/K0S/hMass", "mass vs. p_{T} of K^{0}_{S}", kTH2F, {{200, 0.4, 0.6}, {100, 0, 10}}, false); + fRegistry.add("V0/Lambda/hMass", "mass vs. p_{T} of #Lambda", kTH2F, {{100, 1.08, 1.18}, {100, 0, 10}}, false); + fRegistry.add("V0/AntiLambda/hMass", "mass vs. p_{T} of #bar{#Lambda}", kTH2F, {{100, 1.08, 1.18}, {100, 0, 10}}, false); + fRegistry.add("V0/GammaTMP/hMass", "mass vs. p_{T} of #gamma", kTH2F, {{100, 0.0, 0.1}, {100, 0, 10}}, false); + + fRegistry.add("V0/Photon/hMass", "mass vs. p_{T}", kTH2F, {{100, 0, 0.1}, {100, 0, 10}}, false); + fRegistry.add("V0/Photon/hChi2", "radius vs. KF chi2", kTH2F, {{100, 0, 100}, {100, 0, 100}}, false); + fRegistry.add("V0/Photon/hXY", "photon conversion point;X (cm);Y(cm)", kTH2F, {{400, -100, +100}, {400, -100, 100}}, false); + fRegistry.add("V0/Photon/electron/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("V0/Photon/electron/hsEID", "TPC n sigma el;p_{in} (GeV/c);#eta;n #sigma_{e}^{TPC};", kTHnSparseF, {{200, 0, 10}, {20, -1, +1}, {100, -5, +5}}, false); + } + + template + void fillTrackInfo(TTrack const& track) + { + if (cfgFillTrack) { + fRegistry.fill(HIST("Track/hs"), track.pt(), track.eta(), track.phi(), track.sign()); + fRegistry.fill(HIST("Track/hQoverPt"), track.signed1Pt()); + fRegistry.fill(HIST("Track/hRelSigma1Pt"), track.pt(), track.sigma1Pt() * track.pt()); + fRegistry.fill(HIST("Track/hDCAxyz"), track.dcaXY(), track.dcaZ()); + fRegistry.fill(HIST("Track/hDCAxyzSigma"), track.dcaXY() / std::sqrt(track.cYY()), track.dcaZ() / std::sqrt(track.cZZ())); + fRegistry.fill(HIST("Track/hDCAxyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hDCAzRes_Pt"), track.pt(), std::sqrt(track.cZZ()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hNclsITS"), track.itsNCls()); + fRegistry.fill(HIST("Track/hNclsTPC"), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("Track/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("Track/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("Track/hTPCNclsShared"), track.pt(), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("Track/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("Track/hDeltaPin"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + fRegistry.fill(HIST("Track/hChi2ITS"), track.itsChi2NCl()); + fRegistry.fill(HIST("Track/hITSClusterMap"), track.itsClusterMap()); + fRegistry.fill(HIST("Track/hChi2TOF"), track.p(), track.tofChi2()); + } + if (cfgFillPID) { + fRegistry.fill(HIST("Track/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/hTPCNsigmaMu"), track.tpcInnerParam(), track.tpcNSigmaMu()); + fRegistry.fill(HIST("Track/hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); + fRegistry.fill(HIST("Track/hTPCNsigmaKa"), track.tpcInnerParam(), track.tpcNSigmaKa()); + fRegistry.fill(HIST("Track/hTPCNsigmaPr"), track.tpcInnerParam(), track.tpcNSigmaPr()); + + fRegistry.fill(HIST("Track/hTOFbeta"), track.p(), track.beta()); + fRegistry.fill(HIST("Track/hTOFNsigmaEl"), track.p(), track.tofNSigmaEl()); + fRegistry.fill(HIST("Track/hTOFNsigmaMu"), track.p(), track.tofNSigmaMu()); + fRegistry.fill(HIST("Track/hTOFNsigmaPi"), track.p(), track.tofNSigmaPi()); + fRegistry.fill(HIST("Track/hTOFNsigmaKa"), track.p(), track.tofNSigmaKa()); + fRegistry.fill(HIST("Track/hTOFNsigmaPr"), track.p(), track.tofNSigmaPr()); + + if (cfgFillPIDITS) { + int nsize = 0; + for (int il = 0; il < 7; il++) { + nsize += track.itsClsSizeInLayer(il); + } + fRegistry.fill(HIST("Track/hMeanClusterSizeITS"), track.p(), static_cast(nsize) / static_cast(track.itsNCls()) * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/hITSNsigmaEl"), track.p(), track.itsNSigmaEl()); + fRegistry.fill(HIST("Track/hITSNsigmaMu"), track.p(), track.itsNSigmaMu()); + fRegistry.fill(HIST("Track/hITSNsigmaPi"), track.p(), track.itsNSigmaPi()); + fRegistry.fill(HIST("Track/hITSNsigmaKa"), track.p(), track.itsNSigmaKa()); + fRegistry.fill(HIST("Track/hITSNsigmaPr"), track.p(), track.itsNSigmaPr()); + } + } + if (doprocessEventQC_V0_PID) { + fRegistry.fill(HIST("Track/hsEID"), track.tpcInnerParam(), track.eta(), track.tpcNSigmaEl()); + } + } + + template + void fillEventInfo(TCollision const& collision) + { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 1.0); + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 2.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 3.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 4.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 5.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 6.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 7.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 8.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 9.0); + } + if (collision.sel8()) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 10.0); + } + if (std::fabs(collision.posZ()) < 10.0) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 11.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 12.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 13.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 14.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 15.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 16.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer3)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 17.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 18.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 19.0); + } + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hZvtx"), collision.posZ()); + + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultNTracksPV"), collision.multNTracksPV()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultNTracksPVeta1"), collision.multNTracksPVeta1()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0"), collision.multFT0A(), collision.multFT0C()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0CvsMultNTracksPV"), collision.multFT0C(), collision.multNTracksPV()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0CvsOccupancy"), collision.multFT0C(), collision.trackOccupancyInTimeRange()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hNTracksPVvsOccupancy"), collision.multNTracksPV(), collision.trackOccupancyInTimeRange()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCorrOccupancy"), collision.ft0cOccupancyInTimeRange(), collision.trackOccupancyInTimeRange()); + + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0A"), collision.centFT0A()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0C"), collision.centFT0C()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0M"), collision.centFT0M()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0CvsMultNTracksPV"), collision.centFT0C(), collision.multNTracksPV()); + + if constexpr (ev_id == 1 && std::is_same_v, FilteredMyCollision_Qvec>) { + if (std::find(cfgnMods->begin(), cfgnMods->end(), 2) != cfgnMods->end()) { + fillQvectorInfo(collision); + } + if (std::find(cfgnMods->begin(), cfgnMods->end(), 3) != cfgnMods->end()) { + fillQvectorInfo(collision); + } + if (std::find(cfgnMods->begin(), cfgnMods->end(), 4) != cfgnMods->end()) { + fillQvectorInfo(collision); + } + } + } + + template + void fillQvectorInfo(TCollision const& collision) + { + int idx = std::distance(cfgnMods->begin(), std::find(cfgnMods->begin(), cfgnMods->end(), nmod)); + float qxft0m = collision.qvecFT0MReVec()[idx], qxft0a = collision.qvecFT0AReVec()[idx], qxft0c = collision.qvecFT0CReVec()[idx], qxbpos = collision.qvecBPosReVec()[idx], qxbneg = collision.qvecBNegReVec()[idx], qxbtot = collision.qvecBTotReVec()[idx]; + float qyft0m = collision.qvecFT0MImVec()[idx], qyft0a = collision.qvecFT0AImVec()[idx], qyft0c = collision.qvecFT0CImVec()[idx], qybpos = collision.qvecBPosImVec()[idx], qybneg = collision.qvecBNegImVec()[idx], qybtot = collision.qvecBTotImVec()[idx]; + std::array qft0m = {qxft0m, qyft0m}; + std::array qft0a = {qxft0a, qyft0a}; + std::array qft0c = {qxft0c, qyft0c}; + std::array qbpos = {qxbpos, qybpos}; + std::array qbneg = {qxbneg, qybneg}; + std::array qbtot = {qxbtot, qybtot}; + std::vector> qvectors = {qft0m, qft0a, qft0c, qbpos, qbneg, qbtot}; + + if (!isGoodQvector(qvectors)) { + return; + } + + if constexpr (nmod == 2) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ2xFT0M_CentFT0C"), collision.centFT0C(), qxft0m); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ2yFT0M_CentFT0C"), collision.centFT0C(), qyft0m); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ2xFT0A_CentFT0C"), collision.centFT0C(), qxft0a); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ2yFT0A_CentFT0C"), collision.centFT0C(), qyft0a); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ2xFT0C_CentFT0C"), collision.centFT0C(), qxft0c); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ2yFT0C_CentFT0C"), collision.centFT0C(), qyft0c); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ2xBPos_CentFT0C"), collision.centFT0C(), qxbpos); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ2yBPos_CentFT0C"), collision.centFT0C(), qybpos); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ2xBNeg_CentFT0C"), collision.centFT0C(), qxbneg); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ2yBNeg_CentFT0C"), collision.centFT0C(), qybneg); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ2xBTot_CentFT0C"), collision.centFT0C(), qxbtot); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ2yBTot_CentFT0C"), collision.centFT0C(), qybtot); + + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ2FT0MQ2BPos_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0m, qbpos)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ2FT0MQ2BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0m, qbneg)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ2BPosQ2BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qbpos, qbneg)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ2FT0AQ2BPos_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0a, qbpos)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ2FT0AQ2BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0a, qbneg)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ2FT0AQ2BTot_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0a, qbtot)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ2FT0CQ2BPos_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0c, qbpos)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ2FT0CQ2BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0c, qbneg)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ2FT0CQ2BTot_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0c, qbtot)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ2FT0AQ2FT0C_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0a, qft0c)); + + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hEP2FT0M_CentFT0C"), collision.centFT0C(), getEP(qxft0m, qyft0m, nmod)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hEP2FT0A_CentFT0C"), collision.centFT0C(), getEP(qxft0a, qyft0a, nmod)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hEP2FT0C_CentFT0C"), collision.centFT0C(), getEP(qxft0c, qyft0c, nmod)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hEP2BPos_CentFT0C"), collision.centFT0C(), getEP(qxbpos, qybpos, nmod)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hEP2BNeg_CentFT0C"), collision.centFT0C(), getEP(qxbneg, qybneg, nmod)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hEP2BTot_CentFT0C"), collision.centFT0C(), getEP(qxbtot, qybtot, nmod)); + + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP2FT0MEP2BPos_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0m, qyft0m, nmod) - getEP(qxbpos, qybpos, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP2FT0MEP2BNeg_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0m, qyft0m, nmod) - getEP(qxbneg, qybneg, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP2BPosEP2BNeg_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxbpos, qybpos, nmod) - getEP(qxbneg, qybneg, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP2FT0AEP2BPos_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0a, qyft0a, nmod) - getEP(qxbpos, qybpos, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP2FT0AEP2BNeg_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0a, qyft0a, nmod) - getEP(qxbneg, qybneg, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP2FT0AEP2BTot_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0a, qyft0a, nmod) - getEP(qxbtot, qybtot, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP2FT0CEP2BPos_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0c, qyft0c, nmod) - getEP(qxbpos, qybpos, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP2FT0CEP2BNeg_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0c, qyft0c, nmod) - getEP(qxbneg, qybneg, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP2FT0CEP2BTot_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0c, qyft0c, nmod) - getEP(qxbtot, qybtot, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP2FT0AEP2FT0C_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0a, qyft0a, nmod) - getEP(qxft0c, qyft0c, nmod)))); + } else if constexpr (nmod == 3) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ3xFT0M_CentFT0C"), collision.centFT0C(), qxft0m); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ3yFT0M_CentFT0C"), collision.centFT0C(), qyft0m); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ3xFT0A_CentFT0C"), collision.centFT0C(), qxft0a); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ3yFT0A_CentFT0C"), collision.centFT0C(), qyft0a); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ3xFT0C_CentFT0C"), collision.centFT0C(), qxft0c); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ3yFT0C_CentFT0C"), collision.centFT0C(), qyft0c); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ3xBPos_CentFT0C"), collision.centFT0C(), qxbpos); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ3yBPos_CentFT0C"), collision.centFT0C(), qybpos); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ3xBNeg_CentFT0C"), collision.centFT0C(), qxbneg); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ3yBNeg_CentFT0C"), collision.centFT0C(), qybneg); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ3xBTot_CentFT0C"), collision.centFT0C(), qxbtot); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hQ3yBTot_CentFT0C"), collision.centFT0C(), qybtot); + + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ3FT0MQ3BPos_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0m, qbpos)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ3FT0MQ3BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0m, qbneg)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ3BPosQ3BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qbpos, qbneg)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ3FT0AQ3BPos_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0a, qbpos)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ3FT0AQ3BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0a, qbneg)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ3FT0AQ3BTot_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0a, qbtot)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ3FT0CQ3BPos_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0c, qbpos)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ3FT0CQ3BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0c, qbneg)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ3FT0CQ3BTot_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0c, qbtot)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfQ3FT0AQ3FT0C_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(qft0a, qft0c)); + + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hEP3FT0M_CentFT0C"), collision.centFT0C(), getEP(qxft0m, qyft0m, nmod)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hEP3FT0A_CentFT0C"), collision.centFT0C(), getEP(qxft0a, qyft0a, nmod)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hEP3FT0C_CentFT0C"), collision.centFT0C(), getEP(qxft0c, qyft0c, nmod)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hEP3BPos_CentFT0C"), collision.centFT0C(), getEP(qxbpos, qybpos, nmod)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hEP3BNeg_CentFT0C"), collision.centFT0C(), getEP(qxbneg, qybneg, nmod)); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hEP3BTot_CentFT0C"), collision.centFT0C(), getEP(qxbtot, qybtot, nmod)); + + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP3FT0MEP3BPos_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0m, qyft0m, nmod) - getEP(qxbpos, qybpos, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP3FT0MEP3BNeg_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0m, qyft0m, nmod) - getEP(qxbneg, qybneg, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP3BPosEP3BNeg_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxbpos, qybpos, nmod) - getEP(qxbneg, qybneg, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP3FT0AEP3BPos_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0a, qyft0a, nmod) - getEP(qxbpos, qybpos, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP3FT0AEP3BNeg_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0a, qyft0a, nmod) - getEP(qxbneg, qybneg, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP3FT0AEP3BTot_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0a, qyft0a, nmod) - getEP(qxbtot, qybtot, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP3FT0CEP3BPos_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0c, qyft0c, nmod) - getEP(qxbpos, qybpos, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP3FT0CEP3BNeg_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0c, qyft0c, nmod) - getEP(qxbneg, qybneg, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP3FT0CEP3BTot_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0c, qyft0c, nmod) - getEP(qxbtot, qybtot, nmod)))); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("Qvector/hPrfCosDiffEP3FT0AEP3FT0C_CentFT0C"), collision.centFT0C(), std::cos(nmod * (getEP(qxft0a, qyft0a, nmod) - getEP(qxft0c, qyft0c, nmod)))); + } + } + + template + void fillVn(TCollision const& collision, TTrack const& track) + { + int idx = std::distance(cfgnMods->begin(), std::find(cfgnMods->begin(), cfgnMods->end(), nmod)); + float qxft0m = collision.qvecFT0MReVec()[idx], qxft0a = collision.qvecFT0AReVec()[idx], qxft0c = collision.qvecFT0CReVec()[idx], qxbpos = collision.qvecBPosReVec()[idx], qxbneg = collision.qvecBNegReVec()[idx], qxbtot = collision.qvecBTotReVec()[idx]; + float qyft0m = collision.qvecFT0MImVec()[idx], qyft0a = collision.qvecFT0AImVec()[idx], qyft0c = collision.qvecFT0CImVec()[idx], qybpos = collision.qvecBPosImVec()[idx], qybneg = collision.qvecBNegImVec()[idx], qybtot = collision.qvecBTotImVec()[idx]; + std::array qft0m = {qxft0m, qyft0m}; + std::array qft0a = {qxft0a, qyft0a}; + std::array qft0c = {qxft0c, qyft0c}; + std::array qbpos = {qxbpos, qybpos}; + std::array qbneg = {qxbneg, qybneg}; + std::array qbtot = {qxbtot, qybtot}; + std::vector> qvectors = {qft0m, qft0a, qft0c, qbpos, qbneg, qbtot}; + + if (!isGoodQvector(qvectors)) { + return; + } + + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + + float sp = RecoDecay::dotProd(std::array{static_cast(std::cos(nmod * track.phi())), static_cast(std::sin(nmod * track.phi()))}, qvectors[cfgQvecEstimator]); + float cos = std::cos(nmod * (track.phi() - getEP(qvectors[cfgQvecEstimator][0], qvectors[cfgQvecEstimator][1], nmod))); + if constexpr (nmod == 2) { + fRegistry.fill(HIST("Track/hV2"), centralities[cfgCentEstimator], track.pt(), sp, cos); + } else if constexpr (nmod == 3) { + fRegistry.fill(HIST("Track/hV3"), centralities[cfgCentEstimator], track.pt(), sp, cos); + } + } + + float getEP(float qx, float qy, int nmod) + { + return std::atan2(qy, qx) / static_cast(nmod); + } + + template + bool isGoodQvector(TQvectors const& qvectors) + { + bool is_good = true; + for (auto& qvec : qvectors) { + if (std::fabs(qvec[0]) > 20.f || std::fabs(qvec[1]) > 20.f) { + is_good = false; + break; + } + } + return is_good; + } + + template + bool isSelectedTrack(TTrack const& track) + { + if (!track.hasITS() || !track.hasTPC()) { + return false; + } + + if (track.pt() < trackcuts.cfg_min_pt_track || trackcuts.cfg_max_pt_track < track.pt()) { + return false; + } + + if (track.eta() < trackcuts.cfg_min_eta_track || trackcuts.cfg_max_eta_track < track.eta()) { + return false; + } + + if (std::fabs(track.dcaXY()) > trackcuts.cfg_max_dcaxy) { + return false; + } + + if (std::fabs(track.dcaZ()) > trackcuts.cfg_max_dcaz) { + return false; + } + + if (track.itsChi2NCl() > trackcuts.cfg_max_chi2its) { + return false; + } + + if (track.itsNCls() < trackcuts.cfg_min_ncluster_its) { + return false; + } + + if (track.itsNClsInnerBarrel() < trackcuts.cfg_min_ncluster_itsib) { + return false; + } + + if (track.tpcChi2NCl() > trackcuts.cfg_max_chi2tpc) { + return false; + } + + if (track.tpcNClsFound() < trackcuts.cfg_min_ncluster_tpc) { + return false; + } + + if (track.tpcNClsCrossedRows() < trackcuts.cfg_min_ncrossedrows_tpc) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < trackcuts.cfg_min_cr2findable_ratio_tpc) { + return false; + } + + if (track.tpcFractionSharedCls() > trackcuts.cfg_max_frac_shared_clusters_tpc) { + return false; + } + + return true; + } + + template + bool isElectron(TTrack const& track) + { + if (track.tpcNSigmaEl() < trackcuts.cfg_min_TPCNsigmaEl || trackcuts.cfg_max_TPCNsigmaEl < track.tpcNSigmaEl()) { + return false; + } + + if (trackcuts.cfg_min_TPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < trackcuts.cfg_max_TPCNsigmaPi) { + return false; + } + + if (trackcuts.cfg_requireTOF && !(track.hasTOF() && track.tofChi2() < trackcuts.cfg_max_chi2tof)) { + return false; + } + + if (track.hasTOF() && ((track.tofNSigmaEl() < trackcuts.cfg_min_TOFNsigmaEl || trackcuts.cfg_max_TOFNsigmaEl < track.tofNSigmaEl()) || trackcuts.cfg_max_chi2tof < track.tofChi2())) { + return false; + } + + return true; + } + + template + bool isSelectedV0Leg(TTrack const& track) + { + if (!track.hasTPC()) { + return false; + } + + if (track.hasITS() && track.itsChi2NCl() > v0cuts.cfg_max_chi2its) { + return false; + } + + if (track.tpcChi2NCl() > v0cuts.cfg_max_chi2tpc) { + return false; + } + + if (track.tpcNClsFound() < v0cuts.cfg_min_ncluster_tpc) { + return false; + } + + if (track.tpcNClsCrossedRows() < v0cuts.cfg_min_ncrossedrows_tpc) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < v0cuts.cfg_min_cr2findable_ratio_tpc) { + return false; + } + + if (track.tpcFractionSharedCls() > v0cuts.cfg_max_frac_shared_clusters_tpc) { + return false; + } + + return true; + } + + template + bool isSelectedEvent(TCollision const& collision) + { + if (eventcuts.cfgRequireSel8 && !collision.sel8()) { + return false; + } + + if (collision.posZ() < eventcuts.cfgZvtxMin || eventcuts.cfgZvtxMax < collision.posZ()) { + return false; + } + + if (eventcuts.cfgRequireFT0AND && !collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + return false; + } + + if (eventcuts.cfgRequireNoTFB && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + + if (eventcuts.cfgRequireNoITSROFB && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + + if (eventcuts.cfgRequireNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + + if (eventcuts.cfgRequireGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + + if (eventcuts.cfgRequireNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + + if (eventcuts.cfgRequireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + + if (eventcuts.cfgRequirekNoCollInRofStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + + if (eventcuts.cfgRequirekNoCollInRofStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } + + if (eventcuts.cfgRequirekNoHighMultCollInPrevRof && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + return false; + } + + if (eventcuts.cfgRequireGoodITSLayer3 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer3)) { + return false; + } + + if (eventcuts.cfgRequireGoodITSLayer0123 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)) { + return false; + } + + if (eventcuts.cfgRequireGoodITSLayersAll && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return false; + } + + if (!(eventcuts.cfgTrackOccupancyMin <= collision.trackOccupancyInTimeRange() && collision.trackOccupancyInTimeRange() < eventcuts.cfgTrackOccupancyMax)) { + return false; + } + + if (!(eventcuts.cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange() && collision.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) { + return false; + } + + return true; + } + + Filter collisionFilter_evsel = o2::aod::evsel::sel8 == true && (eventcuts.cfgZvtxMin < o2::aod::collision::posZ && o2::aod::collision::posZ < eventcuts.cfgZvtxMax); + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + Filter collisionFilter_track_occupancy = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_ft0c_occupancy = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + using FilteredMyCollisions = soa::Filtered; + using FilteredMyCollisions_Qvec = soa::Filtered; + + using FilteredMyCollision = FilteredMyCollisions::iterator; + using FilteredMyCollision_Qvec = FilteredMyCollisions_Qvec::iterator; + + Filter trackFilter = (trackcuts.cfg_min_pt_track < o2::aod::track::pt && o2::aod::track::pt < trackcuts.cfg_max_pt_track) && (trackcuts.cfg_min_eta_track < o2::aod::track::eta && o2::aod::track::eta < trackcuts.cfg_max_eta_track) && nabs(o2::aod::track::dcaXY) < trackcuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < trackcuts.cfg_max_dcaz && o2::aod::track::tpcChi2NCl < trackcuts.cfg_max_chi2tpc && o2::aod::track::itsChi2NCl < trackcuts.cfg_max_chi2its && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true; + using FilteredMyTracks = soa::Filtered; + + SliceCache cache; + Preslice perCol = o2::aod::track::collisionId; + Preslice perCol_pcm = o2::aod::v0photonkf::collisionId; + Preslice perCol_v0 = o2::aod::v0data::collisionId; + Preslice perCol_casc = o2::aod::cascdata::collisionId; + + template + void runQC(TCollisions const& collisions, TTracks const& tracks, TV0Photons const& v0photons, TV0Legs const&, TV0StrHadrons const& v0strhadrons) + { + for (auto& collision : collisions) { + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + if (cfgFillEvent) { + fillEventInfo<0>(collision); + } + if (!isSelectedEvent(collision)) { + continue; + } + if (cfgFillEvent) { + fillEventInfo<1>(collision); + } + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 20); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 20); // accepted + + int nGlobalTracks = 0, nGlobalTracksPV = 0; + auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); + for (auto& track : tracks_per_coll) { + if (!isSelectedTrack(track)) { + continue; + } + if (isElectron(track)) { + fillTrackInfo(track); + } + if (std::fabs(track.eta()) < 0.8) { + nGlobalTracks++; + + if constexpr (std::is_same_v, FilteredMyCollisions_Qvec>) { + for (int i = 0; i < static_cast(cfgnMods->size()); i++) { + if (cfgnMods->at(i) == 2) { + fillVn<2>(collision, track); + } else if (cfgnMods->at(i) == 3) { + fillVn<3>(collision, track); + } + } + } + + if (track.isPVContributor()) { + nGlobalTracksPV++; + } + } + } // end of track loop + + if (cfgFillEvent) { + fRegistry.fill(HIST("Event/after/hMultNGlobalTracks"), nGlobalTracks); + fRegistry.fill(HIST("Event/after/hMultNGlobalTracksPV"), nGlobalTracksPV); + fRegistry.fill(HIST("Event/after/hMultFT0CvsMultNGlobalTracks"), collision.multFT0C(), nGlobalTracks); + fRegistry.fill(HIST("Event/after/hMultFT0CvsMultNGlobalTracksPV"), collision.multFT0C(), nGlobalTracksPV); + fRegistry.fill(HIST("Event/after/hNGlobalTracksvsOccupancy"), nGlobalTracks, collision.trackOccupancyInTimeRange()); + fRegistry.fill(HIST("Event/after/hNGlobalTracksPVvsOccupancy"), nGlobalTracksPV, collision.trackOccupancyInTimeRange()); + fRegistry.fill(HIST("Event/after/hCentFT0CvsMultNGlobalTracks"), collision.centFT0C(), nGlobalTracks); + fRegistry.fill(HIST("Event/after/hCentFT0CvsMultNGlobalTracksPV"), collision.centFT0C(), nGlobalTracksPV); + } + + // for V0 PID + if constexpr (doV0s) { + auto v0hadrons_per_coll = v0strhadrons.sliceBy(perCol_v0, collision.globalIndex()); + for (auto& v0hadron : v0hadrons_per_coll) { + if (v0hadron.dcaV0daughters() > v0cuts.cfg_max_pca_v0hadron || v0hadron.v0cosPA() < v0cuts.cfg_min_cospa_v0hadron || v0hadron.v0radius() < v0cuts.cfg_min_radius_v0hadron) { + continue; + } + + fRegistry.fill(HIST("V0/hAP"), v0hadron.alpha(), v0hadron.qtarm()); + fRegistry.fill(HIST("V0/hPCA"), v0hadron.dcaV0daughters()); + fRegistry.fill(HIST("V0/hCosPA"), v0hadron.v0cosPA()); + fRegistry.fill(HIST("V0/hRadius"), v0hadron.v0radius()); + + fRegistry.fill(HIST("V0/K0S/hMass"), v0hadron.mK0Short(), v0hadron.pt()); + if (v0cuts.cfg_min_mass_k0s < v0hadron.mK0Short() && v0hadron.mK0Short() < v0cuts.cfg_max_mass_k0s) { // K0S + fRegistry.fill(HIST("V0/GammaTMP/hMass"), v0hadron.mGamma(), v0hadron.pt()); + fRegistry.fill(HIST("V0/Lambda/hMass"), v0hadron.mLambda(), v0hadron.pt()); + fRegistry.fill(HIST("V0/AntiLambda/hMass"), v0hadron.mAntiLambda(), v0hadron.pt()); + if (v0cuts.cfg_min_mass_lambda < v0hadron.mLambda() && v0hadron.mLambda() < v0cuts.cfg_max_mass_lambda) { // Lambda rejection + continue; + } + if (v0cuts.cfg_min_mass_lambda < v0hadron.mAntiLambda() && v0hadron.mAntiLambda() < v0cuts.cfg_max_mass_lambda) { // AntiLambda rejection + continue; + } + if (v0cuts.cfg_min_mass_photon < v0hadron.mGamma() && v0hadron.mGamma() < v0cuts.cfg_max_mass_photon) { // photon conversion rejection + continue; + } + + auto pos = tracks.rawIteratorAt(v0hadron.posTrackId()); + auto neg = tracks.rawIteratorAt(v0hadron.negTrackId()); + if (!isSelectedV0Leg(pos) || !isSelectedV0Leg(neg)) { + continue; + } + if (!pos.hasITS() || !neg.hasITS()) { + continue; + } + if (std::fabs(pos.dcaXY()) < v0cuts.cfg_min_dcaxy_v0leg || std::fabs(neg.dcaXY()) < v0cuts.cfg_min_dcaxy_v0leg) { + continue; + } + + // if (pos.tpcNSigmaPi() < v0cuts.cfg_min_TPCNsigmaPi || v0cuts.cfg_max_TPCNsigmaPi < pos.tpcNSigmaPi()) { + // continue; + // } + // if (neg.tpcNSigmaPi() < v0cuts.cfg_min_TPCNsigmaPi || v0cuts.cfg_max_TPCNsigmaPi < neg.tpcNSigmaPi()) { + // continue; + // } + + bool isTPCOK_pos = pos.hasTPC() && v0cuts.cfg_min_TPCNsigmaPi < pos.tpcNSigmaPi() && pos.tpcNSigmaPi() < v0cuts.cfg_max_TPCNsigmaPi; + bool isTPCOK_neg = neg.hasTPC() && v0cuts.cfg_min_TPCNsigmaPi < neg.tpcNSigmaPi() && neg.tpcNSigmaPi() < v0cuts.cfg_max_TPCNsigmaPi; + bool isTOFOK_pos = pos.hasTOF() && pos.tofChi2() < v0cuts.cfg_max_chi2tof && v0cuts.cfg_min_TOFNsigmaPi < pos.tofNSigmaPi() && pos.tofNSigmaPi() < v0cuts.cfg_max_TOFNsigmaPi; + bool isTOFOK_neg = neg.hasTOF() && neg.tofChi2() < v0cuts.cfg_max_chi2tof && v0cuts.cfg_min_TOFNsigmaPi < neg.tofNSigmaPi() && neg.tofNSigmaPi() < v0cuts.cfg_max_TOFNsigmaPi; + + if (isTPCOK_neg && isTOFOK_neg) { // K0S is tagged by neg and pos is probe. + fRegistry.fill(HIST("V0/K0S/pion/hTPCdEdx"), pos.tpcInnerParam(), pos.tpcSignal()); + fRegistry.fill(HIST("V0/K0S/pion/hsEID"), pos.tpcInnerParam(), pos.eta(), pos.tpcNSigmaEl()); + } + if (isTPCOK_pos && isTOFOK_pos) { // K0S is tagged by pos and neg is probe. + fRegistry.fill(HIST("V0/K0S/pion/hTPCdEdx"), neg.tpcInnerParam(), neg.tpcSignal()); + fRegistry.fill(HIST("V0/K0S/pion/hsEID"), neg.tpcInnerParam(), neg.eta(), neg.tpcNSigmaEl()); + } + } // end of K0S + } // end of v0hadron loop + + auto v0photons_per_coll = v0photons.sliceBy(perCol_pcm, collision.globalIndex()); + for (auto& v0photon : v0photons_per_coll) { + if (v0photon.chiSquareNDF() > v0cuts.cfg_max_kfchi2) { + continue; + } + + fRegistry.fill(HIST("V0/Photon/hMass"), v0photon.mGamma(), v0photon.pt()); + fRegistry.fill(HIST("V0/Photon/hXY"), v0photon.vx(), v0photon.vy()); + fRegistry.fill(HIST("V0/Photon/hChi2"), v0photon.v0radius(), v0photon.chiSquareNDF()); + auto pos_v0leg = v0photon.template posTrack_as(); + auto neg_v0leg = v0photon.template negTrack_as(); + auto pos = tracks.rawIteratorAt(pos_v0leg.trackId()); + auto neg = tracks.rawIteratorAt(neg_v0leg.trackId()); + + if (!isSelectedV0Leg(pos) || !isSelectedV0Leg(neg)) { + continue; + } + if (std::fabs(pos.dcaXY()) < v0cuts.cfg_min_dcaxy_v0leg || std::fabs(neg.dcaXY()) < v0cuts.cfg_min_dcaxy_v0leg) { + continue; + } + + // if (pos.tpcNSigmaEl() < v0cuts.cfg_min_TPCNsigmaEl || v0cuts.cfg_max_TPCNsigmaEl < pos.tpcNSigmaEl()) { + // continue; + // } + // if (neg.tpcNSigmaEl() < v0cuts.cfg_min_TPCNsigmaEl || v0cuts.cfg_max_TPCNsigmaEl < neg.tpcNSigmaEl()) { + // continue; + // } + + bool isTPCOK_pos = pos.hasTPC() && v0cuts.cfg_min_TPCNsigmaEl < pos.tpcNSigmaEl() && pos.tpcNSigmaEl() < v0cuts.cfg_max_TPCNsigmaEl; + bool isTPCOK_neg = neg.hasTPC() && v0cuts.cfg_min_TPCNsigmaEl < neg.tpcNSigmaEl() && neg.tpcNSigmaEl() < v0cuts.cfg_max_TPCNsigmaEl; + bool isTOFOK_pos = pos.hasTOF() && pos.tofChi2() < v0cuts.cfg_max_chi2tof && v0cuts.cfg_min_TOFNsigmaEl < pos.tofNSigmaEl() && pos.tofNSigmaEl() < v0cuts.cfg_max_TOFNsigmaEl; + bool isTOFOK_neg = neg.hasTOF() && neg.tofChi2() < v0cuts.cfg_max_chi2tof && v0cuts.cfg_min_TOFNsigmaEl < neg.tofNSigmaEl() && neg.tofNSigmaEl() < v0cuts.cfg_max_TOFNsigmaEl; + + if (isTPCOK_neg && isTOFOK_neg) { // photon conversion is tagged by neg and pos is probe. + fRegistry.fill(HIST("V0/Photon/electron/hTPCdEdx"), pos.tpcInnerParam(), pos.tpcSignal()); + fRegistry.fill(HIST("V0/Photon/electron/hsEID"), pos.tpcInnerParam(), pos.eta(), pos.tpcNSigmaEl()); + } + if (isTPCOK_pos && isTOFOK_pos) { // photon conversion is tagged by pos and neg is probe. + fRegistry.fill(HIST("V0/Photon/electron/hTPCdEdx"), neg.tpcInnerParam(), neg.tpcSignal()); + fRegistry.fill(HIST("V0/Photon/electron/hsEID"), neg.tpcInnerParam(), neg.eta(), neg.tpcNSigmaEl()); + } + } // end of v0photon loop + } // end of V0 PID + } // end of collision loop + } // end of process + + void processEventQC(FilteredMyCollisions const& collisions, FilteredMyTracks const& tracks) + { + auto tracksWithITSPid = soa::Attach(tracks); + runQC(collisions, tracksWithITSPid, nullptr, nullptr, nullptr); + } + PROCESS_SWITCH(eventQC, processEventQC, "event QC", true); + + void processEventQC_Cent_Qvec(FilteredMyCollisions_Qvec const& collisions, FilteredMyTracks const& tracks) + { + auto tracksWithITSPid = soa::Attach(tracks); + runQC(collisions, tracksWithITSPid, nullptr, nullptr, nullptr); + } + PROCESS_SWITCH(eventQC, processEventQC_Cent_Qvec, "event QC + q vector", false); + + //! type of V0. 0: built solely for cascades (does not pass standard V0 cuts), 1: standard 2, 3: photon-like with TPC-only use. Regular analysis should always use type 1. + Filter v0Filter = o2::aod::v0data::v0Type == uint8_t(1) && o2::aod::v0data::v0cosPA > v0cuts.cfg_min_cospa_v0hadron.value&& o2::aod::v0data::dcaV0daughters < v0cuts.cfg_max_pca_v0hadron.value; + using filteredV0s = soa::Filtered; + + void processEventQC_V0_PID(FilteredMyCollisions const& collisions, FilteredMyTracks const& tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, filteredV0s const& v0strhadrons) + { + auto tracksWithITSPid = soa::Attach(tracks); + runQC(collisions, tracksWithITSPid, v0photons, v0legs, v0strhadrons); + } + PROCESS_SWITCH(eventQC, processEventQC_V0_PID, "event QC + V0 PID", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"event-qc"})}; +} diff --git a/PWGEM/Dilepton/Tasks/lmeeHFCocktail.cxx b/PWGEM/Dilepton/Tasks/lmeeHFCocktail.cxx new file mode 100644 index 00000000000..d26c22c409a --- /dev/null +++ b/PWGEM/Dilepton/Tasks/lmeeHFCocktail.cxx @@ -0,0 +1,512 @@ +// 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 lmeeHFCocktail.cxx +/// \analysis task for lmee heavy flavour cocktail +/// \author Daniel Samitz, , SMI Vienna +/// Elisa Meninno, , SMI Vienna + +#include + +#include "Math/Vector4D.h" +#include "MathUtils/Utils.h" +#include "Framework/Task.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::pwgem::dilepton::utils::mcutil; + +using McParticlesSmeared = soa::Join; + +enum EFromHFType { + kNoE = -1, + kNoHFE = 0, + kCE = 1, + kBE = 2, + kBCE = 3 +}; + +namespace o2::aod +{ +namespace hftable +{ +DECLARE_SOA_COLUMN(IsHF, isHF, int); +DECLARE_SOA_COLUMN(BHadronId, bHadronId, int); +DECLARE_SOA_COLUMN(CHadronId, cHadronId, int); +DECLARE_SOA_COLUMN(BQuarkId, bQuarkId, int); +DECLARE_SOA_COLUMN(CQuarkId, cQuarkId, int); +DECLARE_SOA_COLUMN(BQuarkOriginId, bQuarkOriginId, int); +DECLARE_SOA_COLUMN(CQuarkOriginId, cQuarkOriginId, int); +DECLARE_SOA_COLUMN(BQuarkRap, bQuarkRap, float); +DECLARE_SOA_COLUMN(CQuarkRap, cQuarkRap, float); +} // namespace hftable +DECLARE_SOA_TABLE(HfTable, "AOD", "HFTABLE", + hftable::IsHF, + hftable::BHadronId, + hftable::CHadronId, + hftable::BQuarkId, + hftable::CQuarkId, + hftable::BQuarkOriginId, + hftable::CQuarkOriginId, + hftable::BQuarkRap, + hftable::CQuarkRap); +} // namespace o2::aod + +const int Nstages = 3; +const char* stageNames[Nstages] = {"gen", "meas", "meas_and_acc"}; +// gen: normal weights applied. By default set to 1. +// meas: normal and efficiency weights applied. By default set to 1. +// meas_acc: normal, efficiency weights and acceptance cuts applied + +template +void doQuark(T& p, std::vector> hRapQuark, float ptMin, float etaMax, int pdg) +{ + float pt[Nstages] = {p.pt(), p.ptSmeared(), p.ptSmeared()}; + float eta[Nstages] = {p.eta(), p.etaSmeared(), p.etaSmeared()}; + float cut_pt[Nstages] = {0., 0., ptMin}; + float cut_eta[Nstages] = {9999., 99999., etaMax}; + for (int i = 0; i < Nstages; i++) { + if (pt[i] > cut_pt[i] && fabs(eta[i]) < cut_eta[i]) { + if (pdg == 4) + hRapQuark[i]->Fill(p.cQuarkRap()); + else if (pdg == 5) + hRapQuark[i]->Fill(p.bQuarkRap()); + else + hRapQuark[i]->Fill(999.); + } + } +} + +template +void doSingle(T& p, std::vector> hEta, std::vector> hPt, std::vector> hPtEta, float ptMin, float etaMax) +{ + float weight[Nstages] = {p.weight(), p.efficiency() * p.weight(), p.efficiency() * p.weight()}; + float pt[Nstages] = {p.pt(), p.ptSmeared(), p.ptSmeared()}; + float eta[Nstages] = {p.eta(), p.etaSmeared(), p.etaSmeared()}; + float cut_pt[Nstages] = {0., 0., ptMin}; + float cut_eta[Nstages] = {9999., 99999., etaMax}; + for (int i = 0; i < Nstages; i++) { + if (pt[i] > cut_pt[i] && fabs(eta[i]) < cut_eta[i]) { + hEta[i]->Fill(eta[i], weight[i]); + hPt[i]->Fill(pt[i], weight[i]); + hPtEta[i]->Fill(pt[i], eta[i], weight[i]); + } + } +} + +template +void doPair(T& p1, T& p2, std::vector> hMee, std::vector> hMeePtee, float ptMin, float etaMax, bool apply_detadphi, float min_deta, float min_dphi) +{ + + ROOT::Math::PtEtaPhiMVector v1(p1.ptSmeared(), p1.etaSmeared(), p1.phiSmeared(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(p2.ptSmeared(), p2.etaSmeared(), p2.phiSmeared(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + ROOT::Math::PtEtaPhiMVector v1_gen(p1.pt(), p1.eta(), p1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2_gen(p2.pt(), p2.eta(), p2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12_gen = v1_gen + v2_gen; + + double mass[Nstages] = {v12_gen.M(), v12.M(), v12.M()}; + double pt[Nstages] = {v12_gen.Pt(), v12.Pt(), v12.Pt()}; + float pt1[Nstages] = {p1.pt(), p1.ptSmeared(), p1.ptSmeared()}; + float pt2[Nstages] = {p2.pt(), p2.ptSmeared(), p2.ptSmeared()}; + float eta1[Nstages] = {p1.eta(), p1.etaSmeared(), p1.etaSmeared()}; + float eta2[Nstages] = {p2.eta(), p2.etaSmeared(), p2.etaSmeared()}; + float weight[Nstages] = {p1.weight() * p2.weight(), p1.efficiency() * p2.efficiency() * p1.weight() * p2.weight(), p1.efficiency() * p2.efficiency() * p1.weight() * p2.weight()}; + float cut_pt[Nstages] = {0., 0., ptMin}; + float cut_eta[Nstages] = {9999., 99999., etaMax}; + + float deta = v1.Eta() - v2.Eta(); + float dphi = v1.Phi() - v2.Phi(); + o2::math_utils::bringToPMPi(dphi); + if (apply_detadphi && std::pow(deta / min_deta, 2) + std::pow(dphi / min_dphi, 2) < 1.f) { + return; + } + + for (int i = 0; i < Nstages; i++) { + if (pt1[i] > cut_pt[i] && pt2[i] > cut_pt[i] && fabs(eta1[i]) < cut_eta[i] && fabs(eta2[i]) < cut_eta[i]) { + hMee[i]->Fill(mass[i], weight[i]); + hMeePtee[i]->Fill(mass[i], pt[i], weight[i]); + } + } +} + +struct MyConfigs : ConfigurableGroup { + Configurable fConfigPtMin{"cfgPtMin", 0.2, "min. pT of single electrons"}; + Configurable fConfigEtaMax{"cfgEtaMax", 0.8, "max. |eta| of single electrons"}; + ConfigurableAxis fConfigPtBins{"cfgPtBins", {200, 0.f, 10.f}, "single electron pT binning"}; + ConfigurableAxis fConfigEtaBins{"cfgEtaBins", {200, -10.f, 10.f}, "single electron eta binning"}; + ConfigurableAxis fConfigRapBins{"cfgRapBins", {200, -10.f, 10.f}, "Quark rapidity binning"}; + ConfigurableAxis fConfigMeeBins{"cfgMeeBins", {800, 0.f, 8.f}, "Mee binning"}; + ConfigurableAxis fConfigPteeBins{"cfgPteeBins", {400, 0.f, 10.f}, "pTee binning"}; + Configurable fConfigApplyDEtaDPhi{"cfgApplyDEtaDPhi", false, "flag to apply deta-phi cut"}; + Configurable fConfigMinDEta{"cfgMinDEta", 0.02, "minimum deta"}; + Configurable fConfigMinDPhi{"cfgMinDPhi", 0.2, "minimum dphi"}; +}; + +struct lmeehfcocktailprefilter { + + Produces hfTable; + void process(aod::McParticles const& mcParticles) + { + for (auto const& p : mcParticles) { + + if (abs(p.pdgCode()) != 11 || o2::mcgenstatus::getHepMCStatusCode(p.statusCode()) != 1 || !p.has_mothers()) { + hfTable(EFromHFType::kNoE, -1, -1, -1, -1, -1, -1, -999., -999.); + continue; + } + + int mother_pdg = mcParticles.iteratorAt(p.mothersIds()[0]).pdgCode(); + bool direct_charm_mother = abs(mother_pdg) < 1e+9 && (std::to_string(mother_pdg)[std::to_string(mother_pdg).length() - 3] == '4' || std::to_string(mother_pdg)[std::to_string(mother_pdg).length() - 4] == '4'); + if (abs(mother_pdg) == 443) { + direct_charm_mother = false; // we don't want JPsi here + } + int cHadronId = -1; + if (direct_charm_mother) { + cHadronId = p.mothersIds()[0]; + } + bool direct_beauty_mother = abs(mother_pdg) < 1e+9 && (std::to_string(mother_pdg)[std::to_string(mother_pdg).length() - 3] == '5' || std::to_string(mother_pdg)[std::to_string(mother_pdg).length() - 4] == '5'); + int bHadronId = IsFromBeauty(p, mcParticles); + + int bQuarkId = -1; + int cQuarkId = -1; + int cQuarkOriginId = -1; + int bQuarkOriginId = -1; + + float bQuarkRap = -999.; + float cQuarkRap = -999.; + + int isHF = EFromHFType::kNoHFE; + + if (direct_beauty_mother) { // b->e + isHF = EFromHFType::kBE; + auto bHadron = mcParticles.iteratorAt(bHadronId); + bQuarkId = searchMothers(bHadron, mcParticles, 5, true); + if (bQuarkId > -1) { + auto bQuark = mcParticles.iteratorAt(bQuarkId); + bQuarkOriginId = searchMothers(bQuark, mcParticles, 5, false); + bQuarkRap = bQuark.y(); + } + } else if (bHadronId > -1 && direct_charm_mother) { // b->c->e + isHF = EFromHFType::kBCE; + auto bHadron = mcParticles.iteratorAt(bHadronId); + bQuarkId = searchMothers(bHadron, mcParticles, 5, true); + if (bQuarkId > -1) { + auto bQuark = mcParticles.iteratorAt(bQuarkId); + bQuarkOriginId = searchMothers(bQuark, mcParticles, 5, false); + bQuarkRap = bQuark.y(); + } + auto cHadron = mcParticles.iteratorAt(cHadronId); + cQuarkId = searchMothers(cHadron, mcParticles, 4, true); + if (cQuarkId > -1) { + auto cQuark = mcParticles.iteratorAt(cQuarkId); + cQuarkOriginId = searchMothers(cQuark, mcParticles, 4, false); + cQuarkRap = cQuark.y(); + } + } else if (bHadronId < 0 && direct_charm_mother) { // c->e + isHF = EFromHFType::kCE; + auto cHadron = mcParticles.iteratorAt(cHadronId); + cQuarkId = searchMothers(cHadron, mcParticles, 4, true); + if (cQuarkId > -1) { + auto cQuark = mcParticles.iteratorAt(cQuarkId); + cQuarkOriginId = searchMothers(cQuark, mcParticles, 4, false); + cQuarkRap = cQuark.y(); + } + } + + hfTable(isHF, bHadronId, cHadronId, bQuarkId, cQuarkId, bQuarkOriginId, cQuarkOriginId, bQuarkRap, cQuarkRap); + } + } +}; + +struct lmeehfcocktailbeauty { + + HistogramRegistry registry{"registry", {}}; + + std::vector>> hRapQuark; + std::vector>> hEta, hPt; + std::vector>> hPtEta; + std::vector> hLS_Mee, hULS_Mee; + std::vector> hLS_MeePtee, hULS_MeePtee; + + std::vector> hLS_Mee_wPartonicCheck, hULS_Mee_wPartonicCheck; + std::vector> hLS_MeePtee_wPartonicCheck, hULS_MeePtee_wPartonicCheck; + + MyConfigs myConfigs; + + Filter hfFilter = o2::aod::hftable::isHF == static_cast(EFromHFType::kBE) || o2::aod::hftable::isHF == static_cast(EFromHFType::kBCE); + using MyFilteredMcParticlesSmeared = soa::Filtered>; + + Preslice perCollision = aod::mcparticle::mcCollisionId; + + Partition Electrons = (aod::mcparticle::pdgCode == 11); + Partition Positrons = (aod::mcparticle::pdgCode == -11); + + void init(o2::framework::InitContext&) + { + registry.add("NEvents", "NEvents", HistType::kTH1F, {{1, 0, 1}}, false); + + const int Nchannels = 2; + const char* typeNamesSingle[Nchannels] = {"be", "bce"}; + const char* typeTitlesSingle[Nchannels] = {"b->e", "b->c->e"}; + + AxisSpec rap_axis = {myConfigs.fConfigRapBins, "y_{b}"}; + AxisSpec eta_axis = {myConfigs.fConfigEtaBins, "#eta_{e}"}; + AxisSpec pt_axis = {myConfigs.fConfigPtBins, "#it{p}_{T,e} (GeV/c)"}; + AxisSpec mass_axis = {myConfigs.fConfigMeeBins, "m_{ee} (GeV/c^{2})"}; + AxisSpec ptee_axis = {myConfigs.fConfigPteeBins, "#it{p}_{T,ee} (GeV/c)"}; + + // quark histograms + for (int i = 0; i < Nchannels; i++) { + std::vector> hRap_temp; + for (int j = 0; j < Nstages; j++) { + hRap_temp.push_back(registry.add(Form("BeautyQuark_Rap_%s_%s", typeNamesSingle[i], stageNames[j]), Form("Rap Beauty Quark %s %s", typeTitlesSingle[i], stageNames[j]), HistType::kTH1F, {rap_axis}, true)); + } + hRapQuark.push_back(hRap_temp); + } + + // single histograms + for (int i = 0; i < Nchannels; i++) { + std::vector> hEta_temp, hPt_temp; + std::vector> hPtEta_temp; + for (int j = 0; j < Nstages; j++) { + hEta_temp.push_back(registry.add(Form("Electron_Eta_%s_%s", typeNamesSingle[i], stageNames[j]), Form("Single Electron Eta %s %s", typeTitlesSingle[i], stageNames[j]), HistType::kTH1F, {eta_axis}, true)); + hPt_temp.push_back(registry.add(Form("Electron_Pt_%s_%s", typeNamesSingle[i], stageNames[j]), Form("Single Electron Pt %s %s", typeTitlesSingle[i], stageNames[j]), HistType::kTH1F, {pt_axis}, true)); + hPtEta_temp.push_back(registry.add(Form("Electron_PtEta_%s_%s", typeNamesSingle[i], stageNames[j]), Form("Single Electron Pt vs. Eta %s %s", typeTitlesSingle[i], stageNames[j]), HistType::kTH2F, {pt_axis, eta_axis}, true)); + } + hEta.push_back(hEta_temp); + hPt.push_back(hPt_temp); + hPtEta.push_back(hPtEta_temp); + } + + // pair histograms + // ULS + for (int j = 0; j < Nstages; j++) { + hULS_Mee.push_back(registry.add(Form("ULS_Mee_%s", stageNames[j]), Form("ULS Mee %s", stageNames[j]), HistType::kTH1F, {mass_axis}, true)); + hULS_MeePtee.push_back(registry.add(Form("ULS_MeePtee_%s", stageNames[j]), Form("ULS Mee vs. Ptee %s", stageNames[j]), HistType::kTH2F, {mass_axis, ptee_axis}, true)); + + hULS_Mee_wPartonicCheck.push_back(registry.add(Form("ULS_Mee_wPartonicCheck_%s", stageNames[j]), Form("ULS Mee wPartonicCheck %s", stageNames[j]), HistType::kTH1F, {mass_axis}, true)); + hULS_MeePtee_wPartonicCheck.push_back(registry.add(Form("ULS_MeePtee_wPartonicCheck_%s", stageNames[j]), Form("ULS Mee vs. Ptee wPartonicCheck %s", stageNames[j]), HistType::kTH2F, {mass_axis, ptee_axis}, true)); + } + // LS + for (int j = 0; j < Nstages; j++) { + hLS_Mee.push_back(registry.add(Form("LS_Mee_%s", stageNames[j]), Form("LS Mee %s", stageNames[j]), HistType::kTH1F, {mass_axis}, true)); + hLS_MeePtee.push_back(registry.add(Form("LS_MeePtee_%s", stageNames[j]), Form("LS Mee vs. Ptee %s", stageNames[j]), HistType::kTH2F, {mass_axis, ptee_axis}, true)); + + hLS_Mee_wPartonicCheck.push_back(registry.add(Form("LS_Mee_wPartonicCheck_%s", stageNames[j]), Form("LS Mee wPartonicCheck %s", stageNames[j]), HistType::kTH1F, {mass_axis}, true)); + hLS_MeePtee_wPartonicCheck.push_back(registry.add(Form("LS_MeePtee_wPartonicCheck_%s", stageNames[j]), Form("LS Mee vs. Ptee wPartonicCheck %s", stageNames[j]), HistType::kTH2F, {mass_axis, ptee_axis}, true)); + } + } + + void processBeauty(aod::McCollisions const& collisions, MyFilteredMcParticlesSmeared const& mcParticles) + { + for (auto const& p : mcParticles) { + int from_quark = p.isHF() - 2; + doSingle(p, hEta[from_quark], hPt[from_quark], hPtEta[from_quark], myConfigs.fConfigPtMin, myConfigs.fConfigEtaMax); + doQuark(p, hRapQuark[from_quark], myConfigs.fConfigPtMin, myConfigs.fConfigEtaMax, 5); + } + + for (auto const& collision : collisions) { + + registry.fill(HIST("NEvents"), 0.5); + + auto const electronsGrouped = Electrons->sliceBy(perCollision, collision.globalIndex()); + auto const positronsGrouped = Positrons->sliceBy(perCollision, collision.globalIndex()); + // ULS spectrum + for (auto const& [particle1, particle2] : combinations(o2::soa::CombinationsFullIndexPolicy(electronsGrouped, positronsGrouped))) { + + if (particle1.mothersIds()[0] == particle2.mothersIds()[0]) { + LOG(error) << "Something is wrong here. There should not be dielectrons with same mother."; + } + + doPair(particle1, particle2, hULS_Mee, hULS_MeePtee, myConfigs.fConfigPtMin, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); + + if (particle1.bQuarkOriginId() < 0 || particle2.bQuarkOriginId() < 0 || particle1.bQuarkOriginId() != particle2.bQuarkOriginId()) + continue; + doPair(particle1, particle2, hULS_Mee_wPartonicCheck, hULS_MeePtee_wPartonicCheck, myConfigs.fConfigPtMin, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); + } + // LS spectrum + for (auto const& [particle1, particle2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(electronsGrouped, electronsGrouped))) { + + if (particle1.mothersIds()[0] == particle2.mothersIds()[0]) { + LOG(error) << "Something is wrong here. There should not be dielectrons with same mother."; + } + + doPair(particle1, particle2, hLS_Mee, hLS_MeePtee, myConfigs.fConfigPtMin, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); + + if (particle1.bQuarkOriginId() < 0 || particle2.bQuarkOriginId() < 0 || particle1.bQuarkOriginId() != particle2.bQuarkOriginId()) + continue; + doPair(particle1, particle2, hLS_Mee_wPartonicCheck, hLS_MeePtee_wPartonicCheck, myConfigs.fConfigPtMin, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); + } + for (auto const& [particle1, particle2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(positronsGrouped, positronsGrouped))) { + + if (particle1.mothersIds()[0] == particle2.mothersIds()[0]) { + LOG(error) << "Something is wrong here. There should not be dielectrons with same mother."; + } + + doPair(particle1, particle2, hLS_Mee, hLS_MeePtee, myConfigs.fConfigPtMin, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); + + if (particle1.bQuarkOriginId() < 0 || particle2.bQuarkOriginId() < 0 || particle1.bQuarkOriginId() != particle2.bQuarkOriginId()) + continue; + doPair(particle1, particle2, hLS_Mee_wPartonicCheck, hLS_MeePtee_wPartonicCheck, myConfigs.fConfigPtMin, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); + } + } + } + + void processDummy(aod::McCollisions const&) + { + // dummy + } + + PROCESS_SWITCH(lmeehfcocktailbeauty, processBeauty, "process beauty cocktail", true); + PROCESS_SWITCH(lmeehfcocktailbeauty, processDummy, "dummy", false); +}; + +struct lmeehfcocktailcharm { + + HistogramRegistry registry{"registry", {}}; + + std::vector> hRapQuark; + std::vector> hEta, hPt, hULS_Mee, hLS_Mee; + std::vector> hPtEta, hULS_MeePtee, hLS_MeePtee; + std::vector> hULS_Mee_wPartonicCheck, hLS_Mee_wPartonicCheck; + std::vector> hULS_MeePtee_wPartonicCheck, hLS_MeePtee_wPartonicCheck; + + MyConfigs myConfigs; + + Filter hfFilter = o2::aod::hftable::isHF == static_cast(EFromHFType::kCE); + using MyFilteredMcParticlesSmeared = soa::Filtered>; + + Preslice perCollision = aod::mcparticle::mcCollisionId; + + Partition Electrons = (aod::mcparticle::pdgCode == 11); + Partition Positrons = (aod::mcparticle::pdgCode == -11); + + void init(o2::framework::InitContext&) + { + registry.add("NEvents", "NEvents", HistType::kTH1F, {{1, 0, 1}}, false); + + const char* typeNamesSingle = "ce"; + const char* typeTitlesSingle = "c->e"; + + AxisSpec rap_axis = {myConfigs.fConfigRapBins, "y_{c}"}; + AxisSpec eta_axis = {myConfigs.fConfigEtaBins, "#eta_{e}"}; + AxisSpec pt_axis = {myConfigs.fConfigPtBins, "#it{p}_{T,e} (GeV/c)"}; + AxisSpec mass_axis = {myConfigs.fConfigMeeBins, "m_{ee} (GeV/c^{2})"}; + AxisSpec ptee_axis = {myConfigs.fConfigPteeBins, "#it{p}_{T,ee} (GeV/c)"}; + + // quark histograms + for (int j = 0; j < Nstages; j++) { + hRapQuark.push_back(registry.add(Form("CharmQuark_Rap_%s_%s", typeNamesSingle, stageNames[j]), Form("Rapidity Charm Quark %s %s", typeTitlesSingle, stageNames[j]), HistType::kTH1F, {rap_axis}, true)); + } + + // single histograms + for (int j = 0; j < Nstages; j++) { + hEta.push_back(registry.add(Form("Electron_Eta_%s_%s", typeNamesSingle, stageNames[j]), Form("Single Electron Eta %s %s", typeTitlesSingle, stageNames[j]), HistType::kTH1F, {eta_axis}, true)); + hPt.push_back(registry.add(Form("Electron_Pt_%s_%s", typeNamesSingle, stageNames[j]), Form("Single Electron Pt %s %s", typeTitlesSingle, stageNames[j]), HistType::kTH1F, {pt_axis}, true)); + hPtEta.push_back(registry.add(Form("Electron_PtEta_%s_%s", typeNamesSingle, stageNames[j]), Form("Single Electron Pt vs. Eta %s %s", typeTitlesSingle, stageNames[j]), HistType::kTH2F, {pt_axis, eta_axis}, true)); + } + + // pair histograms + // ULS + for (int j = 0; j < Nstages; j++) { + hULS_Mee.push_back(registry.add(Form("ULS_Mee_%s", stageNames[j]), Form("ULS Mee %s", stageNames[j]), HistType::kTH1F, {mass_axis}, true)); + hULS_MeePtee.push_back(registry.add(Form("ULS_MeePtee_%s", stageNames[j]), Form("ULS Mee vs Ptee %s", stageNames[j]), HistType::kTH2F, {mass_axis, ptee_axis}, true)); + + hULS_Mee_wPartonicCheck.push_back(registry.add(Form("ULS_Mee_wPartonicCheck_%s", stageNames[j]), Form("ULS Mee wPartonicCheck %s", stageNames[j]), HistType::kTH1F, {mass_axis}, true)); + hULS_MeePtee_wPartonicCheck.push_back(registry.add(Form("ULS_MeePtee_wPartonicCheck_%s", stageNames[j]), Form("ULS Mee vs Ptee wPartonicCheck %s", stageNames[j]), HistType::kTH2F, {mass_axis, ptee_axis}, true)); + } + // LS + for (int j = 0; j < Nstages; j++) { + hLS_Mee.push_back(registry.add(Form("LS_Mee_%s", stageNames[j]), Form("LS Mee %s", stageNames[j]), HistType::kTH1F, {mass_axis}, true)); + hLS_MeePtee.push_back(registry.add(Form("LS_MeePtee_%s", stageNames[j]), Form("LS Mee vs Ptee %s", stageNames[j]), HistType::kTH2F, {mass_axis, ptee_axis}, true)); + + hLS_Mee_wPartonicCheck.push_back(registry.add(Form("LS_Mee_wPartonicCheck_%s", stageNames[j]), Form("LS Mee wPartonicCheck %s", stageNames[j]), HistType::kTH1F, {mass_axis}, true)); + hLS_MeePtee_wPartonicCheck.push_back(registry.add(Form("LS_MeePtee_wPartonicCheck_%s", stageNames[j]), Form("LS Mee vs Ptee wPartonicCheck %s", stageNames[j]), HistType::kTH2F, {mass_axis, ptee_axis}, true)); + } + } + + void processCharm(aod::McCollisions const& collisions, MyFilteredMcParticlesSmeared const& mcParticles) + { + for (auto const& p : mcParticles) { + doSingle(p, hEta, hPt, hPtEta, myConfigs.fConfigPtMin, myConfigs.fConfigEtaMax); + doQuark(p, hRapQuark, myConfigs.fConfigPtMin, myConfigs.fConfigEtaMax, 4); + } + + for (auto const& collision : collisions) { + + registry.fill(HIST("NEvents"), 0.5); + + auto const electronsGrouped = Electrons->sliceBy(perCollision, collision.globalIndex()); + auto const positronsGrouped = Positrons->sliceBy(perCollision, collision.globalIndex()); + // ULS spectrum + for (auto const& [particle1, particle2] : combinations(o2::soa::CombinationsFullIndexPolicy(electronsGrouped, positronsGrouped))) { + + if (particle1.mothersIds()[0] == particle2.mothersIds()[0]) { + LOG(error) << "Something is wrong here. There should not be dielectrons with same mother."; + } + + doPair(particle1, particle2, hULS_Mee, hULS_MeePtee, myConfigs.fConfigPtMin, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); + + if (particle1.cQuarkOriginId() < 0 || particle2.cQuarkOriginId() < 0 || particle1.cQuarkOriginId() != particle2.cQuarkOriginId()) + continue; + doPair(particle1, particle2, hULS_Mee_wPartonicCheck, hULS_MeePtee_wPartonicCheck, myConfigs.fConfigPtMin, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); + } + // LS + for (auto const& [particle1, particle2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(electronsGrouped, electronsGrouped))) { + + if (particle1.mothersIds()[0] == particle2.mothersIds()[0]) { + LOG(error) << "Something is wrong here. There should not be dielectrons with same mother."; + } + + doPair(particle1, particle2, hLS_Mee, hLS_MeePtee, myConfigs.fConfigPtMin, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); + + if (particle1.cQuarkOriginId() < 0 || particle2.cQuarkOriginId() < 0 || particle1.cQuarkOriginId() != particle2.cQuarkOriginId()) + continue; + doPair(particle1, particle2, hLS_Mee_wPartonicCheck, hLS_MeePtee_wPartonicCheck, myConfigs.fConfigPtMin, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); + } + for (auto const& [particle1, particle2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(positronsGrouped, positronsGrouped))) { + + if (particle1.mothersIds()[0] == particle2.mothersIds()[0]) { + LOG(error) << "Something is wrong here. There should not be dielectrons with same mother."; + } + + doPair(particle1, particle2, hLS_Mee, hLS_MeePtee, myConfigs.fConfigPtMin, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); + + if (particle1.cQuarkOriginId() < 0 || particle2.cQuarkOriginId() < 0 || particle1.cQuarkOriginId() != particle2.cQuarkOriginId()) + continue; + doPair(particle1, particle2, hLS_Mee_wPartonicCheck, hLS_MeePtee_wPartonicCheck, myConfigs.fConfigPtMin, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); + } + } + } + + void processDummy(aod::McCollisions const&) + { + // dummy + } + + PROCESS_SWITCH(lmeehfcocktailcharm, processCharm, "process charm cocktail", true); + PROCESS_SWITCH(lmeehfcocktailcharm, processDummy, "dummy", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName("em-lmee-hf-cocktail-charm")), + adaptAnalysisTask(cfgc, TaskName("em-lmee-hf-cocktail-beauty")), + adaptAnalysisTask(cfgc, TaskName("em-lmee-hf-cocktail-prefilter"))}; +} diff --git a/PWGEM/Dilepton/Tasks/lmeeLFCocktail.cxx b/PWGEM/Dilepton/Tasks/lmeeLFCocktail.cxx index 2799fcd8341..1cac2727e98 100644 --- a/PWGEM/Dilepton/Tasks/lmeeLFCocktail.cxx +++ b/PWGEM/Dilepton/Tasks/lmeeLFCocktail.cxx @@ -10,986 +10,543 @@ // or submit itself to any jurisdiction. // // -// Analysis task for lmee light flavour cocktail +/// \file lmeeLFCocktail.cxx +/// \analysis task for lmee light flavour cocktail +/// \author Daniel Samitz, , SMI Vienna +#include #include -#include "Framework/Task.h" +#include + +#include "Math/Vector4D.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" -#include "Framework/Logger.h" -#include "SimulationDataFormat/MCTrack.h" -#include "PWGEM/Dilepton/Utils/MomentumSmearer.h" -#include "Math/Vector4D.h" -#include "Math/Vector3D.h" -#include "TFile.h" -#include "TF1.h" -#include "TRandom.h" -#include "TDatabasePDG.h" -#include "TGenPhaseSpace.h" -#include "TGrid.h" -#include "TTree.h" -#include +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +using namespace o2; using namespace o2::framework; -using namespace ROOT::Math; - -struct eeTTree { - float fd1DCA; - float fd2DCA; - float fpairDCA; - float fd1origpt; - float fd1origp; - float fd1origeta; - float fd1origphi; - float fd2origpt; - float fd2origp; - float fd2origeta; - float fd2origphi; - float fd1pt; - float fd1p; - float fd1eta; - float fd1phi; - float fd2pt; - float fd2p; - float fd2eta; - float fd2phi; - float feeorigpt; - float feeorigp; - float feeorigm; - float feeorigeta; - float feeorigphi; - float feeorigphiv; - float feept; - float feemt; - float feep; - float feem; - float feeeta; - float feephi; - float feephiv; - float fmotherpt; - float fmothermt; - float fmotherp; - float fmotherm; - float fmothereta; - float fmotherphi; - int fID; - int fdectyp; - int fdau3pdg; - float fweight; - float fwEffpT; - float fwMultpT; - float fwMultmT; - float fwMultpT2; - float fwMultmT2; - bool fpass; - float feeorigrap; // only in histogram, not in tree? - float feerap; // only in histogram, not in tree? -}; - -struct lmeelfcocktail { - OutputObj tree{"eeTTree"}; - - HistogramRegistry registry{"registry", {}}; - Int_t nInputParticles = 17; - std::vector fParticleListNames = {"Pi0", "Eta", "EtaP", "EtaP_dalitz_photon", "EtaP_dalitz_omega", "Rho", "Omega", "Omega_2body", "Omega_dalitz", "Phi", "Phi_2body", "Phi_dalitz_eta", "Phi_dalitz_pi0", "Jpsi", "Jpsi_2body", "Jpsi_radiative", "Virtual_Photon"}; - TH1F* fhwEffpT; - TH1F* fhwMultpT; - TH1F* fhwMultmT; - TH1F* fhwMultpT2; - TH1F* fhwMultmT2; - TH1F* fhKW; - TF1* ffVPHpT; - std::vector> fmee_orig, fmotherpT_orig, fphi_orig, frap_orig, fmee_orig_wALT, fmotherpT_orig_wALT, fmee, fphi, frap, fmee_wALT; - std::vector> fpteevsmee_wALT, fpteevsmee_orig_wALT, fpteevsmee_orig, fpteevsmee; +using McParticlesSmeared = soa::Join; - eeTTree treeWords; +struct lmeelfcocktail { - std::vector DCATemplateEdges; - int nbDCAtemplate; - TH1F** fh_DCAtemplates; + enum recLevel { + kGen = 0, + kRec, + kNRecLevels + }; + + struct mesonInfo { + TString name; + std::vector decayModes; + }; + + std::map decays = { + {-1, "e_e/"}, + {-2, "e_e_e_e/"}, + {22, "gamma_e_e/"}, + {223, "omega_e_e/"}, + {211 * 211, "pi_pi_e_e/"}, + {111, "pi0_e_e/"}, + {221, "eta_e_e/"}}; + + std::map mesons = { + {111, {"pi0/", {22, -2}}}, + {221, {"eta/", {22, 211 * 211, -2}}}, + {331, {"etaP/", {22, 223, 211 * 211}}}, + {113, {"rho/", {-1}}}, + {223, {"omega/", {-1, 111}}}, + {333, {"phi/", {-1, 111, 221}}}, + {443, {"Jpsi/", {-1}}}, + {100443, {"psi2S/", {-1}}}, + {553, {"Upsilon/", {-1}}}}; + + std::map histogramId; + + std::vector stage = {"gen/", "rec/"}; - MomentumSmearer smearer; + HistogramRegistry registry{"registry", {}}; - Double_t eMass; + Configurable fConfigApplyDEtaDPhi{"cfgApplyDEtaDPhi", false, "flag to apply deta-phi cut"}; + Configurable fConfigMinDEta{"cfgMinDEta", 0.02, "minimum deta"}; + Configurable fConfigMinDPhi{"cfgMinDPhi", 0.2, "minimum dphi"}; - Configurable fCollisionSystem{"cfgCollisionSystem", 200, "set the collision system"}; - Configurable fConfigWriteTTree{"cfgWriteTTree", false, "write tree output"}; - Configurable fConfigDoPairing{"cfgDoPairing", true, "do like and unlike sign pairing"}; Configurable fConfigMaxEta{"cfgMaxEta", 0.8, "maxium |eta|"}; Configurable fConfigMinPt{"cfgMinPt", 0.2, "minium pT"}; Configurable fConfigMaxPt{"cfgMaxPt", 8.0, "maximum pT"}; - Configurable fConfigNBinsMee{"cfgNBinsMee", 1200, "number of bins in invariant mass"}; - Configurable fConfigMinMee{"cfgMinMee", 0.0, "lowest bin in invariant mass"}; - Configurable fConfigMaxMee{"cfgMaxMee", 6.0, "highest bin in invariant mass"}; - Configurable fConfigNBinsPtee{"cfgNBinsPtee", 400, "number of bins in pT"}; - Configurable fConfigMinPtee{"cfgMinPtee", 0.0, "lowest bin in pT"}; - Configurable fConfigMaxPtee{"cfgMaxPtee", 10.0, "hightest bin in pT"}; - Configurable fConfigALTweight{"cfgALTweight", 1, "set alternative weighting type"}; - Configurable fConfigResFileName{"cfgResFileName", "", "name of resolution file"}; - Configurable fConfigEffFileName{"cfgEffFileName", "", "name of efficiency file"}; - Configurable fConfigMinOpAng{"cfgMinOpAng", 0.050, "minimum opening angle"}; - Configurable fConfigNBinsPhi{"cfgNBinsPhi", 240, "number of bins in phi"}; - Configurable fConfigNBinsRap{"cfgNBinsRap", 240, "number of bins in rap"}; - Configurable fConfigMaxAbsRap{"cfgMaxAbsRap", 1.2, "bin range in rap"}; - Configurable fConfigEffHistName{"cfgEffHistName", "fhwEffpT", "hisogram name in efficiency file"}; - Configurable fConfigResPHistName{"cfgResPHistName", "ptSlices", "histogram name for p in resolution file"}; - Configurable fConfigResPtHistName{"cfgResPtHistName", "RelPtResArrCocktail", "histogram name for pt in resolution file"}; - Configurable fConfigResEtaHistName{"cfgResEtaHistName", "EtaResArr", "histogram name for eta in resolution file"}; - Configurable fConfigResPhiPosHistName{"cfgResPhiPosHistName", "PhiPosResArr", "histogram name for phi pos in resolution file"}; - Configurable fConfigResPhiNegHistName{"cfgResPhiNegHistName", "PhiEleResArr", "hisogram for phi neg in resolution file"}; - Configurable fConfigDCAFileName{"cfgDCAFileName", "", "DCA file name"}; - Configurable fConfigDCAHistName{"cfgDCAHistName", "fh_DCAtemplate", "histogram name in DCA file"}; - Configurable fConfigMultFileName{"cfgMultFileName", "", "multiplicity file name"}; - Configurable fConfigMultHistPtName{"cfgMultHistPtName", "fhwMultpT", "hisogram name for pt in multiplicity file"}; - Configurable fConfigMultHistPt2Name{"cfgMultHistPt2Name", "fhwMultpT_upperlimit", "histogram name for pt 2 in multiplicity file"}; - Configurable fConfigMultHistMtName{"cfgMultHistMtName", "fhwMultmT", "histogram name for mt in multiplicity file"}; - Configurable fConfigMultHistMt2Name{"cfgMultHistMt2Name", "fhwMultmT_upperlimit", "histogram name for mt 2 in multiplicity file"}; - Configurable fConfigKWMax{"cfgKWMax", 1.1, "upper bound of Kroll-Wada"}; - Configurable fConfigDoVirtPh{"cfgDoVirtPh", false, "generate one virt. photon for each pion"}; - Configurable fConfigPhotonPtFileName{"cfgPhotonPtFileName", "", "file name for photon pT parametrization"}; - Configurable fConfigPhotonPtDirName{"cfgPhotonPtDirName", "", "directory name for photon pT parametrization"}; - Configurable fConfigPhotonPtFuncName{"cfgPhotonPtFuncName", "111_pt", "function name for photon pT parametrization"}; - - ConfigurableAxis fConfigPtBins{"cfgPtBins", {VARIABLE_WIDTH, 0., 0.5, 1, 1.5, 2., 2.5, 3., 3.5, 4., 4.5, 5., 5.5, 6., 6.5, 7., 7.5, 8.}, "pT bins"}; - ConfigurableAxis fConfigMBins{"cfgMBins", {VARIABLE_WIDTH, 0., 0.08, 0.14, 0.2, 1.1, 2.7, 2.8, 3.2, 5.0}, "mee bins"}; - ConfigurableAxis fConfigDCABins{"cfgDCABins", {VARIABLE_WIDTH, 0., 0.4, 0.8, 1.2, 1.6, 2.0, 2.4, 3., 4., 5., 7., 10.}, "DCA bins"}; - - Configurable> fConfigDCATemplateEdges{"cfgDCATemplateEdges", {0., .3, .4, .6, 1., 2.}, "DCA template edges"}; - - void init(o2::framework::InitContext&) + Configurable fConfigMinOpAng{"cfgMinOpAng", 0, "minimum opening angle"}; + Configurable fConfigMinPtee{"cfgMinPtee", 0, "minimum pair pT"}; + Configurable fConfigMaxRapee{"cfgMaxRapee", 999., "maximum pair rapidity"}; + ConfigurableAxis fConfigMeeBins{"cfgMeeBins", {600, 0.f, 6.f}, "Mee binning"}; + ConfigurableAxis fConfigPteeBins{"cfgPteeBins", {400, 0.f, 10.f}, "pTee binning"}; + ConfigurableAxis fConfigCos2DPhi{"cfgCos2DPhi", {200, -1.f, +1.f}, "cos(2x(phiee-PsiRP)) binning"}; // for dilepton v2. + ConfigurableAxis fConfigPtBins{"cfgPtBins", {200, 0.f, 10.f}, "pT binning"}; + ConfigurableAxis fConfigEtaBins{"cfgEtaBins", {200, -5.f, 5.f}, "eta binning"}; + ConfigurableAxis fConfigPhiBins{"cfgPhiBins", {200, -TMath::Pi(), TMath::Pi()}, "phi binning"}; + ConfigurableAxis fConfigPhiVBins{"cfgPhiVBins", {200, 0, TMath::Pi()}, "phiV binning"}; + ConfigurableAxis fConfigOpAngBins{"cfgOpAngBins", {200, 0, TMath::Pi()}, "opening angle binning"}; + ConfigurableAxis fConfigDcaBins{"cfgDcaBins", {VARIABLE_WIDTH, 0., 0.4, 0.8, 1.2, 1.6, 2.0, 2.4, 3., 4., 5., 7., 10.}, "dca binning"}; + + std::vector> histograms1D; + std::vector> histograms2D; + std::vector> histogramsND; + + template + bool from_primary(T& p1, U& mcParticles) { - if (fConfigWriteTTree) { - SetTree(); + if (!p1.has_mothers()) { + return false; } - SetHistograms(); - DCATemplateEdges = fConfigDCATemplateEdges; - nbDCAtemplate = DCATemplateEdges.size(); - DCATemplateEdges.push_back(10000000.); - - if ((TString(fConfigEffFileName).BeginsWith("alien://") && TString(fConfigEffFileName).EndsWith(".root")) || (TString(fConfigResFileName).BeginsWith("alien://") && TString(fConfigResFileName).EndsWith(".root")) || (TString(fConfigDCAFileName).BeginsWith("alien://") && TString(fConfigDCAFileName).EndsWith(".root")) || (TString(fConfigMultFileName).BeginsWith("alien://") && TString(fConfigMultFileName).EndsWith(".root")) || (TString(fConfigPhotonPtFileName).BeginsWith("alien://") && TString(fConfigPhotonPtFileName).EndsWith(".root"))) { - LOGP(info, "Connecting to grid via TGrid"); - TGrid::Connect("alien://"); + auto mother = mcParticles.iteratorAt(p1.mothersIds()[0]); + if (mother.has_mothers()) { + return false; } - - GetEffHisto(TString(fConfigEffFileName), TString(fConfigEffHistName)); - InitSmearer(TString(fConfigResFileName), TString(fConfigResPtHistName), TString(fConfigResEtaHistName), TString(fConfigResPhiPosHistName), TString(fConfigResPhiNegHistName)); - GetDCATemplates(TString(fConfigDCAFileName), TString(fConfigDCAHistName)); - GetMultHisto(TString(fConfigMultFileName), TString(fConfigMultHistPtName), TString(fConfigMultHistPt2Name), TString(fConfigMultHistMtName), TString(fConfigMultHistMt2Name)); - if (fConfigDoVirtPh) { - GetPhotonPtParametrization(TString(fConfigPhotonPtFileName), TString(fConfigPhotonPtDirName), TString(fConfigPhotonPtFuncName)); - } - - eMass = (TDatabasePDG::Instance()->GetParticle(11))->Mass(); - - fillKrollWada(); + return true; } - void run(o2::framework::ProcessingContext& pc) + bool isAcceptedSingle(ROOT::Math::PtEtaPhiMVector p1) { - // get number of events per timeframe - auto Nparts = pc.inputs().getNofParts(0); - - for (auto i = 0U; i < Nparts; ++i) { - registry.fill(HIST("NEvents"), 0.5); - // get the tracks - auto mctracks = pc.inputs().get>("mctracks", i); - - std::vector eBuff; - std::vector echBuff; - std::vector eweightBuff; - - bool skipNext = false; - - int trackID = -1; - // Loop over all MC particle - for (auto& mctrack : mctracks) { - trackID++; - if (o2::mcgenstatus::getHepMCStatusCode(mctrack.getStatusCode()) != 1) - continue; - if (abs(mctrack.GetPdgCode()) == 11) { - // get the electron - //--------------- - if (fConfigDoPairing) { - // LS and ULS spectra - PxPyPzEVector e, dielectron; - Char_t ech, dielectron_ch; - Double_t eweight, dielectron_weight; - e.SetPxPyPzE(mctrack.Px(), mctrack.Py(), mctrack.Pz(), - mctrack.GetEnergy()); - if (mctrack.GetPdgCode() > 0) { - ech = 1.; - } else { - ech = -1.; - } - eweight = mctrack.getWeight(); - // put in the buffer - //----------------- - eBuff.push_back(e); - echBuff.push_back(ech); - eweightBuff.push_back(eweight); - // loop the buffer and pair - //------------------------ - for (Int_t jj = eBuff.size() - 2; jj >= 0; jj--) { - dielectron = eBuff.at(jj) + e; - dielectron_ch = (echBuff.at(jj) + ech) / 2; - dielectron_weight = eweightBuff.at(jj) * eweight; - - if (dielectron_ch == 0) - registry.fill(HIST("ULS_orig"), dielectron.M(), dielectron.Pt(), dielectron_weight); - if (dielectron_ch > 0) - registry.fill(HIST("LSpp_orig"), dielectron.M(), dielectron.Pt(), dielectron_weight); - if (dielectron_ch < 0) - registry.fill(HIST("LSmm_orig"), dielectron.M(), dielectron.Pt(), dielectron_weight); - if (e.Pt() > fConfigMinPt && eBuff.at(jj).Pt() > fConfigMinPt && e.Pt() < fConfigMaxPt && eBuff.at(jj).Pt() < fConfigMaxPt && TMath::Abs(e.Eta()) < fConfigMaxEta && TMath::Abs(eBuff.at(jj).Eta()) < fConfigMaxEta && e.Vect().Unit().Dot(eBuff.at(jj).Vect().Unit()) < TMath::Cos(fConfigMinOpAng)) { - if (dielectron_ch == 0) - registry.fill(HIST("ULS"), dielectron.M(), dielectron.Pt(), dielectron_weight); - if (dielectron_ch > 0) - registry.fill(HIST("LSpp"), dielectron.M(), dielectron.Pt(), dielectron_weight); - if (dielectron_ch < 0) - registry.fill(HIST("LSmm"), dielectron.M(), dielectron.Pt(), dielectron_weight); - } - } - } - - if (skipNext) { - skipNext = false; - continue; // skip if marked as second electron - } - - if (!(mctrack.getMotherTrackId() > -1)) - continue; // has no mother - - auto const& mother = mctracks[mctrack.getMotherTrackId()]; - - if (mother.getMotherTrackId() > -1) - continue; // mother is not primary - - if (mctrack.getSecondMotherTrackId() - mctrack.getMotherTrackId() > 0) - continue; // more than one mother - - // skip for the moment other particles rather than pi0, eta, etaprime, - // omega, rho, phi. - switch (mother.GetPdgCode()) { - case 111: - break; - case 221: - break; - case 331: - break; - case 113: - break; - case 223: - break; - case 333: - break; - case 443: - break; - default: - continue; - } - - /* - // Not sure about this cut. From GammaConv group. Harmless a priori. - if (!(fabs(mctrack.GetEnergy() - mctrack.Pz()) > 0.)) - continue; - - // ???? this applied only to first daughter! - Double_t yPre = (mctrack.GetEnergy() + mctrack.Pz()) / (mctrack.GetEnergy() - mctrack.Pz()); - Double_t y = 0.5 * TMath::Log(yPre); - if (fConfigDoRapidityCut) { // Apply rapidity cut on mother consistent with GammaConv group. (??? but it is not applied on mother?) - if (yPre <= 0.) - continue; - if (TMath::Abs(y) > fConfigRapidityCut) - continue; - } else { - if (yPre == 0.) - continue; - }*/ - - treeWords.fdectyp = mother.getLastDaughterTrackId() - mother.getFirstDaughterTrackId() + 1; // fdectyp: decay type (based on number of daughters). - if (treeWords.fdectyp > 4) - continue; // exclude five or more particles decay - - if (trackID == mctracks.size()) - continue; // no particle left in the list - auto mctrack2 = mctracks[trackID + 1]; - if (!(mctrack2.getMotherTrackId() == mctrack.getMotherTrackId())) - continue; // no matching second electron - if (!(mctrack.getSecondMotherTrackId() == -1)) - continue; // second daughter has more than one mother - if (!(abs(mctrack2.GetPdgCode()) == 11)) - continue; // not an electron - - skipNext = true; // is matching electron --> next particle in list will be skipped - - PxPyPzEVector dau1, dau2, ee; - dau1.SetPxPyPzE(mctrack.Px(), mctrack.Py(), mctrack.Pz(), mctrack.GetEnergy()); - dau2.SetPxPyPzE(mctrack2.Px(), mctrack2.Py(), mctrack2.Pz(), mctrack2.GetEnergy()); - - // create dielectron before resolution effects: - ee = dau1 + dau2; - - // get info of the other particles in the decay: - treeWords.fdau3pdg = 0; - for (Int_t jj = mother.getFirstDaughterTrackId(); jj <= mother.getLastDaughterTrackId(); jj++) { - if (jj == trackID || jj == trackID + 1) { - continue; // first or second electron - } - auto mctrack3 = mctracks[jj]; - treeWords.fdau3pdg = abs(mctrack3.GetPdgCode()); - } - - // get index for histograms - Int_t hindex[3]; - for (Int_t jj = 0; jj < 3; jj++) { - hindex[jj] = -1; - } - switch (mother.GetPdgCode()) { - case 111: - hindex[0] = 0; - break; - case 221: - hindex[0] = 1; - break; - case 331: - hindex[0] = 2; - if (treeWords.fdectyp == 3 && treeWords.fdau3pdg == 22) - hindex[1] = 3; - if (treeWords.fdectyp == 3 && treeWords.fdau3pdg == 223) - hindex[1] = 4; - break; - case 113: - hindex[0] = 5; - break; - case 223: - hindex[0] = 6; - if (treeWords.fdectyp == 2) - hindex[1] = 7; - if (treeWords.fdectyp == 3 && treeWords.fdau3pdg == 111) - hindex[1] = 8; - break; - case 333: - hindex[0] = 9; - if (treeWords.fdectyp == 2) - hindex[1] = 10; - if (treeWords.fdectyp == 3 && treeWords.fdau3pdg == 221) - hindex[1] = 11; - if (treeWords.fdectyp == 3 && treeWords.fdau3pdg == 111) - hindex[1] = 12; - break; - case 443: - hindex[0] = 13; - if (treeWords.fdectyp == 2) - hindex[1] = 14; - if (treeWords.fdectyp == 3 && treeWords.fdau3pdg == 22) - hindex[1] = 15; - break; - } - - hindex[2] = nInputParticles; - - if (hindex[0] < 0) { - LOGP(error, "hindex[0]<0"); - continue; - } - - // Fill tree words before resolution/acceptance - treeWords.fd1origpt = dau1.Pt(); - treeWords.fd1origp = dau1.P(); - treeWords.fd1origeta = dau1.Eta(); - treeWords.fd1origphi = dau1.Phi(); - treeWords.fd2origpt = dau2.Pt(); - treeWords.fd2origp = dau2.P(); - treeWords.fd2origeta = dau2.Eta(); - treeWords.fd2origphi = dau2.Phi(); - treeWords.feeorigpt = ee.Pt(); - treeWords.feeorigp = ee.P(); - treeWords.feeorigm = ee.M(); - treeWords.feeorigeta = ee.Eta(); - treeWords.feeorigrap = ee.Rapidity(); - treeWords.feeorigphi = ee.Phi(); - if (mctrack.GetPdgCode() > 0) { - treeWords.feeorigphiv = PhiV(dau1, dau2); - } else { - treeWords.feeorigphiv = PhiV(dau2, dau1); - } - - // get the efficiency weight - Int_t effbin = fhwEffpT->FindBin(treeWords.fd1origpt); - treeWords.fwEffpT = fhwEffpT->GetBinContent(effbin); - effbin = fhwEffpT->FindBin(treeWords.fd2origpt); - treeWords.fwEffpT = treeWords.fwEffpT * fhwEffpT->GetBinContent(effbin); - - // Resolution and acceptance - //------------------------- - int ch1 = 1; - int ch2 = 1; - if (mctrack.GetPdgCode() > 0) { - ch1 = -1; - } - if (mctrack2.GetPdgCode() > 0) { - ch2 = -1; - } - dau1 = applySmearingPxPyPzE(ch1, dau1); - dau2 = applySmearingPxPyPzE(ch2, dau2); - - treeWords.fd1pt = dau1.Pt(); - treeWords.fd1eta = dau1.Eta(); - treeWords.fd2pt = dau2.Pt(); - treeWords.fd2eta = dau2.Eta(); - treeWords.fpass = true; - if (treeWords.fd1pt < fConfigMinPt || treeWords.fd2pt < fConfigMinPt) - treeWords.fpass = false; // leg pT cut - if (treeWords.fd1pt > fConfigMaxPt || treeWords.fd2pt > fConfigMaxPt) - treeWords.fpass = false; // leg pT cut - if (dau1.Vect().Unit().Dot(dau2.Vect().Unit()) > TMath::Cos(fConfigMinOpAng)) - treeWords.fpass = false; // opening angle cut - if (TMath::Abs(treeWords.fd1eta) > fConfigMaxEta || TMath::Abs(treeWords.fd2eta) > fConfigMaxEta) - treeWords.fpass = false; - - // get the pair DCA (based in smeared pT) - for (int jj = 0; jj < nbDCAtemplate; jj++) { // loop over DCA templates - if (dau1.Pt() >= DCATemplateEdges[jj] && dau1.Pt() < DCATemplateEdges[jj + 1]) { - treeWords.fd1DCA = fh_DCAtemplates[jj]->GetRandom(); - } - if (dau2.Pt() >= DCATemplateEdges[jj] && dau2.Pt() < DCATemplateEdges[jj + 1]) { - treeWords.fd2DCA = fh_DCAtemplates[jj]->GetRandom(); - } - } - treeWords.fpairDCA = sqrt((pow(treeWords.fd1DCA, 2) + pow(treeWords.fd2DCA, 2)) / 2); - - // Fill tree words after resolution/acceptance - ee = dau1 + dau2; - treeWords.fd1p = dau1.P(); - treeWords.fd1phi = dau1.Phi(); - treeWords.fd2p = dau2.P(); - treeWords.fd2phi = dau2.Phi(); - treeWords.feept = ee.Pt(); - treeWords.feemt = ee.Mt(); - treeWords.feep = ee.P(); - treeWords.feem = ee.M(); - treeWords.feeeta = ee.Eta(); - treeWords.feerap = ee.Rapidity(); - treeWords.feephi = ee.Phi(); - if (mctrack.GetPdgCode() > 0) { - treeWords.feephiv = PhiV(dau1, dau2); - } else { - treeWords.feephiv = PhiV(dau2, dau1); - } - treeWords.fmotherpt = mother.GetPt(); - treeWords.fmotherm = sqrt(pow(mother.GetEnergy(), 2) + pow(mother.GetP(), 2)); - treeWords.fmothermt = sqrt(pow(treeWords.fmotherm, 2) + pow(treeWords.fmotherpt, 2)); - treeWords.fmotherp = mother.GetP(); - treeWords.fmothereta = mother.GetEta(); - treeWords.fmotherphi = mother.GetPhi(); - treeWords.fID = mother.GetPdgCode(); - treeWords.fweight = mctrack.getWeight(); // get particle weight from generator - - // get multiplicity based weight: - int iwbin = fhwMultpT->FindBin(treeWords.fmotherpt); - treeWords.fwMultpT = fhwMultpT->GetBinContent(iwbin); // pT weight - treeWords.fwMultpT2 = fhwMultpT2->GetBinContent(iwbin); // pT weight - double min_mT = fhwMultmT->GetBinLowEdge(1); // consider as minimum valid mT value the edge of the weight histo. - if (treeWords.fmothermt > min_mT) { - iwbin = fhwMultmT->FindBin(treeWords.fmothermt); - treeWords.fwMultmT = fhwMultmT->GetBinContent(iwbin); // mT weight - treeWords.fwMultmT2 = fhwMultmT2->GetBinContent(iwbin); // mT weight - } else { - LOGP(error, "Generated particle with mT < Pion mass cannot be weighted"); - treeWords.fwMultmT = 0.; - treeWords.fwMultmT2 = 0.; - } - - // Which ALT weight to use?: - Double_t fwALT = treeWords.fwEffpT; // by default use pt efficiency weight - if (fConfigALTweight == 1) - fwALT = treeWords.fwMultmT; // mT multiplicity weight - if (fConfigALTweight == 11) - fwALT = treeWords.fwMultmT2; // mT multiplicity weight, higher mult - if (fConfigALTweight == 2) - fwALT = treeWords.fwMultpT; // pT multiplicity weight - if (fConfigALTweight == 22) - fwALT = treeWords.fwMultpT2; // pT multiplicity weight, higher mult - - // fill the tree - if (fConfigWriteTTree) { - tree->Fill(); - } + if (p1.Pt() < fConfigMinPt) + return false; + if (p1.Pt() > fConfigMaxPt) + return false; + if (fabs(p1.Eta()) > fConfigMaxEta) + return false; + return true; + } - // fill the histograms - if (treeWords.fdectyp < 4) { // why here <4 and before <5 ??? - for (Int_t jj = 0; jj < 3; jj++) { // fill the different hindex -> particles - if (hindex[jj] > -1) { - fmee_orig[hindex[jj]]->Fill(treeWords.feeorigm, treeWords.fweight); - if (fConfigALTweight == 1 || fConfigALTweight == 11) { - fmotherpT_orig[hindex[jj]]->Fill(treeWords.fmothermt, treeWords.fweight); - } else if (fConfigALTweight == 2 || fConfigALTweight == 22 || fConfigALTweight == 0) { - fmotherpT_orig[hindex[jj]]->Fill(treeWords.fmotherpt, treeWords.fweight); - } - fpteevsmee_orig[hindex[jj]]->Fill(treeWords.feeorigm, treeWords.feept, treeWords.fweight); - fphi_orig[hindex[jj]]->Fill(treeWords.feeorigphi, treeWords.fweight); - frap_orig[hindex[jj]]->Fill(treeWords.feeorigrap, treeWords.fweight); - fmee_orig_wALT[hindex[jj]]->Fill(treeWords.feeorigm, treeWords.fweight * fwALT); - fpteevsmee_orig_wALT[hindex[jj]]->Fill(treeWords.feeorigm, treeWords.feept, treeWords.fweight * fwALT); - if (fConfigALTweight == 1 || fConfigALTweight == 11) { - fmotherpT_orig_wALT[hindex[jj]]->Fill(treeWords.fmothermt, treeWords.fweight * fwALT); - } else if (fConfigALTweight == 2 || fConfigALTweight == 22 || fConfigALTweight == 0) { - fmotherpT_orig_wALT[hindex[jj]]->Fill(treeWords.fmotherpt, treeWords.fweight * fwALT); - } - if (treeWords.fpass) { - fmee[hindex[jj]]->Fill(treeWords.feem, treeWords.fweight); - fpteevsmee[hindex[jj]]->Fill(treeWords.feem, treeWords.feept, treeWords.fweight); - fphi[hindex[jj]]->Fill(treeWords.feephi, treeWords.fweight); - frap[hindex[jj]]->Fill(treeWords.feerap, treeWords.fweight); - registry.fill(HIST("DCAeevsmee"), treeWords.feem, treeWords.fpairDCA, treeWords.fweight); - registry.fill(HIST("DCAeevsptee"), treeWords.feept, treeWords.fpairDCA, treeWords.fweight); - fmee_wALT[hindex[jj]]->Fill(treeWords.feem, treeWords.fweight * fwALT); - fpteevsmee_wALT[hindex[jj]]->Fill(treeWords.feem, treeWords.feept, treeWords.fweight * fwALT); - } - } - } - } + bool isAcceptedPair(ROOT::Math::PtEtaPhiMVector p1, ROOT::Math::PtEtaPhiMVector p2) + { + if (!isAcceptedSingle(p1)) { + return false; + } + if (!isAcceptedSingle(p2)) { + return false; + } + ROOT::Math::PtEtaPhiMVector p12 = p1 + p2; + if (p12.Pt() < fConfigMinPtee) { + return false; + } + if (o2::aod::pwgem::dilepton::utils::pairutil::getOpeningAngle(p1.Px(), p1.Py(), p1.Pz(), p2.Px(), p2.Py(), p2.Pz()) < fConfigMinOpAng) { + return false; + } + if (fabs(p12.Rapidity()) > fConfigMaxRapee) { + return false; + } - if (fConfigDoVirtPh) { - // Virtual photon generation - //------------------------- - // We will generate one virtual photon per histogrammed pion - if (mother.GetPdgCode() == 111) { - // get mass and pt from histos and flat eta and phi - Double_t VPHpT = ffVPHpT->GetRandom(); - Double_t VPHmass = fhKW->GetRandom(); - Double_t VPHeta = -1. + gRandom->Rndm() * 2.; - Double_t VPHphi = 2.0 * TMath::ACos(-1.) * gRandom->Rndm(); - TLorentzVector beam; - beam.SetPtEtaPhiM(VPHpT, VPHeta, VPHphi, VPHmass); - Double_t decaymasses[2] = {(TDatabasePDG::Instance()->GetParticle(11))->Mass(), (TDatabasePDG::Instance()->GetParticle(11))->Mass()}; - TGenPhaseSpace VPHgen; - Bool_t SetDecay; - SetDecay = VPHgen.SetDecay(beam, 2, decaymasses); - if (SetDecay == 0) - LOGP(error, "Decay not permitted by kinematics"); - Double_t VPHweight = VPHgen.Generate(); - // get electrons from the decay - TLorentzVector *decay1, *decay2; - decay1 = VPHgen.GetDecay(0); - decay2 = VPHgen.GetDecay(1); - dau1.SetPxPyPzE(decay1->Px(), decay1->Py(), decay1->Pz(), decay1->E()); - dau2.SetPxPyPzE(decay2->Px(), decay2->Py(), decay2->Pz(), decay2->E()); - - // create dielectron before resolution effects: - ee = dau1 + dau2; - - // get index for histograms - hindex[0] = nInputParticles - 1; - hindex[1] = -1; - hindex[2] = -1; - - // Fill tree words before resolution/acceptance - treeWords.fd1origpt = dau1.Pt(); - treeWords.fd1origp = dau1.P(); - treeWords.fd1origeta = dau1.Eta(); - treeWords.fd1origphi = dau1.Phi(); - treeWords.fd2origpt = dau2.Pt(); - treeWords.fd2origp = dau2.P(); - treeWords.fd2origeta = dau2.Eta(); - treeWords.fd2origphi = dau2.Phi(); - treeWords.feeorigpt = ee.Pt(); - treeWords.feeorigp = ee.P(); - treeWords.feeorigm = ee.M(); - treeWords.feeorigeta = ee.Eta(); - treeWords.feeorigrap = ee.Rapidity(); - treeWords.feeorigphi = ee.Phi(); - treeWords.feeorigphiv = PhiV(dau1, dau2); - - // get the efficiency weight - Int_t effbin = fhwEffpT->FindBin(treeWords.fd1origpt); - treeWords.fwEffpT = fhwEffpT->GetBinContent(effbin); - effbin = fhwEffpT->FindBin(treeWords.fd2origpt); - treeWords.fwEffpT = treeWords.fwEffpT * fhwEffpT->GetBinContent(effbin); - - // Resolution and acceptance - //------------------------- - dau1 = applySmearingPxPyPzE(1, dau1); - dau2 = applySmearingPxPyPzE(-1, dau2); - treeWords.fpass = true; - if (dau1.Pt() < fConfigMinPt || dau2.Pt() < fConfigMinPt) - treeWords.fpass = false; // leg pT cut - if (dau1.Pt() > fConfigMaxPt || dau2.Pt() > fConfigMaxPt) - treeWords.fpass = false; // leg pT cut - if (dau1.Vect().Unit().Dot(dau2.Vect().Unit()) > TMath::Cos(fConfigMinOpAng)) - treeWords.fpass = false; // opening angle cut - if (TMath::Abs(dau1.Eta()) > fConfigMaxEta || TMath::Abs(dau2.Eta()) > fConfigMaxEta) - treeWords.fpass = false; - - treeWords.fpairDCA = 10000.; // ?? - - // Fill tree words after resolution/acceptance - ee = dau1 + dau2; - treeWords.fd1pt = dau1.Pt(); - treeWords.fd1p = dau1.P(); - treeWords.fd1eta = dau1.Eta(); - treeWords.fd1phi = dau1.Phi(); - treeWords.fd2pt = dau2.Pt(); - treeWords.fd2p = dau2.P(); - treeWords.fd2eta = dau2.Eta(); - treeWords.fd2phi = dau2.Phi(); - treeWords.feept = ee.Pt(); - treeWords.feemt = ee.Mt(); - treeWords.feep = ee.P(); - treeWords.feem = ee.M(); - treeWords.feeeta = ee.Eta(); - treeWords.feerap = ee.Rapidity(); - treeWords.feephi = ee.Phi(); - treeWords.feephiv = PhiV(dau1, dau2); - treeWords.fmotherpt = beam.Pt(); - treeWords.fmothermt = sqrt(pow(beam.M(), 2) + pow(beam.Pt(), 2)); - treeWords.fmotherp = beam.P(); - treeWords.fmotherm = beam.M(); - treeWords.fmothereta = beam.Eta(); - treeWords.fmotherphi = beam.Phi(); - treeWords.fID = 0; // set ID to Zero for VPH - treeWords.fweight = VPHweight; - // get multiplicity based weight: - treeWords.fwMultmT = 1; // no weight for photons so far - - // Fill the tree - if (fConfigWriteTTree) { // many parameters not set for photons: d1DCA,fd2DCA, fdectyp,fdau3pdg,fwMultpT,fwMultpT2,fwMultmT2 - tree->Fill(); - } - - // Fill the histograms - for (Int_t jj = 0; jj < 3; jj++) { // fill the different hindex -> particles - if (hindex[jj] > -1) { - fmee_orig[hindex[jj]]->Fill(treeWords.feeorigm, VPHweight); - fpteevsmee_orig[hindex[jj]]->Fill(treeWords.feeorigm, treeWords.feept, VPHweight); - fphi_orig[hindex[jj]]->Fill(treeWords.feeorigphi, VPHweight); - frap_orig[hindex[jj]]->Fill(treeWords.feeorigrap, VPHweight); - fmotherpT_orig[hindex[jj]]->Fill(treeWords.fmotherpt, treeWords.fweight); - if (treeWords.fpass) { - fmee[hindex[jj]]->Fill(treeWords.feem, VPHweight); - fpteevsmee[hindex[jj]]->Fill(treeWords.feem, treeWords.feept, VPHweight); - fphi[hindex[jj]]->Fill(treeWords.feephi, VPHweight); - frap[hindex[jj]]->Fill(treeWords.feerap, VPHweight); - } - } - } - - } // mother.pdgCode()==111 - } // fConfigDoVirtPh - - } // abs(pdgCode())==11 - - } // loop over mctracks - - // Clear buffers - eBuff.clear(); - echBuff.clear(); - eweightBuff.clear(); + float deta = p1.Eta() - p2.Eta(); + float dphi = p1.Phi() - p2.Phi(); + o2::math_utils::bringToPMPi(dphi); + if (fConfigApplyDEtaDPhi && std::pow(deta / fConfigMinDEta, 2) + std::pow(dphi / fConfigMinDPhi, 2) < 1.f) { + return false; } + return true; } - Double_t PhiV(PxPyPzEVector e1, PxPyPzEVector e2) + template + bool isAcceptedPair(T& p1, T& p2) { - Double_t outPhiV; - XYZVector p1 = e1.Vect(); - XYZVector p2 = e2.Vect(); - XYZVector p12 = p1 + p2; - XYZVector u = p12.Unit(); - XYZVector p1u = p1.Unit(); - XYZVector p2u = p2.Unit(); - XYZVector v = p1u.Cross(p2u); - XYZVector w = u.Cross(v); - XYZVector zu(0, 0, 1); - XYZVector wc = u.Cross(zu); - outPhiV = TMath::ACos(wc.Unit().Dot(w.Unit())); - return outPhiV; + ROOT::Math::PtEtaPhiMVector v1(p1.ptSmeared(), p1.etaSmeared(), p1.phiSmeared(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(p2.ptSmeared(), p2.etaSmeared(), p2.phiSmeared(), o2::constants::physics::MassElectron); + return isAcceptedPair(v1, v2); } - PxPyPzEVector applySmearingPxPyPzE(int ch, PxPyPzEVector vec) + template + bool isAcceptedSingle(T& p1) { - PxPyPzEVector vecsmeared; - float ptsmeared, etasmeared, phismeared; - smearer.applySmearing(ch, vec.Pt(), vec.Eta(), vec.Phi(), ptsmeared, etasmeared, phismeared); - float sPx = ptsmeared * cos(phismeared); - float sPy = ptsmeared * sin(phismeared); - float sPz = ptsmeared * sinh(etasmeared); - float sP = ptsmeared * cosh(etasmeared); - float sE = sqrt(sP * sP + eMass * eMass); - - vecsmeared.SetPxPyPzE(sPx, sPy, sPz, sE); - - return vecsmeared; + ROOT::Math::PtEtaPhiMVector v1(p1.ptSmeared(), p1.etaSmeared(), p1.phiSmeared(), o2::constants::physics::MassElectron); + return isAcceptedSingle(v1); } - void SetHistograms() + void addHistogram1D_stage(TString histname, AxisSpec axis, int& i, TString s) { - - AxisSpec ptAxis = {fConfigNBinsPtee, fConfigMinPtee, fConfigMaxPtee, "#it{p}_{T,ee} (GeV/c)"}; - AxisSpec mAxis = {fConfigNBinsMee, fConfigMinMee, fConfigMaxMee, "#it{m}_{ee} (GeV/c^{2})"}; - AxisSpec phiAxis = {fConfigNBinsPhi, -TMath::TwoPi() / 2, TMath::TwoPi() / 2, "#it{phi}_{ee}"}; - AxisSpec rapAxis = {fConfigNBinsRap, -fConfigMaxAbsRap, fConfigMaxAbsRap, "#it{y}_{ee}"}; - - registry.add("NEvents", "NEvents", HistType::kTH1F, {{1, 0, 1}}, false); - - if (fConfigDoPairing) { - registry.add("ULS", "ULS", HistType::kTH2F, {mAxis, ptAxis}, true); - registry.add("LSpp", "LSpp", HistType::kTH2F, {mAxis, ptAxis}, true); - registry.add("LSmm", "LSmm", HistType::kTH2F, {mAxis, ptAxis}, true); - - registry.add("ULS_orig", "ULS_orig", HistType::kTH2F, {mAxis, ptAxis}, true); - registry.add("LSpp_orig", "LSpp_orig", HistType::kTH2F, {mAxis, ptAxis}, true); - registry.add("LSmm_orig", "LSmm_orig", HistType::kTH2F, {mAxis, ptAxis}, true); + i++; + TString name = s + histname; + histogramId[name] = i; + histograms1D.push_back(registry.add(name, histname, HistType::kTH1F, {axis}, true)); + for (auto const& [pdg, meson] : mesons) { + i++; + name = s + meson.name + histname; + histogramId[name] = i; + histograms1D.push_back(registry.add(name, histname, HistType::kTH1F, {axis}, true)); + for (auto const& mode : meson.decayModes) { + i++; + name = s + meson.name + decays[mode] + histname; + histogramId[name] = i; + histograms1D.push_back(registry.add(name, histname, HistType::kTH1F, {axis}, true)); + } } + } - registry.add("DCAeevsmee", "DCAeevsmee", HistType::kTH2F, {{fConfigMBins, "#it{m}_{ee} (GeV/c^{2})"}, {fConfigDCABins, "DCA_{xy}^{ee} (cm)"}}, true); - registry.add("DCAeevsptee", "DCAeevsptee", HistType::kTH2F, {{fConfigPtBins, "#it{p}_{T,ee} (GeV/c)"}, {fConfigDCABins, "DCA_{xy}^{ee} (cm)"}}, true); - - for (auto& particle : fParticleListNames) { - fmee.push_back(registry.add(Form("mee_%s", particle.Data()), Form("mee_%s", particle.Data()), HistType::kTH1F, {mAxis}, true)); - fmee_orig.push_back(registry.add(Form("mee_orig_%s", particle.Data()), Form("mee_orig_%s", particle.Data()), HistType::kTH1F, {mAxis}, true)); - fmotherpT_orig.push_back(registry.add(Form("motherpT_orig_%s", particle.Data()), Form("motherpT_orig_%s", particle.Data()), HistType::kTH1F, {ptAxis}, true)); - fphi.push_back(registry.add(Form("phi_%s", particle.Data()), Form("phi_%s", particle.Data()), HistType::kTH1F, {phiAxis}, true)); - fphi_orig.push_back(registry.add(Form("phi_orig_%s", particle.Data()), Form("phi_orig_%s", particle.Data()), HistType::kTH1F, {phiAxis}, true)); - frap.push_back(registry.add(Form("rap_%s", particle.Data()), Form("rap_%s", particle.Data()), HistType::kTH1F, {rapAxis}, true)); - frap_orig.push_back(registry.add(Form("rap_orig_%s", particle.Data()), Form("rap_orig_%s", particle.Data()), HistType::kTH1F, {rapAxis}, true)); - fpteevsmee.push_back(registry.add(Form("pteevsmee_%s", particle.Data()), Form("pteevsmee_%s", particle.Data()), HistType::kTH2F, {mAxis, ptAxis}, true)); - fpteevsmee_orig.push_back(registry.add(Form("pteevsmee_orig_%s", particle.Data()), Form("pteevsmee_orig_%s", particle.Data()), HistType::kTH2F, {mAxis, ptAxis}, true)); - fmee_wALT.push_back(registry.add(Form("mee_wALT_%s", particle.Data()), Form("mee_wALT_%s", particle.Data()), HistType::kTH1F, {mAxis}, true)); - fmee_orig_wALT.push_back(registry.add(Form("mee_orig_wALT_%s", particle.Data()), Form("mee_orig_wALT_%s", particle.Data()), HistType::kTH1F, {mAxis}, true)); - fmotherpT_orig_wALT.push_back(registry.add(Form("motherpT_orig_wALT_%s", particle.Data()), Form("motherpT_orig_wALT%s", particle.Data()), HistType::kTH1F, {ptAxis}, true)); - fpteevsmee_wALT.push_back(registry.add(Form("pteevsmee_wALT%s", particle.Data()), Form("pteevsmee_wALT_%s", particle.Data()), HistType::kTH2F, {mAxis, ptAxis}, true)); - fpteevsmee_orig_wALT.push_back(registry.add(Form("pteevsmee_orig_wALT%s", particle.Data()), Form("pteevsmee_orig_wALT_%s", particle.Data()), HistType::kTH2F, {mAxis, ptAxis}, true)); + void addHistogram1D(TString histname, AxisSpec axis, int& i) + { + for (auto s : stage) { + addHistogram1D_stage(histname, axis, i, s); } - - fmee.push_back(registry.add("mee", "mee", HistType::kTH1F, {mAxis}, true)); - fmee_orig.push_back(registry.add("mee_orig", "mee_orig", HistType::kTH1F, {mAxis}, true)); - fmotherpT_orig.push_back(registry.add("motherpT_orig", "motherpT_orig", HistType::kTH1F, {ptAxis}, true)); - fphi.push_back(registry.add("phi", "phi", HistType::kTH1F, {phiAxis}, true)); - fphi_orig.push_back(registry.add("phi_orig", "phi_orig", HistType::kTH1F, {phiAxis}, true)); - frap.push_back(registry.add("rap", "rap", HistType::kTH1F, {rapAxis}, true)); - frap_orig.push_back(registry.add("rap_orig", "rap_orig", HistType::kTH1F, {rapAxis}, true)); - fpteevsmee.push_back(registry.add("pteevsmee", "pteevsmee", HistType::kTH2F, {mAxis, ptAxis}, true)); - fpteevsmee_orig.push_back(registry.add("pteevsmee_orig", "pteevsmee_orig", HistType::kTH2F, {mAxis, ptAxis}, true)); - fmee_wALT.push_back(registry.add("mee_wALT", "mee_wALT", HistType::kTH1F, {mAxis}, true)); - fmee_orig_wALT.push_back(registry.add("mee_orig_wALT", "mee_orig_wALT", HistType::kTH1F, {mAxis}, true)); - fmotherpT_orig_wALT.push_back(registry.add("motherpT_orig_wALT", "motherpT_orig_wALT", HistType::kTH1F, {ptAxis}, true)); - fpteevsmee_wALT.push_back(registry.add("pteevsmee_wALT", "pteevsmee_wALT", HistType::kTH2F, {mAxis, ptAxis}, true)); - fpteevsmee_orig_wALT.push_back(registry.add("pteevsmee_orig_wALT", "pteevsmee_orig_wALT", HistType::kTH2F, {mAxis, ptAxis}, true)); } - void SetTree() + void addHistogram1D_mother(TString histname, AxisSpec axis, int& i) // mother histograms only for gen. level, no decay channels { - tree.setObject(new TTree("eeTTree", "eeTTree")); - - tree->Branch("fd1DCA", &treeWords.fd1DCA, "fd1DCA/F"); - tree->Branch("fd2DCA", &treeWords.fd2DCA, "fd2DCA/F"); - tree->Branch("fpairDCA", &treeWords.fpairDCA, "fpairDCA/F"); - tree->Branch("fd1origpt", &treeWords.fd1origpt, "fd1origpt/F"); - tree->Branch("fd1origp", &treeWords.fd1origp, "fd1origp/F"); - tree->Branch("fd1origeta", &treeWords.fd1origeta, "fd1origeta/F"); - tree->Branch("fd1origphi", &treeWords.fd1origphi, "fd1origphi/F"); - tree->Branch("fd2origpt", &treeWords.fd2origpt, "fd2origpt/F"); - tree->Branch("fd2origp", &treeWords.fd2origp, "fd2origp/F"); - tree->Branch("fd2origeta", &treeWords.fd2origeta, "fd2origeta/F"); - tree->Branch("fd2origphi", &treeWords.fd2origphi, "fd2origphi/F"); - tree->Branch("fd1pt", &treeWords.fd1pt, "fd1pt/F"); - tree->Branch("fd1p", &treeWords.fd1p, "fd1p/F"); - tree->Branch("fd1eta", &treeWords.fd1eta, "fd1eta/F"); - tree->Branch("fd1phi", &treeWords.fd1phi, "fd1phi/F"); - tree->Branch("fd2pt", &treeWords.fd2pt, "fd2pt/F"); - tree->Branch("fd2p", &treeWords.fd2p, "fd2p/F"); - tree->Branch("fd2eta", &treeWords.fd2eta, "fd2eta/F"); - tree->Branch("fd2phi", &treeWords.fd2phi, "fd2phi/F"); - tree->Branch("feeorigpt", &treeWords.feeorigpt, "feeorigpt/F"); - tree->Branch("feeorigp", &treeWords.feeorigp, "feeorigp/F"); - tree->Branch("feeorigm", &treeWords.feeorigm, "feeorigm/F"); - tree->Branch("feeorigeta", &treeWords.feeorigeta, "feeorigeta/F"); - tree->Branch("feeorigphi", &treeWords.feeorigphi, "feeorigphi/F"); - tree->Branch("feeorigphiv", &treeWords.feeorigphiv, "feeorigphiv/F"); - tree->Branch("feept", &treeWords.feept, "feept/F"); - tree->Branch("feemt", &treeWords.feemt, "feemt/F"); - tree->Branch("feep", &treeWords.feep, "feep/F"); - tree->Branch("feem", &treeWords.feem, "feem/F"); - tree->Branch("feeeta", &treeWords.feeeta, "feeeta/F"); - tree->Branch("feephi", &treeWords.feephi, "feephi/F"); - tree->Branch("feephiv", &treeWords.feephiv, "feephiv/F"); - tree->Branch("fmotherpt", &treeWords.fmotherpt, "fmotherpt/F"); - tree->Branch("fmothermt", &treeWords.fmothermt, "fmothermt/F"); - tree->Branch("fmotherp", &treeWords.fmotherp, "fmotherp/F"); - tree->Branch("fmotherm", &treeWords.fmotherm, "fmotherm/F"); - tree->Branch("fmothereta", &treeWords.fmothereta, "fmothereta/F"); - tree->Branch("fmotherphi", &treeWords.fmotherphi, "fmotherphi/F"); - tree->Branch("fID", &treeWords.fID, "fID/I"); - tree->Branch("fdectyp", &treeWords.fdectyp, "fdectyp/I"); - tree->Branch("fdau3pdg", &treeWords.fdau3pdg, "fdau3pdg/I"); - tree->Branch("fweight", &treeWords.fweight, "fweight/F"); - tree->Branch("fwEffpT", &treeWords.fwEffpT, "fwEffpT/F"); - tree->Branch("fwMultpT", &treeWords.fwMultpT, "fwMultpT/F"); - tree->Branch("fwMultmT", &treeWords.fwMultmT, "fwMultmT/F"); - tree->Branch("fwMultpT2", &treeWords.fwMultpT2, "fwMultpT2/F"); - tree->Branch("fwMultmT2", &treeWords.fwMultmT2, "fwMultmT2/F"); - tree->Branch("fpass", &treeWords.fpass, "fpass/B"); + i++; + TString name = stage[0] + histname; + histogramId[name] = i; + histograms1D.push_back(registry.add(name, histname, HistType::kTH1F, {axis}, true)); + for (auto const& [pdg, meson] : mesons) { + i++; + name = stage[0] + meson.name + histname; + histogramId[name] = i; + histograms1D.push_back(registry.add(name, histname, HistType::kTH1F, {axis}, true)); + } } - void GetEffHisto(TString filename, TString histname) + void addHistogram2D_stage(TString histname, AxisSpec axis1, AxisSpec axis2, int& i, TString s) { - // get efficiency histo - LOGP(info, "Set Efficiency histo"); - // Get Efficiency weight file: - TFile* fFile = TFile::Open(filename.Data()); - if (!fFile) { - LOGP(error, "Could not open Efficiency file {}", filename.Data()); - return; - } - if (fFile->GetListOfKeys()->Contains(histname.Data())) { - fhwEffpT = reinterpret_cast(fFile->Get(histname.Data())); // histo: eff weight in function of pT. - fhwEffpT->SetDirectory(nullptr); - } else { - LOGP(error, "Could not open histogram {} from file {}", histname.Data(), filename.Data()); + i++; + TString name = s + histname; + histogramId[name] = i; + histograms2D.push_back(registry.add(name, histname, HistType::kTH2F, {axis1, axis2}, true)); + for (auto const& [pdg, meson] : mesons) { + i++; + name = s + meson.name + histname; + histogramId[name] = i; + histograms2D.push_back(registry.add(name, histname, HistType::kTH2F, {axis1, axis2}, true)); + for (auto const& mode : meson.decayModes) { + i++; + name = s + meson.name + decays[mode] + histname; + histogramId[name] = i; + histograms2D.push_back(registry.add(name, histname, HistType::kTH2F, {axis1, axis2}, true)); + } } - - fFile->Close(); } - void InitSmearer(TString filename, TString ptHistName, TString etaHistName, TString phiPosHistName, TString phiNegHistName) + void addHistogram2D(TString histname, AxisSpec axis1, AxisSpec axis2, int& i) { - smearer.setResFileName(filename); - smearer.setResPtHistName(ptHistName); - smearer.setResEtaHistName(etaHistName); - smearer.setResPhiPosHistName(phiPosHistName); - smearer.setResPhiNegHistName(phiNegHistName); - smearer.init(); + for (auto s : stage) { + addHistogram2D_stage(histname, axis1, axis2, i, s); + } } - void GetDCATemplates(TString filename, TString histname) + template + void addHistogramND_stage(TString histname, TAxes const& axes, int& i, TString s) { - // get dca tamplates - LOGP(info, "Set DCA templates"); - // Get file: - TFile* fFile = TFile::Open(filename.Data()); - if (!fFile) { - LOGP(error, "Could not open DCATemplate file {}", filename.Data()); - return; - } - fh_DCAtemplates = new TH1F*[nbDCAtemplate]; - for (int jj = 0; jj < nbDCAtemplate; jj++) { - if (fFile->GetListOfKeys()->Contains(Form("%s%d", histname.Data(), jj + 1))) { - fh_DCAtemplates[jj] = reinterpret_cast(fFile->Get(Form("%s%d", histname.Data(), jj + 1))); - } else { - LOGP(error, "Could not open {}{} from file {}", histname.Data(), jj + 1, filename.Data()); + i++; + TString name = s + histname; + histogramId[name] = i; + histogramsND.push_back(registry.add(name, histname, HistType::kTHnSparseF, axes, true)); + for (auto const& [pdg, meson] : mesons) { + i++; + name = s + meson.name + histname; + histogramId[name] = i; + histogramsND.push_back(registry.add(name, histname, HistType::kTHnSparseF, axes, true)); + for (auto const& mode : meson.decayModes) { + i++; + name = s + meson.name + decays[mode] + histname; + histogramId[name] = i; + histogramsND.push_back(registry.add(name, histname, HistType::kTHnSparseF, axes, true)); } } - fFile->Close(); } - void GetMultHisto(TString filename, TString histnamept, TString histnamept2, TString histnamemt, TString histnamemt2) + template + void addHistogramND(TString histname, TAxes const& axes, int& i) { - // get multiplicity weights - LOGP(info, "Set Multiplicity weight files"); - TFile* fFile = TFile::Open(filename.Data()); - if (!fFile) { - LOGP(error, "Could not open Multiplicity weight file {}", filename.Data()); - return; + for (auto s : stage) { + addHistogramND_stage(histname, axes, i, s); } + } - if (fFile->GetListOfKeys()->Contains(histnamept.Data())) { - fhwMultpT = reinterpret_cast(fFile->Get(histnamept.Data())); // histo: multiplicity weight in function of pT. - } else { - LOGP(error, "Could not open {} from file {}", histnamept.Data(), filename.Data()); - } + void fillHistogram1D(TString histname, int s, int pdg, int other_daughter_pdg, float value, float weight) + { + histograms1D[histogramId[stage[s] + histname]]->Fill(value, weight); + histograms1D[histogramId[stage[s] + mesons[pdg].name + histname]]->Fill(value, weight); + histograms1D[histogramId[stage[s] + mesons[pdg].name + decays[other_daughter_pdg] + histname]]->Fill(value, weight); + } - if (fFile->GetListOfKeys()->Contains(histnamemt.Data())) { - fhwMultmT = reinterpret_cast(fFile->Get(histnamemt.Data())); // histo: multiplicity weight in function of mT. - } else { - LOGP(error, "Could not open {} from file {}", histnamemt.Data(), filename.Data()); - } + void fillHistogram1D_mother(TString histname, int pdg, float value, float weight) + { + histograms1D[histogramId[stage[0] + histname]]->Fill(value, weight); + histograms1D[histogramId[stage[0] + mesons[pdg].name + histname]]->Fill(value, weight); + } - if (fFile->GetListOfKeys()->Contains(histnamept2.Data())) { - fhwMultpT2 = reinterpret_cast(fFile->Get(histnamept2.Data())); // histo: multiplicity weight in function of pT. - } else { - LOGP(error, "Could not open {} from file {}", histnamept2.Data(), filename.Data()); - } + void fillHistogram2D(TString histname, int s, int pdg, int other_daughter_pdg, float value1, float value2, float weight) + { + histograms2D[histogramId[stage[s] + histname]]->Fill(value1, value2, weight); + histograms2D[histogramId[stage[s] + mesons[pdg].name + histname]]->Fill(value1, value2, weight); + histograms2D[histogramId[stage[s] + mesons[pdg].name + decays[other_daughter_pdg] + histname]]->Fill(value1, value2, weight); + } + + void fillHistogramND(TString histname, int s, int pdg, int other_daughter_pdg, double* values, double weight) + { + histogramsND[histogramId[stage[s] + histname]]->Fill(values, weight); + histogramsND[histogramId[stage[s] + mesons[pdg].name + histname]]->Fill(values, weight); + histogramsND[histogramId[stage[s] + mesons[pdg].name + decays[other_daughter_pdg] + histname]]->Fill(values, weight); + } - if (fFile->GetListOfKeys()->Contains(histnamemt2.Data())) { - fhwMultmT2 = reinterpret_cast(fFile->Get(histnamemt2)); // histo: multiplicity weight in function of mT. - } else { - LOGP(error, "Could not open {} from file {}", histnamemt2.Data(), filename.Data()); + void init(InitContext& context) + { + registry.add("NEvents", "NEvents", HistType::kTH1F, {{1, 0., 1.}}, false); + + AxisSpec mass_axis = {fConfigMeeBins, "m_{ee} (GeV/#it{c}^{2})"}; + AxisSpec ptee_axis = {fConfigPteeBins, "#it{p}_{T,ee} (GeV/#it{c})"}; + AxisSpec cos2dphi_axis = {fConfigCos2DPhi, "cos(2(#varphi_{ee} - #Psi_{RP}))"}; // PsiRP = 0 rad. in generator. + AxisSpec eta_axis = {fConfigEtaBins, "#it{#eta}_{e}"}; + AxisSpec pt_axis = {fConfigPtBins, "#it{p}_{T,e} (GeV/c)"}; + AxisSpec phi_axis = {fConfigPhiBins, "#it{#varphi}_{e}"}; + AxisSpec phiV_axis = {fConfigPhiVBins, "#it{#varphi}_{V,ee}"}; + AxisSpec opAng_axis = {fConfigOpAngBins, "#it{#omega}_{ee}"}; + AxisSpec eta_axis_mother = {fConfigEtaBins, "#it{#eta}_{mother}"}; + AxisSpec pt_axis_mother = {fConfigPtBins, "#it{p}_{T,mother} (GeV/#it{c})"}; + AxisSpec phi_axis_mother = {fConfigPhiBins, "#it{#varphi}_{mother}"}; + AxisSpec dca_axis = {fConfigDcaBins, "DCA_{e}"}; + AxisSpec dcaee_axis = {fConfigDcaBins, "DCA_{ee}"}; + + if (context.mOptions.get("processPairing")) { + registry.add("gen/ULS", "ULS gen.", HistType::kTH2F, {mass_axis, ptee_axis}, true); + registry.add("gen/LSpp", "LS++ gen.", HistType::kTH2F, {mass_axis, ptee_axis}, true); + registry.add("gen/LSmm", "LS-- gen.", HistType::kTH2F, {mass_axis, ptee_axis}, true); + registry.add("rec/ULS", "ULS rec.", HistType::kTH2F, {mass_axis, ptee_axis}, true); + registry.add("rec/LSpp", "LS++ rec.", HistType::kTH2F, {mass_axis, ptee_axis}, true); + registry.add("rec/LSmm", "LS-- rec.", HistType::kTH2F, {mass_axis, ptee_axis}, true); + } + if (context.mOptions.get("processCocktail")) { + int i = -1; + addHistogram1D("Pt", pt_axis, i); + addHistogram1D("Eta", eta_axis, i); + addHistogram1D("Phi", phi_axis, i); + addHistogram1D_mother("Mother_Pt", pt_axis_mother, i); + addHistogram1D_mother("Mother_Eta", eta_axis_mother, i); + addHistogram1D_mother("Mother_Phi", phi_axis_mother, i); + addHistogram1D("PhiV", phiV_axis, i); + addHistogram1D("OpAng", opAng_axis, i); + addHistogram1D("Mee", mass_axis, i); + addHistogram1D("Ptee", ptee_axis, i); + // addHistogram1D_stage("Dca", dca_axis, i, "rec/"); + // addHistogram1D_stage("Dcaee", dcaee_axis, i, "rec/"); + i = -1; + // addHistogram2D_stage("DcaVsPt", dca_axis, pt_axis, i, "rec/"); + // addHistogram2D_stage("DcaeeVsPtee", dcaee_axis, ptee_axis, i, "rec/"); + // addHistogram2D_stage("DcaeeVsMee", dcaee_axis, mass_axis, i, "rec/"); + i = -1; + addHistogramND("MeeVsPteeVsCos2DPhiRP", std::vector{mass_axis, ptee_axis, cos2dphi_axis}, i); } - fFile->Close(); } - void GetPhotonPtParametrization(TString filename, TString dirname, TString funcname) + void processCocktail(aod::McCollision const&, McParticlesSmeared const& mcParticles) { - LOGP(info, "Set photon parametrization"); + registry.fill(HIST("NEvents"), 0.5); - if (filename.EndsWith(".root")) { // read from ROOT file - TFile* fFile = TFile::Open(filename.Data()); - if (!fFile) { - LOGP(error, "Could not open photon parametrization from file {}", filename.Data()); - return; + for (auto const& particle : mcParticles) { + if (particle.has_mothers()) { + continue; + } + int pdg = abs(particle.pdgCode()); + if (mesons.find(pdg) == mesons.end()) { + LOG(error) << "Found mother particle with pdg = " << pdg << " that is not in list of mesons"; + } + if (!particle.has_daughters()) { + LOG(error) << "Found meson with pdg = " << pdg << "that has no daughters"; } - bool good = false; - if (fFile->GetListOfKeys()->Contains(dirname.Data())) { - TDirectory* dir = fFile->GetDirectory(dirname.Data()); - if (dir->GetListOfKeys()->Contains(funcname.Data())) { - ffVPHpT = reinterpret_cast(dir->Get(funcname.Data())); - ffVPHpT->SetNpx(10000); - good = true; + + int other_daughter_pdg = -1; + int nEle = 0; + int nPos = 0; + + ROOT::Math::PtEtaPhiMVector pEleGen, pPosGen, pEleRec, pPosRec; + float weight(1.), effEle(1.), effPos(1.); //, dcaEle(0.), dcaPos(0.); + for (const auto& daughter : particle.daughters_as()) { + int temp_pdg = daughter.pdgCode(); + if (temp_pdg == 11) { + ROOT::Math::PtEtaPhiMVector temp_p_gen(daughter.pt(), daughter.eta(), daughter.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector temp_p(daughter.ptSmeared(), daughter.etaSmeared(), daughter.phiSmeared(), o2::constants::physics::MassElectron); + pEleGen = temp_p_gen; + pEleRec = temp_p; + weight = daughter.weight(); + effEle = daughter.efficiency(); + // dcaEle = daughter.dca(); + nEle++; + continue; + } + if (temp_pdg == -11) { + ROOT::Math::PtEtaPhiMVector temp_p_gen(daughter.pt(), daughter.eta(), daughter.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector temp_p(daughter.ptSmeared(), daughter.etaSmeared(), daughter.phiSmeared(), o2::constants::physics::MassElectron); + pPosGen = temp_p_gen; + pPosRec = temp_p; + effPos = daughter.efficiency(); + // dcaPos = daughter.dca(); + nPos++; + continue; } + other_daughter_pdg = abs(other_daughter_pdg * temp_pdg); + } + if (!(((nEle == 1) && (nPos == 1)) || ((nEle == 2) && (nPos == 2)))) { + LOG(error) << "Found decay with wrong number of electrons in decay of meson with pdg " << pdg << ": nElectrons = " << nEle << ", nPositrons = " << nPos; + continue; } - if (!good) { - LOGP(error, "Could not open photon parametrization {}/{} from file {}", dirname.Data(), funcname.Data(), filename.Data()); + if ((nEle == 2) && (nPos == 2) && (other_daughter_pdg == -1)) { + other_daughter_pdg = -2; + weight = 2 * weight; } - fFile->Close(); - } else if (filename.EndsWith(".json")) { // read from JSON file - std::ifstream fFile(filename.Data()); - if (!fFile) { - LOGP(error, "Could not open photon parametrization from file {}", filename.Data()); - return; + auto this_meson_decays = mesons[pdg].decayModes; + if (std::find(this_meson_decays.begin(), this_meson_decays.end(), other_daughter_pdg) == this_meson_decays.end()) { + LOG(error) << "Found decay with code = " << other_daughter_pdg << " that is not in list of decays of meson with pdg " << pdg; + continue; } - nlohmann::json paramfile = nlohmann::json::parse(fFile); - if (paramfile.contains(dirname.Data())) { - nlohmann::json dir = paramfile[dirname.Data()]; - if (dir.contains(funcname.Data())) { - std::string formula = dir[funcname.Data()]; - ffVPHpT = new TF1(TString(funcname.Data()), TString(formula), 0, 100); - if (ffVPHpT) { - ffVPHpT->SetNpx(10000); - return; + + for (int s = 0; s < kNRecLevels; s++) { // s=0: gen, s=1: rec + + ROOT::Math::PtEtaPhiMVector pEle, pPos; + float pairWeight(1.), weightEle(1.), weightPos(1.); + bool acceptedEle(true), acceptedPos(true), acceptedPair(true); + + if (s == kGen) { + pEle = pEleGen; + pPos = pPosGen; + pairWeight = weight; + weightEle = weight; + weightPos = weight; + acceptedEle = true; + acceptedPos = true; + acceptedPair = true; + } else if (s == kRec) { + pEle = pEleRec; + pPos = pPosRec; + pairWeight = weight * effEle * effPos; + weightEle = weight * effEle; + weightPos = weight * effPos; + acceptedEle = isAcceptedSingle(pEle); + acceptedPos = isAcceptedSingle(pPos); + acceptedPair = isAcceptedPair(pEle, pPos); + } + + // single track histograms + if (acceptedEle) + fillHistogram1D("Pt", s, pdg, other_daughter_pdg, pEle.Pt(), weightEle); + if (acceptedPos) + fillHistogram1D("Pt", s, pdg, other_daughter_pdg, pPos.Pt(), weightPos); + + if (acceptedEle) + fillHistogram1D("Eta", s, pdg, other_daughter_pdg, pEle.Eta(), weightEle); + if (acceptedPos) + fillHistogram1D("Eta", s, pdg, other_daughter_pdg, pPos.Eta(), weightPos); + + if (acceptedEle) + fillHistogram1D("Phi", s, pdg, other_daughter_pdg, pEle.Phi(), weightEle); + if (acceptedPos) + fillHistogram1D("Phi", s, pdg, other_daughter_pdg, pPos.Phi(), weightPos); + + if (s == kRec) { // dca only at rec. level + if (acceptedEle) { + // fillHistogram1D("Dca", s, pdg, other_daughter_pdg, dcaEle, weightEle); + // fillHistogram2D("DcaVsPt", s, pdg, other_daughter_pdg, dcaEle, pEle.Pt(), weightEle); + } + if (acceptedPos) { + // fillHistogram1D("Dca", s, pdg, other_daughter_pdg, dcaPos, weightPos); + // fillHistogram2D("DcaVsPt", s, pdg, other_daughter_pdg, dcaPos, pPos.Pt(), weightPos); + } + } + + // mother histograms + if (s == kGen) { // only at gen. level + fillHistogram1D_mother("Mother_Pt", pdg, particle.pt(), weight); + fillHistogram1D_mother("Mother_Eta", pdg, particle.eta(), weight); + fillHistogram1D_mother("Mother_Phi", pdg, particle.phi(), weight); + } + + // pair historams + if (acceptedPair) { + ROOT::Math::PtEtaPhiMVector p12 = pEle + pPos; + float mee = p12.M(); + float ptee = p12.Pt(); + float opAng = o2::aod::pwgem::dilepton::utils::pairutil::getOpeningAngle(pPos.Px(), pPos.Py(), pPos.Pz(), pEle.Px(), pEle.Py(), pEle.Pz()); + float phiV = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pPos.Px(), pPos.Py(), pPos.Pz(), pEle.Px(), pEle.Py(), pEle.Pz(), 1, -1, 1); + // float dcaee = sqrt((pow(dcaEle, 2) + pow(dcaPos, 2)) / 2); + float cos2dphi = std::cos(2.f * p12.Phi()); // PsiRP = 0 rad. + double values[3] = {mee, ptee, cos2dphi}; + fillHistogramND("MeeVsPteeVsCos2DPhiRP", s, pdg, other_daughter_pdg, values, pairWeight); + fillHistogram1D("Mee", s, pdg, other_daughter_pdg, mee, pairWeight); + fillHistogram1D("Ptee", s, pdg, other_daughter_pdg, ptee, pairWeight); + fillHistogram1D("PhiV", s, pdg, other_daughter_pdg, phiV, pairWeight); + fillHistogram1D("OpAng", s, pdg, other_daughter_pdg, opAng, pairWeight); + if (s == kRec) { // dca only at rec. level + // fillHistogram1D("Dcaee", s, pdg, other_daughter_pdg, dcaee, pairWeight); + // fillHistogram2D("DcaeeVsPtee", s, pdg, other_daughter_pdg, dcaee, ptee, pairWeight); + // fillHistogram2D("DcaeeVsMee", s, pdg, other_daughter_pdg, dcaee, mee, pairWeight); } } } - LOGP(error, "Could not open photon parametrization {}/{} from file {}", dirname.Data(), funcname.Data(), filename.Data()); - return; - } else { // neither ROOT nor JSON - LOGP(error, "Not compatible file format for {}", filename.Data()); - } + + } // end particle loop } + PROCESS_SWITCH(lmeelfcocktail, processCocktail, "Process cocktail", true); + + // ULS and LS spectra + Preslice perCollision = aod::mcparticle::mcCollisionId; + Partition Electrons = (aod::mcparticle::pdgCode == 11); + Partition Positrons = (aod::mcparticle::pdgCode == -11); - void fillKrollWada() + void processPairing(aod::McCollisions const& mcCollisions, McParticlesSmeared const& mcParticles) { - // Build Kroll-wada for virtual photon mass parametrization: - Double_t KWmass = 0.; - Int_t KWnbins = 10000; - Float_t KWmin = 2. * eMass; - Double_t KWbinwidth = (fConfigKWMax - KWmin) / (Double_t)KWnbins; - fhKW = new TH1F("fhKW", "fhKW", KWnbins, KWmin, fConfigKWMax); - for (Int_t ibin = 1; ibin <= KWnbins; ibin++) { - KWmass = KWmin + (Double_t)(ibin - 1) * KWbinwidth + KWbinwidth / 2.0; - fhKW->AddBinContent(ibin, 2. * (1. / 137.03599911) / 3. / 3.14159265359 / KWmass * sqrt(1. - 4. * eMass * eMass / KWmass / KWmass) * (1. + 2. * eMass * eMass / KWmass / KWmass)); + + for (auto const& mcCollision : mcCollisions) { + auto const electronsGrouped = Electrons->sliceBy(perCollision, mcCollision.globalIndex()); + auto const positronsGrouped = Positrons->sliceBy(perCollision, mcCollision.globalIndex()); + + // ULS spectrum + for (auto const& [p1, p2] : combinations(o2::soa::CombinationsFullIndexPolicy(electronsGrouped, positronsGrouped))) { + if (!(from_primary(p1, mcParticles) && from_primary(p2, mcParticles))) { + continue; + } + ROOT::Math::PtEtaPhiMVector v1_gen(p1.pt(), p1.eta(), p1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2_gen(p2.pt(), p2.eta(), p2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12_gen = v1_gen + v2_gen; + registry.fill(HIST("gen/ULS"), v12_gen.M(), v12_gen.Pt(), p1.weight() * p2.weight()); + if (isAcceptedPair(p1, p2)) { + ROOT::Math::PtEtaPhiMVector v1(p1.ptSmeared(), p1.etaSmeared(), p1.phiSmeared(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(p2.ptSmeared(), p2.etaSmeared(), p2.phiSmeared(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + registry.fill(HIST("rec/ULS"), v12.M(), v12.Pt(), p1.weight() * p2.weight() * p1.efficiency() * p2.efficiency()); + } + } + // LS spectra + for (auto& [p1, p2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(electronsGrouped, electronsGrouped))) { + if (!(from_primary(p1, mcParticles) && from_primary(p2, mcParticles))) { + continue; + } + ROOT::Math::PtEtaPhiMVector v1_gen(p1.pt(), p1.eta(), p1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2_gen(p2.pt(), p2.eta(), p2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12_gen = v1_gen + v2_gen; + registry.fill(HIST("gen/LSmm"), v12_gen.M(), v12_gen.Pt(), p1.weight() * p2.weight()); + if (isAcceptedPair(p1, p2)) { + ROOT::Math::PtEtaPhiMVector v1(p1.ptSmeared(), p1.etaSmeared(), p1.phiSmeared(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(p2.ptSmeared(), p2.etaSmeared(), p2.phiSmeared(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + registry.fill(HIST("rec/LSmm"), v12.M(), v12.Pt(), p1.weight() * p2.weight() * p1.efficiency() * p2.efficiency()); + } + } + for (auto& [p1, p2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(positronsGrouped, positronsGrouped))) { + if (!(from_primary(p1, mcParticles) && from_primary(p2, mcParticles))) { + continue; + } + ROOT::Math::PtEtaPhiMVector v1_gen(p1.pt(), p1.eta(), p1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2_gen(p2.pt(), p2.eta(), p2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12_gen = v1_gen + v2_gen; + registry.fill(HIST("gen/LSpp"), v12_gen.M(), v12_gen.Pt(), p1.weight() * p2.weight()); + if (isAcceptedPair(p1, p2)) { + ROOT::Math::PtEtaPhiMVector v1(p1.ptSmeared(), p1.etaSmeared(), p1.phiSmeared(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(p2.ptSmeared(), p2.etaSmeared(), p2.phiSmeared(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + registry.fill(HIST("rec/LSpp"), v12.M(), v12.Pt(), p1.weight() * p2.weight() * p1.efficiency() * p2.efficiency()); + } + } } } + PROCESS_SWITCH(lmeelfcocktail, processPairing, "Process ULS and LS pairing", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - WorkflowSpec specs; - std::vector inputs; - inputs.emplace_back("mctracks", "MC", "MCTRACKS", 0., Lifetime::Timeframe); - DataProcessorSpec dSpec = adaptAnalysisTask(cfgc, TaskName{"em-lmee-lf-cocktail"}); - dSpec.inputs = inputs; - specs.emplace_back(dSpec); - return specs; + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName("em-lmee-lf-cocktail"))}; } diff --git a/PWGEM/Dilepton/Tasks/matchingMFT.cxx b/PWGEM/Dilepton/Tasks/matchingMFT.cxx new file mode 100644 index 00000000000..895cbad111a --- /dev/null +++ b/PWGEM/Dilepton/Tasks/matchingMFT.cxx @@ -0,0 +1,540 @@ +// 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 matchingMFT.cxx +/// \brief a task to study matching MFT-[MCH-MID] in MC +/// \author daiki.sekihata@cern.ch + +#include +#include +#include + +#include "Framework/DataTypes.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "TableHelper.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "TGeoGlobalMagField.h" +#include "Field/MagneticField.h" + +#include "DetectorsBase/Propagator.h" +#include "GlobalTracking/MatchGlobalFwd.h" +#include "MCHTracking/TrackExtrap.h" +#include "MCHTracking/TrackParam.h" +#include "ReconstructionDataFormats/TrackFwd.h" + +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/PropagatedFwdTrackTables.h" +#include "Common/Core/fwdtrackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" + +using namespace o2; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; +using namespace o2::aod::fwdtrackutils; + +struct matchingMFT { + using MyCollisions = soa::Join; + using MyFwdTracks = soa::Join; + using MyMFTTracks = soa::Join; + + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable minPt{"minPt", 0.01, "min pt for muon"}; + Configurable maxPt{"maxPt", 1e+10, "max pt for muon"}; + Configurable minEtaSA{"minEtaSA", -4.0, "min. eta acceptance for MCH-MID"}; + Configurable maxEtaSA{"maxEtaSA", -2.5, "max. eta acceptance for MCH-MID"}; + Configurable minEtaGL{"minEtaGL", -3.6, "min. eta acceptance for MFT-MCH-MID"}; + Configurable maxEtaGL{"maxEtaGL", -2.5, "max. eta acceptance for MFT-MCH-MID"}; + Configurable minRabs{"minRabs", 17.6, "min. R at absorber end"}; + Configurable midRabs{"midRabs", 26.5, "middle R at absorber end for pDCA cut"}; + Configurable maxRabs{"maxRabs", 89.5, "max. R at absorber end"}; + Configurable maxDCAxy{"maxDCAxy", 1e+10, "max. DCAxy for global muons"}; + Configurable maxPDCAforLargeR{"maxPDCAforLargeR", 324.f, "max. pDCA for large R at absorber end"}; + Configurable maxPDCAforSmallR{"maxPDCAforSmallR", 594.f, "max. pDCA for small R at absorber end"}; + Configurable maxMatchingChi2MCHMFT{"maxMatchingChi2MCHMFT", 1e+10, "max. chi2 for MCH-MFT matching"}; + Configurable maxChi2SA{"maxChi2SA", 1e+6, "max. chi2 for standalone muon"}; + Configurable maxChi2GL{"maxChi2GL", 1e+6, "max. chi2 for global muon"}; + // Configurable maxChi2MFT{"maxChi2MFT", 1e+6, "max. chi2/ndf for MFT track in global muon"}; + Configurable minNclustersMFT{"minNclustersMFT", 5, "min nclusters MFT"}; + Configurable refitGlobalMuon{"refitGlobalMuon", true, "flag to refit global muon"}; + Configurable requireTrueAssociation{"requireTrueAssociation", false, "flag to require true mc collision association"}; + + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentMin{"cfgCentMin", -1.f, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + + HistogramRegistry fRegistry{"fRegistry"}; + static constexpr std::string_view muon_types[5] = {"MFTMCHMID/", "MFTMCHMIDOtherMatch/", "MFTMCH/", "MCHMID/", "MCH/"}; + + void init(o2::framework::InitContext&) + { + if (doprocessWithoutFTTCA && doprocessWithFTTCA) { + LOGF(fatal, "Cannot enable doprocessWithoutFTTCA and doprocessWithFTTCA at the same time. Please choose one."); + } + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + ccdbApi.init(ccdburl); + + addHistograms(); + } + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + int mRunNumber = -1; + + template + void initCCDB(TBC const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + LOGF(info, "mRunNumber = %d", mRunNumber); + std::map metadata; + auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, mRunNumber); + auto ts = soreor.first; + auto grpmag = ccdbApi.retrieveFromTFileAny(grpmagPath, metadata, ts); + o2::base::Propagator::initFieldFromGRP(grpmag); + if (!o2::base::GeometryManager::isGeometryLoaded()) { + ccdb->get(geoPath); + } + o2::mch::TrackExtrap::setField(); + } + + void addHistograms() + { + auto hCollisionCounter = fRegistry.add("Event/hCollisionCounter", "collision counter", kTH1F, {{5, -0.5f, 4.5f}}, false); + hCollisionCounter->GetXaxis()->SetBinLabel(1, "all"); + hCollisionCounter->GetXaxis()->SetBinLabel(2, "accepted"); + + fRegistry.add("Event/hZvtx", "vertex z; Z_{vtx} (cm)", kTH1F, {{100, -50, +50}}, false); + fRegistry.add("Event/hMultNTracksPV", "hMultNTracksPV; N_{track} to PV", kTH1F, {{6001, -0.5, 6000.5}}, false); + fRegistry.add("Event/hMultNTracksPVeta1", "hMultNTracksPVeta1; N_{track} to PV", kTH1F, {{6001, -0.5, 6000.5}}, false); + fRegistry.add("Event/hMultFT0", "hMultFT0;mult. FT0A;mult. FT0C", kTH2F, {{200, 0, 200000}, {60, 0, 60000}}, false); + fRegistry.add("Event/hCentFT0A", "hCentFT0A;centrality FT0A (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry.add("Event/hCentFT0C", "hCentFT0C;centrality FT0C (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry.add("Event/hCentFT0M", "hCentFT0M;centrality FT0M (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry.add("Event/hCentFT0CvsMultNTracksPV", "hCentFT0CvsMultNTracksPV;centrality FT0C (%);N_{track} to PV", kTH2F, {{110, 0, 110}, {600, 0, 6000}}, false); + fRegistry.add("Event/hMultFT0CvsMultNTracksPV", "hMultFT0CvsMultNTracksPV;mult. FT0C;N_{track} to PV", kTH2F, {{60, 0, 60000}, {600, 0, 6000}}, false); + + auto hMuonType = fRegistry.add("hMuonType", "muon type", kTH1F, {{5, -0.5f, 4.5f}}, false); + hMuonType->GetXaxis()->SetBinLabel(1, "MFT-MCH-MID (global muon)"); + hMuonType->GetXaxis()->SetBinLabel(2, "MFT-MCH-MID (global muon other match)"); + hMuonType->GetXaxis()->SetBinLabel(3, "MFT-MCH"); + hMuonType->GetXaxis()->SetBinLabel(4, "MCH-MID"); + hMuonType->GetXaxis()->SetBinLabel(5, "MCH standalone"); + + fRegistry.add("MFTMCHMID/primary/correct/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{100, 0.0f, 10}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {100, -6.f, -1.f}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hEtaPhi_MatchedMCHMID", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {100, -6.f, -1.f}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hDiffCollId", "difference in collision index;collisionId_{TTCA} - collisionId_{MP}", kTH1F, {{41, -20.5, +20.5}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hSign", "sign;sign", kTH1F, {{3, -1.5, +1.5}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hNclusters", "Nclusters;Nclusters", kTH1F, {{21, -0.5f, 20.5}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hNclustersMFT", "NclustersMFT;Nclusters MFT", kTH1F, {{11, -0.5f, 10.5}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hRatAbsorberEnd", "R at absorber end;R at absorber end (cm)", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hPDCA_Rabs", "pDCA vs. Rabs;R at absorber end (cm);p #times DCA (GeV/c #upoint cm)", kTH2F, {{100, 0, 100}, {100, 0.0f, 1000}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hChi2", "chi2;chi2", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hChi2MFT", "chi2 MFT;chi2 MFT", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hChi2MatchMCHMID", "chi2 match MCH-MID;chi2", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hChi2MatchMCHMFT", "chi2 match MCH-MFT;chi2", kTH1F, {{100, 0.0f, 100}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", kTH2F, {{200, -0.5, 0.5}, {200, -0.5, +0.5}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hDCAz", "DCA z;DCA_{z} (cm);", kTH1F, {{1000, 0, 10}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hDCAxy2DinSigma", "DCA x vs. y in sigma;DCA_{x} (#sigma);DCA_{y} (#sigma)", kTH2F, {{200, -10, 10}, {200, -10, +10}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hDCAxy", "DCAxy;DCA_{xy} (cm);", kTH1F, {{100, 0, 1}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hDCAxyinSigma", "DCAxy in sigma;DCA_{xy} (#sigma);", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hDCAxResolutionvsPt", "DCA_{x} resolution vs. p_{T};p_{T} (GeV/c);DCA_{x} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 500}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hDCAyResolutionvsPt", "DCA_{y} resolution vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 500}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hDCAxyResolutionvsPt", "DCA_{xy} resolution vs. p_{T};p_{T} (GeV/c);DCA_{xy} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 500}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hRelDeltaPt", "pT resolution;p_{T}^{gen} (GeV/c);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{100, 0, 10}, {400, -1, +1}}, true); + fRegistry.add("MFTMCHMID/primary/correct/hDeltaEta_Pos", "#eta resolution;p_{T}^{gen} (GeV/c);#eta^{rec} - #eta^{gen}", kTH2F, {{100, 0, 10}, {400, -0.2, +0.2}}, true); + fRegistry.add("MFTMCHMID/primary/correct/hDeltaEta_Neg", "#eta resolution;p_{T}^{gen} (GeV/c);#eta^{rec} - #eta^{gen}", kTH2F, {{100, 0, 10}, {400, -0.2, +0.2}}, true); + fRegistry.add("MFTMCHMID/primary/correct/hDeltaPhi_Pos", "#varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{100, 0, 10}, {400, -0.2, +0.2}}, true); + fRegistry.add("MFTMCHMID/primary/correct/hDeltaPhi_Neg", "#varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{100, 0, 10}, {400, -0.2, +0.2}}, true); + fRegistry.addClone("MFTMCHMID/primary/correct/", "MFTMCHMID/primary/wrong/"); + fRegistry.addClone("MFTMCHMID/primary/", "MFTMCHMID/secondary/"); + + fRegistry.add("Generated/primary/hs", "gen. info;p_{T} (GeV/c);#eta;#varphi (rad.)", kTHnSparseF, {{100, 0.0f, 10}, {60, -5, -2}, {90, 0, 2.f * M_PI}}, false); + } + + bool isSelected(const float pt, const float eta, const float rAtAbsorberEnd, const float pDCA, const float chi2, const uint8_t trackType, const float dcaXY) + { + if (pt < minPt || maxPt < pt) { + return false; + } + if (rAtAbsorberEnd < minRabs || maxRabs < rAtAbsorberEnd) { + return false; + } + if (rAtAbsorberEnd < midRabs ? pDCA > maxPDCAforSmallR : pDCA > maxPDCAforLargeR) { + return false; + } + + if (trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + if (eta < minEtaGL || maxEtaGL < eta) { + return false; + } + if (maxDCAxy < dcaXY) { + return false; + } + if (chi2 < 0.f || maxChi2GL < chi2) { + return false; + } + } else if (trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + if (eta < minEtaSA || maxEtaSA < eta) { + return false; + } + if (chi2 < 0.f || maxChi2SA < chi2) { + return false; + } + } else { + return false; + } + + return true; + } + + template + void fillHistograms(TCollision const& collision, TFwdTrack fwdtrack, TFwdTracks const&, TMFTTracks const&) + { + const auto& mchtrack = fwdtrack.template matchMCHTrack_as(); // MCH-MID + const auto& mfttrack = fwdtrack.template matchMFTTrack_as(); + + if (!fwdtrack.has_mcParticle() || !mchtrack.has_mcParticle() || !mfttrack.has_mcParticle()) { + return; + } + + const auto& mcParticle_MFTMCHMID = fwdtrack.template mcParticle_as(); // this is identical to mcParticle_MCHMID + const auto& mcParticle_MCHMID = mchtrack.template mcParticle_as(); // this is identical to mcParticle_MFTMCHMID + const auto& mcParticle_MFT = mfttrack.template mcParticle_as(); + // LOGF(info, "mcParticle_MFTMCHMID.pdgCode() = %d, mcParticle_MCHMID.pdgCode() = %d, mcParticle_MFT.pdgCode() = %d", mcParticle_MFTMCHMID.pdgCode(), mcParticle_MCHMID.pdgCode(), mcParticle_MFT.pdgCode()); + // LOGF(info, "mcParticle_MFTMCHMID.globalIndex() = %d, mcParticle_MCHMID.globalIndex() = %d, mcParticle_MFT.globalIndex() = %d", mcParticle_MFTMCHMID.globalIndex(), mcParticle_MCHMID.globalIndex(), mcParticle_MFT.globalIndex()); + + if (fwdtrack.chi2MatchMCHMFT() > maxMatchingChi2MCHMFT) { + return; + } + + if (fwdtrack.chi2() < 0.f || maxChi2GL < fwdtrack.chi2()) { + return; + } + + if (fwdtrack.rAtAbsorberEnd() < minRabs || maxRabs < fwdtrack.rAtAbsorberEnd()) { + return; + } + + if (mfttrack.nClusters() < minNclustersMFT) { + return; + } + + if (std::abs(mcParticle_MCHMID.pdgCode()) != 13) { // select true muon + return; + } + + if (requireTrueAssociation && (mcParticle_MCHMID.mcCollisionId() != collision.mcCollisionId())) { + return; + } + + bool isPrimary = mcParticle_MCHMID.isPhysicalPrimary() || mcParticle_MCHMID.producedByGenerator(); + bool isMatched = (mcParticle_MFT.globalIndex() == mcParticle_MCHMID.globalIndex()) && (mcParticle_MFT.mcCollisionId() == mcParticle_MCHMID.mcCollisionId()); + + o2::dataformats::GlobalFwdTrack propmuonAtPV = propagateMuon(fwdtrack, collision, propagationPoint::kToVertex); + o2::dataformats::GlobalFwdTrack propmuonAtDCA = propagateMuon(fwdtrack, collision, propagationPoint::kToDCA); + + float pt = propmuonAtPV.getPt(); + float eta = propmuonAtPV.getEta(); + float phi = propmuonAtPV.getPhi(); + o2::math_utils::bringTo02Pi(phi); + + float cXXatDCA = propmuonAtDCA.getSigma2X(); + float cYYatDCA = propmuonAtDCA.getSigma2Y(); + float cXYatDCA = propmuonAtDCA.getSigmaXY(); + + float dcaX = propmuonAtDCA.getX() - collision.posX(); + float dcaY = propmuonAtDCA.getY() - collision.posY(); + float rAtAbsorberEnd = fwdtrack.rAtAbsorberEnd(); // this works only for GlobalMuonTrack + float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); + float dcaZ = -dcaXY * std::sinh(eta); + + float dFdx = dcaX / dcaXY; + float dFdy = dcaY / dcaXY; + float sigma_dcaXY = std::sqrt(cXXatDCA * dFdx * dFdx + cYYatDCA * dFdy * dFdy + 2.f * cXYatDCA * dFdx * dFdy); + + o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(mchtrack, collision, propagationPoint::kToVertex); + float etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); + float phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); + o2::math_utils::bringTo02Pi(phiMatchedMCHMID); + + o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = propagateMuon(mchtrack, collision, propagationPoint::kToDCA); + float dcaX_Matched = propmuonAtDCA_Matched.getX() - collision.posX(); + float dcaY_Matched = propmuonAtDCA_Matched.getY() - collision.posY(); + float dcaXY_Matched = std::sqrt(dcaX_Matched * dcaX_Matched + dcaY_Matched * dcaY_Matched); + float pDCA = mchtrack.p() * dcaXY_Matched; + int nClustersMFT = mfttrack.nClusters(); + // float chi2mft = mfttrack.chi2()/(2.f * nClustersMFT - 5.f); + float chi2mft = mfttrack.chi2(); + // if (chi2mft < 0.f || maxChi2MFT < chi2mft) { + // return; + // } + + if (refitGlobalMuon) { + eta = mfttrack.eta(); + phi = mfttrack.phi(); + o2::math_utils::bringTo02Pi(phi); + pt = propmuonAtPV_Matched.getP() * std::sin(2.f * std::atan(std::exp(-eta))); + } + + if (!isSelected(pt, eta, rAtAbsorberEnd, pDCA, fwdtrack.chi2(), fwdtrack.trackType(), dcaXY)) { + return; + } + + fRegistry.fill(HIST("hMuonType"), fwdtrack.trackType()); + if (isPrimary) { + if (isMatched) { + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hPt"), pt); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hEtaPhi"), phi, eta); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hEtaPhi_MatchedMCHMID"), phiMatchedMCHMID, etaMatchedMCHMID); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDiffCollId"), collision.globalIndex() - fwdtrack.collisionId()); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hSign"), fwdtrack.sign()); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hNclusters"), fwdtrack.nClusters()); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hNclustersMFT"), nClustersMFT); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hRatAbsorberEnd"), rAtAbsorberEnd); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hChi2"), fwdtrack.chi2()); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hChi2MFT"), chi2mft); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAxy2D"), dcaX, dcaY); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAz"), dcaZ); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAxy2DinSigma"), dcaX / std::sqrt(cXXatDCA), dcaY / std::sqrt(cYYatDCA)); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAxy"), dcaXY); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAxyinSigma"), dcaXY / sigma_dcaXY); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAxResolutionvsPt"), pt, std::sqrt(cXXatDCA) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAyResolutionvsPt"), pt, std::sqrt(cYYatDCA) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um + + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hRelDeltaPt"), mcParticle_MFTMCHMID.pt(), (pt - mcParticle_MFTMCHMID.pt()) / mcParticle_MFTMCHMID.pt()); + if (mcParticle_MFTMCHMID.pdgCode() > 0) { + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDeltaEta_Neg"), mcParticle_MFTMCHMID.pt(), eta - mcParticle_MFTMCHMID.eta()); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDeltaPhi_Neg"), mcParticle_MFTMCHMID.pt(), phi - mcParticle_MFTMCHMID.phi()); + } else { + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDeltaEta_Pos"), mcParticle_MFTMCHMID.pt(), eta - mcParticle_MFTMCHMID.eta()); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDeltaPhi_Pos"), mcParticle_MFTMCHMID.pt(), phi - mcParticle_MFTMCHMID.phi()); + } + } else { + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hPt"), pt); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hEtaPhi"), phi, eta); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hEtaPhi_MatchedMCHMID"), phiMatchedMCHMID, etaMatchedMCHMID); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDiffCollId"), collision.globalIndex() - fwdtrack.collisionId()); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hSign"), fwdtrack.sign()); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hNclusters"), fwdtrack.nClusters()); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hNclustersMFT"), nClustersMFT); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hRatAbsorberEnd"), rAtAbsorberEnd); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hChi2"), fwdtrack.chi2()); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hChi2MFT"), chi2mft); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAxy2D"), dcaX, dcaY); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAz"), dcaZ); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAxy2DinSigma"), dcaX / std::sqrt(cXXatDCA), dcaY / std::sqrt(cYYatDCA)); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAxy"), dcaXY); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAxyinSigma"), dcaXY / sigma_dcaXY); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAxResolutionvsPt"), pt, std::sqrt(cXXatDCA) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAyResolutionvsPt"), pt, std::sqrt(cYYatDCA) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hRelDeltaPt"), mcParticle_MFTMCHMID.pt(), (pt - mcParticle_MFTMCHMID.pt()) / mcParticle_MFTMCHMID.pt()); + if (mcParticle_MFTMCHMID.pdgCode() > 0) { + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDeltaEta_Neg"), mcParticle_MFTMCHMID.pt(), eta - mcParticle_MFTMCHMID.eta()); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDeltaPhi_Neg"), mcParticle_MFTMCHMID.pt(), phi - mcParticle_MFTMCHMID.phi()); + } else { + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDeltaEta_Pos"), mcParticle_MFTMCHMID.pt(), eta - mcParticle_MFTMCHMID.eta()); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDeltaPhi_Pos"), mcParticle_MFTMCHMID.pt(), phi - mcParticle_MFTMCHMID.phi()); + } + } + } else { // secondary + if (isMatched) { + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hPt"), pt); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hEtaPhi"), phi, eta); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hEtaPhi_MatchedMCHMID"), phiMatchedMCHMID, etaMatchedMCHMID); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDiffCollId"), collision.globalIndex() - fwdtrack.collisionId()); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hSign"), fwdtrack.sign()); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hNclusters"), fwdtrack.nClusters()); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hNclustersMFT"), nClustersMFT); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hRatAbsorberEnd"), rAtAbsorberEnd); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hChi2"), fwdtrack.chi2()); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hChi2MFT"), chi2mft); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAxy2D"), dcaX, dcaY); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAz"), dcaZ); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAxy2DinSigma"), dcaX / std::sqrt(cXXatDCA), dcaY / std::sqrt(cYYatDCA)); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAxy"), dcaXY); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAxyinSigma"), dcaXY / sigma_dcaXY); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAxResolutionvsPt"), pt, std::sqrt(cXXatDCA) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAyResolutionvsPt"), pt, std::sqrt(cYYatDCA) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hRelDeltaPt"), mcParticle_MFTMCHMID.pt(), (pt - mcParticle_MFTMCHMID.pt()) / mcParticle_MFTMCHMID.pt()); + if (mcParticle_MFTMCHMID.pdgCode() > 0) { + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDeltaEta_Neg"), mcParticle_MFTMCHMID.pt(), eta - mcParticle_MFTMCHMID.eta()); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDeltaPhi_Neg"), mcParticle_MFTMCHMID.pt(), phi - mcParticle_MFTMCHMID.phi()); + } else { + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDeltaEta_Pos"), mcParticle_MFTMCHMID.pt(), eta - mcParticle_MFTMCHMID.eta()); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDeltaPhi_Pos"), mcParticle_MFTMCHMID.pt(), phi - mcParticle_MFTMCHMID.phi()); + } + } else { + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hPt"), pt); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hEtaPhi"), phi, eta); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hEtaPhi_MatchedMCHMID"), phiMatchedMCHMID, etaMatchedMCHMID); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDiffCollId"), collision.globalIndex() - fwdtrack.collisionId()); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hSign"), fwdtrack.sign()); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hNclusters"), fwdtrack.nClusters()); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hNclustersMFT"), nClustersMFT); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hRatAbsorberEnd"), rAtAbsorberEnd); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hChi2"), fwdtrack.chi2()); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hChi2MFT"), chi2mft); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAxy2D"), dcaX, dcaY); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAz"), dcaZ); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAxy2DinSigma"), dcaX / std::sqrt(cXXatDCA), dcaY / std::sqrt(cYYatDCA)); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAxy"), dcaXY); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAxyinSigma"), dcaXY / sigma_dcaXY); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAxResolutionvsPt"), pt, std::sqrt(cXXatDCA) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAyResolutionvsPt"), pt, std::sqrt(cYYatDCA) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hRelDeltaPt"), mcParticle_MFTMCHMID.pt(), (pt - mcParticle_MFTMCHMID.pt()) / mcParticle_MFTMCHMID.pt()); + if (mcParticle_MFTMCHMID.pdgCode() > 0) { + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDeltaEta_Neg"), mcParticle_MFTMCHMID.pt(), eta - mcParticle_MFTMCHMID.eta()); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDeltaPhi_Neg"), mcParticle_MFTMCHMID.pt(), phi - mcParticle_MFTMCHMID.phi()); + } else { + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDeltaEta_Pos"), mcParticle_MFTMCHMID.pt(), eta - mcParticle_MFTMCHMID.eta()); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDeltaPhi_Pos"), mcParticle_MFTMCHMID.pt(), phi - mcParticle_MFTMCHMID.phi()); + } + } + } + } + + template + void fillEventHistograms(TCollision const& collision) + { + fRegistry.fill(HIST("Event/hZvtx"), collision.posZ()); + fRegistry.fill(HIST("Event/hMultNTracksPV"), collision.multNTracksPV()); + fRegistry.fill(HIST("Event/hMultNTracksPVeta1"), collision.multNTracksPVeta1()); + fRegistry.fill(HIST("Event/hMultFT0"), collision.multFT0A(), collision.multFT0C()); + fRegistry.fill(HIST("Event/hCentFT0A"), collision.centFT0A()); + fRegistry.fill(HIST("Event/hCentFT0C"), collision.centFT0C()); + fRegistry.fill(HIST("Event/hCentFT0M"), collision.centFT0M()); + fRegistry.fill(HIST("Event/hCentFT0CvsMultNTracksPV"), collision.centFT0C(), collision.multNTracksPV()); + fRegistry.fill(HIST("Event/hMultFT0CvsMultNTracksPV"), collision.multFT0C(), collision.multNTracksPV()); + } + + template + void runGen(TMCParticles const& mcParticles) + { + for (const auto& mcParticle : mcParticles) { + if (std::abs(mcParticle.pdgCode()) != 13) { // select true muon + continue; + } + if (!(mcParticle.isPhysicalPrimary() || mcParticle.producedByGenerator())) { + continue; + } + if (mcParticle.eta() < minEtaGL || maxEtaGL < mcParticle.eta()) { + continue; + } + + fRegistry.fill(HIST("Generated/primary/hs"), mcParticle.pt(), mcParticle.eta(), mcParticle.phi()); + + } // end of mc particles + } + + SliceCache cache; + PresliceUnsorted perMFTTrack = o2::aod::fwdtrack::matchMFTTrackId; + Preslice perCollision = o2::aod::fwdtrack::collisionId; + Preslice fwdtrackIndicesPerCollision = aod::track_association::collisionId; + PresliceUnsorted fwdtrackIndicesPerFwdTrack = aod::track_association::fwdtrackId; + + Filter collisionFilter_evsel = o2::aod::evsel::sel8 == true && (cfgZvtxMin < o2::aod::collision::posZ && o2::aod::collision::posZ < cfgZvtxMax); + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + using FilteredMyCollisions = soa::Filtered; + + void processWithoutFTTCA(FilteredMyCollisions const& collisions, MyFwdTracks const& fwdtracks, MyMFTTracks const& mfttracks, aod::BCsWithTimestamps const&, aod::McParticles const& mcParticles) + { + for (const auto& collision : collisions) { + const auto& bc = collision.template bc_as(); + initCCDB(bc); + fRegistry.fill(HIST("Event/hCollisionCounter"), 0); + if (!collision.has_mcCollision()) { + continue; + } + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + fRegistry.fill(HIST("Event/hCollisionCounter"), 1); + fillEventHistograms(collision); + + const auto& fwdtracks_per_coll = fwdtracks.sliceBy(perCollision, collision.globalIndex()); + for (const auto& fwdtrack : fwdtracks_per_coll) { + if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + continue; + } + fillHistograms(collision, fwdtrack, fwdtracks, mfttracks); + } // end of fwdtrack loop + } // end of collision loop + runGen(mcParticles); + } + PROCESS_SWITCH(matchingMFT, processWithoutFTTCA, "process without FTTCA", false); + + void processWithFTTCA(FilteredMyCollisions const& collisions, MyFwdTracks const& fwdtracks, MyMFTTracks const& mfttracks, aod::BCsWithTimestamps const&, aod::FwdTrackAssoc const& fwdtrackIndices, aod::McParticles const& mcParticles) + { + for (const auto& collision : collisions) { + const auto& bc = collision.template bc_as(); + initCCDB(bc); + fRegistry.fill(HIST("Event/hCollisionCounter"), 0); + if (!collision.has_mcCollision()) { + continue; + } + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + fRegistry.fill(HIST("Event/hCollisionCounter"), 1); + fillEventHistograms(collision); + + const auto& fwdtrackIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); + for (const auto& fwdtrackId : fwdtrackIdsThisCollision) { + const auto& fwdtrack = fwdtrackId.template fwdtrack_as(); + if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType()) { + continue; + } + fillHistograms(collision, fwdtrack, fwdtracks, mfttracks); + } // end of fwdtrack loop + } // end of collision loop + runGen(mcParticles); + } + PROCESS_SWITCH(matchingMFT, processWithFTTCA, "process with FTTCA", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"matching-mft"})}; +} diff --git a/PWGEM/Dilepton/Tasks/prefilterDielectron.cxx b/PWGEM/Dilepton/Tasks/prefilterDielectron.cxx new file mode 100644 index 00000000000..5ac01703a06 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/prefilterDielectron.cxx @@ -0,0 +1,554 @@ +// 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. +// +// ======================== +// +// This code produces information on prefilter for dielectron. +// Please write to: daiki.sekihata@cern.ch + +#include +#include +#include +#include +#include + +#include "TString.h" +#include "Math/Vector4D.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" + +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Core/DielectronCut.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "PWGEM/Dilepton/Utils/EMTrack.h" +#include "PWGEM/Dilepton/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; +using namespace o2::aod::pwgem::dilepton::utils::pairutil; + +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; + +using MyTracks = soa::Join; +using MyTrack = MyTracks::iterator; + +struct prefilterDielectron { + Produces pfb_derived; + + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentMin{"cfgCentMin", -1, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + + EMEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", false, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + } eventcuts; + + DielectronCut fDielectronCut; + struct : ConfigurableGroup { + std::string prefix = "dielectroncut_group"; + + // for mee prefilter + Configurable cfg_min_mass{"cfg_min_mass", 0.0, "min mass for prefilter ULS"}; // region to be rejected + Configurable cfg_max_mass{"cfg_max_mass", 0.0, "max mass for prefilter ULS"}; // region to be rejected + + // for phiv prefilter + Configurable cfg_apply_phiv{"cfg_apply_phiv", false, "flag to apply phiv cut"}; // region to be rejected + Configurable cfg_phiv_slope{"cfg_phiv_slope", 0.0185, "slope for m vs. phiv"}; // region to be rejected + Configurable cfg_phiv_intercept{"cfg_phiv_intercept", -0.0280, "intercept for m vs. phiv"}; // region to be rejected + Configurable cfg_min_phiv{"cfg_min_phiv", -1.f, "min phiv"}; // region to be rejected + Configurable cfg_max_phiv{"cfg_max_phiv", 3.2, "max phiv"}; // region to be rejected + + // for deta-dphi prefilter + Configurable cfg_apply_detadphi_uls{"cfg_apply_detadphi_uls", false, "flag to apply generator deta-dphi elliptic cut in ULS"}; // region to be rejected + Configurable cfg_apply_detadphi_ls{"cfg_apply_detadphi_ls", false, "flag to apply generator deta-dphi elliptic cut in LS"}; // region to be rejected + Configurable cfg_min_deta_ls{"cfg_min_deta_ls", 0.04, "deta between 2 electrons (elliptic cut)"}; // region to be rejected + Configurable cfg_min_dphi_ls{"cfg_min_dphi_ls", 0.2, "dphi between 2 electrons (elliptic cut)"}; // region to be rejected + Configurable cfg_min_deta_uls{"cfg_min_deta_uls", 0.04, "deta between 2 electrons (elliptic cut)"}; // region to be rejected + Configurable cfg_min_dphi_uls{"cfg_min_dphi_uls", 0.2, "dphi between 2 electrons (elliptic cut)"}; // region to be rejected + + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -0.9, "min eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", +0.9, "max eta for single track"}; + Configurable cfg_min_phi_track{"cfg_min_phi_track", 0.f, "min phi for single track"}; + Configurable cfg_max_phi_track{"cfg_max_phi_track", 6.3, "max phi for single track"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 100, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_chi2tof{"cfg_max_chi2tof", 1e+10, "max chi2 TOF"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 0.3, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 0.3, "max dca Z for single track in cm"}; + Configurable cfg_require_itsib_any{"cfg_require_itsib_any", true, "flag to require ITS ib any hits"}; + Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", false, "flag to require ITS ib 1st hit"}; + Configurable cfg_min_its_cluster_size{"cfg_min_its_cluster_size", 0.f, "min ITS cluster size"}; + Configurable cfg_max_its_cluster_size{"cfg_max_its_cluster_size", 16.f, "max ITS cluster size"}; + Configurable cfg_min_p_its_cluster_size{"cfg_min_p_its_cluster_size", 0.0, "min p to apply ITS cluster size cut"}; + Configurable cfg_max_p_its_cluster_size{"cfg_max_p_its_cluster_size", 0.0, "max p to apply ITS cluster size cut"}; + Configurable cfg_min_rel_diff_pin{"cfg_min_rel_diff_pin", -1e+10, "min rel. diff. between pin and ppv"}; + Configurable cfg_max_rel_diff_pin{"cfg_max_rel_diff_pin", +1e+10, "max rel. diff. between pin and ppv"}; + + Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DielectronCut::PIDSchemes::kTPChadrejORTOFreq), "pid scheme [kTOFreq : 0, kTPChadrej : 1, kTPChadrejORTOFreq : 2, kTPConly : 3, kTOFif : 4, kPIDML : 5, kTPChadrejORTOFreq_woTOFif : 6]"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + Configurable cfg_min_TPCNsigmaMu{"cfg_min_TPCNsigmaMu", -0.0, "min. TPC n sigma for muon exclusion"}; + Configurable cfg_max_TPCNsigmaMu{"cfg_max_TPCNsigmaMu", +0.0, "max. TPC n sigma for muon exclusion"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -1e+10, "min. TPC n sigma for pion exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +3.0, "max. TPC n sigma for pion exclusion"}; + Configurable cfg_min_TPCNsigmaKa{"cfg_min_TPCNsigmaKa", -3.0, "min. TPC n sigma for kaon exclusion"}; + Configurable cfg_max_TPCNsigmaKa{"cfg_max_TPCNsigmaKa", +3.0, "max. TPC n sigma for kaon exclusion"}; + Configurable cfg_min_TPCNsigmaPr{"cfg_min_TPCNsigmaPr", -3.0, "min. TPC n sigma for proton exclusion"}; + Configurable cfg_max_TPCNsigmaPr{"cfg_max_TPCNsigmaPr", +3.0, "max. TPC n sigma for proton exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; + Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; + + // configuration for PID ML + Configurable> onnxFileNames{"onnxFileNames", std::vector{"filename"}, "ONNX file names for each bin (if not from CCDB full path)"}; + Configurable> onnxPathsCCDB{"onnxPathsCCDB", std::vector{"path"}, "Paths of models on CCDB"}; + Configurable> binsMl{"binsMl", std::vector{-999999., 999999.}, "Bin limits for ML application"}; + Configurable> cutsMl{"cutsMl", std::vector{0.95}, "ML cuts per bin"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature"}, "Names of ML model input features"}; + Configurable nameBinningFeature{"nameBinningFeature", "pt", "Names of ML model binning feature"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + Configurable enableOptimizations{"enableOptimizations", false, "Enables the ONNX extended model-optimization: sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED)"}; + } dielectroncuts; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + int mRunNumber; + float d_bz; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + void init(InitContext& /*context*/) + { + DefineEMEventCut(); + DefineDielectronCut(); + addhistograms(); + + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + } + + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + o2::base::Propagator::initFieldFromGRP(&grpmag); + mRunNumber = collision.runNumber(); + return; + } + + auto run3grp_timestamp = collision.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = collision.runNumber(); + } + + ~prefilterDielectron() {} + + void addhistograms() + { + const AxisSpec axis_mass{400, 0, 4, "m_{ee} (GeV/c^{2})"}; + const AxisSpec axis_pair_pt{100, 0, 10, "p_{T,ee} (GeV/c)"}; + const AxisSpec axis_phiv{90, 0, M_PI, "#varphi_{V} (rad.)"}; + + // for pair + fRegistry.add("Pair/before/uls/hMvsPt", "m_{ee} vs. p_{T,ee}", kTH2D, {axis_mass, axis_pair_pt}, true); + fRegistry.add("Pair/before/uls/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2D, {axis_phiv, {200, 0, 1}}, true); + fRegistry.add("Pair/before/uls/hDeltaEtaDeltaPhi", "#Delta#eta-#Delta#varphi between 2 tracks;#Delta#varphi (rad.);#Delta#eta;", kTH2D, {{180, -M_PI, M_PI}, {200, -1, +1}}, true); + fRegistry.addClone("Pair/before/uls/", "Pair/before/lspp/"); + fRegistry.addClone("Pair/before/uls/", "Pair/before/lsmm/"); + fRegistry.addClone("Pair/before/", "Pair/after/"); + } + + void DefineEMEventCut() + { + fEMEventCut = EMEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + } + + o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; + void DefineDielectronCut() + { + fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); + + // for pair + fDielectronCut.SetMeeRange(0, 1e+10); + fDielectronCut.SetPairPtRange(0.f, 1e+10); + fDielectronCut.SetPairYRange(-1e+10, +1e+10); + fDielectronCut.SetPairDCARange(0.f, 1e+10); // in sigma + fDielectronCut.ApplyPhiV(false); + fDielectronCut.ApplyPrefilter(false); + fDielectronCut.SetMindEtadPhi(false, 1.f, 1.f); + fDielectronCut.SetPairOpAng(0.f, 3.2f); + fDielectronCut.SetRequireDifferentSides(false); + + // for track + fDielectronCut.SetTrackPtRange(dielectroncuts.cfg_min_pt_track, dielectroncuts.cfg_max_pt_track); + fDielectronCut.SetTrackEtaRange(dielectroncuts.cfg_min_eta_track, dielectroncuts.cfg_max_eta_track); + fDielectronCut.SetTrackPhiRange(dielectroncuts.cfg_min_phi_track, dielectroncuts.cfg_max_phi_track); + fDielectronCut.SetMinNClustersTPC(dielectroncuts.cfg_min_ncluster_tpc); + fDielectronCut.SetMinNCrossedRowsTPC(dielectroncuts.cfg_min_ncrossedrows); + fDielectronCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fDielectronCut.SetMaxFracSharedClustersTPC(dielectroncuts.cfg_max_frac_shared_clusters_tpc); + fDielectronCut.SetChi2PerClusterTPC(0.0, dielectroncuts.cfg_max_chi2tpc); + fDielectronCut.SetChi2PerClusterITS(0.0, dielectroncuts.cfg_max_chi2its); + fDielectronCut.SetNClustersITS(dielectroncuts.cfg_min_ncluster_its, 7); + fDielectronCut.SetMeanClusterSizeITS(dielectroncuts.cfg_min_its_cluster_size, dielectroncuts.cfg_max_its_cluster_size, dielectroncuts.cfg_min_p_its_cluster_size, dielectroncuts.cfg_max_p_its_cluster_size); + fDielectronCut.SetTrackMaxDcaXY(dielectroncuts.cfg_max_dcaxy); + fDielectronCut.SetTrackMaxDcaZ(dielectroncuts.cfg_max_dcaz); + fDielectronCut.RequireITSibAny(dielectroncuts.cfg_require_itsib_any); + fDielectronCut.RequireITSib1st(dielectroncuts.cfg_require_itsib_1st); + fDielectronCut.SetChi2TOF(0, dielectroncuts.cfg_max_chi2tof); + fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); + + // for eID + fDielectronCut.SetPIDScheme(dielectroncuts.cfg_pid_scheme); + fDielectronCut.SetTPCNsigmaElRange(dielectroncuts.cfg_min_TPCNsigmaEl, dielectroncuts.cfg_max_TPCNsigmaEl); + fDielectronCut.SetTPCNsigmaMuRange(dielectroncuts.cfg_min_TPCNsigmaMu, dielectroncuts.cfg_max_TPCNsigmaMu); + fDielectronCut.SetTPCNsigmaPiRange(dielectroncuts.cfg_min_TPCNsigmaPi, dielectroncuts.cfg_max_TPCNsigmaPi); + fDielectronCut.SetTPCNsigmaKaRange(dielectroncuts.cfg_min_TPCNsigmaKa, dielectroncuts.cfg_max_TPCNsigmaKa); + fDielectronCut.SetTPCNsigmaPrRange(dielectroncuts.cfg_min_TPCNsigmaPr, dielectroncuts.cfg_max_TPCNsigmaPr); + fDielectronCut.SetTOFNsigmaElRange(dielectroncuts.cfg_min_TOFNsigmaEl, dielectroncuts.cfg_max_TOFNsigmaEl); + + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { // please call this at the end of DefineDileptonCut + static constexpr int nClassesMl = 2; + const std::vector cutDirMl = {o2::cuts_ml::CutSmaller, o2::cuts_ml::CutNot}; + const std::vector labelsClasses = {"Signal", "Background"}; + const uint32_t nBinsMl = dielectroncuts.binsMl.value.size() - 1; + const std::vector labelsBins(nBinsMl, "bin"); + double cutsMlArr[nBinsMl][nClassesMl]; + for (uint32_t i = 0; i < nBinsMl; i++) { + cutsMlArr[i][0] = dielectroncuts.cutsMl.value[i]; + cutsMlArr[i][1] = 0.; + } + o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; + + mlResponseSingleTrack.configure(dielectroncuts.binsMl.value, cutsMl, cutDirMl, nClassesMl); + if (dielectroncuts.loadModelsFromCCDB) { + ccdbApi.init(ccdburl); + mlResponseSingleTrack.setModelPathsCCDB(dielectroncuts.onnxFileNames.value, ccdbApi, dielectroncuts.onnxPathsCCDB.value, dielectroncuts.timestampCCDB.value); + } else { + mlResponseSingleTrack.setModelPathsLocal(dielectroncuts.onnxFileNames.value); + } + mlResponseSingleTrack.cacheInputFeaturesIndices(dielectroncuts.namesInputFeatures); + mlResponseSingleTrack.cacheBinningIndex(dielectroncuts.nameBinningFeature); + mlResponseSingleTrack.init(dielectroncuts.enableOptimizations.value); + + fDielectronCut.SetPIDMlResponse(&mlResponseSingleTrack); + } // end of PID ML + } + + std::unordered_map map_pfb; // map track.globalIndex -> prefilter bit + + SliceCache cache; + Preslice perCollision_track = aod::emprimaryelectron::emeventId; + Partition posTracks = o2::aod::emprimaryelectron::sign > int8_t(0); + Partition negTracks = o2::aod::emprimaryelectron::sign < int8_t(0); + + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + using FilteredMyCollisions = soa::Filtered; + + int ndf = 0; + void processPFB(FilteredMyCollisions const& collisions, MyTracks const& tracks) + { + for (auto& track : tracks) { + map_pfb[track.globalIndex()] = 0; + } // end of track loop + + for (auto& collision : collisions) { + initCCDB(collision); + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + bool is_cent_ok = true; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + is_cent_ok = false; + } + + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + + if (!fEMEventCut.IsSelected(collision) || !is_cent_ok) { + for (auto& pos : posTracks_per_coll) { + map_pfb[pos.globalIndex()] = 0; + } + for (auto& neg : negTracks_per_coll) { + map_pfb[neg.globalIndex()] = 0; + } + continue; + } + + // LOGF(info, "centrality = %f , posTracks_per_coll.size() = %d, negTracks_per_coll.size() = %d", centralities[cfgCentEstimator], posTracks_per_coll.size(), negTracks_per_coll.size()); + + for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + if (!fDielectronCut.IsSelectedTrack(pos) || !fDielectronCut.IsSelectedTrack(ele)) { + continue; + } + // don't apply pair cut when you produce prefilter bit. + + ROOT::Math::PtEtaPhiMVector v1(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(v1.Px(), v1.Py(), v1.Pz(), v2.Px(), v2.Py(), v2.Pz(), pos.sign(), ele.sign(), d_bz); + float deta = pos.sign() * v1.Pt() > ele.sign() * v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi = pos.sign() * v1.Pt() > ele.sign() * v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + o2::math_utils::bringToPMPi(dphi); + + fRegistry.fill(HIST("Pair/before/uls/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/before/uls/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/before/uls/hDeltaEtaDeltaPhi"), dphi, deta); + + if (dielectroncuts.cfg_min_mass < v12.M() && v12.M() < dielectroncuts.cfg_max_mass) { + map_pfb[pos.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kMee); + map_pfb[ele.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kMee); + } + + if (dielectroncuts.cfg_apply_phiv && ((v12.M() < dielectroncuts.cfg_phiv_slope * phiv + dielectroncuts.cfg_phiv_intercept) && (dielectroncuts.cfg_min_phiv < phiv && phiv < dielectroncuts.cfg_max_phiv))) { + map_pfb[pos.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kPhiV); + map_pfb[ele.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kPhiV); + } + + if (dielectroncuts.cfg_apply_detadphi_uls && std::pow(deta / dielectroncuts.cfg_min_deta_uls, 2) + std::pow(dphi / dielectroncuts.cfg_min_dphi_uls, 2) < 1.f) { + map_pfb[pos.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS); + map_pfb[ele.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackULS); + } + } + + for (auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { // LS++ + if (!fDielectronCut.IsSelectedTrack(pos1) || !fDielectronCut.IsSelectedTrack(pos2)) { + continue; + } + // don't apply pair cut when you produce prefilter bit. + + ROOT::Math::PtEtaPhiMVector v1(pos1.pt(), pos1.eta(), pos1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(v1.Px(), v1.Py(), v1.Pz(), v2.Px(), v2.Py(), v2.Pz(), pos1.sign(), pos2.sign(), d_bz); + float deta = pos1.sign() * v1.Pt() > pos2.sign() * v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi = pos1.sign() * v1.Pt() > pos2.sign() * v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + o2::math_utils::bringToPMPi(dphi); + + fRegistry.fill(HIST("Pair/before/lspp/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/before/lspp/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/before/lspp/hDeltaEtaDeltaPhi"), dphi, deta); + + if (dielectroncuts.cfg_apply_detadphi_ls && std::pow(deta / dielectroncuts.cfg_min_deta_ls, 2) + std::pow(dphi / dielectroncuts.cfg_min_dphi_ls, 2) < 1.f) { + map_pfb[pos1.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS); + map_pfb[pos2.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS); + } + } + + for (auto& [ele1, ele2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { // LS-- + if (!fDielectronCut.IsSelectedTrack(ele1) || !fDielectronCut.IsSelectedTrack(ele2)) { + continue; + } + // don't apply pair cut when you produce prefilter bit. + + ROOT::Math::PtEtaPhiMVector v1(ele1.pt(), ele1.eta(), ele1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(v1.Px(), v1.Py(), v1.Pz(), v2.Px(), v2.Py(), v2.Pz(), ele1.sign(), ele2.sign(), d_bz); + float deta = ele1.sign() * v1.Pt() > ele2.sign() * v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi = ele1.sign() * v1.Pt() > ele2.sign() * v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + o2::math_utils::bringToPMPi(dphi); + + fRegistry.fill(HIST("Pair/before/lsmm/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/before/lsmm/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/before/lsmm/hDeltaEtaDeltaPhi"), dphi, deta); + + if (dielectroncuts.cfg_apply_detadphi_ls && std::pow(deta / dielectroncuts.cfg_min_deta_ls, 2) + std::pow(dphi / dielectroncuts.cfg_min_dphi_ls, 2) < 1.f) { + map_pfb[ele1.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS); + map_pfb[ele2.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBitDerived::kSplitOrMergedTrackLS); + } + } + + } // end of collision loop + + for (auto& track : tracks) { + // LOGF(info, "map_pfb[%d] = %d", track.globalIndex(), map_pfb[track.globalIndex()]); + pfb_derived(map_pfb[track.globalIndex()]); + } // end of track loop + + // check pfb. + for (auto& collision : collisions) { + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + + for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + if (!fDielectronCut.IsSelectedTrack(pos) || !fDielectronCut.IsSelectedTrack(ele)) { + continue; + } + if (map_pfb[pos.globalIndex()] != 0 || map_pfb[ele.globalIndex()] != 0) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(v1.Px(), v1.Py(), v1.Pz(), v2.Px(), v2.Py(), v2.Pz(), pos.sign(), ele.sign(), d_bz); + float deta = pos.sign() * v1.Pt() > ele.sign() * v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi = pos.sign() * v1.Pt() > ele.sign() * v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + o2::math_utils::bringToPMPi(dphi); + + fRegistry.fill(HIST("Pair/after/uls/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/after/uls/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/after/uls/hDeltaEtaDeltaPhi"), dphi, deta); + } + + for (auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { // LS++ + if (!fDielectronCut.IsSelectedTrack(pos1) || !fDielectronCut.IsSelectedTrack(pos2)) { + continue; + } + if (map_pfb[pos1.globalIndex()] != 0 || map_pfb[pos2.globalIndex()] != 0) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(pos1.pt(), pos1.eta(), pos1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(v1.Px(), v1.Py(), v1.Pz(), v2.Px(), v2.Py(), v2.Pz(), pos1.sign(), pos2.sign(), d_bz); + float deta = pos1.sign() * v1.Pt() > pos2.sign() * v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi = pos1.sign() * v1.Pt() > pos2.sign() * v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + o2::math_utils::bringToPMPi(dphi); + + fRegistry.fill(HIST("Pair/after/lspp/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/after/lspp/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/after/lspp/hDeltaEtaDeltaPhi"), dphi, deta); + } + + for (auto& [ele1, ele2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { // LS-- + if (!fDielectronCut.IsSelectedTrack(ele1) || !fDielectronCut.IsSelectedTrack(ele2)) { + continue; + } + if (map_pfb[ele1.globalIndex()] != 0 || map_pfb[ele2.globalIndex()] != 0) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(ele1.pt(), ele1.eta(), ele1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(v1.Px(), v1.Py(), v1.Pz(), v2.Px(), v2.Py(), v2.Pz(), ele1.sign(), ele2.sign(), d_bz); + float deta = ele1.sign() * v1.Pt() > ele2.sign() * v2.Pt() ? v1.Eta() - v2.Eta() : v2.Eta() - v1.Eta(); + float dphi = ele1.sign() * v1.Pt() > ele2.sign() * v2.Pt() ? v1.Phi() - v2.Phi() : v2.Phi() - v1.Phi(); + o2::math_utils::bringToPMPi(dphi); + + fRegistry.fill(HIST("Pair/after/lsmm/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/after/lsmm/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/after/lsmm/hDeltaEtaDeltaPhi"), dphi, deta); + } + + } // end of collision loop + ndf++; + map_pfb.clear(); + } // end of process + PROCESS_SWITCH(prefilterDielectron, processPFB, "produce prefilter bit", false); + + void processDummy(MyTracks const& tracks) + { + for (int i = 0; i < tracks.size(); i++) { + pfb_derived(0); + } + } + PROCESS_SWITCH(prefilterDielectron, processDummy, "dummy", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"prefilter-dielectron"})}; +} diff --git a/PWGEM/Dilepton/Tasks/singleElectronQC.cxx b/PWGEM/Dilepton/Tasks/singleElectronQC.cxx new file mode 100644 index 00000000000..4a687e82217 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/singleElectronQC.cxx @@ -0,0 +1,27 @@ +// 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. +// +// ======================== +// +// Analysis task for single electron QC +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" + +#include "PWGEM/Dilepton/Core/SingleTrackQC.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"single-electron-qc"})}; +} diff --git a/PWGEM/Dilepton/Tasks/singleElectronQCMC.cxx b/PWGEM/Dilepton/Tasks/singleElectronQCMC.cxx new file mode 100644 index 00000000000..da2617158ec --- /dev/null +++ b/PWGEM/Dilepton/Tasks/singleElectronQCMC.cxx @@ -0,0 +1,27 @@ +// 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. +// +// ======================== +// +// Analysis task for single electron QC in MC +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" + +#include "PWGEM/Dilepton/Core/SingleTrackQCMC.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"single-electron-qc-mc"})}; +} diff --git a/PWGEM/Dilepton/Tasks/singleMuonQC.cxx b/PWGEM/Dilepton/Tasks/singleMuonQC.cxx new file mode 100644 index 00000000000..b9ccb722ea3 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/singleMuonQC.cxx @@ -0,0 +1,27 @@ +// 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. +// +// ======================== +// +// Analysis task for single muon QC +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" + +#include "PWGEM/Dilepton/Core/SingleTrackQC.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"single-muon-qc"})}; +} diff --git a/PWGEM/Dilepton/Tasks/singleMuonQCMC.cxx b/PWGEM/Dilepton/Tasks/singleMuonQCMC.cxx new file mode 100644 index 00000000000..7b7176238c1 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/singleMuonQCMC.cxx @@ -0,0 +1,27 @@ +// 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. +// +// ======================== +// +// Analysis task for single muon QC in MC +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" + +#include "PWGEM/Dilepton/Core/SingleTrackQCMC.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"single-muon-qc-mc"})}; +} diff --git a/PWGEM/Dilepton/Tasks/smearing.cxx b/PWGEM/Dilepton/Tasks/smearing.cxx index 4206a4664ab..7d2404645ca 100644 --- a/PWGEM/Dilepton/Tasks/smearing.cxx +++ b/PWGEM/Dilepton/Tasks/smearing.cxx @@ -10,9 +10,14 @@ // or submit itself to any jurisdiction. // // -// Analysis task to produce smeared pt,eta,phi for electrons/muons in dilepton analysis +// Analysis task to produce smeared pt, eta, phi for electrons/muons in dilepton analysis // Please write to: daiki.sekihata@cern.ch +#include +#include +#include + +#include "CCDB/BasicCCDBManager.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -20,86 +25,287 @@ #include "Framework/ASoA.h" #include "Framework/DataTypes.h" #include "Framework/HistogramRegistry.h" -#include "PWGDQ/DataModel/ReducedInfoTables.h" +// #include "PWGDQ/DataModel/ReducedInfoTables.h" // remove this later, because 2 data tables (covariant matrix) in this header confilict against EM tables. #include "PWGEM/Dilepton/Utils/MomentumSmearer.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::aod; +namespace o2::aod::pwgem::dilepton::smearing +{ +enum class EMAnaType : int { + kEfficiency = 0, + kCocktail = 1, +}; +} // namespace o2::aod::pwgem::dilepton::smearing + +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; + +using MyMCCollisions = soa::Join; +using MyMCCollision = MyMCCollisions::iterator; + struct ApplySmearing { - Produces smearedtrack; - // Run for electrons or muons (For the moment the task is not designed for both at the same time) - Configurable fPdgCode{"cfgPdgCode", 11, "Set the type of particle to be smeared"}; - // Maps - Configurable fConfigResFileName{"cfgResFileName", "", "name of resolution file"}; - Configurable fConfigResPtHistName{"cfgResPtHistName", "RelPtResArrCocktail", "histogram name for pt in resolution file"}; - Configurable fConfigResEtaHistName{"cfgResEtaHistName", "EtaResArr", "histogram name for eta in resolution file"}; - Configurable fConfigResPhiPosHistName{"cfgResPhiPosHistName", "PhiPosResArr", "histogram name for phi pos in resolution file"}; - Configurable fConfigResPhiNegHistName{"cfgResPhiNegHistName", "PhiEleResArr", "hisogram for phi neg in resolution file"}; + Produces smearedelectron; + Produces smearedmuon; + + Configurable fFromCcdb{"cfgFromCcdb", false, "get resolution and efficiency histos from CCDB"}; + Configurable fConfigCcdbUrl{"cfgCcdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable fTimestamp{"cfgCcdbTimestamp", 10, "valid timestamp of CCDB object"}; + Configurable fCentralityForCocktail{"cfgCentralityForCocktail", 5, "average centrality for cocktail"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + + struct : ConfigurableGroup { + std::string prefix = "electron_filename_group"; + Configurable fConfigNDSmearing{"cfgNDSmearing", false, "apply ND-correlated smearing"}; + Configurable fConfigResFileName{"cfgResFileName", "", "name of resolution file"}; + Configurable fConfigResNDHistName{"cfgResNDHistName", "hs_reso", "name of ND resolution file"}; + Configurable fConfigResPtHistName{"cfgResPtHistName", "RelPtResArrCocktail", "histogram name for pt in resolution file"}; + Configurable fConfigResEtaHistName{"cfgResEtaHistName", "EtaResArr", "histogram name for eta in resolution file"}; + Configurable fConfigResPhiPosHistName{"cfgResPhiPosHistName", "PhiPosResArr", "histogram name for phi pos in resolution file"}; + Configurable fConfigResPhiNegHistName{"cfgResPhiNegHistName", "PhiEleResArr", "hisogram for phi neg in resolution file"}; + Configurable fConfigEffFileName{"cfgEffFileName", "", "name of efficiency file"}; + Configurable fConfigEffHistName{"cfgEffHistName", "fhwEffpT", "name of efficiency histogram"}; + Configurable fConfigDCAFileName{"cfgDCAFileName", "", "name of DCA template file"}; + Configurable fConfigDCAHistName{"cfgDCAHistName", "fh_DCAtempaltes", "histogram name of the DCA templates"}; + Configurable fConfigCcdbPathRes{"cfgCcdbPathRes", "", "path to the ccdb object for resolution"}; + Configurable fConfigCcdbPathEff{"cfgCcdbPahtEff", "", "path to the ccdb object for efficiency"}; + Configurable fConfigCcdbPathDCA{"cfgCcdbPahtDCA", "", "path to the ccdb object for dca"}; + Configurable fConfigMinPt{"cfgMinPt", -1, "if ptgen is smaller than this threshold, this value is used as input for ptgen."}; + } electron_filenames; + + struct : ConfigurableGroup { + std::string prefix = "sa_muon_filename_group"; + Configurable fConfigNDSmearing{"cfgNDSmearing", false, "apply ND-correlated smearing"}; + Configurable fConfigResFileName{"cfgResFileName", "", "name of resolution file"}; + Configurable fConfigResNDHistName{"cfgResNDHistName", "hs_reso", "name of ND resolution file"}; + Configurable fConfigResPtHistName{"cfgResPtHistName", "RelPtResArrCocktail", "histogram name for pt in resolution file"}; + Configurable fConfigResEtaHistName{"cfgResEtaHistName", "EtaResArr", "histogram name for eta in resolution file"}; + Configurable fConfigResPhiPosHistName{"cfgResPhiPosHistName", "PhiPosResArr", "histogram name for phi pos in resolution file"}; + Configurable fConfigResPhiNegHistName{"cfgResPhiNegHistName", "PhiEleResArr", "hisogram for phi neg in resolution file"}; + Configurable fConfigEffFileName{"cfgEffFileName", "", "name of efficiency file"}; + Configurable fConfigEffHistName{"cfgEffHistName", "fhwEffpT", "name of efficiency histogram"}; + Configurable fConfigDCAFileName{"cfgDCAFileName", "", "name of DCA template file"}; + Configurable fConfigDCAHistName{"cfgDCAHistName", "fh_DCAtempaltes", "histogram name of the DCA templates"}; + Configurable fConfigCcdbPathRes{"cfgCcdbPathRes", "", "path to the ccdb object for resolution"}; + Configurable fConfigCcdbPathEff{"cfgCcdbPahtEff", "", "path to the ccdb object for efficiency"}; + Configurable fConfigCcdbPathDCA{"cfgCcdbPahtDCA", "", "path to the ccdb object for dca"}; + Configurable fConfigMinPt{"cfgMinPt", -1, "if ptgen is smaller than this threshold, this value is used as input for ptgen."}; + } sa_muon_filenames; + + struct : ConfigurableGroup { + std::string prefix = "gl_muon_filename_group"; + Configurable fConfigNDSmearing{"cfgNDSmearing", false, "apply ND-correlated smearing"}; + Configurable fConfigResFileName{"cfgResFileName", "", "name of resolution file"}; + Configurable fConfigResNDHistName{"cfgResNDHistName", "hs_reso", "name of ND resolution file"}; + Configurable fConfigResPtHistName{"cfgResPtHistName", "RelPtResArrCocktail", "histogram name for pt in resolution file"}; + Configurable fConfigResEtaHistName{"cfgResEtaHistName", "EtaResArr", "histogram name for eta in resolution file"}; + Configurable fConfigResPhiPosHistName{"cfgResPhiPosHistName", "PhiPosResArr", "histogram name for phi pos in resolution file"}; + Configurable fConfigResPhiNegHistName{"cfgResPhiNegHistName", "PhiEleResArr", "hisogram for phi neg in resolution file"}; + Configurable fConfigEffFileName{"cfgEffFileName", "", "name of efficiency file"}; + Configurable fConfigEffHistName{"cfgEffHistName", "fhwEffpT", "name of efficiency histogram"}; + Configurable fConfigDCAFileName{"cfgDCAFileName", "", "name of DCA template file"}; + Configurable fConfigDCAHistName{"cfgDCAHistName", "fh_DCAtempaltes", "histogram name of the DCA templates"}; + Configurable fConfigCcdbPathRes{"cfgCcdbPathRes", "", "path to the ccdb object for resolution"}; + Configurable fConfigCcdbPathEff{"cfgCcdbPahtEff", "", "path to the ccdb object for efficiency"}; + Configurable fConfigCcdbPathDCA{"cfgCcdbPahtDCA", "", "path to the ccdb object for dca"}; + Configurable fConfigMinPt{"cfgMinPt", -1, "if ptgen is smaller than this threshold, this value is used as input for ptgen."}; + } gl_muon_filenames; - MomentumSmearer smearer; + MomentumSmearer smearer_Electron; + MomentumSmearer smearer_StandaloneMuon; + MomentumSmearer smearer_GlobalMuon; + Service ccdb; void init(InitContext&) { - smearer.setResFileName(TString(fConfigResFileName)); - smearer.setResPtHistName(TString(fConfigResPtHistName)); - smearer.setResEtaHistName(TString(fConfigResEtaHistName)); - smearer.setResPhiPosHistName(TString(fConfigResPhiPosHistName)); - smearer.setResPhiNegHistName(TString(fConfigResPhiNegHistName)); - smearer.init(); + smearer_Electron.setNDSmearing(electron_filenames.fConfigNDSmearing.value); + smearer_Electron.setResFileName(TString(electron_filenames.fConfigResFileName)); + smearer_Electron.setResNDHistName(TString(electron_filenames.fConfigResNDHistName)); + smearer_Electron.setResPtHistName(TString(electron_filenames.fConfigResPtHistName)); + smearer_Electron.setResEtaHistName(TString(electron_filenames.fConfigResEtaHistName)); + smearer_Electron.setResPhiPosHistName(TString(electron_filenames.fConfigResPhiPosHistName)); + smearer_Electron.setResPhiNegHistName(TString(electron_filenames.fConfigResPhiNegHistName)); + smearer_Electron.setEffFileName(TString(electron_filenames.fConfigEffFileName)); + smearer_Electron.setEffHistName(TString(electron_filenames.fConfigEffHistName)); + smearer_Electron.setDCAFileName(TString(electron_filenames.fConfigDCAFileName)); + smearer_Electron.setDCAHistName(TString(electron_filenames.fConfigDCAHistName)); + smearer_Electron.setMinPt(electron_filenames.fConfigMinPt); + + smearer_StandaloneMuon.setNDSmearing(sa_muon_filenames.fConfigNDSmearing.value); + smearer_StandaloneMuon.setResFileName(TString(sa_muon_filenames.fConfigResFileName)); + smearer_StandaloneMuon.setResNDHistName(TString(sa_muon_filenames.fConfigResNDHistName)); + smearer_StandaloneMuon.setResPtHistName(TString(sa_muon_filenames.fConfigResPtHistName)); + smearer_StandaloneMuon.setResEtaHistName(TString(sa_muon_filenames.fConfigResEtaHistName)); + smearer_StandaloneMuon.setResPhiPosHistName(TString(sa_muon_filenames.fConfigResPhiPosHistName)); + smearer_StandaloneMuon.setResPhiNegHistName(TString(sa_muon_filenames.fConfigResPhiNegHistName)); + smearer_StandaloneMuon.setEffFileName(TString(sa_muon_filenames.fConfigEffFileName)); + smearer_StandaloneMuon.setEffHistName(TString(sa_muon_filenames.fConfigEffHistName)); + smearer_StandaloneMuon.setDCAFileName(TString(sa_muon_filenames.fConfigDCAFileName)); + smearer_StandaloneMuon.setDCAHistName(TString(sa_muon_filenames.fConfigDCAHistName)); + smearer_StandaloneMuon.setMinPt(sa_muon_filenames.fConfigMinPt); + + smearer_GlobalMuon.setNDSmearing(gl_muon_filenames.fConfigNDSmearing.value); + smearer_GlobalMuon.setResFileName(TString(gl_muon_filenames.fConfigResFileName)); + smearer_GlobalMuon.setResNDHistName(TString(gl_muon_filenames.fConfigResNDHistName)); + smearer_GlobalMuon.setResPtHistName(TString(gl_muon_filenames.fConfigResPtHistName)); + smearer_GlobalMuon.setResEtaHistName(TString(gl_muon_filenames.fConfigResEtaHistName)); + smearer_GlobalMuon.setResPhiPosHistName(TString(gl_muon_filenames.fConfigResPhiPosHistName)); + smearer_GlobalMuon.setResPhiNegHistName(TString(gl_muon_filenames.fConfigResPhiNegHistName)); + smearer_GlobalMuon.setEffFileName(TString(gl_muon_filenames.fConfigEffFileName)); + smearer_GlobalMuon.setEffHistName(TString(gl_muon_filenames.fConfigEffHistName)); + smearer_GlobalMuon.setDCAFileName(TString(gl_muon_filenames.fConfigDCAFileName)); + smearer_GlobalMuon.setDCAHistName(TString(gl_muon_filenames.fConfigDCAHistName)); + smearer_GlobalMuon.setMinPt(gl_muon_filenames.fConfigMinPt); + + if (fFromCcdb) { + ccdb->setURL(fConfigCcdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); // now + + smearer_Electron.setCcdbPathRes(TString(electron_filenames.fConfigCcdbPathRes)); + smearer_Electron.setCcdbPathEff(TString(electron_filenames.fConfigCcdbPathEff)); + smearer_Electron.setCcdbPathDCA(TString(electron_filenames.fConfigCcdbPathDCA)); + smearer_Electron.setTimestamp(fTimestamp); + smearer_Electron.setCcdb(ccdb); + + smearer_StandaloneMuon.setCcdbPathRes(TString(sa_muon_filenames.fConfigCcdbPathRes)); + smearer_StandaloneMuon.setCcdbPathEff(TString(sa_muon_filenames.fConfigCcdbPathEff)); + smearer_StandaloneMuon.setCcdbPathDCA(TString(sa_muon_filenames.fConfigCcdbPathDCA)); + smearer_StandaloneMuon.setTimestamp(fTimestamp); + smearer_StandaloneMuon.setCcdb(ccdb); + + smearer_GlobalMuon.setCcdbPathRes(TString(gl_muon_filenames.fConfigCcdbPathRes)); + smearer_GlobalMuon.setCcdbPathEff(TString(gl_muon_filenames.fConfigCcdbPathEff)); + smearer_GlobalMuon.setCcdbPathDCA(TString(gl_muon_filenames.fConfigCcdbPathDCA)); + smearer_GlobalMuon.setTimestamp(fTimestamp); + smearer_GlobalMuon.setCcdb(ccdb); + } + smearer_Electron.init(); + smearer_StandaloneMuon.init(); + smearer_GlobalMuon.init(); } - template - void applySmearing(TTracksMC const& tracksMC) + template + void applySmearing(TTracksMC const& tracksMC, TCollisions const& collisions, TMCCollisions const&) { for (auto& mctrack : tracksMC) { float ptgen = mctrack.pt(); float etagen = mctrack.eta(); float phigen = mctrack.phi(); + float efficiency = 1.; + float dca = 0.; + + float ptsmeared = 0, etasmeared = 0, phismeared = 0; + float centrality = -1.f; + if constexpr (type == o2::aod::pwgem::dilepton::smearing::EMAnaType::kEfficiency) { + auto mccollision = mctrack.template emmcevent_as(); + if (mccollision.mpemeventId() > 0) { // if mc collisions are not reconstructed, such mc collisions should not enter efficiency calculation. + auto collision = collisions.rawIteratorAt(mccollision.mpemeventId()); + centrality = std::array{collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}[cfgCentEstimator]; + } else { + ptsmeared = ptgen; + etasmeared = etagen; + phismeared = phigen; + } + } else { + centrality = fCentralityForCocktail; + } int pdgCode = mctrack.pdgCode(); - if (abs(pdgCode) == fPdgCode) { + if (std::abs(pdgCode) == 11) { int ch = -1; if (pdgCode < 0) { ch = 1; } // apply smearing for electrons or muons. - float ptsmeared, etasmeared, phismeared; - smearer.applySmearing(ch, ptgen, etagen, phigen, ptsmeared, etasmeared, phismeared); - smearedtrack(ptsmeared, etasmeared, phismeared); + smearer_Electron.applySmearing(centrality, ch, ptgen, etagen, phigen, ptsmeared, etasmeared, phismeared); + // get the efficiency + efficiency = smearer_Electron.getEfficiency(ptgen, etagen, phigen); + // get DCA + dca = smearer_Electron.getDCA(ptsmeared); + // fill the table + smearedelectron(ptsmeared, etasmeared, phismeared, efficiency, dca); + smearedmuon(ptgen, etagen, phigen, 1.f, 0.f, ptgen, etagen, phigen, 1.f, 0.f); + } else if (std::abs(pdgCode) == 13) { + int ch = -1; + if (pdgCode < 0) { + ch = 1; + } + // apply smearing for muons based on resolution map of standalone muons + float ptsmeared_sa = 0.f, etasmeared_sa = 0.f, phismeared_sa = 0.f, efficiency_sa = 1.f, dca_sa = 0.f; + smearer_StandaloneMuon.applySmearing(centrality, ch, ptgen, etagen, phigen, ptsmeared_sa, etasmeared_sa, phismeared_sa); + efficiency_sa = smearer_StandaloneMuon.getEfficiency(ptgen, etagen, phigen); + dca_sa = smearer_StandaloneMuon.getDCA(ptsmeared_sa); + + float ptsmeared_gl = 0.f, etasmeared_gl = 0.f, phismeared_gl = 0.f, efficiency_gl = 1.f, dca_gl = 0.f; + // apply smearing for muons based on resolution map of global muons + smearer_GlobalMuon.applySmearing(centrality, ch, ptgen, etagen, phigen, ptsmeared_gl, etasmeared_gl, phismeared_gl); + efficiency_gl = smearer_GlobalMuon.getEfficiency(ptgen, etagen, phigen); + dca_gl = smearer_GlobalMuon.getDCA(ptsmeared_gl); + smearedmuon(ptsmeared_sa, etasmeared_sa, phismeared_sa, efficiency_sa, dca_sa, ptsmeared_gl, etasmeared_gl, phismeared_gl, efficiency_gl, dca_gl); + smearedelectron(ptgen, etagen, phigen, 1.f, 0.f); } else { // don't apply smearing - smearedtrack(ptgen, etagen, phigen); + smearedelectron(ptgen, etagen, phigen, efficiency, dca); + smearedmuon(ptgen, etagen, phigen, efficiency, dca, ptgen, etagen, phigen, efficiency, dca); } - } + } // end of mc track loop } - void processMCanalysis(ReducedMCTracks const& tracksMC) + void processMCanalysisEM(aod::EMMCParticles const& tracksMC, MyCollisions const& collisions, MyMCCollisions const& mccollisions) { - applySmearing(tracksMC); + applySmearing(tracksMC, collisions, mccollisions); } + // void processMCanalysisDQ(ReducedMCTracks const& tracksMC) + // { + // applySmearing(tracksMC); + // } + void processCocktail(aod::McParticles const& tracksMC) { - applySmearing(tracksMC); + applySmearing(tracksMC, nullptr, nullptr); } - void processDummyCocktail(aod::McParticles const&) {} + void processDummyCocktail(aod::McParticles const& tracksMC) + { + // don't apply smearing + for (auto& mctrack : tracksMC) { + int pdgCode = mctrack.pdgCode(); + if (std::abs(pdgCode) == 11) { + smearedelectron(mctrack.pt(), mctrack.eta(), mctrack.phi(), 1.0, 0.0); + smearedmuon(mctrack.pt(), mctrack.eta(), mctrack.phi(), 1.0, 0.0, mctrack.pt(), mctrack.eta(), mctrack.phi(), 1.0, 0.0); + } else if (std::abs(pdgCode) == 13) { + smearedelectron(mctrack.pt(), mctrack.eta(), mctrack.phi(), 1.0, 0.0); + smearedmuon(mctrack.pt(), mctrack.eta(), mctrack.phi(), 1.0, 0.0, mctrack.pt(), mctrack.eta(), mctrack.phi(), 1.0, 0.0); + } else { + smearedelectron(mctrack.pt(), mctrack.eta(), mctrack.phi(), 1.0, 0.0); + smearedmuon(mctrack.pt(), mctrack.eta(), mctrack.phi(), 1.0, 0.0, mctrack.pt(), mctrack.eta(), mctrack.phi(), 1.0, 0.0); + } + } + } - void processDummyMCanalysis(ReducedMCTracks const&) {} + void processDummyMCanalysisEM(aod::EMMCParticles const&) {} + // void processDummyMCanalysisDQ(ReducedMCTracks const&) {} - PROCESS_SWITCH(ApplySmearing, processMCanalysis, "Run for MC analysis", false); + PROCESS_SWITCH(ApplySmearing, processMCanalysisEM, "Run for MC analysis which uses skimmed EM data format", false); + // PROCESS_SWITCH(ApplySmearing, processMCanalysisDQ, "Run for MC analysis which uses skimmed DQ data format", false); PROCESS_SWITCH(ApplySmearing, processCocktail, "Run for cocktail analysis", false); - PROCESS_SWITCH(ApplySmearing, processDummyMCanalysis, "Dummy process function", false); + PROCESS_SWITCH(ApplySmearing, processDummyMCanalysisEM, "Dummy process function", false); + // PROCESS_SWITCH(ApplySmearing, processDummyMCanalysisDQ, "Dummy process function", false); PROCESS_SWITCH(ApplySmearing, processDummyCocktail, "Dummy process function", true); }; struct CheckSmearing { - using MyReducedTracks = soa::Join; - using MyCocktailTracks = soa::Join; + using EMMCParticlesWithSmearing = soa::Join; // this is only for electrons + // using MyReducedTracks = soa::Join; // this is only for electrons + using MyCocktailTracks = soa::Join; // this is only for electrons // Run for electrons or muons Configurable fPdgCode{"cfgPdgCode", 11, "Set the type of particle to be checked"}; @@ -112,41 +318,48 @@ struct CheckSmearing { ConfigurableAxis deltaetaResBins{"deltaetaResBins", {500, -0.5f, 0.5f}, "DeltaEta binning for resolution"}; ConfigurableAxis deltaphiResBins{"deltaphiResBins", {500, -0.5f, 0.5f}, "DeltaPhi binning for resolution"}; - HistogramRegistry registry{"HistoAnalysisTrackSelection", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registry{"output", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(o2::framework::InitContext&) { - registry.add("hCorrelation_Pt", "pT correlation", {HistType::kTH2F, {{1000, 0.0f, 10.0f}, {1000, 0.0f, 10.0f}}}); - registry.add("hCorrelation_Eta", "eta correlation", {HistType::kTH2F, {{200, -1.0f, +1.0f}, {200, -1.0f, +1.0f}}}); - registry.add("hCorrelation_Phi", "phi correlation", {HistType::kTH2F, {{100, 0.0f, TMath::TwoPi()}, {100, 0.0f, TMath::TwoPi()}}}); + registry.add("hCorrelation_Pt", "pT correlation;p_{T,l}^{gen} (GeV/c);p_{T,l}^{smeared} (GeV/c)", {HistType::kTH2F, {{1000, 0.0f, 10.0f}, {1000, 0.0f, 10.0f}}}); + registry.add("hCorrelation_Eta", "eta correlation;#eta_{l}^{gen};#eta_{l}^{smeared}", {HistType::kTH2F, {{200, -1.0f, +1.0f}, {200, -1.0f, +1.0f}}}); + registry.add("hCorrelation_Phi", "phi correlation;#varphi_{l}^{gen} (rad.);#varphi_{l}^{smeared} (rad.)", {HistType::kTH2F, {{100, 0.0f, TMath::TwoPi()}, {100, 0.0f, TMath::TwoPi()}}}); // Binning for resolution - AxisSpec axisPtRes{ptResBins, "#it{p}^{gen}_{T,e} (GeV/#it{c})"}; + AxisSpec axisPtRes{ptResBins, "#it{p}^{gen}_{T,l} (GeV/#it{c})"}; AxisSpec axisDeltaptRes{deltaptResBins, "(p^{gen}_{T} - p^{rec}_{T}) / p^{gen}_{T}"}; AxisSpec axisDeltaetaRes{deltaetaResBins, "#eta^{gen} - #eta^{rec}"}; - AxisSpec axisDeltaphiRes{deltaphiResBins, "#varphi^{gen} - #varphi^{rec} (rad)"}; + AxisSpec axisDeltaphiRes{deltaphiResBins, "#varphi^{gen} - #varphi^{rec} (rad.)"}; if (!fConfigUsePtVecRes) { registry.add("PtGen_DeltaPtOverPtGen", "", HistType::kTH2D, {axisPtRes, axisDeltaptRes}, true); registry.add("PtGen_DeltaEta", "", HistType::kTH2D, {axisPtRes, axisDeltaetaRes}, true); - registry.add("PtGen_DeltaPhi_Ele", "", HistType::kTH2D, {axisPtRes, axisDeltaphiRes}, true); + registry.add("PtGen_DeltaPhi_Neg", "", HistType::kTH2D, {axisPtRes, axisDeltaphiRes}, true); registry.add("PtGen_DeltaPhi_Pos", "", HistType::kTH2D, {axisPtRes, axisDeltaphiRes}, true); } else { - registry.add("PtGen_DeltaPtOverPtGen", "", HistType::kTH2D, {{ptResBinsVec, "#it{p}^{gen}_{T,e} (GeV/#it{c})"}, axisDeltaptRes}, true); - registry.add("PtGen_DeltaEta", "", HistType::kTH2D, {{ptResBinsVec, "#it{p}^{gen}_{T,e} (GeV/#it{c})"}, axisDeltaetaRes}, true); - registry.add("PtGen_DeltaPhi_Ele", "", HistType::kTH2D, {{ptResBinsVec, "#it{p}^{gen}_{T,e} (GeV/#it{c})"}, axisDeltaphiRes}, true); - registry.add("PtGen_DeltaPhi_Pos", "", HistType::kTH2D, {{ptResBinsVec, "#it{p}^{gen}_{T,e} (GeV/#it{c})"}, axisDeltaphiRes}, true); + registry.add("PtGen_DeltaPtOverPtGen", "", HistType::kTH2D, {{ptResBinsVec, "#it{p}^{gen}_{T,l} (GeV/#it{c})"}, axisDeltaptRes}, true); + registry.add("PtGen_DeltaEta", "", HistType::kTH2D, {{ptResBinsVec, "#it{p}^{gen}_{T,l} (GeV/#it{c})"}, axisDeltaetaRes}, true); + registry.add("PtGen_DeltaPhi_Neg", "", HistType::kTH2D, {{ptResBinsVec, "#it{p}^{gen}_{T,l} (GeV/#it{c})"}, axisDeltaphiRes}, true); + registry.add("PtGen_DeltaPhi_Pos", "", HistType::kTH2D, {{ptResBinsVec, "#it{p}^{gen}_{T,l} (GeV/#it{c})"}, axisDeltaphiRes}, true); } } - template - void Check(TTracksMC const& tracksMC) + template + void Check(TTracksMC const& tracksMC, TMCCollisions const&) { for (auto& mctrack : tracksMC) { - if (abs(mctrack.pdgCode()) != fPdgCode) { + if (std::abs(mctrack.pdgCode()) != fPdgCode) { continue; } + if constexpr (type == o2::aod::pwgem::dilepton::smearing::EMAnaType::kEfficiency) { + auto mccollision = mctrack.template emmcevent_as(); + if (mccollision.mpemeventId() < 0) { // if mc collisions are not reconstructed, such mc collisions should not enter efficiency calculation. + continue; + } + } + float deltaptoverpt = -1000.; if (mctrack.pt() > 0.) deltaptoverpt = (mctrack.pt() - mctrack.ptSmeared()) / mctrack.pt(); @@ -155,7 +368,7 @@ struct CheckSmearing { registry.fill(HIST("PtGen_DeltaPtOverPtGen"), mctrack.pt(), deltaptoverpt); registry.fill(HIST("PtGen_DeltaEta"), mctrack.pt(), deltaeta); if (mctrack.pdgCode() < 0) { - registry.fill(HIST("PtGen_DeltaPhi_Ele"), mctrack.pt(), deltaphi); + registry.fill(HIST("PtGen_DeltaPhi_Neg"), mctrack.pt(), deltaphi); } else { registry.fill(HIST("PtGen_DeltaPhi_Pos"), mctrack.pt(), deltaphi); } @@ -165,22 +378,30 @@ struct CheckSmearing { } // end of mctrack loop } - void processCheckMCanalysis(MyReducedTracks const& tracksMC) + void processCheckMCanalysisEM(EMMCParticlesWithSmearing const& tracksMC, MyMCCollisions const& mccollisions) { - Check(tracksMC); + Check(tracksMC, mccollisions); } + // void processCheckMCanalysisDQ(MyReducedTracks const& tracksMC) + // { + // Check(tracksMC); + // } + void processCheckCocktail(MyCocktailTracks const& tracksMC) { - Check(tracksMC); + Check(tracksMC, nullptr); } - void processDummyMCanalysis(ReducedMCTracks const&) {} + void processDummyMCanalysisEM(aod::EMMCParticles const&) {} + // void processDummyMCanalysisDQ(ReducedMCTracks const&) {} void processDummyCocktail(aod::McParticles const&) {} - PROCESS_SWITCH(CheckSmearing, processCheckMCanalysis, "Run for MC analysis", false); + PROCESS_SWITCH(CheckSmearing, processCheckMCanalysisEM, "Run for MC analysis", false); + // PROCESS_SWITCH(CheckSmearing, processCheckMCanalysisDQ, "Run for MC analysis", false); PROCESS_SWITCH(CheckSmearing, processCheckCocktail, "Run for cocktail analysis", false); - PROCESS_SWITCH(CheckSmearing, processDummyMCanalysis, "Dummy process function", false); + PROCESS_SWITCH(CheckSmearing, processDummyMCanalysisEM, "Dummy process function", false); + // PROCESS_SWITCH(CheckSmearing, processDummyMCanalysisDQ, "Dummy process function", false); PROCESS_SWITCH(CheckSmearing, processDummyCocktail, "Dummy process function", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGEM/Dilepton/Tasks/studyMCTruth.cxx b/PWGEM/Dilepton/Tasks/studyMCTruth.cxx new file mode 100644 index 00000000000..4204a95a9c4 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/studyMCTruth.cxx @@ -0,0 +1,449 @@ +// 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. +// +// ======================== +// +// This code is to study MC truth. e.g. evet selection bias +// Please write to: daiki.sekihata@cern.ch + +#include +#include "Math/Vector4D.h" + +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/TableHelper.h" +#include "Common/DataModel/EventSelection.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::dilepton::utils::mcutil; + +struct studyMCTruth { + + struct : ConfigurableGroup { + std::string prefix = "mccut_group"; + Configurable cfgEventGeneratorType{"cfgEventGeneratorType", -1, "if positive, select event generator type. i.e. gap or signal"}; + Configurable cfgPdgCodeLepton{"cfgPdgCodeLepton", 11, "pdg code for desired lepton"}; + Configurable cfgMinPtGen{"cfgMinPtGen", 0.2, "min. pT of single lepton"}; + Configurable cfgMaxPtGen{"cfgMaxPtGen", 1e+10f, "max. pT of single lepton"}; + Configurable cfgMinEtaGen{"cfgMinEtaGen", -0.8, "min. eta of for single lepton"}; + Configurable cfgMaxEtaGen{"cfgMaxEtaGen", +0.8, "max. eta of for single lepton"}; + Configurable cfgMuonTrackType{"cfgMuonTrackType", 3, "muon track type [0: MFT-MCH-MID, 3: MCH-MID]"}; + } mccuts; + + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgMinImpPar{"cfgMinImpPar", -1.f, "min. impact parameter in fm"}; // [0, 4] fm for centrality FT0C 0-10%, [8, 10] fm for centrality FT0C 30-50% in PbPb + Configurable cfgMaxImpPar{"cfgMaxImpPar", 999.f, "max. impact parameter in fm"}; + } eventcuts; + + ConfigurableAxis ConfMllBins{"ConfMllBins", {400, 0.f, 4.f}, "mll bins for output histograms"}; + ConfigurableAxis ConfPtllBins{"ConfPtllBins", {100, 0.f, 10.f}, "pTll bins for output histograms"}; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + float leptonMass = o2::constants::physics::MassElectron; + void init(o2::framework::InitContext&) + { + if (std::abs(mccuts.cfgPdgCodeLepton.value) == 11) { + leptonMass = o2::constants::physics::MassElectron; + } else if (std::abs(mccuts.cfgPdgCodeLepton.value) == 13) { + leptonMass = o2::constants::physics::MassMuon; + } else { + LOGF(fatal, "pdg code must be 11 or 13."); + } + addHistograms(); + } + + static constexpr std::string_view dileptonSigns[3] = {"uls/", "lspp/", "lsmm/"}; + static constexpr std::string_view evNames[4] = {"allMC/", "selectedMC/", "selectedMC_and_Rec/", "selectedMC_and_selectedRec/"}; + + void addHistograms() + { + const AxisSpec axis_mll{ConfMllBins, "m_{ll} (GeV/c^{2})"}; + const AxisSpec axis_ptll{ConfPtllBins, "p_{T,ll} (GeV/c)"}; + + fRegistry.add("Event/hDiffBC", "diffrence in BC;BC_{rec. coll.} - BC_{mc coll.}", kTH1D, {{101, -50.5, +50.5}}, false); + fRegistry.add("Event/allMC/hReccollsPerMCcoll", "Rec. colls per MC coll;Rec. colls per MC coll;Number of MC collisions", kTH1D, {{21, -0.5, 20.5}}, false); + fRegistry.add("Event/allMC/hSelReccollsPerMCcoll", "Selected Rec. colls per MC coll;Selected Rec. colls per MC coll;Number of MC collisions", kTH1D, {{21, -0.5, 20.5}}, false); + fRegistry.add("Event/allMC/hZvtx", "MC Zvtx;Z_{vtx} (cm)", kTH1D, {{100, -50, +50}}, false); + fRegistry.add("Event/allMC/hImpactParameter", "impact parameter;impact parameter b (fm)", kTH1D, {{200, 0, 20}}, false); + fRegistry.addClone("Event/allMC/", "Event/selectedMC/"); + fRegistry.addClone("Event/allMC/", "Event/selectedMC_and_Rec/"); + fRegistry.addClone("Event/allMC/", "Event/selectedMC_and_selectedRec/"); + + fRegistry.add("Pair/allMC/Pi0/uls/hMvsPt", "m_{ll} vs. p_{T,ll}", kTH2D, {axis_mll, axis_ptll}, true); + fRegistry.addClone("Pair/allMC/Pi0/uls/", "Pair/allMC/Pi0/lspp/"); + fRegistry.addClone("Pair/allMC/Pi0/uls/", "Pair/allMC/Pi0/lsmm/"); + fRegistry.addClone("Pair/allMC/Pi0/", "Pair/allMC/Eta/"); + fRegistry.addClone("Pair/allMC/Pi0/", "Pair/allMC/EtaPrime/"); + fRegistry.addClone("Pair/allMC/Pi0/", "Pair/allMC/Rho/"); + fRegistry.addClone("Pair/allMC/Pi0/", "Pair/allMC/Omega/"); + fRegistry.addClone("Pair/allMC/Pi0/", "Pair/allMC/Phi/"); + fRegistry.addClone("Pair/allMC/Pi0/", "Pair/allMC/JPsi/"); + fRegistry.addClone("Pair/allMC/Pi0/", "Pair/allMC/ccbar/"); + fRegistry.addClone("Pair/allMC/Pi0/", "Pair/allMC/bbbar/"); + fRegistry.addClone("Pair/allMC/", "Pair/selectedMC/"); + fRegistry.addClone("Pair/allMC/", "Pair/selectedMC_and_Rec/"); + fRegistry.addClone("Pair/allMC/", "Pair/selectedMC_and_selectedRec/"); + + // allMC = all mc collisions + // selectedMC = mc collisions selected by your event cuts + // selectedMC_and_Rec = mc collisions selected by your event cuts and at least 1 reconstructed collision is associated. + // selectedMC_and_selectedRec = mc collisions selected by your event cuts and at least 1 reconstructed collision is associated, and the associated rec. collision is selected by your cuts. + } + + template + int FindLF(TTrack const& posmc, TTrack const& negmc, TMCParticles const& mcparticles) + { + int arr[] = { + FindCommonMotherFrom2Prongs(posmc, negmc, -mccuts.cfgPdgCodeLepton, mccuts.cfgPdgCodeLepton, 111, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -mccuts.cfgPdgCodeLepton, mccuts.cfgPdgCodeLepton, 221, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -mccuts.cfgPdgCodeLepton, mccuts.cfgPdgCodeLepton, 331, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -mccuts.cfgPdgCodeLepton, mccuts.cfgPdgCodeLepton, 113, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -mccuts.cfgPdgCodeLepton, mccuts.cfgPdgCodeLepton, 223, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -mccuts.cfgPdgCodeLepton, mccuts.cfgPdgCodeLepton, 333, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -mccuts.cfgPdgCodeLepton, mccuts.cfgPdgCodeLepton, 443, mcparticles)}; + int size = sizeof(arr) / sizeof(*arr); + int max = *std::max_element(arr, arr + size); + return max; + } + + template + bool isSelectedMCParticle(TMCParticle const& mcparticle) + { + if (std::abs(mcparticle.pdgCode()) != mccuts.cfgPdgCodeLepton) { + return false; + } + if (!mcparticle.has_mothers()) { + return false; + } + if (!(mcparticle.isPhysicalPrimary() || mcparticle.producedByGenerator())) { + return false; + } + + if constexpr (isSmeared) { + if (std::abs(mccuts.cfgPdgCodeLepton) == 11) { + if (mcparticle.ptSmeared() < mccuts.cfgMinPtGen || mccuts.cfgMaxPtGen < mcparticle.ptSmeared()) { + return false; + } + if (mcparticle.etaSmeared() < mccuts.cfgMinEtaGen || mccuts.cfgMaxEtaGen < mcparticle.etaSmeared()) { + return false; + } + } else if (std::abs(mccuts.cfgPdgCodeLepton) == 13) { + if (mccuts.cfgMuonTrackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + if (mcparticle.ptSmeared_sa_muon() < mccuts.cfgMinPtGen || mccuts.cfgMaxPtGen < mcparticle.ptSmeared_sa_muon()) { + return false; + } + if (mcparticle.etaSmeared_sa_muon() < mccuts.cfgMinEtaGen || mccuts.cfgMaxEtaGen < mcparticle.etaSmeared_sa_muon()) { + return false; + } + } else if (mccuts.cfgMuonTrackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + if (mcparticle.ptSmeared_gl_muon() < mccuts.cfgMinPtGen || mccuts.cfgMaxPtGen < mcparticle.ptSmeared_gl_muon()) { + return false; + } + if (mcparticle.etaSmeared_gl_muon() < mccuts.cfgMinEtaGen || mccuts.cfgMaxEtaGen < mcparticle.etaSmeared_gl_muon()) { + return false; + } + } + } + } else { + if (mcparticle.pt() < mccuts.cfgMinPtGen || mccuts.cfgMaxPtGen < mcparticle.pt()) { + return false; + } + if (mcparticle.eta() < mccuts.cfgMinEtaGen || mccuts.cfgMaxEtaGen < mcparticle.eta()) { + return false; + } + } + + return true; + } + + template + bool isSelectedCollision(TCollision const& collision, TBC const& bc) + { + if (collision.posZ() < eventcuts.cfgZvtxMin || eventcuts.cfgZvtxMax < collision.posZ()) { + return false; + } + + if (eventcuts.cfgRequireFT0AND && !bc.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + return false; + } + if (eventcuts.cfgRequireNoTFB && !bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (eventcuts.cfgRequireNoITSROFB && !bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + return true; + } + + template + void fillTrueInfo(TMCLepton const& t1, TMCLepton const& t2, TMCParticles const& mcParticles) + { + if (!isSelectedMCParticle(t1) || !isSelectedMCParticle(t2)) { + return; + } + + float pt1 = 0.f, eta1 = 0.f, phi1 = 0.f, pt2 = 0.f, eta2 = 0.f, phi2 = 0.f; + if constexpr (isSmeared) { + if (std::abs(mccuts.cfgPdgCodeLepton) == 11) { + pt1 = t1.ptSmeared(); + eta1 = t1.etaSmeared(); + phi1 = t1.phiSmeared(); + pt2 = t2.ptSmeared(); + eta2 = t2.etaSmeared(); + phi2 = t2.phiSmeared(); + } else if (std::abs(mccuts.cfgPdgCodeLepton) == 13) { + if (mccuts.cfgMuonTrackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + pt1 = t1.ptSmeared_sa_muon(); + eta1 = t1.etaSmeared_sa_muon(); + phi1 = t1.phiSmeared_sa_muon(); + pt2 = t2.ptSmeared_sa_muon(); + eta2 = t2.etaSmeared_sa_muon(); + phi2 = t2.phiSmeared_sa_muon(); + } else if (mccuts.cfgMuonTrackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + pt1 = t1.ptSmeared_gl_muon(); + eta1 = t1.etaSmeared_gl_muon(); + phi1 = t1.phiSmeared_gl_muon(); + pt2 = t2.ptSmeared_gl_muon(); + eta2 = t2.etaSmeared_gl_muon(); + phi2 = t2.phiSmeared_gl_muon(); + } else { + pt1 = t1.pt(); + eta1 = t1.eta(); + phi1 = t1.phi(); + pt2 = t2.pt(); + eta2 = t2.eta(); + phi2 = t2.phi(); + } + } + } else { + pt1 = t1.pt(); + eta1 = t1.eta(); + phi1 = t1.phi(); + pt2 = t2.pt(); + eta2 = t2.eta(); + phi2 = t2.phi(); + } + + ROOT::Math::PtEtaPhiMVector v1(pt1, eta1, phi1, leptonMass); + ROOT::Math::PtEtaPhiMVector v2(pt2, eta2, phi2, leptonMass); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + + if (v12.Rapidity() < mccuts.cfgMinEtaGen || mccuts.cfgMaxEtaGen < v12.Rapidity()) { + return; + } + + int mother_id = FindLF(t1, t2, mcParticles); + int hfll_type = IsHF(t1, t2, mcParticles); + + if (mother_id > 0) { // same mother (photon, LF, Quarkonia) + const auto& mp = mcParticles.iteratorAt(mother_id); + if (!(mp.isPhysicalPrimary() || mp.producedByGenerator())) { + return; + } + switch (std::abs(mp.pdgCode())) { + case 111: + fRegistry.fill(HIST("Pair/") + HIST(evNames[evtype]) + HIST("Pi0/") + HIST(dileptonSigns[signtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + break; + case 221: + fRegistry.fill(HIST("Pair/") + HIST(evNames[evtype]) + HIST("Eta/") + HIST(dileptonSigns[signtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + break; + case 331: + fRegistry.fill(HIST("Pair/") + HIST(evNames[evtype]) + HIST("EtaPrime/") + HIST(dileptonSigns[signtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + break; + case 113: + fRegistry.fill(HIST("Pair/") + HIST(evNames[evtype]) + HIST("Rho/") + HIST(dileptonSigns[signtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + break; + case 223: + fRegistry.fill(HIST("Pair/") + HIST(evNames[evtype]) + HIST("Omega/") + HIST(dileptonSigns[signtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + break; + case 333: + fRegistry.fill(HIST("Pair/") + HIST(evNames[evtype]) + HIST("Phi/") + HIST(dileptonSigns[signtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + break; + case 443: + fRegistry.fill(HIST("Pair/") + HIST(evNames[evtype]) + HIST("JPsi/") + HIST(dileptonSigns[signtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + break; + default: + break; + } + } else if (hfll_type > -1) { // HFll + switch (hfll_type) { + case static_cast(EM_HFeeType::kCe_Ce): // ULS + fRegistry.fill(HIST("Pair/") + HIST(evNames[evtype]) + HIST("ccbar/") + HIST(dileptonSigns[signtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + break; + case static_cast(EM_HFeeType::kBe_Be): // ULS + fRegistry.fill(HIST("Pair/") + HIST(evNames[evtype]) + HIST("bbbar/") + HIST(dileptonSigns[signtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + break; + case static_cast(EM_HFeeType::kBCe_BCe): // ULS + fRegistry.fill(HIST("Pair/") + HIST(evNames[evtype]) + HIST("bbbar/") + HIST(dileptonSigns[signtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + break; + case static_cast(EM_HFeeType::kBCe_Be_SameB): // ULS + fRegistry.fill(HIST("Pair/") + HIST(evNames[evtype]) + HIST("bbbar/") + HIST(dileptonSigns[signtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + break; + case static_cast(EM_HFeeType::kBCe_Be_DiffB): // LS + fRegistry.fill(HIST("Pair/") + HIST(evNames[evtype]) + HIST("bbbar/") + HIST(dileptonSigns[signtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + default: + break; + } + } + } + + template + void runMC(TMCCollisions const& mcCollisions, TMCParticles const& mcParticles, TBCs const&, TCollisions const& collisions, TMCPosLeptons const& mcPosLeptons, TMCNegLeptons const& mcNegLeptons) + { + for (const auto& mcCollision : mcCollisions) { + + if (mccuts.cfgEventGeneratorType >= 0 && mcCollision.getSubGeneratorId() != mccuts.cfgEventGeneratorType) { + continue; + } + + const auto& bc_from_mcCollision = mcCollision.template bc_as(); + bool isSelectedMC = isSelectedCollision(mcCollision, bc_from_mcCollision); + + const auto& reccolls_per_mccoll = collisions.sliceBy(recColperMcCollision, mcCollision.globalIndex()); + int nselreccolls_per_mccoll = 0; + for (const auto& rec_col : reccolls_per_mccoll) { + if (isSelectedCollision(rec_col, rec_col.template foundBC_as())) { + nselreccolls_per_mccoll++; + } + } // end of reconstructed collision + fRegistry.fill(HIST("Event/allMC/hReccollsPerMCcoll"), reccolls_per_mccoll.size()); + fRegistry.fill(HIST("Event/allMC/hSelReccollsPerMCcoll"), nselreccolls_per_mccoll); + + bool isSelectedRec = false; + bool hasRecCollision = false; + if (mcCollision.mpemeventId() >= 0) { + hasRecCollision = true; + const auto& collision = collisions.rawIteratorAt(mcCollision.mpemeventId()); // most probable reconstructed collision + const auto& bc_from_collision = collision.template foundBC_as(); + isSelectedRec = isSelectedCollision(collision, bc_from_collision); + fRegistry.fill(HIST("Event/hDiffBC"), bc_from_collision.globalBC() - bc_from_mcCollision.globalBC()); + } + fRegistry.fill(HIST("Event/allMC/hZvtx"), mcCollision.posZ()); + fRegistry.fill(HIST("Event/allMC/hImpactParameter"), mcCollision.impactParameter()); + + if (isSelectedMC) { + fRegistry.fill(HIST("Event/selectedMC/hReccollsPerMCcoll"), reccolls_per_mccoll.size()); + fRegistry.fill(HIST("Event/selectedMC/hSelReccollsPerMCcoll"), nselreccolls_per_mccoll); + fRegistry.fill(HIST("Event/selectedMC/hZvtx"), mcCollision.posZ()); + fRegistry.fill(HIST("Event/selectedMC/hImpactParameter"), mcCollision.impactParameter()); + if (hasRecCollision) { + fRegistry.fill(HIST("Event/selectedMC_and_Rec/hReccollsPerMCcoll"), reccolls_per_mccoll.size()); + fRegistry.fill(HIST("Event/selectedMC_and_Rec/hSelReccollsPerMCcoll"), nselreccolls_per_mccoll); + fRegistry.fill(HIST("Event/selectedMC_and_Rec/hZvtx"), mcCollision.posZ()); + fRegistry.fill(HIST("Event/selectedMC_and_Rec/hImpactParameter"), mcCollision.impactParameter()); + if (isSelectedRec) { + fRegistry.fill(HIST("Event/selectedMC_and_selectedRec/hReccollsPerMCcoll"), reccolls_per_mccoll.size()); + fRegistry.fill(HIST("Event/selectedMC_and_selectedRec/hSelReccollsPerMCcoll"), nselreccolls_per_mccoll); + fRegistry.fill(HIST("Event/selectedMC_and_selectedRec/hZvtx"), mcCollision.posZ()); + fRegistry.fill(HIST("Event/selectedMC_and_selectedRec/hImpactParameter"), mcCollision.impactParameter()); + } + } + } + + // store MC true information + const auto& posLeptons_per_mccollision = mcPosLeptons.sliceBy(perMcCollision, mcCollision.globalIndex()); + const auto& negLeptons_per_mccollision = mcNegLeptons.sliceBy(perMcCollision, mcCollision.globalIndex()); + + for (const auto& [pos, neg] : combinations(CombinationsFullIndexPolicy(posLeptons_per_mccollision, negLeptons_per_mccollision))) { // ULS + fillTrueInfo<0, 0, isSmeared>(pos, neg, mcParticles); + if (isSelectedMC) { + fillTrueInfo<1, 0, isSmeared>(pos, neg, mcParticles); + if (hasRecCollision) { + fillTrueInfo<2, 0, isSmeared>(pos, neg, mcParticles); + if (isSelectedRec) { + fillTrueInfo<3, 0, isSmeared>(pos, neg, mcParticles); + } + } + } + } // end of ULS pair loop + + for (auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posLeptons_per_mccollision, posLeptons_per_mccollision))) { // LS++ + fillTrueInfo<0, 1, isSmeared>(pos1, pos2, mcParticles); + if (isSelectedMC) { + fillTrueInfo<1, 1, isSmeared>(pos1, pos2, mcParticles); + if (hasRecCollision) { + fillTrueInfo<2, 1, isSmeared>(pos1, pos2, mcParticles); + if (isSelectedRec) { + fillTrueInfo<3, 1, isSmeared>(pos1, pos2, mcParticles); + } + } + } + } // end of LS++ pair loop + + for (auto& [neg1, neg2] : combinations(CombinationsStrictlyUpperIndexPolicy(negLeptons_per_mccollision, negLeptons_per_mccollision))) { // LS-- + fillTrueInfo<0, 2, isSmeared>(neg1, neg2, mcParticles); + if (isSelectedMC) { + fillTrueInfo<1, 2, isSmeared>(neg1, neg2, mcParticles); + if (hasRecCollision) { + fillTrueInfo<2, 2, isSmeared>(neg1, neg2, mcParticles); + if (isSelectedRec) { + fillTrueInfo<3, 2, isSmeared>(neg1, neg2, mcParticles); + } + } + } + } // end of LS-- pair loop + + } // end of mc collision loop + + } // end of skimmingMC + + SliceCache cache; + Preslice perMcCollision = aod::mcparticle::mcCollisionId; + PresliceUnsorted recColperMcCollision = aod::mccollisionlabel::mcCollisionId; + + using MyMcCollisions = soa::Join; + + Filter collisionFilter = eventcuts.cfgMinImpPar < o2::aod::mccollision::impactParameter && o2::aod::mccollision::impactParameter < eventcuts.cfgMaxImpPar; + using FilteredMyMcCollisions = soa::Filtered; + + Partition McPosLeptons = o2::aod::mcparticle::pdgCode == -mccuts.cfgPdgCodeLepton && (mccuts.cfgMinPtGen < o2::aod::mcparticle::pt && o2::aod::mcparticle::pt < mccuts.cfgMaxPtGen) && (mccuts.cfgMinEtaGen < o2::aod::mcparticle::eta && o2::aod::mcparticle::eta < mccuts.cfgMaxEtaGen); + Partition McNegLeptons = o2::aod::mcparticle::pdgCode == mccuts.cfgPdgCodeLepton && (mccuts.cfgMinPtGen < o2::aod::mcparticle::pt && o2::aod::mcparticle::pt < mccuts.cfgMaxPtGen) && (mccuts.cfgMinEtaGen < o2::aod::mcparticle::eta && o2::aod::mcparticle::eta < mccuts.cfgMaxEtaGen); + + using SmearedMcParticles = soa::Join; + Partition McPosLeptonsSmeared = o2::aod::mcparticle::pdgCode == -mccuts.cfgPdgCodeLepton && ifnode(mccuts.cfgPdgCodeLepton.node() == 11, (mccuts.cfgMinPtGen.node() < o2::aod::smearedtrack::ptSmeared && o2::aod::smearedtrack::ptSmeared < mccuts.cfgMaxPtGen.node()) && (mccuts.cfgMinEtaGen.node() < o2::aod::smearedtrack::etaSmeared && o2::aod::smearedtrack::etaSmeared < mccuts.cfgMaxEtaGen.node()), ifnode(mccuts.cfgMuonTrackType.node() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack), (mccuts.cfgMinPtGen.node() < o2::aod::smearedtrack::ptSmeared_gl_muon && o2::aod::smearedtrack::ptSmeared_gl_muon < mccuts.cfgMaxPtGen.node()) && (mccuts.cfgMinEtaGen.node() < o2::aod::smearedtrack::etaSmeared_gl_muon && o2::aod::smearedtrack::etaSmeared_gl_muon < mccuts.cfgMaxEtaGen.node()), (mccuts.cfgMinPtGen.node() < o2::aod::smearedtrack::ptSmeared_sa_muon && o2::aod::smearedtrack::ptSmeared_sa_muon < mccuts.cfgMaxPtGen.node()) && (mccuts.cfgMinEtaGen.node() < o2::aod::smearedtrack::etaSmeared_sa_muon && o2::aod::smearedtrack::etaSmeared_sa_muon < mccuts.cfgMaxEtaGen.node()))); + Partition McNegLeptonsSmeared = o2::aod::mcparticle::pdgCode == mccuts.cfgPdgCodeLepton && ifnode(mccuts.cfgPdgCodeLepton.node() == 11, (mccuts.cfgMinPtGen.node() < o2::aod::smearedtrack::ptSmeared && o2::aod::smearedtrack::ptSmeared < mccuts.cfgMaxPtGen.node()) && (mccuts.cfgMinEtaGen.node() < o2::aod::smearedtrack::etaSmeared && o2::aod::smearedtrack::etaSmeared < mccuts.cfgMaxEtaGen.node()), ifnode(mccuts.cfgMuonTrackType.node() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack), (mccuts.cfgMinPtGen.node() < o2::aod::smearedtrack::ptSmeared_gl_muon && o2::aod::smearedtrack::ptSmeared_gl_muon < mccuts.cfgMaxPtGen.node()) && (mccuts.cfgMinEtaGen.node() < o2::aod::smearedtrack::etaSmeared_gl_muon && o2::aod::smearedtrack::etaSmeared_gl_muon < mccuts.cfgMaxEtaGen.node()), (mccuts.cfgMinPtGen.node() < o2::aod::smearedtrack::ptSmeared_sa_muon && o2::aod::smearedtrack::ptSmeared_sa_muon < mccuts.cfgMaxPtGen.node()) && (mccuts.cfgMinEtaGen.node() < o2::aod::smearedtrack::etaSmeared_sa_muon && o2::aod::smearedtrack::etaSmeared_sa_muon < mccuts.cfgMaxEtaGen.node()))); + + void processMC(FilteredMyMcCollisions const& mcCollisions, aod::McParticles const& mcParticles, soa::Join const& bcs, soa::Join const& collisions) + { + runMC(mcCollisions, mcParticles, bcs, collisions, McPosLeptons, McNegLeptons); + } + PROCESS_SWITCH(studyMCTruth, processMC, "process MC", true); + + void processMCSmeared(FilteredMyMcCollisions const& mcCollisions, SmearedMcParticles const& mcParticles, soa::Join const& bcs, soa::Join const& collisions) + { + runMC(mcCollisions, mcParticles, bcs, collisions, McPosLeptonsSmeared, McNegLeptonsSmeared); + } + PROCESS_SWITCH(studyMCTruth, processMCSmeared, "processMC with smeared values", false); + + void processDummy(FilteredMyMcCollisions const&) {} + PROCESS_SWITCH(studyMCTruth, processDummy, "process Dummy", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"study-mc-truth"})}; +} diff --git a/PWGEM/Dilepton/Tasks/tableReaderBarrel.cxx b/PWGEM/Dilepton/Tasks/tableReaderBarrel.cxx new file mode 100644 index 00000000000..d78ef01676c --- /dev/null +++ b/PWGEM/Dilepton/Tasks/tableReaderBarrel.cxx @@ -0,0 +1,1266 @@ +// 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. +// +// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/MixingHandler.h" +#include "PWGDQ/Core/AnalysisCut.h" +#include "PWGDQ/Core/AnalysisCompositeCut.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/MixingLibrary.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "Field/MagneticField.h" +#include "TGeoGlobalMagField.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "Common/CCDB/EventSelectionParams.h" + +using std::cout; +using std::endl; +using std::string; + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod; + +// Some definitions +namespace o2::aod +{ + +namespace dqanalysisflags +{ +// TODO: the barrel amd muon selection columns are bit maps so unsigned types should be used, however, for now this is not supported in Filter expressions +// TODO: For now in the tasks we just statically convert from unsigned int to int, which should be fine as long as we do +// not use a large number of bits (>=30) +// Bcandidate columns for ML analysis of B->Jpsi+K +DECLARE_SOA_COLUMN(MixingHash, mixingHash, int); +DECLARE_SOA_COLUMN(IsEventSelected, isEventSelected, int); +DECLARE_SOA_COLUMN(IsBarrelSelected, isBarrelSelected, int); +DECLARE_SOA_COLUMN(IsBarrelSelectedPrefilter, isBarrelSelectedPrefilter, int); +DECLARE_SOA_COLUMN(IsPrefilterVetoed, isPrefilterVetoed, int); +} // namespace dqanalysisflags + +DECLARE_SOA_TABLE(EventCuts, "AOD", "DQANAEVCUTS", dqanalysisflags::IsEventSelected); +DECLARE_SOA_TABLE(MixingHashes, "AOD", "DQANAMIXHASH", dqanalysisflags::MixingHash); +DECLARE_SOA_TABLE(BarrelTrackCuts, "AOD", "DQANATRKCUTS", dqanalysisflags::IsBarrelSelected, dqanalysisflags::IsBarrelSelectedPrefilter); +DECLARE_SOA_TABLE(Prefilter, "AOD", "DQPREFILTER", dqanalysisflags::IsPrefilterVetoed); +} // namespace o2::aod + +// Declarations of various short names +using MyEvents = soa::Join; +using MyEventsSelected = soa::Join; +using MyEventsHashSelected = soa::Join; +using MyEventsVtxCov = soa::Join; +using MyEventsVtxCovSelected = soa::Join; +using MyEventsVtxCovSelectedQvector = soa::Join; +// using MyEventsVtxCovSelectedQvectorCentr = soa::Join; +using MyEventsQvector = soa::Join; +using MyEventsQvectorMultExtra = soa::Join; +using MyEventsQvectorCentr = soa::Join; +using MyEventsQvectorCentrMultExtra = soa::Join; +using MyEventsHashSelectedQvector = soa::Join; +// using MyEventsHashSelectedQvectorCentr = soa::Join; + +using MyBarrelTracks = soa::Join; +using MyBarrelTracksWithCov = soa::Join; +using MyBarrelTracksSelected = soa::Join; +using MyBarrelTracksSelectedWithPrefilter = soa::Join; +using MyBarrelTracksSelectedWithCov = soa::Join; +using MyBarrelTracksSelectedWithColl = soa::Join; + +// bit maps used for the Fill functions of the VarManager +constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended; +constexpr static uint32_t gkEventFillMapWithCov = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov; +constexpr static uint32_t gkEventFillMapWithQvector = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventQvector; +constexpr static uint32_t gkEventFillMapWithQvectorMultExtra = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventQvector | VarManager::ObjTypes::ReducedEventMultExtra; +constexpr static uint32_t gkEventFillMapWithQvectorCentr = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::CollisionQvect; +constexpr static uint32_t gkEventFillMapWithQvectorCentrMultExtra = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::CollisionQvect | VarManager::ObjTypes::ReducedEventMultExtra; +constexpr static uint32_t gkEventFillMapWithCovQvector = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov | VarManager::ObjTypes::ReducedEventQvector; +// constexpr static uint32_t gkEventFillMapWithCovQvectorCentr = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov | VarManager::ObjTypes::CollisionQvect; +constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelPID; +constexpr static uint32_t gkTrackFillMapWithCov = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID; +constexpr static uint32_t gkTrackFillMapWithColl = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelPID | VarManager::ObjTypes::ReducedTrackCollInfo; + +constexpr static int pairTypeEE = VarManager::kDecayToEE; + +// Global function used to define needed histogram classes +void DefineHistograms(HistogramManager* histMan, TString histClasses, Configurable configVar); // defines histograms for all tasks + +struct AnalysisEventSelection { + Produces eventSel; + Produces hash; + OutputObj fOutputList{"output"}; + // TODO: Provide the mixing variables and binning directly via configurables (e.g. vectors of float) + Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; + Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigITSROFrameStartBorderMargin{"ITSROFrameStartBorderMargin", -1, "Number of bcs at the start of ITS RO Frame border. Take from CCDB if -1"}; + Configurable fConfigITSROFrameEndBorderMargin{"ITSROFrameEndBorderMargin", -1, "Number of bcs at the end of ITS RO Frame border. Take from CCDB if -1"}; + Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + AnalysisCompositeCut* fEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgCentFT0CMin{"cfgCentralityMin", -1000000000.f, "min. centrality"}; + Configurable cfgCentFT0CMax{"cfgCentralityMax", 1000000000.f, "max. centrality"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -1000000000, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + } eventcuts; + + HistogramManager* fHistMan = nullptr; + MixingHandler* fMixHandler = nullptr; + int fLastRun; + + Service fCCDB; + + void init(o2::framework::InitContext&) + { + fEventCut = new AnalysisCompositeCut(true); + fEventCut->AddCut(GetEventCut()); + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill + + VarManager::SetDefaultVarNames(); + if (fConfigQA) { + fHistMan = new HistogramManager("analysisHistos", "", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + DefineHistograms(fHistMan, "Event_BeforeCuts;Event_AfterCuts;", fConfigAddEventHistogram); // define all histograms + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } + + TString mixVarsString = fConfigMixingVariables.value; + std::unique_ptr objArray(mixVarsString.Tokenize(",")); + if (objArray->GetEntries() > 0) { + fMixHandler = new MixingHandler("mixingHandler", "mixing handler"); + fMixHandler->Init(); + for (int iVar = 0; iVar < objArray->GetEntries(); ++iVar) { + dqmixing::SetUpMixing(fMixHandler, objArray->At(iVar)->GetName()); + } + } + + // CCDB configuration + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + // Not later than now objects + // fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); + + fLastRun = -1; + } + + template + void runEventSelection(TEvent const& event) + { + if (event.runNumber() != fLastRun) { + auto alppar = fCCDB->getForTimeStamp>("ITS/Config/AlpideParam", event.timestamp()); + EventSelectionParams* par = fCCDB->getForTimeStamp("EventSelection/EventSelectionParams", event.timestamp()); + int itsROFrameStartBorderMargin = fConfigITSROFrameStartBorderMargin < 0 ? par->fITSROFrameStartBorderMargin : fConfigITSROFrameStartBorderMargin; + int itsROFrameEndBorderMargin = fConfigITSROFrameEndBorderMargin < 0 ? par->fITSROFrameEndBorderMargin : fConfigITSROFrameEndBorderMargin; + VarManager::SetITSROFBorderselection(alppar->roFrameBiasInBC, alppar->roFrameLengthInBC, itsROFrameStartBorderMargin, itsROFrameEndBorderMargin); + fLastRun = event.runNumber(); + } + + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNEventWiseVariables); + + VarManager::FillEvent(event); + // TODO: make this condition at compile time + if (fConfigQA) { + fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); // automatically fill all the histograms in the class Event + } + if (fEventCut->IsSelected(VarManager::fgValues)) { + if (fConfigQA) { + fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); + } + eventSel(1); + } else { + eventSel(0); + } + + if (fMixHandler != nullptr) { + int hh = fMixHandler->FindEventCategory(VarManager::fgValues); + hash(hh); + } + } + + AnalysisCut* GetEventCut() + { + AnalysisCut* cut = new AnalysisCut("eventcut", "eventcut"); + cut->AddCut(VarManager::kVtxZ, -eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + if (eventcuts.cfgRequireSel8) + cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); + if (eventcuts.cfgRequireNoTFB) + cut->AddCut(VarManager::kIsNoTFBorder, 0.5, 1.5); + if (eventcuts.cfgRequireNoITSROFB) + cut->AddCut(VarManager::kIsNoITSROFBorder, 0.5, 1.5); + if (eventcuts.cfgRequireNoSameBunchPileup) + cut->AddCut(VarManager::kIsNoSameBunch, 0.5, 1.5); + if (eventcuts.cfgRequireGoodZvtxFT0vsPV) + cut->AddCut(VarManager::kIsGoodZvtxFT0vsPV, 0.5, 1.5); + cut->AddCut(VarManager::kCentFT0C, eventcuts.cfgCentFT0CMin, eventcuts.cfgCentFT0CMax); + cut->AddCut(VarManager::kTrackOccupancyInTimeRange, eventcuts.cfgTrackOccupancyMin, eventcuts.cfgTrackOccupancyMax); + return cut; + } + + void processSkimmed(MyEvents::iterator const& event) + { + runEventSelection(event); + } + void processSkimmedQVector(MyEventsQvector::iterator const& event) + { + runEventSelection(event); + } + void processSkimmedQVectorCentr(MyEventsQvectorCentr::iterator const& event) + { + runEventSelection(event); + } + void processSkimmedQVectorMultExtra(MyEventsQvectorMultExtra::iterator const& event) + { + runEventSelection(event); + } + void processSkimmedQVectorCentrMultExtra(MyEventsQvectorCentrMultExtra::iterator const& event) + { + runEventSelection(event); + } + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisEventSelection, processSkimmed, "Run event selection on DQ skimmed events", false); + PROCESS_SWITCH(AnalysisEventSelection, processSkimmedQVector, "Run event selection on DQ skimmed events with Q vector from GFW", false); + PROCESS_SWITCH(AnalysisEventSelection, processSkimmedQVectorCentr, "Run event selection on DQ skimmed events with Q vector from CFW", false); + PROCESS_SWITCH(AnalysisEventSelection, processSkimmedQVectorMultExtra, "Run event selection on DQ skimmed events with Q vector from GFW and MultPV", false); + PROCESS_SWITCH(AnalysisEventSelection, processSkimmedQVectorCentrMultExtra, "Run event selection on DQ skimmed events with Q vector from CFW and MultPV", false); + PROCESS_SWITCH(AnalysisEventSelection, processDummy, "Dummy function", false); + // TODO: Add process functions subscribing to Framework Collision +}; + +struct AnalysisTrackSelection { + Produces trackSel; + OutputObj fOutputList{"output"}; + // The list of cuts should contain all the track cuts needed later in analysis, including + // for candidate electron selection (+ eventual prefilter cuts) and other needs like quarkonium - hadron correlations + // The user must ensure using them properly in the tasks downstream + // NOTE: For now, the candidate electron cuts must be provided first, then followed by any other needed selections + Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigQAIfSelEvt{"cfgQAIfSelEvt", true, "If true, fill QA only for selected events"}; + Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigPrefilterCutId{"cfgPrefilterCutId", 32, "Id of the Prefilter track cut (starting at 0)"}; // In order to create another column prefilter (should be temporary before improving cut selection in configurables, then displaced to AnalysisPrefilterSelection) + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable fConfigCcdbPathTPC{"ccdb-path-tpc", "Users/z/zhxiong/TPCPID/PostCalib", "base path to the ccdb object"}; + Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable fConfigComputeTPCpostCalib{"cfgTPCpostCalib", false, "If true, compute TPC post-calibrated n-sigmas"}; + Configurable fConfigRunPeriods{"cfgRunPeriods", "LHC22f", "run periods for used data"}; + Configurable fConfigDummyRunlist{"cfgDummyRunlist", false, "If true, use dummy runlist"}; + Configurable fConfigInitRunNumber{"cfgInitRunNumber", 543215, "Initial run number used in run by run checks"}; + Configurable fConfigNbTrackCut{"cfgNbTrackCut", 1, "Number of cuts including prefilter cut, need to be below 30"}; + + std::vector fTrackCuts; + struct : ConfigurableGroup { + std::string prefix = "trackingcut_group"; + Configurable> cfgEtaMax{"cfgEtaMax", {0.8f}, "Comma separated list of eta ranges"}; + Configurable> cfgPtMin{"cfgPtMin", {0.2f}, "Comma separated list of pt min"}; + Configurable> cfgPtMax{"cfgPtMax", {20.f}, "Comma separated list of pt max"}; + Configurable> cfgDCAxyMax{"cfgDCAxyMax", {3.f}, "Comma separated list of dcaxy max"}; + Configurable> cfgDCAzMax{"cfgDCAzMax", {1.f}, "Comma separated list of dcaz max"}; + Configurable> cfgIsSPDfirst{"cfgIsSPDfirst", {1}, "Comma separated list of if one requires one hit in the first ITS layer"}; + Configurable> cfgIsSPDany{"cfgIsSPDany", {-1}, "Comma separated list of if one requires one hit in the first two ITS layers"}; + Configurable> cfgIsITSibAny{"cfgIsITSibAny", {-1}, "Comma separated list of if one requires one hit in the first three ITS layers"}; + Configurable> cfgITSchi2Max{"cfgITSchi2Max", {5.f}, "Comma separated list of its chi2 max"}; + Configurable> cfgITSnclsMin{"cfgITSnclsMin", {4.5f}, "Comma separated list of min number of ITS clusters"}; + Configurable> cfgITSnclsMax{"cfgITSnclsMax", {7.5f}, "Comma separated list of max number of ITS clusters"}; + Configurable> cfgTPCchi2Max{"cfgTPCchi2Max", {4.f}, "Comma separated list of tpc chi2 max"}; + Configurable> cfgTPCnclsMin{"cfgTPCnclsMin", {90.f}, "Comma separated list of min number of TPC clusters"}; + Configurable> cfgTPCnclsMax{"cfgTPCnclsMax", {170.f}, "Comma separated list of max number of TPC clusters"}; + Configurable> cfgTPCnclsCRMin{"cfgTPCnclsCRMin", {80.f}, "Comma separated list of min number of TPC crossed rows"}; + Configurable> cfgTPCnclsCRMax{"cfgTPCnclsCRMax", {170.f}, "Comma separated list of max number of TPC crossed rows"}; + Configurable> cfgIsDalitzLeg{"cfgIsDalitzLeg", {-1}, "Comma separated list of if one requires hit for prefilter done during skimming, should be between 1 and 8"}; + } trackcuts; + + struct : ConfigurableGroup { + std::string prefix = "pidcut_group"; + Configurable> cfgPIDmode{"cfgPIDmode", {1}, "List of PID mode: 1 TPChadrrejection, 2 TOFreq, 3 OR between both"}; + Configurable> cfgRejBadTOF{"cfgRejBadTOF", {1}, "List of reject bad TOF: 1 yes, 0 no"}; + Configurable> cfgTPCNSigmaElMin{"cfgTPCNSigmaElMin", {-1.f}, "Comma separated list of min TPC nsigma e for inclusion"}; + Configurable> cfgTPCNSigmaElMax{"cfgTPCNSigmaElMax", {3.f}, "Comma separated list of max TPC nsigma e for inclusion"}; + Configurable> cfgTPCNSigmaPiMin{"cfgTPCNSigmaPiMin", {-3.f}, "Comma separated list of min TPC nsigma pion for exclusion"}; + Configurable> cfgTPCNSigmaPiMax{"cfgTPCNSigmaPiMax", {4.f}, "Comma separated list of max TPC nsigma pion for exclusion"}; + Configurable> cfgTPCNSigmaPrMin{"cfgTPCNSigmaPrMin", {-3.f}, "Comma separated list of min TPC nsigma proton for exclusion"}; + Configurable> cfgTPCNSigmaPrMax{"cfgTPCNSigmaPrMax", {4.f}, "Comma separated list of max TPC nsigma proton for exclusion"}; + Configurable> cfgTPCNSigmaKaMin{"cfgTPCNSigmaKaMin", {-3.f}, "Comma separated list of min TPC nsigma kaon for exclusion"}; + Configurable> cfgTPCNSigmaKaMax{"cfgTPCNSigmaKaMax", {4.f}, "Comma separated list of max TPC nsigma kaon for exclusion"}; + Configurable> cfgTPCNSigmaMuMin{"cfgTPCNSigmaMuMin", {0.f}, "Comma separated list of min TPC nsigma muon for exclusion"}; + Configurable> cfgTPCNSigmaMuMax{"cfgTPCNSigmaMuMax", {0.f}, "Comma separated list of max TPC nsigma muon for exclusion"}; + Configurable> cfgTOFNSigmaElMin{"cfgTOFNSigmaElMin", {-3.f}, "Comma separated list of min TOF nsigma e for inclusion"}; + Configurable> cfgTOFNSigmaElMax{"cfgTOFNSigmaElMax", {2.f}, "Comma separated list of max TOF nsigma e for inclusion"}; + } pidcuts; + + Service fCCDB; + + HistogramManager* fHistMan; + + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + + void init(o2::framework::InitContext&) + { + fCurrentRun = 0; + + if (fConfigNbTrackCut > 0 && CheckSize()) { + for (std::size_t icut = 0; icut < fConfigNbTrackCut; ++icut) { + AnalysisCompositeCut* cut = new AnalysisCompositeCut(Form("trackcut%zu", icut), Form("trackcut%zu", icut)); + cut->AddCut(GetTrackCut(icut)); + cut->AddCut(GetPIDCut(icut)); + fTrackCuts.push_back(*cut); + } + } + + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill + + if (fConfigQA) { + VarManager::SetDefaultVarNames(); + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + // set one histogram directory for each defined track cut + TString histDirNames = "TrackBarrel_BeforeCuts;"; + for (auto& cut : fTrackCuts) { + histDirNames += Form("TrackBarrel_%s;", cut.GetName()); + } + + DefineHistograms(fHistMan, histDirNames.Data(), fConfigAddTrackHistogram); // define all histograms + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } + if (fConfigDummyRunlist) { + VarManager::SetDummyRunlist(fConfigInitRunNumber); + } + if (fConfigComputeTPCpostCalib) { + // CCDB configuration + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + // Not later than now objects + fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); + } + } + + bool CheckSize() + { + auto veceta = (std::vector)trackcuts.cfgEtaMax; + auto vecptmin = (std::vector)trackcuts.cfgPtMin; + auto vecptmax = (std::vector)trackcuts.cfgPtMax; + auto vecDCAxymax = (std::vector)trackcuts.cfgDCAxyMax; + auto vecDCAzmax = (std::vector)trackcuts.cfgDCAzMax; + auto vecIsSPDfirst = (std::vector)trackcuts.cfgIsSPDfirst; + auto vecIsSPDany = (std::vector)trackcuts.cfgIsSPDany; + auto vecIsITSibAny = (std::vector)trackcuts.cfgIsITSibAny; + auto vecITSchi2max = (std::vector)trackcuts.cfgITSchi2Max; + auto vecITSnclsmin = (std::vector)trackcuts.cfgITSnclsMin; + auto vecITSnclsmax = (std::vector)trackcuts.cfgITSnclsMax; + auto vecTPCchi2max = (std::vector)trackcuts.cfgTPCchi2Max; + auto vecTPCnclsmin = (std::vector)trackcuts.cfgTPCnclsMin; + auto vecTPCnclsmax = (std::vector)trackcuts.cfgTPCnclsMax; + auto vecTPCnclsCRmin = (std::vector)trackcuts.cfgTPCnclsCRMin; + auto vecTPCnclsCRmax = (std::vector)trackcuts.cfgTPCnclsCRMax; + auto vecIsDalitzLeg = (std::vector)trackcuts.cfgIsDalitzLeg; + auto vecPIDmode = (std::vector)pidcuts.cfgPIDmode; + auto vecrejbadtof = (std::vector)pidcuts.cfgRejBadTOF; + auto vecTPCnsigmaelmin = (std::vector)pidcuts.cfgTPCNSigmaElMin; + auto vecTPCnsigmaelmax = (std::vector)pidcuts.cfgTPCNSigmaElMax; + auto vecTPCnsigmapimin = (std::vector)pidcuts.cfgTPCNSigmaPiMin; + auto vecTPCnsigmapimax = (std::vector)pidcuts.cfgTPCNSigmaPiMax; + auto vecTPCnsigmaprmin = (std::vector)pidcuts.cfgTPCNSigmaPrMin; + auto vecTPCnsigmaprmax = (std::vector)pidcuts.cfgTPCNSigmaPrMax; + auto vecTPCnsigmakamin = (std::vector)pidcuts.cfgTPCNSigmaKaMin; + auto vecTPCnsigmakamax = (std::vector)pidcuts.cfgTPCNSigmaKaMax; + auto vecTPCnsigmamumin = (std::vector)pidcuts.cfgTPCNSigmaMuMin; + auto vecTPCnsigmamumax = (std::vector)pidcuts.cfgTPCNSigmaMuMax; + auto vecTOFnsigmaelmin = (std::vector)pidcuts.cfgTOFNSigmaElMin; + auto vecTOFnsigmaelmax = (std::vector)pidcuts.cfgTOFNSigmaElMax; + + if (veceta.size() != fConfigNbTrackCut) + return false; + if (vecptmin.size() != fConfigNbTrackCut) + return false; + if (vecptmax.size() != fConfigNbTrackCut) + return false; + if (vecDCAxymax.size() != fConfigNbTrackCut) + return false; + if (vecDCAzmax.size() != fConfigNbTrackCut) + return false; + if (vecIsSPDfirst.size() != fConfigNbTrackCut) + return false; + if (vecIsSPDany.size() != fConfigNbTrackCut) + return false; + if (vecIsITSibAny.size() != fConfigNbTrackCut) + return false; + if (vecITSchi2max.size() != fConfigNbTrackCut) + return false; + if (vecITSnclsmin.size() != fConfigNbTrackCut) + return false; + if (vecITSnclsmax.size() != fConfigNbTrackCut) + return false; + if (vecTPCchi2max.size() != fConfigNbTrackCut) + return false; + if (vecTPCnclsmin.size() != fConfigNbTrackCut) + return false; + if (vecTPCnclsmax.size() != fConfigNbTrackCut) + return false; + if (vecTPCnclsCRmin.size() != fConfigNbTrackCut) + return false; + if (vecTPCnclsCRmax.size() != fConfigNbTrackCut) + return false; + if (vecIsDalitzLeg.size() != fConfigNbTrackCut) + return false; + if (vecPIDmode.size() != fConfigNbTrackCut) + return false; + if (vecrejbadtof.size() != fConfigNbTrackCut) + return false; + if (vecTPCnsigmaelmin.size() != fConfigNbTrackCut) + return false; + if (vecTPCnsigmaelmax.size() != fConfigNbTrackCut) + return false; + if (vecTPCnsigmapimin.size() != fConfigNbTrackCut) + return false; + if (vecTPCnsigmapimax.size() != fConfigNbTrackCut) + return false; + if (vecTPCnsigmaprmin.size() != fConfigNbTrackCut) + return false; + if (vecTPCnsigmaprmax.size() != fConfigNbTrackCut) + return false; + if (vecTPCnsigmakamin.size() != fConfigNbTrackCut) + return false; + if (vecTPCnsigmakamax.size() != fConfigNbTrackCut) + return false; + if (vecTPCnsigmamumin.size() != fConfigNbTrackCut) + return false; + if (vecTPCnsigmamumax.size() != fConfigNbTrackCut) + return false; + if (vecTOFnsigmaelmin.size() != fConfigNbTrackCut) + return false; + if (vecTOFnsigmaelmax.size() != fConfigNbTrackCut) + return false; + return true; + } + + AnalysisCompositeCut* GetPIDCut(unsigned int i) + { + auto vecPIDmode = (std::vector)pidcuts.cfgPIDmode; + auto vecrejbadtof = (std::vector)pidcuts.cfgRejBadTOF; + auto vecTPCnsigmaelmin = (std::vector)pidcuts.cfgTPCNSigmaElMin; + auto vecTPCnsigmaelmax = (std::vector)pidcuts.cfgTPCNSigmaElMax; + auto vecTPCnsigmapimin = (std::vector)pidcuts.cfgTPCNSigmaPiMin; + auto vecTPCnsigmapimax = (std::vector)pidcuts.cfgTPCNSigmaPiMax; + auto vecTPCnsigmaprmin = (std::vector)pidcuts.cfgTPCNSigmaPrMin; + auto vecTPCnsigmaprmax = (std::vector)pidcuts.cfgTPCNSigmaPrMax; + auto vecTPCnsigmakamin = (std::vector)pidcuts.cfgTPCNSigmaKaMin; + auto vecTPCnsigmakamax = (std::vector)pidcuts.cfgTPCNSigmaKaMax; + auto vecTPCnsigmamumin = (std::vector)pidcuts.cfgTPCNSigmaMuMin; + auto vecTPCnsigmamumax = (std::vector)pidcuts.cfgTPCNSigmaMuMax; + auto vecTOFnsigmaelmin = (std::vector)pidcuts.cfgTOFNSigmaElMin; + auto vecTOFnsigmaelmax = (std::vector)pidcuts.cfgTOFNSigmaElMax; + + AnalysisCompositeCut* cut_tpc_nSigma = new AnalysisCompositeCut(Form("pid_TPCnSigma_%d", i), Form("pid_TPCnSigma_%d", i), kTRUE); + AnalysisCut* cuttpc = new AnalysisCut(Form("pidcuttpc_%d", i), Form("pidcuttpc_%d", i)); + if (!fConfigComputeTPCpostCalib) { + cuttpc->AddCut(VarManager::kTPCnSigmaEl, vecTPCnsigmaelmin.at(i), vecTPCnsigmaelmax.at(i), false, VarManager::kPin, 0.0, 1e+10, false); + cuttpc->AddCut(VarManager::kTPCnSigmaPi, vecTPCnsigmapimin.at(i), vecTPCnsigmapimax.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + cuttpc->AddCut(VarManager::kTPCnSigmaKa, vecTPCnsigmakamin.at(i), vecTPCnsigmakamax.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + cuttpc->AddCut(VarManager::kTPCnSigmaPr, vecTPCnsigmaprmin.at(i), vecTPCnsigmaprmax.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + cuttpc->AddCut(VarManager::kTPCnSigmaMu, vecTPCnsigmamumin.at(i), vecTPCnsigmamumax.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + } else { + cuttpc->AddCut(VarManager::kTPCnSigmaEl_Corr, vecTPCnsigmaelmin.at(i), vecTPCnsigmaelmax.at(i), false, VarManager::kPin, 0.0, 1e+10, false); + cuttpc->AddCut(VarManager::kTPCnSigmaPi_Corr, vecTPCnsigmapimin.at(i), vecTPCnsigmapimax.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + cuttpc->AddCut(VarManager::kTPCnSigmaKa, vecTPCnsigmakamin.at(i), vecTPCnsigmakamax.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + cuttpc->AddCut(VarManager::kTPCnSigmaPr_Corr, vecTPCnsigmaprmin.at(i), vecTPCnsigmaprmax.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + cuttpc->AddCut(VarManager::kTPCnSigmaMu, vecTPCnsigmamumin.at(i), vecTPCnsigmamumax.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + } + + if (vecrejbadtof.at(i) > 0) { + cuttpc->AddCut(VarManager::kTOFbeta, 0., 0.985, true, VarManager::kPin, 0.0, 1e+10, false); + cuttpc->AddCut(VarManager::kTOFbeta, 1.015, 999999999., true, VarManager::kPin, 0.0, 1e+10, false); + } + cut_tpc_nSigma->AddCut(cuttpc); + + if (vecPIDmode.at(i) == 1) + return cut_tpc_nSigma; + + AnalysisCompositeCut* cut_tof_nSigma = new AnalysisCompositeCut(Form("pid_TOFnSigma_%d", i), Form("pid_TOFnSigma_%d", i), kTRUE); + AnalysisCut* cuttof = new AnalysisCut(Form("pidcuttof_%d", i), Form("pidcuttof_%d", i)); + if (!fConfigComputeTPCpostCalib) { + cuttof->AddCut(VarManager::kTPCnSigmaEl, vecTPCnsigmaelmin.at(i), vecTPCnsigmaelmax.at(i), false, VarManager::kPin, 0.0, 1e+10, false); + cuttof->AddCut(VarManager::kTPCnSigmaPi, vecTPCnsigmapimin.at(i), vecTPCnsigmapimax.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + } else { + cuttof->AddCut(VarManager::kTPCnSigmaEl_Corr, vecTPCnsigmaelmin.at(i), vecTPCnsigmaelmax.at(i), false, VarManager::kPin, 0.0, 1e+10, false); + cuttof->AddCut(VarManager::kTPCnSigmaPi_Corr, vecTPCnsigmapimin.at(i), vecTPCnsigmapimax.at(i), true, VarManager::kPin, 0.0, 1e+10, false); + } + cuttof->AddCut(VarManager::kTOFnSigmaEl, vecTOFnsigmaelmin.at(i), vecTOFnsigmaelmax.at(i), false, VarManager::kPin, 0.0, 1e+10, false); + cut_tof_nSigma->AddCut(cuttof); + + if (vecPIDmode.at(i) == 2) + return cut_tof_nSigma; + + AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut(Form("e_NSigma_%d", i), Form("e_NSigma_%d", i), kFALSE); + cut_pid_OR->AddCut(cut_tpc_nSigma); + cut_pid_OR->AddCut(cut_tof_nSigma); + return cut_pid_OR; + } + + AnalysisCut* GetTrackCut(unsigned int i) + { + auto veceta = (std::vector)trackcuts.cfgEtaMax; + auto vecptmin = (std::vector)trackcuts.cfgPtMin; + auto vecptmax = (std::vector)trackcuts.cfgPtMax; + + auto vecDCAxymax = (std::vector)trackcuts.cfgDCAxyMax; + auto vecDCAzmax = (std::vector)trackcuts.cfgDCAzMax; + + auto vecIsSPDfirst = (std::vector)trackcuts.cfgIsSPDfirst; + auto vecIsSPDany = (std::vector)trackcuts.cfgIsSPDany; + auto vecIsITSibAny = (std::vector)trackcuts.cfgIsITSibAny; + + auto vecITSchi2max = (std::vector)trackcuts.cfgITSchi2Max; + auto vecITSnclsmin = (std::vector)trackcuts.cfgITSnclsMin; + auto vecITSnclsmax = (std::vector)trackcuts.cfgITSnclsMax; + + auto vecTPCchi2max = (std::vector)trackcuts.cfgTPCchi2Max; + auto vecTPCnclsmin = (std::vector)trackcuts.cfgTPCnclsMin; + auto vecTPCnclsmax = (std::vector)trackcuts.cfgTPCnclsMax; + auto vecTPCnclsCRmin = (std::vector)trackcuts.cfgTPCnclsCRMin; + auto vecTPCnclsCRmax = (std::vector)trackcuts.cfgTPCnclsCRMax; + + auto vecIsDalitzLeg = (std::vector)trackcuts.cfgIsDalitzLeg; + + AnalysisCut* cut = new AnalysisCut(Form("tracksel%d", i), Form("tracksel%d", i)); + cut->AddCut(VarManager::kPt, vecptmin.at(i), vecptmax.at(i)); + cut->AddCut(VarManager::kEta, -veceta.at(i), veceta.at(i)); + + cut->AddCut(VarManager::kTrackDCAxy, -vecDCAxymax.at(i), vecDCAxymax.at(i)); + cut->AddCut(VarManager::kTrackDCAz, -vecDCAzmax.at(i), vecDCAzmax.at(i)); + + if (vecIsSPDfirst.at(i) > 0) + cut->AddCut(VarManager::kIsSPDfirst, 0.5, 1.5); + if (vecIsSPDany.at(i) > 0) + cut->AddCut(VarManager::kIsSPDany, 0.5, 1.5); + if (vecIsITSibAny.at(i) > 0) + cut->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + + cut->AddCut(VarManager::kITSchi2, 0.0, vecITSchi2max.at(i)); + cut->AddCut(VarManager::kITSncls, vecITSnclsmin.at(i), vecITSnclsmax.at(i)); + + cut->AddCut(VarManager::kTPCchi2, 0.0, vecTPCchi2max.at(i)); + cut->AddCut(VarManager::kTPCnclsCR, vecTPCnclsCRmin.at(i), vecTPCnclsCRmax.at(i)); + cut->AddCut(VarManager::kTPCncls, vecTPCnclsmin.at(i), vecTPCnclsmax.at(i)); + + if (vecIsDalitzLeg.at(i) > 0 && vecIsDalitzLeg.at(i) <= 8) + cut->AddCut(VarManager::kIsDalitzLeg + vecIsDalitzLeg.at(i) - 1, 0.5, 1.5); + return cut; + } + + template + void runTrackSelection(TEvent const& event, TTracks const& tracks) + { + VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); + // fill event information which might be needed in histograms/cuts that combine track and event properties + VarManager::FillEvent(event); + + // check whether the run changed, and if so, update calibrations in the VarManager + // TODO: Here, for the run number and timestamp we assume the function runs with the + // DQ skimmed model. However, we need a compile time check so to make this compatible + // also with the full data model. + if (fConfigComputeTPCpostCalib && fCurrentRun != event.runNumber()) { + auto calibList = fCCDB->getForTimeStamp(fConfigCcdbPathTPC.value, event.timestamp()); + VarManager::SetCalibrationObject(VarManager::kTPCElectronMean, calibList->FindObject("mean_map_electron")); + VarManager::SetCalibrationObject(VarManager::kTPCElectronSigma, calibList->FindObject("sigma_map_electron")); + VarManager::SetCalibrationObject(VarManager::kTPCPionMean, calibList->FindObject("mean_map_pion")); + VarManager::SetCalibrationObject(VarManager::kTPCPionSigma, calibList->FindObject("sigma_map_pion")); + VarManager::SetCalibrationObject(VarManager::kTPCProtonMean, calibList->FindObject("mean_map_proton")); + VarManager::SetCalibrationObject(VarManager::kTPCProtonSigma, calibList->FindObject("sigma_map_proton")); + fCurrentRun = event.runNumber(); + } + + trackSel.reserve(tracks.size()); + uint32_t filterMap = 0; + bool prefilterSelected = false; + int iCut = 0; + + for (auto& track : tracks) { + filterMap = 0; + prefilterSelected = false; + VarManager::FillTrack(track); + if (fConfigQA) { // TODO: make this compile time + if (fConfigQAIfSelEvt) { + if (event.isEventSelected()) { + fHistMan->FillHistClass("TrackBarrel_BeforeCuts", VarManager::fgValues); + } + } else { + fHistMan->FillHistClass("TrackBarrel_BeforeCuts", VarManager::fgValues); + } + } + iCut = 0; + for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, iCut++) { + if ((*cut).IsSelected(VarManager::fgValues)) { + if (iCut != fConfigPrefilterCutId) { + filterMap |= (static_cast(1) << iCut); + } + if (iCut == fConfigPrefilterCutId) { + prefilterSelected = true; + } + if (fConfigQA) { // TODO: make this compile time + if (fConfigQAIfSelEvt) { + if (event.isEventSelected()) { + fHistMan->FillHistClass(Form("TrackBarrel_%s", (*cut).GetName()), VarManager::fgValues); + } + } else { + fHistMan->FillHistClass(Form("TrackBarrel_%s", (*cut).GetName()), VarManager::fgValues); + } + } + } + } + + trackSel(static_cast(filterMap), static_cast(prefilterSelected)); + } // end loop over tracks + } + + void processSkimmed(MyEventsSelected::iterator const& event, MyBarrelTracks const& tracks) + { + runTrackSelection(event, tracks); + } + void processSkimmedWithCov(MyEventsVtxCovSelected::iterator const& event, MyBarrelTracksWithCov const& tracks) + { + runTrackSelection(event, tracks); + } + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisTrackSelection, processSkimmed, "Run barrel track selection on DQ skimmed tracks", false); + PROCESS_SWITCH(AnalysisTrackSelection, processSkimmedWithCov, "Run barrel track selection on DQ skimmed tracks w/ cov matrix", false); + PROCESS_SWITCH(AnalysisTrackSelection, processDummy, "Dummy function", false); +}; + +struct AnalysisPrefilterSelection { + SliceCache cache; + Produces prefilter; + Preslice perCollision = aod::reducedtrack::reducedeventId; + + // Configurables + Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + + Service ccdb; + + o2::parameters::GRPMagField* grpmag = nullptr; + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + + Filter barrelTracksSelectedPrefilter = aod::dqanalysisflags::isBarrelSelectedPrefilter > 0; + + Partition> barrelTracksSelected = aod::dqanalysisflags::isBarrelSelected > 0; + + std::map fPrefiltermap; + AnalysisCompositeCut* fPairCut; + struct : ConfigurableGroup { + std::string prefix = "pairprecut_group"; + Configurable cfgMassMax{"cfgMassMax", 0.05f, "max. mass"}; + Configurable cfgOpAngMax{"cfgOpAngMax", 0.05f, "max. opening angle"}; + Configurable cfgPhiVMin{"cfgPhiVMin", 2.f, "min. phiv"}; + + } pairprecuts; + + AnalysisCut* GetPairPreCut() + { + AnalysisCut* cut = new AnalysisCut("PairPre", "PairPre"); + cut->AddCut(VarManager::kMass, 0.0, pairprecuts.cfgMassMax); + cut->AddCut(VarManager::kOpeningAngle, 0.0, pairprecuts.cfgOpAngMax); + cut->AddCut(VarManager::kPairPhiv, pairprecuts.cfgPhiVMin, 3.2); + return cut; + } + + void init(o2::framework::InitContext&) + { + fCurrentRun = 0; + + ccdb->setURL(ccdburl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + fPairCut = new AnalysisCompositeCut(true); + fPairCut->AddCut(GetPairPreCut()); + + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill + VarManager::SetDefaultVarNames(); + } + + template + void runPrefilterPairing(TTracks1 const& tracks1, TTracks2 const& tracks2) + { + for (auto& [track1, track2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (track1.sign() * track2.sign() > 0) { + continue; + } + + // pairing + VarManager::FillPair(track1, track2); + + if (fPairCut->IsSelected(VarManager::fgValues)) { + fPrefiltermap[track1.globalIndex()] = true; + fPrefiltermap[track2.globalIndex()] = true; + } + } + } + + void processBarrelSkimmed(MyEventsSelected const& events, soa::Filtered const& filteredTracks, MyBarrelTracks const& tracks) + { + const int pairType = VarManager::kDecayToEE; + fPrefiltermap.clear(); + + if (events.size() > 0 && fCurrentRun != events.begin().runNumber()) { + grpmag = ccdb->getForTimeStamp(grpmagPath, events.begin().timestamp()); + if (grpmag != nullptr) { + VarManager::SetMagneticField(grpmag->getNominalL3Field()); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", events.begin().timestamp()); + } + fCurrentRun = events.begin().runNumber(); + } + + for (auto& event : events) { + if (event.isEventSelected()) { + auto groupedPrefilterCandidates = filteredTracks.sliceBy(perCollision, event.globalIndex()); + auto groupedBarrelCandidates = barrelTracksSelected->sliceByCached(aod::reducedtrack::reducedeventId, event.globalIndex(), cache); + runPrefilterPairing(groupedPrefilterCandidates, groupedBarrelCandidates); + } + } // end loop events + + // Fill Prefilter bits for all tracks to have something joinable to MyBarrelTracksSelected + for (auto& track : tracks) { + prefilter(static_cast(fPrefiltermap[track.globalIndex()])); + } + } + + void processDummy(MyEvents&) + { + } + + PROCESS_SWITCH(AnalysisPrefilterSelection, processBarrelSkimmed, "Run Prefilter selection on reduced tracks", false); + PROCESS_SWITCH(AnalysisPrefilterSelection, processDummy, "Do nothing", false); +}; + +struct AnalysisEventMixing { + OutputObj fOutputList{"output"}; + // Here one should provide the list of electron and muon candidate cuts in the same order as specified in the above + // single particle selection tasks to preserve the correspondence between the track cut name and its + // bit position in the cuts bitmap + // TODO: Create a configurable to specify exactly on which of the bits one should run the event mixing + Configurable fConfigNbTrackCut{"cfgNbTrackCut", 1, "Number of cuts without prefilter cut, need to be consistent with the track selection"}; + Configurable fConfigMixingDepth{"cfgMixingDepth", 100, "Number of Events stored for event mixing"}; + Configurable fConfigAddEventMixingHistogram{"cfgAddEventMixingHistogram", "", "Comma separated list of histograms"}; + Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + + Service ccdb; + + o2::parameters::GRPMagField* grpmag = nullptr; + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + + Filter filterEventSelected = aod::dqanalysisflags::isEventSelected == 1; + Filter filterTrackSelected = aod::dqanalysisflags::isBarrelSelected > 0; + + HistogramManager* fHistMan; + // NOTE: The bit mask is required to run pairing just based on the desired electron/muon candidate cuts + uint32_t fTwoTrackFilterMask = 0; + std::vector> fTrackHistNames; + + NoBinningPolicy hashBin; + + void init(o2::framework::InitContext& /*context*/) + { + fCurrentRun = 0; + + ccdb->setURL(ccdburl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + VarManager::SetDefaultVarNames(); + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + // Keep track of all the histogram class names to avoid composing strings in the event mixing pairing + TString histNames = ""; + if (fConfigNbTrackCut > 0 && fConfigNbTrackCut < 31) { + for (std::size_t icut = 0; icut < fConfigNbTrackCut; ++icut) { + std::vector names = { + Form("PairsBarrelMEPM_trackcut%zu", icut), + Form("PairsBarrelMEPP_trackcut%zu", icut), + Form("PairsBarrelMEMM_trackcut%zu", icut)}; + histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); + fTrackHistNames.push_back(names); + fTwoTrackFilterMask |= (static_cast(1) << icut); + } + } + + DefineHistograms(fHistMan, histNames.Data(), fConfigAddEventMixingHistogram); // define all histograms + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } + + template + void runMixedPairing(TTracks1 const& tracks1, TTracks2 const& tracks2) + { + + unsigned int ncuts = fTrackHistNames.size(); + std::vector> histNames = fTrackHistNames; + + uint32_t twoTrackFilter = 0; + for (auto& track1 : tracks1) { + for (auto& track2 : tracks2) { + twoTrackFilter = static_cast(track1.isBarrelSelected()) & static_cast(track2.isBarrelSelected()) & fTwoTrackFilterMask; + + if (!twoTrackFilter) { // the tracks must have at least one filter bit in common to continue + continue; + } + VarManager::FillPairME(track1, track2); + + constexpr bool eventHasQvector = (VarManager::ObjTypes::ReducedEventQvector > 0); + if constexpr (eventHasQvector) { + VarManager::FillPairVn(track1, track2); + } + constexpr bool eventHasQvectorCentr = (VarManager::ObjTypes::CollisionQvect > 0); + if constexpr (eventHasQvectorCentr) { + VarManager::FillPairVn(track1, track2); + } + + for (unsigned int icut = 0; icut < ncuts; icut++) { + if (twoTrackFilter & (static_cast(1) << icut)) { + if (track1.sign() * track2.sign() < 0) { + fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); + } else { + if (track1.sign() > 0) { + fHistMan->FillHistClass(histNames[icut][1].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNames[icut][2].Data(), VarManager::fgValues); + } + } + } // end if (filter bits) + } // end for (cuts) + } // end for (track2) + } // end for (track1) + } + + // barrel-barrel and muon-muon event mixing + template + void runSameSide(TEvents& events, TTracks const& tracks, Preslice& preSlice) + { + if (events.size() > 0 && fCurrentRun != events.begin().runNumber()) { + grpmag = ccdb->getForTimeStamp(grpmagPath, events.begin().timestamp()); + if (grpmag != nullptr) { + VarManager::SetMagneticField(grpmag->getNominalL3Field()); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", events.begin().timestamp()); + } + fCurrentRun = events.begin().runNumber(); + } + + events.bindExternalIndices(&tracks); + int mixingDepth = fConfigMixingDepth.value; + for (auto& [event1, event2] : selfCombinations(hashBin, mixingDepth, -1, events, events)) { + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event1, VarManager::fgValues); + + auto tracks1 = tracks.sliceBy(preSlice, event1.globalIndex()); + tracks1.bindExternalIndices(&events); + + auto tracks2 = tracks.sliceBy(preSlice, event2.globalIndex()); + tracks2.bindExternalIndices(&events); + + VarManager::FillTwoMixEvents(event1, event2, tracks1, tracks2); + runMixedPairing(tracks1, tracks2); + } // end event loop + } + + Preslice> perEventsSelectedT = aod::reducedtrack::reducedeventId; + + void processBarrelSkimmed(soa::Filtered& events, soa::Filtered const& tracks) + { + runSameSide(events, tracks, perEventsSelectedT); + } + void processBarrelVnSkimmed(soa::Filtered& events, soa::Filtered const& tracks) + { + runSameSide(events, tracks, perEventsSelectedT); + } + // TODO: This is a dummy process function for the case when the user does not want to run any of the process functions (no event mixing) + // If there is no process function enabled, the workflow hangs + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisEventMixing, processBarrelSkimmed, "Run barrel-barrel mixing on skimmed tracks", false); + PROCESS_SWITCH(AnalysisEventMixing, processBarrelVnSkimmed, "Run barrel-barrel vn mixing on skimmed tracks", false); + PROCESS_SWITCH(AnalysisEventMixing, processDummy, "Dummy function", false); +}; + +struct AnalysisSameEventPairing { + + float mMagField = 0.0; + o2::parameters::GRPMagField* grpmag = nullptr; + o2::base::MatLayerCylSet* lut = nullptr; + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + + OutputObj fOutputList{"output"}; + Configurable fConfigNbTrackCut{"cfgNbTrackCut", 1, "Number of track cuts without prefilter cut, need to be consistent with the track selection"}; + Configurable fConfigNbPairCut{"cfgNbPairCut", 1, "Number of pair cuts, need to be below 4 right now"}; + Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPath{"ccdb-path", "Users/lm", "base path to the ccdb object"}; + Configurable nolaterthan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable fConfigAddSEPHistogram{"cfgAddSEPHistogram", "", "Comma separated list of histograms"}; + Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable fCollisionSystem{"syst", "pp", "Collision system, pp or PbPb"}; + Configurable fCenterMassEnergy{"energy", 13600, "Center of mass energy in GeV"}; + + Service ccdb; + Filter filterEventSelected = aod::dqanalysisflags::isEventSelected == 1; + // NOTE: the barrel filter map contains decisions for both electrons and hadrons used in the correlation task + Filter filterBarrelTrackSelected = aod::dqanalysisflags::isBarrelSelected > 0; + Filter prefilter = aod::dqanalysisflags::isPrefilterVetoed == 0; + + HistogramManager* fHistMan; + + // NOTE: The track filter produced by the barrel track selection contain a number of electron cut decisions and one last cut for hadrons used in the + // dilepton - hadron task downstream. So the bit mask is required to select pairs just based on the electron cuts + // TODO: provide as Configurable the list and names of the cuts which should be used in pairing + uint32_t fTwoTrackFilterMask = 0; + std::vector> fTrackHistNames; + std::vector fPairCuts; + struct : ConfigurableGroup { + std::string prefix = "paircut_group"; + Configurable> cfgRej{"cfgRej", {1}, "max. mass"}; + Configurable> cfgMassMax{"cfgMassMax", {0.1f}, "max. mass"}; + Configurable> cfgMassMin{"cfgMassMin", {0.f}, "min. mass"}; + Configurable> cfgOpAngMax{"cfgOpAngMax", {-1.f}, "max. opening angle"}; + Configurable> cfgPhiVMin{"cfgPhiVMin", {2.f}, "min. phiv"}; + + } paircuts; + + bool CheckSize() + { + auto vecRej = (std::vector)paircuts.cfgRej; + auto vecmassmin = (std::vector)paircuts.cfgMassMin; + auto vecmassmax = (std::vector)paircuts.cfgMassMax; + auto vecopamax = (std::vector)paircuts.cfgOpAngMax; + auto vecphivmin = (std::vector)paircuts.cfgPhiVMin; + + if (vecRej.size() != fConfigNbPairCut) + return false; + if (vecmassmin.size() != fConfigNbPairCut) + return false; + if (vecmassmax.size() != fConfigNbPairCut) + return false; + if (vecopamax.size() != fConfigNbPairCut) + return false; + if (vecphivmin.size() != fConfigNbPairCut) + return false; + return true; + } + + AnalysisCompositeCut* GetPairCut(unsigned int i) + { + auto vecRej = (std::vector)paircuts.cfgRej; + auto vecmassmin = (std::vector)paircuts.cfgMassMin; + auto vecmassmax = (std::vector)paircuts.cfgMassMax; + auto vecopamax = (std::vector)paircuts.cfgOpAngMax; + auto vecphivmin = (std::vector)paircuts.cfgPhiVMin; + + if (vecRej.at(i)) { + AnalysisCompositeCut* cut_pair = new AnalysisCompositeCut(Form("cut_pair_%d", i), Form("cut_pair_%d", i), kFALSE); + if (vecphivmin.at(i) > 0) { + AnalysisCut* cutphiv = new AnalysisCut(Form("phiv_%d", i), Form("phiv_%d", i)); + cutphiv->AddCut(VarManager::kPairPhiv, vecphivmin.at(i), 3.2, true); + cut_pair->AddCut(cutphiv); + } + if (vecmassmin.at(i) < vecmassmax.at(i)) { + AnalysisCut* cutmass = new AnalysisCut(Form("mass_%d", i), Form("mass_%d", i)); + cutmass->AddCut(VarManager::kMass, vecmassmin.at(i), vecmassmax.at(i), true); + cut_pair->AddCut(cutmass); + } + if (vecopamax.at(i) > 0) { + AnalysisCut* cutopa = new AnalysisCut(Form("opa_%d", i), Form("opa_%d", i)); + cutopa->AddCut(VarManager::kOpeningAngle, 0.0, vecopamax.at(i), true); + cut_pair->AddCut(cutopa); + } + return cut_pair; + } else { + AnalysisCompositeCut* cut_pair = new AnalysisCompositeCut(Form("cut_pair_%d", i), Form("cut_pair_%d", i), kTRUE); + if (vecphivmin.at(i) > 0) { + AnalysisCut* cutphiv = new AnalysisCut(Form("phiv_%d", i), Form("phiv_%d", i)); + cutphiv->AddCut(VarManager::kPairPhiv, vecphivmin.at(i), 3.2); + cut_pair->AddCut(cutphiv); + } + if (vecmassmin.at(i) < vecmassmax.at(i)) { + AnalysisCut* cutmass = new AnalysisCut(Form("mass_%d", i), Form("mass_%d", i)); + cutmass->AddCut(VarManager::kMass, vecmassmin.at(i), vecmassmax.at(i)); + cut_pair->AddCut(cutmass); + } + if (vecopamax.at(i) > 0) { + AnalysisCut* cutopa = new AnalysisCut(Form("opa_%d", i), Form("opa_%d", i)); + cutopa->AddCut(VarManager::kOpeningAngle, 0.0, vecopamax.at(i)); + cut_pair->AddCut(cutopa); + } + return cut_pair; + } + } + + void init(o2::framework::InitContext& /*context*/) + { + fCurrentRun = 0; + + ccdb->setURL(ccdburl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + VarManager::SetDefaultVarNames(); + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + // Keep track of all the histogram class names to avoid composing strings in the event mixing pairing + TString histNames = ""; + std::vector names; + + if (fConfigNbPairCut > 0 && CheckSize()) { + for (std::size_t icut = 0; icut < fConfigNbPairCut; ++icut) { + fPairCuts.push_back(*GetPairCut(icut)); + } + } + + if (fConfigNbTrackCut > 0 && fConfigNbTrackCut < 31) { // if track cuts + for (std::size_t icut = 0; icut < fConfigNbTrackCut; ++icut) { // loop over track cuts + fTwoTrackFilterMask |= (static_cast(1) << icut); + // no pair cuts + names = { + Form("PairsBarrelSEPM_trackcut%zu", icut), + Form("PairsBarrelSEPP_trackcut%zu", icut), + Form("PairsBarrelSEMM_trackcut%zu", icut)}; + histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); + fTrackHistNames.push_back(names); + + for (std::size_t iPairCut = 0; iPairCut < fPairCuts.size(); ++iPairCut) { // loop over pair cuts + names = { + Form("PairsBarrelSEPM_trackcut%zu_paircut%zu", icut, iPairCut), + Form("PairsBarrelSEPP_trackcut%zu_paircut%zu", icut, iPairCut), + Form("PairsBarrelSEMM_trackcut%zu_paircut%zu", icut, iPairCut)}; + + histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); + + fTrackHistNames.push_back(names); + } // end loop (pair cuts) + } // end loop (track cuts) + } // end if (track cuts) + + VarManager::SetCollisionSystem((TString)fCollisionSystem, fCenterMassEnergy); // set collision system and center of mass energy + + DefineHistograms(fHistMan, histNames.Data(), fConfigAddSEPHistogram); // define all histograms + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } + + // Template function to run same event pairing (barrel-barrel, muon-muon, barrel-muon) + template + void runSameEventPairing(TEvent const& event, TTracks1 const& tracks1, TTracks2 const& tracks2) + { + if (fCurrentRun != event.runNumber()) { + grpmag = ccdb->getForTimeStamp(grpmagPath, event.timestamp()); + if (grpmag != nullptr) { + mMagField = grpmag->getNominalL3Field(); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", event.timestamp()); + } + VarManager::SetMagneticField(mMagField); + fCurrentRun = event.runNumber(); + } + + std::vector> histNames = fTrackHistNames; + uint32_t twoTrackFilter = 0; + + for (auto& [t1, t2] : combinations(tracks1, tracks2)) { + twoTrackFilter = static_cast(t1.isBarrelSelected()) & static_cast(t2.isBarrelSelected()) & fTwoTrackFilterMask; + + if (!twoTrackFilter) { // the tracks must have at least one filter bit in common to continue + continue; + } + constexpr bool eventHasQvector = ((TEventFillMap & VarManager::ObjTypes::ReducedEventQvector) > 0); + constexpr bool eventHasQvectorCentr = ((TEventFillMap & VarManager::ObjTypes::CollisionQvect) > 0); + + // TODO: FillPair functions need to provide a template argument to discriminate between cases when cov matrix is available or not + VarManager::FillPair(t1, t2); + if constexpr (eventHasQvector) { + VarManager::FillPairVn(t1, t2); + } + if constexpr (eventHasQvectorCentr) { + VarManager::FillPairVn(t1, t2); + } + + int iCut = 0; + for (std::size_t icut = 0; icut < fConfigNbTrackCut; icut++) { + if (twoTrackFilter & (static_cast(1) << icut)) { + if (t1.sign() * t2.sign() < 0) { + fHistMan->FillHistClass(histNames[iCut][0].Data(), VarManager::fgValues); + } else { + if (t1.sign() > 0) { + fHistMan->FillHistClass(histNames[iCut][1].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNames[iCut][2].Data(), VarManager::fgValues); + } + } + iCut++; + for (unsigned int iPairCut = 0; iPairCut < fPairCuts.size(); iPairCut++, iCut++) { + AnalysisCompositeCut cut = fPairCuts.at(iPairCut); + if (!(cut.IsSelected(VarManager::fgValues))) // apply pair cuts + continue; + if (t1.sign() * t2.sign() < 0) { + fHistMan->FillHistClass(histNames[iCut][0].Data(), VarManager::fgValues); + } else { + if (t1.sign() > 0) { + fHistMan->FillHistClass(histNames[iCut][1].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNames[iCut][2].Data(), VarManager::fgValues); + } + } + } // end loop (pair cuts) + } else { // end if (filter bits) + iCut = iCut + 1 + fPairCuts.size(); + } + } // end loop (cuts) + } // end loop over pairs + } + + void processDecayToEESkimmed(soa::Filtered::iterator const& event, soa::Filtered const& tracks) + { + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event, VarManager::fgValues); + runSameEventPairing(event, tracks, tracks); + } + void processDecayToEESkimmedWithCov(soa::Filtered::iterator const& event, soa::Filtered const& tracks) + { + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event, VarManager::fgValues); + runSameEventPairing(event, tracks, tracks); + } + void processDecayToEEPrefilterSkimmed(soa::Filtered::iterator const& event, soa::Filtered const& tracks) + { + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event, VarManager::fgValues); + runSameEventPairing(event, tracks, tracks); + } + void processDecayToEESkimmedWithColl(soa::Filtered::iterator const& event, soa::Filtered const& tracks) + { + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event, VarManager::fgValues); + runSameEventPairing(event, tracks, tracks); + } + void processVnDecayToEESkimmed(soa::Filtered::iterator const& event, soa::Filtered const& tracks) + { + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event, VarManager::fgValues); + runSameEventPairing(event, tracks, tracks); + } + // TODO: dummy function for the case when no process function is enabled + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToEESkimmed, "Run electron-electron pairing, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToEESkimmedWithCov, "Run electron-electron pairing, with skimmed covariant tracks", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToEEPrefilterSkimmed, "Run electron-electron pairing, with skimmed tracks and prefilter from AnalysisPrefilterSelection", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processDecayToEESkimmedWithColl, "Run electron-electron pairing, with skimmed tracks and with collision information", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processVnDecayToEESkimmed, "Run electron-electron pairing, with skimmed tracks for vn", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processDummy, "Dummy function, enabled only if none of the others are enabled", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +} + +void DefineHistograms(HistogramManager* histMan, TString histClasses, Configurable configVar) +{ + // + // Define here the histograms for all the classes required in analysis. + // The histogram classes are provided in the histClasses string, separated by semicolon ";" + // The histogram classes and their components histograms are defined below depending on the name of the histogram class + // + std::unique_ptr objArray(histClasses.Tokenize(";")); + for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { + TString classStr = objArray->At(iclass)->GetName(); + histMan->AddHistClass(classStr.Data()); + + TString histName = configVar.value; + // NOTE: The level of detail for histogramming can be controlled via configurables + if (classStr.Contains("Event")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "event", histName); + } + + if (classStr.Contains("Track") && !classStr.Contains("Pairs")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); + } + + if (classStr.Contains("Pairs")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", histName); + } + } // end loop over histogram classes +} diff --git a/PWGEM/Dilepton/Tasks/vpPairQC.cxx b/PWGEM/Dilepton/Tasks/vpPairQC.cxx new file mode 100644 index 00000000000..c3a2aaa06e3 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/vpPairQC.cxx @@ -0,0 +1,549 @@ +// 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. +// +// ======================== +// +// This code runs loop over ULS ee pars for virtual photon QC. +// Please write to: daiki.sekihata@cern.ch + +#include +#include +#include + +#include "TString.h" +#include "Math/Vector4D.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Common/Core/RecoDecay.h" + +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Core/DielectronCut.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "PWGEM/Dilepton/Utils/EMTrack.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; + +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; + +using MyTracks = soa::Join; +using MyTrack = MyTracks::iterator; + +struct vpPairQC { + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + ConfigurableAxis ConfPtlBins{"ConfPtlBins", {VARIABLE_WIDTH, 0.00, 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.50, 3.00, 3.50, 4.00, 4.50, 5.00, 6.00, 7.00, 8.00, 9.00, 10.00}, "pTl bins for output histograms"}; + + EMEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInTimeRangeStrict{"cfgRequireNoCollInTimeRangeStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoCollInITSROFStandard{"cfgRequireNoCollInITSROFStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInITSROFStrict{"cfgRequireNoCollInITSROFStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoHighMultCollInPrevRof{"cfgRequireNoHighMultCollInPrevRof", false, "require no HM collision in previous ITS ROF"}; + } eventcuts; + + DielectronCut fDielectronCut; + struct : ConfigurableGroup { + std::string prefix = "dielectroncut_group"; + Configurable cfg_min_mass{"cfg_min_mass", 0.0, "min mass"}; + Configurable cfg_max_mass{"cfg_max_mass", 0.01, "max mass"}; + Configurable cfg_min_pair_pt{"cfg_min_pair_pt", 0.0, "min pair pT"}; + Configurable cfg_max_pair_pt{"cfg_max_pair_pt", 1e+10, "max pair pT"}; + Configurable cfg_min_pair_y{"cfg_min_pair_y", -0.9, "min pair rapidity"}; + Configurable cfg_max_pair_y{"cfg_max_pair_y", +0.9, "max pair rapidity"}; + Configurable cfg_min_pair_dca3d{"cfg_min_pair_dca3d", 0.0, "min pair dca3d in sigma"}; + Configurable cfg_max_pair_dca3d{"cfg_max_pair_dca3d", 1e+10, "max pair dca3d in sigma"}; + Configurable cfg_apply_phiv{"cfg_apply_phiv", true, "flag to apply phiv cut"}; + Configurable cfg_apply_pf{"cfg_apply_pf", false, "flag to apply phiv prefilter"}; + Configurable cfg_require_itsib_any{"cfg_require_itsib_any", false, "flag to require ITS ib any hits"}; + Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; + Configurable cfg_phiv_slope{"cfg_phiv_slope", 0.0185, "slope for m vs. phiv"}; + Configurable cfg_phiv_intercept{"cfg_phiv_intercept", -0.0280, "intercept for m vs. phiv"}; + Configurable cfg_min_phiv{"cfg_min_phiv", 0.0, "min phiv (constant)"}; + Configurable cfg_max_phiv{"cfg_max_phiv", 3.2, "max phiv (constant)"}; + + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.1, "min pT for single track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -0.9, "min eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", +0.9, "max eta for single track"}; + Configurable cfg_max_dca3dsigma_track{"cfg_max_dca3dsigma_track", 1e+10, "max DCA 3D in sigma"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 100, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_chi2tof{"cfg_max_chi2tof", 1e+10, "max chi2 TOF"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1.0, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 1.0, "max dca Z for single track in cm"}; + Configurable cfg_min_its_cluster_size{"cfg_min_its_cluster_size", 0.f, "min ITS cluster size"}; + Configurable cfg_max_its_cluster_size{"cfg_max_its_cluster_size", 16.f, "max ITS cluster size"}; + Configurable cfg_max_p_its_cluster_size{"cfg_max_p_its_cluster_size", 0.2, "max p to apply ITS cluster size cut"}; + Configurable cfg_min_rel_diff_pin{"cfg_min_rel_diff_pin", -1e+10, "min rel. diff. between pin and ppv"}; + Configurable cfg_max_rel_diff_pin{"cfg_max_rel_diff_pin", +1e+10, "max rel. diff. between pin and ppv"}; + + Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DielectronCut::PIDSchemes::kTOFif), "pid scheme [kTOFreq : 0, kTPChadrej : 1, kTPChadrejORTOFreq : 2, kTPConly : 3, kTOFif : 4, kPIDML : 5]"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + Configurable cfg_min_TPCNsigmaMu{"cfg_min_TPCNsigmaMu", -0.0, "min. TPC n sigma for muon exclusion"}; + Configurable cfg_max_TPCNsigmaMu{"cfg_max_TPCNsigmaMu", +0.0, "max. TPC n sigma for muon exclusion"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -0.0, "min. TPC n sigma for pion exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +0.0, "max. TPC n sigma for pion exclusion"}; + Configurable cfg_min_TPCNsigmaKa{"cfg_min_TPCNsigmaKa", -0.0, "min. TPC n sigma for kaon exclusion"}; + Configurable cfg_max_TPCNsigmaKa{"cfg_max_TPCNsigmaKa", +0.0, "max. TPC n sigma for kaon exclusion"}; + Configurable cfg_min_TPCNsigmaPr{"cfg_min_TPCNsigmaPr", -0.0, "min. TPC n sigma for proton exclusion"}; + Configurable cfg_max_TPCNsigmaPr{"cfg_max_TPCNsigmaPr", +0.0, "max. TPC n sigma for proton exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; + Configurable cfg_max_pin_pirejTPC{"cfg_max_pin_pirejTPC", 0.5, "max. pin for pion rejection in TPC"}; + Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; + + // configuration for PID ML + Configurable> onnxFileNames{"onnxFileNames", std::vector{"filename"}, "ONNX file names for each bin (if not from CCDB full path)"}; + Configurable> onnxPathsCCDB{"onnxPathsCCDB", std::vector{"path"}, "Paths of models on CCDB"}; + Configurable> binsMl{"binsMl", std::vector{-999999., 999999.}, "Bin limits for ML application"}; + Configurable> cutsMl{"cutsMl", std::vector{0.95}, "ML cuts per bin"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature"}, "Names of ML model input features"}; + Configurable nameBinningFeature{"nameBinningFeature", "pt", "Names of ML model binning feature"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + Configurable enableOptimizations{"enableOptimizations", false, "Enables the ONNX extended model-optimization: sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED)"}; + } dielectroncuts; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + int mRunNumber; + float d_bz; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view event_cut_types[2] = {"before/", "after/"}; + + void init(InitContext& /*context*/) + { + DefineEMEventCut(); + DefineDielectronCut(); + addhistograms(); + + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + } + + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + mRunNumber = collision.runNumber(); + return; + } + + auto run3grp_timestamp = collision.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = collision.runNumber(); + } + + ~vpPairQC() {} + + void addhistograms() + { + // event info + o2::aod::pwgem::dilepton::utils::eventhistogram::addEventHistograms(&fRegistry); + + const AxisSpec axis_pt{ConfPtlBins, "p_{T,e} (GeV/c)"}; + const AxisSpec axis_eta{20, -1.0, +1.0, "#eta_{e}"}; + const AxisSpec axis_phi{36, 0.0, 2 * M_PI, "#varphi_{e} (rad.)"}; + const AxisSpec axis_dca{{0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0}, "DCA_{e}^{3D} (#sigma)"}; + fRegistry.add("Track/positive/hs", "rec. single electron", kTHnSparseD, {axis_pt, axis_eta, axis_phi, axis_dca}, true); + fRegistry.add("Track/positive/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); + fRegistry.add("Track/positive/hPResolution", "p resolution;p (GeV/c);#Deltap/p", kTH2F, {{1000, 0.0f, 10.0f}, {100, 0.0f, 0.1f}}, false); + fRegistry.add("Track/positive/hPtResolution", "p_{T} resolution;p (GeV/c);#Deltap_{T}/p_{T}", kTH2F, {{1000, 0.0f, 10.0f}, {100, 0.0f, 0.1f}}, false); + fRegistry.add("Track/positive/hThetaResolution", "#theta resolution;p (GeV/c);#Delta#theta (rad.)", kTH2F, {{1000, 0.0f, 10.0f}, {100, 0.0f, 0.01f}}, false); + fRegistry.add("Track/positive/hEtaResolution", "#eta resolution;p (GeV/c);#Delta#eta", kTH2F, {{1000, 0.0f, 10.0f}, {100, 0.0f, 0.01f}}, false); + fRegistry.add("Track/positive/hPhiResolution", "#varphi resolution;p (GeV/c);#Delta#varphi (rad.)", kTH2F, {{1000, 0.0f, 10.0f}, {100, 0.0f, 0.01f}}, false); + fRegistry.add("Track/positive/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -1.0f, 1.0f}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("Track/positive/hDCAxyzSigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/positive/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {{200, 0, 10}, {200, 0., 400}}, false); + fRegistry.add("Track/positive/hDCAzRes_Pt", "DCA_{z} resolution vs. pT;p_{T} (GeV/c);DCA_{z} resolution (#mum)", kTH2F, {{200, 0, 10}, {200, 0., 400}}, false); + fRegistry.add("Track/positive/hDeltaPin", "p_{in} vs. p_{pv};p_{pv} (GeV/c);(p_{in} - p_{pv})/p_{pv}", kTH2F, {{1000, 0, 10}, {200, -1, +1}}, false); + fRegistry.add("Track/positive/hNclsTPC", "number of TPC clusters", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/positive/hNcrTPC", "number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/positive/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/positive/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/positive/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/positive/hTPCNclsShared", "TPC Ncls shared/Ncls;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); + fRegistry.add("Track/positive/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("Track/positive/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/positive/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("Track/positive/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("Track/positive/hTOFbeta", "TOF #beta;p_{pv} (GeV/c);#beta", kTH2F, {{1000, 0, 10}, {240, 0, 1.2}}, false); + fRegistry.add("Track/positive/hChi2TOF", "TOF Chi2;p_{pv} (GeV/c);chi2", kTH2F, {{1000, 0, 10}, {100, 0, 10}}, false); + fRegistry.add("Track/positive/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); on ITS #times cos(#lambda);", kTH2F, {{1000, 0.f, 10.f}, {160, 0, 16}}, false); + fRegistry.add("Track/positive/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hTPCNsigmaMu", "TPC n sigma mu;p_{in} (GeV/c);n #sigma_{#mu}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hTPCNsigmaKa", "TPC n sigma ka;p_{in} (GeV/c);n #sigma_{K}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hTPCNsigmaPr", "TPC n sigma pr;p_{in} (GeV/c);n #sigma_{p}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hTOFNsigmaEl", "TOF n sigma el;p_{pv} (GeV/c);n #sigma_{e}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hTOFNsigmaMu", "TOF n sigma mu;p_{pv} (GeV/c);n #sigma_{#mu}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hTOFNsigmaPi", "TOF n sigma pi;p_{pv} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hTOFNsigmaKa", "TOF n sigma ka;p_{pv} (GeV/c);n #sigma_{K}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/positive/hTOFNsigmaPr", "TOF n sigma pr;p_{pv} (GeV/c);n #sigma_{p}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.addClone("Track/positive/", "Track/negative/"); + + const AxisSpec axis_mass{50, 0, 0.05, "m_{ee} (GeV/c^{2})"}; + const AxisSpec axis_pair_pt{200, 0, 2, "p_{T,ee} (GeV/c)"}; + const AxisSpec axis_pair_dca_3d{100, 0, 10, "DCA_{ee}^{3D} (#sigma)"}; + const AxisSpec axis_pair_dca_xy{100, 0, 10, "DCA_{ee}^{XY} (#sigma)"}; + const AxisSpec axis_phiv{90, 0, M_PI, "#varphi_{V} (rad.)"}; + // for pair + fRegistry.add("Pair/hMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {axis_mass, axis_pair_pt}, true); + fRegistry.add("Pair/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi (rad.);m_{ee} (GeV/c^{2})", kTH2F, {axis_phiv, axis_mass}, true); + fRegistry.add("Pair/hDCA3DvsPhiV", "DCA_{ee}^{3D} vs. #varphi_{V};#varphi_{V} (rad.);DCA_{ee}^{3D} (#sigma)", kTH2F, {axis_phiv, axis_pair_dca_3d}, true); + fRegistry.add("Pair/hDCAXYvsPhiV", "DCA_{ee}^{XY} vs. #varphi_{V};#varphi_{V} (rad.);DCA_{ee}^{XY} (#sigma)", kTH2F, {axis_phiv, axis_pair_dca_xy}, true); + } + + void DefineEMEventCut() + { + fEMEventCut = EMEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireNoCollInTimeRangeStandard(eventcuts.cfgRequireNoCollInTimeRangeStandard); + fEMEventCut.SetRequireNoCollInTimeRangeStrict(eventcuts.cfgRequireNoCollInTimeRangeStrict); + fEMEventCut.SetRequireNoCollInITSROFStandard(eventcuts.cfgRequireNoCollInITSROFStandard); + fEMEventCut.SetRequireNoCollInITSROFStrict(eventcuts.cfgRequireNoCollInITSROFStrict); + fEMEventCut.SetRequireNoHighMultCollInPrevRof(eventcuts.cfgRequireNoHighMultCollInPrevRof); + } + + o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; + void DefineDielectronCut() + { + fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); + + // for pair + fDielectronCut.SetMeeRange(dielectroncuts.cfg_min_mass, dielectroncuts.cfg_max_mass); + fDielectronCut.SetPairPtRange(dielectroncuts.cfg_min_pair_pt, dielectroncuts.cfg_max_pair_pt); + fDielectronCut.SetPairYRange(dielectroncuts.cfg_min_pair_y, dielectroncuts.cfg_max_pair_y); + fDielectronCut.SetPairDCARange(dielectroncuts.cfg_min_pair_dca3d, dielectroncuts.cfg_max_pair_dca3d); // in sigma + fDielectronCut.SetMaxMeePhiVDep([&](float phiv) { return dielectroncuts.cfg_phiv_intercept + phiv * dielectroncuts.cfg_phiv_slope; }, dielectroncuts.cfg_min_phiv, dielectroncuts.cfg_max_phiv); + fDielectronCut.ApplyPhiV(dielectroncuts.cfg_apply_phiv); + fDielectronCut.ApplyPrefilter(dielectroncuts.cfg_apply_pf); + fDielectronCut.RequireITSibAny(dielectroncuts.cfg_require_itsib_any); + fDielectronCut.RequireITSib1st(dielectroncuts.cfg_require_itsib_1st); + + // for track + fDielectronCut.SetTrackPtRange(dielectroncuts.cfg_min_pt_track, dielectroncuts.cfg_max_pt_track); + fDielectronCut.SetTrackEtaRange(dielectroncuts.cfg_min_eta_track, dielectroncuts.cfg_max_eta_track); + fDielectronCut.SetTrackDca3DRange(0.f, dielectroncuts.cfg_max_dca3dsigma_track); // in sigma + fDielectronCut.SetMinNClustersTPC(dielectroncuts.cfg_min_ncluster_tpc); + fDielectronCut.SetMinNCrossedRowsTPC(dielectroncuts.cfg_min_ncrossedrows); + fDielectronCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fDielectronCut.SetMaxFracSharedClustersTPC(dielectroncuts.cfg_max_frac_shared_clusters_tpc); + fDielectronCut.SetChi2PerClusterTPC(0.0, dielectroncuts.cfg_max_chi2tpc); + fDielectronCut.SetChi2PerClusterITS(0.0, dielectroncuts.cfg_max_chi2its); + fDielectronCut.SetNClustersITS(dielectroncuts.cfg_min_ncluster_its, 7); + fDielectronCut.SetMeanClusterSizeITS(dielectroncuts.cfg_min_its_cluster_size, dielectroncuts.cfg_max_its_cluster_size, dielectroncuts.cfg_max_p_its_cluster_size); + fDielectronCut.SetTrackMaxDcaXY(dielectroncuts.cfg_max_dcaxy); + fDielectronCut.SetTrackMaxDcaZ(dielectroncuts.cfg_max_dcaz); + fDielectronCut.SetChi2TOF(0.0, dielectroncuts.cfg_max_chi2tof); + fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); + + // for eID + fDielectronCut.SetPIDScheme(dielectroncuts.cfg_pid_scheme); + fDielectronCut.SetTPCNsigmaElRange(dielectroncuts.cfg_min_TPCNsigmaEl, dielectroncuts.cfg_max_TPCNsigmaEl); + fDielectronCut.SetTPCNsigmaMuRange(dielectroncuts.cfg_min_TPCNsigmaMu, dielectroncuts.cfg_max_TPCNsigmaMu); + fDielectronCut.SetTPCNsigmaPiRange(dielectroncuts.cfg_min_TPCNsigmaPi, dielectroncuts.cfg_max_TPCNsigmaPi); + fDielectronCut.SetTPCNsigmaKaRange(dielectroncuts.cfg_min_TPCNsigmaKa, dielectroncuts.cfg_max_TPCNsigmaKa); + fDielectronCut.SetTPCNsigmaPrRange(dielectroncuts.cfg_min_TPCNsigmaPr, dielectroncuts.cfg_max_TPCNsigmaPr); + fDielectronCut.SetTOFNsigmaElRange(dielectroncuts.cfg_min_TOFNsigmaEl, dielectroncuts.cfg_max_TOFNsigmaEl); + fDielectronCut.SetMaxPinForPionRejectionTPC(dielectroncuts.cfg_max_pin_pirejTPC); + + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { // please call this at the end of DefineDileptonCut + static constexpr int nClassesMl = 2; + const std::vector cutDirMl = {o2::cuts_ml::CutSmaller, o2::cuts_ml::CutNot}; + const std::vector labelsClasses = {"Signal", "Background"}; + const uint32_t nBinsMl = dielectroncuts.binsMl.value.size() - 1; + const std::vector labelsBins(nBinsMl, "bin"); + double cutsMlArr[nBinsMl][nClassesMl]; + for (uint32_t i = 0; i < nBinsMl; i++) { + cutsMlArr[i][0] = dielectroncuts.cutsMl.value[i]; + cutsMlArr[i][1] = 0.; + } + o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; + + mlResponseSingleTrack.configure(dielectroncuts.binsMl.value, cutsMl, cutDirMl, nClassesMl); + if (dielectroncuts.loadModelsFromCCDB) { + ccdbApi.init(ccdburl); + mlResponseSingleTrack.setModelPathsCCDB(dielectroncuts.onnxFileNames.value, ccdbApi, dielectroncuts.onnxPathsCCDB.value, dielectroncuts.timestampCCDB.value); + } else { + mlResponseSingleTrack.setModelPathsLocal(dielectroncuts.onnxFileNames.value); + } + mlResponseSingleTrack.cacheInputFeaturesIndices(dielectroncuts.namesInputFeatures); + mlResponseSingleTrack.cacheBinningIndex(dielectroncuts.nameBinningFeature); + mlResponseSingleTrack.init(dielectroncuts.enableOptimizations.value); + + fDielectronCut.SetPIDMlResponse(&mlResponseSingleTrack); + } // end of PID ML + } + + template + bool fillPairInfo(TCollision const&, TTrack1 const& t1, TTrack2 const& t2) + { + // if (t1.trackId() == t2.trackId()) { // this is protection against pairing identical 2 tracks. This happens, when TTCA is used. TTCA can assign a track to several possible collisions. + // return false; + // } + + if (!fDielectronCut.IsSelectedTrack(t1) || !fDielectronCut.IsSelectedTrack(t2)) { + return false; + } + + if (!fDielectronCut.IsSelectedPair(t1, t2, d_bz)) { + return false; + } + + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), d_bz); + + float dca_t1 = dca3DinSigma(t1); + float dca_t2 = dca3DinSigma(t2); + float pair_dca_3d = std::sqrt((dca_t1 * dca_t1 + dca_t2 * dca_t2) / 2.); + float pair_dca_xy = std::sqrt((std::pow(t1.dcaXY() / std::sqrt(t1.cYY()), 2) + std::pow(t2.dcaXY() / std::sqrt(t2.cYY()), 2)) / 2.); + + fRegistry.fill(HIST("Pair/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/hDCA3DvsPhiV"), phiv, pair_dca_3d); + fRegistry.fill(HIST("Pair/hDCAXYvsPhiV"), phiv, pair_dca_xy); + + if (std::find(used_trackIds.begin(), used_trackIds.end(), t1.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t1.globalIndex()); + fillTrackInfo(t1); + } + if (std::find(used_trackIds.begin(), used_trackIds.end(), t2.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t2.globalIndex()); + fillTrackInfo(t2); + } + + return true; + } + + template + void fillTrackInfo(TTrack const& track) + { + float weight = 1.f; + float dca_3d = dca3DinSigma(track); + if (track.sign() > 0) { + fRegistry.fill(HIST("Track/positive/hs"), track.pt(), track.eta(), track.phi(), dca_3d, weight); + fRegistry.fill(HIST("Track/positive/hQoverPt"), track.sign() / track.pt()); + fRegistry.fill(HIST("Track/positive/hPResolution"), track.p(), sigmaP(track) / track.p()); + fRegistry.fill(HIST("Track/positive/hPtResolution"), track.p(), sigmaPt(track) / track.pt()); + fRegistry.fill(HIST("Track/positive/hThetaResolution"), track.p(), sigmaTheta(track)); + fRegistry.fill(HIST("Track/positive/hEtaResolution"), track.p(), sigmaEta(track)); + fRegistry.fill(HIST("Track/positive/hPhiResolution"), track.p(), sigmaPhi(track)); + fRegistry.fill(HIST("Track/positive/hDCAxyz"), track.dcaXY(), track.dcaZ()); + fRegistry.fill(HIST("Track/positive/hDCAxyzSigma"), track.dcaXY() / sqrt(track.cYY()), track.dcaZ() / sqrt(track.cZZ())); + fRegistry.fill(HIST("Track/positive/hDCAxyRes_Pt"), track.pt(), sqrt(track.cYY()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/positive/hDCAzRes_Pt"), track.pt(), sqrt(track.cZZ()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/positive/hNclsITS"), track.itsNCls()); + fRegistry.fill(HIST("Track/positive/hNclsTPC"), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/positive/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("Track/positive/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("Track/positive/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("Track/positive/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("Track/positive/hTPCNclsShared"), track.pt(), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("Track/positive/hDeltaPin"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + fRegistry.fill(HIST("Track/positive/hChi2ITS"), track.itsChi2NCl()); + fRegistry.fill(HIST("Track/positive/hITSClusterMap"), track.itsClusterMap()); + fRegistry.fill(HIST("Track/positive/hChi2TOF"), track.p(), track.tofChi2()); + + fRegistry.fill(HIST("Track/positive/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + fRegistry.fill(HIST("Track/positive/hTOFbeta"), track.p(), track.beta()); + fRegistry.fill(HIST("Track/positive/hMeanClusterSizeITS"), track.p(), track.meanClusterSizeITS() * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/positive/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/positive/hTPCNsigmaMu"), track.tpcInnerParam(), track.tpcNSigmaMu()); + fRegistry.fill(HIST("Track/positive/hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); + fRegistry.fill(HIST("Track/positive/hTPCNsigmaKa"), track.tpcInnerParam(), track.tpcNSigmaKa()); + fRegistry.fill(HIST("Track/positive/hTPCNsigmaPr"), track.tpcInnerParam(), track.tpcNSigmaPr()); + fRegistry.fill(HIST("Track/positive/hTOFNsigmaEl"), track.p(), track.tofNSigmaEl()); + fRegistry.fill(HIST("Track/positive/hTOFNsigmaMu"), track.p(), track.tofNSigmaMu()); + fRegistry.fill(HIST("Track/positive/hTOFNsigmaPi"), track.p(), track.tofNSigmaPi()); + fRegistry.fill(HIST("Track/positive/hTOFNsigmaKa"), track.p(), track.tofNSigmaKa()); + fRegistry.fill(HIST("Track/positive/hTOFNsigmaPr"), track.p(), track.tofNSigmaPr()); + } else { + fRegistry.fill(HIST("Track/negative/hs"), track.pt(), track.eta(), track.phi(), dca_3d, weight); + fRegistry.fill(HIST("Track/negative/hQoverPt"), track.sign() / track.pt()); + fRegistry.fill(HIST("Track/negative/hPResolution"), track.p(), sigmaP(track) / track.p()); + fRegistry.fill(HIST("Track/negative/hPtResolution"), track.p(), sigmaPt(track) / track.pt()); + fRegistry.fill(HIST("Track/negative/hThetaResolution"), track.p(), sigmaTheta(track)); + fRegistry.fill(HIST("Track/negative/hEtaResolution"), track.p(), sigmaEta(track)); + fRegistry.fill(HIST("Track/negative/hPhiResolution"), track.p(), sigmaPhi(track)); + fRegistry.fill(HIST("Track/negative/hDCAxyz"), track.dcaXY(), track.dcaZ()); + fRegistry.fill(HIST("Track/negative/hDCAxyzSigma"), track.dcaXY() / sqrt(track.cYY()), track.dcaZ() / sqrt(track.cZZ())); + fRegistry.fill(HIST("Track/negative/hDCAxyRes_Pt"), track.pt(), sqrt(track.cYY()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/negative/hDCAzRes_Pt"), track.pt(), sqrt(track.cZZ()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/negative/hNclsITS"), track.itsNCls()); + fRegistry.fill(HIST("Track/negative/hNclsTPC"), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/negative/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("Track/negative/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("Track/negative/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("Track/negative/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("Track/negative/hTPCNclsShared"), track.pt(), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("Track/negative/hDeltaPin"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + fRegistry.fill(HIST("Track/negative/hChi2ITS"), track.itsChi2NCl()); + fRegistry.fill(HIST("Track/negative/hITSClusterMap"), track.itsClusterMap()); + fRegistry.fill(HIST("Track/negative/hChi2TOF"), track.p(), track.tofChi2()); + + fRegistry.fill(HIST("Track/negative/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + fRegistry.fill(HIST("Track/negative/hTOFbeta"), track.p(), track.beta()); + fRegistry.fill(HIST("Track/negative/hMeanClusterSizeITS"), track.p(), track.meanClusterSizeITS() * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/negative/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/negative/hTPCNsigmaMu"), track.tpcInnerParam(), track.tpcNSigmaMu()); + fRegistry.fill(HIST("Track/negative/hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); + fRegistry.fill(HIST("Track/negative/hTPCNsigmaKa"), track.tpcInnerParam(), track.tpcNSigmaKa()); + fRegistry.fill(HIST("Track/negative/hTPCNsigmaPr"), track.tpcInnerParam(), track.tpcNSigmaPr()); + fRegistry.fill(HIST("Track/negative/hTOFNsigmaEl"), track.p(), track.tofNSigmaEl()); + fRegistry.fill(HIST("Track/negative/hTOFNsigmaMu"), track.p(), track.tofNSigmaMu()); + fRegistry.fill(HIST("Track/negative/hTOFNsigmaPi"), track.p(), track.tofNSigmaPi()); + fRegistry.fill(HIST("Track/negative/hTOFNsigmaKa"), track.p(), track.tofNSigmaKa()); + fRegistry.fill(HIST("Track/negative/hTOFNsigmaPr"), track.p(), track.tofNSigmaPr()); + } + } + + Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin < o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + using FilteredMyCollisions = soa::Filtered; + + SliceCache cache; + Preslice perCollision_track = aod::emprimaryelectron::emeventId; + Filter trackFilter_electron = dielectroncuts.cfg_min_pt_track < o2::aod::track::pt && dielectroncuts.cfg_min_eta_track < o2::aod::track::eta && o2::aod::track::eta < dielectroncuts.cfg_max_eta_track && o2::aod::track::tpcChi2NCl < dielectroncuts.cfg_max_chi2tpc && o2::aod::track::itsChi2NCl < dielectroncuts.cfg_max_chi2its && nabs(o2::aod::track::dcaXY) < dielectroncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dielectroncuts.cfg_max_dcaz; + Filter pidFilter_electron = dielectroncuts.cfg_min_TPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < dielectroncuts.cfg_max_TPCNsigmaEl; + Filter ttcaFilter_electron = ifnode(dielectroncuts.enableTTCA.node(), o2::aod::emprimaryelectron::isAssociatedToMPC == true || o2::aod::emprimaryelectron::isAssociatedToMPC == false, o2::aod::emprimaryelectron::isAssociatedToMPC == true); + using FilteredMyTracks = soa::Filtered; + + Partition posTracks = o2::aod::emprimaryelectron::sign > int8_t(0); + Partition negTracks = o2::aod::emprimaryelectron::sign < int8_t(0); + + std::vector used_trackIds; + void processQC(FilteredMyCollisions const& collisions, FilteredMyTracks const& /*tracks*/) + { + for (auto& collision : collisions) { + initCCDB(collision); + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), o2::aod::pwgem::dilepton::utils::eventhistogram::nbin_ev); // accepted + + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + // LOGF(info, "centrality = %f , posTracks_per_coll.size() = %d, negTracks_per_coll.size() = %d", centralities[cfgCentEstimator], posTracks_per_coll.size(), negTracks_per_coll.size()); + + for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + fillPairInfo(collision, pos, ele); + } + } // end of collision loop + + used_trackIds.clear(); + used_trackIds.shrink_to_fit(); + + } // end of process + PROCESS_SWITCH(vpPairQC, processQC, "run vp pair QC", true); + + void processDummy(MyCollisions const&) {} + PROCESS_SWITCH(vpPairQC, processDummy, "Dummy function", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"vp-pair-qc"})}; +} diff --git a/PWGEM/Dilepton/Tasks/vpPairQCMC.cxx b/PWGEM/Dilepton/Tasks/vpPairQCMC.cxx new file mode 100644 index 00000000000..13bda4c1d87 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/vpPairQCMC.cxx @@ -0,0 +1,664 @@ +// 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. +// +// ======================== +// +// This code runs loop over ULS ee pars for virtual photon QC. +// Please write to: daiki.sekihata@cern.ch + +#include +#include +#include + +#include "TString.h" +#include "Math/Vector4D.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" + +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "Common/Core/RecoDecay.h" + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Core/DielectronCut.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/Dilepton/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::dilepton::utils::mcutil; + +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; + +using MyMCTracks = soa::Join; +using MyMCTrack = MyMCTracks::iterator; + +struct vpPairQCMC { + + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + Configurable maxY{"maxY", 0.9, "maximum rapidity for reconstructed particles"}; + + EMEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInTimeRangeStrict{"cfgRequireNoCollInTimeRangeStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoCollInITSROFStandard{"cfgRequireNoCollInITSROFStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInITSROFStrict{"cfgRequireNoCollInITSROFStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoHighMultCollInPrevRof{"cfgRequireNoHighMultCollInPrevRof", false, "require no HM collision in previous ITS ROF"}; + } eventcuts; + + DielectronCut fDielectronCut; + struct : ConfigurableGroup { + std::string prefix = "dielectroncut_group"; + Configurable cfg_min_mass{"cfg_min_mass", 0.0, "min mass"}; + Configurable cfg_max_mass{"cfg_max_mass", 0.01, "max mass"}; + Configurable cfg_min_pair_pt{"cfg_min_pair_pt", 0.0, "min pair pT"}; + Configurable cfg_max_pair_pt{"cfg_max_pair_pt", 1e+10, "max pair pT"}; + Configurable cfg_min_pair_y{"cfg_min_pair_y", -0.9, "min pair rapidity"}; + Configurable cfg_max_pair_y{"cfg_max_pair_y", +0.9, "max pair rapidity"}; + Configurable cfg_min_pair_dca3d{"cfg_min_pair_dca3d", 0.0, "min pair dca3d in sigma"}; + Configurable cfg_max_pair_dca3d{"cfg_max_pair_dca3d", 1e+10, "max pair dca3d in sigma"}; + Configurable cfg_apply_phiv{"cfg_apply_phiv", true, "flag to apply phiv cut"}; + Configurable cfg_apply_pf{"cfg_apply_pf", false, "flag to apply phiv prefilter"}; + Configurable cfg_require_itsib_any{"cfg_require_itsib_any", false, "flag to require ITS ib any hits"}; + Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; + Configurable cfg_phiv_slope{"cfg_phiv_slope", 0.0185, "slope for m vs. phiv"}; + Configurable cfg_phiv_intercept{"cfg_phiv_intercept", -0.0280, "intercept for m vs. phiv"}; + Configurable cfg_min_phiv{"cfg_min_phiv", 0.0, "min phiv (constant)"}; + Configurable cfg_max_phiv{"cfg_max_phiv", 3.2, "max phiv (constant)"}; + + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.1, "min pT for single track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -0.9, "min eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", +0.9, "max eta for single track"}; + Configurable cfg_max_dca3dsigma_track{"cfg_max_dca3dsigma_track", 1e+10, "max DCA 3D in sigma"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 100, "min ncrossed rows"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_chi2tof{"cfg_max_chi2tof", 1e+10, "max chi2 TOF"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1.0, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 1.0, "max dca Z for single track in cm"}; + Configurable cfg_min_its_cluster_size{"cfg_min_its_cluster_size", 0.f, "min ITS cluster size"}; + Configurable cfg_max_its_cluster_size{"cfg_max_its_cluster_size", 16.f, "max ITS cluster size"}; + Configurable cfg_max_p_its_cluster_size{"cfg_max_p_its_cluster_size", 0.2, "max p to apply ITS cluster size cut"}; + Configurable cfg_min_rel_diff_pin{"cfg_min_rel_diff_pin", -1e+10, "min rel. diff. between pin and ppv"}; + Configurable cfg_max_rel_diff_pin{"cfg_max_rel_diff_pin", +1e+10, "max rel. diff. between pin and ppv"}; + + Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DielectronCut::PIDSchemes::kTOFif), "pid scheme [kTOFreq : 0, kTPChadrej : 1, kTPChadrejORTOFreq : 2, kTPConly : 3, kTOFif : 4, kPIDML : 5]"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + Configurable cfg_min_TPCNsigmaMu{"cfg_min_TPCNsigmaMu", -0.0, "min. TPC n sigma for muon exclusion"}; + Configurable cfg_max_TPCNsigmaMu{"cfg_max_TPCNsigmaMu", +0.0, "max. TPC n sigma for muon exclusion"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -0.0, "min. TPC n sigma for pion exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +0.0, "max. TPC n sigma for pion exclusion"}; + Configurable cfg_min_TPCNsigmaKa{"cfg_min_TPCNsigmaKa", -0.0, "min. TPC n sigma for kaon exclusion"}; + Configurable cfg_max_TPCNsigmaKa{"cfg_max_TPCNsigmaKa", +0.0, "max. TPC n sigma for kaon exclusion"}; + Configurable cfg_min_TPCNsigmaPr{"cfg_min_TPCNsigmaPr", -0.0, "min. TPC n sigma for proton exclusion"}; + Configurable cfg_max_TPCNsigmaPr{"cfg_max_TPCNsigmaPr", +0.0, "max. TPC n sigma for proton exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -0.0, "min. TOF n sigma for electron inclusion"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +0.0, "max. TOF n sigma for electron inclusion"}; + Configurable cfg_max_pin_pirejTPC{"cfg_max_pin_pirejTPC", 0.5, "max. pin for pion rejection in TPC"}; + Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; + + // configuration for PID ML + Configurable> onnxFileNames{"onnxFileNames", std::vector{"filename"}, "ONNX file names for each bin (if not from CCDB full path)"}; + Configurable> onnxPathsCCDB{"onnxPathsCCDB", std::vector{"path"}, "Paths of models on CCDB"}; + Configurable> binsMl{"binsMl", std::vector{-999999., 999999.}, "Bin limits for ML application"}; + Configurable> cutsMl{"cutsMl", std::vector{0.95}, "ML cuts per bin"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature"}, "Names of ML model input features"}; + Configurable nameBinningFeature{"nameBinningFeature", "pt", "Names of ML model binning feature"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + Configurable enableOptimizations{"enableOptimizations", false, "Enables the ONNX extended model-optimization: sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED)"}; + } dielectroncuts; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + int mRunNumber; + float d_bz; + + struct : ConfigurableGroup { + std::string prefix = "mctrackcut_group"; + Configurable min_mcPt{"min_mcPt", 0.05, "min. MC pT"}; + Configurable max_mcPt{"max_mcPt", 1e+10, "max. MC pT"}; + Configurable max_mcEta{"max_mcEta", 0.9, "max. MC eta"}; + } mctrackcuts; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view event_cut_types[2] = {"before/", "after/"}; + + ~vpPairQCMC() {} + + void addhistograms() + { + // event info + o2::aod::pwgem::dilepton::utils::eventhistogram::addEventHistograms(&fRegistry); + + std::vector ptbins; + std::vector massbins; + + for (int i = 0; i < 51; i++) { + massbins.emplace_back(0.01 * (i - 0) + 0.0); // every 0.01 GeV/c2 from 0.0 to 0.5 GeV/c2 + } + const AxisSpec axis_mass{massbins, "m_{ee} (GeV/c^{2})"}; + + for (int i = 0; i < 50; i++) { + ptbins.emplace_back(0.1 * (i - 0) + 0.0); // every 0.1 GeV/c from 0.0 to 5.0 GeV/c + } + for (int i = 50; i < 61; i++) { + ptbins.emplace_back(0.5 * (i - 50) + 5.0); // every 0.5 GeV/c from 5.0 to 10 GeV/c + } + const AxisSpec axis_pt{ptbins, "p_{T,ee} (GeV/c)"}; + + // generated info + fRegistry.add("Generated/sm/Pi0/hMvsPt", "m_{ee} vs. p_{T,ee} ULS", kTH2F, {axis_mass, axis_pt}, true); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/Eta/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/EtaPrime/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/Rho/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/Omega/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/Phi/"); + + // reconstructed pair info + fRegistry.add("Pair/sm/Photon/hMvsPt", "m_{ee} vs. p_{T,ee} ULS", kTH2F, {axis_mass, axis_pt}, true); + fRegistry.add("Pair/sm/Photon/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0, M_PI}, {100, 0.0f, 0.1f}}, false); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Pi0/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Eta/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/EtaPrime/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Rho/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Omega/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Phi/"); + + // track info + fRegistry.add("Track/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); + fRegistry.add("Track/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); + fRegistry.add("Track/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {40, -2.0f, 2.0f}}, false); + fRegistry.add("Track/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -1.0f, 1.0f}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("Track/hNclsTPC", "number of TPC clusters", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hNcrTPC", "number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("Track/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("Track/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("Track/hMeanClusterSizeITS", "mean cluster size ITS; on ITS #times cos(#lambda)", kTH1F, {{32, 0, 16}}, false); + } + + void init(InitContext&) + { + DefineEMEventCut(); + DefineDielectronCut(); + addhistograms(); + + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + } + + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + mRunNumber = collision.runNumber(); + return; + } + + auto run3grp_timestamp = collision.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = collision.runNumber(); + } + + void DefineEMEventCut() + { + fEMEventCut = EMEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireNoCollInTimeRangeStandard(eventcuts.cfgRequireNoCollInTimeRangeStandard); + fEMEventCut.SetRequireNoCollInTimeRangeStrict(eventcuts.cfgRequireNoCollInTimeRangeStrict); + fEMEventCut.SetRequireNoCollInITSROFStandard(eventcuts.cfgRequireNoCollInITSROFStandard); + fEMEventCut.SetRequireNoCollInITSROFStrict(eventcuts.cfgRequireNoCollInITSROFStrict); + fEMEventCut.SetRequireNoHighMultCollInPrevRof(eventcuts.cfgRequireNoHighMultCollInPrevRof); + } + + o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; + void DefineDielectronCut() + { + fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); + + // for pair + fDielectronCut.SetMeeRange(dielectroncuts.cfg_min_mass, dielectroncuts.cfg_max_mass); + fDielectronCut.SetPairPtRange(dielectroncuts.cfg_min_pair_pt, dielectroncuts.cfg_max_pair_pt); + fDielectronCut.SetPairYRange(dielectroncuts.cfg_min_pair_y, dielectroncuts.cfg_max_pair_y); + fDielectronCut.SetPairDCARange(dielectroncuts.cfg_min_pair_dca3d, dielectroncuts.cfg_max_pair_dca3d); // in sigma + fDielectronCut.SetMaxMeePhiVDep([&](float phiv) { return dielectroncuts.cfg_phiv_intercept + phiv * dielectroncuts.cfg_phiv_slope; }, dielectroncuts.cfg_min_phiv, dielectroncuts.cfg_max_phiv); + fDielectronCut.ApplyPhiV(dielectroncuts.cfg_apply_phiv); + fDielectronCut.ApplyPrefilter(dielectroncuts.cfg_apply_pf); + fDielectronCut.RequireITSibAny(dielectroncuts.cfg_require_itsib_any); + fDielectronCut.RequireITSib1st(dielectroncuts.cfg_require_itsib_1st); + + // for track + fDielectronCut.SetTrackPtRange(dielectroncuts.cfg_min_pt_track, dielectroncuts.cfg_max_pt_track); + fDielectronCut.SetTrackEtaRange(-dielectroncuts.cfg_max_eta_track, +dielectroncuts.cfg_max_eta_track); + fDielectronCut.SetTrackDca3DRange(0.f, dielectroncuts.cfg_max_dca3dsigma_track); // in sigma + fDielectronCut.SetMinNClustersTPC(dielectroncuts.cfg_min_ncluster_tpc); + fDielectronCut.SetMinNCrossedRowsTPC(dielectroncuts.cfg_min_ncrossedrows); + fDielectronCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fDielectronCut.SetChi2PerClusterTPC(0.0, dielectroncuts.cfg_max_chi2tpc); + fDielectronCut.SetChi2PerClusterITS(0.0, dielectroncuts.cfg_max_chi2its); + fDielectronCut.SetNClustersITS(dielectroncuts.cfg_min_ncluster_its, 7); + fDielectronCut.SetMeanClusterSizeITS(dielectroncuts.cfg_min_its_cluster_size, dielectroncuts.cfg_max_its_cluster_size, dielectroncuts.cfg_max_p_its_cluster_size); + fDielectronCut.SetTrackMaxDcaXY(dielectroncuts.cfg_max_dcaxy); + fDielectronCut.SetTrackMaxDcaZ(dielectroncuts.cfg_max_dcaz); + fDielectronCut.SetChi2TOF(0.0, dielectroncuts.cfg_max_chi2tof); + fDielectronCut.SetRelDiffPin(dielectroncuts.cfg_min_rel_diff_pin, dielectroncuts.cfg_max_rel_diff_pin); + + // for eID + fDielectronCut.SetPIDScheme(dielectroncuts.cfg_pid_scheme); + fDielectronCut.SetTPCNsigmaElRange(dielectroncuts.cfg_min_TPCNsigmaEl, dielectroncuts.cfg_max_TPCNsigmaEl); + fDielectronCut.SetTPCNsigmaMuRange(dielectroncuts.cfg_min_TPCNsigmaMu, dielectroncuts.cfg_max_TPCNsigmaMu); + fDielectronCut.SetTPCNsigmaPiRange(dielectroncuts.cfg_min_TPCNsigmaPi, dielectroncuts.cfg_max_TPCNsigmaPi); + fDielectronCut.SetTPCNsigmaKaRange(dielectroncuts.cfg_min_TPCNsigmaKa, dielectroncuts.cfg_max_TPCNsigmaKa); + fDielectronCut.SetTPCNsigmaPrRange(dielectroncuts.cfg_min_TPCNsigmaPr, dielectroncuts.cfg_max_TPCNsigmaPr); + fDielectronCut.SetTOFNsigmaElRange(dielectroncuts.cfg_min_TOFNsigmaEl, dielectroncuts.cfg_max_TOFNsigmaEl); + fDielectronCut.SetMaxPinForPionRejectionTPC(dielectroncuts.cfg_max_pin_pirejTPC); + + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { // please call this at the end of DefineDileptonCut + static constexpr int nClassesMl = 2; + const std::vector cutDirMl = {o2::cuts_ml::CutSmaller, o2::cuts_ml::CutNot}; + const std::vector labelsClasses = {"Signal", "Background"}; + const uint32_t nBinsMl = dielectroncuts.binsMl.value.size() - 1; + const std::vector labelsBins(nBinsMl, "bin"); + double cutsMlArr[nBinsMl][nClassesMl]; + for (uint32_t i = 0; i < nBinsMl; i++) { + cutsMlArr[i][0] = dielectroncuts.cutsMl.value[i]; + cutsMlArr[i][1] = 0.; + } + o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; + + mlResponseSingleTrack.configure(dielectroncuts.binsMl.value, cutsMl, cutDirMl, nClassesMl); + if (dielectroncuts.loadModelsFromCCDB) { + ccdbApi.init(ccdburl); + mlResponseSingleTrack.setModelPathsCCDB(dielectroncuts.onnxFileNames.value, ccdbApi, dielectroncuts.onnxPathsCCDB.value, dielectroncuts.timestampCCDB.value); + } else { + mlResponseSingleTrack.setModelPathsLocal(dielectroncuts.onnxFileNames.value); + } + mlResponseSingleTrack.cacheInputFeaturesIndices(dielectroncuts.namesInputFeatures); + mlResponseSingleTrack.cacheBinningIndex(dielectroncuts.nameBinningFeature); + mlResponseSingleTrack.init(dielectroncuts.enableOptimizations.value); + + fDielectronCut.SetPIDMlResponse(&mlResponseSingleTrack); + } // end of PID ML + } + + template + int FindLF(TTrack const& posmc, TTrack const& elemc, TMCParticles const& mcparticles) + { + int arr[] = { + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 22, mcparticles), + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 111, mcparticles), + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 221, mcparticles), + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 331, mcparticles), + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 113, mcparticles), + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 223, mcparticles), + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 333, mcparticles), + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 443, mcparticles), + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 100443, mcparticles)}; + int size = sizeof(arr) / sizeof(*arr); + int max = *std::max_element(arr, arr + size); + return max; + } + + template + bool isInAcceptance(T const& t1) + { + if ((mctrackcuts.min_mcPt < t1.pt() && t1.pt() < mctrackcuts.max_mcPt) && abs(t1.eta()) < mctrackcuts.max_mcEta) { + return true; + } else { + return false; + } + } + + template + bool fillTruePairInfo(TCollision const&, TTrack1 const& t1, TTrack2 const& t2, TMCParticles const& mcparticles) + { + if (!fDielectronCut.IsSelectedTrack(t1) || !fDielectronCut.IsSelectedTrack(t2)) { + return false; + } + + if (!fDielectronCut.IsSelectedPair(t1, t2, d_bz)) { + return false; + } + + auto t1mc = t1.template emmcparticle_as(); + auto t2mc = t2.template emmcparticle_as(); + + int mother_id = FindLF(t1mc, t2mc, mcparticles); + int hfee_type = IsHF(t1mc, t2mc, mcparticles); + if (mother_id < 0 && hfee_type < 0) { + return false; + } + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + if (abs(v12.Rapidity()) > maxY) { + return false; + } + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), d_bz); + + if (mother_id > -1 && t1mc.pdgCode() * t2mc.pdgCode() < 0) { + auto mcmother = mcparticles.iteratorAt(mother_id); + if (mcmother.isPhysicalPrimary() || mcmother.producedByGenerator()) { + if ((t1mc.isPhysicalPrimary() || t1mc.producedByGenerator()) && (t2mc.isPhysicalPrimary() || t2mc.producedByGenerator())) { + switch (abs(mcmother.pdgCode())) { + case 111: + fRegistry.fill(HIST("Pair/sm/Pi0/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/sm/Pi0/hMvsPhiV"), phiv, v12.M()); + break; + case 221: + fRegistry.fill(HIST("Pair/sm/Eta/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/sm/Eta/hMvsPhiV"), phiv, v12.M()); + break; + case 331: + fRegistry.fill(HIST("Pair/sm/EtaPrime/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/sm/EtaPrime/hMvsPhiV"), phiv, v12.M()); + break; + case 113: + fRegistry.fill(HIST("Pair/sm/Rho/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/sm/Rho/hMvsPhiV"), phiv, v12.M()); + break; + case 223: + fRegistry.fill(HIST("Pair/sm/Omega/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/sm/Omega/hMvsPhiV"), phiv, v12.M()); + break; + case 333: + fRegistry.fill(HIST("Pair/sm/Phi/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/sm/Phi/hMvsPhiV"), phiv, v12.M()); + break; + default: + break; + } + } else if (!(t1mc.isPhysicalPrimary() || t1mc.producedByGenerator()) && !(t2mc.isPhysicalPrimary() || t2mc.producedByGenerator())) { + switch (abs(mcmother.pdgCode())) { + case 22: + fRegistry.fill(HIST("Pair/sm/Photon/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/sm/Photon/hMvsPhiV"), phiv, v12.M()); + break; + default: + break; + } + } // end of primary/secondary selection + } // end of primary selection for same mother + } + + // fill track info that belong to true pairs. + if (t1.sign() > 0) { + if (std::find(used_trackIds.begin(), used_trackIds.end(), t1.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t1.globalIndex()); + fillTrackInfo(t1); + } + } else { + if (std::find(used_trackIds.begin(), used_trackIds.end(), t1.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t1.globalIndex()); + fillTrackInfo(t1); + } + } + if (t2.sign() > 0) { + if (std::find(used_trackIds.begin(), used_trackIds.end(), t1.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t1.globalIndex()); + fillTrackInfo(t2); + } + } else { + if (std::find(used_trackIds.begin(), used_trackIds.end(), t2.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t2.globalIndex()); + fillTrackInfo(t2); + } + } + + return true; + } + + template + void fillTrackInfo(TTrack const& track) + { + fRegistry.fill(HIST("Track/hPt"), track.pt()); + fRegistry.fill(HIST("Track/hQoverPt"), track.sign() / track.pt()); + fRegistry.fill(HIST("Track/hEtaPhi"), track.phi(), track.eta()); + fRegistry.fill(HIST("Track/hDCAxyz"), track.dcaXY(), track.dcaZ()); + fRegistry.fill(HIST("Track/hNclsITS"), track.itsNCls()); + fRegistry.fill(HIST("Track/hNclsTPC"), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("Track/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("Track/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("Track/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("Track/hChi2ITS"), track.itsChi2NCl()); + fRegistry.fill(HIST("Track/hITSClusterMap"), track.itsClusterMap()); + fRegistry.fill(HIST("Track/hMeanClusterSizeITS"), track.meanClusterSizeITS() * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); + } + + std::vector used_trackIds; + SliceCache cache; + Preslice perCollision_track = aod::emprimaryelectron::emeventId; + Filter trackFilter_electron = dielectroncuts.cfg_min_pt_track < o2::aod::track::pt && dielectroncuts.cfg_min_eta_track < o2::aod::track::eta && o2::aod::track::eta < dielectroncuts.cfg_max_eta_track && o2::aod::track::tpcChi2NCl < dielectroncuts.cfg_max_chi2tpc && o2::aod::track::itsChi2NCl < dielectroncuts.cfg_max_chi2its && nabs(o2::aod::track::dcaXY) < dielectroncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dielectroncuts.cfg_max_dcaz; + Filter pidFilter_electron = dielectroncuts.cfg_min_TPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < dielectroncuts.cfg_max_TPCNsigmaEl; + Filter ttcaFilter_electron = ifnode(dielectroncuts.enableTTCA.node(), o2::aod::emprimaryelectron::isAssociatedToMPC == true || o2::aod::emprimaryelectron::isAssociatedToMPC == false, o2::aod::emprimaryelectron::isAssociatedToMPC == true); + + using FilteredMyMCTracks = soa::Filtered; + Partition posTracks = o2::aod::emprimaryelectron::sign > int8_t(0); + Partition negTracks = o2::aod::emprimaryelectron::sign < int8_t(0); + + Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin < o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + using FilteredMyCollisions = soa::Filtered; + + void processQCMC(FilteredMyCollisions const& collisions, FilteredMyMCTracks const& tracks, aod::EMMCParticles const& mcparticles, aod::EMMCEvents const&) + { + used_trackIds.reserve(tracks.size()); + + for (auto& collision : collisions) { + initCCDB(collision); + + float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + o2::aod::pwgem::dilepton::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 12.0); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 12.0); // accepted + + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + // LOGF(info, "centrality = %f , posTracks_per_coll.size() = %d, negTracks_per_coll.size() = %d", centralities[cfgCentEstimator], posTracks_per_coll.size(), negTracks_per_coll.size()); + + for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + fillTruePairInfo(collision, pos, ele, mcparticles); + } // end of ULS pair loop + + } // end of collision loop + + used_trackIds.clear(); + used_trackIds.shrink_to_fit(); + } // end of process + PROCESS_SWITCH(vpPairQCMC, processQCMC, "run Dalitz QC", true); + + Partition posTracksMC = o2::aod::mcparticle::pdgCode == -11; // e+ + Partition negTracksMC = o2::aod::mcparticle::pdgCode == +11; // e- + PresliceUnsorted perMcCollision = aod::emmcparticle::emmceventId; + void processGen(MyCollisions const& collisions, aod::EMMCEvents const&, aod::EMMCParticles const& mcparticles) + { + // loop over mc stack and fill histograms for pure MC truth signals + // all MC tracks which belong to the MC event corresponding to the current reconstructed event + + for (auto& collision : collisions) { + float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + auto mccollision = collision.emmcevent_as(); + + auto posTracks_per_coll = posTracksMC->sliceByCachedUnsorted(o2::aod::emmcparticle::emmceventId, mccollision.globalIndex(), cache); + auto negTracks_per_coll = negTracksMC->sliceByCachedUnsorted(o2::aod::emmcparticle::emmceventId, mccollision.globalIndex(), cache); + + for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + // LOGF(info, "pdg1 = %d, pdg2 = %d", t1.pdgCode(), t2.pdgCode()); + + if (!isInAcceptance(t1) || !isInAcceptance(t2)) { + continue; + } + + if (!t1.isPhysicalPrimary() && !t1.producedByGenerator()) { + continue; + } + if (!t2.isPhysicalPrimary() && !t2.producedByGenerator()) { + continue; + } + + int mother_id = FindLF(t1, t2, mcparticles); + int hfee_type = IsHF(t1, t2, mcparticles); + if (mother_id < 0 && hfee_type < 0) { + continue; + } + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + + if (abs(v12.Rapidity()) > maxY) { + continue; + } + + if (mother_id > -1) { + auto mcmother = mcparticles.iteratorAt(mother_id); + if (mcmother.isPhysicalPrimary() || mcmother.producedByGenerator()) { + + switch (abs(mcmother.pdgCode())) { + case 111: + fRegistry.fill(HIST("Generated/sm/Pi0/hMvsPt"), v12.M(), v12.Pt()); + break; + case 221: + fRegistry.fill(HIST("Generated/sm/Eta/hMvsPt"), v12.M(), v12.Pt()); + break; + case 331: + fRegistry.fill(HIST("Generated/sm/EtaPrime/hMvsPt"), v12.M(), v12.Pt()); + break; + case 113: + fRegistry.fill(HIST("Generated/sm/Rho/hMvsPt"), v12.M(), v12.Pt()); + break; + case 223: + fRegistry.fill(HIST("Generated/sm/Omega/hMvsPt"), v12.M(), v12.Pt()); + break; + case 333: + fRegistry.fill(HIST("Generated/sm/Phi/hMvsPt"), v12.M(), v12.Pt()); + break; + default: + break; + } + } + } + } // end of true ULS pair loop + } // end of collision loop + } + PROCESS_SWITCH(vpPairQCMC, processGen, "run genrated info", true); + + void processDummy(MyCollisions const&) {} + PROCESS_SWITCH(vpPairQCMC, processDummy, "Dummy function", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"vp-pair-qc-mc"})}; +} diff --git a/PWGEM/Dilepton/Utils/EMFwdTrack.h b/PWGEM/Dilepton/Utils/EMFwdTrack.h new file mode 100644 index 00000000000..760441a08bf --- /dev/null +++ b/PWGEM/Dilepton/Utils/EMFwdTrack.h @@ -0,0 +1,102 @@ +// 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. + +/// \class to store minimal fwdtrack info +/// \author daiki.sekihata@cern.ch + +#ifndef PWGEM_DILEPTON_UTILS_EMFWDTRACK_H_ +#define PWGEM_DILEPTON_UTILS_EMFWDTRACK_H_ + +#include + +namespace o2::aod::pwgem::dilepton::utils +{ +class EMFwdTrack +{ + public: + EMFwdTrack(int dfId, int globalId, int collisionId, int trackId, float pt, float eta, float phi, float mass, int8_t charge, float dcaX, float dcaY, std::vector amb_muon_self_ids, float cXX, float cXY, float cYY) + { + fDFId = dfId; + fGlobalId = globalId; + fCollisionId = collisionId; + fTrackId = trackId; + fPt = pt; + fEta = eta; + fPhi = phi; + fMass = mass; + fCharge = charge; + fDCAx = dcaX; + fDCAy = dcaY; + fPairDCAXYinSigmaOTF = 0; + + fAmbMuonSelfIds = amb_muon_self_ids; + if (fAmbMuonSelfIds.size() > 0) { + fIsAmbiguous = true; + } else { + fIsAmbiguous = false; + } + + fCXX = cXX; + fCXY = cXY; + fCYY = cYY; + } + + ~EMFwdTrack() {} + + int dfId() const { return fDFId; } + int globalIndex() const { return fGlobalId; } + int collisionId() const { return fCollisionId; } + int fwdtrackId() const { return fTrackId; } + float pt() const { return fPt; } + float eta() const { return fEta; } + float phi() const { return fPhi; } + float mass() const { return fMass; } + int8_t sign() const { return fCharge; } + float fwdDcaX() const { return fDCAx; } + float fwdDcaY() const { return fDCAy; } + float fwdDcaXY() const { return std::sqrt(std::pow(fDCAx, 2) + std::pow(fDCAy, 2)); } + float p() const { return fPt * std::cosh(fEta); } + float px() const { return fPt * std::cos(fPhi); } + float py() const { return fPt * std::sin(fPhi); } + float pz() const { return fPt * std::sinh(fEta); } + bool has_ambiguousMuons() const { return fIsAmbiguous; } + std::vector ambiguousMuonsIds() const { return fAmbMuonSelfIds; } + float signed1Pt() const { return fCharge * 1.f / fPt; } + + float cXXatDCA() const { return fCXX; } + float cXYatDCA() const { return fCXY; } + float cYYatDCA() const { return fCYY; } + + float pairDcaXYinSigmaOTF() const { return fPairDCAXYinSigmaOTF; } + void setPairDcaXYinSigmaOTF(float dca) { fPairDCAXYinSigmaOTF = dca; } + + protected: + int fDFId; + int fGlobalId; + int fCollisionId; + int fTrackId; + float fPt; + float fEta; + float fPhi; + float fMass; + int8_t fCharge; + float fDCAx; + float fDCAy; + float fPairDCAXYinSigmaOTF; + bool fIsAmbiguous; + std::vector fAmbMuonSelfIds; + float fCXX; + float fCXY; + float fCYY; +}; + +} // namespace o2::aod::pwgem::dilepton::utils +#endif // PWGEM_DILEPTON_UTILS_EMFWDTRACK_H_ diff --git a/PWGEM/Dilepton/Utils/EMTrack.h b/PWGEM/Dilepton/Utils/EMTrack.h new file mode 100644 index 00000000000..0f894d5b4dc --- /dev/null +++ b/PWGEM/Dilepton/Utils/EMTrack.h @@ -0,0 +1,247 @@ +// 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. + +/// \class to store minimal track info +/// \author daiki.sekihata@cern.ch + +#ifndef PWGEM_DILEPTON_UTILS_EMTRACK_H_ +#define PWGEM_DILEPTON_UTILS_EMTRACK_H_ + +#include +#include "Math/Vector4D.h" + +namespace o2::aod::pwgem::dilepton::utils +{ +class EMTrack +{ + public: + EMTrack(int dfId, int globalId, int collisionId, int trackId, float pt, float eta, float phi, float mass, int8_t charge = 0, float dcaXY = 0.f, float dcaZ = 0.f, std::vector amb_ele_self_ids = {}) + { + fDFId = dfId; + fGlobalId = globalId; + fCollisionId = collisionId; + fTrackId = trackId; + fPt = pt; + fEta = eta; + fPhi = phi; + fMass = mass; + fCharge = charge; + fDCAxy = dcaXY; + fDCAz = dcaZ; + fPairDCA3DinSigmaOTF = 0; + + fAmbEleSelfIds = amb_ele_self_ids; + if (fAmbEleSelfIds.size() > 0) { + fIsAmbiguous = true; + } else { + fIsAmbiguous = false; + } + fVx = 0.f; + fVy = 0.f; + fVz = 0.f; + fVPos = ROOT::Math::PtEtaPhiMVector(0, 0, 0, 0); + fVNeg = ROOT::Math::PtEtaPhiMVector(0, 0, 0, 0); + fAmbPosLegSelfIds.clear(); + fAmbNegLegSelfIds.clear(); + fAmbPosLegSelfIds.shrink_to_fit(); + fAmbNegLegSelfIds.shrink_to_fit(); + fGlobalPosId = 0; + fGlobalNegId = 0; + } + + ~EMTrack() + { + fAmbEleSelfIds.clear(); + fAmbEleSelfIds.shrink_to_fit(); + fAmbPosLegSelfIds.clear(); + fAmbNegLegSelfIds.clear(); + fAmbPosLegSelfIds.shrink_to_fit(); + fAmbNegLegSelfIds.shrink_to_fit(); + } + + int dfId() const { return fDFId; } + int globalIndex() const { return fGlobalId; } + int collisionId() const { return fCollisionId; } + int trackId() const { return fTrackId; } + float pt() const { return fPt; } + float eta() const { return fEta; } + float phi() const { return fPhi; } + float mass() const { return fMass; } + int8_t sign() const { return fCharge; } + float dcaXY() const { return fDCAxy; } + float dcaZ() const { return fDCAz; } + float p() const { return fPt * std::cosh(fEta); } + float px() const { return fPt * std::cos(fPhi); } + float py() const { return fPt * std::sin(fPhi); } + float pz() const { return fPt * std::sinh(fEta); } + bool has_ambiguousElectrons() const { return fIsAmbiguous; } + std::vector ambiguousElectronsIds() const { return fAmbEleSelfIds; } + float signed1Pt() const { return fCharge * 1.f / fPt; } + + float pairDca3DinSigmaOTF() const { return fPairDCA3DinSigmaOTF; } + void setPairDca3DinSigmaOTF(float dca) { fPairDCA3DinSigmaOTF = dca; } + + void setConversionPointXYZ(float x, float y, float z) + { + fVx = x; + fVy = y; + fVz = z; + } + float vx() const { return fVx; } + float vy() const { return fVy; } + float vz() const { return fVz; } + float v0radius() const { return std::sqrt(std::pow(fVx, 2) + std::pow(fVy, 2)); } + float eta_cp() const { return std::atanh(fVz / sqrt(pow(fVx, 2) + pow(fVy, 2) + pow(fVz, 2))); } + float phi_cp() const { return std::atan2(fVy, fVx); } + + void setPositiveLegPtEtaPhiM(float pt, float eta, float phi, float m) + { + fVPos.SetPt(pt); + fVPos.SetEta(eta); + fVPos.SetPhi(phi); + fVPos.SetM(m); + } + void setNegativeLegPtEtaPhiM(float pt, float eta, float phi, float m) + { + fVNeg.SetPt(pt); + fVNeg.SetEta(eta); + fVNeg.SetPhi(phi); + fVNeg.SetM(m); + } + + ROOT::Math::PtEtaPhiMVector getPositiveLeg() const { return fVPos; } + ROOT::Math::PtEtaPhiMVector getNegativeLeg() const { return fVNeg; } + + void setGlobalPosId(int id) { fGlobalPosId = id; } + void setGlobalNegId(int id) { fGlobalNegId = id; } + int globalIndexPos() const { return fGlobalPosId; } + int globalIndexNeg() const { return fGlobalNegId; } + + void setAmbPosLegSelfIds(std::vector selfIds) { fAmbPosLegSelfIds = selfIds; } + void setAmbNegLegSelfIds(std::vector selfIds) { fAmbNegLegSelfIds = selfIds; } + std::vector ambiguousPosLegIds() const { return fAmbPosLegSelfIds; } + std::vector ambiguousNegLegIds() const { return fAmbNegLegSelfIds; } + + protected: + int fDFId; + int fGlobalId; + int fCollisionId; + int fTrackId; + float fPt; + float fEta; + float fPhi; + float fMass; + int8_t fCharge; + float fDCAxy; + float fDCAz; + float fPairDCA3DinSigmaOTF; + bool fIsAmbiguous; + std::vector fAmbEleSelfIds; + + int fGlobalPosId; + int fGlobalNegId; + ROOT::Math::PtEtaPhiMVector fVPos; + ROOT::Math::PtEtaPhiMVector fVNeg; + std::vector fAmbPosLegSelfIds; // for dileptons + std::vector fAmbNegLegSelfIds; // for dileptons + + // only for photon conversion point + float fVx; + float fVy; + float fVz; +}; + +class EMTrackWithCov : public EMTrack +{ + public: + EMTrackWithCov(int dfId, int globalId, int collisionId, int trackId, float pt, float eta, float phi, float mass, int8_t charge = 0, float dcaXY = 0.f, float dcaZ = 0.f, std::vector amb_ele_self_ids = {}, + float X = 0.f, float Y = 0.f, float Z = 0.f, float Alpha = 0.f, float Snp = 0.f, float Tgl = 0.f, + float CYY = 0.f, float CZY = 0.f, float CZZ = 0.f, + float CSnpY = 0.f, float CSnpZ = 0.f, float CSnpSnp = 0.f, + float CTglY = 0.f, float CTglZ = 0.f, float CTglSnp = 0.f, float CTglTgl = 0.f, + float C1PtY = 0.f, float C1PtZ = 0.f, float C1PtSnp = 0.f, float C1PtTgl = 0.f, float C1Pt21Pt2 = 0.f) : EMTrack(dfId, globalId, collisionId, trackId, pt, eta, phi, mass, charge, dcaXY, dcaZ, amb_ele_self_ids) + { + fX = X; + fY = Y; + fZ = Z; + fAlpha = Alpha; + fSnp = Snp; + fTgl = Tgl; + fCYY = CYY; + fCZY = CZY; + fCZZ = CZZ; + fCSnpY = CSnpY; + fCSnpZ = CSnpZ; + fCSnpSnp = CSnpSnp; + fCTglY = CTglY; + fCTglZ = CTglZ; + fCTglSnp = CTglSnp; + fCTglTgl = CTglTgl; + fC1PtY = C1PtY; + fC1PtZ = C1PtZ; + fC1PtSnp = C1PtSnp; + fC1PtTgl = C1PtTgl; + fC1Pt21Pt2 = C1Pt21Pt2; + } + + float x() const { return fX; } + float y() const { return fY; } + float z() const { return fZ; } + float alpha() const { return fAlpha; } + float snp() const { return fSnp; } + float tgl() const { return fTgl; } + + float cYY() const { return fCYY; } + float cZY() const { return fCZY; } + float cZZ() const { return fCZZ; } + float cSnpY() const { return fCSnpY; } + float cSnpZ() const { return fCSnpZ; } + float cSnpSnp() const { return fCSnpSnp; } + float cTglY() const { return fCTglY; } + float cTglZ() const { return fCTglZ; } + float cTglSnp() const { return fCTglSnp; } + float cTglTgl() const { return fCTglTgl; } + float c1PtY() const { return fC1PtY; } + float c1PtZ() const { return fC1PtZ; } + float c1PtSnp() const { return fC1PtSnp; } + float c1PtTgl() const { return fC1PtTgl; } + float c1Pt21Pt2() const { return fC1Pt21Pt2; } + + void setCYY(float cYY) { fCYY = cYY; } + void setCZY(float cZY) { fCZY = cZY; } + void setCZZ(float cZZ) { fCZZ = cZZ; } + + protected: + float fX; + float fY; + float fZ; + float fAlpha; + float fSnp; + float fTgl; + float fCYY; + float fCZY; + float fCZZ; + float fCSnpY; + float fCSnpZ; + float fCSnpSnp; + float fCTglY; + float fCTglZ; + float fCTglSnp; + float fCTglTgl; + float fC1PtY; + float fC1PtZ; + float fC1PtSnp; + float fC1PtTgl; + float fC1Pt21Pt2; +}; + +} // namespace o2::aod::pwgem::dilepton::utils +#endif // PWGEM_DILEPTON_UTILS_EMTRACK_H_ diff --git a/PWGEM/Dilepton/Utils/EMTrackUtilities.h b/PWGEM/Dilepton/Utils/EMTrackUtilities.h new file mode 100644 index 00000000000..6ac2275aee1 --- /dev/null +++ b/PWGEM/Dilepton/Utils/EMTrackUtilities.h @@ -0,0 +1,150 @@ +// 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. + +/// \commonly used to calculate track variables +/// \author daiki.sekihata@cern.ch + +#ifndef PWGEM_DILEPTON_UTILS_EMTRACKUTILITIES_H_ +#define PWGEM_DILEPTON_UTILS_EMTRACKUTILITIES_H_ + +#include +#include +#include +#include + +//_______________________________________________________________________ +namespace o2::aod::pwgem::dilepton::utils::emtrackutil +{ +//_______________________________________________________________________ +template +float dca3DinSigma(T const& track) +{ + float cYY = track.cYY(); + float cZZ = track.cZZ(); + float cZY = track.cZY(); + float dcaXY = track.dcaXY(); // in cm + float dcaZ = track.dcaZ(); // in cm + + float det = cYY * cZZ - cZY * cZY; // determinant + if (det < 0) { + return 999.f; + } else { + return std::sqrt(std::fabs((dcaXY * dcaXY * cZZ + dcaZ * dcaZ * cYY - 2. * dcaXY * dcaZ * cZY) / det / 2.)); // dca 3d in sigma + } +} +//_______________________________________________________________________ +template +float sigmaDca3D(T const& track) +{ + float dcaXY = track.dcaXY(); // in cm + float dcaZ = track.dcaZ(); // in cm + float dca3d = std::sqrt(dcaXY * dcaXY + dcaZ * dcaZ); // in cm + return dca3d / dca3DinSigma(track); +} +//_______________________________________________________________________ +template +float dcaXYinSigma(T const& track) +{ + return track.dcaXY() / std::sqrt(track.cYY()); +} +//_______________________________________________________________________ +template +float dcaZinSigma(T const& track) +{ + return track.dcaZ() / std::sqrt(track.cZZ()); +} +//_______________________________________________________________________ +template +float fwdDcaXYinSigma(T const& track) +{ + float cXX = track.cXXatDCA(); // in cm^2 + float cYY = track.cYYatDCA(); // in cm^2 + float cXY = track.cXYatDCA(); // in cm^2 + float dcaX = track.fwdDcaX(); // in cm + float dcaY = track.fwdDcaY(); // in cm + float det = cXX * cYY - cXY * cXY; // determinant + + if (det < 0) { + return 999.f; + } else { + return std::sqrt(std::fabs((dcaX * dcaX * cYY + dcaY * dcaY * cXX - 2. * dcaX * dcaY * cXY) / det / 2.)); // dca xy in sigma + } +} +//_______________________________________________________________________ +template +float sigmaFwdDcaXY(T const& track) +{ + float dcaX = track.fwdDcaX(); // in cm + float dcaY = track.fwdDcaY(); // in cm + float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); // in cm + return dcaXY / fwdDcaXYinSigma(track); +} +//_______________________________________________________________________ +template +bool isBestMatch(TTrack const& track, TCut const& cut, TTracks const& tracks) +{ + // this is only for muon at forward rapidity + if (track.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + std::map map_chi2MCHMFT; + map_chi2MCHMFT[track.globalIndex()] = track.chi2MatchMCHMFT(); // add myself + for (const auto& glmuonId : track.globalMuonsWithSameMFTIds()) { + const auto& candidate = tracks.rawIteratorAt(glmuonId); + if (candidate.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + if (cut.template IsSelectedTrack(candidate)) { + map_chi2MCHMFT[candidate.globalIndex()] = candidate.chi2MatchMCHMFT(); + } + } + } + if (map_chi2MCHMFT.begin()->first == track.globalIndex()) { // search for minimum matching-chi2 + map_chi2MCHMFT.clear(); + return true; + } else { + map_chi2MCHMFT.clear(); + return false; + } + } else { + return true; + } +} +//_______________________________________________________________________ +template +float sigmaPt(T const& track) +{ + return std::sqrt(track.c1Pt21Pt2()) / std::pow(track.signed1Pt(), 2); // pT resolution +} +//_______________________________________________________________________ +template +float sigmaPhi(T const& track) +{ + return std::sqrt(track.cSnpSnp()) / std::sqrt(1.f - std::pow(track.snp(), 2)); // phi resolution +} +//_______________________________________________________________________ +template +float sigmaTheta(T const& track) +{ + return std::sqrt(track.cTglTgl()) / (1.f + std::pow(track.tgl(), 2)); // theta resolution = lambda resolution. // lambda = pi/2 - theta. theta is polar angle. +} +//_______________________________________________________________________ +template +float sigmaEta(T const& track) +{ + return std::sqrt(track.cTglTgl()) / std::sqrt(1.f + std::pow(track.tgl(), 2)); +} +//_______________________________________________________________________ +template +float sigmaP(T const& track) +{ + // p = 1/1/pT x 1/cos(lambda); + return std::sqrt(std::pow(1.f / track.signed1Pt(), 4) * ((1.f + std::pow(track.tgl(), 2)) * track.c1Pt21Pt2() + 1.f / (1.f + std::pow(track.tgl(), 2)) * std::pow(track.signed1Pt() * track.tgl(), 2) * track.cTglTgl() - 2.f * track.signed1Pt() * track.tgl() * track.c1PtTgl())); +} +//_______________________________________________________________________ +} // namespace o2::aod::pwgem::dilepton::utils::emtrackutil +#endif // PWGEM_DILEPTON_UTILS_EMTRACKUTILITIES_H_ diff --git a/PWGEM/Dilepton/Utils/EventHistograms.h b/PWGEM/Dilepton/Utils/EventHistograms.h new file mode 100644 index 00000000000..7c1d2fe687e --- /dev/null +++ b/PWGEM/Dilepton/Utils/EventHistograms.h @@ -0,0 +1,286 @@ +// 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. + +/// \header file for histograms +/// \author daiki.sekihata@cern.ch + +#ifndef PWGEM_DILEPTON_UTILS_EVENTHISTOGRAMS_H_ +#define PWGEM_DILEPTON_UTILS_EVENTHISTOGRAMS_H_ +using namespace o2::framework; + +namespace o2::aod::pwgem::dilepton::utils::eventhistogram +{ +const int nbin_ev = 21; +template +void addEventHistograms(HistogramRegistry* fRegistry) +{ + // event info + auto hCollisionCounter = fRegistry->add("Event/before/hCollisionCounter", "collision counter;;Number of events", kTH1D, {{nbin_ev, 0.5, nbin_ev + 0.5}}, false); + hCollisionCounter->GetXaxis()->SetBinLabel(1, "all"); + hCollisionCounter->GetXaxis()->SetBinLabel(2, "FT0AND"); + hCollisionCounter->GetXaxis()->SetBinLabel(3, "No TF border"); + hCollisionCounter->GetXaxis()->SetBinLabel(4, "No ITS ROF border"); + hCollisionCounter->GetXaxis()->SetBinLabel(5, "No Same Bunch Pileup"); + hCollisionCounter->GetXaxis()->SetBinLabel(6, "Is Good Zvtx FT0vsPV"); + hCollisionCounter->GetXaxis()->SetBinLabel(7, "Is Vertex ITS-TPC"); + hCollisionCounter->GetXaxis()->SetBinLabel(8, "Is Vertex ITS-TPC-TRD"); + hCollisionCounter->GetXaxis()->SetBinLabel(9, "Is Vertex ITS-TPC-TOF"); + hCollisionCounter->GetXaxis()->SetBinLabel(10, "sel8"); + hCollisionCounter->GetXaxis()->SetBinLabel(11, "|Z_{vtx}| < 10 cm"); + hCollisionCounter->GetXaxis()->SetBinLabel(12, "NoCollInTimeRangeStandard"); + hCollisionCounter->GetXaxis()->SetBinLabel(13, "NoCollInTimeRangeStrict"); + hCollisionCounter->GetXaxis()->SetBinLabel(14, "NoCollInRofStandard"); + hCollisionCounter->GetXaxis()->SetBinLabel(15, "NoCollInRofStrict"); + hCollisionCounter->GetXaxis()->SetBinLabel(16, "NoHighMultCollInPrevRof"); + hCollisionCounter->GetXaxis()->SetBinLabel(17, "IsGoodITSLayer3"); + hCollisionCounter->GetXaxis()->SetBinLabel(18, "IsGoodITSLayer0123"); + hCollisionCounter->GetXaxis()->SetBinLabel(19, "IsGoodITSLayersAll"); + hCollisionCounter->GetXaxis()->SetBinLabel(20, "Calibrated Q vector"); + hCollisionCounter->GetXaxis()->SetBinLabel(21, "accepted"); + + fRegistry->add("Event/before/hZvtx", "vertex z; Z_{vtx} (cm)", kTH1F, {{100, -50, +50}}, false); + fRegistry->add("Event/before/hMultNTracksPV", "hMultNTracksPV; N_{track} to PV", kTH1F, {{6001, -0.5, 6000.5}}, false); + fRegistry->add("Event/before/hMultNTracksPVeta1", "hMultNTracksPVeta1; N_{track} to PV", kTH1F, {{6001, -0.5, 6000.5}}, false); + fRegistry->add("Event/before/hMultFT0", "hMultFT0;mult. FT0A;mult. FT0C", kTH2F, {{200, 0, 200000}, {60, 0, 60000}}, false); + fRegistry->add("Event/before/hCentFT0A", "hCentFT0A;centrality FT0A (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry->add("Event/before/hCentFT0C", "hCentFT0C;centrality FT0C (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry->add("Event/before/hCentFT0M", "hCentFT0M;centrality FT0M (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry->add("Event/before/hCentFT0A_HMpp", "hCentFT0A for HM pp;centrality FT0A (%)", kTH1F, {{100, 0, 1}}, false); + fRegistry->add("Event/before/hCentFT0C_HMpp", "hCentFT0C for HM pp;centrality FT0C (%)", kTH1F, {{100, 0, 1}}, false); + fRegistry->add("Event/before/hCentFT0M_HMpp", "hCentFT0M for HM pp;centrality FT0M (%)", kTH1F, {{100, 0, 1}}, false); + fRegistry->add("Event/before/hCentFT0CvsMultNTracksPV", "hCentFT0CvsMultNTracksPV;centrality FT0C (%);N_{track} to PV", kTH2F, {{110, 0, 110}, {600, 0, 6000}}, false); + fRegistry->add("Event/before/hMultFT0CvsMultNTracksPV", "hMultFT0CvsMultNTracksPV;mult. FT0C;N_{track} to PV", kTH2F, {{60, 0, 60000}, {600, 0, 6000}}, false); + fRegistry->add("Event/before/hMultFT0CvsOccupancy", "hMultFT0CvsOccupancy;mult. FT0C;N_{track} in time range", kTH2F, {{60, 0, 60000}, {200, 0, 20000}}, false); + fRegistry->add("Event/before/hNTracksPVvsOccupancy", "hNTracksPVvsOccupancy;N_{track} to PV;N_{track} in time range", kTH2F, {{600, 0, 6000}, {200, 0, 20000}}, false); + fRegistry->add("Event/before/hCorrOccupancy", "occupancy correlation;FT0C occupancy;track occupancy", kTH2F, {{200, 0, 200000}, {200, 0, 20000}}, false); + + if constexpr (nmod == 2) { // Q2 + fRegistry->add("Event/before/hQ2xFT0M_CentFT0C", "hQ2xFT0M_CentFT0C;centrality FT0C (%);Q_{2,x}^{FT0M}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2yFT0M_CentFT0C", "hQ2yFT0M_CentFT0C;centrality FT0C (%);Q_{2,y}^{FT0M}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2xFT0A_CentFT0C", "hQ2xFT0A_CentFT0C;centrality FT0C (%);Q_{2,x}^{FT0A}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2yFT0A_CentFT0C", "hQ2yFT0A_CentFT0C;centrality FT0C (%);Q_{2,y}^{FT0A}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2xFT0C_CentFT0C", "hQ2xFT0C_CentFT0C;centrality FT0C (%);Q_{2,x}^{FT0C}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2yFT0C_CentFT0C", "hQ2yFT0C_CentFT0C;centrality FT0C (%);Q_{2,y}^{FT0C}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2xBPos_CentFT0C", "hQ2xBPos_CentFT0C;centrality FT0C (%);Q_{2,x}^{BPos}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2yBPos_CentFT0C", "hQ2yBPos_CentFT0C;centrality FT0C (%);Q_{2,y}^{BPos}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2xBNeg_CentFT0C", "hQ2xBNeg_CentFT0C;centrality FT0C (%);Q_{2,x}^{BNeg}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2yBNeg_CentFT0C", "hQ2yBNeg_CentFT0C;centrality FT0C (%);Q_{2,y}^{BNeg}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2xBTot_CentFT0C", "hQ2xBTot_CentFT0C;centrality FT0C (%);Q_{2,x}^{BTot}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2yBTot_CentFT0C", "hQ2yBTot_CentFT0C;centrality FT0C (%);Q_{2,y}^{BTot}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + + fRegistry->add("Event/before/hEP2FT0M_CentFT0C", "2nd harmonics event plane FT0M;centrality FT0C (%);#Psi_{2}^{FT0M} (rad.)", kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + fRegistry->add("Event/before/hEP2FT0A_CentFT0C", "2nd harmonics event plane FT0A;centrality FT0C (%);#Psi_{2}^{FT0A} (rad.)", kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + fRegistry->add("Event/before/hEP2FT0C_CentFT0C", "2nd harmonics event plane FT0C;centrality FT0C (%);#Psi_{2}^{FT0C} (rad.)", kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + fRegistry->add("Event/before/hEP2BPos_CentFT0C", "2nd harmonics event plane BPos;centrality FT0C (%);#Psi_{2}^{BPos} (rad.)", kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + fRegistry->add("Event/before/hEP2BNeg_CentFT0C", "2nd harmonics event plane BNeg;centrality FT0C (%);#Psi_{2}^{BNeg} (rad.)", kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + fRegistry->add("Event/before/hEP2BTot_CentFT0C", "2nd harmonics event plane BTot;centrality FT0C (%);#Psi_{2}^{BTot} (rad.)", kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + + fRegistry->add("Event/before/hPrfQ2FT0MQ2BPos_CentFT0C", "Q_{2}^{FT0M} #upoint Q_{2}^{BPos};centrality FT0C (%);Q_{2}^{FT0M} #upoint Q_{2}^{BPos}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ2FT0MQ2BNeg_CentFT0C", "Q_{2}^{FT0M} #upoint Q_{2}^{BNeg};centrality FT0C (%);Q_{2}^{FT0M} #upoint Q_{2}^{BNeg}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ2BPosQ2BNeg_CentFT0C", "Q_{2}^{BPos} #upoint Q_{2}^{BNeg};centrality FT0C (%);Q_{2}^{BPos} #upoint Q_{2}^{BNeg}", kTProfile, {{100, 0, 100}}, false); // this is common for FT0M, FT0A, FT0C, FV0A resolution. + fRegistry->add("Event/before/hPrfQ2FT0CQ2BPos_CentFT0C", "Q_{2}^{FT0C} #upoint Q_{2}^{BPos};centrality FT0C (%);Q_{2}^{FT0C} #upoint Q_{2}^{BPos}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ2FT0CQ2BNeg_CentFT0C", "Q_{2}^{FT0C} #upoint Q_{2}^{BNeg};centrality FT0C (%);Q_{2}^{FT0C} #upoint Q_{2}^{BNeg}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ2FT0CQ2BTot_CentFT0C", "Q_{2}^{FT0C} #upoint Q_{2}^{BTot};centrality FT0C (%);Q_{2}^{FT0C} #upoint Q_{2}^{BTot}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ2FT0AQ2BPos_CentFT0C", "Q_{2}^{FT0A} #upoint Q_{2}^{BPos};centrality FT0C (%);Q_{2}^{FT0A} #upoint Q_{2}^{BPos}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ2FT0AQ2BNeg_CentFT0C", "Q_{2}^{FT0A} #upoint Q_{2}^{BNeg};centrality FT0C (%);Q_{2}^{FT0A} #upoint Q_{2}^{BNeg}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ2FT0AQ2BTot_CentFT0C", "Q_{2}^{FT0A} #upoint Q_{2}^{BTot};centrality FT0C (%);Q_{2}^{FT0A} #upoint Q_{2}^{BTot}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ2FT0AQ2FT0C_CentFT0C", "Q_{2}^{FT0A} #upoint Q_{2}^{FT0C};centrality FT0C (%);Q_{2}^{FT0A} #upoint Q_{2}^{FT0C}", kTProfile, {{100, 0, 100}}, false); // this is necessary for dimuons + } else if constexpr (nmod == 3) { // Q3 + fRegistry->add("Event/before/hQ3xFT0M_CentFT0C", "hQ3xFT0M_CentFT0C;centrality FT0C (%);Q_{3,x}^{FT0M}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3yFT0M_CentFT0C", "hQ3yFT0M_CentFT0C;centrality FT0C (%);Q_{3,y}^{FT0M}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3xFT0A_CentFT0C", "hQ3xFT0A_CentFT0C;centrality FT0C (%);Q_{3,x}^{FT0A}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3yFT0A_CentFT0C", "hQ3yFT0A_CentFT0C;centrality FT0C (%);Q_{3,y}^{FT0A}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3xFT0C_CentFT0C", "hQ3xFT0C_CentFT0C;centrality FT0C (%);Q_{3,x}^{FT0C}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3yFT0C_CentFT0C", "hQ3yFT0C_CentFT0C;centrality FT0C (%);Q_{3,y}^{FT0C}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3xBPos_CentFT0C", "hQ3xBPos_CentFT0C;centrality FT0C (%);Q_{3,x}^{BPos}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3yBPos_CentFT0C", "hQ3yBPos_CentFT0C;centrality FT0C (%);Q_{3,y}^{BPos}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3xBNeg_CentFT0C", "hQ3xBNeg_CentFT0C;centrality FT0C (%);Q_{3,x}^{BNeg}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3yBNeg_CentFT0C", "hQ3yBNeg_CentFT0C;centrality FT0C (%);Q_{3,y}^{BNeg}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3xBTot_CentFT0C", "hQ3xBTot_CentFT0C;centrality FT0C (%);Q_{3,x}^{BTot}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3yBTot_CentFT0C", "hQ3yBTot_CentFT0C;centrality FT0C (%);Q_{3,y}^{BTot}", kTH2F, {{100, 0, 100}, {200, -10, +10}}, false); + + fRegistry->add("Event/before/hEP3FT0M_CentFT0C", "3rd harmonics event plane FT0M;centrality FT0C (%);#Psi_{3}^{FT0M} (rad.)", kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + fRegistry->add("Event/before/hEP3FT0A_CentFT0C", "3rd harmonics event plane FT0A;centrality FT0C (%);#Psi_{3}^{FT0A} (rad.)", kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + fRegistry->add("Event/before/hEP3FT0C_CentFT0C", "3rd harmonics event plane FT0C;centrality FT0C (%);#Psi_{3}^{FT0C} (rad.)", kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + fRegistry->add("Event/before/hEP3BPos_CentFT0C", "3rd harmonics event plane BPos;centrality FT0C (%);#Psi_{3}^{BPos} (rad.)", kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + fRegistry->add("Event/before/hEP3BNeg_CentFT0C", "3rd harmonics event plane BNeg;centrality FT0C (%);#Psi_{3}^{BNeg} (rad.)", kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + fRegistry->add("Event/before/hEP3BTot_CentFT0C", "3rd harmonics event plane BTot;centrality FT0C (%);#Psi_{3}^{BTot} (rad.)", kTH2F, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + + fRegistry->add("Event/before/hPrfQ3FT0MQ3BPos_CentFT0C", "Q_{3}^{FT0M} #upoint Q_{3}^{BPos};centrality FT0C (%);Q_{3}^{FT0M} #upoint Q_{3}^{BPos}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ3FT0MQ3BNeg_CentFT0C", "Q_{3}^{FT0M} #upoint Q_{3}^{BNeg};centrality FT0C (%);Q_{3}^{FT0M} #upoint Q_{3}^{BNeg}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ3BPosQ3BNeg_CentFT0C", "Q_{3}^{BPos} #upoint Q_{3}^{BNeg};centrality FT0C (%);Q_{3}^{BPos} #upoint Q_{3}^{BNeg}", kTProfile, {{100, 0, 100}}, false); // this is common for FT0M, FT0A, FT0C, FV0A resolution. + fRegistry->add("Event/before/hPrfQ3FT0CQ3BPos_CentFT0C", "Q_{3}^{FT0C} #upoint Q_{3}^{BPos};centrality FT0C (%);Q_{3}^{FT0C} #upoint Q_{3}^{BPos}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ3FT0CQ3BNeg_CentFT0C", "Q_{3}^{FT0C} #upoint Q_{3}^{BNeg};centrality FT0C (%);Q_{3}^{FT0C} #upoint Q_{3}^{BNeg}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ3FT0CQ3BTot_CentFT0C", "Q_{3}^{FT0C} #upoint Q_{3}^{BTot};centrality FT0C (%);Q_{3}^{FT0C} #upoint Q_{3}^{BTot}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ3FT0AQ3BPos_CentFT0C", "Q_{3}^{FT0A} #upoint Q_{3}^{BPos};centrality FT0C (%);Q_{3}^{FT0A} #upoint Q_{3}^{BPos}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ3FT0AQ3BNeg_CentFT0C", "Q_{3}^{FT0A} #upoint Q_{3}^{BNeg};centrality FT0C (%);Q_{3}^{FT0A} #upoint Q_{3}^{BNeg}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ3FT0AQ3BTot_CentFT0C", "Q_{3}^{FT0A} #upoint Q_{3}^{BTot};centrality FT0C (%);Q_{3}^{FT0A} #upoint Q_{3}^{BTot}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ3FT0AQ3FT0C_CentFT0C", "Q_{3}^{FT0A} #upoint Q_{3}^{FT0C};centrality FT0C (%);Q_{3}^{FT0A} #upoint Q_{3}^{FT0C}", kTProfile, {{100, 0, 100}}, false); // this is necessary for dimuons + } + fRegistry->addClone("Event/before/", "Event/after/"); +} + +template +void fillEventInfo(HistogramRegistry* fRegistry, TCollision const& collision, const float /*weight*/ = 1.f) +{ + static constexpr std::string_view event_types[2] = {"before/", "after/"}; + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 1.0); + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 2.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 3.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 4.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 5.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 6.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 7.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 8.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 9.0); + } + if (collision.sel8()) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 10.0); + } + if (abs(collision.posZ()) < 10.0) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 11.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 12.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 13.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 14.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 15.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 16.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer3)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 17.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 18.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 19.0); + } + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hZvtx"), collision.posZ()); + + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultNTracksPV"), collision.multNTracksPV()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultNTracksPVeta1"), collision.multNTracksPVeta1()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0"), collision.multFT0A(), collision.multFT0C()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0A"), collision.centFT0A()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0C"), collision.centFT0C()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0M"), collision.centFT0M()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0A_HMpp"), collision.centFT0A()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0C_HMpp"), collision.centFT0C()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0M_HMpp"), collision.centFT0M()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0CvsMultNTracksPV"), collision.centFT0C(), collision.multNTracksPV()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0CvsMultNTracksPV"), collision.multFT0C(), collision.multNTracksPV()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0CvsOccupancy"), collision.multFT0C(), collision.trackOccupancyInTimeRange()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hNTracksPVvsOccupancy"), collision.multNTracksPV(), collision.trackOccupancyInTimeRange()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCorrOccupancy"), collision.ft0cOccupancyInTimeRange(), collision.trackOccupancyInTimeRange()); + + if constexpr (nmod == 2) { // Q2 + std::array q2ft0m = {collision.q2xft0m(), collision.q2yft0m()}; + std::array q2ft0a = {collision.q2xft0a(), collision.q2yft0a()}; + std::array q2ft0c = {collision.q2xft0c(), collision.q2yft0c()}; + std::array q2bpos = {collision.q2xbpos(), collision.q2ybpos()}; + std::array q2bneg = {collision.q2xbneg(), collision.q2ybneg()}; + std::array q2btot = {collision.q2xbtot(), collision.q2ybtot()}; + + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ2xFT0M_CentFT0C"), collision.centFT0C(), collision.q2xft0m()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ2yFT0M_CentFT0C"), collision.centFT0C(), collision.q2yft0m()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ2xFT0A_CentFT0C"), collision.centFT0C(), collision.q2xft0a()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ2yFT0A_CentFT0C"), collision.centFT0C(), collision.q2yft0a()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ2xFT0C_CentFT0C"), collision.centFT0C(), collision.q2xft0c()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ2yFT0C_CentFT0C"), collision.centFT0C(), collision.q2yft0c()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ2xBPos_CentFT0C"), collision.centFT0C(), collision.q2xbpos()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ2yBPos_CentFT0C"), collision.centFT0C(), collision.q2ybpos()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ2xBNeg_CentFT0C"), collision.centFT0C(), collision.q2xbneg()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ2yBNeg_CentFT0C"), collision.centFT0C(), collision.q2ybneg()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ2xBTot_CentFT0C"), collision.centFT0C(), collision.q2xbtot()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ2yBTot_CentFT0C"), collision.centFT0C(), collision.q2ybtot()); + + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP2FT0M_CentFT0C"), collision.centFT0C(), collision.ep2ft0m()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP2FT0A_CentFT0C"), collision.centFT0C(), collision.ep2ft0a()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP2FT0C_CentFT0C"), collision.centFT0C(), collision.ep2ft0c()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP2BPos_CentFT0C"), collision.centFT0C(), collision.ep2bpos()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP2BNeg_CentFT0C"), collision.centFT0C(), collision.ep2bneg()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP2BTot_CentFT0C"), collision.centFT0C(), collision.ep2btot()); + + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ2FT0MQ2BPos_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q2ft0m, q2bpos)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ2FT0MQ2BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q2ft0m, q2bneg)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ2BPosQ2BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q2bpos, q2bneg)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ2FT0AQ2BPos_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q2ft0a, q2bpos)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ2FT0AQ2BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q2ft0a, q2bneg)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ2FT0AQ2BTot_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q2ft0a, q2btot)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ2FT0CQ2BPos_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q2ft0c, q2bpos)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ2FT0CQ2BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q2ft0c, q2bneg)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ2FT0CQ2BTot_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q2ft0c, q2btot)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ2FT0AQ2FT0C_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q2ft0a, q2ft0c)); + } else if constexpr (nmod == 3) { // Q3 + std::array q3ft0m = {collision.q3xft0m(), collision.q3yft0m()}; + std::array q3ft0a = {collision.q3xft0a(), collision.q3yft0a()}; + std::array q3ft0c = {collision.q3xft0c(), collision.q3yft0c()}; + std::array q3bpos = {collision.q3xbpos(), collision.q3ybpos()}; + std::array q3bneg = {collision.q3xbneg(), collision.q3ybneg()}; + std::array q3btot = {collision.q3xbtot(), collision.q3ybtot()}; + + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ3xFT0M_CentFT0C"), collision.centFT0C(), collision.q3xft0m()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ3yFT0M_CentFT0C"), collision.centFT0C(), collision.q3yft0m()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ3xFT0A_CentFT0C"), collision.centFT0C(), collision.q3xft0a()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ3yFT0A_CentFT0C"), collision.centFT0C(), collision.q3yft0a()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ3xFT0C_CentFT0C"), collision.centFT0C(), collision.q3xft0c()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ3yFT0C_CentFT0C"), collision.centFT0C(), collision.q3yft0c()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ3xBPos_CentFT0C"), collision.centFT0C(), collision.q3xbpos()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ3yBPos_CentFT0C"), collision.centFT0C(), collision.q3ybpos()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ3xBNeg_CentFT0C"), collision.centFT0C(), collision.q3xbneg()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ3yBNeg_CentFT0C"), collision.centFT0C(), collision.q3ybneg()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ3xBTot_CentFT0C"), collision.centFT0C(), collision.q3xbtot()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ3yBTot_CentFT0C"), collision.centFT0C(), collision.q3ybtot()); + + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP3FT0M_CentFT0C"), collision.centFT0C(), collision.ep3ft0m()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP3FT0A_CentFT0C"), collision.centFT0C(), collision.ep3ft0a()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP3FT0C_CentFT0C"), collision.centFT0C(), collision.ep3ft0c()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP3BPos_CentFT0C"), collision.centFT0C(), collision.ep3bpos()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP3BNeg_CentFT0C"), collision.centFT0C(), collision.ep3bneg()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP3BTot_CentFT0C"), collision.centFT0C(), collision.ep3btot()); + + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ3FT0MQ3BPos_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q3ft0m, q3bpos)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ3FT0MQ3BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q3ft0m, q3bneg)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ3BPosQ3BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q3bpos, q3bneg)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ3FT0AQ3BPos_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q3ft0a, q3bpos)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ3FT0AQ3BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q3ft0a, q3bneg)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ3FT0AQ3BTot_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q3ft0a, q3btot)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ3FT0CQ3BPos_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q3ft0c, q3bpos)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ3FT0CQ3BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q3ft0c, q3bneg)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ3FT0CQ3BTot_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q3ft0c, q3btot)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ3FT0AQ3FT0C_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q3ft0a, q3ft0c)); + } +} +} // namespace o2::aod::pwgem::dilepton::utils::eventhistogram +#endif // PWGEM_DILEPTON_UTILS_EVENTHISTOGRAMS_H_ diff --git a/PWGEM/Dilepton/Utils/EventMixingHandler.h b/PWGEM/Dilepton/Utils/EventMixingHandler.h new file mode 100644 index 00000000000..1fa83c60240 --- /dev/null +++ b/PWGEM/Dilepton/Utils/EventMixingHandler.h @@ -0,0 +1,77 @@ +// 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. + +/// \event mixing handler +/// \author daiki.sekihata@cern.ch + +#ifndef PWGEM_DILEPTON_UTILS_EVENTMIXINGHANDLER_H_ +#define PWGEM_DILEPTON_UTILS_EVENTMIXINGHANDLER_H_ + +#include +#include +#include + +namespace o2::aod::pwgem::dilepton::utils +{ +template +class EventMixingHandler +{ + public: + EventMixingHandler() + { + fNdepth = 0; + fMapMixBins.clear(); + fMap_Tracks_per_collision.clear(); + } + + explicit EventMixingHandler(int ndepth) + { + fNdepth = ndepth; + fMapMixBins.clear(); + fMap_Tracks_per_collision.clear(); + } + + ~EventMixingHandler() + { + fMapMixBins.clear(); + fMap_Tracks_per_collision.clear(); + } + + void SetNdepth(int ndepth) { fNdepth = ndepth; } + + void AddTrackToEventPool(U key_df_collision, V obj) + { + fMap_Tracks_per_collision[key_df_collision].emplace_back(obj); + } + + std::vector GetCollisionIdsFromEventPool(T key_bin) { return fMapMixBins[key_bin]; } + std::vector GetTracksPerCollision(T key_bin, int index) { return fMap_Tracks_per_collision[fMapMixBins[key_bin][index]]; } + std::vector GetTracksPerCollision(U key_df_collision) { return fMap_Tracks_per_collision[key_df_collision]; } + + // call this function at the end of collision loop + void AddCollisionIdAtLast(T key_bin, U key_df_collision) + { + // LOGF(info, "fMapMixBins[key_bin].size() = %d", fMapMixBins[key_bin].size()); + if (static_cast(fMapMixBins[key_bin].size()) >= fNdepth) { + fMap_Tracks_per_collision[fMapMixBins[key_bin][0]].clear(); + fMap_Tracks_per_collision[fMapMixBins[key_bin][0]].shrink_to_fit(); + fMapMixBins[key_bin].erase(fMapMixBins[key_bin].begin()); + } + fMapMixBins[key_bin].emplace_back(key_df_collision); + } + + private: + int fNdepth; // depth of event mixing + std::map> fMapMixBins; // map : e.g. -> pair + std::map> fMap_Tracks_per_collision; // map : e.g. pair -> track array +}; +} // namespace o2::aod::pwgem::dilepton::utils +#endif // PWGEM_DILEPTON_UTILS_EVENTMIXINGHANDLER_H_ diff --git a/PWGEM/Dilepton/Utils/MCUtilities.h b/PWGEM/Dilepton/Utils/MCUtilities.h index a4cdb572dce..58484f6fe66 100644 --- a/PWGEM/Dilepton/Utils/MCUtilities.h +++ b/PWGEM/Dilepton/Utils/MCUtilities.h @@ -20,7 +20,7 @@ #include //_______________________________________________________________________ -namespace o2::aod::pwgem::dilepton::mcutil +namespace o2::aod::pwgem::dilepton::utils::mcutil { enum class EM_HFeeType : int { kUndef = -1, @@ -31,6 +31,204 @@ enum class EM_HFeeType : int { kBCe_Be_DiffB = 4, // LS }; +//_______________________________________________________________________ +template +int hasFakeMatchITSTPC(TTrack const& track) +{ + // track and mctracklabel have to be joined. + // bit 13 -- ITS/TPC labels are not equal + + if ((track.mcMask() & 1 << 13)) { + return true; + } else { + return false; + } +} +//_______________________________________________________________________ +template +int hasFakeMatchITSTPCTOF(TTrack const&) +{ + // track and mctracklabel have to be joined. + return false; + // if ((track.mcMask() & 1 << 13) && (track.mcMask() & 1 << 15)) { + // return true; + // } else { + // return false; + // } +} +//_______________________________________________________________________ +template +int hasFakeMatchMFTMCH(TTrack const& track) +{ + // fwdtrack and mcfwdtracklabel have to be joined. + if ((track.mcMask() & 1 << 7)) { + return true; + } else { + return false; + } +} +//_______________________________________________________________________ +template +int FindCommonMotherFrom2ProngsWithoutPDG(TMCParticle1 const& p1, TMCParticle2 const& p2) +{ + if (p1.globalIndex() == p2.globalIndex()) + return -1; // mc particle p1 and p2 is identical. reject. + + if (!p1.has_mothers()) + return -1; + if (!p2.has_mothers()) + return -1; + + // LOGF(info,"original motherid1 = %d , motherid2 = %d", p1.mothersIds()[0], p2.mothersIds()[0]); + + int motherid1 = p1.mothersIds()[0]; + int motherid2 = p2.mothersIds()[0]; + + // LOGF(info,"motherid1 = %d , motherid2 = %d", motherid1, motherid2); + + if (motherid1 != motherid2) + return -1; + return motherid1; +} +//_______________________________________________________________________ +template +int FindCommonMotherFrom3ProngsWithoutPDG(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticle3 const& p3) +{ + if (p1.globalIndex() == p2.globalIndex()) + return -1; // mc particle p1 and p2 are identical. reject. + if (p2.globalIndex() == p3.globalIndex()) + return -1; // mc particle p2 and p3 are identical. reject. + if (p3.globalIndex() == p1.globalIndex()) + return -1; // mc particle p3 and p1 are identical. reject. + + if (!p1.has_mothers()) + return -1; + if (!p2.has_mothers()) + return -1; + if (!p3.has_mothers()) + return -1; + + // LOGF(info,"original motherid1 = %d , motherid2 = %d", p1.mothersIds()[0], p2.mothersIds()[0]); + + int motherid1 = p1.mothersIds()[0]; + int motherid2 = p2.mothersIds()[0]; + int motherid3 = p3.mothersIds()[0]; + + // LOGF(info,"motherid1 = %d , motherid2 = %d", motherid1, motherid2); + + if (motherid1 != motherid2) + return -1; + if (motherid2 != motherid3) + return -1; + if (motherid3 != motherid1) + return -1; + return motherid1; +} +//_______________________________________________________________________ +template +int FindCommonMotherFrom2Prongs(TMCParticle1 const& p1, TMCParticle2 const& p2, const int expected_pdg1, const int expected_pdg2, const int expected_mother_pdg, TMCParticles const& mcparticles) +{ + if (p1.globalIndex() == p2.globalIndex()) + return -1; // mc particle p1 and p2 is identical. reject. + + if (p1.pdgCode() != expected_pdg1) + return -1; + if (p2.pdgCode() != expected_pdg2) + return -1; + + if (!p1.has_mothers()) + return -1; + if (!p2.has_mothers()) + return -1; + + // LOGF(info,"original motherid1 = %d , motherid2 = %d", p1.mothersIds()[0], p2.mothersIds()[0]); + + int motherid1 = p1.mothersIds()[0]; + auto mother1 = mcparticles.iteratorAt(motherid1); + int mother1_pdg = mother1.pdgCode(); + + int motherid2 = p2.mothersIds()[0]; + auto mother2 = mcparticles.iteratorAt(motherid2); + int mother2_pdg = mother2.pdgCode(); + + // LOGF(info,"motherid1 = %d , motherid2 = %d", motherid1, motherid2); + + if (motherid1 != motherid2) + return -1; + if (mother1_pdg != mother2_pdg) + return -1; + if (mother1_pdg != expected_mother_pdg) + return -1; + return motherid1; +} +//_______________________________________________________________________ +template +int FindCommonMotherFrom3Prongs(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticle3 const& p3, const int expected_pdg1, const int expected_pdg2, const int expected_pdg3, const int expected_mother_pdg, TMCParticles const& mcparticles) +{ + if (p1.globalIndex() == p2.globalIndex()) + return -1; // mc particle p1 and p2 are identical. reject. + if (p2.globalIndex() == p3.globalIndex()) + return -1; // mc particle p2 and p3 are identical. reject. + if (p3.globalIndex() == p1.globalIndex()) + return -1; // mc particle p3 and p1 are identical. reject. + + if (p1.pdgCode() != expected_pdg1) + return -1; + if (p2.pdgCode() != expected_pdg2) + return -1; + if (p3.pdgCode() != expected_pdg3) + return -1; + + if (!p1.has_mothers()) + return -1; + if (!p2.has_mothers()) + return -1; + if (!p3.has_mothers()) + return -1; + + // LOGF(info,"original motherid1 = %d , motherid2 = %d", p1.mothersIds()[0], p2.mothersIds()[0]); + + int motherid1 = p1.mothersIds()[0]; + auto mother1 = mcparticles.iteratorAt(motherid1); + int mother1_pdg = mother1.pdgCode(); + + int motherid2 = p2.mothersIds()[0]; + auto mother2 = mcparticles.iteratorAt(motherid2); + int mother2_pdg = mother2.pdgCode(); + + int motherid3 = p3.mothersIds()[0]; + auto mother3 = mcparticles.iteratorAt(motherid3); + int mother3_pdg = mother3.pdgCode(); + + // LOGF(info,"motherid1 = %d , motherid2 = %d", motherid1, motherid2); + + if (motherid1 != motherid2) + return -1; + if (motherid2 != motherid3) + return -1; + if (motherid3 != motherid1) + return -1; + + if (mother1_pdg != mother2_pdg) + return -1; + if (mother2_pdg != mother3_pdg) + return -1; + if (mother3_pdg != mother1_pdg) + return -1; + + if (mother1_pdg != expected_mother_pdg) + return -1; + return motherid1; +} +//_______________________________________________________________________ +template +int getMotherPDGCode(TMCParticle const& p, TMCParticles const& mcparticles) +{ + int motherid = p.mothersIds()[0]; + auto mother = mcparticles.iteratorAt(motherid); + return (mother.pdgCode()); +} +//_______________________________________________________________________ template int IsFromBeauty(TMCParticle const& p, TMCParticles const& mcparticles) { @@ -39,6 +237,11 @@ int IsFromBeauty(TMCParticle const& p, TMCParticles const& mcparticles) } int motherid = p.mothersIds()[0]; // first mother index + auto mp_tmp = mcparticles.iteratorAt(motherid); + if (abs(mp_tmp.pdgCode()) < 1e+9 && (std::to_string(abs(mp_tmp.pdgCode()))[std::to_string(abs(mp_tmp.pdgCode())).length() - 2] == '5' && std::to_string(abs(mp_tmp.pdgCode()))[std::to_string(abs(mp_tmp.pdgCode())).length() - 3] == '5') && abs(mp_tmp.pdgCode()) % 2 == 1) { + return -999; // reject bottomonia + } + while (motherid > -1) { if (motherid < mcparticles.size()) { // protect against bad mother indices. why is this needed? auto mp = mcparticles.iteratorAt(motherid); @@ -58,6 +261,7 @@ int IsFromBeauty(TMCParticle const& p, TMCParticles const& mcparticles) return -999; } +//_______________________________________________________________________ template int IsFromCharm(TMCParticle const& p, TMCParticles const& mcparticles) { @@ -66,6 +270,10 @@ int IsFromCharm(TMCParticle const& p, TMCParticles const& mcparticles) } int motherid = p.mothersIds()[0]; // first mother index + auto mp_tmp = mcparticles.iteratorAt(motherid); + if (abs(mp_tmp.pdgCode()) < 1e+9 && (std::to_string(abs(mp_tmp.pdgCode()))[std::to_string(abs(mp_tmp.pdgCode())).length() - 2] == '4' && std::to_string(abs(mp_tmp.pdgCode()))[std::to_string(abs(mp_tmp.pdgCode())).length() - 3] == '4') && abs(mp_tmp.pdgCode()) % 2 == 1) { + return -999; // reject bottomonia + } while (motherid > -1) { if (motherid < mcparticles.size()) { // protect against bad mother indices. why is this needed? auto mp = mcparticles.iteratorAt(motherid); @@ -85,6 +293,7 @@ int IsFromCharm(TMCParticle const& p, TMCParticles const& mcparticles) return -999; } +//_______________________________________________________________________ template int IsHF(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticles const& mcparticles) { @@ -136,14 +345,14 @@ int IsHF(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticles const& mcp } } - bool is_direct_from_b1 = abs(mothers_pdg1[0]) < 1e+9 && (std::to_string(mothers_pdg1[0])[std::to_string(mothers_pdg1[0]).length() - 3] == '5' || std::to_string(mothers_pdg1[0])[std::to_string(mothers_pdg1[0]).length() - 4] == '5'); - bool is_direct_from_b2 = abs(mothers_pdg2[0]) < 1e+9 && (std::to_string(mothers_pdg2[0])[std::to_string(mothers_pdg2[0]).length() - 3] == '5' || std::to_string(mothers_pdg2[0])[std::to_string(mothers_pdg2[0]).length() - 4] == '5'); - bool is_prompt_c1 = abs(mothers_pdg1[0]) < 1e+9 && (std::to_string(mothers_pdg1[0])[std::to_string(mothers_pdg1[0]).length() - 3] == '4' || std::to_string(mothers_pdg1[0])[std::to_string(mothers_pdg1[0]).length() - 4] == '4') && IsFromBeauty(p1, mcparticles) < 0; - bool is_prompt_c2 = abs(mothers_pdg2[0]) < 1e+9 && (std::to_string(mothers_pdg2[0])[std::to_string(mothers_pdg2[0]).length() - 3] == '4' || std::to_string(mothers_pdg2[0])[std::to_string(mothers_pdg2[0]).length() - 4] == '4') && IsFromBeauty(p2, mcparticles) < 0; - bool is_c_from_b1 = abs(mothers_pdg1[0]) < 1e+9 && (std::to_string(mothers_pdg1[0])[std::to_string(mothers_pdg1[0]).length() - 3] == '4' || std::to_string(mothers_pdg1[0])[std::to_string(mothers_pdg1[0]).length() - 4] == '4') && IsFromBeauty(p1, mcparticles) > 0; - bool is_c_from_b2 = abs(mothers_pdg2[0]) < 1e+9 && (std::to_string(mothers_pdg2[0])[std::to_string(mothers_pdg2[0]).length() - 3] == '4' || std::to_string(mothers_pdg2[0])[std::to_string(mothers_pdg2[0]).length() - 4] == '4') && IsFromBeauty(p2, mcparticles) > 0; + bool is_direct_from_b1 = IsFromBeauty(p1, mcparticles) > 0 && IsFromCharm(p1, mcparticles) < 0; + bool is_direct_from_b2 = IsFromBeauty(p2, mcparticles) > 0 && IsFromCharm(p2, mcparticles) < 0; + bool is_prompt_c1 = IsFromBeauty(p1, mcparticles) < 0 && IsFromCharm(p1, mcparticles) > 0; + bool is_prompt_c2 = IsFromBeauty(p2, mcparticles) < 0 && IsFromCharm(p2, mcparticles) > 0; + bool is_c_from_b1 = IsFromBeauty(p1, mcparticles) > 0 && IsFromCharm(p1, mcparticles) > 0; + bool is_c_from_b2 = IsFromBeauty(p2, mcparticles) > 0 && IsFromCharm(p2, mcparticles) > 0; - if (is_prompt_c1 && is_prompt_c2 && p1.pdgCode() * p2.pdgCode() < 0) { + if (is_direct_from_b1 && is_direct_from_b2 && p1.pdgCode() * p2.pdgCode() < 0) { mothers_id1.clear(); mothers_pdg1.clear(); mothers_id2.clear(); @@ -152,8 +361,9 @@ int IsHF(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticles const& mcp mothers_pdg1.shrink_to_fit(); mothers_id2.shrink_to_fit(); mothers_pdg2.shrink_to_fit(); - return static_cast(EM_HFeeType::kCe_Ce); // cc->ee, decay type = 0 - } else if (is_direct_from_b1 && is_direct_from_b2 && p1.pdgCode() * p2.pdgCode() < 0) { + return static_cast(EM_HFeeType::kBe_Be); // bb->ee, decay type = 2 + } + if (is_prompt_c1 && is_prompt_c2 && p1.pdgCode() * p2.pdgCode() < 0) { mothers_id1.clear(); mothers_pdg1.clear(); mothers_id2.clear(); @@ -162,8 +372,9 @@ int IsHF(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticles const& mcp mothers_pdg1.shrink_to_fit(); mothers_id2.shrink_to_fit(); mothers_pdg2.shrink_to_fit(); - return static_cast(EM_HFeeType::kBe_Be); // bb->ee, decay type = 2 - } else if (is_c_from_b1 && is_c_from_b2 && p1.pdgCode() * p2.pdgCode() < 0) { + return static_cast(EM_HFeeType::kCe_Ce); // cc->ee, decay type = 0 + } + if (is_c_from_b1 && is_c_from_b2 && p1.pdgCode() * p2.pdgCode() < 0) { mothers_id1.clear(); mothers_pdg1.clear(); mothers_id2.clear(); @@ -173,14 +384,16 @@ int IsHF(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticles const& mcp mothers_id2.shrink_to_fit(); mothers_pdg2.shrink_to_fit(); return static_cast(EM_HFeeType::kBCe_BCe); // b->c->e and b->c->e, decay type = 1 - } else if ((is_direct_from_b1 && is_c_from_b2) || (is_direct_from_b2 && is_c_from_b1)) { + } + if ((is_direct_from_b1 && is_c_from_b2) || (is_direct_from_b2 && is_c_from_b1)) { if (p1.pdgCode() * p2.pdgCode() < 0) { // ULS for (auto& mid1 : mothers_id1) { for (auto& mid2 : mothers_id2) { if (mid1 == mid2) { auto common_mp = mcparticles.iteratorAt(mid1); int mp_pdg = common_mp.pdgCode(); - if (abs(mp_pdg) < 1e+9 && (std::to_string(abs(mp_pdg))[std::to_string(abs(mp_pdg)).length() - 3] == '5' || std::to_string(abs(mp_pdg))[std::to_string(abs(mp_pdg)).length() - 4] == '5')) { + bool is_mp_diquark = (1100 < abs(mp_pdg) && abs(mp_pdg) < 5600) && std::to_string(mp_pdg)[std::to_string(mp_pdg).length() - 2] == '0'; + if (!is_mp_diquark && abs(mp_pdg) < 1e+9 && (std::to_string(abs(mp_pdg))[std::to_string(abs(mp_pdg)).length() - 3] == '5' || std::to_string(abs(mp_pdg))[std::to_string(abs(mp_pdg)).length() - 4] == '5')) { mothers_id1.clear(); mothers_pdg1.clear(); mothers_id2.clear(); @@ -192,8 +405,8 @@ int IsHF(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticles const& mcp return static_cast(EM_HFeeType::kBCe_Be_SameB); // b->c->e and b->e, decay type = 3. this should happen only in ULS. } } - } // end of motherid2 - } // end of motherid1 + } // end of motherid2 + } // end of motherid1 } else { // LS bool is_same_mother_found = false; for (auto& mid1 : mothers_id1) { @@ -201,12 +414,13 @@ int IsHF(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticles const& mcp if (mid1 == mid2) { auto common_mp = mcparticles.iteratorAt(mid1); int mp_pdg = common_mp.pdgCode(); - if (abs(mp_pdg) < 1e+9 && (std::to_string(abs(mp_pdg))[std::to_string(abs(mp_pdg)).length() - 3] == '5' || std::to_string(abs(mp_pdg))[std::to_string(abs(mp_pdg)).length() - 4] == '5')) { + bool is_mp_diquark = (1100 < abs(mp_pdg) && abs(mp_pdg) < 5600) && std::to_string(mp_pdg)[std::to_string(mp_pdg).length() - 2] == '0'; + if (!is_mp_diquark && abs(mp_pdg) < 1e+9 && (std::to_string(abs(mp_pdg))[std::to_string(abs(mp_pdg)).length() - 3] == '5' || std::to_string(abs(mp_pdg))[std::to_string(abs(mp_pdg)).length() - 4] == '5')) { is_same_mother_found = true; } } } // end of motherid2 - } // end of motherid1 + } // end of motherid1 if (!is_same_mother_found) { mothers_id1.clear(); mothers_pdg1.clear(); @@ -231,7 +445,148 @@ int IsHF(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticles const& mcp mothers_pdg2.shrink_to_fit(); return static_cast(EM_HFeeType::kUndef); } + +//_______________________________________________________________________ +template +int searchMothers(T& p, U& mcParticles, int pdg, bool equal) +{ // find the first ancestor that is equal/not-equal pdg + + if (!p.has_mothers()) { + return -1; + } + auto mothersids = p.mothersIds(); + std::vector allmothersids; + + if (mothersids.size() == 2) { + if (mothersids[0] == mothersids[1]) { + allmothersids.push_back(mothersids[0]); + } else if (mothersids[1] < mothersids[0]) { + allmothersids.push_back(mothersids[0]); + allmothersids.push_back(mothersids[1]); + } else if ((80 < abs(o2::mcgenstatus::getGenStatusCode(p.statusCode())) && abs(o2::mcgenstatus::getGenStatusCode(p.statusCode())) < 90) || (100 < abs(o2::mcgenstatus::getGenStatusCode(p.statusCode())) && abs(o2::mcgenstatus::getGenStatusCode(p.statusCode())) < 110)) { // NOTE: THIS IS GENERATOR DEPENDENT AND WORKS ONLY FOR PYTHIA! + for (int i = mothersids[0]; i <= mothersids[1]; i++) { + allmothersids.push_back(i); + } + } else { + allmothersids.push_back(mothersids[0]); + allmothersids.push_back(mothersids[1]); + } + } else { + allmothersids.push_back(mothersids[0]); + } + + if (equal) { // we are searching for the quark + int quark_id = -1; + int next_mother_id = -1; + for (int i : allmothersids) { + auto mother = mcParticles.iteratorAt(i); + int mpdg = mother.pdgCode(); + if (abs(mpdg) == pdg && mpdg * p.pdgCode() > 0) { // check for quark + if (quark_id > -1 || next_mother_id > -1) { // we already found a possible candidate in the list of mothers, so now we have (at least) two + // LOG(warning) << "Flavour tracking is ambiguous. Stopping here."; + return -1; + } + quark_id = i; + } else if ((static_cast(abs(mpdg) / 100) == pdg || static_cast(abs(mpdg) / 1000) == pdg) && mpdg * p.pdgCode() > 0) { // check for other mothers with flavour content + if (quark_id > -1 || next_mother_id > -1) { // we already found a possible candidate in the list of mothers, so now we have (at least) two + // LOG(warning) << "Flavour tracking is ambiguous. Stopping here."; + return -1; + } + next_mother_id = i; + } + } + if (quark_id > -1) { // we found the quark + return quark_id; + } + if (next_mother_id > -1) { + auto mother = mcParticles.iteratorAt(next_mother_id); + return searchMothers(mother, mcParticles, pdg, equal); // we found at least something with flavour content, go deeper recursively + } + return -1; + } else { // searching for first ancestor that is not quark anymore + int quark_id = -1; + for (int i : allmothersids) { + auto mother = mcParticles.iteratorAt(i); + int mpdg = abs(mother.pdgCode()); + if (mpdg == pdg && mother.pdgCode() == p.pdgCode()) { // found the quark + if (quark_id > -1) { // we already found a possible candidate in the list of mothers, so now we have (at least) two + // LOG(warning) << "Flavour tracking is ambiguous. Stopping here."; + return -1; + } + quark_id = i; + } + } + if (quark_id > -1) { // we found a quark and now search recursivly through entire history + auto mother = mcParticles.iteratorAt(quark_id); + return searchMothers(mother, mcParticles, pdg, equal); + } else { // no HF quark as mother, so this is the ancestor + return allmothersids[0]; + } + } + return -1; +} + +//_______________________________________________________________________ +template +int findHFOrigin(T& p, U& mcParticles, int pdg) +{ + int quark_id = searchMothers(p, mcParticles, pdg, true); // try to find the hf quark + if (quark_id == -1) { + return -1; + } + auto quark = mcParticles.iteratorAt(quark_id); + int id = searchMothers(quark, mcParticles, pdg, false); // try to find the first ancestor that is not the hf quark anymore + return id; +} +//_______________________________________________________________________ +template +bool checkFromSameQuarkPair(T& p1, T& p2, U& mcParticles, int pdg) +{ // check if two particles come from the same hf q-qbar pair + int id1 = findHFOrigin(p1, mcParticles, pdg); + int id2 = findHFOrigin(p2, mcParticles, pdg); + return id1 == id2 && id1 > -1 && id2 > -1; +} +//_______________________________________________________________________ +template +bool isCharmMeson(T const& track) +{ + if (400 < abs(track.pdgCode()) && abs(track.pdgCode()) < 500) { + return true; + } else { + return false; + } +} +//_______________________________________________________________________ +template +bool isCharmBaryon(T const& track) +{ + if (4000 < abs(track.pdgCode()) && abs(track.pdgCode()) < 5000) { + return true; + } else { + return false; + } +} +//_______________________________________________________________________ +template +bool isBeautyMeson(T const& track) +{ + if (500 < abs(track.pdgCode()) && abs(track.pdgCode()) < 600) { + return true; + } else { + return false; + } +} +//_______________________________________________________________________ +template +bool isBeautyBaryon(T const& track) +{ + if (5000 < abs(track.pdgCode()) && abs(track.pdgCode()) < 6000) { + return true; + } else { + return false; + } +} //_______________________________________________________________________ //_______________________________________________________________________ -} // namespace o2::aod::pwgem::dilepton::mcutil +} // namespace o2::aod::pwgem::dilepton::utils::mcutil #endif // PWGEM_DILEPTON_UTILS_MCUTILITIES_H_ diff --git a/PWGEM/Dilepton/Utils/MlResponseDielectronPair.h b/PWGEM/Dilepton/Utils/MlResponseDielectronPair.h deleted file mode 100644 index 40f97b67937..00000000000 --- a/PWGEM/Dilepton/Utils/MlResponseDielectronPair.h +++ /dev/null @@ -1,238 +0,0 @@ -// 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 MlResponseDiletponPair.h -/// \brief Class to compute the ML response for dielectron analyses at the pair level -/// \author Daniel Samitz , SMI Vienna -/// Elisa Meninno, , SMI Vienna - -#ifndef PWGEM_DILEPTON_UTILS_MLRESPONSEDIELECTRONPAIR_H_ -#define PWGEM_DILEPTON_UTILS_MLRESPONSEDIELECTRONPAIR_H_ - -#include -#include -#include - -#include "Math/Vector4D.h" -#include "Tools/ML/MlResponse.h" - -// Fill the map of available input features -// the key is the feature's name (std::string) -// the value is the corresponding value in EnumInputFeatures -#define FILL_MAP_DIELECTRON_PAIR(FEATURE) \ - { \ -#FEATURE, static_cast < uint8_t>(InputFeaturesDielectronPair::FEATURE) \ - } - -// Check if the index of mCachedIndices (index associated to a FEATURE) -// matches the entry in EnumInputFeatures associated to this FEATURE -// if so, the inputFeatures vector is filled with the FEATURE's value -// by calling the corresponding GETTER from pair fourmomentum v12 -#define CHECK_AND_FILL_VEC_DIELECTRON_PAIR(FEATURE, GETTER) \ - case static_cast(InputFeaturesDielectronPair::FEATURE): { \ - inputFeatures.emplace_back(v12.GETTER()); \ - break; \ - } - -// Check if the index of mCachedIndices (index associated to a FEATURE) -// matches the entry in EnumInputFeatures associated to this FEATURE -// if so, the inputFeatures vector is filled with the FEATURE's value -// by calling the corresponding FUNCTION on the tracks t1 and t2 -#define CHECK_AND_FILL_VEC_DIELECTRON_PAIR_FUNC(FEATURE, FUNCTION) \ - case static_cast(InputFeaturesDielectronPair::FEATURE): { \ - inputFeatures.emplace_back(FUNCTION(t1, t2)); \ - break; \ - } - -namespace o2::analysis -{ -// possible input features for ML -enum class InputFeaturesDielectronPair : uint8_t { - m, - pt, - eta, - phi, - phiv, - pairDcaXY, - pairDcaZ -}; - -template -class MlResponseDielectronPair : public MlResponse -{ - public: - /// Default constructor - MlResponseDielectronPair() = default; - /// Default destructor - virtual ~MlResponseDielectronPair() = default; - - template - float pair_dca_xy(T const& t1, T const& t2) - { - return sqrt((pow(t1.dcaXY() / sqrt(t1.cYY()), 2) + pow(t2.dcaXY() / sqrt(t2.cYY()), 2)) / 2.); - } - - template - float pair_dca_z(T const& t1, T const& t2) - { - return sqrt((pow(t1.dcaZ() / sqrt(t1.cZZ()), 2) + pow(t2.dcaZ() / sqrt(t2.cZZ()), 2)) / 2.); - } - - template - float get_phiv(T const& t1, T const& t2) - { - // cos(phiv) = w*a /|w||a| - // with w = u x v - // and a = u x z / |u x z| , unit vector perpendicular to v12 and z-direction (magnetic field) - // u = v12 / |v12| , the unit vector of v12 - // v = v1 x v2 / |v1 x v2| , unit vector perpendicular to v1 and v2 - - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - - bool swapTracks = false; - if (v1.Pt() < v2.Pt()) { // ordering of track, pt1 > pt2 - ROOT::Math::PtEtaPhiMVector v3 = v1; - v1 = v2; - v2 = v3; - swapTracks = true; - } - - // momentum of e+ and e- in (ax,ay,az) axis. Note that az=0 by definition. - // vector product of pep X pem - float vpx = 0, vpy = 0, vpz = 0; - if (t1.sign() * t2.sign() > 0) { // Like Sign - if (!swapTracks) { - if (d_bz * t1.sign() < 0) { - vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); - vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); - vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); - } else { - vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); - vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); - vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); - } - } else { // swaped tracks - if (d_bz * t2.sign() < 0) { - vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); - vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); - vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); - } else { - vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); - vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); - vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); - } - } - } else { // Unlike Sign - if (!swapTracks) { - if (d_bz * t1.sign() > 0) { - vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); - vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); - vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); - } else { - vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); - vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); - vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); - } - } else { // swaped tracks - if (d_bz * t2.sign() > 0) { - vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); - vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); - vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); - } else { - vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); - vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); - vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); - } - } - } - - // unit vector of pep X pem - float vx = vpx / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); - float vy = vpy / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); - float vz = vpz / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); - - float px = v12.Px(); - float py = v12.Py(); - float pz = v12.Pz(); - - // unit vector of (pep+pem) - float ux = px / TMath::Sqrt(px * px + py * py + pz * pz); - float uy = py / TMath::Sqrt(px * px + py * py + pz * pz); - float uz = pz / TMath::Sqrt(px * px + py * py + pz * pz); - float ax = uy / TMath::Sqrt(ux * ux + uy * uy); - float ay = -ux / TMath::Sqrt(ux * ux + uy * uy); - - // The third axis defined by vector product (ux,uy,uz)X(vx,vy,vz) - float wx = uy * vz - uz * vy; - float wy = uz * vx - ux * vz; - // by construction, (wx,wy,wz) must be a unit vector. Measure angle between (wx,wy,wz) and (ax,ay,0). - // The angle between them should be small if the pair is conversion. This function then returns values close to pi! - return TMath::ACos(wx * ax + wy * ay); // phiv in [0,pi] //cosPhiV = wx * ax + wy * ay; - } - - /// Method to get the input features vector needed for ML inference - /// \param t1 is the first track - /// \param t2 is the second track - /// \return inputFeatures vector - template - std::vector getInputFeatures(T const& t1, T const& t2) - { - std::vector inputFeatures; - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - - for (const auto& idx : MlResponse::mCachedIndices) { - switch (idx) { - CHECK_AND_FILL_VEC_DIELECTRON_PAIR(m, M); - CHECK_AND_FILL_VEC_DIELECTRON_PAIR(pt, Pt); - CHECK_AND_FILL_VEC_DIELECTRON_PAIR(eta, Eta); - CHECK_AND_FILL_VEC_DIELECTRON_PAIR(phi, Phi); - CHECK_AND_FILL_VEC_DIELECTRON_PAIR_FUNC(phiv, get_phiv); - CHECK_AND_FILL_VEC_DIELECTRON_PAIR_FUNC(pairDcaXY, pair_dca_xy); - CHECK_AND_FILL_VEC_DIELECTRON_PAIR_FUNC(pairDcaZ, pair_dca_z); - } - } - - return inputFeatures; - } - - void setBz(float bz) - { - d_bz = bz; - } - - protected: - /// Method to fill the map of available input features - void setAvailableInputFeatures() - { - MlResponse::mAvailableInputFeatures = { - FILL_MAP_DIELECTRON_PAIR(m), - FILL_MAP_DIELECTRON_PAIR(pt), - FILL_MAP_DIELECTRON_PAIR(eta), - FILL_MAP_DIELECTRON_PAIR(phi), - FILL_MAP_DIELECTRON_PAIR(phiv), - FILL_MAP_DIELECTRON_PAIR(pairDcaXY), - FILL_MAP_DIELECTRON_PAIR(pairDcaZ)}; - } - - float d_bz = 0.; -}; - -} // namespace o2::analysis - -#undef FILL_MAP_DIELECTRON_PAIR -#undef CHECK_AND_FILL_VEC_DIELECTRON_PAIR -#undef CHECK_AND_FILL_VEC_DIELECTRON_PAIR_FUNC - -#endif // PWGEM_DILEPTON_UTILS_MLRESPONSEDIELECTRONPAIR_H_ diff --git a/PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h b/PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h index d7217bb49d8..ef1c7b33474 100644 --- a/PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h +++ b/PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h @@ -26,31 +26,66 @@ // Fill the map of available input features // the key is the feature's name (std::string) // the value is the corresponding value in EnumInputFeatures -#define FILL_MAP_DIELECTRON_SINGLE_TRACK(FEATURE) \ - { \ -#FEATURE, static_cast < uint8_t>(InputFeaturesDielectronSingleTrack::FEATURE) \ +#define FILL_MAP_DIELECTRON_SINGLE_TRACK(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesDielectronSingleTrack::FEATURE) \ } // Check if the index of mCachedIndices (index associated to a FEATURE) // matches the entry in EnumInputFeatures associated to this FEATURE // if so, the inputFeatures vector is filled with the FEATURE's value // by calling the corresponding GETTER=FEATURE from track -#define CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(GETTER) \ +#define CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(GETTER) \ case static_cast(InputFeaturesDielectronSingleTrack::GETTER): { \ - inputFeatures.emplace_back(track.GETTER()); \ + inputFeature = track.GETTER(); \ break; \ } +// TPC+TOF combined nSigma +#define CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK_TPCTOF(FEATURE, GETTER1, GETTER2, GETTER3) \ + case static_cast(InputFeaturesDielectronSingleTrack::FEATURE): { \ + if (!track.GETTER3()) { \ + inputFeature = track.GETTER1(); \ + } else { \ + if (track.GETTER1() > 0) { \ + inputFeature = sqrt((pow(track.GETTER1(), 2) + pow(track.GETTER2(), 2)) / 2.); \ + } else { \ + inputFeature = (-1) * sqrt((pow(track.GETTER1(), 2) + pow(track.GETTER2(), 2)) / 2.); \ + } \ + } \ + break; \ + } + // Check if the index of mCachedIndices (index associated to a FEATURE) // matches the entry in EnumInputFeatures associated to this FEATURE // if so, the inputFeatures vector is filled with the FEATURE's value -// by calling the corresponding GETTER form track and applying a sqrt -#define CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK_SQRT(FEATURE, GETTER) \ +// by calling the corresponding GETTER from track and applying a sqrt +#define CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK_SQRT(FEATURE, GETTER) \ case static_cast(InputFeaturesDielectronSingleTrack::FEATURE): { \ - inputFeatures.emplace_back(sqrt(track.GETTER())); \ + inputFeature = sqrt(track.GETTER()); \ break; \ } +// Check if the index of mCachedIndices (index associated to a FEATURE) +// matches the entry in EnumInputFeatures associated to this FEATURE +// if so, the inputFeatures vector is filled with the FEATURE's value +// by calling the corresponding GETTER1 from track and multiplying with cos(atan(GETTER2)) +#define CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK_COS(FEATURE, GETTER1, GETTER2) \ + case static_cast(InputFeaturesDielectronSingleTrack::FEATURE): { \ + inputFeature = track.GETTER1() * std::cos(std::atan(track.GETTER2())); \ + break; \ + } + +// Check if the index of mCachedIndices (index associated to a FEATURE) +// matches the entry in EnumInputFeatures associated to this FEATURE +// if so, the inputFeatures vector is filled with the FEATURE's value +// by calling the corresponding GETTER=FEATURE from collision +#define CHECK_AND_FILL_DIELECTRON_COLLISION(GETTER) \ + case static_cast(InputFeaturesDielectronSingleTrack::GETTER): { \ + inputFeature = collision.GETTER(); \ + break; \ + } + namespace o2::analysis { // possible input features for ML @@ -64,8 +99,9 @@ enum class InputFeaturesDielectronSingleTrack : uint8_t { dcaResXY, dcaResZ, tpcNClsFindable, - tpcNClsFound, - tpcNClsCrossedRows, + tpcNClsFindableMinusFound, + tpcNClsFindableMinusCrossedRows, + tpcNClsShared, tpcChi2NCl, tpcInnerParam, tpcSignal, @@ -80,8 +116,85 @@ enum class InputFeaturesDielectronSingleTrack : uint8_t { tofNSigmaPi, tofNSigmaKa, tofNSigmaPr, + tpctofNSigmaEl, + tpctofNSigmaMu, + tpctofNSigmaPi, + tpctofNSigmaKa, + tpctofNSigmaPr, + itsClusterSizes, + itsChi2NCl, + tofChi2, + detectorMap, + x, + alpha, + y, + z, + snp, + tgl, + isAssociatedToMPC, + tpcNClsFound, + tpcNClsCrossedRows, + tpcCrossedRowsOverFindableCls, + tpcFoundOverFindableCls, + tpcFractionSharedCls, itsClusterMap, - itsChi2NCl + itsNCls, + itsNClsInnerBarrel, + hasITS, + hasTPC, + hasTRD, + hasTOF, + signed1Pt, + p, + px, + py, + pz, + theta, + meanClusterSizeITS, + meanClusterSizeITSib, + meanClusterSizeITSob, + meanClusterSizeITSCos, + meanClusterSizeITSibCos, + meanClusterSizeITSobCos, + cYY, + cZY, + cZZ, + cSnpY, + cSnpZ, + cSnpSnp, + cTglY, + cTglZ, + cTglSnp, + cTglTgl, + c1PtY, + c1PtZ, + c1PtSnp, + c1PtTgl, + c1Pt21Pt2, + posX, + posY, + posZ, + numContrib, + trackOccupancyInTimeRange, + ft0cOccupancyInTimeRange, + // covXX, + // covXY, + // covXZ, + // covYY, + // covYZ, + // covZZ, + // chi2, + multFT0A, + multFT0C, + multNTracksPV, + multNTracksPVeta1, + multNTracksPVetaHalf, + isInelGt0, + isInelGt1, + multFT0M, + centFT0M, + centFT0A, + centFT0C }; template @@ -93,49 +206,153 @@ class MlResponseDielectronSingleTrack : public MlResponse /// Default destructor virtual ~MlResponseDielectronSingleTrack() = default; + template + float return_feature(uint8_t idx, T const& track, U const& collision) + { + float inputFeature = 0.; + switch (idx) { + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(sign); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(pt); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(eta); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(phi); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(dcaXY); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(dcaZ); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK_SQRT(dcaResXY, cYY); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK_SQRT(dcaResZ, cZZ); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tpcNClsFindable); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tpcNClsFindableMinusFound); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tpcNClsFindableMinusCrossedRows); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tpcNClsShared); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tpcChi2NCl); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tpcInnerParam); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tpcSignal); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tpcNSigmaEl); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tpcNSigmaMu); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tpcNSigmaPi); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tpcNSigmaKa); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tpcNSigmaPr); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(beta); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tofNSigmaEl); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tofNSigmaMu); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tofNSigmaPi); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tofNSigmaKa); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tofNSigmaPr); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK_TPCTOF(tpctofNSigmaEl, tpcNSigmaEl, tofNSigmaEl, hasTOF); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK_TPCTOF(tpctofNSigmaMu, tpcNSigmaMu, tofNSigmaMu, hasTOF); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK_TPCTOF(tpctofNSigmaPi, tpcNSigmaPi, tofNSigmaPi, hasTOF); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK_TPCTOF(tpctofNSigmaKa, tpcNSigmaKa, tofNSigmaKa, hasTOF); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK_TPCTOF(tpctofNSigmaPr, tpcNSigmaPr, tofNSigmaPr, hasTOF); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(itsClusterSizes); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(itsChi2NCl); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tofChi2); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(detectorMap); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(x); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(alpha); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(y); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(z); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(snp); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tgl); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(isAssociatedToMPC); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tpcNClsFound); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tpcNClsCrossedRows); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tpcCrossedRowsOverFindableCls); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tpcFoundOverFindableCls); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(tpcFractionSharedCls); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(itsClusterMap); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(itsNCls); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(itsNClsInnerBarrel); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(hasITS); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(hasTPC); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(hasTRD); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(hasTOF); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(signed1Pt); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(p); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(px); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(py); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(pz); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(theta); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(meanClusterSizeITS); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(meanClusterSizeITSib); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(meanClusterSizeITSob); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK_COS(meanClusterSizeITSCos, meanClusterSizeITS, tgl); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK_COS(meanClusterSizeITSibCos, meanClusterSizeITSib, tgl); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK_COS(meanClusterSizeITSobCos, meanClusterSizeITSob, tgl); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(cYY); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(cZY); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(cZZ); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(cSnpY); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(cSnpZ); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(cSnpSnp); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(cTglY); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(cTglZ); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(cTglSnp); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(cTglTgl); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(c1PtY); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(c1PtZ); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(c1PtSnp); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(c1PtTgl); + CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK(c1Pt21Pt2); + CHECK_AND_FILL_DIELECTRON_COLLISION(posX); + CHECK_AND_FILL_DIELECTRON_COLLISION(posY); + CHECK_AND_FILL_DIELECTRON_COLLISION(posZ); + CHECK_AND_FILL_DIELECTRON_COLLISION(numContrib); + CHECK_AND_FILL_DIELECTRON_COLLISION(trackOccupancyInTimeRange); + CHECK_AND_FILL_DIELECTRON_COLLISION(ft0cOccupancyInTimeRange); + // CHECK_AND_FILL_DIELECTRON_COLLISION(covXX); + // CHECK_AND_FILL_DIELECTRON_COLLISION(covXY); + // CHECK_AND_FILL_DIELECTRON_COLLISION(covXZ); + // CHECK_AND_FILL_DIELECTRON_COLLISION(covYY); + // CHECK_AND_FILL_DIELECTRON_COLLISION(covYZ); + // CHECK_AND_FILL_DIELECTRON_COLLISION(covZZ); + // CHECK_AND_FILL_DIELECTRON_COLLISION(chi2); + CHECK_AND_FILL_DIELECTRON_COLLISION(multFT0A); + CHECK_AND_FILL_DIELECTRON_COLLISION(multFT0C); + CHECK_AND_FILL_DIELECTRON_COLLISION(multNTracksPV); + CHECK_AND_FILL_DIELECTRON_COLLISION(multNTracksPVeta1); + CHECK_AND_FILL_DIELECTRON_COLLISION(multNTracksPVetaHalf); + CHECK_AND_FILL_DIELECTRON_COLLISION(isInelGt0); + CHECK_AND_FILL_DIELECTRON_COLLISION(isInelGt1); + CHECK_AND_FILL_DIELECTRON_COLLISION(multFT0M); + CHECK_AND_FILL_DIELECTRON_COLLISION(centFT0M); + CHECK_AND_FILL_DIELECTRON_COLLISION(centFT0A); + CHECK_AND_FILL_DIELECTRON_COLLISION(centFT0C); + } + return inputFeature; + } + /// Method to get the input features vector needed for ML inference - /// \param track is the single track + /// \param track is the single track, \param collision is the collision /// \return inputFeatures vector - template - std::vector getInputFeatures(T const& track) + template + std::vector getInputFeatures(T const& track, U const& collision) { std::vector inputFeatures; - for (const auto& idx : MlResponse::mCachedIndices) { - switch (idx) { - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(sign); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(pt); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(eta); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(phi); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(dcaXY); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(dcaZ); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK_SQRT(dcaResXY, cYY); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK_SQRT(dcaResZ, cZZ); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(tpcNClsFindable); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(tpcNClsFound); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(tpcNClsCrossedRows); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(tpcChi2NCl); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(tpcInnerParam); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(tpcSignal); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(tpcNSigmaEl); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(tpcNSigmaMu); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(tpcNSigmaPi); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(tpcNSigmaKa); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(tpcNSigmaPr); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(beta); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(tofNSigmaEl); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(tofNSigmaMu); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(tofNSigmaPi); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(tofNSigmaKa); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(tofNSigmaPr); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(itsClusterMap); - CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK(itsChi2NCl); - } + float inputFeature = return_feature(idx, track, collision); + inputFeatures.emplace_back(inputFeature); } - return inputFeatures; } + /// Method to get the value of variable chosen for binning + /// \param track is the single track, \param collision is the collision + /// \return binning variable + template + float getBinningFeature(T const& track, U const& collision) + { + return return_feature(mCachedIndexBinning, track, collision); + } + + void cacheBinningIndex(std::string const& cfgBinningFeature) + { + setAvailableInputFeatures(); + if (MlResponse::mAvailableInputFeatures.count(cfgBinningFeature)) { + mCachedIndexBinning = MlResponse::mAvailableInputFeatures[cfgBinningFeature]; + } else { + LOG(fatal) << "Binning feature " << cfgBinningFeature << " not available! Please check your configurables."; + } + } + protected: /// Method to fill the map of available input features void setAvailableInputFeatures() @@ -150,8 +367,9 @@ class MlResponseDielectronSingleTrack : public MlResponse FILL_MAP_DIELECTRON_SINGLE_TRACK(dcaResXY), FILL_MAP_DIELECTRON_SINGLE_TRACK(dcaResZ), FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcNClsFindable), - FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcNClsFound), - FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcNClsCrossedRows), + FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcNClsFindableMinusFound), + FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcNClsFindableMinusCrossedRows), + FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcNClsShared), FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcChi2NCl), FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcInnerParam), FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcSignal), @@ -166,15 +384,97 @@ class MlResponseDielectronSingleTrack : public MlResponse FILL_MAP_DIELECTRON_SINGLE_TRACK(tofNSigmaPi), FILL_MAP_DIELECTRON_SINGLE_TRACK(tofNSigmaKa), FILL_MAP_DIELECTRON_SINGLE_TRACK(tofNSigmaPr), + FILL_MAP_DIELECTRON_SINGLE_TRACK(tpctofNSigmaEl), + FILL_MAP_DIELECTRON_SINGLE_TRACK(tpctofNSigmaMu), + FILL_MAP_DIELECTRON_SINGLE_TRACK(tpctofNSigmaPi), + FILL_MAP_DIELECTRON_SINGLE_TRACK(tpctofNSigmaKa), + FILL_MAP_DIELECTRON_SINGLE_TRACK(tpctofNSigmaPr), + FILL_MAP_DIELECTRON_SINGLE_TRACK(itsClusterSizes), + FILL_MAP_DIELECTRON_SINGLE_TRACK(itsChi2NCl), + FILL_MAP_DIELECTRON_SINGLE_TRACK(tofChi2), + FILL_MAP_DIELECTRON_SINGLE_TRACK(detectorMap), + FILL_MAP_DIELECTRON_SINGLE_TRACK(x), + FILL_MAP_DIELECTRON_SINGLE_TRACK(alpha), + FILL_MAP_DIELECTRON_SINGLE_TRACK(y), + FILL_MAP_DIELECTRON_SINGLE_TRACK(z), + FILL_MAP_DIELECTRON_SINGLE_TRACK(snp), + FILL_MAP_DIELECTRON_SINGLE_TRACK(tgl), + FILL_MAP_DIELECTRON_SINGLE_TRACK(isAssociatedToMPC), + FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcNClsFound), + FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcNClsCrossedRows), + FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcCrossedRowsOverFindableCls), + FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcFoundOverFindableCls), + FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcFractionSharedCls), FILL_MAP_DIELECTRON_SINGLE_TRACK(itsClusterMap), - FILL_MAP_DIELECTRON_SINGLE_TRACK(itsChi2NCl)}; + FILL_MAP_DIELECTRON_SINGLE_TRACK(itsNCls), + FILL_MAP_DIELECTRON_SINGLE_TRACK(itsNClsInnerBarrel), + FILL_MAP_DIELECTRON_SINGLE_TRACK(hasITS), + FILL_MAP_DIELECTRON_SINGLE_TRACK(hasTPC), + FILL_MAP_DIELECTRON_SINGLE_TRACK(hasTRD), + FILL_MAP_DIELECTRON_SINGLE_TRACK(hasTOF), + FILL_MAP_DIELECTRON_SINGLE_TRACK(signed1Pt), + FILL_MAP_DIELECTRON_SINGLE_TRACK(p), + FILL_MAP_DIELECTRON_SINGLE_TRACK(px), + FILL_MAP_DIELECTRON_SINGLE_TRACK(py), + FILL_MAP_DIELECTRON_SINGLE_TRACK(pz), + FILL_MAP_DIELECTRON_SINGLE_TRACK(theta), + FILL_MAP_DIELECTRON_SINGLE_TRACK(meanClusterSizeITS), + FILL_MAP_DIELECTRON_SINGLE_TRACK(meanClusterSizeITSib), + FILL_MAP_DIELECTRON_SINGLE_TRACK(meanClusterSizeITSob), + FILL_MAP_DIELECTRON_SINGLE_TRACK(meanClusterSizeITSCos), + FILL_MAP_DIELECTRON_SINGLE_TRACK(meanClusterSizeITSibCos), + FILL_MAP_DIELECTRON_SINGLE_TRACK(meanClusterSizeITSobCos), + FILL_MAP_DIELECTRON_SINGLE_TRACK(cYY), + FILL_MAP_DIELECTRON_SINGLE_TRACK(cZY), + FILL_MAP_DIELECTRON_SINGLE_TRACK(cZZ), + FILL_MAP_DIELECTRON_SINGLE_TRACK(cSnpY), + FILL_MAP_DIELECTRON_SINGLE_TRACK(cSnpZ), + FILL_MAP_DIELECTRON_SINGLE_TRACK(cSnpSnp), + FILL_MAP_DIELECTRON_SINGLE_TRACK(cTglY), + FILL_MAP_DIELECTRON_SINGLE_TRACK(cTglZ), + FILL_MAP_DIELECTRON_SINGLE_TRACK(cTglSnp), + FILL_MAP_DIELECTRON_SINGLE_TRACK(cTglTgl), + FILL_MAP_DIELECTRON_SINGLE_TRACK(c1PtY), + FILL_MAP_DIELECTRON_SINGLE_TRACK(c1PtZ), + FILL_MAP_DIELECTRON_SINGLE_TRACK(c1PtSnp), + FILL_MAP_DIELECTRON_SINGLE_TRACK(c1PtTgl), + FILL_MAP_DIELECTRON_SINGLE_TRACK(c1Pt21Pt2), + FILL_MAP_DIELECTRON_SINGLE_TRACK(posX), + FILL_MAP_DIELECTRON_SINGLE_TRACK(posY), + FILL_MAP_DIELECTRON_SINGLE_TRACK(posZ), + FILL_MAP_DIELECTRON_SINGLE_TRACK(numContrib), + FILL_MAP_DIELECTRON_SINGLE_TRACK(trackOccupancyInTimeRange), + FILL_MAP_DIELECTRON_SINGLE_TRACK(ft0cOccupancyInTimeRange), + // FILL_MAP_DIELECTRON_SINGLE_TRACK(covXX), + // FILL_MAP_DIELECTRON_SINGLE_TRACK(covXY), + // FILL_MAP_DIELECTRON_SINGLE_TRACK(covXZ), + // FILL_MAP_DIELECTRON_SINGLE_TRACK(covYY), + // FILL_MAP_DIELECTRON_SINGLE_TRACK(covYZ), + // FILL_MAP_DIELECTRON_SINGLE_TRACK(covZZ), + // FILL_MAP_DIELECTRON_SINGLE_TRACK(chi2), + FILL_MAP_DIELECTRON_SINGLE_TRACK(multFT0A), + FILL_MAP_DIELECTRON_SINGLE_TRACK(multFT0C), + FILL_MAP_DIELECTRON_SINGLE_TRACK(multNTracksPV), + FILL_MAP_DIELECTRON_SINGLE_TRACK(multNTracksPVeta1), + FILL_MAP_DIELECTRON_SINGLE_TRACK(multNTracksPVetaHalf), + FILL_MAP_DIELECTRON_SINGLE_TRACK(isInelGt0), + FILL_MAP_DIELECTRON_SINGLE_TRACK(isInelGt1), + FILL_MAP_DIELECTRON_SINGLE_TRACK(multFT0M), + FILL_MAP_DIELECTRON_SINGLE_TRACK(centFT0M), + FILL_MAP_DIELECTRON_SINGLE_TRACK(centFT0A), + FILL_MAP_DIELECTRON_SINGLE_TRACK(centFT0C)}; } + + uint8_t mCachedIndexBinning; // index correspondance between configurable and available input features }; } // namespace o2::analysis #undef FILL_MAP_DIELECTRON_SINGLE_TRACK -#undef CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK -#undef CHECK_AND_FILL_VEC_DIELECTRON_SINGLE_TRACK_SQRT +#undef CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK +#undef CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK_SQRT +#undef CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK_COS +#undef CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK_TPCTOF +#undef CHECK_AND_FILL_DIELECTRON_COLLISION #endif // PWGEM_DILEPTON_UTILS_MLRESPONSEDIELECTRONSINGLETRACK_H_ diff --git a/PWGEM/Dilepton/Utils/MomentumSmearer.h b/PWGEM/Dilepton/Utils/MomentumSmearer.h index ea1cff44cca..7e36dcfed0f 100644 --- a/PWGEM/Dilepton/Utils/MomentumSmearer.h +++ b/PWGEM/Dilepton/Utils/MomentumSmearer.h @@ -15,13 +15,23 @@ #ifndef PWGEM_DILEPTON_UTILS_MOMENTUMSMEARER_H_ #define PWGEM_DILEPTON_UTILS_MOMENTUMSMEARER_H_ -#include +#include + +#include +#include +#include +#include #include #include -#include #include +#include + +#include "CCDB/BasicCCDBManager.h" #include "Framework/Logger.h" +using namespace o2::framework; +using namespace o2; + class MomentumSmearer { public: @@ -36,147 +46,599 @@ class MomentumSmearer setResEtaHistName(resEtaHistName); setResPhiPosHistName(resPhiPosHistName); setResPhiNegHistName(resPhiNegHistName); + setEffFileName(""); + setEffHistName(""); + setDCAFileName(""); + setDCAHistName(""); + init(); + } + + /// Constructor with resolution ND sparse histogram + MomentumSmearer(TString resFileName, TString resNDHistName) + { + setResFileName(resFileName); + setResNDHistName(resNDHistName); + setResPtHistName(""); + setResEtaHistName(""); + setResPhiPosHistName(""); + setResPhiNegHistName(""); + setEffFileName(""); + setEffHistName(""); + setDCAFileName(""); + setDCAHistName(""); + fDoNDSmearing = true; + init(); + } + + /// Constructor with resolution histograms and efficiency + MomentumSmearer(TString resFileName, TString resPtHistName, TString resEtaHistName, TString resPhiPosHistName, TString resPhiNegHistName, TString effFileName, TString effHistName) + { + setResFileName(resFileName); + setResPtHistName(resPtHistName); + setResEtaHistName(resEtaHistName); + setResPhiPosHistName(resPhiPosHistName); + setResPhiNegHistName(resPhiNegHistName); + setEffFileName(effFileName); + setEffHistName(effHistName); + setDCAFileName(""); + setDCAHistName(""); + init(); + } + + /// Constructor with resolution histograms and efficiency and dca + MomentumSmearer(TString resFileName, TString resPtHistName, TString resEtaHistName, TString resPhiPosHistName, TString resPhiNegHistName, TString effFileName, TString effHistName, TString dcaFileName, TString dcaHistName) + { + setResFileName(resFileName); + setResPtHistName(resPtHistName); + setResEtaHistName(resEtaHistName); + setResPhiPosHistName(resPhiPosHistName); + setResPhiNegHistName(resPhiNegHistName); + setEffFileName(effFileName); + setEffHistName(effHistName); + setDCAFileName(dcaFileName); + setDCAHistName(dcaHistName); init(); } /// Default destructor ~MomentumSmearer() = default; + // template + void getResolutionHistos(TList* list) + { + + fResoPt = reinterpret_cast(list->FindObject(fResPtHistName)); + if (!fResoPt) { + LOGP(fatal, "Could not open {} from file {}", fResPtHistName.Data(), fResFileName.Data()); + } + + fResoEta = reinterpret_cast(list->FindObject(fResEtaHistName)); + if (!fResoEta) { + LOGP(fatal, "Could not open {} from file {}", fResEtaHistName.Data(), fResFileName.Data()); + } + + fResoPhi_Pos = reinterpret_cast(list->FindObject(fResPhiPosHistName)); + if (!fResoPhi_Pos) { + LOGP(fatal, "Could not open {} from file {}", fResPhiPosHistName.Data(), fResFileName.Data()); + } + + fResoPhi_Neg = reinterpret_cast(list->FindObject(fResPhiNegHistName)); + if (!fResoPhi_Neg) { + LOGP(fatal, "Could not open {} from file {}", fResPhiNegHistName.Data(), fResFileName.Data()); + } + } + + void fillVecReso(TH2F* fReso, std::vector& fVecReso) + { + TAxis* axisPt = fReso->GetXaxis(); + int nBinsPt = axisPt->GetNbins(); + for (int i = 1; i <= nBinsPt; i++) { + fVecReso.push_back(reinterpret_cast(fReso->ProjectionY("", i, i))); + } + } + + void fillVecResoND(THnSparseF* hs_reso) + { + LOGP(info, "prepare TH3D"); + fNCenBins = hs_reso->GetAxis(0)->GetNbins(); + fNPtBins = hs_reso->GetAxis(1)->GetNbins(); + fNEtaBins = hs_reso->GetAxis(2)->GetNbins(); + fNPhiBins = hs_reso->GetAxis(3)->GetNbins(); + fNChBins = hs_reso->GetAxis(4)->GetNbins(); + LOGF(info, "ncen = %d, npt = %d, neta = %d, nphi = %d, nch = %d without under- and overflow bins", fNCenBins, fNPtBins, fNEtaBins, fNPhiBins, fNChBins); + // fVecResoND.reserve(npt * neta * nphi * nch); + + fVecResoND.resize(fNCenBins, std::vector>>>(fNPtBins, std::vector>>(fNEtaBins, std::vector>(fNPhiBins, std::vector(fNChBins))))); + // fVecResoND.resize(fNPtBins, std::vector>>(fNEtaBins, std::vector>(fNPhiBins, std::vector(fNChBins)))); + // auto h3 = reinterpret_cast(hs_reso->Projection(4, 5, 6)); + // h3->SetName(Form("h3reso_pt%d_eta%d_phi%d_ch%d", 0, 0, 0, 0)); + // fVecResoND[0][0][0][0] = h3; + + for (int icen = 0; icen < fNCenBins; icen++) { + hs_reso->GetAxis(0)->SetRange(icen + 1, icen + 1); + for (int ipt = 0; ipt < fNPtBins; ipt++) { + hs_reso->GetAxis(1)->SetRange(ipt + 1, ipt + 1); + for (int ieta = 0; ieta < fNEtaBins; ieta++) { + hs_reso->GetAxis(2)->SetRange(ieta + 1, ieta + 1); + for (int iphi = 0; iphi < fNPhiBins; iphi++) { + hs_reso->GetAxis(3)->SetRange(iphi + 1, iphi + 1); + for (int ich = 0; ich < fNChBins; ich++) { + if (-0.5 < hs_reso->GetAxis(4)->GetBinCenter(ich + 1) && hs_reso->GetAxis(4)->GetBinCenter(ich + 1) < 0.5) { + continue; + } + hs_reso->GetAxis(4)->SetRange(ich + 1, ich + 1); + auto h3 = reinterpret_cast(hs_reso->Projection(5, 6, 7)); + h3->SetName(Form("h3reso_cen%d_pt%d_eta%d_phi%d_ch%d", icen, ipt, ieta, iphi, ich)); + h3->Scale(1.f, "width"); // convert ntrack to probability density + fVecResoND[icen][ipt][ieta][iphi][ich] = h3; + } // end of charge loop + } // end of phi loop + } // end of eta loop + } // end of pt loop + } // end of centrality loop + } + void init() { - if (fInitialized) + if (fInitialized) { return; + } - if (fResFileName.BeginsWith("alien://")) { + if ((fResFileName.BeginsWith("alien://") || fEffFileName.BeginsWith("alien://") || fDCAFileName.BeginsWith("alien://")) && (!fFromCcdb)) { TGrid::Connect("alien://"); } - // get resolution histo - LOGP(info, "Set Resolution histo"); - // Get Resolution map - TFile* fFile = TFile::Open(fResFileName); - if (!fFile) { - LOGP(error, "Could not open Resolution file {}", fResFileName.Data()); - return; - } - TObjArray* ArrResoPt = nullptr; - if (fFile->GetListOfKeys()->Contains(fResPtHistName)) { - ArrResoPt = reinterpret_cast(fFile->Get(fResPtHistName)); + LOGP(info, "Set resolution histos"); + TList* listRes = new TList(); + if (fFromCcdb) { + if (fCcdbPathRes.CompareTo("") != 0) { + fResType = 1; + listRes = fCcdb->getForTimeStamp(fCcdbPathRes.Data(), fTimestamp); + if (!listRes) { + LOGP(fatal, "Could not get resolution file from CCDB"); + return; + } + } } else { - LOGP(error, "Could not open {} from file {}", fResPtHistName.Data(), fResFileName.Data()); + if (fResFileName.CompareTo("") != 0) { + fResType = 1; + TFile* fFile = TFile::Open(fResFileName); + if (!fFile) { + LOGP(fatal, "Could not open resolution file {}", fResFileName.Data()); + return; + } + if (fFile->GetListOfKeys()->Contains("ccdb_object")) { + listRes = reinterpret_cast(fFile->Get("ccdb_object")); + } else { + for (TObject* keyAsObj : *(fFile->GetListOfKeys())) { + auto key = dynamic_cast(keyAsObj); + TObject* arr = nullptr; + fFile->GetObject(key->GetName(), arr); + listRes->Add(arr); + } + } + fFile->Close(); + } } - TObjArray* ArrResoEta = nullptr; - if (fFile->GetListOfKeys()->Contains(fResEtaHistName)) { - ArrResoEta = reinterpret_cast(fFile->Get(fResEtaHistName)); + LOGF(info, "Apply ND-correlated smearing: fDoNDSmearing = %d , fResNDHistName = %s", fDoNDSmearing, fResNDHistName.Data()); + + if (fDoNDSmearing) { + if (fResType != 0) { + fResoND = reinterpret_cast(listRes->FindObject(fResNDHistName)); + if (!fResoND) { + LOGP(fatal, "Could not open {} from file {}", fResNDHistName.Data(), fResFileName.Data()); + } + fillVecResoND(fResoND); + } } else { - LOGP(error, "Could not open {} from file {}", fResEtaHistName.Data(), fResFileName.Data()); + if (fResType != 0) { + fResoPt = reinterpret_cast(listRes->FindObject(fResPtHistName)); + if (!fResoPt) { + LOGP(fatal, "Could not open {} from file {}", fResPtHistName.Data(), fResFileName.Data()); + } + + fResoEta = reinterpret_cast(listRes->FindObject(fResEtaHistName)); + if (!fResoEta) { + LOGP(fatal, "Could not open {} from file {}", fResEtaHistName.Data(), fResFileName.Data()); + } + + fResoPhi_Pos = reinterpret_cast(listRes->FindObject(fResPhiPosHistName)); + if (!fResoPhi_Pos) { + LOGP(fatal, "Could not open {} from file {}", fResPhiPosHistName.Data(), fResFileName.Data()); + } + + fResoPhi_Neg = reinterpret_cast(listRes->FindObject(fResPhiNegHistName)); + if (!fResoPhi_Neg) { + LOGP(fatal, "Could not open {} from file {}", fResPhiNegHistName.Data(), fResFileName.Data()); + } + fillVecReso(fResoPt, fVecResoPt); + fillVecReso(fResoEta, fVecResoEta); + fillVecReso(fResoPhi_Pos, fVecResoPhi_Pos); + fillVecReso(fResoPhi_Neg, fVecResoPhi_Neg); + } } - TObjArray* ArrResoPhi_Pos = nullptr; - if (fFile->GetListOfKeys()->Contains(TString(fResPhiPosHistName))) { - ArrResoPhi_Pos = reinterpret_cast(fFile->Get(fResPhiPosHistName)); + if (!fFromCcdb) { + delete listRes; + } + + LOGP(info, "Set efficiency histos"); + TList* listEff = new TList(); + if (fFromCcdb) { + if (fCcdbPathEff.CompareTo("") != 0) { + fEffType = 1; + listEff = fCcdb->getForTimeStamp(fCcdbPathEff.Data(), fTimestamp); + if (!listEff) { + LOGP(fatal, "Could not get efficiency file from CCDB"); + return; + } + } } else { - LOGP(error, "Could not open {} from file {}", fResPhiPosHistName.Data(), fResFileName.Data()); + if (fEffFileName.CompareTo("") != 0) { + fEffType = 1; + TFile* fFile = TFile::Open(fEffFileName); + if (!fFile) { + LOGP(fatal, "Could not open efficiency file {}", fEffFileName.Data()); + return; + } + if (fFile->GetListOfKeys()->Contains("ccdb_object")) { + listEff = reinterpret_cast(fFile->Get("ccdb_object")); + } else { + for (TObject* keyAsObj : *(fFile->GetListOfKeys())) { + auto key = dynamic_cast(keyAsObj); + TObject* hist = nullptr; + fFile->GetObject(key->GetName(), hist); + listEff->Add(hist); + } + } + fFile->Close(); + } + } + if (fEffType != 0) { + fEff = reinterpret_cast(listEff->FindObject(fEffHistName)); + if (!fEff) { + LOGP(fatal, "Could not open {} from file {}", fEffHistName.Data(), fEffFileName.Data()); + } + // check which type is used + if (dynamic_cast(fEff)) { + fEffType = 3; + LOGP(info, "Use 3d efficiency histo (pt, eta, phi)"); + } else if (dynamic_cast(fEff)) { + fEffType = 2; + LOGP(info, "Use 2d efficiency histo (pt, eta)"); + } else if (dynamic_cast(fEff)) { + fEffType = 1; + LOGP(info, "Use 1d efficiency histo (pt)"); + } else { + LOGP(fatal, "Could not identify type of histogram {}", fEffHistName.Data()); + } } - TObjArray* ArrResoPhi_Neg = nullptr; - if (fFile->GetListOfKeys()->Contains(TString(fResPhiNegHistName))) { - ArrResoPhi_Neg = reinterpret_cast(fFile->Get(fResPhiNegHistName)); + if (!fFromCcdb) { + delete listEff; + } + + LOGP(info, "Set DCA histos"); + TList* listDCA = new TList(); + if (fFromCcdb) { + if (fCcdbPathDCA.CompareTo("") != 0) { + fDCAType = 1; + listDCA = fCcdb->getForTimeStamp(fCcdbPathDCA.Data(), fTimestamp); + if (!listDCA) { + LOGP(fatal, "Could not get DCA file from CCDB"); + return; + } + } } else { - LOGP(error, "Could not open {} from file {}", fResPhiNegHistName.Data(), fResFileName.Data()); + if (fDCAFileName.CompareTo("") != 0) { + fDCAType = 1; + TFile* fFile = TFile::Open(fDCAFileName); + if (!fFile) { + LOGP(fatal, "Could not open DCA file {}", fDCAFileName.Data()); + return; + } + if (fFile->GetListOfKeys()->Contains("ccdb_object")) { + listDCA = reinterpret_cast(fFile->Get("ccdb_object")); + } else { + for (TObject* keyAsObj : *(fFile->GetListOfKeys())) { + auto key = dynamic_cast(keyAsObj); + TObject* arr = nullptr; + fFile->GetObject(key->GetName(), arr); + listDCA->Add(arr); + } + } + fFile->Close(); + } + } + if (fDCAType != 0) { + fDCA = reinterpret_cast(listDCA->FindObject(fDCAHistName)); + if (!fDCA) { + LOGP(fatal, "Could not open {} from file {}", fDCAHistName.Data(), fDCAFileName.Data()); + } + fillVecReso(fDCA, fVecDCA); } - fArrResoPt = ArrResoPt; - fArrResoEta = ArrResoEta; - fArrResoPhi_Pos = ArrResoPhi_Pos; - fArrResoPhi_Neg = ArrResoPhi_Neg; - fFile->Close(); + if (!fFromCcdb) { + delete listDCA; + } fInitialized = true; } - void applySmearing(const int ch, const float ptgen, const float etagen, const float phigen, float& ptsmeared, float& etasmeared, float& phismeared) + void applySmearing(const float ptgen, const float vargen, const float multiply, float& varsmeared, TH2F* fReso, std::vector& fVecReso) { - // smear pt - int ptbin = reinterpret_cast(fArrResoPt->At(0))->GetXaxis()->FindBin(ptgen); + float ptgen_tmp = ptgen > fMinPtGen ? ptgen : fMinPtGen; + TAxis* axisPt = fReso->GetXaxis(); + int nBinsPt = axisPt->GetNbins(); + int ptbin = axisPt->FindBin(ptgen_tmp); if (ptbin < 1) { ptbin = 1; } - if (ptbin > fArrResoPt->GetLast()) { - ptbin = fArrResoPt->GetLast(); + if (ptbin > nBinsPt) { + ptbin = nBinsPt; } float smearing = 0.; - TH1D* thisHist = reinterpret_cast(fArrResoPt->At(ptbin)); - if (thisHist->GetEntries() > 0) { - smearing = thisHist->GetRandom() * ptgen; + if (fVecReso[ptbin - 1]->GetEntries() > 0) { + smearing = fVecReso[ptbin - 1]->GetRandom() * multiply; } - ptsmeared = ptgen - smearing; + varsmeared = vargen - smearing; + } - // smear eta - ptbin = reinterpret_cast(fArrResoEta->At(0))->GetXaxis()->FindBin(ptgen); + void applySmearing(const float centrality, const int ch, const float ptgen, const float etagen, const float phigen, float& ptsmeared, float& etasmeared, float& phismeared) + { + if (fResType == 0) { + ptsmeared = ptgen; + etasmeared = etagen; + phismeared = phigen; + return; + } + + if (fDoNDSmearing) { + if (centrality < 0) { + ptsmeared = ptgen; + etasmeared = etagen; + phismeared = phigen; + return; + } + applySmearingND(centrality, ch, ptgen, etagen, phigen, ptsmeared, etasmeared, phismeared); + } else { + applySmearing(ptgen, ptgen, ptgen, ptsmeared, fResoPt, fVecResoPt); + applySmearing(ptgen, etagen, 1., etasmeared, fResoEta, fVecResoEta); + if (ch > 0) { + applySmearing(ptgen, phigen, 1., phismeared, fResoPhi_Pos, fVecResoPhi_Pos); + } else { + applySmearing(ptgen, phigen, 1., phismeared, fResoPhi_Neg, fVecResoPhi_Neg); + } + } + } + + void applySmearingND(const float centrality, const int ch, const float ptgen, const float etagen, const float phigen, float& ptsmeared, float& etasmeared, float& phismeared) + { + float ptgen_tmp = ptgen > fMinPtGen ? ptgen : fMinPtGen; + int cenbin = fResoND->GetAxis(0)->FindBin(centrality); + int ptbin = fResoND->GetAxis(1)->FindBin(ptgen_tmp); + int etabin = fResoND->GetAxis(2)->FindBin(etagen); + int phibin = fResoND->GetAxis(3)->FindBin(phigen); + int chbin = fResoND->GetAxis(4)->FindBin(ch); + + // protection + if (cenbin < 1) { + cenbin = 1; + } else if (cenbin > fNCenBins) { + cenbin = fNCenBins; + } + + // protection if (ptbin < 1) { ptbin = 1; + } else if (ptbin > fNPtBins) { + ptbin = fNPtBins; } - if (ptbin > fArrResoEta->GetLast()) { - ptbin = fArrResoEta->GetLast(); + + // protection + if (etabin < 1) { + etabin = 1; + } else if (etabin > fNEtaBins) { + etabin = fNEtaBins; } - smearing = 0.; - thisHist = reinterpret_cast(fArrResoEta->At(ptbin)); - if (thisHist->GetEntries() > 0) { - smearing = thisHist->GetRandom(); + + // protection + if (phibin < 1) { + phibin = 1; + } else if (phibin > fNPhiBins) { + phibin = fNPhiBins; } - etasmeared = etagen - smearing; - // smear phi - ptbin = reinterpret_cast(fArrResoPhi_Pos->At(0))->GetXaxis()->FindBin(ptgen); + // protection + if (chbin < 1) { + chbin = 1; + } else if (chbin > fNChBins) { + chbin = fNChBins; + } + + double dpt_rel = 0, deta = 0, dphi = 0; + if (fVecResoND[cenbin - 1][ptbin - 1][etabin - 1][phibin - 1][chbin - 1]->GetEntries() > 0) { + fVecResoND[cenbin - 1][ptbin - 1][etabin - 1][phibin - 1][chbin - 1]->GetRandom3(dpt_rel, deta, dphi); + } + ptsmeared = ptgen - dpt_rel * ptgen; + etasmeared = etagen - deta; + phismeared = phigen - dphi; + // LOGF(info, "ptgen = %f (GeV/c), etagen = %f, phigen = %f (rad.), ptsmeared = %f (GeV/c), etasmeared = %f, phismeared = %f (rad.)", ptgen, etagen, phigen, ptsmeared, etasmeared, phismeared); + } + + float getEfficiency(float pt, float eta, float phi) + { + + if (fEffType == 0) { + return 1.; + } + + if (fEffType == 1) { + TH1F* hist = reinterpret_cast(fEff); + int ptbin = hist->GetXaxis()->FindBin(pt); + int ptbin_max = hist->GetXaxis()->GetNbins(); + // make sure that no underflow or overflow bins are used + if (ptbin < 1) + ptbin = 1; + else if (ptbin > ptbin_max) + ptbin = ptbin_max; + return hist->GetBinContent(ptbin); + } + + if (fEffType == 2) { + TH2F* hist = reinterpret_cast(fEff); + int ptbin = hist->GetXaxis()->FindBin(pt); + int ptbin_max = hist->GetXaxis()->GetNbins(); + int etabin = hist->GetYaxis()->FindBin(eta); + int etabin_max = hist->GetYaxis()->GetNbins(); + // make sure that no underflow or overflow bins are used + if (ptbin < 1) + ptbin = 1; + else if (ptbin > ptbin_max) + ptbin = ptbin_max; + if (etabin < 1) + etabin = 1; + else if (etabin > etabin_max) + etabin = etabin_max; + return hist->GetBinContent(ptbin, etabin); + } + + if (fEffType == 3) { + TH3F* hist = reinterpret_cast(fEff); + int ptbin = hist->GetXaxis()->FindBin(pt); + int ptbin_max = hist->GetXaxis()->GetNbins(); + int etabin = hist->GetYaxis()->FindBin(eta); + int etabin_max = hist->GetYaxis()->GetNbins(); + int phibin = hist->GetZaxis()->FindBin(phi); + int phibin_max = hist->GetZaxis()->GetNbins(); + // make sure that no underflow or overflow bins are used + if (ptbin < 1) + ptbin = 1; + else if (ptbin > ptbin_max) + ptbin = ptbin_max; + if (etabin < 1) + etabin = 1; + else if (etabin > etabin_max) + etabin = etabin_max; + if (phibin < 1) + phibin = 1; + else if (phibin > phibin_max) + phibin = phibin_max; + return hist->GetBinContent(ptbin, etabin, phibin); + } + + return 1.; + } + + float getDCA(float ptsmeared) + { + if (fDCAType == 0) { + return 0.; + } + + TAxis* axisPt = fDCA->GetXaxis(); + int nBinsPt = axisPt->GetNbins(); + int ptbin = axisPt->FindBin(ptsmeared); if (ptbin < 1) { ptbin = 1; } - if (ptbin > fArrResoPhi_Pos->GetLast()) { - ptbin = fArrResoPhi_Pos->GetLast(); - } - smearing = 0.; - if (ch < 0) { - thisHist = reinterpret_cast(fArrResoPhi_Neg->At(ptbin)); - } else { - thisHist = reinterpret_cast(fArrResoPhi_Pos->At(ptbin)); + if (ptbin > nBinsPt) { + ptbin = nBinsPt; } - if (thisHist->GetEntries() > 0) { - smearing = thisHist->GetRandom(); + float dca = 0.; + if (fVecDCA[ptbin - 1]->GetEntries() > 0) { + dca = fVecDCA[ptbin - 1]->GetRandom(); } - phismeared = phigen - smearing; + return dca; } // setters + void setNDSmearing(bool flag) { fDoNDSmearing = flag; } void setResFileName(TString resFileName) { fResFileName = resFileName; } + void setResNDHistName(TString resNDHistName) { fResNDHistName = resNDHistName; } void setResPtHistName(TString resPtHistName) { fResPtHistName = resPtHistName; } void setResEtaHistName(TString resEtaHistName) { fResEtaHistName = resEtaHistName; } void setResPhiPosHistName(TString resPhiPosHistName) { fResPhiPosHistName = resPhiPosHistName; } void setResPhiNegHistName(TString resPhiNegHistName) { fResPhiNegHistName = resPhiNegHistName; } + void setEffFileName(TString effFileName) { fEffFileName = effFileName; } + void setEffHistName(TString effHistName) { fEffHistName = effHistName; } + void setDCAFileName(TString dcaFileName) { fDCAFileName = dcaFileName; } + void setDCAHistName(TString dcaHistName) { fDCAHistName = dcaHistName; } + void setCcdbPathRes(TString ccdbPathRes) { fCcdbPathRes = ccdbPathRes; } + void setCcdbPathEff(TString ccdbPathEff) { fCcdbPathEff = ccdbPathEff; } + void setCcdbPathDCA(TString ccdbPathDCA) { fCcdbPathDCA = ccdbPathDCA; } + void setCcdb(Service ccdb) + { + fCcdb = ccdb; + fFromCcdb = true; + } + void setTimestamp(int64_t timestamp) { fTimestamp = timestamp; } + void setMinPt(float minpt) { fMinPtGen = minpt; } // getters + bool getNDSmearing() { return fDoNDSmearing; } TString getResFileName() { return fResFileName; } + TString getResNDHistName() { return fResNDHistName; } TString getResPtHistName() { return fResPtHistName; } TString getResEtaHistName() { return fResEtaHistName; } TString getResPhiPosHistName() { return fResPhiPosHistName; } TString getResPhiNegHistName() { return fResPhiNegHistName; } - TObjArray* getArrResoPt() { return fArrResoPt; } - TObjArray* getArrResoEta() { return fArrResoEta; } - TObjArray* getArrResoPhiPos() { return fArrResoPhi_Pos; } - TObjArray* getArrResoPhiNeg() { return fArrResoPhi_Neg; } + TString getEffFileName() { return fEffFileName; } + TString getEffHistName() { return fEffHistName; } + TString getDCAFileName() { return fDCAFileName; } + TString getDCaHistName() { return fDCAHistName; } + TH2F* getHistResoPt() { return fResoPt; } + TH2F* getHistResoEta() { return fResoEta; } + TH2F* getHistResoPhiPos() { return fResoPhi_Pos; } + TH2F* getHistResoPhiNeg() { return fResoPhi_Neg; } + TObject* getHistEff() { return fEff; } + TString getCcdbPathRes() { return fCcdbPathRes; } + TString getCcdbPathEff() { return fCcdbPathEff; } + TString getCcdbPathDCA() { return fCcdbPathDCA; } + float getMinPt() { return fMinPtGen; } private: bool fInitialized = false; + bool fDoNDSmearing = false; TString fResFileName; + TString fResNDHistName; TString fResPtHistName; TString fResEtaHistName; TString fResPhiPosHistName; TString fResPhiNegHistName; - TObjArray* fArrResoPt; - TObjArray* fArrResoEta; - TObjArray* fArrResoPhi_Pos; - TObjArray* fArrResoPhi_Neg; + TString fEffFileName; + TString fEffHistName; + TString fDCAFileName; + TString fDCAHistName; + TString fCcdbPathRes; + TString fCcdbPathEff; + TString fCcdbPathDCA; + int fEffType = 0; + int fResType = 0; + int fDCAType = 0; + THnSparseF* fResoND; + TH2F* fResoPt; + TH2F* fResoEta; + TH2F* fResoPhi_Pos; + TH2F* fResoPhi_Neg; + std::vector>>>> fVecResoND; + int fNCenBins = 1; + int fNPtBins = 1; + int fNEtaBins = 1; + int fNPhiBins = 1; + int fNChBins = 1; + std::vector fVecResoPt; + std::vector fVecResoEta; + std::vector fVecResoPhi_Pos; + std::vector fVecResoPhi_Neg; + TObject* fEff; + TH2F* fDCA; + std::vector fVecDCA; + int64_t fTimestamp; + bool fFromCcdb = false; + Service fCcdb; + float fMinPtGen = -1.f; }; #endif // PWGEM_DILEPTON_UTILS_MOMENTUMSMEARER_H_ diff --git a/PWGEM/Dilepton/Utils/PairUtilities.h b/PWGEM/Dilepton/Utils/PairUtilities.h new file mode 100644 index 00000000000..a1010e76435 --- /dev/null +++ b/PWGEM/Dilepton/Utils/PairUtilities.h @@ -0,0 +1,352 @@ +// 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. + +/// \commonly used to calculate pair variables +/// \author daiki.sekihata@cern.ch + +#ifndef PWGEM_DILEPTON_UTILS_PAIRUTILITIES_H_ +#define PWGEM_DILEPTON_UTILS_PAIRUTILITIES_H_ + +#include +#include +#include "Math/SMatrix.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" +#include "Common/Core/RecoDecay.h" +#include "ReconstructionDataFormats/TrackFwd.h" + +//_______________________________________________________________________ +namespace o2::aod::pwgem::dilepton::utils::pairutil +{ + +enum class DileptonPairType : int { + kDielectron = 0, + kDimuon = 1, +}; +enum class DileptonAnalysisType : int { + kQC = 0, + kUPC = 1, + kFlowV2 = 2, + kFlowV3 = 3, + kPolarization = 4, + kVM = 5, + kHFll = 6, +}; + +enum class DileptonPrefilterBit : int { + kElFromPC = 0, // electron from photon conversion + kElFromPi0_1 = 1, // electron from pi0 dalitz decay, threshold 1 + kElFromPi0_2 = 2, // electron from pi0 dalitz decay, threshold 2 + kElFromPi0_3 = 3, // electron from pi0 dalitz decay, threshold 3 +}; + +enum class DileptonPrefilterBitDerived : int { + kMee = 0, // reject tracks from pi0 dalitz decays at very low mass where S/B > 1 + kPhiV = 1, // reject tracks from photon conversions + kSplitOrMergedTrackLS = 2, // reject split or marged tracks in LS pairs based on momentum deta-dphi at PV + kSplitOrMergedTrackULS = 3, // reject split or marged tracks in ULS pairs based on momentum deta-dphi at PV +}; + +using SMatrix55 = ROOT::Math::SMatrix>; +using SMatrix5 = ROOT::Math::SVector; + +//_______________________________________________________________________ +template +void getAngleHX(TTrack1 const& t1, TTrack2 const& t2, const float m1, const float m2, const float beamE1, const float beamE2, const float beamP1, const float beamP2, float& cos_thetaHX, float& phiHX) +{ + ROOT::Math::PxPyPzEVector v1(t1.px(), t1.py(), t1.pz(), std::sqrt(std::pow(t1.p(), 2) + std::pow(m1, 2))); + ROOT::Math::PxPyPzEVector v2(t2.px(), t2.py(), t2.pz(), std::sqrt(std::pow(t2.p(), 2) + std::pow(m2, 2))); + ROOT::Math::PxPyPzEVector v12 = v1 + v2; + + ROOT::Math::PxPyPzEVector Beam1(0., 0., -beamP1, beamE1); + ROOT::Math::PxPyPzEVector Beam2(0., 0., beamP2, beamE2); + + // Boost to center of mass frame. i.e. rest frame of pair + ROOT::Math::Boost boostv12{v12.BoostToCM()}; + ROOT::Math::XYZVectorF v1_CM{(boostv12(v1).Vect()).Unit()}; + ROOT::Math::XYZVectorF v2_CM{(boostv12(v2).Vect()).Unit()}; + ROOT::Math::XYZVectorF Beam1_CM{(boostv12(Beam1).Vect()).Unit()}; + ROOT::Math::XYZVectorF Beam2_CM{(boostv12(Beam2).Vect()).Unit()}; + // LOGF(info, "boostv12(v12).Vect().X() = %f, boostv12(v12).Vect().Y() = %f, boostv12(v12).Vect().Z() = %f", boostv12(v12).Vect().X(), boostv12(v12).Vect().Y(), boostv12(v12).Vect().Z()); // expected to be (0,0,0) + + // Helicity frame + ROOT::Math::XYZVectorF zaxis_HX{(v12.Vect()).Unit()}; + ROOT::Math::XYZVectorF yaxis_HX{(Beam1_CM.Cross(Beam2_CM)).Unit()}; + ROOT::Math::XYZVectorF xaxis_HX{(yaxis_HX.Cross(zaxis_HX)).Unit()}; + + // pdgCode : 11 for electron, -11 for positron + // pdgCode : 13 for negative muon, -13 for positive muon + // LOGF(info, "zaxis_HX.Dot(v1_CM) = %f , zaxis_HX.Dot(v2_CM) = %f", zaxis_HX.Dot(v1_CM), zaxis_HX.Dot(v2_CM)); // absolute value is identical. only sign is opposite. + + if constexpr (isMC) { + cos_thetaHX = t1.pdgCode() < 0 ? zaxis_HX.Dot(v1_CM) : zaxis_HX.Dot(v2_CM); + phiHX = t1.pdgCode() < 0 ? std::atan2(yaxis_HX.Dot(v1_CM), xaxis_HX.Dot(v1_CM)) : std::atan2(yaxis_HX.Dot(v2_CM), xaxis_HX.Dot(v2_CM)); + } else { + cos_thetaHX = t1.sign() > 0 ? zaxis_HX.Dot(v1_CM) : zaxis_HX.Dot(v2_CM); + phiHX = t1.sign() > 0 ? std::atan2(yaxis_HX.Dot(v1_CM), xaxis_HX.Dot(v1_CM)) : std::atan2(yaxis_HX.Dot(v2_CM), xaxis_HX.Dot(v2_CM)); + } +} + +//_______________________________________________________________________ +//_______________________________________________________________________ +template +void getAngleCS(TTrack1 const& t1, TTrack2 const& t2, const float m1, const float m2, const float beamE1, const float beamE2, const float beamP1, const float beamP2, float& cos_thetaCS, float& phiCS) +{ + ROOT::Math::PxPyPzEVector v1(t1.px(), t1.py(), t1.pz(), std::sqrt(std::pow(t1.p(), 2) + std::pow(m1, 2))); + ROOT::Math::PxPyPzEVector v2(t2.px(), t2.py(), t2.pz(), std::sqrt(std::pow(t2.p(), 2) + std::pow(m2, 2))); + ROOT::Math::PxPyPzEVector v12 = v1 + v2; + + ROOT::Math::PxPyPzEVector Beam1(0., 0., -beamP1, beamE1); + ROOT::Math::PxPyPzEVector Beam2(0., 0., beamP2, beamE2); + + // Boost to center of mass frame. i.e. rest frame of pair + ROOT::Math::Boost boostv12{v12.BoostToCM()}; + ROOT::Math::XYZVectorF v1_CM{(boostv12(v1).Vect()).Unit()}; + ROOT::Math::XYZVectorF v2_CM{(boostv12(v2).Vect()).Unit()}; + ROOT::Math::XYZVectorF Beam1_CM{(boostv12(Beam1).Vect()).Unit()}; + ROOT::Math::XYZVectorF Beam2_CM{(boostv12(Beam2).Vect()).Unit()}; + // LOGF(info, "boostv12(v12).Vect().X() = %f, boostv12(v12).Vect().Y() = %f, boostv12(v12).Vect().Z() = %f", boostv12(v12).Vect().X(), boostv12(v12).Vect().Y(), boostv12(v12).Vect().Z()); // expected to be (0,0,0) + + // Collins-Soper frame + ROOT::Math::XYZVectorF zaxis_CS{((Beam1_CM.Unit() - Beam2_CM.Unit()).Unit())}; + ROOT::Math::XYZVectorF yaxis_CS{(Beam1_CM.Cross(Beam2_CM)).Unit()}; + ROOT::Math::XYZVectorF xaxis_CS{(yaxis_CS.Cross(zaxis_CS)).Unit()}; + + // pdgCode : 11 for electron, -11 for positron + // pdgCode : 13 for negative muon, -13 for positive muon + // LOGF(info, "zaxis_CS.Dot(v1_CM) = %f , zaxis_CS.Dot(v2_CM) = %f", zaxis_CS.Dot(v1_CM), zaxis_CS.Dot(v2_CM)); // absolute value is identical. only sign is opposite. + + if constexpr (isMC) { + cos_thetaCS = t1.pdgCode() < 0 ? zaxis_CS.Dot(v1_CM) : zaxis_CS.Dot(v2_CM); + phiCS = t1.pdgCode() < 0 ? std::atan2(yaxis_CS.Dot(v1_CM), xaxis_CS.Dot(v1_CM)) : std::atan2(yaxis_CS.Dot(v2_CM), xaxis_CS.Dot(v2_CM)); + } else { + cos_thetaCS = t1.sign() > 0 ? zaxis_CS.Dot(v1_CM) : zaxis_CS.Dot(v2_CM); + phiCS = t1.sign() > 0 ? std::atan2(yaxis_CS.Dot(v1_CM), xaxis_CS.Dot(v1_CM)) : std::atan2(yaxis_CS.Dot(v2_CM), xaxis_CS.Dot(v2_CM)); + } +} + +//_______________________________________________________________________ +template +bool isSVFound(TDCAFitter fitter, TCollision const& collision, TTrack const& t1, TTrack const& t2, float& pca, float& lxy, float& cosPA) +{ + std::array svpos = {0.}; // secondary vertex position + std::array pvec0 = {0.}; + std::array pvec1 = {0.}; + auto pTrack = getTrackParCov(t1); + auto nTrack = getTrackParCov(t2); + + int nCand = fitter.process(pTrack, nTrack); + if (nCand != 0) { + fitter.propagateTracksToVertex(); + const auto& vtx = fitter.getPCACandidate(); + for (int i = 0; i < 3; i++) { + svpos[i] = vtx[i]; + } + fitter.getTrack(0).getPxPyPzGlo(pvec0); // positive + fitter.getTrack(1).getPxPyPzGlo(pvec1); // negative + std::array pvxyz{pvec0[0] + pvec1[0], pvec0[1] + pvec1[1], pvec0[2] + pvec1[2]}; + // float pt = RecoDecay::sqrtSumOfSquares(pvxyz[0], pvxyz[1]); + // LOGF(info, "pair pT = %f GeV/c at sv", pt); + + pca = std::sqrt(fitter.getChi2AtPCACandidate()); // distance between 2 legs. + lxy = RecoDecay::sqrtSumOfSquares(svpos[0] - collision.posX(), svpos[1] - collision.posY()); + cosPA = RecoDecay::cpa(std::array{collision.posX(), collision.posY(), collision.posZ()}, svpos, pvxyz); + return true; + } else { + pca = 999.f; + lxy = 999.f; + cosPA = 999.f; + return false; + } +} + +//_______________________________________________________________________ +// function call without cosPA +template +bool isSVFound(TDCAFitter fitter, TCollision const& collision, TTrack const& t1, TTrack const& t2, float& pca, float& lxy) +{ + float cosPA = 999.f; + return isSVFound(fitter, collision, t1, t2, pca, lxy, cosPA); +} +//_______________________________________________________________________ +template +bool isSVFoundFwd(TFwdDCAFitter fitter, TCollision const& collision, TTrack const& t1, TTrack const& t2, float& pca, float& lxy) +{ + std::array svpos = {0.}; // secondary vertex position + // std::array pvec0 = {0.}; + // std::array pvec1 = {0.}; + + SMatrix5 t1pars(t1.x(), t1.y(), t1.phi(), t1.tgl(), t1.signed1Pt()); + std::vector v1{t1.cXX(), t1.cXY(), t1.cYY(), t1.cPhiX(), t1.cPhiY(), + t1.cPhiPhi(), t1.cTglX(), t1.cTglY(), t1.cTglPhi(), t1.cTglTgl(), + t1.c1PtX(), t1.c1PtY(), t1.c1PtPhi(), t1.c1PtTgl(), t1.c1Pt21Pt2()}; + + SMatrix55 t1covs(v1.begin(), v1.end()); + o2::track::TrackParCovFwd pTrack{t1.z(), t1pars, t1covs, t1.chi2()}; + + SMatrix5 t2pars(t2.x(), t2.y(), t2.phi(), t2.tgl(), t2.signed1Pt()); + std::vector v2{t2.cXX(), t2.cXY(), t2.cYY(), t2.cPhiX(), t2.cPhiY(), + t2.cPhiPhi(), t2.cTglX(), t2.cTglY(), t2.cTglPhi(), t2.cTglTgl(), + t2.c1PtX(), t2.c1PtY(), t2.c1PtPhi(), t2.c1PtTgl(), t2.c1Pt21Pt2()}; + SMatrix55 t2covs(v2.begin(), v2.end()); + o2::track::TrackParCovFwd nTrack{t2.z(), t2pars, t2covs, t2.chi2()}; + + // if (abs(t1.cXX()) < 1e-6 || abs(t2.cXX()) < 1e-6) { + // pca = 999.f; + // lxy = 999.f; + // return false; + // } + + int nCand = fitter.process(pTrack, nTrack); + if (nCand != 0) { + fitter.FwdpropagateTracksToVertex(); + const auto& vtx = fitter.getPCACandidate(); + for (int i = 0; i < 3; i++) { + svpos[i] = vtx[i]; + } + // fitter.getTrack(0).getPxPyPzGlo(pvec0); // positive + // fitter.getTrack(1).getPxPyPzGlo(pvec1); // negative + // std::array pvxyz{pvec0[0] + pvec1[0], pvec0[1] + pvec1[1], pvec0[2] + pvec1[2]}; + // float pt = RecoDecay::sqrtSumOfSquares(pvxyz[0], pvxyz[1]); + // LOGF(info, "pair pT = %f GeV/c at sv", pt); + + pca = std::sqrt(fitter.getChi2AtPCACandidate()); // distance between 2 legs. + lxy = RecoDecay::sqrtSumOfSquares(svpos[0] - collision.posX(), svpos[1] - collision.posY()); + return true; + } else { + pca = 999.f; + lxy = 999.f; + return false; + } +} +//_______________________________________________________________________ +inline float getPhivPair(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg, int cpos, int cneg, float bz) +{ + // cos(phiv) = w*a /|w||a| + // with w = u x v + // and a = u x z / |u x z| , unit vector perpendicular to v12 and z-direction (magnetic field) + // u = v12 / |v12| , the unit vector of v12 + // v = v1 x v2 / |v1 x v2| , unit vector perpendicular to v1 and v2 + + // momentum of e+ and e- in (ax,ay,az) axis. Note that az=0 by definition. + // vector product of pep X pem + // std::array arr_pos{t1.GetPx(), t1.GetPy(), t1.GetPz()}; + // std::array arr_ele{t2.GetPx(), t2.GetPy(), t2.GetPz()}; + std::array arr_pos{pxpos, pypos, pzpos}; + std::array arr_ele{pxneg, pyneg, pzneg}; + std::array pos_x_ele{0, 0, 0}; + // LOGF(info, "Q1 = %d , Q2 = %d", cpos, cneg); + float ptpos = std::sqrt(std::pow(pxpos, 2) + std::pow(pypos, 2)); + float ptneg = std::sqrt(std::pow(pxneg, 2) + std::pow(pyneg, 2)); + + if (cpos * cneg > 0) { // Like Sign + if (bz < 0) { + // if (cpos > 0) { + if (cpos * ptpos > cneg * ptneg) { + pos_x_ele = RecoDecay::crossProd(arr_pos, arr_ele); + } else { + pos_x_ele = RecoDecay::crossProd(arr_ele, arr_pos); + } + } else { + // if (cpos > 0) { + if (cpos * ptpos > cneg * ptneg) { + pos_x_ele = RecoDecay::crossProd(arr_ele, arr_pos); + } else { + pos_x_ele = RecoDecay::crossProd(arr_pos, arr_ele); + } + } + } else { // Unlike Sign + if (bz > 0) { + // if (cpos > 0) { + if (cpos * ptpos > cneg * ptneg) { + pos_x_ele = RecoDecay::crossProd(arr_pos, arr_ele); + } else { + pos_x_ele = RecoDecay::crossProd(arr_ele, arr_pos); + } + } else { + // if (cpos > 0) { + if (cpos * ptpos > cneg * ptneg) { + pos_x_ele = RecoDecay::crossProd(arr_ele, arr_pos); + } else { + pos_x_ele = RecoDecay::crossProd(arr_pos, arr_ele); + } + } + } + + // unit vector of pep X pem + float vx = pos_x_ele[0] / RecoDecay::sqrtSumOfSquares(pos_x_ele[0], pos_x_ele[1], pos_x_ele[2]); + float vy = pos_x_ele[1] / RecoDecay::sqrtSumOfSquares(pos_x_ele[0], pos_x_ele[1], pos_x_ele[2]); + float vz = pos_x_ele[2] / RecoDecay::sqrtSumOfSquares(pos_x_ele[0], pos_x_ele[1], pos_x_ele[2]); + + // unit vector of (pep+pem) + float ux = (pxpos + pxneg) / RecoDecay::sqrtSumOfSquares(pxpos + pxneg, pypos + pyneg, pzpos + pzneg); + float uy = (pypos + pyneg) / RecoDecay::sqrtSumOfSquares(pxpos + pxneg, pypos + pyneg, pzpos + pzneg); + float uz = (pzpos + pzneg) / RecoDecay::sqrtSumOfSquares(pxpos + pxneg, pypos + pyneg, pzpos + pzneg); + + float ax = uy / std::sqrt(ux * ux + uy * uy); + float ay = -ux / std::sqrt(ux * ux + uy * uy); + + // The third axis defined by vector product (ux,uy,uz)X(vx,vy,vz) + float wx = uy * vz - uz * vy; + float wy = uz * vx - ux * vz; + // by construction, (wx,wy,wz) must be a unit vector. Measure angle between (wx,wy,wz) and (ax,ay,0). + // The angle between them should be small if the pair is conversion. This function then returns values close to pi! + auto clipToPM1 = [](float x) { return x < -1.f ? -1.f : (x > 1.f ? 1.f : x); }; + + // if (!std::isfinite(std::acos(wx * ax + wy * ay))) { + // LOGF(info, "pxpos = %f, pypos = %f, pzpos = %f", pxpos, pypos, pzpos); + // LOGF(info, "pxneg = %f, pyneg = %f, pzneg = %f", pxneg, pyneg, pzneg); + // LOGF(info, "pos_x_ele[0] = %f, pos_x_ele[1] = %f, pos_x_ele[2] = %f", pos_x_ele[0], pos_x_ele[1], pos_x_ele[2]); + // LOGF(info, "ux = %f, uy = %f, uz = %f", ux, uy, uz); + // LOGF(info, "ax = %f, ay = %f", ax, ay); + // LOGF(info, "wx = %f, wy = %f", wx, wy); + // LOGF(info, "wx * ax + wy * ay = %f", wx * ax + wy * ay); + // LOGF(info, "std::acos(wx * ax + wy * ay) = %f", std::acos(wx * ax + wy * ay)); + // LOGF(info, "std::acos(clipToPM1(wx * ax + wy * ay)) = %f", std::acos(clipToPM1(wx * ax + wy * ay))); + // } + + return std::acos(clipToPM1(wx * ax + wy * ay)); // phiv in [0,pi] //cosPhiV = wx * ax + wy * ay; +} +//_______________________________________________________________________ +inline float getPsiPair(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) +{ + auto clipToPM1 = [](float x) { return x < -1.f ? -1.f : (x > 1.f ? 1.f : x); }; + float ptot2 = RecoDecay::p2(pxpos, pypos, pzpos) * RecoDecay::p2(pxneg, pyneg, pzneg); + float argcos = RecoDecay::dotProd(std::array{pxpos, pypos, pzpos}, std::array{pxneg, pyneg, pzneg}) / std::sqrt(ptot2); + float thetaPos = std::atan2(RecoDecay::sqrtSumOfSquares(pxpos, pypos), pzpos); + float thetaNeg = std::atan2(RecoDecay::sqrtSumOfSquares(pxneg, pyneg), pzneg); + float argsin = (thetaNeg - thetaPos) / std::acos(clipToPM1(argcos)); + return std::asin(clipToPM1(argsin)); +} +//_______________________________________________________________________ +inline float getOpeningAngle(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) +{ + auto clipToPM1 = [](float x) { return x < -1.f ? -1.f : (x > 1.f ? 1.f : x); }; + float ptot2 = RecoDecay::p2(pxpos, pypos, pzpos) * RecoDecay::p2(pxneg, pyneg, pzneg); + float argcos = RecoDecay::dotProd(std::array{pxpos, pypos, pzpos}, std::array{pxneg, pyneg, pzneg}) / std::sqrt(ptot2); + return std::acos(clipToPM1(argcos)); +} +//_______________________________________________________________________ +inline float pairDCAQuadSum(const float dca1, const float dca2) +{ + return std::sqrt((dca1 * dca1 + dca2 * dca2) / 2.); +} + +//_______________________________________________________________________ +inline float pairDCASignQuadSum(const float dca1, const float dca2, const float charge1, const float charge2) +{ + return charge1 * charge2 * TMath::Sign(1., dca1) * TMath::Sign(1., dca2) * std::sqrt((dca1 * dca1 + dca2 * dca2) / 2.); +} + +//_______________________________________________________________________ +} // namespace o2::aod::pwgem::dilepton::utils::pairutil +#endif // PWGEM_DILEPTON_UTILS_PAIRUTILITIES_H_ diff --git a/PWGEM/PhotonMeson/Core/CMakeLists.txt b/PWGEM/PhotonMeson/Core/CMakeLists.txt index 9e00a1a4604..72a17aa1497 100644 --- a/PWGEM/PhotonMeson/Core/CMakeLists.txt +++ b/PWGEM/PhotonMeson/Core/CMakeLists.txt @@ -10,23 +10,23 @@ # or submit itself to any jurisdiction. o2physics_add_library(PWGEMPhotonMesonCore - SOURCES EMEventCut.cxx - V0PhotonCut.cxx + SOURCES V0PhotonCut.cxx PHOSPhotonCut.cxx DalitzEECut.cxx EMCPhotonCut.cxx PairCut.cxx + EMPhotonEventCut.cxx CutsLibrary.cxx HistogramsLibrary.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore) + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore) o2physics_target_root_dictionary(PWGEMPhotonMesonCore - HEADERS EMEventCut.h - V0PhotonCut.h + HEADERS V0PhotonCut.h DalitzEECut.h PHOSPhotonCut.h EMCPhotonCut.h PairCut.h + EMPhotonEventCut.h CutsLibrary.h HistogramsLibrary.h LINKDEF PWGEMPhotonMesonCoreLinkDef.h) diff --git a/PWGEM/PhotonMeson/Core/CutsLibrary.cxx b/PWGEM/PhotonMeson/Core/CutsLibrary.cxx index be3a6297fd4..c2f313e6e62 100644 --- a/PWGEM/PhotonMeson/Core/CutsLibrary.cxx +++ b/PWGEM/PhotonMeson/Core/CutsLibrary.cxx @@ -36,9 +36,9 @@ std::vector splitString(const std::string& str, char delimiter) return ret; } //_______________________________________________ -EMEventCut* o2::aod::pwgem::photon::eventcuts::GetCut(const char* cutName) +EMPhotonEventCut* o2::aod::pwgem::photon::eventcuts::GetCut(const char* cutName) { - EMEventCut* cut = new EMEventCut(cutName, cutName); + EMPhotonEventCut* cut = new EMPhotonEventCut(cutName, cutName); std::string nameStr = cutName; if (!nameStr.compare("nocut")) { @@ -49,7 +49,7 @@ EMEventCut* o2::aod::pwgem::photon::eventcuts::GetCut(const char* cutName) cut->SetRequireNoITSROFB(false); cut->SetRequireNoSameBunchPileup(false); cut->SetRequireVertexITSTPC(false); - cut->SetRequireIsGoodZvtxFT0vsPV(false); + cut->SetRequireGoodZvtxFT0vsPV(false); return cut; } @@ -61,7 +61,7 @@ EMEventCut* o2::aod::pwgem::photon::eventcuts::GetCut(const char* cutName) cut->SetRequireNoITSROFB(false); cut->SetRequireNoSameBunchPileup(false); cut->SetRequireVertexITSTPC(false); - cut->SetRequireIsGoodZvtxFT0vsPV(false); + cut->SetRequireGoodZvtxFT0vsPV(false); return cut; } @@ -73,7 +73,7 @@ EMEventCut* o2::aod::pwgem::photon::eventcuts::GetCut(const char* cutName) cut->SetRequireNoITSROFB(false); // included in sel8 cut->SetRequireNoSameBunchPileup(false); cut->SetRequireVertexITSTPC(false); - cut->SetRequireIsGoodZvtxFT0vsPV(false); + cut->SetRequireGoodZvtxFT0vsPV(false); if (nameStr.find("notfb") != std::string::npos) { cut->SetRequireNoTFB(true); @@ -88,7 +88,7 @@ EMEventCut* o2::aod::pwgem::photon::eventcuts::GetCut(const char* cutName) cut->SetRequireVertexITSTPC(true); } if (nameStr.find("goodvtx") != std::string::npos) { - cut->SetRequireIsGoodZvtxFT0vsPV(true); + cut->SetRequireGoodZvtxFT0vsPV(true); } return cut; @@ -104,114 +104,63 @@ V0PhotonCut* o2::aod::pwgem::photon::pcmcuts::GetCut(const char* cutName) V0PhotonCut* cut = new V0PhotonCut(cutName, cutName); std::string nameStr = cutName; - if (!nameStr.compare("analysis")) { - // for track - cut->SetTrackPtRange(0.04f, 1e10f); - // cut->SetTrackEtaRange(-0.9, +0.9); - cut->SetMinNCrossedRowsTPC(20); - cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); - cut->SetChi2PerClusterTPC(0.0, 4.0); - cut->SetTPCNsigmaElRange(-3, +3); - cut->SetChi2PerClusterITS(-1e+10, 5.0); - cut->SetNClustersITS(2, 4); - cut->SetMeanClusterSizeITSob(0.0, 16.0); - cut->SetIsWithinBeamPipe(true); - // for v0 - cut->SetV0PtRange(0.1f, 1e10f); - cut->SetV0EtaRange(-0.9, +0.9); - cut->SetMinCosPA(0.995); - cut->SetMaxPCA(0.5); - cut->SetRxyRange(1, 90); - return cut; - } - if (!nameStr.compare("qc")) { - // for track - cut->SetTrackPtRange(0.04f, 1e10f); - // cut->SetTrackEtaRange(-0.9, +0.9); - cut->SetMinNCrossedRowsTPC(20); - cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); - cut->SetChi2PerClusterTPC(0.0, 4.0); - cut->SetTPCNsigmaElRange(-3, +3); - cut->SetChi2PerClusterITS(-1e+10, 5.0); - cut->SetNClustersITS(2, 4); - cut->SetMeanClusterSizeITSob(0.0, 16.0); - cut->SetIsWithinBeamPipe(true); - // for v0 - cut->SetV0PtRange(0.1f, 1e10f); - cut->SetV0EtaRange(-0.9, +0.9); - cut->SetMinCosPA(0.99); - cut->SetMaxPCA(3.0); - cut->SetRxyRange(1, 90); - cut->SetAPRange(0.95, 0.01); - cut->RejectITSib(true); - return cut; - } - if (!nameStr.compare("qc_ITSTPC")) { + // e.g. qc_minpt100_mexeta09 + float min_pt = 0.1; + float max_eta = 0.9; + std::vector tmp = splitString(nameStr, '_'); + for (size_t i = 0; i < tmp.size(); i++) { + if (tmp[i].find("minpt") != std::string::npos) { + min_pt = static_cast(customAtoi(tmp[i])) * 1e-3; // convert MeV to GeV + } + if (tmp[i].find("maxeta") != std::string::npos) { + max_eta = static_cast(customAtoi(tmp[i])) * 0.1; + } + } // end of split string loop + + // apply kinetic cuts + cut->SetTrackPtRange(min_pt * 0.4, 1e+10f); // this does not make sense, beucase pT, eta, phi are measured at SV, not at PV. But, reject some low-quality tracks. + // cut->SetTrackEtaRange(-max_eta, +max_eta); // this does not make sense, beucase pT, eta, phi are measured at SV, not at PV. + cut->SetV0PtRange(min_pt, 1e10f); + cut->SetV0EtaRange(-max_eta, +max_eta); + + if (nameStr.find("qc") != std::string::npos) { // for track - cut->SetTrackPtRange(0.04f, 1e10f); - // cut->SetTrackEtaRange(-0.9, +0.9); cut->SetMinNCrossedRowsTPC(20); cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); cut->SetChi2PerClusterTPC(0.0, 4.0); cut->SetTPCNsigmaElRange(-3, +3); - cut->SetIsWithinBeamPipe(true); cut->SetChi2PerClusterITS(-1e+10, 5.0); cut->SetNClustersITS(2, 4); cut->SetMeanClusterSizeITSob(0.0, 16.0); - cut->SetRequireITSTPC(true); - // for v0 - cut->SetV0PtRange(0.1f, 1e10f); - cut->SetV0EtaRange(-0.9, +0.9); - cut->SetMinCosPA(0.99); - cut->SetMaxPCA(1.0); - cut->SetRxyRange(1, 90); - cut->SetAPRange(0.95, 0.01); - cut->RejectITSib(true); - return cut; - } - if (!nameStr.compare("qc_ITSonly")) { - // for track - cut->SetTrackPtRange(0.04f, 1e10f); - // cut->SetTrackEtaRange(-0.9, +0.9); - cut->SetIsWithinBeamPipe(true); - cut->SetRequireITSonly(true); - cut->SetChi2PerClusterITS(-1e+10, 5.0); - cut->SetNClustersITS(4, 4); - cut->SetMeanClusterSizeITSob(0.0, 16.0); - // for v0 - cut->SetV0PtRange(0.1f, 1e10f); - cut->SetV0EtaRange(-0.9, +0.9); - cut->SetMinCosPA(0.99); - cut->SetMaxPCA(1.0); - cut->SetRxyRange(1, 90); - cut->SetAPRange(0.95, 0.01); - cut->RejectITSib(true); - return cut; - } - if (!nameStr.compare("qc_TPConly")) { - // for track - cut->SetTrackPtRange(0.04f, 1e10f); - // cut->SetTrackEtaRange(-0.9, +0.9); - cut->SetMinNCrossedRowsTPC(20); - cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); - cut->SetChi2PerClusterTPC(0.0, 4.0); - cut->SetTPCNsigmaElRange(-3, +3); cut->SetIsWithinBeamPipe(true); - cut->SetRequireTPConly(true); // for v0 - cut->SetV0PtRange(0.1f, 1e10f); - cut->SetV0EtaRange(-0.9, +0.9); cut->SetMinCosPA(0.99); cut->SetMaxPCA(3.0); - cut->SetRxyRange(36, 90); + cut->SetRxyRange(4, 90); cut->SetAPRange(0.95, 0.01); cut->RejectITSib(true); + + if (nameStr.find("ITSTPC") != std::string::npos) { + cut->SetRequireITSTPC(true); + cut->SetMaxPCA(1.0); + cut->SetRxyRange(4, 40); + return cut; + } else if (nameStr.find("ITSonly") != std::string::npos) { + cut->SetRequireITSonly(true); + cut->SetMaxPCA(1.0); + cut->SetRxyRange(4, 24); + return cut; + } else if (nameStr.find("TPConly") != std::string::npos) { + cut->SetRequireTPConly(true); + cut->SetMaxPCA(3.0); + cut->SetRxyRange(36, 90); + return cut; + } return cut; } - if (!nameStr.compare("wwire")) { // conversion only on tungstate wire + + if (nameStr.find("wire") != std::string::npos) { // for track - cut->SetTrackPtRange(0.04f, 1e10f); - // cut->SetTrackEtaRange(-0.9, +0.9); cut->SetMinNCrossedRowsTPC(20); cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); cut->SetChi2PerClusterTPC(0.0, 4.0); @@ -222,70 +171,29 @@ V0PhotonCut* o2::aod::pwgem::photon::pcmcuts::GetCut(const char* cutName) cut->SetMeanClusterSizeITSob(0.0, 16.0); // cut->SetIsWithinBeamPipe(true); // for v0 - cut->SetV0PtRange(0.1f, 1e10f); - cut->SetV0EtaRange(-0.9, +0.9); cut->SetMinCosPA(0.99); cut->SetMaxPCA(0.3); cut->SetOnWwireIB(true); cut->SetOnWwireOB(true); cut->SetAPRange(0.95, 0.01); cut->RejectITSib(true); - return cut; - } - if (!nameStr.compare("wwire_ib")) { // conversion only on tungstate wire outside of ITSib - // for track - cut->SetTrackPtRange(0.04f, 1e10f); - // cut->SetTrackEtaRange(-0.9, +0.9); - cut->SetMinNCrossedRowsTPC(20); - cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); - cut->SetChi2PerClusterTPC(0.0, 4.0); - cut->SetTPCNsigmaElRange(-3, +3); - cut->SetNClustersITS(2, 4); - cut->SetChi2PerClusterITS(-1e+10, 5.0); - cut->SetNClustersITS(2, 4); - cut->SetMeanClusterSizeITSob(0.0, 16.0); - // cut->SetIsWithinBeamPipe(true); - // for v0 - cut->SetV0PtRange(0.1f, 1e10f); - cut->SetV0EtaRange(-0.9, +0.9); - cut->SetMinCosPA(0.99); - cut->SetMaxPCA(0.3); - cut->SetOnWwireIB(true); - cut->SetOnWwireOB(false); - cut->SetAPRange(0.95, 0.01); - cut->RejectITSib(true); - return cut; - } - if (!nameStr.compare("wwire_ob")) { // conversion only on tungstate wire outside of ITSob (middle layer) - // for track - cut->SetTrackPtRange(0.04f, 1e10f); - // cut->SetTrackEtaRange(-0.9, +0.9); - cut->SetMinNCrossedRowsTPC(20); - cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); - cut->SetChi2PerClusterTPC(0.0, 4.0); - cut->SetTPCNsigmaElRange(-3, +3); - cut->SetNClustersITS(0, 2); - cut->SetChi2PerClusterITS(-1e+10, 5.0); - cut->SetNClustersITS(2, 2); - cut->SetMeanClusterSizeITSob(0.0, 16.0); - // cut->SetIsWithinBeamPipe(true); - // for v0 - cut->SetV0PtRange(0.1f, 1e10f); - cut->SetV0EtaRange(-0.9, +0.9); - cut->SetMinCosPA(0.99); - cut->SetMaxPCA(0.3); - cut->SetOnWwireIB(false); - cut->SetOnWwireOB(true); - cut->SetAPRange(0.95, 0.01); - cut->RejectITSib(true); + + if (nameStr.find("ib") != std::string::npos) { + cut->SetOnWwireIB(true); + cut->SetOnWwireOB(false); + cut->SetRxyRange(7, 14); + return cut; + } else if (nameStr.find("ob") != std::string::npos) { + cut->SetOnWwireIB(false); + cut->SetOnWwireOB(true); + cut->SetRxyRange(28, 33); + return cut; + } return cut; } - // for low B=0.2T - if (!nameStr.compare("qc_lowB")) { + if (nameStr.find("analysis") != std::string::npos) { // for track - cut->SetTrackPtRange(0.02f, 1e10f); - // cut->SetTrackEtaRange(-0.9, +0.9); cut->SetMinNCrossedRowsTPC(20); cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); cut->SetChi2PerClusterTPC(0.0, 4.0); @@ -295,19 +203,12 @@ V0PhotonCut* o2::aod::pwgem::photon::pcmcuts::GetCut(const char* cutName) cut->SetMeanClusterSizeITSob(0.0, 16.0); cut->SetIsWithinBeamPipe(true); // for v0 - cut->SetV0PtRange(0.05f, 1e10f); - cut->SetV0EtaRange(-0.9, +0.9); - cut->SetMinCosPA(0.99); - cut->SetMaxPCA(3.0); + cut->SetMinCosPA(0.995); + cut->SetMaxPCA(0.5); cut->SetRxyRange(1, 90); - cut->SetAPRange(0.95, 0.01); - cut->RejectITSib(true); return cut; - } - if (!nameStr.compare("qc_ITSTPC_lowB")) { + } else if (nameStr.find("tag_track") != std::string::npos) { // for track - cut->SetTrackPtRange(0.02f, 1e10f); - // cut->SetTrackEtaRange(-0.9, +0.9); cut->SetMinNCrossedRowsTPC(20); cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); cut->SetChi2PerClusterTPC(0.0, 4.0); @@ -318,59 +219,13 @@ V0PhotonCut* o2::aod::pwgem::photon::pcmcuts::GetCut(const char* cutName) cut->SetIsWithinBeamPipe(true); cut->SetRequireITSTPC(true); // for v0 - cut->SetV0PtRange(0.05f, 1e10f); - cut->SetV0EtaRange(-0.9, +0.9); - cut->SetMinCosPA(0.99); - cut->SetMaxPCA(1.0); - cut->SetRxyRange(1, 90); - cut->SetAPRange(0.95, 0.01); - cut->RejectITSib(true); - return cut; - } - if (!nameStr.compare("qc_ITSonly_lowB")) { - // for track - cut->SetTrackPtRange(0.02f, 1e10f); - // cut->SetTrackEtaRange(-0.9, +0.9); - cut->SetIsWithinBeamPipe(true); - cut->SetRequireITSonly(true); - cut->SetChi2PerClusterITS(-1e+10, 5.0); - cut->SetNClustersITS(4, 4); - cut->SetMeanClusterSizeITSob(0.0, 16.0); - // for v0 - cut->SetV0PtRange(0.05f, 1e10f); - cut->SetV0EtaRange(-0.9, +0.9); cut->SetMinCosPA(0.99); cut->SetMaxPCA(1.0); cut->SetRxyRange(1, 90); cut->SetAPRange(0.95, 0.01); - cut->RejectITSib(true); return cut; - } - if (!nameStr.compare("qc_TPConly_lowB")) { + } else if (nameStr.find("nopid") != std::string::npos) { // for track - cut->SetTrackPtRange(0.02f, 1e10f); - // cut->SetTrackEtaRange(-0.9, +0.9); - cut->SetMinNCrossedRowsTPC(20); - cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); - cut->SetChi2PerClusterTPC(0.0, 4.0); - cut->SetTPCNsigmaElRange(-3, +3); - cut->SetIsWithinBeamPipe(true); - cut->SetRequireTPConly(true); - // for v0 - cut->SetV0PtRange(0.05f, 1e10f); - cut->SetV0EtaRange(-0.9, +0.9); - cut->SetMinCosPA(0.99); - cut->SetMaxPCA(3.0); - cut->SetRxyRange(36, 90); - cut->SetAPRange(0.95, 0.01); - cut->RejectITSib(true); - return cut; - } - - if (!nameStr.compare("nopid")) { - // for track - cut->SetTrackPtRange(0.04f, 1e10f); - // cut->SetTrackEtaRange(-0.9, +0.9); cut->SetMinNCrossedRowsTPC(20); cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); cut->SetChi2PerClusterTPC(0.0, 4.0); @@ -379,19 +234,14 @@ V0PhotonCut* o2::aod::pwgem::photon::pcmcuts::GetCut(const char* cutName) cut->SetMeanClusterSizeITSob(0.0, 16.0); cut->SetIsWithinBeamPipe(true); // for v0 - cut->SetV0PtRange(0.1f, 1e10f); - cut->SetV0EtaRange(-0.9, +0.9); cut->SetMinCosPA(0.99); cut->SetMaxPCA(3.0); cut->SetRxyRange(1, 90); cut->SetAPRange(0.95, 0.01); cut->RejectITSib(true); return cut; - } - if (!nameStr.compare("nocut")) { + } else if (nameStr.find("nocut") != std::string::npos) { // for track - cut->SetTrackPtRange(0.04f, 1e10f); - // cut->SetTrackEtaRange(-0.9, +0.9); cut->SetMinNCrossedRowsTPC(20); cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); cut->SetChi2PerClusterTPC(0.0, 4.0); @@ -401,18 +251,13 @@ V0PhotonCut* o2::aod::pwgem::photon::pcmcuts::GetCut(const char* cutName) cut->SetMeanClusterSizeITSob(0.0, 16.0); cut->SetIsWithinBeamPipe(false); // for v0 - cut->SetV0PtRange(0.1f, 1e10f); - cut->SetV0EtaRange(-0.9, +0.9); cut->SetMinCosPA(0.95); cut->SetMaxPCA(3.0); cut->SetRxyRange(1, 90); cut->SetAPRange(0.95, 0.01); return cut; - } - if (!nameStr.compare("tag_track")) { + } else { // for track - cut->SetTrackPtRange(0.04f, 1e10f); - // cut->SetTrackEtaRange(-0.9, +0.9); cut->SetMinNCrossedRowsTPC(20); cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); cut->SetChi2PerClusterTPC(0.0, 4.0); @@ -420,13 +265,10 @@ V0PhotonCut* o2::aod::pwgem::photon::pcmcuts::GetCut(const char* cutName) cut->SetChi2PerClusterITS(-1e+10, 5.0); cut->SetNClustersITS(2, 4); cut->SetMeanClusterSizeITSob(0.0, 16.0); - cut->SetIsWithinBeamPipe(true); - cut->SetRequireITSTPC(true); + cut->SetIsWithinBeamPipe(false); // for v0 - cut->SetV0PtRange(0.1f, 1e10f); - cut->SetV0EtaRange(-0.9, +0.9); - cut->SetMinCosPA(0.99); - cut->SetMaxPCA(1.0); + cut->SetMinCosPA(0.95); + cut->SetMaxPCA(3.0); cut->SetRxyRange(1, 90); cut->SetAPRange(0.95, 0.01); return cut; @@ -442,196 +284,185 @@ DalitzEECut* o2::aod::pwgem::photon::dalitzeecuts::GetCut(const char* cutName) DalitzEECut* cut = new DalitzEECut(cutName, cutName); std::string nameStr = cutName; // cut name should be like this mee0_120_minpt200_maxeta09_dca20_100_tpchadronbandrej_lowB in unit of MeV. - - if (!nameStr.compare("nocut")) { - // apply kinetic cuts - cut->SetTrackPtRange(0.1, 1e+10f); - cut->SetTrackEtaRange(-0.9, +0.9); - - // for pair - cut->SetMeeRange(0, 1e+10); - cut->SetMaxPhivPairMeeDep([](float mee) { return (mee - -0.028) / 0.0185; }); - cut->ApplyPhiV(false); - cut->ApplyPrefilter(false); - - // for track cuts - cut->SetMinNCrossedRowsTPC(40); - cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); - cut->SetChi2PerClusterTPC(0.0, 4.0); - cut->SetChi2PerClusterITS(0.0, 5.0); - cut->SetNClustersITS(4, 7); - cut->SetMaxDcaXY(1.0); - cut->SetMaxDcaZ(1.0); - return cut; - } - - if (!nameStr.compare("pc_itsib")) { - // for pair - cut->ApplyPhiV(true); - cut->SelectPhotonConversion(true); - cut->SetMeeRange(0.f, 0.03f); - cut->SetMaxPhivPairMeeDep([](float mee) { - return (mee - -0.028) / 0.0185; - }); - - // for track - cut->SetTrackPtRange(0.05f, 1e10f); - cut->SetTrackEtaRange(-0.9, +0.9); - cut->SetMinNCrossedRowsTPC(40); - cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); - cut->SetChi2PerClusterTPC(0.0, 4.0); - cut->SetChi2PerClusterITS(0.0, 5.0); - cut->SetNClustersITS(2, 7); - cut->SetMaxDcaXY(1.0); - cut->SetMaxDcaZ(1.0); - - // for PID - cut->SetPIDScheme(DalitzEECut::PIDSchemes::kTPConly); - cut->SetTOFbetaRange(true, 0.0, 0.95); - cut->SetTPCNsigmaElRange(-3, +3); - cut->SetTPCNsigmaPiRange(0, 0); - return cut; - } - - float min_mass = 0.0; - float max_mass = 1e+10; - float min_pt = 0.05; - float max_eta = 0.9; - float min_dca3d_pair = 0.0; - float max_dca3d_pair = 1e+10; - std::vector tmp = splitString(nameStr, '_'); - for (size_t i = 0; i < tmp.size(); i++) { - // printf("string = %s , num = %d\n", tmp[i].data(), customAtoi(tmp[i])); - if (tmp[i].find("mee") != std::string::npos || tmp[i].find("mmumu") != std::string::npos) { - min_mass = static_cast(customAtoi(tmp[i])) * 1e-3; // convert MeV to GeV - max_mass = static_cast(customAtoi(tmp[i + 1])) * 1e-3; // convert MeV to GeV - } - if (tmp[i].find("minpt") != std::string::npos) { - min_pt = static_cast(customAtoi(tmp[i])) * 1e-3; // convert MeV to GeV - } - if (tmp[i].find("maxeta") != std::string::npos) { - max_eta = static_cast(customAtoi(tmp[i])) * 0.1; - } - if (tmp[i].find("dca") != std::string::npos) { - min_dca3d_pair = static_cast(customAtoi(tmp[i])) * 0.1; // 3d dca in sigma - max_dca3d_pair = static_cast(customAtoi(tmp[i + 1])) * 0.1; // 3d dca in sigma - } - } // end of split string loop - - // apply kinetic cuts - cut->SetTrackPtRange(min_pt, 1e+10f); - cut->SetTrackEtaRange(-max_eta, +max_eta); - - // for pair - cut->SetMeeRange(min_mass, max_mass); - cut->SetMaxPhivPairMeeDep([](float mee) { return (mee - -0.028) / 0.0185; }); - cut->SetPairDCARange(min_dca3d_pair, max_dca3d_pair); // in sigma - - cut->ApplyPhiV(true); - if (nameStr.find("wophiv") != std::string::npos) { - cut->ApplyPhiV(false); - } else if (nameStr.find("wphiv") != std::string::npos) { - cut->ApplyPhiV(true); - } - - cut->ApplyPrefilter(false); - if (nameStr.find("wpf") != std::string::npos) { - cut->ApplyPrefilter(true); - } else if (nameStr.find("wopf") != std::string::npos) { - cut->ApplyPrefilter(false); - } - - // for track cuts - cut->SetMinNCrossedRowsTPC(100); - cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); - cut->SetChi2PerClusterTPC(0.0, 4.0); - cut->SetChi2PerClusterITS(0.0, 5.0); - cut->SetNClustersITS(5, 7); - cut->SetMeanClusterSizeITSob(0, 16); - cut->SetMaxDcaXY(1.0); - cut->SetMaxDcaZ(1.0); - - if (nameStr.find("lowB") != std::string::npos) { - cut->SetMinNCrossedRowsTPC(40); - cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); - cut->SetChi2PerClusterTPC(0.0, 4.0); - cut->SetChi2PerClusterITS(0.0, 5.0); - cut->SetNClustersITS(4, 7); - cut->SetMeanClusterSizeITSob(0, 16); - cut->SetMaxDcaXY(1.0); - cut->SetMaxDcaZ(1.0); - } else if (nameStr.find("nominalB") != std::string::npos) { - cut->SetMinNCrossedRowsTPC(100); - cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); - cut->SetChi2PerClusterTPC(0.0, 4.0); - cut->SetChi2PerClusterITS(0.0, 5.0); - cut->SetNClustersITS(5, 7); - cut->SetMeanClusterSizeITSob(0, 16); - cut->SetMaxDcaXY(1.0); - cut->SetMaxDcaZ(1.0); - } - - // long pid name should be top, because of if--else if conditions. - - if (nameStr.find("mee") != std::string::npos) { // for electron - if (nameStr.find("tpcmupikaprrejortofreq") != std::string::npos) { - // for PID - cut->SetPIDScheme(DalitzEECut::PIDSchemes::kTPChadrejORTOFreq); - cut->SetTOFbetaRange(true, 0.0, 0.95); - cut->SetTPCNsigmaElRange(-2, +3); - cut->SetTPCNsigmaPiRange(-3, +3); - cut->SetTPCNsigmaKaRange(-3, +3); - cut->SetTPCNsigmaPrRange(-3, +3); - cut->SetTOFNsigmaElRange(-3, +3); - cut->SetTPCNsigmaMuRange(-2, +2); - cut->SetMuonExclusionTPC(true); - return cut; - } else if (nameStr.find("tpcpikaprrejortofreq") != std::string::npos) { - // for PID - cut->SetPIDScheme(DalitzEECut::PIDSchemes::kTPChadrejORTOFreq); - cut->SetTOFbetaRange(true, 0.0, 0.95); - cut->SetTPCNsigmaElRange(-2, +3); - cut->SetTPCNsigmaPiRange(-3, +3); - cut->SetTPCNsigmaKaRange(-3, +3); - cut->SetTPCNsigmaPrRange(-3, +3); - cut->SetTOFNsigmaElRange(-3, +3); - return cut; - } else if (nameStr.find("tpconly") != std::string::npos) { - // for PID - cut->SetPIDScheme(DalitzEECut::PIDSchemes::kTPConly); - cut->SetTOFbetaRange(true, 0.0, 0.95); - cut->SetTPCNsigmaElRange(-2, +3); - cut->SetTPCNsigmaPiRange(-3, +3); - return cut; - } else if (nameStr.find("tpcelonly") != std::string::npos) { - // for PID - cut->SetPIDScheme(DalitzEECut::PIDSchemes::kTPConly); - cut->SetTOFbetaRange(true, 0.0, 0.95); - cut->SetTPCNsigmaElRange(-2, +3); - cut->SetTPCNsigmaPiRange(0, 0); - return cut; - } else { // not match electron cut - LOGF(info, Form("Did not find electron ID cut %s", cutName)); - return cut; - } - } else if (nameStr.find("mmumu") != std::string::npos) { // for muon - if (nameStr.find("tpctof") != std::string::npos) { - // for PID - cut->SetPIDScheme(DalitzEECut::PIDSchemes::kMuon_lowB); - cut->SetTPCNsigmaElRange(-2, +2); // exclusion - cut->SetTPCNsigmaMuRange(-3, +3); - cut->SetTPCNsigmaPiRange(-3, +1e+10); - cut->SetTOFNsigmaMuRange(-3, +3); - cut->SetTOFNsigmaPiRange(-3, +1e+10); - return cut; - } else { // not match muon cut - LOGF(info, Form("Did not find muon ID cut %s", cutName)); - return cut; - } - } else { // match neither electron nor electron - LOGF(info, Form("Did not find any pid cut %s", cutName)); - return cut; - } + return cut; + + // if (!nameStr.compare("nocut")) { + // // apply kinetic cuts + // cut->SetTrackPtRange(0.1, 1e+10f); + // cut->SetTrackEtaRange(-0.9, +0.9); + // + // // for pair + // cut->SetMeeRange(0, 1e+10); + // cut->SetMaxPhivPairMeeDep([](float mee) { return (mee - -0.028) / 0.0185; }); + // cut->ApplyPhiV(false); + // cut->ApplyPrefilter(false); + // + // // for track cuts + // cut->SetMinNCrossedRowsTPC(40); + // cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); + // cut->SetChi2PerClusterTPC(0.0, 4.0); + // cut->SetChi2PerClusterITS(0.0, 5.0); + // cut->SetNClustersITS(4, 7); + // cut->SetMaxDcaXY(1.0); + // cut->SetMaxDcaZ(1.0); + // return cut; + // } + // + // if (!nameStr.compare("pc_itsib")) { + // // for pair + // cut->ApplyPhiV(true); + // cut->SelectPhotonConversion(true); + // cut->SetMeeRange(0.f, 0.03f); + // cut->SetMaxPhivPairMeeDep([](float mee) { + // return (mee - -0.028) / 0.0185; + // }); + // + // // for track + // cut->SetTrackPtRange(0.05f, 1e10f); + // cut->SetTrackEtaRange(-0.9, +0.9); + // cut->SetMinNCrossedRowsTPC(40); + // cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); + // cut->SetChi2PerClusterTPC(0.0, 4.0); + // cut->SetChi2PerClusterITS(0.0, 5.0); + // cut->SetNClustersITS(2, 7); + // cut->SetMaxDcaXY(1.0); + // cut->SetMaxDcaZ(1.0); + // + // // for PID + // cut->SetPIDScheme(static_cast(DalitzEECut::PIDSchemes::kTPConly)); + // cut->SetTOFbetaRange(true, 0.0, 0.95); + // cut->SetTPCNsigmaElRange(-3, +3); + // cut->SetTPCNsigmaPiRange(0, 0); + // return cut; + // } + // + // float min_mass = 0.0; + // float max_mass = 1e+10; + // float min_pt = 0.05; + // float max_eta = 0.9; + // float min_dca3d_pair = 0.0; + // float max_dca3d_pair = 1e+10; + // std::vector tmp = splitString(nameStr, '_'); + // for (size_t i = 0; i < tmp.size(); i++) { + // // printf("string = %s , num = %d\n", tmp[i].data(), customAtoi(tmp[i])); + // if (tmp[i].find("mee") != std::string::npos || tmp[i].find("mmumu") != std::string::npos) { + // min_mass = static_cast(customAtoi(tmp[i])) * 1e-3; // convert MeV to GeV + // max_mass = static_cast(customAtoi(tmp[i + 1])) * 1e-3; // convert MeV to GeV + // } + // if (tmp[i].find("minpt") != std::string::npos) { + // min_pt = static_cast(customAtoi(tmp[i])) * 1e-3; // convert MeV to GeV + // } + // if (tmp[i].find("maxeta") != std::string::npos) { + // max_eta = static_cast(customAtoi(tmp[i])) * 0.1; + // } + // if (tmp[i].find("dca") != std::string::npos) { + // min_dca3d_pair = static_cast(customAtoi(tmp[i])) * 0.1; // 3d dca in sigma + // max_dca3d_pair = static_cast(customAtoi(tmp[i + 1])) * 0.1; // 3d dca in sigma + // } + // } // end of split string loop + // + // // apply kinetic cuts + // cut->SetTrackPtRange(min_pt, 1e+10f); + // cut->SetTrackEtaRange(-max_eta, +max_eta); + // + // // for pair + // cut->SetMeeRange(min_mass, max_mass); + // cut->SetMaxPhivPairMeeDep([](float mee) { return (mee - -0.028) / 0.0185; }); + // cut->SetPairDCARange(min_dca3d_pair, max_dca3d_pair); // in sigma + // + // cut->ApplyPhiV(true); + // if (nameStr.find("wophiv") != std::string::npos) { + // cut->ApplyPhiV(false); + // } else if (nameStr.find("wphiv") != std::string::npos) { + // cut->ApplyPhiV(true); + // } + // + // cut->ApplyPrefilter(false); + // if (nameStr.find("wpf") != std::string::npos) { + // cut->ApplyPrefilter(true); + // } else if (nameStr.find("wopf") != std::string::npos) { + // cut->ApplyPrefilter(false); + // } + // + // // for track cuts + // cut->SetMinNCrossedRowsTPC(100); + // cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); + // cut->SetChi2PerClusterTPC(0.0, 4.0); + // cut->SetChi2PerClusterITS(0.0, 5.0); + // cut->SetNClustersITS(5, 7); + // cut->SetMeanClusterSizeITSob(0, 16); + // cut->SetMaxDcaXY(1.0); + // cut->SetMaxDcaZ(1.0); + // + // if (nameStr.find("lowB") != std::string::npos) { + // cut->SetMinNCrossedRowsTPC(40); + // cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); + // cut->SetChi2PerClusterTPC(0.0, 4.0); + // cut->SetChi2PerClusterITS(0.0, 5.0); + // cut->SetNClustersITS(4, 7); + // cut->SetMeanClusterSizeITSob(0, 16); + // cut->SetMaxDcaXY(1.0); + // cut->SetMaxDcaZ(1.0); + // } else if (nameStr.find("nominalB") != std::string::npos) { + // cut->SetMinNCrossedRowsTPC(100); + // cut->SetMinNCrossedRowsOverFindableClustersTPC(0.8); + // cut->SetChi2PerClusterTPC(0.0, 4.0); + // cut->SetChi2PerClusterITS(0.0, 5.0); + // cut->SetNClustersITS(5, 7); + // cut->SetMeanClusterSizeITSob(0, 16); + // cut->SetMaxDcaXY(1.0); + // cut->SetMaxDcaZ(1.0); + // } + // + // // long pid name should be top, because of if--else if conditions. + // + // if (nameStr.find("mee") != std::string::npos) { // for electron + // if (nameStr.find("tpcmupikaprrejortofreq") != std::string::npos) { + // cut->SetPIDScheme(static_cast(DalitzEECut::PIDSchemes::kTPChadrejORTOFreq)); + // cut->SetTOFbetaRange(true, 0.0, 0.95); + // cut->SetTPCNsigmaElRange(-2, +3); + // cut->SetTPCNsigmaPiRange(-3, +3); + // cut->SetTPCNsigmaKaRange(-3, +3); + // cut->SetTPCNsigmaPrRange(-3, +3); + // cut->SetTOFNsigmaElRange(-3, +3); + // cut->SetTPCNsigmaMuRange(-2, +2); + // cut->SetMuonExclusionTPC(true); + // return cut; + // } else if (nameStr.find("tpcpikaprrejortofreq") != std::string::npos) { + // cut->SetPIDScheme(static_cast(DalitzEECut::PIDSchemes::kTPChadrejORTOFreq)); + // cut->SetTOFbetaRange(true, 0.0, 0.95); + // cut->SetTPCNsigmaElRange(-2, +3); + // cut->SetTPCNsigmaPiRange(-3, +3); + // cut->SetTPCNsigmaKaRange(-3, +3); + // cut->SetTPCNsigmaPrRange(-3, +3); + // cut->SetTOFNsigmaElRange(-3, +3); + // return cut; + // } else if (nameStr.find("tpconly") != std::string::npos) { + // cut->SetPIDScheme(static_cast(DalitzEECut::PIDSchemes::kTPConly)); + // cut->SetTOFbetaRange(true, 0.0, 0.95); + // cut->SetTPCNsigmaElRange(-2, +3); + // cut->SetTPCNsigmaPiRange(-3, +3); + // return cut; + // } else if (nameStr.find("tpcelonly") != std::string::npos) { + // cut->SetPIDScheme(static_cast(DalitzEECut::PIDSchemes::kTPConly)); + // cut->SetTOFbetaRange(true, 0.0, 0.95); + // cut->SetTPCNsigmaElRange(-2, +3); + // cut->SetTPCNsigmaPiRange(0, 0); + // return cut; + // } else if (nameStr.find("mleidlocal") != std::string::npos) { + // // cut->EnableEIDML(false, "/Users/d/dsekihat/pidml/", false, -1, "eid_lightgbm.onnx"); + // return cut; + // } else if (nameStr.find("mleid") != std::string::npos) { + // // cut->EnableEIDML(true, "/Users/d/dsekihat/pidml/", false, -1, "eid_lightgbm.onnx"); + // return cut; + // } else { // not match electron cut + // LOGF(info, Form("Did not find electron ID cut %s", cutName)); + // return cut; + // } + // } else { // do not match mee + // LOGF(info, Form("Did not find any pid cut %s", cutName)); + // return cut; + // } } PHOSPhotonCut* o2::aod::pwgem::photon::phoscuts::GetCut(const char* cutName) diff --git a/PWGEM/PhotonMeson/Core/CutsLibrary.h b/PWGEM/PhotonMeson/Core/CutsLibrary.h index 60bb65bbdbb..bf4fcfe7037 100644 --- a/PWGEM/PhotonMeson/Core/CutsLibrary.h +++ b/PWGEM/PhotonMeson/Core/CutsLibrary.h @@ -16,7 +16,7 @@ #define PWGEM_PHOTONMESON_CORE_CUTSLIBRARY_H_ #include -#include "PWGEM/PhotonMeson/Core/EMEventCut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" #include "PWGEM/PhotonMeson/Core/DalitzEECut.h" #include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" @@ -29,7 +29,7 @@ namespace pwgem::photon { namespace eventcuts { -EMEventCut* GetCut(const char* cutName); +EMPhotonEventCut* GetCut(const char* cutName); } // namespace eventcuts namespace pcmcuts diff --git a/PWGEM/PhotonMeson/Core/DalitzEECut.cxx b/PWGEM/PhotonMeson/Core/DalitzEECut.cxx index 3783ee79f0b..99ac9ee356a 100644 --- a/PWGEM/PhotonMeson/Core/DalitzEECut.cxx +++ b/PWGEM/PhotonMeson/Core/DalitzEECut.cxx @@ -13,12 +13,18 @@ // Class for dilepton Cut // +#include +#include + #include "Framework/Logger.h" #include "PWGEM/PhotonMeson/Core/DalitzEECut.h" ClassImp(DalitzEECut); -const char* DalitzEECut::mCutNames[static_cast(DalitzEECut::DalitzEECuts::kNCuts)] = {"Mee", "PairPtRange", "PairEtaRange", "PairDCARange", "PhivPair", "TrackPtRange", "TrackEtaRange", "TPCNCls", "TPCCrossedRows", "TPCCrossedRowsOverNCls", "TPCChi2NDF", "TPCNsigmaEl", "TPCNsigmaMu", "TPCNsigmaPi", "TPCNsigmaKa", "TPCNsigmaPr", "TOFNsigmaEl", "TOFNsigmaMu", "TOFNsigmaPi", "TOFNsigmaKa", "TOFNsigmaPr", "DCA3Dsigma", "DCAxy", "DCAz", "ITSNCls", "ITSChi2NDF", "ITSClusterSize", "Prefilter"}; +// const char* DalitzEECut::mCutNames[static_cast(DalitzEECut::DalitzEECuts::kNCuts)] = {"Mee", "PairPtRange", "PairRapidityRange", "PairDCARange", "PhivPair", "TrackPtRange", "TrackEtaRange", "TPCNCls", "TPCCrossedRows", "TPCCrossedRowsOverNCls", "TPCChi2NDF", "TPCNsigmaEl", "TPCNsigmaMu", "TPCNsigmaPi", "TPCNsigmaKa", "TPCNsigmaPr", "TOFNsigmaEl", "TOFNsigmaMu", "TOFNsigmaPi", "TOFNsigmaKa", "TOFNsigmaPr", "DCA3Dsigma", "DCAxy", "DCAz", "ITSNCls", "ITSChi2NDF", "ITSClusterSize", "Prefilter"}; + +const std::pair> DalitzEECut::its_ib_any_Requirement = {1, {0, 1, 2}}; // hits on any ITS ib layers. +const std::pair> DalitzEECut::its_ib_1st_Requirement = {1, {0}}; // hit on 1st ITS ib layers. void DalitzEECut::SetPairPtRange(float minPt, float maxPt) { @@ -26,17 +32,11 @@ void DalitzEECut::SetPairPtRange(float minPt, float maxPt) mMaxPairPt = maxPt; LOG(info) << "DalitzEE Cut, set pair pt range: " << mMinPairPt << " - " << mMaxPairPt; } -void DalitzEECut::SetPairEtaRange(float minEta, float maxEta) +void DalitzEECut::SetPairYRange(float minY, float maxY) { - mMinPairEta = minEta; - mMaxPairEta = maxEta; - LOG(info) << "DalitzEE Cut, set pair eta range: " << mMinPairEta << " - " << mMaxPairEta; -} -void DalitzEECut::SetPairDCARange(float min, float max) -{ - mMinPairDCA3D = min; - mMaxPairDCA3D = max; - LOG(info) << "DalitzEE Cut, set pair 3d dca range: " << mMinPairDCA3D << " - " << mMaxPairDCA3D; + mMinPairY = minY; + mMaxPairY = maxY; + LOG(info) << "DalitzEE Cut, set pair eta range: " << mMinPairY << " - " << mMaxPairY; } void DalitzEECut::SetMeeRange(float min, float max) { @@ -81,6 +81,11 @@ void DalitzEECut::SetMinNCrossedRowsOverFindableClustersTPC(float minNCrossedRow mMinNCrossedRowsOverFindableClustersTPC = minNCrossedRowsOverFindableClustersTPC; LOG(info) << "DalitzEE Cut, set min N crossed rows over findable clusters TPC: " << mMinNCrossedRowsOverFindableClustersTPC; } +void DalitzEECut::SetMaxFracSharedClustersTPC(float max) +{ + mMaxFracSharedClustersTPC = max; + LOG(info) << "Dalitz EE Cut, set max fraction of shared clusters in TPC: " << mMaxFracSharedClustersTPC; +} void DalitzEECut::SetChi2PerClusterTPC(float min, float max) { mMinChi2PerClusterTPC = min; @@ -100,13 +105,13 @@ void DalitzEECut::SetChi2PerClusterITS(float min, float max) mMaxChi2PerClusterITS = max; LOG(info) << "DalitzEE Cut, set chi2 per cluster ITS range: " << mMinChi2PerClusterITS << " - " << mMaxChi2PerClusterITS; } -void DalitzEECut::SetMeanClusterSizeITSob(float min, float max) +void DalitzEECut::SetMeanClusterSizeITS(float min, float max) { mMinMeanClusterSizeITS = min; mMaxMeanClusterSizeITS = max; LOG(info) << "DalitzEE Cut, set mean cluster size ITS range: " << mMinMeanClusterSizeITS << " - " << mMaxMeanClusterSizeITS; } -void DalitzEECut::SetDca3DRange(float min, float max) +void DalitzEECut::SetTrackDca3DRange(float min, float max) { mMinDca3D = min; mMaxDca3D = max; @@ -133,36 +138,6 @@ void DalitzEECut::ApplyPhiV(bool flag) mApplyPhiV = flag; LOG(info) << "DalitzEE Cut, apply phiv cut: " << mApplyPhiV; } -void DalitzEECut::ApplyPrefilter(bool flag) -{ - mApplyPF = flag; - LOG(info) << "DalitzEE Cut, apply prefilter: " << mApplyPF; -} - -void DalitzEECut::SetPIDScheme(PIDSchemes scheme) -{ - mPIDScheme = scheme; - LOG(info) << "DalitzEE Cut, PID scheme: " << static_cast(mPIDScheme); -} -void DalitzEECut::SetMinPinTOF(float min) -{ - mMinPinTOF = min; - LOG(info) << "DalitzEE Cut, set min pin for TOF: " << mMinPinTOF; -} - -void DalitzEECut::SetMuonExclusionTPC(bool flag) -{ - mMuonExclusionTPC = flag; - LOG(info) << "DalitzEE Cut, set flag for muon exclusion in TPC: " << mMuonExclusionTPC; -} - -void DalitzEECut::SetTOFbetaRange(bool flag, float min, float max) -{ - mApplyTOFbeta = flag; - mMinTOFbeta = min; - mMaxTOFbeta = max; - LOG(info) << "DalitzEE Cut, set TOF beta rejection range: " << mMinTOFbeta << " - " << mMaxTOFbeta; -} void DalitzEECut::SetTPCNsigmaElRange(float min, float max) { @@ -170,30 +145,12 @@ void DalitzEECut::SetTPCNsigmaElRange(float min, float max) mMaxTPCNsigmaEl = max; LOG(info) << "DalitzEE Cut, set TPC n sigma El range: " << mMinTPCNsigmaEl << " - " << mMaxTPCNsigmaEl; } -void DalitzEECut::SetTPCNsigmaMuRange(float min, float max) -{ - mMinTPCNsigmaMu = min; - mMaxTPCNsigmaMu = max; - LOG(info) << "DalitzEE Cut, set TPC n sigma Mu range: " << mMinTPCNsigmaMu << " - " << mMaxTPCNsigmaMu; -} void DalitzEECut::SetTPCNsigmaPiRange(float min, float max) { mMinTPCNsigmaPi = min; mMaxTPCNsigmaPi = max; LOG(info) << "DalitzEE Cut, set TPC n sigma Pi range: " << mMinTPCNsigmaPi << " - " << mMaxTPCNsigmaPi; } -void DalitzEECut::SetTPCNsigmaKaRange(float min, float max) -{ - mMinTPCNsigmaKa = min; - mMaxTPCNsigmaKa = max; - LOG(info) << "DalitzEE Cut, set TPC n sigma Ka range: " << mMinTPCNsigmaKa << " - " << mMaxTPCNsigmaKa; -} -void DalitzEECut::SetTPCNsigmaPrRange(float min, float max) -{ - mMinTPCNsigmaPr = min; - mMaxTPCNsigmaPr = max; - LOG(info) << "DalitzEE Cut, set TPC n sigma Pr range: " << mMinTPCNsigmaPr << " - " << mMaxTPCNsigmaPr; -} void DalitzEECut::SetTOFNsigmaElRange(float min, float max) { @@ -201,67 +158,24 @@ void DalitzEECut::SetTOFNsigmaElRange(float min, float max) mMaxTOFNsigmaEl = max; LOG(info) << "DalitzEE Cut, set TOF n sigma El range: " << mMinTOFNsigmaEl << " - " << mMaxTOFNsigmaEl; } -void DalitzEECut::SetTOFNsigmaMuRange(float min, float max) -{ - mMinTOFNsigmaMu = min; - mMaxTOFNsigmaMu = max; - LOG(info) << "DalitzEE Cut, set TOF n sigma Mu range: " << mMinTOFNsigmaMu << " - " << mMaxTOFNsigmaMu; -} -void DalitzEECut::SetTOFNsigmaPiRange(float min, float max) -{ - mMinTOFNsigmaPi = min; - mMaxTOFNsigmaPi = max; - LOG(info) << "DalitzEE Cut, set TOF n sigma Pi range: " << mMinTOFNsigmaPi << " - " << mMaxTOFNsigmaPi; -} -void DalitzEECut::SetTOFNsigmaKaRange(float min, float max) +void DalitzEECut::RequireITSibAny(bool flag) { - mMinTOFNsigmaKa = min; - mMaxTOFNsigmaKa = max; - LOG(info) << "DalitzEE Cut, set TOF n sigma Ka range: " << mMinTOFNsigmaKa << " - " << mMaxTOFNsigmaKa; + mRequireITSibAny = flag; + LOG(info) << "DalitzEE Cut, require ITS ib any: " << mRequireITSibAny; } -void DalitzEECut::SetTOFNsigmaPrRange(float min, float max) +void DalitzEECut::RequireITSib1st(bool flag) { - mMinTOFNsigmaPr = min; - mMaxTOFNsigmaPr = max; - LOG(info) << "DalitzEE Cut, set TOF n sigma Pr range: " << mMinTOFNsigmaPr << " - " << mMaxTOFNsigmaPr; + mRequireITSib1st = flag; + LOG(info) << "DalitzEE Cut, require ITS ib 1st: " << mRequireITSib1st; } -void DalitzEECut::SetMaxPinMuonTPConly(float max) +void DalitzEECut::SetChi2TOF(float min, float max) { - mMaxPinMuonTPConly = max; - LOG(info) << "DalitzEE Cut, set max pin for Muon ID with TPC only: " << mMaxPinMuonTPConly; + mMinChi2TOF = min; + mMaxChi2TOF = max; + LOG(info) << "Dielectron Cut, set chi2 TOF range: " << mMinChi2TOF << " - " << mMaxChi2TOF; } - -void DalitzEECut::print() const +void DalitzEECut::SetPIDScheme(int scheme) { - LOG(info) << "Dalitz EE Cut:"; - for (int i = 0; i < static_cast(DalitzEECuts::kNCuts); i++) { - switch (static_cast(i)) { - case DalitzEECuts::kTrackPtRange: - LOG(info) << mCutNames[i] << " in [" << mMinTrackPt << ", " << mMaxTrackPt << "]"; - break; - case DalitzEECuts::kTrackEtaRange: - LOG(info) << mCutNames[i] << " in [" << mMinTrackEta << ", " << mMaxTrackEta << "]"; - break; - case DalitzEECuts::kTPCNCls: - LOG(info) << mCutNames[i] << " > " << mMinNClustersTPC; - break; - case DalitzEECuts::kTPCCrossedRows: - LOG(info) << mCutNames[i] << " > " << mMinNCrossedRowsTPC; - break; - case DalitzEECuts::kTPCCrossedRowsOverNCls: - LOG(info) << mCutNames[i] << " > " << mMinNCrossedRowsOverFindableClustersTPC; - break; - case DalitzEECuts::kTPCChi2NDF: - LOG(info) << mCutNames[i] << " < " << mMaxChi2PerClusterTPC; - break; - case DalitzEECuts::kDCAxy: - LOG(info) << mCutNames[i] << " < " << mMaxDcaXY; - break; - case DalitzEECuts::kDCAz: - LOG(info) << mCutNames[i] << " < " << mMaxDcaZ; - break; - default: - LOG(fatal) << "Cut unknown!"; - } - } + mPIDScheme = scheme; + LOG(info) << "DalitzEE Cut, PID scheme: " << static_cast(mPIDScheme); } diff --git a/PWGEM/PhotonMeson/Core/DalitzEECut.h b/PWGEM/PhotonMeson/Core/DalitzEECut.h index 5a15d6b9693..60dff1786d1 100644 --- a/PWGEM/PhotonMeson/Core/DalitzEECut.h +++ b/PWGEM/PhotonMeson/Core/DalitzEECut.h @@ -21,11 +21,19 @@ #include #include #include +#include "TNamed.h" +#include "Math/Vector4D.h" + +#include "Tools/ML/MlResponse.h" +#include "Tools/ML/model.h" + #include "Framework/Logger.h" #include "Framework/DataTypes.h" -#include "Rtypes.h" -#include "TNamed.h" -#include "TMath.h" +#include "CommonConstants/PhysicsConstants.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" + +using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; class DalitzEECut : public TNamed { @@ -37,8 +45,7 @@ class DalitzEECut : public TNamed // pair cut kMee = 0, kPairPtRange, - kPairEtaRange, - kPairDCARange, + kPairYRange, kPhiV, // track cut kTrackPtRange, @@ -46,102 +53,68 @@ class DalitzEECut : public TNamed kTPCNCls, kTPCCrossedRows, kTPCCrossedRowsOverNCls, + kTPCFracSharedClusters, kTPCChi2NDF, kTPCNsigmaEl, - kTPCNsigmaMu, kTPCNsigmaPi, - kTPCNsigmaKa, - kTPCNsigmaPr, - kTOFNsigmaEl, - kTOFNsigmaMu, - kTOFNsigmaPi, - kTOFNsigmaKa, - kTOFNsigmaPr, kDCA3Dsigma, kDCAxy, kDCAz, kITSNCls, kITSChi2NDF, kITSCluserSize, - kPrefilter, kNCuts }; static const char* mCutNames[static_cast(DalitzEECuts::kNCuts)]; enum class PIDSchemes : int { kUnDef = -1, - kTOFreq = 0, - kTPChadrej = 1, - kTPChadrejORTOFreq = 2, - kTPConly = 3, - kMuon_lowB = 4, + kTOFif = 0, + kTPConly = 1, }; - template + template bool IsSelected(TPair const& pair) const { - if (!IsSelectedPair(pair)) { - return false; - } - - auto pos = pair.template posTrack_as(); - auto ele = pair.template negTrack_as(); + auto t1 = std::get<0>(pair); + auto t2 = std::get<1>(pair); + float bz = std::get<2>(pair); - for (auto& track : {pos, ele}) { - if (!IsSelectedTrack(track)) { - return false; - } + if (!IsSelectedTrack(t1) || !IsSelectedTrack(t2)) { + return false; } - // apply pair DCA cut here, because leg info are required. - float dca_pos_3d = pos.dca3DinSigma(); - float dca_ele_3d = ele.dca3DinSigma(); - float dca_ee_3d = std::sqrt((dca_pos_3d * dca_pos_3d + dca_ele_3d * dca_ele_3d) / 2.); - - if (dca_ee_3d < mMinPairDCA3D || mMaxPairDCA3D < dca_ee_3d) { // in sigma for pair + if (!IsSelectedPair(t1, t2, bz)) { return false; } return true; } - bool IsSelectedPair(const float mass, const float dca_3d_pair, const float phiv) const + template + bool IsSelectedPair(TTrack1 const& t1, TTrack2 const& t2, const float bz) const { - if (mass < mMinMee || mMaxMee < mass) { - return false; - } - if (mApplyPhiV && ((phiv < mMinPhivPair || (mMaxPhivPairMeeDep ? mMaxPhivPairMeeDep(mass) : mMaxPhivPair) < phiv) ^ mSelectPC)) { - return false; - } - if (dca_3d_pair < mMinPairDCA3D || mMaxPairDCA3D < dca_3d_pair) { // in sigma for pair - return false; - } - return true; - } + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), bz); - template - bool IsSelectedPair(T const& pair) const - { - if (!IsSelectedPair(pair, DalitzEECuts::kPairPtRange)) { - return false; - } - if (!IsSelectedPair(pair, DalitzEECuts::kPairEtaRange)) { + if (v12.M() < mMinMee || mMaxMee < v12.M()) { return false; } - if (!IsSelectedPair(pair, DalitzEECuts::kPairDCARange)) { - return false; - } - if (!IsSelectedPair(pair, DalitzEECuts::kMee)) { + + if (v12.Rapidity() < mMinPairY || mMaxPairY < v12.Rapidity()) { return false; } - if (mApplyPhiV && !IsSelectedPair(pair, DalitzEECuts::kPhiV)) { + + if (mApplyPhiV && ((phiv < mMinPhivPair || (mMaxPhivPairMeeDep ? mMaxPhivPairMeeDep(v12.M()) : mMaxPhivPair) < phiv) ^ mSelectPC)) { return false; } return true; } - template - bool IsSelectedTrack(T const& track) const + template + bool IsSelectedTrack(TTrack const& track, TCollision const& = 0) const { if (!track.hasITS() || !track.hasTPC()) { // track has to be ITS-TPC matched track return false; @@ -174,6 +147,20 @@ class DalitzEECut : public TNamed return false; } + if (mRequireITSibAny) { + auto hits_ib = std::count_if(its_ib_any_Requirement.second.begin(), its_ib_any_Requirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); + if (hits_ib < its_ib_any_Requirement.first) { + return false; + } + } + + if (mRequireITSib1st) { + auto hits_ib = std::count_if(its_ib_1st_Requirement.second.begin(), its_ib_1st_Requirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); + if (hits_ib < its_ib_1st_Requirement.first) { + return false; + } + } + // TPC cuts if (!IsSelectedTrack(track, DalitzEECuts::kTPCNCls)) { return false; @@ -184,23 +171,18 @@ class DalitzEECut : public TNamed if (!IsSelectedTrack(track, DalitzEECuts::kTPCCrossedRowsOverNCls)) { return false; } - if (!IsSelectedTrack(track, DalitzEECuts::kTPCChi2NDF)) { + if (!IsSelectedTrack(track, DalitzEECuts::kTPCFracSharedClusters)) { return false; } - - if (mApplyPF && !IsSelectedTrack(track, DalitzEECuts::kPrefilter)) { + if (!IsSelectedTrack(track, DalitzEECuts::kTPCChi2NDF)) { return false; } - // PID cuts here. + // PID cuts if (!PassPID(track)) { return false; } - if (mApplyTOFbeta && (mMinTOFbeta < track.beta() && track.beta() < mMaxTOFbeta)) { - return false; - } - return true; } @@ -208,22 +190,13 @@ class DalitzEECut : public TNamed bool PassPID(T const& track) const { switch (mPIDScheme) { - case PIDSchemes::kTOFreq: - return PassTOFreq(track); - - case PIDSchemes::kTPChadrej: - return PassTPChadrej(track); - - case PIDSchemes::kTPChadrejORTOFreq: - return PassTPChadrej(track) || PassTOFreq(track); - - case PIDSchemes::kTPConly: + case static_cast(PIDSchemes::kTPConly): return PassTPConly(track); - case PIDSchemes::kMuon_lowB: - return PassMuon_lowB(track); + case static_cast(PIDSchemes::kTOFif): + return PassTOFif(track); - case PIDSchemes::kUnDef: + case static_cast(PIDSchemes::kUnDef): return true; default: @@ -231,26 +204,6 @@ class DalitzEECut : public TNamed } } - template - bool PassTOFreq(T const& track) const - { - bool is_el_included_TPC = mMinTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < mMaxTPCNsigmaEl; - bool is_pi_excluded_TPC = track.tpcNSigmaPi() < mMinTPCNsigmaPi || mMaxTPCNsigmaPi < track.tpcNSigmaPi(); - bool is_el_included_TOF = mMinTOFNsigmaEl < track.tofNSigmaEl() && track.tofNSigmaEl() < mMaxTOFNsigmaEl; - return is_el_included_TPC && is_pi_excluded_TPC && is_el_included_TOF; - } - - template - bool PassTPChadrej(T const& track) const - { - bool is_el_included_TPC = mMinTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < mMaxTPCNsigmaEl; - bool is_mu_excluded_TPC = mMuonExclusionTPC ? track.tpcNSigmaMu() < mMinTPCNsigmaMu || mMaxTPCNsigmaMu < track.tpcNSigmaMu() : true; - bool is_pi_excluded_TPC = track.tpcNSigmaPi() < mMinTPCNsigmaPi || mMaxTPCNsigmaPi < track.tpcNSigmaPi(); - bool is_ka_excluded_TPC = track.tpcNSigmaKa() < mMinTPCNsigmaKa || mMaxTPCNsigmaKa < track.tpcNSigmaKa(); - bool is_pr_excluded_TPC = track.tpcNSigmaPr() < mMinTPCNsigmaPr || mMaxTPCNsigmaPr < track.tpcNSigmaPr(); - return is_el_included_TPC && is_mu_excluded_TPC && is_pi_excluded_TPC && is_ka_excluded_TPC && is_pr_excluded_TPC; - } - template bool PassTPConly(T const& track) const { @@ -260,49 +213,12 @@ class DalitzEECut : public TNamed } template - bool PassMuon_lowB(T const& track) const - { - bool is_el_excluded_TPC = track.tpcNSigmaEl() < mMinTPCNsigmaEl || mMaxTPCNsigmaEl < track.tpcNSigmaEl(); - if (!is_el_excluded_TPC) { - return false; - } - if (track.hasTOF()) { - bool is_mu_included_TPC = mMinTPCNsigmaMu < track.tpcNSigmaMu() && track.tpcNSigmaMu() < mMaxTPCNsigmaMu; - bool is_mu_included_TOF = mMinTOFNsigmaMu < track.tofNSigmaMu() && track.tofNSigmaMu() < mMaxTOFNsigmaMu; - bool is_pi_excluded_TOF = track.tofNSigmaPi() < mMinTOFNsigmaPi; - return is_mu_included_TPC && is_mu_included_TOF && is_pi_excluded_TOF; - } else if (track.tpcInnerParam() < mMaxPinMuonTPConly) { - bool is_mu_included_TPC = mMinTPCNsigmaMu < track.tpcNSigmaMu() && track.tpcNSigmaMu() < mMaxTPCNsigmaMu; - bool is_pi_excluded_TPC = track.tpcNSigmaPi() < mMinTPCNsigmaPi; - return is_mu_included_TPC && is_pi_excluded_TPC; - } else { - return false; - } - } - - template - bool IsSelectedPair(T const& pair, const DalitzEECuts& cut) const + bool PassTOFif(T const& track) const { - switch (cut) { - case DalitzEECuts::kPairPtRange: - return pair.pt() >= mMinPairPt && pair.pt() <= mMaxPairPt; - - case DalitzEECuts::kPairEtaRange: - return pair.eta() >= mMinPairEta && pair.eta() <= mMaxPairEta; - - case DalitzEECuts::kPairDCARange: { - return pair.eta() >= mMinPairEta && pair.eta() <= mMaxPairEta; - } - - case DalitzEECuts::kMee: - return mMinMee <= pair.mass() && pair.mass() <= mMaxMee; - - case DalitzEECuts::kPhiV: - return (mMinPhivPair <= pair.phiv() && pair.phiv() <= (mMaxPhivPairMeeDep ? mMaxPhivPairMeeDep(pair.mass()) : mMaxPhivPair)) ^ mSelectPC; - - default: - return false; - } + bool is_el_included_TPC = mMinTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < mMaxTPCNsigmaEl; + bool is_pi_excluded_TPC = track.tpcNSigmaPi() < mMinTPCNsigmaPi || mMaxTPCNsigmaPi < track.tpcNSigmaPi(); + bool is_el_included_TOF = track.hasTOF() ? (mMinTOFNsigmaEl < track.tofNSigmaEl() && track.tofNSigmaEl() < mMaxTOFNsigmaEl && track.tofChi2() < mMaxChi2TOF) : true; + return is_el_included_TPC && is_pi_excluded_TPC && is_el_included_TOF; } template @@ -324,17 +240,20 @@ class DalitzEECut : public TNamed case DalitzEECuts::kTPCCrossedRowsOverNCls: return track.tpcCrossedRowsOverFindableCls() >= mMinNCrossedRowsOverFindableClustersTPC; + case DalitzEECuts::kTPCFracSharedClusters: + return track.tpcFractionSharedCls() <= mMaxFracSharedClustersTPC; + case DalitzEECuts::kTPCChi2NDF: return mMinChi2PerClusterTPC < track.tpcChi2NCl() && track.tpcChi2NCl() < mMaxChi2PerClusterTPC; case DalitzEECuts::kDCA3Dsigma: - return mMinDca3D <= track.dca3DinSigma() && track.dca3DinSigma() <= mMaxDca3D; // in sigma for single leg + return mMinDca3D <= dca3DinSigma(track) && dca3DinSigma(track) <= mMaxDca3D; // in sigma for single leg case DalitzEECuts::kDCAxy: - return abs(track.dcaXY()) <= ((mMaxDcaXYPtDep) ? mMaxDcaXYPtDep(track.pt()) : mMaxDcaXY); + return std::fabs(track.dcaXY()) <= ((mMaxDcaXYPtDep) ? mMaxDcaXYPtDep(track.pt()) : mMaxDcaXY); case DalitzEECuts::kDCAz: - return abs(track.dcaZ()) <= mMaxDcaZ; + return std::fabs(track.dcaZ()) <= mMaxDcaZ; case DalitzEECuts::kITSNCls: return mMinNClustersITS <= track.itsNCls() && track.itsNCls() <= mMaxNClustersITS; @@ -343,10 +262,7 @@ class DalitzEECut : public TNamed return mMinChi2PerClusterITS < track.itsChi2NCl() && track.itsChi2NCl() < mMaxChi2PerClusterITS; case DalitzEECuts::kITSCluserSize: - return mMinMeanClusterSizeITS < track.meanClusterSizeITSob() * std::cos(std::atan(track.tgl())) && track.meanClusterSizeITSob() * std::cos(std::atan(track.tgl())) < mMaxMeanClusterSizeITS; - - case DalitzEECuts::kPrefilter: - return track.pfb() <= 0; + return mMinMeanClusterSizeITS < track.meanClusterSizeITS() * std::cos(std::atan(track.tgl())) && track.meanClusterSizeITS() * std::cos(std::atan(track.tgl())) < mMaxMeanClusterSizeITS; default: return false; @@ -355,8 +271,7 @@ class DalitzEECut : public TNamed // Setters void SetPairPtRange(float minPt = 0.f, float maxPt = 1e10f); - void SetPairEtaRange(float minEta = -1e10f, float maxEta = 1e10f); - void SetPairDCARange(float min = 0.f, float max = 1e10f); // 3D DCA in sigma + void SetPairYRange(float minY = -1e10f, float maxY = 1e10f); void SetMeeRange(float min = 0.f, float max = 0.5); void SetMaxPhivPairMeeDep(std::function meeDepCut); void SelectPhotonConversion(bool flag); @@ -366,30 +281,23 @@ class DalitzEECut : public TNamed void SetMinNClustersTPC(int minNClustersTPC); void SetMinNCrossedRowsTPC(int minNCrossedRowsTPC); void SetMinNCrossedRowsOverFindableClustersTPC(float minNCrossedRowsOverFindableClustersTPC); + void SetMaxFracSharedClustersTPC(float max); void SetChi2PerClusterTPC(float min, float max); void SetNClustersITS(int min, int max); void SetChi2PerClusterITS(float min, float max); - void SetMeanClusterSizeITSob(float min, float max); - - void SetPIDScheme(PIDSchemes scheme); - void SetMinPinTOF(float min); - void SetMuonExclusionTPC(bool flag); - void SetTOFbetaRange(bool flag, float min, float max); - void SetTPCNsigmaElRange(float min = -1e+10, float max = 1e+10); - void SetTPCNsigmaMuRange(float min = -1e+10, float max = 1e+10); - void SetTPCNsigmaPiRange(float min = -1e+10, float max = 1e+10); - void SetTPCNsigmaKaRange(float min = -1e+10, float max = 1e+10); - void SetTPCNsigmaPrRange(float min = -1e+10, float max = 1e+10); - void SetTOFNsigmaElRange(float min = -1e+10, float max = 1e+10); - void SetTOFNsigmaMuRange(float min = -1e+10, float max = 1e+10); - void SetTOFNsigmaPiRange(float min = -1e+10, float max = 1e+10); - void SetTOFNsigmaKaRange(float min = -1e+10, float max = 1e+10); - void SetTOFNsigmaPrRange(float min = -1e+10, float max = 1e+10); - void SetMaxPinMuonTPConly(float max); - - void SetDca3DRange(float min, float max); // in sigma - void SetMaxDcaXY(float maxDcaXY); // in cm - void SetMaxDcaZ(float maxDcaZ); // in cm + void SetMeanClusterSizeITS(float min, float max); + void SetChi2TOF(float min, float max); + + void SetPIDScheme(int scheme); + void SetTPCNsigmaElRange(float min, float max); + void SetTPCNsigmaPiRange(float min, float max); + void SetTOFNsigmaElRange(float min, float max); + void RequireITSibAny(bool flag); + void RequireITSib1st(bool flag); + + void SetTrackDca3DRange(float min, float max); // in sigma + void SetMaxDcaXY(float maxDcaXY); // in cm + void SetMaxDcaZ(float maxDcaZ); // in cm void SetMaxDcaXYPtDep(std::function ptDepCut); void ApplyPrefilter(bool flag); void ApplyPhiV(bool flag); @@ -397,15 +305,13 @@ class DalitzEECut : public TNamed // Getters bool IsPhotonConversionSelected() const { return mSelectPC; } - /// @brief Print the track selection - void print() const; - private: + static const std::pair> its_ib_any_Requirement; + static const std::pair> its_ib_1st_Requirement; // pair cuts float mMinMee{0.f}, mMaxMee{1e10f}; - float mMinPairPt{0.f}, mMaxPairPt{1e10f}; // range in pT - float mMinPairEta{-1e10f}, mMaxPairEta{1e10f}; // range in eta - float mMinPairDCA3D{0.f}, mMaxPairDCA3D{1e10f}; // range in 3D DCA in sigma + float mMinPairPt{0.f}, mMaxPairPt{1e10f}; // range in pT + float mMinPairY{-1e10f}, mMaxPairY{1e10f}; // range in rapidity float mMinPhivPair{0.f}, mMaxPhivPair{+3.2}; std::function mMaxPhivPairMeeDep{}; // max phiv as a function of mee bool mSelectPC{false}; // flag to select photon conversion used in mMaxPhivPairMeeDep @@ -419,9 +325,12 @@ class DalitzEECut : public TNamed int mMinNCrossedRowsTPC{0}; // min number of crossed rows in TPC float mMinChi2PerClusterTPC{-1e10f}, mMaxChi2PerClusterTPC{1e10f}; // max tpc fit chi2 per TPC cluster float mMinNCrossedRowsOverFindableClustersTPC{0.f}; // min ratio crossed rows / findable clusters + float mMaxFracSharedClustersTPC{999.f}; // max ratio shared clusters / clusters in TPC int mMinNClustersITS{0}, mMaxNClustersITS{7}; // range in number of ITS clusters float mMinChi2PerClusterITS{-1e10f}, mMaxChi2PerClusterITS{1e10f}; // max its fit chi2 per ITS cluster float mMaxPinMuonTPConly{0.2f}; // max pin cut for muon ID with TPConly + bool mRequireITSibAny{true}; + bool mRequireITSib1st{false}; float mMinDca3D{0.0f}; // min dca in 3D in units of sigma float mMaxDca3D{1e+10}; // max dca in 3D in units of sigma @@ -429,26 +338,14 @@ class DalitzEECut : public TNamed float mMaxDcaZ{1.0f}; // max dca in z direction std::function mMaxDcaXYPtDep{}; // max dca in xy plane as function of pT bool mApplyPhiV{true}; - bool mApplyPF{false}; float mMinMeanClusterSizeITS{-1e10f}, mMaxMeanClusterSizeITS{1e10f}; // max x cos(Lmabda) + float mMinChi2TOF{-1e10f}, mMaxChi2TOF{1e10f}; // max tof chi2 per // pid cuts - PIDSchemes mPIDScheme{PIDSchemes::kUnDef}; - float mMinPinTOF{0.0f}; // min pin cut for TOF. - bool mMuonExclusionTPC{false}; // flag to reject muon in TPC for low B - bool mApplyTOFbeta{false}; // flag to reject hadron contamination with TOF - float mMinTOFbeta{0.0}, mMaxTOFbeta{0.95}; + int mPIDScheme{-1}; float mMinTPCNsigmaEl{-1e+10}, mMaxTPCNsigmaEl{+1e+10}; - float mMinTPCNsigmaMu{-1e+10}, mMaxTPCNsigmaMu{+1e+10}; - float mMinTPCNsigmaPi{-1e+10}, mMaxTPCNsigmaPi{+1e+10}; - float mMinTPCNsigmaKa{-1e+10}, mMaxTPCNsigmaKa{+1e+10}; - float mMinTPCNsigmaPr{-1e+10}, mMaxTPCNsigmaPr{+1e+10}; - + float mMinTPCNsigmaPi{0}, mMaxTPCNsigmaPi{0}; float mMinTOFNsigmaEl{-1e+10}, mMaxTOFNsigmaEl{+1e+10}; - float mMinTOFNsigmaMu{-1e+10}, mMaxTOFNsigmaMu{+1e+10}; - float mMinTOFNsigmaPi{-1e+10}, mMaxTOFNsigmaPi{+1e+10}; - float mMinTOFNsigmaKa{-1e+10}, mMaxTOFNsigmaKa{+1e+10}; - float mMinTOFNsigmaPr{-1e+10}, mMaxTOFNsigmaPr{+1e+10}; ClassDef(DalitzEECut, 1); }; diff --git a/PWGEM/PhotonMeson/Core/EMCPhotonCut.cxx b/PWGEM/PhotonMeson/Core/EMCPhotonCut.cxx index 502e5b283a1..582b9754057 100644 --- a/PWGEM/PhotonMeson/Core/EMCPhotonCut.cxx +++ b/PWGEM/PhotonMeson/Core/EMCPhotonCut.cxx @@ -13,13 +13,20 @@ // Class for EMCal cluster selection // +#include #include "Framework/Logger.h" #include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" +#include "PWGJE/DataModel/EMCALClusters.h" ClassImp(EMCPhotonCut); -const char* EMCPhotonCut::mCutNames[static_cast(EMCPhotonCut::EMCPhotonCuts::kNCuts)] = {"Energy", "NCell", "M02", "Timing", "TrackMatching", "Exotic"}; +const char* EMCPhotonCut::mCutNames[static_cast(EMCPhotonCut::EMCPhotonCuts::kNCuts)] = {"Definition", "Energy", "NCell", "M02", "Timing", "TrackMatching", "Exotic"}; +void EMCPhotonCut::SetClusterizer(std::string clusterDefinitionString) +{ + mDefinition = static_cast(o2::aod::emcalcluster::getClusterDefinitionFromString(clusterDefinitionString)); + LOG(info) << "EMCal Photon Cut, set cluster definition to: " << mDefinition << " (" << clusterDefinitionString << ")"; +} void EMCPhotonCut::SetMinE(float min) { mMinE = min; @@ -61,12 +68,20 @@ void EMCPhotonCut::SetUseExoticCut(bool flag) mUseExoticCut = flag; LOG(info) << "EMCal Photon Cut, set usage of exotic cluster cut to: " << mUseExoticCut; } +void EMCPhotonCut::SetUseTM(bool flag) +{ + mUseTM = flag; + LOG(info) << "EM Photon Cluster Cut, using TM cut is set to : " << mUseTM; +} void EMCPhotonCut::print() const { LOG(info) << "EMCal Photon Cut:"; for (int i = 0; i < static_cast(EMCPhotonCuts::kNCuts); i++) { switch (static_cast(i)) { + case EMCPhotonCuts::kDefinition: + LOG(info) << mCutNames[i] << " > " << mDefinition; + break; case EMCPhotonCuts::kEnergy: LOG(info) << mCutNames[i] << " > " << mMinE; break; diff --git a/PWGEM/PhotonMeson/Core/EMCPhotonCut.h b/PWGEM/PhotonMeson/Core/EMCPhotonCut.h index 1a2e0f28b48..8bfd8ca630f 100644 --- a/PWGEM/PhotonMeson/Core/EMCPhotonCut.h +++ b/PWGEM/PhotonMeson/Core/EMCPhotonCut.h @@ -34,7 +34,8 @@ class EMCPhotonCut : public TNamed enum class EMCPhotonCuts : int { // cluster cut - kEnergy = 0, + kDefinition = 0, + kEnergy, kNCell, kM02, kTiming, @@ -49,35 +50,38 @@ class EMCPhotonCut : public TNamed template bool IsSelected(Cluster const& cluster) const { - // auto track = cluster.template MatchedTrack_as(); - auto track = nullptr; - if (!IsSelectedEMCal(EMCPhotonCuts::kEnergy, cluster, track)) { + if (!IsSelectedEMCal(EMCPhotonCuts::kDefinition, cluster)) { return false; } - if (!IsSelectedEMCal(EMCPhotonCuts::kNCell, cluster, track)) { + if (!IsSelectedEMCal(EMCPhotonCuts::kEnergy, cluster)) { return false; } - if (!IsSelectedEMCal(EMCPhotonCuts::kM02, cluster, track)) { + if (!IsSelectedEMCal(EMCPhotonCuts::kNCell, cluster)) { return false; } - if (!IsSelectedEMCal(EMCPhotonCuts::kTiming, cluster, track)) { + if (!IsSelectedEMCal(EMCPhotonCuts::kM02, cluster)) { return false; } - if (!IsSelectedEMCal(EMCPhotonCuts::kTM, cluster, track)) { + if (!IsSelectedEMCal(EMCPhotonCuts::kTiming, cluster)) { return false; } - if (!IsSelectedEMCal(EMCPhotonCuts::kExotic, cluster, track)) { + if (mUseTM && (!IsSelectedEMCal(EMCPhotonCuts::kTM, cluster))) { + return false; + } + if (!IsSelectedEMCal(EMCPhotonCuts::kExotic, cluster)) { return false; } return true; } - // Temporary function to check if cluster passes a given selection criteria. To be replaced by framework filters. // Returns true if a cluster survives the cuts! - template - bool IsSelectedEMCal(const EMCPhotonCuts& cut, Cluster const& cluster, Track const& /*track*/) const + template + bool IsSelectedEMCal(const EMCPhotonCuts& cut, Cluster const& cluster) const { switch (cut) { + case EMCPhotonCuts::kDefinition: + return cluster.definition() == mDefinition; + case EMCPhotonCuts::kEnergy: return cluster.e() > mMinE; @@ -116,6 +120,7 @@ class EMCPhotonCut : public TNamed } // Setters + void SetClusterizer(std::string clusterDefinitionString = "kV3Default"); void SetMinE(float min = 0.7f); void SetMinNCell(int min = 1); void SetM02Range(float min = 0.1f, float max = 0.7f); @@ -124,12 +129,14 @@ class EMCPhotonCut : public TNamed void SetTrackMatchingPhi(std::function funcTM); void SetMinEoverP(float min = 0.7f); void SetUseExoticCut(bool flag = true); + void SetUseTM(bool flag = true); /// @brief Print the cluster selection void print() const; private: // EMCal cluster cuts + int mDefinition{10}; ///< clusterizer definition float mMinE{0.7f}; ///< minimum energy int mMinNCell{1}; ///< minimum number of cells per cluster float mMinM02{0.1f}; ///< minimum M02 for a cluster @@ -138,6 +145,7 @@ class EMCPhotonCut : public TNamed float mMaxTime{25.f}; ///< maximum cluster timing float mMinEoverP{1.75f}; ///< minimum cluster energy over track momentum ratio needed for the pair to be considered matched bool mUseExoticCut{true}; ///< flag to decide if the exotic cluster cut is to be checked or not + bool mUseTM{true}; ///< flag to decide if track matching cut is to be checek or not std::function mTrackMatchingEta{}; ///< function to get check if a pre matched track and cluster pair is considered an actual match for eta std::function mTrackMatchingPhi{}; ///< function to get check if a pre matched track and cluster pair is considered an actual match for phi diff --git a/PWGEM/PhotonMeson/Core/EMPhotonEventCut.cxx b/PWGEM/PhotonMeson/Core/EMPhotonEventCut.cxx new file mode 100644 index 00000000000..285bf50eba4 --- /dev/null +++ b/PWGEM/PhotonMeson/Core/EMPhotonEventCut.cxx @@ -0,0 +1,31 @@ +// 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. + +// +// Class for em photon event selection +// + +#include "Framework/Logger.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" + +ClassImp(EMPhotonEventCut); + +void EMPhotonEventCut::SetRequireEMCReadoutInMB(bool flag) +{ + mRequireEMCReadoutInMB = flag; + LOG(info) << "EM Photon Event Cut, require the EMC to be read out in an MB collision by checking kTVXinEMC: " << mRequireEMCReadoutInMB; +} + +void EMPhotonEventCut::SetRequireEMCHardwareTriggered(bool flag) +{ + mRequireEMCHardwareTriggered = flag; + LOG(info) << "EM Photon Event Cut, require the EMC to be triggered by requiring kEMC7 or kDMC7: " << mRequireEMCHardwareTriggered; +} diff --git a/PWGEM/PhotonMeson/Core/EMPhotonEventCut.h b/PWGEM/PhotonMeson/Core/EMPhotonEventCut.h new file mode 100644 index 00000000000..3b134ce882e --- /dev/null +++ b/PWGEM/PhotonMeson/Core/EMPhotonEventCut.h @@ -0,0 +1,76 @@ +// 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. + +// +// Class for em photon event selection +// + +#ifndef PWGEM_PHOTONMESON_CORE_EMPHOTONEVENTCUT_H_ +#define PWGEM_PHOTONMESON_CORE_EMPHOTONEVENTCUT_H_ + +#include "PWGEM/Dilepton/Core/EMEventCut.h" + +using namespace std; + +class EMPhotonEventCut : public EMEventCut +{ + public: + EMPhotonEventCut() = default; + EMPhotonEventCut(const char* name, const char* title) : EMEventCut(name, title) {} + + enum class EMPhotonEventCuts : int { + kEMCReadoutInMB = 0, + kEMCHardwareTriggered, + kNCuts + }; + + template + bool IsSelected(T const& collision) const + { + if (!EMEventCut::IsSelected(collision)) { + return false; + } + if (mRequireEMCReadoutInMB && !IsSelected(collision, EMPhotonEventCuts::kEMCReadoutInMB)) { + return false; + } + if (mRequireEMCHardwareTriggered && !IsSelected(collision, EMPhotonEventCuts::kEMCHardwareTriggered)) { + return false; + } + return true; + } + + template + bool IsSelected(T const& collision, const EMPhotonEventCuts& cut) const + { + switch (cut) { + case EMPhotonEventCuts::kEMCReadoutInMB: + return (collision.alias_bit(kTVXinEMC)); + + case EMPhotonEventCuts::kEMCHardwareTriggered: + return (collision.alias_bit(kEMC7) || collision.alias_bit(kDMC7)); + + default: + return true; + } + } + + // Setters + void SetRequireEMCReadoutInMB(bool flag); + void SetRequireEMCHardwareTriggered(bool flag); + + private: + bool mRequireEMCReadoutInMB{false}; + bool mRequireEMCHardwareTriggered{false}; + + ClassDef(EMPhotonEventCut, 1); +}; + +#endif // PWGEM_PHOTONMESON_CORE_EMPHOTONEVENTCUT_H_ diff --git a/PWGEM/PhotonMeson/Core/HistogramsLibrary.h b/PWGEM/PhotonMeson/Core/HistogramsLibrary.h index a5a2683474c..324718a663e 100644 --- a/PWGEM/PhotonMeson/Core/HistogramsLibrary.h +++ b/PWGEM/PhotonMeson/Core/HistogramsLibrary.h @@ -102,8 +102,8 @@ void FillHistClass(THashList* list, const char* subGroup, T1 const& obj1 /*, con reinterpret_cast(list->FindObject("hQ2yFT0A_CentFT0C"))->Fill(obj1.centFT0C(), obj1.q2yft0a()); reinterpret_cast(list->FindObject("hQ2xFT0C_CentFT0C"))->Fill(obj1.centFT0C(), obj1.q2xft0c()); reinterpret_cast(list->FindObject("hQ2yFT0C_CentFT0C"))->Fill(obj1.centFT0C(), obj1.q2yft0c()); - reinterpret_cast(list->FindObject("hQ2xFV0A_CentFT0C"))->Fill(obj1.centFT0C(), obj1.q2xfv0a()); - reinterpret_cast(list->FindObject("hQ2yFV0A_CentFT0C"))->Fill(obj1.centFT0C(), obj1.q2yfv0a()); + // reinterpret_cast(list->FindObject("hQ2xFV0A_CentFT0C"))->Fill(obj1.centFT0C(), obj1.q2xfv0a()); + // reinterpret_cast(list->FindObject("hQ2yFV0A_CentFT0C"))->Fill(obj1.centFT0C(), obj1.q2yfv0a()); reinterpret_cast(list->FindObject("hQ2xBPos_CentFT0C"))->Fill(obj1.centFT0C(), obj1.q2xbpos()); reinterpret_cast(list->FindObject("hQ2yBPos_CentFT0C"))->Fill(obj1.centFT0C(), obj1.q2ybpos()); reinterpret_cast(list->FindObject("hQ2xBNeg_CentFT0C"))->Fill(obj1.centFT0C(), obj1.q2xbneg()); @@ -112,14 +112,14 @@ void FillHistClass(THashList* list, const char* subGroup, T1 const& obj1 /*, con reinterpret_cast(list->FindObject("hEP2FT0M_CentFT0C"))->Fill(obj1.centFT0C(), obj1.ep2ft0m()); reinterpret_cast(list->FindObject("hEP2FT0A_CentFT0C"))->Fill(obj1.centFT0C(), obj1.ep2ft0a()); reinterpret_cast(list->FindObject("hEP2FT0C_CentFT0C"))->Fill(obj1.centFT0C(), obj1.ep2ft0c()); - reinterpret_cast(list->FindObject("hEP2FV0A_CentFT0C"))->Fill(obj1.centFT0C(), obj1.ep2fv0a()); + // reinterpret_cast(list->FindObject("hEP2FV0A_CentFT0C"))->Fill(obj1.centFT0C(), obj1.ep2fv0a()); reinterpret_cast(list->FindObject("hEP2BPos_CentFT0C"))->Fill(obj1.centFT0C(), obj1.ep2bpos()); reinterpret_cast(list->FindObject("hEP2BNeg_CentFT0C"))->Fill(obj1.centFT0C(), obj1.ep2bneg()); std::array q2ft0m = {obj1.q2xft0m(), obj1.q2yft0m()}; std::array q2ft0a = {obj1.q2xft0a(), obj1.q2yft0a()}; std::array q2ft0c = {obj1.q2xft0c(), obj1.q2yft0c()}; - std::array q2fv0a = {obj1.q2xfv0a(), obj1.q2yfv0a()}; + // std::array q2fv0a = {obj1.q2xfv0a(), obj1.q2yfv0a()}; std::array q2bpos = {obj1.q2xbpos(), obj1.q2ybpos()}; std::array q2bneg = {obj1.q2xbneg(), obj1.q2ybneg()}; @@ -129,8 +129,8 @@ void FillHistClass(THashList* list, const char* subGroup, T1 const& obj1 /*, con reinterpret_cast(list->FindObject("hQ2FT0AQ2BNeg_CentFT0C"))->Fill(obj1.centFT0C(), RecoDecay::dotProd(q2ft0a, q2bneg)); reinterpret_cast(list->FindObject("hQ2FT0CQ2BPos_CentFT0C"))->Fill(obj1.centFT0C(), RecoDecay::dotProd(q2ft0c, q2bpos)); reinterpret_cast(list->FindObject("hQ2FT0CQ2BNeg_CentFT0C"))->Fill(obj1.centFT0C(), RecoDecay::dotProd(q2ft0c, q2bneg)); - reinterpret_cast(list->FindObject("hQ2FV0AQ2BPos_CentFT0C"))->Fill(obj1.centFT0C(), RecoDecay::dotProd(q2fv0a, q2bpos)); - reinterpret_cast(list->FindObject("hQ2FV0AQ2BNeg_CentFT0C"))->Fill(obj1.centFT0C(), RecoDecay::dotProd(q2fv0a, q2bneg)); + // reinterpret_cast(list->FindObject("hQ2FV0AQ2BPos_CentFT0C"))->Fill(obj1.centFT0C(), RecoDecay::dotProd(q2fv0a, q2bpos)); + // reinterpret_cast(list->FindObject("hQ2FV0AQ2BNeg_CentFT0C"))->Fill(obj1.centFT0C(), RecoDecay::dotProd(q2fv0a, q2bneg)); reinterpret_cast(list->FindObject("hQ2BPosQ2BNeg_CentFT0C"))->Fill(obj1.centFT0C(), RecoDecay::dotProd(q2bpos, q2bneg)); } } else if constexpr (htype1 == EMHistType::kV0) { diff --git a/PWGEM/PhotonMeson/Core/PWGEMPhotonMesonCoreLinkDef.h b/PWGEM/PhotonMeson/Core/PWGEMPhotonMesonCoreLinkDef.h index a77ec53929f..ff03b41a75e 100644 --- a/PWGEM/PhotonMeson/Core/PWGEMPhotonMesonCoreLinkDef.h +++ b/PWGEM/PhotonMeson/Core/PWGEMPhotonMesonCoreLinkDef.h @@ -16,11 +16,11 @@ #pragma link off all classes; #pragma link off all functions; -#pragma link C++ class EMEventCut + ; #pragma link C++ class V0PhotonCut + ; #pragma link C++ class DalitzEECut + ; #pragma link C++ class PHOSPhotonCut + ; #pragma link C++ class EMCPhotonCut + ; +#pragma link C++ class EMPhotonEventCut + ; #pragma link C++ class PairCut + ; #endif // PWGEM_PHOTONMESON_CORE_PWGEMPHOTONMESONCORELINKDEF_H_ diff --git a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h new file mode 100644 index 00000000000..e4bc8414601 --- /dev/null +++ b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h @@ -0,0 +1,929 @@ +// 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 Pi0EtaToGammaGamma.h +/// \brief This code loops over photons and makes pairs for neutral mesons analyses. +/// +/// \author D. Sekihata, daiki.sekihata@cern.ch + +#ifndef PWGEM_PHOTONMESON_CORE_PI0ETATOGAMMAGAMMA_H_ +#define PWGEM_PHOTONMESON_CORE_PI0ETATOGAMMAGAMMA_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TString.h" +#include "Math/Vector4D.h" +#include "Math/Vector3D.h" +#include "Math/LorentzRotation.h" +#include "Math/Rotation3D.h" +#include "Math/AxisAngle.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#include "DetectorsBase/GeometryManager.h" +#include "EMCALBase/Geometry.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + +#include "Common/Core/RecoDecay.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" +#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" +#include "PWGEM/Dilepton/Utils/EMTrack.h" +#include "PWGEM/Dilepton/Utils/EventMixingHandler.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" +#include "PWGEM/PhotonMeson/Utils/NMHistograms.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::photonmeson::photonpair; +using namespace o2::aod::pwgem::photon; +using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; +using namespace o2::aod::pwgem::dilepton::utils; + +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; + +using MyV0Photons = soa::Filtered>; +using MyV0Photon = MyV0Photons::iterator; + +using MyPrimaryElectrons = soa::Filtered>; +using MyPrimaryElectron = MyPrimaryElectrons::iterator; + +using MyEMCClusters = soa::Join; +using MyEMCCluster = MyEMCClusters::iterator; + +using MyPHOSClusters = soa::Join; +using MyPHOSCluster = MyPHOSClusters::iterator; + +template +struct Pi0EtaToGammaGamma { + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + Configurable ndiff_bc_mix{"ndiff_bc_mix", 198, "difference in global BC required in mixed events"}; + + Configurable cfgQvecEstimator{"cfgQvecEstimator", 0, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgOccupancyEstimator{"cfgOccupancyEstimator", 0, "FT0C:0, Track:1"}; + Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999, "max. centrality"}; + Configurable maxY{"maxY", 0.8, "maximum rapidity for reconstructed particles"}; + Configurable cfgDoMix{"cfgDoMix", true, "flag for event mixing"}; + Configurable ndepth{"ndepth", 10, "depth for event mixing"}; + ConfigurableAxis ConfVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis ConfCentBins{"ConfCentBins", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.f, 999.f}, "Mixing bins - centrality"}; + ConfigurableAxis ConfEPBins{"ConfEPBins", {VARIABLE_WIDTH, -M_PI / 2, -M_PI / 4, 0.0f, +M_PI / 4, +M_PI / 2}, "Mixing bins - event plane angle"}; + ConfigurableAxis ConfOccupancyBins{"ConfOccupancyBins", {VARIABLE_WIDTH, -1, 1e+10}, "Mixing bins - occupancy"}; + + EMPhotonEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgRequireEMCReadoutInMB{"cfgRequireEMCReadoutInMB", false, "require the EMC to be read out in an MB collision (kTVXinEMC)"}; + Configurable cfgRequireEMCHardwareTriggered{"cfgRequireEMCHardwareTriggered", false, "require the EMC to be hardware triggered (kEMC7 or kDMC7)"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable onlyKeepWeightedEvents{"onlyKeepWeightedEvents", false, "flag to keep only weighted events (for JJ MCs) and remove all MB events (with weight = 1)"}; + } eventcuts; + + V0PhotonCut fV0PhotonCut; + struct : ConfigurableGroup { + std::string prefix = "pcmcut_group"; + Configurable cfg_require_v0_with_itstpc{"cfg_require_v0_with_itstpc", false, "flag to select V0s with ITS-TPC matched tracks"}; + Configurable cfg_require_v0_with_itsonly{"cfg_require_v0_with_itsonly", false, "flag to select V0s with ITSonly tracks"}; + Configurable cfg_require_v0_with_tpconly{"cfg_require_v0_with_tpconly", false, "flag to select V0s with TPConly tracks"}; + Configurable cfg_min_pt_v0{"cfg_min_pt_v0", 0.1, "min pT for v0 photons at PV"}; + Configurable cfg_max_pt_v0{"cfg_max_pt_v0", 1e+10, "max pT for v0 photons at PV"}; + Configurable cfg_min_eta_v0{"cfg_min_eta_v0", -0.8, "min eta for v0 photons at PV"}; + Configurable cfg_max_eta_v0{"cfg_max_eta_v0", 0.8, "max eta for v0 photons at PV"}; + Configurable cfg_min_v0radius{"cfg_min_v0radius", 4.0, "min v0 radius"}; + Configurable cfg_max_v0radius{"cfg_max_v0radius", 90.0, "max v0 radius"}; + Configurable cfg_max_alpha_ap{"cfg_max_alpha_ap", 0.95, "max alpha for AP cut"}; + Configurable cfg_max_qt_ap{"cfg_max_qt_ap", 0.01, "max qT for AP cut"}; + Configurable cfg_min_cospa{"cfg_min_cospa", 0.997, "min V0 CosPA"}; + Configurable cfg_max_pca{"cfg_max_pca", 3.0, "max distance btween 2 legs"}; + Configurable cfg_max_chi2kf{"cfg_max_chi2kf", 1e+10, "max chi2/ndf with KF"}; + Configurable cfg_require_v0_with_correct_xz{"cfg_require_v0_with_correct_xz", true, "flag to select V0s with correct xz"}; + Configurable cfg_reject_v0_on_itsib{"cfg_reject_v0_on_itsib", true, "flag to reject V0s on ITSib"}; + Configurable cfg_apply_cuts_from_prefilter_derived{"cfg_apply_cuts_from_prefilter_derived", false, "flag to apply prefilter to V0"}; + + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 10, "min ncluster tpc"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 40, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -3.0, "min. TPC n sigma for electron"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; + Configurable cfg_disable_itsonly_track{"cfg_disable_itsonly_track", false, "flag to disable ITSonly tracks"}; + Configurable cfg_disable_tpconly_track{"cfg_disable_tpconly_track", false, "flag to disable TPConly tracks"}; + } pcmcuts; + + DalitzEECut fDileptonCut; + struct : ConfigurableGroup { + std::string prefix = "dileptoncut_group"; + Configurable cfg_min_mass{"cfg_min_mass", 0.0, "min mass"}; + Configurable cfg_max_mass{"cfg_max_mass", 0.1, "max mass"}; + Configurable cfg_apply_phiv{"cfg_apply_phiv", true, "flag to apply phiv cut"}; + Configurable cfg_require_itsib_any{"cfg_require_itsib_any", false, "flag to require ITS ib any hits"}; + Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; + Configurable cfg_phiv_slope{"cfg_phiv_slope", 0.0185, "slope for m vs. phiv"}; + Configurable cfg_phiv_intercept{"cfg_phiv_intercept", -0.0280, "intercept for m vs. phiv"}; + + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.1, "min pT for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", 0.8, "max eta for single track"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 70, "min ncrossed rows"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 0.05, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 0.05, "max dca Z for single track in cm"}; + Configurable cfg_max_dca3dsigma_track{"cfg_max_dca3dsigma_track", 1.5, "max DCA 3D in sigma"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_apply_cuts_from_prefilter_derived{"cfg_apply_cuts_from_prefilter_derived", false, "flag to apply prefilter to electron"}; + + Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DalitzEECut::PIDSchemes::kTOFif), "pid scheme [kTOFif : 0, kTPConly : 1]"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -0.0, "min. TPC n sigma for pion exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +0.0, "max. TPC n sigma for pion exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; + } dileptoncuts; + + EMCPhotonCut fEMCCut; + struct : ConfigurableGroup { + std::string prefix = "emccut_group"; + Configurable clusterDefinition{"clusterDefinition", "kV3Default", "Clusterizer to be selected, e.g. V3Default"}; + Configurable minOpenAngle{"minOpenAngle", 0.0202, "apply min opening angle"}; + Configurable EMC_minTime{"EMC_minTime", -20., "Minimum cluster time for EMCal time cut"}; + Configurable EMC_maxTime{"EMC_maxTime", +25., "Maximum cluster time for EMCal time cut"}; + Configurable EMC_minM02{"EMC_minM02", 0.1, "Minimum M02 for EMCal M02 cut"}; + Configurable EMC_maxM02{"EMC_maxM02", 0.7, "Maximum M02 for EMCal M02 cut"}; + Configurable EMC_minE{"EMC_minE", 0.7, "Minimum cluster energy for EMCal energy cut"}; + Configurable EMC_minNCell{"EMC_minNCell", 1, "Minimum number of cells per cluster for EMCal NCell cut"}; + Configurable> EMC_TM_Eta{"EMC_TM_Eta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable> EMC_TM_Phi{"EMC_TM_Phi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable EMC_Eoverp{"EMC_Eoverp", 1.75, "Minimum cluster energy over track momentum for EMCal track matching"}; + Configurable EMC_UseExoticCut{"EMC_UseExoticCut", true, "FLag to use the EMCal exotic cluster cut"}; + Configurable cfgDistanceToEdge{"cfgDistanceToEdge", 1, "Distance to edge in cells required for rotated cluster to be accepted"}; + } emccuts; + + PHOSPhotonCut fPHOSCut; + struct : ConfigurableGroup { + std::string prefix = "phoscut_group"; + Configurable cfg_min_Ecluster{"cfg_min_Ecluster", 0.3, "Minimum cluster energy for PHOS in GeV"}; + } phoscuts; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view event_types[2] = {"before/", "after/"}; + static constexpr std::string_view event_pair_types[2] = {"same/", "mix/"}; + + std::vector zvtx_bin_edges; + std::vector cent_bin_edges; + std::vector ep_bin_edges; + std::vector occ_bin_edges; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + int mRunNumber; + float d_bz; + o2::emcal::Geometry* emcalGeom; + + void init(InitContext&) + { + zvtx_bin_edges = std::vector(ConfVtxBins.value.begin(), ConfVtxBins.value.end()); + zvtx_bin_edges.erase(zvtx_bin_edges.begin()); + + cent_bin_edges = std::vector(ConfCentBins.value.begin(), ConfCentBins.value.end()); + cent_bin_edges.erase(cent_bin_edges.begin()); + + ep_bin_edges = std::vector(ConfEPBins.value.begin(), ConfEPBins.value.end()); + ep_bin_edges.erase(ep_bin_edges.begin()); + + LOGF(info, "cfgOccupancyEstimator = %d", cfgOccupancyEstimator.value); + occ_bin_edges = std::vector(ConfOccupancyBins.value.begin(), ConfOccupancyBins.value.end()); + occ_bin_edges.erase(occ_bin_edges.begin()); + + emh1 = new MyEMH(ndepth); + emh2 = new MyEMH(ndepth); + + o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(&fRegistry); + if constexpr (pairtype == PairType::kPCMDalitzEE) { + o2::aod::pwgem::photonmeson::utils::nmhistogram::addNMHistograms(&fRegistry, false, "ee#gamma"); + } else { + o2::aod::pwgem::photonmeson::utils::nmhistogram::addNMHistograms(&fRegistry, false, "#gamma#gamma"); + } + DefineEMEventCut(); + DefinePCMCut(); + DefineDileptonCut(); + DefineEMCCut(); + DefinePHOSCut(); + + if constexpr (pairtype == kEMCEMC) { + fRegistry.addClone("Pair/same/", "Pair/rotation/"); + emcalGeom = o2::emcal::Geometry::GetInstanceFromRunNumber(300000); + } + fRegistry.add("Pair/mix/hDiffBC", "diff. global BC in mixed event;|BC_{current} - BC_{mixed}|", kTH1D, {{10001, -0.5, 10000.5}}, true); + + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + } + + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (std::fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + mRunNumber = collision.runNumber(); + return; + } + + auto run3grp_timestamp = collision.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = collision.runNumber(); + } + + ~Pi0EtaToGammaGamma() + { + delete emh1; + emh1 = 0x0; + delete emh2; + emh2 = 0x0; + + used_photonIds.clear(); + used_photonIds.shrink_to_fit(); + used_dileptonIds.clear(); + used_dileptonIds.shrink_to_fit(); + map_mixed_eventId_to_globalBC.clear(); + } + + void DefineEMEventCut() + { + fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireEMCReadoutInMB(eventcuts.cfgRequireEMCReadoutInMB); + fEMEventCut.SetRequireEMCHardwareTriggered(eventcuts.cfgRequireEMCHardwareTriggered); + } + + void DefinePCMCut() + { + fV0PhotonCut = V0PhotonCut("fV0PhotonCut", "fV0PhotonCut"); + + // for v0 + fV0PhotonCut.SetV0PtRange(pcmcuts.cfg_min_pt_v0, pcmcuts.cfg_max_pt_v0); + fV0PhotonCut.SetV0EtaRange(pcmcuts.cfg_min_eta_v0, pcmcuts.cfg_max_eta_v0); + fV0PhotonCut.SetMinCosPA(pcmcuts.cfg_min_cospa); + fV0PhotonCut.SetMaxPCA(pcmcuts.cfg_max_pca); + fV0PhotonCut.SetMaxChi2KF(pcmcuts.cfg_max_chi2kf); + fV0PhotonCut.SetRxyRange(pcmcuts.cfg_min_v0radius, pcmcuts.cfg_max_v0radius); + fV0PhotonCut.SetAPRange(pcmcuts.cfg_max_alpha_ap, pcmcuts.cfg_max_qt_ap); + fV0PhotonCut.RejectITSib(pcmcuts.cfg_reject_v0_on_itsib); + + // for track + fV0PhotonCut.SetMinNClustersTPC(pcmcuts.cfg_min_ncluster_tpc); + fV0PhotonCut.SetMinNCrossedRowsTPC(pcmcuts.cfg_min_ncrossedrows); + fV0PhotonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fV0PhotonCut.SetMaxFracSharedClustersTPC(pcmcuts.cfg_max_frac_shared_clusters_tpc); + fV0PhotonCut.SetChi2PerClusterTPC(0.0, pcmcuts.cfg_max_chi2tpc); + fV0PhotonCut.SetTPCNsigmaElRange(pcmcuts.cfg_min_TPCNsigmaEl, pcmcuts.cfg_max_TPCNsigmaEl); + fV0PhotonCut.SetChi2PerClusterITS(-1e+10, pcmcuts.cfg_max_chi2its); + fV0PhotonCut.SetNClustersITS(0, 7); + fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); + fV0PhotonCut.SetIsWithinBeamPipe(pcmcuts.cfg_require_v0_with_correct_xz); + fV0PhotonCut.SetDisableITSonly(pcmcuts.cfg_disable_itsonly_track); + fV0PhotonCut.SetDisableTPConly(pcmcuts.cfg_disable_tpconly_track); + fV0PhotonCut.SetRequireITSTPC(pcmcuts.cfg_require_v0_with_itstpc); + fV0PhotonCut.SetRequireITSonly(pcmcuts.cfg_require_v0_with_itsonly); + fV0PhotonCut.SetRequireTPConly(pcmcuts.cfg_require_v0_with_tpconly); + } + + void DefineDileptonCut() + { + fDileptonCut = DalitzEECut("fDileptonCut", "fDileptonCut"); + + // for pair + fDileptonCut.SetMeeRange(dileptoncuts.cfg_min_mass, dileptoncuts.cfg_max_mass); + fDileptonCut.SetMaxPhivPairMeeDep([&](float mll) { return (mll - dileptoncuts.cfg_phiv_intercept) / dileptoncuts.cfg_phiv_slope; }); + fDileptonCut.ApplyPhiV(dileptoncuts.cfg_apply_phiv); + fDileptonCut.RequireITSibAny(dileptoncuts.cfg_require_itsib_any); + fDileptonCut.RequireITSib1st(dileptoncuts.cfg_require_itsib_1st); + + // for track + fDileptonCut.SetTrackPtRange(dileptoncuts.cfg_min_pt_track, 1e+10f); + fDileptonCut.SetTrackEtaRange(-dileptoncuts.cfg_max_eta_track, +dileptoncuts.cfg_max_eta_track); + fDileptonCut.SetMinNClustersTPC(dileptoncuts.cfg_min_ncluster_tpc); + fDileptonCut.SetMinNCrossedRowsTPC(dileptoncuts.cfg_min_ncrossedrows); + fDileptonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fDileptonCut.SetMaxFracSharedClustersTPC(dileptoncuts.cfg_max_frac_shared_clusters_tpc); + fDileptonCut.SetChi2PerClusterTPC(0.0, dileptoncuts.cfg_max_chi2tpc); + fDileptonCut.SetChi2PerClusterITS(0.0, dileptoncuts.cfg_max_chi2its); + fDileptonCut.SetNClustersITS(dileptoncuts.cfg_min_ncluster_its, 7); + fDileptonCut.SetMaxDcaXY(dileptoncuts.cfg_max_dcaxy); + fDileptonCut.SetMaxDcaZ(dileptoncuts.cfg_max_dcaz); + fDileptonCut.SetTrackDca3DRange(0.f, dileptoncuts.cfg_max_dca3dsigma_track); // in sigma + + // for eID + fDileptonCut.SetPIDScheme(dileptoncuts.cfg_pid_scheme); + fDileptonCut.SetTPCNsigmaElRange(dileptoncuts.cfg_min_TPCNsigmaEl, dileptoncuts.cfg_max_TPCNsigmaEl); + fDileptonCut.SetTPCNsigmaPiRange(dileptoncuts.cfg_min_TPCNsigmaPi, dileptoncuts.cfg_max_TPCNsigmaPi); + fDileptonCut.SetTOFNsigmaElRange(dileptoncuts.cfg_min_TOFNsigmaEl, dileptoncuts.cfg_max_TOFNsigmaEl); + } + + void DefineEMCCut() + { + const float a = emccuts.EMC_TM_Eta->at(0); + const float b = emccuts.EMC_TM_Eta->at(1); + const float c = emccuts.EMC_TM_Eta->at(2); + + const float d = emccuts.EMC_TM_Phi->at(0); + const float e = emccuts.EMC_TM_Phi->at(1); + const float f = emccuts.EMC_TM_Phi->at(2); + LOGF(info, "EMCal track matching parameters : a = %f, b = %f, c = %f, d = %f, e = %f, f = %f", a, b, c, d, e, f); + + fEMCCut = EMCPhotonCut("fEMCCut", "fEMCCut"); + + fEMCCut.SetClusterizer(emccuts.clusterDefinition); + fEMCCut.SetMinE(emccuts.EMC_minE); + fEMCCut.SetMinNCell(emccuts.EMC_minNCell); + fEMCCut.SetM02Range(emccuts.EMC_minM02, emccuts.EMC_maxM02); + fEMCCut.SetTimeRange(emccuts.EMC_minTime, emccuts.EMC_maxTime); + + fEMCCut.SetTrackMatchingEta([a, b, c](float pT) { return a + std::pow(pT + b, c); }); + fEMCCut.SetTrackMatchingPhi([d, e, f](float pT) { return d + std::pow(pT + e, f); }); + + fEMCCut.SetMinEoverP(emccuts.EMC_Eoverp); + fEMCCut.SetUseExoticCut(emccuts.EMC_UseExoticCut); + } + + void DefinePHOSCut() + { + fPHOSCut.SetEnergyRange(phoscuts.cfg_min_Ecluster, 1e+10); + } + + /// \brief returns if cluster is too close to edge of EMCal (using rotation background method only for EMCal!) + bool IsTooCloseToEdge(const int cellID, const int DistanceToBorder = 1) + { + if (DistanceToBorder <= 0) { + return false; + } + if (cellID < 0) { + return true; + } + + int iBadCell = -1; + + // check distance to border in case the cell is okay + auto [iSupMod, iMod, iPhi, iEta] = emcalGeom->GetCellIndex(cellID); + auto [irow, icol] = emcalGeom->GetCellPhiEtaIndexInSModule(iSupMod, iMod, iPhi, iEta); + + // Check rows/phi + int iRowLast = 24; + if (emcalGeom->GetSMType(iSupMod) == o2::emcal::EMCALSMType::EMCAL_HALF) { + iRowLast /= 2; // 2/3 sm case + } else if (emcalGeom->GetSMType(iSupMod) == o2::emcal::EMCALSMType::EMCAL_THIRD) { + iRowLast /= 3; // 1/3 sm case + } else if (emcalGeom->GetSMType(iSupMod) == o2::emcal::EMCALSMType::DCAL_EXT) { + iRowLast /= 3; // 1/3 sm case + } + + if (irow < DistanceToBorder || (iRowLast - irow) <= DistanceToBorder) { + iBadCell = 1; + } + + if (iBadCell > 0) { + return true; + } + return false; + } + + /// \brief Calculate background (using rotation background method only for EMCal!) + template + void RotationBackground(const ROOT::Math::PtEtaPhiMVector& meson, ROOT::Math::PtEtaPhiMVector photon1, ROOT::Math::PtEtaPhiMVector photon2, TPhotons const& photons_coll, unsigned int ig1, unsigned int ig2, float eventWeight) + { + // if less than 3 clusters are present skip event since we need at least 3 clusters + if (photons_coll.size() < 3) { + return; + } + const float rotationAngle = M_PI / 2.0; // rotaion angle 90 degree + ROOT::Math::AxisAngle rotationAxis(meson.Vect(), rotationAngle); + ROOT::Math::Rotation3D rotationMatrix(rotationAxis); + photon1 = rotationMatrix * photon1; + photon2 = rotationMatrix * photon2; + + int iCellID_photon1 = 0; + int iCellID_photon2 = 0; + + try { + iCellID_photon1 = emcalGeom->GetAbsCellIdFromEtaPhi(photon1.Eta(), photon1.Phi()); + if (IsTooCloseToEdge(iCellID_photon1, emccuts.cfgDistanceToEdge.value)) { + iCellID_photon1 = -1; + } + } catch (o2::emcal::InvalidPositionException& e) { + iCellID_photon1 = -1; + } + try { + iCellID_photon2 = emcalGeom->GetAbsCellIdFromEtaPhi(photon2.Eta(), photon2.Phi()); + if (IsTooCloseToEdge(iCellID_photon2, emccuts.cfgDistanceToEdge.value)) { + iCellID_photon2 = -1; + } + } catch (o2::emcal::InvalidPositionException& e) { + iCellID_photon2 = -1; + } + if (iCellID_photon1 == -1 && iCellID_photon2 == -1) { + return; + } + + for (const auto& photon : photons_coll) { + if (photon.globalIndex() == ig1 || photon.globalIndex() == ig2) { + // only combine rotated photons with other photons + continue; + } + if (!(fEMCCut.IsSelected(photon))) { + continue; + } + + ROOT::Math::PtEtaPhiMVector photon3(photon.pt(), photon.eta(), photon.phi(), 0.); + ROOT::Math::PtEtaPhiMVector mother1 = photon1 + photon3; + ROOT::Math::PtEtaPhiMVector mother2 = photon2 + photon3; + + float openingAngle1 = std::acos(photon1.Vect().Dot(photon3.Vect()) / (photon1.P() * photon3.P())); + float openingAngle2 = std::acos(photon2.Vect().Dot(photon3.Vect()) / (photon2.P() * photon3.P())); + + if (openingAngle1 > emccuts.minOpenAngle && std::fabs(mother1.Rapidity()) < maxY && iCellID_photon1 > 0) { + fRegistry.fill(HIST("Pair/rotation/hs"), mother1.M(), mother1.Pt(), eventWeight); + } + if (openingAngle2 > emccuts.minOpenAngle && std::fabs(mother2.Rapidity()) < maxY && iCellID_photon2 > 0) { + fRegistry.fill(HIST("Pair/rotation/hs"), mother2.M(), mother2.Pt(), eventWeight); + } + } + return; + } + + SliceCache cache; + Preslice perCollision_pcm = aod::v0photonkf::emeventId; + Preslice perCollision_emc = aod::emccluster::emeventId; + Preslice perCollision_phos = aod::phoscluster::emeventId; + + Preslice perCollision_electron = aod::emprimaryelectron::emeventId; + Partition positrons = o2::aod::emprimaryelectron::sign > int8_t(0) && static_cast(dileptoncuts.cfg_min_pt_track) < o2::aod::track::pt&& nabs(o2::aod::track::eta) < static_cast(dileptoncuts.cfg_max_eta_track) && static_cast(dileptoncuts.cfg_min_TPCNsigmaEl) < o2::aod::pidtpc::tpcNSigmaEl&& o2::aod::pidtpc::tpcNSigmaEl < static_cast(dileptoncuts.cfg_max_TPCNsigmaEl); + Partition electrons = o2::aod::emprimaryelectron::sign < int8_t(0) && static_cast(dileptoncuts.cfg_min_pt_track) < o2::aod::track::pt && nabs(o2::aod::track::eta) < static_cast(dileptoncuts.cfg_max_eta_track) && static_cast(dileptoncuts.cfg_min_TPCNsigmaEl) < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < static_cast(dileptoncuts.cfg_max_TPCNsigmaEl); + + using MyEMH = o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, EMTrack>; + MyEMH* emh1 = nullptr; + MyEMH* emh2 = nullptr; + std::vector> used_photonIds; // + std::vector> used_dileptonIds; // + std::map, uint64_t> map_mixed_eventId_to_globalBC; + + template + void runPairing(TCollisions const& collisions, + TPhotons1 const& photons1, TPhotons2 const& photons2, + TSubInfos1 const& /*subinfos1*/, TSubInfos2 const& /*subinfos2*/, + TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, + TCut1 const& cut1, TCut2 const& cut2) + { + for (const auto& collision : collisions) { + initCCDB(collision); + int ndiphoton = 0; + if ((pairtype == PairType::kPHOSPHOS || pairtype == PairType::kPCMPHOS) && !collision.alias_bit(triggerAliases::kTVXinPHOS)) { + continue; + } + + if (eventcuts.onlyKeepWeightedEvents && std::fabs(collision.weight() - 1.) < 1E-10) { + continue; + } + + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision, collision.weight()); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision, collision.weight()); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 12.0, collision.weight()); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 12.0, collision.weight()); // accepted + + int zbin = lower_bound(zvtx_bin_edges.begin(), zvtx_bin_edges.end(), collision.posZ()) - zvtx_bin_edges.begin() - 1; + if (zbin < 0) { + zbin = 0; + } else if (static_cast(zvtx_bin_edges.size()) - 2 < zbin) { + zbin = static_cast(zvtx_bin_edges.size()) - 2; + } + + float centrality = centralities[cfgCentEstimator]; + int centbin = lower_bound(cent_bin_edges.begin(), cent_bin_edges.end(), centrality) - cent_bin_edges.begin() - 1; + if (centbin < 0) { + centbin = 0; + } else if (static_cast(cent_bin_edges.size()) - 2 < centbin) { + centbin = static_cast(cent_bin_edges.size()) - 2; + } + + float ep2 = collision.ep2btot(); + int epbin = lower_bound(ep_bin_edges.begin(), ep_bin_edges.end(), ep2) - ep_bin_edges.begin() - 1; + if (epbin < 0) { + epbin = 0; + } else if (static_cast(ep_bin_edges.size()) - 2 < epbin) { + epbin = static_cast(ep_bin_edges.size()) - 2; + } + + int occbin = -1; + if (cfgOccupancyEstimator == 0) { + occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.ft0cOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; + } else if (cfgOccupancyEstimator == 1) { + occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.trackOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; + } else { + occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.ft0cOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; + } + + if (occbin < 0) { + occbin = 0; + } else if (static_cast(occ_bin_edges.size()) - 2 < occbin) { + occbin = static_cast(occ_bin_edges.size()) - 2; + } + + // LOGF(info, "collision.globalIndex() = %d, collision.posZ() = %f, centrality = %f, ep2 = %f, collision.trackOccupancyInTimeRange() = %d, zbin = %d, centbin = %d, epbin = %d, occbin = %d", collision.globalIndex(), collision.posZ(), centrality, ep2, collision.trackOccupancyInTimeRange(), zbin, centbin, epbin, occbin); + + std::tuple key_bin = std::make_tuple(zbin, centbin, epbin, occbin); + std::pair key_df_collision = std::make_pair(ndf, collision.globalIndex()); + + if constexpr (pairtype == PairType::kPCMPCM || pairtype == PairType::kPHOSPHOS || pairtype == PairType::kEMCEMC) { // same kinds pairing + auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); + auto photons2_per_collision = photons2.sliceBy(perCollision2, collision.globalIndex()); + + for (const auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photons1_per_collision, photons2_per_collision))) { + if (!cut1.template IsSelected(g1) || !cut2.template IsSelected(g2)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + if (std::fabs(v12.Rapidity()) > maxY) { + continue; + } + + if (pairtype == PairType::kEMCEMC) { + float openingAngle = std::acos(v1.Vect().Dot(v2.Vect()) / (v1.P() * v2.P())); + if (openingAngle < emccuts.minOpenAngle) { + continue; + } + } + + fRegistry.fill(HIST("Pair/same/hs"), v12.M(), v12.Pt(), collision.weight()); + + if constexpr (pairtype == PairType::kEMCEMC) { + RotationBackground(v12, v1, v2, photons2_per_collision, g1.globalIndex(), g2.globalIndex(), collision.weight()); + } + + std::pair pair_tmp_id1 = std::make_pair(ndf, g1.globalIndex()); + std::pair pair_tmp_id2 = std::make_pair(ndf, g2.globalIndex()); + + if (std::find(used_photonIds.begin(), used_photonIds.end(), pair_tmp_id1) == used_photonIds.end()) { + emh1->AddTrackToEventPool(key_df_collision, EMTrack(-1, g1.globalIndex(), collision.globalIndex(), g1.globalIndex(), g1.pt(), g1.eta(), g1.phi(), 0)); + used_photonIds.emplace_back(pair_tmp_id1); + } + if (std::find(used_photonIds.begin(), used_photonIds.end(), pair_tmp_id2) == used_photonIds.end()) { + emh1->AddTrackToEventPool(key_df_collision, EMTrack(-1, g2.globalIndex(), collision.globalIndex(), g2.globalIndex(), g2.pt(), g2.eta(), g2.phi(), 0)); + used_photonIds.emplace_back(pair_tmp_id2); + } + ndiphoton++; + } // end of pairing loop + } else if constexpr (pairtype == PairType::kPCMDalitzEE) { + auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); + auto positrons_per_collision = positrons->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + auto electrons_per_collision = electrons->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + + for (const auto& g1 : photons1_per_collision) { + if (!cut1.template IsSelected(g1)) { + continue; + } + auto pos1 = g1.template posTrack_as(); + auto ele1 = g1.template negTrack_as(); + ROOT::Math::PtEtaPhiMVector v_gamma(g1.pt(), g1.eta(), g1.phi(), 0.); + + for (const auto& [pos2, ele2] : combinations(CombinationsFullIndexPolicy(positrons_per_collision, electrons_per_collision))) { + + if (pos2.trackId() == ele2.trackId()) { // this is protection against pairing identical 2 tracks. + continue; + } + if (pos1.trackId() == pos2.trackId() || ele1.trackId() == ele2.trackId()) { + continue; + } + + if (!cut2.template IsSelectedTrack(pos2, collision) || !cut2.template IsSelectedTrack(ele2, collision)) { + continue; + } + + if (!cut2.IsSelectedPair(pos2, ele2, d_bz)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v_pos(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v_ele(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v_ee = v_pos + v_ele; + ROOT::Math::PtEtaPhiMVector veeg = v_gamma + v_pos + v_ele; + if (std::fabs(veeg.Rapidity()) > maxY) { + continue; + } + + fRegistry.fill(HIST("Pair/same/hs"), veeg.M(), veeg.Pt(), collision.weight()); + + std::pair pair_tmp_id1 = std::make_pair(ndf, g1.globalIndex()); + std::tuple tuple_tmp_id2 = std::make_tuple(ndf, collision.globalIndex(), pos2.trackId(), ele2.trackId()); + if (std::find(used_photonIds.begin(), used_photonIds.end(), pair_tmp_id1) == used_photonIds.end()) { + emh1->AddTrackToEventPool(key_df_collision, EMTrack(-1, g1.globalIndex(), collision.globalIndex(), -1, g1.pt(), g1.eta(), g1.phi(), 0)); + used_photonIds.emplace_back(pair_tmp_id1); + } + if (std::find(used_dileptonIds.begin(), used_dileptonIds.end(), tuple_tmp_id2) == used_dileptonIds.end()) { + emh2->AddTrackToEventPool(key_df_collision, EMTrack(-1, -1, collision.globalIndex(), -1, v_ee.Pt(), v_ee.Eta(), v_ee.Phi(), v_ee.M())); + used_dileptonIds.emplace_back(tuple_tmp_id2); + } + ndiphoton++; + } // end of dielectron loop + } // end of g1 loop + } else { // PCM-EMC, PCM-PHOS. Nightmare. don't run these pairs. + auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); + auto photons2_per_collision = photons2.sliceBy(perCollision2, collision.globalIndex()); + + for (const auto& [g1, g2] : combinations(CombinationsFullIndexPolicy(photons1_per_collision, photons2_per_collision))) { + if (!cut1.template IsSelected(g1) || !cut2.template IsSelected(g2)) { + continue; + } + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + if (std::fabs(v12.Rapidity()) > maxY) { + continue; + } + + fRegistry.fill(HIST("Pair/same/hs"), v12.M(), v12.Pt(), collision.weight()); + + std::pair pair_tmp_id1 = std::make_pair(ndf, g1.globalIndex()); + std::pair pair_tmp_id2 = std::make_pair(ndf, g2.globalIndex()); + + if (std::find(used_photonIds.begin(), used_photonIds.end(), pair_tmp_id1) == used_photonIds.end()) { + emh1->AddTrackToEventPool(key_df_collision, EMTrack(-1, g1.globalIndex(), collision.globalIndex(), -1, g1.pt(), g1.eta(), g1.phi(), 0)); + used_photonIds.emplace_back(pair_tmp_id1); + } + if (std::find(used_photonIds.begin(), used_photonIds.end(), pair_tmp_id2) == used_photonIds.end()) { + emh2->AddTrackToEventPool(key_df_collision, EMTrack(-1, g2.globalIndex(), collision.globalIndex(), -1, g2.pt(), g2.eta(), g2.phi(), 0)); + used_photonIds.emplace_back(pair_tmp_id2); + } + ndiphoton++; + } // end of pairing loop + } // end of pairing in same event + + // event mixing + if (!cfgDoMix || !(ndiphoton > 0)) { + continue; + } + + // make a vector of selected photons in this collision. + auto selected_photons1_in_this_event = emh1->GetTracksPerCollision(key_df_collision); + auto selected_photons2_in_this_event = emh2->GetTracksPerCollision(key_df_collision); + + auto collisionIds1_in_mixing_pool = emh1->GetCollisionIdsFromEventPool(key_bin); + auto collisionIds2_in_mixing_pool = emh2->GetCollisionIdsFromEventPool(key_bin); + + if constexpr (pairtype == PairType::kPCMPCM || pairtype == PairType::kPHOSPHOS || pairtype == PairType::kEMCEMC) { // same kinds pairing + for (const auto& mix_dfId_collisionId : collisionIds1_in_mixing_pool) { + int mix_dfId = mix_dfId_collisionId.first; + int64_t mix_collisionId = mix_dfId_collisionId.second; + + if (collision.globalIndex() == mix_collisionId && ndf == mix_dfId) { // this never happens. only protection. + continue; + } + + auto globalBC_mix = map_mixed_eventId_to_globalBC[mix_dfId_collisionId]; + uint64_t diffBC = std::max(collision.globalBC(), globalBC_mix) - std::min(collision.globalBC(), globalBC_mix); + fRegistry.fill(HIST("Pair/mix/hDiffBC"), diffBC); + if (diffBC < ndiff_bc_mix) { + continue; + } + + auto photons1_from_event_pool = emh1->GetTracksPerCollision(mix_dfId_collisionId); + // LOGF(info, "Do event mixing: current event (%d, %d), ngamma = %d | event pool (%d, %d), ngamma = %d", ndf, collision.globalIndex(), selected_photons1_in_this_event.size(), mix_dfId, mix_collisionId, photons1_from_event_pool.size()); + + for (const auto& g1 : selected_photons1_in_this_event) { + for (const auto& g2 : photons1_from_event_pool) { + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + if (std::fabs(v12.Rapidity()) > maxY) { + continue; + } + + fRegistry.fill(HIST("Pair/mix/hs"), v12.M(), v12.Pt(), collision.weight()); + } + } + } // end of loop over mixed event pool + + } else { // [photon1 from event1, photon2 from event2] and [photon1 from event2, photon2 from event1] + for (const auto& mix_dfId_collisionId : collisionIds2_in_mixing_pool) { + int mix_dfId = mix_dfId_collisionId.first; + int64_t mix_collisionId = mix_dfId_collisionId.second; + + if (collision.globalIndex() == mix_collisionId && ndf == mix_dfId) { // this never happens. only protection. + continue; + } + + auto globalBC_mix = map_mixed_eventId_to_globalBC[mix_dfId_collisionId]; + uint64_t diffBC = std::max(collision.globalBC(), globalBC_mix) - std::min(collision.globalBC(), globalBC_mix); + fRegistry.fill(HIST("Pair/mix/hDiffBC"), diffBC); + if (diffBC < ndiff_bc_mix) { + continue; + } + + auto photons2_from_event_pool = emh2->GetTracksPerCollision(mix_dfId_collisionId); + // LOGF(info, "Do event mixing: current event (%d, %d), ngamma = %d | event pool (%d, %d), nll = %d", ndf, collision.globalIndex(), selected_photons1_in_this_event.size(), mix_dfId, mix_collisionId, photons2_from_event_pool.size()); + + for (const auto& g1 : selected_photons1_in_this_event) { + for (const auto& g2 : photons2_from_event_pool) { + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); + if constexpr (pairtype == PairType::kPCMDalitzEE) { //[photon from event1, dilepton from event2] and [photon from event2, dilepton from event1] + v2.SetM(g2.mass()); + } + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + if (std::fabs(v12.Rapidity()) > maxY) { + continue; + } + fRegistry.fill(HIST("Pair/mix/hs"), v12.M(), v12.Pt(), collision.weight()); + } + } + } // end of loop over mixed event pool + for (const auto& mix_dfId_collisionId : collisionIds1_in_mixing_pool) { + int mix_dfId = mix_dfId_collisionId.first; + int64_t mix_collisionId = mix_dfId_collisionId.second; + + if (collision.globalIndex() == mix_collisionId && ndf == mix_dfId) { // this never happens. only protection. + continue; + } + + auto globalBC_mix = map_mixed_eventId_to_globalBC[mix_dfId_collisionId]; + uint64_t diffBC = std::max(collision.globalBC(), globalBC_mix) - std::min(collision.globalBC(), globalBC_mix); + fRegistry.fill(HIST("Pair/mix/hDiffBC"), diffBC); + if (diffBC < ndiff_bc_mix) { + continue; + } + + auto photons1_from_event_pool = emh1->GetTracksPerCollision(mix_dfId_collisionId); + // LOGF(info, "Do event mixing: current event (%d, %d), nll = %d | event pool (%d, %d), ngamma = %d", ndf, collision.globalIndex(), selected_photons2_in_this_event.size(), mix_dfId, mix_collisionId, photons1_from_event_pool.size()); + + for (const auto& g1 : selected_photons2_in_this_event) { + for (const auto& g2 : photons1_from_event_pool) { + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); + if constexpr (pairtype == PairType::kPCMDalitzEE) { //[photon from event1, dilepton from event2] and [photon from event2, dilepton from event1] + v1.SetM(g1.mass()); + } + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + if (std::fabs(v12.Rapidity()) > maxY) { + continue; + } + fRegistry.fill(HIST("Pair/mix/hs"), v12.M(), v12.Pt(), collision.weight()); + } + } + } // end of loop over mixed event pool + } + + if (ndiphoton > 0) { + emh1->AddCollisionIdAtLast(key_bin, key_df_collision); + emh2->AddCollisionIdAtLast(key_bin, key_df_collision); + map_mixed_eventId_to_globalBC[key_df_collision] = collision.globalBC(); + } + + } // end of collision loop + } + + Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + using FilteredMyCollisions = soa::Filtered; + + Filter prefilter_pcm = ifnode(pcmcuts.cfg_apply_cuts_from_prefilter_derived.node(), o2::aod::v0photonkf::pfbderived == static_cast(0), true); + Filter prefilter_primaryelectron = ifnode(dileptoncuts.cfg_apply_cuts_from_prefilter_derived.node(), o2::aod::emprimaryelectron::pfbderived == static_cast(0), true); + + int ndf = 0; + void processAnalysis(FilteredMyCollisions const& collisions, Types const&... args) + { + // LOGF(info, "ndf = %d", ndf); + if constexpr (pairtype == PairType::kPCMPCM) { + auto v0photons = std::get<0>(std::tie(args...)); + auto v0legs = std::get<1>(std::tie(args...)); + runPairing(collisions, v0photons, v0photons, v0legs, v0legs, perCollision_pcm, perCollision_pcm, fV0PhotonCut, fV0PhotonCut); + } else if constexpr (pairtype == PairType::kPCMDalitzEE) { + auto v0photons = std::get<0>(std::tie(args...)); + auto v0legs = std::get<1>(std::tie(args...)); + auto emprimaryelectrons = std::get<2>(std::tie(args...)); + // LOGF(info, "electrons.size() = %d, positrons.size() = %d", electrons.size(), positrons.size()); + runPairing(collisions, v0photons, emprimaryelectrons, v0legs, emprimaryelectrons, perCollision_pcm, perCollision_electron, fV0PhotonCut, fDileptonCut); + } else if constexpr (pairtype == PairType::kEMCEMC) { + auto emcclusters = std::get<0>(std::tie(args...)); + runPairing(collisions, emcclusters, emcclusters, nullptr, nullptr, perCollision_emc, perCollision_emc, fEMCCut, fEMCCut); + } else if constexpr (pairtype == PairType::kPHOSPHOS) { + auto phosclusters = std::get<0>(std::tie(args...)); + runPairing(collisions, phosclusters, phosclusters, nullptr, nullptr, perCollision_phos, perCollision_phos, fPHOSCut, fPHOSCut); + } + // else if constexpr (pairtype == PairType::kPCMEMC) { + // auto v0photons = std::get<0>(std::tie(args...)); + // auto v0legs = std::get<1>(std::tie(args...)); + // auto emcclusters = std::get<2>(std::tie(args...)); + // auto emcmatchedtracks = std::get<3>(std::tie(args...)); + // runPairing(collisions, v0photons, emcclusters, v0legs, nullptr, perCollision_pcm, perCollision_emc, fV0PhotonCut, fEMCCut, emcmatchedtracks, nullptr); + // } else if constexpr (pairtype == PairType::kPCMPHOS) { + // auto v0photons = std::get<0>(std::tie(args...)); + // auto v0legs = std::get<1>(std::tie(args...)); + // auto phosclusters = std::get<2>(std::tie(args...)); + // runPairing(collisions, v0photons, phosclusters, v0legs, nullptr, perCollision_pcm, perCollision_phos, fV0PhotonCut, fPHOSCut, nullptr, nullptr); + // } + ndf++; + } + PROCESS_SWITCH(Pi0EtaToGammaGamma, processAnalysis, "process pair analysis", false); + + void processDummy(MyCollisions const&) {} + PROCESS_SWITCH(Pi0EtaToGammaGamma, processDummy, "Dummy function", true); +}; +#endif // PWGEM_PHOTONMESON_CORE_PI0ETATOGAMMAGAMMA_H_ diff --git a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h new file mode 100644 index 00000000000..87e2f7b04d4 --- /dev/null +++ b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h @@ -0,0 +1,738 @@ +// 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. +// +// ======================== +// +// This code loops over photons and makes pairs for neutral mesons analyses. +// Please write to: daiki.sekihata@cern.ch + +#ifndef PWGEM_PHOTONMESON_CORE_PI0ETATOGAMMAGAMMAMC_H_ +#define PWGEM_PHOTONMESON_CORE_PI0ETATOGAMMAGAMMAMC_H_ + +#include +#include +#include + +#include "TF1.h" +#include "TString.h" +#include "Math/Vector4D.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + +#include "Common/Core/RecoDecay.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" +#include "PWGEM/PhotonMeson/Utils/NMHistograms.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" +#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::photonmeson::photonpair; +using namespace o2::aod::pwgem::photonmeson::utils::mcutil; +using namespace o2::aod::pwgem::dilepton::utils::mcutil; + +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; + +using MyMCCollisions = soa::Join; +using MyMCCollision = MyMCCollisions::iterator; + +using MyV0Photons = soa::Filtered>; +using MyV0Photon = MyV0Photons::iterator; + +using MyEMCClusters = soa::Join; +using MyEMCCluster = MyEMCClusters::iterator; + +using MyPHOSClusters = soa::Join; +using MyPHOSCluster = MyEMCClusters::iterator; + +using MyMCV0Legs = soa::Join; +using MyMCV0Leg = MyMCV0Legs::iterator; + +using MyMCElectrons = soa::Filtered>; +using MyMCElectron = MyMCElectrons::iterator; + +template +struct Pi0EtaToGammaGammaMC { + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + + Configurable cfgQvecEstimator{"cfgQvecEstimator", 0, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999, "max. centrality"}; + Configurable maxY_rec{"maxY_rec", 0.9, "maximum rapidity for reconstructed particles"}; + Configurable fd_k0s_to_pi0{"fd_k0s_pi0", "1.0", "feed down correction to pi0"}; + Configurable cfgRequireTrueAssociation{"cfgRequireTrueAssociation", false, "flag to require true mc collision association"}; + + EMPhotonEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgRequireEMCReadoutInMB{"cfgRequireEMCReadoutInMB", false, "require the EMC to be read out in an MB collision (kTVXinEMC)"}; + Configurable cfgRequireEMCHardwareTriggered{"cfgRequireEMCHardwareTriggered", false, "require the EMC to be hardware triggered (kEMC7 or kDMC7)"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable onlyKeepWeightedEvents{"onlyKeepWeightedEvents", false, "flag to keep only weighted events (for JJ MCs) and remove all MB events (with weight = 1)"}; + } eventcuts; + + V0PhotonCut fV0PhotonCut; + struct : ConfigurableGroup { + std::string prefix = "pcmcut_group"; + Configurable cfg_require_v0_with_itstpc{"cfg_require_v0_with_itstpc", false, "flag to select V0s with ITS-TPC matched tracks"}; + Configurable cfg_require_v0_with_itsonly{"cfg_require_v0_with_itsonly", false, "flag to select V0s with ITSonly tracks"}; + Configurable cfg_require_v0_with_tpconly{"cfg_require_v0_with_tpconly", false, "flag to select V0s with TPConly tracks"}; + Configurable cfg_min_pt_v0{"cfg_min_pt_v0", 0.1, "min pT for v0 photons at PV"}; + Configurable cfg_max_pt_v0{"cfg_max_pt_v0", 1e+10, "max pT for v0 photons at PV"}; + Configurable cfg_min_eta_v0{"cfg_min_eta_v0", -0.8, "min eta for v0 photons at PV"}; + Configurable cfg_max_eta_v0{"cfg_max_eta_v0", 0.8, "max eta for v0 photons at PV"}; + Configurable cfg_min_v0radius{"cfg_min_v0radius", 4.0, "min v0 radius"}; + Configurable cfg_max_v0radius{"cfg_max_v0radius", 90.0, "max v0 radius"}; + Configurable cfg_max_alpha_ap{"cfg_max_alpha_ap", 0.95, "max alpha for AP cut"}; + Configurable cfg_max_qt_ap{"cfg_max_qt_ap", 0.01, "max qT for AP cut"}; + Configurable cfg_min_cospa{"cfg_min_cospa", 0.997, "min V0 CosPA"}; + Configurable cfg_max_pca{"cfg_max_pca", 3.0, "max distance btween 2 legs"}; + Configurable cfg_max_chi2kf{"cfg_max_chi2kf", 1e+10, "max chi2/ndf with KF"}; + Configurable cfg_require_v0_with_correct_xz{"cfg_require_v0_with_correct_xz", true, "flag to select V0s with correct xz"}; + Configurable cfg_reject_v0_on_itsib{"cfg_reject_v0_on_itsib", true, "flag to reject V0s on ITSib"}; + Configurable cfg_apply_cuts_from_prefilter_derived{"cfg_apply_cuts_from_prefilter_derived", false, "flag to apply prefilter to V0"}; + + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 10, "min ncluster tpc"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 40, "min ncrossed rows"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -3.0, "min. TPC n sigma for electron"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; + Configurable cfg_disable_itsonly_track{"cfg_disable_itsonly_track", false, "flag to disable ITSonly tracks"}; + Configurable cfg_disable_tpconly_track{"cfg_disable_tpconly_track", false, "flag to disable TPConly tracks"}; + } pcmcuts; + + DalitzEECut fDileptonCut; + struct : ConfigurableGroup { + std::string prefix = "dileptoncut_group"; + Configurable cfg_min_mass{"cfg_min_mass", 0.0, "min mass"}; + Configurable cfg_max_mass{"cfg_max_mass", 0.1, "max mass"}; + Configurable cfg_apply_phiv{"cfg_apply_phiv", true, "flag to apply phiv cut"}; + Configurable cfg_require_itsib_any{"cfg_require_itsib_any", false, "flag to require ITS ib any hits"}; + Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; + Configurable cfg_phiv_slope{"cfg_phiv_slope", 0.0185, "slope for m vs. phiv"}; + Configurable cfg_phiv_intercept{"cfg_phiv_intercept", -0.0280, "intercept for m vs. phiv"}; + + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.1, "min pT for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", 0.8, "max eta for single track"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 70, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 0.05, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 0.05, "max dca Z for single track in cm"}; + Configurable cfg_max_dca3dsigma_track{"cfg_max_dca3dsigma_track", 1.5, "max DCA 3D in sigma"}; + Configurable cfg_apply_cuts_from_prefilter_derived{"cfg_apply_cuts_from_prefilter_derived", false, "flag to apply prefilter to electron"}; + + Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DalitzEECut::PIDSchemes::kTOFif), "pid scheme [kTOFif : 0, kTPConly : 1]"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -0.0, "min. TPC n sigma for pion exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +0.0, "max. TPC n sigma for pion exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; + } dileptoncuts; + + EMCPhotonCut fEMCCut; + struct : ConfigurableGroup { + std::string prefix = "emccut_group"; + Configurable clusterDefinition{"clusterDefinition", "kV3Default", "Clusterizer to be selected, e.g. V3Default"}; + Configurable minOpenAngle{"minOpenAngle", 0.0202, "apply min opening angle"}; + Configurable EMC_minTime{"EMC_minTime", -20., "Minimum cluster time for EMCal time cut"}; + Configurable EMC_maxTime{"EMC_maxTime", +25., "Maximum cluster time for EMCal time cut"}; + Configurable EMC_minM02{"EMC_minM02", 0.1, "Minimum M02 for EMCal M02 cut"}; + Configurable EMC_maxM02{"EMC_maxM02", 0.7, "Maximum M02 for EMCal M02 cut"}; + Configurable EMC_minE{"EMC_minE", 0.7, "Minimum cluster energy for EMCal energy cut"}; + Configurable EMC_minNCell{"EMC_minNCell", 1, "Minimum number of cells per cluster for EMCal NCell cut"}; + Configurable> EMC_TM_Eta{"EMC_TM_Eta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable> EMC_TM_Phi{"EMC_TM_Phi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable EMC_Eoverp{"EMC_Eoverp", 1.75, "Minimum cluster energy over track momentum for EMCal track matching"}; + Configurable EMC_UseExoticCut{"EMC_UseExoticCut", true, "FLag to use the EMCal exotic cluster cut"}; + } emccuts; + + Configurable maxY_gen{"maxY_gen", 0.9, "maximum rapidity for generated particles"}; // for PCM and dielectron + Configurable maxRgen{"maxRgen", 90.f, "maximum radius for generated particles"}; + Configurable margin_z_mc{"margin_z_mc", 7.0, "margin for z cut in cm for MC"}; + + PHOSPhotonCut fPHOSCut; + struct : ConfigurableGroup { + std::string prefix = "phoscut_group"; + Configurable cfg_min_Ecluster{"cfg_min_Ecluster", 0.3, "Minimum cluster energy for PHOS in GeV"}; + } phoscuts; + + TF1* f1fd_k0s_to_pi0; + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view event_types[2] = {"before/", "after/"}; + static constexpr std::string_view event_pair_types[2] = {"same/", "mix/"}; + static constexpr std::string_view parnames[2] = {"Pi0/", "Eta/"}; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + int mRunNumber; + float d_bz; + + void init(InitContext&) + { + o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(&fRegistry); + if constexpr (pairtype == PairType::kPCMDalitzEE) { + o2::aod::pwgem::photonmeson::utils::nmhistogram::addNMHistograms(&fRegistry, true, "ee#gamma"); + } else { + o2::aod::pwgem::photonmeson::utils::nmhistogram::addNMHistograms(&fRegistry, true, "#gamma#gamma"); + } + DefineEMEventCut(); + DefinePCMCut(); + DefineDileptonCut(); + DefineEMCCut(); + DefinePHOSCut(); + + f1fd_k0s_to_pi0 = new TF1("f1fd_k0s_to_pi0", TString(fd_k0s_to_pi0), 0.f, 100.f); + + fRegistry.add("Event/hNrecPerMCCollision", "Nrec per mc collision;N_{rec} collisions per MC collision", kTH1F, {{21, -0.5f, 20.5f}}, false); + + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + } + + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (std::fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + mRunNumber = collision.runNumber(); + return; + } + + auto run3grp_timestamp = collision.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = collision.runNumber(); + } + + ~Pi0EtaToGammaGammaMC() + { + delete f1fd_k0s_to_pi0; + f1fd_k0s_to_pi0 = 0x0; + } + + void DefineEMEventCut() + { + fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireEMCReadoutInMB(eventcuts.cfgRequireEMCReadoutInMB); + fEMEventCut.SetRequireEMCHardwareTriggered(eventcuts.cfgRequireEMCHardwareTriggered); + } + + void DefinePCMCut() + { + fV0PhotonCut = V0PhotonCut("fV0PhotonCut", "fV0PhotonCut"); + + // for v0 + fV0PhotonCut.SetV0PtRange(pcmcuts.cfg_min_pt_v0, pcmcuts.cfg_max_pt_v0); + fV0PhotonCut.SetV0EtaRange(pcmcuts.cfg_min_eta_v0, pcmcuts.cfg_max_eta_v0); + fV0PhotonCut.SetMinCosPA(pcmcuts.cfg_min_cospa); + fV0PhotonCut.SetMaxPCA(pcmcuts.cfg_max_pca); + fV0PhotonCut.SetMaxChi2KF(pcmcuts.cfg_max_chi2kf); + fV0PhotonCut.SetRxyRange(pcmcuts.cfg_min_v0radius, pcmcuts.cfg_max_v0radius); + fV0PhotonCut.SetAPRange(pcmcuts.cfg_max_alpha_ap, pcmcuts.cfg_max_qt_ap); + fV0PhotonCut.RejectITSib(pcmcuts.cfg_reject_v0_on_itsib); + + // for track + fV0PhotonCut.SetMinNClustersTPC(pcmcuts.cfg_min_ncluster_tpc); + fV0PhotonCut.SetMinNCrossedRowsTPC(pcmcuts.cfg_min_ncrossedrows); + fV0PhotonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fV0PhotonCut.SetMaxFracSharedClustersTPC(pcmcuts.cfg_max_frac_shared_clusters_tpc); + fV0PhotonCut.SetChi2PerClusterTPC(0.0, pcmcuts.cfg_max_chi2tpc); + fV0PhotonCut.SetTPCNsigmaElRange(pcmcuts.cfg_min_TPCNsigmaEl, pcmcuts.cfg_max_TPCNsigmaEl); + fV0PhotonCut.SetChi2PerClusterITS(-1e+10, pcmcuts.cfg_max_chi2its); + fV0PhotonCut.SetNClustersITS(0, 7); + fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); + fV0PhotonCut.SetIsWithinBeamPipe(pcmcuts.cfg_require_v0_with_correct_xz); + fV0PhotonCut.SetDisableITSonly(pcmcuts.cfg_disable_itsonly_track); + fV0PhotonCut.SetDisableTPConly(pcmcuts.cfg_disable_tpconly_track); + fV0PhotonCut.SetRequireITSTPC(pcmcuts.cfg_require_v0_with_itstpc); + fV0PhotonCut.SetRequireITSonly(pcmcuts.cfg_require_v0_with_itsonly); + fV0PhotonCut.SetRequireTPConly(pcmcuts.cfg_require_v0_with_tpconly); + } + + void DefineDileptonCut() + { + fDileptonCut = DalitzEECut("fDileptonCut", "fDileptonCut"); + + // for pair + fDileptonCut.SetMeeRange(dileptoncuts.cfg_min_mass, dileptoncuts.cfg_max_mass); + fDileptonCut.SetMaxPhivPairMeeDep([&](float mll) { return (mll - dileptoncuts.cfg_phiv_intercept) / dileptoncuts.cfg_phiv_slope; }); + fDileptonCut.ApplyPhiV(dileptoncuts.cfg_apply_phiv); + fDileptonCut.RequireITSibAny(dileptoncuts.cfg_require_itsib_any); + fDileptonCut.RequireITSib1st(dileptoncuts.cfg_require_itsib_1st); + + // for track + fDileptonCut.SetTrackPtRange(dileptoncuts.cfg_min_pt_track, 1e+10f); + fDileptonCut.SetTrackEtaRange(-dileptoncuts.cfg_max_eta_track, +dileptoncuts.cfg_max_eta_track); + fDileptonCut.SetMinNClustersTPC(dileptoncuts.cfg_min_ncluster_tpc); + fDileptonCut.SetMinNCrossedRowsTPC(dileptoncuts.cfg_min_ncrossedrows); + fDileptonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fDileptonCut.SetMaxFracSharedClustersTPC(dileptoncuts.cfg_max_frac_shared_clusters_tpc); + fDileptonCut.SetChi2PerClusterTPC(0.0, dileptoncuts.cfg_max_chi2tpc); + fDileptonCut.SetChi2PerClusterITS(0.0, dileptoncuts.cfg_max_chi2its); + fDileptonCut.SetNClustersITS(dileptoncuts.cfg_min_ncluster_its, 7); + fDileptonCut.SetMaxDcaXY(dileptoncuts.cfg_max_dcaxy); + fDileptonCut.SetMaxDcaZ(dileptoncuts.cfg_max_dcaz); + fDileptonCut.SetTrackDca3DRange(0.f, dileptoncuts.cfg_max_dca3dsigma_track); // in sigma + + // for eID + fDileptonCut.SetPIDScheme(dileptoncuts.cfg_pid_scheme); + fDileptonCut.SetTPCNsigmaElRange(dileptoncuts.cfg_min_TPCNsigmaEl, dileptoncuts.cfg_max_TPCNsigmaEl); + fDileptonCut.SetTPCNsigmaPiRange(dileptoncuts.cfg_min_TPCNsigmaPi, dileptoncuts.cfg_max_TPCNsigmaPi); + fDileptonCut.SetTOFNsigmaElRange(dileptoncuts.cfg_min_TOFNsigmaEl, dileptoncuts.cfg_max_TOFNsigmaEl); + } + + void DefineEMCCut() + { + const float a = emccuts.EMC_TM_Eta->at(0); + const float b = emccuts.EMC_TM_Eta->at(1); + const float c = emccuts.EMC_TM_Eta->at(2); + + const float d = emccuts.EMC_TM_Phi->at(0); + const float e = emccuts.EMC_TM_Phi->at(1); + const float f = emccuts.EMC_TM_Phi->at(2); + LOGF(info, "EMCal track matching parameters : a = %f, b = %f, c = %f, d = %f, e = %f, f = %f", a, b, c, d, e, f); + + fEMCCut = EMCPhotonCut("fEMCCut", "fEMCCut"); + + fEMCCut.SetClusterizer(emccuts.clusterDefinition); + fEMCCut.SetMinE(emccuts.EMC_minE); + fEMCCut.SetMinNCell(emccuts.EMC_minNCell); + fEMCCut.SetM02Range(emccuts.EMC_minM02, emccuts.EMC_maxM02); + fEMCCut.SetTimeRange(emccuts.EMC_minTime, emccuts.EMC_maxTime); + + fEMCCut.SetTrackMatchingEta([a, b, c](float pT) { return a + std::pow(pT + b, c); }); + fEMCCut.SetTrackMatchingPhi([d, e, f](float pT) { return d + std::pow(pT + e, f); }); + + fEMCCut.SetMinEoverP(emccuts.EMC_Eoverp); + fEMCCut.SetUseExoticCut(emccuts.EMC_UseExoticCut); + } + + void DefinePHOSCut() + { + fPHOSCut.SetEnergyRange(phoscuts.cfg_min_Ecluster, 1e+10); + } + + SliceCache cache; + Preslice perCollision_pcm = aod::v0photonkf::emeventId; + Preslice perCollision_emc = aod::emccluster::emeventId; + Preslice perCollision_phos = aod::phoscluster::emeventId; + + Preslice perCollision_electron = aod::emprimaryelectron::emeventId; + Partition positrons = o2::aod::emprimaryelectron::sign > int8_t(0) && static_cast(dileptoncuts.cfg_min_pt_track) < o2::aod::track::pt&& nabs(o2::aod::track::eta) < static_cast(dileptoncuts.cfg_max_eta_track) && static_cast(dileptoncuts.cfg_min_TPCNsigmaEl) < o2::aod::pidtpc::tpcNSigmaEl&& o2::aod::pidtpc::tpcNSigmaEl < static_cast(dileptoncuts.cfg_max_TPCNsigmaEl); + Partition electrons = o2::aod::emprimaryelectron::sign < int8_t(0) && static_cast(dileptoncuts.cfg_min_pt_track) < o2::aod::track::pt && nabs(o2::aod::track::eta) < static_cast(dileptoncuts.cfg_max_eta_track) && static_cast(dileptoncuts.cfg_min_TPCNsigmaEl) < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < static_cast(dileptoncuts.cfg_max_TPCNsigmaEl); + + template + void runTruePairing(TCollisions const& collisions, + TPhotons1 const& photons1, TPhotons2 const& photons2, + TSubInfos1 const& /*subinfos1*/, TSubInfos2 const& /*subinfos2*/, + TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, + TCut1 const& cut1, TCut2 const& cut2, + TMCCollisions const& mccollisions, TMCParticles const& mcparticles) + { + for (auto& collision : collisions) { + initCCDB(collision); + + if ((pairtype == PairType::kPHOSPHOS || pairtype == PairType::kPCMPHOS) && !collision.alias_bit(triggerAliases::kTVXinPHOS)) { + continue; + } + + if (eventcuts.onlyKeepWeightedEvents && std::fabs(collision.weight() - 1.) < 1E-10) { + continue; + } + + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision, collision.weight()); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision, collision.weight()); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 12.0, collision.weight()); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 12.0, collision.weight()); // accepted + + int photonid1 = -1, photonid2 = -1, pi0id = -1, etaid = -1; + if constexpr (pairtype == PairType::kPCMPCM || pairtype == PairType::kPHOSPHOS || pairtype == PairType::kEMCEMC) { // same kinds pairing + auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); + auto photons2_per_collision = photons2.sliceBy(perCollision2, collision.globalIndex()); + + for (auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photons1_per_collision, photons2_per_collision))) { + if (!cut1.template IsSelected(g1) || !cut2.template IsSelected(g2)) { + continue; + } + + if constexpr (pairtype == PairType::kPCMPCM) { // check 2 legs + auto pos1 = g1.template posTrack_as(); + auto ele1 = g1.template negTrack_as(); + auto pos2 = g2.template posTrack_as(); + auto ele2 = g2.template negTrack_as(); + + auto pos1mc = pos1.template emmcparticle_as(); + auto ele1mc = ele1.template emmcparticle_as(); + auto pos2mc = pos2.template emmcparticle_as(); + auto ele2mc = ele2.template emmcparticle_as(); + + photonid1 = FindCommonMotherFrom2Prongs(pos1mc, ele1mc, -11, 11, 22, mcparticles); + photonid2 = FindCommonMotherFrom2Prongs(pos2mc, ele2mc, -11, 11, 22, mcparticles); + } else if constexpr (pairtype == PairType::kEMCEMC) { + auto cluster1mcparticle = mcparticles.iteratorAt(g1.emmcparticleId()); + auto cluster2mcparticle = mcparticles.iteratorAt(g2.emmcparticleId()); + + photonid1 = FindMotherInChain(cluster1mcparticle, mcparticles, std::vector{111, 221}); + photonid2 = FindMotherInChain(cluster2mcparticle, mcparticles, std::vector{111, 221}); + } else { + photonid1 = -1; + photonid2 = -1; + } + + if (photonid1 < 0 || photonid2 < 0) { + continue; + } + auto g1mc = mcparticles.iteratorAt(photonid1); + auto g2mc = mcparticles.iteratorAt(photonid2); + + if constexpr (pairtype == PairType::kPCMPCM) { + if (!IsConversionPointInAcceptance(g1mc, maxRgen, maxY_gen, margin_z_mc, mcparticles) || !IsConversionPointInAcceptance(g2mc, maxRgen, maxY_gen, margin_z_mc, mcparticles)) { + continue; + } + } + + pi0id = FindCommonMotherFrom2Prongs(g1mc, g2mc, 22, 22, 111, mcparticles); + etaid = FindCommonMotherFrom2Prongs(g1mc, g2mc, 22, 22, 221, mcparticles); + + if (g1mc.globalIndex() != g2mc.globalIndex() && pi0id < 0 && etaid < 0) { // for same gamma no pi0/eta will be found, but we still want to fill the FromSameGamma hist + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + if (std::fabs(v12.Rapidity()) > maxY_rec) { + continue; + } + + if (pairtype == PairType::kEMCEMC) { + float openingAngle = std::acos(v1.Vect().Dot(v2.Vect()) / (v1.P() * v2.P())); + if (openingAngle < emccuts.minOpenAngle) { + continue; + } + } + + if (g1mc.globalIndex() == g2mc.globalIndex()) { + if (getMotherPDGCode(g1mc, mcparticles) == 111) + fRegistry.fill(HIST("Pair/Pi0/hs_FromSameGamma"), v12.M(), v12.Pt(), collision.weight()); + else if (getMotherPDGCode(g1mc, mcparticles) == 221) + fRegistry.fill(HIST("Pair/Eta/hs_FromSameGamma"), v12.M(), v12.Pt(), collision.weight()); + continue; + } + + if (pi0id > 0) { + auto pi0mc = mcparticles.iteratorAt(pi0id); + if (cfgRequireTrueAssociation && (pi0mc.emmceventId() != collision.emmceventId())) { + continue; + } + o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, v12, pi0mc, mcparticles, mccollisions, f1fd_k0s_to_pi0, collision.weight()); + } else if (etaid > 0) { + auto etamc = mcparticles.iteratorAt(etaid); + if (cfgRequireTrueAssociation && (etamc.emmceventId() != collision.emmceventId())) { + continue; + } + o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, v12, etamc, mcparticles, mccollisions, f1fd_k0s_to_pi0, collision.weight()); + } + } // end of pairing loop + } else if constexpr (pairtype == PairType::kPCMDalitzEE) { + auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); + auto positrons_per_collision = positrons->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + auto electrons_per_collision = electrons->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + + for (auto& g1 : photons1_per_collision) { + if (!cut1.template IsSelected(g1)) { + continue; + } + auto pos1 = g1.template posTrack_as(); + auto ele1 = g1.template negTrack_as(); + auto pos1mc = pos1.template emmcparticle_as(); + auto ele1mc = ele1.template emmcparticle_as(); + photonid1 = FindCommonMotherFrom2Prongs(pos1mc, ele1mc, -11, 11, 22, mcparticles); + if (photonid1 < 0) { + continue; + } + auto g1mc = mcparticles.iteratorAt(photonid1); + if (!IsConversionPointInAcceptance(g1mc, maxRgen, maxY_gen, margin_z_mc, mcparticles)) { + continue; + } + ROOT::Math::PtEtaPhiMVector v_gamma(g1.pt(), g1.eta(), g1.phi(), 0.f); + + for (auto& [pos2, ele2] : combinations(CombinationsFullIndexPolicy(positrons_per_collision, electrons_per_collision))) { // ULS + if (pos2.trackId() == ele2.trackId()) { // this is protection against pairing identical 2 tracks. + continue; + } + if (pos1.trackId() == pos2.trackId() || ele1.trackId() == ele2.trackId()) { + continue; + } + + if (!cut2.template IsSelectedTrack(pos2, collision) || !cut2.template IsSelectedTrack(ele2, collision)) { + continue; + } + + if (!cut2.IsSelectedPair(pos2, ele2, d_bz)) { + continue; + } + + auto pos2mc = mcparticles.iteratorAt(pos2.emmcparticleId()); + auto ele2mc = mcparticles.iteratorAt(ele2.emmcparticleId()); + pi0id = FindCommonMotherFrom3Prongs(g1mc, pos2mc, ele2mc, 22, -11, 11, 111, mcparticles); + etaid = FindCommonMotherFrom3Prongs(g1mc, pos2mc, ele2mc, 22, -11, 11, 221, mcparticles); + if (pi0id < 0 && etaid < 0) { + continue; + } + ROOT::Math::PtEtaPhiMVector v_pos(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v_ele(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector veeg = v_gamma + v_pos + v_ele; + if (std::fabs(veeg.Rapidity()) > maxY_rec) { + continue; + } + if (pi0id > 0) { + auto pi0mc = mcparticles.iteratorAt(pi0id); + if (cfgRequireTrueAssociation && (pi0mc.emmceventId() != collision.emmceventId())) { + continue; + } + o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, veeg, pi0mc, mcparticles, mccollisions, f1fd_k0s_to_pi0, collision.weight()); + } else if (etaid > 0) { + auto etamc = mcparticles.iteratorAt(etaid); + if (cfgRequireTrueAssociation && (etamc.emmceventId() != collision.emmceventId())) { + continue; + } + o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, veeg, etamc, mcparticles, mccollisions, f1fd_k0s_to_pi0, collision.weight()); + } + } // end of dielectron loop + } // end of pcm loop + } else { // PCM-EMC, PCM-PHOS. Nightmare. don't run these pairs. + auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); + auto photons2_per_collision = photons2.sliceBy(perCollision2, collision.globalIndex()); + + for (auto& [g1, g2] : combinations(CombinationsFullIndexPolicy(photons1_per_collision, photons2_per_collision))) { + if (!cut1.template IsSelected(g1) || !cut2.template IsSelected(g2)) { + continue; + } + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + if (std::fabs(v12.Rapidity()) > maxY_rec) { + continue; + } + // if (pi0id > 0) { + // auto pi0mc = mcparticles.iteratorAt(pi0id); + // o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, v12, pi0mc, mcparticles, mccollisions, f1fd_k0s_to_pi0, collision.weight()); + // } else if (etaid > 0) { + // auto etamc = mcparticles.iteratorAt(etaid); + // o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, v12, etamc, mcparticles, mccollisions, f1fd_k0s_to_pi0, collision.weight()); + // } + } // end of pairing loop + } // end of pairing in same event + } // end of collision loop + } + + template + void fillBinnedData(TBinnedData const& binned_data, const float weight = 1.f) + { + int xbin = 0, ybin = 0, zbin = 0; + auto hPtY = fRegistry.get(HIST("Generated/") + HIST(parnames[par_id]) + HIST("hPtY")); // 2D + auto hPt = fRegistry.get(HIST("Generated/") + HIST(parnames[par_id]) + HIST("hPt")); // 1D + + for (int ibin = 0; ibin < hPtY->GetNcells(); ibin++) { + int nentry = binned_data[ibin]; + hPtY->GetBinXYZ(ibin, xbin, ybin, zbin); + float pt = hPtY->GetXaxis()->GetBinCenter(xbin); + float y = hPtY->GetYaxis()->GetBinCenter(ybin); + if (y > maxY_gen) { + continue; + } + + for (int j = 0; j < nentry; j++) { + hPtY->Fill(pt, y, weight); + hPt->Fill(pt, weight); + } + } + } + + PresliceUnsorted perMcCollision = aod::emmcparticle::emmceventId; + PresliceUnsorted rec_perMcCollision = aod::emmceventlabel::emmceventId; + + template + void runGenInfo(TCollisions const& collisions, TMCCollisions const& mccollisions, TMCParticles const& /*mcparticles*/) + { + // loop over mc stack and fill histograms for pure MC truth signals + // all MC tracks which belong to the MC event corresponding to the current reconstructed event + + for (auto& mccollision : mccollisions) { + auto collision_per_mccoll = collisions.sliceBy(rec_perMcCollision, mccollision.globalIndex()); + int nrec_per_mc = collision_per_mccoll.size(); + fRegistry.fill(HIST("Event/hNrecPerMCCollision"), nrec_per_mc); + } + + for (auto& collision : collisions) { + if ((pairtype == kPHOSPHOS || pairtype == kPCMPHOS) && !collision.alias_bit(triggerAliases::kTVXinPHOS)) { + continue; // I don't know why this is necessary in simulation. + } + + if (eventcuts.onlyKeepWeightedEvents && std::fabs(collision.weight() - 1.) < 1E-10) { + continue; + } + + float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + + auto mccollision = collision.template emmcevent_as(); + auto binned_data_pi0_gen = mccollision.generatedPi0(); + auto binned_data_eta_gen = mccollision.generatedEta(); + fillBinnedData<0>(binned_data_pi0_gen, collision.weight()); + fillBinnedData<1>(binned_data_eta_gen, collision.weight()); + } // end of collision loop + } + + Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + using FilteredMyCollisions = soa::Filtered; + + Filter prefilter_pcm = ifnode(pcmcuts.cfg_apply_cuts_from_prefilter_derived.node(), o2::aod::v0photonkf::pfbderived == static_cast(0), true); + Filter prefilter_primaryelectron = ifnode(dileptoncuts.cfg_apply_cuts_from_prefilter_derived.node(), o2::aod::emprimaryelectron::pfbderived == static_cast(0), true); + + void processAnalysis(FilteredMyCollisions const& collisions, MyMCCollisions const& mccollisions, aod::EMMCParticles const& mcparticles, Types const&... args) + { + if constexpr (pairtype == PairType::kPCMPCM) { + auto v0photons = std::get<0>(std::tie(args...)); + auto v0legs = std::get<1>(std::tie(args...)); + runTruePairing(collisions, v0photons, v0photons, v0legs, v0legs, perCollision_pcm, perCollision_pcm, fV0PhotonCut, fV0PhotonCut, mccollisions, mcparticles); + runGenInfo(collisions, mccollisions, mcparticles); + } else if constexpr (pairtype == PairType::kPCMDalitzEE) { + auto v0photons = std::get<0>(std::tie(args...)); + auto v0legs = std::get<1>(std::tie(args...)); + auto emprimaryelectrons = std::get<2>(std::tie(args...)); + // LOGF(info, "electrons.size() = %d, positrons.size() = %d", electrons.size(), positrons.size()); + runTruePairing(collisions, v0photons, emprimaryelectrons, v0legs, emprimaryelectrons, perCollision_pcm, perCollision_electron, fV0PhotonCut, fDileptonCut, mccollisions, mcparticles); + runGenInfo(collisions, mccollisions, mcparticles); + } else if constexpr (pairtype == PairType::kEMCEMC) { + auto emcclusters = std::get<0>(std::tie(args...)); + runTruePairing(collisions, emcclusters, emcclusters, nullptr, nullptr, perCollision_emc, perCollision_emc, fEMCCut, fEMCCut, mccollisions, mcparticles); + runGenInfo(collisions, mccollisions, mcparticles); + } + + // else if constexpr (pairtype == PairType::kPHOSPHOS) { + // auto phosclusters = std::get<0>(std::tie(args...)); + // runPairing(collisions, phosclusters, phosclusters, nullptr, nullptr, perCollision_phos, perCollision_phos, fPHOSCut, fPHOSCut, nullptr, nullptr); + // } + // else if constexpr (pairtype == PairType::kPCMEMC) { + // auto v0photons = std::get<0>(std::tie(args...)); + // auto v0legs = std::get<1>(std::tie(args...)); + // auto emcclusters = std::get<2>(std::tie(args...)); + // auto emcmatchedtracks = std::get<3>(std::tie(args...)); + // runPairing(collisions, v0photons, emcclusters, v0legs, nullptr, perCollision_pcm, perCollision_emc, fV0PhotonCut, fEMCCut, emcmatchedtracks, nullptr); + // } else if constexpr (pairtype == PairType::kPCMPHOS) { + // auto v0photons = std::get<0>(std::tie(args...)); + // auto v0legs = std::get<1>(std::tie(args...)); + // auto phosclusters = std::get<2>(std::tie(args...)); + // runPairing(collisions, v0photons, phosclusters, v0legs, nullptr, perCollision_pcm, perCollision_phos, fV0PhotonCut, fPHOSCut, nullptr, nullptr); + // } + } + PROCESS_SWITCH(Pi0EtaToGammaGammaMC, processAnalysis, "process pair analysis", false); + + void processDummy(MyCollisions const&) {} + PROCESS_SWITCH(Pi0EtaToGammaGammaMC, processDummy, "Dummy function", true); +}; +#endif // PWGEM_PHOTONMESON_CORE_PI0ETATOGAMMAGAMMAMC_H_ diff --git a/PWGEM/PhotonMeson/Core/TaggingPi0.h b/PWGEM/PhotonMeson/Core/TaggingPi0.h new file mode 100644 index 00000000000..d74af2ceb0c --- /dev/null +++ b/PWGEM/PhotonMeson/Core/TaggingPi0.h @@ -0,0 +1,697 @@ +// 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 TaggingPi0.h +/// \brief This code loops over photons and makes pairs for direct photon analysis. +/// +/// \author D. Sekihata, daiki.sekihata@cern.ch + +#ifndef PWGEM_PHOTONMESON_CORE_TAGGINGPI0_H_ +#define PWGEM_PHOTONMESON_CORE_TAGGINGPI0_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TString.h" +#include "Math/Vector4D.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + +#include "Common/Core/RecoDecay.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" +#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" +#include "PWGEM/Dilepton/Utils/EMTrack.h" +#include "PWGEM/Dilepton/Utils/EventMixingHandler.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::photonmeson::photonpair; +using namespace o2::aod::pwgem::photon; +using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; +using namespace o2::aod::pwgem::dilepton::utils; + +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; + +using MyV0Photons = soa::Join; +using MyV0Photon = MyV0Photons::iterator; + +using MyPrimaryElectrons = soa::Join; +using MyPrimaryElectron = MyPrimaryElectrons::iterator; + +using MyEMCClusters = soa::Join; +using MyEMCCluster = MyEMCClusters::iterator; + +using MyPHOSClusters = soa::Join; +using MyPHOSCluster = MyPHOSClusters::iterator; + +template +struct TaggingPi0 { + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + Configurable ndiff_bc_mix{"ndiff_bc_mix", 198, "difference in global BC required in mixed events"}; + + Configurable cfgQvecEstimator{"cfgQvecEstimator", 0, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgOccupancyEstimator{"cfgOccupancyEstimator", 0, "FT0C:0, Track:1"}; + Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999, "max. centrality"}; + Configurable cfgDoMix{"cfgDoMix", true, "flag for event mixing"}; + Configurable ndepth{"ndepth", 100, "depth for event mixing"}; + ConfigurableAxis ConfVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis ConfCentBins{"ConfCentBins", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.f, 999.f}, "Mixing bins - centrality"}; + ConfigurableAxis ConfEPBins{"ConfEPBins", {VARIABLE_WIDTH, -M_PI / 2, -M_PI / 4, 0.0f, +M_PI / 4, +M_PI / 2}, "Mixing bins - event plane angle"}; + ConfigurableAxis ConfOccupancyBins{"ConfOccupancyBins", {VARIABLE_WIDTH, -1, 1e+10}, "Mixing bins - occupancy"}; + ConfigurableAxis ConfPtBins{"ConfPtBins", {100, 0, 10}, "pT bins for output histograms"}; + + EMPhotonEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgRequireEMCReadoutInMB{"cfgRequireEMCReadoutInMB", false, "require the EMC to be read out in an MB collision (kTVXinEMC)"}; + Configurable cfgRequireEMCHardwareTriggered{"cfgRequireEMCHardwareTriggered", false, "require the EMC to be hardware triggered (kEMC7 or kDMC7)"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable onlyKeepWeightedEvents{"onlyKeepWeightedEvents", false, "flag to keep only weighted events (for JJ MCs) and remove all MB events (with weight = 1)"}; + } eventcuts; + + V0PhotonCut fV0PhotonCut; + struct : ConfigurableGroup { + std::string prefix = "pcmcut_group"; + Configurable cfg_require_v0_with_itstpc{"cfg_require_v0_with_itstpc", false, "flag to select V0s with ITS-TPC matched tracks"}; + Configurable cfg_require_v0_with_itsonly{"cfg_require_v0_with_itsonly", false, "flag to select V0s with ITSonly tracks"}; + Configurable cfg_require_v0_with_tpconly{"cfg_require_v0_with_tpconly", false, "flag to select V0s with TPConly tracks"}; + Configurable cfg_min_pt_v0{"cfg_min_pt_v0", 0.1, "min pT for v0 photons at PV"}; + Configurable cfg_max_pt_v0{"cfg_max_pt_v0", 1e+10, "max pT for v0 photons at PV"}; + Configurable cfg_min_eta_v0{"cfg_min_eta_v0", -0.8, "min eta for v0 photons at PV"}; + Configurable cfg_max_eta_v0{"cfg_max_eta_v0", 0.8, "max eta for v0 photons at PV"}; + Configurable cfg_min_v0radius{"cfg_min_v0radius", 4.0, "min v0 radius"}; + Configurable cfg_max_v0radius{"cfg_max_v0radius", 90.0, "max v0 radius"}; + Configurable cfg_max_alpha_ap{"cfg_max_alpha_ap", 0.95, "max alpha for AP cut"}; + Configurable cfg_max_qt_ap{"cfg_max_qt_ap", 0.01, "max qT for AP cut"}; + Configurable cfg_min_cospa{"cfg_min_cospa", 0.997, "min V0 CosPA"}; + Configurable cfg_max_pca{"cfg_max_pca", 3.0, "max distance btween 2 legs"}; + Configurable cfg_max_chi2kf{"cfg_max_chi2kf", 1e+10, "max chi2/ndf with KF"}; + Configurable cfg_require_v0_with_correct_xz{"cfg_require_v0_with_correct_xz", true, "flag to select V0s with correct xz"}; + Configurable cfg_reject_v0_on_itsib{"cfg_reject_v0_on_itsib", true, "flag to reject V0s on ITSib"}; + + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 10, "min ncluster tpc"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 40, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -3.0, "min. TPC n sigma for electron"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; + Configurable cfg_disable_itsonly_track{"cfg_disable_itsonly_track", false, "flag to disable ITSonly tracks"}; + Configurable cfg_disable_tpconly_track{"cfg_disable_tpconly_track", false, "flag to disable TPConly tracks"}; + } pcmcuts; + + DalitzEECut fDileptonCut; + struct : ConfigurableGroup { + std::string prefix = "dileptoncut_group"; + Configurable cfg_min_mass{"cfg_min_mass", 0.0, "min mass"}; + Configurable cfg_max_mass{"cfg_max_mass", 0.1, "max mass"}; + Configurable cfg_apply_phiv{"cfg_apply_phiv", true, "flag to apply phiv cut"}; + Configurable cfg_require_itsib_any{"cfg_require_itsib_any", false, "flag to require ITS ib any hits"}; + Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; + Configurable cfg_phiv_slope{"cfg_phiv_slope", 0.0185, "slope for m vs. phiv"}; + Configurable cfg_phiv_intercept{"cfg_phiv_intercept", -0.0280, "intercept for m vs. phiv"}; + + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.1, "min pT for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", 0.8, "max eta for single track"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 70, "min ncrossed rows"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 0.05, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 0.05, "max dca Z for single track in cm"}; + Configurable cfg_max_dca3dsigma_track{"cfg_max_dca3dsigma_track", 1.5, "max DCA 3D in sigma"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + + Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DalitzEECut::PIDSchemes::kTOFif), "pid scheme [kTOFif : 0, kTPConly : 1]"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -0.0, "min. TPC n sigma for pion exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +0.0, "max. TPC n sigma for pion exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; + } dileptoncuts; + + EMCPhotonCut fEMCCut; + struct : ConfigurableGroup { + std::string prefix = "emccut_group"; + Configurable clusterDefinition{"clusterDefinition", "kV3Default", "Clusterizer to be selected, e.g. V3Default"}; + Configurable minOpenAngle{"minOpenAngle", 0.0202, "apply min opening angle"}; + Configurable EMC_minTime{"EMC_minTime", -20., "Minimum cluster time for EMCal time cut"}; + Configurable EMC_maxTime{"EMC_maxTime", +25., "Maximum cluster time for EMCal time cut"}; + Configurable EMC_minM02{"EMC_minM02", 0.1, "Minimum M02 for EMCal M02 cut"}; + Configurable EMC_maxM02{"EMC_maxM02", 0.7, "Maximum M02 for EMCal M02 cut"}; + Configurable EMC_minE{"EMC_minE", 0.7, "Minimum cluster energy for EMCal energy cut"}; + Configurable EMC_minNCell{"EMC_minNCell", 1, "Minimum number of cells per cluster for EMCal NCell cut"}; + Configurable> EMC_TM_Eta{"EMC_TM_Eta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable> EMC_TM_Phi{"EMC_TM_Phi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable EMC_Eoverp{"EMC_Eoverp", 1.75, "Minimum cluster energy over track momentum for EMCal track matching"}; + Configurable EMC_UseExoticCut{"EMC_UseExoticCut", true, "FLag to use the EMCal exotic cluster cut"}; + Configurable cfgDistanceToEdge{"cfgDistanceToEdge", 1, "Distance to edge in cells required for rotated cluster to be accepted"}; + } emccuts; + + PHOSPhotonCut fPHOSCut; + struct : ConfigurableGroup { + std::string prefix = "phoscut_group"; + Configurable cfg_min_Ecluster{"cfg_min_Ecluster", 0.3, "Minimum cluster energy for PHOS in GeV"}; + } phoscuts; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view event_types[2] = {"before/", "after/"}; + static constexpr std::string_view event_pair_types[2] = {"same/", "mix/"}; + + std::vector zvtx_bin_edges; + std::vector cent_bin_edges; + std::vector ep_bin_edges; + std::vector occ_bin_edges; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + int mRunNumber; + float d_bz; + + void init(InitContext&) + { + zvtx_bin_edges = std::vector(ConfVtxBins.value.begin(), ConfVtxBins.value.end()); + zvtx_bin_edges.erase(zvtx_bin_edges.begin()); + + cent_bin_edges = std::vector(ConfCentBins.value.begin(), ConfCentBins.value.end()); + cent_bin_edges.erase(cent_bin_edges.begin()); + + ep_bin_edges = std::vector(ConfEPBins.value.begin(), ConfEPBins.value.end()); + ep_bin_edges.erase(ep_bin_edges.begin()); + + LOGF(info, "cfgOccupancyEstimator = %d", cfgOccupancyEstimator.value); + occ_bin_edges = std::vector(ConfOccupancyBins.value.begin(), ConfOccupancyBins.value.end()); + occ_bin_edges.erase(occ_bin_edges.begin()); + + emh1 = new MyEMH(ndepth); + emh2 = new MyEMH(ndepth); + + o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(&fRegistry); + + addHistogrms(); + DefineEMEventCut(); + DefinePCMCut(); + DefineDileptonCut(); + DefineEMCCut(); + DefinePHOSCut(); + + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + } + + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (std::fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + mRunNumber = collision.runNumber(); + return; + } + + auto run3grp_timestamp = collision.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = collision.runNumber(); + } + + ~TaggingPi0() + { + delete emh1; + emh1 = 0x0; + delete emh2; + emh2 = 0x0; + + used_photonIds.clear(); + used_photonIds.shrink_to_fit(); + used_dileptonIds.clear(); + used_dileptonIds.shrink_to_fit(); + map_mixed_eventId_to_globalBC.clear(); + } + + void addHistogrms() + { + TString mggTitle = "ee#gamma"; + if constexpr (pairtype == PairType::kPCMDalitzEE) { + mggTitle = "ee#gamma"; + } else { + mggTitle = "#gamma#gamma"; + } + + const AxisSpec axis_m{200, 0, 0.4, Form("m_{%s} (GeV/c^{2})", mggTitle.Data())}; + const AxisSpec axis_pt{ConfPtBins, "p_{T,#gamma} (GeV/c)"}; + + fRegistry.add("Photon/hPt", "p_{T,#gamma};p_{T,#gamma} (GeV/c)", kTH1D, {axis_pt}, true); + fRegistry.add("Photon/hEtaPhi", "#varphi vs. #eta;#varphi_{#gamma} (rad.);#eta_{#gamma}", kTH2D, {{90, 0, 2 * M_PI}, {40, -1, +1}}, true); + fRegistry.add("Pair/same/hMvsPt", "mass vs. p_{T,#gamma}", kTH2D, {axis_m, axis_pt}, true); + fRegistry.addClone("Pair/same/", "Pair/mix/"); + fRegistry.add("Pair/mix/hDiffBC", "diff. global BC in mixed event;|BC_{current} - BC_{mixed}|", kTH1D, {{10001, -0.5, 10000.5}}, true); + } + + void DefineEMEventCut() + { + fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireEMCReadoutInMB(eventcuts.cfgRequireEMCReadoutInMB); + fEMEventCut.SetRequireEMCHardwareTriggered(eventcuts.cfgRequireEMCHardwareTriggered); + } + + void DefinePCMCut() + { + fV0PhotonCut = V0PhotonCut("fV0PhotonCut", "fV0PhotonCut"); + + // for v0 + fV0PhotonCut.SetV0PtRange(pcmcuts.cfg_min_pt_v0, pcmcuts.cfg_max_pt_v0); + fV0PhotonCut.SetV0EtaRange(pcmcuts.cfg_min_eta_v0, pcmcuts.cfg_max_eta_v0); + fV0PhotonCut.SetMinCosPA(pcmcuts.cfg_min_cospa); + fV0PhotonCut.SetMaxPCA(pcmcuts.cfg_max_pca); + fV0PhotonCut.SetMaxChi2KF(pcmcuts.cfg_max_chi2kf); + fV0PhotonCut.SetRxyRange(pcmcuts.cfg_min_v0radius, pcmcuts.cfg_max_v0radius); + fV0PhotonCut.SetAPRange(pcmcuts.cfg_max_alpha_ap, pcmcuts.cfg_max_qt_ap); + fV0PhotonCut.RejectITSib(pcmcuts.cfg_reject_v0_on_itsib); + + // for track + fV0PhotonCut.SetMinNClustersTPC(pcmcuts.cfg_min_ncluster_tpc); + fV0PhotonCut.SetMinNCrossedRowsTPC(pcmcuts.cfg_min_ncrossedrows); + fV0PhotonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fV0PhotonCut.SetMaxFracSharedClustersTPC(pcmcuts.cfg_max_frac_shared_clusters_tpc); + fV0PhotonCut.SetChi2PerClusterTPC(0.0, pcmcuts.cfg_max_chi2tpc); + fV0PhotonCut.SetTPCNsigmaElRange(pcmcuts.cfg_min_TPCNsigmaEl, pcmcuts.cfg_max_TPCNsigmaEl); + fV0PhotonCut.SetChi2PerClusterITS(-1e+10, pcmcuts.cfg_max_chi2its); + fV0PhotonCut.SetNClustersITS(0, 7); + fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); + fV0PhotonCut.SetIsWithinBeamPipe(pcmcuts.cfg_require_v0_with_correct_xz); + fV0PhotonCut.SetDisableITSonly(pcmcuts.cfg_disable_itsonly_track); + fV0PhotonCut.SetDisableTPConly(pcmcuts.cfg_disable_tpconly_track); + fV0PhotonCut.SetRequireITSTPC(pcmcuts.cfg_require_v0_with_itstpc); + fV0PhotonCut.SetRequireITSonly(pcmcuts.cfg_require_v0_with_itsonly); + fV0PhotonCut.SetRequireTPConly(pcmcuts.cfg_require_v0_with_tpconly); + } + + void DefineDileptonCut() + { + fDileptonCut = DalitzEECut("fDileptonCut", "fDileptonCut"); + + // for pair + fDileptonCut.SetMeeRange(dileptoncuts.cfg_min_mass, dileptoncuts.cfg_max_mass); + fDileptonCut.SetMaxPhivPairMeeDep([&](float mll) { return (mll - dileptoncuts.cfg_phiv_intercept) / dileptoncuts.cfg_phiv_slope; }); + fDileptonCut.ApplyPhiV(dileptoncuts.cfg_apply_phiv); + fDileptonCut.RequireITSibAny(dileptoncuts.cfg_require_itsib_any); + fDileptonCut.RequireITSib1st(dileptoncuts.cfg_require_itsib_1st); + + // for track + fDileptonCut.SetTrackPtRange(dileptoncuts.cfg_min_pt_track, 1e+10f); + fDileptonCut.SetTrackEtaRange(-dileptoncuts.cfg_max_eta_track, +dileptoncuts.cfg_max_eta_track); + fDileptonCut.SetMinNClustersTPC(dileptoncuts.cfg_min_ncluster_tpc); + fDileptonCut.SetMinNCrossedRowsTPC(dileptoncuts.cfg_min_ncrossedrows); + fDileptonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fDileptonCut.SetMaxFracSharedClustersTPC(dileptoncuts.cfg_max_frac_shared_clusters_tpc); + fDileptonCut.SetChi2PerClusterTPC(0.0, dileptoncuts.cfg_max_chi2tpc); + fDileptonCut.SetChi2PerClusterITS(0.0, dileptoncuts.cfg_max_chi2its); + fDileptonCut.SetNClustersITS(dileptoncuts.cfg_min_ncluster_its, 7); + fDileptonCut.SetMaxDcaXY(dileptoncuts.cfg_max_dcaxy); + fDileptonCut.SetMaxDcaZ(dileptoncuts.cfg_max_dcaz); + fDileptonCut.SetTrackDca3DRange(0.f, dileptoncuts.cfg_max_dca3dsigma_track); // in sigma + + // for eID + fDileptonCut.SetPIDScheme(dileptoncuts.cfg_pid_scheme); + fDileptonCut.SetTPCNsigmaElRange(dileptoncuts.cfg_min_TPCNsigmaEl, dileptoncuts.cfg_max_TPCNsigmaEl); + fDileptonCut.SetTPCNsigmaPiRange(dileptoncuts.cfg_min_TPCNsigmaPi, dileptoncuts.cfg_max_TPCNsigmaPi); + fDileptonCut.SetTOFNsigmaElRange(dileptoncuts.cfg_min_TOFNsigmaEl, dileptoncuts.cfg_max_TOFNsigmaEl); + } + + void DefineEMCCut() + { + const float a = emccuts.EMC_TM_Eta->at(0); + const float b = emccuts.EMC_TM_Eta->at(1); + const float c = emccuts.EMC_TM_Eta->at(2); + + const float d = emccuts.EMC_TM_Phi->at(0); + const float e = emccuts.EMC_TM_Phi->at(1); + const float f = emccuts.EMC_TM_Phi->at(2); + LOGF(info, "EMCal track matching parameters : a = %f, b = %f, c = %f, d = %f, e = %f, f = %f", a, b, c, d, e, f); + + fEMCCut = EMCPhotonCut("fEMCCut", "fEMCCut"); + + fEMCCut.SetClusterizer(emccuts.clusterDefinition); + fEMCCut.SetMinE(emccuts.EMC_minE); + fEMCCut.SetMinNCell(emccuts.EMC_minNCell); + fEMCCut.SetM02Range(emccuts.EMC_minM02, emccuts.EMC_maxM02); + fEMCCut.SetTimeRange(emccuts.EMC_minTime, emccuts.EMC_maxTime); + + fEMCCut.SetTrackMatchingEta([a, b, c](float pT) { return a + std::pow(pT + b, c); }); + fEMCCut.SetTrackMatchingPhi([d, e, f](float pT) { return d + std::pow(pT + e, f); }); + + fEMCCut.SetMinEoverP(emccuts.EMC_Eoverp); + fEMCCut.SetUseExoticCut(emccuts.EMC_UseExoticCut); + } + + void DefinePHOSCut() + { + fPHOSCut.SetEnergyRange(phoscuts.cfg_min_Ecluster, 1e+10); + } + + SliceCache cache; + Preslice perCollision_pcm = aod::v0photonkf::emeventId; + Preslice perCollision_emc = aod::emccluster::emeventId; + Preslice perCollision_phos = aod::phoscluster::emeventId; + + Preslice perCollision_electron = aod::emprimaryelectron::emeventId; + Partition positrons = o2::aod::emprimaryelectron::sign > int8_t(0) && static_cast(dileptoncuts.cfg_min_pt_track) < o2::aod::track::pt&& nabs(o2::aod::track::eta) < static_cast(dileptoncuts.cfg_max_eta_track) && static_cast(dileptoncuts.cfg_min_TPCNsigmaEl) < o2::aod::pidtpc::tpcNSigmaEl&& o2::aod::pidtpc::tpcNSigmaEl < static_cast(dileptoncuts.cfg_max_TPCNsigmaEl); + Partition electrons = o2::aod::emprimaryelectron::sign < int8_t(0) && static_cast(dileptoncuts.cfg_min_pt_track) < o2::aod::track::pt && nabs(o2::aod::track::eta) < static_cast(dileptoncuts.cfg_max_eta_track) && static_cast(dileptoncuts.cfg_min_TPCNsigmaEl) < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < static_cast(dileptoncuts.cfg_max_TPCNsigmaEl); + + using MyEMH = o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, EMTrack>; + MyEMH* emh1 = nullptr; + MyEMH* emh2 = nullptr; + std::vector> used_photonIds; // + std::vector> used_dileptonIds; // + std::map, uint64_t> map_mixed_eventId_to_globalBC; + + template + void runPairing(TCollisions const& collisions, + TPhotons1 const& photons1, TPhotons2 const& photons2, + TSubInfos1 const& /*subinfos1*/, TSubInfos2 const& /*subinfos2*/, + TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, + TCut1 const& cut1, TCut2 const& cut2) + { + for (const auto& collision : collisions) { + initCCDB(collision); + int ndiphoton = 0; + + if (eventcuts.onlyKeepWeightedEvents && std::fabs(collision.weight() - 1.f) < 1e-10) { + continue; + } + + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision, collision.weight()); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision, collision.weight()); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 12.0, collision.weight()); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 12.0, collision.weight()); // accepted + + int zbin = lower_bound(zvtx_bin_edges.begin(), zvtx_bin_edges.end(), collision.posZ()) - zvtx_bin_edges.begin() - 1; + if (zbin < 0) { + zbin = 0; + } else if (static_cast(zvtx_bin_edges.size()) - 2 < zbin) { + zbin = static_cast(zvtx_bin_edges.size()) - 2; + } + + float centrality = centralities[cfgCentEstimator]; + int centbin = lower_bound(cent_bin_edges.begin(), cent_bin_edges.end(), centrality) - cent_bin_edges.begin() - 1; + if (centbin < 0) { + centbin = 0; + } else if (static_cast(cent_bin_edges.size()) - 2 < centbin) { + centbin = static_cast(cent_bin_edges.size()) - 2; + } + + float ep2 = collision.ep2btot(); + int epbin = lower_bound(ep_bin_edges.begin(), ep_bin_edges.end(), ep2) - ep_bin_edges.begin() - 1; + if (epbin < 0) { + epbin = 0; + } else if (static_cast(ep_bin_edges.size()) - 2 < epbin) { + epbin = static_cast(ep_bin_edges.size()) - 2; + } + + int occbin = -1; + if (cfgOccupancyEstimator == 0) { + occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.ft0cOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; + } else if (cfgOccupancyEstimator == 1) { + occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.trackOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; + } else { + occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.ft0cOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; + } + + if (occbin < 0) { + occbin = 0; + } else if (static_cast(occ_bin_edges.size()) - 2 < occbin) { + occbin = static_cast(occ_bin_edges.size()) - 2; + } + + // LOGF(info, "collision.globalIndex() = %d, collision.posZ() = %f, centrality = %f, ep2 = %f, collision.trackOccupancyInTimeRange() = %d, zbin = %d, centbin = %d, epbin = %d, occbin = %d", collision.globalIndex(), collision.posZ(), centrality, ep2, collision.trackOccupancyInTimeRange(), zbin, centbin, epbin, occbin); + + std::tuple key_bin = std::make_tuple(zbin, centbin, epbin, occbin); + std::pair key_df_collision = std::make_pair(ndf, collision.globalIndex()); + + if constexpr (pairtype == PairType::kPCMDalitzEE) { + auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); // PCM + auto positrons_per_collision = positrons->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); // positrons + auto electrons_per_collision = electrons->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); // electrons + + for (const auto& g1 : photons1_per_collision) { + if (!cut1.template IsSelected(g1)) { + continue; + } + auto pos1 = g1.template posTrack_as(); + auto ele1 = g1.template negTrack_as(); + ROOT::Math::PtEtaPhiMVector v_gamma(g1.pt(), g1.eta(), g1.phi(), 0.); + fRegistry.fill(HIST("Photon/hPt"), v_gamma.Pt(), collision.weight()); + fRegistry.fill(HIST("Photon/hEtaPhi"), v_gamma.Phi() > 0 ? v_gamma.Phi() : v_gamma.Phi() + 2 * M_PI, v_gamma.Eta(), collision.weight()); + + for (const auto& [pos2, ele2] : combinations(CombinationsFullIndexPolicy(positrons_per_collision, electrons_per_collision))) { + + if (pos2.trackId() == ele2.trackId()) { // this is protection against pairing identical 2 tracks. + continue; + } + if (pos1.trackId() == pos2.trackId() || ele1.trackId() == ele2.trackId()) { + continue; + } + + if (!cut2.template IsSelectedTrack(pos2, collision) || !cut2.template IsSelectedTrack(ele2, collision)) { + continue; + } + + if (!cut2.IsSelectedPair(pos2, ele2, d_bz)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v_pos(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v_ele(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v_ee = v_pos + v_ele; + ROOT::Math::PtEtaPhiMVector veeg = v_gamma + v_pos + v_ele; + fRegistry.fill(HIST("Pair/same/hMvsPt"), veeg.M(), v_gamma.Pt(), collision.weight()); + + std::pair pair_tmp_id1 = std::make_pair(ndf, g1.globalIndex()); + std::tuple tuple_tmp_id2 = std::make_tuple(ndf, collision.globalIndex(), pos2.trackId(), ele2.trackId()); + if (std::find(used_photonIds.begin(), used_photonIds.end(), pair_tmp_id1) == used_photonIds.end()) { + emh1->AddTrackToEventPool(key_df_collision, EMTrack(-1, g1.globalIndex(), collision.globalIndex(), -1, g1.pt(), g1.eta(), g1.phi(), 0)); + used_photonIds.emplace_back(pair_tmp_id1); + } + if (std::find(used_dileptonIds.begin(), used_dileptonIds.end(), tuple_tmp_id2) == used_dileptonIds.end()) { + emh2->AddTrackToEventPool(key_df_collision, EMTrack(-1, -1, collision.globalIndex(), -1, v_ee.Pt(), v_ee.Eta(), v_ee.Phi(), v_ee.M())); + used_dileptonIds.emplace_back(tuple_tmp_id2); + } + ndiphoton++; + } // end of dielectron loop + } // end of g1 loop + } else { // PCM-EMC, PCM-PHOS. Not supported. + auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); // PCM + auto photons2_per_collision = photons2.sliceBy(perCollision2, collision.globalIndex()); // EMC or PHOS + + for (const auto& [g1, g2] : combinations(CombinationsFullIndexPolicy(photons1_per_collision, photons2_per_collision))) { + if (!cut1.template IsSelected(g1) || !cut2.template IsSelected(g2)) { + continue; + } + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + + fRegistry.fill(HIST("Pair/same/hMvsPt"), v12.M(), v1.Pt(), collision.weight()); + + std::pair pair_tmp_id1 = std::make_pair(ndf, g1.globalIndex()); + std::pair pair_tmp_id2 = std::make_pair(ndf, g2.globalIndex()); + + if (std::find(used_photonIds.begin(), used_photonIds.end(), pair_tmp_id1) == used_photonIds.end()) { + emh1->AddTrackToEventPool(key_df_collision, EMTrack(-1, g1.globalIndex(), collision.globalIndex(), -1, g1.pt(), g1.eta(), g1.phi(), 0)); + used_photonIds.emplace_back(pair_tmp_id1); + } + if (std::find(used_photonIds.begin(), used_photonIds.end(), pair_tmp_id2) == used_photonIds.end()) { + emh2->AddTrackToEventPool(key_df_collision, EMTrack(-1, g2.globalIndex(), collision.globalIndex(), -1, g2.pt(), g2.eta(), g2.phi(), 0)); + used_photonIds.emplace_back(pair_tmp_id2); + } + ndiphoton++; + } // end of pairing loop + } // end of pairing in same event + + // event mixing + if (!cfgDoMix || !(ndiphoton > 0)) { + continue; + } + + // make a vector of selected photons in this collision. + auto selected_photons1_in_this_event = emh1->GetTracksPerCollision(key_df_collision); + // auto selected_photons2_in_this_event = emh2->GetTracksPerCollision(key_df_collision); + + // auto collisionIds1_in_mixing_pool = emh1->GetCollisionIdsFromEventPool(key_bin); + auto collisionIds2_in_mixing_pool = emh2->GetCollisionIdsFromEventPool(key_bin); + + for (const auto& mix_dfId_collisionId : collisionIds2_in_mixing_pool) { + int mix_dfId = mix_dfId_collisionId.first; + int64_t mix_collisionId = mix_dfId_collisionId.second; + + if (collision.globalIndex() == mix_collisionId && ndf == mix_dfId) { // this never happens. only protection. + continue; + } + + auto globalBC_mix = map_mixed_eventId_to_globalBC[mix_dfId_collisionId]; + uint64_t diffBC = std::max(collision.globalBC(), globalBC_mix) - std::min(collision.globalBC(), globalBC_mix); + fRegistry.fill(HIST("Pair/mix/hDiffBC"), diffBC); + if (diffBC < ndiff_bc_mix) { + continue; + } + + auto photons2_from_event_pool = emh2->GetTracksPerCollision(mix_dfId_collisionId); + // LOGF(info, "Do event mixing: current event (%d, %d), ngamma = %d | event pool (%d, %d), nll = %d", ndf, collision.globalIndex(), selected_photons1_in_this_event.size(), mix_dfId, mix_collisionId, photons2_from_event_pool.size()); + + for (const auto& g1 : selected_photons1_in_this_event) { // [photon from event1, dilepton from event2] + for (const auto& g2 : photons2_from_event_pool) { + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); + if constexpr (pairtype == PairType::kPCMDalitzEE) { + v2.SetM(g2.mass()); + } + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + fRegistry.fill(HIST("Pair/mix/hMvsPt"), v12.M(), v1.Pt(), collision.weight()); + } + } + } // end of loop over mixed event pool + + if (ndiphoton > 0) { + emh1->AddCollisionIdAtLast(key_bin, key_df_collision); + emh2->AddCollisionIdAtLast(key_bin, key_df_collision); + map_mixed_eventId_to_globalBC[key_df_collision] = collision.globalBC(); + } + + } // end of collision loop + } + + Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + using FilteredMyCollisions = soa::Filtered; + + int ndf = 0; + void processAnalysis(FilteredMyCollisions const& collisions, Types const&... args) + { + // LOGF(info, "ndf = %d", ndf); + if constexpr (pairtype == PairType::kPCMDalitzEE) { + auto v0photons = std::get<0>(std::tie(args...)); + auto v0legs = std::get<1>(std::tie(args...)); + auto emprimaryelectrons = std::get<2>(std::tie(args...)); + // LOGF(info, "electrons.size() = %d, positrons.size() = %d", electrons.size(), positrons.size()); + runPairing(collisions, v0photons, emprimaryelectrons, v0legs, emprimaryelectrons, perCollision_pcm, perCollision_electron, fV0PhotonCut, fDileptonCut); + } + // else if constexpr (pairtype == PairType::kPCMEMC) { + // auto v0photons = std::get<0>(std::tie(args...)); + // auto v0legs = std::get<1>(std::tie(args...)); + // auto emcclusters = std::get<2>(std::tie(args...)); + // auto emcmatchedtracks = std::get<3>(std::tie(args...)); + // runPairing(collisions, v0photons, emcclusters, v0legs, nullptr, perCollision_pcm, perCollision_emc, fV0PhotonCut, fEMCCut, emcmatchedtracks, nullptr); + // } else if constexpr (pairtype == PairType::kPCMPHOS) { + // auto v0photons = std::get<0>(std::tie(args...)); + // auto v0legs = std::get<1>(std::tie(args...)); + // auto phosclusters = std::get<2>(std::tie(args...)); + // runPairing(collisions, v0photons, phosclusters, v0legs, nullptr, perCollision_pcm, perCollision_phos, fV0PhotonCut, fPHOSCut, nullptr, nullptr); + // } + ndf++; + } + PROCESS_SWITCH(TaggingPi0, processAnalysis, "process pair analysis", false); + + void processDummy(MyCollisions const&) {} + PROCESS_SWITCH(TaggingPi0, processDummy, "Dummy function", true); +}; +#endif // PWGEM_PHOTONMESON_CORE_TAGGINGPI0_H_ diff --git a/PWGEM/PhotonMeson/Core/TaggingPi0MC.h b/PWGEM/PhotonMeson/Core/TaggingPi0MC.h new file mode 100644 index 00000000000..56c6274a141 --- /dev/null +++ b/PWGEM/PhotonMeson/Core/TaggingPi0MC.h @@ -0,0 +1,600 @@ +// 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. +// +// ======================== +// +// This code loops over photons and makes pairs for neutral mesons analyses. +// Please write to: daiki.sekihata@cern.ch + +#ifndef PWGEM_PHOTONMESON_CORE_TAGGINGPI0MC_H_ +#define PWGEM_PHOTONMESON_CORE_TAGGINGPI0MC_H_ + +#include +#include +#include + +#include "TF1.h" +#include "TString.h" +#include "Math/Vector4D.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + +#include "Common/Core/RecoDecay.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" +#include "PWGEM/PhotonMeson/Utils/NMHistograms.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" +#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::photonmeson::photonpair; +using namespace o2::aod::pwgem::photonmeson::utils::mcutil; +using namespace o2::aod::pwgem::dilepton::utils::mcutil; + +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; + +using MyMCCollisions = soa::Join; +using MyMCCollision = MyMCCollisions::iterator; + +using MyV0Photons = soa::Join; +using MyV0Photon = MyV0Photons::iterator; + +using MyEMCClusters = soa::Join; +using MyEMCCluster = MyEMCClusters::iterator; + +using MyPHOSClusters = soa::Join; +using MyPHOSCluster = MyEMCClusters::iterator; + +using MyMCV0Legs = soa::Join; +using MyMCV0Leg = MyMCV0Legs::iterator; + +using MyMCElectrons = soa::Join; +using MyMCElectron = MyMCElectrons::iterator; + +template +struct TaggingPi0MC { + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + + Configurable cfgQvecEstimator{"cfgQvecEstimator", 0, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999, "max. centrality"}; + Configurable fd_k0s_to_pi0{"fd_k0s_pi0", "1.0", "feed down correction to pi0"}; + Configurable cfgRequireTrueAssociation{"cfgRequireTrueAssociation", false, "flag to require true mc collision association"}; + ConfigurableAxis ConfPtBins{"ConfPtBins", {100, 0, 10}, "pT bins for output histograms"}; + + EMPhotonEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgRequireEMCReadoutInMB{"cfgRequireEMCReadoutInMB", false, "require the EMC to be read out in an MB collision (kTVXinEMC)"}; + Configurable cfgRequireEMCHardwareTriggered{"cfgRequireEMCHardwareTriggered", false, "require the EMC to be hardware triggered (kEMC7 or kDMC7)"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable onlyKeepWeightedEvents{"onlyKeepWeightedEvents", false, "flag to keep only weighted events (for JJ MCs) and remove all MB events (with weight = 1)"}; + } eventcuts; + + V0PhotonCut fV0PhotonCut; + struct : ConfigurableGroup { + std::string prefix = "pcmcut_group"; + Configurable cfg_require_v0_with_itstpc{"cfg_require_v0_with_itstpc", false, "flag to select V0s with ITS-TPC matched tracks"}; + Configurable cfg_require_v0_with_itsonly{"cfg_require_v0_with_itsonly", false, "flag to select V0s with ITSonly tracks"}; + Configurable cfg_require_v0_with_tpconly{"cfg_require_v0_with_tpconly", false, "flag to select V0s with TPConly tracks"}; + Configurable cfg_min_pt_v0{"cfg_min_pt_v0", 0.1, "min pT for v0 photons at PV"}; + Configurable cfg_max_pt_v0{"cfg_max_pt_v0", 1e+10, "max pT for v0 photons at PV"}; + Configurable cfg_min_eta_v0{"cfg_min_eta_v0", -0.8, "min eta for v0 photons at PV"}; + Configurable cfg_max_eta_v0{"cfg_max_eta_v0", 0.8, "max eta for v0 photons at PV"}; + Configurable cfg_min_v0radius{"cfg_min_v0radius", 4.0, "min v0 radius"}; + Configurable cfg_max_v0radius{"cfg_max_v0radius", 90.0, "max v0 radius"}; + Configurable cfg_max_alpha_ap{"cfg_max_alpha_ap", 0.95, "max alpha for AP cut"}; + Configurable cfg_max_qt_ap{"cfg_max_qt_ap", 0.01, "max qT for AP cut"}; + Configurable cfg_min_cospa{"cfg_min_cospa", 0.997, "min V0 CosPA"}; + Configurable cfg_max_pca{"cfg_max_pca", 3.0, "max distance btween 2 legs"}; + Configurable cfg_max_chi2kf{"cfg_max_chi2kf", 1e+10, "max chi2/ndf with KF"}; + Configurable cfg_require_v0_with_correct_xz{"cfg_require_v0_with_correct_xz", true, "flag to select V0s with correct xz"}; + Configurable cfg_reject_v0_on_itsib{"cfg_reject_v0_on_itsib", true, "flag to reject V0s on ITSib"}; + + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 10, "min ncluster tpc"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 40, "min ncrossed rows"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -3.0, "min. TPC n sigma for electron"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; + Configurable cfg_disable_itsonly_track{"cfg_disable_itsonly_track", false, "flag to disable ITSonly tracks"}; + Configurable cfg_disable_tpconly_track{"cfg_disable_tpconly_track", false, "flag to disable TPConly tracks"}; + } pcmcuts; + + DalitzEECut fDileptonCut; + struct : ConfigurableGroup { + std::string prefix = "dileptoncut_group"; + Configurable cfg_min_mass{"cfg_min_mass", 0.0, "min mass"}; + Configurable cfg_max_mass{"cfg_max_mass", 0.1, "max mass"}; + Configurable cfg_apply_phiv{"cfg_apply_phiv", true, "flag to apply phiv cut"}; + Configurable cfg_require_itsib_any{"cfg_require_itsib_any", false, "flag to require ITS ib any hits"}; + Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; + Configurable cfg_phiv_slope{"cfg_phiv_slope", 0.0185, "slope for m vs. phiv"}; + Configurable cfg_phiv_intercept{"cfg_phiv_intercept", -0.0280, "intercept for m vs. phiv"}; + + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.1, "min pT for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", 0.8, "max eta for single track"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 70, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 0.05, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 0.05, "max dca Z for single track in cm"}; + Configurable cfg_max_dca3dsigma_track{"cfg_max_dca3dsigma_track", 1.5, "max DCA 3D in sigma"}; + + Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DalitzEECut::PIDSchemes::kTOFif), "pid scheme [kTOFif : 0, kTPConly : 1]"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -0.0, "min. TPC n sigma for pion exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +0.0, "max. TPC n sigma for pion exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; + } dileptoncuts; + + EMCPhotonCut fEMCCut; + struct : ConfigurableGroup { + std::string prefix = "emccut_group"; + Configurable clusterDefinition{"clusterDefinition", "kV3Default", "Clusterizer to be selected, e.g. V3Default"}; + Configurable minOpenAngle{"minOpenAngle", 0.0202, "apply min opening angle"}; + Configurable EMC_minTime{"EMC_minTime", -20., "Minimum cluster time for EMCal time cut"}; + Configurable EMC_maxTime{"EMC_maxTime", +25., "Maximum cluster time for EMCal time cut"}; + Configurable EMC_minM02{"EMC_minM02", 0.1, "Minimum M02 for EMCal M02 cut"}; + Configurable EMC_maxM02{"EMC_maxM02", 0.7, "Maximum M02 for EMCal M02 cut"}; + Configurable EMC_minE{"EMC_minE", 0.7, "Minimum cluster energy for EMCal energy cut"}; + Configurable EMC_minNCell{"EMC_minNCell", 1, "Minimum number of cells per cluster for EMCal NCell cut"}; + Configurable> EMC_TM_Eta{"EMC_TM_Eta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable> EMC_TM_Phi{"EMC_TM_Phi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable EMC_Eoverp{"EMC_Eoverp", 1.75, "Minimum cluster energy over track momentum for EMCal track matching"}; + Configurable EMC_UseExoticCut{"EMC_UseExoticCut", true, "FLag to use the EMCal exotic cluster cut"}; + } emccuts; + + PHOSPhotonCut fPHOSCut; + struct : ConfigurableGroup { + std::string prefix = "phoscut_group"; + Configurable cfg_min_Ecluster{"cfg_min_Ecluster", 0.3, "Minimum cluster energy for PHOS in GeV"}; + } phoscuts; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view event_types[2] = {"before/", "after/"}; + static constexpr std::string_view event_pair_types[2] = {"same/", "mix/"}; + static constexpr std::string_view parnames[2] = {"Pi0/", "Eta/"}; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + int mRunNumber; + float d_bz; + TF1* f1fd_k0s_to_pi0; + + void init(InitContext&) + { + o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(&fRegistry); + addHistogrms(); + DefineEMEventCut(); + DefinePCMCut(); + DefineDileptonCut(); + DefineEMCCut(); + DefinePHOSCut(); + + mRunNumber = 0; + d_bz = 0; + f1fd_k0s_to_pi0 = new TF1("f1fd_k0s_to_pi0", TString(fd_k0s_to_pi0), 0.f, 100.f); + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + } + + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (std::fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + mRunNumber = collision.runNumber(); + return; + } + + auto run3grp_timestamp = collision.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = collision.runNumber(); + } + + ~TaggingPi0MC() + { + delete f1fd_k0s_to_pi0; + f1fd_k0s_to_pi0 = 0x0; + } + + void addHistogrms() + { + TString mggTitle = "ee#gamma"; + if constexpr (pairtype == PairType::kPCMDalitzEE) { + mggTitle = "ee#gamma"; + } else { + mggTitle = "#gamma#gamma"; + } + + const AxisSpec axis_m{200, 0, 0.4, Form("m_{%s} (GeV/c^{2})", mggTitle.Data())}; + const AxisSpec axis_pt{ConfPtBins, "p_{T,#gamma} (GeV/c)"}; + + fRegistry.add("Photon/candidate/hPt", "photon candidates;p_{T,#gamma} (GeV/c)", kTH1D, {axis_pt}, true); // for purity + fRegistry.add("Photon/candidate/hEtaPhi", "#varphi vs. #eta;#varphi_{#gamma} (rad.);#eta_{#gamma}", kTH2D, {{90, 0, 2 * M_PI}, {40, -1, +1}}, true); // for purity + fRegistry.add("Photon/primary/hPt", "photon;p_{T,#gamma} (GeV/c)", kTH1D, {axis_pt}, true); // for purity + fRegistry.add("Photon/primary/hEtaPhi", "#varphi vs. #eta;#varphi_{#gamma} (rad.);#eta_{#gamma}", kTH2D, {{90, 0, 2 * M_PI}, {40, -1, +1}}, true); // for purity + fRegistry.addClone("Photon/primary/", "Photon/fromWD/"); // only for completeness + fRegistry.addClone("Photon/primary/", "Photon/fromHS/"); // only for completeness + fRegistry.addClone("Photon/primary/", "Photon/fromPi0/"); // for conditional acceptance, denominator + + fRegistry.add("Pair/primary/hMvsPt", "mass vs. p_{T,#gamma} from #pi^{0}", kTH2D, {axis_m, axis_pt}, true); // for conditional acceptance, numerator + fRegistry.addClone("Pair/primary/", "Pair/fromWD/"); // only for completeness + fRegistry.addClone("Pair/primary/", "Pair/fromHS/"); // only for completeness + } + + void DefineEMEventCut() + { + fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireEMCReadoutInMB(eventcuts.cfgRequireEMCReadoutInMB); + fEMEventCut.SetRequireEMCHardwareTriggered(eventcuts.cfgRequireEMCHardwareTriggered); + } + + void DefinePCMCut() + { + fV0PhotonCut = V0PhotonCut("fV0PhotonCut", "fV0PhotonCut"); + + // for v0 + fV0PhotonCut.SetV0PtRange(pcmcuts.cfg_min_pt_v0, pcmcuts.cfg_max_pt_v0); + fV0PhotonCut.SetV0EtaRange(pcmcuts.cfg_min_eta_v0, pcmcuts.cfg_max_eta_v0); + fV0PhotonCut.SetMinCosPA(pcmcuts.cfg_min_cospa); + fV0PhotonCut.SetMaxPCA(pcmcuts.cfg_max_pca); + fV0PhotonCut.SetMaxChi2KF(pcmcuts.cfg_max_chi2kf); + fV0PhotonCut.SetRxyRange(pcmcuts.cfg_min_v0radius, pcmcuts.cfg_max_v0radius); + fV0PhotonCut.SetAPRange(pcmcuts.cfg_max_alpha_ap, pcmcuts.cfg_max_qt_ap); + fV0PhotonCut.RejectITSib(pcmcuts.cfg_reject_v0_on_itsib); + + // for track + fV0PhotonCut.SetMinNClustersTPC(pcmcuts.cfg_min_ncluster_tpc); + fV0PhotonCut.SetMinNCrossedRowsTPC(pcmcuts.cfg_min_ncrossedrows); + fV0PhotonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fV0PhotonCut.SetMaxFracSharedClustersTPC(pcmcuts.cfg_max_frac_shared_clusters_tpc); + fV0PhotonCut.SetChi2PerClusterTPC(0.0, pcmcuts.cfg_max_chi2tpc); + fV0PhotonCut.SetTPCNsigmaElRange(pcmcuts.cfg_min_TPCNsigmaEl, pcmcuts.cfg_max_TPCNsigmaEl); + fV0PhotonCut.SetChi2PerClusterITS(-1e+10, pcmcuts.cfg_max_chi2its); + fV0PhotonCut.SetNClustersITS(0, 7); + fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); + fV0PhotonCut.SetIsWithinBeamPipe(pcmcuts.cfg_require_v0_with_correct_xz); + fV0PhotonCut.SetDisableITSonly(pcmcuts.cfg_disable_itsonly_track); + fV0PhotonCut.SetDisableTPConly(pcmcuts.cfg_disable_tpconly_track); + fV0PhotonCut.SetRequireITSTPC(pcmcuts.cfg_require_v0_with_itstpc); + fV0PhotonCut.SetRequireITSonly(pcmcuts.cfg_require_v0_with_itsonly); + fV0PhotonCut.SetRequireTPConly(pcmcuts.cfg_require_v0_with_tpconly); + } + + void DefineDileptonCut() + { + fDileptonCut = DalitzEECut("fDileptonCut", "fDileptonCut"); + + // for pair + fDileptonCut.SetMeeRange(dileptoncuts.cfg_min_mass, dileptoncuts.cfg_max_mass); + fDileptonCut.SetMaxPhivPairMeeDep([&](float mll) { return (mll - dileptoncuts.cfg_phiv_intercept) / dileptoncuts.cfg_phiv_slope; }); + fDileptonCut.ApplyPhiV(dileptoncuts.cfg_apply_phiv); + fDileptonCut.RequireITSibAny(dileptoncuts.cfg_require_itsib_any); + fDileptonCut.RequireITSib1st(dileptoncuts.cfg_require_itsib_1st); + + // for track + fDileptonCut.SetTrackPtRange(dileptoncuts.cfg_min_pt_track, 1e+10f); + fDileptonCut.SetTrackEtaRange(-dileptoncuts.cfg_max_eta_track, +dileptoncuts.cfg_max_eta_track); + fDileptonCut.SetMinNClustersTPC(dileptoncuts.cfg_min_ncluster_tpc); + fDileptonCut.SetMinNCrossedRowsTPC(dileptoncuts.cfg_min_ncrossedrows); + fDileptonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fDileptonCut.SetMaxFracSharedClustersTPC(dileptoncuts.cfg_max_frac_shared_clusters_tpc); + fDileptonCut.SetChi2PerClusterTPC(0.0, dileptoncuts.cfg_max_chi2tpc); + fDileptonCut.SetChi2PerClusterITS(0.0, dileptoncuts.cfg_max_chi2its); + fDileptonCut.SetNClustersITS(dileptoncuts.cfg_min_ncluster_its, 7); + fDileptonCut.SetMaxDcaXY(dileptoncuts.cfg_max_dcaxy); + fDileptonCut.SetMaxDcaZ(dileptoncuts.cfg_max_dcaz); + fDileptonCut.SetTrackDca3DRange(0.f, dileptoncuts.cfg_max_dca3dsigma_track); // in sigma + + // for eID + fDileptonCut.SetPIDScheme(dileptoncuts.cfg_pid_scheme); + fDileptonCut.SetTPCNsigmaElRange(dileptoncuts.cfg_min_TPCNsigmaEl, dileptoncuts.cfg_max_TPCNsigmaEl); + fDileptonCut.SetTPCNsigmaPiRange(dileptoncuts.cfg_min_TPCNsigmaPi, dileptoncuts.cfg_max_TPCNsigmaPi); + fDileptonCut.SetTOFNsigmaElRange(dileptoncuts.cfg_min_TOFNsigmaEl, dileptoncuts.cfg_max_TOFNsigmaEl); + } + + void DefineEMCCut() + { + const float a = emccuts.EMC_TM_Eta->at(0); + const float b = emccuts.EMC_TM_Eta->at(1); + const float c = emccuts.EMC_TM_Eta->at(2); + + const float d = emccuts.EMC_TM_Phi->at(0); + const float e = emccuts.EMC_TM_Phi->at(1); + const float f = emccuts.EMC_TM_Phi->at(2); + LOGF(info, "EMCal track matching parameters : a = %f, b = %f, c = %f, d = %f, e = %f, f = %f", a, b, c, d, e, f); + + fEMCCut = EMCPhotonCut("fEMCCut", "fEMCCut"); + + fEMCCut.SetClusterizer(emccuts.clusterDefinition); + fEMCCut.SetMinE(emccuts.EMC_minE); + fEMCCut.SetMinNCell(emccuts.EMC_minNCell); + fEMCCut.SetM02Range(emccuts.EMC_minM02, emccuts.EMC_maxM02); + fEMCCut.SetTimeRange(emccuts.EMC_minTime, emccuts.EMC_maxTime); + + fEMCCut.SetTrackMatchingEta([a, b, c](float pT) { return a + std::pow(pT + b, c); }); + fEMCCut.SetTrackMatchingPhi([d, e, f](float pT) { return d + std::pow(pT + e, f); }); + + fEMCCut.SetMinEoverP(emccuts.EMC_Eoverp); + fEMCCut.SetUseExoticCut(emccuts.EMC_UseExoticCut); + } + + void DefinePHOSCut() + { + fPHOSCut.SetEnergyRange(phoscuts.cfg_min_Ecluster, 1e+10); + } + + SliceCache cache; + Preslice perCollision_pcm = aod::v0photonkf::emeventId; + Preslice perCollision_emc = aod::emccluster::emeventId; + Preslice perCollision_phos = aod::phoscluster::emeventId; + + Preslice perCollision_electron = aod::emprimaryelectron::emeventId; + Partition positrons = o2::aod::emprimaryelectron::sign > int8_t(0) && static_cast(dileptoncuts.cfg_min_pt_track) < o2::aod::track::pt&& nabs(o2::aod::track::eta) < static_cast(dileptoncuts.cfg_max_eta_track) && static_cast(dileptoncuts.cfg_min_TPCNsigmaEl) < o2::aod::pidtpc::tpcNSigmaEl&& o2::aod::pidtpc::tpcNSigmaEl < static_cast(dileptoncuts.cfg_max_TPCNsigmaEl); + Partition electrons = o2::aod::emprimaryelectron::sign < int8_t(0) && static_cast(dileptoncuts.cfg_min_pt_track) < o2::aod::track::pt && nabs(o2::aod::track::eta) < static_cast(dileptoncuts.cfg_max_eta_track) && static_cast(dileptoncuts.cfg_min_TPCNsigmaEl) < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < static_cast(dileptoncuts.cfg_max_TPCNsigmaEl); + + template + void runTruePairing(TCollisions const& collisions, + TPhotons1 const& photons1, TPhotons2 const& photons2, + TSubInfos1 const&, TSubInfos2 const&, + TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, + TCut1 const& cut1, TCut2 const& cut2, + TMCCollisions const&, TMCParticles const& mcparticles) + { + for (const auto& collision : collisions) { + initCCDB(collision); + + if (eventcuts.onlyKeepWeightedEvents && std::fabs(collision.weight() - 1.f) < 1e-10) { + continue; + } + + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision, collision.weight()); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision, collision.weight()); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 12.0, collision.weight()); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 12.0, collision.weight()); // accepted + + if constexpr (pairtype == PairType::kPCMDalitzEE) { + auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); + auto positrons_per_collision = positrons->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + auto electrons_per_collision = electrons->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + + for (const auto& g1 : photons1_per_collision) { + if (!cut1.template IsSelected(g1)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v_gamma(g1.pt(), g1.eta(), g1.phi(), 0.f); + fRegistry.fill(HIST("Photon/candidate/hPt"), v_gamma.Pt(), collision.weight()); + fRegistry.fill(HIST("Photon/candidate/hEtaPhi"), v_gamma.Phi() > 0 ? v_gamma.Phi() : v_gamma.Phi() + 2 * M_PI, v_gamma.Eta(), collision.weight()); + + auto pos1 = g1.template posTrack_as(); + auto ele1 = g1.template negTrack_as(); + auto pos1mc = pos1.template emmcparticle_as(); + auto ele1mc = ele1.template emmcparticle_as(); + int photonid1 = FindCommonMotherFrom2Prongs(pos1mc, ele1mc, -11, 11, 22, mcparticles); + if (photonid1 < 0) { + continue; + } + auto g1mc = mcparticles.iteratorAt(photonid1); + + if (cfgRequireTrueAssociation && (g1mc.emmceventId() != collision.emmceventId())) { + continue; + } + + if (g1mc.isPhysicalPrimary() || g1mc.producedByGenerator()) { + fRegistry.fill(HIST("Photon/primary/hPt"), v_gamma.Pt(), collision.weight()); + fRegistry.fill(HIST("Photon/primary/hEtaPhi"), v_gamma.Phi() > 0 ? v_gamma.Phi() : v_gamma.Phi() + 2 * M_PI, v_gamma.Eta(), collision.weight()); + if (g1mc.has_mothers()) { + auto mp = g1mc.template mothers_first_as(); + if (std::abs(mp.pdgCode()) == 111) { + fRegistry.fill(HIST("Photon/fromPi0/hPt"), v_gamma.Pt(), collision.weight()); + fRegistry.fill(HIST("Photon/fromPi0/hEtaPhi"), v_gamma.Phi() > 0 ? v_gamma.Phi() : v_gamma.Phi() + 2 * M_PI, v_gamma.Eta(), collision.weight()); + } + } + } else if (IsFromWD(g1mc.template emmcevent_as(), g1mc, mcparticles) > 0) { + int motherid_strhad = IsFromWD(g1mc.template emmcevent_as(), g1mc, mcparticles); + auto str_had = mcparticles.iteratorAt(motherid_strhad); + float weight = 1.f; + if (std::abs(str_had.pdgCode()) == 310 && f1fd_k0s_to_pi0 != nullptr) { + weight = f1fd_k0s_to_pi0->Eval(str_had.pt()); + } + fRegistry.fill(HIST("Photon/fromWD/hPt"), v_gamma.Pt(), collision.weight() * weight); + fRegistry.fill(HIST("Photon/fromWD/hEtaPhi"), v_gamma.Phi() > 0 ? v_gamma.Phi() : v_gamma.Phi() + 2 * M_PI, v_gamma.Eta(), collision.weight() * weight); + } else { + fRegistry.fill(HIST("Photon/fromHS/hPt"), v_gamma.Pt(), collision.weight()); + fRegistry.fill(HIST("Photon/fromHS/hEtaPhi"), v_gamma.Phi() > 0 ? v_gamma.Phi() : v_gamma.Phi() + 2 * M_PI, v_gamma.Eta(), collision.weight()); + } + + for (const auto& [pos2, ele2] : combinations(CombinationsFullIndexPolicy(positrons_per_collision, electrons_per_collision))) { // ULS + if (pos2.trackId() == ele2.trackId()) { // this is protection against pairing identical 2 tracks. + continue; + } + if (pos1.trackId() == pos2.trackId() || ele1.trackId() == ele2.trackId()) { + continue; + } + + if (!cut2.template IsSelectedTrack(pos2, collision) || !cut2.template IsSelectedTrack(ele2, collision)) { + continue; + } + + if (!cut2.IsSelectedPair(pos2, ele2, d_bz)) { + continue; + } + + auto pos2mc = mcparticles.iteratorAt(pos2.emmcparticleId()); + auto ele2mc = mcparticles.iteratorAt(ele2.emmcparticleId()); + int pi0id = FindCommonMotherFrom3Prongs(g1mc, pos2mc, ele2mc, 22, -11, 11, 111, mcparticles); + if (pi0id < 0) { + continue; + } + auto pi0mc = mcparticles.iteratorAt(pi0id); + if (cfgRequireTrueAssociation && (pi0mc.emmceventId() != collision.emmceventId())) { + continue; + } + ROOT::Math::PtEtaPhiMVector v_pos(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v_ele(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector veeg = v_gamma + v_pos + v_ele; + + if (pi0mc.isPhysicalPrimary() || pi0mc.producedByGenerator()) { + fRegistry.fill(HIST("Pair/primary/hMvsPt"), veeg.M(), v_gamma.Pt(), collision.weight()); + } else if (IsFromWD(pi0mc.template emmcevent_as(), pi0mc, mcparticles) > 0) { + int motherid_strhad = IsFromWD(pi0mc.template emmcevent_as(), pi0mc, mcparticles); + auto str_had = mcparticles.iteratorAt(motherid_strhad); + float weight = 1.f; + if (std::abs(str_had.pdgCode()) == 310 && f1fd_k0s_to_pi0 != nullptr) { + weight = f1fd_k0s_to_pi0->Eval(str_had.pt()); + } + fRegistry.fill(HIST("Pair/fromWD/hMvsPt"), veeg.M(), v_gamma.Pt(), collision.weight() * weight); + } else { + fRegistry.fill(HIST("Pair/fromHS/hMvsPt"), veeg.M(), v_gamma.Pt(), collision.weight()); + } + + } // end of dielectron loop + } // end of pcm loop + } else { // PCM-EMC, PCM-PHOS. Not supported. + auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); + auto photons2_per_collision = photons2.sliceBy(perCollision2, collision.globalIndex()); + + for (const auto& [g1, g2] : combinations(CombinationsFullIndexPolicy(photons1_per_collision, photons2_per_collision))) { + if (!cut1.template IsSelected(g1) || !cut2.template IsSelected(g2)) { + continue; + } + // ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); + // ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); + // ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + // if (pi0id > 0) { + // auto pi0mc = mcparticles.iteratorAt(pi0id); + // o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, v12, pi0mc, mcparticles, mccollisions, f1fd_k0s_to_pi0, collision.weight()); + // } + } // end of pairing loop + } // end of pairing in same event + } // end of collision loop + } + + Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + using FilteredMyCollisions = soa::Filtered; + + void processAnalysis(FilteredMyCollisions const& collisions, MyMCCollisions const& mccollisions, aod::EMMCParticles const& mcparticles, Types const&... args) + { + if constexpr (pairtype == PairType::kPCMDalitzEE) { + auto v0photons = std::get<0>(std::tie(args...)); + auto v0legs = std::get<1>(std::tie(args...)); + auto emprimaryelectrons = std::get<2>(std::tie(args...)); + // LOGF(info, "electrons.size() = %d, positrons.size() = %d", electrons.size(), positrons.size()); + runTruePairing(collisions, v0photons, emprimaryelectrons, v0legs, emprimaryelectrons, perCollision_pcm, perCollision_electron, fV0PhotonCut, fDileptonCut, mccollisions, mcparticles); + } + // else if constexpr (pairtype == PairType::kPCMEMC) { + // auto v0photons = std::get<0>(std::tie(args...)); + // auto v0legs = std::get<1>(std::tie(args...)); + // auto emcclusters = std::get<2>(std::tie(args...)); + // auto emcmatchedtracks = std::get<3>(std::tie(args...)); + // runPairing(collisions, v0photons, emcclusters, v0legs, nullptr, perCollision_pcm, perCollision_emc, fV0PhotonCut, fEMCCut, emcmatchedtracks, nullptr); + // } else if constexpr (pairtype == PairType::kPCMPHOS) { + // auto v0photons = std::get<0>(std::tie(args...)); + // auto v0legs = std::get<1>(std::tie(args...)); + // auto phosclusters = std::get<2>(std::tie(args...)); + // runPairing(collisions, v0photons, phosclusters, v0legs, nullptr, perCollision_pcm, perCollision_phos, fV0PhotonCut, fPHOSCut, nullptr, nullptr); + // } + } + PROCESS_SWITCH(TaggingPi0MC, processAnalysis, "process pair analysis", false); + + void processDummy(MyCollisions const&) {} + PROCESS_SWITCH(TaggingPi0MC, processDummy, "Dummy function", true); +}; +#endif // PWGEM_PHOTONMESON_CORE_TAGGINGPI0MC_H_ diff --git a/PWGEM/PhotonMeson/Core/V0PhotonCut.cxx b/PWGEM/PhotonMeson/Core/V0PhotonCut.cxx index cb4f71465fe..07d805fa291 100644 --- a/PWGEM/PhotonMeson/Core/V0PhotonCut.cxx +++ b/PWGEM/PhotonMeson/Core/V0PhotonCut.cxx @@ -10,16 +10,17 @@ // or submit itself to any jurisdiction. // -// Class for track selection +// Class for v0 photon selection // +#include +#include + #include "Framework/Logger.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" ClassImp(V0PhotonCut); -const char* V0PhotonCut::mCutNames[static_cast(V0PhotonCut::V0PhotonCuts::kNCuts)] = {"Mee", "V0PtRange", "V0EtaRange", "AP", " PsiPair", "PhivPair", "Rxy", "CosPA", "PCA", "RZLine", "OnWwireIB", "OnWwireOB", "TrackPtRange", "TrackEtaRange", "TPCNCls", "TPCCrossedRows", "TPCCrossedRowsOverNCls", "TPCChi2NDF", "TPCNsigmaEl", "TPCNsigmaPi", "DCAxy", "DCAz", "ITSNCls", "ITSChi2NDF", "IsWithinBeamPipe", "RequireITSTPC", "RequireITSonly", "RequireTPConly", "RequireTPCTRD", "RequireTPCTOF", "RequireTPCTRDTOF"}; - const std::pair> V0PhotonCut::its_ib_Requirement = {0, {0, 1, 2}}; // no hit on 3 ITS ib layers. const std::pair> V0PhotonCut::its_ob_Requirement = {4, {3, 4, 5, 6}}; // all hits on 4 ITS ob layers. const std::pair> V0PhotonCut::its_ob_Requirement_ITSTPC = {2, {3, 4, 5, 6}}; // at least 2 hits on 4 ITS ob layers. @@ -81,6 +82,11 @@ void V0PhotonCut::SetMaxPCA(float max) mMaxPCA = max; LOG(info) << "V0 Photon Cut, set max distance between 2 legs: " << mMaxPCA; } +void V0PhotonCut::SetMaxChi2KF(float max) +{ + mMaxChi2KF = max; + LOG(info) << "V0 Photon Cut, set max chi2/ndf with KF: " << mMaxChi2KF; +} void V0PhotonCut::SetMaxMarginZ(float max) { mMaxMarginZ = max; @@ -140,6 +146,11 @@ void V0PhotonCut::SetMinNCrossedRowsOverFindableClustersTPC(float minNCrossedRow mMinNCrossedRowsOverFindableClustersTPC = minNCrossedRowsOverFindableClustersTPC; LOG(info) << "V0 Photon Cut, set min N crossed rows over findable clusters TPC: " << mMinNCrossedRowsOverFindableClustersTPC; } +void V0PhotonCut::SetMaxFracSharedClustersTPC(float max) +{ + mMaxFracSharedClustersTPC = max; + LOG(info) << "V0 Photon Cut, set max fraction of shared clusters in TPC: " << mMaxFracSharedClustersTPC; +} void V0PhotonCut::SetChi2PerClusterTPC(float min, float max) { mMinChi2PerClusterTPC = min; @@ -218,43 +229,14 @@ void V0PhotonCut::SetRequireTPCTOF(bool flag) LOG(info) << "V0 Photon Cut, require TPC-TOF track: " << mRequireTPCTOF; } -void V0PhotonCut::SetRequireTPCTRDTOF(bool flag) +void V0PhotonCut::SetDisableITSonly(bool flag) { - mRequireTPCTRDTOF = flag; - LOG(info) << "V0 Photon Cut, require TPC-TOF track: " << mRequireTPCTRDTOF; + mDisableITSonly = flag; + LOG(info) << "V0 Photon Cut, disable ITS only track: " << mDisableITSonly; } -void V0PhotonCut::print() const -{ - LOG(info) << "V0 Photon Cut:"; - for (int i = 0; i < static_cast(V0PhotonCuts::kNCuts); i++) { - switch (static_cast(i)) { - case V0PhotonCuts::kTrackPtRange: - LOG(info) << mCutNames[i] << " in [" << mMinTrackPt << ", " << mMaxTrackPt << "]"; - break; - case V0PhotonCuts::kTrackEtaRange: - LOG(info) << mCutNames[i] << " in [" << mMinTrackEta << ", " << mMaxTrackEta << "]"; - break; - case V0PhotonCuts::kTPCNCls: - LOG(info) << mCutNames[i] << " > " << mMinNClustersTPC; - break; - case V0PhotonCuts::kTPCCrossedRows: - LOG(info) << mCutNames[i] << " > " << mMinNCrossedRowsTPC; - break; - case V0PhotonCuts::kTPCCrossedRowsOverNCls: - LOG(info) << mCutNames[i] << " > " << mMinNCrossedRowsOverFindableClustersTPC; - break; - case V0PhotonCuts::kTPCChi2NDF: - LOG(info) << mCutNames[i] << " < " << mMaxChi2PerClusterTPC; - break; - case V0PhotonCuts::kDCAxy: - LOG(info) << mCutNames[i] << " < " << mMaxDcaXY; - break; - case V0PhotonCuts::kDCAz: - LOG(info) << mCutNames[i] << " < " << mMaxDcaZ; - break; - default: - LOG(fatal) << "Cut unknown!"; - } - } +void V0PhotonCut::SetDisableTPConly(bool flag) +{ + mDisableTPConly = flag; + LOG(info) << "V0 Photon Cut, disable TPC only track: " << mDisableTPConly; } diff --git a/PWGEM/PhotonMeson/Core/V0PhotonCut.h b/PWGEM/PhotonMeson/Core/V0PhotonCut.h index 6673884c9cc..d6064ab8786 100644 --- a/PWGEM/PhotonMeson/Core/V0PhotonCut.h +++ b/PWGEM/PhotonMeson/Core/V0PhotonCut.h @@ -45,6 +45,7 @@ class V0PhotonCut : public TNamed kRxy, kCosPA, kPCA, + kChi2KF, kRZLine, kOnWwireIB, kOnWwireOB, @@ -54,6 +55,7 @@ class V0PhotonCut : public TNamed kTPCNCls, kTPCCrossedRows, kTPCCrossedRowsOverNCls, + kTPCFracSharedClusters, kTPCChi2NDF, kTPCNsigmaEl, kTPCNsigmaPi, @@ -61,19 +63,16 @@ class V0PhotonCut : public TNamed kDCAz, kITSNCls, kITSChi2NDF, - kITSCluserSize, + kITSClusterSize, kIsWithinBeamPipe, kRequireITSTPC, kRequireITSonly, kRequireTPConly, kRequireTPCTRD, kRequireTPCTOF, - kRequireTPCTRDTOF, kNCuts }; - static const char* mCutNames[static_cast(V0PhotonCuts::kNCuts)]; - template bool IsSelected(TV0 const& v0) const { @@ -104,6 +103,9 @@ class V0PhotonCut : public TNamed if (!IsSelectedV0(v0, V0PhotonCuts::kPCA)) { return false; } + if (!IsSelectedV0(v0, V0PhotonCuts::kChi2KF)) { + return false; + } if (!IsSelectedV0(v0, V0PhotonCuts::kRZLine)) { return false; } @@ -144,20 +146,28 @@ class V0PhotonCut : public TNamed if (!track.hasITS() && !track.hasTPC()) { // track has to be ITSonly or TPConly or ITS-TPC return false; } - - auto hits_ib = std::count_if(its_ib_Requirement.second.begin(), its_ib_Requirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); - auto hits_ob = std::count_if(its_ob_Requirement.second.begin(), its_ob_Requirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); - bool its_ob_only = (hits_ib <= its_ib_Requirement.first) && (hits_ob >= its_ob_Requirement.first); - if (isITSonlyTrack(track) && !its_ob_only) { // ITSonly tracks should not have any ITSib hits. + if (mDisableITSonly && isITSonlyTrack(track)) { return false; } - - auto hits_ob_itstpc = std::count_if(its_ob_Requirement_ITSTPC.second.begin(), its_ob_Requirement_ITSTPC.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); - bool its_ob_only_itstpc = (hits_ib <= its_ib_Requirement.first) && (hits_ob_itstpc >= its_ob_Requirement_ITSTPC.first); - if (isITSTPCTrack(track) && !its_ob_only_itstpc) { // ITSTPC tracks should not have any ITSib hits. + if (mDisableTPConly && isTPConlyTrack(track)) { return false; } + if (mRejectITSib) { + auto hits_ib = std::count_if(its_ib_Requirement.second.begin(), its_ib_Requirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); + auto hits_ob = std::count_if(its_ob_Requirement.second.begin(), its_ob_Requirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); + bool its_ob_only = (hits_ib <= its_ib_Requirement.first) && (hits_ob >= its_ob_Requirement.first); + if (isITSonlyTrack(track) && !its_ob_only) { // ITSonly tracks should not have any ITSib hits. + return false; + } + + auto hits_ob_itstpc = std::count_if(its_ob_Requirement_ITSTPC.second.begin(), its_ob_Requirement_ITSTPC.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); + bool its_ob_only_itstpc = (hits_ib <= its_ib_Requirement.first) && (hits_ob_itstpc >= its_ob_Requirement_ITSTPC.first); + if (isITSTPCTrack(track) && !its_ob_only_itstpc) { // ITSTPC tracks should not have any ITSib hits. + return false; + } + } + if (track.hasITS() && !CheckITSCuts(track)) { return false; } @@ -187,9 +197,6 @@ class V0PhotonCut : public TNamed if (mRequireTPCTOF && !IsSelectedTrack(track, V0PhotonCuts::kRequireTPCTOF)) { return false; } - if (mRequireTPCTRDTOF && !IsSelectedTrack(track, V0PhotonCuts::kRequireTPCTRDTOF)) { - return false; - } } return true; } @@ -203,7 +210,7 @@ class V0PhotonCut : public TNamed if (!IsSelectedTrack(track, V0PhotonCuts::kITSChi2NDF)) { return false; } - if (!IsSelectedTrack(track, V0PhotonCuts::kITSCluserSize)) { + if (!IsSelectedTrack(track, V0PhotonCuts::kITSClusterSize)) { return false; } return true; @@ -221,6 +228,9 @@ class V0PhotonCut : public TNamed if (!IsSelectedTrack(track, V0PhotonCuts::kTPCCrossedRowsOverNCls)) { return false; } + if (!IsSelectedTrack(track, V0PhotonCuts::kTPCFracSharedClusters)) { + return false; + } if (!IsSelectedTrack(track, V0PhotonCuts::kTPCChi2NDF)) { return false; } @@ -233,31 +243,6 @@ class V0PhotonCut : public TNamed return true; } - template - uint32_t IsSelectedMask(T const& track) const - { - uint32_t flag = 0; - - auto setFlag = [&](const V0PhotonCuts& cut) { - if (IsSelectedTrack(track, cut)) { - flag |= 1UL << static_cast(cut); - } - }; - - setFlag(V0PhotonCuts::kV0PtRange); - setFlag(V0PhotonCuts::kV0EtaRange); - setFlag(V0PhotonCuts::kTrackPtRange); - setFlag(V0PhotonCuts::kTrackEtaRange); - setFlag(V0PhotonCuts::kTPCNCls); - setFlag(V0PhotonCuts::kTPCCrossedRows); - setFlag(V0PhotonCuts::kTPCCrossedRowsOverNCls); - setFlag(V0PhotonCuts::kTPCChi2NDF); - setFlag(V0PhotonCuts::kDCAxy); - setFlag(V0PhotonCuts::kDCAz); - - return flag; - } - template bool IsSelectedV0(T const& v0, const V0PhotonCuts& cut) const { @@ -298,8 +283,11 @@ class V0PhotonCut : public TNamed case V0PhotonCuts::kPCA: return v0.pca() <= mMaxPCA; + case V0PhotonCuts::kChi2KF: + return v0.chiSquareNDF() <= mMaxChi2KF; + case V0PhotonCuts::kRZLine: - return v0.v0radius() > abs(v0.vz()) * std::tan(2 * std::atan(std::exp(-mMaxV0Eta))) - mMaxMarginZ; + return v0.v0radius() > std::fabs(v0.vz()) * std::tan(2 * std::atan(std::exp(-mMaxV0Eta))) - mMaxMarginZ; case V0PhotonCuts::kOnWwireIB: { const float margin_xy = 1.0; // cm @@ -308,9 +296,9 @@ class V0PhotonCut : public TNamed // const float rxy_max = 14.846; // cm // const float z_min = -17.56; // cm // const float z_max = +31.15; // cm - float x = abs(v0.vx()); // cm, measured secondary vertex of gamma->ee - float y = v0.vy(); // cm, measured secondary vertex of gamma->ee - float z = v0.vz(); // cm, measured secondary vertex of gamma->ee + float x = std::fabs(v0.vx()); // cm, measured secondary vertex of gamma->ee + float y = v0.vy(); // cm, measured secondary vertex of gamma->ee + float z = v0.vz(); // cm, measured secondary vertex of gamma->ee float rxy = sqrt(x * x + y * y); if (rxy < 7.0 || 14.0 < rxy) { @@ -322,7 +310,7 @@ class V0PhotonCut : public TNamed return false; } - float dxy = abs(1.0 * y - x * std::tan(-8.52 * TMath::DegToRad())) / sqrt(pow(1.0, 2) + pow(std::tan(-8.52 * TMath::DegToRad()), 2)); + float dxy = std::fabs(1.0 * y - x * std::tan(-8.52 * TMath::DegToRad())) / sqrt(pow(1.0, 2) + pow(std::tan(-8.52 * TMath::DegToRad()), 2)); return !(dxy > margin_xy); } case V0PhotonCuts::kOnWwireOB: { @@ -369,6 +357,9 @@ class V0PhotonCut : public TNamed case V0PhotonCuts::kTPCCrossedRowsOverNCls: return track.tpcCrossedRowsOverFindableCls() >= mMinNCrossedRowsOverFindableClustersTPC; + case V0PhotonCuts::kTPCFracSharedClusters: + return track.tpcFractionSharedCls() <= mMaxFracSharedClustersTPC; + case V0PhotonCuts::kTPCChi2NDF: return mMinChi2PerClusterTPC < track.tpcChi2NCl() && track.tpcChi2NCl() < mMaxChi2PerClusterTPC; @@ -379,10 +370,10 @@ class V0PhotonCut : public TNamed return track.tpcNSigmaPi() >= mMinTPCNsigmaPi && track.tpcNSigmaPi() <= mMaxTPCNsigmaPi; case V0PhotonCuts::kDCAxy: - return abs(track.dcaXY()) <= ((mMaxDcaXYPtDep) ? mMaxDcaXYPtDep(track.pt()) : mMaxDcaXY); + return std::fabs(track.dcaXY()) <= ((mMaxDcaXYPtDep) ? mMaxDcaXYPtDep(track.pt()) : mMaxDcaXY); case V0PhotonCuts::kDCAz: - return abs(track.dcaZ()) <= mMaxDcaZ; + return std::fabs(track.dcaZ()) <= mMaxDcaZ; case V0PhotonCuts::kITSNCls: return mMinNClustersITS <= track.itsNCls() && track.itsNCls() <= mMaxNClustersITS; @@ -390,7 +381,7 @@ class V0PhotonCut : public TNamed case V0PhotonCuts::kITSChi2NDF: return mMinChi2PerClusterITS < track.itsChi2NCl() && track.itsChi2NCl() < mMaxChi2PerClusterITS; - case V0PhotonCuts::kITSCluserSize: { + case V0PhotonCuts::kITSClusterSize: { if (!isITSonlyTrack(track)) { return true; } @@ -405,13 +396,13 @@ class V0PhotonCut : public TNamed // if (abs(track.y()) > abs(track.x() * TMath::Tan(10.f * TMath::DegToRad())) + 15.f) { // return false; // } - if (track.x() < 0.1 && abs(track.y()) > 15.f) { + if (track.x() < 0.1 && std::fabs(track.y()) > 15.f) { return false; } - if (track.x() > 82.9 && abs(track.y()) > abs(track.x() * std::tan(10.f * TMath::DegToRad())) + 5.f) { + if (track.x() > 82.9 && std::fabs(track.y()) > std::fabs(track.x() * std::tan(10.f * TMath::DegToRad())) + 5.f) { return false; } - if (track.x() > 82.9 && abs(track.y()) < 15.0 && abs(abs(track.z()) - 44.5) < 2.5) { + if (track.x() > 82.9 && std::fabs(track.y()) < 15.0 && abs(abs(track.z()) - 44.5) < 2.5) { return false; } return true; @@ -434,9 +425,6 @@ class V0PhotonCut : public TNamed case V0PhotonCuts::kRequireTPCTOF: return isTPCTOFTrack(track); - case V0PhotonCuts::kRequireTPCTRDTOF: - return isTPCTRDTOFTrack(track); - default: return false; } @@ -452,6 +440,7 @@ class V0PhotonCut : public TNamed void SetRxyRange(float min = 0.f, float max = 180.f); void SetMinCosPA(float min = 0.95); void SetMaxPCA(float max = 2.f); + void SetMaxChi2KF(float max = 1e+10); void SetMaxMarginZ(float max = 7.f); void SetMaxMeePsiPairDep(std::function psiDepCut); void SetOnWwireIB(bool flag = false); @@ -463,6 +452,7 @@ class V0PhotonCut : public TNamed void SetMinNClustersTPC(int minNClustersTPC); void SetMinNCrossedRowsTPC(int minNCrossedRowsTPC); void SetMinNCrossedRowsOverFindableClustersTPC(float minNCrossedRowsOverFindableClustersTPC); + void SetMaxFracSharedClustersTPC(float max); void SetChi2PerClusterTPC(float min, float max); void SetNClustersITS(int min, int max); void SetChi2PerClusterITS(float min, float max); @@ -480,10 +470,8 @@ class V0PhotonCut : public TNamed void SetRequireTPConly(bool flag); void SetRequireTPCTRD(bool flag); void SetRequireTPCTOF(bool flag); - void SetRequireTPCTRDTOF(bool flag); - - /// @brief Print the track selection - void print() const; + void SetDisableITSonly(bool flag); + void SetDisableTPConly(bool flag); private: static const std::pair> its_ib_Requirement; @@ -499,6 +487,7 @@ class V0PhotonCut : public TNamed float mMinRxy{0.f}, mMaxRxy{180.f}; float mMinCosPA{0.95}; float mMaxPCA{2.f}; + float mMaxChi2KF{1e+10}; float mMaxMarginZ{7.f}; std::function mMaxMeePsiPairDep{}; // max mee as a function of psipair bool mIsOnWwireIB{false}; @@ -518,6 +507,7 @@ class V0PhotonCut : public TNamed int mMinNCrossedRowsTPC{0}; // min number of crossed rows in TPC float mMinChi2PerClusterTPC{-1e10f}, mMaxChi2PerClusterTPC{1e10f}; // max tpc fit chi2 per TPC cluster float mMinNCrossedRowsOverFindableClustersTPC{0.f}; // min ratio crossed rows / findable clusters + float mMaxFracSharedClustersTPC{999.f}; // max ratio shared clusters / clusters in TPC int mMinNClustersITS{0}, mMaxNClustersITS{7}; // range in number of ITS clusters float mMinChi2PerClusterITS{-1e10f}, mMaxChi2PerClusterITS{1e10f}; // max its fit chi2 per ITS cluster float mMinMeanClusterSizeITS{-1e10f}, mMaxMeanClusterSizeITS{1e10f}; // max x cos(Lmabda) @@ -531,7 +521,8 @@ class V0PhotonCut : public TNamed bool mRequireTPConly{false}; bool mRequireTPCTRD{false}; bool mRequireTPCTOF{false}; - bool mRequireTPCTRDTOF{false}; + bool mDisableITSonly{false}; + bool mDisableTPConly{false}; ClassDef(V0PhotonCut, 1); }; diff --git a/PWGEM/PhotonMeson/DataModel/bcWiseTables.h b/PWGEM/PhotonMeson/DataModel/bcWiseTables.h new file mode 100644 index 00000000000..082b65b48fa --- /dev/null +++ b/PWGEM/PhotonMeson/DataModel/bcWiseTables.h @@ -0,0 +1,146 @@ +// 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 bcWiseTables.h +/// +/// \brief This header provides the table definitions to store very lightweight EMCal clusters per BC +/// +/// \author Nicolas Strangmann (nicolas.strangmann@cern.ch) - Goethe University Frankfurt +/// + +#ifndef PWGEM_PHOTONMESON_DATAMODEL_BCWISETABLES_H_ +#define PWGEM_PHOTONMESON_DATAMODEL_BCWISETABLES_H_ + +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ + +namespace emdownscaling +{ +enum Observables { + kDefinition, + kEnergy, + kEta, + kPhi, + kNCells, + kM02, + kTime, + kFT0MCent, + kZVtx, + kFT0Amp, + kCellAmpSum, + kpT, + nObservables +}; + +// Values in tables are stored in downscaled format to save disk space +const float downscalingFactors[nObservables]{ + 1E0, // Cluster definition + 1E3, // Cluster energy + 1E4, // Cluster eta + 1E4, // Cluster phi + 1E0, // Number of cells + 1E4, // M02 + 1E2, // Cluster time + 2E0, // FT0M centrality + 1E3, // Z-vertex position + 1E0, // FT0M amplitude + 1E0, // Cell energy + 1E3}; // MC pi0 pt +} // namespace emdownscaling + +namespace bcwisebc +{ +DECLARE_SOA_COLUMN(HasFT0, hasFT0, bool); //! has_foundFT0() +DECLARE_SOA_COLUMN(HasTVX, hasTVX, bool); //! has the TVX trigger flag +DECLARE_SOA_COLUMN(HaskTVXinEMC, haskTVXinEMC, bool); //! kTVXinEMC +DECLARE_SOA_COLUMN(HasEMCCell, hasEMCCell, bool); //! at least one EMCal cell in the BC +DECLARE_SOA_COLUMN(HasNoTFROFBorder, hasNoTFROFBorder, bool); //! not in the TF border or ITS ROF border region +DECLARE_SOA_COLUMN(StoredFT0MAmplitude, storedFT0MAmplitude, unsigned int); //! ft0a+c amplitude +DECLARE_SOA_COLUMN(StoredEMCalnCells, storedEMCalnCells, unsigned int); //! number of emcal cells +DECLARE_SOA_COLUMN(StoredEMCalCellEnergy, storedEMCalCellEnergy, float); //! sum of energy in emcal cells +} // namespace bcwisebc +DECLARE_SOA_TABLE(BCWiseBCs, "AOD", "BCWISEBCS", //! table of bc wise centrality estimation and event selection input + o2::soa::Index<>, bcwisebc::HasFT0, bcwisebc::HasTVX, bcwisebc::HaskTVXinEMC, bcwisebc::HasEMCCell, bcwisebc::HasNoTFROFBorder, + bcwisebc::StoredFT0MAmplitude, bcwisebc::StoredEMCalnCells, bcwisebc::StoredEMCalCellEnergy); + +DECLARE_SOA_INDEX_COLUMN(BCWiseBC, bcWiseBC); //! bunch crossing ID used as index + +namespace bcwisecollision +{ +DECLARE_SOA_COLUMN(StoredCentrality, storedCentrality, uint8_t); //! FT0M centrality (0-100) (x2) +DECLARE_SOA_COLUMN(StoredZVtx, storedZVtx, int16_t); //! Z-vertex position (x1000) + +DECLARE_SOA_DYNAMIC_COLUMN(Centrality, centrality, [](uint8_t storedcentrality) -> float { return storedcentrality / emdownscaling::downscalingFactors[emdownscaling::kFT0MCent]; }); //! Centrality (0-100) +DECLARE_SOA_DYNAMIC_COLUMN(ZVtx, zVtx, [](uint8_t storedzvtx) -> float { return storedzvtx / emdownscaling::downscalingFactors[emdownscaling::kZVtx]; }); //! Centrality (0-100) +} // namespace bcwisecollision +DECLARE_SOA_TABLE(BCWiseCollisions, "AOD", "BCWISECOLLS", //! table of skimmed EMCal clusters + o2::soa::Index<>, BCWiseBCId, bcwisecollision::StoredCentrality, bcwisecollision::StoredZVtx, + bcwisecollision::Centrality, bcwisecollision::ZVtx); + +namespace bcwisecluster +{ +DECLARE_SOA_COLUMN(StoredDefinition, storedDefinition, uint8_t); //! cluster definition, see EMCALClusterDefinition.h +DECLARE_SOA_COLUMN(StoredE, storedE, uint16_t); //! cluster energy (1 MeV -> Maximum cluster energy of ~65 GeV) +DECLARE_SOA_COLUMN(StoredEta, storedEta, int16_t); //! cluster pseudorapidity (x10,000) +DECLARE_SOA_COLUMN(StoredPhi, storedPhi, uint16_t); //! cluster azimuthal angle (x10 000) from 0 to 2pi +DECLARE_SOA_COLUMN(StoredNCells, storedNCells, uint8_t); //! number of cells in cluster +DECLARE_SOA_COLUMN(StoredM02, storedM02, uint16_t); //! shower shape long axis (x10 000) +DECLARE_SOA_COLUMN(StoredTime, storedTime, int16_t); //! cluster time (10 ps resolution) +DECLARE_SOA_COLUMN(StoredIsExotic, storedIsExotic, bool); //! flag to mark cluster as exotic + +DECLARE_SOA_DYNAMIC_COLUMN(Definition, definition, [](uint8_t storedDefinition) -> uint8_t { return storedDefinition; }); //! cluster definition, see EMCALClusterDefinition.h +DECLARE_SOA_DYNAMIC_COLUMN(E, e, [](uint16_t storedE) -> float { return storedE / emdownscaling::downscalingFactors[emdownscaling::kEnergy]; }); //! cluster energy (GeV) +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, [](int16_t storedEta) -> float { return storedEta / emdownscaling::downscalingFactors[emdownscaling::kEta]; }); //! cluster pseudorapidity +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, [](uint16_t storedPhi) -> float { return storedPhi / emdownscaling::downscalingFactors[emdownscaling::kPhi]; }); //! cluster azimuthal angle (0 to 2pi) +DECLARE_SOA_DYNAMIC_COLUMN(NCells, nCells, [](uint16_t storedNCells) -> uint16_t { return storedNCells; }); //! number of cells in cluster +DECLARE_SOA_DYNAMIC_COLUMN(M02, m02, [](uint16_t storedM02) -> float { return storedM02 / emdownscaling::downscalingFactors[emdownscaling::kM02]; }); //! shower shape long axis +DECLARE_SOA_DYNAMIC_COLUMN(Time, time, [](int16_t storedTime) -> float { return storedTime / emdownscaling::downscalingFactors[emdownscaling::kTime]; }); //! cluster time (ns) +DECLARE_SOA_DYNAMIC_COLUMN(IsExotic, isExotic, [](bool storedIsExotic) -> bool { return storedIsExotic; }); //! flag to mark cluster as exotic + +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float storedE, float storedEta) -> float { return storedE / emdownscaling::downscalingFactors[emdownscaling::kEnergy] / std::cosh(storedEta / emdownscaling::downscalingFactors[emdownscaling::kEta]); }); //! cluster pt, assuming m=0 (photons) +} // namespace bcwisecluster + +DECLARE_SOA_TABLE(BCWiseClusters, "AOD", "BCWISECLUSTERS", //! table of skimmed EMCal clusters + o2::soa::Index<>, BCWiseBCId, bcwisecluster::StoredDefinition, bcwisecluster::StoredE, bcwisecluster::StoredEta, bcwisecluster::StoredPhi, bcwisecluster::StoredNCells, bcwisecluster::StoredM02, bcwisecluster::StoredTime, bcwisecluster::StoredIsExotic, + bcwisecluster::Definition, bcwisecluster::E, bcwisecluster::Eta, bcwisecluster::Phi, bcwisecluster::NCells, bcwisecluster::M02, bcwisecluster::Time, bcwisecluster::IsExotic, + bcwisecluster::Pt); + +namespace bcwisemcpi0s +{ +DECLARE_SOA_COLUMN(ParticleIdPi0, particleIdPi0, int); //! ID of the pi0 in the MC stack +DECLARE_SOA_COLUMN(StoredPt, storedPt, uint16_t); //! Transverse momentum of generated pi0 (10 MeV) +DECLARE_SOA_COLUMN(IsAccepted, isAccepted, bool); //! Both decay photons are within the EMCal acceptance +DECLARE_SOA_COLUMN(IsPrimary, isPrimary, bool); //! mcParticle.isPhysicalPrimary() || mcParticle.producedByGenerator() +DECLARE_SOA_COLUMN(IsFromWD, isFromWD, bool); //! Pi0 from a weak decay according to pwgem::photonmeson::utils::mcutil::IsFromWD + +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](uint16_t storedpt) -> float { return storedpt / emdownscaling::downscalingFactors[emdownscaling::kpT]; }); //! pT of pi0 (GeV) +} // namespace bcwisemcpi0s + +DECLARE_SOA_TABLE(BCWiseMCPi0s, "AOD", "BCWISEMCPI0S", //! table of pi0s on MC level + o2::soa::Index<>, BCWiseBCId, bcwisemcpi0s::ParticleIdPi0, bcwisemcpi0s::StoredPt, bcwisemcpi0s::IsAccepted, bcwisemcpi0s::IsPrimary, bcwisemcpi0s::IsFromWD, + bcwisemcpi0s::Pt); + +namespace bcwisemccluster +{ +DECLARE_SOA_COLUMN(StoredE, storedE, uint16_t); //! energy of cluster inducing particle (1 MeV precision) + +DECLARE_SOA_DYNAMIC_COLUMN(E, e, [](uint16_t storedE) -> float { return storedE / emdownscaling::downscalingFactors[emdownscaling::kEnergy]; }); //! energy of cluster inducing particle (GeV) +} // namespace bcwisemccluster + +DECLARE_SOA_TABLE(BCWiseMCClusters, "AOD", "BCWISEMCCLS", //! table of MC information for clusters -> To be joined with the cluster table + o2::soa::Index<>, BCWiseBCId, bcwisemccluster::StoredE, bcwisemcpi0s::ParticleIdPi0, + bcwisemccluster::E); + +} // namespace o2::aod + +#endif // PWGEM_PHOTONMESON_DATAMODEL_BCWISETABLES_H_ diff --git a/PWGEM/PhotonMeson/DataModel/gammaTables.h b/PWGEM/PhotonMeson/DataModel/gammaTables.h index f7076ee715a..0abbc3bfe76 100644 --- a/PWGEM/PhotonMeson/DataModel/gammaTables.h +++ b/PWGEM/PhotonMeson/DataModel/gammaTables.h @@ -13,14 +13,10 @@ #include #include "Common/Core/RecoDecay.h" -#include "Framework/AnalysisDataModel.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/CaloClusters.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/Qvectors.h" + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + #include "PWGJE/DataModel/EMCALClusters.h" #ifndef PWGEM_PHOTONMESON_DATAMODEL_GAMMATABLES_H_ @@ -29,168 +25,53 @@ namespace o2::aod { -namespace emevent -{ -DECLARE_SOA_COLUMN(CollisionId, collisionId, int); -DECLARE_SOA_COLUMN(NgammaPCM, ngpcm, int); -DECLARE_SOA_COLUMN(NgammaPHOS, ngphos, int); -DECLARE_SOA_COLUMN(NgammaEMC, ngemc, int); -DECLARE_SOA_COLUMN(NeeULS, neeuls, int); -DECLARE_SOA_COLUMN(NeeLSpp, neelspp, int); -DECLARE_SOA_COLUMN(NeeLSmm, neelsmm, int); -DECLARE_SOA_COLUMN(NmumuULS, nmumuuls, int); -DECLARE_SOA_COLUMN(NmumuLSpp, nmumulspp, int); -DECLARE_SOA_COLUMN(NmumuLSmm, nmumulsmm, int); -DECLARE_SOA_COLUMN(NcollsPerBC, ncollsPerBC, int); -DECLARE_SOA_COLUMN(Bz, bz, float); //! kG -DECLARE_SOA_COLUMN(Q2xFT0M, q2xft0m, float); //! Qx for 2nd harmonics in FT0M (i.e. positive eta) -DECLARE_SOA_COLUMN(Q2yFT0M, q2yft0m, float); //! Qy for 2nd harmonics in FT0M (i.e. positive eta) -DECLARE_SOA_COLUMN(Q2xFT0A, q2xft0a, float); //! Qx for 2nd harmonics in FT0A (i.e. positive eta) -DECLARE_SOA_COLUMN(Q2yFT0A, q2yft0a, float); //! Qy for 2nd harmonics in FT0A (i.e. positive eta) -DECLARE_SOA_COLUMN(Q2xFT0C, q2xft0c, float); //! Qx for 2nd harmonics in FT0C (i.e. negative eta) -DECLARE_SOA_COLUMN(Q2yFT0C, q2yft0c, float); //! Qy for 2nd harmonics in FT0C (i.e. negative eta) -DECLARE_SOA_COLUMN(Q2xFV0A, q2xfv0a, float); //! Qx for 2nd harmonics in FV0A (i.e. positive eta) -DECLARE_SOA_COLUMN(Q2yFV0A, q2yfv0a, float); //! Qy for 2nd harmonics in FV0A (i.e. positive eta) -DECLARE_SOA_COLUMN(Q2xBPos, q2xbpos, float); //! Qx for 2nd harmonics in Barrel positive eta region -DECLARE_SOA_COLUMN(Q2yBPos, q2ybpos, float); //! Qy for 2nd harmonics in Barrel positive eta region -DECLARE_SOA_COLUMN(Q2xBNeg, q2xbneg, float); //! Qx for 2nd harmonics in Barrel negative eta region -DECLARE_SOA_COLUMN(Q2yBNeg, q2ybneg, float); //! Qy for 2nd harmonics in Barrel negative eta region -DECLARE_SOA_COLUMN(Q3xFT0M, q3xft0m, float); //! Qx for 3rd harmonics in FT0M (i.e. positive eta) -DECLARE_SOA_COLUMN(Q3yFT0M, q3yft0m, float); //! Qy for 3rd harmonics in FT0M (i.e. positive eta) -DECLARE_SOA_COLUMN(Q3xFT0A, q3xft0a, float); //! Qx for 3rd harmonics in FT0A (i.e. positive eta) -DECLARE_SOA_COLUMN(Q3yFT0A, q3yft0a, float); //! Qy for 3rd harmonics in FT0A (i.e. positive eta) -DECLARE_SOA_COLUMN(Q3xFT0C, q3xft0c, float); //! Qx for 3rd harmonics in FT0C (i.e. negative eta) -DECLARE_SOA_COLUMN(Q3yFT0C, q3yft0c, float); //! Qy for 3rd harmonics in FT0C (i.e. negative eta) -DECLARE_SOA_COLUMN(Q3xFV0A, q3xfv0a, float); //! Qx for 3rd harmonics in FV0A (i.e. positive eta) -DECLARE_SOA_COLUMN(Q3yFV0A, q3yfv0a, float); //! Qy for 3rd harmonics in FV0A (i.e. positive eta) -DECLARE_SOA_COLUMN(Q3xBPos, q3xbpos, float); //! Qx for 3rd harmonics in Barrel positive eta region -DECLARE_SOA_COLUMN(Q3yBPos, q3ybpos, float); //! Qy for 3rd harmonics in Barrel positive eta region -DECLARE_SOA_COLUMN(Q3xBNeg, q3xbneg, float); //! Qx for 3rd harmonics in Barrel negative eta region -DECLARE_SOA_COLUMN(Q3yBNeg, q3ybneg, float); //! Qy for 3rd harmonics in Barrel negative eta region - -DECLARE_SOA_DYNAMIC_COLUMN(EP2FT0M, ep2ft0m, [](float q2x, float q2y) -> float { return std::atan2(q2y, q2x) / 2.0; }); -DECLARE_SOA_DYNAMIC_COLUMN(EP2FT0A, ep2ft0a, [](float q2x, float q2y) -> float { return std::atan2(q2y, q2x) / 2.0; }); -DECLARE_SOA_DYNAMIC_COLUMN(EP2FT0C, ep2ft0c, [](float q2x, float q2y) -> float { return std::atan2(q2y, q2x) / 2.0; }); -DECLARE_SOA_DYNAMIC_COLUMN(EP2FV0A, ep2fv0a, [](float q2x, float q2y) -> float { return std::atan2(q2y, q2x) / 2.0; }); -DECLARE_SOA_DYNAMIC_COLUMN(EP2BPos, ep2bpos, [](float q2x, float q2y) -> float { return std::atan2(q2y, q2x) / 2.0; }); -DECLARE_SOA_DYNAMIC_COLUMN(EP2BNeg, ep2bneg, [](float q2x, float q2y) -> float { return std::atan2(q2y, q2x) / 2.0; }); -} // namespace emevent -DECLARE_SOA_TABLE(EMEvents, "AOD", "EMEVENT", //! Main event information table - o2::soa::Index<>, emevent::CollisionId, bc::GlobalBC, bc::RunNumber, evsel::Sel8, evsel::Alias, evsel::Selection, emevent::NcollsPerBC, - collision::PosX, collision::PosY, collision::PosZ, - collision::NumContrib, collision::CollisionTime, collision::CollisionTimeRes); -using EMEvent = EMEvents::iterator; - -DECLARE_SOA_TABLE(EMEventsBz, "AOD", "EMEVENTBZ", emevent::Bz); // joinable to EMEvents -using EMEventBz = EMEventsBz::iterator; - -DECLARE_SOA_TABLE(EMEventsMult, "AOD", "EMEVENTMULT", //! event multiplicity table, joinable to EMEvents - mult::MultFV0A, mult::MultFV0C, mult::MultFT0A, mult::MultFT0C, - mult::MultFDDA, mult::MultFDDC, mult::MultZNA, mult::MultZNC, - mult::MultTPC, mult::MultTracklets, mult::MultNTracksPV, mult::MultNTracksPVeta1, mult::MultNTracksPVetaHalf, - mult::IsInelGt0, mult::IsInelGt1); -using EMEventMult = EMEventsMult::iterator; - -DECLARE_SOA_TABLE(EMEventsCent, "AOD", "EMEVENTCENT", //! event centrality table, joinable to EMEvents - cent::CentFT0M, cent::CentFT0A, cent::CentFT0C, cent::CentNTPV); -using EMEventCent = EMEventsCent::iterator; - -DECLARE_SOA_TABLE(EMEventsQvec, "AOD", "EMEVENTQVEC", //! event q vector table, joinable to EMEvents - emevent::Q2xFT0M, emevent::Q2yFT0M, emevent::Q2xFT0A, emevent::Q2yFT0A, emevent::Q2xFT0C, emevent::Q2yFT0C, emevent::Q2xFV0A, emevent::Q2yFV0A, - emevent::Q2xBPos, emevent::Q2yBPos, emevent::Q2xBNeg, emevent::Q2yBNeg, - emevent::Q3xFT0M, emevent::Q3yFT0M, emevent::Q3xFT0A, emevent::Q3yFT0A, emevent::Q3xFT0C, emevent::Q3yFT0C, emevent::Q3xFV0A, emevent::Q3yFV0A, - emevent::Q3xBPos, emevent::Q3yBPos, emevent::Q3xBNeg, emevent::Q3yBNeg, - - // Dynamic columns - emevent::EP2FT0M, - emevent::EP2FT0A, - emevent::EP2FT0C, - emevent::EP2FV0A, - emevent::EP2BPos, - emevent::EP2BNeg); -using EMEventQvec = EMEventsQvec::iterator; - -DECLARE_SOA_TABLE(EMEventsNgPCM, "AOD", "EMEVENTNGPCM", emevent::NgammaPCM); // joinable to EMEvents -using EMEventNgPCM = EMEventsNgPCM::iterator; - -DECLARE_SOA_TABLE(EMEventsNgPHOS, "AOD", "EMEVENTNGPHOS", emevent::NgammaPHOS); // joinable to EMEvents -using EMEventNgPHOS = EMEventsNgPHOS::iterator; - -DECLARE_SOA_TABLE(EMEventsNgEMC, "AOD", "EMEVENTNGEMC", emevent::NgammaEMC); // joinable to EMEvents -using EMEventNgEMC = EMEventsNgEMC::iterator; - -DECLARE_SOA_TABLE(EMEventsNee, "AOD", "EMEVENTNEE", emevent::NeeULS, emevent::NeeLSpp, emevent::NeeLSmm); // joinable to EMEvents -using EMEventNee = EMEventsNee::iterator; - -DECLARE_SOA_TABLE(EMEventsNmumu, "AOD", "EMEVENTNMUMU", emevent::NmumuULS, emevent::NmumuLSpp, emevent::NmumuLSmm); // joinable to EMEvents -using EMEventNmumu = EMEventsNmumu::iterator; - -namespace emmcevent -{ -DECLARE_SOA_COLUMN(McCollisionId, mcCollisionId, int); -} - -DECLARE_SOA_TABLE(EMMCEvents, "AOD", "EMMCEVENT", //! MC event information table - o2::soa::Index<>, emmcevent::McCollisionId, mccollision::GeneratorsID, - mccollision::PosX, mccollision::PosY, mccollision::PosZ, - mccollision::T, mccollision::ImpactParameter, - - // dynamic column - mccollision::GetGeneratorId, - mccollision::GetSubGeneratorId, - mccollision::GetSourceId); - -using EMMCEvent = EMMCEvents::iterator; - -namespace emmceventlabel +namespace emmcbinnedgen { -DECLARE_SOA_INDEX_COLUMN(EMMCEvent, emmcevent); //! MC collision -DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); //! Bit mask to indicate collision mismatches (bit ON means mismatch). Bit 15: indicates negative label -} // namespace emmceventlabel - -DECLARE_SOA_TABLE(EMMCEventLabels, "AOD", "EMMCEVENTLABEL", //! Table joined to the EMEvents table containing the MC index - emmceventlabel::EMMCEventId, emmceventlabel::McMask); -using EMMCEventLabel = EMMCEventLabels::iterator; - -namespace emmcparticle -{ -DECLARE_SOA_INDEX_COLUMN(EMMCEvent, emmcevent); -DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(Mothers, mothers); //! Mother tracks (possible empty) array. Iterate over mcParticle.mothers_as()) -DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(Daughters, daughters); //! Daughter tracks (possibly empty) array. Check for non-zero with mcParticle.has_daughters(). Iterate over mcParticle.daughters_as()) -DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float px, float py) -> float { return RecoDecay::sqrtSumOfSquares(px, py); }); -DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, [](float px, float py, float pz) -> float { return RecoDecay::eta(std::array{px, py, pz}); }); -DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, [](float px, float py) -> float { return RecoDecay::phi(px, py); }); -DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float px, float py, float pz) -> float { return RecoDecay::sqrtSumOfSquares(px, py, pz); }); -DECLARE_SOA_DYNAMIC_COLUMN(Y, y, //! Particle rapidity - [](float pz, float e) -> float { - if ((e - pz) > static_cast(1e-7)) { - return 0.5f * std::log((e + pz) / (e - pz)); - } else { - return -999.0f; - } - }); -} // namespace emmcparticle - -// This table contains all MC truth tracks (both v0 and calos) -DECLARE_SOA_TABLE_FULL(EMMCParticles, "EMMCParticles", "AOD", "EMMCPARTICLE", //! MC track information (on disk) - o2::soa::Index<>, emmcparticle::EMMCEventId, - mcparticle::PdgCode, mcparticle::Flags, - emmcparticle::MothersIds, emmcparticle::DaughtersIds, - mcparticle::Px, mcparticle::Py, mcparticle::Pz, mcparticle::E, - mcparticle::Vx, mcparticle::Vy, mcparticle::Vz, mcparticle::Vt, - - // dynamic column - emmcparticle::Pt, - emmcparticle::Eta, - emmcparticle::Phi, - - emmcparticle::P, - emmcparticle::Y, - mcparticle::ProducedByGenerator, - mcparticle::FromBackgroundEvent, - mcparticle::IsPhysicalPrimary); - -using EMMCParticle = EMMCParticles::iterator; +DECLARE_SOA_COLUMN(GeneratedGamma, generatedGamma, std::vector); //! gamma binned generated data +DECLARE_SOA_COLUMN(GeneratedPi0, generatedPi0, std::vector); //! pi0 binned generated data +DECLARE_SOA_COLUMN(GeneratedEta, generatedEta, std::vector); //! eta binned generated data +DECLARE_SOA_COLUMN(GeneratedOmega, generatedOmega, std::vector); //! omega(782) binned generated data +DECLARE_SOA_COLUMN(GeneratedPhi, generatedPhi, std::vector); //! phi(1020) binned generated data +DECLARE_SOA_COLUMN(GeneratedChargedPion, generatedChargedPion, std::vector); //! charged pion binned generated data +DECLARE_SOA_COLUMN(GeneratedChargedKaon, generatedChargedKaon, std::vector); //! charged kaon binned generated data +DECLARE_SOA_COLUMN(GeneratedK0S, generatedK0S, std::vector); //! K0S binned generated data +DECLARE_SOA_COLUMN(GeneratedLambda, generatedLambda, std::vector); //! Lambda binned generated data + +// DECLARE_SOA_COLUMN(GeneratedPi0_Acc_gg, generatedPi0_acc_gg, std::vector); //! pi0 -> gg binned generated data +// DECLARE_SOA_COLUMN(GeneratedPi0_Acc_eeg, generatedPi0_acc_eeg, std::vector); //! pi0 -> eeg binned generated data +// DECLARE_SOA_COLUMN(GeneratedEta_Acc_gg, generatedEta_acc_gg, std::vector); //! eta -> gg binned generated data +// DECLARE_SOA_COLUMN(GeneratedEta_Acc_eeg, generatedEta_acc_eeg, std::vector); //! eta -> eeg binned generated data +// DECLARE_SOA_COLUMN(GeneratedEta_Acc_mumug, generatedEta_acc_mumug, std::vector); //! eta -> mumug binned generated data +// DECLARE_SOA_COLUMN(GeneratedOmega_Acc_ee, generatedOmega_acc_ee, std::vector); //! omega(782) -> ee binned generated data +// DECLARE_SOA_COLUMN(GeneratedPhi_Acc_ee, generatedPhi_acc_ee, std::vector); //! phi(1020) -> ee binned generated data +// DECLARE_SOA_COLUMN(GeneratedOmega_Acc_mumu, generatedOmega_acc_mumu, std::vector); //! omega(782) -> mumu binned generated data +// DECLARE_SOA_COLUMN(GeneratedPhi_Acc_mumu, generatedPhi_acc_mumu, std::vector); //! phi(1020) -> mumu binned generated data +} // namespace emmcbinnedgen + +DECLARE_SOA_TABLE(BinnedGenPts, "AOD", "BINNEDGENPT", // To be joined with EMMCEvents table at analysis level. + emmcbinnedgen::GeneratedGamma, + emmcbinnedgen::GeneratedPi0, + emmcbinnedgen::GeneratedEta + // emmcbinnedgen::GeneratedOmega, + // emmcbinnedgen::GeneratedPhi, + // emmcbinnedgen::GeneratedChargedPion, + // emmcbinnedgen::GeneratedChargedKaon, + // emmcbinnedgen::GeneratedK0S, + // emmcbinnedgen::GeneratedLambda +); +using BinnedGenPt = BinnedGenPts::iterator; + +// DECLARE_SOA_TABLE(BinnedGenPtAccs, "AOD", "BINNEDGENPTACC", // To be joined with EMMCEvents table at analysis level. +// emmcbinnedgen::GeneratedPi0_Acc_gg, +// emmcbinnedgen::GeneratedPi0_Acc_eeg, +// emmcbinnedgen::GeneratedEta_Acc_gg, +// emmcbinnedgen::GeneratedEta_Acc_eeg, +// emmcbinnedgen::GeneratedEta_Acc_mumug, +// emmcbinnedgen::GeneratedOmega_Acc_ee, +// emmcbinnedgen::GeneratedPhi_Acc_ee) +//// emmcbinnedgen::GeneratedOmega_Acc_mumu, +//// emmcbinnedgen::GeneratedPhi_Acc_mumu); +// using BinnedGenPtAcc = BinnedGenPtAccs::iterator; namespace v0legmclabel { @@ -203,28 +84,6 @@ DECLARE_SOA_TABLE(V0LegMCLabels, "AOD", "V0LEGMCLABEL", //! v0legmclabel::EMMCParticleId, v0legmclabel::McMask); using V0LegMCLabel = V0LegMCLabels::iterator; -namespace emprimaryelectronmclabel -{ -DECLARE_SOA_INDEX_COLUMN(EMMCParticle, emmcparticle); //! -DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); -} // namespace emprimaryelectronmclabel - -// NOTE: MC labels. This table has one entry for each reconstructed track (joinable with EMPrimaryElectrons table) -DECLARE_SOA_TABLE(EMPrimaryElectronMCLabels, "AOD", "EMPRMELMCLABEL", //! - emprimaryelectronmclabel::EMMCParticleId, emprimaryelectronmclabel::McMask); -using EMPrimaryElectronMCLabel = EMPrimaryElectronMCLabels::iterator; - -namespace emprimarymuonmclabel -{ -DECLARE_SOA_INDEX_COLUMN(EMMCParticle, emmcparticle); //! -DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); -} // namespace emprimarymuonmclabel - -// NOTE: MC labels. This table has one entry for each reconstructed track (joinable with EMPrimaryMuons table) -DECLARE_SOA_TABLE(EMPrimaryMuonMCLabels, "AOD", "EMPRMMUMCLABEL", //! - emprimarymuonmclabel::EMMCParticleId, emprimarymuonmclabel::McMask); -using EMPrimaryMuonMCLabel = EMPrimaryMuonMCLabels::iterator; - // * EMC cluster mc label tables: // 1. EMCALMCClusters in EMCalClusters.h: Vectors of global mc particle ids and energy fractions of the cluster // 2. EMCClusterMCLabels: Vector of global mc particle ids @@ -254,6 +113,7 @@ namespace v0leg DECLARE_SOA_COLUMN(CollisionId, collisionId, int); //! DECLARE_SOA_COLUMN(TrackId, trackId, int); //! DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! +DECLARE_SOA_COLUMN(IsMoved, isMoved, bool); //! moved by drift manager. relevant to TPConly tracks DECLARE_SOA_COLUMN(Px, px, float); //! Px at SV DECLARE_SOA_COLUMN(Py, py, float); //! Py at SV DECLARE_SOA_COLUMN(Pz, pz, float); //! Pz at SV @@ -311,7 +171,7 @@ DECLARE_SOA_TABLE(V0Legs, "AOD", "V0LEG", //! o2::soa::Index<>, v0leg::CollisionId, v0leg::TrackId, v0leg::Sign, v0leg::Px, v0leg::Py, v0leg::Pz, track::DcaXY, track::DcaZ, - track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusCrossedRows, + track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusCrossedRows, track::TPCNClsShared, track::TPCChi2NCl, track::TPCInnerParam, track::TPCSignal, pidtpc::TPCNSigmaEl, pidtpc::TPCNSigmaPi, track::ITSClusterSizes, track::ITSChi2NCl, track::DetectorMap, @@ -326,6 +186,7 @@ DECLARE_SOA_TABLE(V0Legs, "AOD", "V0LEG", //! track::TPCNClsCrossedRows, track::TPCCrossedRowsOverFindableCls, track::TPCFoundOverFindableCls, + track::TPCFractionSharedCls, track::v001::ITSClusterMap, track::v001::ITSNCls, track::v001::ITSNClsInnerBarrel, track::HasITS, track::HasTPC, track::HasTRD, track::HasTOF, @@ -336,10 +197,24 @@ DECLARE_SOA_TABLE(V0Legs, "AOD", "V0LEG", //! // iterators using V0Leg = V0Legs::iterator; +namespace emevent +{ +DECLARE_SOA_COLUMN(NgPCM, ngpcm, int); +DECLARE_SOA_COLUMN(Weight, weight, float); //! Weight of the event (e.g. for JJ MCs). Set to 1 for data and non-weighted MCs. +} // namespace emevent + +DECLARE_SOA_TABLE(EMEventsNgPCM, "AOD", "EMEVENTNGPCM", emevent::NgPCM); // joinable to EMEvents or aod::Collisions +using EMEventNgPCM = EMEventsNgPCM::iterator; + +DECLARE_SOA_TABLE(EMEventsWeight, "AOD", "EMEVENTWEIGHT", //! table contanint the weight for eache event (for JJ MCs), joinable to EMEvents + emevent::Weight); +using EMEventWeight = EMEventsWeight::iterator; + namespace v0photonkf { DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! DECLARE_SOA_COLUMN(CollisionId, collisionId, int); //! +DECLARE_SOA_COLUMN(V0Id, v0Id, int); //! DECLARE_SOA_INDEX_COLUMN_FULL(PosTrack, posTrack, int, V0Legs, "_Pos"); //! DECLARE_SOA_INDEX_COLUMN_FULL(NegTrack, negTrack, int, V0Legs, "_Neg"); //! DECLARE_SOA_COLUMN(Vx, vx, float); //! secondary vertex x @@ -352,10 +227,19 @@ DECLARE_SOA_COLUMN(MGamma, mGamma, float); //! inva DECLARE_SOA_COLUMN(DCAxyToPV, dcaXYtopv, float); //! DCAxy of V0 to PV DECLARE_SOA_COLUMN(DCAzToPV, dcaZtopv, float); //! DCAz of V0 to PV DECLARE_SOA_COLUMN(CosPA, cospa, float); //! +DECLARE_SOA_COLUMN(CosPAXY, cospaXY, float); //! +DECLARE_SOA_COLUMN(CosPARZ, cospaRZ, float); //! DECLARE_SOA_COLUMN(PCA, pca, float); //! DECLARE_SOA_COLUMN(Alpha, alpha, float); //! DECLARE_SOA_COLUMN(QtArm, qtarm, float); //! -DECLARE_SOA_COLUMN(ChiSquareNDF, chiSquareNDF, float); // Chi2 / NDF of the reconstructed V0 +DECLARE_SOA_COLUMN(ChiSquareNDF, chiSquareNDF, float); //! Chi2 / NDF of the reconstructed V0 +DECLARE_SOA_COLUMN(SigmaPx2, sigmaPx2, float); //! error^2 of px in covariant matrix +DECLARE_SOA_COLUMN(SigmaPy2, sigmaPy2, float); //! error^2 of py in covariant matrix +DECLARE_SOA_COLUMN(SigmaPz2, sigmaPz2, float); //! error^2 of pz in covariant matrix +DECLARE_SOA_COLUMN(SigmaPxPy, sigmaPxPy, float); //! error of px x py in covariant matrix +DECLARE_SOA_COLUMN(SigmaPyPz, sigmaPyPz, float); //! error of py x pz in covariant matrix +DECLARE_SOA_COLUMN(SigmaPzPx, sigmaPzPx, float); //! error of pz x px in covariant matrix +DECLARE_SOA_COLUMN(PrefilterBitDerived, pfbderived, uint16_t); //! DECLARE_SOA_DYNAMIC_COLUMN(E, e, [](float px, float py, float pz, float m = 0) -> float { return RecoDecay::sqrtSumOfSquares(px, py, pz, m); }); //! energy of v0 photn, mass to be given as argument when getter is called! DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float px, float py) -> float { return RecoDecay::sqrtSumOfSquares(px, py); }); @@ -365,12 +249,12 @@ DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float px, float py, float pz) -> float { ret DECLARE_SOA_DYNAMIC_COLUMN(V0Radius, v0radius, [](float vx, float vy) -> float { return RecoDecay::sqrtSumOfSquares(vx, vy); }); } // namespace v0photonkf DECLARE_SOA_TABLE(V0PhotonsKF, "AOD", "V0PHOTONKF", //! - o2::soa::Index<>, v0photonkf::CollisionId, v0photonkf::PosTrackId, v0photonkf::NegTrackId, + o2::soa::Index<>, v0photonkf::CollisionId, v0photonkf::V0Id, v0photonkf::PosTrackId, v0photonkf::NegTrackId, v0photonkf::Vx, v0photonkf::Vy, v0photonkf::Vz, v0photonkf::Px, v0photonkf::Py, v0photonkf::Pz, v0photonkf::MGamma, v0photonkf::DCAxyToPV, v0photonkf::DCAzToPV, - v0photonkf::CosPA, v0photonkf::PCA, + v0photonkf::CosPA, v0photonkf::CosPAXY, v0photonkf::CosPARZ, v0photonkf::PCA, v0photonkf::Alpha, v0photonkf::QtArm, v0photonkf::ChiSquareNDF, @@ -388,81 +272,24 @@ DECLARE_SOA_TABLE(V0KFEMEventIds, "AOD", "V0KFEMEVENTID", v0photonkf::EMEventId) // iterators using V0KFEMEventId = V0KFEMEventIds::iterator; -namespace emprimaryelectron -{ -DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! -DECLARE_SOA_COLUMN(CollisionId, collisionId, int); //! -DECLARE_SOA_COLUMN(TrackId, trackId, int); //! -DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! -DECLARE_SOA_COLUMN(PrefilterBit, pfb, uint8_t); //! -DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) -> float { return pt * std::cos(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float pt, float phi) -> float { return pt * std::sin(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float pt, float eta) -> float { return pt * std::sinh(eta); }); -DECLARE_SOA_DYNAMIC_COLUMN(DcaXYinSigma, dcaXYinSigma, [](float dcaXY, float cYY) -> float { return dcaXY / std::sqrt(cYY); }); -DECLARE_SOA_DYNAMIC_COLUMN(DcaZinSigma, dcaZinSigma, [](float dcaZ, float cZZ) -> float { return dcaZ / std::sqrt(cZZ); }); -DECLARE_SOA_DYNAMIC_COLUMN(Dca3DinSigma, dca3DinSigma, [](float dcaXY, float dcaZ, float cYY, float cZZ, float cZY) -> float { - float det = cYY * cZZ - cZY * cZY; // determinant - if (det < 0) { - return 999.f; - } else { - return std::sqrt(std::abs((dcaXY * dcaXY * cZZ + dcaZ * dcaZ * cYY - 2. * dcaXY * dcaZ * cZY) / det / 2.)); // dca 3d in sigma - } -}); -DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITS, meanClusterSizeITS, [](uint32_t itsClusterSizes) -> float { - int total_cluster_size = 0, nl = 0; - for (unsigned int layer = 0; layer < 7; layer++) { - int cluster_size_per_layer = (itsClusterSizes >> (layer * 4)) & 0xf; - if (cluster_size_per_layer > 0) { - nl++; - } - total_cluster_size += cluster_size_per_layer; - } - if (nl > 0) { - return static_cast(total_cluster_size) / static_cast(nl); - } else { - return 0; - } -}); -DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITSib, meanClusterSizeITSib, [](uint32_t itsClusterSizes) -> float { - int total_cluster_size = 0, nl = 0; - for (unsigned int layer = 0; layer < 3; layer++) { - int cluster_size_per_layer = (itsClusterSizes >> (layer * 4)) & 0xf; - if (cluster_size_per_layer > 0) { - nl++; - } - total_cluster_size += cluster_size_per_layer; - } - if (nl > 0) { - return static_cast(total_cluster_size) / static_cast(nl); - } else { - return 0; - } -}); -DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITSob, meanClusterSizeITSob, [](uint32_t itsClusterSizes) -> float { - int total_cluster_size = 0, nl = 0; - for (unsigned int layer = 3; layer < 7; layer++) { - int cluster_size_per_layer = (itsClusterSizes >> (layer * 4)) & 0xf; - if (cluster_size_per_layer > 0) { - nl++; - } - total_cluster_size += cluster_size_per_layer; - } - if (nl > 0) { - return static_cast(total_cluster_size) / static_cast(nl); - } else { - return 0; - } -}); -} // namespace emprimaryelectron -DECLARE_SOA_TABLE(EMPrimaryElectrons, "AOD", "EMPRIMARYEL", //! +DECLARE_SOA_TABLE(V0PhotonsKFCov, "AOD", "V0PHOTONKFCOV", //! To be joined with V0PhotonsKF table at analysis level. + v0photonkf::SigmaPx2, v0photonkf::SigmaPy2, v0photonkf::SigmaPz2, v0photonkf::SigmaPxPy, v0photonkf::SigmaPyPz, v0photonkf::SigmaPzPx); +// iterators +using V0PhotonKFCov = V0PhotonsKFCov::iterator; + +DECLARE_SOA_TABLE(V0PhotonsKFPrefilterBitDerived, "AOD", "V0PHOTONKFPFBPI0", v0photonkf::PrefilterBitDerived); // To be joined with V0PhotonsKF table at analysis level. +// iterators +using V0PhotonKFPrefilterBitDerived = V0PhotonsKFPrefilterBitDerived::iterator; + +DECLARE_SOA_TABLE(EMPrimaryElectronsFromDalitz, "AOD", "EMPRIMARYELDA", //! o2::soa::Index<>, emprimaryelectron::CollisionId, emprimaryelectron::TrackId, emprimaryelectron::Sign, - track::Pt, track::Eta, track::Phi, track::DcaXY, track::DcaZ, - track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusCrossedRows, + track::Pt, track::Eta, track::Phi, track::DcaXY, track::DcaZ, track::CYY, track::CZY, track::CZZ, + track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusCrossedRows, track::TPCNClsShared, track::TPCChi2NCl, track::TPCInnerParam, - track::TPCSignal, pidtpc::TPCNSigmaEl, pidtpc::TPCNSigmaMu, pidtpc::TPCNSigmaPi, pidtpc::TPCNSigmaKa, pidtpc::TPCNSigmaPr, - pidtofbeta::Beta, pidtof::TOFNSigmaEl, pidtof::TOFNSigmaMu, pidtof::TOFNSigmaPi, pidtof::TOFNSigmaKa, pidtof::TOFNSigmaPr, - track::ITSClusterSizes, track::ITSChi2NCl, track::DetectorMap, track::Tgl, track::CYY, track::CZZ, track::CZY, + track::TPCSignal, pidtpc::TPCNSigmaEl, pidtpc::TPCNSigmaPi, + pidtofbeta::Beta, pidtof::TOFNSigmaEl, pidtof::TOFNSigmaPi, + track::ITSClusterSizes, track::ITSChi2NCl, track::TOFChi2, track::DetectorMap, track::Tgl, // dynamic column track::TPCNClsFound, @@ -470,27 +297,19 @@ DECLARE_SOA_TABLE(EMPrimaryElectrons, "AOD", "EMPRIMARYEL", //! track::TPCCrossedRowsOverFindableCls, track::TPCFoundOverFindableCls, track::v001::ITSClusterMap, track::v001::ITSNCls, track::v001::ITSNClsInnerBarrel, + track::TPCFractionSharedCls, track::HasITS, track::HasTPC, track::HasTRD, track::HasTOF, + emprimaryelectron::Signed1Pt, + emprimaryelectron::P, emprimaryelectron::Px, emprimaryelectron::Py, emprimaryelectron::Pz, - emprimaryelectron::DcaXYinSigma, - emprimaryelectron::DcaZinSigma, - emprimaryelectron::Dca3DinSigma, emprimaryelectron::MeanClusterSizeITS, emprimaryelectron::MeanClusterSizeITSib, emprimaryelectron::MeanClusterSizeITSob); // iterators -using EMPrimaryElectron = EMPrimaryElectrons::iterator; - -DECLARE_SOA_TABLE(EMPrimaryElectronEMEventIds, "AOD", "PRMELEMEVENTID", emprimaryelectron::EMEventId); // To be joined with EMPrimaryElectrons table at analysis level. -// iterators -using EMPrimaryElectronEMEventId = EMPrimaryElectronEMEventIds::iterator; - -DECLARE_SOA_TABLE(EMPrimaryElectronsPrefilterBit, "AOD", "PRMELEPFB", emprimaryelectron::PrefilterBit); // To be joined with EMPrimaryElectrons table at analysis level. -// iterators -using EMPrimaryElectronPrefilterBit = EMPrimaryElectronsPrefilterBit::iterator; +using EMPrimaryElectronFromDalitz = EMPrimaryElectronsFromDalitz::iterator; namespace dalitzee { @@ -520,138 +339,6 @@ DECLARE_SOA_TABLE(DalitzEEEMEventIds, "AOD", "EEEMEVENTID", dalitzee::EMEventId) // iterators using DalitzEEEMEventId = DalitzEEEMEventIds::iterator; -namespace emprimarymuon -{ -DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! -DECLARE_SOA_COLUMN(CollisionId, collisionId, int); //! -DECLARE_SOA_COLUMN(TrackId, trackId, int); //! -DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! -DECLARE_SOA_COLUMN(PrefilterBit, pfb, uint8_t); //! -DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) -> float { return pt * std::cos(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float pt, float phi) -> float { return pt * std::sin(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float pt, float eta) -> float { return pt * std::sinh(eta); }); -DECLARE_SOA_DYNAMIC_COLUMN(DcaXYinSigma, dcaXYinSigma, [](float dcaXY, float cYY) -> float { return dcaXY / std::sqrt(cYY); }); -DECLARE_SOA_DYNAMIC_COLUMN(DcaZinSigma, dcaZinSigma, [](float dcaZ, float cZZ) -> float { return dcaZ / std::sqrt(cZZ); }); -DECLARE_SOA_DYNAMIC_COLUMN(Dca3DinSigma, dca3DinSigma, [](float dcaXY, float dcaZ, float cYY, float cZZ, float cZY) -> float { - float det = cYY * cZZ - cZY * cZY; // determinant - if (det < 0) { - return 999.f; - } else { - return std::sqrt(std::abs((dcaXY * dcaXY * cZZ + dcaZ * dcaZ * cYY - 2. * dcaXY * dcaZ * cZY) / det / 2.)); // dca 3d in sigma - } -}); -DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITS, meanClusterSizeITS, [](uint32_t itsClusterSizes) -> float { - int total_cluster_size = 0, nl = 0; - for (unsigned int layer = 0; layer < 7; layer++) { - int cluster_size_per_layer = (itsClusterSizes >> (layer * 4)) & 0xf; - if (cluster_size_per_layer > 0) { - nl++; - } - total_cluster_size += cluster_size_per_layer; - } - if (nl > 0) { - return static_cast(total_cluster_size) / static_cast(nl); - } else { - return 0; - } -}); -DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITSib, meanClusterSizeITSib, [](uint32_t itsClusterSizes) -> float { - int total_cluster_size = 0, nl = 0; - for (unsigned int layer = 0; layer < 3; layer++) { - int cluster_size_per_layer = (itsClusterSizes >> (layer * 4)) & 0xf; - if (cluster_size_per_layer > 0) { - nl++; - } - total_cluster_size += cluster_size_per_layer; - } - if (nl > 0) { - return static_cast(total_cluster_size) / static_cast(nl); - } else { - return 0; - } -}); -DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITSob, meanClusterSizeITSob, [](uint32_t itsClusterSizes) -> float { - int total_cluster_size = 0, nl = 0; - for (unsigned int layer = 3; layer < 7; layer++) { - int cluster_size_per_layer = (itsClusterSizes >> (layer * 4)) & 0xf; - if (cluster_size_per_layer > 0) { - nl++; - } - total_cluster_size += cluster_size_per_layer; - } - if (nl > 0) { - return static_cast(total_cluster_size) / static_cast(nl); - } else { - return 0; - } -}); -} // namespace emprimarymuon -DECLARE_SOA_TABLE(EMPrimaryMuons, "AOD", "EMPRIMARYMU", //! - o2::soa::Index<>, emprimarymuon::CollisionId, - emprimarymuon::TrackId, emprimarymuon::Sign, - track::Pt, track::Eta, track::Phi, track::DcaXY, track::DcaZ, - track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusCrossedRows, - track::TPCChi2NCl, track::TPCInnerParam, - track::TPCSignal, pidtpc::TPCNSigmaEl, pidtpc::TPCNSigmaMu, pidtpc::TPCNSigmaPi, pidtpc::TPCNSigmaKa, pidtpc::TPCNSigmaPr, - pidtofbeta::Beta, pidtof::TOFNSigmaEl, pidtof::TOFNSigmaMu, pidtof::TOFNSigmaPi, pidtof::TOFNSigmaKa, pidtof::TOFNSigmaPr, - track::ITSClusterSizes, track::ITSChi2NCl, track::DetectorMap, track::Tgl, track::CYY, track::CZZ, track::CZY, - - // dynamic column - track::TPCNClsFound, - track::TPCNClsCrossedRows, - track::TPCCrossedRowsOverFindableCls, - track::TPCFoundOverFindableCls, - track::v001::ITSClusterMap, track::v001::ITSNCls, track::v001::ITSNClsInnerBarrel, - track::HasITS, track::HasTPC, - track::HasTRD, track::HasTOF, - emprimarymuon::Px, - emprimarymuon::Py, - emprimarymuon::Pz, - emprimarymuon::DcaXYinSigma, - emprimarymuon::DcaZinSigma, - emprimarymuon::Dca3DinSigma, - emprimarymuon::MeanClusterSizeITS, - emprimarymuon::MeanClusterSizeITSib, - emprimarymuon::MeanClusterSizeITSob); -// iterators -using EMPrimaryMuon = EMPrimaryMuons::iterator; - -DECLARE_SOA_TABLE(EMPrimaryMuonEMEventIds, "AOD", "PRMMUEMEVENTID", emprimarymuon::EMEventId); // To be joined with EMPrimaryMuons table at analysis level. -// iterators -using EMPrimaryMuonEMEventId = EMPrimaryMuonEMEventIds::iterator; - -DECLARE_SOA_TABLE(EMPrimaryMuonsPrefilterBit, "AOD", "PRMMUPFB", emprimarymuon::PrefilterBit); // To be joined with EMPrimaryMuons table at analysis level. -// iterators -using EMPrimaryMuonPrefilterBit = EMPrimaryMuonsPrefilterBit::iterator; - -namespace dalitzmumu -{ -DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! -DECLARE_SOA_INDEX_COLUMN_FULL(PosTrack, posTrack, int, EMPrimaryMuons, "_Pos"); //! -DECLARE_SOA_INDEX_COLUMN_FULL(NegTrack, negTrack, int, EMPrimaryMuons, "_Neg"); //! -DECLARE_SOA_COLUMN(CollisionId, collisionId, int); //! -DECLARE_SOA_COLUMN(Pt, pt, float); -DECLARE_SOA_COLUMN(Eta, eta, float); -DECLARE_SOA_COLUMN(Phi, phi, float); -DECLARE_SOA_COLUMN(Mass, mass, float); -DECLARE_SOA_COLUMN(Rapidity, rapidity, float); -DECLARE_SOA_COLUMN(PhiV, phiv, float); -DECLARE_SOA_COLUMN(OpeningAngle, opangle, float); -DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! -DECLARE_SOA_DYNAMIC_COLUMN(Energy, e, [](float pt, float eta, float m) { return RecoDecay::sqrtSumOfSquares(pt * std::cosh(eta), m); }); // e = sqrt(p*p + m*m) -} // namespace dalitzmumu -DECLARE_SOA_TABLE(DalitzMuMus, "AOD", "DALITZMUMU", //! - o2::soa::Index<>, dalitzmumu::CollisionId, dalitzmumu::PosTrackId, dalitzmumu::NegTrackId, - dalitzmumu::Pt, dalitzmumu::Eta, dalitzmumu::Phi, dalitzmumu::Mass, dalitzmumu::Rapidity, - dalitzmumu::PhiV, dalitzmumu::OpeningAngle, dalitzmumu::Sign, - dalitzmumu::Energy); -// iterators -using DalitzMuMu = DalitzMuMus::iterator; - -DECLARE_SOA_TABLE(DalitzMuMuEMEventIds, "AOD", "MUMUEMEVENTID", dalitzmumu::EMEventId); // To be joined with DalitzMuMus table at analysis level. -// iterators -using DalitzMuMuEMEventId = DalitzMuMuEMEventIds::iterator; - namespace pwgem::photon::swtinfo { DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! @@ -753,8 +440,8 @@ DECLARE_SOA_TABLE(McGammasTrue, "AOD", "MCGATRUE", namespace skimmedcluster { -DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! collisionID used as index for matched clusters -DECLARE_SOA_INDEX_COLUMN(BC, bc); //! bunch crossing ID used as index for ambiguous clusters +DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! +DECLARE_SOA_COLUMN(CollisionId, collisionId, int); //! DECLARE_SOA_COLUMN(ID, id, int); //! cluster ID identifying cluster in event DECLARE_SOA_COLUMN(E, e, float); //! cluster energy (GeV) DECLARE_SOA_COLUMN(Eta, eta, float); //! cluster pseudorapidity (calculated using vertex) @@ -782,12 +469,9 @@ DECLARE_SOA_COLUMN(TrackPt, trackpt, std::vector); DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float e, float eta, float m = 0) -> float { return sqrt(e * e - m * m) / cosh(eta); }); //! cluster pt, mass to be given as argument when getter is called! } // namespace emccluster DECLARE_SOA_TABLE(SkimEMCClusters, "AOD", "SKIMEMCCLUSTERS", //! table of skimmed EMCal clusters - o2::soa::Index<>, skimmedcluster::CollisionId, skimmedcluster::BCId, skimmedcluster::E, emccluster::CoreEnergy, - skimmedcluster::Eta, skimmedcluster::Phi, skimmedcluster::M02, skimmedcluster::M20, skimmedcluster::NCells, skimmedcluster::Time, - emccluster::IsExotic, skimmedcluster::DistanceToBadChannel, skimmedcluster::NLM, emccluster::Definition, - emccluster::TrackIds, emccluster::TrackEta, emccluster::TrackPhi, emccluster::TrackP, emccluster::TrackPt, - // dynamic column - emccluster::Pt); + o2::soa::Index<>, skimmedcluster::CollisionId, emccluster::Definition, skimmedcluster::E, skimmedcluster::Eta, skimmedcluster::Phi, + skimmedcluster::M02, skimmedcluster::NCells, skimmedcluster::Time, emccluster::IsExotic, emccluster::TrackEta, + emccluster::TrackPhi, emccluster::TrackP, emccluster::TrackPt, emccluster::Pt); using SkimEMCCluster = SkimEMCClusters::iterator; DECLARE_SOA_TABLE(EMCEMEventIds, "AOD", "EMCEMEVENTID", emccluster::EMEventId); // To be joined with SkimEMCClusters table at analysis level. diff --git a/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt b/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt index a1aeb08d3ef..10266dcb8c2 100644 --- a/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt +++ b/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt @@ -21,7 +21,7 @@ o2physics_add_dpl_workflow(skimmer-gamma-conversion-truthonlymc o2physics_add_dpl_workflow(photon-conversion-builder SOURCES photonconversionbuilder.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DCAFitter O2Physics::AnalysisCore KFParticle::KFParticle + PUBLIC_LINK_LIBRARIES O2::Framework O2::DCAFitter O2Physics::AnalysisCore KFParticle::KFParticle O2Physics::TPCDriftManager COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(create-pcm @@ -29,13 +29,13 @@ o2physics_add_dpl_workflow(create-pcm PUBLIC_LINK_LIBRARIES O2::Framework O2::DCAFitter O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(create-emevent - SOURCES createEMEvent.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore +o2physics_add_dpl_workflow(create-emevent-photon + SOURCES createEMEventPhoton.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGJECore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(associate-mc-info - SOURCES associateMCinfo.cxx +o2physics_add_dpl_workflow(associate-mc-info-photon + SOURCES associateMCinfoPhoton.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) @@ -44,18 +44,18 @@ o2physics_add_dpl_workflow(skimmer-gamma-calo PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(bc-wise-cluster-skimmer + SOURCES bcWiseClusterSkimmer.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(skimmer-phos SOURCES skimmerPHOS.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::PHOSBase COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(skimmer-primary-electron - SOURCES skimmerPrimaryElectron.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(skimmer-primary-muon - SOURCES skimmerPrimaryMuon.cxx +o2physics_add_dpl_workflow(skimmer-primary-electron-from-dalitzee + SOURCES skimmerPrimaryElectronFromDalitzEE.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) @@ -64,11 +64,6 @@ o2physics_add_dpl_workflow(skimmer-dalitz-ee PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(skimmer-dalitz-mumu - SOURCES skimmerDalitzMuMu.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(gamma-table-producer SOURCES gammaSelection.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore diff --git a/PWGEM/PhotonMeson/TableProducer/associateMCinfo.cxx b/PWGEM/PhotonMeson/TableProducer/associateMCinfo.cxx deleted file mode 100644 index 78321d4dbf5..00000000000 --- a/PWGEM/PhotonMeson/TableProducer/associateMCinfo.cxx +++ /dev/null @@ -1,613 +0,0 @@ -// 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. -// -// ======================== -// -// This code produces reduced events for photon analyses. -// Please write to: daiki.sekihata@cern.ch - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::soa; -using namespace o2::aod::pwgem::mcutil; - -using MyCollisionsMC = soa::Join; -using TracksMC = soa::Join; -using MyEMCClusters = soa::Join; - -struct AssociateMCInfo { - enum SubSystem { - kPCM = 0x1, - kPHOS = 0x2, - kEMC = 0x4, - kDalitzEE = 0x8, - kDalitzMuMu = 0x10, - }; - - Produces mcevents; - Produces mceventlabels; - Produces emmcparticles; - Produces v0legmclabels; - Produces emprimaryelectronmclabels; - Produces emprimarymuonmclabels; - Produces ememcclustermclabels; - - Configurable max_rxy_gen{"max_rxy_gen", 100, "max rxy to store generated information"}; - Configurable max_Y_gen{"max_Y_gen", 0.9, "max rapidity Y to store generated information"}; - Configurable margin_z_gen{"margin_z_gen", 15.f, "margin for Z of true photon conversion point to store generated information"}; - - HistogramRegistry registry{"EMMCEvent"}; - - void init(o2::framework::InitContext&) - { - auto hEventCounter = registry.add("hEventCounter", "hEventCounter", kTH1I, {{6, 0.5f, 6.5f}}); - hEventCounter->GetXaxis()->SetBinLabel(1, "all"); - hEventCounter->GetXaxis()->SetBinLabel(2, "has mc collision"); - registry.add("PCM/hXY", "hRxy;X (cm);Y (cm)", kTH2F, {{400, -100, +100}, {400, -100, +100}}); - registry.add("PCM/hRZ", "hRxy;R (cm);Z (cm)", kTH2F, {{400, -100, +100}, {200, 0, +100}}); - registry.add("Generated/hPt_Pi0", "pT distribution of #pi^{0};p_{T} (GeV/c)", kTH1F, {{200, 0, 20}}); - registry.add("Generated/hPt_Eta", "pT distribution of #eta;p_{T} (GeV/c)", kTH1F, {{200, 0, 20}}); - registry.add("Generated/hPt_ChargedPion", "pT distribution of #pi^{#pm};p_{T} (GeV/c)", kTH1F, {{200, 0, 20}}); - registry.add("Generated/hPt_ChargedKaon", "pT distribution of K^{#pm};p_{T} (GeV/c)", kTH1F, {{200, 0, 20}}); - registry.add("Generated/hPt_K0S", "pT distribution of K0S;p_{T} (GeV/c)", kTH1F, {{200, 0, 20}}); - registry.add("Generated/hPt_Lambda", "pT distribution of #Lambda(#bar{#Lambda});p_{T} (GeV/c)", kTH1F, {{200, 0, 20}}); - } - - Preslice perMcCollision = aod::mcparticle::mcCollisionId; - Preslice perCollision_pcm = aod::v0photonkf::collisionId; - Preslice perCollision_el = aod::emprimaryelectron::collisionId; - Preslice perCollision_mu = aod::emprimarymuon::collisionId; - Preslice perCollision_phos = aod::skimmedcluster::collisionId; - Preslice perCollision_emc = aod::skimmedcluster::collisionId; - - template - void skimmingMC(MyCollisionsMC const& collisions, aod::BCs const&, aod::McCollisions const&, aod::McParticles const& mcTracks, TTracks const& o2tracks, TPCMs const& v0photons, TPCMLegs const& /*v0legs*/, TPHOSs const& /*phosclusters*/, TEMCs const& emcclusters, TEMPrimaryElectrons const& emprimaryelectrons, TEMPrimaryMuons const& emprimarymuons) - { - // temporary variables used for the indexing of the skimmed MC stack - std::map fNewLabels; - std::map fNewLabelsReversed; - // std::map fMCFlags; - std::map fEventIdx; - std::map fEventLabels; - int fCounters[2] = {0, 0}; //! [0] - particle counter, [1] - event counter - - for (auto& collision : collisions) { - registry.fill(HIST("hEventCounter"), 1); - - // TODO: investigate the collisions without corresponding mcCollision - if (!collision.has_mcCollision()) { - continue; - } - registry.fill(HIST("hEventCounter"), 2); - - auto mcCollision = collision.mcCollision(); - - // make an entry for this MC event only if it was not already added to the table - if (!(fEventLabels.find(mcCollision.globalIndex()) != fEventLabels.end())) { - mcevents(mcCollision.globalIndex(), mcCollision.generatorsID(), mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.t(), mcCollision.impactParameter()); - fEventLabels[mcCollision.globalIndex()] = fCounters[1]; - fCounters[1]++; - } - - mceventlabels(fEventLabels.find(mcCollision.globalIndex())->second, collision.mcMask()); - - // store mc particles - auto groupedMcTracks = mcTracks.sliceBy(perMcCollision, mcCollision.globalIndex()); - - for (auto& mctrack : groupedMcTracks) { // store necessary information for denominator of efficiency - if (mctrack.pt() < 1e-3 || abs(mctrack.vz()) > 250 || sqrt(pow(mctrack.vx(), 2) + pow(mctrack.vy(), 2)) > max_rxy_gen) { - continue; - } - int pdg = mctrack.pdgCode(); - if (abs(pdg) > 1e+9) { - continue; - } - - // fill basic histograms - if ((mctrack.isPhysicalPrimary() || mctrack.producedByGenerator()) && abs(mctrack.y()) < 0.5) { - switch (abs(pdg)) { - case 111: - registry.fill(HIST("Generated/hPt_Pi0"), mctrack.pt()); - break; - case 211: - registry.fill(HIST("Generated/hPt_ChargedPion"), mctrack.pt()); - break; - case 221: - registry.fill(HIST("Generated/hPt_Eta"), mctrack.pt()); - break; - case 310: - registry.fill(HIST("Generated/hPt_K0S"), mctrack.pt()); - break; - case 321: - registry.fill(HIST("Generated/hPt_ChargedKaon"), mctrack.pt()); - break; - case 3122: - registry.fill(HIST("Generated/hPt_Lambda"), mctrack.pt()); - break; - default: - break; - } - } - - // Note that pi0 from weak decay gives producedByGenerator() = false - if ( - abs(pdg) != 11 // electron - && (abs(pdg) != 13) // muon - && (abs(pdg) != 22) // photon - // light mesons - && (abs(pdg) != 111) // pi0 - && (abs(pdg) != 113) // rho(770) - // && (abs(pdg) != 211) // changed pion - && (abs(pdg) != 221) // eta - && (abs(pdg) != 223) // omega(782) - && (abs(pdg) != 331) // eta'(958) - && (abs(pdg) != 333) // phi(1020) - // charmonia - && (abs(pdg) != 443) // J/psi - && (abs(pdg) != 100443) // psi(2S) - // bottomonia - && (abs(pdg) != 553) // Upsilon(1S) - && (abs(pdg) != 100553) // Upsilon(2S) - && (abs(pdg) != 200553) // Upsilon(3S) - - // heavy flavor hadrons - && (std::to_string(abs(pdg))[std::to_string(abs(pdg)).length() - 3] != '4') // charmed mesons - && (std::to_string(abs(pdg))[std::to_string(abs(pdg)).length() - 3] != '5') // beauty mesons - && (std::to_string(abs(pdg))[std::to_string(abs(pdg)).length() - 4] != '4') // charmed baryons - && (std::to_string(abs(pdg))[std::to_string(abs(pdg)).length() - 4] != '5') // beauty baryons - - // strange hadrons - // && (abs(pdg) != 310) // K0S - // && (abs(pdg) != 130) // K0L - // && (abs(pdg) != 3122) // Lambda - ) { - continue; - } - // LOGF(info,"index = %d , mc track pdg = %d , producedByGenerator = %d , isPhysicalPrimary = %d", mctrack.index(), mctrack.pdgCode(), mctrack.producedByGenerator(), mctrack.isPhysicalPrimary()); - - if (!(mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { // neither physical primary nor producedByGenerator - if (abs(pdg) == 11) { // one more check for secondary electrons. i.e. gamma->ee - - if (sqrt(pow(mctrack.vx(), 2) + pow(mctrack.vy(), 2)) < abs(mctrack.vz()) * std::tan(2 * std::atan(std::exp(-max_Y_gen))) - margin_z_gen) { - continue; - } - - if (mctrack.has_mothers()) { - auto mp = mctrack.template mothers_first_as(); // mother particle of electron - int pdg_mother = mp.pdgCode(); - if (pdg_mother != 22 || !(mp.isPhysicalPrimary() || mp.producedByGenerator())) { // mother of electron is not photon, or not physical primary, or not producedByGenerator - continue; - } - } - } else { // not physical primary, not producedByGenerator, not electrons - continue; - } - } else if (abs(mctrack.y()) > max_Y_gen) { // physical primary or producedByGenerator, but outside of acceptance. - continue; - } - - if (abs(pdg) == 11 && !(mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { // only for quick check, only secondary electrons should appear. - registry.fill(HIST("PCM/hXY"), mctrack.vx(), mctrack.vy()); - registry.fill(HIST("PCM/hRZ"), mctrack.vz(), sqrt(pow(mctrack.vx(), 2) + pow(mctrack.vy(), 2))); - } - - // these are used as denominator for efficiency. (i.e. generated information) - if (!(fNewLabels.find(mctrack.globalIndex()) != fNewLabels.end())) { - fNewLabels[mctrack.globalIndex()] = fCounters[0]; - fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); - // fMCFlags[mctrack.globalIndex()] = mcflags; - fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; - fCounters[0]++; - } - - bool is_used_for_gen = false; - if ((mctrack.isPhysicalPrimary() || mctrack.producedByGenerator()) && (abs(pdg) == 11 || abs(pdg) == 13) && mctrack.has_mothers()) { - auto mp = mctrack.template mothers_first_as(); // mother particle of electron - int pdg_mother = abs(mp.pdgCode()); - - bool is_from_sm = pdg_mother == 111 || pdg_mother == 221 || pdg_mother == 331 || pdg_mother == 113 || pdg_mother == 223 || pdg_mother == 333 || pdg_mother == 443 || pdg_mother == 100443 || pdg_mother == 553 || pdg_mother == 100553 || pdg_mother == 200553; - bool is_from_c_hadron = std::to_string(pdg_mother)[std::to_string(pdg_mother).length() - 3] == '4' || std::to_string(pdg_mother)[std::to_string(pdg_mother).length() - 4] == '4'; - bool is_from_b_hadron = std::to_string(pdg_mother)[std::to_string(pdg_mother).length() - 3] == '5' || std::to_string(pdg_mother)[std::to_string(pdg_mother).length() - 4] == '5'; - - if ((is_from_sm || is_from_c_hadron || is_from_b_hadron)) { - is_used_for_gen = true; - } - } - - if (is_used_for_gen) { - // Next, store mother-chain for only HF->l, because HF->ll analysis requires correlation between HF hadrons or quarks. PLEASE DON'T do this for other partices. - int motherid = -999; // first mother index - if (mctrack.has_mothers()) { - motherid = mctrack.mothersIds()[0]; // first mother index - } - while (motherid > -1) { - if (motherid < mcTracks.size()) { // protect against bad mother indices. why is this needed? - auto mp = mcTracks.iteratorAt(motherid); - - if (abs(mp.pdgCode()) < 100) { // don't store quark/gluon informaiton, because data size explodes. - break; - } - - // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack - if (!(fNewLabels.find(mp.globalIndex()) != fNewLabels.end())) { - fNewLabels[mp.globalIndex()] = fCounters[0]; - fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); - // fMCFlags[mp.globalIndex()] = mcflags; - fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; - fCounters[0]++; - } - - if (mp.has_mothers()) { - motherid = mp.mothersIds()[0]; // first mother index - } else { - motherid = -999; - } - } else { - motherid = -999; - } - } // end of mother chain loop - } - } // end of mc track loop - - if constexpr (static_cast(system & kPCM)) { - auto groupedV0s = v0photons.sliceBy(perCollision_pcm, collision.globalIndex()); - for (auto& v0 : groupedV0s) { - auto ele = v0.template negTrack_as(); - auto pos = v0.template posTrack_as(); - - auto o2track_ele = o2tracks.iteratorAt(pos.trackId()); - auto o2track_pos = o2tracks.iteratorAt(ele.trackId()); - - if (!o2track_ele.has_mcParticle() || !o2track_pos.has_mcParticle()) { - continue; // If no MC particle is found, skip the v0 - } - - for (auto& leg : {pos, ele}) { // be carefull of order {pos, ele}! - // auto o2track = leg.template track_as(); - auto o2track = o2tracks.iteratorAt(leg.trackId()); - auto mctrack = o2track.template mcParticle_as(); - // LOGF(info, "mctrack.globalIndex() = %d, mctrack.index() = %d", mctrack.globalIndex(), mctrack.index()); // these are exactly the same. - - // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack - if (!(fNewLabels.find(mctrack.globalIndex()) != fNewLabels.end())) { - fNewLabels[mctrack.globalIndex()] = fCounters[0]; - fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); - // fMCFlags[mctrack.globalIndex()] = mcflags; - fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; - fCounters[0]++; - } - v0legmclabels(fNewLabels.find(mctrack.index())->second, o2track.mcMask()); - - // Next, store mother-chain of this reconstructed track. - int motherid = -999; // first mother index - if (mctrack.has_mothers()) { - motherid = mctrack.mothersIds()[0]; // first mother index - } - while (motherid > -1) { - if (motherid < mcTracks.size()) { // protect against bad mother indices. why is this needed? - auto mp = mcTracks.iteratorAt(motherid); - - // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack - if (!(fNewLabels.find(mp.globalIndex()) != fNewLabels.end())) { - fNewLabels[mp.globalIndex()] = fCounters[0]; - fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); - // fMCFlags[mp.globalIndex()] = mcflags; - fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; - fCounters[0]++; - } - - if (mp.has_mothers()) { - motherid = mp.mothersIds()[0]; // first mother index - } else { - motherid = -999; - } - } else { - motherid = -999; - } - } // end of mother chain loop - } // end of leg loop - } // end of v0 loop - } - if constexpr (static_cast(system & kDalitzEE)) { - // for dalitz ee - auto emprimaryelectrons_coll = emprimaryelectrons.sliceBy(perCollision_el, collision.globalIndex()); - for (auto& emprimaryelectron : emprimaryelectrons_coll) { - auto o2track = o2tracks.iteratorAt(emprimaryelectron.trackId()); - if (!o2track.has_mcParticle()) { - continue; // If no MC particle is found, skip the dilepton - } - auto mctrack = o2track.template mcParticle_as(); - - // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack - if (!(fNewLabels.find(mctrack.globalIndex()) != fNewLabels.end())) { - fNewLabels[mctrack.globalIndex()] = fCounters[0]; - fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); - // fMCFlags[mctrack.globalIndex()] = mcflags; - fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; - fCounters[0]++; - } - emprimaryelectronmclabels(fNewLabels.find(mctrack.index())->second, o2track.mcMask()); - - // Next, store mother-chain of this reconstructed track. - int motherid = -999; // first mother index - if (mctrack.has_mothers()) { - motherid = mctrack.mothersIds()[0]; // first mother index - } - while (motherid > -1) { - if (motherid < mcTracks.size()) { // protect against bad mother indices. why is this needed? - auto mp = mcTracks.iteratorAt(motherid); - - // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack - if (!(fNewLabels.find(mp.globalIndex()) != fNewLabels.end())) { - fNewLabels[mp.globalIndex()] = fCounters[0]; - fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); - // fMCFlags[mp.globalIndex()] = mcflags; - fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; - fCounters[0]++; - } - - if (mp.has_mothers()) { - motherid = mp.mothersIds()[0]; // first mother index - } else { - motherid = -999; - } - } else { - motherid = -999; - } - } // end of mother chain loop - - } // end of em primary track loop - } - if constexpr (static_cast(system & kDalitzMuMu)) { - // for dalitz mumu - auto emprimarymuons_coll = emprimarymuons.sliceBy(perCollision_mu, collision.globalIndex()); - for (auto& emprimarymuon : emprimarymuons_coll) { - auto o2track = o2tracks.iteratorAt(emprimarymuon.trackId()); - if (!o2track.has_mcParticle()) { - continue; // If no MC particle is found, skip the dilepton - } - auto mctrack = o2track.template mcParticle_as(); - - // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack - if (!(fNewLabels.find(mctrack.globalIndex()) != fNewLabels.end())) { - fNewLabels[mctrack.globalIndex()] = fCounters[0]; - fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); - // fMCFlags[mctrack.globalIndex()] = mcflags; - fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; - fCounters[0]++; - } - emprimarymuonmclabels(fNewLabels.find(mctrack.index())->second, o2track.mcMask()); - - // Next, store mother-chain of this reconstructed track. - int motherid = -999; // first mother index - if (mctrack.has_mothers()) { - motherid = mctrack.mothersIds()[0]; // first mother index - } - while (motherid > -1) { - if (motherid < mcTracks.size()) { // protect against bad mother indices. why is this needed? - auto mp = mcTracks.iteratorAt(motherid); - - // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack - if (!(fNewLabels.find(mp.globalIndex()) != fNewLabels.end())) { - fNewLabels[mp.globalIndex()] = fCounters[0]; - fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); - // fMCFlags[mp.globalIndex()] = mcflags; - fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; - fCounters[0]++; - } - - if (mp.has_mothers()) { - motherid = mp.mothersIds()[0]; // first mother index - } else { - motherid = -999; - } - } else { - motherid = -999; - } - } // end of mother chain loop - - } // end of em primary track loop - } - if constexpr (static_cast(system & kEMC)) { - // for emc photons - auto ememcclusters_coll = emcclusters.sliceBy(perCollision_emc, collision.globalIndex()); - for (auto& ememccluster : ememcclusters_coll) { - auto mcphoton = mcTracks.iteratorAt(ememccluster.emmcparticleIds()[0]); - - // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack - if (!(fNewLabels.find(mcphoton.globalIndex()) != fNewLabels.end())) { - fNewLabels[mcphoton.globalIndex()] = fCounters[0]; - fNewLabelsReversed[fCounters[0]] = mcphoton.globalIndex(); - fEventIdx[mcphoton.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; - fCounters[0]++; - } - ememcclustermclabels(fNewLabels.find(mcphoton.index())->second); - - // Next, store mother-chain of this reconstructed track. - int motherid = -999; // first mother index - if (mcphoton.has_mothers()) { - motherid = mcphoton.mothersIds()[0]; // first mother index - } - while (motherid > -1) { - if (motherid < mcTracks.size()) { // protect against bad mother indices. why is this needed? - auto mp = mcTracks.iteratorAt(motherid); - - // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack - if (!(fNewLabels.find(mp.globalIndex()) != fNewLabels.end())) { - fNewLabels[mp.globalIndex()] = fCounters[0]; - fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); - fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; - fCounters[0]++; - } - - if (mp.has_mothers()) { - motherid = mp.mothersIds()[0]; // first mother index - } else { - motherid = -999; - } - } else { - motherid = -999; - } - } // end of mother chain loop - - } // end of em emc cluster loop - } - } // end of collision loop - - // Loop over the label map, create the mother/daughter relationships if these exist and write the skimmed MC stack - for (const auto& [newLabel, oldLabel] : fNewLabelsReversed) { - auto mctrack = mcTracks.iteratorAt(oldLabel); - // uint16_t mcflags = fMCFlags.find(oldLabel)->second; - - std::vector mothers; - if (mctrack.has_mothers()) { - for (auto& m : mctrack.mothersIds()) { - if (m < mcTracks.size()) { // protect against bad mother indices - if (fNewLabels.find(m) != fNewLabels.end()) { - mothers.push_back(fNewLabels.find(m)->second); - } - } else { - std::cout << "Mother label (" << m << ") exceeds the McParticles size (" << mcTracks.size() << ")" << std::endl; - std::cout << " Check the MC generator" << std::endl; - } - } - } - - // Note that not all daughters from the original table are preserved in the skimmed MC stack - std::vector daughters; - if (mctrack.has_daughters()) { - // LOGF(info, "daughter range in original MC stack pdg = %d | %d - %d , n dau = %d", mctrack.pdgCode(), mctrack.daughtersIds()[0], mctrack.daughtersIds()[1], mctrack.daughtersIds()[1] -mctrack.daughtersIds()[0] +1); - for (int d = mctrack.daughtersIds()[0]; d <= mctrack.daughtersIds()[1]; ++d) { - // TODO: remove this check as soon as issues with MC production are fixed - if (d < mcTracks.size()) { // protect against bad daughter indices - // auto dau_tmp = mcTracks.iteratorAt(d); - // LOGF(info, "daughter pdg = %d", dau_tmp.pdgCode()); - if (fNewLabels.find(d) != fNewLabels.end()) { - daughters.push_back(fNewLabels.find(d)->second); - } - } else { - std::cout << "Daughter label (" << d << ") exceeds the McParticles size (" << mcTracks.size() << ")" << std::endl; - std::cout << " Check the MC generator" << std::endl; - } - } - } - - emmcparticles(fEventIdx.find(oldLabel)->second, mctrack.pdgCode(), mctrack.flags(), - mothers, daughters, - mctrack.px(), mctrack.py(), mctrack.pz(), mctrack.e(), - mctrack.vx(), mctrack.vy(), mctrack.vz(), mctrack.vt()); - } // end loop over labels - - fNewLabels.clear(); - fNewLabelsReversed.clear(); - // fMCFlags.clear(); - fEventIdx.clear(); - fEventLabels.clear(); - fCounters[0] = 0; - fCounters[1] = 0; - } // end of skimmingMC - - void processMC_PCM(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs) - { - skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, v0photons, v0legs, nullptr, nullptr, nullptr, nullptr); - } - void processMC_PCM_DalitzEE(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, aod::EMPrimaryElectrons const& emprimaryelectrons) - { - const uint8_t sysflag = kPCM | kDalitzEE; - skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, v0photons, v0legs, nullptr, nullptr, emprimaryelectrons, nullptr); - } - void processMC_DalitzEE(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, aod::EMPrimaryElectrons const& emprimaryelectrons) - { - const uint8_t sysflag = kDalitzEE; - skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, nullptr, nullptr, nullptr, nullptr, emprimaryelectrons, nullptr); - } - void processMC_PCM_DalitzEE_DalitzMuMu(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, aod::EMPrimaryElectrons const& emprimaryelectrons, aod::EMPrimaryMuons const& emprimarymuons) - { - const uint8_t sysflag = kPCM | kDalitzEE | kDalitzMuMu; - skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, v0photons, v0legs, nullptr, nullptr, emprimaryelectrons, emprimarymuons); - } - - void processMC_PHOS(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, aod::PHOSClusters const& phosclusters) - { - skimmingMC(collisions, bcs, mccollisions, mcTracks, nullptr, nullptr, nullptr, phosclusters, nullptr, nullptr, nullptr); - } - void processMC_EMC(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, MyEMCClusters const& emcclusters) - { - skimmingMC(collisions, bcs, mccollisions, mcTracks, nullptr, nullptr, nullptr, nullptr, emcclusters, nullptr, nullptr); - } - void processMC_PCM_PHOS(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, aod::PHOSClusters const& phosclusters) - { - const uint8_t sysflag = kPCM | kPHOS; - skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, v0photons, v0legs, phosclusters, nullptr, nullptr, nullptr); - } - void processMC_PCM_PHOS_DalitzEE(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, aod::PHOSClusters const& phosclusters, aod::EMPrimaryElectrons const& emprimaryelectrons) - { - const uint8_t sysflag = kPCM | kPHOS | kDalitzEE; - skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, v0photons, v0legs, phosclusters, nullptr, emprimaryelectrons, nullptr); - } - void processMC_PCM_EMC(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, MyEMCClusters const& emcclusters) - { - const uint8_t sysflag = kPCM | kEMC; - skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, v0photons, v0legs, nullptr, emcclusters, nullptr, nullptr); - } - void processMC_PCM_EMC_DalitzEE(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, MyEMCClusters const& emcclusters, aod::EMPrimaryElectrons const& emprimaryelectrons) - { - const uint8_t sysflag = kPCM | kEMC | kDalitzEE; - skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, v0photons, v0legs, nullptr, emcclusters, emprimaryelectrons, nullptr); - } - void processMC_PHOS_EMC(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, aod::PHOSClusters const& phosclusters, MyEMCClusters const& emcclusters) - { - const uint8_t sysflag = kPHOS | kEMC; - skimmingMC(collisions, bcs, mccollisions, mcTracks, nullptr, nullptr, nullptr, phosclusters, emcclusters, nullptr, nullptr); - } - void processMC_PCM_PHOS_EMC(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, aod::PHOSClusters const& phosclusters, MyEMCClusters const& emcclusters) - { - const uint8_t sysflag = kPCM | kPHOS | kEMC; - skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, v0photons, v0legs, phosclusters, emcclusters, nullptr, nullptr); - } - void processMC_PCM_PHOS_EMC_DalitzEE(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, aod::PHOSClusters const& phosclusters, MyEMCClusters const& emcclusters, aod::EMPrimaryElectrons const& emprimaryelectrons) - { - const uint8_t sysflag = kPCM | kPHOS | kEMC | kDalitzEE; - skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, v0photons, v0legs, phosclusters, emcclusters, emprimaryelectrons, nullptr); - } - - void processDummy(MyCollisionsMC const&) {} - - PROCESS_SWITCH(AssociateMCInfo, processMC_PCM, "create em mc event table for PCM", false); - PROCESS_SWITCH(AssociateMCInfo, processMC_PCM_DalitzEE, "create em mc event table for PCM, DalitzEE", false); - PROCESS_SWITCH(AssociateMCInfo, processMC_DalitzEE, "create em mc event table for DalitzEE", false); - PROCESS_SWITCH(AssociateMCInfo, processMC_PCM_DalitzEE_DalitzMuMu, "create em mc event table for PCM, DalitzEE, DalitzMuMu", false); - PROCESS_SWITCH(AssociateMCInfo, processMC_PHOS, "create em mc event table for PHOS", false); - PROCESS_SWITCH(AssociateMCInfo, processMC_EMC, "create em mc event table for EMCal", false); - PROCESS_SWITCH(AssociateMCInfo, processMC_PCM_PHOS, "create em mc event table for PCM, PHOS", false); - PROCESS_SWITCH(AssociateMCInfo, processMC_PCM_PHOS_DalitzEE, "create em mc event table for PCM, PHOS, DalitzEE", false); - PROCESS_SWITCH(AssociateMCInfo, processMC_PCM_EMC, "create em mc event table for PCM, EMCal", false); - PROCESS_SWITCH(AssociateMCInfo, processMC_PCM_EMC_DalitzEE, "create em mc event table for PCM, EMCal, DalitzEE", false); - PROCESS_SWITCH(AssociateMCInfo, processMC_PHOS_EMC, "create em mc event table for PHOS, EMCal", false); - PROCESS_SWITCH(AssociateMCInfo, processMC_PCM_PHOS_EMC, "create em mc event table for PCM, PHOS, EMCal", false); - PROCESS_SWITCH(AssociateMCInfo, processMC_PCM_PHOS_EMC_DalitzEE, "create em mc event table for PCM, PHOS, EMCal, DalitzEE", false); - PROCESS_SWITCH(AssociateMCInfo, processDummy, "processDummy", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"associate-mc-info"})}; -} diff --git a/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx b/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx new file mode 100644 index 00000000000..2fafc5118e3 --- /dev/null +++ b/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx @@ -0,0 +1,541 @@ +// 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 associateMCinfoPhoton.cxx +/// +/// \brief This code produces reduced events for photon analyses +/// +/// \author Daiki Sekihata (daiki.sekihata@cern.ch) +/// + +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::photonmeson::utils::mcutil; + +using MyCollisionsMC = soa::Join; +using TracksMC = soa::Join; +using FwdTracksMC = soa::Join; +using MyEMCClusters = soa::Join; + +struct AssociateMCInfoPhoton { + enum SubSystem { + kPCM = 0x1, + kPHOS = 0x2, + kEMC = 0x4, + kElectron = 0x8, + }; + + Produces mcevents; + Produces mceventlabels; + Produces emmcparticles; + Produces v0legmclabels; + Produces emprimaryelectronmclabels; + Produces ememcclustermclabels; + + Produces binnedGenPt; + + Configurable max_eta_gen_secondary{"max_eta_gen_secondary", 0.9, "max eta to store generated information"}; + Configurable margin_z_gen{"margin_z_gen", 15.f, "margin for Z of true photon conversion point to store generated information"}; + Configurable max_rxy_gen{"max_rxy_gen", 100, "max rxy to store generated information"}; + Configurable requireGammaGammaDecay{"requireGammaGammaDecay", false, "require gamma gamma decay for generated pi0 and eta meson"}; + + HistogramRegistry registry{"EMMCEvent"}; + + void init(o2::framework::InitContext&) + { + auto hEventCounter = registry.add("hEventCounter", "hEventCounter", kTH1F, {{6, 0.5f, 6.5f}}); + hEventCounter->GetXaxis()->SetBinLabel(1, "all"); + hEventCounter->GetXaxis()->SetBinLabel(2, "has mc collision"); + + // !!Don't change pt,eta,y binning. These binnings have to be consistent with binned data at analysis.!! + std::vector ptbins; + for (int i = 0; i < 2; i++) { + ptbins.emplace_back(0.05 * (i - 0) + 0.0); // from 0 to 0.05 GeV/c, every 0.05 GeV/c + } + for (int i = 2; i < 51; i++) { + ptbins.emplace_back(0.1 * (i - 2) + 0.1); // from 0.1 to 4.9 GeV/c, every 0.1 GeV/c + } + for (int i = 51; i < 61; i++) { + ptbins.emplace_back(0.5 * (i - 51) + 5.0); // from 5 to 9.5 GeV/c, every 0.5 GeV/c + } + for (int i = 61; i < 72; i++) { + ptbins.emplace_back(1.0 * (i - 61) + 10.0); // from 10 to 20 GeV/c, every 1 GeV/c + } + const AxisSpec axisPt{ptbins, "p_{T} (GeV/c)"}; + const AxisSpec axisRapidity{{0.0, +0.8, +0.9}, "rapidity |y|"}; + + static constexpr std::string_view ParticleNames[9] = { + "Gamma", "Pi0", "Eta", "Omega", "Phi", + "ChargedPion", "ChargedKaon", "K0S", "Lambda"}; + + for (int i = 0; i < 9; i++) { + registry.add(Form("Generated/h2PtY_%s", ParticleNames[i].data()), Form("Generated %s", ParticleNames[i].data()), kTH2F, {axisPt, axisRapidity}, true); + } + + // reserve space for generated vectors if that process enabled + auto hBinFinder = registry.get(HIST("Generated/h2PtY_Pi0")); + LOGF(info, "Binned generated processing enabled. Initialising with %i elements...", hBinFinder->GetNcells()); + genGamma.resize(hBinFinder->GetNcells(), 0); + genPi0.resize(hBinFinder->GetNcells(), 0); + genEta.resize(hBinFinder->GetNcells(), 0); + } + + Preslice perMcCollision = aod::mcparticle::mcCollisionId; + Preslice perCollisionPCM = aod::v0photonkf::collisionId; + Preslice perCollisionEl = aod::emprimaryelectron::collisionId; + Preslice perCollisionPHOS = aod::skimmedcluster::collisionId; + Preslice perCollisionEMC = aod::skimmedcluster::collisionId; + + std::vector genGamma; // primary, pt, y + std::vector genPi0; // primary, pt, y + std::vector genEta; // primary, pt, y + + template + void skimmingMC(MyCollisionsMC const& collisions, aod::BCs const&, aod::McCollisions const&, aod::McParticles const& mcParticles, TTracks const& o2tracks, TFwdTracks const&, TPCMs const& v0photons, TPCMLegs const&, TPHOSs const&, TEMCs const& emcclusters, TEMPrimaryElectrons const& emprimaryelectrons) + { + // temporary variables used for the indexing of the skimmed MC stack + std::map fNewLabels; + std::map fNewLabelsReversed; + // std::map fMCFlags; + std::map fEventIdx; + std::map fEventLabels; + int fCounters[2] = {0, 0}; //! [0] - particle counter, [1] - event counter + auto hBinFinder = registry.get(HIST("Generated/h2PtY_Gamma")); + + for (const auto& collision : collisions) { + registry.fill(HIST("hEventCounter"), 1); + + // TODO: investigate the collisions without corresponding mcCollision + if (!collision.has_mcCollision()) { + continue; + } + + if (!collision.isSelected()) { + continue; + } + + registry.fill(HIST("hEventCounter"), 2); + + std::fill(genGamma.begin(), genGamma.end(), 0); + std::fill(genPi0.begin(), genPi0.end(), 0); + std::fill(genEta.begin(), genEta.end(), 0); + + auto mcCollision = collision.mcCollision(); + // store mc particles + auto groupedMcParticles = mcParticles.sliceBy(perMcCollision, mcCollision.globalIndex()); + + for (const auto& mcParticle : groupedMcParticles) { // store necessary information for denominator of efficiency + if ((mcParticle.isPhysicalPrimary() || mcParticle.producedByGenerator()) && std::fabs(mcParticle.y()) < 0.9f && mcParticle.pt() < 20.f) { + auto binNumber = hBinFinder->FindBin(mcParticle.pt(), std::fabs(mcParticle.y())); // caution: pack + switch (std::abs(mcParticle.pdgCode())) { + case 22: + registry.fill(HIST("Generated/h2PtY_Gamma"), mcParticle.pt(), std::fabs(mcParticle.y())); + genGamma[binNumber]++; + break; + case 111: + if (requireGammaGammaDecay && !isGammaGammaDecay(mcParticle, mcParticles)) + continue; + registry.fill(HIST("Generated/h2PtY_Pi0"), mcParticle.pt(), std::fabs(mcParticle.y())); + genPi0[binNumber]++; + break; + case 221: + if (requireGammaGammaDecay && !isGammaGammaDecay(mcParticle, mcParticles)) + continue; + registry.fill(HIST("Generated/h2PtY_Eta"), mcParticle.pt(), std::fabs(mcParticle.y())); + genEta[binNumber]++; + break; + default: + break; + } + } + } // end of mc track loop + + // make an entry for this MC event only if it was not already added to the table + if (!(fEventLabels.find(mcCollision.globalIndex()) != fEventLabels.end())) { + mcevents(mcCollision.globalIndex(), mcCollision.generatorsID(), mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.impactParameter(), mcCollision.eventPlaneAngle()); + fEventLabels[mcCollision.globalIndex()] = fCounters[1]; + fCounters[1]++; + binnedGenPt(genGamma, genPi0, genEta); + } + + // LOGF(info, "collision.globalIndex() = %d , mceventlabels.lastIndex() = %d", collision.globalIndex(), mceventlabels.lastIndex()); + mceventlabels(fEventLabels.find(mcCollision.globalIndex())->second, collision.mcMask()); + + for (const auto& mcParticle : groupedMcParticles) { // store necessary information for denominator of efficiency + if (mcParticle.pt() < 1e-3 || std::fabs(mcParticle.vz()) > 250 || std::sqrt(std::pow(mcParticle.vx(), 2) + std::pow(mcParticle.vy(), 2)) > max_rxy_gen) { + continue; + } + int pdg = mcParticle.pdgCode(); + if (std::abs(pdg) > 1e+9) { + continue; + } + + // Note that pi0 from weak decay gives producedByGenerator() = false + // LOGF(info,"index = %d , mc track pdg = %d , producedByGenerator = %d , isPhysicalPrimary = %d", mcParticle.index(), mcParticle.pdgCode(), mcParticle.producedByGenerator(), mcParticle.isPhysicalPrimary()); + + if (std::abs(pdg) == 11 && mcParticle.has_mothers() && !(mcParticle.isPhysicalPrimary() || mcParticle.producedByGenerator())) { // secondary electrons. i.e. ele/pos from photon conversions. + int motherid = mcParticle.mothersIds()[0]; // first mother index + auto mp = mcParticles.iteratorAt(motherid); + + if (std::sqrt(std::pow(mcParticle.vx(), 2) + std::pow(mcParticle.vy(), 2)) < std::fabs(mcParticle.vz()) * std::tan(2 * std::atan(std::exp(-max_eta_gen_secondary))) - margin_z_gen) { + continue; + } + + if (mp.pdgCode() == 22 && (mp.isPhysicalPrimary() || mp.producedByGenerator()) && std::fabs(mp.eta()) < max_eta_gen_secondary) { + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mcParticle.globalIndex()) != fNewLabels.end())) { // store electron information. !!Not photon!! + fNewLabels[mcParticle.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mcParticle.globalIndex(); + // fMCFlags[mcParticle.globalIndex()] = mcflags; + fEventIdx[mcParticle.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; + fCounters[0]++; + } + + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mp.globalIndex()) != fNewLabels.end())) { // store conversion photon + fNewLabels[mp.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); + // fMCFlags[mp.globalIndex()] = mcflags; + fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; + fCounters[0]++; + } + } + } + } // end of mc track loop + + } // end of rec. collision loop + + if constexpr (static_cast(system & kPCM)) { + for (const auto& v0 : v0photons) { + auto collisionFromV0 = collisions.iteratorAt(v0.collisionId()); + if (!collisionFromV0.has_mcCollision()) { + continue; + } + auto mcCollisionFromV0 = collisionFromV0.mcCollision(); + + auto ele = v0.template negTrack_as(); + auto pos = v0.template posTrack_as(); + + auto o2TrackEle = o2tracks.iteratorAt(pos.trackId()); + auto o2TrackPos = o2tracks.iteratorAt(ele.trackId()); + + if (!o2TrackEle.has_mcParticle() || !o2TrackPos.has_mcParticle()) { + continue; // If no MC particle is found, skip the v0 + } + + for (const auto& leg : {pos, ele}) { // be carefull of order {pos, ele}! + auto o2track = o2tracks.iteratorAt(leg.trackId()); + auto mcParticle = o2track.template mcParticle_as(); + // LOGF(info, "mcParticle.globalIndex() = %d, mcParticle.index() = %d", mcParticle.globalIndex(), mcParticle.index()); // these are exactly the same. + + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mcParticle.globalIndex()) != fNewLabels.end())) { + fNewLabels[mcParticle.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mcParticle.globalIndex(); + // fMCFlags[mcParticle.globalIndex()] = mcflags; + fEventIdx[mcParticle.globalIndex()] = fEventLabels.find(mcCollisionFromV0.globalIndex())->second; + fCounters[0]++; + } + v0legmclabels(fNewLabels.find(mcParticle.index())->second, o2track.mcMask()); + + // Next, store mother-chain of this reconstructed track. + int motherid = -999; // first mother index + if (mcParticle.has_mothers()) { + motherid = mcParticle.mothersIds()[0]; // first mother index + } + while (motherid > -1) { + if (motherid < mcParticles.size()) { // protect against bad mother indices. why is this needed? + auto mp = mcParticles.iteratorAt(motherid); + + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mp.globalIndex()) != fNewLabels.end())) { + fNewLabels[mp.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); + // fMCFlags[mp.globalIndex()] = mcflags; + fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollisionFromV0.globalIndex())->second; + fCounters[0]++; + } + + if (mp.has_mothers()) { + motherid = mp.mothersIds()[0]; // first mother index + } else { + motherid = -999; + } + } else { + motherid = -999; + } + } // end of mother chain loop + } // end of leg loop + } // end of v0 loop + } + + if constexpr (static_cast(system & kElectron)) { + // auto emprimaryelectrons_coll = emprimaryelectrons.sliceBy(perCollisionEl, collision.globalIndex()); + for (const auto& emprimaryelectron : emprimaryelectrons) { + auto collisionFromEl = collisions.iteratorAt(emprimaryelectron.collisionId()); + if (!collisionFromEl.has_mcCollision()) { + continue; + } + auto mcCollisionFromEl = collisionFromEl.mcCollision(); + + auto o2track = o2tracks.iteratorAt(emprimaryelectron.trackId()); + if (!o2track.has_mcParticle()) { + continue; // If no MC particle is found, skip the dilepton + } + auto mcParticle = o2track.template mcParticle_as(); + + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mcParticle.globalIndex()) != fNewLabels.end())) { + fNewLabels[mcParticle.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mcParticle.globalIndex(); + // fMCFlags[mcParticle.globalIndex()] = mcflags; + fEventIdx[mcParticle.globalIndex()] = fEventLabels.find(mcCollisionFromEl.globalIndex())->second; + fCounters[0]++; + } + emprimaryelectronmclabels(fNewLabels.find(mcParticle.index())->second, o2track.mcMask()); + + // Next, store mother-chain of this reconstructed track. + int motherid = -999; // first mother index + if (mcParticle.has_mothers()) { + motherid = mcParticle.mothersIds()[0]; // first mother index + } + while (motherid > -1) { + if (motherid < mcParticles.size()) { // protect against bad mother indices. why is this needed? + auto mp = mcParticles.iteratorAt(motherid); + + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mp.globalIndex()) != fNewLabels.end())) { + fNewLabels[mp.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); + // fMCFlags[mp.globalIndex()] = mcflags; + fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollisionFromEl.globalIndex())->second; + fCounters[0]++; + } + + if (mp.has_mothers()) { + motherid = mp.mothersIds()[0]; // first mother index + } else { + motherid = -999; + } + } else { + motherid = -999; + } + } // end of mother chain loop + + } // end of em primary electron loop + } + + if constexpr (static_cast(system & kEMC)) { // for emc photons + // auto ememcclusters_coll = emcclusters.sliceBy(perCollisionEMC, collision.globalIndex()); + for (const auto& emccluster : emcclusters) { + auto collisionFromEMC = collisions.iteratorAt(emccluster.collisionId()); + if (!collisionFromEMC.has_mcCollision()) { + continue; + } + auto mcCollisionFromEMC = collisionFromEMC.mcCollision(); + + auto mcphoton = mcParticles.iteratorAt(emccluster.emmcparticleIds()[0]); + + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mcphoton.globalIndex()) != fNewLabels.end())) { + fNewLabels[mcphoton.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mcphoton.globalIndex(); + fEventIdx[mcphoton.globalIndex()] = fEventLabels.find(mcCollisionFromEMC.globalIndex())->second; + fCounters[0]++; + } + ememcclustermclabels(fNewLabels.find(mcphoton.index())->second); + + // Next, store mother-chain of this reconstructed track. + int motherid = -999; // first mother index + if (mcphoton.has_mothers()) { + motherid = mcphoton.mothersIds()[0]; // first mother index + } + while (motherid > -1) { + if (motherid < mcParticles.size()) { // protect against bad mother indices. why is this needed? + auto mp = mcParticles.iteratorAt(motherid); + + // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack + if (!(fNewLabels.find(mp.globalIndex()) != fNewLabels.end())) { + fNewLabels[mp.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); + fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollisionFromEMC.globalIndex())->second; + fCounters[0]++; + } + + if (mp.has_mothers()) { + motherid = mp.mothersIds()[0]; // first mother index + } else { + motherid = -999; + } + } else { + motherid = -999; + } + } // end of mother chain loop + + } // end of em emc cluster loop + } + + // Loop over the label map, create the mother/daughter relationships if these exist and write the skimmed MC stack + for (const auto& [newLabel, oldLabel] : fNewLabelsReversed) { + auto mcParticle = mcParticles.iteratorAt(oldLabel); + // uint16_t mcflags = fMCFlags.find(oldLabel)->second; + + std::vector mothers; + if (mcParticle.has_mothers()) { + for (const auto& m : mcParticle.mothersIds()) { + if (m < mcParticles.size()) { // protect against bad mother indices + if (fNewLabels.find(m) != fNewLabels.end()) { + mothers.push_back(fNewLabels.find(m)->second); + } + } else { + LOG(info) << "Mother label (" << m << ") exceeds the McParticles size (" << mcParticles.size() << ")"; + LOG(info) << " Check the MC generator"; + } + } + } + + // Note that not all daughters from the original table are preserved in the skimmed MC stack + std::vector daughters; + if (mcParticle.has_daughters()) { + // LOGF(info, "daughter range in original MC stack pdg = %d | %d - %d , n dau = %d", mcParticle.pdgCode(), mcParticle.daughtersIds()[0], mcParticle.daughtersIds()[1], mcParticle.daughtersIds()[1] -mcParticle.daughtersIds()[0] +1); + for (int d = mcParticle.daughtersIds()[0]; d <= mcParticle.daughtersIds()[1]; ++d) { + // TODO: remove this check as soon as issues with MC production are fixed + if (d < mcParticles.size()) { // protect against bad daughter indices + // auto dau_tmp = mcParticles.iteratorAt(d); + // LOGF(info, "daughter pdg = %d", dau_tmp.pdgCode()); + if (fNewLabels.find(d) != fNewLabels.end()) { + daughters.push_back(fNewLabels.find(d)->second); + } + } else { + LOG(info) << "Daughter label (" << d << ") exceeds the McParticles size (" << mcParticles.size() << ")"; + LOG(info) << " Check the MC generator"; + } + } + } + + emmcparticles(fEventIdx.find(oldLabel)->second, mcParticle.pdgCode(), mcParticle.flags(), + mothers, daughters, + mcParticle.px(), mcParticle.py(), mcParticle.pz(), mcParticle.e(), + mcParticle.vx(), mcParticle.vy(), mcParticle.vz()); + } // end loop over labels + + fNewLabels.clear(); + fNewLabelsReversed.clear(); + // fMCFlags.clear(); + fEventIdx.clear(); + fEventLabels.clear(); + fCounters[0] = 0; + fCounters[1] = 0; + } // end of skimmingMC + + void processMC_PCM(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcParticles, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs) + { + skimmingMC(collisions, bcs, mccollisions, mcParticles, o2tracks, nullptr, v0photons, v0legs, nullptr, nullptr, nullptr); + } + PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PCM, "create em mc event table for PCM", false); + + void processMC_PCM_Electron(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcParticles, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, aod::EMPrimaryElectronsFromDalitz const& emprimaryelectrons) + { + const uint8_t sysflag = kPCM | kElectron; + skimmingMC(collisions, bcs, mccollisions, mcParticles, o2tracks, nullptr, v0photons, v0legs, nullptr, nullptr, emprimaryelectrons); + } + PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PCM_Electron, "create em mc event table for PCM, Electron", false); + + void processMC_Electron(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcParticles, TracksMC const& o2tracks, aod::EMPrimaryElectronsFromDalitz const& emprimaryelectrons) + { + const uint8_t sysflag = kElectron; + skimmingMC(collisions, bcs, mccollisions, mcParticles, o2tracks, nullptr, nullptr, nullptr, nullptr, nullptr, emprimaryelectrons); + } + PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_Electron, "create em mc event table for Electron", false); + + void processMC_PHOS(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcParticles, aod::PHOSClusters const& phosclusters) + { + skimmingMC(collisions, bcs, mccollisions, mcParticles, nullptr, nullptr, nullptr, nullptr, phosclusters, nullptr, nullptr); + } + PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PHOS, "create em mc event table for PHOS", false); + + void processMC_EMC(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcParticles, MyEMCClusters const& emcclusters) + { + skimmingMC(collisions, bcs, mccollisions, mcParticles, nullptr, nullptr, nullptr, nullptr, nullptr, emcclusters, nullptr); + } + PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_EMC, "create em mc event table for EMCal", false); + + void processMC_PCM_PHOS(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcParticles, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, aod::PHOSClusters const& phosclusters) + { + const uint8_t sysflag = kPCM | kPHOS; + skimmingMC(collisions, bcs, mccollisions, mcParticles, o2tracks, nullptr, v0photons, v0legs, phosclusters, nullptr, nullptr); + } + PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PCM_PHOS, "create em mc event table for PCM, PHOS", false); + + void processMC_PCM_PHOS_Electron(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcParticles, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, aod::PHOSClusters const& phosclusters, aod::EMPrimaryElectronsFromDalitz const& emprimaryelectrons) + { + const uint8_t sysflag = kPCM | kPHOS | kElectron; + skimmingMC(collisions, bcs, mccollisions, mcParticles, o2tracks, nullptr, v0photons, v0legs, phosclusters, nullptr, emprimaryelectrons); + } + PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PCM_PHOS_Electron, "create em mc event table for PCM, PHOS, Electron", false); + + void processMC_PCM_EMC(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcParticles, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, MyEMCClusters const& emcclusters) + { + const uint8_t sysflag = kPCM | kEMC; + skimmingMC(collisions, bcs, mccollisions, mcParticles, o2tracks, nullptr, v0photons, v0legs, nullptr, emcclusters, nullptr); + } + PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PCM_EMC, "create em mc event table for PCM, EMCal", false); + + void processMC_PCM_EMC_Electron(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcParticles, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, MyEMCClusters const& emcclusters, aod::EMPrimaryElectronsFromDalitz const& emprimaryelectrons) + { + const uint8_t sysflag = kPCM | kEMC | kElectron; + skimmingMC(collisions, bcs, mccollisions, mcParticles, o2tracks, nullptr, v0photons, v0legs, nullptr, emcclusters, emprimaryelectrons); + } + PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PCM_EMC_Electron, "create em mc event table for PCM, EMCal, Electron", false); + + void processMC_PHOS_EMC(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcParticles, aod::PHOSClusters const& phosclusters, MyEMCClusters const& emcclusters) + { + const uint8_t sysflag = kPHOS | kEMC; + skimmingMC(collisions, bcs, mccollisions, mcParticles, nullptr, nullptr, nullptr, nullptr, phosclusters, emcclusters, nullptr); + } + PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PHOS_EMC, "create em mc event table for PHOS, EMCal", false); + + void processMC_PCM_PHOS_EMC(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcParticles, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, aod::PHOSClusters const& phosclusters, MyEMCClusters const& emcclusters) + { + const uint8_t sysflag = kPCM | kPHOS | kEMC; + skimmingMC(collisions, bcs, mccollisions, mcParticles, o2tracks, nullptr, v0photons, v0legs, phosclusters, emcclusters, nullptr); + } + PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PCM_PHOS_EMC, "create em mc event table for PCM, PHOS, EMCal", false); + + void processMC_PCM_PHOS_EMC_Electron(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcParticles, TracksMC const& o2tracks, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, aod::PHOSClusters const& phosclusters, MyEMCClusters const& emcclusters, aod::EMPrimaryElectronsFromDalitz const& emprimaryelectrons) + { + const uint8_t sysflag = kPCM | kPHOS | kEMC | kElectron; + skimmingMC(collisions, bcs, mccollisions, mcParticles, o2tracks, nullptr, v0photons, v0legs, phosclusters, emcclusters, emprimaryelectrons); + } + PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PCM_PHOS_EMC_Electron, "create em mc event table for PCM, PHOS, EMCal, Electron", false); + + void processDummy(MyCollisionsMC const&) {} + PROCESS_SWITCH(AssociateMCInfoPhoton, processDummy, "processDummy", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"associate-mc-info-photon"})}; +} diff --git a/PWGEM/PhotonMeson/TableProducer/bcWiseClusterSkimmer.cxx b/PWGEM/PhotonMeson/TableProducer/bcWiseClusterSkimmer.cxx new file mode 100644 index 00000000000..2cdaf79f2f0 --- /dev/null +++ b/PWGEM/PhotonMeson/TableProducer/bcWiseClusterSkimmer.cxx @@ -0,0 +1,274 @@ +// 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 bcWiseClusterSkimmer.cxx +/// +/// \brief This task creates minimalistic skimmed tables containing EMC clusters and centrality information +/// +/// \author Nicolas Strangmann (nicolas.strangmann@cern.ch) - Goethe University Frankfurt +/// + +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" + +#include "DetectorsBase/GeometryManager.h" +#include "EMCALBase/Geometry.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" +#include "PWGEM/PhotonMeson/DataModel/bcWiseTables.h" + +using namespace o2; +using namespace o2::aod::emdownscaling; +using namespace o2::framework; + +using MyCollisions = soa::Join; +using MyMCCollisions = soa::Join; +using MyBCs = soa::Join; + +using SelectedUniqueClusters = soa::Filtered; // Clusters from collisions with only one collision in the BC +using SelectedUniqueMCClusters = soa::Filtered>; // Clusters from collisions with only one collision in the BC +using SelectedAmbiguousClusters = soa::Filtered; // Clusters from BCs with multiple collisions (no vertex assignment possible) +using SelectedAmbiguousMCClusters = soa::Filtered>; // Clusters from BCs with multiple collisions (no vertex assignment possible) +using SelectedCells = o2::soa::Filtered; + +struct bcWiseClusterSkimmer { + Produces bcTable; + Produces clusterTable; + Produces collisionTable; + Produces mcpi0Table; + Produces mcclusterTable; + + PresliceUnsorted perFoundBC = aod::evsel::foundBCId; + Preslice perCol = aod::emcalcluster::collisionId; + Preslice perBC = aod::emcalcluster::bcId; + Preslice cellsPerBC = aod::calo::bcId; + + Configurable cfgMinClusterEnergy{"cfgMinClusterEnergy", 0.5, "Minimum energy of selected clusters (GeV)"}; + Configurable cfgMinM02{"cfgMinM02", -1., "Minimum M02 of selected clusters"}; + Configurable cfgMaxM02{"cfgMaxM02", 5., "Maximum M02 of selected clusters"}; + Configurable cfgMinTime{"cfgMinTime", -25, "Minimum time of selected clusters (ns)"}; + Configurable cfgMaxTime{"cfgMaxTime", 25, "Maximum time of selected clusters (ns)"}; + Configurable cfgRapidityCut{"cfgRapidityCut", 0.8f, "Maximum absolute rapidity of counted generated particles"}; + + expressions::Filter energyFilter = aod::emcalcluster::energy > cfgMinClusterEnergy; + expressions::Filter m02Filter = (aod::emcalcluster::nCells == 1 || (aod::emcalcluster::m02 > cfgMinM02 && aod::emcalcluster::m02 < cfgMaxM02)); + expressions::Filter timeFilter = (aod::emcalcluster::time > cfgMinTime && aod::emcalcluster::time < cfgMaxTime); + expressions::Filter emccellfilter = aod::calo::caloType == 1; + + HistogramRegistry mHistManager{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + void init(framework::InitContext&) + { + const int nEventBins = 6; + mHistManager.add("nBCs", "Number of BCs;;#bf{#it{N}_{BCs}}", HistType::kTH1F, {{nEventBins, -0.5, 5.5}}); + const TString binLabels[nEventBins] = {"All", "FT0", "TVX", "kTVXinEMC", "Cell", "NoBorder"}; + for (int iBin = 0; iBin < nEventBins; iBin++) + mHistManager.get(HIST("nBCs"))->GetXaxis()->SetBinLabel(iBin + 1, binLabels[iBin]); + + mHistManager.add("hAmplitudeVsCentrality", "FT0M AmplitudeVsCentrality;FT0M Centrality;FT0M Amplitude", HistType::kTH2F, {{105, 0, 105}, {400, 0, 200000}}); + mHistManager.add("sumAmp", "Sum Amplitude", HistType::kTH1F, {{1000, 0., 10.}}); + mHistManager.add("nCells", "Number of EMCal cells", HistType::kTH1F, {{5000, -0.5, 5000.5}}); + + LOG(info) << "| Timing cut: " << cfgMinTime << " < t < " << cfgMaxTime; + LOG(info) << "| M02 cut: " << cfgMinM02 << " < M02 < " << cfgMaxM02; + LOG(info) << "| E cut: E > " << cfgMinClusterEnergy; + + o2::emcal::Geometry::GetInstanceFromRunNumber(300000); + } + + /// \brief Process EMCAL clusters (either ambigous or unique) + template + OutputType convertForStorage(InputType const& valueIn, Observables observable) + { + double valueToBeChecked = valueIn * downscalingFactors[observable]; + if (valueToBeChecked < std::numeric_limits::lowest()) { + LOG(warning) << "Value " << valueToBeChecked << " of observable " << observable << " below lowest possible value of " << typeid(OutputType).name() << ": " << static_cast(std::numeric_limits::lowest()); + valueToBeChecked = static_cast(std::numeric_limits::lowest()); + } + if (valueToBeChecked > std::numeric_limits::max()) { + LOG(warning) << "Value " << valueToBeChecked << " of observable " << observable << " obove highest possible value of " << typeid(OutputType).name() << ": " << static_cast(std::numeric_limits::max()); + valueToBeChecked = static_cast(std::numeric_limits::max()); + } + + return static_cast(valueToBeChecked); + } + + /// \brief Process EMCAL clusters (either ambigous or unique) + template + void processClusters(Clusters const& clusters, const int bcID) + { + for (const auto& cluster : clusters) { + clusterTable(bcID, + convertForStorage(cluster.definition(), kDefinition), + convertForStorage(cluster.energy(), kEnergy), + convertForStorage(cluster.eta(), kEta), + convertForStorage(cluster.phi(), kPhi), + convertForStorage(cluster.nCells(), kNCells), + convertForStorage(cluster.m02(), kM02), + convertForStorage(cluster.time(), kTime), + cluster.isExotic()); + } + } + + template + void processClusterMCInfo(Clusters const& clusters, const int bcID, aod::McParticles const& mcParticles) + { + for (const auto& cluster : clusters) { + float clusterInducerEnergy = 0.; + int pi0MCIndex = -1; + if (cluster.amplitudeA().size() > 0) { + int clusterInducerId = cluster.mcParticleIds()[0]; + auto clusterInducer = mcParticles.iteratorAt(clusterInducerId); + clusterInducerEnergy = clusterInducer.e(); + int daughterId = aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(clusterInducer, mcParticles, std::vector{111}); + if (daughterId > 0) { + pi0MCIndex = mcParticles.iteratorAt(daughterId).mothersIds()[0]; + } + } + mcclusterTable(bcID, convertForStorage(clusterInducerEnergy, kEnergy), pi0MCIndex); + } + } + + void processEventProperties(const auto& bc, const auto& collisionsInBC, const auto& cellsInBC) + { + float sumAmp = 0.; + for (const auto& cell : cellsInBC) + sumAmp += cell.amplitude(); + mHistManager.fill(HIST("sumAmp"), sumAmp); + mHistManager.fill(HIST("nCells"), cellsInBC.size()); + + bool hasFT0 = bc.has_foundFT0(); + bool hasTVX = bc.selection_bit(aod::evsel::kIsTriggerTVX); + bool haskTVXinEMC = bc.alias_bit(kTVXinEMC); + bool hasEMCCell = cellsInBC.size() > 0; + bool hasNoTFROFBorder = bc.selection_bit(aod::evsel::kNoTimeFrameBorder) && bc.selection_bit(aod::evsel::kNoITSROFrameBorder); + mHistManager.fill(HIST("nBCs"), 0); + if (hasFT0) + mHistManager.fill(HIST("nBCs"), 1); + if (hasTVX) + mHistManager.fill(HIST("nBCs"), 2); + if (haskTVXinEMC) + mHistManager.fill(HIST("nBCs"), 3); + if (hasEMCCell) + mHistManager.fill(HIST("nBCs"), 4); + if (hasNoTFROFBorder) + mHistManager.fill(HIST("nBCs"), 5); + + float ft0Amp = hasFT0 ? bc.foundFT0().sumAmpA() + bc.foundFT0().sumAmpC() : 0.; + + bcTable(hasFT0, hasTVX, haskTVXinEMC, hasEMCCell, hasNoTFROFBorder, convertForStorage(ft0Amp, kFT0Amp), convertForStorage(cellsInBC.size(), kNCells), convertForStorage(sumAmp, kCellAmpSum)); + + for (const auto& collision : collisionsInBC) { + collisionTable(bcTable.lastIndex(), convertForStorage(collision.centFT0M(), kFT0MCent), convertForStorage(collision.posZ(), kZVtx)); + mHistManager.fill(HIST("hAmplitudeVsCentrality"), collision.centFT0M(), ft0Amp); + } + + if (collisionsInBC.size() == 0) + mHistManager.fill(HIST("hAmplitudeVsCentrality"), 103, ft0Amp); + } + + template + bool isGammaGammaDecay(TMCParticle mcParticle, TMCParticles mcParticles) + { + auto daughtersIds = mcParticle.daughtersIds(); + if (daughtersIds.size() != 2) + return false; + for (const auto& daughterId : daughtersIds) { + if (mcParticles.iteratorAt(daughterId).pdgCode() != 22) + return false; + } + return true; + } + + template + bool isAccepted(TMCParticle mcParticle, TMCParticles mcParticles) + { + auto daughtersIds = mcParticle.daughtersIds(); + if (daughtersIds.size() != 2) + return false; + for (const auto& daughterId : daughtersIds) { + if (mcParticles.iteratorAt(daughterId).pdgCode() != 22) + return false; + int iCellID = -1; + try { + iCellID = emcal::Geometry::GetInstance()->GetAbsCellIdFromEtaPhi(mcParticles.iteratorAt(daughterId).eta(), mcParticles.iteratorAt(daughterId).phi()); + } catch (emcal::InvalidPositionException& e) { + iCellID = -1; + } + if (iCellID == -1) + return false; + } + return true; + } + + void processData(MyBCs const& bcs, MyCollisions const& collisions, aod::FT0s const&, SelectedCells const& cells, SelectedUniqueClusters const& uClusters, SelectedAmbiguousClusters const& aClusters) + { + for (const auto& bc : bcs) { + auto collisionsInBC = collisions.sliceBy(perFoundBC, bc.globalIndex()); + auto cellsInBC = cells.sliceBy(cellsPerBC, bc.globalIndex()); + + processEventProperties(bc, collisionsInBC, cellsInBC); + + if (collisionsInBC.size() == 1) { + auto clustersInBC = uClusters.sliceBy(perCol, collisionsInBC.begin().globalIndex()); + processClusters(clustersInBC, bcTable.lastIndex()); + } else { + auto clustersInBC = aClusters.sliceBy(perBC, bc.globalIndex()); + processClusters(clustersInBC, bcTable.lastIndex()); + } + } + } + PROCESS_SWITCH(bcWiseClusterSkimmer, processData, "Run skimming for data", true); + + Preslice mcCollperBC = aod::mccollision::bcId; + Preslice perMcCollision = aod::mcparticle::mcCollisionId; + + void processMC(MyBCs const& bcs, MyMCCollisions const& collisions, aod::McCollisions const& mcCollisions, aod::FT0s const&, SelectedCells const& cells, SelectedUniqueMCClusters const& uClusters, SelectedAmbiguousMCClusters const& aClusters, aod::McParticles const& mcParticles) + { + for (const auto& bc : bcs) { + auto collisionsInBC = collisions.sliceBy(perFoundBC, bc.globalIndex()); + auto cellsInBC = cells.sliceBy(cellsPerBC, bc.globalIndex()); + + processEventProperties(bc, collisionsInBC, cellsInBC); + + auto mcCollisionsBC = mcCollisions.sliceBy(mcCollperBC, bc.globalIndex()); + for (const auto& mcCollision : mcCollisionsBC) { + auto mcParticlesInColl = mcParticles.sliceBy(perMcCollision, mcCollision.globalIndex()); + for (const auto& mcParticle : mcParticlesInColl) { + if (mcParticle.pdgCode() != 111 || fabs(mcParticle.y()) > cfgRapidityCut || !isGammaGammaDecay(mcParticle, mcParticles)) + continue; + bool isPrimary = mcParticle.isPhysicalPrimary() || mcParticle.producedByGenerator(); + bool isFromWD = (aod::pwgem::photonmeson::utils::mcutil::IsFromWD(mcCollision, mcParticle, mcParticles)) > 0; + mcpi0Table(bc.globalIndex(), mcParticle.globalIndex(), convertForStorage(mcParticle.pt(), kpT), isAccepted(mcParticle, mcParticles), isPrimary, isFromWD); + } + } + + if (collisionsInBC.size() == 1) { + auto clustersInBC = uClusters.sliceBy(perCol, collisionsInBC.begin().globalIndex()); + processClusters(clustersInBC, bcTable.lastIndex()); + processClusterMCInfo(clustersInBC, bc.globalIndex(), mcParticles); + } else { + auto clustersInBC = aClusters.sliceBy(perBC, bc.globalIndex()); + processClusters(clustersInBC, bcTable.lastIndex()); + processClusterMCInfo(clustersInBC, bc.globalIndex(), mcParticles); + } + } + } + PROCESS_SWITCH(bcWiseClusterSkimmer, processMC, "Run skimming for MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGEM/PhotonMeson/TableProducer/createEMEvent.cxx b/PWGEM/PhotonMeson/TableProducer/createEMEvent.cxx deleted file mode 100644 index 24c8982a760..00000000000 --- a/PWGEM/PhotonMeson/TableProducer/createEMEvent.cxx +++ /dev/null @@ -1,290 +0,0 @@ -// 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. -// -// ======================== -// -// This code produces reduced events for photon analyses. -// Please write to: daiki.sekihata@cern.ch - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::soa; - -using MyBCs = soa::Join; - -using MyCollisions = soa::Join; -using MyCollisions_Cent = soa::Join; // centrality table has dependency on multiplicity table. -using MyCollisions_Cent_Qvec = soa::Join; - -using MyCollisionsMC = soa::Join; -using MyCollisionsMC_Cent = soa::Join; // centrality table has dependency on multiplicity table. -using MyCollisionsMC_Cent_Qvec = soa::Join; - -struct CreateEMEvent { - Produces event; - Produces event_mult; - Produces event_cent; - Produces event_qvec; - - enum class EMEventType : int { - kEvent = 0, - kEvent_Cent = 1, - kEvent_Cent_Qvec = 2, - }; - - HistogramRegistry registry{"registry"}; - void init(o2::framework::InitContext&) - { - auto hEventCounter = registry.add("hEventCounter", "hEventCounter", kTH1I, {{7, 0.5f, 7.5f}}); - hEventCounter->GetXaxis()->SetBinLabel(1, "all"); - hEventCounter->GetXaxis()->SetBinLabel(2, "sel8"); - } - - PresliceUnsorted preslice_collisions_per_bc = o2::aod::evsel::foundBCId; - std::unordered_map map_ncolls_per_bc; - - //! Please don't skip any event! - template - void skimEvent(TCollisions const& collisions, TBCs const& bcs) - { - // first count the number of collisions per bc - for (auto& bc : bcs) { - auto collisions_per_bc = collisions.sliceBy(preslice_collisions_per_bc, bc.globalIndex()); - map_ncolls_per_bc[bc.globalIndex()] = collisions_per_bc.size(); - // LOGF(info, "bc-loop | bc.globalIndex() = %d , collisions_per_bc.size() = %d", bc.globalIndex(), collisions_per_bc.size()); - } - - for (auto& collision : collisions) { - if constexpr (isMC) { - if (!collision.has_mcCollision()) { - continue; - } - } - auto bc = collision.template foundBC_as(); - - // LOGF(info, "collision-loop | bc.globalIndex() = %d, ncolls_per_bc = %d", bc.globalIndex(), map_ncolls_per_bc[bc.globalIndex()]); - registry.fill(HIST("hEventCounter"), 1); - - if (collision.sel8()) { - registry.fill(HIST("hEventCounter"), 2); - } - - // uint64_t tag = collision.selection_raw(); - event(collision.globalIndex(), bc.globalBC(), bc.runNumber(), collision.sel8(), collision.alias_raw(), collision.selection_raw(), map_ncolls_per_bc[bc.globalIndex()], - collision.posX(), collision.posY(), collision.posZ(), - collision.numContrib(), collision.collisionTime(), collision.collisionTimeRes()); - - event_mult(collision.multFV0A(), collision.multFV0C(), collision.multFT0A(), collision.multFT0C(), collision.multFDDA(), collision.multFDDC(), - collision.multZNA(), collision.multZNC(), - collision.multTPC(), collision.multTracklets(), collision.multNTracksPV(), collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf()); - - if constexpr (eventype == EMEventType::kEvent) { - event_cent(105.f, 105.f, 105.f, 105.f); - event_qvec(999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, - 999.f, 999.f, 999.f, 999.f, - 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, - 999.f, 999.f, 999.f, 999.f); - } else if constexpr (eventype == EMEventType::kEvent_Cent) { - event_cent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()); - event_qvec(999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, - 999.f, 999.f, 999.f, 999.f, - 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, - 999.f, 999.f, 999.f, 999.f); - } else if constexpr (eventype == EMEventType::kEvent_Cent_Qvec) { - event_cent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()); - event_qvec(collision.qvecFT0MRe(), collision.qvecFT0MIm(), collision.qvecFT0ARe(), collision.qvecFT0AIm(), collision.qvecFT0CRe(), collision.qvecFT0CIm(), collision.qvecFV0ARe(), collision.qvecFV0AIm(), - collision.qvecBPosRe(), collision.qvecBPosIm(), collision.qvecBNegRe(), collision.qvecBNegIm(), - 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, - 999.f, 999.f, 999.f, 999.f); // as of 20240416, only 2nd harmonics is supported. - } else { - event_cent(105.f, 105.f, 105.f, 105.f); - event_qvec(999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, - 999.f, 999.f, 999.f, 999.f, - 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, 999.f, - 999.f, 999.f, 999.f, 999.f); - } - } // end of collision loop - map_ncolls_per_bc.clear(); - } // end of skimEvent - - void processEvent(MyCollisions const& collisions, MyBCs const& bcs) - { - skimEvent(collisions, bcs); - } - PROCESS_SWITCH(CreateEMEvent, processEvent, "process event info", false); - - void processEventMC(MyCollisionsMC const& collisions, MyBCs const& bcs) - { - skimEvent(collisions, bcs); - } - PROCESS_SWITCH(CreateEMEvent, processEventMC, "process event info", false); - - void processEvent_Cent(MyCollisions_Cent const& collisions, MyBCs const& bcs) - { - skimEvent(collisions, bcs); - } - PROCESS_SWITCH(CreateEMEvent, processEvent_Cent, "process event info", false); - - void processEvent_Cent_Qvec(MyCollisions_Cent_Qvec const& collisions, MyBCs const& bcs) - { - skimEvent(collisions, bcs); - } - PROCESS_SWITCH(CreateEMEvent, processEvent_Cent_Qvec, "process event info", false); - - void processEventMC_Cent(MyCollisionsMC_Cent const& collisions, MyBCs const& bcs) - { - skimEvent(collisions, bcs); - } - PROCESS_SWITCH(CreateEMEvent, processEventMC_Cent, "process event info", false); - - void processEventMC_Cent_Qvec(MyCollisionsMC_Cent_Qvec const& collisions, MyBCs const& bcs) - { - skimEvent(collisions, bcs); - } - PROCESS_SWITCH(CreateEMEvent, processEventMC_Cent_Qvec, "process event info", false); - - void processDummy(aod::Collisions const&) {} - PROCESS_SWITCH(CreateEMEvent, processDummy, "processDummy", true); -}; -struct AssociatePhotonToEMEvent { - Produces v0kfeventid; - Produces prmeleventid; - Produces prmmueventid; - Produces phoseventid; - Produces emceventid; - - Produces event_ng_pcm; - Produces event_ng_phos; - Produces event_ng_emc; - - Preslice perCollision_pcm = aod::v0photonkf::collisionId; - PresliceUnsorted perCollision_el = aod::emprimaryelectron::collisionId; - PresliceUnsorted perCollision_mu = aod::emprimarymuon::collisionId; - Preslice perCollision_phos = aod::skimmedcluster::collisionId; - Preslice perCollision_emc = aod::skimmedcluster::collisionId; - - bool doPCM = false, doDalitzEE = false, doDalitzMuMu = false, doPHOS = false, doEMC = false; - void init(o2::framework::InitContext& context) - { - if (context.mOptions.get("processPCM")) { - doPCM = true; - } - if (context.mOptions.get("processDalitzEE")) { - doDalitzEE = true; - } - if (context.mOptions.get("processDalitzMuMu")) { - doDalitzMuMu = true; - } - if (context.mOptions.get("processPHOS")) { - doPHOS = true; - } - if (context.mOptions.get("processEMC")) { - doEMC = true; - } - } - - template - void zero_padding(TCollisions const& collisions, TEventNg& event_ng) - { - int nc = collisions.size(); - for (int ic = 0; ic < nc; ic++) { - event_ng(0); - } // end of collision loop - } - - template - void fillEventId_Ng(TCollisions const& collisions, TPhotons const& photons, TEventIds& eventIds, TEventNg& event_ng, TPreslice const& perCollision) - { - for (auto& collision : collisions) { - auto photons_coll = photons.sliceBy(perCollision, collision.collisionId()); - int ng = photons_coll.size(); - for (int ig = 0; ig < ng; ig++) { - eventIds(collision.globalIndex()); - } // end of photon loop - event_ng(ng); - } // end of collision loop - } - - template - void fillEventId(TCollisions const& collisions, TPhotons const& photons, TEventIds& eventIds, TPreslice const& perCollision) - { - for (auto& collision : collisions) { - auto photons_coll = photons.sliceBy(perCollision, collision.collisionId()); - int ng = photons_coll.size(); - for (int ig = 0; ig < ng; ig++) { - eventIds(collision.globalIndex()); - } // end of photon loop - } // end of collision loop - } - - // This struct is for both data and MC. - // Note that reconstructed collisions without mc collisions are already rejected in CreateEMEvent in MC. - - void processPCM(aod::EMEvents const& collisions, aod::V0PhotonsKF const& photons) - { - fillEventId_Ng(collisions, photons, v0kfeventid, event_ng_pcm, perCollision_pcm); - } - - void processDalitzEE(aod::EMEvents const& collisions, aod::EMPrimaryElectrons const& tracks) - { - fillEventId(collisions, tracks, prmeleventid, perCollision_el); - } - - void processDalitzMuMu(aod::EMEvents const& collisions, aod::EMPrimaryMuons const& tracks) - { - fillEventId(collisions, tracks, prmmueventid, perCollision_mu); - } - - void processPHOS(aod::EMEvents const& collisions, aod::PHOSClusters const& photons) - { - fillEventId_Ng(collisions, photons, phoseventid, event_ng_phos, perCollision_phos); - } - - void processEMC(aod::EMEvents const& collisions, aod::SkimEMCClusters const& photons) - { - fillEventId_Ng(collisions, photons, emceventid, event_ng_emc, perCollision_emc); - } - - void processZeroPadding(aod::EMEvents const& collisions) - { - if (!doPCM) { - zero_padding(collisions, event_ng_pcm); - } - if (!doPHOS) { - zero_padding(collisions, event_ng_phos); - } - if (!doEMC) { - zero_padding(collisions, event_ng_emc); - } - } - - PROCESS_SWITCH(AssociatePhotonToEMEvent, processPCM, "process pcm-event indexing", false); - PROCESS_SWITCH(AssociatePhotonToEMEvent, processDalitzEE, "process dalitzee-event indexing", false); - PROCESS_SWITCH(AssociatePhotonToEMEvent, processDalitzMuMu, "process dalitzmumu-event indexing", false); - PROCESS_SWITCH(AssociatePhotonToEMEvent, processPHOS, "process phos-event indexing", false); - PROCESS_SWITCH(AssociatePhotonToEMEvent, processEMC, "process emc-event indexing", false); - PROCESS_SWITCH(AssociatePhotonToEMEvent, processZeroPadding, "process zero padding.", true); -}; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"create-emevent"}), - adaptAnalysisTask(cfgc, TaskName{"associate-photon-to-emevent"}), - }; -} diff --git a/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx b/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx new file mode 100644 index 00000000000..fc155fe5502 --- /dev/null +++ b/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx @@ -0,0 +1,344 @@ +// 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 createEMEventPhoton.cxx +/// \brief This code produces reduced events for photon analyses. +/// +/// \author Daiki Sekihata, daiki.sekihata@cern.ch + +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" + +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "Common/CCDB/TriggerAliases.h" + +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" + +#include "PWGJE/DataModel/Jet.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +using MyBCs = soa::Join; +using MyQvectors = soa::Join; + +using MyCollisions = soa::Join; +using MyCollisionsCent = soa::Join; // centrality table has dependency on multiplicity table. +using MyCollisionsCentQvec = soa::Join; + +using MyCollisionsMC = soa::Join; +using MyCollisionsMCCent = soa::Join; // centrality table has dependency on multiplicity table. +using MyCollisionsMCCentQvec = soa::Join; + +struct CreateEMEventPhoton { + Produces event; + // Produces eventCov; + Produces eventMult; + Produces eventCent; + Produces eventQvec; + Produces eventWeights; + + enum class EMEventType : int { + kEvent = 0, + kEventCent = 1, + kEventCent_Qvec = 2, + kEvent_JJ = 3, + }; + + // CCDB options + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable dBzInput{"d_bz", -999, "bz field, -999 is automatic"}; + Configurable needEMCTrigger{"needEMCTrigger", false, "flag to only save events which have kTVXinEMC trigger bit. To reduce PbPb derived data size"}; + Configurable needPHSTrigger{"needPHSTrigger", false, "flag to only save events which have kTVXinPHOS trigger bit. To reduce PbPb derived data size"}; + Configurable enableJJHistograms{"enableJJHistograms", false, "flag to fill JJ QA histograms for outlier rejection"}; + Configurable maxpTJetOverpTHard{"maxpTJetOverpTHard", 2., "set weight to 0 for JJ events with larger pTJet/pTHard"}; + + HistogramRegistry registry{"registry"}; + void init(o2::framework::InitContext&) + { + auto hEventCounter = registry.add("hEventCounter", "hEventCounter", kTH1I, {{7, 0.5f, 7.5f}}); + hEventCounter->GetXaxis()->SetBinLabel(1, "all"); + hEventCounter->GetXaxis()->SetBinLabel(2, "sel8"); + + if (enableJJHistograms) { + auto hJJ_pTHardVsJetpT = registry.add("hJJ_pTHardVsJetpT", "hJJ_pTHardVsJetpT;#bf{#it{p}_{T}^{hard}};#bf{#it{p}_{T}^{leading jet}}", kTH2F, {{500, 0, 1000}, {500, 0, 1000}}); + } + } + + int mRunNumber; + float dBz; + Service ccdb; + + template + void initCCDB(TBC const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (dBzInput > -990) { + dBz = dBzInput; + o2::parameters::GRPMagField grpmag; + if (std::fabs(dBz) > 1e-5) { + grpmag.setL3Current(30000.f / (dBz / 5.0f)); + } + mRunNumber = bc.runNumber(); + return; + } + + auto run3GRPTimestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3GRPTimestamp); + if (grpo) { + // Fetch magnetic field from ccdb for current collision + dBz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3GRPTimestamp << " with magnetic field of " << dBz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3GRPTimestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3GRPTimestamp; + } + // Fetch magnetic field from ccdb for current collision + dBz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3GRPTimestamp << " with magnetic field of " << dBz << " kZG"; + } + mRunNumber = bc.runNumber(); + } + + template + void skimEvent(TCollisions const& collisions, TBCs const&) + { + for (const auto& collision : collisions) { + if constexpr (isMC) { + if (!collision.has_mcCollision()) { + continue; + } + } + + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!collision.isSelected()) { + continue; + } + if (needEMCTrigger && !collision.alias_bit(kTVXinEMC)) { + continue; + } + if (needPHSTrigger && !collision.alias_bit(kTVXinPHOS)) { + continue; + } + + const float qDefault = 999.f; // default value for q vectors if not obtained + + registry.fill(HIST("hEventCounter"), 1); + + if (collision.sel8()) { + registry.fill(HIST("hEventCounter"), 2); + } + + event(collision.globalIndex(), bc.runNumber(), bc.globalBC(), collision.alias_raw(), collision.selection_raw(), collision.rct_raw(), bc.timestamp(), + collision.posX(), collision.posY(), collision.posZ(), + collision.numContrib(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + + // eventCov(collision.covXX(), collision.covXY(), collision.covXZ(), collision.covYY(), collision.covYZ(), collision.covZZ(), collision.chi2()); + + eventMult(collision.multFT0A(), collision.multFT0C(), collision.multNTracksPV(), collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf()); + + if constexpr (eventype != EMEventType::kEvent_JJ) { + eventWeights(1.f); + } + + if constexpr (eventype == EMEventType::kEvent) { + eventCent(105.f, 105.f, 105.f); + eventQvec(qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, + qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault); + } else if constexpr (eventype == EMEventType::kEventCent) { + eventCent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C()); + eventQvec(qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, + qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault); + } else if constexpr (eventype == EMEventType::kEventCent_Qvec) { + eventCent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C()); + const size_t qvecSize = collision.qvecFT0CReVec().size(); + if (qvecSize >= 2) { // harmonics 2,3 + eventQvec(collision.qvecFT0MReVec()[0], collision.qvecFT0MImVec()[0], collision.qvecFT0AReVec()[0], collision.qvecFT0AImVec()[0], collision.qvecFT0CReVec()[0], collision.qvecFT0CImVec()[0], collision.qvecBPosReVec()[0], collision.qvecBPosImVec()[0], collision.qvecBNegReVec()[0], collision.qvecBNegImVec()[0], collision.qvecBTotReVec()[0], collision.qvecBTotImVec()[0], + collision.qvecFT0MReVec()[1], collision.qvecFT0MImVec()[1], collision.qvecFT0AReVec()[1], collision.qvecFT0AImVec()[1], collision.qvecFT0CReVec()[1], collision.qvecFT0CImVec()[1], collision.qvecBPosReVec()[1], collision.qvecBPosImVec()[1], collision.qvecBNegReVec()[1], collision.qvecBNegImVec()[1], collision.qvecBTotReVec()[1], collision.qvecBTotImVec()[1]); + } else if (qvecSize >= 1) { // harmonics 2 + eventQvec(collision.qvecFT0MReVec()[0], collision.qvecFT0MImVec()[0], collision.qvecFT0AReVec()[0], collision.qvecFT0AImVec()[0], collision.qvecFT0CReVec()[0], collision.qvecFT0CImVec()[0], collision.qvecBPosReVec()[0], collision.qvecBPosImVec()[0], collision.qvecBNegReVec()[0], collision.qvecBNegImVec()[0], collision.qvecBTotReVec()[0], collision.qvecBTotImVec()[0], + qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault); + } + } else { + eventCent(105.f, 105.f, 105.f); + eventQvec(qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, + qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault, qDefault); + } + } // end of collision loop + + } // end of skimEvent + + Preslice perCollision_jet = aod::jet::mcCollisionId; + + using MyJJCollisions = soa::Join; + + void fillEventWeights(MyCollisionsMC const& collisions, MyJJCollisions const&, MyBCs const&, aod::FullMCParticleLevelJets const& jets) + { + for (const auto& collision : collisions) { + if (!collision.has_mcCollision()) { + continue; + } + if (!collision.isSelected()) { + continue; + } + + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + auto mcCollision = collision.mcCollision_as(); + + // Outlier rejection: Set weight to 0 for events with large pTJet/pTHard + // ---------------------------------------------------------------------- + auto jetsInThisCollision = jets.sliceBy(perCollision_jet, mcCollision.globalIndex()); + float collisionWeight = mcCollision.weight(); + for (const auto& jet : jetsInThisCollision) { + if (jet.pt() > maxpTJetOverpTHard * mcCollision.ptHard()) + collisionWeight = 0.f; + registry.fill(HIST("hJJ_pTHardVsJetpT"), mcCollision.ptHard(), jet.pt()); + } + + eventWeights(collisionWeight); + } + } + + void processEvent(MyCollisions const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(CreateEMEventPhoton, processEvent, "process event info", false); + + void processEventMC(MyCollisionsMC const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(CreateEMEventPhoton, processEventMC, "process event info", false); + + void processEventJJMC(MyCollisionsMC const& collisions, MyJJCollisions const& mcCollisions, MyBCs const& bcs, aod::FullMCParticleLevelJets const& jets) + { + skimEvent(collisions, bcs); + fillEventWeights(collisions, mcCollisions, bcs, jets); + } + PROCESS_SWITCH(CreateEMEventPhoton, processEventJJMC, "process event info", false); + + void processEvent_Cent(MyCollisionsCent const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(CreateEMEventPhoton, processEvent_Cent, "process event info", false); + + void processEvent_Cent_Qvec(MyCollisionsCentQvec const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(CreateEMEventPhoton, processEvent_Cent_Qvec, "process event info", false); + + void processEventMC_Cent(MyCollisionsMCCent const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(CreateEMEventPhoton, processEventMC_Cent, "process event info", false); + + void processEventMC_Cent_Qvec(MyCollisionsMCCentQvec const& collisions, MyBCs const& bcs) + { + skimEvent(collisions, bcs); + } + PROCESS_SWITCH(CreateEMEventPhoton, processEventMC_Cent_Qvec, "process event info", false); + + void processDummy(aod::Collisions const&) {} + PROCESS_SWITCH(CreateEMEventPhoton, processDummy, "processDummy", true); +}; +struct AssociatePhotonToEMEvent { + Produces v0kfeventid; + Produces prmeleventid; + Produces prmmueventid; + Produces phoseventid; + Produces emceventid; + + Preslice perCollisionPCM = aod::v0photonkf::collisionId; + PresliceUnsorted perCollisionEl = aod::emprimaryelectron::collisionId; + Preslice perCollisionPHOS = aod::skimmedcluster::collisionId; + Preslice perCollisionEMC = aod::skimmedcluster::collisionId; + + void init(o2::framework::InitContext&) {} + + template + void fillEventId(TCollisions const& collisions, TPhotons const& photons, TEventIds& eventIds, TPreslice const& perCollision) + { + for (const auto& collision : collisions) { + auto photonsColl = photons.sliceBy(perCollision, collision.collisionId()); + int ng = photonsColl.size(); + for (int ig = 0; ig < ng; ig++) { + eventIds(collision.globalIndex()); + } // end of photon loop + } // end of collision loop + } + + // This struct is for both data and MC. + // Note that reconstructed collisions without mc collisions are already rejected in CreateEMEventPhoton in MC. + + void processPCM(aod::EMEvents const& collisions, aod::V0PhotonsKF const& photons) + { + fillEventId(collisions, photons, v0kfeventid, perCollisionPCM); + } + + void processElectronFromDalitz(aod::EMEvents const& collisions, aod::EMPrimaryElectronsFromDalitz const& tracks) + { + fillEventId(collisions, tracks, prmeleventid, perCollisionEl); + } + + void processPHOS(aod::EMEvents const& collisions, aod::PHOSClusters const& photons) + { + fillEventId(collisions, photons, phoseventid, perCollisionPHOS); + } + + void processEMC(aod::EMEvents const& collisions, aod::SkimEMCClusters const& photons) + { + fillEventId(collisions, photons, emceventid, perCollisionEMC); + } + + void processDummy(aod::EMEvents const&) {} + + PROCESS_SWITCH(AssociatePhotonToEMEvent, processPCM, "process pcm-event indexing", false); + PROCESS_SWITCH(AssociatePhotonToEMEvent, processElectronFromDalitz, "process dalitzee-event indexing", false); + PROCESS_SWITCH(AssociatePhotonToEMEvent, processPHOS, "process phos-event indexing", false); + PROCESS_SWITCH(AssociatePhotonToEMEvent, processEMC, "process emc-event indexing", false); + PROCESS_SWITCH(AssociatePhotonToEMEvent, processDummy, "process dummy", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"create-emevent-photon"}), + adaptAnalysisTask(cfgc, TaskName{"associate-photon-to-emevent"}), + }; +} diff --git a/PWGEM/PhotonMeson/TableProducer/createPCM.cxx b/PWGEM/PhotonMeson/TableProducer/createPCM.cxx index ed7383727d4..f8ba87d2cbc 100644 --- a/PWGEM/PhotonMeson/TableProducer/createPCM.cxx +++ b/PWGEM/PhotonMeson/TableProducer/createPCM.cxx @@ -49,7 +49,7 @@ struct createPCM { SliceCache cache; Preslice perCol = o2::aod::track::collisionId; Produces v0indices; - Produces v0cores; + Produces v0cores; Produces v0trackXs; // Basic checks diff --git a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx index d31486d0571..b8c46daa494 100644 --- a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx +++ b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx @@ -21,6 +21,11 @@ #include #include #include +#include +#include +#include +#include +#include #include "Math/Vector4D.h" @@ -39,6 +44,8 @@ #include "DataFormatsParameters/GRPObject.h" #include "DataFormatsParameters/GRPMagField.h" #include "CCDB/BasicCCDBManager.h" +#include "Common/Core/TableHelper.h" +#include "Common/Core/TPCVDriftManager.h" #include "Tools/KFparticle/KFUtilities.h" @@ -54,7 +61,8 @@ using namespace o2::constants::physics; using namespace o2::pwgem::photonmeson; using std::array; -using MyCollisions = aod::Collisions; +using MyCollisions = soa::Join; +using MyCollisionsWithSWT = soa::Join; using MyCollisionsMC = soa::Join; using MyTracksIU = soa::Join; @@ -62,7 +70,9 @@ using MyTracksIUMC = soa::Join; struct PhotonConversionBuilder { Produces v0photonskf; + Produces v0photonskfcov; Produces v0legs; + Produces events_ngpcm; // CCDB options Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -77,17 +87,22 @@ struct PhotonConversionBuilder { Configurable useMatCorrType{"useMatCorrType", 0, "0: none, 1: TGeo, 2: LUT"}; // single track cuts - Configurable min_ncluster_tpc{"min_ncluster_tpc", 10, "min ncluster tpc"}; - Configurable mincrossedrows{"mincrossedrows", 10, "min crossed rows"}; + Configurable min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable mincrossedrows{"mincrossedrows", 40, "min crossed rows"}; + Configurable moveTPCTracks{"moveTPCTracks", true, "Move TPC-only tracks under the collision assumption"}; + Configurable disableITSonlyTracks{"disableITSonlyTracks", false, "disable ITSonly tracks in V0 legs"}; + Configurable disableTPConlyTracks{"disableTPConlyTracks", false, "disable TPConly tracks in V0 legs"}; + Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max chi2/NclsTPC"}; // default 4.0 + 1.0 Configurable maxchi2its{"maxchi2its", 6.0, "max chi2/NclsITS"}; // default 5.0 + 1.0 Configurable maxpt_itsonly{"maxpt_itsonly", 0.15, "max pT for ITSonly tracks at SV"}; Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", 4.0, "max. TPC n sigma for electron"}; + Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -4.0, "min. TPC n sigma for electron"}; + Configurable max_frac_shared_clusters_tpc{"max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; Configurable dcanegtopv{"dcanegtopv", 0.1, "DCA Neg To PV"}; Configurable dcapostopv{"dcapostopv", 0.1, "DCA Pos To PV"}; - Configurable min_pt_leg{"min_pt_leg", 0.04, "min pT for v0 legs at SV"}; - Configurable max_mean_its_cluster_size{"max_mean_its_cluster_size", 16.f, "max. x cos(lambda) for ITSonly tracks"}; // this is to suppress random combination for V0s with ITSonly tracks. default 3 + 1 for skimming. Configurable maxX{"maxX", 83.1, "max X for track IU"}; + Configurable min_pt_trackiu{"min_pt_trackiu", 0.05, "min pT for trackiu"}; // this comes from online processing. pT of track seed is above 50 MeV/c in B = 0.5 T, 20 MeV/c in B = 0.2 T. // v0 cuts Configurable min_v0cospa_tpconly{"min_v0cospa_tpconly", 0.99, "min V0 CosPA to V0s with TPConly tracks"}; // double -> N.B. dcos(x)/dx = 0 at x=0) @@ -97,21 +112,23 @@ struct PhotonConversionBuilder { Configurable max_dcav0dau_itsibss{"max_dcav0dau_itsibss", 1.0, "max distance btween 2 legs to V0s with ITS hits on ITSib SS"}; Configurable max_dcav0dau_tpc_inner_fc{"max_dcav0dau_tpc_inner_fc", 1.5, "max distance btween 2 legs to V0s with ITS hits on TPC inner FC"}; Configurable min_v0radius{"min_v0radius", 1.0, "min v0 radius"}; + Configurable max_v0radius{"max_v0radius", 90.0, "max v0 radius"}; Configurable margin_r_its{"margin_r_its", 3.0, "margin for r cut in cm"}; Configurable margin_r_tpc{"margin_r_tpc", 7.0, "margin for r cut in cm"}; Configurable margin_r_itstpc_tpc{"margin_r_itstpc_tpc", 7.0, "margin for r cut in cm"}; Configurable margin_z{"margin_z", 7.0, "margin for z cut in cm"}; Configurable max_alpha_ap{"max_alpha_ap", 0.95, "max alpha for AP cut"}; Configurable max_qt_ap{"max_qt_ap", 0.01, "max qT for AP cut"}; - Configurable min_pt_v0{"min_pt_v0", 0.05, "min pT for v0 photons at PV"}; + Configurable min_pt_v0{"min_pt_v0", 0.1, "min pT for v0 photons at PV"}; Configurable max_pt_v0_itsonly{"max_pt_v0_itsonly", 0.3, "max pT for v0 photons wth 2 ITSonly tracks at PV"}; Configurable max_eta_v0{"max_eta_v0", 0.9, "max eta for v0 photons at PV"}; Configurable kfMassConstrain{"kfMassConstrain", -1.f, "mass constrain for the KFParticle mother particle"}; Configurable max_r_req_its{"max_r_req_its", 16.0, "max Rxy for V0 with ITS hits"}; - Configurable min_r_tpconly{"min_r_tpconly", 36.0, "min Rxy for V0 with TPConly tracks"}; + Configurable min_r_tpconly{"min_r_tpconly", 32.0, "min Rxy for V0 with TPConly tracks"}; Configurable max_r_itsmft_ss{"max_r_itsmft_ss", 66.0, "max Rxy for ITS/MFT SS"}; Configurable max_dcatopv_xy_v0{"max_dcatopv_xy_v0", +1e+10, "max. DCAxy to PV for V0"}; Configurable max_dcatopv_z_v0{"max_dcatopv_z_v0", +1e+10, "max. DCAz to PV for V0"}; + Configurable reject_v0_on_itsib{"reject_v0_on_itsib", true, "flag to reject v0s on ITSib"}; int mRunNumber; float d_bz; @@ -120,6 +137,7 @@ struct PhotonConversionBuilder { Service ccdb; o2::base::MatLayerCylSet* lut = nullptr; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + o2::aod::common::TPCVDriftManager mVDriftMgr; HistogramRegistry registry{ "registry", @@ -129,14 +147,14 @@ struct PhotonConversionBuilder { {"V0/hConversionPointXY", "conversion point in XY;X (cm);Y (cm)", {HistType::kTH2F, {{400, -100.0f, 100.0f}, {400, -100.f, 100.f}}}}, {"V0/hConversionPointRZ", "conversion point in RZ;Z (cm);R_{xy} (cm)", {HistType::kTH2F, {{200, -100.0f, 100.0f}, {200, 0.f, 100.f}}}}, {"V0/hPt", "pT of V0 at PV;p_{T,#gamma} (GeV/c)", {HistType::kTH1F, {{1000, 0.0f, 10.0f}}}}, - {"V0/hEtaPhi", "#eta vs. #varphi of V0 at PV;#varphi (rad.);#eta", {HistType::kTH2F, {{72, 0.0f, 2 * M_PI}, {400, -2, +2}}}}, - {"V0/hCosPA", "cosine of pointing angle;cosine of pointing angle", {HistType::kTH1F, {{100, 0.9f, 1.f}}}}, - {"V0/hCosPA_Rxy", "cosine of pointing angle;r_{xy} (cm);cosine of pointing angle", {HistType::kTH2F, {{200, 0, 100}, {100, 0.9f, 1.f}}}}, - {"V0/hCosPAXY_Rxy", "cosine of pointing angle;r_{xy} (cm);cosine of pointing angle", {HistType::kTH2F, {{200, 0, 100}, {100, 0.9f, 1.f}}}}, - {"V0/hCosPARZ_Rxy", "cosine of pointing angle;r_{xy} (cm);cosine of pointing angle", {HistType::kTH2F, {{200, 0, 100}, {100, 0.9f, 1.f}}}}, + {"V0/hEtaPhi", "#eta vs. #varphi of V0 at PV;#varphi (rad.);#eta", {HistType::kTH2F, {{72, 0.0f, 2 * M_PI}, {200, -1, +1}}}}, + {"V0/hCosPA", "cosine of pointing angle;cosine of pointing angle", {HistType::kTH1F, {{100, 0.99f, 1.f}}}}, + {"V0/hCosPA_Rxy", "cosine of pointing angle;r_{xy} (cm);cosine of pointing angle", {HistType::kTH2F, {{200, 0, 100}, {100, 0.99f, 1.f}}}}, + {"V0/hCosPAXY_Rxy", "cosine of pointing angle;r_{xy} (cm);cosine of pointing angle", {HistType::kTH2F, {{200, 0, 100}, {100, 0.99f, 1.f}}}}, + {"V0/hCosPARZ_Rxy", "cosine of pointing angle;r_{xy} (cm);cosine of pointing angle", {HistType::kTH2F, {{200, 0, 100}, {100, 0.99f, 1.f}}}}, {"V0/hPCA", "distance between 2 legs at SV;PCA (cm)", {HistType::kTH1F, {{500, 0.0f, 5.f}}}}, {"V0/hPCA_Rxy", "distance between 2 legs at SV;R_{xy} (cm);PCA (cm)", {HistType::kTH2F, {{200, 0, 100}, {500, 0.0f, 5.f}}}}, - {"V0/hPCA_CosPA", "distance between 2 legs at SV vs. cosPA;cosine of pointing angle;PCA (cm)", {HistType::kTH2F, {{100, 0.9, 1}, {500, 0.0f, 5.f}}}}, + {"V0/hPCA_CosPA", "distance between 2 legs at SV vs. cosPA;cosine of pointing angle;PCA (cm)", {HistType::kTH2F, {{100, 0.99, 1}, {500, 0.0f, 5.f}}}}, {"V0/hDCAxyz", "DCA to PV;DCA_{xy} (cm);DCA_{z} (cm)", {HistType::kTH2F, {{200, -5.f, +5.f}, {200, -5.f, +5.f}}}}, {"V0/hMeeSV_Rxy", "mee at SV vs. R_{xy};R_{xy} (cm);m_{ee} at SV (GeV/c^{2})", {HistType::kTH2F, {{200, 0.0f, 100.f}, {100, 0, 0.1f}}}}, {"V0/hRxy_minX_ITSonly_ITSonly", "min trackiu X vs. R_{xy};trackiu X (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{100, 0.0f, 100.f}, {100, -50.0, 50.0f}}}}, @@ -146,10 +164,12 @@ struct PhotonConversionBuilder { {"V0/hRxy_minX_TPC_TPC", "min trackiu X vs. R_{xy};trackiu X (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{100, 0.0f, 100.f}, {100, -50.0, 50.0f}}}}, {"V0/hPCA_diffX", "PCA vs. trackiu X - R_{xy};distance btween 2 legs (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{500, 0.0f, 5.f}, {100, -50.0, 50.0f}}}}, {"V0Leg/hPt", "pT of leg at SV;p_{T,e} (GeV/c)", {HistType::kTH1F, {{1000, 0.0f, 10.0f}}}}, - {"V0Leg/hEtaPhi", "#eta vs. #varphi of leg at SV;#varphi (rad.);#eta", {HistType::kTH2F, {{72, 0.0f, 2 * M_PI}, {400, -2, +2}}}}, + {"V0Leg/hEtaPhi", "#eta vs. #varphi of leg at SV;#varphi (rad.);#eta", {HistType::kTH2F, {{72, 0.0f, 2 * M_PI}, {200, -1, +1}}}}, + {"V0Leg/hRelDeltaPt", "pT resolution;p_{T} (GeV/c);#Deltap_{T}/p_{T}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, 0, 1}}}}, {"V0Leg/hDCAxyz", "DCA xy vs. z to PV;DCA_{xy} (cm);DCA_{z} (cm)", {HistType::kTH2F, {{200, -50.f, 50.f}, {200, -50.f, +50.f}}}}, {"V0Leg/hdEdx_Pin", "TPC dE/dx vs. p_{in};p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{1000, 0.f, 10.f}, {200, 0.f, 200.f}}}}, {"V0Leg/hTPCNsigmaEl", "TPC dE/dx vs. p_{in};p_{in} (GeV/c);n #sigma_{e}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5.f, +5.f}}}}, + {"V0Leg/hXZ", "track iu x vs. z;z (cm);x (cm)", {HistType::kTH2F, {{200, -100.f, 100.f}, {200, 0.f, 100.f}}}}, }}; void init(InitContext&) @@ -175,10 +195,12 @@ struct PhotonConversionBuilder { lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); } - if (useMatCorrType == 1) + if (useMatCorrType == 1) { matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; - if (useMatCorrType == 2) + } + if (useMatCorrType == 2) { matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + } } void initCCDB(aod::BCsWithTimestamps::iterator const& bc) @@ -191,7 +213,7 @@ struct PhotonConversionBuilder { if (d_bz_input > -990) { d_bz = d_bz_input; o2::parameters::GRPMagField grpmag; - if (fabs(d_bz) > 1e-5) { + if (std::fabs(d_bz) > 1e-5) { grpmag.setL3Current(30000.f / (d_bz / 5.0f)); } o2::base::Propagator::initFieldFromGRP(&grpmag); @@ -200,18 +222,19 @@ struct PhotonConversionBuilder { } auto run3grp_timestamp = bc.timestamp(); - o2::parameters::GRPObject* grpo = 0x0; - o2::parameters::GRPMagField* grpmag = 0x0; - if (!skipGRPOquery) + o2::parameters::GRPObject* grpo = nullptr; + o2::parameters::GRPMagField* grpmag = nullptr; + if (!skipGRPOquery) { grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); - if (grpo) { + } + if (grpo != nullptr) { o2::base::Propagator::initFieldFromGRP(grpo); // Fetch magnetic field from ccdb for current collision d_bz = grpo->getNominalL3Field(); LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; } else { grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); - if (!grpmag) { + if (grpmag == nullptr) { LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; } o2::base::Propagator::initFieldFromGRP(grpmag); @@ -226,8 +249,17 @@ struct PhotonConversionBuilder { o2::base::Propagator::Instance()->setMatLUT(lut); } /// Set magnetic field for KF vertexing - float magneticField = o2::base::Propagator::Instance()->getNominalBz(); + const float magneticField = o2::base::Propagator::Instance()->getNominalBz(); KFParticle::SetField(magneticField); + + mVDriftMgr.init(&ccdb->instance()); + } + + void updateCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + auto timestamp = bc.timestamp(); + + mVDriftMgr.update(timestamp); } std::pair> its_ib_Requirement = {0, {0, 1, 2}}; // no hit on 3 ITS ib layers. @@ -240,6 +272,14 @@ struct PhotonConversionBuilder { } } + if (disableITSonlyTracks && isITSonlyTrack(track)) { + return false; + } + + if (disableTPConlyTracks && isTPConlyTrack(track)) { + return false; + } + if (track.x() > maxX) { return false; } @@ -259,7 +299,10 @@ struct PhotonConversionBuilder { if (track.tpcNClsCrossedRows() < mincrossedrows || track.tpcChi2NCl() > maxchi2tpc) { return false; } - if (abs(track.tpcNSigmaEl()) > maxTPCNsigmaEl) { + if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { + return false; + } + if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { return false; } } @@ -269,23 +312,10 @@ struct PhotonConversionBuilder { return false; } - auto hits_ib = std::count_if(its_ib_Requirement.second.begin(), its_ib_Requirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); - bool its_ob_only = hits_ib <= its_ib_Requirement.first; - if (!its_ob_only) { - return false; - } - - if (isITSonlyTrack(track)) { - uint32_t itsClusterSizes = track.itsClusterSizes(); - int total_cluster_size = 0, nl = 0; - for (unsigned int layer = 0; layer < 7; layer++) { - int cluster_size_per_layer = (itsClusterSizes >> (layer * 4)) & 0xf; - if (cluster_size_per_layer > 0) { - nl++; - } - total_cluster_size += cluster_size_per_layer; - } - if (static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(track.tgl())) > max_mean_its_cluster_size) { + if (reject_v0_on_itsib) { + auto hits_ib = std::count_if(its_ib_Requirement.second.begin(), its_ib_Requirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); + bool its_ob_only = hits_ib <= its_ib_Requirement.first; + if (!its_ob_only) { return false; } } @@ -329,30 +359,35 @@ struct PhotonConversionBuilder { return cospaRZ; } - template - void fillTrackTable(TTrack const& track, TKFParticle const& kfp, float dcaXY, float dcaZ) + template + void fillTrackTable(TTrack const& track, TShiftedTrack const& shiftedtrack, TKFParticle const& kfp, const float dcaXY, const float dcaZ) { v0legs(track.collisionId(), track.globalIndex(), track.sign(), kfp.GetPx(), kfp.GetPy(), kfp.GetPz(), dcaXY, dcaZ, - track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), + track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), track.tpcNClsShared(), track.tpcChi2NCl(), track.tpcInnerParam(), track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaPi(), track.itsClusterSizes(), track.itsChi2NCl(), track.detectorMap(), - track.x(), track.y(), track.z(), track.tgl()); + shiftedtrack.getX(), shiftedtrack.getY(), shiftedtrack.getZ(), shiftedtrack.getTgl()); } - template + template void fillV0Table(TV0 const& v0, const bool filltable) { // Get tracks - auto pos = v0.template posTrack_as(); - auto ele = v0.template negTrack_as(); - auto collision = v0.template collision_as(); // collision where this v0 belongs to. + const auto& pos = v0.template posTrack_as(); + const auto& ele = v0.template negTrack_as(); + const auto& collision = v0.template collision_as(); // collision where this v0 belongs to. + // LOGF(info, "v0.collisionId() = %d, pos.collisionId() = %d, ele.collisionId() = %d", v0.collisionId(), pos.collisionId(), ele.collisionId()); if (pos.sign() * ele.sign() > 0) { // reject same sign pair return; } + if (pos.pt() < min_pt_trackiu || ele.pt() < min_pt_trackiu) { + return; + } + if (pos.globalIndex() == ele.globalIndex()) { return; } @@ -360,6 +395,7 @@ struct PhotonConversionBuilder { if (isITSonlyTrack(pos) && !ele.hasITS()) { return; } + if (isITSonlyTrack(ele) && !pos.hasITS()) { return; } @@ -367,37 +403,55 @@ struct PhotonConversionBuilder { if (!checkV0leg(pos) || !checkV0leg(ele)) { return; } + // LOGF(info, "v0.collisionId() = %d , v0.posTrackId() = %d , v0.negTrackId() = %d", v0.collisionId(), v0.posTrackId(), v0.negTrackId()); + // if(isTPConlyTrack(ele)){ + // // LOGF(info, "TPConly: ele.globalIndex() = %d, ele.x() = %f, ele.y() = %f, ele.z() = %f, ele.tgl() = %f, ele.alpha() = %f, ele.snp() = %f, ele.signed1Pt() = %f", ele.globalIndex(), ele.x(), ele.y(), ele.z(), ele.tgl(), ele.alpha(), ele.snp(), ele.signed1Pt()); + // // LOGF(info, "TPConly: ele.globalIndex() = %d, ele.cYY() = %f, ele.cZY() = %f, ele.cZZ() = %f, ele.cSnpY() = %f, ele.cSnpZ() = %f, ele.cSnpSnp() = %f, ele.cTglY() = %f, ele.cTglZ() = %f, ele.cTglSnp() = %f, ele.cTglTgl() = %f, ele.c1PtY() = %f, ele.c1PtZ() = %f, ele.c1PtSnp() = %f, ele.c1PtTgl() = %f, ele.c1Pt21Pt2() = %f", ele.globalIndex(), ele.cYY(), ele.cZY(), ele.cZZ(), ele.cSnpY(), ele.cSnpZ(), ele.cSnpSnp(), ele.cTglY(), ele.cTglZ(), ele.cTglSnp(), ele.cTglTgl(), ele.c1PtY(), ele.c1PtZ(), ele.c1PtSnp(), ele.c1PtTgl(), ele.c1Pt21Pt2()); + // } + // Calculate DCA with respect to the collision associated to the v0, not individual tracks gpu::gpustd::array dcaInfo; - auto pTrack = getTrackPar(pos); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrack, 2.f, matCorr, &dcaInfo); + auto pTrack = getTrackParCov(pos); + if (moveTPCTracks && isTPConlyTrack(pos) && !mVDriftMgr.moveTPCTrack(collision, pos, pTrack)) { + LOGP(error, "failed correction for positive tpc track"); + return; + } + auto pTrackC = pTrack; + pTrackC.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackC, 2.f, matCorr, &dcaInfo); auto posdcaXY = dcaInfo[0]; auto posdcaZ = dcaInfo[1]; - auto nTrack = getTrackPar(ele); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrack, 2.f, matCorr, &dcaInfo); + auto nTrack = getTrackParCov(ele); + if (moveTPCTracks && isTPConlyTrack(ele) && !mVDriftMgr.moveTPCTrack(collision, ele, nTrack)) { + LOGP(error, "failed correction for negative tpc track"); + return; + } + auto nTrackC = nTrack; + nTrackC.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackC, 2.f, matCorr, &dcaInfo); auto eledcaXY = dcaInfo[0]; auto eledcaZ = dcaInfo[1]; - if (fabs(posdcaXY) < dcapostopv || fabs(eledcaXY) < dcanegtopv) { + if (std::fabs(posdcaXY) < dcapostopv || std::fabs(eledcaXY) < dcanegtopv) { return; } float xyz[3] = {0.f, 0.f, 0.f}; - Vtx_recalculation(o2::base::Propagator::Instance(), pos, ele, xyz, matCorr); + Vtx_recalculationParCov(o2::base::Propagator::Instance(), pTrack, nTrack, xyz, matCorr); float rxy_tmp = RecoDecay::sqrtSumOfSquares(xyz[0], xyz[1]); if (rxy_tmp > maxX + margin_r_tpc) { return; } - if (rxy_tmp < abs(xyz[2]) * TMath::Tan(2 * TMath::ATan(TMath::Exp(-max_eta_v0))) - margin_z) { + if (rxy_tmp < std::fabs(xyz[2]) * std::tan(2 * std::atan(std::exp(-max_eta_v0))) - margin_z) { return; // RZ line cut } - KFPTrack kfp_track_pos = createKFPTrackFromTrack(pos); - KFPTrack kfp_track_ele = createKFPTrackFromTrack(ele); + KFPTrack kfp_track_pos = createKFPTrackFromTrackParCov(pTrack, pos.sign(), pos.tpcNClsFound(), pos.tpcChi2NCl()); + KFPTrack kfp_track_ele = createKFPTrackFromTrackParCov(nTrack, ele.sign(), ele.tpcNClsFound(), ele.tpcChi2NCl()); KFParticle kfp_pos(kfp_track_pos, -11); KFParticle kfp_ele(kfp_track_ele, 11); const KFParticle* GammaDaughters[2] = {&kfp_pos, &kfp_ele}; @@ -430,39 +484,39 @@ struct PhotonConversionBuilder { if (rxy > maxX + margin_r_tpc) { return; } - if (rxy < abs(gammaKF_DecayVtx.GetZ()) * TMath::Tan(2 * TMath::ATan(TMath::Exp(-max_eta_v0))) - margin_z) { + if (rxy < std::fabs(gammaKF_DecayVtx.GetZ()) * std::tan(2 * std::atan(std::exp(-max_eta_v0))) - margin_z) { return; // RZ line cut } - if (rxy < min_v0radius) { + if (rxy < min_v0radius || max_v0radius < rxy) { return; } if (!filltable) { if (isITSTPCTrack(pos) && isITSTPCTrack(ele)) { - registry.fill(HIST("V0/hRxy_minX_ITSTPC_ITSTPC"), std::min(pos.x(), ele.x()), std::min(pos.x(), ele.x()) - rxy); // trackiu.x() - rxy should be positive + registry.fill(HIST("V0/hRxy_minX_ITSTPC_ITSTPC"), std::min(pTrack.getX(), nTrack.getX()), std::min(pTrack.getX(), nTrack.getX()) - rxy); // trackiu.x() - rxy should be positive } else if (isITSonlyTrack(pos) && isITSonlyTrack(ele)) { - registry.fill(HIST("V0/hRxy_minX_ITSonly_ITSonly"), std::min(pos.x(), ele.x()), std::min(pos.x(), ele.x()) - rxy); // trackiu.x() - rxy should be positive + registry.fill(HIST("V0/hRxy_minX_ITSonly_ITSonly"), std::min(pTrack.getX(), nTrack.getX()), std::min(pTrack.getX(), nTrack.getX()) - rxy); // trackiu.x() - rxy should be positive } else if ((isITSTPCTrack(pos) && isITSonlyTrack(ele)) || (isITSTPCTrack(ele) && isITSonlyTrack(pos))) { - registry.fill(HIST("V0/hRxy_minX_ITSTPC_ITSonly"), std::min(pos.x(), ele.x()), std::min(pos.x(), ele.x()) - rxy); // trackiu.x() - rxy should be positive + registry.fill(HIST("V0/hRxy_minX_ITSTPC_ITSonly"), std::min(pTrack.getX(), nTrack.getX()), std::min(pTrack.getX(), nTrack.getX()) - rxy); // trackiu.x() - rxy should be positive } else if (isITSTPCTrack(pos) && !ele.hasITS()) { - registry.fill(HIST("V0/hRxy_minX_ITSTPC_TPC"), std::min(pos.x(), 83.f), std::min(pos.x(), 83.f) - rxy); // trackiu.x() - rxy should be positive + registry.fill(HIST("V0/hRxy_minX_ITSTPC_TPC"), std::min(pTrack.getX(), 83.f), std::min(pTrack.getX(), 83.f) - rxy); // trackiu.x() - rxy should be positive } else if (isITSTPCTrack(ele) && !pos.hasITS()) { - registry.fill(HIST("V0/hRxy_minX_ITSTPC_TPC"), std::min(ele.x(), 83.f), std::min(ele.x(), 83.f) - rxy); // trackiu.x() - rxy should be positive + registry.fill(HIST("V0/hRxy_minX_ITSTPC_TPC"), std::min(nTrack.getX(), 83.f), std::min(nTrack.getX(), 83.f) - rxy); // trackiu.x() - rxy should be positive } else { registry.fill(HIST("V0/hRxy_minX_TPC_TPC"), std::min(83.f, 83.f), std::min(83.f, 83.f) - rxy); // trackiu.x() - rxy should be positive } } if (pos.hasITS() && ele.hasITS()) { // ITSonly-ITSonly, ITSTPC-ITSTPC, ITSTPC-ITSonly - if (rxy > std::min(pos.x(), ele.x()) + margin_r_its) { + if (rxy > std::min(pTrack.getX(), nTrack.getX()) + margin_r_its) { return; } } else if (!pos.hasITS() && ele.hasITS()) { // ITSTPC-TPC - if (rxy > std::min(83.f, ele.x()) + margin_r_itstpc_tpc) { + if (rxy > std::min(83.f, nTrack.getX()) + margin_r_itstpc_tpc) { return; } } else if (pos.hasITS() && !ele.hasITS()) { // ITSTPC-TPC - if (rxy > std::min(pos.x(), 83.f) + margin_r_itstpc_tpc) { + if (rxy > std::min(pTrack.getX(), 83.f) + margin_r_itstpc_tpc) { return; } } else if (!pos.hasITS() && !ele.hasITS()) { // TPC-TPC @@ -493,7 +547,7 @@ struct PhotonConversionBuilder { // LOGF(info, "gammaKF_PV.GetPy() = %f, gammaKF_DecayVtx.GetPy() = %f, gammaKF_DecayVtx2.GetPy() = %f", gammaKF_PV.GetPy(), gammaKF_DecayVtx.GetPy(), gammaKF_DecayVtx2.GetPy()); // LOGF(info, "gammaKF_PV.GetPz() = %f, gammaKF_DecayVtx.GetPz() = %f, gammaKF_DecayVtx2.GetPz() = %f", gammaKF_PV.GetPz(), gammaKF_DecayVtx.GetPz(), gammaKF_DecayVtx2.GetPz()); - if (fabs(v0eta) > max_eta_v0 || v0pt < min_pt_v0) { + if (std::fabs(v0eta) > max_eta_v0 || v0pt < min_pt_v0) { return; } @@ -531,9 +585,6 @@ struct PhotonConversionBuilder { float pos_pt = RecoDecay::sqrtSumOfSquares(kfp_pos_DecayVtx.GetPx(), kfp_pos_DecayVtx.GetPy()); float ele_pt = RecoDecay::sqrtSumOfSquares(kfp_ele_DecayVtx.GetPx(), kfp_ele_DecayVtx.GetPy()); - if (pos_pt < min_pt_leg || ele_pt < min_pt_leg) { - return; - } if (isITSonlyTrack(pos) && pos_pt > maxpt_itsonly) { return; @@ -551,7 +602,7 @@ struct PhotonConversionBuilder { float dca_z_v0_to_pv = (gammaKF_DecayVtx.GetZ() - gammaKF_DecayVtx.GetPz() * cospa_kf * length / v0mom) - collision.posZ(); float sign_tmp = dca_x_v0_to_pv * dca_y_v0_to_pv > 0 ? +1.f : -1.f; float dca_xy_v0_to_pv = RecoDecay::sqrtSumOfSquares(dca_x_v0_to_pv, dca_y_v0_to_pv) * sign_tmp; - if (abs(dca_xy_v0_to_pv) > max_dcatopv_xy_v0 || abs(dca_z_v0_to_pv) > max_dcatopv_z_v0) { + if (std::fabs(dca_xy_v0_to_pv) > max_dcatopv_xy_v0 || std::fabs(dca_z_v0_to_pv) > max_dcatopv_z_v0) { return; } @@ -575,7 +626,7 @@ struct PhotonConversionBuilder { registry.fill(HIST("V0/hPCA_CosPA"), cospa_kf, pca_kf); registry.fill(HIST("V0/hPCA_Rxy"), rxy, pca_kf); registry.fill(HIST("V0/hDCAxyz"), dca_xy_v0_to_pv, dca_z_v0_to_pv); - registry.fill(HIST("V0/hPCA_diffX"), pca_kf, std::min(pos.x(), ele.x()) - rxy); // trackiu.x() - rxy should be positive + registry.fill(HIST("V0/hPCA_diffX"), pca_kf, std::min(pTrack.getX(), nTrack.getX()) - rxy); // trackiu.x() - rxy should be positive float cospaXY_kf = cospaXY_KF(gammaKF_DecayVtx, KFPV); float cospaRZ_kf = cospaRZ_KF(gammaKF_DecayVtx, KFPV); @@ -596,6 +647,10 @@ struct PhotonConversionBuilder { registry.fill(HIST("V0Leg/hdEdx_Pin"), leg.tpcInnerParam(), leg.tpcSignal()); registry.fill(HIST("V0Leg/hTPCNsigmaEl"), leg.tpcInnerParam(), leg.tpcNSigmaEl()); } // end of leg loop + for (auto& leg : {pTrack, nTrack}) { + registry.fill(HIST("V0Leg/hXZ"), leg.getZ(), leg.getX()); + registry.fill(HIST("V0Leg/hRelDeltaPt"), leg.getPt(), leg.getPt() * std::sqrt(leg.getSigma1Pt2())); + } // end of leg loop registry.fill(HIST("V0Leg/hDCAxyz"), posdcaXY, posdcaZ); registry.fill(HIST("V0Leg/hDCAxyz"), eledcaXY, eledcaZ); @@ -604,45 +659,64 @@ struct PhotonConversionBuilder { ROOT::Math::PxPyPzMVector v0_sv = vpos_sv + vele_sv; registry.fill(HIST("V0/hMeeSV_Rxy"), rxy, v0_sv.M()); - v0photonskf(collision.globalIndex(), v0legs.lastIndex() + 1, v0legs.lastIndex() + 2, + v0photonskf(collision.globalIndex(), v0.globalIndex(), v0legs.lastIndex() + 1, v0legs.lastIndex() + 2, gammaKF_DecayVtx.GetX(), gammaKF_DecayVtx.GetY(), gammaKF_DecayVtx.GetZ(), gammaKF_PV.GetPx(), gammaKF_PV.GetPy(), gammaKF_PV.GetPz(), v0_sv.M(), dca_xy_v0_to_pv, dca_z_v0_to_pv, - cospa_kf, pca_kf, alpha, qt, chi2kf); + cospa_kf, cospaXY_kf, cospaRZ_kf, pca_kf, alpha, qt, chi2kf); + + v0photonskfcov(gammaKF_PV.GetCovariance(9), gammaKF_PV.GetCovariance(14), gammaKF_PV.GetCovariance(20), gammaKF_PV.GetCovariance(13), gammaKF_PV.GetCovariance(19), gammaKF_PV.GetCovariance(18)); - fillTrackTable(pos, kfp_pos_DecayVtx, posdcaXY, posdcaZ); // positive leg first - fillTrackTable(ele, kfp_ele_DecayVtx, eledcaXY, eledcaZ); // negative leg second - } // end of fill table + fillTrackTable(pos, pTrack, kfp_pos_DecayVtx, posdcaXY, posdcaZ); // positive leg first + fillTrackTable(ele, nTrack, kfp_ele_DecayVtx, eledcaXY, eledcaZ); // negative leg second + } // end of fill table } Preslice perCollision = o2::aod::v0::collisionId; - std::map, float> pca_map; //(v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) -> pca - std::map, float> cospa_map; //(v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) -> cospa - std::vector> stored_v0Ids; //(pos.globalIndex(), ele.globalIndex()) - - template - void build(TCollisions const& collisions, TV0s const& v0s, TTracks const& /*tracks*/, TBCs const&) + std::map, float> pca_map; // (v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) -> pca + std::map, float> cospa_map; // (v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) -> cospa + std::vector> stored_v0Ids; // (pos.globalIndex(), ele.globalIndex()) + std::vector> stored_fullv0Ids; // (v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) + std::unordered_map nv0_map; // map collisionId -> nv0 + + template + void build(TCollisions const& collisions, TV0s const& v0s, TTracks const&, TBCs const&) { - for (auto& collision : collisions) { + for (const auto& collision : collisions) { if constexpr (isMC) { if (!collision.has_mcCollision()) { continue; } } - auto bc = collision.template bc_as(); + if (!collision.isSelected()) { + continue; + } + + if constexpr (isTriggerAnalysis) { + if (collision.swtaliastmp_raw() == 0) { + continue; + } + } + + nv0_map[collision.globalIndex()] = 0; + + const auto& bc = collision.template foundBC_as(); initCCDB(bc); registry.fill(HIST("hCollisionCounter"), 1); - auto v0s_per_coll = v0s.sliceBy(perCollision, collision.globalIndex()); + updateCCDB(bc); // delay update until is needed + + const auto& v0s_per_coll = v0s.sliceBy(perCollision, collision.globalIndex()); // LOGF(info, "n v0 = %d", v0s_per_coll.size()); - for (auto& v0 : v0s_per_coll) { + for (const auto& v0 : v0s_per_coll) { // LOGF(info, "collision.globalIndex() = %d, v0.globalIndex() = %d, v0.posTrackId() = %d, v0.negTrackId() = %d", collision.globalIndex(), v0.globalIndex(), v0.posTrackId() , v0.negTrackId()); - fillV0Table(v0, false); + fillV0Table(v0, false); } // end of v0 loop - } // end of collision loop + } // end of collision loop - stored_v0Ids.reserve(pca_map.size()); // number of photon candidates per DF + stored_v0Ids.reserve(pca_map.size()); // number of photon candidates per DF + stored_fullv0Ids.reserve(pca_map.size()); // number of photon candidates per DF // find minimal pca for (const auto& [key, value] : pca_map) { @@ -682,20 +756,55 @@ struct PhotonConversionBuilder { bool is_stored = std::find(stored_v0Ids.begin(), stored_v0Ids.end(), std::make_pair(posId, eleId)) != stored_v0Ids.end(); if (is_closest_v0 && is_most_aligned_v0 && !is_stored) { - auto v0 = v0s.rawIteratorAt(v0Id); + // auto v0 = v0s.rawIteratorAt(v0Id); // auto collision = collisions.rawIteratorAt(collisionId); // auto pos = tracks.rawIteratorAt(posId); // auto ele = tracks.rawIteratorAt(eleId); // LOGF(info, "!accept! | collision id = %d | v0id1 = %d , posid1 = %d , eleid1 = %d , pca1 = %f , cospa = %f", collisionId, v0Id, posId, eleId, v0pca, cospa); - fillV0Table(v0, true); + + // fillV0Table(v0, true); stored_v0Ids.emplace_back(std::make_pair(posId, eleId)); + stored_fullv0Ids.emplace_back(std::make_tuple(v0Id, collisionId, posId, eleId)); + nv0_map[collisionId]++; } } // end of pca_map loop // LOGF(info, "pca_map.size() = %d", pca_map.size()); + + for (auto& fullv0Id : stored_fullv0Ids) { + auto v0Id = std::get<0>(fullv0Id); + // auto collisionId = std::get<1>(fullv0Id); + // auto posId = std::get<2>(fullv0Id); + // auto eleId = std::get<3>(fullv0Id); + // LOGF(info, "!accept! | collision id = %d | v0id = %d , posid = %d , eleid = %d", collisionId, v0Id, posId, eleId); + + auto v0 = v0s.rawIteratorAt(v0Id); + if constexpr (enableFilter) { + auto collision_tmp = v0.template collision_as(); // collision where this v0 belongs. + if (!(collision_tmp.neeuls() >= 1 || collision_tmp.neeuls() + nv0_map[collision_tmp.globalIndex()] >= 2)) { + continue; + } + // LOGF(info, "collision_tmp.globalIndex() = %d, collision_tmp.neeuls() = %d, nv0_map = %d", collision_tmp.globalIndex(), collision_tmp.neeuls(), nv0_map[collision_tmp.globalIndex()]); + } + + fillV0Table(v0, true); + } // end of fullv0Id loop + + for (auto& collision : collisions) { + if constexpr (isMC) { + if (!collision.has_mcCollision()) { + continue; + } + } + events_ngpcm(nv0_map[collision.globalIndex()]); + } // end of collision loop + pca_map.clear(); cospa_map.clear(); + nv0_map.clear(); stored_v0Ids.clear(); stored_v0Ids.shrink_to_fit(); + stored_fullv0Ids.clear(); + stored_fullv0Ids.shrink_to_fit(); } // end of build //! type of V0. 0: built solely for cascades (does not pass standard V0 cuts), 1: standard 2, 3: photon-like with TPC-only use. Regular analysis should always use type 1 or 3. @@ -704,15 +813,33 @@ struct PhotonConversionBuilder { void processRec(MyCollisions const& collisions, filteredV0s const& v0s, MyTracksIU const& tracks, aod::BCsWithTimestamps const& bcs) { - build(collisions, v0s, tracks, bcs); + build(collisions, v0s, tracks, bcs); } PROCESS_SWITCH(PhotonConversionBuilder, processRec, "process reconstructed info for data", true); + void processRec_SWT(MyCollisionsWithSWT const& collisions, filteredV0s const& v0s, MyTracksIU const& tracks, aod::BCsWithTimestamps const& bcs) + { + build(collisions, v0s, tracks, bcs); + } + PROCESS_SWITCH(PhotonConversionBuilder, processRec_SWT, "process reconstructed info for data", false); + void processMC(MyCollisionsMC const& collisions, filteredV0s const& v0s, MyTracksIUMC const& tracks, aod::BCsWithTimestamps const& bcs) { - build(collisions, v0s, tracks, bcs); + build(collisions, v0s, tracks, bcs); } PROCESS_SWITCH(PhotonConversionBuilder, processMC, "process reconstructed info for MC", false); + + void processRec_OnlyIfDielectron(soa::Join const& collisions, filteredV0s const& v0s, MyTracksIU const& tracks, aod::BCsWithTimestamps const& bcs) + { + build(collisions, v0s, tracks, bcs); + } + PROCESS_SWITCH(PhotonConversionBuilder, processRec_OnlyIfDielectron, "process reconstructed info for data", false); + + void processRec_SWT_OnlyIfDielectron(soa::Join const& collisions, filteredV0s const& v0s, MyTracksIU const& tracks, aod::BCsWithTimestamps const& bcs) + { + build(collisions, v0s, tracks, bcs); + } + PROCESS_SWITCH(PhotonConversionBuilder, processRec_SWT_OnlyIfDielectron, "process reconstructed info for data", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerDalitzEE.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerDalitzEE.cxx index 65746d4f46f..5eb1bfeb069 100644 --- a/PWGEM/PhotonMeson/TableProducer/skimmerDalitzEE.cxx +++ b/PWGEM/PhotonMeson/TableProducer/skimmerDalitzEE.cxx @@ -13,12 +13,18 @@ /// \author daiki.sekihata@cern.ch #include "Math/Vector4D.h" + +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "CommonConstants/PhysicsConstants.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" using namespace o2; using namespace o2::soa; @@ -26,12 +32,15 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::constants::physics; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; -using MyTracks = soa::Join; +using MyTracks = soa::Join; using MyTrack = MyTracks::iterator; +using MyTracksCEFP = soa::Join; +using MyTrackCEFP = MyTracksCEFP::iterator; + struct skimmerDalitzEE { enum class EM_EEPairType : int { kULS = 0, @@ -43,13 +52,19 @@ struct skimmerDalitzEE { Preslice perCol = o2::aod::emprimaryelectron::emeventId; SliceCache cache_cefp; - PresliceUnsorted perCol_cefp = o2::aod::emprimaryelectron::collisionId; + PresliceUnsorted perCol_cefp = o2::aod::emprimaryelectron::collisionId; Produces dalitzees; Produces dalitz_ee_eventid; Produces event_nee; // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; @@ -89,7 +104,58 @@ struct skimmerDalitzEE { }, }; - void init(InitContext const&) {} + Service ccdb; + int mRunNumber; + float d_bz; + void init(InitContext const&) + { + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + } + + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + mRunNumber = collision.runNumber(); + return; + } + + auto run3grp_timestamp = collision.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = collision.runNumber(); + } std::pair> itsRequirement = {1, {0, 1, 2}}; // any hits on 3 ITS ib layers. @@ -207,8 +273,8 @@ struct skimmerDalitzEE { if (v12.M() > maxMee) { // don't store continue; } - float phiv = getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), collision.bz()); - float opangle = getOpeningAngle(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz()); + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), d_bz); + float opangle = o2::aod::pwgem::dilepton::utils::pairutil::getOpeningAngle(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz()); // if (!std::isfinite(phiv)) { // LOGF(info, "t1.px() = %f, t1.py() = %f, t1.pz() = %f, t2.px() = %f, t2.py() = %f, t2.pz() = %f", t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz()); @@ -236,8 +302,8 @@ struct skimmerDalitzEE { if (v12.M() > maxMee) { // don't store continue; } - float phiv = getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), collision.bz()); - float opangle = getOpeningAngle(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz()); + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), d_bz); + float opangle = o2::aod::pwgem::dilepton::utils::pairutil::getOpeningAngle(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz()); if constexpr (isCEFP) { dalitzees(collision.globalIndex(), t1.globalIndex(), t2.globalIndex(), v12.Pt(), v12.Eta(), v12.Phi() > 0 ? v12.Phi() : v12.Phi() + TMath::TwoPi(), v12.M(), v12.M(), phiv, opangle, static_cast(pairtype)); @@ -259,6 +325,7 @@ struct skimmerDalitzEE { void processAnalysis(MyCollisions const& collisions, MyTracks const&) { for (auto& collision : collisions) { + initCCDB(collision); float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { event_nee(0, 0, 0); @@ -282,11 +349,13 @@ struct skimmerDalitzEE { } PROCESS_SWITCH(skimmerDalitzEE, processAnalysis, "Process dalitz ee for analysis", true); - Partition posTracks_cefp = o2::aod::emprimaryelectron::sign > int8_t(0) && o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& minTPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl&& o2::aod::pidtpc::tpcNSigmaEl < maxTPCNsigmaEl; - Partition negTracks_cefp = o2::aod::emprimaryelectron::sign < int8_t(0) && o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& minTPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl&& o2::aod::pidtpc::tpcNSigmaEl < maxTPCNsigmaEl; - void processCEFP(soa::Join const& collisions, aod::EMPrimaryElectrons const&) + Partition posTracks_cefp = o2::aod::emprimaryelectron::sign > int8_t(0) && o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& minTPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl&& o2::aod::pidtpc::tpcNSigmaEl < maxTPCNsigmaEl; + Partition negTracks_cefp = o2::aod::emprimaryelectron::sign < int8_t(0) && o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& minTPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl&& o2::aod::pidtpc::tpcNSigmaEl < maxTPCNsigmaEl; + void processCEFP(aod::Collisions const& collisions, MyTracksCEFP const&, aod::BCsWithTimestamps const&) { for (auto& collision : collisions) { + auto bc = collision.template bc_as(); + initCCDB(bc); auto posTracks_per_coll = posTracks_cefp->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache_cefp); auto negTracks_per_coll = negTracks_cefp->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache_cefp); diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerDalitzMuMu.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerDalitzMuMu.cxx deleted file mode 100644 index 8e0e2116326..00000000000 --- a/PWGEM/PhotonMeson/TableProducer/skimmerDalitzMuMu.cxx +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright 2020-2022 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 write relevant information for dalitz mumu analysis to an AO2D.root file. This file is then the only necessary input to perform pcm analysis. -/// \author daiki.sekihata@cern.ch - -#include "Math/Vector4D.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "CommonConstants/PhysicsConstants.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" - -using namespace o2; -using namespace o2::soa; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::constants::physics; - -using MyCollisions = soa::Join; -using MyCollision = MyCollisions::iterator; - -using MyTracks = soa::Join; -using MyTrack = MyTracks::iterator; - -struct skimmerDalitzMuMu { - enum class EM_MuMuPairType : int { - kULS = 0, - kLSpp = +1, - kLSmm = -1, - }; - - SliceCache cache; - Preslice perCol = o2::aod::emprimarymuon::emeventId; - Produces dalitzmumus; - Produces dalitz_mumu_eventid; - Produces event_nmumu; - - // Configurables - Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; - Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; - Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; - - Configurable maxMmumu{"maxMmumu", 1.1, "max. mmumu to store mumu pairs"}; - Configurable storeLS{"storeLS", false, "flag to store LS pairs"}; - Configurable minpt{"minpt", 0.05, "min pt for track"}; - Configurable maxpt{"maxpt", 0.6, "max pt for track"}; - Configurable maxeta{"maxeta", 0.9, "eta acceptance"}; - Configurable min_ncluster_tpc{"min_ncluster_tpc", 10, "min ncluster tpc"}; - Configurable mincrossedrows{"mincrossedrows", 70, "min. crossed rows"}; - Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; - Configurable minitsncls{"minitsncls", 5, "min. number of ITS clusters"}; - Configurable maxchi2tpc{"maxchi2tpc", 4.0, "max. chi2/NclsTPC"}; - Configurable maxchi2its{"maxchi2its", 5.0, "max. chi2/NclsITS"}; - Configurable dca_xy_max{"dca_xy_max", 1.0f, "max DCAxy in cm"}; - Configurable dca_z_max{"dca_z_max", 1.0f, "max DCAz in cm"}; - Configurable dca_3d_sigma_max{"dca_3d_sigma_max", 1.0f, "max DCA 3D in sigma"}; - Configurable minTPCNsigmaMu{"minTPCNsigmaMu", -3.0, "min. TPC n sigma for muon inclusion"}; - Configurable maxTPCNsigmaMu{"maxTPCNsigmaMu", 3.0, "max. TPC n sigma for muon inclusion"}; - - HistogramRegistry fRegistry{ - "fRegistry", - { - {"hNpairs", "hNpairs;pair type;Number of Pairs", {HistType::kTH1F, {{3, -1.5f, +1.5f}}}}, - }, - }; - - void init(InitContext const&) {} - - std::pair> itsRequirement = {1, {0, 1, 2}}; // any hits on 3 ITS ib layers. - - template - bool checkTrack(TTrack const& track) - { - if (!track.hasITS() || !track.hasTPC()) { - return false; - } - - if (track.itsNCls() < minitsncls) { - return false; - } - - auto hits = std::count_if(itsRequirement.second.begin(), itsRequirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); - if (hits < itsRequirement.first) { - return false; - } - - if (track.tpcNClsFound() < min_ncluster_tpc) { - return false; - } - - if (track.tpcNClsCrossedRows() < mincrossedrows) { - return false; - } - - if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { - return false; - } - - // float rel_diff = (track.tpcInnerParam() - track.p())/track.p(); - // if (rel_diff < -0.0156432+-0.00154524/pow(track.p(),2.29244) - 0.02 || -0.0156432+-0.00154524/pow(track.p(),2.29244) + 0.02 < rel_diff) { - // return false; - // } - - float dca_3d = 999.f; - float det = track.cYY() * track.cZZ() - track.cZY() * track.cZY(); - if (det < 0) { - dca_3d = 999.f; - } else { - float chi2 = (track.dcaXY() * track.dcaXY() * track.cZZ() + track.dcaZ() * track.dcaZ() * track.cYY() - 2. * track.dcaXY() * track.dcaZ() * track.cZY()) / det; - dca_3d = std::sqrt(std::abs(chi2) / 2.); - } - if (dca_3d > dca_3d_sigma_max) { - return false; - } - - return true; - } - - template - int fillPairTable(TCollision const& collision, TTracks1 const& tracks1, TTracks2 const& tracks2) - { - int npair = 0; - const float phiv = 0.f; - const float opangle = 0.f; - if constexpr (pairtype == EM_MuMuPairType::kULS) { // ULS - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { - if (!checkTrack(t1) || !checkTrack(t2)) { - continue; - } - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassMuon); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassMuon); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - if (v12.M() > maxMmumu) { // don't store - continue; - } - dalitzmumus(collision.collisionId(), t1.globalIndex(), t2.globalIndex(), v12.Pt(), v12.Eta(), v12.Phi() > 0 ? v12.Phi() : v12.Phi() + TMath::TwoPi(), v12.M(), v12.Rapidity(), phiv, opangle, static_cast(pairtype)); - dalitz_mumu_eventid(collision.globalIndex()); - fRegistry.fill(HIST("hNpairs"), static_cast(pairtype)); - npair++; - } // end of pairing loop - } else { // LS - for (auto& [t1, t2] : combinations(CombinationsStrictlyUpperIndexPolicy(tracks1, tracks2))) { - if (!checkTrack(t1) || !checkTrack(t2)) { - continue; - } - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassMuon); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassMuon); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - if (v12.M() > maxMmumu) { // don't store - continue; - } - dalitzmumus(collision.collisionId(), t1.globalIndex(), t2.globalIndex(), v12.Pt(), v12.Eta(), v12.Phi() > 0 ? v12.Phi() : v12.Phi() + TMath::TwoPi(), v12.M(), v12.Rapidity(), phiv, opangle, static_cast(pairtype)); - dalitz_mumu_eventid(collision.globalIndex()); - fRegistry.fill(HIST("hNpairs"), static_cast(pairtype)); - npair++; - } // end of pairing loop - } - return npair; - } - - Partition posTracks = minpt < o2::aod::track::pt && o2::aod::track::pt < maxpt && nabs(o2::aod::track::eta) < maxeta && o2::aod::emprimarymuon::sign > int8_t(0) && minTPCNsigmaMu < o2::aod::pidtpc::tpcNSigmaMu&& o2::aod::pidtpc::tpcNSigmaMu < maxTPCNsigmaMu; - Partition negTracks = minpt < o2::aod::track::pt && o2::aod::track::pt < maxpt && nabs(o2::aod::track::eta) < maxeta && o2::aod::emprimarymuon::sign < int8_t(0) && minTPCNsigmaMu < o2::aod::pidtpc::tpcNSigmaMu && o2::aod::pidtpc::tpcNSigmaMu < maxTPCNsigmaMu; - void processAnalysis(MyCollisions const& collisions, MyTracks const&) - { - for (auto& collision : collisions) { - float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { - event_nmumu(0, 0, 0); - continue; - } - - auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::emprimarymuon::emeventId, collision.globalIndex(), cache); - auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::emprimarymuon::emeventId, collision.globalIndex(), cache); - - int npair_uls = 0, npair_lspp = 0, npair_lsmm = 0; - npair_uls = fillPairTable(collision, posTracks_per_coll, negTracks_per_coll); // ULS - if (storeLS) { - npair_lspp = fillPairTable(collision, posTracks_per_coll, posTracks_per_coll); // LS++ - npair_lsmm = fillPairTable(collision, negTracks_per_coll, negTracks_per_coll); // LS-- - } - event_nmumu(npair_uls, npair_lspp, npair_lsmm); - } // end of collision loop - } - PROCESS_SWITCH(skimmerDalitzMuMu, processAnalysis, "Process dalitz mumu for analysis", true); - - void processOnlyNmumu(soa::Join const& collisions) - { - for (auto& collision : collisions) { - float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { - event_nmumu(0, 0, 0); - continue; - } - event_nmumu(0, 0, 0); - } // end of collision loop - } - PROCESS_SWITCH(skimmerDalitzMuMu, processOnlyNmumu, "Process only nmumu", false); // for central event filter processing -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"skimmer-dalitz-mumu"})}; -} diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx index c3843080eaf..da85ef3c8b4 100644 --- a/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx +++ b/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx @@ -13,10 +13,15 @@ /// dependencies: emcal-correction-task /// \author marvin.hemmer@cern.ch +#include +#include + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" +#include "Common/Core/TableHelper.h" + // includes for the R recalculation #include "DetectorsBase/GeometryManager.h" #include "DataFormatsParameters/GRPObject.h" @@ -44,46 +49,79 @@ struct skimmerGammaCalo { Configurable maxTime{"maxTime", +200., "Maximum cluster time for time cut"}; Configurable minM02{"minM02", 0.0, "Minimum M02 for M02 cut"}; Configurable maxM02{"maxM02", 1.0, "Maximum M02 for M02 cut"}; - Configurable hasPropagatedTracks{"hasPropagatedTracks", false, "temporary flag, only set to true when running over data which has the tracks propagated to EMCal/PHOS!"}; + Configurable minE{"minE", 0.5, "Minimum energy for energy cut"}; + Configurable> clusterDefinitions{"clusterDefinitions", {0, 1, 2, 10, 11, 12, 13, 20, 21, 22, 30, 40, 41, 42, 43, 44, 45}, "Cluster definitions to be accepted (e.g. 13 for kV3MostSplitLowSeed)"}; + Configurable maxdEta{"maxdEta", 0.1, "Set a maximum difference in eta for tracks and cluster to still count as matched"}; + Configurable maxdPhi{"maxdPhi", 0.1, "Set a maximum difference in phi for tracks and cluster to still count as matched"}; - HistogramRegistry historeg{ - "historeg", - {}, - OutputObjHandlingPolicy::QAObject, - false, - true}; + HistogramRegistry historeg{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; void init(o2::framework::InitContext&) { - historeg.add("hCaloClusterEIn", "hCaloClusterEIn", gHistoSpec_clusterE); - historeg.add("hCaloClusterEOut", "hCaloClusterEOut", gHistoSpec_clusterE); - historeg.add("hMTEtaPhi", "hMTEtaPhi", gHistoSpec_EtaPhi); - auto hCaloClusterFilter = historeg.add("hCaloClusterFilter", "hCaloClusterFilter", kTH1I, {{4, 0, 4}}); + historeg.add("DefinitionIn", "Cluster definitions before cuts;#bf{Cluster definition};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{51, -0.5, 50.5}}); + historeg.add("DefinitionOut", "Cluster definitions after cuts;#bf{Cluster definition};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{51, -0.5, 50.5}}); + historeg.add("EIn", "Energy of clusters before cuts", gHistoSpec_clusterE); + historeg.add("EOut", "Energy of clusters after cuts", gHistoSpec_clusterE); + historeg.add("MTEtaPhi", "Eta phi of matched tracks", gHistoSpec_clusterTM_dEtadPhi); + historeg.add("M02In", "Shape of cluster before cuts;#bf{#it{M}_{02}};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{200, 0, 2}}); + historeg.add("M02Out", "Shape of cluster after cuts;#bf{#it{M}_{02}};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{200, 0, 2}}); + historeg.add("TimeIn", "Time of cluster before cuts;#bf{#it{t} (ns)};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{200, -100, 100}}); + historeg.add("TimeOut", "Time of cluster after cuts;#bf{#it{t} (ns)};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{200, -100, 100}}); + + auto hCaloClusterFilter = historeg.add("hCaloClusterFilter", "hCaloClusterFilter", kTH1I, {{6, 0, 6}}); hCaloClusterFilter->GetXaxis()->SetBinLabel(1, "in"); - hCaloClusterFilter->GetXaxis()->SetBinLabel(2, "time cut"); - hCaloClusterFilter->GetXaxis()->SetBinLabel(3, "M02 cut"); - hCaloClusterFilter->GetXaxis()->SetBinLabel(4, "out"); - - LOG(info) << "| Timing cut: " << minTime << " < t < " << maxTime << std::endl; - LOG(info) << "| M02 cut: " << minM02 << " < M02 < " << maxM02 << std::endl; + hCaloClusterFilter->GetXaxis()->SetBinLabel(2, "Definition cut"); + hCaloClusterFilter->GetXaxis()->SetBinLabel(3, "E cut"); + hCaloClusterFilter->GetXaxis()->SetBinLabel(4, "time cut"); + hCaloClusterFilter->GetXaxis()->SetBinLabel(5, "M02 cut"); + hCaloClusterFilter->GetXaxis()->SetBinLabel(6, "out"); + + LOG(info) << "| Timing cut: " << minTime << " < t < " << maxTime; + LOG(info) << "| M02 cut: " << minM02 << " < M02 < " << maxM02; + LOG(info) << "| E cut: E > " << minE; } - void processRec(aod::Collision const&, aod::EMCALClusters const& emcclusters, aod::EMCALClusterCells const& emcclustercells, aod::EMCALMatchedTracks const& emcmatchedtracks, aod::FullTracks const&) + void processRec(soa::Join::iterator const& collision, aod::EMCALClusters const& emcclusters, aod::EMCALClusterCells const& emcclustercells, aod::EMCALMatchedTracks const& emcmatchedtracks, aod::FullTracks const&) { + if (!collision.isSelected()) { + return; + } + for (const auto& emccluster : emcclusters) { - historeg.fill(HIST("hCaloClusterEIn"), emccluster.energy()); historeg.fill(HIST("hCaloClusterFilter"), 0); + historeg.fill(HIST("DefinitionIn"), emccluster.definition()); + historeg.fill(HIST("EIn"), emccluster.energy()); + historeg.fill(HIST("M02In"), emccluster.m02()); + historeg.fill(HIST("TimeIn"), emccluster.time()); + + // Definition cut + if (!(std::find(clusterDefinitions.value.begin(), clusterDefinitions.value.end(), emccluster.definition()) != clusterDefinitions.value.end())) { + historeg.fill(HIST("hCaloClusterFilter"), 1); + continue; + } + historeg.fill(HIST("EIn"), emccluster.energy()); + // Energy cut + if (emccluster.energy() < minE) { + historeg.fill(HIST("hCaloClusterFilter"), 2); + continue; + } // timing cut if (emccluster.time() > maxTime || emccluster.time() < minTime) { - historeg.fill(HIST("hCaloClusterFilter"), 1); + historeg.fill(HIST("hCaloClusterFilter"), 3); continue; } // M02 cut if (emccluster.nCells() > 1 && (emccluster.m02() > maxM02 || emccluster.m02() < minM02)) { - historeg.fill(HIST("hCaloClusterFilter"), 2); + historeg.fill(HIST("hCaloClusterFilter"), 4); continue; } + historeg.fill(HIST("hCaloClusterFilter"), 5); + + historeg.fill(HIST("DefinitionOut"), emccluster.definition()); + historeg.fill(HIST("EOut"), emccluster.energy()); + historeg.fill(HIST("M02Out"), emccluster.m02()); + historeg.fill(HIST("TimeOut"), emccluster.time()); // Skimmed cell table auto groupedCells = emcclustercells.sliceBy(CellperCluster, emccluster.globalIndex()); @@ -104,50 +142,45 @@ struct skimmerGammaCalo { vP.reserve(groupedMTs.size()); vPt.reserve(groupedMTs.size()); for (const auto& emcmatchedtrack : groupedMTs) { - if (hasPropagatedTracks) { // only temporarily while not every data has the tracks propagated to EMCal/PHOS - historeg.fill(HIST("hMTEtaPhi"), emccluster.eta() - emcmatchedtrack.track_as().trackEtaEmcal(), emccluster.phi() - emcmatchedtrack.track_as().trackPhiEmcal()); - vTrackIds.emplace_back(emcmatchedtrack.trackId()); - vEta.emplace_back(emcmatchedtrack.track_as().trackEtaEmcal()); - vPhi.emplace_back(emcmatchedtrack.track_as().trackPhiEmcal()); - vP.emplace_back(emcmatchedtrack.track_as().p()); - vPt.emplace_back(emcmatchedtrack.track_as().pt()); - tableTrackEMCReco(emcmatchedtrack.emcalclusterId(), emcmatchedtrack.track_as().trackEtaEmcal(), emcmatchedtrack.track_as().trackPhiEmcal(), - emcmatchedtrack.track_as().p(), emcmatchedtrack.track_as().pt()); - } else { - historeg.fill(HIST("hMTEtaPhi"), emccluster.eta() - emcmatchedtrack.track_as().eta(), emccluster.phi() - emcmatchedtrack.track_as().phi()); - vTrackIds.emplace_back(emcmatchedtrack.trackId()); - vEta.emplace_back(emcmatchedtrack.track_as().eta()); - vPhi.emplace_back(emcmatchedtrack.track_as().phi()); - vP.emplace_back(emcmatchedtrack.track_as().p()); - vPt.emplace_back(emcmatchedtrack.track_as().pt()); - tableTrackEMCReco(emcmatchedtrack.emcalclusterId(), emcmatchedtrack.track_as().eta(), emcmatchedtrack.track_as().phi(), - emcmatchedtrack.track_as().p(), emcmatchedtrack.track_as().pt()); + if (std::abs(emccluster.eta() - emcmatchedtrack.track_as().trackEtaEmcal()) >= maxdEta || std::abs(emccluster.phi() - emcmatchedtrack.track_as().trackPhiEmcal()) >= maxdPhi) { + continue; } + historeg.fill(HIST("MTEtaPhi"), emccluster.eta() - emcmatchedtrack.track_as().trackEtaEmcal(), emccluster.phi() - emcmatchedtrack.track_as().trackPhiEmcal()); + vTrackIds.emplace_back(emcmatchedtrack.trackId()); + vEta.emplace_back(emcmatchedtrack.track_as().trackEtaEmcal()); + vPhi.emplace_back(emcmatchedtrack.track_as().trackPhiEmcal()); + vP.emplace_back(emcmatchedtrack.track_as().p()); + vPt.emplace_back(emcmatchedtrack.track_as().pt()); + tableTrackEMCReco(emcmatchedtrack.emcalclusterId(), emcmatchedtrack.track_as().trackEtaEmcal(), emcmatchedtrack.track_as().trackPhiEmcal(), + emcmatchedtrack.track_as().p(), emcmatchedtrack.track_as().pt()); } - historeg.fill(HIST("hCaloClusterEOut"), emccluster.energy()); - historeg.fill(HIST("hCaloClusterFilter"), 3); - - tableGammaEMCReco(emccluster.collisionId(), emccluster.id(), - emccluster.energy(), emccluster.coreEnergy(), emccluster.eta(), emccluster.phi(), emccluster.m02(), - emccluster.m20(), emccluster.nCells(), emccluster.time(), emccluster.isExotic(), emccluster.distanceToBadChannel(), emccluster.nlm(), - emccluster.definition(), vTrackIds, vEta, vPhi, vP, vPt); + tableGammaEMCReco(emccluster.collisionId(), emccluster.definition(), emccluster.energy(), emccluster.eta(), emccluster.phi(), emccluster.m02(), + emccluster.nCells(), emccluster.time(), emccluster.isExotic(), vEta, vPhi, vP, vPt); } } - void processMC(aod::Collision const&, soa::Join const& emcclusters, aod::McParticles const&) + void processMC(soa::Join::iterator const& collision, soa::Join const& emcclusters, aod::McParticles const&) { + if (!collision.isSelected()) { + return; + } + for (const auto& emccluster : emcclusters) { - historeg.fill(HIST("hCaloClusterEIn"), emccluster.energy()); - historeg.fill(HIST("hCaloClusterFilter"), 0); + // Definition cut + if (!(std::find(clusterDefinitions.value.begin(), clusterDefinitions.value.end(), emccluster.definition()) != clusterDefinitions.value.end())) { + continue; + } + // Energy cut + if (emccluster.energy() < minE) { + continue; + } // timing cut if (emccluster.time() > maxTime || emccluster.time() < minTime) { - historeg.fill(HIST("hCaloClusterFilter"), 1); continue; } // M02 cut if (emccluster.nCells() > 1 && (emccluster.m02() > maxM02 || emccluster.m02() < minM02)) { - historeg.fill(HIST("hCaloClusterFilter"), 2); continue; } std::vector mcLabels; diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerGammaConversion.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerGammaConversion.cxx index 40334a036c0..6a39aea8881 100644 --- a/PWGEM/PhotonMeson/TableProducer/skimmerGammaConversion.cxx +++ b/PWGEM/PhotonMeson/TableProducer/skimmerGammaConversion.cxx @@ -23,6 +23,11 @@ // runme like: o2-analysis-trackselection -b --aod-file ${sourceFile} --aod-writer-json ${writerFile} | o2-analysis-timestamp -b | o2-analysis-trackextension -b | o2-analysis-lf-lambdakzerobuilder -b | o2-analysis-pid-tpc -b | o2-analysis-em-skimmermc -b +#include +#include +#include +#include + // todo: remove reduantant information in GammaConversionsInfoTrue #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/gammaConvDefinitions.h" @@ -181,7 +186,7 @@ struct skimmerGammaConversion { v0legs(theTrack.collisionId(), theTrack.globalIndex(), theTrack.sign(), kfp.GetPx(), kfp.GetPy(), kfp.GetPz(), theTrack.dcaXY(), theTrack.dcaZ(), - theTrack.tpcNClsFindable(), theTrack.tpcNClsFindableMinusFound(), theTrack.tpcNClsFindableMinusCrossedRows(), + theTrack.tpcNClsFindable(), theTrack.tpcNClsFindableMinusFound(), theTrack.tpcNClsFindableMinusCrossedRows(), theTrack.tpcNClsShared(), theTrack.tpcChi2NCl(), theTrack.tpcInnerParam(), theTrack.tpcSignal(), theTrack.tpcNSigmaEl(), theTrack.tpcNSigmaPi(), theTrack.itsClusterSizes(), theTrack.itsChi2NCl(), theTrack.detectorMap(), @@ -304,11 +309,11 @@ struct skimmerGammaConversion { float sign_tmp = dca_y_v0_to_pv > 0 ? +1 : -1; float dca_xy_v0_to_pv = RecoDecay::sqrtSumOfSquares(dca_x_v0_to_pv, dca_y_v0_to_pv) * sign_tmp; - v0photonskf(collision.globalIndex(), v0legs.lastIndex() + 1, v0legs.lastIndex() + 2, + v0photonskf(collision.globalIndex(), v0.globalIndex(), v0legs.lastIndex() + 1, v0legs.lastIndex() + 2, gammaKF_DecayVtx.GetX(), gammaKF_DecayVtx.GetY(), gammaKF_DecayVtx.GetZ(), gammaKF_DecayVtx.GetPx(), gammaKF_DecayVtx.GetPy(), gammaKF_DecayVtx.GetPz(), v0_sv.M(), dca_xy_v0_to_pv, dca_z_v0_to_pv, - cospa_kf, pca_kf, alpha, qt, chi2kf); + cospa_kf, 1.f, 1.f, pca_kf, alpha, qt, chi2kf); fillTrackTable(pos, kfp_pos_DecayVtx); fillTrackTable(ele, kfp_ele_DecayVtx); @@ -342,7 +347,7 @@ struct skimmerGammaConversion { fillV0KF(collision, v0); } // end of v0 loop - } // end of collision loop + } // end of collision loop } PROCESS_SWITCH(skimmerGammaConversion, processRec, "process reconstructed info only", true); diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectron.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectron.cxx deleted file mode 100644 index 0b17d214929..00000000000 --- a/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectron.cxx +++ /dev/null @@ -1,940 +0,0 @@ -// 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 write relevant information for dalitz ee analysis to an AO2D.root file. This file is then the only necessary input to perform pcm analysis. -/// \author daiki.sekihata@cern.ch - -#include -#include "Math/Vector4D.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" -#include "Common/Core/trackUtilities.h" -#include "CommonConstants/PhysicsConstants.h" -#include "Common/DataModel/CollisionAssociationTables.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" -#include "PWGEM/PhotonMeson/Utils/TrackSelection.h" - -using namespace o2; -using namespace o2::soa; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::constants::physics; -using namespace o2::pwgem::photonmeson; - -using MyTracks = soa::Join; -using MyTrack = MyTracks::iterator; -using MyTracksMC = soa::Join; -using MyTrackMC = MyTracksMC::iterator; - -struct skimmerPrimaryElectron { - enum class EM_EEPairType : int { - kULS = 0, - kLSpp = +1, - kLSnn = -1, - }; - - SliceCache cache; - Preslice perCol = o2::aod::track::collisionId; - Produces emprimaryelectrons; - Produces events_bz; - - // Configurables - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; - - // Operation and minimisation criteria - Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; - Configurable min_ncluster_tpc{"min_ncluster_tpc", 10, "min ncluster tpc"}; - Configurable mincrossedrows{"mincrossedrows", 70, "min. crossed rows"}; - Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; - Configurable max_mean_itsob_cluster_size{"max_mean_itsob_cluster_size", 16.f, "max. x cos(lambda)"}; // this is to suppress random combination. default 4 + 1 for skimming. - Configurable minitsncls{"minitsncls", 4, "min. number of ITS clusters"}; - Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max. chi2/NclsTPC"}; - Configurable maxchi2its{"maxchi2its", 6.0, "max. chi2/NclsITS"}; - Configurable minpt{"minpt", 0.05, "min pt for track"}; - Configurable maxeta{"maxeta", 0.9, "eta acceptance"}; - Configurable dca_xy_max{"dca_xy_max", 1.0f, "max DCAxy in cm"}; - Configurable dca_z_max{"dca_z_max", 1.0f, "max DCAz in cm"}; - Configurable dca_3d_sigma_max{"dca_3d_sigma_max", 1e+10, "max DCA 3D in sigma"}; - Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -3.0, "min. TPC n sigma for electron inclusion"}; - Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", 4.0, "max. TPC n sigma for electron inclusion"}; - Configurable maxTOFNsigmaEl{"maxTOFNsigmaEl", 4.0, "max. TOF n sigma for electron inclusion"}; - Configurable minTPCNsigmaPi{"minTPCNsigmaPi", 0.0, "min. TPC n sigma for pion exclusion"}; // set to -2 for lowB, -999 for nominalB - Configurable maxTPCNsigmaPi{"maxTPCNsigmaPi", 0.0, "max. TPC n sigma for pion exclusion"}; - Configurable maxTPCNsigmaKa{"maxTPCNsigmaKa", 2.0, "max. TPC n sigma for kaon exclusion"}; - Configurable maxTPCNsigmaPr{"maxTPCNsigmaPr", 2.0, "max. TPC n sigma for proton exclusion"}; - Configurable maxMee{"maxMee", 1e+10, "max. mee to store ee pairs"}; - Configurable storeLS{"storeLS", false, "flag to store LS pairs"}; - Configurable applyKaRej_TPC{"applyKaRej_TPC", false, "flag to apply Kaon rejection in TPC at the skimming level"}; // used for CEFP only - Configurable applyPrRej_TPC{"applyPrRej_TPC", false, "flag to apply Kaon rejection in TPC at the skimming level"}; // used for CEFP only - - HistogramRegistry fRegistry{ - "fRegistry", - { - {"hNpairs", "hNpairs;pair type;Number of Pairs", {HistType::kTH1F, {{3, -1.5f, +1.5f}}}}, - {"Track/hTPCdEdx_Pin_before", "TPC dE/dx vs. p_{in};p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{1000, 0.f, 10.f}, {200, 0.f, 200.f}}}}, - {"Track/hTPCdEdx_Pin_after", "TPC dE/dx vs. p_{in};p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{1000, 0.f, 10.f}, {200, 0.f, 200.f}}}}, - {"Track/hTOFbeta_Pin_before", "TOF beta vs. p_{in};p_{in} (GeV/c);TOF #beta", {HistType::kTH2F, {{1000, 0.f, 10.f}, {240, 0.f, 1.2f}}}}, - {"Track/hTOFbeta_Pin_after", "TOF beta vs. p_{in};p_{in} (GeV/c);TOF #beta", {HistType::kTH2F, {{1000, 0.f, 10.f}, {240, 0.f, 1.2f}}}}, - {"Track/hTPCNsigmaEl_before", "TPC n sigma e vs. p_{in};p_{in} (GeV/c);n #sigma_{e}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5.f, +5.f}}}}, - {"Track/hTOFNsigmaEl_before", "TOF n sigma e vs. p_{in};p_{in} (GeV/c);n #sigma_{e}^{TOF}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5.f, +5.f}}}}, - {"Track/hTPCNsigmaMu_before", "TPC n sigma #mu vs. p_{in};p_{in} (GeV/c);n #sigma_{#mu}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5.f, +5.f}}}}, - {"Track/hTOFNsigmaMu_before", "TOF n sigma #mu vs. p_{in};p_{in} (GeV/c);n #sigma_{#mu}^{TOF}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5.f, +5.f}}}}, - {"Track/hTPCNsigmaPi_before", "TPC n sigma #pi vs. p_{in};p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5.f, +5.f}}}}, - {"Track/hTOFNsigmaPi_before", "TOF n sigma #pi vs. p_{in};p_{in} (GeV/c);n #sigma_{#pi}^{TOF}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5.f, +5.f}}}}, - {"Track/hTPCNsigmaEl_after", "TPC n sigma e vs. p_{in};p_{in} (GeV/c);n #sigma_{e}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5.f, +5.f}}}}, - {"Track/hTOFNsigmaEl_after", "TOF n sigma e vs. p_{in};p_{in} (GeV/c);n #sigma_{e}^{TOF}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5.f, +5.f}}}}, - {"Track/hTPCNsigmaMu_after", "TPC n sigma #mu vs. p_{in};p_{in} (GeV/c);n #sigma_{#mu}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5.f, +5.f}}}}, - {"Track/hTOFNsigmaMu_after", "TOF n sigma #mu vs. p_{in};p_{in} (GeV/c);n #sigma_{#mu}^{TOF}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5.f, +5.f}}}}, - {"Track/hTPCNsigmaPi_after", "TPC n sigma #pi vs. p_{in};p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5.f, +5.f}}}}, - {"Track/hTOFNsigmaPi_after", "TOF n sigma #pi vs. p_{in};p_{in} (GeV/c);n #sigma_{#pi}^{TOF}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5.f, +5.f}}}}, - {"Pair/hMeePtee_ULS", "ULS m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", {HistType::kTH2F, {{400, 0.f, 4.f}, {100, 0.f, 10.f}}}}, - {"Pair/hMeePtee_LSpp", "LS++ m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", {HistType::kTH2F, {{400, 0.f, 4.f}, {100, 0.f, 10.f}}}}, - {"Pair/hMeePtee_LSnn", "LS-- m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", {HistType::kTH2F, {{400, 0.f, 4.f}, {100, 0.f, 10.f}}}}, - }, - }; - - std::pair> itsRequirement = {1, {0, 1, 2}}; // any hits on 3 ITS ib layers. - - int mRunNumber; - float d_bz; - Service ccdb; - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - - void init(InitContext&) - { - mRunNumber = 0; - d_bz = 0; - - ccdb->setURL(ccdburl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - } - - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - - // In case override, don't proceed, please - no CCDB access required - if (d_bz_input > -990) { - d_bz = d_bz_input; - o2::parameters::GRPMagField grpmag; - if (fabs(d_bz) > 1e-5) { - grpmag.setL3Current(30000.f / (d_bz / 5.0f)); - } - o2::base::Propagator::initFieldFromGRP(&grpmag); - mRunNumber = bc.runNumber(); - return; - } - - auto run3grp_timestamp = bc.timestamp(); - o2::parameters::GRPObject* grpo = 0x0; - o2::parameters::GRPMagField* grpmag = 0x0; - if (!skipGRPOquery) - grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); - if (grpo) { - o2::base::Propagator::initFieldFromGRP(grpo); - // Fetch magnetic field from ccdb for current collision - d_bz = grpo->getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; - } else { - grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); - if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; - } - o2::base::Propagator::initFieldFromGRP(grpmag); - // Fetch magnetic field from ccdb for current collision - d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; - } - mRunNumber = bc.runNumber(); - } - - template - bool checkTrack(TCollision const& collision, TTrack const& track) - { - if constexpr (isMC) { - if (!track.has_mcParticle()) { - return false; - } - } - - if (track.tpcChi2NCl() > maxchi2tpc) { - return false; - } - - if (track.itsChi2NCl() > maxchi2its) { - return false; - } - - if (!track.hasITS() || !track.hasTPC()) { - return false; - } - if (track.itsNCls() < minitsncls) { - return false; - } - - auto hits = std::count_if(itsRequirement.second.begin(), itsRequirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); - if (hits < itsRequirement.first) { - return false; - } - - uint32_t itsClusterSizes = track.itsClusterSizes(); - int total_cluster_size = 0, nl = 0; - for (unsigned int layer = 3; layer < 7; layer++) { - int cluster_size_per_layer = (itsClusterSizes >> (layer * 4)) & 0xf; - if (cluster_size_per_layer > 0) { - nl++; - } - total_cluster_size += cluster_size_per_layer; - } - if (static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(track.tgl())) > max_mean_itsob_cluster_size) { - return false; - } - - if (track.tpcNClsFound() < min_ncluster_tpc) { - return false; - } - - if (track.tpcNClsCrossedRows() < mincrossedrows) { - return false; - } - - if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { - return false; - } - - if ((0.0 < track.beta() && track.beta() < 0.95) || 1.05 < track.beta()) { - return false; - } - - gpu::gpustd::array dcaInfo; - auto track_par_cov_recalc = getTrackParCov(track); - std::array pVec_recalc = {0, 0, 0}; // px, py, pz - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, track_par_cov_recalc, 2.f, matCorr, &dcaInfo); - getPxPyPz(track_par_cov_recalc, pVec_recalc); - float dcaXY = dcaInfo[0]; - float dcaZ = dcaInfo[1]; - - if (track_par_cov_recalc.getPt() < minpt || abs(track_par_cov_recalc.getEta()) > maxeta) { - return false; - } - - float dca_3d = 999.f; - float det = track_par_cov_recalc.getSigmaY2() * track_par_cov_recalc.getSigmaZ2() - track_par_cov_recalc.getSigmaZY() * track_par_cov_recalc.getSigmaZY(); - if (det < 0) { - dca_3d = 999.f; - } else { - float chi2 = (dcaXY * dcaXY * track_par_cov_recalc.getSigmaZ2() + dcaZ * dcaZ * track_par_cov_recalc.getSigmaY2() - 2. * dcaXY * dcaZ * track_par_cov_recalc.getSigmaZY()) / det; - dca_3d = std::sqrt(std::abs(chi2) / 2.); - } - if (dca_3d > dca_3d_sigma_max) { - return false; - } - - return true; - } - - template - bool isElectron(TTrack const& track) - { - return isElectron_TPChadrej(track) || isElectron_TOFrecovery(track) || isElectron_TOFrecovery_lowB(track); - } - - template - bool isElectron_TPChadrej(TTrack const& track) - { - if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { - return false; - } - if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi) { - return false; - } - if (applyKaRej_TPC && abs(track.tpcNSigmaKa()) < maxTPCNsigmaKa) { - return false; - } - if (applyPrRej_TPC && abs(track.tpcNSigmaPr()) < maxTPCNsigmaPr) { - return false; - } - - return true; - } - - template - bool isElectron_TOFrecovery(TTrack const& track) - { - if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi) { - return false; - } - return minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl && abs(track.tofNSigmaEl()) < maxTOFNsigmaEl; - } - - template - bool isElectron_TOFrecovery_lowB(TTrack const& track) - { - // TOF info is available for pin > 0.12 GeV/c at B=0.2T and pin > 0.34 GeV/c at B=0.5T. This is for electron recovery in pion rejection band. - return minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl && abs(track.tofNSigmaEl()) < maxTOFNsigmaEl && track.tpcInnerParam() < 0.4; // TOF recovery only at low pin. - } - - template - void fillTrackHistogram(TCollision const& collision, TTracks const& tracks) - { - for (auto& track : tracks) { - if (!checkTrack(collision, track) || !isElectron(track)) { - continue; - } - fRegistry.fill(HIST("Track/hTPCdEdx_Pin_before"), track.tpcInnerParam(), track.tpcSignal()); - fRegistry.fill(HIST("Track/hTOFbeta_Pin_before"), track.tpcInnerParam(), track.beta()); - fRegistry.fill(HIST("Track/hTPCNsigmaEl_before"), track.tpcInnerParam(), track.tpcNSigmaEl()); - fRegistry.fill(HIST("Track/hTOFNsigmaEl_before"), track.tpcInnerParam(), track.tofNSigmaEl()); - fRegistry.fill(HIST("Track/hTPCNsigmaMu_before"), track.tpcInnerParam(), track.tpcNSigmaMu()); - fRegistry.fill(HIST("Track/hTOFNsigmaMu_before"), track.tpcInnerParam(), track.tofNSigmaMu()); - fRegistry.fill(HIST("Track/hTPCNsigmaPi_before"), track.tpcInnerParam(), track.tpcNSigmaPi()); - fRegistry.fill(HIST("Track/hTOFNsigmaPi_before"), track.tpcInnerParam(), track.tofNSigmaPi()); - } - } - - template - void fillTrackTable(TCollision const& collision, TTrack const& track) - { - - if (std::find(stored_trackIds.begin(), stored_trackIds.end(), std::make_pair(collision.globalIndex(), track.globalIndex())) == stored_trackIds.end()) { - gpu::gpustd::array dcaInfo; - auto track_par_cov_recalc = getTrackParCov(track); - std::array pVec_recalc = {0, 0, 0}; // px, py, pz - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, track_par_cov_recalc, 2.f, matCorr, &dcaInfo); - getPxPyPz(track_par_cov_recalc, pVec_recalc); - float dcaXY = dcaInfo[0]; - float dcaZ = dcaInfo[1]; - - float pt_recalc = track_par_cov_recalc.getPt(); - float eta_recalc = track_par_cov_recalc.getEta(); - float phi_recalc = track_par_cov_recalc.getPhi(); - float tgl_recalc = track_par_cov_recalc.getTgl(); - float cYY_recalc = track_par_cov_recalc.getSigmaY2(); - float cZZ_recalc = track_par_cov_recalc.getSigmaZ2(); - float cZY_recalc = track_par_cov_recalc.getSigmaZY(); - - // if (collision.globalIndex() != track.collisionId()) { - // LOGF(info, "dca_xy: before = %f , after = %f | pT: before = %f , after = %f | cYY : before = %f , after = %f", track.dcaXY(), dcaInfo[0], track.pt(), pt_recalc, track.cYY(), cYY_recalc); - // } - - emprimaryelectrons(collision.globalIndex(), track.globalIndex(), track.sign(), - pt_recalc, eta_recalc, phi_recalc, dcaXY, dcaZ, - track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), - track.tpcChi2NCl(), track.tpcInnerParam(), - track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaMu(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), - track.beta(), track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), - track.itsClusterSizes(), track.itsChi2NCl(), track.detectorMap(), tgl_recalc, cYY_recalc, cZZ_recalc, cZY_recalc); - fRegistry.fill(HIST("Track/hTPCdEdx_Pin_after"), track.tpcInnerParam(), track.tpcSignal()); - fRegistry.fill(HIST("Track/hTOFbeta_Pin_after"), track.tpcInnerParam(), track.beta()); - fRegistry.fill(HIST("Track/hTPCNsigmaEl_after"), track.tpcInnerParam(), track.tpcNSigmaEl()); - fRegistry.fill(HIST("Track/hTOFNsigmaEl_after"), track.tpcInnerParam(), track.tofNSigmaEl()); - fRegistry.fill(HIST("Track/hTPCNsigmaMu_after"), track.tpcInnerParam(), track.tpcNSigmaMu()); - fRegistry.fill(HIST("Track/hTOFNsigmaMu_after"), track.tpcInnerParam(), track.tofNSigmaMu()); - fRegistry.fill(HIST("Track/hTPCNsigmaPi_after"), track.tpcInnerParam(), track.tpcNSigmaPi()); - fRegistry.fill(HIST("Track/hTOFNsigmaPi_after"), track.tpcInnerParam(), track.tofNSigmaPi()); - stored_trackIds.emplace_back(std::make_pair(collision.globalIndex(), track.globalIndex())); - } - } - - template - void fillPairInfo(TCollision const& collision, TTracks1 const& tracks1, TTracks2 const& tracks2) - { - if constexpr (pairtype == EM_EEPairType::kULS) { // ULS - for (auto& t1 : tracks1) { - for (auto& t2 : tracks2) { - if (!checkTrack(collision, t1) || !checkTrack(collision, t2)) { - continue; - } - if (!isElectron(t1) || !isElectron(t2)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - fRegistry.fill(HIST("Pair/hMeePtee_ULS"), v12.M(), v12.Pt()); - - if (v12.M() > maxMee) { // don't store - continue; - } - fRegistry.fill(HIST("hNpairs"), static_cast(pairtype)); - fillTrackTable(collision, t1); - fillTrackTable(collision, t2); - } // end of t2 - } // end of t1 - } else { // LS - std::vector> used_pairs; - used_pairs.reserve(tracks1.size() * tracks2.size()); - - for (auto& t1 : tracks1) { - for (auto& t2 : tracks2) { - if (t1.globalIndex() == t2.globalIndex()) { - continue; - } - - if (std::find(used_pairs.begin(), used_pairs.end(), std::make_pair(t1.globalIndex(), t2.globalIndex())) == used_pairs.end()) { - if (!checkTrack(collision, t1) || !checkTrack(collision, t2)) { - continue; - } - if (!isElectron(t1) || !isElectron(t2)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - - if (pairtype == EM_EEPairType::kLSpp) { - fRegistry.fill(HIST("Pair/hMeePtee_LSpp"), v12.M(), v12.Pt()); - } else if (pairtype == EM_EEPairType::kLSnn) { - fRegistry.fill(HIST("Pair/hMeePtee_LSnn"), v12.M(), v12.Pt()); - } - - if (v12.M() > maxMee) { // don't store - continue; - } - fRegistry.fill(HIST("hNpairs"), static_cast(pairtype)); - fillTrackTable(collision, t1); - fillTrackTable(collision, t2); - - used_pairs.emplace_back(std::make_pair(t1.globalIndex(), t2.globalIndex())); - used_pairs.emplace_back(std::make_pair(t2.globalIndex(), t1.globalIndex())); - } - } // end of t2 - } // end of t1 - used_pairs.clear(); - used_pairs.shrink_to_fit(); - } - } - - std::vector> stored_trackIds; - Filter trackFilter = o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& nabs(o2::aod::track::dcaXY) < dca_xy_max&& nabs(o2::aod::track::dcaZ) < dca_z_max&& o2::aod::track::tpcChi2NCl < maxchi2tpc&& o2::aod::track::itsChi2NCl < maxchi2its&& ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true; - Filter pidFilter = minTPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < maxTPCNsigmaEl && ((0.95f < o2::aod::pidtofbeta::beta && o2::aod::pidtofbeta::beta < 1.05f) || o2::aod::pidtofbeta::beta < 0.f); - using MyFilteredTracks = soa::Filtered; - - Partition posTracks = o2::aod::track::signed1Pt > 0.f; - Partition negTracks = o2::aod::track::signed1Pt < 0.f; - - // ---------- for data ---------- - - void processRec_SA(aod::Collisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const& tracks) - { - stored_trackIds.reserve(tracks.size()); - - for (auto& collision : collisions) { - auto bc = collision.bc_as(); - initCCDB(bc); - events_bz(d_bz); - - auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - fillTrackHistogram(collision, posTracks_per_coll); - fillTrackHistogram(collision, negTracks_per_coll); - - fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS - if (storeLS) { - fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ - fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- - } - } // end of collision loop - - stored_trackIds.clear(); - stored_trackIds.shrink_to_fit(); - } - PROCESS_SWITCH(skimmerPrimaryElectron, processRec_SA, "process reconstructed info only", true); // standalone - - Preslice trackIndicesPerCollision = aod::track_association::collisionId; - void processRec_TTCA(aod::Collisions const& collisions, aod::BCsWithTimestamps const&, MyTracks const& tracks, aod::TrackAssoc const& trackIndices) - { - stored_trackIds.reserve(tracks.size() * 2); - - for (auto& collision : collisions) { - auto bc = collision.bc_as(); - initCCDB(bc); - events_bz(d_bz); - - auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); - std::vector posTracks_per_coll; - std::vector negTracks_per_coll; - posTracks_per_coll.reserve(trackIdsThisCollision.size()); - negTracks_per_coll.reserve(trackIdsThisCollision.size()); - - for (auto& trackId : trackIdsThisCollision) { - auto track = trackId.template track_as(); - if (!checkTrack(collision, track) || !isElectron(track)) { - continue; - } - - if (track.sign() > 0) { - posTracks_per_coll.emplace_back(track); - } else { - negTracks_per_coll.emplace_back(track); - } - } - - fillTrackHistogram(collision, posTracks_per_coll); - fillTrackHistogram(collision, negTracks_per_coll); - - fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS - if (storeLS) { - fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ - fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- - } - - posTracks_per_coll.clear(); - negTracks_per_coll.clear(); - posTracks_per_coll.shrink_to_fit(); - negTracks_per_coll.shrink_to_fit(); - } // end of collision loop - - stored_trackIds.clear(); - stored_trackIds.shrink_to_fit(); - } - PROCESS_SWITCH(skimmerPrimaryElectron, processRec_TTCA, "process reconstructed info only", false); // with TTCA - - // ---------- for MC ---------- - - using MyFilteredTracksMC = soa::Filtered; - Partition posTracksMC = o2::aod::track::signed1Pt > 0.f; - Partition negTracksMC = o2::aod::track::signed1Pt < 0.f; - void processMC_SA(soa::Join const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyFilteredTracksMC const& tracks) - { - stored_trackIds.reserve(tracks.size()); - - for (auto& collision : collisions) { - if (!collision.has_mcCollision()) { - continue; - } - auto bc = collision.bc_as(); - initCCDB(bc); - events_bz(d_bz); - - auto posTracks_per_coll = posTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - auto negTracks_per_coll = negTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - fillTrackHistogram(collision, posTracks_per_coll); - fillTrackHistogram(collision, negTracks_per_coll); - - fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS - if (storeLS) { - fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ - fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- - } - } // end of collision loop - - stored_trackIds.clear(); - stored_trackIds.shrink_to_fit(); - } - PROCESS_SWITCH(skimmerPrimaryElectron, processMC_SA, "process reconstructed and MC info ", false); - - void processMC_TTCA(soa::Join const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyTracksMC const& tracks, aod::TrackAssoc const& trackIndices) - { - stored_trackIds.reserve(tracks.size() * 2); - - for (auto& collision : collisions) { - if (!collision.has_mcCollision()) { - continue; - } - auto bc = collision.bc_as(); - initCCDB(bc); - events_bz(d_bz); - - auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); - std::vector posTracks_per_coll; - std::vector negTracks_per_coll; - posTracks_per_coll.reserve(trackIdsThisCollision.size()); - negTracks_per_coll.reserve(trackIdsThisCollision.size()); - - for (auto& trackId : trackIdsThisCollision) { - auto track = trackId.template track_as(); - if (!checkTrack(collision, track) || !isElectron(track)) { - continue; - } - - if (track.sign() > 0) { - posTracks_per_coll.emplace_back(track); - } else { - negTracks_per_coll.emplace_back(track); - } - } - - fillTrackHistogram(collision, posTracks_per_coll); - fillTrackHistogram(collision, negTracks_per_coll); - - fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS - if (storeLS) { - fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ - fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- - } - - posTracks_per_coll.clear(); - negTracks_per_coll.clear(); - posTracks_per_coll.shrink_to_fit(); - negTracks_per_coll.shrink_to_fit(); - } // end of collision loop - - stored_trackIds.clear(); - stored_trackIds.shrink_to_fit(); - } - PROCESS_SWITCH(skimmerPrimaryElectron, processMC_TTCA, "process reconstructed info only", false); // with TTCA -}; - -struct prefilterPrimaryElectron { - enum class EM_Electron_PF : int { - kElFromPC = 0, // electron from photon conversion - }; - - Produces ele_pfb; - - SliceCache cache; - Preslice perCol_track = o2::aod::track::collisionId; - PresliceUnsorted perCol_ele = o2::aod::emprimaryelectron::collisionId; - - // CCDB options - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; - - // Operation and minimisation criteria - Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; - - Configurable max_pt_itsonly{"max_pt_itsonly", 0.15, "max pT for ITSonly tracks at PV"}; - Configurable min_dcatopv{"min_dcatopv", -1.f, "DCAxy To PV"}; - Configurable minpt{"minpt", 0.05, "min pt for track for loose track sample"}; - Configurable maxeta{"maxeta", 1.2, "eta acceptance for loose track sample"}; - Configurable mincrossedrows{"mincrossedrows", 40, "min crossed rows"}; - Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max chi2/NclsTPC"}; - Configurable maxchi2its{"maxchi2its", 6.0, "max chi2/NclsITS"}; - Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -4.0, "min. TPC n sigma for electron inclusion"}; - Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", 4.0, "max. TPC n sigma for electron inclusion"}; - Configurable slope{"slope", 0.0185, "slope for m vs. phiv"}; - Configurable intercept{"intercept", -0.0280, "intercept for m vs. phiv"}; - - HistogramRegistry fRegistry{ - "fRegistry", - { - {"hMvsPhiV_PV", "mass vs. phiv;#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", {HistType::kTH2F, {{90, .0f, TMath::Pi()}, {100, 0, 0.1}}}}, - }, - }; - - int mRunNumber; - float d_bz; - Service ccdb; - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - - void init(InitContext&) - { - mRunNumber = 0; - d_bz = 0; - - ccdb->setURL(ccdburl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - } - - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - - // In case override, don't proceed, please - no CCDB access required - if (d_bz_input > -990) { - d_bz = d_bz_input; - o2::parameters::GRPMagField grpmag; - if (fabs(d_bz) > 1e-5) { - grpmag.setL3Current(30000.f / (d_bz / 5.0f)); - } - o2::base::Propagator::initFieldFromGRP(&grpmag); - mRunNumber = bc.runNumber(); - return; - } - - auto run3grp_timestamp = bc.timestamp(); - o2::parameters::GRPObject* grpo = 0x0; - o2::parameters::GRPMagField* grpmag = 0x0; - if (!skipGRPOquery) - grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); - if (grpo) { - o2::base::Propagator::initFieldFromGRP(grpo); - // Fetch magnetic field from ccdb for current collision - d_bz = grpo->getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; - } else { - grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); - if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; - } - o2::base::Propagator::initFieldFromGRP(grpmag); - // Fetch magnetic field from ccdb for current collision - d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; - } - mRunNumber = bc.runNumber(); - } - - o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - - template - bool checkTrack(TCollision const& collision, TTrack const& track) - { - if (!track.hasITS()) { - return false; - } - if (track.itsChi2NCl() > maxchi2its) { - return false; - } - - if (track.hasTPC()) { - if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { - return false; - } - if (track.tpcNClsCrossedRows() < mincrossedrows) { - return false; - } - - if (track.tpcChi2NCl() > maxchi2its) { - return false; - } - } - - gpu::gpustd::array dcaInfo; - auto track_par_recalc = getTrackPar(track); - std::array pVec_recalc = {0, 0, 0}; // px, py, pz - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, track_par_recalc, 2.f, matCorr, &dcaInfo); - getPxPyPz(track_par_recalc, pVec_recalc); - - if (abs(dcaInfo[0]) < min_dcatopv) { - return false; - } - - if (isITSonlyTrack(track) && track_par_recalc.getPt() > max_pt_itsonly) { - return false; - } - if (abs(track_par_recalc.getEta()) > maxeta) { - return false; - } - - return true; - } - - template - bool reconstructPC(TCollision const& collision, TTrack1 const& ele, TTrack2 const& pos) - { - if (pos.sign() * ele.sign() > 0) { // reject same sign pair - return false; - } - - float mee, phiv = 0; - gpu::gpustd::array dcaInfo; - std::array pVec_recalc = {0, 0, 0}; // px, py, pz - - if constexpr (loose_track_sign > 0) { // positive track is loose track - auto track_par_recalc = getTrackPar(pos); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, track_par_recalc, 2.f, matCorr, &dcaInfo); - getPxPyPz(track_par_recalc, pVec_recalc); - - ROOT::Math::PtEtaPhiMVector v1(ele.pt(), ele.eta(), ele.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(track_par_recalc.getPt(), track_par_recalc.getEta(), track_par_recalc.getPhi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - mee = v12.M(); - phiv = getPhivPair(pVec_recalc[0], pVec_recalc[1], pVec_recalc[2], ele.px(), ele.py(), ele.pz(), pos.sign(), ele.sign(), d_bz); - } else { - auto track_par_recalc = getTrackPar(ele); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, track_par_recalc, 2.f, matCorr, &dcaInfo); - getPxPyPz(track_par_recalc, pVec_recalc); - - ROOT::Math::PtEtaPhiMVector v1(track_par_recalc.getPt(), track_par_recalc.getEta(), track_par_recalc.getPhi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - mee = v12.M(); - phiv = getPhivPair(pos.px(), pos.py(), pos.pz(), pVec_recalc[0], pVec_recalc[1], pVec_recalc[2], pos.sign(), ele.sign(), d_bz); - } - - fRegistry.fill(HIST("hMvsPhiV_PV"), phiv, mee); - - if (mee < slope * phiv + intercept) { - return true; - } else { - return false; - } - } - - Preslice trackIndicesPerCollision = aod::track_association::collisionId; - - Filter trackFilter = o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& min_dcatopv < nabs(o2::aod::track::dcaXY) && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true; - using MyFilteredTracks = soa::Filtered; - Partition posTracks = o2::aod::track::signed1Pt > 0.f; - Partition negTracks = o2::aod::track::signed1Pt < 0.f; - - Partition positrons = o2::aod::emprimaryelectron::sign > int8_t(0); - Partition electrons = o2::aod::emprimaryelectron::sign < int8_t(0); - - void processPrefilter_TTCA(aod::Collisions const& collisions, aod::BCsWithTimestamps const&, MyTracks const&, aod::EMPrimaryElectrons const& primaryelectrons, aod::TrackAssoc const& trackIndices) - { - std::map pfb_map; // map track.globalIndex -> prefilter bit - - for (auto& collision : collisions) { - auto bc = collision.template bc_as(); - initCCDB(bc); - - auto positrons_per_coll = positrons->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache); // signal sample - auto electrons_per_coll = electrons->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache); // signal sample - - auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); - std::vector posTracks_per_coll; - std::vector negTracks_per_coll; - posTracks_per_coll.reserve(trackIdsThisCollision.size()); - negTracks_per_coll.reserve(trackIdsThisCollision.size()); - - for (auto& trackId : trackIdsThisCollision) { - auto track = trackId.template track_as(); - if (!checkTrack(collision, track)) { - continue; - } - - if (track.sign() > 0) { - posTracks_per_coll.emplace_back(track); - } else { - negTracks_per_coll.emplace_back(track); - } - } - - for (auto& empos : positrons_per_coll) { - // auto pos = tracks.rawIteratorAt(empos.trackId()); // use rawIterator, if the table is filtered. - for (auto& ele : negTracks_per_coll) { - if (!checkTrack(collision, ele)) { - continue; - } - if (empos.trackId() == ele.globalIndex()) { - continue; - } - bool isPC = reconstructPC<-1>(collision, ele, empos); - if (isPC) { - pfb_map[empos.globalIndex()] |= (uint8_t(1) << static_cast(EM_Electron_PF::kElFromPC)); - } - } // end of loose electron loop - } // end of signal positon loop - - for (auto& emele : electrons_per_coll) { - // auto ele = tracks.rawIteratorAt(emele.trackId()); // use rawIterator, if the table is filtered. - for (auto& pos : posTracks_per_coll) { - if (!checkTrack(collision, pos)) { // track cut is applied to loose sample - continue; - } - if (emele.trackId() == pos.globalIndex()) { - continue; - } - bool isPC = reconstructPC<+1>(collision, emele, pos); - if (isPC) { - pfb_map[emele.globalIndex()] |= (uint8_t(1) << static_cast(EM_Electron_PF::kElFromPC)); - } - } // end of loose positon loop - } // end of signal electron loop - - posTracks_per_coll.clear(); - negTracks_per_coll.clear(); - posTracks_per_coll.shrink_to_fit(); - negTracks_per_coll.shrink_to_fit(); - } // end of collision loop - - for (auto& ele : primaryelectrons) { - ele_pfb(pfb_map[ele.globalIndex()]); - } - - pfb_map.clear(); - } - PROCESS_SWITCH(prefilterPrimaryElectron, processPrefilter_TTCA, "process prefilter with TTCA", false); - - void processPrefilter_SA(aod::Collisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const&, aod::EMPrimaryElectrons const& primaryelectrons) - { - std::map pfb_map; // map track.globalIndex -> prefilter bit - - for (auto& collision : collisions) { - auto bc = collision.template bc_as(); - initCCDB(bc); - - auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); // loose track sample - auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); // loose track sample - - auto positrons_per_coll = positrons->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache); // signal sample - auto electrons_per_coll = electrons->sliceByCachedUnsorted(o2::aod::emprimaryelectron::collisionId, collision.globalIndex(), cache); // signal sample - - for (auto& [ele, empos] : combinations(CombinationsFullIndexPolicy(negTracks_per_coll, positrons_per_coll))) { - // auto pos = tracks.rawIteratorAt(empos.trackId()); // use rawIterator, if the table is filtered. - if (!checkTrack(collision, ele)) { // track cut is applied to loose sample - continue; - } - if (empos.trackId() == ele.globalIndex()) { - continue; - } - - bool isPC = reconstructPC<-1>(collision, ele, empos); - if (isPC) { - pfb_map[empos.globalIndex()] |= (uint8_t(1) << static_cast(EM_Electron_PF::kElFromPC)); - } - } - - for (auto& [pos, emele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, electrons_per_coll))) { - // auto ele = tracks.rawIteratorAt(emele.trackId()); // use rawIterator, if the table is filtered. - if (!checkTrack(collision, pos)) { // track cut is applied to loose sample - continue; - } - if (emele.trackId() == pos.globalIndex()) { - continue; - } - bool isPC = reconstructPC<+1>(collision, emele, pos); - if (isPC) { - pfb_map[emele.globalIndex()] |= (uint8_t(1) << static_cast(EM_Electron_PF::kElFromPC)); - } - } - } // end of collision loop - - for (auto& ele : primaryelectrons) { - ele_pfb(pfb_map[ele.globalIndex()]); - } - - pfb_map.clear(); - } - PROCESS_SWITCH(prefilterPrimaryElectron, processPrefilter_SA, "process prefilter standalone", false); - - void processDummy(aod::EMPrimaryElectrons const& primaryelectrons) - { - for (int i = 0; i < primaryelectrons.size(); i++) { - ele_pfb(0); - } - } - PROCESS_SWITCH(prefilterPrimaryElectron, processDummy, "process dummy", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"skimmer-primary-electron"}), - adaptAnalysisTask(cfgc, TaskName{"prefilter-primary-electron"})}; -} diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx new file mode 100644 index 00000000000..7f840cb179c --- /dev/null +++ b/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx @@ -0,0 +1,440 @@ +// 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 write relevant information about primary electrons. +/// \author daiki.sekihata@cern.ch + +#include +#include +#include +#include + +#include "Math/Vector4D.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "Common/Core/trackUtilities.h" +#include "CommonConstants/PhysicsConstants.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/TrackSelection.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +using namespace o2; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; +using namespace o2::pwgem::photonmeson; + +using MyCollisions = soa::Join; +using MyCollisionsMC = soa::Join; +using MyTracks = soa::Join; +using MyTrack = MyTracks::iterator; +using MyTracksMC = soa::Join; +using MyTrackMC = MyTracksMC::iterator; + +struct skimmerPrimaryElectronFromDalitzEE { + SliceCache cache; + Preslice perCol = o2::aod::track::collisionId; + Produces emprimaryelectrons; + + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + + // Operation and minimisation criteria + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + Configurable min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable mincrossedrows{"mincrossedrows", 70, "min. crossed rows"}; + Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; + Configurable max_frac_shared_clusters_tpc{"max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable min_ncluster_its{"min_ncluster_its", 4, "min ncluster its"}; + Configurable min_ncluster_itsib{"min_ncluster_itsib", 1, "min ncluster itsib"}; + Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max. chi2/NclsTPC"}; + Configurable maxchi2its{"maxchi2its", 6.0, "max. chi2/NclsITS"}; + Configurable minpt{"minpt", 0.05, "min pt for track"}; + Configurable maxeta{"maxeta", 2.0, "max eta acceptance"}; + Configurable dca_xy_max{"dca_xy_max", 1, "max DCAxy in cm"}; + Configurable dca_z_max{"dca_z_max", 1, "max DCAz in cm"}; + Configurable dca_3d_sigma_max{"dca_3d_sigma_max", 2, "max DCA 3D in sigma"}; + Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -2.5, "min. TPC n sigma for electron inclusion"}; + Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", +3.5, "max. TPC n sigma for electron inclusion"}; + Configurable maxTPCNsigmaPi{"maxTPCNsigmaPi", 0.0, "max. TPC n sigma for pion exclusion"}; + Configurable minTPCNsigmaPi{"minTPCNsigmaPi", 0.0, "min. TPC n sigma for pion exclusion"}; + Configurable minTOFNsigmaEl{"minTOFNsigmaEl", -3.5, "min. TOF n sigma for electron inclusion"}; + Configurable maxTOFNsigmaEl{"maxTOFNsigmaEl", +3.5, "max. TOF n sigma for electron inclusion"}; + Configurable maxMee{"maxMee", 0.04, "max. mee to store dalitz ee pairs"}; + Configurable fillLS{"fillLS", true, "flag to fill LS histograms for QA"}; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view dileptonSigns[3] = {"uls/", "lspp/", "lsmm/"}; + + int mRunNumber; + float d_bz; + Service ccdb; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + + void init(InitContext&) + { + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + fRegistry.add("Track/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); + fRegistry.add("Track/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {400, -2.0f, 2.0f}}, false); + fRegistry.add("Track/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); + fRegistry.add("Track/hRelDeltaPt", "pT resolution;p_{T} (GeV/c);#Deltap_{T}/p_{T}", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); + fRegistry.add("Track/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -1.0f, 1.0f}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("Track/hDCAxy_Pt", "DCA_{xy} vs. pT;p_{T} (GeV/c);DCA_{xy} (cm)", kTH2F, {{200, 0, 10}, {200, -1, 1}}, false); + fRegistry.add("Track/hDCAz_Pt", "DCA_{z} vs. pT;p_{T} (GeV/c);DCA_{z} (cm)", kTH2F, {{200, 0, 10}, {200, -1, 1}}, false); + fRegistry.add("Track/hDCAxyzSigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/hDCAzRes_Pt", "DCA_{z} resolution vs. pT;p_{T} (GeV/c);DCA_{z} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); + + // TPC + fRegistry.add("Track/hNclsTPC", "number of TPC clusters", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hNcrTPC", "number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hTPCNclsShared", "TPC Ncls shared/Ncls;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); + fRegistry.add("Track/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("Track/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + + // ITS + fRegistry.add("Track/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("Track/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("Track/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); on ITS #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); + + // TOF + fRegistry.add("Track/hChi2TOF", "chi2 of TOF", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hTOFbeta", "TOF beta;p_{pv} (GeV/c);#beta", kTH2F, {{1000, 0, 10}, {240, 0, 1.2}}, false); + fRegistry.add("Track/hTOFNsigmaEl", "TOF n sigma el;p_{pv} (GeV/c);n #sigma_{e}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaPi", "TOF n sigma pi;p_{pv} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + + // pair + fRegistry.add("Pair/uls/hMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {200, 0, 2}}, false); + fRegistry.add("Pair/uls/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{180, 0, M_PI}, {100, 0, 0.1}}, false); + fRegistry.addClone("Pair/uls/", "Pair/lspp/"); + fRegistry.addClone("Pair/uls/", "Pair/lsmm/"); + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (std::fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + o2::base::Propagator::initFieldFromGRP(&grpmag); + mRunNumber = bc.runNumber(); + return; + } + + auto run3grp_timestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = bc.runNumber(); + } + + template + bool checkTrack(TCollision const&, TTrack const& track) + { + if constexpr (isMC) { + if (!track.has_mcParticle()) { + return false; + } + } + + if (track.tpcChi2NCl() > maxchi2tpc) { + return false; + } + + if (track.itsChi2NCl() > maxchi2its) { + return false; + } + + if (!track.hasITS() || !track.hasTPC()) { + return false; + } + if (track.itsNCls() < min_ncluster_its) { + return false; + } + if (track.itsNClsInnerBarrel() < min_ncluster_itsib) { + return false; + } + + if (track.tpcNClsFound() < min_ncluster_tpc) { + return false; + } + + if (track.tpcNClsCrossedRows() < mincrossedrows) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { + return false; + } + + if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { + return false; + } + + if (std::fabs(track.dcaXY()) > dca_xy_max || std::fabs(track.dcaZ()) > dca_z_max) { + return false; + } + + float dca_3d = 999.f; + float det = track.cYY() * track.cZZ() - track.cZY() * track.cZY(); + if (det < 0) { + dca_3d = 999.f; + } else { + float chi2 = (track.dcaXY() * track.dcaXY() * track.cZZ() + track.dcaZ() * track.dcaZ() * track.cYY() - 2. * track.dcaXY() * track.dcaZ() * track.cZY()) / det; + dca_3d = std::sqrt(std::fabs(chi2) / 2.); + } + if (dca_3d > dca_3d_sigma_max) { + return false; + } + + if (track.pt() < minpt || std::fabs(track.eta()) > maxeta) { + return false; + } + + return true; + } + + template + bool isElectron(TTrack const& track) + { + if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { + return false; + } + if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi) { + return false; + } + if (track.hasTOF() && (track.tofNSigmaEl() < minTOFNsigmaEl || maxTOFNsigmaEl < track.tofNSigmaEl())) { // TOFif + return false; + } + return true; + } + + template + void fillTrackTable(TCollision const& collision, TTrack const& track) + { + if (std::find(stored_trackIds.begin(), stored_trackIds.end(), std::make_pair(collision.globalIndex(), track.globalIndex())) == stored_trackIds.end()) { + emprimaryelectrons(collision.globalIndex(), track.globalIndex(), track.sign(), + track.pt(), track.eta(), track.phi(), track.dcaXY(), track.dcaZ(), track.cYY(), track.cZY(), track.cZZ(), + track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), track.tpcNClsShared(), + track.tpcChi2NCl(), track.tpcInnerParam(), + track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaPi(), + track.beta(), track.tofNSigmaEl(), track.tofNSigmaPi(), + track.itsClusterSizes(), track.itsChi2NCl(), track.tofChi2(), track.detectorMap(), track.tgl()); + + fRegistry.fill(HIST("Track/hPt"), track.pt()); + fRegistry.fill(HIST("Track/hEtaPhi"), track.phi(), track.eta()); + fRegistry.fill(HIST("Track/hQoverPt"), track.sign() / track.pt()); + fRegistry.fill(HIST("Track/hRelDeltaPt"), track.pt(), track.sigma1Pt() * track.pt()); + fRegistry.fill(HIST("Track/hDCAxyz"), track.dcaXY(), track.dcaZ()); + fRegistry.fill(HIST("Track/hDCAxy_Pt"), track.pt(), track.dcaXY()); + fRegistry.fill(HIST("Track/hDCAz_Pt"), track.pt(), track.dcaZ()); + fRegistry.fill(HIST("Track/hDCAxyzSigma"), track.dcaXY() / std::sqrt(track.cYY()), track.dcaZ() / std::sqrt(track.cZZ())); + fRegistry.fill(HIST("Track/hDCAxyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hDCAzRes_Pt"), track.pt(), std::sqrt(track.cZZ()) * 1e+4); // convert cm to um + + fRegistry.fill(HIST("Track/hNclsTPC"), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("Track/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("Track/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("Track/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("Track/hTPCNclsShared"), track.pt(), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("Track/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); + + fRegistry.fill(HIST("Track/hChi2TOF"), track.tofChi2()); + fRegistry.fill(HIST("Track/hTOFbeta"), track.p(), track.beta()); + fRegistry.fill(HIST("Track/hTOFNsigmaEl"), track.p(), track.tofNSigmaEl()); + fRegistry.fill(HIST("Track/hTOFNsigmaPi"), track.p(), track.tofNSigmaPi()); + + fRegistry.fill(HIST("Track/hNclsITS"), track.itsNCls()); + fRegistry.fill(HIST("Track/hChi2ITS"), track.itsChi2NCl()); + fRegistry.fill(HIST("Track/hITSClusterMap"), track.itsClusterMap()); + + int nsize = 0; + for (int il = 0; il < 7; il++) { + nsize += track.itsClsSizeInLayer(il); + } + fRegistry.fill(HIST("Track/hMeanClusterSizeITS"), track.p(), static_cast(nsize) / static_cast(track.itsNCls()) * std::cos(std::atan(track.tgl()))); + + stored_trackIds.emplace_back(std::make_pair(collision.globalIndex(), track.globalIndex())); + } + } + + template + void fillPairInfo(TCollision const& collision, TTracks1 const& tracks1, TTracks2 const& tracks2) + { + if constexpr (pairtype == 0) { // ULS + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (!checkTrack(collision, t1) || !checkTrack(collision, t2)) { + continue; + } + if (!isElectron(t1) || !isElectron(t2)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), d_bz); + fRegistry.fill(HIST("Pair/") + HIST(dileptonSigns[pairtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/") + HIST(dileptonSigns[pairtype]) + HIST("hMvsPhiV"), phiv, v12.M()); + + if (v12.M() > maxMee) { // don't store + continue; + } + fillTrackTable(collision, t1); + fillTrackTable(collision, t2); + } // end of pairing + } else { // LS + for (auto& [t1, t2] : combinations(CombinationsStrictlyUpperIndexPolicy(tracks1, tracks2))) { + if (!checkTrack(collision, t1) || !checkTrack(collision, t2)) { + continue; + } + if (!isElectron(t1) || !isElectron(t2)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), d_bz); + fRegistry.fill(HIST("Pair/") + HIST(dileptonSigns[pairtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/") + HIST(dileptonSigns[pairtype]) + HIST("hMvsPhiV"), phiv, v12.M()); + } // end of pairing + } + } + + std::vector> stored_trackIds; + Filter trackFilter = o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& o2::aod::track::tpcChi2NCl < maxchi2tpc&& o2::aod::track::itsChi2NCl < maxchi2its&& ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true && nabs(o2::aod::track::dcaXY) < dca_xy_max&& nabs(o2::aod::track::dcaZ) < dca_z_max; + Filter pidFilter = minTPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < maxTPCNsigmaEl; + using MyFilteredTracks = soa::Filtered; + Partition posTracks = o2::aod::track::signed1Pt > 0.f; + Partition negTracks = o2::aod::track::signed1Pt < 0.f; + + // ---------- for data ---------- + void processRec(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const& tracks) + { + stored_trackIds.reserve(tracks.size()); + + for (const auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + if (!collision.isSelected()) { + continue; + } + + if (collision.ngpcm() < 1) { + continue; + } + + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + + fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS + if (fillLS) { + fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ + fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- + } + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryElectronFromDalitzEE, processRec, "process reconstructed info only", true); // standalone + + using MyFilteredTracksMC = soa::Filtered; + Partition posTracksMC = o2::aod::track::signed1Pt > 0.f; + Partition negTracksMC = o2::aod::track::signed1Pt < 0.f; + // ---------- for MC ---------- + void processMC(MyCollisionsMC const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyFilteredTracksMC const& tracks) + { + stored_trackIds.reserve(tracks.size()); + + for (const auto& collision : collisions) { + if (!collision.has_mcCollision()) { + continue; + } + if (!collision.isSelected()) { + continue; + } + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (collision.ngpcm() < 1) { + continue; + } + + auto posTracks_per_coll = posTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + + fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS + if (fillLS) { + fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ + fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- + } + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryElectronFromDalitzEE, processMC, "process reconstructed and MC info ", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"skimmer-primary-electron-from-dalitzee"})}; +} diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryMuon.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryMuon.cxx deleted file mode 100644 index ef5284d0568..00000000000 --- a/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryMuon.cxx +++ /dev/null @@ -1,471 +0,0 @@ -// 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 write relevant information for dalitz ee analysis to an AO2D.root file. This file is then the only necessary input to perform pcm analysis. -/// \author daiki.sekihata@cern.ch - -#include "Math/Vector4D.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Common/Core/trackUtilities.h" -#include "CommonConstants/PhysicsConstants.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" - -using namespace o2; -using namespace o2::soa; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::constants::physics; - -using MyTracks = soa::Join; -using MyTracksMC = soa::Join; - -struct skimmerPrimaryMuon { - enum class EM_EEPairType : int { - kULS = 0, - kLSpp = +1, - kLSnn = -1, - }; - - SliceCache cache; - Preslice perCol = o2::aod::track::collisionId; - Produces emprimarymuons; - Produces muon_pfb; - - // Configurables - Configurable min_ncluster_tpc{"min_ncluster_tpc", 10, "min ncluster tpc"}; - Configurable mincrossedrows{"mincrossedrows", 70, "min. crossed rows"}; - Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; - Configurable max_mean_itsob_cluster_size{"max_mean_itsob_cluster_size", 16.f, "max. x cos(lambda)"}; // this is to suppress random combination. - Configurable minitsncls{"minitsncls", 4, "min. number of ITS clusters"}; - Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max. chi2/NclsTPC"}; - Configurable maxchi2its{"maxchi2its", 6.0, "max. chi2/NclsITS"}; - Configurable minpt{"minpt", 0.05, "min pt for track"}; - Configurable maxpt{"maxpt", 1.0, "max pt for track"}; - Configurable maxeta{"maxeta", 0.9, "eta acceptance"}; - Configurable dca_xy_max{"dca_xy_max", 1.0f, "max DCAxy in cm"}; - Configurable dca_z_max{"dca_z_max", 1.0f, "max DCAz in cm"}; - Configurable dca_3d_sigma_max{"dca_3d_sigma_max", 2.0f, "max DCA 3D in sigma"}; - Configurable minTPCNsigmaMu{"minTPCNsigmaMu", -4.0, "min. TPC n sigma for muon inclusion"}; - Configurable maxTPCNsigmaMu{"maxTPCNsigmaMu", 4.0, "max. TPC n sigma for muon inclusion"}; - Configurable maxPin{"maxPin", 1.0, "max pin for PID"}; - Configurable maxPin_TPC{"maxPin_TPC", 0.2, "max pin for TPC pid only"}; - Configurable maxTPCNsigmaMu_lowPin{"maxTPCNsigmaMu_lowPin", +4.0, "max. TPC n sigma for muon inclusion at low pin"}; - Configurable maxTPCNsigmaMu_highPin{"maxTPCNsigmaMu_highPin", +4.0, "max. TPC n sigma for muon inclusion at high pin"}; - Configurable maxTOFNsigmaMu_highPin{"maxTOFNsigmaMu_highPin", +4.0, "max. TOF n sigma for muon inclusion at high pin"}; - Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", 1.0, "max. TPC n sigma for electron exclusion"}; - Configurable maxTPCNsigmaPi_lowPin{"maxTPCNsigmaPi_lowPin", -2.0, "max. TPC n sigma for pion exclusion"}; - Configurable maxTOFNsigmaPi{"maxTOFNsigmaPi", -2.0, "max. TPC n sigma for electron exclusion"}; - Configurable maxMmumu{"maxMmumu", 1.1, "max. mee to store ee pairs"}; - Configurable storeLS{"storeLS", false, "flag to store LS pairs"}; - - HistogramRegistry fRegistry{ - "fRegistry", - { - {"hNpairs", "hNpairs;pair type;Number of Pairs", {HistType::kTH1F, {{3, -1.5f, +1.5f}}}}, - {"Track/hTPCdEdx_Pin_before", "TPC dE/dx vs. p_{in};p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{1000, 0.f, 1.f}, {200, 0.f, 200.f}}}}, - {"Track/hTPCdEdx_Pin_after", "TPC dE/dx vs. p_{in};p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{1000, 0.f, 1.f}, {200, 0.f, 200.f}}}}, - {"Track/hTOFbeta_Pin_before", "TOF beta vs. p_{in};p_{in} (GeV/c);TOF #beta", {HistType::kTH2F, {{1000, 0.f, 1.f}, {250, 0.6f, 1.1f}}}}, - {"Track/hTOFbeta_Pin_after", "TOF beta vs. p_{in};p_{in} (GeV/c);TOF #beta", {HistType::kTH2F, {{1000, 0.f, 1.f}, {250, 0.6f, 1.1f}}}}, - {"Track/hTPCNsigmaEl_before", "TPC n sigma e vs. p_{in};p_{in} (GeV/c);n #sigma_{e}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 1.f}, {100, -5.f, +5.f}}}}, - {"Track/hTOFNsigmaEl_before", "TOF n sigma e vs. p_{in};p_{in} (GeV/c);n #sigma_{e}^{TOF}", {HistType::kTH2F, {{1000, 0.f, 1.f}, {100, -5.f, +5.f}}}}, - {"Track/hTPCNsigmaMu_before", "TPC n sigma #mu vs. p_{in};p_{in} (GeV/c);n #sigma_{#mu}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 1.f}, {100, -5.f, +5.f}}}}, - {"Track/hTOFNsigmaMu_before", "TOF n sigma #mu vs. p_{in};p_{in} (GeV/c);n #sigma_{#mu}^{TOF}", {HistType::kTH2F, {{1000, 0.f, 1.f}, {100, -5.f, +5.f}}}}, - {"Track/hTPCNsigmaPi_before", "TPC n sigma #pi vs. p_{in};p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 1.f}, {100, -5.f, +5.f}}}}, - {"Track/hTOFNsigmaPi_before", "TOF n sigma #pi vs. p_{in};p_{in} (GeV/c);n #sigma_{#pi}^{TOF}", {HistType::kTH2F, {{1000, 0.f, 1.f}, {100, -5.f, +5.f}}}}, - {"Track/hTPCNsigmaEl_after", "TPC n sigma e vs. p_{in};p_{in} (GeV/c);n #sigma_{e}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 1.f}, {100, -5.f, +5.f}}}}, - {"Track/hTOFNsigmaEl_after", "TOF n sigma e vs. p_{in};p_{in} (GeV/c);n #sigma_{e}^{TOF}", {HistType::kTH2F, {{1000, 0.f, 1.f}, {100, -5.f, +5.f}}}}, - {"Track/hTPCNsigmaMu_after", "TPC n sigma #mu vs. p_{in};p_{in} (GeV/c);n #sigma_{#mu}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 1.f}, {100, -5.f, +5.f}}}}, - {"Track/hTOFNsigmaMu_after", "TOF n sigma #mu vs. p_{in};p_{in} (GeV/c);n #sigma_{#mu}^{TOF}", {HistType::kTH2F, {{1000, 0.f, 1.f}, {100, -5.f, +5.f}}}}, - {"Track/hTPCNsigmaPi_after", "TPC n sigma #pi vs. p_{in};p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 1.f}, {100, -5.f, +5.f}}}}, - {"Track/hTOFNsigmaPi_after", "TOF n sigma #pi vs. p_{in};p_{in} (GeV/c);n #sigma_{#pi}^{TOF}", {HistType::kTH2F, {{1000, 0.f, 1.f}, {100, -5.f, +5.f}}}}, - {"Track/hDCAxyz_before", "DCA xy vs. z to PV;DCA_{xy} (cm);DCA_{z} (cm)", {HistType::kTH2F, {{200, -1.f, 1.f}, {200, -1.f, +1.f}}}}, - {"Track/hDCAxyz_after", "DCA xy vs. z to PV;DCA_{xy} (cm);DCA_{z} (cm)", {HistType::kTH2F, {{200, -1.f, 1.f}, {200, -1.f, +1.f}}}}, - {"Pair/hMmumuPtmumu", "ULS m_{#mu#mu} vs. p_{T,#mu#mu};m_{#mu#mu} (GeV/c^{2});p_{T,#mu#mu} (GeV/c)", {HistType::kTH2F, {{100, 0.2f, 1.2f}, {120, 0.f, 1.2f}}}}, - // for MC primary muon - {"MC/Primary/hPt_Gen", "generated pT;p_{T,#mu}^{gen} (GeV/c)", {HistType::kTH1F, {{100, 0.f, 1.f}}}}, - {"MC/Primary/hPt_Rec", "reconstructed pT;p_{T,#mu}^{rec} (GeV/c)", {HistType::kTH1F, {{100, 0.f, 1.f}}}}, - {"MC/Primary/hP_Correlation", "p vs. pin correlation;p_{pv} (GeV/c);(p_{in} - p_{pv})/p_{pv}", {HistType::kTH2F, {{100, 0.f, 1.f}, {200, -1, +1}}}}, - {"MC/Primary/hP_Correlation_Profile", "p vs. pin correlation;p_{pv} (GeV/c);(p_{in} - p_{pv})/p_{pv}", {HistType::kTProfile, {{100, 0.f, 1.f}}}}, - {"MC/Primary/hTPCdEdx_Pin", "TPC dE/dx vs. p_{in};p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{1000, 0.f, 1.f}, {200, 0.f, 200.f}}}}, - {"MC/Primary/hTOFbeta_Pin", "TOF beta vs. p_{in};p_{in} (GeV/c);TOF #beta", {HistType::kTH2F, {{1000, 0.f, 1.f}, {250, 0.6f, 1.1f}}}}, - {"MC/Primary/hNclsITS", "Ncls ITS;N_{cls}^{ITS}", {HistType::kTH1F, {{8, -0.5f, +7.5f}}}}, - {"MC/Primary/hChi2ITS", "chi2 ITS;#chi^{2}/N_{cls}^{ITS}", {HistType::kTH1F, {{100, 0.f, 10.f}}}}, - {"MC/Primary/hNclsTPC", "Ncls TPC;N_{cls}^{TPC}", {HistType::kTH1F, {{161, -0.5f, +160.5f}}}}, - {"MC/Primary/hNcrTPC", "Ncr TPC;N_{cr}^{TPC}", {HistType::kTH1F, {{161, -0.5f, +160.5f}}}}, - {"MC/Primary/hNfTPC", "Nfindable TPC;N_{f}^{TPC}", {HistType::kTH1F, {{161, -0.5f, +160.5f}}}}, - {"MC/Primary/hChi2TPC", "chi2 TPC;#chi^{2}/N_{cls}^{TPC}", {HistType::kTH1F, {{100, 0.f, 10.f}}}}, - {"MC/Primary/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", {HistType::kTH2F, {{200, -1.f, +1.f}, {200, -1.f, +1.f}}}}, - {"MC/Primary/hDCAxy_Pt", "DCA xy vs. p_{T};p_{T} (GeV/c);DCA_{xy} (cm)", {HistType::kTH2F, {{100, 0.f, +1.f}, {200, -1.f, +1.f}}}}, - {"MC/Primary/hDCAz_Pt", "DCA z vs. p_{T};p_{T} (GeV/c);DCA_{z} (cm)", {HistType::kTH2F, {{100, 0.f, +1.f}, {200, -1.f, +1.f}}}}, - {"MC/Primary/hDCA3D", "DCA;DCA_{3D} (cm)", {HistType::kTH1F, {{100, 0.f, +1.f}}}}, - {"MC/Primary/hDCAxy_resolution", "DCA xy resolution;DCA_{xy} resolution (cm)", {HistType::kTH1F, {{100, 0.f, +0.1f}}}}, - {"MC/Primary/hDCAz_resolution", "DCA z resolution;DCA_{z} resolution (cm)", {HistType::kTH1F, {{100, 0.f, +0.1f}}}}, - {"MC/Primary/hDCAxyz_sigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", {HistType::kTH2F, {{200, -10.f, +10.f}, {200, -10.f, +10.f}}}}, - {"MC/Primary/hDCA3D_sigma", "DCA;DCA_{3D} (#sigma)", {HistType::kTH1F, {{100, 0.f, +10.f}}}}, - {"MC/Primary/hProdVtx", "#mu production vtx;X_{MC} (cm);Y_{MC} (cm)", {HistType::kTH2F, {{200, -100.f, +100.f}, {200, -100.f, +100.f}}}}, - // for MC seconday muon - {"MC/Secondary/hPt_Gen", "generated pT;p_{T,#mu}^{gen} (GeV/c)", {HistType::kTH1F, {{100, 0.f, 1.f}}}}, - {"MC/Secondary/hPt_Rec", "reconstructed pT;p_{T,#mu}^{rec} (GeV/c)", {HistType::kTH1F, {{100, 0.f, 1.f}}}}, - {"MC/Secondary/hP_Correlation", "p vs. pin correlation;p_{pv} (GeV/c);(p_{in} - p_{pv})/p_{pv}", {HistType::kTH2F, {{100, 0.f, 1.f}, {200, -1, +1}}}}, - {"MC/Secondary/hP_Correlation_Profile", "p vs. pin correlation;p_{pv} (GeV/c);(p_{in} - p_{pv})/p_{pv}", {HistType::kTProfile, {{100, 0.f, 1.f}}}}, - {"MC/Secondary/hTPCdEdx_Pin", "TPC dE/dx vs. p_{in};p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{1000, 0.f, 1.f}, {200, 0.f, 200.f}}}}, - {"MC/Secondary/hTOFbeta_Pin", "TOF beta vs. p_{in};p_{in} (GeV/c);TOF #beta", {HistType::kTH2F, {{1000, 0.f, 1.f}, {250, 0.6f, 1.1f}}}}, - {"MC/Secondary/hNclsITS", "Ncls ITS;N_{cls}^{ITS}", {HistType::kTH1F, {{8, -0.5f, +7.5f}}}}, - {"MC/Secondary/hChi2ITS", "chi2 ITS;#chi^{2}/N_{cls}^{ITS}", {HistType::kTH1F, {{100, 0.f, 10.f}}}}, - {"MC/Secondary/hNclsTPC", "Ncls TPC;N_{cls}^{TPC}", {HistType::kTH1F, {{161, -0.5f, +160.5f}}}}, - {"MC/Secondary/hNcrTPC", "Ncr TPC;N_{cr}^{TPC}", {HistType::kTH1F, {{161, -0.5f, +160.5f}}}}, - {"MC/Secondary/hNfTPC", "Nfindable TPC;N_{f}^{TPC}", {HistType::kTH1F, {{161, -0.5f, +160.5f}}}}, - {"MC/Secondary/hChi2TPC", "chi2 TPC;#chi^{2}/N_{cls}^{TPC}", {HistType::kTH1F, {{100, 0.f, 10.f}}}}, - {"MC/Secondary/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", {HistType::kTH2F, {{200, -1.f, +1.f}, {200, -1.f, +1.f}}}}, - {"MC/Secondary/hDCAxy_Pt", "DCA xy vs. p_{T};p_{T} (GeV/c);DCA_{xy} (cm)", {HistType::kTH2F, {{100, 0.f, +1.f}, {200, -1.f, +1.f}}}}, - {"MC/Secondary/hDCAz_Pt", "DCA z vs. p_{T};p_{T} (GeV/c);DCA_{z} (cm)", {HistType::kTH2F, {{100, 0.f, +1.f}, {200, -1.f, +1.f}}}}, - {"MC/Secondary/hDCA3D", "DCA;DCA_{3D} (cm)", {HistType::kTH1F, {{100, 0.f, +1.f}}}}, - {"MC/Secondary/hDCAxy_resolution", "DCA xy resolution;DCA_{xy} resolution (cm)", {HistType::kTH1F, {{100, 0.f, +0.1f}}}}, - {"MC/Secondary/hDCAz_resolution", "DCA z resolution;DCA_{z} resolution (cm)", {HistType::kTH1F, {{100, 0.f, +0.1f}}}}, - {"MC/Secondary/hDCAxyz_sigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", {HistType::kTH2F, {{200, -10.f, +10.f}, {200, -10.f, +10.f}}}}, - {"MC/Secondary/hDCA3D_sigma", "DCA;DCA_{3D} (#sigma)", {HistType::kTH1F, {{100, 0.f, +10.f}}}}, - {"MC/Secondary/hProdVtx", "#mu production vtx;X_{MC} (cm);Y_{MC} (cm)", {HistType::kTH2F, {{200, -100.f, +100.f}, {200, -100.f, +100.f}}}}, - }, - }; - - std::pair> itsRequirement = {1, {0, 1, 2}}; // any hits on 3 ITS ib layers. - - void init(InitContext const&) {} - - template - bool checkTrack(TTrack const& track) - { - if constexpr (isMC) { - if (!track.has_mcParticle()) { - return false; - } - } - - if (!track.hasITS() || !track.hasTPC()) { - return false; - } - - if (track.itsNCls() < minitsncls) { - return false; - } - - auto hits = std::count_if(itsRequirement.second.begin(), itsRequirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); - if (hits < itsRequirement.first) { - return false; - } - - uint32_t itsClusterSizes = track.itsClusterSizes(); - int total_cluster_size = 0, nl = 0; - for (unsigned int layer = 3; layer < 7; layer++) { - int cluster_size_per_layer = (itsClusterSizes >> (layer * 4)) & 0xf; - if (cluster_size_per_layer > 0) { - nl++; - } - total_cluster_size += cluster_size_per_layer; - } - if (static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(track.tgl())) > max_mean_itsob_cluster_size) { - return false; - } - - if (track.tpcNClsFound() < min_ncluster_tpc) { - return false; - } - - if (track.tpcNClsCrossedRows() < mincrossedrows) { - return false; - } - - if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { - return false; - } - - // float rel_diff = (track.tpcInnerParam() - track.p())/track.p(); - // if (rel_diff < -0.0156432+-0.00154524/pow(track.p(),2.29244) - 0.02 || -0.0156432+-0.00154524/pow(track.p(),2.29244) + 0.02 < rel_diff) { - // return false; - // } - - float dca_3d = 999.f; - float det = track.cYY() * track.cZZ() - track.cZY() * track.cZY(); - if (det < 0) { - dca_3d = 999.f; - } else { - float chi2 = (track.dcaXY() * track.dcaXY() * track.cZZ() + track.dcaZ() * track.dcaZ() * track.cYY() - 2. * track.dcaXY() * track.dcaZ() * track.cZY()) / det; - dca_3d = std::sqrt(std::abs(chi2) / 2.); - } - if (dca_3d > dca_3d_sigma_max) { - return false; - } - - return true; - } - - template - bool isMuon(TTrack const& track) - { - if (isInElectronBand(track)) { // reject electron first. - return false; - } - - if (track.hasTOF()) { - return abs(track.tpcNSigmaMu()) < maxTPCNsigmaMu_highPin && abs(track.tofNSigmaMu()) < maxTOFNsigmaMu_highPin && track.tofNSigmaPi() < maxTOFNsigmaPi; - } else if (track.tpcInnerParam() < maxPin_TPC) { - return abs(track.tpcNSigmaMu()) < maxTPCNsigmaMu_lowPin && track.tpcNSigmaPi() < maxTPCNsigmaPi_lowPin; - } else { // muon at high momentum cannot be identified without TOF. - return false; - } - } - - template - bool isInElectronBand(TTrack const& track) - { - return abs(track.tpcNSigmaEl()) < maxTPCNsigmaEl; - } - - template - void fillTrackHistogram(TTracks const& tracks) - { - for (auto& track : tracks) { - if (!checkTrack(track)) { - continue; - } - - fRegistry.fill(HIST("Track/hTPCdEdx_Pin_before"), track.tpcInnerParam(), track.tpcSignal()); - fRegistry.fill(HIST("Track/hTOFbeta_Pin_before"), track.tpcInnerParam(), track.beta()); - fRegistry.fill(HIST("Track/hTPCNsigmaMu_before"), track.tpcInnerParam(), track.tpcNSigmaMu()); - fRegistry.fill(HIST("Track/hTOFNsigmaMu_before"), track.tpcInnerParam(), track.tofNSigmaMu()); - fRegistry.fill(HIST("Track/hTPCNsigmaPi_before"), track.tpcInnerParam(), track.tpcNSigmaPi()); - fRegistry.fill(HIST("Track/hTOFNsigmaPi_before"), track.tpcInnerParam(), track.tofNSigmaPi()); - fRegistry.fill(HIST("Track/hTPCNsigmaEl_before"), track.tpcInnerParam(), track.tpcNSigmaEl()); - fRegistry.fill(HIST("Track/hTOFNsigmaEl_before"), track.tpcInnerParam(), track.tofNSigmaEl()); - fRegistry.fill(HIST("Track/hDCAxyz_before"), track.dcaXY(), track.dcaZ()); - - float dca_3d = 999.f; - float det = track.cYY() * track.cZZ() - track.cZY() * track.cZY(); - if (det < 0) { - dca_3d = 999.f; - } else { - float chi2 = (track.dcaXY() * track.dcaXY() * track.cZZ() + track.dcaZ() * track.dcaZ() * track.cYY() - 2. * track.dcaXY() * track.dcaZ() * track.cZY()) / det; - dca_3d = std::sqrt(std::abs(chi2) / 2.); - } - - if constexpr (isMC) { - auto mctrack = track.template mcParticle_as(); - if (abs(mctrack.pdgCode()) == 13 /* && mctrack.has_mothers()*/) { - // auto mp = mctrack.template mothers_first_as(); - if (mctrack.isPhysicalPrimary()) { - if (isMuon(track)) { - fRegistry.fill(HIST("MC/Primary/hPt_Rec"), track.pt()); - } - fRegistry.fill(HIST("MC/Primary/hP_Correlation"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); - fRegistry.fill(HIST("MC/Primary/hP_Correlation_Profile"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); - fRegistry.fill(HIST("MC/Primary/hTPCdEdx_Pin"), track.tpcInnerParam(), track.tpcSignal()); - fRegistry.fill(HIST("MC/Primary/hTOFbeta_Pin"), track.tpcInnerParam(), track.beta()); - fRegistry.fill(HIST("MC/Primary/hNclsITS"), track.itsNCls()); - fRegistry.fill(HIST("MC/Primary/hChi2ITS"), track.itsChi2NCl()); - fRegistry.fill(HIST("MC/Primary/hNcrTPC"), track.tpcNClsCrossedRows()); - fRegistry.fill(HIST("MC/Primary/hNclsTPC"), track.tpcNClsFound()); - fRegistry.fill(HIST("MC/Primary/hNfTPC"), track.tpcNClsFindable()); - fRegistry.fill(HIST("MC/Primary/hChi2TPC"), track.tpcChi2NCl()); - fRegistry.fill(HIST("MC/Primary/hDCAxyz"), track.dcaXY(), track.dcaZ()); - fRegistry.fill(HIST("MC/Primary/hDCAxy_Pt"), track.pt(), track.dcaXY()); - fRegistry.fill(HIST("MC/Primary/hDCAz_Pt"), track.pt(), track.dcaZ()); - fRegistry.fill(HIST("MC/Primary/hDCA3D"), sqrt(pow(track.dcaXY(), 2) + pow(track.dcaZ(), 2))); - fRegistry.fill(HIST("MC/Primary/hDCAxy_resolution"), sqrt(track.cYY())); - fRegistry.fill(HIST("MC/Primary/hDCAz_resolution"), sqrt(track.cZZ())); - fRegistry.fill(HIST("MC/Primary/hDCAxyz_sigma"), track.dcaXY() / sqrt(track.cYY()), track.dcaZ() / sqrt(track.cZZ())); - fRegistry.fill(HIST("MC/Primary/hDCA3D_sigma"), dca_3d); - fRegistry.fill(HIST("MC/Primary/hProdVtx"), mctrack.vx(), mctrack.vy()); - } else { - if (isMuon(track)) { - fRegistry.fill(HIST("MC/Secondary/hPt_Rec"), track.pt()); - } - fRegistry.fill(HIST("MC/Secondary/hP_Correlation"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); - fRegistry.fill(HIST("MC/Secondary/hP_Correlation_Profile"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); - fRegistry.fill(HIST("MC/Secondary/hTPCdEdx_Pin"), track.tpcInnerParam(), track.tpcSignal()); - fRegistry.fill(HIST("MC/Secondary/hTOFbeta_Pin"), track.tpcInnerParam(), track.beta()); - fRegistry.fill(HIST("MC/Secondary/hNclsITS"), track.itsNCls()); - fRegistry.fill(HIST("MC/Secondary/hChi2ITS"), track.itsChi2NCl()); - fRegistry.fill(HIST("MC/Secondary/hNcrTPC"), track.tpcNClsCrossedRows()); - fRegistry.fill(HIST("MC/Secondary/hNclsTPC"), track.tpcNClsFound()); - fRegistry.fill(HIST("MC/Secondary/hNfTPC"), track.tpcNClsFindable()); - fRegistry.fill(HIST("MC/Secondary/hChi2TPC"), track.tpcChi2NCl()); - fRegistry.fill(HIST("MC/Secondary/hDCAxyz"), track.dcaXY(), track.dcaZ()); - fRegistry.fill(HIST("MC/Secondary/hDCAxy_Pt"), track.pt(), track.dcaXY()); - fRegistry.fill(HIST("MC/Secondary/hDCAz_Pt"), track.pt(), track.dcaZ()); - fRegistry.fill(HIST("MC/Secondary/hDCA3D"), sqrt(pow(track.dcaXY(), 2) + pow(track.dcaZ(), 2))); - fRegistry.fill(HIST("MC/Secondary/hDCAxy_resolution"), sqrt(track.cYY())); - fRegistry.fill(HIST("MC/Secondary/hDCAz_resolution"), sqrt(track.cZZ())); - fRegistry.fill(HIST("MC/Secondary/hDCAxyz_sigma"), track.dcaXY() / sqrt(track.cYY()), track.dcaZ() / sqrt(track.cZZ())); - fRegistry.fill(HIST("MC/Secondary/hDCA3D_sigma"), dca_3d); - fRegistry.fill(HIST("MC/Secondary/hProdVtx"), mctrack.vx(), mctrack.vy()); - } - } - } - } - } - - template - void fillTrackTable(TTrack const& track) - { - // bool is_stored = std::find(stored_trackIds.begin(), stored_trackIds.end(), track.globalIndex()) != stored_trackIds.end(); - if (std::find(stored_trackIds.begin(), stored_trackIds.end(), track.globalIndex()) == stored_trackIds.end()) { - emprimarymuons(track.collisionId(), track.globalIndex(), track.sign(), - track.pt(), track.eta(), track.phi(), track.dcaXY(), track.dcaZ(), - track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), - track.tpcChi2NCl(), track.tpcInnerParam(), - track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaMu(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), - track.beta(), track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), - track.itsClusterSizes(), track.itsChi2NCl(), track.detectorMap(), track.tgl(), track.cYY(), track.cZZ(), track.cZY()); - fRegistry.fill(HIST("Track/hTPCdEdx_Pin_after"), track.tpcInnerParam(), track.tpcSignal()); - fRegistry.fill(HIST("Track/hTOFbeta_Pin_after"), track.tpcInnerParam(), track.beta()); - fRegistry.fill(HIST("Track/hTPCNsigmaMu_after"), track.tpcInnerParam(), track.tpcNSigmaMu()); - fRegistry.fill(HIST("Track/hTOFNsigmaMu_after"), track.tpcInnerParam(), track.tofNSigmaMu()); - fRegistry.fill(HIST("Track/hTPCNsigmaPi_after"), track.tpcInnerParam(), track.tpcNSigmaPi()); - fRegistry.fill(HIST("Track/hTOFNsigmaPi_after"), track.tpcInnerParam(), track.tofNSigmaPi()); - fRegistry.fill(HIST("Track/hTPCNsigmaEl_after"), track.tpcInnerParam(), track.tpcNSigmaEl()); - fRegistry.fill(HIST("Track/hTOFNsigmaEl_after"), track.tpcInnerParam(), track.tofNSigmaEl()); - fRegistry.fill(HIST("Track/hDCAxyz_after"), track.dcaXY(), track.dcaZ()); - stored_trackIds.emplace_back(track.globalIndex()); - muon_pfb(0); - } - } - - template - void fillPairInfo(TCollision const& /*collision*/, TTracks1 const& tracks1, TTracks2 const& tracks2) - { - if constexpr (pairtype == EM_EEPairType::kULS) { // ULS - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { - if (!checkTrack(t1) || !checkTrack(t2)) { - continue; - } - if (!isMuon(t1) || !isMuon(t2)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassMuon); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassMuon); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - fRegistry.fill(HIST("Pair/hMmumuPtmumu"), v12.M(), v12.Pt()); - - if (v12.M() > maxMmumu) { // don't store - continue; - } - fRegistry.fill(HIST("hNpairs"), static_cast(pairtype)); - fillTrackTable(t1); - fillTrackTable(t2); - } // end of pairing loop - } else { // LS - for (auto& [t1, t2] : combinations(CombinationsStrictlyUpperIndexPolicy(tracks1, tracks2))) { - if (!checkTrack(t1) || !checkTrack(t2)) { - continue; - } - if (!isMuon(t1) || !isMuon(t2)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassMuon); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassMuon); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - if (v12.M() > maxMmumu) { // don't store - continue; - } - fRegistry.fill(HIST("hNpairs"), static_cast(pairtype)); - fillTrackTable(t1); - fillTrackTable(t2); - } // end of pairing loop - } - } - - // ============================ FUNCTION DEFINITIONS ==================================================== - std::vector stored_trackIds; - - Filter trackFilter = minpt < o2::aod::track::pt && o2::aod::track::pt < maxpt && nabs(o2::aod::track::eta) < maxeta && nabs(o2::aod::track::dcaXY) < dca_xy_max && nabs(o2::aod::track::dcaZ) < dca_z_max && o2::aod::track::tpcChi2NCl < maxchi2tpc && o2::aod::track::itsChi2NCl < maxchi2its && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true; - Filter pidFilter = minTPCNsigmaMu < o2::aod::pidtpc::tpcNSigmaMu && o2::aod::pidtpc::tpcNSigmaMu < maxTPCNsigmaMu && o2::aod::track::tpcInnerParam < maxPin; - - using MyFilteredTracks = soa::Filtered; - Partition posTracks = o2::aod::track::signed1Pt > 0.f; - Partition negTracks = o2::aod::track::signed1Pt < 0.f; - void processRec(aod::Collisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const& tracks) - { - stored_trackIds.reserve(tracks.size()); - for (auto& collision : collisions) { - auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - fillTrackHistogram(posTracks_per_coll); - fillTrackHistogram(negTracks_per_coll); - - fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS - if (storeLS) { - fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ - fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- - } - } // end of collision loop - - stored_trackIds.clear(); - stored_trackIds.shrink_to_fit(); - } - PROCESS_SWITCH(skimmerPrimaryMuon, processRec, "process reconstructed info only", true); - - using MyFilteredTracksMC = soa::Filtered; - Partition posTracksMC = o2::aod::track::signed1Pt > 0.f; - Partition negTracksMC = o2::aod::track::signed1Pt < 0.f; - void processMC(soa::Join const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyFilteredTracksMC const& tracks, aod::McParticles const& mcparticles) - { - stored_trackIds.reserve(tracks.size()); - for (auto& collision : collisions) { - if (!collision.has_mcCollision()) { - continue; - } - - auto posTracks_per_coll = posTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - auto negTracks_per_coll = negTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - fillTrackHistogram(posTracks_per_coll); - fillTrackHistogram(negTracks_per_coll); - - fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS - if (storeLS) { - fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ - fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- - } - } // end of collision loop - - stored_trackIds.clear(); - stored_trackIds.shrink_to_fit(); - - // for generated info - for (auto& mcparticle : mcparticles) { - if (abs(mcparticle.pdgCode()) != 13) { - continue; - } - - if (abs(mcparticle.eta()) > maxeta) { - continue; - } - - if (mcparticle.isPhysicalPrimary()) { - fRegistry.fill(HIST("MC/Primary/hPt_Gen"), mcparticle.pt()); - } else { - fRegistry.fill(HIST("MC/Secondary/hPt_Gen"), mcparticle.pt()); - } - } - } - - PROCESS_SWITCH(skimmerPrimaryMuon, processMC, "process reconstructed and MC info ", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"skimmer-primary-muon"})}; -} diff --git a/PWGEM/PhotonMeson/Tasks/CMakeLists.txt b/PWGEM/PhotonMeson/Tasks/CMakeLists.txt index c3bf7fe18e5..975a217fab7 100644 --- a/PWGEM/PhotonMeson/Tasks/CMakeLists.txt +++ b/PWGEM/PhotonMeson/Tasks/CMakeLists.txt @@ -24,6 +24,11 @@ o2physics_add_dpl_workflow(emc-pi0-qc PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(emc-bc-wise-pi0 + SOURCES emcalBcWisePi0.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(pcm-qc SOURCES pcmQC.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore @@ -36,22 +41,12 @@ o2physics_add_dpl_workflow(pcm-qc-mc o2physics_add_dpl_workflow(dalitz-ee-qc SOURCES dalitzEEQC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore O2Physics::PWGEMDileptonCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(dalitz-ee-qc-mc SOURCES dalitzEEQCMC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(dalitz-mumu-qc - SOURCES dalitzMuMuQC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(dalitz-mumu-qc-mc - SOURCES dalitzMuMuQCMC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore O2Physics::PWGEMDileptonCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(emcal-qc @@ -59,6 +54,11 @@ o2physics_add_dpl_workflow(emcal-qc PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(heavy-neutral-meson + SOURCES HeavyNeutralMeson.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(phos-qc SOURCES phosQC.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore @@ -74,34 +74,39 @@ o2physics_add_dpl_workflow(single-photon-mc PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(pi0eta-to-gammagamma - SOURCES Pi0EtaToGammaGamma.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore +o2physics_add_dpl_workflow(pi0eta-to-gammagamma-pcmpcm + SOURCES Pi0EtaToGammaGammaPCMPCM.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(pi0eta-to-gammagamma-mc - SOURCES Pi0EtaToGammaGammaMC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore +o2physics_add_dpl_workflow(pi0eta-to-gammagamma-pcmdalitzee + SOURCES Pi0EtaToGammaGammaPCMDalitzEE.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(tagging-pi0 - SOURCES TaggingPi0.cxx +o2physics_add_dpl_workflow(pi0eta-to-gammagamma-emcemc + SOURCES Pi0EtaToGammaGammaEMCEMC.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(tagging-pi0-mc - SOURCES TaggingPi0MC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore +o2physics_add_dpl_workflow(pi0eta-to-gammagamma-mc-pcmpcm + SOURCES Pi0EtaToGammaGammaMCPCMPCM.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pi0eta-to-gammagamma-mc-pcmdalitzee + SOURCES Pi0EtaToGammaGammaMCPCMDalitzEE.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(photon-hbt - SOURCES PhotonHBT.cxx +o2physics_add_dpl_workflow(pi0eta-to-gammagamma-mc-emcemc + SOURCES Pi0EtaToGammaGammaMCEMCEMC.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(tag-and-probe SOURCES TagAndProbe.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(material-budget @@ -119,3 +124,23 @@ o2physics_add_dpl_workflow(check-mc-v0 PUBLIC_LINK_LIBRARIES O2::Framework O2::DCAFitter O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(pi0-flow-emc + SOURCES taskPi0FlowEMC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(prefilter-photon + SOURCES prefilterPhoton.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(tagging-pi0-pcmdalitzee + SOURCES TaggingPi0PCMDalitzEE.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(tagging-pi0-mc-pcmdalitzee + SOURCES TaggingPi0MCPCMDalitzEE.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) + diff --git a/PWGEM/PhotonMeson/Tasks/HeavyNeutralMeson.cxx b/PWGEM/PhotonMeson/Tasks/HeavyNeutralMeson.cxx new file mode 100644 index 00000000000..56ef57a6d79 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/HeavyNeutralMeson.cxx @@ -0,0 +1,593 @@ +// 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 HeavyNeutralMeson.cxx +/// +/// \brief This code loops over collisions to reconstruct heavy mesons (omega or eta') using EMCal clusters and V0s (PCM) +/// +/// \author Nicolas Strangmann (nicolas.strangmann@cern.ch) - Goethe University Frankfurt +/// + +#include +#include +#include + +#include "Math/GenVector/Boost.h" +#include "Math/Vector4D.h" +#include "TMath.h" +#include "TRandom3.h" + +#include "PWGEM/PhotonMeson/Utils/HNMUtilities.h" +#include "PWGJE/DataModel/EMCALMatchedCollisions.h" + +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "fairlogger/Logger.h" +#include "Framework/Configurable.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "CommonConstants/MathConstants.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::pwgem::photonmeson; + +namespace o2::aod +{ +using MyBCs = soa::Join; +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; +using SelectedTracks = soa::Join; +} // namespace o2::aod + +namespace hnm +{ + +enum TracksPID { + kPion, + kNTracksPID +}; + +enum PIDLimits { kTPCMin, + kTPCMax, + kTPCTOF, + kITSmin, + kITSmax, + kNPIDLimits +}; + +const std::vector speciesName{"pion"}; // ToDo include charged pions +const std::vector pTCutsName{"Pt min", "Pt max", "P TOF thres"}; +const std::vector pidCutsName{"TPC min", "TPC max", "TPCTOF max", "ITS min", "ITS max"}; +const float pidcutsTable[kNTracksPID][kNPIDLimits]{{-4.f, 4.f, 4.f, -99.f, 99.f}}; +const float ptcutsTable[kNTracksPID][3]{{0.35f, 6.f, 0.75f}}; +const float nClusterMinTPC[1][kNTracksPID]{{80.0f}}; +const float nClusterMinITS[1][kNTracksPID]{{4}}; + +} // namespace hnm + +struct HeavyNeutralMeson { + + // --------------------------------> Configurables <------------------------------------ + // - Event selection cuts + // - Track selection cuts + // - Cluster shifts + // - HNM mass selection windows + // ------------------------------------------------------------------------------------- + // ---> Event selection + Configurable confEvtSelectZvtx{"confEvtSelectZvtx", true, "Event selection includes max. z-Vertex"}; + Configurable confEvtZvtx{"confEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; + Configurable confEvtRequireSel8{"confEvtRequireSel8", false, "Evt sel: check for offline selection (sel8)"}; + + // ---> Track selection + Configurable> cfgPtCuts{"cfgPtCuts", {hnm::ptcutsTable[0], 1, 3, hnm::speciesName, hnm::pTCutsName}, "Track pT selections"}; + Configurable cfgTrkEta{"cfgTrkEta", 0.9, "Eta"}; + Configurable> cfgTPCNClustersMin{"cfgTPCNClustersMin", {hnm::nClusterMinTPC[0], 1, 1, std::vector{"TPCNClusMin"}, hnm::speciesName}, "Mininum of TPC Clusters"}; + Configurable cfgTrkTPCfCls{"cfgTrkTPCfCls", 0.83, "Minimum fraction of crossed rows over findable clusters"}; + Configurable cfgTrkTPCcRowsMin{"cfgTrkTPCcRowsMin", 70, "Minimum number of crossed TPC rows"}; + Configurable cfgTrkTPCsClsSharedFrac{"cfgTrkTPCsClsSharedFrac", 1.f, "Fraction of shared TPC clusters"}; + Configurable> cfgTrkITSnclsMin{"cfgTrkITSnclsMin", {hnm::nClusterMinITS[0], 1, 1, std::vector{"Cut"}, hnm::speciesName}, "Minimum number of ITS clusters"}; + Configurable cfgTrkDCAxyMax{"cfgTrkDCAxyMax", 0.15, "Maximum DCA_xy"}; + Configurable cfgTrkDCAzMax{"cfgTrkDCAzMax", 0.3, "Maximum DCA_z"}; + Configurable cfgTrkMaxChi2PerClusterTPC{"cfgTrkMaxChi2PerClusterTPC", 4.0f, "Minimal track selection: max allowed chi2 per TPC cluster"}; // 4.0 is default of global tracks on 20.01.2023 + Configurable cfgTrkMaxChi2PerClusterITS{"cfgTrkMaxChi2PerClusterITS", 36.0f, "Minimal track selection: max allowed chi2 per ITS cluster"}; // 36.0 is default of global tracks on 20.01.2023 + + Configurable> cfgPIDCuts{"cfgPIDCuts", {hnm::pidcutsTable[0], 1, hnm::kNPIDLimits, hnm::speciesName, hnm::pidCutsName}, "Femtopartner PID nsigma selections"}; // PID selections + + // ---> Configurables to allow for a shift in eta/phi of EMCal clusters to better align with extrapolated TPC tracks + Configurable cfgDoEMCShift{"cfgDoEMCShift", false, "Apply SM-wise shift in eta and phi to EMCal clusters to align with TPC tracks"}; + Configurable> cfgEMCEtaShift{"cfgEMCEtaShift", {0.f}, "values for SM-wise shift in eta to be added to EMCal clusters to align with TPC tracks"}; + Configurable> cfgEMCPhiShift{"cfgEMCPhiShift", {0.f}, "values for SM-wise shift in phi to be added to EMCal clusters to align with TPC tracks"}; + static const int nSMs = 20; + std::array emcEtaShift = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + std::array emcPhiShift = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + // ---> Shift the omega/eta' mass based on the difference of the reconstructed mass of the pi0/eta to its PDG mass to reduce smearing caused by EMCal/PCM in photon measurement + Configurable cfgHNMMassCorrection{"cfgHNMMassCorrection", 1, "Use GG PDG mass to correct HNM mass (0 = off, 1 = subDeltaPi0, 2 = subLambda)"}; + + // ---> Mass windows for the selection of heavy neutral mesons (also based on mass of their light neutral meson decay daughter) + static constexpr float DefaultMassWindows[2][4] = {{0., 0.4, 0.6, 1.}, {0.4, 0.8, 0.8, 1.2}}; + Configurable> cfgMassWindowOmega{"cfgMassWindowOmega", {DefaultMassWindows[0], 4, {"pi0_min", "pi0_max", "omega_min", "omega_max"}}, "Mass window for selected omegas and their decay pi0"}; + Configurable> cfgMassWindowEtaPrime{"cfgMassWindowEtaPrime", {DefaultMassWindows[1], 4, {"eta_min", "eta_max", "etaprime_min", "etaprime_max"}}, "Mass window for selected eta' and their decay eta"}; + + Configurable cfgMinGGPtOverHNMPt{"cfgMinGGPtOverHNMPt", 0., "Minimum ratio of the pT of the gamma gamma pair over the pT of the HNM (can be used to increase the S/B)"}; + + HistogramRegistry mHistManager{"HeavyNeutralMesonHistograms", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Prepare vectors for different species + std::vector vGGs; + std::vector vHNMs; + std::vector etaPrimeEMC, etaPrimePCM, omegaEMC, omegaPCM, proton, antiproton, deuteron, antideuteron, pion, antipion; + float mMassProton = constants::physics::MassProton; + float mMassDeuteron = constants::physics::MassDeuteron; + float mMassOmega = 0.782; + float mMassEtaPrime = 0.957; + float mMassPionCharged = constants::physics::MassPionCharged; + + Preslice perCollisionPCM = aod::v0photonkf::collisionId; + Preslice perCollisionEMC = aod::skimmedcluster::collisionId; + + template + bool isSelectedTrack(T const& track, hnm::TracksPID partSpecies) + { + if (track.pt() < cfgPtCuts->get(partSpecies, "Pt min")) + return false; + if (track.pt() > cfgPtCuts->get(partSpecies, "Pt max")) + return false; + if (std::abs(track.eta()) > cfgTrkEta) + return false; + if (track.tpcNClsFound() < cfgTPCNClustersMin->get("TPCNClusMin", partSpecies)) + return false; + if (track.tpcCrossedRowsOverFindableCls() < cfgTrkTPCfCls) + return false; + if (track.tpcNClsCrossedRows() < cfgTrkTPCcRowsMin) + return false; + if (track.tpcFractionSharedCls() > cfgTrkTPCsClsSharedFrac) + return false; + if (track.itsNCls() < cfgTrkITSnclsMin->get(static_cast(0), partSpecies)) + return false; + if (std::abs(track.dcaXY()) > cfgTrkDCAxyMax) + return false; + if (std::abs(track.dcaZ()) > cfgTrkDCAzMax) + return false; + if (track.tpcChi2NCl() > cfgTrkMaxChi2PerClusterTPC) + return false; + if (track.itsChi2NCl() > cfgTrkMaxChi2PerClusterITS) + return false; + return true; + } + + template + bool isSelectedTrackPID(T const& track, hnm::TracksPID partSpecies) + { + bool isSelected = false; + + float nSigmaTrackTPC = track.tpcNSigmaPi(); + float nSigmaTrackTOF = track.tofNSigmaPi(); + float nSigmaTrackITS = track.itsNSigmaPi(); + + float nSigmaTrackTPCTOF = std::sqrt(std::pow(nSigmaTrackTPC, 2) + std::pow(nSigmaTrackTOF, 2)); + + if (track.p() <= cfgPtCuts->get(partSpecies, "P TOF thres")) { + if (nSigmaTrackTPC > cfgPIDCuts->get(partSpecies, hnm::kTPCMin) && + nSigmaTrackTPC < cfgPIDCuts->get(partSpecies, hnm::kTPCMax) && + nSigmaTrackITS > cfgPIDCuts->get(partSpecies, hnm::kITSmin) && + nSigmaTrackITS < cfgPIDCuts->get(partSpecies, hnm::kITSmax)) { + isSelected = true; + } + } else { + if (nSigmaTrackTPCTOF < cfgPIDCuts->get(partSpecies, hnm::kTPCTOF)) { + isSelected = true; + } + } + return isSelected; + } + + template + bool isSelectedEvent(T const& col) + { + if (confEvtSelectZvtx && std::abs(col.posZ()) > confEvtZvtx) { + return false; + } + if (confEvtRequireSel8 && !col.sel8()) { + return false; + } + return true; + } + + void init(InitContext const&) + { + mHistManager.add("Event/nGGs", "Number of (selected) #gamma#gamma paris;#bf{#it{N}_{#gamma#gamma}};#bf{#it{N}_{#gamma#gamma}^{selected}}", HistType::kTH2F, {{51, -0.5, 50.5}, {51, -0.5, 50.5}}); + mHistManager.add("Event/nHeavyNeutralMesons", "Number of (selected) HNM candidates;#bf{#it{N}_{HNM}};#bf{#it{N}_{HNM}^{selected}}", HistType::kTH2F, {{51, -0.5, 50.5}, {51, -0.5, 50.5}}); + mHistManager.add("Event/nClustersVsV0s", "Number of clusters and V0s in the collision;#bf{#it{N}_{clusters}};#bf{#it{N}_{V0s}}", HistType::kTH2F, {{26, -0.5, 25.5}, {26, -0.5, 25.5}}); + mHistManager.add("Event/nEMCalEvents", "Number of collisions with a certain combination of EMCal triggers;;#bf{#it{N}_{collisions}}", HistType::kTH1F, {{5, -0.5, 4.5}}); + std::vector nEventTitles = {"Cells & kTVXinEMC", "Cells & L0", "Cells & !kTVXinEMC & !L0", "!Cells & kTVXinEMC", "!Cells & L0"}; + for (size_t iBin = 0; iBin < nEventTitles.size(); iBin++) + mHistManager.get(HIST("Event/nEMCalEvents"))->GetXaxis()->SetBinLabel(iBin + 1, nEventTitles[iBin].data()); + mHistManager.add("Event/fMultiplicityBefore", "Multiplicity of all processed events;#bf{#it{N}_{tracks}};#bf{#it{N}_{collisions}}", HistType::kTH1F, {{500, 0, 500}}); + mHistManager.add("Event/fMultiplicityAfter", "Multiplicity after event cuts;#bf{#it{N}_{tracks}};#bf{#it{N}_{collisions}}", HistType::kTH1F, {{500, 0, 500}}); + mHistManager.add("Event/fZvtxBefore", "Zvtx of all processed events;#bf{z_{vtx} (cm)};#bf{#it{N}_{collisions}}", HistType::kTH1F, {{500, -15, 15}}); + mHistManager.add("Event/fZvtxAfter", "Zvtx after event cuts;#bf{z_{vtx} (cm)};#bf{#it{N}_{collisions}}", HistType::kTH1F, {{500, -15, 15}}); + + mHistManager.add("GG/invMassVsPt_PCM", "Invariant mass and pT of gg candidates;#bf{#it{M}_{#gamma#gamma}};#bf{#it{pT}_{#gamma#gamma}}", HistType::kTH2F, {{400, 0., 0.8}, {250, 0., 25.}}); + mHistManager.add("GG/invMassVsPt_PCMEMC", "Invariant mass and pT of gg candidates;#bf{#it{M}_{#gamma#gamma}};#bf{#it{pT}_{#gamma#gamma}}", HistType::kTH2F, {{400, 0., 0.8}, {250, 0., 25.}}); + mHistManager.add("GG/invMassVsPt_EMC", "Invariant mass and pT of gg candidates;#bf{#it{M}_{#gamma#gamma}};#bf{#it{pT}_{#gamma#gamma}}", HistType::kTH2F, {{400, 0., 0.8}, {250, 0., 25.}}); + + // Momentum correlations p vs p_TPC + mHistManager.add("TrackCuts/TracksBefore/fMomCorrelationPos", "fMomCorrelation;#bf{#it{p} (GeV/#it{c})};#bf{#it{p}_{TPC} (GeV/#it{c})}", {HistType::kTH2F, {{500, 0.0f, 20.0f}, {500, 0.0f, 20.0f}}}); + mHistManager.add("TrackCuts/TracksBefore/fMomCorrelationNeg", "fMomCorrelation;#bf{#it{p} (GeV/#it{c})};#bf{#it{p}_{TPC} (GeV/#it{c})}", {HistType::kTH2F, {{500, 0.0f, 20.0f}, {500, 0.0f, 20.0f}}}); + + // All tracks + mHistManager.add("TrackCuts/TracksBefore/fPtTrackBefore", "Transverse momentum of all processed tracks;#bf{#it{p}_{T} (GeV/#it{c})};#bf{#it{N}_{tracks}}", HistType::kTH1F, {{500, 0, 10}}); + mHistManager.add("TrackCuts/TracksBefore/fEtaTrackBefore", "Pseudorapidity of all processed tracks;#eta;#bf{#it{N}_{tracks}}", HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add("TrackCuts/TracksBefore/fPhiTrackBefore", "Azimuthal angle of all processed tracks;#phi;#bf{#it{N}_{tracks}}", HistType::kTH1F, {{720, 0, constants::math::TwoPI}}); + + // TPC signal + mHistManager.add("TrackCuts/TPCSignal/fTPCSignalTPCP", "TPCSignal;#bf{#it{p}_{TPC} (GeV/#it{c})};dE/dx", {HistType::kTH2F, {{500, 0.0f, 6.0f}, {2000, -100.f, 500.f}}}); + mHistManager.add("TrackCuts/TPCSignal/fTPCSignal", "TPCSignalP;#bf{#it{p} (GeV/#it{c})};dE/dx", {HistType::kTH2F, {{500, 0.0f, 6.0f}, {2000, -100.f, 500.f}}}); + // TPC signal antiparticles (negative charge) + mHistManager.add("TrackCuts/TPCSignal/fTPCSignalAntiTPCP", "TPCSignal;#bf{#it{p}_{TPC} (GeV/#it{c})};dE/dx", {HistType::kTH2F, {{500, 0.0f, 6.0f}, {2000, -100.f, 500.f}}}); + mHistManager.add("TrackCuts/TPCSignal/fTPCSignalAnti", "TPCSignalP;#bf{#it{p} (GeV/#it{c})};dE/dx", {HistType::kTH2F, {{500, 0.0f, 6.0f}, {2000, -100.f, 500.f}}}); + + const int nTrackSpecies = 2; // x2 because of anti particles + const char* particleSpecies[nTrackSpecies] = {"Pion", "AntiPion"}; + const char* particleSpeciesLatex[nTrackSpecies] = {"#pi^{+}", "#pi^{-}"}; + + for (int iParticle = 0; iParticle < nTrackSpecies; iParticle++) { + mHistManager.add(Form("TrackCuts/TracksBefore/fMomCorrelationAfterCuts%s", particleSpecies[iParticle]), "fMomCorrelation;#bf{#it{p} (GeV/#it{c})};#bf{#it{p}_{TPC} (GeV/#it{c})}", {HistType::kTH2F, {{500, 0.0f, 20.0f}, {500, 0.0f, 20.0f}}}); + mHistManager.add(Form("TrackCuts/TPCSignal/fTPCSignal%s", particleSpecies[iParticle]), Form("%s TPC energy loss;#bf{#it{p}_{TPC}^{%s} (GeV/#it{c})};dE/dx", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{500, 0.0f, 6.0f}, {10000, -100.f, 500.f}}}); + + mHistManager.add(Form("TrackCuts/%s/fP", particleSpecies[iParticle]), Form("%s momentum at PV;#bf{#it{p}^{%s} (GeV/#it{c})};#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{500, 0, 10}}); + mHistManager.add(Form("TrackCuts/%s/fPt", particleSpecies[iParticle]), Form("%s transverse momentum;#bf{#it{p}_{T}^{%s} (GeV/#it{c})};#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{500, 0, 10}}); + mHistManager.add(Form("TrackCuts/%s/fMomCorDif", particleSpecies[iParticle]), Form("Momentum correlation;#bf{#it{p}^{%s} (GeV/#it{c})};#bf{#it{p}_{TPC}^{%s} - #it{p}^{%s} (GeV/#it{c})}", particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{500, 0, 10}, {600, -3, 3}}}); + mHistManager.add(Form("TrackCuts/%s/fMomCorRatio", particleSpecies[iParticle]), Form("Relative momentum correlation;#bf{#it{p}^{%s} (GeV/#it{c})};#bf{#it{p}_{TPC}^{%s} - #it{p}^{%s} / #it{p}^{%s}}", particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{500, 0, 10}, {200, -1, 1}}}); + mHistManager.add(Form("TrackCuts/%s/fEta", particleSpecies[iParticle]), Form("%s pseudorapidity distribution;#eta;#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add(Form("TrackCuts/%s/fPhi", particleSpecies[iParticle]), Form("%s azimuthal angle distribution;#phi;#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{720, 0, constants::math::TwoPI}}); + + mHistManager.add(Form("TrackCuts/%s/fNsigmaTPCvsTPCP", particleSpecies[iParticle]), Form("NSigmaTPC %s;#bf{#it{p}_{TPC}^{%s} (GeV/#it{c})};n#sigma_{TPC}^{%s}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + mHistManager.add(Form("TrackCuts/%s/fNsigmaTOFvsTPCP", particleSpecies[iParticle]), Form("NSigmaTOF %s;#bf{#it{p}_{TPC}^{%s} (GeV/#it{c})};n#sigma_{TOF}^{%s}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + mHistManager.add(Form("TrackCuts/%s/fNsigmaTPCTOFvsTPCP", particleSpecies[iParticle]), Form("NSigmaTPCTOF %s;#bf{#it{p}_{TPC}^{%s} (GeV/#it{c})};n#sigma_{comb}^{%s}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); + mHistManager.add(Form("TrackCuts/%s/fNsigmaITSvsP", particleSpecies[iParticle]), Form("NSigmaITS %s;#bf{#it{p}^{%s} (GeV/#it{c})};n#sigma_{ITS}^{%s}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + mHistManager.add(Form("TrackCuts/%s/fNsigmaTPCvsP", particleSpecies[iParticle]), Form("NSigmaTPC %s P;#bf{#it{p}^{%s} (GeV/#it{c})};n#sigma_{TPC}^{%s}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + mHistManager.add(Form("TrackCuts/%s/fNsigmaTOFvsP", particleSpecies[iParticle]), Form("NSigmaTOF %s P;#bf{#it{p}^{%s} (GeV/#it{c})};n#sigma_{TOF}^{%s}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); + mHistManager.add(Form("TrackCuts/%s/fNsigmaTPCTOFvsP", particleSpecies[iParticle]), Form("NSigmaTPCTOF %s P;#bf{#it{p}^{%s} (GeV/#it{c})};n#sigma_{comb}^{%s}", particleSpecies[iParticle], particleSpeciesLatex[iParticle], particleSpeciesLatex[iParticle]), {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, 0.f, 10.f}}}); + + mHistManager.add(Form("TrackCuts/%s/fDCAxy", particleSpecies[iParticle]), Form("fDCAxy %s;#bf{DCA_{xy}};#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{500, -0.5f, 0.5f}}); + mHistManager.add(Form("TrackCuts/%s/fDCAz", particleSpecies[iParticle]), Form("fDCAz %s;#bf{DCA_{z}};#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{500, -0.5f, 0.5f}}); + mHistManager.add(Form("TrackCuts/%s/fTPCsCls", particleSpecies[iParticle]), Form("fTPCsCls %s;#bf{TPC Shared Clusters};#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{163, -1.0f, 162.0f}}); + mHistManager.add(Form("TrackCuts/%s/fTPCcRows", particleSpecies[iParticle]), Form("fTPCcRows %s;#bf{TPC Crossed Rows};#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{163, -1.0f, 162.0f}}); + mHistManager.add(Form("TrackCuts/%s/fTrkTPCfCls", particleSpecies[iParticle]), Form("fTrkTPCfCls %s;#bf{TPC Findable/CrossedRows};#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{500, 0.0f, 3.0f}}); + mHistManager.add(Form("TrackCuts/%s/fTPCncls", particleSpecies[iParticle]), Form("fTPCncls %s;#bf{TPC Clusters};#bf{#it{N}^{%s}}", particleSpecies[iParticle], particleSpeciesLatex[iParticle]), HistType::kTH1F, {{163, -1.0f, 162.0f}}); + } + + // --> HNM QA + // pi+ daughter + mHistManager.add("HNM/Before/PosDaughter/fInvMass", "Invariant mass HMN Pos Daugh;#bf{#it{M}^{#pi^{+}} (GeV/#it{c}^{2})};#bf{#it{N}^{#pi^{+}}}", HistType::kTH1F, {{200, 0, 0.2}}); + mHistManager.add("HNM/Before/PosDaughter/fPt", "Transverse momentum HMN Pos Daugh tracks;#bf{#it{p}_{T} (GeV/#it{c})};#bf{#it{N}^{#pi^{+}}}", HistType::kTH1F, {{500, 0, 10}}); + mHistManager.add("HNM/Before/PosDaughter/fEta", "HMN Pos Daugh Eta;#eta;#bf{#it{N}^{#pi^{+}}}", HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add("HNM/Before/PosDaughter/fPhi", "Azimuthal angle of HMN Pos Daugh tracks;#phi;#bf{#it{N}^{#pi^{+}}}", HistType::kTH1F, {{720, 0, constants::math::TwoPI}}); + // pi- daughter + mHistManager.add("HNM/Before/NegDaughter/fInvMass", "Invariant mass HMN Neg Daugh;#bf{#it{M}^{#pi^{-}} (GeV/#it{c}^{2})};#bf{#it{N}^{#pi^{-}}}", HistType::kTH1F, {{200, 0, 0.2}}); + mHistManager.add("HNM/Before/NegDaughter/fPt", "Transverse momentum HMN Neg Daugh tracks;#bf{#it{p}_{T} (GeV/#it{c})};#bf{#it{N}^{#pi^{-}}}", HistType::kTH1F, {{500, 0, 10}}); + mHistManager.add("HNM/Before/NegDaughter/fEta", "HMN Neg Daugh Eta;#eta;#bf{#it{N}^{#pi^{-}}}", HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add("HNM/Before/NegDaughter/fPhi", "Azimuthal angle of HMN Neg Daugh tracks;#phi;#bf{#it{N}^{#pi^{-}}}", HistType::kTH1F, {{720, 0, constants::math::TwoPI}}); + // Properties of the pi+pi- pair + mHistManager.add("HNM/Before/PiPlPiMi/fInvMassVsPt", "Invariant mass and pT of #pi^+pi^- pairs;#bf{#it{M}^{#pi^{+}#pi^{-}} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#pi^{+}#pi^{-}} (GeV/#it{c})}", HistType::kTH2F, {{400, 0.2, 1.}, {250, 0., 25.}}); + mHistManager.add("HNM/Before/PiPlPiMi/fEta", "Pseudorapidity of HMNCand;#eta;#bf{#it{N}^{#pi^{+}#pi^{-}}}", HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add("HNM/Before/PiPlPiMi/fPhi", "Azimuthal angle of HMNCand;#phi;#bf{#it{N}^{#pi^{+}#pi^{-}}}", HistType::kTH1F, {{720, 0, constants::math::TwoPI}}); + + for (const auto& BeforeAfterString : {"Before", "After"}) { + for (const auto& iHNM : {"Omega", "EtaPrime"}) { + for (const auto& MethodString : {"PCM", "EMC"}) { + mHistManager.add(Form("HNM/%s/%s/%s/fInvMassVsPt", BeforeAfterString, iHNM, MethodString), "Invariant mass and pT of heavy neutral meson candidates;#bf{#it{M}^{#pi^{+}#pi^{-}#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#pi^{+}#pi^{-}#gamma#gamma} (GeV/#it{c})}", HistType::kTH2F, {{600, 0.6, 1.2}, {250, 0., 25.}}); + mHistManager.add(Form("HNM/%s/%s/%s/fEta", BeforeAfterString, iHNM, MethodString), "Pseudorapidity of HNM candidate;#eta;#bf{#it{N}^{#pi^{+}#pi^{-}#gamma#gamma}}", HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add(Form("HNM/%s/%s/%s/fPhi", BeforeAfterString, iHNM, MethodString), "Azimuthal angle of HNM candidate;#phi;#bf{#it{N}^{#pi^{+}#pi^{-}#gamma#gamma}}", HistType::kTH1F, {{720, 0, constants::math::TwoPI}}); + } + } + } + mHistManager.add("HNM/Before/Omega/PCMEMC/fInvMassVsPt", "Invariant mass and pT of omega meson candidates;#bf{#it{M}^{#pi^{+}#pi^{-}#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#pi^{+}#pi^{-}#gamma#gamma} (GeV/#it{c})}", HistType::kTH2F, {{600, 0.6, 1.2}, {250, 0., 25.}}); + mHistManager.add("HNM/Before/Omega/PCMEMC/fEta", "Pseudorapidity of HMNCand;#eta;#bf{#it{N}^{#pi^{+}#pi^{-}#gamma#gamma}}", HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add("HNM/Before/Omega/PCMEMC/fPhi", "Azimuthal angle of HMNCand;#phi;#bf{#it{N}^{#pi^{+}#pi^{-}#gamma#gamma}}", HistType::kTH1F, {{720, 0, constants::math::TwoPI}}); + mHistManager.add("HNM/Before/EtaPrime/PCMEMC/fInvMassVsPt", "Invariant mass and pT of eta' meson candidates;#bf{#it{M}^{#pi^{+}#pi^{-}#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#pi^{+}#pi^{-}#gamma#gamma} (GeV/#it{c})}", HistType::kTH2F, {{600, 0.8, 1.2}, {250, 0., 25.}}); + mHistManager.add("HNM/Before/EtaPrime/PCMEMC/fEta", "Pseudorapidity of HMNCand;#eta;#bf{#it{N}^{#pi^{+}#pi^{-}#gamma#gamma}}", HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add("HNM/Before/EtaPrime/PCMEMC/fPhi", "Azimuthal angle of HMNCand;#phi;#bf{#it{N}^{#pi^{+}#pi^{-}#gamma#gamma}}", HistType::kTH1F, {{720, 0, constants::math::TwoPI}}); + + if (cfgDoEMCShift.value) { + for (int iSM = 0; iSM < nSMs; iSM++) { + emcEtaShift[iSM] = cfgEMCEtaShift.value[iSM]; + emcPhiShift[iSM] = cfgEMCPhiShift.value[iSM]; + LOG(info) << "SM-wise shift in eta/phi for SM " << iSM << ": " << emcEtaShift[iSM] << " / " << emcPhiShift[iSM]; + } + } + } + + void process(aod::MyCollision const& collision, aod::MyBCs const&, aod::SkimEMCClusters const& clusters, aod::V0PhotonsKF const& v0s, aod::SelectedTracks const& tracks) + { + // inlcude ITS PID information + auto tracksWithItsPid = soa::Attach(tracks); + + // QA all evts + mHistManager.fill(HIST("Event/fMultiplicityBefore"), collision.multNTracksPV()); + mHistManager.fill(HIST("Event/fZvtxBefore"), collision.posZ()); + + // Ensure evts are consistent with Sel8 and Vtx-z selection + if (!isSelectedEvent(collision)) + return; + + // QA accepted evts + mHistManager.fill(HIST("Event/fMultiplicityAfter"), collision.multNTracksPV()); + mHistManager.fill(HIST("Event/fZvtxAfter"), collision.posZ()); + + // clean vecs + pion.clear(); + antipion.clear(); + vHNMs.clear(); + // vGGs vector is cleared in reconstructGGs. + + // ---------------------------------> EMCal event QA <---------------------------------- + // - Fill Event/nEMCalEvents histogram for EMCal event QA + // ------------------------------------------------------------------------------------- + bool bcHasEMCCells = collision.isemcreadout(); + bool iskTVXinEMC = collision.foundBC_as().alias_bit(kTVXinEMC); + bool isL0Triggered = collision.foundBC_as().alias_bit(kEMC7) || collision.foundBC_as().alias_bit(kEG1) || collision.foundBC_as().alias_bit(kEG2); + + if (bcHasEMCCells && iskTVXinEMC) + mHistManager.fill(HIST("Event/nEMCalEvents"), 0); + if (bcHasEMCCells && isL0Triggered) + mHistManager.fill(HIST("Event/nEMCalEvents"), 1); + if (bcHasEMCCells && !iskTVXinEMC && !isL0Triggered) + mHistManager.fill(HIST("Event/nEMCalEvents"), 2); + if (!bcHasEMCCells && iskTVXinEMC) + mHistManager.fill(HIST("Event/nEMCalEvents"), 3); + if (!bcHasEMCCells && isL0Triggered) + mHistManager.fill(HIST("Event/nEMCalEvents"), 4); + + // --------------------------------> Process Photons <---------------------------------- + // - Slice clusters and V0s by collision ID to get the ones in this collision + // - Store the clusters and V0s in the vGammas vector + // - Reconstruct gamma-gamma pairs + // ------------------------------------------------------------------------------------- + auto v0sInThisCollision = v0s.sliceBy(perCollisionPCM, collision.globalIndex()); + auto clustersInThisCollision = clusters.sliceBy(perCollisionEMC, collision.globalIndex()); + mHistManager.fill(HIST("Event/nClustersVsV0s"), clustersInThisCollision.size(), v0sInThisCollision.size()); + + std::vector vGammas; + hnmutilities::storeGammasInVector(clustersInThisCollision, v0sInThisCollision, vGammas, emcEtaShift, emcPhiShift); + hnmutilities::reconstructGGs(vGammas, vGGs); + vGammas.clear(); + processGGs(vGGs); + + // ------------------------------> Loop over all tracks <------------------------------- + // - Sort them into vectors based on PID ((anti)protons, (anti)deuterons, (anti)pions) + // - Fill QA histograms for all tracks and per particle species + // ------------------------------------------------------------------------------------- + for (const auto& track : tracksWithItsPid) { + mHistManager.fill(HIST("TrackCuts/TracksBefore/fPtTrackBefore"), track.pt()); + mHistManager.fill(HIST("TrackCuts/TracksBefore/fEtaTrackBefore"), track.eta()); + mHistManager.fill(HIST("TrackCuts/TracksBefore/fPhiTrackBefore"), track.phi()); + if (track.sign() > 0) { // All particles (positive electric charge) + mHistManager.fill(HIST("TrackCuts/TPCSignal/fTPCSignalTPCP"), track.tpcInnerParam(), track.tpcSignal()); + mHistManager.fill(HIST("TrackCuts/TPCSignal/fTPCSignal"), track.p(), track.tpcSignal()); + mHistManager.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationPos"), track.p(), track.tpcInnerParam()); + } + if (track.sign() < 0) { // All anti-particles (negative electric charge) + mHistManager.fill(HIST("TrackCuts/TPCSignal/fTPCSignalAntiTPCP"), track.tpcInnerParam(), track.tpcSignal()); + mHistManager.fill(HIST("TrackCuts/TPCSignal/fTPCSignalAnti"), track.p(), track.tpcSignal()); + mHistManager.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationNeg"), track.p(), track.tpcInnerParam()); + } + + // For each track, check if it fulfills track and PID criteria to be identified as a proton, deuteron or pion + bool isPion = (isSelectedTrackPID(track, hnm::kPion) && isSelectedTrack(track, hnm::kPion)); + + if (track.sign() > 0) { // Positive charge -> Particles + if (isPion) { + pion.emplace_back(track.pt(), track.eta(), track.phi(), mMassPionCharged); + mHistManager.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationAfterCutsPion"), track.p(), track.tpcInnerParam()); + mHistManager.fill(HIST("TrackCuts/TPCSignal/fTPCSignalPion"), track.tpcInnerParam(), track.tpcSignal()); + + mHistManager.fill(HIST("TrackCuts/Pion/fP"), track.p()); + mHistManager.fill(HIST("TrackCuts/Pion/fPt"), track.pt()); + mHistManager.fill(HIST("TrackCuts/Pion/fMomCorDif"), track.p(), track.tpcInnerParam() - track.p()); + mHistManager.fill(HIST("TrackCuts/Pion/fMomCorRatio"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + mHistManager.fill(HIST("TrackCuts/Pion/fEta"), track.eta()); + mHistManager.fill(HIST("TrackCuts/Pion/fPhi"), track.phi()); + + mHistManager.fill(HIST("TrackCuts/Pion/fNsigmaTPCvsTPCP"), track.tpcInnerParam(), track.tpcNSigmaPi()); + mHistManager.fill(HIST("TrackCuts/Pion/fNsigmaTOFvsTPCP"), track.tpcInnerParam(), track.tofNSigmaPi()); + auto nSigmaTrackTPCTOF = std::sqrt(std::pow(track.tpcNSigmaPi(), 2) + std::pow(track.tofNSigmaPi(), 2)); + mHistManager.fill(HIST("TrackCuts/Pion/fNsigmaTPCTOFvsTPCP"), track.tpcInnerParam(), std::sqrt(std::pow(track.tpcNSigmaPi() - nSigmaTrackTPCTOF, 2) + std::pow(track.tofNSigmaPi() - nSigmaTrackTPCTOF, 2))); + mHistManager.fill(HIST("TrackCuts/Pion/fNsigmaITSvsP"), track.p(), track.itsNSigmaPi()); + mHistManager.fill(HIST("TrackCuts/Pion/fNsigmaTPCvsP"), track.p(), track.tpcNSigmaPi()); + mHistManager.fill(HIST("TrackCuts/Pion/fNsigmaTOFvsP"), track.p(), track.tofNSigmaPi()); + mHistManager.fill(HIST("TrackCuts/Pion/fNsigmaTPCTOFvsP"), track.p(), std::sqrt(std::pow(track.tpcNSigmaPi() - nSigmaTrackTPCTOF, 2) + std::pow(track.tofNSigmaPi() - nSigmaTrackTPCTOF, 2))); + + mHistManager.fill(HIST("TrackCuts/Pion/fDCAxy"), track.dcaXY()); + mHistManager.fill(HIST("TrackCuts/Pion/fDCAz"), track.dcaZ()); + mHistManager.fill(HIST("TrackCuts/Pion/fTPCsCls"), track.tpcNClsShared()); + mHistManager.fill(HIST("TrackCuts/Pion/fTPCcRows"), track.tpcNClsCrossedRows()); + mHistManager.fill(HIST("TrackCuts/Pion/fTrkTPCfCls"), track.tpcCrossedRowsOverFindableCls()); + mHistManager.fill(HIST("TrackCuts/Pion/fTPCncls"), track.tpcNClsFound()); + } + } else { // Negative charge -> Anti-particles + if (isPion) { + antipion.emplace_back(track.pt(), track.eta(), track.phi(), mMassPionCharged); + mHistManager.fill(HIST("TrackCuts/TracksBefore/fMomCorrelationAfterCutsAntiPion"), track.p(), track.tpcInnerParam()); + mHistManager.fill(HIST("TrackCuts/TPCSignal/fTPCSignalAntiPion"), track.tpcInnerParam(), track.tpcSignal()); + + mHistManager.fill(HIST("TrackCuts/AntiPion/fP"), track.p()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fPt"), track.pt()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fMomCorDif"), track.p(), track.tpcInnerParam() - track.p()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fMomCorRatio"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fEta"), track.eta()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fPhi"), track.phi()); + + mHistManager.fill(HIST("TrackCuts/AntiPion/fNsigmaTPCvsTPCP"), track.tpcInnerParam(), track.tpcNSigmaPi()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fNsigmaTOFvsTPCP"), track.tpcInnerParam(), track.tofNSigmaPi()); + auto nSigmaTrackTPCTOF = std::sqrt(std::pow(track.tpcNSigmaPi(), 2) + std::pow(track.tofNSigmaPi(), 2)); + mHistManager.fill(HIST("TrackCuts/AntiPion/fNsigmaTPCTOFvsTPCP"), track.tpcInnerParam(), std::sqrt(std::pow(track.tpcNSigmaPi() - nSigmaTrackTPCTOF, 2) + std::pow(track.tofNSigmaPi() - nSigmaTrackTPCTOF, 2))); + mHistManager.fill(HIST("TrackCuts/AntiPion/fNsigmaITSvsP"), track.p(), track.itsNSigmaPi()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fNsigmaTPCvsP"), track.p(), track.tpcNSigmaPi()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fNsigmaTOFvsP"), track.p(), track.tofNSigmaPi()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fNsigmaTPCTOFvsP"), track.p(), std::sqrt(std::pow(track.tpcNSigmaPi() - nSigmaTrackTPCTOF, 2) + std::pow(track.tofNSigmaPi() - nSigmaTrackTPCTOF, 2))); + + mHistManager.fill(HIST("TrackCuts/AntiPion/fDCAxy"), track.dcaXY()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fDCAz"), track.dcaZ()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fTPCsCls"), track.tpcNClsShared()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fTPCcRows"), track.tpcNClsCrossedRows()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fTrkTPCfCls"), track.tpcCrossedRowsOverFindableCls()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fTPCncls"), track.tpcNClsFound()); + } + } + } + + // -------------------------> Reconstruct HNM candidates <------------------------------ + // - Based on the previously filled (anti)pion vectors + // - Fill QA histograms for kinematics of the pions and their combinations + // ------------------------------------------------------------------------------------- + for (const auto& posPion : pion) { + for (const auto& negPion : antipion) { + ROOT::Math::PtEtaPhiMVector vecPiPlPiMi = posPion + negPion; + hnmutilities::reconstructHeavyNeutralMesons(vecPiPlPiMi, vGGs, vHNMs); + + mHistManager.fill(HIST("HNM/Before/PiPlPiMi/fInvMassVsPt"), vecPiPlPiMi.M(), vecPiPlPiMi.pt()); + mHistManager.fill(HIST("HNM/Before/PiPlPiMi/fEta"), vecPiPlPiMi.eta()); + mHistManager.fill(HIST("HNM/Before/PiPlPiMi/fPhi"), RecoDecay::constrainAngle(vecPiPlPiMi.phi())); + + mHistManager.fill(HIST("HNM/Before/PosDaughter/fInvMass"), posPion.M()); + mHistManager.fill(HIST("HNM/Before/PosDaughter/fPt"), posPion.pt()); + mHistManager.fill(HIST("HNM/Before/PosDaughter/fEta"), posPion.eta()); + mHistManager.fill(HIST("HNM/Before/PosDaughter/fPhi"), RecoDecay::constrainAngle(posPion.phi())); + + mHistManager.fill(HIST("HNM/Before/NegDaughter/fInvMass"), negPion.M()); + mHistManager.fill(HIST("HNM/Before/NegDaughter/fPt"), negPion.pt()); + mHistManager.fill(HIST("HNM/Before/NegDaughter/fEta"), negPion.eta()); + mHistManager.fill(HIST("HNM/Before/NegDaughter/fPhi"), RecoDecay::constrainAngle(negPion.phi())); + } + } + + // ---------------------------> Process HNM candidates <-------------------------------- + // - Fill invMassVsPt histograms separated into HNM types (based on GG mass) and gamma reco method + // ------------------------------------------------------------------------------------- + processHNMs(vHNMs); + } + + /// \brief Loop over the GG candidates, fill the mass/pt histograms and set the isPi0/isEta flags based on the reconstructed mass + void processGGs(std::vector& vGGs) + { + int nGGsBeforeMassCuts = vGGs.size(); + for (unsigned int iGG = 0; iGG < vGGs.size(); iGG++) { + auto lightMeson = &vGGs.at(iGG); + + if (lightMeson->reconstructionType == photonpair::kPCMPCM) { + mHistManager.fill(HIST("GG/invMassVsPt_PCM"), lightMeson->m(), lightMeson->pT()); + } else if (lightMeson->reconstructionType == photonpair::kEMCEMC) { + mHistManager.fill(HIST("GG/invMassVsPt_EMC"), lightMeson->m(), lightMeson->pT()); + } else { + mHistManager.fill(HIST("GG/invMassVsPt_PCMEMC"), lightMeson->m(), lightMeson->pT()); + } + + if (lightMeson->m() > cfgMassWindowOmega->get("pi0_min") && lightMeson->m() < cfgMassWindowOmega->get("pi0_max")) { + lightMeson->isPi0 = true; + } else if (lightMeson->m() > cfgMassWindowEtaPrime->get("eta_min") && lightMeson->m() < cfgMassWindowEtaPrime->get("eta_max")) { + lightMeson->isEta = true; + } else { + vGGs.erase(vGGs.begin() + iGG); + iGG--; + } + } + mHistManager.fill(HIST("Event/nGGs"), nGGsBeforeMassCuts, vGGs.size()); + } + + /// \brief Loop over the heavy neutral meson candidates, fill the mass/pt histograms and set the trigger flags based on the reconstructed mass + void processHNMs(std::vector& vHNMs) + { + int nHNMsBeforeMassCuts = vHNMs.size(); + + for (unsigned int iHNM = 0; iHNM < vHNMs.size(); iHNM++) { + auto heavyNeutralMeson = vHNMs.at(iHNM); + float massHNM = heavyNeutralMeson.m(cfgHNMMassCorrection); + + if (heavyNeutralMeson.gg->reconstructionType == photonpair::kPCMPCM) { + if (heavyNeutralMeson.gg->isPi0) { + mHistManager.fill(HIST("HNM/Before/Omega/PCM/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/Before/Omega/PCM/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/Before/Omega/PCM/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } else if (heavyNeutralMeson.gg->isEta) { + mHistManager.fill(HIST("HNM/Before/EtaPrime/PCM/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/Before/EtaPrime/PCM/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/Before/EtaPrime/PCM/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } + } else if (heavyNeutralMeson.gg->reconstructionType == photonpair::kEMCEMC) { + if (heavyNeutralMeson.gg->isPi0) { + mHistManager.fill(HIST("HNM/Before/Omega/EMC/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/Before/Omega/EMC/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/Before/Omega/EMC/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } else if (heavyNeutralMeson.gg->isEta) { + mHistManager.fill(HIST("HNM/Before/EtaPrime/EMC/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/Before/EtaPrime/EMC/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/Before/EtaPrime/EMC/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } + } else { + if (heavyNeutralMeson.gg->isPi0) { + mHistManager.fill(HIST("HNM/Before/Omega/PCMEMC/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/Before/Omega/PCMEMC/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/Before/Omega/PCMEMC/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } else if (heavyNeutralMeson.gg->isEta) { + mHistManager.fill(HIST("HNM/Before/EtaPrime/PCMEMC/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/Before/EtaPrime/PCMEMC/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/Before/EtaPrime/PCMEMC/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } + } + + if (heavyNeutralMeson.gg->isPi0 && massHNM > cfgMassWindowOmega->get("omega_min") && massHNM < cfgMassWindowOmega->get("omega_max") && heavyNeutralMeson.gg->pT() / heavyNeutralMeson.pT() > cfgMinGGPtOverHNMPt) { + if (heavyNeutralMeson.gg->reconstructionType == photonpair::kPCMPCM) { + omegaPCM.emplace_back(heavyNeutralMeson.pT(), heavyNeutralMeson.eta(), RecoDecay::constrainAngle(heavyNeutralMeson.phi()), mMassOmega); + mHistManager.fill(HIST("HNM/After/Omega/PCM/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/After/Omega/PCM/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/After/Omega/PCM/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } else if (heavyNeutralMeson.gg->reconstructionType == photonpair::kEMCEMC) { + omegaEMC.emplace_back(heavyNeutralMeson.pT(), heavyNeutralMeson.eta(), RecoDecay::constrainAngle(heavyNeutralMeson.phi()), mMassOmega); + mHistManager.fill(HIST("HNM/After/Omega/EMC/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/After/Omega/EMC/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/After/Omega/EMC/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } + } else if (heavyNeutralMeson.gg->isEta && massHNM > cfgMassWindowEtaPrime->get("etaprime_min") && massHNM < cfgMassWindowEtaPrime->get("etaprime_max") && heavyNeutralMeson.gg->pT() / heavyNeutralMeson.pT() > cfgMinGGPtOverHNMPt) { + if (heavyNeutralMeson.gg->reconstructionType == photonpair::kPCMPCM) { + etaPrimePCM.emplace_back(heavyNeutralMeson.pT(), heavyNeutralMeson.eta(), RecoDecay::constrainAngle(heavyNeutralMeson.phi()), mMassEtaPrime); + mHistManager.fill(HIST("HNM/After/EtaPrime/PCM/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/After/EtaPrime/PCM/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/After/EtaPrime/PCM/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } else if (heavyNeutralMeson.gg->reconstructionType == photonpair::kEMCEMC) { + etaPrimeEMC.emplace_back(heavyNeutralMeson.pT(), heavyNeutralMeson.eta(), RecoDecay::constrainAngle(heavyNeutralMeson.phi()), mMassEtaPrime); + mHistManager.fill(HIST("HNM/After/EtaPrime/EMC/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("HNM/After/EtaPrime/EMC/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("HNM/After/EtaPrime/EMC/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } + } else { + vHNMs.erase(vHNMs.begin() + iHNM); + iHNM--; + } + } + mHistManager.fill(HIST("Event/nHeavyNeutralMesons"), nHNMsBeforeMassCuts, vHNMs.size()); + } +}; + +WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGEM/PhotonMeson/Tasks/MaterialBudget.cxx b/PWGEM/PhotonMeson/Tasks/MaterialBudget.cxx index d7ce6b28678..b5c1a5d8fde 100644 --- a/PWGEM/PhotonMeson/Tasks/MaterialBudget.cxx +++ b/PWGEM/PhotonMeson/Tasks/MaterialBudget.cxx @@ -41,10 +41,10 @@ using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; -using namespace o2::aod::photonpair; +using namespace o2::aod::pwgem::photonmeson::photonpair; using namespace o2::aod::pwgem::photon; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyV0Photons = soa::Join; @@ -62,7 +62,7 @@ struct MaterialBudget { Configurable fDoMixing{"DoMixing", false, "do event mixing"}; Configurable fConfigEMEventCut{"cfgEMEventCut", "minbias", "em event cut"}; // only 1 event cut per wagon - EMEventCut fEMEventCut; + EMPhotonEventCut fEMEventCut; static constexpr std::string_view event_types[2] = {"before", "after"}; OutputObj fOutputEvent{"Event"}; @@ -204,7 +204,7 @@ struct MaterialBudget { template bool IsSelectedPair(TG1 const& g1, TG2 const& g2, TCut1 const& cut1, TCut2 const& cut2) { - return o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); + return o2::aod::pwgem::photonmeson::photonpair::IsSelectedPair(g1, g2, cut1, cut2); } template @@ -321,8 +321,6 @@ struct MaterialBudget { THashList* list_pair_ss = static_cast(fMainList->FindObject("Pair")->FindObject(pairnames[pairtype].data())); for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, ndepth, -1, collisions, collisions)) { // internally, CombinationsStrictlyUpperIndexPolicy(collisions, collisions) is called. - // LOGF(info, "Mixed event globalIndex: (%d, %d) , ngpcm: (%d, %d), ngphos: (%d, %d), ngemc: (%d, %d)", collision1.globalIndex(), collision2.globalIndex(), collision1.ngpcm(), collision2.ngpcm(), collision1.ngphos(), collision2.ngphos(), collision1.ngemc(), collision2.ngemc()); - const float centralities1[3] = {collision1.centFT0M(), collision1.centFT0A(), collision1.centFT0C()}; const float centralities2[3] = {collision2.centFT0M(), collision2.centFT0A(), collision2.centFT0C()}; @@ -380,7 +378,6 @@ struct MaterialBudget { Partition grouped_collisions = cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax; // this goes to same event. Filter collisionFilter_common = nabs(o2::aod::collision::posZ) < 10.f && o2::aod::collision::numContrib > (uint16_t)0 && o2::aod::evsel::sel8 == true; Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); - Filter collisionFilter_subsys = o2::aod::emevent::ngpcm >= 2; using MyFilteredCollisions = soa::Filtered; // this goes to mixed event. void processMB(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, MyV0Photons const& v0photons, aod::V0Legs const& legs) diff --git a/PWGEM/PhotonMeson/Tasks/MaterialBudgetMC.cxx b/PWGEM/PhotonMeson/Tasks/MaterialBudgetMC.cxx index 9eef10ead68..3fe51c1ff7c 100644 --- a/PWGEM/PhotonMeson/Tasks/MaterialBudgetMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/MaterialBudgetMC.cxx @@ -36,17 +36,19 @@ #include "PWGEM/PhotonMeson/Core/PairCut.h" #include "PWGEM/PhotonMeson/Core/CutsLibrary.h" #include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; -using namespace o2::aod::photonpair; -using namespace o2::aod::pwgem::mcutil; +using namespace o2::aod::pwgem::photonmeson::photonpair; +using namespace o2::aod::pwgem::photonmeson::utils::mcutil; +using namespace o2::aod::pwgem::dilepton::utils::mcutil; using namespace o2::aod::pwgem::photon; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyV0Photons = soa::Join; @@ -69,7 +71,7 @@ struct MaterialBudgetMC { Configurable fConfigPairCuts{"cfgPairCuts", "nocut", "Comma separated list of pair cuts"}; Configurable fConfigEMEventCut{"cfgEMEventCut", "minbias", "em event cut"}; // only 1 event cut per wagon - EMEventCut fEMEventCut; + EMPhotonEventCut fEMEventCut; static constexpr std::string_view event_types[2] = {"before", "after"}; OutputObj fOutputEvent{"Event"}; @@ -221,7 +223,7 @@ struct MaterialBudgetMC { template bool IsSelectedPair(TG1 const& g1, TG2 const& g2, TCut1 const& tagcut, TCut2 const& probecut) { - return o2::aod::photonpair::IsSelectedPair(g1, g2, tagcut, probecut); + return o2::aod::pwgem::photonmeson::photonpair::IsSelectedPair(g1, g2, tagcut, probecut); } template @@ -380,7 +382,6 @@ struct MaterialBudgetMC { Partition grouped_collisions = cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax; // this goes to same event. Filter collisionFilter_common = nabs(o2::aod::collision::posZ) < 10.f && o2::aod::collision::numContrib > (uint16_t)0 && o2::aod::evsel::sel8 == true; Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); - Filter collisionFilter_subsys = o2::aod::emevent::ngpcm >= 2; using MyFilteredCollisions = soa::Filtered; // this goes to same event pairing. void processMBMC(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, MyV0Photons const& v0photons, MyMCV0Legs const& legs, aod::EMMCParticles const& mcparticles, aod::EMMCEvents const& mccollisions) diff --git a/PWGEM/PhotonMeson/Tasks/PhotonHBT.cxx b/PWGEM/PhotonMeson/Tasks/PhotonHBT.cxx deleted file mode 100644 index 8713ab7ba48..00000000000 --- a/PWGEM/PhotonMeson/Tasks/PhotonHBT.cxx +++ /dev/null @@ -1,684 +0,0 @@ -// 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. -// -// ======================== -// -// This code loops over v0 photons and makes pairs for photon HBT analysis. -// Please write to: daiki.sekihata@cern.ch - -#include -#include - -#include "TString.h" -#include "Math/Vector4D.h" -#include "Math/Vector3D.h" -#include "Math/LorentzRotation.h" -#include "Math/GenVector/Boost.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" -#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" -#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" -#include "PWGEM/PhotonMeson/Core/PairCut.h" -#include "PWGEM/PhotonMeson/Core/CutsLibrary.h" -#include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" - -using namespace o2; -using namespace o2::aod; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::soa; -using namespace o2::aod::photonpair; -using namespace o2::aod::pwgem::photon; - -using MyCollisions = soa::Join; -using MyCollision = MyCollisions::iterator; - -using MyV0Photons = soa::Join; -using MyV0Photon = MyV0Photons::iterator; - -using MyDalitzEEs = soa::Join; -using MyDalitzEE = MyDalitzEEs::iterator; - -using MyPrimaryElectrons = soa::Join; -using MyPrimaryElectron = MyPrimaryElectrons::iterator; - -struct PhotonHBT { - Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; - Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; - Configurable cfgCentMax{"cfgCentMax", 999, "max. centrality"}; - - Configurable fConfigPCMCuts{"cfgPCMCuts", "qc", "Comma separated list of V0 photon cuts"}; - Configurable fConfigDalitzEECuts{"cfgDalitzEECuts", "mee_all_tpchadrejortofreq_prompt", "Comma separated list of DalitzEE cuts"}; - Configurable fConfigPHOSCuts{"cfgPHOSCuts", "test02,test03", "Comma separated list of PHOS photon cuts"}; - Configurable fConfigPairCuts{"cfgPairCuts", "nocut", "Comma separated list of pair cuts"}; - Configurable fConfigDo3D{"cfgDo3D", false, "Flag to analyze 3D BE correlation"}; // it is very heavy. - Configurable maxY_dielectron{"maxY_dielectron", 0.9, "maximum rapidity for dielectron"}; - - Configurable fConfigEMEventCut{"cfgEMEventCut", "minbias", "em event cut"}; // only 1 event cut per wagon - EMEventCut fEMEventCut; - static constexpr std::string_view event_types[2] = {"before", "after"}; - - OutputObj fOutputEvent{"Event"}; - OutputObj fOutputPair{"Pair"}; // 2-photon pair - THashList* fMainList = new THashList(); - - std::vector fPCMCuts; - std::vector fDalitzEECuts; - std::vector fPHOSCuts; - std::vector fPairCuts; - - std::vector fPairNames; - void init(InitContext& context) - { - if (context.mOptions.get("processPCMPCM")) { - fPairNames.push_back("PCMPCM"); - } - if (context.mOptions.get("processPCMDalitzEE")) { - fPairNames.push_back("PCMDalitzEE"); - } - if (context.mOptions.get("processDalitzEEDalitzEE")) { - fPairNames.push_back("DalitzEEDalitzEE"); - } - if (context.mOptions.get("processPHOSPHOS")) { - fPairNames.push_back("PHOSPHOS"); - } - if (context.mOptions.get("processPCMPHOS")) { - fPairNames.push_back("PCMPHOS"); - } - - DefinePCMCuts(); - DefineDalitzEECuts(); - DefinePHOSCuts(); - DefinePairCuts(); - addhistograms(); - TString ev_cut_name = fConfigEMEventCut.value; - fEMEventCut = *eventcuts::GetCut(ev_cut_name.Data()); - - fOutputEvent.setObject(reinterpret_cast(fMainList->FindObject("Event"))); - fOutputPair.setObject(reinterpret_cast(fMainList->FindObject("Pair"))); - } - - template - void add_pair_histograms(THashList* list_pair, const std::string pairname, TCuts1 const& cuts1, TCuts2 const& cuts2, TCuts3 const& cuts3) - { - for (auto& cut1 : cuts1) { - for (auto& cut2 : cuts2) { - std::string cutname1 = cut1.GetName(); - std::string cutname2 = cut2.GetName(); - - if ((pairname == "PCMPCM" || pairname == "PHOSPHOS" || pairname == "EMCEMC" || pairname == "DalitzEEDalitzEE") && (cutname1 != cutname2)) { - continue; - } - - THashList* list_pair_subsys = reinterpret_cast(list_pair->FindObject(pairname.data())); - std::string photon_cut_name = cutname1 + "_" + cutname2; - o2::aod::pwgem::photon::histogram::AddHistClass(list_pair_subsys, photon_cut_name.data()); - THashList* list_pair_subsys_photoncut = reinterpret_cast(list_pair_subsys->FindObject(photon_cut_name.data())); - - for (auto& cut3 : cuts3) { - std::string pair_cut_name = cut3.GetName(); - o2::aod::pwgem::photon::histogram::AddHistClass(list_pair_subsys_photoncut, pair_cut_name.data()); - THashList* list_pair_subsys_paircut = reinterpret_cast(list_pair_subsys_photoncut->FindObject(pair_cut_name.data())); - if (fConfigDo3D) { - o2::aod::pwgem::photon::histogram::DefineHistograms(list_pair_subsys_paircut, "photon_hbt", "3d"); - } else { - o2::aod::pwgem::photon::histogram::DefineHistograms(list_pair_subsys_paircut, "photon_hbt", "1d"); - } - } // end of pair cut3 loop - } // end of cut2 loop - } // end of cut1 loop - } - - static constexpr std::string_view pairnames[9] = {"PCMPCM", "PHOSPHOS", "EMCEMC", "PCMPHOS", "PCMEMC", "PCMDalitzEE", "PCMDalitzMuMu", "PHOSEMC", "DalitzEEDalitzEE"}; - void addhistograms() - { - fMainList->SetOwner(true); - fMainList->SetName("fMainList"); - - // create sub lists first. - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Event"); - THashList* list_ev = reinterpret_cast(fMainList->FindObject("Event")); - - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Pair"); - THashList* list_pair = reinterpret_cast(fMainList->FindObject("Pair")); - - for (auto& pairname : fPairNames) { - LOGF(info, "Enabled pairs = %s", pairname.data()); - - THashList* list_ev_pair = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_ev, pairname.data())); - for (const auto& evtype : event_types) { - THashList* list_ev_type = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_ev_pair, evtype.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_ev_type, "Event", evtype.data()); - } - - o2::aod::pwgem::photon::histogram::AddHistClass(list_pair, pairname.data()); - - if (pairname == "PCMPCM") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fPCMCuts, fPairCuts); - } - if (pairname == "PCMDalitzEE") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fDalitzEECuts, fPairCuts); - } - if (pairname == "DalitzEEDalitzEE") { - add_pair_histograms(list_pair, pairname, fDalitzEECuts, fDalitzEECuts, fPairCuts); - } - if (pairname == "PHOSPHOS") { - add_pair_histograms(list_pair, pairname, fPHOSCuts, fPHOSCuts, fPairCuts); - } - if (pairname == "PCMPHOS") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fPHOSCuts, fPairCuts); - } - - } // end of pair name loop - } - - void DefinePCMCuts() - { - TString cutNamesStr = fConfigPCMCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fPCMCuts.push_back(*pcmcuts::GetCut(cutname)); - } - } - LOGF(info, "Number of PCM cuts = %d", fPCMCuts.size()); - } - - void DefineDalitzEECuts() - { - TString cutNamesStr = fConfigDalitzEECuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fDalitzEECuts.push_back(*dalitzeecuts::GetCut(cutname)); - } - } - LOGF(info, "Number of DalitzEE cuts = %d", fDalitzEECuts.size()); - } - - void DefinePHOSCuts() - { - TString cutNamesStr = fConfigPHOSCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fPHOSCuts.push_back(*phoscuts::GetCut(cutname)); - } - } - LOGF(info, "Number of PHOS cuts = %d", fPHOSCuts.size()); - } - - void DefinePairCuts() - { - TString cutNamesStr = fConfigPairCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fPairCuts.push_back(*paircuts::GetCut(cutname)); - } - } - LOGF(info, "Number of Pair cuts = %d", fPairCuts.size()); - } - - template - bool IsSelectedPair(TG1 const& g1, TG2 const& g2, TCut1 const& cut1, TCut2 const& cut2) - { - bool is_selected_pair = false; - if constexpr (pairtype == PairType::kPCMPCM) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPCMDalitzEE) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kDalitzEEDalitzEE) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPHOSPHOS) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); // dummy, because track matching is not ready. - } else if constexpr (pairtype == PairType::kPCMPHOS) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else { - is_selected_pair = true; - } - return is_selected_pair; - } - - template - void SameEventPairing(TEvents const& collisions, TPhotons1 const& photons1, TPhotons2 const& photons2, TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, TCuts1 const& cuts1, TCuts2 const& cuts2, TPairCuts const& paircuts, TLegs const& /*legs*/, TEMPrimaryElectrons const& /*emprimaryelectrons*/) - { - THashList* list_ev_pair_before = static_cast(fMainList->FindObject("Event")->FindObject(pairnames[pairtype].data())->FindObject(event_types[0].data())); - THashList* list_ev_pair_after = static_cast(fMainList->FindObject("Event")->FindObject(pairnames[pairtype].data())->FindObject(event_types[1].data())); - THashList* list_pair_ss = static_cast(fMainList->FindObject("Pair")->FindObject(pairnames[pairtype].data())); - - for (auto& collision : collisions) { - if ((pairtype == kPHOSPHOS || pairtype == kPCMPHOS) && !collision.alias_bit(triggerAliases::kTVXinPHOS)) { - continue; - } - - const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { - continue; - } - - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_pair_before, "", collision); - if (!fEMEventCut.IsSelected(collision)) { - continue; - } - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_pair_after, "", collision); - reinterpret_cast(list_ev_pair_before->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - reinterpret_cast(list_ev_pair_after->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - - auto photons1_coll = photons1.sliceBy(perCollision1, collision.globalIndex()); - auto photons2_coll = photons2.sliceBy(perCollision2, collision.globalIndex()); - // LOGF(info, "photons1_coll.size() = %d, photons2_coll.size() = %d", photons1_coll.size(), photons2_coll.size()); - - float dca_pos1_3d = 999.f, dca_ele1_3d = 999.f, dca_ee1_3d = 999.f; - float dca_pos2_3d = 999.f, dca_ele2_3d = 999.f, dca_ee2_3d = 999.f; - - double values_1d[6] = {0.f}; - double values_3d[10] = {0.f}; - if constexpr (pairtype == PairType::kPCMPCM || pairtype == PairType::kPHOSPHOS || pairtype == PairType::kEMCEMC || pairtype == PairType::kDalitzEEDalitzEE) { - for (auto& cut : cuts1) { - for (auto& paircut : paircuts) { - for (auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photons1_coll, photons2_coll))) { - if (!IsSelectedPair(g1, g2, cut, cut)) { - continue; - } - - values_1d[0] = 0.0, values_1d[1] = 0.0, values_1d[2] = 0.0, values_1d[3] = 0.0; - values_3d[0] = 0.0, values_3d[1] = 0.0, values_3d[2] = 0.0, values_3d[3] = 0.0; - // center-of-mass system (CMS) - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); - if constexpr (pairtype == PairType::kDalitzEEDalitzEE) { - auto pos1 = g1.template posTrack_as(); - auto ele1 = g1.template negTrack_as(); - auto pos2 = g2.template posTrack_as(); - auto ele2 = g2.template negTrack_as(); - if (pos1.trackId() == pos2.trackId() || ele1.trackId() == ele2.trackId()) { - continue; - } - v1.SetM(g1.mass()); - v2.SetM(g2.mass()); - values_1d[0] = g1.mass(); - values_1d[1] = g2.mass(); - values_3d[0] = g1.mass(); - values_3d[1] = g2.mass(); - - dca_pos1_3d = pos1.dca3DinSigma(); - dca_ele1_3d = ele1.dca3DinSigma(); - dca_ee1_3d = std::sqrt((dca_pos1_3d * dca_pos1_3d + dca_ele1_3d * dca_ele1_3d) / 2.); - values_1d[2] = dca_ee1_3d; - values_3d[2] = dca_ee1_3d; - - dca_pos2_3d = pos2.dca3DinSigma(); - dca_ele2_3d = ele2.dca3DinSigma(); - dca_ee2_3d = std::sqrt((dca_pos2_3d * dca_pos2_3d + dca_ele2_3d * dca_ele2_3d) / 2.); - values_1d[3] = dca_ee2_3d; - values_3d[3] = dca_ee2_3d; - } - - ROOT::Math::PtEtaPhiMVector q12 = v1 - v2; - ROOT::Math::PtEtaPhiMVector k12 = 0.5 * (v1 + v2); - float qinv = -q12.M(); - float kt = k12.Pt(); - - values_1d[4] = kt; - values_1d[5] = qinv; - - if (fConfigDo3D) { - // float qt = q12.Pt(); - float qlong_cms = q12.Pz(); - - ROOT::Math::XYZVector q_3d = q12.Vect(); // 3D q vector - ROOT::Math::XYZVector uv_out(k12.Px() / k12.Pt(), k12.Py() / k12.Pt(), 0); // unit vector for out. i.e. parallel to kt - ROOT::Math::XYZVector uv_long(0, 0, 1); // unit vector for long, beam axis - ROOT::Math::XYZVector uv_side = uv_out.Cross(uv_long); // unit vector for side - float qout_cms = q_3d.Dot(uv_out); - float qside_cms = q_3d.Dot(uv_side); - - // longitudinally co-moving system (LCMS) - ROOT::Math::PxPyPzEVector v1_cartesian(v1.Px(), v1.Py(), v1.Pz(), v1.E()); - ROOT::Math::PxPyPzEVector v2_cartesian(v2.Px(), v2.Py(), v2.Pz(), v2.E()); - ROOT::Math::PxPyPzEVector q12_cartesian = v1_cartesian - v2_cartesian; - float beta_z = (v1 + v2).Pz() / (v1 + v2).E(); - ROOT::Math::Boost bst_z(0, 0, -beta_z); // Boost supports only PxPyPzEVector - ROOT::Math::PxPyPzEVector q12_lcms = bst_z(q12_cartesian); - float qlong_lcms = q12_lcms.Pz(); - - // ROOT::Math::PxPyPzEVector v1_lcms_cartesian = bst_z(v1_cartesian); - // ROOT::Math::PxPyPzEVector v2_lcms_cartesian = bst_z(v2_cartesian); - // ROOT::Math::PxPyPzEVector q12_lcms_cartesian = bst_z(q12_cartesian); - // LOGF(info, "q12.Pz() = %f, q12_cartesian.Pz() = %f",q12.Pz(), q12_cartesian.Pz()); - // LOGF(info, "v1.Pz() = %f, v2.Pz() = %f",v1.Pz(), v2.Pz()); - // LOGF(info, "v1_lcms_cartesian.Pz() = %f, v2_lcms_cartesian.Pz() = %f",v1_lcms_cartesian.Pz(), v2_lcms_cartesian.Pz()); - // LOGF(info, "q12_lcms_cartesian.Pz() = %f", q12_lcms_cartesian.Pz()); - values_3d[4] = kt; - values_3d[5] = qinv; - values_3d[6] = qlong_cms; - values_3d[7] = qout_cms; - values_3d[8] = qside_cms; - values_3d[9] = qlong_lcms; - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut.GetName(), cut.GetName()))->FindObject(paircut.GetName())->FindObject("hs_q_same"))->Fill(values_3d); - } else { - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut.GetName(), cut.GetName()))->FindObject(paircut.GetName())->FindObject("hs_q_same"))->Fill(values_1d); - } - } // end of combination - } // end of pair cut loop - } // end of cut loop - } else { // different subsystem pairs - for (auto& cut1 : cuts1) { - for (auto& cut2 : cuts2) { - for (auto& paircut : paircuts) { - for (auto& [g1, g2] : combinations(CombinationsFullIndexPolicy(photons1_coll, photons2_coll))) { - if (!IsSelectedPair(g1, g2, cut1, cut2)) { - continue; - } - if (!paircut.IsSelected(g1, g2)) { - continue; - } - if constexpr (pairtype == PairType::kPCMPHOS) { - auto pos = g1.template posTrack_as(); - auto ele = g1.template negTrack_as(); - if (o2::aod::photonpair::DoesV0LegMatchWithCluster(pos, g2, 0.02, 0.4, 0.2) || o2::aod::photonpair::DoesV0LegMatchWithCluster(ele, g2, 0.02, 0.4, 0.2)) { - continue; - } - } - - values_1d[0] = 0.0, values_1d[1] = 0.0, values_1d[2] = 0.0, values_1d[3] = 0.0; - values_3d[0] = 0.0, values_3d[1] = 0.0, values_3d[2] = 0.0, values_3d[3] = 0.0; - // center-of-mass system (CMS) - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); - if constexpr (pairtype == PairType::kPCMDalitzEE) { - auto pos2 = g2.template posTrack_as(); - auto ele2 = g2.template negTrack_as(); - v2.SetM(g2.mass()); - values_1d[1] = g2.mass(); - values_3d[1] = g2.mass(); - dca_pos2_3d = pos2.dca3DinSigma(); - dca_ele2_3d = ele2.dca3DinSigma(); - dca_ee2_3d = std::sqrt((dca_pos2_3d * dca_pos2_3d + dca_ele2_3d * dca_ele2_3d) / 2.); - values_1d[3] = dca_ee2_3d; - values_3d[3] = dca_ee2_3d; - } - ROOT::Math::PtEtaPhiMVector q12 = v1 - v2; - ROOT::Math::PtEtaPhiMVector k12 = 0.5 * (v1 + v2); - float qinv = -q12.M(); - float kt = k12.Pt(); - - values_1d[4] = kt; - values_1d[5] = qinv; - - if (fConfigDo3D) { - // float qt = q12.Pt(); - float qlong_cms = q12.Pz(); - - ROOT::Math::XYZVector q_3d = q12.Vect(); // 3D q vector - ROOT::Math::XYZVector uv_out(k12.Px() / k12.Pt(), k12.Py() / k12.Pt(), 0); // unit vector for out. i.e. parallel to kt - ROOT::Math::XYZVector uv_long(0, 0, 1); // unit vector for long, beam axis - ROOT::Math::XYZVector uv_side = uv_out.Cross(uv_long); // unit vector for side - float qout_cms = q_3d.Dot(uv_out); - float qside_cms = q_3d.Dot(uv_side); - - // longitudinally co-moving system (LCMS) - ROOT::Math::PxPyPzEVector v1_cartesian(v1.Px(), v1.Py(), v1.Pz(), v1.E()); - ROOT::Math::PxPyPzEVector v2_cartesian(v2.Px(), v2.Py(), v2.Pz(), v2.E()); - ROOT::Math::PxPyPzEVector q12_cartesian = v1_cartesian - v2_cartesian; - float beta_z = (v1 + v2).Pz() / (v1 + v2).E(); - ROOT::Math::Boost bst_z(0, 0, -beta_z); // Boost supports only PxPyPzEVector - ROOT::Math::PxPyPzEVector q12_lcms = bst_z(q12_cartesian); - float qlong_lcms = q12_lcms.Pz(); - values_3d[4] = kt; - values_3d[5] = qinv; - values_3d[6] = qlong_cms; - values_3d[7] = qout_cms; - values_3d[8] = qside_cms; - values_3d[9] = qlong_lcms; - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hs_q_same"))->Fill(values_3d); - } else { - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hs_q_same"))->Fill(values_1d); - } - } // end of combination - } // end of pair cut loop - } // end of cut2 loop - } // end of cut1 loop - } - } // end of collision loop - } - - Configurable ndepth{"ndepth", 10, "depth for event mixing"}; - ConfigurableAxis ConfVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - ConfigurableAxis ConfCentBins{"ConfCentBins", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 999.f}, "Mixing bins - centrality"}; - using BinningType_M = ColumnBinningPolicy; - using BinningType_A = ColumnBinningPolicy; - using BinningType_C = ColumnBinningPolicy; - BinningType_M colBinning_M{{ConfVtxBins, ConfCentBins}, true}; - BinningType_A colBinning_A{{ConfVtxBins, ConfCentBins}, true}; - BinningType_C colBinning_C{{ConfVtxBins, ConfCentBins}, true}; - - template - void MixedEventPairing(TEvents const& collisions, TPhotons1 const& photons1, TPhotons2 const& photons2, TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, TCuts1 const& cuts1, TCuts2 const& cuts2, TPairCuts const& paircuts, TLegs const& /*legs*/, TEMPrimaryElectrons const& /*emprimaryelectrons*/, TMixedBinning const& colBinning) - { - THashList* list_pair_ss = static_cast(fMainList->FindObject("Pair")->FindObject(pairnames[pairtype].data())); - // LOGF(info, "Number of collisions after filtering: %d", collisions.size()); - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, ndepth, -1, collisions, collisions)) { // internally, CombinationsStrictlyUpperIndexPolicy(collisions, collisions) is called. - // LOGF(info, "Mixed event globalIndex: (%d, %d) , counter = %d, ngpcm: (%d, %d), ngphos: (%d, %d), ngemc: (%d, %d)", collision1.globalIndex(), collision2.globalIndex(), nev, collision1.ngpcm(), collision2.ngpcm(), collision1.ngphos(), collision2.ngphos(), collision1.ngemc(), collision2.ngemc()); - - const float centralities1[3] = {collision1.centFT0M(), collision1.centFT0A(), collision1.centFT0C()}; - const float centralities2[3] = {collision2.centFT0M(), collision2.centFT0A(), collision2.centFT0C()}; - - if (centralities1[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities1[cfgCentEstimator]) { - continue; - } - if (centralities2[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities2[cfgCentEstimator]) { - continue; - } - if (!fEMEventCut.IsSelected(collision1) || !fEMEventCut.IsSelected(collision2)) { - continue; - } - - auto photons_coll1 = photons1.sliceBy(perCollision1, collision1.globalIndex()); - auto photons_coll2 = photons2.sliceBy(perCollision2, collision2.globalIndex()); - // LOGF(info, "collision1: posZ = %f, numContrib = %d , sel8 = %d | collision2: posZ = %f, numContrib = %d , sel8 = %d", collision1.posZ(), collision1.numContrib(), collision1.sel8(), collision2.posZ(), collision2.numContrib(), collision2.sel8()); - - float dca_pos1_3d = 999.f, dca_ele1_3d = 999.f, dca_ee1_3d = 999.f; - float dca_pos2_3d = 999.f, dca_ele2_3d = 999.f, dca_ee2_3d = 999.f; - double values_1d[6] = {0.f}; - double values_3d[10] = {0.f}; - for (auto& cut1 : cuts1) { - for (auto& cut2 : cuts2) { - for (auto& paircut : paircuts) { - for (auto& [g1, g2] : combinations(soa::CombinationsFullIndexPolicy(photons_coll1, photons_coll2))) { - // LOGF(info, "Mixed event photon pair: (%d, %d) from events (%d, %d), photon event: (%d, %d)", g1.index(), g2.index(), collision1.index(), collision2.index(), g1.globalIndex(), g2.globalIndex()); - - if ((pairtype == PairType::kPCMPCM || pairtype == PairType::kPHOSPHOS || pairtype == PairType::kEMCEMC || pairtype == PairType::kDalitzEEDalitzEE) && (TString(cut1.GetName()) != TString(cut2.GetName()))) { - continue; - } - if (!IsSelectedPair(g1, g2, cut1, cut2)) { - continue; - } - if (!paircut.IsSelected(g1, g2)) { - continue; - } - - // center-of-mass system (CMS) - values_1d[0] = 0.0, values_1d[1] = 0.0, values_1d[2] = 0.0, values_1d[3] = 0.0; - values_3d[0] = 0.0, values_3d[1] = 0.0, values_3d[2] = 0.0, values_3d[3] = 0.0; - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); - if constexpr (pairtype == PairType::kPCMDalitzEE) { - auto pos2 = g2.template posTrack_as(); - auto ele2 = g2.template negTrack_as(); - v2.SetM(g2.mass()); - values_1d[1] = g2.mass(); - values_3d[1] = g2.mass(); - dca_pos2_3d = pos2.dca3DinSigma(); - dca_ele2_3d = ele2.dca3DinSigma(); - dca_ee2_3d = std::sqrt((dca_pos2_3d * dca_pos2_3d + dca_ele2_3d * dca_ele2_3d) / 2.); - values_1d[3] = dca_ee2_3d; - values_3d[3] = dca_ee2_3d; - } else if constexpr (pairtype == PairType::kDalitzEEDalitzEE) { - auto pos1 = g1.template posTrack_as(); - auto ele1 = g1.template negTrack_as(); - auto pos2 = g2.template posTrack_as(); - auto ele2 = g2.template negTrack_as(); - v1.SetM(g1.mass()); - v2.SetM(g2.mass()); - values_1d[0] = g1.mass(); - values_1d[1] = g2.mass(); - values_3d[0] = g1.mass(); - values_3d[1] = g2.mass(); - - dca_pos1_3d = pos1.dca3DinSigma(); - dca_ele1_3d = ele1.dca3DinSigma(); - dca_ee1_3d = std::sqrt((dca_pos1_3d * dca_pos1_3d + dca_ele1_3d * dca_ele1_3d) / 2.); - values_1d[2] = dca_ee1_3d; - values_3d[2] = dca_ee1_3d; - - dca_pos2_3d = pos2.dca3DinSigma(); - dca_ele2_3d = ele2.dca3DinSigma(); - dca_ee2_3d = std::sqrt((dca_pos2_3d * dca_pos2_3d + dca_ele2_3d * dca_ele2_3d) / 2.); - values_1d[3] = dca_ee2_3d; - values_3d[3] = dca_ee2_3d; - } - ROOT::Math::PtEtaPhiMVector q12 = v1 - v2; - ROOT::Math::PtEtaPhiMVector k12 = 0.5 * (v1 + v2); - float qinv = -q12.M(); - float kt = k12.Pt(); - values_1d[4] = kt; - values_1d[5] = qinv; - - if (fConfigDo3D) { - // float qt = q12.Pt(); - float qlong_cms = q12.Pz(); - - ROOT::Math::XYZVector q_3d = q12.Vect(); // 3D q vector - ROOT::Math::XYZVector uv_out(k12.Px() / k12.Pt(), k12.Py() / k12.Pt(), 0); // unit vector for out. i.e. parallel to kt - ROOT::Math::XYZVector uv_long(0, 0, 1); // unit vector for long, beam axis - ROOT::Math::XYZVector uv_side = uv_out.Cross(uv_long); // unit vector for side - float qout_cms = q_3d.Dot(uv_out); - float qside_cms = q_3d.Dot(uv_side); - - // longitudinally co-moving system (LCMS) - ROOT::Math::PxPyPzEVector v1_cartesian(v1.Px(), v1.Py(), v1.Pz(), v1.E()); - ROOT::Math::PxPyPzEVector v2_cartesian(v2.Px(), v2.Py(), v2.Pz(), v2.E()); - ROOT::Math::PxPyPzEVector q12_cartesian = v1_cartesian - v2_cartesian; - float beta_z = (v1 + v2).Pz() / (v1 + v2).E(); - ROOT::Math::Boost bst_z(0, 0, -beta_z); // Boost supports only PxPyPzEVector - ROOT::Math::PxPyPzEVector q12_lcms = bst_z(q12_cartesian); - float qlong_lcms = q12_lcms.Pz(); - - values_3d[4] = kt; - values_3d[5] = qinv; - values_3d[6] = qlong_cms; - values_3d[7] = qout_cms; - values_3d[8] = qside_cms; - values_3d[9] = qlong_lcms; - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hs_q_mix"))->Fill(values_3d); - } else { - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hs_q_mix"))->Fill(values_1d); - } - - } // end of different photon combinations - } // end of pair cut loop - } // end of cut2 loop - } // end of cut1 loop - } // end of different collision combinations - } - - Preslice perCollision_pcm = aod::v0photonkf::emeventId; - Preslice perCollision_dalitzee = aod::dalitzee::emeventId; - Preslice perCollision_phos = aod::skimmedcluster::collisionId; - - Filter eeFilter = o2::aod::dalitzee::sign == 0 && nabs(o2::aod::dalitzee::rapidity) < maxY_dielectron; // analyze only uls - using filteredMyDalitzEEs = soa::Filtered; - - Partition grouped_collisions = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); // this goes to same event. - - Filter collisionFilter_common = nabs(o2::aod::collision::posZ) < 10.f && o2::aod::collision::numContrib > (uint16_t)0 && o2::aod::evsel::sel8 == true; - Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); - Filter collisionFilter_subsys = (o2::aod::emevent::ngpcm >= 1) || (o2::aod::emevent::neeuls >= 1); - using MyFilteredCollisions = soa::Filtered; - - void processPCMPCM(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, MyV0Photons const& v0photons, aod::V0Legs const& legs) - { - SameEventPairing(grouped_collisions, v0photons, v0photons, perCollision_pcm, perCollision_pcm, fPCMCuts, fPCMCuts, fPairCuts, legs, nullptr); - if (cfgCentEstimator == 0) { - MixedEventPairing(filtered_collisions, v0photons, v0photons, perCollision_pcm, perCollision_pcm, fPCMCuts, fPCMCuts, fPairCuts, legs, nullptr, colBinning_M); - } else if (cfgCentEstimator == 1) { - MixedEventPairing(filtered_collisions, v0photons, v0photons, perCollision_pcm, perCollision_pcm, fPCMCuts, fPCMCuts, fPairCuts, legs, nullptr, colBinning_A); - } else if (cfgCentEstimator == 2) { - MixedEventPairing(filtered_collisions, v0photons, v0photons, perCollision_pcm, perCollision_pcm, fPCMCuts, fPCMCuts, fPairCuts, legs, nullptr, colBinning_C); - } - } - - void processPCMDalitzEE(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, MyV0Photons const& v0photons, aod::V0Legs const& legs, filteredMyDalitzEEs const& dielectrons, MyPrimaryElectrons const& emprimaryelectrons) - { - SameEventPairing(grouped_collisions, v0photons, dielectrons, perCollision_pcm, perCollision_dalitzee, fPCMCuts, fDalitzEECuts, fPairCuts, legs, emprimaryelectrons); - if (cfgCentEstimator == 0) { - MixedEventPairing(filtered_collisions, v0photons, dielectrons, perCollision_pcm, perCollision_dalitzee, fPCMCuts, fDalitzEECuts, fPairCuts, legs, emprimaryelectrons, colBinning_M); - } else if (cfgCentEstimator == 1) { - MixedEventPairing(filtered_collisions, v0photons, dielectrons, perCollision_pcm, perCollision_dalitzee, fPCMCuts, fDalitzEECuts, fPairCuts, legs, emprimaryelectrons, colBinning_A); - } else if (cfgCentEstimator == 2) { - MixedEventPairing(filtered_collisions, v0photons, dielectrons, perCollision_pcm, perCollision_dalitzee, fPCMCuts, fDalitzEECuts, fPairCuts, legs, emprimaryelectrons, colBinning_C); - } - } - - void processDalitzEEDalitzEE(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, filteredMyDalitzEEs const& dielectrons, MyPrimaryElectrons const& emprimaryelectrons) - { - SameEventPairing(grouped_collisions, dielectrons, dielectrons, perCollision_dalitzee, perCollision_dalitzee, fDalitzEECuts, fDalitzEECuts, fPairCuts, nullptr, emprimaryelectrons); - if (cfgCentEstimator == 0) { - MixedEventPairing(filtered_collisions, dielectrons, dielectrons, perCollision_dalitzee, perCollision_dalitzee, fDalitzEECuts, fDalitzEECuts, fPairCuts, nullptr, emprimaryelectrons, colBinning_M); - } else if (cfgCentEstimator == 1) { - MixedEventPairing(filtered_collisions, dielectrons, dielectrons, perCollision_dalitzee, perCollision_dalitzee, fDalitzEECuts, fDalitzEECuts, fPairCuts, nullptr, emprimaryelectrons, colBinning_A); - } else if (cfgCentEstimator == 2) { - MixedEventPairing(filtered_collisions, dielectrons, dielectrons, perCollision_dalitzee, perCollision_dalitzee, fDalitzEECuts, fDalitzEECuts, fPairCuts, nullptr, emprimaryelectrons, colBinning_C); - } - } - - void processPHOSPHOS(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, aod::PHOSClusters const& phosclusters) - { - SameEventPairing(grouped_collisions, phosclusters, phosclusters, perCollision_phos, perCollision_phos, fPHOSCuts, fPHOSCuts, fPairCuts, nullptr, nullptr); - MixedEventPairing(filtered_collisions, phosclusters, phosclusters, perCollision_phos, perCollision_phos, fPHOSCuts, fPHOSCuts, fPairCuts, nullptr, nullptr, colBinning_C); - } - - void processPCMPHOS(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, MyV0Photons const& v0photons, aod::PHOSClusters const& phosclusters, aod::V0Legs const& legs) - { - SameEventPairing(grouped_collisions, v0photons, phosclusters, perCollision_pcm, perCollision_phos, fPCMCuts, fPHOSCuts, fPairCuts, legs, nullptr); - MixedEventPairing(filtered_collisions, v0photons, phosclusters, perCollision_pcm, perCollision_phos, fPCMCuts, fPHOSCuts, fPairCuts, legs, nullptr, colBinning_C); - } - - void processDummy(MyCollisions const&) {} - - PROCESS_SWITCH(PhotonHBT, processPCMPCM, "pairing PCM-PCM", false); - PROCESS_SWITCH(PhotonHBT, processPCMDalitzEE, "pairing PCM-DalitzEE", false); - PROCESS_SWITCH(PhotonHBT, processDalitzEEDalitzEE, "pairing DalitzEE-DalitzEE", false); - PROCESS_SWITCH(PhotonHBT, processPHOSPHOS, "pairing PHOS-PHOS", false); - PROCESS_SWITCH(PhotonHBT, processPCMPHOS, "pairing PCM-PHOS", false); - PROCESS_SWITCH(PhotonHBT, processDummy, "Dummy function", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"photon-hbt"})}; -} diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGamma.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGamma.cxx deleted file mode 100644 index 16a7aa1ddf3..00000000000 --- a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGamma.cxx +++ /dev/null @@ -1,790 +0,0 @@ -// 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. -// -// ======================== -// -// This code loops over photons and makes pairs for neutral mesons analyses. -// Please write to: daiki.sekihata@cern.ch - -#include -#include - -#include "TString.h" -#include "Math/Vector4D.h" -#include "Math/Vector3D.h" -#include "Math/LorentzRotation.h" -#include "Math/Rotation3D.h" -#include "Math/AxisAngle.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" - -#include "Common/Core/RecoDecay.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" -#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" -#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" -#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" -#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" -#include "PWGEM/PhotonMeson/Core/PairCut.h" -#include "PWGEM/PhotonMeson/Core/CutsLibrary.h" -#include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" - -using namespace o2; -using namespace o2::aod; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::soa; -using namespace o2::aod::photonpair; -using namespace o2::aod::pwgem::photon; - -using MyCollisions = soa::Join; -using MyCollision = MyCollisions::iterator; - -using MyV0Photons = soa::Join; -using MyV0Photon = MyV0Photons::iterator; - -using MyDalitzEEs = soa::Join; -using MyDalitzEE = MyDalitzEEs::iterator; - -using MyDalitzMuMus = soa::Join; -using MyDalitzMuMu = MyDalitzMuMus::iterator; - -using MyPrimaryElectrons = soa::Join; -using MyPrimaryElectron = MyPrimaryElectrons::iterator; - -using MyPrimaryMuons = soa::Join; -using MyPrimaryMuon = MyPrimaryMuons::iterator; - -struct Pi0EtaToGammaGamma { - - Configurable cfgDoFlow{"cfgDoFlow", false, "flag to analyze vn"}; - - Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; - Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; - Configurable cfgCentMax{"cfgCentMax", 999, "max. centrality"}; - - Configurable maxY{"maxY", 0.9, "maximum rapidity for reconstructed particles"}; - Configurable fConfigPCMCuts{"cfgPCMCuts", "qc,nocut", "Comma separated list of V0 photon cuts"}; - Configurable fConfigDalitzEECuts{"cfgDalitzEECuts", "mee_0_120_tpchadrejortofreq_lowB,mee_120_500_tpchadrejortofreq_lowB,mee_0_500_tpchadrejortofreq_lowB", "Comma separated list of Dalitz ee cuts"}; - Configurable fConfigDalitzMuMuCuts{"cfgDalitzMuMuCuts", "mmumu_0_500_tpctof_lowB", "Comma separated list of Dalitz mumu cuts"}; - Configurable fConfigPHOSCuts{"cfgPHOSCuts", "test02,test03", "Comma separated list of PHOS photon cuts"}; - Configurable fConfigPairCuts{"cfgPairCuts", "nocut", "Comma separated list of pair cuts"}; - - Configurable minOpenAngle{"minOpenAngle", 0.0202, "apply min opening angle"}; - Configurable fConfigEMCCuts{"cfgEMCCuts", "custom,standard,nocut", "Comma separated list of EMCal photon cuts"}; - - // Configurable for EMCal cuts - Configurable requireCaloReadout{"requireCaloReadout", true, "Require calorimeters readout when analyzing EMCal/PHOS"}; - Configurable EMC_minTime{"EMC_minTime", -20., "Minimum cluster time for EMCal time cut"}; - Configurable EMC_maxTime{"EMC_maxTime", +25., "Maximum cluster time for EMCal time cut"}; - Configurable EMC_minM02{"EMC_minM02", 0.1, "Minimum M02 for EMCal M02 cut"}; - Configurable EMC_maxM02{"EMC_maxM02", 0.7, "Maximum M02 for EMCal M02 cut"}; - Configurable EMC_minE{"EMC_minE", 0.7, "Minimum cluster energy for EMCal energy cut"}; - Configurable EMC_minNCell{"EMC_minNCell", 1, "Minimum number of cells per cluster for EMCal NCell cut"}; - Configurable> EMC_TM_Eta{"EMC_TM_Eta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; - Configurable> EMC_TM_Phi{"EMC_TM_Phi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; - Configurable EMC_Eoverp{"EMC_Eoverp", 1.75, "Minimum cluster energy over track momentum for EMCal track matching"}; - Configurable EMC_UseExoticCut{"EMC_UseExoticCut", true, "FLag to use the EMCal exotic cluster cut"}; - - Configurable fConfigEMEventCut{"cfgEMEventCut", "minbias", "em event cut"}; // only 1 event cut per wagon - EMEventCut fEMEventCut; - static constexpr std::string_view event_types[2] = {"before", "after"}; - - OutputObj fOutputEvent{"Event"}; - OutputObj fOutputPair{"Pair"}; // 2-photon pair - THashList* fMainList = new THashList(); - - std::vector fPCMCuts; - std::vector fDalitzEECuts; - std::vector fDalitzMuMuCuts; - std::vector fPHOSCuts; - std::vector fEMCCuts; - std::vector fPairCuts; - std::vector fPairNames; - - void init(InitContext& context) - { - if (context.mOptions.get("processPCMPCM")) { - fPairNames.push_back("PCMPCM"); - } - if (context.mOptions.get("processPHOSPHOS")) { - fPairNames.push_back("PHOSPHOS"); - } - if (context.mOptions.get("processEMCEMC")) { - fPairNames.push_back("EMCEMC"); - } - if (context.mOptions.get("processPCMPHOS")) { - fPairNames.push_back("PCMPHOS"); - } - if (context.mOptions.get("processPCMEMC")) { - fPairNames.push_back("PCMEMC"); - } - if (context.mOptions.get("processPCMDalitzEE")) { - fPairNames.push_back("PCMDalitzEE"); - } - if (context.mOptions.get("processPCMDalitzMuMu")) { - fPairNames.push_back("PCMDalitzMuMu"); - } - if (context.mOptions.get("processPHOSEMC")) { - fPairNames.push_back("PHOSEMC"); - } - - DefinePCMCuts(); - DefineDalitzEECuts(); - DefineDalitzMuMuCuts(); - DefinePHOSCuts(); - DefineEMCCuts(); - DefinePairCuts(); - addhistograms(); - - TString ev_cut_name = fConfigEMEventCut.value; - fEMEventCut = *eventcuts::GetCut(ev_cut_name.Data()); - - fOutputEvent.setObject(reinterpret_cast(fMainList->FindObject("Event"))); - fOutputPair.setObject(reinterpret_cast(fMainList->FindObject("Pair"))); - } - - template - void add_pair_histograms(THashList* list_pair, const std::string pairname, TCuts1 const& cuts1, TCuts2 const& cuts2, TCuts3 const& cuts3) - { - for (auto& cut1 : cuts1) { - for (auto& cut2 : cuts2) { - std::string cutname1 = cut1.GetName(); - std::string cutname2 = cut2.GetName(); - - if ((pairname == "PCMPCM" || pairname == "PHOSPHOS" || pairname == "EMCEMC") && (cutname1 != cutname2)) - continue; - - THashList* list_pair_subsys = reinterpret_cast(list_pair->FindObject(pairname.data())); - std::string photon_cut_name = cutname1 + "_" + cutname2; - o2::aod::pwgem::photon::histogram::AddHistClass(list_pair_subsys, photon_cut_name.data()); - THashList* list_pair_subsys_photoncut = reinterpret_cast(list_pair_subsys->FindObject(photon_cut_name.data())); - - for (auto& cut3 : cuts3) { - std::string pair_cut_name = cut3.GetName(); - o2::aod::pwgem::photon::histogram::AddHistClass(list_pair_subsys_photoncut, pair_cut_name.data()); - THashList* list_pair_subsys_paircut = reinterpret_cast(list_pair_subsys_photoncut->FindObject(pair_cut_name.data())); - - if (cfgDoFlow) { - o2::aod::pwgem::photon::histogram::DefineHistograms(list_pair_subsys_paircut, "gammagamma_mass_pt", Form("%s,%s", pairname.data(), ",qvector")); - } else { - o2::aod::pwgem::photon::histogram::DefineHistograms(list_pair_subsys_paircut, "gammagamma_mass_pt", pairname.data()); - } - } // end of cut3 loop pair cut - } // end of cut2 loop - } // end of cut1 loop - } - - static constexpr std::string_view pairnames[9] = {"PCMPCM", "PHOSPHOS", "EMCEMC", "PCMPHOS", "PCMEMC", "PCMDalitzEE", "PCMDalitzMuMu", "PHOSEMC", "DalitzEEDalitzEE"}; - void addhistograms() - { - fMainList->SetOwner(true); - fMainList->SetName("fMainList"); - - // create sub lists first. - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Event"); - THashList* list_ev = reinterpret_cast(fMainList->FindObject("Event")); - - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Pair"); - THashList* list_pair = reinterpret_cast(fMainList->FindObject("Pair")); - - for (auto& pairname : fPairNames) { - LOGF(info, "Enabled pairs = %s", pairname.data()); - - THashList* list_ev_pair = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_ev, pairname.data())); - for (const auto& evtype : event_types) { - THashList* list_ev_type = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_ev_pair, evtype.data())); - - if (cfgDoFlow) { - o2::aod::pwgem::photon::histogram::DefineHistograms(list_ev_type, "Event", "qvector"); - } else { - o2::aod::pwgem::photon::histogram::DefineHistograms(list_ev_type, "Event", ""); - } - } - - o2::aod::pwgem::photon::histogram::AddHistClass(list_pair, pairname.data()); - - if (pairname == "PCMPCM") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fPCMCuts, fPairCuts); - } - if (pairname == "PHOSPHOS") { - add_pair_histograms(list_pair, pairname, fPHOSCuts, fPHOSCuts, fPairCuts); - } - if (pairname == "EMCEMC") { - add_pair_histograms(list_pair, pairname, fEMCCuts, fEMCCuts, fPairCuts); - } - if (pairname == "PCMPHOS") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fPHOSCuts, fPairCuts); - } - if (pairname == "PCMEMC") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fEMCCuts, fPairCuts); - } - if (pairname == "PCMDalitzEE") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fDalitzEECuts, fPairCuts); - } - if (pairname == "PCMDalitzMuMu") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fDalitzMuMuCuts, fPairCuts); - } - if (pairname == "PHOSEMC") { - add_pair_histograms(list_pair, pairname, fPHOSCuts, fEMCCuts, fPairCuts); - } - - } // end of pair name loop - } - - void DefinePCMCuts() - { - TString cutNamesStr = fConfigPCMCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fPCMCuts.push_back(*pcmcuts::GetCut(cutname)); - } - } - LOGF(info, "Number of PCM cuts = %d", fPCMCuts.size()); - } - - void DefineDalitzEECuts() - { - TString cutNamesStr = fConfigDalitzEECuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fDalitzEECuts.push_back(*dalitzeecuts::GetCut(cutname)); - } - } - LOGF(info, "Number of DalitzEE cuts = %d", fDalitzEECuts.size()); - } - void DefineDalitzMuMuCuts() - { - TString cutNamesStr = fConfigDalitzMuMuCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fDalitzMuMuCuts.push_back(*dalitzeecuts::GetCut(cutname)); - } - } - LOGF(info, "Number of DalitzMuMu cuts = %d", fDalitzMuMuCuts.size()); - } - - void DefinePHOSCuts() - { - TString cutNamesStr = fConfigPHOSCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fPHOSCuts.push_back(*phoscuts::GetCut(cutname)); - } - } - LOGF(info, "Number of PHOS cuts = %d", fPHOSCuts.size()); - } - - void DefineEMCCuts() - { - const float a = EMC_TM_Eta->at(0); - const float b = EMC_TM_Eta->at(1); - const float c = EMC_TM_Eta->at(2); - - const float d = EMC_TM_Phi->at(0); - const float e = EMC_TM_Phi->at(1); - const float f = EMC_TM_Phi->at(2); - LOGF(info, "EMCal track matching parameters : a = %f, b = %f, c = %f, d = %f, e = %f, f = %f", a, b, c, d, e, f); - - TString cutNamesStr = fConfigEMCCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - if (std::strcmp(cutname, "custom") == 0) { - EMCPhotonCut* custom_cut = new EMCPhotonCut(cutname, cutname); - custom_cut->SetMinE(EMC_minE); - custom_cut->SetMinNCell(EMC_minNCell); - custom_cut->SetM02Range(EMC_minM02, EMC_maxM02); - custom_cut->SetTimeRange(EMC_minTime, EMC_maxTime); - - custom_cut->SetTrackMatchingEta([&a, &b, &c](float pT) { - return a + pow(pT + b, c); - }); - custom_cut->SetTrackMatchingPhi([&d, &e, &f](float pT) { - return d + pow(pT + e, f); - }); - - custom_cut->SetMinEoverP(EMC_Eoverp); - custom_cut->SetUseExoticCut(EMC_UseExoticCut); - fEMCCuts.push_back(*custom_cut); - } else { - fEMCCuts.push_back(*emccuts::GetCut(cutname)); - } - } - } - LOGF(info, "Number of EMCal cuts = %d", fEMCCuts.size()); - } - - void DefinePairCuts() - { - TString cutNamesStr = fConfigPairCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fPairCuts.push_back(*paircuts::GetCut(cutname)); - } - } - LOGF(info, "Number of Pair cuts = %d", fPairCuts.size()); - } - - Preslice perCollision = aod::v0photonkf::emeventId; - Preslice perCollision_dalitzee = aod::dalitzee::emeventId; - Preslice perCollision_dalitzmumu = aod::dalitzmumu::emeventId; - Preslice perCollision_phos = aod::skimmedcluster::collisionId; - Preslice perCollision_emc = aod::skimmedcluster::collisionId; - - template - bool IsSelectedPair(TG1 const& g1, TG2 const& g2, TCut1 const& cut1, TCut2 const& cut2) - { - bool is_selected_pair = false; - if constexpr (pairtype == PairType::kPCMPCM) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPHOSPHOS) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); // dummy, because track matching is not ready. - } else if constexpr (pairtype == PairType::kEMCEMC) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPCMPHOS) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPCMEMC) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPCMDalitzEE) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPCMDalitzMuMu) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPHOSEMC) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else { - is_selected_pair = true; - } - return is_selected_pair; - } - - template - void SameEventPairing(TEvents const& collisions, TPhotons1 const& photons1, TPhotons2 const& photons2, TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, TCuts1 const& cuts1, TCuts2 const& cuts2, TPairCuts const& paircuts, TLegs const& /*legs*/, TEMPrimaryElectrons const& /*emprimaryelectrons*/, TEMPrimaryMuons const& /*emprimarymuons*/, TEMCMTs const& emcmatchedtracks) - { - THashList* list_ev_pair_before = static_cast(fMainList->FindObject("Event")->FindObject(pairnames[pairtype].data())->FindObject(event_types[0].data())); - THashList* list_ev_pair_after = static_cast(fMainList->FindObject("Event")->FindObject(pairnames[pairtype].data())->FindObject(event_types[1].data())); - THashList* list_pair_ss = static_cast(fMainList->FindObject("Pair")->FindObject(pairnames[pairtype].data())); - double values[3] = {0, 0, 0}; - - for (auto& collision : collisions) { - if ((pairtype == PairType::kPHOSPHOS || pairtype == PairType::kPCMPHOS) && !collision.alias_bit(triggerAliases::kTVXinPHOS)) { - continue; - } - if ((pairtype == PairType::kEMCEMC || pairtype == PairType::kPCMEMC) && ((!collision.alias_bit(triggerAliases::kTVXinEMC) && requireCaloReadout) || collision.ncollsPerBC() != 1)) { - continue; - } - - const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { - continue; - } - - if (cfgDoFlow) { - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_pair_before, "", collision); - } else { - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_pair_before, "", collision); - } - - if (!fEMEventCut.IsSelected(collision)) { - continue; - } - - if (cfgDoFlow) { - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_pair_after, "", collision); - } else { - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_pair_after, "", collision); - } - - reinterpret_cast(list_ev_pair_before->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - reinterpret_cast(list_ev_pair_after->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - std::array q2ft0m = {collision.q2xft0m(), collision.q2yft0m()}; - std::array q2ft0a = {collision.q2xft0a(), collision.q2yft0a()}; - std::array q2ft0c = {collision.q2xft0c(), collision.q2yft0c()}; - std::array q2fv0a = {collision.q2xfv0a(), collision.q2yfv0a()}; - - auto photons1_coll = photons1.sliceBy(perCollision1, collision.globalIndex()); - auto photons2_coll = photons2.sliceBy(perCollision2, collision.globalIndex()); - - if constexpr (pairtype == PairType::kPCMPCM || pairtype == PairType::kPHOSPHOS || pairtype == PairType::kEMCEMC) { - for (auto& cut : cuts1) { - for (auto& paircut : paircuts) { - - for (auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photons1_coll, photons2_coll))) { - if (!IsSelectedPair(g1, g2, cut, cut)) { - continue; - } - if (!paircut.IsSelected(g1, g2)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - if (abs(v12.Rapidity()) > maxY) { - continue; - } - - if (cfgDoFlow) { - values[0] = v12.M(), values[1] = v12.Pt(); - std::array u2_gg = {static_cast(std::cos(2 * v12.Phi())), static_cast(std::sin(2 * v12.Phi()))}; - values[2] = RecoDecay::dotProd(u2_gg, q2ft0m); - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut.GetName(), cut.GetName()))->FindObject(paircut.GetName())->FindObject("hs_Same_SPQ2FT0M"))->Fill(values); - values[2] = RecoDecay::dotProd(u2_gg, q2ft0a); - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut.GetName(), cut.GetName()))->FindObject(paircut.GetName())->FindObject("hs_Same_SPQ2FT0A"))->Fill(values); - values[2] = RecoDecay::dotProd(u2_gg, q2ft0c); - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut.GetName(), cut.GetName()))->FindObject(paircut.GetName())->FindObject("hs_Same_SPQ2FT0C"))->Fill(values); - values[2] = RecoDecay::dotProd(u2_gg, q2fv0a); - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut.GetName(), cut.GetName()))->FindObject(paircut.GetName())->FindObject("hs_Same_SPQ2FV0A"))->Fill(values); - } else { - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut.GetName(), cut.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_Same"))->Fill(v12.M(), v12.Pt()); - if constexpr (pairtype == PairType::kEMCEMC) { - RotationBackground(v12, v1, v2, photons2_coll, g1.globalIndex(), g2.globalIndex(), cut, paircut, emcmatchedtracks); - } - } - - } // end of combination - } // end of pair cut loop - } // end of cut loop - - } else { // different subsystem pairs - for (auto& cut1 : cuts1) { - for (auto& cut2 : cuts2) { - for (auto& paircut : paircuts) { - for (auto& [g1, g2] : combinations(CombinationsFullIndexPolicy(photons1_coll, photons2_coll))) { - if (!IsSelectedPair(g1, g2, cut1, cut2)) { - continue; - } - if (!paircut.IsSelected(g1, g2)) { - continue; - } - - if constexpr (pairtype == PairType::kPCMPHOS || pairtype == PairType::kPCMEMC) { - auto pos = g1.template posTrack_as(); - auto ele = g1.template negTrack_as(); - - for (auto& v0leg : {pos, ele}) { - float deta = v0leg.eta() - g2.eta(); - float dphi = TVector2::Phi_mpi_pi(TVector2::Phi_0_2pi(v0leg.phi()) - TVector2::Phi_0_2pi(g2.phi())); - float Ep = g2.e() / v0leg.p(); - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hdEtadPhi"))->Fill(dphi, deta); - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hdEtaPt"))->Fill(v0leg.pt(), deta); - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hdPhiPt"))->Fill(v0leg.pt(), dphi); - if (pow(deta / 0.02, 2) + pow(dphi / 0.4, 2) < 1) { - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hEp_E"))->Fill(g2.e(), Ep); - } - } - - if constexpr (pairtype == PairType::kPCMPHOS) { - if (o2::aod::photonpair::DoesV0LegMatchWithCluster(pos, g2, 0.02, 0.4, 0.2) || o2::aod::photonpair::DoesV0LegMatchWithCluster(ele, g2, 0.02, 0.4, 0.2)) { - continue; - } - } else if constexpr (pairtype == PairType::kPCMEMC) { - if (o2::aod::photonpair::DoesV0LegMatchWithCluster(pos, g2, 0.02, 0.4, 0.5) || o2::aod::photonpair::DoesV0LegMatchWithCluster(ele, g2, 0.02, 0.4, 0.5)) { - continue; - } - } - } - - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); - if constexpr (pairtype == PairType::kPCMDalitzEE) { - v2.SetM(g2.mass()); - auto pos_sv = g1.template posTrack_as(); - auto ele_sv = g1.template negTrack_as(); - auto pos_pv = g2.template posTrack_as(); - auto ele_pv = g2.template negTrack_as(); - if (pos_sv.trackId() == pos_pv.trackId() || ele_sv.trackId() == ele_pv.trackId()) { - continue; - } - } else if constexpr (pairtype == PairType::kPCMDalitzMuMu) { - v2.SetM(g2.mass()); - auto pos_sv = g1.template posTrack_as(); - auto ele_sv = g1.template negTrack_as(); - auto pos_pv = g2.template posTrack_as(); - auto ele_pv = g2.template negTrack_as(); - if (pos_sv.trackId() == pos_pv.trackId() || ele_sv.trackId() == ele_pv.trackId()) { - continue; - } - } - - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - if (abs(v12.Rapidity()) > maxY) { - continue; - } - if (cfgDoFlow) { - values[0] = v12.M(), values[1] = v12.Pt(); - std::array u_gg = {static_cast(v12.Px() / v12.Pt()), static_cast(v12.Py() / v12.Pt())}; - values[2] = RecoDecay::dotProd(u_gg, q2ft0m); - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hs_Same_SPQ2FT0M"))->Fill(values); - values[2] = RecoDecay::dotProd(u_gg, q2ft0a); - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hs_Same_SPQ2FT0A"))->Fill(values); - values[2] = RecoDecay::dotProd(u_gg, q2ft0c); - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hs_Same_SPQ2FT0C"))->Fill(values); - values[2] = RecoDecay::dotProd(u_gg, q2fv0a); - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hs_Same_SPQ2FV0A"))->Fill(values); - } else { - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_Same"))->Fill(v12.M(), v12.Pt()); - } - - } // end of combination - } // end of pair cut loop - } // end of cut2 loop - } // end of cut1 loop - } - } // end of collision loop - } - - Configurable ndepth{"ndepth", 10, "depth for event mixing"}; - ConfigurableAxis ConfVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - ConfigurableAxis ConfCentBins{"ConfCentBins", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 999.f}, "Mixing bins - centrality"}; - using BinningType_M = ColumnBinningPolicy; - using BinningType_A = ColumnBinningPolicy; - using BinningType_C = ColumnBinningPolicy; - BinningType_M colBinning_M{{ConfVtxBins, ConfCentBins}, true}; - BinningType_A colBinning_A{{ConfVtxBins, ConfCentBins}, true}; - BinningType_C colBinning_C{{ConfVtxBins, ConfCentBins}, true}; - - template - void MixedEventPairing(TEvents const& collisions, TPhotons1 const& photons1, TPhotons2 const& photons2, TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, TCuts1 const& cuts1, TCuts2 const& cuts2, TPairCuts const& paircuts, TLegs const& /*legs*/, TEMPrimaryElectrons const& /*emprimaryelectrons*/, TEMPrimaryMuons const& /*emprimarymuons*/, TEMCMTs const& /*emcmatchedtracks*/, TMixedBinning const& colBinning) - { - THashList* list_pair_ss = static_cast(fMainList->FindObject("Pair")->FindObject(pairnames[pairtype].data())); - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, ndepth, -1, collisions, collisions)) { // internally, CombinationsStrictlyUpperIndexPolicy(collisions, collisions) is called. - - // LOGF(info, "Mixed event globalIndex: (%d, %d) , ngpcm: (%d, %d), ngphos: (%d, %d), ngemc: (%d, %d)", collision1.globalIndex(), collision2.globalIndex(), collision1.ngpcm(), collision2.ngpcm(), collision1.ngphos(), collision2.ngphos(), collision1.ngemc(), collision2.ngemc()); - - const float centralities1[3] = {collision1.centFT0M(), collision1.centFT0A(), collision1.centFT0C()}; - const float centralities2[3] = {collision2.centFT0M(), collision2.centFT0A(), collision2.centFT0C()}; - - if (centralities1[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities1[cfgCentEstimator]) { - continue; - } - if (centralities2[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities2[cfgCentEstimator]) { - continue; - } - if (!fEMEventCut.IsSelected(collision1) || !fEMEventCut.IsSelected(collision2)) { - continue; - } - - auto photons_coll1 = photons1.sliceBy(perCollision1, collision1.globalIndex()); - auto photons_coll2 = photons2.sliceBy(perCollision2, collision2.globalIndex()); - // LOGF(info, "collision1: posZ = %f, numContrib = %d , sel8 = %d | collision2: posZ = %f, numContrib = %d , sel8 = %d", collision1.posZ(), collision1.numContrib(), collision1.sel8(), collision2.posZ(), collision2.numContrib(), collision2.sel8()); - - for (auto& cut1 : cuts1) { - for (auto& cut2 : cuts2) { - for (auto& paircut : paircuts) { - for (auto& [g1, g2] : combinations(soa::CombinationsFullIndexPolicy(photons_coll1, photons_coll2))) { - // LOGF(info, "Mixed event photon pair: (%d, %d) from events (%d, %d), photon event: (%d, %d)", g1.index(), g2.index(), collision1.index(), collision2.index(), g1.globalIndex(), g2.globalIndex()); - - if ((pairtype == PairType::kPCMPCM || pairtype == PairType::kPHOSPHOS || pairtype == PairType::kEMCEMC) && (TString(cut1.GetName()) != TString(cut2.GetName()))) { - continue; - } - if (!IsSelectedPair(g1, g2, cut1, cut2)) { - continue; - } - if (!paircut.IsSelected(g1, g2)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); - if constexpr (pairtype == PairType::kPCMDalitzEE || pairtype == PairType::kPCMDalitzMuMu) { - v2.SetM(g2.mass()); - } - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - if (abs(v12.Rapidity()) > maxY) { - continue; - } - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_Mixed"))->Fill(v12.M(), v12.Pt()); - - } // end of different photon combinations - } // end of pair cut loop - } // end of cut2 loop - } // end of cut1 loop - } // end of different collision combinations - } - - /// \brief Calculate background (using rotation background method only for EMCal!) - template - void RotationBackground(const ROOT::Math::PtEtaPhiMVector& meson, ROOT::Math::PtEtaPhiMVector photon1, ROOT::Math::PtEtaPhiMVector photon2, TPhotons const& photons_coll, unsigned int ig1, unsigned int ig2, EMCPhotonCut const& cut, PairCut const& paircut, SkimEMCMTs const& /*emcmatchedtracks*/) - { - // if less than 3 clusters are present skip event since we need at least 3 clusters - if (photons_coll.size() < 3) { - return; - } - const double rotationAngle = M_PI / 2.0; // rotaion angle 90° - // ROOT::Math::XYZVector meson3D(meson.Px(), meson.Py(), meson.Pz()); - ROOT::Math::AxisAngle rotationAxis(meson.Vect(), rotationAngle); - // LOG(info) << "rotationAxis.Angle() = " << rotationAxis.Angle(); - ROOT::Math::Rotation3D rotationMatrix(rotationAxis); - // ROOT::Math::XYZVector test(photon1.Px(), photon1.Py(), photon1.Pz()); - // ROOT::Math::XYZVector photon1_3D(photon1.Px(), photon1.Py(), photon1.Pz()); - // ROOT::Math::XYZVector photon2_3D(photon2.Px(), photon2.Py(), photon2.Pz()); - - // float openingAngleTest = std::acos(photon1_3D.Dot(test) / (std::sqrt(photon1_3D.Mag2()) * std::sqrt(test.Mag2()))); - // LOG(info) << "openingAngleTest before rotation = " << openingAngleTest; - photon1 = rotationMatrix * photon1; - photon2 = rotationMatrix * photon2; - - // openingAngleTest = std::acos(photon1_3D.Dot(test) / (std::sqrt(photon1_3D.Mag2()) * std::sqrt(test.Mag2()))); - // LOG(info) << "openingAngleTest = " << openingAngleTest; - - for (auto& photon : photons_coll) { - if (photon.globalIndex() == ig1 || photon.globalIndex() == ig2) { - // only combine rotated photons with other photons - continue; - } - if (!cut.template IsSelected(photon)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector photon3; - photon3.SetPt(photon.pt()); - photon3.SetEta(photon.eta()); - photon3.SetPhi(photon.phi()); - photon3.SetM(0.); - // ROOT::Math::XYZVector photon3_3D(photon3.Px(), photon3.Py(), photon3.Pz()); - ROOT::Math::PtEtaPhiMVector mother1 = photon1 + photon3; - ROOT::Math::PtEtaPhiMVector mother2 = photon2 + photon3; - - float openingAngle1 = std::acos(photon1.Vect().Dot(photon3.Vect()) / (photon1.P() * photon3.P())); - float openingAngle2 = std::acos(photon2.Vect().Dot(photon3.Vect()) / (photon2.P() * photon3.P())); - // float openingAngle1_1 = std::acos(photon1_3D.Dot(photon3_3D) / (std::sqrt(photon1_3D.Mag2()) * std::sqrt(photon3_3D.Mag2()))); - // float openingAngle2_2 = std::acos(photon2_3D.Dot(photon3_3D) / (std::sqrt(photon2_3D.Mag2()) * std::sqrt(photon3_3D.Mag2()))); - // LOG(info) << "openingAngle1 = " << openingAngle1; - // LOG(info) << "openingAngle2 = " << openingAngle2; - // LOG(info) << "openingAngle1_1 = " << openingAngle1_1; - // LOG(info) << "openingAngle2_2 = " << openingAngle2_2; - - // Fill histograms - if (openingAngle1 > minOpenAngle) { - reinterpret_cast(fMainList->FindObject("Pair")->FindObject("EMCEMC")->FindObject(Form("%s_%s", cut.GetName(), cut.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_Same_RotatedBkg"))->Fill(mother1.M(), mother1.Pt()); - } - if (openingAngle2 > minOpenAngle) { - reinterpret_cast(fMainList->FindObject("Pair")->FindObject("EMCEMC")->FindObject(Form("%s_%s", cut.GetName(), cut.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_Same_RotatedBkg"))->Fill(mother2.M(), mother2.Pt()); - } - } - } - - Filter DalitzEEFilter = o2::aod::dalitzee::sign == 0; // analyze only uls - using MyFilteredDalitzEEs = soa::Filtered; - - Filter DalitzMuMuFilter = o2::aod::dalitzmumu::sign == 0; // analyze only uls - using MyFilteredDalitzMuMus = soa::Filtered; - - Partition grouped_collisions = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); // this goes to same event. - Filter collisionFilter_common = nabs(o2::aod::collision::posZ) < 10.f && o2::aod::collision::numContrib > (uint16_t)0 && o2::aod::evsel::sel8 == true; - Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); - Filter collisionFilter_subsys = (o2::aod::emevent::ngpcm >= 1) || (o2::aod::emevent::ngphos >= 1) || (o2::aod::emevent::ngemc >= 1) || (aod::emevent::neeuls >= 1); - using MyFilteredCollisions = soa::Filtered; // this goes to mixed event. - - void processPCMPCM(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, MyV0Photons const& v0photons, aod::V0Legs const& legs) - { - SameEventPairing(grouped_collisions, v0photons, v0photons, perCollision, perCollision, fPCMCuts, fPCMCuts, fPairCuts, legs, nullptr, nullptr, nullptr); - if (cfgCentEstimator == 0) { - MixedEventPairing(filtered_collisions, v0photons, v0photons, perCollision, perCollision, fPCMCuts, fPCMCuts, fPairCuts, legs, nullptr, nullptr, nullptr, colBinning_M); - } else if (cfgCentEstimator == 1) { - MixedEventPairing(filtered_collisions, v0photons, v0photons, perCollision, perCollision, fPCMCuts, fPCMCuts, fPairCuts, legs, nullptr, nullptr, nullptr, colBinning_A); - } else if (cfgCentEstimator == 2) { - MixedEventPairing(filtered_collisions, v0photons, v0photons, perCollision, perCollision, fPCMCuts, fPCMCuts, fPairCuts, legs, nullptr, nullptr, nullptr, colBinning_C); - } - } - - void processPHOSPHOS(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, aod::PHOSClusters const& phosclusters) - { - SameEventPairing(grouped_collisions, phosclusters, phosclusters, perCollision_phos, perCollision_phos, fPHOSCuts, fPHOSCuts, fPairCuts, nullptr, nullptr, nullptr, nullptr); - MixedEventPairing(filtered_collisions, phosclusters, phosclusters, perCollision_phos, perCollision_phos, fPHOSCuts, fPHOSCuts, fPairCuts, nullptr, nullptr, nullptr, nullptr, colBinning_C); - } - - void processEMCEMC(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, aod::SkimEMCClusters const& emcclusters, aod::SkimEMCMTs const& emcmatchedtracks) - { - SameEventPairing(grouped_collisions, emcclusters, emcclusters, perCollision_emc, perCollision_emc, fEMCCuts, fEMCCuts, fPairCuts, nullptr, nullptr, nullptr, emcmatchedtracks); - MixedEventPairing(filtered_collisions, emcclusters, emcclusters, perCollision_emc, perCollision_emc, fEMCCuts, fEMCCuts, fPairCuts, nullptr, nullptr, nullptr, emcmatchedtracks, colBinning_C); - } - - void processPCMDalitzEE(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, MyV0Photons const& v0photons, aod::V0Legs const& legs, MyFilteredDalitzEEs const& dileptons, MyPrimaryElectrons const& emprimaryelectrons) - { - SameEventPairing(grouped_collisions, v0photons, dileptons, perCollision, perCollision_dalitzee, fPCMCuts, fDalitzEECuts, fPairCuts, legs, emprimaryelectrons, nullptr, nullptr); - if (cfgCentEstimator == 0) { - MixedEventPairing(filtered_collisions, v0photons, dileptons, perCollision, perCollision_dalitzee, fPCMCuts, fDalitzEECuts, fPairCuts, legs, emprimaryelectrons, nullptr, nullptr, colBinning_M); - } else if (cfgCentEstimator == 1) { - MixedEventPairing(filtered_collisions, v0photons, dileptons, perCollision, perCollision_dalitzee, fPCMCuts, fDalitzEECuts, fPairCuts, legs, emprimaryelectrons, nullptr, nullptr, colBinning_A); - } else if (cfgCentEstimator == 2) { - MixedEventPairing(filtered_collisions, v0photons, dileptons, perCollision, perCollision_dalitzee, fPCMCuts, fDalitzEECuts, fPairCuts, legs, emprimaryelectrons, nullptr, nullptr, colBinning_C); - } - } - - void processPCMDalitzMuMu(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, MyV0Photons const& v0photons, aod::V0Legs const& legs, MyFilteredDalitzMuMus const& dileptons, MyPrimaryMuons const& emprimarymuons) - { - SameEventPairing(grouped_collisions, v0photons, dileptons, perCollision, perCollision_dalitzmumu, fPCMCuts, fDalitzMuMuCuts, fPairCuts, legs, nullptr, emprimarymuons, nullptr); - if (cfgCentEstimator == 0) { - MixedEventPairing(filtered_collisions, v0photons, dileptons, perCollision, perCollision_dalitzmumu, fPCMCuts, fDalitzMuMuCuts, fPairCuts, legs, nullptr, emprimarymuons, nullptr, colBinning_M); - } else if (cfgCentEstimator == 1) { - MixedEventPairing(filtered_collisions, v0photons, dileptons, perCollision, perCollision_dalitzmumu, fPCMCuts, fDalitzMuMuCuts, fPairCuts, legs, nullptr, emprimarymuons, nullptr, colBinning_A); - } else if (cfgCentEstimator == 2) { - MixedEventPairing(filtered_collisions, v0photons, dileptons, perCollision, perCollision_dalitzmumu, fPCMCuts, fDalitzMuMuCuts, fPairCuts, legs, nullptr, emprimarymuons, nullptr, colBinning_C); - } - } - - void processPCMPHOS(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, MyV0Photons const& v0photons, aod::PHOSClusters const& phosclusters, aod::V0Legs const& legs) - { - SameEventPairing(grouped_collisions, v0photons, phosclusters, perCollision, perCollision_phos, fPCMCuts, fPHOSCuts, fPairCuts, legs, nullptr, nullptr, nullptr); - MixedEventPairing(filtered_collisions, v0photons, phosclusters, perCollision, perCollision_phos, fPCMCuts, fPHOSCuts, fPairCuts, legs, nullptr, nullptr, nullptr, colBinning_C); - } - - void processPCMEMC(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, MyV0Photons const& v0photons, aod::SkimEMCClusters const& emcclusters, aod::V0Legs const& legs, aod::SkimEMCMTs const& emcmatchedtracks) - { - SameEventPairing(grouped_collisions, v0photons, emcclusters, perCollision, perCollision_emc, fPCMCuts, fEMCCuts, fPairCuts, legs, nullptr, nullptr, emcmatchedtracks); - MixedEventPairing(filtered_collisions, v0photons, emcclusters, perCollision, perCollision_emc, fPCMCuts, fEMCCuts, fPairCuts, legs, nullptr, nullptr, emcmatchedtracks, colBinning_C); - } - - void processPHOSEMC(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, aod::PHOSClusters const& phosclusters, aod::SkimEMCClusters const& emcclusters, aod::SkimEMCMTs const& emcmatchedtracks) - { - SameEventPairing(grouped_collisions, phosclusters, emcclusters, perCollision_phos, perCollision_emc, fPHOSCuts, fEMCCuts, fPairCuts, nullptr, nullptr, nullptr, emcmatchedtracks); - MixedEventPairing(filtered_collisions, phosclusters, emcclusters, perCollision_phos, perCollision_emc, fPHOSCuts, fEMCCuts, fPairCuts, nullptr, nullptr, nullptr, emcmatchedtracks, colBinning_C); - } - - void processDummy(MyCollisions const&) {} - - PROCESS_SWITCH(Pi0EtaToGammaGamma, processPCMPCM, "pairing PCM-PCM", false); - PROCESS_SWITCH(Pi0EtaToGammaGamma, processPHOSPHOS, "pairing PHOS-PHOS", false); - PROCESS_SWITCH(Pi0EtaToGammaGamma, processEMCEMC, "pairing EMCal-EMCal", false); - PROCESS_SWITCH(Pi0EtaToGammaGamma, processPCMPHOS, "pairing PCM-PHOS", false); - PROCESS_SWITCH(Pi0EtaToGammaGamma, processPCMEMC, "pairing PCM-EMCal", false); - PROCESS_SWITCH(Pi0EtaToGammaGamma, processPCMDalitzEE, "pairing PCM-DalitzEE", false); - PROCESS_SWITCH(Pi0EtaToGammaGamma, processPCMDalitzMuMu, "pairing PCM-DalitzMuMu", false); - PROCESS_SWITCH(Pi0EtaToGammaGamma, processPHOSEMC, "pairing PHOS-EMCal", false); - PROCESS_SWITCH(Pi0EtaToGammaGamma, processDummy, "Dummy function", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"pi0eta-to-gammagamma"})}; -} diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaEMCEMC.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaEMCEMC.cxx new file mode 100644 index 00000000000..3b7893f7373 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaEMCEMC.cxx @@ -0,0 +1,37 @@ +// 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. +// +// ======================== +// +// This code loops over photons and makes pairs for neutral mesons analyses. +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h" + +using namespace o2; +using namespace o2::aod; + +using MyEMCClusters = soa::Join; +using MyEMCCluster = MyEMCClusters::iterator; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"pi0eta-to-gammagamma-emcemc"}), + }; +} diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMC.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMC.cxx deleted file mode 100644 index 53373c7af36..00000000000 --- a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMC.cxx +++ /dev/null @@ -1,751 +0,0 @@ -// 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. -// -// ======================== -// -// This code loops over photons and makes pairs for neutral mesons analyses. -// Please write to: daiki.sekihata@cern.ch - -#include "TString.h" -#include "Math/Vector4D.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" - -#include "Common/Core/RecoDecay.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" -#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" -#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" -#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" -#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" -#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" -#include "PWGEM/PhotonMeson/Core/PairCut.h" -#include "PWGEM/PhotonMeson/Core/CutsLibrary.h" -#include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" - -using namespace o2; -using namespace o2::aod; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::soa; -using namespace o2::aod::photonpair; -using namespace o2::aod::pwgem::mcutil; -using namespace o2::aod::pwgem::photon; - -using MyCollisions = soa::Join; -using MyCollision = MyCollisions::iterator; - -using MyV0Photons = soa::Join; -using MyV0Photon = MyV0Photons::iterator; - -using MyDalitzEEs = soa::Join; -using MyDalitzEE = MyDalitzEEs::iterator; - -using MyDalitzMuMus = soa::Join; -using MyDalitzMuMu = MyDalitzMuMus::iterator; - -using MyEMCClusters = soa::Join; -using MyEMCCluster = MyEMCClusters::iterator; - -struct Pi0EtaToGammaGammaMC { - using MyMCV0Legs = soa::Join; - using MyMCElectrons = soa::Join; - using MyMCMuons = soa::Join; - - Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; - Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; - Configurable cfgCentMax{"cfgCentMax", 999, "max. centrality"}; - - Configurable maxY_track{"maxY_track", 0.9, "maximum rapidity for generated particles"}; // for PCM and dielectron - Configurable minPhi_track{"minPhi_track", 0, "minimum azimuthal angle for generated particles"}; // for PCM and dielectron - Configurable maxPhi_track{"maxPhi_track", 2 * M_PI, "maximum azimuthal angle for generated particles"}; // for PCM and dielectron - Configurable maxRgen{"maxRgen", 90.f, "maximum radius for generated particles"}; - Configurable margin_z_mc{"margin_z_mc", 7.0, "margin for z cut in cm for MC"}; - - Configurable maxY_phos{"maxY_phos", 0.9, "maximum rapidity for generated particles"}; // for EMC - Configurable minPhi_phos{"minPhi_phos", 3 / 2 * M_PI, "minimum azimuthal angle for generated particles"}; // for PCM and dielectron - Configurable maxPhi_phos{"maxPhi_phos", 2 * M_PI, "maximum azimuthal angle for generated particles"}; // for PCM and dielectron - - Configurable maxY_emc{"maxY_emc", 0.9, "maximum rapidity for generated particles"}; // for EMC - Configurable minPhi_emc{"minPhi_emc", M_PI / 2., "minimum azimuthal angle for generated particles"}; // for PCM and dielectron - Configurable maxPhi_emc{"maxPhi_emc", M_PI, "maximum azimuthal angle for generated particles"}; // for PCM and dielectron - - Configurable fConfigPCMCuts{"cfgPCMCuts", "qc,nocut", "Comma separated list of V0 photon cuts"}; - Configurable fConfigDalitzEECuts{"cfgDalitzEECuts", "mee_0_120_tpchadrejortofreq_lowB,mee_120_500_tpchadrejortofreq_lowB,mee_0_500_tpchadrejortofreq_lowB", "Comma separated list of Dalitz ee cuts"}; - Configurable fConfigDalitzMuMuCuts{"cfgDalitzMuMuCuts", "mmumu_0_500_tpctof_lowB", "Comma separated list of Dalitz mumu cuts"}; - Configurable fConfigEMCCuts{"cfgEMCCuts", "custom,standard,nocut", "Comma separated list of EMCal photon cuts"}; - - // Configurable for EMCal cuts - Configurable requireCaloReadout{"requireCaloReadout", true, "Require calorimeters readout when analyzing EMCal/PHOS"}; - Configurable EMC_minTime{"EMC_minTime", -20., "Minimum cluster time for EMCal time cut"}; - Configurable EMC_maxTime{"EMC_maxTime", +25., "Maximum cluster time for EMCal time cut"}; - Configurable EMC_minM02{"EMC_minM02", 0.1, "Minimum M02 for EMCal M02 cut"}; - Configurable EMC_maxM02{"EMC_maxM02", 0.7, "Maximum M02 for EMCal M02 cut"}; - Configurable EMC_minE{"EMC_minE", 0.7, "Minimum cluster energy for EMCal energy cut"}; - Configurable EMC_minNCell{"EMC_minNCell", 1, "Minimum number of cells per cluster for EMCal NCell cut"}; - Configurable> EMC_TM_Eta{"EMC_TM_Eta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; - Configurable> EMC_TM_Phi{"EMC_TM_Phi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; - Configurable EMC_Eoverp{"EMC_Eoverp", 1.75, "Minimum cluster energy over track momentum for EMCal track matching"}; - Configurable EMC_UseExoticCut{"EMC_UseExoticCut", true, "FLag to use the EMCal exotic cluster cut"}; - - Configurable fConfigPairCuts{"cfgPairCuts", "nocut,asym08", "Comma separated list of pair cuts"}; - - Configurable fConfigEMEventCut{"cfgEMEventCut", "minbias", "em event cut"}; // only 1 event cut per wagon - EMEventCut fEMEventCut; - static constexpr std::string_view event_types[2] = {"before", "after"}; - - OutputObj fOutputEvent{"Event"}; - OutputObj fOutputPair{"Pair"}; // 2-photon pair - OutputObj fOutputGen{"Generated"}; - THashList* fMainList = new THashList(); - - std::vector fPCMCuts; - std::vector fDalitzEECuts; - std::vector fDalitzMuMuCuts; - std::vector fPHOSCuts; - std::vector fEMCCuts; - std::vector fPairCuts; - - std::vector fPairNames; - void init(InitContext& context) - { - if (context.mOptions.get("processPCMPCM")) { - fPairNames.push_back("PCMPCM"); - } - if (context.mOptions.get("processPHOSPHOS")) { - fPairNames.push_back("PHOSPHOS"); - } - if (context.mOptions.get("processEMCEMC")) { - fPairNames.push_back("EMCEMC"); - } - if (context.mOptions.get("processPCMPHOS")) { - fPairNames.push_back("PCMPHOS"); - } - if (context.mOptions.get("processPCMEMC")) { - fPairNames.push_back("PCMEMC"); - } - if (context.mOptions.get("processPCMDalitzEE")) { - fPairNames.push_back("PCMDalitzEE"); - } - if (context.mOptions.get("processPCMDalitzMuMu")) { - fPairNames.push_back("PCMDalitzMuMu"); - } - if (context.mOptions.get("processPHOSEMC")) { - fPairNames.push_back("PHOSEMC"); - } - - DefinePCMCuts(); - DefineDalitzEECuts(); - DefineDalitzMuMuCuts(); - DefineEMCCuts(); - DefinePairCuts(); - addhistograms(); - TString ev_cut_name = fConfigEMEventCut.value; - fEMEventCut = *eventcuts::GetCut(ev_cut_name.Data()); - - fOutputEvent.setObject(reinterpret_cast(fMainList->FindObject("Event"))); - fOutputPair.setObject(reinterpret_cast(fMainList->FindObject("Pair"))); - fOutputGen.setObject(reinterpret_cast(fMainList->FindObject("Generated"))); - } - - template - void add_pair_histograms(THashList* list_pair, const std::string pairname, TCuts1 const& cuts1, TCuts2 const& cuts2, TCuts3 const& cuts3) - { - for (auto& cut1 : cuts1) { - for (auto& cut2 : cuts2) { - std::string cutname1 = cut1.GetName(); - std::string cutname2 = cut2.GetName(); - - if ((pairname == "PCMPCM" || pairname == "PHOSPHOS" || pairname == "EMCEMC") && (cutname1 != cutname2)) - continue; - - THashList* list_pair_subsys = reinterpret_cast(list_pair->FindObject(pairname.data())); - std::string photon_cut_name = cutname1 + "_" + cutname2; - o2::aod::pwgem::photon::histogram::AddHistClass(list_pair_subsys, photon_cut_name.data()); - THashList* list_pair_subsys_photoncut = reinterpret_cast(list_pair_subsys->FindObject(photon_cut_name.data())); - - for (auto& cut3 : cuts3) { - std::string pair_cut_name = cut3.GetName(); - o2::aod::pwgem::photon::histogram::AddHistClass(list_pair_subsys_photoncut, pair_cut_name.data()); - THashList* list_pair_subsys_paircut = reinterpret_cast(list_pair_subsys_photoncut->FindObject(pair_cut_name.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_pair_subsys_paircut, "gammagamma_mass_pt_mc"); - } // end of cut3 loop - } // end of cut2 loop - } // end of cut1 loop - } - - static constexpr std::string_view pairnames[9] = {"PCMPCM", "PHOSPHOS", "EMCEMC", "PCMPHOS", "PCMEMC", "PCMDalitzEE", "PCMDalitzMuMu", "PHOSEMC", "DalitzEEDalitzEE"}; - - void addhistograms() - { - fMainList->SetOwner(true); - fMainList->SetName("fMainList"); - - // create sub lists first. - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Event"); - THashList* list_ev = reinterpret_cast(fMainList->FindObject("Event")); - - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Pair"); - THashList* list_pair = reinterpret_cast(fMainList->FindObject("Pair")); - - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Generated"); - THashList* list_gen = reinterpret_cast(fMainList->FindObject("Generated")); - - for (auto& pairname : fPairNames) { - LOGF(info, "Enabled pairs = %s", pairname.data()); - - // for events - THashList* list_ev_pair = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_ev, pairname.data())); - for (const auto& evtype : event_types) { - THashList* list_ev_type = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_ev_pair, evtype.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_ev_type, "Event", evtype.data()); - } - - // for generated particles - THashList* list_gen_pair = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_gen, pairname.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_gen_pair, "Generated", "Pi0Eta"); - - // for truely reconstructed particles - o2::aod::pwgem::photon::histogram::AddHistClass(list_pair, pairname.data()); - if (pairname == "PCMPCM") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fPCMCuts, fPairCuts); - } - if (pairname == "PHOSPHOS") { - add_pair_histograms(list_pair, pairname, fPHOSCuts, fPHOSCuts, fPairCuts); - } - if (pairname == "EMCEMC") { - add_pair_histograms(list_pair, pairname, fEMCCuts, fEMCCuts, fPairCuts); - } - if (pairname == "PCMPHOS") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fPHOSCuts, fPairCuts); - } - if (pairname == "PCMEMC") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fEMCCuts, fPairCuts); - } - if (pairname == "PCMDalitzEE") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fDalitzEECuts, fPairCuts); - } - if (pairname == "PCMDalitzMuMu") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fDalitzMuMuCuts, fPairCuts); - } - if (pairname == "PHOSEMC") { - add_pair_histograms(list_pair, pairname, fPHOSCuts, fEMCCuts, fPairCuts); - } - - } // end of pair name loop - } - - void DefinePCMCuts() - { - TString cutNamesStr = fConfigPCMCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fPCMCuts.push_back(*pcmcuts::GetCut(cutname)); - } - } - LOGF(info, "Number of PCM cuts = %d", fPCMCuts.size()); - } - - void DefineDalitzEECuts() - { - TString cutNamesStr = fConfigDalitzEECuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fDalitzEECuts.push_back(*dalitzeecuts::GetCut(cutname)); - } - } - LOGF(info, "Number of DalitzEE cuts = %d", fDalitzEECuts.size()); - } - - void DefineDalitzMuMuCuts() - { - TString cutNamesStr = fConfigDalitzMuMuCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fDalitzMuMuCuts.push_back(*dalitzeecuts::GetCut(cutname)); - } - } - LOGF(info, "Number of DalitzMuMu cuts = %d", fDalitzMuMuCuts.size()); - } - - void DefineEMCCuts() - { - const float a = EMC_TM_Eta->at(0); - const float b = EMC_TM_Eta->at(1); - const float c = EMC_TM_Eta->at(2); - - const float d = EMC_TM_Phi->at(0); - const float e = EMC_TM_Phi->at(1); - const float f = EMC_TM_Phi->at(2); - LOGF(info, "EMCal track matching parameters : a = %f, b = %f, c = %f, d = %f, e = %f, f = %f", a, b, c, d, e, f); - - TString cutNamesStr = fConfigEMCCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - if (std::strcmp(cutname, "custom") == 0) { - EMCPhotonCut* custom_cut = new EMCPhotonCut(cutname, cutname); - custom_cut->SetMinE(EMC_minE); - custom_cut->SetMinNCell(EMC_minNCell); - custom_cut->SetM02Range(EMC_minM02, EMC_maxM02); - custom_cut->SetTimeRange(EMC_minTime, EMC_maxTime); - - custom_cut->SetTrackMatchingEta([&a, &b, &c](float pT) { - return a + pow(pT + b, c); - }); - custom_cut->SetTrackMatchingPhi([&d, &e, &f](float pT) { - return d + pow(pT + e, f); - }); - - custom_cut->SetMinEoverP(EMC_Eoverp); - custom_cut->SetUseExoticCut(EMC_UseExoticCut); - fEMCCuts.push_back(*custom_cut); - } else { - fEMCCuts.push_back(*emccuts::GetCut(cutname)); - } - } - } - LOGF(info, "Number of EMCal cuts = %d", fEMCCuts.size()); - } - - void DefinePairCuts() - { - TString cutNamesStr = fConfigPairCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fPairCuts.push_back(*paircuts::GetCut(cutname)); - } - } - LOGF(info, "Number of Pair cuts = %d", fPairCuts.size()); - } - - template - bool IsSelectedPair(TG1 const& g1, TG2 const& g2, TCut1 const& cut1, TCut2 const& cut2) - { - bool is_selected_pair = false; - if constexpr (pairtype == PairType::kPCMPCM) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPHOSPHOS) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); // dummy, because track matching is not ready. - } else if constexpr (pairtype == PairType::kEMCEMC) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPCMPHOS) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPCMEMC) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPCMDalitzEE) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPCMDalitzMuMu) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPHOSEMC) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else { - is_selected_pair = true; - } - return is_selected_pair; - } - - template - bool IsInAcceptance(TMCParticle const& mcparticle, TMCParticles const& mcparticles) - { - if (pairtype == PairType::kPCMPCM) { - return o2::aod::pwgem::mcutil::IsInAcceptance(mcparticle, mcparticles, std::vector{22, 22}, -maxY_track, +maxY_track, minPhi_track, maxPhi_track); - } else if (pairtype == PairType::kPCMDalitzEE) { - return o2::aod::pwgem::mcutil::IsInAcceptance(mcparticle, mcparticles, std::vector{-11, 11, 22}, -maxY_track, +maxY_track, minPhi_track, maxPhi_track); - } else if (pairtype == PairType::kPCMDalitzMuMu) { - return o2::aod::pwgem::mcutil::IsInAcceptance(mcparticle, mcparticles, std::vector{-13, 13, 22}, -maxY_track, +maxY_track, minPhi_track, maxPhi_track); - } else if (pairtype == PairType::kPHOSPHOS) { - return o2::aod::pwgem::mcutil::IsInAcceptance(mcparticle, mcparticles, std::vector{-13, 13, 22}, -maxY_phos, +maxY_phos, minPhi_phos, maxPhi_phos); - } else if (pairtype == PairType::kEMCEMC) { - return o2::aod::pwgem::mcutil::IsInAcceptance(mcparticle, mcparticles, std::vector{22, 22}, -maxY_emc, +maxY_emc, minPhi_emc, maxPhi_emc); - } - return true; - } - - Preslice perCollision_pcm = aod::v0photonkf::emeventId; - Preslice perCollision_dalitzee = aod::dalitzee::emeventId; - Preslice perCollision_dalitzmumu = aod::dalitzmumu::emeventId; - Preslice perCollision_emc = aod::emccluster::emeventId; - - template - void TruePairing(TEvents const& collisions, TPhotons1 const& photons1, TPhotons2 const& photons2, TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, TCuts1 const& cuts1, TCuts2 const& cuts2, TPairCuts const& paircuts, TV0Legs const& /*v0legs*/, TEMPrimaryElectrons const& /*emprimaryelectrons*/, TEMPrimaryMuons const& /*emprimarymuons*/, TMCEvents const& /*mcevents*/, TMCParticles const& mcparticles) - { - THashList* list_ev_pair_before = static_cast(fMainList->FindObject("Event")->FindObject(pairnames[pairtype].data())->FindObject(event_types[0].data())); - THashList* list_ev_pair_after = static_cast(fMainList->FindObject("Event")->FindObject(pairnames[pairtype].data())->FindObject(event_types[1].data())); - THashList* list_pair_ss = static_cast(fMainList->FindObject("Pair")->FindObject(pairnames[pairtype].data())); - - for (auto& collision : collisions) { - - if ((pairtype == kPHOSPHOS || pairtype == kPCMPHOS) && !collision.alias_bit(triggerAliases::kTVXinPHOS)) { - continue; - } - if ((pairtype == kEMCEMC || pairtype == kPCMEMC) && ((!collision.alias_bit(triggerAliases::kTVXinEMC) && requireCaloReadout) || collision.ncollsPerBC() != 1)) { - continue; - } - - float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { - continue; - } - - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_pair_before, "", collision); - if (!fEMEventCut.IsSelected(collision)) { - continue; - } - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_pair_after, "", collision); - reinterpret_cast(list_ev_pair_before->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - reinterpret_cast(list_ev_pair_after->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - - auto photons1_coll = photons1.sliceBy(perCollision1, collision.globalIndex()); - auto photons2_coll = photons2.sliceBy(perCollision2, collision.globalIndex()); - - int pi0id = -1; - int etaid = -1; - if constexpr (pairtype == PairType::kPCMPCM || pairtype == PairType::kPHOSPHOS || pairtype == PairType::kEMCEMC) { - for (auto& cut : cuts1) { - for (auto& paircut : paircuts) { - for (auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photons1_coll, photons2_coll))) { - if (!IsSelectedPair(g1, g2, cut, cut)) { - continue; - } - if (!paircut.IsSelected(g1, g2)) { - continue; - } - - int photonid1 = -1; - int photonid2 = -1; - if constexpr (pairtype == PairType::kPCMPCM) { // check 2 legs - auto pos1 = g1.template posTrack_as(); - auto ele1 = g1.template negTrack_as(); - auto pos2 = g2.template posTrack_as(); - auto ele2 = g2.template negTrack_as(); - - auto pos1mc = pos1.template emmcparticle_as(); - auto ele1mc = ele1.template emmcparticle_as(); - auto pos2mc = pos2.template emmcparticle_as(); - auto ele2mc = ele2.template emmcparticle_as(); - // LOGF(info,"pos1mc.globalIndex() = %d , ele1mc.globalIndex() = %d , pos2mc.globalIndex() = %d , ele2mc.globalIndex() = %d", pos1mc.globalIndex(), ele1mc.globalIndex(), pos2mc.globalIndex(), ele2mc.globalIndex()); - - photonid1 = FindCommonMotherFrom2Prongs(pos1mc, ele1mc, -11, 11, 22, mcparticles); - photonid2 = FindCommonMotherFrom2Prongs(pos2mc, ele2mc, -11, 11, 22, mcparticles); - } else if constexpr (pairtype == PairType::kEMCEMC) { - auto cluster1mcparticle = mcparticles.iteratorAt(g1.emmcparticleId()); - auto cluster2mcparticle = mcparticles.iteratorAt(g2.emmcparticleId()); - - photonid1 = FindMotherInChain(cluster1mcparticle, mcparticles, std::vector{111, 221}); - photonid2 = FindMotherInChain(cluster2mcparticle, mcparticles, std::vector{111, 221}); - } - - if (photonid1 < 0 || photonid2 < 0) { - continue; - } - auto g1mc = mcparticles.iteratorAt(photonid1); - auto g2mc = mcparticles.iteratorAt(photonid2); - - pi0id = FindCommonMotherFrom2Prongs(g1mc, g2mc, 22, 22, 111, mcparticles); - etaid = FindCommonMotherFrom2Prongs(g1mc, g2mc, 22, 22, 221, mcparticles); - - if (pi0id < 0 && etaid < 0) { - continue; - } - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - if (abs(v12.Rapidity()) > maxY_track) { - continue; - } - - if (pi0id > 0) { - auto pi0mc = mcparticles.iteratorAt(pi0id); - if (pi0mc.isPhysicalPrimary() || pi0mc.producedByGenerator()) { - if constexpr (pairtype == PairType::kPCMPCM) { - if (!IsConversionPointInAcceptance(g1mc, maxRgen, maxY_track, margin_z_mc, mcparticles) || !IsConversionPointInAcceptance(g2mc, maxRgen, maxY_track, margin_z_mc, mcparticles)) { - continue; - } - } - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut.GetName(), cut.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_Pi0_Primary"))->Fill(v12.M(), v12.Pt()); - } else if (IsFromWD(pi0mc.emmcevent(), pi0mc, mcparticles)) { - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut.GetName(), cut.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_Pi0_FromWD"))->Fill(v12.M(), v12.Pt()); - } - } else if (etaid > 0) { - auto etamc = mcparticles.iteratorAt(etaid); - if (etamc.isPhysicalPrimary() || etamc.producedByGenerator()) { - if constexpr (pairtype == PairType::kPCMPCM) { - if (!IsConversionPointInAcceptance(g1mc, maxRgen, maxY_track, margin_z_mc, mcparticles) || !IsConversionPointInAcceptance(g2mc, maxRgen, maxY_track, margin_z_mc, mcparticles)) { - continue; - } - } - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut.GetName(), cut.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_Eta_Primary"))->Fill(v12.M(), v12.Pt()); - } - } - } // end of combination - } // end of paircutloop - } // end of cut loop - - } else { // different subsystem pairs - for (auto& cut1 : cuts1) { - for (auto& cut2 : cuts2) { - for (auto& paircut : paircuts) { - for (auto& [g1, g2] : combinations(CombinationsFullIndexPolicy(photons1_coll, photons2_coll))) { - if (!IsSelectedPair(g1, g2, cut1, cut2)) { - continue; - } - if (!paircut.IsSelected(g1, g2)) { - continue; - } - - int photonid1 = -1; - int photonid2 = -1; - - if constexpr (pairtype == PairType::kPCMPHOS || pairtype == PairType::kPCMEMC) { - auto pos = g1.template posTrack_as(); - auto ele = g1.template negTrack_as(); - if constexpr (pairtype == PairType::kPCMPHOS) { - if (o2::aod::photonpair::DoesV0LegMatchWithCluster(pos, g2, 0.02, 0.4, 0.2) || o2::aod::photonpair::DoesV0LegMatchWithCluster(ele, g2, 0.02, 0.4, 0.2)) { - continue; - } - } else if constexpr (pairtype == PairType::kPCMEMC) { - if (o2::aod::photonpair::DoesV0LegMatchWithCluster(pos, g2, 0.02, 0.4, 0.5) || o2::aod::photonpair::DoesV0LegMatchWithCluster(ele, g2, 0.02, 0.4, 0.5)) { - continue; - } - } - } else if constexpr (pairtype == PairType::kPCMDalitzEE) { // check 4 legs - auto pos1 = g1.template posTrack_as(); - auto ele1 = g1.template negTrack_as(); - auto pos2 = g2.template posTrack_as(); - auto ele2 = g2.template negTrack_as(); - if (pos1.trackId() == pos2.trackId() || ele1.trackId() == ele2.trackId()) { - continue; - } - - auto pos1mc = pos1.template emmcparticle_as(); - auto ele1mc = ele1.template emmcparticle_as(); - auto pos2mc = pos2.template emmcparticle_as(); - auto ele2mc = ele2.template emmcparticle_as(); - // LOGF(info,"pos1mc.globalIndex() = %d , ele1mc.globalIndex() = %d , pos2mc.globalIndex() = %d , ele2mc.globalIndex() = %d", pos1mc.globalIndex(), ele1mc.globalIndex(), pos2mc.globalIndex(), ele2mc.globalIndex()); - - photonid1 = FindCommonMotherFrom2Prongs(pos1mc, ele1mc, -11, 11, 22, mcparticles); // real photon - if (photonid1 < 0) { - continue; - } - auto g1mc = mcparticles.iteratorAt(photonid1); - - if (cut2.IsPhotonConversionSelected()) { // v0photon + photon conversion on ITSib stored in dielectron table. pi0 -> gamma gamma - photonid2 = FindCommonMotherFrom2Prongs(pos2mc, ele2mc, -11, 11, 22, mcparticles); // photon conversion stored in dielectron table - if (photonid2 < 0) { - continue; - } - auto g2mc = mcparticles.iteratorAt(photonid2); - pi0id = FindCommonMotherFrom2Prongs(g1mc, g2mc, 22, 22, 111, mcparticles); - etaid = FindCommonMotherFrom2Prongs(g1mc, g2mc, 22, 22, 221, mcparticles); - } else { // pi0/eta -> ee gamma, dalitz decay - pi0id = FindCommonMotherFrom3Prongs(g1mc, pos2mc, ele2mc, 22, -11, 11, 111, mcparticles); - etaid = FindCommonMotherFrom3Prongs(g1mc, pos2mc, ele2mc, 22, -11, 11, 221, mcparticles); - } - } else if constexpr (pairtype == PairType::kPCMDalitzMuMu) { // check 4 legs - auto pos1 = g1.template posTrack_as(); - auto ele1 = g1.template negTrack_as(); - auto pos2 = g2.template posTrack_as(); - auto ele2 = g2.template negTrack_as(); - if (pos1.trackId() == pos2.trackId() || ele1.trackId() == ele2.trackId()) { - continue; - } - - auto pos1mc = pos1.template emmcparticle_as(); - auto ele1mc = ele1.template emmcparticle_as(); - auto pos2mc = pos2.template emmcparticle_as(); - auto ele2mc = ele2.template emmcparticle_as(); - // LOGF(info,"pos1mc.globalIndex() = %d , ele1mc.globalIndex() = %d , pos2mc.globalIndex() = %d , ele2mc.globalIndex() = %d", pos1mc.globalIndex(), ele1mc.globalIndex(), pos2mc.globalIndex(), ele2mc.globalIndex()); - - photonid1 = FindCommonMotherFrom2Prongs(pos1mc, ele1mc, -11, 11, 22, mcparticles); // real photon - if (photonid1 < 0) { - continue; - } - auto g1mc = mcparticles.iteratorAt(photonid1); - pi0id = -1; - etaid = FindCommonMotherFrom3Prongs(g1mc, pos2mc, ele2mc, 22, -13, 13, 221, mcparticles); - } - - if (pi0id < 0 && etaid < 0) { - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); - if constexpr (pairtype == PairType::kPCMDalitzEE || pairtype == PairType::kPCMDalitzMuMu) { - v2.SetM(g2.mass()); - } - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - if (abs(v12.Rapidity()) > maxY_track) { - continue; - } - if (pi0id > 0) { - auto pi0mc = mcparticles.iteratorAt(pi0id); - if (pi0mc.isPhysicalPrimary() || pi0mc.producedByGenerator()) { - if constexpr (pairtype == PairType::kPCMDalitzEE || pairtype == kPCMDalitzMuMu) { - auto g1mc = mcparticles.iteratorAt(photonid1); - if (!IsConversionPointInAcceptance(g1mc, maxRgen, maxY_track, margin_z_mc, mcparticles)) { - continue; - } - } - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_Pi0_Primary"))->Fill(v12.M(), v12.Pt()); - } else if (IsFromWD(pi0mc.emmcevent(), pi0mc, mcparticles)) { - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_Pi0_FromWD"))->Fill(v12.M(), v12.Pt()); - } - } else if (etaid > 0) { - auto etamc = mcparticles.iteratorAt(etaid); - if (etamc.isPhysicalPrimary() || etamc.producedByGenerator()) { - if constexpr (pairtype == PairType::kPCMDalitzEE || pairtype == kPCMDalitzMuMu) { - auto g1mc = mcparticles.iteratorAt(photonid1); - if (!IsConversionPointInAcceptance(g1mc, maxRgen, maxY_track, margin_z_mc, mcparticles)) { - continue; - } - } - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_Eta_Primary"))->Fill(v12.M(), v12.Pt()); - } - } - - } // end of combination - } // end of paircutloop - } // end of cut2 loop - } // end of cut1 loop - } - - } // end of collision loop - } - - PresliceUnsorted perMcCollision = aod::emmcparticle::emmceventId; - PresliceUnsorted rec_perMcCollision = aod::emmceventlabel::emmceventId; - - template - void runGenInfo(TCollisions const& collisions, TMCCollisions const& mccollisions, TMCParticles const& mcparticles) - { - THashList* list_gen_pair = static_cast(fMainList->FindObject("Generated")->FindObject(pairnames[pairtype].data())); - // loop over mc stack and fill histograms for pure MC truth signals - // all MC tracks which belong to the MC event corresponding to the current reconstructed event - for (auto& mccollision : mccollisions) { - auto collision_per_mccoll = collisions.sliceBy(rec_perMcCollision, mccollision.globalIndex()); - int nrec_per_mc = collision_per_mccoll.size(); - reinterpret_cast(list_gen_pair->FindObject("hNrecPerMCCollision"))->Fill(nrec_per_mc); // all - } - - for (auto& collision : collisions) { - if ((pairtype == kPHOSPHOS || pairtype == kPCMPHOS) && !collision.alias_bit(triggerAliases::kTVXinPHOS)) { - continue; // I don't know why this is necessary in simulation. - } - if ((pairtype == kEMCEMC || pairtype == kPCMEMC) && ((!collision.alias_bit(triggerAliases::kTVXinEMC) && requireCaloReadout) || collision.ncollsPerBC() != 1)) { - continue; // I don't know why this is necessary in simulation. - } - - float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { - continue; - } - - if (!fEMEventCut.IsSelected(collision)) { - continue; - } - - auto mccollision = collision.emmcevent(); - auto mctracks_coll = mcparticles.sliceBy(perMcCollision, mccollision.globalIndex()); - for (auto& mctrack : mctracks_coll) { - if (abs(mctrack.y()) > maxY_track) { - continue; - } - int pdg = mctrack.pdgCode(); - - if (abs(pdg) == 111 && (mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { - reinterpret_cast(list_gen_pair->FindObject("hPt_Pi0"))->Fill(mctrack.pt()); - reinterpret_cast(list_gen_pair->FindObject("hY_Pi0"))->Fill(mctrack.y()); - reinterpret_cast(list_gen_pair->FindObject("hPhi_Pi0"))->Fill(mctrack.phi()); - if (IsInAcceptance(mctrack, mcparticles)) { - reinterpret_cast(list_gen_pair->FindObject("hPt_Pi0_Acc"))->Fill(mctrack.pt()); - reinterpret_cast(list_gen_pair->FindObject("hY_Pi0_Acc"))->Fill(mctrack.y()); - reinterpret_cast(list_gen_pair->FindObject("hPhi_Pi0_Acc"))->Fill(mctrack.phi()); - } - } else if (abs(pdg) == 221 && (mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { - reinterpret_cast(list_gen_pair->FindObject("hPt_Eta"))->Fill(mctrack.pt()); - reinterpret_cast(list_gen_pair->FindObject("hY_Eta"))->Fill(mctrack.y()); - reinterpret_cast(list_gen_pair->FindObject("hPhi_Eta"))->Fill(mctrack.phi()); - if (IsInAcceptance(mctrack, mcparticles)) { - reinterpret_cast(list_gen_pair->FindObject("hPt_Eta_Acc"))->Fill(mctrack.pt()); - reinterpret_cast(list_gen_pair->FindObject("hY_Eta_Acc"))->Fill(mctrack.y()); - reinterpret_cast(list_gen_pair->FindObject("hPhi_Eta_Acc"))->Fill(mctrack.phi()); - } - } - } // end of mc track loop - } // end of collision loop - } - - Partition grouped_collisions = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); // this goes to same event. - - void processPCMPCM(MyCollisions const&, MyV0Photons const& v0photons, MyMCV0Legs const& v0legs, aod::EMMCEvents const& mccollisions, aod::EMMCParticles const& mcparticles) - { - TruePairing(grouped_collisions, v0photons, v0photons, perCollision_pcm, perCollision_pcm, fPCMCuts, fPCMCuts, fPairCuts, v0legs, nullptr, nullptr, mccollisions, mcparticles); - runGenInfo(grouped_collisions, mccollisions, mcparticles); - } - void processPHOSPHOS(MyCollisions const&) {} - void processEMCEMC(MyCollisions const&, MyEMCClusters const& emcclusters, aod::EMMCEvents const& mccollisions, aod::EMMCParticles const& mcparticles) - { - TruePairing(grouped_collisions, emcclusters, emcclusters, perCollision_emc, perCollision_emc, fEMCCuts, fEMCCuts, fPairCuts, nullptr, nullptr, nullptr, mccollisions, mcparticles); - runGenInfo(grouped_collisions, mccollisions, mcparticles); - } - void processPCMPHOS(MyCollisions const&) {} - void processPCMEMC(MyCollisions const&) {} - - void processPCMDalitzEE(MyCollisions const&, MyV0Photons const& v0photons, MyMCV0Legs const& v0legs, MyDalitzEEs const& dileptons, MyMCElectrons const& emprimaryelectrons, aod::EMMCEvents const& mccollisions, aod::EMMCParticles const& mcparticles) - { - TruePairing(grouped_collisions, v0photons, dileptons, perCollision_pcm, perCollision_dalitzee, fPCMCuts, fDalitzEECuts, fPairCuts, v0legs, emprimaryelectrons, nullptr, mccollisions, mcparticles); - runGenInfo(grouped_collisions, mccollisions, mcparticles); - } - - void processPCMDalitzMuMu(MyCollisions const&, MyV0Photons const& v0photons, MyMCV0Legs const& v0legs, MyDalitzMuMus const& dileptons, MyMCMuons const& emprimarymuons, aod::EMMCEvents const& mccollisions, aod::EMMCParticles const& mcparticles) - { - TruePairing(grouped_collisions, v0photons, dileptons, perCollision_pcm, perCollision_dalitzmumu, fPCMCuts, fDalitzMuMuCuts, fPairCuts, v0legs, nullptr, emprimarymuons, mccollisions, mcparticles); - runGenInfo(grouped_collisions, mccollisions, mcparticles); - } - - void processPHOSEMC(MyCollisions const&) {} - - void processDummy(MyCollisions const&) {} - - PROCESS_SWITCH(Pi0EtaToGammaGammaMC, processPCMPCM, "true pairing PCM-PCM", false); - PROCESS_SWITCH(Pi0EtaToGammaGammaMC, processPHOSPHOS, "true pairing PHOS-PHOS", false); - PROCESS_SWITCH(Pi0EtaToGammaGammaMC, processEMCEMC, "true pairing EMC-EMC", false); - PROCESS_SWITCH(Pi0EtaToGammaGammaMC, processPCMPHOS, "true pairing PCM-PHOS", false); - PROCESS_SWITCH(Pi0EtaToGammaGammaMC, processPCMEMC, "true pairing PCM-EMC", false); - PROCESS_SWITCH(Pi0EtaToGammaGammaMC, processPCMDalitzEE, "true pairing PCM-DalitzEE", false); - PROCESS_SWITCH(Pi0EtaToGammaGammaMC, processPCMDalitzMuMu, "true pairing PCM-DalitzMuMu", false); - PROCESS_SWITCH(Pi0EtaToGammaGammaMC, processPHOSEMC, "true pairing PHOS-EMC", false); - PROCESS_SWITCH(Pi0EtaToGammaGammaMC, processDummy, "Dummy function", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"pi0eta-to-gammagamma-mc"})}; -} diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCEMCEMC.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCEMCEMC.cxx new file mode 100644 index 00000000000..7cd7ba3c492 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCEMCEMC.cxx @@ -0,0 +1,37 @@ +// 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. +// +// ======================== +// +// This code loops over photons and makes pairs for neutral mesons analyses. +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h" + +using namespace o2; +using namespace o2::aod; + +using MyEMCClusters = soa::Join; +using MyEMCCluster = MyEMCClusters::iterator; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"pi0eta-to-gammagamma-mc-emcemc"}), + }; +} diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMDalitzEE.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMDalitzEE.cxx new file mode 100644 index 00000000000..2d929f1a82a --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMDalitzEE.cxx @@ -0,0 +1,43 @@ +// 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. +// +// ======================== +// +// This code loops over photons and makes pairs for neutral mesons analyses. +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h" + +using namespace o2; +using namespace o2::aod; + +// using MyV0Photons = soa::Join; +// using MyV0Photon = MyV0Photons::iterator; +// +// using MyMCV0Legs = soa::Join; +// using MyMCV0Leg = MyMCV0Legs::iterator; +// +// using MyMCElectrons = soa::Join; +// using MyMCElectron = MyMCElectrons::iterator; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"pi0eta-to-gammagamma-mc-pcmdalitzee"}), + }; +} diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMPCM.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMPCM.cxx new file mode 100644 index 00000000000..9b79891739c --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMPCM.cxx @@ -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. +// +// ======================== +// +// This code loops over photons and makes pairs for neutral mesons analyses. +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h" + +using namespace o2; +using namespace o2::aod; + +// using MyV0Photons = soa::Join; +// using MyV0Photon = MyV0Photons::iterator; + +// using MyMCV0Legs = soa::Join; +// using MyMCV0Leg = MyMCV0Legs::iterator; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"pi0eta-to-gammagamma-mc-pcmpcm"}), + }; +} diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMDalitzEE.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMDalitzEE.cxx new file mode 100644 index 00000000000..15ccbe72bd4 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMDalitzEE.cxx @@ -0,0 +1,35 @@ +// 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. +// +// ======================== +// +// This code loops over photons and makes pairs for neutral mesons analyses. +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#include "Common/Core/RecoDecay.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h" + +using namespace o2; +using namespace o2::aod; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"pi0eta-to-gammagamma-pcmdalitzee"}), + }; +} diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCM.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCM.cxx new file mode 100644 index 00000000000..24557c828a7 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCM.cxx @@ -0,0 +1,37 @@ +// 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. +// +// ======================== +// +// This code loops over photons and makes pairs for neutral mesons analyses. +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h" + +using namespace o2; +using namespace o2::aod; + +// using MyV0Photons = soa::Join; +// using MyV0Photon = MyV0Photons::iterator; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"pi0eta-to-gammagamma-pcmpcm"}), + }; +} diff --git a/PWGEM/PhotonMeson/Tasks/SinglePhoton.cxx b/PWGEM/PhotonMeson/Tasks/SinglePhoton.cxx index 6f8d87a1fd3..9c82fa7b09a 100644 --- a/PWGEM/PhotonMeson/Tasks/SinglePhoton.cxx +++ b/PWGEM/PhotonMeson/Tasks/SinglePhoton.cxx @@ -82,7 +82,7 @@ struct SinglePhoton { Configurable EMC_UseExoticCut{"EMC_UseExoticCut", true, "FLag to use the EMCal exotic cluster cut"}; Configurable fConfigEMEventCut{"cfgEMEventCut", "minbias", "em event cut"}; // only 1 event cut per wagon - EMEventCut fEMEventCut; + EMPhotonEventCut fEMEventCut; static constexpr std::string_view event_types[2] = {"before", "after"}; OutputObj fOutputEvent{"Event"}; @@ -228,10 +228,10 @@ struct SinglePhoton { custom_cut->SetM02Range(EMC_minM02, EMC_maxM02); custom_cut->SetTimeRange(EMC_minTime, EMC_maxTime); - custom_cut->SetTrackMatchingEta([&a, &b, &c](float pT) { + custom_cut->SetTrackMatchingEta([a, b, c](float pT) { return a + pow(pT + b, c); }); - custom_cut->SetTrackMatchingPhi([&d, &e, &f](float pT) { + custom_cut->SetTrackMatchingPhi([d, e, f](float pT) { return d + pow(pT + e, f); }); @@ -306,7 +306,7 @@ struct SinglePhoton { std::array q2ft0m = {collision.q2xft0m(), collision.q2yft0m()}; std::array q2ft0a = {collision.q2xft0a(), collision.q2yft0a()}; std::array q2ft0c = {collision.q2xft0c(), collision.q2yft0c()}; - std::array q2fv0a = {collision.q2xfv0a(), collision.q2yfv0a()}; + // std::array q2fv0a = {collision.q2xfv0a(), collision.q2yfv0a()}; auto photons1_coll = photons1.sliceBy(perCollision1, collision.globalIndex()); for (auto& cut : cuts1) { @@ -323,7 +323,7 @@ struct SinglePhoton { reinterpret_cast(list_photon_det_cut->FindObject("hPt_SPQ2FT0M"))->Fill(photon.pt(), RecoDecay::dotProd(u2_photon, q2ft0m)); reinterpret_cast(list_photon_det_cut->FindObject("hPt_SPQ2FT0A"))->Fill(photon.pt(), RecoDecay::dotProd(u2_photon, q2ft0a)); reinterpret_cast(list_photon_det_cut->FindObject("hPt_SPQ2FT0C"))->Fill(photon.pt(), RecoDecay::dotProd(u2_photon, q2ft0c)); - reinterpret_cast(list_photon_det_cut->FindObject("hPt_SPQ2FV0A"))->Fill(photon.pt(), RecoDecay::dotProd(u2_photon, q2fv0a)); + // reinterpret_cast(list_photon_det_cut->FindObject("hPt_SPQ2FV0A"))->Fill(photon.pt(), RecoDecay::dotProd(u2_photon, q2fv0a)); } else { reinterpret_cast(list_photon_det_cut->FindObject("hPt"))->Fill(photon.pt()); } @@ -331,8 +331,8 @@ struct SinglePhoton { reinterpret_cast(list_photon_det_cut->FindObject("hY"))->Fill(photon.eta()); reinterpret_cast(list_photon_det_cut->FindObject("hPhi"))->Fill(photon.phi()); } // end of photon loop - } // end of cut loop - } // end of collision loop + } // end of cut loop + } // end of collision loop } Partition grouped_collisions = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); // this goes to same event. diff --git a/PWGEM/PhotonMeson/Tasks/SinglePhotonMC.cxx b/PWGEM/PhotonMeson/Tasks/SinglePhotonMC.cxx index 0d1e32e8d77..ccb33db7f3a 100644 --- a/PWGEM/PhotonMeson/Tasks/SinglePhotonMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/SinglePhotonMC.cxx @@ -39,13 +39,15 @@ #include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" #include "PWGEM/PhotonMeson/Core/CutsLibrary.h" #include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; -using namespace o2::aod::pwgem::mcutil; +using namespace o2::aod::pwgem::photonmeson::utils::mcutil; +using namespace o2::aod::pwgem::dilepton::utils::mcutil; using namespace o2::aod::pwgem::photon; using MyCollisions = soa::Join; @@ -88,7 +90,7 @@ struct SinglePhotonMC { // Configurable EMC_UseExoticCut{"EMC_UseExoticCut", true, "FLag to use the EMCal exotic cluster cut"}; Configurable fConfigEMEventCut{"cfgEMEventCut", "minbias", "em event cut"}; // only 1 event cut per wagon - EMEventCut fEMEventCut; + EMPhotonEventCut fEMEventCut; static constexpr std::string_view event_types[2] = {"before", "after"}; OutputObj fOutputEvent{"Event"}; @@ -338,7 +340,7 @@ struct SinglePhotonMC { reinterpret_cast(list_photon_det_cut->FindObject("hPt_Photon_Primary"))->Fill(photon.pt()); reinterpret_cast(list_photon_det_cut->FindObject("hY_Photon_Primary"))->Fill(photon.eta()); reinterpret_cast(list_photon_det_cut->FindObject("hPhi_Photon_Primary"))->Fill(photon.phi()); - } else if (IsFromWD(mcphoton.emmcevent(), mcphoton, mcparticles)) { + } else if (IsFromWD(mcphoton.emmcevent(), mcphoton, mcparticles) > 0) { reinterpret_cast(list_photon_det_cut->FindObject("hPt_Photon_FromWD"))->Fill(photon.pt()); reinterpret_cast(list_photon_det_cut->FindObject("hY_Photon_FromWD"))->Fill(photon.eta()); reinterpret_cast(list_photon_det_cut->FindObject("hPhi_Photon_FromWD"))->Fill(photon.phi()); diff --git a/PWGEM/PhotonMeson/Tasks/TagAndProbe.cxx b/PWGEM/PhotonMeson/Tasks/TagAndProbe.cxx index d41c4d744da..2f91a62dc43 100644 --- a/PWGEM/PhotonMeson/Tasks/TagAndProbe.cxx +++ b/PWGEM/PhotonMeson/Tasks/TagAndProbe.cxx @@ -42,10 +42,10 @@ using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; -using namespace o2::aod::photonpair; +using namespace o2::aod::pwgem::photonmeson::photonpair; using namespace o2::aod::pwgem::photon; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyV0Photons = soa::Join; @@ -69,7 +69,7 @@ struct TagAndProbe { Configurable minOpenAngle{"minOpenAngle", 0.0202, "apply min opening angle"}; Configurable fConfigEMEventCut{"cfgEMEventCut", "minbias", "em event cut"}; // only 1 event cut per wagon - EMEventCut fEMEventCut; + EMPhotonEventCut fEMEventCut; static constexpr std::string_view event_types[2] = {"before", "after"}; OutputObj fOutputEvent{"Event"}; @@ -341,8 +341,6 @@ struct TagAndProbe { for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, ndepth, -1, collisions, collisions)) { // internally, CombinationsStrictlyUpperIndexPolicy(collisions, collisions) is called. - // LOGF(info, "Mixed event globalIndex: (%d, %d) , ngpcm: (%d, %d), ngphos: (%d, %d), ngemc: (%d, %d)", collision1.globalIndex(), collision2.globalIndex(), collision1.ngpcm(), collision2.ngpcm(), collision1.ngphos(), collision2.ngphos(), collision1.ngemc(), collision2.ngemc()); - const float centralities1[3] = {collision1.centFT0M(), collision1.centFT0A(), collision1.centFT0C()}; const float centralities2[3] = {collision2.centFT0M(), collision2.centFT0A(), collision2.centFT0C()}; @@ -478,7 +476,6 @@ struct TagAndProbe { Partition grouped_collisions = cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax; // this goes to same event. Filter collisionFilter_common = nabs(o2::aod::collision::posZ) < 10.f && o2::aod::collision::numContrib > (uint16_t)0 && o2::aod::evsel::sel8 == true; Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); - Filter collisionFilter_subsys = (o2::aod::emevent::ngpcm >= 1) || (o2::aod::emevent::ngphos >= 1) || (o2::aod::emevent::ngemc >= 1); using MyFilteredCollisions = soa::Filtered; // this goes to mixed event. void processPCMPCM(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, MyV0Photons const& v0photons, aod::V0Legs const& legs) diff --git a/PWGEM/PhotonMeson/Tasks/TaggingPi0.cxx b/PWGEM/PhotonMeson/Tasks/TaggingPi0.cxx deleted file mode 100644 index 7aced38cb7d..00000000000 --- a/PWGEM/PhotonMeson/Tasks/TaggingPi0.cxx +++ /dev/null @@ -1,503 +0,0 @@ -// 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. -// -// ======================== -// -// This code runs loop over photons with PCM and PHOS for direct photon analysis. -// Please write to: daiki.sekihata@cern.ch - -#include -#include - -#include "TString.h" -#include "Math/Vector4D.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Common/Core/RecoDecay.h" -#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" -#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" -#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" -#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" -#include "PWGEM/PhotonMeson/Core/PairCut.h" -#include "PWGEM/PhotonMeson/Core/CutsLibrary.h" -#include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" - -using namespace o2; -using namespace o2::aod; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::soa; -using namespace o2::aod::photonpair; -using namespace o2::aod::pwgem::photon; - -using MyCollisions = soa::Join; -using MyCollision = MyCollisions::iterator; - -using MyV0Photons = soa::Join; -using MyV0Photon = MyV0Photons::iterator; - -using MyDalitzEEs = soa::Join; -using MyDalitzEE = MyDalitzEEs::iterator; - -using MyPrimaryElectrons = soa::Join; -using MyPrimaryElectron = MyPrimaryElectrons::iterator; - -struct TaggingPi0 { - - Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; - Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; - Configurable cfgCentMax{"cfgCentMax", 999, "max. centrality"}; - - // Configurable maxY{"maxY", 0.9, "maximum rapidity for reconstructed particles"}; - Configurable fConfigPCMCuts{"cfgPCMCuts", "qc", "Comma separated list of V0 photon cuts"}; - Configurable fConfigDalitzEECuts{"cfgDalitzEECuts", "mee_0_120_tpchadrejortofreq,mee_0_120_tpchadrejortofreq_lowB", "Comma separated list of Dalitz ee cuts"}; - Configurable fConfigPHOSCuts{"cfgPHOSCuts", "test02,test03", "Comma separated list of PHOS photon cuts"}; - Configurable fConfigEMCCuts{"cfgEMCCuts", "standard", "Comma separated list of EMCal photon cuts"}; - Configurable fConfigPairCuts{"cfgPairCuts", "nocut", "Comma separated list of pair cuts"}; - - // Configurable for EMCal cuts - Configurable EMC_minTime{"EMC_minTime", -20., "Minimum cluster time for EMCal time cut"}; - Configurable EMC_maxTime{"EMC_maxTime", +25., "Maximum cluster time for EMCal time cut"}; - Configurable EMC_minM02{"EMC_minM02", 0.1, "Minimum M02 for EMCal M02 cut"}; - Configurable EMC_maxM02{"EMC_maxM02", 0.7, "Maximum M02 for EMCal M02 cut"}; - Configurable EMC_minE{"EMC_minE", 0.7, "Minimum cluster energy for EMCal energy cut"}; - Configurable EMC_minNCell{"EMC_minNCell", 1, "Minimum number of cells per cluster for EMCal NCell cut"}; - Configurable> EMC_TM_Eta{"EMC_TM_Eta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; - Configurable> EMC_TM_Phi{"EMC_TM_Phi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; - Configurable EMC_Eoverp{"EMC_Eoverp", 1.75, "Minimum cluster energy over track momentum for EMCal track matching"}; - Configurable EMC_UseExoticCut{"EMC_UseExoticCut", true, "FLag to use the EMCal exotic cluster cut"}; - - Configurable fConfigEMEventCut{"cfgEMEventCut", "minbias", "em event cut"}; // only 1 event cut per wagon - EMEventCut fEMEventCut; - static constexpr std::string_view event_types[2] = {"before", "after"}; - - OutputObj fOutputEvent{"Event"}; - OutputObj fOutputPair{"Pair"}; // 2-photon pair - THashList* fMainList = new THashList(); - - std::vector fPCMCuts; - std::vector fDalitzEECuts; - std::vector fPHOSCuts; - std::vector fEMCCuts; - std::vector fPairCuts; - - std::vector fPairNames; - void init(InitContext& context) - { - if (context.mOptions.get("processPCMDalitzEE")) { - fPairNames.push_back("PCMDalitzEE"); - } - if (context.mOptions.get("processPCMPHOS")) { - fPairNames.push_back("PCMPHOS"); - } - if (context.mOptions.get("processPCMEMC")) { - fPairNames.push_back("PCMEMC"); - } - - DefinePCMCuts(); - DefineDalitzEECuts(); - DefinePHOSCuts(); - DefineEMCCuts(); - DefinePairCuts(); - addhistograms(); - TString ev_cut_name = fConfigEMEventCut.value; - fEMEventCut = *eventcuts::GetCut(ev_cut_name.Data()); - - fOutputEvent.setObject(reinterpret_cast(fMainList->FindObject("Event"))); - fOutputPair.setObject(reinterpret_cast(fMainList->FindObject("Pair"))); - } - - template - void add_pair_histograms(THashList* list_pair, const std::string pairname, TCuts1 const& cuts1, TCuts2 const& cuts2, TCuts3 const& cuts3) - { - for (auto& cut1 : cuts1) { - for (auto& cut2 : cuts2) { - std::string cutname1 = cut1.GetName(); - std::string cutname2 = cut2.GetName(); - - if ((pairname == "PCMPCM" || pairname == "PHOSPHOS" || pairname == "EMCEMC") && (cutname1 != cutname2)) - continue; - - THashList* list_pair_subsys = reinterpret_cast(list_pair->FindObject(pairname.data())); - std::string photon_cut_name = cutname1 + "_" + cutname2; - o2::aod::pwgem::photon::histogram::AddHistClass(list_pair_subsys, photon_cut_name.data()); - THashList* list_pair_subsys_photoncut = reinterpret_cast(list_pair_subsys->FindObject(photon_cut_name.data())); - - for (auto& cut3 : cuts3) { - std::string pair_cut_name = cut3.GetName(); - o2::aod::pwgem::photon::histogram::AddHistClass(list_pair_subsys_photoncut, pair_cut_name.data()); - THashList* list_pair_subsys_paircut = reinterpret_cast(list_pair_subsys_photoncut->FindObject(pair_cut_name.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_pair_subsys_paircut, "tagging_pi0"); - } // end of cut3 loop - } // end of cut2 loop - } // end of cut1 loop - } - - static constexpr std::string_view pairnames[9] = {"PCMPCM", "PHOSPHOS", "EMCEMC", "PCMPHOS", "PCMEMC", "PCMDalitzEE", "PCMDalitzMuMu", "PHOSEMC", "DalitzEEDalitzEE"}; - void addhistograms() - { - fMainList->SetOwner(true); - fMainList->SetName("fMainList"); - - // create sub lists first. - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Event"); - THashList* list_ev = reinterpret_cast(fMainList->FindObject("Event")); - - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Pair"); - THashList* list_pair = reinterpret_cast(fMainList->FindObject("Pair")); - - for (auto& pairname : fPairNames) { - LOGF(info, "Enabled pairs = %s", pairname.data()); - - THashList* list_ev_pair = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_ev, pairname.data())); - for (const auto& evtype : event_types) { - THashList* list_ev_type = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_ev_pair, evtype.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_ev_type, "Event", evtype.data()); - } - - o2::aod::pwgem::photon::histogram::AddHistClass(list_pair, pairname.data()); - - if (pairname == "PCMPHOS") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fPHOSCuts, fPairCuts); - } - if (pairname == "PCMEMC") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fEMCCuts, fPairCuts); - } - if (pairname == "PCMDalitzEE") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fDalitzEECuts, fPairCuts); - } - - } // end of pair name loop - } - - void DefinePCMCuts() - { - TString cutNamesStr = fConfigPCMCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fPCMCuts.push_back(*pcmcuts::GetCut(cutname)); - } - } - LOGF(info, "Number of PCM cuts = %d", fPCMCuts.size()); - } - - void DefineDalitzEECuts() - { - TString cutNamesStr = fConfigDalitzEECuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fDalitzEECuts.push_back(*dalitzeecuts::GetCut(cutname)); - } - } - LOGF(info, "Number of DalitzEE cuts = %d", fDalitzEECuts.size()); - } - - void DefinePHOSCuts() - { - TString cutNamesStr = fConfigPHOSCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fPHOSCuts.push_back(*phoscuts::GetCut(cutname)); - } - } - LOGF(info, "Number of PHOS cuts = %d", fPHOSCuts.size()); - } - - void DefineEMCCuts() - { - const float a = EMC_TM_Eta->at(0); - const float b = EMC_TM_Eta->at(1); - const float c = EMC_TM_Eta->at(2); - - const float d = EMC_TM_Phi->at(0); - const float e = EMC_TM_Phi->at(1); - const float f = EMC_TM_Phi->at(2); - LOGF(info, "EMCal track matching parameters : a = %f, b = %f, c = %f, d = %f, e = %f, f = %f", a, b, c, d, e, f); - - TString cutNamesStr = fConfigEMCCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - if (std::strcmp(cutname, "custom") == 0) { - EMCPhotonCut* custom_cut = new EMCPhotonCut(cutname, cutname); - custom_cut->SetMinE(EMC_minE); - custom_cut->SetMinNCell(EMC_minNCell); - custom_cut->SetM02Range(EMC_minM02, EMC_maxM02); - custom_cut->SetTimeRange(EMC_minTime, EMC_maxTime); - - custom_cut->SetTrackMatchingEta([&a, &b, &c](float pT) { - return a + pow(pT + b, c); - }); - custom_cut->SetTrackMatchingPhi([&d, &e, &f](float pT) { - return d + pow(pT + e, f); - }); - - custom_cut->SetMinEoverP(EMC_Eoverp); - custom_cut->SetUseExoticCut(EMC_UseExoticCut); - fEMCCuts.push_back(*custom_cut); - } else { - fEMCCuts.push_back(*emccuts::GetCut(cutname)); - } - } - } - LOGF(info, "Number of EMCal cuts = %d", fEMCCuts.size()); - } - - void DefinePairCuts() - { - TString cutNamesStr = fConfigPairCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fPairCuts.push_back(*paircuts::GetCut(cutname)); - } - } - LOGF(info, "Number of Pair cuts = %d", fPairCuts.size()); - } - - template - bool IsSelectedPair(TG1 const& g1, TG2 const& g2, TCut1 const& cut1, TCut2 const& cut2) - { - bool is_selected_pair = false; - if constexpr (pairtype == PairType::kPCMPHOS) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPCMEMC) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPCMDalitzEE) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else { - is_selected_pair = true; - } - return is_selected_pair; - } - - template - void SameEventPairing(TEvents const& collisions, TPhotons1 const& photons1, TPhotons2 const& photons2, TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, TCuts1 const& cuts1, TCuts2 const& cuts2, TPairCuts const& paircuts, TLegs const& /*legs*/, TEMPrimaryElectrons const& /*emprimaryelectrons*/) - { - THashList* list_ev_pair_before = static_cast(fMainList->FindObject("Event")->FindObject(pairnames[pairtype].data())->FindObject(event_types[0].data())); - THashList* list_ev_pair_after = static_cast(fMainList->FindObject("Event")->FindObject(pairnames[pairtype].data())->FindObject(event_types[1].data())); - THashList* list_pair_ss = static_cast(fMainList->FindObject("Pair")->FindObject(pairnames[pairtype].data())); - - for (auto& collision : collisions) { - - if ((pairtype == kPHOSPHOS || pairtype == kPCMPHOS) && !collision.alias_bit(triggerAliases::kTVXinPHOS)) { - continue; - } - if ((pairtype == kEMCEMC || pairtype == kPCMEMC) && !collision.alias_bit(triggerAliases::kTVXinEMC)) { - continue; - } - - const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { - continue; - } - - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_pair_before, "", collision); - if (!fEMEventCut.IsSelected(collision)) { - continue; - } - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_pair_after, "", collision); - reinterpret_cast(list_ev_pair_before->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - reinterpret_cast(list_ev_pair_after->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - - auto photons1_coll = photons1.sliceBy(perCollision1, collision.globalIndex()); - auto photons2_coll = photons2.sliceBy(perCollision2, collision.globalIndex()); - - for (auto& cut1 : cuts1) { - for (auto& cut2 : cuts2) { - for (auto& paircut : paircuts) { - for (auto& [g1, g2] : combinations(CombinationsFullIndexPolicy(photons1_coll, photons2_coll))) { - if (!IsSelectedPair(g1, g2, cut1, cut2)) { - continue; - } - - if (!paircut.IsSelected(g1, g2)) { - continue; - } - - if constexpr (pairtype == PairType::kPCMPHOS || pairtype == PairType::kPCMEMC) { - auto pos = g1.template posTrack_as(); - auto ele = g1.template negTrack_as(); - if constexpr (pairtype == PairType::kPCMPHOS) { - if (o2::aod::photonpair::DoesV0LegMatchWithCluster(pos, g2, 0.02, 0.4, 0.2) || o2::aod::photonpair::DoesV0LegMatchWithCluster(ele, g2, 0.02, 0.4, 0.2)) { - continue; - } - } else if constexpr (pairtype == PairType::kPCMEMC) { - if (o2::aod::photonpair::DoesV0LegMatchWithCluster(pos, g2, 0.02, 0.4, 0.5) || o2::aod::photonpair::DoesV0LegMatchWithCluster(ele, g2, 0.02, 0.4, 0.5)) { - continue; - } - } - } - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); // pcm - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); // phos or emc or dalitzee - if constexpr (pairtype == PairType::kPCMDalitzEE) { - v2.SetM(g2.mass()); - } - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - // if (abs(v12.Rapidity()) > maxY) { - // continue; - // } - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_Same"))->Fill(v12.M(), v1.Pt()); - } // end of combination - } // end of pair cut loop - } // end of cut2 loop - } // end of cut1 loop - } // end of collision loop - } - - Configurable ndepth{"ndepth", 10, "depth for event mixing"}; - ConfigurableAxis ConfVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - ConfigurableAxis ConfCentBins{"ConfCentBins", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 999.f}, "Mixing bins - centrality"}; - using BinningType_M = ColumnBinningPolicy; - using BinningType_A = ColumnBinningPolicy; - using BinningType_C = ColumnBinningPolicy; - BinningType_M colBinning_M{{ConfVtxBins, ConfCentBins}, true}; - BinningType_A colBinning_A{{ConfVtxBins, ConfCentBins}, true}; - BinningType_C colBinning_C{{ConfVtxBins, ConfCentBins}, true}; - - template - void MixedEventPairing(TEvents const& collisions, TPhotons1 const& photons1, TPhotons2 const& photons2, TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, TCuts1 const& cuts1, TCuts2 const& cuts2, TPairCuts const& paircuts, TLegs const& /*legs*/, TEMPrimaryElectrons const& /*emprimaryelectrons*/, TMixedBinning const& colBinning) - { - THashList* list_pair_ss = static_cast(fMainList->FindObject("Pair")->FindObject(pairnames[pairtype].data())); - - // LOGF(info, "Number of collisions after filtering: %d", collisions.size()); - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, ndepth, -1, collisions, collisions)) { // internally, CombinationsStrictlyUpperIndexPolicy(collisions, collisions) is called. - - // LOGF(info, "Mixed event globalIndex: (%d, %d) , counter = %d, ngpcm: (%d, %d), ngphos: (%d, %d), ngemc: (%d, %d)", - // collision1.globalIndex(), collision2.globalIndex(), nev, collision1.ngpcm(), collision2.ngpcm(), collision1.ngphos(), collision2.ngphos(), collision1.ngemc(), collision2.ngemc()); - - const float centralities1[3] = {collision1.centFT0M(), collision1.centFT0A(), collision1.centFT0C()}; - const float centralities2[3] = {collision2.centFT0M(), collision2.centFT0A(), collision2.centFT0C()}; - - if (centralities1[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities1[cfgCentEstimator]) { - continue; - } - if (centralities2[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities2[cfgCentEstimator]) { - continue; - } - if (!fEMEventCut.IsSelected(collision1) || !fEMEventCut.IsSelected(collision2)) { - continue; - } - - auto photons_coll1 = photons1.sliceBy(perCollision1, collision1.globalIndex()); - auto photons_coll2 = photons2.sliceBy(perCollision2, collision2.globalIndex()); - // LOGF(info, "collision1: posZ = %f, numContrib = %d , sel8 = %d | collision2: posZ = %f, numContrib = %d , sel8 = %d", - // collision1.posZ(), collision1.numContrib(), collision1.sel8(), collision2.posZ(), collision2.numContrib(), collision2.sel8()); - - for (auto& cut1 : cuts1) { - for (auto& cut2 : cuts2) { - for (auto& paircut : paircuts) { - for (auto& [g1, g2] : combinations(soa::CombinationsFullIndexPolicy(photons_coll1, photons_coll2))) { - // LOGF(info, "Mixed event photon pair: (%d, %d) from events (%d, %d), photon event: (%d, %d)", g1.index(), g2.index(), collision1.index(), collision2.index(), g1.globalIndex(), g2.globalIndex()); - - if ((pairtype == PairType::kPCMPCM || pairtype == PairType::kPHOSPHOS || pairtype == PairType::kEMCEMC) && (TString(cut1.GetName()) != TString(cut2.GetName()))) { - continue; - } - if (!IsSelectedPair(g1, g2, cut1, cut2)) { - continue; - } - if (!paircut.IsSelected(g1, g2)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); // pcm - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); // phos or emc or dalitzee - if constexpr (pairtype == PairType::kPCMDalitzEE) { - v2.SetM(g2.mass()); - auto pos_sv = g1.template posTrack_as(); - auto ele_sv = g1.template negTrack_as(); - auto pos_pv = g2.template posTrack_as(); - auto ele_pv = g2.template negTrack_as(); - if (pos_sv.trackId() == pos_pv.trackId() || ele_sv.trackId() == ele_pv.trackId()) { - continue; - } - } - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - // if (abs(v12.Rapidity()) > maxY) { - // continue; - // } - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_Mixed"))->Fill(v12.M(), v1.Pt()); - - } // end of different photon combinations - } // end of pair cut loop - } // end of cut2 loop - } // end of cut1 loop - } // end of different collision combinations - } - - Partition grouped_collisions = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); // this goes to same event. - Filter collisionFilter_common = nabs(o2::aod::collision::posZ) < 10.f && o2::aod::collision::numContrib > (uint16_t)0 && o2::aod::evsel::sel8 == true; - Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); - Filter collisionFilter_subsys = (o2::aod::emevent::ngpcm >= 1) || (o2::aod::emevent::ngphos >= 1) || (o2::aod::emevent::ngemc >= 1) || (o2::aod::emevent::neeuls >= 1); - using MyFilteredCollisions = soa::Filtered; - - Filter DalitzEEFilter = o2::aod::dalitzee::sign == 0; // analyze only uls - using MyFilteredDalitzEEs = soa::Filtered; - - Preslice perCollision_pcm = aod::v0photonkf::emeventId; - Preslice perCollision_dalitz = aod::dalitzee::emeventId; - Preslice perCollision_phos = aod::skimmedcluster::collisionId; - Preslice perCollision_emc = aod::skimmedcluster::collisionId; - - void processPCMDalitzEE(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, MyV0Photons const& v0photons, aod::V0Legs const& legs, MyFilteredDalitzEEs const& dielectrons, MyPrimaryElectrons const& emprimaryelectrons) - { - SameEventPairing(grouped_collisions, v0photons, dielectrons, perCollision_pcm, perCollision_dalitz, fPCMCuts, fDalitzEECuts, fPairCuts, legs, emprimaryelectrons); - if (cfgCentEstimator == 0) { - MixedEventPairing(filtered_collisions, v0photons, dielectrons, perCollision_pcm, perCollision_dalitz, fPCMCuts, fDalitzEECuts, fPairCuts, legs, emprimaryelectrons, colBinning_M); - } else if (cfgCentEstimator == 1) { - MixedEventPairing(filtered_collisions, v0photons, dielectrons, perCollision_pcm, perCollision_dalitz, fPCMCuts, fDalitzEECuts, fPairCuts, legs, emprimaryelectrons, colBinning_A); - } else if (cfgCentEstimator == 2) { - MixedEventPairing(filtered_collisions, v0photons, dielectrons, perCollision_pcm, perCollision_dalitz, fPCMCuts, fDalitzEECuts, fPairCuts, legs, emprimaryelectrons, colBinning_C); - } - } - - void processPCMPHOS(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, MyV0Photons const& v0photons, aod::PHOSClusters const& phosclusters, aod::V0Legs const& legs) - { - SameEventPairing(grouped_collisions, v0photons, phosclusters, perCollision_pcm, perCollision_phos, fPCMCuts, fPHOSCuts, fPairCuts, legs, nullptr); - MixedEventPairing(filtered_collisions, v0photons, phosclusters, perCollision_pcm, perCollision_phos, fPCMCuts, fPHOSCuts, fPairCuts, legs, nullptr, colBinning_C); - } - - void processPCMEMC(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, MyV0Photons const& v0photons, aod::SkimEMCClusters const& emcclusters, aod::V0Legs const& legs) - { - SameEventPairing(grouped_collisions, v0photons, emcclusters, perCollision_pcm, perCollision_emc, fPCMCuts, fEMCCuts, fPairCuts, legs, nullptr); - MixedEventPairing(filtered_collisions, v0photons, emcclusters, perCollision_pcm, perCollision_emc, fPCMCuts, fEMCCuts, fPairCuts, legs, nullptr, colBinning_C); - } - - void processDummy(MyCollisions const&) {} - - PROCESS_SWITCH(TaggingPi0, processPCMDalitzEE, "pairing PCM-Dalitz", false); - PROCESS_SWITCH(TaggingPi0, processPCMPHOS, "pairing PCM-PHOS", false); - PROCESS_SWITCH(TaggingPi0, processPCMEMC, "pairing PCM-EMCal", false); - PROCESS_SWITCH(TaggingPi0, processDummy, "Dummy function", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"tagging-pi0"})}; -} diff --git a/PWGEM/PhotonMeson/Tasks/TaggingPi0MC.cxx b/PWGEM/PhotonMeson/Tasks/TaggingPi0MC.cxx deleted file mode 100644 index 3e247e64c2b..00000000000 --- a/PWGEM/PhotonMeson/Tasks/TaggingPi0MC.cxx +++ /dev/null @@ -1,507 +0,0 @@ -// 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. -// -// ======================== -// -// This code runs loop over photons with PCM and PHOS for direct photon analysis. -// Please write to: daiki.sekihata@cern.ch - -#include -#include - -#include "TString.h" -#include "Math/Vector4D.h" - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" - -#include "Common/Core/RecoDecay.h" -#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" -#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" -#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" -#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" -#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" -#include "PWGEM/PhotonMeson/Core/PairCut.h" -#include "PWGEM/PhotonMeson/Core/CutsLibrary.h" -#include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" - -using namespace o2; -using namespace o2::aod; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::soa; -using namespace o2::aod::photonpair; -using namespace o2::aod::pwgem::mcutil; -using namespace o2::aod::pwgem::photon; - -using MyCollisions = soa::Join; -using MyCollision = MyCollisions::iterator; - -using MyV0Photons = soa::Join; -using MyV0Photon = MyV0Photons::iterator; - -using MyDalitzEEs = soa::Join; -using MyDalitzEE = MyDalitzEEs::iterator; - -struct TaggingPi0MC { - using MyMCV0Legs = soa::Join; - using MyMCTracks = soa::Join; - - Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; - Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; - Configurable cfgCentMax{"cfgCentMax", 999, "max. centrality"}; - - Configurable maxY{"maxY", 0.9, "maximum rapidity for reconstructed particles"}; - Configurable maxRgen{"maxRgen", 90.f, "maximum radius for generated particles"}; - Configurable margin_z_mc{"margin_z_mc", 7.0, "margin for z cut in cm for MC"}; - - Configurable fConfigPCMCuts{"cfgPCMCuts", "qc", "Comma separated list of V0 photon cuts"}; - Configurable fConfigDalitzEECuts{"cfgDalitzEECuts", "mee_0_120_tpchadrejortofreq,mee_0_120_tpchadrejortofreq_lowB", "Comma separated list of Dalitz ee cuts"}; - Configurable fConfigPHOSCuts{"cfgPHOSCuts", "test02,test03", "Comma separated list of PHOS photon cuts"}; - Configurable fConfigEMCCuts{"fConfigEMCCuts", "standard", "Comma separated list of EMCal photon cuts"}; - Configurable fConfigPairCuts{"cfgPairCuts", "nocut", "Comma separated list of pair cuts"}; - - // Configurable for EMCal cuts - Configurable EMC_minTime{"EMC_minTime", -20., "Minimum cluster time for EMCal time cut"}; - Configurable EMC_maxTime{"EMC_maxTime", +25., "Maximum cluster time for EMCal time cut"}; - Configurable EMC_minM02{"EMC_minM02", 0.1, "Minimum M02 for EMCal M02 cut"}; - Configurable EMC_maxM02{"EMC_maxM02", 0.7, "Maximum M02 for EMCal M02 cut"}; - Configurable EMC_minE{"EMC_minE", 0.7, "Minimum cluster energy for EMCal energy cut"}; - Configurable EMC_minNCell{"EMC_minNCell", 1, "Minimum number of cells per cluster for EMCal NCell cut"}; - Configurable> EMC_TM_Eta{"EMC_TM_Eta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; - Configurable> EMC_TM_Phi{"EMC_TM_Phi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; - Configurable EMC_Eoverp{"EMC_Eoverp", 1.75, "Minimum cluster energy over track momentum for EMCal track matching"}; - Configurable EMC_UseExoticCut{"EMC_UseExoticCut", true, "FLag to use the EMCal exotic cluster cut"}; - - Configurable fConfigEMEventCut{"cfgEMEventCut", "minbias", "em event cut"}; // only 1 event cut per wagon - EMEventCut fEMEventCut; - static constexpr std::string_view event_types[2] = {"before", "after"}; - - OutputObj fOutputEvent{"Event"}; - OutputObj fOutputPair{"Pair"}; // 2-photon pair - OutputObj fOutputPCM{"PCM"}; // v0-photon - THashList* fMainList = new THashList(); - - std::vector fPCMCuts; - std::vector fDalitzEECuts; - std::vector fPHOSCuts; - std::vector fEMCCuts; - std::vector fPairCuts; - - std::vector fPairNames; - void init(InitContext& context) - { - if (context.mOptions.get("processPCMDalitzEE")) { - fPairNames.push_back("PCMDalitzEE"); - } - if (context.mOptions.get("processPCMPHOS")) { - fPairNames.push_back("PCMPHOS"); - } - if (context.mOptions.get("processPCMEMC")) { - fPairNames.push_back("PCMEMC"); - } - - DefinePCMCuts(); - DefineDalitzEECuts(); - DefinePHOSCuts(); - DefineEMCCuts(); - DefinePairCuts(); - addhistograms(); - TString ev_cut_name = fConfigEMEventCut.value; - fEMEventCut = *eventcuts::GetCut(ev_cut_name.Data()); - - fOutputEvent.setObject(reinterpret_cast(fMainList->FindObject("Event"))); - fOutputPair.setObject(reinterpret_cast(fMainList->FindObject("Pair"))); - fOutputPCM.setObject(reinterpret_cast(fMainList->FindObject("PCM"))); - } - - template - void add_pair_histograms(THashList* list_pair, const std::string pairname, TCuts1 const& cuts1, TCuts2 const& cuts2, TCuts3 const& cuts3) - { - for (auto& cut1 : cuts1) { - for (auto& cut2 : cuts2) { - std::string cutname1 = cut1.GetName(); - std::string cutname2 = cut2.GetName(); - - if ((pairname == "PCMPCM" || pairname == "PHOSPHOS" || pairname == "EMCEMC") && (cutname1 != cutname2)) - continue; - - THashList* list_pair_subsys = reinterpret_cast(list_pair->FindObject(pairname.data())); - std::string photon_cut_name = cutname1 + "_" + cutname2; - o2::aod::pwgem::photon::histogram::AddHistClass(list_pair_subsys, photon_cut_name.data()); - THashList* list_pair_subsys_photoncut = reinterpret_cast(list_pair_subsys->FindObject(photon_cut_name.data())); - - for (auto& cut3 : cuts3) { - std::string pair_cut_name = cut3.GetName(); - o2::aod::pwgem::photon::histogram::AddHistClass(list_pair_subsys_photoncut, pair_cut_name.data()); - THashList* list_pair_subsys_paircut = reinterpret_cast(list_pair_subsys_photoncut->FindObject(pair_cut_name.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_pair_subsys_paircut, "tagging_pi0_mc", "pair"); - } // end of pair cut loop - } // end of cut2 loop - } // end of cut1 loop - } - - static constexpr std::string_view pairnames[9] = {"PCMPCM", "PHOSPHOS", "EMCEMC", "PCMPHOS", "PCMEMC", "PCMDalitzEE", "PCMDalitzMuMu", "PHOSEMC", "DalitzEEDalitzEE"}; - void addhistograms() - { - fMainList->SetOwner(true); - fMainList->SetName("fMainList"); - - // create sub lists first. - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Event"); - THashList* list_ev = reinterpret_cast(fMainList->FindObject("Event")); - - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "PCM"); - THashList* list_pcm = reinterpret_cast(fMainList->FindObject("PCM")); - for (auto& cut : fPCMCuts) { - THashList* list_pcm_cut = o2::aod::pwgem::photon::histogram::AddHistClass(list_pcm, cut.GetName()); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_pcm_cut, "tagging_pi0_mc", "pcm"); - } - - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Pair"); - THashList* list_pair = reinterpret_cast(fMainList->FindObject("Pair")); - - for (auto& pairname : fPairNames) { - LOGF(info, "Enabled pairs = %s", pairname.data()); - - THashList* list_ev_pair = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_ev, pairname.data())); - for (const auto& evtype : event_types) { - THashList* list_ev_type = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_ev_pair, evtype.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_ev_type, "Event", evtype.data()); - } - - o2::aod::pwgem::photon::histogram::AddHistClass(list_pair, pairname.data()); - - if (pairname == "PCMDalitzEE") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fDalitzEECuts, fPairCuts); - } - if (pairname == "PCMPHOS") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fPHOSCuts, fPairCuts); - } - if (pairname == "PCMEMC") { - add_pair_histograms(list_pair, pairname, fPCMCuts, fEMCCuts, fPairCuts); - } - - } // end of pair name loop - } - - void DefinePCMCuts() - { - TString cutNamesStr = fConfigPCMCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fPCMCuts.push_back(*pcmcuts::GetCut(cutname)); - } - } - LOGF(info, "Number of PCM cuts = %d", fPCMCuts.size()); - } - - void DefineDalitzEECuts() - { - TString cutNamesStr = fConfigDalitzEECuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fDalitzEECuts.push_back(*dalitzeecuts::GetCut(cutname)); - } - } - LOGF(info, "Number of DalitzEE cuts = %d", fDalitzEECuts.size()); - } - - void DefinePHOSCuts() - { - TString cutNamesStr = fConfigPHOSCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fPHOSCuts.push_back(*phoscuts::GetCut(cutname)); - } - } - LOGF(info, "Number of PHOS cuts = %d", fPHOSCuts.size()); - } - - void DefineEMCCuts() - { - const float a = EMC_TM_Eta->at(0); - const float b = EMC_TM_Eta->at(1); - const float c = EMC_TM_Eta->at(2); - - const float d = EMC_TM_Phi->at(0); - const float e = EMC_TM_Phi->at(1); - const float f = EMC_TM_Phi->at(2); - LOGF(info, "EMCal track matching parameters : a = %f, b = %f, c = %f, d = %f, e = %f, f = %f", a, b, c, d, e, f); - - TString cutNamesStr = fConfigEMCCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - if (std::strcmp(cutname, "custom") == 0) { - EMCPhotonCut* custom_cut = new EMCPhotonCut(cutname, cutname); - custom_cut->SetMinE(EMC_minE); - custom_cut->SetMinNCell(EMC_minNCell); - custom_cut->SetM02Range(EMC_minM02, EMC_maxM02); - custom_cut->SetTimeRange(EMC_minTime, EMC_maxTime); - - custom_cut->SetTrackMatchingEta([&a, &b, &c](float pT) { - return a + pow(pT + b, c); - }); - custom_cut->SetTrackMatchingPhi([&d, &e, &f](float pT) { - return d + pow(pT + e, f); - }); - - custom_cut->SetMinEoverP(EMC_Eoverp); - custom_cut->SetUseExoticCut(EMC_UseExoticCut); - fEMCCuts.push_back(*custom_cut); - } else { - fEMCCuts.push_back(*emccuts::GetCut(cutname)); - } - } - } - LOGF(info, "Number of EMCal cuts = %d", fEMCCuts.size()); - } - - void DefinePairCuts() - { - TString cutNamesStr = fConfigPairCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fPairCuts.push_back(*paircuts::GetCut(cutname)); - } - } - LOGF(info, "Number of Pair cuts = %d", fPairCuts.size()); - } - - template - bool IsSelectedPair(TG1 const& g1, TG2 const& g2, TCut1 const& cut1, TCut2 const& cut2) - { - bool is_selected_pair = false; - if constexpr (pairtype == PairType::kPCMPHOS) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPCMEMC) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPCMDalitzEE) { - is_selected_pair = o2::aod::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else { - is_selected_pair = true; - } - return is_selected_pair; - } - - template - void TruePairing(TEvents const& collisions, TPhotons1 const& photons1, TPhotons2 const& photons2, TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, TCuts1 const& cuts1, TCuts2 const& cuts2, TPairCuts const& paircuts, TLegs const& /*legs*/, TEMPrimaryElectrons const& /*emprimaryelectrons*/, TMCParticles const& mcparticles, TMCEvents const& /*mcevents*/) - { - THashList* list_ev_pair_before = static_cast(fMainList->FindObject("Event")->FindObject(pairnames[pairtype].data())->FindObject(event_types[0].data())); - THashList* list_ev_pair_after = static_cast(fMainList->FindObject("Event")->FindObject(pairnames[pairtype].data())->FindObject(event_types[1].data())); - THashList* list_pair_ss = static_cast(fMainList->FindObject("Pair")->FindObject(pairnames[pairtype].data())); - THashList* list_pcm = static_cast(fMainList->FindObject("PCM")); - - for (auto& collision : collisions) { - if ((pairtype == kPHOSPHOS || pairtype == kPCMPHOS) && !collision.alias_bit(triggerAliases::kTVXinPHOS)) { - continue; - } - if ((pairtype == kEMCEMC || pairtype == kPCMEMC) && !collision.alias_bit(triggerAliases::kTVXinEMC)) { - continue; - } - - const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { - continue; - } - - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_pair_before, "", collision); - if (!fEMEventCut.IsSelected(collision)) { - continue; - } - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_pair_after, "", collision); - reinterpret_cast(list_ev_pair_before->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - reinterpret_cast(list_ev_pair_after->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - - auto photons1_coll = photons1.sliceBy(perCollision1, collision.globalIndex()); - auto photons2_coll = photons2.sliceBy(perCollision2, collision.globalIndex()); - - for (auto& cut1 : cuts1) { - for (auto& g1 : photons1_coll) { - - if (!cut1.template IsSelected(g1)) { - continue; - } - if (abs(g1.eta()) > maxY) { // photon is massless particle. rapidity = pseudo-rapidity - continue; - } - - auto pos1 = g1.template posTrack_as(); - auto ele1 = g1.template negTrack_as(); - auto pos1mc = pos1.template emmcparticle_as(); - auto ele1mc = ele1.template emmcparticle_as(); - - int photonid1 = FindCommonMotherFrom2Prongs(pos1mc, ele1mc, -11, 11, 22, mcparticles); - if (photonid1 < 0) { - continue; - } - auto mcphoton1 = mcparticles.iteratorAt(photonid1); - - int pi0id1 = IsXFromY(mcphoton1, mcparticles, 22, 111); - if (pi0id1 < 0) { // photon from pi0 decay - continue; - } - auto mcpi01 = mcparticles.iteratorAt(pi0id1); - - // // check if pi0 is physical primary or produced by generator, photon should be physical primary or produced by generator. - // LOGF(info, "mcphoton1.isPhysicalPrimary() = %d, mcphoton1.producedByGenerator() = %d, mcpi01.isPhysicalPrimary() = %d, mcpi01.producedByGenerator() = %d", - // mcphoton1.isPhysicalPrimary(), mcphoton1.producedByGenerator(), mcpi01.isPhysicalPrimary(), mcpi01.producedByGenerator()); - - if (mcpi01.isPhysicalPrimary() || mcpi01.producedByGenerator()) { - if (!IsConversionPointInAcceptance(mcphoton1, maxRgen, maxY, margin_z_mc, mcparticles)) { - continue; - } - reinterpret_cast(list_pcm->FindObject(cut1.GetName())->FindObject("hPt_v0photon_Pi0_Primary"))->Fill(g1.pt()); - } else if (IsFromWD(mcpi01.emmcevent(), mcpi01, mcparticles)) { - reinterpret_cast(list_pcm->FindObject(cut1.GetName())->FindObject("hPt_v0photon_Pi0_FromWD"))->Fill(g1.pt()); - } else { - reinterpret_cast(list_pcm->FindObject(cut1.GetName())->FindObject("hPt_v0photon_Pi0_hs"))->Fill(g1.pt()); - } - - } // end of pcm photon loop - } // end of cut loop - - for (auto& cut1 : cuts1) { - for (auto& cut2 : cuts2) { - for (auto& paircut : paircuts) { - for (auto& [g1, g2] : combinations(CombinationsFullIndexPolicy(photons1_coll, photons2_coll))) { - if (!IsSelectedPair(g1, g2, cut1, cut2)) { - continue; - } - - auto pos1 = g1.template posTrack_as(); - auto ele1 = g1.template negTrack_as(); - auto pos1mc = pos1.template emmcparticle_as(); - auto ele1mc = ele1.template emmcparticle_as(); - - int photonid1 = FindCommonMotherFrom2Prongs(pos1mc, ele1mc, -11, 11, 22, mcparticles); - if (photonid1 < 0) { // check swap, true electron is reconstructed as positron and vice versa. - photonid1 = FindCommonMotherFrom2Prongs(pos1mc, ele1mc, 11, -11, 22, mcparticles); - } - if (photonid1 < 0) { - continue; - } - - if constexpr (pairtype == PairType::kPCMPHOS || pairtype == PairType::kPCMEMC) { - if constexpr (pairtype == PairType::kPCMPHOS) { - if (o2::aod::photonpair::DoesV0LegMatchWithCluster(pos1, g2, 0.02, 0.4, 0.2) || o2::aod::photonpair::DoesV0LegMatchWithCluster(ele1, g2, 0.02, 0.4, 0.2)) { - continue; - } - } else if constexpr (pairtype == PairType::kPCMEMC) { - if (o2::aod::photonpair::DoesV0LegMatchWithCluster(pos1, g2, 0.02, 0.4, 0.5) || o2::aod::photonpair::DoesV0LegMatchWithCluster(ele1, g2, 0.02, 0.4, 0.5)) { - continue; - } - } - } - - auto g1mc = mcparticles.iteratorAt(photonid1); - - int pi0id = -1; - if constexpr (pairtype == PairType::kPCMDalitzEE) { - auto pos2 = g2.template posTrack_as(); - auto ele2 = g2.template negTrack_as(); - if (pos1.trackId() == pos2.trackId() || ele1.trackId() == ele2.trackId()) { - continue; - } - auto pos2mc = pos2.template emmcparticle_as(); - auto ele2mc = ele2.template emmcparticle_as(); - pi0id = FindCommonMotherFrom3Prongs(g1mc, pos2mc, ele2mc, 22, -11, 11, 111, mcparticles); - } - if (pi0id < 0) { - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); // pcm - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); // phos or emc or dalitzee - if constexpr (pairtype == PairType::kPCMDalitzEE) { - v2.SetM(g2.mass()); - } - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - // if (abs(v12.Rapidity()) > maxY) { - // continue; - // } - - if (pi0id > 0) { - auto mcpi0 = mcparticles.iteratorAt(pi0id); - if (mcpi0.isPhysicalPrimary() || mcpi0.producedByGenerator()) { - if (!IsConversionPointInAcceptance(g1mc, maxRgen, maxY, margin_z_mc, mcparticles)) { - continue; - } - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_Pi0_Primary"))->Fill(v12.M(), v1.Pt()); - } else if (IsFromWD(mcpi0.emmcevent(), mcpi0, mcparticles)) { - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_Pi0_FromWD"))->Fill(v12.M(), v1.Pt()); - } else { - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", cut1.GetName(), cut2.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_Pi0_hs"))->Fill(v12.M(), v1.Pt()); - } - } - } // end of combination - } // end of pair cut loop - } // end of cut2 loop - } // end of cut1 loop - } // end of collision loop - } - - Filter DalitzEEFilter = o2::aod::dalitzee::sign == 0; // analyze only uls - using MyFilteredDalitzEEs = soa::Filtered; - - Preslice perCollision_pcm = aod::v0photonkf::emeventId; - Preslice perCollision_dalitz = aod::dalitzee::emeventId; - Preslice perCollision_phos = aod::skimmedcluster::collisionId; - Preslice perCollision_emc = aod::skimmedcluster::collisionId; - Partition grouped_collisions = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); // this goes to same event. - - void processPCMDalitzEE(MyCollisions const&, MyV0Photons const& v0photons, MyMCV0Legs const& legs, MyFilteredDalitzEEs const& dielectrons, MyMCTracks const& emprimaryelectrons, aod::EMMCParticles const& mcparticles, aod::EMMCEvents const& mccollisions) - { - TruePairing(grouped_collisions, v0photons, dielectrons, perCollision_pcm, perCollision_dalitz, fPCMCuts, fDalitzEECuts, fPairCuts, legs, emprimaryelectrons, mcparticles, mccollisions); - } - - void processPCMPHOS(MyCollisions const&, MyV0Photons const& v0photons, aod::PHOSClusters const& phosclusters, MyMCV0Legs const& legs, aod::EMMCParticles const& mcparticles, aod::EMMCEvents const& mccollisions) - { - TruePairing(grouped_collisions, v0photons, phosclusters, perCollision_pcm, perCollision_phos, fPCMCuts, fPHOSCuts, fPairCuts, legs, nullptr, mcparticles, mccollisions); - } - - void processPCMEMC(MyCollisions const&, MyV0Photons const& v0photons, aod::SkimEMCClusters const& emcclusters, MyMCV0Legs const& legs, aod::EMMCParticles const& mcparticles, aod::EMMCEvents const& mccollisions) - { - TruePairing(grouped_collisions, v0photons, emcclusters, perCollision_pcm, perCollision_emc, fPCMCuts, fEMCCuts, fPairCuts, legs, nullptr, mcparticles, mccollisions); - } - - void processDummy(MyCollisions const&) {} - - PROCESS_SWITCH(TaggingPi0MC, processPCMDalitzEE, "pairing PCM-Dalitz", false); - PROCESS_SWITCH(TaggingPi0MC, processPCMPHOS, "pairing PCM-PHOS", false); - PROCESS_SWITCH(TaggingPi0MC, processPCMEMC, "pairing PCM-EMCal", false); - PROCESS_SWITCH(TaggingPi0MC, processDummy, "Dummy function", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"tagging-pi0-mc"})}; -} diff --git a/PWGEM/PhotonMeson/Tasks/TaggingPi0MCPCMDalitzEE.cxx b/PWGEM/PhotonMeson/Tasks/TaggingPi0MCPCMDalitzEE.cxx new file mode 100644 index 00000000000..ccdc4184568 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/TaggingPi0MCPCMDalitzEE.cxx @@ -0,0 +1,29 @@ +// 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. +// +// ======================== +// +// This code loops over photons and makes pairs for neutral mesons analyses. +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "PWGEM/PhotonMeson/Core/TaggingPi0MC.h" + +using namespace o2; +using namespace o2::aod; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"tagging-pi0-mc-pcmdalitzee"}), + }; +} diff --git a/PWGEM/PhotonMeson/Tasks/TaggingPi0PCMDalitzEE.cxx b/PWGEM/PhotonMeson/Tasks/TaggingPi0PCMDalitzEE.cxx new file mode 100644 index 00000000000..2292faef120 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/TaggingPi0PCMDalitzEE.cxx @@ -0,0 +1,29 @@ +// 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. +// +// ======================== +// +// This code loops over photons and makes pairs for neutral mesons analyses. +// Please write to: daiki.sekihata@cern.ch + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "PWGEM/PhotonMeson/Core/TaggingPi0.h" + +using namespace o2; +using namespace o2::aod; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"tagging-pi0-pcmdalitzee"}), + }; +} diff --git a/PWGEM/PhotonMeson/Tasks/dalitzEEQC.cxx b/PWGEM/PhotonMeson/Tasks/dalitzEEQC.cxx index c7f03892676..74c97448baf 100644 --- a/PWGEM/PhotonMeson/Tasks/dalitzEEQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/dalitzEEQC.cxx @@ -14,372 +14,364 @@ // This code runs loop over dalitz ee table for dalitz QC. // Please write to: daiki.sekihata@cern.ch -#include +#include +#include + #include "TString.h" -#include "THashList.h" -#include "TDirectory.h" #include "Math/Vector4D.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/ASoAHelpers.h" - #include "Common/Core/RecoDecay.h" + +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Core/DalitzEECut.h" -#include "PWGEM/PhotonMeson/Core/CutsLibrary.h" -#include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" -#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; -using namespace o2::aod::pwgem::photon; -using std::array; +using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; -using MyDalitzEEs = soa::Join; -using MyDalitzEE = MyDalitzEEs::iterator; - -using MyTracks = soa::Join; +using MyTracks = soa::Join; using MyTrack = MyTracks::iterator; struct DalitzEEQC { + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + Configurable maxY{"maxY", 0.9, "maximum rapidity for reconstructed particles"}; + + EMPhotonEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgOccupancyMin{"cfgOccupancyMin", -1, "min. occupancy"}; + Configurable cfgOccupancyMax{"cfgOccupancyMax", 1000000000, "max. occupancy"}; + } eventcuts; + + DalitzEECut fDileptonCut; + struct : ConfigurableGroup { + std::string prefix = "dileptoncut_group"; + Configurable cfg_min_mass{"cfg_min_mass", 0.0, "min mass"}; + Configurable cfg_max_mass{"cfg_max_mass", 0.02, "max mass"}; + Configurable cfg_apply_phiv{"cfg_apply_phiv", true, "flag to apply phiv cut"}; + Configurable cfg_require_itsib_any{"cfg_require_itsib_any", true, "flag to require ITS ib any hits"}; + Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", false, "flag to require ITS ib 1st hit"}; + Configurable cfg_phiv_slope{"cfg_phiv_slope", 0.0185, "slope for m vs. phiv"}; + Configurable cfg_phiv_intercept{"cfg_phiv_intercept", -0.0280, "intercept for m vs. phiv"}; + + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.1, "min pT for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", 0.9, "max eta for single track"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 70, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1.0, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 1.0, "max dca Z for single track in cm"}; + Configurable cfg_max_dca3dsigma_track{"cfg_max_dca3dsigma_track", 1.5, "max DCA 3D in sigma"}; + + Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DalitzEECut::PIDSchemes::kTOFif), "pid scheme [kTOFif : 0, kTPConly : 1]"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -0.0, "min. TPC n sigma for pion exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +0.0, "max. TPC n sigma for pion exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; + } dileptoncuts; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + int mRunNumber; + float d_bz; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view event_cut_types[2] = {"before/", "after/"}; + + void init(InitContext& /*context*/) + { + DefineEMEventCut(); + DefineDileptonCut(); + addhistograms(); - Configurable fConfigDalitzEECuts{"cfgDalitzEECuts", "mee_all_tpchadrejortofreq_lowB,nocut", "Comma separated list of dalitz ee cuts"}; - std::vector fDalitzEECuts; + mRunNumber = 0; + d_bz = 0; - Configurable cfgDoDCAstudy{"cfgDoDCAstudy", false, "flag to fill histograms for DCA"}; + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + } - Configurable fConfigEMEventCut{"cfgEMEventCut", "minbias", "em event cut"}; // only 1 event cut per wagon - EMEventCut fEMEventCut; - static constexpr std::string_view event_types[2] = {"before", "after"}; + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } - static constexpr std::string_view cent_det_names[3] = {"FT0M", "FT0A", "FT0C"}; - OutputObj fOutputEvent{"Event"}; - OutputObj fOutputTrack{"Track"}; - OutputObj fOutputDalitzEE{"DalitzEE"}; - THashList* fMainList = new THashList(); - bool doMix = false; + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (std::fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + mRunNumber = collision.runNumber(); + return; + } - void addhistograms() - { - fMainList->SetOwner(true); - fMainList->SetName("fMainList"); - - // create sub lists first. - THashList* list_ev = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Event")); - for (const auto& evtype : event_types) { - THashList* list_ev_type = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_ev, evtype.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_ev_type, "Event", evtype.data()); + auto run3grp_timestamp = collision.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; } + mRunNumber = collision.runNumber(); + } - THashList* list_track = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Track")); - THashList* list_dalitzee = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "DalitzEE")); + ~DalitzEEQC() {} - for (const auto& cut : fDalitzEECuts) { - const char* cutname = cut.GetName(); - THashList* list_track_cut = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_track, cutname)); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_track_cut, "Track"); + void addhistograms() + { + // event info + o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(&fRegistry); + + // pair info + const AxisSpec axis_mass{200, 0, 0.2, "m_{ee} (GeV/c^{2})"}; + const AxisSpec axis_pt{200, 0, 2, "p_{T,ee} (GeV/c)"}; + + fRegistry.add("Pair/same/hMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {axis_mass, axis_pt}, true); + fRegistry.add("Pair/same/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0, M_PI}, {100, 0.0f, 0.1f}}, true); + + fRegistry.add("Track/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); + fRegistry.add("Track/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); + fRegistry.add("Track/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {40, -2.0f, 2.0f}}, false); + fRegistry.add("Track/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -0.1f, 0.1f}, {200, -0.1f, 0.1f}}, false); + fRegistry.add("Track/hDCAxyzSigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/hDCAzRes_Pt", "DCA_{z} resolution vs. pT;p_{T} (GeV/c);DCA_{z} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/hNclsTPC", "number of TPC clusters", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hNcrTPC", "number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hTPCNclsShared", "TPC Ncls shared/Ncls;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); + + fRegistry.add("Track/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("Track/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("Track/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); on ITS #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); + + fRegistry.add("Track/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("Track/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + + fRegistry.add("Track/hChi2TOF", "chi2 of TOF", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hTOFbeta", "TOF beta;p_{pv} (GeV/c);#beta", kTH2F, {{1000, 0, 10}, {240, 0, 1.2}}, false); + fRegistry.add("Track/hTOFNsigmaEl", "TOF n sigma el;p_{pv} (GeV/c);n #sigma_{e}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaPi", "TOF n sigma pi;p_{pv} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + } - THashList* list_dalitzee_cut = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_dalitzee, cutname)); - std::string histo_sub_group = ""; - if (doMix) { - histo_sub_group += "mix"; - } - if (cfgDoDCAstudy) { - histo_sub_group += "dca"; - } - o2::aod::pwgem::photon::histogram::DefineHistograms(list_dalitzee_cut, "DalitzEE", histo_sub_group.data()); - } // end of cut loop + void DefineEMEventCut() + { + fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); } - void DefineCuts() + void DefineDileptonCut() { - TString cutNamesStr = fConfigDalitzEECuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fDalitzEECuts.push_back(*dalitzeecuts::GetCut(cutname)); - } - } - LOGF(info, "Number of Dalitz cuts = %d", fDalitzEECuts.size()); + fDileptonCut = DalitzEECut("fDileptonCut", "fDileptonCut"); + + // for pair + fDileptonCut.SetMeeRange(dileptoncuts.cfg_min_mass, dileptoncuts.cfg_max_mass); + fDileptonCut.SetMaxPhivPairMeeDep([&](float mll) { return (mll - dileptoncuts.cfg_phiv_intercept) / dileptoncuts.cfg_phiv_slope; }); + fDileptonCut.ApplyPhiV(dileptoncuts.cfg_apply_phiv); + fDileptonCut.RequireITSibAny(dileptoncuts.cfg_require_itsib_any); + fDileptonCut.RequireITSib1st(dileptoncuts.cfg_require_itsib_1st); + + // for track + fDileptonCut.SetTrackPtRange(dileptoncuts.cfg_min_pt_track, 1e+10f); + fDileptonCut.SetTrackEtaRange(-dileptoncuts.cfg_max_eta_track, +dileptoncuts.cfg_max_eta_track); + fDileptonCut.SetMinNClustersTPC(dileptoncuts.cfg_min_ncluster_tpc); + fDileptonCut.SetMinNCrossedRowsTPC(dileptoncuts.cfg_min_ncrossedrows); + fDileptonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fDileptonCut.SetMaxFracSharedClustersTPC(dileptoncuts.cfg_max_frac_shared_clusters_tpc); + fDileptonCut.SetChi2PerClusterTPC(0.0, dileptoncuts.cfg_max_chi2tpc); + fDileptonCut.SetChi2PerClusterITS(0.0, dileptoncuts.cfg_max_chi2its); + fDileptonCut.SetNClustersITS(dileptoncuts.cfg_min_ncluster_its, 7); + fDileptonCut.SetMaxDcaXY(dileptoncuts.cfg_max_dcaxy); + fDileptonCut.SetMaxDcaZ(dileptoncuts.cfg_max_dcaz); + fDileptonCut.SetTrackDca3DRange(0.f, dileptoncuts.cfg_max_dca3dsigma_track); // in sigma + + // for eID + fDileptonCut.SetPIDScheme(dileptoncuts.cfg_pid_scheme); + fDileptonCut.SetTPCNsigmaElRange(dileptoncuts.cfg_min_TPCNsigmaEl, dileptoncuts.cfg_max_TPCNsigmaEl); + fDileptonCut.SetTPCNsigmaPiRange(dileptoncuts.cfg_min_TPCNsigmaPi, dileptoncuts.cfg_max_TPCNsigmaPi); + fDileptonCut.SetTOFNsigmaElRange(dileptoncuts.cfg_min_TOFNsigmaEl, dileptoncuts.cfg_max_TOFNsigmaEl); } - void init(InitContext& context) + template + bool fillPairInfo(TCollision const&, TTrack1 const& t1, TTrack2 const& t2) { - if (context.mOptions.get("processEventMixing")) { - doMix = true; + if (t1.trackId() == t2.trackId()) { // this is protection against pairing identical 2 tracks. This happens, when TTCA is used. TTCA can assign a track to several possible collisions. + return false; + } + + if (!fDileptonCut.IsSelectedTrack(t1) || !fDileptonCut.IsSelectedTrack(t2)) { + return false; + } + + if (!fDileptonCut.IsSelectedPair(t1, t2, d_bz)) { + return false; + } + + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + if (std::fabs(v12.Rapidity()) > maxY) { + return false; } + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), d_bz); - DefineCuts(); - addhistograms(); // please call this after DefinCuts(); - TString ev_cut_name = fConfigEMEventCut.value; - fEMEventCut = *eventcuts::GetCut(ev_cut_name.Data()); + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/same/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/same/hMvsPhiV"), phiv, v12.M()); + } - fOutputEvent.setObject(reinterpret_cast(fMainList->FindObject("Event"))); - fOutputTrack.setObject(reinterpret_cast(fMainList->FindObject("Track"))); - fOutputDalitzEE.setObject(reinterpret_cast(fMainList->FindObject("DalitzEE"))); + if (std::find(used_trackIds.begin(), used_trackIds.end(), t1.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t1.globalIndex()); + fillTrackInfo(t1); + } + if (std::find(used_trackIds.begin(), used_trackIds.end(), t2.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t2.globalIndex()); + fillTrackInfo(t2); + } + return true; } - Partition uls_pairs = o2::aod::dalitzee::sign == 0; - Partition lspp_pairs = o2::aod::dalitzee::sign == +1; - Partition lsmm_pairs = o2::aod::dalitzee::sign == -1; + template + void fillTrackInfo(TTrack const& track) + { + fRegistry.fill(HIST("Track/hPt"), track.pt()); + fRegistry.fill(HIST("Track/hQoverPt"), track.sign() / track.pt()); + fRegistry.fill(HIST("Track/hEtaPhi"), track.phi(), track.eta()); + fRegistry.fill(HIST("Track/hDCAxyz"), track.dcaXY(), track.dcaZ()); + fRegistry.fill(HIST("Track/hDCAxyzSigma"), track.dcaXY() / std::sqrt(track.cYY()), track.dcaZ() / std::sqrt(track.cZZ())); + fRegistry.fill(HIST("Track/hDCAxyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hDCAzRes_Pt"), track.pt(), std::sqrt(track.cZZ()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hNclsITS"), track.itsNCls()); + fRegistry.fill(HIST("Track/hNclsTPC"), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("Track/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("Track/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("Track/hTPCNclsShared"), track.pt(), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("Track/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("Track/hChi2ITS"), track.itsChi2NCl()); + fRegistry.fill(HIST("Track/hChi2TOF"), track.tofChi2()); + fRegistry.fill(HIST("Track/hITSClusterMap"), track.itsClusterMap()); + fRegistry.fill(HIST("Track/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); + fRegistry.fill(HIST("Track/hTOFNsigmaEl"), track.p(), track.tofNSigmaEl()); + fRegistry.fill(HIST("Track/hTOFNsigmaPi"), track.p(), track.tofNSigmaPi()); + fRegistry.fill(HIST("Track/hTOFbeta"), track.p(), track.beta()); + fRegistry.fill(HIST("Track/hMeanClusterSizeITS"), track.p(), track.meanClusterSizeITS() * std::cos(std::atan(track.tgl()))); + } + + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + using FilteredMyCollisions = soa::Filtered; SliceCache cache; - Preslice perCollision = aod::dalitzee::emeventId; Preslice perCollision_track = aod::emprimaryelectron::emeventId; - Partition grouped_collisions = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); // this goes to same event. - - void processQC(MyCollisions const&, MyDalitzEEs const&, MyTracks const&) + Filter trackFilter = dileptoncuts.cfg_min_pt_track < o2::aod::track::pt && nabs(o2::aod::track::eta) < dileptoncuts.cfg_max_eta_track && o2::aod::track::tpcChi2NCl < dileptoncuts.cfg_max_chi2tpc && o2::aod::track::itsChi2NCl < dileptoncuts.cfg_max_chi2its && nabs(o2::aod::track::dcaXY) < dileptoncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dileptoncuts.cfg_max_dcaz; + Filter pidFilter = dileptoncuts.cfg_min_TPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < dileptoncuts.cfg_max_TPCNsigmaEl && (o2::aod::pidtpc::tpcNSigmaPi < dileptoncuts.cfg_min_TPCNsigmaPi || dileptoncuts.cfg_max_TPCNsigmaPi < o2::aod::pidtpc::tpcNSigmaPi); + using FilteredMyTracks = soa::Filtered; + Partition posTracks = o2::aod::emprimaryelectron::sign > int8_t(0); + Partition negTracks = o2::aod::emprimaryelectron::sign < int8_t(0); + + std::vector used_trackIds; + void processQC(FilteredMyCollisions const& collisions, FilteredMyTracks const& /*tracks*/) { - THashList* list_ev_before = static_cast(fMainList->FindObject("Event")->FindObject(event_types[0].data())); - THashList* list_ev_after = static_cast(fMainList->FindObject("Event")->FindObject(event_types[1].data())); - THashList* list_dalitzee = static_cast(fMainList->FindObject("DalitzEE")); - THashList* list_track = static_cast(fMainList->FindObject("Track")); - double values[3] = {0, 0, 0}; - double values_single[4] = {0, 0, 0, 0}; - float dca_pos_3d = 999.f, dca_ele_3d = 999.f, dca_ee_3d = 999.f; - - for (auto& collision : grouped_collisions) { - float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + for (auto& collision : collisions) { + initCCDB(collision); + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_before, "", collision); + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision); if (!fEMEventCut.IsSelected(collision)) { continue; } - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_after, "", collision); - reinterpret_cast(list_ev_before->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - reinterpret_cast(list_ev_after->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - - auto uls_pairs_per_coll = uls_pairs->sliceByCached(o2::aod::dalitzee::emeventId, collision.globalIndex(), cache); - auto lspp_pairs_per_coll = lspp_pairs->sliceByCached(o2::aod::dalitzee::emeventId, collision.globalIndex(), cache); - auto lsmm_pairs_per_coll = lsmm_pairs->sliceByCached(o2::aod::dalitzee::emeventId, collision.globalIndex(), cache); - - for (const auto& cut : fDalitzEECuts) { - THashList* list_dalitzee_cut = static_cast(list_dalitzee->FindObject(cut.GetName())); - THashList* list_track_cut = static_cast(list_track->FindObject(cut.GetName())); - - std::vector used_trackIds; - used_trackIds.reserve(uls_pairs_per_coll.size() * 2); - - int nuls = 0, nlspp = 0, nlsmm = 0; - for (auto& uls_pair : uls_pairs_per_coll) { - auto pos = uls_pair.template posTrack_as(); - auto ele = uls_pair.template negTrack_as(); - if (cut.IsSelected(uls_pair)) { - dca_pos_3d = pos.dca3DinSigma(); - dca_ele_3d = ele.dca3DinSigma(); - dca_ee_3d = std::sqrt((dca_pos_3d * dca_pos_3d + dca_ele_3d * dca_ele_3d) / 2.); - - if (cfgDoDCAstudy) { - values_single[0] = uls_pair.mass(); - values_single[1] = dca_pos_3d; - values_single[2] = dca_ele_3d; - values_single[3] = dca_ee_3d; - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_uls_dca_same"))->Fill(values_single); - } - - values[0] = uls_pair.mass(); - values[1] = uls_pair.pt(); - values[2] = dca_ee_3d; - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_uls_same"))->Fill(values); - reinterpret_cast(list_dalitzee_cut->FindObject("hMvsPhiV_uls_same"))->Fill(uls_pair.phiv(), uls_pair.mass()); - nuls++; - for (auto& track : {pos, ele}) { - if (std::find(used_trackIds.begin(), used_trackIds.end(), track.globalIndex()) == used_trackIds.end()) { - o2::aod::pwgem::photon::histogram::FillHistClass(list_track_cut, "", track); - used_trackIds.emplace_back(track.globalIndex()); - } - } - } - } // end of uls pair loop - reinterpret_cast(list_dalitzee_cut->FindObject("hNpair_uls"))->Fill(nuls); - - for (auto& lspp_pair : lspp_pairs_per_coll) { - auto pos = lspp_pair.template posTrack_as(); - auto ele = lspp_pair.template negTrack_as(); - if (cut.IsSelected(lspp_pair)) { - dca_pos_3d = pos.dca3DinSigma(); - dca_ele_3d = ele.dca3DinSigma(); - dca_ee_3d = std::sqrt((dca_pos_3d * dca_pos_3d + dca_ele_3d * dca_ele_3d) / 2.); - - if (cfgDoDCAstudy) { - values_single[0] = lspp_pair.mass(); - values_single[1] = dca_pos_3d; - values_single[2] = dca_ele_3d; - values_single[3] = dca_ee_3d; - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_lspp_dca_same"))->Fill(values_single); - } - values[0] = lspp_pair.mass(); - values[1] = lspp_pair.pt(); - values[2] = dca_ee_3d; - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_lspp_same"))->Fill(values); - reinterpret_cast(list_dalitzee_cut->FindObject("hMvsPhiV_lspp_same"))->Fill(lspp_pair.phiv(), lspp_pair.mass()); - nlspp++; - } - } // end of lspp pair loop - reinterpret_cast(list_dalitzee_cut->FindObject("hNpair_lspp"))->Fill(nlspp); - - for (auto& lsmm_pair : lsmm_pairs_per_coll) { - auto pos = lsmm_pair.template posTrack_as(); - auto ele = lsmm_pair.template negTrack_as(); - if (cut.IsSelected(lsmm_pair)) { - dca_pos_3d = pos.dca3DinSigma(); - dca_ele_3d = ele.dca3DinSigma(); - dca_ee_3d = std::sqrt((dca_pos_3d * dca_pos_3d + dca_ele_3d * dca_ele_3d) / 2.); - - if (cfgDoDCAstudy) { - values_single[0] = lsmm_pair.mass(); - values_single[1] = dca_pos_3d; - values_single[2] = dca_ele_3d; - values_single[3] = dca_ee_3d; - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_lsmm_dca_same"))->Fill(values_single); - } - - values[0] = lsmm_pair.mass(); - values[1] = lsmm_pair.pt(); - values[2] = dca_ee_3d; - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_lsmm_same"))->Fill(values); - reinterpret_cast(list_dalitzee_cut->FindObject("hMvsPhiV_lsmm_same"))->Fill(lsmm_pair.phiv(), lsmm_pair.mass()); - nlsmm++; - } - } // end of lsmm pair loop - reinterpret_cast(list_dalitzee_cut->FindObject("hNpair_lsmm"))->Fill(nlsmm); - - used_trackIds.clear(); - used_trackIds.shrink_to_fit(); - } // end of cut loop - } // end of collision loop - } // end of process - PROCESS_SWITCH(DalitzEEQC, processQC, "run Dalitz QC", true); - - Configurable ndepth{"ndepth", 10, "depth for event mixing"}; - ConfigurableAxis ConfVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - ConfigurableAxis ConfCentBins{"ConfCentBins", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 999.f}, "Mixing bins - centrality"}; - using BinningType_M = ColumnBinningPolicy; - using BinningType_A = ColumnBinningPolicy; - using BinningType_C = ColumnBinningPolicy; - BinningType_M colBinning_M{{ConfVtxBins, ConfCentBins}, true}; - BinningType_A colBinning_A{{ConfVtxBins, ConfCentBins}, true}; - BinningType_C colBinning_C{{ConfVtxBins, ConfCentBins}, true}; - - Filter collisionFilter_common = nabs(o2::aod::collision::posZ) < 10.f && o2::aod::collision::numContrib > (uint16_t)0 && o2::aod::evsel::sel8 == true; - Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); - Filter collisionFilter_subsys = (o2::aod::emevent::neeuls >= 1) || (o2::aod::emevent::neelspp >= 1) || (o2::aod::emevent::neelsmm >= 1); - using MyFilteredCollisions = soa::Filtered; // this goes to mixed event. - - // e+, e- enter to event mixing, only if any pair exists. If you want to do mixed event, please store LS for ee - template - void MixedEventPairing(TEvents const& collisions, TTracks const& tracks, TMixedBinning const& colBinning) - { - THashList* list_dalitzee = static_cast(fMainList->FindObject("DalitzEE")); - double values[3] = {0, 0, 0}; - ROOT::Math::PtEtaPhiMVector v1, v2, v12; - float phiv = 0; - double values_single[4] = {0, 0, 0, 0}; - float dca_pos_3d = 999.f, dca_ele_3d = 999.f, dca_ee_3d = 999.f; - - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, ndepth, -1, collisions, collisions)) { // internally, CombinationsStrictlyUpperIndexPolicy(collisions, collisions) is called. - const float centralities1[3] = {collision1.centFT0M(), collision1.centFT0A(), collision1.centFT0C()}; - const float centralities2[3] = {collision2.centFT0M(), collision2.centFT0A(), collision2.centFT0C()}; - - if (centralities1[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities1[cfgCentEstimator]) { - continue; - } - if (centralities2[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities2[cfgCentEstimator]) { + if (!(eventcuts.cfgOccupancyMin <= collision.trackOccupancyInTimeRange() && collision.trackOccupancyInTimeRange() < eventcuts.cfgOccupancyMax)) { continue; } - if (!fEMEventCut.IsSelected(collision1) || !fEMEventCut.IsSelected(collision2)) { - continue; + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 12.0); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 12.0); // accepted + + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + // LOGF(info, "centrality = %f , posTracks_per_coll.size() = %d, negTracks_per_coll.size() = %d", centralities[cfgCentEstimator], posTracks_per_coll.size(), negTracks_per_coll.size()); + + for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + fillPairInfo(collision, pos, ele); } + } // end of collision loop - auto tracks_coll1 = tracks.sliceBy(perCollision_track, collision1.globalIndex()); - auto tracks_coll2 = tracks.sliceBy(perCollision_track, collision2.globalIndex()); - // LOGF(info, "collision1.globalIndex() = %d, collision1: posZ = %f, sel8 = %d, centFT0C = %f, ndl1 = %d | collision2.globalIndex() = %d, collision2: posZ = %f, sel8 = %d, centFT0C = %f, ndl2 = %d",collision1.globalIndex(), collision1.posZ(), collision1.sel8(), collision1.centFT0C(), tracks_coll1.size(), collision2.globalIndex(), collision2.posZ(), collision2.sel8(), collision2.centFT0C(), tracks_coll2.size()); - - for (auto& cut : fDalitzEECuts) { - THashList* list_dalitzee_cut = static_cast(list_dalitzee->FindObject(cut.GetName())); - for (auto& [t1, t2] : combinations(soa::CombinationsFullIndexPolicy(tracks_coll1, tracks_coll2))) { - v1 = ROOT::Math::PtEtaPhiMVector(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); - v2 = ROOT::Math::PtEtaPhiMVector(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); - v12 = v1 + v2; - phiv = getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), collision1.bz()); - // if (!std::isfinite(phiv)) { - // LOGF(info, "t1.px() = %f, t1.py() = %f, t1.pz() = %f, t2.px() = %f, t2.py() = %f, t2.pz() = %f, phiv = %f", t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), phiv); - // } - - if (t1.trackId() == t2.trackId()) { // this is protection against pairing identical 2 tracks. This happens, when TTCA is used. TTCA can assign a track to several possible collisions. - continue; - } - - dca_pos_3d = t1.dca3DinSigma(); - dca_ele_3d = t2.dca3DinSigma(); - dca_ee_3d = std::sqrt((dca_pos_3d * dca_pos_3d + dca_ele_3d * dca_ele_3d) / 2.); - - values_single[0] = v12.M(); - values_single[1] = dca_pos_3d; - values_single[2] = dca_ele_3d; - values_single[3] = dca_ee_3d; - - values[0] = v12.M(); - values[1] = v12.Pt(); - values[2] = dca_ee_3d; - - if (cut.IsSelectedTrack(t1) && cut.IsSelectedTrack(t2) && cut.IsSelectedPair(v12.M(), dca_ee_3d, phiv)) { - if (t1.sign() * t2.sign() < 0) { - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_uls_mix"))->Fill(values); - reinterpret_cast(list_dalitzee_cut->FindObject("hMvsPhiV_uls_mix"))->Fill(phiv, v12.M()); - } else if (t1.sign() > 0 && t2.sign() > 0) { - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_lspp_mix"))->Fill(values); - reinterpret_cast(list_dalitzee_cut->FindObject("hMvsPhiV_lspp_mix"))->Fill(phiv, v12.M()); - } else if (t1.sign() < 0 && t2.sign() < 0) { - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_lsmm_mix"))->Fill(values); - reinterpret_cast(list_dalitzee_cut->FindObject("hMvsPhiV_lsmm_mix"))->Fill(phiv, v12.M()); - } else { - LOGF(info, "This should not happen."); - } - - if (cfgDoDCAstudy) { - if (t1.sign() * t2.sign() < 0) { - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_uls_dca_mix"))->Fill(values_single); - } else if (t1.sign() > 0 && t2.sign() > 0) { - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_lspp_dca_mix"))->Fill(values_single); - } else if (t1.sign() < 0 && t2.sign() < 0) { - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_lsmm_dca_mix"))->Fill(values_single); - } else { - LOGF(info, "This should not happen."); - } - } - } - } // end of different dileptn combinations - } // end of cut loop - } // end of different collision combinations - } + used_trackIds.clear(); + used_trackIds.shrink_to_fit(); - void processEventMixing(MyFilteredCollisions const& collisions, MyTracks const& tracks) - { - if (cfgCentEstimator == 0) { - MixedEventPairing(collisions, tracks, colBinning_M); - } else if (cfgCentEstimator == 1) { - MixedEventPairing(collisions, tracks, colBinning_A); - } else if (cfgCentEstimator == 2) { - MixedEventPairing(collisions, tracks, colBinning_C); - } - } - PROCESS_SWITCH(DalitzEEQC, processEventMixing, "run Dalitz EE QC event mixing", true); + } // end of process + PROCESS_SWITCH(DalitzEEQC, processQC, "run Dalitz QC", true); void processDummy(MyCollisions const&) {} PROCESS_SWITCH(DalitzEEQC, processDummy, "Dummy function", false); diff --git a/PWGEM/PhotonMeson/Tasks/dalitzEEQCMC.cxx b/PWGEM/PhotonMeson/Tasks/dalitzEEQCMC.cxx index 529fe4031fe..4e2e33c2d18 100644 --- a/PWGEM/PhotonMeson/Tasks/dalitzEEQCMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/dalitzEEQCMC.cxx @@ -14,488 +14,554 @@ // This code runs loop over dalitz ee table for dalitz QC. // Please write to: daiki.sekihata@cern.ch -#include +#include +#include + #include "TString.h" -#include "THashList.h" -#include "TDirectory.h" #include "Math/Vector4D.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/ASoAHelpers.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + #include "Common/Core/RecoDecay.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Core/DalitzEECut.h" -#include "PWGEM/PhotonMeson/Core/CutsLibrary.h" -#include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" #include "PWGEM/PhotonMeson/Utils/MCUtilities.h" #include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; -using namespace o2::aod::pwgem::mcutil; -using namespace o2::aod::pwgem::photon; -using namespace o2::aod::pwgem::dilepton::mcutil; -using std::array; +using namespace o2::aod::pwgem::photonmeson::utils::mcutil; +using namespace o2::aod::pwgem::dilepton::utils::mcutil; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; -using MyDalitzEEs = soa::Join; -using MyDalitzEE = MyDalitzEEs::iterator; - -using MyTracks = soa::Join; -using MyMCTracks = soa::Join; +using MyMCTracks = soa::Join; +using MyMCTrack = MyMCTracks::iterator; struct DalitzEEQCMC { + + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; - - Configurable fConfigDalitzEECuts{"cfgDalitzEECuts", "mee_all_tpchadrejortofreq_lowB,nocut", "Comma separated list of dalitz ee cuts"}; - std::vector fDalitzEECuts; - - Configurable cfgDoDCAstudy{"cfgDoDCAstudy", false, "flag to fill histograms for DCA"}; - - Configurable fConfigEMEventCut{"cfgEMEventCut", "minbias", "em event cut"}; // only 1 event cut per wagon - EMEventCut fEMEventCut; - static constexpr std::string_view event_types[2] = {"before", "after"}; - - OutputObj fOutputEvent{"Event"}; - OutputObj fOutputTrack{"Track"}; - OutputObj fOutputDalitzEE{"DalitzEE"}; - OutputObj fOutputGen{"Generated"}; - THashList* fMainList = new THashList(); + Configurable maxY{"maxY", 0.9, "maximum rapidity for reconstructed particles"}; + Configurable cfgRequireTrueAssociation{"cfgRequireTrueAssociation", false, "flag to require true mc collision association"}; + + EMPhotonEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgOccupancyMin{"cfgOccupancyMin", -1, "min. occupancy"}; + Configurable cfgOccupancyMax{"cfgOccupancyMax", 1000000000, "max. occupancy"}; + } eventcuts; + + DalitzEECut fDileptonCut; + struct : ConfigurableGroup { + std::string prefix = "dileptoncut_group"; + Configurable cfg_min_mass{"cfg_min_mass", 0.0, "min mass"}; + Configurable cfg_max_mass{"cfg_max_mass", 0.02, "max mass"}; + Configurable cfg_apply_phiv{"cfg_apply_phiv", true, "flag to apply phiv cut"}; + Configurable cfg_require_itsib_any{"cfg_require_itsib_any", true, "flag to require ITS ib any hits"}; + Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", false, "flag to require ITS ib 1st hit"}; + Configurable cfg_phiv_slope{"cfg_phiv_slope", 0.0185, "slope for m vs. phiv"}; + Configurable cfg_phiv_intercept{"cfg_phiv_intercept", -0.0280, "intercept for m vs. phiv"}; + + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.1, "min pT for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", 0.9, "max eta for single track"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 70, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1.0, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 1.0, "max dca Z for single track in cm"}; + Configurable cfg_max_dca3dsigma_track{"cfg_max_dca3dsigma_track", 1.5, "max DCA 3D in sigma"}; + + Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DalitzEECut::PIDSchemes::kTOFif), "pid scheme [kTOFif : 0, kTPConly : 1]"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -0.0, "min. TPC n sigma for pion exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +0.0, "max. TPC n sigma for pion exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; + } dileptoncuts; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + int mRunNumber; + float d_bz; + + struct : ConfigurableGroup { + std::string prefix = "mctrackcut_group"; + Configurable min_mcPt{"min_mcPt", 0.05, "min. MC pT"}; + Configurable max_mcPt{"max_mcPt", 1e+10, "max. MC pT"}; + Configurable max_mcEta{"max_mcEta", 0.9, "max. MC eta"}; + } mctrackcuts; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view event_cut_types[2] = {"before/", "after/"}; + static constexpr std::string_view track_types[2] = {"primary/", "secondary/"}; + + ~DalitzEEQCMC() {} void addhistograms() { - fMainList->SetOwner(true); - fMainList->SetName("fMainList"); - - // create sub lists first. - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Event"); - THashList* list_ev = reinterpret_cast(fMainList->FindObject("Event")); - for (const auto& evtype : event_types) { - THashList* list_ev_type = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_ev, evtype.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_ev_type, "Event", evtype.data()); - } + // event info + o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(&fRegistry); + + const AxisSpec axis_mass{200, 0, 0.2, "m_{ee} (GeV/c^{2})"}; + const AxisSpec axis_pt{200, 0, 2, "p_{T,ee} (GeV/c)"}; + + // generated info + fRegistry.add("Generated/sm/Pi0/hMvsPt", "m_{ee} vs. p_{T,ee} ULS", kTH2F, {axis_mass, axis_pt}, true); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/Eta/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/EtaPrime/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/Rho/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/Omega/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/Phi/"); + + // reconstructed pair info + fRegistry.add("Pair/sm/Photon/hMvsPt", "m_{ee} vs. p_{T,ee} ULS", kTH2F, {axis_mass, axis_pt}, true); + fRegistry.add("Pair/sm/Photon/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0, M_PI}, {100, 0.0f, 0.1f}}, false); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Pi0/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Eta/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/EtaPrime/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Rho/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Omega/"); + fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Phi/"); + + // track info + fRegistry.add("Track/primary/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); + fRegistry.add("Track/primary/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); + fRegistry.add("Track/primary/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {40, -2.0f, 2.0f}}, false); + fRegistry.add("Track/primary/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -0.1f, 0.1f}, {200, -0.1f, 0.1f}}, false); + fRegistry.add("Track/primary/hDCAxyzSigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/primary/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/primary/hDCAzRes_Pt", "DCA_{z} resolution vs. pT;p_{T} (GeV/c);DCA_{z} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/primary/hNclsTPC", "number of TPC clusters", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/primary/hNcrTPC", "number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/primary/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/primary/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/primary/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/primary/hTPCNclsShared", "TPC Ncls shared/Ncls;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); + + fRegistry.add("Track/primary/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("Track/primary/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/primary/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + + fRegistry.add("Track/primary/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("Track/primary/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/primary/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("Track/primary/hMeanClusterSizeITS", "mean cluster size ITS; on ITS #times cos(#lambda)", kTH1F, {{32, 0, 16}}, false); + + fRegistry.add("Track/primary/hChi2TOF", "chi2 of TOF", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/primary/hTOFbeta", "TOF beta;p_{pv} (GeV/c);#beta", kTH2F, {{1000, 0, 10}, {240, 0, 1.2}}, false); + fRegistry.add("Track/primary/hTOFNsigmaEl", "TOF n sigma el;p_{pv} (GeV/c);n #sigma_{e}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/primary/hTOFNsigmaPi", "TOF n sigma pi;p_{pv} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/primary/hPtGen_DeltaPtOverPtGen", "electron p_{T} resolution;p_{T}^{gen} (GeV/c);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{1000, 0, 10}, {200, -1.0f, 1.0f}}, true); + fRegistry.add("Track/primary/hPtGen_DeltaEta", "electron #eta resolution;p_{T}^{gen} (GeV/c);#eta^{rec} - #eta^{gen}", kTH2F, {{1000, 0, 10}, {100, -0.5f, 0.5f}}, true); + fRegistry.add("Track/primary/hPtGen_DeltaPhi", "electron #varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{1000, 0, 10}, {100, -0.5f, 0.5f}}, true); + fRegistry.addClone("Track/primary/", "Track/secondary/"); + } - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Track"); - THashList* list_track = reinterpret_cast(fMainList->FindObject("Track")); + void init(InitContext&) + { + DefineEMEventCut(); + DefineDileptonCut(); + addhistograms(); - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "DalitzEE"); - THashList* list_dalitzee = reinterpret_cast(fMainList->FindObject("DalitzEE")); + mRunNumber = 0; + d_bz = 0; - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Generated"); - THashList* list_gen = reinterpret_cast(fMainList->FindObject("Generated")); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_gen, "Generated", "dielectron"); + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + } - for (const auto& cut : fDalitzEECuts) { - const char* cutname = cut.GetName(); - o2::aod::pwgem::photon::histogram::AddHistClass(list_track, cutname); - o2::aod::pwgem::photon::histogram::AddHistClass(list_dalitzee, cutname); + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; } - // for single tracks - for (auto& cut : fDalitzEECuts) { - std::string_view cutname = cut.GetName(); - THashList* list = reinterpret_cast(fMainList->FindObject("Track")->FindObject(cutname.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list, "Track", "mc"); + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (std::fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + mRunNumber = collision.runNumber(); + return; } - // for DalitzEEs - for (auto& cut : fDalitzEECuts) { - std::string_view cutname = cut.GetName(); - THashList* list = reinterpret_cast(fMainList->FindObject("DalitzEE")->FindObject(cutname.data())); - // o2::aod::pwgem::photon::histogram::DefineHistograms(list, "DalitzEE", "mc"); - std::string histo_sub_group = "mc,"; - if (cfgDoDCAstudy) { - histo_sub_group += "dca"; + auto run3grp_timestamp = collision.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; } - o2::aod::pwgem::photon::histogram::DefineHistograms(list, "DalitzEE", histo_sub_group.data()); + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; } + mRunNumber = collision.runNumber(); } - void DefineCuts() + void DefineEMEventCut() { - TString cutNamesStr = fConfigDalitzEECuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fDalitzEECuts.push_back(*dalitzeecuts::GetCut(cutname)); - } - } - LOGF(info, "Number of Dalitz cuts = %d", fDalitzEECuts.size()); + fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); } - void init(InitContext&) + void DefineDileptonCut() { - DefineCuts(); - addhistograms(); // please call this after DefinCuts(); - TString ev_cut_name = fConfigEMEventCut.value; - fEMEventCut = *eventcuts::GetCut(ev_cut_name.Data()); - - fOutputEvent.setObject(reinterpret_cast(fMainList->FindObject("Event"))); - fOutputTrack.setObject(reinterpret_cast(fMainList->FindObject("Track"))); - fOutputDalitzEE.setObject(reinterpret_cast(fMainList->FindObject("DalitzEE"))); - fOutputGen.setObject(reinterpret_cast(fMainList->FindObject("Generated"))); + fDileptonCut = DalitzEECut("fDileptonCut", "fDileptonCut"); + + // for pair + fDileptonCut.SetMeeRange(dileptoncuts.cfg_min_mass, dileptoncuts.cfg_max_mass); + fDileptonCut.SetMaxPhivPairMeeDep([&](float mll) { return (mll - dileptoncuts.cfg_phiv_intercept) / dileptoncuts.cfg_phiv_slope; }); + fDileptonCut.ApplyPhiV(dileptoncuts.cfg_apply_phiv); + fDileptonCut.RequireITSibAny(dileptoncuts.cfg_require_itsib_any); + fDileptonCut.RequireITSib1st(dileptoncuts.cfg_require_itsib_1st); + + // for track + fDileptonCut.SetTrackPtRange(dileptoncuts.cfg_min_pt_track, 1e+10f); + fDileptonCut.SetTrackEtaRange(-dileptoncuts.cfg_max_eta_track, +dileptoncuts.cfg_max_eta_track); + fDileptonCut.SetMinNClustersTPC(dileptoncuts.cfg_min_ncluster_tpc); + fDileptonCut.SetMinNCrossedRowsTPC(dileptoncuts.cfg_min_ncrossedrows); + fDileptonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fDileptonCut.SetMaxFracSharedClustersTPC(dileptoncuts.cfg_max_frac_shared_clusters_tpc); + fDileptonCut.SetChi2PerClusterTPC(0.0, dileptoncuts.cfg_max_chi2tpc); + fDileptonCut.SetChi2PerClusterITS(0.0, dileptoncuts.cfg_max_chi2its); + fDileptonCut.SetNClustersITS(dileptoncuts.cfg_min_ncluster_its, 7); + fDileptonCut.SetMaxDcaXY(dileptoncuts.cfg_max_dcaxy); + fDileptonCut.SetMaxDcaZ(dileptoncuts.cfg_max_dcaz); + fDileptonCut.SetTrackDca3DRange(0.f, dileptoncuts.cfg_max_dca3dsigma_track); // in sigma + + // for eID + fDileptonCut.SetPIDScheme(dileptoncuts.cfg_pid_scheme); + fDileptonCut.SetTPCNsigmaElRange(dileptoncuts.cfg_min_TPCNsigmaEl, dileptoncuts.cfg_max_TPCNsigmaEl); + fDileptonCut.SetTPCNsigmaPiRange(dileptoncuts.cfg_min_TPCNsigmaPi, dileptoncuts.cfg_max_TPCNsigmaPi); + fDileptonCut.SetTOFNsigmaElRange(dileptoncuts.cfg_min_TOFNsigmaEl, dileptoncuts.cfg_max_TOFNsigmaEl); } - template - int FindLF(TTrack const& posmc, TTrack const& elemc, TMCTracks const& mcparticles) + template + int FindLF(TTrack const& posmc, TTrack const& elemc, TMCParticles const& mcparticles) { int arr[] = { - FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 111, mcparticles), FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 221, mcparticles), FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 331, mcparticles), FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 113, mcparticles), FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 223, mcparticles), FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 333, mcparticles), FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 443, mcparticles)}; + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 22, mcparticles), + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 111, mcparticles), + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 221, mcparticles), + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 331, mcparticles), + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 113, mcparticles), + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 223, mcparticles), + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 333, mcparticles), + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 443, mcparticles), + FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 100443, mcparticles)}; int size = sizeof(arr) / sizeof(*arr); int max = *std::max_element(arr, arr + size); return max; } - Partition uls_pairs = o2::aod::dalitzee::sign == 0; - Partition lspp_pairs = o2::aod::dalitzee::sign == +1; - Partition lsmm_pairs = o2::aod::dalitzee::sign == -1; - - SliceCache cache; - Preslice perCollision = aod::dalitzee::emeventId; - Partition grouped_collisions = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); // this goes to same event. + template + bool isInAcceptance(T const& t1) + { + if ((mctrackcuts.min_mcPt < t1.pt() && t1.pt() < mctrackcuts.max_mcPt) && std::fabs(t1.eta()) < mctrackcuts.max_mcEta) { + return true; + } else { + return false; + } + } - void processQCMC(MyCollisions const&, MyDalitzEEs const&, MyMCTracks const&, aod::EMMCParticles const& mcparticles, aod::EMMCEvents const&) + template + bool fillTruePairInfo(TCollision const& collision, TTrack1 const& t1, TTrack2 const& t2, TMCParticles const& mcparticles) { - THashList* list_ev_before = static_cast(fMainList->FindObject("Event")->FindObject(event_types[0].data())); - THashList* list_ev_after = static_cast(fMainList->FindObject("Event")->FindObject(event_types[1].data())); - THashList* list_dalitzee = static_cast(fMainList->FindObject("DalitzEE")); - THashList* list_track = static_cast(fMainList->FindObject("Track")); - double values[3] = {0, 0, 0}; - double values_single[4] = {0, 0, 0, 0}; - float dca_pos_3d = 999.f, dca_ele_3d = 999.f, dca_ee_3d = 999.f; - - for (auto& collision : grouped_collisions) { - float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { - continue; - } + if (!fDileptonCut.IsSelectedTrack(t1) || !fDileptonCut.IsSelectedTrack(t2)) { + return false; + } - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_before, "", collision); - if (!fEMEventCut.IsSelected(collision)) { - continue; - } - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_after, "", collision); - reinterpret_cast(list_ev_before->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - reinterpret_cast(list_ev_after->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - - auto uls_pairs_per_coll = uls_pairs->sliceByCached(o2::aod::dalitzee::emeventId, collision.globalIndex(), cache); - auto lspp_pairs_per_coll = lspp_pairs->sliceByCached(o2::aod::dalitzee::emeventId, collision.globalIndex(), cache); - auto lsmm_pairs_per_coll = lsmm_pairs->sliceByCached(o2::aod::dalitzee::emeventId, collision.globalIndex(), cache); - - for (const auto& cut : fDalitzEECuts) { - THashList* list_dalitzee_cut = static_cast(list_dalitzee->FindObject(cut.GetName())); - THashList* list_track_cut = static_cast(list_track->FindObject(cut.GetName())); - std::vector used_trackIds; - used_trackIds.reserve(uls_pairs_per_coll.size() * 2); - - int nuls = 0; - for (auto& uls_pair : uls_pairs_per_coll) { - auto pos = uls_pair.template posTrack_as(); - auto ele = uls_pair.template negTrack_as(); - - if (!cut.IsSelected(uls_pair)) { - continue; - } + if (!fDileptonCut.IsSelectedPair(t1, t2, d_bz)) { + return false; + } - auto posmc = pos.template emmcparticle_as(); - auto elemc = ele.template emmcparticle_as(); + auto t1mc = t1.template emmcparticle_as(); + auto t2mc = t2.template emmcparticle_as(); - if (posmc.pdgCode() != -11 || elemc.pdgCode() != 11) { - continue; - } + int mother_id = FindLF(t1mc, t2mc, mcparticles); + if (mother_id < 0) { + return false; + } + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + if (std::fabs(v12.Rapidity()) > maxY) { + return false; + } + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), d_bz); - int mother_id = FindLF(posmc, elemc, mcparticles); - int hfee_type = IsHF(posmc, elemc, mcparticles); - int photonid = FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 22, mcparticles); - if (mother_id < 0 && hfee_type < 0 && photonid < 0) { - continue; - } + if (mother_id > -1 && t1mc.pdgCode() * t2mc.pdgCode() < 0) { + auto mcmother = mcparticles.iteratorAt(mother_id); + if (cfgRequireTrueAssociation && (mcmother.emmceventId() != collision.emmceventId())) { + return false; + } - dca_pos_3d = pos.dca3DinSigma(); - dca_ele_3d = ele.dca3DinSigma(); - dca_ee_3d = std::sqrt((dca_pos_3d * dca_pos_3d + dca_ele_3d * dca_ele_3d) / 2.); - values[0] = uls_pair.mass(); - values[1] = uls_pair.pt(); - values[2] = dca_ee_3d; - - if (mother_id > -1) { - auto mcmother = mcparticles.iteratorAt(mother_id); - if (mcmother.isPhysicalPrimary() || mcmother.producedByGenerator()) { - - if (cfgDoDCAstudy) { - values_single[0] = uls_pair.mass(); - values_single[1] = dca_pos_3d; - values_single[2] = dca_ele_3d; - values_single[3] = dca_ee_3d; - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_uls_dca_same"))->Fill(values_single); + if (mcmother.isPhysicalPrimary() || mcmother.producedByGenerator()) { + if ((t1mc.isPhysicalPrimary() || t1mc.producedByGenerator()) && (t2mc.isPhysicalPrimary() || t2mc.producedByGenerator())) { + switch (std::abs(mcmother.pdgCode())) { + case 111: + fRegistry.fill(HIST("Pair/sm/Pi0/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/sm/Pi0/hMvsPhiV"), phiv, v12.M()); + if (std::find(used_trackIds.begin(), used_trackIds.end(), t1.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t1.globalIndex()); + fillTrackInfo<0>(t1); } - - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_uls_same"))->Fill(values); - - if (mcmother.pdgCode() == 111) { - reinterpret_cast(list_dalitzee_cut->FindObject("hMvsPhiV_Pi0"))->Fill(uls_pair.phiv(), uls_pair.mass()); - reinterpret_cast(list_dalitzee_cut->FindObject("hMvsOPA_Pi0"))->Fill(uls_pair.opangle(), uls_pair.mass()); - } else if (mcmother.pdgCode() == 221) { - reinterpret_cast(list_dalitzee_cut->FindObject("hMvsPhiV_Eta"))->Fill(uls_pair.phiv(), uls_pair.mass()); - reinterpret_cast(list_dalitzee_cut->FindObject("hMvsOPA_Eta"))->Fill(uls_pair.opangle(), uls_pair.mass()); + if (std::find(used_trackIds.begin(), used_trackIds.end(), t2.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t2.globalIndex()); + fillTrackInfo<0>(t2); } - - switch (abs(mcmother.pdgCode())) { - case 111: - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_mc_rec_Pi0"))->Fill(values); - break; - case 221: - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_mc_rec_Eta"))->Fill(values); - break; - case 331: - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_mc_rec_EtaPrime"))->Fill(values); - break; - case 113: - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_mc_rec_Rho"))->Fill(values); - break; - case 223: - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_mc_rec_Omega"))->Fill(values); - break; - case 333: - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_mc_rec_Phi"))->Fill(values); - break; - case 443: { - if (IsFromBeauty(mcmother, mcparticles) > 0) { - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_mc_rec_NonPromptJpsi"))->Fill(values); - } else { - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_mc_rec_PromptJpsi"))->Fill(values); - } - break; - } - default: - break; + break; + case 221: + fRegistry.fill(HIST("Pair/sm/Eta/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/sm/Eta/hMvsPhiV"), phiv, v12.M()); + if (std::find(used_trackIds.begin(), used_trackIds.end(), t1.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t1.globalIndex()); + fillTrackInfo<0>(t1); } - - nuls++; - for (auto& track : {pos, ele}) { - if (std::find(used_trackIds.begin(), used_trackIds.end(), track.globalIndex()) == used_trackIds.end()) { - o2::aod::pwgem::photon::histogram::FillHistClass(list_track_cut, "", track); - used_trackIds.emplace_back(track.globalIndex()); - auto mctrack = track.template emmcparticle_as(); - reinterpret_cast(fMainList->FindObject("Track")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaPtOverPtGen"))->Fill(mctrack.pt(), (track.pt() - mctrack.pt()) / mctrack.pt()); - reinterpret_cast(fMainList->FindObject("Track")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaEta"))->Fill(mctrack.pt(), track.eta() - mctrack.eta()); - reinterpret_cast(fMainList->FindObject("Track")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaPhi"))->Fill(mctrack.pt(), track.phi() - mctrack.phi()); - } + if (std::find(used_trackIds.begin(), used_trackIds.end(), t2.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t2.globalIndex()); + fillTrackInfo<0>(t2); + } + break; + case 331: + fRegistry.fill(HIST("Pair/sm/EtaPrime/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/sm/EtaPrime/hMvsPhiV"), phiv, v12.M()); + if (std::find(used_trackIds.begin(), used_trackIds.end(), t1.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t1.globalIndex()); + fillTrackInfo<0>(t1); } - } // end of LF - } else if (hfee_type > -1) { - if ((posmc.isPhysicalPrimary() || posmc.producedByGenerator()) && (elemc.isPhysicalPrimary() || elemc.producedByGenerator())) { - switch (hfee_type) { - case static_cast(EM_HFeeType::kCe_Ce): - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_mc_rec_Ce_Ce"))->Fill(values); - break; - case static_cast(EM_HFeeType::kBe_Be): - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_mc_rec_Be_Be"))->Fill(values); - break; - case static_cast(EM_HFeeType::kBCe_BCe): - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_mc_rec_BCe_BCe"))->Fill(values); - break; - case static_cast(EM_HFeeType::kBCe_Be_SameB): // ULS - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_mc_rec_BCe_Be_SameB"))->Fill(values); - break; - case static_cast(EM_HFeeType::kBCe_Be_DiffB): // LS - LOGF(info, "You should not see kBCe_Be_DiffB in ULS. Good luck."); - break; - default: - break; + if (std::find(used_trackIds.begin(), used_trackIds.end(), t2.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t2.globalIndex()); + fillTrackInfo<0>(t2); } - nuls++; - } - } else if (photonid > -1) { - auto mcphoton = mcparticles.iteratorAt(photonid); - if ((mcphoton.isPhysicalPrimary() || mcphoton.producedByGenerator()) && IsEleFromPC(elemc, mcparticles) && IsEleFromPC(posmc, mcparticles)) { - reinterpret_cast(list_dalitzee_cut->FindObject("hMvsPhiV_Photon"))->Fill(uls_pair.phiv(), uls_pair.mass()); - reinterpret_cast(list_dalitzee_cut->FindObject("hMvsOPA_Photon"))->Fill(uls_pair.opangle(), uls_pair.mass()); - } + break; + case 113: + fRegistry.fill(HIST("Pair/sm/Rho/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/sm/Rho/hMvsPhiV"), phiv, v12.M()); + if (std::find(used_trackIds.begin(), used_trackIds.end(), t1.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t1.globalIndex()); + fillTrackInfo<0>(t1); + } + if (std::find(used_trackIds.begin(), used_trackIds.end(), t2.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t2.globalIndex()); + fillTrackInfo<0>(t2); + } + break; + case 223: + fRegistry.fill(HIST("Pair/sm/Omega/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/sm/Omega/hMvsPhiV"), phiv, v12.M()); + if (std::find(used_trackIds.begin(), used_trackIds.end(), t1.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t1.globalIndex()); + fillTrackInfo<0>(t1); + } + if (std::find(used_trackIds.begin(), used_trackIds.end(), t2.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t2.globalIndex()); + fillTrackInfo<0>(t2); + } + break; + case 333: + fRegistry.fill(HIST("Pair/sm/Phi/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/sm/Phi/hMvsPhiV"), phiv, v12.M()); + if (std::find(used_trackIds.begin(), used_trackIds.end(), t1.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t1.globalIndex()); + fillTrackInfo<0>(t1); + } + if (std::find(used_trackIds.begin(), used_trackIds.end(), t2.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t2.globalIndex()); + fillTrackInfo<0>(t2); + } + break; + default: + break; } - } // end of uls pair loop - reinterpret_cast(list_dalitzee_cut->FindObject("hNpair_uls"))->Fill(nuls); - - int nlspp = 0; - for (auto& lspp_pair : lspp_pairs_per_coll) { - auto pos = lspp_pair.template posTrack_as(); - auto ele = lspp_pair.template negTrack_as(); - - if (!cut.IsSelected(lspp_pair)) { - continue; + } else if (!(t1mc.isPhysicalPrimary() || t1mc.producedByGenerator()) && !(t2mc.isPhysicalPrimary() || t2mc.producedByGenerator())) { + switch (std::abs(mcmother.pdgCode())) { + case 22: + fRegistry.fill(HIST("Pair/sm/Photon/hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/sm/Photon/hMvsPhiV"), phiv, v12.M()); + if (std::find(used_trackIds.begin(), used_trackIds.end(), t1.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t1.globalIndex()); + fillTrackInfo<1>(t1); + } + if (std::find(used_trackIds.begin(), used_trackIds.end(), t2.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t2.globalIndex()); + fillTrackInfo<1>(t2); + } + break; + default: + break; } + } // end of primary/secondary selection + } // end of primary selection for same mother + } + return true; + } - auto posmc = pos.template emmcparticle_as(); - auto elemc = ele.template emmcparticle_as(); + template + void fillTrackInfo(TTrack const& track) + { + auto mctrack = track.template emmcparticle_as(); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hPt"), track.pt()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hQoverPt"), track.sign() / track.pt()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hEtaPhi"), track.phi(), track.eta()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hDCAxyz"), track.dcaXY(), track.dcaZ()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hDCAxyzSigma"), track.dcaXY() / std::sqrt(track.cYY()), track.dcaZ() / std::sqrt(track.cZZ())); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hDCAxyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hDCAzRes_Pt"), track.pt(), std::sqrt(track.cZZ()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hNclsITS"), track.itsNCls()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hNclsTPC"), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hTPCNclsShared"), track.pt(), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hChi2ITS"), track.itsChi2NCl()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hITSClusterMap"), track.itsClusterMap()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hMeanClusterSizeITS"), track.p(), track.meanClusterSizeITS() * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hTOFNsigmaEl"), track.p(), track.tofNSigmaEl()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hTOFNsigmaPi"), track.p(), track.tofNSigmaPi()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hTOFbeta"), track.p(), track.beta()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hPtGen_DeltaPtOverPtGen"), mctrack.pt(), (track.pt() - mctrack.pt()) / mctrack.pt()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hPtGen_DeltaEta"), mctrack.pt(), track.eta() - mctrack.eta()); + fRegistry.fill(HIST("Track/") + HIST(track_types[tracktype]) + HIST("hPtGen_DeltaPhi"), mctrack.pt(), track.phi() - mctrack.phi()); + } - if (posmc.pdgCode() != -11 || elemc.pdgCode() != -11) { - continue; - } + std::vector used_trackIds; + SliceCache cache; + Preslice perCollision_track = aod::emprimaryelectron::emeventId; + Filter trackFilter = dileptoncuts.cfg_min_pt_track < o2::aod::track::pt && nabs(o2::aod::track::eta) < dileptoncuts.cfg_max_eta_track && o2::aod::track::tpcChi2NCl < dileptoncuts.cfg_max_chi2tpc && o2::aod::track::itsChi2NCl < dileptoncuts.cfg_max_chi2its && nabs(o2::aod::track::dcaXY) < dileptoncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dileptoncuts.cfg_max_dcaz; + Filter pidFilter = dileptoncuts.cfg_min_TPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < dileptoncuts.cfg_max_TPCNsigmaEl && (o2::aod::pidtpc::tpcNSigmaPi < dileptoncuts.cfg_min_TPCNsigmaPi || dileptoncuts.cfg_max_TPCNsigmaPi < o2::aod::pidtpc::tpcNSigmaPi); + using FilteredMyMCTracks = soa::Filtered; + Partition posTracks = o2::aod::emprimaryelectron::sign > int8_t(0); + Partition negTracks = o2::aod::emprimaryelectron::sign < int8_t(0); - int hfee_type = IsHF(posmc, elemc, mcparticles); - if (hfee_type < 0) { - continue; - } + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + using FilteredMyCollisions = soa::Filtered; - dca_pos_3d = pos.dca3DinSigma(); - dca_ele_3d = ele.dca3DinSigma(); - dca_ee_3d = std::sqrt((dca_pos_3d * dca_pos_3d + dca_ele_3d * dca_ele_3d) / 2.); - values[0] = lspp_pair.mass(); - values[1] = lspp_pair.pt(); - values[2] = dca_ee_3d; - - if ((posmc.isPhysicalPrimary() || posmc.producedByGenerator()) && (elemc.isPhysicalPrimary() || elemc.producedByGenerator())) { - switch (hfee_type) { - case static_cast(EM_HFeeType::kCe_Ce): - LOGF(info, "You should not see kCe_Ce in LS++. Good luck."); - break; - case static_cast(EM_HFeeType::kBe_Be): - LOGF(info, "You should not see kBe_Be in LS++. Good luck."); - break; - case static_cast(EM_HFeeType::kBCe_BCe): - LOGF(info, "You should not see kBCe_BCe in LS++. Good luck."); - break; - case static_cast(EM_HFeeType::kBCe_Be_SameB): // ULS - LOGF(info, "You should not see kBCe_Be_SameB in LS++. Good luck."); - break; - case static_cast(EM_HFeeType::kBCe_Be_DiffB): // LS - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_mc_rec_BCe_Be_DiffB"))->Fill(values); - break; - default: - break; - } - } - nlspp++; - for (auto& track : {pos, ele}) { - if (std::find(used_trackIds.begin(), used_trackIds.end(), track.globalIndex()) == used_trackIds.end()) { - o2::aod::pwgem::photon::histogram::FillHistClass(list_track_cut, "", track); - used_trackIds.emplace_back(track.globalIndex()); - auto mctrack = track.template emmcparticle_as(); - reinterpret_cast(fMainList->FindObject("Track")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaPtOverPtGen"))->Fill(mctrack.pt(), (track.pt() - mctrack.pt()) / mctrack.pt()); - reinterpret_cast(fMainList->FindObject("Track")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaEta"))->Fill(mctrack.pt(), track.eta() - mctrack.eta()); - reinterpret_cast(fMainList->FindObject("Track")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaPhi"))->Fill(mctrack.pt(), track.phi() - mctrack.phi()); - } - } - } // end of lspp pair loop - reinterpret_cast(list_dalitzee_cut->FindObject("hNpair_lspp"))->Fill(nlspp); + void processQCMC(FilteredMyCollisions const& collisions, FilteredMyMCTracks const& tracks, aod::EMMCParticles const& mcparticles, aod::EMMCEvents const&) + { + used_trackIds.reserve(tracks.size()); - int nlsmm = 0; - for (auto& lsmm_pair : lsmm_pairs_per_coll) { - auto pos = lsmm_pair.template posTrack_as(); - auto ele = lsmm_pair.template negTrack_as(); + for (auto& collision : collisions) { + initCCDB(collision); - if (!cut.IsSelected(lsmm_pair)) { - continue; - } + float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (!(eventcuts.cfgOccupancyMin <= collision.trackOccupancyInTimeRange() && collision.trackOccupancyInTimeRange() < eventcuts.cfgOccupancyMax)) { + continue; + } + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 12.0); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 12.0); // accepted - auto posmc = pos.template emmcparticle_as(); - auto elemc = ele.template emmcparticle_as(); + auto posTracks_per_coll = posTracks->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + // LOGF(info, "centrality = %f , posTracks_per_coll.size() = %d, negTracks_per_coll.size() = %d", centralities[cfgCentEstimator], posTracks_per_coll.size(), negTracks_per_coll.size()); - if (posmc.pdgCode() != 11 || elemc.pdgCode() != 11) { - continue; - } + for (auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + fillTruePairInfo(collision, pos, ele, mcparticles); + } // end of ULS pair loop - int hfee_type = IsHF(posmc, elemc, mcparticles); - if (hfee_type < 0) { - continue; - } + } // end of collision loop - dca_pos_3d = pos.dca3DinSigma(); - dca_ele_3d = ele.dca3DinSigma(); - dca_ee_3d = std::sqrt((dca_pos_3d * dca_pos_3d + dca_ele_3d * dca_ele_3d) / 2.); - values[0] = lsmm_pair.mass(); - values[1] = lsmm_pair.pt(); - values[2] = dca_ee_3d; - - if ((posmc.isPhysicalPrimary() || posmc.producedByGenerator()) && (elemc.isPhysicalPrimary() || elemc.producedByGenerator())) { - switch (hfee_type) { - case static_cast(EM_HFeeType::kCe_Ce): - LOGF(info, "You should not see kCe_Ce in LS--. Good luck."); - break; - case static_cast(EM_HFeeType::kBe_Be): - LOGF(info, "You should not see kBe_Be in LS--. Good luck."); - break; - case static_cast(EM_HFeeType::kBCe_BCe): - LOGF(info, "You should not see kBCe_BCe in LS--. Good luck."); - break; - case static_cast(EM_HFeeType::kBCe_Be_SameB): // ULS - LOGF(info, "You should not see kBCe_Be_SameB in LS--. Good luck."); - break; - case static_cast(EM_HFeeType::kBCe_Be_DiffB): // LS - reinterpret_cast(list_dalitzee_cut->FindObject("hs_dilepton_mc_rec_BCe_Be_DiffB"))->Fill(values); - break; - default: - break; - } - } - nlsmm++; - for (auto& track : {pos, ele}) { - if (std::find(used_trackIds.begin(), used_trackIds.end(), track.globalIndex()) == used_trackIds.end()) { - o2::aod::pwgem::photon::histogram::FillHistClass(list_track_cut, "", track); - used_trackIds.emplace_back(track.globalIndex()); - auto mctrack = track.template emmcparticle_as(); - reinterpret_cast(fMainList->FindObject("Track")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaPtOverPtGen"))->Fill(mctrack.pt(), (track.pt() - mctrack.pt()) / mctrack.pt()); - reinterpret_cast(fMainList->FindObject("Track")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaEta"))->Fill(mctrack.pt(), track.eta() - mctrack.eta()); - reinterpret_cast(fMainList->FindObject("Track")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaPhi"))->Fill(mctrack.pt(), track.phi() - mctrack.phi()); - } - } - } // end of lsmm pair loop - reinterpret_cast(list_dalitzee_cut->FindObject("hNpair_lsmm"))->Fill(nlsmm); - - used_trackIds.clear(); - used_trackIds.shrink_to_fit(); - } // end of cut loop - } // end of collision loop - } // end of process + used_trackIds.clear(); + used_trackIds.shrink_to_fit(); + } // end of process PROCESS_SWITCH(DalitzEEQCMC, processQCMC, "run Dalitz QC", true); - Configurable min_mcPt{"min_mcPt", 0.05, "min. MC pT"}; - Configurable max_mcPt{"max_mcPt", 1e+10, "max. MC pT"}; - Configurable max_mcEta{"max_mcEta", 0.9, "max. MC eta"}; - Partition posTracks = o2::aod::mcparticle::pdgCode == -11; // e+ - Partition negTracks = o2::aod::mcparticle::pdgCode == +11; // e- + Partition posTracksMC = o2::aod::mcparticle::pdgCode == -11; // e+ + Partition negTracksMC = o2::aod::mcparticle::pdgCode == +11; // e- PresliceUnsorted perMcCollision = aod::emmcparticle::emmceventId; - void processGen(MyCollisions const&, aod::EMMCEvents const&, aod::EMMCParticles const& mcparticles) + void processGen(MyCollisions const& collisions, aod::EMMCEvents const&, aod::EMMCParticles const& mcparticles) { // loop over mc stack and fill histograms for pure MC truth signals // all MC tracks which belong to the MC event corresponding to the current reconstructed event - for (auto& collision : grouped_collisions) { + + for (auto& collision : collisions) { float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } - auto mccollision = collision.emmcevent(); - // LOGF(info, "mccollision.globalIndex() = %d", mccollision.globalIndex()); - // auto mctracks_coll = mcparticles.sliceBy(perMcCollision, mccollision.globalIndex()); - - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hCollisionCounter"))->Fill(1.0); - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hZvtx_before"))->Fill(mccollision.posZ()); if (!fEMEventCut.IsSelected(collision)) { continue; } + if (!(eventcuts.cfgOccupancyMin <= collision.trackOccupancyInTimeRange() && collision.trackOccupancyInTimeRange() < eventcuts.cfgOccupancyMax)) { + continue; + } + auto mccollision = collision.emmcevent_as(); + + auto posTracks_per_coll = posTracksMC->sliceByCachedUnsorted(o2::aod::emmcparticle::emmceventId, mccollision.globalIndex(), cache); + auto negTracks_per_coll = negTracksMC->sliceByCachedUnsorted(o2::aod::emmcparticle::emmceventId, mccollision.globalIndex(), cache); - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hCollisionCounter"))->Fill(4.0); - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hZvtx_after"))->Fill(mccollision.posZ()); - auto posTracks_per_coll = posTracks->sliceByCachedUnsorted(o2::aod::emmcparticle::emmceventId, mccollision.globalIndex(), cache); - auto negTracks_per_coll = negTracks->sliceByCachedUnsorted(o2::aod::emmcparticle::emmceventId, mccollision.globalIndex(), cache); - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { + for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS // LOGF(info, "pdg1 = %d, pdg2 = %d", t1.pdgCode(), t2.pdgCode()); - if (t1.pt() < min_mcPt || max_mcPt < t1.pt() || abs(t1.eta()) > max_mcEta) { - continue; - } - if (t2.pt() < min_mcPt || max_mcPt < t2.pt() || abs(t2.eta()) > max_mcEta) { + if (!isInAcceptance(t1) || !isInAcceptance(t2)) { continue; } @@ -507,167 +573,46 @@ struct DalitzEEQCMC { } int mother_id = FindLF(t1, t2, mcparticles); - int hfee_type = IsHF(t1, t2, mcparticles); - if (mother_id < 0 && hfee_type < 0) { + if (mother_id < 0) { continue; } ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + if (std::fabs(v12.Rapidity()) > maxY) { + continue; + } + if (mother_id > -1) { auto mcmother = mcparticles.iteratorAt(mother_id); if (mcmother.isPhysicalPrimary() || mcmother.producedByGenerator()) { - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hMvsPt"))->Fill(v12.M(), v12.Pt()); - switch (abs(mcmother.pdgCode())) { + switch (std::abs(mcmother.pdgCode())) { case 111: - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hMvsPt_Pi0"))->Fill(v12.M(), v12.Pt()); + fRegistry.fill(HIST("Generated/sm/Pi0/hMvsPt"), v12.M(), v12.Pt()); break; case 221: - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hMvsPt_Eta"))->Fill(v12.M(), v12.Pt()); + fRegistry.fill(HIST("Generated/sm/Eta/hMvsPt"), v12.M(), v12.Pt()); break; case 331: - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hMvsPt_EtaPrime"))->Fill(v12.M(), v12.Pt()); + fRegistry.fill(HIST("Generated/sm/EtaPrime/hMvsPt"), v12.M(), v12.Pt()); break; case 113: - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hMvsPt_Rho"))->Fill(v12.M(), v12.Pt()); + fRegistry.fill(HIST("Generated/sm/Rho/hMvsPt"), v12.M(), v12.Pt()); break; case 223: - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hMvsPt_Omega"))->Fill(v12.M(), v12.Pt()); + fRegistry.fill(HIST("Generated/sm/Omega/hMvsPt"), v12.M(), v12.Pt()); break; case 333: - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hMvsPt_Phi"))->Fill(v12.M(), v12.Pt()); - break; - case 443: { - if (IsFromBeauty(mcmother, mcparticles) > 0) { - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hMvsPt_NonPromptJpsi"))->Fill(v12.M(), v12.Pt()); - } else { - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hMvsPt_PromptJpsi"))->Fill(v12.M(), v12.Pt()); - } + fRegistry.fill(HIST("Generated/sm/Phi/hMvsPt"), v12.M(), v12.Pt()); break; - } default: break; } } - } else if (hfee_type > -1) { - switch (hfee_type) { - case static_cast(EM_HFeeType::kCe_Ce): - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hMvsPt_Ce_Ce"))->Fill(v12.M(), v12.Pt()); - break; - case static_cast(EM_HFeeType::kBe_Be): - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hMvsPt_Be_Be"))->Fill(v12.M(), v12.Pt()); - break; - case static_cast(EM_HFeeType::kBCe_BCe): - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hMvsPt_BCe_BCe"))->Fill(v12.M(), v12.Pt()); - break; - case static_cast(EM_HFeeType::kBCe_Be_SameB): // ULS - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hMvsPt_BCe_Be_SameB"))->Fill(v12.M(), v12.Pt()); - break; - case static_cast(EM_HFeeType::kBCe_Be_DiffB): // LS - LOGF(info, "You should not see kBCe_Be_DiffB in ULS. Good luck."); - break; - default: - break; - } } } // end of true ULS pair loop - - for (auto& [t1, t2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { - // LOGF(info, "pdg1 = %d, pdg2 = %d", t1.pdgCode(), t2.pdgCode()); - - if (t1.pt() < min_mcPt || max_mcPt < t1.pt() || abs(t1.eta()) > max_mcEta) { - continue; - } - if (t2.pt() < min_mcPt || max_mcPt < t2.pt() || abs(t2.eta()) > max_mcEta) { - continue; - } - - if (!t1.isPhysicalPrimary() && !t1.producedByGenerator()) { - continue; - } - if (!t2.isPhysicalPrimary() && !t2.producedByGenerator()) { - continue; - } - - int hfee_type = IsHF(t1, t2, mcparticles); - if (hfee_type < 0) { - continue; - } - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - if (hfee_type > -1) { - switch (hfee_type) { - case static_cast(EM_HFeeType::kCe_Ce): - LOGF(info, "You should not see kCe_Ce in LS++. Good luck."); - break; - case static_cast(EM_HFeeType::kBe_Be): - LOGF(info, "You should not see kBe_Be in LS++. Good luck."); - break; - case static_cast(EM_HFeeType::kBCe_BCe): - LOGF(info, "You should not see kBCe_BCe in LS++. Good luck."); - break; - case static_cast(EM_HFeeType::kBCe_Be_SameB): // ULS - LOGF(info, "You should not see kBCe_Be_SameB in LS++. Good luck."); - break; - case static_cast(EM_HFeeType::kBCe_Be_DiffB): // LS - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hMvsPt_BCe_Be_DiffB"))->Fill(v12.M(), v12.Pt()); - break; - default: - break; - } - } - } // end of true LS++ pair loop - - for (auto& [t1, t2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { - // LOGF(info, "pdg1 = %d, pdg2 = %d", t1.pdgCode(), t2.pdgCode()); - - if (t1.pt() < min_mcPt || max_mcPt < t1.pt() || abs(t1.eta()) > max_mcEta) { - continue; - } - if (t2.pt() < min_mcPt || max_mcPt < t2.pt() || abs(t2.eta()) > max_mcEta) { - continue; - } - - if (!t1.isPhysicalPrimary() && !t1.producedByGenerator()) { - continue; - } - if (!t2.isPhysicalPrimary() && !t2.producedByGenerator()) { - continue; - } - - int hfee_type = IsHF(t1, t2, mcparticles); - if (hfee_type < 0) { - continue; - } - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - if (hfee_type > -1) { - switch (hfee_type) { - case static_cast(EM_HFeeType::kCe_Ce): - LOGF(info, "You should not see kCe_Ce in LS--. Good luck."); - break; - case static_cast(EM_HFeeType::kBe_Be): - LOGF(info, "You should not see kBe_Be in LS--. Good luck."); - break; - case static_cast(EM_HFeeType::kBCe_BCe): - LOGF(info, "You should not see kBCe_BCe in LS--. Good luck."); - break; - case static_cast(EM_HFeeType::kBCe_Be_SameB): // ULS - LOGF(info, "You should not see kBCe_Be_SameB in LS--. Good luck."); - break; - case static_cast(EM_HFeeType::kBCe_Be_DiffB): // LS - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hMvsPt_BCe_Be_DiffB"))->Fill(v12.M(), v12.Pt()); - break; - default: - break; - } - } - } // end of true LS++ pair loop - } // end of collision loop } PROCESS_SWITCH(DalitzEEQCMC, processGen, "run genrated info", true); diff --git a/PWGEM/PhotonMeson/Tasks/dalitzMuMuQC.cxx b/PWGEM/PhotonMeson/Tasks/dalitzMuMuQC.cxx deleted file mode 100644 index 00d4cffbff4..00000000000 --- a/PWGEM/PhotonMeson/Tasks/dalitzMuMuQC.cxx +++ /dev/null @@ -1,349 +0,0 @@ -// 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. -// -// ======================== -// -// This code runs loop over dalitz ee table for dalitz QC. -// Please write to: daiki.sekihata@cern.ch - -#include -#include "TString.h" -#include "THashList.h" -#include "TDirectory.h" -#include "Math/Vector4D.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" - -#include "Common/Core/RecoDecay.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" -#include "PWGEM/PhotonMeson/Core/CutsLibrary.h" -#include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" - -using namespace o2; -using namespace o2::aod; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::soa; -using namespace o2::aod::pwgem::photon; -using std::array; - -using MyCollisions = soa::Join; -using MyCollision = MyCollisions::iterator; - -using MyDalitzMuMus = soa::Join; -using MyDalitzMuMu = MyDalitzMuMus::iterator; - -using MyTracks = soa::Join; -using MyTrack = MyTracks::iterator; - -struct DalitzMuMuQC { - Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; - Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; - Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; - - Configurable fConfigDalitzMuMuCuts{"cfgDalitzMuMuCuts", "nocut", "Comma separated list of dalitz mumu cuts"}; - std::vector fDalitzMuMuCuts; - - Configurable fConfigEMEventCut{"cfgEMEventCut", "minbias", "em event cut"}; // only 1 event cut per wagon - EMEventCut fEMEventCut; - static constexpr std::string_view event_types[2] = {"before", "after"}; - - OutputObj fOutputEvent{"Event"}; - OutputObj fOutputTrack{"Track"}; - OutputObj fOutputDalitzMuMu{"DalitzMuMu"}; - THashList* fMainList = new THashList(); - bool doMix = false; - - void addhistograms() - { - fMainList->SetOwner(true); - fMainList->SetName("fMainList"); - - // create sub lists first. - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Event"); - THashList* list_ev = reinterpret_cast(fMainList->FindObject("Event")); - for (const auto& evtype : event_types) { - THashList* list_ev_type = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_ev, evtype.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_ev_type, "Event", evtype.data()); - } - - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Track"); - THashList* list_track = reinterpret_cast(fMainList->FindObject("Track")); - - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "DalitzMuMu"); - THashList* list_dalitzmumu = reinterpret_cast(fMainList->FindObject("DalitzMuMu")); - - for (const auto& cut : fDalitzMuMuCuts) { - const char* cutname = cut.GetName(); - o2::aod::pwgem::photon::histogram::AddHistClass(list_track, cutname); - o2::aod::pwgem::photon::histogram::AddHistClass(list_dalitzmumu, cutname); - } - - // for single tracks - for (auto& cut : fDalitzMuMuCuts) { - std::string_view cutname = cut.GetName(); - THashList* list = reinterpret_cast(fMainList->FindObject("Track")->FindObject(cutname.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list, "Track", "Mu"); - } - - // for DalitzMuMus - for (auto& cut : fDalitzMuMuCuts) { - std::string_view cutname = cut.GetName(); - THashList* list = reinterpret_cast(fMainList->FindObject("DalitzMuMu")->FindObject(cutname.data())); - - if (doMix) { - o2::aod::pwgem::photon::histogram::DefineHistograms(list, "DalitzMuMu", "mix"); - } else { - o2::aod::pwgem::photon::histogram::DefineHistograms(list, "DalitzMuMu", ""); - } - } - } - - void DefineCuts() - { - TString cutNamesStr = fConfigDalitzMuMuCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fDalitzMuMuCuts.push_back(*dalitzeecuts::GetCut(cutname)); - } - } - LOGF(info, "Number of Dalitz cuts = %d", fDalitzMuMuCuts.size()); - } - - void init(InitContext& context) - { - if (context.mOptions.get("processEventMixing")) { - doMix = true; - } - - DefineCuts(); - addhistograms(); // please call this after DefinCuts(); - TString ev_cut_name = fConfigEMEventCut.value; - fEMEventCut = *eventcuts::GetCut(ev_cut_name.Data()); - - fOutputEvent.setObject(reinterpret_cast(fMainList->FindObject("Event"))); - fOutputTrack.setObject(reinterpret_cast(fMainList->FindObject("Track"))); - fOutputDalitzMuMu.setObject(reinterpret_cast(fMainList->FindObject("DalitzMuMu"))); - } - - Partition uls_pairs = o2::aod::dalitzmumu::sign == 0; - Partition lspp_pairs = o2::aod::dalitzmumu::sign == +1; - Partition lsmm_pairs = o2::aod::dalitzmumu::sign == -1; - - SliceCache cache; - Preslice perCollision = aod::dalitzmumu::emeventId; - Preslice perCollision_track = aod::emprimarymuon::emeventId; - Partition grouped_collisions = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); // this goes to same event. - - std::vector used_trackIds; - - void processQC(MyCollisions const&, MyDalitzMuMus const&, MyTracks const&) - { - THashList* list_ev_before = static_cast(fMainList->FindObject("Event")->FindObject(event_types[0].data())); - THashList* list_ev_after = static_cast(fMainList->FindObject("Event")->FindObject(event_types[1].data())); - THashList* list_dalitzmumu = static_cast(fMainList->FindObject("DalitzMuMu")); - THashList* list_track = static_cast(fMainList->FindObject("Track")); - double values[3] = {0, 0, 0}; - float dca_pos_3d = 999.f, dca_ele_3d = 999.f, dca_ee_3d = 999.f; - - for (auto& collision : grouped_collisions) { - float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { - continue; - } - - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_before, "", collision); - if (!fEMEventCut.IsSelected(collision)) { - continue; - } - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_after, "", collision); - reinterpret_cast(list_ev_before->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - reinterpret_cast(list_ev_after->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - - auto uls_pairs_per_coll = uls_pairs->sliceByCached(o2::aod::dalitzmumu::emeventId, collision.globalIndex(), cache); - auto lspp_pairs_per_coll = lspp_pairs->sliceByCached(o2::aod::dalitzmumu::emeventId, collision.globalIndex(), cache); - auto lsmm_pairs_per_coll = lsmm_pairs->sliceByCached(o2::aod::dalitzmumu::emeventId, collision.globalIndex(), cache); - - for (const auto& cut : fDalitzMuMuCuts) { - THashList* list_dalitzmumu_cut = static_cast(list_dalitzmumu->FindObject(cut.GetName())); - THashList* list_track_cut = static_cast(list_track->FindObject(cut.GetName())); - used_trackIds.reserve(uls_pairs_per_coll.size() * 2); - - int nuls = 0, nlspp = 0, nlsmm = 0; - for (auto& uls_pair : uls_pairs_per_coll) { - auto pos = uls_pair.template posTrack_as(); - auto ele = uls_pair.template negTrack_as(); - - if (cut.IsSelected(uls_pair)) { - dca_pos_3d = pos.dca3DinSigma(); - dca_ele_3d = ele.dca3DinSigma(); - dca_ee_3d = std::sqrt((dca_pos_3d * dca_pos_3d + dca_ele_3d * dca_ele_3d) / 2.); - - values[0] = uls_pair.mass(); - values[1] = uls_pair.pt(); - values[2] = dca_ee_3d; - reinterpret_cast(list_dalitzmumu_cut->FindObject("hs_dilepton_uls_same"))->Fill(values); - nuls++; - for (auto& track : {pos, ele}) { - if (std::find(used_trackIds.begin(), used_trackIds.end(), track.globalIndex()) == used_trackIds.end()) { - o2::aod::pwgem::photon::histogram::FillHistClass(list_track_cut, "", track); - used_trackIds.emplace_back(track.globalIndex()); - } - } - } - } // end of uls pair loop - reinterpret_cast(list_dalitzmumu_cut->FindObject("hNpair_uls"))->Fill(nuls); - - for (auto& lspp_pair : lspp_pairs_per_coll) { - auto pos = lspp_pair.template posTrack_as(); - auto ele = lspp_pair.template negTrack_as(); - if (cut.IsSelected(lspp_pair)) { - dca_pos_3d = pos.dca3DinSigma(); - dca_ele_3d = ele.dca3DinSigma(); - dca_ee_3d = std::sqrt((dca_pos_3d * dca_pos_3d + dca_ele_3d * dca_ele_3d) / 2.); - - values[0] = lspp_pair.mass(); - values[1] = lspp_pair.pt(); - values[2] = dca_ee_3d; - reinterpret_cast(list_dalitzmumu_cut->FindObject("hs_dilepton_lspp_same"))->Fill(values); - nlspp++; - } - } // end of lspp pair loop - reinterpret_cast(list_dalitzmumu_cut->FindObject("hNpair_lspp"))->Fill(nlspp); - - for (auto& lsmm_pair : lsmm_pairs_per_coll) { - auto pos = lsmm_pair.template posTrack_as(); - auto ele = lsmm_pair.template negTrack_as(); - if (cut.IsSelected(lsmm_pair)) { - dca_pos_3d = pos.dca3DinSigma(); - dca_ele_3d = ele.dca3DinSigma(); - dca_ee_3d = std::sqrt((dca_pos_3d * dca_pos_3d + dca_ele_3d * dca_ele_3d) / 2.); - - values[0] = lsmm_pair.mass(); - values[1] = lsmm_pair.pt(); - values[2] = dca_ee_3d; - reinterpret_cast(list_dalitzmumu_cut->FindObject("hs_dilepton_lsmm_same"))->Fill(values); - nlsmm++; - } - } // end of lsmm pair loop - reinterpret_cast(list_dalitzmumu_cut->FindObject("hNpair_lsmm"))->Fill(nlsmm); - - used_trackIds.clear(); - used_trackIds.shrink_to_fit(); - } // end of cut loop - } // end of collision loop - } // end of process - PROCESS_SWITCH(DalitzMuMuQC, processQC, "run Dalitz QC", true); - - Configurable ndepth{"ndepth", 10, "depth for event mixing"}; - ConfigurableAxis ConfVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - ConfigurableAxis ConfCentBins{"ConfCentBins", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 999.f}, "Mixing bins - centrality"}; - using BinningType_M = ColumnBinningPolicy; - using BinningType_A = ColumnBinningPolicy; - using BinningType_C = ColumnBinningPolicy; - BinningType_M colBinning_M{{ConfVtxBins, ConfCentBins}, true}; - BinningType_A colBinning_A{{ConfVtxBins, ConfCentBins}, true}; - BinningType_C colBinning_C{{ConfVtxBins, ConfCentBins}, true}; - - Filter collisionFilter_common = nabs(o2::aod::collision::posZ) < 10.f && o2::aod::collision::numContrib > (uint16_t)0 && o2::aod::evsel::sel8 == true; - Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); - Filter collisionFilter_subsys = (o2::aod::emevent::nmumuuls >= 1) || (o2::aod::emevent::nmumulspp >= 1) || (o2::aod::emevent::nmumulsmm >= 1); - using MyFilteredCollisions = soa::Filtered; // this goes to mixed event. - - // mu+, mu- enter to event mixing, only if any pair exists. If you want to do mixed event, please store LS for mumu - template - void MixedEventPairing(TEvents const& collisions, TTracks const& tracks, TMixedBinning const& colBinning) - { - THashList* list_dalitzmumu = static_cast(fMainList->FindObject("DalitzMuMu")); - double values[3] = {0, 0, 0}; - ROOT::Math::PtEtaPhiMVector v1, v2, v12; - float phiv = 0; - float dca_pos_3d = 999.f, dca_ele_3d = 999.f, dca_ee_3d = 999.f; - - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, ndepth, -1, collisions, collisions)) { // internally, CombinationsStrictlyUpperIndexPolicy(collisions, collisions) is called. - - const float centralities1[3] = {collision1.centFT0M(), collision1.centFT0A(), collision1.centFT0C()}; - const float centralities2[3] = {collision2.centFT0M(), collision2.centFT0A(), collision2.centFT0C()}; - - if (centralities1[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities1[cfgCentEstimator]) { - continue; - } - if (centralities2[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities2[cfgCentEstimator]) { - continue; - } - if (!fEMEventCut.IsSelected(collision1) || !fEMEventCut.IsSelected(collision2)) { - continue; - } - - auto tracks_coll1 = tracks.sliceBy(perCollision_track, collision1.globalIndex()); - auto tracks_coll2 = tracks.sliceBy(perCollision_track, collision2.globalIndex()); - - for (auto& cut : fDalitzMuMuCuts) { - THashList* list_dalitzmumu_cut = static_cast(list_dalitzmumu->FindObject(cut.GetName())); - for (auto& [t1, t2] : combinations(soa::CombinationsFullIndexPolicy(tracks_coll1, tracks_coll2))) { - if (t1.trackId() == t2.trackId()) { // this is protection against pairing identical 2 tracks. This happens, when TTCA is used. TTCA can assign a track to several possible collisions. - continue; - } - - v1 = ROOT::Math::PtEtaPhiMVector(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassMuon); - v2 = ROOT::Math::PtEtaPhiMVector(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassMuon); - v12 = v1 + v2; - - dca_pos_3d = t1.dca3DinSigma(); - dca_ele_3d = t2.dca3DinSigma(); - dca_ee_3d = std::sqrt((dca_pos_3d * dca_pos_3d + dca_ele_3d * dca_ele_3d) / 2.); - - values[0] = v12.M(); - values[1] = v12.Pt(); - values[2] = dca_ee_3d; - - if (cut.IsSelectedTrack(t1) && cut.IsSelectedTrack(t2) && cut.IsSelectedPair(v12.M(), dca_ee_3d, phiv)) { - if (t1.sign() * t2.sign() < 0) { - reinterpret_cast(list_dalitzmumu_cut->FindObject("hs_dilepton_uls_mix"))->Fill(values); - } else if (t1.sign() > 0 && t2.sign() > 0) { - reinterpret_cast(list_dalitzmumu_cut->FindObject("hs_dilepton_lspp_mix"))->Fill(values); - } else if (t1.sign() < 0 && t2.sign() < 0) { - reinterpret_cast(list_dalitzmumu_cut->FindObject("hs_dilepton_lsmm_mix"))->Fill(values); - } else { - LOGF(info, "This should not happen."); - } - } - } // end of different dileptn combinations - } // end of cut loop - } // end of different collision combinations - } - - void processEventMixing(MyFilteredCollisions const& collisions, MyTracks const& tracks) - { - if (cfgCentEstimator == 0) { - MixedEventPairing(collisions, tracks, colBinning_M); - } else if (cfgCentEstimator == 1) { - MixedEventPairing(collisions, tracks, colBinning_A); - } else if (cfgCentEstimator == 2) { - MixedEventPairing(collisions, tracks, colBinning_C); - } - } - PROCESS_SWITCH(DalitzMuMuQC, processEventMixing, "run Dalitz MuMu QC event mixing", true); - - void processDummy(MyCollisions const&) {} - PROCESS_SWITCH(DalitzMuMuQC, processDummy, "Dummy function", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"dalitz-mumu-qc"})}; -} diff --git a/PWGEM/PhotonMeson/Tasks/dalitzMuMuQCMC.cxx b/PWGEM/PhotonMeson/Tasks/dalitzMuMuQCMC.cxx deleted file mode 100644 index b45dbb6e6f2..00000000000 --- a/PWGEM/PhotonMeson/Tasks/dalitzMuMuQCMC.cxx +++ /dev/null @@ -1,314 +0,0 @@ -// 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. -// -// ======================== -// -// This code runs loop over dalitz ee table for dalitz QC. -// Please write to: daiki.sekihata@cern.ch - -#include -#include "TString.h" -#include "THashList.h" -#include "TDirectory.h" -#include "Math/Vector4D.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" - -#include "Common/Core/RecoDecay.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" -#include "PWGEM/PhotonMeson/Core/CutsLibrary.h" -#include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" -#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" - -using namespace o2; -using namespace o2::aod; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::soa; -using namespace o2::aod::pwgem::mcutil; -using namespace o2::aod::pwgem::photon; -using std::array; - -using MyCollisions = soa::Join; -using MyCollision = MyCollisions::iterator; - -using MyDalitzMuMus = soa::Join; -using MyDalitzMuMu = MyDalitzMuMus::iterator; - -using MyTracks = soa::Join; -using MyMCTracks = soa::Join; - -struct DalitzMuMuQCMC { - Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; - Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; - Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; - - Configurable fConfigDalitzMuMuCuts{"cfgDalitzMuMuCuts", "nocut", "Comma separated list of dalitz mumu cuts"}; - std::vector fDalitzMuMuCuts; - - Configurable fConfigEMEventCut{"cfgEMEventCut", "minbias", "em event cut"}; // only 1 event cut per wagon - EMEventCut fEMEventCut; - static constexpr std::string_view event_types[2] = {"before", "after"}; - - OutputObj fOutputEvent{"Event"}; - OutputObj fOutputTrack{"Track"}; - OutputObj fOutputDalitzMuMu{"DalitzMuMu"}; - OutputObj fOutputGen{"Generated"}; - THashList* fMainList = new THashList(); - - void addhistograms() - { - fMainList->SetOwner(true); - fMainList->SetName("fMainList"); - - // create sub lists first. - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Event"); - THashList* list_ev = reinterpret_cast(fMainList->FindObject("Event")); - for (const auto& evtype : event_types) { - THashList* list_ev_type = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_ev, evtype.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_ev_type, "Event", evtype.data()); - } - - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Track"); - THashList* list_track = reinterpret_cast(fMainList->FindObject("Track")); - - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "DalitzMuMu"); - THashList* list_dalitzmumu = reinterpret_cast(fMainList->FindObject("DalitzMuMu")); - - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Generated"); - THashList* list_gen = reinterpret_cast(fMainList->FindObject("Generated")); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_gen, "Generated", "dimuon"); - - for (const auto& cut : fDalitzMuMuCuts) { - const char* cutname = cut.GetName(); - o2::aod::pwgem::photon::histogram::AddHistClass(list_track, cutname); - o2::aod::pwgem::photon::histogram::AddHistClass(list_dalitzmumu, cutname); - } - - // for single tracks - for (auto& cut : fDalitzMuMuCuts) { - std::string_view cutname = cut.GetName(); - THashList* list = reinterpret_cast(fMainList->FindObject("Track")->FindObject(cutname.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list, "Track", "Mu,mc"); - } - - // for DalitzMuMus - for (auto& cut : fDalitzMuMuCuts) { - std::string_view cutname = cut.GetName(); - THashList* list = reinterpret_cast(fMainList->FindObject("DalitzMuMu")->FindObject(cutname.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list, "DalitzMuMu", "mc"); - } - } - - void DefineCuts() - { - TString cutNamesStr = fConfigDalitzMuMuCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fDalitzMuMuCuts.push_back(*dalitzeecuts::GetCut(cutname)); - } - } - LOGF(info, "Number of Dalitz cuts = %d", fDalitzMuMuCuts.size()); - } - - void init(InitContext&) - { - DefineCuts(); - addhistograms(); // please call this after DefineCuts(); - TString ev_cut_name = fConfigEMEventCut.value; - fEMEventCut = *eventcuts::GetCut(ev_cut_name.Data()); - - fOutputEvent.setObject(reinterpret_cast(fMainList->FindObject("Event"))); - fOutputTrack.setObject(reinterpret_cast(fMainList->FindObject("Track"))); - fOutputDalitzMuMu.setObject(reinterpret_cast(fMainList->FindObject("DalitzMuMu"))); - fOutputGen.setObject(reinterpret_cast(fMainList->FindObject("Generated"))); - } - - template - int FindLF(TTrack const& posmc, TTrack const& elemc, TMCTracks const& mcparticles) - { - int arr[] = { - FindCommonMotherFrom2Prongs(posmc, elemc, -13, 13, 111, mcparticles), FindCommonMotherFrom2Prongs(posmc, elemc, -13, 13, 221, mcparticles), FindCommonMotherFrom2Prongs(posmc, elemc, -13, 13, 331, mcparticles), FindCommonMotherFrom2Prongs(posmc, elemc, -13, 13, 113, mcparticles), FindCommonMotherFrom2Prongs(posmc, elemc, -13, 13, 223, mcparticles), FindCommonMotherFrom2Prongs(posmc, elemc, -13, 13, 333, mcparticles)}; - int size = sizeof(arr) / sizeof(*arr); - int max = *std::max_element(arr, arr + size); - return max; - } - - Partition uls_pairs = o2::aod::dalitzmumu::sign == 0; - - SliceCache cache; - Preslice perCollision = aod::dalitzmumu::emeventId; - Partition grouped_collisions = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); // this goes to same event. - - std::vector used_trackIds; - - void processQCMC(MyCollisions const&, MyDalitzMuMus const&, MyMCTracks const&, aod::EMMCParticles const& mcparticles, aod::EMMCEvents const&) - { - THashList* list_ev_before = static_cast(fMainList->FindObject("Event")->FindObject(event_types[0].data())); - THashList* list_ev_after = static_cast(fMainList->FindObject("Event")->FindObject(event_types[1].data())); - THashList* list_dalitzmumu = static_cast(fMainList->FindObject("DalitzMuMu")); - THashList* list_track = static_cast(fMainList->FindObject("Track")); - double values[3] = {0, 0, 0}; - float dca_pos_3d = 999.f, dca_ele_3d = 999.f, dca_ee_3d = 999.f; - - for (auto& collision : grouped_collisions) { - float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { - continue; - } - - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_before, "", collision); - if (!fEMEventCut.IsSelected(collision)) { - continue; - } - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_after, "", collision); - reinterpret_cast(list_ev_before->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - reinterpret_cast(list_ev_after->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - - auto uls_pairs_per_coll = uls_pairs->sliceByCached(o2::aod::dalitzmumu::emeventId, collision.globalIndex(), cache); - - for (const auto& cut : fDalitzMuMuCuts) { - THashList* list_dalitzmumu_cut = static_cast(list_dalitzmumu->FindObject(cut.GetName())); - THashList* list_track_cut = static_cast(list_track->FindObject(cut.GetName())); - used_trackIds.reserve(uls_pairs_per_coll.size() * 2); - - int nuls = 0; - for (auto& uls_pair : uls_pairs_per_coll) { - auto pos = uls_pair.template posTrack_as(); - auto ele = uls_pair.template negTrack_as(); - if (!cut.IsSelected(uls_pair)) { - continue; - } - auto posmc = pos.template emmcparticle_as(); - auto elemc = ele.template emmcparticle_as(); - - // LOGF(info, "posmc.pdgCode() = %d, , posmc.has_mothers()() = %d | elemc.pdgCode() = %d, elemc.has_mothers() = %d", posmc.pdgCode(), posmc.has_mothers(), elemc.pdgCode(), elemc.has_mothers()); - - int mother_id = FindLF(posmc, elemc, mcparticles); - if (mother_id < 0) { - continue; - } - if (mother_id > 0) { - auto mcmother = mcparticles.iteratorAt(mother_id); - if (mcmother.isPhysicalPrimary() || mcmother.producedByGenerator()) { - dca_pos_3d = pos.dca3DinSigma(); - dca_ele_3d = ele.dca3DinSigma(); - dca_ee_3d = std::sqrt((dca_pos_3d * dca_pos_3d + dca_ele_3d * dca_ele_3d) / 2.); - - values[0] = uls_pair.mass(); - values[1] = uls_pair.pt(); - values[2] = dca_ee_3d; - reinterpret_cast(list_dalitzmumu_cut->FindObject("hs_dilepton_uls_same"))->Fill(values); - - nuls++; - for (auto& track : {pos, ele}) { - if (std::find(used_trackIds.begin(), used_trackIds.end(), track.globalIndex()) == used_trackIds.end()) { - o2::aod::pwgem::photon::histogram::FillHistClass(list_track_cut, "", track); - used_trackIds.emplace_back(track.globalIndex()); - auto mctrack = track.template emmcparticle_as(); - reinterpret_cast(fMainList->FindObject("Track")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaPtOverPtGen"))->Fill(mctrack.pt(), (track.pt() - mctrack.pt()) / mctrack.pt()); - reinterpret_cast(fMainList->FindObject("Track")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaEta"))->Fill(mctrack.pt(), track.eta() - mctrack.eta()); - reinterpret_cast(fMainList->FindObject("Track")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaPhi"))->Fill(mctrack.pt(), track.phi() - mctrack.phi()); - } - } - } // end of LF - } - } // end of uls pair loop - reinterpret_cast(list_dalitzmumu_cut->FindObject("hNpair_uls"))->Fill(nuls); - - used_trackIds.clear(); - used_trackIds.shrink_to_fit(); - } // end of cut loop - } // end of collision loop - } // end of process - PROCESS_SWITCH(DalitzMuMuQCMC, processQCMC, "run Dalitz QC", true); - - Configurable min_mcPt{"min_mcPt", 0.05, "min. MC pT"}; - Configurable max_mcPt{"max_mcPt", 0.6, "max. MC pT"}; - Configurable max_mcEta{"max_mcEta", 0.9, "max. MC eta"}; - Partition posTracks = o2::aod::mcparticle::pdgCode == -13; // mu+ - Partition negTracks = o2::aod::mcparticle::pdgCode == +13; // mu- - PresliceUnsorted perMcCollision = aod::emmcparticle::emmceventId; - void processGen(MyCollisions const&, aod::EMMCEvents const&, aod::EMMCParticles const& mcparticles) - { - // loop over mc stack and fill histograms for pure MC truth signals - // all MC tracks which belong to the MC event corresponding to the current reconstructed event - for (auto& collision : grouped_collisions) { - float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { - continue; - } - - auto mccollision = collision.emmcevent(); - - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hCollisionCounter"))->Fill(1.0); - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hZvtx_before"))->Fill(mccollision.posZ()); - if (!collision.sel8()) { - continue; - } - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hCollisionCounter"))->Fill(2.0); - - if (collision.numContrib() < 0.5) { - continue; - } - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hCollisionCounter"))->Fill(3.0); - - if (abs(collision.posZ()) > 10.0) { - continue; - } - if (!fEMEventCut.IsSelected(collision)) { - continue; - } - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hCollisionCounter"))->Fill(4.0); - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hZvtx_after"))->Fill(mccollision.posZ()); - - auto posTracks_per_coll = posTracks->sliceByCachedUnsorted(o2::aod::emmcparticle::emmceventId, mccollision.globalIndex(), cache); - auto negTracks_per_coll = negTracks->sliceByCachedUnsorted(o2::aod::emmcparticle::emmceventId, mccollision.globalIndex(), cache); - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { - // LOGF(info, "pdg1 = %d, pdg2 = %d", t1.pdgCode(), t2.pdgCode()); - - if (t1.pt() < min_mcPt || max_mcPt < t1.pt() || abs(t1.eta()) > max_mcEta) { - continue; - } - if (t2.pt() < min_mcPt || max_mcPt < t2.pt() || abs(t2.eta()) > max_mcEta) { - continue; - } - - int mother_id = FindLF(t1, t2, mcparticles); - if (mother_id < 0) { - continue; - } - auto mcmother = mcparticles.iteratorAt(mother_id); - if (mcmother.isPhysicalPrimary() || mcmother.producedByGenerator()) { - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassMuon); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassMuon); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hMvsPt"))->Fill(v12.M(), v12.Pt()); - } // end of LF - } // end of true ULS pair loop - } // end of collision loop - } - PROCESS_SWITCH(DalitzMuMuQCMC, processGen, "run genrated info", true); - - void processDummy(MyCollisions const&) {} - PROCESS_SWITCH(DalitzMuMuQCMC, processDummy, "Dummy function", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"dalitz-mumu-qc-mc"})}; -} diff --git a/PWGEM/PhotonMeson/Tasks/emcalBcWisePi0.cxx b/PWGEM/PhotonMeson/Tasks/emcalBcWisePi0.cxx new file mode 100644 index 00000000000..d8b1599d596 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/emcalBcWisePi0.cxx @@ -0,0 +1,218 @@ +// Copyright 2019-2024 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 emcalBcWisePi0.cxx +/// +/// \brief Task that extracts pi0s from BC wise derived data of EMCal clusters +/// +/// \author Nicolas Strangmann (nicolas.strangmann@cern.ch) Goethe University Frankfurt +/// + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" + +#include "TString.h" +#include "Math/Vector4D.h" +#include "Math/Vector3D.h" +#include "Math/LorentzRotation.h" +#include "Math/Rotation3D.h" +#include "Math/AxisAngle.h" + +#include "CommonConstants/MathConstants.h" +#include "EMCALBase/Geometry.h" +#include "PWGEM/PhotonMeson/DataModel/bcWiseTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct EmcalBcWisePi0 { + HistogramRegistry mHistManager{"EmcalGammaGammaBcWiseHistograms"}; + + Configurable cfgClusterDefinition{"cfgClusterDefinition", 10, "Clusterizer to be selected, e.g. 13 for kV3MostSplitLowSeed"}; + Configurable cfgMinClusterEnergy{"cfgMinClusterEnergy", 0.7, "Minimum energy of selected clusters (GeV)"}; + Configurable cfgMinM02{"cfgMinM02", 0.1, "Minimum M02 of selected clusters"}; + Configurable cfgMaxM02{"cfgMaxM02", 0.7, "Maximum M02 of selected clusters"}; + Configurable cfgMinTime{"cfgMinTime", -15, "Minimum time of selected clusters (ns)"}; + Configurable cfgMaxTime{"cfgMaxTime", 15, "Maximum time of selected clusters (ns)"}; + Configurable cfgRapidityCut{"cfgRapidityCut", 0.8f, "Maximum absolute rapidity of counted particles"}; + Configurable cfgMinOpenAngle{"cfgMinOpenAngle", 0.0202, "Minimum opening angle between photons"}; + Configurable cfgDistanceToEdge{"cfgDistanceToEdge", 1, "Distance to edge in cells required for rotated cluster to be accepted"}; + Configurable cfgBGEventDownsampling{"cfgBGEventDownsampling", 1, "Only calculate background for every n-th event (performance reasons in PbPb)"}; + + static constexpr float DefaultCentralityWindow[2] = {-1., 101.}; + Configurable> cfgCentralityWindow{"cfgCentralityWindow", {DefaultCentralityWindow, 2, {"Min_Centrality", "Max_Centrality"}}, "Select centrality window (also requires unique collision)"}; + + Filter clusterDefinitionFilter = aod::bcwisecluster::storedDefinition == static_cast(cfgClusterDefinition); + Filter energyFilter = aod::bcwisecluster::storedE > static_cast(cfgMinClusterEnergy* aod::emdownscaling::downscalingFactors[aod::emdownscaling::kEnergy]); + Filter m02Filter = (aod::bcwisecluster::storedNCells == static_cast(1) || (aod::bcwisecluster::storedM02 > static_cast(cfgMinM02 * aod::emdownscaling::downscalingFactors[aod::emdownscaling::kM02]) && aod::bcwisecluster::storedM02 < static_cast(cfgMaxM02 * aod::emdownscaling::downscalingFactors[aod::emdownscaling::kM02]))); + Filter timeFilter = (aod::bcwisecluster::storedTime > static_cast(cfgMinTime * aod::emdownscaling::downscalingFactors[aod::emdownscaling::kTime]) && aod::bcwisecluster::storedTime < static_cast(cfgMaxTime * aod::emdownscaling::downscalingFactors[aod::emdownscaling::kTime])); + + emcal::Geometry* emcalGeom; + + void init(InitContext const&) + { + emcalGeom = emcal::Geometry::GetInstanceFromRunNumber(300000); + const int nEventBins = 8; + mHistManager.add("nBCs", "Number of BCs;;#bf{#it{N}_{BC}}", HistType::kTH1F, {{nEventBins, -0.5, 7.5}}); + const TString binLabels[nEventBins] = {"All", "FT0", "TVX", "kTVXinEMC", "Cell", "Cluster", "NoBorder", "Collision"}; + for (int iBin = 0; iBin < nEventBins; iBin++) + mHistManager.get(HIST("nBCs"))->GetXaxis()->SetBinLabel(iBin + 1, binLabels[iBin]); + + mHistManager.add("Centrality", "FT0M centrality;FT0M centrality (%);#bf{#it{N}_{BC} (only BCs containing exactly 1 collision)}", HistType::kTH1F, {{100, 0., 100.}}); + + mHistManager.add("clusterE", "Energy of cluster;#bf{#it{E} (GeV)};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{200, 0, 20}}); + mHistManager.add("clusterM02", "Shape of cluster;#bf{#it{M}_{02}};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{200, 0, 2}}); + mHistManager.add("clusterTime", "Time of cluster;#bf{#it{t} (ns)};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{200, -100, 100}}); + mHistManager.add("clusterNCells", "Number of cells per cluster;#bf{#it{N}_{cells}};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{51, 0., 50.5}}); + mHistManager.add("clusterExotic", "Is cluster exotic?;#bf{Exotic?};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{2, -0.5, 1.5}}); + mHistManager.add("clusterEtaPhi", "Eta/Phi distribution of clusters;#eta;#phi", HistType::kTH2F, {{400, -0.8, 0.8}, {400, 0, constants::math::TwoPI}}); + + mHistManager.add("invMassVsPt", "Invariant mass and pT of meson candidates", HistType::kTH2F, {{400, 0., 0.8}, {200, 0., 20.}}); + mHistManager.add("invMassVsPtBackground", "Invariant mass and pT of background meson candidates", HistType::kTH2F, {{400, 0., 0.8}, {200, 0., 20.}}); + } + + /// \brief returns if cluster is too close to edge of EMCal + bool isTooCloseToEdge(const int cellID, const int DistanceToBorder = 1) + { + if (DistanceToBorder <= 0) + return false; + if (cellID < 0) + return true; + + // check distance to border in case the cell is okay + auto [iSupMod, iMod, iPhi, iEta] = emcalGeom->GetCellIndex(cellID); + auto [irow, icol] = emcalGeom->GetCellPhiEtaIndexInSModule(iSupMod, iMod, iPhi, iEta); + int iRowLast = (emcalGeom->GetSMType(iSupMod) == o2::emcal::EMCALSMType::EMCAL_THIRD || emcalGeom->GetSMType(iSupMod) == o2::emcal::EMCALSMType::DCAL_EXT) ? 8 : 24; + + return (irow < DistanceToBorder || (iRowLast - irow) <= DistanceToBorder); + } + + void fillEventHists(const auto& bc, const auto& collisions, const auto& clusters) + { + mHistManager.fill(HIST("nBCs"), 0); + if (bc.hasFT0()) + mHistManager.fill(HIST("nBCs"), 1); + if (bc.hasTVX()) + mHistManager.fill(HIST("nBCs"), 2); + if (bc.haskTVXinEMC()) + mHistManager.fill(HIST("nBCs"), 3); + if (bc.hasEMCCell()) + mHistManager.fill(HIST("nBCs"), 4); + if (clusters.size() > 0) + mHistManager.fill(HIST("nBCs"), 5); + if (bc.hasNoTFROFBorder()) + mHistManager.fill(HIST("nBCs"), 6); + if (collisions.size() > 0) + mHistManager.fill(HIST("nBCs"), 7); + + if (collisions.size() == 1) { + for (const auto& collision : collisions) + mHistManager.fill(HIST("Centrality"), collision.centrality()); + } + } + + void fillClusterHists(const auto& clusters) + { + for (const auto& cluster : clusters) { + mHistManager.fill(HIST("clusterE"), cluster.e()); + mHistManager.fill(HIST("clusterM02"), cluster.m02()); + mHistManager.fill(HIST("clusterTime"), cluster.time()); + mHistManager.fill(HIST("clusterNCells"), cluster.nCells()); + mHistManager.fill(HIST("clusterEtaPhi"), cluster.eta(), cluster.phi()); + mHistManager.fill(HIST("clusterExotic"), cluster.isExotic()); + } + } + + void reconstructMesons(const auto& clusters, int bcId) + { + for (const auto& [g1, g2] : soa::combinations(soa::CombinationsStrictlyUpperIndexPolicy(clusters, clusters))) { + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + if (std::fabs(v12.Rapidity()) > cfgRapidityCut) + continue; + + float openingAngle12 = std::acos(v1.Vect().Dot(v2.Vect()) / (v1.P() * v2.P())); + if (openingAngle12 < cfgMinOpenAngle) + continue; + + mHistManager.fill(HIST("invMassVsPt"), v12.M(), v12.Pt()); + + if (clusters.size() < 3) + continue; + + if (bcId % cfgBGEventDownsampling != 0) + continue; + + // "else: Calculate background" + + ROOT::Math::AxisAngle rotationAxis(v12.Vect(), constants::math::PIHalf); + ROOT::Math::Rotation3D rotationMatrix(rotationAxis); + for (ROOT::Math::PtEtaPhiMVector vi : {v1, v2}) { + + vi = rotationMatrix * vi; + + try { + int iCellID = emcalGeom->GetAbsCellIdFromEtaPhi(vi.Eta(), vi.Phi()); + if (isTooCloseToEdge(iCellID, cfgDistanceToEdge)) + continue; + } catch (o2::emcal::InvalidPositionException& e) { + continue; + } + + for (const auto& g3 : clusters) { + if (g3.globalIndex() == g1.globalIndex() || g3.globalIndex() == g2.globalIndex()) + continue; + + ROOT::Math::PtEtaPhiMVector v3(g3.pt(), g3.eta(), g3.phi(), 0.); + + float openingAnglei3 = std::acos(vi.Vect().Dot(v3.Vect()) / (vi.P() * v3.P())); + if (openingAnglei3 < cfgMinOpenAngle) + continue; + + ROOT::Math::PtEtaPhiMVector vBG = v3 + vi; + + mHistManager.fill(HIST("invMassVsPtBackground"), vBG.M(), vBG.Pt()); + } + } + } + } + + bool isCentralitySelected(const auto& collisions) + { + if (cfgCentralityWindow->get("Min_Centrality") > -0.5 || cfgCentralityWindow->get("Max_Centrality") < 100.5) { // Centrality window is set + if (collisions.size() != 1) + return false; + for (const auto& collision : collisions) { + if (collision.centrality() < cfgCentralityWindow->get("Min_Centrality") || collision.centrality() > cfgCentralityWindow->get("Max_Centrality")) + return false; + } + } + return true; + } + + void process(aod::BCWiseBCs::iterator const& bc, aod::BCWiseCollisions const& collisions, soa::Filtered const& clusters) + { + if (!isCentralitySelected(collisions)) + return; + + fillEventHists(bc, collisions, clusters); + + fillClusterHists(clusters); + + reconstructMesons(clusters, bc.globalIndex()); + } +}; + +WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGEM/PhotonMeson/Tasks/emcalPi0QC.cxx b/PWGEM/PhotonMeson/Tasks/emcalPi0QC.cxx index d1bbb378827..509e74402b5 100644 --- a/PWGEM/PhotonMeson/Tasks/emcalPi0QC.cxx +++ b/PWGEM/PhotonMeson/Tasks/emcalPi0QC.cxx @@ -137,6 +137,8 @@ struct Pi0QCTask { // configurable parameters // TODO adapt mDoEventSel switch to also allow selection of other triggers (e.g. EMC7) Configurable mDoEventSel{"doEventSel", 0, "demand kINT7"}; + Configurable mRequireCaloReadout{"RequireCaloReadout", 0, "require kTVXinEMC"}; + Configurable mRequireEMCalCells{"RequireEMCalCells", 0, "require at least one EMC cell in each collision"}; Configurable mVetoBCID{"vetoBCID", "", "BC ID(s) to be excluded, this should be used as an alternative to the event selection"}; Configurable mSelectBCID{"selectBCID", "all", "BC ID(s) to be included, this should be used as an alternative to the event selection"}; Configurable mVertexCut{"vertexCut", -1, "apply z-vertex cut with value in cm"}; @@ -266,7 +268,7 @@ struct Pi0QCTask { for (auto& collision : collisions) { mHistManager.fill(HIST("events"), 1); // Fill "All events" bin of event histogram - if (mDoEventSel && (!collision.sel8() || !collision.alias_bit(kTVXinEMC))) { // Check sel8 and whether EMC was read out + if (mDoEventSel && (!collision.sel8() || (mRequireCaloReadout && !collision.alias_bit(kTVXinEMC)))) { // Check sel8 and whether EMC was read out continue; } mHistManager.fill(HIST("events"), 2); // Fill sel8 + readout @@ -290,7 +292,7 @@ struct Pi0QCTask { if (mDoEventSel) { auto found = cellGlobalBCs.find(collision.foundBC_as().globalBC()); - if (found == cellGlobalBCs.end() || found->second == 0) { // Skip collisions without any readout EMCal cells + if (mRequireEMCalCells && (found == cellGlobalBCs.end() || found->second == 0)) { // Skip collisions without any readout EMCal cells continue; } } diff --git a/PWGEM/PhotonMeson/Tasks/emcalQC.cxx b/PWGEM/PhotonMeson/Tasks/emcalQC.cxx index ed909f4dfbd..efb18ea36a3 100644 --- a/PWGEM/PhotonMeson/Tasks/emcalQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/emcalQC.cxx @@ -9,11 +9,17 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // -// ======================== -// -// This code runs loop over EMCal clusters for EMCal QC. -// Please write to: nicolas.strangmann@cern.ch - +/// EMCAL QC Task +/// +/// \file emcalQC.cxx +/// +/// \brief Task that runs basic EMCal cluster QA for derived data in the EM format +/// +/// \author Nicolas Strangmann (nicolas.strangmann@cern.ch) Goethe University Frankfurt +/// + +#include +#include #include #include "TString.h" #include "THashList.h" @@ -32,7 +38,8 @@ #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" #include "PWGEM/PhotonMeson/Core/CutsLibrary.h" -#include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" +#include "PWGEM/PhotonMeson/Utils/ClusterHistograms.h" using namespace o2; using namespace o2::aod; @@ -40,200 +47,201 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::aod::pwgem::photon; -using std::array; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; -struct emcalQC { - - Configurable requireCaloReadout{"requireCaloReadout", true, "Require calorimeters readout when analyzing EMCal/PHOS"}; - Configurable fConfigEMCCuts{"cfgEMCCuts", "custom,standard,nocut", "Comma separated list of EMCal photon cuts"}; - Configurable EMC_minTime{"EMC_minTime", -20., "Minimum cluster time for EMCal time cut"}; - Configurable EMC_maxTime{"EMC_maxTime", +25., "Maximum cluster time for EMCal time cut"}; - Configurable EMC_minM02{"EMC_minM02", 0.1, "Minimum M02 for EMCal M02 cut"}; - Configurable EMC_maxM02{"EMC_maxM02", 0.7, "Maximum M02 for EMCal M02 cut"}; - Configurable EMC_minE{"EMC_minE", 0.7, "Minimum cluster energy for EMCal energy cut"}; - Configurable EMC_minNCell{"EMC_minNCell", 1, "Minimum number of cells per cluster for EMCal NCell cut"}; - Configurable> EMC_TM_Eta{"EMC_TM_Eta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; - Configurable> EMC_TM_Phi{"EMC_TM_Phi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; - Configurable EMC_Eoverp{"EMC_Eoverp", 1.75, "Minimum cluster energy over track momentum for EMCal track matching"}; - Configurable EMC_UseExoticCut{"EMC_UseExoticCut", true, "FLag to use the EMCal exotic cluster cut"}; - Configurable fDo2DQC{"Do2DQC", true, "Flag to output 2D QC histograms displaying the energy dependence on the second axis"}; - - std::vector fEMCCuts; - - OutputObj fOutputEvent{"Event"}; - OutputObj fOutputCluster{"Cluster"}; - THashList* fMainList = new THashList(); - - void addhistograms() +using MyEMCClusters = soa::Join; +using MyEMCCluster = MyEMCClusters::iterator; + +struct EmcalQC { + + Configurable cfgDo2DQA{"cfgDo2DQA", true, "perform 2 dimensional cluster QA"}; + ConfigurableAxis confVtxBins{"confVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + + EMPhotonEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgRequireEMCReadoutInMB{"cfgRequireEMCReadoutInMB", false, "require the EMC to be read out in an MB collision (kTVXinEMC)"}; + Configurable cfgRequireEMCHardwareTriggered{"cfgRequireEMCHardwareTriggered", false, "require the EMC to be hardware triggered (kEMC7 or kDMC7)"}; + Configurable cfgOccupancyMin{"cfgOccupancyMin", -1, "min. occupancy"}; + Configurable cfgOccupancyMax{"cfgOccupancyMax", 1000000000, "max. occupancy"}; + Configurable onlyKeepWeightedEvents{"onlyKeepWeightedEvents", false, "flag to keep only weighted events (for JJ MCs) and remove all MB events (with weight = 1)"}; + } eventcuts; + + EMCPhotonCut fEMCCut; + struct : ConfigurableGroup { + std::string prefix = "emccut_group"; + Configurable clusterDefinition{"clusterDefinition", "kV3Default", "Clusterizer to be selected, e.g. V3Default"}; + Configurable minOpenAngle{"minOpenAngle", 0.0202, "apply min opening angle"}; + Configurable minClusterTime{"minClusterTime", -20., "Minimum cluster time for EMCal time cut"}; + Configurable maxClusterTime{"maxClusterTime", +25., "Maximum cluster time for EMCal time cut"}; + Configurable minM02{"minM02", 0.1, "Minimum M02 for EMCal M02 cut"}; + Configurable maxM02{"maxM02", 0.7, "Maximum M02 for EMCal M02 cut"}; + Configurable minClusterE{"minClusterE", 0.7, "Minimum cluster energy for EMCal energy cut"}; + Configurable minNCell{"minNCell", 1, "Minimum number of cells per cluster for EMCal NCell cut"}; + Configurable> tmEta{"tmEta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable> tmPhi{"tmPhi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable tmEoverP{"tmEoverP", 1.75, "Minimum cluster energy over track momentum for EMCal track matching"}; + Configurable useExoticCut{"useExoticCut", true, "FLag to use the EMCal exotic cluster cut"}; + } emccuts; + + void defineEMEventCut() { - fMainList->SetOwner(true); - fMainList->SetName("fMainList"); - - // create sub lists first. - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Event"); - THashList* list_ev = reinterpret_cast(fMainList->FindObject("Event")); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_ev, "Event"); - - list_ev->Add(new TH1F("hNEvents", "hNEvents", 6, 0.5f, 6.5f)); - reinterpret_cast(list_ev->FindObject("hNEvents"))->GetXaxis()->SetBinLabel(1, "all cols"); - reinterpret_cast(list_ev->FindObject("hNEvents"))->GetXaxis()->SetBinLabel(2, "sel8"); - reinterpret_cast(list_ev->FindObject("hNEvents"))->GetXaxis()->SetBinLabel(3, "emc readout"); - reinterpret_cast(list_ev->FindObject("hNEvents"))->GetXaxis()->SetBinLabel(4, "1+ Contributor"); - reinterpret_cast(list_ev->FindObject("hNEvents"))->GetXaxis()->SetBinLabel(5, "z<10cm"); - reinterpret_cast(list_ev->FindObject("hNEvents"))->GetXaxis()->SetBinLabel(6, "unique col"); - - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Cluster"); - THashList* list_cluster = reinterpret_cast(fMainList->FindObject("Cluster")); - - for (const auto& cut : fEMCCuts) { - const char* cutname = cut.GetName(); - o2::aod::pwgem::photon::histogram::AddHistClass(list_cluster, cutname); - } - - // for Clusters - for (auto& cut : fEMCCuts) { - std::string_view cutname = cut.GetName(); - THashList* list = reinterpret_cast(fMainList->FindObject("Cluster")->FindObject(cutname.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list, "Cluster", fDo2DQC ? "2D_EMC" : "EMC"); - } + fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireEMCReadoutInMB(eventcuts.cfgRequireEMCReadoutInMB); + fEMEventCut.SetRequireEMCHardwareTriggered(eventcuts.cfgRequireEMCHardwareTriggered); } - void DefineCuts() + void defineEMCCut() { - const float a = EMC_TM_Eta->at(0); - const float b = EMC_TM_Eta->at(1); - const float c = EMC_TM_Eta->at(2); + const float a = emccuts.tmEta->at(0); + const float b = emccuts.tmEta->at(1); + const float c = emccuts.tmEta->at(2); - const float d = EMC_TM_Phi->at(0); - const float e = EMC_TM_Phi->at(1); - const float f = EMC_TM_Phi->at(2); + const float d = emccuts.tmPhi->at(0); + const float e = emccuts.tmPhi->at(1); + const float f = emccuts.tmPhi->at(2); LOGF(info, "EMCal track matching parameters : a = %f, b = %f, c = %f, d = %f, e = %f, f = %f", a, b, c, d, e, f); - TString cutNamesStr = fConfigEMCCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - if (std::strcmp(cutname, "custom") == 0) { - EMCPhotonCut* custom_cut = new EMCPhotonCut(cutname, cutname); - custom_cut->SetMinE(EMC_minE); - custom_cut->SetMinNCell(EMC_minNCell); - custom_cut->SetM02Range(EMC_minM02, EMC_maxM02); - custom_cut->SetTimeRange(EMC_minTime, EMC_maxTime); - - custom_cut->SetTrackMatchingEta([&a, &b, &c](float pT) { - return a + pow(pT + b, c); - }); - custom_cut->SetTrackMatchingPhi([&d, &e, &f](float pT) { - return d + pow(pT + e, f); - }); - - custom_cut->SetMinEoverP(EMC_Eoverp); - custom_cut->SetUseExoticCut(EMC_UseExoticCut); - fEMCCuts.push_back(*custom_cut); - } else { - fEMCCuts.push_back(*emccuts::GetCut(cutname)); - } - } - } - LOGF(info, "Number of EMC cuts = %d", fEMCCuts.size()); + fEMCCut.SetClusterizer(emccuts.clusterDefinition); + fEMCCut.SetMinE(emccuts.minClusterE); + fEMCCut.SetMinNCell(emccuts.minNCell); + fEMCCut.SetM02Range(emccuts.minM02, emccuts.maxM02); + fEMCCut.SetTimeRange(emccuts.minClusterTime, emccuts.maxClusterTime); + + fEMCCut.SetTrackMatchingEta([a, b, c](float pT) { return a + std::pow(pT + b, c); }); + fEMCCut.SetTrackMatchingPhi([d, e, f](float pT) { return d + std::pow(pT + e, f); }); + + fEMCCut.SetMinEoverP(emccuts.tmEoverP); + fEMCCut.SetUseExoticCut(emccuts.useExoticCut); } + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + std::vector zVtxBinEdges; + void init(InitContext&) { - DefineCuts(); - addhistograms(); // please call this after DefinCuts(); - - fOutputEvent.setObject(reinterpret_cast(fMainList->FindObject("Event"))); - fOutputCluster.setObject(reinterpret_cast(fMainList->FindObject("Cluster"))); + zVtxBinEdges = std::vector(confVtxBins.value.begin(), confVtxBins.value.end()); + zVtxBinEdges.erase(zVtxBinEdges.begin()); + + defineEMCCut(); + defineEMEventCut(); + + o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(&fRegistry); + auto hEMCCollisionCounter = fRegistry.add("Event/hEMCCollisionCounter", "Number of collisions after event cuts", HistType::kTH1D, {{7, 0.5, 7.5}}, false); + hEMCCollisionCounter->GetXaxis()->SetBinLabel(1, "all"); + hEMCCollisionCounter->GetXaxis()->SetBinLabel(2, "+TVX"); // TVX + hEMCCollisionCounter->GetXaxis()->SetBinLabel(3, "+|z|<10cm"); // TVX with z < 10cm + hEMCCollisionCounter->GetXaxis()->SetBinLabel(4, "+Sel8"); // TVX with z < 10cm and Sel8 + hEMCCollisionCounter->GetXaxis()->SetBinLabel(5, "+Good z vtx"); // TVX with z < 10cm and Sel8 and good z xertex + hEMCCollisionCounter->GetXaxis()->SetBinLabel(6, "+unique"); // TVX with z < 10cm and Sel8 and good z xertex and unique (only collision in the BC) + hEMCCollisionCounter->GetXaxis()->SetBinLabel(7, "+EMC readout"); // TVX with z < 10cm and Sel8 and good z xertex and unique (only collision in the BC) and kTVXinEMC + o2::aod::pwgem::photonmeson::utils::clusterhistogram::addClusterHistograms(&fRegistry, cfgDo2DQA); } - Preslice perCollision = aod::skimmedcluster::collisionId; + Preslice perCollision = aod::emccluster::emeventId; - void processQC(MyCollisions const& collisions, aod::SkimEMCClusters const& clusters) + void processQC(MyCollisions const& collisions, MyEMCClusters const& clusters) { - THashList* list_ev = static_cast(fMainList->FindObject("Event")); - THashList* list_cluster = static_cast(fMainList->FindObject("Cluster")); + for (const auto& collision : collisions) { - for (auto& collision : collisions) { - reinterpret_cast(fMainList->FindObject("Event")->FindObject("hNEvents"))->Fill(1.0); - if (!collision.sel8()) { + if (eventcuts.onlyKeepWeightedEvents && std::fabs(collision.weight() - 1.) < 1E-10) { continue; } - reinterpret_cast(fMainList->FindObject("Event")->FindObject("hNEvents"))->Fill(2.0); - if (collision.alias_bit(triggerAliases::kTVXinEMC) == 0 && requireCaloReadout) { - continue; - } - reinterpret_cast(fMainList->FindObject("Event")->FindObject("hNEvents"))->Fill(3.0); - if (collision.numContrib() < 0.5) { - continue; + fRegistry.fill(HIST("Event/hEMCCollisionCounter"), 1, collision.weight()); + if (!eventcuts.cfgRequireFT0AND || collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + fRegistry.fill(HIST("Event/hEMCCollisionCounter"), 2, collision.weight()); + if (std::abs(collision.posZ()) < eventcuts.cfgZvtxMax) { + fRegistry.fill(HIST("Event/hEMCCollisionCounter"), 3, collision.weight()); + if (!eventcuts.cfgRequireSel8 || collision.sel8()) { + fRegistry.fill(HIST("Event/hEMCCollisionCounter"), 4, collision.weight()); + if (!eventcuts.cfgRequireGoodZvtxFT0vsPV || collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + fRegistry.fill(HIST("Event/hEMCCollisionCounter"), 5, collision.weight()); + if (!eventcuts.cfgRequireNoSameBunchPileup || collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + fRegistry.fill(HIST("Event/hEMCCollisionCounter"), 6, collision.weight()); + if (!eventcuts.cfgRequireEMCReadoutInMB || collision.alias_bit(kTVXinEMC)) + fRegistry.fill(HIST("Event/hEMCCollisionCounter"), 7, collision.weight()); + } + } + } + } } - reinterpret_cast(fMainList->FindObject("Event")->FindObject("hNEvents"))->Fill(4.0); - if (abs(collision.posZ()) > 10.0) { + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision, collision.weight()); + if (!fEMEventCut.IsSelected(collision)) { continue; } - reinterpret_cast(fMainList->FindObject("Event")->FindObject("hNEvents"))->Fill(5.0); - reinterpret_cast(fMainList->FindObject("Event")->FindObject("hZvtx"))->Fill(collision.posZ()); - - if (collision.ncollsPerBC() != 1) { // Check that the collision is unique (the only one in the bc) + if (!(eventcuts.cfgOccupancyMin <= collision.trackOccupancyInTimeRange() && collision.trackOccupancyInTimeRange() < eventcuts.cfgOccupancyMax)) { continue; } - reinterpret_cast(fMainList->FindObject("Event")->FindObject("hNEvents"))->Fill(6.0); - - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev, "", collision); // Fill event histograms - - auto clusters_per_coll = clusters.sliceBy(perCollision, collision.collisionId()); - for (const auto& cut : fEMCCuts) { - THashList* list_cluster_cut = static_cast(list_cluster->FindObject(cut.GetName())); - int ng = 0; - for (auto& cluster : clusters_per_coll) { - // Fill the cluster properties before applying any cuts - - // Apply cuts one by one and fill in hClusterQualityCuts histogram - reinterpret_cast(fMainList->FindObject("Cluster")->FindObject(cut.GetName())->FindObject("hClusterQualityCuts"))->Fill(0., cluster.e()); - auto track = nullptr; - - // Define two boleans to see, whether the cluster "survives" the EMC cluster cuts to later check, whether the cuts in this task align with the ones in EMCPhotonCut.h: - bool survivesIsSelectedEMCalCuts = true; // Survives "manual" cuts listed in this task - bool survivesIsSelectedCuts = cut.IsSelected(cluster); // Survives the cutlist defines in EMCPhotonCut.h, which is also used in the Pi0Eta task - - for (int icut = 0; icut < static_cast(EMCPhotonCut::EMCPhotonCuts::kNCuts); icut++) { // Loop through different cut observables - EMCPhotonCut::EMCPhotonCuts specificcut = static_cast(icut); - if (!cut.IsSelectedEMCal(specificcut, cluster, track)) { // Check whether cluster passes this cluster requirement, if not, fill why in the next row - reinterpret_cast(fMainList->FindObject("Cluster")->FindObject(cut.GetName())->FindObject("hClusterQualityCuts"))->Fill(icut + 1, cluster.e()); - survivesIsSelectedEMCalCuts = false; - } - } - if (survivesIsSelectedCuts != survivesIsSelectedEMCalCuts) { - LOGF(info, "Cummulative application of IsSelectedEMCal cuts does not equal the IsSelected result"); + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision, collision.weight()); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 12.0, collision.weight()); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 12.0, collision.weight()); // accepted + + auto clustersPerColl = clusters.sliceBy(perCollision, collision.collisionId()); + fRegistry.fill(HIST("Cluster/before/hNgamma"), clustersPerColl.size(), collision.weight()); + int ngAfter = 0; + for (const auto& cluster : clustersPerColl) { + // Fill the cluster properties before applying any cuts + if (!fEMCCut.IsSelectedEMCal(EMCPhotonCut::EMCPhotonCuts::kDefinition, cluster)) + continue; + o2::aod::pwgem::photonmeson::utils::clusterhistogram::fillClusterHistograms<0>(&fRegistry, cluster, cfgDo2DQA, collision.weight()); + + // Apply cuts one by one and fill in hClusterQualityCuts histogram + fRegistry.fill(HIST("Cluster/hClusterQualityCuts"), 0., cluster.e(), collision.weight()); + + // Define two boleans to see, whether the cluster "survives" the EMC cluster cuts to later check, whether the cuts in this task align with the ones in EMCPhotonCut.h: + bool survivesIsSelectedEMCalCuts = true; // Survives "manual" cuts listed in this task + bool survivesIsSelectedCuts = fEMCCut.IsSelected(cluster); // Survives the cutlist defines in EMCPhotonCut.h, which is also used in the Pi0Eta task + + for (int icut = 1; icut < static_cast(EMCPhotonCut::EMCPhotonCuts::kNCuts); icut++) { // Loop through different cut observables, start at 1 to ignore ClusterDefinition + EMCPhotonCut::EMCPhotonCuts specificcut = static_cast(icut); + if (!fEMCCut.IsSelectedEMCal(specificcut, cluster)) { // Check whether cluster passes this cluster requirement, if not, fill why in the next row + fRegistry.fill(HIST("Cluster/hClusterQualityCuts"), icut, cluster.e(), collision.weight()); + survivesIsSelectedEMCalCuts = false; } + } - if (survivesIsSelectedCuts) { - o2::aod::pwgem::photon::histogram::FillHistClass(list_cluster_cut, fDo2DQC ? "2D" : "1D", cluster); - reinterpret_cast(fMainList->FindObject("Cluster")->FindObject(cut.GetName())->FindObject("hClusterQualityCuts"))->Fill(7., cluster.e()); - ng++; - } + if (survivesIsSelectedCuts != survivesIsSelectedEMCalCuts) { + LOGF(info, "Cummulative application of IsSelectedEMCal cuts does not equal the IsSelected result"); } - reinterpret_cast(fMainList->FindObject("Cluster")->FindObject(cut.GetName())->FindObject("hNgamma"))->Fill(ng); - } // end of cut loop - } // end of collision loop - } // end of process + + if (survivesIsSelectedCuts) { + o2::aod::pwgem::photonmeson::utils::clusterhistogram::fillClusterHistograms<1>(&fRegistry, cluster, cfgDo2DQA, collision.weight()); + fRegistry.fill(HIST("Cluster/hClusterQualityCuts"), 7., cluster.e(), collision.weight()); + ngAfter++; + } + } + fRegistry.fill(HIST("Cluster/after/hNgamma"), ngAfter, collision.weight()); + } // end of collision loop + } // end of process void processDummy(MyCollisions const&) {} - PROCESS_SWITCH(emcalQC, processQC, "run EMCal QC", false); - PROCESS_SWITCH(emcalQC, processDummy, "Dummy function", true); + PROCESS_SWITCH(EmcalQC, processQC, "run EMCal QC", false); + PROCESS_SWITCH(EmcalQC, processDummy, "Dummy function", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"emcal-qc"})}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx index 48e52e2730e..9d9d2f6496e 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx @@ -14,32 +14,18 @@ // This code runs loop over v0 photons for PCM QC. // Please write to: daiki.sekihata@cern.ch -#include -#include "TString.h" -#include "THashList.h" -#include "TDirectory.h" -#include "Math/Vector4D.h" -#include "Math/Vector3D.h" -#include "Math/LorentzRotation.h" -#include "Math/Rotation3D.h" -#include "Math/AxisAngle.h" +#include +#include + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/trackUtilities.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/Core/RecoDecay.h" + #include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" -#include "PWGEM/PhotonMeson/Core/CutsLibrary.h" -#include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" using namespace o2; using namespace o2::aod; @@ -47,12 +33,11 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::aod::pwgem::photon; -using std::array; using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; -using MyV0Photons = soa::Join; +using MyV0Photons = soa::Join; using MyV0Photon = MyV0Photons::iterator; struct PCMQC { @@ -60,130 +45,332 @@ struct PCMQC { Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; - Configurable fConfigPCMCuts{"cfgPCMCuts", "qc,qc_ITSTPC,qc_ITSonly,qc_TPConly,wwire_ib,nocut", "Comma separated list of v0 photon cuts"}; - std::vector fPCMCuts; + EMPhotonEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", true, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", true, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInTimeRangeStrict{"cfgRequireNoCollInTimeRangeStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoCollInITSROFStandard{"cfgRequireNoCollInITSROFStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInITSROFStrict{"cfgRequireNoCollInITSROFStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoHighMultCollInPrevRof{"cfgRequireNoHighMultCollInPrevRof", false, "require no HM collision in previous ITS ROF"}; + } eventcuts; - Configurable fConfigEMEventCut{"cfgEMEventCut", "minbias", "em event cut"}; // only 1 event cut per wagon - EMEventCut fEMEventCut; - static constexpr std::string_view event_types[2] = {"before", "after"}; + V0PhotonCut fV0PhotonCut; + struct : ConfigurableGroup { + std::string prefix = "pcmcut_group"; + Configurable cfg_require_v0_with_itstpc{"cfg_require_v0_with_itstpc", false, "flag to select V0s with ITS-TPC matched tracks"}; + Configurable cfg_require_v0_with_itsonly{"cfg_require_v0_with_itsonly", false, "flag to select V0s with ITSonly tracks"}; + Configurable cfg_require_v0_with_tpconly{"cfg_require_v0_with_tpconly", false, "flag to select V0s with TPConly tracks"}; + Configurable cfg_min_pt_v0{"cfg_min_pt_v0", 0.1, "min pT for v0 photons at PV"}; + Configurable cfg_max_pt_v0{"cfg_max_pt_v0", 1e+10, "max pT for v0 photons at PV"}; + Configurable cfg_min_eta_v0{"cfg_min_eta_v0", -0.8, "min eta for v0 photons at PV"}; + Configurable cfg_max_eta_v0{"cfg_max_eta_v0", +0.8, "max eta for v0 photons at PV"}; + Configurable cfg_min_v0radius{"cfg_min_v0radius", 4.0, "min v0 radius"}; + Configurable cfg_max_v0radius{"cfg_max_v0radius", 90.0, "max v0 radius"}; + Configurable cfg_max_alpha_ap{"cfg_max_alpha_ap", 0.95, "max alpha for AP cut"}; + Configurable cfg_max_qt_ap{"cfg_max_qt_ap", 0.01, "max qT for AP cut"}; + Configurable cfg_min_cospa{"cfg_min_cospa", 0.997, "min V0 CosPA"}; + Configurable cfg_max_pca{"cfg_max_pca", 3.0, "max distance btween 2 legs"}; + Configurable cfg_max_chi2kf{"cfg_max_chi2kf", 1e+10, "max chi2/ndf with KF"}; + Configurable cfg_require_v0_with_correct_xz{"cfg_require_v0_with_correct_xz", true, "flag to select V0s with correct xz"}; + Configurable cfg_reject_v0_on_itsib{"cfg_reject_v0_on_itsib", true, "flag to reject V0s on ITSib"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 40, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -3.0, "min. TPC n sigma for electron"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; + Configurable cfg_disable_itsonly_track{"cfg_disable_itsonly_track", false, "flag to disable ITSonly tracks"}; + Configurable cfg_disable_tpconly_track{"cfg_disable_tpconly_track", false, "flag to disable TPConly tracks"}; + } pcmcuts; - OutputObj fOutputEvent{"Event"}; - OutputObj fOutputV0Leg{"V0Leg"}; - OutputObj fOutputV0{"V0"}; - THashList* fMainList = new THashList(); + static constexpr std::string_view event_types[2] = {"before/", "after/"}; + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + void init(InitContext&) + { + addhistograms(); + DefineEMEventCut(); + DefinePCMCut(); + } void addhistograms() { - fMainList->SetOwner(true); - fMainList->SetName("fMainList"); + // event info + auto hCollisionCounter = fRegistry.add("Event/before/hCollisionCounter", "collision counter;;Number of events", kTH1F, {{10, 0.5, 10.5}}, false); + hCollisionCounter->GetXaxis()->SetBinLabel(1, "all"); + hCollisionCounter->GetXaxis()->SetBinLabel(2, "No TF border"); + hCollisionCounter->GetXaxis()->SetBinLabel(3, "No ITS ROF border"); + hCollisionCounter->GetXaxis()->SetBinLabel(4, "No Same Bunch Pileup"); + hCollisionCounter->GetXaxis()->SetBinLabel(5, "Is Vertex ITSTPC"); + hCollisionCounter->GetXaxis()->SetBinLabel(6, "Is Good Zvtx FT0vsPV"); + hCollisionCounter->GetXaxis()->SetBinLabel(7, "FT0AND"); + hCollisionCounter->GetXaxis()->SetBinLabel(8, "sel8"); + hCollisionCounter->GetXaxis()->SetBinLabel(9, "|Z_{vtx}| < 10 cm"); + hCollisionCounter->GetXaxis()->SetBinLabel(10, "accepted"); - // create sub lists first. - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Event"); - THashList* list_ev = reinterpret_cast(fMainList->FindObject("Event")); + fRegistry.add("Event/before/hZvtx", "vertex z; Z_{vtx} (cm)", kTH1F, {{100, -50, +50}}, false); + fRegistry.add("Event/before/hMultNTracksPV", "hMultNTracksPV; N_{track} to PV", kTH1F, {{6001, -0.5, 6000.5}}, false); + fRegistry.add("Event/before/hMultNTracksPVeta1", "hMultNTracksPVeta1; N_{track} to PV", kTH1F, {{6001, -0.5, 6000.5}}, false); + fRegistry.add("Event/before/hMultFT0", "hMultFT0;mult. FT0A;mult. FT0C", kTH2F, {{300, 0, 6000}, {300, 0, 6000}}, false); + fRegistry.add("Event/before/hCentFT0A", "hCentFT0A;centrality FT0A (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry.add("Event/before/hCentFT0C", "hCentFT0C;centrality FT0C (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry.add("Event/before/hCentFT0M", "hCentFT0M;centrality FT0M (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry.add("Event/before/hCentFT0MvsMultNTracksPV", "hCentFT0MvsMultNTracksPV;centrality FT0M (%);N_{track} to PV", kTH2F, {{110, 0, 110}, {600, 0, 6000}}, false); + fRegistry.add("Event/before/hMultFT0MvsMultNTracksPV", "hMultFT0MvsMultNTracksPV;mult. FT0M;N_{track} to PV", kTH2F, {{600, 0, 6000}, {600, 0, 6000}}, false); + fRegistry.addClone("Event/before/", "Event/after/"); - for (const auto& evtype : event_types) { - THashList* list_ev_type = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_ev, evtype.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_ev_type, "Event", evtype.data()); - } + // v0 info + fRegistry.add("V0/hPt", "pT;p_{T,#gamma} (GeV/c)", kTH1F, {{2000, 0.0f, 20}}, false); + fRegistry.add("V0/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{90, 0, 2 * M_PI}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("V0/hXY", "conversion point in XY;V_{x} (cm);V_{y} (cm)", kTH2F, {{400, -100.0f, 100.0f}, {400, -100.0f, 100.0f}}, false); + fRegistry.add("V0/hRZ", "conversion point in RZ;Z (cm);R_{xy} (cm)", kTH2F, {{200, -100, 100}, {200, 0.0f, 100.0f}}, false); + fRegistry.add("V0/hCosPA", "V0CosPA;cosine pointing angle in 3D", kTH1F, {{100, 0.99f, 1.0f}}, false); + fRegistry.add("V0/hCosPAXY", "V0CosPA;cosine pointing angle in XY", kTH1F, {{100, 0.99f, 1.0f}}, false); + fRegistry.add("V0/hCosPARZ", "V0CosPA;cosine pointing angle in RZ", kTH1F, {{100, 0.99f, 1.0f}}, false); + fRegistry.add("V0/hPCA", "distance between 2 legs;PCA (cm)", kTH1F, {{500, 0.0f, 5.0f}}, false); + fRegistry.add("V0/hDCAxyz", "DCA to PV;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -5.f, +5.f}, {200, -5.f, +5.f}}, false); + fRegistry.add("V0/hDCAz_Pt", "DCA_{z} to PV vs. p_{T};DCA_{z} (cm);p_{T} (GeV/c)", kTH2F, {{200, -5.f, +5.f}, {2000, 0.0f, 20}}, false); + fRegistry.add("V0/hAPplot", "AP plot;#alpha;q_{T} (GeV/c)", kTH2F, {{200, -1.0f, +1.0f}, {250, 0.0f, 0.25f}}, false); + fRegistry.add("V0/hMassGamma", "hMassGamma;R_{xy} (cm);m_{ee} (GeV/c^{2})", kTH2F, {{200, 0.0f, 100.0f}, {100, 0.0f, 0.1f}}, false); + fRegistry.add("V0/hKFChi2vsM", "KF chi2 vs. m_{ee};m_{ee} (GeV/c^{2});KF chi2/NDF", kTH2F, {{100, 0.0f, 0.1f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/hKFChi2vsR", "KF chi2 vs. conversion point in XY;R_{xy} (cm);KF chi2/NDF", kTH2F, {{200, 0.0f, 100.0f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/hKFChi2vsX", "KF chi2 vs. conversion point in X;X (cm);KF chi2/NDF", kTH2F, {{200, -100.0f, 100.0f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/hKFChi2vsY", "KF chi2 vs. conversion point in Y;Y (cm);KF chi2/NDF", kTH2F, {{200, -100.0f, 100.0f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/hKFChi2vsZ", "KF chi2 vs. conversion point in Z;Z (cm);KF chi2/NDF", kTH2F, {{200, -100.0f, 100.0f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/hPResolution", "p resolution;p_{#gamma} (GeV/c);#Deltap/p", kTH2F, {{1000, 0.0f, 10}, {100, 0, 0.1}}, false); + fRegistry.add("V0/hPtResolution", "p_{T} resolution;p_{#gamma} (GeV/c);#Deltap_{T}/p_{T}", kTH2F, {{1000, 0.0f, 10}, {100, 0, 0.1}}, false); + fRegistry.add("V0/hEtaResolution", "#eta resolution;p_{#gamma} (GeV/c);#Delta#eta", kTH2F, {{1000, 0.0f, 10}, {100, 0, 0.01}}, false); + fRegistry.add("V0/hThetaResolution", "#theta resolution;p_{#gamma} (GeV/c);#Delta#theta (rad.)", kTH2F, {{1000, 0.0f, 10}, {100, 0, 0.01}}, false); + fRegistry.add("V0/hPhiResolution", "#varphi resolution;p_{#gamma} (GeV/c);#Delta#varphi (rad.)", kTH2F, {{1000, 0.0f, 10}, {100, 0, 0.01}}, false); + fRegistry.add("V0/hsConvPoint", "photon conversion point;r_{xy} (cm);#varphi (rad.);#eta;", kTHnSparseF, {{100, 0.0f, 100}, {90, 0, 2 * M_PI}, {80, -2, +2}}, false); + fRegistry.add("V0/hNgamma", "Number of #gamma candidates per collision", kTH1F, {{101, -0.5f, 100.5f}}); - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "V0Leg"); - THashList* list_v0leg = reinterpret_cast(fMainList->FindObject("V0Leg")); + // v0leg info + fRegistry.add("V0Leg/hPt", "pT;p_{T,e} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); + fRegistry.add("V0Leg/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{1000, -50, 50}}, false); + fRegistry.add("V0Leg/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{90, 0, 2 * M_PI}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("V0Leg/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -50.0f, 50.0f}, {200, -50.0f, 50.0f}}, false); + fRegistry.add("V0Leg/hNclsTPC", "number of TPC clusters", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("V0Leg/hNcrTPC", "number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("V0Leg/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("V0Leg/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("V0Leg/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("V0Leg/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("V0Leg/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("V0Leg/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("V0Leg/hTPCNclsShared", "TPC Ncls shared/Ncls;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); + fRegistry.add("V0Leg/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("V0Leg/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("V0Leg/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("V0Leg/hMeanClusterSizeITS", "mean cluster size ITS; on ITS #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {160, 0, 16}}, false); + fRegistry.add("V0Leg/hXY", "X vs. Y;X (cm);Y (cm)", kTH2F, {{100, 0, 100}, {80, -20, 20}}, false); + fRegistry.add("V0Leg/hZX", "Z vs. X;Z (cm);X (cm)", kTH2F, {{200, -100, 100}, {100, 0, 100}}, false); + fRegistry.add("V0Leg/hZY", "Z vs. Y;Z (cm);Y (cm)", kTH2F, {{200, -100, 100}, {80, -20, 20}}, false); + } - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "V0"); - THashList* list_v0 = reinterpret_cast(fMainList->FindObject("V0")); + void DefineEMEventCut() + { + fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireNoCollInTimeRangeStandard(eventcuts.cfgRequireNoCollInTimeRangeStandard); + fEMEventCut.SetRequireNoCollInTimeRangeStrict(eventcuts.cfgRequireNoCollInTimeRangeStrict); + fEMEventCut.SetRequireNoCollInITSROFStandard(eventcuts.cfgRequireNoCollInITSROFStandard); + fEMEventCut.SetRequireNoCollInITSROFStrict(eventcuts.cfgRequireNoCollInITSROFStrict); + fEMEventCut.SetRequireNoHighMultCollInPrevRof(eventcuts.cfgRequireNoHighMultCollInPrevRof); + } - for (const auto& cut : fPCMCuts) { - const char* cutname = cut.GetName(); - o2::aod::pwgem::photon::histogram::AddHistClass(list_v0leg, cutname); - o2::aod::pwgem::photon::histogram::AddHistClass(list_v0, cutname); - } + void DefinePCMCut() + { + fV0PhotonCut = V0PhotonCut("fV0PhotonCut", "fV0PhotonCut"); - // for single tracks - for (auto& cut : fPCMCuts) { - std::string_view cutname = cut.GetName(); - THashList* list = reinterpret_cast(fMainList->FindObject("V0Leg")->FindObject(cutname.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list, "V0Leg"); - } + // for v0 + fV0PhotonCut.SetV0PtRange(pcmcuts.cfg_min_pt_v0, pcmcuts.cfg_max_pt_v0); + fV0PhotonCut.SetV0EtaRange(pcmcuts.cfg_min_eta_v0, pcmcuts.cfg_max_eta_v0); + fV0PhotonCut.SetMinCosPA(pcmcuts.cfg_min_cospa); + fV0PhotonCut.SetMaxPCA(pcmcuts.cfg_max_pca); + fV0PhotonCut.SetMaxChi2KF(pcmcuts.cfg_max_chi2kf); + fV0PhotonCut.SetRxyRange(pcmcuts.cfg_min_v0radius, pcmcuts.cfg_max_v0radius); + fV0PhotonCut.SetAPRange(pcmcuts.cfg_max_alpha_ap, pcmcuts.cfg_max_qt_ap); + fV0PhotonCut.RejectITSib(pcmcuts.cfg_reject_v0_on_itsib); - // for V0s - for (auto& cut : fPCMCuts) { - std::string_view cutname = cut.GetName(); - THashList* list = reinterpret_cast(fMainList->FindObject("V0")->FindObject(cutname.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list, "V0"); - } + // for track + fV0PhotonCut.SetMinNClustersTPC(pcmcuts.cfg_min_ncluster_tpc); + fV0PhotonCut.SetMinNCrossedRowsTPC(pcmcuts.cfg_min_ncrossedrows); + fV0PhotonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fV0PhotonCut.SetMaxFracSharedClustersTPC(pcmcuts.cfg_max_frac_shared_clusters_tpc); + fV0PhotonCut.SetChi2PerClusterTPC(0.0, pcmcuts.cfg_max_chi2tpc); + fV0PhotonCut.SetTPCNsigmaElRange(pcmcuts.cfg_min_TPCNsigmaEl, pcmcuts.cfg_max_TPCNsigmaEl); + fV0PhotonCut.SetChi2PerClusterITS(-1e+10, pcmcuts.cfg_max_chi2its); + fV0PhotonCut.SetNClustersITS(0, 7); + fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); + fV0PhotonCut.SetIsWithinBeamPipe(pcmcuts.cfg_require_v0_with_correct_xz); + fV0PhotonCut.SetDisableITSonly(pcmcuts.cfg_disable_itsonly_track); + fV0PhotonCut.SetDisableTPConly(pcmcuts.cfg_disable_tpconly_track); + fV0PhotonCut.SetRequireITSTPC(pcmcuts.cfg_require_v0_with_itstpc); + fV0PhotonCut.SetRequireITSonly(pcmcuts.cfg_require_v0_with_itsonly); + fV0PhotonCut.SetRequireTPConly(pcmcuts.cfg_require_v0_with_tpconly); } - void DefineCuts() + template + void fillEventInfo(TCollision const& collision, const float /*weight*/ = 1.f) { - TString cutNamesStr = fConfigPCMCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fPCMCuts.push_back(*pcmcuts::GetCut(cutname)); - } + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 1.0); + if (collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 2.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 3.0); } - LOGF(info, "Number of PCM cuts = %d", fPCMCuts.size()); + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 4.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 5.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 6.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 7.0); + } + if (collision.sel8()) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 8.0); + } + if (std::fabs(collision.posZ()) < 10.0) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 9.0); + } + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hZvtx"), collision.posZ()); + + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultNTracksPV"), collision.multNTracksPV()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultNTracksPVeta1"), collision.multNTracksPVeta1()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0"), collision.multFT0A(), collision.multFT0C()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0A"), collision.centFT0A()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0C"), collision.centFT0C()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0M"), collision.centFT0M()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0MvsMultNTracksPV"), collision.centFT0M(), collision.multNTracksPV()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0MvsMultNTracksPV"), collision.multFT0A() + collision.multFT0C(), collision.multNTracksPV()); } - void init(InitContext&) + template + void fillV0Info(TV0 const& v0) { - DefineCuts(); - addhistograms(); // please call this after DefinCuts(); - TString ev_cut_name = fConfigEMEventCut.value; - fEMEventCut = *eventcuts::GetCut(ev_cut_name.Data()); - fOutputEvent.setObject(reinterpret_cast(fMainList->FindObject("Event"))); - fOutputV0Leg.setObject(reinterpret_cast(fMainList->FindObject("V0Leg"))); - fOutputV0.setObject(reinterpret_cast(fMainList->FindObject("V0"))); + fRegistry.fill(HIST("V0/hPt"), v0.pt()); + fRegistry.fill(HIST("V0/hEtaPhi"), v0.phi(), v0.eta()); + fRegistry.fill(HIST("V0/hXY"), v0.vx(), v0.vy()); + fRegistry.fill(HIST("V0/hRZ"), v0.vz(), v0.v0radius()); + fRegistry.fill(HIST("V0/hCosPA"), v0.cospa()); + fRegistry.fill(HIST("V0/hCosPAXY"), v0.cospaXY()); + fRegistry.fill(HIST("V0/hCosPARZ"), v0.cospaRZ()); + fRegistry.fill(HIST("V0/hPCA"), v0.pca()); + fRegistry.fill(HIST("V0/hDCAxyz"), v0.dcaXYtopv(), v0.dcaZtopv()); + fRegistry.fill(HIST("V0/hDCAz_Pt"), v0.dcaZtopv(), v0.pt()); + fRegistry.fill(HIST("V0/hAPplot"), v0.alpha(), v0.qtarm()); + fRegistry.fill(HIST("V0/hMassGamma"), v0.v0radius(), v0.mGamma()); + fRegistry.fill(HIST("V0/hKFChi2vsM"), v0.mGamma(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/hKFChi2vsR"), v0.v0radius(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/hKFChi2vsX"), v0.vx(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/hKFChi2vsY"), v0.vy(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/hKFChi2vsZ"), v0.vz(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/hPResolution"), v0.p(), getPResolution(v0) / v0.p()); + fRegistry.fill(HIST("V0/hPtResolution"), v0.p(), getPtResolution(v0) / v0.pt()); + fRegistry.fill(HIST("V0/hEtaResolution"), v0.p(), getEtaResolution(v0)); + fRegistry.fill(HIST("V0/hThetaResolution"), v0.p(), getThetaResolution(v0)); + fRegistry.fill(HIST("V0/hPhiResolution"), v0.p(), getPhiResolution(v0)); + + float phi_cp = std::atan2(v0.vy(), v0.vx()); + o2::math_utils::bringTo02Pi(phi_cp); + float eta_cp = std::atanh(v0.vz() / std::sqrt(std::pow(v0.vx(), 2) + std::pow(v0.vy(), 2) + std::pow(v0.vz(), 2))); + fRegistry.fill(HIST("V0/hsConvPoint"), v0.v0radius(), phi_cp, eta_cp); + } + + template + void fillV0LegInfo(TLeg const& leg) + { + fRegistry.fill(HIST("V0Leg/hPt"), leg.pt()); + fRegistry.fill(HIST("V0Leg/hQoverPt"), leg.sign() / leg.pt()); + fRegistry.fill(HIST("V0Leg/hEtaPhi"), leg.phi(), leg.eta()); + fRegistry.fill(HIST("V0Leg/hDCAxyz"), leg.dcaXY(), leg.dcaZ()); + fRegistry.fill(HIST("V0Leg/hNclsITS"), leg.itsNCls()); + fRegistry.fill(HIST("V0Leg/hNclsTPC"), leg.tpcNClsFound()); + fRegistry.fill(HIST("V0Leg/hNcrTPC"), leg.tpcNClsCrossedRows()); + fRegistry.fill(HIST("V0Leg/hTPCNcr2Nf"), leg.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("V0Leg/hTPCNcls2Nf"), leg.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("V0Leg/hTPCNclsShared"), leg.pt(), leg.tpcFractionSharedCls()); + fRegistry.fill(HIST("V0Leg/hChi2TPC"), leg.tpcChi2NCl()); + fRegistry.fill(HIST("V0Leg/hChi2ITS"), leg.itsChi2NCl()); + fRegistry.fill(HIST("V0Leg/hITSClusterMap"), leg.itsClusterMap()); + if (leg.hasITS()) { + fRegistry.fill(HIST("V0Leg/hMeanClusterSizeITS"), leg.p(), leg.meanClusterSizeITS() * std::cos(std::atan(leg.tgl()))); + } + fRegistry.fill(HIST("V0Leg/hTPCdEdx"), leg.tpcInnerParam(), leg.tpcSignal()); + fRegistry.fill(HIST("V0Leg/hTPCNsigmaEl"), leg.tpcInnerParam(), leg.tpcNSigmaEl()); + fRegistry.fill(HIST("V0Leg/hTPCNsigmaPi"), leg.tpcInnerParam(), leg.tpcNSigmaPi()); + fRegistry.fill(HIST("V0Leg/hXY"), leg.x(), leg.y()); + fRegistry.fill(HIST("V0Leg/hZX"), leg.z(), leg.x()); + fRegistry.fill(HIST("V0Leg/hZY"), leg.z(), leg.y()); } Preslice perCollision = aod::v0photonkf::emeventId; - Partition grouped_collisions = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); // this goes to same event. + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + using FilteredMyCollisions = soa::Filtered; - void processQC(MyCollisions const&, MyV0Photons const& v0photons, aod::V0Legs const&) + void processQC(FilteredMyCollisions const& collisions, MyV0Photons const& v0photons, aod::V0Legs const&) { - THashList* list_ev_before = static_cast(fMainList->FindObject("Event")->FindObject(event_types[0].data())); - THashList* list_ev_after = static_cast(fMainList->FindObject("Event")->FindObject(event_types[1].data())); - THashList* list_v0 = static_cast(fMainList->FindObject("V0")); - THashList* list_v0leg = static_cast(fMainList->FindObject("V0Leg")); - - for (auto& collision : grouped_collisions) { + for (auto& collision : collisions) { const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_before, "", collision); + fillEventInfo<0>(collision); if (!fEMEventCut.IsSelected(collision)) { continue; } - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_after, "", collision); - reinterpret_cast(list_ev_before->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - reinterpret_cast(list_ev_after->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - - auto V0Photons_coll = v0photons.sliceBy(perCollision, collision.globalIndex()); - for (const auto& cut : fPCMCuts) { - THashList* list_v0_cut = static_cast(list_v0->FindObject(cut.GetName())); - THashList* list_v0leg_cut = static_cast(list_v0leg->FindObject(cut.GetName())); - - int nv0 = 0; - for (auto& v0 : V0Photons_coll) { - auto pos = v0.posTrack_as(); - auto ele = v0.negTrack_as(); - if (cut.IsSelected(v0)) { - o2::aod::pwgem::photon::histogram::FillHistClass(list_v0_cut, "", v0); - nv0++; - - for (auto& leg : {pos, ele}) { - o2::aod::pwgem::photon::histogram::FillHistClass(list_v0leg_cut, "", leg); - } - } - } // end of v0 loop - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hNgamma"))->Fill(nv0); - } // end of cut loop - } // end of collision loop - } // end of process + fillEventInfo<1>(collision); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 10.0); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 10.0); // accepted + + int nv0 = 0; + auto v0photons_coll = v0photons.sliceBy(perCollision, collision.globalIndex()); + for (auto& v0 : v0photons_coll) { + auto pos = v0.posTrack_as(); + auto ele = v0.negTrack_as(); + + if (!fV0PhotonCut.IsSelected(v0)) { + continue; + } + fillV0Info(v0); + for (auto& leg : {pos, ele}) { + fillV0LegInfo(leg); + } + nv0++; + } // end of v0 loop + fRegistry.fill(HIST("V0/hNgamma"), nv0); + } // end of collision loop + } // end of process void processDummy(MyCollisions const&) {} diff --git a/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx index a25756fb8ff..5dd3e438c89 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx @@ -14,327 +14,662 @@ // This code runs loop over v0 photons for PCM QC. // Please write to: daiki.sekihata@cern.ch -#include -#include "TString.h" -#include "THashList.h" -#include "Math/Vector4D.h" -#include "Math/Vector3D.h" -#include "Math/LorentzRotation.h" -#include "Math/Rotation3D.h" -#include "Math/AxisAngle.h" +#include +#include + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/trackUtilities.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/Core/RecoDecay.h" + #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" #include "PWGEM/PhotonMeson/Utils/MCUtilities.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" -#include "PWGEM/PhotonMeson/Core/CutsLibrary.h" -#include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; -using namespace o2::aod::pwgem::mcutil; +using namespace o2::aod::pwgem::photonmeson::utils::mcutil; +using namespace o2::aod::pwgem::dilepton::utils::mcutil; using namespace o2::aod::pwgem::photon; -using std::array; using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; -using MyV0Photons = soa::Join; +using MyMCCollisions = soa::Join; +using MyMCCollision = MyMCCollisions::iterator; + +using MyV0Photons = soa::Join; using MyV0Photon = MyV0Photons::iterator; +using MyMCV0Legs = soa::Join; +using MyMCV0Leg = MyMCV0Legs::iterator; + struct PCMQCMC { - using MyMCV0Legs = soa::Join; Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; - Configurable fConfigPCMCuts{"cfgPCMCuts", "qc,qc_ITSTPC,qc_ITSonly,qc_TPConly,wwire_ib,nocut", "Comma separated list of v0 photon cuts"}; - Configurable maxY{"maxY", 0.9f, "maximum rapidity for generated particles"}; Configurable maxRgen{"maxRgen", 90.f, "maximum radius for generated particles"}; Configurable margin_z_mc{"margin_z_mc", 7.0, "margin for z cut in cm for MC"}; + Configurable cfgRequireTrueAssociation{"cfgRequireTrueAssociation", false, "flag to require true mc collision association"}; + Configurable cfg_fill_resolution{"cfg_fill_resoltion", false, "flag to fill resolution histogram"}; + + EMPhotonEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", true, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", true, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInTimeRangeStrict{"cfgRequireNoCollInTimeRangeStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoCollInITSROFStandard{"cfgRequireNoCollInITSROFStandard", false, "require no collision in time range standard"}; + Configurable cfgRequireNoCollInITSROFStrict{"cfgRequireNoCollInITSROFStrict", false, "require no collision in time range strict"}; + Configurable cfgRequireNoHighMultCollInPrevRof{"cfgRequireNoHighMultCollInPrevRof", false, "require no HM collision in previous ITS ROF"}; + } eventcuts; + + V0PhotonCut fV0PhotonCut; + struct : ConfigurableGroup { + std::string prefix = "pcmcut_group"; + Configurable cfg_require_v0_with_itstpc{"cfg_require_v0_with_itstpc", false, "flag to select V0s with ITS-TPC matched tracks"}; + Configurable cfg_require_v0_with_itsonly{"cfg_require_v0_with_itsonly", false, "flag to select V0s with ITSonly tracks"}; + Configurable cfg_require_v0_with_tpconly{"cfg_require_v0_with_tpconly", false, "flag to select V0s with TPConly tracks"}; + Configurable cfg_min_pt_v0{"cfg_min_pt_v0", 0.1, "min pT for v0 photons at PV"}; + Configurable cfg_max_pt_v0{"cfg_max_pt_v0", 1e+10, "max pT for v0 photons at PV"}; + Configurable cfg_min_eta_v0{"cfg_min_eta_v0", -0.8, "min eta for v0 photons at PV"}; + Configurable cfg_max_eta_v0{"cfg_max_eta_v0", +0.8, "max eta for v0 photons at PV"}; + Configurable cfg_min_v0radius{"cfg_min_v0radius", 4.0, "min v0 radius"}; + Configurable cfg_max_v0radius{"cfg_max_v0radius", 90.0, "max v0 radius"}; + Configurable cfg_max_alpha_ap{"cfg_max_alpha_ap", 0.95, "max alpha for AP cut"}; + Configurable cfg_max_qt_ap{"cfg_max_qt_ap", 0.01, "max qT for AP cut"}; + Configurable cfg_min_cospa{"cfg_min_cospa", 0.997, "min V0 CosPA"}; + Configurable cfg_max_pca{"cfg_max_pca", 3.0, "max distance btween 2 legs"}; + Configurable cfg_max_chi2kf{"cfg_max_chi2kf", 1e+10, "max chi2/ndf with KF"}; + Configurable cfg_require_v0_with_correct_xz{"cfg_require_v0_with_correct_xz", true, "flag to select V0s with correct xz"}; + Configurable cfg_reject_v0_on_itsib{"cfg_reject_v0_on_itsib", true, "flag to reject V0s on ITSib"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 40, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -3.0, "min. TPC n sigma for electron"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; + Configurable cfg_disable_itsonly_track{"cfg_disable_itsonly_track", false, "flag to disable ITSonly tracks"}; + Configurable cfg_disable_tpconly_track{"cfg_disable_tpconly_track", false, "flag to disable TPConly tracks"}; + } pcmcuts; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view event_types[2] = {"before/", "after/"}; + static constexpr std::string_view mcphoton_types[5] = {"primary/", "fromWD/", "fromHS/", "fromPi0Dalitz/", "fromEtaDalitz/"}; - std::vector fPCMCuts; - - Configurable fConfigEMEventCut{"cfgEMEventCut", "minbias", "em event cut"}; // only 1 event cut per wagon - EMEventCut fEMEventCut; - static constexpr std::string_view event_types[2] = {"before", "after"}; - - OutputObj fOutputEvent{"Event"}; - OutputObj fOutputV0Leg{"V0Leg"}; - OutputObj fOutputV0{"V0"}; - OutputObj fOutputGen{"Generated"}; - THashList* fMainList = new THashList(); + void init(InitContext&) + { + DefineEMEventCut(); + DefinePCMCut(); + addhistograms(); + } void addhistograms() { - fMainList->SetOwner(true); - fMainList->SetName("fMainList"); - - // create sub lists first. - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Event"); - THashList* list_ev = reinterpret_cast(fMainList->FindObject("Event")); - for (const auto& evtype : event_types) { - THashList* list_ev_type = reinterpret_cast(o2::aod::pwgem::photon::histogram::AddHistClass(list_ev, evtype.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_ev_type, "Event", evtype.data()); + std::vector ptbins; + for (int i = 0; i < 2; i++) { + ptbins.emplace_back(0.05 * (i - 0) + 0.0); // from 0 to 0.05 GeV/c, every 0.05 GeV/c + } + for (int i = 2; i < 51; i++) { + ptbins.emplace_back(0.1 * (i - 2) + 0.1); // from 0.1 to 4.9 GeV/c, every 0.1 GeV/c + } + for (int i = 51; i < 61; i++) { + ptbins.emplace_back(0.5 * (i - 51) + 5.0); // from 5 to 9.5 GeV/c, every 0.5 GeV/c + } + for (int i = 61; i < 72; i++) { + ptbins.emplace_back(1.0 * (i - 61) + 10.0); // from 10 to 20 GeV/c, every 1 GeV/c + } + const AxisSpec axis_pt{ptbins, "p_{T,#gamma} (GeV/c)"}; + const AxisSpec axis_rapidity{{0.0, +0.8, +0.9}, "rapidity |y_{#gamma}|"}; + + if (doprocessGen) { + fRegistry.add("Generated/hPt", "pT;p_{T} (GeV/c)", kTH1F, {axis_pt}, true); + fRegistry.add("Generated/hPtY", "Generated info", kTH2F, {axis_pt, axis_rapidity}, true); + fRegistry.add("Generated/hPt_ConversionPhoton", "converted photon pT;p_{T} (GeV/c)", kTH1F, {axis_pt}, true); + fRegistry.add("Generated/hY_ConversionPhoton", "converted photon y;rapidity y", kTH1F, {{40, -2.0f, 2.0f}}, true); + fRegistry.add("Generated/hPhi_ConversionPhoton", "converted photon #varphi;#varphi (rad.)", kTH1F, {{180, 0, 2 * M_PI}}, true); + fRegistry.add("Generated/hXY", "conversion point in XY MC;V_{x} (cm);V_{y} (cm)", kTH2F, {{800, -100.0f, 100.0f}, {800, -100.0f, 100.0f}}, true); + fRegistry.add("Generated/hRZ", "conversion point in RZ MC;V_{z} (cm);R_{xy} (cm)", kTH2F, {{400, -100.0f, 100.0f}, {400, 0.f, 100.0f}}, true); + fRegistry.add("Generated/hRPhi", "conversion point of #varphi vs. R_{xy} MC;#varphi (rad.);R_{xy} (cm);N_{e}", kTH2F, {{360, 0.0f, 2 * M_PI}, {400, 0, 100}}, true); + fRegistry.add("Generated/hsConvPoint", "photon conversion point;r_{xy} (cm);#varphi (rad.);#eta;", kTHnSparseF, {{100, 0.0f, 100}, {90, 0, 2 * M_PI}, {80, -2, +2}}, true); } - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "V0Leg"); - THashList* list_v0leg = reinterpret_cast(fMainList->FindObject("V0Leg")); + // event info + auto hCollisionCounter = fRegistry.add("Event/before/hCollisionCounter", "collision counter;;Number of events", kTH1F, {{10, 0.5, 10.5}}, false); + hCollisionCounter->GetXaxis()->SetBinLabel(1, "all"); + hCollisionCounter->GetXaxis()->SetBinLabel(2, "No TF border"); + hCollisionCounter->GetXaxis()->SetBinLabel(3, "No ITS ROF border"); + hCollisionCounter->GetXaxis()->SetBinLabel(4, "No Same Bunch Pileup"); + hCollisionCounter->GetXaxis()->SetBinLabel(5, "Is Vertex ITSTPC"); + hCollisionCounter->GetXaxis()->SetBinLabel(6, "Is Good Zvtx FT0vsPV"); + hCollisionCounter->GetXaxis()->SetBinLabel(7, "FT0AND"); + hCollisionCounter->GetXaxis()->SetBinLabel(8, "sel8"); + hCollisionCounter->GetXaxis()->SetBinLabel(9, "|Z_{vtx}| < 10 cm"); + hCollisionCounter->GetXaxis()->SetBinLabel(10, "accepted"); + + fRegistry.add("Event/before/hZvtx", "vertex z; Z_{vtx} (cm)", kTH1F, {{100, -50, +50}}, false); + fRegistry.add("Event/before/hMultNTracksPV", "hMultNTracksPV; N_{track} to PV", kTH1F, {{6001, -0.5, 6000.5}}, false); + fRegistry.add("Event/before/hMultNTracksPVeta1", "hMultNTracksPVeta1; N_{track} to PV", kTH1F, {{6001, -0.5, 6000.5}}, false); + fRegistry.add("Event/before/hMultFT0", "hMultFT0;mult. FT0A;mult. FT0C", kTH2F, {{300, 0, 6000}, {300, 0, 6000}}, false); + fRegistry.add("Event/before/hCentFT0A", "hCentFT0A;centrality FT0A (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry.add("Event/before/hCentFT0C", "hCentFT0C;centrality FT0C (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry.add("Event/before/hCentFT0M", "hCentFT0M;centrality FT0M (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry.add("Event/before/hCentFT0MvsMultNTracksPV", "hCentFT0MvsMultNTracksPV;centrality FT0M (%);N_{track} to PV", kTH2F, {{110, 0, 110}, {600, 0, 6000}}, false); + fRegistry.add("Event/before/hMultFT0MvsMultNTracksPV", "hMultFT0MvsMultNTracksPV;mult. FT0M;N_{track} to PV", kTH2F, {{600, 0, 6000}, {600, 0, 6000}}, false); + fRegistry.addClone("Event/before/", "Event/after/"); + + // v0 info + fRegistry.add("V0/primary/hPt", "pT;p_{T,#gamma} (GeV/c)", kTH1F, {{2000, 0.0f, 20}}, false); + fRegistry.add("V0/primary/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{90, 0, 2 * M_PI}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("V0/primary/hXY", "conversion point in XY;V_{x} (cm);V_{y} (cm)", kTH2F, {{400, -100.0f, 100.0f}, {400, -100.0f, 100.0f}}, false); + fRegistry.add("V0/primary/hRZ", "conversion point in RZ;Z (cm);R_{xy} (cm)", kTH2F, {{200, -100, 100}, {200, 0.0f, 100.0f}}, false); + fRegistry.add("V0/primary/hCosPA", "V0CosPA;cosine pointing angle in 3D", kTH1F, {{100, 0.99f, 1.0f}}, false); + fRegistry.add("V0/primary/hCosPAXY", "V0CosPA;cosine pointing angle in XY", kTH1F, {{100, 0.99f, 1.0f}}, false); + fRegistry.add("V0/primary/hCosPARZ", "V0CosPA;cosine pointing angle in RZ", kTH1F, {{100, 0.99f, 1.0f}}, false); + fRegistry.add("V0/primary/hPCA", "distance between 2 legs;PCA (cm)", kTH1F, {{500, 0.0f, 5.0f}}, false); + fRegistry.add("V0/primary/hDCAxyz", "DCA to PV;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -5.f, +5.f}, {200, -5.f, +5.f}}, false); + fRegistry.add("V0/primary/hDCAz_Pt", "DCA_{z} to PV vs. p_{T};DCA_{z} (cm);p_{T} (GeV/c)", kTH2F, {{200, -5.f, +5.f}, {2000, 0.0f, 20}}, false); + fRegistry.add("V0/primary/hAPplot", "AP plot;#alpha;q_{T} (GeV/c)", kTH2F, {{200, -1.0f, +1.0f}, {250, 0.0f, 0.25f}}, false); + fRegistry.add("V0/primary/hMassGamma", "hMassGamma;R_{xy} (cm);m_{ee} (GeV/c^{2})", kTH2F, {{200, 0.0f, 100.0f}, {100, 0.0f, 0.1f}}, false); + fRegistry.add("V0/primary/hKFChi2vsM", "KF chi2 vs. m_{ee};m_{ee} (GeV/c^{2});KF chi2/NDF", kTH2F, {{100, 0.0f, 0.1f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/primary/hKFChi2vsR", "KF chi2 vs. conversion point in XY;R_{xy} (cm);KF chi2/NDF", kTH2F, {{200, 0.0f, 100.0f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/primary/hKFChi2vsX", "KF chi2 vs. conversion point in X;X (cm);KF chi2/NDF", kTH2F, {{200, -100.0f, 100.0f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/primary/hKFChi2vsY", "KF chi2 vs. conversion point in Y;Y (cm);KF chi2/NDF", kTH2F, {{200, -100.0f, 100.0f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/primary/hKFChi2vsZ", "KF chi2 vs. conversion point in Z;Z (cm);KF chi2/NDF", kTH2F, {{200, -100.0f, 100.0f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/primary/hPResolution", "p resolution;p_{#gamma} (GeV/c);#Deltap/p", kTH2F, {{1000, 0.0f, 10}, {100, 0, 0.1}}, false); + fRegistry.add("V0/primary/hPtResolution", "p_{T} resolution;p_{#gamma} (GeV/c);#Deltap_{T}/p_{T}", kTH2F, {{1000, 0.0f, 10}, {100, 0, 0.1}}, false); + fRegistry.add("V0/primary/hEtaResolution", "#eta resolution;p_{#gamma} (GeV/c);#Delta#eta", kTH2F, {{1000, 0.0f, 10}, {100, 0, 0.01}}, false); + fRegistry.add("V0/primary/hThetaResolution", "#theta resolution;p_{#gamma} (GeV/c);#Delta#theta (rad.)", kTH2F, {{1000, 0.0f, 10}, {100, 0, 0.01}}, false); + fRegistry.add("V0/primary/hPhiResolution", "#varphi resolution;p_{#gamma} (GeV/c);#Delta#varphi (rad.)", kTH2F, {{1000, 0.0f, 10}, {100, 0, 0.01}}, false); + fRegistry.add("V0/primary/hNgamma", "Number of true #gamma per collision;N_{#gamma} per event;Number of events", kTH1F, {{101, -0.5f, 100.5f}}); + fRegistry.add("V0/primary/hConvPoint_diffX", "conversion point diff X MC;X_{MC} (cm);X_{rec} - X_{MC} (cm)", kTH2F, {{200, -100, +100}, {100, -50.0f, 50.0f}}, true); + fRegistry.add("V0/primary/hConvPoint_diffY", "conversion point diff Y MC;Y_{MC} (cm);Y_{rec} - Y_{MC} (cm)", kTH2F, {{200, -100, +100}, {100, -50.0f, 50.0f}}, true); + fRegistry.add("V0/primary/hConvPoint_diffZ", "conversion point diff Z MC;Z_{MC} (cm);Z_{rec} - Z_{MC} (cm)", kTH2F, {{200, -100, +100}, {100, -50.0f, 50.0f}}, true); + fRegistry.add("V0/primary/hPtGen_DeltaPtOverPtGen", "photon p_{T} resolution;p_{T}^{gen} (GeV/c);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{1000, 0, 10}, {200, -1.0f, 1.0f}}, true); + fRegistry.add("V0/primary/hPtGen_DeltaEta", "photon #eta resolution;p_{T}^{gen} (GeV/c);#eta^{rec} - #eta^{gen}", kTH2F, {{1000, 0, 10}, {100, -0.5f, 0.5f}}, true); + fRegistry.add("V0/primary/hPtGen_DeltaPhi", "photon #varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{1000, 0, 10}, {100, -0.5f, 0.5f}}, true); + fRegistry.add("V0/primary/hRxyGen_DeltaPtOverPtGen", "photon p_{T} resolution; R_{xy}^{gen} (cm);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{100, 0, 100}, {200, -1.0f, 1.0f}}, true); + fRegistry.add("V0/primary/hsPhotonResolution", + "Photon resolution;p_{T};#eta;R_{xy};Z_{conv};Z_{vtx};#Deltap_{T}/p_{T};#Delta#eta;#Delta#phi", + kTHnSparseF, + {{100, 0, 10}, + {80, -1.6, 1.6}, + {100, 0, 100}, + {100, -50, 50}, + {100, -50, 50}, + {200, -1, 1}, + {100, -0.5, 0.5}, + {100, -0.5, 0.5}}, + false); + fRegistry.add("V0/primary/hRxyGen_DeltaEta", "photon #eta resolution;R_{xy}^{gen} (cm);#eta^{rec} - #eta^{gen}", kTH2F, {{100, 0, 100}, {100, -0.5f, 0.5f}}, true); + fRegistry.add("V0/primary/hRxyGen_DeltaPhi", "photon #varphi resolution;R_{xy}^{gen} (cm);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{100, 0, 100}, {100, -0.5f, 0.5f}}, true); + fRegistry.add("V0/primary/hRxyGen_DeltaR", "photon #varphi resolution;R_{xy}^{gen} (cm);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{100, 0, 100}, {100, 0, 100}}, true); + fRegistry.add("V0/primary/hsConvVtxZPtR", "z_{vtx} vs p_{T} vs R_{xy};z_{vtx} (cm);p_{T} (GeV/c);R_{xy} (cm)", kTHnSparseF, {{100, -20.0f, +20.0f}, {100, 0.0f, 10.0f}, {100, 0, 100}}, false); + fRegistry.add("V0/primary/hXY_MC", "X vs. Y of true photon conversion point.;X (cm);Y (cm)", kTH2F, {{400, -100.0f, +100}, {400, -100, +100}}, true); + fRegistry.add("V0/primary/hRZ_MC", "R vs. Z of true photon conversion point;Z (cm);R_{xy} (cm)", kTH2F, {{200, -100.0f, +100}, {200, 0, 100}}, true); + fRegistry.add("V0/primary/hsConvPoint", "photon conversion point;r_{xy} (cm);#varphi (rad.);#eta;", kTHnSparseF, {{100, 0.0f, 100}, {90, 0, 2 * M_PI}, {80, -2, +2}}, false); + fRegistry.addClone("V0/primary/", "V0/fromWD/"); // from weak decay + fRegistry.addClone("V0/primary/", "V0/fromHS/"); // from hadronic shower in detector materials + fRegistry.addClone("V0/primary/", "V0/fromPi0Dalitz/"); // misidentified dielectron from pi0 dalitz decay + fRegistry.addClone("V0/primary/", "V0/fromEtaDalitz/"); // misidentified dielectron from eta dalitz decay + fRegistry.addClone("V0/primary/hPt", "V0/candidate/hPt"); // only for purity + fRegistry.addClone("V0/primary/hEtaPhi", "V0/candidate/hEtaPhi"); // only for purity + + // v0leg info + fRegistry.add("V0Leg/primary/hPt", "pT;p_{T,e} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); + fRegistry.add("V0Leg/primary/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{1000, -50, 50}}, false); + fRegistry.add("V0Leg/primary/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{90, 0, 2 * M_PI}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("V0Leg/primary/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -50.0f, 50.0f}, {200, -50.0f, 50.0f}}, false); + fRegistry.add("V0Leg/primary/hNclsTPC", "number of TPC clusters", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("V0Leg/primary/hNcrTPC", "number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("V0Leg/primary/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("V0Leg/primary/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("V0Leg/primary/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("V0Leg/primary/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("V0Leg/primary/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("V0Leg/primary/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("V0Leg/primary/hTPCNclsShared", "TPC Ncls shared/Ncls;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); + fRegistry.add("V0Leg/primary/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("V0Leg/primary/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("V0Leg/primary/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("V0Leg/primary/hMeanClusterSizeITS", "mean cluster size ITS; on ITS #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {160, 0, 16}}, false); + fRegistry.add("V0Leg/primary/hXY", "X vs. Y;X (cm);Y (cm)", kTH2F, {{100, 0, 100}, {40, -20, 20}}, false); + fRegistry.add("V0Leg/primary/hZX", "Z vs. X;Z (cm);X (cm)", kTH2F, {{200, -100, 100}, {100, 0, 100}}, false); + fRegistry.add("V0Leg/primary/hZY", "Z vs. Y;Z (cm);Y (cm)", kTH2F, {{200, -100, 100}, {40, -20, 20}}, false); + fRegistry.add("V0Leg/primary/hPtGen_DeltaPtOverPtGen", "electron p_{T} resolution;p_{T}^{gen} (GeV/c);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{1000, 0, 10}, {200, -1.0f, 1.0f}}, true); + fRegistry.add("V0Leg/primary/hPtGen_DeltaEta", "electron #eta resolution;p_{T}^{gen} (GeV/c);#eta^{rec} - #eta^{gen}", kTH2F, {{1000, 0, 10}, {100, -0.5f, 0.5f}}, true); + if (cfg_fill_resolution) { + fRegistry.add("V0Leg/primary/hsPhotonResolution", + "Photon resolution;p_{T};#eta;R_{xy};Z_{conv};Z_{vtx};#Deltap_{T}/p_{T};#Delta#eta;#Delta#phi", + kTHnSparseF, + {{100, 0, 10}, + {80, -1.6, 1.6}, + {100, 0, 100}, + {100, -50, 50}, + {100, -50, 50}, + {200, -1, 1}, + {100, -0.5, 0.5}, + {100, -0.5, 0.5}}, + false); + } - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "V0"); - THashList* list_v0 = reinterpret_cast(fMainList->FindObject("V0")); + fRegistry.add("V0Leg/primary/hPtGen_DeltaPhi", "electron #varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{1000, 0, 10}, {100, -0.5f, 0.5f}}, true); + fRegistry.add("V0Leg/primary/hRxyGen_DeltaPtOverPtGen", "photon p_{T} resolution; R_{xy}^{gen} (cm);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{100, 0, 100}, {200, -1.0f, 1.0f}}, true); + fRegistry.add("V0Leg/primary/hRxyGen_DeltaEta", "photon #eta resolution;R_{xy}^{gen} (cm);#eta^{rec} - #eta^{gen}", kTH2F, {{100, 0, 100}, {100, -0.5f, 0.5f}}, true); + fRegistry.add("V0Leg/primary/hRxyGen_DeltaPhi", "photon #varphi resolution;R_{xy}^{gen} (cm);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{100, 0, 100}, {100, 0, 100}}, true); + fRegistry.add("V0Leg/primary/hRxyGen_DeltaR", "photon p_{T} resolution; R_{xy}^{gen} (cm);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{100, 0, 100}, {200, -1.0f, 1.0f}}, true); - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Generated"); - THashList* list_gen = reinterpret_cast(fMainList->FindObject("Generated")); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_gen, "Generated", "Photon"); + fRegistry.addClone("V0Leg/primary/", "V0Leg/fromWD/"); // from weak decay + fRegistry.addClone("V0Leg/primary/", "V0Leg/fromHS/"); // from hadronic shower in detector materials + fRegistry.addClone("V0Leg/primary/", "V0Leg/fromPi0Dalitz/"); // misidentified dielectron from pi0 dalitz decay + fRegistry.addClone("V0Leg/primary/", "V0Leg/fromEtaDalitz/"); // misidentified dielectron from eta dalitz decay - for (const auto& cut : fPCMCuts) { - const char* cutname = cut.GetName(); - o2::aod::pwgem::photon::histogram::AddHistClass(list_v0leg, cutname); - o2::aod::pwgem::photon::histogram::AddHistClass(list_v0, cutname); - } + fRegistry.addClone("V0Leg/primary/hPt", "V0Leg/candidate/hPt"); // only for purity + fRegistry.addClone("V0Leg/primary/hEtaPhi", "V0Leg/candidate/hEtaPhi"); // only for purity + } - // for single tracks - for (auto& cut : fPCMCuts) { - std::string_view cutname = cut.GetName(); - THashList* list = reinterpret_cast(fMainList->FindObject("V0Leg")->FindObject(cutname.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list, "V0Leg", "mc"); - } + void DefineEMEventCut() + { + fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireNoCollInTimeRangeStandard(eventcuts.cfgRequireNoCollInTimeRangeStandard); + fEMEventCut.SetRequireNoCollInTimeRangeStrict(eventcuts.cfgRequireNoCollInTimeRangeStrict); + fEMEventCut.SetRequireNoCollInITSROFStandard(eventcuts.cfgRequireNoCollInITSROFStandard); + fEMEventCut.SetRequireNoCollInITSROFStrict(eventcuts.cfgRequireNoCollInITSROFStrict); + fEMEventCut.SetRequireNoHighMultCollInPrevRof(eventcuts.cfgRequireNoHighMultCollInPrevRof); + } + + void DefinePCMCut() + { + fV0PhotonCut = V0PhotonCut("fV0PhotonCut", "fV0PhotonCut"); + + // for v0 + fV0PhotonCut.SetV0PtRange(pcmcuts.cfg_min_pt_v0, pcmcuts.cfg_max_pt_v0); + fV0PhotonCut.SetV0EtaRange(pcmcuts.cfg_min_eta_v0, pcmcuts.cfg_max_eta_v0); + fV0PhotonCut.SetMinCosPA(pcmcuts.cfg_min_cospa); + fV0PhotonCut.SetMaxPCA(pcmcuts.cfg_max_pca); + fV0PhotonCut.SetMaxChi2KF(pcmcuts.cfg_max_chi2kf); + fV0PhotonCut.SetRxyRange(pcmcuts.cfg_min_v0radius, pcmcuts.cfg_max_v0radius); + fV0PhotonCut.SetAPRange(pcmcuts.cfg_max_alpha_ap, pcmcuts.cfg_max_qt_ap); + fV0PhotonCut.RejectITSib(pcmcuts.cfg_reject_v0_on_itsib); + + // for track + fV0PhotonCut.SetMinNClustersTPC(pcmcuts.cfg_min_ncluster_tpc); + fV0PhotonCut.SetMinNCrossedRowsTPC(pcmcuts.cfg_min_ncrossedrows); + fV0PhotonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fV0PhotonCut.SetMaxFracSharedClustersTPC(pcmcuts.cfg_max_frac_shared_clusters_tpc); + fV0PhotonCut.SetChi2PerClusterTPC(0.0, pcmcuts.cfg_max_chi2tpc); + fV0PhotonCut.SetTPCNsigmaElRange(pcmcuts.cfg_min_TPCNsigmaEl, pcmcuts.cfg_max_TPCNsigmaEl); + fV0PhotonCut.SetChi2PerClusterITS(-1e+10, pcmcuts.cfg_max_chi2its); + fV0PhotonCut.SetNClustersITS(0, 7); + fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); + fV0PhotonCut.SetIsWithinBeamPipe(pcmcuts.cfg_require_v0_with_correct_xz); + fV0PhotonCut.SetDisableITSonly(pcmcuts.cfg_disable_itsonly_track); + fV0PhotonCut.SetDisableTPConly(pcmcuts.cfg_disable_tpconly_track); + fV0PhotonCut.SetRequireITSTPC(pcmcuts.cfg_require_v0_with_itstpc); + fV0PhotonCut.SetRequireITSonly(pcmcuts.cfg_require_v0_with_itsonly); + fV0PhotonCut.SetRequireTPConly(pcmcuts.cfg_require_v0_with_tpconly); + } - // for V0s - for (auto& cut : fPCMCuts) { - std::string_view cutname = cut.GetName(); - THashList* list = reinterpret_cast(fMainList->FindObject("V0")->FindObject(cutname.data())); - o2::aod::pwgem::photon::histogram::DefineHistograms(list, "V0", "mc"); + template + void fillEventInfo(TCollision const& collision, const float /*weight*/ = 1.f) + { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 1.0); + if (collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 2.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 3.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 4.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 5.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 6.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 7.0); + } + if (collision.sel8()) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 8.0); + } + if (std::fabs(collision.posZ()) < 10.0) { + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 9.0); } + + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hZvtx"), collision.posZ()); + + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultNTracksPV"), collision.multNTracksPV()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultNTracksPVeta1"), collision.multNTracksPVeta1()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0"), collision.multFT0A(), collision.multFT0C()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0A"), collision.centFT0A()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0C"), collision.centFT0C()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0M"), collision.centFT0M()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0MvsMultNTracksPV"), collision.centFT0M(), collision.multNTracksPV()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0MvsMultNTracksPV"), collision.multFT0A() + collision.multFT0C(), collision.multNTracksPV()); } - void DefineCuts() + template + void fillV0Info(TV0 const& v0, TMCV0 const& mcphoton, TMCLeg const& mcleg) { - TString cutNamesStr = fConfigPCMCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - const char* cutname = objArray->At(icut)->GetName(); - LOGF(info, "add cut : %s", cutname); - fPCMCuts.push_back(*pcmcuts::GetCut(cutname)); - } + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPt"), v0.pt()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hEtaPhi"), v0.phi(), v0.eta()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hXY"), v0.vx(), v0.vy()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRZ"), v0.vz(), v0.v0radius()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hCosPA"), v0.cospa()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hCosPAXY"), v0.cospaXY()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hCosPARZ"), v0.cospaRZ()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPCA"), v0.pca()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hDCAxyz"), v0.dcaXYtopv(), v0.dcaZtopv()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hDCAz_Pt"), v0.dcaZtopv(), v0.pt()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hAPplot"), v0.alpha(), v0.qtarm()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hMassGamma"), v0.v0radius(), v0.mGamma()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hKFChi2vsM"), v0.mGamma(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hKFChi2vsR"), v0.v0radius(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hsConvVtxZPtR"), + v0.vz(), v0.pt(), v0.v0radius()); + + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hKFChi2vsX"), v0.vx(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hKFChi2vsY"), v0.vy(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hKFChi2vsZ"), v0.vz(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPResolution"), v0.p(), getPResolution(v0) / v0.p()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPtResolution"), v0.p(), getPtResolution(v0) / v0.pt()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hEtaResolution"), v0.p(), getEtaResolution(v0)); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hThetaResolution"), v0.p(), getThetaResolution(v0)); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPhiResolution"), v0.p(), getPhiResolution(v0)); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaPtOverPtGen"), mcphoton.pt(), (v0.pt() - mcphoton.pt()) / mcphoton.pt()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaEta"), mcphoton.pt(), v0.eta() - mcphoton.eta()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaPhi"), mcphoton.pt(), v0.phi() - mcphoton.phi()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaPtOverPtGen"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), (v0.pt() - mcphoton.pt()) / mcphoton.pt()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaEta"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), v0.eta() - mcphoton.eta()); + if (cfg_fill_resolution) { + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hsPhotonResolution"), + mcphoton.pt(), + mcphoton.eta(), + std::sqrt(mcleg.vx() * mcleg.vx() + mcleg.vy() * mcleg.vy()), + mcleg.vz(), + v0.vz(), + (v0.pt() - mcphoton.pt()) / mcphoton.pt(), + v0.eta() - mcphoton.eta(), + TVector2::Phi_mpi_pi(v0.phi() - mcphoton.phi())); } - LOGF(info, "Number of PCM cuts = %d", fPCMCuts.size()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaPhi"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), v0.phi() - mcphoton.phi()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaR"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), v0.v0radius() - std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2))); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hConvPoint_diffX"), mcleg.vx(), v0.vx() - mcleg.vx()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hConvPoint_diffY"), mcleg.vy(), v0.vy() - mcleg.vy()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hConvPoint_diffZ"), mcleg.vz(), v0.vz() - mcleg.vz()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hXY_MC"), mcleg.vx(), mcleg.vy()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRZ_MC"), mcleg.vz(), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2))); + + float phi_cp = std::atan2(v0.vy(), v0.vx()); + o2::math_utils::bringTo02Pi(phi_cp); + float eta_cp = std::atanh(v0.vz() / std::sqrt(std::pow(v0.vx(), 2) + std::pow(v0.vy(), 2) + std::pow(v0.vz(), 2))); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hsConvPoint"), v0.v0radius(), phi_cp, eta_cp); } - void init(InitContext&) + template + void fillV0LegInfo(TLeg const& leg) { - DefineCuts(); - addhistograms(); // please call this after DefinCuts(); - TString ev_cut_name = fConfigEMEventCut.value; - fEMEventCut = *eventcuts::GetCut(ev_cut_name.Data()); - - fOutputEvent.setObject(reinterpret_cast(fMainList->FindObject("Event"))); - fOutputV0Leg.setObject(reinterpret_cast(fMainList->FindObject("V0Leg"))); - fOutputV0.setObject(reinterpret_cast(fMainList->FindObject("V0"))); - fOutputGen.setObject(reinterpret_cast(fMainList->FindObject("Generated"))); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hPt"), leg.pt()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hQoverPt"), leg.sign() / leg.pt()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hEtaPhi"), leg.phi(), leg.eta()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hDCAxyz"), leg.dcaXY(), leg.dcaZ()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hNclsITS"), leg.itsNCls()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hNclsTPC"), leg.tpcNClsFound()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hNcrTPC"), leg.tpcNClsCrossedRows()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCNcr2Nf"), leg.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCNcls2Nf"), leg.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCNclsShared"), leg.pt(), leg.tpcFractionSharedCls()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hChi2TPC"), leg.tpcChi2NCl()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hChi2ITS"), leg.itsChi2NCl()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hITSClusterMap"), leg.itsClusterMap()); + if (leg.hasITS()) { + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hMeanClusterSizeITS"), leg.p(), leg.meanClusterSizeITS() * std::cos(std::atan(leg.tgl()))); + } + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCdEdx"), leg.tpcInnerParam(), leg.tpcSignal()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCNsigmaEl"), leg.tpcInnerParam(), leg.tpcNSigmaEl()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCNsigmaPi"), leg.tpcInnerParam(), leg.tpcNSigmaPi()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hXY"), leg.x(), leg.y()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hZX"), leg.z(), leg.x()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hZY"), leg.z(), leg.y()); + auto mcleg = leg.template emmcparticle_as(); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaPtOverPtGen"), mcleg.pt(), (leg.pt() - mcleg.pt()) / mcleg.pt()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaEta"), mcleg.pt(), leg.eta() - mcleg.eta()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaPhi"), mcleg.pt(), leg.phi() - mcleg.phi()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaPtOverPtGen"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), (leg.pt() - mcleg.pt()) / mcleg.pt()); + if (cfg_fill_resolution) { + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hsPhotonResolution"), + mcleg.pt(), + mcleg.eta(), + std::sqrt(mcleg.vx() * mcleg.vx() + mcleg.vy() * mcleg.vy()), + mcleg.vz(), + leg.z(), + (leg.pt() - mcleg.pt()) / mcleg.pt(), + leg.eta() - mcleg.eta(), + TVector2::Phi_mpi_pi(leg.phi() - mcleg.phi())); + } + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaEta"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), leg.eta() - mcleg.eta()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaPhi"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), leg.phi() - mcleg.phi()); } - Partition grouped_collisions = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); // this goes to same event. + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + using FilteredMyCollisions = soa::Filtered; Preslice perCollision = aod::v0photonkf::emeventId; - void processQCMC(MyCollisions const&, MyV0Photons const& v0photons, MyMCV0Legs const&, aod::EMMCParticles const& mcparticles, aod::EMMCEvents const&) + void processQCMC(FilteredMyCollisions const& collisions, MyV0Photons const& v0photons, MyMCV0Legs const&, aod::EMMCParticles const& mcparticles, aod::EMMCEvents const&) { - THashList* list_ev_before = static_cast(fMainList->FindObject("Event")->FindObject(event_types[0].data())); - THashList* list_ev_after = static_cast(fMainList->FindObject("Event")->FindObject(event_types[1].data())); - THashList* list_v0 = static_cast(fMainList->FindObject("V0")); - THashList* list_v0leg = static_cast(fMainList->FindObject("V0Leg")); - - for (auto& collision : grouped_collisions) { + for (auto& collision : collisions) { const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_before, "", collision); + fillEventInfo<0>(collision); if (!fEMEventCut.IsSelected(collision)) { continue; } - o2::aod::pwgem::photon::histogram::FillHistClass(list_ev_after, "", collision); - reinterpret_cast(list_ev_before->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); - reinterpret_cast(list_ev_after->FindObject("hCollisionCounter"))->Fill("accepted", 1.f); + fillEventInfo<1>(collision); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 10.0); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 10.0); // accepted auto V0Photons_coll = v0photons.sliceBy(perCollision, collision.globalIndex()); - for (const auto& cut : fPCMCuts) { - THashList* list_v0_cut = static_cast(list_v0->FindObject(cut.GetName())); - THashList* list_v0leg_cut = static_cast(list_v0leg->FindObject(cut.GetName())); - int nv0 = 0; - for (auto& v0 : V0Photons_coll) { - auto pos = v0.posTrack_as(); - auto ele = v0.negTrack_as(); - auto posmc = pos.template emmcparticle_as(); - auto elemc = ele.template emmcparticle_as(); - - // LOGF(info, "posmc.isPhysicalPrimary() = %d, posmc.producedByGenerator() = %d, elemc.isPhysicalPrimary() = %d, elemc.producedByGenerator() = %d", posmc.isPhysicalPrimary(), posmc.producedByGenerator(), elemc.isPhysicalPrimary(), elemc.producedByGenerator()); - - if (cut.IsSelected(v0)) { - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hPt_Photon_Candidate"))->Fill(v0.pt()); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hEtaPhi_Photon_Candidate"))->Fill(v0.phi(), v0.eta()); - - int photonid = FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 22, mcparticles); - if (photonid < 0) { - continue; + int ng_primary = 0, ng_wd = 0, ng_hs = 0, nee_pi0 = 0, nee_eta = 0; + for (auto& v0 : V0Photons_coll) { + auto pos = v0.posTrack_as(); + auto ele = v0.negTrack_as(); + auto posmc = pos.template emmcparticle_as(); + auto elemc = ele.template emmcparticle_as(); + + // LOGF(info, "posmc.isPhysicalPrimary() = %d, posmc.producedByGenerator() = %d, elemc.isPhysicalPrimary() = %d, elemc.producedByGenerator() = %d", posmc.isPhysicalPrimary(), posmc.producedByGenerator(), elemc.isPhysicalPrimary(), elemc.producedByGenerator()); + + if (!fV0PhotonCut.IsSelected(v0)) { + continue; + } + + fRegistry.fill(HIST("V0/candidate/hPt"), v0.pt()); + fRegistry.fill(HIST("V0/candidate/hEtaPhi"), v0.phi(), v0.eta()); + for (auto& leg : {pos, ele}) { + fRegistry.fill(HIST("V0Leg/candidate/hPt"), leg.pt()); + fRegistry.fill(HIST("V0Leg/candidate/hEtaPhi"), leg.phi(), leg.eta()); + } + + int photonid = FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 22, mcparticles); + int pi0id = FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 111, mcparticles); // pi0 dalitz decay + int etaid = FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 221, mcparticles); // eta dalitz decay + if (photonid < 0 && pi0id < 0 && etaid < 0) { + continue; + } + + if (photonid > 0) { + auto mcphoton = mcparticles.iteratorAt(photonid); + if (cfgRequireTrueAssociation && (mcphoton.emmceventId() != collision.emmceventId())) { + continue; + } + + if (mcphoton.isPhysicalPrimary() || mcphoton.producedByGenerator()) { + fillV0Info<0>(v0, mcphoton, elemc); + for (auto& leg : {pos, ele}) { + fillV0LegInfo<0>(leg); } - auto mcphoton = mcparticles.iteratorAt(photonid); - - float rxy_rec = sqrt(v0.vx() * v0.vx() + v0.vy() * v0.vy()); - float rxy_mc = sqrt(posmc.vx() * posmc.vx() + posmc.vy() * posmc.vy()); - float eta_cp = std::atanh(v0.vz() / sqrt(pow(v0.vx(), 2) + pow(v0.vy(), 2) + pow(v0.vz(), 2))); - - o2::aod::pwgem::photon::histogram::FillHistClass(list_v0_cut, "", v0); - if (mcphoton.isPhysicalPrimary() || mcphoton.producedByGenerator()) { - if (IsConversionPointInAcceptance(mcphoton, maxRgen, maxY, margin_z_mc, mcparticles)) { - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hPt_Photon_Primary"))->Fill(v0.pt()); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hEtaPhi_Photon_Primary"))->Fill(v0.phi(), v0.eta()); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hXY_Photon_Primary"))->Fill(v0.vx(), v0.vy()); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hXY_Photon_Primary_MC"))->Fill(posmc.vx(), posmc.vy()); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hRZ_Photon_Primary"))->Fill(v0.vz(), rxy_rec); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hRZ_Photon_Primary_MC"))->Fill(posmc.vz(), rxy_mc); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hCosPA_Rxy_Photon_Primary"))->Fill(v0.v0radius(), v0.cospa()); - - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaPtOverPtGen"))->Fill(mcphoton.pt(), (v0.pt() - mcphoton.pt()) / mcphoton.pt()); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaEta"))->Fill(mcphoton.pt(), v0.eta() - mcphoton.eta()); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaPhi"))->Fill(mcphoton.pt(), v0.phi() - mcphoton.phi()); - - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hEtaRec_DeltaPtOverPtGen"))->Fill(eta_cp, (v0.pt() - mcphoton.pt()) / mcphoton.pt()); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hEtaRec_DeltaEta"))->Fill(eta_cp, v0.eta() - mcphoton.eta()); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hEtaRec_DeltaPhi"))->Fill(eta_cp, v0.phi() - mcphoton.phi()); - - for (auto& leg : {pos, ele}) { - o2::aod::pwgem::photon::histogram::FillHistClass(list_v0leg_cut, "", leg); - auto mcleg = leg.template emmcparticle_as(); - reinterpret_cast(fMainList->FindObject("V0Leg")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaPtOverPtGen"))->Fill(mcleg.pt(), (leg.pt() - mcleg.pt()) / mcleg.pt()); - reinterpret_cast(fMainList->FindObject("V0Leg")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaEta"))->Fill(mcleg.pt(), leg.eta() - mcleg.eta()); - reinterpret_cast(fMainList->FindObject("V0Leg")->FindObject(cut.GetName())->FindObject("hPtGen_DeltaPhi"))->Fill(mcleg.pt(), leg.phi() - mcleg.phi()); - reinterpret_cast(fMainList->FindObject("V0Leg")->FindObject(cut.GetName())->FindObject("hEtaRec_DeltaPtOverPtGen"))->Fill(eta_cp, (leg.pt() - mcleg.pt()) / mcleg.pt()); - reinterpret_cast(fMainList->FindObject("V0Leg")->FindObject(cut.GetName())->FindObject("hEtaRec_DeltaEta"))->Fill(eta_cp, leg.eta() - mcleg.eta()); - reinterpret_cast(fMainList->FindObject("V0Leg")->FindObject(cut.GetName())->FindObject("hEtaRec_DeltaPhi"))->Fill(eta_cp, leg.phi() - mcleg.phi()); - } - } - - } else if (IsFromWD(mcphoton.emmcevent(), mcphoton, mcparticles)) { - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hPt_Photon_FromWD"))->Fill(v0.pt()); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hEtaPhi_Photon_FromWD"))->Fill(v0.phi(), v0.eta()); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hCosPA_Rxy_Photon_FromWD"))->Fill(v0.v0radius(), v0.cospa()); - } else { - // int mother_pdg = 0; - // if(mcphoton.has_mothers()){ - // auto mp = mcphoton.template mothers_first_as(); - // mother_pdg = mp.pdgCode(); - // } - // LOGF(info, "mcphoton.vx() = %f, mcphoton.vy() = %f, mcphoton.vz() = %f, mother_pdg = %d", mcphoton.vx(), mcphoton.vy(), mcphoton.vz(), mother_pdg); - float rxy_photon_hs = sqrt(mcphoton.vx() * mcphoton.vx() + mcphoton.vy() * mcphoton.vy()); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hPt_Photon_hs"))->Fill(v0.pt()); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hEtaPhi_Photon_hs"))->Fill(v0.phi(), v0.eta()); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hXY_Photon_hs_MC"))->Fill(mcphoton.vx(), mcphoton.vy()); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hRZ_Photon_hs_MC"))->Fill(mcphoton.vz(), rxy_photon_hs); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hCosPA_Rxy_Photon_hs"))->Fill(v0.v0radius(), v0.cospa()); + ng_primary++; + } else if (IsFromWD(mcphoton.template emmcevent_as(), mcphoton, mcparticles) > 0) { + fillV0Info<1>(v0, mcphoton, elemc); + for (auto& leg : {pos, ele}) { + fillV0LegInfo<1>(leg); } - - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hConvPoint_diffX"))->Fill(elemc.vx(), v0.vx() - elemc.vx()); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hConvPoint_diffY"))->Fill(elemc.vy(), v0.vy() - elemc.vy()); - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hConvPoint_diffZ"))->Fill(elemc.vz(), v0.vz() - elemc.vz()); - nv0++; + ng_wd++; + } else { + fillV0Info<2>(v0, mcphoton, elemc); + for (auto& leg : {pos, ele}) { + fillV0LegInfo<2>(leg); + } + ng_hs++; + // LOGF(info, "mcphoton.vx() = %f, mcphoton.vy() = %f, mcphoton.vz() = %f, mother_pdg = %d", mcphoton.vx(), mcphoton.vy(), mcphoton.vz(), mother_pdg); + } + } else if (pi0id > 0) { + auto mcpi0 = mcparticles.iteratorAt(pi0id); + if (cfgRequireTrueAssociation && (mcpi0.emmceventId() != collision.emmceventId())) { + continue; + } + if (mcpi0.isPhysicalPrimary() || mcpi0.producedByGenerator()) { + fillV0Info<3>(v0, mcpi0, elemc); + for (auto& leg : {pos, ele}) { + fillV0LegInfo<3>(leg); + } + nee_pi0++; + } + } else if (etaid > 0) { + auto mceta = mcparticles.iteratorAt(etaid); + if (cfgRequireTrueAssociation && (mceta.emmceventId() != collision.emmceventId())) { + continue; + } + if (mceta.isPhysicalPrimary() || mceta.producedByGenerator()) { + fillV0Info<4>(v0, mceta, elemc); + for (auto& leg : {pos, ele}) { + fillV0LegInfo<4>(leg); + } + nee_eta++; } - } // end of v0 loop - reinterpret_cast(fMainList->FindObject("V0")->FindObject(cut.GetName())->FindObject("hNgamma"))->Fill(nv0); - } // end of cut loop - } // end of collision loop - } // end of process + } + } // end of v0 loop + fRegistry.fill(HIST("V0/primary/hNgamma"), ng_primary); + fRegistry.fill(HIST("V0/fromWD/hNgamma"), ng_wd); + fRegistry.fill(HIST("V0/fromHS/hNgamma"), ng_hs); + fRegistry.fill(HIST("V0/fromPi0Dalitz/hNgamma"), nee_pi0); + fRegistry.fill(HIST("V0/fromEtaDalitz/hNgamma"), nee_eta); + } // end of collision loop + } // end of process + + template + void fillBinnedData(TBinnedData const& binned_data, const float weight = 1.f) + { + int xbin = 0, ybin = 0, zbin = 0; + auto hPtY = fRegistry.get(HIST("Generated/hPtY")); // 2D + auto hPt = fRegistry.get(HIST("Generated/hPt")); // 1D + + for (int ibin = 0; ibin < hPtY->GetNcells(); ibin++) { + int nentry = binned_data[ibin]; + hPtY->GetBinXYZ(ibin, xbin, ybin, zbin); + float pt = hPtY->GetXaxis()->GetBinCenter(xbin); + float y = hPtY->GetYaxis()->GetBinCenter(ybin); + if (y > pcmcuts.cfg_max_eta_v0) { + continue; + } + + for (int j = 0; j < nentry; j++) { + hPtY->Fill(pt, y, weight); + hPt->Fill(pt, weight); + } + } + } + // aod::EMMCParticles contain primary photon conversions. // aod::BinnedGenPts contain primary photons PresliceUnsorted perMcCollision = aod::emmcparticle::emmceventId; - void processGen(MyCollisions const&, aod::EMMCEvents const&, aod::EMMCParticles const& mcparticles) + void processGen(FilteredMyCollisions const& collisions, MyMCCollisions const&, aod::EMMCParticles const& mcparticles) { // loop over mc stack and fill histograms for pure MC truth signals // all MC tracks which belong to the MC event corresponding to the current reconstructed event - for (auto& collision : grouped_collisions) { + for (auto& collision : collisions) { const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } - auto mccollision = collision.emmcevent(); - // LOGF(info, "mccollision.globalIndex() = %d", mccollision.globalIndex()); if (!fEMEventCut.IsSelected(collision)) { continue; } + auto mccollision = collision.template emmcevent_as(); + auto binned_data_gamma_gen = mccollision.generatedGamma(); + fillBinnedData(binned_data_gamma_gen, 1.f); + // LOGF(info, "mccollision.globalIndex() = %d", mccollision.globalIndex()); + auto mctracks_coll = mcparticles.sliceBy(perMcCollision, mccollision.globalIndex()); for (auto& mctrack : mctracks_coll) { - if (abs(mctrack.y()) > maxY) { + if (std::fabs(mctrack.y()) > pcmcuts.cfg_max_eta_v0) { continue; } - if (abs(mctrack.pdgCode()) == 22 && (mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hPt_Photon"))->Fill(mctrack.pt()); - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hY_Photon"))->Fill(mctrack.y()); - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hPhi_Photon"))->Fill(mctrack.phi()); + if (std::abs(mctrack.pdgCode()) == 22 && (mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { + auto daughter = mcparticles.iteratorAt(mctrack.daughtersIds()[0]); // choose ele or pos. + float rxy_gen_e = std::sqrt(std::pow(daughter.vx(), 2) + std::pow(daughter.vy(), 2)); + float phi_cp = std::atan2(daughter.vy(), daughter.vx()); + o2::math_utils::bringTo02Pi(phi_cp); + float eta_cp = std::atanh(daughter.vz() / std::sqrt(std::pow(daughter.vx(), 2) + std::pow(daughter.vy(), 2) + std::pow(daughter.vz(), 2))); - bool is_ele_fromPC = false; - bool is_pos_fromPC = false; - auto daughtersIds = mctrack.daughtersIds(); - if (daughtersIds.size() != 2) { + if (rxy_gen_e < std::fabs(daughter.vz()) * std::tan(2 * std::atan(std::exp(-pcmcuts.cfg_max_eta_v0))) - margin_z_mc) { continue; } - for (auto& daughterId : daughtersIds) { - if (daughterId < 0) { - continue; - } - auto daughter = mcparticles.iteratorAt(daughterId); // always electron and positron - float rxy_gen_e = sqrt(pow(daughter.vx(), 2) + pow(daughter.vy(), 2)); - if (rxy_gen_e > maxRgen || rxy_gen_e < abs(daughter.vz()) * std::tan(2 * std::atan(std::exp(-maxY))) - margin_z_mc) { - continue; - } - - if (daughter.pdgCode() == 11) { // electron from photon conversion - is_ele_fromPC = true; - } else if (daughter.pdgCode() == -11) { // positron from photon conversion - is_pos_fromPC = true; - } - } // end of daughter loop - - if (is_ele_fromPC && is_pos_fromPC) { // ele and pos from photon conversion - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hPt_ConvertedPhoton"))->Fill(mctrack.pt()); - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hY_ConvertedPhoton"))->Fill(mctrack.y()); - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hPhi_ConvertedPhoton"))->Fill(mctrack.phi()); - - auto daughter = mcparticles.iteratorAt(daughtersIds[0]); // choose ele or pos. - float rxy_gen_e = sqrt(pow(daughter.vx(), 2) + pow(daughter.vy(), 2)); - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hPhotonRZ"))->Fill(daughter.vz(), rxy_gen_e); - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hPhotonRxy"))->Fill(daughter.vx(), daughter.vy()); - reinterpret_cast(fMainList->FindObject("Generated")->FindObject("hPhotonPhivsRxy"))->Fill(daughter.phi(), rxy_gen_e); + if (rxy_gen_e > maxRgen) { + continue; } + + fRegistry.fill(HIST("Generated/hPt_ConversionPhoton"), mctrack.pt()); + fRegistry.fill(HIST("Generated/hY_ConversionPhoton"), mctrack.y()); + fRegistry.fill(HIST("Generated/hPhi_ConversionPhoton"), mctrack.phi()); + fRegistry.fill(HIST("Generated/hsConvPoint"), rxy_gen_e, phi_cp, eta_cp); + fRegistry.fill(HIST("Generated/hXY"), daughter.vx(), daughter.vy()); + fRegistry.fill(HIST("Generated/hRZ"), daughter.vz(), rxy_gen_e); + fRegistry.fill(HIST("Generated/hRPhi"), phi_cp, rxy_gen_e); } } // end of mctrack loop per collision - } // end of collision loop + } // end of collision loop } - void processDummy(MyCollisions const&) - { - // do nothing - } + void processDummy(MyCollisions const&) {} PROCESS_SWITCH(PCMQCMC, processQCMC, "run PCM QC in MC", false); PROCESS_SWITCH(PCMQCMC, processGen, "run generated information", false); diff --git a/PWGEM/PhotonMeson/Tasks/prefilterPhoton.cxx b/PWGEM/PhotonMeson/Tasks/prefilterPhoton.cxx new file mode 100644 index 00000000000..4b0ce098f6c --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/prefilterPhoton.cxx @@ -0,0 +1,637 @@ +// 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. +// +// ======================== +// +// This code produces information on prefilter for photon. +// Please write to: daiki.sekihata@cern.ch + +#include +#include +#include +#include +#include + +// #include "TString.h" +#include "Math/Vector4D.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +// #include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" + +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::photonmeson::photonpair; + +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; + +using MyV0Photons = soa::Join; +using MyV0Photon = MyV0Photons::iterator; + +using MyPrimaryElectrons = soa::Join; +using MyPrimaryElectron = MyPrimaryElectrons::iterator; + +struct prefilterPhoton { + Produces pfb_v0_derived; + Produces pfb_ele_derived; + + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentMin{"cfgCentMin", -1, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + + EMPhotonEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", false, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + } eventcuts; + + V0PhotonCut fV0PhotonCut; + struct : ConfigurableGroup { + std::string prefix = "pcmcut_group"; + + Configurable cfg_min_pt_v0{"cfg_min_pt_v0", 0.1, "min pT for v0 photons at PV"}; + Configurable cfg_max_pt_v0{"cfg_max_pt_v0", 1e+10, "max pT for v0 photons at PV"}; + Configurable cfg_min_eta_v0{"cfg_min_eta_v0", -0.9, "min eta for v0 photons at PV"}; + Configurable cfg_max_eta_v0{"cfg_max_eta_v0", +0.9, "max eta for v0 photons at PV"}; + Configurable cfg_min_v0radius{"cfg_min_v0radius", 4.0, "min v0 radius"}; + Configurable cfg_max_v0radius{"cfg_max_v0radius", 90.0, "max v0 radius"}; + Configurable cfg_max_alpha_ap{"cfg_max_alpha_ap", 0.95, "max alpha for AP cut"}; + Configurable cfg_max_qt_ap{"cfg_max_qt_ap", 0.01, "max qT for AP cut"}; + Configurable cfg_min_cospa{"cfg_min_cospa", 0.99, "min V0 CosPA"}; + Configurable cfg_max_pca{"cfg_max_pca", 1.5, "max distance btween 2 legs"}; + Configurable cfg_max_chi2kf{"cfg_max_chi2kf", 1e+10, "max chi2/ndf with KF"}; + Configurable cfg_require_v0_with_correct_xz{"cfg_require_v0_with_correct_xz", false, "flag to select V0s with correct xz"}; + Configurable cfg_reject_v0_on_itsib{"cfg_reject_v0_on_itsib", true, "flag to reject V0s on ITSib"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 40, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -3.0, "min. TPC n sigma for electron"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; + Configurable cfg_disable_itsonly_track{"cfg_disable_itsonly_track", false, "flag to disable ITSonly tracks"}; + Configurable cfg_disable_tpconly_track{"cfg_disable_tpconly_track", false, "flag to disable TPConly tracks"}; + } pcmcuts; + + DalitzEECut fDileptonCut; + struct : ConfigurableGroup { + std::string prefix = "dileptoncut_group"; + + Configurable cfg_min_mee{"cfg_min_mee", 0.0, "min mass"}; + Configurable cfg_max_mee{"cfg_max_mee", 0.02, "max mass"}; + // Configurable cfg_apply_phiv{"cfg_apply_phiv", false, "flag to apply phiv cut"}; + Configurable cfg_apply_pf{"cfg_apply_pf", false, "flag to apply phiv prefilter"}; + Configurable cfg_require_itsib_any{"cfg_require_itsib_any", false, "flag to require ITS ib any hits"}; + Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; + Configurable cfg_phiv_slope{"cfg_phiv_slope", 0.0185, "slope for m vs. phiv"}; + Configurable cfg_phiv_intercept{"cfg_phiv_intercept", -0.0280, "intercept for m vs. phiv"}; + + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.05, "min pT for single track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 1e+10, "max pT for single track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -2.0, "min eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", 2.0, "max eta for single track"}; + Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 40, "min ncluster tpc"}; + Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 0, "min ncrossed rows"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 1.f, "max dca XY for single track in cm"}; + Configurable cfg_max_dcaz{"cfg_max_dcaz", 1.f, "max dca Z for single track in cm"}; + Configurable cfg_max_dca3dsigma_track{"cfg_max_dca3dsigma_track", 1.5, "max DCA 3D in sigma"}; + + Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DalitzEECut::PIDSchemes::kTOFif), "pid scheme [kTOFif : 0, kTPConly : 1]"}; + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", 0.0, "min. TPC n sigma for pion exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", 0.0, "max. TPC n sigma for pion exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; + } dileptoncuts; + + struct : ConfigurableGroup { + std::string prefix = "ggcut_group"; + Configurable cfg_min_mass{"cfg_min_mass", 0.10, "min mass for prefilter"}; // region to be rejected + Configurable cfg_max_mass{"cfg_max_mass", 0.15, "max mass for prefilter"}; // region to be rejected + } ggcuts; + + struct : ConfigurableGroup { + std::string prefix = "eegcut_group"; + Configurable cfg_min_mass{"cfg_min_mass", 0.10, "min mass for prefilter"}; // region to be rejected + Configurable cfg_max_mass{"cfg_max_mass", 0.15, "max mass for prefilter"}; // region to be rejected + } eegcuts; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + int mRunNumber; + float d_bz; + + void init(InitContext& /*context*/) + { + DefineEMEventCut(); + DefinePCMCut(); + addhistograms(); + + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + } + + ~prefilterPhoton() {} + + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (fabs(d_bz) > 1e-5) { + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + } + mRunNumber = collision.runNumber(); + return; + } + + auto run3grp_timestamp = collision.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (!skipGRPOquery) + grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + if (grpo) { + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = collision.runNumber(); + } + + void addhistograms() + { + const AxisSpec axis_mass{200, 0, 0.8, "m_{#gamma#gamma} (GeV/c^{2})"}; + const AxisSpec axis_pair_pt{100, 0, 10, "p_{T,#gamma#gamma} (GeV/c)"}; + const AxisSpec axis_phiv{180, 0, M_PI, "#varphi_{V} (rad.)"}; + + // for pair + fRegistry.add("Pair/PCMPCM/before/hMvsPt", "m_{#gamma#gamma} vs. p_{T,#gamma#gamma}", kTH2D, {axis_mass, axis_pair_pt}, true); + fRegistry.add("Pair/PCMDalitzEE/before/hMvsPt", "m_{ee#gamma} vs. p_{T,ee#gamma}", kTH2D, {axis_mass, axis_pair_pt}, true); + fRegistry.add("Pair/PCMDalitzEE/before/hMvsPhiV", "m_{ee} vs. #varphi_{V}", kTH2D, {{180, 0, M_PI}, {100, 0, 0.1}}, true); + fRegistry.addClone("Pair/PCMPCM/before/", "Pair/PCMPCM/after/"); + fRegistry.addClone("Pair/PCMDalitzEE/before/", "Pair/PCMDalitzEE/after/"); + } + + void DefineEMEventCut() + { + fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + } + + void DefinePCMCut() + { + fV0PhotonCut = V0PhotonCut("fV0PhotonCut", "fV0PhotonCut"); + + // for v0 + fV0PhotonCut.SetV0PtRange(pcmcuts.cfg_min_pt_v0, pcmcuts.cfg_max_pt_v0); + fV0PhotonCut.SetV0EtaRange(pcmcuts.cfg_min_eta_v0, pcmcuts.cfg_max_eta_v0); + fV0PhotonCut.SetMinCosPA(pcmcuts.cfg_min_cospa); + fV0PhotonCut.SetMaxPCA(pcmcuts.cfg_max_pca); + fV0PhotonCut.SetMaxChi2KF(pcmcuts.cfg_max_chi2kf); + fV0PhotonCut.SetRxyRange(pcmcuts.cfg_min_v0radius, pcmcuts.cfg_max_v0radius); + fV0PhotonCut.SetAPRange(pcmcuts.cfg_max_alpha_ap, pcmcuts.cfg_max_qt_ap); + fV0PhotonCut.RejectITSib(pcmcuts.cfg_reject_v0_on_itsib); + + // for track + fV0PhotonCut.SetMinNClustersTPC(pcmcuts.cfg_min_ncluster_tpc); + fV0PhotonCut.SetMinNCrossedRowsTPC(pcmcuts.cfg_min_ncrossedrows); + fV0PhotonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fV0PhotonCut.SetMaxFracSharedClustersTPC(pcmcuts.cfg_max_frac_shared_clusters_tpc); + fV0PhotonCut.SetChi2PerClusterTPC(0.0, pcmcuts.cfg_max_chi2tpc); + fV0PhotonCut.SetTPCNsigmaElRange(pcmcuts.cfg_min_TPCNsigmaEl, pcmcuts.cfg_max_TPCNsigmaEl); + fV0PhotonCut.SetChi2PerClusterITS(-1e+10, pcmcuts.cfg_max_chi2its); + fV0PhotonCut.SetDisableITSonly(pcmcuts.cfg_disable_itsonly_track); + fV0PhotonCut.SetDisableTPConly(pcmcuts.cfg_disable_tpconly_track); + + fV0PhotonCut.SetNClustersITS(0, 7); + fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); + fV0PhotonCut.SetIsWithinBeamPipe(pcmcuts.cfg_require_v0_with_correct_xz); + } + + void DefineDileptonCut() + { + fDileptonCut = DalitzEECut("fDileptonCut", "fDileptonCut"); + + // for pair + fDileptonCut.SetMeeRange(dileptoncuts.cfg_min_mee, dileptoncuts.cfg_max_mee); + fDileptonCut.SetMaxPhivPairMeeDep([&](float mll) { return (mll - dileptoncuts.cfg_phiv_intercept) / dileptoncuts.cfg_phiv_slope; }); + fDileptonCut.ApplyPhiV(false); + fDileptonCut.RequireITSibAny(dileptoncuts.cfg_require_itsib_any); + fDileptonCut.RequireITSib1st(dileptoncuts.cfg_require_itsib_1st); + + // for track + fDileptonCut.SetTrackPtRange(dileptoncuts.cfg_min_pt_track, dileptoncuts.cfg_max_pt_track); + fDileptonCut.SetTrackEtaRange(-dileptoncuts.cfg_min_eta_track, +dileptoncuts.cfg_max_eta_track); + fDileptonCut.SetMinNClustersTPC(dileptoncuts.cfg_min_ncluster_tpc); + fDileptonCut.SetMinNCrossedRowsTPC(dileptoncuts.cfg_min_ncrossedrows); + fDileptonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fDileptonCut.SetMaxFracSharedClustersTPC(dileptoncuts.cfg_max_frac_shared_clusters_tpc); + fDileptonCut.SetChi2PerClusterTPC(0.0, dileptoncuts.cfg_max_chi2tpc); + fDileptonCut.SetChi2PerClusterITS(0.0, dileptoncuts.cfg_max_chi2its); + fDileptonCut.SetNClustersITS(dileptoncuts.cfg_min_ncluster_its, 7); + fDileptonCut.SetMaxDcaXY(dileptoncuts.cfg_max_dcaxy); + fDileptonCut.SetMaxDcaZ(dileptoncuts.cfg_max_dcaz); + fDileptonCut.SetTrackDca3DRange(0.f, dileptoncuts.cfg_max_dca3dsigma_track); // in sigma + + // for eID + fDileptonCut.SetPIDScheme(dileptoncuts.cfg_pid_scheme); + fDileptonCut.SetTPCNsigmaElRange(dileptoncuts.cfg_min_TPCNsigmaEl, dileptoncuts.cfg_max_TPCNsigmaEl); + fDileptonCut.SetTPCNsigmaPiRange(dileptoncuts.cfg_min_TPCNsigmaPi, dileptoncuts.cfg_max_TPCNsigmaPi); + fDileptonCut.SetTOFNsigmaElRange(dileptoncuts.cfg_min_TOFNsigmaEl, dileptoncuts.cfg_max_TOFNsigmaEl); + } + + template + void runPairing(TCollisions const& collisions, + TPhotons1 const& photons1, TPhotons2 const& photons2, + TSubInfos1 const&, TSubInfos2 const&, + TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, + TCut1 const& cut1, TCut2 const& cut2) + { + if constexpr (pairtype == PairType::kPCMPCM) { + for (const auto& photon1 : photons1) { + map_pfb_v0[photon1.globalIndex()] = 0; + } // end of v0 loop + } else if constexpr (pairtype == PairType::kPCMDalitzEE) { + for (const auto& photon1 : photons1) { + map_pfb_v0[photon1.globalIndex()] = 0; + } // end of v0 loop + for (const auto& photon2 : photons2) { + map_pfb_ele[photon2.globalIndex()] = 0; + } // end of electron loop + } + + if constexpr (pairtype == PairType::kPCMPCM) { + for (const auto& collision : collisions) { + initCCDB(collision); + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + bool is_cent_ok = true; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + is_cent_ok = false; + } + + auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); + auto photons2_per_collision = photons2.sliceBy(perCollision2, collision.globalIndex()); + + if (!fEMEventCut.IsSelected(collision) || !is_cent_ok) { + for (const auto& photon1 : photons1_per_collision) { + map_pfb_v0[photon1.globalIndex()] = 0; + } + continue; + } + for (const auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photons1_per_collision, photons2_per_collision))) { + if (!cut1.template IsSelected(g1) || !cut2.template IsSelected(g2)) { + continue; + } + // don't apply pair cut when you produce prefilter bit. + + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.f); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.f); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + fRegistry.fill(HIST("Pair/PCMPCM/before/hMvsPt"), v12.M(), v12.Pt()); + + if (ggcuts.cfg_min_mass < v12.M() && v12.M() < ggcuts.cfg_max_mass) { + map_pfb_v0[g1.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::photonmeson::utils::pairutil::PhotonPrefilterBitDerived::kPhotonFromPi0gg); + map_pfb_v0[g2.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::photonmeson::utils::pairutil::PhotonPrefilterBitDerived::kPhotonFromPi0gg); + } + } // end of 2photon pairing loop + } // end of collision loop + } else if constexpr (pairtype == PairType::kPCMDalitzEE) { + for (const auto& collision : collisions) { + initCCDB(collision); + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + bool is_cent_ok = true; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + is_cent_ok = false; + } + + auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); + auto positrons_per_collision = posTracks->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + auto electrons_per_collision = negTracks->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + + if (!fEMEventCut.IsSelected(collision) || !is_cent_ok) { + for (const auto& photon1 : photons1_per_collision) { + map_pfb_v0[photon1.globalIndex()] = 0; + } + for (const auto& pos : positrons_per_collision) { + map_pfb_ele[pos.globalIndex()] = 0; + } + for (const auto& ele : electrons_per_collision) { + map_pfb_ele[ele.globalIndex()] = 0; + } + continue; + } + + for (const auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photons1_per_collision, photons1_per_collision))) { // PCM-PCM // cut, and subinfo is different from kPCMPCM + if (!cut1.template IsSelected(g1) || !cut1.template IsSelected(g2)) { + continue; + } + // don't apply pair cut when you produce prefilter bit. + + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.f); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.f); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + fRegistry.fill(HIST("Pair/PCMPCM/before/hMvsPt"), v12.M(), v12.Pt()); + + if (ggcuts.cfg_min_mass < v12.M() && v12.M() < ggcuts.cfg_max_mass) { + map_pfb_v0[g1.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::photonmeson::utils::pairutil::PhotonPrefilterBitDerived::kPhotonFromPi0gg); + map_pfb_v0[g2.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::photonmeson::utils::pairutil::PhotonPrefilterBitDerived::kPhotonFromPi0gg); + } + } // end of 2photon pairing loop + + for (const auto& g1 : photons1_per_collision) { // PCM-DalitzEE + if (!cut1.template IsSelected(g1)) { + continue; + } + auto pos1 = g1.template posTrack_as(); + auto ele1 = g1.template negTrack_as(); + ROOT::Math::PtEtaPhiMVector v_gamma(g1.pt(), g1.eta(), g1.phi(), 0.); + + for (const auto& [pos2, ele2] : combinations(CombinationsFullIndexPolicy(positrons_per_collision, electrons_per_collision))) { + if (pos2.trackId() == ele2.trackId()) { // this is protection against pairing identical 2 tracks. + continue; + } + if (pos1.trackId() == pos2.trackId() || ele1.trackId() == ele2.trackId()) { + continue; + } + + if (!cut2.template IsSelectedTrack(pos2, collision) || !cut2.template IsSelectedTrack(ele2, collision)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v_pos(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v_ele(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v_ee = v_pos + v_ele; + if (!(dileptoncuts.cfg_min_mee < v_ee.M() && v_ee.M() < dileptoncuts.cfg_max_mee)) { + continue; + } + ROOT::Math::PtEtaPhiMVector veeg = v_gamma + v_pos + v_ele; + fRegistry.fill(HIST("Pair/PCMDalitzEE/before/hMvsPt"), veeg.M(), veeg.Pt()); + + if (eegcuts.cfg_min_mass < veeg.M() && veeg.M() < eegcuts.cfg_max_mass) { + map_pfb_v0[g1.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::photonmeson::utils::pairutil::PhotonPrefilterBitDerived::kPhotonFromPi0eeg); + map_pfb_ele[pos2.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::photonmeson::utils::pairutil::ElectronPrefilterBitDerived::kElectronFromPi0eeg); + map_pfb_ele[ele2.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::photonmeson::utils::pairutil::ElectronPrefilterBitDerived::kElectronFromPi0eeg); + } + } // end of dielectron loop + } // end of g1 loop + + for (const auto& [pos2, ele2] : combinations(CombinationsFullIndexPolicy(positrons_per_collision, electrons_per_collision))) { + if (pos2.trackId() == ele2.trackId()) { // this is protection against pairing identical 2 tracks. + continue; + } + + if (!cut2.template IsSelectedTrack(pos2, collision) || !cut2.template IsSelectedTrack(ele2, collision)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v_pos(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v_ele(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v_ee = v_pos + v_ele; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pos2.px(), pos2.py(), pos2.pz(), ele2.px(), ele2.py(), ele2.pz(), pos2.sign(), ele2.sign(), d_bz); + fRegistry.fill(HIST("Pair/PCMDalitzEE/before/hMvsPhiV"), phiv, v_ee.M()); + + if (v_ee.M() < phiv * dileptoncuts.cfg_phiv_slope + dileptoncuts.cfg_phiv_intercept) { + map_pfb_ele[pos2.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::photonmeson::utils::pairutil::ElectronPrefilterBitDerived::kElectronFromFakePC); + map_pfb_ele[ele2.globalIndex()] |= 1 << static_cast(o2::aod::pwgem::photonmeson::utils::pairutil::ElectronPrefilterBitDerived::kElectronFromFakePC); + } + } // end of dielectron loop to reject photon conversion + } // end of collision loop + } + + if constexpr (pairtype == PairType::kPCMPCM) { + for (const auto& photon1 : photons1) { + pfb_v0_derived(map_pfb_v0[photon1.globalIndex()]); + } // end of v0 loop + } else if constexpr (pairtype == PairType::kPCMDalitzEE) { + for (const auto& photon1 : photons1) { + pfb_v0_derived(map_pfb_v0[photon1.globalIndex()]); + } // end of v0 loop + for (const auto& photon2 : photons2) { + pfb_ele_derived(map_pfb_ele[photon2.globalIndex()]); + } // end of electron loop + } + + // check pfb. + if constexpr (pairtype == PairType::kPCMPCM) { + for (auto& collision : collisions) { + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + + auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); + auto photons2_per_collision = photons2.sliceBy(perCollision2, collision.globalIndex()); + + for (const auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photons1_per_collision, photons2_per_collision))) { + if (!cut1.template IsSelected(g1) || !cut2.template IsSelected(g2)) { + continue; + } + if (map_pfb_v0[g1.globalIndex()] != 0 || map_pfb_v0[g2.globalIndex()] != 0) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.f); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.f); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + fRegistry.fill(HIST("Pair/PCMPCM/after/hMvsPt"), v12.M(), v12.Pt()); + } + } // end of collision loop + } else if constexpr (pairtype == PairType::kPCMDalitzEE) { + for (auto& collision : collisions) { + initCCDB(collision); + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + + auto photons1_per_collision = photons1.sliceBy(perCollision1, collision.globalIndex()); + auto positrons_per_collision = posTracks->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + auto electrons_per_collision = negTracks->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + + for (const auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photons1_per_collision, photons1_per_collision))) { + if (!cut1.template IsSelected(g1) || !cut1.template IsSelected(g2)) { + continue; + } + if (map_pfb_v0[g1.globalIndex()] != 0 || map_pfb_v0[g2.globalIndex()] != 0) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.f); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.f); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + fRegistry.fill(HIST("Pair/PCMPCM/after/hMvsPt"), v12.M(), v12.Pt()); + } + + for (const auto& g1 : photons1_per_collision) { + if (!cut1.template IsSelected(g1)) { + continue; + } + auto pos1 = g1.template posTrack_as(); + auto ele1 = g1.template negTrack_as(); + ROOT::Math::PtEtaPhiMVector v_gamma(g1.pt(), g1.eta(), g1.phi(), 0.); + + for (const auto& [pos2, ele2] : combinations(CombinationsFullIndexPolicy(positrons_per_collision, electrons_per_collision))) { + if (pos2.trackId() == ele2.trackId()) { // this is protection against pairing identical 2 tracks. + continue; + } + if (pos1.trackId() == pos2.trackId() || ele1.trackId() == ele2.trackId()) { + continue; + } + + if (!cut2.template IsSelectedTrack(pos2, collision) || !cut2.template IsSelectedTrack(ele2, collision)) { + continue; + } + if (map_pfb_v0[g1.globalIndex()] != 0 || map_pfb_ele[pos2.globalIndex()] != 0 || map_pfb_ele[ele2.globalIndex()] != 0) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v_pos(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v_ele(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v_ee = v_pos + v_ele; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pos2.px(), pos2.py(), pos2.pz(), ele2.px(), ele2.py(), ele2.pz(), pos2.sign(), ele2.sign(), d_bz); + if (!(dileptoncuts.cfg_min_mee < v_ee.M() && v_ee.M() < dileptoncuts.cfg_max_mee)) { + continue; + } + ROOT::Math::PtEtaPhiMVector veeg = v_gamma + v_pos + v_ele; + fRegistry.fill(HIST("Pair/PCMDalitzEE/after/hMvsPt"), veeg.M(), veeg.Pt()); + fRegistry.fill(HIST("Pair/PCMDalitzEE/after/hMvsPhiV"), phiv, v_ee.M()); + } // end of dielectron loop + } // end of g1 loop + } // end of collision loop + } + + map_pfb_v0.clear(); + map_pfb_ele.clear(); + } + + std::unordered_map map_pfb_v0; // map v0.globalIndex -> prefilter bit + std::unordered_map map_pfb_ele; // map ele.globalIndex -> prefilter bit + + SliceCache cache; + Preslice perCollision_v0 = aod::v0photonkf::emeventId; + Preslice perCollision_electron = aod::emprimaryelectron::emeventId; + + Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); + Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + using FilteredMyCollisions = soa::Filtered; + + Partition posTracks = o2::aod::emprimaryelectron::sign > int8_t(0); + Partition negTracks = o2::aod::emprimaryelectron::sign < int8_t(0); + + void processPCMPCM(FilteredMyCollisions const& collisions, MyV0Photons const& v0s, aod::V0Legs const& v0legs) + { + runPairing(collisions, v0s, v0s, v0legs, v0legs, perCollision_v0, perCollision_v0, fV0PhotonCut, fV0PhotonCut); // produces filter bit for both photons + } + PROCESS_SWITCH(prefilterPhoton, processPCMPCM, "produce prefilter bit for PCM-PCM", false); + + void processPCMDalitzEE(FilteredMyCollisions const& collisions, MyV0Photons const& v0s, aod::V0Legs const& v0legs, MyPrimaryElectrons const& primaryelectrons) + { + runPairing(collisions, v0s, primaryelectrons, v0legs, primaryelectrons, perCollision_v0, perCollision_electron, fV0PhotonCut, fDileptonCut); // produces filter bit for both photons and electrons + } + PROCESS_SWITCH(prefilterPhoton, processPCMDalitzEE, "produce prefilter bit for PCM-DalitzEE", false); + + void processDummyV0(MyV0Photons const& v0s) + { + for (int i = 0; i < v0s.size(); i++) { + pfb_v0_derived(0); + } + } + PROCESS_SWITCH(prefilterPhoton, processDummyV0, "dummy for v0s", true); + + void processDummyElectron(MyPrimaryElectrons const& primaryelectrons) + { + for (int i = 0; i < primaryelectrons.size(); i++) { + pfb_ele_derived(0); + } + } + PROCESS_SWITCH(prefilterPhoton, processDummyElectron, "dummy for electrons", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"prefilter-photon"})}; +} diff --git a/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx new file mode 100644 index 00000000000..2e64bd6ebe2 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx @@ -0,0 +1,1436 @@ +// 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 taskPi0FlowEMC.cxx +/// \brief Analysis task for neutral pion flow with EMCal +/// +/// \author M. Hemmer, marvin.hemmer@cern.ch + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Math/Vector4D.h" +#include "Math/Vector3D.h" +#include "Math/LorentzRotation.h" +#include "Math/Rotation3D.h" +#include "Math/AxisAngle.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/EventPlaneHelper.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Qvectors.h" +#include "CommonConstants/MathConstants.h" + +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsEMCAL/Constants.h" +#include "EMCALBase/Geometry.h" +#include "EMCALCalib/BadChannelMap.h" + +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/emcalHistoDefinitions.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" +#include "PWGEM/PhotonMeson/Utils/NMHistograms.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::photonmeson::photonpair; +using namespace o2::aod::pwgem::photon; +using namespace o2::aod::pwgem::dilepton::utils; + +enum QvecEstimator { FT0M = 0, + FT0A = 1, + FT0C, + TPCPos, + TPCNeg, + TPCTot }; + +enum CentralityEstimator { None = 0, + CFT0A = 1, + CFT0C, + CFT0M, + NCentralityEstimators +}; + +struct TaskPi0FlowEMC { + // configurable for flow + Configurable harmonic{"harmonic", 2, "harmonic number"}; + Configurable qvecDetector{"qvecDetector", 0, "Detector for Q vector estimation (FT0M: 0, FT0A: 1, FT0C: 2, TPC Pos: 3, TPC Neg: 4, TPC Tot: 5)"}; + Configurable qvecSubADetector{"qvecSubADetector", 3, "Sub A Detector for Q vector estimation for resolution (FT0M: 0, FT0A: 1, FT0C: 2, TPC Pos: 3, TPC Neg: 4, TPC Tot: 5)"}; + Configurable qvecSubBDetector{"qvecSubBDetector", 4, "Sub B Detector for Q vector estimation for resolution (FT0M: 0, FT0A: 1, FT0C: 2, TPC Pos: 3, TPC Neg: 4, TPC Tot: 5)"}; + Configurable centEstimator{"centEstimator", 2, "Centrality estimation (FT0A: 1, FT0C: 2, FT0M: 3)"}; + Configurable saveEpResoHisto{"saveEpResoHisto", false, "Flag to save event plane resolution histogram"}; + Configurable saveSPResoHist{"saveSPResoHist", false, "Flag to save scalar product resolution histogram"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable cfgDoRotation{"cfgDoRotation", true, "Flag to enable rotation background method"}; + Configurable cfgDownsampling{"cfgDownsampling", 1, "Calculate rotation background only for every collision"}; + Configurable cfgEMCalMapLevelBackground{"cfgEMCalMapLevelBackground", 2, "Different levels of correction for the background, the smaller number includes the level of the higher number (4: none, 3: only inside EMCal, 2: exclude bad channels, 1: remove edges)"}; + Configurable cfgEMCalMapLevelSameEvent{"cfgEMCalMapLevelSameEvent", 1, "Different levels of correction for the same event, the smaller number includes the level of the higher number (4: none, 3: only inside EMCal, 2: exclude bad channels, 1: remove edges)"}; + Configurable cfgRotAngle{"cfgRotAngle", std::move(const_cast(o2::constants::math::PIHalf)), "Angle used for the rotation method"}; + Configurable cfgDistanceToEdge{"cfgDistanceToEdge", 1, "Distance to edge in cells required for rotated cluster to be accepted"}; + Configurable cfgDoM02{"cfgDoM02", false, "Flag to enable flow vs M02 for single photons"}; + Configurable cfgDoReverseScaling{"cfgDoReverseScaling", false, "Flag to reverse the scaling that is possibly applied during NonLin"}; + Configurable cfgDoPlaneQA{"cfgDoPlaneQA", false, "Flag to enable QA plots comparing in and out of plane"}; + + // configurable axis + ConfigurableAxis thnConfigAxisInvMass{"thnConfigAxisInvMass", {400, 0.0, 0.8}, ""}; + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {100, 0., 20.}, ""}; + ConfigurableAxis thnConfigAxisCent{"thnConfigAxisCent", {20, 0., 100.}, ""}; + ConfigurableAxis thnConfigAxisCosNPhi{"thnConfigAxisCosNPhi", {100, -1., 1.}, ""}; + ConfigurableAxis thnConfigAxisCosDeltaPhi{"thnConfigAxisCosDeltaPhi", {8, -1., 1.}, ""}; + ConfigurableAxis thnConfigAxisScalarProd{"thnConfigAxisScalarProd", {100, -5., 5.}, ""}; + ConfigurableAxis thnConfigAxisM02{"thnConfigAxisM02", {200, 0., 5.}, ""}; + + EMPhotonEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcuts"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgRequireEMCReadoutInMB{"cfgRequireEMCReadoutInMB", true, "require the EMC to be read out in an MB collision (kTVXinEMC)"}; + Configurable cfgRequireEMCHardwareTriggered{"cfgRequireEMCHardwareTriggered", false, "require the EMC to be hardware triggered (kEMC7 or kDMC7)"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -1, "min. track occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. track occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -1, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable cfgMinCent{"cfgMinCent", 0, "min. centrality (%)"}; + Configurable cfgMaxCent{"cfgMaxCent", 90, "max. centrality (%)"}; + Configurable onlyKeepWeightedEvents{"onlyKeepWeightedEvents", false, "flag to keep only weighted events (for JJ MCs) and remove all MB events (with weight = 1)"}; + Configurable cfgEnableQA{"cfgEnableQA", false, "flag to turn QA plots on/off"}; + } eventcuts; + + EMCPhotonCut fEMCCut; + struct : ConfigurableGroup { + std::string prefix = "emccuts"; + Configurable clusterDefinition{"clusterDefinition", "kV3Default", "Clusterizer to be selected, e.g. V3Default"}; + Configurable cfgEMCminTime{"cfgEMCminTime", -25., "Minimum cluster time for EMCal time cut"}; + Configurable cfgEMCmaxTime{"cfgEMCmaxTime", +30., "Maximum cluster time for EMCal time cut"}; + Configurable cfgEMCminM02{"cfgEMCminM02", 0.1, "Minimum M02 for EMCal M02 cut"}; + Configurable cfgEMCmaxM02{"cfgEMCmaxM02", 0.7, "Maximum M02 for EMCal M02 cut"}; + Configurable cfgEMCminE{"cfgEMCminE", 0.7, "Minimum cluster energy for EMCal energy cut"}; + Configurable cfgEMCminNCell{"cfgEMCminNCell", 1, "Minimum number of cells per cluster for EMCal NCell cut"}; + Configurable> cfgEMCTMEta{"cfgEMCTMEta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable> cfgEMCTMPhi{"cfgEMCTMPhi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable cfgEMCEoverp{"cfgEMCEoverp", 1.75, "Minimum cluster energy over track momentum for EMCal track matching"}; + Configurable cfgEMCUseExoticCut{"cfgEMCUseExoticCut", true, "FLag to use the EMCal exotic cluster cut"}; + Configurable cfgEMCUseTM{"cfgEMCUseTM", false, "flag to use EMCal track matching cut or not"}; + Configurable cfgEnableQA{"cfgEnableQA", false, "flag to turn QA plots on/off"}; + } emccuts; + + struct : ConfigurableGroup { + std::string prefix = "mesonConfig"; + Configurable minOpenAngle{"minOpenAngle", 0.0202, "apply min opening angle. Default value one EMCal cell"}; + Configurable enableTanThetadPhi{"enableTanThetadPhi", false, "flag to turn cut opening angle in delta theta delta phi on/off"}; + Configurable minTanThetadPhi{"minTanThetadPhi", 4., "apply min opening angle in delta theta delta phi to cut on late conversion"}; + Configurable maxEnergyAsymmetry{"maxEnergyAsymmetry", 1., "apply max energy asymmetry for meson candidate"}; + Configurable cfgEnableQA{"cfgEnableQA", false, "flag to turn QA plots on/off"}; + ConfigurableAxis thConfigAxisTanThetaPhi{"thConfigAxisTanThetaPhi", {180, -90.f, 90.f}, ""}; + } mesonConfig; + + struct : ConfigurableGroup { + std::string prefix = "mixingConfig"; + ConfigurableAxis cfgVtxBins{"cfgVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis cfgCentBins{"cfgCentBins", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.f}, "Mixing bins - centrality"}; + ConfigurableAxis cfgEPBins{"cfgEPBins", {8, o2::constants::math::PIHalf, o2::constants::math::PIHalf}, "Mixing bins - event plane angle"}; + ConfigurableAxis cfgOccupancyBins{"cfgOccupancyBins", {VARIABLE_WIDTH, 0, 100, 500, 1000, 2000}, "Mixing bins - occupancy"}; + Configurable cfgMixingDepth{"cfgMixingDepth", 2, "Mixing depth"}; + } mixingConfig; + + struct : ConfigurableGroup { + std::string prefix = "correctionConfig"; + Configurable cfgSpresoPath{"cfgSpresoPath", "Users/m/mhemmer/EM/Flow/Resolution", "Path to SP resolution file"}; + Configurable cfgApplySPresolution{"cfgApplySPresolution", 0, "Apply resolution correction"}; + Configurable doEMCalCalib{"doEMCalCalib", 0, "Produce output for EMCal calibration"}; + } correctionConfig; + + SliceCache cache; + EventPlaneHelper epHelper; + o2::framework::Service ccdb; + int runNow = 0; + int runBefore = -1; + + Filter clusterFilter = aod::skimmedcluster::time >= emccuts.cfgEMCminTime && aod::skimmedcluster::time <= emccuts.cfgEMCmaxTime && aod::skimmedcluster::m02 >= emccuts.cfgEMCminM02 && aod::skimmedcluster::m02 <= emccuts.cfgEMCmaxM02 && skimmedcluster::e >= emccuts.cfgEMCminE; + Filter collisionFilter = (nabs(aod::collision::posZ) <= eventcuts.cfgZvtxMax) && (aod::evsel::ft0cOccupancyInTimeRange <= eventcuts.cfgFT0COccupancyMax) && (aod::evsel::ft0cOccupancyInTimeRange >= eventcuts.cfgFT0COccupancyMin); + using FilteredEMCalPhotons = soa::Filtered>; + using EMCalPhotons = soa::Join; + using FilteredCollsWithQvecs = soa::Filtered>; + using CollsWithQvecs = soa::Join; + + Preslice perCollisionEMC = aod::emccluster::emeventId; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + o2::emcal::Geometry* emcalGeom; + o2::emcal::BadChannelMap* mBadChannels; + TH1D* h1SPResolution = nullptr; + // Constants for eta and phi ranges + double etaMin = -0.75, etaMax = 0.75; + int nBinsEta = 150; // 150 bins for eta + + double phiMin = 1.35, phiMax = 5.75; + int nBinsPhi = 440; // (440 bins = 0.01 step size covering most regions) + + std::vector lookupTable1D; + float epsilon = 1.e-8; + + // To access the 1D array + inline int getIndex(int iEta, int iPhi) + { + return iEta * nBinsPhi + iPhi; + } + + // Function to access the lookup table + inline int8_t checkEtaPhi1D(double eta, double phi) + { + if (eta < etaMin || eta > etaMax || phi < phiMin || phi > phiMax) { + return 3; // Out of bounds + } + + // Compute indices directly + int iEta = static_cast((eta - etaMin) / ((etaMax - etaMin) / nBinsEta)); + int iPhi = static_cast((phi - phiMin) / ((phiMax - phiMin) / nBinsPhi)); + + return lookupTable1D[getIndex(iEta, iPhi)]; + } + + void defineEMEventCut() + { + fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireEMCReadoutInMB(eventcuts.cfgRequireEMCReadoutInMB); + fEMEventCut.SetRequireEMCHardwareTriggered(eventcuts.cfgRequireEMCHardwareTriggered); + } + + void defineEMCCut() + { + fEMCCut = EMCPhotonCut("fEMCCut", "fEMCCut"); + const float a = emccuts.cfgEMCTMEta->at(0); + const float b = emccuts.cfgEMCTMEta->at(1); + const float c = emccuts.cfgEMCTMEta->at(2); + + const float d = emccuts.cfgEMCTMPhi->at(0); + const float e = emccuts.cfgEMCTMPhi->at(1); + const float f = emccuts.cfgEMCTMPhi->at(2); + LOGF(info, "EMCal track matching parameters : a = %f, b = %f, c = %f, d = %f, e = %f, f = %f", a, b, c, d, e, f); + fEMCCut.SetTrackMatchingEta([a, b, c](float pT) { return a + std::pow(pT + b, c); }); + fEMCCut.SetTrackMatchingPhi([d, e, f](float pT) { return d + std::pow(pT + e, f); }); + fEMCCut.SetMinEoverP(emccuts.cfgEMCEoverp); + + fEMCCut.SetMinE(emccuts.cfgEMCminE); + fEMCCut.SetMinNCell(emccuts.cfgEMCminNCell); + fEMCCut.SetM02Range(emccuts.cfgEMCminM02, emccuts.cfgEMCmaxM02); + fEMCCut.SetTimeRange(emccuts.cfgEMCminTime, emccuts.cfgEMCmaxTime); + fEMCCut.SetUseExoticCut(emccuts.cfgEMCUseExoticCut); + fEMCCut.SetClusterizer(emccuts.clusterDefinition); + } + + void init(InitContext&) + { + if (harmonic != 2 && harmonic != 3) { + LOG(info) << "Harmonic was set to " << harmonic << " but can only be 2 or 3!"; + } + + defineEMEventCut(); + defineEMCCut(); + fEMCCut.SetUseTM(emccuts.cfgEMCUseTM); // disables TM + o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(®istry); + + const AxisSpec thnAxisInvMass{thnConfigAxisInvMass, "#it{M}_{#gamma#gamma} (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisPt{thnConfigAxisPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisCent{thnConfigAxisCent, "Centrality (%)"}; + const AxisSpec thnAxisCosNPhi{thnConfigAxisCosNPhi, Form("cos(%d#varphi)", harmonic.value)}; + const AxisSpec thnAxisCosDeltaPhi{thnConfigAxisCosDeltaPhi, Form("cos(%d(#varphi - #Psi_{sub}))", harmonic.value)}; + const AxisSpec thnAxisScalarProd{thnConfigAxisScalarProd, "SP"}; + const AxisSpec thnAxisM02{thnConfigAxisM02, "M_{02}"}; + const AxisSpec thAxisTanThetaPhi{mesonConfig.thConfigAxisTanThetaPhi, "atan(#Delta#theta/#Delta#varphi)"}; + const AxisSpec thAxisClusterEnergy{thnConfigAxisPt, "#it{E} (GeV)"}; + const AxisSpec thAxisAlpha{100, -1., +1, "#alpha"}; + const AxisSpec thAxisMult{1000, 0., +1000, "#it{N}_{ch}"}; + const AxisSpec thAxisEnergy{1000, 0., 100., "#it{E}_{clus} (GeV)"}; + const AxisSpec thAxisEnergyCalib{100, 0., 20., "#it{E}_{clus} (GeV)"}; + const AxisSpec thAxisTime{1500, -600, 900, "#it{t}_{cl} (ns)"}; + const AxisSpec thAxisEta{320, -0.8, 0.8, "#eta"}; + const AxisSpec thAxisPhi{500, 0, 2 * 3.14159, "phi"}; + const AxisSpec thAxisNCell{17664, 0.5, +17664.5, "#it{N}_{cell}"}; + const AxisSpec thAxisPsi{360 / harmonic.value, -(1. / static_cast(harmonic.value)) * std::numbers::pi_v, (1. / static_cast(harmonic.value)) * std::numbers::pi_v, Form("#Psi_{%d}", harmonic.value)}; + const AxisSpec thAxisCN{8, 0.5, 8.5, "#it{c}_{n}"}; + const AxisSpec thAxisSN{8, 0.5, 8.5, "#it{s}_{n}"}; + const AxisSpec thAxisCPUTime{1000, 0, 10000, "#it{t} (#mus)"}; + + const AxisSpec thnAxisMixingVtx{mixingConfig.cfgVtxBins, "#it{z} (cm)"}; + const AxisSpec thnAxisMixingCent{mixingConfig.cfgCentBins, "Centrality (%)"}; + const AxisSpec thnAxisMixingEP{mixingConfig.cfgEPBins, Form("cos(%d#varphi)", harmonic.value)}; + + registry.add("hSparsePi0Flow", "THn for SP", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCent, thnAxisScalarProd}); + registry.add("hSparseBkgRotFlow", "THn for SP", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCent, thnAxisScalarProd}); + registry.add("hSparseBkgMixFlow", "THn for SP", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCent, thnAxisScalarProd}); + registry.add("h3DMixingCount", "THn Event Mixing QA", HistType::kTH3D, {thnAxisMixingVtx, thnAxisMixingCent, thnAxisMixingEP}); + if (cfgDoPlaneQA.value) { + registry.add("hSparsePi0FlowPlane", "THn for SP", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCent, thnAxisCosDeltaPhi}); + } + auto hClusterCuts = registry.add("hClusterCuts", "hClusterCuts;;Counts", kTH1D, {{6, 0.5, 6.5}}, false); + hClusterCuts->GetXaxis()->SetBinLabel(1, "in"); + hClusterCuts->GetXaxis()->SetBinLabel(2, "opening angle"); + hClusterCuts->GetXaxis()->SetBinLabel(3, "#it{M}_{#gamma#gamma}"); + hClusterCuts->GetXaxis()->SetBinLabel(4, "#it{p}_{T}"); + hClusterCuts->GetXaxis()->SetBinLabel(5, "conversion cut"); + hClusterCuts->GetXaxis()->SetBinLabel(6, "out"); + + auto hClusterCutsMixed = registry.add("hClusterCutsMixed", "hClusterCutsMixed;;Counts", kTH1D, {{6, 0.5, 6.5}}, false); + hClusterCutsMixed->GetXaxis()->SetBinLabel(1, "in"); + hClusterCutsMixed->GetXaxis()->SetBinLabel(2, "opening angle"); + hClusterCutsMixed->GetXaxis()->SetBinLabel(3, "#it{M}_{#gamma#gamma}"); + hClusterCutsMixed->GetXaxis()->SetBinLabel(4, "#it{p}_{T}"); + hClusterCutsMixed->GetXaxis()->SetBinLabel(5, "conversion cut"); + hClusterCutsMixed->GetXaxis()->SetBinLabel(6, "out"); + + if (saveSPResoHist) { + registry.add("spReso/hSpResoFT0cFT0a", "hSpResoFT0cFT0a; centrality; Q_{FT0c} #bullet Q_{FT0a}", HistType::kTH2D, {thnAxisCent, thnConfigAxisScalarProd}); + registry.add("spReso/hSpResoFT0cTPCpos", "hSpResoFT0cTPCpos; centrality; Q_{FT0c} #bullet Q_{TPCpos}", HistType::kTH2D, {thnAxisCent, thnConfigAxisScalarProd}); + registry.add("spReso/hSpResoFT0cTPCneg", "hSpResoFT0cTPCneg; centrality; Q_{FT0c} #bullet Q_{TPCneg}", HistType::kTH2D, {thnAxisCent, thnConfigAxisScalarProd}); + registry.add("spReso/hSpResoFT0cTPCtot", "hSpResoFT0cTPCtot; centrality; Q_{FT0c} #bullet Q_{TPCtot}", HistType::kTH2D, {thnAxisCent, thnConfigAxisScalarProd}); + registry.add("spReso/hSpResoFT0aTPCpos", "hSpResoFT0aTPCpos; centrality; Q_{FT0a} #bullet Q_{TPCpos}", HistType::kTH2D, {thnAxisCent, thnConfigAxisScalarProd}); + registry.add("spReso/hSpResoFT0aTPCneg", "hSpResoFT0aTPCneg; centrality; Q_{FT0a} #bullet Q_{TPCneg}", HistType::kTH2D, {thnAxisCent, thnConfigAxisScalarProd}); + registry.add("spReso/hSpResoFT0aTPCtot", "hSpResoFT0aTPCtot; centrality; Q_{FT0m} #bullet Q_{TPCtot}", HistType::kTH2D, {thnAxisCent, thnConfigAxisScalarProd}); + registry.add("spReso/hSpResoFT0mTPCpos", "hSpResoFT0mTPCpos; centrality; Q_{FT0m} #bullet Q_{TPCpos}", HistType::kTH2D, {thnAxisCent, thnConfigAxisScalarProd}); + registry.add("spReso/hSpResoFT0mTPCneg", "hSpResoFT0mTPCneg; centrality; Q_{FT0m} #bullet Q_{TPCneg}", HistType::kTH2D, {thnAxisCent, thnConfigAxisScalarProd}); + registry.add("spReso/hSpResoFT0mTPCtot", "hSpResoFT0mTPCtot; centrality; Q_{FT0m} #bullet Q_{TPCtot}", HistType::kTH2D, {thnAxisCent, thnConfigAxisScalarProd}); + registry.add("spReso/hSpResoTPCposTPCneg", "hSpResoTPCposTPCneg; centrality; Q_{TPCpos} #bullet Q_{TPCneg}", HistType::kTH2D, {thnAxisCent, thnConfigAxisScalarProd}); + } + + if (saveEpResoHisto) { + registry.add("hEventPlaneAngleFT0M", "hEventPlaneAngleFT0M", HistType::kTH2D, {thnAxisCent, thAxisPsi}); + registry.add("hEventPlaneAngleTPCpos", "hEventPlaneAngleTPCpos", HistType::kTH2D, {thnAxisCent, thAxisPsi}); + registry.add("hEventPlaneAngleTPCneg", "hEventPlaneAngleTPCneg", HistType::kTH2D, {thnAxisCent, thAxisPsi}); + registry.add("epReso/hEpResoFT0cFT0a", "hEpResoFT0cFT0a; centrality; #Delta#Psi_{sub}", HistType::kTH2D, {thnAxisCent, thnAxisCosNPhi}); + registry.add("epReso/hEpResoFT0cTPCpos", "hEpResoFT0cTPCpos; centrality; #Delta#Psi_{sub}", HistType::kTH2D, {thnAxisCent, thnAxisCosNPhi}); + registry.add("epReso/hEpResoFT0cTPCneg", "hEpResoFT0cTPCneg; centrality; #Delta#Psi_{sub}", HistType::kTH2D, {thnAxisCent, thnAxisCosNPhi}); + registry.add("epReso/hEpResoFT0cTPCtot", "hEpResoFT0cTPCtot; centrality; #Delta#Psi_{sub}", HistType::kTH2D, {thnAxisCent, thnAxisCosNPhi}); + registry.add("epReso/hEpResoFT0aTPCpos", "hEpResoFT0aTPCpos; centrality; #Delta#Psi_{sub}", HistType::kTH2D, {thnAxisCent, thnAxisCosNPhi}); + registry.add("epReso/hEpResoFT0aTPCneg", "hEpResoFT0aTPCneg; centrality; #Delta#Psi_{sub}", HistType::kTH2D, {thnAxisCent, thnAxisCosNPhi}); + registry.add("epReso/hEpResoFT0aTPCtot", "hEpResoFT0aTPCtot; centrality; #Delta#Psi_{sub}", HistType::kTH2D, {thnAxisCent, thnAxisCosNPhi}); + registry.add("epReso/hEpResoFT0mTPCpos", "hEpResoFT0mTPCpos; centrality; #Delta#Psi_{sub}", HistType::kTH2D, {thnAxisCent, thnAxisCosNPhi}); + registry.add("epReso/hEpResoFT0mTPCneg", "hEpResoFT0mTPCneg; centrality; #Delta#Psi_{sub}", HistType::kTH2D, {thnAxisCent, thnAxisCosNPhi}); + registry.add("epReso/hEpResoFT0mTPCtot", "hEpResoFT0mTPCtot; centrality; #Delta#Psi_{sub}", HistType::kTH2D, {thnAxisCent, thnAxisCosNPhi}); + registry.add("epReso/hEpResoTPCposTPCneg", "hEpResoTPCposTPCneg; centrality; #Delta#Psi_{sub}", HistType::kTH2D, {thnAxisCent, thnAxisCosNPhi}); + registry.add("epReso/hEpCosCoefficientsFT0c", "hEpCosCoefficientsFT0c; centrality; c_{n}", HistType::kTProfile2D, {thnAxisCent, thAxisCN}); + registry.add("epReso/hEpSinCoefficientsFT0c", "hEpSinCoefficientsFT0c; centrality; s_{n}", HistType::kTProfile2D, {thnAxisCent, thAxisSN}); + registry.add("epReso/hEpCosCoefficientsFT0a", "hEpCosCoefficientsFT0a; centrality; c_{n}", HistType::kTProfile2D, {thnAxisCent, thAxisCN}); + registry.add("epReso/hEpSinCoefficientsFT0a", "hEpSinCoefficientsFT0a; centrality; s_{n}", HistType::kTProfile2D, {thnAxisCent, thAxisSN}); + registry.add("epReso/hEpCosCoefficientsFT0m", "hEpCosCoefficientsFT0m; centrality; c_{n}", HistType::kTProfile2D, {thnAxisCent, thAxisCN}); + registry.add("epReso/hEpSinCoefficientsFT0m", "hEpSinCoefficientsFT0m; centrality; s_{n}", HistType::kTProfile2D, {thnAxisCent, thAxisSN}); + registry.add("epReso/hEpCosCoefficientsTPCpos", "hEpCosCoefficientsTPCpos; centrality; c_{n}", HistType::kTProfile2D, {thnAxisCent, thAxisCN}); + registry.add("epReso/hEpSinCoefficientsTPCpos", "hEpSinCoefficientsTPCpos; centrality; s_{n}", HistType::kTProfile2D, {thnAxisCent, thAxisSN}); + registry.add("epReso/hEpCosCoefficientsTPCneg", "hEpCosCoefficientsTPCneg; centrality; c_{n}", HistType::kTProfile2D, {thnAxisCent, thAxisCN}); + registry.add("epReso/hEpSinCoefficientsTPCneg", "hEpSinCoefficientsTPCneg; centrality; s_{n}", HistType::kTProfile2D, {thnAxisCent, thAxisSN}); + registry.add("epReso/hEpCosCoefficientsTPCTots", "hEpCosCoefficientsTPCTots; centrality; c_{n}", HistType::kTProfile2D, {thnAxisCent, thAxisCN}); + registry.add("epReso/hEpSinCoefficientsTPCTots", "hEpSinCoefficientsTPCTots; centrality; s_{n}", HistType::kTProfile2D, {thnAxisCent, thAxisSN}); + } + if (eventcuts.cfgEnableQA) { + auto hCollisionEMCCheck = registry.add("hCollisionEMCCheck", "collision counter;;Counts", kTH1D, {{7, 0.5, 7.5}}, false); + hCollisionEMCCheck->GetXaxis()->SetBinLabel(1, "all"); + hCollisionEMCCheck->GetXaxis()->SetBinLabel(2, "EMC MB Readout"); + hCollisionEMCCheck->GetXaxis()->SetBinLabel(3, "has clusters"); + hCollisionEMCCheck->GetXaxis()->SetBinLabel(4, "EMC MB Readout & has clusters"); + hCollisionEMCCheck->GetXaxis()->SetBinLabel(5, "EMC MB Readout but no clusters"); + hCollisionEMCCheck->GetXaxis()->SetBinLabel(6, "No EMC MB Readout but has clusters"); + hCollisionEMCCheck->GetXaxis()->SetBinLabel(7, "No EMC MB Readout and no clusters"); + } + + if (emccuts.cfgEnableQA) { + registry.add("hEClusterBefore", "Histo for cluster energy before cuts", HistType::kTH1D, {thAxisClusterEnergy}); + registry.add("hEClusterAfter", "Histo for cluster energy after cuts", HistType::kTH1D, {thAxisClusterEnergy}); + } + + if (mesonConfig.cfgEnableQA) { + registry.add("hInvMassPt", "Histo for inv pair mass vs pt", HistType::kTH2D, {thnAxisInvMass, thnAxisPt}); + registry.add("hTanThetaPhi", "Histo for identification of conversion cluster", HistType::kTH2D, {thnAxisInvMass, thAxisTanThetaPhi}); + registry.add("hAlphaPt", "Histo of meson asymmetry vs pT", HistType::kTH2D, {thAxisAlpha, thnAxisPt}); + registry.add("mesonQA/hClusterEtaPhiBefore", "hClusterEtaPhiBefore", HistType::kTH2D, {thAxisPhi, thAxisEta}); + registry.add("mesonQA/hClusterEtaPhiAfter", "hClusterEtaPhiAfter", HistType::kTH2D, {thAxisPhi, thAxisEta}); + registry.add("hInvMassPtMixed", "Histo for inv pair mass vs pt for mixed event", HistType::kTH2D, {thnAxisInvMass, thnAxisPt}); + registry.add("hTanThetaPhiMixed", "Histo for identification of conversion cluster for mixed event", HistType::kTH2D, {thnAxisInvMass, thAxisTanThetaPhi}); + registry.add("hAlphaPtMixed", "Histo of meson asymmetry vs pT for mixed event", HistType::kTH2D, {thAxisAlpha, thnAxisPt}); + registry.add("mesonQA/hClusterEtaPhiBeforeMixed", "hClusterEtaPhiBefore for mixed event", HistType::kTH2D, {thAxisPhi, thAxisEta}); + registry.add("mesonQA/hClusterEtaPhiAfterMixed", "hClusterEtaPhiAfter for mixed event", HistType::kTH2D, {thAxisPhi, thAxisEta}); + if (cfgDoRotation) { + registry.add("mesonQA/hClusterBackEtaPhiBefore", "hClusterBackEtaPhiBefore", HistType::kTH2D, {thAxisPhi, thAxisEta}); + registry.add("mesonQA/hClusterBackEtaPhiAfter", "hClusterBackEtaPhiAfter", HistType::kTH2D, {thAxisPhi, thAxisEta}); + } + } + + if (correctionConfig.doEMCalCalib) { + registry.add("hSparseCalibSE", "THn for Calib same event", HistType::kTHnSparseF, {thnAxisInvMass, thAxisEnergyCalib, thnAxisCent}); + registry.add("hSparseCalibBack", "THn for Calib background", HistType::kTHnSparseF, {thnAxisInvMass, thAxisEnergyCalib, thnAxisCent}); + } + + if (cfgDoM02.value) { + registry.add("hSparseFlow", "THn for SP", HistType::kTHnSparseF, {thnAxisM02, thnAxisPt, thnAxisCent, thnAxisScalarProd}); + } + + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + LOG(info) << "thnConfigAxisInvMass.value[1] = " << thnConfigAxisInvMass.value[1] << " thnConfigAxisInvMass.value.back() = " << thnConfigAxisInvMass.value.back(); + LOG(info) << "thnConfigAxisPt.value[1] = " << thnConfigAxisPt.value[1] << " thnConfigAxisPt.value.back() = " << thnConfigAxisPt.value.back(); + }; // end init + + /// Change radians to degree + /// \param angle in radians + /// \return angle in degree + float getAngleDegree(float angle) + { + return angle * 180.f * std::numbers::inv_pi_v; + } + + /// Compute the delta psi in the range [0, pi/harmonic] + /// \param psi1 is the first angle + /// \param psi2 is the second angle + float getDeltaPsiInRange(float psi1, float psi2) + { + float deltaPsi = psi1 - psi2; + return RecoDecay::constrainAngle(deltaPsi, 0.f, harmonic); + } + + /// Fill THnSparse + /// \param mass is the invariant mass of the candidate + /// \param pt is the transverse momentum of the candidate + /// \param cent is the centrality of the collision + /// \param sp is the scalar product + template + void fillThn(float& mass, + float& pt, + float& cent, + float& sp) + { + static constexpr std::string_view HistTypes[3] = {"hSparsePi0Flow", "hSparseBkgRotFlow", "hSparseBkgMixFlow"}; + registry.fill(HIST(HistTypes[histType]), mass, pt, cent, sp); + } + + /// Get the centrality + /// \param collision is the collision with the centrality information + float getCentrality(CollsWithQvecs::iterator const& collision) + { + float cent = -999.; + switch (centEstimator) { + case CentralityEstimator::CFT0M: + cent = collision.centFT0M(); + break; + case CentralityEstimator::CFT0A: + cent = collision.centFT0A(); + break; + case CentralityEstimator::CFT0C: + cent = collision.centFT0C(); + break; + default: + LOG(warning) << "Centrality estimator not valid. Possible values are T0M, T0A, T0C. Fallback to T0C"; + cent = collision.centFT0C(); + break; + } + return cent; + } + + /// Get all used Q vector + /// \param collision is the collision with the Q vector information + std::vector getAllQvec(CollsWithQvecs::iterator const& collision) + { + // Retrieve the Q vectors using the helper function for each detector + auto [xQVecMain, yQVecMain] = getQvec(collision, qvecDetector); + auto [xQVecSubA, yQVecSubA] = getQvec(collision, qvecSubADetector); + auto [xQVecSubB, yQVecSubB] = getQvec(collision, qvecSubBDetector); + + return {xQVecMain, yQVecMain, xQVecSubA, yQVecSubA, xQVecSubB, yQVecSubB}; + } + + /// Get the Q vector + /// \param collision is the collision with the Q vector information + std::pair getQvec(CollsWithQvecs::iterator const& collision, int detector) + { + float xQVec = -999.f; + float yQVec = -999.f; + + switch (detector) { + case QvecEstimator::FT0M: + if (harmonic == 2) { + xQVec = collision.q2xft0m(); + yQVec = collision.q2yft0m(); + } else if (harmonic == 3) { + xQVec = collision.q3xft0m(); + yQVec = collision.q3yft0m(); + } + break; + case QvecEstimator::FT0A: + if (harmonic == 2) { + xQVec = collision.q2xft0a(); + yQVec = collision.q2yft0a(); + } else if (harmonic == 3) { + xQVec = collision.q3xft0a(); + yQVec = collision.q3yft0a(); + } + break; + case QvecEstimator::FT0C: + if (harmonic == 2) { + xQVec = collision.q2xft0c(); + yQVec = collision.q2yft0c(); + } else if (harmonic == 3) { + xQVec = collision.q3xft0c(); + yQVec = collision.q3yft0c(); + } + break; + case QvecEstimator::TPCPos: + if (harmonic == 2) { + xQVec = collision.q2xbpos(); + yQVec = collision.q2ybpos(); + } else if (harmonic == 3) { + xQVec = collision.q3xbpos(); + yQVec = collision.q3ybpos(); + } + break; + case QvecEstimator::TPCNeg: + if (harmonic == 2) { + xQVec = collision.q2xbneg(); + yQVec = collision.q2ybneg(); + } else if (harmonic == 3) { + xQVec = collision.q3xbneg(); + yQVec = collision.q3ybneg(); + } + break; + case QvecEstimator::TPCTot: + if (harmonic == 2) { + xQVec = collision.q2xbtot(); + yQVec = collision.q2ybtot(); + } else if (harmonic == 3) { + xQVec = collision.q3xbtot(); + yQVec = collision.q3ybtot(); + } + break; + default: + LOG(warning) << "Q vector estimator not valid. Falling back to FT0M"; + if (harmonic == 2) { + xQVec = collision.q2xft0m(); + yQVec = collision.q2yft0m(); + } else if (harmonic == 3) { + xQVec = collision.q3xft0m(); + yQVec = collision.q3yft0m(); + } + break; + } + return {xQVec, yQVec}; + } + + /// Check if the QVector values are within reasonable range + /// \param collision is the collision with the Q vector information + bool isQvecGood(std::vector const& QVecs) + { + bool isgood = true; + for (const auto& QVec : QVecs) { + if (std::fabs(QVec) > 20.f) { + isgood = false; + break; + } + } + return isgood; + } + + bool isTooCloseToEdge(const int cellID, const int DistanceToBorder = 1) + { + if (DistanceToBorder <= 0) { + return false; + } + if (cellID < 0) { + return true; + } + + int iBadCell = -1; + + // check distance to border in case the cell is okay + auto [iSupMod, iMod, iPhi, iEta] = emcalGeom->GetCellIndex(cellID); + auto [irow, icol] = emcalGeom->GetCellPhiEtaIndexInSModule(iSupMod, iMod, iPhi, iEta); + + // Check rows/phi + int iRowLast = 24; + if (emcalGeom->GetSMType(iSupMod) == o2::emcal::EMCALSMType::EMCAL_HALF) { + iRowLast /= 2; // 2/3 sm case + } else if (emcalGeom->GetSMType(iSupMod) == o2::emcal::EMCALSMType::EMCAL_THIRD) { + iRowLast /= 3; // 1/3 sm case + } else if (emcalGeom->GetSMType(iSupMod) == o2::emcal::EMCALSMType::DCAL_EXT) { + iRowLast /= 3; // 1/3 sm case + } + + if (irow < DistanceToBorder || (iRowLast - irow) <= DistanceToBorder) { + iBadCell = 1; + } + + if (iBadCell > 0) { + return true; + } + return false; + } + + bool isCellMasked(int cellID) + { + bool masked = false; + if (mBadChannels) { + auto maskStatus = mBadChannels->getChannelStatus(cellID); + masked = (maskStatus != o2::emcal::BadChannelMap::MaskType_t::GOOD_CELL); + } + return masked; + } + + template + void initCCDB(TCollision const& collision) + { + // Load EMCal geometry + emcalGeom = o2::emcal::Geometry::GetInstanceFromRunNumber(collision.runNumber()); + // Load Bad Channel map + mBadChannels = ccdb->getForTimeStamp("EMC/Calib/BadChannelMap", collision.timestamp()); + lookupTable1D = std::vector(nBinsEta * nBinsPhi, -1); + double binWidthEta = (etaMax - etaMin) / nBinsEta; + double binWidthPhi = (phiMax - phiMin) / nBinsPhi; + + for (int iEta = 0; iEta < nBinsEta; ++iEta) { + double etaCenter = etaMin + (iEta + 0.5) * binWidthEta; + for (int iPhi = 0; iPhi < nBinsPhi; ++iPhi) { + double phiCenter = phiMin + (iPhi + 0.5) * binWidthPhi; + try { + // Get the cell ID + int cellID = emcalGeom->GetAbsCellIdFromEtaPhi(etaCenter, phiCenter); + + // Check conditions for the cell + if (isTooCloseToEdge(cellID, 1)) { + lookupTable1D[getIndex(iEta, iPhi)] = 2; // Edge + } else if (isCellMasked(cellID)) { + lookupTable1D[getIndex(iEta, iPhi)] = 1; // Bad + } else { + lookupTable1D[getIndex(iEta, iPhi)] = 0; // Good + } + } catch (o2::emcal::InvalidPositionException& e) { + lookupTable1D[getIndex(iEta, iPhi)] = 3; // Outside geometry + } + } + } + if (correctionConfig.cfgApplySPresolution.value) { + h1SPResolution = ccdb->getForTimeStamp(correctionConfig.cfgSpresoPath.value, collision.timestamp()); + } + } + + /// \brief Calculate background using rotation background method + template + void rotationBackground(const ROOT::Math::PtEtaPhiMVector& meson, ROOT::Math::PtEtaPhiMVector photon1, ROOT::Math::PtEtaPhiMVector photon2, TPhotons const& photons_coll, unsigned int ig1, unsigned int ig2, CollsWithQvecs::iterator const& collision) + { + // if less than 3 clusters are present skip event since we need at least 3 clusters + if (photons_coll.size() < 3) { + return; + } + + auto [xQVec, yQVec] = getQvec(collision, qvecDetector); + float cent = getCentrality(collision); + int iCellIDPhoton1 = 0; + int iCellIDPhoton2 = 0; + + ROOT::Math::AxisAngle rotationAxis(meson.Vect(), cfgRotAngle.value); + ROOT::Math::Rotation3D rotationMatrix(rotationAxis); + photon1 = rotationMatrix * photon1; + photon2 = rotationMatrix * photon2; + + if (emccuts.cfgEnableQA) { + registry.fill(HIST("mesonQA/hClusterBackEtaPhiBefore"), RecoDecay::constrainAngle(photon1.Phi()), photon1.Eta()); // before check but after rotation + registry.fill(HIST("mesonQA/hClusterBackEtaPhiBefore"), RecoDecay::constrainAngle(photon2.Phi()), photon2.Eta()); // before check but after rotation + } + + if (checkEtaPhi1D(photon1.Eta(), RecoDecay::constrainAngle(photon1.Phi())) >= cfgEMCalMapLevelBackground.value) { + iCellIDPhoton1 = -1; + } else if (emccuts.cfgEnableQA) { + registry.fill(HIST("mesonQA/hClusterBackEtaPhiAfter"), RecoDecay::constrainAngle(photon1.Phi()), photon1.Eta()); // after check + } + if (checkEtaPhi1D(photon2.Eta(), RecoDecay::constrainAngle(photon2.Phi())) >= cfgEMCalMapLevelBackground.value) { + iCellIDPhoton2 = -1; + } else if (emccuts.cfgEnableQA) { + registry.fill(HIST("mesonQA/hClusterBackEtaPhiAfter"), RecoDecay::constrainAngle(photon2.Phi()), photon2.Eta()); // after check + } + if (iCellIDPhoton1 == -1 && iCellIDPhoton2 == -1) { + return; + } + for (const auto& photon : photons_coll) { + if (photon.globalIndex() == ig1 || photon.globalIndex() == ig2) { + // only combine rotated photons with other photons + continue; + } + if (!(fEMCCut.IsSelected(photon))) { + continue; + } + if (checkEtaPhi1D(photon.eta(), RecoDecay::constrainAngle(photon.phi())) >= cfgEMCalMapLevelBackground.value) { + continue; + } + ROOT::Math::PtEtaPhiMVector photon3(photon.pt(), photon.eta(), photon.phi(), 0.); + if (iCellIDPhoton1 >= 0) { + ROOT::Math::PtEtaPhiMVector mother1 = photon1 + photon3; + float openingAngle1 = std::acos(photon1.Vect().Dot(photon3.Vect()) / (photon1.P() * photon3.P())); + float cosNPhi1 = std::cos(harmonic * mother1.Phi()); + float sinNPhi1 = std::sin(harmonic * mother1.Phi()); + float scalprodCand1 = cosNPhi1 * xQVec + sinNPhi1 * yQVec; + + if (correctionConfig.cfgApplySPresolution.value) { + scalprodCand1 = scalprodCand1 / h1SPResolution->GetBinContent(h1SPResolution->FindBin(cent + epsilon)); + } + + if (openingAngle1 > mesonConfig.minOpenAngle && thnConfigAxisInvMass.value[1] <= mother1.M() && thnConfigAxisInvMass.value.back() >= mother1.M() && thnConfigAxisPt.value[1] <= mother1.Pt() && thnConfigAxisPt.value.back() >= mother1.Pt()) { + if (mesonConfig.enableTanThetadPhi) { + float dTheta = photon1.Theta() - photon3.Theta(); + float dPhi = photon1.Phi() - photon3.Phi(); + if (mesonConfig.enableTanThetadPhi && mesonConfig.minTanThetadPhi > std::fabs(getAngleDegree(std::atan(dTheta / dPhi)))) { + registry.fill(HIST("hSparseBkgRotFlow"), mother1.M(), mother1.Pt(), cent, scalprodCand1); + } + } else { + registry.fill(HIST("hSparseBkgRotFlow"), mother1.M(), mother1.Pt(), cent, scalprodCand1); + } + } + } + if (iCellIDPhoton2 >= 0) { + ROOT::Math::PtEtaPhiMVector mother2 = photon2 + photon3; + float openingAngle2 = std::acos(photon2.Vect().Dot(photon3.Vect()) / (photon2.P() * photon3.P())); + float cosNPhi2 = std::cos(harmonic * mother2.Phi()); + float sinNPhi2 = std::sin(harmonic * mother2.Phi()); + float scalprodCand2 = cosNPhi2 * xQVec + sinNPhi2 * yQVec; + + if (correctionConfig.cfgApplySPresolution.value) { + scalprodCand2 = scalprodCand2 / h1SPResolution->GetBinContent(h1SPResolution->FindBin(cent + epsilon)); + } + + if (openingAngle2 > mesonConfig.minOpenAngle && thnConfigAxisInvMass.value[1] <= mother2.M() && thnConfigAxisInvMass.value.back() >= mother2.M() && thnConfigAxisPt.value[1] <= mother2.Pt() && thnConfigAxisPt.value.back() >= mother2.Pt()) { + if (mesonConfig.enableTanThetadPhi) { + float dTheta = photon2.Theta() - photon3.Theta(); + float dPhi = photon2.Phi() - photon3.Phi(); + if (mesonConfig.enableTanThetadPhi && mesonConfig.minTanThetadPhi > std::fabs(getAngleDegree(std::atan(dTheta / dPhi)))) { + registry.fill(HIST("hSparseBkgRotFlow"), mother2.M(), mother2.Pt(), cent, scalprodCand2); + } + } else { + registry.fill(HIST("hSparseBkgRotFlow"), mother2.M(), mother2.Pt(), cent, scalprodCand2); + } + } + } + } // end of loop over third photon + return; + } + + /// \brief Calculate background using rotation background method for calib + template + void rotationBackgroundCalib(const ROOT::Math::PtEtaPhiMVector& meson, ROOT::Math::PtEtaPhiMVector photon1, ROOT::Math::PtEtaPhiMVector photon2, TPhotons const& photons_coll, unsigned int ig1, unsigned int ig2, CollsWithQvecs::iterator const& collision) + { + // if less than 3 clusters are present skip event since we need at least 3 clusters + if (photons_coll.size() < 3) { + return; + } + float cent = getCentrality(collision); + int iCellIDPhoton1 = 0; + int iCellIDPhoton2 = 0; + + ROOT::Math::AxisAngle rotationAxis(meson.Vect(), cfgRotAngle.value); + ROOT::Math::Rotation3D rotationMatrix(rotationAxis); + photon1 = rotationMatrix * photon1; + photon2 = rotationMatrix * photon2; + + if (checkEtaPhi1D(photon1.Eta(), RecoDecay::constrainAngle(photon1.Phi())) >= cfgEMCalMapLevelBackground.value) { + iCellIDPhoton1 = -1; + } + if (checkEtaPhi1D(photon2.Eta(), RecoDecay::constrainAngle(photon2.Phi())) >= cfgEMCalMapLevelBackground.value) { + iCellIDPhoton2 = -1; + } + + if (iCellIDPhoton1 == -1 && iCellIDPhoton2 == -1) { + return; + } + for (const auto& photon : photons_coll) { + if (photon.globalIndex() == ig1 || photon.globalIndex() == ig2) { + // only combine rotated photons with other photons + continue; + } + if (!(fEMCCut.IsSelected(photon))) { + continue; + } + if (checkEtaPhi1D(photon.eta(), RecoDecay::constrainAngle(photon.phi())) >= cfgEMCalMapLevelBackground.value) { + continue; + } + ROOT::Math::PtEtaPhiMVector photon3(photon.pt(), photon.eta(), photon.phi(), 0.); + if (iCellIDPhoton1 >= 0) { + if (std::fabs((photon1.E() - photon3.E()) / (photon1.E() + photon3.E()) < 0.1)) { // only use symmetric decays + ROOT::Math::PtEtaPhiMVector mother1 = photon1 + photon3; + float openingAngle1 = std::acos(photon1.Vect().Dot(photon3.Vect()) / (photon1.P() * photon3.P())); + + if (openingAngle1 > mesonConfig.minOpenAngle && thnConfigAxisInvMass.value[1] <= mother1.M() && thnConfigAxisInvMass.value.back() >= mother1.M() && thnConfigAxisPt.value[1] <= mother1.Pt() && thnConfigAxisPt.value.back() >= mother1.Pt()) { + if (mesonConfig.enableTanThetadPhi) { + float dTheta = photon1.Theta() - photon3.Theta(); + float dPhi = photon1.Phi() - photon3.Phi(); + if (mesonConfig.enableTanThetadPhi && mesonConfig.minTanThetadPhi > std::fabs(getAngleDegree(std::atan(dTheta / dPhi)))) { + registry.fill(HIST("hSparseCalibBack"), mother1.M(), mother1.E() / 2., cent); + } + } else { + registry.fill(HIST("hSparseCalibBack"), mother1.M(), mother1.E() / 2., cent); + } + } + } + } + if (iCellIDPhoton2 >= 0) { + if (std::fabs((photon2.E() - photon3.E()) / (photon2.E() + photon3.E()) < 0.1)) { // only use symmetric decays + ROOT::Math::PtEtaPhiMVector mother2 = photon2 + photon3; + float openingAngle2 = std::acos(photon2.Vect().Dot(photon3.Vect()) / (photon2.P() * photon3.P())); + + if (openingAngle2 > mesonConfig.minOpenAngle && thnConfigAxisInvMass.value[1] <= mother2.M() && thnConfigAxisInvMass.value.back() >= mother2.M() && thnConfigAxisPt.value[1] <= mother2.Pt() && thnConfigAxisPt.value.back() >= mother2.Pt()) { + if (mesonConfig.enableTanThetadPhi) { + float dTheta = photon2.Theta() - photon3.Theta(); + float dPhi = photon2.Phi() - photon3.Phi(); + if (mesonConfig.enableTanThetadPhi && mesonConfig.minTanThetadPhi > std::fabs(getAngleDegree(std::atan(dTheta / dPhi)))) { + registry.fill(HIST("hSparseCalibBack"), mother2.M(), mother2.E() / 2., cent); + } + } else { + registry.fill(HIST("hSparseCalibBack"), mother2.M(), mother2.E() / 2., cent); + } + } + } + } + } // end of loop over third photon + return; + } + + /// Compute the scalar product + /// \param collision is the collision with the Q vector information and event plane + /// \param meson are the selected candidates + template + void runFlowAnalysis(CollsWithQvecs::iterator const& collision, ROOT::Math::PtEtaPhiMVector const& meson) + { + auto [xQVec, yQVec] = getQvec(collision, qvecDetector); + float cent = getCentrality(collision); + + float massCand = meson.M(); + float ptCand = meson.Pt(); + float phiCand = meson.Phi(); + + float cosNPhi = std::cos(harmonic * phiCand); + float sinNPhi = std::sin(harmonic * phiCand); + float scalprodCand = cosNPhi * xQVec + sinNPhi * yQVec; + + if (correctionConfig.cfgApplySPresolution.value) { + scalprodCand = scalprodCand / h1SPResolution->GetBinContent(h1SPResolution->FindBin(cent + epsilon)); + } + + if (cfgDoPlaneQA.value && histType == 0) { + float epAngle = epHelper.GetEventPlane(xQVec, yQVec, harmonic); + float cosDeltaPhi = std::cos(harmonic * getDeltaPsiInRange(phiCand, epAngle)); + registry.fill(HIST("hSparsePi0FlowPlane"), massCand, ptCand, cent, cosDeltaPhi); + } + + fillThn(massCand, ptCand, cent, scalprodCand); + return; + } + + // Pi0 from EMCal + void processEMCal(CollsWithQvecs const& collisions, EMCalPhotons const& clusters) + { + int nColl = 1; + for (const auto& collision : collisions) { + auto photonsPerCollision = clusters.sliceBy(perCollisionEMC, collision.globalIndex()); + + if (eventcuts.cfgEnableQA) { + // TODO: check EMCal NCells in collisions without EMC Readout + registry.fill(HIST("hCollisionEMCCheck"), 1.); // all + if (collision.alias_bit(kTVXinEMC) == true) { + registry.fill(HIST("hCollisionEMCCheck"), 2.); // has EMC read out + if (photonsPerCollision.size() > 0) { + registry.fill(HIST("hCollisionEMCCheck"), 3.); // has EMC cluster + registry.fill(HIST("hCollisionEMCCheck"), 4.); // has EMC read out and clusters + } else { + registry.fill(HIST("hCollisionEMCCheck"), 5.); // has EMC read out but no clusters + } + } else { + if (photonsPerCollision.size() > 0) { + registry.fill(HIST("hCollisionEMCCheck"), 3.); // has EMC cluster + registry.fill(HIST("hCollisionEMCCheck"), 6.); // has no EMC read out and clusters + } else { + registry.fill(HIST("hCollisionEMCCheck"), 7.); // has no EMC read out and no clusters + } + } + } + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(®istry, collision); + if (!(fEMEventCut.IsSelected(collision))) { + // general event selection + continue; + } + if (!(eventcuts.cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange() && collision.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) { + // occupancy selection + continue; + } + float cent = getCentrality(collision); + if (cent < eventcuts.cfgMinCent || cent > eventcuts.cfgMaxCent) { + // event selection + continue; + } + if (!isQvecGood(getAllQvec(collision))) { + // selection based on QVector + continue; + } + runNow = collision.runNumber(); + if (runNow != runBefore) { + initCCDB(collision); + runBefore = runNow; + } + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(®istry, collision); + registry.fill(HIST("Event/before/hCollisionCounter"), 12.0); // accepted + registry.fill(HIST("Event/after/hCollisionCounter"), 12.0); // accepted + + if (emccuts.cfgEnableQA) { + for (const auto& photon : photonsPerCollision) { + registry.fill(HIST("hEClusterBefore"), photon.e()); // before cuts + registry.fill(HIST("mesonQA/hClusterEtaPhiBefore"), photon.phi(), photon.eta()); // before cuts + if (!(fEMCCut.IsSelected(photon))) { + continue; + } + if (cfgDistanceToEdge.value && (checkEtaPhi1D(photon.eta(), RecoDecay::constrainAngle(photon.phi())) >= cfgEMCalMapLevelSameEvent.value)) { + continue; + } + registry.fill(HIST("hEClusterAfter"), photon.e()); // accepted after cuts + registry.fill(HIST("mesonQA/hClusterEtaPhiAfter"), photon.phi(), photon.eta()); // before cuts + } + } + for (const auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photonsPerCollision, photonsPerCollision))) { + if (!(fEMCCut.IsSelected(g1)) || !(fEMCCut.IsSelected(g2))) { + continue; + } + + // Cut edge clusters away, similar to rotation method to ensure same acceptance is used + if (cfgDistanceToEdge.value) { + if (checkEtaPhi1D(g1.eta(), RecoDecay::constrainAngle(g1.phi())) >= cfgEMCalMapLevelSameEvent.value) { + continue; + } + if (checkEtaPhi1D(g2.eta(), RecoDecay::constrainAngle(g2.phi())) >= cfgEMCalMapLevelSameEvent.value) { + continue; + } + } + + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); + if (cfgDoReverseScaling.value) { + // Convert to PxPyPzEVector to modify energy + ROOT::Math::PxPyPzEVector v1Mod(v1); + v1Mod.SetE(v1Mod.E() * 1.0505); + v1 = ROOT::Math::PtEtaPhiMVector(v1Mod.Pt(), v1Mod.Eta(), v1Mod.Phi(), 0.); + ROOT::Math::PxPyPzEVector v2Mod(v2); + v2Mod.SetE(v2Mod.E() * 1.0505); + v2 = ROOT::Math::PtEtaPhiMVector(v2Mod.Pt(), v2Mod.Eta(), v2Mod.Phi(), 0.); + } + ROOT::Math::PtEtaPhiMVector vMeson = v1 + v2; + float dTheta = v1.Theta() - v2.Theta(); + float dPhi = v1.Phi() - v2.Phi(); + float openingAngle = std::acos(v1.Vect().Dot(v2.Vect()) / (v1.P() * v2.P())); + registry.fill(HIST("hClusterCuts"), 1); + if (openingAngle <= mesonConfig.minOpenAngle) { + registry.fill(HIST("hClusterCuts"), 2); + continue; + } + if (cfgDoRotation) { + if (nColl % cfgDownsampling.value == 0) { + rotationBackground(vMeson, v1, v2, photonsPerCollision, g1.globalIndex(), g2.globalIndex(), collision); + } + } + if (thnConfigAxisInvMass.value[1] > vMeson.M() || thnConfigAxisInvMass.value.back() < vMeson.M()) { + registry.fill(HIST("hClusterCuts"), 3); + continue; + } + if (thnConfigAxisPt.value[1] > vMeson.Pt() || thnConfigAxisPt.value.back() < vMeson.Pt()) { + registry.fill(HIST("hClusterCuts"), 4); + continue; + } + if (mesonConfig.cfgEnableQA) { + registry.fill(HIST("hInvMassPt"), vMeson.M(), vMeson.Pt()); + registry.fill(HIST("hTanThetaPhi"), vMeson.M(), getAngleDegree(std::atan(dTheta / dPhi))); + registry.fill(HIST("hAlphaPt"), (v1.E() - v2.E()) / (v1.E() + v2.E()), vMeson.Pt()); + } + if (mesonConfig.enableTanThetadPhi && mesonConfig.minTanThetadPhi > std::fabs(getAngleDegree(std::atan(dTheta / dPhi)))) { + registry.fill(HIST("hClusterCuts"), 5); + continue; + } + registry.fill(HIST("hClusterCuts"), 6); + runFlowAnalysis<0>(collision, vMeson); + } + if (cfgDoRotation) { + if (nColl % cfgDownsampling.value == 0) { + nColl = 1; // reset counter + } else { + nColl++; + } + } + } + } + PROCESS_SWITCH(TaskPi0FlowEMC, processEMCal, "Process EMCal Pi0 candidates", true); + + // Pi0 from EMCal + void processEMCalMixed(FilteredCollsWithQvecs const& collisions, FilteredEMCalPhotons const& clusters) + { + auto getClustersSize = + [&clusters, this](FilteredCollsWithQvecs::iterator const& col) { + auto associatedClusters = clusters.sliceByCached(emccluster::emeventId, col.globalIndex(), this->cache); // it's cached, so slicing/grouping happens only once + return associatedClusters.size(); + }; + + using BinningType = FlexibleBinningPolicy, aod::collision::PosZ, aod::cent::CentFT0C, emevent::EP2FT0M>; + BinningType binningWithLambda{{getClustersSize}, {mixingConfig.cfgVtxBins, mixingConfig.cfgCentBins, mixingConfig.cfgEPBins}, true}; + + auto clustersTuple = std::make_tuple(clusters); + SameKindPair pair{binningWithLambda, mixingConfig.cfgMixingDepth, -1, collisions, clustersTuple, &cache}; // indicates that 5 events should be mixed and under/overflow (-1) to be ignored + + for (const auto& [c1, clusters1, c2, clusters2] : pair) { + if (!(fEMEventCut.IsSelected(c1)) || !(fEMEventCut.IsSelected(c2))) { + // general event selection + continue; + } + if (!(eventcuts.cfgFT0COccupancyMin <= c1.ft0cOccupancyInTimeRange() && c1.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax) || !(eventcuts.cfgFT0COccupancyMin <= c2.ft0cOccupancyInTimeRange() && c2.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) { + // occupancy selection + continue; + } + if (getCentrality(c1) < eventcuts.cfgMinCent || getCentrality(c1) > eventcuts.cfgMaxCent || getCentrality(c2) < eventcuts.cfgMinCent || getCentrality(c2) > eventcuts.cfgMaxCent) { + // event selection + continue; + } + if (!isQvecGood(getAllQvec(c1)) || !isQvecGood(getAllQvec(c2))) { + // selection based on QVector + continue; + } + runNow = c1.runNumber(); + if (runNow != runBefore) { + initCCDB(c1); + runBefore = runNow; + } + registry.fill(HIST("h3DMixingCount"), c1.posZ(), getCentrality(c1), c1.ep2ft0m()); + for (const auto& [g1, g2] : combinations(CombinationsFullIndexPolicy(clusters1, clusters2))) { + if (!(fEMCCut.IsSelected(g1)) || !(fEMCCut.IsSelected(g2))) { + continue; + } + // Cut edge clusters away, similar to rotation method to ensure same acceptance is used + if (cfgDistanceToEdge.value) { + if (checkEtaPhi1D(g1.eta(), RecoDecay::constrainAngle(g1.phi())) >= cfgEMCalMapLevelBackground.value) { + continue; + } + if (checkEtaPhi1D(g2.eta(), RecoDecay::constrainAngle(g2.phi())) >= cfgEMCalMapLevelBackground.value) { + continue; + } + } + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); + + if (cfgDoReverseScaling.value) { + // Convert to PxPyPzEVector to modify energy + ROOT::Math::PxPyPzEVector v1Mod(v1); + v1Mod.SetE(v1Mod.E() * 1.0505); + v1 = ROOT::Math::PtEtaPhiMVector(v1Mod.Pt(), v1Mod.Eta(), v1Mod.Phi(), 0.); + ROOT::Math::PxPyPzEVector v2Mod(v2); + v2Mod.SetE(v2Mod.E() * 1.0505); + v2 = ROOT::Math::PtEtaPhiMVector(v2Mod.Pt(), v2Mod.Eta(), v2Mod.Phi(), 0.); + } + ROOT::Math::PtEtaPhiMVector vMeson = v1 + v2; + + float dTheta = v1.Theta() - v2.Theta(); + float dPhi = v1.Phi() - v2.Phi(); + float openingAngle = std::acos(v1.Vect().Dot(v2.Vect()) / (v1.P() * v2.P())); + + registry.fill(HIST("hClusterCutsMixed"), 1); + if (openingAngle <= mesonConfig.minOpenAngle) { + registry.fill(HIST("hClusterCutsMixed"), 2); + continue; + } + if (thnConfigAxisInvMass.value[1] > vMeson.M() || thnConfigAxisInvMass.value.back() < vMeson.M()) { + registry.fill(HIST("hClusterCutsMixed"), 3); + continue; + } + if (thnConfigAxisPt.value[1] > vMeson.Pt() || thnConfigAxisPt.value.back() < vMeson.Pt()) { + registry.fill(HIST("hClusterCutsMixed"), 4); + continue; + } + if (mesonConfig.cfgEnableQA) { + registry.fill(HIST("hInvMassPtMixed"), vMeson.M(), vMeson.Pt()); + registry.fill(HIST("hTanThetaPhiMixed"), vMeson.M(), getAngleDegree(std::atan(dTheta / dPhi))); + registry.fill(HIST("hAlphaPtMixed"), (v1.E() - v2.E()) / (v1.E() + v2.E()), vMeson.Pt()); + } + if (mesonConfig.enableTanThetadPhi && mesonConfig.minTanThetadPhi > std::fabs(getAngleDegree(std::atan(dTheta / dPhi)))) { + registry.fill(HIST("hClusterCutsMixed"), 5); + continue; + } + registry.fill(HIST("hClusterCutsMixed"), 6); + runFlowAnalysis<2>(c1, vMeson); + } + } + } + PROCESS_SWITCH(TaskPi0FlowEMC, processEMCalMixed, "Process EMCal Pi0 mixed event candidates", false); + + // Resolution + void processResolution(CollsWithQvecs::iterator const& collision) + { + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(®istry, collision); + if (!(fEMEventCut.IsSelected(collision))) { + // no selection on the centrality is applied on purpose to allow for the resolution study in post-processing + return; + } + if (!(eventcuts.cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange() && collision.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) { + return; + } + float cent = getCentrality(collision); + if (cent < eventcuts.cfgMinCent || cent > eventcuts.cfgMaxCent) { + // event selection + return; + } + if (!isQvecGood(getAllQvec(collision))) { + // selection based on QVector + return; + } + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(®istry, collision); + registry.fill(HIST("Event/before/hCollisionCounter"), 12.0); // accepted + registry.fill(HIST("Event/after/hCollisionCounter"), 12.0); // accepted + + float centrality = getCentrality(collision); // centrality not updated in the rejection mask function + float xQVecFT0a = -999.f; + float yQVecFT0a = -999.f; + float xQVecFT0c = -999.f; + float yQVecFT0c = -999.f; + float xQVecFT0m = -999.f; + float yQVecFT0m = -999.f; + float xQVecBPos = -999.f; + float yQVecBPos = -999.f; + float xQVecBNeg = -999.f; + float yQVecBNeg = -999.f; + float xQVecBTot = -999.f; + float yQVecBTot = -999.f; + if (harmonic == 2) { + xQVecFT0a = collision.q2xft0a(); + yQVecFT0a = collision.q2yft0a(); + xQVecFT0c = collision.q2xft0c(); + yQVecFT0c = collision.q2yft0c(); + xQVecFT0m = collision.q2xft0m(); + yQVecFT0m = collision.q2yft0m(); + xQVecBPos = collision.q2xbpos(); + yQVecBPos = collision.q2ybpos(); + xQVecBNeg = collision.q2xbneg(); + yQVecBNeg = collision.q2ybneg(); + xQVecBTot = collision.q2xbtot(); + yQVecBTot = collision.q2ybtot(); + } else if (harmonic == 3) { + xQVecFT0a = collision.q3xft0a(); + yQVecFT0a = collision.q3yft0a(); + xQVecFT0c = collision.q3xft0c(); + yQVecFT0c = collision.q3yft0c(); + xQVecFT0m = collision.q3xft0m(); + yQVecFT0m = collision.q3yft0m(); + xQVecBPos = collision.q3xbpos(); + yQVecBPos = collision.q3ybpos(); + xQVecBNeg = collision.q3xbneg(); + yQVecBNeg = collision.q3ybneg(); + xQVecBTot = collision.q3xbtot(); + yQVecBTot = collision.q3ybtot(); + } + + if (saveSPResoHist) { + registry.fill(HIST("spReso/hSpResoFT0cFT0a"), centrality, xQVecFT0c * xQVecFT0a + yQVecFT0c * yQVecFT0a); + registry.fill(HIST("spReso/hSpResoFT0cTPCpos"), centrality, xQVecFT0c * xQVecBPos + yQVecFT0c * yQVecBPos); + registry.fill(HIST("spReso/hSpResoFT0cTPCneg"), centrality, xQVecFT0c * xQVecBNeg + yQVecFT0c * yQVecBNeg); + registry.fill(HIST("spReso/hSpResoFT0cTPCtot"), centrality, xQVecFT0c * xQVecBTot + yQVecFT0c * yQVecBTot); + registry.fill(HIST("spReso/hSpResoFT0aTPCpos"), centrality, xQVecFT0a * xQVecBPos + yQVecFT0a * yQVecBPos); + registry.fill(HIST("spReso/hSpResoFT0aTPCneg"), centrality, xQVecFT0a * xQVecBNeg + yQVecFT0a * yQVecBNeg); + registry.fill(HIST("spReso/hSpResoFT0aTPCtot"), centrality, xQVecFT0a * xQVecBTot + yQVecFT0a * yQVecBTot); + registry.fill(HIST("spReso/hSpResoFT0mTPCpos"), centrality, xQVecFT0m * xQVecBPos + yQVecFT0m * yQVecBPos); + registry.fill(HIST("spReso/hSpResoFT0mTPCneg"), centrality, xQVecFT0m * xQVecBNeg + yQVecFT0m * yQVecBNeg); + registry.fill(HIST("spReso/hSpResoFT0mTPCtot"), centrality, xQVecFT0m * xQVecBTot + yQVecFT0m * yQVecBTot); + registry.fill(HIST("spReso/hSpResoTPCposTPCneg"), centrality, xQVecBPos * xQVecBNeg + yQVecBPos * yQVecBNeg); + } + + if (saveEpResoHisto) { + float epFT0a = epHelper.GetEventPlane(xQVecFT0a, yQVecFT0a, harmonic); + float epFT0c = epHelper.GetEventPlane(xQVecFT0c, yQVecFT0c, harmonic); + float epFT0m = epHelper.GetEventPlane(xQVecFT0m, yQVecFT0m, harmonic); + float epBPoss = epHelper.GetEventPlane(xQVecBPos, yQVecBPos, harmonic); + float epBNegs = epHelper.GetEventPlane(xQVecBNeg, yQVecBNeg, harmonic); + float epBTots = epHelper.GetEventPlane(xQVecBTot, yQVecBTot, harmonic); + + registry.fill(HIST("hEventPlaneAngleFT0M"), centrality, epFT0m); + registry.fill(HIST("hEventPlaneAngleTPCpos"), centrality, epBPoss); + registry.fill(HIST("hEventPlaneAngleTPCneg"), centrality, epBNegs); + + registry.fill(HIST("epReso/hEpResoFT0cFT0a"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0c, epFT0a))); + registry.fill(HIST("epReso/hEpResoFT0cTPCpos"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0c, epBPoss))); + registry.fill(HIST("epReso/hEpResoFT0cTPCneg"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0c, epBNegs))); + registry.fill(HIST("epReso/hEpResoFT0cTPCtot"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0c, epBTots))); + registry.fill(HIST("epReso/hEpResoFT0aTPCpos"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0a, epBPoss))); + registry.fill(HIST("epReso/hEpResoFT0aTPCneg"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0a, epBNegs))); + registry.fill(HIST("epReso/hEpResoFT0aTPCtot"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0a, epBTots))); + registry.fill(HIST("epReso/hEpResoFT0mTPCpos"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0m, epBPoss))); + registry.fill(HIST("epReso/hEpResoFT0mTPCneg"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0m, epBNegs))); + registry.fill(HIST("epReso/hEpResoFT0mTPCtot"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0m, epBTots))); + registry.fill(HIST("epReso/hEpResoTPCposTPCneg"), centrality, std::cos(harmonic * getDeltaPsiInRange(epBPoss, epBNegs))); + for (int n = 1; n <= 8; n++) { + registry.fill(HIST("epReso/hEpCosCoefficientsFT0c"), centrality, n, std::cos(n * epFT0c)); + registry.fill(HIST("epReso/hEpSinCoefficientsFT0c"), centrality, n, std::sin(n * epFT0c)); + registry.fill(HIST("epReso/hEpCosCoefficientsFT0a"), centrality, n, std::cos(n * epFT0a)); + registry.fill(HIST("epReso/hEpSinCoefficientsFT0a"), centrality, n, std::sin(n * epFT0a)); + registry.fill(HIST("epReso/hEpCosCoefficientsFT0m"), centrality, n, std::cos(n * epFT0m)); + registry.fill(HIST("epReso/hEpSinCoefficientsFT0m"), centrality, n, std::sin(n * epFT0m)); + registry.fill(HIST("epReso/hEpCosCoefficientsTPCpos"), centrality, n, std::cos(n * epBPoss)); + registry.fill(HIST("epReso/hEpSinCoefficientsTPCpos"), centrality, n, std::sin(n * epBPoss)); + registry.fill(HIST("epReso/hEpCosCoefficientsTPCneg"), centrality, n, std::cos(n * epBNegs)); + registry.fill(HIST("epReso/hEpSinCoefficientsTPCneg"), centrality, n, std::sin(n * epBNegs)); + registry.fill(HIST("epReso/hEpCosCoefficientsTPCTots"), centrality, n, std::cos(n * epBTots)); + registry.fill(HIST("epReso/hEpSinCoefficientsTPCTots"), centrality, n, std::sin(n * epBTots)); + } + } + } + PROCESS_SWITCH(TaskPi0FlowEMC, processResolution, "Process resolution", false); + + // EMCal calibration + void processEMCalCalib(CollsWithQvecs const& collisions, EMCalPhotons const& clusters) + { + if (!correctionConfig.doEMCalCalib) { + return; + } + int nColl = 1; + for (const auto& collision : collisions) { + auto photonsPerCollision = clusters.sliceBy(perCollisionEMC, collision.globalIndex()); + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(®istry, collision); + if (!(fEMEventCut.IsSelected(collision))) { + // general event selection + continue; + } + if (!(eventcuts.cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange() && collision.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) { + // occupancy selection + continue; + } + float cent = getCentrality(collision); + if (cent < eventcuts.cfgMinCent || cent > eventcuts.cfgMaxCent) { + // event selection + continue; + } + if (!isQvecGood(getAllQvec(collision))) { + // selection based on QVector + continue; + } + runNow = collision.runNumber(); + if (runNow != runBefore) { + initCCDB(collision); + runBefore = runNow; + } + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(®istry, collision); + registry.fill(HIST("Event/before/hCollisionCounter"), 12.0); // accepted + registry.fill(HIST("Event/after/hCollisionCounter"), 12.0); // accepted + + if (emccuts.cfgEnableQA) { + for (const auto& photon : photonsPerCollision) { + registry.fill(HIST("hEClusterBefore"), photon.e()); // before cuts + if (!(fEMCCut.IsSelected(photon))) { + continue; + } + registry.fill(HIST("hEClusterAfter"), photon.e()); // accepted after cuts + } + } + for (const auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photonsPerCollision, photonsPerCollision))) { + if (!(fEMCCut.IsSelected(g1)) || !(fEMCCut.IsSelected(g2))) { + continue; + } + + // Cut edge clusters away, similar to rotation method to ensure same acceptance is used + if (cfgDistanceToEdge.value) { + if (checkEtaPhi1D(g1.eta(), RecoDecay::constrainAngle(g1.phi())) >= cfgEMCalMapLevelSameEvent.value) { + continue; + } + if (checkEtaPhi1D(g2.eta(), RecoDecay::constrainAngle(g2.phi())) >= cfgEMCalMapLevelSameEvent.value) { + continue; + } + } + + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); + if (cfgDoReverseScaling.value) { + // Convert to PxPyPzEVector to modify energy + ROOT::Math::PxPyPzEVector v1Mod(v1); + v1Mod.SetE(v1Mod.E() * 1.0505); + v1 = ROOT::Math::PtEtaPhiMVector(v1Mod.Pt(), v1Mod.Eta(), v1Mod.Phi(), 0.); + ROOT::Math::PxPyPzEVector v2Mod(v2); + v2Mod.SetE(v2Mod.E() * 1.0505); + v2 = ROOT::Math::PtEtaPhiMVector(v2Mod.Pt(), v2Mod.Eta(), v2Mod.Phi(), 0.); + } + ROOT::Math::PtEtaPhiMVector vMeson = v1 + v2; + float dTheta = v1.Theta() - v2.Theta(); + float dPhi = v1.Phi() - v2.Phi(); + float openingAngle = std::acos(v1.Vect().Dot(v2.Vect()) / (v1.P() * v2.P())); + registry.fill(HIST("hClusterCuts"), 1); + if (openingAngle <= mesonConfig.minOpenAngle) { + registry.fill(HIST("hClusterCuts"), 2); + continue; + } + if (cfgDoRotation) { + if (nColl % cfgDownsampling.value == 0) { + rotationBackgroundCalib(vMeson, v1, v2, photonsPerCollision, g1.globalIndex(), g2.globalIndex(), collision); + } + } + if (thnConfigAxisInvMass.value[1] > vMeson.M() || thnConfigAxisInvMass.value.back() < vMeson.M()) { + registry.fill(HIST("hClusterCuts"), 3); + continue; + } + if (thnConfigAxisPt.value[1] > vMeson.Pt() || thnConfigAxisPt.value.back() < vMeson.Pt()) { + registry.fill(HIST("hClusterCuts"), 4); + continue; + } + if (mesonConfig.cfgEnableQA) { + registry.fill(HIST("hInvMassPt"), vMeson.M(), vMeson.Pt()); + registry.fill(HIST("hTanThetaPhi"), vMeson.M(), getAngleDegree(std::atan(dTheta / dPhi))); + registry.fill(HIST("hAlphaPt"), (v1.E() - v2.E()) / (v1.E() + v2.E()), vMeson.Pt()); + } + if (mesonConfig.enableTanThetadPhi && mesonConfig.minTanThetadPhi > std::fabs(getAngleDegree(std::atan(dTheta / dPhi)))) { + registry.fill(HIST("hClusterCuts"), 5); + continue; + } + if (std::fabs((v1.E() - v2.E()) / (v1.E() + v2.E()) < 0.1)) { // only use symmetric decays + registry.fill(HIST("hClusterCuts"), 6); + registry.fill(HIST("hSparseCalibSE"), vMeson.M(), vMeson.E() / 2., getCentrality(collision)); + } + } + if (cfgDoRotation) { + if (nColl % cfgDownsampling.value == 0) { + nColl = 1; // reset counter + } else { + nColl++; + } + } + } + } + PROCESS_SWITCH(TaskPi0FlowEMC, processEMCalCalib, "Process EMCal calibration", false); + + // Pi0 from EMCal + void processM02(CollsWithQvecs const& collisions, EMCalPhotons const& clusters) + { + for (const auto& collision : collisions) { + auto photonsPerCollision = clusters.sliceBy(perCollisionEMC, collision.globalIndex()); + + if (eventcuts.cfgEnableQA) { + registry.fill(HIST("hCollisionEMCCheck"), 1.); // all + if (collision.alias_bit(kTVXinEMC) == true) { + registry.fill(HIST("hCollisionEMCCheck"), 2.); // has EMC read out + if (photonsPerCollision.size() > 0) { + registry.fill(HIST("hCollisionEMCCheck"), 3.); // has EMC cluster + registry.fill(HIST("hCollisionEMCCheck"), 4.); // has EMC read out and clusters + } else { + registry.fill(HIST("hCollisionEMCCheck"), 5.); // has EMC read out but no clusters + } + } else { + if (photonsPerCollision.size() > 0) { + registry.fill(HIST("hCollisionEMCCheck"), 3.); // has EMC cluster + registry.fill(HIST("hCollisionEMCCheck"), 6.); // has no EMC read out and clusters + } else { + registry.fill(HIST("hCollisionEMCCheck"), 7.); // has no EMC read out and no clusters + } + } + } + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(®istry, collision); + if (!(fEMEventCut.IsSelected(collision))) { + // general event selection + continue; + } + if (!(eventcuts.cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange() && collision.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) { + // occupancy selection + continue; + } + float cent = getCentrality(collision); + if (cent < eventcuts.cfgMinCent || cent > eventcuts.cfgMaxCent) { + // event selection + continue; + } + if (!isQvecGood(getAllQvec(collision))) { + // selection based on QVector + continue; + } + runNow = collision.runNumber(); + if (runNow != runBefore) { + initCCDB(collision); + runBefore = runNow; + } + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(®istry, collision); + registry.fill(HIST("Event/before/hCollisionCounter"), 12.0); // accepted + registry.fill(HIST("Event/after/hCollisionCounter"), 12.0); // accepted + + for (const auto& photon : photonsPerCollision) { + if (mesonConfig.cfgEnableQA) { + registry.fill(HIST("hEClusterBefore"), photon.e()); // before cuts + registry.fill(HIST("mesonQA/hClusterEtaPhiBefore"), photon.phi(), photon.eta()); // before cuts + } + if (!(fEMCCut.IsSelected(photon))) { + continue; + } + if (cfgDistanceToEdge.value && (checkEtaPhi1D(photon.eta(), RecoDecay::constrainAngle(photon.phi())) >= cfgEMCalMapLevelSameEvent.value)) { + continue; + } + if (mesonConfig.cfgEnableQA) { + registry.fill(HIST("hEClusterAfter"), photon.e()); // accepted after cuts + registry.fill(HIST("mesonQA/hClusterEtaPhiAfter"), photon.phi(), photon.eta()); // before cuts + } + + auto [xQVec, yQVec] = getQvec(collision, qvecDetector); + float cent = getCentrality(collision); + + float phiCand = photon.phi(); + + float cosNPhi = std::cos(harmonic * phiCand); + float sinNPhi = std::sin(harmonic * phiCand); + float scalprodCand = cosNPhi * xQVec + sinNPhi * yQVec; + + if (correctionConfig.cfgApplySPresolution.value) { + scalprodCand = scalprodCand / h1SPResolution->GetBinContent(h1SPResolution->FindBin(cent + epsilon)); + } + if (cfgDoM02.value) { + registry.fill(HIST("hSparseFlow"), photon.m02(), photon.pt(), cent, scalprodCand); + } + return; + } // end of loop over single cluster + } // end of loop over collisions + } // processM02 + PROCESS_SWITCH(TaskPi0FlowEMC, processM02, "Process single EMCal clusters as function of M02", false); + +}; // End struct TaskPi0FlowEMC + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGEM/PhotonMeson/Utils/ClusterHistograms.h b/PWGEM/PhotonMeson/Utils/ClusterHistograms.h new file mode 100644 index 00000000000..677dfa00902 --- /dev/null +++ b/PWGEM/PhotonMeson/Utils/ClusterHistograms.h @@ -0,0 +1,90 @@ +// Copyright 2019-2024 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. + +/// Header file for histograms used in EMC cluster QA +/// \author nicolas.strangmann@cern.ch + +#ifndef PWGEM_PHOTONMESON_UTILS_CLUSTERHISTOGRAMS_H_ +#define PWGEM_PHOTONMESON_UTILS_CLUSTERHISTOGRAMS_H_ + +using namespace o2::framework; + +namespace o2::aod::pwgem::photonmeson::utils::clusterhistogram +{ +void addClusterHistograms(HistogramRegistry* fRegistry, bool do2DQA) +{ + fRegistry->add("Cluster/before/hE", "E_{cluster};#it{E}_{cluster} (GeV);#it{N}_{cluster}", kTH1F, {{500, 0.0f, 50}}, true); + fRegistry->add("Cluster/before/hPt", "Transverse momenta of clusters;#it{p}_{T} (GeV/c);#it{N}_{cluster}", kTH1F, {{500, 0.0f, 50}}, true); + fRegistry->add("Cluster/before/hNgamma", "Number of #gamma candidates per collision;#it{N}_{#gamma} per collision;#it{N}_{collisions}", kTH1F, {{51, -0.5f, 50.5f}}, true); + fRegistry->add("Cluster/before/hEtaPhi", "#eta vs #varphi;#eta;#varphi (rad.)", kTH2F, {{280, -0.7f, 0.7f}, {180, 0, 2 * M_PI}}, true); + fRegistry->add("Cluster/before/hNTracks", "Number of tracks considered for TM;#it{N}_{tracks};#it{N}_{cluster}", kTH1F, {{20, -0.5f, 19.5}}, true); + fRegistry->add("Cluster/before/hTrackdEtadPhi", "d#eta vs. d#varphi of matched tracks;d#eta;d#varphi (rad.)", kTH2F, {{200, -0.2f, 0.2f}, {200, -0.2f, 0.2f}}, true); + + if (do2DQA) { // Check if 2D QA histograms were selected in em-qc task + fRegistry->add("Cluster/before/hNCell", "#it{N}_{cells};N_{cells} (GeV);#it{E}_{cluster} (GeV)", kTH2F, {{26, -0.5, 25.5}, {200, 0, 20}}, true); + fRegistry->add("Cluster/before/hM02", "Long ellipse axis;#it{M}_{02} (cm);#it{E}_{cluster} (GeV)", kTH2F, {{200, 0, 2}, {200, 0, 20}}, true); + fRegistry->add("Cluster/before/hTime", "Cluster time;#it{t}_{cls} (ns);#it{E}_{cluster} (GeV)", kTH2F, {{300, -150, 150}, {200, 0, 20}}, true); + fRegistry->add("Cluster/before/hTrackdEta", "d#eta vs. E of matched tracks;d#eta;#it{E}_{cluster} (GeV)", kTH2F, {{200, -0.2f, 0.2f}, {200, 0, 20}}, true); + fRegistry->add("Cluster/before/hTrackdPhi", "d#phi vs. E of matched tracks;d#varphi (rad.);#it{E}_{cluster} (GeV)", kTH2F, {{200, -0.2f, 0.2f}, {200, 0, 20}}, true); + fRegistry->add("Cluster/before/hTrackEOverP", "Energy of cluster divided by momentum of matched tracks;#it{E}_{cluster}/#it{p}_{track} (#it{c});#it{E}_{cluster} (GeV)", kTH2F, {{200, 0., 5.}, {200, 0, 20}}, true); + } else { + fRegistry->add("Cluster/before/hNCell", "#it{N}_{cells};N_{cells} (GeV);#it{N}_{cluster}", kTH1F, {{26, -0.5, 25.5}}, true); + fRegistry->add("Cluster/before/hM02", "Long ellipse axis;#it{M}_{02} (cm);#it{N}_{cluster}", kTH1F, {{400, 0, 2}}, true); + fRegistry->add("Cluster/before/hTime", "Cluster time;#it{t}_{cls} (ns);#it{N}_{cluster}", kTH1F, {{600, -150, 150}}, true); + fRegistry->add("Cluster/before/hTrackEOverP", "Energy of cluster divided by momentum of matched tracks;#it{E}_{cluster}/#it{p}_{track} (#it{c})", kTH1F, {{200, 0., 5.}}, true); + } + + auto hClusterQualityCuts = fRegistry->add("Cluster/hClusterQualityCuts", "Energy at which clusters are removed by a given cut;;#it{E} (GeV)", kTH2F, {{8, -0.5, 7.5}, {500, 0, 50}}, true); + hClusterQualityCuts->GetXaxis()->SetBinLabel(1, "In"); + hClusterQualityCuts->GetXaxis()->SetBinLabel(2, "Energy"); + hClusterQualityCuts->GetXaxis()->SetBinLabel(3, "NCell"); + hClusterQualityCuts->GetXaxis()->SetBinLabel(4, "M02"); + hClusterQualityCuts->GetXaxis()->SetBinLabel(5, "Timing"); + hClusterQualityCuts->GetXaxis()->SetBinLabel(6, "Track matching"); + hClusterQualityCuts->GetXaxis()->SetBinLabel(7, "Exotic"); + hClusterQualityCuts->GetXaxis()->SetBinLabel(8, "Out"); + + fRegistry->addClone("Cluster/before/", "Cluster/after/"); +} + +template +void fillClusterHistograms(HistogramRegistry* fRegistry, TCluster cluster, bool do2DQA, float weight = 1.f) +{ + static constexpr std::string_view cluster_types[2] = {"before/", "after/"}; + fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hE"), cluster.e(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hPt"), cluster.pt(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hEtaPhi"), cluster.eta(), cluster.phi(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hNTracks"), cluster.tracketa().size(), weight); + for (size_t itrack = 0; itrack < cluster.tracketa().size(); itrack++) { // Fill TrackEtaPhi histogram with delta phi and delta eta of all tracks saved in the vectors in skimmerGammaCalo.cxx + fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hTrackdEtadPhi"), cluster.tracketa()[itrack] - cluster.eta(), cluster.trackphi()[itrack] - cluster.phi(), weight); + } + if (do2DQA) { + fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hNCell"), cluster.nCells(), cluster.e(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hM02"), cluster.m02(), cluster.e(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hTime"), cluster.time(), cluster.e(), weight); + for (size_t itrack = 0; itrack < cluster.tracketa().size(); itrack++) { + fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hTrackEOverP"), cluster.e() / cluster.trackp()[itrack], cluster.e(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hTrackdEta"), cluster.tracketa()[itrack] - cluster.eta(), cluster.e(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hTrackdPhi"), cluster.trackphi()[itrack] - cluster.phi(), cluster.e(), weight); + } + } else { + fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hNCell"), cluster.nCells(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hM02"), cluster.m02(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hTime"), cluster.time(), weight); + for (size_t itrack = 0; itrack < cluster.tracketa().size(); itrack++) { + fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hTrackEOverP"), cluster.e() / cluster.trackp()[itrack], weight); + } + } +} + +} // namespace o2::aod::pwgem::photonmeson::utils::clusterhistogram + +#endif // PWGEM_PHOTONMESON_UTILS_CLUSTERHISTOGRAMS_H_ diff --git a/PWGEM/PhotonMeson/Utils/EventHistograms.h b/PWGEM/PhotonMeson/Utils/EventHistograms.h new file mode 100644 index 00000000000..49d8ff05cdb --- /dev/null +++ b/PWGEM/PhotonMeson/Utils/EventHistograms.h @@ -0,0 +1,101 @@ +// 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. + +/// \header file for histograms +/// \author daiki.sekihata@cern.ch + +#ifndef PWGEM_PHOTONMESON_UTILS_EVENTHISTOGRAMS_H_ +#define PWGEM_PHOTONMESON_UTILS_EVENTHISTOGRAMS_H_ +using namespace o2::framework; + +namespace o2::aod::pwgem::photonmeson::utils::eventhistogram +{ +void addEventHistograms(HistogramRegistry* fRegistry) +{ + // event info + auto hCollisionCounter = fRegistry->add("Event/before/hCollisionCounter", "collision counter;;Number of events", kTH1D, {{12, 0.5, 12.5}}, false); + hCollisionCounter->GetXaxis()->SetBinLabel(1, "all"); + hCollisionCounter->GetXaxis()->SetBinLabel(2, "No TF border"); + hCollisionCounter->GetXaxis()->SetBinLabel(3, "No ITS ROF border"); + hCollisionCounter->GetXaxis()->SetBinLabel(4, "No Same Bunch Pileup"); + hCollisionCounter->GetXaxis()->SetBinLabel(5, "Is Vertex ITSTPC"); + hCollisionCounter->GetXaxis()->SetBinLabel(6, "Is Good Zvtx FT0vsPV"); + hCollisionCounter->GetXaxis()->SetBinLabel(7, "FT0AND"); + hCollisionCounter->GetXaxis()->SetBinLabel(8, "sel8"); + hCollisionCounter->GetXaxis()->SetBinLabel(9, "|Z_{vtx}| < 10 cm"); + hCollisionCounter->GetXaxis()->SetBinLabel(10, "EMC MB Readout"); + hCollisionCounter->GetXaxis()->SetBinLabel(11, "EMC L0 Triggered"); + hCollisionCounter->GetXaxis()->SetBinLabel(12, "accepted"); + + fRegistry->add("Event/before/hZvtx", "vertex z; Z_{vtx} (cm)", kTH1F, {{100, -50, +50}}, false); + fRegistry->add("Event/before/hMultNTracksPV", "hMultNTracksPV; N_{track} to PV", kTH1F, {{6001, -0.5, 6000.5}}, false); + fRegistry->add("Event/before/hMultNTracksPVeta1", "hMultNTracksPVeta1; N_{track} to PV", kTH1F, {{6001, -0.5, 6000.5}}, false); + fRegistry->add("Event/before/hMultFT0", "hMultFT0;mult. FT0A;mult. FT0C", kTH2F, {{200, 0, 200000}, {60, 0, 60000}}, false); + fRegistry->add("Event/before/hCentFT0A", "hCentFT0A;centrality FT0A (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry->add("Event/before/hCentFT0C", "hCentFT0C;centrality FT0C (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry->add("Event/before/hCentFT0M", "hCentFT0M;centrality FT0M (%)", kTH1F, {{110, 0, 110}}, false); + fRegistry->add("Event/before/hCentFT0CvsMultNTracksPV", "hCentFT0CvsMultNTracksPV;centrality FT0C (%);N_{track} to PV", kTH2F, {{110, 0, 110}, {500, 0, 5000}}, false); + fRegistry->add("Event/before/hMultFT0CvsMultNTracksPV", "hMultFT0CvsMultNTracksPV;mult. FT0C;N_{track} to PV", kTH2F, {{60, 0, 60000}, {500, 0, 5000}}, false); + fRegistry->add("Event/before/hMultFT0CvsOccupancy", "hMultFT0CvsOccupancy;mult. FT0C;N_{track} in time range", kTH2F, {{60, 0, 60000}, {2000, 0, 20000}}, false); + fRegistry->addClone("Event/before/", "Event/after/"); +} + +template +void fillEventInfo(HistogramRegistry* fRegistry, TCollision const& collision, float weight = 1.) +{ + static constexpr std::string_view event_types[2] = {"before/", "after/"}; + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 1.0, weight); + if (collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 2.0, weight); + } + if (collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 3.0, weight); + } + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 4.0, weight); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 5.0, weight); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 6.0, weight); + } + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 7.0, weight); + } + if (collision.sel8()) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 8.0, weight); + } + if (std::abs(collision.posZ()) < 10.0) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 9.0, weight); + } + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hZvtx"), collision.posZ(), weight); + if (collision.alias_bit(kTVXinEMC)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 10.0, weight); + } + if (collision.alias_bit(kEMC7) || collision.alias_bit(kDMC7)) { + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 11.0, weight); + } + + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultNTracksPV"), collision.multNTracksPV(), weight); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultNTracksPVeta1"), collision.multNTracksPVeta1(), weight); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0"), collision.multFT0A(), collision.multFT0C(), weight); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0A"), collision.centFT0A(), weight); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0C"), collision.centFT0C(), weight); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0M"), collision.centFT0M(), weight); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCentFT0CvsMultNTracksPV"), collision.centFT0C(), collision.multNTracksPV(), weight); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0CvsMultNTracksPV"), collision.multFT0C(), collision.multNTracksPV(), weight); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0CvsOccupancy"), collision.multFT0C(), collision.trackOccupancyInTimeRange(), weight); +} + +} // namespace o2::aod::pwgem::photonmeson::utils::eventhistogram + +#endif // PWGEM_PHOTONMESON_UTILS_EVENTHISTOGRAMS_H_ diff --git a/PWGEM/PhotonMeson/Utils/HNMUtilities.h b/PWGEM/PhotonMeson/Utils/HNMUtilities.h new file mode 100644 index 00000000000..bb985686285 --- /dev/null +++ b/PWGEM/PhotonMeson/Utils/HNMUtilities.h @@ -0,0 +1,192 @@ +// 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 HNMUtilities.h +/// +/// \brief This code provides helper functions for the reconstruction of heavy neutral mesons (omega and eta meson) via their three pion decay +/// +/// \author Nicolas Strangmann (nicolas.strangmann@cern.ch) - Goethe University Frankfurt +/// + +#ifndef PWGEM_PHOTONMESON_UTILS_HNMUTILITIES_H_ +#define PWGEM_PHOTONMESON_UTILS_HNMUTILITIES_H_ + +#include +#include +#include +#include "TVector3.h" + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Common/DataModel/EventSelection.h" +#include "EMCALBase/Geometry.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "EventFiltering/filterTables.h" + +namespace o2::aod::pwgem::photonmeson::hnmutilities +{ +// -------> Struct to store photons from EMC clusters or V0s +struct Photon { + Photon(float px, float py, float pz, bool isFromConversion) : px(px), py(py), pz(pz), pt(std::sqrt(px * px + py * py)), isFromConversion(isFromConversion) + { + photon.SetPxPyPzE(px, py, pz, std::sqrt(px * px + py * py + pz * pz)); + } + + static Photon fromPxPyPz(float px, float py, float pz) + { + Photon photon(px, py, pz, true); + return photon; + } + + static Photon fromEtaPhiEnergy(float eta, float phi, float energy) + { + float theta = 2 * std::atan2(std::exp(-eta), 1); + float px = energy * std::sin(theta) * std::cos(phi); + float py = energy * std::sin(theta) * std::sin(phi); + float pz = energy * std::cos(theta); + Photon photon(px, py, pz, false); + return photon; + } + + ROOT::Math::PxPyPzEVector photon; + float px, py, pz, pt; + bool isFromConversion; +}; + +// -------> Struct to store gamma gamma pairs (pi0 or eta meson candidates) +struct GammaGammaPair { + GammaGammaPair(Photon p1, Photon p2) : p1(p1), p2(p2) + { + vGG = p1.photon + p2.photon; + } + Photon p1, p2; + ROOT::Math::PxPyPzEVector vGG; + + bool isPi0 = false; + bool isEta = false; + ushort reconstructionType; + void setReconstructionType(ushort type) { reconstructionType = type; } + + float m() const { return vGG.M(); } + float pT() const { return vGG.Pt(); } +}; + +// -------> Enum to specify how the heavy neutral meson mass should be corrected based on the PDG mass of its light neutral meson decay daughter +enum MassCorrectionType { + kNoHNMMassCorrection = 0, + kSubDeltaPi0 = 1, + kSubLambda = 2 +}; + +struct HeavyNeutralMeson { + HeavyNeutralMeson(GammaGammaPair* gg, float eTracks, float pxTracks, float pyTracks, float pzTracks) : gg(gg) + { + vHeavyNeutralMeson.SetPxPyPzE(gg->vGG.Px() + pxTracks, gg->vGG.Py() + pyTracks, gg->vGG.Pz() + pzTracks, gg->vGG.e() + eTracks); + } + + GammaGammaPair* gg = nullptr; + ROOT::Math::PxPyPzEVector vHeavyNeutralMeson; + + float m(int massCorrectionType) const + { + float massHNM = vHeavyNeutralMeson.M(); + switch (massCorrectionType) { + case kNoHNMMassCorrection: // No mass correction + break; + case kSubDeltaPi0: // Subtract the mass difference of the reconstructed light neutral meson mass to the PDG mass + massHNM -= gg->m(); + massHNM += (gg->isPi0 ? constants::physics::MassPi0 : 0.547862); + break; + case kSubLambda: // Subtract an opening angle dependent mass correction (see https://arxiv.org/abs/2502.19956 for details) + LOGF(warning, "SubLambdaMassCorrection not yet implemented!"); + break; + default: + LOGF(fatal, "Unknown mass correction type %d", massCorrectionType); + } + return massHNM; + } + float pT() const { return vHeavyNeutralMeson.Pt(); } + float eta() const { return vHeavyNeutralMeson.Eta(); } + float phi() const { return vHeavyNeutralMeson.Phi(); } +}; + +const int nSMEdges = 9; +float smPhiEdges[nSMEdges] = {1.75, 2.1, 2.45, 2.8, 3.14, 4., 4.89, 5.24, 5.58}; + +int getSMNumber(float eta, float phi) +{ + int smNumber = 0; + for (int iPhiInterval = 0; iPhiInterval < nSMEdges; iPhiInterval++) { + if (phi > smPhiEdges[iPhiInterval]) + smNumber = 2 * (iPhiInterval + 1); + } + if (eta < 0) + smNumber += 1; + + return smNumber; +} + +/// \brief Store photons from EMC clusters and V0s in a vector and possibly add a eta and phi offset for alignment of EMCal clusters +template +void storeGammasInVector(C clusters, V v0s, std::vector& vPhotons, std::array EMCEtaShift, std::array EMCPhiShift) +{ + vPhotons.clear(); + for (const auto& cluster : clusters) { + float eta = cluster.eta(); + float phi = cluster.phi(); + int smNumber = getSMNumber(eta, phi); + // LOG(info) << "Shifting in sm " << smNumber << ", eta/phi = " << eta << " / " << phi << " to eta/phi = " << eta + EMCEtaShift[getSMNumber(eta, phi)] << " / " << phi + EMCPhiShift[getSMNumber(eta, phi)]; + eta += EMCEtaShift[smNumber]; + phi += EMCPhiShift[smNumber]; + vPhotons.push_back(Photon::fromEtaPhiEnergy(eta, phi, cluster.e())); + } + + for (const auto& v0 : v0s) + vPhotons.push_back(Photon::fromPxPyPz(v0.px(), v0.py(), v0.pz())); +} + +/// \brief Reconstruct light neutral mesons from photons and fill them into the vGGs vector +void reconstructGGs(std::vector vPhotons, std::vector& vGGs) +{ + vGGs.clear(); + // loop over all photon combinations and build meson candidates + for (unsigned int ig1 = 0; ig1 < vPhotons.size(); ++ig1) { + for (unsigned int ig2 = ig1 + 1; ig2 < vPhotons.size(); ++ig2) { + GammaGammaPair lightMeson(vPhotons[ig1], vPhotons[ig2]); // build lightMeson from photons + if (vPhotons[ig1].isFromConversion && vPhotons[ig2].isFromConversion) + lightMeson.setReconstructionType(photonpair::kPCMPCM); + else if (!vPhotons[ig1].isFromConversion && !vPhotons[ig2].isFromConversion) + lightMeson.setReconstructionType(photonpair::kEMCEMC); + else + lightMeson.setReconstructionType(photonpair::kPCMEMC); + + vGGs.push_back(lightMeson); + } + } +} + +/// \brief Reconstruct heavy neutral mesons from the given pion, antipion and the GG candidates and add them to the vHNMs vector +void reconstructHeavyNeutralMesons(ROOT::Math::PtEtaPhiMVector const& vecPiPlPiMi, std::vector& vGGs, std::vector& vHNMs) +{ + for (size_t iGG = 0; iGG < vGGs.size(); iGG++) { + HeavyNeutralMeson heavyNeutralMeson(&vGGs.at(iGG), vecPiPlPiMi.E(), vecPiPlPiMi.Px(), vecPiPlPiMi.Py(), vecPiPlPiMi.Pz()); + vHNMs.push_back(heavyNeutralMeson); + } +} + +} // namespace o2::aod::pwgem::photonmeson::hnmutilities + +#endif // PWGEM_PHOTONMESON_UTILS_HNMUTILITIES_H_ diff --git a/PWGEM/PhotonMeson/Utils/MCUtilities.h b/PWGEM/PhotonMeson/Utils/MCUtilities.h index 9c97de5e7ee..19432c66475 100644 --- a/PWGEM/PhotonMeson/Utils/MCUtilities.h +++ b/PWGEM/PhotonMeson/Utils/MCUtilities.h @@ -20,7 +20,7 @@ #include "Framework/AnalysisTask.h" //_______________________________________________________________________ -namespace o2::aod::pwgem::mcutil +namespace o2::aod::pwgem::photonmeson::utils::mcutil { template bool IsPhysicalPrimary(TTrack const& mctrack) @@ -34,11 +34,11 @@ bool IsPhysicalPrimary(TTrack const& mctrack) } //_______________________________________________________________________ template -bool IsFromWD(TCollision const&, T const& mctrack, TMCs const& mcTracks) +int IsFromWD(TCollision const&, T const& mctrack, TMCs const& mcTracks) { // is this particle from weak decay? if (mctrack.isPhysicalPrimary() || mctrack.producedByGenerator()) { - return false; + return -1; } if (mctrack.has_mothers()) { @@ -50,7 +50,7 @@ bool IsFromWD(TCollision const&, T const& mctrack, TMCs const& mcTracks) int pdg_mother = mp.pdgCode(); if (abs(pdg_mother) == 310 || abs(pdg_mother) == 130 || abs(pdg_mother) == 3122) { // LOGF(info, "mctrack.globalIndex() = %d, mp.globalIndex() = %d , pdg_mother = %d", mctrack.globalIndex(), mp.globalIndex(), pdg_mother); - return true; + return motherid; } if (mp.has_mothers()) { motherid = mp.mothersIds()[0]; // first mother index @@ -60,9 +60,9 @@ bool IsFromWD(TCollision const&, T const& mctrack, TMCs const& mcTracks) } } } else { - return false; + return -1; } - return false; + return -1; } //_______________________________________________________________________ template @@ -122,103 +122,59 @@ int IsEleFromPC(T const& mctrack, TMCs const& mcTracks) return -1; } //_______________________________________________________________________ -template -int FindCommonMotherFrom2Prongs(TMCParticle1 const& p1, TMCParticle2 const& p2, const int expected_pdg1, const int expected_pdg2, const int expected_mother_pdg, TMCParticles const& mcparticles) -{ - if (p1.globalIndex() == p2.globalIndex()) - return -1; // mc particle p1 and p2 is identical. reject. - - if (p1.pdgCode() != expected_pdg1) - return -1; - if (p2.pdgCode() != expected_pdg2) - return -1; - - if (!p1.has_mothers()) - return -1; - if (!p2.has_mothers()) - return -1; - - // LOGF(info,"original motherid1 = %d , motherid2 = %d", p1.mothersIds()[0], p2.mothersIds()[0]); - - int motherid1 = p1.mothersIds()[0]; - auto mother1 = mcparticles.iteratorAt(motherid1); - int mother1_pdg = mother1.pdgCode(); - - int motherid2 = p2.mothersIds()[0]; - auto mother2 = mcparticles.iteratorAt(motherid2); - int mother2_pdg = mother2.pdgCode(); - - // LOGF(info,"motherid1 = %d , motherid2 = %d", motherid1, motherid2); - - if (motherid1 != motherid2) - return -1; - if (mother1_pdg != mother2_pdg) - return -1; - if (mother1_pdg != expected_mother_pdg) - return -1; - return motherid1; -} -template -int FindCommonMotherFrom3Prongs(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticle3 const& p3, const int expected_pdg1, const int expected_pdg2, const int expected_pdg3, const int expected_mother_pdg, TMCParticles const& mcparticles) +template +bool IsInAcceptanceNonDerived(TMCParticle const& mcparticle, TMCParticles const& mcparticles, TTargetPDGs target_pdgs, const float ymin, const float ymax, const float phimin, const float phimax) { - if (p1.globalIndex() == p2.globalIndex()) - return -1; // mc particle p1 and p2 are identical. reject. - if (p2.globalIndex() == p3.globalIndex()) - return -1; // mc particle p2 and p3 are identical. reject. - if (p3.globalIndex() == p1.globalIndex()) - return -1; // mc particle p3 and p1 are identical. reject. + // contents in vector of daughter ID is different. - if (p1.pdgCode() != expected_pdg1) - return -1; - if (p2.pdgCode() != expected_pdg2) - return -1; - if (p3.pdgCode() != expected_pdg3) - return -1; - - if (!p1.has_mothers()) - return -1; - if (!p2.has_mothers()) - return -1; - if (!p3.has_mothers()) - return -1; - - // LOGF(info,"original motherid1 = %d , motherid2 = %d", p1.mothersIds()[0], p2.mothersIds()[0]); - - int motherid1 = p1.mothersIds()[0]; - auto mother1 = mcparticles.iteratorAt(motherid1); - int mother1_pdg = mother1.pdgCode(); - - int motherid2 = p2.mothersIds()[0]; - auto mother2 = mcparticles.iteratorAt(motherid2); - int mother2_pdg = mother2.pdgCode(); - - int motherid3 = p3.mothersIds()[0]; - auto mother3 = mcparticles.iteratorAt(motherid3); - int mother3_pdg = mother3.pdgCode(); - - // LOGF(info,"motherid1 = %d , motherid2 = %d", motherid1, motherid2); + if (mcparticle.y() < ymin || ymax < mcparticle.y()) { + return false; // mother rapidity is out of acceptance + } + if (mcparticle.phi() < phimin || phimax < mcparticle.phi()) { + return false; // mother rapidity is out of acceptance + } + // auto daughtersIds = mcparticle.daughtersIds(); // always size = 2. first and last index. one should run loop from the first index to the last index. + int ndau = mcparticle.daughtersIds()[1] - mcparticle.daughtersIds()[0] + 1; - if (motherid1 != motherid2) - return -1; - if (motherid2 != motherid3) - return -1; - if (motherid3 != motherid1) - return -1; + if (ndau != static_cast(target_pdgs.size())) { + return false; + } + std::vector pdgs; + pdgs.reserve(target_pdgs.size()); + for (int daughterId = mcparticle.daughtersIds()[0]; daughterId <= mcparticle.daughtersIds()[1]; ++daughterId) { + if (daughterId < 0) { + pdgs.clear(); + pdgs.shrink_to_fit(); + return false; + } + auto daughter = mcparticles.iteratorAt(daughterId); + pdgs.emplace_back(daughter.pdgCode()); - if (mother1_pdg != mother2_pdg) - return -1; - if (mother2_pdg != mother3_pdg) - return -1; - if (mother3_pdg != mother1_pdg) - return -1; + if (daughter.eta() < ymin || ymax < daughter.eta()) { + pdgs.clear(); + pdgs.shrink_to_fit(); + return false; + } + if (daughter.phi() < phimin || phimax < daughter.phi()) { + pdgs.clear(); + pdgs.shrink_to_fit(); + return false; + } + } // end of daughter loop - if (mother1_pdg != expected_mother_pdg) - return -1; - return motherid1; + sort(target_pdgs.begin(), target_pdgs.end()); + sort(pdgs.begin(), pdgs.end()); + bool is_equal = std::equal(pdgs.cbegin(), pdgs.cend(), target_pdgs.cbegin()); + pdgs.clear(); + pdgs.shrink_to_fit(); + if (!is_equal) { + return false; // garantee daughter is in acceptance. + } + return true; } //_______________________________________________________________________ template -bool IsInAcceptance(TMCParticle const& mcparticle, TMCParticles const& mcparticles, TTargetPDGs const& target_pdgs, const float ymin, const float ymax, const float phimin, const float phimax) +bool IsInAcceptance(TMCParticle const& mcparticle, TMCParticles const& mcparticles, TTargetPDGs target_pdgs, const float ymin, const float ymax, const float phimin, const float phimax) { if (mcparticle.y() < ymin || ymax < mcparticle.y()) { return false; // mother rapidity is out of acceptance @@ -226,9 +182,8 @@ bool IsInAcceptance(TMCParticle const& mcparticle, TMCParticles const& mcparticl if (mcparticle.phi() < phimin || phimax < mcparticle.phi()) { return false; // mother rapidity is out of acceptance } - auto daughtersIds = mcparticle.daughtersIds(); // always size = 2. first and last index. one should run loop from the first index to the last index. + auto daughtersIds = mcparticle.daughtersIds(); - // if (daughtersIds.size() != static_cast(target_pdgs.size())) { if (daughtersIds.size() != target_pdgs.size()) { return false; } @@ -255,6 +210,7 @@ bool IsInAcceptance(TMCParticle const& mcparticle, TMCParticles const& mcparticl } } // end of daughter loop + sort(target_pdgs.begin(), target_pdgs.end()); sort(pdgs.begin(), pdgs.end()); bool is_equal = std::equal(pdgs.cbegin(), pdgs.cend(), target_pdgs.cbegin()); pdgs.clear(); @@ -268,7 +224,7 @@ bool IsInAcceptance(TMCParticle const& mcparticle, TMCParticles const& mcparticl template bool IsConversionPointInAcceptance(TMCPhoton const& mcphoton, const float max_r_gen, const float max_eta_gen, const float margin_z_mc, TMCParticles const& mcparticles) { - if (abs(mcphoton.pdgCode()) != 22) { + if (std::abs(mcphoton.pdgCode()) != 22) { return false; } @@ -282,7 +238,7 @@ bool IsConversionPointInAcceptance(TMCPhoton const& mcphoton, const float max_r_ return false; } auto daughter = mcparticles.iteratorAt(daughterId); - if (abs(daughter.pdgCode()) != 11) { + if (std::abs(daughter.pdgCode()) != 11) { return false; } @@ -290,7 +246,7 @@ bool IsConversionPointInAcceptance(TMCPhoton const& mcphoton, const float max_r_ return false; } - float rxy_gen_e = sqrt(pow(daughter.vx(), 2) + pow(daughter.vy(), 2)); + float rxy_gen_e = std::sqrt(std::pow(daughter.vx(), 2) + pow(daughter.vy(), 2)); // LOGF(info, "daughterId = %d , pdg = %d , vx = %f , vy = %f , vz = %f, rxy = %f", daughterId, daughter.pdgCode(), daughter.vx(), daughter.vy(), daughter.vz(), rxy_gen_e); if (rxy_gen_e > max_r_gen || rxy_gen_e < abs(daughter.vz()) * std::tan(2 * std::atan(std::exp(-max_eta_gen))) - margin_z_mc) { return false; @@ -300,7 +256,20 @@ bool IsConversionPointInAcceptance(TMCPhoton const& mcphoton, const float max_r_ return true; } //_______________________________________________________________________ -} // namespace o2::aod::pwgem::mcutil +template +bool isGammaGammaDecay(TMCParticle mcParticle, TMCParticles mcParticles) +{ + auto daughtersIds = mcParticle.daughtersIds(); + if (daughtersIds.size() != 2) + return false; + for (auto& daughterId : daughtersIds) { + if (mcParticles.iteratorAt(daughterId).pdgCode() != 22) + return false; + } + return true; +} +//_______________________________________________________________________ +} // namespace o2::aod::pwgem::photonmeson::utils::mcutil //_______________________________________________________________________ //_______________________________________________________________________ #endif // PWGEM_PHOTONMESON_UTILS_MCUTILITIES_H_ diff --git a/PWGEM/PhotonMeson/Utils/NMHistograms.h b/PWGEM/PhotonMeson/Utils/NMHistograms.h new file mode 100644 index 00000000000..88df03a3aed --- /dev/null +++ b/PWGEM/PhotonMeson/Utils/NMHistograms.h @@ -0,0 +1,112 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \header file for histograms +/// \author daiki.sekihata@cern.ch + +#ifndef PWGEM_PHOTONMESON_UTILS_NMHISTOGRAMS_H_ +#define PWGEM_PHOTONMESON_UTILS_NMHISTOGRAMS_H_ + +#include +#include "TF1.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" + +using namespace o2::framework; +using namespace o2::aod::pwgem::photonmeson::utils::mcutil; + +namespace o2::aod::pwgem::photonmeson::utils::nmhistogram +{ +void addNMHistograms(HistogramRegistry* fRegistry, bool isMC, const char* pairname = "#gamma#gamma") +{ + // !!Don't change pt,eta,y binning. These binnings have to be consistent with binned data at skimming.!! + std::vector ptbins; + for (int i = 0; i < 2; i++) { + ptbins.emplace_back(0.05 * (i - 0) + 0.0); // from 0 to 0.05 GeV/c, every 0.05 GeV/c + } + for (int i = 2; i < 51; i++) { + ptbins.emplace_back(0.1 * (i - 2) + 0.1); // from 0.1 to 4.9 GeV/c, every 0.1 GeV/c + } + for (int i = 51; i < 61; i++) { + ptbins.emplace_back(0.5 * (i - 51) + 5.0); // from 5 to 9.5 GeV/c, every 0.5 GeV/c + } + for (int i = 61; i < 72; i++) { + ptbins.emplace_back(1.0 * (i - 61) + 10.0); // from 10 to 20 GeV/c, every 1 GeV/c + } + const AxisSpec axis_pt{ptbins, Form("p_{T,%s} (GeV/c)", pairname)}; + const AxisSpec axis_mass{400, 0, 0.8, Form("m_{%s} (GeV/c^{2})", pairname)}; + + if (isMC) { + fRegistry->add("Pair/Pi0/hs_Primary", "rec. true pi0", kTHnSparseD, {axis_mass, axis_pt}, true); + fRegistry->add("Pair/Pi0/hs_FromWD", "rec. true pi0 from weak decay", kTHnSparseD, {axis_mass, axis_pt}, true); + fRegistry->add("Pair/Pi0/hs_FromHS", "rec. true pi0 from hadronic shower in material", kTHnSparseD, {axis_mass, axis_pt}, true); + fRegistry->add("Pair/Pi0/hs_FromSameGamma", "Two clusters from same gamma that is a pi0 daughter (conversion)", kTHnSparseD, {axis_mass, axis_pt}, true); + fRegistry->add("Pair/Eta/hs_FromSameGamma", "Two clusters from same gamma that is a eta daughter (conversion)", kTHnSparseD, {axis_mass, axis_pt}, true); + fRegistry->add("Pair/Eta/hs_Primary", "rec. true eta", kTHnSparseD, {axis_mass, axis_pt}, true); + fRegistry->add("Pair/Eta/hs_FromWD", "rec. true eta from weak decay", kTHnSparseD, {axis_mass, axis_pt}, true); + fRegistry->add("Pair/Eta/hs_FromHS", "rec. true eta from hadronic shower in material", kTHnSparseD, {axis_mass, axis_pt}, true); + + const AxisSpec axis_rapidity{{0.0, +0.8, +0.9}, "rapidity |y|"}; + fRegistry->add("Generated/Pi0/hPt", "pT;p_{T} (GeV/c)", kTH1F, {axis_pt}, true); + fRegistry->add("Generated/Pi0/hPtY", "Generated info", kTH2F, {axis_pt, axis_rapidity}, true); + fRegistry->addClone("Generated/Pi0/", "Generated/Eta/"); + + fRegistry->get(HIST("Generated/Pi0/hPt"))->SetXTitle("p_{T} (GeV/c)"); + fRegistry->get(HIST("Generated/Eta/hPt"))->SetXTitle("p_{T} (GeV/c)"); + fRegistry->get(HIST("Generated/Pi0/hPtY"))->SetXTitle("p_{T} (GeV/c)"); + fRegistry->get(HIST("Generated/Pi0/hPtY"))->SetYTitle("rapidity |y|"); + fRegistry->get(HIST("Generated/Eta/hPtY"))->SetXTitle("p_{T} (GeV/c)"); + fRegistry->get(HIST("Generated/Eta/hPtY"))->SetYTitle("rapidity |y|"); + } else { + fRegistry->add("Pair/same/hs", "diphoton", kTHnSparseD, {axis_mass, axis_pt}, true); + fRegistry->addClone("Pair/same/", "Pair/mix/"); + } +} + +template +void fillTruePairInfo(HistogramRegistry* fRegistry, TDiphoton const& v12, TMCParitlce const& mcparticle, TMCParticles const& mcparticles, TMCCollisions const&, const TF1* f1fd_k0s_to_pi0 = nullptr, float eventWeight = 1.f) +{ + int pdg = std::abs(mcparticle.pdgCode()); + float weight = eventWeight; + int motherid_strhad = IsFromWD(mcparticle.template emmcevent_as(), mcparticle, mcparticles); + switch (pdg) { + case 111: { + if (mcparticle.isPhysicalPrimary() || mcparticle.producedByGenerator()) { + fRegistry->fill(HIST("Pair/Pi0/hs_Primary"), v12.M(), v12.Pt(), weight); + } else if (motherid_strhad > 0) { + auto str_had = mcparticles.iteratorAt(motherid_strhad); + if (std::abs(str_had.pdgCode()) == 310 && f1fd_k0s_to_pi0 != nullptr) { + weight *= f1fd_k0s_to_pi0->Eval(str_had.pt()); + } + fRegistry->fill(HIST("Pair/Pi0/hs_FromWD"), v12.M(), v12.Pt(), weight); + } else { + fRegistry->fill(HIST("Pair/Pi0/hs_FromHS"), v12.M(), v12.Pt(), weight); + } + break; + } + case 221: { + if (mcparticle.isPhysicalPrimary() || mcparticle.producedByGenerator()) { + fRegistry->fill(HIST("Pair/Eta/hs_Primary"), v12.M(), v12.Pt(), weight); + } else if (motherid_strhad > 0) { + fRegistry->fill(HIST("Pair/Eta/hs_FromWD"), v12.M(), v12.Pt(), weight); + } else { + fRegistry->fill(HIST("Pair/Eta/hs_FromHS"), v12.M(), v12.Pt(), weight); + } + break; + } + default: + break; + } +} + +} // namespace o2::aod::pwgem::photonmeson::utils::nmhistogram + +#endif // PWGEM_PHOTONMESON_UTILS_NMHISTOGRAMS_H_ diff --git a/PWGEM/PhotonMeson/Utils/PCMUtilities.h b/PWGEM/PhotonMeson/Utils/PCMUtilities.h index ecf23c85a6b..625156cb373 100644 --- a/PWGEM/PhotonMeson/Utils/PCMUtilities.h +++ b/PWGEM/PhotonMeson/Utils/PCMUtilities.h @@ -19,13 +19,12 @@ #include "DCAFitter/HelixHelper.h" #include "DetectorsBase/Propagator.h" #include "Common/Core/trackUtilities.h" -#include "Framework/AnalysisTask.h" #include "Common/Core/RecoDecay.h" //_______________________________________________________________________ -bool checkAP(const float alpha, const float qt, const float alpha_max = 0.95, const float qt_max = 0.05) +inline bool checkAP(const float alpha, const float qt, const float alpha_max = 0.95, const float qt_max = 0.05) { - float ellipse = pow(alpha / alpha_max, 2) + pow(qt / qt_max, 2); + float ellipse = std::pow(alpha / alpha_max, 2) + std::pow(qt / qt_max, 2); if (ellipse < 1.0) { return true; } else { @@ -33,7 +32,7 @@ bool checkAP(const float alpha, const float qt, const float alpha_max = 0.95, co } } //_______________________________________________________________________ -float v0_alpha(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) +inline float v0_alpha(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) { float momTot = RecoDecay::p(pxpos + pxneg, pypos + pyneg, pzpos + pzneg); float lQlNeg = RecoDecay::dotProd(std::array{pxneg, pyneg, pzneg}, std::array{pxpos + pxneg, pypos + pyneg, pzpos + pzneg}) / momTot; @@ -41,27 +40,18 @@ float v0_alpha(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, return (lQlPos - lQlNeg) / (lQlPos + lQlNeg); // longitudinal momentum asymmetry of v0 } //_______________________________________________________________________ -float v0_qt(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) +inline float v0_qt(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) { float momTot = RecoDecay::p2(pxpos + pxneg, pypos + pyneg, pzpos + pzneg); float dp = RecoDecay::dotProd(std::array{pxneg, pyneg, pzneg}, std::array{pxpos + pxneg, pypos + pyneg, pzpos + pzneg}); return std::sqrt(RecoDecay::p2(pxneg, pyneg, pzneg) - dp * dp / momTot); // qt of v0 } //_______________________________________________________________________ -template -void Vtx_recalculation(o2::base::Propagator* prop, T1 lTrackPos, T2 lTrackNeg, float xyz[3], o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE) +template +inline void Vtx_recalculationParCov(o2::base::Propagator* prop, const o2::track::TrackParametrizationWithError& trackPosInformation, const o2::track::TrackParametrizationWithError& trackNegInformation, float xyz[3], o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE) { float bz = prop->getNominalBz(); - //******************************************************* - - // o2::track::TrackParametrizationWithError = TrackParCov, I use the full version to have control over the data type - o2::track::TrackParametrizationWithError trackPosInformation = getTrackParCov(lTrackPos); // first get an object that stores Track information (positive) - o2::track::TrackParametrizationWithError trackNegInformation = getTrackParCov(lTrackNeg); // first get an object that stores Track information (negative) - - // trackPosInformation.setPID(o2::track::PID::Electron); - // trackNegInformation.setPID(o2::track::PID::Electron); - o2::track::TrackAuxPar helixPos(trackPosInformation, bz); // This object is a descendant of a CircleXY and stores cirlce information with respect to the magnetic field. This object uses functions and information of the o2::track::TrackParametrizationWithError object (positive) o2::track::TrackAuxPar helixNeg(trackNegInformation, bz); // This object is a descendant of a CircleXY and stores cirlce information with respect to the magnetic field. This object uses functions and information of the o2::track::TrackParametrizationWithError object (negative) @@ -69,20 +59,18 @@ void Vtx_recalculation(o2::base::Propagator* prop, T1 lTrackPos, T2 lTrackNeg, f xyz[1] = (helixPos.yC * helixNeg.rC + helixNeg.yC * helixPos.rC) / (helixPos.rC + helixNeg.rC); // If this calculation doesn't work check if the rotateZ function, because the "documentation" says I get global coordinates but maybe i don't. // I am unsure about the Z calculation but this is how it is done in AliPhysics as far as I understand - o2::track::TrackParametrizationWithError trackPosInformationCopy = o2::track::TrackParametrizationWithError(trackPosInformation); - o2::track::TrackParametrizationWithError trackNegInformationCopy = o2::track::TrackParametrizationWithError(trackNegInformation); - // trackPosInformationCopy.setPID(o2::track::PID::Electron); - // trackNegInformationCopy.setPID(o2::track::PID::Electron); + auto trackPosInformationCopy = trackPosInformation; + auto trackNegInformationCopy = trackNegInformation; // I think this calculation gets the closest point on the track to the conversion point // This alpha is a different alpha than the usual alpha and I think it is the angle between X axis and conversion point - float alphaPos = TMath::Pi() + TMath::ATan2(-(xyz[1] - helixPos.yC), -(xyz[0] - helixPos.xC)); - float alphaNeg = TMath::Pi() + TMath::ATan2(-(xyz[1] - helixNeg.yC), -(xyz[0] - helixNeg.xC)); + float alphaPos = M_PI + std::atan2(-(xyz[1] - helixPos.yC), -(xyz[0] - helixPos.xC)); + float alphaNeg = M_PI + std::atan2(-(xyz[1] - helixNeg.yC), -(xyz[0] - helixNeg.xC)); - float vertexXPos = helixPos.xC + helixPos.rC * TMath::Cos(alphaPos); - float vertexYPos = helixPos.yC + helixPos.rC * TMath::Sin(alphaPos); - float vertexXNeg = helixNeg.xC + helixNeg.rC * TMath::Cos(alphaNeg); - float vertexYNeg = helixNeg.yC + helixNeg.rC * TMath::Sin(alphaNeg); + float vertexXPos = helixPos.xC + helixPos.rC * std::cos(alphaPos); + float vertexYPos = helixPos.yC + helixPos.rC * std::sin(alphaPos); + float vertexXNeg = helixNeg.xC + helixNeg.rC * std::cos(alphaNeg); + float vertexYNeg = helixNeg.yC + helixNeg.rC * std::sin(alphaNeg); TVector2 vertexPos(vertexXPos, vertexYPos); TVector2 vertexNeg(vertexXNeg, vertexYNeg); @@ -104,116 +92,92 @@ void Vtx_recalculation(o2::base::Propagator* prop, T1 lTrackPos, T2 lTrackNeg, f o2::base::PropagatorImpl::MAX_STEP, matCorr); - // TODO: This is still off and needs to be checked... xyz[2] = (trackPosInformationCopy.getZ() * helixNeg.rC + trackNegInformationCopy.getZ() * helixPos.rC) / (helixPos.rC + helixNeg.rC); } //_______________________________________________________________________ -float getPhivPair(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg, int cpos, int cneg, float bz) +template +inline void Vtx_recalculation(o2::base::Propagator* prop, T1 lTrackPos, T2 lTrackNeg, float xyz[3], o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE) { - // cos(phiv) = w*a /|w||a| - // with w = u x v - // and a = u x z / |u x z| , unit vector perpendicular to v12 and z-direction (magnetic field) - // u = v12 / |v12| , the unit vector of v12 - // v = v1 x v2 / |v1 x v2| , unit vector perpendicular to v1 and v2 - - // momentum of e+ and e- in (ax,ay,az) axis. Note that az=0 by definition. - // vector product of pep X pem - // std::array arr_pos{t1.GetPx(), t1.GetPy(), t1.GetPz()}; - // std::array arr_ele{t2.GetPx(), t2.GetPy(), t2.GetPz()}; - std::array arr_pos{pxpos, pypos, pzpos}; - std::array arr_ele{pxneg, pyneg, pzneg}; - std::array pos_x_ele{0, 0, 0}; - // LOGF(info, "Q1 = %d , Q2 = %d", cpos, cneg); - - if (cpos * cneg > 0) { // Like Sign - if (bz < 0) { - if (cpos > 0) { - pos_x_ele = RecoDecay::crossProd(arr_pos, arr_ele); - } else { - pos_x_ele = RecoDecay::crossProd(arr_ele, arr_pos); - } - } else { - if (cpos > 0) { - pos_x_ele = RecoDecay::crossProd(arr_ele, arr_pos); - } else { - pos_x_ele = RecoDecay::crossProd(arr_pos, arr_ele); - } - } - } else { // Unlike Sign - if (bz > 0) { - if (cpos > 0) { - pos_x_ele = RecoDecay::crossProd(arr_pos, arr_ele); - } else { - pos_x_ele = RecoDecay::crossProd(arr_ele, arr_pos); - } - } else { - if (cpos > 0) { - pos_x_ele = RecoDecay::crossProd(arr_ele, arr_pos); - } else { - pos_x_ele = RecoDecay::crossProd(arr_pos, arr_ele); - } - } - } - - // unit vector of pep X pem - float vx = pos_x_ele[0] / RecoDecay::sqrtSumOfSquares(pos_x_ele[0], pos_x_ele[1], pos_x_ele[2]); - float vy = pos_x_ele[1] / RecoDecay::sqrtSumOfSquares(pos_x_ele[0], pos_x_ele[1], pos_x_ele[2]); - float vz = pos_x_ele[2] / RecoDecay::sqrtSumOfSquares(pos_x_ele[0], pos_x_ele[1], pos_x_ele[2]); - - // unit vector of (pep+pem) - float ux = (pxpos + pxneg) / RecoDecay::sqrtSumOfSquares(pxpos + pxneg, pypos + pyneg, pzpos + pzneg); - float uy = (pypos + pyneg) / RecoDecay::sqrtSumOfSquares(pxpos + pxneg, pypos + pyneg, pzpos + pzneg); - float uz = (pzpos + pzneg) / RecoDecay::sqrtSumOfSquares(pxpos + pxneg, pypos + pyneg, pzpos + pzneg); - - float ax = uy / std::sqrt(ux * ux + uy * uy); - float ay = -ux / std::sqrt(ux * ux + uy * uy); - - // The third axis defined by vector product (ux,uy,uz)X(vx,vy,vz) - float wx = uy * vz - uz * vy; - float wy = uz * vx - ux * vz; - // by construction, (wx,wy,wz) must be a unit vector. Measure angle between (wx,wy,wz) and (ax,ay,0). - // The angle between them should be small if the pair is conversion. This function then returns values close to pi! - auto clipToPM1 = [](float x) { return x < -1.f ? -1.f : (x > 1.f ? 1.f : x); }; - - // if (!std::isfinite(std::acos(wx * ax + wy * ay))) { - // LOGF(info, "pxpos = %f, pypos = %f, pzpos = %f", pxpos, pypos, pzpos); - // LOGF(info, "pxneg = %f, pyneg = %f, pzneg = %f", pxneg, pyneg, pzneg); - // LOGF(info, "pos_x_ele[0] = %f, pos_x_ele[1] = %f, pos_x_ele[2] = %f", pos_x_ele[0], pos_x_ele[1], pos_x_ele[2]); - // LOGF(info, "ux = %f, uy = %f, uz = %f", ux, uy, uz); - // LOGF(info, "ax = %f, ay = %f", ax, ay); - // LOGF(info, "wx = %f, wy = %f", wx, wy); - // LOGF(info, "wx * ax + wy * ay = %f", wx * ax + wy * ay); - // LOGF(info, "std::acos(wx * ax + wy * ay) = %f", std::acos(wx * ax + wy * ay)); - // LOGF(info, "std::acos(clipToPM1(wx * ax + wy * ay)) = %f", std::acos(clipToPM1(wx * ax + wy * ay))); - // } + // o2::track::TrackParametrizationWithError = TrackParCov, I use the full version to have control over the data type + o2::track::TrackParametrizationWithError trackPosInformation = getTrackParCov(lTrackPos); // first get an object that stores Track information (positive) + o2::track::TrackParametrizationWithError trackNegInformation = getTrackParCov(lTrackNeg); // first get an object that stores Track information (negative) - return std::acos(clipToPM1(wx * ax + wy * ay)); // phiv in [0,pi] //cosPhiV = wx * ax + wy * ay; + Vtx_recalculationParCov(prop, trackPosInformation, trackNegInformation, xyz, matCorr); } //_______________________________________________________________________ -float getPsiPair(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) +template +float getPtResolution(TV0 const& v0) { - // float pxpos = t1.GetPx(); - // float pypos = t1.GetPy(); - // float pzpos = t1.GetPz(); - // float pxneg = t2.GetPx(); - // float pyneg = t2.GetPy(); - // float pzneg = t2.GetPz(); - - auto clipToPM1 = [](float x) { return x < -1.f ? -1.f : (x > 1.f ? 1.f : x); }; - float ptot2 = RecoDecay::p2(pxpos, pypos, pzpos) * RecoDecay::p2(pxneg, pyneg, pzneg); - float argcos = RecoDecay::dotProd(std::array{pxpos, pypos, pzpos}, std::array{pxneg, pyneg, pzneg}) / std::sqrt(ptot2); - float thetaPos = std::atan2(RecoDecay::sqrtSumOfSquares(pxpos, pypos), pzpos); - float thetaNeg = std::atan2(RecoDecay::sqrtSumOfSquares(pxneg, pyneg), pzneg); - float argsin = (thetaNeg - thetaPos) / std::acos(clipToPM1(argcos)); - return std::asin(clipToPM1(argsin)); + float px = v0.px(); + float py = v0.py(); + float pt = v0.pt(); + float px_err = std::sqrt(std::fabs(v0.sigmaPx2())); + float py_err = std::sqrt(std::fabs(v0.sigmaPy2())); + float pxy_err = v0.sigmaPxPy(); + return std::sqrt(std::pow(px / pt * px_err, 2) + std::pow(py / pt * py_err, 2) + 2.f * px / pt * py / pt * pxy_err); +} +//_______________________________________________________________________ +template +float getPhiResolution(TV0 const& v0) +{ + float px = v0.px(); + float py = v0.py(); + float pt = v0.pt(); + float px_err = std::sqrt(std::fabs(v0.sigmaPx2())); + float py_err = std::sqrt(std::fabs(v0.sigmaPy2())); + float pxy_err = v0.sigmaPxPy(); + return std::sqrt(std::pow(px / pt / pt * py_err, 2) + std::pow(py / pt / pt * px_err, 2) - 2.f * px / pt / pt * py / pt / pt * pxy_err); } //_______________________________________________________________________ -float getOpeningAngle(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) +template +float getThetaResolution(TV0 const& v0) { - auto clipToPM1 = [](float x) { return x < -1.f ? -1.f : (x > 1.f ? 1.f : x); }; - float ptot2 = RecoDecay::p2(pxpos, pypos, pzpos) * RecoDecay::p2(pxneg, pyneg, pzneg); - float argcos = RecoDecay::dotProd(std::array{pxpos, pypos, pzpos}, std::array{pxneg, pyneg, pzneg}) / std::sqrt(ptot2); - return std::acos(clipToPM1(argcos)); + float px = v0.px(); + float py = v0.py(); + float pz = v0.pz(); + float pt = v0.pt(); + float p = v0.p(); + float px_err = std::sqrt(std::fabs(v0.sigmaPx2())); + float py_err = std::sqrt(std::fabs(v0.sigmaPy2())); + float pz_err = std::sqrt(std::fabs(v0.sigmaPz2())); + float pxy_err = v0.sigmaPxPy(); + float pyz_err = v0.sigmaPyPz(); + float pzx_err = v0.sigmaPzPx(); + return std::sqrt(std::pow(pz * pz / p / p, 2) * (std::pow(px / pz / pt * px_err, 2) + std::pow(py / pz / pt * py_err, 2) + std::pow(pt / pz / pz * pz_err, 2) + 2.f * (px * py / pz / pz / pt / pt * pxy_err - py / pz / pz / pz * pyz_err - px / pz / pz / pz * pzx_err))); } //_______________________________________________________________________ +template +float getEtaResolution(TV0 const& v0) +{ + float px = v0.px(); + float py = v0.py(); + float pz = v0.pz(); + float pt = v0.pt(); + float p = v0.p(); + float px_err = std::sqrt(std::fabs(v0.sigmaPx2())); + float py_err = std::sqrt(std::fabs(v0.sigmaPy2())); + float pz_err = std::sqrt(std::fabs(v0.sigmaPz2())); + float pxy_err = v0.sigmaPxPy(); + float pyz_err = v0.sigmaPyPz(); + float pzx_err = v0.sigmaPzPx(); + return std::sqrt(std::pow(1.f / p / pt / pt, 2) * (std::pow(pz * px * px_err, 2) + std::pow(pz * py * py_err, 2) + std::pow(pt * pt * pz_err, 2) + 2.f * (pz * pz * px * py * pxy_err - pt * pt * py * pz * pyz_err - pt * pt * pz * px * pzx_err))); +} +//_______________________________________________________________________ +template +float getPResolution(TV0 const& v0) +{ + float px = v0.px(); + float py = v0.py(); + float pz = v0.pz(); + float p = v0.p(); + float px_err = std::sqrt(std::fabs(v0.sigmaPx2())); + float py_err = std::sqrt(std::fabs(v0.sigmaPy2())); + float pz_err = std::sqrt(std::fabs(v0.sigmaPz2())); + float pxy_err = v0.sigmaPxPy(); + float pyz_err = v0.sigmaPyPz(); + float pzx_err = v0.sigmaPzPx(); + return std::sqrt(std::pow(1.f / p, 2) * (std::pow(px * px_err, 2) + std::pow(py * py_err, 2) + std::pow(pz * pz_err, 2) + 2.f * (px * py * pxy_err + py * pz * pyz_err + pz * px * pzx_err))); +} +//_______________________________________________________________________ +//_______________________________________________________________________ #endif // PWGEM_PHOTONMESON_UTILS_PCMUTILITIES_H_ diff --git a/PWGEM/PhotonMeson/Utils/PairUtilities.h b/PWGEM/PhotonMeson/Utils/PairUtilities.h index 39b41bfd655..86ac4f0eb16 100644 --- a/PWGEM/PhotonMeson/Utils/PairUtilities.h +++ b/PWGEM/PhotonMeson/Utils/PairUtilities.h @@ -18,7 +18,18 @@ #include #include -namespace o2::aod::photonpair +namespace o2::aod::pwgem::photonmeson::utils::pairutil +{ +enum class PhotonPrefilterBitDerived : int { + kPhotonFromPi0gg = 0, // photon from pi0->gg + kPhotonFromPi0eeg = 1, // photon from pi0->eeg +}; +enum class ElectronPrefilterBitDerived : int { + kElectronFromPi0eeg = 0, // electron from pi0->eeg + kElectronFromFakePC = 1, // electron from photon->ee, misidentified photon conversion as virtual photon +}; +} // namespace o2::aod::pwgem::photonmeson::utils::pairutil +namespace o2::aod::pwgem::photonmeson::photonpair { enum PairType { kPCMPCM = 0, @@ -29,7 +40,7 @@ enum PairType { kPCMDalitzEE = 5, kPCMDalitzMuMu = 6, kPHOSEMC = 7, - kDalitzEEDalitzEE = 8, + kEEEE = 8, // dielectron-dielectron kNpair, }; @@ -52,6 +63,6 @@ bool DoesV0LegMatchWithCluster(TV0Leg const& v0leg, TCluster const& cluster, con float Ep = cluster.e() / v0leg.p(); return (pow(deta / max_deta, 2) + pow(dphi / max_dphi, 2) < 1) && (abs(Ep - 1) < max_Ep_width); } -} // namespace o2::aod::photonpair +} // namespace o2::aod::pwgem::photonmeson::photonpair #endif // PWGEM_PHOTONMESON_UTILS_PAIRUTILITIES_H_ diff --git a/PWGEM/PhotonMeson/Utils/TrackSelection.h b/PWGEM/PhotonMeson/Utils/TrackSelection.h index d7c4df97d2c..bdc2f5be533 100644 --- a/PWGEM/PhotonMeson/Utils/TrackSelection.h +++ b/PWGEM/PhotonMeson/Utils/TrackSelection.h @@ -43,7 +43,7 @@ inline bool isITSTPCTrack(TTrack const& track) template inline bool isTPCTRDTrack(TTrack const& track) { - return !track.hasITS() && track.hasTPC() && track.hasTRD(); + return !track.hasITS() && track.hasTPC() && track.hasTRD() && !track.hasTOF(); } /** @@ -56,7 +56,7 @@ inline bool isTPCTRDTrack(TTrack const& track) template inline bool isITSTPCTRDTrack(TTrack const& track) { - return track.hasITS() && track.hasTPC() && track.hasTRD(); + return track.hasITS() && track.hasTPC() && track.hasTRD() && !track.hasTOF(); } /** @@ -215,7 +215,7 @@ inline bool isTPConly_ITSonly(TTrack const& track0, TTrack const& track1) template inline bool checkMCParticles(T const& mc1, T const& mc2) { - if (abs(mc1.pdgCode()) != kElectron || abs(mc2.pdgCode()) != kElectron) { + if (std::abs(mc1.pdgCode()) != kElectron || std::abs(mc2.pdgCode()) != kElectron) { return false; } if (!mc1.has_mothers() || !mc2.has_mothers()) { diff --git a/PWGEM/Tasks/CMakeLists.txt b/PWGEM/Tasks/CMakeLists.txt index 4f0a92bd6f2..ef263b02e2e 100644 --- a/PWGEM/Tasks/CMakeLists.txt +++ b/PWGEM/Tasks/CMakeLists.txt @@ -9,47 +9,47 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. -o2physics_add_dpl_workflow(phoscellqa +o2physics_add_dpl_workflow(phos-cell-q-a SOURCES phosCellQA.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::PHOSBase COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(phoscluqa +o2physics_add_dpl_workflow(phos-clu-q-a SOURCES phosCluQA.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::PHOSBase COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(phostrigqa +o2physics_add_dpl_workflow(phos-trig-q-a SOURCES phosTrigQA.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::PHOSBase COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(phospi0 +o2physics_add_dpl_workflow(phos-pi0 SOURCES phosPi0.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::PHOSBase + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::PHOSBase O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(phoscalib +o2physics_add_dpl_workflow(phos-calibration SOURCES phosCalibration.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::PHOSBase O2::PHOSReconstruction COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(phosalign +o2physics_add_dpl_workflow(phos-align SOURCES phosAlign.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::PHOSBase O2::PHOSReconstruction COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(phosnbar +o2physics_add_dpl_workflow(phos-nbar SOURCES phosNbar.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::PHOSBase COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(phosnonlin +o2physics_add_dpl_workflow(phos-nonlin SOURCES phosNonlin.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::PHOSBase O2::PHOSReconstruction + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::PHOSBase O2::PHOSReconstruction O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(phoselid +o2physics_add_dpl_workflow(phos-el-id SOURCES phosElId.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::PHOSBase COMPONENT_NAME Analysis) diff --git a/PWGEM/Tasks/phosAlign.cxx b/PWGEM/Tasks/phosAlign.cxx index 2b213959ac0..d63d77b84e5 100644 --- a/PWGEM/Tasks/phosAlign.cxx +++ b/PWGEM/Tasks/phosAlign.cxx @@ -60,6 +60,8 @@ struct phosAlign { using SelCollisions = soa::Join; using tracks = soa::Join; + using mcClusters = soa::Join; + using mcTracks = soa::Join; Configurable mMinE{"mMinCluE", 0.3, "Minimum cluster energy for analysis"}; Configurable mMinCluTime{"minCluTime", -25.e-9, "Min. cluster time"}; @@ -76,13 +78,14 @@ struct phosAlign { { public: trackMatch() = default; - trackMatch(double x, double z, double p, bool el, bool charge) : pX(x), pZ(z), mom(p), isEl(el), isPos(charge) {} + trackMatch(double x, double z, double p, int32_t l, bool el, bool charge) : pX(x), pZ(z), mom(p), label(l), isEl(el), isPos(charge) {} ~trackMatch() = default; public: - double pX = 9999.; // X (phi) track coordinate in PHOS plane - double pZ = 9999.; // Z (theta) track coordinate in PHOS plane - double mom = 0.; // track momentum + double pX = 9999.; // X (phi) track coordinate in PHOS plane + double pZ = 9999.; // Z (theta) track coordinate in PHOS plane + double mom = 0.; // track momentum + int32_t label = 0; bool isEl = false; // is electron from TPC dEdx bool isPos = false; // is positive charge }; @@ -147,8 +150,8 @@ struct phosAlign { /// \brief match tracks and clusters in different PHOS modules void process(soa::Join::iterator const& collision, - aod::CaloClusters& clusters, - tracks& tracks, + mcClusters& clusters, + mcTracks& tracks, aod::BCsWithTimestamps const&) { @@ -238,7 +241,7 @@ struct phosAlign { electron = false; } } - trackMatchPoints[regionIndex].emplace_back(trackX, trackZ, track.p(), electron, static_cast(track.sign() > 0)); + trackMatchPoints[regionIndex].emplace_back(trackX, trackZ, track.p(), track.mcParticleId(), electron, static_cast(track.sign() > 0)); } for (const auto& clu : clusters) { @@ -249,6 +252,12 @@ struct phosAlign { continue; } + // int label = -1; // if no MC + // auto mcList = clu.labels(); // const std::vector + // if (mcList.size() > 0) { + // label = mcList[0]; + // } + // CPV and track match const float cellSizeX = 2 * cpvMaxX / kCpvX; const float cellSizeZ = 2 * cpvMaxZ / kCpvZ; diff --git a/PWGEM/Tasks/phosCalibration.cxx b/PWGEM/Tasks/phosCalibration.cxx index 05bdc600235..1116f47f0f2 100644 --- a/PWGEM/Tasks/phosCalibration.cxx +++ b/PWGEM/Tasks/phosCalibration.cxx @@ -191,12 +191,8 @@ struct phosCalibration { } if (sorTimestamp == 0) { - std::map metadata, headers; - const std::string run_path = Form("%s/%i", rctPath.value.data(), runNumber); - headers = ccdb_api.retrieveHeaders(run_path, metadata, -1); - if (headers.count("SOR") == 0) - LOGF(fatal, "Cannot find start-of-run timestamp for run number in path '%s'.", run_path.data()); - sorTimestamp = atol(headers["SOR"].c_str()); // timestamp of the SOR in ms + auto eorsor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdb_api, runNumber); + sorTimestamp = eorsor.first; } if (!clusterizer) { diff --git a/PWGEM/Tasks/phosCellQA.cxx b/PWGEM/Tasks/phosCellQA.cxx index 911402a9782..710244c1a6d 100644 --- a/PWGEM/Tasks/phosCellQA.cxx +++ b/PWGEM/Tasks/phosCellQA.cxx @@ -14,9 +14,12 @@ #include #include #include +#include +#include "CCDB/BasicCCDBManager.h" #include "Common/DataModel/EventSelection.h" #include "DataFormatsPHOS/Cell.h" +#include "DataFormatsPHOS/CalibParams.h" #include "Framework/ConfigParamSpec.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -43,13 +46,17 @@ using namespace o2::framework; using namespace o2::framework::expressions; struct phosCellQA { - ConfigurableAxis amplitudeAxisLarge{"amplitude", {1000, 0., 100.}, "Amplutude (GeV)"}; + + Service ccdb; + + ConfigurableAxis amplitudeAxisLarge{"amplitude", {1000, 0., 10.}, "Amplutude (GeV)"}; ConfigurableAxis timeAxisLarge{"celltime", {1000, -1500.e-9, 3500.e-9}, "cell time (ns)"}; Configurable mEvSelTrig{"mEvSelTrig", kTVXinPHOS, "Select events with this trigger"}; - Configurable mMinCellAmplitude{"minCellAmplitude", 0., "Minimum cell amplitude for histograms."}; + Configurable mMinCellAmplitude{"minCellAmplitude", 0.5, "Minimum cell energy for histograms (GeV)"}; Configurable mMinCellTimeMain{"minCellTimeMain", -50, "Min. cell time of main bunch selection"}; Configurable mMaxCellTimeMain{"maxCellTimeMain", 100, "Max. cell time of main bunch selection"}; Configurable mVetoBCID{"vetoBCID", -1, "BC ID to be excluded"}; + Configurable mCalibPath{"calibPath", "PHS/Calib/CalibParams", "path to Calibration snapshot"}; o2::framework::HistogramRegistry mHistManager{"phosCallQAHistograms"}; @@ -91,6 +98,15 @@ struct phosCellQA { void process(o2::aod::Calos const& cells, BCsWithBcSels const& bcs) { LOG(debug) << "Processing next event"; + + int64_t timestamp = 0; + if (bcs.begin() != bcs.end()) { + timestamp = bcs.begin().timestamp(); // timestamp for CCDB object retrieval + } else { + return; + } + const o2::phos::CalibParams* calibParams = ccdb->getForTimeStamp(mCalibPath, timestamp); + for (const auto& bc : bcs) { o2::InteractionRecord eventIR; eventIR.setFromLong(bc.globalBC()); @@ -110,45 +126,52 @@ struct phosCellQA { if (mVetoBCID >= 0 && cellIR.bc == mVetoBCID) continue; mHistManager.fill(HIST("cellBCSelected"), cellIR.bc); - // mHistManager.fill(HIST("cellAmplitude"), cell.amplitude(), cell.cellNumber()); if (!cell.bc_as().alias_bit(mEvSelTrig)) continue; - if (cell.amplitude() < mMinCellAmplitude) + // bool isHighGain = cell.cellType(); + double energy = calibParams->getGain(cell.cellNumber()) * cell.amplitude(); + // if (isHighGain) { + // energy = calibParams->getGain(cell.cellNumber()) * cell.amplitude(); + // } else { + // energy = calibParams->getGain(cell.cellNumber()) * cell.amplitude() * calibParams->getHGLGRatio(cell.cellNumber()); + // } + + if (energy < mMinCellAmplitude) continue; char relid[3]; o2::phos::Geometry::absToRelNumbering(cell.cellNumber(), relid); if (relid[0] == 1) { mHistManager.fill(HIST("cellOccM1"), relid[1] - 0.5, relid[2] - 0.5); - mHistManager.fill(HIST("cellAmpM1"), relid[1] - 0.5, relid[2] - 0.5, cell.amplitude()); + mHistManager.fill(HIST("cellAmpM1"), relid[1] - 0.5, relid[2] - 0.5, energy); mHistManager.fill(HIST("cellTimeM1"), relid[1] - 0.5, relid[2] - 0.5, cell.time()); if (cell.time() > mMinCellTimeMain && cell.time() < mMaxCellTimeMain) { - mHistManager.fill(HIST("cellAmpTimeM1"), cell.time(), cell.amplitude()); + mHistManager.fill(HIST("cellAmpTimeM1"), cell.time(), energy); } } if (relid[0] == 2) { mHistManager.fill(HIST("cellOccM2"), relid[1] - 0.5, relid[2] - 0.5); - mHistManager.fill(HIST("cellAmpM2"), relid[1] - 0.5, relid[2] - 0.5, cell.amplitude()); + mHistManager.fill(HIST("cellAmpM2"), relid[1] - 0.5, relid[2] - 0.5, energy); mHistManager.fill(HIST("cellTimeM2"), relid[1] - 0.5, relid[2] - 0.5, cell.time()); if (cell.time() > mMinCellTimeMain && cell.time() < mMaxCellTimeMain) { - mHistManager.fill(HIST("cellAmpTimeM2"), cell.time(), cell.amplitude()); + mHistManager.fill(HIST("cellAmpTimeM2"), cell.time(), energy); } } if (relid[0] == 3) { mHistManager.fill(HIST("cellOccM3"), relid[1] - 0.5, relid[2] - 0.5); - mHistManager.fill(HIST("cellAmpM3"), relid[1] - 0.5, relid[2] - 0.5, cell.amplitude()); + mHistManager.fill(HIST("cellAmpM3"), relid[1] - 0.5, relid[2] - 0.5, energy); mHistManager.fill(HIST("cellTimeM3"), relid[1] - 0.5, relid[2] - 0.5, cell.time()); if (cell.time() > mMinCellTimeMain && cell.time() < mMaxCellTimeMain) { - mHistManager.fill(HIST("cellAmpTimeM3"), cell.time(), cell.amplitude()); + mHistManager.fill(HIST("cellAmpTimeM3"), cell.time(), energy); } } if (relid[0] == 4) { mHistManager.fill(HIST("cellOccM4"), relid[1] - 0.5, relid[2] - 0.5); - mHistManager.fill(HIST("cellAmpM4"), relid[1] - 0.5, relid[2] - 0.5, cell.amplitude()); + mHistManager.fill(HIST("cellAmpM4"), relid[1] - 0.5, relid[2] - 0.5, energy); mHistManager.fill(HIST("cellTimeM4"), relid[1] - 0.5, relid[2] - 0.5, cell.time()); if (cell.time() > mMinCellTimeMain && cell.time() < mMaxCellTimeMain) { - mHistManager.fill(HIST("cellAmpTimeM4"), cell.time(), cell.amplitude()); + mHistManager.fill(HIST("cellAmpTimeM4"), cell.time(), energy); } } } diff --git a/PWGEM/Tasks/phosElId.cxx b/PWGEM/Tasks/phosElId.cxx index 9ae4a00f846..a2e43d23b01 100644 --- a/PWGEM/Tasks/phosElId.cxx +++ b/PWGEM/Tasks/phosElId.cxx @@ -9,6 +9,13 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file phosElId.cxx +/// \struct PHOS electron id analysis +/// \brief Task for calculating electron identification parameters +/// +/// \author Yeghishe Hambardzumyan, MIPT +/// \since Apr, 2024 + #include #include #include @@ -19,11 +26,12 @@ #include "Common/Core/TrackSelectionDefaults.h" #include "Common/DataModel/CaloClusters.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/TrackSelectionTables.h" #include "ReconstructionDataFormats/TrackParametrization.h" - #include "Framework/ConfigParamSpec.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -31,90 +39,280 @@ #include "Framework/ASoA.h" #include "Framework/ASoAHelpers.h" #include "Framework/HistogramRegistry.h" - #include "PHOSBase/Geometry.h" #include "DataFormatsParameters/GRPMagField.h" #include "CommonDataFormat/InteractionRecord.h" #include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPLHCIFData.h" #include "DetectorsBase/Propagator.h" - -/// \struct PHOS electron id analysis -/// \brief Task for calculating electron identification parameters -/// \author Yeghishe Hambardzumyan, MIPT -/// \since Apr, 2024 -/// @note Inherits functions and variables from phosAlign & phosPi0. -/// @note Results will be used for candidate table producing task. -/// +#include "TF1.h" +#include "TLorentzVector.h" using namespace o2; +using namespace o2::soa; using namespace o2::aod::evsel; using namespace o2::framework; using namespace o2::framework::expressions; -struct phosElId { +namespace o2::aod +{ +namespace phos_match +{ +DECLARE_SOA_INDEX_COLUMN(Collision, collision); +DECLARE_SOA_INDEX_COLUMN(Track, track); +DECLARE_SOA_INDEX_COLUMN(CaloCluster, caloCluster); +DECLARE_SOA_COLUMN(SignalCharge, signalCharge, float); +DECLARE_SOA_COLUMN(SignalZ, signalZ, float); +DECLARE_SOA_COLUMN(SignalPx, signalPx, double); +DECLARE_SOA_COLUMN(SignalPy, signalPy, double); +DECLARE_SOA_COLUMN(SignalPz, signalPz, double); +DECLARE_SOA_COLUMN(SignalE, signalE, double); +} // namespace phos_match + +DECLARE_SOA_TABLE(PHOSMatchindexTable, "AOD", "PHSMTCH", //! + o2::soa::Index<>, phos_match::CollisionId, phos_match::CaloClusterId, phos_match::TrackId); //! - using SelCollisions = soa::Join; - using tracks = soa::Join; +} // namespace o2::aod + +// globalized estimator names for centrality +enum CentEstimators { FV0A, + FT0M, + FT0A, + FT0C, + FDDM, + NTPV }; - Configurable mMinE{"mMinCluE", 0.3, "Minimum cluster energy for analysis"}; +struct PhosElId { - Configurable nBinsDeltaX{"nBinsDeltaX", 250, "N bins for track and cluster coordinate delta"}; - Configurable mDeltaXmin{"mDeltaXmin", -50., "Min for track and cluster coordinate delta"}; - Configurable mDeltaXmax{"mDeltaXmax", 50., "Max for track and cluster coordinate delta"}; + Produces phosMatch; - Configurable nBinsDeltaZ{"nBinsDeltaZ", 250, "N bins for track and cluster coordinate delta"}; - Configurable mDeltaZmin{"mDeltaZmin", -50., "Min for track and cluster coordinate delta"}; - Configurable mDeltaZmax{"mDeltaZmax", 50., "Max for track and cluster coordinate delta"}; + using SelCollisions = soa::Join; + using MyTracks = soa::Join; + Configurable mMinCluE{"mMinCluE", 0.3, "Minimum cluster energy for analysis"}, + mMinCluTime{"minCluTime", -25.e-9, "Min. cluster time"}, + mMaxCluTime{"mMaxCluTime", 25.e-9, "Max. cluster time"}, + mCluTimeAxisMin{"mCluTimeAxisMin", -100, "lower axis limit for cluster time in nanoseconds"}, + mCluTimeAxisMax{"mCluTimeAxisMax", 100, "upper axis limit for cluster time in nanoseconds"}, + mDeltaXmin{"mDeltaXmin", -100., "Min for track and cluster coordinate delta"}, + mDeltaXmax{"mDeltaXmax", 100., "Max for track and cluster coordinate delta"}, + mDeltaZmin{"mDeltaZmin", -100., "Min for track and cluster coordinate delta"}, + mDeltaZmax{"mDeltaZmax", 100., "Max for track and cluster coordinate delta"}, + mEpmin{"mEpmin", -1., "Min for E/p histograms"}, + mEpmax{"mEpmax", 3., "Max for E/p histograms"}, + cfgEtaMax{"cfgEtaMax", {0.8f}, "eta ranges"}, + cfgPtMin{"cfgPtMin", {0.2f}, "pt min"}, + cfgPtMax{"cfgPtMax", {20.f}, "pt max"}, + cfgDCAxyMax{"cfgDCAxyMax", {3.f}, "dcaxy max"}, + cfgDCAzMax{"cfgDCAzMax", {3.f}, "dcaz max"}, + cfgITSchi2Max{"cfgITSchi2Max", {5.f}, "its chi2 max"}, + cfgITSnclsMin{"cfgITSnclsMin", {4.5f}, "min number of ITS clusters"}, + cfgITSnclsMax{"cfgITSnclsMax", {7.5f}, "max number of ITS clusters"}, + cfgTPCchi2Max{"cfgTPCchi2Max", {4.f}, "tpc chi2 max"}, + cfgTPCnclsMin{"cfgTPCnclsMin", {90.f}, "min number of TPC clusters"}, + cfgTPCnclsMax{"cfgTPCnclsMax", {170.f}, "max number of TPC clusters"}, + cfgTPCnclsCRMin{"cfgTPCnclsCRMin", {80.f}, "min number of TPC crossed rows"}, + cfgTPCnclsCRMax{"cfgTPCnclsCRMax", {161.f}, "max number of TPC crossed rows"}, + cfgTPCNSigmaElMin{"cfgTPCNSigmaElMin", {-3.f}, "min TPC nsigma e for inclusion"}, + cfgTPCNSigmaElMax{"cfgTPCNSigmaElMax", {2.f}, "max TPC nsigma e for inclusion"}, + cfgTPCNSigmaPiMin{"cfgTPCNSigmaPiMin", {-3.f}, "min TPC nsigma pion for exclusion"}, + cfgTPCNSigmaPiMax{"cfgTPCNSigmaPiMax", {3.5f}, "max TPC nsigma pion for exclusion"}, + cfgTPCNSigmaPrMin{"cfgTPCNSigmaPrMin", {-3.f}, "min TPC nsigma proton for exclusion"}, + cfgTPCNSigmaPrMax{"cfgTPCNSigmaPrMax", {4.f}, "max TPC nsigma proton for exclusion"}, + cfgTPCNSigmaKaMin{"cfgTPCNSigmaKaMin", {-3.f}, "min TPC nsigma kaon for exclusion"}, + cfgTPCNSigmaKaMax{"cfgTPCNSigmaKaMax", {4.f}, "max TPC nsigma kaon for exclusion"}, + cfgTOFNSigmaElMin{"cfgTOFNSigmaElMin", {-3.f}, "min TOF nsigma e for inclusion"}, + cfgTOFNSigmaElMax{"cfgTOFNSigmaElMax", {3.f}, "max TOF nsigma e for inclusion"}, + cfgNsigmaTrackMatch{"cfgNsigmaTrackMatch", {2.f}, "PHOS Track Matching Nsigma for inclusion"}; + + Configurable mEvSelTrig{"mEvSelTrig", kTVXinPHOS, "Select events with this trigger"}, + mMinCluNcell{"minCluNcell", 3, "min cells in cluster"}, + nBinsDeltaX{"nBinsDeltaX", 500, "N bins for track and cluster coordinate delta"}, + nBinsDeltaZ{"nBinsDeltaZ", 500, "N bins for track and cluster coordinate delta"}, + nBinsEp{"nBinsEp", 400, "N bins for E/p histograms"}; - Configurable nBinsEp{"nBinsEp", 400, "N bins for E/p histograms"}; - Configurable mEpmin{"mEpmin", -1., "Min for E/p histograms"}; - Configurable mEpmax{"mEpmax", 3., "Max for E/p histograms"}; + Configurable> pSigmadZ{"pSigmadZ", {0.642, 0., 1.77, 2.725, 0.}, "parameters for sigma dz function"}, + pSigmadX{"pSigmadX", {2.17769, 1.60275, 2.24136}, "parameters for sigma dx function"}, + pPhosShiftZ{"pPhosShiftZ", {4.78838, 2.75138, 1.40825, 2.28735}, "Phos coordinate centering Z per module"}, + pPhosShiftX{"pPhosShiftX", {2.158702, -1.526772, -0.814658, -1.852678}, "Phos coordinate centering X per module"}, + pMeandXPosMod1{"pMeandXPosMod1", {-10.57, -0.42, 1.06}, "parameters for mean dx function on module 1 for positive tracks"}, + pMeandXPosMod2{"pMeandXPosMod2", {-8.1, -0.42, 1.14}, "parameters for mean dx function on module 2 for positive tracks"}, + pMeandXPosMod3{"pMeandXPosMod3", {-8.34, -0.42, 1.04}, "parameters for mean dx function on module 3 for positive tracks"}, + pMeandXPosMod4{"pMeandXPosMod4", {-7.38, -0.42, 1.17}, "parameters for mean dx function on module 4 for positive tracks"}, + pMeandXNegMod1{"pMeandXNegMod1", {9.92, -0.42, 1.29}, "parameters for mean dx function on module 1 for negative tracks"}, + pMeandXNegMod2{"pMeandXNegMod2", {7.82, -0.4, 1.34}, "parameters for mean dx function on module 2 for negative tracks"}, + pMeandXNegMod3{"pMeandXNegMod3", {8.45, -0.33, 1.5}, "parameters for mean dx function on module 3 for negative tracks"}, + pMeandXNegMod4{"pMeandXNegMod4", {7.5, -0.42, 1.25}, "parameters for mean dx function on module 4 for negative tracks"}; + + Filter ptFilter = (aod::track::pt > cfgPtMin) && (aod::track::pt < cfgPtMax); + Filter etafilter = nabs(aod::track::eta) < cfgEtaMax; + Filter dcaxyfilter = nabs(aod::track::dcaXY) < cfgDCAxyMax; + Filter dcazfilter = nabs(aod::track::dcaZ) < cfgDCAzMax; + Filter itschi2filter = aod::track::itsChi2NCl < cfgITSchi2Max; + Filter tpcchi2filter = aod::track::tpcChi2NCl < cfgTPCchi2Max; + Filter mapfilter = (aod::track::itsClusterMap & uint8_t(1)) > 0; Service ccdb; std::unique_ptr geomPHOS; double bz{0.}; // magnetic field int runNumber{0}; - HistogramRegistry mHistManager{"phosElIdHistograms"}; + HistogramRegistry mHistManager{"PhosElIdHistograms"}; + TF1 *fSigma_dz, *fSigma_dx; + float *PhosShiftX, *PhosShiftZ; + + TF1* fMeandXPosMod1; + TF1* fMeandXNegMod1; + TF1* fMeandXPosMod2; + TF1* fMeandXNegMod2; + TF1* fMeandXPosMod3; + TF1* fMeandXNegMod3; + TF1* fMeandXPosMod4; + TF1* fMeandXNegMod4; void init(InitContext const&) { LOG(info) << "Initializing PHOS electron identification analysis task ..."; - std::vector momentum_binning = {0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.8, 0.85, 0.9, 0.95, 1.0, - 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, - 4.5, 5.0, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 10.}; - const AxisSpec - axisP{momentum_binning, "p (GeV/c)"}, - axisCounter{1, 0, +1, ""}, + std::vector momentumBinning = {0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, + 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 10.}; + std::vector parametersSigmadZ = pSigmadZ; + std::vector parametersSigmadX = pSigmadX; + std::vector vPhosShiftX = pPhosShiftX; + std::vector vPhosShiftZ = pPhosShiftZ; + std::vector meandXPosMod1 = pMeandXPosMod1; + std::vector meandXPosMod2 = pMeandXPosMod2; + std::vector meandXPosMod3 = pMeandXPosMod3; + std::vector meandXPosMod4 = pMeandXPosMod4; + std::vector meandXNegMod1 = pMeandXNegMod1; + std::vector meandXNegMod2 = pMeandXNegMod2; + std::vector meandXNegMod3 = pMeandXNegMod3; + std::vector meandXNegMod4 = pMeandXNegMod4; + + PhosShiftX = new float[4]; + PhosShiftX[0] = vPhosShiftX.at(0); + PhosShiftX[1] = vPhosShiftX.at(1); + PhosShiftX[2] = vPhosShiftX.at(2); + PhosShiftX[3] = vPhosShiftX.at(3); + + PhosShiftZ = new float[4]; + PhosShiftZ[0] = vPhosShiftZ.at(0); + PhosShiftZ[1] = vPhosShiftZ.at(1); + PhosShiftZ[2] = vPhosShiftZ.at(2); + PhosShiftZ[3] = vPhosShiftZ.at(3); + + const AxisSpec axisCounter{1, 0, +1, ""}, + axisP{momentumBinning, "p (GeV/c)"}, + axisPt{momentumBinning, "p_{T} (GeV/c)"}, + axisEta{200, -0.2, 0.2, "#eta"}, + axisPhi{80, 240, 320, "#varphi"}, + axisE{200, 0, 10, "E (GeV)", "E (GeV)"}, + axisMassSpectrum{4000, 0, 4, "M (GeV/c^{2})", "Mass e^{+}e^{-} (GeV/c^{2})"}, axisEp{nBinsEp, mEpmin, mEpmax, "E/p", "E_{cluster}/p_{track}"}, axisdX{nBinsDeltaX, mDeltaXmin, mDeltaXmax, "x_{tr}-x_{clu} (cm)", "x_{tr}-x_{clu} (cm)"}, axisdZ{nBinsDeltaZ, mDeltaZmin, mDeltaZmax, "z_{tr}-z_{clu} (cm)", "z_{tr}-z_{clu} (cm)"}, + axisCells{20, 0., 20., "number of cells", "number of cells"}, + axisTime{200, mCluTimeAxisMin, mCluTimeAxisMax, "time (ns)", "time (nanoseconds)"}, axisModes{4, 1., 5., "module", "module"}, axisX{150, -75., 75., "x (cm)", "x (cm)"}, - axisZ{150, -75., 75., "z (cm)", "z (cm)"}; + axisZ{150, -75., 75., "z (cm)", "z (cm)"}, + axisDCATrackXY{400, -.1, .1, "DCA XY (cm)", "DCA XY (cm)"}, + axisDCATrackZ{400, -.1, .1, "DCA Z (cm)", "DCA Z (cm)"}, + axisVColX{400, -.1, .1, "colision vertex x (cm)", "colision vertex x (cm)"}, + axisVColY{400, -.1, .1, "colision vertex y (cm)", "colision vertex y (cm)"}, + axisVColZ{400, -20., 20., "colision vertex z (cm)", "colision vertex z (cm)"}, // should look like gauss + axisVTrackX{400, -10., 10., "track vertex x (cm)", "track vertex x (cm)"}, + axisVTrackY{400, -10., 10., "track vertex y (cm)", "track vertex y (cm)"}, + axisVTrackZ{400, -10., 10., "track vertex z (cm)", "track vertex z (cm)"}; mHistManager.add("eventCounter", "eventCounter", kTH1F, {axisCounter}); - mHistManager.add("hDeltaXPos_v_p", "positive trackX - clusterX vs p", HistType::kTH2F, {axisdX, axisP}); - mHistManager.add("hDeltaXNeg_v_p", "negative trackX - clusterX vs p", HistType::kTH2F, {axisdX, axisP}); - mHistManager.add("hDeltaZ_v_p", "trackZ - clusterZ vs p", HistType::kTH2F, {axisdZ, axisP}); - mHistManager.add("hEp_v_p", "E/p ratio vs p", HistType::kTH2F, {axisEp, axisP}); - mHistManager.add("hEp_v_p_disp", "E/p ratio vs p | OK dispersion", HistType::kTH2F, {axisEp, axisP}); - mHistManager.add("hdXdZp", "dx,dz,p_{tr}", HistType::kTH3F, {axisdX, axisdZ, axisP}); - mHistManager.add("hdZpmod", "dz,p_{tr},module", HistType::kTH3F, {axisdZ, axisP, axisModes}); - mHistManager.add("hdXpmod", "dx,p_{tr},module", HistType::kTH3F, {axisdX, axisP, axisModes}); - mHistManager.add("hdXpmod_pos", "dx,p_{tr},module positive tracks", HistType::kTH3F, {axisdX, axisP, axisModes}); - mHistManager.add("hdXpmod_neg", "dx,p_{tr},module negative tracks", HistType::kTH3F, {axisdX, axisP, axisModes}); + mHistManager.add("TVXinPHOSCounter", "TVXinPHOSCounter", kTH1F, {axisCounter}); + + mHistManager.add("hTrackPtEtaPhi", "Track pt vs eta vs phi", HistType::kTH3F, {axisPt, axisEta, axisPhi}); + mHistManager.add("hTrackPtEtaPhi_Phos", "Track pt vs eta vs phi on Phos surface", HistType::kTH3F, {axisPt, axisEta, axisPhi}); + mHistManager.add("hTrackDCA", "Track DCA info", HistType::kTH2F, {axisDCATrackXY, axisDCATrackZ}); + mHistManager.add("hTrackVX", "Track vertex coordinate X", HistType::kTH1F, {axisVTrackX}); + mHistManager.add("hTrackVY", "Track vertex coordinate Y", HistType::kTH1F, {axisVTrackY}); + mHistManager.add("hTrackVZ", "Track vertex coordinate Z", HistType::kTH1F, {axisVTrackZ}); + mHistManager.add("hColVX", "Collision vertex coordinate X", HistType::kTH1F, {axisVColX}); + mHistManager.add("hColVY", "Collision vertex coordinate Y", HistType::kTH1F, {axisVColY}); + mHistManager.add("hColVZ", "Collision vertex coordinate Z", HistType::kTH1F, {axisVColZ}); + mHistManager.add("hTrackPhosProjMod", "Track projection coordinates on PHOS modules", HistType::kTH3F, {axisX, axisZ, axisModes}); + + mHistManager.add("hCluE_v_mod_v_time", "Cluster energy spectrum (E > 0.3 GeV) vs time per module", HistType::kTH3F, {axisE, axisTime, axisModes}); + + mHistManager.add("hCluE_mod_energy_cut", "Cluster energy spectrum (E > 0.3 GeV) per module", HistType::kTH2F, {axisE, axisModes}); + mHistManager.add("hCluE_mod_time_cut", "Cluster energy spectrum (E > 0.3 GeV)(time +-25 ns) per module", HistType::kTH2F, {axisE, axisModes}); + mHistManager.add("hCluE_mod_cell_cut", "Cluster energy spectrum (E > 0.3 GeV)(time +-25 ns)(ncells > 3) per module", HistType::kTH2F, {axisE, axisModes}); + mHistManager.add("hCluE_mod_disp", "Cluster energy spectrum OK dispersion and (E > 0.3 GeV)(time +-25 ns)(ncells > 3) per module", HistType::kTH2F, {axisE, axisModes}); + + mHistManager.add("hCluE_ncells_mod", "Cluster energy spectrum per module", HistType::kTH3F, {axisE, axisCells, axisModes}); + mHistManager.add("hCluXZ_mod", "Local cluster X Z per module", HistType::kTH3F, {axisX, axisZ, axisModes}); + + mHistManager.add("hdZpmod", "dz,p_{tr},module", HistType::kTH3F, {axisdZ, axisPt, axisModes}); + mHistManager.add("hdZpmod_pos", "dz,p_{tr},module positive tracks", HistType::kTH3F, {axisdZ, axisPt, axisModes}); + mHistManager.add("hdZpmod_neg", "dz,p_{tr},module negative tracks", HistType::kTH3F, {axisdZ, axisPt, axisModes}); + mHistManager.add("hdXpmod", "dx,p_{tr},module", HistType::kTH3F, {axisdX, axisPt, axisModes}); + mHistManager.add("hdXpmod_pos", "dx,p_{tr},module positive tracks", HistType::kTH3F, {axisdX, axisPt, axisModes}); + mHistManager.add("hdXpmod_neg", "dx,p_{tr},module negative tracks", HistType::kTH3F, {axisdX, axisPt, axisModes}); + + mHistManager.add("hCluE_v_pt_disp", "Cluster energy vs p | OK dispersion", HistType::kTH3F, {axisE, axisPt, axisModes}); + mHistManager.add("hCluE_v_pt_Nsigma", "Cluster energy vs p within trackmatch Nsigma", HistType::kTH3F, {axisE, axisPt, axisModes}); + mHistManager.add("hCluE_v_pt_Nsigma_disp", "Cluster energy vs p within trackmatch Nsigma | OK dispersion", HistType::kTH3F, {axisE, axisPt, axisModes}); + + mHistManager.add("hCluE_v_pt_disp_TPC", "Cluster energy vs p | OK dispersion", HistType::kTH3F, {axisE, axisPt, axisModes}); + mHistManager.add("hCluE_v_pt_Nsigma_TPC", "Cluster energy vs p within trackmatch Nsigma", HistType::kTH3F, {axisE, axisPt, axisModes}); + mHistManager.add("hCluE_v_pt_Nsigma_disp_TPC", "Cluster energy vs p within trackmatch Nsigma | OK dispersion", HistType::kTH3F, {axisE, axisPt, axisModes}); + + mHistManager.add("hEp_v_pt_disp", "E/p ratio vs p | OK dispersion", HistType::kTH3F, {axisEp, axisPt, axisModes}); + mHistManager.add("hEp_v_pt_Nsigma", "E/p ratio vs p within trackmatch Nsigma", HistType::kTH3F, {axisEp, axisPt, axisModes}); + mHistManager.add("hEp_v_pt_Nsigma_disp", "E/p ratio vs p within trackmatch Nsigma | OK dispersion", HistType::kTH3F, {axisEp, axisPt, axisModes}); + + mHistManager.add("hEp_v_E_disp", "E/p ratio vs cluster E | OK dispersion", HistType::kTH3F, {axisEp, axisE, axisModes}); + mHistManager.add("hEp_v_E_Nsigma", "E/p ratio vs cluster E within trackmatch Nsigma", HistType::kTH3F, {axisEp, axisE, axisModes}); + mHistManager.add("hEp_v_E_Nsigma_disp", "E/p ratio vs cluster E within trackmatch Nsigma | OK dispersion", HistType::kTH3F, {axisEp, axisE, axisModes}); + + mHistManager.add("hEp_v_pt_disp_TPC", "E/p ratio vs p | OK dispersion", HistType::kTH3F, {axisEp, axisPt, axisModes}); + mHistManager.add("hEp_v_pt_Nsigma_TPC", "E/p ratio vs p within trackmatch Nsigma", HistType::kTH3F, {axisEp, axisPt, axisModes}); + mHistManager.add("hEp_v_pt_Nsigma_disp_TPC", "E/p ratio vs p within trackmatch Nsigma | OK dispersion", HistType::kTH3F, {axisEp, axisPt, axisModes}); + + mHistManager.add("hEp_v_E_disp_TPC", "E/p ratio vs cluster E | OK dispersion", HistType::kTH3F, {axisEp, axisE, axisModes}); + mHistManager.add("hEp_v_E_Nsigma_TPC", "E/p ratio vs cluster E within trackmatch Nsigma", HistType::kTH3F, {axisEp, axisE, axisModes}); + mHistManager.add("hEp_v_E_Nsigma_disp_TPC", "E/p ratio vs cluster E within trackmatch Nsigma | OK dispersion", HistType::kTH3F, {axisEp, axisE, axisModes}); geomPHOS = std::make_unique("PHOS"); + fSigma_dz = new TF1("fSigma_dz", "[0]/(x+[1])^[2]+pol1(3)", 0.3, 10); + fSigma_dz->SetParameters(parametersSigmadZ.at(0), parametersSigmadZ.at(1), parametersSigmadZ.at(2), parametersSigmadZ.at(3), parametersSigmadZ.at(4)); + + fSigma_dx = new TF1("fSigma_dx", "[0]/x^[1]+[2]", 0.1, 10); + fSigma_dx->SetParameters(parametersSigmadX.at(0), parametersSigmadX.at(1), parametersSigmadX.at(2)); + + fMeandXPosMod1 = new TF1("funcMeandx_pos_mod1", "[0]/(x+[1])^[2]", 0.1, 10); + fMeandXNegMod1 = new TF1("funcMeandx_neg_mod1", "[0]/(x+[1])^[2]", 0.1, 10); + fMeandXPosMod2 = new TF1("funcMeandx_pos_mod2", "[0]/(x+[1])^[2]", 0.1, 10); + fMeandXNegMod2 = new TF1("funcMeandx_neg_mod2", "[0]/(x+[1])^[2]", 0.1, 10); + fMeandXPosMod3 = new TF1("funcMeandx_pos_mod3", "[0]/(x+[1])^[2]", 0.1, 10); + fMeandXNegMod3 = new TF1("funcMeandx_neg_mod3", "[0]/(x+[1])^[2]", 0.1, 10); + fMeandXPosMod4 = new TF1("funcMeandx_pos_mod4", "[0]/(x+[1])^[2]", 0.1, 10); + fMeandXNegMod4 = new TF1("funcMeandx_neg_mod4", "[0]/(x+[1])^[2]", 0.1, 10); + + fMeandXPosMod1->SetParameters(meandXPosMod1.at(0), meandXPosMod1.at(1), meandXPosMod1.at(2)); + fMeandXPosMod2->SetParameters(meandXPosMod2.at(0), meandXPosMod2.at(1), meandXPosMod2.at(2)); + fMeandXPosMod3->SetParameters(meandXPosMod3.at(0), meandXPosMod3.at(1), meandXPosMod3.at(2)); + fMeandXPosMod4->SetParameters(meandXPosMod4.at(0), meandXPosMod4.at(1), meandXPosMod4.at(2)); + + fMeandXNegMod1->SetParameters(meandXNegMod1.at(0), meandXNegMod1.at(1), meandXNegMod1.at(2)); + fMeandXNegMod2->SetParameters(meandXNegMod2.at(0), meandXNegMod2.at(1), meandXNegMod2.at(2)); + fMeandXNegMod3->SetParameters(meandXNegMod3.at(0), meandXNegMod3.at(1), meandXNegMod3.at(2)); + fMeandXNegMod4->SetParameters(meandXNegMod4.at(0), meandXNegMod4.at(1), meandXNegMod4.at(2)); } - void process(soa::Join::iterator const& collision, - aod::CaloClusters& clusters, - tracks& tracks, + void process(SelCollisions::iterator const& collision, + aod::CaloClusters const& clusters, + soa::Filtered const& tracks, aod::BCsWithTimestamps const&) { - mHistManager.fill(HIST("eventCounter"), 0.5); auto bc = collision.bc_as(); if (runNumber != bc.runNumber()) { LOG(info) << ">>>>>>>>>>>> Current run number: " << runNumber; @@ -127,19 +325,40 @@ struct phosElId { LOG(info) << ">>>>>>>>>>>> Magnetic field: " << bz; runNumber = bc.runNumber(); } + if (std::fabs(collision.posZ()) > 10.f) + return; + mHistManager.fill(HIST("eventCounter"), 0.5); + if (!collision.alias_bit(mEvSelTrig)) + return; + mHistManager.fill(HIST("TVXinPHOSCounter"), 0.5); if (clusters.size() == 0) return; // Nothing to process + mHistManager.fill(HIST("hColVX"), collision.posX()); + mHistManager.fill(HIST("hColVY"), collision.posY()); + mHistManager.fill(HIST("hColVZ"), collision.posZ()); for (auto const& track : tracks) { - if (!track.has_collision()) + + if (!track.has_collision() || std::fabs(track.dcaXY()) > cfgDCAxyMax || std::fabs(track.dcaZ()) > cfgDCAzMax || !track.hasTPC() || std::fabs(track.eta()) > 0.15) continue; - if (std::abs(track.collision_as().posZ()) > 10.f) + if (track.pt() < cfgPtMin || track.pt() > cfgPtMax) continue; - - // calculate coordinate in PHOS plane - if (std::abs(track.eta()) > 0.3) + if (track.itsChi2NCl() > cfgITSchi2Max) continue; + if (track.itsNCls() < cfgITSnclsMin || track.itsNCls() > cfgITSnclsMax || !((track.itsClusterMap() & uint8_t(1)) > 0)) + continue; + if (track.tpcChi2NCl() > cfgTPCchi2Max) + continue; + if (track.tpcNClsFound() < cfgTPCnclsMin || track.tpcNClsFound() > cfgTPCnclsMax) + continue; + if (track.tpcNClsCrossedRows() < cfgTPCnclsCRMin || track.tpcNClsCrossedRows() > cfgTPCnclsCRMax) + continue; + + mHistManager.fill(HIST("hTrackVX"), track.x()); + mHistManager.fill(HIST("hTrackVY"), track.y()); + mHistManager.fill(HIST("hTrackVZ"), track.z()); + int16_t module; float trackX = 999., trackZ = 999.; @@ -148,31 +367,133 @@ struct phosElId { continue; float trackMom = track.p(); - for (const auto& clu : clusters) { - if (clu.e() < mMinE) - continue; + float trackPT = track.pt(); + + bool isElectron = false; + if (track.hasTPC()) { + float nsigmaTPCEl = track.tpcNSigmaEl(); + float nsigmaTOFEl = track.tofNSigmaEl(); + bool isTPCElectron = nsigmaTPCEl > cfgTPCNSigmaElMin && nsigmaTPCEl < cfgTPCNSigmaElMax; + bool isTOFElectron = nsigmaTOFEl > cfgTOFNSigmaElMin && nsigmaTOFEl < cfgTOFNSigmaElMax; + isElectron = isTPCElectron || isTOFElectron; + + float nsigmaTPCPi = track.tpcNSigmaPi(); + float nsigmaTPCKa = track.tpcNSigmaKa(); + float nsigmaTPCPr = track.tpcNSigmaPr(); + bool isPion = nsigmaTPCPi > cfgTPCNSigmaPiMin && nsigmaTPCPi < cfgTPCNSigmaPiMax; + bool isKaon = nsigmaTPCKa > cfgTPCNSigmaKaMin && nsigmaTPCKa < cfgTPCNSigmaKaMax; + bool isProton = nsigmaTPCPr > cfgTPCNSigmaPrMin && nsigmaTPCPr < cfgTPCNSigmaPrMax; + if (isElectron && !(isPion || isKaon || isProton)) + isElectron = true; + } + + bool posTrack = track.sign() * bz > 0; + for (auto const& clu : clusters) { if (module != clu.mod()) continue; - bool isDispOK = testLambda(clu.e(), clu.m02(), clu.m20()); - float posX = clu.x(), posZ = clu.z(), dX = trackX - posX, dZ = trackZ - posZ; - - if (track.sign() > 0) - mHistManager.fill(HIST("hDeltaXPos_v_p"), dX, trackMom); - else - mHistManager.fill(HIST("hDeltaXNeg_v_p"), dX, trackMom); - mHistManager.fill(HIST("hDeltaZ_v_p"), dZ, trackMom); - mHistManager.fill(HIST("hEp_v_p"), clu.e() / trackMom, trackMom); - mHistManager.fill(HIST("hdZpmod"), dZ, trackMom, module); - mHistManager.fill(HIST("hdXpmod"), dX, trackMom, module); - if (track.sign() > 0) - mHistManager.fill(HIST("hdXpmod_pos"), dX, trackMom, module); - else - mHistManager.fill(HIST("hdXpmod_neg"), dX, trackMom, module); - - if (isDispOK) - mHistManager.fill(HIST("hEp_v_p_disp"), clu.e() / trackMom, trackMom); + double cluE = clu.e(); + + if (cluE < mMinCluE || + clu.ncell() < mMinCluNcell || + clu.time() > mMaxCluTime || clu.time() < mMinCluTime) + continue; + + bool isDispOK = testLambda(cluE, clu.m02(), clu.m20()); + float posX = clu.x(), posZ = clu.z(), dX = trackX - posX, dZ = trackZ - posZ, Ep = cluE / trackMom; + + mHistManager.fill(HIST("hdZpmod"), dZ, trackPT, module); + mHistManager.fill(HIST("hdXpmod"), dX, trackPT, module); + if (posTrack) { + mHistManager.fill(HIST("hdZpmod_pos"), dZ, trackPT, module); + mHistManager.fill(HIST("hdXpmod_pos"), dX, trackPT, module); + } else { + mHistManager.fill(HIST("hdZpmod_neg"), dZ, trackPT, module); + mHistManager.fill(HIST("hdXpmod_neg"), dX, trackPT, module); + } + + if (isDispOK) { + mHistManager.fill(HIST("hCluE_v_pt_disp"), cluE, trackPT, module); + mHistManager.fill(HIST("hEp_v_pt_disp"), Ep, trackPT, module); + mHistManager.fill(HIST("hEp_v_E_disp"), Ep, cluE, module); + if (isElectron) { + mHistManager.fill(HIST("hCluE_v_pt_disp_TPC"), cluE, trackPT, module); + mHistManager.fill(HIST("hEp_v_pt_disp_TPC"), Ep, trackPT, module); + mHistManager.fill(HIST("hEp_v_E_disp_TPC"), Ep, cluE, module); + } + } + if (!isWithinNSigma(module, trackPT, dZ, dX)) + continue; + mHistManager.fill(HIST("hCluE_v_pt_Nsigma"), cluE, trackPT, module); + mHistManager.fill(HIST("hEp_v_pt_Nsigma"), Ep, trackPT, module); + mHistManager.fill(HIST("hEp_v_E_Nsigma"), Ep, cluE, module); + if (isElectron) { + mHistManager.fill(HIST("hCluE_v_pt_Nsigma_TPC"), cluE, trackPT, module); + mHistManager.fill(HIST("hEp_v_pt_Nsigma_TPC"), Ep, trackPT, module); + mHistManager.fill(HIST("hEp_v_E_Nsigma_TPC"), Ep, cluE, module); + } + if (isDispOK) { + mHistManager.fill(HIST("hCluE_v_pt_Nsigma_disp"), cluE, trackPT, module); + mHistManager.fill(HIST("hEp_v_pt_Nsigma_disp"), Ep, trackPT, module); + mHistManager.fill(HIST("hEp_v_E_Nsigma_disp"), Ep, cluE, module); + if (isElectron) { + mHistManager.fill(HIST("hCluE_v_pt_Nsigma_disp_TPC"), cluE, trackPT, module); + mHistManager.fill(HIST("hEp_v_pt_Nsigma_disp_TPC"), Ep, trackPT, module); + mHistManager.fill(HIST("hEp_v_E_Nsigma_disp_TPC"), Ep, cluE, module); + } + phosMatch(collision.index(), clu.index(), track.index()); + } + } + + mHistManager.fill(HIST("hTrackPtEtaPhi"), track.pt(), track.eta(), track.phi() * TMath::RadToDeg()); + mHistManager.fill(HIST("hTrackPtEtaPhi_Phos"), track.pt(), track.trackEtaEmcal(), track.trackPhiEmcal() * TMath::RadToDeg()); + mHistManager.fill(HIST("hTrackDCA"), track.dcaXY(), track.dcaZ()); + mHistManager.fill(HIST("hTrackPhosProjMod"), trackX, trackZ, module); + } // end of double loop + + for (auto const& clu : clusters) { + double cluE = clu.e(), cluTime = clu.time(); + int mod = clu.mod(); + if (cluE > mMinCluE) { + mHistManager.fill(HIST("hCluE_mod_energy_cut"), cluE, mod); + mHistManager.fill(HIST("hCluE_v_mod_v_time"), cluE, cluTime * 1e9, mod); + if (cluTime < mMaxCluTime && cluTime > mMinCluTime) { + mHistManager.fill(HIST("hCluE_mod_time_cut"), cluE, mod); + if (clu.ncell() >= mMinCluNcell) { + mHistManager.fill(HIST("hCluE_mod_cell_cut"), cluE, mod); + mHistManager.fill(HIST("hCluXZ_mod"), clu.x(), clu.z(), mod); + mHistManager.fill(HIST("hCluE_ncells_mod"), cluE, clu.ncell(), mod); + if (testLambda(cluE, clu.m02(), clu.m20())) + mHistManager.fill(HIST("hCluE_mod_disp"), cluE, mod); + } + } } + } // end of cluster loop + } + + bool isWithinNSigma(int16_t& mod, float p, float deltaZ, float deltaX) + { + if (mod == 1) { + if (std::fabs(deltaZ - PhosShiftZ[0]) > cfgNsigmaTrackMatch * fSigma_dz->Eval(p)) + return false; + if (std::fabs(deltaX - fMeandXPosMod1->Eval(p) + PhosShiftX[0]) > cfgNsigmaTrackMatch * fSigma_dx->Eval(p)) + return false; + } else if (mod == 2) { + if (std::fabs(deltaZ - PhosShiftZ[1]) > cfgNsigmaTrackMatch * fSigma_dz->Eval(p)) + return false; + if (std::fabs(deltaX - fMeandXPosMod2->Eval(p) + PhosShiftX[1]) > cfgNsigmaTrackMatch * fSigma_dx->Eval(p)) + return false; + } else if (mod == 3) { + if (std::fabs(deltaZ - PhosShiftZ[2]) > cfgNsigmaTrackMatch * fSigma_dz->Eval(p)) + return false; + if (std::fabs(deltaX - fMeandXPosMod3->Eval(p) + PhosShiftX[2]) > cfgNsigmaTrackMatch * fSigma_dx->Eval(p)) + return false; + } else if (mod == 4) { + if (std::fabs(deltaZ - PhosShiftZ[3]) > cfgNsigmaTrackMatch * fSigma_dz->Eval(p)) + return false; + if (std::fabs(deltaX - fMeandXPosMod4->Eval(p) + PhosShiftX[3]) > cfgNsigmaTrackMatch * fSigma_dx->Eval(p)) + return false; } + return true; } /////////////////////////////////////////////////////////////////////// @@ -184,17 +505,10 @@ struct phosElId { const float phiMin = 240. * 0.017453293; // degToRad const float phiMax = 323. * 0.017453293; // PHOS+20 cm * degToRad const float etaMax = 0.178266; - if (trackPhi < phiMin || trackPhi > phiMax || abs(trackEta) > etaMax) { + if (trackPhi < phiMin || trackPhi > phiMax || std::abs(trackEta) > etaMax) { return false; } - const float dphi = 20. * 0.017453293; - if (trackPhi < 0.) { - trackPhi += TMath::TwoPi(); - } - if (trackPhi > TMath::TwoPi()) { - trackPhi -= TMath::TwoPi(); - } module = 1 + static_cast((trackPhi - phiMin) / dphi); if (module < 1) { module = 1; @@ -204,11 +518,11 @@ struct phosElId { } // get PHOS radius - constexpr float shiftY = -1.26; // Depth-optimized - double posL[3] = {0., 0., shiftY}; // local position at the center of module + constexpr float ShiftY = -1.26; // Depth-optimized + double posL[3] = {0., 0., ShiftY}; // local position at the center of module double posG[3] = {0}; geomPHOS->getAlignmentMatrix(module)->LocalToMaster(posL, posG); - double rPHOS = sqrt(posG[0] * posG[0] + posG[1] * posG[1]); + double rPHOS = std::sqrt(posG[0] * posG[0] + posG[1] * posG[1]); double alpha = (230. + 20. * module) * 0.017453293; // During main reconstruction track was propagated to radius 460 cm with accounting material @@ -233,7 +547,7 @@ struct phosElId { return false; } alpha = trackPar.getAlpha(); - double ca = cos(alpha), sa = sin(alpha); + double ca = std::cos(alpha), sa = std::sin(alpha); posG[0] = trackPar.getX() * ca - trackPar.getY() * sa; posG[1] = trackPar.getY() * ca + trackPar.getX() * sa; posG[2] = trackPar.getZ(); @@ -247,12 +561,718 @@ struct phosElId { bool testLambda(float pt, float l1, float l2) { // Parameterization for full dispersion - // Parameterizatino for full dispersion float l2Mean = 1.53126 + 9.50835e+06 / (1. + 1.08728e+07 * pt + 1.73420e+06 * pt * pt); - float l1Mean = 1.12365 + 0.123770 * TMath::Exp(-pt * 0.246551) + 5.30000e-03 * pt; + float l1Mean = 1.12365 + 0.123770 * std::exp(-pt * 0.246551) + 5.30000e-03 * pt; + float l2Sigma = 6.48260e-02 + 7.60261e+10 / (1. + 1.53012e+11 * pt + 5.01265e+05 * pt * pt) + 9.00000e-03 * pt; + float l1Sigma = 4.44719e-04 + 6.99839e-01 / (1. + 1.22497e+00 * pt + 6.78604e-07 * pt * pt) + 9.00000e-03 * pt; + float c = -0.35 - 0.550 * std::exp(-0.390730 * pt); + + return 0.5 * (l1 - l1Mean) * (l1 - l1Mean) / l1Sigma / l1Sigma + + 0.5 * (l2 - l2Mean) * (l2 - l2Mean) / l2Sigma / l2Sigma + + 0.5 * c * (l1 - l1Mean) * (l2 - l2Mean) / l1Sigma / l2Sigma < + 4.; + } +}; + +struct MassSpectra { + + using SelCollisions = soa::Join; + using MyTracks = soa::Join; + Configurable mEvSelTrig{"mEvSelTrig", kTVXinPHOS, "Select events with this trigger"}, + cfgMassBinning{"cfgMassBinning", 1000, "Binning for mass"}, + cfgEnergyBinning{"cfgEnergyBinning", 100, "Binning for energy"}, + cfgEpRatioBinning{"cfgEpRatioBinning", 200, "Binning for energy to momentum ratio"}, + cfgCentBinning{"cfgCentBinning", 10, "Binning for centrality"}, + cfgCentEst{"cfgCentEst", 1, "Centrality estimator, 0: FV0A, 1: FT0M, 2: FT0A, 3: FT0C, 4: FDDM, 5: NTPV"}; + + Configurable cfgEtaMax{"cfgEtaMax", {0.8f}, "eta ranges"}, + cfgPtMin{"cfgPtMin", {0.2f}, "pt min"}, + cfgPtMax{"cfgPtMax", {20.f}, "pt max"}, + cfgMassSpectraMin{"cfgMassSpectraMin", {2.5f}, "mass spectra min for e+e-"}, + cfgMassSpectraMax{"cfgMassSpectraMax", {3.5f}, "mass spcetra max for e+e-"}, + cfgDCAxyMax{"cfgDCAxyMax", {3.f}, "dcaxy max"}, + cfgDCAzMax{"cfgDCAzMax", {3.f}, "dcaz max"}, + cfgITSchi2Max{"cfgITSchi2Max", {5.f}, "its chi2 max"}, + cfgITSnclsMin{"cfgITSnclsMin", {4.5f}, "min number of ITS clusters"}, + cfgITSnclsMax{"cfgITSnclsMax", {7.5f}, "max number of ITS clusters"}, + cfgTPCchi2Max{"cfgTPCchi2Max", {4.f}, "tpc chi2 max"}, + cfgTPCnclsMin{"cfgTPCnclsMin", {90.f}, "min number of TPC clusters"}, + cfgTPCnclsMax{"cfgTPCnclsMax", {170.f}, "max number of TPC clusters"}, + cfgTPCnclsCRMin{"cfgTPCnclsCRMin", {80.f}, "min number of TPC crossed rows"}, + cfgTPCnclsCRMax{"cfgTPCnclsCRMax", {161.f}, "max number of TPC crossed rows"}, + cfgTPCNSigmaElMin{"cfgTPCNSigmaElMin", {-3.f}, "min TPC nsigma e for inclusion"}, + cfgTPCNSigmaElMax{"cfgTPCNSigmaElMax", {2.f}, "max TPC nsigma e for inclusion"}, + cfgTPCNSigmaPiMin{"cfgTPCNSigmaPiMin", {-3.f}, "min TPC nsigma pion for exclusion"}, + cfgTPCNSigmaPiMax{"cfgTPCNSigmaPiMax", {3.5f}, "max TPC nsigma pion for exclusion"}, + cfgTPCNSigmaPrMin{"cfgTPCNSigmaPrMin", {-3.f}, "min TPC nsigma proton for exclusion"}, + cfgTPCNSigmaPrMax{"cfgTPCNSigmaPrMax", {4.f}, "max TPC nsigma proton for exclusion"}, + cfgTPCNSigmaKaMin{"cfgTPCNSigmaKaMin", {-3.f}, "min TPC nsigma kaon for exclusion"}, + cfgTPCNSigmaKaMax{"cfgTPCNSigmaKaMax", {4.f}, "max TPC nsigma kaon for exclusion"}, + cfgTOFNSigmaElMin{"cfgTOFNSigmaElMin", {-3.f}, "min TOF nsigma e for inclusion"}, + cfgTOFNSigmaElMax{"cfgTOFNSigmaElMax", {3.f}, "max TOF nsigma e for inclusion"}, + cfgShiftEp{"cfgShiftEp", {0.055f}, "PHOS E/p shift for electrons"}, + cfgNsigmaEp{"cfgNsigmaEp", {2.f}, "PHOS E/p nsigma for inclusion"}; + + Configurable> cfgEpSigmaPars{"cfgEpSigmaPars", {1.3e-02, 1.9e-02, 1.1e-02, 3.e-02}, "E/p sigma function parameters (from alice 3 mc tests + const)"}; + + Service ccdb; + std::unique_ptr geomPHOS; + double bz{0.}; // magnetic field + int runNumber{0}; + + HistogramRegistry mHistManager{"MassSpectraHistograms"}; + TF1* fEpSigmaPhos; + + void init(InitContext const&) + { + LOG(info) << "Initializing PHOS electron identification analysis task ..."; + + std::vector momentumBinning = {0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, + 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 10.}; + const AxisSpec axisCounter{1, 0, +1, ""}, + axisCent{cfgCentBinning, 0, 100, "centrality percentage"}, + axisPt{momentumBinning, "p_{T} (GeV/c)"}, + axisEp{cfgEpRatioBinning, 0., 2., "E/p", "E_{cluster}/p_{track}"}, + axisE{cfgEnergyBinning, 0, 10, "E (GeV)", "E (GeV)"}, + axisMassSpectrum{cfgMassBinning, cfgMassSpectraMin, cfgMassSpectraMax, "M (GeV/c^{2})", "Mass e^{+}e^{-} (GeV/c^{2})"}; + + mHistManager.add("eventCounter", "eventCounter", kTH1F, {axisCounter}); + mHistManager.add("TVXinPHOSCounter", "TVXinPHOSCounter", kTH1F, {axisCounter}); + + mHistManager.add("h_eh_pp_mass_spectra_v_pt_v_cent", "Mass e^{+}h^{+} vs momentum e^{+}h^{+}", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add("h_ee_pp_mass_spectra_v_pt_v_cent", "Mass e^{+}e^{+} vs momentum e^{+}e^{+}", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add("h_eh_mm_mass_spectra_v_pt_v_cent", "Mass e^{-}h^{-} vs momentum e^{-}h^{-}", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add("h_ee_mm_mass_spectra_v_pt_v_cent", "Mass e^{-}e^{-} vs momentum e^{-}e^{-}", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + + mHistManager.add("h_eh_pp_mass_spectra_v_E_v_cent", "Mass e^{+}h^{+} vs cluster E e^{+}h^{+}", HistType::kTH3F, {axisMassSpectrum, axisE, axisCent}); + mHistManager.add("h_ee_pp_mass_spectra_v_E_v_cent", "Mass e^{+}e^{+} vs cluster E e^{+}e^{+}", HistType::kTH3F, {axisMassSpectrum, axisE, axisCent}); + mHistManager.add("h_eh_mm_mass_spectra_v_E_v_cent", "Mass e^{-}h^{-} vs cluster E e^{-}h^{-}", HistType::kTH3F, {axisMassSpectrum, axisE, axisCent}); + mHistManager.add("h_ee_mm_mass_spectra_v_E_v_cent", "Mass e^{-}e^{-} vs cluster E e^{-}e^{-}", HistType::kTH3F, {axisMassSpectrum, axisE, axisCent}); + + mHistManager.add("h_eh_mp_mass_spectra_v_pt_v_cent", "Mass e^{#pm}h^{#mp} vs momentum e^{#pm}h^{#mp}", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add("h_ee_mp_mass_spectra_v_pt_v_cent", "Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp}", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add("h_eh_mp_mass_spectra_v_E_v_cent", "Mass e^{#pm}h^{#mp} vs cluster E e^{#pm}h^{#mp}", HistType::kTH3F, {axisMassSpectrum, axisE, axisCent}); + mHistManager.add("h_ee_mp_mass_spectra_v_E_v_cent", "Mass e^{#pm}e^{#mp} vs cluster E e^{#pm}e^{#mp}", HistType::kTH3F, {axisMassSpectrum, axisE, axisCent}); + + mHistManager.add("hEp_v_E_v_cent", "E/p ratio vs cluster E", HistType::kTH3F, {axisEp, axisE, axisCent}); + mHistManager.add("hEp_v_E_v_cent_cutEp", "E/p ratio vs cluster E within nSigma corridor", HistType::kTH3F, {axisEp, axisE, axisCent}); + + geomPHOS = std::make_unique("PHOS"); + + std::vector epSigmaPars = cfgEpSigmaPars; + fEpSigmaPhos = new TF1("fEpSigmaPhos", "sqrt([0]*[0]/x/x+[1]*[1]/x+[2]*[2])+[3]", 0.01, 10); + fEpSigmaPhos->SetParameters(epSigmaPars.at(0), epSigmaPars.at(1), epSigmaPars.at(2), epSigmaPars.at(3)); + } + + void process(SelCollisions::iterator const& collision, + aod::CaloClusters const& clusters, + MyTracks const& tracks, + o2::aod::PHOSMatchindexTable const& matches, + aod::BCsWithTimestamps const&) + { + auto bc = collision.bc_as(); + if (runNumber != bc.runNumber()) { + LOG(info) << ">>>>>>>>>>>> Current run number: " << runNumber; + o2::parameters::GRPMagField* grpo = ccdb->getForTimeStamp("GLO/Config/GRPMagField", bc.timestamp()); + if (grpo == nullptr) { + LOGF(fatal, "Run 3 GRP object (type o2::parameters::GRPMagField) is not available in CCDB for run=%d at timestamp=%llu", bc.runNumber(), bc.timestamp()); + } + o2::base::Propagator::initFieldFromGRP(grpo); + bz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << ">>>>>>>>>>>> Magnetic field: " << bz; + runNumber = bc.runNumber(); + } + if (std::fabs(collision.posZ()) > 10.f) + return; + mHistManager.fill(HIST("eventCounter"), 0.5); + if (!collision.alias_bit(mEvSelTrig)) + return; + mHistManager.fill(HIST("TVXinPHOSCounter"), 0.5); + + if (clusters.size() == 0) + return; // Nothing to process + + float cent = -1.; + switch (cfgCentEst) { + case FV0A: + cent = collision.centFV0A(); + break; + case FT0M: + cent = collision.centFT0M(); + break; + case FT0A: + cent = collision.centFT0A(); + break; + case FT0C: + cent = collision.centFT0C(); + break; + case FDDM: + cent = collision.centFDDM(); + break; + case NTPV: + cent = collision.centNTPV(); + break; + } + + for (auto const& TPCel : tracks) { + + if (!TPCel.has_collision() || std::fabs(TPCel.dcaXY()) > cfgDCAxyMax || std::fabs(TPCel.dcaZ()) > cfgDCAzMax || !TPCel.hasTPC() || std::fabs(TPCel.eta()) > 0.15) + continue; + if (TPCel.pt() < cfgPtMin || TPCel.pt() > cfgPtMax) + continue; + if (TPCel.itsChi2NCl() > cfgITSchi2Max) + continue; + if (TPCel.itsNCls() < cfgITSnclsMin || TPCel.itsNCls() > cfgITSnclsMax || !((TPCel.itsClusterMap() & uint8_t(1)) > 0)) + continue; + if (TPCel.tpcChi2NCl() > cfgTPCchi2Max) + continue; + if (TPCel.tpcNClsFound() < cfgTPCnclsMin || TPCel.tpcNClsFound() > cfgTPCnclsMax) + continue; + if (TPCel.tpcNClsCrossedRows() < cfgTPCnclsCRMin || TPCel.tpcNClsCrossedRows() > cfgTPCnclsCRMax) + continue; + + bool isElectron = false; + float nsigmaTPCEl = TPCel.tpcNSigmaEl(); + float nsigmaTOFEl = TPCel.tofNSigmaEl(); + bool isTPCElectron = nsigmaTPCEl > cfgTPCNSigmaElMin && nsigmaTPCEl < cfgTPCNSigmaElMax; + bool isTOFElectron = nsigmaTOFEl > cfgTOFNSigmaElMin && nsigmaTOFEl < cfgTOFNSigmaElMax; + isElectron = isTPCElectron || isTOFElectron; + + float nsigmaTPCPi = TPCel.tpcNSigmaPi(); + float nsigmaTPCKa = TPCel.tpcNSigmaKa(); + float nsigmaTPCPr = TPCel.tpcNSigmaPr(); + bool isPion = nsigmaTPCPi > cfgTPCNSigmaPiMin && nsigmaTPCPi < cfgTPCNSigmaPiMax; + bool isKaon = nsigmaTPCKa > cfgTPCNSigmaKaMin && nsigmaTPCKa < cfgTPCNSigmaKaMax; + bool isProton = nsigmaTPCPr > cfgTPCNSigmaPrMin && nsigmaTPCPr < cfgTPCNSigmaPrMax; + if (isElectron && !(isPion || isKaon || isProton)) + isElectron = true; + if (!isElectron) + continue; + bool posTrack = TPCel.sign() * bz > 0; + + for (auto const& match : matches) { + auto clust2 = clusters.iteratorAt(match.caloClusterId()); + auto track2 = tracks.iteratorAt(match.trackId()); + + if (TPCel.collisionId() != track2.collisionId()) + continue; + if (TPCel.index() >= track2.index()) + break; + + float mass2Tracks = 0, mom2Tracks = 0, cluE = clust2.e(); + TLorentzVector fourVectorP1, fourVectorP2; + fourVectorP1.SetPxPyPzE(TPCel.px(), TPCel.py(), TPCel.pz(), TPCel.energy(0)); + fourVectorP2.SetPxPyPzE(track2.px(), track2.py(), track2.pz(), track2.energy(0)); + mom2Tracks = (fourVectorP1 + fourVectorP2).Pt(); + mass2Tracks = (fourVectorP1 + fourVectorP2).M(); + bool elCandidate = (std::fabs(cluE / track2.p() - cfgShiftEp - 1) < cfgNsigmaEp * fEpSigmaPhos->Eval(cluE)); + + if (TPCel.sign() == track2.sign()) { + if (posTrack) { + mHistManager.fill(HIST("h_eh_pp_mass_spectra_v_pt_v_cent"), mass2Tracks, mom2Tracks, cent); + mHistManager.fill(HIST("h_eh_pp_mass_spectra_v_E_v_cent"), mass2Tracks, cluE, cent); + if (elCandidate) { + mHistManager.fill(HIST("h_ee_pp_mass_spectra_v_pt_v_cent"), mass2Tracks, mom2Tracks, cent); + mHistManager.fill(HIST("h_ee_pp_mass_spectra_v_E_v_cent"), mass2Tracks, cluE, cent); + } + } else { + mHistManager.fill(HIST("h_eh_mm_mass_spectra_v_pt_v_cent"), mass2Tracks, mom2Tracks, cent); + mHistManager.fill(HIST("h_eh_mm_mass_spectra_v_E_v_cent"), mass2Tracks, cluE, cent); + if (elCandidate) { + mHistManager.fill(HIST("h_ee_mm_mass_spectra_v_pt_v_cent"), mass2Tracks, mom2Tracks, cent); + mHistManager.fill(HIST("h_ee_mm_mass_spectra_v_E_v_cent"), mass2Tracks, cluE, cent); + } + } + } else { + mHistManager.fill(HIST("h_eh_mp_mass_spectra_v_pt_v_cent"), mass2Tracks, mom2Tracks, cent); + mHistManager.fill(HIST("h_eh_mp_mass_spectra_v_E_v_cent"), mass2Tracks, cluE, cent); + if (elCandidate) { + mHistManager.fill(HIST("h_ee_mp_mass_spectra_v_pt_v_cent"), mass2Tracks, mom2Tracks, cent); + mHistManager.fill(HIST("h_ee_mp_mass_spectra_v_E_v_cent"), mass2Tracks, cluE, cent); + } + } + } + } // end of double loop + + for (auto const& match : matches) { + auto clust = clusters.iteratorAt(match.caloClusterId()); + auto track = tracks.iteratorAt(match.trackId()); + float cluE = clust.e(); + float epRatio = cluE / track.p(); + mHistManager.fill(HIST("hEp_v_E_v_cent"), epRatio, cluE, cent); + bool elCandidate = (std::fabs(epRatio - cfgShiftEp - 1) < cfgNsigmaEp * fEpSigmaPhos->Eval(cluE)); + if (elCandidate) + mHistManager.fill(HIST("hEp_v_E_v_cent_cutEp"), epRatio, cluE, cent); + } + } +}; + +struct TpcElIdMassSpectrum { + + using SelCollisions = soa::Join; + using MyTracks = soa::Join; + Configurable mMinCluE{"mMinCluE", 0.1, "Minimum cluster energy for photons in the analysis"}, + mCutMIPCluE{"mCutMIPCluE", 0.3, "Min cluster energy to reject MIPs in the analysis"}, + mMaxCluE{"mMaxCluE", 1., "Maximum cluster energy for photons in the analysis"}, + mMinCluTime{"minCluTime", -25.e-9, "Min. cluster time"}, + mMaxCluTime{"mMaxCluTime", 25.e-9, "Max. cluster time"}, + cfgEtaMax{"cfgEtaMax", {0.8f}, "eta ranges"}, + cfgPtMin{"cfgPtMin", {0.2f}, "pt min"}, + cfgPtMax{"cfgPtMax", {20.f}, "pt max"}, + cfgMassSpectraJpsiMin{"cfgMassSpectraJpsiMin", {2.5f}, "mass spectra min for Jpsi region"}, + cfgMassSpectraJpsiMax{"cfgMassSpectraJpsiMax", {3.5f}, "mass spcetra max for Jpsi region"}, + cfgMassSpectraChicMin{"cfgMassSpectraChicMin", {3.f}, "mass spectra min Chic region"}, + cfgMassSpectraChicMax{"cfgMassSpectraChicMax", {4.f}, "mass spcetra max Chic region"}, + cfgDCAxyMax{"cfgDCAxyMax", {3.f}, "dcaxy max"}, + cfgDCAzMax{"cfgDCAzMax", {3.f}, "dcaz max"}, + cfgITSchi2Max{"cfgITSchi2Max", {5.f}, "its chi2 max"}, + cfgITSnclsMin{"cfgITSnclsMin", {4.5f}, "min number of ITS clusters"}, + cfgITSnclsMax{"cfgITSnclsMax", {7.5f}, "max number of ITS clusters"}, + cfgTPCchi2Max{"cfgTPCchi2Max", {4.f}, "tpc chi2 max"}, + cfgTPCnclsMin{"cfgTPCnclsMin", {90.f}, "min number of TPC clusters"}, + cfgTPCnclsMax{"cfgTPCnclsMax", {170.f}, "max number of TPC clusters"}, + cfgTPCnclsCRMin{"cfgTPCnclsCRMin", {80.f}, "min number of TPC crossed rows"}, + cfgTPCnclsCRMax{"cfgTPCnclsCRMax", {161.f}, "max number of TPC crossed rows"}, + cfgTPCNSigmaElMin{"cfgTPCNSigmaElMin", {-3.f}, "min TPC nsigma e for inclusion"}, + cfgTPCNSigmaElMax{"cfgTPCNSigmaElMax", {2.f}, "max TPC nsigma e for inclusion"}, + cfgTPCNSigmaPiMin{"cfgTPCNSigmaPiMin", {-3.f}, "min TPC nsigma pion for exclusion"}, + cfgTPCNSigmaPiMax{"cfgTPCNSigmaPiMax", {3.5f}, "max TPC nsigma pion for exclusion"}, + cfgTPCNSigmaPrMin{"cfgTPCNSigmaPrMin", {-3.f}, "min TPC nsigma proton for exclusion"}, + cfgTPCNSigmaPrMax{"cfgTPCNSigmaPrMax", {4.f}, "max TPC nsigma proton for exclusion"}, + cfgTPCNSigmaKaMin{"cfgTPCNSigmaKaMin", {-3.f}, "min TPC nsigma kaon for exclusion"}, + cfgTPCNSigmaKaMax{"cfgTPCNSigmaKaMax", {4.f}, "max TPC nsigma kaon for exclusion"}, + cfgTOFNSigmaElMin{"cfgTOFNSigmaElMin", {-3.f}, "min TOF nsigma e for inclusion"}, + cfgTOFNSigmaElMax{"cfgTOFNSigmaElMax", {3.f}, "max TOF nsigma e for inclusion"}, + cfgPhosRangeEta{"cfgPhosRangeEta", {0.12f}, "Phos range definition plus minus eta"}, + cfgPhosRangePhiMin{"cfgPhosRangePhiMin", {230.f}, "Phos range angle phi min"}, + cfgPhosRangePhiMax{"cfgPhosRangePhiMax", {330.f}, "Phos range angle phi max"}, + cfgeeMassMin{"cfgeeMassMin", {2.9f}, "J/psi(e+e-) Mass corridor lower limit"}, + cfgeeMassMax{"cfgeeMassMax", {3.3f}, "J/psi(e+e-) Mass corridor upper limit"}, + cfgJpsiMass{"cfgJpsiMass", {3.097f}, "J/psi Mass constant"}; + + Configurable mEvSelTrig{"mEvSelTrig", kTVXinPHOS, "Select events with this trigger"}, + cfgCentBinning{"cfgCentBinning", 10, "Binning for centrality"}, + cfgCentEst{"cfgCentEst", 1, "Centrality estimator, 0: FV0A, 1: FT0M, 2: FT0A, 3: FT0C, 4: FDDM, 5: NTPV"}, + cfgMassBinning{"cfgMassBinning", 1000, "Binning for mass"}, + cfgEnergyBinning{"cfgEnergyBinning", 100, "Binning for energy"}, + mMinCluNcell{"minCluNcell", 3, "min cells in cluster"}; + + Filter ptFilter = (aod::track::pt > cfgPtMin) && (aod::track::pt < cfgPtMax), + etaFilter = nabs(aod::track::eta) < cfgEtaMax, + dcaxyFilter = nabs(aod::track::dcaXY) < cfgDCAxyMax, + dcazFilter = nabs(aod::track::dcaZ) < cfgDCAzMax; + + Filter tpctofEl = ((aod::pidtpc::tpcNSigmaEl > cfgTPCNSigmaElMin) && (aod::pidtpc::tpcNSigmaEl < cfgTPCNSigmaElMax)) || + ((aod::pidtof::tofNSigmaEl > cfgTOFNSigmaElMin) && (aod::pidtof::tofNSigmaEl < cfgTOFNSigmaElMax)), + tpcPiRej = (aod::pidtpc::tpcNSigmaPi < cfgTPCNSigmaPiMin) || (aod::pidtpc::tpcNSigmaPi > cfgTPCNSigmaPiMax), + tpcKaRej = (aod::pidtpc::tpcNSigmaKa < cfgTPCNSigmaKaMin) || (aod::pidtpc::tpcNSigmaKa > cfgTPCNSigmaPrMax), + tpcPrRej = (aod::pidtpc::tpcNSigmaPr < cfgTPCNSigmaPrMin) || (aod::pidtpc::tpcNSigmaPr > cfgTPCNSigmaPrMax); + + Service ccdb; + double bz{0.}; // magnetic field + int runNumber{0}; + + HistogramRegistry mHistManager{"tpcElIdHistograms"}; + + void init(InitContext const&) + { + LOG(info) << "Initializing ee mass spectrum via TPC electron identification analysis task ..."; + + std::vector momentumBinning = {0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, + 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 10.}; + const AxisSpec axisCounter{1, 0, +1, ""}, + axisCent{cfgCentBinning, 0, 100, "centrality percentage"}, + axisVTrackX{400, -5., 5., "track vertex x (cm)", "track vertex x (cm)"}, + axisVTrackY{400, -5., 5., "track vertex y (cm)", "track vertex y (cm)"}, + axisVTrackZ{400, -20., 20., "track vertex z (cm)", "track vertex z (cm)"}, + axisE{cfgEnergyBinning, 0, 10, "E (GeV)", "E (GeV)"}, + axisMassSpectrum{cfgMassBinning, cfgMassSpectraJpsiMin, cfgMassSpectraJpsiMax, "M (GeV/c^{2})", "Mass e^{+}e^{-} (GeV/c^{2})"}, + axisMassSpectrumChiC{cfgMassBinning, cfgMassSpectraChicMin, cfgMassSpectraChicMax, "M (GeV/c^{2})", "Mass e^{+}e^{-}#gamma (GeV/c^{2})"}, + axisMassSpectrumChiCNoJpsiErrors{cfgMassBinning, cfgMassSpectraChicMin, cfgMassSpectraChicMax, "M (GeV/c^{2})", "Mass e^{+}e^{-}#gamma - Mass e^{+}e^{-} + Mass J/#psi (GeV/c^{2})"}, + axisTPC{1000, 0, 200, "TPC signal (dE/dx)"}, + axisPt{momentumBinning, "p_{T} (GeV/c)"}, + axisPtBig{2000, 0, 20, "p_{T} (GeV/c)"}, + axisEta{600, -3., 3., "#eta"}; + + mHistManager.add("eventCounter", "eventCounter", kTH1F, {axisCounter}); + mHistManager.add("hTPCspectra", "TPC dE/dx spectra", HistType::kTH2F, {axisPt, axisTPC}); + mHistManager.add("hTPCspectra_isElectronRej", "isElectron with rejection | TPC dE/dx spectra", HistType::kTH2F, {axisPt, axisTPC}); + + mHistManager.add("h_TPCee_MS_mp_v_pt_v_cent", "Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp} (from TPC candidates)", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add("h_TPCee_MS_mm_v_pt_v_cent", "Mass e^{-}e^{-} vs momentum e^{-}e^{-} (from TPC candidates)", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add("h_TPCee_MS_pp_v_pt_v_cent", "Mass e^{+}e^{+} vs momentum e^{+}e^{+} (from TPC candidates)", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + + mHistManager.add("h_TPCee_MS_mp_phosRange_v_pt_v_cent", "Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp} (from TPC candidates) with one e in phos acceptance range", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add("h_TPCee_MS_mm_phosRange_v_pt_v_cent", "Mass e^{-}e^{-} vs momentum e^{-}e^{-} (from TPC candidates) with one e in phos acceptance range", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add("h_TPCee_MS_pp_phosRange_v_pt_v_cent", "Mass e^{+}e^{+} vs momentum e^{+}e^{+} (from TPC candidates) with one e in phos acceptance range", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + + mHistManager.add("h_TPCee_MS_mp_phosRange_kTVXinPHOS_v_pt_v_cent", "Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp} (from TPC candidates) with one e in phos acceptance range", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add("h_TPCee_MS_mm_phosRange_kTVXinPHOS_v_pt_v_cent", "Mass e^{-}e^{-} vs momentum e^{-}e^{-} (from TPC candidates) with one e in phos acceptance range", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add("h_TPCee_MS_pp_phosRange_kTVXinPHOS_v_pt_v_cent", "Mass e^{+}e^{+} vs momentum e^{+}e^{+} (from TPC candidates) with one e in phos acceptance range", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + + mHistManager.add("h_TPCeePhosGamma_MS_withMatches_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}Track vs momentum e^{#pm}e^{#mp}Track", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_MS_noMatches_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma vs momentum e^{#pm}e^{#mp}#gamma", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_MS_noMatches_aroundJpsi_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma (around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_MS_noMatches_aroundJpsi_DispOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma (around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma | DispOK", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_MS_noMatches_aroundJpsi_DispNotOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma (around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma | DispNotOK", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_MS_noMatches_notAroundJpsi_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma (not around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_MS_noMatches_DispOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma vs momentum e^{#pm}e^{#mp}#gamma | DispOK", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_MS_noMatches_DispNotOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma vs momentum e^{#pm}e^{#mp}#gamma | DispNotOK", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_MS_aroundJpsi_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma (around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_MS_notAroundJpsi_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma (not around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_MS_DispOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma vs momentum e^{#pm}e^{#mp}#gamma | DispOK", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_MS_DispNotOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma vs momentum e^{#pm}e^{#mp}#gamma | DispNotOK", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_MS_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma vs momentum e^{#pm}e^{#mp}#gamma | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_MS_withMatches_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}Track vs momentum e^{#pm}e^{#mp}Track | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_MS_noMatches_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma vs momentum e^{#pm}e^{#mp}#gamma | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_MS_noMatches_aroundJpsi_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma (around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_MS_noMatches_aroundJpsi_DispOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma (around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma | DispOK | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_MS_noMatches_aroundJpsi_DispNotOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma (around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma | DispNotOK | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_MS_noMatches_notAroundJpsi_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma (not around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_MS_noMatches_DispOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma vs momentum e^{#pm}e^{#mp}#gamma | DispOK | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_MS_noMatches_DispNotOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma vs momentum e^{#pm}e^{#mp}#gamma | DispNotOK | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_MS_aroundJpsi_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma (around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_MS_notAroundJpsi_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma (not around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_MS_DispOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma vs momentum e^{#pm}e^{#mp}#gamma | DispOK | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_MS_DispNotOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma vs momentum e^{#pm}e^{#mp}#gamma | DispNotOK | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_isMIP_MS_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma vs momentum e^{#pm}e^{#mp}#gamma | cluE < E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + + mHistManager.add("h_TPCeePhosGamma_MS_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma vs momentum e^{#pm}e^{#mp}#gamma (TPC candidates + Phos cluster)", HistType::kTH3F, {axisMassSpectrumChiC, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_MS_v_cluE", "Mass e^{#pm}e^{#mp}#gamma vs cluster Energy left by the photon", HistType::kTH3F, {axisMassSpectrumChiC, axisE, axisCent}); + + mHistManager.add("h_TPCeePhosGamma_minusee_MS_withMatches_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}Track - Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp}Track", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_minusee_MS_noMatches_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp}#gamma", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_minusee_MS_noMatches_aroundJpsi_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} (around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_minusee_MS_noMatches_aroundJpsi_DispOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} (around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma | DispOK", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_minusee_MS_noMatches_aroundJpsi_DispNotOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} (around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma | DispNotOK", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_minusee_MS_noMatches_notAroundJpsi_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} (not around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_minusee_MS_noMatches_DispOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp}#gamma | DispOK", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_minusee_MS_noMatches_DispNotOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp}#gamma | DispNotOK", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_minusee_MS_aroundJpsi_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} (around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_minusee_MS_notAroundJpsi_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} (not around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_minusee_MS_DispOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp}#gamma | DispOK", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_minusee_MS_DispNotOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp}#gamma | DispNotOK", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_minusee_MS_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp}#gamma | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_minusee_MS_withMatches_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}Track - Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp}Track | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_minusee_MS_noMatches_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp}#gamma | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_minusee_MS_noMatches_aroundJpsi_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} (around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_minusee_MS_noMatches_aroundJpsi_DispOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} (around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma | DispOK | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_minusee_MS_noMatches_aroundJpsi_DispNotOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} (around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma | DispNotOK | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_minusee_MS_noMatches_notAroundJpsi_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} (not around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_minusee_MS_noMatches_DispOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp}#gamma | DispOK | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_minusee_MS_noMatches_DispNotOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp}#gamma | DispNotOK | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_minusee_MS_aroundJpsi_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} (around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_minusee_MS_notAroundJpsi_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} (not around J/#psi) vs momentum e^{#pm}e^{#mp}#gamma | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_minusee_MS_DispOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp}#gamma | DispOK | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_notMIP_minusee_MS_DispNotOK_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp}#gamma | DispNotOK | cluE > E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_isMIP_minusee_MS_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp}#gamma | cluE < E_{MIP}", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + + mHistManager.add("h_TPCeePhosGamma_minusee_MS_v_3pt_v_cent", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} - Mass e^{#pm}e^{#mp} + Mass J/#psi vs momentum e^{#pm}e^{#mp}#gamma (TPC candidates + Phos cluster)", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisPt, axisCent}); + mHistManager.add("h_TPCeePhosGamma_minusee_MS_v_cluE", "Mass e^{#pm}e^{#mp}#gamma - Mass e^{#pm}e^{#mp} - Mass e^{#pm}e^{#mp} + Mass J/#psi vs cluster Energy left by the photon", HistType::kTH3F, {axisMassSpectrumChiCNoJpsiErrors, axisE, axisCent}); + + mHistManager.add("hTrackVX", "Track vertex coordinate X", HistType::kTH1F, {axisVTrackX}); + mHistManager.add("hTrackVY", "Track vertex coordinate Y", HistType::kTH1F, {axisVTrackY}); + mHistManager.add("hTrackVZ", "Track vertex coordinate Z", HistType::kTH1F, {axisVTrackZ}); + mHistManager.add("hTrackVX_Cut", "Track vertex coordinate X after cut", HistType::kTH1F, {axisVTrackX}); + mHistManager.add("hTrackVY_Cut", "Track vertex coordinate Y after cut", HistType::kTH1F, {axisVTrackY}); + mHistManager.add("hTrackVZ_Cut", "Track vertex coordinate Z after cut", HistType::kTH1F, {axisVTrackZ}); + + mHistManager.add("hTrackPt", "Track pt", HistType::kTH1F, {axisPtBig}); + mHistManager.add("hTrackPt_Cut", "Track pt after cut", HistType::kTH1F, {axisPtBig}); + mHistManager.add("hTrackEta", "Track eta", HistType::kTH1F, {axisEta}); + mHistManager.add("hTrackEta_Cut", "Track eta after cut", HistType::kTH1F, {axisEta}); + } + void process(SelCollisions::iterator const& collision, + aod::CaloClusters const& clusters, + MyTracks const& tracks, + soa::Filtered const& filteredTracks, + o2::aod::PHOSMatchindexTable const& matches, + aod::BCsWithTimestamps const&) + { + auto bc = collision.bc_as(); + if (runNumber != bc.runNumber()) { + LOG(info) << ">>>>>>>>>>>> Current run number: " << runNumber; + o2::parameters::GRPMagField* grpo = ccdb->getForTimeStamp("GLO/Config/GRPMagField", bc.timestamp()); + if (grpo == nullptr) { + LOGF(fatal, "Run 3 GRP object (type o2::parameters::GRPMagField) is not available in CCDB for run=%d at timestamp=%llu", bc.runNumber(), bc.timestamp()); + } + o2::base::Propagator::initFieldFromGRP(grpo); + bz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << ">>>>>>>>>>>> Magnetic field: " << bz; + runNumber = bc.runNumber(); + } + mHistManager.fill(HIST("eventCounter"), 0.5); + if (std::fabs(collision.posZ()) > 10.f) + return; + + float cent = -1.; + switch (cfgCentEst) { + case FV0A: + cent = collision.centFV0A(); + break; + case FT0M: + cent = collision.centFT0M(); + break; + case FT0A: + cent = collision.centFT0A(); + break; + case FT0C: + cent = collision.centFT0C(); + break; + case FDDM: + cent = collision.centFDDM(); + break; + case NTPV: + cent = collision.centNTPV(); + break; + } + + for (auto const& [track1, track2] : combinations(CombinationsStrictlyUpperIndexPolicy(filteredTracks, filteredTracks))) { + if (!track1.has_collision() || !track1.hasTPC()) + continue; + if (!track2.has_collision() || !track2.hasTPC()) + continue; + if (track1.collisionId() != track2.collisionId()) + continue; + if (!((track1.itsClusterMap() & uint8_t(1)) > 0) || !((track2.itsClusterMap() & uint8_t(1)) > 0)) + continue; + if (track1.itsChi2NCl() > cfgITSchi2Max || track2.itsChi2NCl() > cfgITSchi2Max) + continue; + if (track1.tpcChi2NCl() > cfgTPCchi2Max || track2.tpcChi2NCl() > cfgTPCchi2Max) + continue; + if (track1.itsNCls() < cfgITSnclsMin || track2.itsNCls() < cfgITSnclsMin) + continue; + if (track1.itsNCls() > cfgITSnclsMax || track2.itsNCls() > cfgITSnclsMax) + continue; + if (track1.tpcNClsFound() < cfgTPCnclsMin || track2.tpcNClsFound() < cfgTPCnclsMin) + continue; + if (track1.tpcNClsFound() > cfgTPCnclsMax || track2.tpcNClsFound() > cfgTPCnclsMax) + continue; + if (track1.tpcNClsCrossedRows() < cfgTPCnclsCRMin || track2.tpcNClsCrossedRows() < cfgTPCnclsCRMin) + continue; + if (track1.tpcNClsCrossedRows() > cfgTPCnclsCRMax || track2.tpcNClsCrossedRows() > cfgTPCnclsCRMax) + continue; + + TLorentzVector fourVectorP1, fourVectorP2; + fourVectorP1.SetPxPyPzE(track1.px(), track1.py(), track1.pz(), track1.energy(0)); + fourVectorP2.SetPxPyPzE(track2.px(), track2.py(), track2.pz(), track2.energy(0)); + + bool inPhosEtaRange1 = std::fabs(track1.eta()) < cfgPhosRangeEta; + bool inPhosEtaRange2 = std::fabs(track2.eta()) < cfgPhosRangeEta; + bool inPhosPhiRange1 = (track1.phi() * TMath::RadToDeg() > cfgPhosRangePhiMin && track1.phi() * TMath::RadToDeg() < cfgPhosRangePhiMax); + bool inPhosPhiRange2 = (track2.phi() * TMath::RadToDeg() > cfgPhosRangePhiMin && track2.phi() * TMath::RadToDeg() < cfgPhosRangePhiMax); + bool inPhosRange = (inPhosEtaRange1 && inPhosPhiRange1) || (inPhosEtaRange2 && inPhosPhiRange2); + bool posTrack = track1.sign() * bz > 0; + + double pairMass = (fourVectorP1 + fourVectorP2).M(), pairPt = (fourVectorP1 + fourVectorP2).Pt(); + + if (track1.sign() == track2.sign()) { + if (posTrack) { + mHistManager.fill(HIST("h_TPCee_MS_pp_v_pt_v_cent"), pairMass, pairPt, cent); + if (inPhosRange) { + mHistManager.fill(HIST("h_TPCee_MS_pp_phosRange_v_pt_v_cent"), pairMass, pairPt, cent); + if (collision.alias_bit(mEvSelTrig)) + mHistManager.fill(HIST("h_TPCee_MS_pp_phosRange_kTVXinPHOS_v_pt_v_cent"), pairMass, pairPt, cent); + } + } else { + mHistManager.fill(HIST("h_TPCee_MS_mm_v_pt_v_cent"), pairMass, pairPt, cent); + if (inPhosRange) { + mHistManager.fill(HIST("h_TPCee_MS_mm_phosRange_v_pt_v_cent"), pairMass, pairPt, cent); + if (collision.alias_bit(mEvSelTrig)) + mHistManager.fill(HIST("h_TPCee_MS_mm_phosRange_kTVXinPHOS_v_pt_v_cent"), pairMass, pairPt, cent); + } + } + } else { + mHistManager.fill(HIST("h_TPCee_MS_mp_v_pt_v_cent"), pairMass, pairPt, cent); + if (inPhosRange) { + mHistManager.fill(HIST("h_TPCee_MS_mp_phosRange_v_pt_v_cent"), pairMass, pairPt, cent); + if (collision.alias_bit(mEvSelTrig)) + mHistManager.fill(HIST("h_TPCee_MS_mp_phosRange_kTVXinPHOS_v_pt_v_cent"), pairMass, pairPt, cent); + } + + if (collision.alias_bit(mEvSelTrig) && clusters.size() != 0) { + for (auto const& gamma : clusters) { + float cluE = gamma.e(); + + if (cluE < mMinCluE || cluE > mMaxCluE || + gamma.ncell() < mMinCluNcell || + gamma.time() > mMaxCluTime || gamma.time() < mMinCluTime) + continue; + + bool matchFlag = 0, + isJpsi = 0, + isNotMIP = cluE > mCutMIPCluE, + isDispOK = testLambda(cluE, gamma.m02(), gamma.m20()); + + if (pairMass > cfgeeMassMin && pairMass < cfgeeMassMax) + isJpsi = 1; + + for (auto const& match : matches) { + if (gamma.index() == match.caloClusterId()) { + matchFlag = 1; + break; + } + } + + TLorentzVector fourVectorP3; + fourVectorP3.SetPxPyPzE(gamma.px(), gamma.py(), gamma.pz(), cluE); + double tripletMass = (fourVectorP1 + fourVectorP2 + fourVectorP3).M(), tripletPt = (fourVectorP1 + fourVectorP2 + fourVectorP3).Pt(); + + mHistManager.fill(HIST("h_TPCeePhosGamma_MS_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_minusee_MS_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + + mHistManager.fill(HIST("h_TPCeePhosGamma_MS_v_cluE"), tripletMass, cluE, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_minusee_MS_v_cluE"), tripletMass - pairMass + cfgJpsiMass, cluE, cent); + + if (matchFlag) { + mHistManager.fill(HIST("h_TPCeePhosGamma_MS_withMatches_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_minusee_MS_withMatches_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } else { + mHistManager.fill(HIST("h_TPCeePhosGamma_MS_noMatches_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_minusee_MS_noMatches_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + if (isJpsi) { + mHistManager.fill(HIST("h_TPCeePhosGamma_MS_noMatches_aroundJpsi_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_minusee_MS_noMatches_aroundJpsi_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + if (isDispOK) { + mHistManager.fill(HIST("h_TPCeePhosGamma_MS_noMatches_aroundJpsi_DispOK_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_minusee_MS_noMatches_aroundJpsi_DispOK_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } else { + mHistManager.fill(HIST("h_TPCeePhosGamma_MS_noMatches_aroundJpsi_DispNotOK_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_minusee_MS_noMatches_aroundJpsi_DispNotOK_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } + } else { + mHistManager.fill(HIST("h_TPCeePhosGamma_MS_noMatches_notAroundJpsi_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_minusee_MS_noMatches_notAroundJpsi_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } + if (isDispOK) { + mHistManager.fill(HIST("h_TPCeePhosGamma_MS_noMatches_DispOK_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_minusee_MS_noMatches_DispOK_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } else { + mHistManager.fill(HIST("h_TPCeePhosGamma_MS_noMatches_DispNotOK_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_minusee_MS_noMatches_DispNotOK_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } + } + + if (isJpsi) { + mHistManager.fill(HIST("h_TPCeePhosGamma_MS_aroundJpsi_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_minusee_MS_aroundJpsi_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } else { + mHistManager.fill(HIST("h_TPCeePhosGamma_MS_notAroundJpsi_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_minusee_MS_notAroundJpsi_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } + + if (isDispOK) { + mHistManager.fill(HIST("h_TPCeePhosGamma_MS_DispOK_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_minusee_MS_DispOK_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } else { + mHistManager.fill(HIST("h_TPCeePhosGamma_MS_DispNotOK_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_minusee_MS_DispNotOK_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } + + if (isNotMIP) { + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_MS_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_minusee_MS_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + if (matchFlag) { + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_MS_withMatches_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_minusee_MS_withMatches_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } else { + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_MS_noMatches_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_minusee_MS_noMatches_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + if (isJpsi) { + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_MS_noMatches_aroundJpsi_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_minusee_MS_noMatches_aroundJpsi_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + if (isDispOK) { + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_MS_noMatches_aroundJpsi_DispOK_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_minusee_MS_noMatches_aroundJpsi_DispOK_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } else { + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_MS_noMatches_aroundJpsi_DispNotOK_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_minusee_MS_noMatches_aroundJpsi_DispNotOK_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } + } else { + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_MS_noMatches_notAroundJpsi_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_minusee_MS_noMatches_notAroundJpsi_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } + if (isDispOK) { + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_MS_noMatches_DispOK_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_minusee_MS_noMatches_DispOK_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } else { + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_MS_noMatches_DispNotOK_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_minusee_MS_noMatches_DispNotOK_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } + } + + if (isJpsi) { + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_MS_aroundJpsi_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_minusee_MS_aroundJpsi_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } else { + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_MS_notAroundJpsi_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_minusee_MS_notAroundJpsi_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } + + if (isDispOK) { + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_MS_DispOK_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_minusee_MS_DispOK_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } else { + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_MS_DispNotOK_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_notMIP_minusee_MS_DispNotOK_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } + } else { + mHistManager.fill(HIST("h_TPCeePhosGamma_isMIP_MS_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("h_TPCeePhosGamma_isMIP_minusee_MS_v_3pt_v_cent"), tripletMass - pairMass + cfgJpsiMass, tripletPt, cent); + } + } + } + } + } + + for (auto const& track : tracks) { + mHistManager.fill(HIST("hTrackPt"), track.pt()); + mHistManager.fill(HIST("hTrackEta"), track.eta()); + mHistManager.fill(HIST("hTrackVX"), track.x()); + mHistManager.fill(HIST("hTrackVY"), track.y()); + mHistManager.fill(HIST("hTrackVZ"), track.z()); + mHistManager.fill(HIST("hTPCspectra"), track.pt(), track.tpcSignal()); + } + for (auto const& track : filteredTracks) { + if (!track.has_collision() || !track.hasTPC()) + continue; + if (track.itsChi2NCl() > cfgITSchi2Max || track.tpcChi2NCl() > cfgTPCchi2Max) + continue; + if (track.itsNCls() < cfgITSnclsMin || track.itsNCls() > cfgITSnclsMax || !((track.itsClusterMap() & uint8_t(1)) > 0)) + continue; + if (track.tpcNClsFound() < cfgTPCnclsMin || track.tpcNClsFound() > cfgTPCnclsMax) + continue; + if (track.tpcNClsCrossedRows() < cfgTPCnclsCRMin || track.tpcNClsCrossedRows() > cfgTPCnclsCRMax) + continue; + mHistManager.fill(HIST("hTPCspectra_isElectronRej"), track.pt(), track.tpcSignal()); + mHistManager.fill(HIST("hTrackPt_Cut"), track.pt()); + mHistManager.fill(HIST("hTrackEta_Cut"), track.eta()); + mHistManager.fill(HIST("hTrackVX_Cut"), track.x()); + mHistManager.fill(HIST("hTrackVY_Cut"), track.y()); + mHistManager.fill(HIST("hTrackVZ_Cut"), track.z()); + } + } + //_____________________________________________________________________________ + bool testLambda(float pt, float l1, float l2) + { + // Parameterization for full dispersion + float l2Mean = 1.53126 + 9.50835e+06 / (1. + 1.08728e+07 * pt + 1.73420e+06 * pt * pt); + float l1Mean = 1.12365 + 0.123770 * std::exp(-pt * 0.246551) + 5.30000e-03 * pt; float l2Sigma = 6.48260e-02 + 7.60261e+10 / (1. + 1.53012e+11 * pt + 5.01265e+05 * pt * pt) + 9.00000e-03 * pt; float l1Sigma = 4.44719e-04 + 6.99839e-01 / (1. + 1.22497e+00 * pt + 6.78604e-07 * pt * pt) + 9.00000e-03 * pt; - float c = -0.35 - 0.550 * TMath::Exp(-0.390730 * pt); + float c = -0.35 - 0.550 * std::exp(-0.390730 * pt); return 0.5 * (l1 - l1Mean) * (l1 - l1Mean) / l1Sigma / l1Sigma + 0.5 * (l2 - l2Mean) * (l2 - l2Mean) / l2Sigma / l2Sigma + @@ -264,6 +1284,8 @@ struct phosElId { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { auto workflow = WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; return workflow; } diff --git a/PWGEM/Tasks/phosNbar.cxx b/PWGEM/Tasks/phosNbar.cxx index e9256e943aa..7cd2e4387a7 100644 --- a/PWGEM/Tasks/phosNbar.cxx +++ b/PWGEM/Tasks/phosNbar.cxx @@ -44,6 +44,7 @@ /// - Count rate in 2D representation using namespace o2; +using namespace o2::aod::evsel; using namespace o2::framework; using namespace o2::framework::expressions; @@ -56,12 +57,15 @@ struct phosNbar { Service ccdb; using SelCollision = soa::Join::iterator; + using SelCollisionMC = soa::Join::iterator; using TrackCandidates = soa::Join; using mcClusters = soa::Join; using mcTracks = soa::Join; // using MatchedClusters = soa::Join; + Configurable mPairingMethod{"mPairingMethod", 0, "0:max CPA, 1: min DCA"}; + Configurable mIsMC{"isMC", false, "to fill MC histograms"}; Configurable mEvSelTrig{"mEvSelTrig", kTVXinPHOS, "Select events with this trigger"}; // nbar selection Configurable mMinCluE{"minCluE", 0.3, "Minimum cluster energy"}; @@ -75,8 +79,12 @@ struct phosNbar { // track selection Configurable mPionDeDxCut{"piondEdx", 3., "pion dE/dx cut in sigma"}; // Topological cuts + Configurable mDCAcut{"DCAmax", 0.2, "DCA max cut"}; + Configurable mCPAcut{"CPAmin", 0.96, "CPA min cut"}; Configurable mNmix{"nMix", 5, "depth of mixing buffer"}; + Configurable mStrictParentCut{"StrictParent", true, "parent with largest Edep or any parent"}; + int mPrevMCColId = -1; // mark MC collissions already scanned static constexpr double c = 29979245800.; // speed of light in cm/sec static constexpr double mNbar = 0.939485; // neutron mass static constexpr double mpi = 0.13957039; // pion mass @@ -92,6 +100,8 @@ struct phosNbar { nbar() = default; nbar(double p, double xPHS, double yPHS, bool zPHS, int mcLabel) : mom(p), x(xPHS), y(yPHS), z(zPHS), label(mcLabel) {} ~nbar() = default; + bool testPIDBit(int ibit) { return (mPIDbits & (1 << ibit)) > 0; } + void setPIDBit(int ibit) { mPIDbits |= (1 << ibit); } public: double mom = 0.; // momentum estimated from Time @@ -99,39 +109,98 @@ struct phosNbar { double y = 9999.; // y coordinate in PHOS plane double z = 9999.; // z coordinate in PHOS plane int label = -1; // label of MC particle + int mPIDbits = 0; // keep PID cuts }; - std::vector> piEvent; + // class to keep nbar candidate parameters + class pion + { + public: + pion() = default; + pion(const pion&) = default; + pion(const o2::track::TrackParametrization& tr, int mcLabel) : mom(tr), label(mcLabel) {} + ~pion() = default; + bool testPIDBit(int ibit) { return (mPIDbits & (1 << ibit)) > 0; } + void setPIDBit(int ibit) { mPIDbits |= (1 << ibit); } + + public: + o2::track::TrackParametrization mom; // track parameterization + int label = -1; // label of MC particle + int mPIDbits = 0; // keep PID cuts + }; + + std::vector piEvent; std::vector nbarEvent; - std::array>>, mNZbins> mixTrackEvts; + std::array>, mNZbins> mixTrackEvts; std::array>, mNZbins> mixNbarEvts; - TH2 *hRePP, *hRePM, *hMiPP, *hMiPM, *hSignalSP, *hSignalSM; + TH2 *hRePP, *hRePM, *hMiPP, *hMiPM; + TH3 *hSignalSP, *hSignalSM, *hSignalOther; + TH3 *hRePPDCA, *hRePMDCA, *hMiPPDCA, *hMiPMDCA, *hRePPCPA, *hRePMCPA, *hMiPPCPA, *hMiPMCPA; /// \brief Create output histograms void init(o2::framework::InitContext const&) { - - mHistManager.add("evsel", "event selection", HistType::kTH1F, {{10, 0., 10.}}); + mHistManager.add("evsel", "event selection", HistType::kTH1F, {{14, 0., 14.}}); mHistManager.add("vtxZ", "Vertex z distribution", HistType::kTH1F, {{100, -20., 20., "z_{vtx} (cm)", "z_{vtx} (cm)"}}); mHistManager.add("cluCuts", "Spectrum vs cut", HistType::kTH2F, {{100, 0., 5., "E (GeV)", "E (GeV)"}, {10, 0., 10., "cut"}}); mHistManager.add("nbarCuts", "Spectrum vs cut", HistType::kTH2F, {{100, 0., 5., "E (GeV)", "E (GeV)"}, {10, 0., 10., "cut"}}); + mHistManager.add("nbarSigmaCuts", "Spectrum vs cut", HistType::kTH2F, {{100, 0., 5., "E (GeV)", "E (GeV)"}, {10, 0., 10., "cut"}}); mHistManager.add("trackCuts", "Spectrum vs cut", HistType::kTH2F, {{100, 0., 5., "p_{T} (GeV)", "p_{T} (GeV)"}, {10, 0., 10., "cut"}}); + mHistManager.add("trackSigmaCuts", "Spectrum vs cut", HistType::kTH2F, {{100, 0., 5., "p_{T} (GeV)", "p_{T} (GeV)"}, {10, 0., 10., "cut"}}); mHistManager.add("cluTime", "Time vs E clu", HistType::kTH2F, {{200, -100.e-9, 100.e-9, "t (s)", "t (s)"}, {100, 0., 10., "E (GeV)", "E (GeV)"}}); mHistManager.add("nbarTime", "Time vs E clu nbar", HistType::kTH2F, {{200, -100.e-9, 100.e-9, "t (s)", "t (s)"}, {100, 0., 10., "E (GeV)", "E (GeV)"}}); - mHistManager.add("cluRveto", "CPV radius vs E clu", HistType::kTH2F, {{100, 0., 20., "R (sigmas)", "R (sigmas)"}, {100, 0., 10., "E (GeV)", "E (GeV)"}}); - mHistManager.add("nbarRveto", "CPV radius vs E clu nbar", HistType::kTH2F, {{100, 0., 20., "R (sigmas)", "R (sigmas)"}, {100, 0., 10., "E (GeV)", "E (GeV)"}}); + mHistManager.add("nbarSigmaTime", "Time vs E clu nbar", HistType::kTH2F, {{200, -100.e-9, 100.e-9, "t (s)", "t (s)"}, {100, 0., 10., "E (GeV)", "E (GeV)"}}); + mHistManager.add("cluRveto", "CPV radius vs E clu", HistType::kTH2F, {{100, 0., 10., "R (sigmas)", "R (sigmas)"}, {100, 0., 10., "E (GeV)", "E (GeV)"}}); + mHistManager.add("nbarRveto", "CPV radius vs E clu nbar", HistType::kTH2F, {{100, 0., 10., "R (sigmas)", "R (sigmas)"}, {100, 0., 10., "E (GeV)", "E (GeV)"}}); + mHistManager.add("nbarSigmaRveto", "CPV radius vs E clu nbar", HistType::kTH2F, {{100, 0., 10., "R (sigmas)", "R (sigmas)"}, {100, 0., 10., "E (GeV)", "E (GeV)"}}); const AxisSpec massAxis{500, 1., 1.5}, - ptAxis{100, 0., 10.}; + ptAxis{100, 0., 10.}, + dcaAxis{100, 0., 5}, + cpaAxis{100, 0., 1.}, + pidAxis{5, 0., 5.}; hRePP = (std::get>(mHistManager.add("RePiP", "Inv mass", HistType::kTH2F, {massAxis, ptAxis}))).get(); hRePM = (std::get>(mHistManager.add("RePiM", "Inv mass", HistType::kTH2F, {massAxis, ptAxis}))).get(); hMiPP = (std::get>(mHistManager.add("MiPiP", "Inv mass", HistType::kTH2F, {massAxis, ptAxis}))).get(); hMiPM = (std::get>(mHistManager.add("MiPiM", "Inv mass", HistType::kTH2F, {massAxis, ptAxis}))).get(); - hSignalSP = (std::get>(mHistManager.add("SignalSP", "Inv mass", HistType::kTH2F, {massAxis, ptAxis}))).get(); - hSignalSM = (std::get>(mHistManager.add("SignalSM", "Inv mass", HistType::kTH2F, {massAxis, ptAxis}))).get(); + if (mIsMC) { + hSignalSP = (std::get>(mHistManager.add("SignalSP", "Inv mass", HistType::kTH3F, {massAxis, ptAxis, pidAxis}))).get(); + hSignalSM = (std::get>(mHistManager.add("SignalSM", "Inv mass", HistType::kTH3F, {massAxis, ptAxis, pidAxis}))).get(); + hSignalOther = (std::get>(mHistManager.add("SignalOther", "Inv mass", HistType::kTH3F, {massAxis, ptAxis, pidAxis}))).get(); + } + + hRePPDCA = (std::get>(mHistManager.add("RePiPDCA", "DCA", HistType::kTH3F, {massAxis, ptAxis, dcaAxis}))).get(); + hRePMDCA = (std::get>(mHistManager.add("RePiMDCA", "DCA", HistType::kTH3F, {massAxis, ptAxis, dcaAxis}))).get(); + hMiPPDCA = (std::get>(mHistManager.add("MiPiPDCA", "DCA", HistType::kTH3F, {massAxis, ptAxis, dcaAxis}))).get(); + hMiPMDCA = (std::get>(mHistManager.add("MiPiMDCA", "DCA", HistType::kTH3F, {massAxis, ptAxis, dcaAxis}))).get(); + + hRePPCPA = (std::get>(mHistManager.add("RePiPCPA", "CPA", HistType::kTH3F, {massAxis, ptAxis, cpaAxis}))).get(); + hRePMCPA = (std::get>(mHistManager.add("RePiMCPA", "CPA", HistType::kTH3F, {massAxis, ptAxis, cpaAxis}))).get(); + hMiPPCPA = (std::get>(mHistManager.add("MiPiPCPA", "CPA", HistType::kTH3F, {massAxis, ptAxis, cpaAxis}))).get(); + hMiPMCPA = (std::get>(mHistManager.add("MiPiMCPA", "CPA", HistType::kTH3F, {massAxis, ptAxis, cpaAxis}))).get(); + + if (mIsMC) { + mHistManager.add("hMCSigPSp", "Sigma spectrum inclusive", HistType::kTH1F, {ptAxis}); + mHistManager.add("hMCSigPSpAll", "Sigma spectrum inclusive", HistType::kTH1F, {ptAxis}); + mHistManager.add("hMCSigPSpPrim", "Sigma spectrum Primary", HistType::kTH1F, {ptAxis}); + mHistManager.add("hMCSigPRap", "Sigma rapidity", HistType::kTH1F, {{100, -3., 3., "Rapidity"}}); + mHistManager.add("hMCSigPPhi", "Sigma phi", HistType::kTH1F, {{100, 0., TMath::TwoPi(), "#phi (rad)"}}); + mHistManager.add("hMCSigPRapPrim", "Sigma rapidity primary", HistType::kTH1F, {{100, -1., 1., "Rapidity"}}); + mHistManager.add("hMCSigPPhiPrim", "Sigma phi primary", HistType::kTH1F, {{100, 0., TMath::TwoPi(), "#phi (rad)"}}); + mHistManager.add("hMCSigPSecVtx", "Sigma secondary", HistType::kTH2F, {{100, 0., 500., "R (cm)"}, {100, -TMath::Pi(), TMath::Pi(), "#phi (rad)"}}); + + mHistManager.add("hMCSigMSp", "Sigma spectrum inclusive", HistType::kTH1F, {ptAxis}); + mHistManager.add("hMCSigMSpAll", "Sigma spectrum inclusive", HistType::kTH1F, {ptAxis}); + mHistManager.add("hMCSigMSpPrim", "Sigma spectrum Primary", HistType::kTH1F, {ptAxis}); + mHistManager.add("hMCSigMRap", "Sigma rapidity", HistType::kTH1F, {{100, -3., 3., "Rapidity"}}); + mHistManager.add("hMCSigMPhi", "Sigma phi", HistType::kTH1F, {{100, 0., TMath::TwoPi(), "#phi (rad)"}}); + mHistManager.add("hMCSigMRapPrim", "Sigma rapidity primary", HistType::kTH1F, {{100, -1., 1., "Rapidity"}}); + mHistManager.add("hMCSigMPhiPrim", "Sigma phi primary", HistType::kTH1F, {{100, 0., TMath::TwoPi(), "#phi (rad)"}}); + mHistManager.add("hMCSigMSecVtx", "Sigma secondary", HistType::kTH2F, {{100, 0., 500., "R (cm)"}, {100, -TMath::Pi(), TMath::Pi(), "#phi (rad)"}}); + } ccdb->setURL(o2::base::NameConf::getCCDBServer()); ccdb->setCaching(true); @@ -146,28 +215,147 @@ struct phosNbar { if (!selectEvent(collision, mixIndex)) { return; } + if constexpr (isMC) { + if (clusters.size() == 0) { + return; + } + } + // count events + int ntr = tracks.size(); + int nclu = clusters.size(); + mHistManager.fill(HIST("evsel"), 10. + 2 * (ntr > 0) + (nclu > 0)); + mHistManager.fill(HIST("evsel"), 8.); + + // Fill MC distributions + // Sigma rapidity, pt, phi + // secondary Sigmas + if constexpr (isMC) { + // check current collision Id for clusters + int cluMcBCId = -1; + for (auto clu : clusters) { + auto mcList = clu.labels(); // const std::vector + int nParents = mcList.size(); + for (int iParent = 0; iParent < nParents; iParent++) { // Not found nbar parent yiet + int label = mcList[iParent]; + if (label > -1) { + auto parent = mcParticles->iteratorAt(label); + cluMcBCId = parent.mcCollision().bcId(); + break; + } + } + if (cluMcBCId > -1) { + break; + } + } + // Scan MC particles in current MC event + if (mcParticles->begin() != mcParticles->end()) { + for (auto part : *mcParticles) { + if (part.mcCollision().bcId() != cluMcBCId) { + continue; + if (part.pdgCode() == -3112) { // Sigma+ + double pt = part.pt(); + mHistManager.fill(HIST("hMCSigPSp"), pt); + mHistManager.fill(HIST("hMCSigPRap"), part.y()); + mHistManager.fill(HIST("hMCSigPPhi"), part.phi()); + if (abs(part.y()) < .5) { + mHistManager.fill(HIST("hMCSigPSpAll"), pt); + double r = sqrt(pow(part.vx(), 2) + pow(part.vy(), 2)); + double phiVtx = atan2(part.vy(), part.vx()); + mHistManager.fill(HIST("hMCSigPSecVtx"), r, phiVtx); + if (r < 0.5) { + mHistManager.fill(HIST("hMCSigPSpPrim"), pt); + mHistManager.fill(HIST("hMCSigPRapPrim"), part.y()); + mHistManager.fill(HIST("hMCSigPPhiPrim"), part.phi()); + } + } + } + if (part.pdgCode() == -3222) { // Sigma- + double pt = part.pt(); + mHistManager.fill(HIST("hMCSigMSp"), pt); + mHistManager.fill(HIST("hMCSigMRap"), part.y()); + mHistManager.fill(HIST("hMCSigMPhi"), part.phi()); + if (abs(part.y()) < .5) { + mHistManager.fill(HIST("hMCSigMSpAll"), pt); + double r = sqrt(pow(part.vx(), 2) + pow(part.vy(), 2)); + double phiVtx = atan2(part.vy(), part.vx()); + mHistManager.fill(HIST("hMCSigMSecVtx"), r, phiVtx); + if (r < 0.5) { + mHistManager.fill(HIST("hMCSigMSpPrim"), pt); + mHistManager.fill(HIST("hMCSigMRapPrim"), part.y()); + mHistManager.fill(HIST("hMCSigMPhiPrim"), part.phi()); + } + } + } + } + } + } + } + selectNbars(clusters, mcParticles); - selectTracks(tracks); + selectTracks(tracks, mcParticles); // Fill Real double cpa, m, pt; math_utils::Point3D vtxV0; for (auto tr : piEvent) { for (auto nbar : nbarEvent) { - if (!minimizeCPA(nbar, tr, cpa, vtxV0, m, pt)) { - continue; + int cp = 0; + if constexpr (isMC) { // test parent + cp = commonParentPDG(tr.label, nbar.label, mcParticles); } - if (tr.getCharge2Pt() > 0) { - hRePP->Fill(m, pt); + double dca = 999.; + switch (mPairingMethod) { + case 0: // maximize CPA + if (!minimizeCPA(nbar, tr, cpa, vtxV0, m, pt)) { + continue; + } + break; + case 1: // Minimize DCA + if (!propagateToDCA(nbar, tr, cpa, dca, vtxV0, m, pt)) { + continue; + } + break; + default: // do nothing + continue; + } + if (tr.mom.getCharge2Pt() > 0) { + hRePPDCA->Fill(m, pt, dca); + hRePPCPA->Fill(m, pt, cpa); + if ((mPairingMethod == 0 && cpa > mCPAcut) || + (mPairingMethod == 1 && dca < mDCAcut && cpa > mCPAcut)) { + hRePP->Fill(m, pt); + } } else { - hRePM->Fill(m, pt); + hRePMDCA->Fill(m, pt, dca); + hRePMCPA->Fill(m, pt, cpa); + if ((mPairingMethod == 0 && cpa > mCPAcut) || + (mPairingMethod == 1 && dca < mDCAcut && cpa > mCPAcut)) { + hRePM->Fill(m, pt); + } } - if constexpr (isMC) { // test parent - int cp = commonParentPDG(tr.getUserField(), nbar.label, mcParticles); - if (cp == -3112) { // Sigma+ - hSignalSP->Fill(m, pt); + if (cp == -3112) { // Sigma+ + hSignalSP->Fill(m, pt, static_cast(0)); + for (int iPIDbit = 1; iPIDbit < 5; iPIDbit++) { + if (nbar.testPIDBit(iPIDbit)) { + hSignalSP->Fill(m, pt, static_cast(iPIDbit)); + } } - if (cp == -3222) { // Sigmap - hSignalSM->Fill(m, pt); + } else { + if (cp == -3222) { // Sigma- + hSignalSM->Fill(m, pt, static_cast(0)); + for (int iPIDbit = 1; iPIDbit < 5; iPIDbit++) { + if (nbar.testPIDBit(iPIDbit)) { + hSignalSM->Fill(m, pt, static_cast(iPIDbit)); + } + } + } else { + if (cp != 0) { + if (cp == -1114 || cp == -2114 || cp == -2214) // Delta + hSignalOther->Fill(m, pt, 0.); + if (cp == -3114 || cp == -3214 || cp == -3312) // Sigma*, Xi + hSignalOther->Fill(m, pt, 1.); + if (abs(cp) < 400) // mesons + hSignalOther->Fill(m, pt, 2.); + } } } } @@ -182,13 +370,33 @@ struct phosNbar { for (auto tr : piEvent) { for (auto nbarMixEv : mixNbarEvts[mixIndex]) { for (auto nbar : nbarMixEv) { - if (!minimizeCPA(nbar, tr, cpa, vtxV0, m, pt)) { - continue; + double dca = 999.; + switch (mPairingMethod) { + case 0: // maximize CPA + if (!minimizeCPA(nbar, tr, cpa, vtxV0, m, pt)) { + continue; + } + break; + case 1: // Minimize DCA + if (!propagateToDCA(nbar, tr, cpa, dca, vtxV0, m, pt)) { + continue; + } + break; + default: // do nothing + continue; } - if (tr.getCharge2Pt() > 0) { - hMiPP->Fill(m, pt); + if (tr.mom.getCharge2Pt() > 0) { + hMiPPDCA->Fill(m, pt, dca); + hMiPPCPA->Fill(m, pt, cpa); + if (dca < mDCAcut && cpa > mCPAcut) { + hMiPP->Fill(m, pt); + } } else { - hMiPM->Fill(m, pt); + hMiPMDCA->Fill(m, pt, dca); + hMiPMCPA->Fill(m, pt, cpa); + if (dca < mDCAcut && cpa > mCPAcut) { + hMiPM->Fill(m, pt); + } } } } @@ -196,13 +404,33 @@ struct phosNbar { for (auto trMixEvent : mixTrackEvts[mixIndex]) { for (auto tr : trMixEvent) { for (auto nbar : nbarEvent) { - if (!minimizeCPA(nbar, tr, cpa, vtxV0, m, pt)) { - continue; + double dca = 999.; + switch (mPairingMethod) { + case 0: // maximize CPA + if (!minimizeCPA(nbar, tr, cpa, vtxV0, m, pt)) { + continue; + } + break; + case 1: // Minimize DCA + if (!propagateToDCA(nbar, tr, cpa, dca, vtxV0, m, pt)) { + continue; + } + break; + default: // do nothing + continue; } - if (tr.getCharge2Pt() > 0) { - hMiPP->Fill(m, pt); + if (tr.mom.getCharge2Pt() > 0) { + hMiPPDCA->Fill(m, pt, dca); + hMiPPCPA->Fill(m, pt, cpa); + if (dca < mDCAcut && cpa > mCPAcut) { + hMiPP->Fill(m, pt); + } } else { - hMiPM->Fill(m, pt); + hMiPMDCA->Fill(m, pt, dca); + hMiPMCPA->Fill(m, pt, cpa); + if (dca < mDCAcut && cpa > mCPAcut) { + hMiPM->Fill(m, pt); + } } } } @@ -225,21 +453,48 @@ struct phosNbar { template bool selectEvent(TCollision const& col, int& indx) { + bool isColSelected = false; + mHistManager.fill(HIST("evsel"), 0.); + if (col.selection_bit(kIsBBT0A) || col.selection_bit(kIsBBT0C)) { + mHistManager.fill(HIST("evsel"), 1.); + } + if (col.selection_bit(kIsBBT0A) && col.selection_bit(kIsBBT0C)) { + mHistManager.fill(HIST("evsel"), 2.); + } + if (col.alias_bit(kTVXinPHOS)) { + mHistManager.fill(HIST("evsel"), 3.); + } + if (col.selection_bit(kIsTriggerTVX)) { + mHistManager.fill(HIST("evsel"), 4.); + } + if (col.alias_bit(kTVXinPHOS)) { + mHistManager.fill(HIST("evsel"), 5.); + } + if (col.alias_bit(kTVXinPHOS)) { + mHistManager.fill(HIST("evsel"), 6); + } + isColSelected = false; + if constexpr (isMC) { + isColSelected = col.selection_bit(kIsTriggerTVX); + } else { + isColSelected = col.alias_bit(mEvSelTrig); + } + if (!isColSelected) { + return false; + } + mVtxZ = col.posZ(); mHistManager.fill(HIST("vtxZ"), mVtxZ); if (std::abs(mVtxZ) > 10.f) { return false; } - mHistManager.fill(HIST("evsel"), 1.); + mHistManager.fill(HIST("evsel"), 7.); if constexpr (!isMC) { if (!col.alias_bit(mEvSelTrig)) { return false; } } - // Remove pileup??? - mHistManager.fill(HIST("evsel"), 2.); - // so far only binning according to zvtx is implemented indx = (mVtxZ + 10.) / 20. * mNZbins; if (indx >= mNZbins) { @@ -254,23 +509,33 @@ struct phosNbar { // Select clusters produced by nbar and prepare list of nbar candidates for (const auto& clu : clusters) { bool isNbar = false; + bool isNbarSigma = false; int label = -1; // if no MC if constexpr (isMC) { auto mcList = clu.labels(); // const std::vector - if (mcList.size() > 0) { - label = mcList[0]; + int nParents = 0; + if (mStrictParentCut) { + nParents = std::min(1, static_cast(mcList.size())); + } else { + nParents = mcList.size(); } - int iparent = label; - while (iparent > -1) { - auto parent = mcParticles->iteratorAt(iparent); - if (parent.pdgCode() == -2112) { - isNbar = true; - break; - } - if (parent.mothersIds().size() == 0 || abs(parent.pdgCode()) < 22 || abs(parent.pdgCode()) > 5000) { // no parents, parent not quark/gluon, strings - break; + for (int iParent = 0; iParent < nParents && !isNbar; iParent++) { // Not found nbar parent yiet + label = mcList[iParent]; + int ip = label; + while (ip > -1) { + auto parent = mcParticles->iteratorAt(ip); + if (parent.pdgCode() == -2112) { + isNbar = true; + break; + } + if (parent.mothersIds().size() == 0 || abs(parent.pdgCode()) < 22 || abs(parent.pdgCode()) > 5000) { // no parents, parent not quark/gluon, strings + break; + } + ip = parent.mothersIds()[0]; } - iparent = parent.mothersIds()[0]; + } + if (isNbar) { + isNbarSigma = isSigmaDaughter(label, mcParticles); } } @@ -278,6 +543,9 @@ struct phosNbar { mHistManager.fill(HIST("cluCuts"), clu.e(), 0.); if (isNbar) { mHistManager.fill(HIST("nbarCuts"), clu.e(), 0.); + if (isNbarSigma) { + mHistManager.fill(HIST("nbarSigmaCuts"), clu.e(), 0.); + } } if (clu.e() < mMinCluE) { continue; @@ -285,55 +553,36 @@ struct phosNbar { mHistManager.fill(HIST("cluCuts"), clu.e(), 1.); if (isNbar) { mHistManager.fill(HIST("nbarCuts"), clu.e(), 1.); + if (isNbarSigma) { + mHistManager.fill(HIST("nbarSigmaCuts"), clu.e(), 1.); + } } - if (clu.m02() < 0.2) { // standard exotics cut + + if (clu.time() < mTimeMin || clu.time() > mTimeMax) { continue; } mHistManager.fill(HIST("cluCuts"), clu.e(), 2.); if (isNbar) { mHistManager.fill(HIST("nbarCuts"), clu.e(), 2.); + if (isNbarSigma) { + mHistManager.fill(HIST("nbarSigmaCuts"), clu.e(), 2.); + } } - if (clu.ncell() < mNCellMin) { - continue; - } - mHistManager.fill(HIST("cluCuts"), clu.e(), 3.); - if (isNbar) { - mHistManager.fill(HIST("nbarCuts"), clu.e(), 3.); - } - if (clu.time() < mTimeMin || clu.time() > mTimeMax) { - continue; - } - mHistManager.fill(HIST("cluCuts"), clu.e(), 4.); - if (isNbar) { - mHistManager.fill(HIST("nbarCuts"), clu.e(), 4.); - } - mHistManager.fill(HIST("cluRveto"), clu.trackdist(), clu.e()); if (isNbar) { mHistManager.fill(HIST("nbarRveto"), clu.trackdist(), clu.e()); + if (isNbarSigma) { + mHistManager.fill(HIST("nbarSigmaRveto"), clu.trackdist(), clu.e()); + } } - - if (clu.trackdist() < mRvetoSigma) // neutrality - { - continue; - } - mHistManager.fill(HIST("cluCuts"), clu.e(), 5.); - if (isNbar) { - mHistManager.fill(HIST("nbarCuts"), clu.e(), 5.); - } - if (clu.m02() < mDispA * clu.m20() + mDispB) { - continue; - } - mHistManager.fill(HIST("cluCuts"), clu.e(), 6.); - if (isNbar) { - mHistManager.fill(HIST("nbarCuts"), clu.e(), 6.); - } - mHistManager.fill(HIST("cluTime"), clu.time(), clu.e()); if (isNbar) { mHistManager.fill(HIST("nbarTime"), clu.time(), clu.e()); + if (isNbarSigma) { + mHistManager.fill(HIST("nbarSigmaTime"), clu.time(), clu.e()); + } } - + // estimate momentum float t = clu.time(); float r = sqrt(clu.globalx() * clu.globalx() + clu.globaly() * clu.globaly() + (clu.globalz() - mVtxZ) * (clu.globalz() - mVtxZ)); float tgamma = r / c; @@ -352,40 +601,97 @@ struct phosNbar { } double mom = mNbar / std::sqrt(std::pow(t * c / r, 2) - 1.); nbarEvent.emplace_back(mom, clu.globalx(), clu.globaly(), clu.globalz(), label); + // set PID cuts + if (clu.m02() > 0.2) { // standard exotics cut + nbarEvent.back().setPIDBit(1); + mHistManager.fill(HIST("cluCuts"), clu.e(), 3.); + if (isNbar) { + mHistManager.fill(HIST("nbarCuts"), clu.e(), 3.); + if (isNbarSigma) { + mHistManager.fill(HIST("nbarSigmaCuts"), clu.e(), 3.); + } + } + } + if (clu.ncell() >= mNCellMin) { + nbarEvent.back().setPIDBit(2); + mHistManager.fill(HIST("cluCuts"), clu.e(), 4.); + if (isNbar) { + mHistManager.fill(HIST("nbarCuts"), clu.e(), 4.); + if (isNbarSigma) { + mHistManager.fill(HIST("nbarSigmaCuts"), clu.e(), 4.); + } + } + } + if (clu.trackdist() > mRvetoSigma) // neutrality + { + nbarEvent.back().setPIDBit(3); + mHistManager.fill(HIST("cluCuts"), clu.e(), 5.); + if (isNbar) { + mHistManager.fill(HIST("nbarCuts"), clu.e(), 5.); + if (isNbarSigma) { + mHistManager.fill(HIST("nbarSigmaCuts"), clu.e(), 5.); + } + } + } + if (clu.m02() > mDispA * clu.m20() + mDispB) { + nbarEvent.back().setPIDBit(4); + mHistManager.fill(HIST("cluCuts"), clu.e(), 6.); + if (isNbar) { + mHistManager.fill(HIST("nbarCuts"), clu.e(), 6.); + if (isNbarSigma) { + mHistManager.fill(HIST("nbarSigmaCuts"), clu.e(), 6.); + } + } + } } } // selectNbars //---------------------------------------- template - void selectTracks(TTracks const& tracks) + void selectTracks(TTracks const& tracks, aod::McParticles const* mcParticles) { // Select pion tracks to pair with nbar for (const auto& piontrack : tracks) { + int label = -1; + bool isSigmaPi = false; + if constexpr (isMC) { + label = piontrack.mcParticleId(); + isSigmaPi = isSigmaDaughter(label, mcParticles); + } mHistManager.fill(HIST("trackCuts"), piontrack.pt(), 0.); + if (isSigmaPi) { + mHistManager.fill(HIST("trackSigmaCuts"), piontrack.pt(), 0.); + } if (piontrack.hasITS() == false) { continue; } mHistManager.fill(HIST("trackCuts"), piontrack.pt(), 1.); + if (isSigmaPi) { + mHistManager.fill(HIST("trackSigmaCuts"), piontrack.pt(), 1.); + } if (piontrack.hasTPC() == false) { continue; } mHistManager.fill(HIST("trackCuts"), piontrack.pt(), 2.); - if (std::abs(piontrack.tpcNSigmaPi()) > mPionDeDxCut) { - continue; + if (isSigmaPi) { + mHistManager.fill(HIST("trackSigmaCuts"), piontrack.pt(), 2.); } - mHistManager.fill(HIST("trackCuts"), piontrack.pt(), 2.); - // DCA cut??? + piEvent.emplace_back(getTrackPar(piontrack), label); - piEvent.emplace_back(getTrackPar(piontrack)); - if constexpr (isMC) { - piEvent.back().setUserField(piontrack.mcParticleId()); + if (std::abs(piontrack.tpcNSigmaPi()) < mPionDeDxCut) { + piEvent.back().setPIDBit(0); + mHistManager.fill(HIST("trackCuts"), piontrack.pt(), 3.); + if (isSigmaPi) { + mHistManager.fill(HIST("trackSigmaCuts"), piontrack.pt(), 4.); + } } + // DCA cut??? } } //---------------------------------------- - int commonParentPDG(uint16_t labPi, int labNbar, aod::McParticles const* mcParticles) + int commonParentPDG(int labPi, int labNbar, aod::McParticles const* mcParticles) { // Tests if two labels contain common ancestor // return 0 if no common parent @@ -395,16 +701,19 @@ struct phosNbar { int iparentN = labNbar; while (iparentN > -1) { if (iparentPi == iparentN) { - return mcParticles->iteratorAt(iparentPi).pdgCode(); + if (abs(mcParticles->iteratorAt(iparentPi).pdgCode()) > 10000) // string etc + return 0; + else + return mcParticles->iteratorAt(iparentPi).pdgCode(); } auto parentN = mcParticles->iteratorAt(iparentN); - if (parentN.mothersIds().size() == 0 || parentN.pdgCode() == 21 || abs(parentN.pdgCode()) < 11 || abs(parentN.pdgCode()) > 5000) { // no parents, parent not quark/gluon, strings + if (!parentN.has_mothers() || parentN.pdgCode() == 21 || abs(parentN.pdgCode()) < 11 || abs(parentN.pdgCode()) > 5000) { // no parents, parent not quark/gluon, strings break; } iparentN = parentN.mothersIds()[0]; } auto parentPi = mcParticles->iteratorAt(iparentPi); - if (parentPi.mothersIds().size() == 0 || parentPi.pdgCode() == 21 || abs(parentPi.pdgCode()) < 11 || abs(parentPi.pdgCode()) > 5000) { // no parents, parent not quark/gluon, strings + if (!parentPi.has_mothers() || parentPi.pdgCode() == 21 || abs(parentPi.pdgCode()) < 11 || abs(parentPi.pdgCode()) > 5000) { // no parents, parent not quark/gluon, strings break; } iparentPi = parentPi.mothersIds()[0]; @@ -413,7 +722,7 @@ struct phosNbar { } //---------------------------------------- - bool minimizeCPA(nbar& n, track::TrackParametrization& pion, double& cpa, math_utils::Point3D& vtxV0, double& m, double& pt) + bool minimizeCPA(nbar& n, pion& pn, double& cpa, math_utils::Point3D& vtxV0, double& m, double& pt) { //-------------------------------------------------------------------- // Function finds optimal decay vertex where CPA (cosine of Pointing Angle) is maximal @@ -426,18 +735,20 @@ struct phosNbar { const double eps = 0.2; // accuracy of vertex reconstruction double xMax = 10., xMin = -10.; std::pair st[npoints]; + // operate on copy + o2::track::TrackParametrization tmpT(pn.mom); // Maximal number of minimization steps int nsteps = 20; while (nsteps && xMax - xMin > eps) { double dx = (xMax - xMin) / npoints; for (int i = 0; i < npoints; i++) { double t = xMin + dx * i; - pion.propagateTo(t, mBz); - vtxV0 = pion.getXYZGlo(); - float ptp = pion.getPt(); - float cs = cosf(pion.getAlpha()), sn = sinf(pion.getAlpha()); - float rp = std::sqrt((1.f - pion.getSnp()) * (1.f + pion.getSnp())); - math_utils::Vector3D pPi(ptp * (rp * cs - pion.getSnp() * sn), ptp * (pion.getSnp() * cs + rp * sn), ptp * pion.getTgl()); + tmpT.propagateTo(t, mBz); + vtxV0 = tmpT.getXYZGlo(); + float ptp = tmpT.getPt(); + float cs = cosf(tmpT.getAlpha()), sn = sinf(tmpT.getAlpha()); + float rp = std::sqrt((1.f - tmpT.getSnp()) * (1.f + tmpT.getSnp())); + math_utils::Vector3D pPi(ptp * (rp * cs - tmpT.getSnp() * sn), ptp * (tmpT.getSnp() * cs + rp * sn), ptp * tmpT.getTgl()); // recalculate Nbar momentum math_utils::Vector3D pNbar(n.x - vtxV0.x(), n.y - vtxV0.y(), n.z - vtxV0.z()); @@ -477,14 +788,14 @@ struct phosNbar { } nsteps--; } - pion.propagateTo(0.5 * (xMin + xMax), mBz); + tmpT.propagateTo(0.5 * (xMin + xMax), mBz); // calculate final CPA, Sigma inv mass using find pion and nbar momenta // may be re-calculate nbar |p| using reconstructed vertex - vtxV0 = pion.getXYZGlo(); - float ptp = pion.getPt(); - float cs = cosf(pion.getAlpha()), sn = sinf(pion.getAlpha()); - float rp = std::sqrt((1.f - pion.getSnp()) * (1.f + pion.getSnp())); - math_utils::Vector3D pPi(ptp * (rp * cs - pion.getSnp() * sn), ptp * (pion.getSnp() * cs + rp * sn), ptp * pion.getTgl()); + vtxV0 = tmpT.getXYZGlo(); + float ptp = tmpT.getPt(); + float cs = cosf(tmpT.getAlpha()), sn = sinf(tmpT.getAlpha()); + float rp = std::sqrt((1.f - tmpT.getSnp()) * (1.f + tmpT.getSnp())); + math_utils::Vector3D pPi(ptp * (rp * cs - tmpT.getSnp() * sn), ptp * (tmpT.getSnp() * cs + rp * sn), ptp * tmpT.getTgl()); // recalculate Nbar momentum math_utils::Vector3D pNbar(n.x - vtxV0.x(), n.y - vtxV0.y(), n.z - vtxV0.z()); @@ -509,6 +820,156 @@ struct phosNbar { return true; } + bool propagateToDCA(nbar& n, pion& pn, + double& cpa, double& dca, math_utils::Point3D& vtxV0, double& m, double& pt) + { + //-------------------------------------------------------------------- + // This function returns the DCA between the neutron and the track + // Proparate track to primary vertex, + // rotate perp. to nbar and propagate to minimal DCA vertex (in fact it will minimize distance in x) + const double k = (sqrt(5.) - 1.) / 2.; // 0.61803399 + const double minX = -10., maxX = 10.; + const double eps = 1.e-3; + double step = 1.; // initial step 1 cm + + o2::math_utils::Point3D vtxPrim(0., 0., mVtxZ); // Primary vertex + // unit vector in nbar direction + o2::math_utils::Vector3D pNbar(n.x - vtxPrim.x(), n.y - vtxPrim.y(), n.z - vtxPrim.z()); + pNbar /= sqrt(pNbar.Mag2()); // unit vector + + auto tmpT(pn.mom); // operate on the copy + // 1: find most probable position + double phiN = pNbar.phi(); + double xv = -vtxPrim.x() * sin(phiN) - vtxPrim.y() * cos(phiN); // Rotation by phiN+pi/2 + tmpT.rotateParam(phiN + 0.5 * o2::math_utils::pi()); // If rotation failed, it only increases number of iterations + if (!tmpT.propagateParamTo(xv, mBz)) { // Failed to propagate??? + return false; + } + vtxV0 = tmpT.getXYZGlo(); + dca = sqrt((vtxV0 - vtxPrim).Cross(pNbar).Mag2()); + + // 2: DCA(t) has V-shape. Find range around estimated minimum which has larger DCA + double x[4] = {xv - k * step, xv + (1. - 2. * k) * step, xv, xv + (1. - k) * step}; + double dcaP[4] = {dca, dca, dca, dca}; + for (int i = 0; i < 4; i++) { + if (i == 2) + continue; + if (!tmpT.propagateParamTo(x[i], mBz)) { + return false; + } + vtxV0 = tmpT.getXYZGlo(); + dcaP[i] = sqrt((vtxV0 - vtxPrim).Cross(pNbar).Mag2()); + } + while (dcaP[0] < dcaP[1]) { // too narrow range, should be expanded/shifted + x[2] = x[1]; + dcaP[2] = dcaP[1]; + x[1] = x[0]; + dcaP[1] = dcaP[0]; + x[0] = x[3] - (x[3] - x[0]) / k; + if (x[0] < minX) { + return false; // DCA too far from vertex + } + if (!tmpT.propagateParamTo(x[0], mBz)) { + return false; + } + vtxV0 = tmpT.getXYZGlo(); + dcaP[0] = sqrt((vtxV0 - vtxPrim).Cross(pNbar).Mag2()); + } + // same to the right + while (dcaP[3] < dcaP[2]) { + x[1] = x[2]; + dcaP[1] = dcaP[2]; + x[2] = x[3]; + dcaP[2] = dcaP[3]; + x[3] = x[0] + (x[3] - x[0]) / k; + if (x[3] > maxX) { + return false; // DCA too far from vertex + } + if (!tmpT.propagateParamTo(x[3], mBz)) { + return false; + } + vtxV0 = tmpT.getXYZGlo(); + dcaP[3] = sqrt((vtxV0 - vtxPrim).Cross(pNbar).Mag2()); + } + + // 3: minimize using golden section + math_utils::Point3D vtx[4]; + while (x[2] - x[1] > eps) { + if (dcaP[1] < dcaP[2]) { + x[3] = x[2]; + dcaP[3] = dcaP[2]; + x[2] = x[1]; + dcaP[2] = dcaP[1]; + x[1] = x[3] - k * (x[3] - x[0]); + if (!tmpT.propagateParamTo(x[1], mBz)) { + return false; + } + vtx[1] = tmpT.getXYZGlo(); + dcaP[1] = sqrt((vtx[1] - vtxPrim).Cross(pNbar).Mag2()); + } else { + x[0] = x[1]; + dcaP[0] = dcaP[1]; + x[1] = x[2]; + dcaP[1] = dcaP[2]; + x[2] = x[0] + k * (x[3] - x[0]); + if (!tmpT.propagateParamTo(x[2], mBz)) { + return false; + } + vtx[2] = tmpT.getXYZGlo(); + dcaP[2] = sqrt((vtx[2] - vtxPrim).Cross(pNbar).Mag2()); + } + } + if (dcaP[1] < dcaP[2]) { + vtxV0 = vtx[1]; + dca = dcaP[1]; + } else { + vtxV0 = vtx[2]; + dca = dcaP[2]; + } + + // calculate topological and kinematic parameters + // CPA, Sigma inv mass using find pion and nbar momenta + // may be re-calculate nbar |p| using reconstructed vertex + // tmpT was extrapolated last time to vtx + float ptp = tmpT.getPt(); + float cs = cosf(tmpT.getAlpha()), sn = sinf(tmpT.getAlpha()); + float rp = std::sqrt((1.f - tmpT.getSnp()) * (1.f + tmpT.getSnp())); + math_utils::Vector3D pPi(ptp * (rp * cs - tmpT.getSnp() * sn), ptp * (tmpT.getSnp() * cs + rp * sn), ptp * tmpT.getTgl()); + + // recalculate Nbar momentum + pNbar *= n.mom; + + math_utils::Vector3D pSum = pPi + pNbar; + double denom = sqrt(pSum.Mag2() * (vtxV0 - vtxPrim).Mag2()); + if (denom > 0) { + cpa = (vtxV0 - vtxPrim).Dot(pSum) / denom; + } else { // in primary vertex, step off a bit + cpa = -1.; + } + // m^2 = (E1+E2)^2 - (p1+p2)^2 = + double Epi2 = pPi.mag2() + mpi * mpi; + double En = pNbar.mag2() + mNbar * mNbar; + m = Epi2 + En + 2. * sqrt(Epi2 * En) - pSum.mag2(); + if (m > 0) + m = sqrt(m); + pt = pSum.Rho(); + // asymalpha = (pNbar.mag()-pPi.mag())/(pNbar.mag()+pPi.mag()); + return true; + } + bool isSigmaDaughter(int label, aod::McParticles const* mcParticles) + { + while (label > -1) { + auto parent = mcParticles->iteratorAt(label); + if ((parent.pdgCode() == -3112) || (parent.pdgCode() == -3222)) { + return true; + } + if (!parent.has_mothers() || parent.pdgCode() == 21 || abs(parent.pdgCode()) < 11 || abs(parent.pdgCode()) > 5000) { // no parents, parent not quark/gluon, strings + return false; + } + label = parent.mothersIds()[0]; + } + return false; + } void processData(SelCollision const& coll, aod::BCsWithTimestamps const&, aod::CaloClusters const& clusters, TrackCandidates const& tracks) { @@ -522,8 +983,8 @@ struct phosNbar { } PROCESS_SWITCH(phosNbar, processData, "process data", false); - void processMc(SelCollision const& coll, - aod::BCsWithTimestamps const&, mcClusters const& clusters, mcTracks const& tracks, aod::McParticles const& mcPart) + void processMC(SelCollisionMC const& coll, + aod::BCsWithTimestamps const&, mcClusters const& clusters, mcTracks const& tracks, aod::McParticles const& mcPart, aod::McCollisions const& /*mcCol*/) { // Initialize B-field if (mBz == 123456.) { @@ -533,7 +994,7 @@ struct phosNbar { } processAll(coll, tracks, clusters, &mcPart); } - PROCESS_SWITCH(phosNbar, processMc, "process MC", true); + PROCESS_SWITCH(phosNbar, processMC, "process MC", true); }; o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) diff --git a/PWGEM/Tasks/phosNonlin.cxx b/PWGEM/Tasks/phosNonlin.cxx index fc61b606e30..f25043c5f0c 100644 --- a/PWGEM/Tasks/phosNonlin.cxx +++ b/PWGEM/Tasks/phosNonlin.cxx @@ -9,17 +9,26 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file phosNonlin.cxx +/// \brief task to calculate PHOS non-lienarity based on pi0 peak position +/// \author Dmitri Peresunko +/// + +#include #include #include #include #include +#include #include -#include + #include #include "Common/DataModel/CaloClusters.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" #include "Framework/ConfigParamSpec.h" #include "Framework/runDataProcessing.h" @@ -34,26 +43,23 @@ #include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPLHCIFData.h" -/// \struct PHOS pi0 analysis -/// \brief Monitoring task for PHOS related quantities -/// \author Dmitri Peresunko, NRC "Kurchatov institute" -/// \since Nov, 2022 -/// - using namespace o2; using namespace o2::aod::evsel; using namespace o2::framework; using namespace o2::framework::expressions; -struct phosNonlin { - Configurable mEvSelTrig{"mEvSelTrig", kTVXinPHOS, "Select events with this trigger"}; - Configurable mMinCluE{"mMinCluE", 0.1, "Minimum cluster energy for analysis"}; - Configurable mMinCluTime{"minCluTime", -25.e-9, "Min. cluster time"}; - Configurable mMaxCluTime{"maxCluTime", 25.e-9, "Max. cluster time"}; - Configurable mMinCluNcell{"minCluNcell", 1, "min cells in cluster"}; - Configurable mMinM02{"minM02", 0.2, "Min disp M02 cut"}; - Configurable mNMixedEvents{"nMixedEvents", 2, "number of events to mix"}; - Configurable mSelectOneCollPerBC{"selectOneColPerBC", true, "skip multiple coll. per bc"}; +struct PhosNonlin { + Configurable skimmedProcessing{"skimmedProcessing", true, "Skimmed dataset processing"}; + Configurable trigName{"trigName", "fPHOSPhoton", "name of offline trigger"}; + Configurable zorroCCDBpath{"zorroCCDBpath", "/Users/m/mpuccio/EventFiltering/OTS/", "path to the zorro ccdb objects"}; + Configurable evSelTrig{"evSelTrig", kTVXinPHOS, "Select events with this trigger"}; + Configurable paramType{"paramType", 0, "Functional form 0: a-la data, 1: a-la MC"}; + Configurable minCluE{"minCluE", 0.1, "Minimum cluster energy for analysis"}; + Configurable minCluTime{"minCluTime", -25.e-9, "Min. cluster time"}; + Configurable maxCluTime{"maxCluTime", 25.e-9, "Max. cluster time"}; + Configurable minCluNcell{"minCluNcell", 1, "min cells in cluster"}; + Configurable minM02{"minM02", 0.2, "Min disp M02 cut"}; + Configurable nMixedEvents{"nMixedEvents", 2, "number of events to mix"}; Configurable mA{"mA", 9.34913e-01, "A"}; Configurable mdAi{"mdAi", 0., "A var. vs i"}; Configurable mdAj{"mdAj", 0., "A var. vs j"}; @@ -81,29 +87,34 @@ struct phosNonlin { using SelCollisions = soa::Join; using BCsWithBcSels = soa::Join; + o2::framework::Service ccdb; HistogramRegistry mHistManager1{"phosNonlinHistograms"}; + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + // class to keep photon candidate parameters - class photon : public TLorentzVector + class Photon : public TLorentzVector { public: - photon() = default; - photon(const photon& p) = default; - photon(double px, double py, double pz, double e, int m) : TLorentzVector(px, py, pz, e), mod(m) {} + Photon() = default; + Photon(const Photon& p) = default; + Photon(double px, double py, double pz, double e, int m) : TLorentzVector(px, py, pz, e), mod(m) {} public: int mod; }; + int mRunNumber = -1; // Current run number int mixedEventBin = 0; // Which list of Mixed use for mixing - std::vector mCurEvent; - static constexpr int nMaxMixBins = 10; // maximal number of kinds of events for mixing - std::array>, nMaxMixBins> mMixedEvents; + std::vector mCurEvent; + static constexpr int kMaxMixBins = 10; // maximal number of kinds of events for mixing + std::array>, kMaxMixBins> mMixedEvents; // fast access to histos - static constexpr int mNp = 10; - std::array hReIJ, hReKL, hReMIJ, hReMKL; + static constexpr int kNp = 10; + std::array hReIJ, hReKL, hReMIJ, hReMKL; TH2* hMi; std::vector pt = {0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.8, 0.85, 0.9, 0.95, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.5, 5.0, @@ -115,21 +126,26 @@ struct phosNonlin { { LOG(info) << "Initializing PHOS nonlin analysis task ..."; - const AxisSpec - ptAxis{pt, "p_{T} (GeV/c)"}, + zorroSummary.setObject(zorro.getZorroSummary()); + zorro.setBaseCCDBPath(zorroCCDBpath.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + const AxisSpec ptAxis{pt, "p_{T} (GeV/c)"}, mggAxis{150, 0., 0.3, "m_{#gamma#gamma} (GeV/c^{2})"}; - for (int i = 0; i < mNp; i++) { - for (int j = 0; j < mNp; j++) { - hReIJ[i * mNp + j] = std::get>(mHistManager1.add(Form("hRe_a%d_b%d", i, j), "inv mass", + for (int i = 0; i < kNp; i++) { + for (int j = 0; j < kNp; j++) { + hReIJ[i * kNp + j] = std::get>(mHistManager1.add(Form("hRe_a%d_b%d", i, j), "inv mass", HistType::kTH2F, {mggAxis, ptAxis})) .get(); - hReKL[i * mNp + j] = std::get>(mHistManager1.add(Form("hRe_c%d_d%d", i, j), "inv mass", + hReKL[i * kNp + j] = std::get>(mHistManager1.add(Form("hRe_c%d_d%d", i, j), "inv mass", HistType::kTH2F, {mggAxis, ptAxis})) .get(); - // hReMIJ[i*mNp+j] = std::get>(mHistManager2.add(Form("hReM_a%d_b%d",i,j), "inv mass", + // hReMIJ[i*kNp+j] = std::get>(mHistManager2.add(Form("hReM_a%d_b%d",i,j), "inv mass", // HistType::kTH2F, {mggAxis, ptAxis})).get(); - // hReMKL[i*mNp+j] = std::get>(mHistManager2.add(Form("hReM_c%d_d%d",i,j), "inv mass", + // hReMKL[i*kNp+j] = std::get>(mHistManager2.add(Form("hReM_c%d_d%d",i,j), "inv mass", // HistType::kTH2F, {mggAxis, ptAxis})).get(); } } @@ -140,57 +156,71 @@ struct phosNonlin { /// \brief Process PHOS data void process(SelCollisions::iterator const& col, - aod::CaloClusters const& clusters) + aod::CaloClusters const& clusters, + aod::BCsWithTimestamps const&) { // Fill number of events of different kind - if (!col.alias_bit(mEvSelTrig)) { - return; + if (skimmedProcessing) { + auto bc = col.template bc_as(); + if (mRunNumber != bc.runNumber()) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), trigName); + zorro.populateHistRegistry(mHistManager1, bc.runNumber()); + mRunNumber = bc.runNumber(); + } + + if (!zorro.isSelected(bc.globalBC())) { + return; /// + } + } else { + if (!col.selection_bit(evSelTrig)) { + return; + } } mixedEventBin = findMixedEventBin(col.posZ()); mCurEvent.clear(); int i, j, k, l; - for (const auto& clu : clusters) { - if (clu.e() < mMinCluE || - clu.ncell() < mMinCluNcell || - clu.time() > mMaxCluTime || clu.time() < mMinCluTime || - clu.m02() < mMinM02) { + for (auto const& clu : clusters) { + if (clu.e() < minCluE || + clu.ncell() < minCluNcell || + clu.time() > maxCluTime || clu.time() < minCluTime || + clu.m02() < minM02) { continue; } - photon ph1(clu.px(), clu.py(), clu.pz(), clu.e(), clu.mod()); + Photon ph1(clu.px(), clu.py(), clu.pz(), clu.e(), clu.mod()); // Mix with other photons added to stack - for (auto ph2 : mCurEvent) { + for (auto const& ph2 : mCurEvent) { double m = (ph1 + ph2).M(); double pt1 = ph1.Pt(); double pt2 = ph2.Pt(); - k = mNp / 2; - l = mNp / 2; - for (i = 0; i < mNp; i++) { - for (j = 0; j < mNp; j++) { - if (ph1.E() * NonLin(ph1.E(), i, j, k, l) > mMinCluE && ph2.E() * NonLin(ph2.E(), i, j, k, l) > mMinCluE) { - Double_t m12 = m * TMath::Sqrt(NonLin(ph1.E(), i, j, k, l) * NonLin(ph2.E(), i, j, k, l)); - hReIJ[i * mNp + j]->Fill(m12, pt1); - hReIJ[i * mNp + j]->Fill(m12, pt2); + k = kNp / 2; + l = kNp / 2; + for (i = 0; i < kNp; i++) { + for (j = 0; j < kNp; j++) { + if (ph1.E() * nonLin(ph1.E(), i, j, k, l) > minCluE && ph2.E() * nonLin(ph2.E(), i, j, k, l) > minCluE) { + double m12 = m * std::sqrt(nonLin(ph1.E(), i, j, k, l) * nonLin(ph2.E(), i, j, k, l)); + hReIJ[i * kNp + j]->Fill(m12, pt1); + hReIJ[i * kNp + j]->Fill(m12, pt2); // if(ph1.mod==ph2.mod){ - // hReMIJ[i*mNp + j]->Fill(m12,pt1); - // hReMIJ[i*mNp + j]->Fill(m12,pt2); + // hReMIJ[i*kNp + j]->Fill(m12,pt1); + // hReMIJ[i*kNp + j]->Fill(m12,pt2); // } } } } - i = mNp / 2; - j = mNp / 2; - for (k = 0; k < mNp; k++) { - for (l = 0; l < mNp; l++) { - if (ph1.E() * NonLin(ph1.E(), i, j, k, l) > mMinCluE && ph2.E() * NonLin(ph2.E(), i, j, k, l) > mMinCluE) { - Double_t m12 = m * TMath::Sqrt(NonLin(ph1.E(), i, j, k, l) * NonLin(ph2.E(), i, j, k, l)); - hReKL[k * mNp + l]->Fill(m12, pt1); - hReKL[k * mNp + l]->Fill(m12, pt2); + i = kNp / 2; + j = kNp / 2; + for (k = 0; k < kNp; k++) { + for (l = 0; l < kNp; l++) { + if (ph1.E() * nonLin(ph1.E(), i, j, k, l) > minCluE && ph2.E() * nonLin(ph2.E(), i, j, k, l) > minCluE) { + double m12 = m * std::sqrt(nonLin(ph1.E(), i, j, k, l) * nonLin(ph2.E(), i, j, k, l)); + hReKL[k * kNp + l]->Fill(m12, pt1); + hReKL[k * kNp + l]->Fill(m12, pt2); // if(ph1.mod==ph2.mod){ - // hReMKL[k*mNp + l]->Fill(m12,pt1); - // hReMKL[k*mNp + l]->Fill(m12,pt2); + // hReMKL[k*kNp + l]->Fill(m12,pt1); + // hReMKL[k*kNp + l]->Fill(m12,pt2); // } } } @@ -201,19 +231,19 @@ struct phosNonlin { } // Mixed - for (auto ph1 : mCurEvent) { - for (auto mixEvent : mMixedEvents[mixedEventBin]) { - for (auto ph2 : mixEvent) { + for (const auto& ph1 : mCurEvent) { + for (const auto& mixEvent : mMixedEvents[mixedEventBin]) { + for (const auto& ph2 : mixEvent) { double m = (ph1 + ph2).M(); double pt1 = ph1.Pt(); double pt2 = ph2.Pt(); - i = mNp / 2; - j = mNp / 2; - k = mNp / 2; - l = mNp / 2; - if (ph1.E() * NonLin(ph1.E(), i, j, k, l) > mMinCluE && ph2.E() * NonLin(ph2.E(), i, j, k, l) > mMinCluE) { - Double_t m12 = m * TMath::Sqrt(NonLin(ph1.E(), i, j, k, l) * NonLin(ph2.E(), i, j, k, l)); + i = kNp / 2; + j = kNp / 2; + k = kNp / 2; + l = kNp / 2; + if (ph1.E() * nonLin(ph1.E(), i, j, k, l) > minCluE && ph2.E() * nonLin(ph2.E(), i, j, k, l) > minCluE) { + double m12 = m * std::sqrt(nonLin(ph1.E(), i, j, k, l) * nonLin(ph2.E(), i, j, k, l)); hMi->Fill(m12, pt1); hMi->Fill(m12, pt2); } @@ -224,7 +254,7 @@ struct phosNonlin { // Fill events to store and remove oldest to keep buffer size if (mCurEvent.size() > 0) { mMixedEvents[mixedEventBin].emplace_back(mCurEvent); - if (mMixedEvents[mixedEventBin].size() > static_cast(mNMixedEvents)) { + if (mMixedEvents[mixedEventBin].size() > static_cast(nMixedEvents)) { mMixedEvents[mixedEventBin].pop_front(); } } @@ -239,29 +269,40 @@ struct phosNonlin { if (res < 0) return 0; - if (res >= nMaxMixBins) - return nMaxMixBins - 1; + if (res >= kMaxMixBins) + return kMaxMixBins - 1; return res; } //_____________________________________________________________________________ - double NonLin(double en, int i, int j, int k, int l) + double nonLin(double en, int i, int j, int k, int l) { if (en <= 0.) return 0.; - const Double_t a = mA + mdAi * (i - mNp / 2) + mdAj * (j - mNp / 2); - const Double_t b = mB + mdBi * (i - mNp / 2) + mdBj * (j - mNp / 2); - const Double_t c = mC + mdCi * (i - mNp / 2) + mdCj * (j - mNp / 2); - const Double_t d = mD + mdDk * (k - mNp / 2) + mdDl * (l - mNp / 2); - const Double_t e = mE + mdEk * (k - mNp / 2) + mdEl * (l - mNp / 2); - const Double_t f = mF + mdFk * (k - mNp / 2) + mdFl * (l - mNp / 2); - const Double_t g = mG + mdGk * (k - mNp / 2) + mdGl * (l - mNp / 2); - const Double_t s = mS + mdSi * (i - mNp / 2) + mdSj * (j - mNp / 2); - return a + b / en + c / (en * en) + d / ((en - e) * (en - e) + f * f) + g * en + s / (en * en * en * en); + if (paramType == 0) { + const double a = mA + mdAi * (i - kNp / 2) + mdAj * (j - kNp / 2); + const double b = mB + mdBi * (i - kNp / 2) + mdBj * (j - kNp / 2); + const double c = mC + mdCi * (i - kNp / 2) + mdCj * (j - kNp / 2); + const double d = mD + mdDk * (k - kNp / 2) + mdDl * (l - kNp / 2); + const double e = mE + mdEk * (k - kNp / 2) + mdEl * (l - kNp / 2); + const double f = mF + mdFk * (k - kNp / 2) + mdFl * (l - kNp / 2); + const double g = mG + mdGk * (k - kNp / 2) + mdGl * (l - kNp / 2); + const double s = mS + mdSi * (i - kNp / 2) + mdSj * (j - kNp / 2); + return a + b / en + c / (en * en) + d / ((en - e) * (en - e) + f * f) + g * en + s / (en * en * en * en); + } + if (paramType == 1) { + const double a = mA + mdAi * (i - kNp / 2) + mdAj * (j - kNp / 2); + const double b = mB + mdBi * (i - kNp / 2) + mdBj * (j - kNp / 2); + const double c = mC + mdCi * (i - kNp / 2) + mdCj * (j - kNp / 2); + const double d = mD + mdDk * (k - kNp / 2) + mdDl * (l - kNp / 2); + const double e = mE + mdEk * (k - kNp / 2) + mdEl * (l - kNp / 2); + return a + b / std::sqrt(en) + c / en + d / (en * std::sqrt(en)) + e / (en * en); + } + return 0.; } }; o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) { return o2::framework::WorkflowSpec{ - o2::framework::adaptAnalysisTask(cfgc)}; + o2::framework::adaptAnalysisTask(cfgc)}; } diff --git a/PWGEM/Tasks/phosPi0.cxx b/PWGEM/Tasks/phosPi0.cxx index 9fe57ba1bb3..a47aaa0d485 100644 --- a/PWGEM/Tasks/phosPi0.cxx +++ b/PWGEM/Tasks/phosPi0.cxx @@ -9,11 +9,19 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file phosPi0.cxx +/// \brief PHOS pi0/eta analysis +/// \author Dmitri Peresunko +/// + +#include #include #include #include #include +#include #include + #include "Common/DataModel/CaloClusters.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" @@ -27,94 +35,108 @@ #include "Framework/ASoAHelpers.h" #include "Framework/HistogramRegistry.h" +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" + #include "PHOSBase/Geometry.h" #include "CommonDataFormat/InteractionRecord.h" #include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPLHCIFData.h" -/// \struct PHOS pi0 analysis -/// \brief Monitoring task for PHOS related quantities -/// \author Dmitri Peresunko, NRC "Kurchatov institute" -/// \since Nov, 2022 -/// - using namespace o2; using namespace o2::aod::evsel; using namespace o2::framework; using namespace o2::framework::expressions; -struct phosPi0 { - Configurable mIsMC{"isMC", false, "to fill MC histograms"}; - Configurable mEvSelTrig{"mEvSelTrig", kTVXinPHOS, "Select events with this trigger"}; - Configurable mMinCluE{"mMinCluE", 0.3, "Minimum cluster energy for analysis"}; - Configurable mMinCluTime{"minCluTime", -25.e-9, "Min. cluster time"}; - Configurable mMaxCluTime{"maxCluTime", 25.e-9, "Max. cluster time"}; - Configurable mMinCluNcell{"minCluNcell", 2, "min cells in cluster"}; - Configurable mMinM02{"minM02", 0.2, "Min disp M02 cut"}; - Configurable mCPVCut{"CPVCut", 2., "Min distance to track"}; - Configurable mNMixedEvents{"nMixedEvents", 10, "number of events to mix"}; - Configurable mSelectOneCollPerBC{"selectOneColPerBC", true, "skip multiple coll. per bc"}; - Configurable mFillQC{"fillQC", true, "Fill QC histos"}; - Configurable mOccE{"minOccE", 0.5, "Min. cluster energy of occupancy plots"}; +struct PhosPi0 { + Configurable skimmedProcessing{"skimmedProcessing", false, "Skimmed dataset processing"}; + Configurable trigName{"trigName", "fPHOSPhoton", "name of offline trigger"}; + Configurable zorroCCDBpath{"zorroCCDBpath", "/Users/m/mpuccio/EventFiltering/OTS/", "path to the zorro ccdb objects"}; + Configurable evSelTrig{"evSelTrig", aod::evsel::kIsTriggerTVX, "Select events with this trigger"}; + Configurable isMC{"isMC", false, "to fill MC histograms"}; + Configurable minCluE{"minCluE", 0.3, "Minimum cluster energy for analysis"}; + Configurable minCluTime{"minCluTime", -25.e-9, "Min. cluster time"}; + Configurable maxCluTime{"maxCluTime", 25.e-9, "Max. cluster time"}; + Configurable minCluNcell{"minCluNcell", 2, "min cells in cluster"}; + Configurable minM02{"minM02", 0.2, "Min disp M02 cut"}; + Configurable cpvCut{"cpvCut", 2., "Min distance to track"}; + Configurable nMixedEvents{"nMixedEvents", 10, "number of events to mix"}; + Configurable fillQC{"fillQC", true, "Fill QC histos"}; + Configurable minOccE{"minOccE", 0.5, "Min. cluster energy of occupancy plots"}; + Configurable nonlinA{"nonlinA", 1., "nonlinsrity param A (scale)"}; + Configurable nonlinB{"nonlinB", 0., "nonlinsrity param B (a+b*exp(-e/c))"}; + Configurable nonlinC{"nonlinC", 1., "nonlinsrity param C (a+b*exp(-e/c))"}; + Configurable tofEffParam{"tofEffParam", 0, "parameterization of TOF cut efficiency"}; + Configurable timeOffset{"timeOffset", 0., "time offset to compensate imperfection of time calibration"}; using SelCollisions = soa::Join; + using SelCollisionsMC = soa::Join; using BCsWithBcSels = soa::Join; - using mcClusters = soa::Join; - using mcAmbClusters = soa::Join; + using McClusters = soa::Join; + using McAmbClusters = soa::Join; o2::framework::Service ccdb; + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; - HistogramRegistry mHistManager{"phosPi0Histograms"}; + HistogramRegistry mHistManager{"PHOSPi0Histograms"}; // class to keep photon candidate parameters - class photon + class Photon { public: - photon() = default; - photon(double x, double y, double z, double ee, int m, bool isDispOK, bool isCPVOK, int mcLabel) : px(x), py(y), pz(z), e(ee), mod(m), mPID(isDispOK << 1 | isCPVOK << 2), label(mcLabel) {} - ~photon() = default; + Photon() = default; + Photon(double x, double y, double z, double ee, double t, int m, bool isDispOK, bool isCPVOK, int mcLabel) : px(x), py(y), pz(z), e(ee), time(t), mod(m), mPID(isDispOK << 1 | isCPVOK << 2), label(mcLabel) {} + ~Photon() = default; - bool isCPVOK() { return (mPID >> 2) & 1; } - bool isDispOK() { return (mPID >> 1) & 1; } + bool isCPVOK() const { return (mPID >> 2) & 1; } + bool isDispOK() const { return (mPID >> 1) & 1; } + double pt() const { return std::sqrt(px * px + py * py); } public: - double px = 0.; // px - double py = 0.; // py - double pz = 0.; // pz - double e = 0.; // energy - int mod = 0; // module - int mPID = 0; // store PID bits - int label = -1; // label of MC particle + double px = 0.; // px + double py = 0.; // py + double pz = 0.; // pz + double e = 0.; // energy + double time = 0.; // time + int mod = 0; // module + int mPID = 0; // store PID bits + int label = -1; // label of MC particle }; + int mRunNumber = 0; // Current run number int mixedEventBin = 0; // Which list of Mixed use for mixing - std::vector mCurEvent; - static constexpr int nMaxMixBins = 20; // maximal number of kinds of events for mixing - std::array>, nMaxMixBins> mMixedEvents; - std::array>, nMaxMixBins> mAmbMixedEvents; + std::vector mCurEvent; + static constexpr int kMaxMixBins = 20; // maximal number of kinds of events for mixing + std::array>, kMaxMixBins> mMixedEvents; + std::array>, kMaxMixBins> mAmbMixedEvents; int mPrevMCColId = -1; // mark MC collissions already scanned // fast access to histos + TH1* hColl; TH3 *hReMod, *hMiMod; TH2 *hReAll, *hReDisp, *hReCPV, *hReBoth, *hSignalAll, *hPi0SignalAll, *hPi0SignalCPV, *hPi0SignalDisp, *hPi0SignalBoth, *hMiAll, *hMiDisp, *hMiCPV, *hMiBoth; + TH2 *hReOneAll, *hReOneDisp, *hReOneCPV, *hReOneBoth, *hMiOneAll, *hMiOneDisp, *hMiOneCPV, *hMiOneBoth; + TH2 *hReTime12, *hReTime30, *hReTime50, *hReTime100; - std::vector pt = {0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.8, 0.85, 0.9, 0.95, 1.0, 1.1, 1.2, - 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.5, 5.0, - 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 10., 11., 12., 13., 14., 15., 16., 18., 20., 22., 24., 26., 28., - 30., 34., 38., 42., 46., 50., 55., 60., 70., 80., 90., 100., 110., 120., 150.}; + std::vector pt = {0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, 1.1, + 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.5, 4.6, 4.8, 5.0, + 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10., 11., 12., 13., 14., 15., 16., 17., 18., 19., 20., 22., 24., 26., 28., + 30., 34., 38., 42., 46., 50., 55., 60., 70., 75., 80., 85., 90., 95., 100., 110., 120., 130., 140., 150., 160., 180., 200.}; /// \brief Create output histograms void init(InitContext const&) { LOG(info) << "Initializing PHOS pi0 analysis task ..."; + zorroSummary.setObject(zorro.getZorroSummary()); + zorro.setBaseCCDBPath(zorroCCDBpath.value); - const AxisSpec - ptAxis{pt, "p_{T} (GeV/c)"}, + const AxisSpec ptAxis{pt, "p_{T} (GeV/c)"}, mggAxis{625, 0., 1.25, "m_{#gamma#gamma} (GeV/c^{2})"}, timeAxis{100, -500.e-9, 500.e-9, "t (s)"}, - M02Axis{100, 0., 20., "M02 (cm^{2})"}, - M20Axis{100, 0., 20., "M20 (cm^{2})"}, + m02Axis{100, 0., 20., "M02 (cm^{2})"}, + m20Axis{100, 0., 20., "M20 (cm^{2})"}, nCellsAxis{100, 0., 100., "N_{cell}"}, zAxis{56, -63., 63., "z", "z (cm)"}, phiAxis{64, -72., 72., "x", "x (cm)"}, @@ -125,16 +147,16 @@ struct phosPi0 { centAxis{10, 0., 10.}, centralityAxis{100, 0., 100., "centrality", "centrality"}; - auto h{std::get>(mHistManager.add("eventsCol", "Number of events", HistType::kTH1F, {{9, 0., 9.}}))}; - h->GetXaxis()->SetBinLabel(1, "All"); - h->GetXaxis()->SetBinLabel(2, "T0a||T0c"); - h->GetXaxis()->SetBinLabel(3, "T0a&&T0c"); - h->GetXaxis()->SetBinLabel(4, "alias kTVXinPHOS"); - h->GetXaxis()->SetBinLabel(5, "kIsTriggerTVX"); - h->GetXaxis()->SetBinLabel(6, "kTVXinPHOS"); - h->GetXaxis()->SetBinLabel(7, "PHOSClu"); - h->GetXaxis()->SetBinLabel(8, "PHOSClu&&Trig"); - h->GetXaxis()->SetBinLabel(9, "PHOSClu&&Trig&&BB"); + hColl = std::get>(mHistManager.add("eventsCol", "Number of events", HistType::kTH1F, {{10, 0., 10.}})).get(); + hColl->GetXaxis()->SetBinLabel(1, "All"); + hColl->GetXaxis()->SetBinLabel(2, "SwTr"); + hColl->GetXaxis()->SetBinLabel(3, "T0a||T0c"); + hColl->GetXaxis()->SetBinLabel(4, "T0a&&T0c"); + hColl->GetXaxis()->SetBinLabel(5, "kTVXinPHOS"); + hColl->GetXaxis()->SetBinLabel(6, "kIsTriggerTVX"); + hColl->GetXaxis()->SetBinLabel(7, "PHOSClu"); + hColl->GetXaxis()->SetBinLabel(8, "PHOSClu&&kTVXinPHOS"); + hColl->GetXaxis()->SetBinLabel(9, "Accepted"); auto h2{std::get>(mHistManager.add("eventsBC", "Number of events per trigger", HistType::kTH1F, {{8, 0., 8.}}))}; h2->GetXaxis()->SetBinLabel(1, "All"); @@ -147,16 +169,16 @@ struct phosPi0 { h2->GetXaxis()->SetBinLabel(8, "PHOSClu&&Trig"); mHistManager.add("contributors", "Contributors per collision", HistType::kTH2F, {{10, 0., 10.}, {10, 0., 100.}}); - mHistManager.add("vertex", "vertex", HistType::kTH2F, {{10, 0., 10.}, vertexAxis}); + mHistManager.add("vertex", "vertex", HistType::kTH1F, {vertexAxis}); - if (mFillQC) { + if (fillQC) { // QC histograms for normal collisions mHistManager.add("cluSp", "Cluster spectrum per module", HistType::kTH2F, {ptAxis, modAxis}); mHistManager.add("cluSpDisp", "Cluster spectrum per module", HistType::kTH2F, {ptAxis, modAxis}); mHistManager.add("cluSpCPV", "Cluster spectrum per module", HistType::kTH2F, {ptAxis, modAxis}); mHistManager.add("cluSpBoth", "Cluster spectrum per module", HistType::kTH2F, {ptAxis, modAxis}); - mHistManager.add("hM02Clu", "(M02,M20) in clusters", HistType::kTH2F, {ptAxis, M02Axis}); - mHistManager.add("hM20Clu", "(M02,M20) in clusters", HistType::kTH2F, {ptAxis, M20Axis}); + mHistManager.add("hM02Clu", "(M02,M20) in clusters", HistType::kTH2F, {ptAxis, m02Axis}); + mHistManager.add("hM20Clu", "(M02,M20) in clusters", HistType::kTH2F, {ptAxis, m20Axis}); mHistManager.add("hNcellClu", "Number of cells in clusters", HistType::kTH3F, {ptAxis, nCellsAxis, modAxis}); mHistManager.add("cluETime", "Cluster time vs E", HistType::kTH3F, {ptAxis, timeAxis, modAxis}); @@ -181,8 +203,33 @@ struct phosPi0 { hReBoth = std::get>(mHistManager.add("mggReBoth", "inv mass for centrality", HistType::kTH2F, {mggAxis, ptAxis})) .get(); - - if (mIsMC) { + hReOneAll = std::get>(mHistManager.add("mggReOneAll", "inv mass for centrality", + HistType::kTH2F, {mggAxis, ptAxis})) + .get(); + hReOneCPV = std::get>(mHistManager.add("mggReOneCPV", "inv mass for centrality", + HistType::kTH2F, {mggAxis, ptAxis})) + .get(); + hReOneDisp = std::get>(mHistManager.add("mggReOneDisp", "inv mass for centrality", + HistType::kTH2F, {mggAxis, ptAxis})) + .get(); + hReOneBoth = std::get>(mHistManager.add("mggReOneBoth", "inv mass for centrality", + HistType::kTH2F, {mggAxis, ptAxis})) + .get(); + + hReTime12 = std::get>(mHistManager.add("mggReTime12", "inv mass for centrality", + HistType::kTH2F, {mggAxis, ptAxis})) + .get(); + hReTime30 = std::get>(mHistManager.add("mggReTime30", "inv mass for centrality", + HistType::kTH2F, {mggAxis, ptAxis})) + .get(); + hReTime50 = std::get>(mHistManager.add("mggReTime50", "inv mass for centrality", + HistType::kTH2F, {mggAxis, ptAxis})) + .get(); + hReTime100 = std::get>(mHistManager.add("mggReTime100", "inv mass for centrality", + HistType::kTH2F, {mggAxis, ptAxis})) + .get(); + + if (isMC) { hSignalAll = std::get>(mHistManager.add("mggSignal", "inv mass for correlated pairs", HistType::kTH2F, {mggAxis, ptAxis})) .get(); @@ -215,92 +262,203 @@ struct phosPi0 { hMiBoth = std::get>(mHistManager.add("mggMiBoth", "inv mass for centrality", HistType::kTH2F, {mggAxis, ptAxis})) .get(); - if (mIsMC) { + hMiOneAll = std::get>(mHistManager.add("mggMiOneAll", "inv mass for centrality", + HistType::kTH2F, {mggAxis, ptAxis})) + .get(); + hMiOneCPV = std::get>(mHistManager.add("mggMiOneCPV", "inv mass for centrality", + HistType::kTH2F, {mggAxis, ptAxis})) + .get(); + hMiOneDisp = std::get>(mHistManager.add("mggMiOneDisp", "inv mass for centrality", + HistType::kTH2F, {mggAxis, ptAxis})) + .get(); + hMiOneBoth = std::get>(mHistManager.add("mggMiOneBoth", "inv mass for centrality", + HistType::kTH2F, {mggAxis, ptAxis})) + .get(); + if (isMC) { mHistManager.add("hMCPi0SpAll", "pi0 spectrum inclusive", HistType::kTH1F, {ptAxis}); mHistManager.add("hMCPi0SpPrim", "pi0 spectrum Primary", HistType::kTH1F, {ptAxis}); mHistManager.add("hMCPi0RapPrim", "pi0 rapidity primary", HistType::kTH1F, {{100, -1., 1., "Rapidity"}}); - mHistManager.add("hMCPi0PhiPrim", "pi0 phi primary", HistType::kTH1F, {{100, 0., TMath::TwoPi(), "#phi (rad)"}}); - mHistManager.add("hMCPi0SecVtx", "pi0 secondary", HistType::kTH2F, {{100, 0., 500., "Rapidity"}, {100, 0., TMath::TwoPi(), "#phi (rad)"}}); + mHistManager.add("hMCPi0PhiPrim", "pi0 phi primary", HistType::kTH1F, {{100, 0., o2::constants::math::TwoPI, "#phi (rad)"}}); + mHistManager.add("hMCPi0SecVtx", "pi0 secondary", HistType::kTH2F, {{100, 0., 500., "R (cm)"}, {100, -o2::constants::math::PI, o2::constants::math::PI, "#phi (rad)"}}); } } + // template + // float getCentrality(Tcoll const& collision) + // { + // float centrality = 1.; + // if constexpr (std::is_same::value || std::is_same::value || std::is_same::value) { + // if (cfgCentralityEstimator == nuclei::centDetectors::kFV0A) { + // centrality = collision.centFV0A(); + // } else if (cfgCentralityEstimator == nuclei::centDetectors::kFT0M) { + // centrality = collision.centFT0M(); + // } else if (cfgCentralityEstimator == nuclei::centDetectors::kFT0A) { + // centrality = collision.centFT0A(); + // } else if (cfgCentralityEstimator == nuclei::centDetectors::kFT0C) { + // centrality = collision.centFT0C(); + // } else { + // LOG(warning) << "Centrality estimator not valid. Possible values: (FV0A: 0, FT0M: 1, FT0A: 2, FT0C: 3). Centrality set to 1."; + // } + // } + // return centrality; + // } + /// \brief Process PHOS data void processData(SelCollisions::iterator const& col, - aod::CaloClusters const& clusters) + aod::CaloClusters const& clusters, + aod::BCsWithTimestamps const&) { aod::McParticles const* mcPart = nullptr; - processAll(col, clusters, mcPart); + scanAll(col, clusters, mcPart); } - PROCESS_SWITCH(phosPi0, processData, "process data", true); - void processMC(SelCollisions::iterator const& col, - mcClusters const& clusters, - aod::McParticles const& mcPart) + PROCESS_SWITCH(PhosPi0, processData, "processData", true); + void processMC(SelCollisionsMC::iterator const& col, + McClusters const& clusters, + aod::McParticles const& mcPart, + aod::McCollisions const& /*mcCol*/, + aod::BCsWithTimestamps const&) { - processAll(col, clusters, &mcPart); + scanAll(col, clusters, &mcPart); } - PROCESS_SWITCH(phosPi0, processMC, "process MC", false); + PROCESS_SWITCH(PhosPi0, processMC, "processMC", false); template - void processAll(TCollision& col, - TClusters& clusters, - aod::McParticles const* mcPart) + void scanAll(TCollision& col, + TClusters& clusters, + aod::McParticles const* mcPart) { - bool isColSelected = false; mixedEventBin = 0; + hColl->Fill(0.5); + if (skimmedProcessing) { + auto bc = col.template bc_as(); + if (mRunNumber != bc.runNumber()) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), trigName); + zorro.populateHistRegistry(mHistManager, bc.runNumber()); + mRunNumber = bc.runNumber(); + } + + if (!zorro.isSelected(bc.globalBC())) { + return; /// + } + } else { + if (!col.selection_bit(evSelTrig)) { + return; + } + } + + hColl->Fill(1.5); + const double vtxCut = 10.; + double vtxZ = col.posZ(); + mHistManager.fill(HIST("vertex"), vtxZ); + bool isColSelected = false; + if constexpr (isMC) { + isColSelected = (col.selection_bit(kIsTriggerTVX) && (clusters.size() > 0)); + } else { + isColSelected = col.selection_bit(evSelTrig) && std::abs(vtxZ) < vtxCut; // col.alias_bit(evSelTrig) + // collision.selection_bit(aod::evsel::kNoTimeFrameBorder); + } - mHistManager.fill(HIST("eventsCol"), 0.); if (col.selection_bit(kIsBBT0A) || col.selection_bit(kIsBBT0C)) { - mHistManager.fill(HIST("eventsCol"), 1.); + hColl->Fill(2.5); } if (col.selection_bit(kIsBBT0A) && col.selection_bit(kIsBBT0C)) { - mHistManager.fill(HIST("eventsCol"), 2.); + hColl->Fill(3.5); } if (col.alias_bit(kTVXinPHOS)) { - mHistManager.fill(HIST("eventsCol"), 3.); + hColl->Fill(4.5); } if (col.selection_bit(kIsTriggerTVX)) { - mHistManager.fill(HIST("eventsCol"), 4.); - } - if (col.alias_bit(kTVXinPHOS)) { - mHistManager.fill(HIST("eventsCol"), 5.); + hColl->Fill(5.5); } if (clusters.size() > 0) { - mHistManager.fill(HIST("eventsCol"), 6); + hColl->Fill(6.5); if (col.alias_bit(kTVXinPHOS)) { - mHistManager.fill(HIST("eventsCol"), 7); + hColl->Fill(7.5); } } - isColSelected = col.alias_bit(mEvSelTrig); - double vtxZ = col.posZ(); + // //Event Plane| jet orientation + // if (flag & (kProton | kDeuteron | kTriton | kHe3 | kHe4) || doprocessMC) { /// ignore PID pre-selections for the MC + // if constexpr (std::is_same::value) { + // nuclei::candidates_flow.emplace_back(NucleusCandidateFlow{ + // collision.centFV0A(), + // collision.centFT0M(), + // collision.centFT0A(), + // collision.centFT0C(), + // collision.psiFT0A(), + // collision.multFT0A(), + // collision.psiFT0C(), + // collision.multFT0C(), + // collision.psiTPC(), + // collision.psiTPCL(), + // collision.psiTPCR(), + // collision.multTPC()}); + // } else if constexpr (std::is_same::value) { + // nuclei::candidates_flow.emplace_back(NucleusCandidateFlow{ + // collision.centFV0A(), + // collision.centFT0M(), + // collision.centFT0A(), + // collision.centFT0C(), + // 0.5 * std::atan2(collision.qvecFT0AIm(), collision.qvecFT0ARe()), + // collision.multFT0A(), + // 0.5 * std::atan2(collision.qvecFT0CIm(), collision.qvecFT0CRe()), + // collision.multFT0C(), + // -999., + // 0.5 * std::atan2(collision.qvecBNegIm(), collision.qvecBNegRe()), + // 0.5 * std::atan2(collision.qvecBPosIm(), collision.qvecBPosRe()), + // collision.multTPC()}); + // } + int mult = 1.; // multiplicity TODO!!! mixedEventBin = findMixedEventBin(vtxZ, mult); - if constexpr (isMC) { - isColSelected = true; // aliaces do not work in MC??? - } - if (!isColSelected) { return; } + hColl->Fill(8.5); // Fill MC distributions // pion rapidity, pt, phi // secondary pi0s if constexpr (isMC) { + // check current collision Id for clusters + int cluMcBCId = -1; + for (const auto& clu : clusters) { + auto mcList = clu.labels(); // const std::vector + int nParents = mcList.size(); + for (int iParent = 0; iParent < nParents; iParent++) { // Not found nbar parent yiet + int label = mcList[iParent]; + if (label > -1) { + auto parent = mcPart->iteratorAt(label); + cluMcBCId = parent.mcCollision().bcId(); + break; + } + } + if (cluMcBCId > -1) { + break; + } + } if (mcPart->begin() != mcPart->end()) { if (mcPart->begin().mcCollisionId() != mPrevMCColId) { mPrevMCColId = mcPart->begin().mcCollisionId(); // to avoid scanning full MC table each BC - for (auto part : *mcPart) { + for (const auto& part : *mcPart) { + if (part.mcCollision().bcId() != col.bcId()) { + continue; + } if (part.pdgCode() == 111) { - double pt = part.pt(); - mHistManager.fill(HIST("hMCPi0SpAll"), pt); - double r = sqrt(pow(part.vx(), 2) + pow(part.vy(), 2)); - double phiVtx = atan2(part.vy(), part.vx()); - mHistManager.fill(HIST("hMCPi0SecVtx"), r, phiVtx); + double r = std::sqrt(std::pow(part.vx(), 2) + std::pow(part.vy(), 2)); if (r < 0.5) { - mHistManager.fill(HIST("hMCPi0SpPrim"), pt); mHistManager.fill(HIST("hMCPi0RapPrim"), part.y()); - mHistManager.fill(HIST("hMCPi0PhiPrim"), part.phi()); + } + if (std::abs(part.y()) < .5) { + double pt = part.pt(); + mHistManager.fill(HIST("hMCPi0SpAll"), pt); + double phiVtx = std::atan2(part.vy(), part.vx()); + if (r > 0.5) { + mHistManager.fill(HIST("hMCPi0SecVtx"), r, phiVtx); + } else { + mHistManager.fill(HIST("hMCPi0SpPrim"), pt); + mHistManager.fill(HIST("hMCPi0PhiPrim"), part.phi()); + } } } } @@ -312,31 +470,31 @@ struct phosPi0 { mCurEvent.clear(); for (const auto& clu : clusters) { // Fill QC histos - if (mFillQC) { + if (fillQC) { mHistManager.fill(HIST("hM02Clu"), clu.e(), clu.m02()); mHistManager.fill(HIST("hM20Clu"), clu.e(), clu.m20()); mHistManager.fill(HIST("hNcellClu"), clu.e(), clu.ncell(), clu.mod()); mHistManager.fill(HIST("cluETime"), clu.e(), clu.time(), clu.mod()); } - if (clu.e() < mMinCluE || - clu.ncell() < mMinCluNcell || - clu.time() > mMaxCluTime || clu.time() < mMinCluTime || - clu.m02() < mMinM02) { + if (clu.e() < minCluE || + clu.ncell() < minCluNcell || + clu.time() > maxCluTime || clu.time() < minCluTime || + clu.m02() < minM02) { continue; } - if (mFillQC) { + if (fillQC) { mHistManager.fill(HIST("cluSp"), clu.e(), clu.mod()); - if (clu.e() > mOccE) { + if (clu.e() > minOccE) { mHistManager.fill(HIST("cluOcc"), clu.x(), clu.z(), clu.mod()); if (clu.trackdist() > 2.) { mHistManager.fill(HIST("cluCPVOcc"), clu.x(), clu.z(), clu.mod()); mHistManager.fill(HIST("cluSpCPV"), clu.e(), clu.mod()); - if (TestLambda(clu.e(), clu.m02(), clu.m20())) { + if (testLambda(clu.e(), clu.m02(), clu.m20())) { mHistManager.fill(HIST("cluBothOcc"), clu.x(), clu.z(), clu.mod()); mHistManager.fill(HIST("cluSpBoth"), clu.e(), clu.mod()); } } - if (TestLambda(clu.e(), clu.m02(), clu.m20())) { + if (testLambda(clu.e(), clu.m02(), clu.m20())) { mHistManager.fill(HIST("cluDispOcc"), clu.x(), clu.z(), clu.mod()); mHistManager.fill(HIST("cluSpDisp"), clu.e(), clu.mod()); } @@ -350,67 +508,269 @@ struct phosPi0 { mcLabel = mcList[0]; } } - photon ph1(clu.px(), clu.py(), clu.pz(), clu.e(), clu.mod(), TestLambda(clu.e(), clu.m02(), clu.m20()), clu.trackdist() > mCPVCut, mcLabel); + double enCorr = 1; + if constexpr (isMC) { // correct MC energy + enCorr = nonlinearity(clu.e()); + } + Photon ph1(clu.px() * enCorr, clu.py() * enCorr, clu.pz() * enCorr, clu.e() * enCorr, clu.time(), clu.mod(), testLambda(clu.e(), clu.m02(), clu.m20()), clu.trackdist() > cpvCut, mcLabel); // Mix with other photons added to stack - for (auto ph2 : mCurEvent) { - double m = pow(ph1.e + ph2.e, 2) - pow(ph1.px + ph2.px, 2) - - pow(ph1.py + ph2.py, 2) - pow(ph1.pz + ph2.pz, 2); + for (const auto& ph2 : mCurEvent) { + double m = std::pow(ph1.e + ph2.e, 2) - std::pow(ph1.px + ph2.px, 2) - + std::pow(ph1.py + ph2.py, 2) - std::pow(ph1.pz + ph2.pz, 2); if (m > 0) { - m = sqrt(m); + m = std::sqrt(m); } - double pt = sqrt(pow(ph1.px + ph2.px, 2) + - pow(ph1.py + ph2.py, 2)); - int modComb = ModuleCombination(ph1.mod, ph2.mod); - hReMod->Fill(m, pt, modComb); - hReAll->Fill(m, pt); + double pt = std::sqrt(std::pow(ph1.px + ph2.px, 2) + + std::pow(ph1.py + ph2.py, 2)); + int modComb = moduleCombination(ph1.mod, ph2.mod); + double w = 1.; + if constexpr (isMC) { // correct MC energy + w = tofCutEff(ph1.e) * tofCutEff(ph2.e); + } + hReMod->Fill(m, pt, modComb, w); + hReAll->Fill(m, pt, w); + hReOneAll->Fill(m, ph1.pt(), w); + hReOneAll->Fill(m, ph2.pt(), w); + if (ph1.isCPVOK()) { + hReOneCPV->Fill(m, ph1.pt(), w); + } + if (ph2.isCPVOK()) { + hReOneCPV->Fill(m, ph2.pt(), w); + } + if (ph1.isDispOK()) { + hReOneDisp->Fill(m, ph1.pt(), w); + if (ph1.isCPVOK()) { + hReOneBoth->Fill(m, ph1.pt(), w); + } + } + if (ph2.isDispOK()) { + hReOneDisp->Fill(m, ph2.pt(), w); + if (ph2.isCPVOK()) { + hReOneBoth->Fill(m, ph2.pt(), w); + } + } + // Test time eff + if (std::abs(ph1.time - timeOffset) < 12.5e-9) { // strict cut on first photon + if (std::abs(ph2.time - timeOffset) < 100.e-9) { + hReTime100->Fill(m, ph2.pt()); + if (std::abs(ph2.time - timeOffset) < 50.e-9) { + hReTime50->Fill(m, ph2.pt()); + if (std::abs(ph2.time - timeOffset) < 30.e-9) { + hReTime30->Fill(m, ph2.pt()); + if (std::abs(ph2.time - timeOffset) < 12.5e-9) { + hReTime12->Fill(m, ph2.pt()); + } + } + } + } + } + if (std::abs(ph2.time - timeOffset) < 12.5e-9) { // strict cut on first photon + if (std::abs(ph1.time - timeOffset) < 100.e-9) { + hReTime100->Fill(m, ph1.pt()); + if (std::abs(ph1.time - timeOffset) < 50.e-9) { + hReTime50->Fill(m, ph1.pt()); + if (std::abs(ph1.time - timeOffset) < 30.e-9) { + hReTime30->Fill(m, ph1.pt()); + if (std::abs(ph1.time - timeOffset) < 12.5e-9) { + hReTime12->Fill(m, ph1.pt()); + } + } + } + } + } + bool isPi0 = false; if constexpr (isMC) { // test parent int cp = commonParentPDG(ph1.label, ph2.label, mcPart); if (cp != 0) { - hSignalAll->Fill(m, pt); + hSignalAll->Fill(m, pt, w); if (cp == 111) { isPi0 = true; - hPi0SignalAll->Fill(m, pt); + hPi0SignalAll->Fill(m, pt, w); } } } if (ph1.isCPVOK() && ph2.isCPVOK()) { - hReCPV->Fill(m, pt); + hReCPV->Fill(m, pt, w); if (isPi0) { - hPi0SignalCPV->Fill(m, pt); + hPi0SignalCPV->Fill(m, pt, w); } } if (ph1.isDispOK() && ph2.isDispOK()) { - hReDisp->Fill(m, pt); + hReDisp->Fill(m, pt, w); if (isPi0) { - hPi0SignalDisp->Fill(m, pt); + hPi0SignalDisp->Fill(m, pt, w); } if (ph1.isCPVOK() && ph2.isCPVOK()) { - hReBoth->Fill(m, pt); + hReBoth->Fill(m, pt, w); if (isPi0) { - hPi0SignalBoth->Fill(m, pt); + hPi0SignalBoth->Fill(m, pt, w); + } + } + } + } + + // Add photon to stack + mCurEvent.emplace_back(ph1); + } + + // Mixed + for (const auto& ph1 : mCurEvent) { + for (const auto& mixEvent : mMixedEvents[mixedEventBin]) { + for (const auto& ph2 : mixEvent) { + double m = std::pow(ph1.e + ph2.e, 2) - std::pow(ph1.px + ph2.px, 2) - + std::pow(ph1.py + ph2.py, 2) - std::pow(ph1.pz + ph2.pz, 2); + if (m > 0) { + m = std::sqrt(m); + } + double pt = std::sqrt(std::pow(ph1.px + ph2.px, 2) + + std::pow(ph1.py + ph2.py, 2)); + int modComb = moduleCombination(ph1.mod, ph2.mod); + double w = 1.; + if constexpr (isMC) { // correct MC energy + w = tofCutEff(ph1.e) * tofCutEff(ph2.e); + } + hMiMod->Fill(m, pt, modComb, w); + hMiAll->Fill(m, pt, w); + hMiOneAll->Fill(m, ph1.pt(), w); + hMiOneAll->Fill(m, ph2.pt(), w); + if (ph1.isCPVOK()) { + hMiOneCPV->Fill(m, ph1.pt(), w); + } + if (ph2.isCPVOK()) { + hMiOneCPV->Fill(m, ph2.pt(), w); + } + if (ph1.isDispOK()) { + hMiOneDisp->Fill(m, ph1.pt(), w); + if (ph1.isCPVOK()) { + hMiOneBoth->Fill(m, ph1.pt(), w); + } + } + if (ph2.isDispOK()) { + hMiOneDisp->Fill(m, ph2.pt(), w); + if (ph2.isCPVOK()) { + hMiOneBoth->Fill(m, ph2.pt(), w); + } + } + if (ph1.isCPVOK() && ph2.isCPVOK()) { + hMiCPV->Fill(m, pt, w); + } + if (ph1.isDispOK() && ph2.isDispOK()) { + hMiDisp->Fill(m, pt, w); + if (ph1.isCPVOK() && ph2.isCPVOK()) { + hMiBoth->Fill(m, pt, w); } } } } + } + + // Fill events to store and remove oldest to keep buffer size + if (mCurEvent.size() > 0) { + mMixedEvents[mixedEventBin].emplace_back(mCurEvent); + if (mMixedEvents[mixedEventBin].size() > static_cast(nMixedEvents)) { + mMixedEvents[mixedEventBin].pop_front(); + } + } + } + void processBC(aod::BCs::iterator const& /*bc*/, + aod::CaloAmbiguousClusters const& clusters) + { + bool isSelected = true; + mixedEventBin = 0; + + mHistManager.fill(HIST("eventsBC"), 0.); + double vtxZ = 0; // no vtx info + int mult = 1.; // multiplicity TODO!!! + mixedEventBin = findMixedEventBin(vtxZ, mult); + + if (!isSelected) { + return; + } + + // Fill invariant mass distributions + mCurEvent.clear(); + for (const auto& clu : clusters) { + // Fill QC histos + if (fillQC) { + mHistManager.fill(HIST("hM02Clu"), clu.e(), clu.m02()); + mHistManager.fill(HIST("hM20Clu"), clu.e(), clu.m20()); + mHistManager.fill(HIST("hNcellClu"), clu.e(), clu.ncell(), clu.mod()); + mHistManager.fill(HIST("cluETime"), clu.e(), clu.time(), clu.mod()); + } + if (clu.e() < minCluE || + clu.ncell() < minCluNcell || + clu.time() > maxCluTime || clu.time() < minCluTime || + clu.m02() < minM02) { + continue; + } + if (fillQC) { + mHistManager.fill(HIST("cluSp"), clu.e(), clu.mod()); + if (clu.e() > minOccE) { + mHistManager.fill(HIST("cluOcc"), clu.x(), clu.z(), clu.mod()); + if (clu.trackdist() > 2.) { + mHistManager.fill(HIST("cluCPVOcc"), clu.x(), clu.z(), clu.mod()); + mHistManager.fill(HIST("cluSpCPV"), clu.e(), clu.mod()); + if (testLambda(clu.e(), clu.m02(), clu.m20())) { + mHistManager.fill(HIST("cluBothOcc"), clu.x(), clu.z(), clu.mod()); + mHistManager.fill(HIST("cluSpBoth"), clu.e(), clu.mod()); + } + } + if (testLambda(clu.e(), clu.m02(), clu.m20())) { + mHistManager.fill(HIST("cluDispOcc"), clu.x(), clu.z(), clu.mod()); + mHistManager.fill(HIST("cluSpDisp"), clu.e(), clu.mod()); + } + } + } + + int mcLabel = -1; + double enCorr = 1; + if (isMC) { // correct MC energy + enCorr = nonlinearity(clu.e()); + } + Photon ph1(clu.px() * enCorr, clu.py() * enCorr, clu.pz() * enCorr, clu.e() * enCorr, clu.time(), clu.mod(), testLambda(clu.e(), clu.m02(), clu.m20()), clu.trackdist() > cpvCut, mcLabel); + + // Mix with other photons added to stack + for (const auto& ph2 : mCurEvent) { + double m = std::pow(ph1.e + ph2.e, 2) - std::pow(ph1.px + ph2.px, 2) - + std::pow(ph1.py + ph2.py, 2) - std::pow(ph1.pz + ph2.pz, 2); + if (m > 0) { + m = std::sqrt(m); + } + double pt = std::sqrt(std::pow(ph1.px + ph2.px, 2) + + std::pow(ph1.py + ph2.py, 2)); + int modComb = moduleCombination(ph1.mod, ph2.mod); + hReMod->Fill(m, pt, modComb); + hReAll->Fill(m, pt); + + if (ph1.isCPVOK() && ph2.isCPVOK()) { + hReCPV->Fill(m, pt); + } + if (ph1.isDispOK() && ph2.isDispOK()) { + hReDisp->Fill(m, pt); + if (ph1.isCPVOK() && ph2.isCPVOK()) { + hReBoth->Fill(m, pt); + } + } + } // Add photon to stack mCurEvent.emplace_back(ph1); } // Mixed - for (auto ph1 : mCurEvent) { - for (auto mixEvent : mMixedEvents[mixedEventBin]) { - for (auto ph2 : mixEvent) { - double m = pow(ph1.e + ph2.e, 2) - pow(ph1.px + ph2.px, 2) - - pow(ph1.py + ph2.py, 2) - pow(ph1.pz + ph2.pz, 2); + for (const auto& ph1 : mCurEvent) { + for (const auto& mixEvent : mMixedEvents[mixedEventBin]) { + for (const auto& ph2 : mixEvent) { + double m = std::pow(ph1.e + ph2.e, 2) - std::pow(ph1.px + ph2.px, 2) - + std::pow(ph1.py + ph2.py, 2) - std::pow(ph1.pz + ph2.pz, 2); if (m > 0) { - m = sqrt(m); + m = std::sqrt(m); } - double pt = sqrt(pow(ph1.px + ph2.px, 2) + - pow(ph1.py + ph2.py, 2)); - int modComb = ModuleCombination(ph1.mod, ph2.mod); + double pt = std::sqrt(std::pow(ph1.px + ph2.px, 2) + + std::pow(ph1.py + ph2.py, 2)); + int modComb = moduleCombination(ph1.mod, ph2.mod); hMiMod->Fill(m, pt, modComb); hMiAll->Fill(m, pt); if (ph1.isCPVOK() && ph2.isCPVOK()) { @@ -429,40 +789,41 @@ struct phosPi0 { // Fill events to store and remove oldest to keep buffer size if (mCurEvent.size() > 0) { mMixedEvents[mixedEventBin].emplace_back(mCurEvent); - if (mMixedEvents[mixedEventBin].size() > static_cast(mNMixedEvents)) { + if (mMixedEvents[mixedEventBin].size() > static_cast(nMixedEvents)) { mMixedEvents[mixedEventBin].pop_front(); } } } + PROCESS_SWITCH(PhosPi0, processBC, "processBC", false); //_____________________________________________________________________________ - int ModuleCombination(int m1, int m2) + int moduleCombination(int m1, int m2) { // enumerates possible module combinations // (1,1)=0, (2,2)=1, (3,3)=2, (4,4)=3, (1,2)=(2,1)=4, (2,3)=(3,2)=5, (3,4)=(4,3)=6, (1,3)=(3,1)=7, // (2,4)=(4,2)=8, (1,4)=(4,1)=9 - int d = TMath::Abs(m1 - m2); + int d = std::abs(m1 - m2); if (d == 0) { return m1 - 1; } if (d == 1) { - return 3 + TMath::Min(m1, m2); + return 3 + std::min(m1, m2); } if (d == 2) { - return 6 + TMath::Min(m1, m2); + return 6 + std::min(m1, m2); } return 9; } //_____________________________________________________________________________ - bool TestLambda(float pt, float l1, float l2) + bool testLambda(float pt, float l1, float l2) { // Parameterization for full dispersion // Parameterizatino for full dispersion float l2Mean = 1.53126 + 9.50835e+06 / (1. + 1.08728e+07 * pt + 1.73420e+06 * pt * pt); - float l1Mean = 1.12365 + 0.123770 * TMath::Exp(-pt * 0.246551) + 5.30000e-03 * pt; + float l1Mean = 1.12365 + 0.123770 * std::exp(-pt * 0.246551) + 5.30000e-03 * pt; float l2Sigma = 6.48260e-02 + 7.60261e+10 / (1. + 1.53012e+11 * pt + 5.01265e+05 * pt * pt) + 9.00000e-03 * pt; float l1Sigma = 4.44719e-04 + 6.99839e-01 / (1. + 1.22497e+00 * pt + 6.78604e-07 * pt * pt) + 9.00000e-03 * pt; - float c = -0.35 - 0.550 * TMath::Exp(-0.390730 * pt); + float c = -0.35 - 0.550 * std::exp(-0.390730 * pt); return 0.5 * (l1 - l1Mean) * (l1 - l1Mean) / l1Sigma / l1Sigma + 0.5 * (l2 - l2Mean) * (l2 - l2Mean) / l2Sigma / l2Sigma + @@ -478,8 +839,8 @@ struct phosPi0 { if (res < 0) return 0; - if (res >= nMaxMixBins) - return nMaxMixBins - 1; + if (res >= kMaxMixBins) + return kMaxMixBins - 1; return res; } //---------------------------------------- @@ -496,23 +857,60 @@ struct phosPi0 { return mcParticles->iteratorAt(iparent1).pdgCode(); } auto parent2 = mcParticles->iteratorAt(iparent2); - if (parent2.mothersIds().size() == 0 || parent2.pdgCode() == 21 || abs(parent2.pdgCode()) < 11 || abs(parent2.pdgCode()) > 5000) { // no parents, parent not quark/gluon, strings + if (parent2.mothersIds().size() == 0 || parent2.pdgCode() == 21 || std::abs(parent2.pdgCode()) < 11 || std::abs(parent2.pdgCode()) > 5000) { // no parents, parent not quark/gluon, strings break; } iparent2 = parent2.mothersIds()[0]; } auto parent1 = mcParticles->iteratorAt(iparent1); - if (parent1.mothersIds().size() == 0 || parent1.pdgCode() == 21 || abs(parent1.pdgCode()) < 11 || abs(parent1.pdgCode()) > 5000) { // no parents, parent not quark/gluon, strings + if (parent1.mothersIds().size() == 0 || parent1.pdgCode() == 21 || std::abs(parent1.pdgCode()) < 11 || std::abs(parent1.pdgCode()) > 5000) { // no parents, parent not quark/gluon, strings return 0; } iparent1 = parent1.mothersIds()[0]; } return 0; // nothing found } + double nonlinearity(double e) + { + return nonlinA + nonlinB * std::exp(-e / nonlinC); + } + double tofCutEff(double en) + { + if (tofEffParam == 0) { + return 1.; + } + if (tofEffParam == 1) { // Run2 100 ns + // parameterization 01.08.2020 + if (en > 1.1) + en = 1.1; + if (en < 0.11) + en = 0.11; + return std::exp((-1.15295e+05 + 2.26754e+05 * en - 1.26063e+05 * en * en + en * en * en) / + (1. - 3.16443e+05 * en + 3.68044e+06 * en * en + en * en * en)); + } + if (tofEffParam == 2) { // Run2 30 ns + if (en > 1.6) + en = 1.6; + return 1. / (1. + std::exp((4.83230e+01 - 8.89758e+01 * en + 1.10897e+03 * en * en - 5.73755e+03 * en * en * en - + 1.43777e+03 * en * en * en * en) / + (1. - 1.23667e+02 * en + 1.07255e+03 * en * en + 5.87221e+02 * en * en * en))); + } + if (tofEffParam == 2) { // Run2 12.5 ns + if (en < 4.6) { + return std::exp(3.64952e-03 * + (-5.80032e+01 - 1.53442e+02 * en + 1.30994e+02 * en * en + -3.53094e+01 * en * en * en + en * en * en * en) / + (-7.75638e-02 + 8.64761e-01 * en + 1.22320e+00 * en * en - 1.00177e+00 * en * en * en + en * en * en * en)); + } else { + return 0.63922783 * (1. - 1.63273e-01 * std::tanh((en - 7.94528e+00) / 1.28997e+00)) * + (-4.39257e+00 * en + 2.25503e+00 * en * en + en * en * en) / (2.37160e+00 * en - 6.93786e-01 * en * en + en * en * en); + } + } + return 1.; + } }; o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) { return o2::framework::WorkflowSpec{ - o2::framework::adaptAnalysisTask(cfgc)}; + o2::framework::adaptAnalysisTask(cfgc)}; } diff --git a/PWGHF/ALICE3/TableProducer/candidateCreatorChic.cxx b/PWGHF/ALICE3/TableProducer/candidateCreatorChic.cxx index af643fe92e9..e01b4fe0a6a 100644 --- a/PWGHF/ALICE3/TableProducer/candidateCreatorChic.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateCreatorChic.cxx @@ -15,6 +15,9 @@ /// /// \author Alessandro De Falco , Cagliari University +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "DCAFitter/DCAFitterN.h" #include "Framework/AnalysisTask.h" diff --git a/PWGHF/ALICE3/TableProducer/candidateCreatorX.cxx b/PWGHF/ALICE3/TableProducer/candidateCreatorX.cxx index 9f58eb93a75..2e3477dab99 100644 --- a/PWGHF/ALICE3/TableProducer/candidateCreatorX.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateCreatorX.cxx @@ -16,6 +16,9 @@ /// \author Rik Spijkers , Utrecht University /// \author Luca Micheletti , INFN +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "DCAFitter/DCAFitterN.h" #include "Framework/AnalysisTask.h" diff --git a/PWGHF/ALICE3/TableProducer/candidateSelectorChicToJpsiGamma.cxx b/PWGHF/ALICE3/TableProducer/candidateSelectorChicToJpsiGamma.cxx index affa3a6df99..5160a2ba99c 100644 --- a/PWGHF/ALICE3/TableProducer/candidateSelectorChicToJpsiGamma.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateSelectorChicToJpsiGamma.cxx @@ -15,6 +15,8 @@ /// /// \author Alessandro De Falco , Università/INFN Cagliari +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -46,7 +48,7 @@ struct HfCandidateSelectorChicToJpsiGamma { Configurable nSigmaTofMax{"nSigmaTofMax", 3., "Nsigma cut on TOF only"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_chic_to_jpsi_gamma::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_chic_to_jpsi_gamma::cuts[0], hf_cuts_chic_to_jpsi_gamma::nBinsPt, hf_cuts_chic_to_jpsi_gamma::nCutVars, hf_cuts_chic_to_jpsi_gamma::labelsPt, hf_cuts_chic_to_jpsi_gamma::labelsCutVar}, "Jpsi candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_chic_to_jpsi_gamma::Cuts[0], hf_cuts_chic_to_jpsi_gamma::NBinsPt, hf_cuts_chic_to_jpsi_gamma::NCutVars, hf_cuts_chic_to_jpsi_gamma::labelsPt, hf_cuts_chic_to_jpsi_gamma::labelsCutVar}, "Jpsi candidate selection per pT bin"}; HfHelper hfHelper; @@ -95,8 +97,8 @@ struct HfCandidateSelectorChicToJpsiGamma { return false; // CPA check } - if ((std::abs(hfCandChic.impactParameter0()) > cuts->get(pTBin, "d0 Jpsi"))) { // adf: Warning: no cut on photon - return false; // DCA check on daughters + if ((std::abs(hfCandChic.impactParameter0()) > cuts->get(pTBin, "d0 Jpsi"))) { // adf: Warning: no cut on photon + return false; // DCA check on daughters } // add more cuts: d0 product? PCA? diff --git a/PWGHF/ALICE3/TableProducer/candidateSelectorD0Alice3Barrel.cxx b/PWGHF/ALICE3/TableProducer/candidateSelectorD0Alice3Barrel.cxx index ebf4e98b930..705deeeaff2 100644 --- a/PWGHF/ALICE3/TableProducer/candidateSelectorD0Alice3Barrel.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateSelectorD0Alice3Barrel.cxx @@ -15,6 +15,9 @@ /// \author Nima Zardoshti , CERN /// \author Vít Kučera , CERN +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -65,7 +68,7 @@ struct HfCandidateSelectorD0Alice3Barrel { Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 5., "Nsigma cut on TOF combined with TPC"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_d0_to_pi_k::cuts[0], hf_cuts_d0_to_pi_k::nBinsPt, hf_cuts_d0_to_pi_k::nCutVars, hf_cuts_d0_to_pi_k::labelsPt, hf_cuts_d0_to_pi_k::labelsCutVar}, "D0 candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_d0_to_pi_k::Cuts[0], hf_cuts_d0_to_pi_k::NBinsPt, hf_cuts_d0_to_pi_k::NCutVars, hf_cuts_d0_to_pi_k::labelsPt, hf_cuts_d0_to_pi_k::labelsCutVar}, "D0 candidate selection per pT bin"}; HfHelper hfHelper; diff --git a/PWGHF/ALICE3/TableProducer/candidateSelectorD0Alice3Forward.cxx b/PWGHF/ALICE3/TableProducer/candidateSelectorD0Alice3Forward.cxx index 5dadba32b98..a213c3edd04 100644 --- a/PWGHF/ALICE3/TableProducer/candidateSelectorD0Alice3Forward.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateSelectorD0Alice3Forward.cxx @@ -15,6 +15,9 @@ /// \author Nima Zardoshti , CERN /// \author Vít Kučera , CERN +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -65,7 +68,7 @@ struct HfCandidateSelectorD0Alice3Forward { Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 5., "Nsigma cut on TOF combined with TPC"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_d0_to_pi_k::cuts[0], hf_cuts_d0_to_pi_k::nBinsPt, hf_cuts_d0_to_pi_k::nCutVars, hf_cuts_d0_to_pi_k::labelsPt, hf_cuts_d0_to_pi_k::labelsCutVar}, "D0 candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_d0_to_pi_k::Cuts[0], hf_cuts_d0_to_pi_k::NBinsPt, hf_cuts_d0_to_pi_k::NCutVars, hf_cuts_d0_to_pi_k::labelsPt, hf_cuts_d0_to_pi_k::labelsCutVar}, "D0 candidate selection per pT bin"}; HfHelper hfHelper; diff --git a/PWGHF/ALICE3/TableProducer/candidateSelectorD0ParametrizedPid.cxx b/PWGHF/ALICE3/TableProducer/candidateSelectorD0ParametrizedPid.cxx index b429b08cf10..6a46231b0c2 100644 --- a/PWGHF/ALICE3/TableProducer/candidateSelectorD0ParametrizedPid.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateSelectorD0ParametrizedPid.cxx @@ -15,6 +15,9 @@ /// \author Nima Zardoshti , CERN /// \author Vít Kučera , CERN +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -65,7 +68,7 @@ struct HfCandidateSelectorD0ParametrizedPid { Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 5., "Nsigma cut on TOF combined with TPC"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_d0_to_pi_k::cuts[0], hf_cuts_d0_to_pi_k::nBinsPt, hf_cuts_d0_to_pi_k::nCutVars, hf_cuts_d0_to_pi_k::labelsPt, hf_cuts_d0_to_pi_k::labelsCutVar}, "D0 candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_d0_to_pi_k::Cuts[0], hf_cuts_d0_to_pi_k::NBinsPt, hf_cuts_d0_to_pi_k::NCutVars, hf_cuts_d0_to_pi_k::labelsPt, hf_cuts_d0_to_pi_k::labelsCutVar}, "D0 candidate selection per pT bin"}; HfHelper hfHelper; diff --git a/PWGHF/ALICE3/TableProducer/candidateSelectorJpsi.cxx b/PWGHF/ALICE3/TableProducer/candidateSelectorJpsi.cxx index 74690e954c3..391aba49da0 100644 --- a/PWGHF/ALICE3/TableProducer/candidateSelectorJpsi.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateSelectorJpsi.cxx @@ -16,6 +16,8 @@ /// \author Nima Zardoshti , CERN /// \author Vít Kučera , CERN +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" @@ -82,7 +84,7 @@ struct HfCandidateSelectorJpsi { Configurable nSigmaRichCombinedTofMax{"nSigmaRichCombinedTofMax", 5., "Nsigma cut on RICH combined with TOF"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_jpsi_to_e_e::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_jpsi_to_e_e::cuts[0], hf_cuts_jpsi_to_e_e::nBinsPt, hf_cuts_jpsi_to_e_e::nCutVars, hf_cuts_jpsi_to_e_e::labelsPt, hf_cuts_jpsi_to_e_e::labelsCutVar}, "Jpsi candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_jpsi_to_e_e::Cuts[0], hf_cuts_jpsi_to_e_e::NBinsPt, hf_cuts_jpsi_to_e_e::NCutVars, hf_cuts_jpsi_to_e_e::labelsPt, hf_cuts_jpsi_to_e_e::labelsCutVar}, "Jpsi candidate selection per pT bin"}; HfHelper hfHelper; TrackSelectorEl selectorElectron; diff --git a/PWGHF/ALICE3/TableProducer/candidateSelectorLcAlice3.cxx b/PWGHF/ALICE3/TableProducer/candidateSelectorLcAlice3.cxx index 8fae8fe6e6f..c9abeedad39 100644 --- a/PWGHF/ALICE3/TableProducer/candidateSelectorLcAlice3.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateSelectorLcAlice3.cxx @@ -16,6 +16,8 @@ /// \author Nima Zardoshti , CERN /// \author Vít Kučera , CERN +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -67,7 +69,7 @@ struct HfCandidateSelectorLcAlice3 { // topological cuts Configurable decayLengthXYNormalisedMin{"decayLengthXYNormalisedMin", 3., "Min. normalised decay length"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_lc_to_p_k_pi::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_lc_to_p_k_pi::cuts[0], hf_cuts_lc_to_p_k_pi::nBinsPt, hf_cuts_lc_to_p_k_pi::nCutVars, hf_cuts_lc_to_p_k_pi::labelsPt, hf_cuts_lc_to_p_k_pi::labelsCutVar}, "Lc candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_lc_to_p_k_pi::Cuts[0], hf_cuts_lc_to_p_k_pi::NBinsPt, hf_cuts_lc_to_p_k_pi::NCutVars, hf_cuts_lc_to_p_k_pi::labelsPt, hf_cuts_lc_to_p_k_pi::labelsCutVar}, "Lc candidate selection per pT bin"}; HfHelper hfHelper; diff --git a/PWGHF/ALICE3/TableProducer/candidateSelectorLcParametrizedPid.cxx b/PWGHF/ALICE3/TableProducer/candidateSelectorLcParametrizedPid.cxx index 491b15a04d2..0a3210a63f6 100644 --- a/PWGHF/ALICE3/TableProducer/candidateSelectorLcParametrizedPid.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateSelectorLcParametrizedPid.cxx @@ -16,6 +16,8 @@ /// \author Nima Zardoshti , CERN /// \author Vít Kučera , CERN +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -68,7 +70,7 @@ struct HfCandidateSelectorLcParametrizedPid { // topological cuts Configurable decayLengthXYNormalisedMin{"decayLengthXYNormalisedMin", 3., "Normalised decay length"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_lc_to_p_k_pi::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_lc_to_p_k_pi::cuts[0], hf_cuts_lc_to_p_k_pi::nBinsPt, hf_cuts_lc_to_p_k_pi::nCutVars, hf_cuts_lc_to_p_k_pi::labelsPt, hf_cuts_lc_to_p_k_pi::labelsCutVar}, "Lc candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_lc_to_p_k_pi::Cuts[0], hf_cuts_lc_to_p_k_pi::NBinsPt, hf_cuts_lc_to_p_k_pi::NCutVars, hf_cuts_lc_to_p_k_pi::labelsPt, hf_cuts_lc_to_p_k_pi::labelsCutVar}, "Lc candidate selection per pT bin"}; HfHelper hfHelper; diff --git a/PWGHF/ALICE3/TableProducer/candidateSelectorXToJpsiPiPi.cxx b/PWGHF/ALICE3/TableProducer/candidateSelectorXToJpsiPiPi.cxx index 62a542d94f9..bff87d84e70 100644 --- a/PWGHF/ALICE3/TableProducer/candidateSelectorXToJpsiPiPi.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateSelectorXToJpsiPiPi.cxx @@ -16,6 +16,8 @@ /// \author Rik Spijkers , Utrecht University /// \author Luca Micheletti , INFN +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -47,7 +49,7 @@ struct HfCandidateSelectorXToJpsiPiPi { Configurable nSigmaTofMax{"nSigmaTofMax", 3., "Nsigma cut on TOF only"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_x_to_jpsi_pi_pi::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_x_to_jpsi_pi_pi::cuts[0], hf_cuts_x_to_jpsi_pi_pi::nBinsPt, hf_cuts_x_to_jpsi_pi_pi::nCutVars, hf_cuts_x_to_jpsi_pi_pi::labelsPt, hf_cuts_x_to_jpsi_pi_pi::labelsCutVar}, "Jpsi candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_x_to_jpsi_pi_pi::Cuts[0], hf_cuts_x_to_jpsi_pi_pi::NBinsPt, hf_cuts_x_to_jpsi_pi_pi::NCutVars, hf_cuts_x_to_jpsi_pi_pi::labelsPt, hf_cuts_x_to_jpsi_pi_pi::labelsCutVar}, "Jpsi candidate selection per pT bin"}; HfHelper hfHelper; diff --git a/PWGHF/ALICE3/Tasks/taskChic.cxx b/PWGHF/ALICE3/Tasks/taskChic.cxx index 026f781f6f4..f8cb85454a1 100644 --- a/PWGHF/ALICE3/Tasks/taskChic.cxx +++ b/PWGHF/ALICE3/Tasks/taskChic.cxx @@ -15,6 +15,8 @@ /// \author Gian Michele Innocenti , CERN /// \author Alessandro De Falco , Cagliari University +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" diff --git a/PWGHF/ALICE3/Tasks/taskJpsi.cxx b/PWGHF/ALICE3/Tasks/taskJpsi.cxx index f3bcbd8dcb2..a9210ccca86 100644 --- a/PWGHF/ALICE3/Tasks/taskJpsi.cxx +++ b/PWGHF/ALICE3/Tasks/taskJpsi.cxx @@ -16,6 +16,8 @@ /// \author Vít Kučera , CERN /// \author Biao Zhang , CCNU +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" diff --git a/PWGHF/ALICE3/Tasks/taskQaPidRejection.cxx b/PWGHF/ALICE3/Tasks/taskQaPidRejection.cxx index e3fcba65268..f0e819e3086 100644 --- a/PWGHF/ALICE3/Tasks/taskQaPidRejection.cxx +++ b/PWGHF/ALICE3/Tasks/taskQaPidRejection.cxx @@ -16,6 +16,9 @@ /// \author Henrique J C Zanoli , Utrecht University /// \author Nicolo' Jacazio , CERN +#include +#include + #include #include #include diff --git a/PWGHF/ALICE3/Tasks/taskX.cxx b/PWGHF/ALICE3/Tasks/taskX.cxx index 610f9f94a33..f090eb57876 100644 --- a/PWGHF/ALICE3/Tasks/taskX.cxx +++ b/PWGHF/ALICE3/Tasks/taskX.cxx @@ -16,6 +16,8 @@ /// \author Rik Spijkers , Utrecht University /// \author Luca Micheletti , INFN +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" diff --git a/PWGHF/CMakeLists.txt b/PWGHF/CMakeLists.txt index 01cba79d8f5..5bb211e6f56 100644 --- a/PWGHF/CMakeLists.txt +++ b/PWGHF/CMakeLists.txt @@ -13,7 +13,7 @@ # add_subdirectory(DataModel) add_subdirectory(TableProducer) add_subdirectory(Tasks) -add_subdirectory(ALICE3) +# add_subdirectory(ALICE3) add_subdirectory(D2H) add_subdirectory(HFC) add_subdirectory(HFJ) diff --git a/PWGHF/Core/CentralityEstimation.h b/PWGHF/Core/CentralityEstimation.h new file mode 100644 index 00000000000..203cc4680c8 --- /dev/null +++ b/PWGHF/Core/CentralityEstimation.h @@ -0,0 +1,194 @@ +// 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 CentralityEstimation.h +/// \brief Definitions of centrality estimators +/// \author Vít Kučera , Inha University + +#ifndef PWGHF_CORE_CENTRALITYESTIMATION_H_ +#define PWGHF_CORE_CENTRALITYESTIMATION_H_ + +namespace o2::hf_centrality +{ +// centrality selection estimators +enum CentralityEstimator { + None = 0, + FT0A, + FT0C, + FT0M, + FV0A, + NTracksPV, + NCentralityEstimators +}; + +template +concept hasFT0ACent = requires(T collision) +{ + collision.centFT0A(); +}; + +template +concept hasFT0CCent = requires(T collision) +{ + collision.centFT0C(); +}; + +template +concept hasFT0MCent = requires(T collision) +{ + collision.centFT0M(); +}; + +template +concept hasFV0ACent = requires(T collision) +{ + collision.centFV0A(); +}; + +template +concept hasNTracksPVCent = requires(T collision) +{ + collision.centNTPV(); +}; + +/// Evaluate centrality/multiplicity percentile using FT0A estimator +/// \param candidate is candidate +/// \return centrality/multiplicity percentile of the collision +template +float getCentralityColl(const Coll& collision) +{ + return collision.centFT0A(); +} + +/// Evaluate centrality/multiplicity percentile using FT0C estimator +/// \param candidate is candidate +/// \return centrality/multiplicity percentile of the collision +template +float getCentralityColl(const Coll& collision) +{ + return collision.centFT0C(); +} + +/// Evaluate centrality/multiplicity percentile using FT0M estimator +/// \param candidate is candidate +/// \return centrality/multiplicity percentile of the collision +template +float getCentralityColl(const Coll& collision) +{ + return collision.centFT0M(); +} + +/// Evaluate centrality/multiplicity percentile using FV0A estimator +/// \param candidate is candidate +/// \return centrality/multiplicity percentile of the collision +template +float getCentralityColl(const Coll& collision) +{ + return collision.centFV0A(); +} + +/// Evaluate centrality/multiplicity percentile using NTracksPV estimator +/// \param candidate is candidate +/// \return centrality/multiplicity percentile of the collision +template +float getCentralityColl(const Coll& collision) +{ + return collision.centNTPV(); +} + +/// Default case if no centrality/multiplicity estimator is provided +/// \param candidate is candidate +/// \return dummy value for centrality/multiplicity percentile of the collision +template +float getCentralityColl(const Coll&) +{ + return 105.0f; +} + +/// Get the centrality +/// \param collision is the collision with the centrality information +/// \param centEstimator integer to select the centrality estimator +/// \return collision centrality +template +float getCentralityColl(const Coll& collision, int centEstimator) +{ + switch (centEstimator) { + case CentralityEstimator::FT0A: + if constexpr (hasFT0ACent) { + return collision.centFT0A(); + } + LOG(fatal) << "Collision does not have centFT0A()."; + break; + case CentralityEstimator::FT0C: + if constexpr (hasFT0CCent) { + return collision.centFT0C(); + } + LOG(fatal) << "Collision does not have centFT0C()."; + break; + case CentralityEstimator::FT0M: + if constexpr (hasFT0MCent) { + return collision.centFT0M(); + } + LOG(fatal) << "Collision does not have centFT0M()."; + break; + case CentralityEstimator::FV0A: + if constexpr (hasFV0ACent) { + return collision.centFV0A(); + } + LOG(fatal) << "Collision does not have centFV0A()."; + break; + default: + LOG(fatal) << "Centrality estimator not valid. Possible values are V0A, T0M, T0A, T0C."; + break; + } + return -999.f; +} + +/// \brief Function to get MC collision centrality +/// \param collSlice collection of reconstructed collisions associated to a generated one +/// \return generated MC collision centrality +template +float getCentralityGenColl(CCs const& collSlice) +{ + float centrality{-1}; + float multiplicity{0.f}; + for (const auto& collision : collSlice) { + float collMult = collision.numContrib(); + if (collMult > multiplicity) { + centrality = getCentralityColl(collision); + multiplicity = collMult; + } + } + return centrality; +} + +/// \brief Function to get MC collision centrality +/// \param collSlice collection of reconstructed collisions associated to a generated one +/// \param centEstimator integer to select the centrality estimator +/// \return generated MC collision centrality +template +float getCentralityGenColl(CCs const& collSlice, int centEstimator) +{ + float centrality{-1}; + float multiplicity{0.f}; + for (const auto& collision : collSlice) { + float collMult = collision.numContrib(); + if (collMult > multiplicity) { + centrality = getCentralityColl(collision, centEstimator); + multiplicity = collMult; + } + } + return centrality; +} + +} // namespace o2::hf_centrality + +#endif // PWGHF_CORE_CENTRALITYESTIMATION_H_ diff --git a/PWGHF/Core/HfHelper.h b/PWGHF/Core/HfHelper.h index 2ea6afa54ad..7b723769d85 100644 --- a/PWGHF/Core/HfHelper.h +++ b/PWGHF/Core/HfHelper.h @@ -17,8 +17,10 @@ #ifndef PWGHF_CORE_HFHELPER_H_ #define PWGHF_CORE_HFHELPER_H_ -#include -#include +#include + +#include "Math/GenVector/Boost.h" +#include "Math/Vector4D.h" #include #include "CommonConstants/PhysicsConstants.h" @@ -358,6 +360,42 @@ class HfHelper return candidate.m(std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus, o2::constants::physics::MassProton}); } + template + auto invMassKPiPairLcToPKPi(const T& candidate) + { + return RecoDecay::m(std::array{candidate.pVectorProng1(), candidate.pVectorProng2()}, std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); + } + + template + auto invMassKPiPairLcToPiKP(const T& candidate) + { + return RecoDecay::m(std::array{candidate.pVectorProng1(), candidate.pVectorProng0()}, std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); + } + + template + auto invMassPKPairLcToPKPi(const T& candidate) + { + return RecoDecay::m(std::array{candidate.pVectorProng0(), candidate.pVectorProng1()}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassKPlus}); + } + + template + auto invMassPKPairLcToPiKP(const T& candidate) + { + return RecoDecay::m(std::array{candidate.pVectorProng2(), candidate.pVectorProng1()}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassKPlus}); + } + + template + auto invMassPPiPairLcToPKPi(const T& candidate) + { + return RecoDecay::m(std::array{candidate.pVectorProng0(), candidate.pVectorProng2()}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPiPlus}); + } + + template + auto invMassPPiPairLcToPiKP(const T& candidate) + { + return RecoDecay::m(std::array{candidate.pVectorProng2(), candidate.pVectorProng0()}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPiPlus}); + } + // Ξc± → p± K∓ π± template @@ -653,6 +691,14 @@ class HfHelper return candidate.y(o2::constants::physics::MassSigmaCPlusPlus); } + /// Σc0,++ → Λc+(→K0sP) π-,+ + /// @brief Sc inv. mass using reco mass for Lc in K0sP and PDG mass for pion + template + auto invMassScRecoLcToK0sP(const T& candidateSc, const U& candidateLc) + { + return candidateSc.m(std::array{static_cast(invMassLcToK0sP(candidateLc)), o2::constants::physics::MassPiMinus}); + } + /// Apply topological cuts as defined in SelectorCuts.h /// \param candB0 B0 candidate /// \param cuts B0 candidate selection per pT bin" @@ -795,6 +841,16 @@ class HfHelper return false; } + // d0 of pi + if (std::abs(candBp.impactParameter1()) < cuts->get(pTBin, "d0 Pi")) { + return false; + } + + // d0 of D + if (std::abs(candBp.impactParameter0()) < cuts->get(pTBin, "d0 D0")) { + return false; + } + return true; } @@ -903,34 +959,59 @@ class HfHelper } /// Apply selection on ML scores for charm-hadron daughter in b-hadron decays (common for all the beauty channels) - /// \param candB b-hadron candidates /// \param cuts ML score selection per bin of charm-hadron pT /// \param binsPtC pT bin limits of charm hadron + /// \param mlScores vector with ml scores of charm hadron (position 0:bkg 1:prompt 2:nonprompt) /// \return true if b-hadron candidate passes all selections - template - bool selectionDmesMlScoresForB(const T1& candB, const T2& cuts, const T3& binsPtC) + template + bool applySelectionDmesMlScoresForB(const T1& cuts, const T2& binsPtC, float ptC, std::vector mlScores) { - auto ptC = RecoDecay::pt(candB.pxProng0(), candB.pyProng0()); // the first daughter is the charm hadron int pTBin = o2::analysis::findBin(binsPtC, ptC); if (pTBin == -1) { return false; } - if (candB.prong0MlScoreBkg() > cuts->get(pTBin, "ML score charm bkg")) { + if (mlScores[0] > cuts->get(pTBin, "ML score charm bkg")) { return false; } - if (candB.prong0MlScorePrompt() > cuts->get(pTBin, "ML score charm prompt")) { // we want non-prompt for beauty + if (mlScores[1] > cuts->get(pTBin, "ML score charm prompt")) { // we want non-prompt for beauty return false; } - if (candB.prong0MlScoreNonprompt() < cuts->get(pTBin, "ML score charm nonprompt")) { // we want non-prompt for beauty + if (mlScores[2] < cuts->get(pTBin, "ML score charm nonprompt")) { // we want non-prompt for beauty return false; } return true; } + /// Apply selection on ML scores for charm-hadron daughter in b-hadron decays (could be common for all the beauty channels) + /// \param candB b-hadron candidates + /// \param cuts ML score selection per bin of charm-hadron pT + /// \param binsPtC pT bin limits of charm hadron + /// \return true if b-hadron candidate passes all selections + template + bool selectionDmesMlScoresForB(const T1& candD, const T2& cuts, const T3& binsPtC, const std::vector& mlScores) + { + return applySelectionDmesMlScoresForB(cuts, binsPtC, candD.pt(), mlScores); + } + + /// Apply selection on ML scores for charm-hadron daughter in b-hadron decays in reduced format (common for all the beauty channels) + /// \param candB b-hadron candidates + /// \param cuts ML score selection per bin of charm-hadron pT + /// \param binsPtC pT bin limits of charm hadron + /// \return true if b-hadron candidate passes all selections + template + bool selectionDmesMlScoresForBReduced(const T1& candB, const T2& cuts, const T3& binsPtC) + { + std::vector mlScores; + mlScores.push_back(candB.prong0MlScoreBkg()); + mlScores.push_back(candB.prong0MlScorePrompt()); + mlScores.push_back(candB.prong0MlScoreNonprompt()); // we want non-prompt for beauty + return applySelectionDmesMlScoresForB(cuts, binsPtC, RecoDecay::pt(candB.pxProng0(), candB.pyProng0()), mlScores); + } + private: }; diff --git a/PWGHF/Core/HfMlResponseB0ToDPi.h b/PWGHF/Core/HfMlResponseB0ToDPi.h index 08853a21eac..1e2f82c028f 100644 --- a/PWGHF/Core/HfMlResponseB0ToDPi.h +++ b/PWGHF/Core/HfMlResponseB0ToDPi.h @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file HfMlResponsB0ToDPi.h +/// \file HfMlResponseB0ToDPi.h /// \brief Class to compute the ML response for B0 → D∓ π± analysis selections /// \author Alexandre Bigot , IPHC Strasbourg @@ -21,13 +21,14 @@ #include #include "PWGHF/Core/HfMlResponse.h" +#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" // Fill the map of available input features // the key is the feature's name (std::string) // the value is the corresponding value in EnumInputFeatures -#define FILL_MAP_B0(FEATURE) \ - { \ -#FEATURE, static_cast < uint8_t>(InputFeaturesB0ToDPi::FEATURE) \ +#define FILL_MAP_B0(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesB0ToDPi::FEATURE) \ } // Check if the index of mCachedIndices (index associated to a FEATURE) @@ -58,31 +59,6 @@ break; \ } -namespace o2::pid_tpc_tof_utils -{ -template -float getTpcTofNSigmaPi1(const T1& prong1) -{ - float defaultNSigma = -999.f; // -999.f is the default value set in TPCPIDResponse.h and PIDTOF.h - - bool hasTpc = prong1.hasTPC(); - bool hasTof = prong1.hasTOF(); - - if (hasTpc && hasTof) { - float tpcNSigma = prong1.tpcNSigmaPi(); - float tofNSigma = prong1.tofNSigmaPi(); - return sqrt(.5f * tpcNSigma * tpcNSigma + .5f * tofNSigma * tofNSigma); - } - if (hasTpc) { - return abs(prong1.tpcNSigmaPi()); - } - if (hasTof) { - return abs(prong1.tofNSigmaPi()); - } - return defaultNSigma; -} -} // namespace o2::pid_tpc_tof_utils - namespace o2::analysis { diff --git a/PWGHF/Core/HfMlResponseBplusToD0Pi.h b/PWGHF/Core/HfMlResponseBplusToD0Pi.h new file mode 100644 index 00000000000..90fb0669675 --- /dev/null +++ b/PWGHF/Core/HfMlResponseBplusToD0Pi.h @@ -0,0 +1,210 @@ +// 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 HfMlResponseBplusToD0Pi.h +/// \brief Class to compute the ML response for B± → D0(bar) π± analysis selections +/// \author Antonio Palasciano , INFN Bari + +#ifndef PWGHF_CORE_HFMLRESPONSEBPLUSTOD0PI_H_ +#define PWGHF_CORE_HFMLRESPONSEBPLUSTOD0PI_H_ + +#include +#include +#include + +#include "PWGHF/Core/HfMlResponse.h" +#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" + +// Fill the map of available input features +// the key is the feature's name (std::string) +// the value is the corresponding value in EnumInputFeatures +#define FILL_MAP_BPLUS(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesBplusToD0Pi::FEATURE) \ + } + +// Check if the index of mCachedIndices (index associated to a FEATURE) +// matches the entry in EnumInputFeatures associated to this FEATURE +// if so, the inputFeatures vector is filled with the FEATURE's value +// by calling the corresponding GETTER from OBJECT +#define CHECK_AND_FILL_VEC_BPLUS_FULL(OBJECT, FEATURE, GETTER) \ + case static_cast(InputFeaturesBplusToD0Pi::FEATURE): { \ + inputFeatures.emplace_back(OBJECT.GETTER()); \ + break; \ + } + +// Check if the index of mCachedIndices (index associated to a FEATURE) +// matches the entry in EnumInputFeatures associated to this FEATURE +// if so, the inputFeatures vector is filled with the FEATURE's value +// by calling the GETTER function taking OBJECT in argument +#define CHECK_AND_FILL_VEC_BPLUS_FUNC(OBJECT, FEATURE, GETTER) \ + case static_cast(InputFeaturesBplusToD0Pi::FEATURE): { \ + inputFeatures.emplace_back(GETTER(OBJECT)); \ + break; \ + } + +// Specific case of CHECK_AND_FILL_VEC_BPLUS_FULL(OBJECT, FEATURE, GETTER) +// where OBJECT is named candidate and FEATURE = GETTER +#define CHECK_AND_FILL_VEC_BPLUS(GETTER) \ + case static_cast(InputFeaturesBplusToD0Pi::GETTER): { \ + inputFeatures.emplace_back(candidate.GETTER()); \ + break; \ + } + +// where OBJECT is named candidateD , FEATURE = GETTER and INDEX is the index of the vector +#define CHECK_AND_FILL_VEC_D0_INDEX(FEATURE, GETTER1, GETTER2, INDEX) \ + case static_cast(InputFeaturesBplusToD0Pi::FEATURE): { \ + if (pdgCode == o2::constants::physics::kD0) { \ + inputFeatures.emplace_back((candidateD0.GETTER1())[INDEX]); \ + } else { \ + inputFeatures.emplace_back((candidateD0.GETTER2())[INDEX]); \ + } \ + break; \ + } + +namespace o2::analysis +{ + +enum class InputFeaturesBplusToD0Pi : uint8_t { + ptProng0 = 0, + ptProng1, + impactParameter0, + impactParameter1, + impactParameterProduct, + chi2PCA, + decayLength, + decayLengthXY, + decayLengthNormalised, + decayLengthXYNormalised, + cpa, + cpaXY, + maxNormalisedDeltaIP, + prong0MlProbBkg, + prong0MlProbPrompt, + prong0MlProbNonPrompt, + tpcNSigmaPi1, + tofNSigmaPi1, + tpcTofNSigmaPi1 +}; + +template +class HfMlResponseBplusToD0Pi : public HfMlResponse +{ + public: + /// Default constructor + HfMlResponseBplusToD0Pi() = default; + /// Default destructor + virtual ~HfMlResponseBplusToD0Pi() = default; + + /// Method to get the input features vector needed for ML inference + /// \param candidate is the B+ candidate + /// \param prong1 is the candidate's prong1 + /// \return inputFeatures vector + template + std::vector getInputFeatures(T1 const& candidate, + T2 const& candidateD0, + int const& pdgCode, + T3 const& prong1) + { + std::vector inputFeatures; + + for (const auto& idx : MlResponse::mCachedIndices) { + if constexpr (withDmesMl) { + switch (idx) { + CHECK_AND_FILL_VEC_BPLUS(ptProng0); + CHECK_AND_FILL_VEC_BPLUS(ptProng1); + CHECK_AND_FILL_VEC_BPLUS(impactParameter0); + CHECK_AND_FILL_VEC_BPLUS(impactParameter1); + CHECK_AND_FILL_VEC_BPLUS(impactParameterProduct); + CHECK_AND_FILL_VEC_BPLUS(chi2PCA); + CHECK_AND_FILL_VEC_BPLUS(decayLength); + CHECK_AND_FILL_VEC_BPLUS(decayLengthXY); + CHECK_AND_FILL_VEC_BPLUS(decayLengthNormalised); + CHECK_AND_FILL_VEC_BPLUS(decayLengthXYNormalised); + CHECK_AND_FILL_VEC_BPLUS(cpa); + CHECK_AND_FILL_VEC_BPLUS(cpaXY); + CHECK_AND_FILL_VEC_BPLUS(maxNormalisedDeltaIP); + CHECK_AND_FILL_VEC_D0_INDEX(prong0MlProbBkg, mlProbD0, mlProbD0bar, 0); + CHECK_AND_FILL_VEC_D0_INDEX(prong0MlProbPrompt, mlProbD0, mlProbD0bar, 1); + CHECK_AND_FILL_VEC_D0_INDEX(prong0MlProbNonPrompt, mlProbD0, mlProbD0bar, 2); + // TPC PID variable + CHECK_AND_FILL_VEC_BPLUS_FULL(prong1, tpcNSigmaPi1, tpcNSigmaPi); + // TOF PID variable + CHECK_AND_FILL_VEC_BPLUS_FULL(prong1, tofNSigmaPi1, tofNSigmaPi); + // Combined PID variables + CHECK_AND_FILL_VEC_BPLUS_FUNC(prong1, tpcTofNSigmaPi1, o2::pid_tpc_tof_utils::getTpcTofNSigmaPi1); + } + } else { + switch (idx) { + CHECK_AND_FILL_VEC_BPLUS(ptProng0); + CHECK_AND_FILL_VEC_BPLUS(ptProng1); + CHECK_AND_FILL_VEC_BPLUS(impactParameter0); + CHECK_AND_FILL_VEC_BPLUS(impactParameter1); + CHECK_AND_FILL_VEC_BPLUS(impactParameterProduct); + CHECK_AND_FILL_VEC_BPLUS(chi2PCA); + CHECK_AND_FILL_VEC_BPLUS(decayLength); + CHECK_AND_FILL_VEC_BPLUS(decayLengthXY); + CHECK_AND_FILL_VEC_BPLUS(decayLengthNormalised); + CHECK_AND_FILL_VEC_BPLUS(decayLengthXYNormalised); + CHECK_AND_FILL_VEC_BPLUS(cpa); + CHECK_AND_FILL_VEC_BPLUS(cpaXY); + CHECK_AND_FILL_VEC_BPLUS(maxNormalisedDeltaIP); + // TPC PID variable + CHECK_AND_FILL_VEC_BPLUS_FULL(prong1, tpcNSigmaPi1, tpcNSigmaPi); + // TOF PID variable + CHECK_AND_FILL_VEC_BPLUS_FULL(prong1, tofNSigmaPi1, tofNSigmaPi); + // Combined PID variables + CHECK_AND_FILL_VEC_BPLUS_FUNC(prong1, tpcTofNSigmaPi1, o2::pid_tpc_tof_utils::getTpcTofNSigmaPi1); + } + } + } + + return inputFeatures; + } + + protected: + /// Method to fill the map of available input features + void setAvailableInputFeatures() + { + MlResponse::mAvailableInputFeatures = { + FILL_MAP_BPLUS(ptProng0), + FILL_MAP_BPLUS(ptProng1), + FILL_MAP_BPLUS(impactParameter0), + FILL_MAP_BPLUS(impactParameter1), + FILL_MAP_BPLUS(impactParameterProduct), + FILL_MAP_BPLUS(chi2PCA), + FILL_MAP_BPLUS(decayLength), + FILL_MAP_BPLUS(decayLengthXY), + FILL_MAP_BPLUS(decayLengthNormalised), + FILL_MAP_BPLUS(decayLengthXYNormalised), + FILL_MAP_BPLUS(cpa), + FILL_MAP_BPLUS(cpaXY), + FILL_MAP_BPLUS(maxNormalisedDeltaIP), + FILL_MAP_BPLUS(prong0MlProbBkg), + FILL_MAP_BPLUS(prong0MlProbPrompt), + FILL_MAP_BPLUS(prong0MlProbNonPrompt), + // TPC PID variable + FILL_MAP_BPLUS(tpcNSigmaPi1), + // TOF PID variable + FILL_MAP_BPLUS(tofNSigmaPi1), + // Combined PID variable + FILL_MAP_BPLUS(tpcTofNSigmaPi1)}; + } +}; + +} // namespace o2::analysis + +#undef FILL_MAP_BPLUS +#undef CHECK_AND_FILL_VEC_BPLUS_FULL +#undef CHECK_AND_FILL_VEC_BPLUS_FUNC +#undef CHECK_AND_FILL_VEC_BPLUS + +#endif // PWGHF_CORE_HFMLRESPONSEBPLUSTOD0PI_H_ diff --git a/PWGHF/Core/HfMlResponseBplusToD0PiReduced.h b/PWGHF/Core/HfMlResponseBplusToD0PiReduced.h new file mode 100644 index 00000000000..6f56cbce245 --- /dev/null +++ b/PWGHF/Core/HfMlResponseBplusToD0PiReduced.h @@ -0,0 +1,197 @@ +// 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 HfMlResponseBplusToD0PiReduced.h +/// \brief Class to compute the ML response for B± → D0(bar) π± analysis selections in the reduced format +/// \author Antonio Palasciano , INFN Bari + +#ifndef PWGHF_CORE_HFMLRESPONSEBPLUSTOD0PIREDUCED_H_ +#define PWGHF_CORE_HFMLRESPONSEBPLUSTOD0PIREDUCED_H_ + +#include +#include +#include + +#include "PWGHF/Core/HfMlResponse.h" +#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" + +// Fill the map of available input features +// the key is the feature's name (std::string) +// the value is the corresponding value in EnumInputFeatures +#define FILL_MAP_BPLUS(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesBplusToD0PiReduced::FEATURE) \ + } + +// Check if the index of mCachedIndices (index associated to a FEATURE) +// matches the entry in EnumInputFeatures associated to this FEATURE +// if so, the inputFeatures vector is filled with the FEATURE's value +// by calling the corresponding GETTER from OBJECT +#define CHECK_AND_FILL_VEC_BPLUS_FULL(OBJECT, FEATURE, GETTER) \ + case static_cast(InputFeaturesBplusToD0PiReduced::FEATURE): { \ + inputFeatures.emplace_back(OBJECT.GETTER()); \ + break; \ + } + +// Check if the index of mCachedIndices (index associated to a FEATURE) +// matches the entry in EnumInputFeatures associated to this FEATURE +// if so, the inputFeatures vector is filled with the FEATURE's value +// by calling the GETTER function taking OBJECT in argument +#define CHECK_AND_FILL_VEC_BPLUS_FUNC(OBJECT, FEATURE, GETTER) \ + case static_cast(InputFeaturesBplusToD0PiReduced::FEATURE): { \ + inputFeatures.emplace_back(GETTER(OBJECT)); \ + break; \ + } + +// Specific case of CHECK_AND_FILL_VEC_BPLUS_FULL(OBJECT, FEATURE, GETTER) +// where OBJECT is named candidate and FEATURE = GETTER +#define CHECK_AND_FILL_VEC_BPLUS(GETTER) \ + case static_cast(InputFeaturesBplusToD0PiReduced::GETTER): { \ + inputFeatures.emplace_back(candidate.GETTER()); \ + break; \ + } + +namespace o2::analysis +{ + +enum class InputFeaturesBplusToD0PiReduced : uint8_t { + ptProng0 = 0, + ptProng1, + impactParameter0, + impactParameter1, + impactParameterProduct, + chi2PCA, + decayLength, + decayLengthXY, + decayLengthNormalised, + decayLengthXYNormalised, + cpa, + cpaXY, + maxNormalisedDeltaIP, + prong0MlScoreBkg, + prong0MlScorePrompt, + prong0MlScoreNonprompt, + tpcNSigmaPi1, + tofNSigmaPi1, + tpcTofNSigmaPi1 +}; + +template +class HfMlResponseBplusToD0PiReduced : public HfMlResponse +{ + public: + /// Default constructor + HfMlResponseBplusToD0PiReduced() = default; + /// Default destructor + virtual ~HfMlResponseBplusToD0PiReduced() = default; + + /// Method to get the input features vector needed for ML inference + /// \param candidate is the B+ candidate + /// \param prong1 is the candidate's prong1 + /// \return inputFeatures vector + template + std::vector getInputFeatures(T1 const& candidate, + T2 const& prong1) + { + std::vector inputFeatures; + + for (const auto& idx : MlResponse::mCachedIndices) { + if constexpr (withDmesMl) { + switch (idx) { + CHECK_AND_FILL_VEC_BPLUS(ptProng0); + CHECK_AND_FILL_VEC_BPLUS(ptProng1); + CHECK_AND_FILL_VEC_BPLUS(impactParameter0); + CHECK_AND_FILL_VEC_BPLUS(impactParameter1); + CHECK_AND_FILL_VEC_BPLUS(impactParameterProduct); + CHECK_AND_FILL_VEC_BPLUS(chi2PCA); + CHECK_AND_FILL_VEC_BPLUS(decayLength); + CHECK_AND_FILL_VEC_BPLUS(decayLengthXY); + CHECK_AND_FILL_VEC_BPLUS(decayLengthNormalised); + CHECK_AND_FILL_VEC_BPLUS(decayLengthXYNormalised); + CHECK_AND_FILL_VEC_BPLUS(cpa); + CHECK_AND_FILL_VEC_BPLUS(cpaXY); + CHECK_AND_FILL_VEC_BPLUS(maxNormalisedDeltaIP); + CHECK_AND_FILL_VEC_BPLUS(prong0MlScoreBkg); + CHECK_AND_FILL_VEC_BPLUS(prong0MlScorePrompt); + CHECK_AND_FILL_VEC_BPLUS(prong0MlScoreNonprompt); + // TPC PID variable + CHECK_AND_FILL_VEC_BPLUS_FULL(prong1, tpcNSigmaPi1, tpcNSigmaPi); + // TOF PID variable + CHECK_AND_FILL_VEC_BPLUS_FULL(prong1, tofNSigmaPi1, tofNSigmaPi); + // Combined PID variables + CHECK_AND_FILL_VEC_BPLUS_FUNC(prong1, tpcTofNSigmaPi1, o2::pid_tpc_tof_utils::getTpcTofNSigmaPi1); + } + } else { + switch (idx) { + CHECK_AND_FILL_VEC_BPLUS(ptProng0); + CHECK_AND_FILL_VEC_BPLUS(ptProng1); + CHECK_AND_FILL_VEC_BPLUS(impactParameter0); + CHECK_AND_FILL_VEC_BPLUS(impactParameter1); + CHECK_AND_FILL_VEC_BPLUS(impactParameterProduct); + CHECK_AND_FILL_VEC_BPLUS(chi2PCA); + CHECK_AND_FILL_VEC_BPLUS(decayLength); + CHECK_AND_FILL_VEC_BPLUS(decayLengthXY); + CHECK_AND_FILL_VEC_BPLUS(decayLengthNormalised); + CHECK_AND_FILL_VEC_BPLUS(decayLengthXYNormalised); + CHECK_AND_FILL_VEC_BPLUS(cpa); + CHECK_AND_FILL_VEC_BPLUS(cpaXY); + CHECK_AND_FILL_VEC_BPLUS(maxNormalisedDeltaIP); + // TPC PID variable + CHECK_AND_FILL_VEC_BPLUS_FULL(prong1, tpcNSigmaPi1, tpcNSigmaPi); + // TOF PID variable + CHECK_AND_FILL_VEC_BPLUS_FULL(prong1, tofNSigmaPi1, tofNSigmaPi); + // Combined PID variables + CHECK_AND_FILL_VEC_BPLUS_FUNC(prong1, tpcTofNSigmaPi1, o2::pid_tpc_tof_utils::getTpcTofNSigmaPi1); + } + } + } + + return inputFeatures; + } + + protected: + /// Method to fill the map of available input features + void setAvailableInputFeatures() + { + MlResponse::mAvailableInputFeatures = { + FILL_MAP_BPLUS(ptProng0), + FILL_MAP_BPLUS(ptProng1), + FILL_MAP_BPLUS(impactParameter0), + FILL_MAP_BPLUS(impactParameter1), + FILL_MAP_BPLUS(impactParameterProduct), + FILL_MAP_BPLUS(chi2PCA), + FILL_MAP_BPLUS(decayLength), + FILL_MAP_BPLUS(decayLengthXY), + FILL_MAP_BPLUS(decayLengthNormalised), + FILL_MAP_BPLUS(decayLengthXYNormalised), + FILL_MAP_BPLUS(cpa), + FILL_MAP_BPLUS(cpaXY), + FILL_MAP_BPLUS(maxNormalisedDeltaIP), + FILL_MAP_BPLUS(prong0MlScoreBkg), + FILL_MAP_BPLUS(prong0MlScorePrompt), + FILL_MAP_BPLUS(prong0MlScoreNonprompt), + // TPC PID variable + FILL_MAP_BPLUS(tpcNSigmaPi1), + // TOF PID variable + FILL_MAP_BPLUS(tofNSigmaPi1), + // Combined PID variable + FILL_MAP_BPLUS(tpcTofNSigmaPi1)}; + } +}; + +} // namespace o2::analysis + +#undef FILL_MAP_BPLUS +#undef CHECK_AND_FILL_VEC_BPLUS_FULL +#undef CHECK_AND_FILL_VEC_BPLUS_FUNC +#undef CHECK_AND_FILL_VEC_BPLUS + +#endif // PWGHF_CORE_HFMLRESPONSEBPLUSTOD0PIREDUCED_H_ diff --git a/PWGHF/Core/HfMlResponseBsToDsPi.h b/PWGHF/Core/HfMlResponseBsToDsPi.h new file mode 100644 index 00000000000..111a76b1227 --- /dev/null +++ b/PWGHF/Core/HfMlResponseBsToDsPi.h @@ -0,0 +1,191 @@ +// 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 HfMlResponseBsToDsPi.h +/// \brief Class to compute the ML response for Bs → Ds∓ π± analysis selections +/// \author Fabio Catalano , CERN + +#ifndef PWGHF_CORE_HFMLRESPONSEBSTODSPI_H_ +#define PWGHF_CORE_HFMLRESPONSEBSTODSPI_H_ + +#include +#include +#include + +#include "PWGHF/Core/HfMlResponse.h" +#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" + +// Fill the map of available input features +// the key is the feature's name (std::string) +// the value is the corresponding value in EnumInputFeatures +#define FILL_MAP_BS(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesBsToDsPi::FEATURE) \ + } + +// Check if the index of mCachedIndices (index associated to a FEATURE) +// matches the entry in EnumInputFeatures associated to this FEATURE +// if so, the inputFeatures vector is filled with the FEATURE's value +// by calling the corresponding GETTER from OBJECT +#define CHECK_AND_FILL_VEC_BS_FULL(OBJECT, FEATURE, GETTER) \ + case static_cast(InputFeaturesBsToDsPi::FEATURE): { \ + inputFeatures.emplace_back(OBJECT.GETTER()); \ + break; \ + } + +// Check if the index of mCachedIndices (index associated to a FEATURE) +// matches the entry in EnumInputFeatures associated to this FEATURE +// if so, the inputFeatures vector is filled with the FEATURE's value +// by calling the GETTER function taking OBJECT in argument +#define CHECK_AND_FILL_VEC_BS_FUNC(OBJECT, FEATURE, GETTER) \ + case static_cast(InputFeaturesBsToDsPi::FEATURE): { \ + inputFeatures.emplace_back(GETTER(OBJECT)); \ + break; \ + } + +// Specific case of CHECK_AND_FILL_VEC_BS_FULL(OBJECT, FEATURE, GETTER) +// where OBJECT is named candidate and FEATURE = GETTER +#define CHECK_AND_FILL_VEC_BS(GETTER) \ + case static_cast(InputFeaturesBsToDsPi::GETTER): { \ + inputFeatures.emplace_back(candidate.GETTER()); \ + break; \ + } + +namespace o2::analysis +{ + +enum class InputFeaturesBsToDsPi : uint8_t { + ptProng0 = 0, + ptProng1, + impactParameter0, + impactParameter1, + impactParameterProduct, + chi2PCA, + decayLength, + decayLengthXY, + decayLengthNormalised, + decayLengthXYNormalised, + cpa, + cpaXY, + maxNormalisedDeltaIP, + prong0MlScoreBkg, + prong0MlScorePrompt, + prong0MlScoreNonprompt, + tpcNSigmaPi1, + tofNSigmaPi1, + tpcTofNSigmaPi1 +}; + +template +class HfMlResponseBsToDsPi : public HfMlResponse +{ + public: + /// Default constructor + HfMlResponseBsToDsPi() = default; + /// Default destructor + virtual ~HfMlResponseBsToDsPi() = default; + + /// Method to get the input features vector needed for ML inference + /// \param candidate is the Bs candidate + /// \param prong1 is the candidate's prong1 + /// \return inputFeatures vector + template + std::vector getInputFeatures(T1 const& candidate, + T2 const& prong1) + { + std::vector inputFeatures; + + for (const auto& idx : MlResponse::mCachedIndices) { + if constexpr (withDmesMl) { + switch (idx) { + CHECK_AND_FILL_VEC_BS(ptProng0); + CHECK_AND_FILL_VEC_BS(ptProng1); + CHECK_AND_FILL_VEC_BS(impactParameter0); + CHECK_AND_FILL_VEC_BS(impactParameter1); + CHECK_AND_FILL_VEC_BS(impactParameterProduct); + CHECK_AND_FILL_VEC_BS(chi2PCA); + CHECK_AND_FILL_VEC_BS(decayLength); + CHECK_AND_FILL_VEC_BS(decayLengthXY); + CHECK_AND_FILL_VEC_BS(decayLengthNormalised); + CHECK_AND_FILL_VEC_BS(decayLengthXYNormalised); + CHECK_AND_FILL_VEC_BS(cpa); + CHECK_AND_FILL_VEC_BS(cpaXY); + CHECK_AND_FILL_VEC_BS(maxNormalisedDeltaIP); + CHECK_AND_FILL_VEC_BS(prong0MlScoreBkg); + CHECK_AND_FILL_VEC_BS(prong0MlScorePrompt); + CHECK_AND_FILL_VEC_BS(prong0MlScoreNonprompt); + // Pion PID variables + CHECK_AND_FILL_VEC_BS_FULL(prong1, tpcNSigmaPi1, tpcNSigmaPi); + CHECK_AND_FILL_VEC_BS_FULL(prong1, tofNSigmaPi1, tofNSigmaPi); + CHECK_AND_FILL_VEC_BS_FUNC(prong1, tpcTofNSigmaPi1, o2::pid_tpc_tof_utils::getTpcTofNSigmaPi1); + } + } else { + switch (idx) { + CHECK_AND_FILL_VEC_BS(ptProng0); + CHECK_AND_FILL_VEC_BS(ptProng1); + CHECK_AND_FILL_VEC_BS(impactParameter0); + CHECK_AND_FILL_VEC_BS(impactParameter1); + CHECK_AND_FILL_VEC_BS(impactParameterProduct); + CHECK_AND_FILL_VEC_BS(chi2PCA); + CHECK_AND_FILL_VEC_BS(decayLength); + CHECK_AND_FILL_VEC_BS(decayLengthXY); + CHECK_AND_FILL_VEC_BS(decayLengthNormalised); + CHECK_AND_FILL_VEC_BS(decayLengthXYNormalised); + CHECK_AND_FILL_VEC_BS(cpa); + CHECK_AND_FILL_VEC_BS(cpaXY); + CHECK_AND_FILL_VEC_BS(maxNormalisedDeltaIP); + // Pion PID variables + CHECK_AND_FILL_VEC_BS_FULL(prong1, tpcNSigmaPi1, tpcNSigmaPi); + CHECK_AND_FILL_VEC_BS_FULL(prong1, tofNSigmaPi1, tofNSigmaPi); + CHECK_AND_FILL_VEC_BS_FUNC(prong1, tpcTofNSigmaPi1, o2::pid_tpc_tof_utils::getTpcTofNSigmaPi1); + } + } + } + + return inputFeatures; + } + + protected: + /// Method to fill the map of available input features + void setAvailableInputFeatures() + { + MlResponse::mAvailableInputFeatures = { + FILL_MAP_BS(ptProng0), + FILL_MAP_BS(ptProng1), + FILL_MAP_BS(impactParameter0), + FILL_MAP_BS(impactParameter1), + FILL_MAP_BS(impactParameterProduct), + FILL_MAP_BS(chi2PCA), + FILL_MAP_BS(decayLength), + FILL_MAP_BS(decayLengthXY), + FILL_MAP_BS(decayLengthNormalised), + FILL_MAP_BS(decayLengthXYNormalised), + FILL_MAP_BS(cpa), + FILL_MAP_BS(cpaXY), + FILL_MAP_BS(maxNormalisedDeltaIP), + FILL_MAP_BS(prong0MlScoreBkg), + FILL_MAP_BS(prong0MlScorePrompt), + FILL_MAP_BS(prong0MlScoreNonprompt), + // Pion PID variables + FILL_MAP_BS(tpcNSigmaPi1), + FILL_MAP_BS(tofNSigmaPi1), + FILL_MAP_BS(tpcTofNSigmaPi1)}; + } +}; + +} // namespace o2::analysis + +#undef FILL_MAP_BS +#undef CHECK_AND_FILL_VEC_BS_FULL +#undef CHECK_AND_FILL_VEC_BS_FUNC +#undef CHECK_AND_FILL_VEC_BS + +#endif // PWGHF_CORE_HFMLRESPONSEBSTODSPI_H_ diff --git a/PWGHF/Core/HfMlResponseD0ToKPi.h b/PWGHF/Core/HfMlResponseD0ToKPi.h index 91790751503..fbca4f8319e 100644 --- a/PWGHF/Core/HfMlResponseD0ToKPi.h +++ b/PWGHF/Core/HfMlResponseD0ToKPi.h @@ -29,9 +29,9 @@ // Fill the map of available input features // the key is the feature's name (std::string) // the value is the corresponding value in EnumInputFeatures -#define FILL_MAP_D0(FEATURE) \ - { \ -#FEATURE, static_cast < uint8_t>(InputFeaturesD0ToKPi::FEATURE) \ +#define FILL_MAP_D0(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesD0ToKPi::FEATURE) \ } // Check if the index of mCachedIndices (index associated to a FEATURE) @@ -73,6 +73,48 @@ break; \ } +// Variation of CHECK_AND_FILL_VEC_D0_HFHELPER(OBJECT, FEATURE, GETTER) +// where GETTER1 and GETTER2 are methods of hfHelper, and the variable +// is filled depending on whether it is a D0 or a D0bar +#define CHECK_AND_FILL_VEC_D0_OBJECT_HFHELPER_SIGNED(OBJECT1, OBJECT2, FEATURE, GETTER) \ + case static_cast(InputFeaturesD0ToKPi::FEATURE): { \ + if (pdgCode == o2::constants::physics::kD0) { \ + inputFeatures.emplace_back(OBJECT1.GETTER()); \ + } else { \ + inputFeatures.emplace_back(OBJECT2.GETTER()); \ + } \ + break; \ + } + +// Variation of CHECK_AND_FILL_VEC_D0_HFHELPER_SIGNED(OBJECT, FEATURE, GETTER1, GETTER2) +// where GETTER1 and GETTER2 are methods of the OBJECT, and the variable +// is filled depending on whether it is a D0 or a D0bar +#define CHECK_AND_FILL_VEC_D0_SIGNED(OBJECT, FEATURE, GETTER1, GETTER2) \ + case static_cast(InputFeaturesD0ToKPi::FEATURE): { \ + if (pdgCode == o2::constants::physics::kD0) { \ + inputFeatures.emplace_back(OBJECT.GETTER1()); \ + } else { \ + inputFeatures.emplace_back(OBJECT.GETTER2()); \ + } \ + break; \ + } + +// Variation of CHECK_AND_FILL_VEC_D0_SIGNED(OBJECT, FEATURE, GETTER1, GETTER2) +// where GETTER1 and GETTER2 are methods of the OBJECT, the variable +// is filled depending on whether it is a D0 or a D0bar +// and INDEX is the index of the vector +#define CHECK_AND_FILL_VEC_D0_ML(OBJECT, FEATURE, GETTER1, GETTER2, INDEX) \ + case static_cast(InputFeaturesD0ToKPi::FEATURE): { \ + if constexpr (usingMl) { \ + if (pdgCode == o2::constants::physics::kD0) { \ + inputFeatures.emplace_back(OBJECT.GETTER1()[INDEX]); \ + } else { \ + inputFeatures.emplace_back(OBJECT.GETTER2()[INDEX]); \ + } \ + } \ + break; \ + } + namespace o2::analysis { enum class InputFeaturesD0ToKPi : uint8_t { @@ -100,8 +142,23 @@ enum class InputFeaturesD0ToKPi : uint8_t { nSigTofKa1, nSigTpcTofPi1, nSigTpcTofKa1, + nSigTpcPiExpPi, + nSigTpcKaExpPi, + nSigTpcPiExpKa, + nSigTpcKaExpKa, + nSigTofPiExpPi, + nSigTofKaExpPi, + nSigTofPiExpKa, + nSigTofKaExpKa, + nSigTpcTofPiExpPi, + nSigTpcTofKaExpPi, + nSigTpcTofPiExpKa, + nSigTpcTofKaExpKa, maxNormalisedDeltaIP, impactParameterProduct, + bdtOutputBkg, + bdtOutputNonPrompt, + bdtOutputPrompt, cosThetaStar, cpa, cpaXY, @@ -121,12 +178,9 @@ class HfMlResponseD0ToKPi : public HfMlResponse /// Method to get the input features vector needed for ML inference /// \param candidate is the D0 candidate - /// \param prong0 is the candidate's prong0 - /// \param prong1 is the candidate's prong1 /// \return inputFeatures vector - template - std::vector getInputFeatures(T1 const& candidate, - T2 const& prong0, T2 const& prong1, int const& pdgCode) + template + std::vector getInputFeatures(T1 const& candidate, int const& pdgCode) { std::vector inputFeatures; @@ -144,20 +198,36 @@ class HfMlResponseD0ToKPi : public HfMlResponse CHECK_AND_FILL_VEC_D0(impactParameterZ0); CHECK_AND_FILL_VEC_D0(impactParameterZ1); // TPC PID variables - CHECK_AND_FILL_VEC_D0_FULL(prong0, nSigTpcPi0, tpcNSigmaPi); - CHECK_AND_FILL_VEC_D0_FULL(prong0, nSigTpcKa0, tpcNSigmaKa); - CHECK_AND_FILL_VEC_D0_FULL(prong1, nSigTpcPi1, tpcNSigmaPi); - CHECK_AND_FILL_VEC_D0_FULL(prong1, nSigTpcKa1, tpcNSigmaKa); + CHECK_AND_FILL_VEC_D0_FULL(candidate, nSigTpcPi0, /*getter*/ nSigTpcPi0); + CHECK_AND_FILL_VEC_D0_FULL(candidate, nSigTpcKa0, /*getter*/ nSigTpcKa0); + CHECK_AND_FILL_VEC_D0_FULL(candidate, nSigTpcPi1, /*getter*/ nSigTpcPi1); + CHECK_AND_FILL_VEC_D0_FULL(candidate, nSigTpcKa1, /*getter*/ nSigTpcKa1); + CHECK_AND_FILL_VEC_D0_SIGNED(candidate, nSigTpcPiExpPi, nSigTpcPi0, nSigTpcPi1); + CHECK_AND_FILL_VEC_D0_SIGNED(candidate, nSigTpcKaExpPi, nSigTpcKa0, nSigTpcKa1); + CHECK_AND_FILL_VEC_D0_SIGNED(candidate, nSigTpcPiExpKa, nSigTpcPi1, nSigTpcPi0); + CHECK_AND_FILL_VEC_D0_SIGNED(candidate, nSigTpcKaExpKa, nSigTpcKa1, nSigTpcKa0); // TOF PID variables - CHECK_AND_FILL_VEC_D0_FULL(prong0, nSigTofPi0, tofNSigmaPi); - CHECK_AND_FILL_VEC_D0_FULL(prong0, nSigTofKa0, tofNSigmaKa); - CHECK_AND_FILL_VEC_D0_FULL(prong1, nSigTofPi1, tofNSigmaPi); - CHECK_AND_FILL_VEC_D0_FULL(prong1, nSigTofKa1, tofNSigmaKa); + CHECK_AND_FILL_VEC_D0_FULL(candidate, nSigTofPi0, /*getter*/ nSigTofPi0); + CHECK_AND_FILL_VEC_D0_FULL(candidate, nSigTofKa0, /*getter*/ nSigTofKa0); + CHECK_AND_FILL_VEC_D0_FULL(candidate, nSigTofPi1, /*getter*/ nSigTofPi1); + CHECK_AND_FILL_VEC_D0_FULL(candidate, nSigTofKa1, /*getter*/ nSigTofKa1); + CHECK_AND_FILL_VEC_D0_SIGNED(candidate, nSigTofPiExpPi, nSigTofPi0, nSigTofPi1); + CHECK_AND_FILL_VEC_D0_SIGNED(candidate, nSigTofKaExpPi, nSigTofKa0, nSigTofKa1); + CHECK_AND_FILL_VEC_D0_SIGNED(candidate, nSigTofPiExpKa, nSigTofPi1, nSigTofPi0); + CHECK_AND_FILL_VEC_D0_SIGNED(candidate, nSigTofKaExpKa, nSigTofKa1, nSigTofKa0); // Combined PID variables - CHECK_AND_FILL_VEC_D0_FULL(prong0, nSigTpcTofPi0, tpcTofNSigmaPi); - CHECK_AND_FILL_VEC_D0_FULL(prong0, nSigTpcTofKa0, tpcTofNSigmaKa); - CHECK_AND_FILL_VEC_D0_FULL(prong1, nSigTpcTofPi1, tpcTofNSigmaPi); - CHECK_AND_FILL_VEC_D0_FULL(prong1, nSigTpcTofKa1, tpcTofNSigmaKa); + CHECK_AND_FILL_VEC_D0_FULL(candidate, nSigTpcTofPi0, tpcTofNSigmaPi0); + CHECK_AND_FILL_VEC_D0_FULL(candidate, nSigTpcTofKa0, tpcTofNSigmaKa0); + CHECK_AND_FILL_VEC_D0_FULL(candidate, nSigTpcTofPi1, tpcTofNSigmaPi1); + CHECK_AND_FILL_VEC_D0_FULL(candidate, nSigTpcTofKa1, tpcTofNSigmaKa1); + CHECK_AND_FILL_VEC_D0_SIGNED(candidate, nSigTpcTofPiExpPi, tpcTofNSigmaPi0, tpcTofNSigmaPi1); + CHECK_AND_FILL_VEC_D0_SIGNED(candidate, nSigTpcTofKaExpPi, tpcTofNSigmaKa0, tpcTofNSigmaKa1); + CHECK_AND_FILL_VEC_D0_SIGNED(candidate, nSigTpcTofPiExpKa, tpcTofNSigmaPi1, tpcTofNSigmaPi0); + CHECK_AND_FILL_VEC_D0_SIGNED(candidate, nSigTpcTofKaExpKa, tpcTofNSigmaKa1, tpcTofNSigmaKa0); + + CHECK_AND_FILL_VEC_D0_ML(candidate, bdtOutputBkg, mlProbD0, mlProbD0bar, 0); + CHECK_AND_FILL_VEC_D0_ML(candidate, bdtOutputNonPrompt, mlProbD0, mlProbD0bar, 1); + CHECK_AND_FILL_VEC_D0_ML(candidate, bdtOutputPrompt, mlProbD0, mlProbD0bar, 2); CHECK_AND_FILL_VEC_D0(maxNormalisedDeltaIP); CHECK_AND_FILL_VEC_D0_FULL(candidate, impactParameterProduct, impactParameterProduct); @@ -192,16 +262,32 @@ class HfMlResponseD0ToKPi : public HfMlResponse FILL_MAP_D0(nSigTpcKa0), FILL_MAP_D0(nSigTpcPi1), FILL_MAP_D0(nSigTpcKa1), + FILL_MAP_D0(nSigTpcPiExpPi), + FILL_MAP_D0(nSigTpcKaExpPi), + FILL_MAP_D0(nSigTpcPiExpKa), + FILL_MAP_D0(nSigTpcKaExpKa), // TOF PID variables FILL_MAP_D0(nSigTofPi0), FILL_MAP_D0(nSigTofKa0), FILL_MAP_D0(nSigTofPi1), FILL_MAP_D0(nSigTofKa1), + FILL_MAP_D0(nSigTofPiExpPi), + FILL_MAP_D0(nSigTofKaExpPi), + FILL_MAP_D0(nSigTofPiExpKa), + FILL_MAP_D0(nSigTofKaExpKa), // Combined PID variables FILL_MAP_D0(nSigTpcTofPi0), FILL_MAP_D0(nSigTpcTofKa0), FILL_MAP_D0(nSigTpcTofPi1), FILL_MAP_D0(nSigTpcTofKa1), + FILL_MAP_D0(nSigTpcTofPiExpPi), + FILL_MAP_D0(nSigTpcTofKaExpPi), + FILL_MAP_D0(nSigTpcTofPiExpKa), + FILL_MAP_D0(nSigTpcTofKaExpKa), + // ML variables + FILL_MAP_D0(bdtOutputBkg), + FILL_MAP_D0(bdtOutputNonPrompt), + FILL_MAP_D0(bdtOutputPrompt), FILL_MAP_D0(maxNormalisedDeltaIP), FILL_MAP_D0(impactParameterProduct), @@ -219,5 +305,7 @@ class HfMlResponseD0ToKPi : public HfMlResponse #undef CHECK_AND_FILL_VEC_D0 #undef CHECK_AND_FILL_VEC_D0_HFHELPER #undef CHECK_AND_FILL_VEC_D0_HFHELPER_SIGNED +#undef CHECK_AND_FILL_VEC_D0_OBJECT_HFHELPER_SIGNED +#undef CHECK_AND_FILL_VEC_D0_ML #endif // PWGHF_CORE_HFMLRESPONSED0TOKPI_H_ diff --git a/PWGHF/Core/HfMlResponseDsToKKPi.h b/PWGHF/Core/HfMlResponseDsToKKPi.h index 62e93882ddf..1b27d52adde 100644 --- a/PWGHF/Core/HfMlResponseDsToKKPi.h +++ b/PWGHF/Core/HfMlResponseDsToKKPi.h @@ -68,6 +68,19 @@ break; \ } +// Variation of CHECK_AND_FILL_VEC_DS_HFHELPER(OBJECT, FEATURE, GETTER) +// where OBJECT1 and OBJECT2 are the objects from which we call the GETTER method, and the variable +// is filled depending on whether it is a DsToKKPi or a DsToPiKK +#define CHECK_AND_FILL_VEC_DS_OBJECT_SIGNED(OBJECT1, OBJECT2, FEATURE, GETTER) \ + case static_cast(InputFeaturesDsToKKPi::FEATURE): { \ + if (caseDsToKKPi) { \ + inputFeatures.emplace_back(OBJECT1.GETTER()); \ + } else { \ + inputFeatures.emplace_back(OBJECT2.GETTER()); \ + } \ + break; \ + } + namespace o2::analysis { enum class InputFeaturesDsToKKPi : uint8_t { @@ -95,12 +108,24 @@ enum class InputFeaturesDsToKKPi : uint8_t { nSigTpcKa0, nSigTpcKa1, nSigTpcKa2, + nSigTofPi0, + nSigTofPi1, + nSigTofPi2, + nSigTofKa0, + nSigTofKa1, + nSigTofKa2, nSigTpcTofPi0, nSigTpcTofPi1, nSigTpcTofPi2, nSigTpcTofKa0, nSigTpcTofKa1, nSigTpcTofKa2, + nSigTpcKaExpKa0, + nSigTpcPiExpPi2, + nSigTofKaExpKa0, + nSigTofPiExpPi2, + nSigTpcTofKaExpKa0, + nSigTpcTofPiExpPi2, absCos3PiK, deltaMassPhi }; @@ -156,6 +181,17 @@ class HfMlResponseDsToKKPi : public HfMlResponse CHECK_AND_FILL_VEC_DS_FULL(prong0, nSigTpcKa0, tpcNSigmaKa); CHECK_AND_FILL_VEC_DS_FULL(prong1, nSigTpcKa1, tpcNSigmaKa); CHECK_AND_FILL_VEC_DS_FULL(prong2, nSigTpcKa2, tpcNSigmaKa); + CHECK_AND_FILL_VEC_DS_FULL(prong0, nSigTofPi0, tofNSigmaPi); + CHECK_AND_FILL_VEC_DS_FULL(prong1, nSigTofPi1, tofNSigmaPi); + CHECK_AND_FILL_VEC_DS_FULL(prong2, nSigTofPi2, tofNSigmaPi); + CHECK_AND_FILL_VEC_DS_FULL(prong0, nSigTofKa0, tofNSigmaKa); + CHECK_AND_FILL_VEC_DS_FULL(prong1, nSigTofKa1, tofNSigmaKa); + CHECK_AND_FILL_VEC_DS_FULL(prong2, nSigTofKa2, tofNSigmaKa); + CHECK_AND_FILL_VEC_DS_OBJECT_SIGNED(prong0, prong2, nSigTpcKaExpKa0, tpcNSigmaKa); + CHECK_AND_FILL_VEC_DS_OBJECT_SIGNED(prong2, prong0, nSigTpcPiExpPi2, tpcNSigmaPi); + CHECK_AND_FILL_VEC_DS_OBJECT_SIGNED(prong0, prong2, nSigTofKaExpKa0, tofNSigmaKa); + CHECK_AND_FILL_VEC_DS_OBJECT_SIGNED(prong2, prong0, nSigTofPiExpPi2, tofNSigmaPi); + // Combined PID variables CHECK_AND_FILL_VEC_DS_FULL(prong0, nSigTpcTofPi0, tpcTofNSigmaPi); CHECK_AND_FILL_VEC_DS_FULL(prong1, nSigTpcTofPi1, tpcTofNSigmaPi); @@ -163,6 +199,8 @@ class HfMlResponseDsToKKPi : public HfMlResponse CHECK_AND_FILL_VEC_DS_FULL(prong0, nSigTpcTofKa0, tpcTofNSigmaKa); CHECK_AND_FILL_VEC_DS_FULL(prong1, nSigTpcTofKa1, tpcTofNSigmaKa); CHECK_AND_FILL_VEC_DS_FULL(prong2, nSigTpcTofKa2, tpcTofNSigmaKa); + CHECK_AND_FILL_VEC_DS_OBJECT_SIGNED(prong0, prong2, nSigTpcTofKaExpKa0, tpcTofNSigmaKa); + CHECK_AND_FILL_VEC_DS_OBJECT_SIGNED(prong2, prong0, nSigTpcTofPiExpPi2, tpcTofNSigmaPi); // Ds specific variables CHECK_AND_FILL_VEC_DS_HFHELPER_SIGNED(candidate, absCos3PiK, absCos3PiKDsToKKPi, absCos3PiKDsToPiKK); @@ -193,6 +231,9 @@ class HfMlResponseDsToKKPi : public HfMlResponse FILL_MAP_DS(impactParameterXY0), FILL_MAP_DS(impactParameterXY1), FILL_MAP_DS(impactParameterXY2), + FILL_MAP_DS(impactParameterZ0), + FILL_MAP_DS(impactParameterZ1), + FILL_MAP_DS(impactParameterZ2), // TPC PID variables FILL_MAP_DS(nSigTpcPi0), FILL_MAP_DS(nSigTpcPi1), @@ -200,6 +241,16 @@ class HfMlResponseDsToKKPi : public HfMlResponse FILL_MAP_DS(nSigTpcKa0), FILL_MAP_DS(nSigTpcKa1), FILL_MAP_DS(nSigTpcKa2), + FILL_MAP_DS(nSigTofPi0), + FILL_MAP_DS(nSigTofPi1), + FILL_MAP_DS(nSigTofPi2), + FILL_MAP_DS(nSigTofKa0), + FILL_MAP_DS(nSigTofKa1), + FILL_MAP_DS(nSigTofKa2), + FILL_MAP_DS(nSigTpcKaExpKa0), + FILL_MAP_DS(nSigTpcPiExpPi2), + FILL_MAP_DS(nSigTofKaExpKa0), + FILL_MAP_DS(nSigTofPiExpPi2), // Combined PID variables FILL_MAP_DS(nSigTpcTofPi0), FILL_MAP_DS(nSigTpcTofPi1), @@ -207,6 +258,8 @@ class HfMlResponseDsToKKPi : public HfMlResponse FILL_MAP_DS(nSigTpcTofKa0), FILL_MAP_DS(nSigTpcTofKa1), FILL_MAP_DS(nSigTpcTofKa2), + FILL_MAP_DS(nSigTpcTofKaExpKa0), + FILL_MAP_DS(nSigTpcTofPiExpPi2), // Ds specific variables FILL_MAP_DS(absCos3PiK), @@ -221,5 +274,6 @@ class HfMlResponseDsToKKPi : public HfMlResponse #undef CHECK_AND_FILL_VEC_DS #undef CHECK_AND_FILL_VEC_DS_HFHELPER #undef CHECK_AND_FILL_VEC_DS_HFHELPER_SIGNED +#undef CHECK_AND_FILL_VEC_D0_OBJECT_HFHELPER_SIGNED #endif // PWGHF_CORE_HFMLRESPONSEDSTOKKPI_H_ diff --git a/PWGHF/Core/HfMlResponseDstarToD0Pi.h b/PWGHF/Core/HfMlResponseDstarToD0Pi.h index 7e0276b1b74..66fc3a712d4 100644 --- a/PWGHF/Core/HfMlResponseDstarToD0Pi.h +++ b/PWGHF/Core/HfMlResponseDstarToD0Pi.h @@ -61,6 +61,18 @@ break; \ } +// Very specific case of CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(OBJECT, FEATURE, GETTER) +// Use for push back different value for D*+ or D*- candidate getting the correct feature from two different objects (tracks) +#define CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE_FROMOBJECT(OBJECTPOS, OBJECTNEG, FEATURENAME, GETTER) \ + case static_cast(InputFeaturesDstarToD0Pi::FEATURENAME): { \ + if (candidate.signSoftPi() > 0) { \ + inputFeatures.emplace_back(OBJECTPOS.GETTER()); \ + } else { \ + inputFeatures.emplace_back(OBJECTNEG.GETTER()); \ + } \ + break; \ + } + // Very specific case of CHECK_AND_FILL_VEC_DSTAR_FULL(OBJECT, FEATURE, GETTER) // Use for push back deltaMassD0 for D*+ or D*- candidate #define CHECK_AND_FILL_VEC_DSTAR_DELTA_MASS_D0(FEATURENAME) \ @@ -91,10 +103,16 @@ enum class InputFeaturesDstarToD0Pi : uint8_t { ptSoftPi, impactParameter0, impactParameter1, + impactParameterZ0, + impactParameterZ1, impParamSoftPi, + impParamZSoftPi, impactParameterNormalised0, impactParameterNormalised1, + impactParameterZNormalised0, + impactParameterZNormalised1, normalisedImpParamSoftPi, + normalisedImpParamZSoftPi, cosThetaStarD0, massD0, deltaMassD0, @@ -150,30 +168,36 @@ class HfMlResponseDstarToD0Pi : public HfMlResponse CHECK_AND_FILL_VEC_DSTAR(cpaXYD0); CHECK_AND_FILL_VEC_DSTAR(deltaIPNormalisedMaxD0); CHECK_AND_FILL_VEC_DSTAR(impactParameterProductD0); - CHECK_AND_FILL_VEC_DSTAR(ptProng0); - CHECK_AND_FILL_VEC_DSTAR(ptProng1); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(ptProng0, ptProng1, ptProng0); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(ptProng1, ptProng0, ptProng1); CHECK_AND_FILL_VEC_DSTAR(ptSoftPi); - CHECK_AND_FILL_VEC_DSTAR(impactParameter0); - CHECK_AND_FILL_VEC_DSTAR(impactParameter1); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(impactParameter0, impactParameter1, impactParameter0); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(impactParameter1, impactParameter0, impactParameter1); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(impactParameterZ0, impactParameterZ1, impactParameterZ0); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(impactParameterZ1, impactParameterZ0, impactParameterZ1); CHECK_AND_FILL_VEC_DSTAR(impParamSoftPi); - CHECK_AND_FILL_VEC_DSTAR(impactParameterNormalised0); - CHECK_AND_FILL_VEC_DSTAR(impactParameterNormalised1); + CHECK_AND_FILL_VEC_DSTAR(impParamZSoftPi); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(impactParameterNormalised0, impactParameterNormalised1, impactParameterNormalised0); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(impactParameterNormalised1, impactParameterNormalised0, impactParameterNormalised1); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(impactParameterZNormalised0, impactParameterZNormalised1, impactParameterZNormalised0); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(impactParameterZNormalised1, impactParameterZNormalised0, impactParameterZNormalised1); CHECK_AND_FILL_VEC_DSTAR(normalisedImpParamSoftPi); + CHECK_AND_FILL_VEC_DSTAR(normalisedImpParamZSoftPi); CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(cosThetaStarD0, cosThetaStarD0Bar, cosThetaStarD0); CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(invMassD0, invMassD0Bar, massD0); CHECK_AND_FILL_VEC_DSTAR_DELTA_MASS_D0(deltaMassD0); - CHECK_AND_FILL_VEC_DSTAR_FULL(prong0, nSigmaTPCPiPr0, tpcNSigmaPi); - CHECK_AND_FILL_VEC_DSTAR_FULL(prong0, nSigmaTPCKaPr0, tpcNSigmaKa); - CHECK_AND_FILL_VEC_DSTAR_FULL(prong0, nSigmaTOFPiPr0, tofNSigmaPi); - CHECK_AND_FILL_VEC_DSTAR_FULL(prong0, nSigmaTOFKaPr0, tofNSigmaKa); - CHECK_AND_FILL_VEC_DSTAR_FULL(prong0, nSigmaTPCTOFPiPr0, tpcTofNSigmaPi); - CHECK_AND_FILL_VEC_DSTAR_FULL(prong0, nSigmaTPCTOFKaPr0, tpcTofNSigmaKa); - CHECK_AND_FILL_VEC_DSTAR_FULL(prong1, nSigmaTPCPiPr1, tpcNSigmaPi); - CHECK_AND_FILL_VEC_DSTAR_FULL(prong1, nSigmaTPCKaPr1, tpcNSigmaKa); - CHECK_AND_FILL_VEC_DSTAR_FULL(prong1, nSigmaTOFPiPr1, tofNSigmaPi); - CHECK_AND_FILL_VEC_DSTAR_FULL(prong1, nSigmaTOFKaPr1, tofNSigmaKa); - CHECK_AND_FILL_VEC_DSTAR_FULL(prong1, nSigmaTPCTOFPiPr1, tpcTofNSigmaPi); - CHECK_AND_FILL_VEC_DSTAR_FULL(prong1, nSigmaTPCTOFKaPr1, tpcTofNSigmaKa); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE_FROMOBJECT(prong0, prong1, nSigmaTPCPiPr0, tpcNSigmaPi); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE_FROMOBJECT(prong0, prong1, nSigmaTPCKaPr0, tpcNSigmaKa); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE_FROMOBJECT(prong0, prong1, nSigmaTOFPiPr0, tofNSigmaPi); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE_FROMOBJECT(prong0, prong1, nSigmaTOFKaPr0, tofNSigmaKa); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE_FROMOBJECT(prong0, prong1, nSigmaTPCTOFPiPr0, tpcTofNSigmaPi); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE_FROMOBJECT(prong0, prong1, nSigmaTPCTOFKaPr0, tpcTofNSigmaKa); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE_FROMOBJECT(prong1, prong0, nSigmaTPCPiPr1, tpcNSigmaPi); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE_FROMOBJECT(prong1, prong0, nSigmaTPCKaPr1, tpcNSigmaKa); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE_FROMOBJECT(prong1, prong0, nSigmaTOFPiPr1, tofNSigmaPi); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE_FROMOBJECT(prong1, prong0, nSigmaTOFKaPr1, tofNSigmaKa); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE_FROMOBJECT(prong1, prong0, nSigmaTPCTOFPiPr1, tpcTofNSigmaPi); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE_FROMOBJECT(prong1, prong0, nSigmaTPCTOFKaPr1, tpcTofNSigmaKa); CHECK_AND_FILL_VEC_DSTAR_FULL(prongSoftPi, nSigmaTPCPiPrSoftPi, tpcNSigmaPi); CHECK_AND_FILL_VEC_DSTAR_FULL(prongSoftPi, nSigmaTPCKaPrSoftPi, tpcNSigmaKa); CHECK_AND_FILL_VEC_DSTAR_FULL(prongSoftPi, nSigmaTOFPiPrSoftPi, tofNSigmaPi); @@ -205,10 +229,16 @@ class HfMlResponseDstarToD0Pi : public HfMlResponse FILL_MAP_DSTAR(ptSoftPi), FILL_MAP_DSTAR(impactParameter0), FILL_MAP_DSTAR(impactParameter1), + FILL_MAP_DSTAR(impactParameterZ0), + FILL_MAP_DSTAR(impactParameterZ1), FILL_MAP_DSTAR(impParamSoftPi), + FILL_MAP_DSTAR(impParamZSoftPi), FILL_MAP_DSTAR(impactParameterNormalised0), FILL_MAP_DSTAR(impactParameterNormalised1), + FILL_MAP_DSTAR(impactParameterZNormalised0), + FILL_MAP_DSTAR(impactParameterZNormalised1), FILL_MAP_DSTAR(normalisedImpParamSoftPi), + FILL_MAP_DSTAR(normalisedImpParamZSoftPi), FILL_MAP_DSTAR(cosThetaStarD0), FILL_MAP_DSTAR(massD0), FILL_MAP_DSTAR(deltaMassD0), diff --git a/PWGHF/Core/HfMlResponseLcToPKPi.h b/PWGHF/Core/HfMlResponseLcToPKPi.h index e011567c4d6..ea4767b85c6 100644 --- a/PWGHF/Core/HfMlResponseLcToPKPi.h +++ b/PWGHF/Core/HfMlResponseLcToPKPi.h @@ -54,6 +54,19 @@ break; \ } +// Variation of CHECK_AND_FILL_VEC_LCTOPKPI_OBJECT_SIGNED(OBJECT1, OBJECT2, FEATURE, GETTER) +// where OBJECT1 and OBJECT2 are the objects from which we call the GETTER method, and the variable +// is filled depending on whether it is a LcToPKPi or a LcToPiKP +#define CHECK_AND_FILL_VEC_LCTOPKPI_OBJECT_SIGNED(OBJECT1, OBJECT2, FEATURE, GETTER) \ + case static_cast(InputFeaturesLcToPKPi::FEATURE): { \ + if (caseLcToPKPi) { \ + inputFeatures.emplace_back(OBJECT1.GETTER()); \ + } else { \ + inputFeatures.emplace_back(OBJECT2.GETTER()); \ + } \ + break; \ + } + namespace o2::analysis { enum class InputFeaturesLcToPKPi : uint8_t { @@ -98,7 +111,13 @@ enum class InputFeaturesLcToPKPi : uint8_t { tpcTofNSigmaKa2, tpcTofNSigmaPr0, tpcTofNSigmaPr1, - tpcTofNSigmaPr2 + tpcTofNSigmaPr2, + tpcNSigmaPrExpPr0, + tpcNSigmaPiExpPi2, + tofNSigmaPrExpPr0, + tofNSigmaPiExpPi2, + tpcTofNSigmaPrExpPr0, + tpcTofNSigmaPiExpPi2 }; template @@ -118,7 +137,7 @@ class HfMlResponseLcToPKPi : public HfMlResponse /// \return inputFeatures vector template std::vector getInputFeatures(T1 const& candidate, - T2 const& prong0, T2 const& prong1, T2 const& prong2) + T2 const& prong0, T2 const& prong1, T2 const& prong2, bool const& caseLcToPKPi) { std::vector inputFeatures; @@ -149,6 +168,8 @@ class HfMlResponseLcToPKPi : public HfMlResponse CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong2, tpcNSigmaP2, tpcNSigmaPr); CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong2, tpcNSigmaKa2, tpcNSigmaKa); CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong2, tpcNSigmaPi2, tpcNSigmaPi); + CHECK_AND_FILL_VEC_LCTOPKPI_OBJECT_SIGNED(prong0, prong2, tpcNSigmaPrExpPr0, tpcNSigmaPr); + CHECK_AND_FILL_VEC_LCTOPKPI_OBJECT_SIGNED(prong2, prong0, tpcNSigmaPiExpPi2, tpcNSigmaPi); // TOF PID variables CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong0, tofNSigmaP0, tofNSigmaPr); CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong0, tofNSigmaKa0, tofNSigmaKa); @@ -159,6 +180,8 @@ class HfMlResponseLcToPKPi : public HfMlResponse CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong2, tofNSigmaP2, tofNSigmaPr); CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong2, tofNSigmaKa2, tofNSigmaKa); CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong2, tofNSigmaPi2, tofNSigmaPi); + CHECK_AND_FILL_VEC_LCTOPKPI_OBJECT_SIGNED(prong0, prong2, tofNSigmaPrExpPr0, tofNSigmaPr); + CHECK_AND_FILL_VEC_LCTOPKPI_OBJECT_SIGNED(prong2, prong0, tofNSigmaPiExpPi2, tofNSigmaPi); // Combined PID variables CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong0, tpcTofNSigmaPi0, tpcTofNSigmaPi); CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong1, tpcTofNSigmaPi1, tpcTofNSigmaPi); @@ -169,6 +192,8 @@ class HfMlResponseLcToPKPi : public HfMlResponse CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong0, tpcTofNSigmaPr0, tpcTofNSigmaPr); CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong1, tpcTofNSigmaPr1, tpcTofNSigmaPr); CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong2, tpcTofNSigmaPr2, tpcTofNSigmaPr); + CHECK_AND_FILL_VEC_LCTOPKPI_OBJECT_SIGNED(prong0, prong2, tpcTofNSigmaPrExpPr0, tpcTofNSigmaPr); + CHECK_AND_FILL_VEC_LCTOPKPI_OBJECT_SIGNED(prong2, prong0, tpcTofNSigmaPiExpPi2, tpcTofNSigmaPi); } } @@ -205,6 +230,8 @@ class HfMlResponseLcToPKPi : public HfMlResponse FILL_MAP_LCTOPKPI(tpcNSigmaP2), FILL_MAP_LCTOPKPI(tpcNSigmaKa2), FILL_MAP_LCTOPKPI(tpcNSigmaPi2), + FILL_MAP_LCTOPKPI(tpcNSigmaPrExpPr0), + FILL_MAP_LCTOPKPI(tpcNSigmaPiExpPi2), // TOF PID variables FILL_MAP_LCTOPKPI(tofNSigmaP0), FILL_MAP_LCTOPKPI(tofNSigmaKa0), @@ -215,6 +242,8 @@ class HfMlResponseLcToPKPi : public HfMlResponse FILL_MAP_LCTOPKPI(tofNSigmaP2), FILL_MAP_LCTOPKPI(tofNSigmaKa2), FILL_MAP_LCTOPKPI(tofNSigmaPi2), + FILL_MAP_LCTOPKPI(tofNSigmaPrExpPr0), + FILL_MAP_LCTOPKPI(tofNSigmaPiExpPi2), // Combined PID variables FILL_MAP_LCTOPKPI(tpcTofNSigmaPi0), FILL_MAP_LCTOPKPI(tpcTofNSigmaPi1), @@ -224,7 +253,9 @@ class HfMlResponseLcToPKPi : public HfMlResponse FILL_MAP_LCTOPKPI(tpcTofNSigmaKa2), FILL_MAP_LCTOPKPI(tpcTofNSigmaPr0), FILL_MAP_LCTOPKPI(tpcTofNSigmaPr1), - FILL_MAP_LCTOPKPI(tpcTofNSigmaPr2)}; + FILL_MAP_LCTOPKPI(tpcTofNSigmaPr2), + FILL_MAP_LCTOPKPI(tpcTofNSigmaPrExpPr0), + FILL_MAP_LCTOPKPI(tpcTofNSigmaPiExpPi2)}; } }; @@ -234,5 +265,6 @@ class HfMlResponseLcToPKPi : public HfMlResponse #undef CHECK_AND_FILL_VEC_LCTOPKPI_FULL #undef CHECK_AND_FILL_VEC_LCTOPKPI #undef CHECK_AND_FILL_VEC_LCTOPKPI_HFHELPER +#undef CHECK_AND_FILL_VEC_LCTOPKPI_OBJECT_SIGNED #endif // PWGHF_CORE_HFMLRESPONSELCTOPKPI_H_ diff --git a/PWGHF/Core/HfMlResponseOmegacToOmegaPi.h b/PWGHF/Core/HfMlResponseOmegacToOmegaPi.h new file mode 100644 index 00000000000..be2b5ac62ce --- /dev/null +++ b/PWGHF/Core/HfMlResponseOmegacToOmegaPi.h @@ -0,0 +1,152 @@ +// 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 HfMlResponseOmegacToOmegaPi.h +/// \brief Class to compute the ML response for Ωc± → Ω∓ π± analysis selections +/// \author Yunfan Liu , China University of Geosciences + +#ifndef PWGHF_CORE_HFMLRESPONSEOMEGACTOOMEGAPI_H_ +#define PWGHF_CORE_HFMLRESPONSEOMEGACTOOMEGAPI_H_ + +#include +#include +#include + +#include "CommonConstants/PhysicsConstants.h" + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/HfMlResponse.h" + +// Fill the map of available input features +// the key is the feature's name (std::string) +// the value is the corresponding value in EnumInputFeatures +#define FILL_MAP_OMEGAC0(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesOmegacToOmegaPi::FEATURE) \ + } + +// Check if the index of mCachedIndices (index associated to a FEATURE) +// matches the entry in EnumInputFeatures associated to this FEATURE +// if so, the inputFeatures vector is filled with the FEATURE's value +// by calling the corresponding GETTER from OBJECT +#define CHECK_AND_FILL_VEC_OMEGAC0_FULL(OBJECT, FEATURE, GETTER) \ + case static_cast(InputFeaturesOmegacToOmegaPi::FEATURE): { \ + inputFeatures.emplace_back(OBJECT.GETTER()); \ + break; \ + } + +// Specific case of CHECK_AND_FILL_VEC_OMEGAC0_FULL(OBJECT, FEATURE, GETTER) +// where OBJECT is named candidate and FEATURE = GETTER +#define CHECK_AND_FILL_VEC_OMEGAC0(GETTER) \ + case static_cast(InputFeaturesOmegacToOmegaPi::GETTER): { \ + inputFeatures.emplace_back(candidate.GETTER()); \ + break; \ + } + +// Variation of CHECK_AND_FILL_VEC_OMEGAC0_FULL(OBJECT, FEATURE, GETTER) +// where GETTER is a method of hfHelper +#define CHECK_AND_FILL_VEC_OMEGAC0_HFHELPER(OBJECT, FEATURE, GETTER) \ + case static_cast(InputFeaturesOmegacToOmegaPi::FEATURE): { \ + inputFeatures.emplace_back(hfHelper.GETTER(OBJECT)); \ + break; \ + } +namespace o2::analysis +{ +enum class InputFeaturesOmegacToOmegaPi : uint8_t { + + cosPaOmegacToPv = 0, + kfDcaXYPiFromOmegac, + cosThetaStarPiFromOmegac, + chi2TopoPiFromOmegacToPv, + dcaCharmBaryonDau, + invMassCascade, + massCascChi2OverNdf, + cosPaCascToPv, + kfDcaXYCascToPv, + nSigmaTPCPiFromV0, + nSigmaTPCPiFromOmegac, + nSigmaTPCKaFromCasc + +}; + +template +class HfMlResponseOmegacToOmegaPi : public HfMlResponse +{ + public: + /// Default constructor + HfMlResponseOmegacToOmegaPi() = default; + /// Default destructor + virtual ~HfMlResponseOmegacToOmegaPi() = default; + + HfHelper hfHelper; + + /// Method to get the input features vector needed for ML inference + /// \param candidate is the OMEGAC0 candidate + /// \param lamProngPi is the candidate's lamProngPi + /// \return inputFeatures vector + template + std::vector getInputFeatures(T1 const& candidate, T2 const& lamProngPi, T2 const& cascProng, T3 const& charmBaryonProng) + { + std::vector inputFeatures; + + for (const auto& idx : MlResponse::mCachedIndices) { + switch (idx) { + + CHECK_AND_FILL_VEC_OMEGAC0(kfDcaXYPiFromOmegac); + CHECK_AND_FILL_VEC_OMEGAC0(cosThetaStarPiFromOmegac); + CHECK_AND_FILL_VEC_OMEGAC0(chi2TopoPiFromOmegacToPv); + CHECK_AND_FILL_VEC_OMEGAC0(dcaCharmBaryonDau); + CHECK_AND_FILL_VEC_OMEGAC0(invMassCascade); + CHECK_AND_FILL_VEC_OMEGAC0(massCascChi2OverNdf); + CHECK_AND_FILL_VEC_OMEGAC0(kfDcaXYCascToPv); + CHECK_AND_FILL_VEC_OMEGAC0_FULL(candidate, cosPaOmegacToPv, cosPACharmBaryon); + CHECK_AND_FILL_VEC_OMEGAC0_FULL(candidate, cosPaCascToPv, cosPACasc); + // TPC PID variables + CHECK_AND_FILL_VEC_OMEGAC0_FULL(lamProngPi, nSigmaTPCPiFromV0, tpcNSigmaPi); + CHECK_AND_FILL_VEC_OMEGAC0_FULL(cascProng, nSigmaTPCKaFromCasc, tpcNSigmaKa); + CHECK_AND_FILL_VEC_OMEGAC0_FULL(charmBaryonProng, nSigmaTPCPiFromOmegac, tpcNSigmaPi); + } + } + + return inputFeatures; + } + + protected: + /// Method to fill the map of available input features + void setAvailableInputFeatures() + { + MlResponse::mAvailableInputFeatures = { + + FILL_MAP_OMEGAC0(invMassCascade), + FILL_MAP_OMEGAC0(cosPaOmegacToPv), + FILL_MAP_OMEGAC0(dcaCharmBaryonDau), + FILL_MAP_OMEGAC0(kfDcaXYPiFromOmegac), + FILL_MAP_OMEGAC0(cosThetaStarPiFromOmegac), + FILL_MAP_OMEGAC0(chi2TopoPiFromOmegacToPv), + FILL_MAP_OMEGAC0(massCascChi2OverNdf), + FILL_MAP_OMEGAC0(cosPaCascToPv), + FILL_MAP_OMEGAC0(kfDcaXYCascToPv), + // TPC PID variables + FILL_MAP_OMEGAC0(nSigmaTPCPiFromV0), + FILL_MAP_OMEGAC0(nSigmaTPCKaFromCasc), + FILL_MAP_OMEGAC0(nSigmaTPCPiFromOmegac), + + }; + } +}; + +} // namespace o2::analysis + +#undef FILL_MAP_OMEGAC0 +#undef CHECK_AND_FILL_VEC_OMEGAC0_FULL +#undef CHECK_AND_FILL_VEC_OMEGAC0 +#undef CHECK_AND_FILL_VEC_OMEGAC0_HFHELPER +#endif // PWGHF_CORE_HFMLRESPONSEOMEGACTOOMEGAPI_H_ diff --git a/PWGHF/Core/HfMlResponseXicToPKPi.h b/PWGHF/Core/HfMlResponseXicToPKPi.h index 398357a66d6..94542745772 100644 --- a/PWGHF/Core/HfMlResponseXicToPKPi.h +++ b/PWGHF/Core/HfMlResponseXicToPKPi.h @@ -48,6 +48,19 @@ break; \ } +// Variation of CHECK_AND_FILL_VEC_XIC_OBJECT_SIGNED(OBJECT1, OBJECT2, FEATURE, GETTER) +// where OBJECT1 and OBJECT2 are the objects from which we call the GETTER method, and the variable +// is filled depending on whether it is a XicToPKPi or a XicToPiKP +#define CHECK_AND_FILL_VEC_XIC_OBJECT_SIGNED(OBJECT1, OBJECT2, FEATURE, GETTER) \ + case static_cast(InputFeaturesXicToPKPi::FEATURE): { \ + if (caseXicToPKPi) { \ + inputFeatures.emplace_back(OBJECT1.GETTER()); \ + } else { \ + inputFeatures.emplace_back(OBJECT2.GETTER()); \ + } \ + break; \ + } + namespace o2::analysis { enum class InputFeaturesXicToPKPi : uint8_t { @@ -92,8 +105,13 @@ enum class InputFeaturesXicToPKPi : uint8_t { tpcTofNSigmaKa2, tpcTofNSigmaPr0, tpcTofNSigmaPr1, - tpcTofNSigmaPr2 - + tpcTofNSigmaPr2, + tpcNSigmaPrExpPr0, + tpcNSigmaPiExpPi2, + tofNSigmaPrExpPr0, + tofNSigmaPiExpPi2, + tpcTofNSigmaPrExpPr0, + tpcTofNSigmaPiExpPi2 }; template @@ -113,7 +131,7 @@ class HfMlResponseXicToPKPi : public HfMlResponse /// \return inputFeatures vector template std::vector getInputFeatures(T1 const& candidate, - T2 const& prong0, T2 const& prong1, T2 const& prong2) + T2 const& prong0, T2 const& prong1, T2 const& prong2, bool const& caseXicToPKPi) { std::vector inputFeatures; @@ -144,6 +162,8 @@ class HfMlResponseXicToPKPi : public HfMlResponse CHECK_AND_FILL_VEC_XIC_FULL(prong2, tpcNSigmaP2, tpcNSigmaPr); CHECK_AND_FILL_VEC_XIC_FULL(prong2, tpcNSigmaKa2, tpcNSigmaKa); CHECK_AND_FILL_VEC_XIC_FULL(prong2, tpcNSigmaPi2, tpcNSigmaPi); + CHECK_AND_FILL_VEC_XIC_OBJECT_SIGNED(prong0, prong2, tpcNSigmaPrExpPr0, tpcNSigmaPr); + CHECK_AND_FILL_VEC_XIC_OBJECT_SIGNED(prong2, prong0, tpcNSigmaPiExpPi2, tpcNSigmaPi); // TOF PID variables CHECK_AND_FILL_VEC_XIC_FULL(prong0, tofNSigmaP0, tofNSigmaPr); CHECK_AND_FILL_VEC_XIC_FULL(prong0, tofNSigmaKa0, tofNSigmaKa); @@ -154,6 +174,8 @@ class HfMlResponseXicToPKPi : public HfMlResponse CHECK_AND_FILL_VEC_XIC_FULL(prong2, tofNSigmaP2, tofNSigmaPr); CHECK_AND_FILL_VEC_XIC_FULL(prong2, tofNSigmaKa2, tofNSigmaKa); CHECK_AND_FILL_VEC_XIC_FULL(prong2, tofNSigmaPi2, tofNSigmaPi); + CHECK_AND_FILL_VEC_XIC_OBJECT_SIGNED(prong0, prong2, tofNSigmaPrExpPr0, tofNSigmaPr); + CHECK_AND_FILL_VEC_XIC_OBJECT_SIGNED(prong2, prong0, tofNSigmaPiExpPi2, tofNSigmaPi); // Combined PID variables CHECK_AND_FILL_VEC_XIC_FULL(prong0, tpcTofNSigmaPi0, tpcTofNSigmaPi); CHECK_AND_FILL_VEC_XIC_FULL(prong1, tpcTofNSigmaPi1, tpcTofNSigmaPi); @@ -164,6 +186,8 @@ class HfMlResponseXicToPKPi : public HfMlResponse CHECK_AND_FILL_VEC_XIC_FULL(prong0, tpcTofNSigmaPr0, tpcTofNSigmaPr); CHECK_AND_FILL_VEC_XIC_FULL(prong1, tpcTofNSigmaPr1, tpcTofNSigmaPr); CHECK_AND_FILL_VEC_XIC_FULL(prong2, tpcTofNSigmaPr2, tpcTofNSigmaPr); + CHECK_AND_FILL_VEC_XIC_OBJECT_SIGNED(prong0, prong2, tpcTofNSigmaPrExpPr0, tpcTofNSigmaPr); + CHECK_AND_FILL_VEC_XIC_OBJECT_SIGNED(prong2, prong0, tpcTofNSigmaPiExpPi2, tpcTofNSigmaPi); } } @@ -200,6 +224,8 @@ class HfMlResponseXicToPKPi : public HfMlResponse FILL_MAP_XIC(tpcNSigmaP2), FILL_MAP_XIC(tpcNSigmaKa2), FILL_MAP_XIC(tpcNSigmaPi2), + FILL_MAP_XIC(tpcNSigmaPrExpPr0), + FILL_MAP_XIC(tpcNSigmaPiExpPi2), // TOF PID variables FILL_MAP_XIC(tofNSigmaP0), FILL_MAP_XIC(tofNSigmaKa0), @@ -210,6 +236,8 @@ class HfMlResponseXicToPKPi : public HfMlResponse FILL_MAP_XIC(tofNSigmaP2), FILL_MAP_XIC(tofNSigmaKa2), FILL_MAP_XIC(tofNSigmaPi2), + FILL_MAP_XIC(tofNSigmaPrExpPr0), + FILL_MAP_XIC(tofNSigmaPiExpPi2), // Combined PID variables FILL_MAP_XIC(tpcTofNSigmaPi0), FILL_MAP_XIC(tpcTofNSigmaPi1), @@ -219,7 +247,9 @@ class HfMlResponseXicToPKPi : public HfMlResponse FILL_MAP_XIC(tpcTofNSigmaKa2), FILL_MAP_XIC(tpcTofNSigmaPr0), FILL_MAP_XIC(tpcTofNSigmaPr1), - FILL_MAP_XIC(tpcTofNSigmaPr2)}; + FILL_MAP_XIC(tpcTofNSigmaPr2), + FILL_MAP_XIC(tpcTofNSigmaPrExpPr0), + FILL_MAP_XIC(tpcTofNSigmaPiExpPi2)}; } }; @@ -228,5 +258,6 @@ class HfMlResponseXicToPKPi : public HfMlResponse #undef FILL_MAP_XIC #undef CHECK_AND_FILL_VEC_XIC_FULL #undef CHECK_AND_FILL_VEC_XIC +#undef CHECK_AND_FILL_VEC_XIC_OBJECT_SIGNED #endif // PWGHF_CORE_HFMLRESPONSEXICTOPKPI_H_ diff --git a/PWGHF/Core/HfMlResponseXicToXiPiPi.h b/PWGHF/Core/HfMlResponseXicToXiPiPi.h new file mode 100644 index 00000000000..d8c040b28ce --- /dev/null +++ b/PWGHF/Core/HfMlResponseXicToXiPiPi.h @@ -0,0 +1,204 @@ +// 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 HfMlResponseXicToXiPiPi.h +/// \brief Class to compute the ML response for Ξc± → Ξ∓ π± π± analysis selections +/// \author Jaeyoon Cho , Inha University + +#ifndef PWGHF_CORE_HFMLRESPONSEXICTOXIPIPI_H_ +#define PWGHF_CORE_HFMLRESPONSEXICTOXIPIPI_H_ + +#include +#include +#include + +#include "PWGHF/Core/HfMlResponse.h" + +// Fill the map of available input features +// the key is the feature's name (std::string) +// the value is the corresponding value in EnumInputFeatures +#define FILL_MAP_XICTOXIPIPI(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesXicToXiPiPi::FEATURE) \ + } + +// Check if the index of mCachedIndices (index associated to a FEATURE) +// matches the entry in EnumInputFeatures associated to this FEATURE +// if so, the inputFeatures vector is filled with the FEATURE's value +// by calling the corresponding GETTER from OBJECT +#define CHECK_AND_FILL_VEC_XICTOXIPIPI_FULL(OBJECT, FEATURE, GETTER) \ + case static_cast(InputFeaturesXicToXiPiPi::FEATURE): { \ + inputFeatures.emplace_back(OBJECT.GETTER()); \ + break; \ + } + +// Specific case of CHECK_AND_FILL_VEC_XICTOXIPIPI_FULL(OBJECT, FEATURE, GETTER) +// where OBJECT is named candidate and FEATURE = GETTER +#define CHECK_AND_FILL_VEC_XICTOXIPIPI(GETTER) \ + case static_cast(InputFeaturesXicToXiPiPi::GETTER): { \ + inputFeatures.emplace_back(candidate.GETTER()); \ + break; \ + } + +namespace o2::analysis +{ + +enum class InputFeaturesXicToXiPiPi : uint8_t { + ptProng0 = 0, + ptProng1, + ptProng2, + chi2PCA, + decayLength, + decayLengthNormalised, + decayLengthXY, + decayLengthXYNormalised, + cpa, + cpaXY, + cosPaXi, + cosPaXYXi, + cosPaLambda, + cosPaXYLambda, + impactParameterXi, + impactParameterPi0, + impactParameterPi1, + invMassXi, + invMassLambda, + dcaXiDaughters, + dcaV0Daughters, + dcaPosToPV, + dcaNegToPV, + dcaBachelorToPV, + dcaXYCascToPV, + dcaZCascToPV, + nSigTpcPiFromXicPlus0, + nSigTpcPiFromXicPlus1, + nSigTpcBachelorPi, + nSigTpcPiFromLambda, + nSigTpcPrFromLambda, + nSigTofPiFromXicPlus0, + nSigTofPiFromXicPlus1, + nSigTofBachelorPi, + nSigTofPiFromLambda, + nSigTofPrFromLambda +}; + +template +class HfMlResponseXicToXiPiPi : public HfMlResponse +{ + public: + /// Default constructor + HfMlResponseXicToXiPiPi() = default; + /// Default destructor + virtual ~HfMlResponseXicToXiPiPi() = default; + + /// Method to get the input features vector needed for ML inference + /// \param candidate is the Xic candidate + /// \return inputFeatures vector + template + std::vector getInputFeatures(T1 const& candidate) + { + std::vector inputFeatures; + + for (const auto& idx : MlResponse::mCachedIndices) { + switch (idx) { + CHECK_AND_FILL_VEC_XICTOXIPIPI(ptProng0); + CHECK_AND_FILL_VEC_XICTOXIPIPI(ptProng1); + CHECK_AND_FILL_VEC_XICTOXIPIPI(ptProng2); + CHECK_AND_FILL_VEC_XICTOXIPIPI(chi2PCA); + CHECK_AND_FILL_VEC_XICTOXIPIPI(decayLength); + CHECK_AND_FILL_VEC_XICTOXIPIPI(decayLengthNormalised); + CHECK_AND_FILL_VEC_XICTOXIPIPI(decayLengthXY); + CHECK_AND_FILL_VEC_XICTOXIPIPI(decayLengthXYNormalised); + CHECK_AND_FILL_VEC_XICTOXIPIPI(cpa); + CHECK_AND_FILL_VEC_XICTOXIPIPI(cpaXY); + CHECK_AND_FILL_VEC_XICTOXIPIPI(cosPaXi); + CHECK_AND_FILL_VEC_XICTOXIPIPI(cosPaXYXi); + CHECK_AND_FILL_VEC_XICTOXIPIPI(cosPaLambda); + CHECK_AND_FILL_VEC_XICTOXIPIPI(cosPaXYLambda); + CHECK_AND_FILL_VEC_XICTOXIPIPI_FULL(candidate, impactParameterXi, impactParameter0); + CHECK_AND_FILL_VEC_XICTOXIPIPI_FULL(candidate, impactParameterPi0, impactParameter1); + CHECK_AND_FILL_VEC_XICTOXIPIPI_FULL(candidate, impactParameterPi1, impactParameter2); + CHECK_AND_FILL_VEC_XICTOXIPIPI(invMassXi); + CHECK_AND_FILL_VEC_XICTOXIPIPI(invMassLambda); + CHECK_AND_FILL_VEC_XICTOXIPIPI(dcaXiDaughters); + CHECK_AND_FILL_VEC_XICTOXIPIPI(dcaV0Daughters); + CHECK_AND_FILL_VEC_XICTOXIPIPI(dcaPosToPV); + CHECK_AND_FILL_VEC_XICTOXIPIPI(dcaNegToPV); + CHECK_AND_FILL_VEC_XICTOXIPIPI(dcaBachelorToPV); + CHECK_AND_FILL_VEC_XICTOXIPIPI(dcaXYCascToPV); + CHECK_AND_FILL_VEC_XICTOXIPIPI(dcaZCascToPV); + CHECK_AND_FILL_VEC_XICTOXIPIPI(nSigTpcPiFromXicPlus0); + CHECK_AND_FILL_VEC_XICTOXIPIPI(nSigTpcPiFromXicPlus1); + CHECK_AND_FILL_VEC_XICTOXIPIPI(nSigTpcBachelorPi); + CHECK_AND_FILL_VEC_XICTOXIPIPI(nSigTpcPiFromLambda); + CHECK_AND_FILL_VEC_XICTOXIPIPI(nSigTpcPrFromLambda); + CHECK_AND_FILL_VEC_XICTOXIPIPI(nSigTofPiFromXicPlus0); + CHECK_AND_FILL_VEC_XICTOXIPIPI(nSigTofPiFromXicPlus1); + CHECK_AND_FILL_VEC_XICTOXIPIPI(nSigTofBachelorPi); + CHECK_AND_FILL_VEC_XICTOXIPIPI(nSigTofPiFromLambda); + CHECK_AND_FILL_VEC_XICTOXIPIPI(nSigTofPrFromLambda); + } + } + + return inputFeatures; + } + + protected: + /// Method to fill the map of available input features + void setAvailableInputFeatures() + { + MlResponse::mAvailableInputFeatures = { + FILL_MAP_XICTOXIPIPI(ptProng0), + FILL_MAP_XICTOXIPIPI(ptProng1), + FILL_MAP_XICTOXIPIPI(ptProng2), + FILL_MAP_XICTOXIPIPI(chi2PCA), + FILL_MAP_XICTOXIPIPI(decayLength), + FILL_MAP_XICTOXIPIPI(decayLengthNormalised), + FILL_MAP_XICTOXIPIPI(decayLengthXY), + FILL_MAP_XICTOXIPIPI(decayLengthXYNormalised), + FILL_MAP_XICTOXIPIPI(cpa), + FILL_MAP_XICTOXIPIPI(cpaXY), + FILL_MAP_XICTOXIPIPI(cosPaXi), + FILL_MAP_XICTOXIPIPI(cosPaXYXi), + FILL_MAP_XICTOXIPIPI(cosPaLambda), + FILL_MAP_XICTOXIPIPI(cosPaXYLambda), + FILL_MAP_XICTOXIPIPI(impactParameterXi), + FILL_MAP_XICTOXIPIPI(impactParameterPi0), + FILL_MAP_XICTOXIPIPI(impactParameterPi1), + FILL_MAP_XICTOXIPIPI(invMassXi), + FILL_MAP_XICTOXIPIPI(invMassLambda), + FILL_MAP_XICTOXIPIPI(dcaXiDaughters), + FILL_MAP_XICTOXIPIPI(dcaV0Daughters), + FILL_MAP_XICTOXIPIPI(dcaPosToPV), + FILL_MAP_XICTOXIPIPI(dcaNegToPV), + FILL_MAP_XICTOXIPIPI(dcaBachelorToPV), + FILL_MAP_XICTOXIPIPI(dcaXYCascToPV), + FILL_MAP_XICTOXIPIPI(dcaZCascToPV), + FILL_MAP_XICTOXIPIPI(nSigTpcPiFromXicPlus0), + FILL_MAP_XICTOXIPIPI(nSigTpcPiFromXicPlus1), + FILL_MAP_XICTOXIPIPI(nSigTpcBachelorPi), + FILL_MAP_XICTOXIPIPI(nSigTpcPiFromLambda), + FILL_MAP_XICTOXIPIPI(nSigTpcPrFromLambda), + FILL_MAP_XICTOXIPIPI(nSigTofPiFromXicPlus0), + FILL_MAP_XICTOXIPIPI(nSigTofPiFromXicPlus1), + FILL_MAP_XICTOXIPIPI(nSigTofBachelorPi), + FILL_MAP_XICTOXIPIPI(nSigTofPiFromLambda), + FILL_MAP_XICTOXIPIPI(nSigTofPrFromLambda)}; + } +}; + +} // namespace o2::analysis + +#undef FILL_MAP_XICTOXIPIPI +#undef CHECK_AND_FILL_VEC_XICTOXIPIPI_FULL +#undef CHECK_AND_FILL_VEC_XICTOXIPIPI + +#endif // PWGHF_CORE_HFMLRESPONSEXICTOXIPIPI_H_ diff --git a/PWGHF/Core/SelectorCuts.h b/PWGHF/Core/SelectorCuts.h index fecacb15b1e..a3313abe79e 100644 --- a/PWGHF/Core/SelectorCuts.h +++ b/PWGHF/Core/SelectorCuts.h @@ -11,6 +11,8 @@ /// \file SelectorCuts.h /// \brief Default pT bins and cut arrays for heavy-flavour selectors and analysis tasks +/// +/// \author Anton Alkin , CERN #ifndef PWGHF_CORE_SELECTORCUTS_H_ #define PWGHF_CORE_SELECTORCUTS_H_ @@ -25,12 +27,12 @@ namespace o2::analysis namespace hf_cuts_single_track { -static constexpr int nBinsPtTrack = 6; -static constexpr int nCutVarsTrack = 2; +static constexpr int NBinsPtTrack = 6; +static constexpr int NCutVarsTrack = 4; // default values for the pT bin edges (can be used to configure histogram axis) // common for any candidate type (2-prong, 3-prong) // offset by 1 from the bin numbers in cuts array -constexpr double binsPtTrack[nBinsPtTrack + 1] = { +constexpr double BinsPtTrack[NBinsPtTrack + 1] = { 0, 0.5, 1.0, @@ -38,35 +40,35 @@ constexpr double binsPtTrack[nBinsPtTrack + 1] = { 2.0, 3.0, 1000.0}; -auto vecBinsPtTrack = std::vector{binsPtTrack, binsPtTrack + nBinsPtTrack + 1}; - -// default values for the cuts of displaced tracks -constexpr double cutsTrack[nBinsPtTrack][nCutVarsTrack] = {{0.0025, 10.}, /* 0 < pt < 0.5 */ - {0.0025, 10.}, /* 0.5 < pt < 1 */ - {0.0025, 10.}, /* 1 < pt < 1.5 */ - {0.0025, 10.}, /* 1.5 < pt < 2 */ - {0.0000, 10.}, /* 2 < pt < 3 */ - {0.0000, 10.}}; /* 3 < pt < 1000 */ - -// default values for the cuts of primary tracks (e.g. D* soft pions) -constexpr double cutsTrackPrimary[nBinsPtTrack][nCutVarsTrack] = {{0.0000, 2.}, /* 0 < pt < 0.5 */ - {0.0000, 2.}, /* 0.5 < pt < 1 */ - {0.0000, 2.}, /* 1 < pt < 1.5 */ - {0.0000, 2.}, /* 1.5 < pt < 2 */ - {0.0000, 2.}, /* 2 < pt < 3 */ - {0.0000, 2.}}; /* 3 < pt < 1000 */ +auto vecBinsPtTrack = std::vector{BinsPtTrack, BinsPtTrack + NBinsPtTrack + 1}; + +// default values for the dca_xy and dca_z cuts of displaced tracks +constexpr double CutsTrack[NBinsPtTrack][NCutVarsTrack] = {{0.0000, 10., 0.0000, 100.}, /* 0 < pt < 0.5 */ + {0.0000, 10., 0.0000, 100.}, /* 0.5 < pt < 1 */ + {0.0000, 10., 0.0000, 100.}, /* 1 < pt < 1.5 */ + {0.0000, 10., 0.0000, 100.}, /* 1.5 < pt < 2 */ + {0.0000, 10., 0.0000, 100.}, /* 2 < pt < 3 */ + {0.0000, 10., 0.0000, 100.}}; /* 3 < pt < 1000 */ + +// default values for the dca_xy and dca_z cuts of primary tracks (e.g. D* soft pions) +constexpr double CutsTrackPrimary[NBinsPtTrack][NCutVarsTrack] = {{0.0000, 2., 0.0000, 100.}, /* 0 < pt < 0.5 */ + {0.0000, 2., 0.0000, 100.}, /* 0.5 < pt < 1 */ + {0.0000, 2., 0.0000, 100.}, /* 1 < pt < 1.5 */ + {0.0000, 2., 0.0000, 100.}, /* 1.5 < pt < 2 */ + {0.0000, 2., 0.0000, 100.}, /* 2 < pt < 3 */ + {0.0000, 2., 0.0000, 100.}}; /* 3 < pt < 1000 */ // row labels static const std::vector labelsPtTrack{}; // column labels -static const std::vector labelsCutVarTrack = {"min_dcaxytoprimary", "max_dcaxytoprimary"}; +static const std::vector labelsCutVarTrack = {"min_dcaxytoprimary", "max_dcaxytoprimary", "min_dcaztoprimary", "max_dcaztoprimary"}; } // namespace hf_cuts_single_track namespace hf_presel_pid { // default values for the PID cuts for protons in the track-index-skim-creator -constexpr float cutsPid[4][6] = {{0.f, 1000.f, 5.f, 0.f, 1000.f, 5.f}, +constexpr float CutsPid[4][6] = {{0.f, 1000.f, 5.f, 0.f, 1000.f, 5.f}, {0.f, 1000.f, 5.f, 0.f, 1000.f, 5.f}, {0.f, 1000.f, 5.f, 0.f, 1000.f, 5.f}, {0.f, 1000.f, 5.f, 0.f, 1000.f, 5.f}}; @@ -76,18 +78,18 @@ static const std::vector labelsRowsPid = {"ProtonInLcToPKPi", "Prot namespace hf_cuts_bdt_multiclass { -static constexpr int nBinsPt = 1; -static constexpr int nCutBdtScores = 3; +static constexpr int NBinsPt = 1; +static constexpr int NCutBdtScores = 3; // default values for the pT bin edges (can be used to configure histogram axis) // common for any charm candidate // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 0., 1000.0}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts -constexpr double cuts[nBinsPt][nCutBdtScores] = {{0.1, 0.5, 0.5}}; +constexpr double Cuts[NBinsPt][NCutBdtScores] = {{0.1, 0.5, 0.5}}; // row labels static const std::vector labelsPt{}; @@ -115,10 +117,10 @@ enum CutDirection { CutNot // do not cut on score }; -static constexpr int nBinsPt = 12; -static constexpr int nCutScores = 3; +static constexpr int NBinsPt = 12; +static constexpr int NCutScores = 3; // default values for the pT bin edges, offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 0., 1., 2., @@ -132,18 +134,18 @@ constexpr double binsPt[nBinsPt + 1] = { 16., 24., 50.}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the ML model paths, one model per pT bin static const std::vector modelPaths = { ""}; // default values for the cut directions -constexpr int cutDir[nCutScores] = {CutGreater, CutSmaller, CutSmaller}; -auto vecCutDir = std::vector{cutDir, cutDir + nCutScores}; +constexpr int CutDir[NCutScores] = {CutGreater, CutSmaller, CutSmaller}; +auto vecCutDir = std::vector{CutDir, CutDir + NCutScores}; // default values for the cuts -constexpr double cuts[nBinsPt][nCutScores] = { +constexpr double Cuts[NBinsPt][NCutScores] = { {0.5, 0.5, 0.5}, {0.5, 0.5, 0.5}, {0.5, 0.5, 0.5}, @@ -179,19 +181,19 @@ static const std::vector labelsDmesCutScore = {"ML score charm bkg" namespace hf_cuts_presel_2prong { -static constexpr int nBinsPt = 2; -static constexpr int nCutVars = 4; +static constexpr int NBinsPt = 2; +static constexpr int NCutVars = 4; // default values for the pT bin edges (can be used to configure histogram axis) // common for any 2-prong candidate // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 1., 5., 1000.0}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts -constexpr double cuts[nBinsPt][nCutVars] = {{1.65, 2.15, 0.5, 100.}, /* 1 < pt < 5 */ +constexpr double Cuts[NBinsPt][NCutVars] = {{1.65, 2.15, 0.5, 100.}, /* 1 < pt < 5 */ {1.65, 2.15, 0.5, 100.}}; /* 5 < pt < 1000 */ // row labels @@ -203,19 +205,19 @@ static const std::vector labelsCutVar = {"massMin", "massMax", "cos namespace hf_cuts_presel_3prong { -static constexpr int nBinsPt = 2; -static constexpr int nCutVars = 4; +static constexpr int NBinsPt = 2; +static constexpr int NCutVars = 4; // default values for the pT bin edges (can be used to configure histogram axis) // common for any 3-prong candidate // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 1., 5., 1000.0}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts -constexpr double cuts[nBinsPt][nCutVars] = {{1.75, 2.05, 0.7, 0.02}, /* 1 < pt < 5 */ +constexpr double Cuts[NBinsPt][NCutVars] = {{1.75, 2.05, 0.7, 0.02}, /* 1 < pt < 5 */ {1.75, 2.05, 0.5, 0.02}}; /* 5 < pt < 1000 */ // row labels @@ -227,18 +229,18 @@ static const std::vector labelsCutVar = {"massMin", "massMax", "cos namespace hf_cuts_presel_ds { -static constexpr int nBinsPt = 2; -static constexpr int nCutVars = 5; +static constexpr int NBinsPt = 2; +static constexpr int NCutVars = 5; // default values for the pT bin edges (can be used to configure histogram axis) // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 1., 5., 1000.0}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts -constexpr double cuts[nBinsPt][nCutVars] = {{1.70, 2.15, 0.7, 0.02, 0.02}, /* 1 < pt < 5 */ +constexpr double Cuts[NBinsPt][NCutVars] = {{1.70, 2.15, 0.7, 0.02, 0.02}, /* 1 < pt < 5 */ {1.70, 2.15, 0.5, 0.02, 0.02}}; /* 5 < pt < 1000 */ // row labels @@ -250,18 +252,18 @@ static const std::vector labelsCutVar = {"massMin", "massMax", "cos namespace hf_cuts_presel_dstar { -static constexpr int nBinsPt = 2; -static constexpr int nCutVars = 2; +static constexpr int NBinsPt = 2; +static constexpr int NCutVars = 2; // default values for the pT bin edges (can be used to configure histogram axis) // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 1., 5., 1000.0}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts -constexpr double cuts[nBinsPt][nCutVars] = {{0.17, 0.05}, /* 1 < pt < 5 */ +constexpr double Cuts[NBinsPt][NCutVars] = {{0.17, 0.05}, /* 1 < pt < 5 */ {0.17, 0.08}}; /* 5 < pt < 1000 */ // row labels @@ -273,11 +275,11 @@ static const std::vector labelsCutVar = {"deltaMassMax", "deltaMass namespace hf_cuts_d0_to_pi_k { -static constexpr int nBinsPt = 25; -static constexpr int nCutVars = 15; +static constexpr int NBinsPt = 25; +static constexpr int NCutVars = 15; // default values for the pT bin edges (can be used to configure histogram axis) // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 0, 0.5, 1.0, @@ -304,10 +306,10 @@ constexpr double binsPt[nBinsPt + 1] = { 36.0, 50.0, 100.0}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts -constexpr double cuts[nBinsPt][nCutVars] = {{0.400, 350. * 1E-4, 0.8, 0.5, 0.5, 1000. * 1E-4, 1000. * 1E-4, -5000. * 1E-8, 0.80, 0., 0., 10., 10., 0.06, 0.5}, /* 0 < pT < 0.5 */ +constexpr double Cuts[NBinsPt][NCutVars] = {{0.400, 350. * 1E-4, 0.8, 0.5, 0.5, 1000. * 1E-4, 1000. * 1E-4, -5000. * 1E-8, 0.80, 0., 0., 10., 10., 0.06, 0.5}, /* 0 < pT < 0.5 */ {0.400, 350. * 1E-4, 0.8, 0.5, 0.5, 1000. * 1E-4, 1000. * 1E-4, -5000. * 1E-8, 0.80, 0., 0., 10., 10., 0.06, 0.5}, /* 0.5 < pT < 1 */ {0.400, 300. * 1E-4, 0.8, 0.4, 0.4, 1000. * 1E-4, 1000. * 1E-4, -25000. * 1E-8, 0.80, 0., 0., 10., 10., 0.06, 0.5}, /* 1 < pT < 1.5 */ {0.400, 300. * 1E-4, 0.8, 0.4, 0.4, 1000. * 1E-4, 1000. * 1E-4, -25000. * 1E-8, 0.80, 0., 0., 10., 10., 0.06, 0.5}, /* 1.5 < pT < 2 */ @@ -367,11 +369,11 @@ static const std::vector labelsCutVar = {"m", "DCA", "cos theta*", namespace hf_cuts_dstar_to_d0_pi { -static constexpr int nBinsPt = 25; -static constexpr int nCutVars = 8; +static constexpr int NBinsPt = 25; +static constexpr int NCutVars = 8; // default values for the pT bin edges (can be used to configure histogram axis) // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 0., 0.5, 1.0, @@ -398,7 +400,7 @@ constexpr double binsPt[nBinsPt + 1] = { 36.0, 50.0, 100.0}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // row labels static const std::vector labelsPt = { @@ -432,7 +434,7 @@ static const std::vector labelsPt = { static const std::vector labelsCutVar = {"ptSoftPiMin", "ptSoftPiMax", "d0SoftPi", "d0SoftPiNormalised", "deltaMInvDstar", "chi2PCA", "d0Prong0Normalised", "d0Prong1Normalised"}; // default values for the cuts -constexpr double cuts[nBinsPt][nCutVars] = {{0.05, 0.2, 0.1, 1000.0, 0.2, 300.0, 0.0, 0.0}, +constexpr double Cuts[NBinsPt][NCutVars] = {{0.05, 0.2, 0.1, 1000.0, 0.2, 300.0, 0.0, 0.0}, {0.05, 0.2, 0.1, 1000.0, 0.2, 300.0, 0.0, 0.0}, {0.05, 0.3, 0.1, 1000.0, 0.2, 300.0, 0.0, 0.0}, {0.05, 0.3, 0.1, 1000.0, 0.2, 300.0, 0.0, 0.0}, @@ -461,11 +463,11 @@ constexpr double cuts[nBinsPt][nCutVars] = {{0.05, 0.2, 0.1, 1000.0, 0.2, 300.0, namespace hf_cuts_lc_to_p_k_pi { -static constexpr int nBinsPt = 10; -static constexpr int nCutVars = 7; +static constexpr int NBinsPt = 10; +static constexpr int NCutVars = 11; // default values for the pT bin edges (can be used to configure histogram axis) // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 0., 1., 2., @@ -477,19 +479,19 @@ constexpr double binsPt[nBinsPt + 1] = { 12., 24., 36.}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; - -// default values for the cuts -constexpr double cuts[nBinsPt][nCutVars] = {{0.400, 0.4, 0.4, 0.4, 0., 0.005, 0.}, /* 0 < pT < 1 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0.}, /* 1 < pT < 2 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0.}, /* 2 < pT < 3 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0.}, /* 3 < pT < 4 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0.}, /* 4 < pT < 5 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0.}, /* 5 < pT < 6 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0.}, /* 6 < pT < 8 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0.}, /* 8 < pT < 12 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0.}, /* 12 < pT < 24 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0.}}; /* 24 < pT < 36 */ +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; + +// default values for the cuts m, ptP, ptK, ptPi, chi2PCA, dL, cosp, dLXY, NdLXY, ImpParXY, mass(Kpi) +constexpr double Cuts[NBinsPt][NCutVars] = {{0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10, -1.}, /* 0 < pT < 1 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10, -1.}, /* 1 < pT < 2 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10, -1.}, /* 2 < pT < 3 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10, -1.}, /* 3 < pT < 4 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10, -1.}, /* 4 < pT < 5 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10, -1.}, /* 5 < pT < 6 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10, -1.}, /* 6 < pT < 8 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10, -1.}, /* 8 < pT < 12 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10, -1.}, /* 12 < pT < 24 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10, -1.}}; /* 24 < pT < 36 */ // row labels static const std::vector labelsPt = { @@ -505,16 +507,16 @@ static const std::vector labelsPt = { "pT bin 9"}; // column labels -static const std::vector labelsCutVar = {"m", "pT p", "pT K", "pT Pi", "Chi2PCA", "decay length", "cos pointing angle"}; +static const std::vector labelsCutVar = {"m", "pT p", "pT K", "pT Pi", "Chi2PCA", "decay length", "cos pointing angle", "decLengthXY", "normDecLXY", "impParXY", "mass (Kpi)"}; } // namespace hf_cuts_lc_to_p_k_pi namespace hf_cuts_lc_to_k0s_p { -static constexpr int nBinsPt = 8; -static constexpr int nCutVars = 8; +static constexpr int NBinsPt = 8; +static constexpr int NCutVars = 8; // default values for the pT bin edges (can be used to configure histogram axis) // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 1., 2., 3., @@ -524,11 +526,11 @@ constexpr double binsPt[nBinsPt + 1] = { 8., 12., 24.}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts // mK0s(GeV) mLambdas(GeV) mGammas(GeV) ptp ptK0sdau ptK0s d0p d0K0 -constexpr double cuts[nBinsPt][nCutVars] = {{0.008, 0.005, 0.1, 0.5, 0.3, 0.6, 0.05, 999999.}, // 1 < pt < 2 +constexpr double Cuts[NBinsPt][NCutVars] = {{0.008, 0.005, 0.1, 0.5, 0.3, 0.6, 0.05, 999999.}, // 1 < pt < 2 {0.008, 0.005, 0.1, 0.5, 0.4, 1.3, 0.05, 999999.}, // 2 < pt < 3 {0.009, 0.005, 0.1, 0.6, 0.4, 1.3, 0.05, 999999.}, // 3 < pt < 4 {0.011, 0.005, 0.1, 0.6, 0.4, 1.4, 0.05, 999999.}, // 4 < pt < 5 @@ -554,11 +556,11 @@ static const std::vector labelsCutVar = {"mK0s", "mLambda", "mGamma namespace hf_cuts_dplus_to_pi_k_pi { -static const int nBinsPt = 12; -static const int nCutVars = 8; +static constexpr int NBinsPt = 12; +static constexpr int NCutVars = 8; // default values for the pT bin edges (can be used to configure histogram axis) // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 1., 2., 3., @@ -572,11 +574,11 @@ constexpr double binsPt[nBinsPt + 1] = { 16., 24., 36.}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts // selections from pp at 5 TeV 2017 analysis https://alice-notes.web.cern.ch/node/808 -constexpr double cuts[nBinsPt][nCutVars] = {{0.2, 0.3, 0.3, 0.07, 6., 0.96, 0.985, 2.5}, /* 1 < pT < 2 */ +constexpr double Cuts[NBinsPt][NCutVars] = {{0.2, 0.3, 0.3, 0.07, 6., 0.96, 0.985, 2.5}, /* 1 < pT < 2 */ {0.2, 0.3, 0.3, 0.07, 5., 0.96, 0.985, 2.5}, /* 2 < pT < 3 */ {0.2, 0.3, 0.3, 0.10, 5., 0.96, 0.980, 2.5}, /* 3 < pT < 4 */ {0.2, 0.3, 0.3, 0.10, 5., 0.96, 0.000, 2.5}, /* 4 < pT < 5 */ @@ -610,10 +612,10 @@ static const std::vector labelsCutVar = {"deltaM", "pT Pi", "pT K", namespace hf_cuts_ds_to_k_k_pi { -static const int nBinsPt = 8; -static const int nCutVars = 11; +static constexpr int NBinsPt = 8; +static constexpr int NCutVars = 11; // momentary cuts -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 2., 3., 4., @@ -623,11 +625,11 @@ constexpr double binsPt[nBinsPt + 1] = { 12., 16., 24.}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts // selections from pp at 5 TeV 2017 analysis https://alice-notes.web.cern.ch/node/808 -constexpr double cuts[nBinsPt][nCutVars] = {{0.2, 0.3, 0.3, 0.02, 4., 0.92, 0.92, 0.014, 0.010, 0.10, 5}, /* 2 < pT < 3 */ +constexpr double Cuts[NBinsPt][NCutVars] = {{0.2, 0.3, 0.3, 0.02, 4., 0.92, 0.92, 0.014, 0.010, 0.10, 5}, /* 2 < pT < 3 */ {0.2, 0.3, 0.3, 0.02, 4., 0.92, 0.92, 0.014, 0.010, 0.10, 5}, /* 3 < pT < 4 */ {0.2, 0.3, 0.3, 0.03, 4., 0.90, 0.90, 0.012, 0.010, 0.05, 5}, /* 4 < pT < 5 */ {0.2, 0.3, 0.3, 0.03, 4., 0.90, 0.90, 0.012, 0.010, 0.05, 5}, /* 5 < pT < 6 */ @@ -651,13 +653,47 @@ static const std::vector labelsPt = { static const std::vector labelsCutVar = {"deltaM", "pT Pi", "pT K", "decay length", "normalized decay length XY", "cos pointing angle", "cos pointing angle XY", "impact parameter XY", "deltaM Phi", "cos^3 theta_PiK", "chi2PCA"}; } // namespace hf_cuts_ds_to_k_k_pi +namespace hf_cuts_omegac_to_omega_pi +{ +static constexpr int NBinsPt = 4; +static constexpr int NCutVars = 1; +// default values for the pT bin edges (can be used to configure histogram axis) +// offset by 1 from the bin numbers in cuts array +constexpr double BinsPt[NBinsPt + 1] = { + + 1.0, + 2.0, + 4.0, + 6.0, + 12.0}; + +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; + +// default values for the cuts +// pi_pT +constexpr double Cuts[NBinsPt][NCutVars] = {{0.2}, /* 1 < pt < 2 */ + {0.2}, /* 2 < pt < 4 */ + {0.6}, /* 4 < pt < 6 */ + {0.8}}; /* 6 < pt < 12 */ + +// row labels +static const std::vector labelsPt = { + "pT bin 0", + "pT bin 1", + "pT bin 2", + "pT bin 3"}; + +// column labels +static const std::vector labelsCutVar = {"pT pi from Omegac"}; +} // namespace hf_cuts_omegac_to_omega_pi + namespace hf_cuts_xic_to_p_k_pi { -static const int nBinsPt = 10; -static const int nCutVars = 11; +static constexpr int NBinsPt = 10; +static constexpr int NCutVars = 11; // default values for the pT bin edges (can be used to configure histogram axis) // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 0., 1., 2., @@ -669,10 +705,10 @@ constexpr double binsPt[nBinsPt + 1] = { 12., 24., 36.}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts m ptP ptK ptPi chi2PCA dL cosp, dLXY, NdL, ct, ImpParXY -constexpr double cuts[nBinsPt][nCutVars] = {{0.400, 0.4, 0.4, 0.4, 1e-5, 0.005, 0.8, 0.005, 4., 2., 0.}, /* 0 < pT < 1 */ +constexpr double Cuts[NBinsPt][NCutVars] = {{0.400, 0.4, 0.4, 0.4, 1e-5, 0.005, 0.8, 0.005, 4., 2., 0.}, /* 0 < pT < 1 */ {0.400, 0.4, 0.4, 0.4, 1e-5, 0.005, 0.8, 0.005, 4., 2., 0.}, /* 1 < pT < 2 */ {0.400, 0.4, 0.4, 0.4, 1e-5, 0.005, 0.8, 0.005, 4., 2., 0.}, /* 2 < pT < 3 */ {0.400, 0.4, 0.4, 0.4, 1e-5, 0.005, 0.8, 0.005, 4., 2., 0.}, /* 3 < pT < 4 */ @@ -700,13 +736,62 @@ static const std::vector labelsPt = { static const std::vector labelsCutVar = {"m", "pT p", "pT K", "pT Pi", "chi2PCA", "decay length", "cos pointing angle", "decLengthXY", "normDecLXY", "ct", "impParXY"}; } // namespace hf_cuts_xic_to_p_k_pi +namespace hf_cuts_xic_to_xi_pi_pi +{ +static constexpr int NBinsPt = 10; +static constexpr int NCutVars = 12; +// default values for the pT bin edges (can be used to configure histogram axis) +// offset by 1 from the bin numbers in cuts array +constexpr double BinsPt[NBinsPt + 1] = { + 0., + 1., + 2., + 3., + 4., + 5., + 6., + 8., + 12., + 24., + 36.}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; + +// default values for the cuts m ptXi ptPi0 ptPi1 chi2PCA dL dLXY cosp cospXY impParXY Xi Pi0 Pi1 +constexpr double Cuts[NBinsPt][NCutVars] = {{0.4, 0.4, 0.4, 0.4, 1e-5, 0.5, 0.5, 0.9, 0.9, 0.1, 0.1, 0.1}, /* 0 < pT < 1 */ + {0.4, 0.4, 0.4, 0.4, 1e-5, 0.5, 0.5, 0.9, 0.9, 0.1, 0.1, 0.1}, /* 1 < pT < 2 */ + {0.4, 0.4, 0.4, 0.4, 1e-5, 0.5, 0.5, 0.9, 0.9, 0.1, 0.1, 0.1}, /* 2 < pT < 3 */ + {0.4, 0.4, 0.4, 0.4, 1e-5, 0.5, 0.5, 0.9, 0.9, 0.1, 0.1, 0.1}, /* 3 < pT < 4 */ + {0.4, 0.4, 0.4, 0.4, 1e-5, 0.5, 0.5, 0.9, 0.9, 0.1, 0.1, 0.1}, /* 4 < pT < 5 */ + {0.4, 0.4, 0.4, 0.4, 1e-5, 0.5, 0.5, 0.9, 0.9, 0.1, 0.1, 0.1}, /* 5 < pT < 6 */ + {0.4, 0.4, 0.4, 0.4, 1e-5, 0.5, 0.5, 0.9, 0.9, 0.1, 0.1, 0.1}, /* 6 < pT < 8 */ + {0.4, 0.4, 0.4, 0.4, 1e-5, 0.5, 0.5, 0.9, 0.9, 0.1, 0.1, 0.1}, /* 8 < pT < 10 */ + {0.4, 0.4, 0.4, 0.4, 1e-5, 0.5, 0.5, 0.9, 0.9, 0.1, 0.1, 0.1}, /* 12 < pT < 24 */ + {0.4, 0.4, 0.4, 0.4, 1e-5, 0.5, 0.5, 0.9, 0.9, 0.1, 0.1, 0.1}}; /* 24 < pT < 36 */ + +// row labels +static const std::vector labelsPt = { + "pT bin 0", + "pT bin 1", + "pT bin 2", + "pT bin 3", + "pT bin 4", + "pT bin 5", + "pT bin 6", + "pT bin 7", + "pT bin 8", + "pT bin 9"}; + +// column labels +static const std::vector labelsCutVar = {"m", "pT Xi", "pT Pi0", "pT Pi1", "chi2PCA", "max decay length", "max decay length XY", "cos pointing angle", "cos pointing angle XY", "max impParXY Xi", "max impParXY Pi0", "max impParXY Pi1"}; +} // namespace hf_cuts_xic_to_xi_pi_pi + namespace hf_cuts_xicc_to_p_k_pi_pi { -static const int nBinsPt = 10; -static const int nCutVars = 14; +static constexpr int NBinsPt = 10; +static constexpr int NCutVars = 14; // default values for the pT bin edges (can be used to configure histogram axis) // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 0., 1., 2., @@ -718,10 +803,10 @@ constexpr double binsPt[nBinsPt + 1] = { 12., 24., 36.}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts -constexpr double cuts[nBinsPt][nCutVars] = {{0.400, 0.5, 0.2, 1.e-3, 10.0, 1.e-3, 10.0, 9999., 1.e-3, 0.0, 50.0, 50.0, 0.8, 0.8}, /* 0 < pT < 1 */ +constexpr double Cuts[NBinsPt][NCutVars] = {{0.400, 0.5, 0.2, 1.e-3, 10.0, 1.e-3, 10.0, 9999., 1.e-3, 0.0, 50.0, 50.0, 0.8, 0.8}, /* 0 < pT < 1 */ {0.400, 0.5, 0.2, 1.e-3, 10.0, 1.e-3, 10.0, 9999., 1.e-3, 0.0, 50.0, 50.0, 0.8, 0.8}, /* 1 < pT < 2 */ {0.400, 0.5, 0.2, 1.e-3, 10.0, 1.e-3, 10.0, 9999., 1.e-3, 0.0, 50.0, 50.0, 0.8, 0.8}, /* 2 < pT < 3 */ {0.400, 0.5, 0.2, 1.e-3, 10.0, 1.e-3, 10.0, 9999., 1.e-3, 0.0, 50.0, 50.0, 0.8, 0.8}, /* 3 < pT < 4 */ @@ -751,11 +836,11 @@ static const std::vector labelsCutVar = {"m", "pT Xic", "pT Pi", "m namespace hf_cuts_jpsi_to_e_e { -static constexpr int nBinsPt = 9; -static constexpr int nCutVars = 5; +static constexpr int NBinsPt = 9; +static constexpr int NCutVars = 5; // default values for the pT bin edges (can be used to configure histogram axis) // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 0, 0.5, 1.0, @@ -767,10 +852,10 @@ constexpr double binsPt[nBinsPt + 1] = { 10.0, 15.0, }; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts -constexpr double cuts[nBinsPt][nCutVars] = {{0.5, 0.2, 0.4, 1, 1.}, /* 0 < pT < 0.5 */ +constexpr double Cuts[NBinsPt][NCutVars] = {{0.5, 0.2, 0.4, 1, 1.}, /* 0 < pT < 0.5 */ {0.5, 0.2, 0.4, 1, 1.}, /* 0.5 < pT < 1 */ {0.5, 0.2, 0.4, 1, 1.}, /* 1 < pT < 2 */ {0.5, 0.2, 0.4, 1, 1.}, /* 2 < pT < 3 */ @@ -798,11 +883,11 @@ static const std::vector labelsCutVar = {"m", "DCA_xy", "DCA_z", "p namespace hf_cuts_b0_to_d_pi { -static constexpr int nBinsPt = 12; -static constexpr int nCutVars = 12; +static constexpr int NBinsPt = 12; +static constexpr int NCutVars = 12; // default values for the pT bin edges (can be used to configure histogram axis) // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 0, 0.5, 1.0, @@ -817,11 +902,11 @@ constexpr double binsPt[nBinsPt + 1] = { 20.0, 24.0}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts // DeltaM CPA chi2PCA d0D d0Pi pTD pTPi B0DecayLength B0DecayLengthXY IPProd DeltaMD CthetaStr -constexpr double cuts[nBinsPt][nCutVars] = {{1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.8}, /* 0 < pt < 0.5 */ +constexpr double Cuts[NBinsPt][NCutVars] = {{1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.8}, /* 0 < pt < 0.5 */ {1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.8}, /* 0.5 < pt < 1 */ {1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.8}, /* 1 < pt < 2 */ {1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.8}, /* 2 < pt < 3 */ @@ -854,25 +939,50 @@ static const std::vector labelsCutVar = {"m", "CPA", "Chi2PCA", "d0 namespace hf_cuts_bs_to_ds_pi { -static constexpr int nBinsPt = 2; -static constexpr int nCutVars = 10; +static constexpr int NBinsPt = 10; +static constexpr int NCutVars = 10; // default values for the pT bin edges (can be used to configure histogram axis) // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 0, 1.0, - 2.0}; + 2.0, + 3.0, + 4.0, + 5.0, + 8.0, + 10.0, + 12.0, + 16.0, + 24.0}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts // DeltaM CPA chi2PCA d0Ds d0Pi pTDs pTPi BsDecayLength BsDecayLengthXY IPProd -constexpr double cuts[nBinsPt][nCutVars] = {{1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0.}, /* 0 < pt < 1 */ - {1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0.}}; /* 1 < pt < 2 */ +constexpr double Cuts[NBinsPt][NCutVars] = {{1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0.}, /* 0 < pt < 1 */ + {1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0.}, /* 1 < pt < 2 */ + {1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0.}, /* 2 < pt < 3 */ + {1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0.}, /* 3 < pt < 4 */ + {1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0.}, /* 4 < pt < 5 */ + {1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0.}, /* 5 < pt < 6 */ + {1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0.}, /* 8 < pt < 10 */ + {1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0.}, /* 10 < pt < 12 */ + {1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0.}, /* 12 < pt < 16 */ + {1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0.}}; /* 16 < pt < 24 */ + // row labels static const std::vector labelsPt = { "pT bin 0", - "pT bin 1"}; + "pT bin 1", + "pT bin 2", + "pT bin 3", + "pT bin 4", + "pT bin 5", + "pT bin 6", + "pT bin 7", + "pT bin 8", + "pT bin 9"}; // column labels static const std::vector labelsCutVar = {"m", "CPA", "Chi2PCA", "d0 Ds", "d0 Pi", "pT Ds", "pT Pi", "Bs decLen", "Bs decLenXY", "Imp. Par. Product"}; @@ -880,11 +990,11 @@ static const std::vector labelsCutVar = {"m", "CPA", "Chi2PCA", "d0 namespace hf_cuts_bplus_to_d0_pi { -static constexpr int nBinsPt = 12; -static constexpr int nCutVars = 11; +static constexpr int NBinsPt = 12; +static constexpr int NCutVars = 11; // default values for the pT bin edges (can be used to configure histogram axis) // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 0, 0.5, 1.0, @@ -899,11 +1009,11 @@ constexpr double binsPt[nBinsPt + 1] = { 20.0, 24.0}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts // DeltaM CPA d0D0 d0Pi pTD0 pTPi BDecayLength BDecayLengthXY IPProd DeltaMD0 CthetaStr -constexpr double cuts[nBinsPt][nCutVars] = {{1., 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.8}, /* 0 < pt < 0.5 */ +constexpr double Cuts[NBinsPt][NCutVars] = {{1., 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.8}, /* 0 < pt < 0.5 */ {1., 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.8}, /* 0.5 < pt < 1 */ {1., 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.8}, /* 1 < pt < 2 */ {1., 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.8}, /* 2 < pt < 3 */ @@ -936,11 +1046,11 @@ static const std::vector labelsCutVar = {"m", "CPA", "d0 D0", "d0 P namespace hf_cuts_lb_to_lc_pi { -static constexpr int nBinsPt = 12; -static constexpr int nCutVars = 12; +static constexpr int NBinsPt = 12; +static constexpr int NCutVars = 12; // default values for the pT bin edges (can be used to configure histogram axis) // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 0, 0.5, 1.0, @@ -955,11 +1065,11 @@ constexpr double binsPt[nBinsPt + 1] = { 20.0, 24.0}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts // DeltaM CPA chi2PCA d0Lc d0Pi pTLc pTPi LbDecayLength LbDecayLengthXY IPProd DeltaMLc CthetaStr -constexpr double cuts[nBinsPt][nCutVars] = {{1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.8}, /* 0 < pt < 0.5 */ +constexpr double Cuts[NBinsPt][NCutVars] = {{1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.8}, /* 0 < pt < 0.5 */ {1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.8}, /* 0.5 < pt < 1 */ {1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.8}, /* 1 < pt < 2 */ {1., 0.8, 1., 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.8}, /* 2 < pt < 3 */ @@ -992,11 +1102,11 @@ static const std::vector labelsCutVar = {"m", "CPA", "Chi2PCA", "d0 namespace hf_cuts_x_to_jpsi_pi_pi { -static constexpr int nBinsPt = 9; -static constexpr int nCutVars = 7; +static constexpr int NBinsPt = 9; +static constexpr int NCutVars = 7; // default values for the pT bin edges (can be used to configure histogram axis) // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 0, 0.5, 1.0, @@ -1008,11 +1118,11 @@ constexpr double binsPt[nBinsPt + 1] = { 10.0, 15.0, }; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts // m CPA d0Jpsi d0Pi pTJpsi pTPi chi2PCA -constexpr double cuts[nBinsPt][nCutVars] = {{0.5, 0.80, 0.001, 0.001, 3.0, 0.15, 1.}, /* 0 labelsCutVar = {"m", "CPA", "d0 Jpsi", "d0 namespace hf_cuts_chic_to_jpsi_gamma { // dummy selections for chic --> TO BE IMPLEMENTED -static constexpr int nBinsPt = 9; -static constexpr int nCutVars = 7; +static constexpr int NBinsPt = 9; +static constexpr int NCutVars = 7; // default values for the pT bin edges (can be used to configure histogram axis) // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 0, 0.5, 1.0, @@ -1055,11 +1165,11 @@ constexpr double binsPt[nBinsPt + 1] = { 10.0, 15.0, }; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts // m CPA d0Jpsi d0gamma pTJpsi pTgamma chi2PCA -constexpr double cuts[nBinsPt][nCutVars] = {{3.0, -1., 0.001, 0.001, 0.5, 0.15, 1.}, /* 0 labelsCutVar = {"m", "CPA", "d0 Jpsi", "d0 namespace hf_cuts_sigmac_to_p_k_pi { -static constexpr int nBinsPt = 10; -static constexpr int nCutVars = 2; +static constexpr int NBinsPt = 10; +static constexpr int NCutVars = 2; // default values for the pT bin edges (can be used to configure histogram axis) // offset by 1 from the bin numbers in cuts array -constexpr double binsPt[nBinsPt + 1] = { +constexpr double BinsPt[NBinsPt + 1] = { 0., 1., 2., @@ -1101,10 +1211,10 @@ constexpr double binsPt[nBinsPt + 1] = { 12., 24., 36.}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // default values for the cuts -constexpr double cuts[nBinsPt][nCutVars] = {{0.03, 0.03}, /* 0 < pT < 1 */ +constexpr double Cuts[NBinsPt][NCutVars] = {{0.03, 0.03}, /* 0 < pT < 1 */ {0.03, 0.03}, /* 1 < pT < 2 */ {0.03, 0.03}, /* 2 < pT < 3 */ {0.03, 0.03}, /* 3 < pT < 4 */ diff --git a/PWGHF/D2H/Core/SelectorCutsRedDataFormat.h b/PWGHF/D2H/Core/SelectorCutsRedDataFormat.h new file mode 100644 index 00000000000..039de3834df --- /dev/null +++ b/PWGHF/D2H/Core/SelectorCutsRedDataFormat.h @@ -0,0 +1,91 @@ +// 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 SelectorCutsRedDataFormat.h +/// \brief Default pT bins and cut arrays for heavy-flavour selectors and analysis tasks +/// +/// \author Luca Aglietta , Università degli Studi di Torino + +// namespace with D selections for reduced charmed-resonances analysis + +#ifndef PWGHF_D2H_CORE_SELECTORCUTSREDDATAFORMAT_H_ +#define PWGHF_D2H_CORE_SELECTORCUTSREDDATAFORMAT_H_ + +#include // std::string +#include // std::vector + +namespace o2::analysis +{ +namespace hf_cuts_d_daughter +{ +static constexpr int NBinsPt = 7; +static constexpr int NCutVars = 6; +constexpr double BinsPt[NBinsPt + 1] = { + 1., + 2., + 4., + 6., + 8., + 12., + 24., + 1000.}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; +// default values for the cuts +constexpr double Cuts[NBinsPt][NCutVars] = {{1.84, 1.89, 1.77, 1.81, 1.92, 1.96}, /* 1 < pt < 2 */ + {1.84, 1.89, 1.77, 1.81, 1.92, 1.96}, /* 2 < pt < 4 */ + {1.84, 1.89, 1.77, 1.81, 1.92, 1.96}, /* 4 < pt < 6 */ + {1.84, 1.89, 1.77, 1.81, 1.92, 1.96}, /* 6 < pt < 8 */ + {1.84, 1.89, 1.77, 1.81, 1.92, 1.96}, /* 8 < pt < 12 */ + {1.84, 1.89, 1.77, 1.81, 1.92, 1.96}, /* 12 < pt < 24 */ + {1.84, 1.89, 1.77, 1.81, 1.92, 1.96}}; /* 24 < pt < 1000 */ +// row labels +static const std::vector labelsPt{ + "pT bin 0", + "pT bin 1", + "pT bin 2", + "pT bin 3", + "pT bin 4", + "pT bin 5", + "pT bin 6"}; +// column labels +static const std::vector labelsCutVar = {"invMassSignalLow", "invMassSignalHigh", "invMassLeftSBLow", "invMassLeftSBHigh", "invMassRightSBLow", "invMassRightSBHigh"}; +} // namespace hf_cuts_d_daughter + +// namespace with v0 selections for reduced charmed-resonances analysis +namespace hf_cuts_v0_daughter +{ +static constexpr int NBinsPt = 7; +static constexpr int NCutVars = 5; +constexpr double BinsPt[NBinsPt + 1] = { + 0., + 1., + 2., + 4., + 8., + 12., + 24., + 1000.}; +auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; +// default values for the cuts +constexpr double Cuts[NBinsPt][NCutVars] = {{0.48, 0.52, 0.99, 1., 0.9}, /* 1 < pt < 2 */ + {0.48, 0.52, 0.99, 1., 0.9}, /* 2 < pt < 4 */ + {0.48, 0.52, 0.99, 1., 0.9}, /* 4 < pt < 6 */ + {0.48, 0.52, 0.99, 1., 0.9}, /* 6 < pt < 8 */ + {0.48, 0.52, 0.99, 1., 0.9}, /* 8 < pt < 12 */ + {0.48, 0.52, 0.99, 1., 0.9}, /* 12 < pt < 24 */ + {0.48, 0.52, 0.99, 1., 0.9}}; /* 24 < pt < 1000 */ +// row labels +static const std::vector labelsPt{}; +// column labels +static const std::vector labelsCutVar = {"invMassLow", "invMassHigh", "cpaMin", "dcaMax", "radiusMin"}; +} // namespace hf_cuts_v0_daughter +} // namespace o2::analysis +#endif // PWGHF_D2H_CORE_SELECTORCUTSREDDATAFORMAT_H_ diff --git a/PWGHF/D2H/DataModel/ReducedDataModel.h b/PWGHF/D2H/DataModel/ReducedDataModel.h index f268e2e90ed..e902d1de8e3 100644 --- a/PWGHF/D2H/DataModel/ReducedDataModel.h +++ b/PWGHF/D2H/DataModel/ReducedDataModel.h @@ -11,11 +11,13 @@ /// \file ReducedDataModel.h /// \brief Header file with definition of methods and tables -// used to fold (unfold) track and primary vertex information by writing (reading) AO2Ds -/// \note +/// \note used to fold (unfold) track and primary vertex information by writing (reading) AO2Ds /// /// \author Alexandre Bigot , IPHC Strasbourg /// \author Antonio Palasciano , Università degli Studi di Bari & INFN, Bari +/// \author Fabio Catalano , CERN +/// \author Fabrizio Grosa , CERN +/// \author Luca Aglietta , Università degli Studi di Torino (UniTO) #ifndef PWGHF_D2H_DATAMODEL_REDUCEDDATAMODEL_H_ #define PWGHF_D2H_DATAMODEL_REDUCEDDATAMODEL_H_ @@ -29,6 +31,7 @@ #include "Common/DataModel/PIDResponse.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/Utils/utilsPid.h" namespace o2 { @@ -36,9 +39,15 @@ namespace aod { namespace hf_reduced_collision { -DECLARE_SOA_COLUMN(Bz, bz, float); //! Magnetic field in z-direction +DECLARE_SOA_COLUMN(Bz, bz, float); //! Magnetic field in z-direction +DECLARE_SOA_COLUMN(HfCollisionRejectionMap, hfCollisionRejectionMap, uint16_t); //! Bitmask with failed selection criteria // keep track of the number of studied events (for normalization purposes) -DECLARE_SOA_COLUMN(OriginalCollisionCount, originalCollisionCount, int); //! Size of COLLISION table processed +DECLARE_SOA_COLUMN(OriginalCollisionCount, originalCollisionCount, int); //! Size of COLLISION table processed +DECLARE_SOA_COLUMN(ZvtxSelectedCollisionCount, zvtxSelectedCollisionCount, int); //! Number of COLLISIONS with |zvtx| < zvtxMax +DECLARE_SOA_COLUMN(TriggerSelectedCollisionCount, triggerSelectedCollisionCount, int); //! Number of COLLISIONS with sel8 +DECLARE_SOA_COLUMN(ZvtxAndTriggerSelectedCollisionCount, zvtxAndTriggerSelectedCollisionCount, int); //! Number of COLLISIONS with |zvtx| < zvtxMax and sel8 +DECLARE_SOA_COLUMN(ZvtxAndTriggerAndSoftTriggerSelectedCollisionCount, zvtxAndTriggerAndSoftTriggerSelectedCollisionCount, int); //! Number of COLLISIONS with |zvtx| < zvtxMax, sel8, and selected by the software trigger +DECLARE_SOA_COLUMN(AllSelectionsCollisionCount, allSelectionsCollisionCount, int); //! Number of COLLISIONS that passed all selections } // namespace hf_reduced_collision DECLARE_SOA_TABLE(HfRedCollisions, "AOD", "HFREDCOLLISION", //! Table with collision for reduced workflow @@ -46,21 +55,54 @@ DECLARE_SOA_TABLE(HfRedCollisions, "AOD", "HFREDCOLLISION", //! Table with colli collision::PosX, collision::PosY, collision::PosZ, + collision::NumContrib, + hf_reduced_collision::HfCollisionRejectionMap, + hf_reduced_collision::Bz, o2::soa::Marker<1>); +DECLARE_SOA_TABLE(HfRedCollCents, "AOD", "HFREDCOLLCENT", //! Table with collision centrality for reduced workflow + cent::CentFT0C, + cent::CentFT0M, + evsel::NumTracksInTimeRange, + evsel::SumAmpFT0CInTimeRange); + +DECLARE_SOA_TABLE(HfRedQvectors, "AOD", "HFREDQVECTOR", //! Table with collision centrality for reduced workflow + qvec::QvecFT0CRe, + qvec::QvecFT0CIm, + qvec::SumAmplFT0C, + qvec::QvecFT0ARe, + qvec::QvecFT0AIm, + qvec::SumAmplFT0A, + qvec::QvecFT0MRe, + qvec::QvecFT0MIm, + qvec::SumAmplFT0M, + qvec::QvecTPCposRe, + qvec::QvecTPCposIm, + qvec::NTrkTPCpos, + qvec::QvecTPCnegRe, + qvec::QvecTPCnegIm, + qvec::NTrkTPCneg, + qvec::QvecTPCallRe, + qvec::QvecTPCallIm, + qvec::NTrkTPCall); + DECLARE_SOA_TABLE(HfRedCollExtras, "AOD", "HFREDCOLLEXTRA", //! Table with collision extras for reduced workflow collision::CovXX, collision::CovXY, collision::CovYY, collision::CovXZ, collision::CovYZ, - collision::CovZZ, - hf_reduced_collision::Bz); + collision::CovZZ); using HfRedCollision = HfRedCollisions::iterator; DECLARE_SOA_TABLE(HfOrigColCounts, "AOD", "HFORIGCOLCOUNT", //! Table with original number of collisions - hf_reduced_collision::OriginalCollisionCount); + hf_reduced_collision::OriginalCollisionCount, + hf_reduced_collision::ZvtxSelectedCollisionCount, + hf_reduced_collision::TriggerSelectedCollisionCount, + hf_reduced_collision::ZvtxAndTriggerSelectedCollisionCount, + hf_reduced_collision::ZvtxAndTriggerAndSoftTriggerSelectedCollisionCount, + hf_reduced_collision::AllSelectionsCollisionCount); namespace hf_track_par_cov { @@ -116,10 +158,88 @@ DECLARE_SOA_COLUMN(TrackId, trackId, int); //! Original track ind DECLARE_SOA_COLUMN(Prong0Id, prong0Id, int); //! Original track index DECLARE_SOA_COLUMN(Prong1Id, prong1Id, int); //! Original track index DECLARE_SOA_COLUMN(Prong2Id, prong2Id, int); //! Original track index -DECLARE_SOA_COLUMN(HasTPC, hasTPC, bool); //! Flag to check if track has a TPC match -DECLARE_SOA_COLUMN(HasTOF, hasTOF, bool); //! Flag to check if track has a TOF match } // namespace hf_track_index_reduced +namespace hf_track_vars_reduced +{ +// CAREFUL: the getters names shall be the same as the ones of the getTrackParCov method in Common/Core/trackUtilities.h +DECLARE_SOA_COLUMN(Px, px, float); //! x-component of momentum +DECLARE_SOA_COLUMN(Py, py, float); //! y-component of momentum +DECLARE_SOA_COLUMN(Pz, pz, float); //! z-component of momentum +DECLARE_SOA_COLUMN(Sign, sign, uint8_t); //! charge sign +DECLARE_SOA_COLUMN(HasTPC, hasTPC, bool); //! Flag to check if track has a TPC match +DECLARE_SOA_COLUMN(HasTOF, hasTOF, bool); //! Flag to check if track has a TOF match +DECLARE_SOA_COLUMN(HasTPCProng0, hasTPCProng0, bool); //! Flag to check if prong0 has a TPC match +DECLARE_SOA_COLUMN(HasTOFProng0, hasTOFProng0, bool); //! Flag to check if prong0 has a TOF match +DECLARE_SOA_COLUMN(HasTPCProng1, hasTPCProng1, bool); //! Flag to check if prong1 has a TPC match +DECLARE_SOA_COLUMN(HasTOFProng1, hasTOFProng1, bool); //! Flag to check if prong1 has a TOF match +DECLARE_SOA_COLUMN(HasTPCProng2, hasTPCProng2, bool); //! Flag to check if prong2 has a TPC match +DECLARE_SOA_COLUMN(HasTOFProng2, hasTOFProng2, bool); //! Flag to check if prong2 has a TOF match +DECLARE_SOA_COLUMN(ItsNCls, itsNCls, int); //! Number of clusters in ITS +DECLARE_SOA_COLUMN(TpcNClsCrossedRows, tpcNClsCrossedRows, int); //! Number of TPC crossed rows +DECLARE_SOA_COLUMN(TpcChi2NCl, tpcChi2NCl, float); //! TPC chi2 +DECLARE_SOA_COLUMN(ItsNClsProngMin, itsNClsProngMin, int); //! minimum value of number of ITS clusters for the decay daughter tracks +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsProngMin, tpcNClsCrossedRowsProngMin, int); //! minimum value of number of TPC crossed rows for the decay daughter tracks +DECLARE_SOA_COLUMN(TpcChi2NClProngMax, tpcChi2NClProngMax, float); //! maximum value of TPC chi2 for the decay daughter tracks +DECLARE_SOA_COLUMN(PtProngMin, ptProngMin, float); //! minimum value of transverse momentum for the decay daughter tracks +DECLARE_SOA_COLUMN(AbsEtaProngMin, absEtaProngMin, float); //! minimum value of absolute pseudorapidity for the decay daughter tracks + +// dynamic columns +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! transverse momentum + [](float px, float py) -> float { return RecoDecay::pt(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, //! azimuthal angle + [](float px, float py) -> float { return RecoDecay::phi(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, //! pseudorapidity + [](float px, float py, float pz) -> float { return RecoDecay::eta(std::array{px, py, pz}); }); +DECLARE_SOA_DYNAMIC_COLUMN(PtProng0, ptProng0, //! + [](float pxProng0, float pyProng0) -> float { return RecoDecay::pt(pxProng0, pyProng0); }); +DECLARE_SOA_DYNAMIC_COLUMN(PtProng1, ptProng1, //! + [](float pxProng1, float pyProng1) -> float { return RecoDecay::pt(pxProng1, pyProng1); }); +DECLARE_SOA_DYNAMIC_COLUMN(PtProng2, ptProng2, //! + [](float pxProng2, float pyProng2) -> float { return RecoDecay::pt(pxProng2, pyProng2); }); +DECLARE_SOA_DYNAMIC_COLUMN(EtaProng0, etaProng0, //! + [](float pxProng0, float pyProng0, float pzProng0) -> float { return RecoDecay::eta(std::array{pxProng0, pyProng0, pzProng0}); }); +DECLARE_SOA_DYNAMIC_COLUMN(EtaProng1, etaProng1, //! + [](float pxProng1, float pyProng1, float pzProng1) -> float { return RecoDecay::eta(std::array{pxProng1, pyProng1, pzProng1}); }); +DECLARE_SOA_DYNAMIC_COLUMN(EtaProng2, etaProng2, //! + [](float pxProng2, float pyProng2, float pzProng2) -> float { return RecoDecay::eta(std::array{pxProng2, pyProng2, pzProng2}); }); +} // namespace hf_track_vars_reduced + +namespace hf_track_pid_reduced +{ +DECLARE_SOA_COLUMN(TPCNSigmaPiProng0, tpcNSigmaPiProng0, float); //! NsigmaTPCPi for prong0, o2-linter: disable=name/o2-column (written to disk) +DECLARE_SOA_COLUMN(TPCNSigmaPiProng1, tpcNSigmaPiProng1, float); //! NsigmaTPCPi for prong1, o2-linter: disable=name/o2-column (written to disk) +DECLARE_SOA_COLUMN(TPCNSigmaPiProng2, tpcNSigmaPiProng2, float); //! NsigmaTPCPi for prong2, o2-linter: disable=name/o2-column (written to disk) +DECLARE_SOA_COLUMN(TPCNSigmaKaProng0, tpcNSigmaKaProng0, float); //! NsigmaTPCKa for prong0, o2-linter: disable=name/o2-column (written to disk) +DECLARE_SOA_COLUMN(TPCNSigmaKaProng1, tpcNSigmaKaProng1, float); //! NsigmaTPCKa for prong1, o2-linter: disable=name/o2-column (written to disk) +DECLARE_SOA_COLUMN(TPCNSigmaKaProng2, tpcNSigmaKaProng2, float); //! NsigmaTPCKa for prong2, o2-linter: disable=name/o2-column (written to disk) +DECLARE_SOA_COLUMN(TOFNSigmaPiProng0, tofNSigmaPiProng0, float); //! NsigmaTOFPi for prong0, o2-linter: disable=name/o2-column (written to disk) +DECLARE_SOA_COLUMN(TOFNSigmaPiProng1, tofNSigmaPiProng1, float); //! NsigmaTOFPi for prong1, o2-linter: disable=name/o2-column (written to disk) +DECLARE_SOA_COLUMN(TOFNSigmaPiProng2, tofNSigmaPiProng2, float); //! NsigmaTOFPi for prong2, o2-linter: disable=name/o2-column (written to disk) +DECLARE_SOA_COLUMN(TOFNSigmaKaProng0, tofNSigmaKaProng0, float); //! NsigmaTOFKa for prong0, o2-linter: disable=name/o2-column (written to disk) +DECLARE_SOA_COLUMN(TOFNSigmaKaProng1, tofNSigmaKaProng1, float); //! NsigmaTOFKa for prong1, o2-linter: disable=name/o2-column (written to disk) +DECLARE_SOA_COLUMN(TOFNSigmaKaProng2, tofNSigmaKaProng2, float); //! NsigmaTOFKa for prong2, o2-linter: disable=name/o2-column (written to disk) +// dynamic columns +DECLARE_SOA_DYNAMIC_COLUMN(TPCTOFNSigmaPi, tpcTofNSigmaPi, //! Combination of NsigmaTPC and NsigmaTOF, o2-linter: disable=name/o2-column (written to disk) + [](float tpcNSigmaPi, float tofNSigmaPi) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi, tofNSigmaPi); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCTOFNSigmaKa, tpcTofNSigmaKa, //! Combination of NsigmaTPC and NsigmaTOF, o2-linter: disable=name/o2-column (written to disk) + [](float tpcNSigmaPi, float tofNSigmaPi) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi, tofNSigmaPi); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCTOFNSigmaPr, tpcTofNSigmaPr, //! Combination of NsigmaTPC and NsigmaTOF, o2-linter: disable=name/o2-column (written to disk) + [](float tpcNSigmaPi, float tofNSigmaPi) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi, tofNSigmaPi); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCTOFNSigmaPiProng0, tpcTofNSigmaPiProng0, //! Combination of NsigmaTPC and NsigmaTOF, o2-linter: disable=name/o2-column (written to disk) + [](float tpcNSigmaPi, float tofNSigmaPi) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi, tofNSigmaPi); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCTOFNSigmaPiProng1, tpcTofNSigmaPiProng1, //! Combination of NsigmaTPC and NsigmaTOF, o2-linter: disable=name/o2-column (written to disk) + [](float tpcNSigmaPi, float tofNSigmaPi) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi, tofNSigmaPi); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCTOFNSigmaPiProng2, tpcTofNSigmaPiProng2, //! Combination of NsigmaTPC and NsigmaTOF, o2-linter: disable=name/o2-column (written to disk) + [](float tpcNSigmaPi, float tofNSigmaPi) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi, tofNSigmaPi); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCTOFNSigmaKaProng0, tpcTofNSigmaKaProng0, //! Combination of NsigmaTPC and NsigmaTOF, o2-linter: disable=name/o2-column (written to disk) + [](float tpcNSigmaKa, float tofNSigmaKa) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaKa, tofNSigmaKa); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCTOFNSigmaKaProng1, tpcTofNSigmaKaProng1, //! Combination of NsigmaTPC and NsigmaTOF, o2-linter: disable=name/o2-column (written to disk) + [](float tpcNSigmaKa, float tofNSigmaKa) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaKa, tofNSigmaKa); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCTOFNSigmaKaProng2, tpcTofNSigmaKaProng2, //! Combination of NsigmaTPC and NsigmaTOF, o2-linter: disable=name/o2-column (written to disk) + [](float tpcNSigmaKa, float tofNSigmaKa) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaKa, tofNSigmaKa); }); +} // namespace hf_track_pid_reduced + // CAREFUL: need to follow convention [Name = Description + 's'] in DECLARE_SOA_TABLE(Name, "AOD", Description) // to call DECLARE_SOA_INDEX_COLUMN_FULL later on DECLARE_SOA_TABLE(HfRedTrackBases, "AOD", "HFREDTRACKBASE", //! Table with track information for reduced workflow @@ -127,6 +247,9 @@ DECLARE_SOA_TABLE(HfRedTrackBases, "AOD", "HFREDTRACKBASE", //! Table with track hf_track_index_reduced::TrackId, hf_track_index_reduced::HfRedCollisionId, HFTRACKPAR_COLUMNS, + hf_track_vars_reduced::ItsNCls, + hf_track_vars_reduced::TpcNClsCrossedRows, + hf_track_vars_reduced::TpcChi2NCl, aod::track::Px, aod::track::Py, aod::track::Pz, @@ -139,10 +262,11 @@ DECLARE_SOA_TABLE(HfRedTracksCov, "AOD", "HFREDTRACKCOV", //! Table with track c // table with all attributes needed to call statusTpcAndTof() in the selector task DECLARE_SOA_TABLE(HfRedTracksPid, "AOD", "HFREDTRACKPID", //! Table with PID track information for reduced workflow o2::soa::Index<>, - hf_track_index_reduced::HasTPC, - hf_track_index_reduced::HasTOF, + hf_track_vars_reduced::HasTPC, + hf_track_vars_reduced::HasTOF, pidtpc::TPCNSigmaPi, - pidtof::TOFNSigmaPi); + pidtof::TOFNSigmaPi, + hf_track_pid_reduced::TPCTOFNSigmaPi); DECLARE_SOA_EXTENDED_TABLE_USER(HfRedTracksExt, HfRedTrackBases, "HFREDTRACKEXT", //! Track parameters at collision vertex aod::track::Pt); @@ -151,9 +275,8 @@ using HfRedTracks = HfRedTracksExt; namespace hf_charm_cand_reduced { -DECLARE_SOA_COLUMN(InvMass, invMass, float); //! Invariant mass of 2prong candidate in GeV/c2 -DECLARE_SOA_COLUMN(InvMassD0, invMassD0, float); //! Invariant mass of 2prong candidate in GeV/c2 -DECLARE_SOA_COLUMN(InvMassD0Bar, invMassD0Bar, float); //! Invariant mass of 2prong candidate in GeV/c2 +DECLARE_SOA_COLUMN(InvMassHypo0, invMassHypo0, float); //! Invariant mass of candidate in GeV/c2 (mass hypothesis 0) +DECLARE_SOA_COLUMN(InvMassHypo1, invMassHypo1, float); //! Invariant mass of candidate in GeV/c2 (mass hypothesis 1) DECLARE_SOA_COLUMN(MlScoreBkgMassHypo0, mlScoreBkgMassHypo0, float); //! ML score for background class (mass hypothesis 0) DECLARE_SOA_COLUMN(MlScorePromptMassHypo0, mlScorePromptMassHypo0, float); //! ML score for prompt class (mass hypothesis 0) DECLARE_SOA_COLUMN(MlScoreNonpromptMassHypo0, mlScoreNonpromptMassHypo0, float); //! ML score for non-prompt class (mass hypothesis 0) @@ -170,7 +293,9 @@ DECLARE_SOA_TABLE(HfRed2Prongs, "AOD", "HFRED2PRONG", //! Table with 2prong cand hf_track_index_reduced::HfRedCollisionId, HFTRACKPAR_COLUMNS, hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ZSecondaryVertex, - hf_charm_cand_reduced::InvMassD0, hf_charm_cand_reduced::InvMassD0Bar, + hf_charm_cand_reduced::InvMassHypo0, hf_charm_cand_reduced::InvMassHypo1, + hf_track_vars_reduced::PtProngMin, hf_track_vars_reduced::AbsEtaProngMin, + hf_track_vars_reduced::ItsNClsProngMin, hf_track_vars_reduced::TpcNClsCrossedRowsProngMin, hf_track_vars_reduced::TpcChi2NClProngMax, aod::track::Px, aod::track::Py, aod::track::Pz, @@ -197,7 +322,9 @@ DECLARE_SOA_TABLE(HfRed3Prongs, "AOD", "HFRED3PRONG", //! Table with 3prong cand hf_track_index_reduced::HfRedCollisionId, HFTRACKPAR_COLUMNS, hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ZSecondaryVertex, - hf_charm_cand_reduced::InvMass, + hf_charm_cand_reduced::InvMassHypo0, hf_charm_cand_reduced::InvMassHypo1, + hf_track_vars_reduced::PtProngMin, hf_track_vars_reduced::AbsEtaProngMin, + hf_track_vars_reduced::ItsNClsProngMin, hf_track_vars_reduced::TpcNClsCrossedRowsProngMin, hf_track_vars_reduced::TpcChi2NClProngMax, aod::track::Px, aod::track::Py, aod::track::Pz, @@ -208,11 +335,52 @@ DECLARE_SOA_TABLE(HfRed3ProngsCov, "AOD", "HFRED3PRONGSCOV", //! Table with 3pro HFTRACKPARCOV_COLUMNS, o2::soa::Marker<2>); -DECLARE_SOA_TABLE(HfRed3ProngsMl, "AOD", "HFRED3PRONGML", //! Table with 3prong candidate ML scores +DECLARE_SOA_TABLE(HfRed3ProngsMl_000, "AOD", "HFRED3PRONGML", //! Table with 3prong candidate ML scores hf_charm_cand_reduced::MlScoreBkgMassHypo0, hf_charm_cand_reduced::MlScorePromptMassHypo0, hf_charm_cand_reduced::MlScoreNonpromptMassHypo0); +DECLARE_SOA_TABLE_VERSIONED(HfRed3ProngsMl_001, "AOD", "HFRED3PRONGML", 1, //! Table with 3prong candidate ML scores (format for 2 mass hypotheses needed for Ds and Lc) + hf_charm_cand_reduced::MlScoreBkgMassHypo0, + hf_charm_cand_reduced::MlScorePromptMassHypo0, + hf_charm_cand_reduced::MlScoreNonpromptMassHypo0, + hf_charm_cand_reduced::MlScoreBkgMassHypo1, + hf_charm_cand_reduced::MlScorePromptMassHypo1, + hf_charm_cand_reduced::MlScoreNonpromptMassHypo1, + o2::soa::Marker<1>); + +using HfRed3ProngsMl = HfRed3ProngsMl_001; + +DECLARE_SOA_TABLE(HfRedPidDau0s, "AOD", "HFREDPIDDAU0", //! + hf_track_pid_reduced::TPCNSigmaPiProng0, + hf_track_pid_reduced::TOFNSigmaPiProng0, + hf_track_pid_reduced::TPCNSigmaKaProng0, + hf_track_pid_reduced::TOFNSigmaKaProng0, + hf_track_vars_reduced::HasTOFProng0, + hf_track_vars_reduced::HasTPCProng0, + hf_track_pid_reduced::TPCTOFNSigmaPiProng0, + hf_track_pid_reduced::TPCTOFNSigmaKaProng0); + +DECLARE_SOA_TABLE(HfRedPidDau1s, "AOD", "HFREDPIDDAU1", //! + hf_track_pid_reduced::TPCNSigmaPiProng1, + hf_track_pid_reduced::TOFNSigmaPiProng1, + hf_track_pid_reduced::TPCNSigmaKaProng1, + hf_track_pid_reduced::TOFNSigmaKaProng1, + hf_track_vars_reduced::HasTOFProng1, + hf_track_vars_reduced::HasTPCProng1, + hf_track_pid_reduced::TPCTOFNSigmaPiProng1, + hf_track_pid_reduced::TPCTOFNSigmaKaProng1); + +DECLARE_SOA_TABLE(HfRedPidDau2s, "AOD", "HFREDPIDDAU2", //! + hf_track_pid_reduced::TPCNSigmaPiProng2, + hf_track_pid_reduced::TOFNSigmaPiProng2, + hf_track_pid_reduced::TPCNSigmaKaProng2, + hf_track_pid_reduced::TOFNSigmaKaProng2, + hf_track_vars_reduced::HasTOFProng2, + hf_track_vars_reduced::HasTPCProng2, + hf_track_pid_reduced::TPCTOFNSigmaPiProng2, + hf_track_pid_reduced::TPCTOFNSigmaKaProng2); + // Beauty candidates prongs namespace hf_cand_b0_reduced { @@ -238,13 +406,42 @@ namespace hf_cand_bplus_reduced { DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfRed2Prongs, "_0"); //! Prong0 index DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, HfRedTrackBases, "_1"); //! Prong1 index +DECLARE_SOA_COLUMN(Prong0MlScoreBkg, prong0MlScoreBkg, float); //! Bkg ML score of the D daughter +DECLARE_SOA_COLUMN(Prong0MlScorePrompt, prong0MlScorePrompt, float); //! Prompt ML score of the D daughter +DECLARE_SOA_COLUMN(Prong0MlScoreNonprompt, prong0MlScoreNonprompt, float); //! Nonprompt ML score of the D daughter } // namespace hf_cand_bplus_reduced DECLARE_SOA_TABLE(HfRedBplusProngs, "AOD", "HFREDBPPRONG", hf_cand_bplus_reduced::Prong0Id, hf_cand_bplus_reduced::Prong1Id); +DECLARE_SOA_TABLE(HfRedBplusD0Mls, "AOD", "HFREDBPLUSD0ML", //! Table with ML scores for the D0 daughter + hf_cand_bplus_reduced::Prong0MlScoreBkg, + hf_cand_bplus_reduced::Prong0MlScorePrompt, + hf_cand_bplus_reduced::Prong0MlScoreNonprompt, + o2::soa::Marker<1>); + using HfRedCandBplus = soa::Join; +namespace hf_cand_bs_reduced +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfRed3Prongs, "_0"); //! Prong0 index +DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, HfRedTrackBases, "_1"); //! Prong1 index +DECLARE_SOA_COLUMN(Prong0MlScoreBkg, prong0MlScoreBkg, float); //! Bkg ML score of the D daughter +DECLARE_SOA_COLUMN(Prong0MlScorePrompt, prong0MlScorePrompt, float); //! Prompt ML score of the D daughter +DECLARE_SOA_COLUMN(Prong0MlScoreNonprompt, prong0MlScoreNonprompt, float); //! Nonprompt ML score of the D daughter +} // namespace hf_cand_bs_reduced + +DECLARE_SOA_TABLE(HfRedBsProngs, "AOD", "HFREDBSPRONG", //! Table with Bs daughter indices + hf_cand_bs_reduced::Prong0Id, hf_cand_bs_reduced::Prong1Id); + +DECLARE_SOA_TABLE(HfRedBsDsMls, "AOD", "HFREDBSDSML", //! Table with ML scores for the Ds daughter + hf_cand_bs_reduced::Prong0MlScoreBkg, + hf_cand_bs_reduced::Prong0MlScorePrompt, + hf_cand_bs_reduced::Prong0MlScoreNonprompt, + o2::soa::Marker<1>); + +using HfRedCandBs = soa::Join; + namespace hf_b0_mc { // MC Rec @@ -273,6 +470,7 @@ DECLARE_SOA_TABLE(HfMcRecRedDpPis, "AOD", "HFMCRECREDDPPI", //! Table with recon hf_cand_b0_reduced::Prong0Id, hf_cand_b0_reduced::Prong1Id, hf_cand_b0::FlagMcMatchRec, + hf_cand_b0::FlagWrongCollision, hf_cand_b0::DebugMcRec, hf_b0_mc::PtMother); @@ -290,6 +488,7 @@ DECLARE_SOA_TABLE(HfMcCheckDpPis, "AOD", "HFMCCHECKDPPI", //! Table with reconst // Table with same size as HFCANDB0 DECLARE_SOA_TABLE(HfMcRecRedB0s, "AOD", "HFMCRECREDB0", //! Reconstruction-level MC information on B0 candidates for reduced workflow hf_cand_b0::FlagMcMatchRec, + hf_cand_b0::FlagWrongCollision, hf_cand_b0::DebugMcRec, hf_b0_mc::PtMother); @@ -340,6 +539,12 @@ DECLARE_SOA_COLUMN(EtaProng0, etaProng0, float); //! Pseudorapidity of the track DECLARE_SOA_COLUMN(PtProng1, ptProng1, float); //! Transverse momentum of the track's prong1 in GeV/c DECLARE_SOA_COLUMN(YProng1, yProng1, float); //! Rapidity of the track's prong1 DECLARE_SOA_COLUMN(EtaProng1, etaProng1, float); //! Pseudorapidity of the track's prong1 + +DECLARE_SOA_COLUMN(PdgCodeBeautyMother, pdgCodeBeautyMother, int); //! Pdg code of beauty mother +DECLARE_SOA_COLUMN(PdgCodeCharmMother, pdgCodeCharmMother, int); //! Pdg code of charm mother +DECLARE_SOA_COLUMN(PdgCodeProng0, pdgCodeProng0, int); //! Pdg code of prong0 +DECLARE_SOA_COLUMN(PdgCodeProng1, pdgCodeProng1, int); //! Pdg code of prong1 +DECLARE_SOA_COLUMN(PdgCodeProng2, pdgCodeProng2, int); //! Pdg code of prong2 } // namespace hf_bplus_mc // table with results of reconstruction level MC matching @@ -347,15 +552,34 @@ DECLARE_SOA_TABLE(HfMcRecRedD0Pis, "AOD", "HFMCRECREDD0PI", //! Table with recon hf_cand_bplus_reduced::Prong0Id, hf_cand_bplus_reduced::Prong1Id, hf_cand_bplus::FlagMcMatchRec, + hf_cand_bplus::FlagWrongCollision, hf_cand_bplus::DebugMcRec, hf_bplus_mc::PtMother); +// DECLARE_SOA_EXTENDED_TABLE_USER(ExTable, Tracks, "EXTABLE", +DECLARE_SOA_TABLE(HfMcCheckD0Pis, "AOD", "HFMCCHECKD0PI", //! Table with reconstructed MC information on D0Pi(<-B0) pairs for MC checks in reduced workflow + hf_bplus_mc::PdgCodeBeautyMother, + hf_bplus_mc::PdgCodeCharmMother, + hf_bplus_mc::PdgCodeProng0, + hf_bplus_mc::PdgCodeProng1, + hf_bplus_mc::PdgCodeProng2, + o2::soa::Marker<1>); + // Table with same size as HFCANDBPLUS DECLARE_SOA_TABLE(HfMcRecRedBps, "AOD", "HFMCRECREDBP", //! Reconstruction-level MC information on B+ candidates for reduced workflow hf_cand_bplus::FlagMcMatchRec, + hf_cand_bplus::FlagWrongCollision, hf_cand_bplus::DebugMcRec, hf_bplus_mc::PtMother); +DECLARE_SOA_TABLE(HfMcCheckBps, "AOD", "HFMCCHECKBP", //! Table with reconstructed MC information on B+ candidates for MC checks in reduced workflow + hf_bplus_mc::PdgCodeBeautyMother, + hf_bplus_mc::PdgCodeCharmMother, + hf_bplus_mc::PdgCodeProng0, + hf_bplus_mc::PdgCodeProng1, + hf_bplus_mc::PdgCodeProng2, + o2::soa::Marker<2>); + DECLARE_SOA_TABLE(HfMcGenRedBps, "AOD", "HFMCGENREDBP", //! Generation-level MC information on B+ candidates for reduced workflow hf_cand_bplus::FlagMcMatchGen, hf_bplus_mc::PtTrack, @@ -382,76 +606,336 @@ DECLARE_SOA_TABLE(HfCandBpConfigs, "AOD", "HFCANDBPCONFIG", //! Table with confi hf_cand_bplus_config::MySelectionFlagD0bar, hf_cand_bplus_config::MyInvMassWindowD0Pi); +namespace hf_bs_mc +{ +// MC Rec +DECLARE_SOA_COLUMN(PtMother, ptMother, float); //! Transverse momentum of the mother in GeV/c +// MC Gen +DECLARE_SOA_COLUMN(PtTrack, ptTrack, float); //! Transverse momentum of the track in GeV/c +DECLARE_SOA_COLUMN(YTrack, yTrack, float); //! Rapidity of the track +DECLARE_SOA_COLUMN(EtaTrack, etaTrack, float); //! Pseudorapidity of the track +DECLARE_SOA_COLUMN(PtProng0, ptProng0, float); //! Transverse momentum of the track's prong0 in GeV/c +DECLARE_SOA_COLUMN(YProng0, yProng0, float); //! Rapidity of the track's prong0 +DECLARE_SOA_COLUMN(EtaProng0, etaProng0, float); //! Pseudorapidity of the track's prong0 +DECLARE_SOA_COLUMN(PtProng1, ptProng1, float); //! Transverse momentum of the track's prong1 in GeV/c +DECLARE_SOA_COLUMN(YProng1, yProng1, float); //! Rapidity of the track's prong1 +DECLARE_SOA_COLUMN(EtaProng1, etaProng1, float); //! Pseudorapidity of the track's prong1 + +DECLARE_SOA_COLUMN(PdgCodeBeautyMother, pdgCodeBeautyMother, int); //! Pdg code of beauty mother +DECLARE_SOA_COLUMN(PdgCodeCharmMother, pdgCodeCharmMother, int); //! Pdg code of charm mother +DECLARE_SOA_COLUMN(PdgCodeProng0, pdgCodeProng0, int); //! Pdg code of prong0 +DECLARE_SOA_COLUMN(PdgCodeProng1, pdgCodeProng1, int); //! Pdg code of prong1 +DECLARE_SOA_COLUMN(PdgCodeProng2, pdgCodeProng2, int); //! Pdg code of prong2 +DECLARE_SOA_COLUMN(PdgCodeProng3, pdgCodeProng3, int); //! Pdg code of prong3 +} // namespace hf_bs_mc + +// table with results of reconstruction level MC matching +DECLARE_SOA_TABLE(HfMcRecRedDsPis, "AOD", "HFMCRECREDDSPI", //! Table with reconstructed MC information on DsPi(<-Bs) pairs for reduced workflow + hf_cand_bs_reduced::Prong0Id, + hf_cand_bs_reduced::Prong1Id, + hf_cand_bs::FlagMcMatchRec, + hf_cand_bs::FlagWrongCollision, + hf_cand_bs::DebugMcRec, + hf_bs_mc::PtMother); + +// try with extended table ? +// DECLARE_SOA_EXTENDED_TABLE_USER(ExTable, Tracks, "EXTABLE", +DECLARE_SOA_TABLE(HfMcCheckDsPis, "AOD", "HFMCCHECKDSPI", //! Table with reconstructed MC information on DsPi(<-Bs) pairs for MC checks in reduced workflow + hf_bs_mc::PdgCodeBeautyMother, + hf_bs_mc::PdgCodeCharmMother, + hf_bs_mc::PdgCodeProng0, + hf_bs_mc::PdgCodeProng1, + hf_bs_mc::PdgCodeProng2, + hf_bs_mc::PdgCodeProng3, + o2::soa::Marker<1>); + +// Table with same size as HFCANDBS +DECLARE_SOA_TABLE(HfMcRecRedBss, "AOD", "HFMCRECREDBS", //! Reconstruction-level MC information on Bs candidates for reduced workflow + hf_cand_bs::FlagMcMatchRec, + hf_cand_bs::FlagWrongCollision, + hf_cand_bs::DebugMcRec, + hf_bs_mc::PtMother); + +DECLARE_SOA_TABLE(HfMcCheckBss, "AOD", "HFMCCHECKBS", //! Table with reconstructed MC information on Bs candidates for MC checks in reduced workflow + hf_bs_mc::PdgCodeBeautyMother, + hf_bs_mc::PdgCodeCharmMother, + hf_bs_mc::PdgCodeProng0, + hf_bs_mc::PdgCodeProng1, + hf_bs_mc::PdgCodeProng2, + hf_bs_mc::PdgCodeProng3, + o2::soa::Marker<2>); + +DECLARE_SOA_TABLE(HfMcGenRedBss, "AOD", "HFMCGENREDBS", //! Generation-level MC information on Bs candidates for reduced workflow + hf_cand_bs::FlagMcMatchGen, + hf_bs_mc::PtTrack, + hf_bs_mc::YTrack, + hf_bs_mc::EtaTrack, + hf_bs_mc::PtProng0, + hf_bs_mc::YProng0, + hf_bs_mc::EtaProng0, + hf_bs_mc::PtProng1, + hf_bs_mc::YProng1, + hf_bs_mc::EtaProng1); + +// store all configurables values used in the first part of the workflow +// so we can use them in the Bs part +namespace hf_cand_bs_config +{ +DECLARE_SOA_COLUMN(MySelectionFlagD, mySelectionFlagD, int8_t); //! Flag to filter selected Ds mesons +DECLARE_SOA_COLUMN(MyInvMassWindowDPi, myInvMassWindowDPi, float); //! Half-width of the Bs invariant-mass window in GeV/c2 +} // namespace hf_cand_bs_config + +DECLARE_SOA_TABLE(HfCandBsConfigs, "AOD", "HFCANDBSCONFIG", //! Table with configurables information for reduced workflow + hf_cand_bs_config::MySelectionFlagD, + hf_cand_bs_config::MyInvMassWindowDPi); + // Charm resonances analysis -namespace hf_reso_cand_reduced +namespace hf_reso_3_prong +{ +DECLARE_SOA_COLUMN(DType, dType, int8_t); //! Integer with selected D candidate type: 1 = Dplus, -1 = Dminus, 2 = DstarPlus, -2 = DstarMinus + +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! + [](float pxProng0, float pxProng1, float pxProng2) -> float { return 1.f * pxProng0 + 1.f * pxProng1 + 1.f * pxProng2; }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, //! + [](float pyProng0, float pyProng1, float pyProng2) -> float { return 1.f * pyProng0 + 1.f * pyProng1 + 1.f * pyProng2; }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! + [](float pzProng0, float pzProng1, float pzProng2) -> float { return 1.f * pzProng0 + 1.f * pzProng1 + 1.f * pzProng2; }); +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! + [](float pxProng0, float pxProng1, float pxProng2, float pyProng0, float pyProng1, float pyProng2) -> float { return RecoDecay::pt((1.f * pxProng0 + 1.f * pxProng1 + 1.f * pxProng2), (1.f * pyProng0 + 1.f * pyProng1 + 1.f * pyProng2)); }); +DECLARE_SOA_DYNAMIC_COLUMN(InvMassDplus, invMassDplus, + [](float px0, float py0, float pz0, float px1, float py1, float pz1, float px2, float py2, float pz2) -> float { return RecoDecay::m(std::array{std::array{px0, py0, pz0}, std::array{px1, py1, pz1}, std::array{px2, py2, pz2}}, std::array{constants::physics::MassPiPlus, constants::physics::MassKPlus, constants::physics::MassPiPlus}); }); +DECLARE_SOA_DYNAMIC_COLUMN(PVector, pVector, + [](float px0, float py0, float pz0, float px1, float py1, float pz1, float px2, float py2, float pz2) -> std::array { return std::array{px0 + px1 + px2, py0 + py1 + py2, pz0 + pz1 + pz2}; }); +} // namespace hf_reso_3_prong + +namespace hf_reso_v0 { -DECLARE_SOA_COLUMN(InvMass, invMass, float); //! Invariant mass in GeV/c2 -DECLARE_SOA_COLUMN(InvMassK0s, invMassK0s, float); //! Invariant mass of V0 candidate in GeV/c2, under K0s mass assumption -DECLARE_SOA_COLUMN(InvMassLambda, invMassLambda, float); //! Invariant mass of V0 candidate in GeV/c2, under Lambda mass assumption -DECLARE_SOA_COLUMN(InvMassAntiLambda, invMassAntiLambda, float); //! Invariant mass of V0 candidate in GeV/c2, under AntiLambda mass assumption -DECLARE_SOA_COLUMN(Px, px, float); //! Momentum of V0/3 prong candidate in GeV/c -DECLARE_SOA_COLUMN(Py, py, float); -DECLARE_SOA_COLUMN(Pz, pz, float); DECLARE_SOA_COLUMN(Cpa, cpa, float); //! Cosine of Pointing Angle of V0 candidate DECLARE_SOA_COLUMN(Dca, dca, float); //! DCA of V0 candidate DECLARE_SOA_COLUMN(Radius, radius, float); //! Radius of V0 candidate DECLARE_SOA_COLUMN(V0Type, v0Type, uint8_t); //! Bitmap with mass hypothesis of the V0 -DECLARE_SOA_COLUMN(DType, dType, int8_t); //! Integer with selected D candidate type: 1 = Dplus, -1 = Dminus, 2 = DstarPlus, -2 = DstarMinus -DECLARE_SOA_COLUMN(Pt, pt, float); //! Pt of Resonance candidate in GeV/c -DECLARE_SOA_COLUMN(PtProng0, ptProng0, float); //! Pt of D daughter in GeV/c -DECLARE_SOA_COLUMN(PtProng1, ptProng1, float); //! Pt of V0 daughter in GeV/c -DECLARE_SOA_COLUMN(InvMassProng0, invMassProng0, float); //! Invariant Mass of D daughter in GeV/c -DECLARE_SOA_COLUMN(InvMassProng1, invMassProng1, float); //! Invariant Mass of V0 daughter in GeV/c -DECLARE_SOA_COLUMN(MlScoreBkgProng0, mlScoreBkgProng0, float); //! Bkg ML score of the D daughter -DECLARE_SOA_COLUMN(MlScorePromptProng0, mlScorePromptProng0, float); //! Prompt ML score of the D daughter -DECLARE_SOA_COLUMN(MlScoreNonpromptProng0, mlScoreNonpromptProng0, float); //! Nonprompt ML score of the D daughter -} // namespace hf_reso_cand_reduced + +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! + [](float pxProng0, float pxProng1) -> float { return 1.f * pxProng0 + 1.f * pxProng1; }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, //! + [](float pyProng0, float pyProng1) -> float { return 1.f * pyProng0 + 1.f * pyProng1; }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! + [](float pzProng0, float pzProng1) -> float { return 1.f * pzProng0 + 1.f * pzProng1; }); +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! + [](float pxProng0, float pxProng1, float pyProng0, float pyProng1) -> float { return RecoDecay::pt((1.f * pxProng0 + 1.f * pxProng1), (1.f * pyProng0 + 1.f * pyProng1)); }); +DECLARE_SOA_DYNAMIC_COLUMN(V0Radius, v0Radius, //! V0 decay radius (2D, centered at zero) + [](float x, float y) -> float { return RecoDecay::sqrtSumOfSquares(x, y); }); +DECLARE_SOA_DYNAMIC_COLUMN(InvMassLambda, invMassLambda, //! mass under lambda hypothesis + [](float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) -> float { return RecoDecay::m(std::array{std::array{pxpos, pypos, pzpos}, std::array{pxneg, pyneg, pzneg}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); }); +DECLARE_SOA_DYNAMIC_COLUMN(InvMassAntiLambda, invMassAntiLambda, //! mass under antilambda hypothesis + [](float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) -> float { return RecoDecay::m(std::array{std::array{pxpos, pypos, pzpos}, std::array{pxneg, pyneg, pzneg}}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton}); }); +DECLARE_SOA_DYNAMIC_COLUMN(InvMassK0s, invMassK0s, //! mass under K0short hypothesis + [](float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) -> float { return RecoDecay::m(std::array{std::array{pxpos, pypos, pzpos}, std::array{pxneg, pyneg, pzneg}}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged}); }); +DECLARE_SOA_DYNAMIC_COLUMN(PVector, pVector, + [](float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) -> std::array { return std::array{pxpos + pxneg, pypos + pyneg, pzpos + pzneg}; }); +} // namespace hf_reso_v0 DECLARE_SOA_TABLE(HfRedVzeros, "AOD", "HFREDVZERO", //! Table with V0 candidate information for resonances reduced workflow o2::soa::Index<>, + // Indices hf_track_index_reduced::Prong0Id, hf_track_index_reduced::Prong1Id, hf_track_index_reduced::HfRedCollisionId, + // Static hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ZSecondaryVertex, - hf_reso_cand_reduced::InvMassK0s, hf_reso_cand_reduced::InvMassLambda, hf_reso_cand_reduced::InvMassAntiLambda, - hf_reso_cand_reduced::Px, - hf_reso_cand_reduced::Py, - hf_reso_cand_reduced::Pz, - hf_reso_cand_reduced::Cpa, - hf_reso_cand_reduced::Dca, - hf_reso_cand_reduced::Radius, - hf_reso_cand_reduced::V0Type, - mcparticle::PVector); + hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, + hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, + hf_reso_v0::Cpa, hf_reso_v0::Dca, + hf_track_vars_reduced::ItsNClsProngMin, hf_track_vars_reduced::TpcNClsCrossedRowsProngMin, hf_track_vars_reduced::TpcChi2NClProngMax, + hf_reso_v0::V0Type, + // Dynamic + hf_reso_v0::Px, + hf_reso_v0::Py, + hf_reso_v0::Pz, + hf_track_vars_reduced::PtProng0, + hf_track_vars_reduced::PtProng1, + hf_track_vars_reduced::EtaProng0, + hf_track_vars_reduced::EtaProng1, + hf_reso_v0::InvMassK0s, + hf_reso_v0::InvMassLambda, + hf_reso_v0::InvMassAntiLambda, + hf_reso_v0::V0Radius, + hf_reso_v0::Pt, + hf_cand::PVectorProng0, + hf_cand::PVectorProng1, + hf_reso_v0::PVector); + +DECLARE_SOA_TABLE(HfRedTrkNoParams, "AOD", "HFREDTRKNOPARAM", //! Table with tracks without track parameters for resonances reduced workflow + o2::soa::Index<>, + // Indices + hf_track_index_reduced::HfRedCollisionId, + // Static + hf_track_vars_reduced::Px, + hf_track_vars_reduced::Py, + hf_track_vars_reduced::Pz, + hf_track_vars_reduced::Sign, + pidtpc::TPCNSigmaPi, + pidtpc::TPCNSigmaKa, + pidtpc::TPCNSigmaPr, + pidtof::TOFNSigmaPi, + pidtof::TOFNSigmaKa, + pidtof::TOFNSigmaPr, + hf_track_vars_reduced::HasTOF, + hf_track_vars_reduced::HasTPC, + hf_track_vars_reduced::ItsNCls, + hf_track_vars_reduced::TpcNClsCrossedRows, + hf_track_vars_reduced::TpcChi2NCl, + // Dynamic + hf_track_vars_reduced::Pt, + hf_track_vars_reduced::Eta, + hf_track_vars_reduced::Phi, + hf_track_pid_reduced::TPCTOFNSigmaPi, + hf_track_pid_reduced::TPCTOFNSigmaKa, + hf_track_pid_reduced::TPCTOFNSigmaPr); DECLARE_SOA_TABLE(HfRed3PrNoTrks, "AOD", "HFRED3PRNOTRK", //! Table with 3 prong candidate information for resonances reduced workflow o2::soa::Index<>, + // Indices hf_track_index_reduced::Prong0Id, hf_track_index_reduced::Prong1Id, hf_track_index_reduced::Prong2Id, hf_track_index_reduced::HfRedCollisionId, + // Static hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ZSecondaryVertex, - hf_reso_cand_reduced::InvMass, - hf_reso_cand_reduced::Px, - hf_reso_cand_reduced::Py, - hf_reso_cand_reduced::Pz, - hf_reso_cand_reduced::DType, - mcparticle::PVector); + hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, + hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, + hf_cand::PxProng2, hf_cand::PyProng2, hf_cand::PzProng2, + hf_track_vars_reduced::ItsNClsProngMin, hf_track_vars_reduced::TpcNClsCrossedRowsProngMin, hf_track_vars_reduced::TpcChi2NClProngMax, + hf_reso_3_prong::DType, + // Dynamic + hf_reso_3_prong::Px, + hf_reso_3_prong::Py, + hf_reso_3_prong::Pz, + hf_track_vars_reduced::PtProng0, + hf_track_vars_reduced::PtProng1, + hf_track_vars_reduced::PtProng2, + hf_track_vars_reduced::EtaProng0, + hf_track_vars_reduced::EtaProng1, + hf_track_vars_reduced::EtaProng2, + hf_reso_3_prong::InvMassDplus, + hf_cand_dstar::InvMassDstar, + hf_cand_dstar::InvMassAntiDstar, + hf_cand_dstar::InvMassD0, + hf_cand_dstar::InvMassD0Bar, + hf_reso_3_prong::Pt, + hf_cand::PVectorProng0, + hf_cand::PVectorProng1, + hf_cand::PVectorProng2, + hf_reso_3_prong::PVector); + +namespace hf_reso_cand_reduced +{ +DECLARE_SOA_COLUMN(InvMass, invMass, float); //! Invariant mass in GeV/c2 +DECLARE_SOA_COLUMN(InvMassProng0, invMassProng0, float); //! Invariant Mass of D daughter in GeV/c +DECLARE_SOA_COLUMN(InvMassProng1, invMassProng1, float); //! Invariant Mass of V0 daughter in GeV/c +DECLARE_SOA_COLUMN(InvMassD0, invMassD0, float); //! Invariant Mass of potential D0 daughter + +DECLARE_SOA_COLUMN(MlScoreBkgProng0, mlScoreBkgProng0, float); //! Bkg ML score of the D daughter +DECLARE_SOA_COLUMN(MlScorePromptProng0, mlScorePromptProng0, float); //! Prompt ML score of the D daughter +DECLARE_SOA_COLUMN(MlScoreNonpromptProng0, mlScoreNonpromptProng0, float); //! Nonprompt ML score of the D daughter + +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfRed3PrNoTrks, "_0"); //! Prong0 index (D daughter) +DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, HfRedVzeros, "_1"); //! Prong1 index (V0 daughter) +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // flag for decay channel classification reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // flag for decay channel classification generator level +DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association at reconstruction level +DECLARE_SOA_COLUMN(Origin, origin, int8_t); // Flag for origin of MC particle 1=promt, 2=FD +DECLARE_SOA_COLUMN(SignD0, signD0, int8_t); // Sign of the D0 in the channels with D* -> D0 pi, needed in case of non-matched D* + +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! + [](float pxProng0, float pxProng1, float pyProng0, float pyProng1) -> float { return RecoDecay::pt((1.f * pxProng0 + 1.f * pxProng1), (1.f * pyProng0 + 1.f * pyProng1)); }); +DECLARE_SOA_DYNAMIC_COLUMN(PtProng0, ptProng0, //! + [](float pxProng0, float pyProng0) -> float { return RecoDecay::pt(pxProng0, pyProng0); }); +DECLARE_SOA_DYNAMIC_COLUMN(PtProng1, ptProng1, //! + [](float pxProng1, float pyProng1) -> float { return RecoDecay::pt(pxProng1, pyProng1); }); +DECLARE_SOA_DYNAMIC_COLUMN(CosThetaStarDs1, cosThetaStarDs1, //! costhetastar under Ds1 hypothesis + [](float px0, float py0, float pz0, float px1, float py1, float pz1, float invMass) -> float { return RecoDecay::cosThetaStar(std::array{std::array{px0, py0, pz0}, std::array{px1, py1, pz1}}, std::array{o2::constants::physics::MassDStar, o2::constants::physics::MassK0}, invMass, 1); }); +DECLARE_SOA_DYNAMIC_COLUMN(CosThetaStarDs2Star, cosThetaStarDs2Star, //! costhetastar under Ds2Star hypothesis + [](float px0, float py0, float pz0, float px1, float py1, float pz1, float invMass) -> float { return RecoDecay::cosThetaStar(std::array{std::array{px0, py0, pz0}, std::array{px1, py1, pz1}}, std::array{o2::constants::physics::MassDPlus, o2::constants::physics::MassK0}, invMass, 1); }); +DECLARE_SOA_DYNAMIC_COLUMN(CosThetaStarXiC3055, cosThetaStarXiC3055, //! costhetastar under XiC3055 hypothesis + [](float px0, float py0, float pz0, float px1, float py1, float pz1, float invMass) -> float { return RecoDecay::cosThetaStar(std::array{std::array{px0, py0, pz0}, std::array{px1, py1, pz1}}, std::array{o2::constants::physics::MassDPlus, o2::constants::physics::MassLambda0}, invMass, 1); }); +} // namespace hf_reso_cand_reduced DECLARE_SOA_TABLE(HfCandCharmReso, "AOD", "HFCANDCHARMRESO", //! Table with Resonance candidate information for resonances reduced workflow o2::soa::Index<>, - hf_track_index_reduced::HfRedCollisionId, + // Static + hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, + hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, hf_reso_cand_reduced::InvMass, - hf_reso_cand_reduced::Pt, hf_reso_cand_reduced::InvMassProng0, - hf_reso_cand_reduced::PtProng0, hf_reso_cand_reduced::InvMassProng1, - hf_reso_cand_reduced::PtProng1, - hf_reso_cand_reduced::Cpa, - hf_reso_cand_reduced::Dca, - hf_reso_cand_reduced::Radius); + hf_reso_v0::Cpa, + hf_reso_v0::Dca, + hf_reso_v0::Radius, + hf_reso_cand_reduced::InvMassD0, + // Dynamic + hf_reso_cand_reduced::Pt, + hf_reso_cand_reduced::PtProng0, + hf_reso_cand_reduced::PtProng1, + hf_reso_v0::Px, + hf_reso_v0::Py, + hf_reso_v0::Pz, + hf_cand::PVectorProng0, + hf_cand::PVectorProng1, + hf_reso_cand_reduced::CosThetaStarDs1, + hf_reso_cand_reduced::CosThetaStarDs2Star, + hf_reso_cand_reduced::CosThetaStarXiC3055); + +DECLARE_SOA_TABLE(HfResoIndices, "AOD", "HFRESOINDICES", //! Table with Indices of resonance daughters for MC matching + hf_track_index_reduced::HfRedCollisionId, + hf_reso_cand_reduced::Prong0Id, + hf_reso_cand_reduced::Prong1Id); DECLARE_SOA_TABLE(HfCharmResoMLs, "AOD", "HFCHARMRESOML", //! Table with ML scores for the D daughter hf_reso_cand_reduced::MlScoreBkgProng0, hf_reso_cand_reduced::MlScorePromptProng0, hf_reso_cand_reduced::MlScoreNonpromptProng0, o2::soa::Marker<1>); + +// Tables for MC Resonance analysis +// table with results of reconstruction level MC matching +DECLARE_SOA_TABLE(HfMcRecRedDV0s, "AOD", "HFMCRECREDDV0", //! Table with reconstructed MC information on DV0(<-Ds*) pairs for reduced workflow + hf_reso_cand_reduced::Prong0Id, + hf_reso_cand_reduced::Prong1Id, + hf_reso_cand_reduced::FlagMcMatchRec, + hf_reso_cand_reduced::DebugMcRec, + hf_reso_cand_reduced::Origin, + hf_reso_cand_reduced::SignD0, + hf_b0_mc::PtMother, + o2::soa::Marker<1>); + +DECLARE_SOA_TABLE(HfMcGenRedResos, "AOD", "HFMCGENREDRESO", //! Generation-level MC information on Ds-Resonances candidates for reduced workflow + hf_cand_b0::FlagMcMatchGen, + hf_reso_cand_reduced::Origin, + hf_b0_mc::PtTrack, + hf_b0_mc::YTrack, + hf_b0_mc::EtaTrack, + hf_b0_mc::PtProng0, + hf_b0_mc::YProng0, + hf_b0_mc::EtaProng0, + hf_b0_mc::PtProng1, + hf_b0_mc::YProng1, + hf_b0_mc::EtaProng1, + o2::soa::Marker<1>); + +DECLARE_SOA_TABLE(HfCandChaResTr, "AOD", "HFCANDCHARESTR", //! Table with Resonance candidate information for resonances plus tracks reduced workflow + // Static + hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, + hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, + hf_reso_cand_reduced::InvMass, + hf_reso_cand_reduced::InvMassProng0, + // Dynamic + hf_reso_cand_reduced::PtProng0); + +// Table with same size as HfCandCharmReso +DECLARE_SOA_TABLE(HfMcRecRedResos, "AOD", "HFMCRECREDRESO", //! Reconstruction-level MC information on Ds-Resonances candidates for reduced workflow + hf_reso_cand_reduced::FlagMcMatchRec, + hf_reso_cand_reduced::DebugMcRec, + hf_reso_cand_reduced::Origin, + hf_b0_mc::PtMother, + o2::soa::Marker<1>); } // namespace aod namespace soa diff --git a/PWGHF/D2H/Macros/HFInvMassFitter.cxx b/PWGHF/D2H/Macros/HFInvMassFitter.cxx index 9b1ac55cd31..091b5a6f943 100644 --- a/PWGHF/D2H/Macros/HFInvMassFitter.cxx +++ b/PWGHF/D2H/Macros/HFInvMassFitter.cxx @@ -591,8 +591,8 @@ void HFInvMassFitter::calculateSignificance(Double_t& significance, Double_t& er Double_t sgnErrSquare = errSignal * errSignal; Double_t bkgErrSquare = errBkg * errBkg; Double_t totalSgnBkg = signal + bkg; - significance = signal / sqrt(signal + bkg); - errSignificance = significance * sqrt((sgnErrSquare + bkgErrSquare) / (mNSigmaForSidebands * totalSgnBkg * totalSgnBkg) + (bkg / totalSgnBkg) * (sgnErrSquare / signal / signal)); + significance = signal / std::sqrt(signal + bkg); + errSignificance = significance * std::sqrt((sgnErrSquare + bkgErrSquare) / (mNSigmaForSidebands * totalSgnBkg * totalSgnBkg) + (bkg / totalSgnBkg) * (sgnErrSquare / signal / signal)); } // estimate Signnal diff --git a/PWGHF/D2H/Macros/HFInvMassFitter.h b/PWGHF/D2H/Macros/HFInvMassFitter.h index 6ac9357c5c2..410450de273 100644 --- a/PWGHF/D2H/Macros/HFInvMassFitter.h +++ b/PWGHF/D2H/Macros/HFInvMassFitter.h @@ -20,7 +20,8 @@ #ifndef PWGHF_D2H_MACROS_HFINVMASSFITTER_H_ #define PWGHF_D2H_MACROS_HFINVMASSFITTER_H_ -#include // std::string +#include // std::cout +#include // std::string #include #include @@ -121,7 +122,7 @@ class HFInvMassFitter : public TNamed { if (mean < meanLowLimit || mean > meanUpLimit) { - cout << "Invalid Gaussian mean limmit!" << endl; + std::cout << "Invalid Gaussian mean limmit!" << std::endl; } setInitialGaussianMean(mean); mMassLowLimit = meanLowLimit; @@ -132,7 +133,7 @@ class HFInvMassFitter : public TNamed { if (mean < meanLowLimit || mean > meanUpLimit) { - cout << "Invalid Gaussian mean limmit for reflection!" << endl; + std::cout << "Invalid Gaussian mean limmit for reflection!" << std::endl; } setInitialGaussianMean(mean); mMassReflLowLimit = meanLowLimit; @@ -153,7 +154,7 @@ class HFInvMassFitter : public TNamed void setFixSecondGaussianSigma(Double_t sigma) { if (mTypeOfSgnPdf != DoubleGaus) { - cout << "Fit type should be 2Gaus!" << endl; + std::cout << "Fit type should be 2Gaus!" << std::endl; } setInitialSecondGaussianSigma(sigma); mFixedSigmaDoubleGaus = kTRUE; @@ -162,7 +163,7 @@ class HFInvMassFitter : public TNamed { if (mTypeOfSgnPdf != DoubleGaus && mTypeOfSgnPdf != DoubleGausSigmaRatioPar) { - cout << "Fit type should be 2Gaus or 2GausSigmaRatio!" << endl; + std::cout << "Fit type should be 2Gaus or 2GausSigmaRatio!" << std::endl; } setInitialFracDoubleGaus(frac); mFixedFracDoubleGaus = kTRUE; @@ -170,7 +171,7 @@ class HFInvMassFitter : public TNamed void setFixRatioToGausSigma(Double_t sigmaFrac) { if (mTypeOfSgnPdf != DoubleGausSigmaRatioPar) { - cout << "Fit type should be set to k2GausSigmaRatioPar!" << endl; + std::cout << "Fit type should be set to k2GausSigmaRatioPar!" << std::endl; } setInitialRatioDoubleGausSigma(sigmaFrac); mFixedRatioDoubleGausSigma = kTRUE; diff --git a/PWGHF/D2H/Macros/ML/README.md b/PWGHF/D2H/Macros/ML/README.md new file mode 100644 index 00000000000..5b416d998d0 --- /dev/null +++ b/PWGHF/D2H/Macros/ML/README.md @@ -0,0 +1,34 @@ +# Macros for ML training in D2H +## Requirements +In order to execute the training macro in this folder, the following python libraries are needed: +- [hipe4ml](https://github.com/hipe4ml/hipe4ml) +- [hipe4ml_converter](https://github.com/hipe4ml/hipe4ml_converter) + +All configurables needed for sample preparation and ML training are respectively embedded in configuration files such as: +- `config_preparation_DplusToPiKPi.yml`; +- `config_training_DplusToPiKPi.yml`. + +## Training +### Download training samples from Hyperloop +Download the derived `AO2D.root` (produced via a treeCreator task for example) and save it in a dedicated directory (one directory per workflow). In each directory, the output of the data preparation will be stored. A posteriori, inside the training configuration file, one shall specify the path to these directories. There is then no need to specify the files names as these ones are generated automatically (according to the analysed decay channel). + +### Prepare samples + +In order to prepare the samples the following script can be used while being in O2(Physics) environment: +``` +python3 prepare_samples.py config_preparation_DplusToPiKPi.yml +``` + +Preselections can be applied at this level. This macro shall produce `.root` files containing labeled data samples for each input `AO2D` file. + + +### Perform training +In order to perform the training and produce the BDT models to be used in D2H, the following script can be used: +``` +python3 train_models.py config_training_DplusToPiKPi.yml +``` +Given the output directory set in `config_training_DplusToPiKPi.yml`, a directory is created for each pT bin (i.e. each model trained) and filled with: +- plots at data preparation level: variables distributions and correlations +- plots at training-testing level: BDT output scores, ROC curves, precision recall, features importance +- trained models in files containing `ModelHandler` prefix (in `pickle` and `onnx` formats). *The `.onnx` can be used for ML inference in O2Physics selection task.* +- model applied to test set in file containing `ModelApplied` suffix diff --git a/PWGHF/D2H/Macros/ML/config_preparation_DplusToPiKPi.yml b/PWGHF/D2H/Macros/ML/config_preparation_DplusToPiKPi.yml new file mode 100644 index 00000000000..b2abfd72e32 --- /dev/null +++ b/PWGHF/D2H/Macros/ML/config_preparation_DplusToPiKPi.yml @@ -0,0 +1,31 @@ +--- +channel: DplusToPiKPi +labels: # class labels, keep the right number of classes + [ + Bkg, # check that the background class position in this list matches ID_BKG value in the script + Prompt, + Nonprompt + ] +col_tag: &col_tag fOriginMcRec # name of the column containing the candidate label tag + +prepare_samples: + input: + files: # list of input .root files + [ + /home/abigot/HFStudies/ML/training_samples/HF_LHC22b1a_2P3PDstar_run_136451/AO2D_merged.root + ] + tree_name: O2hfcanddplite + +preselections: null # null or list of selections (e.g. [fCpa > 0.95, fPt > 2]) linked by "&&" logic in the script +cols_to_remove: # list of columns to remove in the output, default entry is MC origin flag + [ + *col_tag + ] +filt_bkg_mass: "fM < 1.82 || (1.92 < fM && fM < 2.00)" # invariant mass sidebands for Bkg labeling + +output: + dirs: # list of paths of output directories (without trailing slash) + [ + . + ] + tree_name: treeMLDplus # tree name in the output files diff --git a/PWGHF/D2H/Macros/ML/config_training_DplusToPiKPi.yml b/PWGHF/D2H/Macros/ML/config_training_DplusToPiKPi.yml new file mode 100644 index 00000000000..0cc7d55f23d --- /dev/null +++ b/PWGHF/D2H/Macros/ML/config_training_DplusToPiKPi.yml @@ -0,0 +1,88 @@ +--- +channel: DplusToPiKPi +seed_split: 42 # seed used for df_bkg sampling and train_test_split(...) +labels: [Bkg, Prompt, Nonprompt] # class labels, keep the right number of classes + +data_prep: + indirs: # directories containing outputs of prepare_samples.py (.root labeled files) + Prompt: + [ + dirPath/ + ] + Nonprompt: # set to null to deactivate this class + [ + dirPath/ + ] + Bkg: + [ + dirPath/ + ] + + tree_name: treeMLDplus # null if .parquet input files, not null if .root input files + + pt_bins_limits: [1, 24] + name_pt_var: fPt # name of pT branch in original TTree + downsample_bkg_factor: 1 # value of downSampleBkgFactor set at TTree creation level + + class_balance: + share: equal # change how the dataset is built, options available: 'equal', 'all_signal' + # 'equal' -> same number of prompt/nonprompt/bkg (not using all the signal available) + # 'all_signal' -> try to use all the signal (prompt and nonprompt) + add n_bkg = bkg_factor * (n_prompt + n_nonprompt) + bkg_factor: [1.] # list of multipliers for (n_prompt + n_nonprompt) used to determine n_cand_bkg in the 'all_signal' option + test_fraction: 0.3 + +ml: + raw_output: false + roc_auc_approach: ovo + roc_auc_average: macro + training_vars: + [ + fPtProng0, + fImpactParameter0, + fPtProng1, + fImpactParameter1, + fPtProng2, + fImpactParameter2, + fDecayLength, + fCpa, + fCpaXY, + fNSigTpcTofPi0, + fNSigTpcTofKa0, + fNSigTpcTofPi1, + fNSigTpcTofKa1, + fNSigTpcTofPi2, + fNSigTpcTofKa2, + ] + hyper_pars: [ + { + "max_depth": 3, + "learning_rate": 0.045, + "n_estimators": 800, + "min_child_weight": 4, + "n_jobs": 4, + "tree_method": hist, + }] + hyper_pars_opt: + activate: false + ntrials: 25 + njobs: 4 + timeout: 1800 + hyper_par_ranges: + { + "max_depth": !!python/tuple [2, 3], + "learning_rate": !!python/tuple [0.03, 0.06], + "n_estimators": !!python/tuple [400, 2000], + "min_child_weight": !!python/tuple [4, 4], + "subsample": !!python/tuple [1, 1], + "colsample_bytree": !!python/tuple [1, 1] + } + +output: + dir: trainings/Dplus + log_file: log.txt # name of log file for each model training + # list of variables saved in the dataframes with the applied models + column_to_save_list: ["fPt", "fM"] + +plots: + extra_columns: ["fPt", "fM"] # list of variables to plot (on top of the training ones) + extension: ["pdf", "png"] # extension of files containing saved plots diff --git a/PWGHF/D2H/Macros/ML/prepare_samples.py b/PWGHF/D2H/Macros/ML/prepare_samples.py new file mode 100644 index 00000000000..e30d03d941a --- /dev/null +++ b/PWGHF/D2H/Macros/ML/prepare_samples.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python3 + +# 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: prepare_samples.py +brief: script to prepare data samples for ML training +usage: python3 prepare_samples.py CONFIG +author: Alexandre Bigot , Strasbourg University +""" + +import argparse +import os +import sys + +import yaml # pylint: disable=import-error + +# pylint: disable=import-error,no-name-in-module +from ROOT import EnableImplicitMT, RDataFrame, TChain, TFile + +ID_BKG = 0 # index of background class in labeling configuration + + +def get_path_input_trees(name_input_files, name_tree): + """ + Helper method to get the path of the input TTrees + + Parameters + ----------------- + - name_input_files: list with input file names + - name_tree: the (common) name of the TTree + + Returns + ----------------- + - path_input_trees: path of input trees + """ + + name_df = "DF" + delimiter = ";" + path_input_trees = [] + for name_file in name_input_files: + myfile = TFile.Open(name_file, "READ") + name_dirs = [] + keys = myfile.GetListOfKeys() + for key in keys: + # fill list only if DF in the dir name (no parent files dir) + name = key.GetName() + if name_df in name: + name_dirs.append(name) + myfile.Close() + + if len(name_dirs) > 2: + print( + "\033[91mERROR: too many DFs in !" + "Run o2-aod-merger with --max-size to get only one DF.\033[0m" + ) + sys.exit() + if len(name_dirs) == 2: + # check if the two DFs are are the same (o2-aod-merger artefact) + name0 = name_dirs[0].split(delimiter)[0] + name1 = name_dirs[1].split(delimiter)[0] + if name0 != name1: + print( + "\033[91mERROR: too many DFs in !" + "Run o2-aod-merger with --max-size to get only one DF.\033[0m" + ) + sys.exit() + + path_input_trees.append(name_file + "/" + name_dirs[0] + "/" + name_tree) + + return path_input_trees + + +# pylint: disable=too-many-locals +def main(cfg): + """ + Main function + + Parameters + ----------------- + - config: dictionary with config read from a yaml file + """ + + channel = cfg["channel"] + labels = cfg["labels"] + col_tag = cfg["col_tag"] + + # input configurables + name_in_files = cfg["prepare_samples"]["input"]["files"] + name_in_tree = cfg["prepare_samples"]["input"]["tree_name"] + + # output configurables + inv_mass_sidebands = cfg["filt_bkg_mass"] + preselections = cfg["preselections"] + cols_to_remove = cfg["cols_to_remove"] + name_out_dirs = cfg["output"]["dirs"] + name_out_tree = cfg["output"]["tree_name"] + + # configure access to the input TTrees + path_input_trees = get_path_input_trees(name_in_files, name_in_tree) + + # define preselections, if enabled + presels = "" + if preselections is not None: + for i, presel in enumerate(preselections): + presels += presel + if i < len(preselections) - 1: + presels += " && " + + # extract dataframes from input + counter_outdir = 0 + for path_input_tree in path_input_trees: + print("\033[32mExtracting dataframes from input " f"{name_in_files[counter_outdir]}\033[0m") + chain = TChain() + chain.Add(path_input_tree) + + # define dataframe from the input TTrees + EnableImplicitMT(8) # tell ROOT to go parallel + df = RDataFrame(chain) + + cols_to_keep = list(df.GetColumnNames()) + for col in cols_to_remove: + cols_to_keep.remove(col) + + # apply preselections, if enabled + if preselections is not None: + df = df.Filter(presels) + + # divide dataframe into classes and save them in flagged .root files + for idx, _ in enumerate(labels): + name_out_file = f"{name_out_dirs[counter_outdir]}/{labels[idx]}_{channel}.root" + if os.path.isfile(name_out_file): + print(f"\033[93mWARNING: Output file {name_out_file} already exists, overwrite ongoing!\033[0m") + if idx == ID_BKG: + df.Filter(f"{col_tag} == {idx}").Filter(inv_mass_sidebands).Snapshot( + name_out_tree, name_out_file, cols_to_keep + ) + else: + df.Filter(f"{col_tag} == {idx}").Snapshot(name_out_tree, name_out_file, cols_to_keep) + + counter_outdir += 1 + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Arguments") + parser.add_argument("config", metavar="text", default="config.yml", help="config file name for ml") + args = parser.parse_args() + + print("Loading configuration: ...", end="\r") + with open(args.config, "r", encoding="utf-8") as yml_cfg: + configuration = yaml.load(yml_cfg, yaml.FullLoader) + print("Loading configuration: Done!") + + main(configuration) diff --git a/PWGHF/D2H/Macros/ML/train_models.py b/PWGHF/D2H/Macros/ML/train_models.py new file mode 100644 index 00000000000..dfdb3840eb4 --- /dev/null +++ b/PWGHF/D2H/Macros/ML/train_models.py @@ -0,0 +1,551 @@ +#!/usr/bin/env python3 + +# 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: train_models.py +brief: script for the training of ML models to be used in D2H +note: inspired by EventFiltering/PWGHF/Macros/train_hf_triggers.py and Run2 macros +usage: python3 train_models.py CONFIG +author: Alexandre Bigot , Strasbourg University +author: Mingyu Zhang , Central China Normal University +""" + +import argparse +import os +import pickle +import sys + +# pylint: disable=import-error +try: + from hipe4ml import plot_utils + from hipe4ml.model_handler import ModelHandler + from hipe4ml.tree_handler import TreeHandler +except ModuleNotFoundError: + print("Module 'hipe4ml' is not installed. Please install it to run this macro") + +import matplotlib.pyplot as plt # pylint: disable=import-error +import numpy as np # pylint: disable=import-error +import pandas as pd # pylint: disable=import-error +import xgboost as xgb # pylint: disable=import-error +import yaml # pylint: disable=import-error +from sklearn.model_selection import train_test_split # pylint: disable=import-error + +try: + from hipe4ml_converter.h4ml_converter import H4MLConverter +except ModuleNotFoundError: + print("Module 'hipe4ml_converter' is not installed. Please install it to run this macro") + +LABEL_BKG = 0 +LABEL_PROMPT = 1 +LABEL_NONPROMPT = 2 + +MAX_BKG_FRAC = 0.4 # max of bkg fraction to keep for training + + +def enforce_list(x): + """ + Helper method to enforce list type + + Parameters + ----------------- + - x: a string or a list of string + + Returns + ----------------- + - x_list if x was not a list (and not None), x itself otherwise + """ + + if not isinstance(x, list): + # handle possible spaces in config file entry + x = x.split(",") + for i, element in enumerate(x): + x[i] = element.strip() + + return x + + +# pylint: disable= too-many-instance-attributes, too-few-public-methods +class MlTrainer: + """ + Class for ML training and testing + """ + + def __init__(self, config): + """ + Init method + + Parameters + ----------------- + - config: dictionary with config read from a yaml file + """ + + # input + self.channel = config["channel"] + self.seed_split = config["seed_split"] + self.labels = enforce_list(config["labels"]) + pt_bins_limits = enforce_list(config["data_prep"]["pt_bins_limits"]) + self.pt_bins = [[a, b] for a, b in zip(pt_bins_limits[:-1], pt_bins_limits[1:])] + + self.indirs = config["data_prep"]["indirs"] + self.tree_name = config["data_prep"]["tree_name"] + self.infile_extension = "parquet.gzip" if self.tree_name is None else "root" + self.binary = self.indirs["Nonprompt"] is None + self.file_lists = {} + + # (hyper)parameters + self.share = config["data_prep"]["class_balance"]["share"] + self.bkg_factor = config["data_prep"]["class_balance"]["bkg_factor"] + self.downsample_bkg_factor = config["data_prep"]["downsample_bkg_factor"] + self.training_vars = enforce_list(config["ml"]["training_vars"]) + self.test_frac = config["data_prep"]["test_fraction"] + self.vars_to_draw = config["plots"]["extra_columns"] + self.training_vars + self.name_pt_var = config["data_prep"]["name_pt_var"] + + self.raw_output = config["ml"]["raw_output"] + self.roc_auc_approach = config["ml"]["roc_auc_approach"] + self.roc_auc_average = config["ml"]["roc_auc_average"] + self.score_metric = "roc_auc" + self.hyper_pars = config["ml"]["hyper_pars"] + self.hyper_pars_opt = config["ml"]["hyper_pars_opt"] + + # output + self.outdir = config["output"]["dir"] + self.extension = config["plots"]["extension"] + self.column_to_save_list = config["output"]["column_to_save_list"] + self.log_file = config["output"]["log_file"] + + def __check_input_consistency(self): + """ + Helper method to check self consistency of inputs + """ + + # class balance + if self.share not in ("equal", "all_signal"): + print(f"\033[91mERROR: class_balance option {self.share} not implemented\033[0m") + sys.exit() + if self.share == "all_signal" and len(self.bkg_factor) != len(self.pt_bins): + print("\033[91mERROR: bkg_factor must be defined for each pT bin!\033[0m") + sys.exit() + # training + if self.training_vars is None: + print("\033[91mERROR: training columns must be defined!\033[0m") + sys.exit() + # hyper-parameters options + if not isinstance(self.hyper_pars, list): + print("\033[91mERROR: hyper-parameters must be defined or be a list containing an empty dict!\033[0m") + sys.exit() + if not isinstance(self.hyper_pars[0], dict): + print("\033[91mERROR: hyper-parameters must be a list of dict!\033[0m") + sys.exit() + if len(self.hyper_pars) != len(self.pt_bins): + print("\033[91mERROR: hyper-parameters definition does not match pT binning!\033[0m") + sys.exit() + if not isinstance(self.hyper_pars_opt["hyper_par_ranges"], dict): + print("\033[91mERROR: hyper_pars_opt_config must be defined!\033[0m") + sys.exit() + if not self.binary: + if not (self.roc_auc_average in ["macro", "weighted"] and self.roc_auc_approach in ["ovo", "ovr"]): + print("\033[91mERROR: selected ROC configuration is not valid!\033[0m") + sys.exit() + + if self.roc_auc_average == "weighted": + self.score_metric += f"_{self.roc_auc_approach}_{self.roc_auc_average}" + else: + self.score_metric += f"_{self.roc_auc_approach}" + + def __fill_list_input_files(self): + """ + Helper method to fill a dictionary with lists of input files for each class + """ + + file_lists = {} + for cand_type in self.indirs: + file_lists[cand_type] = [] + if self.indirs[cand_type] is None: + continue + for indir in self.indirs[cand_type]: + file = os.path.join(indir, f"{cand_type}_{self.channel}.{self.infile_extension}") + if os.path.isfile(file): + file_lists[cand_type].append(file) + else: + print( + "\033[91mERROR: missing file, did you prepare the samples?\n" + "If not, do python3 prepare_samples.py CONFIG\033[0m" + ) + sys.exit() + + self.file_lists = file_lists + + def __get_sliced_dfs(self): + """ + Helper method to get pT-sliced dataframes for each class + + Returns + ----------------- + - hdl_bkg: pandas dataframe containing only background candidates + - hdl_prompt: pandas dataframe containing only prompt signal + - hdl_nonprompt: pandas dataframe containing only non-prompt signal + """ + + print("Loading and preparing data files: ...", end="\r") + + self.__fill_list_input_files() + + hdl_bkg = TreeHandler(file_name=self.file_lists[self.labels[0]], tree_name=self.tree_name) + hdl_prompt = TreeHandler(file_name=self.file_lists[self.labels[1]], tree_name=self.tree_name) + hdl_nonprompt = ( + None if self.binary else TreeHandler(file_name=self.file_lists[self.labels[2]], tree_name=self.tree_name) + ) + + hdl_prompt.slice_data_frame(self.name_pt_var, self.pt_bins, True) + if hdl_nonprompt is not None: + hdl_nonprompt.slice_data_frame(self.name_pt_var, self.pt_bins, True) + hdl_bkg.slice_data_frame(self.name_pt_var, self.pt_bins, True) + + print("Loading and preparing data files: Done!") + return hdl_bkg, hdl_prompt, hdl_nonprompt + + # pylint: disable=too-many-statements, too-many-branches, too-many-arguments, too-many-locals + def __data_prep(self, df_bkg, df_prompt, df_nonprompt, pt_bin, out_dir, bkg_factor): + """ + Helper method for pt-dependent data preparation + + Parameters + ----------------- + - df_bkg: pandas dataframe containing only background candidates + - df_prompt: pandas dataframe containing only prompt signal + - df_nonprompt: pandas dataframe containing only non-prompt signal + - pt_bin: pT bin + - out_dir: output directory + - bkg_factor: multiplier for (n_prompt + n_nonprompt) used to determine n_cand_bkg in the 'all_signal' option + + Returns + ----------------- + - train_test_data: list containing train/test sets and the associated model predictions + """ + + n_prompt = len(df_prompt) + n_nonprompt = len(df_nonprompt) + n_bkg = len(df_bkg) + if self.binary: + log_available_cands = ( + f"\nNumber of available candidates " + f"in {pt_bin[0]} < pT < {pt_bin[1]} GeV/c: \n " + f"Signal: {n_prompt}\n Bkg: {n_bkg}" + ) + else: + log_available_cands = ( + f"\nNumber of available candidates " + f"in {pt_bin[0]} < pT < {pt_bin[1]} GeV/c: \n " + f"Prompt: {n_prompt}\n Nonprompt: {n_nonprompt}\n Bkg: {n_bkg}" + ) + print(log_available_cands) + + if self.share == "equal": + if self.binary: + n_cand_min = min([n_prompt, n_bkg]) + bkg_fraction = n_cand_min / n_bkg + n_bkg = n_prompt = n_cand_min + else: + n_cand_min = min([n_prompt, n_nonprompt, n_bkg]) + bkg_fraction = n_cand_min / n_bkg + n_bkg = n_prompt = n_nonprompt = n_cand_min + log_share = ( + "\nKeep the same number of candidates for each class, " + "chosen as the minimal number of candidates among all classes." + ) + + elif self.share == "all_signal": + n_cand_bkg = int(min([n_bkg, (n_prompt + n_nonprompt) * bkg_factor])) + if self.binary: + log_share = ( + f"\nKeep all signal and use {n_cand_bkg} bkg candidates " + f"for training and testing ({1 - self.test_frac}-{self.test_frac})" + ) + else: + log_share = ( + f"\nKeep all prompt and nonprompt and use {n_cand_bkg} " + "bkg candidates for training and testing " + f"({1 - self.test_frac}-{self.test_frac})" + ) + bkg_fraction = n_cand_bkg / n_bkg + n_bkg = n_cand_bkg + + else: + print(f"\033[91mERROR: class_balance option {self.share} not implemented\033[0m") + sys.exit() + + print(log_share) + + log_bkg_fraction = ( + "\nFraction of original (i.e. from original dataset) bkg candidates used for ML: " + f"{100*bkg_fraction*self.downsample_bkg_factor:.2f}%" + ) + if (1 - self.test_frac) * bkg_fraction * self.downsample_bkg_factor > MAX_BKG_FRAC: + log_bkg_fraction += ( + f"\n\033[93m\nWARNING: using more than {100*MAX_BKG_FRAC:.0f}% " + "of original (i.e. from original dataset) bkg available for training!\033[0m" + ) + print(log_bkg_fraction) + + if self.binary: + log_training_cands = ( + "\nNumber of candidates used for training and testing: \n " f"Signal: {n_prompt}\n Bkg: {n_bkg}\n" + ) + else: + log_training_cands = ( + "\nNumber of candidates used for training and testing: \n " + f"Prompt: {n_prompt}\n Nonprompt: {n_nonprompt}\n Bkg: {n_bkg}\n" + ) + + print(log_training_cands) + + # write logs in log file + with open(os.path.join(out_dir, self.log_file), "w", encoding="utf-8") as file: + file.write(log_available_cands) + file.write(log_share) + file.write(log_bkg_fraction) + file.write(log_training_cands) + + df_tot = pd.concat([df_bkg[:n_bkg], df_prompt[:n_prompt], df_nonprompt[:n_nonprompt]], sort=True) + + labels_array = np.array([LABEL_BKG] * n_bkg + [LABEL_PROMPT] * n_prompt + [LABEL_NONPROMPT] * n_nonprompt) + if 0 < self.test_frac < 1: + train_set, test_set, y_train, y_test = train_test_split( + df_tot, labels_array, test_size=self.test_frac, random_state=self.seed_split + ) + else: + print("ERROR: test_fraction must belong to ]0,1[") + sys.exit(0) + + train_test_data = [train_set, y_train, test_set, y_test] + del df_tot # release memory + + # safety + if len(np.unique(train_test_data[3])) != len(self.labels): + print( + "\033[91mERROR: The number of labels defined does not match" + "the number of classes! \nCheck the CONFIG file\033[0m" + ) + sys.exit() + + # plots + df_list = [df_bkg, df_prompt] if self.binary else [df_bkg, df_prompt, df_nonprompt] + + # _____________________________________________ + plot_utils.plot_distr( + df_list, self.vars_to_draw, 100, self.labels, figsize=(12, 7), alpha=0.3, log=True, grid=False, density=True + ) + plt.subplots_adjust(left=0.06, bottom=0.06, right=0.99, top=0.96, hspace=0.55, wspace=0.55) + for ext in self.extension: + plt.savefig(f"{out_dir}/DistributionsAll_pT_{pt_bin[0]}_{pt_bin[1]}.{ext}") + plt.close("all") + # _____________________________________________ + corr_matrix_fig = plot_utils.plot_corr(df_list, self.vars_to_draw, self.labels) + for fig, lab in zip(corr_matrix_fig, self.labels): + plt.figure(fig.number) + plt.subplots_adjust(left=0.2, bottom=0.25, right=0.95, top=0.9) + for ext in self.extension: + fig.savefig(f"{out_dir}/CorrMatrix{lab}_pT_{pt_bin[0]}_{pt_bin[1]}.{ext}") + + return train_test_data + + # pylint: disable=too-many-statements, too-many-branches + def __train_test(self, train_test_data, hyper_pars, pt_bin, out_dir): + """ + Helper method for model training and testing + + Parameters + ----------------- + - train_test_data: list containing train/test sets and the associated model predictions + - hyper_pars: default hyper-parameters (can be modified if Optuna enabled) + - pt_bin: pT bin + - out_dir: output directory + """ + + n_classes = len(np.unique(train_test_data[3])) + model_clf = xgb.XGBClassifier(use_label_encoder=False) + model_hdl = ModelHandler(model_clf, self.training_vars, hyper_pars) + + # hyperparams optimization + if self.hyper_pars_opt["activate"]: + print("Performing optuna hyper-parameters optimisation: ...", end="\r") + + with open(os.path.join(out_dir, self.log_file), "a", encoding="utf-8") as file: + file.write("\nOptuna hyper-parameters optimisation:") + sys.stdout = file + model_hdl.optimize_params_optuna( + train_test_data, + self.hyper_pars_opt["hyper_par_ranges"], + cross_val_scoring=self.score_metric, + timeout=self.hyper_pars_opt["timeout"], + n_jobs=self.hyper_pars_opt["njobs"], + n_trials=self.hyper_pars_opt["ntrials"], + direction="maximize", + ) + sys.stdout = sys.__stdout__ + print("Performing optuna hyper-parameters optimisation: Done!") + print(f"Optuna hyper-parameters:\n{model_hdl.get_model_params()}") + else: + model_hdl.set_model_params(hyper_pars) + + # store final hyperparameters in info file + with open(os.path.join(out_dir, self.log_file), "a", encoding="utf-8") as file: + file.write(f"\nModel hyperparameters:\n {model_hdl.get_model_params()}") + + # train and test the model with the updated hyper-parameters + y_pred_test = model_hdl.train_test_model( + train_test_data, + True, + output_margin=self.raw_output, + average=self.roc_auc_average, + multi_class_opt=self.roc_auc_approach, + ) + + y_pred_train = model_hdl.predict(train_test_data[0], self.raw_output) + + # Save applied model to test set + test_set_df = train_test_data[2] + test_set_df = test_set_df.loc[:, self.column_to_save_list] + test_set_df["Labels"] = train_test_data[3] + + for pred, lab in enumerate(self.labels): + if self.binary: + test_set_df["ML_output"] = y_pred_test + else: + test_set_df[f"ML_output_{lab}"] = y_pred_test[:, pred] + + test_set_df.to_parquet(f"{out_dir}/{self.channel}_ModelApplied" f"_pT_{pt_bin[0]}_{pt_bin[1]}.parquet.gzip") + + # save model + if os.path.isfile(f"{out_dir}/ModelHandler_{self.channel}.pickle"): + os.remove(f"{out_dir}/ModelHandler_{self.channel}.pickle") + if os.path.isfile(f"{out_dir}/ModelHandler_onnx_{self.channel}.onnx"): + os.remove(f"{out_dir}/ModelHandler_onnx_{self.channel}.onnx") + + model_hdl.dump_model_handler(f"{out_dir}/ModelHandler_{self.channel}" f"_pT_{pt_bin[0]}_{pt_bin[1]}.pickle") + model_conv = H4MLConverter(model_hdl) + model_conv.convert_model_onnx(1) + model_conv.dump_model_onnx(f"{out_dir}/ModelHandler_onnx_{self.channel}" f"_pT_{pt_bin[0]}_{pt_bin[1]}.onnx") + + # plots + # _____________________________________________ + plt.rcParams["figure.figsize"] = (10, 7) + fig_ml_output = plot_utils.plot_output_train_test( + model_hdl, train_test_data, 80, self.raw_output, self.labels, True, density=True + ) + if n_classes > 2: + for fig, lab in zip(fig_ml_output, self.labels): + for ext in self.extension: + fig.savefig(f"{out_dir}/MLOutputDistr{lab}_pT_{pt_bin[0]}_{pt_bin[1]}.{ext}") + else: + for ext in self.extension: + fig_ml_output.savefig(f"{out_dir}/MLOutputDistr_pT_{pt_bin[0]}_{pt_bin[1]}.{ext}") + # _____________________________________________ + plt.rcParams["figure.figsize"] = (10, 9) + fig_roc_curve = plot_utils.plot_roc( + train_test_data[3], y_pred_test, None, self.labels, self.roc_auc_average, self.roc_auc_approach + ) + for ext in self.extension: + fig_roc_curve.savefig(f"{out_dir}/ROCCurveAll_pT_{pt_bin[0]}_{pt_bin[1]}.{ext}") + pickle.dump(fig_roc_curve, open(f"{out_dir}/ROCCurveAll_pT_{pt_bin[0]}_{pt_bin[1]}.pkl", "wb")) + # _____________________________________________ + plt.rcParams["figure.figsize"] = (10, 9) + fig_roc_curve_tt = plot_utils.plot_roc_train_test( + train_test_data[3], + y_pred_test, + train_test_data[1], + y_pred_train, + None, + self.labels, + self.roc_auc_average, + self.roc_auc_approach, + ) + + fig_roc_curve_tt.savefig(f"{out_dir}/ROCCurveTrainTest_pT_{pt_bin[0]}_{pt_bin[1]}.pdf") + # _____________________________________________ + precision_recall_fig = plot_utils.plot_precision_recall(train_test_data[3], y_pred_test, self.labels) + precision_recall_fig.savefig(f"{out_dir}/PrecisionRecallAll_pT_{pt_bin[0]}_{pt_bin[1]}.pdf") + # _____________________________________________ + plt.rcParams["figure.figsize"] = (12, 7) + fig_feat_importance = plot_utils.plot_feature_imp( + train_test_data[2][train_test_data[0].columns], train_test_data[3], model_hdl, self.labels + ) + n_plot = n_classes if n_classes > 2 else 1 + for i_fig, fig in enumerate(fig_feat_importance): + if i_fig < n_plot: + lab = self.labels[i_fig] if n_classes > 2 else "" + for ext in self.extension: + fig.savefig(f"{out_dir}/FeatureImportance_{lab}_{self.channel}.{ext}") + else: + for ext in self.extension: + fig.savefig(f"{out_dir}/FeatureImportanceAll_{self.channel}.{ext}") + + def process(self): + """ + Process function of the class, performing data preparation, + training, testing, saving the model and important plots + """ + + self.__check_input_consistency() + df_bkg, df_prompt, df_nonprompt = self.__get_sliced_dfs() + + for i_pt, pt_bin in enumerate(self.pt_bins): + print(f"\n\033[94mStarting ML analysis --- {pt_bin[0]} < pT < {pt_bin[1]} GeV/c\033[0m") + + out_dir_pt = os.path.join(os.path.expanduser(self.outdir), f"pt{pt_bin[0]}_{pt_bin[1]}") + if os.path.isdir(out_dir_pt): + print( + ( + f"\033[93mWARNING: Output directory '{out_dir_pt}' already exists," + " overwrites possibly ongoing!\033[0m" + ) + ) + else: + os.makedirs(out_dir_pt) + + df_pt_nonprompt = pd.DataFrame() if df_nonprompt is None else df_nonprompt.get_slice(i_pt) + if self.share == "all_signal": + bkg_factor = self.bkg_factor[i_pt] + else: + bkg_factor = None + + train_test_data = self.__data_prep( + df_bkg.get_slice(i_pt), df_prompt.get_slice(i_pt), df_pt_nonprompt, pt_bin, out_dir_pt, bkg_factor + ) + self.__train_test(train_test_data, self.hyper_pars[i_pt], pt_bin, out_dir_pt) + + +def main(cfg): + """ + Main function + + Parameters + ----------------- + - config: dictionary with config read from a yaml file + """ + MlTrainer(cfg).process() + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Arguments") + parser.add_argument("config", metavar="text", default="config.yml", help="config file name for ml") + args = parser.parse_args() + + print("Loading analysis configuration: ...", end="\r") + with open(args.config, "r", encoding="utf-8") as yml_cfg: + configuration = yaml.load(yml_cfg, yaml.FullLoader) + print("Loading analysis configuration: Done!") + + main(configuration) diff --git a/PWGHF/D2H/Macros/compute_fraction_cutvar.py b/PWGHF/D2H/Macros/compute_fraction_cutvar.py index 57182744893..04b3e9f6fe2 100644 --- a/PWGHF/D2H/Macros/compute_fraction_cutvar.py +++ b/PWGHF/D2H/Macros/compute_fraction_cutvar.py @@ -10,11 +10,13 @@ import argparse import json import os +import sys import numpy as np # pylint: disable=import-error import ROOT # pylint: disable=import-error +sys.path.insert(0, '..') from cut_variation import CutVarMinimiser -from style_formatter import set_object_style +from utils.style_formatter import set_object_style # pylint: disable=no-member,too-many-locals,too-many-statements @@ -176,24 +178,39 @@ def main(config): canv_cov.Write() histo_cov.Write() + canv_combined = ROOT.TCanvas("canv_combined", "", 1000, 1000) + canv_combined.Divide(2, 2) + canv_combined.cd(1) + canv_rawy.DrawClonePad() + canv_combined.cd(2) + canv_eff.DrawClonePad() + canv_combined.cd(3) + canv_frac.DrawClonePad() + canv_combined.cd(4) + canv_cov.DrawClonePad() + output_name_rawy_pdf = f"Distr_{cfg['output']['file'].replace('.root', '.pdf')}" output_name_eff_pdf = f"Eff_{cfg['output']['file'].replace('.root', '.pdf')}" output_name_frac_pdf = f"Frac_{cfg['output']['file'].replace('.root', '.pdf')}" output_name_covmat_pdf = f"CovMatrix_{cfg['output']['file'].replace('.root', '.pdf')}" + output_name_pdf = f"{cfg['output']['file'].replace('.root', '.pdf')}" if ipt == 0: canv_rawy.SaveAs(f"{os.path.join(cfg['output']['directory'], output_name_rawy_pdf)}[") canv_eff.SaveAs(f"{os.path.join(cfg['output']['directory'], output_name_eff_pdf)}[") canv_frac.SaveAs(f"{os.path.join(cfg['output']['directory'], output_name_frac_pdf)}[") canv_cov.SaveAs(f"{os.path.join(cfg['output']['directory'], output_name_covmat_pdf)}[") + canv_combined.SaveAs(f"{os.path.join(cfg['output']['directory'], output_name_pdf)}[") canv_rawy.SaveAs(f"{os.path.join(cfg['output']['directory'], output_name_rawy_pdf)}") canv_eff.SaveAs(f"{os.path.join(cfg['output']['directory'], output_name_eff_pdf)}") canv_frac.SaveAs(f"{os.path.join(cfg['output']['directory'], output_name_frac_pdf)}") canv_cov.SaveAs(f"{os.path.join(cfg['output']['directory'], output_name_covmat_pdf)}") + canv_combined.SaveAs(f"{os.path.join(cfg['output']['directory'], output_name_pdf)}") if ipt == hist_rawy[0].GetNbinsX() - 1: canv_rawy.SaveAs(f"{os.path.join(cfg['output']['directory'], output_name_rawy_pdf)}]") canv_eff.SaveAs(f"{os.path.join(cfg['output']['directory'], output_name_eff_pdf)}]") canv_frac.SaveAs(f"{os.path.join(cfg['output']['directory'], output_name_frac_pdf)}]") canv_cov.SaveAs(f"{os.path.join(cfg['output']['directory'], output_name_covmat_pdf)}]") + canv_combined.SaveAs(f"{os.path.join(cfg['output']['directory'], output_name_pdf)}]") output.cd() hist_corry_prompt.Write() diff --git a/PWGHF/D2H/Macros/cut_variation.py b/PWGHF/D2H/Macros/cut_variation.py index 74292f5acd5..ba827a6309c 100644 --- a/PWGHF/D2H/Macros/cut_variation.py +++ b/PWGHF/D2H/Macros/cut_variation.py @@ -11,7 +11,8 @@ import numpy as np # pylint: disable=import-error import ROOT # pylint: disable=import-error -from style_formatter import set_global_style, set_object_style +sys.path.insert(0, '..') +from utils.style_formatter import set_global_style, set_object_style # pylint: disable=too-many-instance-attributes @@ -295,6 +296,49 @@ def get_raw_prompt_fraction(self, effacc_p, effacc_np): return f_p, f_p_unc + def get_raw_prompt_fraction_ext(self, corry_p, corry_np, unc_corry_p, + unc_corry_np, cov_p_np, effacc_p, effacc_np): + """ + Helper function to get the raw prompt fraction given the efficiencies + + Parameters + ----------------------------------------------------- + - corry_p: float + corrected yield for prompt signal + - corry_np: float + corrected yield for non-prompt signal + - unc_corry_np: float + uncertainty on corrected yield for prompt signal + - unc_corry_np: float + uncertainty on corrected yield for non-prompt signal + - cov_p_np: float + covariance between prompt and non-prompt signal + - effacc_p: float + eff x acc for prompt signal + - effacc_np: float + eff x acc for non-prompt signal + + Returns + ----------------------------------------------------- + - f_p, f_p_unc: (float, float) + raw prompt fraction with its uncertainty + """ + + rawy_p = effacc_p * corry_p + rawy_np = effacc_np * corry_np + f_p = rawy_p / (rawy_p + rawy_np) + + # derivatives of prompt fraction wrt corr yields + d_p = (effacc_p * (rawy_p + rawy_np) - effacc_p**2 * corry_p) / (rawy_p + rawy_np) ** 2 + d_np = -effacc_np * rawy_p / (rawy_p + rawy_np) ** 2 + f_p_unc = np.sqrt( + d_p**2 * unc_corry_p**2 + + d_np**2 * unc_corry_np**2 + + 2 * d_p * d_np * cov_p_np + ) + + return f_p, f_p_unc + def get_raw_nonprompt_fraction(self, effacc_p, effacc_np): """ Helper function to get the raw non-prompt fraction given the efficiencies @@ -318,6 +362,41 @@ def get_raw_nonprompt_fraction(self, effacc_p, effacc_np): return f_np, f_np_unc + def get_raw_nonprompt_fraction_ext(self, corry_p, corry_np, unc_corry_p, + unc_corry_np, cov_p_np, effacc_p, effacc_np): + """ + Helper function to get the raw non-prompt fraction given the efficiencies + + Parameters + ----------------------------------------------------- + - corry_p: float + corrected yield for prompt signal + - corry_np: float + corrected yield for non-prompt signal + - unc_corry_np: float + uncertainty on corrected yield for prompt signal + - unc_corry_np: float + uncertainty on corrected yield for non-prompt signal + - cov_p_np: float + covariance between prompt and non-prompt signal + - effacc_p: float + eff x acc for prompt signal + - effacc_np: float + eff x acc for non-prompt signal + + Returns + ----------------------------------------------------- + - f_np, f_np_unc: (float, float) + raw non-prompt fraction with its uncertainty + + """ + + f_p, f_np_unc = self.get_raw_prompt_fraction_ext(corry_p, corry_np, unc_corry_p, + unc_corry_np, cov_p_np, effacc_p, effacc_np) + f_np = 1 - f_p + + return f_np, f_np_unc + def get_corr_prompt_fraction(self): """ Helper function to get the corrected prompt fraction @@ -365,7 +444,7 @@ def plot_result(self, suffix=""): needed otherwise it is destroyed """ - set_global_style(padleftmargin=0.16, padbottommargin=0.12, titleoffsety=1.6) + set_global_style(padleftmargin=0.16, padbottommargin=0.12, padtopmargin=0.075, titleoffsety=1.6) hist_raw_yield = ROOT.TH1F( f"hRawYieldVsCut{suffix}", @@ -435,7 +514,7 @@ def plot_result(self, suffix=""): hist_raw_yield.GetMaximum() * 1.2, ";cut set;raw yield", ) - leg = ROOT.TLegend(0.6, 0.65, 0.8, 0.9) + leg = ROOT.TLegend(0.6, 0.65, 0.8, 0.85) leg.SetBorderSize(0) leg.SetFillStyle(0) leg.SetTextSize(0.04) diff --git a/PWGHF/D2H/Macros/runMassFitter.C b/PWGHF/D2H/Macros/runMassFitter.C index 0c4c44f9ff7..b5fc1fb9187 100644 --- a/PWGHF/D2H/Macros/runMassFitter.C +++ b/PWGHF/D2H/Macros/runMassFitter.C @@ -40,7 +40,7 @@ using namespace rapidjson; int runMassFitter(TString configFileName = "config_massfitter.json"); template -void readArray(const Value& jsonArray, vector& output) +void readArray(const Value& jsonArray, std::vector& output) { for (auto it = jsonArray.Begin(); it != jsonArray.End(); it++) { auto value = it->template Get(); @@ -48,7 +48,7 @@ void readArray(const Value& jsonArray, vector& output) } } -void parseStringArray(const Value& jsonArray, vector& output) +void parseStringArray(const Value& jsonArray, std::vector& output) { size_t arrayLength = jsonArray.Size(); for (size_t i = 0; i < arrayLength; i++) { diff --git a/PWGHF/D2H/TableProducer/CMakeLists.txt b/PWGHF/D2H/TableProducer/CMakeLists.txt index 19cf1d44e5f..92eeda51051 100644 --- a/PWGHF/D2H/TableProducer/CMakeLists.txt +++ b/PWGHF/D2H/TableProducer/CMakeLists.txt @@ -21,6 +21,11 @@ o2physics_add_dpl_workflow(candidate-creator-bplus-reduced PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(candidate-creator-bs-reduced + SOURCES candidateCreatorBsReduced.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(candidate-creator-charm-reso-reduced SOURCES candidateCreatorCharmResoReduced.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -35,18 +40,29 @@ o2physics_add_dpl_workflow(candidate-selector-b0-to-d-pi-reduced o2physics_add_dpl_workflow(candidate-selector-bplus-to-d0-pi-reduced SOURCES candidateSelectorBplusToD0PiReduced.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(candidate-selector-bs-to-ds-pi-reduced + SOURCES candidateSelectorBsToDsPiReduced.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore COMPONENT_NAME Analysis) # Data creators o2physics_add_dpl_workflow(data-creator-charm-had-pi-reduced SOURCES dataCreatorCharmHadPiReduced.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(data-creator-charm-reso-reduced SOURCES dataCreatorCharmResoReduced.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) +# Converters + +o2physics_add_dpl_workflow(converter-reduced-3-prongs-ml + SOURCES converterReduced3ProngsMl.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) \ No newline at end of file diff --git a/PWGHF/D2H/TableProducer/candidateCreatorB0Reduced.cxx b/PWGHF/D2H/TableProducer/candidateCreatorB0Reduced.cxx index c12bd8da3b7..89562743ef4 100644 --- a/PWGHF/D2H/TableProducer/candidateCreatorB0Reduced.cxx +++ b/PWGHF/D2H/TableProducer/candidateCreatorB0Reduced.cxx @@ -15,6 +15,8 @@ /// \author Alexandre Bigot , IPHC Strasbourg /// \author Fabrizio Grosa , CERN +#include + #include "CommonConstants/PhysicsConstants.h" #include "DCAFitter/DCAFitterN.h" #include "Framework/AnalysisTask.h" @@ -148,7 +150,7 @@ struct HfCandidateCreatorB0Reduced { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN cannot work, skipping the candidate."; + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; hCandidates->Fill(SVFitting::Fail); continue; } @@ -193,8 +195,7 @@ struct HfCandidateCreatorB0Reduced { pVecD[0], pVecD[1], pVecD[2], pVecPion[0], pVecPion[1], pVecPion[2], dcaD.getY(), dcaPion.getY(), - std::sqrt(dcaD.getSigmaY2()), std::sqrt(dcaPion.getSigmaY2()), - BIT(hf_cand_b0::DecayType::B0ToDPi)); + std::sqrt(dcaD.getSigmaY2()), std::sqrt(dcaPion.getSigmaY2())); rowCandidateProngs(candD.globalIndex(), trackPion.globalIndex()); @@ -294,7 +295,7 @@ struct HfCandidateCreatorB0ReducedExpressions { if ((rowDPiMcRec.prong0Id() != candB0.prong0Id()) || (rowDPiMcRec.prong1Id() != candB0.prong1Id())) { continue; } - rowB0McRec(rowDPiMcRec.flagMcMatchRec(), rowDPiMcRec.debugMcRec(), rowDPiMcRec.ptMother()); + rowB0McRec(rowDPiMcRec.flagMcMatchRec(), rowDPiMcRec.flagWrongCollision(), rowDPiMcRec.debugMcRec(), rowDPiMcRec.ptMother()); filledMcInfo = true; if constexpr (checkDecayTypeMc) { rowB0McCheck(rowDPiMcRec.pdgCodeBeautyMother(), @@ -307,7 +308,7 @@ struct HfCandidateCreatorB0ReducedExpressions { break; } if (!filledMcInfo) { // protection to get same size tables in case something went wrong: we created a candidate that was not preselected in the D-Pi creator - rowB0McRec(0, -1, -1.f); + rowB0McRec(0, -1, -1, -1.f); if constexpr (checkDecayTypeMc) { rowB0McCheck(-1, -1, -1, -1, -1, -1); } diff --git a/PWGHF/D2H/TableProducer/candidateCreatorBplusReduced.cxx b/PWGHF/D2H/TableProducer/candidateCreatorBplusReduced.cxx index 8bdb7ed36d5..3cd3e0f571b 100644 --- a/PWGHF/D2H/TableProducer/candidateCreatorBplusReduced.cxx +++ b/PWGHF/D2H/TableProducer/candidateCreatorBplusReduced.cxx @@ -14,6 +14,8 @@ /// /// \author Antonio Palasciano , Università degli Studi di Bari +#include + #include "CommonConstants/PhysicsConstants.h" #include "DCAFitter/DCAFitterN.h" #include "Framework/AnalysisTask.h" @@ -37,8 +39,9 @@ using namespace o2::hf_trkcandsel; /// Reconstruction of B+ candidates struct HfCandidateCreatorBplusReduced { - Produces rowCandidateBase; // table defined in CandidateReconstructionTables.h - Produces rowCandidateProngs; // table defined in ReducedDataModel.h + Produces rowCandidateBase; // table defined in CandidateReconstructionTables.h + Produces rowCandidateProngs; // table defined in ReducedDataModel.h + Produces rowCandidateDmesMlScores; // table defined in ReducedDataModel.h // vertexing Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; @@ -61,6 +64,7 @@ struct HfCandidateCreatorBplusReduced { using HfRedCollisionsWithExtras = soa::Join; Preslice> candsDPerCollision = hf_track_index_reduced::hfRedCollisionId; + Preslice> candsDWithMlPerCollision = hf_track_index_reduced::hfRedCollisionId; Preslice> tracksPionPerCollision = hf_track_index_reduced::hfRedCollisionId; std::shared_ptr hCandidates; @@ -68,6 +72,11 @@ struct HfCandidateCreatorBplusReduced { void init(InitContext const&) { + std::array doprocess{doprocessData, doprocessDataWithDmesMl}; + if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { + LOGP(fatal, "Only one process function for data should be enabled at a time."); + } + // invariant-mass window cut massPi = o2::constants::physics::MassPiPlus; massD0 = o2::constants::physics::MassD0; @@ -93,11 +102,112 @@ struct HfCandidateCreatorBplusReduced { setLabelHistoCands(hCandidates); } - void process(HfRedCollisionsWithExtras const& collisions, - soa::Join const& candsD, - soa::Join const& tracksPion, - aod::HfOrigColCounts const& collisionsCounter, - aod::HfCandBpConfigs const& configs) + /// Main function to perform B+ candidate creation + /// \param withDmesMl is the flag to use the table with ML scores for the D0 daughter (only possible if present in the derived data) + /// \param collision the collision + /// \param candsDThisColl B+ candidates in this collision + /// \param tracksPionThisCollision pion tracks in this collision + /// \param invMass2D0PiMin minimum B+ invariant-mass + /// \param invMass2D0PiMax maximum B+ invariant-mass + template + void runCandidateCreation(Coll const& collision, + Cands const& candsDThisColl, + Pions const& tracksPionThisCollision, + const float& invMass2D0PiMin, + const float& invMass2D0PiMax) + { + auto primaryVertex = getPrimaryVertex(collision); + auto covMatrixPV = primaryVertex.getCov(); + + // Set the magnetic field from ccdb + bz = collision.bz(); + df2.setBz(bz); + + for (const auto& candD0 : candsDThisColl) { + auto trackParCovD = getTrackParCov(candD0); + std::array pVecD0 = candD0.pVector(); + + for (const auto& trackPion : tracksPionThisCollision) { + auto trackParCovPi = getTrackParCov(trackPion); + std::array pVecPion = trackPion.pVector(); + + // compute invariant mass square and apply selection + auto invMass2D0Pi = RecoDecay::m2(std::array{pVecD0, pVecPion}, std::array{massD0, massPi}); + if ((invMass2D0Pi < invMass2D0PiMin) || (invMass2D0Pi > invMass2D0PiMax)) { + continue; + } + // --------------------------------- + // reconstruct the 2-prong B+ vertex + hCandidates->Fill(SVFitting::BeforeFit); + try { + if (df2.process(trackParCovD, trackParCovPi) == 0) { + continue; + } + } catch (const std::runtime_error& error) { + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; + hCandidates->Fill(SVFitting::Fail); + continue; + } + hCandidates->Fill(SVFitting::FitOk); + // D0Pi passed B+ reconstruction + + // calculate relevant properties + const auto& secondaryVertexBplus = df2.getPCACandidate(); + auto chi2PCA = df2.getChi2AtPCACandidate(); + auto covMatrixPCA = df2.calcPCACovMatrixFlat(); + registry.fill(HIST("hCovSVXX"), covMatrixPCA[0]); + registry.fill(HIST("hCovPVXX"), covMatrixPV[0]); + + // propagate D0 and Pi to the B+ vertex + df2.propagateTracksToVertex(); + // track.getPxPyPzGlo(pVec) modifies pVec of track + df2.getTrack(0).getPxPyPzGlo(pVecD0); // momentum of D0 at the B+ vertex + df2.getTrack(1).getPxPyPzGlo(pVecPion); // momentum of Pi at the B+ vertex + + registry.fill(HIST("hMassBplusToD0Pi"), std::sqrt(invMass2D0Pi)); + + // compute impact parameters of D0 and Pi + o2::dataformats::DCA dcaD0; + o2::dataformats::DCA dcaPion; + trackParCovD.propagateToDCA(primaryVertex, bz, &dcaD0); + trackParCovPi.propagateToDCA(primaryVertex, bz, &dcaPion); + + // get uncertainty of the decay length + double phi, theta; + // getPointDirection modifies phi and theta + getPointDirection(std::array{collision.posX(), collision.posY(), collision.posZ()}, secondaryVertexBplus, phi, theta); + auto errorDecayLength = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); + auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); + + // fill the candidate table for the B+ here: + rowCandidateBase(collision.globalIndex(), + collision.posX(), collision.posY(), collision.posZ(), + secondaryVertexBplus[0], secondaryVertexBplus[1], secondaryVertexBplus[2], + errorDecayLength, errorDecayLengthXY, + chi2PCA, + pVecD0[0], pVecD0[1], pVecD0[2], + pVecPion[0], pVecPion[1], pVecPion[2], + dcaD0.getY(), dcaPion.getY(), + std::sqrt(dcaD0.getSigmaY2()), std::sqrt(dcaPion.getSigmaY2())); + + rowCandidateProngs(candD0.globalIndex(), trackPion.globalIndex()); + + if constexpr (withDmesMl) { + if (trackPion.signed1Pt() < 0) { + rowCandidateDmesMlScores(candD0.mlScoreBkgMassHypo0(), candD0.mlScorePromptMassHypo0(), candD0.mlScoreNonpromptMassHypo0()); + } else { + rowCandidateDmesMlScores(candD0.mlScoreBkgMassHypo1(), candD0.mlScorePromptMassHypo1(), candD0.mlScoreNonpromptMassHypo1()); + } + } + } // pi loop + } // D0 loop + } // end runCandidateCreation + + void processData(HfRedCollisionsWithExtras const& collisions, + soa::Join const& candsD, + soa::Join const& tracksPion, + aod::HfOrigColCounts const& collisionsCounter, + aod::HfCandBpConfigs const& configs) { // D0Pi invariant-mass window cut for (const auto& config : configs) { @@ -116,105 +226,66 @@ struct HfCandidateCreatorBplusReduced { for (const auto& collision : collisions) { auto thisCollId = collision.globalIndex(); - auto primaryVertex = getPrimaryVertex(collision); - auto covMatrixPV = primaryVertex.getCov(); - + auto candsDThisColl = candsD.sliceBy(candsDPerCollision, thisCollId); + auto tracksPionThisCollision = tracksPion.sliceBy(tracksPionPerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, tracksPionThisCollision, invMass2D0PiMin, invMass2D0PiMax); if (ncol % 10000 == 0) { LOG(debug) << ncol << " collisions parsed"; } ncol++; + } + } // processData + + PROCESS_SWITCH(HfCandidateCreatorBplusReduced, processData, "Process data without any ML score", true); + + void processDataWithDmesMl(HfRedCollisionsWithExtras const& collisions, + soa::Join const& candsD, + soa::Join const& tracksPion, + aod::HfOrigColCounts const& collisionsCounter, + aod::HfCandBpConfigs const& configs) + { + // D0Pi invariant-mass window cut + for (const auto& config : configs) { + myInvMassWindowD0Pi = config.myInvMassWindowD0Pi(); + } + // invMassWindowD0PiTolerance is used to apply a slightly tighter cut than in D0Pi pair preselection + // to avoid accepting D0Pi pairs that were not formed in D0Pi pair creator + float invMass2D0PiMin = (massBplus - myInvMassWindowD0Pi + invMassWindowD0PiTolerance) * (massBplus - myInvMassWindowD0Pi + invMassWindowD0PiTolerance); + float invMass2D0PiMax = (massBplus + myInvMassWindowD0Pi - invMassWindowD0PiTolerance) * (massBplus + myInvMassWindowD0Pi - invMassWindowD0PiTolerance); - // Set the magnetic field from ccdb - bz = collision.bz(); - df2.setBz(bz); + for (const auto& collisionCounter : collisionsCounter) { + registry.fill(HIST("hEvents"), 1, collisionCounter.originalCollisionCount()); + } + static int ncol = 0; + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD.sliceBy(candsDPerCollision, thisCollId); - for (const auto& candD0 : candsDThisColl) { - auto trackParCovD = getTrackParCov(candD0); - std::array pVecD0 = candD0.pVector(); - - auto tracksPionThisCollision = tracksPion.sliceBy(tracksPionPerCollision, thisCollId); - for (const auto& trackPion : tracksPionThisCollision) { - auto trackParCovPi = getTrackParCov(trackPion); - std::array pVecPion = trackPion.pVector(); - - // compute invariant mass square and apply selection - auto invMass2D0Pi = RecoDecay::m2(std::array{pVecD0, pVecPion}, std::array{massD0, massPi}); - if ((invMass2D0Pi < invMass2D0PiMin) || (invMass2D0Pi > invMass2D0PiMax)) { - continue; - } - // --------------------------------- - // reconstruct the 2-prong B+ vertex - hCandidates->Fill(SVFitting::BeforeFit); - try { - if (df2.process(trackParCovD, trackParCovPi) == 0) { - continue; - } - } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN cannot work, skipping the candidate."; - hCandidates->Fill(SVFitting::Fail); - continue; - } - hCandidates->Fill(SVFitting::FitOk); - - // D0Pi passed B+ reconstruction - - // calculate relevant properties - const auto& secondaryVertexBplus = df2.getPCACandidate(); - auto chi2PCA = df2.getChi2AtPCACandidate(); - auto covMatrixPCA = df2.calcPCACovMatrixFlat(); - registry.fill(HIST("hCovSVXX"), covMatrixPCA[0]); - registry.fill(HIST("hCovPVXX"), covMatrixPV[0]); - - // propagate D0 and Pi to the B+ vertex - df2.propagateTracksToVertex(); - // track.getPxPyPzGlo(pVec) modifies pVec of track - df2.getTrack(0).getPxPyPzGlo(pVecD0); // momentum of D0 at the B+ vertex - df2.getTrack(1).getPxPyPzGlo(pVecPion); // momentum of Pi at the B+ vertex - - registry.fill(HIST("hMassBplusToD0Pi"), std::sqrt(invMass2D0Pi)); - - // compute impact parameters of D0 and Pi - o2::dataformats::DCA dcaD0; - o2::dataformats::DCA dcaPion; - trackParCovD.propagateToDCA(primaryVertex, bz, &dcaD0); - trackParCovPi.propagateToDCA(primaryVertex, bz, &dcaPion); - - // get uncertainty of the decay length - double phi, theta; - // getPointDirection modifies phi and theta - getPointDirection(std::array{collision.posX(), collision.posY(), collision.posZ()}, secondaryVertexBplus, phi, theta); - auto errorDecayLength = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); - auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); - - int hfFlag = BIT(hf_cand_bplus::DecayType::BplusToD0Pi); - - // fill the candidate table for the B+ here: - rowCandidateBase(thisCollId, - collision.posX(), collision.posY(), collision.posZ(), - secondaryVertexBplus[0], secondaryVertexBplus[1], secondaryVertexBplus[2], - errorDecayLength, errorDecayLengthXY, - chi2PCA, - pVecD0[0], pVecD0[1], pVecD0[2], - pVecPion[0], pVecPion[1], pVecPion[2], - dcaD0.getY(), dcaPion.getY(), - std::sqrt(dcaD0.getSigmaY2()), std::sqrt(dcaPion.getSigmaY2()), - hfFlag); - - rowCandidateProngs(candD0.globalIndex(), trackPion.globalIndex()); - } // pi loop - } // D0 loop - } // collision loop - } // process -}; // struct + auto tracksPionThisCollision = tracksPion.sliceBy(tracksPionPerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, tracksPionThisCollision, invMass2D0PiMin, invMass2D0PiMax); + if (ncol % 10000 == 0) { + LOGP(debug, "collisions parsed {}", ncol); + } + ncol++; + } + } // processDataWithDmesMl + + PROCESS_SWITCH(HfCandidateCreatorBplusReduced, processDataWithDmesMl, "Process data with ML scores of D mesons", false); +}; // struct /// Extends the table base with expression columns and performs MC matching. struct HfCandidateCreatorBplusReducedExpressions { Spawns rowCandidateBPlus; Spawns rowTracksExt; Produces rowBplusMcRec; - - void processMc(HfMcRecRedD0Pis const& rowsD0PiMcRec, HfRedBplusProngs const& candsBplus) + Produces rowBplusMcCheck; + + /// Fill candidate information at MC reconstruction level + /// \param checkDecayTypeMc + /// \param rowsD0PiMcRec MC reco information on D0Pi pairs + /// \param candsBplus prong global indices of B+ candidates + template + void fillBplusMcRec(McRec const& rowsD0PiMcRec, HfRedBplusProngs const& candsBplus) { for (const auto& candBplus : candsBplus) { bool filledMcInfo{false}; @@ -222,16 +293,37 @@ struct HfCandidateCreatorBplusReducedExpressions { if ((rowD0PiMcRec.prong0Id() != candBplus.prong0Id()) || (rowD0PiMcRec.prong1Id() != candBplus.prong1Id())) { continue; } - rowBplusMcRec(rowD0PiMcRec.flagMcMatchRec(), rowD0PiMcRec.debugMcRec(), rowD0PiMcRec.ptMother()); + rowBplusMcRec(rowD0PiMcRec.flagMcMatchRec(), rowD0PiMcRec.flagWrongCollision(), rowD0PiMcRec.debugMcRec(), rowD0PiMcRec.ptMother()); filledMcInfo = true; + if constexpr (checkDecayTypeMc) { + rowBplusMcCheck(rowD0PiMcRec.pdgCodeBeautyMother(), + rowD0PiMcRec.pdgCodeCharmMother(), + rowD0PiMcRec.pdgCodeProng0(), + rowD0PiMcRec.pdgCodeProng1(), + rowD0PiMcRec.pdgCodeProng2()); + } break; } - if (!filledMcInfo) { // protection to get same size tables in case something went wrong: we created a candidate that was not preselected in the D-Pi creator - rowBplusMcRec(0, -1, -1.f); + if (!filledMcInfo) { // protection to get same size tables in case something went wrong: we created a candidate that was not preselected in the D0-Pi creator + rowBplusMcRec(0, -1, -1, -1.f); + if constexpr (checkDecayTypeMc) { + rowBplusMcCheck(-1, -1, -1, -1, -1); + } } } } + + void processMc(HfMcRecRedD0Pis const& rowsD0PiMcRec, HfRedBplusProngs const& candsBplus) + { + fillBplusMcRec(rowsD0PiMcRec, candsBplus); + } PROCESS_SWITCH(HfCandidateCreatorBplusReducedExpressions, processMc, "Process MC", false); + + void processMcWithDecayTypeCheck(soa::Join const& rowsD0PiMcRec, HfRedBplusProngs const& candsBplus) + { + fillBplusMcRec(rowsD0PiMcRec, candsBplus); + } + PROCESS_SWITCH(HfCandidateCreatorBplusReducedExpressions, processMcWithDecayTypeCheck, "Process MC with decay type checks", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/D2H/TableProducer/candidateCreatorBsReduced.cxx b/PWGHF/D2H/TableProducer/candidateCreatorBsReduced.cxx new file mode 100644 index 00000000000..7198796bc9b --- /dev/null +++ b/PWGHF/D2H/TableProducer/candidateCreatorBsReduced.cxx @@ -0,0 +1,333 @@ +// 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 candidateCreatorBsReduced.cxx +/// \brief Reconstruction of Bs candidates +/// +/// \author Fabio Catalano , CERN + +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/DCA.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/CollisionAssociationTables.h" + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/Utils/utilsTrkCandHf.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::hf_trkcandsel; + +/// Reconstruction of Bs candidates +struct HfCandidateCreatorBsReduced { + Produces rowCandidateBase; // table defined in CandidateReconstructionTables.h + Produces rowCandidateProngs; // table defined in ReducedDataModel.h + Produces rowCandidateDmesMlScores; // table defined in ReducedDataModel.h + + // vertexing + Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; + Configurable useAbsDCA{"useAbsDCA", true, "Minimise abs. distance rather than chi2"}; + Configurable useWeightedFinalPCA{"useWeightedFinalPCA", false, "Recalculate vertex position using track covariances, effective only if useAbsDCA is true"}; + Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; + Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; + Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any B0 is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations is chi2/chi2old > this"}; + // selection + Configurable invMassWindowDPiTolerance{"invMassWindowDPiTolerance", 0.01, "invariant-mass window tolerance for DsPi pair preselections (GeV/c2)"}; + + float myInvMassWindowDPi{1.}; // variable that will store the value of invMassWindowCharmHadPi (defined in dataCreatorCharmHadPiReduced.cxx) + float massPi{o2::constants::physics::MassPiPlus}; + float massD{o2::constants::physics::MassDS}; + float massB{o2::constants::physics::MassBS}; + float bz{0.}; + + o2::vertexing::DCAFitterN<2> df2; // fitter for B vertex (2-prong vertex fitter) + + using HfRedCollisionsWithExtras = soa::Join; + + Preslice> candsDPerCollision = hf_track_index_reduced::hfRedCollisionId; + Preslice> candsDWithMlPerCollision = hf_track_index_reduced::hfRedCollisionId; + Preslice> tracksPionPerCollision = hf_track_index_reduced::hfRedCollisionId; + + std::shared_ptr hCandidates; + HistogramRegistry registry{"registry"}; + + void init(InitContext const&) + { + std::array doprocess{doprocessData, doprocessDataWithDmesMl}; + if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { + LOGP(fatal, "Only one process function for data should be enabled at a time."); + } + + // Initialize fitter + df2.setPropagateToPCA(propagateToPCA); + df2.setMaxR(maxR); + df2.setMaxDZIni(maxDZIni); + df2.setMinParamChange(minParamChange); + df2.setMinRelChi2Change(minRelChi2Change); + df2.setUseAbsDCA(useAbsDCA); + df2.setWeightedFinalPCA(useWeightedFinalPCA); + + // histograms + registry.add("hMassBsToDsPi", "2-prong candidates;inv. mass (B^{0}_{s} #rightarrow D_{s}^{#minus}#pi^{#plus} #rightarrow #K^{#minus}K^{#plus}#pi^{#minus}#pi^{#plus}) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 3., 8.}}}); + registry.add("hCovPVXX", "2-prong candidates;XX element of cov. matrix of prim. vtx. position (cm^{2});entries", {HistType::kTH1F, {{100, 0., 1.e-4}}}); + registry.add("hCovSVXX", "2-prong candidates;XX element of cov. matrix of sec. vtx. position (cm^{2});entries", {HistType::kTH1F, {{100, 0., 0.2}}}); + registry.add("hEvents", "Events;;entries", HistType::kTH1F, {{1, 0.5, 1.5}}); + + /// candidate monitoring + hCandidates = registry.add("hCandidates", "candidates counter", {HistType::kTH1D, {axisCands}}); + setLabelHistoCands(hCandidates); + } + + /// Main function to perform Bs candidate creation + /// \param withDmesMl is the flag to use the table with ML scores for the Ds- daughter (only possible if present in the derived data) + /// \param collision the collision + /// \param candsDThisColl Bs candidates in this collision + /// \param tracksPionThisCollision pion tracks in this collision + /// \param invMass2DPiMin minimum Bs invariant-mass + /// \param invMass2DPiMax maximum Bs invariant-mass + template + void runCandidateCreation(Coll const& collision, + Cands const& candsDThisColl, + Pions const& tracksPionThisCollision, + const float& invMass2DPiMin, + const float& invMass2DPiMax) + { + auto primaryVertex = getPrimaryVertex(collision); + auto covMatrixPV = primaryVertex.getCov(); + + // Set the magnetic field from ccdb + bz = collision.bz(); + df2.setBz(bz); + + for (const auto& candD : candsDThisColl) { + auto trackParCovD = getTrackParCov(candD); + std::array pVecD = candD.pVector(); + + for (const auto& trackPion : tracksPionThisCollision) { + // this track is among daughters + if (trackPion.trackId() == candD.prong0Id() || trackPion.trackId() == candD.prong1Id() || trackPion.trackId() == candD.prong2Id()) { + continue; + } + + auto trackParCovPi = getTrackParCov(trackPion); + std::array pVecPion = trackPion.pVector(); + + // compute invariant mass square and apply selection + auto invMass2DPi = RecoDecay::m2(std::array{pVecD, pVecPion}, std::array{massD, massPi}); + if ((invMass2DPi < invMass2DPiMin) || (invMass2DPi > invMass2DPiMax)) { + continue; + } + // --------------------------------- + // reconstruct the 2-prong Bs vertex + hCandidates->Fill(SVFitting::BeforeFit); + try { + if (df2.process(trackParCovD, trackParCovPi) == 0) { + continue; + } + } catch (const std::runtime_error& error) { + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; + hCandidates->Fill(SVFitting::Fail); + continue; + } + hCandidates->Fill(SVFitting::FitOk); // DsPi passed Bs reconstruction + + // calculate relevant properties + const auto& secondaryVertexB = df2.getPCACandidate(); + auto chi2PCA = df2.getChi2AtPCACandidate(); + auto covMatrixPCA = df2.calcPCACovMatrixFlat(); + registry.fill(HIST("hCovSVXX"), covMatrixPCA[0]); + registry.fill(HIST("hCovPVXX"), covMatrixPV[0]); + + // propagate Ds and Pi to the Bs vertex + df2.propagateTracksToVertex(); + // track.getPxPyPzGlo(pVec) modifies pVec of track + df2.getTrack(0).getPxPyPzGlo(pVecD); // momentum of Ds at the Bs vertex + df2.getTrack(1).getPxPyPzGlo(pVecPion); // momentum of Pi at the Bs vertex + + registry.fill(HIST("hMassBsToDsPi"), std::sqrt(invMass2DPi)); + + // compute impact parameters of Ds and Pi + o2::dataformats::DCA dcaD; + o2::dataformats::DCA dcaPion; + trackParCovD.propagateToDCA(primaryVertex, bz, &dcaD); + trackParCovPi.propagateToDCA(primaryVertex, bz, &dcaPion); + + // get uncertainty of the decay length + float phi, theta; + // getPointDirection modifies phi and theta + getPointDirection(std::array{collision.posX(), collision.posY(), collision.posZ()}, secondaryVertexB, phi, theta); + auto errorDecayLength = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); + auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); + + // fill the candidate table for the Bs here: + rowCandidateBase(collision.globalIndex(), + collision.posX(), collision.posY(), collision.posZ(), + secondaryVertexB[0], secondaryVertexB[1], secondaryVertexB[2], + errorDecayLength, errorDecayLengthXY, + chi2PCA, + pVecD[0], pVecD[1], pVecD[2], + pVecPion[0], pVecPion[1], pVecPion[2], + dcaD.getY(), dcaPion.getY(), + std::sqrt(dcaD.getSigmaY2()), std::sqrt(dcaPion.getSigmaY2())); + + rowCandidateProngs(candD.globalIndex(), trackPion.globalIndex()); + + if constexpr (withDmesMl) { + if (candD.invMassHypo0() > 0) { + rowCandidateDmesMlScores(candD.mlScoreBkgMassHypo0(), candD.mlScorePromptMassHypo0(), candD.mlScoreNonpromptMassHypo0()); + } else { + rowCandidateDmesMlScores(candD.mlScoreBkgMassHypo1(), candD.mlScorePromptMassHypo1(), candD.mlScoreNonpromptMassHypo1()); + } + // TODO: here we are assuming that only one of the two hypotheses is filled, to be checked + } + } // pi loop + } // D loop + } + + void processData(HfRedCollisionsWithExtras const& collisions, + soa::Join const& candsD, + soa::Join const& tracksPion, + aod::HfOrigColCounts const& collisionsCounter, + aod::HfCandBsConfigs const& configs) + { + // DsPi invariant-mass window cut + for (const auto& config : configs) { + myInvMassWindowDPi = config.myInvMassWindowDPi(); + } + // invMassWindowDPiTolerance is used to apply a slightly tighter cut than in DsPi pair preselection + // to avoid accepting DsPi pairs that were not formed in DsPi pair creator + float invMass2DPiMin = (massB - myInvMassWindowDPi + invMassWindowDPiTolerance) * (massB - myInvMassWindowDPi + invMassWindowDPiTolerance); + float invMass2DPiMax = (massB + myInvMassWindowDPi - invMassWindowDPiTolerance) * (massB + myInvMassWindowDPi - invMassWindowDPiTolerance); + + for (const auto& collisionCounter : collisionsCounter) { + registry.fill(HIST("hEvents"), 1, collisionCounter.originalCollisionCount()); + } + + static int ncol = 0; + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsD.sliceBy(candsDPerCollision, thisCollId); + auto tracksPionThisCollision = tracksPion.sliceBy(tracksPionPerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, tracksPionThisCollision, invMass2DPiMin, invMass2DPiMax); + if (ncol % 10000 == 0) { + LOGP(debug, "collisions parsed {}", ncol); + } + ncol++; + } + } // processData + + PROCESS_SWITCH(HfCandidateCreatorBsReduced, processData, "Process data without any ML score", true); + + void processDataWithDmesMl(HfRedCollisionsWithExtras const& collisions, + soa::Join const& candsD, + soa::Join const& tracksPion, + aod::HfOrigColCounts const& collisionsCounter, + aod::HfCandBsConfigs const& configs) + { + // DPi invariant-mass window cut + for (const auto& config : configs) { + myInvMassWindowDPi = config.myInvMassWindowDPi(); + } + // invMassWindowDPiTolerance is used to apply a slightly tighter cut than in DsPi pair preselection + // to avoid accepting DPi pairs that were not formed in DsPi pair creator + float invMass2DPiMin = (massB - myInvMassWindowDPi + invMassWindowDPiTolerance) * (massB - myInvMassWindowDPi + invMassWindowDPiTolerance); + float invMass2DPiMax = (massB + myInvMassWindowDPi - invMassWindowDPiTolerance) * (massB + myInvMassWindowDPi - invMassWindowDPiTolerance); + + for (const auto& collisionCounter : collisionsCounter) { + registry.fill(HIST("hEvents"), 1, collisionCounter.originalCollisionCount()); + } + + static int ncol = 0; + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsD.sliceBy(candsDPerCollision, thisCollId); + auto tracksPionThisCollision = tracksPion.sliceBy(tracksPionPerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, tracksPionThisCollision, invMass2DPiMin, invMass2DPiMax); + if (ncol % 10000 == 0) { + LOGP(debug, "collisions parsed {}", ncol); + } + ncol++; + } + } // processDataWithDmesMl + + PROCESS_SWITCH(HfCandidateCreatorBsReduced, processDataWithDmesMl, "Process data with ML scores of D mesons", false); +}; // struct + +/// Extends the table base with expression columns and performs MC matching. +struct HfCandidateCreatorBsReducedExpressions { + Spawns rowCandidateBs; + Spawns rowTracksExt; + Produces rowBsMcRec; + Produces rowBsMcCheck; + + /// Fill candidate information at MC reconstruction level + /// \param checkDecayTypeMc + /// \param rowsDPiMcRec MC reco information on DsPi pairs + /// \param candsB prong global indices of Bs candidates + template + void fillBsMcRec(McRec const& rowsDPiMcRec, HfRedBsProngs const& candsB) + { + for (const auto& candB : candsB) { + bool filledMcInfo{false}; + for (const auto& rowDPiMcRec : rowsDPiMcRec) { + if ((rowDPiMcRec.prong0Id() != candB.prong0Id()) || (rowDPiMcRec.prong1Id() != candB.prong1Id())) { + continue; + } + rowBsMcRec(rowDPiMcRec.flagMcMatchRec(), rowDPiMcRec.flagWrongCollision(), rowDPiMcRec.debugMcRec(), rowDPiMcRec.ptMother()); + filledMcInfo = true; + if constexpr (checkDecayTypeMc) { + rowBsMcCheck(rowDPiMcRec.pdgCodeBeautyMother(), + rowDPiMcRec.pdgCodeCharmMother(), + rowDPiMcRec.pdgCodeProng0(), + rowDPiMcRec.pdgCodeProng1(), + rowDPiMcRec.pdgCodeProng2(), + rowDPiMcRec.pdgCodeProng3()); + } + break; + } + if (!filledMcInfo) { // protection to get same size tables in case something went wrong: we created a candidate that was not preselected in the DsPi creator + rowBsMcRec(0, -1, -1, -1.f); + if constexpr (checkDecayTypeMc) { + rowBsMcCheck(-1, -1, -1, -1, -1, -1); + } + } + } + } + + void processMc(HfMcRecRedDsPis const& rowsDPiMcRec, HfRedBsProngs const& candsB) + { + fillBsMcRec(rowsDPiMcRec, candsB); + } + PROCESS_SWITCH(HfCandidateCreatorBsReducedExpressions, processMc, "Process MC", false); + + void processMcWithDecayTypeCheck(soa::Join const& rowsDPiMcRec, HfRedBsProngs const& candsB) + { + fillBsMcRec(rowsDPiMcRec, candsB); + } + PROCESS_SWITCH(HfCandidateCreatorBsReducedExpressions, processMcWithDecayTypeCheck, "Process MC with decay type checks", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/TableProducer/candidateCreatorCharmResoReduced.cxx b/PWGHF/D2H/TableProducer/candidateCreatorCharmResoReduced.cxx index 699d0bbbc31..8b83e3bf349 100644 --- a/PWGHF/D2H/TableProducer/candidateCreatorCharmResoReduced.cxx +++ b/PWGHF/D2H/TableProducer/candidateCreatorCharmResoReduced.cxx @@ -13,6 +13,8 @@ /// \brief Reconstruction of Resonance candidates /// /// \author Luca Aglietta , Università degli Studi di Torino +#include +#include #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" @@ -22,33 +24,52 @@ #include "Common/Core/trackUtilities.h" #include "Common/DataModel/CollisionAssociationTables.h" +#include "EventFiltering/PWGHF/HFFilterHelpers.h" #include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/D2H/Core/SelectorCutsRedDataFormat.h" +#include "PWGHF/Utils/utilsAnalysis.h" using namespace o2; using namespace o2::aod; +using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::constants::physics; enum Selections : uint8_t { NoSel = 0, DSel, V0Sel, + TrackSel, NSelSteps }; enum DecayChannel : uint8_t { Ds1ToDstarK0s = 0, Ds2StarToDplusK0s, XcToDplusLambda, - LambdaDminus + LambdaDminus, + DstarTrack }; + enum V0Type : uint8_t { K0s = 0, Lambda, AntiLambda }; -const int nBins = 7; -constexpr double binsPt[nBins + 1] = { + +enum DecayTypeMc : uint8_t { + Ds1ToDStarK0ToD0PiK0s = 1, + Ds2StarToDplusK0sToPiKaPiPiPi, + Ds1ToDStarK0ToDPlusPi0K0s, + Ds1ToDStarK0ToD0PiK0sPart, + Ds1ToDStarK0ToD0NoPiK0sPart, + Ds1ToDStarK0ToD0PiK0sOneMu, + Ds2StarToDplusK0sOneMu +}; + +const int nBinsPt = 7; +constexpr double binsPt[nBinsPt + 1] = { 1., 2., 4., @@ -56,89 +77,123 @@ constexpr double binsPt[nBins + 1] = { 8., 12., 24., - 50.}; -auto vecBins = std::vector{binsPt, binsPt + nBins + 1}; + 1000.}; +auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; struct HfCandidateCreatorCharmResoReduced { // Produces: Tables with resonance info Produces rowCandidateReso; - // Optional D daughter ML scores table + Produces rowCandidateResoTrack; + // Optional daughter ML scores table Produces mlScores; + // Table with candidate indices for MC matching + Produces rowCandidateResoIndices; // Configurables - Configurable invMassWindowD{"invMassWindowD", 0.5, "invariant-mass window for D candidates (GeV/c2)"}; - Configurable invMassWindowV0{"invMassWindowV0", 0.5, "invariant-mass window for V0 candidates (GeV/c2)"}; + Configurable rejectDV0PairsWithCommonDaughter{"rejectDV0PairsWithCommonDaughter", true, "flag to reject the pairs that share a daughter track if not done in the derived data creation"}; + Configurable keepSideBands{"keepSideBands", false, "flag to keep events from D meson sidebands for backgorund estimation"}; // QA switch Configurable activateQA{"activateQA", false, "Flag to enable QA histogram"}; - // Hist Axis - Configurable> binsPt{"binsPt", std::vector{vecBins}, "pT bin limits"}; + Configurable> binsPt{"binsPt", std::vector{vecBinsPt}, "Histogram pT bin limits"}; + // Daughters selection cuts + Configurable> cutsD{"cutsDdaughter", {hf_cuts_d_daughter::Cuts[0], hf_cuts_d_daughter::NBinsPt, hf_cuts_d_daughter::NCutVars, hf_cuts_d_daughter::labelsPt, hf_cuts_d_daughter::labelsCutVar}, "D daughter selections"}; + Configurable> binsPtD{"binsPtD", std::vector{hf_cuts_d_daughter::vecBinsPt}, "pT bin limits for D daughter cuts"}; + Configurable> cutsV0{"cutsV0daughter", {hf_cuts_v0_daughter::Cuts[0], hf_cuts_v0_daughter::NBinsPt, hf_cuts_v0_daughter::NCutVars, hf_cuts_v0_daughter::labelsPt, hf_cuts_v0_daughter::labelsCutVar}, "V0 daughter selections"}; + Configurable> binsPtV0{"binsPtV0", std::vector{hf_cuts_v0_daughter::vecBinsPt}, "pT bin limits for V0 daughter cuts"}; - using reducedDWithMl = soa::Join; + // Configurables for ME + Configurable numberEventsMixed{"numberEventsMixed", 5, "Number of events mixed in ME process"}; + Configurable numberEventsToSkip{"numberEventsToSkip", -1, "Number of events to Skip in ME process"}; + ConfigurableAxis multPoolBins{"multPoolBins", {VARIABLE_WIDTH, 0., 45., 60., 75., 95, 250}, "event multiplicity pools (PV contributors for now)"}; + ConfigurableAxis zPoolBins{"zPoolBins", {VARIABLE_WIDTH, -10.0, -4, -1, 1, 4, 10.0}, "z vertex position pools"}; + + using HfRed3PrNoTrksWithMl = soa::Join; // Partition of V0 candidates based on v0Type - Partition candidatesK0s = aod::hf_reso_cand_reduced::v0Type == (uint8_t)1 || aod::hf_reso_cand_reduced::v0Type == (uint8_t)3 || aod::hf_reso_cand_reduced::v0Type == (uint8_t)5; - Partition candidatesLambda = aod::hf_reso_cand_reduced::v0Type == (uint8_t)2 || aod::hf_reso_cand_reduced::v0Type == (uint8_t)4; + Partition candidatesK0s = aod::hf_reso_v0::v0Type == (uint8_t)1 || aod::hf_reso_v0::v0Type == (uint8_t)3 || aod::hf_reso_v0::v0Type == (uint8_t)5; + Partition candidatesLambda = aod::hf_reso_v0::v0Type == (uint8_t)2 || aod::hf_reso_v0::v0Type == (uint8_t)4; - // Useful constants - double massK0{0.}; - double massLambda{0.}; - double massDplus{0.}; - double massDstar{0.}; + SliceCache cache; + Preslice candsV0PerCollision = aod::hf_track_index_reduced::hfRedCollisionId; + Preslice candsTrackPerCollision = aod::hf_track_index_reduced::hfRedCollisionId; + Preslice candsDPerCollision = hf_track_index_reduced::hfRedCollisionId; + Preslice candsDPerCollisionWithMl = hf_track_index_reduced::hfRedCollisionId; - // Histogram registry: if task make it with a THNsparse with all variables you want to save HistogramRegistry registry{"registry"}; void init(InitContext const&) { // check that only one process function is enabled - std::array doprocess{doprocessDs2StarToDplusK0s, doprocessDs2StarToDplusK0sWithMl, doprocessDs1ToDstarK0s, doprocessDs1ToDstarK0sWithMl, doprocessXcToDplusLambda, doprocessXcToDplusLambdaWithMl, doprocessLambdaDminus, doprocessLambdaDminusWithMl}; + std::array doprocess{doprocessDs2StarToDplusK0s, doprocessDs2StarToDplusK0sWithMl, doprocessDs1ToDstarK0s, doprocessDs1ToDstarK0sWithMl, doprocessDs1ToDstarK0sMixedEvent, doprocessDs1ToDstarK0sMixedEventWithMl, doprocessDs2StarToDplusK0sMixedEventWithMl, + doprocessXcToDplusLambda, doprocessXcToDplusLambdaWithMl, doprocessLambdaDminus, doprocessLambdaDminusWithMl, doprocessDstarTrack, doprocessDstarTrackWithMl}; if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { LOGP(fatal, "Only one process function should be enabled! Please check your configuration!"); } // histograms - const AxisSpec axisPt{(std::vector)vecBins, "#it{p}_{T} (GeV/#it{c})"}; - registry.add("hMassDs1", "Ds1 candidates;m_{Ds1} (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{100, 2.4, 2.7}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hMassDs2Star", "Ds^{*}2 candidates; m_Ds^{*}2 (GeV/#it{c}^{2}) ;entries", {HistType::kTH2F, {{100, 2.4, 2.7}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hMassXcRes", "XcRes candidates; m_XcRes (GeV/#it{c}^{2}) ;entries", {HistType::kTH2F, {{100, 2.9, 3.3}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hMassLambdaDminus", "LambdaDminus candidates; m_LambdaDminus (GeV/#it{c}^{2}) ;entries", {HistType::kTH2F, {{100, 2.9, 3.3}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + const AxisSpec axisPt{(std::vector)vecBinsPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisMassDsj{400, 0.49f, 0.89f, ""}; + registry.add("hMassDs1", "Ds1 candidates;m_{Ds1} (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisMassDsj, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassDs2Star", "Ds^{*}2 candidates; m_Ds^{*}2 (GeV/#it{c}^{2}) ;entries", {HistType::kTH2F, {axisMassDsj, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassXcRes", "XcRes candidates; m_XcRes (GeV/#it{c}^{2}) ;entries", {HistType::kTH2F, {{300, 1.1, 1.4}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassLambdaDminus", "LambdaDminus candidates; m_LambdaDminus (GeV/#it{c}^{2}) ;entries", {HistType::kTH2F, {{300, 1.1, 1.4}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassDstarTrack", "DstarTrack candidates; m_DstarTrack (GeV/#it{c}^{2}) ;entries", {HistType::kTH2F, {{100, 0.9, 1.4}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + if (doprocessDs1ToDstarK0sMixedEvent) { + registry.add("hNPvContCorr", "Collision number of PV contributors ; N contrib ; N contrib", {HistType::kTH2F, {{100, 0, 250}, {100, 0, 250}}}); + registry.add("hZvertCorr", "Collision Z Vtx ; z PV [cm] ; z PV [cm]", {HistType::kTH2F, {{120, -12., 12.}, {120, -12., 12.}}}); + } + if (activateQA) { constexpr int kNBinsSelections = Selections::NSelSteps; std::string labels[kNBinsSelections]; labels[Selections::NoSel] = "No selection"; labels[Selections::DSel] = "D Candidates Selection"; labels[Selections::V0Sel] = "D & V0 candidate Selection"; + labels[Selections::TrackSel] = "D & Track candidate Selection"; static const AxisSpec axisSelections = {kNBinsSelections, 0.5, kNBinsSelections + 0.5, ""}; registry.add("hSelections", "Selections", {HistType::kTH1F, {axisSelections}}); for (int iBin = 0; iBin < kNBinsSelections; ++iBin) { registry.get(HIST("hSelections"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); } } - // mass constants - massK0 = o2::constants::physics::MassK0Short; - massLambda = o2::constants::physics::MassLambda; - massDplus = o2::constants::physics::MassDPlus; - massDstar = o2::constants::physics::MassDStar; } + /// Basic selection of D candidates /// \param candD is the reduced D meson candidate /// \return true if selections are passed template bool isDSelected(DRedTable const& candD) { - float massD{0.}; - // slection on D candidate mass + float invMassD{0.}; + float ptD = candD.pt(); + int ptBin = findBin(binsPtD, ptD); + if (ptBin == -1) { + return false; + } if (channel == DecayChannel::Ds2StarToDplusK0s || channel == DecayChannel::XcToDplusLambda || channel == DecayChannel::LambdaDminus) { - massD = massDplus; - } else if (channel == DecayChannel::Ds1ToDstarK0s) { - massD = massDstar; + invMassD = candD.invMassDplus(); + } else if (channel == DecayChannel::Ds1ToDstarK0s || channel == DecayChannel::DstarTrack) { + if (candD.dType() > 0) + invMassD = candD.invMassDstar() - candD.invMassD0(); + else + invMassD = candD.invMassAntiDstar() - candD.invMassD0Bar(); } - if (std::fabs(candD.invMass() - massD) > invMassWindowD) { - return false; + // invariant mass selection + if (!keepSideBands) { + if (invMassD < cutsD->get(ptBin, "invMassSignalLow") || invMassD > cutsD->get(ptBin, "invMassSignalHigh")) { + return false; + } + } else { + if ((invMassD < cutsD->get(ptBin, "invMassLeftSBLow")) || + (invMassD > cutsD->get(ptBin, "invMassLeftSBHigh") && invMassD < cutsD->get(ptBin, "invMassSignalLow")) || + (invMassD > cutsD->get(ptBin, "invMassSignalHigh") && invMassD < cutsD->get(ptBin, "invMassRightSBLow")) || + (invMassD > cutsD->get(ptBin, "invMassRightSBHigh"))) { + return false; + } } return true; } - /// Basic selection of V0 candidates + /// Basic selection of V0 and track candidates /// \param candV0 is the reduced V0 candidate /// \param candD is the reduced D meson candidate /// \return true if selections are passed @@ -147,13 +202,16 @@ struct HfCandidateCreatorCharmResoReduced { { float massV0{0.}; float invMassV0{0.}; - - // slection on V0 candidate mass + float ptV0 = candV0.pt(); + int ptBin = findBin(binsPtV0, ptV0); + if (ptBin == -1) { + return false; + } if (channel == DecayChannel::Ds2StarToDplusK0s || channel == DecayChannel::Ds1ToDstarK0s) { - massV0 = massK0; + massV0 = MassK0Short; invMassV0 = candV0.invMassK0s(); } else if (channel == DecayChannel::XcToDplusLambda || channel == DecayChannel::LambdaDminus) { - massV0 = massLambda; + massV0 = MassLambda; int wsFact{1}; if (channel == DecayChannel::LambdaDminus) wsFact = -1; @@ -165,20 +223,26 @@ struct HfCandidateCreatorCharmResoReduced { invMassV0 = candV0.invMassAntiLambda(); targetV0Type = V0Type::AntiLambda; } + // check skimming cuts if (!TESTBIT(candV0.v0Type(), targetV0Type)) { return false; } } - if (std::fabs(invMassV0 - massV0) > invMassWindowV0) { + // selection on V0 candidate mass + if ((invMassV0 - massV0) > cutsV0->get(ptBin, "invMassLow") && (massV0 - invMassV0) < cutsV0->get(ptBin, "invMassLow")) { + return false; + } + // selection on kinematics and topology + if (candV0.dca() > cutsV0->get(ptBin, "dcaMax") || candV0.cpa() < cutsV0->get(ptBin, "cpaMin") || candV0.v0Radius() < cutsV0->get(ptBin, "radiusMin")) { return false; } return true; } - template - void runCandidateCreation(Coll const& collisions, + template + void runCandidateCreation(Coll const& collision, DRedTable const& candsD, - V0RedTable const& candsV0) + V0TrRedTable const& candsV0Tr) { // loop on D candidates for (const auto& candD : candsD) { @@ -192,142 +256,464 @@ struct HfCandidateCreatorCharmResoReduced { if (activateQA) { registry.fill(HIST("hSelections"), 1 + Selections::DSel); } - float invMassD = candD.invMass(); - std::array pVecD = candD.pVector(); - float ptD = RecoDecay::pt(pVecD); - ; - // loop on V0 candidates + float invMassD{0.}; + float invMassD0{0.}; + if (std::abs(candD.dType()) == 1) + invMassD = candD.invMassDplus(); + if (candD.dType() == 2) { + invMassD = candD.invMassDstar(); + invMassD0 = candD.invMassD0(); + } + if (candD.dType() == -2) { + invMassD = candD.invMassAntiDstar(); + invMassD0 = candD.invMassD0Bar(); + } + std::array pVecD = {candD.px(), candD.py(), candD.pz()}; + + // loop on V0 or track candidates bool alreadyCounted{false}; - for (const auto& candV0 : candsV0) { - if (!isV0Selected(candV0, candD)) { + for (const auto& candV0Tr : candsV0Tr) { + if (rejectDV0PairsWithCommonDaughter) { + const std::array dDaughtersIDs = {candD.prong0Id(), candD.prong1Id(), candD.prong2Id()}; + if constexpr (channel == DecayChannel::DstarTrack) { + if (std::find(dDaughtersIDs.begin(), dDaughtersIDs.end(), candV0Tr.globalIndex()) != dDaughtersIDs.end()) { + continue; + } + } else { + if (std::find(dDaughtersIDs.begin(), dDaughtersIDs.end(), candV0Tr.prong0Id()) != dDaughtersIDs.end() || std::find(dDaughtersIDs.begin(), dDaughtersIDs.end(), candV0Tr.prong1Id()) != dDaughtersIDs.end()) { + continue; + } + } + } + if constexpr (channel != DecayChannel::DstarTrack) { + if (!isV0Selected(candV0Tr, candD)) { + continue; + } + if (activateQA && !alreadyCounted) { + registry.fill(HIST("hSelections"), 1 + Selections::V0Sel); + alreadyCounted = true; + } + } + + float invMassReso{0.}; + float invMassV0{0.}; + std::array pVecV0Tr = {candV0Tr.px(), candV0Tr.py(), candV0Tr.pz()}; + std::array, 3> pVectorCharmProngs = {candD.pVectorProng0(), candD.pVectorProng1(), candD.pVectorProng2()}; + float ptReso = RecoDecay::pt(RecoDecay::sumOfVec(pVecV0Tr, pVecD)); + + if constexpr (channel == DecayChannel::DstarTrack) { + if (candD.dType() > 0) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassProton}); + } else { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[1], pVectorCharmProngs[0], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassProton}); + } + registry.fill(HIST("hMassDstarTrack"), invMassReso - invMassD, ptReso); + } else { + switch (channel) { + case DecayChannel::Ds1ToDstarK0s: + invMassV0 = candV0Tr.invMassK0s(); + if (candD.dType() > 0) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassK0Short}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[1], pVectorCharmProngs[0], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassK0Short}) - invMassD; + } + registry.fill(HIST("hMassDs1"), invMassReso, ptReso); + break; + case DecayChannel::Ds2StarToDplusK0s: + invMassV0 = candV0Tr.invMassK0s(); + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassK0Short}) - invMassD; + registry.fill(HIST("hMassDs2Star"), invMassReso, ptReso); + break; + case DecayChannel::XcToDplusLambda: + if (candD.dType() > 0) { + invMassV0 = candV0Tr.invMassLambda(); + } else { + invMassV0 = candV0Tr.invMassAntiLambda(); + } + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassLambda}) - invMassD; + registry.fill(HIST("hMassXcRes"), invMassReso, ptReso); + break; + case DecayChannel::LambdaDminus: + if (candD.dType() < 0) { + invMassV0 = candV0Tr.invMassLambda(); + } else { + invMassV0 = candV0Tr.invMassAntiLambda(); + } + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassLambda}) - invMassD; + registry.fill(HIST("hMassLambdaDminus"), invMassReso, ptReso); + break; + default: + break; + } + } + // Filling Output table + if constexpr (channel == DecayChannel::DstarTrack) { + rowCandidateResoTrack(pVecD[0], pVecD[1], pVecD[2], + candV0Tr.px(), candV0Tr.py(), candV0Tr.pz(), + invMassReso, + invMassD - invMassD0); + } else { + rowCandidateReso(pVecD[0], pVecD[1], pVecD[2], + pVecV0Tr[0], pVecV0Tr[1], pVecV0Tr[2], + invMassReso, + invMassD, + invMassV0, + candV0Tr.cpa(), + candV0Tr.dca(), + candV0Tr.v0Radius(), + invMassD0); + rowCandidateResoIndices(collision.globalIndex(), + candD.globalIndex(), + candV0Tr.globalIndex()); + } + if constexpr (fillMl) { + mlScores(candD.mlScoreBkgMassHypo0(), candD.mlScorePromptMassHypo0(), candD.mlScoreNonpromptMassHypo0()); + } + } + } + } // main function + // Process data with Mixed Event + /// \tparam fillMl is a flag to Fill ML scores if present + /// \tparam channel is the decay channel of the Resonance + /// \param Coll is the reduced collisions table + /// \param DRedTable is the D bachelors table + /// \param V0TrRedTable is the V0/Track bachelors table + template + void runCandidateCreationMixedEvent(Coll const& collisions, + DRedTable const& candsD, + V0TrRedTable const& candsV0Tr) + { + using BinningType = ColumnBinningPolicy; + BinningType corrBinning{{zPoolBins, multPoolBins}, true}; + auto bachTuple = std::make_tuple(candsD, candsV0Tr); + Pair pairs{corrBinning, numberEventsMixed, numberEventsToSkip, collisions, bachTuple, &cache}; + for (const auto& [collision1, bachDs, collision2, bachV0Trs] : pairs) { + registry.fill(HIST("hNPvContCorr"), collision1.numContrib(), collision2.numContrib()); + registry.fill(HIST("hZvertCorr"), collision1.posZ(), collision2.posZ()); + for (const auto& [bachD, bachV0Tr] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(bachDs, bachV0Trs))) { + // Apply analysis selections on D and V0 bachelors + if (!isDSelected(bachD) || !isV0Selected(bachV0Tr, bachD)) { continue; } - if (activateQA && !alreadyCounted) { - registry.fill(HIST("hSelections"), 1 + Selections::V0Sel); - alreadyCounted = true; + // Retrieve D and V0 informations + float invMassD{0.}; + float invMassD0{0.}; + if (std::abs(bachD.dType()) == 1) + invMassD = bachD.invMassDplus(); + if (bachD.dType() == 2) { + invMassD = bachD.invMassDstar(); + invMassD0 = bachD.invMassD0(); + } + if (bachD.dType() == -2) { + invMassD = bachD.invMassAntiDstar(); + invMassD0 = bachD.invMassD0Bar(); } + std::array pVecD = {bachD.px(), bachD.py(), bachD.pz()}; float invMassReso{0.}; float invMassV0{0.}; - std::array pVecV0 = candV0.pVector(); - float ptV0 = RecoDecay::pt(pVecV0); - float ptReso = RecoDecay::pt(RecoDecay::sumOfVec(pVecV0, pVecD)); + std::array pVecV0Tr = {bachV0Tr.px(), bachV0Tr.py(), bachV0Tr.pz()}; + float ptReso = RecoDecay::pt(RecoDecay::sumOfVec(pVecV0Tr, pVecD)); switch (channel) { case DecayChannel::Ds1ToDstarK0s: - invMassV0 = candV0.invMassK0s(); - invMassReso = RecoDecay::m(std::array{pVecD, pVecV0}, std::array{massDstar, massK0}); + invMassV0 = bachV0Tr.invMassK0s(); + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassDStar, MassK0Short}); registry.fill(HIST("hMassDs1"), invMassReso, ptReso); break; case DecayChannel::Ds2StarToDplusK0s: - invMassV0 = candV0.invMassK0s(); - invMassReso = RecoDecay::m(std::array{pVecD, pVecV0}, std::array{massDplus, massK0}); + invMassV0 = bachV0Tr.invMassK0s(); + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassDPlus, MassK0Short}); registry.fill(HIST("hMassDs2Star"), invMassReso, ptReso); break; case DecayChannel::XcToDplusLambda: - if (candD.dType() > 0) { - invMassV0 = candV0.invMassLambda(); + if (bachD.dType() > 0) { + invMassV0 = bachV0Tr.invMassLambda(); } else { - invMassV0 = candV0.invMassAntiLambda(); + invMassV0 = bachV0Tr.invMassAntiLambda(); } - invMassReso = RecoDecay::m(std::array{pVecD, pVecV0}, std::array{massDplus, massLambda}); + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassDPlus, MassLambda}); registry.fill(HIST("hMassXcRes"), invMassReso, ptReso); break; case DecayChannel::LambdaDminus: - if (candD.dType() < 0) { - invMassV0 = candV0.invMassLambda(); + if (bachD.dType() < 0) { + invMassV0 = bachV0Tr.invMassLambda(); } else { - invMassV0 = candV0.invMassAntiLambda(); + invMassV0 = bachV0Tr.invMassAntiLambda(); } - invMassReso = RecoDecay::m(std::array{pVecD, pVecV0}, std::array{massDplus, massLambda}); + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassDPlus, MassLambda}); registry.fill(HIST("hMassLambdaDminus"), invMassReso, ptReso); break; default: break; } - // Filling Output table - rowCandidateReso(collisions.globalIndex(), + // Fill output table + rowCandidateReso(pVecD[0], pVecD[1], pVecD[2], + pVecV0Tr[0], pVecV0Tr[1], pVecV0Tr[2], invMassReso, - ptReso, invMassD, - ptD, invMassV0, - ptV0, - candV0.cpa(), - candV0.dca(), - candV0.radius()); + bachV0Tr.cpa(), + bachV0Tr.dca(), + bachV0Tr.v0Radius(), + invMassD0); + rowCandidateResoIndices(collision1.globalIndex(), + bachD.globalIndex(), + bachV0Tr.globalIndex()); if constexpr (fillMl) { - mlScores(candD.mlScoreBkgMassHypo0(), candD.mlScorePromptMassHypo0(), candD.mlScoreNonpromptMassHypo0()); + mlScores(bachD.mlScoreBkgMassHypo0(), bachD.mlScorePromptMassHypo0(), bachD.mlScoreNonpromptMassHypo0()); } } } - } // main function + } // runCandidateCreationMixedEvent - void processDs2StarToDplusK0s(aod::HfRedCollisions::iterator const& collision, + // List of Process Functions + void processDs2StarToDplusK0s(aod::HfRedCollisions const& collisions, aod::HfRed3PrNoTrks const& candsD, aod::HfRedVzeros const&) { - runCandidateCreation(collision, candsD, candidatesK0s); + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsD.sliceBy(candsDPerCollision, thisCollId); + auto k0sThisColl = candidatesK0s.sliceBy(candsV0PerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, k0sThisColl); + } } PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDs2StarToDplusK0s, "Process Ds2* candidates without ML info", true); - void processDs2StarToDplusK0sWithMl(aod::HfRedCollisions::iterator const& collision, + void processDs2StarToDplusK0sWithMl(aod::HfRedCollisions const& collisions, soa::Join const& candsD, aod::HfRedVzeros const&) { - runCandidateCreation(collision, candsD, candidatesK0s); + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsD.sliceBy(candsDPerCollisionWithMl, thisCollId); + auto k0sThisColl = candidatesK0s.sliceBy(candsV0PerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, k0sThisColl); + } } PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDs2StarToDplusK0sWithMl, "Process Ds2* candidates with Ml info", false); - void processDs1ToDstarK0s(aod::HfRedCollisions::iterator const& collision, + void processDs2StarToDplusK0sMixedEvent(aod::HfRedCollisions const& collisions, + aod::HfRed3PrNoTrks const& candsD, + aod::HfRedVzeros const& candsV0) + { + runCandidateCreationMixedEvent(collisions, candsD, candsV0); + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDs2StarToDplusK0sMixedEvent, "Process Ds2Star mixed Event without ML", false); + + void processDs2StarToDplusK0sMixedEventWithMl(aod::HfRedCollisions const& collisions, + HfRed3PrNoTrksWithMl const& candsD, + aod::HfRedVzeros const& candsV0) + { + runCandidateCreationMixedEvent(collisions, candsD, candsV0); + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDs2StarToDplusK0sMixedEventWithMl, "Process Ds2Star mixed Event with ML", false); + + void processDs1ToDstarK0s(aod::HfRedCollisions const& collisions, aod::HfRed3PrNoTrks const& candsD, aod::HfRedVzeros const&) { - runCandidateCreation(collision, candsD, candidatesK0s); + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsD.sliceBy(candsDPerCollision, thisCollId); + auto k0sThisColl = candidatesK0s.sliceBy(candsV0PerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, k0sThisColl); + } } PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDs1ToDstarK0s, "Process Ds1 candidates without Ml info", false); - void processDs1ToDstarK0sWithMl(aod::HfRedCollisions::iterator const& collision, - soa::Join const& candsD, + void processDs1ToDstarK0sWithMl(aod::HfRedCollisions const& collisions, + HfRed3PrNoTrksWithMl const& candsD, aod::HfRedVzeros const&) { - runCandidateCreation(collision, candsD, candidatesK0s); + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsD.sliceBy(candsDPerCollisionWithMl, thisCollId); + auto k0sThisColl = candidatesK0s.sliceBy(candsV0PerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, k0sThisColl); + } } PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDs1ToDstarK0sWithMl, "Process Ds1 candidates with Ml info", false); - void processXcToDplusLambda(aod::HfRedCollisions::iterator const& collision, + void processDs1ToDstarK0sMixedEvent(aod::HfRedCollisions const& collisions, + aod::HfRed3PrNoTrks const& candsD, + aod::HfRedVzeros const& candsV0) + { + runCandidateCreationMixedEvent(collisions, candsD, candsV0); + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDs1ToDstarK0sMixedEvent, "Process Ds1 mixed Event without ML", false); + + void processDs1ToDstarK0sMixedEventWithMl(aod::HfRedCollisions const& collisions, + HfRed3PrNoTrksWithMl const& candsD, + aod::HfRedVzeros const& candsV0) + { + runCandidateCreationMixedEvent(collisions, candsD, candsV0); + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDs1ToDstarK0sMixedEventWithMl, "Process Ds1 mixed Event with ML", false); + + void processXcToDplusLambda(aod::HfRedCollisions const& collisions, aod::HfRed3PrNoTrks const& candsD, aod::HfRedVzeros const&) { - runCandidateCreation(collision, candsD, candidatesLambda); + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsD.sliceBy(candsDPerCollision, thisCollId); + auto lambdaThisColl = candidatesLambda.sliceBy(candsV0PerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, lambdaThisColl); + } } PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processXcToDplusLambda, "Process Xc candidates without Ml info", false); - void processXcToDplusLambdaWithMl(aod::HfRedCollisions::iterator const& collision, - soa::Join const& candsD, + void processXcToDplusLambdaWithMl(aod::HfRedCollisions const& collisions, + HfRed3PrNoTrksWithMl const& candsD, aod::HfRedVzeros const&) { - runCandidateCreation(collision, candsD, candidatesLambda); + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsD.sliceBy(candsDPerCollisionWithMl, thisCollId); + auto lambdaThisColl = candidatesLambda.sliceBy(candsV0PerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, lambdaThisColl); + } } PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processXcToDplusLambdaWithMl, "Process Xc candidates with Ml info", false); - void processLambdaDminus(aod::HfRedCollisions::iterator const& collision, + void processLambdaDminus(aod::HfRedCollisions const& collisions, aod::HfRed3PrNoTrks const& candsD, aod::HfRedVzeros const&) { - runCandidateCreation(collision, candsD, candidatesLambda); + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsD.sliceBy(candsDPerCollision, thisCollId); + auto lambdaThisColl = candidatesLambda.sliceBy(candsV0PerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, lambdaThisColl); + } } PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processLambdaDminus, "Process LambdaDminus candidates without Ml info", false); - void processLambdaDminusWithMl(aod::HfRedCollisions::iterator const& collision, - soa::Join const& candsD, + void processLambdaDminusWithMl(aod::HfRedCollisions const& collisions, + HfRed3PrNoTrksWithMl const& candsD, aod::HfRedVzeros const&) { - runCandidateCreation(collision, candsD, candidatesLambda); + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsD.sliceBy(candsDPerCollisionWithMl, thisCollId); + auto lambdaThisColl = candidatesLambda.sliceBy(candsV0PerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, lambdaThisColl); + } } PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processLambdaDminusWithMl, "Process LambdaDminus candidates with Ml info", false); + void processDstarTrack(aod::HfRedCollisions const& collisions, + aod::HfRed3PrNoTrks const& candsD, + aod::HfRedTrkNoParams const& candidatesTrack) + { + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsD.sliceBy(candsDPerCollision, thisCollId); + auto trackThisColl = candidatesTrack.sliceBy(candsTrackPerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, trackThisColl); + } + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDstarTrack, "Process DStar candidates without Ml info", false); + + void processDstarTrackWithMl(aod::HfRedCollisions const& collisions, + HfRed3PrNoTrksWithMl const& candsD, + aod::HfRedTrkNoParams const& candidatesTrack) + { + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsD.sliceBy(candsDPerCollisionWithMl, thisCollId); + auto trackThisColl = candidatesTrack.sliceBy(candsTrackPerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, trackThisColl); + } + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDstarTrackWithMl, "Process DStar candidates with Ml info", false); + +}; // struct HfCandidateCreatorCharmResoReduced -}; // struct +struct HfCandidateCreatorCharmResoReducedExpressions { + + Produces rowResoMcRec; + + using CandResoWithIndices = soa::Join; + + // Configurable axis + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0., 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 8.f, 12.f, 24.f, 50.f}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis axisInvMassReso{"axisInvMassReso", {400, 0.49f, 0.89f}, "inv. mass (DV_{0}) (GeV/#it{c}^{2})"}; + ConfigurableAxis axisInvMassProng0{"axisInvMassProng0", {200, 0.14, 0.17}, "inv. mass (D) (GeV/#it{c}^{2})"}; + ConfigurableAxis axisInvMassProng1{"axisInvMassProng1", {200, 0.47, 0.53}, "inv. mass ({V}_{0}) (GeV/#it{c}^{2})"}; + ConfigurableAxis axisInvMassD0{"axisInvMassD0", {200, 1.65, 2.05}, "inv. mass ({V}_{0}) (GeV/#it{c}^{2})"}; + ConfigurableAxis axisDebug{"axisDebug", {16, -0.5, 15.5}, "MC debug flag"}; + ConfigurableAxis axisOrigin{"axisOrigin", {3, -0.5, 2.5}, "MC origin flag"}; + HistogramRegistry registry{"registry"}; + + void init(InitContext const&) + { + registry.add("hMassMcMatched", "Reso MC candidates Matched with generate particle;m (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisInvMassReso, axisPt}}); + registry.add("hMassMcMatchedIncomplete", "Reso MC candidates Matched with generate particle w. Invcomplete decay;m (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisInvMassReso, axisPt}}); + registry.add("hMassMcUnmatched", "Reso MC candidates NOT Matched with generate particle;m (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisInvMassReso, axisPt}}); + registry.add("hMassMcNoEntry", "Reso MC candidates w.o. entry in MC Reco table;m (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisInvMassReso, axisPt}}); + registry.add("hMassMcMatchedVsBach0Mass", "Reso MC candidates Matched with generate particle;m (GeV/#it{c}^{2}); m (GeV/#it{c}^{2})", {HistType::kTH2F, {axisInvMassReso, axisInvMassProng0}}); + registry.add("hMassMcUnmatchedVsBach0Mass", "Reso MC candidates Matched with generate particle w. Invcomplete decay;m (GeV/#it{c}^{2}); m (GeV/#it{c}^{2})", {HistType::kTH2F, {axisInvMassReso, axisInvMassProng0}}); + registry.add("hMassMcMatchedVsBach1Mass", "Reso MC candidates NOT Matched with generate particle;m (GeV/#it{c}^{2}); m (GeV/#it{c}^{2})", {HistType::kTH2F, {axisInvMassReso, axisInvMassProng1}}); + registry.add("hMassMcUnmatchedVsBach1Mass", "Reso MC candidates Matched with generate particle w. Invcomplete decay;m (GeV/#it{c}^{2}); m (GeV/#it{c}^{2})", {HistType::kTH2F, {axisInvMassReso, axisInvMassProng1}}); + registry.add("hMassMcMatchedVsD0Mass", "Reso MC candidates NOT Matched with generate particle;m (GeV/#it{c}^{2}); m (GeV/#it{c}^{2})", {HistType::kTH2F, {axisInvMassReso, axisInvMassD0}}); + registry.add("hMassMcUnmatchedVsD0Mass", "Reso MC candidates Matched with generate particle w. Invcomplete decay;m (GeV/#it{c}^{2}); m (GeV/#it{c}^{2})", {HistType::kTH2F, {axisInvMassReso, axisInvMassD0}}); + registry.add("hMassMcUnmatchedVsDebug", "Reso MC candidates NOT Matched with generate particle;m (GeV/#it{c}^{2});debug flag", {HistType::kTH2F, {axisInvMassReso, axisDebug}}); + registry.add("hSparseUnmatchedDebug", "THn for debug of MC matching and Correlated BKG study", HistType::kTHnSparseF, {axisInvMassReso, axisPt, axisInvMassProng0, axisInvMassProng1, axisInvMassD0, axisDebug, axisOrigin}); + } + + /// Fill candidate information at MC reconstruction level + /// \param rowsDV0McRec MC reco information on DPi pairs + /// \param candsReso prong global indices of B0 candidates + template + void fillResoMcRec(McRec const& rowsDV0McRec, CandResoWithIndices const& candsReso) + { + for (const auto& candReso : candsReso) { + bool filledMcInfo{false}; + for (const auto& rowDV0McRec : rowsDV0McRec) { + if ((rowDV0McRec.prong0Id() != candReso.prong0Id()) || (rowDV0McRec.prong1Id() != candReso.prong1Id())) { + continue; + } + rowResoMcRec(rowDV0McRec.flagMcMatchRec(), rowDV0McRec.debugMcRec(), rowDV0McRec.origin(), rowDV0McRec.ptMother()); + filledMcInfo = true; + if (std::abs(rowDV0McRec.flagMcMatchRec()) == DecayTypeMc::Ds1ToDStarK0ToD0PiK0s || std::abs(rowDV0McRec.flagMcMatchRec()) == DecayTypeMc::Ds2StarToDplusK0sToPiKaPiPiPi || + std::abs(rowDV0McRec.flagMcMatchRec()) == DecayTypeMc::Ds1ToDStarK0ToD0PiK0sOneMu || std::abs(rowDV0McRec.flagMcMatchRec()) == DecayTypeMc::Ds2StarToDplusK0sOneMu) { + registry.fill(HIST("hMassMcMatched"), candReso.invMass(), candReso.pt()); + registry.fill(HIST("hMassMcMatchedVsBach0Mass"), candReso.invMass(), candReso.invMassProng0() - candReso.invMassD0()); + registry.fill(HIST("hMassMcMatchedVsBach1Mass"), candReso.invMass(), candReso.invMassProng1()); + registry.fill(HIST("hMassMcMatchedVsD0Mass"), candReso.invMass(), candReso.invMassD0()); + + } else if (std::abs(rowDV0McRec.flagMcMatchRec()) == DecayTypeMc::Ds1ToDStarK0ToD0NoPiK0sPart || std::abs(rowDV0McRec.flagMcMatchRec()) == DecayTypeMc::Ds1ToDStarK0ToDPlusPi0K0s) { + registry.fill(HIST("hMassMcMatchedIncomplete"), candReso.invMass(), candReso.pt()); + } else { + registry.fill(HIST("hMassMcUnmatched"), candReso.invMass(), candReso.pt()); + registry.fill(HIST("hMassMcUnmatchedVsBach0Mass"), candReso.invMass(), candReso.invMassProng0() - candReso.invMassD0()); + registry.fill(HIST("hMassMcUnmatchedVsBach1Mass"), candReso.invMass(), candReso.invMassProng1()); + registry.fill(HIST("hMassMcUnmatchedVsD0Mass"), candReso.invMass(), candReso.invMassD0()); + registry.fill(HIST("hMassMcUnmatchedVsDebug"), candReso.invMass(), rowDV0McRec.debugMcRec()); + registry.fill(HIST("hSparseUnmatchedDebug"), candReso.invMass(), candReso.pt(), candReso.invMassProng0() - candReso.invMassD0(), candReso.invMassProng1(), candReso.invMassD0(), rowDV0McRec.debugMcRec(), rowDV0McRec.origin()); + } + + break; + } + if (!filledMcInfo) { // protection to get same size tables in case something went wrong: we created a candidate that was not preselected in the D-Pi creator + rowResoMcRec(0, -1, -1, -1.f); + registry.fill(HIST("hMassMcNoEntry"), candReso.invMass(), candReso.pt()); + } + } + } + + void processMc(aod::HfMcRecRedDV0s const& rowsDV0McRec, CandResoWithIndices const& candsReso) + { + fillResoMcRec(rowsDV0McRec, candsReso); + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReducedExpressions, processMc, "Process MC", false); + + void processDummy(CandResoWithIndices const&) {} + PROCESS_SWITCH(HfCandidateCreatorCharmResoReducedExpressions, processDummy, "Process dummy", true); +}; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; } diff --git a/PWGHF/D2H/TableProducer/candidateSelectorB0ToDPiReduced.cxx b/PWGHF/D2H/TableProducer/candidateSelectorB0ToDPiReduced.cxx index 3653471dbbf..2ad0f29869a 100644 --- a/PWGHF/D2H/TableProducer/candidateSelectorB0ToDPiReduced.cxx +++ b/PWGHF/D2H/TableProducer/candidateSelectorB0ToDPiReduced.cxx @@ -15,6 +15,9 @@ /// \author Alexandre Bigot , IPHC Strasbourg /// \author Fabrizio Grosa , CERN +#include +#include + #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -39,7 +42,7 @@ struct HfCandidateSelectorB0ToDPiReduced { Configurable ptCandMin{"ptCandMin", 0., "Lower bound of candidate pT"}; Configurable ptCandMax{"ptCandMax", 50., "Upper bound of candidate pT"}; // Enable PID - Configurable usePionPid{"usePionPid", 1, "Switch for PID selection for the bachelor pion (0: none, 1: TPC or TOF, 2: TPC and TOF)"}; + Configurable pionPidMethod{"pionPidMethod", 1, "PID selection method for the bachelor pion (0: none, 1: TPC or TOF, 2: TPC and TOF)"}; Configurable acceptPIDNotApplicable{"acceptPIDNotApplicable", true, "Switch to accept Status::NotApplicable [(NotApplicable for one detector) and (NotApplicable or Conditional for the other)] in PID selection"}; // TPC PID Configurable ptPidTpcMin{"ptPidTpcMin", 0.15, "Lower bound of track pT for TPC PID"}; @@ -53,18 +56,18 @@ struct HfCandidateSelectorB0ToDPiReduced { Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 5., "Nsigma cut on TOF combined with TPC"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_b0_to_d_pi::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_b0_to_d_pi::cuts[0], hf_cuts_b0_to_d_pi::nBinsPt, hf_cuts_b0_to_d_pi::nCutVars, hf_cuts_b0_to_d_pi::labelsPt, hf_cuts_b0_to_d_pi::labelsCutVar}, "B0 candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_b0_to_d_pi::Cuts[0], hf_cuts_b0_to_d_pi::NBinsPt, hf_cuts_b0_to_d_pi::NCutVars, hf_cuts_b0_to_d_pi::labelsPt, hf_cuts_b0_to_d_pi::labelsCutVar}, "B0 candidate selection per pT bin"}; // D-meson ML cuts Configurable> binsPtDmesMl{"binsPtDmesMl", std::vector{hf_cuts_ml::vecBinsPt}, "D-meson pT bin limits for ML cuts"}; - Configurable> cutsDmesMl{"cutsDmesMl", {hf_cuts_ml::cuts[0], hf_cuts_ml::nBinsPt, hf_cuts_ml::nCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsDmesCutScore}, "D-meson ML cuts per pT bin"}; + Configurable> cutsDmesMl{"cutsDmesMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsDmesCutScore}, "D-meson ML cuts per pT bin"}; // QA switch Configurable activateQA{"activateQA", false, "Flag to enable QA histogram"}; // B0 ML inference Configurable applyB0Ml{"applyB0Ml", false, "Flag to apply ML selections"}; Configurable> binsPtB0Ml{"binsPtB0Ml", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; Configurable> cutDirB0Ml{"cutDirB0Ml", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; - Configurable> cutsB0Ml{"cutsB0Ml", {hf_cuts_ml::cuts[0], hf_cuts_ml::nBinsPt, hf_cuts_ml::nCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; - Configurable nClassesB0Ml{"nClassesB0Ml", (int8_t)hf_cuts_ml::nCutScores, "Number of classes in ML model"}; + Configurable> cutsB0Ml{"cutsB0Ml", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable nClassesB0Ml{"nClassesB0Ml", static_cast(hf_cuts_ml::NCutScores), "Number of classes in ML model"}; Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; // CCDB configuration Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -94,11 +97,11 @@ struct HfCandidateSelectorB0ToDPiReduced { LOGP(fatal, "Only one process function for data should be enabled at a time."); } - if (usePionPid < 0 || usePionPid > 2) { + if (pionPidMethod < 0 || pionPidMethod > 2) { LOGP(fatal, "Invalid PID option in configurable, please set 0 (no PID), 1 (TPC or TOF), or 2 (TPC and TOF)"); } - if (usePionPid) { + if (pionPidMethod) { selectorPion.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); selectorPion.setRangeNSigmaTpc(-nSigmaTpcMax, nSigmaTpcMax); selectorPion.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedMax, nSigmaTpcCombinedMax); @@ -114,6 +117,7 @@ struct HfCandidateSelectorB0ToDPiReduced { labels[1 + SelectionStep::RecoSkims] = "Skims selection"; labels[1 + SelectionStep::RecoTopol] = "Skims & Topological selections"; labels[1 + SelectionStep::RecoPID] = "Skims & Topological & PID selections"; + labels[1 + aod::SelectionStep::RecoMl] = "ML selection"; static const AxisSpec axisSelections = {kNBinsSelections, 0.5, kNBinsSelections + 0.5, ""}; registry.add("hSelections", "Selections;;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisSelections, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); for (int iBin = 0; iBin < kNBinsSelections; ++iBin) { @@ -153,18 +157,6 @@ struct HfCandidateSelectorB0ToDPiReduced { int statusB0ToDPi = 0; auto ptCandB0 = hfCandB0.pt(); - // check if flagged as B0 → D π - if (!TESTBIT(hfCandB0.hfflag(), hf_cand_b0::DecayType::B0ToDPi)) { - hfSelB0ToDPiCandidate(statusB0ToDPi); - if (applyB0Ml) { - hfMlB0ToDPiCandidate(outputMlNotPreselected); - } - if (activateQA) { - registry.fill(HIST("hSelections"), 1, ptCandB0); - } - // LOGF(info, "B0 candidate selection failed at hfflag check"); - continue; - } SETBIT(statusB0ToDPi, SelectionStep::RecoSkims); // RecoSkims = 0 --> statusB0ToDPi = 1 if (activateQA) { registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoSkims, ptCandB0); @@ -181,7 +173,7 @@ struct HfCandidateSelectorB0ToDPiReduced { } if constexpr (withDmesMl) { // we include it in the topological selections - if (!hfHelper.selectionDmesMlScoresForB(hfCandB0, cutsDmesMl, binsPtDmesMl)) { + if (!hfHelper.selectionDmesMlScoresForBReduced(hfCandB0, cutsDmesMl, binsPtDmesMl)) { hfSelB0ToDPiCandidate(statusB0ToDPi); if (applyB0Ml) { hfMlB0ToDPiCandidate(outputMlNotPreselected); @@ -198,9 +190,9 @@ struct HfCandidateSelectorB0ToDPiReduced { // track-level PID selection auto trackPi = hfCandB0.template prong1_as(); - if (usePionPid) { + if (pionPidMethod) { int pidTrackPi{TrackSelectorPID::Status::NotApplicable}; - if (usePionPid == 1) { + if (pionPidMethod == 1) { pidTrackPi = selectorPion.statusTpcOrTof(trackPi); } else { pidTrackPi = selectorPion.statusTpcAndTof(trackPi); @@ -229,7 +221,7 @@ struct HfCandidateSelectorB0ToDPiReduced { hfSelB0ToDPiCandidate(statusB0ToDPi); continue; } - SETBIT(statusB0ToDPi, SelectionStep::RecoMl); // RecoML = 3 --> statusB0ToDPi = 15 if usePionPid, 11 otherwise + SETBIT(statusB0ToDPi, SelectionStep::RecoMl); // RecoML = 3 --> statusB0ToDPi = 15 if pionPidMethod, 11 otherwise if (activateQA) { registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoMl, ptCandB0); } diff --git a/PWGHF/D2H/TableProducer/candidateSelectorBplusToD0PiReduced.cxx b/PWGHF/D2H/TableProducer/candidateSelectorBplusToD0PiReduced.cxx index 32ce92edb07..09a9c39c933 100644 --- a/PWGHF/D2H/TableProducer/candidateSelectorBplusToD0PiReduced.cxx +++ b/PWGHF/D2H/TableProducer/candidateSelectorBplusToD0PiReduced.cxx @@ -14,12 +14,16 @@ /// /// \author Antonio Palasciano , Università degli Studi di Bari +#include +#include + #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "Common/Core/TrackSelectorPID.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/HfMlResponseBplusToD0PiReduced.h" #include "PWGHF/Core/SelectorCuts.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" @@ -32,11 +36,12 @@ using namespace o2::analysis; struct HfCandidateSelectorBplusToD0PiReduced { Produces hfSelBplusToD0PiCandidate; // table defined in CandidateSelectionTables.h + Produces hfMlBplusToD0PiCandidate; // table defined in CandidateSelectionTables.h Configurable ptCandMin{"ptCandMin", 0., "Lower bound of candidate pT"}; Configurable ptCandMax{"ptCandMax", 50., "Upper bound of candidate pT"}; // Enable PID - Configurable usePid{"usePid", true, "Switch for PID selection at track level"}; + Configurable pionPidMethod{"pionPidMethod", 1, "PID selection method for the bachelor pion (0: none, 1: TPC or TOF, 2: TPC and TOF)"}; Configurable acceptPIDNotApplicable{"acceptPIDNotApplicable", true, "Switch to accept Status::NotApplicable [(NotApplicable for one detector) and (NotApplicable or Conditional for the other)] in PID selection"}; // TPC PID Configurable ptPidTpcMin{"ptPidTpcMin", 0.15, "Lower bound of track pT for TPC PID"}; @@ -50,15 +55,34 @@ struct HfCandidateSelectorBplusToD0PiReduced { Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 5., "Nsigma cut on TOF combined with TPC"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_bplus_to_d0_pi::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_bplus_to_d0_pi::cuts[0], hf_cuts_bplus_to_d0_pi::nBinsPt, hf_cuts_bplus_to_d0_pi::nCutVars, hf_cuts_bplus_to_d0_pi::labelsPt, hf_cuts_bplus_to_d0_pi::labelsCutVar}, "B+ candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_bplus_to_d0_pi::Cuts[0], hf_cuts_bplus_to_d0_pi::NBinsPt, hf_cuts_bplus_to_d0_pi::NCutVars, hf_cuts_bplus_to_d0_pi::labelsPt, hf_cuts_bplus_to_d0_pi::labelsCutVar}, "B+ candidate selection per pT bin"}; + // D0-meson ML cuts + Configurable> binsPtDmesMl{"binsPtDmesMl", std::vector{hf_cuts_ml::vecBinsPt}, "D0-meson pT bin limits for ML cuts"}; + Configurable> cutsDmesMl{"cutsDmesMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsDmesCutScore}, "D0-meson ML cuts per pT bin"}; // QA switch Configurable activateQA{"activateQA", false, "Flag to enable QA histogram"}; - - bool selectionFlagDAndUsePidInSync = true; + // B+ ML inference + Configurable applyBplusMl{"applyBplusMl", false, "Flag to apply ML selections"}; + Configurable> binsPtBpMl{"binsPtBpMl", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; + Configurable> cutDirBpMl{"cutDirBpMl", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; + Configurable> cutsBpMl{"cutsBpMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable nClassesBpMl{"nClassesBpMl", static_cast(hf_cuts_ml::NCutScores), "Number of classes in ML model"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; + // CCDB configuration + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"path_ccdb/BDT_BPLUS/"}, "Paths of models on CCDB"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_BPLUSToD0Pi.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; // variable that will store the value of selectionFlagD (defined in dataCreatorD0PiReduced.cxx) int mySelectionFlagD0 = -1; int mySelectionFlagD0bar = -1; + o2::analysis::HfMlResponseBplusToD0PiReduced hfMlResponse; + float outputMlNotPreselected = -1.; + std::vector outputMl = {}; + o2::ccdb::CcdbApi ccdbApi; + HfHelper hfHelper; TrackSelectorPi selectorPion; @@ -68,7 +92,16 @@ struct HfCandidateSelectorBplusToD0PiReduced { void init(InitContext const&) { - if (usePid) { + std::array doprocess{doprocessSelection, doprocessSelectionWithDmesMl}; + if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { + LOGP(fatal, "Only one process function for data should be enabled at a time."); + } + + if (pionPidMethod < 0 || pionPidMethod > 2) { + LOGP(fatal, "Invalid PID option in configurable, please set 0 (no PID), 1 (TPC or TOF), or 2 (TPC and TOF)"); + } + + if (pionPidMethod) { selectorPion.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); selectorPion.setRangeNSigmaTpc(-nSigmaTpcMax, nSigmaTpcMax); selectorPion.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedMax, nSigmaTpcCombinedMax); @@ -84,46 +117,47 @@ struct HfCandidateSelectorBplusToD0PiReduced { labels[1 + SelectionStep::RecoSkims] = "Skims selection"; labels[1 + SelectionStep::RecoTopol] = "Skims & Topological selections"; labels[1 + SelectionStep::RecoPID] = "Skims & Topological & PID selections"; + labels[1 + aod::SelectionStep::RecoMl] = "ML selection"; static const AxisSpec axisSelections = {kNBinsSelections, 0.5, kNBinsSelections + 0.5, ""}; registry.add("hSelections", "Selections;;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisSelections, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); for (int iBin = 0; iBin < kNBinsSelections; ++iBin) { registry.get(HIST("hSelections"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); } } + + if (applyBplusMl) { + hfMlResponse.configure(binsPtBpMl, cutsBpMl, cutDirBpMl, nClassesBpMl); + if (loadModelsFromCCDB) { + ccdbApi.init(ccdbUrl); + hfMlResponse.setModelPathsCCDB(onnxFileNames, ccdbApi, modelPathsCCDB, timestampCCDB); + } else { + hfMlResponse.setModelPathsLocal(onnxFileNames); + } + hfMlResponse.cacheInputFeaturesIndices(namesInputFeatures); + hfMlResponse.init(); + } } - void process(HfRedCandBplus const& hfCandBs, - TracksPion const&, - HfCandBpConfigs const& configs) + /// Main function to perform B+ candidate creation + /// \param withDmesMl is the flag to use the table with ML scores for the D- daughter (only possible if present in the derived data) + /// \param hfCandsBp B+ candidates + /// \param pionTracks pion tracks + /// \param configs config inherited from the D0pi data creator + template + void runSelection(Cands const& hfCandsBp, + TracksPion const& /*pionTracks*/, + HfCandBpConfigs const& configs) { - // get DplusPi creator configurable + // get D0Pi creator configurable for (const auto& config : configs) { mySelectionFlagD0 = config.mySelectionFlagD0(); mySelectionFlagD0bar = config.mySelectionFlagD0bar(); - - if ((usePid && !mySelectionFlagD0) || (usePid && !mySelectionFlagD0bar)) { - selectionFlagDAndUsePidInSync = false; - LOG(warning) << "PID selections required on B+ daughters (usePid=true) but no PID selections on D candidates were required a priori."; - } - if ((!usePid && mySelectionFlagD0) || (!usePid && mySelectionFlagD0bar)) { - selectionFlagDAndUsePidInSync = false; - LOG(warning) << "No PID selections required on Bp daughters (usePid=false) but PID selections on D candidates were required a priori."; - } } - for (const auto& hfCandBp : hfCandBs) { + for (const auto& hfCandBp : hfCandsBp) { int statusBplus = 0; auto ptCandBplus = hfCandBp.pt(); - // check if flagged as B+ → D π - if (!TESTBIT(hfCandBp.hfflag(), hf_cand_bplus::DecayType::BplusToD0Pi)) { - hfSelBplusToD0PiCandidate(statusBplus); - if (activateQA) { - registry.fill(HIST("hSelections"), 1, ptCandBplus); - } - // LOGF(info, "B+ candidate selection failed at hfflag check"); - continue; - } SETBIT(statusBplus, SelectionStep::RecoSkims); // RecoSkims = 0 --> statusBplus = 1 if (activateQA) { registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoSkims, ptCandBplus); @@ -132,26 +166,44 @@ struct HfCandidateSelectorBplusToD0PiReduced { // topological cuts if (!hfHelper.selectionBplusToD0PiTopol(hfCandBp, cuts, binsPt)) { hfSelBplusToD0PiCandidate(statusBplus); + if (applyBplusMl) { + hfMlBplusToD0PiCandidate(outputMlNotPreselected); + } // LOGF(info, "B+ candidate selection failed at topology selection"); continue; } + + if constexpr (withDmesMl) { // we include it in the topological selections + if (!hfHelper.selectionDmesMlScoresForBReduced(hfCandBp, cutsDmesMl, binsPtDmesMl)) { + hfSelBplusToD0PiCandidate(statusBplus); + if (applyBplusMl) { + hfMlBplusToD0PiCandidate(outputMlNotPreselected); + } + // LOGF(info, "B+ candidate selection failed at D0-meson ML selection"); + continue; + } + } + SETBIT(statusBplus, SelectionStep::RecoTopol); // RecoTopol = 1 --> statusBplus = 3 if (activateQA) { registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoTopol, ptCandBplus); } - // checking if selectionFlagD and usePid are in sync - if (!selectionFlagDAndUsePidInSync) { - hfSelBplusToD0PiCandidate(statusBplus); - continue; - } // track-level PID selection - if (usePid) { - auto trackPi = hfCandBp.prong1_as(); - int pidTrackPi = selectorPion.statusTpcAndTof(trackPi); + auto trackPi = hfCandBp.template prong1_as(); + if (pionPidMethod) { + int pidTrackPi{TrackSelectorPID::Status::NotApplicable}; + if (pionPidMethod == 1) { + pidTrackPi = selectorPion.statusTpcOrTof(trackPi); + } else { + pidTrackPi = selectorPion.statusTpcAndTof(trackPi); + } if (!hfHelper.selectionBplusToD0PiPid(pidTrackPi, acceptPIDNotApplicable.value)) { // LOGF(info, "B+ candidate selection failed at PID selection"); hfSelBplusToD0PiCandidate(statusBplus); + if (applyBplusMl) { + hfMlBplusToD0PiCandidate(outputMlNotPreselected); + } continue; } SETBIT(statusBplus, SelectionStep::RecoPID); // RecoPID = 2 --> statusBplus = 7 @@ -159,10 +211,44 @@ struct HfCandidateSelectorBplusToD0PiReduced { registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoPID, ptCandBplus); } } + if (applyBplusMl) { + // B+ ML selections + std::vector inputFeatures = hfMlResponse.getInputFeatures(hfCandBp, trackPi); + bool isSelectedMl = hfMlResponse.isSelectedMl(inputFeatures, ptCandBplus, outputMl); + hfMlBplusToD0PiCandidate(outputMl[1]); // storing ML score for signal class + + if (!isSelectedMl) { + hfSelBplusToD0PiCandidate(statusBplus); + continue; + } + SETBIT(statusBplus, SelectionStep::RecoMl); // RecoML = 3 --> statusBplus = 15 if pionPidMethod, 11 otherwise + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoMl, ptCandBplus); + } + } + hfSelBplusToD0PiCandidate(statusBplus); // LOGF(info, "B+ candidate selection passed all selections"); } } + + void processSelection(HfRedCandBplus const& hfCandsBp, + TracksPion const& pionTracks, + HfCandBpConfigs const& configs) + { + runSelection(hfCandsBp, pionTracks, configs); + } // processSelection + + PROCESS_SWITCH(HfCandidateSelectorBplusToD0PiReduced, processSelection, "Process selection without ML scores of D mesons", true); + + void processSelectionWithDmesMl(soa::Join const& hfCandsBp, + TracksPion const& pionTracks, + HfCandBpConfigs const& configs) + { + runSelection(hfCandsBp, pionTracks, configs); + } // processSelectionWithDmesMl + + PROCESS_SWITCH(HfCandidateSelectorBplusToD0PiReduced, processSelectionWithDmesMl, "Process selection with ML scores of D mesons", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/D2H/TableProducer/candidateSelectorBsToDsPiReduced.cxx b/PWGHF/D2H/TableProducer/candidateSelectorBsToDsPiReduced.cxx new file mode 100644 index 00000000000..3e970cc347b --- /dev/null +++ b/PWGHF/D2H/TableProducer/candidateSelectorBsToDsPiReduced.cxx @@ -0,0 +1,245 @@ +// 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 candidateSelectorBsToDsPiReduced.cxx +/// \brief Bs → Ds- π+ candidate selector +/// +/// \author Fabio Catalano , CERN + +#include +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/TrackSelectorPID.h" + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/HfMlResponseBsToDsPi.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::analysis; + +struct HfCandidateSelectorBsToDsPiReduced { + Produces hfSelBsToDsPiCandidate; // table defined in CandidateSelectionTables.h + Produces hfMlBsToDsPiCandidate; // table defined in CandidateSelectionTables.h + + Configurable ptCandMin{"ptCandMin", 0., "Lower bound of candidate pT"}; + Configurable ptCandMax{"ptCandMax", 50., "Upper bound of candidate pT"}; + // Enable PID + Configurable pionPidMethod{"pionPidMethod", 1, "PID selection method for the bachelor pion (0: none, 1: TPC or TOF, 2: TPC and TOF)"}; + Configurable acceptPIDNotApplicable{"acceptPIDNotApplicable", true, "Switch to accept Status::NotApplicable [(NotApplicable for one detector) and (NotApplicable or Conditional for the other)] in PID selection"}; + // TPC PID + Configurable ptPidTpcMin{"ptPidTpcMin", 0.15, "Lower bound of track pT for TPC PID"}; + Configurable ptPidTpcMax{"ptPidTpcMax", 20., "Upper bound of track pT for TPC PID"}; + Configurable nSigmaTpcMax{"nSigmaTpcMax", 5., "Nsigma cut on TPC only"}; + Configurable nSigmaTpcCombinedMax{"nSigmaTpcCombinedMax", 5., "Nsigma cut on TPC combined with TOF"}; + // TOF PID + Configurable ptPidTofMin{"ptPidTofMin", 0.15, "Lower bound of track pT for TOF PID"}; + Configurable ptPidTofMax{"ptPidTofMax", 20., "Upper bound of track pT for TOF PID"}; + Configurable nSigmaTofMax{"nSigmaTofMax", 5., "Nsigma cut on TOF only"}; + Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 5., "Nsigma cut on TOF combined with TPC"}; + // topological cuts + Configurable> binsPt{"binsPt", std::vector{hf_cuts_bs_to_ds_pi::vecBinsPt}, "pT bin limits"}; + Configurable> cuts{"cuts", {hf_cuts_bs_to_ds_pi::Cuts[0], hf_cuts_bs_to_ds_pi::NBinsPt, hf_cuts_bs_to_ds_pi::NCutVars, hf_cuts_bs_to_ds_pi::labelsPt, hf_cuts_bs_to_ds_pi::labelsCutVar}, "Bs candidate selection per pT bin"}; + // D-meson ML cuts + Configurable> binsPtDmesMl{"binsPtDmesMl", std::vector{hf_cuts_ml::vecBinsPt}, "D-meson pT bin limits for ML cuts"}; + Configurable> cutsDmesMl{"cutsDmesMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsDmesCutScore}, "D-meson ML cuts per pT bin"}; + // QA switch + Configurable activateQA{"activateQA", false, "Flag to enable QA histogram"}; + // B0 ML inference + Configurable applyBsMl{"applyBsMl", false, "Flag to apply ML selections"}; + Configurable> binsPtBsMl{"binsPtBsMl", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; + Configurable> cutDirBsMl{"cutDirBsMl", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; + Configurable> cutsBsMl{"cutsBsMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable nClassesBsMl{"nClassesBsMl", static_cast(hf_cuts_ml::NCutScores), "Number of classes in ML model"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; + // CCDB configuration + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"path_ccdb/BDT_Bs/"}, "Paths of models on CCDB"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_BsToDsPi.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + + o2::analysis::HfMlResponseBsToDsPi hfMlResponse; + std::vector outputMl = {}; + o2::ccdb::CcdbApi ccdbApi; + + TrackSelectorPi selectorPion; + HfHelper hfHelper; + + using TracksPion = soa::Join; + + HistogramRegistry registry{"registry"}; + + void init(InitContext const&) + { + std::array doprocess{doprocessSelection, doprocessSelectionWithDmesMl}; + if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { + LOGP(fatal, "Only one process function for data should be enabled at a time."); + } + + if (pionPidMethod < 0 || pionPidMethod > 2) { + LOGP(fatal, "Invalid PID option in configurable, please set 0 (no PID), 1 (TPC or TOF), or 2 (TPC and TOF)"); + } + + if (pionPidMethod) { + selectorPion.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); + selectorPion.setRangeNSigmaTpc(-nSigmaTpcMax, nSigmaTpcMax); + selectorPion.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedMax, nSigmaTpcCombinedMax); + selectorPion.setRangePtTof(ptPidTofMin, ptPidTofMax); + selectorPion.setRangeNSigmaTof(-nSigmaTofMax, nSigmaTofMax); + selectorPion.setRangeNSigmaTofCondTpc(-nSigmaTofCombinedMax, nSigmaTofCombinedMax); + } + + if (activateQA) { + constexpr int kNBinsSelections = 1 + SelectionStep::NSelectionSteps; + std::string labels[kNBinsSelections]; + labels[0] = "No selection"; + labels[1 + SelectionStep::RecoSkims] = "Skims selection"; + labels[1 + SelectionStep::RecoTopol] = "Skims & Topological selections"; + labels[1 + SelectionStep::RecoPID] = "Skims & Topological & PID selections"; + labels[1 + aod::SelectionStep::RecoMl] = "ML selection"; + static const AxisSpec axisSelections = {kNBinsSelections, 0.5, kNBinsSelections + 0.5, ""}; + registry.add("hSelections", "Selections;;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisSelections, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + for (int iBin = 0; iBin < kNBinsSelections; ++iBin) { + registry.get(HIST("hSelections"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); + } + } + + if (applyBsMl) { + hfMlResponse.configure(binsPtBsMl, cutsBsMl, cutDirBsMl, nClassesBsMl); + if (loadModelsFromCCDB) { + ccdbApi.init(ccdbUrl); + hfMlResponse.setModelPathsCCDB(onnxFileNames, ccdbApi, modelPathsCCDB, timestampCCDB); + } else { + hfMlResponse.setModelPathsLocal(onnxFileNames); + } + hfMlResponse.cacheInputFeaturesIndices(namesInputFeatures); + hfMlResponse.init(); + } + } + + /// Main function to perform Bs candidate selection + /// \param withDmesMl is the flag to use the table with ML scores for the Ds- daughter (only possible if present in the derived data) + /// \param hfCandsBs Bs candidates + /// \param pionTracks pion tracks + /// \param configs config inherited from the charm-hadron data creator + template + void runSelection(Cands const& hfCandsBs, + TracksPion const&, + HfCandBsConfigs const&) + { + for (const auto& hfCandBs : hfCandsBs) { + int statusBsToDsPi = 0; + outputMl.clear(); + auto ptCandBs = hfCandBs.pt(); + + SETBIT(statusBsToDsPi, SelectionStep::RecoSkims); // RecoSkims = 0 --> statusBsToDsPi = 1 + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoSkims, ptCandBs); + } + + // topological cuts + if (!hfHelper.selectionBsToDsPiTopol(hfCandBs, cuts, binsPt)) { + hfSelBsToDsPiCandidate(statusBsToDsPi); + if (applyBsMl) { + hfMlBsToDsPiCandidate(outputMl); + } + continue; + } + + if constexpr (withDmesMl) { // we include it in the topological selections + if (!hfHelper.selectionDmesMlScoresForBReduced(hfCandBs, cutsDmesMl, binsPtDmesMl)) { + hfSelBsToDsPiCandidate(statusBsToDsPi); + if (applyBsMl) { + hfMlBsToDsPiCandidate(outputMl); + } + continue; + } + } + + SETBIT(statusBsToDsPi, SelectionStep::RecoTopol); // RecoTopol = 1 --> statusBsToDsPi = 3 + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoTopol, ptCandBs); + } + + // track-level PID selection + auto trackPi = hfCandBs.template prong1_as(); + if (pionPidMethod) { + int pidTrackPi{TrackSelectorPID::Status::NotApplicable}; + if (pionPidMethod == 1) { + pidTrackPi = selectorPion.statusTpcOrTof(trackPi); + } else { + pidTrackPi = selectorPion.statusTpcAndTof(trackPi); + } + if (!hfHelper.selectionBsToDsPiPid(pidTrackPi, acceptPIDNotApplicable.value)) { + hfSelBsToDsPiCandidate(statusBsToDsPi); + if (applyBsMl) { + hfMlBsToDsPiCandidate(outputMl); + } + continue; + } + SETBIT(statusBsToDsPi, SelectionStep::RecoPID); // RecoPID = 2 --> statusBsToDsPi = 7 + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoPID, ptCandBs); + } + } + + if (applyBsMl) { + // Bs ML selections + std::vector inputFeatures = hfMlResponse.getInputFeatures(hfCandBs, trackPi); + bool isSelectedMl = hfMlResponse.isSelectedMl(inputFeatures, ptCandBs, outputMl); + hfMlBsToDsPiCandidate(outputMl); + + if (!isSelectedMl) { + hfSelBsToDsPiCandidate(statusBsToDsPi); + continue; + } + SETBIT(statusBsToDsPi, SelectionStep::RecoMl); // RecoML = 3 --> statusBsToDsPi = 15 if pionPidMethod, 11 otherwise + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoMl, ptCandBs); + } + } + + hfSelBsToDsPiCandidate(statusBsToDsPi); + } + } + + void processSelection(HfRedCandBs const& hfCandsBs, + TracksPion const& pionTracks, + HfCandBsConfigs const& configs) + { + runSelection(hfCandsBs, pionTracks, configs); + } // processSelection + + PROCESS_SWITCH(HfCandidateSelectorBsToDsPiReduced, processSelection, "Process selection without ML scores of D mesons", true); + + void processSelectionWithDmesMl(soa::Join const& hfCandsBs, + TracksPion const& pionTracks, + HfCandBsConfigs const& configs) + { + runSelection(hfCandsBs, pionTracks, configs); + } // processSelectionWithDmesMl + + PROCESS_SWITCH(HfCandidateSelectorBsToDsPiReduced, processSelectionWithDmesMl, "Process selection with ML scores of D mesons", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/TableProducer/converterReduced3ProngsMl.cxx b/PWGHF/D2H/TableProducer/converterReduced3ProngsMl.cxx new file mode 100644 index 00000000000..ea9450eca08 --- /dev/null +++ b/PWGHF/D2H/TableProducer/converterReduced3ProngsMl.cxx @@ -0,0 +1,41 @@ +// 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 converterReduced3ProngsMl.cxx +/// \brief Task for conversion of HfRed3ProngsMl to version 001 +/// +/// \author Fabrizio Grosa , CERN + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" + +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" + +using namespace o2; +using namespace o2::framework; + +// Swaps covariance matrix elements if the data is known to be bogus (collision_000 is bogus) +struct HfConverterReduced3ProngsMl { + Produces ml3Prongs; + + void process(aod::HfRed3ProngsMl_000::iterator const& mlScoreTable) + { + ml3Prongs(mlScoreTable.mlScoreBkgMassHypo0(), mlScoreTable.mlScorePromptMassHypo0(), mlScoreTable.mlScoreNonpromptMassHypo0(), -1.f, -1.f, -1.f); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGHF/D2H/TableProducer/dataCreatorCharmHadPiReduced.cxx b/PWGHF/D2H/TableProducer/dataCreatorCharmHadPiReduced.cxx index b4b9f12eb23..869e037c788 100644 --- a/PWGHF/D2H/TableProducer/dataCreatorCharmHadPiReduced.cxx +++ b/PWGHF/D2H/TableProducer/dataCreatorCharmHadPiReduced.cxx @@ -15,8 +15,13 @@ /// \author Alexandre Bigot , IPHC Strasbourg /// \author Antonio Palasciano , Università degli Studi di Bari /// \author Fabrizio Grosa , CERN +/// \author Fabio Catalano , CERN +#include #include +#include +#include +#include #include "CommonConstants/PhysicsConstants.h" #include "DCAFitter/DCAFitterN.h" @@ -27,13 +32,17 @@ #include "Common/Core/trackUtilities.h" #include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Qvectors.h" #include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsEvSelHf.h" #include "PWGHF/D2H/DataModel/ReducedDataModel.h" #include "PWGHF/Utils/utilsTrkCandHf.h" +#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" using namespace o2; using namespace o2::analysis; @@ -53,6 +62,13 @@ enum Event : uint8_t { enum DecayChannel : uint8_t { B0ToDminusPi = 0, BplusToD0barPi, + BsToDsminusPi +}; + +enum WrongCollisionType : uint8_t { + None = 0, + WrongAssociation, + SplitCollision, }; /// Creation of CharmHad-Pi pairs for Beauty hadrons @@ -60,6 +76,8 @@ struct HfDataCreatorCharmHadPiReduced { // Produces AOD tables to store track information // collision related tables Produces hfReducedCollision; + Produces hfReducedCollCentrality; + Produces hfReducedQvector; Produces hfReducedCollExtra; Produces hfCollisionCounter; // Pi bachelor related tables @@ -73,6 +91,11 @@ struct HfDataCreatorCharmHadPiReduced { Produces hfCand3Prong; Produces hfCand3ProngCov; Produces hfCand3ProngMl; + // PID tables for charm-hadron candidate daughter tracks + Produces hfCandPidProng0; + Produces hfCandPidProng1; + Produces hfCandPidProng2; + // B-hadron config and MC related tables Produces rowCandidateConfigB0; Produces rowHfDPiMcRecReduced; @@ -81,8 +104,14 @@ struct HfDataCreatorCharmHadPiReduced { Produces rowCandidateConfigBplus; Produces rowHfD0PiMcRecReduced; + Produces rowHfD0PiMcCheckReduced; Produces rowHfBpMcGenReduced; + Produces rowCandidateConfigBs; + Produces rowHfDsPiMcRecReduced; + Produces rowHfDsPiMcCheckReduced; + Produces rowHfBsMcGenReduced; + // vertexing // Configurable bz{"bz", 5., "magnetic field"}; Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; @@ -95,10 +124,12 @@ struct HfDataCreatorCharmHadPiReduced { // selection Configurable usePionIsGlobalTrackWoDCA{"usePionIsGlobalTrackWoDCA", true, "check isGlobalTrackWoDCA status for pions, for Run3 studies"}; Configurable ptPionMin{"ptPionMin", 0.5, "minimum pion pT threshold (GeV/c)"}; + Configurable absEtaPionMax{"etaPionMax", 0.8, "maximum pion absolute eta threshold"}; Configurable> binsPtPion{"binsPtPion", std::vector{hf_cuts_single_track::vecBinsPtTrack}, "track pT bin limits for pion DCA XY pT-dependent cut"}; - Configurable> cutsTrackPionDCA{"cutsTrackPionDCA", {hf_cuts_single_track::cutsTrack[0], hf_cuts_single_track::nBinsPtTrack, hf_cuts_single_track::nCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for pions"}; + Configurable> cutsTrackPionDCA{"cutsTrackPionDCA", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for pions"}; Configurable invMassWindowCharmHadPi{"invMassWindowCharmHadPi", 0.3, "invariant-mass window for CharmHad-Pi pair preselections (GeV/c2)"}; Configurable selectionFlagDplus{"selectionFlagDplus", 7, "Selection Flag for D+"}; + Configurable selectionFlagDs{"selectionFlagDs", 7, "Selection Flag for Ds"}; Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection Flag for D0bar"}; @@ -110,6 +141,7 @@ struct HfDataCreatorCharmHadPiReduced { Configurable checkDecayTypeMc{"checkDecayTypeMc", false, "flag to enable MC checks on decay type"}; HfHelper hfHelper; + o2::hf_evsel::HfEventSelection hfEvSel; // CCDB service Service ccdb; @@ -132,30 +164,45 @@ struct HfDataCreatorCharmHadPiReduced { o2::vertexing::DCAFitterN<3> df3; o2::vertexing::DCAFitterN<2> df2; - using TracksPidPi = soa::Join; - using TracksPidWithSel = soa::Join; + using TracksPid = soa::Join; // TODO: revert to pion only once the Nsigma variables for the charm-hadron candidate daughters are in the candidate table for 3 prongs too + using TracksPidWithSel = soa::Join; using TracksPidWithSelAndMc = soa::Join; using CandsDplusFiltered = soa::Filtered>; using CandsDplusFilteredWithMl = soa::Filtered>; - using CandsD0Filtered = soa::Filtered>; - using CandsD0FilteredWithMl = soa::Filtered>; + using CandsDsFiltered = soa::Filtered>; + using CandsDsFilteredWithMl = soa::Filtered>; + using CandsD0Filtered = soa::Filtered>; + using CandsD0FilteredWithMl = soa::Filtered>; + + using CollisionsWCent = soa::Join; + using CollisionsWCentAndMcLabels = soa::Join; + using CollisionsWCentAndQvectors = soa::Join; Filter filterSelectDplusCandidates = (aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus); + Filter filterSelectDsCandidates = (aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlagDs || aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlagDs); Filter filterSelectDzeroCandidates = (aod::hf_sel_candidate_d0::isSelD0 >= selectionFlagD0 || aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlagD0bar); Preslice candsDplusPerCollision = aod::track_association::collisionId; Preslice candsDplusPerCollisionWithMl = aod::track_association::collisionId; + Preslice candsDsPerCollision = aod::track_association::collisionId; + Preslice candsDsPerCollisionWithMl = aod::track_association::collisionId; Preslice candsD0PerCollision = aod::track_association::collisionId; Preslice candsD0PerCollisionWithMl = aod::track_association::collisionId; Preslice trackIndicesPerCollision = aod::track_association::collisionId; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; - std::shared_ptr hCandidatesD0, hCandidatesDPlus; + std::shared_ptr hCandidatesD0, hCandidatesDPlus, hCandidatesDs; HistogramRegistry registry{"registry"}; + std::array arrPDGResonantDsPhiPi = {kPhi, kPiPlus}; // Ds± → Phi π± + std::array arrPDGResonantDKstarK = {kK0Star892, kKPlus}; // Ds± → K*(892)0bar K± and D± → K*(892)0bar K± + void init(InitContext const&) { - std::array doProcess = {doprocessDplusPiData, doprocessDplusPiDataWithMl, doprocessDplusPiMc, doprocessDplusPiMcWithMl, doprocessD0PiData, doprocessD0PiDataWithMl, doprocessD0PiMc, doprocessD0PiMcWithMl}; + std::array doProcess = {doprocessDplusPiData, doprocessDplusPiDataWithMl, doprocessDplusPiMc, doprocessDplusPiMcWithMl, + doprocessDsPiData, doprocessDsPiDataWithMl, doprocessDsPiMc, doprocessDsPiMcWithMl, + doprocessD0PiData, doprocessD0PiDataWithMl, doprocessD0PiMc, doprocessD0PiMcWithMl}; if (std::accumulate(doProcess.begin(), doProcess.end(), 0) != 1) { LOGP(fatal, "One and only one process function can be enabled at a time, please fix your configuration!"); } @@ -165,6 +212,9 @@ struct HfDataCreatorCharmHadPiReduced { if (doprocessDplusPiData || doprocessDplusPiDataWithMl || doprocessDplusPiMc || doprocessDplusPiMcWithMl) { massC = MassDMinus; massB = MassB0; + } else if (doprocessDsPiData || doprocessDsPiDataWithMl || doprocessDsPiMc || doprocessDsPiMcWithMl) { + massC = MassDS; + massB = MassBS; } else if (doprocessD0PiData || doprocessD0PiDataWithMl || doprocessD0PiMc || doprocessD0PiMcWithMl) { massC = MassD0; massB = MassBPlus; @@ -173,7 +223,8 @@ struct HfDataCreatorCharmHadPiReduced { invMass2ChHadPiMax = (massB + invMassWindowCharmHadPi) * (massB + invMassWindowCharmHadPi); // Initialize fitter - if (doprocessDplusPiData || doprocessDplusPiDataWithMl || doprocessDplusPiMc || doprocessDplusPiMcWithMl) { + if (doprocessDplusPiData || doprocessDplusPiDataWithMl || doprocessDplusPiMc || doprocessDplusPiMcWithMl || + doprocessDsPiData || doprocessDsPiDataWithMl || doprocessDsPiMc || doprocessDsPiMcWithMl) { df3.setPropagateToPCA(propagateToPCA); df3.setMaxR(maxR); df3.setMaxDZIni(maxDZIni); @@ -211,36 +262,35 @@ struct HfDataCreatorCharmHadPiReduced { registry.get(HIST("hEvents"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); } - std::string charmHadInvMassTitle = ""; - std::string charmHadTitle0 = ""; - std::string charmHadTitle1 = ""; - std::string histMassTitle0 = ""; - std::string histMassTitle1 = ""; + std::string charmHadTitle = ""; + std::string histMassTitle = ""; if (doprocessDplusPiData || doprocessDplusPiDataWithMl || doprocessDplusPiMc || doprocessDplusPiMcWithMl) { - charmHadTitle0 = "D^{#plus}"; - histMassTitle0 = "Dplus"; - charmHadInvMassTitle = "#it{M}(K#pi#pi)"; + charmHadTitle = "D^{#plus}"; + histMassTitle = "Dplus"; + registry.add("hMassDplus", "D^{#plus} candidates; #it{M}(K#pi#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0., 5.}}}); + } else if (doprocessDsPiData || doprocessDsPiDataWithMl || doprocessDsPiMc || doprocessDsPiMcWithMl) { + charmHadTitle = "D_{s}^{#plus}"; + histMassTitle = "Ds"; + registry.add("hMassDsToKKPi", "D_{s}^{#plus} to KKpi candidates; #it{M}(KK#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0., 5.}}}); + registry.add("hMassDsToPiKK", "D_{s}^{#plus} to piKK candidates; #it{M}(KK#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0., 5.}}}); } else if (doprocessD0PiData || doprocessD0PiDataWithMl || doprocessD0PiMc || doprocessD0PiMcWithMl) { - charmHadTitle0 = "D^{0}"; - charmHadTitle1 = "#overline{D}^{0}"; - histMassTitle0 = "D0"; - histMassTitle1 = "D0bar"; - charmHadInvMassTitle = "#it{M}(K#pi)"; + charmHadTitle = "D^{0}"; + histMassTitle = "D0"; + registry.add("hMassD0", "D^{0} candidates; #it{M}(K#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0., 5.}}}); + registry.add("hMassD0bar", "#overline{D}^{0} candidates; #it{M}(K#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0., 5.}}}); } - registry.add(Form("hMass%s", histMassTitle0.data()), Form("%s candidates; %s (GeV/#it{c}^{2});entries", charmHadTitle0.data(), charmHadInvMassTitle.data()), {HistType::kTH1F, {{500, 0., 5.}}}); - if (doprocessD0PiData || doprocessD0PiDataWithMl || doprocessD0PiMc || doprocessD0PiMcWithMl) { - registry.add(Form("hMass%s", histMassTitle1.data()), Form("%s candidates; %s (GeV/#it{c}^{2});entries", charmHadTitle1.data(), charmHadInvMassTitle.data()), {HistType::kTH1F, {{500, 0., 5.}}}); - } - registry.add(Form("hPt%s", histMassTitle0.data()), Form("%s candidates candidates;%s candidate #it{p}_{T} (GeV/#it{c});entries", charmHadTitle0.data(), charmHadTitle0.data()), {HistType::kTH1F, {{100, 0., 10.}}}); + registry.add(Form("hPt%s", histMassTitle.data()), Form("%s candidates candidates;%s candidate #it{p}_{T} (GeV/#it{c});entries", charmHadTitle.data(), charmHadTitle.data()), {HistType::kTH1F, {{100, 0., 10.}}}); registry.add("hPtPion", "#pi^{#plus} candidates;#pi^{#plus} candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 10.}}}); - registry.add(Form("hCpa%s", histMassTitle0.data()), Form("%s candidates;%s cosine of pointing angle;entries", charmHadTitle0.data(), charmHadTitle0.data()), {HistType::kTH1F, {{110, -1.1, 1.1}}}); + registry.add(Form("hCpa%s", histMassTitle.data()), Form("%s candidates;%s cosine of pointing angle;entries", charmHadTitle.data(), charmHadTitle.data()), {HistType::kTH1F, {{110, -1.1, 1.1}}}); /// candidate monitoring - hCandidatesD0 = registry.add("hCandidatesD0", "D candidate counter", {HistType::kTH1D, {axisCands}}); - hCandidatesDPlus = registry.add("hCandidatesDPlus", "B candidate counter", {HistType::kTH1D, {axisCands}}); + hCandidatesD0 = registry.add("hCandidatesD0", "D0 candidate counter", {HistType::kTH1D, {axisCands}}); + hCandidatesDPlus = registry.add("hCandidatesDPlus", "Dplus candidate counter", {HistType::kTH1D, {axisCands}}); + hCandidatesDs = registry.add("hCandidatesDs", "Ds candidate counter", {HistType::kTH1D, {axisCands}}); setLabelHistoCands(hCandidatesD0); setLabelHistoCands(hCandidatesDPlus); + setLabelHistoCands(hCandidatesDs); } /// Pion selection (D Pi <-- B0) @@ -256,8 +306,8 @@ struct HfDataCreatorCharmHadPiReduced { if (usePionIsGlobalTrackWoDCA && !trackPion.isGlobalTrackWoDCA()) { return false; } - // minimum pT selection - if (trackParCovPion.getPt() < ptPionMin || !isSelectedTrackDCA(trackParCovPion, dcaPion)) { + // minimum pT and eta selection + if (trackParCovPion.getPt() < ptPionMin || std::abs(trackParCovPion.getEta()) > absEtaPionMax || !isSelectedTrackDCA(trackParCovPion, dcaPion)) { return false; } // reject pions that are charm-hadron daughters @@ -291,21 +341,62 @@ struct HfDataCreatorCharmHadPiReduced { return true; } + /// Calculates the index of the collision with the maximum number of contributions. + ///\param collisions are the collisions to search through. + ///\return The index of the collision with the maximum number of contributions. + template + int64_t getIndexCollisionMaxNumContrib(const CColl& collisions) + { + unsigned maxNumContrib = 0; + int64_t indexCollisionMaxNumContrib = -1; + for (const auto& collision : collisions) { + if (collision.numContrib() > maxNumContrib) { + maxNumContrib = collision.numContrib(); + indexCollisionMaxNumContrib = collision.globalIndex(); + } + } + return indexCollisionMaxNumContrib; + } + + /// Checks if the B meson is associated with a different collision than the one it was generated in + /// \param particleMother is the mother particle + /// \param collision is the reconstructed collision + /// \param indexCollisionMaxNumContrib is the index of the collision associated with a given MC collision with the largest number of contributors. + /// \param flagWrongCollision is the flag indicating if whether the associated collision is incorrect. + template + void checkWrongCollision(const PParticle& particleMother, + const CColl& collision, + const int64_t& indexCollisionMaxNumContrib, + int8_t& flagWrongCollision) + { + + if (particleMother.mcCollision().globalIndex() != collision.mcCollisionId()) { + flagWrongCollision = WrongCollisionType::WrongAssociation; + } else { + if (collision.globalIndex() != indexCollisionMaxNumContrib) { + flagWrongCollision = WrongCollisionType::SplitCollision; + } + } + } + /// Function for filling MC reco information in the tables /// \param particlesMc is the table with MC particles /// \param vecDaughtersB is the vector with all daughter tracks (bachelor pion in last position) /// \param indexHfCandCharm is the index of the charm-hadron candidate /// \param selectedTracksPion is the map with the indices of selected bachelor pion tracks - template - void fillMcRecoInfo(const PParticles& particlesMc, + template + void fillMcRecoInfo(const CColl& collision, + const PParticles& particlesMc, const std::vector& vecDaughtersB, int& indexHfCandCharm, - std::map selectedTracksPion) + std::map selectedTracksPion, + const int64_t indexCollisionMaxNumContrib) { // we check the MC matching to be stored int8_t sign{0}; int8_t flag{0}; + int8_t flagWrongCollision{WrongCollisionType::None}; int8_t debug{0}; int pdgCodeBeautyMother{-1}; int pdgCodeCharmMother{-1}; @@ -317,11 +408,11 @@ struct HfDataCreatorCharmHadPiReduced { if constexpr (decChannel == DecayChannel::B0ToDminusPi) { // B0 → D- π+ → (π- K+ π-) π+ - auto indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2], vecDaughtersB[3]}, Pdg::kB0, std::array{-kPiPlus, +kKPlus, -kPiPlus, +kPiPlus}, true, &sign, 3); + auto indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2], vecDaughtersB[3]}, Pdg::kB0, std::array{-kPiPlus, +kKPlus, -kPiPlus, +kPiPlus}, true, &sign, 3); if (indexRec > -1) { // D- → π- K+ π- // Printf("Checking D- → π- K+ π-"); - indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2]}, Pdg::kDMinus, std::array{-kPiPlus, +kKPlus, -kPiPlus}, true, &sign, 2); + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2]}, Pdg::kDMinus, std::array{-kPiPlus, +kKPlus, -kPiPlus}, true, &sign, 2); if (indexRec > -1) { flag = sign * BIT(hf_cand_b0::DecayTypeMc::B0ToDplusPiToPiKPiPi); } else { @@ -333,6 +424,7 @@ struct HfDataCreatorCharmHadPiReduced { if (indexMother >= 0) { auto particleMother = particlesMc.rawIteratorAt(indexMother); motherPt = particleMother.pt(); + checkWrongCollision(particleMother, collision, indexCollisionMaxNumContrib, flagWrongCollision); } } @@ -340,15 +432,26 @@ struct HfDataCreatorCharmHadPiReduced { if (checkDecayTypeMc) { // B0 → Ds- π+ → (K- K+ π-) π+ if (!flag) { - indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2], vecDaughtersB[3]}, Pdg::kB0, std::array{-kKPlus, +kKPlus, -kPiPlus, +kPiPlus}, true, &sign, 3); + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2], vecDaughtersB[3]}, Pdg::kB0, std::array{-kKPlus, +kKPlus, -kPiPlus, +kPiPlus}, true, &sign, 3); if (indexRec > -1) { // Ds- → K- K+ π- - indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2]}, -Pdg::kDS, std::array{-kKPlus, +kKPlus, -kPiPlus}, true, &sign, 2); + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2]}, -Pdg::kDS, std::array{-kKPlus, +kKPlus, -kPiPlus}, true, &sign, 2); if (indexRec > -1) { flag = sign * BIT(hf_cand_b0::DecayTypeMc::B0ToDsPiToKKPiPi); } } } + // Bs → Ds- π+ → (K- K+ π-) π+ + if (!flag) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2], vecDaughtersB[3]}, Pdg::kBS, std::array{-kKPlus, +kKPlus, -kPiPlus, +kPiPlus}, true, &sign, 3); + if (indexRec > -1) { + // Ds- → K- K+ π- + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2]}, -Pdg::kDS, std::array{-kKPlus, +kKPlus, -kPiPlus}, true, &sign, 2); + if (indexRec > -1) { + flag = sign * BIT(hf_cand_b0::DecayTypeMc::BsToDsPiToKKPiPi); + } + } + } // Partly reconstructed decays, i.e. the 4 prongs have a common b-hadron ancestor // convention: final state particles are prong0,1,2,3 if (!flag) { @@ -359,7 +462,7 @@ struct HfDataCreatorCharmHadPiReduced { // b-hadron hypothesis std::array bHadronMotherHypos = {Pdg::kB0, Pdg::kBS, Pdg::kLambdaB0}; // c-hadron hypothesis - std::array cHadronMotherHypos = {Pdg::kDPlus, Pdg::kDS, Pdg::kDStar}; + std::array cHadronMotherHypos = {Pdg::kDPlus, Pdg::kDS, Pdg::kDStar, Pdg::kLambdaCPlus}; for (const auto& bHadronMotherHypo : bHadronMotherHypos) { int index0Mother = RecoDecay::getMother(particlesMc, particleProng0, bHadronMotherHypo, true); @@ -393,6 +496,7 @@ struct HfDataCreatorCharmHadPiReduced { // Pdg::kDPlus + Pdg::kDStar (if D+ is the mother and D*+ -> D+ π0/γ) // Pdg::kDStar (if D*+ is the mother and D*+ -> D0 π+) // Pdg::kDS (if Ds is the mother) + // Pdg::kLambdaCPlus (if Λc+ is the mother) pdgCodeCharmMother += std::abs(particlesMc.rawIteratorAt(index0CharmMother).pdgCode()); } } @@ -404,37 +508,213 @@ struct HfDataCreatorCharmHadPiReduced { } rowHfDPiMcCheckReduced(pdgCodeBeautyMother, pdgCodeCharmMother, pdgCodeProng0, pdgCodeProng1, pdgCodeProng2, pdgCodeProng3); } - rowHfDPiMcRecReduced(indexHfCandCharm, selectedTracksPion[vecDaughtersB.back().globalIndex()], flag, debug, motherPt); + rowHfDPiMcRecReduced(indexHfCandCharm, selectedTracksPion[vecDaughtersB.back().globalIndex()], flag, flagWrongCollision, debug, motherPt); + } else if constexpr (decChannel == DecayChannel::BsToDsminusPi) { + // Bs → Ds- π+ → (K- K+ π-) π+ + auto indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2], vecDaughtersB[3]}, Pdg::kBS, std::array{-kKPlus, +kKPlus, -kPiPlus, +kPiPlus}, true, &sign, 3); + if (indexRec > -1) { + // Ds- → K- K+ π- + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2]}, -Pdg::kDS, std::array{-kKPlus, +kKPlus, -kPiPlus}, true, &sign, 2); + if (indexRec > -1) { + std::vector arrDaughDsIndex; + std::array arrPDGDaughDs; + RecoDecay::getDaughters(particlesMc.rawIteratorAt(indexRec), &arrDaughDsIndex, std::array{0}, 1); + if (arrDaughDsIndex.size() == 2) { + for (auto iProng = 0u; iProng < arrDaughDsIndex.size(); ++iProng) { + auto daughI = particlesMc.rawIteratorAt(arrDaughDsIndex[iProng]); + arrPDGDaughDs[iProng] = std::abs(daughI.pdgCode()); + } + // Ds- → Phi π- → K- K+ π- and Ds- → K0* K- → K- K+ π- + if ((arrPDGDaughDs[0] == arrPDGResonantDsPhiPi[0] && arrPDGDaughDs[1] == arrPDGResonantDsPhiPi[1]) || (arrPDGDaughDs[0] == arrPDGResonantDsPhiPi[1] && arrPDGDaughDs[1] == arrPDGResonantDsPhiPi[0])) { + flag = sign * BIT(hf_cand_bs::DecayTypeMc::BsToDsPiToPhiPiPiToKKPiPi); + } else if ((arrPDGDaughDs[0] == arrPDGResonantDKstarK[0] && arrPDGDaughDs[1] == arrPDGResonantDKstarK[1]) || (arrPDGDaughDs[0] == arrPDGResonantDKstarK[1] && arrPDGDaughDs[1] == arrPDGResonantDKstarK[0])) { + flag = sign * BIT(hf_cand_bs::DecayTypeMc::BsToDsPiToK0starKPiToKKPiPi); + } + } + } else { + debug = 1; + LOGF(debug, "Bs decays in the expected final state but the condition on the intermediate state is not fulfilled"); + } + + auto indexMother = RecoDecay::getMother(particlesMc, vecDaughtersB.back().template mcParticle_as(), Pdg::kBS, true); + if (indexMother >= 0) { + auto particleMother = particlesMc.rawIteratorAt(indexMother); + motherPt = particleMother.pt(); + checkWrongCollision(particleMother, collision, indexCollisionMaxNumContrib, flagWrongCollision); + } + } + + // additional checks for correlated backgrounds + if (checkDecayTypeMc) { + // B0 → Ds- π+ → (K- K+ π-) π+ + if (!flag) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2], vecDaughtersB[3]}, Pdg::kB0, std::array{-kKPlus, +kKPlus, -kPiPlus, +kPiPlus}, true, &sign, 3); + if (indexRec > -1) { + // Ds- → K- K+ π- + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2]}, -Pdg::kDS, std::array{-kKPlus, +kKPlus, -kPiPlus}, true, &sign, 2); + if (indexRec > -1) { + std::vector arrDaughDsIndex; + std::array arrPDGDaughDs; + RecoDecay::getDaughters(particlesMc.rawIteratorAt(indexRec), &arrDaughDsIndex, std::array{0}, 1); + if (arrDaughDsIndex.size() == 2) { + for (auto iProng = 0u; iProng < arrDaughDsIndex.size(); ++iProng) { + auto daughI = particlesMc.rawIteratorAt(arrDaughDsIndex[iProng]); + arrPDGDaughDs[iProng] = std::abs(daughI.pdgCode()); + } + // Ds- → Phi π- → K- K+ π- and Ds- → K0* K- → K- K+ π- + if ((arrPDGDaughDs[0] == arrPDGResonantDsPhiPi[0] && arrPDGDaughDs[1] == arrPDGResonantDsPhiPi[1]) || (arrPDGDaughDs[0] == arrPDGResonantDsPhiPi[1] && arrPDGDaughDs[1] == arrPDGResonantDsPhiPi[0])) { + flag = sign * BIT(hf_cand_bs::DecayTypeMc::B0ToDsPiToPhiPiPiToKKPiPi); + } else if ((arrPDGDaughDs[0] == arrPDGResonantDKstarK[0] && arrPDGDaughDs[1] == arrPDGResonantDKstarK[1]) || (arrPDGDaughDs[0] == arrPDGResonantDKstarK[1] && arrPDGDaughDs[1] == arrPDGResonantDKstarK[0])) { + flag = sign * BIT(hf_cand_bs::DecayTypeMc::B0ToDsPiToK0starKPiToKKPiPi); + } + } + } + } + } + // Partly reconstructed decays, i.e. the 4 prongs have a common b-hadron ancestor + // convention: final state particles are prong0,1,2,3 + if (!flag) { + auto particleProng0 = vecDaughtersB[0].mcParticle(); + auto particleProng1 = vecDaughtersB[1].mcParticle(); + auto particleProng2 = vecDaughtersB[2].mcParticle(); + auto particleProng3 = vecDaughtersB[3].mcParticle(); + // b-hadron hypothesis + std::array bHadronMotherHypos = {Pdg::kB0, Pdg::kBS, Pdg::kLambdaB0}; + // c-hadron hypothesis + std::array cHadronMotherHypos = {Pdg::kDPlus, Pdg::kDS, Pdg::kDStar, Pdg::kDSStar, Pdg::kLambdaCPlus}; + + for (const auto& bHadronMotherHypo : bHadronMotherHypos) { + int index0Mother = RecoDecay::getMother(particlesMc, particleProng0, bHadronMotherHypo, true); + int index1Mother = RecoDecay::getMother(particlesMc, particleProng1, bHadronMotherHypo, true); + int index2Mother = RecoDecay::getMother(particlesMc, particleProng2, bHadronMotherHypo, true); + int index3Mother = RecoDecay::getMother(particlesMc, particleProng3, bHadronMotherHypo, true); + + // look for common b-hadron ancestor + if (index0Mother > -1 && index1Mother > -1 && index2Mother > -1 && index3Mother > -1) { + if (index0Mother == index1Mother && index1Mother == index2Mother && index2Mother == index3Mother) { + flag = BIT(hf_cand_bs::DecayTypeMc::PartlyRecoDecay); + pdgCodeBeautyMother = particlesMc.rawIteratorAt(index0Mother).pdgCode(); + pdgCodeCharmMother = 0; + pdgCodeProng0 = particleProng0.pdgCode(); + pdgCodeProng1 = particleProng1.pdgCode(); + pdgCodeProng2 = particleProng2.pdgCode(); + pdgCodeProng3 = particleProng3.pdgCode(); + // look for common c-hadron mother among prongs 0, 1 and 2 + for (const auto& cHadronMotherHypo : cHadronMotherHypos) { + int8_t depthMax = 2; + if (cHadronMotherHypo == Pdg::kDStar || cHadronMotherHypo == Pdg::kDSStar) { // to include D* -> D π0/γ, D* -> D0 π, and Ds* -> Ds π0/γ + depthMax += 1; + } + int index0CharmMother = RecoDecay::getMother(particlesMc, particleProng0, cHadronMotherHypo, true, &sign, depthMax); + int index1CharmMother = RecoDecay::getMother(particlesMc, particleProng1, cHadronMotherHypo, true, &sign, depthMax); + int index2CharmMother = RecoDecay::getMother(particlesMc, particleProng2, cHadronMotherHypo, true, &sign, depthMax); + if (index0CharmMother > -1 && index1CharmMother > -1 && index2CharmMother > -1) { + if (index0CharmMother == index1CharmMother && index1CharmMother == index2CharmMother) { + // pdgCodeCharmMother = + // Pdg::kDPlus (if D+ is the mother and does not come from D*+) + // Pdg::kDPlus + Pdg::kDStar (if D+ is the mother and D*+ -> D+ π0/γ) + // Pdg::kDStar (if D*+ is the mother and D*+ -> D0 π+) + // Pdg::kDS (if Ds is the mother and does not come from Ds*) + // Pdg::kDS + Pdg::kDSStar (if Ds is the mother and Ds* -> Ds π0/γ) + // Pdg::kLambdaCPlus (if Λc+ is the mother) + pdgCodeCharmMother += std::abs(particlesMc.rawIteratorAt(index0CharmMother).pdgCode()); + } + } + } + break; + } + } + } + } + rowHfDsPiMcCheckReduced(pdgCodeBeautyMother, pdgCodeCharmMother, pdgCodeProng0, pdgCodeProng1, pdgCodeProng2, pdgCodeProng3); + } + rowHfDsPiMcRecReduced(indexHfCandCharm, selectedTracksPion[vecDaughtersB.back().globalIndex()], flag, flagWrongCollision, debug, motherPt); } else if constexpr (decChannel == DecayChannel::BplusToD0barPi) { // B+ → D0(bar) π+ → (K+ π-) π+ - auto indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2]}, Pdg::kBPlus, std::array{+kPiPlus, +kKPlus, -kPiPlus}, true, &sign, 2); + auto indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2]}, Pdg::kBPlus, std::array{+kPiPlus, +kKPlus, -kPiPlus}, true, &sign, 2); if (indexRec > -1) { - // D0bar → K+ π- - // Printf("Checking D0bar → K+ π-"); - indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1]}, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign, 1); + // D0(bar) → K+ π-; + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1]}, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign, 1); if (indexRec > -1) { flag = sign * BIT(hf_cand_bplus::DecayType::BplusToD0Pi); } else { debug = 1; - LOGF(debug, "B0 decays in the expected final state but the condition on the intermediate state is not fulfilled"); + LOGF(debug, "B+ decays in the expected final state but the condition on the intermediate state is not fulfilled"); } auto indexMother = RecoDecay::getMother(particlesMc, vecDaughtersB.back().template mcParticle_as(), Pdg::kBPlus, true); if (indexMother >= 0) { auto particleMother = particlesMc.rawIteratorAt(indexMother); motherPt = particleMother.pt(); + checkWrongCollision(particleMother, collision, indexCollisionMaxNumContrib, flagWrongCollision); + } + } + // additional checks for correlated backgrounds + if (checkDecayTypeMc) { + // Partly reconstructed decays, i.e. the 3 prongs have a common b-hadron ancestor + // convention: final state particles are prong0,1,2 + if (!flag) { + auto particleProng0 = vecDaughtersB[0].mcParticle(); + auto particleProng1 = vecDaughtersB[1].mcParticle(); + auto particleProng2 = vecDaughtersB[2].mcParticle(); + // b-hadron hypothesis + std::array bHadronMotherHypos = {Pdg::kBPlus, Pdg::kB0, Pdg::kBS, Pdg::kLambdaB0}; + // c-hadron hypothesis + std::array cHadronMotherHypos = {Pdg::kD0, Pdg::kDPlus, Pdg::kDS, Pdg::kDStar, 423, Pdg::kDSStar, Pdg::kLambdaCPlus}; + + for (const auto& bHadronMotherHypo : bHadronMotherHypos) { + int index0Mother = RecoDecay::getMother(particlesMc, particleProng0, bHadronMotherHypo, true); + int index1Mother = RecoDecay::getMother(particlesMc, particleProng1, bHadronMotherHypo, true); + int index2Mother = RecoDecay::getMother(particlesMc, particleProng2, bHadronMotherHypo, true); + + // look for common b-hadron ancestor + if (index0Mother > -1 && index1Mother > -1 && index2Mother > -1) { + if (index0Mother == index1Mother && index1Mother == index2Mother) { + flag = BIT(hf_cand_bplus::DecayTypeMc::PartlyRecoDecay); + pdgCodeBeautyMother = particlesMc.rawIteratorAt(index0Mother).pdgCode(); + pdgCodeCharmMother = 0; + pdgCodeProng0 = particleProng0.pdgCode(); + pdgCodeProng1 = particleProng1.pdgCode(); + pdgCodeProng2 = particleProng2.pdgCode(); + // look for common c-hadron mother among prongs 0, 1 and 2 + for (const auto& cHadronMotherHypo : cHadronMotherHypos) { + int8_t depthMax = 2; + if (cHadronMotherHypo == Pdg::kDStar || cHadronMotherHypo == 423 || cHadronMotherHypo == Pdg::kDSStar) { // to include D* -> D π0/γ, D* -> D0 π, and Ds* -> Ds π0/γ + depthMax += 1; + } + int index0CharmMother = RecoDecay::getMother(particlesMc, particleProng0, cHadronMotherHypo, true, &sign, depthMax); + int index1CharmMother = RecoDecay::getMother(particlesMc, particleProng1, cHadronMotherHypo, true, &sign, depthMax); + if (index0CharmMother > -1 && index1CharmMother > -1) { + if (index0CharmMother == index1CharmMother) { + // pdgCodeCharmMother = + // Pdg::kDPlus (if D+ is the mother and does not come from D*+) + // Pdg::kDPlus + Pdg::kDStar (if D+ is the mother and D*+ -> D+ π0/γ) + // Pdg::kDStar (if D*+ is the mother and D*+ -> D0 π+) + // Pdg::kDS (if Ds is the mother and does not come from Ds*) + // Pdg::kDS + Pdg::kDSStar (if Ds is the mother and Ds* -> Ds π0/γ) + // Pdg::kLambdaCPlus (if Λc+ is the mother) + pdgCodeCharmMother += std::abs(particlesMc.rawIteratorAt(index0CharmMother).pdgCode()); + } + } + } + break; + } + } + } } + rowHfD0PiMcCheckReduced(pdgCodeBeautyMother, pdgCodeCharmMother, pdgCodeProng0, pdgCodeProng1, pdgCodeProng2); } - rowHfD0PiMcRecReduced(indexHfCandCharm, selectedTracksPion[vecDaughtersB.back().globalIndex()], flag, debug, motherPt); + rowHfD0PiMcRecReduced(indexHfCandCharm, selectedTracksPion[vecDaughtersB.back().globalIndex()], flag, flagWrongCollision, debug, motherPt); } } - template - void runDataCreation(aod::Collision const& collision, + template + void runDataCreation(Coll const& collision, CCharmCands const& candsC, aod::TrackAssoc const& trackIndices, TTracks const&, PParticles const& particlesMc, + uint64_t const& indexCollisionMaxNumContrib, aod::BCsWithTimestamps const&) { // helpers for ReducedTables filling @@ -449,7 +729,7 @@ struct HfDataCreatorCharmHadPiReduced { // Set the magnetic field from ccdb. // The static instance of the propagator was already modified in the HFTrackIndexSkimCreator, // but this is not true when running on Run2 data/MC already converted into AO2Ds. - auto bc = collision.bc_as(); + auto bc = collision.template bc_as(); if (runNumber != bc.runNumber()) { LOG(info) << ">>>>>>>>>>>> Current run number: " << runNumber; o2::parameters::GRPMagField* grpo = ccdb->getForTimeStamp(ccdbPathGrpMag, bc.timestamp()); @@ -473,6 +753,18 @@ struct HfDataCreatorCharmHadPiReduced { registry.fill(HIST("hMassDplus"), invMassC0); registry.fill(HIST("hPtDplus"), candC.pt()); registry.fill(HIST("hCpaDplus"), candC.cpa()); + } else if constexpr (decChannel == DecayChannel::BsToDsminusPi) { + indexHfCandCharm = hfCand3Prong.lastIndex() + 1; + if (candC.isSelDsToKKPi() >= selectionFlagDs) { + invMassC0 = hfHelper.invMassDsToKKPi(candC); + registry.fill(HIST("hMassDsToKKPi"), invMassC0); + } + if (candC.isSelDsToPiKK() >= selectionFlagDs) { + invMassC1 = hfHelper.invMassDsToPiKK(candC); + registry.fill(HIST("hMassDsToPiKK"), invMassC1); + } + registry.fill(HIST("hPtDs"), candC.pt()); + registry.fill(HIST("hCpaDs"), candC.cpa()); } else if constexpr (decChannel == DecayChannel::BplusToD0barPi) { indexHfCandCharm = hfCand2Prong.lastIndex() + 1; if (candC.isSelD0() >= selectionFlagD0) { @@ -511,7 +803,7 @@ struct HfDataCreatorCharmHadPiReduced { } // third track, if it's a 3-prong - if constexpr (decChannel == DecayChannel::B0ToDminusPi) { + if constexpr (decChannel == DecayChannel::B0ToDminusPi || decChannel == DecayChannel::BsToDsminusPi) { charmHadDauTracks.push_back(candC.template prong2_as()); trackParCov2 = getTrackParCov(charmHadDauTracks[2]); pVec2 = charmHadDauTracks[2].pVector(); @@ -526,19 +818,32 @@ struct HfDataCreatorCharmHadPiReduced { // reconstruct charm candidate secondary vertex o2::track::TrackParCov trackParCovCharmHad{}; std::array pVecCharm{}; - if constexpr (decChannel == DecayChannel::B0ToDminusPi) { // D∓ → π∓ K± π∓ + if constexpr (decChannel == DecayChannel::B0ToDminusPi || decChannel == DecayChannel::BsToDsminusPi) { // D∓ → π∓ K± π∓ and Ds∓ → K∓ K± π∓ + + if constexpr (decChannel == DecayChannel::B0ToDminusPi) { + hCandidatesDPlus->Fill(SVFitting::BeforeFit); + } else { + hCandidatesDs->Fill(SVFitting::BeforeFit); + } - hCandidatesDPlus->Fill(SVFitting::BeforeFit); try { if (df3.process(trackParCov0, trackParCov1, trackParCov2) == 0) { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN cannot work, skipping the candidate."; - hCandidatesDPlus->Fill(SVFitting::Fail); + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; + if constexpr (decChannel == DecayChannel::B0ToDminusPi) { + hCandidatesDPlus->Fill(SVFitting::Fail); + } else { + hCandidatesDs->Fill(SVFitting::Fail); + } continue; } - hCandidatesDPlus->Fill(SVFitting::FitOk); + if constexpr (decChannel == DecayChannel::B0ToDminusPi) { + hCandidatesDPlus->Fill(SVFitting::FitOk); + } else { + hCandidatesDs->Fill(SVFitting::FitOk); + } auto secondaryVertexCharm = df3.getPCACandidate(); trackParCov0.propagateTo(secondaryVertexCharm[0], bz); @@ -558,7 +863,7 @@ struct HfDataCreatorCharmHadPiReduced { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN cannot work, skipping the candidate."; + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; hCandidatesD0->Fill(SVFitting::Fail); continue; } @@ -574,6 +879,26 @@ struct HfDataCreatorCharmHadPiReduced { trackParCovCharmHad.setAbsCharge(0); // to be sure } + float ptDauMin = 1.e6, etaDauMin = 999.f, chi2TpcDauMax = -1.f; + int nItsClsDauMin = 8, nTpcCrossRowsDauMin = 200; + for (const auto& charmHadTrack : charmHadDauTracks) { + if (charmHadTrack.pt() < ptDauMin) { + ptDauMin = charmHadTrack.pt(); + } + if (std::abs(charmHadTrack.eta()) < etaDauMin) { + etaDauMin = std::abs(charmHadTrack.eta()); + } + if (charmHadTrack.itsNCls() < nItsClsDauMin) { + nItsClsDauMin = charmHadTrack.itsNCls(); + } + if (charmHadTrack.tpcNClsCrossedRows() < nTpcCrossRowsDauMin) { + nTpcCrossRowsDauMin = charmHadTrack.tpcNClsCrossedRows(); + } + if (charmHadTrack.tpcChi2NCl() > chi2TpcDauMax) { + chi2TpcDauMax = charmHadTrack.tpcChi2NCl(); + } + } + for (const auto& trackId : trackIndices) { auto trackPion = trackId.template track_as(); @@ -587,7 +912,7 @@ struct HfDataCreatorCharmHadPiReduced { } // reject pi D with same sign as D - if constexpr (decChannel == DecayChannel::B0ToDminusPi) { // D∓ → π∓ K± π∓ + if constexpr (decChannel == DecayChannel::B0ToDminusPi || decChannel == DecayChannel::BsToDsminusPi) { // D∓ → π∓ K± π∓ and Ds∓ → K∓ K± π∓ if (trackPion.sign() * charmHadDauTracks[0].sign() > 0) { continue; } @@ -615,7 +940,8 @@ struct HfDataCreatorCharmHadPiReduced { hfTrackPion(trackPion.globalIndex(), indexHfReducedCollision, trackParCovPion.getX(), trackParCovPion.getAlpha(), trackParCovPion.getY(), trackParCovPion.getZ(), trackParCovPion.getSnp(), - trackParCovPion.getTgl(), trackParCovPion.getQ2Pt()); + trackParCovPion.getTgl(), trackParCovPion.getQ2Pt(), + trackPion.itsNCls(), trackPion.tpcNClsCrossedRows(), trackPion.tpcChi2NCl()); hfTrackCovPion(trackParCovPion.getSigmaY2(), trackParCovPion.getSigmaZY(), trackParCovPion.getSigmaZ2(), trackParCovPion.getSigmaSnpY(), trackParCovPion.getSigmaSnpZ(), trackParCovPion.getSigmaSnp2(), trackParCovPion.getSigmaTglY(), trackParCovPion.getSigmaTglZ(), @@ -636,26 +962,41 @@ struct HfDataCreatorCharmHadPiReduced { beautyHadDauTracks.push_back(track); } beautyHadDauTracks.push_back(trackPion); - fillMcRecoInfo(particlesMc, beautyHadDauTracks, indexHfCandCharm, selectedTracksPion); + fillMcRecoInfo(collision, particlesMc, beautyHadDauTracks, indexHfCandCharm, selectedTracksPion, indexCollisionMaxNumContrib); } fillHfCandCharm = true; - } // pion loop - if (fillHfCandCharm) { // fill candCplus table only once per D candidate - if constexpr (decChannel == DecayChannel::B0ToDminusPi) { // D∓ → π∓ K± π∓ + } // pion loop + if (fillHfCandCharm) { // fill candCplus table only once per D candidate + if constexpr (decChannel == DecayChannel::B0ToDminusPi || decChannel == DecayChannel::BsToDsminusPi) { // D∓ → π∓ K± π∓ and Ds∓ → K∓ K± π∓ hfCand3Prong(charmHadDauTracks[0].globalIndex(), charmHadDauTracks[1].globalIndex(), charmHadDauTracks[2].globalIndex(), indexHfReducedCollision, trackParCovCharmHad.getX(), trackParCovCharmHad.getAlpha(), trackParCovCharmHad.getY(), trackParCovCharmHad.getZ(), trackParCovCharmHad.getSnp(), trackParCovCharmHad.getTgl(), trackParCovCharmHad.getQ2Pt(), - candC.xSecondaryVertex(), candC.ySecondaryVertex(), candC.zSecondaryVertex(), invMassC0); + candC.xSecondaryVertex(), candC.ySecondaryVertex(), candC.zSecondaryVertex(), invMassC0, invMassC1, + ptDauMin, etaDauMin, nItsClsDauMin, nTpcCrossRowsDauMin, chi2TpcDauMax); hfCand3ProngCov(trackParCovCharmHad.getSigmaY2(), trackParCovCharmHad.getSigmaZY(), trackParCovCharmHad.getSigmaZ2(), trackParCovCharmHad.getSigmaSnpY(), trackParCovCharmHad.getSigmaSnpZ(), trackParCovCharmHad.getSigmaSnp2(), trackParCovCharmHad.getSigmaTglY(), trackParCovCharmHad.getSigmaTglZ(), trackParCovCharmHad.getSigmaTglSnp(), trackParCovCharmHad.getSigmaTgl2(), trackParCovCharmHad.getSigma1PtY(), trackParCovCharmHad.getSigma1PtZ(), trackParCovCharmHad.getSigma1PtSnp(), trackParCovCharmHad.getSigma1PtTgl(), trackParCovCharmHad.getSigma1Pt2()); + hfCandPidProng0(charmHadDauTracks[0].tpcNSigmaPi(), charmHadDauTracks[0].tofNSigmaPi(), charmHadDauTracks[0].tpcNSigmaKa(), charmHadDauTracks[0].tofNSigmaKa(), charmHadDauTracks[0].hasTOF(), charmHadDauTracks[0].hasTPC()); + hfCandPidProng1(charmHadDauTracks[1].tpcNSigmaPi(), charmHadDauTracks[1].tofNSigmaPi(), charmHadDauTracks[1].tpcNSigmaKa(), charmHadDauTracks[1].tofNSigmaKa(), charmHadDauTracks[1].hasTOF(), charmHadDauTracks[1].hasTPC()); + hfCandPidProng2(charmHadDauTracks[2].tpcNSigmaPi(), charmHadDauTracks[2].tofNSigmaPi(), charmHadDauTracks[2].tpcNSigmaKa(), charmHadDauTracks[2].tofNSigmaKa(), charmHadDauTracks[2].hasTOF(), charmHadDauTracks[2].hasTPC()); if constexpr (withMl) { - hfCand3ProngMl(candC.mlProbDplusToPiKPi()[0], candC.mlProbDplusToPiKPi()[1], candC.mlProbDplusToPiKPi()[2]); + if constexpr (decChannel == DecayChannel::B0ToDminusPi) { + hfCand3ProngMl(candC.mlProbDplusToPiKPi()[0], candC.mlProbDplusToPiKPi()[1], candC.mlProbDplusToPiKPi()[2], -1., -1., -1.); + } else { + std::array mlScores = {-1.f, -1.f, -1.f, -1.f, -1.f, -1.f}; + if (candC.mlProbDsToKKPi().size() == 3) { + std::copy(candC.mlProbDsToKKPi().begin(), candC.mlProbDsToKKPi().end(), mlScores.begin()); + } + if (candC.mlProbDsToPiKK().size() == 3) { + std::copy(candC.mlProbDsToPiKK().begin(), candC.mlProbDsToPiKK().end(), mlScores.begin() + 3); + } + hfCand3ProngMl(mlScores[0], mlScores[1], mlScores[2], mlScores[3], mlScores[4], mlScores[5]); + } } } else if constexpr (decChannel == DecayChannel::BplusToD0barPi) { // D0(bar) → K± π∓ hfCand2Prong(charmHadDauTracks[0].globalIndex(), charmHadDauTracks[1].globalIndex(), @@ -663,23 +1004,25 @@ struct HfDataCreatorCharmHadPiReduced { trackParCovCharmHad.getX(), trackParCovCharmHad.getAlpha(), trackParCovCharmHad.getY(), trackParCovCharmHad.getZ(), trackParCovCharmHad.getSnp(), trackParCovCharmHad.getTgl(), trackParCovCharmHad.getQ2Pt(), - candC.xSecondaryVertex(), candC.ySecondaryVertex(), candC.zSecondaryVertex(), invMassC0, invMassC1); + candC.xSecondaryVertex(), candC.ySecondaryVertex(), candC.zSecondaryVertex(), invMassC0, invMassC1, + ptDauMin, etaDauMin, nItsClsDauMin, nTpcCrossRowsDauMin, chi2TpcDauMax); hfCand2ProngCov(trackParCovCharmHad.getSigmaY2(), trackParCovCharmHad.getSigmaZY(), trackParCovCharmHad.getSigmaZ2(), trackParCovCharmHad.getSigmaSnpY(), trackParCovCharmHad.getSigmaSnpZ(), trackParCovCharmHad.getSigmaSnp2(), trackParCovCharmHad.getSigmaTglY(), trackParCovCharmHad.getSigmaTglZ(), trackParCovCharmHad.getSigmaTglSnp(), trackParCovCharmHad.getSigmaTgl2(), trackParCovCharmHad.getSigma1PtY(), trackParCovCharmHad.getSigma1PtZ(), trackParCovCharmHad.getSigma1PtSnp(), trackParCovCharmHad.getSigma1PtTgl(), trackParCovCharmHad.getSigma1Pt2()); + hfCandPidProng0(candC.nSigTpcPi0(), candC.nSigTofPi0(), candC.nSigTpcKa0(), candC.nSigTofKa0(), charmHadDauTracks[0].hasTOF(), charmHadDauTracks[0].hasTPC()); + hfCandPidProng1(candC.nSigTpcPi1(), candC.nSigTofPi1(), candC.nSigTpcKa1(), candC.nSigTofKa1(), charmHadDauTracks[1].hasTOF(), charmHadDauTracks[1].hasTPC()); if constexpr (withMl) { - std::array bdtScores = {-1.f, -1.f, -1.f, -1.f, -1.f, -1.f}; + std::array mlScores = {-1.f, -1.f, -1.f, -1.f, -1.f, -1.f}; if (candC.mlProbD0().size() == 3) { - std::copy(candC.mlProbD0().begin(), candC.mlProbD0().end(), bdtScores.begin()); + std::copy(candC.mlProbD0().begin(), candC.mlProbD0().end(), mlScores.begin()); } if (candC.mlProbD0bar().size() == 3) { - std::copy(candC.mlProbD0bar().begin(), candC.mlProbD0bar().end(), bdtScores.begin() + 3); + std::copy(candC.mlProbD0bar().begin(), candC.mlProbD0bar().end(), mlScores.begin() + 3); } - - hfCand2ProngMl(bdtScores[0], bdtScores[1], bdtScores[2], bdtScores[3], bdtScores[4], bdtScores[5]); + hfCand2ProngMl(mlScores[0], mlScores[1], mlScores[2], mlScores[3], mlScores[4], mlScores[5]); } } fillHfReducedCollision = true; @@ -692,11 +1035,21 @@ struct HfDataCreatorCharmHadPiReduced { return; } registry.fill(HIST("hEvents"), 1 + Event::CharmHadPiSelected); + float centrality = -1.f; + uint16_t hfRejMap = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); // fill collision table if it contains a DPi pair a minima - hfReducedCollision(collision.posX(), collision.posY(), collision.posZ()); + hfReducedCollision(collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), hfRejMap, bz); hfReducedCollExtra(collision.covXX(), collision.covXY(), collision.covYY(), - collision.covXZ(), collision.covYZ(), collision.covZZ(), - bz); + collision.covXZ(), collision.covYZ(), collision.covZZ()); + hfReducedCollCentrality(collision.centFT0C(), collision.centFT0M(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + if constexpr (withQvec) { + hfReducedQvector(collision.qvecFT0CRe(), collision.qvecFT0CIm(), collision.sumAmplFT0C(), + collision.qvecFT0ARe(), collision.qvecFT0AIm(), collision.sumAmplFT0A(), + collision.qvecFT0MRe(), collision.qvecFT0MIm(), collision.sumAmplFT0M(), + collision.qvecTPCposRe(), collision.qvecTPCposIm(), collision.nTrkTPCpos(), + collision.qvecTPCnegRe(), collision.qvecTPCnegIm(), collision.nTrkTPCneg(), + collision.qvecTPCallRe(), collision.qvecTPCallIm(), collision.nTrkTPCall()); + } } template @@ -739,9 +1092,84 @@ struct HfDataCreatorCharmHadPiReduced { rowHfB0McGenReduced(flag, ptParticle, yParticle, etaParticle, ptProngs[0], yProngs[0], etaProngs[0], ptProngs[1], yProngs[1], etaProngs[1]); + } else if constexpr (decayChannel == DecayChannel::BsToDsminusPi) { + // Bs → Ds- π+ + if (RecoDecay::isMatchedMCGen(particlesMc, particle, Pdg::kBS, std::array{-static_cast(Pdg::kDS), +kPiPlus}, true)) { + // Match Ds- -> π- K+ π- + auto candCMC = particlesMc.rawIteratorAt(particle.daughtersIds().front()); + if (RecoDecay::isMatchedMCGen(particlesMc, candCMC, -static_cast(Pdg::kDS), std::array{-kKPlus, +kKPlus, -kPiPlus}, true, &sign, 2)) { + std::vector arrDaughDsIndex; + std::array arrPDGDaughDs; + RecoDecay::getDaughters(candCMC, &arrDaughDsIndex, std::array{0}, 1); + if (arrDaughDsIndex.size() == 2) { + for (auto jProng = 0u; jProng < arrDaughDsIndex.size(); ++jProng) { + auto daughJ = particlesMc.rawIteratorAt(arrDaughDsIndex[jProng]); + arrPDGDaughDs[jProng] = std::abs(daughJ.pdgCode()); + } + // Ds- → Phi π- → K- K+ π- and Ds- → K0* K- → K- K+ π- + if ((arrPDGDaughDs[0] == arrPDGResonantDsPhiPi[0] && arrPDGDaughDs[1] == arrPDGResonantDsPhiPi[1]) || (arrPDGDaughDs[0] == arrPDGResonantDsPhiPi[1] && arrPDGDaughDs[1] == arrPDGResonantDsPhiPi[0])) { + flag = sign * BIT(hf_cand_bs::DecayTypeMc::BsToDsPiToPhiPiPiToKKPiPi); + } else if ((arrPDGDaughDs[0] == arrPDGResonantDKstarK[0] && arrPDGDaughDs[1] == arrPDGResonantDKstarK[1]) || (arrPDGDaughDs[0] == arrPDGResonantDKstarK[1] && arrPDGDaughDs[1] == arrPDGResonantDKstarK[0])) { + flag = sign * BIT(hf_cand_bs::DecayTypeMc::BsToDsPiToK0starKPiToKKPiPi); + } + } + } + } + + // additional checks for correlated backgrounds + if (checkDecayTypeMc) { + // B0 → Ds- π+ + if (!flag) { + if (RecoDecay::isMatchedMCGen(particlesMc, particle, Pdg::kB0, std::array{-static_cast(Pdg::kDS), +kPiPlus}, true)) { + // Match Ds- -> π- K+ π- + auto candCMC = particlesMc.rawIteratorAt(particle.daughtersIds().front()); + if (RecoDecay::isMatchedMCGen(particlesMc, candCMC, -static_cast(Pdg::kDS), std::array{-kKPlus, +kKPlus, -kPiPlus}, true, &sign, 2)) { + std::vector arrDaughDsIndex; + std::array arrPDGDaughDs; + RecoDecay::getDaughters(candCMC, &arrDaughDsIndex, std::array{0}, 1); + if (arrDaughDsIndex.size() == 2) { + for (auto jProng = 0u; jProng < arrDaughDsIndex.size(); ++jProng) { + auto daughJ = particlesMc.rawIteratorAt(arrDaughDsIndex[jProng]); + arrPDGDaughDs[jProng] = std::abs(daughJ.pdgCode()); + } + // Ds- → Phi π- → K- K+ π- and Ds- → K0* K- → K- K+ π- + if ((arrPDGDaughDs[0] == arrPDGResonantDsPhiPi[0] && arrPDGDaughDs[1] == arrPDGResonantDsPhiPi[1]) || (arrPDGDaughDs[0] == arrPDGResonantDsPhiPi[1] && arrPDGDaughDs[1] == arrPDGResonantDsPhiPi[0])) { + flag = sign * BIT(hf_cand_bs::DecayTypeMc::B0ToDsPiToPhiPiPiToKKPiPi); + } else if ((arrPDGDaughDs[0] == arrPDGResonantDKstarK[0] && arrPDGDaughDs[1] == arrPDGResonantDKstarK[1]) || (arrPDGDaughDs[0] == arrPDGResonantDKstarK[1] && arrPDGDaughDs[1] == arrPDGResonantDKstarK[0])) { + flag = sign * BIT(hf_cand_bs::DecayTypeMc::B0ToDsPiToK0starKPiToKKPiPi); + } + } + } + } + } + } + + // save information for Bs task + if (!TESTBIT(std::abs(flag), hf_cand_bs::DecayTypeMc::BsToDsPiToPhiPiPiToKKPiPi) && !TESTBIT(std::abs(flag), hf_cand_bs::DecayTypeMc::BsToDsPiToK0starKPiToKKPiPi) && + !TESTBIT(std::abs(flag), hf_cand_bs::DecayTypeMc::B0ToDsPiToPhiPiPiToKKPiPi) && !TESTBIT(std::abs(flag), hf_cand_bs::DecayTypeMc::B0ToDsPiToK0starKPiToKKPiPi)) { + continue; + } + + auto ptParticle = particle.pt(); + auto yParticle = RecoDecay::y(particle.pVector(), massB); + auto etaParticle = particle.eta(); + + std::array ptProngs; + std::array yProngs; + std::array etaProngs; + int counter = 0; + for (const auto& daught : particle.daughters_as()) { + ptProngs[counter] = daught.pt(); + etaProngs[counter] = daught.eta(); + yProngs[counter] = RecoDecay::y(daught.pVector(), pdg->Mass(daught.pdgCode())); + counter++; + } + rowHfBsMcGenReduced(flag, ptParticle, yParticle, etaParticle, + ptProngs[0], yProngs[0], etaProngs[0], + ptProngs[1], yProngs[1], etaProngs[1]); } else if constexpr (decayChannel == DecayChannel::BplusToD0barPi) { // B+ → D0bar π+ - if (RecoDecay::isMatchedMCGen(particlesMc, particle, Pdg::kBPlus, std::array{static_cast(Pdg::kD0), +kPiPlus}, true)) { + if (RecoDecay::isMatchedMCGen(particlesMc, particle, Pdg::kBPlus, std::array{-static_cast(Pdg::kD0), +kPiPlus}, true)) { // Match D0bar -> π- K+ auto candD0MC = particlesMc.rawIteratorAt(particle.daughtersIds().front()); // Printf("Checking D0bar -> π- K+"); @@ -779,7 +1207,7 @@ struct HfDataCreatorCharmHadPiReduced { //////////////////////////////////////////////////////////////////////////////////////////////////// // PROCESS FUNCTIONS FOR DATA - void processDplusPiData(aod::Collisions const& collisions, + void processDplusPiData(CollisionsWCent const& collisions, CandsDplusFiltered const& candsC, aod::TrackAssoc const& trackIndices, TracksPidWithSel const& tracks, @@ -791,19 +1219,25 @@ struct HfDataCreatorCharmHadPiReduced { isHfCandBhadConfigFilled = true; } - // handle normalization by the right number of collisions - hfCollisionCounter(collisions.tableSize()); - + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + auto thisCollId = collision.globalIndex(); auto candsCThisColl = candsC.sliceBy(candsDplusPerCollision, thisCollId); auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, bcs); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDplusPiData, "Process DplusPi without MC info and without ML info", true); - void processDplusPiDataWithMl(aod::Collisions const& collisions, + void processDplusPiDataWithMl(CollisionsWCent const& collisions, CandsDplusFilteredWithMl const& candsC, aod::TrackAssoc const& trackIndices, TracksPidWithSel const& tracks, @@ -815,19 +1249,205 @@ struct HfDataCreatorCharmHadPiReduced { isHfCandBhadConfigFilled = true; } + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; + for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + + auto thisCollId = collision.globalIndex(); + auto candsCThisColl = candsC.sliceBy(candsDplusPerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } // handle normalization by the right number of collisions - hfCollisionCounter(collisions.tableSize()); + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDplusPiDataWithMl, "Process DplusPi without MC info and with ML info", false); + void processDplusPiDataWithQvec(CollisionsWCentAndQvectors const& collisions, + CandsDplusFiltered const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs) + { + // store configurables needed for B0 workflow + if (!isHfCandBhadConfigFilled) { + rowCandidateConfigB0(selectionFlagDplus.value, invMassWindowCharmHadPi.value); + isHfCandBhadConfigFilled = true; + } + + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; + for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + + auto thisCollId = collision.globalIndex(); + auto candsCThisColl = candsC.sliceBy(candsDplusPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDplusPiDataWithQvec, "Process DplusPi without MC info, without ML info and with Q-vectors", true); + + void processDplusPiDataWithMlAndQvec(CollisionsWCentAndQvectors const& collisions, + CandsDplusFilteredWithMl const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs) + { + // store configurables needed for B0 workflow + if (!isHfCandBhadConfigFilled) { + rowCandidateConfigB0(selectionFlagDplus.value, invMassWindowCharmHadPi.value); + isHfCandBhadConfigFilled = true; + } + + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + auto thisCollId = collision.globalIndex(); auto candsCThisColl = candsC.sliceBy(candsDplusPerCollisionWithMl, thisCollId); auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, bcs); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } - PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDplusPiDataWithMl, "Process DplusPi without MC info and with ML info", false); + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDplusPiDataWithMlAndQvec, "Process DplusPi without MC info, with ML info and with Q-vectors", false); + + void processDsPiData(CollisionsWCent const& collisions, + CandsDsFiltered const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs) + { + // store configurables needed for Bs workflow + if (!isHfCandBhadConfigFilled) { + rowCandidateConfigBs(selectionFlagDs.value, invMassWindowCharmHadPi.value); + isHfCandBhadConfigFilled = true; + } + + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; + for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + + auto thisCollId = collision.globalIndex(); + auto candsCThisColl = candsC.sliceBy(candsDplusPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDsPiData, "Process DsPi without MC info and without ML info", true); + + void processDsPiDataWithMl(CollisionsWCent const& collisions, + CandsDsFilteredWithMl const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs) + { + // store configurables needed for Bs workflow + if (!isHfCandBhadConfigFilled) { + rowCandidateConfigBs(selectionFlagDs.value, invMassWindowCharmHadPi.value); + isHfCandBhadConfigFilled = true; + } + + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; + for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + + auto thisCollId = collision.globalIndex(); + auto candsCThisColl = candsC.sliceBy(candsDplusPerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDsPiDataWithMl, "Process DsPi without MC info and with ML info", false); + + void processDsPiDataWithQvec(CollisionsWCentAndQvectors const& collisions, + CandsDsFiltered const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs) + { + // store configurables needed for Bs workflow + if (!isHfCandBhadConfigFilled) { + rowCandidateConfigBs(selectionFlagDs.value, invMassWindowCharmHadPi.value); + isHfCandBhadConfigFilled = true; + } + + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; + for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + + auto thisCollId = collision.globalIndex(); + auto candsCThisColl = candsC.sliceBy(candsDplusPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDsPiDataWithQvec, "Process DsPi without MC info, without ML info and with Q-vectors", true); + + void processDsPiDataWithMlAndQvec(CollisionsWCentAndQvectors const& collisions, + CandsDsFilteredWithMl const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs) + { + // store configurables needed for Bs workflow + if (!isHfCandBhadConfigFilled) { + rowCandidateConfigBs(selectionFlagDs.value, invMassWindowCharmHadPi.value); + isHfCandBhadConfigFilled = true; + } - void processD0PiData(aod::Collisions const& collisions, + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; + for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + + auto thisCollId = collision.globalIndex(); + auto candsCThisColl = candsC.sliceBy(candsDplusPerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDsPiDataWithMlAndQvec, "Process DsPi without MC info, with ML info and Q-vectors", false); + + void processD0PiData(CollisionsWCent const& collisions, CandsD0Filtered const& candsC, aod::TrackAssoc const& trackIndices, TracksPidWithSel const& tracks, @@ -839,19 +1459,25 @@ struct HfDataCreatorCharmHadPiReduced { isHfCandBhadConfigFilled = true; } - // handle normalization by the right number of collisions - hfCollisionCounter(collisions.tableSize()); - + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + auto thisCollId = collision.globalIndex(); auto candsCThisColl = candsC.sliceBy(candsD0PerCollision, thisCollId); auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, bcs); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processD0PiData, "Process D0Pi without MC info and without ML info", false); - void processD0PiDataWithMl(aod::Collisions const& collisions, + void processD0PiDataWithMl(CollisionsWCent const& collisions, CandsD0FilteredWithMl const& candsC, aod::TrackAssoc const& trackIndices, TracksPidWithSel const& tracks, @@ -863,27 +1489,94 @@ struct HfDataCreatorCharmHadPiReduced { isHfCandBhadConfigFilled = true; } + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; + for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + + auto thisCollId = collision.globalIndex(); + auto candsCThisColl = candsC.sliceBy(candsD0PerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } // handle normalization by the right number of collisions - hfCollisionCounter(collisions.tableSize()); + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processD0PiDataWithMl, "Process D0Pi without MC info and with ML info", false); + void processD0PiDataWithQvec(CollisionsWCentAndQvectors const& collisions, + CandsD0Filtered const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs) + { + // store configurables needed for B+ workflow + if (!isHfCandBhadConfigFilled) { + rowCandidateConfigBplus(selectionFlagD0.value, selectionFlagD0bar.value, invMassWindowCharmHadPi.value); + isHfCandBhadConfigFilled = true; + } + + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; + for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + + auto thisCollId = collision.globalIndex(); + auto candsCThisColl = candsC.sliceBy(candsD0PerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processD0PiDataWithQvec, "Process D0Pi without MC info, without ML info, and with Q-vectors", false); + + void processD0PiDataWithMlAndQvec(CollisionsWCentAndQvectors const& collisions, + CandsD0FilteredWithMl const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs) + { + // store configurables needed for B+ workflow + if (!isHfCandBhadConfigFilled) { + rowCandidateConfigBplus(selectionFlagD0.value, selectionFlagD0bar.value, invMassWindowCharmHadPi.value); + isHfCandBhadConfigFilled = true; + } + + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + auto thisCollId = collision.globalIndex(); auto candsCThisColl = candsC.sliceBy(candsD0PerCollisionWithMl, thisCollId); auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, bcs); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } - PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processD0PiDataWithMl, "Process D0Pi without MC info and with ML info", false); + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processD0PiDataWithMlAndQvec, "Process D0Pi without MC info, with ML info, and with Q-vectors", false); //////////////////////////////////////////////////////////////////////////////////////////////////// // PROCESS FUNCTIONS FOR MC - void processDplusPiMc(aod::Collisions const& collisions, + void processDplusPiMc(CollisionsWCentAndMcLabels const& collisions, CandsDplusFiltered const& candsC, aod::TrackAssoc const& trackIndices, TracksPidWithSelAndMc const& tracks, aod::McParticles const& particlesMc, - aod::BCsWithTimestamps const& bcs) + aod::BCsWithTimestamps const& bcs, + McCollisions const&) { // store configurables needed for B0 workflow if (!isHfCandBhadConfigFilled) { @@ -891,25 +1584,34 @@ struct HfDataCreatorCharmHadPiReduced { isHfCandBhadConfigFilled = true; } - // handle normalization by the right number of collisions - hfCollisionCounter(collisions.tableSize()); - + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + auto thisCollId = collision.globalIndex(); auto candsCThisColl = candsC.sliceBy(candsDplusPerCollision, thisCollId); auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, bcs); + auto collsSameMcCollision = collisions.sliceBy(colPerMcCollision, collision.mcCollisionId()); + int64_t indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); runMcGen(particlesMc); } PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDplusPiMc, "Process DplusPi with MC info and without ML info", false); - void processDplusPiMcWithMl(aod::Collisions const& collisions, + void processDplusPiMcWithMl(CollisionsWCentAndMcLabels const& collisions, CandsDplusFilteredWithMl const& candsC, aod::TrackAssoc const& trackIndices, TracksPidWithSelAndMc const& tracks, aod::McParticles const& particlesMc, - aod::BCsWithTimestamps const& bcs) + aod::BCsWithTimestamps const& bcs, + McCollisions const&) { // store configurables needed for B0 workflow if (!isHfCandBhadConfigFilled) { @@ -917,25 +1619,104 @@ struct HfDataCreatorCharmHadPiReduced { isHfCandBhadConfigFilled = true; } - // handle normalization by the right number of collisions - hfCollisionCounter(collisions.tableSize()); - + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + auto thisCollId = collision.globalIndex(); auto candsCThisColl = candsC.sliceBy(candsDplusPerCollisionWithMl, thisCollId); auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, bcs); + auto collsSameMcCollision = collisions.sliceBy(colPerMcCollision, collision.mcCollisionId()); + int64_t indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); runMcGen(particlesMc); } PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDplusPiMcWithMl, "Process DplusPi with MC info and with ML info", false); - void processD0PiMc(aod::Collisions const& collisions, + void processDsPiMc(CollisionsWCentAndMcLabels const& collisions, + CandsDsFiltered const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSelAndMc const& tracks, + aod::McParticles const& particlesMc, + aod::BCsWithTimestamps const& bcs, + McCollisions const&) + { + // store configurables needed for Bs workflow + if (!isHfCandBhadConfigFilled) { + rowCandidateConfigBs(selectionFlagDs.value, invMassWindowCharmHadPi.value); + isHfCandBhadConfigFilled = true; + } + + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; + for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + + auto thisCollId = collision.globalIndex(); + auto candsCThisColl = candsC.sliceBy(candsDplusPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + auto collsSameMcCollision = collisions.sliceBy(colPerMcCollision, collision.mcCollisionId()); + int64_t indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + runMcGen(particlesMc); + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDsPiMc, "Process DsPi with MC info and without ML info", false); + + void processDsPiMcWithMl(CollisionsWCentAndMcLabels const& collisions, + CandsDsFilteredWithMl const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSelAndMc const& tracks, + aod::McParticles const& particlesMc, + aod::BCsWithTimestamps const& bcs, + McCollisions const&) + { + // store configurables needed for Bs workflow + if (!isHfCandBhadConfigFilled) { + rowCandidateConfigBs(selectionFlagDs.value, invMassWindowCharmHadPi.value); + isHfCandBhadConfigFilled = true; + } + + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; + for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + + auto thisCollId = collision.globalIndex(); + auto candsCThisColl = candsC.sliceBy(candsDplusPerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + auto collsSameMcCollision = collisions.sliceBy(colPerMcCollision, collision.mcCollisionId()); + int64_t indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + runMcGen(particlesMc); + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDsPiMcWithMl, "Process DsPi with MC info and with ML info", false); + + void processD0PiMc(CollisionsWCentAndMcLabels const& collisions, CandsD0Filtered const& candsC, aod::TrackAssoc const& trackIndices, TracksPidWithSelAndMc const& tracks, aod::McParticles const& particlesMc, - aod::BCsWithTimestamps const& bcs) + aod::BCsWithTimestamps const& bcs, + McCollisions const&) { // store configurables needed for B+ workflow if (!isHfCandBhadConfigFilled) { @@ -943,25 +1724,34 @@ struct HfDataCreatorCharmHadPiReduced { isHfCandBhadConfigFilled = true; } - // handle normalization by the right number of collisions - hfCollisionCounter(collisions.tableSize()); - + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + auto thisCollId = collision.globalIndex(); auto candsCThisColl = candsC.sliceBy(candsD0PerCollision, thisCollId); auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, bcs); + auto collsSameMcCollision = collisions.sliceBy(colPerMcCollision, collision.mcCollisionId()); + int64_t indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); runMcGen(particlesMc); } PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processD0PiMc, "Process D0Pi with MC info and without ML info", false); - void processD0PiMcWithMl(aod::Collisions const& collisions, + void processD0PiMcWithMl(CollisionsWCentAndMcLabels const& collisions, CandsD0FilteredWithMl const& candsC, aod::TrackAssoc const& trackIndices, TracksPidWithSelAndMc const& tracks, aod::McParticles const& particlesMc, - aod::BCsWithTimestamps const& bcs) + aod::BCsWithTimestamps const& bcs, + McCollisions const&) { // store configurables needed for B+ workflow if (!isHfCandBhadConfigFilled) { @@ -969,15 +1759,23 @@ struct HfDataCreatorCharmHadPiReduced { isHfCandBhadConfigFilled = true; } - // handle normalization by the right number of collisions - hfCollisionCounter(collisions.tableSize()); - + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + auto thisCollId = collision.globalIndex(); auto candsCThisColl = candsC.sliceBy(candsD0PerCollisionWithMl, thisCollId); auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, bcs); + auto collsSameMcCollision = collisions.sliceBy(colPerMcCollision, collision.mcCollisionId()); + int64_t indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); runMcGen(particlesMc); } PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processD0PiMcWithMl, "Process D0Pi with MC info and with ML info", false); diff --git a/PWGHF/D2H/TableProducer/dataCreatorCharmResoReduced.cxx b/PWGHF/D2H/TableProducer/dataCreatorCharmResoReduced.cxx index 1acec493668..714de7448ac 100644 --- a/PWGHF/D2H/TableProducer/dataCreatorCharmResoReduced.cxx +++ b/PWGHF/D2H/TableProducer/dataCreatorCharmResoReduced.cxx @@ -13,9 +13,13 @@ /// \brief Creation of D-V0 pairs /// /// \author Luca Aglietta , UniTO Turin +/// \author Fabrizio Grosa , CERN +#include #include #include +#include +#include #include "DetectorsBase/Propagator.h" #include "CommonConstants/PhysicsConstants.h" @@ -27,6 +31,7 @@ #include "Common/Core/trackUtilities.h" #include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "PWGLF/DataModel/LFStrangenessTables.h" @@ -35,6 +40,8 @@ #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" #include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" using namespace o2; using namespace o2::analysis; @@ -53,13 +60,15 @@ enum Event : uint8_t { enum DecayChannel : uint8_t { DstarV0 = 0, - DplusV0 + DplusV0, + DstarTrack }; -enum V0Type : uint8_t { +enum BachelorType : uint8_t { K0s = 0, Lambda, - AntiLambda + AntiLambda, + Track }; enum DType : uint8_t { @@ -67,17 +76,40 @@ enum DType : uint8_t { Dstar }; +enum DecayTypeMc : uint8_t { + Ds1ToDStarK0ToD0PiK0s = 1, + Ds2StarToDplusK0sToPiKaPiPiPi, + Ds1ToDStarK0ToDPlusPi0K0s, + Ds1ToDStarK0ToD0PiK0sPart, + Ds1ToDStarK0ToD0NoPiK0sPart, + Ds1ToDStarK0ToD0PiK0sOneMu, + Ds2StarToDplusK0sOneMu +}; + +enum PartialMatchMc : uint8_t { + K0Matched = 0, + D0Matched, + DStarMatched, + DPlusMatched, + K0MuMatched, + DStarMuMatched +}; + /// Creation of D-V0 pairs struct HfDataCreatorCharmResoReduced { - // Produces AOD tables to store track information + // Produces AOD tables to store collision information Produces hfReducedCollision; // Defined in PWGHF/D2H/DataModel/ReducedDataModel.h Produces hfCollisionCounter; // Defined in PWGHF/D2H/DataModel/ReducedDataModel.h - // V0 and D candidates reduced tables - Produces hfCandV0; // Defined in PWGHF/D2H/DataModel/ReducedDataModel.h - Produces hfCandD; // Defined in PWGHF/D2H/DataModel/ReducedDataModel.h + // tracks, V0 and D candidates reduced tables + Produces hfCandV0; // Defined in PWGHF/D2H/DataModel/ReducedDataModel.h + Produces hfTrackNoParam; // Defined in PWGHF/D2H/DataModel/ReducedDataModel.h + Produces hfCandD; // Defined in PWGHF/D2H/DataModel/ReducedDataModel.h // ML optional Tables Produces hfCandDMl; // Defined in PWGHF/D2H/DataModel/ReducedDataModel.h + // MC Tables + Produces rowHfDV0McRecReduced; + Produces rowHfResoMcGenReduced; // CCDB configuration o2::ccdb::CcdbApi ccdbApi; @@ -85,44 +117,102 @@ struct HfDataCreatorCharmResoReduced { Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; Configurable propagateV0toPV{"propagateV0toPV", false, "Enable or disable V0 propagation to V0"}; + Configurable doMcRecQa{"doMcRecQa", true, "Fill QA histograms for Mc matching"}; int runNumber{0}; // needed to detect if the run changed and trigger update of calibrations etc. // selection D - Configurable selectionFlagDplus{"selectionFlagDplus", 7, "Selection Flag for D"}; - Configurable selectionFlagDstarToD0Pi{"selectionFlagDstarToD0Pi", true, "Selection Flag for D* decay to D0 & Pi"}; + struct : ConfigurableGroup { + std::string prefix = "dmesons"; + Configurable selectionFlagDplus{"selectionFlagDplus", 7, "Selection Flag for D"}; + Configurable selectionFlagDstarToD0Pi{"selectionFlagDstarToD0Pi", true, "Selection Flag for D* decay to D0 & Pi"}; + } cfgDmesCuts; + // selection V0 - Configurable minK0sLambdaCosinePa{"minK0sLambdaCosinePa", 0.97, "minimum cosp for K0S and Lambda"}; - Configurable minK0sLambdaRadius{"minK0sLambdaRadius", 0.5, "minimum radius for K0S and Lambda"}; - Configurable deltaMassK0s{"deltaMassK0s", 0.03, "delta mass cut for K0S"}; - Configurable deltaMassLambda{"deltaMassLambda", 0.015, "delta mass cut for Lambda"}; - Configurable minV0dauEta{"minV0dauEta", 1., "minimum eta for V0 daughters"}; - Configurable maxV0DCA{"maxV0DCA", 0.1, "maximum DCA for K0S and Lambda"}; - Configurable minV0dauDCA{"minV0dauDCA", 0.05, "minimum DCA for V0 daughters"}; - Configurable maxV0dauDCA{"maxV0dauDCA", 1., "maximum DCA for V0 daughters"}; - Configurable maxNsigmaPrForLambda{"maxNsigmaPrForLambda", 4., "maximum proton NSigma in TPC and TOF for Lambdas"}; + struct : ConfigurableGroup { + std::string prefix = "v0s"; + Configurable deltaMassK0s{"deltaMassK0s", 0.02, "delta mass cut for K0S"}; + Configurable deltaMassLambda{"deltaMassLambda", 0.01, "delta mass cut for Lambda"}; + Configurable etaMax{"etaMax", 0.8f, "maximum eta"}; + Configurable etaMaxDau{"etaMaxDau", 5.f, "maximum eta V0 daughters"}; + Configurable trackNclusItsCut{"trackNclusItsCut", 0, "Minimum number of ITS clusters for V0 daughter"}; + Configurable trackNCrossedRowsTpc{"trackNCrossedRowsTpc", 50, "Minimum TPC crossed rows"}; + Configurable trackNsharedClusTpc{"trackNsharedClusTpc", 1000, "Maximum number of shared TPC clusters for V0 daughter"}; + Configurable dcaDau{"dcaDau", 1.f, "DCA V0 daughters"}; + Configurable dcaMaxDauToPv{"dcaMaxDauToPv", 0.1f, "Maximum daughter's DCA to PV"}; + Configurable dcaPv{"dcaPv", 1.f, "DCA V0 to PV"}; + Configurable cosPa{"cosPa", 0.99f, "V0 CosPA"}; + Configurable radiusMin{"radiusMin", 0.9f, "Minimum v0 radius accepted"}; + Configurable nSigmaTpc{"nSigmaTpc", 4.f, "Nsigmatpc"}; + Configurable nSigmaTofPr{"nSigmaTofPr", 4.f, "N sigma TOF for protons only"}; + } cfgV0Cuts; + + // selection single tracks + struct : ConfigurableGroup { + std::string prefix = "single_tracks"; + Configurable setTrackSelections{"setTrackSelections", 2, "flag to apply track selections: 0=none; 1=global track w/o DCA selection; 2=global track; 3=only ITS quality"}; + Configurable maxEta{"maxEta", 0.8, "maximum pseudorapidity for single tracks to be paired with D mesons"}; + Configurable minPt{"minPt", 0.1, "minimum pT for single tracks to be paired with D mesons"}; + Configurable maxNsigmaTpcPi{"maxNsigmaTpcPi", -1., "maximum pion NSigma in TPC for single tracks to be paired with D mesons; set negative to reject"}; + Configurable maxNsigmaTpcKa{"maxNsigmaTpcKa", -1., "maximum kaon NSigma in TPC for single tracks to be paired with D mesons; set negative to reject"}; + Configurable maxNsigmaTpcPr{"maxNsigmaTpcPr", 3., "maximum proton NSigma in TPC for single tracks to be paired with D mesons; set negative to reject"}; + } cfgSingleTrackCuts; + + // other configurables + Configurable rejectPairsWithCommonDaughter{"rejectPairsWithCommonDaughter", true, "flag to reject already at this stage the pairs that share a daughter track"}; // material correction for track propagation o2::base::MatLayerCylSet* lut; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; HfHelper hfHelper; + o2::hf_evsel::HfEventSelection hfEvSel; + o2::vertexing::DCAFitterN<2> fitter; + double bz{0.}; + Service pdg; - bool isHfCandResoConfigFilled = false; + // bool isHfCandResoConfigFilled = false; + // Helper struct to pass V0 informations + struct { + std::array pos; + std::array mom; + std::array momPos; + std::array momNeg; + float pT; + float cosPA; + float dcaV0ToPv; + float dcaDau; + float alpha; + float eta; + float radius; + float mK0Short; + float mLambda; + uint8_t v0Type; + } candidateV0; + + struct { + float invMassD; + float ptD; + float invMassDdau; + float invMassKPiPiV0; + float ptReso; + } varUtils; using CandsDplusFiltered = soa::Filtered>; using CandsDplusFilteredWithMl = soa::Filtered>; using CandDstarFiltered = soa::Filtered>; using CandDstarFilteredWithMl = soa::Filtered>; - using BigTracksPID = soa::Join; + using TracksWithPID = soa::Join; + using TracksIUWithPID = soa::Join; + using TracksIUWithPIDAndMC = soa::Join; - Filter filterSelectDplus = (aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus); - Filter filterSelectedCandDstar = (aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == selectionFlagDstarToD0Pi); + Filter filterSelectDplus = (aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= cfgDmesCuts.selectionFlagDplus); + Filter filterSelectedCandDstar = (aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == cfgDmesCuts.selectionFlagDstarToD0Pi); - Preslice candsDplusPerCollision = aod::track_association::collisionId; - Preslice candsDplusPerCollisionWithMl = aod::track_association::collisionId; - Preslice candsDstarPerCollision = aod::track_association::collisionId; - Preslice candsDstarPerCollisionWithMl = aod::track_association::collisionId; + Preslice candsDplusPerCollision = aod::hf_cand::collisionId; + Preslice candsDplusPerCollisionWithMl = aod::hf_cand::collisionId; + Preslice candsDstarPerCollision = aod::hf_cand::collisionId; + Preslice candsDstarPerCollisionWithMl = aod::hf_cand::collisionId; + Preslice candsV0PerCollision = aod::v0::collisionId; Preslice trackIndicesPerCollision = aod::track_association::collisionId; - Preslice candsV0PerCollision = aod::track_association::collisionId; HistogramRegistry registry{"registry"}; @@ -139,85 +229,518 @@ struct HfDataCreatorCharmResoReduced { for (int iBin = 0; iBin < kNBinsEvents; iBin++) { registry.get(HIST("hEvents"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); } - registry.add("hMassDplus", "Dplus candidates;inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{100, 1.7, 2}}}); - registry.add("hMassDstar", "Dstar candidates;inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{100, 0.14, 0.17}}}); - registry.add("hMassK0s", "K0^{s} candidates;inv. mass (#pi^{#plus}#pi^{#minus}) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{100, 0.35, 0.65}}}); - registry.add("hMassLambda", "Lambda candidates;inv. mass (p #pi^{#minus}) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{100, 1.05, 1.35}}}); - registry.add("hPtDplus", "D^{#minus} candidates;D^{#minus} candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 10.}}}); - registry.add("hPtDstar", "D^{*} candidates;D^{*} candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 10.}}}); - registry.add("hPtV0", "V0 candidates;V0 candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 10.}}}); - registry.add("hMassDs1", "Ds1 candidates;m_{Ds1} - m_{D^{*}} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{100, 2.4, 2.7}}}); - registry.add("hMassDsStar2", "Ds^{*}2 candidates; Ds^{*}2 - m_{D^{#plus}} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{100, 2.4, 2.7}}}); - registry.add("hMassXcRes", "XcRes candidates; XcRes - m_{D^{#plus}} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{100, 2.9, 3.3}}}); - registry.add("hV0Type", "V0 selection flag", {HistType::kTH1F, {{8, -0.5, 7.5}}}); + + const AxisSpec axisPt{50, 0.f, 50.f, ""}; + const AxisSpec axisP{100, 0.f, 10.f, ""}; + const AxisSpec axisDeDx{500, 0.f, 1000.f, ""}; + const AxisSpec axisMassDplus{200, 1.7f, 2.1f, ""}; + const AxisSpec axisMassDstar{200, 0.139f, 0.179f, ""}; + const AxisSpec axisMassLambda{100, 1.05f, 1.35f, ""}; + const AxisSpec axisMassKzero{100, 0.35f, 0.65f, ""}; + const AxisSpec axisMassDsj{400, 0.49f, 0.89f, ""}; + + registry.add("hMassVsPtDplusAll", "Dplus candidates (all, regardless the pairing with V0s);#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDplus}}); + registry.add("hMassVsPtDstarAll", "Dstar candidates (all, regardless the pairing with V0s);#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDstar}}); + registry.add("hMassVsPtDplusPaired", "Dplus candidates (paired with V0s);#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDplus}}); + registry.add("hMassVsPtDstarPaired", "Dstar candidates (paired with V0s);#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDstar}}); + + registry.add("hMassVsPtK0s", "K0^{s} candidates;#it{p}_{T} (GeV/#it{c});inv. mass (#pi^{#plus}#pi^{#minus}) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassKzero}}); + registry.add("hMassVsPtLambda", "Lambda candidates;#it{p}_{T} (GeV/#it{c});inv. mass (p #pi^{#minus}) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassLambda}}); + registry.add("hdEdxVsP", "Tracks;#it{p} (GeV/#it{c});d#it{E}/d#it{x};entries", {HistType::kTH2F, {axisP, axisDeDx}}); + + registry.add("hMassDs1", "Ds1 candidates;m_{Ds1} - m_{D^{*}} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMassDsj}}); + registry.add("hMassDsStar2", "Ds^{*}2 candidates; Ds^{*}2 - m_{D^{#plus}} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMassDsj}}); + registry.add("hMassXcRes", "XcRes candidates; XcRes - m_{D^{#plus}} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{300, 1.1, 1.4}}}); + registry.add("hMassDstarProton", "D^{*}-proton candidates;m_{D^{*}p} - m_{D^{*}} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0.9, 1.4}}}); registry.add("hDType", "D selection flag", {HistType::kTH1F, {{5, -2.5, 2.5}}}); + registry.add("hMCRecCounter", "Number of Reconstructed MC Matched candidates per channel", {HistType::kTH1F, {{17, -8.5, 8.5}}}); + registry.add("hMCRecDebug", "Debug of MC Reco", {HistType::kTH1F, {{16, -0.5, 15.5}}}); + registry.add("hMCRecOrigin", "Origin of Matched particles", {HistType::kTH1F, {{3, -0.5, 2.5}}}); + + registry.add("hMCGenCounter", "Number of Generated particles; Decay Channel Flag; pT [GeV/c]", {HistType::kTH2F, {{17, -8.5, 8.5}, {100, 0, 50}}}); + registry.add("hMCSignCounter", "Sign of Generated particles", {HistType::kTH1F, {{3, -1.5, 1.5}}}); + registry.add("hMCGenOrigin", "Origin of Generated particles", {HistType::kTH1F, {{3, -0.5, 2.5}}}); + registry.add("hMCOriginCounterWrongDecay", "Origin of Generated particles in Wrong decay", {HistType::kTH1F, {{3, -0.5, 2.5}}}); + + if (doMcRecQa) { + registry.add("hMassVsPtK0Matched", "K0s candidates Matched ;#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassKzero}}); + registry.add("hMassVsPtD0Matched", "D0 candidates Matched ;#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDplus}}); + registry.add("hMassVsPtDstarMatched", "Dstar candidates Matched ;#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDstar}}); + registry.add("hMassVsPtDplusMatched", "Dplus candidates Matched ;#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDplus}}); + registry.add("hMassVsPtDs1Matched", "Ds1 candidates Matched ;#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDsj}}); + registry.add("hMassVsPtDs2StarMatched", "Ds2Star candidates Matched ;#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDsj}}); + registry.add("hMassVsPtK0MatchedPiToMu", "K0s candidates Matched with PiToMu decay ;#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassKzero}}); + registry.add("hMassVsPtD0MatchedPiToMu", "D0 candidates Matched with PiToMu decay ;#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDplus}}); + registry.add("hMassVsPtDstarMatchedPiToMu", "Dstar candidates Matched with PiToMu decay ;#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDstar}}); + registry.add("hMassVsPtDplusMatchedPiToMu", "Dplus candidates Matched with PiToMu decay ;#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDplus}}); + registry.add("hMassVsPtDs1MatchedPiToMu", "Ds1 candidates Matched with PiToMu decay ;#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDsj}}); + registry.add("hMassVsPtDs2StarMatchedPiToMu", "Ds2Star candidates Matched with PiToMu decay ;#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDsj}}); + registry.add("hMassVsPtD0MatchedKaToPi", "D0 candidates Matched with KaToPi decay ;#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDplus}}); + registry.add("hMassVsPtDstarMatchedKaToPi", "Dstar candidates Matched with KaToPi decay ;#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDstar}}); + registry.add("hMassVsPtDplusMatchedKaToPi", "Dplus candidates Matched with KaToPi decay ;#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDplus}}); + registry.add("hMassVsPtDs1MatchedKaToPi", "Ds1 candidates Matched with KaToPi decay ;#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDsj}}); + registry.add("hMassVsPtDs2StarMatchedKaToPi", "Ds2Star candidates Matched with KaToPi decay ;#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPt, axisMassDsj}}); + } + + // Configure CCDB access ccdb->setURL(url.value); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); ccdbApi.init(url); + runNumber = 0; lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get("GLO/Param/MatLUT")); + + // Configure DCA fitter + fitter.setPropagateToPCA(true); + fitter.setMaxR(200.); + fitter.setMinParamChange(1e-3); + fitter.setMinRelChi2Change(0.9); + fitter.setMaxDZIni(1e9); + fitter.setMaxDXYIni(4); + fitter.setMaxChi2(1e9); + fitter.setUseAbsDCA(true); + fitter.setWeightedFinalPCA(false); } + /// Basic track quality selections for V0 daughters + /// \param Tr is a track + /// \param dDaughtersIds are the IDs of the D meson daughter tracks + template + bool selectV0Daughter(Tr const& track, const std::array& dDaughtersIds) + { + // acceptance selection + if (std::abs(track.eta()) > cfgV0Cuts.etaMaxDau) { + return false; + } + // Tpc Refit + if (!(track.hasTPC())) { + return false; + } + // track quality selection + if (track.itsNCls() < cfgV0Cuts.trackNclusItsCut || + track.tpcNClsFound() < cfgV0Cuts.trackNCrossedRowsTpc || + track.tpcNClsCrossedRows() < cfgV0Cuts.trackNCrossedRowsTpc || + track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || + track.tpcNClsShared() > cfgV0Cuts.trackNsharedClusTpc) { + return false; + } + // rejection of tracks that share a daughter with the D meson + if (rejectPairsWithCommonDaughter && std::find(dDaughtersIds.begin(), dDaughtersIds.end(), track.globalIndex()) != dDaughtersIds.end()) { + return false; + } + return true; + } + + // Utility to find which v0 daughter carries the largest fraction of the mother longitudinal momentum + float alphaAP(std::array const& momA, std::array const& momB, std::array const& momC) + { + float momTot = std::sqrt(std::pow(momA[0], 2.) + std::pow(momA[1], 2.) + std::pow(momA[2], 2.)); + float lQlPos = (momB[0] * momA[0] + momB[1] * momA[1] + momB[2] * momA[2]) / momTot; + float lQlNeg = (momC[0] * momA[0] + momC[1] * momA[1] + momC[2] * momA[2]) / momTot; + return (lQlPos - lQlNeg) / (lQlPos + lQlNeg); + } + // Utility to find DCA of V0 to Primary vertex + float calculateDCAStraightToPV(float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) + { + return std::sqrt((std::pow((pvY - Y) * Pz - (pvZ - Z) * Py, 2) + std::pow((pvX - X) * Pz - (pvZ - Z) * Px, 2) + std::pow((pvX - X) * Py - (pvY - Y) * Px, 2)) / (Px * Px + Py * Py + Pz * Pz)); + } /// Basic selection of V0 candidates - /// \param v0 is the v0 candidate /// \param collision is the current collision /// \param dauTracks are the v0 daughter tracks - /// \param dDaughtersIDs are the IDs of the D meson daughter tracks + /// \param dDaughtersIds are the IDs of the D meson daughter tracks /// \return a bitmap with mass hypotesis if passes all cuts - template - inline uint8_t getSelectionMapV0(const V0& v0, const Coll& /*collision*/, const std::array& dauTracks, const std::array& dDaughtersIDs) + template + bool buildAndSelectV0(const Coll& collision, const std::array& dDaughtersIds, const std::array& dauTracks) { - uint8_t selMap{BIT(K0s) | BIT(Lambda) | BIT(AntiLambda)}; - // reject VOs that share daughters with D - if (std::find(dDaughtersIDs.begin(), dDaughtersIDs.end(), v0.posTrackId()) != dDaughtersIDs.end() || std::find(dDaughtersIDs.begin(), dDaughtersIDs.end(), v0.negTrackId()) != dDaughtersIDs.end()) { - return 0; + auto trackPos = dauTracks[0]; + auto trackNeg = dauTracks[1]; + + // single-tracks selection + if (!selectV0Daughter(trackPos, dDaughtersIds) || !selectV0Daughter(trackNeg, dDaughtersIds)) + return false; + // daughters DCA to V0's collision primary vertex + gpu::gpustd::array dcaInfo; + auto trackPosPar = getTrackPar(trackPos); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPosPar, 2.f, fitter.getMatCorrType(), &dcaInfo); + auto trackPosDcaXY = dcaInfo[0]; + auto trackNegPar = getTrackPar(trackNeg); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackNegPar, 2.f, fitter.getMatCorrType(), &dcaInfo); + auto trackNegDcaXY = dcaInfo[0]; + if (std::fabs(trackPosDcaXY) < cfgV0Cuts.dcaMaxDauToPv || std::fabs(trackNegDcaXY) < cfgV0Cuts.dcaMaxDauToPv) { + return false; + } + // vertex reconstruction + auto trackPosCov = getTrackParCov(trackPos); + auto trackNegCov = getTrackParCov(trackNeg); + int nCand = 0; + try { + nCand = fitter.process(trackPosCov, trackNegCov); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call!"; + return false; + } + if (nCand == 0) { + return false; + } + // compute candidate momentum from tracks propagated to decay vertex + auto& trackPosProp = fitter.getTrack(0); + auto& trackNegProp = fitter.getTrack(1); + trackPosProp.getPxPyPzGlo(candidateV0.momPos); + trackNegProp.getPxPyPzGlo(candidateV0.momNeg); + for (int i = 0; i < 3; ++i) { + candidateV0.mom[i] = candidateV0.momPos[i] + candidateV0.momNeg[i]; + } + candidateV0.pT = std::hypot(candidateV0.mom[0], candidateV0.mom[1]); + // topological selections: + // v0 eta + candidateV0.eta = RecoDecay::eta(candidateV0.mom); + if (std::abs(candidateV0.eta) > cfgV0Cuts.etaMax) { + return false; } - // eta of daughters - if (std::fabs(v0.negativeeta()) > minV0dauEta || std::fabs(v0.positiveeta()) > minV0dauEta) { // cut all V0 daughters with |eta| > 1. - return 0; + // daughters DCA + candidateV0.dcaDau = std::sqrt(fitter.getChi2AtPCACandidate()); + if (candidateV0.dcaDau > cfgV0Cuts.dcaDau) { + return false; } - // minimum v0radius - if (v0.v0radius() < minK0sLambdaRadius) { - return 0; + // v0 radius + const auto& vtx = fitter.getPCACandidate(); + candidateV0.radius = std::hypot(vtx[0], vtx[1]); + if (candidateV0.radius < cfgV0Cuts.radiusMin) { + return false; } - // cosine of pointing angle - auto v0CosinePa = v0.v0cosPA(); - if (v0CosinePa < minK0sLambdaCosinePa) { - return 0; + for (int i = 0; i < 3; i++) { + candidateV0.pos[i] = vtx[i]; } - // DCA V0 and V0 daughters to select for primary V0s - if (v0.dcav0topv() > maxV0DCA || v0.dcaV0daughters() > maxV0dauDCA || std::fabs(v0.dcapostopv()) < minV0dauDCA || std::fabs(v0.dcanegtopv()) < minV0dauDCA) { - return 0; + // v0 DCA to primary vertex + candidateV0.dcaV0ToPv = calculateDCAStraightToPV( + vtx[0], vtx[1], vtx[2], + candidateV0.momPos[0] + candidateV0.momNeg[0], + candidateV0.momPos[1] + candidateV0.momNeg[1], + candidateV0.momPos[2] + candidateV0.momNeg[2], + collision.posX(), collision.posY(), collision.posZ()); + if (std::abs(candidateV0.dcaV0ToPv) > cfgV0Cuts.dcaPv) { + return false; } + // v0 cosine of pointing angle + std::array primVtx = {collision.posX(), collision.posY(), collision.posZ()}; + candidateV0.cosPA = RecoDecay::cpa(primVtx, vtx, candidateV0.mom); + if (candidateV0.cosPA < cfgV0Cuts.cosPa) { + return false; + } + + // distinguish between K0s, and Lambda hypotesys + candidateV0.v0Type = {BIT(K0s) | BIT(Lambda) | BIT(AntiLambda)}; + // for lambda hypotesys define if its lambda or anti-lambda + candidateV0.alpha = alphaAP(candidateV0.mom, candidateV0.momPos, candidateV0.momNeg); + bool matter = candidateV0.alpha > 0; + CLRBIT(candidateV0.v0Type, matter ? AntiLambda : Lambda); + auto massPos = matter ? o2::constants::physics::MassProton : o2::constants::physics::MassPionCharged; + auto massNeg = matter ? o2::constants::physics::MassPionCharged : o2::constants::physics::MassProton; // mass hypotesis - if (std::fabs(v0.mK0Short() - MassK0) > deltaMassK0s) { - CLRBIT(selMap, K0s); + candidateV0.mLambda = RecoDecay::m(std::array{candidateV0.momPos, candidateV0.momNeg}, std::array{massPos, massNeg}); + candidateV0.mK0Short = RecoDecay::m(std::array{candidateV0.momPos, candidateV0.momNeg}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged}); + if (std::fabs(candidateV0.mK0Short - MassK0) > cfgV0Cuts.deltaMassK0s) { + CLRBIT(candidateV0.v0Type, K0s); + } + if (std::fabs(candidateV0.mLambda - MassLambda0) > cfgV0Cuts.deltaMassLambda) { + CLRBIT(candidateV0.v0Type, Lambda); + CLRBIT(candidateV0.v0Type, AntiLambda); + } + // PID + if (TESTBIT(candidateV0.v0Type, K0s)) { + if ((trackPos.hasTPC() && std::fabs(trackPos.tpcNSigmaPi()) > cfgV0Cuts.nSigmaTpc) || + (trackNeg.hasTPC() && std::fabs(trackNeg.tpcNSigmaPi()) > cfgV0Cuts.nSigmaTpc)) + CLRBIT(candidateV0.v0Type, K0s); + } + if (TESTBIT(candidateV0.v0Type, Lambda)) { + if ((trackPos.hasTPC() && std::fabs(trackPos.tpcNSigmaPr()) > cfgV0Cuts.nSigmaTpc) || + (trackPos.hasTOF() && std::fabs(trackPos.tofNSigmaPr()) > cfgV0Cuts.nSigmaTofPr) || + (trackNeg.hasTPC() && std::fabs(trackNeg.tpcNSigmaPi()) > cfgV0Cuts.nSigmaTpc)) + CLRBIT(candidateV0.v0Type, Lambda); + } + if (TESTBIT(candidateV0.v0Type, AntiLambda)) { + if ((trackPos.hasTPC() && std::fabs(trackPos.tpcNSigmaPi()) > cfgV0Cuts.nSigmaTpc) || + (trackNeg.hasTPC() && std::fabs(trackNeg.tpcNSigmaPr()) > cfgV0Cuts.nSigmaTpc) || + (trackNeg.hasTOF() && std::fabs(trackNeg.tofNSigmaPr()) > cfgV0Cuts.nSigmaTofPr)) + CLRBIT(candidateV0.v0Type, AntiLambda); } - if (std::fabs(v0.mLambda() - MassLambda0) > deltaMassLambda) { - CLRBIT(selMap, Lambda); + if (candidateV0.v0Type == 0) { + return false; } - if (std::fabs(v0.mAntiLambda() - MassLambda0) > deltaMassLambda) { - CLRBIT(selMap, AntiLambda); + return true; + } + + /// Basic selection of tracks + /// \param track is the track + /// \param dDaughtersIds are the IDs of the D meson daughter tracks + /// \return true if passes all cuts + template + bool isTrackSelected(const Tr& track, const std::array& dDaughtersIds) + { + + if (rejectPairsWithCommonDaughter && std::find(dDaughtersIds.begin(), dDaughtersIds.end(), track.globalIndex()) != dDaughtersIds.end()) { + return false; } - // PID (Lambda/AntiLambda only) - float nSigmaPrTpc[2] = {dauTracks[0].tpcNSigmaPr(), dauTracks[1].tpcNSigmaPr()}; - float nSigmaPrTof[2] = {dauTracks[0].tofNSigmaPr(), dauTracks[1].tofNSigmaPr()}; - if (TESTBIT(selMap, Lambda) && ((dauTracks[0].hasTPC() && std::fabs(nSigmaPrTpc[0]) > maxNsigmaPrForLambda) || (dauTracks[0].hasTOF() && std::fabs(nSigmaPrTof[0]) > maxNsigmaPrForLambda))) { - CLRBIT(selMap, Lambda); + + switch (cfgSingleTrackCuts.setTrackSelections) { + case 1: + if (!track.isGlobalTrackWoDCA()) { + return false; + } + break; + case 2: + if (!track.isGlobalTrack()) { + return false; + } + break; + case 3: + if (!track.isQualityTrackITS()) { + return false; + } + break; + } + + if (track.pt() < cfgSingleTrackCuts.minPt) { + return false; } - if (TESTBIT(selMap, AntiLambda) && ((dauTracks[1].hasTPC() && std::fabs(nSigmaPrTpc[1]) > maxNsigmaPrForLambda) || (dauTracks[1].hasTOF() && std::fabs(nSigmaPrTof[1]) > maxNsigmaPrForLambda))) { - CLRBIT(selMap, AntiLambda); + + if (std::abs(track.eta()) > cfgSingleTrackCuts.maxEta) { + return false; + } + + if (!track.hasTPC()) { + return false; + } + + bool isPion = std::abs(track.tpcNSigmaPi()) < cfgSingleTrackCuts.maxNsigmaTpcPi; + bool isKaon = std::abs(track.tpcNSigmaKa()) < cfgSingleTrackCuts.maxNsigmaTpcKa; + bool isProton = std::abs(track.tpcNSigmaPr()) < cfgSingleTrackCuts.maxNsigmaTpcPr; + + if (!isPion && !isKaon && !isProton) { // we keep the track if is it compatible with at least one of the PID hypotheses selected + return false; + } + + return true; + } + + /// Function for filling MC reco information in the tables + /// \param particlesMc is the table with MC particles + /// \param vecDaughtersReso is the vector with all daughter tracks (bachelor pion in last position) + /// \param indexHfCandCharm is the index of the charm-hadron bachelor in the reduced table + /// \param indexCandV0 is the index of the v0 bachelor in the reduced table + template + void fillMcRecoInfo(const PParticles& particlesMc, + const std::vector& vecDaughtersReso, + int& indexHfCandCharm, + int& indexCandV0) + { + + // we check the MC matching to be stored + int8_t sign{0}; + int8_t signDStar{0}; + int8_t signDPlus{0}; + int8_t signD0{0}; + int8_t signV0{0}; + int8_t flag{0}; + int8_t debug{0}; + int8_t origin{0}; + int8_t nPiToMuReso{0}, nPiToMuV0, nPiToMuD0{0}, nPiToMuDstar{0}, nPiToMuDplus{0}; + int8_t nKaToPiReso{0}, nKaToPiV0, nKaToPiD0{0}, nKaToPiDstar{0}, nKaToPiDplus{0}; + std::vector idxBhadMothers{}; + float motherPt{-1.f}; + int indexRecReso{-1}, indexRecDstar{-1}, indexRecDplus{-1}, indexRecD0{-1}, indexRecK0{-1}, indexRecResoPartReco{-1}; + + if constexpr (decChannel == DecayChannel::DstarV0) { + // Ds1 → D* K0 → (D0 π+) K0s → ((K-π+) π+)(π+π-) + indexRecD0 = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersReso[0], vecDaughtersReso[1]}, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &signD0, 1, &nPiToMuD0, &nKaToPiD0); + indexRecK0 = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersReso[3], vecDaughtersReso[4]}, kK0, std::array{+kPiPlus, -kPiPlus}, true, &signV0, 2, &nPiToMuV0, &nKaToPiV0); + if (indexRecD0 > -1) { + indexRecDstar = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersReso[0], vecDaughtersReso[1], vecDaughtersReso[2]}, Pdg::kDStar, std::array{-kKPlus, +kPiPlus, +kPiPlus}, true, &signDStar, 2, &nPiToMuDstar, &nKaToPiDstar); + } + if (indexRecD0 > -1 && indexRecDstar > -1 && indexRecK0 > -1) { + indexRecReso = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersReso[0], vecDaughtersReso[1], vecDaughtersReso[2], vecDaughtersReso[3], vecDaughtersReso[4]}, Pdg::kDS1, std::array{+kPiPlus, -kKPlus, +kPiPlus, +kPiPlus, -kPiPlus}, true, &sign, 3, &nPiToMuReso, &nKaToPiReso); + if (indexRecReso > -1 && nPiToMuReso == 0 && nKaToPiReso == 0) { + flag = sign * DecayTypeMc::Ds1ToDStarK0ToD0PiK0s; + } else if (indexRecReso > -1 && nPiToMuReso >= 1 && nKaToPiReso == 0) { + flag = sign * DecayTypeMc::Ds1ToDStarK0ToD0PiK0sOneMu; + } + } + + // Ds1+ not matched: we check if it is partially reco + if (indexRecReso < 0) { + indexRecResoPartReco = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersReso[0], vecDaughtersReso[1], vecDaughtersReso[2], vecDaughtersReso[3], vecDaughtersReso[4]}, Pdg::kDS1, std::array{+kPiPlus, -kKPlus, +kPiPlus, +kPiPlus, -kPiPlus}, true, &sign, 3); + indexRecDplus = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersReso[0], vecDaughtersReso[1], vecDaughtersReso[2]}, Pdg::kDPlus, std::array{+kPiPlus, -kKPlus, +kPiPlus}, true, &signDPlus, 2); + if (indexRecResoPartReco > -1) { // we look for decays of D* or D0 with more daughters + if (indexRecDstar < 0 && indexRecK0 > -1) { + auto indexRecDstarPartReco = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersReso[0], vecDaughtersReso[1], vecDaughtersReso[2]}, Pdg::kDStar, std::array{-kKPlus, +kPiPlus, +kPiPlus}, true, &signDStar, 3); + if (indexRecDstarPartReco > -1) { + if (indexRecDplus > -1) { // Ds1 -> D* K0s -> D+ π0 K0s + flag = sign * DecayTypeMc::Ds1ToDStarK0ToDPlusPi0K0s; + } else { + auto indexRecDzeroPartReco = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersReso[0], vecDaughtersReso[1]}, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &signD0, 2); + if (indexRecDzeroPartReco > -1) { // Ds1 -> D* K0s -> D0 π+ K0s -> K- π+ π0 π+ K0s + flag = sign * DecayTypeMc::Ds1ToDStarK0ToD0PiK0sPart; + } + } + } + } + } else { // we look for D* not matched, but all the other ones yes, we check if we only lost the soft pion + if (indexRecD0 > -1 && indexRecK0 > -1 && indexRecDstar < 0) { + indexRecResoPartReco = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersReso[0], vecDaughtersReso[1], vecDaughtersReso[3], vecDaughtersReso[4]}, Pdg::kDS1, std::array{+kPiPlus, -kKPlus, +kPiPlus, -kPiPlus}, true, &sign, 3); + if (indexRecResoPartReco > -1) { + flag = sign * DecayTypeMc::Ds1ToDStarK0ToD0NoPiK0sPart; + } + } + } + } + if (flag != 0) { + int indexParticle{-1}; + if (indexRecReso > -1) { + indexParticle = indexRecReso; + } else if (indexRecResoPartReco > -1) { + indexParticle = indexRecResoPartReco; + } + auto particleReso = particlesMc.iteratorAt(indexParticle); + origin = RecoDecay::getCharmHadronOrigin(particlesMc, particleReso, false, &idxBhadMothers); + motherPt = particleReso.pt(); + } + if (doMcRecQa) { + if (indexRecReso > -1) { + if (nPiToMuReso == 0 && nKaToPiReso == 0) { + registry.fill(HIST("hMassVsPtDs1Matched"), varUtils.ptD, varUtils.invMassKPiPiV0 - varUtils.invMassD); + } + if (nPiToMuReso >= 1) { + registry.fill(HIST("hMassVsPtDs1MatchedPiToMu"), varUtils.ptD, varUtils.invMassKPiPiV0 - varUtils.invMassD); + } + if (nKaToPiReso >= 1) { + registry.fill(HIST("hMassVsPtDs1MatchedKaToPi"), varUtils.ptD, varUtils.invMassKPiPiV0 - varUtils.invMassD); + } + } + if (indexRecD0 > -1) { + if (nPiToMuD0 == 0 && nKaToPiD0 == 0) { + registry.fill(HIST("hMassVsPtD0Matched"), varUtils.ptD, varUtils.invMassDdau); + } + if (nPiToMuD0 >= 1) { + registry.fill(HIST("hMassVsPtD0MatchedPiToMu"), varUtils.ptD, varUtils.invMassDdau); + } + if (nKaToPiD0 >= 1) { + registry.fill(HIST("hMassVsPtD0MatchedKaToPi"), varUtils.ptD, varUtils.invMassDdau); + } + } + if (indexRecDstar > -1) { + if (nPiToMuDstar == 0 && nKaToPiDstar == 0) { + registry.fill(HIST("hMassVsPtDstarMatched"), varUtils.ptD, varUtils.invMassD - varUtils.invMassDdau); + } + if (nPiToMuDstar >= 1) { + registry.fill(HIST("hMassVsPtDstarMatchedPiToMu"), varUtils.ptD, varUtils.invMassD - varUtils.invMassDdau); + } + if (nKaToPiDstar >= 1) { + registry.fill(HIST("hMassVsPtDstarMatchedKaToPi"), varUtils.ptD, varUtils.invMassD - varUtils.invMassDdau); + } + } + if (indexRecK0 > -1) { + if (nPiToMuV0 == 0 && nKaToPiV0 == 0) { + registry.fill(HIST("hMassVsPtK0Matched"), candidateV0.pT, candidateV0.mK0Short); + } + if (nPiToMuV0 >= 1) { + registry.fill(HIST("hMassVsPtK0MatchedPiToMu"), candidateV0.pT, candidateV0.mK0Short); + } + if (nKaToPiV0 >= 1) { + registry.fill(HIST("hMassVsPtK0MatchedKaToPi"), candidateV0.pT, candidateV0.mK0Short); + } + } + } + } else if constexpr (decChannel == DecayChannel::DplusV0) { + // Ds2Star → D+ K0 → (π+K-π+) K0s → (π+K-π+)(π+π-) + indexRecK0 = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersReso[3], vecDaughtersReso[4]}, kK0, std::array{+kPiPlus, -kPiPlus}, true, &signV0, 2, &nPiToMuV0, &nKaToPiV0); + indexRecDplus = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersReso[0], vecDaughtersReso[1], vecDaughtersReso[2]}, Pdg::kDPlus, std::array{+kPiPlus, -kKPlus, +kPiPlus}, true, &signDPlus, 2, &nPiToMuDplus, &nKaToPiDplus); + if (indexRecK0 > -1 && indexRecDplus > -1) { + indexRecReso = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersReso[0], vecDaughtersReso[1], vecDaughtersReso[2], vecDaughtersReso[3], vecDaughtersReso[4]}, Pdg::kDS2Star, std::array{+kPiPlus, -kKPlus, +kPiPlus, +kPiPlus, -kPiPlus}, true, &sign, 3, &nPiToMuReso, &nKaToPiReso); + if (indexRecReso > -1 && nPiToMuReso == 0 && nKaToPiReso == 0) { + flag = sign * DecayTypeMc::Ds2StarToDplusK0sToPiKaPiPiPi; + } else if (indexRecReso > -1 && nPiToMuReso >= 1 && nKaToPiReso == 0) { + flag = sign * DecayTypeMc::Ds2StarToDplusK0sOneMu; + } else if (indexRecReso < 0) { + // Verify partly reconstructed decay Ds1 -> D* K0s -> D+ π0 K0s + indexRecDstar = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersReso[0], vecDaughtersReso[1], vecDaughtersReso[2]}, Pdg::kDStar, std::array{-kKPlus, +kPiPlus, +kPiPlus}, true, &signDStar, 2); + if (indexRecDstar > -1) { + indexRecReso = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersReso[0], vecDaughtersReso[1], vecDaughtersReso[2], vecDaughtersReso[3], vecDaughtersReso[4]}, Pdg::kDS1, std::array{+kPiPlus, -kKPlus, +kPiPlus, +kPiPlus, -kPiPlus}, true, &sign, 3); + if (indexRecReso > -1) { + flag = sign * DecayTypeMc::Ds1ToDStarK0ToDPlusPi0K0s; + } + } + } + } + if (flag != 0) { + auto particleReso = particlesMc.iteratorAt(indexRecReso); + origin = RecoDecay::getCharmHadronOrigin(particlesMc, particleReso, false, &idxBhadMothers); + motherPt = particleReso.pt(); + } + if (doMcRecQa) { + if (indexRecReso > -1) { + if (nPiToMuReso == 0 && nKaToPiReso == 0) { + registry.fill(HIST("hMassVsPtDs2StarMatched"), varUtils.ptD, varUtils.invMassKPiPiV0 - varUtils.invMassD); + } + if (nPiToMuReso >= 1) { + registry.fill(HIST("hMassVsPtDs2StarMatchedPiToMu"), varUtils.ptD, varUtils.invMassKPiPiV0 - varUtils.invMassD); + } + if (nKaToPiReso >= 1) { + registry.fill(HIST("hMassVsPtDs2StarMatchedKaToPi"), varUtils.ptD, varUtils.invMassKPiPiV0 - varUtils.invMassD); + } + } + if (indexRecDplus > -1) { + if (nPiToMuDplus == 0 && nKaToPiDplus == 0) { + registry.fill(HIST("hMassVsPtDplusMatched"), varUtils.ptD, varUtils.invMassD); + } + if (nPiToMuDplus >= 1) { + registry.fill(HIST("hMassVsPtDplusMatchedPiToMu"), varUtils.ptD, varUtils.invMassD); + } + if (nKaToPiDplus >= 1) { + registry.fill(HIST("hMassVsPtDplusMatchedKaToPi"), varUtils.ptD, varUtils.invMassD); + } + } + if (indexRecK0 > -1) { + if (nPiToMuV0 == 0 && nKaToPiV0 == 0) { + registry.fill(HIST("hMassVsPtK0Matched"), candidateV0.pT, candidateV0.mK0Short); + } + if (nPiToMuV0 >= 1) { + registry.fill(HIST("hMassVsPtK0MatchedPiToMu"), candidateV0.pT, candidateV0.mK0Short); + } + if (nKaToPiV0 >= 1) { + registry.fill(HIST("hMassVsPtK0MatchedKaToPi"), candidateV0.pT, candidateV0.mK0Short); + } + } + } + } // DecayChannel::DplusV0 + if (flag != 0) { + registry.fill(HIST("hMCRecCounter"), flag); + registry.fill(HIST("hMCRecOrigin"), origin); + } else { + if (indexRecK0 > -1) { + SETBIT(debug, PartialMatchMc::K0Matched); + } + if (indexRecD0 > -1) { + SETBIT(debug, PartialMatchMc::D0Matched); + } + if (indexRecDstar > -1) { + SETBIT(debug, PartialMatchMc::DStarMatched); + } + if (indexRecDplus > -1) { + SETBIT(debug, PartialMatchMc::DPlusMatched); + } + registry.fill(HIST("hMCRecDebug"), debug); } - return selMap; + rowHfDV0McRecReduced(indexHfCandCharm, indexCandV0, flag, debug, origin, signD0, motherPt); } - template - void runDataCreation(aod::Collision const& collision, + template + void runDataCreation(Coll const& collision, CCands const& candsD, - aod::V0Datas const& V0s, - BigTracksPID const&, + BBach const& bachelors, + Tr const&, + PParticles const& particlesMc, aod::BCsWithTimestamps const&) { // helpers for ReducedTables filling @@ -225,28 +748,36 @@ struct HfDataCreatorCharmResoReduced { // std::map where the key is the V0.globalIndex() and // the value is the V0 index in the table of the selected v0s std::map selectedV0s; + std::map selectedTracks; bool fillHfReducedCollision = false; - auto bc = collision.bc_as(); - initCCDB(bc, runNumber, ccdb, ccdbPathGrpMag, lut, false); + auto bc = collision.template bc_as(); + if (runNumber != bc.runNumber()) { + LOG(info) << ">>>>>>>>>>>> Current run number: " << runNumber; + initCCDB(bc, runNumber, ccdb, ccdbPathGrpMag, lut, false); + bz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << ">>>>>>>>>>>> Magnetic field: " << bz; + } + fitter.setBz(bz); // loop on D candidates for (const auto& candD : candsD) { // initialize variables depending on decay channel bool fillHfCandD = false; - float invMassD; - float massD; - float massV0{0.}; std::array pVecD; + std::array pVecProng2; std::array secondaryVertexD; std::array prongIdsD; - uint8_t v0type; int8_t dtype; std::array bdtScores; - if constexpr (DecayChannel == DecayChannel::DstarV0) { - if (candD.signSoftPi() > 0) - invMassD = candD.invMassDstar(); - else - invMassD = candD.invMassAntiDstar() - candD.invMassD0Bar(); - massD = MassDStar; + std::vector charmHadDauTracks{}; + varUtils.ptD = candD.pt(); + if constexpr (DecayChannel == DecayChannel::DstarV0 || DecayChannel == DecayChannel::DstarTrack) { + if (candD.signSoftPi() > 0) { + varUtils.invMassD = candD.invMassDstar(); + varUtils.invMassDdau = candD.invMassD0(); + } else { + varUtils.invMassD = candD.invMassAntiDstar(); + varUtils.invMassDdau = candD.invMassD0Bar(); + } pVecD = candD.pVector(); secondaryVertexD[0] = candD.xSecondaryVertexD0(); secondaryVertexD[1] = candD.ySecondaryVertexD0(); @@ -254,14 +785,18 @@ struct HfDataCreatorCharmResoReduced { prongIdsD[0] = candD.prong0Id(); prongIdsD[1] = candD.prong1Id(); prongIdsD[2] = candD.prongPiId(); + pVecProng2 = candD.pVecSoftPi(); + charmHadDauTracks.push_back(candD.template prong0_as
()); + charmHadDauTracks.push_back(candD.template prong1_as
()); + charmHadDauTracks.push_back(candD.template prongPi_as
()); dtype = candD.signSoftPi() * DType::Dstar; if constexpr (withMl) { std::copy(candD.mlProbDstarToD0Pi().begin(), candD.mlProbDstarToD0Pi().end(), bdtScores.begin()); } + registry.fill(HIST("hMassVsPtDstarAll"), candD.pt(), varUtils.invMassD - varUtils.invMassDdau); } else if constexpr (DecayChannel == DecayChannel::DplusV0) { - auto prong0 = candD.template prong0_as(); - invMassD = hfHelper.invMassDplusToPiKPi(candD); - massD = MassDPlus; + auto prong0 = candD.template prong0_as
(); + varUtils.invMassD = hfHelper.invMassDplusToPiKPi(candD); pVecD = candD.pVector(); secondaryVertexD[0] = candD.xSecondaryVertex(); secondaryVertexD[1] = candD.ySecondaryVertex(); @@ -269,106 +804,184 @@ struct HfDataCreatorCharmResoReduced { prongIdsD[0] = candD.prong0Id(); prongIdsD[1] = candD.prong1Id(); prongIdsD[2] = candD.prong2Id(); + pVecProng2 = candD.pVectorProng2(); dtype = static_cast(prong0.sign() * DType::Dplus); + charmHadDauTracks.push_back(candD.template prong0_as
()); + charmHadDauTracks.push_back(candD.template prong1_as
()); + charmHadDauTracks.push_back(candD.template prong2_as
()); if constexpr (withMl) { std::copy(candD.mlProbDplusToPiKPi().begin(), candD.mlProbDplusToPiKPi().end(), bdtScores.begin()); } + registry.fill(HIST("hMassVsPtDplusAll"), candD.pt(), varUtils.invMassD); } // else if - // Loop on V0 candidates - for (const auto& v0 : V0s) { - auto posTrack = v0.posTrack_as(); - auto negTrack = v0.negTrack_as(); - // Apply selsection - v0type = getSelectionMapV0(v0, collision, std::array{posTrack, negTrack}, prongIdsD); - if (v0type == 0) { - continue; + // Get single track variables + float chi2TpcDauMax = -1.f; + int nItsClsDauMin = 8, nTpcCrossRowsDauMin = 200; + for (const auto& charmHadTrack : charmHadDauTracks) { + if (charmHadTrack.itsNCls() < nItsClsDauMin) { + nItsClsDauMin = charmHadTrack.itsNCls(); } - // propagate V0 to primary vertex (if enabled) - std::array pVecV0 = {v0.px(), v0.py(), v0.pz()}; - if (propagateV0toPV) { - std::array pVecV0Orig = {v0.px(), v0.py(), v0.pz()}; - std::array posVecV0 = {v0.x(), v0.y(), v0.z()}; - gpu::gpustd::array dcaInfo; - auto trackParK0 = o2::track::TrackPar(posVecV0, pVecV0Orig, 0, true); - trackParK0.setPID(o2::track::PID::K0); - trackParK0.setAbsCharge(0); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParK0, 2.f, matCorr, &dcaInfo); - getPxPyPz(trackParK0, pVecV0); + if (charmHadTrack.tpcNClsCrossedRows() < nTpcCrossRowsDauMin) { + nTpcCrossRowsDauMin = charmHadTrack.tpcNClsCrossedRows(); } - float ptV0 = RecoDecay::pt(pVecV0); // fill histos - registry.fill(HIST("hPtV0"), ptV0); - registry.fill(HIST("hV0Type"), v0type); - if (TESTBIT(v0type, K0s)) { - massV0 = MassK0; - auto invMassDV0 = RecoDecay::m(std::array{pVecD, pVecV0}, std::array{massD, massV0}); - registry.fill(HIST("hMassK0s"), v0.mK0Short()); - switch (DecayChannel) { - case DecayChannel::DstarV0: - registry.fill(HIST("hMassDs1"), invMassDV0); - break; - case DecayChannel::DplusV0: - registry.fill(HIST("hMassDsStar2"), invMassDV0); - break; - default: - break; - } + if (charmHadTrack.tpcChi2NCl() > chi2TpcDauMax) { + chi2TpcDauMax = charmHadTrack.tpcChi2NCl(); } - if (TESTBIT(v0type, Lambda)) { - massV0 = MassLambda0; - auto invMassDV0 = RecoDecay::m(std::array{pVecD, pVecV0}, std::array{massD, massV0}); - registry.fill(HIST("hMassLambda"), v0.mLambda()); - if (DecayChannel == DecayChannel::DplusV0) { - registry.fill(HIST("hMassXcRes"), invMassDV0); + } + + if constexpr (DecayChannel == DecayChannel::DplusV0 || DecayChannel == DecayChannel::DstarV0) { + // Loop on V0 candidates + for (const auto& v0 : bachelors) { + auto trackPos = v0.template posTrack_as
(); + auto trackNeg = v0.template negTrack_as
(); + // Apply selsection + auto v0DauTracks = std::array{trackPos, trackNeg}; + if (!buildAndSelectV0(collision, prongIdsD, v0DauTracks)) { + continue; } - } - if (TESTBIT(v0type, AntiLambda)) { - massV0 = MassLambda0; - auto invMassDV0 = RecoDecay::m(std::array{pVecD, pVecV0}, std::array{massD, massV0}); - registry.fill(HIST("hMassLambda"), v0.mAntiLambda()); - if (DecayChannel == DecayChannel::DplusV0) { - registry.fill(HIST("hMassXcRes"), invMassDV0); + // Get single track variables + float chi2TpcDauV0Max = -1.f; + int nItsClsDauV0Min = 8, nTpcCrossRowsDauV0Min = 200; + for (const auto& v0Track : v0DauTracks) { + if (v0Track.itsNCls() < nItsClsDauV0Min) { + nItsClsDauV0Min = v0Track.itsNCls(); + } + if (v0Track.tpcNClsCrossedRows() < nTpcCrossRowsDauV0Min) { + nTpcCrossRowsDauV0Min = v0Track.tpcNClsCrossedRows(); + } + if (v0Track.tpcChi2NCl() > chi2TpcDauV0Max) { + chi2TpcDauV0Max = v0Track.tpcChi2NCl(); + } } - } - // fill V0 table - // if information on V0 already stored, go to next V0 - if (!selectedV0s.count(v0.globalIndex())) { - hfCandV0(v0.posTrackId(), v0.negTrackId(), - indexHfReducedCollision, - v0.x(), v0.y(), v0.z(), - v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), - pVecV0[0], pVecV0[1], pVecV0[2], - v0.v0cosPA(), - v0.dcav0topv(), - v0.v0radius(), - v0type); - selectedV0s[v0.globalIndex()] = hfCandV0.lastIndex(); - } - fillHfCandD = true; - } // V0 loop + // propagate V0 to primary vertex (if enabled) + if (propagateV0toPV) { + std::array pVecV0Orig = {candidateV0.mom[0], candidateV0.mom[1], candidateV0.mom[2]}; + gpu::gpustd::array dcaInfo; + auto trackParK0 = o2::track::TrackPar(candidateV0.pos, pVecV0Orig, 0, true); + trackParK0.setPID(o2::track::PID::K0); + trackParK0.setAbsCharge(0); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParK0, 2.f, matCorr, &dcaInfo); + getPxPyPz(trackParK0, candidateV0.mom); + } + if (TESTBIT(candidateV0.v0Type, K0s)) { + if constexpr (DecayChannel == DecayChannel::DplusV0) { + varUtils.invMassKPiPiV0 = RecoDecay::m(std::array{candD.pVectorProng0(), candD.pVectorProng1(), candD.pVectorProng2(), candidateV0.mom}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassK0}); + // varUtils.ptReso = RecoDecay::pt(std::array{candD.pVectorProng0(), candD.pVectorProng1(), candD.pVectorProng2(), candidateV0.mom}); + } else if (DecayChannel == DecayChannel::DstarV0) { + // varUtils.ptReso = RecoDecay::pt(std::array{candD.pVectorProng0(), candD.pVectorProng1(), candD.pVecSoftPi(), candidateV0.mom}); + if (candD.signSoftPi() > 0) { + varUtils.invMassKPiPiV0 = RecoDecay::m(std::array{candD.pVectorProng0(), candD.pVectorProng1(), candD.pVecSoftPi(), candidateV0.mom}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassK0}); + } else { + varUtils.invMassKPiPiV0 = RecoDecay::m(std::array{candD.pVectorProng1(), candD.pVectorProng0(), candD.pVecSoftPi(), candidateV0.mom}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassK0}); + } + } + registry.fill(HIST("hMassVsPtK0s"), candidateV0.pT, candidateV0.mK0Short); + if constexpr (DecayChannel == DecayChannel::DstarV0) { + registry.fill(HIST("hMassDs1"), varUtils.invMassKPiPiV0 - varUtils.invMassD); + } else if constexpr (DecayChannel == DecayChannel::DplusV0) { + registry.fill(HIST("hMassDsStar2"), varUtils.invMassKPiPiV0 - varUtils.invMassD); + } + } + bool isLambda = TESTBIT(candidateV0.v0Type, Lambda); + bool isAntiLambda = TESTBIT(candidateV0.v0Type, AntiLambda); + if (isLambda || isAntiLambda) { + if constexpr (DecayChannel == DecayChannel::DplusV0) { + varUtils.invMassKPiPiV0 = RecoDecay::m(std::array{candD.pVectorProng0(), candD.pVectorProng1(), candD.pVectorProng2(), candidateV0.mom}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassLambda0}); + } else if (DecayChannel == DecayChannel::DstarV0) { + if (candD.signSoftPi() > 0) { + varUtils.invMassKPiPiV0 = RecoDecay::m(std::array{candD.pVectorProng0(), candD.pVectorProng1(), candD.pVecSoftPi(), candidateV0.mom}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassLambda0}); + } else { + varUtils.invMassKPiPiV0 = RecoDecay::m(std::array{candD.pVectorProng1(), candD.pVectorProng0(), candD.pVecSoftPi(), candidateV0.mom}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassLambda0}); + } + } + if (isLambda || isAntiLambda) { + registry.fill(HIST("hMassVsPtLambda"), candidateV0.pT, candidateV0.mLambda); + } + if constexpr (DecayChannel == DecayChannel::DplusV0) { + registry.fill(HIST("hMassXcRes"), varUtils.invMassKPiPiV0 - varUtils.invMassD); + } + } + // fill V0 table + // if information on V0 already stored, go to next V0 + if (!selectedV0s.count(v0.globalIndex())) { + hfCandV0(trackPos.globalIndex(), trackNeg.globalIndex(), + indexHfReducedCollision, + candidateV0.pos[0], candidateV0.pos[1], candidateV0.pos[2], + candidateV0.momPos[0], candidateV0.momPos[1], candidateV0.momPos[2], + candidateV0.momNeg[0], candidateV0.momNeg[1], candidateV0.momNeg[2], + candidateV0.cosPA, + candidateV0.dcaV0ToPv, + nItsClsDauV0Min, nTpcCrossRowsDauV0Min, chi2TpcDauV0Max, + candidateV0.v0Type); + selectedV0s[v0.globalIndex()] = hfCandV0.lastIndex(); + } + fillHfCandD = true; + // Optional filling of MC Rec table + if constexpr (doMc) { + std::vector charmResoDauTracks{}; + for (const auto& track : charmHadDauTracks) { + charmResoDauTracks.push_back(track); + } + charmResoDauTracks.push_back(trackPos); + charmResoDauTracks.push_back(trackNeg); + int indexHfCandCharm = hfCandD.lastIndex() + 1; + int indexHfCandV0 = hfCandV0.lastIndex(); + fillMcRecoInfo(particlesMc, charmResoDauTracks, indexHfCandCharm, indexHfCandV0); + } + } // V0 loop + } else if constexpr (DecayChannel == DecayChannel::DstarTrack) { + for (const auto& trackIndex : bachelors) { + auto track = trackIndex.template track_as
(); + if (!isTrackSelected(track, prongIdsD)) { + continue; + } + + // if the track has been reassociated, re-propagate it to PV (minor difference) + auto trackParCovTrack = getTrackParCov(track); + o2::gpu::gpustd::array dcaTrack{track.dcaXY(), track.dcaZ()}; + std::array pVecTrack = track.pVector(); + if (track.collisionId() != collision.globalIndex()) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParCovTrack, 2.f, matCorr, &dcaTrack); + getPxPyPz(trackParCovTrack, pVecTrack); + } + + registry.fill(HIST("hdEdxVsP"), track.p(), track.tpcSignal()); + float invMassKPiPiP{0.f}; + if (candD.signSoftPi() > 0) { + invMassKPiPiP = RecoDecay::m(std::array{candD.pVectorProng0(), candD.pVectorProng1(), candD.pVecSoftPi(), pVecTrack}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassProton}); + } else { + invMassKPiPiP = RecoDecay::m(std::array{candD.pVectorProng1(), candD.pVectorProng0(), candD.pVecSoftPi(), pVecTrack}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassProton}); + } + registry.fill(HIST("hMassDstarProton"), invMassKPiPiP - varUtils.invMassD); + if (!selectedTracks.count(track.globalIndex())) { + hfTrackNoParam(indexHfReducedCollision, + track.px(), track.py(), track.pz(), track.sign(), + track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), + track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), + track.hasTOF(), track.hasTPC(), track.itsNCls(), track.tpcNClsCrossedRows(), track.tpcChi2NCl()); + selectedTracks[track.globalIndex()] = hfTrackNoParam.lastIndex(); + } + fillHfCandD = true; + } // track loop + } if (fillHfCandD) { // fill candDplus table only once per D candidate, only if at least one V0 is found hfCandD(prongIdsD[0], prongIdsD[1], prongIdsD[2], indexHfReducedCollision, secondaryVertexD[0], secondaryVertexD[1], secondaryVertexD[2], - invMassD, - pVecD[0], pVecD[1], pVecD[2], - dtype); + candD.pxProng0(), candD.pyProng0(), candD.pzProng0(), + candD.pxProng1(), candD.pyProng1(), candD.pzProng1(), + pVecProng2[0], pVecProng2[1], pVecProng2[2], + nItsClsDauMin, nTpcCrossRowsDauMin, chi2TpcDauMax, dtype); if constexpr (withMl) { - hfCandDMl(bdtScores[0], bdtScores[1], bdtScores[2]); + hfCandDMl(bdtScores[0], bdtScores[1], bdtScores[2], -1., -1., -1.); } fillHfReducedCollision = true; - switch (DecayChannel) { - case DecayChannel::DstarV0: - registry.fill(HIST("hMassDstar"), invMassD); - registry.fill(HIST("hPtDstar"), candD.pt()); - break; - case DecayChannel::DplusV0: - registry.fill(HIST("hMassDplus"), invMassD); - registry.fill(HIST("hPtDplus"), candD.pt()); - break; - default: - break; + if constexpr (DecayChannel == DecayChannel::DstarV0 || DecayChannel == DecayChannel::DstarTrack) { + registry.fill(HIST("hMassVsPtDstarPaired"), candD.pt(), varUtils.invMassD - varUtils.invMassDdau); + } else if constexpr (DecayChannel == DecayChannel::DplusV0) { + registry.fill(HIST("hMassVsPtDplusPaired"), candD.pt(), varUtils.invMassD); } registry.fill(HIST("hDType"), dtype); } @@ -379,85 +992,385 @@ struct HfDataCreatorCharmResoReduced { return; } registry.fill(HIST("hEvents"), 1 + Event::DV0Selected); + float centrality = -1.f; + uint16_t hfRejMap = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); // fill collision table if it contains a DPi pair a minima - hfReducedCollision(collision.posX(), collision.posY(), collision.posZ()); + hfReducedCollision(collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), hfRejMap, bz); } // run data creation - void processDplusV0(aod::Collisions const& collisions, + template + void runMcGen(aod::McParticles const& particlesMc) + { + // Match generated particles. + for (const auto& particle : particlesMc) { + int8_t sign{0}; + int8_t flag{0}; + int8_t signDStar{0}; + int8_t signDPlus{0}; + int8_t signV0{0}; + int8_t origin = 0; + std::vector idxBhadMothers{}; + + if constexpr (decayChannel == DecayChannel::DstarV0) { + // Ds1 → D* K0 + if (RecoDecay::isMatchedMCGen(particlesMc, particle, Pdg::kDS1, std::array{static_cast(Pdg::kDStar), +kK0}, true, &sign, 1)) { + registry.fill(HIST("hMCSignCounter"), sign); + origin = RecoDecay::getCharmHadronOrigin(particlesMc, particle, false, &idxBhadMothers); + registry.fill(HIST("hMCGenOrigin"), origin); + auto candV0MC = particlesMc.rawIteratorAt(particle.daughtersIds().back()); + auto candDStarMC = particlesMc.rawIteratorAt(particle.daughtersIds().front()); + // K0 -> K0s -> π+π- + if (RecoDecay::isMatchedMCGen(particlesMc, candV0MC, kK0, std::array{+kPiPlus, -kPiPlus}, true, &signV0, 2)) { + // D* -> D0 π+ -> K-π+π+ + if (RecoDecay::isMatchedMCGen(particlesMc, candDStarMC, Pdg::kDStar, std::array{static_cast(Pdg::kD0), +static_cast(kPiPlus)}, true, &signDStar, 1)) { + auto candD0MC = particlesMc.rawIteratorAt(candDStarMC.daughtersIds().front()); + if (RecoDecay::isMatchedMCGen(particlesMc, candDStarMC, Pdg::kDStar, std::array{-kKPlus, +kPiPlus, +kPiPlus}, true, &signDStar, 2)) { + flag = signDStar * DecayTypeMc::Ds1ToDStarK0ToD0PiK0s; + } else if (RecoDecay::isMatchedMCGen(particlesMc, candD0MC, Pdg::kD0, std::array{-kKPlus, +kPiPlus, +kPiPlus, +kPi0}, true, &signDStar, 2) || + RecoDecay::isMatchedMCGen(particlesMc, candD0MC, Pdg::kD0, std::array{-kKPlus, +kPiPlus, +kPiPlus, -kPi0}, true, &signDStar, 2)) { + flag = signDStar * DecayTypeMc::Ds1ToDStarK0ToD0PiK0sPart; + } + } else if (RecoDecay::isMatchedMCGen(particlesMc, candDStarMC, Pdg::kDStar, std::array{static_cast(Pdg::kDPlus), static_cast(kGamma)}, true, &signDStar, 1) || + RecoDecay::isMatchedMCGen(particlesMc, candDStarMC, Pdg::kDStar, std::array{static_cast(Pdg::kDPlus), -static_cast(kGamma)}, true, &signDStar, 1) || + RecoDecay::isMatchedMCGen(particlesMc, candDStarMC, Pdg::kDStar, std::array{static_cast(Pdg::kDPlus), static_cast(kPi0)}, true, &signDStar, 1) || + RecoDecay::isMatchedMCGen(particlesMc, candDStarMC, Pdg::kDStar, std::array{static_cast(Pdg::kDPlus), -static_cast(kPi0)}, true, &signDStar, 1)) { + auto candDPlusMC = particlesMc.rawIteratorAt(candDStarMC.daughtersIds().front()); + if (RecoDecay::isMatchedMCGen(particlesMc, candDPlusMC, Pdg::kDPlus, std::array{+kPiPlus, -kKPlus, +kPiPlus}, true, &signDPlus, 2)) + flag = sign * DecayTypeMc::Ds1ToDStarK0ToDPlusPi0K0s; + } + } + } else { + if (std::abs(particle.pdgCode()) == Pdg::kDS1) { + origin = RecoDecay::getCharmHadronOrigin(particlesMc, particle, false, &idxBhadMothers); + registry.fill(HIST("hMCOriginCounterWrongDecay"), origin); + } + } + // save information for task + if (flag == 0) { + continue; + } + + auto ptParticle = particle.pt(); + auto yParticle = RecoDecay::y(particle.pVector(), MassDS1); + auto etaParticle = particle.eta(); + + std::array ptProngs; + std::array yProngs; + std::array etaProngs; + int counter = 0; + for (const auto& daught : particle.daughters_as()) { + ptProngs[counter] = daught.pt(); + etaProngs[counter] = daught.eta(); + yProngs[counter] = RecoDecay::y(daught.pVector(), pdg->Mass(daught.pdgCode())); + counter++; + } + registry.fill(HIST("hMCGenCounter"), flag, ptParticle); + rowHfResoMcGenReduced(flag, origin, ptParticle, yParticle, etaParticle, + ptProngs[0], yProngs[0], etaProngs[0], + ptProngs[1], yProngs[1], etaProngs[1]); + } else if constexpr (decayChannel == DecayChannel::DplusV0) { // Ds2Star → D+ K0 + if (RecoDecay::isMatchedMCGen(particlesMc, particle, Pdg::kDS2Star, std::array{static_cast(Pdg::kDPlus), +kK0}, true, &sign, 1)) { + registry.fill(HIST("hMCSignCounter"), sign); + origin = RecoDecay::getCharmHadronOrigin(particlesMc, particle, false, &idxBhadMothers); + registry.fill(HIST("hMCGenOrigin"), origin); + auto candV0MC = particlesMc.rawIteratorAt(particle.daughtersIds().back()); + auto candDPlusMC = particlesMc.rawIteratorAt(particle.daughtersIds().front()); + // K0 -> K0s -> π+π- + if (RecoDecay::isMatchedMCGen(particlesMc, candV0MC, kK0, std::array{+kPiPlus, -kPiPlus}, true, &signV0, 2)) { + // D* -> D0 π+ -> K-π+π+ + if (RecoDecay::isMatchedMCGen(particlesMc, candDPlusMC, Pdg::kDPlus, std::array{+kPiPlus, -kKPlus, +kPiPlus}, true, &signDPlus, 2)) { + flag = sign * DecayTypeMc::Ds2StarToDplusK0sToPiKaPiPiPi; + } + } + } else if (RecoDecay::isMatchedMCGen(particlesMc, particle, Pdg::kDS1, std::array{static_cast(Pdg::kDStar), +kK0}, true, &sign, 1)) { + auto candV0MC = particlesMc.rawIteratorAt(particle.daughtersIds().back()); + // K0 -> K0s -> π+π- + if (RecoDecay::isMatchedMCGen(particlesMc, candV0MC, kK0, std::array{+kPiPlus, -kPiPlus}, true, &signV0, 2)) { + auto candDStarMC = particlesMc.rawIteratorAt(particle.daughtersIds().front()); + // D* -> D+ π0/γ ->π+K-π+ π0/γ + if (RecoDecay::isMatchedMCGen(particlesMc, candDStarMC, Pdg::kDStar, std::array{static_cast(Pdg::kDPlus), static_cast(kGamma)}, true, &signDStar, 1) || + RecoDecay::isMatchedMCGen(particlesMc, candDStarMC, Pdg::kDStar, std::array{static_cast(Pdg::kDPlus), -static_cast(kGamma)}, true, &signDStar, 1) || + RecoDecay::isMatchedMCGen(particlesMc, candDStarMC, Pdg::kDStar, std::array{static_cast(Pdg::kDPlus), static_cast(kPi0)}, true, &signDStar, 1) || + RecoDecay::isMatchedMCGen(particlesMc, candDStarMC, Pdg::kDStar, std::array{static_cast(Pdg::kDPlus), -static_cast(kPi0)}, true, &signDStar, 1)) { + auto candDPlusMC = particlesMc.rawIteratorAt(candDStarMC.daughtersIds().front()); + if (RecoDecay::isMatchedMCGen(particlesMc, candDPlusMC, Pdg::kDPlus, std::array{+kPiPlus, -kKPlus, +kPiPlus}, true, &signDPlus, 2)) + flag = sign * DecayTypeMc::Ds1ToDStarK0ToDPlusPi0K0s; + } + } + } else { + if (std::abs(particle.pdgCode()) == Pdg::kDS2Star) { + origin = RecoDecay::getCharmHadronOrigin(particlesMc, particle, false, &idxBhadMothers); + // LOGF(info, "Found DS2Star that decays into %d, %d", particlesMc.rawIteratorAt(particle.daughtersIds().front()).pdgCode(),particlesMc.rawIteratorAt(particle.daughtersIds().back()).pdgCode()); + registry.fill(HIST("hMCOriginCounterWrongDecay"), origin); + } + } + // save information for task + if (flag == 0) { + continue; + } + + auto ptParticle = particle.pt(); + auto yParticle = RecoDecay::y(particle.pVector(), MassDS2Star); + auto etaParticle = particle.eta(); + + std::array ptProngs; + std::array yProngs; + std::array etaProngs; + int counter = 0; + for (const auto& daught : particle.daughters_as()) { + ptProngs[counter] = daught.pt(); + etaProngs[counter] = daught.eta(); + yProngs[counter] = RecoDecay::y(daught.pVector(), pdg->Mass(daught.pdgCode())); + counter++; + } + registry.fill(HIST("hMCGenCounter"), flag, ptParticle); + rowHfResoMcGenReduced(flag, origin, ptParticle, yParticle, etaParticle, + ptProngs[0], yProngs[0], etaProngs[0], + ptProngs[1], yProngs[1], etaProngs[1]); + } // Dplus V0 + } // for loop + } // gen + + void processDplusV0(soa::Join const& collisions, CandsDplusFiltered const& candsDplus, - aod::TrackAssoc const&, - aod::V0Datas const& V0s, - BigTracksPID const& tracks, + aod::V0s const& V0s, + TracksIUWithPID const& tracks, aod::BCsWithTimestamps const& bcs) { + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; + for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollision, thisCollId); + auto V0sThisColl = V0s.sliceBy(candsV0PerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, V0sThisColl, tracks, tracks, bcs); + } // handle normalization by the right number of collisions - hfCollisionCounter(collisions.tableSize()); + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusV0, "Process Dplus candidates paired with V0s without MC info and without ML info", true); + void processDplusV0MC(soa::Join const& collisions, + CandsDplusFiltered const& candsDplus, + aod::V0s const& V0s, + TracksIUWithPIDAndMC const& tracks, + aod::McParticles const& particlesMc, + aod::BCsWithTimestamps const& bcs) + { + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollision, thisCollId); auto V0sThisColl = V0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, V0sThisColl, tracks, bcs); + runDataCreation(collision, candsDThisColl, V0sThisColl, tracks, particlesMc, bcs); } + runMcGen(particlesMc); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } - PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusV0, "Process Dplus candidates without MC info and without ML info", true); + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusV0MC, "Process DPlus candidates paired with V0s with MC matching and without ML info", false); - void processDplusV0WithMl(aod::Collisions const& collisions, + void processDplusV0WithMl(soa::Join const& collisions, CandsDplusFilteredWithMl const& candsDplus, - aod::TrackAssoc const& trackIndices, - aod::V0Datas const& V0s, - BigTracksPID const& tracks, + aod::V0s const& V0s, + TracksIUWithPID const& tracks, aod::BCsWithTimestamps const& bcs) { + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; + for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollisionWithMl, thisCollId); + auto V0sThisColl = V0s.sliceBy(candsV0PerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, V0sThisColl, tracks, tracks, bcs); + } // handle normalization by the right number of collisions - hfCollisionCounter(collisions.tableSize()); + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusV0WithMl, "Process Dplus candidates paired with V0s with ML info", false); + void processDplusV0MCWithMl(soa::Join const& collisions, + CandsDplusFilteredWithMl const& candsDplus, + aod::V0s const& V0s, + TracksIUWithPIDAndMC const& tracks, + aod::McParticles const& particlesMc, + aod::BCsWithTimestamps const& bcs) + { + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); auto thisCollId = collision.globalIndex(); - auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollisionWithMl, thisCollId); + auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollision, thisCollId); auto V0sThisColl = V0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, V0sThisColl, tracks, bcs); + runDataCreation(collision, candsDThisColl, V0sThisColl, tracks, particlesMc, bcs); } + runMcGen(particlesMc); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } - PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusV0WithMl, "Process Dplus candidates with ML info", false); + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusV0MCWithMl, "Process DPlus candidates paired with V0s with MC matching and with ML info", false); - void processDstarV0(aod::Collisions const& collisions, + void processDstarV0(soa::Join const& collisions, CandDstarFiltered const& candsDstar, - aod::TrackAssoc const&, - aod::V0Datas const& V0s, - BigTracksPID const& tracks, + aod::V0s const& V0s, + TracksIUWithPID const& tracks, aod::BCsWithTimestamps const& bcs) { + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; + for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollision, thisCollId); + auto V0sThisColl = V0s.sliceBy(candsV0PerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, V0sThisColl, tracks, tracks, bcs); + } // handle normalization by the right number of collisions - hfCollisionCounter(collisions.tableSize()); + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarV0, "Process DStar candidates paired with V0s without MC info and without ML info", false); + void processDstarV0MC(soa::Join const& collisions, + CandDstarFiltered const& candsDstar, + aod::V0s const& V0s, + TracksIUWithPIDAndMC const& tracks, + aod::McParticles const& particlesMc, + aod::BCsWithTimestamps const& bcs) + { + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollision, thisCollId); auto V0sThisColl = V0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, V0sThisColl, tracks, bcs); + runDataCreation(collision, candsDThisColl, V0sThisColl, tracks, particlesMc, bcs); } + runMcGen(particlesMc); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } - PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarV0, "Process DStar candidates without MC info and without ML info", false); + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarV0MC, "Process DStar candidates paired with V0s with MC matching and without ML info", false); - void processDstarV0WithMl(aod::Collisions const& collisions, + void processDstarV0WithMl(soa::Join const& collisions, CandDstarFilteredWithMl const& candsDstar, - aod::TrackAssoc const& trackIndices, - aod::V0Datas const& V0s, - BigTracksPID const& tracks, + aod::V0s const& V0s, + TracksIUWithPID const& tracks, aod::BCsWithTimestamps const& bcs) { + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; + for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollisionWithMl, thisCollId); + auto V0sThisColl = V0s.sliceBy(candsV0PerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, V0sThisColl, tracks, tracks, bcs); + } // handle normalization by the right number of collisions - hfCollisionCounter(collisions.tableSize()); + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarV0WithMl, "Process DStar candidates paired with V0s with ML info", false); + void processDstarV0MCWithMl(soa::Join const& collisions, + CandDstarFilteredWithMl const& candsDstar, + aod::V0s const& V0s, + TracksIUWithPIDAndMC const& tracks, + aod::McParticles const& particlesMc, + aod::BCsWithTimestamps const& bcs) + { + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); auto thisCollId = collision.globalIndex(); - auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollisionWithMl, thisCollId); + auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollision, thisCollId); auto V0sThisColl = V0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, V0sThisColl, tracks, bcs); + runDataCreation(collision, candsDThisColl, V0sThisColl, tracks, particlesMc, bcs); } + runMcGen(particlesMc); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } - PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarV0WithMl, "Process DStar candidates with ML info", false); + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarV0MCWithMl, "Process MC DStar candidates paired with V0s with ML info", false); + + void processDstarTrack(soa::Join const& collisions, + CandDstarFiltered const& candsDstar, + aod::TrackAssoc const& trackIndices, + TracksWithPID const& tracks, + aod::BCsWithTimestamps const& bcs) + { + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; + for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollision, thisCollId); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, trackIdsThisColl, tracks, tracks, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarTrack, "Process DStar candidates paired with tracks without MC info and without ML info", false); + + void processDstarTrackWithMl(soa::Join const& collisions, + CandDstarFilteredWithMl const& candsDstar, + aod::TrackAssoc const& trackIndices, + TracksWithPID const& tracks, + aod::BCsWithTimestamps const& bcs) + { + int zvtxColl{0}; + int sel8Coll{0}; + int zvtxAndSel8Coll{0}; + int zvtxAndSel8CollAndSoftTrig{0}; + int allSelColl{0}; + for (const auto& collision : collisions) { + o2::hf_evsel::checkEvSel(collision, hfEvSel, zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl, ccdb, registry); + + auto thisCollId = collision.globalIndex(); + auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollisionWithMl, thisCollId); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, trackIdsThisColl, tracks, tracks, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarTrackWithMl, "Process DStar candidates paired with tracks with ML info", false); + }; // struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/D2H/Tasks/CMakeLists.txt b/PWGHF/D2H/Tasks/CMakeLists.txt index 08a62450afa..89f660b85ba 100644 --- a/PWGHF/D2H/Tasks/CMakeLists.txt +++ b/PWGHF/D2H/Tasks/CMakeLists.txt @@ -29,16 +29,36 @@ o2physics_add_dpl_workflow(task-bplus-reduced PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(task-bs-reduced + SOURCES taskBsReduced.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(task-bs SOURCES taskBs.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(task-charm-polarisation + SOURCES taskCharmPolarisation.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(task-charm-reso-reduced + SOURCES taskCharmResoReduced.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(task-d0 SOURCES taskD0.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(task-directed-flow-charm-hadrons + SOURCES taskDirectedFlowCharmHadrons.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(task-dplus SOURCES taskDplus.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -54,6 +74,11 @@ o2physics_add_dpl_workflow(task-dstar-to-d0-pi PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(task-flow-charm-hadrons + SOURCES taskFlowCharmHadrons.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(task-lb SOURCES taskLb.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -69,27 +94,32 @@ o2physics_add_dpl_workflow(task-lc-to-k0s-p PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(task-omegac0-to-omega-pi + SOURCES taskOmegac0ToOmegapi.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(task-sigmac SOURCES taskSigmac.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(task-xic - SOURCES taskXic.cxx +o2physics_add_dpl_workflow(task-sigmac-to-cascade + SOURCES taskSigmacToCascade.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(task-xicc - SOURCES taskXicc.cxx +o2physics_add_dpl_workflow(task-xic + SOURCES taskXic.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(task-flow-charm-hadrons - SOURCES taskFlowCharmHadrons.cxx +o2physics_add_dpl_workflow(task-xic-to-xi-pi-pi + SOURCES taskXicToXiPiPi.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(task-charm-polarisation - SOURCES taskCharmPolarisation.cxx +o2physics_add_dpl_workflow(task-xicc + SOURCES taskXicc.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) \ No newline at end of file + COMPONENT_NAME Analysis) diff --git a/PWGHF/D2H/Tasks/taskB0.cxx b/PWGHF/D2H/Tasks/taskB0.cxx index 29d59ed912e..c1076cab906 100644 --- a/PWGHF/D2H/Tasks/taskB0.cxx +++ b/PWGHF/D2H/Tasks/taskB0.cxx @@ -14,6 +14,8 @@ /// /// \author Alexandre Bigot , IPHC Strasbourg +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" @@ -157,9 +159,6 @@ struct HfTaskB0 { TracksWithSel const&) { for (const auto& candidate : candidates) { - if (!TESTBIT(candidate.hfflag(), hf_cand_b0::DecayType::B0ToDPi)) { - continue; - } if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { continue; } @@ -197,9 +196,6 @@ struct HfTaskB0 { { // MC rec for (const auto& candidate : candidates) { - if (!TESTBIT(candidate.hfflag(), hf_cand_b0::DecayType::B0ToDPi)) { - continue; - } if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { continue; } diff --git a/PWGHF/D2H/Tasks/taskB0Reduced.cxx b/PWGHF/D2H/Tasks/taskB0Reduced.cxx index 9b5a9c2d40a..d3f81aac980 100644 --- a/PWGHF/D2H/Tasks/taskB0Reduced.cxx +++ b/PWGHF/D2H/Tasks/taskB0Reduced.cxx @@ -36,65 +36,116 @@ namespace o2::aod { namespace hf_cand_b0_lite { -DECLARE_SOA_COLUMN(PtProng0, ptProng0, float); //! Transverse momentum of prong0 (GeV/c) -DECLARE_SOA_COLUMN(PtProng1, ptProng1, float); //! Transverse momentum of prong1 (GeV/c) -DECLARE_SOA_COLUMN(MProng0, mProng0, float); //! Invariant mass of prong0 (GeV/c) -DECLARE_SOA_COLUMN(M, m, float); //! Invariant mass of candidate (GeV/c2) -DECLARE_SOA_COLUMN(Pt, pt, float); //! Transverse momentum of candidate (GeV/c) -DECLARE_SOA_COLUMN(PtGen, ptGen, float); //! Transverse momentum of candidate (GeV/c) -DECLARE_SOA_COLUMN(P, p, float); //! Momentum of candidate (GeV/c) -DECLARE_SOA_COLUMN(Y, y, float); //! Rapidity of candidate -DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity of candidate -DECLARE_SOA_COLUMN(Phi, phi, float); //! Azimuth angle of candidate -DECLARE_SOA_COLUMN(E, e, float); //! Energy of candidate (GeV) -DECLARE_SOA_COLUMN(NSigTpcPi1, nSigTpcPi1, float); //! TPC Nsigma separation for prong1 with pion mass hypothesis -DECLARE_SOA_COLUMN(NSigTofPi1, nSigTofPi1, float); //! TOF Nsigma separation for prong1 with pion mass hypothesis -DECLARE_SOA_COLUMN(DecayLength, decayLength, float); //! Decay length of candidate (cm) -DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); //! Transverse decay length of candidate (cm) -DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); //! Normalised decay length of candidate -DECLARE_SOA_COLUMN(DecayLengthXYNormalised, decayLengthXYNormalised, float); //! Normalised transverse decay length of candidate -DECLARE_SOA_COLUMN(ImpactParameterProduct, impactParameterProduct, float); //! Impact parameter product of candidate -DECLARE_SOA_COLUMN(Cpa, cpa, float); //! Cosine pointing angle of candidate -DECLARE_SOA_COLUMN(CpaXY, cpaXY, float); //! Cosine pointing angle of candidate in transverse plane -DECLARE_SOA_COLUMN(MaxNormalisedDeltaIP, maxNormalisedDeltaIP, float); //! Maximum normalized difference between measured and expected impact parameter of candidate prongs -DECLARE_SOA_COLUMN(MlScoreSig, mlScoreSig, float); //! ML score for signal class +DECLARE_SOA_COLUMN(PtD, ptD, float); //! Transverse momentum of D-meson daughter candidate (GeV/c) +DECLARE_SOA_COLUMN(PtBach, ptBach, float); //! Transverse momentum of bachelor pion (GeV/c) +DECLARE_SOA_COLUMN(AbsEtaBach, absEtaBach, float); //! Absolute pseudorapidity of bachelor pion +DECLARE_SOA_COLUMN(ItsNClsBach, itsNClsBach, int); //! Number of ITS clusters of bachelor pion +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsBach, tpcNClsCrossedRowsBach, int); //! Number of TPC crossed rows of prongs of bachelor pion +DECLARE_SOA_COLUMN(TpcChi2NClBach, tpcChi2NClBach, float); //! Maximum TPC chi2 of prongs of D-meson daughter candidate +DECLARE_SOA_COLUMN(PtDmesProngMin, ptProngDmesMin, float); //! Minimum pT of prongs of D-meson daughter candidate (GeV/c) +DECLARE_SOA_COLUMN(AbsEtaDmesProngMin, absEtaProngDmesMin, float); //! Minimum absolute pseudorapidity of prongs of D-meson daughter candidate +DECLARE_SOA_COLUMN(ItsNClsDmesProngMin, itsNClsDmesProngMin, int); //! Minimum number of ITS clusters of prongs of D-meson daughter candidate +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsDmesProngMin, tpcNClsCrossedRowsDmesProngMin, int); //! Minimum number of TPC crossed rows of prongs of D-meson daughter candidate +DECLARE_SOA_COLUMN(TpcChi2NClDmesProngMax, tpcChi2NClDmesProngMax, float); //! Maximum TPC chi2 of prongs of D-meson daughter candidate +DECLARE_SOA_COLUMN(MD, mD, float); //! Invariant mass of D-meson daughter candidates (GeV/c) +DECLARE_SOA_COLUMN(M, m, float); //! Invariant mass of candidate (GeV/c2) +DECLARE_SOA_COLUMN(Pt, pt, float); //! Transverse momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(PtGen, ptGen, float); //! Transverse momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(P, p, float); //! Momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(Y, y, float); //! Rapidity of candidate +DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity of candidate +DECLARE_SOA_COLUMN(Phi, phi, float); //! Azimuth angle of candidate +DECLARE_SOA_COLUMN(E, e, float); //! Energy of candidate (GeV) +DECLARE_SOA_COLUMN(NSigTpcPiBachelor, nSigTpcPiBachelor, float); //! TPC Nsigma separation for bachelor with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTofPiBachelor, nSigTofPiBachelor, float); //! TOF Nsigma separation for bachelor with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofPiBachelor, nSigTpcTofPiBachelor, float); //! Combined TPC and TOF Nsigma separation for bachelor with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcPiDmesProng0, nSigTpcPiDmesProng0, float); //! TPC Nsigma separation for D-meson prong0 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTofPiDmesProng0, nSigTofPiDmesProng0, float); //! TOF Nsigma separation for D-meson prong0 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofPiDmesProng0, nSigTpcTofPiDmesProng0, float); //! Combined TPC and TOF Nsigma separation for D-meson prong0 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcKaDmesProng1, nSigTpcKaDmesProng1, float); //! TPC Nsigma separation for D-meson prong1 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTofKaDmesProng1, nSigTofKaDmesProng1, float); //! TOF Nsigma separation for D-meson prong1 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofKaDmesProng1, nSigTpcTofKaDmesProng1, float); //! Combined TPC and TOF Nsigma separation for D-meson prong1 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcPiDmesProng2, nSigTpcPiDmesProng2, float); //! TPC Nsigma separation for D-meson prong2 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTofPiDmesProng2, nSigTofPiDmesProng2, float); //! TOF Nsigma separation for D-meson prong2 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofPiDmesProng2, nSigTpcTofPiDmesProng2, float); //! Combined TPC and TOF Nsigma separation for D-meson prong0 with pion mass hypothesis +DECLARE_SOA_COLUMN(DecayLength, decayLength, float); //! Decay length of candidate (cm) +DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); //! Transverse decay length of candidate (cm) +DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); //! Normalised decay length of candidate +DECLARE_SOA_COLUMN(DecayLengthXYNormalised, decayLengthXYNormalised, float); //! Normalised transverse decay length of candidate +DECLARE_SOA_COLUMN(DecayLengthD, decayLengthD, float); //! Decay length of D-meson daughter candidate (cm) +DECLARE_SOA_COLUMN(DecayLengthXYD, decayLengthXYD, float); //! Transverse decay length of D-meson daughter candidate (cm) +DECLARE_SOA_COLUMN(ImpactParameterD, impactParameterD, float); //! Impact parameter product of D-meson daughter candidate +DECLARE_SOA_COLUMN(ImpactParameterBach, impactParameterBach, float); //! Impact parameter product of bachelor pion +DECLARE_SOA_COLUMN(ImpactParameterProduct, impactParameterProduct, float); //! Impact parameter product of daughters +DECLARE_SOA_COLUMN(Cpa, cpa, float); //! Cosine pointing angle of candidate +DECLARE_SOA_COLUMN(CpaXY, cpaXY, float); //! Cosine pointing angle of candidate in transverse plane +DECLARE_SOA_COLUMN(MaxNormalisedDeltaIP, maxNormalisedDeltaIP, float); //! Maximum normalized difference between measured and expected impact parameter of candidate prongs +DECLARE_SOA_COLUMN(MlScoreSig, mlScoreSig, float); //! ML score for signal class +DECLARE_SOA_COLUMN(FlagWrongCollision, flagWrongCollision, int8_t); //! Flag for association with wrong collision } // namespace hf_cand_b0_lite DECLARE_SOA_TABLE(HfRedCandB0Lites, "AOD", "HFREDCANDB0LITE", //! Table with some B0 properties + // B meson features hf_cand_b0_lite::M, + hf_cand_b0_lite::M, + hf_cand_b0_lite::Pt, + hf_cand_b0_lite::Eta, + hf_cand_b0_lite::Phi, + hf_cand_b0_lite::Y, + hf_cand_b0_lite::Cpa, + hf_cand_b0_lite::CpaXY, hf_cand::Chi2PCA, hf_cand_b0_lite::DecayLength, hf_cand_b0_lite::DecayLengthXY, hf_cand_b0_lite::DecayLengthNormalised, hf_cand_b0_lite::DecayLengthXYNormalised, - hf_cand_b0_lite::MProng0, - hf_cand_b0_lite::PtProng0, - hf_cand_b0_lite::PtProng1, - hf_cand::ImpactParameter0, - hf_cand::ImpactParameter1, hf_cand_b0_lite::ImpactParameterProduct, - hf_cand_b0_lite::NSigTpcPi1, - hf_cand_b0_lite::NSigTofPi1, + hf_cand_b0_lite::MaxNormalisedDeltaIP, + hf_cand_b0_lite::MlScoreSig, + hf_sel_candidate_b0::IsSelB0ToDPi, + // D meson features + hf_cand_b0_lite::MD, + hf_cand_b0_lite::PtD, + hf_cand_b0_lite::DecayLengthD, + hf_cand_b0_lite::DecayLengthXYD, + hf_cand_b0_lite::ImpactParameterD, + hf_cand_b0_lite::PtDmesProngMin, + hf_cand_b0_lite::AbsEtaDmesProngMin, + hf_cand_b0_lite::ItsNClsDmesProngMin, + hf_cand_b0_lite::TpcNClsCrossedRowsDmesProngMin, + hf_cand_b0_lite::TpcChi2NClDmesProngMax, + hf_cand_b0_lite::NSigTpcPiDmesProng0, + hf_cand_b0_lite::NSigTofPiDmesProng0, + hf_cand_b0_lite::NSigTpcTofPiDmesProng0, + hf_cand_b0_lite::NSigTpcKaDmesProng1, + hf_cand_b0_lite::NSigTofKaDmesProng1, + hf_cand_b0_lite::NSigTpcTofKaDmesProng1, + hf_cand_b0_lite::NSigTpcPiDmesProng2, + hf_cand_b0_lite::NSigTofPiDmesProng2, + hf_cand_b0_lite::NSigTpcTofPiDmesProng2, hf_cand_b0_reduced::Prong0MlScoreBkg, hf_cand_b0_reduced::Prong0MlScorePrompt, hf_cand_b0_reduced::Prong0MlScoreNonprompt, - hf_cand_b0_lite::MlScoreSig, - hf_sel_candidate_b0::IsSelB0ToDPi, - hf_cand_b0_lite::M, - hf_cand_b0_lite::Pt, - hf_cand_b0_lite::Cpa, - hf_cand_b0_lite::CpaXY, - hf_cand_b0_lite::MaxNormalisedDeltaIP, - hf_cand_b0_lite::Eta, - hf_cand_b0_lite::Phi, - hf_cand_b0_lite::Y, + // pion features + hf_cand_b0_lite::PtBach, + hf_cand_b0_lite::AbsEtaBach, + hf_cand_b0_lite::ItsNClsBach, + hf_cand_b0_lite::TpcNClsCrossedRowsBach, + hf_cand_b0_lite::TpcChi2NClBach, + hf_cand_b0_lite::ImpactParameterBach, + hf_cand_b0_lite::NSigTpcPiBachelor, + hf_cand_b0_lite::NSigTofPiBachelor, + hf_cand_b0_lite::NSigTpcTofPiBachelor, + // MC truth hf_cand_3prong::FlagMcMatchRec, hf_cand_3prong::OriginMcRec, + hf_cand_b0_lite::FlagWrongCollision, hf_cand_b0_lite::PtGen); DECLARE_SOA_TABLE(HfRedB0McCheck, "AOD", "HFREDB0MCCHECK", //! Table with MC decay type check hf_cand_3prong::FlagMcMatchRec, - hf_cand_b0_lite::MProng0, - hf_cand_b0_lite::PtProng0, + hf_cand_b0_lite::FlagWrongCollision, + hf_cand_b0_lite::MD, + hf_cand_b0_lite::PtD, hf_cand_b0_lite::M, hf_cand_b0_lite::Pt, hf_cand_b0_lite::MlScoreSig, @@ -130,6 +181,7 @@ struct HfTaskB0Reduced { HistogramRegistry registry{"registry"}; using TracksPion = soa::Join; + using CandsDplus = soa::Join; void init(InitContext&) { @@ -137,16 +189,11 @@ struct HfTaskB0Reduced { if ((std::accumulate(processFuncData.begin(), processFuncData.end(), 0)) > 1) { LOGP(fatal, "Only one process function for data can be enabled at a time."); } - std::array processFuncMc{doprocessMc, doprocessMcWithDecayTypeCheck, doprocessMcWithDmesMl, doprocessMcWithB0Ml, doprocessMcWithB0MlAndDecayTypeCheck}; + std::array processFuncMc{doprocessMc, doprocessMcWithDecayTypeCheck, doprocessMcWithDmesMl, doprocessMcWithDmesMlAndDecayTypeCheck, doprocessMcWithB0Ml, doprocessMcWithB0MlAndDecayTypeCheck}; if ((std::accumulate(processFuncMc.begin(), processFuncMc.end(), 0)) > 1) { LOGP(fatal, "Only one process function for MC can be enabled at a time."); } - if (((doprocessData || doprocessDataWithDmesMl) && fillTree && downSampleBkgFactor >= 1.) || - ((doprocessMc || doprocessMcWithDmesMl) && fillTree && fillBackground && downSampleBkgFactor >= 1.)) { - LOGP(fatal, "Set downSampleBkgFactor below unity when filling tree with background."); - } - const AxisSpec axisMlScore{100, 0.f, 1.f}; const AxisSpec axisMassB0{300, 4.5f, 6.0f}; const AxisSpec axisMassDminus{300, 1.75f, 2.05f}; @@ -203,7 +250,7 @@ struct HfTaskB0Reduced { } } - if (doprocessMc || doprocessMcWithDecayTypeCheck || doprocessMcWithDmesMl || doprocessMcWithB0Ml || doprocessMcWithB0MlAndDecayTypeCheck) { + if (doprocessMc || doprocessMcWithDecayTypeCheck || doprocessMcWithDmesMl || doprocessMcWithDmesMlAndDecayTypeCheck || doprocessMcWithB0Ml || doprocessMcWithB0MlAndDecayTypeCheck) { if (fillHistograms) { // gen histos registry.add("hEtaGen", "B^{0} particles (generated);#it{p}_{T}^{gen}(B^{0}) (GeV/#it{c});#it{#eta}^{gen}(B^{0});entries", {HistType::kTH2F, {axisPtB0, axisEta}}); @@ -258,7 +305,7 @@ struct HfTaskB0Reduced { registry.add("hCospXyDRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(D^{#minus}) (GeV/#it{c});D^{#minus} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtDminus, axisCosp}}); } // MC checks - if (doprocessMcWithDecayTypeCheck || doprocessMcWithB0MlAndDecayTypeCheck) { + if (doprocessMcWithDecayTypeCheck || doprocessMcWithB0MlAndDecayTypeCheck || doprocessMcWithDmesMlAndDecayTypeCheck) { constexpr uint8_t kNBinsDecayTypeMc = hf_cand_b0::DecayTypeMc::NDecayTypeMc; TString labels[kNBinsDecayTypeMc]; labels[hf_cand_b0::DecayTypeMc::B0ToDplusPiToPiKPiPi] = "B^{0} #rightarrow (D^{#minus} #rightarrow #pi^{#minus} K^{#plus} #pi^{#minus}) #pi^{#plus}"; @@ -272,7 +319,7 @@ struct HfTaskB0Reduced { } } // ML scores of D- daughter - if (doprocessMcWithDmesMl) { + if (doprocessMcWithDmesMl || doprocessMcWithDmesMlAndDecayTypeCheck) { // signal registry.add("hMlScoreBkgDRecSig", "B^{0} candidates (matched);#it{p}_{T}(D^{#minus}) (GeV/#it{c});prong0, D^{#minus} ML background score;entries", {HistType::kTH2F, {axisPtDminus, axisMlScore}}); registry.add("hMlScorePromptDRecSig", "B^{0} candidates (matched);#it{p}_{T}(D^{#minus}) (GeV/#it{c});prong0, D^{#minus} ML prompt score;entries", {HistType::kTH2F, {axisPtDminus, axisMlScore}}); @@ -328,15 +375,15 @@ struct HfTaskB0Reduced { /// \param withB0Ml is the flag to enable the filling with ML scores for the B0 candidate /// \param candidate is the B0 candidate /// \param candidatesD is the table with D- candidates - template + template void fillCand(Cand const& candidate, - aod::HfRed3Prongs const&) + CandsDmes const&) { auto ptCandB0 = candidate.pt(); auto invMassB0 = hfHelper.invMassB0ToDPi(candidate); - auto candD = candidate.template prong0_as(); + auto candD = candidate.template prong0_as(); auto ptD = candidate.ptProng0(); - auto invMassD = candD.invMass(); + auto invMassD = candD.invMassHypo0(); std::array posPv{candidate.posX(), candidate.posY(), candidate.posZ()}; std::array posSvD{candD.xSecondaryVertex(), candD.ySecondaryVertex(), candD.zSecondaryVertex()}; std::array momD{candD.pVector()}; @@ -346,9 +393,11 @@ struct HfTaskB0Reduced { auto decLenXyD = RecoDecay::distanceXY(posPv, posSvD); int8_t flagMcMatchRec = 0; + int8_t flagWrongCollision = 0; bool isSignal = false; if constexpr (doMc) { flagMcMatchRec = candidate.flagMcMatchRec(); + flagWrongCollision = candidate.flagWrongCollision(); isSignal = TESTBIT(std::abs(flagMcMatchRec), hf_cand_b0::DecayTypeMc::B0ToDplusPiToPiKPiPi); } @@ -474,7 +523,7 @@ struct HfTaskB0Reduced { } } if (fillTree) { - float pseudoRndm = ptD * 1000. - (int64_t)(ptD * 1000); + float pseudoRndm = ptD * 1000. - static_cast(ptD * 1000); if (flagMcMatchRec != 0 || (((doMc && fillBackground) || !doMc) && (ptCandB0 >= ptMaxForDownSample || pseudoRndm < downSampleBkgFactor))) { float prong0MlScoreBkg = -1.; float prong0MlScorePrompt = -1.; @@ -496,54 +545,78 @@ struct HfTaskB0Reduced { } hfRedCandB0Lite( + // B-meson features + invMassB0, + ptCandB0, + candidate.eta(), + candidate.phi(), + hfHelper.yB0(candidate), + candidate.cpa(), + candidate.cpaXY(), candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.decayLengthNormalised(), candidate.decayLengthXYNormalised(), + candidate.impactParameterProduct(), + candidate.maxNormalisedDeltaIP(), + candidateMlScoreSig, + candidate.isSelB0ToDPi(), + // D-meson features invMassD, ptD, - candidate.ptProng1(), + decLenD, + decLenXyD, candidate.impactParameter0(), - candidate.impactParameter1(), - candidate.impactParameterProduct(), - prong1.tpcNSigmaPi(), - prong1.tofNSigmaPi(), + candD.ptProngMin(), + candD.absEtaProngMin(), + candD.itsNClsProngMin(), + candD.tpcNClsCrossedRowsProngMin(), + candD.tpcChi2NClProngMax(), + candD.tpcNSigmaPiProng0(), + candD.tofNSigmaPiProng0(), + candD.tpcTofNSigmaPiProng0(), + candD.tpcNSigmaKaProng1(), + candD.tofNSigmaKaProng1(), + candD.tpcTofNSigmaKaProng1(), + candD.tpcNSigmaPiProng2(), + candD.tofNSigmaPiProng2(), + candD.tpcTofNSigmaPiProng2(), prong0MlScoreBkg, prong0MlScorePrompt, prong0MlScoreNonprompt, - candidateMlScoreSig, - candidate.isSelB0ToDPi(), - invMassB0, - ptCandB0, - candidate.cpa(), - candidate.cpaXY(), - candidate.maxNormalisedDeltaIP(), - candidate.eta(), - candidate.phi(), - hfHelper.yB0(candidate), + // pion features + candidate.ptProng1(), + std::abs(RecoDecay::eta(prong1.pVector())), + prong1.itsNCls(), + prong1.tpcNClsCrossedRows(), + prong1.tpcChi2NCl(), + candidate.impactParameter1(), + prong1.tpcNSigmaPi(), + prong1.tofNSigmaPi(), + prong1.tpcTofNSigmaPi(), + // MC truth flagMcMatchRec, isSignal, + flagWrongCollision, ptMother); - } - if constexpr (withDecayTypeCheck) { - float candidateMlScoreSig = -1; - if constexpr (withB0Ml) { - candidateMlScoreSig = candidate.mlProbB0ToDPi(); + + if constexpr (withDecayTypeCheck) { + hfRedB0McCheck( + flagMcMatchRec, + flagWrongCollision, + invMassD, + ptD, + invMassB0, + ptCandB0, + candidateMlScoreSig, + candidate.pdgCodeBeautyMother(), + candidate.pdgCodeCharmMother(), + candidate.pdgCodeProng0(), + candidate.pdgCodeProng1(), + candidate.pdgCodeProng2(), + candidate.pdgCodeProng3()); } - hfRedB0McCheck( - flagMcMatchRec, - invMassD, - ptD, - invMassB0, - ptCandB0, - candidateMlScoreSig, - candidate.pdgCodeBeautyMother(), - candidate.pdgCodeCharmMother(), - candidate.pdgCodeProng0(), - candidate.pdgCodeProng1(), - candidate.pdgCodeProng2(), - candidate.pdgCodeProng3()); } } } @@ -588,63 +661,51 @@ struct HfTaskB0Reduced { // Process functions void processData(soa::Filtered> const& candidates, - aod::HfRed3Prongs const& candidatesD, + CandsDplus const& candidatesD, TracksPion const&) { for (const auto& candidate : candidates) { - if (!TESTBIT(candidate.hfflag(), hf_cand_b0::DecayType::B0ToDPi)) { - continue; - } if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { continue; } fillCand(candidate, candidatesD); } // candidate loop - } // processData + } // processData PROCESS_SWITCH(HfTaskB0Reduced, processData, "Process data without ML scores for B0 and D daughter", true); void processDataWithDmesMl(soa::Filtered> const& candidates, - aod::HfRed3Prongs const& candidatesD, + CandsDplus const& candidatesD, TracksPion const&) { for (const auto& candidate : candidates) { - if (!TESTBIT(candidate.hfflag(), hf_cand_b0::DecayType::B0ToDPi)) { - continue; - } if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { continue; } fillCand(candidate, candidatesD); } // candidate loop - } // processDataWithDmesMl + } // processDataWithDmesMl PROCESS_SWITCH(HfTaskB0Reduced, processDataWithDmesMl, "Process data with(out) ML scores for D daughter (B0)", false); void processDataWithB0Ml(soa::Filtered> const& candidates, - aod::HfRed3Prongs const& candidatesD, + CandsDplus const& candidatesD, TracksPion const&) { for (const auto& candidate : candidates) { - if (!TESTBIT(candidate.hfflag(), hf_cand_b0::DecayType::B0ToDPi)) { - continue; - } if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { continue; } fillCand(candidate, candidatesD); } // candidate loop - } // processDataWithB0Ml + } // processDataWithB0Ml PROCESS_SWITCH(HfTaskB0Reduced, processDataWithB0Ml, "Process data with(out) ML scores for B0 (D daughter)", false); void processMc(soa::Filtered> const& candidates, aod::HfMcGenRedB0s const& mcParticles, - aod::HfRed3Prongs const& candidatesD, + CandsDplus const& candidatesD, TracksPion const&) { // MC rec for (const auto& candidate : candidates) { - if (!TESTBIT(candidate.hfflag(), hf_cand_b0::DecayType::B0ToDPi)) { - continue; - } if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { continue; } @@ -655,19 +716,16 @@ struct HfTaskB0Reduced { for (const auto& particle : mcParticles) { fillCandMcGen(particle); } // gen - } // processMc + } // processMc PROCESS_SWITCH(HfTaskB0Reduced, processMc, "Process MC without ML scores for B0 and D daughter", false); void processMcWithDecayTypeCheck(soa::Filtered> const& candidates, aod::HfMcGenRedB0s const& mcParticles, - aod::HfRed3Prongs const& candidatesD, + CandsDplus const& candidatesD, TracksPion const&) { // MC rec for (const auto& candidate : candidates) { - if (!TESTBIT(candidate.hfflag(), hf_cand_b0::DecayType::B0ToDPi)) { - continue; - } if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { continue; } @@ -678,19 +736,16 @@ struct HfTaskB0Reduced { for (const auto& particle : mcParticles) { fillCandMcGen(particle); } // gen - } // processMc + } // processMc PROCESS_SWITCH(HfTaskB0Reduced, processMcWithDecayTypeCheck, "Process MC with decay type check and without ML scores for B0 and D daughter", false); void processMcWithDmesMl(soa::Filtered> const& candidates, aod::HfMcGenRedB0s const& mcParticles, - aod::HfRed3Prongs const& candidatesD, + CandsDplus const& candidatesD, TracksPion const&) { // MC rec for (const auto& candidate : candidates) { - if (!TESTBIT(candidate.hfflag(), hf_cand_b0::DecayType::B0ToDPi)) { - continue; - } if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { continue; } @@ -701,19 +756,36 @@ struct HfTaskB0Reduced { for (const auto& particle : mcParticles) { fillCandMcGen(particle); } // gen - } // processMcWithDmesMl + } // processMcWithDmesMl PROCESS_SWITCH(HfTaskB0Reduced, processMcWithDmesMl, "Process MC with(out) ML scores for D daughter (B0)", false); + void processMcWithDmesMlAndDecayTypeCheck(soa::Filtered> const& candidates, + aod::HfMcGenRedB0s const& mcParticles, + CandsDplus const& candidatesD, + TracksPion const&) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesD); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMc + PROCESS_SWITCH(HfTaskB0Reduced, processMcWithDmesMlAndDecayTypeCheck, "Process MC with decay type check and with(out) ML scores for B0 (D daughter)", false); + void processMcWithB0Ml(soa::Filtered> const& candidates, aod::HfMcGenRedB0s const& mcParticles, - aod::HfRed3Prongs const& candidatesD, + CandsDplus const& candidatesD, TracksPion const&) { // MC rec for (const auto& candidate : candidates) { - if (!TESTBIT(candidate.hfflag(), hf_cand_b0::DecayType::B0ToDPi)) { - continue; - } if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { continue; } @@ -724,19 +796,16 @@ struct HfTaskB0Reduced { for (const auto& particle : mcParticles) { fillCandMcGen(particle); } // gen - } // processMcWithB0Ml + } // processMcWithB0Ml PROCESS_SWITCH(HfTaskB0Reduced, processMcWithB0Ml, "Process MC with(out) ML scores for B0 (D daughter)", false); void processMcWithB0MlAndDecayTypeCheck(soa::Filtered> const& candidates, aod::HfMcGenRedB0s const& mcParticles, - aod::HfRed3Prongs const& candidatesD, + CandsDplus const& candidatesD, TracksPion const&) { // MC rec for (const auto& candidate : candidates) { - if (!TESTBIT(candidate.hfflag(), hf_cand_b0::DecayType::B0ToDPi)) { - continue; - } if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { continue; } @@ -747,7 +816,7 @@ struct HfTaskB0Reduced { for (const auto& particle : mcParticles) { fillCandMcGen(particle); } // gen - } // processMc + } // processMc PROCESS_SWITCH(HfTaskB0Reduced, processMcWithB0MlAndDecayTypeCheck, "Process MC with decay type check and with(out) ML scores for B0 (D daughter)", false); }; // struct diff --git a/PWGHF/D2H/Tasks/taskBplus.cxx b/PWGHF/D2H/Tasks/taskBplus.cxx index 6920054084c..b98a2930258 100644 --- a/PWGHF/D2H/Tasks/taskBplus.cxx +++ b/PWGHF/D2H/Tasks/taskBplus.cxx @@ -18,6 +18,8 @@ /// \author Antonio Palasciano , Università degli Studi di Bari & INFN, Sezione di Bari /// \author Deepa Thomas , UT Austin +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" @@ -164,9 +166,6 @@ struct HfTaskBplus { { for (const auto& candidate : selectedBPlusCandidates) { - if (!TESTBIT(candidate.hfflag(), hf_cand_bplus::DecayType::BplusToD0Pi)) { - continue; - } if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { continue; } @@ -208,9 +207,6 @@ struct HfTaskBplus { { // MC rec for (const auto& candidate : selectedBPlusCandidatesMC) { - if (!TESTBIT(candidate.hfflag(), hf_cand_bplus::DecayType::BplusToD0Pi)) { - continue; - } if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { continue; } @@ -269,7 +265,7 @@ struct HfTaskBplus { float ptProngs[2], yProngs[2], etaProngs[2]; int counter = 0; - for (const auto& daught : particle.daughters_as()) { + for (const auto& daught : particle.daughters_as>()) { ptProngs[counter] = daught.pt(); etaProngs[counter] = daught.eta(); yProngs[counter] = RecoDecay::y(daught.pVector(), pdg->Mass(daught.pdgCode())); @@ -294,7 +290,7 @@ struct HfTaskBplus { registry.fill(HIST("hPtGenWithRapidityBelowHalf"), ptParticle); } - // reject B0 daughters that are not in geometrical acceptance + // reject B+ daughters that are not in geometrical acceptance if (!isProngInAcceptance(etaProngs[0], ptProngs[0]) || !isProngInAcceptance(etaProngs[1], ptProngs[1])) { continue; } diff --git a/PWGHF/D2H/Tasks/taskBplusReduced.cxx b/PWGHF/D2H/Tasks/taskBplusReduced.cxx index 6f1b775c240..f296b059503 100644 --- a/PWGHF/D2H/Tasks/taskBplusReduced.cxx +++ b/PWGHF/D2H/Tasks/taskBplusReduced.cxx @@ -14,9 +14,12 @@ /// /// \author Antonio Palasciano , Università degli Studi di Bari & INFN, Sezione di Bari +#include + #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" +#include "Common/Core/RecoDecay.h" #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/SelectorCuts.h" @@ -30,8 +33,130 @@ using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; +namespace o2::aod +{ +namespace hf_cand_bplus_lite +{ +DECLARE_SOA_COLUMN(PtD, ptD, float); //! Transverse momentum of D-meson daughter candidate (GeV/c) +DECLARE_SOA_COLUMN(PtBach, ptBach, float); //! Transverse momentum of bachelor pion (GeV/c) +DECLARE_SOA_COLUMN(AbsEtaBach, absEtaBach, float); //! Absolute pseudorapidity of bachelor pion +DECLARE_SOA_COLUMN(ItsNClsBach, itsNClsBach, int); //! Number of ITS clusters of bachelor pion +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsBach, tpcNClsCrossedRowsBach, int); //! Number of TPC crossed rows of prongs of bachelor pion +DECLARE_SOA_COLUMN(TpcChi2NClBach, tpcChi2NClBach, float); //! Maximum TPC chi2 of prongs of D0-meson daughter candidate +DECLARE_SOA_COLUMN(PtDmesProngMin, ptDmesProngMin, float); //! Minimum pT of prongs of D-meson daughter candidate (GeV/c) +DECLARE_SOA_COLUMN(AbsEtaDmesProngMin, absEtaDmesProngMin, float); //! Minimum absolute pseudorapidity of prongs of D-meson daughter candidate +DECLARE_SOA_COLUMN(ItsNClsDmesProngMin, itsNClsDmesProngMin, int); //! Minimum number of ITS clusters of prongs of D-meson daughter candidate +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsDmesProngMin, tpcNClsCrossedRowsDmesProngMin, int); //! Minimum number of TPC crossed rows of prongs of D-meson daughter candidate +DECLARE_SOA_COLUMN(TpcChi2NClDmesProngMax, tpcChi2NClDmesProngMax, float); //! Maximum TPC chi2 of prongs of D-meson daughter candidate +DECLARE_SOA_COLUMN(MD, mD, float); //! Invariant mass of D-meson daughter candidates (GeV/c) +DECLARE_SOA_COLUMN(M, m, float); //! Invariant mass of candidate (GeV/c2) +DECLARE_SOA_COLUMN(Pt, pt, float); //! Transverse momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(PtGen, ptGen, float); //! Transverse momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(P, p, float); //! Momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(Y, y, float); //! Rapidity of candidate +DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity of candidate +DECLARE_SOA_COLUMN(Phi, phi, float); //! Azimuth angle of candidate +DECLARE_SOA_COLUMN(E, e, float); //! Energy of candidate (GeV) +DECLARE_SOA_COLUMN(NSigTpcPiBachelor, nSigTpcPiBachelor, float); //! TPC Nsigma separation for bachelor with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTofPiBachelor, nSigTofPiBachelor, float); //! TOF Nsigma separation for bachelor with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofPiBachelor, nSigTpcTofPiBachelor, float); //! Combined TPC and TOF Nsigma separation for bachelor with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcPiDmesProng0, nSigTpcPiDmesProng0, float); //! TPC Nsigma separation for D-meson prong0 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTofPiDmesProng0, nSigTofPiDmesProng0, float); //! TOF Nsigma separation for D-meson prong0 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofPiDmesProng0, nSigTpcTofPiDmesProng0, float); //! Combined TPC and TOF Nsigma separation for D-meson prong0 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcKaDmesProng1, nSigTpcKaDmesProng1, float); //! TPC Nsigma separation for D-meson prong1 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTofKaDmesProng1, nSigTofKaDmesProng1, float); //! TOF Nsigma separation for D-meson prong1 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofKaDmesProng1, nSigTpcTofKaDmesProng1, float); //! Combined TPC and TOF Nsigma separation for D-meson prong1 with kaon mass hypothesis +DECLARE_SOA_COLUMN(DecayLength, decayLength, float); //! Decay length of candidate (cm) +DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); //! Transverse decay length of candidate (cm) +DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); //! Normalised decay length of candidate +DECLARE_SOA_COLUMN(DecayLengthXYNormalised, decayLengthXYNormalised, float); //! Normalised transverse decay length of candidate +DECLARE_SOA_COLUMN(DecayLengthD, decayLengthD, float); //! Decay length of D-meson daughter candidate (cm) +DECLARE_SOA_COLUMN(DecayLengthXYD, decayLengthXYD, float); //! Transverse decay length of D-meson daughter candidate (cm) +DECLARE_SOA_COLUMN(ImpactParameterD, impactParameterD, float); //! Impact parameter product of D-meson daughter candidate +DECLARE_SOA_COLUMN(ImpactParameterBach, impactParameterBach, float); //! Impact parameter product of bachelor pion +DECLARE_SOA_COLUMN(ImpactParameterProduct, impactParameterProduct, float); //! Impact parameter product of daughters +DECLARE_SOA_COLUMN(Cpa, cpa, float); //! Cosine pointing angle of candidate +DECLARE_SOA_COLUMN(CpaXY, cpaXY, float); //! Cosine pointing angle of candidate in transverse plane +DECLARE_SOA_COLUMN(CpaD, cpaD, float); //! Cosine pointing angle of D-meson daughter candidate +DECLARE_SOA_COLUMN(CpaXYD, cpaXYD, float); //! Cosine pointing angle in transverse plane of D-meson daughter candidate +DECLARE_SOA_COLUMN(MaxNormalisedDeltaIP, maxNormalisedDeltaIP, float); //! Maximum normalized difference between measured and expected impact parameter of candidate prongs +DECLARE_SOA_COLUMN(MlScoreSig, mlScoreSig, float); //! ML score for signal class +DECLARE_SOA_COLUMN(FlagWrongCollision, flagWrongCollision, int8_t); //! Flag for association with wrong collision +} // namespace hf_cand_bplus_lite + +DECLARE_SOA_TABLE(HfRedCandBpLites, "AOD", "HFREDCANDBPLITE", //! Table with some B+ properties + hf_cand_bplus_lite::M, + hf_cand_bplus_lite::Pt, + hf_cand_bplus_lite::Eta, + hf_cand_bplus_lite::Phi, + hf_cand_bplus_lite::Y, + hf_cand_bplus_lite::Cpa, + hf_cand_bplus_lite::CpaXY, + hf_cand::Chi2PCA, + hf_cand_bplus_lite::DecayLength, + hf_cand_bplus_lite::DecayLengthXY, + hf_cand_bplus_lite::DecayLengthNormalised, + hf_cand_bplus_lite::DecayLengthXYNormalised, + hf_cand_bplus_lite::ImpactParameterProduct, + hf_cand_bplus_lite::MaxNormalisedDeltaIP, + hf_cand_bplus_lite::MlScoreSig, + hf_sel_candidate_bplus::IsSelBplusToD0Pi, + // D meson features + hf_cand_bplus_lite::MD, + hf_cand_bplus_lite::PtD, + hf_cand_bplus_lite::DecayLengthD, + hf_cand_bplus_lite::DecayLengthXYD, + hf_cand_bplus_lite::ImpactParameterD, + hf_cand_bplus_lite::CpaD, + hf_cand_bplus_lite::CpaXYD, + hf_cand_bplus_lite::PtDmesProngMin, + hf_cand_bplus_lite::AbsEtaDmesProngMin, + hf_cand_bplus_lite::ItsNClsDmesProngMin, + hf_cand_bplus_lite::TpcNClsCrossedRowsDmesProngMin, + hf_cand_bplus_lite::TpcChi2NClDmesProngMax, + hf_cand_bplus_lite::NSigTpcPiDmesProng0, + hf_cand_bplus_lite::NSigTofPiDmesProng0, + hf_cand_bplus_lite::NSigTpcTofPiDmesProng0, + hf_cand_bplus_lite::NSigTpcKaDmesProng1, + hf_cand_bplus_lite::NSigTofKaDmesProng1, + hf_cand_bplus_lite::NSigTpcTofKaDmesProng1, + hf_cand_bplus_reduced::Prong0MlScoreBkg, + hf_cand_bplus_reduced::Prong0MlScorePrompt, + hf_cand_bplus_reduced::Prong0MlScoreNonprompt, + // pion features + hf_cand_bplus_lite::PtBach, + hf_cand_bplus_lite::AbsEtaBach, + hf_cand_bplus_lite::ItsNClsBach, + hf_cand_bplus_lite::TpcNClsCrossedRowsBach, + hf_cand_bplus_lite::TpcChi2NClBach, + hf_cand_bplus_lite::ImpactParameterBach, + hf_cand_bplus_lite::NSigTpcPiBachelor, + hf_cand_bplus_lite::NSigTofPiBachelor, + hf_cand_bplus_lite::NSigTpcTofPiBachelor, + // MC truth + hf_cand_2prong::FlagMcMatchRec, + hf_cand_2prong::OriginMcRec, + hf_cand_bplus_lite::FlagWrongCollision, + hf_cand_bplus_lite::PtGen); + +DECLARE_SOA_TABLE(HfRedBpMcCheck, "AOD", "HFREDBPMCCHECK", //! Table with MC decay type check + hf_cand_2prong::FlagMcMatchRec, + hf_cand_bplus_lite::FlagWrongCollision, + hf_cand_bplus_lite::MD, + hf_cand_bplus_lite::PtD, + hf_cand_bplus_lite::M, + hf_cand_bplus_lite::Pt, + hf_cand_bplus_lite::MlScoreSig, + hf_bplus_mc::PdgCodeBeautyMother, + hf_bplus_mc::PdgCodeCharmMother, + hf_bplus_mc::PdgCodeProng0, + hf_bplus_mc::PdgCodeProng1, + hf_bplus_mc::PdgCodeProng2); +} // namespace o2::aod + // string definitions, used for histogram axis labels const TString stringPt = "#it{p}_{T} (GeV/#it{c})"; +const TString stringPtD = "#it{p}_{T}(D0) (GeV/#it{c});"; const TString bPlusCandTitle = "B+ candidates;"; const TString entries = "entries"; const TString bPlusCandMatch = "B+ candidates (matched);"; @@ -40,33 +165,47 @@ const TString mcParticleMatched = "MC particles (matched);"; /// B+ analysis task struct HfTaskBplusReduced { + Produces hfRedCandBpLite; + Produces hfRedBpMcCheck; + Configurable selectionFlagBplus{"selectionFlagBplus", 1, "Selection Flag for Bplus"}; Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen particle rapidity"}; Configurable yCandRecoMax{"yCandRecoMax", 0.8, "max. cand. rapidity"}; Configurable etaTrackMax{"etaTrackMax", 0.8, "max. track pseudo-rapidity"}; Configurable ptTrackMin{"ptTrackMin", 0.1, "min. track transverse momentum"}; + Configurable fillHistograms{"fillHistograms", true, "Flag to enable histogram filling"}; + Configurable fillSparses{"fillSparses", false, "Flag to enable sparse filling"}; + Configurable fillTree{"fillTree", false, "Flag to enable tree filling"}; + Configurable fillBackground{"fillBackground", false, "Flag to enable filling of background histograms/sparses/tree (only MC)"}; + Configurable downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of background candidates to keep for ML trainings"}; + Configurable ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_bplus_to_d0_pi::vecBinsPt}, "pT bin limits"}; HfHelper hfHelper; + using TracksPion = soa::Join; + using CandsD0 = soa::Join; + Filter filterSelectCandidates = (aod::hf_sel_candidate_bplus::isSelBplusToD0Pi >= selectionFlagBplus); - HistogramRegistry registry{ - "registry", - {{"hPtProng0", bPlusCandTitle + "prong 0 #it{p}_{T} (GeV/#it{c});" + entries, {HistType::kTH1F, {{1000, 0., 50.}}}}, - {"hPtProng1", bPlusCandTitle + "prong 1 #it{p}_{T} (GeV/#it{c});" + entries, {HistType::kTH1F, {{200, 0., 10.}}}}, - {"hPtCand", bPlusCandTitle + "candidate #it{p}_{T} (GeV/#it{c});" + entries, {HistType::kTH1F, {{1000, 0., 50.}}}}, - {"hCentrality", "centrality;centrality percentile;" + entries, {HistType::kTH1F, {{100, 0., 100.}}}}, - {"hPtRecSig", bPlusCandMatch + "candidate #it{p}_{T} (GeV/#it{c});" + entries, {HistType::kTH1F, {{300, 0., 30.}}}}, - {"hPtRecBg", bPlusCandUnmatch + "candidate #it{p}_{T} (GeV/#it{c});" + entries, {HistType::kTH1F, {{300, 0., 30.}}}}, - {"hPtGenSig", bPlusCandMatch + "candidate #it{p}_{T}^{gen.} (GeV/#it{c});" + entries, {HistType::kTH1F, {{300, 0., 30.}}}}, - {"hPtGen", mcParticleMatched + "candidate #it{p}_{T} (GeV/#it{c});" + entries, {HistType::kTH1F, {{300, 0., 30.}}}}}}; + HistogramRegistry registry{"registry"}; void init(InitContext&) { - const AxisSpec axisMass{150, 4.5, 6.0}; - const AxisSpec axisCPA{120, -1.1, 1.1}; - const AxisSpec axisCPAFiner{300, 0.85, 1.0}; + std::array processFuncData{doprocessData, doprocessDataWithDmesMl, doprocessDataWithBplusMl}; + if ((std::accumulate(processFuncData.begin(), processFuncData.end(), 0)) > 1) { + LOGP(fatal, "Only one process function for data can be enabled at a time."); + } + std::array processFuncMc{doprocessMc, doprocessMcWithDecayTypeCheck, doprocessMcWithDmesMl, doprocessMcWithDmesMlAndDecayTypeCheck, doprocessMcWithBplusMl, doprocessMcWithBplusMlAndDecayTypeCheck}; + if ((std::accumulate(processFuncMc.begin(), processFuncMc.end(), 0)) > 1) { + LOGP(fatal, "Only one process function for MC can be enabled at a time."); + } + + const AxisSpec axisMlScore{100, 0.f, 1.f}; + const AxisSpec axisMassBplus{150, 4.5, 6.0}; + const AxisSpec axisMassD0{300, 1.75f, 2.05f}; + const AxisSpec axisCpa{120, -1.1, 1.1}; + const AxisSpec axisCpaD{101, 0.9, 1.01}; const AxisSpec axisPtProng{100, 0., 10.}; const AxisSpec axisD0Prong{200, -0.05, 0.05}; const AxisSpec axisImpParProd{200, -0.001, 0.001}; @@ -74,78 +213,160 @@ struct HfTaskBplusReduced { const AxisSpec axisNormDecLength{40, 0., 20}; const AxisSpec axisEta{100, -2., 2.}; const AxisSpec axisRapidity{100, -2., 2.}; + const AxisSpec axisPtD0{100, 0., 50.}; const AxisSpec axisPtB{(std::vector)binsPt, "#it{p}_{T}^{B^{+}} (GeV/#it{c})"}; - // histograms process - registry.add("hMass", bPlusCandTitle + "inv. mass #bar{D^{0}}#pi^{+} (GeV/#it{c}^{2});" + stringPt, {HistType::kTH2F, {axisMass, axisPtB}}); - registry.add("hDecLength", bPlusCandTitle + "decay length (cm);" + stringPt, {HistType::kTH2F, {axisDecLength, axisPtB}}); - registry.add("hDecLengthXY", bPlusCandTitle + "decay length xy (cm);" + stringPt, {HistType::kTH2F, {axisDecLength, axisPtB}}); - registry.add("hd0Prong0", bPlusCandTitle + "prong 0 DCAxy to prim. vertex (cm);" + stringPt, {HistType::kTH2F, {axisD0Prong, axisPtB}}); - registry.add("hd0Prong1", bPlusCandTitle + "prong 1 DCAxy to prim. vertex (cm);" + stringPt, {HistType::kTH2F, {axisD0Prong, axisPtB}}); - registry.add("hCPA", bPlusCandTitle + "candidate cosine of pointing angle;" + stringPt, {HistType::kTH2F, {axisCPA, axisPtB}}); - registry.add("hCPAxy", bPlusCandTitle + "candidate cosine of pointing angle xy;" + stringPt, {HistType::kTH2F, {axisCPA, axisPtB}}); - registry.add("hEta", bPlusCandTitle + "candidate #it{#eta};" + stringPt, {HistType::kTH2F, {axisEta, axisPtB}}); - registry.add("hRapidity", bPlusCandTitle + "candidate #it{y};" + stringPt, {HistType::kTH2F, {axisRapidity, axisPtB}}); - registry.add("hImpParErr", bPlusCandTitle + "candidate impact parameter error (cm);" + stringPt, {HistType::kTH2F, {{100, -1., 1.}, axisPtB}}); - registry.add("hDecLenErr", bPlusCandTitle + "candidate decay length error (cm);" + stringPt, {HistType::kTH2F, {{100, 0., 1.}, axisPtB}}); - registry.add("hDecLenXYErr", bPlusCandTitle + "candidate decay length xy error (cm);" + stringPt, {HistType::kTH2F, {{100, 0., 1.}, axisPtB}}); - registry.add("hd0d0", bPlusCandTitle + "candidate product of DCAxy to prim. vertex (cm^{2});" + stringPt, {HistType::kTH2F, {axisImpParProd, axisPtB}}); - registry.add("hInvMassD0", bPlusCandTitle + "prong0, D0 inv. mass (GeV/#it{c}^{2});" + stringPt, {HistType::kTH2F, {{500, 1.4, 2.4}, axisPtB}}); - registry.add("hCPAFinerBinning", bPlusCandTitle + "candidate cosine of pointing angle;" + stringPt, {HistType::kTH2F, {axisCPAFiner, axisPtB}}); - registry.add("hCPAxyFinerBinning", bPlusCandTitle + "candidate cosine of pointing angle xy;" + stringPt, {HistType::kTH2F, {axisCPAFiner, axisPtB}}); - // histograms processMC - Gen Level - registry.add("hEtaGen", mcParticleMatched + "candidate #it{#eta}^{gen};" + stringPt, {HistType::kTH2F, {axisEta, axisPtB}}); - registry.add("hYGen", mcParticleMatched + "candidate #it{y}^{gen};" + stringPt, {HistType::kTH2F, {axisRapidity, axisPtB}}); - registry.add("hPtProng0Gen", mcParticleMatched + "prong 0 #it{p}_{T}^{gen} (GeV/#it{c});" + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); - registry.add("hPtProng1Gen", mcParticleMatched + "prong 1 #it{p}_{T}^{gen} (GeV/#it{c});" + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); - registry.add("hYProng0Gen", mcParticleMatched + "prong 0 #it{y}^{gen};" + stringPt, {HistType::kTH2F, {axisRapidity, axisPtB}}); - registry.add("hYProng1Gen", mcParticleMatched + "prong 1 #it{y}^{gen};" + stringPt, {HistType::kTH2F, {axisRapidity, axisPtB}}); - registry.add("hEtaProng0Gen", mcParticleMatched + "prong 0 #it{#eta}^{gen};" + stringPt, {HistType::kTH2F, {axisEta, axisPtB}}); - registry.add("hEtaProng1Gen", mcParticleMatched + "prong 1 #it{#eta}^{gen};" + stringPt, {HistType::kTH2F, {axisEta, axisPtB}}); - registry.add("hPtProngsVsPtBGen", mcParticleMatched + "prong 0 #it{p}_{T}^{gen} (GeV/#it{c});prong 1 #it{p}_{T}^{gen} (GeV/#it{c});" + stringPt, {HistType::kTH3F, {axisPtProng, axisPtProng, axisPtB}}); - registry.add("hYProngsVsBplusGen", mcParticleMatched + "prong 0 #it{y}^{gen};prong 1 #it{y}^{gen};" + stringPt, {HistType::kTH3F, {axisRapidity, axisRapidity, axisPtB}}); - registry.add("hEtaProngsVsBplusGen", mcParticleMatched + "prong 0 #it{#eta}^{gen};prong 1 #it{#eta}^{gen};" + stringPt, {HistType::kTH3F, {axisEta, axisEta, axisPtB}}); - registry.add("hPtGenWithRapidityBelowHalf", "MC particles (generated - |#it{y}^{gen}|<0.5);candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 30.}}}); - registry.add("hPtGenWithProngsInAcceptance", "MC particles (generated-daughters in acceptance);candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 30.}}}); - registry.add("hEtaGenWithProngsInAcceptance", "MC particles (generated-daughters in acceptance);B^{0} candidate #it{#eta}^{gen};entries", {HistType::kTH2F, {{100, -2., 2.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hYGenWithProngsInAcceptance", "MC particles (generated-daughters in acceptance);B^{0} candidate #it{y}^{gen};entries", {HistType::kTH2F, {{100, -2., 2.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - // histograms processMC - Reco Level - registry.add("hCPARecSig", bPlusCandMatch + "candidate cosine of pointing angle;" + stringPt, {HistType::kTH2F, {axisCPA, axisPtB}}); - registry.add("hCPARecBg", bPlusCandUnmatch + "candidate cosine of pointing angle;" + stringPt, {HistType::kTH2F, {axisCPA, axisPtB}}); - registry.add("hCPAxyRecSig", bPlusCandMatch + "candidate CPAxy;" + stringPt, {HistType::kTH2F, {axisCPA, axisPtB}}); - registry.add("hCPAxyRecBg", bPlusCandUnmatch + "candidate CPAxy;" + stringPt, {HistType::kTH2F, {axisCPA, axisPtB}}); - registry.add("hEtaRecSig", bPlusCandMatch + "candidate #it{#eta};" + stringPt, {HistType::kTH2F, {axisEta, axisPtB}}); - registry.add("hEtaRecBg", bPlusCandUnmatch + "candidate #it{#eta};" + stringPt, {HistType::kTH2F, {axisEta, axisPtB}}); - registry.add("hRapidityRecSig", bPlusCandMatch + "candidate #it{y};" + stringPt, {HistType::kTH2F, {axisRapidity, axisPtB}}); - registry.add("hRapidityRecBg", bPlusCandUnmatch + "candidate #it{#y};" + stringPt, {HistType::kTH2F, {axisRapidity, axisPtB}}); - registry.add("hPtProng0RecSig", bPlusCandMatch + "prong 0 #it{p}_{T} (GeV/#it{c});" + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); - registry.add("hPtProng1RecSig", bPlusCandMatch + "prong 1 #it{p}_{T} (GeV/#it{c});" + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); - registry.add("hPtProngsVsBplusRecBg", bPlusCandUnmatch + "prong 0 #it{p}_{T} (GeV/#it{c});prong 1 #it{p}_{T} (GeV/#it{c});" + stringPt, {HistType::kTH3F, {axisPtProng, axisPtProng, axisPtB}}); - registry.add("hPtProng0RecBg", bPlusCandUnmatch + "prong 0 #it{p}_{T} (GeV/#it{c});" + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); - registry.add("hPtProng1RecBg", bPlusCandUnmatch + "prong 1 #it{p}_{T} (GeV/#it{c});" + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); - registry.add("hMassRecSig", bPlusCandMatch + "inv. mass #bar{D^{0}}#pi^{+} (GeV/#it{c}^{2});" + stringPt, {HistType::kTH2F, {axisMass, axisPtB}}); - registry.add("hMassRecBg", bPlusCandUnmatch + "inv. mass #bar{D^{0}}#pi^{+} (GeV/#it{c}^{2});" + stringPt, {HistType::kTH2F, {axisMass, axisPtB}}); - registry.add("hd0Prong0RecSig", bPlusCandMatch + "prong 0 DCAxy to prim. vertex (cm);" + stringPt, {HistType::kTH2F, {axisD0Prong, axisPtB}}); - registry.add("hd0Prong1RecSig", bPlusCandMatch + "prong 1 DCAxy to prim. vertex (cm);" + stringPt, {HistType::kTH2F, {axisD0Prong, axisPtB}}); - registry.add("hd0Prong0RecBg", bPlusCandUnmatch + "prong 0 DCAxy to prim. vertex (cm);" + stringPt, {HistType::kTH2F, {axisD0Prong, axisPtB}}); - registry.add("hd0Prong1RecBg", bPlusCandUnmatch + "prong 1 DCAxy to prim. vertex (cm);" + stringPt, {HistType::kTH2F, {axisD0Prong, axisPtB}}); - registry.add("hDecLengthRecSig", bPlusCandMatch + "candidate decay length (cm);" + stringPt, {HistType::kTH2F, {axisDecLength, axisPtB}}); - registry.add("hDecLengthXYRecSig", bPlusCandMatch + "candidate decay length xy (cm);" + stringPt, {HistType::kTH2F, {axisDecLength, axisPtB}}); - registry.add("hDecLengthRecBg", bPlusCandUnmatch + "candidate decay length (cm);" + stringPt, {HistType::kTH2F, {axisDecLength, axisPtB}}); - registry.add("hDecLengthXYRecBg", bPlusCandUnmatch + "candidate decay length xy(cm);" + stringPt, {HistType::kTH2F, {axisDecLength, axisPtB}}); - registry.add("hDecLengthNormRecSig", bPlusCandMatch + "candidate normalized decay length (cm);" + stringPt, {HistType::kTH2F, {axisNormDecLength, axisPtB}}); - registry.add("hDecLengthNormRecBg", bPlusCandUnmatch + "candidate normalized decay length (cm);" + stringPt, {HistType::kTH2F, {axisNormDecLength, axisPtB}}); - registry.add("hd0d0RecSig", bPlusCandMatch + "product of DCAxy to prim. vertex (cm^{2});" + stringPt, {HistType::kTH2F, {axisImpParProd, axisPtB}}); - registry.add("hd0d0RecBg", bPlusCandUnmatch + "product of DCAxy to prim. vertex (cm^{2});" + stringPt, {HistType::kTH2F, {axisImpParProd, axisPtB}}); - // MC histograms with finer binning - registry.add("hCPAFinerBinningRecSig", bPlusCandMatch + "candidate cosine of pointing angle;" + stringPt, {HistType::kTH2F, {axisCPAFiner, axisPtB}}); - registry.add("hCPAFinerBinningRecBg", bPlusCandMatch + "candidate cosine of pointing angle;" + stringPt, {HistType::kTH2F, {axisCPAFiner, axisPtB}}); - registry.add("hCPAxyFinerBinningRecSig", bPlusCandMatch + "candidate cosine of pointing angle;" + stringPt, {HistType::kTH2F, {axisCPAFiner, axisPtB}}); - registry.add("hCPAxyFinerBinningRecBg", bPlusCandMatch + "candidate cosine of pointing angle;" + stringPt, {HistType::kTH2F, {axisCPAFiner, axisPtB}}); - // histograms prong0(D0) - Reco Level - registry.add("hCPAD0RecSig", bPlusCandMatch + "prong0 (D^{0}) cosine of pointing angle;#it{p}_{T}(D0) (GeV/#it{c})" + entries, {HistType::kTH2F, {{220, 0., 1.1}, {120, 0., 60.}}}); - registry.add("hCPAD0RecBg", bPlusCandUnmatch + "prong0 (D^{0}) cosine of pointing angle;#it{p}_{T}(D0) (GeV/#it{c})" + entries, {HistType::kTH2F, {{220, 0., 1.1}, {120, 0., 60.}}}); - registry.add("hDecLengthD0RecSig", bPlusCandMatch + "prong0 D^{0} decay length (cm);#it{p}_{T}(D0) (GeV/#it{c})" + entries, {HistType::kTH2F, {{100, 0., 0.5}, {120, 0., 60.}}}); - registry.add("hDecLengthD0RecBg", bPlusCandUnmatch + "prong0 D^{0} candidate decay length (cm);#it{p}_{T}(D0) (GeV/#it{c})" + entries, {HistType::kTH2F, {{100, 0., 0.5}, {120, 0., 60.}}}); + const AxisSpec axisPtPi{100, 0.f, 10.f}; + + if (doprocessData || doprocessDataWithDmesMl || doprocessDataWithBplusMl) { + if (fillHistograms) { + registry.add("hMass", bPlusCandTitle + "inv. mass #bar{D^{0}}#pi^{+} (GeV/#it{c}^{2});" + stringPt, {HistType::kTH2F, {axisMassBplus, axisPtB}}); + registry.add("hPtCand", bPlusCandTitle + "candidate #it{p}_{T} (GeV/#it{c});" + entries, {HistType::kTH1F, {{1000, 0., 50.}}}); + registry.add("hPtProng0", bPlusCandTitle + "prong 0 #it{p}_{T}^{gen} (GeV/#it{c});" + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); + registry.add("hPtProng1", bPlusCandTitle + "prong 1 #it{p}_{T}^{gen} (GeV/#it{c});" + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); + registry.add("hDecLength", bPlusCandTitle + "decay length (cm);" + stringPt, {HistType::kTH2F, {axisDecLength, axisPtB}}); + registry.add("hDecLengthXy", bPlusCandTitle + "decay length xy (cm);" + stringPt, {HistType::kTH2F, {axisDecLength, axisPtB}}); + registry.add("hNormDecLengthXy", bPlusCandTitle + "Norm. decay length xy (cm);" + stringPt, {HistType::kTH2F, {axisNormDecLength, axisPtB}}); + registry.add("hd0Prong0", bPlusCandTitle + "prong 0 DCAxy to prim. vertex (cm);" + stringPt, {HistType::kTH2F, {axisD0Prong, axisPtB}}); + registry.add("hd0Prong1", bPlusCandTitle + "prong 1 DCAxy to prim. vertex (cm);" + stringPt, {HistType::kTH2F, {axisD0Prong, axisPtB}}); + registry.add("hCpa", bPlusCandTitle + "candidate cosine of pointing angle;" + stringPt, {HistType::kTH2F, {axisCpa, axisPtB}}); + registry.add("hCpaXy", bPlusCandTitle + "candidate cosine of pointing angle xy;" + stringPt, {HistType::kTH2F, {axisCpa, axisPtB}}); + registry.add("hEta", bPlusCandTitle + "candidate #it{#eta};" + stringPt, {HistType::kTH2F, {axisEta, axisPtB}}); + registry.add("hRapidity", bPlusCandTitle + "candidate #it{y};" + stringPt, {HistType::kTH2F, {axisRapidity, axisPtB}}); + registry.add("hd0d0", bPlusCandTitle + "candidate product of DCAxy to prim. vertex (cm^{2});" + stringPt, {HistType::kTH2F, {axisImpParProd, axisPtB}}); + registry.add("hInvMassD0", bPlusCandTitle + "prong0, D0 inv. mass (GeV/#it{c}^{2});" + stringPt, {HistType::kTH2F, {axisMassD0, axisPtD0}}); + registry.add("hDecLengthD0", bPlusCandTitle + "D^{0} candidate decay length (cm);#it{p}_{T}(D^{0}) (GeV/#it{c});entries", {HistType::kTH2F, {axisDecLength, axisPtD0}}); + registry.add("hDecLengthXyD0", bPlusCandTitle + "decay length XY (cm);#it{p}_{T}(D^{0}) (GeV/#it{c});entries", {HistType::kTH2F, {axisDecLength, axisPtD0}}); + registry.add("hCpaD0", bPlusCandTitle + "D^{0} candidate cos(#vartheta_{P});#it{p}_{T}(D^{0}) (GeV/#it{c});entries", {HistType::kTH2F, {axisCpaD, axisPtD0}}); + registry.add("hCpaXyD0", bPlusCandTitle + "D^{0} candidate cos(#vartheta_{P}^{XY});#it{p}_{T}(D^{0}) (GeV/#it{c});entries", {HistType::kTH2F, {axisCpaD, axisPtD0}}); + + // ML scores of D0 daughter + if (doprocessDataWithDmesMl) { + registry.add("hMlScoreBkgD", bPlusCandTitle + "#it{p}_{T}(D0) (GeV/#it{c});prong0, D0 ML background score;entries", {HistType::kTH2F, {axisPtD0, axisMlScore}}); + registry.add("hMlScorePromptD", bPlusCandTitle + "#it{p}_{T}(D0) (GeV/#it{c});prong0, D0 ML prompt score;entries", {HistType::kTH2F, {axisPtD0, axisMlScore}}); + registry.add("hMlScoreNonPromptD", bPlusCandTitle + "#it{p}_{T}(D0) (GeV/#it{c});prong0, D0 ML nonprompt score;entries", {HistType::kTH2F, {axisPtD0, axisMlScore}}); + } + + // ML scores of B+ candidate + if (doprocessDataWithBplusMl) { + registry.add("hMlScoreSigBplus", bPlusCandTitle + "#it{p}_{T} (GeV/#it{c});prong0, B^{+} ML signal score;entries", {HistType::kTH2F, {axisPtB, axisMlScore}}); + } + } + if (fillSparses) { + if (!(doprocessDataWithDmesMl || doprocessDataWithBplusMl)) { + registry.add("hMassPtCutVars", bPlusCandTitle + "#it{M} (D0#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{+}) (GeV/#it{c});B^{+} candidate decay length (cm);B^{+} candidate norm. decay length XY (cm);B^{+} candidate impact parameter product (cm);B^{+} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(D0) (GeV/#it{c});D0 candidate decay length (cm);D0 candidate cos(#vartheta_{P})", {HistType::kTHnSparseF, {axisMassBplus, axisPtB, axisDecLength, axisNormDecLength, axisImpParProd, axisCpa, axisMassD0, axisPtD0, axisDecLength, axisCpa}}); + } else { + registry.add("hMassPtCutVars", bPlusCandTitle + "#it{M} (D0#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{+}) (GeV/#it{c});B^{+} candidate decay length (cm);B^{+} candidate norm. decay length XY (cm);B^{+} candidate impact parameter product (cm);B^{+} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(D0) (GeV/#it{c});D0 candidate ML score bkg;D0 candidate ML score nonprompt", {HistType::kTHnSparseF, {axisMassBplus, axisPtB, axisDecLength, axisNormDecLength, axisImpParProd, axisCpa, axisMassD0, axisPtD0, axisMlScore, axisMlScore}}); + } + } + } + + // histograms processMC + if (doprocessMc || doprocessMcWithDecayTypeCheck || doprocessMcWithDmesMl || doprocessMcWithDmesMlAndDecayTypeCheck || doprocessMcWithBplusMl || doprocessMcWithBplusMlAndDecayTypeCheck) { + if (fillHistograms) { + // Gen Level + registry.add("hEtaGen", mcParticleMatched + "candidate #it{#eta}^{gen};" + stringPt, {HistType::kTH2F, {axisEta, axisPtB}}); + registry.add("hYGen", mcParticleMatched + "candidate #it{y}^{gen};" + stringPt, {HistType::kTH2F, {axisRapidity, axisPtB}}); + registry.add("hPtProng0Gen", mcParticleMatched + "prong 0 #it{p}_{T}^{gen} (GeV/#it{c});" + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); + registry.add("hPtProng1Gen", mcParticleMatched + "prong 1 #it{p}_{T}^{gen} (GeV/#it{c});" + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); + registry.add("hYProng0Gen", mcParticleMatched + "prong 0 #it{y}^{gen};" + stringPt, {HistType::kTH2F, {axisRapidity, axisPtB}}); + registry.add("hYProng1Gen", mcParticleMatched + "prong 1 #it{y}^{gen};" + stringPt, {HistType::kTH2F, {axisRapidity, axisPtB}}); + registry.add("hEtaProng0Gen", mcParticleMatched + "prong 0 #it{#eta}^{gen};" + stringPt, {HistType::kTH2F, {axisEta, axisPtB}}); + registry.add("hEtaProng1Gen", mcParticleMatched + "prong 1 #it{#eta}^{gen};" + stringPt, {HistType::kTH2F, {axisEta, axisPtB}}); + registry.add("hPtProngsVsPtBGen", mcParticleMatched + "prong 0 #it{p}_{T}^{gen} (GeV/#it{c});prong 1 #it{p}_{T}^{gen} (GeV/#it{c});" + stringPt, {HistType::kTH3F, {axisPtProng, axisPtProng, axisPtB}}); + registry.add("hYProngsVsBplusGen", mcParticleMatched + "prong 0 #it{y}^{gen};prong 1 #it{y}^{gen};" + stringPt, {HistType::kTH3F, {axisRapidity, axisRapidity, axisPtB}}); + registry.add("hEtaProngsVsBplusGen", mcParticleMatched + "prong 0 #it{#eta}^{gen};prong 1 #it{#eta}^{gen};" + stringPt, {HistType::kTH3F, {axisEta, axisEta, axisPtB}}); + registry.add("hYGenWithProngsInAcceptance", "MC particles (generated-daughters in acceptance);B^{+} candidate #it{y}^{gen};entries", {HistType::kTH2F, {{100, -2., 2.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + // Reco Level - Signal + registry.add("hPtRecSig", bPlusCandMatch + "candidate #it{p}_{T} (GeV/#it{c});" + entries, {HistType::kTH1F, {{300, 0., 30.}}}); + registry.add("hCpaRecSig", bPlusCandMatch + "candidate cosine of pointing angle;" + stringPt, {HistType::kTH2F, {axisCpa, axisPtB}}); + registry.add("hCpaXyRecSig", bPlusCandMatch + "candidate CpaXy;" + stringPt, {HistType::kTH2F, {axisCpa, axisPtB}}); + registry.add("hEtaRecSig", bPlusCandMatch + "candidate #it{#eta};" + stringPt, {HistType::kTH2F, {axisEta, axisPtB}}); + registry.add("hRapidityRecSig", bPlusCandMatch + "candidate #it{y};" + stringPt, {HistType::kTH2F, {axisRapidity, axisPtB}}); + registry.add("hPtProng0RecSig", bPlusCandMatch + "prong 0 #it{p}_{T} (GeV/#it{c});" + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); + registry.add("hPtProng1RecSig", bPlusCandMatch + "prong 1 #it{p}_{T} (GeV/#it{c});" + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); + registry.add("hMassRecSig", bPlusCandMatch + "inv. mass #bar{D^{0}}#pi^{+} (GeV/#it{c}^{2});" + stringPt, {HistType::kTH2F, {axisMassBplus, axisPtB}}); + registry.add("hd0Prong0RecSig", bPlusCandMatch + "prong 0 DCAxy to prim. vertex (cm);" + stringPt, {HistType::kTH2F, {axisD0Prong, axisPtB}}); + registry.add("hd0Prong1RecSig", bPlusCandMatch + "prong 1 DCAxy to prim. vertex (cm);" + stringPt, {HistType::kTH2F, {axisD0Prong, axisPtB}}); + registry.add("hDecLengthRecSig", bPlusCandMatch + "candidate decay length (cm);" + stringPt, {HistType::kTH2F, {axisDecLength, axisPtB}}); + registry.add("hDecLengthXyRecSig", bPlusCandMatch + "candidate decay length xy (cm);" + stringPt, {HistType::kTH2F, {axisDecLength, axisPtB}}); + registry.add("hNormDecLengthXyRecSig", bPlusCandMatch + "candidate normalized decay length (cm);" + stringPt, {HistType::kTH2F, {axisNormDecLength, axisPtB}}); + registry.add("hd0d0RecSig", bPlusCandMatch + "product of DCAxy to prim. vertex (cm^{2});" + stringPt, {HistType::kTH2F, {axisImpParProd, axisPtB}}); + registry.add("hCpaD0RecSig", bPlusCandMatch + "prong0 (D^{0}) cosine of pointing angle;" + stringPtD + entries, {HistType::kTH2F, {{220, 0., 1.1}, {120, 0., 60.}}}); + registry.add("hCpaXyD0RecSig", bPlusCandMatch + "prong0 (D^{0}) cosine of pointing angle;" + stringPtD + entries, {HistType::kTH2F, {{220, 0., 1.1}, {120, 0., 60.}}}); + registry.add("hDecLengthD0RecSig", bPlusCandMatch + "prong0 D^{0} decay length (cm);" + stringPtD + entries, {HistType::kTH2F, {{100, 0., 0.5}, {120, 0., 60.}}}); + registry.add("hDecLengthXyD0RecSig", bPlusCandMatch + "prong0 D^{0} decay length XY (cm);" + stringPtD + entries, {HistType::kTH2F, {{100, 0., 0.5}, {120, 0., 60.}}}); + // background + if (fillBackground) { + registry.add("hPtRecBg", bPlusCandUnmatch + "candidate #it{p}_{T} (GeV/#it{c});" + entries, {HistType::kTH1F, {{300, 0., 30.}}}); + registry.add("hCpaRecBg", bPlusCandUnmatch + "candidate cosine of pointing angle;" + stringPt, {HistType::kTH2F, {axisCpa, axisPtB}}); + registry.add("hCpaXyRecBg", bPlusCandUnmatch + "candidate CpaXy;" + stringPt, {HistType::kTH2F, {axisCpa, axisPtB}}); + registry.add("hEtaRecBg", bPlusCandUnmatch + "candidate #it{#eta};" + stringPt, {HistType::kTH2F, {axisEta, axisPtB}}); + registry.add("hRapidityRecBg", bPlusCandUnmatch + "candidate #it{#y};" + stringPt, {HistType::kTH2F, {axisRapidity, axisPtB}}); + registry.add("hPtProngsVsBplusRecBg", bPlusCandUnmatch + "prong 0 #it{p}_{T} (GeV/#it{c});prong 1 #it{p}_{T} (GeV/#it{c});" + stringPt, {HistType::kTH3F, {axisPtProng, axisPtProng, axisPtB}}); + registry.add("hPtProng0RecBg", bPlusCandUnmatch + "prong 0 #it{p}_{T} (GeV/#it{c});" + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); + registry.add("hPtProng1RecBg", bPlusCandUnmatch + "prong 1 #it{p}_{T} (GeV/#it{c});" + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); + registry.add("hMassRecBg", bPlusCandUnmatch + "inv. mass #bar{D^{0}}#pi^{+} (GeV/#it{c}^{2});" + stringPt, {HistType::kTH2F, {axisMassBplus, axisPtB}}); + registry.add("hd0Prong0RecBg", bPlusCandUnmatch + "prong 0 DCAxy to prim. vertex (cm);" + stringPt, {HistType::kTH2F, {axisD0Prong, axisPtB}}); + registry.add("hd0Prong1RecBg", bPlusCandUnmatch + "prong 1 DCAxy to prim. vertex (cm);" + stringPt, {HistType::kTH2F, {axisD0Prong, axisPtB}}); + registry.add("hDecLengthRecBg", bPlusCandUnmatch + "candidate decay length (cm);" + stringPt, {HistType::kTH2F, {axisDecLength, axisPtB}}); + registry.add("hDecLengthXyRecBg", bPlusCandUnmatch + "candidate decay length xy(cm);" + stringPt, {HistType::kTH2F, {axisDecLength, axisPtB}}); + registry.add("hNormDecLengthXyRecBg", bPlusCandUnmatch + "candidate normalized decay length (cm);" + stringPt, {HistType::kTH2F, {axisNormDecLength, axisPtB}}); + registry.add("hd0d0RecBg", bPlusCandUnmatch + "product of DCAxy to prim. vertex (cm^{2});" + stringPt, {HistType::kTH2F, {axisImpParProd, axisPtB}}); + registry.add("hCpaD0RecBg", bPlusCandUnmatch + "prong0 (D^{0}) cosine of pointing angle;" + stringPtD + entries, {HistType::kTH2F, {{220, 0., 1.1}, {120, 0., 60.}}}); + registry.add("hCpaXyD0RecBg", bPlusCandUnmatch + "prong0 (D^{0}) cosine of pointing angle;" + stringPtD + entries, {HistType::kTH2F, {{220, 0., 1.1}, {120, 0., 60.}}}); + registry.add("hDecLengthD0RecBg", bPlusCandUnmatch + "prong0 D^{0} decay length (cm);" + stringPtD + entries, {HistType::kTH2F, {{100, 0., 0.5}, {120, 0., 60.}}}); + registry.add("hDecLengthXyD0RecBg", bPlusCandUnmatch + "prong0 D^{0} decay length XY (cm);" + stringPtD + entries, {HistType::kTH2F, {{100, 0., 0.5}, {120, 0., 60.}}}); + } + // MC checks + if (doprocessMcWithDecayTypeCheck || doprocessMcWithDmesMlAndDecayTypeCheck || doprocessMcWithBplusMlAndDecayTypeCheck) { + constexpr uint8_t kNBinsDecayTypeMc = hf_cand_bplus::DecayTypeMc::NDecayTypeMc; + TString labels[kNBinsDecayTypeMc]; + labels[hf_cand_bplus::DecayTypeMc::BplusToD0PiToKPiPi] = "B^{+} #rightarrow (#overline{D^{0}} #rightarrow K^{#plus} #pi^{#minus}) #pi^{#plus}"; + labels[hf_cand_bplus::DecayTypeMc::PartlyRecoDecay] = "Partly reconstructed decay channel"; + labels[hf_cand_bplus::DecayTypeMc::OtherDecay] = "Other decays"; + static const AxisSpec axisDecayType = {kNBinsDecayTypeMc, 0.5, kNBinsDecayTypeMc + 0.5, ""}; + registry.add("hDecayTypeMc", "DecayType", {HistType::kTH3F, {axisDecayType, axisMassBplus, axisPtB}}); + for (uint8_t iBin = 0; iBin < kNBinsDecayTypeMc; ++iBin) { + registry.get(HIST("hDecayTypeMc"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin]); + } + } + // ML scores of D0 daughter + if (doprocessMcWithDmesMl || doprocessMcWithDmesMlAndDecayTypeCheck) { + // signal + registry.add("hMlScoreBkgDRecSig", bPlusCandMatch + stringPtD + "prong0, D0 ML background score;entries", {HistType::kTH2F, {axisPtD0, axisMlScore}}); + registry.add("hMlScorePromptDRecSig", bPlusCandMatch + stringPtD + "prong0, D0 ML prompt score;entries", {HistType::kTH2F, {axisPtD0, axisMlScore}}); + registry.add("hMlScoreNonPromptDRecSig", bPlusCandMatch + stringPtD + "prong0, D0 ML nonprompt score;entries", {HistType::kTH2F, {axisPtD0, axisMlScore}}); + // background + registry.add("hMlScoreBkgDRecBg", bPlusCandUnmatch + stringPtD + "prong0, D0 ML background score;entries", {HistType::kTH2F, {axisPtD0, axisMlScore}}); + registry.add("hMlScorePromptDRecBg", bPlusCandUnmatch + stringPtD + "prong0, D0 ML prompt score;entries", {HistType::kTH2F, {axisPtD0, axisMlScore}}); + registry.add("hMlScoreNonPromptDRecBg", bPlusCandUnmatch + stringPtD + "prong0, D0 ML nonprompt score;entries", {HistType::kTH2F, {axisPtD0, axisMlScore}}); + } + // ML scores of B+ candidate + if (doprocessMcWithBplusMl || doprocessMcWithBplusMlAndDecayTypeCheck) { + // signal + registry.add("hMlScoreSigBplusRecSig", bPlusCandMatch + "#it{p}_{T}(B^{+}) (GeV/#it{c});prong0, B^{+} ML signal score;entries", {HistType::kTH2F, {axisPtB, axisMlScore}}); + // background + registry.add("hMlScoreSigBplusRecBg", bPlusCandUnmatch + "#it{p}_{T}(B^{+}) (GeV/#it{c});prong0, B^{+} ML signal score;entries", {HistType::kTH2F, {axisPtB, axisMlScore}}); + } + } + if (fillSparses) { + // gen sparses + registry.add("hPtYGenSig", "B^{+} particles (generated);#it{p}_{T}(B^{+}) (GeV/#it{c});#it{y}(B^{+})", {HistType::kTHnSparseF, {axisPtB, axisEta}}); + registry.add("hPtYWithProngsInAccepanceGenSig", "B^{+} particles (generated-daughters in acceptance);#it{p}_{T}(B^{+}) (GeV/#it{c});#it{y}(B^{+})", {HistType::kTHnSparseF, {axisPtB, axisEta}}); + // reco sparses + if (!doprocessDataWithDmesMl) { + registry.add("hMassPtCutVarsRecSig", bPlusCandMatch + "#it{M} (D^{0}#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{+}) (GeV/#it{c});B^{+} candidate decay length (cm);B^{+} candidate norm. decay length XY (cm);B^{+} candidate impact parameter product (cm);B^{+} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(D0) (GeV/#it{c});D0 candidate decay length (cm);D0 candidate cos(#vartheta_{P})", {HistType::kTHnSparseF, {axisMassBplus, axisPtB, axisDecLength, axisNormDecLength, axisImpParProd, axisCpa, axisMassD0, axisPtD0, axisDecLength, axisCpa}}); + if (fillBackground) { + registry.add("hMassPtCutVarsRecBg", bPlusCandUnmatch + "#it{M} (D^{0}#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{+}) (GeV/#it{c});B^{+} candidate decay length (cm);B^{+} candidate norm. decay length XY (cm);B^{+} candidate impact parameter product (cm);B^{+} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(D0) (GeV/#it{c});D0 candidate decay length (cm);D0 candidate cos(#vartheta_{P})", {HistType::kTHnSparseF, {axisMassBplus, axisPtB, axisDecLength, axisNormDecLength, axisImpParProd, axisCpa, axisMassD0, axisPtD0, axisDecLength, axisCpa}}); + } + } else { + registry.add("hMassPtCutVarsRecSig", bPlusCandMatch + "#it{M} (D^{0}#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{+}) (GeV/#it{c});B^{+} candidate decay length (cm);B^{+} candidate norm. decay length XY (cm);B^{+} candidate impact parameter product (cm);B^{+} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(D0) (GeV/#it{c});D0 candidate ML score bkg;D0 candidate ML score nonprompt", {HistType::kTHnSparseF, {axisMassBplus, axisPtB, axisDecLength, axisNormDecLength, axisImpParProd, axisCpa, axisMassD0, axisPtD0, axisMlScore, axisMlScore}}); + if (fillBackground) { + registry.add("hMassPtCutVarsRecBg", bPlusCandUnmatch + "#it{M} (D^{0}#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{+}) (GeV/#it{c});B^{+} candidate decay length (cm);B^{+} candidate norm. decay length XY (cm);B^{+} candidate impact parameter product (cm);B^{+} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(D0) (GeV/#it{c});D0 candidate ML score bkg;D0 candidate ML score nonprompt", {HistType::kTHnSparseF, {axisMassBplus, axisPtB, axisDecLength, axisNormDecLength, axisImpParProd, axisCpa, axisMassD0, axisPtD0, axisMlScore, axisMlScore}}); + } + } + } + } } /// Selection of B+ daughter in geometrical acceptance @@ -158,152 +379,474 @@ struct HfTaskBplusReduced { return std::abs(etaProng) <= etaTrackMax && ptProng >= ptTrackMin; } - void process(soa::Filtered> const& candidates, - aod::HfRed2Prongs const&, - aod::HfRedTracks const&) + /// Fill candidate information at reconstruction level + /// \param doMc is the flag to enable the filling with MC information + /// \param withDecayTypeCheck is the flag to enable MC with decay type check + /// \param withDmesMl is the flag to enable the filling with ML scores for the D0 daughter + /// \param withBplusMl is the flag to enable the filling with ML scores for the B+ candidate + /// \param candidate is the B+ candidate + /// \param candidatesD is the table with D0 candidates + template + void fillCand(Cand const& candidate, + CandsDmes const& /*candidatesD*/, + TracksPion const&) + { + auto ptCandBplus = candidate.pt(); + auto invMassBplus = hfHelper.invMassBplusToD0Pi(candidate); + auto candD0 = candidate.template prong0_as(); + auto candPi = candidate.template prong1_as(); + auto ptD0 = candidate.ptProng0(); + auto invMassD0 = (candPi.signed1Pt() < 0) ? candD0.invMassHypo0() : candD0.invMassHypo1(); + std::array posPv{candidate.posX(), candidate.posY(), candidate.posZ()}; + std::array posSvD{candD0.xSecondaryVertex(), candD0.ySecondaryVertex(), candD0.zSecondaryVertex()}; + std::array momD{candD0.pVector()}; + auto cpaD0 = RecoDecay::cpa(posPv, posSvD, momD); + auto cpaXyD0 = RecoDecay::cpaXY(posPv, posSvD, momD); + auto decLenD0 = RecoDecay::distance(posPv, posSvD); + auto decLenXyD0 = RecoDecay::distanceXY(posPv, posSvD); + + int8_t flagMcMatchRec = 0; + int8_t flagWrongCollision = 0; + bool isSignal = false; + if constexpr (doMc) { + flagMcMatchRec = candidate.flagMcMatchRec(); + flagWrongCollision = candidate.flagWrongCollision(); + isSignal = TESTBIT(std::abs(flagMcMatchRec), hf_cand_bplus::DecayTypeMc::BplusToD0PiToKPiPi); + } + + if (fillHistograms) { + if constexpr (doMc) { + if (isSignal) { + registry.fill(HIST("hMassRecSig"), invMassBplus, ptCandBplus); + registry.fill(HIST("hPtRecSig"), ptCandBplus); + registry.fill(HIST("hPtProng0RecSig"), ptD0, ptCandBplus); + registry.fill(HIST("hPtProng1RecSig"), candidate.ptProng1(), ptCandBplus); + registry.fill(HIST("hCpaRecSig"), candidate.cpa(), ptCandBplus); + registry.fill(HIST("hCpaXyRecSig"), candidate.cpaXY(), ptCandBplus); + registry.fill(HIST("hEtaRecSig"), candidate.eta(), ptCandBplus); + registry.fill(HIST("hRapidityRecSig"), hfHelper.yBplus(candidate), ptCandBplus); + registry.fill(HIST("hDecLengthRecSig"), candidate.decayLength(), ptCandBplus); + registry.fill(HIST("hDecLengthXyRecSig"), candidate.decayLengthXY(), ptCandBplus); + registry.fill(HIST("hNormDecLengthXyRecSig"), candidate.decayLengthXYNormalised(), ptCandBplus); + registry.fill(HIST("hd0Prong0RecSig"), candidate.impactParameter0(), ptCandBplus); + registry.fill(HIST("hd0Prong1RecSig"), candidate.impactParameter1(), ptCandBplus); + registry.fill(HIST("hd0d0RecSig"), candidate.impactParameterProduct(), ptCandBplus); + registry.fill(HIST("hPtProng0RecSig"), candidate.ptProng0(), ptCandBplus); + registry.fill(HIST("hPtProng1RecSig"), candidate.ptProng1(), ptCandBplus); + registry.fill(HIST("hDecLengthD0RecSig"), decLenD0, candidate.ptProng0()); + registry.fill(HIST("hDecLengthXyD0RecSig"), decLenXyD0, ptD0); + registry.fill(HIST("hCpaD0RecSig"), cpaD0, ptD0); + registry.fill(HIST("hCpaXyD0RecSig"), cpaXyD0, ptD0); + if constexpr (withDecayTypeCheck) { + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_bplus::DecayTypeMc::BplusToD0PiToKPiPi, invMassBplus, ptCandBplus); + } + if constexpr (withDmesMl) { + registry.fill(HIST("hMlScoreBkgDRecSig"), ptD0, candidate.prong0MlScoreBkg()); + registry.fill(HIST("hMlScorePromptDRecSig"), ptD0, candidate.prong0MlScorePrompt()); + registry.fill(HIST("hMlScoreNonPromptDRecSig"), ptD0, candidate.prong0MlScoreNonprompt()); + } + if constexpr (withBplusMl) { + registry.fill(HIST("hMlScoreSigBplusRecSig"), ptCandBplus, candidate.mlProbBplusToD0Pi()); + } + } else if (fillBackground) { + registry.fill(HIST("hMassRecBg"), invMassBplus, ptCandBplus); + registry.fill(HIST("hPtRecBg"), ptCandBplus); + registry.fill(HIST("hPtProng0RecBg"), candidate.ptProng0(), ptCandBplus); + registry.fill(HIST("hPtProng1RecBg"), candidate.ptProng1(), ptCandBplus); + registry.fill(HIST("hCpaRecBg"), candidate.cpa(), ptCandBplus); + registry.fill(HIST("hCpaXyRecBg"), candidate.cpaXY(), ptCandBplus); + registry.fill(HIST("hEtaRecBg"), candidate.eta(), ptCandBplus); + registry.fill(HIST("hRapidityRecBg"), hfHelper.yBplus(candidate), ptCandBplus); + registry.fill(HIST("hDecLengthRecBg"), candidate.decayLength(), ptCandBplus); + registry.fill(HIST("hDecLengthXyRecBg"), candidate.decayLengthXY(), ptCandBplus); + registry.fill(HIST("hNormDecLengthXyRecBg"), candidate.decayLengthXYNormalised(), ptCandBplus); + registry.fill(HIST("hd0Prong0RecBg"), candidate.impactParameter0(), ptCandBplus); + registry.fill(HIST("hd0Prong1RecBg"), candidate.impactParameter1(), ptCandBplus); + registry.fill(HIST("hd0d0RecBg"), candidate.impactParameterProduct(), ptCandBplus); + registry.fill(HIST("hDecLengthD0RecBg"), decLenD0, candidate.ptProng0()); + registry.fill(HIST("hInvMassDRecBg"), invMassD0, ptD0); + registry.fill(HIST("hDecLengthDRecBg"), decLenD0, ptD0); + registry.fill(HIST("hDecLengthXyDRecBg"), decLenXyD0, ptD0); + registry.fill(HIST("hCpaDRecBg"), cpaD0, ptD0); + registry.fill(HIST("hCpaXyDRecBg"), cpaXyD0, ptD0); + if constexpr (withDmesMl) { + registry.fill(HIST("hMlScoreBkgDRecBg"), ptD0, candidate.prong0MlScoreBkg()); + registry.fill(HIST("hMlScorePromptDRecBg"), ptD0, candidate.prong0MlScorePrompt()); + registry.fill(HIST("hMlScoreNonPromptDRecBg"), ptD0, candidate.prong0MlScoreNonprompt()); + } + if constexpr (withBplusMl) { + registry.fill(HIST("hMlScoreSigBplusRecBg"), ptCandBplus, candidate.mlProbBplusToD0Pi()); + } + } else if constexpr (withDecayTypeCheck) { + if (TESTBIT(flagMcMatchRec, hf_cand_bplus::DecayTypeMc::PartlyRecoDecay)) { // Partly reconstructed decay channel + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_bplus::DecayTypeMc::PartlyRecoDecay, invMassBplus, ptCandBplus); + } else { + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_bplus::DecayTypeMc::OtherDecay, invMassBplus, ptCandBplus); + } + } + } else { + registry.fill(HIST("hMass"), invMassBplus, ptCandBplus); + registry.fill(HIST("hPtCand"), ptCandBplus); + registry.fill(HIST("hPtProng0"), ptD0, ptCandBplus); + registry.fill(HIST("hPtProng1"), candidate.ptProng1(), ptCandBplus); + registry.fill(HIST("hd0d0"), candidate.impactParameterProduct(), ptCandBplus); + registry.fill(HIST("hDecLength"), candidate.decayLength(), ptCandBplus); + registry.fill(HIST("hDecLengthXy"), candidate.decayLengthXY(), ptCandBplus); + registry.fill(HIST("hNormDecLengthXy"), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), ptCandBplus); + registry.fill(HIST("hd0Prong0"), candidate.impactParameter0(), ptCandBplus); + registry.fill(HIST("hd0Prong1"), candidate.impactParameter1(), ptCandBplus); + registry.fill(HIST("hCpa"), candidate.cpa(), ptCandBplus); + registry.fill(HIST("hCpaXy"), candidate.cpaXY(), ptCandBplus); + registry.fill(HIST("hEta"), candidate.eta(), ptCandBplus); + registry.fill(HIST("hRapidity"), hfHelper.yBplus(candidate), ptCandBplus); + registry.fill(HIST("hInvMassD0"), invMassD0, ptCandBplus); + registry.fill(HIST("hDecLengthD0"), decLenD0, ptD0); + registry.fill(HIST("hDecLengthXyD0"), decLenXyD0, ptD0); + registry.fill(HIST("hCpaD0"), cpaD0, ptD0); + registry.fill(HIST("hCpaXyD0"), cpaXyD0, ptD0); + if constexpr (withDmesMl) { + registry.fill(HIST("hMlScoreBkgD"), ptD0, candidate.prong0MlScoreBkg()); + registry.fill(HIST("hMlScorePromptD"), ptD0, candidate.prong0MlScorePrompt()); + registry.fill(HIST("hMlScoreNonPromptD"), ptD0, candidate.prong0MlScoreNonprompt()); + } + if constexpr (withBplusMl) { + registry.fill(HIST("hMlScoreSigBplus"), ptCandBplus, candidate.mlProbBplusToD0Pi()); + } + } + } + if (fillSparses) { + if constexpr (doMc) { + if (isSignal) { + if constexpr (withDmesMl) { + registry.fill(HIST("hMassPtCutVarsRecSig"), invMassBplus, ptCandBplus, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassD0, ptD0, candidate.prong0MlScoreBkg(), candidate.prong0MlScoreNonprompt()); + } else { + registry.fill(HIST("hMassPtCutVarsRecSig"), invMassBplus, ptCandBplus, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassD0, ptD0, decLenD0, cpaD0); + } + } else if (fillBackground) { + if constexpr (withDmesMl) { + registry.fill(HIST("hMassPtCutVarsRecBg"), invMassBplus, ptCandBplus, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassD0, ptD0, candidate.prong0MlScoreBkg(), candidate.prong0MlScoreNonprompt()); + } else { + registry.fill(HIST("hMassPtCutVarsRecBg"), invMassBplus, ptCandBplus, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassD0, ptD0, decLenD0, cpaD0); + } + } + } else { + if constexpr (withDmesMl) { + registry.fill(HIST("hMassPtCutVars"), invMassBplus, ptCandBplus, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassD0, ptD0, candidate.prong0MlScoreBkg(), candidate.prong0MlScoreNonprompt()); + } else { + registry.fill(HIST("hMassPtCutVars"), invMassBplus, ptCandBplus, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassD0, ptD0, decLenD0, cpaD0); + } + } + } + if (fillTree) { + float pseudoRndm = ptD0 * 1000. - static_cast(ptD0 * 1000); + if (ptCandBplus >= ptMaxForDownSample || pseudoRndm < downSampleBkgFactor) { + float prong0MlScoreBkg = -1.; + float prong0MlScorePrompt = -1.; + float prong0MlScoreNonprompt = -1.; + float candidateMlScoreSig = -1; + if constexpr (withDmesMl) { + prong0MlScoreBkg = candidate.prong0MlScoreBkg(); + prong0MlScorePrompt = candidate.prong0MlScorePrompt(); + prong0MlScoreNonprompt = candidate.prong0MlScoreNonprompt(); + } + if constexpr (withBplusMl) { + candidateMlScoreSig = candidate.mlProbBplusToD0Pi(); + } + auto prong1 = candidate.template prong1_as(); + float tpcNSigmaPi, tofNSigmaPi, tpcTofNSigmaPi, tpcNSigmaKa, tofNSigmaKa, tpcTofNSigmaKa; + if (prong1.signed1Pt() < 0) { + tpcNSigmaPi = candD0.tpcNSigmaPiProng1(); + tofNSigmaPi = candD0.tofNSigmaPiProng1(); + tpcTofNSigmaPi = candD0.tpcTofNSigmaPiProng1(); + tpcNSigmaKa = candD0.tpcNSigmaKaProng0(); + tofNSigmaKa = candD0.tofNSigmaKaProng0(); + tpcTofNSigmaKa = candD0.tpcTofNSigmaKaProng0(); + } else { + tpcNSigmaPi = candD0.tpcNSigmaPiProng0(); + tofNSigmaPi = candD0.tofNSigmaPiProng0(); + tpcTofNSigmaPi = candD0.tpcTofNSigmaPiProng0(); + tpcNSigmaKa = candD0.tpcNSigmaKaProng1(); + tofNSigmaKa = candD0.tofNSigmaKaProng1(); + tpcTofNSigmaKa = candD0.tpcTofNSigmaKaProng1(); + } + + float ptMother = -1.; + if constexpr (doMc) { + ptMother = candidate.ptMother(); + } + + hfRedCandBpLite( + // B+ - meson features + invMassBplus, + ptCandBplus, + candidate.eta(), + candidate.phi(), + hfHelper.yBplus(candidate), + candidate.cpa(), + candidate.cpaXY(), + candidate.chi2PCA(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.decayLengthNormalised(), + candidate.decayLengthXYNormalised(), + candidate.impactParameterProduct(), + candidate.maxNormalisedDeltaIP(), + candidateMlScoreSig, + candidate.isSelBplusToD0Pi(), + // D-meson features + invMassD0, + ptD0, + decLenD0, + decLenXyD0, + candidate.impactParameter0(), + cpaD0, + cpaXyD0, + candD0.ptProngMin(), + candD0.absEtaProngMin(), + candD0.itsNClsProngMin(), + candD0.tpcNClsCrossedRowsProngMin(), + candD0.tpcChi2NClProngMax(), + tpcNSigmaPi, + tofNSigmaPi, + tpcTofNSigmaPi, + tpcNSigmaKa, + tofNSigmaKa, + tpcTofNSigmaKa, + prong0MlScoreBkg, + prong0MlScorePrompt, + prong0MlScoreNonprompt, + // pion features + candidate.ptProng1(), + std::abs(RecoDecay::eta(prong1.pVector())), + prong1.itsNCls(), + prong1.tpcNClsCrossedRows(), + prong1.tpcChi2NCl(), + candidate.impactParameter1(), + prong1.tpcNSigmaPi(), + prong1.tofNSigmaPi(), + prong1.tpcTofNSigmaPi(), + // MC truth + flagMcMatchRec, + isSignal, + flagWrongCollision, + ptMother); + + if constexpr (withDecayTypeCheck) { + hfRedBpMcCheck( + flagMcMatchRec, + flagWrongCollision, + invMassD0, + ptD0, + invMassBplus, + ptCandBplus, + candidateMlScoreSig, + candidate.pdgCodeBeautyMother(), + candidate.pdgCodeCharmMother(), + candidate.pdgCodeProng0(), + candidate.pdgCodeProng1(), + candidate.pdgCodeProng2()); + } + } + } + } + + /// Fill particle histograms (gen MC truth) + void fillCandMcGen(aod::HfMcGenRedBps::iterator const& particle) + { + auto ptParticle = particle.ptTrack(); + auto yParticle = particle.yTrack(); + auto etaParticle = particle.etaTrack(); + if (yCandGenMax >= 0. && std::abs(yParticle) > yCandGenMax) { + return; + } + std::array ptProngs = {particle.ptProng0(), particle.ptProng1()}; + std::array yProngs = {particle.yProng0(), particle.yProng1()}; + std::array etaProngs = {particle.etaProng0(), particle.etaProng1()}; + bool prongsInAcc = isProngInAcceptance(etaProngs[0], ptProngs[0]) && isProngInAcceptance(etaProngs[1], ptProngs[1]); + + if (fillHistograms) { + registry.fill(HIST("hPtProng0Gen"), ptParticle, ptProngs[0]); + registry.fill(HIST("hPtProng1Gen"), ptParticle, ptProngs[1]); + registry.fill(HIST("hYProng0Gen"), ptParticle, yProngs[0]); + registry.fill(HIST("hYProng1Gen"), ptParticle, yProngs[1]); + registry.fill(HIST("hEtaProng0Gen"), ptParticle, etaProngs[0]); + registry.fill(HIST("hEtaProng1Gen"), ptParticle, etaProngs[1]); + + registry.fill(HIST("hYGen"), ptParticle, yParticle); + registry.fill(HIST("hEtaGen"), ptParticle, etaParticle); + + // generated B+ with daughters in geometrical acceptance + if (prongsInAcc) { + registry.fill(HIST("hYGenWithProngsInAcceptance"), ptParticle, yParticle); + } + } + if (fillSparses) { + registry.fill(HIST("hPtYGenSig"), ptParticle, yParticle); + if (prongsInAcc) { + registry.fill(HIST("hPtYWithProngsInAccepanceGenSig"), ptParticle, yParticle); + } + } + } + + // Process functions + void processData(soa::Filtered> const& candidates, + CandsD0 const& candidatesD, + TracksPion const& pionTracks) { for (const auto& candidate : candidates) { - if (!TESTBIT(candidate.hfflag(), hf_cand_bplus::DecayType::BplusToD0Pi)) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { continue; } + fillCand(candidate, candidatesD, pionTracks); + } // candidate loop + } // processData + PROCESS_SWITCH(HfTaskBplusReduced, processData, "Process data without ML scores for D0 daughter", true); + + void processDataWithDmesMl(soa::Filtered> const& candidates, + CandsD0 const& candidatesD, + TracksPion const& pionTracks) + { + for (const auto& candidate : candidates) { if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { continue; } + fillCand(candidate, candidatesD, pionTracks); + } // candidate loop + } // processDataWithDmesMl + PROCESS_SWITCH(HfTaskBplusReduced, processDataWithDmesMl, "Process data with ML scores for D0 daughter", false); - auto candD0 = candidate.prong0_as(); - auto candPi = candidate.prong1_as(); - auto ptCandBplus = candidate.pt(); - auto invMassD0 = (candPi.signed1Pt() < 0) ? candD0.invMassD0() : candD0.invMassD0Bar(); - - registry.fill(HIST("hMass"), hfHelper.invMassBplusToD0Pi(candidate), ptCandBplus); - registry.fill(HIST("hPtCand"), ptCandBplus); - registry.fill(HIST("hPtProng0"), candidate.ptProng0()); - registry.fill(HIST("hPtProng1"), candidate.ptProng1()); - registry.fill(HIST("hd0d0"), candidate.impactParameterProduct(), ptCandBplus); - registry.fill(HIST("hDecLength"), candidate.decayLength(), ptCandBplus); - registry.fill(HIST("hDecLengthXY"), candidate.decayLengthXY(), ptCandBplus); - registry.fill(HIST("hd0Prong0"), candidate.impactParameter0(), ptCandBplus); - registry.fill(HIST("hd0Prong1"), candidate.impactParameter1(), ptCandBplus); - registry.fill(HIST("hCPA"), candidate.cpa(), ptCandBplus); - registry.fill(HIST("hCPAxy"), candidate.cpaXY(), ptCandBplus); - registry.fill(HIST("hEta"), candidate.eta(), ptCandBplus); - registry.fill(HIST("hRapidity"), hfHelper.yBplus(candidate), ptCandBplus); - registry.fill(HIST("hImpParErr"), candidate.errorImpactParameter0(), ptCandBplus); - registry.fill(HIST("hImpParErr"), candidate.errorImpactParameter1(), ptCandBplus); - registry.fill(HIST("hDecLenErr"), candidate.errorDecayLength(), ptCandBplus); - registry.fill(HIST("hDecLenXYErr"), candidate.errorDecayLengthXY(), ptCandBplus); - registry.fill(HIST("hInvMassD0"), invMassD0, ptCandBplus); - registry.fill(HIST("hCPAFinerBinning"), candidate.cpa(), ptCandBplus); - registry.fill(HIST("hCPAxyFinerBinning"), candidate.cpaXY(), ptCandBplus); + void processDataWithBplusMl(soa::Filtered> const& candidates, + CandsD0 const& candidatesD, + TracksPion const& pionTracks) + { + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesD, pionTracks); } // candidate loop - } // process + } // processDataWithBplusMl + PROCESS_SWITCH(HfTaskBplusReduced, processDataWithBplusMl, "Process data with(out) ML scores for B+ (D0 daughter)", false); - /// B+ MC analysis and fill histograms - void processMc(soa::Join const& candidates, + void processMc(soa::Filtered> const& candidates, aod::HfMcGenRedBps const& mcParticles, - aod::HfRed2Prongs const&) + CandsD0 const& candidatesD, + TracksPion const& pionTracks) { // MC rec for (const auto& candidate : candidates) { - if (!TESTBIT(candidate.hfflag(), hf_cand_bplus::DecayType::BplusToD0Pi)) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { continue; } + fillCand(candidate, candidatesD, pionTracks); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMc + PROCESS_SWITCH(HfTaskBplusReduced, processMc, "Process MC without ML scores for B+ and D0 daughter", false); + + void processMcWithDecayTypeCheck(soa::Filtered> const& candidates, + aod::HfMcGenRedBps const& mcParticles, + CandsD0 const& candidatesD, + TracksPion const& pionTracks) + { + // MC rec + for (const auto& candidate : candidates) { if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { continue; } + fillCand(candidate, candidatesD, pionTracks); + } // rec - auto ptCandBplus = candidate.pt(); - auto candD0 = candidate.prong0_as(); - std::array posPv{candidate.posX(), candidate.posY(), candidate.posZ()}; - std::array posSvD{candD0.xSecondaryVertex(), candD0.ySecondaryVertex(), candD0.zSecondaryVertex()}; - std::array momD{candD0.pVector()}; - auto cospD0 = RecoDecay::cpa(posPv, posSvD, momD); - auto decLenD0 = RecoDecay::distance(posPv, posSvD); - - if (TESTBIT(std::abs(candidate.flagMcMatchRec()), hf_cand_bplus::DecayType::BplusToD0Pi)) { - - registry.fill(HIST("hPtGenSig"), candidate.ptMother()); - registry.fill(HIST("hPtRecSig"), ptCandBplus); - registry.fill(HIST("hCPARecSig"), candidate.cpa(), ptCandBplus); - registry.fill(HIST("hCPAxyRecSig"), candidate.cpaXY(), ptCandBplus); - registry.fill(HIST("hCPAFinerBinningRecSig"), candidate.cpa(), ptCandBplus); - registry.fill(HIST("hCPAxyFinerBinningRecSig"), candidate.cpaXY(), ptCandBplus); - registry.fill(HIST("hEtaRecSig"), candidate.eta(), ptCandBplus); - registry.fill(HIST("hRapidityRecSig"), hfHelper.yBplus(candidate), ptCandBplus); - registry.fill(HIST("hDecLengthRecSig"), candidate.decayLength(), ptCandBplus); - registry.fill(HIST("hDecLengthXYRecSig"), candidate.decayLengthXY(), ptCandBplus); - registry.fill(HIST("hMassRecSig"), hfHelper.invMassBplusToD0Pi(candidate), ptCandBplus); - registry.fill(HIST("hd0Prong0RecSig"), candidate.impactParameter0(), ptCandBplus); - registry.fill(HIST("hd0Prong1RecSig"), candidate.impactParameter1(), ptCandBplus); - registry.fill(HIST("hPtProng0RecSig"), candidate.ptProng0(), ptCandBplus); - registry.fill(HIST("hPtProng1RecSig"), candidate.ptProng1(), ptCandBplus); - registry.fill(HIST("hd0d0RecSig"), candidate.impactParameterProduct(), ptCandBplus); - registry.fill(HIST("hDecLengthNormRecSig"), candidate.decayLengthXYNormalised(), ptCandBplus); - registry.fill(HIST("hCPAD0RecSig"), cospD0, candidate.ptProng0()); - registry.fill(HIST("hDecLengthD0RecSig"), decLenD0, candidate.ptProng0()); - } else { - registry.fill(HIST("hPtRecBg"), ptCandBplus); - registry.fill(HIST("hCPARecBg"), candidate.cpa(), ptCandBplus); - registry.fill(HIST("hCPAxyRecBg"), candidate.cpaXY(), ptCandBplus); - registry.fill(HIST("hCPAFinerBinningRecBg"), candidate.cpa(), ptCandBplus); - registry.fill(HIST("hCPAxyFinerBinningRecBg"), candidate.cpaXY(), ptCandBplus); - registry.fill(HIST("hEtaRecBg"), candidate.eta(), ptCandBplus); - registry.fill(HIST("hRapidityRecBg"), hfHelper.yBplus(candidate), ptCandBplus); - registry.fill(HIST("hDecLengthRecBg"), candidate.decayLength(), ptCandBplus); - registry.fill(HIST("hDecLengthXYRecBg"), candidate.decayLengthXY(), ptCandBplus); - registry.fill(HIST("hMassRecBg"), hfHelper.invMassBplusToD0Pi(candidate), ptCandBplus); - registry.fill(HIST("hd0Prong0RecBg"), candidate.impactParameter0(), ptCandBplus); - registry.fill(HIST("hd0Prong1RecBg"), candidate.impactParameter1(), ptCandBplus); - registry.fill(HIST("hPtProng0RecBg"), candidate.ptProng0(), ptCandBplus); - registry.fill(HIST("hPtProng1RecBg"), candidate.ptProng1(), ptCandBplus); - registry.fill(HIST("hd0d0RecBg"), candidate.impactParameterProduct(), ptCandBplus); - registry.fill(HIST("hDecLengthNormRecBg"), candidate.decayLengthXYNormalised(), ptCandBplus); - registry.fill(HIST("hCPAD0RecBg"), cospD0, candidate.ptProng0()); - registry.fill(HIST("hDecLengthD0RecBg"), decLenD0, candidate.ptProng0()); + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMc + PROCESS_SWITCH(HfTaskBplusReduced, processMcWithDecayTypeCheck, "Process MC with decay type check and without ML scores for B+ and D daughter", false); + + void processMcWithDmesMl(soa::Filtered> const& candidates, + aod::HfMcGenRedBps const& mcParticles, + CandsD0 const& candidatesD, + TracksPion const& pionTracks) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { + continue; } + fillCand(candidate, candidatesD, pionTracks); } // rec // MC gen. level for (const auto& particle : mcParticles) { - auto ptParticle = particle.ptTrack(); - auto yParticle = particle.yTrack(); - auto etaParticle = particle.etaTrack(); - if (yCandGenMax >= 0. && std::abs(yParticle) > yCandGenMax) { + fillCandMcGen(particle); + } // gen + } // processMcWithDmesMl + PROCESS_SWITCH(HfTaskBplusReduced, processMcWithDmesMl, "Process MC with(out) ML scores for D0 daughter (B+)", false); + + void processMcWithDmesMlAndDecayTypeCheck(soa::Filtered> const& candidates, + aod::HfMcGenRedBps const& mcParticles, + CandsD0 const& candidatesD, + TracksPion const& pionTracks) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { continue; } + fillCand(candidate, candidatesD, pionTracks); + } // rec - std::array ptProngs = {particle.ptProng0(), particle.ptProng1()}; - std::array yProngs = {particle.yProng0(), particle.yProng1()}; - std::array etaProngs = {particle.etaProng0(), particle.etaProng1()}; - - registry.fill(HIST("hPtProng0Gen"), ptProngs[0], ptParticle); - registry.fill(HIST("hPtProng1Gen"), ptProngs[1], ptParticle); - registry.fill(HIST("hPtProngsVsPtBGen"), ptProngs[0], ptProngs[1], ptParticle); - registry.fill(HIST("hYProng0Gen"), yProngs[0], ptParticle); - registry.fill(HIST("hYProng1Gen"), yProngs[1], ptParticle); - registry.fill(HIST("hYProngsVsBplusGen"), yProngs[0], yProngs[1], ptParticle); - registry.fill(HIST("hEtaProng0Gen"), etaProngs[0], ptParticle); - registry.fill(HIST("hEtaProng1Gen"), etaProngs[1], ptParticle); - registry.fill(HIST("hEtaProngsVsBplusGen"), etaProngs[0], etaProngs[1], ptParticle); - - registry.fill(HIST("hPtGen"), ptParticle); - registry.fill(HIST("hYGen"), yParticle, ptParticle); - registry.fill(HIST("hEtaGen"), etaParticle, ptParticle); - - // generated B+ with |y|<0.5 - if (std::abs(yParticle) < 0.5) { - registry.fill(HIST("hPtGenWithRapidityBelowHalf"), ptParticle); + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMc + PROCESS_SWITCH(HfTaskBplusReduced, processMcWithDmesMlAndDecayTypeCheck, "Process MC with decay type check and with(out) ML scores for B+ (D0 daughter)", false); + + void processMcWithBplusMl(soa::Filtered> const& candidates, + aod::HfMcGenRedBps const& mcParticles, + CandsD0 const& candidatesD, + TracksPion const& pionTracks) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { + continue; } + fillCand(candidate, candidatesD, pionTracks); + } // rec - // generated B+ with daughters in geometrical acceptance - if (isProngInAcceptance(etaProngs[0], ptProngs[0]) && isProngInAcceptance(etaProngs[1], ptProngs[1])) { - registry.fill(HIST("hPtGenWithProngsInAcceptance"), ptParticle); - registry.fill(HIST("hYGenWithProngsInAcceptance"), yParticle, ptParticle); - registry.fill(HIST("hEtaGenWithProngsInAcceptance"), etaParticle, ptParticle); + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMcWithBplusMl + PROCESS_SWITCH(HfTaskBplusReduced, processMcWithBplusMl, "Process MC with(out) ML scores for B+ (D0 daughter)", false); + + void processMcWithBplusMlAndDecayTypeCheck(soa::Filtered> const& candidates, + aod::HfMcGenRedBps const& mcParticles, + CandsD0 const& candidatesD, + TracksPion const& pionTracks) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { + continue; } + fillCand(candidate, candidatesD, pionTracks); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); } // gen - } // process - PROCESS_SWITCH(HfTaskBplusReduced, processMc, "Process MC", false); + } // processMc + PROCESS_SWITCH(HfTaskBplusReduced, processMcWithBplusMlAndDecayTypeCheck, "Process MC with decay type check and with(out) ML scores for B+ (D0 daughter)", false); }; // struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/D2H/Tasks/taskBs.cxx b/PWGHF/D2H/Tasks/taskBs.cxx index 29c424f869b..c394db35d1d 100644 --- a/PWGHF/D2H/Tasks/taskBs.cxx +++ b/PWGHF/D2H/Tasks/taskBs.cxx @@ -15,6 +15,8 @@ /// /// \author Phil Stahlhut +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" @@ -128,8 +130,8 @@ struct HfTaskBs { if (checkDecayTypeMc) { constexpr uint8_t kNBinsDecayTypeMc = hf_cand_bs::DecayTypeMc::NDecayTypeMc + 1; TString labels[kNBinsDecayTypeMc]; - labels[hf_cand_bs::DecayTypeMc::BsToDsPiToKKPiPi] = "B^{0}_{s} #rightarrow (D^{#mp}_{s} #rightarrow K^{#minus} K^{#plus} #pi^{#mp}) #pi^{#pm}"; - labels[hf_cand_bs::DecayTypeMc::B0ToDsPiToKKPiPi] = "B^{0} #rightarrow (D^{#pm}_{s} #rightarrow K^{#minus} K^{#plus} #pi^{#pm}) #pi^{#mp}"; + labels[hf_cand_bs::DecayTypeMc::BsToDsPiToPhiPiPiToKKPiPi] = "B^{0}_{s} #rightarrow (D^{#mp}_{s} #rightarrow K^{#minus} K^{#plus} #pi^{#mp}) #pi^{#pm}"; + labels[hf_cand_bs::DecayTypeMc::B0ToDsPiToPhiPiPiToKKPiPi] = "B^{0} #rightarrow (D^{#pm}_{s} #rightarrow K^{#minus} K^{#plus} #pi^{#pm}) #pi^{#mp}"; labels[hf_cand_bs::DecayTypeMc::PartlyRecoDecay] = "Partly reconstructed decay channel"; labels[hf_cand_bs::DecayTypeMc::NDecayTypeMc] = "Other decays"; static const AxisSpec axisDecayType = {kNBinsDecayTypeMc, 0.5, kNBinsDecayTypeMc + 0.5, ""}; @@ -155,9 +157,6 @@ struct HfTaskBs { TracksWithSel const&) { for (const auto& candidate : candidates) { - if (!TESTBIT(candidate.hfflag(), hf_cand_bs::DecayType::BsToDsPi)) { - continue; - } if (yCandRecoMax >= 0. && std::abs(hfHelper.yBs(candidate)) > yCandRecoMax) { continue; } @@ -194,9 +193,6 @@ struct HfTaskBs { { // MC rec for (const auto& candidate : candidates) { - if (!TESTBIT(candidate.hfflag(), hf_cand_bs::DecayType::BsToDsPi)) { - continue; - } if (yCandRecoMax >= 0. && std::abs(hfHelper.yBs(candidate)) > yCandRecoMax) { continue; } @@ -206,7 +202,7 @@ struct HfTaskBs { auto invMassCandBs = hfHelper.invMassBsToDsPi(candidate); int flagMcMatchRecBs = std::abs(candidate.flagMcMatchRec()); - if (TESTBIT(flagMcMatchRecBs, hf_cand_bs::DecayTypeMc::BsToDsPiToKKPiPi)) { + if (TESTBIT(flagMcMatchRecBs, hf_cand_bs::DecayTypeMc::BsToDsPiToPhiPiPiToKKPiPi)) { auto indexMother = RecoDecay::getMother(mcParticles, candidate.prong1_as().mcParticle_as>(), o2::constants::physics::Pdg::kBS, true); auto particleMother = mcParticles.rawIteratorAt(indexMother); @@ -230,7 +226,7 @@ struct HfTaskBs { registry.fill(HIST("hChi2PCARecSig"), candidate.chi2PCA(), ptCandBs); if (checkDecayTypeMc) { - registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_bs::DecayTypeMc::BsToDsPiToKKPiPi, invMassCandBs, ptCandBs); + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_bs::DecayTypeMc::BsToDsPiToPhiPiPiToKKPiPi, invMassCandBs, ptCandBs); } } else { registry.fill(HIST("hPtRecBg"), ptCandBs); @@ -252,8 +248,8 @@ struct HfTaskBs { registry.fill(HIST("hChi2PCARecBg"), candidate.chi2PCA(), ptCandBs); if (checkDecayTypeMc) { - if (TESTBIT(flagMcMatchRecBs, hf_cand_bs::DecayTypeMc::B0ToDsPiToKKPiPi)) { // B0(bar) → Ds± π∓ → (K- K+ π±) π∓ - registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_bs::DecayTypeMc::B0ToDsPiToKKPiPi, invMassCandBs, ptCandBs); + if (TESTBIT(flagMcMatchRecBs, hf_cand_bs::DecayTypeMc::B0ToDsPiToPhiPiPiToKKPiPi)) { // B0(bar) → Ds± π∓ → (K- K+ π±) π∓ + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_bs::DecayTypeMc::B0ToDsPiToPhiPiPiToKKPiPi, invMassCandBs, ptCandBs); } else if (TESTBIT(flagMcMatchRecBs, hf_cand_bs::DecayTypeMc::PartlyRecoDecay)) { // Partly reconstructed decay channel registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_bs::DecayTypeMc::PartlyRecoDecay, invMassCandBs, ptCandBs); } else { @@ -265,7 +261,7 @@ struct HfTaskBs { // MC gen. level for (const auto& particle : mcParticles) { - if (TESTBIT(std::abs(particle.flagMcMatchGen()), hf_cand_bs::DecayTypeMc::BsToDsPiToKKPiPi)) { + if (TESTBIT(std::abs(particle.flagMcMatchGen()), hf_cand_bs::DecayTypeMc::BsToDsPiToPhiPiPiToKKPiPi)) { auto ptParticle = particle.pt(); auto yParticle = RecoDecay::y(particle.pVector(), o2::constants::physics::MassBS); diff --git a/PWGHF/D2H/Tasks/taskBsReduced.cxx b/PWGHF/D2H/Tasks/taskBsReduced.cxx new file mode 100644 index 00000000000..51dadbf05b5 --- /dev/null +++ b/PWGHF/D2H/Tasks/taskBsReduced.cxx @@ -0,0 +1,760 @@ +// 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 taskBsReduced.cxx +/// \brief Bs → Ds- π+ → (K- K+ π-) π+ analysis task +/// +/// \author Fabio Catalano , CERN + +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "Common/Core/RecoDecay.h" + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace o2::aod +{ +namespace hf_cand_bs_lite +{ +DECLARE_SOA_COLUMN(PtProng0, ptProng0, float); //! Transverse momentum of prong0 (GeV/c) +DECLARE_SOA_COLUMN(PtProng1, ptProng1, float); //! Transverse momentum of prong1 (GeV/c) +DECLARE_SOA_COLUMN(MProng0, mProng0, float); //! Invariant mass of prong0 (GeV/c) +DECLARE_SOA_COLUMN(M, m, float); //! Invariant mass of candidate (GeV/c2) +DECLARE_SOA_COLUMN(Pt, pt, float); //! Transverse momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(PtGen, ptGen, float); //! Transverse momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(P, p, float); //! Momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(Y, y, float); //! Rapidity of candidate +DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity of candidate +DECLARE_SOA_COLUMN(Phi, phi, float); //! Azimuth angle of candidate +DECLARE_SOA_COLUMN(E, e, float); //! Energy of candidate (GeV) +DECLARE_SOA_COLUMN(NSigTpcPi1, nSigTpcPi1, float); //! TPC Nsigma separation for prong1 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTofPi1, nSigTofPi1, float); //! TOF Nsigma separation for prong1 with pion mass hypothesis +DECLARE_SOA_COLUMN(DecayLength, decayLength, float); //! Decay length of candidate (cm) +DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); //! Transverse decay length of candidate (cm) +DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); //! Normalised decay length of candidate +DECLARE_SOA_COLUMN(DecayLengthXYNormalised, decayLengthXYNormalised, float); //! Normalised transverse decay length of candidate +DECLARE_SOA_COLUMN(ImpactParameterProduct, impactParameterProduct, float); //! Impact parameter product of candidate +DECLARE_SOA_COLUMN(Cpa, cpa, float); //! Cosine pointing angle of candidate +DECLARE_SOA_COLUMN(CpaXY, cpaXY, float); //! Cosine pointing angle of candidate in transverse plane +DECLARE_SOA_COLUMN(MaxNormalisedDeltaIP, maxNormalisedDeltaIP, float); //! Maximum normalized difference between measured and expected impact parameter of candidate prongs +DECLARE_SOA_COLUMN(MlScoreSig, mlScoreSig, float); //! ML score for signal class +DECLARE_SOA_COLUMN(FlagWrongCollision, flagWrongCollision, int8_t); //! Flag for association with wrong collision +} // namespace hf_cand_bs_lite + +DECLARE_SOA_TABLE(HfRedCandBsLites, "AOD", "HFREDCANDBSLITE", //! Table with some Bs properties + hf_cand::Chi2PCA, + hf_cand_bs_lite::DecayLength, + hf_cand_bs_lite::DecayLengthXY, + hf_cand_bs_lite::DecayLengthNormalised, + hf_cand_bs_lite::DecayLengthXYNormalised, + hf_cand_bs_lite::MProng0, + hf_cand_bs_lite::PtProng0, + hf_cand_bs_lite::PtProng1, + hf_cand::ImpactParameter0, + hf_cand::ImpactParameter1, + hf_cand_bs_lite::ImpactParameterProduct, + hf_cand_bs_lite::NSigTpcPi1, + hf_cand_bs_lite::NSigTofPi1, + hf_cand_bs_reduced::Prong0MlScoreBkg, + hf_cand_bs_reduced::Prong0MlScorePrompt, + hf_cand_bs_reduced::Prong0MlScoreNonprompt, + hf_cand_bs_lite::MlScoreSig, + hf_sel_candidate_bs::IsSelBsToDsPi, + hf_cand_bs_lite::M, + hf_cand_bs_lite::Pt, + hf_cand_bs_lite::Cpa, + hf_cand_bs_lite::CpaXY, + hf_cand_bs_lite::MaxNormalisedDeltaIP, + hf_cand_bs_lite::Eta, + hf_cand_bs_lite::Phi, + hf_cand_bs_lite::Y, + hf_cand_3prong::FlagMcMatchRec, + hf_cand_3prong::OriginMcRec, + hf_cand_bs_lite::FlagWrongCollision, + hf_cand_bs_lite::PtGen); + +DECLARE_SOA_TABLE(HfRedBsMcCheck, "AOD", "HFREDBSMCCHECK", //! Table with MC decay type check + hf_cand_3prong::FlagMcMatchRec, + hf_cand_bs_lite::FlagWrongCollision, + hf_cand_bs_lite::MProng0, + hf_cand_bs_lite::PtProng0, + hf_cand_bs_lite::M, + hf_cand_bs_lite::Pt, + hf_cand_bs_lite::MlScoreSig, + hf_bs_mc::PdgCodeBeautyMother, + hf_bs_mc::PdgCodeCharmMother, + hf_bs_mc::PdgCodeProng0, + hf_bs_mc::PdgCodeProng1, + hf_bs_mc::PdgCodeProng2, + hf_bs_mc::PdgCodeProng3); +} // namespace o2::aod + +/// Bs analysis task +struct HfTaskBsReduced { + Produces hfRedCandBsLite; + Produces hfRedBsMcCheck; + + Configurable selectionFlagBs{"selectionFlagBs", 1, "Selection Flag for Bs"}; + Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen particle rapidity"}; + Configurable yCandRecoMax{"yCandRecoMax", 0.8, "max. cand. rapidity"}; + Configurable etaTrackMax{"etaTrackMax", 0.8, "max. track pseudo-rapidity for acceptance calculation"}; + Configurable ptTrackMin{"ptTrackMin", 0.1, "min. track transverse momentum for acceptance calculation"}; + Configurable fillHistograms{"fillHistograms", true, "Flag to enable histogram filling"}; + Configurable fillSparses{"fillSparses", false, "Flag to enable sparse filling"}; + Configurable fillTree{"fillTree", false, "Flag to enable tree filling"}; + Configurable fillBackground{"fillBackground", false, "Flag to enable filling of background histograms/sparses/tree (only MC)"}; + Configurable downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of background_{s} candidates to keep for ML trainings"}; + Configurable ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"}; + + HfHelper hfHelper; + + Filter filterSelectCandidates = (aod::hf_sel_candidate_bs::isSelBsToDsPi >= selectionFlagBs); + + HistogramRegistry registry{"registry"}; + + using TracksPion = soa::Join; + + void init(InitContext&) + { + std::array processFuncData{doprocessData, doprocessDataWithDmesMl, doprocessDataWithBsMl}; + if ((std::accumulate(processFuncData.begin(), processFuncData.end(), 0)) > 1) { + LOGP(fatal, "Only one process function for data can be enabled at a time."); + } + std::array processFuncMc{doprocessMc, doprocessMcWithDecayTypeCheck, doprocessMcWithDmesMl, doprocessMcWithDmesMlAndDecayTypeCheck, doprocessMcWithBsMl, doprocessMcWithBsMlAndDecayTypeCheck}; + if ((std::accumulate(processFuncMc.begin(), processFuncMc.end(), 0)) > 1) { + LOGP(fatal, "Only one process function for MC can be enabled at a time."); + } + + const AxisSpec axisMlScore{100, 0.f, 1.f}; + const AxisSpec axisMassBs{300, 4.5f, 6.0f}; + const AxisSpec axisMassDs{300, 1.75f, 2.05f}; + const AxisSpec axisDecayLength{200, 0.f, 0.4f}; + const AxisSpec axisNormDecayLength{100, 0.f, 50.f}; + const AxisSpec axisDca{100, -0.05f, 0.05f}; + const AxisSpec axisCosp{110, 0.f, 1.1f}; + const AxisSpec axisEta{30, -1.5f, 1.5f}; + const AxisSpec axisError{100, 0.f, 1.f}; + const AxisSpec axisImpParProd{100, -1.e-3, 1.e-3}; + const AxisSpec axisPtBs{100, 0.f, 50.f}; + const AxisSpec axisPtDs{100, 0.f, 50.f}; + const AxisSpec axisPtPi{100, 0.f, 10.f}; + + if (doprocessData || doprocessDataWithDmesMl || doprocessDataWithBsMl) { + if (fillHistograms) { + registry.add("hMass", "B^{0}_{s} candidates;#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});#it{M} (D_{s}#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtBs, axisMassBs}}); + registry.add("hDecLength", "B^{0}_{s} candidates;#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtBs, axisDecayLength}}); + registry.add("hDecLengthXy", "B^{0}_{s} candidates;#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate decay length XY (cm);entries", {HistType::kTH2F, {axisPtBs, axisDecayLength}}); + registry.add("hNormDecLengthXy", "B^{0}_{s} candidates;#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate norm. decay length XY (cm);entries", {HistType::kTH2F, {axisPtBs, axisNormDecayLength}}); + registry.add("hDcaProng0", "B^{0}_{s} candidates;#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});prong 0 (D_{s}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtBs, axisDca}}); + registry.add("hDcaProng1", "B^{0}_{s} candidates;#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});prong 1 (#pi) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtBs, axisDca}}); + registry.add("hPtProng0", "B^{0}_{s} candidates;#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});#it{p}_{T}(D_{s}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtBs, axisPtDs}}); + registry.add("hPtProng1", "B^{0}_{s} candidates;#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});#it{p}_{T}(#pi) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtBs, axisPtPi}}); + registry.add("hCosp", "B^{0}_{s} candidates;#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtBs, axisCosp}}); + registry.add("hCospXy", "B^{0}_{s} candidates;#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtBs, axisCosp}}); + registry.add("hEta", "B^{0}_{s} candidates;#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate #it{#eta};entries", {HistType::kTH2F, {axisPtBs, axisEta}}); + registry.add("hRapidity", "B^{0}_{s} candidates;#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate #it{y};entries", {HistType::kTH2F, {axisPtBs, axisEta}}); + registry.add("hImpParProd", "B^{0}_{s} candidates;#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate impact parameter product;entries", {HistType::kTH2F, {axisPtBs, axisImpParProd}}); + registry.add("hInvMassD", "B^{0}_{s} candidates;#it{p}_{T}(D_{s}) (GeV/#it{c});prong0, #it{M}(KK#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtDs, axisMassDs}}); + registry.add("hDecLengthD", "B^{0}_{s} candidates;#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtDs, axisDecayLength}}); + registry.add("hDecLengthXyD", "B^{0}_{s} candidates;#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate decay length XY (cm);entries", {HistType::kTH2F, {axisPtDs, axisDecayLength}}); + registry.add("hCospD", "B^{0}_{s} candidates;#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtDs, axisCosp}}); + registry.add("hCospXyD", "B^{0}_{s} candidates;#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtDs, axisCosp}}); + + // ML scores of Ds- daughter + if (doprocessDataWithDmesMl) { + registry.add("hMlScoreBkgDs", "B^{0}_{s} candidates;#it{p}_{T}(D_{s}) (GeV/#it{c});prong0, Ds ML background score;entries", {HistType::kTH2F, {axisPtDs, axisMlScore}}); + registry.add("hMlScorePromptDs", "B^{0}_{s} candidates;#it{p}_{T}(D_{s}) (GeV/#it{c});prong0, Ds ML prompt score;entries", {HistType::kTH2F, {axisPtDs, axisMlScore}}); + registry.add("hMlScoreNonPromptDs", "B^{0}_{s} candidates;#it{p}_{T}(D_{s}) (GeV/#it{c});prong0, Ds ML nonprompt score;entries", {HistType::kTH2F, {axisPtDs, axisMlScore}}); + } + + // ML scores of Bs candidate + if (doprocessDataWithBsMl) { + registry.add("hMlScoreSigBs", "B^{0}_{s} candidates;#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});prong0, B^{0}_{s} ML signal score;entries", {HistType::kTH2F, {axisPtBs, axisMlScore}}); + } + } + if (fillSparses) { + if (!(doprocessDataWithDmesMl || doprocessDataWithBsMl)) { + registry.add("hMassPtCutVars", "B^{0}_{s} candidates;#it{M} (D_{s}#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate decay length (cm);B^{0}_{s} candidate norm. decay length XY (cm);B^{0}_{s} candidate impact parameter product (cm);B^{0}_{s} candidate cos(#vartheta_{P});#it{M} (KK#pi) (GeV/#it{c}^{2});#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate decay length (cm);D_{s} candidate cos(#vartheta_{P})", {HistType::kTHnSparseF, {axisMassBs, axisPtBs, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassDs, axisPtDs, axisDecayLength, axisCosp}}); + } else { + registry.add("hMassPtCutVars", "B^{0}_{s} candidates;#it{M} (D_{s}#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate decay length (cm);B^{0}_{s} candidate norm. decay length XY (cm);B^{0}_{s} candidate impact parameter product (cm);B^{0}_{s} candidate cos(#vartheta_{P});#it{M} (KK#pi) (GeV/#it{c}^{2});#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate ML score bkg;D_{s} candidate ML score nonprompt", {HistType::kTHnSparseF, {axisMassBs, axisPtBs, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassDs, axisPtDs, axisMlScore, axisMlScore}}); + } + } + } + + if (doprocessMc || doprocessMcWithDecayTypeCheck || doprocessMcWithDmesMl || doprocessMcWithDmesMlAndDecayTypeCheck || doprocessMcWithBsMl || doprocessMcWithBsMlAndDecayTypeCheck) { + if (fillHistograms) { + // gen histos + registry.add("hEtaGen", "B^{0}_{s} particles (generated);#it{p}_{T}^{gen}(B^{0}_{s}) (GeV/#it{c});#it{#eta}^{gen}(B^{0}_{s});entries", {HistType::kTH2F, {axisPtBs, axisEta}}); + registry.add("hYGen", "B^{0}_{s} particles (generated);#it{p}_{T}^{gen}(B^{0}_{s}) (GeV/#it{c});#it{y}^{gen}(B^{0}_{s});entries", {HistType::kTH2F, {axisPtBs, axisEta}}); + registry.add("hYGenWithProngsInAcceptance", "MC particles (generated-daughters in acceptance);#it{p}_{T}^{gen}(B^{0}_{s}) (GeV/#it{c});#it{y}^{gen}(B^{0}_{s});entries", {HistType::kTH2F, {axisPtBs, axisEta}}); + registry.add("hPtProng0Gen", "B^{0}_{s} particles (generated);#it{p}_{T}^{gen}(B^{0}_{s}) (GeV/#it{c});#it{p}_{T}^{gen}(D_{s}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtBs, axisPtDs}}); + registry.add("hPtProng1Gen", "B^{0}_{s} particles (generated);#it{p}_{T}^{gen}(B^{0}_{s}) (GeV/#it{c});#it{p}_{T}^{gen}(#pi) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtBs, axisPtPi}}); + registry.add("hYProng0Gen", "B^{0}_{s} particles (generated);#it{p}_{T}^{gen}(B^{0}_{s}) (GeV/#it{c});#it{y}^{gen}(D_{s});entries", {HistType::kTH2F, {axisPtBs, axisEta}}); + registry.add("hYProng1Gen", "B^{0}_{s} particles (generated);#it{p}_{T}^{gen}(B^{0}_{s}) (GeV/#it{c});#it{y}^{gen}(#pi);entries", {HistType::kTH2F, {axisPtBs, axisEta}}); + registry.add("hEtaProng0Gen", "B^{0}_{s} particles (generated);#it{p}_{T}^{gen}(B^{0}_{s}) (GeV/#it{c});#it{#eta}^{gen}(D_{s});entries", {HistType::kTH2F, {axisPtBs, axisEta}}); + registry.add("hEtaProng1Gen", "B^{0}_{s} particles (generated);#it{p}_{T}^{gen}(B^{0}_{s}) (GeV/#it{c});#it{#eta}^{gen}(#pi);entries", {HistType::kTH2F, {axisPtBs, axisEta}}); + + // reco histos + // signal + registry.add("hMassRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});#it{M} (D_{s}#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtBs, axisMassBs}}); + registry.add("hDecLengthRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtBs, axisDecayLength}}); + registry.add("hDecLengthXyRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate decay length XY (cm);entries", {HistType::kTH2F, {axisPtBs, axisDecayLength}}); + registry.add("hNormDecLengthXyRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate norm. decay length XY (cm);entries", {HistType::kTH2F, {axisPtBs, axisNormDecayLength}}); + registry.add("hDcaProng0RecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});prong 0 (D_{s}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtBs, axisDca}}); + registry.add("hDcaProng1RecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});prong 1 (#pi) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtBs, axisDca}}); + registry.add("hPtProng0RecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});#it{p}_{T}(D_{s}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtBs, axisPtDs}}); + registry.add("hPtProng1RecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});#it{p}_{T}(#pi) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtBs, axisPtPi}}); + registry.add("hCospRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtBs, axisCosp}}); + registry.add("hCospXyRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtBs, axisCosp}}); + registry.add("hEtaRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate #it{#eta};entries", {HistType::kTH2F, {axisPtBs, axisEta}}); + registry.add("hRapidityRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate #it{y};entries", {HistType::kTH2F, {axisPtBs, axisEta}}); + registry.add("hImpParProdRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate impact parameter product;entries", {HistType::kTH2F, {axisPtBs, axisImpParProd}}); + registry.add("hInvMassDRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(D_{s}) (GeV/#it{c});prong0, #it{M}(KK#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtDs, axisMassDs}}); + registry.add("hDecLengthDRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtDs, axisDecayLength}}); + registry.add("hDecLengthXyDRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate decay length XY (cm);entries", {HistType::kTH2F, {axisPtDs, axisDecayLength}}); + registry.add("hCospDRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtDs, axisCosp}}); + registry.add("hCospXyDRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtDs, axisCosp}}); + // background + if (fillBackground) { + registry.add("hMassRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});#it{M} (D_{s}#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtBs, axisMassBs}}); + registry.add("hDecLengthRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtBs, axisDecayLength}}); + registry.add("hDecLengthXyRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate decay length XY (cm);entries", {HistType::kTH2F, {axisPtBs, axisDecayLength}}); + registry.add("hNormDecLengthXyRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate norm. decay length XY (cm);entries", {HistType::kTH2F, {axisPtBs, axisNormDecayLength}}); + registry.add("hDcaProng0RecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});prong 0 (D_{s}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtBs, axisDca}}); + registry.add("hDcaProng1RecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});prong 1 (#pi) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtBs, axisDca}}); + registry.add("hPtProng0RecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});#it{p}_{T}(D_{s}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtBs, axisPtDs}}); + registry.add("hPtProng1RecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});#it{p}_{T}(#pi) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtBs, axisPtPi}}); + registry.add("hCospRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtBs, axisCosp}}); + registry.add("hCospXyRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtBs, axisCosp}}); + registry.add("hEtaRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate #it{#eta};entries", {HistType::kTH2F, {axisPtBs, axisEta}}); + registry.add("hRapidityRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate #it{y};entries", {HistType::kTH2F, {axisPtBs, axisEta}}); + registry.add("hImpParProdRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate impact parameter product;entries", {HistType::kTH2F, {axisPtBs, axisImpParProd}}); + registry.add("hInvMassDRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(D_{s}) (GeV/#it{c});prong0, #it{M}(KK#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtDs, axisMassDs}}); + registry.add("hDecLengthDRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtDs, axisDecayLength}}); + registry.add("hDecLengthXyDRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate decay length XY (cm);entries", {HistType::kTH2F, {axisPtDs, axisDecayLength}}); + registry.add("hCospDRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtDs, axisCosp}}); + registry.add("hCospXyDRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtDs, axisCosp}}); + } + // MC checks + if (doprocessMcWithDecayTypeCheck || doprocessMcWithBsMlAndDecayTypeCheck || doprocessMcWithDmesMlAndDecayTypeCheck) { + constexpr uint8_t kNBinsDecayTypeMc = hf_cand_bs::DecayTypeMc::NDecayTypeMc; + TString labels[kNBinsDecayTypeMc]; + labels[hf_cand_bs::DecayTypeMc::BsToDsPiToPhiPiPiToKKPiPi] = "B^{0}_{s} #rightarrow (D_{s} #rightarrow #Phi#pi #rightarrow KK#pi) #pi"; + labels[hf_cand_bs::DecayTypeMc::BsToDsPiToK0starKPiToKKPiPi] = "B^{0}_{s} #rightarrow (D_{s} #rightarrow K^{0*}K #rightarrow KK#pi) #pi"; + labels[hf_cand_bs::DecayTypeMc::B0ToDsPiToPhiPiPiToKKPiPi] = "B^{0} #rightarrow (D_{s} #rightarrow #Phi#pi #rightarrow KK#pi) #pi"; + labels[hf_cand_bs::DecayTypeMc::B0ToDsPiToK0starKPiToKKPiPi] = "B^{0} #rightarrow (D_{s} #rightarrow K^{0*}K #rightarrow KK#pi) #pi"; + labels[hf_cand_bs::DecayTypeMc::PartlyRecoDecay] = "Partly reconstructed decay channel"; + labels[hf_cand_bs::DecayTypeMc::OtherDecay] = "Other decays"; + static const AxisSpec axisDecayType = {kNBinsDecayTypeMc, 0.5, kNBinsDecayTypeMc + 0.5, ""}; + registry.add("hDecayTypeMc", "DecayType", {HistType::kTH3F, {axisDecayType, axisMassBs, axisPtBs}}); + for (uint8_t iBin = 0; iBin < kNBinsDecayTypeMc; ++iBin) { + registry.get(HIST("hDecayTypeMc"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin]); + } + } + // ML scores of Ds- daughter + if (doprocessMcWithDmesMl || doprocessMcWithDmesMlAndDecayTypeCheck) { + // signal + registry.add("hMlScoreBkgDsRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(D_{s}) (GeV/#it{c});prong0, Ds ML background score;entries", {HistType::kTH2F, {axisPtDs, axisMlScore}}); + registry.add("hMlScorePromptDsRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(D_{s}) (GeV/#it{c});prong0, Ds ML prompt score;entries", {HistType::kTH2F, {axisPtDs, axisMlScore}}); + registry.add("hMlScoreNonPromptDsRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(D_{s}) (GeV/#it{c});prong0, Ds ML nonprompt score;entries", {HistType::kTH2F, {axisPtDs, axisMlScore}}); + // background + registry.add("hMlScoreBkgDsRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(D_{s}) (GeV/#it{c});prong0, Ds ML background score;entries", {HistType::kTH2F, {axisPtDs, axisMlScore}}); + registry.add("hMlScorePromptDsRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(D_{s}) (GeV/#it{c});prong0, Ds ML prompt score;entries", {HistType::kTH2F, {axisPtDs, axisMlScore}}); + registry.add("hMlScoreNonPromptDsRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(D_{s}) (GeV/#it{c});prong0, Ds ML nonprompt score;entries", {HistType::kTH2F, {axisPtDs, axisMlScore}}); + } + // ML scores of Bs candidate + if (doprocessMcWithBsMl || doprocessMcWithBsMlAndDecayTypeCheck) { + // signal + registry.add("hMlScoreSigBsRecSig", "B^{0}_{s} candidates (matched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});prong0, B^{0}_{s} ML signal score;entries", {HistType::kTH2F, {axisPtBs, axisMlScore}}); + // background + registry.add("hMlScoreSigBsRecBg", "B^{0}_{s} candidates (unmatched);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});prong0, B^{0}_{s} ML signal score;entries", {HistType::kTH2F, {axisPtBs, axisMlScore}}); + } + } + if (fillSparses) { + // gen sparses + registry.add("hPtYGenSig", "B^{0}_{s} particles (generated);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});#it{y}(B^{0}_{s})", {HistType::kTHnSparseF, {axisPtBs, axisEta}}); + registry.add("hPtYWithProngsInAccepanceGenSig", "B^{0}_{s} particles (generated-daughters in acceptance);#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});#it{y}(B^{0}_{s})", {HistType::kTHnSparseF, {axisPtBs, axisEta}}); + + // reco sparses + if (!(doprocessDataWithDmesMl || doprocessDataWithBsMl)) { + registry.add("hMassPtCutVarsRecSig", "B^{0}_{s} candidates (matched);#it{M} (D_{s}#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate decay length (cm);B^{0}_{s} candidate norm. decay length XY (cm);B^{0}_{s} candidate impact parameter product (cm);B^{0}_{s} candidate cos(#vartheta_{P});#it{M} (KK#pi) (GeV/#it{c}^{2});#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate decay length (cm);D_{s} candidate cos(#vartheta_{P})", {HistType::kTHnSparseF, {axisMassBs, axisPtBs, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassDs, axisPtDs, axisDecayLength, axisCosp}}); + if (fillBackground) { + registry.add("hMassPtCutVarsRecBg", "B^{0}_{s} candidates (unmatched);#it{M} (D_{s}#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate decay length (cm);B^{0}_{s} candidate norm. decay length XY (cm);B^{0}_{s} candidate impact parameter product (cm);B^{0}_{s} candidate cos(#vartheta_{P});#it{M} (KK#pi) (GeV/#it{c}^{2});#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate decay length (cm);D_{s} candidate cos(#vartheta_{P})", {HistType::kTHnSparseF, {axisMassBs, axisPtBs, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassDs, axisPtDs, axisDecayLength, axisCosp}}); + } + } else { + registry.add("hMassPtCutVarsRecSig", "B^{0}_{s} candidates (matched);#it{M} (D_{s}#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate decay length (cm);B^{0}_{s} candidate norm. decay length XY (cm);B^{0}_{s} candidate impact parameter product (cm);B^{0}_{s} candidate cos(#vartheta_{P});#it{M} (KK#pi) (GeV/#it{c}^{2});#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate ML score bkg;D_{s} candidate ML score nonprompt", {HistType::kTHnSparseF, {axisMassBs, axisPtBs, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassDs, axisPtDs, axisMlScore, axisMlScore}}); + if (fillBackground) { + registry.add("hMassPtCutVarsRecBg", "B^{0}_{s} candidates (unmatched);#it{M} (D_{s}#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}_{s}) (GeV/#it{c});B^{0}_{s} candidate decay length (cm);B^{0}_{s} candidate norm. decay length XY (cm);B^{0}_{s} candidate impact parameter product (cm);B^{0}_{s} candidate cos(#vartheta_{P});#it{M} (KK#pi) (GeV/#it{c}^{2});#it{p}_{T}(D_{s}) (GeV/#it{c});D_{s} candidate ML score bkg;D_{s} candidate ML score nonprompt", {HistType::kTHnSparseF, {axisMassBs, axisPtBs, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassDs, axisPtDs, axisMlScore, axisMlScore}}); + } + } + } + } + } + + /// Selection of Bs daughter in geometrical acceptance + /// \param etaProng is the pseudorapidity of Bs prong + /// \param ptProng is the pT of Bs prong + /// \return true if prong is in geometrical acceptance + template + bool isProngInAcceptance(const T& etaProng, const T& ptProng) + { + return std::abs(etaProng) <= etaTrackMax && ptProng >= ptTrackMin; + } + + /// Fill candidate information at reconstruction level + /// \param doMc is the flag to enable the filling with MC information + /// \param withDecayTypeCheck is the flag to enable MC with decay type check + /// \param withDmesMl is the flag to enable the filling with ML scores for the Ds- daughter + /// \param withBsMl is the flag to enable the filling with ML scores for the Bs candidate + /// \param candidate is the Bs candidate + /// \param candidatesD is the table with Ds- candidates + template + void fillCand(Cand const& candidate, + aod::HfRed3Prongs const&) + { + auto ptCandBs = candidate.pt(); + auto invMassBs = hfHelper.invMassBsToDsPi(candidate); + auto candDs = candidate.template prong0_as(); + auto ptDs = candidate.ptProng0(); + auto invMassDs = candDs.invMassHypo0() > 0 ? candDs.invMassHypo0() : candDs.invMassHypo1(); + // TODO: here we are assuming that only one of the two hypotheses is filled, to be checked + std::array posPv{candidate.posX(), candidate.posY(), candidate.posZ()}; + std::array posSvDs{candDs.xSecondaryVertex(), candDs.ySecondaryVertex(), candDs.zSecondaryVertex()}; + std::array momDs{candDs.pVector()}; + auto cospDs = RecoDecay::cpa(posPv, posSvDs, momDs); + auto cospXyDs = RecoDecay::cpaXY(posPv, posSvDs, momDs); + auto decLenDs = RecoDecay::distance(posPv, posSvDs); + auto decLenXyDs = RecoDecay::distanceXY(posPv, posSvDs); + + int8_t flagMcMatchRec = 0; + int8_t flagWrongCollision = 0; + bool isSignal = false; + if constexpr (doMc) { + flagMcMatchRec = candidate.flagMcMatchRec(); + flagWrongCollision = candidate.flagWrongCollision(); + isSignal = TESTBIT(std::abs(flagMcMatchRec), hf_cand_bs::DecayTypeMc::BsToDsPiToPhiPiPiToKKPiPi); + } + + if (fillHistograms) { + if constexpr (doMc) { + if (isSignal) { + registry.fill(HIST("hMassRecSig"), ptCandBs, invMassBs); + registry.fill(HIST("hPtProng0RecSig"), ptCandBs, candidate.ptProng0()); + registry.fill(HIST("hPtProng1RecSig"), ptCandBs, candidate.ptProng1()); + registry.fill(HIST("hImpParProdRecSig"), ptCandBs, candidate.impactParameterProduct()); + registry.fill(HIST("hDecLengthRecSig"), ptCandBs, candidate.decayLength()); + registry.fill(HIST("hDecLengthXyRecSig"), ptCandBs, candidate.decayLengthXY()); + registry.fill(HIST("hNormDecLengthXyRecSig"), ptCandBs, candidate.decayLengthXY() / candidate.errorDecayLengthXY()); + registry.fill(HIST("hDcaProng0RecSig"), ptCandBs, candidate.impactParameter0()); + registry.fill(HIST("hDcaProng1RecSig"), ptCandBs, candidate.impactParameter1()); + registry.fill(HIST("hCospRecSig"), ptCandBs, candidate.cpa()); + registry.fill(HIST("hCospXyRecSig"), ptCandBs, candidate.cpaXY()); + registry.fill(HIST("hEtaRecSig"), ptCandBs, candidate.eta()); + registry.fill(HIST("hRapidityRecSig"), ptCandBs, hfHelper.yBs(candidate)); + registry.fill(HIST("hInvMassDRecSig"), ptDs, invMassDs); + registry.fill(HIST("hDecLengthDRecSig"), ptDs, decLenDs); + registry.fill(HIST("hDecLengthXyDRecSig"), ptDs, decLenXyDs); + registry.fill(HIST("hCospDRecSig"), ptDs, cospDs); + registry.fill(HIST("hCospXyDRecSig"), ptDs, cospXyDs); + if constexpr (withDecayTypeCheck) { + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_bs::DecayTypeMc::BsToDsPiToPhiPiPiToKKPiPi, invMassBs, ptCandBs); + } + if constexpr (withDmesMl) { + registry.fill(HIST("hMlScoreBkgDsRecSig"), ptDs, candidate.prong0MlScoreBkg()); + registry.fill(HIST("hMlScorePromptDsRecSig"), ptDs, candidate.prong0MlScorePrompt()); + registry.fill(HIST("hMlScoreNonPromptDsRecSig"), ptDs, candidate.prong0MlScoreNonprompt()); + } + if constexpr (withBsMl) { + registry.fill(HIST("hMlScoreSigBsRecSig"), ptCandBs, candidate.mlProbBsToDsPi()[1]); + } + } else if (fillBackground) { + registry.fill(HIST("hMassRecBg"), ptCandBs, invMassBs); + registry.fill(HIST("hPtProng0RecBg"), ptCandBs, candidate.ptProng0()); + registry.fill(HIST("hPtProng1RecBg"), ptCandBs, candidate.ptProng1()); + registry.fill(HIST("hImpParProdRecBg"), ptCandBs, candidate.impactParameterProduct()); + registry.fill(HIST("hDecLengthRecBg"), ptCandBs, candidate.decayLength()); + registry.fill(HIST("hDecLengthXyRecBg"), ptCandBs, candidate.decayLengthXY()); + registry.fill(HIST("hNormDecLengthXyRecBg"), ptCandBs, candidate.decayLengthXY() / candidate.errorDecayLengthXY()); + registry.fill(HIST("hDcaProng0RecBg"), ptCandBs, candidate.impactParameter0()); + registry.fill(HIST("hDcaProng1RecBg"), ptCandBs, candidate.impactParameter1()); + registry.fill(HIST("hCospRecBg"), ptCandBs, candidate.cpa()); + registry.fill(HIST("hCospXyRecBg"), ptCandBs, candidate.cpaXY()); + registry.fill(HIST("hEtaRecBg"), ptCandBs, candidate.eta()); + registry.fill(HIST("hRapidityRecBg"), ptCandBs, hfHelper.yBs(candidate)); + registry.fill(HIST("hInvMassDRecBg"), ptDs, invMassDs); + registry.fill(HIST("hDecLengthDRecBg"), ptDs, decLenDs); + registry.fill(HIST("hDecLengthXyDRecBg"), ptDs, decLenXyDs); + registry.fill(HIST("hCospDRecBg"), ptDs, cospDs); + registry.fill(HIST("hCospXyDRecBg"), ptDs, cospXyDs); + if constexpr (withDmesMl) { + registry.fill(HIST("hMlScoreBkgDsRecBg"), ptDs, candidate.prong0MlScoreBkg()); + registry.fill(HIST("hMlScorePromptDsRecBg"), ptDs, candidate.prong0MlScorePrompt()); + registry.fill(HIST("hMlScoreNonPromptDsRecBg"), ptDs, candidate.prong0MlScoreNonprompt()); + } + if constexpr (withBsMl) { + registry.fill(HIST("hMlScoreSigBsRecBg"), ptCandBs, candidate.mlProbBsToDsPi()[1]); + } + } else if constexpr (withDecayTypeCheck) { + for (uint8_t iFlag = 1; iFlag < hf_cand_bs::DecayTypeMc::NDecayTypeMc; ++iFlag) { + if (TESTBIT(flagMcMatchRec, iFlag)) { + registry.fill(HIST("hDecayTypeMc"), 1 + iFlag, invMassBs, ptCandBs); + } + } + } + } else { + registry.fill(HIST("hMass"), ptCandBs, invMassBs); + registry.fill(HIST("hPtProng0"), ptCandBs, candidate.ptProng0()); + registry.fill(HIST("hPtProng1"), ptCandBs, candidate.ptProng1()); + registry.fill(HIST("hImpParProd"), ptCandBs, candidate.impactParameterProduct()); + registry.fill(HIST("hDecLength"), ptCandBs, candidate.decayLength()); + registry.fill(HIST("hDecLengthXy"), ptCandBs, candidate.decayLengthXY()); + registry.fill(HIST("hNormDecLengthXy"), ptCandBs, candidate.decayLengthXY() / candidate.errorDecayLengthXY()); + registry.fill(HIST("hDcaProng0"), ptCandBs, candidate.impactParameter0()); + registry.fill(HIST("hDcaProng1"), ptCandBs, candidate.impactParameter1()); + registry.fill(HIST("hCosp"), ptCandBs, candidate.cpa()); + registry.fill(HIST("hCospXy"), ptCandBs, candidate.cpaXY()); + registry.fill(HIST("hEta"), ptCandBs, candidate.eta()); + registry.fill(HIST("hRapidity"), ptCandBs, hfHelper.yBs(candidate)); + registry.fill(HIST("hInvMassD"), ptDs, invMassDs); + registry.fill(HIST("hDecLengthD"), ptDs, decLenDs); + registry.fill(HIST("hDecLengthXyD"), ptDs, decLenXyDs); + registry.fill(HIST("hCospD"), ptDs, cospDs); + registry.fill(HIST("hCospXyD"), ptDs, cospXyDs); + + if constexpr (withDmesMl) { + registry.fill(HIST("hMlScoreBkgDs"), ptDs, candidate.prong0MlScoreBkg()); + registry.fill(HIST("hMlScorePromptDs"), ptDs, candidate.prong0MlScorePrompt()); + registry.fill(HIST("hMlScoreNonPromptDs"), ptDs, candidate.prong0MlScoreNonprompt()); + } + if constexpr (withBsMl) { + registry.fill(HIST("hMlScoreSigBs"), ptCandBs, candidate.mlProbBsToDsPi()[1]); + } + } + } + if (fillSparses) { + if constexpr (withDmesMl) { + if (isSignal) { + if constexpr (withDmesMl) { + registry.fill(HIST("hMassPtCutVarsRecSig"), invMassBs, ptCandBs, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassDs, ptDs, candidate.prong0MlScoreBkg(), candidate.prong0MlScoreNonprompt()); + } else { + registry.fill(HIST("hMassPtCutVarsRecSig"), invMassBs, ptCandBs, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassDs, ptDs, decLenDs, cospDs); + } + } else if (fillBackground) { + if constexpr (withDmesMl) { + registry.fill(HIST("hMassPtCutVarsRecBg"), invMassBs, ptCandBs, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassDs, ptDs, candidate.prong0MlScoreBkg(), candidate.prong0MlScoreNonprompt()); + } else { + registry.fill(HIST("hMassPtCutVarsRecBg"), invMassBs, ptCandBs, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassDs, ptDs, decLenDs, cospDs); + } + } + } else { + if constexpr (withDmesMl) { + registry.fill(HIST("hMassPtCutVars"), invMassBs, ptCandBs, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassDs, ptDs, candidate.prong0MlScoreBkg(), candidate.prong0MlScoreNonprompt()); + } else { + registry.fill(HIST("hMassPtCutVars"), invMassBs, ptCandBs, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassDs, ptDs, decLenDs, cospDs); + } + } + } + if (fillTree) { + float pseudoRndm = ptDs * 1000. - static_cast(ptDs * 1000); + if (flagMcMatchRec != 0 || (((doMc && fillBackground) || !doMc) && (ptCandBs >= ptMaxForDownSample || pseudoRndm < downSampleBkgFactor))) { + float prong0MlScoreBkg = -1.; + float prong0MlScorePrompt = -1.; + float prong0MlScoreNonprompt = -1.; + float candidateMlScoreSig = -1; + if constexpr (withDmesMl) { + prong0MlScoreBkg = candidate.prong0MlScoreBkg(); + prong0MlScorePrompt = candidate.prong0MlScorePrompt(); + prong0MlScoreNonprompt = candidate.prong0MlScoreNonprompt(); + } + if constexpr (withBsMl) { + candidateMlScoreSig = candidate.mlProbBsToDsPi()[1]; + } + auto prong1 = candidate.template prong1_as(); + + float ptMother = -1.; + if constexpr (doMc) { + ptMother = candidate.ptMother(); + } + + hfRedCandBsLite( + candidate.chi2PCA(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.decayLengthNormalised(), + candidate.decayLengthXYNormalised(), + invMassDs, + ptDs, + candidate.ptProng1(), + candidate.impactParameter0(), + candidate.impactParameter1(), + candidate.impactParameterProduct(), + prong1.tpcNSigmaPi(), + prong1.tofNSigmaPi(), + prong0MlScoreBkg, + prong0MlScorePrompt, + prong0MlScoreNonprompt, + candidateMlScoreSig, + candidate.isSelBsToDsPi(), + invMassBs, + ptCandBs, + candidate.cpa(), + candidate.cpaXY(), + candidate.maxNormalisedDeltaIP(), + candidate.eta(), + candidate.phi(), + hfHelper.yBs(candidate), + flagMcMatchRec, + isSignal, + flagWrongCollision, + ptMother); + + if constexpr (withDecayTypeCheck) { + float candidateMlScoreSig = -1; + if constexpr (withBsMl) { + candidateMlScoreSig = candidate.mlProbBsToDsPi()[1]; + } + hfRedBsMcCheck( + flagMcMatchRec, + flagWrongCollision, + invMassDs, + ptDs, + invMassBs, + ptCandBs, + candidateMlScoreSig, + candidate.pdgCodeBeautyMother(), + candidate.pdgCodeCharmMother(), + candidate.pdgCodeProng0(), + candidate.pdgCodeProng1(), + candidate.pdgCodeProng2(), + candidate.pdgCodeProng3()); + } + } + } + } + + /// Fill particle histograms (gen MC truth) + void fillCandMcGen(aod::HfMcGenRedBss::iterator const& particle) + { + // keep only generated Bs with the analysis decay channel + if (!TESTBIT(std::abs(particle.flagMcMatchGen()), hf_cand_bs::DecayTypeMc::BsToDsPiToPhiPiPiToKKPiPi)) { + return; + } + auto ptParticle = particle.ptTrack(); + auto yParticle = particle.yTrack(); + auto etaParticle = particle.etaTrack(); + if (yCandGenMax >= 0. && std::abs(yParticle) > yCandGenMax) { + return; + } + std::array ptProngs = {particle.ptProng0(), particle.ptProng1()}; + std::array yProngs = {particle.yProng0(), particle.yProng1()}; + std::array etaProngs = {particle.etaProng0(), particle.etaProng1()}; + bool prongsInAcc = isProngInAcceptance(etaProngs[0], ptProngs[0]) && isProngInAcceptance(etaProngs[1], ptProngs[1]); + + if (fillHistograms) { + registry.fill(HIST("hPtProng0Gen"), ptParticle, ptProngs[0]); + registry.fill(HIST("hPtProng1Gen"), ptParticle, ptProngs[1]); + registry.fill(HIST("hYProng0Gen"), ptParticle, yProngs[0]); + registry.fill(HIST("hYProng1Gen"), ptParticle, yProngs[1]); + registry.fill(HIST("hEtaProng0Gen"), ptParticle, etaProngs[0]); + registry.fill(HIST("hEtaProng1Gen"), ptParticle, etaProngs[1]); + + registry.fill(HIST("hYGen"), ptParticle, yParticle); + registry.fill(HIST("hEtaGen"), ptParticle, etaParticle); + + // generated Bs with daughters in geometrical acceptance + if (prongsInAcc) { + registry.fill(HIST("hYGenWithProngsInAcceptance"), ptParticle, yParticle); + } + } + if (fillSparses) { + registry.fill(HIST("hPtYGenSig"), ptParticle, yParticle); + if (prongsInAcc) { + registry.fill(HIST("hPtYWithProngsInAccepanceGenSig"), ptParticle, yParticle); + } + } + } + + // Process functions + void processData(soa::Filtered> const& candidates, + aod::HfRed3Prongs const& candidatesD, + TracksPion const&) + { + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yBs(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesD); + } // candidate loop + } // processData + PROCESS_SWITCH(HfTaskBsReduced, processData, "Process data without ML scores for Bs and D daughter", true); + + void processDataWithDmesMl(soa::Filtered> const& candidates, + aod::HfRed3Prongs const& candidatesD, + TracksPion const&) + { + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yBs(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesD); + } // candidate loop + } // processDataWithDmesMl + PROCESS_SWITCH(HfTaskBsReduced, processDataWithDmesMl, "Process data with(out) ML scores for D daughter (Bs)", false); + + void processDataWithBsMl(soa::Filtered> const& candidates, + aod::HfRed3Prongs const& candidatesD, + TracksPion const&) + { + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yBs(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesD); + } // candidate loop + } // processDataWithBsMl + PROCESS_SWITCH(HfTaskBsReduced, processDataWithBsMl, "Process data with(out) ML scores for Bs (D daughter)", false); + + void processMc(soa::Filtered> const& candidates, + aod::HfMcGenRedBss const& mcParticles, + aod::HfRed3Prongs const& candidatesD, + TracksPion const&) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yBs(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesD); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMc + PROCESS_SWITCH(HfTaskBsReduced, processMc, "Process MC without ML scores for Bs and D daughter", false); + + void processMcWithDecayTypeCheck(soa::Filtered> const& candidates, + aod::HfMcGenRedBss const& mcParticles, + aod::HfRed3Prongs const& candidatesD, + TracksPion const&) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yBs(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesD); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMc + PROCESS_SWITCH(HfTaskBsReduced, processMcWithDecayTypeCheck, "Process MC with decay type check and without ML scores for Bs and D daughter", false); + + void processMcWithDmesMl(soa::Filtered> const& candidates, + aod::HfMcGenRedBss const& mcParticles, + aod::HfRed3Prongs const& candidatesD, + TracksPion const&) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yBs(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesD); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMcWithDmesMl + PROCESS_SWITCH(HfTaskBsReduced, processMcWithDmesMl, "Process MC with(out) ML scores for D daughter (Bs)", false); + + void processMcWithDmesMlAndDecayTypeCheck(soa::Filtered> const& candidates, + aod::HfMcGenRedBss const& mcParticles, + aod::HfRed3Prongs const& candidatesD, + TracksPion const&) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yBs(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesD); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMc + PROCESS_SWITCH(HfTaskBsReduced, processMcWithDmesMlAndDecayTypeCheck, "Process MC with decay type check and with(out) ML scores for Bs (D daughter)", false); + + void processMcWithBsMl(soa::Filtered> const& candidates, + aod::HfMcGenRedBss const& mcParticles, + aod::HfRed3Prongs const& candidatesD, + TracksPion const&) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yBs(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesD); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMcWithBsMl + PROCESS_SWITCH(HfTaskBsReduced, processMcWithBsMl, "Process MC with(out) ML scores for Bs (D daughter)", false); + + void processMcWithBsMlAndDecayTypeCheck(soa::Filtered> const& candidates, + aod::HfMcGenRedBss const& mcParticles, + aod::HfRed3Prongs const& candidatesD, + TracksPion const&) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yBs(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesD); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMc + PROCESS_SWITCH(HfTaskBsReduced, processMcWithBsMlAndDecayTypeCheck, "Process MC with decay type check and with(out) ML scores for B0 (D daughter)", false); +}; // struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/Tasks/taskCharmPolarisation.cxx b/PWGHF/D2H/Tasks/taskCharmPolarisation.cxx index 2f45e221317..43b75756959 100644 --- a/PWGHF/D2H/Tasks/taskCharmPolarisation.cxx +++ b/PWGHF/D2H/Tasks/taskCharmPolarisation.cxx @@ -16,6 +16,8 @@ /// \author S. Kundu (CERN) sourav.kundu@cern.ch /// \author M. Faggin (CERN) mattia.faggin@cern.ch +#include + #include "TRandom3.h" #include "Math/Vector3D.h" #include "Math/Vector4D.h" @@ -59,12 +61,52 @@ enum MassHyposLcToPKPi : uint8_t { PiKP, NMassHypoLcToPKPi }; + +/// columns for table to study the Lc->PKPi background +DECLARE_SOA_COLUMN(MassLc, massLc, float); +DECLARE_SOA_COLUMN(PtLc, ptLc, float); +DECLARE_SOA_COLUMN(RapidityLc, rapidityLc, float); +DECLARE_SOA_COLUMN(CosThetaStar, cosThetaStar, float); +DECLARE_SOA_COLUMN(PdgMotherProng0, pdgMotherProng0, int); +DECLARE_SOA_COLUMN(PdgMotherProng1, pdgMotherProng1, int); +DECLARE_SOA_COLUMN(PdgMotherProng2, pdgMotherProng2, int); +DECLARE_SOA_COLUMN(MassKPi, massKPi, float); +DECLARE_SOA_COLUMN(MassKProton, massKProton, float); +DECLARE_SOA_COLUMN(MassPiProton, massPiProton, float); +DECLARE_SOA_COLUMN(BdtBkgScore, bdtBkgScore, float); +DECLARE_SOA_COLUMN(BdtNonPromptScore, bdtNonPromptScore, float); +DECLARE_SOA_COLUMN(IsRealPKPi, isRealPKPi, int8_t); +DECLARE_SOA_COLUMN(IsRealLcPKPi, isRealLcPKPi, int8_t); +DECLARE_SOA_COLUMN(IsReflected, isReflected, int8_t); +DECLARE_SOA_COLUMN(Charge, charge, int8_t); +DECLARE_SOA_COLUMN(Origin, origin, int8_t); + } // namespace charm_polarisation + +/// table to study the Lc->PKPi background +DECLARE_SOA_TABLE(HfLcPolBkg, "AOD", "HFLCPOLBKG", + charm_polarisation::MassLc, + charm_polarisation::PtLc, + charm_polarisation::RapidityLc, + charm_polarisation::CosThetaStar, + charm_polarisation::PdgMotherProng0, + charm_polarisation::PdgMotherProng1, + charm_polarisation::PdgMotherProng2, + charm_polarisation::MassKPi, + charm_polarisation::MassKProton, + charm_polarisation::MassPiProton, + charm_polarisation::BdtBkgScore, + charm_polarisation::BdtNonPromptScore, + charm_polarisation::IsRealPKPi, + charm_polarisation::IsRealLcPKPi, + charm_polarisation::IsReflected, + charm_polarisation::Charge, + charm_polarisation::Origin); + } // namespace o2::aod struct TaskPolarisationCharmHadrons { - using CandDstarWSelFlag = soa::Join; - using CandLcToPKPiWSelFlag = soa::Join; + Produces rowCandLcBkg; float massPi{0.f}; float massProton{0.f}; @@ -80,37 +122,122 @@ struct TaskPolarisationCharmHadrons { ConfigurableAxis configThnAxisInvMass{"configThnAxisInvMass", {200, 0.139f, 0.179f}, "#it{M} (GeV/#it{c}^{2})"}; ConfigurableAxis configThnAxisPt{"configThnAxisPt", {100, 0.f, 100.f}, "#it{p}_{T} (GeV/#it{c})"}; - ConfigurableAxis configThnAxisPz{"configThnAxisPz", {100, -50.f, 50.f}, "#it{p}_{z} (GeV/#it{c})"}; ConfigurableAxis configThnAxisY{"configThnAxisY", {20, -1.f, 1.f}, "#it{y}"}; ConfigurableAxis configThnAxisCosThetaStarHelicity{"configThnAxisCosThetaStarHelicity", {20, -1.f, 1.f}, "cos(#vartheta_{helicity})"}; ConfigurableAxis configThnAxisCosThetaStarProduction{"configThnAxisCosThetaStarProduction", {20, -1.f, 1.f}, "cos(#vartheta_{production})"}; ConfigurableAxis configThnAxisCosThetaStarRandom{"configThnAxisCosThetaStarRandom", {20, -1.f, 1.f}, "cos(#vartheta_{random})"}; ConfigurableAxis configThnAxisCosThetaStarBeam{"configThnAxisCosThetaStarBeam", {20, -1.f, 1.f}, "cos(#vartheta_{beam})"}; ConfigurableAxis configThnAxisMlBkg{"configThnAxisMlBkg", {100, 0.f, 1.f}, "ML bkg"}; - ConfigurableAxis configThnAxisInvMassD0{"configThnAxisInvMassD0", {250, 1.65f, 2.15f}, "#it{M}(D^{0}) (GeV/#it{c}^{2})"}; // only for D*+ + ConfigurableAxis configThnAxisInvMassD0{"configThnAxisInvMassD0", {250, 1.65f, 2.15f}, "#it{M}(D^{0}) (GeV/#it{c}^{2})"}; // only for D*+ + ConfigurableAxis configThnAxisInvMassKPiLc{"configThnAxisInvMassKPiLc", {120, 0.65f, 1.25f}, "#it{M}(K#pi) from #Lambda_{c}^{+} (GeV/#it{c}^{2})"}; // only for Lc+->pKpi // ConfigurableAxis configThnAxisMlPrompt{"configThnAxisMlPrompt", {100, 0.f, 1.f}, "ML prompt"}; ConfigurableAxis configThnAxisMlNonPrompt{"configThnAxisMlNonPrompt", {100, 0.f, 1.f}, "ML non-prompt"}; // ConfigurableAxis configThnAxisCent{"configThnAxisCent", {102, -1.f, 101.f}, "centrality (%)"}; + ConfigurableAxis configThnAxisNumPvContributors{"configThnAxisNumPvContributors", {300, -0.5f, 299.5f}, "num PV contributors"}; + ConfigurableAxis configThnAxisPtB{"configThnAxisPtB", {3000, 0.f, 300.f}, "#it{p}_{T}(B mother) (GeV/#it{c})"}; + ConfigurableAxis configThnAxisAbsEtaTrackMin{"configThnAxisEtaTrackMin", {3, 0.f, 0.3f}, "min |#it{#eta_{track}}|"}; + ConfigurableAxis configThnAxisNumItsClsMin{"configThnAxisNumItsClsMin", {4, 3.5f, 7.5f}, "min #it{N}_{cls ITS}"}; + ConfigurableAxis configThnAxisNumTpcClsMin{"configThnAxisNumTpcClsMin", {3, 79.5f, 140.5f}, "min #it{N}_{cls TPC}"}; + ConfigurableAxis configThnAxisCharge{"configThnAxisCharge", {2, -2.f, 2.f}, "electric charge"}; /// activate rotational background Configurable nBkgRotations{"nBkgRotations", 0, "Number of rotated copies (background) per each original candidate"}; + Configurable minRotAngleMultByPi{"minRotAngleMultByPi", 5. / 6, "Minimum angle rotation for track rotation, to be multiplied by pi"}; + Configurable maxRotAngleMultByPi{"maxRotAngleMultByPi", 7. / 6, "Maximum angle rotation for track rotation, to be multiplied by pi"}; + + // activate study of systematic uncertainties of tracking + Configurable activateTrackingSys{"activateTrackingSys", false, "Activate the study of systematic uncertainties of tracking"}; /// output THnSparses Configurable activateTHnSparseCosThStarHelicity{"activateTHnSparseCosThStarHelicity", true, "Activate the THnSparse with cosThStar w.r.t. helicity axis"}; Configurable activateTHnSparseCosThStarProduction{"activateTHnSparseCosThStarProduction", true, "Activate the THnSparse with cosThStar w.r.t. production axis"}; Configurable activateTHnSparseCosThStarBeam{"activateTHnSparseCosThStarBeam", true, "Activate the THnSparse with cosThStar w.r.t. beam axis"}; Configurable activateTHnSparseCosThStarRandom{"activateTHnSparseCosThStarRandom", true, "Activate the THnSparse with cosThStar w.r.t. random axis"}; + Configurable activatePartRecoDstar{"activatePartRecoDstar", false, "Activate the study of partly reconstructed D*+ -> D0 (-> KPiPi0) Pi decays"}; + float minInvMass{0.f}; + float maxInvMass{1000.f}; + + /// table for Lc->pKpi background studies in MC + Configurable cosThStarAxisLcPKPiBkgMc{"cosThStarAxisLcPKPiBkgMc", 1, "cos(Theta*) axis for background studies (1 = helicity; 2 = production; 3 = beam; 4 = random)"}; + + /// veto conditions for Lc->pKpi analysis + struct : ConfigurableGroup { + Configurable applyLcBkgVeto{"applyLcBkgVeto", false, "Flag to enable the veto on D+ and Ds+ background for Lc->pKpi analysis"}; + /// background from D+->K-pi+pi+ + Configurable enableLcBkgVetoDplusKPiPi{"enableLcBkgVetoDplusKPiPi", false, "Flag to enable the veto on D+->K-pi+pi+ for Lc->pKpi analysis"}; + Configurable massDplusKPiPiMinVeto{"massDplusKPiPiMinVeto", 1.85, "Min. value for D+->K-pi+pi+ veto"}; + Configurable massDplusKPiPiMaxVeto{"massDplusKPiPiMaxVeto", 1.90, "Max. value for D+->K-pi+pi+ veto"}; + /// background from D+->K+K-pi+ + Configurable enableLcBkgVetoDplusKKPi{"enableLcBkgVetoDplusKKPi", false, "Flag to enable the veto on D+->K+K-pi+ for Lc->pKpi analysis"}; + Configurable massDplusKKPiMinVeto{"massDplusKKPiMinVeto", 1.85, "Min. value for D+->K+K-pi+ veto"}; // one can use also massDplusKPiPiMinVeto, but this allows more flexibility in analysis + Configurable massDplusKKPiMaxVeto{"massDplusKKPiMaxVeto", 1.90, "Max. value for D+->K+K-pi+ veto"}; // one can use also massDplusKPiPiMaxVeto, but this allows more flexibility in analysis + /// background from Ds+->K+K-pi+ + Configurable enableLcBkgVetoDsKKPi{"enableLcBkgVetoDsKKPi", false, "Flag to enable the veto on Ds+->K+K-pi+ for Lc->pKpi analysis"}; + Configurable massDsKKPiMinVeto{"massDsKKPiMinVeto", 1.94, "Min. value for Ds+->K+K-pi+ veto"}; + Configurable massDsKKPiMaxVeto{"massDsKKPiMaxVeto", 2.00, "Max. value for Ds+->K+K-pi+ veto"}; + } lcBkgVeto; + struct : ConfigurableGroup { + /// monitoring histograms (Dalitz plot) + Configurable activateTHnLcChannelMonitor{"activateTHnLcChannelMonitor", false, "Flag to switch on the monitoring THnSparse of M2(Kpi), M2(pK), M2(ppi), pt correlation for Lc -> pKpi"}; + ConfigurableAxis configThnAxisInvMass2KPiLcMonitoring{"configThnAxisInvMassKPiLcMonitoring", {200, 0.3f, 2.3f}, "#it{M}^{2}(K#pi) from #Lambda_{c}^{+} (GeV/#it{c}^{2})"}; + ConfigurableAxis configThnAxisInvMass2PKLcMonitoring{"configThnAxisInvMass2PKLcMonitoring", {320, 2.f, 5.2f}, "#it{M}^{2}(pK) from #Lambda_{c}^{+} (GeV/#it{c}^{2})"}; + ConfigurableAxis configThnAxisInvMass2PPiLcMonitoring{"configThnAxisInvMass2PPiLcMonitoring", {400, 1.f, 5.f}, "#it{M}^{2}(p#pi) from #Lambda_{c}^{+} (GeV/#it{c}^{2})"}; + + /// veto conditions on Lc->pKpi signals + Configurable applyLcSignalVeto{"applyLcSignalVeto", false, "Flag to enable the veto on Lc->pKpi resonant channels"}; + Configurable mass2PPiLcMinVeto{"mass2PPiLcMinVeto", 1.f, "Min. value for Delta++(<-Lc) mass veto"}; + Configurable mass2PPiLcMaxVeto{"mass2PPiLcMaxVeto", 1.6f, "Max. value for Delta++(<-Lc) mass veto"}; + + } lcPKPiChannels; + + /// Monitoring of phi Euler angle + Configurable activateTHnEulerPhiMonitor{"activateTHnEulerPhiMonitor", false, "Flag to switch on the monitoring THnSparse vs. Euler angle phi (Lc -> pKpi)"}; + ConfigurableAxis configTHnAxisEulerPhi{"configTHnAxisEulerPhi", {24, -o2::constants::math::PI, o2::constants::math::PI}, "Euler polar angle #phi"}; + + /// Application of rapidity cut for reconstructed candidates + Configurable rapidityCut{"rapidityCut", 999.f, "Max. value of reconstructed candidate rapidity (abs. value)"}; Filter filterSelectDstarCandidates = aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == selectionFlagDstarToD0Pi; Filter filterSelectLcToPKPiCandidates = (aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLcToPKPi) || (aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLcToPKPi); + using CollisionsWithMcLabels = soa::SmallGroups>; + using TracksWithMcLabels = soa::Join; + using TracksWithExtra = soa::Join; + + using McParticlesDstarMatched = soa::Join; + using McParticles3ProngMatched = soa::Join; + + using CandDstarWSelFlag = soa::Join; + using CandLcToPKPiWSelFlag = soa::Join; + + using FilteredCandDstarWSelFlag = soa::Filtered; + using FilteredCandDstarWSelFlagAndMl = soa::Filtered>; + using FilteredCandDstarWSelFlagAndMc = soa::Filtered>; + using FilteredCandDstarWSelFlagAndMcAndMl = soa::Filtered>; + + using FilteredCandLcToPKPiWSelFlag = soa::Filtered; + using FilteredCandLcToPKPiWSelFlagAndMl = soa::Filtered>; + using FilteredCandLcToPKPiWSelFlagAndMc = soa::Filtered>; + using FilteredCandLcToPKPiWSelFlagAndMcAndMl = soa::Filtered>; + + SliceCache cache; + Preslice dstarPerCollision = aod::hf_cand::collisionId; + Preslice dstarWithMlPerCollision = aod::hf_cand::collisionId; + Preslice dstarWithMcPerCollision = aod::hf_cand::collisionId; + Preslice dstarWithMcAndMlPerCollision = aod::hf_cand::collisionId; + + Preslice lcToPKPiPerCollision = aod::hf_cand::collisionId; + Preslice lcToPKPiWithMlPerCollision = aod::hf_cand::collisionId; + Preslice lcToPKPiWithMcPerCollision = aod::hf_cand::collisionId; + Preslice lcToPKPiWithMcAndMlPerCollision = aod::hf_cand::collisionId; + HfHelper hfHelper; HistogramRegistry registry{"registry", {}}; void init(InitContext&) { /// check process functions - std::array processes = {doprocessDstar, doprocessDstarWithMl, doprocessLcToPKPi, doprocessLcToPKPiWithMl, doprocessDstarMc, doprocessDstarMcWithMl, doprocessLcToPKPiMc, doprocessLcToPKPiMcWithMl}; + std::array processes = {doprocessDstar, doprocessDstarWithMl, doprocessLcToPKPi, doprocessLcToPKPiWithMl, doprocessDstarMc, doprocessDstarMcWithMl, doprocessLcToPKPiMc, doprocessLcToPKPiMcWithMl, doprocessLcToPKPiBackgroundMcWithMl}; const int nProcesses = std::accumulate(processes.begin(), processes.end(), 0); if (nProcesses > 1) { LOGP(fatal, "Only one process function should be enabled at a time, please check your configuration"); @@ -137,8 +264,12 @@ struct TaskPolarisationCharmHadrons { } } + if (activatePartRecoDstar && !(doprocessDstarMc || doprocessDstarMcWithMl)) { + LOGP(fatal, "Check on partly reconstructed D* mesons only possible for processDstarMc and processDstarMcWithMl"); + } + // check bkg rotation for MC (not supported currently) - if (nBkgRotations > 0 && (doprocessDstarMc || doprocessDstarMcWithMl || doprocessLcToPKPiMc || doprocessLcToPKPiMcWithMl)) { + if (nBkgRotations > 0 && (doprocessDstarMc || doprocessDstarMcWithMl || doprocessLcToPKPiMc || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl)) { LOGP(fatal, "No background rotation supported for MC."); } @@ -147,12 +278,12 @@ struct TaskPolarisationCharmHadrons { massKaon = o2::constants::physics::MassKaonCharged; massDstar = o2::constants::physics::MassDStar; massLc = o2::constants::physics::MassLambdaCPlus; - bkgRotationAngleStep = constants::math::TwoPI / (nBkgRotations + 1); // nBkgRotations==0: 2π (no rotation); nBkgRotations==1: π; nBkgRotations==2: 2π/3, 4π/3; ... + bkgRotationAngleStep = (nBkgRotations > 1) ? (maxRotAngleMultByPi - minRotAngleMultByPi) * constants::math::PI / (nBkgRotations - 1) : 0.; const AxisSpec thnAxisInvMass{configThnAxisInvMass, "#it{M} (GeV/#it{c}^{2})"}; const AxisSpec thnAxisInvMassD0{configThnAxisInvMassD0, "#it{M}(D^{0}) (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisInvMassKPiLc{configThnAxisInvMassKPiLc, "#it{M}(K#pi) from #Lambda_{c}^{+} (GeV/#it{c}^{2})"}; const AxisSpec thnAxisPt{configThnAxisPt, "#it{p}_{T} (GeV/#it{c})"}; - const AxisSpec thnAxisPz{configThnAxisPz, "#it{p}_{z} (GeV/#it{c})"}; const AxisSpec thnAxisY{configThnAxisY, "#it{y}"}; const AxisSpec thnAxisCosThetaStarHelicity{configThnAxisCosThetaStarHelicity, "cos(#vartheta_{helicity})"}; const AxisSpec thnAxisCosThetaStarProduction{configThnAxisCosThetaStarProduction, "cos(#vartheta_{production})"}; @@ -161,161 +292,277 @@ struct TaskPolarisationCharmHadrons { const AxisSpec thnAxisMlBkg{configThnAxisMlBkg, "ML bkg"}; const AxisSpec thnAxisMlNonPrompt{configThnAxisMlNonPrompt, "ML non-prompt"}; const AxisSpec thnAxisIsRotatedCandidate{2, -0.5f, 1.5f, "rotated bkg"}; + const AxisSpec thnAxisNumPvContributors{configThnAxisNumPvContributors, "num PV contributors"}; + const AxisSpec thnAxisPtB{configThnAxisPtB, "#it{p}_{T}(B mother) (GeV/#it{c})"}; + const AxisSpec thnAxisDausAcc{2, -0.5f, 1.5f, "daughters in acceptance"}; + const AxisSpec thnAxisDauToMuons{4, -0.5f, 3.5f, "daughters decayed to muons"}; + const AxisSpec thnAxisResoChannelLc{4, -0.5, 3.5, "0: direct 1,2,3: resonant"}; // 0: direct; 1: Λc± → p± K*; 2: Λc± → Δ(1232)±± K∓; 3: Λc± → Λ(1520) π± + const AxisSpec thnAxisAbsEtaTrackMin{configThnAxisAbsEtaTrackMin, "min |#it{#eta_{track}}|"}; + const AxisSpec thnAxisNumItsClsMin{configThnAxisNumItsClsMin, "min #it{N}_{cls ITS}"}; + const AxisSpec thnAxisNumTpcClsMin{configThnAxisNumTpcClsMin, "min #it{N}_{cls TPC}"}; + const AxisSpec thnAxisCharge{configThnAxisCharge, "charge"}; + const AxisSpec thnAxisInvMass2KPiLcMonitoring{lcPKPiChannels.configThnAxisInvMass2KPiLcMonitoring, "#it{M}^{2}(K#pi) from #Lambda_{c}^{+} (GeV/#it{c}^{2}"}; + const AxisSpec thnAxisInvMass2PKLcMonitoring{lcPKPiChannels.configThnAxisInvMass2PKLcMonitoring, "#it{M}^{2}(pK) from #Lambda_{c}^{+} (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisInvMass2PPiLcMonitoring{lcPKPiChannels.configThnAxisInvMass2PPiLcMonitoring, "#it{M}^{2}(p#pi) from #Lambda_{c}^{+} (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisTHnAxisEulerPhi{configTHnAxisEulerPhi, "Euler polar angle #phi"}; + + auto invMassBins = thnAxisInvMass.binEdges; + minInvMass = invMassBins.front(); + maxInvMass = invMassBins.back(); + + registry.add("hNumPvContributorsAll", "Number of PV contributors for all events ;num. PV contributors; counts", HistType::kTH1F, {thnAxisNumPvContributors}); + registry.add("hNumPvContributorsCand", "Number of PV contributors for events with candidates;num. PV contributors; counts", HistType::kTH1F, {thnAxisNumPvContributors}); + registry.add("hNumPvContributorsCandInMass", "Number of PV contributors for events with candidates in the signal region;num. PV contributors; counts", HistType::kTH1F, {thnAxisNumPvContributors}); if (doprocessDstarWithMl || doprocessDstarMcWithMl) { /// analysis for D*+ meson with ML, w/o rot. background axis if (doprocessDstarWithMl) { if (activateTHnSparseCosThStarHelicity) { - registry.add("hHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarHelicity, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisIsRotatedCandidate}); + registry.add("hHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarHelicity, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate}); } if (activateTHnSparseCosThStarProduction) { - registry.add("hProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisIsRotatedCandidate}); + registry.add("hProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate}); } if (activateTHnSparseCosThStarBeam) { - registry.add("hBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarBeam, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisIsRotatedCandidate}); + registry.add("hBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarBeam, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate}); } if (activateTHnSparseCosThStarRandom) { - registry.add("hRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarRandom, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisIsRotatedCandidate}); + registry.add("hRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarRandom, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate}); } } else { if (activateTHnSparseCosThStarHelicity) { - registry.add("hRecoPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarHelicity, thnAxisMlBkg, thnAxisMlNonPrompt}); - registry.add("hRecoNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarHelicity, thnAxisMlBkg, thnAxisMlNonPrompt}); + registry.add("hRecoPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarHelicity, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons}); + registry.add("hRecoNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarHelicity, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons, thnAxisPtB}); + if (activatePartRecoDstar) { + registry.add("hPartRecoPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores -- partially reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarHelicity, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons}); + registry.add("hPartRecoNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores -- partially reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarHelicity, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons, thnAxisPtB}); + } } if (activateTHnSparseCosThStarProduction) { - registry.add("hRecoPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction, thnAxisMlBkg, thnAxisMlNonPrompt}); - registry.add("hRecoNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction, thnAxisMlBkg, thnAxisMlNonPrompt}); + registry.add("hRecoPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons}); + registry.add("hRecoNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons, thnAxisPtB}); + if (activatePartRecoDstar) { + registry.add("hPartRecoPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores -- partially reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons}); + registry.add("hPartRecoNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores -- partially reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons, thnAxisPtB}); + } } if (activateTHnSparseCosThStarBeam) { - registry.add("hRecoPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarBeam, thnAxisMlBkg, thnAxisMlNonPrompt}); - registry.add("hRecoNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarBeam, thnAxisMlBkg, thnAxisMlNonPrompt}); + registry.add("hRecoPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarBeam, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons}); + registry.add("hRecoNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarBeam, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons, thnAxisPtB}); + if (activatePartRecoDstar) { + registry.add("hPartRecoPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores -- partially reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarBeam, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons}); + registry.add("hPartRecoNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores -- partially reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarBeam, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons, thnAxisPtB}); + } } if (activateTHnSparseCosThStarRandom) { - registry.add("hRecoPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarRandom, thnAxisMlBkg, thnAxisMlNonPrompt}); - registry.add("hRecoNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarRandom, thnAxisMlBkg, thnAxisMlNonPrompt}); + registry.add("hRecoPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarRandom, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons}); + registry.add("hRecoNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarRandom, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons, thnAxisPtB}); + if (activatePartRecoDstar) { + registry.add("hPartRecoPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores -- partially reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarRandom, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons}); + registry.add("hPartRecoNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores -- partially reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarRandom, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons, thnAxisPtB}); + } } } - } else if (doprocessLcToPKPiWithMl || doprocessLcToPKPiMcWithMl) { + } else if (doprocessLcToPKPiWithMl || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { /// analysis for Lc+ baryon with ML, w/ rot. background axis (for data only) if (doprocessLcToPKPiWithMl) { if (activateTHnSparseCosThStarHelicity) { - registry.add("hHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarHelicity, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisIsRotatedCandidate}); + registry.add("hHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarHelicity, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + if (activateTHnEulerPhiMonitor) { + registry.add("hEulerPhiHelicity", "THn for polarisation studies with Euler phi w.r.t. helicity axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisCharge}); + } } if (activateTHnSparseCosThStarProduction) { - registry.add("hProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarProduction, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisIsRotatedCandidate}); + registry.add("hProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarProduction, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + if (activateTHnEulerPhiMonitor) { + registry.add("hEulerPhiProduction", "THn for polarisation studies with Euler phi w.r.t. production axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisCharge}); + } } if (activateTHnSparseCosThStarBeam) { - registry.add("hBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarBeam, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisIsRotatedCandidate}); + registry.add("hBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarBeam, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + if (activateTHnEulerPhiMonitor) { + registry.add("hEulerPhiBeam", "THn for polarisation studies with Euler phi w.r.t. beam axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisCharge}); + } } if (activateTHnSparseCosThStarRandom) { - registry.add("hRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarRandom, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisIsRotatedCandidate}); + registry.add("hRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarRandom, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); } } else { if (activateTHnSparseCosThStarHelicity) { - registry.add("hRecoPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarHelicity, thnAxisMlBkg, thnAxisMlNonPrompt}); - registry.add("hRecoNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarHelicity, thnAxisMlBkg, thnAxisMlNonPrompt}); + registry.add("hRecoPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarHelicity, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisCharge}); + registry.add("hRecoNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarHelicity, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisCharge}); + if (activateTHnEulerPhiMonitor) { + registry.add("hRecPromptEulerPhiHelicity", "THn for polarisation studies with Euler phi w.r.t. helicity axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc, thnAxisCharge}); + registry.add("hRecNonPromptEulerPhiHelicity", "THn for polarisation studies with Euler phi w.r.t. helicity axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc, thnAxisCharge}); + } } if (activateTHnSparseCosThStarProduction) { - registry.add("hRecoPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarProduction, thnAxisMlBkg, thnAxisMlNonPrompt}); - registry.add("hRecoNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarProduction, thnAxisMlBkg, thnAxisMlNonPrompt}); + registry.add("hRecoPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarProduction, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisCharge}); + registry.add("hRecoNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarProduction, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisCharge}); + if (activateTHnEulerPhiMonitor) { + registry.add("hRecPromptEulerPhiProduction", "THn for polarisation studies with Euler phi w.r.t. production axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc, thnAxisCharge}); + registry.add("hRecNonPromptEulerPhiProduction", "THn for polarisation studies with Euler phi w.r.t. production axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc, thnAxisCharge}); + } } if (activateTHnSparseCosThStarBeam) { - registry.add("hRecoPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarBeam, thnAxisMlBkg, thnAxisMlNonPrompt}); - registry.add("hRecoNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarBeam, thnAxisMlBkg, thnAxisMlNonPrompt}); + registry.add("hRecoPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarBeam, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisCharge}); + registry.add("hRecoNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarBeam, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisCharge}); + if (activateTHnEulerPhiMonitor) { + registry.add("hRecPromptEulerPhiBeam", "THn for polarisation studies with Euler phi w.r.t. beam axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc, thnAxisCharge}); + registry.add("hRecNonPromptEulerPhiBeam", "THn for polarisation studies with Euler phi w.r.t. beam axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc, thnAxisCharge}); + } } if (activateTHnSparseCosThStarRandom) { - registry.add("hRecoPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarRandom, thnAxisMlBkg, thnAxisMlNonPrompt}); - registry.add("hRecoNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarRandom, thnAxisMlBkg, thnAxisMlNonPrompt}); + registry.add("hRecoPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarRandom, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisCharge}); + registry.add("hRecoNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarRandom, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisCharge}); } } } else if (doprocessDstar || doprocessDstarMc) { /// analysis for D*+ meson, w/o rot. background axis if (doprocessDstar) { if (activateTHnSparseCosThStarHelicity) { - registry.add("hHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarHelicity, thnAxisIsRotatedCandidate}); + registry.add("hHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarHelicity, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate}); } if (activateTHnSparseCosThStarProduction) { - registry.add("hProduction", "THn for polarisation studies with cosThStar w.r.t. production axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction, thnAxisIsRotatedCandidate}); + registry.add("hProduction", "THn for polarisation studies with cosThStar w.r.t. production axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate}); } if (activateTHnSparseCosThStarBeam) { - registry.add("hBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarBeam, thnAxisIsRotatedCandidate}); + registry.add("hBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarBeam, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate}); } if (activateTHnSparseCosThStarRandom) { - registry.add("hRandom", "THn for polarisation studies with cosThStar w.r.t. random axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarRandom, thnAxisIsRotatedCandidate}); + registry.add("hRandom", "THn for polarisation studies with cosThStar w.r.t. random axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarRandom, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate}); } } else { if (activateTHnSparseCosThStarHelicity) { - registry.add("hRecoPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarHelicity}); - registry.add("hRecoNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarHelicity}); + registry.add("hRecoPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarHelicity, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons}); + registry.add("hRecoNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarHelicity, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons, thnAxisPtB}); + if (activatePartRecoDstar) { + registry.add("hPartRecoPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis -- partially reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarHelicity, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons}); + registry.add("hPartRecoNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis -- partially reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarHelicity, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons, thnAxisPtB}); + } } if (activateTHnSparseCosThStarProduction) { - registry.add("hRecoPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction}); - registry.add("hRecoNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction}); + registry.add("hRecoPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons}); + registry.add("hRecoNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons, thnAxisPtB}); + if (activatePartRecoDstar) { + registry.add("hPartRecoPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis -- partially reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons}); + registry.add("hPartRecoNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis -- partially reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons, thnAxisPtB}); + } } if (activateTHnSparseCosThStarBeam) { - registry.add("hRecoPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarBeam}); - registry.add("hRecoNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarBeam}); + registry.add("hRecoPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarBeam, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons}); + registry.add("hRecoNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarBeam, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons, thnAxisPtB}); + if (activatePartRecoDstar) { + registry.add("hPartRecoPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis -- partially reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarBeam, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons}); + registry.add("hPartRecoNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis -- partially reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarBeam, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons, thnAxisPtB}); + } } if (activateTHnSparseCosThStarRandom) { - registry.add("hRecoPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarRandom}); - registry.add("hRecoNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarRandom}); + registry.add("hRecoPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarRandom, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons}); + registry.add("hRecoNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarRandom, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons, thnAxisPtB}); + if (activatePartRecoDstar) { + registry.add("hPartRecoPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis -- partially reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarRandom, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons}); + registry.add("hPartRecoNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis -- partially reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarRandom, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisDauToMuons, thnAxisPtB}); + } } } } else if (doprocessLcToPKPi || doprocessLcToPKPiMc) { /// analysis for Lc+ baryon, rot. background axis (for data only) if (doprocessLcToPKPi) { if (activateTHnSparseCosThStarHelicity) { - registry.add("hHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarHelicity, thnAxisIsRotatedCandidate}); + registry.add("hHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarHelicity, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + if (activateTHnEulerPhiMonitor) { + registry.add("hEulerPhiHelicity", "THn for polarisation studies with Euler phi w.r.t. helicity axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisCharge}); + } } if (activateTHnSparseCosThStarProduction) { - registry.add("hProduction", "THn for polarisation studies with cosThStar w.r.t. production axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarProduction, thnAxisIsRotatedCandidate}); + registry.add("hProduction", "THn for polarisation studies with cosThStar w.r.t. production axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarProduction, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + if (activateTHnEulerPhiMonitor) { + registry.add("hEulerPhiProduction", "THn for polarisation studies with Euler phi w.r.t. helicity axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisCharge}); + } } if (activateTHnSparseCosThStarBeam) { - registry.add("hBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarBeam, thnAxisIsRotatedCandidate}); + registry.add("hBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarBeam, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + if (activateTHnEulerPhiMonitor) { + registry.add("hEulerPhiBeam", "THn for polarisation studies with Euler phi w.r.t. beam axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisCharge}); + } } if (activateTHnSparseCosThStarRandom) { - registry.add("hRandom", "THn for polarisation studies with cosThStar w.r.t. random axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarRandom, thnAxisIsRotatedCandidate}); + registry.add("hRandom", "THn for polarisation studies with cosThStar w.r.t. random axis", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarRandom, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); } } else { if (activateTHnSparseCosThStarHelicity) { - registry.add("hRecoPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarHelicity}); - registry.add("hRecoNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarHelicity}); + registry.add("hRecoPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarHelicity, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + registry.add("hRecoNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarHelicity, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + if (activateTHnEulerPhiMonitor) { + registry.add("hRecPromptEulerPhiHelicity", "THn for polarisation studies with Euler phi w.r.t. helicity axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisResoChannelLc, thnAxisCharge}); + registry.add("hRecNonPromptEulerPhiHelicity", "THn for polarisation studies with Euler phi w.r.t. helicity axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisResoChannelLc, thnAxisCharge}); + } } if (activateTHnSparseCosThStarProduction) { - registry.add("hRecoPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarProduction}); - registry.add("hRecoNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarProduction}); + registry.add("hRecoPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarProduction, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + registry.add("hRecoNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarProduction, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + if (activateTHnEulerPhiMonitor) { + registry.add("hRecPromptEulerPhiProduction", "THn for polarisation studies with Euler phi w.r.t. production axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisResoChannelLc, thnAxisCharge}); + registry.add("hRecNonPromptEulerPhiProduction", "THn for polarisation studies with Euler phi w.r.t. production axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisResoChannelLc, thnAxisCharge}); + } } if (activateTHnSparseCosThStarBeam) { - registry.add("hRecoPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarBeam}); - registry.add("hRecoNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarBeam}); + registry.add("hRecoPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarBeam, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + registry.add("hRecoNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarBeam, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + if (activateTHnEulerPhiMonitor) { + registry.add("hRecPromptEulerPhiBeam", "THn for polarisation studies with Euler phi w.r.t. beam axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisResoChannelLc, thnAxisCharge}); + registry.add("hRecNonPromptEulerPhiBeam", "THn for polarisation studies with Euler phi w.r.t. beam axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi, thnAxisResoChannelLc, thnAxisCharge}); + } } if (activateTHnSparseCosThStarRandom) { - registry.add("hRecoPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarRandom}); - registry.add("hRecoNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarRandom}); + registry.add("hRecoPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis -- reco prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarRandom, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + registry.add("hRecoNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis -- reco non-prompt signal", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarRandom, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); } } } // MC Gen histos - if (doprocessDstarMc || doprocessDstarMcWithMl || doprocessLcToPKPiMc || doprocessLcToPKPiMcWithMl) { + if (doprocessDstarMc || doprocessDstarMcWithMl || doprocessLcToPKPiMc || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { if (activateTHnSparseCosThStarHelicity) { - registry.add("hGenPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis -- gen prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarHelicity}); - registry.add("hGenNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis -- gen non-prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarHelicity}); + registry.add("hGenPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis -- gen prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarHelicity, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}); + registry.add("hGenNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis -- gen non-prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarHelicity, thnAxisPtB, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}); + if (activatePartRecoDstar && (doprocessDstarMc || doprocessDstarMcWithMl)) { + registry.add("hGenPartRecoPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis -- gen prompt partly reco signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarHelicity, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}); + registry.add("hGenPartRecoNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis -- gen non-prompt partly reco signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarHelicity, thnAxisPtB, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}); + } } if (activateTHnSparseCosThStarProduction) { - registry.add("hGenPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis -- gen prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarProduction}); - registry.add("hGenNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis -- gen non-prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarProduction}); + registry.add("hGenPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis -- gen prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarProduction, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}); + registry.add("hGenNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis -- gen non-prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarProduction, thnAxisPtB, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}); + if (activatePartRecoDstar && (doprocessDstarMc || doprocessDstarMcWithMl)) { + registry.add("hGenPartRecoPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis -- gen partly reco prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarProduction, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}); + registry.add("hGenPartRecoNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis -- gen partly reco non-prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarProduction, thnAxisPtB, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}); + } } if (activateTHnSparseCosThStarBeam) { - registry.add("hGenPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis -- gen prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarBeam}); - registry.add("hGenNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis -- gen non-prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarBeam}); + registry.add("hGenPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis -- gen prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarBeam, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}); + registry.add("hGenNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis -- gen non-prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarBeam, thnAxisPtB, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}); + if (activatePartRecoDstar && (doprocessDstarMc || doprocessDstarMcWithMl)) { + registry.add("hGenPartRecoPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis -- gen partly reco prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarBeam, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}); + registry.add("hGenPartRecoNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis -- gen partly reco non-prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarBeam, thnAxisPtB, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}); + } } if (activateTHnSparseCosThStarRandom) { - registry.add("hGenPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis -- gen prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarRandom}); - registry.add("hGenNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis -- gen non-prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisPz, thnAxisY, thnAxisCosThetaStarRandom}); + registry.add("hGenPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis -- gen prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarRandom, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}); + registry.add("hGenNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis -- gen non-prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarRandom, thnAxisPtB, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}); + if (activatePartRecoDstar && (doprocessDstarMc || doprocessDstarMcWithMl)) { + registry.add("hGenPartRecoPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis -- gen partly reco prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarRandom, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}); + registry.add("hGenPartRecoNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis -- gen partly reco non-prompt signal", HistType::kTHnSparseF, {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarRandom, thnAxisPtB, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}); + } } } + /// control plots for Lc->pKPi + if ((doprocessLcToPKPi || doprocessLcToPKPiWithMl || doprocessLcToPKPiMc || doprocessLcToPKPiMcWithMl) && lcPKPiChannels.activateTHnLcChannelMonitor) { + registry.add("hMass2PairsLcPKPi", "THnSparse to monitor M2(Kpi), M2(pK), M2(ppi), pt correlation for Lc -> pKpi", HistType::kTHnSparseF, {thnAxisInvMass2KPiLcMonitoring, thnAxisInvMass2PKLcMonitoring, thnAxisInvMass2PPiLcMonitoring, thnAxisPt}); + } + // inv. mass hypothesis to loop over // e.g.: Lc->pKpi has the ambiguity pKpi vs. piKp if (doprocessLcToPKPi || doprocessLcToPKPiWithMl) { @@ -329,58 +576,103 @@ struct TaskPolarisationCharmHadrons { /// \param invMassCharmHad is the invariant-mass of the candidate /// \param ptCharmHad is the pt of the candidate - /// \param pzCharmHad is the pz of the candidate + /// \param numPvContributors is the number of PV contributors /// \param rapCharmHad is the rapidity of the candidate /// \param invMassD0 is the invariant-mass of the D0 daugher (only for D*+) + /// \param invMassKPiLc is the invariant-mass of the K-pi pair (only for Lc+) + /// \param invMassPKLc is the invariant-mass of the p-K pair (only for Lc+) + /// \param invMassPPiLc is the invariant-mass of the p-pi pair (only for Lc+) /// \param cosThetaStar is the cosThetaStar of the candidate /// \param outputMl is the array with ML output scores /// \param isRotatedCandidate is a flag that keeps the info of the rotation of the candidate for bkg studies /// \param origin is the MC origin + /// \param ptBhadMother is the pt of the b-hadron mother (only in case of non-prompt) + /// \param resoChannelLc indicates the Lc decay channel (direct, resonant) + /// \param absEtaMin is the minimum absolute eta of the daughter tracks + /// \param numItsClsMin is the minimum number of ITS clusters of the daughter tracks + /// \param numTpcClsMin is the minimum number of TPC clusters of the daughter tracks + /// \param charge is the charge of the hadron + /// \param nMuons is the number of muons from daughter decays + /// \param isPartRecoDstar is a flag indicating if it is a partly reconstructed Dstar meson (MC only) template - void fillRecoHistos(float invMassCharmHad, float ptCharmHad, float pzCharmHad, float rapCharmHad, float invMassD0, float cosThetaStar, std::array outputMl, int isRotatedCandidate, int8_t origin) + void fillRecoHistos(float invMassCharmHad, float ptCharmHad, int numPvContributors, float rapCharmHad, float invMassD0, float invMassKPiLc, float cosThetaStar, float phiEuler, std::array outputMl, int isRotatedCandidate, int8_t origin, float ptBhadMother, int8_t resoChannelLc, float absEtaMin, int numItsClsMin, int numTpcClsMin, int8_t charge, int8_t nMuons, bool isPartRecoDstar) { if constexpr (cosThetaStarType == charm_polarisation::CosThetaStarType::Helicity) { // Helicity if constexpr (!doMc) { // data if constexpr (withMl) { // with ML if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hHelicity"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], isRotatedCandidate); + registry.fill(HIST("hHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hHelicity"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], isRotatedCandidate); + registry.fill(HIST("hHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hEulerPhiHelicity"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, outputMl[0], /*outputMl[1],*/ outputMl[2], charge); + } } } else { // without ML if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hHelicity"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar, isRotatedCandidate); + registry.fill(HIST("hHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hHelicity"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar, isRotatedCandidate); + registry.fill(HIST("hHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hEulerPhiHelicity"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, charge); + } } } } else { // MC --> no distinction among channels, since rotational bkg not supported if constexpr (withMl) { // with ML if (origin == RecoDecay::OriginType::Prompt) { // prompt if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } else { + registry.fill(HIST("hPartRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hRecPromptEulerPhiHelicity"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, charge); + } } } else { // non-prompt if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } else { + registry.fill(HIST("hPartRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hRecNonPromptEulerPhiHelicity"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, charge); + } } } } else { // without ML if (origin == RecoDecay::OriginType::Prompt) { // prompt if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar); + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } else { + registry.fill(HIST("hPartRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar); + registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hRecPromptEulerPhiHelicity"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, resoChannelLc, charge); + } } } else { // non-prompt if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar); + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } else { + registry.fill(HIST("hPartRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar); + registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hRecNonPromptEulerPhiHelicity"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, resoChannelLc, charge); + } } } } @@ -389,44 +681,78 @@ struct TaskPolarisationCharmHadrons { if constexpr (!doMc) { // data if constexpr (withMl) { // with ML if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], isRotatedCandidate); + registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], isRotatedCandidate); + registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hEulerPhiProduction"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, outputMl[0], /*outputMl[1],*/ outputMl[2], charge); + } } } else { // without ML if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar, isRotatedCandidate); + registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar, isRotatedCandidate); + registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hEulerPhiProduction"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, charge); + } } } } else { // MC --> no distinction among channels, since rotational bkg not supported if constexpr (withMl) { // with ML if (origin == RecoDecay::OriginType::Prompt) { // prompt if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } else { + registry.fill(HIST("hPartRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hRecPromptEulerPhiProduction"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, charge); + } } } else { // non-prompt if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } else { + registry.fill(HIST("hPartRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hRecNonPromptEulerPhiProduction"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, charge); + } } } } else { // without ML if (origin == RecoDecay::OriginType::Prompt) { // prompt if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar); + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } else { + registry.fill(HIST("hPartRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar); + registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hRecPromptEulerPhiProduction"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, resoChannelLc, charge); + } } } else { // non-prompt if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar); + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } else { + registry.fill(HIST("hPartRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar); + registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hRecNonPromptEulerPhiProduction"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, resoChannelLc, charge); + } } } } @@ -435,44 +761,78 @@ struct TaskPolarisationCharmHadrons { if constexpr (!doMc) { // data if constexpr (withMl) { // with ML if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], isRotatedCandidate); + registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], isRotatedCandidate); + registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hEulerPhiBeam"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, outputMl[0], /*outputMl[1],*/ outputMl[2], charge); + } } } else { // without ML if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar, isRotatedCandidate); + registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar, isRotatedCandidate); + registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hEulerPhiBeam"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, charge); + } } } } else { // MC --> no distinction among channels, since rotational bkg not supported if constexpr (withMl) { // with ML if (origin == RecoDecay::OriginType::Prompt) { // prompt if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } else { + registry.fill(HIST("hPartRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hRecPromptEulerPhiBeam"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, charge); + } } } else { // non-prompt if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } else { + registry.fill(HIST("hPartRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hRecNonPromptEulerPhiBeam"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, charge); + } } } } else { // without ML if (origin == RecoDecay::OriginType::Prompt) { // prompt if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar); + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } else { + registry.fill(HIST("hPartRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar); + registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hRecPromptEulerPhiBeam"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, resoChannelLc, charge); + } } } else { // non-prompt if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar); + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } else { + registry.fill(HIST("hPartRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar); + registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + if (activateTHnEulerPhiMonitor) { + registry.fill(HIST("hRecNonPromptEulerPhiBeam"), invMassCharmHad, ptCharmHad, invMassKPiLc, phiEuler, resoChannelLc, charge); + } } } } @@ -481,44 +841,60 @@ struct TaskPolarisationCharmHadrons { if constexpr (!doMc) { // data if constexpr (withMl) { // with ML if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], isRotatedCandidate); + registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], isRotatedCandidate); + registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate, charge); } } else { // without ML if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar, isRotatedCandidate); + registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar, isRotatedCandidate); + registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassKPiLc, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate, charge); } } } else { // MC --> no distinction among channels, since rotational bkg not supported if constexpr (withMl) { // with ML if (origin == RecoDecay::OriginType::Prompt) { // prompt if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } else { + registry.fill(HIST("hPartRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); } } else { // non-prompt if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } else { + registry.fill(HIST("hPartRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); } } } else { // without ML if (origin == RecoDecay::OriginType::Prompt) { // prompt if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar); + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } else { + registry.fill(HIST("hPartRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar); + registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); } } else { // non-prompt if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, invMassD0, cosThetaStar); + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } else { + registry.fill(HIST("hPartRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar); + registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); } } } @@ -527,63 +903,227 @@ struct TaskPolarisationCharmHadrons { } /// \param ptCharmHad is the pt of the particle - /// \param pzCharmHad is the pz of the particle + /// \param numPvContributors is the number of PV contributors /// \param rapCharmHad is the rapidity of the particle /// \param cosThetaStar is the cosThetaStar of the particle /// \param origin is the MC origin + /// \param ptBhadMother is the pt of the b-hadron mother (only in case of non-prompt) + /// \param areDausInAcc is a flag indicating whether the daughters are in acceptance or not + /// \param resoChannelLc indicates the Lc decay channel (direct, resonant) + /// \param isPartRecoDstar is a flag indicating if it is a partly reconstructed Dstar->D0pi->Kpipipi0 meson (MC only) template - void fillGenHistos(float ptCharmHad, float pzCharmHad, float rapCharmHad, float cosThetaStar, int8_t origin) + void fillGenHistos(float ptCharmHad, int numPvContributors, float rapCharmHad, float cosThetaStar, int8_t origin, float ptBhadMother, bool areDausInAcc, uint8_t resoChannelLc, int8_t charge, bool isPartRecoDstar) { if constexpr (cosThetaStarType == charm_polarisation::CosThetaStarType::Helicity) { // Helicity if (origin == RecoDecay::OriginType::Prompt) { // prompt - registry.fill(HIST("hGenPromptHelicity"), ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar); + if (!isPartRecoDstar) { + registry.fill(HIST("hGenPromptHelicity"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + } else { + registry.fill(HIST("hGenPartRecoPromptHelicity"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + } } else { // non-prompt - registry.fill(HIST("hGenNonPromptHelicity"), ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar); + if (!isPartRecoDstar) { + registry.fill(HIST("hGenNonPromptHelicity"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + } else { + registry.fill(HIST("hGenPartRecoNonPromptHelicity"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + } } } else if constexpr (cosThetaStarType == charm_polarisation::CosThetaStarType::Production) { // Production if (origin == RecoDecay::OriginType::Prompt) { // prompt - registry.fill(HIST("hGenPromptProduction"), ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar); + if (!isPartRecoDstar) { + registry.fill(HIST("hGenPromptProduction"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + } else { + registry.fill(HIST("hGenPartRecoPromptProduction"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + } } else { // non-prompt - registry.fill(HIST("hGenNonPromptProduction"), ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar); + if (!isPartRecoDstar) { + registry.fill(HIST("hGenNonPromptProduction"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + } else { + registry.fill(HIST("hGenPartRecoNonPromptProduction"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + } } } else if constexpr (cosThetaStarType == charm_polarisation::CosThetaStarType::Beam) { // Beam if (origin == RecoDecay::OriginType::Prompt) { // prompt - registry.fill(HIST("hGenPromptBeam"), ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar); + if (!isPartRecoDstar) { + registry.fill(HIST("hGenPromptBeam"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + } else { + registry.fill(HIST("hGenPartRecoPromptBeam"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + } } else { // non-prompt - registry.fill(HIST("hGenNonPromptBeam"), ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar); + if (!isPartRecoDstar) { + registry.fill(HIST("hGenNonPromptBeam"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + } else { + registry.fill(HIST("hGenPartRecoNonPromptBeam"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + } } } else if constexpr (cosThetaStarType == charm_polarisation::CosThetaStarType::Random) { // Random if (origin == RecoDecay::OriginType::Prompt) { // prompt - registry.fill(HIST("hGenPromptRandom"), ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar); + if (!isPartRecoDstar) { + registry.fill(HIST("hGenPromptRandom"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + } else { + registry.fill(HIST("hGenPartRecoPromptRandom"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + } } else { // non-prompt - registry.fill(HIST("hGenNonPromptRandom"), ptCharmHad, pzCharmHad, rapCharmHad, cosThetaStar); + if (!isPartRecoDstar) { + registry.fill(HIST("hGenNonPromptRandom"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + } else { + registry.fill(HIST("hGenPartRecoNonPromptRandom"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + } + } + } + } + + /// \param numPvContributors is the number of PV contributors + /// \param nCands is the number of candidates associated to a collision + /// \param nCandsInMass is the number of candidates in the signal mass region associated to a colslision + void fillMultHistos(int numPvContributors, int nCands, int nCandsInMass) + { + registry.fill(HIST("hNumPvContributorsAll"), numPvContributors); + if (nCands > 0) { + registry.fill(HIST("hNumPvContributorsCand"), numPvContributors); + } + if (nCandsInMass > 0) { + registry.fill(HIST("hNumPvContributorsCandInMass"), numPvContributors); + } + } + + /// \param invMass is the invariant mass + /// \return true if candidate in signal region + template + bool isInSignalRegion(float invMass) + { + if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (0.142f < invMass && invMass < 0.15f) { + return true; + } + } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ (to be tuned!) + if (2.25f < invMass && invMass < 2.35f) { + return true; + } + } + + return false; + } + + /// \param daughter is the daughter particle + /// \param ptMin is the minimum pt + /// \param etaMax is the maximum eta + /// \return true if daughter is in acceptance + template + bool isDaughterInAcceptance(Part const& daughter, float ptMin, float etaMax) + { + if (daughter.pt() < ptMin) { + return false; + } + if (std::abs(daughter.eta()) > etaMax) { + return false; + } + + return true; + } + + /// \param prongTrack is the track we want to find the mother of + /// \param idMothers is the vector containing the mother IDs + /// \param particles are the MC particles + template + void searchFirstLevelMother(Trk const& prongTrack, std::vector& idMothers, Part const& /*particles*/) + { + /// particle associated to the prong track + if (!prongTrack.has_mcParticle()) { + return; + } + auto prongParticle = prongTrack.template mcParticle_as(); + /// leave the vector of mother indices empty if the currect paticle has no mothers + if (!prongParticle.has_mothers()) { + return; + } + // loop over the mother particles of the analysed particle + for (auto iMother = prongParticle.mothersIds().front(); iMother <= prongParticle.mothersIds().back(); ++iMother) { + idMothers.push_back(iMother); + break; // we keep only the first one + } + }; + + /// prongTracks is the vector of daughter tracks + /// etaMin is the minimum eta + /// nItsClsMin is the minumum number of clusters in ITS + /// nTpcClsMin is the minumum number of clusters in TPC + template + void getTrackingInfos(std::vector const& prongTracks, float& etaMin, int& nItsClsMin, int& nTpcClsMin) + { + etaMin = 10.f; + nItsClsMin = 10; + nTpcClsMin = 1000; + + for (const auto& track : prongTracks) { + if (std::abs(track.eta()) < etaMin) { + etaMin = std::abs(track.eta()); + } + if (track.itsNCls() < nItsClsMin) { + nItsClsMin = track.itsNCls(); + } + if (track.tpcNClsCrossedRows() < nTpcClsMin) { + nTpcClsMin = track.tpcNClsCrossedRows(); } } } /// \param candidates are the selected candidates /// \param bkgRotationId is the id for the background rotation - template - void runPolarisationAnalysis(Cand const& candidate, int bkgRotationId = 0) + /// \param numPvContributors is the number of PV contributors + /// \param particles are the generated particles + /// \param tracks are the reconstructed tracks + /// \return true if candidate in signal region + template + bool runPolarisationAnalysis(Cand const& candidate, int bkgRotationId, int numPvContributors, Part const& particles, Trk const& /*tracks*/) { + bool isCandidateInSignalRegion{false}; int8_t origin{RecoDecay::OriginType::None}; int8_t massHypoMcTruth{-1}; + float ptBhadMother{-1.f}; + int8_t resoChannelLc = -1; + int8_t charge = -99; + bool partRecoDstar{false}; if constexpr (doMc) { if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { - if (!TESTBIT(std::abs(candidate.flagMcMatchRec()), aod::hf_cand_dstar::DecayType::DstarToD0Pi)) { // this candidate is not signal, skip - return; + partRecoDstar = TESTBIT(std::abs(candidate.flagMcMatchRec()), aod::hf_cand_dstar::DecayType::DstarToD0PiPi0) && TESTBIT(std::abs(candidate.flagMcMatchRecD0()), aod::hf_cand_dstar::DecayType::D0ToPiKPi0); + bool signalDstar = TESTBIT(std::abs(candidate.flagMcMatchRec()), aod::hf_cand_dstar::DecayType::DstarToD0Pi) && TESTBIT(std::abs(candidate.flagMcMatchRecD0()), aod::hf_cand_dstar::DecayType::D0ToPiK); + if (!signalDstar && (!partRecoDstar || !activatePartRecoDstar)) { // this candidate is not signal and not partially reconstructed signal, skip + return isCandidateInSignalRegion; } origin = candidate.originMcRec(); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { - if (!TESTBIT(std::abs(candidate.flagMcMatchRec()), aod::hf_cand_3prong::DecayType::LcToPKPi)) { // this candidate is not signal, skip - return; + ptBhadMother = candidate.ptBhadMotherPart(); + int pdgBhadMother = candidate.pdgBhadMotherPart(); + // For unknown reasons there are charm hadrons coming directly from beauty diquarks without an intermediate B-hadron which have an unreasonable correlation between the pT of the charm hadron and the beauty mother. We also remove charm hadrons from quarkonia. + if (origin == RecoDecay::OriginType::NonPrompt && (pdgBhadMother == 5101 || pdgBhadMother == 5103 || pdgBhadMother == 5201 || pdgBhadMother == 5203 || pdgBhadMother == 5301 || pdgBhadMother == 5303 || pdgBhadMother == 5401 || pdgBhadMother == 5403 || pdgBhadMother == 5503 || pdgBhadMother == 553 || pdgBhadMother == 555 || pdgBhadMother == 553 || pdgBhadMother == 557)) { + return isCandidateInSignalRegion; } - origin = candidate.originMcRec(); - if (candidate.isCandidateSwapped()) { - massHypoMcTruth = charm_polarisation::MassHyposLcToPKPi::PiKP; - } else { - massHypoMcTruth = charm_polarisation::MassHyposLcToPKPi::PKPi; + } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { + if constexpr (!studyLcPKPiBkgMc) { // skip this if studyLcPKPiBkgMc is true, since we are interested in background + if (!TESTBIT(std::abs(candidate.flagMcMatchRec()), aod::hf_cand_3prong::DecayType::LcToPKPi)) { // this candidate is not signal, skip + return isCandidateInSignalRegion; + } + origin = candidate.originMcRec(); + if (candidate.isCandidateSwapped()) { + massHypoMcTruth = charm_polarisation::MassHyposLcToPKPi::PiKP; + } else { + massHypoMcTruth = charm_polarisation::MassHyposLcToPKPi::PKPi; + } + resoChannelLc = candidate.flagMcDecayChanRec(); /// 0: direct; 1: Λc± → p± K*; 2: Λc± → Δ(1232)±± K∓; 3: Λc± → Λ(1520) π± } + + /// Lc electric charge from MC truth + /// This is checked when the reconstructed 3-prong candidate is matched to MC with RecoDecay::getMatchedMCRec + int8_t flagMc = candidate.flagMcMatchRec(); + charge = std::abs(flagMc) > 0 ? flagMc / std::abs(flagMc) : 0; /// 0 should never happen, debug protection + } + } else { + /// data + if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { + /// Calculate the electric charge from reconstructed daughter tracks + /// Lc charge == first daughter charge + auto trackProng0 = candidate.template prong0_as(); + charge = static_cast(trackProng0.sign()); } } @@ -593,7 +1133,7 @@ struct TaskPolarisationCharmHadrons { // variable definition float pxDau{-1000.f}, pyDau{-1000.f}, pzDau{-1000.f}; float pxCharmHad{-1000.f}, pyCharmHad{-1000.f}, pzCharmHad{-1000.f}; - float massDau{0.f}, invMassCharmHad{0.f}, invMassCharmHadForSparse{0.f}, invMassD0{0.f}; + float massDau{0.f}, invMassCharmHad{0.f}, invMassCharmHadForSparse{0.f}, invMassD0{0.f}, invMassKPiLc{0.f}, invMassPKLc{0.f}, invMassPPiLc{0.f}; float rapidity{-999.f}; std::array outputMl{-1.f, -1.f, -1.f}; int isRotatedCandidate = 0; // currently meaningful only for Lc->pKpi @@ -603,7 +1143,8 @@ struct TaskPolarisationCharmHadrons { // polarization measured from the soft-pion daughter (*) massDau = massPi; // (*) - const float bkgRotAngle = bkgRotationAngleStep * bkgRotationId; + const float bkgRotAngle = (bkgRotationId > 0) ? minRotAngleMultByPi * constants::math::PI + bkgRotationAngleStep * (bkgRotationId - 1) : 0; + std::array threeVecSoftPi{candidate.pxSoftPi() * std::cos(bkgRotAngle) - candidate.pySoftPi() * std::sin(bkgRotAngle), candidate.pxSoftPi() * std::sin(bkgRotAngle) + candidate.pySoftPi() * std::cos(bkgRotAngle), candidate.pzSoftPi()}; // we rotate the soft pion std::array threeVecD0Prong0{candidate.pVectorProng0()}; std::array threeVecD0Prong1{candidate.pVectorProng1()}; @@ -659,7 +1200,8 @@ struct TaskPolarisationCharmHadrons { /// mass-hypothesis-independent variables /// daughters momenta - const float bkgRotAngle = bkgRotationAngleStep * bkgRotationId; + const float bkgRotAngle = (bkgRotationId > 0) ? minRotAngleMultByPi * constants::math::PI + bkgRotationAngleStep * (bkgRotationId - 1) : 0; + std::array threeVecLcProng0{candidate.pVectorProng0()}; std::array threeVecLcRotatedProng1{candidate.pxProng1() * std::cos(bkgRotAngle) - candidate.pyProng1() * std::sin(bkgRotAngle), candidate.pxProng1() * std::sin(bkgRotAngle) + candidate.pyProng1() * std::cos(bkgRotAngle), candidate.pzProng1()}; std::array threeVecLcProng2{candidate.pVectorProng2()}; @@ -681,6 +1223,9 @@ struct TaskPolarisationCharmHadrons { rapidity = RecoDecay::y(candidate.pVector(), massLc); /// mass-hypothesis-dependent variables + float invMassPiKPi = 0.f; // bkg. from D+ -> K+pi-pi- + float invMassKKPi = 0.f; // bkg. from D+, Ds+ -> K+K-pi+ (1st mass hypothesis) + float invMassPiKK = 0.f; // bkg. from D+, Ds+ -> pi+K-K+ (2nd mass hypothesis) if (iMass == charm_polarisation::MassHyposLcToPKPi::PKPi && candidate.isSelLcToPKPi() >= selectionFlagLcToPKPi) { // reconstructed as pKpi pxDau = candidate.pxProng0(); @@ -705,6 +1250,16 @@ struct TaskPolarisationCharmHadrons { outputMl[2] = candidate.mlProbLcToPKPi()[2]; } } + // invariant mass of the KPi pair + invMassKPiLc = hfHelper.invMassKPiPairLcToPKPi(candidate); + invMassPKLc = hfHelper.invMassPKPairLcToPKPi(candidate); + invMassPPiLc = hfHelper.invMassPPiPairLcToPKPi(candidate); + + // D+ and Ds+ invariant mass values, to put a veto on background sources + invMassPiKPi = hfHelper.invMassDplusToPiKPi(candidate); // bkg. from D+ -> K+pi-pi- + invMassKKPi = hfHelper.invMassDsToKKPi(candidate); // bkg. from D+, Ds+ -> K+K-pi+ (1st mass hypothesis) + invMassPiKK = hfHelper.invMassDsToPiKK(candidate); // bkg. from D+, Ds+ -> pi+K-K+ (2nd mass hypothesis) + } else if (iMass == charm_polarisation::MassHyposLcToPKPi::PiKP && candidate.isSelLcToPiKP() >= selectionFlagLcToPKPi) { // reconstructed as piKp pxDau = candidate.pxProng2(); @@ -729,6 +1284,16 @@ struct TaskPolarisationCharmHadrons { outputMl[2] = candidate.mlProbLcToPiKP()[2]; } } + // invariant mass of the KPi pair + invMassKPiLc = hfHelper.invMassKPiPairLcToPiKP(candidate); + invMassPKLc = hfHelper.invMassPKPairLcToPiKP(candidate); + invMassPPiLc = hfHelper.invMassPPiPairLcToPiKP(candidate); + + // D+ and Ds+ invariant mass values, to put a veto on background sources + invMassPiKPi = hfHelper.invMassDplusToPiKPi(candidate); // bkg. from D+ -> K+pi-pi- + invMassKKPi = hfHelper.invMassDsToKKPi(candidate); // bkg. from D+, Ds+ -> K+K-pi+ (1st mass hypothesis) + invMassPiKK = hfHelper.invMassDsToPiKK(candidate); // bkg. from D+, Ds+ -> pi+K-K+ (2nd mass hypothesis) + } else { // NB: no need to check cases in which candidate.isSelLcToPKPi() and candidate.isSelLcToPiKP() are both false, because they are rejected already by the Filter // ... but we need to put this protections here! @@ -736,8 +1301,42 @@ struct TaskPolarisationCharmHadrons { continue; } + /// put veto on D+, Ds+ inv. masses, to reduce the background + if (lcBkgVeto.applyLcBkgVeto && ((lcBkgVeto.enableLcBkgVetoDplusKPiPi && lcBkgVeto.massDplusKPiPiMinVeto < invMassPiKPi && invMassPiKPi < lcBkgVeto.massDplusKPiPiMaxVeto) /*bkg. from D+ -> K+pi-pi-*/ || + (lcBkgVeto.enableLcBkgVetoDplusKKPi && lcBkgVeto.massDplusKKPiMinVeto < invMassKKPi && invMassKKPi < lcBkgVeto.massDplusKKPiMaxVeto) /*bkg. from D+ -> K+K-pi+ (1st mass hypothesis)*/ || + (lcBkgVeto.enableLcBkgVetoDplusKKPi && lcBkgVeto.massDplusKKPiMinVeto < invMassPiKK && invMassPiKK < lcBkgVeto.massDplusKKPiMaxVeto) /*bkg. from D+ -> K+K-pi+ (2nd mass hypothesis)*/ || + (lcBkgVeto.enableLcBkgVetoDsKKPi && lcBkgVeto.massDsKKPiMinVeto < invMassKKPi && invMassKKPi < lcBkgVeto.massDsKKPiMaxVeto) /*bkg. from Ds+ -> K+K-pi+ (1st mass hypothesis)*/ || + (lcBkgVeto.enableLcBkgVetoDsKKPi && lcBkgVeto.massDsKKPiMinVeto < invMassPiKK && invMassPiKK < lcBkgVeto.massDsKKPiMaxVeto)) /*bkg. from Ds+ -> K+K-pi+ (2nd mass hypothesis)*/) { + /// this candidate has D+ and/or Ds+ in the veto range, let's reject it + continue; + } + + /// control plots on pair masses + double invMass2KPiLc = invMassKPiLc * invMassKPiLc; + double invMass2PKLc = invMassPKLc * invMassPKLc; + double invMass2PPiLc = invMassPPiLc * invMassPPiLc; + if (lcPKPiChannels.activateTHnLcChannelMonitor && bkgRotationId == 0) { + /// fill Dalitz plot only for genuine candidates (i.e. non-rotated) + registry.fill(HIST("hMass2PairsLcPKPi"), invMass2KPiLc, invMass2PKLc, invMass2PPiLc, candidate.pt()); + } + + /// veto cut on pair masses + if (lcPKPiChannels.applyLcSignalVeto && lcPKPiChannels.mass2PPiLcMinVeto < invMass2PPiLc && invMass2PPiLc < lcPKPiChannels.mass2PPiLcMaxVeto) { + /// this candidate has a significant contribution from Lc+ -> Delta++ K-, let's reject it + continue; + } + } // Lc->pKpi + if (invMassCharmHadForSparse < minInvMass || invMassCharmHadForSparse > maxInvMass) { + continue; + } + + /// apply rapidity selection on the reconstructed candidate + if (std::abs(rapidity) > rapidityCut) { + continue; + } + float phiRandom = gRandom->Uniform(0.f, constants::math::TwoPI); float thetaRandom = gRandom->Uniform(0.f, constants::math::PI); ROOT::Math::PxPyPzMVector fourVecDau = ROOT::Math::PxPyPzMVector(pxDau, pyDau, pzDau, massDau); @@ -748,42 +1347,283 @@ struct TaskPolarisationCharmHadrons { float ptCharmHad = std::sqrt(pxCharmHad * pxCharmHad + pyCharmHad * pyCharmHad); // this definition is valid for both rotated and original candidates + if (!isCandidateInSignalRegion) { // it could be that only one mass hypothesis is in signal region + isCandidateInSignalRegion = isInSignalRegion(invMassCharmHadForSparse); + } + + float absEtaTrackMin{-1.f}; + int numItsClsMin{-1}, numTpcClsMin{-1}; + + if (activateTrackingSys) { + auto trackProng0 = candidate.template prong0_as(); + auto trackProng1 = candidate.template prong1_as(); + if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { + auto trackProng2 = candidate.template prongPi_as(); + getTrackingInfos(std::vector{trackProng0, trackProng1, trackProng2}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } else if (channel == charm_polarisation::DecayChannel::LcToPKPi) { + auto trackProng2 = candidate.template prong2_as(); + getTrackingInfos(std::vector{trackProng0, trackProng1, trackProng2}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } + } + + // helicity + ROOT::Math::XYZVector helicityVec = fourVecMother.Vect(); + float cosThetaStarHelicity = -10.f; + float phiHelicity = -10.f; + // production + ROOT::Math::XYZVector normalVec = ROOT::Math::XYZVector(pyCharmHad, -pxCharmHad, 0.f); + float cosThetaStarProduction = -10.f; + float phiProduction = -10.f; + // beam + ROOT::Math::XYZVector beamVec = ROOT::Math::XYZVector(0.f, 0.f, 1.f); + float cosThetaStarBeam = -10.f; + float phiBeam = -10.f; + // random + float cosThetaStarRandom = -10.f; + + int8_t nMuons{0u}; + if constexpr (doMc) { + nMuons = candidate.nTracksDecayed(); + } + if (activateTHnSparseCosThStarHelicity) { - ROOT::Math::XYZVector helicityVec = fourVecMother.Vect(); - float cosThetaStarHelicity = helicityVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(helicityVec.Mag2()); - fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, pzCharmHad, rapidity, invMassD0, cosThetaStarHelicity, outputMl, isRotatedCandidate, origin); + // helicity + cosThetaStarHelicity = helicityVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(helicityVec.Mag2()); + phiHelicity = std::atan2(beamVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()), normalVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(normalVec.Mag2()))); + fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, numPvContributors, rapidity, invMassD0, invMassKPiLc, cosThetaStarHelicity, phiHelicity, outputMl, isRotatedCandidate, origin, ptBhadMother, resoChannelLc, absEtaTrackMin, numItsClsMin, numTpcClsMin, charge, nMuons, partRecoDstar); } if (activateTHnSparseCosThStarProduction) { - ROOT::Math::XYZVector normalVec = ROOT::Math::XYZVector(pyCharmHad, -pxCharmHad, 0.f); - float cosThetaStarProduction = normalVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(normalVec.Mag2()); - fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, pzCharmHad, rapidity, invMassD0, cosThetaStarProduction, outputMl, isRotatedCandidate, origin); + // production + cosThetaStarProduction = normalVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(normalVec.Mag2()); + phiProduction = std::atan2(normalVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(normalVec.Mag2())), helicityVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(helicityVec.Mag2()))); + fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, numPvContributors, rapidity, invMassD0, invMassKPiLc, cosThetaStarProduction, phiProduction, outputMl, isRotatedCandidate, origin, ptBhadMother, resoChannelLc, absEtaTrackMin, numItsClsMin, numTpcClsMin, charge, nMuons, partRecoDstar); } if (activateTHnSparseCosThStarBeam) { - ROOT::Math::XYZVector beamVec = ROOT::Math::XYZVector(0.f, 0.f, 1.f); - float cosThetaStarBeam = beamVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); - fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, pzCharmHad, rapidity, invMassD0, cosThetaStarBeam, outputMl, isRotatedCandidate, origin); + // beam + cosThetaStarBeam = beamVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + phiBeam = std::atan2(helicityVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(helicityVec.Mag2())), beamVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2())); + fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, numPvContributors, rapidity, invMassD0, invMassKPiLc, cosThetaStarBeam, phiBeam, outputMl, isRotatedCandidate, origin, ptBhadMother, resoChannelLc, absEtaTrackMin, numItsClsMin, numTpcClsMin, charge, nMuons, partRecoDstar); } if (activateTHnSparseCosThStarRandom) { + // random ROOT::Math::XYZVector randomVec = ROOT::Math::XYZVector(std::sin(thetaRandom) * std::cos(phiRandom), std::sin(thetaRandom) * std::sin(phiRandom), std::cos(thetaRandom)); - float cosThetaStarRandom = randomVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); - fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, pzCharmHad, rapidity, invMassD0, cosThetaStarRandom, outputMl, isRotatedCandidate, origin); + cosThetaStarRandom = randomVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, numPvContributors, rapidity, invMassD0, invMassKPiLc, cosThetaStarRandom, -99.f, outputMl, isRotatedCandidate, origin, ptBhadMother, resoChannelLc, absEtaTrackMin, numItsClsMin, numTpcClsMin, charge, nMuons, partRecoDstar); } + + /// Table for Lc->pKpi background studies + /// Defined only in MC simulations, to study resonances and reflected signal + if constexpr (doMc && channel == charm_polarisation::DecayChannel::LcToPKPi) { + if constexpr (studyLcPKPiBkgMc) { + /****************************************************************************************** + The code below can work only without grouping on "mcCollision". + In fact, grouping by "mcCollision" introduces the following inconsistencies: + + 1) the particle getters "track.template mcParticle_as()" retrieve the daughter particles quering the full particle table in the dataframe. + In other words, even if the 3-prong candidate is reconstructed in a completely wrong reco. collision due to the track-to-collision associator, + therefore this collision points to a "mcCollision" different from the current one and the daughter particles are associated to this different "mcCollision", + the getter "mcParticle_as" works anyway, because it works with unbound tables ignoring the fact that "particles" is grouped; + + 2) when we look for the mother index from the daughter particles of the previous point, but the daughter particles belong to a "mcCollision" different from the current one, + then also the mother particle belongs to this different "mcCollision". This means that the mother index ( - "particles.offset()") is outside the "particles.size()", + because the table "particles" is grouped w.r.t. the current "mcCollision". + *******************************************************************************************/ + + /// check if the tracks are associated to a pion + a kaon + a proton + int8_t isRealPKPi = 0; /// true only if the triplet is formed by a MC pion + a MC kaon + a MC proton + bool isGenPKPi = false; + bool isGenPiKP = false; + auto trackProng0 = candidate.template prong0_as(); + auto trackProng1 = candidate.template prong1_as(); + auto trackProng2 = candidate.template prong2_as(); + int pdgProng0 = 0; + int pdgProng1 = 0; + int pdgProng2 = 0; + int8_t originProng0 = -1; + int8_t originProng1 = -1; + int8_t originProng2 = -1; + std::vector idxBhadMothersProng0{}; + std::vector idxBhadMothersProng1{}; + std::vector idxBhadMothersProng2{}; + if (trackProng0.has_mcParticle()) { + /// BEWARE: even when grouping by mcCollision, mcParticle_as<> gets the mcParticle even if it belongs to a different mcCollision + /// because _as<> works with unbound tables. (*) + auto particleProng0 = trackProng0.template mcParticle_as(); + pdgProng0 = particleProng0.pdgCode(); + originProng0 = RecoDecay::getCharmHadronOrigin(particles, particleProng0, false, &idxBhadMothersProng0); + } + if (trackProng1.has_mcParticle()) { + /// BEWARE: even when grouping by mcCollision, mcParticle_as<> gets the mcParticle even if it belongs to a different mcCollision + /// because _as<> works with unbound tables. (*) + auto particleProng1 = trackProng1.template mcParticle_as(); + pdgProng1 = particleProng1.pdgCode(); + originProng1 = RecoDecay::getCharmHadronOrigin(particles, particleProng1, false, &idxBhadMothersProng1); + } + if (trackProng2.has_mcParticle()) { + /// BEWARE: even when grouping by mcCollision, mcParticle_as<> gets the mcParticle even if it belongs to a different mcCollision + /// because _as<> works with unbound tables. (*) + auto particleProng2 = trackProng2.template mcParticle_as(); + pdgProng2 = particleProng2.pdgCode(); + originProng2 = RecoDecay::getCharmHadronOrigin(particles, particleProng2, false, &idxBhadMothersProng2); + } + isGenPKPi = std::abs(pdgProng0) == kProton && std::abs(pdgProng1) == kKPlus && std::abs(pdgProng2) == kPiPlus; + isGenPiKP = std::abs(pdgProng0) == kPiPlus && std::abs(pdgProng1) == kKPlus && std::abs(pdgProng2) == kProton; + if (isGenPKPi || isGenPiKP) { + isRealPKPi = 1; + } + + /// check if the triplet is reflected or not + /// i.e. generated as pKpi but reconstructed as piKp, or viceversa + int8_t isReflected = 0; + if (isRealPKPi && ((iMass == charm_polarisation::MassHyposLcToPKPi::PKPi && candidate.isSelLcToPKPi() >= selectionFlagLcToPKPi && isGenPiKP) || (iMass == charm_polarisation::MassHyposLcToPKPi::PiKP && candidate.isSelLcToPiKP() >= selectionFlagLcToPKPi && isGenPKPi))) { + isReflected = 1; + } + + /// check the origin (prompt, non-prompt of the triplet) + /// need to check each prong, since they might come from combinatorial background + /// convention: + /// - all 3 prongs from the same B hadron: non-prompt + /// - all 3 prongs claimed to be prompt: prompt --> check on same charm mother done offline with prong PDG daughters (more difficult for beauty, due to more intermediate resonances) and checking that the distribution peaks somehow (otherwise: combinatorial background) + /// - otherwise: none + int8_t originTriplet = RecoDecay::OriginType::None; + if (originProng0 == RecoDecay::OriginType::Prompt && originProng1 == RecoDecay::OriginType::Prompt && originProng2 == RecoDecay::OriginType::Prompt) { + /// we claim this triplet as prong w/o checking if all triplets have the same mother + originTriplet = RecoDecay::OriginType::Prompt; + } else if (originProng0 == RecoDecay::OriginType::NonPrompt && originProng1 == RecoDecay::OriginType::NonPrompt && originProng2 == RecoDecay::OriginType::NonPrompt) { + /// check if the three particles share the same B-hadron id. If yes: claim the triplet as "non-prompt" + int idBMotherProng0 = idxBhadMothersProng0.at(0); + int idBMotherProng1 = idxBhadMothersProng1.at(0); + int idBMotherProng2 = idxBhadMothersProng2.at(0); + if (idBMotherProng0 == idBMotherProng1 && idBMotherProng1 == idBMotherProng2) { + originTriplet = RecoDecay::OriginType::NonPrompt; + } + } + + /// check if the pKpi triplet is a Lc->pKpi + int8_t isRealLcPKPi = 0; + if (isRealPKPi && TESTBIT(std::abs(candidate.flagMcMatchRec()), aod::hf_cand_3prong::DecayType::LcToPKPi)) { + isRealLcPKPi = 1; + } + + /// look for daughters' mothers (1st level only) + std::vector idMothersProng0 = {}; + std::vector idMothersProng1 = {}; + std::vector idMothersProng2 = {}; + searchFirstLevelMother(trackProng0, idMothersProng0, particles); + searchFirstLevelMother(trackProng1, idMothersProng1, particles); + searchFirstLevelMother(trackProng2, idMothersProng2, particles); + + /// check if daughter pairs have the same mother + /// it should be enough to check the 1st one only (only particles from partonic events, or interactions with material, can have more than 1 mother) + int pdgMotherProng0 = -1; + int pdgMotherProng1 = -1; + int pdgMotherProng2 = -1; + bool atLeast2ProngsFromSameMother = (idMothersProng0.size() > 0 && idMothersProng1.size() > 0 && idMothersProng0.at(0) == idMothersProng1.at(0)) || + (idMothersProng1.size() > 0 && idMothersProng2.size() > 0 && idMothersProng1.at(0) == idMothersProng2.at(0)) || + (idMothersProng0.size() > 0 && idMothersProng2.size() > 0 && idMothersProng0.at(0) == idMothersProng2.at(0)); + if (atLeast2ProngsFromSameMother) { + if (idMothersProng0.size() > 0) { + /// BEWARE: in case of mcCollision grouping, the idMother can anyway point to a particle in another collision (*) + /// therefore the rawIteratorAt call might crash the code because one goes above the (grouped) particles table size + auto mother = particles.rawIteratorAt(idMothersProng0.at(0) - particles.offset()); + pdgMotherProng0 = std::abs(mother.pdgCode()); // PDG code of the mother + } + if (idMothersProng1.size() > 0) { + /// BEWARE: in case of mcCollision grouping, the idMother can anyway point to a particle in another collision (*) + /// therefore the rawIteratorAt call might crash the code because one goes above the (grouped) particles table size + auto mother = particles.rawIteratorAt(idMothersProng1.at(0) - particles.offset()); + pdgMotherProng1 = std::abs(mother.pdgCode()); // PDG code of the mother + } + if (idMothersProng2.size() > 0) { + /// BEWARE: in case of mcCollision grouping, the idMother can anyway point to a particle in another collision (*) + /// therefore the rawIteratorAt call might crash the code because one goes above the (grouped) particles table size + auto mother = particles.rawIteratorAt(idMothersProng2.at(0) - particles.offset()); + pdgMotherProng2 = std::abs(mother.pdgCode()); // PDG code of the mother + } + } + + /// calculate inv. masses for pairs, depending on mass hypothesis + std::array pVecPion = {}; + std::array pVecKaon = candidate.pVectorProng1(); + std::array pVecProton = {}; + if (iMass == charm_polarisation::MassHyposLcToPKPi::PKPi && candidate.isSelLcToPKPi() >= selectionFlagLcToPKPi) { + pVecProton = candidate.pVectorProng0(); + pVecPion = candidate.pVectorProng2(); + } else if (iMass == charm_polarisation::MassHyposLcToPKPi::PiKP && candidate.isSelLcToPiKP() >= selectionFlagLcToPKPi) { + pVecProton = candidate.pVectorProng2(); + pVecPion = candidate.pVectorProng0(); + } + const float massKPi = RecoDecay::m(std::array{pVecKaon, pVecPion}, std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); + const float massKProton = RecoDecay::m(std::array{pVecKaon, pVecProton}, std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassProton}); + const float massPiProton = RecoDecay::m(std::array{pVecPion, pVecProton}, std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassProton}); + + /// Fill the table for selected candidates + /// No need to check explicitly if candidates are selected, since the Filter is applied + float cosThetaStarForTable = -10.f; + switch (cosThStarAxisLcPKPiBkgMc) { + case 1: + cosThetaStarForTable = cosThetaStarHelicity; + break; + case 2: + cosThetaStarForTable = cosThetaStarProduction; + break; + case 3: + cosThetaStarForTable = cosThetaStarBeam; + break; + case 4: + cosThetaStarForTable = cosThetaStarRandom; + break; + default: + LOG(fatal) << "cosThStarAxisLcPKPiBkgMc must be between 1 and 4 (1: helicity; 2: production; 3: beam; 4: random), but cosThStarAxisLcPKPiBkgMc = " << cosThStarAxisLcPKPiBkgMc << ". Fix it!"; + break; + } + rowCandLcBkg(invMassCharmHadForSparse, ptCharmHad, rapidity, + cosThetaStarForTable, + pdgMotherProng0, pdgMotherProng1, pdgMotherProng2, + massKPi, massKProton, massPiProton, + outputMl.at(0), outputMl.at(2), + isRealPKPi, isRealLcPKPi, isReflected, + charge, originTriplet); + } // end studyLcPKPiBkgMc + } // end table for Lc->pKpi background studies + } /// end loop over mass hypotheses + + return isCandidateInSignalRegion; } /// \param mcParticle is the Mc particle /// \param mcParticles is the table of Mc particles + /// \param numPvContributors is the number of PV contributors in the associated reco collision template - void runMcGenPolarisationAnalysis(Part const& mcParticle, Particles const& mcParticles) + void runMcGenPolarisationAnalysis(Part const& mcParticle, Particles const& mcParticles, int numPvContributors) { int8_t origin{RecoDecay::OriginType::None}; std::vector listDaughters{}; float massDau{0.f}, massCharmHad{0.f}; + float ptBhadMother{-1.f}; + bool areDauInAcc{true}; + int8_t resoChannelLc = -1; + int8_t charge = -99; + bool partRecoDstar{false}; if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { - if (!TESTBIT(std::abs(mcParticle.flagMcMatchGen()), aod::hf_cand_dstar::DecayType::DstarToD0Pi)) { // this particle is not signal, skip + partRecoDstar = TESTBIT(std::abs(mcParticle.flagMcMatchGen()), aod::hf_cand_dstar::DecayType::DstarToD0PiPi0) && TESTBIT(std::abs(mcParticle.flagMcMatchGenD0()), aod::hf_cand_dstar::DecayType::D0ToPiKPi0); + bool signalDstar = TESTBIT(std::abs(mcParticle.flagMcMatchGen()), aod::hf_cand_dstar::DecayType::DstarToD0Pi) && TESTBIT(std::abs(mcParticle.flagMcMatchGenD0()), aod::hf_cand_dstar::DecayType::D0ToPiK); + + if (!signalDstar && (!activatePartRecoDstar || !partRecoDstar)) { // this particle is not signal and not partially reconstructed signal, skip return; } origin = mcParticle.originMcGen(); + if (origin == RecoDecay::OriginType::NonPrompt) { + auto bHadMother = mcParticles.rawIteratorAt(mcParticle.idxBhadMotherPart() - mcParticles.offset()); + int pdgBhadMother = std::abs(bHadMother.pdgCode()); + // For unknown reasons there are charm hadrons coming directly from beauty diquarks without an intermediate B-hadron which have an unreasonable correlation between the pT of the charm hadron and the beauty mother. We also remove charm hadrons from quarkonia. + if (pdgBhadMother == 5101 || pdgBhadMother == 5103 || pdgBhadMother == 5201 || pdgBhadMother == 5203 || pdgBhadMother == 5301 || pdgBhadMother == 5303 || pdgBhadMother == 5401 || pdgBhadMother == 5403 || pdgBhadMother == 5503 || pdgBhadMother == 553 || pdgBhadMother == 555 || pdgBhadMother == 553 || pdgBhadMother == 557) { + return; + } + ptBhadMother = bHadMother.pt(); + } + std::array dauPdgs = {kPiPlus, o2::constants::physics::Pdg::kD0}; RecoDecay::getDaughters(mcParticle, &listDaughters, dauPdgs, 1); massDau = massPi; @@ -793,10 +1633,15 @@ struct TaskPolarisationCharmHadrons { return; } origin = mcParticle.originMcGen(); + resoChannelLc = mcParticle.flagMcDecayChanGen(); std::array dauPdgs = {kProton, -kKPlus, kPiPlus}; RecoDecay::getDaughters(mcParticle, &listDaughters, dauPdgs, 2); massDau = massProton; massCharmHad = massLc; + + /// electric charge from PDG code + int pdgCode = mcParticle.pdgCode(); + charge = static_cast(pdgCode / std::abs(pdgCode)); } float rapidity = mcParticle.y(); @@ -811,20 +1656,34 @@ struct TaskPolarisationCharmHadrons { float pxDau{-1000.f}, pyDau{-1000.f}, pzDau{-1000.f}; for (const auto& dauIdx : listDaughters) { - auto dauPart = mcParticles.rawIteratorAt(dauIdx); + auto dauPart = mcParticles.rawIteratorAt(dauIdx - mcParticles.offset()); if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { if (std::abs(dauPart.pdgCode()) == kPiPlus) { pxDau = dauPart.px(); pyDau = dauPart.py(); pzDau = dauPart.pz(); - break; + if (areDauInAcc) { + areDauInAcc = isDaughterInAcceptance(dauPart, 0.1, 0.8); + } + } else if (areDauInAcc) { // check also D0 daughters + std::vector listDaughtersD0{}; + std::array dauPdgsD0 = {kPiPlus, -kKPlus}; + RecoDecay::getDaughters(mcParticle, &listDaughtersD0, dauPdgsD0, 1); + for (const auto& dauIdxD0 : listDaughtersD0) { + auto dauPartD0 = mcParticles.rawIteratorAt(dauIdxD0 - mcParticles.offset()); + if (areDauInAcc) { + areDauInAcc = isDaughterInAcceptance(dauPartD0, 0.3, 0.8); + } + } } } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { if (std::abs(dauPart.pdgCode()) == kProton) { pxDau = dauPart.px(); pyDau = dauPart.py(); pzDau = dauPart.pz(); - break; + } + if (areDauInAcc) { + areDauInAcc = isDaughterInAcceptance(dauPart, 0.3, 0.8); } } } @@ -840,22 +1699,22 @@ struct TaskPolarisationCharmHadrons { if (activateTHnSparseCosThStarHelicity) { ROOT::Math::XYZVector helicityVec = fourVecMother.Vect(); float cosThetaStarHelicity = helicityVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(helicityVec.Mag2()); - fillGenHistos(ptCharmHad, pzCharmHad, rapidity, cosThetaStarHelicity, origin); + fillGenHistos(ptCharmHad, numPvContributors, rapidity, cosThetaStarHelicity, origin, ptBhadMother, areDauInAcc, resoChannelLc, charge, partRecoDstar); } if (activateTHnSparseCosThStarProduction) { ROOT::Math::XYZVector normalVec = ROOT::Math::XYZVector(pyCharmHad, -pxCharmHad, 0.f); float cosThetaStarProduction = normalVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(normalVec.Mag2()); - fillGenHistos(ptCharmHad, pzCharmHad, rapidity, cosThetaStarProduction, origin); + fillGenHistos(ptCharmHad, numPvContributors, rapidity, cosThetaStarProduction, origin, ptBhadMother, areDauInAcc, resoChannelLc, charge, partRecoDstar); } if (activateTHnSparseCosThStarBeam) { ROOT::Math::XYZVector beamVec = ROOT::Math::XYZVector(0.f, 0.f, 1.f); float cosThetaStarBeam = beamVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); - fillGenHistos(ptCharmHad, pzCharmHad, rapidity, cosThetaStarBeam, origin); + fillGenHistos(ptCharmHad, numPvContributors, rapidity, cosThetaStarBeam, origin, ptBhadMother, areDauInAcc, resoChannelLc, charge, partRecoDstar); } if (activateTHnSparseCosThStarRandom) { ROOT::Math::XYZVector randomVec = ROOT::Math::XYZVector(std::sin(thetaRandom) * std::cos(phiRandom), std::sin(thetaRandom) * std::sin(phiRandom), std::cos(thetaRandom)); float cosThetaStarRandom = randomVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); - fillGenHistos(ptCharmHad, pzCharmHad, rapidity, cosThetaStarRandom, origin); + fillGenHistos(ptCharmHad, numPvContributors, rapidity, cosThetaStarRandom, origin, ptBhadMother, areDauInAcc, resoChannelLc, charge, partRecoDstar); } } @@ -864,50 +1723,119 @@ struct TaskPolarisationCharmHadrons { ///////////////////////// // Dstar with rectangular cuts - void processDstar(soa::Filtered::iterator const& dstarCandidate) + void processDstar(aod::Collisions const& collisions, + FilteredCandDstarWSelFlag const& dstarCandidates, + TracksWithExtra const& tracks) { - runPolarisationAnalysis(dstarCandidate); + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + int numPvContributors = collision.numContrib(); + auto groupedDstarCandidates = dstarCandidates.sliceBy(dstarPerCollision, thisCollId); + int nCands{0}, nCandsInSignalRegion{0}; + + for (const auto& dstarCandidate : groupedDstarCandidates) { + nCands++; + if (runPolarisationAnalysis(dstarCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks)) { + nCandsInSignalRegion++; + } - for (int iRotation{1}; iRotation <= nBkgRotations; ++iRotation) { - runPolarisationAnalysis(dstarCandidate, iRotation); + for (int iRotation{1}; iRotation <= nBkgRotations; ++iRotation) { + runPolarisationAnalysis(dstarCandidate, iRotation, numPvContributors, -1 /*MC particles*/, tracks); + } + } + fillMultHistos(numPvContributors, nCands, nCandsInSignalRegion); } } PROCESS_SWITCH(TaskPolarisationCharmHadrons, processDstar, "Process Dstar candidates without ML", true); // Dstar with ML cuts - void processDstarWithMl(soa::Filtered>::iterator const& dstarCandidate) + void processDstarWithMl(aod::Collisions const& collisions, + FilteredCandDstarWSelFlagAndMl const& dstarCandidates, + TracksWithExtra const& tracks) { - runPolarisationAnalysis(dstarCandidate); + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + int numPvContributors = collision.numContrib(); + auto groupedDstarCandidates = dstarCandidates.sliceBy(dstarWithMlPerCollision, thisCollId); + int nCands{0}, nCandsInSignalRegion{0}; + + for (const auto& dstarCandidate : groupedDstarCandidates) { + nCands++; + if (runPolarisationAnalysis(dstarCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks)) { + nCandsInSignalRegion++; + } - /// rotational background - for (int iRotation{1}; iRotation <= nBkgRotations; ++iRotation) { - runPolarisationAnalysis(dstarCandidate, iRotation); + for (int iRotation{1}; iRotation <= nBkgRotations; ++iRotation) { + runPolarisationAnalysis(dstarCandidate, iRotation, numPvContributors, -1 /*MC particles*/, tracks); + } + } + fillMultHistos(numPvContributors, nCands, nCandsInSignalRegion); } } PROCESS_SWITCH(TaskPolarisationCharmHadrons, processDstarWithMl, "Process Dstar candidates with ML", false); // Dstar in MC with rectangular cuts - void processDstarMc(soa::Filtered> const& dstarCandidates, soa::Join const& mcParticles) + void processDstarMc(aod::McCollisions::iterator const&, + McParticlesDstarMatched const& mcParticles, + CollisionsWithMcLabels const& collisions, // this is grouped with SmallGroupsCollisionsWithMcLabels const& collisions, + FilteredCandDstarWSelFlagAndMc const& dstarCandidates, + TracksWithExtra const& tracks) { - for (const auto& dstarCandidate : dstarCandidates) { - runPolarisationAnalysis(dstarCandidate); + int numPvContributorsGen{0}; + for (const auto& collision : collisions) { // loop over reco collisions associated to this gen collision + auto thisCollId = collision.globalIndex(); + int numPvContributors = collision.numContrib(); + auto groupedDstarCandidates = dstarCandidates.sliceBy(dstarWithMcPerCollision, thisCollId); + int nCands{0}, nCandsInSignalRegion{0}; + + if (numPvContributors > numPvContributorsGen) { // we take the associated reconstructed collision with higher number of PV contributors + numPvContributorsGen = numPvContributors; + } + + for (const auto& dstarCandidate : groupedDstarCandidates) { + nCands++; + if (runPolarisationAnalysis(dstarCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks)) { + nCandsInSignalRegion++; + } + } + fillMultHistos(numPvContributors, nCands, nCandsInSignalRegion); } for (const auto& mcParticle : mcParticles) { - runMcGenPolarisationAnalysis(mcParticle, mcParticles); + runMcGenPolarisationAnalysis(mcParticle, mcParticles, numPvContributorsGen); } } PROCESS_SWITCH(TaskPolarisationCharmHadrons, processDstarMc, "Process Dstar candidates in MC without ML", false); // Dstar in MC with ML cuts - void processDstarMcWithMl(soa::Filtered> const& dstarCandidates, soa::Join const& mcParticles) + void processDstarMcWithMl(aod::McCollisions::iterator const&, + McParticlesDstarMatched const& mcParticles, + CollisionsWithMcLabels const& collisions, // this is grouped with SmallGroupsCollisionsWithMcLabels const& collisions, + FilteredCandDstarWSelFlagAndMcAndMl const& dstarCandidates, + TracksWithExtra const& tracks) { - for (const auto& dstarCandidate : dstarCandidates) { - runPolarisationAnalysis(dstarCandidate); + int numPvContributorsGen{0}; + for (const auto& collision : collisions) { // loop over reco collisions associated to this gen collision + auto thisCollId = collision.globalIndex(); + int numPvContributors = collision.numContrib(); + auto groupedDstarCandidates = dstarCandidates.sliceBy(dstarWithMcAndMlPerCollision, thisCollId); + int nCands{0}, nCandsInSignalRegion{0}; + + if (numPvContributors > numPvContributorsGen) { // we take the associated reconstructed collision with higher number of PV contributors + numPvContributorsGen = numPvContributors; + } + + for (const auto& dstarCandidate : groupedDstarCandidates) { + nCands++; + if (runPolarisationAnalysis(dstarCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks)) { + nCandsInSignalRegion++; + } + } + fillMultHistos(numPvContributors, nCands, nCandsInSignalRegion); } for (const auto& mcParticle : mcParticles) { - runMcGenPolarisationAnalysis(mcParticle, mcParticles); + runMcGenPolarisationAnalysis(mcParticle, mcParticles, numPvContributorsGen); } } PROCESS_SWITCH(TaskPolarisationCharmHadrons, processDstarMcWithMl, "Process Dstar candidates in MC with ML", false); @@ -917,54 +1845,139 @@ struct TaskPolarisationCharmHadrons { //////////////////////////// // Lc->pKpi with rectangular cuts - void processLcToPKPi(soa::Filtered::iterator const& lcCandidate) + void processLcToPKPi(aod::Collisions const& collisions, + FilteredCandLcToPKPiWSelFlag const& lcCandidates, + TracksWithExtra const& tracks) { - runPolarisationAnalysis(lcCandidate); + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + int numPvContributors = collision.numContrib(); + auto groupedLcCandidates = lcCandidates.sliceBy(lcToPKPiPerCollision, thisCollId); + int nCands{0}, nCandsInSignalRegion{0}; + + for (const auto& lcCandidate : groupedLcCandidates) { + nCands++; + if (runPolarisationAnalysis(lcCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks)) { + nCandsInSignalRegion++; + } - /// rotational background - for (int iRotation{1}; iRotation <= nBkgRotations; ++iRotation) { - runPolarisationAnalysis(lcCandidate, iRotation); + /// rotational background + for (int iRotation{1}; iRotation <= nBkgRotations; ++iRotation) { + runPolarisationAnalysis(lcCandidate, iRotation, numPvContributors, -1 /*MC particles*/, tracks); + } + } + fillMultHistos(numPvContributors, nCands, nCandsInSignalRegion); } } PROCESS_SWITCH(TaskPolarisationCharmHadrons, processLcToPKPi, "Process Lc candidates without ML", false); // Lc->pKpi with ML cuts - void processLcToPKPiWithMl(soa::Filtered>::iterator const& lcCandidate) + void processLcToPKPiWithMl(aod::Collisions const& collisions, + FilteredCandLcToPKPiWSelFlagAndMl const& lcCandidates, + TracksWithExtra const& tracks) { - runPolarisationAnalysis(lcCandidate); + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + int numPvContributors = collision.numContrib(); + auto groupedLcCandidates = lcCandidates.sliceBy(lcToPKPiWithMlPerCollision, thisCollId); + int nCands{0}, nCandsInSignalRegion{0}; + + for (const auto& lcCandidate : groupedLcCandidates) { + nCands++; + if (runPolarisationAnalysis(lcCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks)) { + nCandsInSignalRegion++; + } - /// rotational background - for (int iRotation{1}; iRotation <= nBkgRotations; ++iRotation) { - runPolarisationAnalysis(lcCandidate, iRotation); + /// rotational background + for (int iRotation{1}; iRotation <= nBkgRotations; ++iRotation) { + runPolarisationAnalysis(lcCandidate, iRotation, numPvContributors, -1 /*MC particles*/, tracks); + } + } + fillMultHistos(numPvContributors, nCands, nCandsInSignalRegion); } } PROCESS_SWITCH(TaskPolarisationCharmHadrons, processLcToPKPiWithMl, "Process Lc candidates with ML", false); // Lc->pKpi in MC with rectangular cuts - void processLcToPKPiMc(soa::Filtered> const& lcCandidates, soa::Join const& mcParticles) + void processLcToPKPiMc(aod::McCollisions::iterator const&, + McParticles3ProngMatched const& mcParticles, + CollisionsWithMcLabels const& collisions, // this is grouped with SmallGroupsCollisionsWithMcLabels const& collisions, + FilteredCandLcToPKPiWSelFlagAndMc const& lcCandidates, + TracksWithExtra const& tracks) { - for (const auto& lcCandidate : lcCandidates) { - runPolarisationAnalysis(lcCandidate); + int numPvContributorsGen{0}; + for (const auto& collision : collisions) { // loop over reco collisions associated to this gen collision + auto thisCollId = collision.globalIndex(); + int numPvContributors = collision.numContrib(); + auto groupedLcCandidates = lcCandidates.sliceBy(lcToPKPiWithMcAndMlPerCollision, thisCollId); + int nCands{0}, nCandsInSignalRegion{0}; + + if (numPvContributors > numPvContributorsGen) { // we take the associated reconstructed collision with higher number of PV contributors + numPvContributorsGen = numPvContributors; + } + + for (const auto& lcCandidate : groupedLcCandidates) { + nCands++; + if (runPolarisationAnalysis(lcCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks)) { + nCandsInSignalRegion++; + } + } + fillMultHistos(numPvContributors, nCands, nCandsInSignalRegion); } for (const auto& mcParticle : mcParticles) { - runMcGenPolarisationAnalysis(mcParticle, mcParticles); + runMcGenPolarisationAnalysis(mcParticle, mcParticles, numPvContributorsGen); } } PROCESS_SWITCH(TaskPolarisationCharmHadrons, processLcToPKPiMc, "Process Lc candidates in MC without ML", false); // Lc->pKpi in MC with ML cuts - void processLcToPKPiMcWithMl(soa::Filtered> const& lcCandidates, soa::Join const& mcParticles) + void processLcToPKPiMcWithMl(aod::McCollisions::iterator const&, + McParticles3ProngMatched const& mcParticles, + CollisionsWithMcLabels const& collisions, // this is grouped with SmallGroups + FilteredCandLcToPKPiWSelFlagAndMcAndMl const& lcCandidates, + TracksWithExtra const& tracks) { - for (const auto& lcCandidate : lcCandidates) { - runPolarisationAnalysis(lcCandidate); + int numPvContributorsGen{0}; + for (const auto& collision : collisions) { // loop over reco collisions associated to this gen collision + auto thisCollId = collision.globalIndex(); + int numPvContributors = collision.numContrib(); + auto groupedLcCandidates = lcCandidates.sliceBy(lcToPKPiWithMcAndMlPerCollision, thisCollId); + int nCands{0}, nCandsInSignalRegion{0}; + + if (numPvContributors > numPvContributorsGen) { // we take the associated reconstructed collision with higher number of PV contributors + numPvContributorsGen = numPvContributors; + } + + for (const auto& lcCandidate : groupedLcCandidates) { + nCands++; + if (runPolarisationAnalysis(lcCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks)) { + nCandsInSignalRegion++; + } + } + fillMultHistos(numPvContributors, nCands, nCandsInSignalRegion); } for (const auto& mcParticle : mcParticles) { - runMcGenPolarisationAnalysis(mcParticle, mcParticles); + runMcGenPolarisationAnalysis(mcParticle, mcParticles, numPvContributorsGen); } } PROCESS_SWITCH(TaskPolarisationCharmHadrons, processLcToPKPiMcWithMl, "Process Lc candidates in MC with ML", false); + + // Lc->pKpi in MC with ML cuts w/o mcCollision grouping (to study Lc background) + void processLcToPKPiBackgroundMcWithMl(McParticles3ProngMatched const& mcParticles, + FilteredCandLcToPKPiWSelFlagAndMcAndMl const& lcCandidates, + TracksWithMcLabels const& tracks) + { + for (const auto& lcCandidate : lcCandidates) { + runPolarisationAnalysis(lcCandidate, 0, /*numPvContributors*/ -1, mcParticles, tracks); + } + + for (const auto& mcParticle : mcParticles) { + runMcGenPolarisationAnalysis(mcParticle, mcParticles, /*numPvContributorsGen*/ -1); + } + } + PROCESS_SWITCH(TaskPolarisationCharmHadrons, processLcToPKPiBackgroundMcWithMl, "Process Lc candidates in MC with ML w/o mcCollision grouping", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/D2H/Tasks/taskCharmResoReduced.cxx b/PWGHF/D2H/Tasks/taskCharmResoReduced.cxx new file mode 100644 index 00000000000..078be76881c --- /dev/null +++ b/PWGHF/D2H/Tasks/taskCharmResoReduced.cxx @@ -0,0 +1,476 @@ +// 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 taskCharmResoReduced.cxx +/// \brief Charmed Resonances analysis task +/// +/// \author Luca Aglietta , University and INFN Torino + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/RecoDecay.h" + +// #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" + +using namespace o2; +using namespace o2::soa; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +enum DecayTypeMc : uint8_t { + Ds1ToDStarK0ToD0PiK0s = 1, + Ds2StarToDplusK0sToPiKaPiPiPi, + Ds1ToDStarK0ToDPlusPi0K0s, + Ds1ToDStarK0ToD0PiK0sPart, + Ds1ToDStarK0ToD0NoPiK0sPart, + Ds1ToDStarK0ToD0PiK0sOneMu, + Ds2StarToDplusK0sOneMu +}; + +namespace o2::aod +{ +namespace hf_cand_reso_lite +{ +DECLARE_SOA_COLUMN(PtBach0, ptBach0, float); //! Transverse momentum of bachelor 0 (GeV/c) +DECLARE_SOA_COLUMN(PtBach1, ptBach1, float); //! Transverse momentum of bachelor 1 (GeV/c) +DECLARE_SOA_COLUMN(MBach0, mBach0, float); //! Invariant mass of bachelor 0 (GeV/c) +DECLARE_SOA_COLUMN(MBach1, mBach1, float); //! Invariant mass of bachelor 1 (GeV/c) +DECLARE_SOA_COLUMN(MBachD0, mBachD0, float); //! Invariant mass of D0 bachelor (of bachelor 0) (GeV/c) +DECLARE_SOA_COLUMN(M, m, float); //! Invariant mass of candidate (GeV/c2) +DECLARE_SOA_COLUMN(Pt, pt, float); //! Transverse momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(P, p, float); //! Momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(Y, y, float); //! Rapidity of candidate +DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity of candidate +DECLARE_SOA_COLUMN(Phi, phi, float); //! Azimuth angle of candidate +DECLARE_SOA_COLUMN(E, e, float); //! Energy of candidate (GeV) +DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! Sign of candidate +DECLARE_SOA_COLUMN(CosThetaStar, cosThetaStar, float); //! VosThetaStar of candidate (GeV) +DECLARE_SOA_COLUMN(MlScoreBkgBach0, mlScoreBkgBach0, float); //! ML score for background class of charm daughter +DECLARE_SOA_COLUMN(MlScorePromptBach0, mlScorePromptBach0, float); //! ML score for prompt class of charm daughter +DECLARE_SOA_COLUMN(MlScoreNonPromptBach0, mlScoreNonPromptBach0, float); //! ML score for non-prompt class of charm daughter +DECLARE_SOA_COLUMN(ItsNClsProngMinBach0, itsNClsProngMinBach0, int); //! minimum value of number of ITS clusters for the decay daughter tracks of bachelor 0 +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsProngMinBach0, tpcNClsCrossedRowsProngMinBach0, int); //! minimum value of number of TPC crossed rows for the decay daughter tracks of bachelor 0 +DECLARE_SOA_COLUMN(TpcChi2NClProngMaxBach0, tpcChi2NClProngMaxBach0, float); //! maximum value of TPC chi2 for the decay daughter tracks of bachelor 0 +DECLARE_SOA_COLUMN(ItsNClsProngMinBach1, itsNClsProngMinBach1, int); //! minimum value of number of ITS clusters for the decay daughter tracks of bachelor 1 +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsProngMinBach1, tpcNClsCrossedRowsProngMinBach1, int); //! minimum value of number of TPC crossed rows for the decay daughter tracks of bachelor 1 +DECLARE_SOA_COLUMN(TpcChi2NClProngMaxBach1, tpcChi2NClProngMaxBach1, float); //! maximum value of TPC chi2 for the decay daughter tracks of bachelor 1 +DECLARE_SOA_COLUMN(CpaBach1, cpaBach1, float); //! Cosine of Pointing Angle of bachelor 1 +DECLARE_SOA_COLUMN(DcaBach1, dcaBach1, float); //! DCA of bachelor 1 +DECLARE_SOA_COLUMN(RadiusBach1, radiusBach1, float); //! Radius of bachelor 1 +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); //! flag for decay channel classification reconstruction level +DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); //! debug flag for mis-association at reconstruction level +DECLARE_SOA_COLUMN(Origin, origin, int8_t); //! Flag for origin of MC particle 1=promt, 2=FD +DECLARE_SOA_COLUMN(PtGen, ptGen, float); //! Transverse momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(SignD0, signD0, float); //! Flag to distinguish D0 and D0Bar + +} // namespace hf_cand_reso_lite + +DECLARE_SOA_TABLE(HfCandResoLites, "AOD", "HFCANDRESOLITE", //! Table with some B0 properties + // Candidate Properties + hf_cand_reso_lite::M, + hf_cand_reso_lite::Pt, + hf_cand_reso_lite::P, + hf_cand_reso_lite::Y, + hf_cand_reso_lite::Eta, + hf_cand_reso_lite::Phi, + hf_cand_reso_lite::E, + hf_cand_reso_lite::CosThetaStar, + hf_cand_reso_lite::Sign, + // Bachelors Properties + hf_cand_reso_lite::MBach0, + hf_cand_reso_lite::PtBach0, + hf_cand_reso_lite::MlScoreBkgBach0, + hf_cand_reso_lite::MlScorePromptBach0, + hf_cand_reso_lite::MlScoreNonPromptBach0, + hf_cand_reso_lite::ItsNClsProngMinBach0, + hf_cand_reso_lite::TpcNClsCrossedRowsProngMinBach0, + hf_cand_reso_lite::TpcChi2NClProngMaxBach0, + hf_cand_reso_lite::MBach1, + hf_cand_reso_lite::PtBach1, + hf_cand_reso_lite::CpaBach1, + hf_cand_reso_lite::DcaBach1, + hf_cand_reso_lite::RadiusBach1, + hf_cand_reso_lite::ItsNClsProngMinBach1, + hf_cand_reso_lite::TpcNClsCrossedRowsProngMinBach1, + hf_cand_reso_lite::TpcChi2NClProngMaxBach1, + // MC + hf_cand_reso_lite::FlagMcMatchRec, + hf_cand_reso_lite::DebugMcRec, + hf_cand_reso_lite::Origin, + hf_cand_reso_lite::PtGen, + hf_cand_reso_lite::SignD0); + +DECLARE_SOA_TABLE(HfGenResoLites, "AOD", "HFGENRESOLITE", //! Table with some B0 properties + hf_cand_reso_lite::Pt, + hf_cand_reso_lite::Y, + hf_cand_reso_lite::Origin); + +} // namespace o2::aod + +enum DecayChannel : uint8_t { + Ds1ToDstarK0s = 0, + Ds2StarToDplusK0s, + XcToDplusLambda, + LambdaDminus +}; + +struct HfTaskCharmResoReduced { + Produces hfCandResoLite; + Produces hfGenResoLite; + Configurable ptMinReso{"ptMinReso", -1, "Discard events with smaller pT"}; + Configurable fillTrees{"fillTrees", true, "Fill output Trees"}; + Configurable fillSparses{"fillSparses", false, "Fill output Sparses"}; + Configurable useDeltaMass{"useDeltaMass", true, "Use Delta Mass for resonance invariant Mass calculation"}; + Configurable fillOnlySignal{"fillOnlySignal", false, "Flag to Fill only signal candidates (MC only)"}; + Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen particle rapidity"}; + Configurable yCandRecoMax{"yCandRecoMax", -1, "max. cand. rapidity"}; + Configurable etaTrackMax{"etaTrackMax", 0.8, "max. track pseudo-rapidity for acceptance calculation"}; + Configurable ptTrackMin{"ptTrackMin", 0.1, "min. track transverse momentum for acceptance calculation"}; + Configurable massResoMin{"massResoMin", 0.49, "min. mass of resonance"}; + Configurable massResoMax{"massResoMax", 1.29, "max. mass of resonance"}; + // Configurables axis for histos + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0., 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 8.f, 12.f, 24.f, 50.f}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis axisPtProng0{"axisPtProng0", {VARIABLE_WIDTH, 0., 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 8.f, 12.f, 24.f, 50.f}, "prong0 bach. #it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis axisPtProng1{"axisPtProng1", {VARIABLE_WIDTH, 0., 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 8.f, 12.f, 24.f, 50.f}, "prong1 bach. #it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis axisInvMassReso{"axisInvMassReso", {200, 2.34, 2.74}, "inv. mass (DV_{0}) (GeV/#it{c}^{2})"}; + ConfigurableAxis axisInvMassProng0{"axisInvMassProng0", {175, 1.70, 2.05}, "inv. mass (D) (GeV/#it{c}^{2})"}; + ConfigurableAxis axisInvMassProng1{"axisInvMassProng1", {80, 0.46, 0.54}, "inv. mass ({V}_{0}) (GeV/#it{c}^{2})"}; + ConfigurableAxis axisCosThetaStar{"axisCosThetaStar", {40, -1, 1}, "cos(#vartheta*)"}; + ConfigurableAxis axisBkgBdtScore{"axisBkgBdtScore", {100, 0, 1}, "bkg BDT Score"}; + ConfigurableAxis axisNonPromptBdtScore{"axisNonPromptBdtScore", {100, 0, 1}, "non-prompt BDT Score"}; + ConfigurableAxis axisEta{"axisEta", {30, -1.5, 1.5}, "pseudorapidity"}; + ConfigurableAxis axisOrigin{"axisOrigin", {3, -0.5, 2.5}, "origin"}; + ConfigurableAxis axisFlag{"axisFlag", {65, -32.5, 32.5}, "mc flag"}; + + using ReducedReso = soa::Join; + using ReducedResoWithMl = soa::Join; + using ReducedResoMc = soa::Join; + using ReducedResoWithMlMc = soa::Join; + + // Histogram Registry + HistogramRegistry registry; + + // init + void init(InitContext&) + { + registry.add("hMass", "Charm resonance candidates inv. mass", {HistType::kTH1F, {axisInvMassReso}}); + registry.add("hMassProng0", "D daughters inv. mass", {HistType::kTH1F, {axisInvMassProng0}}); + registry.add("hMassProng1", "V0 daughter inv. mass", {HistType::kTH1F, {axisInvMassProng1}}); + registry.add("hPt", "Charm resonance candidates pT", {HistType::kTH1F, {axisPt}}); + registry.add("hPtProng0", "D daughters pT", {HistType::kTH1F, {axisPtProng0}}); + registry.add("hPtProng1", "V0 daughter pT", {HistType::kTH1F, {axisPtProng1}}); + registry.add("hNPvCont", "Collision number of PV contributors ; N contrib ; entries", {HistType::kTH1F, {{125, -0.5, 249.5}}}); + registry.add("hZvert", "Collision Z Vtx ; z PV [cm] ; entries", {HistType::kTH1F, {{120, -12., 12.}}}); + registry.add("hBz", "Collision Bz ; Bz [T] ; entries", {HistType::kTH1F, {{20, -10., 10.}}}); + registry.add("hSparse", "THn for production studies with cosThStar and BDT scores", HistType::kTHnSparseF, {axisPt, axisPtProng0, axisPtProng1, axisInvMassReso, axisInvMassProng0, axisInvMassProng1, axisCosThetaStar, axisBkgBdtScore, axisNonPromptBdtScore}); + + if (doprocessDs1Mc || doprocessDs2StarMc || doprocessDs1McWithMl || doprocessDs2StarMcWithMl) { + // gen histos + registry.add("hYRecPrompt", "Charm resonance candidates pT", {HistType::kTH2F, {axisPt, axisEta}}); + registry.add("hYRecNonPrompt", "Charm resonance candidates pT", {HistType::kTH2F, {axisPt, axisEta}}); + registry.add("hYGenPrompt", "Prompt {D_{S}}^j particles (generated);#it{p}_{T}^{gen}({D_{S}}^j) (GeV/#it{c});#it{y}^{gen}({D_{S}}^j);entries", {HistType::kTH2F, {axisPt, axisEta}}); + registry.add("hYGenPromptWithProngsInAcceptance", "Prompt {D_{S}}^j particles (generated-daughters in acceptance);#it{p}_{T}^{gen}({D_{S}}^j) (GeV/#it{c});#it{y}^{gen}({D_{S}}^j);entries", {HistType::kTH2F, {axisPt, axisEta}}); + registry.add("hYGenNonPrompt", "NonPrompt {D_{S}}^j particles (generated);#it{p}_{T}^{gen}({D_{S}}^j) (GeV/#it{c});#it{y}^{gen}({D_{S}}^j);entries", {HistType::kTH2F, {axisPt, axisEta}}); + registry.add("hYGenNonPromptWithProngsInAcceptance", "NonPrompt {D_{S}}^j particles (generated-daughters in acceptance);#it{p}_{T}^{gen}({D_{S}}^j) (GeV/#it{c});#it{y}^{gen}({D_{S}}^j);entries", {HistType::kTH2F, {axisPt, axisEta}}); + if (fillSparses) { + registry.add("hPtYGenSig", "{D_{S}}^j particles (generated);#it{p}_{T}({D_{S}}^j) (GeV/#it{c});#it{y}({D_{S}}^j)", {HistType::kTHnSparseF, {axisPt, axisEta, axisOrigin, axisFlag}}); + registry.add("hPtYWithProngsInAccepanceGenSig", "{D_{S}}^j particles (generated-daughters in acceptance);#it{p}_{T}({D_{S}}^j) (GeV/#it{c});#it{y}({D_{S}}^j)", {HistType::kTHnSparseF, {axisPt, axisEta, axisOrigin, axisFlag}}); + } + } + } + + // Fill histograms + /// \tparam channel is the decay channel of the Resonance + /// \param candidate is a candidate + /// \param coll is a reduced collision + /// \param bach0 is a bachelor of the candidate + /// \param bach1 is a bachelor of the candidate + template + void fillCand(const Cand& candidate, const Coll& collision, const CharmBach& bach0, const V0Bach& bach1) + { + // Compute quantities to be saved + float invMassReso{0}, pdgMassReso, invMassBach0, invMassBach1, pdgMassBach0, pdgMassBach1, sign, invMassD0, cosThetaStar; + if (channel == DecayChannel::Ds1ToDstarK0s) { + pdgMassReso = MassDS1; + pdgMassBach0 = MassDStar; + pdgMassBach1 = MassK0; + invMassBach1 = bach1.invMassK0s(); + cosThetaStar = candidate.cosThetaStarDs1(); + if (bach0.dType() > 0) { + invMassBach0 = bach0.invMassDstar(); + invMassD0 = bach0.invMassD0(); + sign = 1; + if (useDeltaMass) { + invMassReso = RecoDecay::m(std::array{bach0.pVectorProng0(), bach0.pVectorProng1(), bach0.pVectorProng2(), bach1.pVector()}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassK0}); + } + } else { + invMassBach0 = bach0.invMassAntiDstar(); + invMassD0 = bach0.invMassD0Bar(); + sign = -1; + if (useDeltaMass) { + invMassReso = RecoDecay::m(std::array{bach0.pVectorProng1(), bach0.pVectorProng0(), bach0.pVectorProng2(), bach1.pVector()}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassK0}); + } + } + } else if (channel == DecayChannel::Ds2StarToDplusK0s) { + pdgMassReso = MassDS2Star; + pdgMassBach0 = MassDPlus; + pdgMassBach1 = MassK0; + invMassBach0 = bach0.invMassDplus(); + invMassD0 = 0; + invMassBach1 = bach1.invMassK0s(); + cosThetaStar = candidate.cosThetaStarDs2Star(); + if (useDeltaMass) { + invMassReso = RecoDecay::m(std::array{bach0.pVectorProng0(), bach0.pVectorProng1(), bach0.pVectorProng2(), bach1.pVector()}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassK0}); + } + if (bach0.dType() > 0) { + sign = 1; + } else { + sign = -1; + } + } + float y = RecoDecay::y(std::array{candidate.px(), candidate.py(), candidate.pz()}, pdgMassReso); + float eta = RecoDecay::eta(std::array{candidate.px(), candidate.py(), candidate.pz()}); + float phi = RecoDecay::phi(candidate.px(), candidate.py()); + float p = RecoDecay::p(std::array{candidate.px(), candidate.py(), candidate.pz()}); + float e = RecoDecay::e(std::array{candidate.px(), candidate.py(), candidate.pz()}, pdgMassReso); + if (useDeltaMass) { + invMassReso = invMassReso - invMassBach0; + } else { + invMassReso = RecoDecay::m(std::array{bach0.pVector(), bach1.pVector()}, std::array{pdgMassBach0, pdgMassBach1}); + } + if (invMassReso < massResoMin || invMassReso > massResoMax) { + return; + } + invMassBach0 = invMassBach0 - invMassD0; + float ptGen{-1.}; + int8_t origin{-1}, flagMcMatchRec{-1}, debugMcRec{-1}, signD0{0}; + if constexpr (doMc) { + ptGen = candidate.ptMother(); + origin = candidate.origin(); + flagMcMatchRec = candidate.flagMcMatchRec(); + debugMcRec = candidate.debugMcRec(); + if (fillOnlySignal) { + if (channel == DecayChannel::Ds1ToDstarK0s && !(std::abs(flagMcMatchRec) == DecayTypeMc::Ds1ToDStarK0ToD0PiK0s || std::abs(flagMcMatchRec) == DecayTypeMc::Ds1ToDStarK0ToD0PiK0sPart || std::abs(flagMcMatchRec) == DecayTypeMc::Ds1ToDStarK0ToD0NoPiK0sPart || std::abs(flagMcMatchRec) == DecayTypeMc::Ds1ToDStarK0ToD0PiK0sOneMu)) { + return; + } + if (channel == DecayChannel::Ds2StarToDplusK0s && !(std::abs(flagMcMatchRec) == DecayTypeMc::Ds2StarToDplusK0sToPiKaPiPiPi || std::abs(flagMcMatchRec) == DecayTypeMc::Ds2StarToDplusK0sOneMu)) { + return; + } + } + if (origin == 1) { + registry.fill(HIST("hYRecPrompt"), candidate.pt(), y); + } else if (origin == 2) { + registry.fill(HIST("hYRecNonPrompt"), candidate.pt(), y); + } + } + float mlScoreBkg{-1.}, mlScorePrompt{-1.}, mlScoreNonPrompt{-1.}; + if constexpr (withMl) { + mlScoreBkg = bach0.mlScoreBkgMassHypo0(); + mlScorePrompt = bach0.mlScorePromptMassHypo0(); + mlScoreNonPrompt = bach0.mlScoreNonpromptMassHypo0(); + } + // Collision properties + registry.fill(HIST("hNPvCont"), collision.numContrib()); + registry.fill(HIST("hZvert"), collision.posZ()); + registry.fill(HIST("hBz"), collision.bz()); + // Candidate properties + registry.fill(HIST("hMass"), invMassReso); + registry.fill(HIST("hMassProng0"), invMassBach0); + registry.fill(HIST("hMassProng1"), invMassBach1); + registry.fill(HIST("hPt"), candidate.pt()); + registry.fill(HIST("hPtProng0"), candidate.ptProng0()); + registry.fill(HIST("hPtProng1"), candidate.ptProng1()); + if (fillSparses) { + registry.fill(HIST("hSparse"), candidate.pt(), candidate.ptProng0(), candidate.ptProng1(), invMassReso, invMassBach0, invMassBach1, cosThetaStar, mlScoreBkg, mlScoreNonPrompt); + } + + if (fillTrees) { + hfCandResoLite( + invMassReso, + candidate.pt(), + p, + y, + eta, + phi, + e, + cosThetaStar, + sign, + // Bachelors Properties + invMassBach0, + bach0.pt(), + mlScoreBkg, + mlScorePrompt, + mlScoreNonPrompt, + bach0.itsNClsProngMin(), + bach0.tpcNClsCrossedRowsProngMin(), + bach0.tpcChi2NClProngMax(), + invMassBach1, + bach1.pt(), + bach1.cpa(), + bach1.dca(), + bach1.v0Radius(), + bach1.itsNClsProngMin(), + bach1.tpcNClsCrossedRowsProngMin(), + bach1.tpcChi2NClProngMax(), + // MC + flagMcMatchRec, + debugMcRec, + origin, + ptGen, + signD0); + } + } // fillCand + + // Process data + /// \tparam channel is the decay channel of the Resonance + /// \param Coll is the reduced collisions table + /// \param CharmBach is the reduced 3 prong table + /// \param V0Bach is the reduced v0 table + /// \param Cand is the candidates table + template + void processData(Coll const&, Candidates const& candidates, CharmBach const&, aod::HfRedVzeros const&) + { + for (const auto& cand : candidates) { + if (ptMinReso >= 0 && cand.pt() < ptMinReso) { + continue; + } + float pdgMassReso{0}; + if (channel == DecayChannel::Ds1ToDstarK0s) { + pdgMassReso = MassDS1; + } else if (channel == DecayChannel::Ds2StarToDplusK0s) { + pdgMassReso = MassDS2Star; + } + if (yCandRecoMax >= 0. && std::abs(RecoDecay::y(std::array{cand.px(), cand.py(), cand.pz()}, pdgMassReso)) > yCandRecoMax) { + continue; + } + auto coll = cand.template hfRedCollision_as(); + auto bach0 = cand.template prong0_as(); + auto bach1 = cand.template prong1_as(); + fillCand(cand, coll, bach0, bach1); + } + } + + /// Selection of resonance daughters in geometrical acceptance + /// \param etaProng is the pseudorapidity of Resonance prong + /// \param ptProng is the pT of Resonance prong + /// \return true if prong is in geometrical acceptance + template + bool isProngInAcceptance(const T& etaProng, const T& ptProng) + { + return std::abs(etaProng) <= etaTrackMax && ptProng >= ptTrackMin; + } + + /// Fill particle histograms (gen MC truth) + template + void fillCandMcGen(aod::HfMcGenRedResos const& mcParticles) + { + for (const auto& particle : mcParticles) { + auto ptParticle = particle.ptTrack(); + auto yParticle = particle.yTrack(); + auto originParticle = particle.origin(); + auto flag = particle.flagMcMatchGen(); + if (yCandGenMax >= 0. && std::abs(yParticle) > yCandGenMax) { + continue; + } + std::array ptProngs = {particle.ptProng0(), particle.ptProng1()}; + std::array etaProngs = {particle.etaProng0(), particle.etaProng1()}; + bool prongsInAcc = isProngInAcceptance(etaProngs[0], ptProngs[0]) && isProngInAcceptance(etaProngs[1], ptProngs[1]); + if ((channel == DecayChannel::Ds1ToDstarK0s && std::abs(flag) == DecayTypeMc::Ds1ToDStarK0ToD0PiK0s) || + (channel == DecayChannel::Ds2StarToDplusK0s && std::abs(flag) == DecayTypeMc::Ds2StarToDplusK0sToPiKaPiPiPi)) { + if (originParticle == 1) { // prompt particles + registry.fill(HIST("hYGenPrompt"), ptParticle, yParticle); + if (prongsInAcc) { + registry.fill(HIST("hYGenPromptWithProngsInAcceptance"), ptParticle, yParticle); + } + } else if (originParticle == 2) { + registry.fill(HIST("hYGenNonPrompt"), ptParticle, yParticle); + if (prongsInAcc) { + registry.fill(HIST("hYGenNonPromptWithProngsInAcceptance"), ptParticle, yParticle); + } + } + } + if (fillSparses) { + registry.fill(HIST("hPtYGenSig"), ptParticle, yParticle, originParticle, flag); + if (prongsInAcc) { + registry.fill(HIST("hPtYWithProngsInAccepanceGenSig"), ptParticle, yParticle, originParticle, flag); + } + } + if (fillTrees) { + hfGenResoLite(ptParticle, yParticle, originParticle); + } + } + } // fillCandMcGen + + // process functions + + void processDs1Data(aod::HfRedCollisions const& collisions, ReducedReso const& candidates, aod::HfRed3PrNoTrks const& charmBachs, aod::HfRedVzeros const& v0Bachs) + { + processData(collisions, candidates, charmBachs, v0Bachs); + } + PROCESS_SWITCH(HfTaskCharmResoReduced, processDs1Data, "Process data for Ds1 analysis without Ml", true); + + void processDs1DataWithMl(aod::HfRedCollisions const& collisions, ReducedResoWithMl const& candidates, soa::Join const& charmBachs, aod::HfRedVzeros const& v0Bachs) + { + processData(collisions, candidates, charmBachs, v0Bachs); + } + PROCESS_SWITCH(HfTaskCharmResoReduced, processDs1DataWithMl, "Process data for Ds1 analysis with Ml", false); + + void processDs2StarData(aod::HfRedCollisions const& collisions, ReducedReso const& candidates, aod::HfRed3PrNoTrks const& charmBachs, aod::HfRedVzeros const& v0Bachs) + { + processData(collisions, candidates, charmBachs, v0Bachs); + } + PROCESS_SWITCH(HfTaskCharmResoReduced, processDs2StarData, "Process data Ds2Star analysis without Ml", false); + + void processDs2StarDataWithMl(aod::HfRedCollisions const& collisions, ReducedResoWithMl const& candidates, soa::Join const& charmBachs, aod::HfRedVzeros const& v0Bachs) + { + processData(collisions, candidates, charmBachs, v0Bachs); + } + PROCESS_SWITCH(HfTaskCharmResoReduced, processDs2StarDataWithMl, "Process data Ds2Star analysis with Ml", false); + + void processDs1Mc(aod::HfRedCollisions const& collisions, ReducedResoMc const& candidates, aod::HfMcGenRedResos const& mcParticles, aod::HfRed3PrNoTrks const& charmBachs, aod::HfRedVzeros const& v0Bachs) + { + processData(collisions, candidates, charmBachs, v0Bachs); + fillCandMcGen(mcParticles); + } + PROCESS_SWITCH(HfTaskCharmResoReduced, processDs1Mc, "Process Mc for Ds1 analysis without Ml", false); + + void processDs1McWithMl(aod::HfRedCollisions const& collisions, ReducedResoWithMlMc const& candidates, aod::HfMcGenRedResos const& mcParticles, soa::Join const& charmBachs, aod::HfRedVzeros const& v0Bachs) + { + processData(collisions, candidates, charmBachs, v0Bachs); + fillCandMcGen(mcParticles); + } + PROCESS_SWITCH(HfTaskCharmResoReduced, processDs1McWithMl, "Process Mc for Ds1 analysis with Ml", false); + + void processDs2StarMc(aod::HfRedCollisions const& collisions, ReducedResoMc const& candidates, aod::HfMcGenRedResos const& mcParticles, aod::HfRed3PrNoTrks const& charmBachs, aod::HfRedVzeros const& v0Bachs) + { + processData(collisions, candidates, charmBachs, v0Bachs); + fillCandMcGen(mcParticles); + } + PROCESS_SWITCH(HfTaskCharmResoReduced, processDs2StarMc, "Process Mc for Ds2Star analysis without Ml", false); + + void processDs2StarMcWithMl(aod::HfRedCollisions const& collisions, ReducedResoWithMlMc const& candidates, aod::HfMcGenRedResos const& mcParticles, soa::Join const& charmBachs, aod::HfRedVzeros const& v0Bachs) + { + processData(collisions, candidates, charmBachs, v0Bachs); + fillCandMcGen(mcParticles); + } + PROCESS_SWITCH(HfTaskCharmResoReduced, processDs2StarMcWithMl, "Process Mc for Ds2Star analysis with Ml", false); + +}; // struct HfTaskCharmResoReduced +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 84edf213c89..0db5a832135 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -15,28 +15,38 @@ /// \author Gian Michele Innocenti , CERN /// \author Vít Kučera , CERN +#include +#include // std::min + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" +#include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsAnalysis.h" using namespace o2; using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::hf_centrality; +using namespace o2::hf_occupancy; /// D0 analysis task namespace { enum CandTypeSel { - SigD0 = 0, // Signal D0 - SigD0bar, // Signal D0bar - ReflectedD0, // Reflected D0 - ReflectedD0bar // Reflected D0bar + SigD0 = 0, // Signal D0 + SigD0bar, // Signal D0bar + ReflectedD0, // Reflected D0 + ReflectedD0bar, // Reflected D0bar + PureSigD0, // Signal D0 exclude Reflected D0bar + PureSigD0bar // Signal D0bar exclude Reflected D0 }; } // namespace struct HfTaskD0 { @@ -49,20 +59,17 @@ struct HfTaskD0 { Configurable selectionCand{"selectionCand", 1, "Selection Flag for conj. topol. selected candidates"}; Configurable selectionPid{"selectionPid", 1, "Selection Flag for reco PID candidates"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits"}; + Configurable centEstimator{"centEstimator", 0, "Centrality estimation (None: 0, FT0C: 2, FT0M: 3)"}; + Configurable occEstimator{"occEstimator", 0, "Occupancy estimation (None: 0, ITS: 1, FT0C: 2)"}; + Configurable storeCentrality{"storeCentrality", false, "Flag to store centrality information"}; + Configurable storeOccupancy{"storeOccupancy", false, "Flag to store occupancy information"}; + Configurable storeTrackQuality{"storeTrackQuality", false, "Flag to store track quality information"}; // ML inference Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; - // ThnSparse for ML outputScores and Vars - ConfigurableAxis thnConfigAxisBkgScore{"thnConfigAxisBkgScore", {50, 0, 1}, "Bkg score bins"}; - ConfigurableAxis thnConfigAxisNonPromptScore{"thnConfigAxisNonPromptScore", {50, 0, 1}, "Non-prompt score bins"}; - ConfigurableAxis thnConfigAxisMass{"thnConfigAxisMass", {120, 1.5848, 2.1848}, "Cand. inv-mass bins"}; - ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {120, 0, 24}, "Cand. pT bins"}; - ConfigurableAxis thnConfigAxisY{"thnConfigAxisY", {20, -1, 1}, "Cand. rapidity bins"}; - ConfigurableAxis thnConfigAxisOrigin{"thnConfigAxisOrigin", {3, -0.5, 2.5}, "Cand. origin type"}; - ConfigurableAxis thnConfigAxisCandType{"thnConfigAxisCandType", {4, -0.5, 3.5}, "D0 type"}; - HfHelper hfHelper; + SliceCache cache; using D0Candidates = soa::Join; using D0CandidatesMc = soa::Join; using D0CandidatesKF = soa::Join; @@ -73,6 +80,14 @@ struct HfTaskD0 { using D0CandidatesMlKF = soa::Join; using D0CandidatesMlMcKF = soa::Join; + using Collisions = soa::Join; + using CollisionsCent = soa::Join; + using CollisionsWithMcLabels = soa::Join; + using CollisionsWithMcLabelsCent = soa::Join; + using TracksSelQuality = soa::Join; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + PresliceUnsorted colPerMcCollisionCent = aod::mccollisionlabel::mcCollisionId; + Partition selectedD0Candidates = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlagD0 || aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlagD0bar; Partition selectedD0CandidatesKF = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlagD0 || aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlagD0bar; Partition selectedD0CandidatesMc = aod::hf_sel_candidate_d0::isRecoHfFlag >= selectionFlagHf; @@ -83,6 +98,24 @@ struct HfTaskD0 { Partition selectedD0CandidatesMlMc = aod::hf_sel_candidate_d0::isRecoHfFlag >= selectionFlagHf; Partition selectedD0CandidatesMlMcKF = aod::hf_sel_candidate_d0::isRecoHfFlag >= selectionFlagHf; + // ThnSparse for ML outputScores and Vars + ConfigurableAxis thnConfigAxisBkgScore{"thnConfigAxisBkgScore", {50, 0, 1}, "Bkg score bins"}; + ConfigurableAxis thnConfigAxisNonPromptScore{"thnConfigAxisNonPromptScore", {50, 0, 1}, "Non-prompt score bins"}; + ConfigurableAxis thnConfigAxisPromptScore{"thnConfigAxisPromptScore", {50, 0, 1}, "Prompt score bins"}; + ConfigurableAxis thnConfigAxisMass{"thnConfigAxisMass", {120, 1.5848, 2.1848}, "Cand. inv-mass bins"}; + ConfigurableAxis thnConfigAxisPtB{"thnConfigAxisPtB", {1000, 0, 100}, "Cand. beauty mother pTB bins"}; + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {500, 0, 50}, "Cand. pT bins"}; + ConfigurableAxis thnConfigAxisY{"thnConfigAxisY", {20, -1, 1}, "Cand. rapidity bins"}; + ConfigurableAxis thnConfigAxisOrigin{"thnConfigAxisOrigin", {3, -0.5, 2.5}, "Cand. origin type"}; + ConfigurableAxis thnConfigAxisCandType{"thnConfigAxisCandType", {6, -0.5, 5.5}, "D0 type"}; + ConfigurableAxis thnConfigAxisGenPtD{"thnConfigAxisGenPtD", {500, 0, 50}, "Gen Pt D"}; + ConfigurableAxis thnConfigAxisGenPtB{"thnConfigAxisGenPtB", {1000, 0, 100}, "Gen Pt B"}; + ConfigurableAxis thnConfigAxisNumPvContr{"thnConfigAxisNumPvContr", {200, -0.5, 199.5}, "Number of PV contributors"}; + ConfigurableAxis thnConfigAxisCent{"thnConfigAxisCent", {110, 0., 110.}, ""}; + ConfigurableAxis thnConfigAxisOccupancy{"thnConfigAxisOccupancy", {14, 0, 14000}, "axis for centrality"}; + ConfigurableAxis thnConfigAxisMinItsNCls{"thnConfigAxisMinItsNCls", {5, 3, 8}, "axis for minimum ITS NCls of candidate prongs"}; + ConfigurableAxis thnConfigAxisMinTpcNCrossedRows{"thnConfigAxisMinTpcNCrossedRows", {10, 70, 180}, "axis for minimum TPC NCls crossed rows of candidate prongs"}; + HistogramRegistry registry{ "registry", {{"hPtCand", "2-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, @@ -161,14 +194,16 @@ struct HfTaskD0 { void init(InitContext&) { - std::array doprocess{doprocessDataWithDCAFitterN, doprocessDataWithKFParticle, doprocessMcWithDCAFitterN, doprocessMcWithKFParticle, doprocessDataWithDCAFitterNMl, doprocessDataWithKFParticleMl, doprocessMcWithDCAFitterNMl, doprocessMcWithKFParticleMl}; + std::array doprocess{doprocessDataWithDCAFitterN, doprocessDataWithDCAFitterNCent, doprocessDataWithKFParticle, doprocessMcWithDCAFitterN, doprocessMcWithDCAFitterNCent, doprocessMcWithKFParticle, doprocessDataWithDCAFitterNMl, doprocessDataWithDCAFitterNMlCent, doprocessDataWithKFParticleMl, doprocessMcWithDCAFitterNMl, doprocessMcWithDCAFitterNMlCent, doprocessMcWithKFParticleMl}; if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) == 0) { LOGP(fatal, "At least one process function should be enabled at a time."); } - if ((doprocessDataWithDCAFitterN || doprocessMcWithDCAFitterN || doprocessDataWithDCAFitterNMl || doprocessMcWithDCAFitterNMl) && (doprocessDataWithKFParticle || doprocessMcWithKFParticle || doprocessDataWithKFParticleMl || doprocessMcWithKFParticleMl)) { + if ((doprocessDataWithDCAFitterN || doprocessDataWithDCAFitterNCent || doprocessMcWithDCAFitterN || doprocessMcWithDCAFitterNCent || doprocessDataWithDCAFitterNMl || doprocessDataWithDCAFitterNMlCent || doprocessMcWithDCAFitterNMl || doprocessMcWithDCAFitterNMlCent) && (doprocessDataWithKFParticle || doprocessMcWithKFParticle || doprocessDataWithKFParticleMl || doprocessMcWithKFParticleMl)) { LOGP(fatal, "DCAFitterN and KFParticle can not be enabled at a time."); } - + if ((storeCentrality || storeOccupancy) && !(doprocessDataWithDCAFitterNCent || doprocessMcWithDCAFitterNCent || doprocessDataWithDCAFitterNMlCent || doprocessMcWithDCAFitterNMlCent)) { + LOGP(fatal, "Can't enable the storeCentrality and storeOccupancu without cent process"); + } auto vbins = (std::vector)binsPt; registry.add("hMass", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{500, 0., 5.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("hMassVsPhi", "2-prong candidates vs phi;inv. mass (#pi K) (GeV/#it{c}^{2});phi (rad);entries", {HistType::kTH3F, {{120, 1.5848, 2.1848}, {vbins, "#it{p}_{T} (GeV/#it{c})"}, {32, 0, o2::constants::math::TwoPI}}}); @@ -208,22 +243,71 @@ struct HfTaskD0 { registry.add("hDecLengthVsPtSig", "2-prong candidates;decay length (cm) vs #it{p}_{T} for signal;entries", {HistType::kTH2F, {{800, 0., 4.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("hDecLengthxyVsPtSig", "2-prong candidates;decay length xy (cm) vs #it{p}_{T} for signal;entries", {HistType::kTH2F, {{800, 0., 4.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + const AxisSpec thnAxisMass{thnConfigAxisMass, "inv. mass (#pi K) (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisPt{thnConfigAxisPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisPtB{thnConfigAxisPtB, "#it{p}_{T}^{B} (GeV/#it{c})"}; + const AxisSpec thnAxisY{thnConfigAxisY, "y"}; + const AxisSpec thnAxisOrigin{thnConfigAxisOrigin, "Origin"}; + const AxisSpec thnAxisCandType{thnConfigAxisCandType, "D0 type"}; + const AxisSpec thnAxisGenPtD{thnConfigAxisGenPtD, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisGenPtB{thnConfigAxisGenPtB, "#it{p}_{T}^{B} (GeV/#it{c})"}; + const AxisSpec thnAxisNumPvContr{thnConfigAxisNumPvContr, "Number of PV contributors"}; + const AxisSpec thnAxisCent{thnConfigAxisCent, "Centrality"}; + const AxisSpec thnAxisOccupancy{thnConfigAxisOccupancy, "Occupancy"}; + const AxisSpec thnAxisMinItsNCls{thnConfigAxisMinItsNCls, "Minimum ITS cluster found"}; + const AxisSpec thnAxisMinTpcNCrossedRows{thnConfigAxisMinTpcNCrossedRows, "Minimum TPC crossed rows"}; + + if (doprocessMcWithDCAFitterN || doprocessMcWithDCAFitterNCent || doprocessMcWithKFParticle || doprocessMcWithDCAFitterNMl || doprocessMcWithDCAFitterNMlCent || doprocessMcWithKFParticleMl) { + std::vector axesAcc = {thnAxisGenPtD, thnAxisGenPtB, thnAxisY, thnAxisOrigin, thnAxisNumPvContr}; + + if (storeCentrality) { + axesAcc.push_back(thnAxisCent); + } + if (storeOccupancy) { + axesAcc.push_back(thnAxisOccupancy); + } + + registry.add("hSparseAcc", "Thn for generated D0 from charm and beauty", HistType::kTHnSparseD, axesAcc); + registry.get(HIST("hSparseAcc"))->Sumw2(); + } + + std::vector axes = {thnAxisMass, thnAxisPt, thnAxisY, thnAxisCandType}; + if (doprocessMcWithDCAFitterN || doprocessMcWithDCAFitterNCent || doprocessMcWithKFParticle || doprocessMcWithDCAFitterNMl || doprocessMcWithDCAFitterNMlCent || doprocessMcWithKFParticleMl) { + axes.push_back(thnAxisPtB); + axes.push_back(thnAxisOrigin); + axes.push_back(thnAxisNumPvContr); + } + if (storeCentrality) { + axes.push_back(thnAxisCent); + } + if (storeOccupancy) { + axes.push_back(thnAxisOccupancy); + } + if (storeTrackQuality) { + axes.push_back(thnAxisMinItsNCls); + axes.push_back(thnAxisMinTpcNCrossedRows); + } if (applyMl) { const AxisSpec thnAxisBkgScore{thnConfigAxisBkgScore, "BDT score bkg."}; const AxisSpec thnAxisNonPromptScore{thnConfigAxisNonPromptScore, "BDT score non-prompt."}; - const AxisSpec thnAxisMass{thnConfigAxisMass, "inv. mass (#pi K) (GeV/#it{c}^{2})"}; - const AxisSpec thnAxisPt{thnConfigAxisPt, "#it{p}_{T} (GeV/#it{c})"}; - const AxisSpec thnAxisY{thnConfigAxisY, "y"}; - const AxisSpec thnAxisOrigin{thnConfigAxisOrigin, "Origin"}; - const AxisSpec thnAxisCandType{thnConfigAxisCandType, "D0 type"}; - - registry.add("hBdtScoreVsMassVsPtVsYVsOriginVsD0Type", "Thn for D0 candidates with BDT scores", HistType::kTHnSparseD, {thnAxisBkgScore, thnAxisNonPromptScore, thnAxisMass, thnAxisPt, thnAxisY, thnAxisOrigin, thnAxisCandType}); - registry.get(HIST("hBdtScoreVsMassVsPtVsYVsOriginVsD0Type"))->Sumw2(); + const AxisSpec thnAxisPromptScore{thnConfigAxisPromptScore, "BDT score prompt."}; + + axes.insert(axes.begin(), thnAxisPromptScore); + axes.insert(axes.begin(), thnAxisNonPromptScore); + axes.insert(axes.begin(), thnAxisBkgScore); + + registry.add("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type", "Thn for D0 candidates", HistType::kTHnSparseD, axes); + registry.get(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"))->Sumw2(); + } else { + registry.add("hMassVsPtVsPtBVsYVsOriginVsD0Type", "Thn for D0 candidates", HistType::kTHnSparseD, axes); + registry.get(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"))->Sumw2(); } } - template - void processData(CandType const& candidates) + template + void processData(CandType const& candidates, + CollType const&, + aod::TracksWExtra const&) { for (const auto& candidate : candidates) { if (!(candidate.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { @@ -282,44 +366,163 @@ struct HfTaskD0 { registry.fill(HIST("hCPAFinerBinning"), candidate.cpa(), ptCandidate); registry.fill(HIST("hCPAXYFinerBinning"), candidate.cpaXY(), ptCandidate); + float cent{-1.f}; + float occ{-1.f}; + if (storeCentrality || storeOccupancy) { + auto collision = candidate.template collision_as(); + if (storeCentrality && centEstimator != CentralityEstimator::None) { + cent = getCentralityColl(collision, centEstimator); + } + if (storeOccupancy && occEstimator != OccupancyEstimator::None) { + occ = getOccupancyColl(collision, occEstimator); + } + } + + auto trackPos = candidate.template prong0_as(); // positive daughter + auto trackNeg = candidate.template prong1_as(); // negative daughter + int minItsClustersOfProngs = std::min(trackPos.itsNCls(), trackNeg.itsNCls()); + int minTpcCrossedRowsOfProngs = std::min(trackPos.tpcNClsCrossedRows(), trackNeg.tpcNClsCrossedRows()); if constexpr (applyMl) { - if (candidate.isSelD0() >= selectionFlagD0) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], massD0, ptCandidate, hfHelper.yD0(candidate), 0, SigD0); + if (storeCentrality && storeOccupancy) { + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, hfHelper.yD0(candidate), SigD0, cent, occ); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, cent, occ); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, hfHelper.yD0(candidate), SigD0bar, cent, occ); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar, cent, occ); + } + } else if (storeCentrality && !storeOccupancy) { + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, hfHelper.yD0(candidate), SigD0, cent); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, cent); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, hfHelper.yD0(candidate), SigD0bar, cent); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar, cent); + } + } else if (!storeCentrality && storeOccupancy) { + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, hfHelper.yD0(candidate), SigD0, occ); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, occ); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, hfHelper.yD0(candidate), SigD0bar, occ); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar, occ); + } + } else if (storeTrackQuality) { + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, hfHelper.yD0(candidate), SigD0, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, hfHelper.yD0(candidate), SigD0bar, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + } + } else { + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, hfHelper.yD0(candidate), SigD0); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, hfHelper.yD0(candidate), SigD0bar); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar); + } } - if (candidate.isSelD0bar() >= selectionFlagD0bar) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], massD0bar, ptCandidate, hfHelper.yD0(candidate), 0, SigD0bar); + } else { + if (storeCentrality && storeOccupancy) { + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, hfHelper.yD0(candidate), SigD0, cent, occ); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, cent, occ); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, hfHelper.yD0(candidate), SigD0bar, cent, occ); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar, cent, occ); + } + } else if (storeCentrality && !storeOccupancy) { + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, hfHelper.yD0(candidate), SigD0, cent); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, cent); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, hfHelper.yD0(candidate), SigD0bar, cent); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar, cent); + } + } else if (!storeCentrality && storeOccupancy) { + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, hfHelper.yD0(candidate), SigD0, occ); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, occ); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, hfHelper.yD0(candidate), SigD0bar, occ); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar, occ); + } + } else if (storeTrackQuality) { + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, hfHelper.yD0(candidate), SigD0, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, hfHelper.yD0(candidate), SigD0bar); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar); + } + } else { + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, hfHelper.yD0(candidate), SigD0); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, hfHelper.yD0(candidate), SigD0bar); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, hfHelper.yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar); + } } } } } - void processDataWithDCAFitterN(D0Candidates const&) + void processDataWithDCAFitterN(D0Candidates const&, Collisions const& collisions, aod::TracksWExtra const& tracks) { - processData(selectedD0Candidates); + processData(selectedD0Candidates, collisions, tracks); } PROCESS_SWITCH(HfTaskD0, processDataWithDCAFitterN, "process taskD0 with DCAFitterN", true); - void processDataWithKFParticle(D0CandidatesKF const&) + void processDataWithDCAFitterNCent(D0Candidates const&, CollisionsCent const& collisions, aod::TracksWExtra const& tracks) + { + processData(selectedD0Candidates, collisions, tracks); + } + PROCESS_SWITCH(HfTaskD0, processDataWithDCAFitterNCent, "process taskD0 with DCAFitterN and centrality", false); + + void processDataWithKFParticle(D0CandidatesKF const&, Collisions const& collisions, aod::TracksWExtra const& tracks) { - processData(selectedD0CandidatesKF); + processData(selectedD0CandidatesKF, collisions, tracks); } PROCESS_SWITCH(HfTaskD0, processDataWithKFParticle, "process taskD0 with KFParticle", false); + // TODO: add processKFParticleCent - void processDataWithDCAFitterNMl(D0CandidatesMl const&) + void processDataWithDCAFitterNMl(D0CandidatesMl const&, Collisions const& collisions, aod::TracksWExtra const& tracks) { - processData(selectedD0CandidatesMl); + processData(selectedD0CandidatesMl, collisions, tracks); } PROCESS_SWITCH(HfTaskD0, processDataWithDCAFitterNMl, "process taskD0 with DCAFitterN and ML selections", false); - void processDataWithKFParticleMl(D0CandidatesMlKF const&) + void processDataWithDCAFitterNMlCent(D0CandidatesMl const&, CollisionsCent const& collisions, aod::TracksWExtra const& tracks) { - processData(selectedD0CandidatesMlKF); + processData(selectedD0CandidatesMl, collisions, tracks); + } + PROCESS_SWITCH(HfTaskD0, processDataWithDCAFitterNMlCent, "process taskD0 with DCAFitterN and ML selections and centrality", false); + + void processDataWithKFParticleMl(D0CandidatesMlKF const&, Collisions const& collisions, aod::TracksWExtra const& tracks) + { + processData(selectedD0CandidatesMlKF, collisions, tracks); } PROCESS_SWITCH(HfTaskD0, processDataWithKFParticleMl, "process taskD0 with KFParticle and ML selections", false); + // TODO: add processKFParticleMlCent - template + template void processMc(CandType const& candidates, soa::Join const& mcParticles, - aod::TracksWMc const&) + TracksSelQuality const&, + CollType const& collisions, + aod::McCollisions const&) { // MC rec. for (const auto& candidate : candidates) { @@ -329,6 +532,17 @@ struct HfTaskD0 { if (yCandRecoMax >= 0. && std::abs(hfHelper.yD0(candidate)) > yCandRecoMax) { continue; } + + float cent{-1.f}; + float occ{-1.f}; + auto collision = candidate.template collision_as(); + auto numPvContributors = collision.numContrib(); + if (storeCentrality && centEstimator != CentralityEstimator::None) { + cent = getCentralityColl(collision, centEstimator); + } + if (storeOccupancy && occEstimator != OccupancyEstimator::None) { + occ = getOccupancyColl(collision, occEstimator); + } float massD0, massD0bar; if constexpr (reconstructionType == aod::hf_cand::VertexerType::KfParticle) { massD0 = candidate.kfGeoMassD0(); @@ -337,13 +551,15 @@ struct HfTaskD0 { massD0 = hfHelper.invMassD0ToPiK(candidate); massD0bar = hfHelper.invMassD0barToKPi(candidate); } + auto trackPos = candidate.template prong0_as(); // positive daughter + auto trackNeg = candidate.template prong1_as(); // negative daughter if (std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { // Get the corresponding MC particle. - auto indexMother = RecoDecay::getMother(mcParticles, candidate.template prong0_as().template mcParticle_as>(), o2::constants::physics::Pdg::kD0, true); + auto indexMother = RecoDecay::getMother(mcParticles, trackPos.template mcParticle_as>(), o2::constants::physics::Pdg::kD0, true); auto particleMother = mcParticles.rawIteratorAt(indexMother); - auto ptGen = particleMother.pt(); // gen. level pT - auto yGen = RecoDecay::y(particleMother.pVector(), o2::constants::physics::MassD0); // gen. level y - registry.fill(HIST("hPtGenSig"), ptGen); // gen. level pT + auto ptGen = particleMother.pt(); // gen. level pT + auto yGen = RecoDecay::y(particleMother.pVector(), o2::constants::physics::MassD0); // gen. level y + registry.fill(HIST("hPtGenSig"), ptGen); // gen. level pT auto ptRec = candidate.pt(); auto yRec = hfHelper.yD0(candidate); if (candidate.isRecoHfFlag() >= selectionFlagHf) { @@ -427,6 +643,8 @@ struct HfTaskD0 { auto ctCandidate = hfHelper.ctD0(candidate); auto cpaCandidate = candidate.cpa(); auto cpaxyCandidate = candidate.cpaXY(); + int minItsClustersOfProngs = std::min(trackPos.itsNCls(), trackNeg.itsNCls()); + int minTpcCrossedRowsOfProngs = std::min(trackPos.tpcNClsCrossedRows(), trackNeg.tpcNClsCrossedRows()); if (candidate.isSelD0() >= selectionFlagD0) { registry.fill(HIST("hMassSigBkgD0"), massD0, ptCandidate, rapidityCandidate); if (candidate.flagMcMatchRec() == (1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { @@ -454,7 +672,29 @@ struct HfTaskD0 { registry.fill(HIST("hDecLengthxyVsPtSig"), declengthxyCandidate, ptCandidate); registry.fill(HIST("hMassSigD0"), massD0, ptCandidate, rapidityCandidate); if constexpr (applyMl) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], massD0, ptCandidate, rapidityCandidate, candidate.originMcRec(), SigD0); + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ); + } else if (storeTrackQuality) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + } else { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + } + } else { + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ); + } else if (storeTrackQuality) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + } else { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + } } } else { registry.fill(HIST("hPtProng0Bkg"), ptProng0, rapidityCandidate); @@ -474,7 +714,29 @@ struct HfTaskD0 { if (candidate.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { registry.fill(HIST("hMassReflBkgD0"), massD0, ptCandidate, rapidityCandidate); if constexpr (applyMl) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], massD0, ptCandidate, rapidityCandidate, candidate.originMcRec(), ReflectedD0); + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ); + } else if (storeTrackQuality) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + } else { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + } + } else { + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ); + } else if (storeTrackQuality) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + } else { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + } } } } @@ -484,14 +746,58 @@ struct HfTaskD0 { if (candidate.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { registry.fill(HIST("hMassSigD0bar"), massD0bar, ptCandidate, rapidityCandidate); if constexpr (applyMl) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], massD0bar, ptCandidate, rapidityCandidate, candidate.originMcRec(), SigD0bar); + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ); + } else if (storeTrackQuality) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + } else { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + } + } else { + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ); + } else if (storeTrackQuality) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + } else { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + } } } else { registry.fill(HIST("hMassBkgD0bar"), massD0bar, ptCandidate, rapidityCandidate); if (candidate.flagMcMatchRec() == (1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { registry.fill(HIST("hMassReflBkgD0bar"), massD0bar, ptCandidate, rapidityCandidate); if constexpr (applyMl) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], massD0bar, ptCandidate, rapidityCandidate, candidate.originMcRec(), ReflectedD0bar); + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ); + } else if (storeTrackQuality) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + } else { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + } + } else { + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ); + } else if (storeTrackQuality) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + } else { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + } } } } @@ -503,18 +809,60 @@ struct HfTaskD0 { if (yCandGenMax >= 0. && std::abs(RecoDecay::y(particle.pVector(), o2::constants::physics::MassD0)) > yCandGenMax) { continue; } + float ptGenB = -1; auto ptGen = particle.pt(); auto yGen = RecoDecay::y(particle.pVector(), o2::constants::physics::MassD0); registry.fill(HIST("hPtGen"), ptGen); registry.fill(HIST("hPtVsYGen"), ptGen, yGen); + + unsigned maxNumContrib = 0; + float cent{-1.f}; + float occ{-1.f}; + if constexpr (std::is_same_v) { + const auto& recoCollsPerMcCollCent = collisions.sliceBy(colPerMcCollisionCent, particle.mcCollision().globalIndex()); + for (const auto& recCol : recoCollsPerMcCollCent) { + maxNumContrib = recCol.numContrib() > maxNumContrib ? recCol.numContrib() : maxNumContrib; + } + if (storeCentrality && centEstimator != CentralityEstimator::None) { + cent = getCentralityGenColl(recoCollsPerMcCollCent, centEstimator); + } + if (storeOccupancy && occEstimator != OccupancyEstimator::None) { + occ = getOccupancyGenColl(recoCollsPerMcCollCent, occEstimator); + } + } else { + const auto& recoCollsPerMcColl = collisions.sliceBy(colPerMcCollision, particle.mcCollision().globalIndex()); + for (const auto& recCol : recoCollsPerMcColl) { + maxNumContrib = recCol.numContrib() > maxNumContrib ? recCol.numContrib() : maxNumContrib; + } + } + if (particle.originMcGen() == RecoDecay::OriginType::Prompt) { registry.fill(HIST("hPtGenPrompt"), ptGen); registry.fill(HIST("hYGenPrompt"), yGen); registry.fill(HIST("hPtVsYGenPrompt"), ptGen, yGen); + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 1, maxNumContrib, cent, occ); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 1, maxNumContrib, cent); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 1, maxNumContrib, occ); + } else { + registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 1, maxNumContrib); + } } else { + ptGenB = mcParticles.rawIteratorAt(particle.idxBhadMotherPart()).pt(); registry.fill(HIST("hPtGenNonPrompt"), ptGen); registry.fill(HIST("hYGenNonPrompt"), yGen); registry.fill(HIST("hPtVsYGenNonPrompt"), ptGen, yGen); + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 2, maxNumContrib, cent, occ); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 2, maxNumContrib, cent); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 2, maxNumContrib, occ); + } else { + registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 2, maxNumContrib); + } } registry.fill(HIST("hEtaGen"), particle.eta()); } @@ -523,35 +871,65 @@ struct HfTaskD0 { void processMcWithDCAFitterN(D0CandidatesMc const&, soa::Join const& mcParticles, - aod::TracksWMc const& tracks) + TracksSelQuality const& tracks, + CollisionsWithMcLabels const& collisions, + aod::McCollisions const& mcCollisions) { - processMc(selectedD0CandidatesMc, mcParticles, tracks); + processMc(selectedD0CandidatesMc, mcParticles, tracks, collisions, mcCollisions); } PROCESS_SWITCH(HfTaskD0, processMcWithDCAFitterN, "Process MC with DCAFitterN", false); + void processMcWithDCAFitterNCent(D0CandidatesMc const&, + soa::Join const& mcParticles, + TracksSelQuality const& tracks, + CollisionsWithMcLabelsCent const& collisions, + aod::McCollisions const& mcCollisions) + { + processMc(selectedD0CandidatesMc, mcParticles, tracks, collisions, mcCollisions); + } + PROCESS_SWITCH(HfTaskD0, processMcWithDCAFitterNCent, "Process MC with DCAFitterN and centrality", false); + void processMcWithKFParticle(D0CandidatesMcKF const&, soa::Join const& mcParticles, - aod::TracksWMc const& tracks) + TracksSelQuality const& tracks, + CollisionsWithMcLabels const& collisions, + aod::McCollisions const& mcCollisions) { - processMc(selectedD0CandidatesMcKF, mcParticles, tracks); + processMc(selectedD0CandidatesMcKF, mcParticles, tracks, collisions, mcCollisions); } PROCESS_SWITCH(HfTaskD0, processMcWithKFParticle, "Process MC with KFParticle", false); + // TODO: add the processMcWithKFParticleCent void processMcWithDCAFitterNMl(D0CandidatesMlMc const&, soa::Join const& mcParticles, - aod::TracksWMc const& tracks) + TracksSelQuality const& tracks, + CollisionsWithMcLabels const& collisions, + aod::McCollisions const& mcCollisions) { - processMc(selectedD0CandidatesMlMc, mcParticles, tracks); + processMc(selectedD0CandidatesMlMc, mcParticles, tracks, collisions, mcCollisions); } PROCESS_SWITCH(HfTaskD0, processMcWithDCAFitterNMl, "Process MC with DCAFitterN and ML selection", false); + void processMcWithDCAFitterNMlCent(D0CandidatesMlMc const&, + soa::Join const& mcParticles, + TracksSelQuality const& tracks, + CollisionsWithMcLabelsCent const& collisions, + aod::McCollisions const& mcCollisions) + { + processMc(selectedD0CandidatesMlMc, mcParticles, tracks, collisions, mcCollisions); + } + PROCESS_SWITCH(HfTaskD0, processMcWithDCAFitterNMlCent, "Process MC with DCAFitterN and ML selection and centrality", false); + void processMcWithKFParticleMl(D0CandidatesMlMcKF const&, soa::Join const& mcParticles, - aod::TracksWMc const& tracks) + TracksSelQuality const& tracks, + CollisionsWithMcLabels const& collisions, + aod::McCollisions const& mcCollisions) { - processMc(selectedD0CandidatesMlMcKF, mcParticles, tracks); + processMc(selectedD0CandidatesMlMcKF, mcParticles, tracks, collisions, mcCollisions); } PROCESS_SWITCH(HfTaskD0, processMcWithKFParticleMl, "Process MC with KFParticle and ML selections", false); + // TODO: add the processMcWithKFParticleMlCent }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/D2H/Tasks/taskDirectedFlowCharmHadrons.cxx b/PWGHF/D2H/Tasks/taskDirectedFlowCharmHadrons.cxx new file mode 100644 index 00000000000..db2300126f2 --- /dev/null +++ b/PWGHF/D2H/Tasks/taskDirectedFlowCharmHadrons.cxx @@ -0,0 +1,420 @@ +// 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 taskDirectedFlowCharmHadrons.cxx +/// \brief Analysis task for charm hadron directed flow +/// +/// \author Prottay Das, prottay.das@cern.ch +/// \author Biao Zhang, biao.zhanng@cern.ch + +#include +#include +#include +#include + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/EventPlaneHelper.h" +#include "PWGLF/DataModel/SPCalibrationTables.h" + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/Utils/utilsEvSelHf.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::hf_centrality; +using namespace o2::hf_evsel; + +enum DecayChannel { DplusToPiKPi = 0, + D0ToPiK, + D0ToKPi, + DstarToD0Pi }; + +struct HfTaskDirectedFlowCharmHadrons { + Configurable centEstimator{"centEstimator", 2, "Centrality estimation (FT0A: 1, FT0C: 2, FT0M: 3, FV0A: 4)"}; + Configurable selectionFlagDstar{"selectionFlagDstar", false, "Selection Flag for Dstar"}; + Configurable selectionFlag{"selectionFlag", 1, "Selection Flag for hadron (e.g. 1 for skimming, 3 for topo. and kine., 7 for PID)"}; + Configurable centralityMin{"centralityMin", 0., "Minimum centrality accepted in SP computation"}; + Configurable centralityMax{"centralityMax", 100., "Maximum centrality accepted in SP computation"}; + Configurable storeMl{"storeMl", false, "Flag to store ML scores"}; + Configurable direct{"direct", false, "Flag to calculate direct v1 odd and even"}; + Configurable correction{"correction", false, "Flag for correction"}; + Configurable userap{"userap", false, "Flag to fill rapidity vs eta "}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable> classMl{"classMl", {0, 2}, "Indices of BDT scores to be stored. Two indexes max."}; + + HfHelper hfHelper; + EventPlaneHelper epHelper; + SliceCache cache; + HfEventSelection hfEvSel; // event selection and monitoring + o2::framework::Service ccdb; + + using CandDplusDataWMl = soa::Filtered>; + using CandDplusData = soa::Filtered>; + using CandD0DataWMl = soa::Filtered>; + using CandD0Data = soa::Filtered>; + using CandDstarDataWMl = soa::Filtered>; + using CandDstarData = soa::Filtered>; + using CollsWithQvecs = soa::Join; + using TracksWithExtra = soa::Join; + + Filter filterSelectDplusCandidates = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlag; + Filter filterSelectD0Candidates = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlag || aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlag; + Filter filterSelectDstarCandidates = aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == selectionFlagDstar; + + Partition selectedD0ToPiK = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlag; + Partition selectedD0ToKPi = aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlag; + Partition selectedD0ToPiKWMl = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlag; + Partition selectedD0ToKPiWMl = aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlag; + + ConfigurableAxis thnConfigAxisInvMass{"thnConfigAxisInvMass", {100, 1.78, 2.05}, ""}; + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {VARIABLE_WIDTH, 0.2, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.5, 8.0, 10.0}, ""}; + ConfigurableAxis thnConfigAxisEta{"thnConfigAxisEta", {VARIABLE_WIDTH, -0.8, -0.4, 0, 0.4, 0.8}, ""}; + ConfigurableAxis thnConfigAxisCent{"thnConfigAxisCent", {VARIABLE_WIDTH, 0.0, 10.0, 40.0, 80.0}, ""}; + ConfigurableAxis thnConfigAxisScalarProd{"thnConfigAxisScalarProd", {8000, -2.0, 2.0}, ""}; + ConfigurableAxis thnConfigAxisSign{"thnConfigAxisSign", {2, -2.0, 2.0}, ""}; + ConfigurableAxis thnConfigAxisMlOne{"thnConfigAxisMlOne", {1000, 0., 1.}, ""}; + ConfigurableAxis thnConfigAxisMlTwo{"thnConfigAxisMlTwo", {1000, 0., 1.}, ""}; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext&) + { + + /// check process functions + std::array processes = {doprocessDplusStd, doprocessDplusMl, doprocessD0Std, doprocessD0Ml, doprocessDstarStd, doprocessDstarMl}; + const int nProcesses = std::accumulate(processes.begin(), processes.end(), 0); + if (nProcesses > 1) { + LOGP(fatal, "Only one process function should be enabled at a time, please check your configuration"); + } else if (nProcesses == 0) { + LOGP(fatal, "No process function enabled"); + } + + const AxisSpec thnAxisInvMass{thnConfigAxisInvMass, "Inv. mass (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisPt{thnConfigAxisPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisEta{thnConfigAxisEta, "#it{#eta}"}; + const AxisSpec thnAxisCent{thnConfigAxisCent, "Centrality"}; + const AxisSpec thnAxisScalarProd{thnConfigAxisScalarProd, "SP"}; + const AxisSpec thnAxisSign{thnConfigAxisSign, "Sign"}; + const AxisSpec thnAxisMlOne{thnConfigAxisMlOne, "Bkg score"}; + const AxisSpec thnAxisMlTwo{thnConfigAxisMlTwo, "FD score"}; + + std::vector axes = {thnAxisInvMass, thnAxisCent, thnAxisPt, thnAxisEta, thnAxisScalarProd, thnAxisSign}; + if (storeMl) { + axes.insert(axes.end(), {thnAxisMlOne, thnAxisMlTwo}); + } + + if (direct) { + registry.add("hpQxytpvscent", "hpQxytpvscent", HistType::kTHnSparseF, {thnAxisCent, thnAxisScalarProd}, true); + registry.add("hpoddvscentpteta", "hpoddvscentpteta", HistType::kTHnSparseF, axes, true); + registry.add("hpevenvscentpteta", "hpevenvscentpteta", HistType::kTHnSparseF, axes, true); + if (correction) { + registry.add("hpuxyQxypvscentpteta", "hpuxyQxypvscentpteta", HistType::kTHnSparseF, axes, true); + registry.add("hpuxyQxytvscentpteta", "hpuxyQxytvscentpteta", HistType::kTHnSparseF, axes, true); + + registry.add("hpQxpvscent", "hpQxpvscent", HistType::kTHnSparseF, {thnAxisCent, thnAxisScalarProd}, true); + registry.add("hpQypvscent", "hpQypvscent", HistType::kTHnSparseF, {thnAxisCent, thnAxisScalarProd}, true); + registry.add("hpQxtvscent", "hpQxtvscent", HistType::kTHnSparseF, {thnAxisCent, thnAxisScalarProd}, true); + registry.add("hpQytvscent", "hpQytvscent", HistType::kTHnSparseF, {thnAxisCent, thnAxisScalarProd}, true); + registry.add("hpuxvscentpteta", "hpuxvscentpteta", HistType::kTHnSparseF, axes, true); + registry.add("hpuyvscentpteta", "hpuyvscentpteta", HistType::kTHnSparseF, axes, true); + } + } else { + registry.add("hpQxtQxpvscent", "hpQxtQxpvscent", HistType::kTHnSparseF, {thnAxisCent, thnAxisScalarProd}, true); + registry.add("hpQytQypvscent", "hpQytQypvscent", HistType::kTHnSparseF, {thnAxisCent, thnAxisScalarProd}, true); + registry.add("hpQxtQypvscent", "hpQxtQypvscent", HistType::kTHnSparseF, {thnAxisCent, thnAxisScalarProd}, true); + registry.add("hpQxpQytvscent", "hpQxpQytvscent", HistType::kTHnSparseF, {thnAxisCent, thnAxisScalarProd}, true); + registry.add("hpuxQxpvscentpteta", "hpuxQxpvscentpteta", HistType::kTHnSparseF, axes, true); + registry.add("hpuyQypvscentpteta", "hpuyQypvscentpteta", HistType::kTHnSparseF, axes, true); + registry.add("hpuxQxtvscentpteta", "hpuxQxtvscentpteta", HistType::kTHnSparseF, axes, true); + registry.add("hpuyQytvscentpteta", "hpuyQytvscentpteta", HistType::kTHnSparseF, axes, true); + + registry.add("hpQxpvscent", "hpQxpvscent", HistType::kTHnSparseF, {thnAxisCent, thnAxisScalarProd}, true); + registry.add("hpQypvscent", "hpQypvscent", HistType::kTHnSparseF, {thnAxisCent, thnAxisScalarProd}, true); + registry.add("hpQxtvscent", "hpQxtvscent", HistType::kTHnSparseF, {thnAxisCent, thnAxisScalarProd}, true); + registry.add("hpQytvscent", "hpQytvscent", HistType::kTHnSparseF, {thnAxisCent, thnAxisScalarProd}, true); + registry.add("hpuxvscentpteta", "hpuxvscentpteta", HistType::kTHnSparseF, axes, true); + registry.add("hpuyvscentpteta", "hpuyvscentpteta", HistType::kTHnSparseF, axes, true); + } + + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + }; // end init + + /// Get the centrality + /// \param collision is the collision with the centrality information + double getCentrality(CollsWithQvecs::iterator const& collision) + { + double cent = -999.; + switch (centEstimator) { + case CentralityEstimator::FV0A: + cent = collision.centFV0A(); + break; + case CentralityEstimator::FT0M: + cent = collision.centFT0M(); + break; + case CentralityEstimator::FT0A: + cent = collision.centFT0A(); + break; + case CentralityEstimator::FT0C: + cent = collision.centFT0C(); + break; + default: + LOG(warning) << "Centrality estimator not valid. Possible values are V0A, T0M, T0A, T0C. Fallback to V0A"; + cent = collision.centFV0A(); + break; + } + return cent; + } + + /// Compute the scalar product + /// \param collision is the collision with the Q vector information and event plane + /// \param candidates are the selected candidates + template + void runFlowAnalysis(CollsWithQvecs::iterator const& collision, + T1 const& candidates, + Trk const& /*tracks*/) + { + double cent = getCentrality(collision); + if (cent < centralityMin || cent > centralityMax) { + return; + } + + if (!collision.triggereventsp()) { // for selecting only callibrated events + return; + } + + auto qxZDCA = collision.qxZDCA(); + auto qyZDCA = collision.qyZDCA(); + auto qxZDCC = collision.qxZDCC(); // extracting q vectors of ZDC + auto qyZDCC = collision.qyZDCC(); + + auto qxtQxp = qxZDCC * qxZDCA; + auto qytQyp = qyZDCC * qyZDCA; + auto qxytp = qxtQxp + qytQyp; + auto qxpQyt = qxZDCA * qyZDCC; + auto qxtQyp = qxZDCC * qyZDCA; + + // correlations in the denominators for SP calculation + if (direct) { + registry.fill(HIST("hpQxytpvscent"), cent, qxytp); + if (correction) { + registry.fill(HIST("hpQxpvscent"), cent, qxZDCA); + registry.fill(HIST("hpQxtvscent"), cent, qxZDCC); + registry.fill(HIST("hpQypvscent"), cent, qyZDCA); + registry.fill(HIST("hpQytvscent"), cent, qyZDCC); + } + } else { + registry.fill(HIST("hpQxtQxpvscent"), cent, qxtQxp); + registry.fill(HIST("hpQytQypvscent"), cent, qytQyp); + registry.fill(HIST("hpQxpQytvscent"), cent, qxpQyt); + registry.fill(HIST("hpQxtQypvscent"), cent, qxtQyp); + registry.fill(HIST("hpQxpvscent"), cent, qxZDCA); + registry.fill(HIST("hpQxtvscent"), cent, qxZDCC); + registry.fill(HIST("hpQypvscent"), cent, qyZDCA); + registry.fill(HIST("hpQytvscent"), cent, qyZDCC); + } + + for (const auto& candidate : candidates) { + double massCand = 0.; + double rapCand = 0.; + double sign = 0.; // electric charge of the first daughter track to differentiate particle and antiparticle + double signDstarCand = 0.0; + std::vector outputMl = {-999., -999.}; + if constexpr (std::is_same_v || std::is_same_v) { + massCand = hfHelper.invMassDplusToPiKPi(candidate); + rapCand = hfHelper.yDplus(candidate); + auto trackprong0 = candidate.template prong0_as(); + sign = trackprong0.sign(); + if constexpr (std::is_same_v) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) + outputMl[iclass] = candidate.mlProbDplusToPiKPi()[classMl->at(iclass)]; + } + } else if constexpr (std::is_same_v || std::is_same_v) { + switch (channel) { + case DecayChannel::D0ToPiK: + massCand = hfHelper.invMassD0ToPiK(candidate); + rapCand = hfHelper.yD0(candidate); + sign = candidate.isSelD0bar() ? 3 : 1; // 3: reflected D0bar, 1: pure D0 excluding reflected D0bar + if constexpr (std::is_same_v) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) + outputMl[iclass] = candidate.mlProbD0()[classMl->at(iclass)]; + } + break; + case DecayChannel::D0ToKPi: + massCand = hfHelper.invMassD0barToKPi(candidate); + rapCand = hfHelper.yD0(candidate); + sign = candidate.isSelD0() ? 3 : 2; // 3: reflected D0, 2: pure D0bar excluding reflected D0 + if constexpr (std::is_same_v) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) + outputMl[iclass] = candidate.mlProbD0bar()[classMl->at(iclass)]; + } + break; + default: + break; + } + } else if constexpr (std::is_same_v || std::is_same_v) { + signDstarCand = candidate.signSoftPi(); + if (candidate.signSoftPi() > 0) { + massCand = std::abs(candidate.invMassDstar() - candidate.invMassD0()); + rapCand = candidate.y(candidate.invMassDstar()); + } else if (candidate.signSoftPi() < 0) { + massCand = std::abs(candidate.invMassAntiDstar() - candidate.invMassD0Bar()); + rapCand = candidate.y(candidate.invMassAntiDstar()); + } + if constexpr (std::is_same_v) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) + outputMl[iclass] = candidate.mlProbDstarToD0Pi()[classMl->at(iclass)]; + } + } + + double ptCand = candidate.pt(); + double etaCand = candidate.eta(); + double phiCand = candidate.phi(); + double cosNPhi = std::cos(phiCand); + double sinNPhi = std::sin(phiCand); + + if (userap) + etaCand = rapCand; + + if (selectionFlagDstar) + sign = signDstarCand; + + auto ux = cosNPhi; // real part of candidate q vector + auto uy = sinNPhi; // imaginary part of candidate q vector + auto uxQxp = ux * qxZDCA; + auto uyQyp = uy * qyZDCA; // correlations of particle and ZDC q vectors + auto uxyQxyp = uxQxp + uyQyp; + auto uxQxt = ux * qxZDCC; + auto uyQyt = uy * qyZDCC; + auto uxyQxyt = uxQxt + uyQyt; + auto oddv1 = ux * (qxZDCA - qxZDCC) + uy * (qyZDCA - qyZDCC); + auto evenv1 = ux * (qxZDCA + qxZDCC) + uy * (qyZDCA + qyZDCC); + + if (storeMl) { + if (direct) { + registry.fill(HIST("hpoddvscentpteta"), massCand, cent, ptCand, etaCand, oddv1, sign, outputMl[0], outputMl[1]); + registry.fill(HIST("hpevenvscentpteta"), massCand, cent, ptCand, etaCand, evenv1, sign, outputMl[0], outputMl[1]); + if (correction) { + registry.fill(HIST("hpuxyQxypvscentpteta"), massCand, cent, ptCand, etaCand, uxyQxyp, sign, outputMl[0], outputMl[1]); + registry.fill(HIST("hpuxyQxytvscentpteta"), massCand, cent, ptCand, etaCand, uxyQxyt, sign, outputMl[0], outputMl[1]); + + registry.fill(HIST("hpuxvscentpteta"), massCand, cent, ptCand, etaCand, ux, sign, outputMl[0], outputMl[1]); + registry.fill(HIST("hpuyvscentpteta"), massCand, cent, ptCand, etaCand, uy, sign, outputMl[0], outputMl[1]); + } + } else { + registry.fill(HIST("hpuxQxpvscentpteta"), massCand, cent, ptCand, etaCand, uxQxp, sign, outputMl[0], outputMl[1]); + registry.fill(HIST("hpuyQypvscentpteta"), massCand, cent, ptCand, etaCand, uyQyp, sign, outputMl[0], outputMl[1]); + registry.fill(HIST("hpuxQxtvscentpteta"), massCand, cent, ptCand, etaCand, uxQxt, sign, outputMl[0], outputMl[1]); + registry.fill(HIST("hpuyQytvscentpteta"), massCand, cent, ptCand, etaCand, uyQyt, sign, outputMl[0], outputMl[1]); + + registry.fill(HIST("hpuxvscentpteta"), massCand, cent, ptCand, etaCand, ux, sign, outputMl[0], outputMl[1]); + registry.fill(HIST("hpuyvscentpteta"), massCand, cent, ptCand, etaCand, uy, sign, outputMl[0], outputMl[1]); + } + } else { + if (direct) { + registry.fill(HIST("hpoddvscentpteta"), massCand, cent, ptCand, etaCand, oddv1, sign); + registry.fill(HIST("hpevenvscentpteta"), massCand, cent, ptCand, etaCand, evenv1, sign); + + if (correction) { + registry.fill(HIST("hpuxyQxypvscentpteta"), massCand, cent, ptCand, etaCand, uxyQxyp, sign); + registry.fill(HIST("hpuxyQxytvscentpteta"), massCand, cent, ptCand, etaCand, uxyQxyt, sign); + + registry.fill(HIST("hpuxvscentpteta"), massCand, cent, ptCand, etaCand, ux, sign); + registry.fill(HIST("hpuyvscentpteta"), massCand, cent, ptCand, etaCand, uy, sign); + } + } else { + registry.fill(HIST("hpuxQxpvscentpteta"), massCand, cent, ptCand, etaCand, uxQxp, sign); + registry.fill(HIST("hpuyQypvscentpteta"), massCand, cent, ptCand, etaCand, uyQyp, sign); + registry.fill(HIST("hpuxQxtvscentpteta"), massCand, cent, ptCand, etaCand, uxQxt, sign); + registry.fill(HIST("hpuyQytvscentpteta"), massCand, cent, ptCand, etaCand, uyQyt, sign); + + registry.fill(HIST("hpuxvscentpteta"), massCand, cent, ptCand, etaCand, ux, sign); + registry.fill(HIST("hpuyvscentpteta"), massCand, cent, ptCand, etaCand, uy, sign); + } + } + } + } + // D0 with ML + void processD0Ml(CollsWithQvecs::iterator const& collision, + CandD0DataWMl const& /*candidatesD0*/, + TracksWithExtra const& tracks) + { + auto candsD0ToPiKWMl = selectedD0ToPiKWMl->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); + auto candsD0ToKPiWMl = selectedD0ToKPiWMl->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); + runFlowAnalysis(collision, candsD0ToPiKWMl, tracks); + runFlowAnalysis(collision, candsD0ToKPiWMl, tracks); + } + PROCESS_SWITCH(HfTaskDirectedFlowCharmHadrons, processD0Ml, "Process D0 candidates with ML", false); + + // D0 with rectangular cuts + void processD0Std(CollsWithQvecs::iterator const& collision, + CandD0Data const& /*candidatesD0*/, + TracksWithExtra const& tracks) + { + auto candsD0ToPiK = selectedD0ToPiK->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); + auto candsD0ToKPi = selectedD0ToKPi->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); + runFlowAnalysis(collision, candsD0ToPiK, tracks); + runFlowAnalysis(collision, candsD0ToKPi, tracks); + } + PROCESS_SWITCH(HfTaskDirectedFlowCharmHadrons, processD0Std, "Process D0 candidates with rectangular cuts", false); + + // Dplus with ML + void processDplusMl(CollsWithQvecs::iterator const& collision, + CandDplusDataWMl const& candidatesDplus, + TracksWithExtra const& tracks) + { + runFlowAnalysis(collision, candidatesDplus, tracks); + } + PROCESS_SWITCH(HfTaskDirectedFlowCharmHadrons, processDplusMl, "Process Dplus candidates with ML", false); + + // Dplus with rectangular cuts + void processDplusStd(CollsWithQvecs::iterator const& collision, + CandDplusData const& candidatesDplus, + TracksWithExtra const& tracks) + { + runFlowAnalysis(collision, candidatesDplus, tracks); + } + PROCESS_SWITCH(HfTaskDirectedFlowCharmHadrons, processDplusStd, "Process Dplus candidates with rectangular cuts", true); + + // Dstar with ML + void processDstarMl(CollsWithQvecs::iterator const& collision, + CandDstarDataWMl const& candidatesDstar, + TracksWithExtra const& tracks) + { + runFlowAnalysis(collision, candidatesDstar, tracks); + } + PROCESS_SWITCH(HfTaskDirectedFlowCharmHadrons, processDstarMl, "Process Dstar candidates with ML", false); + + // Dstar with rectangular cuts + void processDstarStd(CollsWithQvecs::iterator const& collision, + CandDstarData const& candidatesDstar, + TracksWithExtra const& tracks) + { + runFlowAnalysis(collision, candidatesDstar, tracks); + } + PROCESS_SWITCH(HfTaskDirectedFlowCharmHadrons, processDstarStd, "Process Dstar candidates with rectangular cuts", true); + +}; // End struct HfTaskDirectedFlowCharmHadrons + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index ca28eacd505..e67ec0dfa69 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -17,30 +17,40 @@ /// \author Vít Kučera , CERN /// \author Luca Aglietta , University and INFN Torino +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" +#include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsAnalysis.h" using namespace o2; using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::hf_centrality; +using namespace o2::hf_occupancy; /// D± analysis task struct HfTaskDplus { Configurable selectionFlagDplus{"selectionFlagDplus", 7, "Selection Flag for DPlus"}; // 7 corresponds to topo+PID cuts Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen particle rapidity"}; Configurable yCandRecoMax{"yCandRecoMax", 0.8, "max. cand. rapidity"}; + Configurable yGenNBins{"yGenNBins", 100, "number of bins for y axis in sparse for gen candidates"}; + Configurable centEstimator{"centEstimator", 0, "Centrality estimation (None: 0, FT0C: 2, FT0M: 3)"}; + Configurable occEstimator{"occEstimator", 0, "Occupancy estimation (None: 0, ITS: 1, FT0C: 2)"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_dplus_to_pi_k_pi::vecBinsPt}, "pT bin limits"}; Configurable> classMl{"classMl", {0, 1, 2}, "Indexes of ML scores to be stored. Three indexes max."}; - ConfigurableAxis axisMlScore0{"axisMlScore0", {100, 0., 1.}, "axis for ML output score 0"}; - ConfigurableAxis axisMlScore1{"axisMlScore1", {100, 0., 1.}, "axis for ML output score 1"}; - ConfigurableAxis axisMlScore2{"axisMlScore2", {100, 0., 1.}, "axis for ML output score 2"}; + Configurable storeCentrality{"storeCentrality", false, "Flag to store centrality information"}; + Configurable storeOccupancy{"storeOccupancy", false, "Flag to store occupancy information"}; + Configurable fillMcBkgHistos{"fillMcBkgHistos", false, "Flag to fill and store histograms for MC background"}; HfHelper hfHelper; @@ -48,10 +58,16 @@ struct HfTaskDplus { using CandDplusDataWithMl = soa::Filtered>; using CandDplusMcReco = soa::Filtered>; using CandDplusMcRecoWithMl = soa::Filtered>; - using McParticles = soa::Join; + using CandDplusMcGen = soa::Join; + + using CollisionsCent = soa::Join; + using McRecoCollisionsCent = soa::Join; Filter filterDplusFlag = (o2::aod::hf_track_index::hfflag & static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi))) != static_cast(0); + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + PresliceUnsorted recoColPerMcCollision = aod::mccollisionlabel::mcCollisionId; + // data Partition selectedDPlusCandidates = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; Partition selectedDPlusCandidatesWithMl = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; @@ -64,7 +80,14 @@ struct HfTaskDplus { Partition recoBkgCandidates = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi)) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; Partition recoBkgCandidatesWithMl = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi)) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; - // Generated particles + ConfigurableAxis thnConfigAxisY{"thnConfigAxisY", {40, -1, 1}, "Cand. rapidity bins"}; + ConfigurableAxis thnConfigAxisCent{"thnConfigAxisCent", {110, 0., 110.}, ""}; + ConfigurableAxis thnConfigAxisOccupancy{"thnConfigAxisOccupancy", {14, 0, 14000}, "axis for centrality"}; + ConfigurableAxis thnConfigAxisPtBHad{"thnConfigAxisPtBHad", {25, 0., 50}, "axis for pt of B hadron decayed into D candidate"}; + ConfigurableAxis thnConfigAxisFlagBHad{"thnConfigAxisFlagBHad", {5, 0., 5}, "axis for PDG of B hadron"}; + ConfigurableAxis thnConfigAxisMlScore0{"thnConfigAxisMlScore0", {100, 0., 1.}, "axis for ML output score 0"}; + ConfigurableAxis thnConfigAxisMlScore1{"thnConfigAxisMlScore1", {100, 0., 1.}, "axis for ML output score 1"}; + ConfigurableAxis thnConfigAxisMlScore2{"thnConfigAxisMlScore2", {100, 0., 1.}, "axis for ML output score 2"}; HistogramRegistry registry{ "registry", @@ -84,9 +107,18 @@ struct HfTaskDplus { if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { LOGP(fatal, "Only one process function should be enabled! Please check your configuration!"); } - auto vbins = (std::vector)binsPt; - AxisSpec ptbins = {vbins, "#it{p}_{T} (GeV/#it{c})"}; - AxisSpec massbins = {600, 1.67, 2.27, "inv. mass (K#pi#pi) (GeV/#it{c}^{2})"}; + auto vbins = static_cast>(binsPt); + AxisSpec thnAxisPt = {vbins, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec thnAxisMass = {600, 1.67, 2.27, "inv. mass (K#pi#pi) (GeV/#it{c}^{2})"}; + AxisSpec thnAxisY = {thnConfigAxisY, "y"}; + AxisSpec thnAxisMlScore0 = {thnConfigAxisMlScore0, "Score 0"}; + AxisSpec thnAxisMlScore1 = {thnConfigAxisMlScore1, "Score 1"}; + AxisSpec thnAxisMlScore2 = {thnConfigAxisMlScore2, "Score 2"}; + AxisSpec thnAxisPtBHad{thnConfigAxisPtBHad, "#it{p}_{T,B} (GeV/#it{c})"}; + AxisSpec thnAxisFlagBHad{thnConfigAxisFlagBHad, "B Hadron flag"}; + AxisSpec thnAxisCent{thnConfigAxisCent, "Centrality"}; + AxisSpec thnAxisOccupancy{thnConfigAxisOccupancy, "Occupancy"}; + registry.add("hMass", "3-prong candidates;inv. mass (#pi K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{350, 1.7, 2.05}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("hEta", "3-prong candidates;candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("hCt", "3-prong candidates;proper lifetime (D^{#pm}) * #it{c} (cm);entries", {HistType::kTH2F, {{120, -20., 100.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); @@ -124,13 +156,58 @@ struct HfTaskDplus { registry.add("hPtVsYGen", "MC particles (matched);#it{p}_{T}^{gen.}; #it{y}", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {100, -5., 5.}}}); registry.add("hPtVsYGenPrompt", "MC particles (matched, prompt);#it{p}_{T}^{gen.}; #it{y}", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {100, -5., 5.}}}); registry.add("hPtVsYGenNonPrompt", "MC particles (matched, non-prompt);#it{p}_{T}^{gen.}; #it{y}", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {100, -5., 5.}}}); - if (doprocessDataWithMl) { - registry.add("hSparseMass", "THn for Dplus", HistType::kTHnSparseF, {massbins, ptbins, axisMlScore0, axisMlScore1, axisMlScore2}); + + if (doprocessDataWithMl || doprocessData) { + std::vector axes = {thnAxisMass, thnAxisPt}; + + if (doprocessDataWithMl) { + axes.insert(axes.end(), {thnAxisMlScore0, thnAxisMlScore1, thnAxisMlScore2}); + } + if (storeCentrality) { + axes.insert(axes.end(), {thnAxisCent}); + } + if (storeOccupancy) { + axes.insert(axes.end(), {thnAxisOccupancy}); + } + + registry.add("hSparseMass", "THn for Dplus", HistType::kTHnSparseF, axes); } - if (doprocessMcWithMl) { - registry.add("hSparseMassPrompt", "THn for Dplus Prompt", HistType::kTHnSparseF, {massbins, ptbins, axisMlScore0, axisMlScore1, axisMlScore2}); - registry.add("hSparseMassFD", "THn for Dplus FD", HistType::kTHnSparseF, {massbins, ptbins, axisMlScore0, axisMlScore1, axisMlScore2}); - registry.add("hSparseMassBkg", "THn for Dplus Bkg", HistType::kTHnSparseF, {massbins, ptbins, axisMlScore0, axisMlScore1, axisMlScore2}); + if (doprocessMcWithMl || doprocessMc) { + std::vector axes = {thnAxisMass, thnAxisPt}; + std::vector axesFD = {thnAxisMass, thnAxisPt}; + std::vector axesGenPrompt = {thnAxisPt, thnAxisY}; + std::vector axesGenFD = {thnAxisPt, thnAxisY}; + + if (doprocessMcWithMl) { + axes.insert(axes.end(), {thnAxisMlScore0, thnAxisMlScore1, thnAxisMlScore2}); + axesFD.insert(axesFD.end(), {thnAxisMlScore0, thnAxisMlScore1, thnAxisMlScore2}); + } + if (storeCentrality) { + axes.insert(axes.end(), {thnAxisCent}); + axesFD.insert(axesFD.end(), {thnAxisCent}); + axesGenPrompt.insert(axesGenPrompt.end(), {thnAxisCent}); + axesGenFD.insert(axesGenFD.end(), {thnAxisCent}); + } + if (storeOccupancy) { + axes.insert(axes.end(), {thnAxisOccupancy}); + axesFD.insert(axesFD.end(), {thnAxisOccupancy}); + axesGenPrompt.insert(axesGenPrompt.end(), {thnAxisOccupancy}); + axesGenFD.insert(axesGenFD.end(), {thnAxisOccupancy}); + } + + axesFD.insert(axesFD.end(), {thnAxisPtBHad}); + axesFD.insert(axesFD.end(), {thnAxisFlagBHad}); + axesGenFD.insert(axesGenFD.end(), {thnAxisPtBHad}); + axesGenFD.insert(axesGenFD.end(), {thnAxisFlagBHad}); + + registry.add("hSparseMassPrompt", "THn for Dplus Prompt", HistType::kTHnSparseF, axes); + registry.add("hSparseMassFD", "THn for Dplus FD", HistType::kTHnSparseF, axesFD); + if (fillMcBkgHistos) { + registry.add("hSparseMassBkg", "THn for Dplus Bkg", HistType::kTHnSparseF, axes); + } + registry.add("hSparseMassNotMatched", "THn for Dplus not matched", HistType::kTHnSparseF, axes); + registry.add("hSparseMassGenPrompt", "THn for gen Prompt Dplus", HistType::kTHnSparseF, axesGenPrompt); + registry.add("hSparseMassGenFD", "THn for gen FD Dplus", HistType::kTHnSparseF, axesGenFD); } } @@ -167,25 +244,81 @@ struct HfTaskDplus { // Fill THnSparses for the ML analysis /// \param candidate is a particle candidate + /// \param ptbhad transverse momentum of beauty mother for nonprompt candidates + /// \param flagBHad transverse momentum of beauty mother for nonprompt candidates + /// \param centrality collision centrality + /// \param occupancy collision occupancy template - void fillSparseML(const T1& candidate) + void fillSparseML(const T1& candidate, + float ptbhad, + int flagBHad, + float centrality, + float occupancy) { std::vector outputMl = {-999., -999., -999.}; for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMl[iclass] = candidate.mlProbDplusToPiKPi()[classMl->at(iclass)]; } - if constexpr (isMc) { - if constexpr (isMatched) { - if (candidate.originMcRec() == RecoDecay::OriginType::Prompt) { - registry.fill(HIST("hSparseMassPrompt"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2]); - } else if (candidate.originMcRec() == RecoDecay::OriginType::NonPrompt) { - registry.fill(HIST("hSparseMassFD"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2]); + if constexpr (isMc) { // MC + if constexpr (isMatched) { // Matched + if (candidate.originMcRec() == RecoDecay::OriginType::Prompt) { // Prompt + + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMassPrompt"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, occupancy); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hSparseMassPrompt"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMassPrompt"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], occupancy); + } else { + registry.fill(HIST("hSparseMassPrompt"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2]); + } + + } else if (candidate.originMcRec() == RecoDecay::OriginType::NonPrompt) { // FD + + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMassFD"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, occupancy, ptbhad, flagBHad); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hSparseMassFD"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, ptbhad, flagBHad); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMassFD"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], occupancy, ptbhad, flagBHad); + } else { + registry.fill(HIST("hSparseMassFD"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], ptbhad, flagBHad); + } + + } else { // Bkg + if (fillMcBkgHistos) { + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMassBkg"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, occupancy); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hSparseMassBkg"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMassBkg"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], occupancy); + } else { + registry.fill(HIST("hSparseMassBkg"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2]); + } + } } } else { - registry.fill(HIST("hSparseMassBkg"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2]); + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMassNotMatched"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, occupancy); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hSparseMassNotMatched"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMassNotMatched"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], occupancy); + } else { + registry.fill(HIST("hSparseMassNotMatched"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2]); + } + } + } else { // Data + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMass"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, occupancy); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hSparseMass"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMass"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], occupancy); + } else { + registry.fill(HIST("hSparseMass"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2]); } - } else { - registry.fill(HIST("hSparseMass"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2]); } } @@ -258,11 +391,52 @@ struct HfTaskDplus { registry.fill(HIST("hEtaGen"), particle.eta()); } + // Fill THnSparse of quantities for generated Dplus particles + /// \param particle is a particle with MC information + /// \param ptGenB transverse momentum of beauty mother for nonprompt candidates + /// \param flagGenB transverse momentum of beauty mother for nonprompt candidates + /// \param centrality collision centrality + /// \param occupancy collision occupancy + template + void fillSparseMcGen(const T1& particle, + float ptGenB, + int flagGenB, + float centrality, + float occupancy) + { + auto yGen = RecoDecay::y(particle.pVector(), o2::constants::physics::MassDPlus); + if (particle.originMcGen() == RecoDecay::OriginType::Prompt) { + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMassGenPrompt"), particle.pt(), yGen, centrality, occupancy); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hSparseMassGenPrompt"), particle.pt(), yGen, centrality); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMassGenPrompt"), particle.pt(), yGen, occupancy); + } else { + registry.fill(HIST("hSparseMassGenPrompt"), particle.pt(), yGen); + } + } else { + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMassGenFD"), particle.pt(), yGen, centrality, occupancy, ptGenB, flagGenB); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hSparseMassGenFD"), particle.pt(), yGen, centrality, ptGenB, flagGenB); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMassGenFD"), particle.pt(), yGen, occupancy, ptGenB, flagGenB); + } else { + registry.fill(HIST("hSparseMassGenFD"), particle.pt(), yGen, ptGenB, flagGenB); + } + } + } + // Run analysis for the reconstructed Dplus candidates from data /// \param candidates are reconstructed candidates template - void runDataAnalysis(const T1& /*candidates*/) + void runDataAnalysis(const T1& /*candidates*/, CollisionsCent const& /*colls*/) { + float cent{-1.f}; + float occ{-1.f}; + float ptBhad{-1.f}; + int flagBHad{-1}; if constexpr (!fillMl) { for (const auto& candidate : selectedDPlusCandidates) { if ((yCandRecoMax >= 0. && std::abs(hfHelper.yDplus(candidate)) > yCandRecoMax)) { @@ -275,17 +449,34 @@ struct HfTaskDplus { if ((yCandRecoMax >= 0. && std::abs(hfHelper.yDplus(candidate)) > yCandRecoMax)) { continue; } + + if (storeCentrality || storeOccupancy) { + auto collision = candidate.template collision_as(); + if (storeCentrality && centEstimator != CentralityEstimator::None) { + cent = getCentralityColl(collision, centEstimator); + } + if (storeOccupancy && occEstimator != OccupancyEstimator::None) { + occ = getOccupancyColl(collision, occEstimator); + } + } + fillHisto(candidate); - fillSparseML(candidate); + fillSparseML(candidate, ptBhad, flagBHad, cent, occ); } } } + // Run analysis for the reconstructed Dplus candidates with MC matching - /// \param candidates are reconstructed candidates - /// \param mcParticles are particles with MC information - template - void runMCAnalysis(const T1& /*recoCandidates*/, const T2& mcParticles) + /// \param recoCandidates are reconstructed candidates + /// \param recoColls are reconstructed collisions + template + void runAnalysisMcRec(McRecoCollisionsCent const& /*recoColls*/) { + float cent{-1}; + float occ{-1}; + float ptBhad{-1}; + int flagBHad{-1}; + // MC rec. w/o Ml if constexpr (!fillMl) { for (const auto& candidate : recoDPlusCandidates) { @@ -296,64 +487,133 @@ struct HfTaskDplus { fillHistoMCRec(candidate); } // Bkg - for (const auto& candidate : recoBkgCandidates) { - if ((yCandRecoMax >= 0. && std::abs(hfHelper.yDplus(candidate)) > yCandRecoMax)) { - continue; + if (fillMcBkgHistos) { + for (const auto& candidate : recoBkgCandidates) { + if ((yCandRecoMax >= 0. && std::abs(hfHelper.yDplus(candidate)) > yCandRecoMax)) { + continue; + } + fillHistoMCRec(candidate); } - fillHistoMCRec(candidate); } } else { for (const auto& candidate : recoDPlusCandidatesWithMl) { if ((yCandRecoMax >= 0. && std::abs(hfHelper.yDplus(candidate)) > yCandRecoMax)) { continue; } + ptBhad = candidate.ptBhadMotherPart(); + flagBHad = getBHadMotherFlag(candidate.pdgBhadMotherPart()); + + if (storeCentrality || storeOccupancy) { + auto collision = candidate.template collision_as(); + if (storeCentrality && centEstimator != CentralityEstimator::None) { + cent = getCentralityColl(collision, centEstimator); + } + if (storeOccupancy && occEstimator != OccupancyEstimator::None) { + occ = getOccupancyColl(collision, occEstimator); + } + } + fillHisto(candidate); fillHistoMCRec(candidate); - fillSparseML(candidate); + fillSparseML(candidate, ptBhad, flagBHad, cent, occ); } // Bkg - for (const auto& candidate : recoBkgCandidatesWithMl) { - if ((yCandRecoMax >= 0. && std::abs(hfHelper.yDplus(candidate)) > yCandRecoMax)) { - continue; + ptBhad = -1; + flagBHad = -1; + if (fillMcBkgHistos) { + for (const auto& candidate : recoBkgCandidatesWithMl) { + if ((yCandRecoMax >= 0. && std::abs(hfHelper.yDplus(candidate)) > yCandRecoMax)) { + continue; + } + auto collision = candidate.template collision_as(); + if (storeCentrality && centEstimator != CentralityEstimator::None) { + cent = getCentralityColl(collision, centEstimator); + } + if (storeOccupancy && occEstimator != OccupancyEstimator::None) { + occ = getOccupancyColl(collision, occEstimator); + } + fillHistoMCRec(candidate); + fillSparseML(candidate, ptBhad, flagBHad, cent, occ); } - fillHistoMCRec(candidate); - fillSparseML(candidate); } } + } + + // Run analysis for the generated Dplus candidates + /// \param mcGenCollisions are the generated MC collisions + /// \param mcRecoCollisions are the reconstructed MC collisions + /// \param mcGenParticles are the generated MC particle candidates + template + void runAnalysisMcGen(aod::McCollisions const& mcGenCollisions, + McRecoCollisionsCent const& mcRecoCollisions, + Cand const& mcGenParticles) + { // MC gen. - for (const auto& particle : mcParticles) { - auto yGen = RecoDecay::y(particle.pVector(), o2::constants::physics::MassDPlus); - if ((yCandGenMax >= 0. && std::abs(yGen) > yCandGenMax) || (std::abs(particle.flagMcMatchGen()) != 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi)) { - continue; + float cent{-1.}; + float occ{-1.}; + float ptGenB{-1.}; + int flagGenB{-1}; + + for (const auto& mcGenCollision : mcGenCollisions) { + const auto recoCollsPerGenMcColl = mcRecoCollisions.sliceBy(recoColPerMcCollision, mcGenCollision.globalIndex()); + const auto mcParticlesPerGenMcColl = mcGenParticles.sliceBy(mcParticlesPerMcCollision, mcGenCollision.globalIndex()); + if (storeCentrality && centEstimator != CentralityEstimator::None) { + cent = getCentralityGenColl(recoCollsPerGenMcColl, centEstimator); + } + if (storeOccupancy && occEstimator != OccupancyEstimator::None) { + occ = getOccupancyGenColl(recoCollsPerGenMcColl, occEstimator); + } + + for (const auto& particle : mcParticlesPerGenMcColl) { + ptGenB = -1; + flagGenB = -1; + auto yGen = RecoDecay::y(particle.pVector(), o2::constants::physics::MassDPlus); + if ((yCandGenMax >= 0. && std::abs(yGen) > yCandGenMax) || (std::abs(particle.flagMcMatchGen()) != 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi)) { + continue; + } + if (particle.originMcGen() == RecoDecay::OriginType::NonPrompt) { + auto bHadMother = mcGenParticles.rawIteratorAt(particle.idxBhadMotherPart() - mcGenParticles.offset()); + flagGenB = getBHadMotherFlag(bHadMother.pdgCode()); + ptGenB = bHadMother.pt(); + } + fillHistoMCGen(particle); + if constexpr (fillMl) { + fillSparseMcGen(particle, ptGenB, flagGenB, cent, occ); + } } - fillHistoMCGen(particle); } } // process functions - void processData(CandDplusData const& candidates) + void processData(CandDplusData const& candidates, CollisionsCent const& collisions) { - runDataAnalysis(candidates); + runDataAnalysis(candidates, collisions); } PROCESS_SWITCH(HfTaskDplus, processData, "Process data w/o ML", true); - void processDataWithMl(CandDplusDataWithMl const& candidates) + void processDataWithMl(CandDplusDataWithMl const& candidates, CollisionsCent const& collisions) { - runDataAnalysis(candidates); + runDataAnalysis(candidates, collisions); } PROCESS_SWITCH(HfTaskDplus, processDataWithMl, "Process data with ML", false); - void processMc(CandDplusMcReco const& candidates, - McParticles const& mcParticles) + void processMc(CandDplusMcReco const&, + CandDplusMcGen const& mcGenParticles, + McRecoCollisionsCent const& mcRecoCollisions, + aod::McCollisions const& mcGenCollisions) { - runMCAnalysis(candidates, mcParticles); + runAnalysisMcRec(mcRecoCollisions); + runAnalysisMcGen(mcGenCollisions, mcRecoCollisions, mcGenParticles); } PROCESS_SWITCH(HfTaskDplus, processMc, "Process MC w/o ML", false); - void processMcWithMl(CandDplusMcRecoWithMl const& candidates, - McParticles const& mcParticles) + void processMcWithMl(CandDplusMcRecoWithMl const&, + CandDplusMcGen const& mcGenParticles, + McRecoCollisionsCent const& mcRecoCollisions, + aod::McCollisions const& mcGenCollisions) { - runMCAnalysis(candidates, mcParticles); + runAnalysisMcRec(mcRecoCollisions); + runAnalysisMcGen(mcGenCollisions, mcRecoCollisions, mcGenParticles); } PROCESS_SWITCH(HfTaskDplus, processMcWithMl, "Process MC with ML", false); }; diff --git a/PWGHF/D2H/Tasks/taskDs.cxx b/PWGHF/D2H/Tasks/taskDs.cxx index fc9f0aaa0b0..f8d848e596f 100644 --- a/PWGHF/D2H/Tasks/taskDs.cxx +++ b/PWGHF/D2H/Tasks/taskDs.cxx @@ -17,20 +17,33 @@ /// \author Stefano Politanò , Politecnico & INFN Torino /// \author Fabrizio Chinu , Universita and INFN Torino +#include +#include +#include +#include +#include + +#include "CCDB/BasicCCDBManager.h" #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" +#include "MetadataHelper.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsAnalysis.h" using namespace o2; using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; +MetadataHelper metadataInfo; // Metadata helper + enum FinalState { KKPi = 0, PiKK }; @@ -40,13 +53,15 @@ enum DataType { Data = 0, McDplusPrompt, McDplusNonPrompt, McDplusBkg, + McLcBkg, McBkg, kDataTypes }; -enum SpeciesAndDecay { DsToKKPi = 0, - DplusToKKPi, - DplusToPiKPi, - kSpeciesAndDecay }; +template +concept hasDsMlInfo = requires(T candidate) { + candidate.mlProbDsToKKPi(); + candidate.mlProbDsToPiKK(); +}; /// Ds± analysis task struct HfTaskDs { @@ -55,71 +70,86 @@ struct HfTaskDs { Configurable fillDplusMc{"fillDplusMc", true, "Switch to fill Dplus MC information"}; Configurable selectionFlagDs{"selectionFlagDs", 7, "Selection Flag for Ds"}; Configurable> classMl{"classMl", {0, 2, 3}, "Indexes of ML scores to be stored. Three indexes max."}; - Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen particle rapidity"}; - Configurable yCandRecoMax{"yCandRecoMax", 0.8, "max. cand. rapidity"}; - ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 8.f, 12.f, 24.f}, "axis for pT"}; - ConfigurableAxis axisMlScore0{"axisMlScore0", {100, 0., 1.}, "axis for ML output score 0"}; - ConfigurableAxis axisMlScore1{"axisMlScore1", {100, 0., 1.}, "axis for ML output score 1"}; - ConfigurableAxis axisMlScore2{"axisMlScore2", {100, 0., 1.}, "axis for ML output score 2"}; + Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen particle rapidity"}; + Configurable yCandRecoMax{"yCandRecoMax", 0.8, "max. cand. rapidity"}; + Configurable massDsSignalMin{"massDsSignalMin", 1.934, "min mass for Ds signal"}; + Configurable massDsSignalMax{"massDsSignalMax", 1.994, "max mass for Ds signal"}; + Configurable massDplusSignalMin{"massDplusSignalMin", 1.866, "min mass for Dplus signal"}; + Configurable massDplusSignalMax{"massDplusSignalMax", 1.906, "max mass for Dplus signal"}; + Configurable fillPercentiles{"fillPercentiles", true, "Wheter to fill multiplicity axis with percentiles or raw information"}; + Configurable storeOccupancy{"storeOccupancy", false, "Flag to store occupancy information"}; + Configurable occEstimator{"occEstimator", 0, "Occupancy estimation (None: 0, ITS: 1, FT0C: 2)"}; + Configurable fillMcBkgHistos{"fillMcBkgHistos", false, "Flag to fill and store histograms for MC background"}; + + struct : ConfigurableGroup { + Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "The CCDB endpoint url address"}; + Configurable ccdbPath{"ccdbPath", "Centrality/Calibration", "The CCDB path for centrality/multiplicity information"}; + Configurable reconstructionPass{"reconstructionPass", "", {"Apass to use when fetching the calibration tables. Empty (default) does not check for any pass. Use `metadata` to fetch it from the AO2D metadata. Otherwise it will override the metadata."}}; + } ccdbConfig; HfHelper hfHelper; + SliceCache cache; + Service ccdb; - using CentralityEstimator = o2::aod::hf_collision_centrality::CentralityEstimator; - using TH1_ptr = std::shared_ptr; - using TH2_ptr = std::shared_ptr; - using THnSparse_ptr = std::shared_ptr; - using histTypes = std::variant; + using TH1Ptr = std::shared_ptr; + using TH2Ptr = std::shared_ptr; + using THnSparsePtr = std::shared_ptr; + using HistTypes = std::variant; + template + using MemberFunctionPointer = bool (HfTaskDs::*)(const CandDs&); + + using CollisionsWithFT0C = soa::Join; + using CollisionsWithFT0M = soa::Join; + using CollisionsWithNTracksPV = soa::Join; + + using CollisionsMc = soa::Join; + using CollisionsMcWithFT0C = soa::Join; + using CollisionsMcWithFT0M = soa::Join; + using CollisionsMcWithNTracksPV = soa::Join; - using CollisionsWithFT0C = soa::Join; - using CollisionsWithFT0M = soa::Join; - using CollisionsWithNTracksPV = soa::Join; using CandDsData = soa::Filtered>; using CandDsDataWithMl = soa::Filtered>; using CandDsMcReco = soa::Filtered>; using CandDsMcRecoWithMl = soa::Filtered>; using CandDsMcGen = soa::Join; - int offsetDplusDecayChannel = aod::hf_cand_3prong::DecayChannelDToKKPi::DplusToPhiPi - aod::hf_cand_3prong::DecayChannelDToKKPi::DsToPhiPi; // Offset between Dplus and Ds to use the same decay channel. See aod::hf_cand_3prong::DecayChannelDToKKPi - Filter filterDsFlag = (o2::aod::hf_track_index::hfflag & static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi))) != static_cast(0); - // Data - Partition selectedDsToKKPiCandData = aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlagDs; - Partition selectedDsToKKPiCandWithMlData = aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlagDs; - Partition selectedDsToPiKKCandData = aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlagDs; - Partition selectedDsToPiKKCandWithMlData = aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlagDs; - - // MC - Partition selectedDsToKKPiCandMc = aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlagDs; - Partition selectedDsToKKPiCandWithMlMc = aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlagDs; - Partition selectedDsToPiKKCandMc = aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlagDs; - Partition selectedDsToPiKKCandWithMlMc = aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlagDs; - - // Matched MC, no ML - Partition reconstructedCandDsSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi)) && aod::hf_cand_3prong::flagMcDecayChanRec == decayChannel; - Partition reconstructedCandDplusSig = fillDplusMc && nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi)) && aod::hf_cand_3prong::flagMcDecayChanRec == (decayChannel + offsetDplusDecayChannel); - Partition reconstructedCandDplusBkg = fillDplusMc && nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi)); - Partition reconstructedCandBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi)); - - // Matched MC, with ML - Partition reconstructedCandDsSigWithMl = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi)) && aod::hf_cand_3prong::flagMcDecayChanRec == decayChannel; - Partition reconstructedCandDplusSigWithMl = fillDplusMc && nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi)) && aod::hf_cand_3prong::flagMcDecayChanRec == (decayChannel + offsetDplusDecayChannel); - Partition reconstructedCandDplusBkgWithMl = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi)) && aod::hf_cand_3prong::flagMcDecayChanRec == decayChannel; - Partition reconstructedCandBkgWithMl = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi)); + Preslice candDsPerCollision = aod::hf_cand::collisionId; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 8.f, 12.f, 24.f}, "axis for pT"}; + ConfigurableAxis axisPtBHad{"axisPtBHad", {50, 0., 100}, "axis for pt of B hadron decayed into D candidate"}; + ConfigurableAxis axisFlagBHad{"axisFlagBHad", {5, 0, 5}, "axis for B hadron mother flag"}; + ConfigurableAxis axisNPvContributors{"axisNPvContributors", {200, -0.5f, 199.5f}, "axis for NPvContributors"}; + ConfigurableAxis axisMlScore0{"axisMlScore0", {100, 0., 1.}, "axis for ML output score 0"}; + ConfigurableAxis axisMlScore1{"axisMlScore1", {100, 0., 1.}, "axis for ML output score 1"}; + ConfigurableAxis axisMlScore2{"axisMlScore2", {100, 0., 1.}, "axis for ML output score 2"}; + ConfigurableAxis axisCentrality{"axisCentrality", {100, 0., 1.}, "axis for centrality/multiplicity"}; + ConfigurableAxis axisOccupancy{"axisOccupancy", {14, 0., 14000.}, "axis for occupancy"}; + + int offsetDplusDecayChannel = aod::hf_cand_3prong::DecayChannelDToKKPi::DplusToPhiPi - aod::hf_cand_3prong::DecayChannelDToKKPi::DsToPhiPi; // Offset between Dplus and Ds to use the same decay channel. See aod::hf_cand_3prong::DecayChannelDToKKPi + int mRunNumber{0}; + bool lCalibLoaded; + TList* lCalibObjects; + TProfile* hVtxZFT0A; + TProfile* hVtxZFT0C; + TProfile* hVtxZNTracks; HistogramRegistry registry{"registry", {}}; - std::array folders = {"Data/", "MC/Ds/Prompt/", "MC/Ds/NonPrompt/", "MC/Dplus/Prompt/", "MC/Dplus/NonPrompt/", "MC/Dplus/Bkg/", "MC/Bkg/"}; + std::array folders = {"Data/", "MC/Ds/Prompt/", "MC/Ds/NonPrompt/", "MC/Dplus/Prompt/", "MC/Dplus/NonPrompt/", "MC/Dplus/Bkg/", "MC/Lc/", "MC/Bkg/"}; - std::unordered_map dataHistograms = {}; - std::unordered_map mcDsPromptHistograms = {}; - std::unordered_map mcDsNonPromptHistograms = {}; - std::unordered_map mcDplusPromptHistograms = {}; - std::unordered_map mcDplusNonPromptHistograms = {}; - std::unordered_map mcDplusBkgHistograms = {}; - std::unordered_map mcBkgHistograms = {}; + std::unordered_map dataHistograms = {}; + std::unordered_map mcDsPromptHistograms = {}; + std::unordered_map mcDsNonPromptHistograms = {}; + std::unordered_map mcDplusPromptHistograms = {}; + std::unordered_map mcDplusNonPromptHistograms = {}; + std::unordered_map mcDplusBkgHistograms = {}; + std::unordered_map mcLcBkgHistograms = {}; + std::unordered_map mcBkgHistograms = {}; - std::array, DataType::kDataTypes> histosPtr = {dataHistograms, mcDsPromptHistograms, mcDsNonPromptHistograms, mcDplusPromptHistograms, mcDplusNonPromptHistograms, mcDplusBkgHistograms, mcBkgHistograms}; + std::array, DataType::kDataTypes> histosPtr = {dataHistograms, mcDsPromptHistograms, mcDsNonPromptHistograms, mcDplusPromptHistograms, mcDplusNonPromptHistograms, mcDplusBkgHistograms, mcLcBkgHistograms, mcBkgHistograms}; void init(InitContext&) { @@ -133,22 +163,64 @@ struct HfTaskDs { } AxisSpec ptbins{axisPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptBHad{axisPtBHad, "#it{p}_{T}(B) (GeV/#it{c})"}; + AxisSpec flagBHad{axisFlagBHad, "B Hadron flag"}; AxisSpec ybins = {100, -5., 5, "#it{y}"}; AxisSpec massbins = {600, 1.67, 2.27, "inv. mass (KK#pi) (GeV/#it{c}^{2})"}; AxisSpec centralitybins = {100, 0., 100., "Centrality"}; + AxisSpec npvcontributorsbins = {axisNPvContributors, "NPvContributors"}; + AxisSpec mlscore0bins = {axisMlScore0, "Score 0"}; + AxisSpec mlscore1bins = {axisMlScore1, "Score 1"}; + AxisSpec mlscore2bins = {axisMlScore2, "Score 2"}; + AxisSpec occupancybins = {axisOccupancy, "Occupancy"}; + + histosPtr[DataType::Data]["hNPvContribAll"] = registry.add((folders[DataType::Data] + "hNPvContribAll").c_str(), "3-prong candidates;NPvContributors;Centrality;Entries", HistType::kTH2F, {axisNPvContributors, {100, 0., 100}}); + + std::vector axes = {massbins, ptbins, centralitybins}; + std::vector axesMl = {massbins, ptbins, centralitybins, mlscore0bins, mlscore1bins, mlscore2bins}; + std::vector axesFdWithNpv = {massbins, ptbins, centralitybins, npvcontributorsbins, ptBHad, flagBHad}; + std::vector axesFdWithNpvMl = {massbins, ptbins, centralitybins, mlscore0bins, mlscore1bins, mlscore2bins, npvcontributorsbins, ptBHad, flagBHad}; + std::vector axesWithNpv = {massbins, ptbins, centralitybins, npvcontributorsbins}; + std::vector axesWithNpvMl = {massbins, ptbins, centralitybins, mlscore0bins, mlscore1bins, mlscore2bins, npvcontributorsbins}; + std::vector axesGenPrompt = {ptbins, ybins, npvcontributorsbins, centralitybins}; + std::vector axesGenFd = {ptbins, ybins, npvcontributorsbins, centralitybins, ptBHad, flagBHad}; + + if (storeOccupancy) { + axes.insert(axes.end(), {occupancybins}); + axesMl.insert(axesMl.end(), {occupancybins}); + axesFdWithNpv.insert(axesFdWithNpv.end(), {occupancybins}); + axesFdWithNpvMl.insert(axesFdWithNpvMl.end(), {occupancybins}); + axesWithNpv.insert(axesWithNpv.end(), {occupancybins}); + axesWithNpvMl.insert(axesWithNpvMl.end(), {occupancybins}); + axesGenPrompt.insert(axesGenPrompt.end(), {occupancybins}); + axesGenFd.insert(axesGenFd.end(), {occupancybins}); + } for (auto i = 0; i < DataType::kDataTypes; ++i) { - if (doprocessDataWithCentFT0C || doprocessDataWithCentFT0M || doprocessDataWithCentNTracksPV || - doprocessMcWithCentFT0C || doprocessMcWithCentFT0M || doprocessMcWithCentNTracksPV) { - histosPtr[i]["hSparseMass"] = registry.add((folders[i] + "hSparseMass").c_str(), "THn for Ds", HistType::kTHnSparseF, {massbins, ptbins, centralitybins}); - } else if (doprocessDataWithMlAndCentFT0C || doprocessDataWithMlAndCentFT0M || doprocessDataWithMlAndCentNTracksPV || - doprocessMcWithMlAndCentFT0C || doprocessMcWithMlAndCentFT0M || doprocessMcWithMlAndCentNTracksPV) { - histosPtr[i]["hSparseMass"] = registry.add((folders[i] + "hSparseMass").c_str(), "THn for Ds", HistType::kTHnSparseF, {massbins, ptbins, centralitybins, axisMlScore0, axisMlScore1, axisMlScore2}); - } else if (doprocessData || doprocessMc) { - histosPtr[i]["hSparseMass"] = registry.add((folders[i] + "hSparseMass").c_str(), "THn for Ds", HistType::kTHnSparseF, {massbins, ptbins}); - } else if (doprocessDataWithMl || doprocessMcWithMl) { - histosPtr[i]["hSparseMass"] = registry.add((folders[i] + "hSparseMass").c_str(), "THn for Ds", HistType::kTHnSparseF, {massbins, ptbins, axisMlScore0, axisMlScore1, axisMlScore2}); + if (doprocessDataWithCentFT0C || doprocessDataWithCentFT0M || doprocessDataWithCentNTracksPV || doprocessData || doprocessMcWithCentFT0C || doprocessMcWithCentFT0M || doprocessMcWithCentNTracksPV || doprocessMc) { + if (i == DataType::Data) { // If data do not fill PV contributors in sparse + histosPtr[i]["hSparseMass"] = registry.add((folders[i] + "hSparseMass").c_str(), "THn for Ds", HistType::kTHnSparseF, axes); + } else if (i == DataType::McDsNonPrompt || i == DataType::McDplusNonPrompt) { + histosPtr[i]["hSparseMass"] = registry.add((folders[i] + "hSparseMass").c_str(), "THn for Ds", HistType::kTHnSparseF, axesFdWithNpv); + } else { + histosPtr[i]["hSparseMass"] = registry.add((folders[i] + "hSparseMass").c_str(), "THn for Ds", HistType::kTHnSparseF, axesWithNpv); + } + } else if (doprocessDataWithMlAndCentFT0C || doprocessDataWithMlAndCentFT0M || doprocessDataWithMlAndCentNTracksPV || doprocessDataWithMl || doprocessMcWithMlAndCentFT0C || doprocessMcWithMlAndCentFT0M || doprocessMcWithMlAndCentNTracksPV || doprocessMcWithMl) { + if (i == DataType::McBkg && !fillMcBkgHistos) { + continue; + } + + if (i == DataType::Data) { // If data do not fill PV contributors in sparse + histosPtr[i]["hSparseMass"] = registry.add((folders[i] + "hSparseMass").c_str(), "THn for Ds", HistType::kTHnSparseF, axesMl); + } else if (i == DataType::McDsNonPrompt || i == DataType::McDplusNonPrompt) { + histosPtr[i]["hSparseMass"] = registry.add((folders[i] + "hSparseMass").c_str(), "THn for Ds", HistType::kTHnSparseF, axesFdWithNpvMl); + } else { + histosPtr[i]["hSparseMass"] = registry.add((folders[i] + "hSparseMass").c_str(), "THn for Ds", HistType::kTHnSparseF, axesWithNpvMl); + } } + histosPtr[i]["hNPvContribCands"] = registry.add((folders[i] + "hNPvContribCands").c_str(), "3-prong candidates;NPvContributors;Centrality;Entries", HistType::kTH2F, {axisNPvContributors, centralitybins}); + histosPtr[i]["hNPvContribCandsInSignalRegionDs"] = registry.add((folders[i] + "hNPvContribCandsInSignalRegionDs").c_str(), "3-prong candidates;NPvContributors;Centrality;Entries", HistType::kTH2F, {axisNPvContributors, centralitybins}); + histosPtr[i]["hNPvContribCandsInSignalRegionDplus"] = registry.add((folders[i] + "hNPvContribCandsInSignalRegionDplus").c_str(), "3-prong candidates;NPvContributors;Centrality;Entries", HistType::kTH2F, {axisNPvContributors, centralitybins}); histosPtr[i]["hPt"] = registry.add((folders[i] + "hPt").c_str(), "3-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}); histosPtr[i]["hPtProng0"] = registry.add((folders[i] + "hPtProng0").c_str(), "3-prong candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}); histosPtr[i]["hPtProng1"] = registry.add((folders[i] + "hPtProng1").c_str(), "3-prong candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}); @@ -180,35 +252,143 @@ struct HfTaskDs { doprocessMc || doprocessMcWithMl) { // processing MC for (auto i = 0; i < DataType::kDataTypes; ++i) { - if (i == DataType::McDsPrompt || i == DataType::McDsNonPrompt || i == DataType::McDplusPrompt || i == DataType::McDplusNonPrompt || i == DataType::McDplusBkg) { - + if (i == DataType::McDsPrompt || i == DataType::McDsNonPrompt || i == DataType::McDplusPrompt || i == DataType::McDplusNonPrompt || i == DataType::McDplusBkg || i == DataType::McLcBkg) { histosPtr[i]["hEtaGen"] = registry.add((folders[i] + "hEtaGen").c_str(), "3-prong candidates (matched);#eta;entries", {HistType::kTH1F, {{100, -2., 2.}}}); - histosPtr[i]["hEtaRecSig"] = registry.add((folders[i] + "hEtaRecSig").c_str(), "3-prong candidates (matched);#eta;entries", {HistType::kTH1F, {{100, -2., 2.}}}); - histosPtr[i]["hCPARecSig"] = registry.add((folders[i] + "hCPARecSig").c_str(), "3-prong candidates (matched);cos. pointing angle;entries", {HistType::kTH1F, {{100, -1., 1.}}}); - histosPtr[i]["hPtRecSig"] = registry.add((folders[i] + "hPtRecSig").c_str(), "3-prong candidates (matched);#it{p}_{T}^{rec.} (GeV/#it{c});entries", {HistType::kTH1F, {ptbins}}); - histosPtr[i]["hPtGenSig"] = registry.add((folders[i] + "hPtGenSig").c_str(), "MC particles (matched);#it{p}_{T}^{gen.} (GeV/#it{c});entries", {HistType::kTH1F, {ptbins}}); histosPtr[i]["hPtGen"] = registry.add((folders[i] + "hPtGen").c_str(), "MC particles (unmatched);#it{p}_{T}^{gen.} (GeV/#it{c});entries", {HistType::kTH1F, {ptbins}}); - histosPtr[i]["hPtVsYRecSigRecoPID"] = registry.add((folders[i] + "hPtVsYRecSigRecoPID").c_str(), "3-prong candidates (RecoPID - matched);#it{p}_{T}^{rec.}; #it{y}", {HistType::kTH2F, {ptbins, {ybins}}}); - histosPtr[i]["hPtVsYRecSigRecoTopol"] = registry.add((folders[i] + "hPtVsYRecSigRecoTopol").c_str(), "3-prong candidates (RecoTopol - matched);#it{p}_{T}^{rec.}; #it{y}", {HistType::kTH2F, {ptbins, {ybins}}}); - histosPtr[i]["hPtVsYRecSigRecoSkim"] = registry.add((folders[i] + "hPtVsYRecSigRecoSkim").c_str(), "3-prong candidates (RecoSkim - matched);#it{p}_{T}^{rec.}; #it{y}", {HistType::kTH2F, {ptbins, {ybins}}}); - histosPtr[i]["hPtVsYGen"] = registry.add((folders[i] + "hPtVsYGen").c_str(), "MC particles (unmatched);#it{p}_{T}^{gen.}; #it{y}", {HistType::kTH2F, {ptbins, {ybins}}}); + histosPtr[i]["hPtVsYRecoPID"] = registry.add((folders[i] + "hPtVsYRecoPID").c_str(), "3-prong candidates (RecoPID - matched);#it{p}_{T}^{rec.}; #it{y}", {HistType::kTH2F, {ptbins, {ybins}}}); + histosPtr[i]["hPtVsYRecoTopol"] = registry.add((folders[i] + "hPtVsYRecoTopol").c_str(), "3-prong candidates (RecoTopol - matched);#it{p}_{T}^{rec.}; #it{y}", {HistType::kTH2F, {ptbins, {ybins}}}); + histosPtr[i]["hPtVsYRecoSkim"] = registry.add((folders[i] + "hPtVsYRecoSkim").c_str(), "3-prong candidates (RecoSkim - matched);#it{p}_{T}^{rec.}; #it{y}", {HistType::kTH2F, {ptbins, {ybins}}}); + } + if (i == DataType::McDsPrompt || i == DataType::McDplusPrompt) { + histosPtr[i]["hSparseGen"] = registry.add((folders[i] + "hSparseGen").c_str(), "Thn for generated prompt candidates", HistType::kTHnSparseF, axesGenPrompt); + } + if (i == DataType::McDsNonPrompt || i == DataType::McDplusNonPrompt) { + histosPtr[i]["hSparseGen"] = registry.add((folders[i] + "hSparseGen").c_str(), "Thn for generated nonprompt candidates", HistType::kTHnSparseF, axesGenFd); } } } } - /// Evaluate multiplicity + template + bool isDsPrompt(const CandDs& candidate) + { + return std::abs(candidate.flagMcMatchRec()) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi)) && candidate.flagMcDecayChanRec() == decayChannel && candidate.originMcRec() == RecoDecay::OriginType::Prompt; + } + + template + bool isDplusPrompt(const CandDs& candidate) + { + return std::abs(candidate.flagMcMatchRec()) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi)) && candidate.flagMcDecayChanRec() == decayChannel + offsetDplusDecayChannel && candidate.originMcRec() == RecoDecay::OriginType::Prompt; + } + + template + bool isDsNonPrompt(const CandDs& candidate) + { + return std::abs(candidate.flagMcMatchRec()) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi)) && candidate.flagMcDecayChanRec() == decayChannel && candidate.originMcRec() == RecoDecay::OriginType::NonPrompt; + } + + template + bool isDplusNonPrompt(const CandDs& candidate) + { + return std::abs(candidate.flagMcMatchRec()) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi)) && candidate.flagMcDecayChanRec() == decayChannel + offsetDplusDecayChannel && candidate.originMcRec() == RecoDecay::OriginType::NonPrompt; + } + + template + bool isDplusBkg(const CandDs& candidate) + { + return std::abs(candidate.flagMcMatchRec()) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi)); + } + + template + bool isLcBkg(const CandDs& candidate) + { + return std::abs(candidate.flagMcMatchRec()) == static_cast(BIT(aod::hf_cand_3prong::DecayType::LcToPKPi)); + } + + /// Checks whether the candidate is in the signal region of either the Ds or D+ decay + /// \param candidate is the candidate + /// \param isDs is true if we check for the Ds signal region, false for the D+ signal region + /// \return true if the candidate is in the signal region, false otherwise + template + bool isCandInSignalRegion(const CandDs& candidate, bool isDs) + { + bool isKKPi = candidate.isSelDsToKKPi() >= selectionFlagDs; + float invMass = isKKPi ? hfHelper.invMassDsToKKPi(candidate) : hfHelper.invMassDsToPiKK(candidate); + if (isDs && (invMass < massDsSignalMin || invMass > massDsSignalMax)) { + return false; + } + if (!isDs && (invMass < massDplusSignalMin || invMass > massDplusSignalMax)) { + return false; + } + return true; + } + + /// Evaluate centrality/multiplicity percentile using FT0M estimator + /// \param candidate is candidate + /// \return centrality/multiplicity percentile of the collision + template + float getZEqMultColl(const Coll& collision, uint8_t nProngsContributorsPV) + { + auto multFT0A = collision.multFT0A() - nProngsContributorsPV; + auto multFT0C = collision.multFT0C() - nProngsContributorsPV; + float multZeqFT0A = hVtxZFT0A->Interpolate(0.0) * multFT0A / hVtxZFT0A->Interpolate(collision.posZ()); + float multZeqFT0C = hVtxZFT0C->Interpolate(0.0) * multFT0C / hVtxZFT0C->Interpolate(collision.posZ()); + return multZeqFT0A + multZeqFT0C; + } + + /// Evaluate centrality/multiplicity percentile using NTracksPV estimator /// \param candidate is candidate - /// \return multiplicity of the collision associated to the candidate - template - int evaluateCentrality(const T1& candidate) + /// \return centrality/multiplicity percentile of the collision + template + float getZEqMultColl(const Coll& collision, uint8_t nProngsContributorsPV) { - if constexpr (centDetector == CentralityEstimator::FT0C) - return candidate.template collision_as().centFT0C(); - else if constexpr (centDetector == CentralityEstimator::FT0M) - return candidate.template collision_as().centFT0M(); - else if constexpr (centDetector == CentralityEstimator::NTracksPV) - return candidate.template collision_as().centNTPV(); + auto multNTracksPV = collision.multNTracksPV() - nProngsContributorsPV; + float multZeqNTracksPV = hVtxZNTracks->Interpolate(0.0) * multNTracksPV / hVtxZNTracks->Interpolate(collision.posZ()); + return multZeqNTracksPV; + } + + /// Default case if no centrality/multiplicity estimator is provided + /// \param candidate is candidate + /// \return dummy value for centrality/multiplicity percentile of the collision + template + float getZEqMultColl(const Coll&, uint8_t) + { + return -1.f; + } + + /// Evaluate centrality/multiplicity percentile (centrality estimator is automatically selected based on the used table) + /// \param candidate is candidate + /// \return centrality/multiplicity percentile of the collision + template + float evaluateCentralityColl(const Coll& collision, const CandDs& candidate) + { + if (fillPercentiles) { + return o2::hf_centrality::getCentralityColl(collision); + } else { + return getZEqMultColl(collision, candidate.nProngsContributorsPV()); + } + } + + /// Evaluate centrality/multiplicity percentile (centrality estimator is automatically selected based on the used table) + /// \param candidate is candidate + /// \return centrality/multiplicity percentile of the collision + template + float evaluateCentralityColl(const Coll& collision) + { + if (fillPercentiles) { + return o2::hf_centrality::getCentralityColl(collision); + } else { + return getZEqMultColl(collision, 0); + } + } + + /// Evaluate centrality/multiplicity percentile + /// \param candidate is candidate + /// \return centrality/multiplicity percentile of the collision associated to the candidate + template + float evaluateCentralityCand(const T1& candidate) + { + return evaluateCentralityColl(candidate.template collision_as(), candidate); } /// Fill histograms of quantities independent from the daugther-mass hypothesis @@ -218,94 +398,151 @@ struct HfTaskDs { void fillHisto(const T1& candidate, DataType dataType) { auto pt = candidate.pt(); - std::get(histosPtr[dataType]["hPt"])->Fill(pt); - std::get(histosPtr[dataType]["hPtProng0"])->Fill(candidate.ptProng0()); - std::get(histosPtr[dataType]["hPtProng1"])->Fill(candidate.ptProng1()); - std::get(histosPtr[dataType]["hPtProng2"])->Fill(candidate.ptProng2()); - std::get(histosPtr[dataType]["hEta"])->Fill(candidate.eta(), pt); - std::get(histosPtr[dataType]["hCt"])->Fill(hfHelper.ctDs(candidate), pt); - std::get(histosPtr[dataType]["hDecayLength"])->Fill(candidate.decayLength(), pt); - std::get(histosPtr[dataType]["hDecayLengthXY"])->Fill(candidate.decayLengthXY(), pt); - std::get(histosPtr[dataType]["hNormalisedDecayLengthXY"])->Fill(candidate.decayLengthXYNormalised(), pt); - std::get(histosPtr[dataType]["hCPA"])->Fill(candidate.cpa(), pt); - std::get(histosPtr[dataType]["hCPAxy"])->Fill(candidate.cpaXY(), pt); - std::get(histosPtr[dataType]["hImpactParameterXY"])->Fill(candidate.impactParameterXY(), pt); - std::get(histosPtr[dataType]["hMaxNormalisedDeltaIP"])->Fill(candidate.maxNormalisedDeltaIP(), pt); - std::get(histosPtr[dataType]["hImpactParameterProngSqSum"])->Fill(candidate.impactParameterProngSqSum(), pt); - std::get(histosPtr[dataType]["hDecayLengthError"])->Fill(candidate.errorDecayLength(), pt); - std::get(histosPtr[dataType]["hDecayLengthXYError"])->Fill(candidate.errorDecayLengthXY(), pt); - std::get(histosPtr[dataType]["hImpactParameterError"])->Fill(candidate.errorImpactParameter0(), pt); - std::get(histosPtr[dataType]["hImpactParameterError"])->Fill(candidate.errorImpactParameter1(), pt); - std::get(histosPtr[dataType]["hImpactParameterError"])->Fill(candidate.errorImpactParameter2(), pt); - std::get(histosPtr[dataType]["hd0Prong0"])->Fill(candidate.impactParameter0(), pt); - std::get(histosPtr[dataType]["hd0Prong1"])->Fill(candidate.impactParameter1(), pt); - std::get(histosPtr[dataType]["hd0Prong2"])->Fill(candidate.impactParameter2(), pt); + std::get(histosPtr[dataType]["hPt"])->Fill(pt); + std::get(histosPtr[dataType]["hPtProng0"])->Fill(candidate.ptProng0()); + std::get(histosPtr[dataType]["hPtProng1"])->Fill(candidate.ptProng1()); + std::get(histosPtr[dataType]["hPtProng2"])->Fill(candidate.ptProng2()); + std::get(histosPtr[dataType]["hEta"])->Fill(candidate.eta(), pt); + std::get(histosPtr[dataType]["hCt"])->Fill(hfHelper.ctDs(candidate), pt); + std::get(histosPtr[dataType]["hDecayLength"])->Fill(candidate.decayLength(), pt); + std::get(histosPtr[dataType]["hDecayLengthXY"])->Fill(candidate.decayLengthXY(), pt); + std::get(histosPtr[dataType]["hNormalisedDecayLengthXY"])->Fill(candidate.decayLengthXYNormalised(), pt); + std::get(histosPtr[dataType]["hCPA"])->Fill(candidate.cpa(), pt); + std::get(histosPtr[dataType]["hCPAxy"])->Fill(candidate.cpaXY(), pt); + std::get(histosPtr[dataType]["hImpactParameterXY"])->Fill(candidate.impactParameterXY(), pt); + std::get(histosPtr[dataType]["hMaxNormalisedDeltaIP"])->Fill(candidate.maxNormalisedDeltaIP(), pt); + std::get(histosPtr[dataType]["hImpactParameterProngSqSum"])->Fill(candidate.impactParameterProngSqSum(), pt); + std::get(histosPtr[dataType]["hDecayLengthError"])->Fill(candidate.errorDecayLength(), pt); + std::get(histosPtr[dataType]["hDecayLengthXYError"])->Fill(candidate.errorDecayLengthXY(), pt); + std::get(histosPtr[dataType]["hImpactParameterError"])->Fill(candidate.errorImpactParameter0(), pt); + std::get(histosPtr[dataType]["hImpactParameterError"])->Fill(candidate.errorImpactParameter1(), pt); + std::get(histosPtr[dataType]["hImpactParameterError"])->Fill(candidate.errorImpactParameter2(), pt); + std::get(histosPtr[dataType]["hd0Prong0"])->Fill(candidate.impactParameter0(), pt); + std::get(histosPtr[dataType]["hd0Prong1"])->Fill(candidate.impactParameter1(), pt); + std::get(histosPtr[dataType]["hd0Prong2"])->Fill(candidate.impactParameter2(), pt); return; } - /// Fill histograms of quantities for the KKPi daugther-mass hypothesis + /// Fill mass sparse if ML information is present /// \param candidate is candidate /// \param dataType is data class, as defined in DataType enum - template - void fillHistoKKPi(const T1& candidate, DataType dataType) + /// \param finalState is either KKPi or PiKK, as defined in FinalState enum + template + void fillSparse(const Cand& candidate, DataType dataType, FinalState finalState) { + auto mass = finalState == FinalState::KKPi ? hfHelper.invMassDsToKKPi(candidate) : hfHelper.invMassDsToPiKK(candidate); auto pt = candidate.pt(); - if constexpr (useMl) { - std::vector outputMl = {-999., -999., -999.}; - for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { // TODO: add checks for classMl size - outputMl[iclass] = candidate.mlProbDsToKKPi()[classMl->at(iclass)]; + auto mlScore = finalState == FinalState::KKPi ? candidate.mlProbDsToKKPi() : candidate.mlProbDsToPiKK(); + + std::vector outputMl = {-999., -999., -999.}; + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { // TODO: add checks for classMl size + if (mlScore.size() == 0) { + continue; } - if constexpr (centDetector != CentralityEstimator::None) { - std::get(histosPtr[dataType]["hSparseMass"])->Fill(hfHelper.invMassDsToKKPi(candidate), pt, evaluateCentrality(candidate), outputMl[0], outputMl[1], outputMl[2]); + outputMl[iclass] = mlScore[classMl->at(iclass)]; + } + + if (dataType == DataType::Data) { // If data do not fill PV contributors in sparse + if (storeOccupancy) { + std::get(histosPtr[dataType]["hSparseMass"])->Fill(mass, pt, evaluateCentralityCand(candidate), outputMl[0], outputMl[1], outputMl[2], o2::hf_occupancy::getOccupancyColl(candidate.template collision_as(), occEstimator)); + return; } else { - std::get(histosPtr[dataType]["hSparseMass"])->Fill(hfHelper.invMassDsToKKPi(candidate), pt, outputMl[0], outputMl[1], outputMl[2]); + std::get(histosPtr[dataType]["hSparseMass"])->Fill(mass, pt, evaluateCentralityCand(candidate), outputMl[0], outputMl[1], outputMl[2]); + return; } - } else { - if constexpr (centDetector != CentralityEstimator::None) { - std::get(histosPtr[dataType]["hSparseMass"])->Fill(hfHelper.invMassDsToKKPi(candidate), pt, evaluateCentrality(candidate)); + } + if constexpr (isMc) { + if (dataType == DataType::McDsNonPrompt || dataType == DataType::McDplusNonPrompt) { + if (storeOccupancy) { + std::get(histosPtr[dataType]["hSparseMass"])->Fill(mass, pt, evaluateCentralityCand(candidate), outputMl[0], outputMl[1], outputMl[2], candidate.template collision_as().numContrib(), candidate.ptBhadMotherPart(), getBHadMotherFlag(candidate.pdgBhadMotherPart()), o2::hf_occupancy::getOccupancyColl(candidate.template collision_as(), occEstimator)); + return; + } else { + std::get(histosPtr[dataType]["hSparseMass"])->Fill(mass, pt, evaluateCentralityCand(candidate), outputMl[0], outputMl[1], outputMl[2], candidate.template collision_as().numContrib(), candidate.ptBhadMotherPart(), getBHadMotherFlag(candidate.pdgBhadMotherPart())); + return; + } } else { - std::get(histosPtr[dataType]["hSparseMass"])->Fill(hfHelper.invMassDsToKKPi(candidate), pt); + if (storeOccupancy) { + std::get(histosPtr[dataType]["hSparseMass"])->Fill(mass, pt, evaluateCentralityCand(candidate), outputMl[0], outputMl[1], outputMl[2], candidate.template collision_as().numContrib(), o2::hf_occupancy::getOccupancyColl(candidate.template collision_as(), occEstimator)); + return; + } else { + std::get(histosPtr[dataType]["hSparseMass"])->Fill(mass, pt, evaluateCentralityCand(candidate), outputMl[0], outputMl[1], outputMl[2], candidate.template collision_as().numContrib()); + return; + } } } - - std::get(histosPtr[dataType]["hCos3PiK"])->Fill(hfHelper.cos3PiKDsToKKPi(candidate), pt); - std::get(histosPtr[dataType]["hAbsCos3PiK"])->Fill(hfHelper.absCos3PiKDsToKKPi(candidate), pt); - std::get(histosPtr[dataType]["hDeltaMassPhi"])->Fill(hfHelper.deltaMassPhiDsToKKPi(candidate), pt); - std::get(histosPtr[dataType]["hMassKK"])->Fill(hfHelper.massKKPairDsToKKPi(candidate), pt); - - return; } - /// Fill histograms of quantities for the PiKK daugther-mass hypothesis + /// Fill mass sparse if ML information is not present /// \param candidate is candidate /// \param dataType is data class, as defined in DataType enum - template - void fillHistoPiKK(const T1& candidate, DataType dataType) + /// \param finalState is either KKPi or PiKK, as defined in FinalState enum + template + void fillSparse(const Cand& candidate, DataType dataType, FinalState finalState) { + auto mass = finalState == FinalState::KKPi ? hfHelper.invMassDsToKKPi(candidate) : hfHelper.invMassDsToPiKK(candidate); auto pt = candidate.pt(); - if constexpr (useMl) { - std::vector outputMl = {-999., -999., -999.}; - for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { // TODO: add checks for classMl size - outputMl[iclass] = candidate.mlProbDsToPiKK()[classMl->at(iclass)]; - } - if constexpr (centDetector != CentralityEstimator::None) { - std::get(histosPtr[dataType]["hSparseMass"])->Fill(hfHelper.invMassDsToPiKK(candidate), pt, evaluateCentrality(candidate), outputMl[0], outputMl[1], outputMl[2]); + + if (dataType == DataType::Data) { // If data do not fill PV contributors in sparse + if (storeOccupancy) { + std::get(histosPtr[dataType]["hSparseMass"])->Fill(mass, pt, evaluateCentralityCand(candidate), o2::hf_occupancy::getOccupancyColl(candidate.template collision_as(), occEstimator)); + return; } else { - std::get(histosPtr[dataType]["hSparseMass"])->Fill(hfHelper.invMassDsToPiKK(candidate), pt, outputMl[0], outputMl[1], outputMl[2]); + std::get(histosPtr[dataType]["hSparseMass"])->Fill(mass, pt, evaluateCentralityCand(candidate)); + return; } - } else { - if constexpr (centDetector != CentralityEstimator::None) { - std::get(histosPtr[dataType]["hSparseMass"])->Fill(hfHelper.invMassDsToPiKK(candidate), pt, evaluateCentrality(candidate)); + } + if constexpr (isMc) { + if (dataType == DataType::McDsNonPrompt || dataType == DataType::McDplusNonPrompt) { + if (storeOccupancy) { + std::get(histosPtr[dataType]["hSparseMass"])->Fill(mass, pt, evaluateCentralityCand(candidate), candidate.template collision_as().numContrib(), candidate.ptBhadMotherPart(), getBHadMotherFlag(candidate.pdgBhadMotherPart()), o2::hf_occupancy::getOccupancyColl(candidate.template collision_as(), occEstimator)); + return; + } else { + std::get(histosPtr[dataType]["hSparseMass"])->Fill(mass, pt, evaluateCentralityCand(candidate), candidate.template collision_as().numContrib(), candidate.ptBhadMotherPart(), getBHadMotherFlag(candidate.pdgBhadMotherPart())); + return; + } } else { - std::get(histosPtr[dataType]["hSparseMass"])->Fill(hfHelper.invMassDsToPiKK(candidate), pt); + if (storeOccupancy) { + std::get(histosPtr[dataType]["hSparseMass"])->Fill(mass, pt, evaluateCentralityCand(candidate), candidate.template collision_as().numContrib(), o2::hf_occupancy::getOccupancyColl(candidate.template collision_as(), occEstimator)); + return; + } else { + std::get(histosPtr[dataType]["hSparseMass"])->Fill(mass, pt, evaluateCentralityCand(candidate), candidate.template collision_as().numContrib()); + return; + } } } + } - std::get(histosPtr[dataType]["hCos3PiK"])->Fill(hfHelper.cos3PiKDsToPiKK(candidate), pt); - std::get(histosPtr[dataType]["hAbsCos3PiK"])->Fill(hfHelper.absCos3PiKDsToPiKK(candidate), pt); - std::get(histosPtr[dataType]["hDeltaMassPhi"])->Fill(hfHelper.deltaMassPhiDsToPiKK(candidate), pt); - std::get(histosPtr[dataType]["hMassKK"])->Fill(hfHelper.massKKPairDsToPiKK(candidate), pt); + /// Fill histograms of quantities for the KKPi daugther-mass hypothesis + /// \param candidate is candidate + /// \param dataType is data class, as defined in DataType enum + template + void fillHistoKKPi(const T1& candidate, DataType dataType) + { + auto pt = candidate.pt(); + fillSparse(candidate, dataType, FinalState::KKPi); + + std::get(histosPtr[dataType]["hCos3PiK"])->Fill(hfHelper.cos3PiKDsToKKPi(candidate), pt); + std::get(histosPtr[dataType]["hAbsCos3PiK"])->Fill(hfHelper.absCos3PiKDsToKKPi(candidate), pt); + std::get(histosPtr[dataType]["hDeltaMassPhi"])->Fill(hfHelper.deltaMassPhiDsToKKPi(candidate), pt); + std::get(histosPtr[dataType]["hMassKK"])->Fill(hfHelper.massKKPairDsToKKPi(candidate), pt); + + return; + } + + /// Fill histograms of quantities for the PiKK daugther-mass hypothesis + /// \param candidate is candidate + /// \param dataType is data class, as defined in DataType enum + template + void fillHistoPiKK(const T1& candidate, DataType dataType) + { + auto pt = candidate.pt(); + fillSparse(candidate, dataType, FinalState::PiKK); + + std::get(histosPtr[dataType]["hCos3PiK"])->Fill(hfHelper.cos3PiKDsToPiKK(candidate), pt); + std::get(histosPtr[dataType]["hAbsCos3PiK"])->Fill(hfHelper.absCos3PiKDsToPiKK(candidate), pt); + std::get(histosPtr[dataType]["hDeltaMassPhi"])->Fill(hfHelper.deltaMassPhiDsToPiKK(candidate), pt); + std::get(histosPtr[dataType]["hMassKK"])->Fill(hfHelper.massKKPairDsToPiKK(candidate), pt); return; } @@ -314,250 +551,170 @@ struct HfTaskDs { /// \param candidate is candidate /// \param mcParticles are particles with MC information /// \param whichSpeciesDecay defines which histogram to fill - template - void fillHistoMCRec(const T1& candidate, const CandDsMcGen& mcParticles, SpeciesAndDecay whichSpeciesDecay) + template + void fillHistoMCRec(const T1& candidate, const CandDsMcGen& mcParticles, DataType dataType) { + + int id = o2::constants::physics::Pdg::kDS; + auto yCand = hfHelper.yDs(candidate); + if (dataType == DataType::McDplusPrompt || dataType == DataType::McDplusNonPrompt || dataType == DataType::McDplusBkg) { + id = o2::constants::physics::Pdg::kDPlus; + yCand = hfHelper.yDplus(candidate); + } else if (dataType == DataType::McLcBkg) { + id = o2::constants::physics::Pdg::kLambdaCPlus; + yCand = hfHelper.yLc(candidate); + } + auto indexMother = RecoDecay::getMother(mcParticles, candidate.template prong0_as().template mcParticle_as(), - whichSpeciesDecay == SpeciesAndDecay::DsToKKPi ? o2::constants::physics::Pdg::kDS : o2::constants::physics::Pdg::kDPlus, true); + id, true); if (indexMother != -1) { - if (yCandRecoMax >= 0. && std::abs(whichSpeciesDecay == SpeciesAndDecay::DsToKKPi ? hfHelper.yDs(candidate) : hfHelper.yDplus(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(yCand) > yCandRecoMax) { return; } - auto particleMother = mcParticles.iteratorAt(indexMother); - - int flag = candidate.isCandidateSwapped() ? candidate.isSelDsToPiKK() : candidate.isSelDsToKKPi(); // 0 corresponds to KKPi, 1 to PiKK - auto pt = candidate.pt(); // rec. level pT - // Ds - if (whichSpeciesDecay == SpeciesAndDecay::DsToKKPi) { - - auto y = hfHelper.yDs(candidate); - - // prompt - if (candidate.originMcRec() == RecoDecay::OriginType::Prompt) { - fillHisto(candidate, DataType::McDsPrompt); - if (candidate.isSelDsToKKPi() >= selectionFlagDs) // KKPi - fillHistoKKPi(candidate, DataType::McDsPrompt); - if (candidate.isSelDsToPiKK() >= selectionFlagDs) // PiKK - fillHistoPiKK(candidate, DataType::McDsPrompt); - - std::get(histosPtr[DataType::McDsPrompt]["hPtRecSig"])->Fill(pt); - std::get(histosPtr[DataType::McDsPrompt]["hPtGenSig"])->Fill(particleMother.pt()); // gen. level pT - std::get(histosPtr[DataType::McDsPrompt]["hPtVsYRecSigRecoSkim"])->Fill(pt, y); - std::get(histosPtr[DataType::McDsPrompt]["hCPARecSig"])->Fill(candidate.cpa()); - std::get(histosPtr[DataType::McDsPrompt]["hEtaRecSig"])->Fill(candidate.eta()); - if (TESTBIT(flag, aod::SelectionStep::RecoTopol)) { - std::get(histosPtr[DataType::McDsPrompt]["hPtVsYRecSigRecoTopol"])->Fill(pt, y); - } - if (TESTBIT(flag, aod::SelectionStep::RecoPID)) { - std::get(histosPtr[DataType::McDsPrompt]["hPtVsYRecSigRecoPID"])->Fill(pt, y); - } - } + if (candidate.isSelDsToKKPi() >= selectionFlagDs) { // KKPi + fillHisto(candidate, dataType); + fillHistoKKPi(candidate, dataType); - // non-prompt - if (candidate.originMcRec() == RecoDecay::OriginType::NonPrompt) { - fillHisto(candidate, DataType::McDsNonPrompt); - if (candidate.isSelDsToKKPi() >= selectionFlagDs) // KKPi - fillHistoKKPi(candidate, DataType::McDsNonPrompt); - if (candidate.isSelDsToPiKK() >= selectionFlagDs) // PiKK - fillHistoPiKK(candidate, DataType::McDsNonPrompt); - - std::get(histosPtr[DataType::McDsNonPrompt]["hPtRecSig"])->Fill(pt); - std::get(histosPtr[DataType::McDsNonPrompt]["hPtGenSig"])->Fill(particleMother.pt()); // gen. level pT - std::get(histosPtr[DataType::McDsNonPrompt]["hPtVsYRecSigRecoSkim"])->Fill(pt, y); - std::get(histosPtr[DataType::McDsNonPrompt]["hCPARecSig"])->Fill(candidate.cpa()); - std::get(histosPtr[DataType::McDsNonPrompt]["hEtaRecSig"])->Fill(candidate.eta()); - if (TESTBIT(flag, aod::SelectionStep::RecoTopol)) { - std::get(histosPtr[DataType::McDsNonPrompt]["hPtVsYRecSigRecoTopol"])->Fill(pt, y); - } - if (TESTBIT(flag, aod::SelectionStep::RecoPID)) { - std::get(histosPtr[DataType::McDsNonPrompt]["hPtVsYRecSigRecoPID"])->Fill(pt, y); - } + if (TESTBIT(candidate.isSelDsToKKPi(), aod::SelectionStep::RecoSkims)) { + std::get(histosPtr[dataType]["hPtVsYRecoSkim"])->Fill(pt, yCand); } - return; - } // end Ds - - // D+→ K± K∓ π± - if (whichSpeciesDecay == SpeciesAndDecay::DplusToKKPi) { - auto y = hfHelper.yDplus(candidate); - - // prompt - if (candidate.originMcRec() == RecoDecay::OriginType::Prompt) { - fillHisto(candidate, DataType::McDplusPrompt); - if (candidate.isSelDsToKKPi() >= selectionFlagDs) // KKPi - fillHistoKKPi(candidate, DataType::McDplusPrompt); - if (candidate.isSelDsToPiKK() >= selectionFlagDs) // PiKK - fillHistoPiKK(candidate, DataType::McDplusPrompt); - - std::get(histosPtr[DataType::McDplusPrompt]["hPtRecSig"])->Fill(pt); - std::get(histosPtr[DataType::McDplusPrompt]["hPtGenSig"])->Fill(particleMother.pt()); // gen. level pT - std::get(histosPtr[DataType::McDplusPrompt]["hPtVsYRecSigRecoSkim"])->Fill(pt, y); - std::get(histosPtr[DataType::McDplusPrompt]["hCPARecSig"])->Fill(candidate.cpa()); - std::get(histosPtr[DataType::McDplusPrompt]["hEtaRecSig"])->Fill(candidate.eta()); - if (TESTBIT(flag, aod::SelectionStep::RecoTopol)) { - std::get(histosPtr[DataType::McDplusPrompt]["hPtVsYRecSigRecoTopol"])->Fill(pt, y); - } - if (TESTBIT(flag, aod::SelectionStep::RecoPID)) { - std::get(histosPtr[DataType::McDplusPrompt]["hPtVsYRecSigRecoPID"])->Fill(pt, y); - } + if (TESTBIT(candidate.isSelDsToKKPi(), aod::SelectionStep::RecoTopol)) { + std::get(histosPtr[dataType]["hPtVsYRecoTopol"])->Fill(pt, yCand); } - - // non-prompt - if (candidate.originMcRec() == RecoDecay::OriginType::NonPrompt) { - fillHisto(candidate, DataType::McDplusNonPrompt); - if (candidate.isSelDsToKKPi() >= selectionFlagDs) // KKPi - fillHistoKKPi(candidate, DataType::McDplusNonPrompt); - if (candidate.isSelDsToPiKK() >= selectionFlagDs) // PiKK - fillHistoPiKK(candidate, DataType::McDplusNonPrompt); - - std::get(histosPtr[DataType::McDplusNonPrompt]["hPtRecSig"])->Fill(pt); - std::get(histosPtr[DataType::McDplusNonPrompt]["hPtGenSig"])->Fill(particleMother.pt()); // gen. level pT - std::get(histosPtr[DataType::McDplusNonPrompt]["hPtVsYRecSigRecoSkim"])->Fill(pt, y); - std::get(histosPtr[DataType::McDplusNonPrompt]["hCPARecSig"])->Fill(candidate.cpa()); - std::get(histosPtr[DataType::McDplusNonPrompt]["hEtaRecSig"])->Fill(candidate.eta()); - if (TESTBIT(flag, aod::SelectionStep::RecoTopol)) { - std::get(histosPtr[DataType::McDplusNonPrompt]["hPtVsYRecSigRecoTopol"])->Fill(pt, y); - } - if (TESTBIT(flag, aod::SelectionStep::RecoPID)) { - std::get(histosPtr[DataType::McDplusNonPrompt]["hPtVsYRecSigRecoPID"])->Fill(pt, y); - } + if (TESTBIT(candidate.isSelDsToKKPi(), aod::SelectionStep::RecoPID)) { + std::get(histosPtr[dataType]["hPtVsYRecoPID"])->Fill(pt, yCand); } + } + if (candidate.isSelDsToPiKK() >= selectionFlagDs) { // PiKK + fillHisto(candidate, dataType); + fillHistoPiKK(candidate, dataType); - return; - } // end D+→ K± K∓ π± - - // D+→ π± K∓ π± - if (whichSpeciesDecay == SpeciesAndDecay::DplusToPiKPi) { - auto y = hfHelper.yDplus(candidate); - - // Fill whether it is prompt or non-prompt - fillHisto(candidate, DataType::McDplusBkg); - - if (candidate.isSelDsToKKPi() >= selectionFlagDs) // KKPi - fillHistoKKPi(candidate, DataType::McDplusBkg); - if (candidate.isSelDsToPiKK() >= selectionFlagDs) // PiKK - fillHistoPiKK(candidate, DataType::McDplusBkg); - - std::get(histosPtr[DataType::McDplusBkg]["hPtRecSig"])->Fill(pt); - std::get(histosPtr[DataType::McDplusBkg]["hPtGenSig"])->Fill(particleMother.pt()); // gen. level pT - std::get(histosPtr[DataType::McDplusBkg]["hPtVsYRecSigRecoSkim"])->Fill(pt, y); - std::get(histosPtr[DataType::McDplusBkg]["hCPARecSig"])->Fill(candidate.cpa()); - std::get(histosPtr[DataType::McDplusBkg]["hEtaRecSig"])->Fill(candidate.eta()); - if (TESTBIT(flag, aod::SelectionStep::RecoTopol)) { - std::get(histosPtr[DataType::McDplusBkg]["hPtVsYRecSigRecoTopol"])->Fill(pt, y); + if (TESTBIT(candidate.isSelDsToPiKK(), aod::SelectionStep::RecoSkims)) { + std::get(histosPtr[dataType]["hPtVsYRecoSkim"])->Fill(pt, yCand); } - if (TESTBIT(flag, aod::SelectionStep::RecoPID)) { - std::get(histosPtr[DataType::McDplusBkg]["hPtVsYRecSigRecoPID"])->Fill(pt, y); + if (TESTBIT(candidate.isSelDsToPiKK(), aod::SelectionStep::RecoTopol)) { + std::get(histosPtr[dataType]["hPtVsYRecoTopol"])->Fill(pt, yCand); } - - return; - } // end D+→ π± K∓ π± + if (TESTBIT(candidate.isSelDsToPiKK(), aod::SelectionStep::RecoPID)) { + std::get(histosPtr[dataType]["hPtVsYRecoPID"])->Fill(pt, yCand); + } + } } + return; } - template - void runDataAnalysis(CandsDs const& candidates) + template + void runDataAnalysisPerCandidate(CandDs const& candidate) { - for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yDs(candidate)) > yCandRecoMax) { - continue; - } + if (yCandRecoMax >= 0. && std::abs(hfHelper.yDs(candidate)) > yCandRecoMax) { + return; + } + + if (candidate.isSelDsToKKPi() >= selectionFlagDs) { // KKPi fillHisto(candidate, DataType::Data); - if constexpr (decayChannel == FinalState::KKPi) { // KKPi - fillHistoKKPi(candidate, DataType::Data); - } else if constexpr (decayChannel == FinalState::PiKK) { // PiKK - fillHistoPiKK(candidate, DataType::Data); - } + fillHistoKKPi(candidate, DataType::Data); + } + if (candidate.isSelDsToPiKK() >= selectionFlagDs) { // PiKK + fillHisto(candidate, DataType::Data); + fillHistoPiKK(candidate, DataType::Data); } } - template - void runMcAnalysis(CandsDs const& /*candidates*/, - CandDsMcGen const& mcParticles) + template + void runMcAnalysisPerCandidate(CandDs const& candidate, + CandDsMcGen const& mcParticles) { // MC rec. - // Ds± → K± K∓ π± - if constexpr (useMl) { - // Ds - for (const auto& candidate : reconstructedCandDsSigWithMl) - if (candidate.isSelDsToKKPi() >= selectionFlagDs || candidate.isSelDsToPiKK() >= selectionFlagDs) - fillHistoMCRec(candidate, mcParticles, SpeciesAndDecay::DsToKKPi); - // D+→ K± K∓ π± - for (const auto& candidate : reconstructedCandDplusSigWithMl) - if (candidate.isSelDsToKKPi() >= selectionFlagDs || candidate.isSelDsToPiKK() >= selectionFlagDs) - fillHistoMCRec(candidate, mcParticles, SpeciesAndDecay::DplusToKKPi); - // D+→ π± K∓ π± - for (const auto& candidate : reconstructedCandDplusBkgWithMl) - if (candidate.isSelDsToKKPi() >= selectionFlagDs || candidate.isSelDsToPiKK() >= selectionFlagDs) - fillHistoMCRec(candidate, mcParticles, SpeciesAndDecay::DplusToPiKPi); - // Bkg - for (const auto& candidate : reconstructedCandBkgWithMl) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yDs(candidate)) > yCandRecoMax) { - continue; - } + std::array, 6> isOfType = {// Contains the functions to check if the candidate is of a certain type + &HfTaskDs::isDsPrompt, + &HfTaskDs::isDsNonPrompt, + &HfTaskDs::isDplusPrompt, + &HfTaskDs::isDplusNonPrompt, + &HfTaskDs::isDplusBkg, + &HfTaskDs::isLcBkg}; + + bool isBkg = true; + for (int i = DataType::McDsPrompt; i <= DataType::McLcBkg; i++) { // Check what type of MC signal candidate it is, and fill the corresponding histograms + if ((this->*isOfType[i - DataType::McDsPrompt])(candidate)) { + isBkg = false; + fillHistoMCRec(candidate, mcParticles, static_cast(i)); + break; + } + } + if (isBkg && fillMcBkgHistos) { + if (yCandRecoMax >= 0. && std::abs(hfHelper.yDs(candidate)) > yCandRecoMax) { + return; + } - if (candidate.isSelDsToKKPi() >= selectionFlagDs || candidate.isSelDsToPiKK() >= selectionFlagDs) + if (candidate.isSelDsToKKPi() >= selectionFlagDs || candidate.isSelDsToPiKK() >= selectionFlagDs) { + if (candidate.isSelDsToKKPi() >= selectionFlagDs) { // KKPi fillHisto(candidate, DataType::McBkg); - } - } else { - // Ds - for (const auto& candidate : reconstructedCandDsSig) - if (candidate.isSelDsToKKPi() >= selectionFlagDs || candidate.isSelDsToPiKK() >= selectionFlagDs) - fillHistoMCRec(candidate, mcParticles, SpeciesAndDecay::DsToKKPi); - - // D+→ K± K∓ π± - for (const auto& candidate : reconstructedCandDplusSig) - if (candidate.isSelDsToKKPi() >= selectionFlagDs || candidate.isSelDsToPiKK() >= selectionFlagDs) - fillHistoMCRec(candidate, mcParticles, SpeciesAndDecay::DplusToKKPi); - - // D+→ π± K∓ π± - for (const auto& candidate : reconstructedCandDplusBkg) - if (candidate.isSelDsToKKPi() >= selectionFlagDs || candidate.isSelDsToPiKK() >= selectionFlagDs) - fillHistoMCRec(candidate, mcParticles, SpeciesAndDecay::DplusToPiKPi); - - // Bkg - for (const auto& candidate : reconstructedCandBkg) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yDs(candidate)) > yCandRecoMax) { - continue; + fillHistoKKPi(candidate, DataType::McBkg); } - - if (candidate.isSelDsToKKPi() >= selectionFlagDs || candidate.isSelDsToPiKK() >= selectionFlagDs) { + if (candidate.isSelDsToPiKK() >= selectionFlagDs) { // PiKK fillHisto(candidate, DataType::McBkg); - if (candidate.isSelDsToKKPi() >= selectionFlagDs) // KKPi - fillHistoKKPi(candidate, DataType::McDsPrompt); - if (candidate.isSelDsToPiKK() >= selectionFlagDs) // PiKK - fillHistoPiKK(candidate, DataType::McDsPrompt); + fillHistoPiKK(candidate, DataType::McBkg); } } } // TODO: add histograms for reflections + } + template + void fillMcGenHistosSparse(CandDsMcGen const& mcParticles, + Coll const& recoCollisions) + { // MC gen. for (const auto& particle : mcParticles) { + if (std::abs(particle.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::DsToKKPi) { + const auto& recoCollsPerMcColl = recoCollisions.sliceBy(colPerMcCollision, particle.mcCollision().globalIndex()); if (particle.flagMcDecayChanGen() == decayChannel || (fillDplusMc && particle.flagMcDecayChanGen() == (decayChannel + offsetDplusDecayChannel))) { auto pt = particle.pt(); - auto y = 0; + double y{0.f}; + + unsigned maxNumContrib = 0; + for (const auto& recCol : recoCollsPerMcColl) { + maxNumContrib = recCol.numContrib() > maxNumContrib ? recCol.numContrib() : maxNumContrib; + } + float cent = o2::hf_centrality::getCentralityGenColl(recoCollsPerMcColl); + float occ{-1.}; + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + occ = o2::hf_occupancy::getOccupancyGenColl(recoCollsPerMcColl, occEstimator); + } if (particle.flagMcDecayChanGen() == decayChannel) { y = RecoDecay::y(particle.pVector(), o2::constants::physics::MassDS); if (yCandGenMax >= 0. && std::abs(y) > yCandGenMax) { continue; } + if (particle.originMcGen() == RecoDecay::OriginType::Prompt) { - std::get(histosPtr[DataType::McDsPrompt]["hPtGen"])->Fill(pt); // gen. level pT - std::get(histosPtr[DataType::McDsPrompt]["hPtVsYGen"])->Fill(pt, y); // gen. level pT - std::get(histosPtr[DataType::McDsPrompt]["hEtaGen"])->Fill(particle.eta()); // gen. level pT + std::get(histosPtr[DataType::McDsPrompt]["hPtGen"])->Fill(pt); // gen. level pT + std::get(histosPtr[DataType::McDsPrompt]["hEtaGen"])->Fill(particle.eta()); + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + std::get(histosPtr[DataType::McDsPrompt]["hSparseGen"])->Fill(pt, y, maxNumContrib, cent, occ); + } else { + std::get(histosPtr[DataType::McDsPrompt]["hSparseGen"])->Fill(pt, y, maxNumContrib, cent); + } } if (particle.originMcGen() == RecoDecay::OriginType::NonPrompt) { - std::get(histosPtr[DataType::McDsNonPrompt]["hPtGen"])->Fill(pt); // gen. level pT - std::get(histosPtr[DataType::McDsNonPrompt]["hPtVsYGen"])->Fill(pt, y); // gen. level pT - std::get(histosPtr[DataType::McDsNonPrompt]["hEtaGen"])->Fill(particle.eta()); // gen. level pT + std::get(histosPtr[DataType::McDsNonPrompt]["hPtGen"])->Fill(pt); // gen. level pT + std::get(histosPtr[DataType::McDsNonPrompt]["hEtaGen"])->Fill(particle.eta()); + auto bHadMother = mcParticles.rawIteratorAt(particle.idxBhadMotherPart() - mcParticles.offset()); + int flagGenB = getBHadMotherFlag(bHadMother.pdgCode()); + float ptGenB = bHadMother.pt(); + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + std::get(histosPtr[DataType::McDsNonPrompt]["hSparseGen"])->Fill(pt, y, maxNumContrib, cent, occ, ptGenB, flagGenB); + } else { + std::get(histosPtr[DataType::McDsNonPrompt]["hSparseGen"])->Fill(pt, y, maxNumContrib, cent, ptGenB, flagGenB); + } } } else if (fillDplusMc) { y = RecoDecay::y(particle.pVector(), o2::constants::physics::MassDPlus); @@ -565,175 +722,379 @@ struct HfTaskDs { continue; } if (particle.originMcGen() == RecoDecay::OriginType::Prompt) { - std::get(histosPtr[DataType::McDplusPrompt]["hPtGen"])->Fill(pt); // gen. level pT - std::get(histosPtr[DataType::McDplusPrompt]["hPtVsYGen"])->Fill(pt, y); // gen. level pT - std::get(histosPtr[DataType::McDplusPrompt]["hEtaGen"])->Fill(particle.eta()); + std::get(histosPtr[DataType::McDplusPrompt]["hPtGen"])->Fill(pt); // gen. level pT + std::get(histosPtr[DataType::McDplusPrompt]["hEtaGen"])->Fill(particle.eta()); + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + std::get(histosPtr[DataType::McDplusPrompt]["hSparseGen"])->Fill(pt, y, maxNumContrib, cent, occ); + } else { + std::get(histosPtr[DataType::McDplusPrompt]["hSparseGen"])->Fill(pt, y, maxNumContrib, cent); + } } if (particle.originMcGen() == RecoDecay::OriginType::NonPrompt) { - std::get(histosPtr[DataType::McDplusNonPrompt]["hPtGen"])->Fill(pt); // gen. level pT - std::get(histosPtr[DataType::McDplusNonPrompt]["hPtVsYGen"])->Fill(pt, y); - std::get(histosPtr[DataType::McDplusNonPrompt]["hEtaGen"])->Fill(particle.eta()); + std::get(histosPtr[DataType::McDplusNonPrompt]["hPtGen"])->Fill(pt); // gen. level pT + std::get(histosPtr[DataType::McDplusNonPrompt]["hEtaGen"])->Fill(particle.eta()); + auto bHadMother = mcParticles.rawIteratorAt(particle.idxBhadMotherPart() - mcParticles.offset()); + int flagGenB = getBHadMotherFlag(bHadMother.pdgCode()); + float ptGenB = bHadMother.pt(); + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + std::get(histosPtr[DataType::McDplusNonPrompt]["hSparseGen"])->Fill(pt, y, maxNumContrib, cent, occ, ptGenB, flagGenB); + } else { + std::get(histosPtr[DataType::McDplusNonPrompt]["hSparseGen"])->Fill(pt, y, maxNumContrib, cent, ptGenB, flagGenB); + } + } + } + } + } + } + } + + template + void fillNPvContribHisto(const Coll& collision, + std::array& nCandsPerType, + std::array& nCandsInSignalRegionDsPerType, + std::array& nCandsInSignalRegionDplusPerType) + { + int numPvContributors = collision.numContrib(); + float centrality = evaluateCentralityColl(collision); + std::get(histosPtr[DataType::Data]["hNPvContribAll"])->Fill(numPvContributors, centrality); + for (int i = 0; i < DataType::kDataTypes; i++) { + if (i == DataType::McBkg && !fillMcBkgHistos) { + continue; + } + if (nCandsPerType[i]) { + std::get(histosPtr[i]["hNPvContribCands"])->Fill(numPvContributors, centrality); + } + if (nCandsInSignalRegionDsPerType[i]) { + std::get(histosPtr[i]["hNPvContribCandsInSignalRegionDs"])->Fill(numPvContributors, centrality); + } + if (nCandsInSignalRegionDplusPerType[i]) { + std::get(histosPtr[i]["hNPvContribCandsInSignalRegionDplus"])->Fill(numPvContributors, centrality); + } + } + } + + template + void runDataAnalysisPerCollision(const Coll& collisions, const CandsDs& candsDs) + { + for (const auto& collision : collisions) { + /* check the previous run number */ + const auto& bc = collision.bc(); + if (bc.runNumber() != mRunNumber) { + mRunNumber = bc.runNumber(); // mark this run as at least tried + if (ccdbConfig.reconstructionPass.value == "") { + lCalibObjects = ccdb->getForRun(ccdbConfig.ccdbPath, mRunNumber); + } else if (ccdbConfig.reconstructionPass.value == "metadata") { + std::map metadata; + metadata["RecoPassName"] = metadataInfo.get("RecoPassName"); + LOGF(info, "Loading CCDB for reconstruction pass (from metadata): %s", metadataInfo.get("RecoPassName")); + lCalibObjects = ccdb->getSpecificForRun(ccdbConfig.ccdbPath, mRunNumber, metadata); + } else { + std::map metadata; + metadata["RecoPassName"] = ccdbConfig.reconstructionPass.value; + LOGF(info, "Loading CCDB for reconstruction pass (from provided argument): %s", ccdbConfig.reconstructionPass.value); + lCalibObjects = ccdb->getSpecificForRun(ccdbConfig.ccdbPath, mRunNumber, metadata); + } + + if (lCalibObjects) { + LOG(info) << "CCDB objects loaded successfully"; + hVtxZFT0A = static_cast(lCalibObjects->FindObject("hVtxZFT0A")); + hVtxZFT0C = static_cast(lCalibObjects->FindObject("hVtxZFT0C")); + hVtxZNTracks = static_cast(lCalibObjects->FindObject("hVtxZNTracksPV")); + lCalibLoaded = true; + // Capture error + if (!hVtxZFT0A || !hVtxZFT0C || !hVtxZNTracks) { + LOGF(error, "Problem loading CCDB objects! Please check"); + lCalibLoaded = false; + } + } else { + LOGF(error, "Problem loading CCDB object! Please check"); + lCalibLoaded = false; + } + } + + auto thisCollId = collision.globalIndex(); + std::array nCandsPerType{0}; + std::array nCandsInSignalRegionDsPerType{0}; + std::array nCandsInSignalRegionDplusPerType{0}; + + auto groupedDsCandidates = candsDs.sliceBy(candDsPerCollision, thisCollId); + for (const auto& candidate : groupedDsCandidates) { + if (candidate.isSelDsToKKPi() < selectionFlagDs && candidate.isSelDsToPiKK() < selectionFlagDs) { + continue; + } + runDataAnalysisPerCandidate(candidate); + + ++nCandsPerType[DataType::Data]; + if (isCandInSignalRegion(candidate, true)) { + ++nCandsInSignalRegionDsPerType[DataType::Data]; + } + if (isCandInSignalRegion(candidate, false)) { + ++nCandsInSignalRegionDplusPerType[DataType::Data]; + } + } + fillNPvContribHisto(collision, nCandsPerType, nCandsInSignalRegionDsPerType, nCandsInSignalRegionDplusPerType); + } + } + + template + void runMcAnalysisPerCollision(const Coll& collisions, + const CandsDs& candsDs, + const CandDsMcGen& mcParticles) + { + for (const auto& collision : collisions) { + /* check the previous run number */ + const auto& bc = collision.bc(); + if (bc.runNumber() != mRunNumber) { + mRunNumber = bc.runNumber(); // mark this run as at least tried + if (ccdbConfig.reconstructionPass.value == "") { + lCalibObjects = ccdb->getForRun(ccdbConfig.ccdbPath, mRunNumber); + } else if (ccdbConfig.reconstructionPass.value == "metadata") { + std::map metadata; + metadata["RecoPassName"] = metadataInfo.get("RecoPassName"); + LOGF(info, "Loading CCDB for reconstruction pass (from metadata): %s", metadataInfo.get("RecoPassName")); + lCalibObjects = ccdb->getSpecificForRun(ccdbConfig.ccdbPath, mRunNumber, metadata); + } else { + std::map metadata; + metadata["RecoPassName"] = ccdbConfig.reconstructionPass.value; + LOGF(info, "Loading CCDB for reconstruction pass (from provided argument): %s", ccdbConfig.reconstructionPass.value); + lCalibObjects = ccdb->getSpecificForRun(ccdbConfig.ccdbPath, mRunNumber, metadata); + } + + if (lCalibObjects) { + LOG(info) << "CCDB objects loaded successfully"; + hVtxZFT0A = static_cast(lCalibObjects->FindObject("hVtxZFT0A")); + hVtxZFT0C = static_cast(lCalibObjects->FindObject("hVtxZFT0C")); + hVtxZNTracks = static_cast(lCalibObjects->FindObject("hVtxZNTracksPV")); + lCalibLoaded = true; + // Capture error + if (!hVtxZFT0A || !hVtxZFT0C || !hVtxZNTracks) { + LOGF(error, "Problem loading CCDB objects! Please check"); + lCalibLoaded = false; + } + } else { + LOGF(error, "Problem loading CCDB object! Please check"); + lCalibLoaded = false; + } + } + + auto thisCollId = collision.globalIndex(); + std::array nCandsPerType{0}; + std::array nCandsInSignalRegionDsPerType{0}; + std::array nCandsInSignalRegionDplusPerType{0}; + + auto groupedDsCandidates = candsDs.sliceBy(candDsPerCollision, thisCollId); + for (const auto& candidate : groupedDsCandidates) { + if (candidate.isSelDsToKKPi() < selectionFlagDs && candidate.isSelDsToPiKK() < selectionFlagDs) { + continue; + } + runDataAnalysisPerCandidate(candidate); + runMcAnalysisPerCandidate(candidate, mcParticles); + + // Increase the number of candidates of the corresponding type to fill the NPvContrib histos + std::array, 4> isOfType = {// Contains the functions to check if the candidate is of a certain type + &HfTaskDs::isDsPrompt, + &HfTaskDs::isDsNonPrompt, + &HfTaskDs::isDplusPrompt, + &HfTaskDs::isDplusNonPrompt}; + bool isBkg = true; + for (int i = DataType::McDsPrompt; i <= DataType::McDplusNonPrompt; i++) { // Check what type of MC signal candidate it is, and fill the corresponding arrays + if ((this->*isOfType[i - DataType::McDsPrompt])(candidate)) { + isBkg = false; + ++nCandsPerType[i]; + if (isCandInSignalRegion(candidate, true)) { + ++nCandsInSignalRegionDsPerType[i]; + } + if (isCandInSignalRegion(candidate, false)) { + ++nCandsInSignalRegionDplusPerType[i]; } + break; } } + if (isBkg) { + ++nCandsPerType[DataType::McBkg]; + if (isCandInSignalRegion(candidate, true)) { + ++nCandsInSignalRegionDsPerType[DataType::McBkg]; + } + if (isCandInSignalRegion(candidate, false)) { + ++nCandsInSignalRegionDplusPerType[DataType::McBkg]; + } + } + + nCandsPerType[DataType::Data] = nCandsPerType[DataType::McDsPrompt] + nCandsPerType[DataType::McDsNonPrompt] + nCandsPerType[DataType::McDplusPrompt] + nCandsPerType[DataType::McDplusNonPrompt] + nCandsPerType[DataType::McBkg]; + + nCandsInSignalRegionDsPerType[DataType::Data] = nCandsInSignalRegionDsPerType[DataType::McDsPrompt] + nCandsInSignalRegionDsPerType[DataType::McDsNonPrompt] + nCandsInSignalRegionDsPerType[DataType::McDplusPrompt] + nCandsInSignalRegionDsPerType[DataType::McDplusNonPrompt] + nCandsInSignalRegionDsPerType[DataType::McBkg]; + + nCandsInSignalRegionDplusPerType[DataType::Data] = nCandsInSignalRegionDplusPerType[DataType::McDsPrompt] + nCandsInSignalRegionDplusPerType[DataType::McDsNonPrompt] + nCandsInSignalRegionDplusPerType[DataType::McDplusPrompt] + nCandsInSignalRegionDplusPerType[DataType::McDplusNonPrompt] + nCandsInSignalRegionDplusPerType[DataType::McBkg]; } + fillNPvContribHisto(collision, nCandsPerType, nCandsInSignalRegionDsPerType, nCandsInSignalRegionDplusPerType); } + fillMcGenHistosSparse(mcParticles, collisions); } - void processDataWithCentFT0C(CollisionsWithFT0C const&, - CandDsData const&) + void processDataWithCentFT0C(CollisionsWithFT0C const& collisions, + CandDsData const& candsDs, + aod::BCs const&, + aod::Tracks const&) { - runDataAnalysis(selectedDsToKKPiCandData); - runDataAnalysis(selectedDsToPiKKCandData); + runDataAnalysisPerCollision(collisions, candsDs); } PROCESS_SWITCH(HfTaskDs, processDataWithCentFT0C, "Process data w/o ML information on Ds, with information on centrality from FT0C", false); - void processDataWithCentFT0M(CollisionsWithFT0M const&, - CandDsData const&) + void processDataWithCentFT0M(CollisionsWithFT0M const& collisions, + CandDsData const& candsDs, + aod::BCs const&, + aod::Tracks const&) { - runDataAnalysis(selectedDsToKKPiCandData); - runDataAnalysis(selectedDsToPiKKCandData); + runDataAnalysisPerCollision(collisions, candsDs); } PROCESS_SWITCH(HfTaskDs, processDataWithCentFT0M, "Process data w/o ML information on Ds, with information on centrality from FT0M", false); - void processDataWithCentNTracksPV(CollisionsWithNTracksPV const&, - CandDsData const&) + void processDataWithCentNTracksPV(CollisionsWithNTracksPV const& collisions, + CandDsData const& candsDs, + aod::BCs const&, + aod::Tracks const&) { - runDataAnalysis(selectedDsToKKPiCandData); - runDataAnalysis(selectedDsToPiKKCandData); + runDataAnalysisPerCollision(collisions, candsDs); } PROCESS_SWITCH(HfTaskDs, processDataWithCentNTracksPV, "Process data w/o ML information on Ds, with information on centrality from NTracksPV", false); - void processData(aod::Collisions const&, - CandDsData const&) + void processData(soa::Join const& collisions, + CandDsData const& candsDs, + aod::BCs const&, + aod::Tracks const&) { - runDataAnalysis(selectedDsToKKPiCandData); - runDataAnalysis(selectedDsToPiKKCandData); + runDataAnalysisPerCollision(collisions, candsDs); } PROCESS_SWITCH(HfTaskDs, processData, "Process data w/o ML information on Ds, w/o information on centrality", true); - void processDataWithMlAndCentFT0C(CollisionsWithFT0C const&, - CandDsDataWithMl const&) + void processDataWithMlAndCentFT0C(CollisionsWithFT0C const& collisions, + CandDsDataWithMl const& candsDs, + aod::BCs const&, + aod::Tracks const&) { - runDataAnalysis(selectedDsToKKPiCandWithMlData); - runDataAnalysis(selectedDsToPiKKCandWithMlData); + runDataAnalysisPerCollision(collisions, candsDs); } PROCESS_SWITCH(HfTaskDs, processDataWithMlAndCentFT0C, "Process data with ML information on Ds, with information on centrality from FT0C", false); - void processDataWithMlAndCentFT0M(CollisionsWithFT0M const&, - CandDsDataWithMl const&) + void processDataWithMlAndCentFT0M(CollisionsWithFT0M const& collisions, + CandDsDataWithMl const& candsDs, + aod::BCs const&, + aod::Tracks const&) { - runDataAnalysis(selectedDsToKKPiCandWithMlData); - runDataAnalysis(selectedDsToPiKKCandWithMlData); + runDataAnalysisPerCollision(collisions, candsDs); } PROCESS_SWITCH(HfTaskDs, processDataWithMlAndCentFT0M, "Process data with ML information on Ds, with information on centrality from FT0M", false); - void processDataWithMlAndCentNTracksPV(CollisionsWithNTracksPV const&, - CandDsDataWithMl const&) + void processDataWithMlAndCentNTracksPV(CollisionsWithNTracksPV const& collisions, + CandDsDataWithMl const& candsDs, + aod::BCs const&, + aod::Tracks const&) { - runDataAnalysis(selectedDsToKKPiCandWithMlData); - runDataAnalysis(selectedDsToPiKKCandWithMlData); + runDataAnalysisPerCollision(collisions, candsDs); } PROCESS_SWITCH(HfTaskDs, processDataWithMlAndCentNTracksPV, "Process data with ML information on Ds, with information on centrality", false); - void processDataWithMl(aod::Collisions const&, - CandDsDataWithMl const&) + void processDataWithMl(soa::Join const& collisions, + CandDsDataWithMl const& candsDs, + aod::BCs const&, + aod::Tracks const&) { - runDataAnalysis(selectedDsToKKPiCandWithMlData); - runDataAnalysis(selectedDsToPiKKCandWithMlData); + runDataAnalysisPerCollision(collisions, candsDs); } PROCESS_SWITCH(HfTaskDs, processDataWithMl, "Process data with ML information on Ds, w/o information on centrality", false); - void processMcWithCentFT0C(CollisionsWithFT0C const&, - CandDsMcReco const& candidates, + void processMcWithCentFT0C(CollisionsMcWithFT0C const& collisions, + CandDsMcReco const& candsDs, CandDsMcGen const& mcParticles, + aod::BCs const&, + aod::McCollisions const&, aod::TracksWMc const&) { - runMcAnalysis(candidates, mcParticles); - runDataAnalysis(selectedDsToKKPiCandMc); - runDataAnalysis(selectedDsToPiKKCandMc); + runMcAnalysisPerCollision(collisions, candsDs, mcParticles); } PROCESS_SWITCH(HfTaskDs, processMcWithCentFT0C, "Process MC w/o ML information on Ds, with information on centrality from FT0C", false); - void processMcWithCentFT0M(CollisionsWithFT0M const&, - CandDsMcReco const& candidates, + void processMcWithCentFT0M(CollisionsMcWithFT0M const& collisions, + CandDsMcReco const& candsDs, CandDsMcGen const& mcParticles, + aod::BCs const&, + aod::McCollisions const&, aod::TracksWMc const&) { - runMcAnalysis(candidates, mcParticles); - runDataAnalysis(selectedDsToKKPiCandMc); - runDataAnalysis(selectedDsToPiKKCandMc); + runMcAnalysisPerCollision(collisions, candsDs, mcParticles); } PROCESS_SWITCH(HfTaskDs, processMcWithCentFT0M, "Process MC w/o ML information on Ds, with information on centrality from FT0M", false); - void processMcWithCentNTracksPV(CollisionsWithNTracksPV const&, - CandDsMcReco const& candidates, + void processMcWithCentNTracksPV(CollisionsMcWithNTracksPV const& collisions, + CandDsMcReco const& candsDs, CandDsMcGen const& mcParticles, + aod::BCs const&, + aod::McCollisions const&, aod::TracksWMc const&) { - runMcAnalysis(candidates, mcParticles); - runDataAnalysis(selectedDsToKKPiCandMc); - runDataAnalysis(selectedDsToPiKKCandMc); + runMcAnalysisPerCollision(collisions, candsDs, mcParticles); } PROCESS_SWITCH(HfTaskDs, processMcWithCentNTracksPV, "Process MC w/o ML information on Ds, with information on centrality from NTracksPV", false); - void processMc(aod::Collisions const&, - CandDsMcReco const& candidates, + void processMc(CollisionsMc const& collisions, + CandDsMcReco const& candsDs, CandDsMcGen const& mcParticles, + aod::BCs const&, + aod::McCollisions const&, aod::TracksWMc const&) { - runMcAnalysis(candidates, mcParticles); - runDataAnalysis(selectedDsToKKPiCandMc); - runDataAnalysis(selectedDsToPiKKCandMc); + runMcAnalysisPerCollision(collisions, candsDs, mcParticles); } PROCESS_SWITCH(HfTaskDs, processMc, "Process MC w/o ML information on Ds, w/o information on centrality", false); - void processMcWithMlAndCentFT0C(CollisionsWithFT0C const&, - CandDsMcRecoWithMl const& candidates, + void processMcWithMlAndCentFT0C(CollisionsMcWithFT0C const& collisions, + CandDsMcRecoWithMl const& candsDs, CandDsMcGen const& mcParticles, + aod::BCs const&, + aod::McCollisions const&, aod::TracksWMc const&) { - runMcAnalysis(candidates, mcParticles); - runDataAnalysis(selectedDsToKKPiCandWithMlMc); - runDataAnalysis(selectedDsToPiKKCandWithMlMc); + runMcAnalysisPerCollision(collisions, candsDs, mcParticles); } PROCESS_SWITCH(HfTaskDs, processMcWithMlAndCentFT0C, "Process MC with ML information on Ds, with information on centrality from FT0C", false); - void processMcWithMlAndCentFT0M(CollisionsWithFT0M const&, - CandDsMcRecoWithMl const& candidates, + void processMcWithMlAndCentFT0M(CollisionsMcWithFT0M const& collisions, + CandDsMcRecoWithMl const& candsDs, CandDsMcGen const& mcParticles, + aod::BCs const&, + aod::McCollisions const&, aod::TracksWMc const&) { - runMcAnalysis(candidates, mcParticles); - runDataAnalysis(selectedDsToKKPiCandWithMlMc); - runDataAnalysis(selectedDsToPiKKCandWithMlMc); + runMcAnalysisPerCollision(collisions, candsDs, mcParticles); } PROCESS_SWITCH(HfTaskDs, processMcWithMlAndCentFT0M, "Process MC with ML information on Ds, with information on centrality from FT0M", false); - void processMcWithMlAndCentNTracksPV(CollisionsWithNTracksPV const&, - CandDsMcRecoWithMl const& candidates, + void processMcWithMlAndCentNTracksPV(CollisionsMcWithNTracksPV const& collisions, + CandDsMcRecoWithMl const& candsDs, CandDsMcGen const& mcParticles, + aod::BCs const&, + aod::McCollisions const&, aod::TracksWMc const&) { - runMcAnalysis(candidates, mcParticles); - runDataAnalysis(selectedDsToKKPiCandWithMlMc); - runDataAnalysis(selectedDsToPiKKCandWithMlMc); + runMcAnalysisPerCollision(collisions, candsDs, mcParticles); } PROCESS_SWITCH(HfTaskDs, processMcWithMlAndCentNTracksPV, "Process MC with ML information on Ds, with information on centrality from NTracksPV", false); - void processMcWithMl(aod::Collisions const&, - CandDsMcRecoWithMl const& candidates, + void processMcWithMl(CollisionsMc const& collisions, + CandDsMcRecoWithMl const& candsDs, CandDsMcGen const& mcParticles, + aod::BCs const&, + aod::McCollisions const&, aod::TracksWMc const&) { - runMcAnalysis(candidates, mcParticles); - runDataAnalysis(selectedDsToKKPiCandWithMlMc); - runDataAnalysis(selectedDsToPiKKCandWithMlMc); + runMcAnalysisPerCollision(collisions, candsDs, mcParticles); } PROCESS_SWITCH(HfTaskDs, processMcWithMl, "Process MC with ML information on Ds, w/o information on centrality", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { + // Parse the metadata + metadataInfo.initMetadata(cfgc); return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGHF/D2H/Tasks/taskDstarToD0Pi.cxx b/PWGHF/D2H/Tasks/taskDstarToD0Pi.cxx index c3428717c61..eaadbab783c 100644 --- a/PWGHF/D2H/Tasks/taskDstarToD0Pi.cxx +++ b/PWGHF/D2H/Tasks/taskDstarToD0Pi.cxx @@ -15,8 +15,15 @@ /// \author Deependra Sharma , IITB /// \author Fabrizio Grosa , CERN +/// \brief Dstar production analysis task (With and Without ML) + +#include +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" #include "Framework/runDataProcessing.h" #include "PWGHF/Core/SelectorCuts.h" @@ -27,6 +34,7 @@ using namespace o2; using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::soa; /// Dstar analysis task struct HfTaskDstarToD0Pi { @@ -36,18 +44,35 @@ struct HfTaskDstarToD0Pi { Configurable selectionFlagHfD0ToPiK{"selectionFlagHfD0ToPiK", true, "Selection Flag for HF flagged candidates"}; Configurable> ptBins{"ptBins", std::vector{hf_cuts_dstar_to_d0_pi::vecBinsPt}, "pT bin limits for Dstar"}; + SliceCache cache; + using CandDstarWSelFlag = soa::Join; + using CandDstarWSelFlagWMl = soa::Join; /// @brief specially for MC data // full reconstructed Dstar candidate using CandDstarWSelFlagMcRec = soa::Join; + using CandDstarWSelFlagWMlMcRec = soa::Join; using CandDstarMcGen = soa::Join; - Partition rowsSelectedCandDstar = aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == selectionFlagDstarToD0Pi; + using CollisionsWCent = soa::Join; + using CollisionsWCentMcLabel = soa::Join; + + Filter candFilter = aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == selectionFlagDstarToD0Pi; + Preslice> preslicSelectedCandDstarPerCol = aod::hf_cand::collisionId; + Preslice> preslicSelectedCandDstarPerColWMl = aod::hf_cand::collisionId; + + PresliceUnsorted colsPerMcCollision = aod::mccollisionlabel::mcCollisionId; + Partition rowsSelectedCandDstarMcRec = aod::hf_sel_candidate_dstar::isRecoD0Flag == selectionFlagHfD0ToPiK; + Partition rowsSelectedCandDstarMcRecWMl = aod::hf_sel_candidate_dstar::isRecoD0Flag == selectionFlagHfD0ToPiK; ConfigurableAxis binningImpactParam{"binningImpactParam", {1000, 0.1, -0.1}, " Bins of Impact Parameter"}; ConfigurableAxis binningDecayLength{"binningDecayLength", {1000, 0.0, 0.7}, "Bins of Decay Length"}; ConfigurableAxis binningNormDecayLength{"binningNormDecayLength", {1000, 0.0, 40.0}, "Bins of Normalised Decay Length"}; + ConfigurableAxis binningCentrality{"binningCentrality", {VARIABLE_WIDTH, 0.0, 1.0, 10.0, 30.0, 50.0, 70.0, 100.0}, "centrality binning"}; + ConfigurableAxis binningDeltaInvMass{"binningDeltaInvMass", {100, 0.13, 0.16}, "Bins of Delta InvMass of Dstar"}; + ConfigurableAxis binningBkgBDTScore{"binningBkgBDTScore", {100, 0.0f, 1.0f}, "Bins for background BDT Score"}; + ConfigurableAxis binningSigBDTScore{"binningSigBDTScore", {100, 0.0f, 1.0f}, "Bins for Signal (Prompts + Non Prompt) BDT Score"}; HistogramRegistry registry{ "registry", @@ -57,18 +82,28 @@ struct HfTaskDstarToD0Pi { {"QA/hPtProng1D0", "Prong1 of D0 Candidates; Prong1 #it{p}_{T} (GeV/#it{c}); entries", {HistType::kTH1F, {{360, 0., 36.}}}}, {"QA/hPtProng0D0Bar", "Prong0 of D0Bar Candidates; Prong0 #it{p}_{T} (GeV/#it{c}); entries", {HistType::kTH1F, {{360, 0., 36.}}}}, {"QA/hPtProng1D0Bar", "Prong1 of D0Bar Candidates; Prong1 #it{p}_{T} (GeV/#it{c}); entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"QA/hPtSoftPi", "Soft Pi ; Soft Pi #it{p}_{T} (GeV/#it{c}); entries", {HistType::kTH1F, {{100, 0., 1.}}}}}}; + {"QA/hPtSoftPi", "Soft Pi ; Soft Pi #it{p}_{T} (GeV/#it{c}); entries", {HistType::kTH1F, {{100, 0., 1.}}}}, + {"QA/hDeltaCentGen", "#{Delta}Cent % distribution of Collisions having same MC Collision;FT0M #{Delta}Cent %; Counts", {HistType::kTH1F, {{100, 0.0, 100.0}}}}}}; void init(InitContext&) { + if ((doprocessDataWoML && doprocessDataWML) || (doprocessMcWoMl && doprocessMcWML) || (doprocessDataWoML && doprocessMcWML) || (doprocessDataWML && doprocessMcWoMl)) { + LOGP(fatal, "Only Without-ML or With-ML functions should be enabled at a time! Please check your configuration!"); + } auto vecPtBins = (std::vector)ptBins; AxisSpec axisImpactParam = {binningImpactParam, "impact parameter (cm)"}; AxisSpec axisDecayLength = {binningDecayLength, " decay length (cm)"}; AxisSpec axisNormDecayLength = {binningNormDecayLength, "normalised decay length (cm)"}; + AxisSpec axisCentrality = {binningCentrality, "centrality (%)"}; + AxisSpec axisDeltaInvMass = {binningDeltaInvMass, "#Delta #it{M}_{inv} D*"}; + AxisSpec axisBDTScorePrompt = {binningSigBDTScore, "BDT Score for Prompt Cand"}; + AxisSpec axisBDTScoreNonPrompt = {binningSigBDTScore, "BDT Score for Non-Prompt Cand"}; + AxisSpec axisBDTScoreBackground = {binningBkgBDTScore, "BDT Score for Background Cand"}; - registry.add("Yield/hDeltaInvMassDstar2D", "#Delta #it{M}_{inv} D* Candidate; inv. mass ((#pi #pi k) - (#pi k)) (GeV/#it{c}^{2});#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, 0.13, 0.16}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}, true); - registry.add("Yield/hDeltaInvMassDstar1D", "#Delta #it{M}_{inv} D* Candidate; inv. mass ((#pi #pi k) - (#pi k)) (GeV/#it{c}^{2}); entries", {HistType::kTH1F, {{100, 0.13, 0.16}}}, true); + registry.add("Yield/hDeltaInvMassDstar3D", "#Delta #it{M}_{inv} D* Candidate; inv. mass ((#pi #pi k) - (#pi k)) (GeV/#it{c}^{2});#it{p}_{T} (GeV/#it{c}); FT0M centrality", {HistType::kTH3F, {{axisDeltaInvMass}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {axisCentrality}}}, true); + registry.add("Yield/hDeltaInvMassDstar2D", "#Delta #it{M}_{inv} D* Candidate; inv. mass ((#pi #pi k) - (#pi k)) (GeV/#it{c}^{2});#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{axisDeltaInvMass}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}, true); + registry.add("Yield/hDeltaInvMassDstar1D", "#Delta #it{M}_{inv} D* Candidate; inv. mass ((#pi #pi k) - (#pi k)) (GeV/#it{c}^{2}); entries", {HistType::kTH1F, {{axisDeltaInvMass}}}, true); registry.add("Yield/hInvMassDstar", "#Delta #it{M}_{inv} D* Candidate; inv. mass (#pi #pi k) (GeV/#it{c}^{2}); entries", {HistType::kTH1F, {{500, 0., 5.0}}}, true); registry.add("Yield/hInvMassD0", "#it{M}_{inv}D^{0} candidate;#it{M}_{inv} D^{0} (GeV/#it{c});#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{500, 0., 5.0}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}, true); // only QA @@ -94,11 +129,13 @@ struct HfTaskDstarToD0Pi { registry.add("QA/hEtaSkimD0RecSig", "MC Matched Skimed D* Candidates at Reconstruction Level; #it{#eta} of D0 Prong", {HistType::kTH1F, {{100, -2., 2.}}}); registry.add("QA/hEtaSkimDstarRecSig", "MC Matched Skimed D* Candidates at Reconstruction Level; #it{#eta} of D* Candidate", {HistType::kTH1F, {{100, -2., 2.}}}); // pt vs y - registry.add("QA/hPtSkimDstarGenSig", "MC Matched Skimed D* Reconstructed Candidates at Generator Level; #it{p}_{T} of D* at Generator Level (GeV/#it{c})", {HistType::kTH1F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hPtSkimDstarGenSig", "MC Matched Skimed D* Reconstructed Candidates at Generator Level; #it{p}_{T} of D* at Generator Level (GeV/#it{c})", {HistType::kTH1F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}, true); + registry.add("Efficiency/hPtVsCentSkimDstarGenSig", "MC Matched Skimed D* Reconstructed Candidates at Generator Level; #it{p}_{T} of D* at Generator Level (GeV/#it{c}); Centrality (%)", {HistType::kTH2F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {axisCentrality}}}, true); registry.add("QA/hPtVsYSkimDstarRecSig", "MC Matched Skimed D* Candidates at Reconstruction Level; #it{p}_{T} of D* at Reconstruction Level (GeV/#it{c}); #it{y}", {HistType::kTH2F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {100, -5., 5.}}}); registry.add("QA/hPtVsYRecoTopolDstarRecSig", "MC Matched RecoTopol D* Candidates at Reconstruction Level; #it{p}_{T} of D* at Reconstruction Level (GeV/#it{c}); #it{y}", {HistType::kTH2F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {100, -5., 5.}}}); registry.add("QA/hPtVsYRecoPidDstarRecSig", "MC Matched RecoPid D* Candidates at Reconstruction Level; #it{p}_{T} of D* at Reconstruction Level (GeV/#it{c}); #it{y}", {HistType::kTH2F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {100, -5., 5.}}}); registry.add("QA/hPtFullRecoDstarRecSig", "MC Matched FullReco D* Candidates at Reconstruction Level; #it{p}_{T} of D* at Reconstruction Level (GeV/#it{c})", {HistType::kTH1F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Efficiency/hPtVsCentFullRecoDstarRecSig", "MC Matched FullReco D* Candidates at Reconstruction Level; #it{p}_{T} of D* at Reconstruction Level (GeV/#it{c}); Centrality (%)", {HistType::kTH2F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {axisCentrality}}}, true); // Only Prompt RecSig registry.add("QA/hPtVsYSkimPromptDstarRecSig", "MC Matched Skimed Prompt D* Candidates at Reconstruction Level; #it{p}_{T} of D* at Reconstruction Level (GeV/#it{c}; #it{y})", {HistType::kTH2F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {100, -5., 5.}}}); registry.add("QA/hPtVsYRecoTopolPromptDstarRecSig", "MC Matched RecoTopol Prompt D* Candidates at Reconstruction Level; #it{p}_{T} of D* at Reconstruction Level (GeV/#it{c}); #it{y}", {HistType::kTH2F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {100, -5., 5.}}}); @@ -108,7 +145,7 @@ struct HfTaskDstarToD0Pi { registry.add("QA/hPtVsYSkimNonPromptDstarRecSig", "MC Matched Skimed Non-Prompt D* Candidates at Reconstruction Level; #it{p}_{T} of D* at Reconstruction Level (GeV/#it{c}); #it{y}", {HistType::kTH2F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {100, -5., 5.}}}); registry.add("QA/hPtVsYRecoTopolNonPromptDstarRecSig", "MC Matched RecoTopol Non-Prompt D* Candidates at Reconstruction Level; #it{p}_{T} of D* at Reconstruction Level (GeV/#it{c}); #it{y}", {HistType::kTH2F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {100, -5., 5.}}}); registry.add("QA/hPtVsYRecoPidNonPromptDstarRecSig", "MC Matched RecoPid Non-Prompt D* Candidates at Reconstruction Level; #it{p}_{T} of D* at Reconstruction Level (GeV/#it{c}); #it{y}", {HistType::kTH2F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {100, -5., 5.}}}); - registry.add("QA/hPtVsYFullRecoNonPromptDstarRecSig", "MC Matched FullReco Non-Prompt D* Candidates at Reconstruction Level; #it{p}_{T} of D* at Reconstruction Level (GeV/#it{c})", {HistType::kTH1F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hPtFullRecoNonPromptDstarRecSig", "MC Matched FullReco Non-Prompt D* Candidates at Reconstruction Level; #it{p}_{T} of D* at Reconstruction Level (GeV/#it{c})", {HistType::kTH1F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); // MC Matching UnSuccessful registry.add("QA/hCPASkimD0RecBg", "MC UnMatched Skimmed D0 Candidates at Reconstruction Level; cosine of pointing angle", {HistType::kTH1F, {{110, -1., 1.}}}); registry.add("QA/hEtaSkimD0RecBg", "MC UnMatched Skimmed D0 Candidates at Reconstruction Level; #it{#eta} of D0 Prong", {HistType::kTH1F, {{100, -2., 2.}}}); @@ -118,6 +155,7 @@ struct HfTaskDstarToD0Pi { // MC Matching at Generator level Successful registry.add("QA/hEtaDstarGen", "MC Matched D* Candidates at Generator Level; #it{#eta}", {HistType::kTH1F, {{100, -2., 2.}}}); registry.add("QA/hPtDstarGen", "MC Matched D* Candidates at Generator Level; #it{p}_{T} of D*", {HistType::kTH1F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Efficiency/hPtVsCentDstarGen", "MC Matched D* Candidates at Generator Level; #it{p}_{T} of D*;Centrality (%) ", {HistType::kTH2F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {axisCentrality}}}, true); registry.add("QA/hPtVsYDstarGen", "MC Matched D* Candidates at Generator Level; #it{p}_{T} of D*; #it{y}", {HistType::kTH2F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {100, -5., 5.}}}); // Prompt Gen registry.add("QA/hPtPromptDstarGen", "MC Matched Prompt D* Candidates at Generator Level; #it{p}_{T} of D*", {HistType::kTH1F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); @@ -125,82 +163,165 @@ struct HfTaskDstarToD0Pi { // Non Prmpt Gen registry.add("QA/hPtNonPromptDstarGen", "MC Matched Non-Prompt D* Candidates at Generator Level; #it{p}_{T} of D*", {HistType::kTH1F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("QA/hPtVsYNonPromptDstarGen", "MC Matched Non-Prompt D* Candidates at Generator Level; #it{p}_{T} of D*; #it{y}", {HistType::kTH2F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {100, -5., 5.}}}); + + // Checking PV contributors from Data as well MC rec + registry.add("Efficiency/hNumPvContributorsAll", "PV Contributors; PV Contributor; FT0M Centrality", {HistType::kTH2F, {{100, 0, 300}, {axisCentrality}}}, true); + registry.add("Efficiency/hNumPvContributorsCand", "PV Contributors; PV Contributor; FT0M Centrality", {HistType::kTH2F, {{100, 0, 300}, {axisCentrality}}}, true); + registry.add("Efficiency/hNumPvContributorsCandInMass", "PV Contributors; PV Contributor; FT0M Centrality", {HistType::kTH2F, {{100, 0, 300}, {axisCentrality}}}, true); + + // BDT Score (axisBDTScoreBackground, axisBDTScorePrompt, axisBDTScoreNonPrompt) + if (doprocessDataWML) { + registry.add("Yield/hDeltaInvMassVsPtVsCentVsBDTScore", "#Delta #it{M}_{inv} Vs Pt Vs Cent Vs BDTScore", {HistType::kTHnSparseF, {{axisDeltaInvMass}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {axisCentrality}, {axisBDTScoreBackground}, {axisBDTScorePrompt}, {axisBDTScoreNonPrompt}}}); + } + if (doprocessMcWML) { + registry.add("Efficiency/hPtVsCentVsBDTScore", "Pt Vs Cent Vs BDTScore", {HistType::kTHnSparseF, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {axisCentrality}, {axisBDTScoreBackground}, {axisBDTScorePrompt}, {axisBDTScoreNonPrompt}}}); + registry.add("Efficiency/hPtPromptVsCentVsBDTScore", "Pt Vs Cent Vs BDTScore", {HistType::kTHnSparseF, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {axisCentrality}, {axisBDTScoreBackground}, {axisBDTScorePrompt}, {axisBDTScoreNonPrompt}}}); + registry.add("Efficiency/hPtNonPromptVsCentVsBDTScore", "Pt Vs Cent Vs BDTScore", {HistType::kTHnSparseF, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {axisCentrality}, {axisBDTScoreBackground}, {axisBDTScorePrompt}, {axisBDTScoreNonPrompt}}}); + // registry.add("Efficiency/hPtBkgVsCentVsBDTScore", "Pt Vs Cent Vs BDTScore", {HistType::kTHnSparseF, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {axisCentrality}, {axisBDTScoreBackground}, {axisBDTScorePrompt}, {axisBDTScoreNonPrompt}}}); + } } - void process(CandDstarWSelFlag const&) + // Comparator function to sort based on the second argument of a tuple + static bool compare(const std::pair::iterator, int>& a, const std::pair::iterator, int>& b) { - for (const auto& candDstar : rowsSelectedCandDstar) { - auto yDstar = candDstar.y(constants::physics::MassDStar); - if (yCandDstarRecoMax >= 0. && std::abs(yDstar) > yCandDstarRecoMax) { - continue; + return a.second > b.second; + } + + /// @brief This function runs over Data to obatin yield + /// @tparam T1 type of the candidate + /// @tparam T2 type of preslice used to slice the candidate table + /// @tparam applyMl a boolean to apply ML or not + /// @param cols reconstructed collision with centrality + /// @param selectedCands selected candidates with selection flag + /// @param preslice preslice to slice + template + void runTaskDstar(CollisionsWCent const& cols, T1 selectedCands, T2 preslice) + { + for (const auto& col : cols) { + auto nPVContributors = col.numContrib(); + auto centrality = col.centFT0M(); + registry.fill(HIST("Efficiency/hNumPvContributorsAll"), nPVContributors, centrality); + + auto gIndexCol = col.globalIndex(); + auto selectedCandsCurrentCol = selectedCands.sliceBy(preslice, gIndexCol); + auto nCandsCurrentCol = selectedCandsCurrentCol.size(); + + if (nCandsCurrentCol > 0) { + // LOGF(debug, "size of selectedCandsCurrentCol: %d", nCandsCurrentCol); + registry.fill(HIST("Efficiency/hNumPvContributorsCand"), nPVContributors, centrality); } - registry.fill(HIST("QA/hPtDstar"), candDstar.pt()); - registry.fill(HIST("QA/hPtD0"), candDstar.ptD0()); - registry.fill(HIST("QA/hPtSoftPi"), candDstar.ptSoftPi()); - registry.fill(HIST("QA/hEtaDstar"), candDstar.eta(), candDstar.pt()); - registry.fill(HIST("QA/hCtD0"), candDstar.ctD0(), candDstar.pt()); - registry.fill(HIST("QA/hDecayLengthD0"), candDstar.decayLengthD0(), candDstar.pt()); - registry.fill(HIST("QA/hDecayLengthXYD0"), candDstar.decayLengthXYD0(), candDstar.pt()); - registry.fill(HIST("QA/hDecayLengthNormalisedD0"), candDstar.decayLengthNormalisedD0(), candDstar.pt()); - registry.fill(HIST("QA/hDecayLengthXYNormalisedD0"), candDstar.decayLengthXYNormalisedD0(), candDstar.pt()); - registry.fill(HIST("QA/hCPAD0"), candDstar.cpaD0(), candDstar.pt()); - registry.fill(HIST("QA/hCPAxyD0"), candDstar.cpaXYD0(), candDstar.pt()); - registry.fill(HIST("QA/hImpactParameterXYD0"), candDstar.impactParameterXYD0(), candDstar.pt()); - registry.fill(HIST("QA/hDeltaIPMaxNormalisedD0"), candDstar.deltaIPNormalisedMaxD0(), candDstar.pt()); - registry.fill(HIST("QA/hSqSumProngsImpactParameterD0"), candDstar.impactParameterProngSqSumD0(), candDstar.pt()); - registry.fill(HIST("QA/hDecayLengthErrorD0"), candDstar.errorDecayLengthD0(), candDstar.pt()); - registry.fill(HIST("QA/hDecayLengthXYErrorD0"), candDstar.errorDecayLengthXYD0(), candDstar.pt()); - registry.fill(HIST("QA/hImpactParameterError"), candDstar.errorImpactParameter0(), candDstar.pt()); - registry.fill(HIST("QA/hImpactParameterError"), candDstar.errorImpactParameter1(), candDstar.pt()); - registry.fill(HIST("QA/hImpactParameterError"), candDstar.errorImpParamSoftPi(), candDstar.pt()); - registry.fill(HIST("QA/hd0Prong0"), candDstar.impactParameter0(), candDstar.pt()); - registry.fill(HIST("QA/hd0Prong1"), candDstar.impactParameter1(), candDstar.pt()); - registry.fill(HIST("QA/hd0ProngSoftPi"), candDstar.impParamSoftPi(), candDstar.pt()); - - auto invDstar = candDstar.invMassDstar(); - auto invAntiDstar = candDstar.invMassAntiDstar(); - auto invD0 = candDstar.invMassD0(); - auto invD0Bar = candDstar.invMassD0Bar(); - - auto signDstar = candDstar.signSoftPi(); - if (signDstar > 0) { - registry.fill(HIST("Yield/hDeltaInvMassDstar2D"), (invDstar - invD0), candDstar.pt()); - registry.fill(HIST("Yield/hInvMassD0"), invD0, candDstar.ptD0()); - registry.fill(HIST("Yield/hDeltaInvMassDstar1D"), (invDstar - invD0)); - registry.fill(HIST("Yield/hInvMassDstar"), invDstar); - // filling pt of two pronges of D0 - registry.fill(HIST("QA/hPtProng0D0"), candDstar.ptProng0()); - registry.fill(HIST("QA/hPtProng1D0"), candDstar.ptProng1()); - } else if (signDstar < 0) { - registry.fill(HIST("Yield/hDeltaInvMassDstar2D"), (invAntiDstar - invD0Bar), candDstar.pt()); - registry.fill(HIST("Yield/hInvMassD0"), invD0Bar, candDstar.ptD0()); - registry.fill(HIST("Yield/hDeltaInvMassDstar1D"), (invAntiDstar - invD0Bar)); - registry.fill(HIST("Yield/hInvMassDstar"), invAntiDstar); - // filling pt of two pronges of D0Bar - registry.fill(HIST("QA/hPtProng0D0Bar"), candDstar.ptProng0()); - registry.fill(HIST("QA/hPtProng1D0Bar"), candDstar.ptProng1()); + + int nCandsSignalRegion = 0; + for (const auto& candDstar : selectedCandsCurrentCol) { + auto yDstar = candDstar.y(constants::physics::MassDStar); + if (yCandDstarRecoMax >= 0. && std::abs(yDstar) > yCandDstarRecoMax) { + continue; + } + + registry.fill(HIST("QA/hPtDstar"), candDstar.pt()); + registry.fill(HIST("QA/hPtD0"), candDstar.ptD0()); + registry.fill(HIST("QA/hPtSoftPi"), candDstar.ptSoftPi()); + registry.fill(HIST("QA/hEtaDstar"), candDstar.eta(), candDstar.pt()); + registry.fill(HIST("QA/hCtD0"), candDstar.ctD0(), candDstar.pt()); + registry.fill(HIST("QA/hDecayLengthD0"), candDstar.decayLengthD0(), candDstar.pt()); + registry.fill(HIST("QA/hDecayLengthXYD0"), candDstar.decayLengthXYD0(), candDstar.pt()); + registry.fill(HIST("QA/hDecayLengthNormalisedD0"), candDstar.decayLengthNormalisedD0(), candDstar.pt()); + registry.fill(HIST("QA/hDecayLengthXYNormalisedD0"), candDstar.decayLengthXYNormalisedD0(), candDstar.pt()); + registry.fill(HIST("QA/hCPAD0"), candDstar.cpaD0(), candDstar.pt()); + registry.fill(HIST("QA/hCPAxyD0"), candDstar.cpaXYD0(), candDstar.pt()); + registry.fill(HIST("QA/hImpactParameterXYD0"), candDstar.impactParameterXYD0(), candDstar.pt()); + registry.fill(HIST("QA/hDeltaIPMaxNormalisedD0"), candDstar.deltaIPNormalisedMaxD0(), candDstar.pt()); + registry.fill(HIST("QA/hSqSumProngsImpactParameterD0"), candDstar.impactParameterProngSqSumD0(), candDstar.pt()); + registry.fill(HIST("QA/hDecayLengthErrorD0"), candDstar.errorDecayLengthD0(), candDstar.pt()); + registry.fill(HIST("QA/hDecayLengthXYErrorD0"), candDstar.errorDecayLengthXYD0(), candDstar.pt()); + registry.fill(HIST("QA/hImpactParameterError"), candDstar.errorImpactParameter0(), candDstar.pt()); + registry.fill(HIST("QA/hImpactParameterError"), candDstar.errorImpactParameter1(), candDstar.pt()); + registry.fill(HIST("QA/hImpactParameterError"), candDstar.errorImpParamSoftPi(), candDstar.pt()); + registry.fill(HIST("QA/hd0Prong0"), candDstar.impactParameter0(), candDstar.pt()); + registry.fill(HIST("QA/hd0Prong1"), candDstar.impactParameter1(), candDstar.pt()); + registry.fill(HIST("QA/hd0ProngSoftPi"), candDstar.impParamSoftPi(), candDstar.pt()); + + auto invDstar = candDstar.invMassDstar(); + auto invAntiDstar = candDstar.invMassAntiDstar(); + auto invD0 = candDstar.invMassD0(); + auto invD0Bar = candDstar.invMassD0Bar(); + + auto signDstar = candDstar.signSoftPi(); + if (signDstar > 0) { + auto deltaMDstar = std::abs(invDstar - invD0); + if (0.142f < deltaMDstar && deltaMDstar < 0.15f) { + nCandsSignalRegion++; + } + + if constexpr (applyMl) { + auto mlBdtScore = candDstar.mlProbDstarToD0Pi(); + registry.fill(HIST("Yield/hDeltaInvMassVsPtVsCentVsBDTScore"), deltaMDstar, candDstar.pt(), centrality, mlBdtScore[0], mlBdtScore[1], mlBdtScore[2]); + } + + registry.fill(HIST("Yield/hDeltaInvMassDstar3D"), deltaMDstar, candDstar.pt(), centrality); + registry.fill(HIST("Yield/hDeltaInvMassDstar2D"), deltaMDstar, candDstar.pt()); + registry.fill(HIST("Yield/hInvMassD0"), invD0, candDstar.ptD0()); + registry.fill(HIST("Yield/hDeltaInvMassDstar1D"), deltaMDstar); + registry.fill(HIST("Yield/hInvMassDstar"), invDstar); + // filling pt of two pronges of D0 + registry.fill(HIST("QA/hPtProng0D0"), candDstar.ptProng0()); + registry.fill(HIST("QA/hPtProng1D0"), candDstar.ptProng1()); + } else if (signDstar < 0) { + auto deltaMAntiDstar = std::abs(invAntiDstar - invD0Bar); + if (0.142f < deltaMAntiDstar && deltaMAntiDstar < 0.15f) { + nCandsSignalRegion++; + } + + if constexpr (applyMl) { + auto mlBdtScore = candDstar.mlProbDstarToD0Pi(); + registry.fill(HIST("Yield/hDeltaInvMassVsPtVsCentVsBDTScore"), deltaMAntiDstar, candDstar.pt(), centrality, mlBdtScore[0], mlBdtScore[1], mlBdtScore[2]); + } + + registry.fill(HIST("Yield/hDeltaInvMassDstar3D"), deltaMAntiDstar, candDstar.pt(), centrality); + registry.fill(HIST("Yield/hDeltaInvMassDstar2D"), deltaMAntiDstar, candDstar.pt()); + registry.fill(HIST("Yield/hInvMassD0"), invD0Bar, candDstar.ptD0()); + registry.fill(HIST("Yield/hDeltaInvMassDstar1D"), deltaMAntiDstar); + registry.fill(HIST("Yield/hInvMassDstar"), invAntiDstar); + // filling pt of two pronges of D0Bar + registry.fill(HIST("QA/hPtProng0D0Bar"), candDstar.ptProng0()); + registry.fill(HIST("QA/hPtProng1D0Bar"), candDstar.ptProng1()); + } + } // candidate loop for current collision ends + + if (nCandsSignalRegion > 0) { + registry.fill(HIST("Efficiency/hNumPvContributorsCandInMass"), nPVContributors, centrality); } - } + } // collision loop ends } - void processMC(CandDstarWSelFlagMcRec const&, - CandDstarMcGen const& rowsMcPartilces, - aod::TracksWMc const&) + /// @brief This function runs over MC at reco level to obatin efficiency + /// @tparam T1 type of the candidate table + /// @tparam applyMl a boolean to apply ML or not + /// @param candsMcRecSel reconstructed candidates with selection flag + /// @param rowsMcPartilces generated particles table + template + void runMcRecTaskDstar(T1 const& candsMcRecSel, CandDstarMcGen const& rowsMcPartilces) { - + // LOGF(info, "Running MC Rec Task Dstar"); int8_t signDstar = 0; // MC at Reconstruction level - for (const auto& candDstarMcRec : rowsSelectedCandDstarMcRec) { + for (const auto& candDstarMcRec : candsMcRecSel) { + // LOGF(info, "MC Rec Dstar loop"); auto ptDstarRecSig = candDstarMcRec.pt(); auto yDstarRecSig = candDstarMcRec.y(constants::physics::MassDStar); if (yCandDstarRecoMax >= 0. && std::abs(yDstarRecSig) > yCandDstarRecoMax) { continue; } + auto collision = candDstarMcRec.template collision_as(); + auto centrality = collision.centFT0M(); // 0-100% if (TESTBIT(std::abs(candDstarMcRec.flagMcMatchRec()), aod::hf_cand_dstar::DecayType::DstarToD0Pi)) { // if MC matching is successful at Reconstruction Level + // LOGF(info, "MC Rec Dstar loop MC Matched"); // get MC Mother particle - auto indexMother = RecoDecay::getMother(rowsMcPartilces, candDstarMcRec.prong0_as().mcParticle_as(), o2::constants::physics::Pdg::kDStar, true, &signDstar, 2); - auto particleMother = rowsMcPartilces.rawIteratorAt(indexMother); // What is difference between rawIterator() or iteratorAt() methods? - registry.fill(HIST("QA/hPtDstarGenSig"), particleMother.pt()); // generator level pt + auto prong0 = candDstarMcRec.template prong0_as(); + auto indexMother = RecoDecay::getMother(rowsMcPartilces, prong0.template mcParticle_as(), o2::constants::physics::Pdg::kDStar, true, &signDstar, 2); + auto particleMother = rowsMcPartilces.rawIteratorAt(indexMother); // What is difference between rawIterator() or iteratorAt() methods? + registry.fill(HIST("QA/hPtSkimDstarGenSig"), particleMother.pt()); // generator level pt + registry.fill(HIST("Efficiency/hPtVsCentSkimDstarGenSig"), particleMother.pt(), centrality); registry.fill(HIST("QA/hPtVsYSkimDstarRecSig"), ptDstarRecSig, yDstarRecSig); // Skimed at level of trackIndexSkimCreator if (candDstarMcRec.isRecoTopol()) { // if Topological selection are passed @@ -209,8 +330,13 @@ struct HfTaskDstarToD0Pi { if (candDstarMcRec.isRecoPid()) { // if PID selection is passed registry.fill(HIST("QA/hPtVsYRecoPidDstarRecSig"), ptDstarRecSig, yDstarRecSig); } - if (candDstarMcRec.isRecoCand()) { // if all selection passed + if (candDstarMcRec.isSelDstarToD0Pi()) { // if all selection passed registry.fill(HIST("QA/hPtFullRecoDstarRecSig"), ptDstarRecSig); + registry.fill(HIST("Efficiency/hPtVsCentFullRecoDstarRecSig"), ptDstarRecSig, centrality); + if constexpr (applyMl) { + auto bdtScore = candDstarMcRec.mlProbDstarToD0Pi(); + registry.fill(HIST("Efficiency/hPtVsCentVsBDTScore"), ptDstarRecSig, centrality, bdtScore[0], bdtScore[1], bdtScore[2]); + } } registry.fill(HIST("QA/hCPASkimD0RecSig"), candDstarMcRec.cpaD0()); registry.fill(HIST("QA/hEtaSkimD0RecSig"), candDstarMcRec.etaD0()); @@ -225,43 +351,78 @@ struct HfTaskDstarToD0Pi { if (candDstarMcRec.isRecoPid()) { // if PID selection is passed registry.fill(HIST("QA/hPtVsYRecoPidPromptDstarRecSig"), ptDstarRecSig, yDstarRecSig); } - if (candDstarMcRec.isRecoCand()) { // if all selection passed + if (candDstarMcRec.isSelDstarToD0Pi()) { // if all selection passed registry.fill(HIST("QA/hPtFullRecoPromptDstarRecSig"), ptDstarRecSig); + if constexpr (applyMl) { + auto bdtScore = candDstarMcRec.mlProbDstarToD0Pi(); + registry.fill(HIST("Efficiency/hPtPromptVsCentVsBDTScore"), ptDstarRecSig, centrality, bdtScore[0], bdtScore[1], bdtScore[2]); + } } - } else if (candDstarMcRec.originMcRec() == RecoDecay::OriginType::NonPrompt) { // only non-prompt signal at reconstruction level registry.fill(HIST("QA/hPtVsYSkimNonPromptDstarRecSig"), ptDstarRecSig, yDstarRecSig); if (candDstarMcRec.isRecoTopol()) { // if Topological selection are passed registry.fill(HIST("QA/hPtVsYRecoTopolNonPromptDstarRecSig"), ptDstarRecSig, yDstarRecSig); } - if (candDstarMcRec.isRecoPid()) { - registry.fill(HIST("QA/PtVsYRecoPidNonPromptDstarRecSig"), ptDstarRecSig, yDstarRecSig); + if (candDstarMcRec.isRecoPid()) { // if PID selection is passed + registry.fill(HIST("QA/hPtVsYRecoPidNonPromptDstarRecSig"), ptDstarRecSig, yDstarRecSig); } - if (candDstarMcRec.isRecoCand()) { - registry.fill(HIST("QA/PtFullRecoPromptDstarRecSig"), ptDstarRecSig); + if (candDstarMcRec.isSelDstarToD0Pi()) { // if all selection passed + registry.fill(HIST("QA/hPtFullRecoNonPromptDstarRecSig"), ptDstarRecSig); + if constexpr (applyMl) { + auto bdtScore = candDstarMcRec.mlProbDstarToD0Pi(); + registry.fill(HIST("Efficiency/hPtNonPromptVsCentVsBDTScore"), ptDstarRecSig, centrality, bdtScore[0], bdtScore[1], bdtScore[2]); + } } } } else { // MC Unmatched (Baground at Reconstruction Level) registry.fill(HIST("QA/hCPASkimD0RecBg"), candDstarMcRec.cpaD0()); registry.fill(HIST("QA/hEtaSkimD0RecBg"), candDstarMcRec.etaD0()); registry.fill(HIST("QA/hEtaSkimDstarRecBg"), candDstarMcRec.eta()); - registry.fill(HIST("QA/hPtSkimD0RecBg"), candDstarMcRec.ptD0()); - registry.fill(HIST("QA/hPtSkimDstarRecBg"), candDstarMcRec.pt()); + if (candDstarMcRec.isSelDstarToD0Pi()) { + registry.fill(HIST("QA/hPtSkimDstarRecBg"), candDstarMcRec.pt()); + } } - } + } // candidate loop ends + } - // MC at Generator Level - for (const auto& mcParticle : rowsMcPartilces) { + /// @brief This function runs over MC at gen level to obatin efficiency + /// @param collisions reconstructed collision with centrality + /// @param rowsMcPartilces generated particles table + void runMcGenTaskDstar(CollisionsWCentMcLabel const& collisions, CandDstarMcGen const& rowsMcPartilces) + { + // MC Gen level + for (auto const& mcParticle : rowsMcPartilces) { if (TESTBIT(std::abs(mcParticle.flagMcMatchGen()), aod::hf_cand_dstar::DecayType::DstarToD0Pi)) { // MC Matching is successful at Generator Level auto ptGen = mcParticle.pt(); - // auto yGen = mcParticle.y(); // Can we use this definition? auto yGen = RecoDecay::y(mcParticle.pVector(), o2::constants::physics::MassDStar); if (yCandDstarGenMax >= 0. && std::abs(yGen) > yCandDstarGenMax) { continue; } + auto mcCollision = mcParticle.template mcCollision_as(); + auto recCollisions = collisions.sliceBy(colsPerMcCollision, mcCollision.globalIndex()); + // looking if a generated collision reconstructed more than a times. + if (recCollisions.size() > 1) { + for (const auto& [c1, c2] : combinations(CombinationsStrictlyUpperIndexPolicy(recCollisions, recCollisions))) { + auto deltaCent = std::abs(c1.centFT0M() - c2.centFT0M()); + registry.fill(HIST("QA/hDeltaCentGen"), deltaCent); + } + } + float centFT0MGen; + // assigning centrality to MC Collision using max FT0M amplitute from Reconstructed collisions + if (recCollisions.size()) { + std::vector::iterator, int>> tempRecCols; + for (const auto& recCol : recCollisions) { + tempRecCols.push_back(std::make_pair(recCol, recCol.numContrib())); + } + std::sort(tempRecCols.begin(), tempRecCols.end(), compare); + centFT0MGen = tempRecCols.at(0).first.centFT0M(); + } else { + centFT0MGen = -999.; + } registry.fill(HIST("QA/hEtaDstarGen"), mcParticle.eta()); registry.fill(HIST("QA/hPtDstarGen"), ptGen); registry.fill(HIST("QA/hPtVsYDstarGen"), ptGen, yGen); + registry.fill(HIST("Efficiency/hPtVsCentDstarGen"), ptGen, centFT0MGen); // only promt Dstar candidate at Generator level if (mcParticle.originMcGen() == RecoDecay::OriginType::Prompt) { registry.fill(HIST("QA/hPtPromptDstarGen"), ptGen); @@ -271,9 +432,44 @@ struct HfTaskDstarToD0Pi { registry.fill(HIST("QA/hPtVsYNonPromptDstarGen"), ptGen, yGen); } } - } + } // MC Particle loop ends + } + + // process data function without susing ML + void processDataWoML(CollisionsWCent const& cols, soa::Filtered const& selectedCands) + { + runTaskDstar, Preslice>>(cols, selectedCands, preslicSelectedCandDstarPerCol); + } + PROCESS_SWITCH(HfTaskDstarToD0Pi, processDataWoML, "Process Data without ML", true); + + // process data function with using ML, Here we store BDT score as well + void processDataWML(CollisionsWCent const& cols, soa::Filtered const& selectedCands) + { + runTaskDstar, Preslice>>(cols, selectedCands, preslicSelectedCandDstarPerColWMl); + } + PROCESS_SWITCH(HfTaskDstarToD0Pi, processDataWML, "Process Data with ML", false); + + // process MC function without using ML + void processMcWoMl(aod::McCollisions const&, CollisionsWCentMcLabel const& collisions, CandDstarWSelFlagMcRec const&, + CandDstarMcGen const& rowsMcPartilces, + aod::TracksWMc const&) + { + rowsSelectedCandDstarMcRec.bindExternalIndices(&collisions); + runMcRecTaskDstar>(rowsSelectedCandDstarMcRec, rowsMcPartilces); + runMcGenTaskDstar(collisions, rowsMcPartilces); + } + PROCESS_SWITCH(HfTaskDstarToD0Pi, processMcWoMl, "Process MC Data without ML", false); + + // process MC function with using ML + void processMcWML(aod::McCollisions const&, CollisionsWCentMcLabel const& collisions, CandDstarWSelFlagWMlMcRec const&, + CandDstarMcGen const& rowsMcPartilces, + aod::TracksWMc const&) + { + rowsSelectedCandDstarMcRecWMl.bindExternalIndices(&collisions); + runMcRecTaskDstar>(rowsSelectedCandDstarMcRecWMl, rowsMcPartilces); + runMcGenTaskDstar(collisions, rowsMcPartilces); } - PROCESS_SWITCH(HfTaskDstarToD0Pi, processMC, "Process MC Data", false); + PROCESS_SWITCH(HfTaskDstarToD0Pi, processMcWML, "Process MC Data with ML", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx b/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx index 499b0d70946..862b4910c72 100644 --- a/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx +++ b/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx @@ -15,6 +15,10 @@ /// \author S. Politanò, INFN Torino, Italy /// \author Wu Chuntai, CUG, China +#include +#include + +#include "CCDB/BasicCCDBManager.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" @@ -23,14 +27,18 @@ #include "Common/DataModel/Qvectors.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/Utils/utilsEvSelHf.h" using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; -using namespace o2::aod::hf_collision_centrality; +using namespace o2::hf_centrality; +using namespace o2::hf_occupancy; +using namespace o2::hf_evsel; enum DecayChannel { DplusToPiKPi = 0, DsToKKPi, @@ -38,33 +46,54 @@ enum DecayChannel { DplusToPiKPi = 0, D0ToPiK, D0ToKPi, LcToPKPi, - LcToPiKP }; + LcToPiKP, + XicToPKPi, + XicToPiKP +}; enum QvecEstimator { FV0A = 0, FT0M, FT0A, FT0C, TPCPos, - TPCNeg }; + TPCNeg, + TPCTot }; struct HfTaskFlowCharmHadrons { - Configurable zVtxMax{"zVtxMax", 10., "Max vertex coordinate z"}; Configurable harmonic{"harmonic", 2, "harmonic number"}; - Configurable qvecDetector{"qvecDetector", 3, "Detector for Q vector estimation (FV0A: 0, FT0M: 1, FT0A: 2, FT0C: 3, TPC Pos: 4, TPC Neg: 5)"}; + Configurable qvecDetector{"qvecDetector", 3, "Detector for Q vector estimation (FV0A: 0, FT0M: 1, FT0A: 2, FT0C: 3, TPC Pos: 4, TPC Neg: 5, TPC Tot: 6)"}; Configurable centEstimator{"centEstimator", 2, "Centrality estimation (FT0A: 1, FT0C: 2, FT0M: 3, FV0A: 4)"}; Configurable selectionFlag{"selectionFlag", 1, "Selection Flag for hadron (e.g. 1 for skimming, 3 for topo. and kine., 7 for PID)"}; + Configurable centralityMin{"centralityMin", 0., "Minimum centrality accepted in SP/EP computation (not applied in resolution process)"}; + Configurable centralityMax{"centralityMax", 100., "Maximum centrality accepted in SP/EP computation (not applied in resolution process)"}; + Configurable storeEP{"storeEP", false, "Flag to store EP-related axis"}; Configurable storeMl{"storeMl", false, "Flag to store ML scores"}; + Configurable storeResoOccu{"storeResoOccu", false, "Flag to store Occupancy in resolution ThnSparse"}; + Configurable storeEpCosSin{"storeEpCosSin", false, "Flag to store cos and sin of EP angle in ThnSparse"}; + Configurable occEstimator{"occEstimator", 0, "Occupancy estimation (0: None, 1: ITS, 2: FT0C)"}; Configurable saveEpResoHisto{"saveEpResoHisto", false, "Flag to save event plane resolution histogram"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable> classMl{"classMl", {0, 2}, "Indexes of BDT scores to be stored. Two indexes max."}; ConfigurableAxis thnConfigAxisInvMass{"thnConfigAxisInvMass", {100, 1.78, 2.05}, ""}; ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {10, 0., 10.}, ""}; ConfigurableAxis thnConfigAxisCent{"thnConfigAxisCent", {10000, 0., 100.}, ""}; ConfigurableAxis thnConfigAxisCosNPhi{"thnConfigAxisCosNPhi", {100, -1., 1.}, ""}; + ConfigurableAxis thnConfigAxisPsi{"thnConfigAxisPsi", {6000, 2. * TMath::Pi(), 2. * TMath::Pi()}, ""}; ConfigurableAxis thnConfigAxisCosDeltaPhi{"thnConfigAxisCosDeltaPhi", {100, -1., 1.}, ""}; ConfigurableAxis thnConfigAxisScalarProd{"thnConfigAxisScalarProd", {100, 0., 1.}, ""}; ConfigurableAxis thnConfigAxisMlOne{"thnConfigAxisMlOne", {1000, 0., 1.}, ""}; ConfigurableAxis thnConfigAxisMlTwo{"thnConfigAxisMlTwo", {1000, 0., 1.}, ""}; + ConfigurableAxis thnConfigAxisOccupancyITS{"thnConfigAxisOccupancyITS", {14, 0, 14000}, ""}; + ConfigurableAxis thnConfigAxisOccupancyFT0C{"thnConfigAxisOccupancyFT0C", {14, 0, 140000}, ""}; + ConfigurableAxis thnConfigAxisNoSameBunchPileup{"thnConfigAxisNoSameBunchPileup", {2, 0, 2}, ""}; + ConfigurableAxis thnConfigAxisOccupancy{"thnConfigAxisOccupancy", {2, 0, 2}, ""}; + ConfigurableAxis thnConfigAxisNoCollInTimeRangeNarrow{"thnConfigAxisNoCollInTimeRangeNarrow", {2, 0, 2}, ""}; + ConfigurableAxis thnConfigAxisNoCollInTimeRangeStandard{"thnConfigAxisNoCollInTimeRangeStandard", {2, 0, 2}, ""}; + ConfigurableAxis thnConfigAxisNoCollInRofStandard{"thnConfigAxisNoCollInRofStandard", {2, 0, 2}, ""}; + ConfigurableAxis thnConfigAxisResoFT0cFV0a{"thnConfigAxisResoFT0cFV0a", {160, -8, 8}, ""}; + ConfigurableAxis thnConfigAxisResoFT0cTPCtot{"thnConfigAxisResoFT0cTPCtot", {160, -8, 8}, ""}; + ConfigurableAxis thnConfigAxisResoFV0aTPCtot{"thnConfigAxisResoFV0aTPCtot", {160, -8, 8}, ""}; using CandDsDataWMl = soa::Filtered>; using CandDsData = soa::Filtered>; @@ -72,14 +101,17 @@ struct HfTaskFlowCharmHadrons { using CandDplusData = soa::Filtered>; using CandLcData = soa::Filtered>; using CandLcDataWMl = soa::Filtered>; + using CandXicData = soa::Filtered>; + using CandXicDataWMl = soa::Filtered>; using CandD0DataWMl = soa::Filtered>; using CandD0Data = soa::Filtered>; - using CollsWithQvecs = soa::Join; + using CollsWithQvecs = soa::Join; Filter filterSelectDsCandidates = aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlag || aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlag; Filter filterSelectDplusCandidates = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlag; Filter filterSelectD0Candidates = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlag || aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlag; Filter filterSelectLcCandidates = aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlag || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlag; + Filter filterSelectXicCandidates = aod::hf_sel_candidate_xic::isSelXicToPKPi >= selectionFlag || aod::hf_sel_candidate_xic::isSelXicToPiKP >= selectionFlag; Partition selectedDsToKKPi = aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlag; Partition selectedDsToPiKK = aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlag; @@ -93,57 +125,127 @@ struct HfTaskFlowCharmHadrons { Partition selectedLcToPiKP = aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlag; Partition selectedLcToPKPiWMl = aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlag; Partition selectedLcToPiKPWMl = aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlag; + Partition selectedXicToPKPi = aod::hf_sel_candidate_xic::isSelXicToPKPi >= selectionFlag; + Partition selectedXicToPiKP = aod::hf_sel_candidate_xic::isSelXicToPiKP >= selectionFlag; + Partition selectedXicToPKPiWMl = aod::hf_sel_candidate_xic::isSelXicToPKPi >= selectionFlag; + Partition selectedXicToPiKPWMl = aod::hf_sel_candidate_xic::isSelXicToPiKP >= selectionFlag; SliceCache cache; HfHelper hfHelper; EventPlaneHelper epHelper; + HfEventSelection hfEvSel; // event selection and monitoring + o2::framework::Service ccdb; HistogramRegistry registry{"registry", {}}; void init(InitContext&) { + if (storeResoOccu && occEstimator == 0) { + LOGP(fatal, "Occupancy estimation must be enabled to store resolution THnSparse! Please check your configuration!"); + } const AxisSpec thnAxisInvMass{thnConfigAxisInvMass, "Inv. mass (GeV/#it{c}^{2})"}; const AxisSpec thnAxisPt{thnConfigAxisPt, "#it{p}_{T} (GeV/#it{c})"}; const AxisSpec thnAxisCent{thnConfigAxisCent, "Centrality"}; const AxisSpec thnAxisCosNPhi{thnConfigAxisCosNPhi, Form("cos(%d#varphi)", harmonic.value)}; + const AxisSpec thnAxisSinNPhi{thnConfigAxisCosNPhi, Form("sin(%d#varphi)", harmonic.value)}; + const AxisSpec thnAxisPsi{thnConfigAxisPsi, Form("#Psi_{%d}", harmonic.value)}; const AxisSpec thnAxisCosDeltaPhi{thnConfigAxisCosDeltaPhi, Form("cos(%d(#varphi - #Psi_{sub}))", harmonic.value)}; const AxisSpec thnAxisScalarProd{thnConfigAxisScalarProd, "SP"}; const AxisSpec thnAxisMlOne{thnConfigAxisMlOne, "Bkg score"}; const AxisSpec thnAxisMlTwo{thnConfigAxisMlTwo, "FD score"}; - + const AxisSpec thnAxisOccupancyITS{thnConfigAxisOccupancyITS, "OccupancyITS"}; + const AxisSpec thnAxisOccupancyFT0C{thnConfigAxisOccupancyFT0C, "OccupancyFT0C"}; + const AxisSpec thnAxisNoSameBunchPileup{thnConfigAxisNoSameBunchPileup, "NoSameBunchPileup"}; + const AxisSpec thnAxisOccupancy{thnConfigAxisOccupancy, "Occupancy"}; + const AxisSpec thnAxisNoCollInTimeRangeNarrow{thnConfigAxisNoCollInTimeRangeNarrow, "NoCollInTimeRangeNarrow"}; + const AxisSpec thnAxisNoCollInTimeRangeStandard{thnConfigAxisNoCollInTimeRangeStandard, "NoCollInTimeRangeStandard"}; + const AxisSpec thnAxisNoCollInRofStandard{thnConfigAxisNoCollInRofStandard, "NoCollInRofStandard"}; + // TODO: currently only the Q vector of FT0c FV0a and TPCtot are considered + const AxisSpec thnAxisResoFT0cFV0a{thnConfigAxisResoFT0cFV0a, "Q_{FT0c} #bullet Q_{FV0a}"}; + const AxisSpec thnAxisResoFT0cTPCtot{thnConfigAxisResoFT0cTPCtot, "Q_{FT0c} #bullet Q_{TPCtot}"}; + const AxisSpec thnAxisResoFV0aTPCtot{thnConfigAxisResoFV0aTPCtot, "Q_{FV0a} #bullet Q_{TPCtot}"}; + + std::vector axes = {thnAxisInvMass, thnAxisPt, thnAxisCent, thnAxisScalarProd}; + if (storeEP) { + axes.insert(axes.end(), {thnAxisCosNPhi, thnAxisSinNPhi, thnAxisCosDeltaPhi}); + } if (storeMl) { - registry.add("hSparseFlowCharm", "THn for SP", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCent, thnAxisCosNPhi, thnAxisCosDeltaPhi, thnAxisScalarProd, thnAxisMlOne, thnAxisMlTwo}); - } else { - registry.add("hSparseFlowCharm", "THn for SP", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCent, thnAxisCosNPhi, thnAxisCosDeltaPhi, thnAxisScalarProd}); + axes.insert(axes.end(), {thnAxisMlOne, thnAxisMlTwo}); + } + if (occEstimator != 0) { + if (occEstimator == 1) { + axes.insert(axes.end(), {thnAxisOccupancyITS, thnAxisNoSameBunchPileup, thnAxisOccupancy, + thnAxisNoCollInTimeRangeNarrow, thnAxisNoCollInTimeRangeStandard, thnAxisNoCollInRofStandard}); + } else { + axes.insert(axes.end(), {thnAxisOccupancyFT0C, thnAxisNoSameBunchPileup, thnAxisOccupancy, + thnAxisNoCollInTimeRangeNarrow, thnAxisNoCollInTimeRangeStandard, thnAxisNoCollInRofStandard}); + } } - registry.add("spReso/hSpResoFT0cFT0a", "hSpResoFT0cFT0a; centrality; Q_{FT0c} #bullet Q_{FT0a}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); - registry.add("spReso/hSpResoFT0cFV0a", "hSpResoFT0cFV0a; centrality; Q_{FT0c} #bullet Q_{FV0a}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); - registry.add("spReso/hSpResoFT0cTPCpos", "hSpResoFT0cTPCpos; centrality; Q_{FT0c} #bullet Q_{TPCpos}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); - registry.add("spReso/hSpResoFT0cTPCneg", "hSpResoFT0cTPCneg; centrality; Q_{FT0c} #bullet Q_{TPCneg}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); - registry.add("spReso/hSpResoFT0aFV0a", "hSpResoFT0aFV0a; centrality; Q_{FT0a} #bullet Q_{FV0a}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); - registry.add("spReso/hSpResoFT0aTPCpos", "hSpResoFT0aTPCpos; centrality; Q_{FT0a} #bullet Q_{TPCpos}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); - registry.add("spReso/hSpResoFT0aTPCneg", "hSpResoFT0aTPCneg; centrality; Q_{FT0a} #bullet Q_{TPCneg}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); - registry.add("spReso/hSpResoFT0mFV0a", "hSpResoFT0mFV0a; centrality; Q_{FT0m} #bullet Q_{FV0a}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); - registry.add("spReso/hSpResoFT0mTPCpos", "hSpResoFT0mTPCpos; centrality; Q_{FT0m} #bullet Q_{TPCpos}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); - registry.add("spReso/hSpResoFT0mTPCneg", "hSpResoFT0mTPCneg; centrality; Q_{FT0m} #bullet Q_{TPCneg}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); - registry.add("spReso/hSpResoFV0aTPCpos", "hSpResoFV0aTPCpos; centrality; Q_{FV0a} #bullet Q_{TPCpos}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); - registry.add("spReso/hSpResoFV0aTPCneg", "hSpResoFV0aTPCneg; centrality; Q_{FV0a} #bullet Q_{TPCneg}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); - registry.add("spReso/hSpResoTPCposTPCneg", "hSpResoTPCposTPCneg; centrality; Q_{TPCpos} #bullet Q_{TPCneg}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + registry.add("hSparseFlowCharm", "THn for SP", HistType::kTHnSparseF, axes); - if (saveEpResoHisto) { - registry.add("epReso/hEpResoFT0cFT0a", "hEpResoFT0cFT0a; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); - registry.add("epReso/hEpResoFT0cFV0a", "hEpResoFT0cFV0a; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); - registry.add("epReso/hEpResoFT0cTPCpos", "hEpResoFT0cTPCpos; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); - registry.add("epReso/hEpResoFT0cTPCneg", "hEpResoFT0cTPCneg; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); - registry.add("epReso/hEpResoFT0aFV0a", "hEpResoFT0aFV0a; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); - registry.add("epReso/hEpResoFT0aTPCpos", "hEpResoFT0aTPCpos; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); - registry.add("epReso/hEpResoFT0aTPCneg", "hEpResoFT0aTPCneg; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); - registry.add("epReso/hEpResoFT0mFV0a", "hEpResoFT0mFV0a; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); - registry.add("epReso/hEpResoFT0mTPCpos", "hEpResoFT0mTPCpos; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); - registry.add("epReso/hEpResoFT0mTPCneg", "hEpResoFT0mTPCneg; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); - registry.add("epReso/hEpResoFV0aTPCpos", "hEpResoFV0aTPCpos; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); - registry.add("epReso/hEpResoFV0aTPCneg", "hEpResoFV0aTPCneg; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); - registry.add("epReso/hEpResoTPCposTPCneg", "hEpResoTPCposTPCneg; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + if (occEstimator != 0) { + registry.add("trackOccVsFT0COcc", "trackOccVsFT0COcc; trackOcc; FT0COcc", {HistType::kTH2F, {thnAxisOccupancyITS, thnAxisOccupancyFT0C}}); + } + + if (storeEpCosSin) { + registry.add("ep/hSparseEp", "THn for Event Plane distirbution", {HistType::kTHnSparseF, {thnAxisCent, thnAxisPsi, thnAxisCosNPhi, thnAxisSinNPhi}}); + } + + if (doprocessResolution) { // enable resolution histograms only for resolution process + registry.add("spReso/hSpResoFT0cFT0a", "hSpResoFT0cFT0a; centrality; Q_{FT0c} #bullet Q_{FT0a}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + registry.add("spReso/hSpResoFT0cFV0a", "hSpResoFT0cFV0a; centrality; Q_{FT0c} #bullet Q_{FV0a}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + registry.add("spReso/hSpResoFT0cTPCpos", "hSpResoFT0cTPCpos; centrality; Q_{FT0c} #bullet Q_{TPCpos}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + registry.add("spReso/hSpResoFT0cTPCneg", "hSpResoFT0cTPCneg; centrality; Q_{FT0c} #bullet Q_{TPCneg}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + registry.add("spReso/hSpResoFT0cTPCtot", "hSpResoFT0cTPCtot; centrality; Q_{FT0c} #bullet Q_{TPCtot}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + registry.add("spReso/hSpResoFT0aFV0a", "hSpResoFT0aFV0a; centrality; Q_{FT0a} #bullet Q_{FV0a}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + registry.add("spReso/hSpResoFT0aTPCpos", "hSpResoFT0aTPCpos; centrality; Q_{FT0a} #bullet Q_{TPCpos}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + registry.add("spReso/hSpResoFT0aTPCneg", "hSpResoFT0aTPCneg; centrality; Q_{FT0a} #bullet Q_{TPCneg}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + registry.add("spReso/hSpResoFT0aTPCtot", "hSpResoFT0aTPCtot; centrality; Q_{FT0m} #bullet Q_{TPCtot}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + registry.add("spReso/hSpResoFT0mFV0a", "hSpResoFT0mFV0a; centrality; Q_{FT0m} #bullet Q_{FV0a}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + registry.add("spReso/hSpResoFT0mTPCpos", "hSpResoFT0mTPCpos; centrality; Q_{FT0m} #bullet Q_{TPCpos}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + registry.add("spReso/hSpResoFT0mTPCneg", "hSpResoFT0mTPCneg; centrality; Q_{FT0m} #bullet Q_{TPCneg}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + registry.add("spReso/hSpResoFT0mTPCtot", "hSpResoFT0mTPCtot; centrality; Q_{FV0a} #bullet Q_{TPCtot}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + registry.add("spReso/hSpResoFV0aTPCpos", "hSpResoFV0aTPCpos; centrality; Q_{FV0a} #bullet Q_{TPCpos}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + registry.add("spReso/hSpResoFV0aTPCneg", "hSpResoFV0aTPCneg; centrality; Q_{FV0a} #bullet Q_{TPCneg}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + registry.add("spReso/hSpResoFV0aTPCtot", "hSpResoFV0aTPCtot; centrality; Q_{FV0a} #bullet Q_{TPCtot}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + registry.add("spReso/hSpResoTPCposTPCneg", "hSpResoTPCposTPCneg; centrality; Q_{TPCpos} #bullet Q_{TPCneg}", {HistType::kTH2F, {thnAxisCent, thnAxisScalarProd}}); + + if (saveEpResoHisto) { + registry.add("epReso/hEpResoFT0cFT0a", "hEpResoFT0cFT0a; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + registry.add("epReso/hEpResoFT0cFV0a", "hEpResoFT0cFV0a; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + registry.add("epReso/hEpResoFT0cTPCpos", "hEpResoFT0cTPCpos; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + registry.add("epReso/hEpResoFT0cTPCneg", "hEpResoFT0cTPCneg; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + registry.add("epReso/hEpResoFT0cTPCtot", "hEpResoFT0cTPCtot; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + registry.add("epReso/hEpResoFT0aFV0a", "hEpResoFT0aFV0a; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + registry.add("epReso/hEpResoFT0aTPCpos", "hEpResoFT0aTPCpos; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + registry.add("epReso/hEpResoFT0aTPCneg", "hEpResoFT0aTPCneg; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + registry.add("epReso/hEpResoFT0aTPCtot", "hEpResoFT0aTPCtot; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + registry.add("epReso/hEpResoFT0mFV0a", "hEpResoFT0mFV0a; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + registry.add("epReso/hEpResoFT0mTPCpos", "hEpResoFT0mTPCpos; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + registry.add("epReso/hEpResoFT0mTPCneg", "hEpResoFT0mTPCneg; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + registry.add("epReso/hEpResoFT0mTPCtot", "hEpResoFT0mTPCtot; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + registry.add("epReso/hEpResoFV0aTPCpos", "hEpResoFV0aTPCpos; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + registry.add("epReso/hEpResoFV0aTPCneg", "hEpResoFV0aTPCneg; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + registry.add("epReso/hEpResoFV0aTPCtot", "hEpResoFV0aTPCtot; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + registry.add("epReso/hEpResoTPCposTPCneg", "hEpResoTPCposTPCneg; centrality; #Delta#Psi_{sub}", {HistType::kTH2F, {thnAxisCent, thnAxisCosNPhi}}); + } + + if (storeResoOccu) { + std::vector axes_reso = {thnAxisCent, thnAxisResoFT0cFV0a, thnAxisResoFT0cTPCtot, thnAxisResoFV0aTPCtot}; + if (occEstimator == 1) { + axes_reso.insert(axes_reso.end(), {thnAxisOccupancyITS, thnAxisNoSameBunchPileup, thnAxisOccupancy, + thnAxisNoCollInTimeRangeNarrow, thnAxisNoCollInTimeRangeStandard, thnAxisNoCollInRofStandard}); + } else { + axes_reso.insert(axes_reso.end(), {thnAxisOccupancyFT0C, thnAxisNoSameBunchPileup, thnAxisOccupancy, + thnAxisNoCollInTimeRangeNarrow, thnAxisNoCollInTimeRangeStandard, thnAxisNoCollInRofStandard}); + } + registry.add("spReso/hSparseReso", "THn for resolution with occupancy", HistType::kTHnSparseF, axes_reso); + } + + hfEvSel.addHistograms(registry); // collision monitoring + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); } }; // end init @@ -199,53 +301,94 @@ struct HfTaskFlowCharmHadrons { return deltaPsi; } + /// Get the event selection flags + /// \param hfevselflag is the event selection flag + std::vector getEventSelectionFlags(uint16_t hfevselflag) + { + return { + TESTBIT(hfevselflag, o2::hf_evsel::EventRejection::NoSameBunchPileup), + TESTBIT(hfevselflag, o2::hf_evsel::EventRejection::Occupancy), + TESTBIT(hfevselflag, o2::hf_evsel::EventRejection::NoCollInTimeRangeNarrow), + TESTBIT(hfevselflag, o2::hf_evsel::EventRejection::NoCollInTimeRangeStandard), + TESTBIT(hfevselflag, o2::hf_evsel::EventRejection::NoCollInRofStandard)}; + } + /// Fill THnSparse /// \param mass is the invariant mass of the candidate /// \param pt is the transverse momentum of the candidate /// \param cent is the centrality of the collision /// \param cosNPhi is the cosine of the n*phi angle + /// \param sinNPhi is the sine of the n*phi angle /// \param cosDeltaPhi is the cosine of the n*(phi - evtPl) angle /// \param sp is the scalar product /// \param outputMl are the ML scores + /// \param occupancy is the occupancy of the collision using the track estimator + /// \param hfevselflag flag of the collision associated to utilsEvSelHf.h void fillThn(float& mass, float& pt, float& cent, float& cosNPhi, + float& sinNPhi, float& cosDeltaPhi, float& sp, - std::vector& outputMl) + std::vector& outputMl, + float& occupancy, + uint16_t& hfevselflag) { - if (storeMl) { - registry.fill(HIST("hSparseFlowCharm"), mass, pt, cent, cosNPhi, cosDeltaPhi, sp, outputMl[0], outputMl[1]); + if (occEstimator != 0) { + std::vector evtSelFlags = getEventSelectionFlags(hfevselflag); + if (storeMl) { + if (storeEP) { + registry.fill(HIST("hSparseFlowCharm"), mass, pt, cent, sp, cosNPhi, sinNPhi, cosDeltaPhi, outputMl[0], outputMl[1], occupancy, + evtSelFlags[0], evtSelFlags[1], evtSelFlags[2], evtSelFlags[3], evtSelFlags[4]); + } else { + registry.fill(HIST("hSparseFlowCharm"), mass, pt, cent, sp, outputMl[0], outputMl[1], occupancy, + evtSelFlags[0], evtSelFlags[1], evtSelFlags[2], evtSelFlags[3], evtSelFlags[4]); + } + } else { + if (storeEP) { + registry.fill(HIST("hSparseFlowCharm"), mass, pt, cent, sp, cosNPhi, sinNPhi, cosDeltaPhi, occupancy, + evtSelFlags[0], evtSelFlags[1], evtSelFlags[2], evtSelFlags[3], evtSelFlags[4]); + } else { + registry.fill(HIST("hSparseFlowCharm"), mass, pt, cent, sp, occupancy, + evtSelFlags[0], evtSelFlags[1], evtSelFlags[2], evtSelFlags[3], evtSelFlags[4]); + } + } } else { - registry.fill(HIST("hSparseFlowCharm"), mass, pt, cent, cosNPhi, cosDeltaPhi, sp); + if (storeMl) { + if (storeEP) { + registry.fill(HIST("hSparseFlowCharm"), mass, pt, cent, sp, cosNPhi, sinNPhi, cosDeltaPhi, outputMl[0], outputMl[1]); + } else { + registry.fill(HIST("hSparseFlowCharm"), mass, pt, cent, sp, outputMl[0], outputMl[1]); + } + } else { + if (storeEP) { + registry.fill(HIST("hSparseFlowCharm"), mass, pt, cent, sp, cosNPhi, sinNPhi, cosDeltaPhi); + } else { + registry.fill(HIST("hSparseFlowCharm"), mass, pt, cent, sp); + } + } } } - /// Get the centrality - /// \param collision is the collision with the centrality information - float getCentrality(CollsWithQvecs::iterator const& collision) + /// Check if the collision is selected + /// \param collision is the collision with the Q vector information + /// \param bc is the bunch crossing with timestamp information + /// \param centrality is the collision centrality + /// \return true if the collision is selected, false otherwise + template + bool isCollSelected(CollsWithQvecs::iterator const& collision, + aod::BCsWithTimestamps const&, + float& centrality) { - float cent = -999.; - switch (centEstimator) { - case CentralityEstimator::FV0A: - cent = collision.centFV0A(); - break; - case CentralityEstimator::FT0M: - cent = collision.centFT0M(); - break; - case CentralityEstimator::FT0A: - cent = collision.centFT0A(); - break; - case CentralityEstimator::FT0C: - cent = collision.centFT0C(); - break; - default: - LOG(warning) << "Centrality estimator not valid. Possible values are V0A, T0M, T0A, T0C. Fallback to V0A"; - cent = collision.centFV0A(); - break; - } - return cent; + float occupancy = getOccupancyColl(collision, occEstimator); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + centrality = o2::hf_centrality::getCentralityColl(collision, centEstimator); + + /// monitor the satisfied event selections + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy); + registry.fill(HIST("trackOccVsFT0COcc"), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + return rejectionMask == 0; } /// Get the Q vector @@ -282,6 +425,11 @@ struct HfTaskFlowCharmHadrons { yQVec = collision.qvecBNegIm(); amplQVec = collision.nTrkBNeg(); break; + case QvecEstimator::TPCTot: + xQVec = collision.qvecBTotRe(); + yQVec = collision.qvecBTotIm(); + amplQVec = collision.nTrkBTot(); + break; default: LOG(warning) << "Q vector estimator not valid. Please choose between FV0A, FT0M, FT0A, FT0C, TPC Pos, TPC Neg. Fallback to FV0A"; xQVec = collision.qvecFV0ARe(); @@ -298,12 +446,23 @@ struct HfTaskFlowCharmHadrons { void runFlowAnalysis(CollsWithQvecs::iterator const& collision, T1 const& candidates) { + float cent = o2::hf_centrality::getCentralityColl(collision, centEstimator); + if (cent < centralityMin || cent > centralityMax) { + return; + } + float occupancy = 0.; + uint16_t hfevflag{}; + if (occEstimator != 0) { + occupancy = getOccupancyColl(collision, occEstimator); + registry.fill(HIST("trackOccVsFT0COcc"), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + hfevflag = hfEvSel.getHfCollisionRejectionMask(collision, cent, ccdb, registry); + } + std::vector qVecs = getQvec(collision); float xQVec = qVecs[0]; float yQVec = qVecs[1]; float amplQVec = qVecs[2]; float evtPl = epHelper.GetEventPlane(xQVec, yQVec, harmonic); - float cent = getCentrality(collision); int nProngs = 3; for (const auto& candidate : candidates) { @@ -374,6 +533,25 @@ struct HfTaskFlowCharmHadrons { default: break; } + } else if constexpr (std::is_same_v || std::is_same_v) { + switch (channel) { + case DecayChannel::XicToPKPi: + massCand = hfHelper.invMassXicToPKPi(candidate); + if constexpr (std::is_same_v) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) + outputMl[iclass] = candidate.mlProbXicToPKPi()[classMl->at(iclass)]; + } + break; + case DecayChannel::XicToPiKP: + massCand = hfHelper.invMassXicToPiKP(candidate); + if constexpr (std::is_same_v) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) + outputMl[iclass] = candidate.mlProbXicToPiKP()[classMl->at(iclass)]; + } + break; + default: + break; + } } float ptCand = candidate.pt(); @@ -397,7 +575,7 @@ struct HfTaskFlowCharmHadrons { float scalprodCand = cosNPhi * xQVec + sinNPhi * yQVec; float cosDeltaPhi = std::cos(harmonic * (phiCand - evtPl)); - fillThn(massCand, ptCand, cent, cosNPhi, cosDeltaPhi, scalprodCand, outputMl); + fillThn(massCand, ptCand, cent, cosNPhi, sinNPhi, cosDeltaPhi, scalprodCand, outputMl, occupancy, hfevflag); } } @@ -483,15 +661,33 @@ struct HfTaskFlowCharmHadrons { } PROCESS_SWITCH(HfTaskFlowCharmHadrons, processLc, "Process Lc candidates", false); - // Resolution - void processResolution(CollsWithQvecs::iterator const& collision) + // Xic with ML + void processXicMl(CollsWithQvecs::iterator const& collision, + CandXicDataWMl const&) { + auto candsXicToPKPiWMl = selectedXicToPKPiWMl->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); + auto candsXicToPiKPWMl = selectedXicToPiKPWMl->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); + runFlowAnalysis(collision, candsXicToPKPiWMl); + runFlowAnalysis(collision, candsXicToPiKPWMl); + } + PROCESS_SWITCH(HfTaskFlowCharmHadrons, processXicMl, "Process Xic candidates with ML", false); - if (!collision.sel8() || std::abs(collision.posZ()) > zVtxMax) { - return; - } + // Xic with rectangular cuts + void processXic(CollsWithQvecs::iterator const& collision, + CandXicData const&) + { + auto candsXicToPKPi = selectedXicToPKPi->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); + auto candsXicToPiKP = selectedXicToPiKP->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); + runFlowAnalysis(collision, candsXicToPKPi); + runFlowAnalysis(collision, candsXicToPiKP); + } + PROCESS_SWITCH(HfTaskFlowCharmHadrons, processXic, "Process Xic candidates", false); - float centrality = getCentrality(collision); + // Resolution + void processResolution(CollsWithQvecs::iterator const& collision, + aod::BCsWithTimestamps const& bcs) + { + float centrality{-1.f}; float xQVecFT0a = collision.qvecFT0ARe(); float yQVecFT0a = collision.qvecFT0AIm(); float xQVecFT0c = collision.qvecFT0CRe(); @@ -504,19 +700,43 @@ struct HfTaskFlowCharmHadrons { float yQVecBPos = collision.qvecBPosIm(); float xQVecBNeg = collision.qvecBNegRe(); float yQVecBNeg = collision.qvecBNegIm(); + float xQVecBTot = collision.qvecBTotRe(); + float yQVecBTot = collision.qvecBTotIm(); + + centrality = o2::hf_centrality::getCentralityColl(collision, o2::hf_centrality::CentralityEstimator::FT0C); + if (storeResoOccu) { + float occupancy{-1.f}; + occupancy = getOccupancyColl(collision, occEstimator); + registry.fill(HIST("trackOccVsFT0COcc"), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + uint16_t hfevflag = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + std::vector evtSelFlags = getEventSelectionFlags(hfevflag); + registry.fill(HIST("spReso/hSparseReso"), centrality, xQVecFT0c * xQVecFV0a + yQVecFT0c * yQVecFV0a, + xQVecFT0c * xQVecBTot + yQVecFT0c * yQVecBTot, + xQVecFV0a * xQVecBTot + yQVecFV0a * yQVecBTot, + occupancy, evtSelFlags[0], evtSelFlags[1], evtSelFlags[2], evtSelFlags[3], evtSelFlags[4]); + } + + if (!isCollSelected(collision, bcs, centrality)) { + // no selection on the centrality is applied, but on event selection flags + return; + } registry.fill(HIST("spReso/hSpResoFT0cFT0a"), centrality, xQVecFT0c * xQVecFT0a + yQVecFT0c * yQVecFT0a); registry.fill(HIST("spReso/hSpResoFT0cFV0a"), centrality, xQVecFT0c * xQVecFV0a + yQVecFT0c * yQVecFV0a); registry.fill(HIST("spReso/hSpResoFT0cTPCpos"), centrality, xQVecFT0c * xQVecBPos + yQVecFT0c * yQVecBPos); registry.fill(HIST("spReso/hSpResoFT0cTPCneg"), centrality, xQVecFT0c * xQVecBNeg + yQVecFT0c * yQVecBNeg); + registry.fill(HIST("spReso/hSpResoFT0cTPCtot"), centrality, xQVecFT0c * xQVecBTot + yQVecFT0c * yQVecBTot); registry.fill(HIST("spReso/hSpResoFT0aFV0a"), centrality, xQVecFT0a * xQVecFV0a + yQVecFT0a * yQVecFV0a); registry.fill(HIST("spReso/hSpResoFT0aTPCpos"), centrality, xQVecFT0a * xQVecBPos + yQVecFT0a * yQVecBPos); registry.fill(HIST("spReso/hSpResoFT0aTPCneg"), centrality, xQVecFT0a * xQVecBNeg + yQVecFT0a * yQVecBNeg); + registry.fill(HIST("spReso/hSpResoFT0aTPCtot"), centrality, xQVecFT0a * xQVecBTot + yQVecFT0a * yQVecBTot); registry.fill(HIST("spReso/hSpResoFT0mFV0a"), centrality, xQVecFT0m * xQVecFV0a + yQVecFT0m * yQVecFV0a); registry.fill(HIST("spReso/hSpResoFT0mTPCpos"), centrality, xQVecFT0m * xQVecBPos + yQVecFT0m * yQVecBPos); registry.fill(HIST("spReso/hSpResoFT0mTPCneg"), centrality, xQVecFT0m * xQVecBNeg + yQVecFT0m * yQVecBNeg); + registry.fill(HIST("spReso/hSpResoFT0mTPCtot"), centrality, xQVecFT0m * xQVecBTot + yQVecFT0m * yQVecBTot); registry.fill(HIST("spReso/hSpResoFV0aTPCpos"), centrality, xQVecFV0a * xQVecBPos + yQVecFV0a * yQVecBPos); registry.fill(HIST("spReso/hSpResoFV0aTPCneg"), centrality, xQVecFV0a * xQVecBNeg + yQVecFV0a * yQVecBNeg); + registry.fill(HIST("spReso/hSpResoFV0aTPCtot"), centrality, xQVecFV0a * xQVecBTot + yQVecFV0a * yQVecBTot); registry.fill(HIST("spReso/hSpResoTPCposTPCneg"), centrality, xQVecBPos * xQVecBNeg + yQVecBPos * yQVecBNeg); if (saveEpResoHisto) { @@ -526,21 +746,33 @@ struct HfTaskFlowCharmHadrons { float epFV0a = epHelper.GetEventPlane(xQVecFV0a, yQVecFV0a, harmonic); float epBPoss = epHelper.GetEventPlane(xQVecBPos, yQVecBPos, harmonic); float epBNegs = epHelper.GetEventPlane(xQVecBNeg, yQVecBNeg, harmonic); + float epBTots = epHelper.GetEventPlane(xQVecBTot, yQVecBTot, harmonic); registry.fill(HIST("epReso/hEpResoFT0cFT0a"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0c, epFT0a))); registry.fill(HIST("epReso/hEpResoFT0cFV0a"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0c, epFV0a))); registry.fill(HIST("epReso/hEpResoFT0cTPCpos"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0c, epBPoss))); registry.fill(HIST("epReso/hEpResoFT0cTPCneg"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0c, epBNegs))); + registry.fill(HIST("epReso/hEpResoFT0cTPCtot"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0c, epBTots))); registry.fill(HIST("epReso/hEpResoFT0aFV0a"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0a, epFV0a))); registry.fill(HIST("epReso/hEpResoFT0aTPCpos"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0a, epBPoss))); registry.fill(HIST("epReso/hEpResoFT0aTPCneg"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0a, epBNegs))); + registry.fill(HIST("epReso/hEpResoFT0aTPCtot"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0a, epBTots))); registry.fill(HIST("epReso/hEpResoFT0mFV0a"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0m, epFV0a))); registry.fill(HIST("epReso/hEpResoFT0mTPCpos"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0m, epBPoss))); registry.fill(HIST("epReso/hEpResoFT0mTPCneg"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0m, epBNegs))); + registry.fill(HIST("epReso/hEpResoFT0mTPCtot"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFT0m, epBTots))); registry.fill(HIST("epReso/hEpResoFV0aTPCpos"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFV0a, epBPoss))); registry.fill(HIST("epReso/hEpResoFV0aTPCneg"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFV0a, epBNegs))); + registry.fill(HIST("epReso/hEpResoFV0aTPCtot"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFV0a, epBTots))); registry.fill(HIST("epReso/hEpResoTPCposTPCneg"), centrality, std::cos(harmonic * getDeltaPsiInRange(epBPoss, epBNegs))); } + + if (storeEpCosSin) { + registry.fill(HIST("ep/hSparseEp"), centrality, + epHelper.GetEventPlane(xQVecFT0c, yQVecFT0c, harmonic), + std::cos(harmonic * epHelper.GetEventPlane(xQVecFT0c, yQVecFT0c, harmonic)), + std::sin(harmonic * epHelper.GetEventPlane(xQVecFT0c, yQVecFT0c, harmonic))); + } } PROCESS_SWITCH(HfTaskFlowCharmHadrons, processResolution, "Process resolution", false); diff --git a/PWGHF/D2H/Tasks/taskLb.cxx b/PWGHF/D2H/Tasks/taskLb.cxx index 788e9717be4..a2c0723bd4f 100644 --- a/PWGHF/D2H/Tasks/taskLb.cxx +++ b/PWGHF/D2H/Tasks/taskLb.cxx @@ -13,6 +13,9 @@ /// \brief Λb0 analysis task /// /// \author Panos Christakoglou , Nikhef +/// \author Martin Voelkl , University of Birmingham + +#include #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" @@ -32,35 +35,76 @@ using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; -void customize(std::vector& workflowOptions) -{ - ConfigParamSpec optionDoMC{"doMC", VariantType::Bool, true, {"Fill MC histograms."}}; - workflowOptions.push_back(optionDoMC); -} - #include "Framework/runDataProcessing.h" /// Λb0 analysis task struct HfTaskLb { - Configurable selectionFlagLb{"selectionFlagLb", 1, "Selection Flag for Lb"}; - Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen particle rapidity"}; - Configurable yCandRecoMax{"yCandRecoMax", 0.8, "max. cand. rapidity"}; + Configurable selectionFlagLb{"selectionFlagLb", 0, "Selection Flag for Lb"}; + Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen particle rapidity"}; + Configurable yCandRecoMax{"yCandRecoMax", 0.8, "max. cand. rapidity"}; + Configurable DCALengthParameter{"DCALengthParameter", 0.02, "decay length for DCA"}; + Configurable minLikelihoodRatio{"minLikelihoodRatio", 10., "min. likelihood ratio for combined DCAs"}; + Configurable minLikelihoodRatioLc{"minLikelihoodRatioLc", 10., "min. likelihood ratio for Lc cross check"}; + Configurable mDiffKStar892Max{"mDiffKStar892Max", 0.0473, "Accepted range around KStar mass peak"}; + Configurable mDiffDelta1232Max{"mDiffDelta1232Max", 0.117, "Accepted range around Delta mass peak"}; + Configurable mDiffLambda1520Max{"mDiffLambda1520Max", 0.016 * 2., "Accepted range around Lambda 1520 mass peak"}; + Configurable mDiffLcMax{"mDiffLcMax", 0.1, "Accepted range around LambdaC mass peak for filling two body mass histograms"}; + Configurable maximumImpactParameterForLambdaCCrossChecks{"maximumImpactParameterForLambdaCCrossChecks", 0.2, "maximum d0 for LambdaC checks"}; + Configurable resoCorrectionFactor{"resoCorrectionFactor", 1.1, "Resolution correction compared to reconstruction estimate"}; + Configurable largeLifetimeBG{"largeLifetimeBG", 0.01, "fraction of strange contribution within 2mm"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_lb_to_lc_pi::vecBinsPt}, "pT bin limits"}; HfHelper hfHelper; + Service pdg; Filter filterSelectCandidates = (aod::hf_sel_candidate_lb::isSelLbToLcPi >= selectionFlagLb); + using TracksWExt = soa::Join; + using TracksWExtMc = soa::Join; + + PresliceUnsorted McPartID = aod::mctracklabel::mcParticleId; + + bool passesImpactParameterResolution(float pT, float d0Resolution) + { + float expectedResolution(0.001 + 0.0052 * std::exp(-0.655 * pT)); + return (d0Resolution <= expectedResolution * 1.5); + } // Compares to pT dependent cut on impact parameter resolution + + float logLikelihoodRatioSingleTrackDCA(float DCA, float reso, float lengthParameter) + { + reso *= resoCorrectionFactor; // In case real resolution is worse + float numerator = 1. / lengthParameter * std::exp(-DCA / lengthParameter); + float denominator = (1. - largeLifetimeBG) * TMath::Gaus(DCA, 0., reso, true) + largeLifetimeBG / 0.2; // flat distribution to 2 mm + return std::log(numerator / denominator); + } // Creates the single track log likelihood assuming an exonential law for the secondaries + HistogramRegistry registry{ "registry", {{"hPtProng0", "Lb candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{1000, 0., 50.}}}}, {"hPtProng1", "Lb candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 10.}}}}, {"hPtCand", "Lb candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{1000, 0., 50.}}}}, - {"hCentrality", "centrality;centrality percentile;entries", {HistType::kTH1F, {{100, 0., 100.}}}}}}; + {"hIPs", "Impact parameters;p_{T} (GeV/#it{c});d_{0} (cm)", {HistType::kTH2F, {{20, 0., 20.}, {400, 0., 0.2}}}}, + {"hIPsAfterCut", "Impact parameters;p_{T} (GeV/#it{c});d_{0} (cm)", {HistType::kTH2F, {{20, 0., 20.}, {400, 0., 0.2}}}}, + {"hIPResolution", "Impact parameter resolution;p_{T} (GeV/#it{c});#sigma_{d_{0}} (cm)", {HistType::kTH2F, {{20, 0., 10.}, {400, 0., 0.02}}}}, + {"hPtlogLikelihood", "log Likelihood;p_{T} (GeV/#it{c});log L", {HistType::kTH2F, {{20, 0., 20.}, {400, -10., 70.}}}}, + {"hPtinvMassKStar", "K^{*}(892) invariant mass;p_{T} (GeV/#it{c});m_{inv}", {HistType::kTH2F, {{20, 0., 20.}, {400, 0.5, 1.5}}}}, + {"hPtinvMassDelta", "#Delta(1232) invariant mass;p_{T} (GeV/#it{c});m_{inv}", {HistType::kTH2F, {{20, 0., 20.}, {400, 1.0, 2.0}}}}, + {"hPtinvMassLambda1520", "#Lambda(1520) invariant maas;p_{T} (GeV/#it{c});m_{inv}", {HistType::kTH2F, {{20, 0., 20.}, {400, 1.0, 2.0}}}}, + {"hPtinvMassLcKStar", "#Lambda_{c} invariant mass from K^{*};p_{T} (GeV/#it{c});m_{inv}", {HistType::kTH2F, {{20, 0., 20.}, {400, 1.5, 3.5}}}}, + {"hPtinvMassLcDelta", "#Lambda_{c} invariant mass from #Delta;p_{T} (GeV/#it{c});m_{inv}", {HistType::kTH2F, {{20, 0., 20.}, {400, 1.5, 3.5}}}}, + {"hPtinvMassLcLambda1520", "#Lambda_{c} invariant mass from #Lambda;p_{T} (GeV/#it{c});m_{inv}", {HistType::kTH2F, {{20, 0., 20.}, {400, 1.5, 3.5}}}}, + {"hPtinvMassLc", "#Lambda_{c} invariant mass;p_{T} (GeV/#it{c});m_{inv}", {HistType::kTH2F, {{20, 0., 20.}, {400, 1.5, 3.5}}}}, + {"hPtinvMassLcReso", "#Lambda_{c} from resonances invariant mass;p_{T} (GeV/#it{c});m_{inv}", {HistType::kTH2F, {{20, 0., 20.}, {400, 1.5, 3.5}}}}, + {"hPtinvMassLb", "#Lambda_{b} invariant mass;p_{T} (GeV/#it{c});m_{inv}", {HistType::kTH2F, {{20, 0., 20.}, {400, 3.5, 7.5}}}}, + {"hZVertex", "z Vertex;z_{vtx};counts", {HistType::kTH1F, {{100, -20., 20.}}}}, + {"MC/hPtRecSig", "Lb candidates (matched);candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 30.}}}}, + {"MC/hPtRecBg", "Lb candidates (unmatched);candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 30.}}}}, + {"MC/hPtGenSig", "Lb candidates (matched);candidate #it{p}_{T}^{gen.} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 10.}}}}, + {"MC/hPtGen", "MC particles (matched);candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 30.}}}}}}; void init(InitContext&) { - registry.add("hMass", "#Lambda_{b}^{0} candidates;inv. mass #Lambda_{c}^{#plus}#pi^{#minus} (GeV/#it{c}^{2});#it{p}_{T} (GeV/#it{c}); centrality", {HistType::kTH3F, {{500, 0., 10.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}, {100, 0., 100.}}}); + registry.add("hMass", "#Lambda_{b}^{0} candidates;inv. mass #Lambda_{c}^{#plus}#pi^{#minus} (GeV/#it{c}^{2});#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{500, 0., 10.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("hDecLength", "#Lambda_{b}^{0} candidates;decay length (cm);entries", {HistType::kTH2F, {{200, 0., 0.4}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("hDecLengthXY", "#Lambda_{b}^{0} candidates;decay length xy (cm);entries", {HistType::kTH2F, {{200, 0., 0.4}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("hd0Prong0", "#Lambda_{b}^{0} candidates;prong 0 (#Lambda_{c}^{#plus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{100, -0.05, 0.05}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); @@ -73,28 +117,166 @@ struct HfTaskLb { registry.add("hDecLenXYErr", "#Lambda_{b}^{0} candidates;#Lambda_{b}^{0} candidate decay length xy error (cm);entries", {HistType::kTH2F, {{100, 0., 1.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("hIPProd", "#Lambda_{b}^{0} candidates;#Lambda_{b}^{0} candidate impact parameter product;entries", {HistType::kTH2F, {{100, -0.5, 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("hInvMassLc", "#Lambda_{b}^{0} candidates;prong0, #Lambda_{c}^{+} inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{500, 0, 5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + + // Now add MC histograms + registry.add("MC/hEtaGen", "MC particles (matched);#Lambda_{b}^{0} candidate #it{#eta}^{gen};entries", {HistType::kTH2F, {{100, -2., 2.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hYGen", "MC particles (matched);#Lambda_{b}^{0} candidate #it{y}^{gen};entries", {HistType::kTH2F, {{100, -2., 2.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hPtProng0Gen", "MC particles (matched);prong 0 (#Lambda_{c}^{+}) #it{p}_{T}^{gen} (GeV/#it{c});entries", {HistType::kTH2F, {{100, 0., 10.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hPtProng1Gen", "MC particles (matched);prong 1 (#pi^{-}) #it{p}_{T}^{gen} (GeV/#it{c});entries", {HistType::kTH2F, {{100, 0., 10.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hYProng0Gen", "MC particles (matched);prong 0 (#Lambda_{c}^{+}) #it{y}^{gen};entries", {HistType::kTH2F, {{100, -2, 2}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hYProng1Gen", "MC particles (matched);prong 1 (#pi^{-}) #it{y}^{gen};entries", {HistType::kTH2F, {{100, -2, 2}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hEtaProng0Gen", "MC particles (matched);prong 0 (#Lambda_{b}^{0}) #it{#eta}^{gen};entries", {HistType::kTH2F, {{100, -2, 2}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hEtaProng1Gen", "MC particles (matched);prong 1 (#pi^{-}) #it{#eta}^{gen};entries", {HistType::kTH2F, {{100, -2, 2}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hCPARecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate cosine of pointing angle;entries", {HistType::kTH2F, {{220, 0., 1.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hCPARecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate cosine of pointing angle;entries", {HistType::kTH2F, {{220, 0., 1.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hCPAxyRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate CPAxy;entries", {HistType::kTH2F, {{220, 0., 1.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hCPAxyRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate CPAxy;entries", {HistType::kTH2F, {{220, 0., 1.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hCPALcRecSig", "#Lambda_{b}^{0} candidates (matched);prong 0 (#Lambda_{c}^{+}) cosine of pointing angle;entries", {HistType::kTH2F, {{220, 0., 1.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hCPALcRecBg", "#Lambda_{b}^{0} candidates (unmatched);prong 0 (#Lambda_{c}^{+}) cosine of pointing angle;entries", {HistType::kTH2F, {{220, 0., 1.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hEtaRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hEtaRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hRapidityRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate #it{y};entries", {HistType::kTH2F, {{100, -2., 2.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hRapidityRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate #it{#y};entries", {HistType::kTH2F, {{100, -2., 2.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + + registry.add("MC/hPtProng0RecSig", "#Lambda_{b}^{0} candidates (matched);prong 0 (#Lambda_{c}^{+}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{100, 0., 10.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hPtProng1RecSig", "#Lambda_{b}^{0} candidates (matched);prong 1 (#pi^{#minus}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{100, 0., 10.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hPtProng0RecBg", "#Lambda_{b}^{0} candidates (unmatched);prong 0 (#Lambda_{c}^{+}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{100, 0., 10.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hPtProng1RecBg", "#Lambda_{b}^{0} candidates (unmatched);prong 1 (#pi^{#minus}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{100, 0., 10.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hMassRecSig", "#Lambda_{b}^{0} candidates (matched);inv. mass #Lambda_{c}^{+}#pi^{+} (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{300, 4.0, 7.00}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hMassRecBg", "#Lambda_{b}^{0} candidates (unmatched);inv. mass #Lambda_{c}^{+}#pi^{+} (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{300, 4.0, 7.0}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hd0Prong0RecSig", "#Lambda_{b}^{0} candidates (matched);prong 0 (#Lambda_{c}^{+}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{200, -0.05, 0.05}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hd0Prong1RecSig", "#Lambda_{b}^{0} candidates (matched);prong 1 (#pi^{#minus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{200, -0.05, 0.05}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hd0Prong0RecBg", "#Lambda_{b}^{0} candidates (unmatched);prong 0 (#Lambda_{c}^{+}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{200, -0.05, 0.05}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hd0Prong1RecBg", "#Lambda_{b}^{0} candidates (unmatched);prong 1 (#pi^{#minus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{200, -0.05, 0.05}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hDecLengthRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate decay length (cm);entries", {HistType::kTH2F, {{100, 0., 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hDecLengthXYRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate decay length xy (cm);entries", {HistType::kTH2F, {{100, 0., 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hDecLengthRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate decay length (cm);entries", {HistType::kTH2F, {{100, 0., 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hDecLengthXYRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate decay length xy(cm);entries", {HistType::kTH2F, {{100, 0., 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hDecLengthLcRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate decay length (cm);entries", {HistType::kTH2F, {{100, 0., 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hDecLengthLcRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate decay length (cm);entries", {HistType::kTH2F, {{100, 0., 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hDecLengthNormRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate decay length (cm);entries", {HistType::kTH2F, {{100, 0., 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hDecLengthNormRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate decay length (cm);entries", {HistType::kTH2F, {{100, 0., 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hImpParProdLbRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate impact parameter product ;entries", {HistType::kTH2F, {{100, -0.5, 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hImpParProdLbRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate impact parameter product ;entries", {HistType::kTH2F, {{100, -0.5, 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + + registry.add("MC/hChi2PCARecSig", "#Lambda_{b}^{0} candidates (matched);sum of distances of the secondary vertex to its prongs;entries", {HistType::kTH2F, {{240, -0.01, 0.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hChi2PCARecBg", "#Lambda_{b}^{0} candidates (unmatched);sum of distances of the secondary vertex to its prongs;entries", {HistType::kTH2F, {{240, -0.01, 0.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hThetaStarRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} #cos(#theta^{*});entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/hThetaStarRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} #cos(#theta^{*});entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); } - void process(soa::Join::iterator const& collision, - soa::Filtered> const& candidates, - soa::Join const&, - aod::Tracks const&) + void processData(aod::Collisions::iterator const& collision, + soa::Filtered> const& candidates, + soa::Join const& candidatesLc, + TracksWExt const&) { - float centrality = collision.centRun2V0M(); - registry.fill(HIST("hCentrality"), centrality); + float massKStar892 = 0.892; + float massDelta1232 = 1.232; + + for (const auto& candidateLc : candidatesLc) { + if (!candidateLc.isSelLcToPKPi() && !candidateLc.isSelLcToPiKP()) + continue; + auto track0 = candidateLc.prong0_as(); + auto track1 = candidateLc.prong1_as(); + auto track2 = candidateLc.prong2_as(); + registry.get(HIST("hIPs"))->Fill(candidateLc.pt(), candidateLc.impactParameter0()); + registry.get(HIST("hIPs"))->Fill(candidateLc.pt(), candidateLc.impactParameter1()); + registry.get(HIST("hIPs"))->Fill(candidateLc.pt(), candidateLc.impactParameter2()); + float reso0 = candidateLc.errorImpactParameter0(); // 0.0023166 *pow(track0.pt(), -0.788); + float reso1 = candidateLc.errorImpactParameter1(); + float reso2 = candidateLc.errorImpactParameter2(); + registry.get(HIST("hIPResolution"))->Fill(track0.pt(), reso0); + registry.get(HIST("hIPResolution"))->Fill(track1.pt(), reso1); + registry.get(HIST("hIPResolution"))->Fill(track2.pt(), reso2); + if (!passesImpactParameterResolution(track0.pt(), reso0)) + continue; + if (!passesImpactParameterResolution(track1.pt(), reso1)) + continue; + if (!passesImpactParameterResolution(track2.pt(), reso2)) + continue; + float DCA0 = candidateLc.impactParameter0(); + float DCA1 = candidateLc.impactParameter1(); + float DCA2 = candidateLc.impactParameter2(); + if (DCA0 > maximumImpactParameterForLambdaCCrossChecks || DCA1 > maximumImpactParameterForLambdaCCrossChecks || DCA2 > maximumImpactParameterForLambdaCCrossChecks) + continue; + float likelihoodRatio = logLikelihoodRatioSingleTrackDCA(DCA0, reso0, DCALengthParameter) + logLikelihoodRatioSingleTrackDCA(DCA1, reso1, DCALengthParameter) + logLikelihoodRatioSingleTrackDCA(DCA2, reso2, DCALengthParameter); + registry.get(HIST("hPtlogLikelihood"))->Fill(candidateLc.pt(), likelihoodRatio); + if (likelihoodRatio < minLikelihoodRatioLc) + continue; + registry.get(HIST("hIPsAfterCut"))->Fill(candidateLc.pt(), candidateLc.impactParameter0()); + registry.get(HIST("hIPsAfterCut"))->Fill(candidateLc.pt(), candidateLc.impactParameter1()); + registry.get(HIST("hIPsAfterCut"))->Fill(candidateLc.pt(), candidateLc.impactParameter2()); + if (candidateLc.isSelLcToPKPi()) { + registry.get(HIST("hPtinvMassLc"))->Fill(candidateLc.pt(), hfHelper.invMassLcToPKPi(candidateLc)); + float mRecoKstar = RecoDecay::m(std::array{track1.pVector(), track2.pVector()}, std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); + float mRecoDelta1232 = RecoDecay::m(std::array{track0.pVector(), track2.pVector()}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPiPlus}); + float mRecoLambda1520 = RecoDecay::m(std::array{track0.pVector(), track1.pVector()}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassKPlus}); + float mDiffKStar892 = std::abs(mRecoKstar - massKStar892); + float mDiffDelta1232 = std::abs(mRecoDelta1232 - massDelta1232); + float mDiffLambda1520 = std::abs(mRecoLambda1520 - o2::constants::physics::MassLambda1520); + if (mDiffKStar892 < mDiffKStar892Max || mDiffDelta1232 < mDiffDelta1232Max || mDiffLambda1520 < mDiffLambda1520Max) + registry.get(HIST("hPtinvMassLcReso"))->Fill(candidateLc.pt(), hfHelper.invMassLcToPKPi(candidateLc)); + if (mDiffKStar892 < mDiffKStar892Max) + registry.get(HIST("hPtinvMassLcKStar"))->Fill(candidateLc.pt(), hfHelper.invMassLcToPKPi(candidateLc)); + if (mDiffDelta1232 < mDiffDelta1232Max) + registry.get(HIST("hPtinvMassLcDelta"))->Fill(candidateLc.pt(), hfHelper.invMassLcToPKPi(candidateLc)); + if (mDiffLambda1520 < mDiffLambda1520Max) + registry.get(HIST("hPtinvMassLcLambda1520"))->Fill(candidateLc.pt(), hfHelper.invMassLcToPKPi(candidateLc)); + + if (std::abs(hfHelper.invMassLcToPKPi(candidateLc) - o2::constants::physics::MassLambdaCPlus) < mDiffLcMax) { + registry.get(HIST("hPtinvMassKStar"))->Fill(candidateLc.pt(), mRecoKstar); + registry.get(HIST("hPtinvMassDelta"))->Fill(candidateLc.pt(), mRecoDelta1232); + registry.get(HIST("hPtinvMassLambda1520"))->Fill(candidateLc.pt(), mRecoLambda1520); + } + } + if (candidateLc.isSelLcToPiKP()) { + registry.get(HIST("hPtinvMassLc"))->Fill(candidateLc.pt(), hfHelper.invMassLcToPiKP(candidateLc)); + float mRecoKstar = RecoDecay::m(std::array{track1.pVector(), track0.pVector()}, std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); + float mRecoDelta1232 = RecoDecay::m(std::array{track2.pVector(), track0.pVector()}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPiPlus}); + float mRecoLambda1520 = RecoDecay::m(std::array{track2.pVector(), track1.pVector()}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassKPlus}); + float mDiffKStar892 = std::abs(mRecoKstar - massKStar892); + float mDiffDelta1232 = std::abs(mRecoDelta1232 - massDelta1232); + float mDiffLambda1520 = std::abs(mRecoLambda1520 - o2::constants::physics::MassLambda1520); + if (mDiffKStar892 < mDiffKStar892Max || mDiffDelta1232 < mDiffDelta1232Max || mDiffLambda1520 < mDiffLambda1520Max) + registry.get(HIST("hPtinvMassLcReso"))->Fill(candidateLc.pt(), hfHelper.invMassLcToPiKP(candidateLc)); + if (mDiffKStar892 < mDiffKStar892Max) + registry.get(HIST("hPtinvMassLcKStar"))->Fill(candidateLc.pt(), hfHelper.invMassLcToPiKP(candidateLc)); + if (mDiffDelta1232 < mDiffDelta1232Max) + registry.get(HIST("hPtinvMassLcDelta"))->Fill(candidateLc.pt(), hfHelper.invMassLcToPiKP(candidateLc)); + if (mDiffLambda1520 < mDiffLambda1520Max) + registry.get(HIST("hPtinvMassLcLambda1520"))->Fill(candidateLc.pt(), hfHelper.invMassLcToPiKP(candidateLc)); + + if (std::abs(hfHelper.invMassLcToPiKP(candidateLc) - o2::constants::physics::MassLambdaCPlus) < mDiffLcMax) { + registry.get(HIST("hPtinvMassKStar"))->Fill(candidateLc.pt(), mRecoKstar); + registry.get(HIST("hPtinvMassDelta"))->Fill(candidateLc.pt(), mRecoDelta1232); + registry.get(HIST("hPtinvMassLambda1520"))->Fill(candidateLc.pt(), mRecoLambda1520); + } + } + } // Lambda_c candidates loop for cross checks for (const auto& candidate : candidates) { - if (!(candidate.hfflag() & 1 << hf_cand_lb::DecayType::LbToLcPi)) { + if (!(candidate.hfflag() & 1 << hf_cand_lb::DecayType::LbToLcPi)) { // This should never be true as the loop is over Lb candidates continue; } if (yCandRecoMax >= 0. && std::abs(hfHelper.yLb(candidate)) > yCandRecoMax) { continue; } + registry.get(HIST("hZVertex"))->Fill(collision.posZ()); auto candLc = candidate.prong0_as>(); - auto candPi = candidate.prong1(); - - registry.fill(HIST("hMass"), hfHelper.invMassLbToLcPi(candidate), candidate.pt(), centrality); + float d0resolution0 = candLc.errorImpactParameter0(); + float d0resolution1 = candLc.errorImpactParameter1(); + float d0resolution2 = candLc.errorImpactParameter2(); + float DCA0 = candLc.impactParameter0(); + float DCA1 = candLc.impactParameter1(); + float DCA2 = candLc.impactParameter2(); + float likelihoodRatio = logLikelihoodRatioSingleTrackDCA(DCA0, d0resolution0, DCALengthParameter) + logLikelihoodRatioSingleTrackDCA(DCA1, d0resolution1, DCALengthParameter) + logLikelihoodRatioSingleTrackDCA(DCA2, d0resolution2, DCALengthParameter); + if (likelihoodRatio < minLikelihoodRatio) + continue; // Larger likelihood means more likely to be signal + float lbMass = hfHelper.invMassLbToLcPi(candidate); + registry.get(HIST("hPtinvMassLb"))->Fill(candidate.pt(), lbMass); + + registry.fill(HIST("hMass"), hfHelper.invMassLbToLcPi(candidate), candidate.pt()); registry.fill(HIST("hPtCand"), candidate.pt()); registry.fill(HIST("hPtProng0"), candidate.ptProng0()); registry.fill(HIST("hPtProng1"), candidate.ptProng1()); @@ -110,84 +292,15 @@ struct HfTaskLb { registry.fill(HIST("hImpParErr"), candidate.errorImpactParameter1(), candidate.pt()); registry.fill(HIST("hDecLenErr"), candidate.errorDecayLength(), candidate.pt()); registry.fill(HIST("hDecLenXYErr"), candidate.errorDecayLengthXY(), candidate.pt()); - if (candPi.sign() < 0) { - registry.fill(HIST("hInvMassLc"), hfHelper.invMassLcToPKPi(candLc), candidate.pt()); - } + registry.fill(HIST("hInvMassLc"), lbMass, candidate.pt()); } // candidate loop - } // process -}; // struct - -/// Lb MC analysis and fill histograms -struct HfTaskLbMc { - Configurable selectionFlagLb{"selectionFlagLb", 1, "Selection Flag for Lb"}; - Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen particle rapidity"}; - Configurable yCandRecoMax{"yCandRecoMax", 0.8, "max. cand. rapidity"}; - Configurable> binsPt{"binsPt", std::vector{hf_cuts_lb_to_lc_pi::vecBinsPt}, "pT bin limits"}; - - Service pdg; - HfHelper hfHelper; - - Filter filterSelectCandidates = (aod::hf_sel_candidate_lb::isSelLbToLcPi >= selectionFlagLb); - - HistogramRegistry registry{ - "registry", - {{"hPtRecSig", "Lb candidates (matched);candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 30.}}}}, - {"hPtRecBg", "Lb candidates (unmatched);candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 30.}}}}, - {"hPtGenSig", "Lb candidates (matched);candidate #it{p}_{T}^{gen.} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 10.}}}}, - {"hPtGen", "MC particles (matched);candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 30.}}}}}}; - - void init(InitContext&) - { - registry.add("hEtaGen", "MC particles (matched);#Lambda_{b}^{0} candidate #it{#eta}^{gen};entries", {HistType::kTH2F, {{100, -2., 2.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hYGen", "MC particles (matched);#Lambda_{b}^{0} candidate #it{y}^{gen};entries", {HistType::kTH2F, {{100, -2., 2.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hPtProng0Gen", "MC particles (matched);prong 0 (#Lambda_{c}^{+}) #it{p}_{T}^{gen} (GeV/#it{c});entries", {HistType::kTH2F, {{100, 0., 10.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hPtProng1Gen", "MC particles (matched);prong 1 (#pi^{-}) #it{p}_{T}^{gen} (GeV/#it{c});entries", {HistType::kTH2F, {{100, 0., 10.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hYProng0Gen", "MC particles (matched);prong 0 (#Lambda_{c}^{+}) #it{y}^{gen};entries", {HistType::kTH2F, {{100, -2, 2}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hYProng1Gen", "MC particles (matched);prong 1 (#pi^{-}) #it{y}^{gen};entries", {HistType::kTH2F, {{100, -2, 2}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hEtaProng0Gen", "MC particles (matched);prong 0 (#Lambda_{b}^{0}) #it{#eta}^{gen};entries", {HistType::kTH2F, {{100, -2, 2}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hEtaProng1Gen", "MC particles (matched);prong 1 (#pi^{-}) #it{#eta}^{gen};entries", {HistType::kTH2F, {{100, -2, 2}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hCPARecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate cosine of pointing angle;entries", {HistType::kTH2F, {{220, 0., 1.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hCPARecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate cosine of pointing angle;entries", {HistType::kTH2F, {{220, 0., 1.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hCPAxyRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate CPAxy;entries", {HistType::kTH2F, {{220, 0., 1.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hCPAxyRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate CPAxy;entries", {HistType::kTH2F, {{220, 0., 1.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hCPALcRecSig", "#Lambda_{b}^{0} candidates (matched);prong 0 (#Lambda_{c}^{+}) cosine of pointing angle;entries", {HistType::kTH2F, {{220, 0., 1.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hCPALcRecBg", "#Lambda_{b}^{0} candidates (unmatched);prong 0 (#Lambda_{c}^{+}) cosine of pointing angle;entries", {HistType::kTH2F, {{220, 0., 1.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hEtaRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hEtaRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hRapidityRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate #it{y};entries", {HistType::kTH2F, {{100, -2., 2.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hRapidityRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate #it{#y};entries", {HistType::kTH2F, {{100, -2., 2.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - - registry.add("hPtProng0RecSig", "#Lambda_{b}^{0} candidates (matched);prong 0 (#Lambda_{c}^{+}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{100, 0., 10.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hPtProng1RecSig", "#Lambda_{b}^{0} candidates (matched);prong 1 (#pi^{#minus}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{100, 0., 10.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hPtProng0RecBg", "#Lambda_{b}^{0} candidates (unmatched);prong 0 (#Lambda_{c}^{+}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{100, 0., 10.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hPtProng1RecBg", "#Lambda_{b}^{0} candidates (unmatched);prong 1 (#pi^{#minus}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{100, 0., 10.}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hMassRecSig", "#Lambda_{b}^{0} candidates (matched);inv. mass #Lambda_{c}^{+}#pi^{+} (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{300, 4.0, 7.00}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hMassRecBg", "#Lambda_{b}^{0} candidates (unmatched);inv. mass #Lambda_{c}^{+}#pi^{+} (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{300, 4.0, 7.0}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hd0Prong0RecSig", "#Lambda_{b}^{0} candidates (matched);prong 0 (#Lambda_{c}^{+}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{200, -0.05, 0.05}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hd0Prong1RecSig", "#Lambda_{b}^{0} candidates (matched);prong 1 (#pi^{#minus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{200, -0.05, 0.05}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hd0Prong0RecBg", "#Lambda_{b}^{0} candidates (unmatched);prong 0 (#Lambda_{c}^{+}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{200, -0.05, 0.05}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hd0Prong1RecBg", "#Lambda_{b}^{0} candidates (unmatched);prong 1 (#pi^{#minus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{200, -0.05, 0.05}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hDecLengthRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate decay length (cm);entries", {HistType::kTH2F, {{100, 0., 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hDecLengthXYRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate decay length xy (cm);entries", {HistType::kTH2F, {{100, 0., 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hDecLengthRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate decay length (cm);entries", {HistType::kTH2F, {{100, 0., 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hDecLengthXYRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate decay length xy(cm);entries", {HistType::kTH2F, {{100, 0., 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hDecLengthLcRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate decay length (cm);entries", {HistType::kTH2F, {{100, 0., 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hDecLengthLcRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate decay length (cm);entries", {HistType::kTH2F, {{100, 0., 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hDecLengthNormRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate decay length (cm);entries", {HistType::kTH2F, {{100, 0., 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hDecLengthNormRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate decay length (cm);entries", {HistType::kTH2F, {{100, 0., 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hImpParProdLbRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} candidate impact parameter product ;entries", {HistType::kTH2F, {{100, -0.5, 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hImpParProdLbRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} candidate impact parameter product ;entries", {HistType::kTH2F, {{100, -0.5, 0.5}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - - registry.add("hChi2PCARecSig", "#Lambda_{b}^{0} candidates (matched);sum of distances of the secondary vertex to its prongs;entries", {HistType::kTH2F, {{240, -0.01, 0.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hChi2PCARecBg", "#Lambda_{b}^{0} candidates (unmatched);sum of distances of the secondary vertex to its prongs;entries", {HistType::kTH2F, {{240, -0.01, 0.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hThetaStarRecSig", "#Lambda_{b}^{0} candidates (matched);#Lambda_{b}^{0} #cos(#theta^{*});entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hThetaStarRecBg", "#Lambda_{b}^{0} candidates (unmatched);#Lambda_{b}^{0} #cos(#theta^{*});entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); } + PROCESS_SWITCH(HfTaskLb, processData, "Process Data", true); - void process(soa::Filtered> const& candidates, - soa::Join const& mcParticles, - aod::TracksWMc const&, - aod::HfCand3Prong const&) + void processMc(soa::Filtered> const& candidates, + soa::Join const& mcParticles, + TracksWExtMc const&, + aod::HfCand3Prong const&) { // MC rec for (const auto& candidate : candidates) { @@ -198,48 +311,49 @@ struct HfTaskLbMc { continue; } auto candLc = candidate.prong0_as(); + if (std::abs(candidate.flagMcMatchRec()) == 1 << hf_cand_lb::DecayType::LbToLcPi) { - auto indexMother = RecoDecay::getMother(mcParticles, candidate.prong1_as().mcParticle_as>(), o2::constants::physics::Pdg::kLambdaB0, true); + auto indexMother = RecoDecay::getMother(mcParticles, candidate.prong1_as().mcParticle_as>(), o2::constants::physics::Pdg::kLambdaB0, true); auto particleMother = mcParticles.rawIteratorAt(indexMother); - registry.fill(HIST("hPtGenSig"), particleMother.pt()); - registry.fill(HIST("hPtRecSig"), candidate.pt()); - registry.fill(HIST("hCPARecSig"), candidate.cpa(), candidate.pt()); - registry.fill(HIST("hCPAxyRecSig"), candidate.cpa(), candidate.pt()); - registry.fill(HIST("hEtaRecSig"), candidate.eta(), candidate.pt()); - registry.fill(HIST("hRapidityRecSig"), hfHelper.yLb(candidate), candidate.pt()); - registry.fill(HIST("hDecLengthRecSig"), candidate.decayLength(), candidate.pt()); - registry.fill(HIST("hDecLengthXYRecSig"), candidate.decayLengthXY(), candidate.pt()); - registry.fill(HIST("hMassRecSig"), hfHelper.invMassLbToLcPi(candidate), candidate.pt()); - registry.fill(HIST("hd0Prong0RecSig"), candidate.impactParameter0(), candidate.pt()); - registry.fill(HIST("hd0Prong1RecSig"), candidate.impactParameter1(), candidate.pt()); - registry.fill(HIST("hPtProng0RecSig"), candidate.ptProng0(), candidate.pt()); - registry.fill(HIST("hPtProng1RecSig"), candidate.ptProng1(), candidate.pt()); - registry.fill(HIST("hImpParProdLbRecSig"), candidate.impactParameterProduct(), candidate.pt()); - registry.fill(HIST("hDecLengthNormRecSig"), candidate.decayLengthXYNormalised(), candidate.pt()); - registry.fill(HIST("hCPALcRecSig"), candLc.cpa(), candidate.pt()); - registry.fill(HIST("hDecLengthLcRecSig"), candLc.decayLength(), candidate.pt()); - registry.fill(HIST("hChi2PCARecSig"), candidate.chi2PCA(), candidate.pt()); - // registry.fill(HIST("hThetaStarRecSig"), candidate.cosThetaStar(), candidate.pt()); + registry.fill(HIST("MC/hPtGenSig"), particleMother.pt()); + registry.fill(HIST("MC/hPtRecSig"), candidate.pt()); + registry.fill(HIST("MC/hCPARecSig"), candidate.cpa(), candidate.pt()); + registry.fill(HIST("MC/hCPAxyRecSig"), candidate.cpa(), candidate.pt()); + registry.fill(HIST("MC/hEtaRecSig"), candidate.eta(), candidate.pt()); + registry.fill(HIST("MC/hRapidityRecSig"), hfHelper.yLb(candidate), candidate.pt()); + registry.fill(HIST("MC/hDecLengthRecSig"), candidate.decayLength(), candidate.pt()); + registry.fill(HIST("MC/hDecLengthXYRecSig"), candidate.decayLengthXY(), candidate.pt()); + registry.fill(HIST("MC/hMassRecSig"), hfHelper.invMassLbToLcPi(candidate), candidate.pt()); + registry.fill(HIST("MC/hd0Prong0RecSig"), candidate.impactParameter0(), candidate.pt()); + registry.fill(HIST("MC/hd0Prong1RecSig"), candidate.impactParameter1(), candidate.pt()); + registry.fill(HIST("MC/hPtProng0RecSig"), candidate.ptProng0(), candidate.pt()); + registry.fill(HIST("MC/hPtProng1RecSig"), candidate.ptProng1(), candidate.pt()); + registry.fill(HIST("MC/hImpParProdLbRecSig"), candidate.impactParameterProduct(), candidate.pt()); + registry.fill(HIST("MC/hDecLengthNormRecSig"), candidate.decayLengthXYNormalised(), candidate.pt()); + registry.fill(HIST("MC/hCPALcRecSig"), candLc.cpa(), candidate.pt()); + registry.fill(HIST("MC/hDecLengthLcRecSig"), candLc.decayLength(), candidate.pt()); + registry.fill(HIST("MC/hChi2PCARecSig"), candidate.chi2PCA(), candidate.pt()); + // registry.fill(HIST("MC/hThetaStarRecSig"), candidate.cosThetaStar(), candidate.pt()); } else { - registry.fill(HIST("hPtRecBg"), candidate.pt()); - registry.fill(HIST("hCPARecBg"), candidate.cpa(), candidate.pt()); - registry.fill(HIST("hCPAxyRecBg"), candidate.cpa(), candidate.pt()); - registry.fill(HIST("hEtaRecBg"), candidate.eta(), candidate.pt()); - registry.fill(HIST("hRapidityRecBg"), hfHelper.yLb(candidate), candidate.pt()); - registry.fill(HIST("hDecLengthRecBg"), candidate.decayLength(), candidate.pt()); - registry.fill(HIST("hDecLengthXYRecBg"), candidate.decayLengthXY(), candidate.pt()); - registry.fill(HIST("hMassRecBg"), hfHelper.invMassLbToLcPi(candidate), candidate.pt()); - registry.fill(HIST("hd0Prong0RecBg"), candidate.impactParameter0(), candidate.pt()); - registry.fill(HIST("hd0Prong1RecBg"), candidate.impactParameter1(), candidate.pt()); - registry.fill(HIST("hPtProng0RecBg"), candidate.ptProng0(), candidate.pt()); - registry.fill(HIST("hPtProng1RecBg"), candidate.ptProng1(), candidate.pt()); - registry.fill(HIST("hImpParProdLbRecBg"), candidate.impactParameterProduct(), candidate.pt()); - registry.fill(HIST("hDecLengthNormRecBg"), candidate.decayLengthXYNormalised(), candidate.pt()); - registry.fill(HIST("hCPALcRecBg"), candLc.cpa(), candidate.pt()); - registry.fill(HIST("hDecLengthLcRecBg"), candLc.decayLength(), candidate.pt()); - registry.fill(HIST("hChi2PCARecBg"), candidate.chi2PCA(), candidate.pt()); - // registry.fill(HIST("hThetaStarRecBg"), candidate.cosThetaStar(), candidate.pt()); + registry.fill(HIST("MC/hPtRecBg"), candidate.pt()); + registry.fill(HIST("MC/hCPARecBg"), candidate.cpa(), candidate.pt()); + registry.fill(HIST("MC/hCPAxyRecBg"), candidate.cpa(), candidate.pt()); + registry.fill(HIST("MC/hEtaRecBg"), candidate.eta(), candidate.pt()); + registry.fill(HIST("MC/hRapidityRecBg"), hfHelper.yLb(candidate), candidate.pt()); + registry.fill(HIST("MC/hDecLengthRecBg"), candidate.decayLength(), candidate.pt()); + registry.fill(HIST("MC/hDecLengthXYRecBg"), candidate.decayLengthXY(), candidate.pt()); + registry.fill(HIST("MC/hMassRecBg"), hfHelper.invMassLbToLcPi(candidate), candidate.pt()); + registry.fill(HIST("MC/hd0Prong0RecBg"), candidate.impactParameter0(), candidate.pt()); + registry.fill(HIST("MC/hd0Prong1RecBg"), candidate.impactParameter1(), candidate.pt()); + registry.fill(HIST("MC/hPtProng0RecBg"), candidate.ptProng0(), candidate.pt()); + registry.fill(HIST("MC/hPtProng1RecBg"), candidate.ptProng1(), candidate.pt()); + registry.fill(HIST("MC/hImpParProdLbRecBg"), candidate.impactParameterProduct(), candidate.pt()); + registry.fill(HIST("MC/hDecLengthNormRecBg"), candidate.decayLengthXYNormalised(), candidate.pt()); + registry.fill(HIST("MC/hCPALcRecBg"), candLc.cpa(), candidate.pt()); + registry.fill(HIST("MC/hDecLengthLcRecBg"), candLc.decayLength(), candidate.pt()); + registry.fill(HIST("MC/hChi2PCARecBg"), candidate.chi2PCA(), candidate.pt()); + // registry.fill(HIST("MC/hThetaStarRecBg"), candidate.cosThetaStar(), candidate.pt()); } } // rec @@ -254,38 +368,33 @@ struct HfTaskLbMc { float ptProngs[2], yProngs[2], etaProngs[2]; int counter = 0; - for (const auto& daught : particle.daughters_as()) { + for (const auto& daught : particle.daughters_as>()) { ptProngs[counter] = daught.pt(); etaProngs[counter] = daught.eta(); yProngs[counter] = RecoDecay::y(daught.pVector(), pdg->Mass(daught.pdgCode())); counter++; } - registry.fill(HIST("hPtProng0Gen"), ptProngs[0], particle.pt()); - registry.fill(HIST("hPtProng1Gen"), ptProngs[1], particle.pt()); - registry.fill(HIST("hYProng0Gen"), yProngs[0], particle.pt()); - registry.fill(HIST("hYProng1Gen"), yProngs[1], particle.pt()); - registry.fill(HIST("hEtaProng0Gen"), etaProngs[0], particle.pt()); - registry.fill(HIST("hEtaProng1Gen"), etaProngs[1], particle.pt()); + registry.fill(HIST("MC/hPtProng0Gen"), ptProngs[0], particle.pt()); + registry.fill(HIST("MC/hPtProng1Gen"), ptProngs[1], particle.pt()); + registry.fill(HIST("MC/hYProng0Gen"), yProngs[0], particle.pt()); + registry.fill(HIST("MC/hYProng1Gen"), yProngs[1], particle.pt()); + registry.fill(HIST("MC/hEtaProng0Gen"), etaProngs[0], particle.pt()); + registry.fill(HIST("MC/hEtaProng1Gen"), etaProngs[1], particle.pt()); // if (yCandMax >= 0. && (std::abs(yProngs[0]) > yCandMax || std::abs(yProngs[1]) > yCandMax)) // continue; - registry.fill(HIST("hPtGen"), particle.pt()); - registry.fill(HIST("hYGen"), yParticle, particle.pt()); - registry.fill(HIST("hEtaGen"), particle.eta(), particle.pt()); + registry.fill(HIST("MC/hPtGen"), particle.pt()); + registry.fill(HIST("MC/hYGen"), yParticle, particle.pt()); + registry.fill(HIST("MC/hEtaGen"), particle.eta(), particle.pt()); } } // gen - } // process -}; // struct + } + PROCESS_SWITCH(HfTaskLb, processMc, "Process MC", false); +}; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - WorkflowSpec workflow{}; - const bool doMC = cfgc.options().get("doMC"); - workflow.push_back(adaptAnalysisTask(cfgc)); - if (doMC) { - workflow.push_back(adaptAnalysisTask(cfgc)); - } - return workflow; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGHF/D2H/Tasks/taskLc.cxx b/PWGHF/D2H/Tasks/taskLc.cxx index 842c4b18e11..be75dc055bf 100644 --- a/PWGHF/D2H/Tasks/taskLc.cxx +++ b/PWGHF/D2H/Tasks/taskLc.cxx @@ -18,19 +18,25 @@ /// \author Annalena Kalteyer , GSI Darmstadt /// \author Biao Zhang , Heidelberg University +#include // std::vector + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsEvSelHf.h" using namespace o2; using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::hf_centrality; +using namespace o2::hf_occupancy; /// Λc± → p± K∓ π± analysis task struct HfTaskLc { @@ -39,26 +45,44 @@ struct HfTaskLc { Configurable yCandRecoMax{"yCandRecoMax", 0.8, "max. cand. rapidity"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_lc_to_p_k_pi::vecBinsPt}, "pT bin limits"}; // ThnSparse for ML outputScores and Vars - Configurable enableTHn{"enableTHn", false, "enable THn for Lc"}; + Configurable fillTHn{"fillTHn", false, "fill THn"}; + Configurable storeOccupancy{"storeOccupancy", true, "Flag to store occupancy information"}; + Configurable occEstimator{"occEstimator", 2, "Occupancy estimation (None: 0, ITS: 1, FT0C: 2)"}; + + HfHelper hfHelper; + SliceCache cache; + + using Collisions = soa::Join; + using CollisionsMc = soa::Join; + using CollisionsWithFT0C = soa::Join; + using CollisionsMcWithFT0C = soa::Join; + using CollisionsWithFT0M = soa::Join; + using CollisionsMcWithFT0M = soa::Join; + + using LcCandidates = soa::Filtered>; + using LcCandidatesMl = soa::Filtered>; + + using LcCandidatesMc = soa::Filtered>; + using LcCandidatesMlMc = soa::Filtered>; + using McParticles3ProngMatched = soa::Join; + Filter filterSelectCandidates = aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLc || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLc; + Preslice candLcPerCollision = aod::hf_cand::collisionId; + PresliceUnsorted colPerMcCollision = aod::mcparticle::mcCollisionId; + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {72, 0, 36}, ""}; ConfigurableAxis thnConfigAxisMass{"thnConfigAxisMass", {300, 1.98, 2.58}, ""}; ConfigurableAxis thnConfigAxisPtProng{"thnConfigAxisPtProng", {100, 0, 20}, ""}; - ConfigurableAxis thnConfigAxisMultiplicity{"thnConfigAxisMultiplicity", {100, 0, 1000}, ""}; + ConfigurableAxis thnConfigAxisCentrality{"thnConfigAxisCentrality", {100, 0, 100}, ""}; ConfigurableAxis thnConfigAxisChi2PCA{"thnConfigAxisChi2PCA", {100, 0, 20}, ""}; ConfigurableAxis thnConfigAxisDecLength{"thnConfigAxisDecLength", {10, 0, 0.05}, ""}; ConfigurableAxis thnConfigAxisCPA{"thnConfigAxisCPA", {20, 0.8, 1}, ""}; ConfigurableAxis thnConfigAxisBdtScoreBkg{"thnConfigAxisBdtScoreBkg", {1000, 0., 1.}, ""}; ConfigurableAxis thnConfigAxisBdtScoreSignal{"thnConfigAxisBdtScoreSignal", {100, 0., 1.}, ""}; ConfigurableAxis thnConfigAxisCanType{"thnConfigAxisCanType", {5, 0., 5.}, ""}; - - HfHelper hfHelper; - Filter filterSelectCandidates = aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLc || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLc; - - using LcCandidates = soa::Filtered>; - using LcCandidatesMl = soa::Filtered>; - - using LcCandidatesMc = soa::Filtered>; - using LcCandidatesMlMc = soa::Filtered>; + ConfigurableAxis thnAxisRapidity{"thnAxisRapidity", {20, -1, 1}, "Cand. rapidity bins"}; + ConfigurableAxis thnConfigAxisGenPtB{"thnConfigAxisGenPtB", {1000, 0, 100}, "Gen Pt B"}; + ConfigurableAxis thnConfigAxisNumPvContr{"thnConfigAxisNumPvContr", {200, -0.5, 199.5}, "Number of PV contributors"}; + ConfigurableAxis thnConfigAxisOccupancy{"thnConfigAxisOccupancy", {14, 0, 14000}, "axis for centrality"}; HistogramRegistry registry{ "registry", @@ -88,7 +112,6 @@ struct HfTaskLc { {"MC/reconstructed/signal/hPtRecProng2Sig", "3-prong candidates (matched);prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, {"MC/reconstructed/prompt/hPtRecProng2SigPrompt", "3-prong candidates (matched, prompt);prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, {"MC/reconstructed/nonprompt/hPtRecProng2SigNonPrompt", "3-prong candidates (matched, non-prompt);prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"Data/hMultiplicity", "multiplicity;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}}, /// DCAxy to prim. vertex prongs {"Data/hd0Prong0", "3-prong candidates;prong 0 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}}, {"MC/reconstructed/signal/hd0RecProng0Sig", "3-prong candidates (matched);prong 0 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}}, @@ -154,14 +177,14 @@ struct HfTaskLc { void init(InitContext&) { - std::array doprocess{doprocessDataStd, doprocessDataWithMl, doprocessMcStd, doprocessMcWithMl}; + std::array doprocess{doprocessDataStd, doprocessDataStdWithFT0C, doprocessDataStdWithFT0M, doprocessDataWithMl, doprocessDataWithMlWithFT0C, doprocessDataWithMlWithFT0M, doprocessMcStd, doprocessMcStdWithFT0C, doprocessMcStdWithFT0M, doprocessMcWithMl, doprocessMcWithMlWithFT0C, doprocessMcWithMlWithFT0M}; if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { LOGP(fatal, "no or more than one process function enabled! Please check your configuration!"); } auto vbins = (std::vector)binsPt; /// mass candidate - registry.add("Data/hMassVsPtVsMult", "3-prong candidates;inv. mass (p K #pi) (GeV/#it{c}^{2}); p_{T}; multiplicity", {HistType::kTH3F, {{600, 1.98, 2.58}, {vbins, "#it{p}_{T} (GeV/#it{c})"}, {5000, 0., 10000.}}}); + registry.add("Data/hMassVsPtVsNPvContributors", "3-prong candidates;inv. mass (p K #pi) (GeV/#it{c}^{2}); p_{T}; Number of PV contributors", {HistType::kTH3F, {{600, 1.98, 2.58}, {vbins, "#it{p}_{T} (GeV/#it{c})"}, {5000, 0., 10000.}}}); registry.add("Data/hMassVsPt", "3-prong candidates;inv. mass (p K #pi) (GeV/#it{c}^{2}); p_{T}", {HistType::kTH2F, {{600, 1.98, 2.58}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("MC/reconstructed/signal/hMassVsPtRecSig", "3-prong candidates (matched);inv. mass (p K #pi) (GeV/#it{c}^{2}); p_{T}", {HistType::kTH2F, {{600, 1.98, 2.58}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("MC/reconstructed/prompt/hMassVsPtRecSigPrompt", "3-prong candidates (matched, prompt);inv. mass (p K #pi) (GeV/#it{c}^{2}); p_{T}", {HistType::kTH2F, {{600, 1.98, 2.58}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); @@ -259,13 +282,13 @@ struct HfTaskLc { registry.add("MC/reconstructed/prompt/hDecLenErrSigPrompt", "3-prong candidates (matched, prompt);decay length error (cm);entries", {HistType::kTH2F, {{100, 0., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("MC/reconstructed/nonprompt/hDecLenErrSigNonPrompt", "3-prong candidates (matched, non-prompt);decay length error (cm);entries", {HistType::kTH2F, {{100, 0., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - if (enableTHn) { + if (fillTHn) { const AxisSpec thnAxisMass{thnConfigAxisMass, "inv. mass (p K #pi) (GeV/#it{c}^{2})"}; const AxisSpec thnAxisPt{thnConfigAxisPt, "#it{p}_{T}(#Lambda_{c}^{+}) (GeV/#it{c})"}; const AxisSpec thnAxisPtProng0{thnConfigAxisPtProng, "#it{p}_{T}(prong0) (GeV/#it{c})"}; const AxisSpec thnAxisPtProng1{thnConfigAxisPtProng, "#it{p}_{T}(prong1) (GeV/#it{c})"}; const AxisSpec thnAxisPtProng2{thnConfigAxisPtProng, "#it{p}_{T}(prong2) (GeV/#it{c})"}; - const AxisSpec thnAxisMultiplicity{thnConfigAxisMultiplicity, "multiplicity"}; + const AxisSpec thnAxisCentrality{thnConfigAxisCentrality, "centrality (FT0C)"}; const AxisSpec thnAxisChi2PCA{thnConfigAxisChi2PCA, "Chi2PCA to sec. vertex (cm)"}; const AxisSpec thnAxisDecLength{thnConfigAxisDecLength, "decay length (cm)"}; const AxisSpec thnAxisCPA{thnConfigAxisCPA, "cosine of pointing angle"}; @@ -273,158 +296,76 @@ struct HfTaskLc { const AxisSpec thnAxisBdtScoreLcPrompt{thnConfigAxisBdtScoreSignal, "BDT prompt score (Lc)"}; const AxisSpec thnAxisBdtScoreLcNonPrompt{thnConfigAxisBdtScoreSignal, "BDT non-prompt score (Lc)"}; const AxisSpec thnAxisCanType{thnConfigAxisCanType, "candidates type"}; + const AxisSpec thnAxisY{thnAxisRapidity, "rapidity"}; + const AxisSpec thnAxisPtB{thnConfigAxisGenPtB, "#it{p}_{T}^{B} (GeV/#it{c})"}; + const AxisSpec thnAxisTracklets{thnConfigAxisNumPvContr, "Number of PV contributors"}; + const AxisSpec thnAxisOccupancy{thnConfigAxisOccupancy, "Occupancy"}; - if (doprocessDataWithMl || doprocessMcWithMl) { - registry.add("hnLcVarsWithBdt", "THn for Lambdac candidates with BDT scores", HistType::kTHnSparseF, {thnAxisMass, thnAxisPt, thnAxisMultiplicity, thnAxisBdtScoreLcBkg, thnAxisBdtScoreLcPrompt, thnAxisBdtScoreLcNonPrompt, thnAxisCanType}); - } else { - registry.add("hnLcVars", "THn for Lambdac candidates", HistType::kTHnSparseF, {thnAxisMass, thnAxisPt, thnAxisMultiplicity, thnAxisPtProng0, thnAxisPtProng1, thnAxisPtProng2, thnAxisChi2PCA, thnAxisDecLength, thnAxisCPA, thnAxisCanType}); - } - } - } + bool isDataWithMl = doprocessDataWithMl || doprocessDataWithMlWithFT0C || doprocessDataWithMlWithFT0M; + bool isMcWithMl = doprocessMcWithMl || doprocessMcWithMlWithFT0C || doprocessMcWithMlWithFT0M; + bool isDataStd = doprocessDataStd || doprocessDataStdWithFT0C || doprocessDataStdWithFT0M; + bool isMcStd = doprocessMcStd || doprocessMcStdWithFT0C || doprocessMcStdWithFT0M; - template - void processData(aod::Collision const& collision, - CandType const& candidates, - aod::TracksWDca const& tracks) - { - int nTracks = 0; - if (collision.numContrib() > 1) { - for (const auto& track : tracks) { - if (std::abs(track.eta()) > 4.0) { - continue; - } - if (std::abs(track.dcaXY()) > 0.0025 || std::abs(track.dcaZ()) > 0.0025) { - continue; - } - nTracks++; - } - } - registry.fill(HIST("Data/hMultiplicity"), nTracks); + std::vector axesStd, axesWithBdt, axesGen; - for (const auto& candidate : candidates) { - if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) { - continue; + if (isDataStd) { + axesStd = {thnAxisMass, thnAxisPt, thnAxisCentrality, thnAxisPtProng0, thnAxisPtProng1, thnAxisPtProng2, thnAxisChi2PCA, thnAxisDecLength, thnAxisCPA, thnAxisTracklets}; } - if (yCandRecoMax >= 0. && std::abs(hfHelper.yLc(candidate)) > yCandRecoMax) { - continue; + if (isMcStd) { + axesStd = {thnAxisMass, thnAxisPt, thnAxisCentrality, thnAxisPtProng0, thnAxisPtProng1, thnAxisPtProng2, thnAxisChi2PCA, thnAxisDecLength, thnAxisCPA, thnAxisTracklets, thnAxisPtB, thnAxisCanType}; } - auto pt = candidate.pt(); - auto ptProng0 = candidate.ptProng0(); - auto ptProng1 = candidate.ptProng1(); - auto ptProng2 = candidate.ptProng2(); - auto decayLength = candidate.decayLength(); - auto decayLengthXY = candidate.decayLengthXY(); - auto chi2PCA = candidate.chi2PCA(); - auto cpa = candidate.cpa(); - auto cpaXY = candidate.cpaXY(); - - if (candidate.isSelLcToPKPi() >= selectionFlagLc) { - registry.fill(HIST("Data/hMass"), hfHelper.invMassLcToPKPi(candidate)); - registry.fill(HIST("Data/hMassVsPtVsMult"), hfHelper.invMassLcToPKPi(candidate), pt, nTracks); - registry.fill(HIST("Data/hMassVsPt"), hfHelper.invMassLcToPKPi(candidate), pt); + if (isMcStd || isMcWithMl) { + axesGen = {thnAxisPt, thnAxisCentrality, thnAxisY, thnAxisTracklets, thnAxisPtB, thnAxisCanType}; } - if (candidate.isSelLcToPiKP() >= selectionFlagLc) { - registry.fill(HIST("Data/hMass"), hfHelper.invMassLcToPiKP(candidate)); - registry.fill(HIST("Data/hMassVsPtVsMult"), hfHelper.invMassLcToPiKP(candidate), pt, nTracks); - registry.fill(HIST("Data/hMassVsPt"), hfHelper.invMassLcToPiKP(candidate), pt); + if (isDataWithMl) { + axesWithBdt = {thnAxisMass, thnAxisPt, thnAxisCentrality, thnAxisBdtScoreLcBkg, thnAxisBdtScoreLcPrompt, thnAxisBdtScoreLcNonPrompt, thnAxisTracklets}; + } + if (isMcWithMl) { + axesWithBdt = {thnAxisMass, thnAxisPt, thnAxisCentrality, thnAxisBdtScoreLcBkg, thnAxisBdtScoreLcPrompt, thnAxisBdtScoreLcNonPrompt, thnAxisTracklets, thnAxisPtB, thnAxisCanType}; } - registry.fill(HIST("Data/hPt"), pt); - registry.fill(HIST("Data/hPtProng0"), ptProng0); - registry.fill(HIST("Data/hPtProng1"), ptProng1); - registry.fill(HIST("Data/hPtProng2"), ptProng2); - registry.fill(HIST("Data/hd0Prong0"), candidate.impactParameter0()); - registry.fill(HIST("Data/hd0Prong1"), candidate.impactParameter1()); - registry.fill(HIST("Data/hd0Prong2"), candidate.impactParameter2()); - registry.fill(HIST("Data/hd0VsPtProng0"), candidate.impactParameter0(), pt); - registry.fill(HIST("Data/hd0VsPtProng1"), candidate.impactParameter1(), pt); - registry.fill(HIST("Data/hd0VsPtProng2"), candidate.impactParameter2(), pt); - registry.fill(HIST("Data/hDecLength"), decayLength); - registry.fill(HIST("Data/hDecLengthVsPt"), decayLength, pt); - registry.fill(HIST("Data/hDecLengthxy"), decayLengthXY); - registry.fill(HIST("Data/hDecLengthxyVsPt"), decayLengthXY, pt); - registry.fill(HIST("Data/hCt"), hfHelper.ctLc(candidate)); - registry.fill(HIST("Data/hCtVsPt"), hfHelper.ctLc(candidate), pt); - registry.fill(HIST("Data/hCPA"), cpa); - registry.fill(HIST("Data/hCPAVsPt"), cpa, pt); - registry.fill(HIST("Data/hCPAxy"), cpaXY); - registry.fill(HIST("Data/hCPAxyVsPt"), cpaXY, pt); - registry.fill(HIST("Data/hDca2"), chi2PCA); - registry.fill(HIST("Data/hDca2VsPt"), chi2PCA, pt); - registry.fill(HIST("Data/hEta"), candidate.eta()); - registry.fill(HIST("Data/hEtaVsPt"), candidate.eta(), pt); - registry.fill(HIST("Data/hPhi"), candidate.phi()); - registry.fill(HIST("Data/hPhiVsPt"), candidate.phi(), pt); - registry.fill(HIST("hSelectionStatus"), candidate.isSelLcToPKPi(), pt); - registry.fill(HIST("hSelectionStatus"), candidate.isSelLcToPiKP(), pt); - registry.fill(HIST("Data/hImpParErrProng0"), candidate.errorImpactParameter0(), pt); - registry.fill(HIST("Data/hImpParErrProng1"), candidate.errorImpactParameter1(), pt); - registry.fill(HIST("Data/hImpParErrProng2"), candidate.errorImpactParameter2(), pt); - registry.fill(HIST("Data/hDecLenErr"), candidate.errorDecayLength(), pt); - - if (enableTHn) { - double massLc(-1); - double outputBkg(-1), outputPrompt(-1), outputFD(-1); - if (candidate.isSelLcToPKPi() >= selectionFlagLc) { - massLc = hfHelper.invMassLcToPKPi(candidate); - - if constexpr (fillMl) { - - if (candidate.mlProbLcToPKPi().size() == 3) { - - outputBkg = candidate.mlProbLcToPKPi()[0]; /// bkg score - outputPrompt = candidate.mlProbLcToPKPi()[1]; /// prompt score - outputFD = candidate.mlProbLcToPKPi()[2]; /// non-prompt score - } - /// Fill the ML outputScores and variables of candidate - registry.get(HIST("hnLcVarsWithBdt"))->Fill(massLc, pt, nTracks, outputBkg, outputPrompt, outputFD, 0); - } else { - registry.get(HIST("hnLcVars"))->Fill(massLc, pt, nTracks, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, 0); - } - } - if (candidate.isSelLcToPiKP() >= selectionFlagLc) { - massLc = hfHelper.invMassLcToPiKP(candidate); - - if constexpr (fillMl) { - if (candidate.mlProbLcToPiKP().size() == 3) { + if (storeOccupancy) { + if (!axesWithBdt.empty()) + axesWithBdt.push_back(thnAxisOccupancy); + if (!axesStd.empty()) + axesStd.push_back(thnAxisOccupancy); + if (!axesGen.empty()) + axesGen.push_back(thnAxisOccupancy); + } - outputBkg = candidate.mlProbLcToPiKP()[0]; /// bkg score - outputPrompt = candidate.mlProbLcToPiKP()[1]; /// prompt score - outputFD = candidate.mlProbLcToPiKP()[2]; /// non-prompt score - } - /// Fill the ML outputScores and variables of candidate - registry.get(HIST("hnLcVarsWithBdt"))->Fill(massLc, pt, nTracks, outputBkg, outputPrompt, outputFD, 0); - } else { - registry.get(HIST("hnLcVars"))->Fill(massLc, pt, nTracks, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, 0); - } - } + if (isDataWithMl) { + registry.add("hnLcVarsWithBdt", "THn for Lambdac candidates with BDT scores for data with ML", HistType::kTHnSparseF, axesWithBdt); + } else if (isMcWithMl) { + registry.add("hnLcVarsWithBdt", "THn for Lambdac candidates with BDT scores for mc with ML", HistType::kTHnSparseF, axesWithBdt); + registry.add("hnLcVarsGen", "THn for Generated Lambdac", HistType::kTHnSparseF, axesGen); + } else if (isDataStd) { + registry.add("hnLcVars", "THn for Reconstructed Lambdac candidates for data without ML", HistType::kTHnSparseF, axesStd); + } else { + registry.add("hnLcVars", "THn for Reconstructed Lambdac candidates for mc without ML", HistType::kTHnSparseF, axesStd); + registry.add("hnLcVarsGen", "THn for Generated Lambdac", HistType::kTHnSparseF, axesGen); } } } - void processDataStd(aod::Collision const& collision, - LcCandidates const& selectedLcCandidates, - aod::TracksWDca const& tracks) + /// Evaluate centrality/multiplicity percentile (centrality estimator is automatically selected based on the used table) + /// \param candidate is candidate + /// \return centrality/multiplicity percentile of the collision + template + float evaluateCentralityColl(const Coll& collision) { - processData(collision, selectedLcCandidates, tracks); + return o2::hf_centrality::getCentralityColl(collision); } - PROCESS_SWITCH(HfTaskLc, processDataStd, "Process Data with the standard method", true); - void processDataWithMl(aod::Collision const& collision, - LcCandidatesMl const& selectedLcCandidatesMl, - aod::TracksWDca const& tracks) + /// Fill MC histograms at reconstruction level + /// \tparam fillMl switch to fill ML histograms + template + void fillHistosMcRec(CollType const& collision, CandLcMcRec const& candidates, CandLcMcGen const& mcParticles) { - processData(collision, selectedLcCandidatesMl, tracks); - } - PROCESS_SWITCH(HfTaskLc, processDataWithMl, "Process Data with the ML method", false); - /// Fills MC histograms. - template - void processMc(CandType const& candidates, - soa::Join const& mcParticles, - aod::TracksWMc const&) - { - for (const auto& candidate : candidates) { + auto thisCollId = collision.globalIndex(); + auto groupedLcCandidates = candidates.sliceBy(candLcPerCollision, thisCollId); + + for (const auto& candidate : groupedLcCandidates) { /// Select Lc if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) { continue; @@ -452,6 +393,9 @@ struct HfTaskLc { auto cpa = candidate.cpa(); auto cpaXY = candidate.cpaXY(); auto originType = candidate.originMcRec(); + auto numPvContributors = collision.numContrib(); + auto ptRecB = candidate.ptBhadMotherPart(); + /// MC reconstructed signal if ((candidate.isSelLcToPKPi() >= selectionFlagLc) && pdgCodeProng0 == kProton) { registry.fill(HIST("MC/reconstructed/signal/hMassRecSig"), hfHelper.invMassLcToPKPi(candidate)); @@ -573,47 +517,75 @@ struct HfTaskLc { registry.fill(HIST("MC/reconstructed/nonprompt/hImpParErrProng2SigNonPrompt"), candidate.errorImpactParameter2(), pt); registry.fill(HIST("MC/reconstructed/nonprompt/hDecLenErrSigNonPrompt"), candidate.errorDecayLength(), pt); } - if (enableTHn) { + if (fillTHn) { + float cent = evaluateCentralityColl(collision); + float occ{-1.}; + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); + } double massLc(-1); double outputBkg(-1), outputPrompt(-1), outputFD(-1); if ((candidate.isSelLcToPKPi() >= selectionFlagLc) && pdgCodeProng0 == kProton) { massLc = hfHelper.invMassLcToPKPi(candidate); if constexpr (fillMl) { - if (candidate.mlProbLcToPKPi().size() == 3) { - outputBkg = candidate.mlProbLcToPKPi()[0]; /// bkg score outputPrompt = candidate.mlProbLcToPKPi()[1]; /// prompt score outputFD = candidate.mlProbLcToPKPi()[2]; /// non-prompt score } - /// Fill the ML outputScores and variables of candidate (todo: add multiplicity) - registry.get(HIST("hnLcVarsWithBdt"))->Fill(massLc, pt, 0, outputBkg, outputPrompt, outputFD, originType); + /// Fill the ML outputScores and variables of candidate + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + registry.get(HIST("hnLcVarsWithBdt"))->Fill(massLc, pt, cent, outputBkg, outputPrompt, outputFD, numPvContributors, ptRecB, originType, occ); + } else { + registry.get(HIST("hnLcVarsWithBdt"))->Fill(massLc, pt, cent, outputBkg, outputPrompt, outputFD, numPvContributors, ptRecB, originType); + } + } else { - registry.get(HIST("hnLcVars"))->Fill(massLc, pt, 0, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, originType); + + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + registry.get(HIST("hnLcVars"))->Fill(massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, numPvContributors, ptRecB, originType, occ); + + } else { + + registry.get(HIST("hnLcVars"))->Fill(massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, numPvContributors, ptRecB, originType); + } } } if ((candidate.isSelLcToPiKP() >= selectionFlagLc) && pdgCodeProng0 == kPiPlus) { massLc = hfHelper.invMassLcToPiKP(candidate); if constexpr (fillMl) { - if (candidate.mlProbLcToPiKP().size() == 3) { - outputBkg = candidate.mlProbLcToPiKP()[0]; /// bkg score outputPrompt = candidate.mlProbLcToPiKP()[1]; /// prompt score outputFD = candidate.mlProbLcToPiKP()[2]; /// non-prompt score } /// Fill the ML outputScores and variables of candidate (todo: add multiplicity) - registry.get(HIST("hnLcVarsWithBdt"))->Fill(massLc, pt, 0, outputBkg, outputPrompt, outputFD, originType); + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + registry.get(HIST("hnLcVarsWithBdt"))->Fill(massLc, pt, cent, outputBkg, outputPrompt, outputFD, numPvContributors, ptRecB, originType, occ); + + } else { + registry.get(HIST("hnLcVarsWithBdt"))->Fill(massLc, pt, cent, outputBkg, outputPrompt, outputFD, numPvContributors, ptRecB, originType); + } } else { - registry.get(HIST("hnLcVars"))->Fill(massLc, pt, 0, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, originType); + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + registry.get(HIST("hnLcVars"))->Fill(massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, numPvContributors, ptRecB, originType, occ); + } else { + registry.get(HIST("hnLcVars"))->Fill(massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, numPvContributors, ptRecB, originType); + } } } } } } + } + /// Fill MC histograms at generated level + /// \tparam fillMl switch to fill ML histograms + template + void fillHistosMcGen(CandLcMcGen const& mcParticles, Coll const& recoCollisions) + { // MC gen. for (const auto& particle : mcParticles) { if (std::abs(particle.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::LcToPKPi) { @@ -622,6 +594,19 @@ struct HfTaskLc { continue; } auto ptGen = particle.pt(); + auto originType = particle.originMcGen(); + float ptGenB = -1.; + unsigned int numPvContributors = 0; + const auto& recoCollsPerMcColl = recoCollisions.sliceBy(colPerMcCollision, particle.mcCollision().globalIndex()); + for (const auto& recCol : recoCollsPerMcColl) { + numPvContributors = recCol.numContrib() > numPvContributors ? recCol.numContrib() : numPvContributors; + } + float cent = o2::hf_centrality::getCentralityGenColl(recoCollsPerMcColl); + float occ{-1.}; + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + occ = o2::hf_occupancy::getOccupancyGenColl(recoCollsPerMcColl, occEstimator); + } + registry.fill(HIST("MC/generated/signal/hPtGen"), ptGen); registry.fill(HIST("MC/generated/signal/hEtaGen"), particle.eta()); registry.fill(HIST("MC/generated/signal/hYGen"), yGen); @@ -631,6 +616,14 @@ struct HfTaskLc { registry.fill(HIST("MC/generated/signal/hPhiVsPtGenSig"), particle.phi(), ptGen); if (particle.originMcGen() == RecoDecay::OriginType::Prompt) { + if (fillTHn) { + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + registry.get(HIST("hnLcVarsGen"))->Fill(ptGen, cent, yGen, numPvContributors, ptGenB, originType, occ); + + } else { + registry.get(HIST("hnLcVarsGen"))->Fill(ptGen, cent, yGen, numPvContributors, ptGenB, originType); + } + } registry.fill(HIST("MC/generated/prompt/hPtGenPrompt"), ptGen); registry.fill(HIST("MC/generated/prompt/hEtaGenPrompt"), particle.eta()); registry.fill(HIST("MC/generated/prompt/hYGenPrompt"), yGen); @@ -640,6 +633,15 @@ struct HfTaskLc { registry.fill(HIST("MC/generated/prompt/hPhiVsPtGenSigPrompt"), particle.phi(), ptGen); } if (particle.originMcGen() == RecoDecay::OriginType::NonPrompt) { + ptGenB = mcParticles.rawIteratorAt(particle.idxBhadMotherPart()).pt(); + if (fillTHn) { + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + registry.get(HIST("hnLcVarsGen"))->Fill(ptGen, cent, yGen, numPvContributors, ptGenB, originType, occ); + + } else { + registry.get(HIST("hnLcVarsGen"))->Fill(ptGen, cent, yGen, numPvContributors, ptGenB, originType); + } + } registry.fill(HIST("MC/generated/nonprompt/hPtGenNonPrompt"), ptGen); registry.fill(HIST("MC/generated/nonprompt/hEtaGenNonPrompt"), particle.eta()); registry.fill(HIST("MC/generated/nonprompt/hYGenNonPrompt"), yGen); @@ -652,21 +654,269 @@ struct HfTaskLc { } } - void processMcStd(LcCandidatesMc const& selectedLcCandidatesMc, - soa::Join const& mcParticles, - aod::TracksWMc const& tracksWithMc) + /// Fill histograms for real data + /// \tparam fillMl switch to fill ML histograms + template + void fillHistosData(CollType const& collision, CandType const& candidates) { - processMc(selectedLcCandidatesMc, mcParticles, tracksWithMc); + auto thisCollId = collision.globalIndex(); + auto groupedLcCandidates = candidates.sliceBy(candLcPerCollision, thisCollId); + auto numPvContributors = collision.numContrib(); + + for (const auto& candidate : groupedLcCandidates) { + if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) { + continue; + } + if (yCandRecoMax >= 0. && std::abs(hfHelper.yLc(candidate)) > yCandRecoMax) { + continue; + } + auto pt = candidate.pt(); + auto ptProng0 = candidate.ptProng0(); + auto ptProng1 = candidate.ptProng1(); + auto ptProng2 = candidate.ptProng2(); + auto decayLength = candidate.decayLength(); + auto decayLengthXY = candidate.decayLengthXY(); + auto chi2PCA = candidate.chi2PCA(); + auto cpa = candidate.cpa(); + auto cpaXY = candidate.cpaXY(); + + if (candidate.isSelLcToPKPi() >= selectionFlagLc) { + registry.fill(HIST("Data/hMass"), hfHelper.invMassLcToPKPi(candidate)); + registry.fill(HIST("Data/hMassVsPtVsNPvContributors"), hfHelper.invMassLcToPKPi(candidate), pt, numPvContributors); + registry.fill(HIST("Data/hMassVsPt"), hfHelper.invMassLcToPKPi(candidate), pt); + } + if (candidate.isSelLcToPiKP() >= selectionFlagLc) { + registry.fill(HIST("Data/hMass"), hfHelper.invMassLcToPiKP(candidate)); + registry.fill(HIST("Data/hMassVsPtVsNPvContributors"), hfHelper.invMassLcToPiKP(candidate), pt, numPvContributors); + registry.fill(HIST("Data/hMassVsPt"), hfHelper.invMassLcToPiKP(candidate), pt); + } + registry.fill(HIST("Data/hPt"), pt); + registry.fill(HIST("Data/hPtProng0"), ptProng0); + registry.fill(HIST("Data/hPtProng1"), ptProng1); + registry.fill(HIST("Data/hPtProng2"), ptProng2); + registry.fill(HIST("Data/hd0Prong0"), candidate.impactParameter0()); + registry.fill(HIST("Data/hd0Prong1"), candidate.impactParameter1()); + registry.fill(HIST("Data/hd0Prong2"), candidate.impactParameter2()); + registry.fill(HIST("Data/hd0VsPtProng0"), candidate.impactParameter0(), pt); + registry.fill(HIST("Data/hd0VsPtProng1"), candidate.impactParameter1(), pt); + registry.fill(HIST("Data/hd0VsPtProng2"), candidate.impactParameter2(), pt); + registry.fill(HIST("Data/hDecLength"), decayLength); + registry.fill(HIST("Data/hDecLengthVsPt"), decayLength, pt); + registry.fill(HIST("Data/hDecLengthxy"), decayLengthXY); + registry.fill(HIST("Data/hDecLengthxyVsPt"), decayLengthXY, pt); + registry.fill(HIST("Data/hCt"), hfHelper.ctLc(candidate)); + registry.fill(HIST("Data/hCtVsPt"), hfHelper.ctLc(candidate), pt); + registry.fill(HIST("Data/hCPA"), cpa); + registry.fill(HIST("Data/hCPAVsPt"), cpa, pt); + registry.fill(HIST("Data/hCPAxy"), cpaXY); + registry.fill(HIST("Data/hCPAxyVsPt"), cpaXY, pt); + registry.fill(HIST("Data/hDca2"), chi2PCA); + registry.fill(HIST("Data/hDca2VsPt"), chi2PCA, pt); + registry.fill(HIST("Data/hEta"), candidate.eta()); + registry.fill(HIST("Data/hEtaVsPt"), candidate.eta(), pt); + registry.fill(HIST("Data/hPhi"), candidate.phi()); + registry.fill(HIST("Data/hPhiVsPt"), candidate.phi(), pt); + registry.fill(HIST("hSelectionStatus"), candidate.isSelLcToPKPi(), pt); + registry.fill(HIST("hSelectionStatus"), candidate.isSelLcToPiKP(), pt); + registry.fill(HIST("Data/hImpParErrProng0"), candidate.errorImpactParameter0(), pt); + registry.fill(HIST("Data/hImpParErrProng1"), candidate.errorImpactParameter1(), pt); + registry.fill(HIST("Data/hImpParErrProng2"), candidate.errorImpactParameter2(), pt); + registry.fill(HIST("Data/hDecLenErr"), candidate.errorDecayLength(), pt); + + if (fillTHn) { + float cent = evaluateCentralityColl(collision); + float occ{-1.}; + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); + } + double massLc(-1); + double outputBkg(-1), outputPrompt(-1), outputFD(-1); + if (candidate.isSelLcToPKPi() >= selectionFlagLc) { + massLc = hfHelper.invMassLcToPKPi(candidate); + + if constexpr (fillMl) { + if (candidate.mlProbLcToPKPi().size() == 3) { + outputBkg = candidate.mlProbLcToPKPi()[0]; /// bkg score + outputPrompt = candidate.mlProbLcToPKPi()[1]; /// prompt score + outputFD = candidate.mlProbLcToPKPi()[2]; /// non-prompt score + } + /// Fill the ML outputScores and variables of candidate + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + registry.get(HIST("hnLcVarsWithBdt"))->Fill(massLc, pt, cent, outputBkg, outputPrompt, outputFD, numPvContributors, occ); + + } else { + registry.get(HIST("hnLcVarsWithBdt"))->Fill(massLc, pt, cent, outputBkg, outputPrompt, outputFD, numPvContributors); + } + } else { + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + + registry.get(HIST("hnLcVars"))->Fill(massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, numPvContributors, occ); + } else { + + registry.get(HIST("hnLcVars"))->Fill(massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, numPvContributors); + } + } + } + if (candidate.isSelLcToPiKP() >= selectionFlagLc) { + massLc = hfHelper.invMassLcToPiKP(candidate); + + if constexpr (fillMl) { + if (candidate.mlProbLcToPiKP().size() == 3) { + outputBkg = candidate.mlProbLcToPiKP()[0]; /// bkg score + outputPrompt = candidate.mlProbLcToPiKP()[1]; /// prompt score + outputFD = candidate.mlProbLcToPiKP()[2]; /// non-prompt score + } + /// Fill the ML outputScores and variables of candidate + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + registry.get(HIST("hnLcVarsWithBdt"))->Fill(massLc, pt, cent, outputBkg, outputPrompt, outputFD, numPvContributors, occ); + } else { + registry.get(HIST("hnLcVarsWithBdt"))->Fill(massLc, pt, cent, outputBkg, outputPrompt, outputFD, numPvContributors); + } + } else { + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + registry.get(HIST("hnLcVars"))->Fill(massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, numPvContributors, occ); + } else { + registry.get(HIST("hnLcVars"))->Fill(massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, numPvContributors); + } + } + } + } + } + } + /// Run the analysis on real data + /// \tparam fillMl switch to fill ML histograms + template + void runAnalysisPerCollisionData(CollType const& collisions, + CandType const& candidates) + { + + for (const auto& collision : collisions) { + fillHistosData(collision, candidates); + } + } + + /// Run the analysis on MC data + /// \tparam fillMl switch to fill ML histograms + template + void runAnalysisPerCollisionMc(CollType const& collisions, + CandType const& candidates, + CandLcMcGen const& mcParticles) + { + for (const auto& collision : collisions) { + // MC Rec. + fillHistosMcRec(collision, candidates, mcParticles); + } + // MC gen. + fillHistosMcGen(mcParticles, collisions); + } + + void processDataStd(Collisions const& collisions, + LcCandidates const& selectedLcCandidates, + aod::Tracks const&) + { + runAnalysisPerCollisionData(collisions, selectedLcCandidates); + } + PROCESS_SWITCH(HfTaskLc, processDataStd, "Process Data with the standard method", true); + + void processDataWithMl(Collisions const& collisions, + LcCandidatesMl const& selectedLcCandidatesMl, + aod::Tracks const&) + { + runAnalysisPerCollisionData(collisions, selectedLcCandidatesMl); + } + PROCESS_SWITCH(HfTaskLc, processDataWithMl, "Process real data with the ML method and without centrality", false); + + void processDataStdWithFT0C(CollisionsWithFT0C const& collisions, + LcCandidates const& selectedLcCandidates, + aod::Tracks const&) + { + runAnalysisPerCollisionData(collisions, selectedLcCandidates); + } + PROCESS_SWITCH(HfTaskLc, processDataStdWithFT0C, "Process real data with the standard method and with FT0C centrality", false); + + void processDataWithMlWithFT0C(CollisionsWithFT0C const& collisions, + LcCandidatesMl const& selectedLcCandidatesMl, + aod::Tracks const&) + { + runAnalysisPerCollisionData(collisions, selectedLcCandidatesMl); + } + PROCESS_SWITCH(HfTaskLc, processDataWithMlWithFT0C, "Process real data with the ML method and with FT0C centrality", false); + + void processDataStdWithFT0M(CollisionsWithFT0M const& collisions, + LcCandidates const& selectedLcCandidates, + aod::Tracks const&) + { + runAnalysisPerCollisionData(collisions, selectedLcCandidates); + } + PROCESS_SWITCH(HfTaskLc, processDataStdWithFT0M, "Process real data with the standard method and with FT0M centrality", false); + + void processDataWithMlWithFT0M(CollisionsWithFT0M const& collisions, + LcCandidatesMl const& selectedLcCandidatesMl, + aod::Tracks const&) + { + runAnalysisPerCollisionData(collisions, selectedLcCandidatesMl); + } + PROCESS_SWITCH(HfTaskLc, processDataWithMlWithFT0M, "Process real data with the ML method and with FT0M centrality", false); + + void processMcStd(CollisionsMc const& collisions, + LcCandidatesMc const& selectedLcCandidatesMc, + McParticles3ProngMatched const& mcParticles, + aod::McCollisions const&, + aod::TracksWMc const&) + { + runAnalysisPerCollisionMc(collisions, selectedLcCandidatesMc, mcParticles); } PROCESS_SWITCH(HfTaskLc, processMcStd, "Process MC with the standard method", false); - void processMcWithMl(LcCandidatesMlMc const& selectedLcCandidatesMlMc, - soa::Join const& mcParticles, - aod::TracksWMc const& tracksWithMc) + void processMcWithMl(CollisionsMc const& collisions, + LcCandidatesMlMc const& selectedLcCandidatesMlMc, + McParticles3ProngMatched const& mcParticles, + aod::McCollisions const&, + aod::TracksWMc const&) + { + runAnalysisPerCollisionMc(collisions, selectedLcCandidatesMlMc, mcParticles); + } + PROCESS_SWITCH(HfTaskLc, processMcWithMl, "Process Mc with the ML method and without centrality", false); + + void processMcStdWithFT0C(CollisionsMcWithFT0C const& collisions, + LcCandidatesMc const& selectedLcCandidatesMc, + McParticles3ProngMatched const& mcParticles, + aod::McCollisions const&, + aod::TracksWMc const&) + { + runAnalysisPerCollisionMc(collisions, selectedLcCandidatesMc, mcParticles); + } + PROCESS_SWITCH(HfTaskLc, processMcStdWithFT0C, "Process MC with the standard method with FT0C centrality", false); + + void processMcWithMlWithFT0C(CollisionsMcWithFT0C const& collisions, + LcCandidatesMlMc const& selectedLcCandidatesMlMc, + McParticles3ProngMatched const& mcParticles, + aod::McCollisions const&, + aod::TracksWMc const&) + { + runAnalysisPerCollisionMc(collisions, selectedLcCandidatesMlMc, mcParticles); + } + PROCESS_SWITCH(HfTaskLc, processMcWithMlWithFT0C, "Process Mc with the ML method with FT0C centrality", false); + + void processMcStdWithFT0M(CollisionsMcWithFT0M const& collisions, + LcCandidatesMc const& selectedLcCandidatesMc, + McParticles3ProngMatched const& mcParticles, + aod::McCollisions const&, + aod::TracksWMc const&) + { + runAnalysisPerCollisionMc(collisions, selectedLcCandidatesMc, mcParticles); + } + PROCESS_SWITCH(HfTaskLc, processMcStdWithFT0M, "Process MC with the standard method with FT0M centrality", false); + + void processMcWithMlWithFT0M(CollisionsMcWithFT0M const& collisions, + LcCandidatesMlMc const& selectedLcCandidatesMlMc, + McParticles3ProngMatched const& mcParticles, + aod::McCollisions const&, + aod::TracksWMc const&) { - processMc(selectedLcCandidatesMlMc, mcParticles, tracksWithMc); + runAnalysisPerCollisionMc(collisions, selectedLcCandidatesMlMc, mcParticles); } - PROCESS_SWITCH(HfTaskLc, processMcWithMl, "Process Mc with the ML method", false); + PROCESS_SWITCH(HfTaskLc, processMcWithMlWithFT0M, "Process Mc with the ML method with FT0M centrality", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/D2H/Tasks/taskLcToK0sP.cxx b/PWGHF/D2H/Tasks/taskLcToK0sP.cxx index c8a9d1c2128..6df67174cfd 100644 --- a/PWGHF/D2H/Tasks/taskLcToK0sP.cxx +++ b/PWGHF/D2H/Tasks/taskLcToK0sP.cxx @@ -17,6 +17,8 @@ /// /// \note based on taskD0.cxx, taskLc.cxx +#include + #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" diff --git a/PWGHF/D2H/Tasks/taskOmegac0ToOmegapi.cxx b/PWGHF/D2H/Tasks/taskOmegac0ToOmegapi.cxx new file mode 100644 index 00000000000..7142b2d2e49 --- /dev/null +++ b/PWGHF/D2H/Tasks/taskOmegac0ToOmegapi.cxx @@ -0,0 +1,229 @@ +// 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 taskOmegac0ToOmegapi.cxx +/// \brief OmegaC0 analysis task +/// \author Yunfan Liu , China University of Geosciences +/// \author Fabio Catalano , University of Houston + +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsEvSelHf.h" + +using namespace o2; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// Omegac0 analysis task + +struct HfTaskOmegac0ToOmegapi { + // ML inference + Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; + Configurable selectionFlagOmegac0{"selectionFlagOmegac0", true, "Select Omegac0 candidates"}; + Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen particle rapidity"}; + Configurable yCandRecoMax{"yCandRecoMax", 0.8, "max. cand. rapidity"}; + + HfHelper hfHelper; + SliceCache cache; + + using TracksMc = soa::Join; + + using Omegac0Cands = soa::Filtered>; + using Omegac0CandsKF = soa::Filtered>; + using OmegaC0CandsMcKF = soa::Filtered>; + + using Omegac0CandsMl = soa::Filtered>; + using Omegac0CandsMlKF = soa::Filtered>; + using Omegac0CandsMlMcKF = soa::Filtered>; + + using Omegac0Gen = soa::Filtered>; + + using Collisions = soa::Join; + using CollisionsWithMcLabels = soa::Join; + + Filter filterOmegaCToOmegaPiFlag = (aod::hf_track_index::hfflag & static_cast(BIT(aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi))) != static_cast(0); + Filter filterOmegaCMatchedRec = nabs(aod::hf_cand_xic0_omegac0::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi)); + Filter filterOmegaCMatchedGen = nabs(aod::hf_cand_xic0_omegac0::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi)); + + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + + // ThnSparse for ML outputScores and Vars + ConfigurableAxis thnConfigAxisPromptScore{"thnConfigAxisPromptScore", {50, 0, 1}, "Prompt score bins"}; + ConfigurableAxis thnConfigAxisMass{"thnConfigAxisMass", {120, 2.4, 3.1}, "Cand. inv-mass bins"}; + ConfigurableAxis thnConfigAxisPtB{"thnConfigAxisPtB", {1000, 0, 100}, "Cand. beauty mother pTB bins"}; + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {100, 0, 20}, "Cand. pT bins"}; + ConfigurableAxis thnConfigAxisY{"thnConfigAxisY", {20, -1, 1}, "Cand. rapidity bins"}; + ConfigurableAxis thnConfigAxisOrigin{"thnConfigAxisOrigin", {3, -0.5, 2.5}, "Cand. origin type"}; + ConfigurableAxis thnConfigAxisMatchFlag{"thnConfigAxisMatchFlag", {15, -7.5, 7.5}, "Cand. MC Match Flag type"}; + ConfigurableAxis thnConfigAxisGenPtD{"thnConfigAxisGenPtD", {500, 0, 50}, "Gen Pt D"}; + ConfigurableAxis thnConfigAxisGenPtB{"thnConfigAxisGenPtB", {1000, 0, 100}, "Gen Pt B"}; + ConfigurableAxis thnConfigAxisNumPvContr{"thnConfigAxisNumPvContr", {200, -0.5, 199.5}, "Number of PV contributors"}; + HistogramRegistry registry{"registry", {}}; + + void init(InitContext&) + { + std::array doprocess{doprocessDataWithKFParticle, doprocessMcWithKFParticle, doprocessDataWithKFParticleMl, doprocessMcWithKFParticleMl}; + if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { + LOGP(fatal, "One and only one process function should be enabled at a time."); + } + + const AxisSpec thnAxisMass{thnConfigAxisMass, "inv. mass (#Omega#pi) (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisPt{thnConfigAxisPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisPtB{thnConfigAxisPtB, "#it{p}_{T}^{B} (GeV/#it{c})"}; + const AxisSpec thnAxisY{thnConfigAxisY, "y"}; + const AxisSpec thnAxisOrigin{thnConfigAxisOrigin, "Origin"}; + const AxisSpec thnAxisMatchFlag{thnConfigAxisMatchFlag, "MatchFlag"}; + const AxisSpec thnAxisGenPtD{thnConfigAxisGenPtD, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisGenPtB{thnConfigAxisGenPtB, "#it{p}_{T}^{B} (GeV/#it{c})"}; + const AxisSpec thnAxisNumPvContr{thnConfigAxisNumPvContr, "Number of PV contributors"}; + + if (doprocessMcWithKFParticle || doprocessMcWithKFParticleMl) { + std::vector axesAcc = {thnAxisGenPtD, thnAxisGenPtB, thnAxisY, thnAxisOrigin, thnAxisNumPvContr}; + registry.add("hSparseAcc", "Thn for generated Omega0 from charm and beauty", HistType::kTHnSparseD, axesAcc); + registry.get(HIST("hSparseAcc"))->Sumw2(); + } + + std::vector axes = {thnAxisMass, thnAxisPt, thnAxisY}; + if (doprocessMcWithKFParticle || doprocessMcWithKFParticleMl) { + axes.push_back(thnAxisPtB); + axes.push_back(thnAxisOrigin); + axes.push_back(thnAxisMatchFlag); + axes.push_back(thnAxisNumPvContr); + } + if (applyMl) { + const AxisSpec thnAxisPromptScore{thnConfigAxisPromptScore, "BDT score prompt."}; + axes.insert(axes.begin(), thnAxisPromptScore); + registry.add("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsOmegac0Type", "Thn for Omegac0 candidates", HistType::kTHnSparseD, axes); + registry.get(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsOmegac0Type"))->Sumw2(); + } else { + registry.add("hMassVsPtVsPtBVsYVsOriginVsOmegac0Type", "Thn for Omegac0 candidates", HistType::kTHnSparseF, axes); + registry.get(HIST("hMassVsPtVsPtBVsYVsOriginVsOmegac0Type"))->Sumw2(); + } + } + + template + void processData(const CandType& candidates, CollType const&) + { + for (const auto& candidate : candidates) { + if (!(candidate.resultSelections() == true || (candidate.resultSelections() == false && !selectionFlagOmegac0))) { + continue; + } + if (yCandRecoMax >= 0. && std::abs(candidate.kfRapOmegac()) > yCandRecoMax) { + continue; + } + + if constexpr (applyMl) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsOmegac0Type"), candidate.mlProbOmegac()[0], candidate.invMassCharmBaryon(), candidate.ptCharmBaryon(), candidate.kfRapOmegac()); + } else { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsOmegac0Type"), candidate.invMassCharmBaryon(), candidate.ptCharmBaryon(), candidate.kfRapOmegac()); + } + } + } + + template + void processMc(const CandType& candidates, + Omegac0Gen const& mcParticles, + TracksMc const&, + CollType const& collisions, + aod::McCollisions const&) + { + // MC rec. + for (const auto& candidate : candidates) { + if (!(candidate.resultSelections() == true || (candidate.resultSelections() == false && !selectionFlagOmegac0))) { + continue; + } + if (yCandRecoMax >= 0. && std::abs(candidate.kfRapOmegac()) > yCandRecoMax) { + continue; + } + + auto numPvContributors = candidate.template collision_as().numContrib(); + + if constexpr (applyMl) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsOmegac0Type"), candidate.mlProbOmegac()[0], candidate.invMassCharmBaryon(), candidate.ptCharmBaryon(), candidate.kfRapOmegac(), candidate.ptBhadMotherPart(), candidate.originRec(), candidate.flagMcMatchRec(), numPvContributors); + + } else { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsOmegac0Type"), candidate.invMassCharmBaryon(), candidate.ptCharmBaryon(), candidate.kfRapOmegac(), candidate.ptBhadMotherPart(), candidate.originRec(), candidate.flagMcMatchRec(), numPvContributors); + } + } + + // MC gen. + for (const auto& particle : mcParticles) { + if (yCandGenMax >= 0. && std::abs(particle.rapidityCharmBaryonGen()) > yCandGenMax) { + continue; + } + + auto ptGen = particle.pt(); + auto yGen = particle.rapidityCharmBaryonGen(); + + unsigned maxNumContrib = 0; + const auto& recoCollsPerMcColl = collisions.sliceBy(colPerMcCollision, particle.mcCollision().globalIndex()); + for (const auto& recCol : recoCollsPerMcColl) { + maxNumContrib = recCol.numContrib() > maxNumContrib ? recCol.numContrib() : maxNumContrib; + } + + if (particle.originGen() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hSparseAcc"), ptGen, -1., yGen, RecoDecay::OriginType::Prompt, maxNumContrib); + } else { + float ptGenB = mcParticles.rawIteratorAt(particle.idxBhadMotherPart()).pt(); + registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, RecoDecay::OriginType::NonPrompt, maxNumContrib); + } + } + } + + void processDataWithKFParticle(Omegac0CandsKF const& candidates, + Collisions const& collisions) + { + processData(candidates, collisions); + } + PROCESS_SWITCH(HfTaskOmegac0ToOmegapi, processDataWithKFParticle, "process HfTaskOmegac0ToOmegapi with KFParticle", false); + + void processDataWithKFParticleMl(Omegac0CandsMlKF const& candidates, + Collisions const& collisions) + { + processData(candidates, collisions); + } + PROCESS_SWITCH(HfTaskOmegac0ToOmegapi, processDataWithKFParticleMl, "process HfTaskOmegac0ToOmegapi with KFParticle and ML selections", false); + + void processMcWithKFParticle(OmegaC0CandsMcKF const& omegaC0CandidatesMcKF, + Omegac0Gen const& mcParticles, + TracksMc const& tracks, + CollisionsWithMcLabels const& collisions, + aod::McCollisions const& mcCollisions) + { + processMc(omegaC0CandidatesMcKF, mcParticles, tracks, collisions, mcCollisions); + } + PROCESS_SWITCH(HfTaskOmegac0ToOmegapi, processMcWithKFParticle, "Process MC with KFParticle", false); + + void processMcWithKFParticleMl(Omegac0CandsMlMcKF const& omegac0CandidatesMlMcKF, + Omegac0Gen const& mcParticles, + TracksMc const& tracks, + CollisionsWithMcLabels const& collisions, + aod::McCollisions const& mcCollisions) + { + processMc(omegac0CandidatesMlMcKF, mcParticles, tracks, collisions, mcCollisions); + } + PROCESS_SWITCH(HfTaskOmegac0ToOmegapi, processMcWithKFParticleMl, "Process MC with KFParticle and ML selections", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/Tasks/taskSigmac.cxx b/PWGHF/D2H/Tasks/taskSigmac.cxx index 72cdb981776..e7083d7283e 100644 --- a/PWGHF/D2H/Tasks/taskSigmac.cxx +++ b/PWGHF/D2H/Tasks/taskSigmac.cxx @@ -15,6 +15,8 @@ /// /// \author Mattia Faggin , University and INFN PADOVA +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" @@ -37,11 +39,20 @@ struct HfTaskSigmac { /// Properly normalize your results to provide a cross section /// OR /// consider the new parametrization of the fiducial acceptance (to be seen for reco signal in MC) - Configurable yCandMax{"yCandMax", -1, "Sc rapidity"}; + Configurable yCandGenMax{"yCandGenMax", -1, "Maximum generated Sc rapidity"}; + Configurable yCandRecoMax{"yCandRecoMax", -1, "Maximum Sc candidate rapidity"}; + Configurable enableTHn{"enableTHn", false, "enable the usage of THn for Λc+ and Σc0,++"}; + + HfHelper hfHelper; + bool isMc; + static constexpr std::size_t NDaughters{2u}; + + using RecoLc = soa::Join; /// THn for candidate Λc+ and Σc0,++ cut variation - Configurable enableTHn{"enableTHn", false, "enable the usage of THn for Λc+ and Σc0,++"}; ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {16, 0, 16}, ""}; + ConfigurableAxis thnConfigAxisGenPt{"thnConfigAxisGenPt", {240, 0, 24}, "Gen pt prompt"}; + ConfigurableAxis thnConfigAxisGenPtB{"thnConfigAxisGenPtB", {800, 0, 80}, "Gen pt non-prompt"}; ConfigurableAxis thnConfigAxisDecLength{"thnConfigAxisDecLength", {10, 0, 0.05}, ""}; ConfigurableAxis thnConfigAxisDecLengthXY{"thnConfigAxisDecLengthXY", {10, 0, 0.05}, ""}; ConfigurableAxis thnConfigAxisCPA{"thnConfigAxisCPA", {20, 0.8, 1}, ""}; @@ -50,8 +61,23 @@ struct HfTaskSigmac { ConfigurableAxis configAxisDeltaMassSigmaC{"configAxisDeltaMassSigmaC", {200, 0.13, 0.23}, ""}; ConfigurableAxis thnConfigAxisBdtScoreLcBkg{"thnConfigAxisBdtScoreLcBkg", {100, 0., 1.}, ""}; ConfigurableAxis thnConfigAxisBdtScoreLcNonPrompt{"thnConfigAxisBdtScoreLcNonPrompt", {100, 0., 1.}, ""}; - - HfHelper hfHelper; + const AxisSpec thnAxisMassLambdaC{configAxisMassLambdaC, "inv. mass (p K #pi) (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisPtLambdaC{thnConfigAxisPt, "#it{p}_{T}(#Lambda_{c}^{+}) (GeV/#it{c})"}; + const AxisSpec thnAxisPtSigmaC{thnConfigAxisPt, "#it{p}_{T}(#Sigma_{c}^{0,++}) (GeV/#it{c})"}; + const AxisSpec thnAxisDecLength{thnConfigAxisDecLength, "decay length #Lambda_{c}^{+} (cm)"}; + const AxisSpec thnAxisDecLengthXY{thnConfigAxisDecLengthXY, "decay length XY #Lambda_{c}^{+} (cm)"}; + const AxisSpec thnAxisCPA{thnConfigAxisCPA, "cosine of pointing angle #Lambda_{c}^{+}"}; + const AxisSpec thnAxisCPAXY{thnConfigAxisCPAXY, "cosine of pointing angle XY #Lambda_{c}^{+}"}; + const AxisSpec thnAxisOriginMc{3, -0.5, 2.5, "0: none, 1: prompt, 2: non-prompt"}; + const AxisSpec thnAxisChargeSigmaC{3, -0.5, 2.5, "#Sigma_{c}-baryon charge"}; + const AxisSpec thnAxisChannel{4, -0.5, 3.5, "0: direct 1,2,3: resonant"}; + const AxisSpec thnAxisBdtScoreLcBkg{thnConfigAxisBdtScoreLcBkg, "BDT bkg score (Lc)"}; + const AxisSpec thnAxisBdtScoreLcNonPrompt{thnConfigAxisBdtScoreLcNonPrompt, "BDT non-prompt score (Lc)"}; + const AxisSpec thnAxisGenPtLambdaC{thnConfigAxisGenPt, "#it{p}_{T}^{gen}(#Lambda_{c}^{+}) (GeV/#it{c})"}; + const AxisSpec thnAxisGenPtSigmaC{thnConfigAxisGenPt, "#it{p}_{T}^{gen}(#Sigma_{c}^{0,++}) (GeV/#it{c})"}; + const AxisSpec thnAxisGenPtLambdaCBMother{thnConfigAxisGenPtB, "#it{p}_{T}^{gen}(#Lambda_{c}^{+} B mother) (GeV/#it{c})"}; + const AxisSpec thnAxisGenPtSigmaCBMother{thnConfigAxisGenPtB, "#it{p}_{T}^{gen}(#Sigma_{c}^{0,++} B mother) (GeV/#it{c})"}; + const AxisSpec thnAxisGenSigmaCSpecies = {o2::aod::hf_cand_sigmac::Species::NSpecies, -0.5f, +o2::aod::hf_cand_sigmac::Species::NSpecies - 0.5f, "bin 1: #Sigma_{c}(2455), bin 2: #Sigma_{c}(2520)"}; /// analysis histograms HistogramRegistry registry{ @@ -96,10 +122,6 @@ struct HfTaskSigmac { {"Data/hPhiLcFromSc0PlusPlus", "#Lambda_{c}^{+} #leftarrow #Sigma_{c}^{0,++} candidates; #varphi(#Lambda_{c}^{+} #leftarrow #Sigma_{c}^{0,++}); entries;", {HistType::kTH1D, {{72, 0, constants::math::TwoPI}}}}}}; //{"Data/hDeltaMassLcFromSc0PlusPlus", "#Lambda_{c}^{+} #leftarrow #Sigma_{c}^{0,++} candidates; #it{M}(pK#pi#pi) - #it{M}(pK#pi) (GeV/#it{c}^{2}); #it{p}_{T}(#Lambda_{c}^{+} #leftarrow #Sigma_{c}^{0,++}) (GeV/#it{c});", {HistType::kTH2D, {axisDeltaMassSigmaC, {36, 0., 36.}}}}}}; - using RecoLc = soa::Join; - - bool isMc; - /// @brief init function, to define the additional analysis histograms /// @param void init(InitContext&) @@ -243,24 +265,34 @@ struct HfTaskSigmac { /// THn for candidate Λc+ and Σc0,++ cut variation if (enableTHn) { - const AxisSpec thnAxisMassLambdaC{configAxisMassLambdaC, "inv. mass (p K #pi) (GeV/#it{c}^{2})"}; - const AxisSpec thnAxisPtLambdaC{thnConfigAxisPt, "#it{p}_{T}(#Lambda_{c}^{+}) (GeV/#it{c})"}; - const AxisSpec thnAxisPtSigmaC{thnConfigAxisPt, "#it{p}_{T}(#Sigma_{c}^{0,++}) (GeV/#it{c})"}; - const AxisSpec thnAxisDecLength{thnConfigAxisDecLength, "decay length #Lambda_{c}^{+} (cm)"}; - const AxisSpec thnAxisDecLengthXY{thnConfigAxisDecLengthXY, "decay length XY #Lambda_{c}^{+} (cm)"}; - const AxisSpec thnAxisCPA{thnConfigAxisCPA, "cosine of pointing angle #Lambda_{c}^{+}"}; - const AxisSpec thnAxisCPAXY{thnConfigAxisCPAXY, "cosine of pointing angle XY #Lambda_{c}^{+}"}; - const AxisSpec thnAxisOriginMc{3, -0.5, 2.5, "0: none, 1: prompt, 2: non-prompt"}; - const AxisSpec thnAxisChargeSigmaC{3, -0.5, 2.5, "#Sigma_{c}-baryon charge"}; - const AxisSpec thnAxisChannel{4, -0.5, 3.5, "0: direct 1,2,3: resonant"}; - const AxisSpec thnAxisBdtScoreLcBkg{thnConfigAxisBdtScoreLcBkg, "BDT bkg score (Lc)"}; - const AxisSpec thnAxisBdtScoreLcNonPrompt{thnConfigAxisBdtScoreLcNonPrompt, "BDT non-prompt score (Lc)"}; - if (doprocessDataWithMl || doprocessMcWithMl) { - registry.add("hnLambdaC", "THn for Lambdac", HistType::kTHnSparseF, {thnAxisPtLambdaC, thnAxisMassLambdaC, thnAxisBdtScoreLcBkg, thnAxisBdtScoreLcNonPrompt, thnAxisOriginMc, thnAxisChannel}); - registry.add("hnSigmaC", "THn for Sigmac", HistType::kTHnSparseF, {thnAxisPtLambdaC, axisDeltaMassSigmaC, thnAxisBdtScoreLcBkg, thnAxisBdtScoreLcNonPrompt, thnAxisOriginMc, thnAxisChannel, thnAxisPtSigmaC, thnAxisChargeSigmaC}); + std::vector axesLambdaCWithMl = {thnAxisPtLambdaC, thnAxisMassLambdaC, thnAxisBdtScoreLcBkg, thnAxisBdtScoreLcNonPrompt, thnAxisOriginMc, thnAxisChannel}; + std::vector axesSigmaCWithMl = {thnAxisPtLambdaC, axisDeltaMassSigmaC, thnAxisBdtScoreLcBkg, thnAxisBdtScoreLcNonPrompt, thnAxisOriginMc, thnAxisChannel, thnAxisPtSigmaC, thnAxisChargeSigmaC}; + std::vector axesLambdaCWoMl = {thnAxisPtLambdaC, thnAxisMassLambdaC, thnAxisDecLength, thnAxisDecLengthXY, thnAxisCPA, thnAxisCPAXY, thnAxisOriginMc, thnAxisChannel}; + std::vector axesSigmaCWoMl = {thnAxisPtLambdaC, axisDeltaMassSigmaC, thnAxisDecLength, thnAxisDecLengthXY, thnAxisCPA, thnAxisCPAXY, thnAxisOriginMc, thnAxisChannel, thnAxisPtSigmaC, thnAxisChargeSigmaC}; + if (isMc) { + registry.add("MC/generated/hnLambdaCGen", "THn for Lambdac gen", HistType::kTHnSparseF, {thnAxisGenPtLambdaC, thnAxisGenPtLambdaCBMother, thnAxisOriginMc, thnAxisChannel}); + registry.add("MC/generated/hnSigmaCGen", "THn for Sigmac gen", HistType::kTHnSparseF, {thnAxisGenPtSigmaC, thnAxisGenPtSigmaCBMother, thnAxisOriginMc, thnAxisChannel, thnAxisGenPtLambdaC, thnAxisChargeSigmaC, thnAxisGenSigmaCSpecies}); + if (doprocessMcWithMl) { + axesLambdaCWithMl.push_back(thnAxisGenPtLambdaCBMother); + axesSigmaCWithMl.push_back(thnAxisGenPtSigmaCBMother); + axesSigmaCWithMl.push_back(thnAxisGenSigmaCSpecies); + registry.add("hnLambdaC", "THn for Lambdac", HistType::kTHnSparseF, axesLambdaCWithMl); + registry.add("hnSigmaC", "THn for Sigmac", HistType::kTHnSparseF, axesSigmaCWithMl); + } else { + axesLambdaCWoMl.push_back(thnAxisGenPtLambdaCBMother); + axesSigmaCWoMl.push_back(thnAxisGenPtSigmaCBMother); + axesSigmaCWoMl.push_back(thnAxisGenSigmaCSpecies); + registry.add("hnLambdaC", "THn for Lambdac", HistType::kTHnSparseF, axesLambdaCWoMl); + registry.add("hnSigmaC", "THn for Sigmac", HistType::kTHnSparseF, axesSigmaCWoMl); + } } else { - registry.add("hnLambdaC", "THn for Lambdac", HistType::kTHnSparseF, {thnAxisPtLambdaC, thnAxisMassLambdaC, thnAxisDecLength, thnAxisDecLengthXY, thnAxisCPA, thnAxisCPAXY, thnAxisOriginMc, thnAxisChannel}); - registry.add("hnSigmaC", "THn for Sigmac", HistType::kTHnSparseF, {thnAxisPtLambdaC, axisDeltaMassSigmaC, thnAxisDecLength, thnAxisDecLengthXY, thnAxisCPA, thnAxisCPAXY, thnAxisOriginMc, thnAxisChannel, thnAxisPtSigmaC, thnAxisChargeSigmaC}); + if (doprocessDataWithMl) { + registry.add("hnLambdaC", "THn for Lambdac", HistType::kTHnSparseF, axesLambdaCWithMl); + registry.add("hnSigmaC", "THn for Sigmac", HistType::kTHnSparseF, axesSigmaCWithMl); + } else { + registry.add("hnLambdaC", "THn for Lambdac", HistType::kTHnSparseF, axesLambdaCWoMl); + registry.add("hnSigmaC", "THn for Sigmac", HistType::kTHnSparseF, axesSigmaCWoMl); + } } } @@ -273,16 +305,16 @@ struct HfTaskSigmac { /// @param candSc Sc candidate /// @return 0: none; 1: only Λc+ → pK-π+ possible; 2: Λc+ → π+K-p possible; 3: both possible template - int isDecayToPKPiToPiKP(L& candidateLc, S& candSc) + int8_t isDecayToPKPiToPiKP(L& candidateLc, S& candSc) { - int channel = 0; + int8_t channel = 0; if ((candidateLc.isSelLcToPKPi() >= 1) && candSc.statusSpreadLcMinvPKPiFromPDG()) { // Λc+ → pK-π+ and within the requested mass to build the Σc0,++ - channel += 1; + SETBIT(channel, o2::aod::hf_cand_sigmac::Decays::PKPi); } if ((candidateLc.isSelLcToPiKP() >= 1) && candSc.statusSpreadLcMinvPiKPFromPDG()) { // Λc+ → π+K-p and within the requested mass to build the Σc0,++ - channel += 2; + SETBIT(channel, o2::aod::hf_cand_sigmac::Decays::PiKP); } return channel; /// 0: none; 1: pK-π+ only; 2: π+K-p only; 3: both possible } @@ -299,6 +331,12 @@ struct HfTaskSigmac { /// loop over the candidate Σc0,++ for (const auto& candSc : candidatesSc) { + /// rapidity selection on Σc0,++ + /// NB: since in data we cannot tag Sc(2455) and Sc(2520), then we use only Sc(2455) for y selection on reconstructed signal + if (yCandRecoMax >= 0. && std::abs(hfHelper.ySc0(candSc)) > yCandRecoMax && std::abs(hfHelper.yScPlusPlus(candSc)) > yCandRecoMax) { + continue; + } + const int8_t chargeSc = candSc.charge(); // either Σc0 or Σc++ /// get the candidate Λc+ used to build the candidate Σc0,++ @@ -306,7 +344,7 @@ struct HfTaskSigmac { const auto& candidateLc = candSc.prongLc_as(); // const int iscandidateLcpKpi = (candidateLc.isSelLcToPKPi() >= 1) && candSc.statusSpreadLcMinvPKPiFromPDG(); // Λc+ → pK-π+ and within the requested mass to build the Σc0,++ // const int iscandidateLcpiKp = (candidateLc.isSelLcToPiKP() >= 1) && candSc.statusSpreadLcMinvPiKPFromPDG(); // Λc+ → π+K-p and within the requested mass to build the Σc0,++ - const int isCandPKPiPiKP = isDecayToPKPiToPiKP(candidateLc, candSc); + const int8_t isCandPKPiPiKP = isDecayToPKPiToPiKP(candidateLc, candSc); double massSc(-1.), massLc(-1.), deltaMass(-1.); double ptSc(candSc.pt()), ptLc(candidateLc.pt()); double etaSc(candSc.eta()), etaLc(candidateLc.eta()); @@ -315,12 +353,12 @@ struct HfTaskSigmac { double decLengthLc(candidateLc.decayLength()), decLengthXYLc(candidateLc.decayLengthXY()); double cpaLc(candidateLc.cpa()), cpaXYLc(candidateLc.cpaXY()); /// candidate Λc+ → pK-π+ (and charge conjugate) within the range of M(pK-π+) chosen in the Σc0,++ builder - if (isCandPKPiPiKP == 1 || isCandPKPiPiKP == 3) { + if (TESTBIT(isCandPKPiPiKP, o2::aod::hf_cand_sigmac::Decays::PKPi)) { massSc = hfHelper.invMassScRecoLcToPKPi(candSc, candidateLc); massLc = hfHelper.invMassLcToPKPi(candidateLc); deltaMass = massSc - massLc; /// fill the histograms - if (chargeSc == 0) { + if (chargeSc == o2::aod::hf_cand_sigmac::ChargeNull) { registry.fill(HIST("Data/hPtSc0"), ptSc); registry.fill(HIST("Data/hEtaSc0"), etaSc); registry.fill(HIST("Data/hPhiSc0"), phiSc); @@ -388,12 +426,12 @@ struct HfTaskSigmac { } } /// end candidate Λc+ → pK-π+ (and charge conjugate) /// candidate Λc+ → π+K-p (and charge conjugate) within the range of M(π+K-p) chosen in the Σc0,++ builder - if (isCandPKPiPiKP == 2 || isCandPKPiPiKP == 3) { + if (TESTBIT(isCandPKPiPiKP, o2::aod::hf_cand_sigmac::Decays::PiKP)) { massSc = hfHelper.invMassScRecoLcToPiKP(candSc, candidateLc); massLc = hfHelper.invMassLcToPiKP(candidateLc); deltaMass = massSc - massLc; /// fill the histograms - if (chargeSc == 0) { + if (chargeSc == o2::aod::hf_cand_sigmac::ChargeNull) { registry.fill(HIST("Data/hPtSc0"), ptSc); registry.fill(HIST("Data/hEtaSc0"), etaSc); registry.fill(HIST("Data/hPhiSc0"), phiSc); @@ -460,7 +498,7 @@ struct HfTaskSigmac { } } } /// end candidate Λc+ → π+K-p (and charge conjugate) - } /// end loop over the candidate Σc0,++ + } /// end loop over the candidate Σc0,++ /// THn for candidate Λc+ cut variation w/o Σc0,++ mass-window cut if (enableTHn) { @@ -507,7 +545,7 @@ struct HfTaskSigmac { } } } /// end THn for candidate Λc+ cut variation w/o Σc0,++ mass-window cut - }; /// end fillHistosData + }; /// end fillHistosData /// @brief function to fill the histograms needed in analysis (MC) /// @param candidatesSc are the reconstructed candidate Σc0,++ with MC info @@ -522,13 +560,15 @@ struct HfTaskSigmac { aod::TracksWMc const&) { - /// MC generated particles + /// loop over Sc generated particles for (const auto& particle : mcParticlesSc) { /// reject immediately particles different from Σc0,++ - bool isSc0Gen = (std::abs(particle.flagMcMatchGen()) == (1 << aod::hf_cand_sigmac::DecayType::Sc0ToPKPiPi)); - bool isScPlusPlusGen = (std::abs(particle.flagMcMatchGen()) == (1 << aod::hf_cand_sigmac::DecayType::ScplusplusToPKPiPi)); - if (!isSc0Gen && !isScPlusPlusGen) + bool isSc0Gen = (std::abs(particle.flagMcMatchGen()) == BIT(aod::hf_cand_sigmac::DecayType::Sc0ToPKPiPi)); + bool isScStar0Gen = (std::abs(particle.flagMcMatchGen()) == BIT(aod::hf_cand_sigmac::DecayType::ScStar0ToPKPiPi)); + bool isScPlusPlusGen = (std::abs(particle.flagMcMatchGen()) == BIT(aod::hf_cand_sigmac::DecayType::ScplusplusToPKPiPi)); + bool isScStarPlusPlusGen = (std::abs(particle.flagMcMatchGen()) == BIT(aod::hf_cand_sigmac::DecayType::ScStarPlusPlusToPKPiPi)); + if (!isSc0Gen && !isScPlusPlusGen && !isScStar0Gen && !isScStarPlusPlusGen) continue; /// look for generated particles in acceptance @@ -542,16 +582,29 @@ struct HfTaskSigmac { OR consider the new parametrization of the fiducial acceptance (to be seen for reco signal in MC) */ - if (yCandMax >= 0. && std::abs(RecoDecay::y(particle.pVector(), o2::constants::physics::MassSigmaC0)) > yCandMax) { - continue; + if (yCandGenMax >= 0.) { + double mass = -1; + if (isSc0Gen) { + mass = o2::constants::physics::MassSigmaC0; + } else if (isScPlusPlusGen) { + mass = o2::constants::physics::MassSigmaCPlusPlus; + } else if (isScStar0Gen) { + mass = o2::constants::physics::MassSigmaCStar0; + } else if (isScStarPlusPlusGen) { + mass = o2::constants::physics::MassSigmaCStarPlusPlus; + } + if (mass > -1. && std::abs(RecoDecay::y(particle.pVector(), mass)) > yCandGenMax) { + continue; + } } /// Get the kinematic information of Σc0,++ and the daughters /// Get information about origin (prompt, non-prompt) /// Get information about decay Λc+ channel (direct, resonant) double ptGenSc(particle.pt()), etaGenSc(particle.eta()), phiGenSc(particle.phi()); + double ptGenScBMother(-1.); auto arrayDaughtersIds = particle.daughtersIds(); - if (arrayDaughtersIds.size() != 2) { + if (arrayDaughtersIds.size() != NDaughters) { /// This should never happen LOG(fatal) << "generated Σc0,++ has a number of daughter particles different than 2"; continue; @@ -561,7 +614,8 @@ struct HfTaskSigmac { double phiGenLc(-1.), phiGenSoftPi(-1.); int origin = -1; int8_t channel = -1; - if (std::abs(arrayDaughtersIds[0]) == o2::constants::physics::Pdg::kLambdaCPlus) { + auto daughter0 = mcParticles.rawIteratorAt(arrayDaughtersIds[0]); + if (std::abs(daughter0.pdgCode()) == o2::constants::physics::Pdg::kLambdaCPlus) { /// daughter 0 is the Λc+, daughter 1 the soft π auto daugLc = mcParticlesLc.rawIteratorAt(arrayDaughtersIds[0]); auto daugSoftPi = mcParticles.rawIteratorAt(arrayDaughtersIds[1]); @@ -573,7 +627,7 @@ struct HfTaskSigmac { ptGenSoftPi = daugSoftPi.pt(); etaGenSoftPi = daugSoftPi.eta(); phiGenSoftPi = daugSoftPi.phi(); - } else if (std::abs(arrayDaughtersIds[0]) == kPiPlus) { + } else if (std::abs(daughter0.pdgCode()) == kPiPlus) { /// daughter 0 is the soft π, daughter 1 the Λc+ auto daugLc = mcParticlesLc.rawIteratorAt(arrayDaughtersIds[1]); auto daugSoftPi = mcParticles.rawIteratorAt(arrayDaughtersIds[0]); @@ -588,7 +642,13 @@ struct HfTaskSigmac { } /// Fill histograms - if (isSc0Gen) { + int sigmacSpecies = -1; + if (isSc0Gen || isScPlusPlusGen) { + sigmacSpecies = o2::aod::hf_cand_sigmac::Sc2455; + } else if (isScStar0Gen || isScStarPlusPlusGen) { + sigmacSpecies = o2::aod::hf_cand_sigmac::Sc2520; + } + if (isSc0Gen || isScStar0Gen) { /// Generated Σc0 and Λc+ ← Σc0 signals registry.fill(HIST("MC/generated/hPtGenSc0Sig"), ptGenSc, origin, channel); registry.fill(HIST("MC/generated/hEtaGenSc0Sig"), etaGenSc, origin, channel); @@ -609,7 +669,20 @@ struct HfTaskSigmac { registry.fill(HIST("MC/generated/hPtGenLcFromSc0PlusPlusSig"), ptGenLc, origin, channel); registry.fill(HIST("MC/generated/hEtaGenLcFromSc0PlusPlusSig"), etaGenLc, origin, channel); registry.fill(HIST("MC/generated/hPhiGenLcFromSc0PlusPlusSig"), phiGenLc, origin, channel); /// Generated Λc+ ← Σc0,++ signal - } else if (isScPlusPlusGen) { + if (origin == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("MC/generated/hnSigmaCGen"), ptGenSc, ptGenScBMother, origin, channel, ptGenLc, 0, sigmacSpecies); + } else { + ptGenScBMother = mcParticlesSc.rawIteratorAt(particle.idxBhadMotherPart()).pt(); + registry.fill(HIST("MC/generated/hnSigmaCGen"), ptGenSc, ptGenScBMother, origin, channel, ptGenLc, 0, sigmacSpecies); + } + + // debug -- uncomment if needed + // it should be solved after the implementation of ev. selection for generated SigmaC particles + // if(origin != RecoDecay::OriginType::Prompt && origin != RecoDecay::OriginType::NonPrompt) { + // LOG(info) << " --> (Sc0 gen) origin " << static_cast(origin) << ", particle.originMcGen() " << static_cast(particle.originMcGen()) << ", particle.flagMcMatchGen() " << static_cast(particle.flagMcMatchGen()) << ", pdg " << particle.pdgCode(); + //} + + } else if (isScPlusPlusGen || isScStarPlusPlusGen) { /// Generated Σc++ and Λc+ ← Σc++ signals registry.fill(HIST("MC/generated/hPtGenScPlusPlusSig"), ptGenSc, origin, channel); registry.fill(HIST("MC/generated/hEtaGenScPlusPlusSig"), etaGenSc, origin, channel); @@ -630,19 +703,52 @@ struct HfTaskSigmac { registry.fill(HIST("MC/generated/hPtGenLcFromSc0PlusPlusSig"), ptGenLc, origin, channel); registry.fill(HIST("MC/generated/hEtaGenLcFromSc0PlusPlusSig"), etaGenLc, origin, channel); registry.fill(HIST("MC/generated/hPhiGenLcFromSc0PlusPlusSig"), phiGenLc, origin, channel); /// Generated Λc+ ← Σc0,++ signal + if (origin == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("MC/generated/hnSigmaCGen"), ptGenSc, ptGenScBMother, origin, channel, ptGenLc, 2, sigmacSpecies); + } else { + ptGenScBMother = mcParticlesSc.rawIteratorAt(particle.idxBhadMotherPart()).pt(); + registry.fill(HIST("MC/generated/hnSigmaCGen"), ptGenSc, ptGenScBMother, origin, channel, ptGenLc, 2, sigmacSpecies); + } + + // debug -- uncomment if needed + // it should be solved after the implementation of ev. selection for generated SigmaC particles + // if(origin != RecoDecay::OriginType::Prompt && origin != RecoDecay::OriginType::NonPrompt) { + // LOG(info) << " --> (Sc++ gen) origin " << static_cast(origin) << ", particle.originMcGen() " << static_cast(particle.originMcGen()) << ", particle.flagMcMatchGen() " << static_cast(particle.flagMcMatchGen()) << ", pdg " << particle.pdgCode(); + //} } - } /// end loop over generated particles + } /// end loop over Sc generated particles + + /// loop over Lc generated particles + for (const auto& particle : mcParticlesLc) { + if (std::abs(particle.flagMcMatchGen()) != BIT(aod::hf_cand_3prong::DecayType::LcToPKPi)) { + continue; + } + if (yCandGenMax >= 0. && std::abs(RecoDecay::y(particle.pVector(), o2::constants::physics::MassLambdaCPlus)) > yCandGenMax) { + continue; + } + double ptGenLc(-1.), ptGenLcBMother(-1.); + int origin = particle.originMcGen(); + int channel = particle.flagMcDecayChanGen(); + if (origin == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("MC/generated/hnLambdaCGen"), ptGenLc, ptGenLcBMother, origin, channel); + } else { + ptGenLcBMother = mcParticlesLc.rawIteratorAt(particle.idxBhadMotherPart()).pt(); + registry.fill(HIST("MC/generated/hnLambdaCGen"), ptGenLc, ptGenLcBMother, origin, channel); + } + } /// end loop over Lc generated particles /// reconstructed Σc0,++ matched to MC for (const auto& candSc : candidatesSc) { /// Candidate selected as Σc0 and/or Σc++ - if (!(candSc.hfflag() & 1 << aod::hf_cand_sigmac::DecayType::Sc0ToPKPiPi) && !(candSc.hfflag() & 1 << aod::hf_cand_sigmac::DecayType::ScplusplusToPKPiPi)) { + if (!(candSc.hfflag() & BIT(aod::hf_cand_sigmac::DecayType::Sc0ToPKPiPi)) && !(candSc.hfflag() & BIT(aod::hf_cand_sigmac::DecayType::ScplusplusToPKPiPi)) && // Σc0,++(2455) + !(candSc.hfflag() & BIT(aod::hf_cand_sigmac::DecayType::ScStar0ToPKPiPi)) && !(candSc.hfflag() & BIT(aod::hf_cand_sigmac::DecayType::ScStarPlusPlusToPKPiPi))) { // Σc0,++(2520) continue; } /// rapidity selection on Σc0,++ - if (yCandMax >= 0. && std::abs(hfHelper.ySc0(candSc)) > yCandMax && std::abs(hfHelper.yScPlusPlus(candSc)) > yCandMax) { + /// NB: since in data we cannot tag Sc(2455) and Sc(2520), then we use only Sc(2455) for y selection on reconstructed signal + if (yCandRecoMax >= 0. && std::abs(hfHelper.ySc0(candSc)) > yCandRecoMax && std::abs(hfHelper.yScPlusPlus(candSc)) > yCandRecoMax) { continue; } @@ -652,14 +758,28 @@ struct HfTaskSigmac { /// get the candidate Λc+ used to build the Σc0 /// and understand which mass hypotheses are possible const auto& candidateLc = candSc.prongLc_as(); - const int isCandPKPiPiKP = isDecayToPKPiToPiKP(candidateLc, candSc); + const int8_t isCandPKPiPiKP = isDecayToPKPiToPiKP(candidateLc, candSc); // candidateLc.flagMcDecayChanRec(); - /// Reconstructed Σc0 signal - if (std::abs(candSc.flagMcMatchRec()) == 1 << aod::hf_cand_sigmac::DecayType::Sc0ToPKPiPi && (chargeSc == 0)) { + bool isTrueSc0Reco = std::abs(candSc.flagMcMatchRec()) == BIT(aod::hf_cand_sigmac::DecayType::Sc0ToPKPiPi); + bool isTrueScStar0Reco = std::abs(candSc.flagMcMatchRec()) == BIT(aod::hf_cand_sigmac::DecayType::ScStar0ToPKPiPi); + bool isTrueScPlusPlusReco = std::abs(candSc.flagMcMatchRec()) == BIT(aod::hf_cand_sigmac::DecayType::ScplusplusToPKPiPi); + bool isTrueScStarPlusPlusReco = std::abs(candSc.flagMcMatchRec()) == BIT(aod::hf_cand_sigmac::DecayType::ScStarPlusPlusToPKPiPi); + int sigmacSpecies = -1; + if ((isTrueSc0Reco || isTrueScStar0Reco) && (chargeSc == o2::aod::hf_cand_sigmac::ChargeNull)) { + /// Reconstructed Σc0 signal // Get the corresponding MC particle for Sc, found as the mother of the soft pion - auto indexMcScRec = RecoDecay::getMother(mcParticles, candSc.prong1_as().mcParticle(), o2::constants::physics::Pdg::kSigmaC0, true); + int indexMcScRec = -1; + if (isTrueSc0Reco) { + // Σc0(2455) + indexMcScRec = RecoDecay::getMother(mcParticles, candSc.prong1_as().mcParticle(), o2::constants::physics::Pdg::kSigmaC0, true); + sigmacSpecies = o2::aod::hf_cand_sigmac::Sc2455; + } else if (isTrueScStar0Reco) { + // Σc0(2520) + indexMcScRec = RecoDecay::getMother(mcParticles, candSc.prong1_as().mcParticle(), o2::constants::physics::Pdg::kSigmaCStar0, true); + sigmacSpecies = o2::aod::hf_cand_sigmac::Sc2520; + } auto particleSc = mcParticles.rawIteratorAt(indexMcScRec); // Get the corresponding MC particle for Lc auto arrayDaughtersLc = std::array{candidateLc.template prong0_as(), candidateLc.template prong1_as(), candidateLc.template prong2_as()}; @@ -683,7 +803,7 @@ struct HfTaskSigmac { auto channel = candidateLc.flagMcDecayChanRec(); /// 0: direct; 1: Λc± → p± K*; 2: Λc± → Δ(1232)±± K∓; 3: Λc± → Λ(1520) π± /// candidate Λc+ → pK-π+ (and charge conjugate) within the range of M(pK-π+) chosen in the Σc0,++ builder - if ((isCandPKPiPiKP == 1 || isCandPKPiPiKP == 3) && std::abs(candidateLc.template prong0_as().mcParticle().pdgCode()) == kProton) { + if ((TESTBIT(isCandPKPiPiKP, o2::aod::hf_cand_sigmac::Decays::PKPi)) && std::abs(candidateLc.template prong0_as().mcParticle().pdgCode()) == kProton) { massSc = hfHelper.invMassScRecoLcToPKPi(candSc, candidateLc); massLc = hfHelper.invMassLcToPKPi(candidateLc); deltaMass = massSc - massLc; @@ -748,16 +868,16 @@ struct HfTaskSigmac { outputMl.at(0) = candidateLc.mlProbLcToPKPi()[0]; /// bkg score outputMl.at(1) = candidateLc.mlProbLcToPKPi()[2]; /// non-prompt score } - registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), origin, channel, ptSc, std::abs(chargeSc)); + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies); } else { /// fill w/o BDT information - registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc)); + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies); } } } /// end candidate Λc+ → pK-π+ (and charge conjugate) /// candidate Λc+ → π+K-p (and charge conjugate) within the range of M(π+K-p) chosen in the Σc0,++ builder - if ((isCandPKPiPiKP == 2 || isCandPKPiPiKP == 3) && std::abs(candidateLc.template prong0_as().mcParticle().pdgCode()) == kPiPlus) { + if ((TESTBIT(isCandPKPiPiKP, o2::aod::hf_cand_sigmac::Decays::PiKP)) && std::abs(candidateLc.template prong0_as().mcParticle().pdgCode()) == kPiPlus) { massSc = hfHelper.invMassScRecoLcToPiKP(candSc, candidateLc); massLc = hfHelper.invMassLcToPiKP(candidateLc); deltaMass = massSc - massLc; @@ -822,19 +942,28 @@ struct HfTaskSigmac { outputMl.at(0) = candidateLc.mlProbLcToPiKP()[0]; /// bkg score outputMl.at(1) = candidateLc.mlProbLcToPiKP()[2]; /// non-prompt score } - registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), origin, channel, ptSc, std::abs(chargeSc)); + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies); } else { /// fill w/o BDT information - registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc)); + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies); } } } /// end candidate Λc+ → π+K-p (and charge conjugate) /// end reconstructed Σc0 signal - } else if (std::abs(candSc.flagMcMatchRec()) == 1 << aod::hf_cand_sigmac::DecayType::ScplusplusToPKPiPi && (std::abs(chargeSc) == 2)) { + } else if ((isTrueScPlusPlusReco || isTrueScStarPlusPlusReco) && (std::abs(chargeSc) == o2::aod::hf_cand_sigmac::ChargePlusPlus)) { /// Reconstructed Σc++ signal // Get the corresponding MC particle for Sc, found as the mother of the soft pion - auto indexMcScRec = RecoDecay::getMother(mcParticles, candSc.prong1_as().mcParticle(), o2::constants::physics::Pdg::kSigmaCPlusPlus, true); + int indexMcScRec = -1; + if (isTrueScPlusPlusReco) { + // Σc0(2455) + indexMcScRec = RecoDecay::getMother(mcParticles, candSc.prong1_as().mcParticle(), o2::constants::physics::Pdg::kSigmaCPlusPlus, true); + sigmacSpecies = o2::aod::hf_cand_sigmac::Sc2455; + } else if (isTrueScStarPlusPlusReco) { + // Σc0(2520) + indexMcScRec = RecoDecay::getMother(mcParticles, candSc.prong1_as().mcParticle(), o2::constants::physics::Pdg::kSigmaCStarPlusPlus, true); + sigmacSpecies = o2::aod::hf_cand_sigmac::Sc2520; + } auto particleSc = mcParticles.rawIteratorAt(indexMcScRec); // Get the corresponding MC particle for Lc auto arrayDaughtersLc = std::array{candidateLc.template prong0_as(), candidateLc.template prong1_as(), candidateLc.template prong2_as()}; @@ -858,7 +987,7 @@ struct HfTaskSigmac { auto channel = candidateLc.flagMcDecayChanRec(); /// 0: direct; 1: Λc± → p± K*; 2: Λc± → Δ(1232)±± K∓; 3: Λc± → Λ(1520) π± /// candidate Λc+ → pK-π+ (and charge conjugate) within the range of M(pK-π+) chosen in the Σc0,++ builder - if ((isCandPKPiPiKP == 1 || isCandPKPiPiKP == 3) && std::abs(candidateLc.template prong0_as().mcParticle().pdgCode()) == kProton) { + if ((TESTBIT(isCandPKPiPiKP, o2::aod::hf_cand_sigmac::Decays::PKPi)) && std::abs(candidateLc.template prong0_as().mcParticle().pdgCode()) == kProton) { massSc = hfHelper.invMassScRecoLcToPKPi(candSc, candidateLc); massLc = hfHelper.invMassLcToPKPi(candidateLc); deltaMass = massSc - massLc; @@ -923,16 +1052,16 @@ struct HfTaskSigmac { outputMl.at(0) = candidateLc.mlProbLcToPKPi()[0]; /// bkg score outputMl.at(1) = candidateLc.mlProbLcToPKPi()[2]; /// non-prompt score } - registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), origin, channel, ptSc, std::abs(chargeSc)); + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies); } else { /// fill w/o BDT information - registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc)); + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies); } } } /// end candidate Λc+ → pK-π+ (and charge conjugate) /// candidate Λc+ → π+K-p (and charge conjugate) within the range of M(π+K-p) chosen in the Σc0,++ builder - if ((isCandPKPiPiKP == 2 || isCandPKPiPiKP == 3) && std::abs(candidateLc.template prong0_as().mcParticle().pdgCode()) == kPiPlus) { + if ((TESTBIT(isCandPKPiPiKP, o2::aod::hf_cand_sigmac::Decays::PiKP)) && std::abs(candidateLc.template prong0_as().mcParticle().pdgCode()) == kPiPlus) { massSc = hfHelper.invMassScRecoLcToPiKP(candSc, candidateLc); massLc = hfHelper.invMassLcToPiKP(candidateLc); deltaMass = massSc - massLc; @@ -995,15 +1124,15 @@ struct HfTaskSigmac { outputMl.at(0) = candidateLc.mlProbLcToPiKP()[0]; /// bkg score outputMl.at(1) = candidateLc.mlProbLcToPiKP()[2]; /// non-prompt score } - registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), origin, channel, ptSc, std::abs(chargeSc)); + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies); } else { /// fill w/o BDT information - registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc)); + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies); } } } /// end candidate Λc+ → π+K-p (and charge conjugate) - } /// end reconstructed Σc++ signal + } /// end reconstructed Σc++ signal } /// end loop on reconstructed Σc0,++ @@ -1034,10 +1163,10 @@ struct HfTaskSigmac { outputMl.at(0) = candidateLc.mlProbLcToPKPi()[0]; /// bkg score outputMl.at(1) = candidateLc.mlProbLcToPKPi()[2]; /// non-prompt score } - registry.get(HIST("hnLambdaC"))->Fill(ptLc, massLc, outputMl.at(0), outputMl.at(1), origin, channel); + registry.get(HIST("hnLambdaC"))->Fill(ptLc, massLc, outputMl.at(0), outputMl.at(1), origin, channel, candidateLc.ptBhadMotherPart()); } else { /// fill w/o BDT information - registry.get(HIST("hnLambdaC"))->Fill(ptLc, massLc, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel); + registry.get(HIST("hnLambdaC"))->Fill(ptLc, massLc, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, candidateLc.ptBhadMotherPart()); } } if (candidateLc.isSelLcToPiKP() >= 1 && pdgAbs == kPiPlus) { @@ -1050,10 +1179,10 @@ struct HfTaskSigmac { outputMl.at(0) = candidateLc.mlProbLcToPiKP()[0]; /// bkg score outputMl.at(1) = candidateLc.mlProbLcToPiKP()[2]; /// non-prompt score } - registry.get(HIST("hnLambdaC"))->Fill(ptLc, massLc, outputMl.at(0), outputMl.at(1), origin, channel); + registry.get(HIST("hnLambdaC"))->Fill(ptLc, massLc, outputMl.at(0), outputMl.at(1), origin, channel, candidateLc.ptBhadMotherPart()); } else { /// fill w/o BDT information - registry.get(HIST("hnLambdaC"))->Fill(ptLc, massLc, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel); + registry.get(HIST("hnLambdaC"))->Fill(ptLc, massLc, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, candidateLc.ptBhadMotherPart()); } } } diff --git a/PWGHF/D2H/Tasks/taskSigmacToCascade.cxx b/PWGHF/D2H/Tasks/taskSigmacToCascade.cxx new file mode 100644 index 00000000000..279c9322b0e --- /dev/null +++ b/PWGHF/D2H/Tasks/taskSigmacToCascade.cxx @@ -0,0 +1,206 @@ +// 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 taskSigmacToCascade.cxx +/// \brief Task for Σc0,++ → Λc(→ K0sP) + π-,+ analysis +/// \note Here the Lc from the cascade channel is obtained using the task taskLcToK0sP.cxx +/// \author Rutuparna Rath , INFN BOLOGNA and GSI Darmstadt +/// In collaboration with Andrea Alici , INFN BOLOGNA + +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +using namespace o2; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct HfTaskSigmacToCascade { + + Configurable enableTHn{"enableTHn", false, "enable the usage of THn for Σc0, Σc++ and Σc0,++"}; + Configurable selectionFlagLcToK0sP{"selectionFlagLcToK0sP", 1, "Selection Flag for Lc"}; + Configurable selectionFlagLcbarToK0sP{"selectionFlagLcbarToK0sP", 1, "Selection Flag for Lcbar"}; + Configurable etaCandMax{"etaCandMax", -1., "max. cand. pseudorapidity"}; + Configurable> binsPt{"binsPt", std::vector{hf_cuts_lc_to_k0s_p::vecBinsPt}, "pT bin limits"}; + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {16, 0, 16}, ""}; + ConfigurableAxis thnConfigAxisDecLength{"thnConfigAxisDecLength", {10, 0, 0.05}, ""}; + ConfigurableAxis thnConfigAxisDecLengthXY{"thnConfigAxisDecLengthXY", {10, 0, 0.05}, ""}; + ConfigurableAxis thnConfigAxisCPA{"thnConfigAxisCPA", {20, 0.8, 1}, ""}; + ConfigurableAxis thnConfigAxisCPAXY{"thnConfigAxisCPAXY", {20, 0.8, 1}, ""}; + ConfigurableAxis configAxisMassLambdaC{"configAxisMassLambdaC", {600, 1.98, 2.58}, ""}; + ConfigurableAxis configAxisDeltaMassSigmaC{"configAxisDeltaMassSigmaC", {200, 0.13, 0.23}, ""}; + Configurable nSigmaSoftPi{"pionNSigma", 3., "NSigma TPC selection"}; + ConfigurableAxis configAxisChargeSigmaC{"configAxisChargeSigmaC", {3, 0, 3}, "charge of SigmaC"}; + + /// Filter the candidate Λc+ used for the Σc0,++ creation + Filter filterSelectCandidateLc = (aod::hf_sel_candidate_lc_to_k0s_p::isSelLcToK0sP >= selectionFlagLcToK0sP || + aod::hf_sel_candidate_lc_to_k0s_p::isSelLcToK0sP >= selectionFlagLcbarToK0sP); + + using RecoLc = soa::Filtered>; + + HistogramRegistry registry{"registry"}; + HfHelper hfHelper; + + void init(InitContext&) + { + // axes + AxisSpec axisBinsPt = {binsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisPt = {300, 0.0f, 30.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisEta = {500, -2.0f, 2.0f, "#it{#eta}"}; + AxisSpec axisY = {500, -2.0f, 2.0f, "y"}; + AxisSpec axisPhi = {100, 0.f, 6.3f, "#it{#phi}"}; + AxisSpec axisMassCand = {600, 1.98f, 2.58f, "inv. mass (p K_{S}^{0}) (GeV/#it{c}^{2})"}; + AxisSpec axisd0 = {500, -0.5f, 0.5f, "DCAxy (cm)"}; + AxisSpec axisd0V0Daughters = {1000, -5.0f, 5.0f, "DCAxy (cm)"}; + AxisSpec axisV0CPA = {500, 0.98f, 1.0001f, "v0 cos pointing angle"}; + AxisSpec axisV0Radius = {1000, 0.f, 40.f, "V0 radius (cm)"}; + AxisSpec axisV0DCADaughters = {200, 0.f, 2.f, "DCA (cm)"}; + AxisSpec axisMassK0Short = {500, 0.4f, 0.6f, "#it{m}(K_{S}^{0}) (GeV/#it{c}^{2})"}; + AxisSpec axisMassLambda = {500, 1.0f, 1.2f, "#it{m}(#Lambda) (GeV/#it{c}^{2})"}; + AxisSpec axisMassGamma = {500, 0.0f, 0.4f, "#it{m}(#gamma) (GeV/#it{c}^{2})"}; + AxisSpec axisCPACand = {110, -1.1f, 1.1f, "candiate cos pointing angle"}; + AxisSpec axisDecLength = {200, 0.f, 2.0f, "decay length (cm)"}; + AxisSpec axisProperLifetime = {100, 0.f, 0.2f, "#it{c#tau} (cm)"}; + AxisSpec axisProperLifetimeV0 = {1000, 0.f, 80.f, "#it{c#tau} (cm)"}; + AxisSpec axisNSigma = {100, -6.f, 6.f, "n#it{#sigma}_{p}"}; + AxisSpec axisPidP = {100, 0.f, 10.0f, "#it{p} (GeV/#it{c})"}; + const AxisSpec axisDeltaMassSigmaC{configAxisDeltaMassSigmaC, "#it{M}(pK_{S}^{0}#pi) - #it{M}(pK_{S}^{0}) (GeV/#it{c}^{2})"}; + + // data + //////////////////////////////////////////////////////////////////////////// + /// Declare histograms related to Sigma_C analysis from LcToK0sP channel/// + /////////////////////////////////////////////////////////////////////////// + + registry.add("Data/hDeltaMassSc0", "#Sigma_{c}^{0} candidates; #it{M}(K0sP #pi) - #it{M}(K0sP) (GeV/#it{c}^{2}); counts;", {HistType::kTH1D, {{200, 0.13, 0.23}}}); /// Σc0 + registry.add("Data/hDeltaMassScPlusPlus", "#Sigma_{c}^{++} candidates; #it{M}(K0sP#pi) - #it{M}(K0sP) (GeV/#it{c}^{2}); counts;", {HistType::kTH1D, {{200, 0.13, 0.23}}}); /// Σc++ + registry.add("Data/hDeltaMassSc0PlusPlus", "#Sigma_{c}^{0, ++} candidates; #it{M}(K0sP#pi) - #it{M}(K0sP) (GeV/#it{c}^{2}); counts;", {HistType::kTH1D, {{200, 0.13, 0.23}}}); /// Σc0,++ + registry.add("Data/hDeltaMassSc0VsPt", "#Sigma_{c}^{0} candidates; #it{M}(K0sP #pi) - #it{M}(K0sP) (GeV/#it{c}^{2}); #it{p}_{T}(#Sigma_{c}^{0}) (GeV/#it{c});", {HistType::kTH2D, {{200, 0.13, 0.23}, {36, 0., 36.}}}); /// Σc0 + registry.add("Data/hDeltaMassScPlusPlusVsPt", "#Sigma_{c}^{++} candidates; #it{M}(K0sP #pi) - #it{M}(K0sP) (GeV/#it{c}^{2}); #it{p}_{T}(#Sigma_{c}^{++}) (GeV/#it{c});", {HistType::kTH2D, {{200, 0.13, 0.23}, {36, 0., 36.}}}); /// Σc++ + registry.add("Data/hDeltaMassSc0PlusPlusVsPt", "#Sigma_{c}^{0, ++} candidates; #it{M}(K0sP #pi) - #it{M}(K0sP) (GeV/#it{c}^{2}); #it{p}_{T}(#Sigma_{c}^{++}) (GeV/#it{c});", {HistType::kTH2D, {{200, 0.13, 0.23}, {36, 0., 36.}}}); /// Σc0, ++ + registry.add("Data/hEtaSc0", "#Sigma_{c}^{0} candidates; #eta ; counts;", {HistType::kTH1D, {axisEta}}); /// Σc0 + registry.add("Data/hEtaScPlusPlus", "#Sigma_{c}^{++} candidates; #eta ; counts;", {HistType::kTH1D, {axisEta}}); /// Σc++ + registry.add("Data/hEtaSc0PlusPlus", "#Sigma_{c}^{0, ++} candidates; #eta ; counts;", {HistType::kTH1D, {axisEta}}); /// Σc0,++ + registry.add("Data/hEtaSc0PlusPlusVsPt", "#Sigma_{c}^{0, ++} candidates; #eta; #it{p}_{T}(#Sigma_{c}^{0}) (GeV/#it{c});", {HistType::kTH2D, {axisEta, axisPt}}); /// Σc0,++ + registry.add("Data/hYSc0PlusPlusVsPt", "#Sigma_{c}^{0, ++} candidates; y (rapidity); #it{p}_{T}(#Sigma_{c}^{0}) (GeV/#it{c});", {HistType::kTH2D, {axisY, axisPt}}); /// Σc0,++ + registry.add("Data/hPhiSc0", "#Sigma_{c}^{0} candidates; #Phi ; counts;", {HistType::kTH1D, {axisPhi}}); /// Σc0 + registry.add("Data/hPhiScPlusPlus", "#Sigma_{c}^{++} candidates; #Phi ; counts;", {HistType::kTH1D, {axisPhi}}); /// Σc++ + registry.add("Data/hPhiSc0PlusPlus", "#Sigma_{c}^{0, ++} candidates; #Phi ; counts;", {HistType::kTH1D, {axisPhi}}); /// Σc0,++ + + /// softPions + registry.add("Data/hPtSoftPiSc0", "#pi^{-} #leftarrow #Sigma_{c}^{0} candidates; #it{p}_{T}(#pi^{-} #leftarrow #Sigma_{c}^{0}) (GeV/#it{c}); counts;", {HistType::kTH1D, {axisPt}}); /// Σc0 + registry.add("Data/hPtSoftPiScPlusPlus", "#pi^{+} #leftarrow #Sigma_{c}^{++} candidates; #it{p}_{T}(#pi^{+} #leftarrow #Sigma_{c}^{0}) (GeV/#it{c}); counts;", {HistType::kTH1D, {axisPt}}); /// Σc++ + registry.add("Data/hPtSoftPiSc0PlusPlus", "#pi^{#pm} #leftarrow #Sigma_{c}^{0, ++} candidates; #it{p}_{T}(#pi^{#pm} #leftarrow #Sigma_{c}^{0}) (GeV/#it{c}); counts;", {HistType::kTH1D, {axisPt}}); /// Σc0,++ + registry.add("Data/hEtaSoftPiSc0", "#pi^{-} #leftarrow #Sigma_{c}^{0} candidates; #eta ; counts;", {HistType::kTH1D, {axisEta}}); /// Σc0 + registry.add("Data/hEtaSoftPiScPlusPlus", "#pi^{+} #leftarrow #Sigma_{c}^{++} candidates; #eta ; counts;", {HistType::kTH1D, {axisEta}}); /// Σc++ + registry.add("Data/hEtaSoftPiSc0PlusPlus", "#pi^{#pm} #leftarrow #Sigma_{c}^{0, ++} candidates; #eta ; counts;", {HistType::kTH1D, {axisEta}}); /// Σc0,++ + registry.add("Data/hPhiSoftPiSc0", "#pi^{-} #leftarrow #Sigma_{c}^{0} candidates; #Phi ; counts;", {HistType::kTH1D, {axisPhi}}); /// Σc0 + registry.add("Data/hPhiSoftPiScPlusPlus", "#pi^{+} #leftarrow #Sigma_{c}^{++} candidates; #Phi ; counts;", {HistType::kTH1D, {axisPhi}}); /// Σc++ + registry.add("Data/hPhiSoftPiSc0PlusPlus", "#pi^{#pm} #leftarrow #Sigma_{c}^{0, ++} candidates; #Phi ; counts;", {HistType::kTH1D, {axisPhi}}); /// Σc0,++ + + /// THn for candidate Λc+ and Σc0,++ cut variation + if (enableTHn) { + const AxisSpec thnAxisChargeSigmaC{configAxisChargeSigmaC, "charge of SigmaC"}; + const AxisSpec thnAxisMassLambdaC{configAxisMassLambdaC, "inv. mass (K0s p) (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisPtLambdaC{thnConfigAxisPt, "#it{p}_{T}(#Lambda_{c}^{+}) (GeV/#it{c})"}; + const AxisSpec thnAxisPtSigmaC{thnConfigAxisPt, "#it{p}_{T}(#Sigma_{c}^{0,++}) (GeV/#it{c})"}; + const AxisSpec thnAxisDecLength{thnConfigAxisDecLength, "decay length #Lambda_{c}^{+} (cm)"}; + const AxisSpec thnAxisDecLengthXY{thnConfigAxisDecLengthXY, "decay length XY #Lambda_{c}^{+} (cm)"}; + const AxisSpec thnAxisCPA{thnConfigAxisCPA, "cosine of pointing angle #Lambda_{c}^{+}"}; + const AxisSpec thnAxisCPAXY{thnConfigAxisCPAXY, "cosine of pointing angle XY #Lambda_{c}^{+}"}; + registry.add("hnSigmaC0PlusPlus", "THn for Sigmac from Cascade channel", HistType::kTHnSparseF, {thnAxisChargeSigmaC, thnAxisMassLambdaC, thnAxisPtLambdaC, axisDeltaMassSigmaC, thnAxisDecLength, thnAxisDecLengthXY, thnAxisCPA, thnAxisCPAXY, thnAxisPtSigmaC}); + } + } + + void processSigmacToLcPi(aod::HfCandScCascades const& candScs, + RecoLc const&, + aod::Tracks const&) + { + for (const auto& candSc : candScs) { + const auto& candidateLc = candSc.prongLc_as(); + float massSc(-1.), massLc(-1.), deltaMass(-1.); + float ptSc(candSc.pt()), ptLc(candidateLc.pt()); + float etaSc(candSc.eta()) /*, etaLc(candidateLc.eta())*/; + float phiSc(candSc.phi()) /*, phiLc(candidateLc.phi())*/; + float ptSoftPi(candSc.prong1().pt()), etaSoftPi(candSc.prong1().eta()), phiSoftPi(candSc.prong1().phi()); + double decLengthLc(candidateLc.decayLength()), decLengthXYLc(candidateLc.decayLengthXY()); + float cpaLc(candidateLc.cpa()), cpaXYLc(candidateLc.cpaXY()); + float y(-1.); + + massLc = hfHelper.invMassLcToK0sP(candidateLc); + massSc = hfHelper.invMassScRecoLcToK0sP(candSc, candidateLc); + deltaMass = massSc - massLc; + if (candSc.charge() == 0) { + y = hfHelper.ySc0(candSc); + } else if (candSc.charge() == 2) { + y = hfHelper.yScPlusPlus(candSc); + } + registry.fill(HIST("Data/hDeltaMassSc0PlusPlus"), deltaMass); /// Σc(0,++) for both charges + registry.fill(HIST("Data/hDeltaMassSc0PlusPlusVsPt"), deltaMass, ptSc); /// Σc(0,++) for both charges + registry.fill(HIST("Data/hEtaSc0PlusPlus"), etaSc); /// Σc(0,++) for both charges + registry.fill(HIST("Data/hEtaSc0PlusPlusVsPt"), etaSc, ptSc); /// Σc(0,++) for both charges + registry.fill(HIST("Data/hYSc0PlusPlusVsPt"), y, ptSc); /// Σc(0,++) for both charges + registry.fill(HIST("Data/hPhiSc0PlusPlus"), phiSc); /// Σc(0,++) for both charges + + /// fill histograms for softpion from Σc(0,++) + registry.fill(HIST("Data/hPtSoftPiSc0PlusPlus"), ptSoftPi); + registry.fill(HIST("Data/hEtaSoftPiSc0PlusPlus"), etaSoftPi); + registry.fill(HIST("Data/hPhiSoftPiSc0PlusPlus"), phiSoftPi); // π ← Σc0,++ + + if (candSc.charge() == 0) { + registry.fill(HIST("Data/hDeltaMassSc0"), deltaMass); /// Σc0 + registry.fill(HIST("Data/hDeltaMassSc0VsPt"), deltaMass, ptSc); /// Σc0 + registry.fill(HIST("Data/hEtaSc0"), etaSc); /// Σc0 + registry.fill(HIST("Data/hPhiSc0"), phiSc); /// Σc0 + + /// fill histograms for softpion + registry.fill(HIST("Data/hPtSoftPiSc0"), ptSoftPi); + registry.fill(HIST("Data/hEtaSoftPiSc0"), etaSoftPi); + registry.fill(HIST("Data/hPhiSoftPiSc0"), phiSoftPi); // π ← Σc0 + + if (enableTHn) { + registry.get(HIST("hnSigmaC0PlusPlus"))->Fill(candSc.charge(), massLc, ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, ptSc); + } + /// Σc0 + } else if (candSc.charge() == 2) { + registry.fill(HIST("Data/hDeltaMassScPlusPlus"), deltaMass); /// Σc++ + registry.fill(HIST("Data/hDeltaMassScPlusPlusVsPt"), deltaMass, ptSc); /// Σc++ + registry.fill(HIST("Data/hEtaScPlusPlus"), etaSc); /// Σc++ + registry.fill(HIST("Data/hPhiScPlusPlus"), phiSc); /// Σc++ + + /// fill histograms for softpion + registry.fill(HIST("Data/hPtSoftPiScPlusPlus"), ptSoftPi); + registry.fill(HIST("Data/hEtaSoftPiScPlusPlus"), etaSoftPi); + registry.fill(HIST("Data/hPhiSoftPiScPlusPlus"), phiSoftPi); // π ← Σc++ + + if (enableTHn) { + registry.get(HIST("hnSigmaC0PlusPlus"))->Fill(candSc.charge(), massLc, ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, ptSc); + } + } + } + } + PROCESS_SWITCH(HfTaskSigmacToCascade, processSigmacToLcPi, "Process Data", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/Tasks/taskXic.cxx b/PWGHF/D2H/Tasks/taskXic.cxx index fa337ff6265..6ec5e39a687 100644 --- a/PWGHF/D2H/Tasks/taskXic.cxx +++ b/PWGHF/D2H/Tasks/taskXic.cxx @@ -19,6 +19,8 @@ /// \author Himanshu Sharma , University and INFN Padova /// \author Cristina Terrevoli , INFN Bari +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" @@ -56,6 +58,7 @@ struct HfTaskXic { ConfigurableAxis thnConfigAxisCPA{"thnConfigAxisCPA", {20, 0.8, 1}, ""}; ConfigurableAxis thnConfigAxisBdtScoreBkg{"thnConfigAxisBdtScoreBkg", {100, 0., 1.}, ""}; ConfigurableAxis thnConfigAxisBdtScoreSignal{"thnConfigAxisBdtScoreSignal", {100, 0., 1.}, ""}; + ConfigurableAxis thnConfigAxisYMC{"thnConfigAxisYMC", {100, -2., 2.}, ""}; // Service pdg; HfHelper hfHelper; @@ -73,21 +76,28 @@ struct HfTaskXic { HistogramRegistry registry{ "registry", // histo not in pt bins { - {"Data/hPt", "3-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, // pt Xic - {"Data/hEta", "3-prong candidates;candidate #it{eta};entries", {HistType::kTH1F, {{100, -5., 5.}}}}, // eta Xic - {"Data/hPhi", "3-prong candidates;candidate #varphi;entries", {HistType::kTH1F, {{72, 0., constants::math::TwoPI}}}}, // phi Xic - {"Data/hMass", "3-prong candidates; inv. mass (p K #pi) (GeV/#it{c}^{2})", {HistType::kTH1F, {{600, 2.18, 2.58}}}}, // mass Xic - {"Data/hMultiplicity", "multiplicity;multiplicity;entries", {HistType::kTH1F, {{1000, 0., 1000.}}}}, - - {"MC/reconstructed/signal/hPtRecSig", "3-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, // pt Xic - {"MC/reconstructed/background/hPtRecBg", "3-prong candidates (unmatched);#it{p}_{T}^{rec.} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 10.}}}}, - {"MC/generated/hPtGen", "MC particles (matched);#it{p}_{T}^{gen.} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 10.}}}}, - {"MC/generated/hPtGenWithProngsInAcceptance", "MC particles (generated-daughters in acceptance); #it{p}_{T}^{gen.} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 10.}}}}, - {"MC/generated/hEtaGen", "MC particles; #it{eta}^{gen} ;#it{p}_{T}^{gen.};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, - {"MC/generated/hYGen", "MC particles; #it{y}^{gen} ;#it{p}_{T}^{gen.} ;entries", {HistType::kTH1F, {{100, -2., 2.}}}}, - // add generated in acceptance!! - - }}; + {"Data/hPt", "3-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {{360, 0., 36.}}}}, // pt Xic + {"Data/hEta", "3-prong candidates;candidate #it{eta};entries", {HistType::kTH1D, {{100, -2., 2.}}}}, // eta Xic + {"Data/hPhi", "3-prong candidates;candidate #varphi;entries", {HistType::kTH1D, {{72, 0., constants::math::TwoPI}}}}, // phi Xic + {"Data/hMass", "3-prong candidates; inv. mass (p K #pi) (GeV/#it{c}^{2})", {HistType::kTH1D, {{600, 1.98, 2.58}}}}, // mass Xic + {"Data/hMultiplicity", "multiplicity;multiplicity;entries", {HistType::kTH1D, {{1000, 0., 1000.}}}}, + {"MC/generated/signal/hPtGenSig", "3-prong candidates (matched);#it{p}_{T}^{gen.} (GeV/#it{c});entries", {HistType::kTH1D, {{360, 0., 36.}}}}, + {"MC/generated/signal/hPtGen", "MC particles (matched);#it{p}_{T}^{gen.} (GeV/#it{c});entries", {HistType::kTH1D, {{360, 0., 36.}}}}, + {"MC/generated/prompt/hPtGenPrompt", "MC particles (matched, prompt);#it{p}_{T}^{gen.} (GeV/#it{c});entries", {HistType::kTH1D, {{360, 0., 36.}}}}, + {"MC/generated/nonprompt/hPtGenNonPrompt", "MC particles (matched, non-prompt);#it{p}_{T}^{gen.} (GeV/#it{c});entries", {HistType::kTH1D, {{360, 0., 36.}}}}, + {"MC/generated/signal/hEtaGen", "MC particles (matched);#it{#eta};entries", {HistType::kTH1D, {{100, -2., 2.}}}}, + {"MC/generated/prompt/hEtaGenPrompt", "MC particles (matched, prompt);#it{#eta};entries", {HistType::kTH1D, {{100, -2., 2.}}}}, + {"MC/generated/nonprompt/hEtaGenNonPrompt", "MC particles (matched, non-prompt);#it{#eta};entries", {HistType::kTH1D, {{100, -2., 2.}}}}, + {"MC/generated/signal/hYGen", "MC particles (matched);#it{y};entries", {HistType::kTH1D, {{100, -2., 2.}}}}, + {"MC/generated/prompt/hYGenPrompt", "MC particles (matched, prompt);#it{y};entries", {HistType::kTH1D, {{100, -2., 2.}}}}, + {"MC/generated/nonprompt/hYGenNonPrompt", "MC particles (matched, non-prompt);#it{y};entries", {HistType::kTH1D, {{100, -2., 2.}}}}, + {"MC/reconstructed/signal/hMassRecSig", "3-prong candidates (matched);inv. mass (p K #pi) (GeV/#it{c}^{2})", {HistType::kTH1D, {{600, 2.18, 2.58}}}}, + {"MC/reconstructed/prompt/hMassRecSigPrompt", "3-prong candidates (matched, prompt);inv. mass (p K #pi) (GeV/#it{c}^{2})", {HistType::kTH1D, {{600, 2.18, 2.58}}}}, + {"MC/reconstructed/nonprompt/hMassRecSigNonPrompt", "3-prong candidates (matched, non-prompt);inv. mass (p K #pi) (GeV/#it{c}^{2})", {HistType::kTH1D, {{600, 2.18, 2.58}}}}, + {"MC/reconstructed/signal/hPtRecSig", "3-prong candidates (matched);#it{p}_{T}^{rec.} (GeV/#it{c});entries", {HistType::kTH1D, {{360, 0., 36.}}}}, + {"MC/reconstructed/prompt/hPtRecSigPrompt", "3-prong candidates (matched, prompt);#it{p}_{T}^{rec.} (GeV/#it{c});entries", {HistType::kTH1D, {{360, 0., 36.}}}}, + {"MC/reconstructed/nonprompt/hPtRecSigNonPrompt", "3-prong candidates (matched, non-prompt);#it{p}_{T}^{rec.} (GeV/#it{c});entries", {HistType::kTH1D, {{360, 0., 36.}}}}, + {"MC/reconstructed/background/hPtRecBg", "3-prong candidates (unmatched);#it{p}_{T}^{rec.} (GeV/#it{c});entries", {HistType::kTH1D, {{100, 0., 10.}}}}}}; void init(InitContext&) { @@ -174,6 +184,22 @@ struct HfTaskXic { registry.add("MC/reconstructed/signal/hPtProng2RecSig", "3-prong candidates;prong 2 #it{p}_{T} (GeV/#it{c});;entries", {HistType::kTH2F, {{100, 0., 10.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("MC/reconstructed/signal/hChi2PCARecSig", "3-prong candidates;prong Chi2PCA to sec. vertex (cm);; entries", {HistType::kTH2F, {{100, 0, 120}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/reconstructed/signal/hMassVsPtRecSig", "3-prong candidates (matched);inv. mass (p K #pi) (GeV/#it{c}^{2}); p_{T}", {HistType::kTH2F, {{600, 2.18, 2.58}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/reconstructed/prompt/hMassVsPtRecSigPrompt", "3-prong candidates (matched, prompt);inv. mass (p K #pi) (GeV/#it{c}^{2}); p_{T}", {HistType::kTH2F, {{600, 2.18, 2.58}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/reconstructed/nonprompt/hMassVsPtRecSigNonPrompt", "3-prong candidates (matched, non-prompt);inv. mass (p K #pi) (GeV/#it{c}^{2}); p_{T}", {HistType::kTH2F, {{600, 2.18, 2.58}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + + registry.add("MC/reconstructed/signal/hEtaVsPtRecSig", "3-prong candidates (matched);candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/reconstructed/prompt/hEtaVsPtRecSigPrompt", "3-prong candidates (matched, prompt);candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/reconstructed/nonprompt/hEtaVsPtRecSigNonPrompt", "3-prong candidates (matched, non-prompt);candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + + registry.add("MC/generated/signal/hEtaVsPtGenSig", "3-prong candidates (matched);candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/generated/prompt/hEtaVsPtGenSigPrompt", "3-prong candidates (matched, prompt);candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/generated/nonprompt/hEtaVsPtGenSigNonPrompt", "3-prong candidates (matched, non-prompt);candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + + registry.add("MC/generated/signal/hYVsPtGenSig", "3-prong candidates (matched);candidate #it{y};entries", {HistType::kTH2F, {{100, -2., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/generated/prompt/hYVsPtGenSigPrompt", "3-prong candidates (matched, prompt);candidate #it{y};entries", {HistType::kTH2F, {{100, -2., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("MC/generated/nonprompt/hYVsPtGenSigNonPrompt", "3-prong candidates (matched, non-prompt);candidate #it{y};entries", {HistType::kTH2F, {{100, -2., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + // background registry.add("MC/reconstructed/background/hMassBg", "Invariant mass (unmatched);m (p K #pi) (GeV/#it{c}^{2});;entries", {HistType::kTH2F, {{500, 1.6, 3.1}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("MC/reconstructed/background/hDecLengthRecBg", "3-prong candidates;decay length (cm);;entries", {HistType::kTH2F, {{200, 0., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); @@ -198,6 +224,8 @@ struct HfTaskXic { if (enableTHn) { const AxisSpec thnAxisMass{thnConfigAxisMass, "inv. mass (p K #pi) (GeV/#it{c}^{2})"}; const AxisSpec thnAxisPt{thnConfigAxisPt, "#it{p}_{T}(#Xi_{c}^{+}) (GeV/#it{c})"}; + const AxisSpec thnAxisPtMC{thnConfigAxisPt, "#it{p}_{T}(#Xi_{c}^{+} MC) (GeV/#it{c})"}; + const AxisSpec thnAxisYMC{thnConfigAxisYMC, "#it{y}_{MC}(#Xi_{c}^{+} MC)"}; const AxisSpec thnAxisChi2PCA{thnConfigAxisChi2PCA, "Chi2PCA to sec. vertex (cm)"}; const AxisSpec thnAxisDecLength{thnConfigAxisDecLength, "decay length (cm)"}; const AxisSpec thnAxisDecLengthXY{thnConfigAxisDecLengthXY, "decay length (cm)"}; @@ -206,11 +234,12 @@ struct HfTaskXic { const AxisSpec thnAxisBdtScoreXicPrompt{thnConfigAxisBdtScoreSignal, "BDT prompt score (Xic)"}; const AxisSpec thnAxisBdtScoreXicNonPrompt{thnConfigAxisBdtScoreSignal, "BDT non-prompt score (Xic)"}; const AxisSpec thnAxisMcOrigin{3, -0.5, 2.5, "MC origin"}; + const AxisSpec thnAxisMCAllProngAccepted{2, -0.5, 1.5, "All MC prongs accepted"}; if (doprocessDataWithMl || doprocessMcWithMl) { // with ML - registry.add("hnXicVarsWithBdt", "THn for Xic candidates with BDT scores", HistType::kTHnSparseF, {thnAxisMass, thnAxisPt, thnAxisBdtScoreXicBkg, thnAxisBdtScoreXicPrompt, thnAxisBdtScoreXicNonPrompt, thnAxisMcOrigin}); + registry.add("hnXicVarsWithBdt", "THn for Xic candidates with BDT scores", HistType::kTHnSparseF, {thnAxisMass, thnAxisPt, thnAxisBdtScoreXicBkg, thnAxisBdtScoreXicPrompt, thnAxisBdtScoreXicNonPrompt, thnAxisMcOrigin, thnAxisPtMC, thnAxisYMC, thnAxisMCAllProngAccepted}); } else { - registry.add("hnXicVars", "THn for Xic candidates", HistType::kTHnSparseF, {thnAxisMass, thnAxisPt, thnAxisChi2PCA, thnAxisDecLength, thnAxisDecLengthXY, thnAxisCPA, thnAxisMcOrigin}); + registry.add("hnXicVars", "THn for Xic candidates", HistType::kTHnSparseF, {thnAxisMass, thnAxisPt, thnAxisChi2PCA, thnAxisDecLength, thnAxisDecLengthXY, thnAxisCPA, thnAxisMcOrigin, thnAxisPtMC, thnAxisYMC, thnAxisMCAllProngAccepted}); } } } // end init @@ -334,9 +363,9 @@ struct HfTaskXic { outputFD = candidate.mlProbXicToPKPi()[2]; /// non-prompt score } /// Fill the ML outputScores and variables of candidate Xic - registry.get(HIST("hnXicVarsWithBdt"))->Fill(massXic, ptCandidate, outputBkg, outputPrompt, outputFD, 0); + registry.get(HIST("hnXicVarsWithBdt"))->Fill(massXic, ptCandidate, outputBkg, outputPrompt, outputFD, 0, 0.0, 0.0, false); } else { - registry.get(HIST("hnXicVars"))->Fill(massXic, ptCandidate, candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa(), 0); + registry.get(HIST("hnXicVars"))->Fill(massXic, ptCandidate, candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa(), 0, 0.0, 0.0, false); } } if (candidate.isSelXicToPiKP() >= selectionFlagXic) { @@ -348,9 +377,9 @@ struct HfTaskXic { outputFD = candidate.mlProbXicToPiKP()[2]; /// non-prompt score } /// Fill the ML outputScores and variables of candidate - registry.get(HIST("hnXicVarsWithBdt"))->Fill(massXic, ptCandidate, outputBkg, outputPrompt, outputFD, 0); + registry.get(HIST("hnXicVarsWithBdt"))->Fill(massXic, ptCandidate, outputBkg, outputPrompt, outputFD, 0, 0.0, 0.0, false); } else { - registry.get(HIST("hnXicVars"))->Fill(massXic, ptCandidate, candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa(), 0); + registry.get(HIST("hnXicVars"))->Fill(massXic, ptCandidate, candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa(), 0, 0.0, 0.0, false); } } } // thn for Xic @@ -403,16 +432,20 @@ struct HfTaskXic { // Get the corresponding MC particle. auto mcParticleProng0 = candidate.template prong0_as().template mcParticle_as>(); auto pdgCodeProng0 = std::abs(mcParticleProng0.pdgCode()); + auto yProng0 = RecoDecay::y(mcParticleProng0.pVector(), o2::constants::physics::MassXiCPlus); + std::array ptProngs; + std::array etaProngs; // Signal registry.fill(HIST("MC/reconstructed/signal/hPtRecSig"), ptCandidate); // rec. level pT if (massXicToPKPi != 0.) { - registry.fill(HIST("MC/reconstructed/signal/hMassSig"), massXicToPKPi, ptCandidate); + registry.fill(HIST("MC/reconstructed/signal/hMassVsPtRecSig"), massXicToPKPi, ptCandidate); + registry.fill(HIST("MC/reconstructed/signal/hMassRecSig"), massXicToPKPi); } if (massXicToPiKP != 0.) { - registry.fill(HIST("MC/reconstructed/signal/hMassSig"), massXicToPiKP, ptCandidate); + registry.fill(HIST("MC/reconstructed/signal/hMassVsPtRecSig"), massXicToPiKP, ptCandidate); + registry.fill(HIST("MC/reconstructed/signal/hMassRecSig"), massXicToPiKP); } - registry.fill(HIST("MC/reconstructed/signal/hDecLengthRecSig"), candidate.decayLength(), ptCandidate); registry.fill(HIST("MC/reconstructed/signal/hDecLengthXYRecSig"), candidate.decayLengthXY(), ptCandidate); registry.fill(HIST("MC/reconstructed/signal/hNormalisedDecayLengthXYRecSig"), candidate.decayLengthXYNormalised(), ptCandidate); @@ -430,12 +463,46 @@ struct HfTaskXic { registry.fill(HIST("MC/reconstructed/signal/hImpParErrSig"), candidate.errorImpactParameter0(), ptCandidate); registry.fill(HIST("MC/reconstructed/signal/hDecLenErrSig"), candidate.errorDecayLength(), ptCandidate); registry.fill(HIST("MC/reconstructed/signal/hChi2PCARecSig"), candidate.chi2PCA(), ptCandidate); + registry.fill(HIST("MC/reconstructed/signal/hEtaVsPtRecSig"), candidate.eta(), ptCandidate); + + /// reconstructed signal prompt + if (candidate.originMcRec() == RecoDecay::OriginType::Prompt) { + if ((candidate.isSelXicToPKPi() >= selectionFlagXic) && pdgCodeProng0 == kProton) { + registry.fill(HIST("MC/reconstructed/prompt/hMassRecSigPrompt"), massXicToPKPi); + registry.fill(HIST("MC/reconstructed/prompt/hMassVsPtRecSigPrompt"), massXicToPKPi, ptCandidate); + } + if ((candidate.isSelXicToPiKP() >= selectionFlagXic) && pdgCodeProng0 == kPiPlus) { + registry.fill(HIST("MC/reconstructed/prompt/hMassRecSigPrompt"), massXicToPiKP); + registry.fill(HIST("MC/reconstructed/prompt/hMassVsPtRecSigPrompt"), massXicToPiKP, ptCandidate); + } + registry.fill(HIST("MC/reconstructed/prompt/hEtaVsPtRecSigPrompt"), candidate.eta(), ptCandidate); + registry.fill(HIST("MC/reconstructed/prompt/hPtRecSigPrompt"), ptCandidate); + } else { + if ((candidate.isSelXicToPKPi() >= selectionFlagXic) && pdgCodeProng0 == kProton) { + registry.fill(HIST("MC/reconstructed/nonprompt/hMassRecSigNonPrompt"), massXicToPKPi); + registry.fill(HIST("MC/reconstructed/nonprompt/hMassVsPtRecSigNonPrompt"), massXicToPKPi, ptCandidate); + } + if ((candidate.isSelXicToPiKP() >= selectionFlagXic) && pdgCodeProng0 == kPiPlus) { + registry.fill(HIST("MC/reconstructed/nonprompt/hMassRecSigNonPrompt"), massXicToPiKP); + registry.fill(HIST("MC/reconstructed/nonprompt/hMassVsPtRecSigNonPrompt"), massXicToPiKP, ptCandidate); + } + registry.fill(HIST("MC/reconstructed/nonprompt/hEtaVsPtRecSigNonPrompt"), candidate.eta(), ptCandidate); + registry.fill(HIST("MC/reconstructed/nonprompt/hPtRecSigNonPrompt"), ptCandidate); + } if (enableTHn) { double massXic(-1); double outputBkg(-1), outputPrompt(-1), outputFD(-1); + bool allProngsInAcceptance = false; if ((candidate.isSelXicToPKPi() >= selectionFlagXic) && pdgCodeProng0 == kProton) { massXic = hfHelper.invMassXicToPKPi(candidate); + int counter = 0; + for (const auto& daught : mcParticleProng0.template daughters_as>()) { + ptProngs[counter] = daught.pt(); + etaProngs[counter] = daught.eta(); + counter++; + } + allProngsInAcceptance = isProngInAcceptance(etaProngs[0], ptProngs[0]) && isProngInAcceptance(etaProngs[1], ptProngs[1]) && isProngInAcceptance(etaProngs[2], ptProngs[2]); if constexpr (useMl) { if (candidate.mlProbXicToPKPi().size() == 3) { outputBkg = candidate.mlProbXicToPKPi()[0]; /// bkg score @@ -443,13 +510,20 @@ struct HfTaskXic { outputFD = candidate.mlProbXicToPKPi()[2]; /// non-prompt score } /// Fill the ML outputScores and variables of candidate (todo: add multiplicity) - registry.get(HIST("hnXicVarsWithBdt"))->Fill(massXic, ptCandidate, outputBkg, outputPrompt, outputFD, candidate.originMcRec()); + registry.get(HIST("hnXicVarsWithBdt"))->Fill(massXic, ptCandidate, outputBkg, outputPrompt, outputFD, candidate.originMcRec(), mcParticleProng0.pt(), yProng0, allProngsInAcceptance); } else { - registry.get(HIST("hnXicVars"))->Fill(massXic, ptCandidate, candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa(), candidate.originMcRec()); + registry.get(HIST("hnXicVars"))->Fill(massXic, ptCandidate, candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa(), candidate.originMcRec(), mcParticleProng0.pt(), yProng0, allProngsInAcceptance); } } if ((candidate.isSelXicToPiKP() >= selectionFlagXic) && pdgCodeProng0 == kPiPlus) { massXic = hfHelper.invMassXicToPiKP(candidate); + int counter = 0; + for (const auto& daught : mcParticleProng0.template daughters_as>()) { + ptProngs[counter] = daught.pt(); + etaProngs[counter] = daught.eta(); + counter++; + } + allProngsInAcceptance = isProngInAcceptance(etaProngs[0], ptProngs[0]) && isProngInAcceptance(etaProngs[1], ptProngs[1]) && isProngInAcceptance(etaProngs[2], ptProngs[2]); if constexpr (useMl) { if (candidate.mlProbXicToPiKP().size() == 3) { outputBkg = candidate.mlProbXicToPiKP()[0]; /// bkg score @@ -457,9 +531,10 @@ struct HfTaskXic { outputFD = candidate.mlProbXicToPiKP()[2]; /// non-prompt score } /// Fill the ML outputScores and variables of candidate (todo: add multiplicity) - registry.get(HIST("hnXicVarsWithBdt"))->Fill(massXic, ptCandidate, outputBkg, outputPrompt, outputFD, candidate.originMcRec()); + // add here the pT_Mother, y_Mother, level (reco, Gen, Gen + Acc) + registry.get(HIST("hnXicVarsWithBdt"))->Fill(massXic, ptCandidate, outputBkg, outputPrompt, outputFD, candidate.originMcRec(), mcParticleProng0.pt(), yProng0, allProngsInAcceptance); } else { - registry.get(HIST("hnXicVars"))->Fill(massXic, ptCandidate, candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa(), candidate.originMcRec()); + registry.get(HIST("hnXicVars"))->Fill(massXic, ptCandidate, candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa(), candidate.originMcRec(), mcParticleProng0.pt(), yProng0, allProngsInAcceptance); } } } // enable THn @@ -497,36 +572,34 @@ struct HfTaskXic { // MC gen. for (const auto& particle : mcParticles) { if (std::abs(particle.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::XicToPKPi) { - auto yParticle = RecoDecay::y(particle.pVector(), o2::constants::physics::MassXiCPlus); - if (yCandGenMax >= 0. && std::abs(yParticle) > yCandGenMax) { + auto yGen = RecoDecay::y(particle.pVector(), o2::constants::physics::MassXiCPlus); + if (yCandGenMax >= 0. && std::abs(yGen) > yCandGenMax) { continue; } - auto ptParticle = particle.pt(); - std::array ptProngs; - std::array yProngs; - std::array etaProngs; - int counter = 0; - for (const auto& daught : particle.daughters_as>()) { - ptProngs[counter] = daught.pt(); - etaProngs[counter] = daught.eta(); - yProngs[counter] = RecoDecay::y(daught.pVector(), pdg->Mass(daught.pdgCode())); - counter++; + auto ptGen = particle.pt(); + registry.fill(HIST("MC/generated/signal/hPtGen"), ptGen); + registry.fill(HIST("MC/generated/signal/hEtaGen"), particle.eta()); + registry.fill(HIST("MC/generated/signal/hYGen"), yGen); + registry.fill(HIST("MC/generated/signal/hEtaVsPtGenSig"), particle.eta(), ptGen); + registry.fill(HIST("MC/generated/signal/hYVsPtGenSig"), yGen, ptGen); + + if (particle.originMcGen() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("MC/generated/prompt/hPtGenPrompt"), ptGen); + registry.fill(HIST("MC/generated/prompt/hEtaGenPrompt"), particle.eta()); + registry.fill(HIST("MC/generated/prompt/hYGenPrompt"), yGen); + registry.fill(HIST("MC/generated/prompt/hEtaVsPtGenSigPrompt"), particle.eta(), ptGen); + registry.fill(HIST("MC/generated/prompt/hYVsPtGenSigPrompt"), yGen, ptGen); } - - registry.fill(HIST("MC/generated/hPtGen"), ptParticle); - registry.fill(HIST("MC/generated/hEtaGen"), particle.eta(), ptParticle); - registry.fill(HIST("MC/generated/hYGen"), yParticle, ptParticle); - // reject Xic daughters that are not in geometrical acceptance - if (!isProngInAcceptance(etaProngs[0], ptProngs[0]) || !isProngInAcceptance(etaProngs[1], ptProngs[1]) || !isProngInAcceptance(etaProngs[2], ptProngs[2])) { - continue; + if (particle.originMcGen() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("MC/generated/nonprompt/hPtGenNonPrompt"), ptGen); + registry.fill(HIST("MC/generated/nonprompt/hEtaGenNonPrompt"), particle.eta()); + registry.fill(HIST("MC/generated/nonprompt/hYGenNonPrompt"), yGen); + registry.fill(HIST("MC/generated/nonprompt/hEtaVsPtGenSigNonPrompt"), particle.eta(), ptGen); + registry.fill(HIST("MC/generated/nonprompt/hYVsPtGenSigNonPrompt"), yGen, ptGen); } - registry.fill(HIST("MC/generated/hPtGenWithProngsInAcceptance"), ptParticle); - registry.fill(HIST("MC/generated/hYGenWithProngsInAcceptance"), yParticle, ptParticle); - registry.fill(HIST("MC/generated/hEtaGenWithProngsInAcceptance"), particle.eta(), ptParticle); } } } - void processMcStd(soa::Filtered> const& selectedCandidatesMc, soa::Join const& mcParticles, aod::TracksWMc const& tracksWithMc) diff --git a/PWGHF/D2H/Tasks/taskXicToXiPiPi.cxx b/PWGHF/D2H/Tasks/taskXicToXiPiPi.cxx new file mode 100644 index 00000000000..d9958ba459f --- /dev/null +++ b/PWGHF/D2H/Tasks/taskXicToXiPiPi.cxx @@ -0,0 +1,618 @@ +// 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 taskXicToXiPiPi.cxx +/// \brief Ξc± → (Ξ∓ → (Λ → p π∓) π∓) π± π± analysis task +/// \note adapted from taskBs.cxx +/// +/// \author Phil Lennart Stahlhut , Heidelberg University +/// \author Carolina Reetz , Heidelberg University +/// \author Jaeyoon Cho , Inha University + +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// Xic analysis task +struct HfTaskXicToXiPiPi { + Configurable selectionFlagXic{"selectionFlagXic", 1, "Selection Flag for Xic"}; + Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen particle rapidity"}; + Configurable yCandRecoMax{"yCandRecoMax", 0.8, "max. cand. rapidity"}; + Configurable etaTrackMax{"etaTrackMax", 0.8, "max. track pseudo-rapidity"}; + Configurable ptTrackMin{"ptTrackMin", 0.1, "min. track transverse momentum"}; + Configurable> binsPt{"binsPt", std::vector{hf_cuts_xic_to_xi_pi_pi::vecBinsPt}, "pT bin limits"}; + // MC checks + Configurable checkDecayTypeMc{"checkDecayTypeMc", false, "Flag to enable DecayType histogram"}; + // THnSparese for ML selection check + Configurable enableTHn{"enableTHn", false, "Fill THnSparse for Xic"}; + + Service pdg; + + Filter filterSelectCandidates = (aod::hf_sel_candidate_xic::isSelXicToXiPiPi >= selectionFlagXic); + + // Axis + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {400, 0., 40.}, ""}; + ConfigurableAxis thnConfigAxisMass{"thnConfigAxisMass", {300, 1.8, 3.0}, ""}; + ConfigurableAxis thnConfigAxisPtProng{"thnConfigAxisPtProng", {300, 0., 30.}, ""}; + ConfigurableAxis thnConfigAxisChi2PCA{"thnConfigAxisChi2PCA", {200, 0., 20}, ""}; + ConfigurableAxis thnConfigAxisDecLength{"thnConfigAxisDecLength", {200, 0., 0.5}, ""}; + ConfigurableAxis thnConfigAxisDecLengthXY{"thnConfigAxisDecLengthXY", {200, 0., 0.5}, ""}; + ConfigurableAxis thnConfigAxisCPA{"thnConfigAxisCPA", {110, -1.1, 1.1}, ""}; + ConfigurableAxis thnConfigAxisBdtScoreBkg{"thnConfigAxisBdtScoreBkg", {100, 0., 1.}, ""}; + ConfigurableAxis thnConfigAxisBdtScorePrompt{"thnConfigAxisBdtScorePrompt", {100, 0., 1.}, ""}; + ConfigurableAxis thnConfigAxisBdtScoreNonPrompt{"thnConfigAxisBdtScoreNonPrompt", {100, 0., 1.}, ""}; + ConfigurableAxis binsDecLength{"binsDecLength", {200, 0., 0.5}, ""}; + ConfigurableAxis binsErrDecLength{"binsErrDecLength", {100, 0., 1.}, ""}; + ConfigurableAxis binsDCA{"binsDCA", {100, -0.05, 0.05}, ""}; + ConfigurableAxis binsImpParErr{"binsImpParErr", {200, -0.1, 0.1}, ""}; + ConfigurableAxis binsSV{"binsSV", {200, -5., 5.}, ""}; + ConfigurableAxis binsChi2{"binsChi2", {200, 0., 0.1}, ""}; + + HistogramRegistry registry{"registry"}; + + void init(InitContext const&) + { + std::array doprocess{doprocessWithDCAFitter, doprocessWithKFParticle, doprocessWithDCAFitterAndML, doprocessWithKFParticleAndML, doprocessMcWithDCAFitter, doprocessMcWithKFParticle, doprocessMcWithDCAFitterAndML, doprocessMcWithKFParticleAndML}; + if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) == 0) { + LOGP(fatal, "No process function enabled. Please enable one."); + } + if ((doprocessWithDCAFitter || doprocessWithDCAFitterAndML || doprocessMcWithDCAFitter || doprocessMcWithDCAFitterAndML) && (doprocessWithKFParticle || doprocessWithKFParticleAndML || doprocessMcWithKFParticle || doprocessMcWithKFParticleAndML)) { + LOGP(fatal, "Cannot enable DCAFitter and KFParticle at the same time. Please choose one."); + } + if ((doprocessWithDCAFitter || doprocessWithKFParticle || doprocessMcWithDCAFitter || doprocessMcWithKFParticle) && (doprocessWithDCAFitterAndML || doprocessWithKFParticleAndML || doprocessMcWithDCAFitterAndML || doprocessMcWithKFParticleAndML)) { + LOGP(fatal, "Cannot enable process function with ML and process function without ML at the same time. Please choose one."); + } + + static const AxisSpec axisMassXic = {300, 1.8, 3.0, "inv. mass (GeV/#it{c}^{2})"}; + static const AxisSpec axisMassXiRes = {300, 1.4, 2.7, "inv. mass (GeV/#it{c}^{2})"}; + static const AxisSpec axisPt = {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}; + static const AxisSpec axisDecLength = {binsDecLength}; + static const AxisSpec axisErrDecLength = {binsErrDecLength}; + static const AxisSpec axisDCA = {binsDCA}; + static const AxisSpec axisImpParErr = {binsImpParErr}; + static const AxisSpec axisSV = {binsSV}; + static const AxisSpec axisChi2 = {binsChi2}; + + if (doprocessWithDCAFitter || doprocessWithKFParticle || doprocessWithDCAFitterAndML || doprocessWithKFParticleAndML) { + // candidate + registry.add("hPt", "#Xi^{#plus}_{c} candidates;#Xi^{#plus}_{c} candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{400, 0., 40.}}}); + registry.add("hEta", "#Xi^{#plus}_{c} candidates;#Xi^{#plus}_{c} candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, axisPt}}); + registry.add("hRapidity", "#Xi^{#plus}_{c} candidates;#Xi^{#plus}_{c} candidate #it{y};entries", {HistType::kTH2F, {{100, -2., 2.}, axisPt}}); + registry.add("hCPA", "#Xi^{#plus}_{c} candidates;#Xi^{#plus}_{c} candidate cosine of pointing angle;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, axisPt}}); + registry.add("hCPAxy", "#Xi^{#plus}_{c} candidates;#Xi^{#plus}_{c} candidate cosine of pointing angle xy;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, axisPt}}); + registry.add("hMass", "#Xi^{#plus}_{c} candidates;inv. mass #Xi^{#mp} #pi^{#pm} #pi^{#pm} (GeV/#it{c}^{2});#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisMassXic, axisPt}}); + registry.add("hDecLength", "#Xi^{#plus}_{c} candidates;decay length (cm);entries", {HistType::kTH2F, {axisDecLength, axisPt}}); + registry.add("hErrDecLength", "#Xi^{#plus}_{c} candidates;#Xi^{#plus}_{c} candidate decay length error (cm);entries", {HistType::kTH2F, {axisErrDecLength, axisPt}}); + registry.add("hDecLengthXY", "#Xi^{#plus}_{c} candidates;decay length xy (cm);entries", {HistType::kTH2F, {axisDecLength, axisPt}}); + registry.add("hErrDecLengthXY", "#Xi^{#plus}_{c} candidates;#Xi^{#plus}_{c} candidate decay length xy error (cm);entries", {HistType::kTH2F, {axisErrDecLength, axisPt}}); + registry.add("hSVx", "#Xi^{#plus}_{c} candidates;#Xi^{#plus}_{c} candidate secondary vertex position x (cm);entries", {HistType::kTH2F, {axisSV, axisPt}}); + registry.add("hSVy", "#Xi^{#plus}_{c} candidates;#Xi^{#plus}_{c} candidate secondary vertex position y (cm);entries", {HistType::kTH2F, {axisSV, axisPt}}); + registry.add("hSVz", "#Xi^{#plus}_{c} candidates;#Xi^{#plus}_{c} candidate secondary vertex position z (cm);entries", {HistType::kTH2F, {axisSV, axisPt}}); + // daughters + registry.add("hPtProng0", "#Xi^{#plus}_{c} candidates;prong 0 (#Xi^{#mp}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 20.}}}); + registry.add("hPtProng1", "#Xi^{#plus}_{c} candidates;prong 1 (#pi^{#plus}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 20.}}}); + registry.add("hPtProng2", "#Xi^{#plus}_{c} candidates;prong 2 (#pi^{#plus}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 20.}}}); + registry.add("hPtProng0vsPt", "#Xi^{#plus}_{c} candidates;prong 0 (#Xi^{#mp}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{200, 0., 20.}, axisPt}}); + registry.add("hPtProng1vsPt", "#Xi^{#plus}_{c} candidates;prong 1 (#pi^{#pm}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{200, 0., 20.}, axisPt}}); + registry.add("hPtProng2vsPt", "#Xi^{#plus}_{c} candidates;prong 2 (#pi^{#pm}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{200, 0., 20.}, axisPt}}); + registry.add("hCPAXi", "#Xi^{#plus}_{c} candidates;#Xi^{#minus} candidate cosine of pointing angle;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, axisPt}}); + registry.add("hCPAxyXi", "#Xi^{#plus}_{c} candidates;#Xi^{#minus} candidate cosine of pointing angle xy;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, axisPt}}); + registry.add("hCPALambda", "#Xi^{#plus}_{c} candidates;#Lambda candidate cosine of pointing angle;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, axisPt}}); + registry.add("hCPAxyLambda", "#Xi^{#plus}_{c} candidates;#Lambda candidate cosine of pointing angle xy;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, axisPt}}); + registry.add("hd0Prong0", "#Xi^{#plus}_{c} candidates;prong 0 (#Xi^{#mp}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisDCA, axisPt}}); + registry.add("hd0Prong1", "#Xi^{#plus}_{c} candidates;prong 1 (#pi^{#pm}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisDCA, axisPt}}); + registry.add("hd0Prong2", "#Xi^{#plus}_{c} candidates;prong 2 (#pi^{#pm}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisDCA, axisPt}}); + registry.add("hImpParErr", "#Xi^{#plus}_{c} candidates;prongs impact parameter error (cm);entries", {HistType::kTH2F, {axisImpParErr, axisPt}}); + registry.add("hChi2PCA", "#Xi^{#plus}_{c} candidates (matched);sum of distances of the secondary vertex to its prongs;entries", {HistType::kTH2F, {{240, -0.01, 0.5}, axisPt}}); + registry.add("hMassXiPi1", "#Xi^{#plus}_{c} candidates;inv. mass #Xi^{#mp} #pi^{#pm} (prong 1) (GeV/#it{c}^{2});#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisMassXiRes, axisPt}}); + registry.add("hMassXiPi2", "#Xi^{#plus}_{c} candidates;inv. mass #Xi^{#mp} #pi^{#pm} (prong 2) (GeV/#it{c}^{2});#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisMassXiRes, axisPt}}); + // KFParticle + if (doprocessWithKFParticle || doprocessWithKFParticleAndML) { + registry.add("hChi2geoXi", "#Xi^{#plus}_{c} candidates;#Xi^{#mp} #chi^{2}_{geo};entries", {HistType::kTH2F, {axisChi2, axisPt}}); + registry.add("hChi2geoLam", "#Xi^{#plus}_{c} candidates;#Lambda #chi^{2}_{geo};entries", {HistType::kTH2F, {axisChi2, axisPt}}); + registry.add("hChi2topoToPV", "#Xi^{#plus}_{c} candidates;#Xi^{#plus}_{c} candidate #chi^{2}_{topo} to PV;entries", {HistType::kTH2F, {axisChi2, axisPt}}); + registry.add("hChi2topoXiToXicPlus", "#Xi^{#plus}_{c} candidates;#Xi^{#mp} candidate #chi^{2}_{topo} to #Xi^{#plus}_{c};entries", {HistType::kTH2F, {axisChi2, axisPt}}); + } + } + + if (doprocessMcWithDCAFitter || doprocessMcWithKFParticle || doprocessMcWithDCAFitterAndML || doprocessMcWithKFParticleAndML) { + // MC reconstructed + registry.add("hPtGenSig", "#Xi^{#plus}_{c} candidates (gen+rec);candidate #it{p}_{T}^{gen.} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 30.}}}); + registry.add("hPtRecSig", "#Xi^{#plus}_{c} candidates (matched);candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 30.}}}); + registry.add("hPtRecBg", "#Xi^{#plus}_{c} candidates (unmatched);candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 30.}}}); + registry.add("hPtProng0RecSig", "#Xi^{#plus}_{c} candidates (matched);prong 0 (#Xi^{#mp}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 30.}}}); + registry.add("hPtProng0RecBg", "#Xi^{#plus}_{c} candidates (unmatched);prong 0 (#Xi^{#mp}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 30.}}}); + registry.add("hPtProng1RecSig", "#Xi^{#plus}_{c} candidates (matched);prong 1 (#pi^{#pm}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 20.}}}); + registry.add("hPtProng1RecBg", "#Xi^{#plus}_{c} candidates (unmatched);prong 1 (#pi^{#pm}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 20.}}}); + registry.add("hPtProng2RecSig", "#Xi^{#plus}_{c} candidates (matched);prong 2 (#pi^{#pm}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 20.}}}); + registry.add("hPtProng2RecBg", "#Xi^{#plus}_{c} candidates (unmatched);prong 2 (#pi^{#pm}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 20.}}}); + registry.add("hPtProng0vsPtRecSig", "#Xi^{#plus}_{c} candidates (matched);#Xi^{#mp} #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{200, 0., 20.}, axisPt}}); + registry.add("hPtProng0vsPtRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Xi^{#mp} #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{200, 0., 20.}, axisPt}}); + registry.add("hPtProng1vsPtRecSig", "#Xi^{#plus}_{c} candidates (matched);prong 1 (#pi^{#pm}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{200, 0., 20.}, axisPt}}); + registry.add("hPtProng1vsPtRecBg", "#Xi^{#plus}_{c} candidates (unmatched);prong 1 (#pi^{#pm}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{200, 0., 20.}, axisPt}}); + registry.add("hPtProng2vsPtRecSig", "#Xi^{#plus}_{c} candidates (matched);prong 2 (#pi^{#pm}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{200, 0., 20.}, axisPt}}); + registry.add("hPtProng2vsPtRecBg", "#Xi^{#plus}_{c} candidates (unmatched);prong 2 (#pi^{#pm}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{200, 0., 20.}, axisPt}}); + registry.add("hEtaRecSig", "#Xi^{#plus}_{c} candidates (matched);#Xi^{#plus}_{c} candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, axisPt}}); + registry.add("hEtaRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Xi^{#plus}_{c} candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, axisPt}}); + registry.add("hRapidityRecSig", "#Xi^{#plus}_{c} candidates (matched);#Xi^{#plus}_{c} candidate #it{y};entries", {HistType::kTH2F, {{100, -2., 2.}, axisPt}}); + registry.add("hRapidityRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Xi^{#plus}_{c} candidate #it{y};entries", {HistType::kTH2F, {{100, -2., 2.}, axisPt}}); + registry.add("hSVxRecSig", "#Xi^{#plus}_{c} candidates (matched);#Xi^{#plus}_{c} candidate secondary vertex position x (cm);entries", {HistType::kTH2F, {axisSV, axisPt}}); + registry.add("hSVxRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Xi^{#plus}_{c} candidate secondary vertex position x (cm);entries", {HistType::kTH2F, {axisSV, axisPt}}); + registry.add("hSVyRecSig", "#Xi^{#plus}_{c} candidates (matched);#Xi^{#plus}_{c} candidate secondary vertex position y (cm);entries", {HistType::kTH2F, {axisSV, axisPt}}); + registry.add("hSVyRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Xi^{#plus}_{c} candidate secondary vertex position y (cm);entries", {HistType::kTH2F, {axisSV, axisPt}}); + registry.add("hSVzRecSig", "#Xi^{#plus}_{c} candidates (matched);#Xi^{#plus}_{c} candidate secondary vertex position z (cm);entries", {HistType::kTH2F, {axisSV, axisPt}}); + registry.add("hSVzRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Xi^{#plus}_{c} candidate secondary vertex position z (cm);entries", {HistType::kTH2F, {axisSV, axisPt}}); + registry.add("hCPARecSig", "#Xi^{#plus}_{c} candidates (matched);#Xi^{#plus}_{c} candidate cosine of pointing angle;entries", {HistType::kTH2F, {{220, -1.1, 1.1}, axisPt}}); + registry.add("hCPARecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Xi^{#plus}_{c} candidate cosine of pointing angle;entries", {HistType::kTH2F, {{220, -1.1, 1.1}, axisPt}}); + registry.add("hCPAxyRecSig", "#Xi^{#plus}_{c} candidates (matched);#Xi^{#plus}_{c} candidate CPAxy;entries", {HistType::kTH2F, {{220, -1.1, 1.1}, axisPt}}); + registry.add("hCPAxyRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Xi^{#plus}_{c} candidate CPAxy;entries", {HistType::kTH2F, {{220, -1.1, 1.1}, axisPt}}); + registry.add("hMassRecSig", "#Xi^{#plus}_{c} candidates (matched);inv. mass #Xi^{#mp} #pi^{#pm} #pi^{#pm} (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{300, 1.8, 3.0}, axisPt}}); + registry.add("hMassRecBg", "#Xi^{#plus}_{c} candidates (unmatched);inv. mass #Xi^{#mp} #pi^{#pm} #pi^{#pm} (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{300, 1.8, 3.0}, axisPt}}); + registry.add("hDecLengthRecSig", "#Xi^{#plus}_{c} candidates (matched);#Xi^{#plus}_{c} candidate decay length (cm);entries", {HistType::kTH2F, {axisDecLength, axisPt}}); + registry.add("hDecLengthRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Xi^{#plus}_{c} candidate decay length (cm);entries", {HistType::kTH2F, {axisDecLength, axisPt}}); + registry.add("hErrDecLengthRecSig", "#Xi^{#plus}_{c} candidates (matched);#Xi^{#plus}_{c} candidate decay length (cm);entries", {HistType::kTH2F, {axisErrDecLength, axisPt}}); + registry.add("hErrDecLengthRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Xi^{#plus}_{c} candidate decay length (cm);entries", {HistType::kTH2F, {axisErrDecLength, axisPt}}); + registry.add("hDecLengthXYRecSig", "#Xi^{#plus}_{c} candidates (matched);#Xi^{#plus}_{c} candidate decay length xy (cm);entries", {HistType::kTH2F, {axisDecLength, axisPt}}); + registry.add("hDecLengthXYRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Xi^{#plus}_{c} candidate decay length xy(cm);entries", {HistType::kTH2F, {axisDecLength, axisPt}}); + registry.add("hErrDecLengthXYRecSig", "#Xi^{#plus}_{c} candidates (matched);#Xi^{#plus}_{c} candidate decay length xy (cm);entries", {HistType::kTH2F, {axisErrDecLength, axisPt}}); + registry.add("hErrDecLengthXYRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Xi^{#plus}_{c} candidate decay length xy(cm);entries", {HistType::kTH2F, {axisErrDecLength, axisPt}}); + registry.add("hd0Prong0RecSig", "#Xi^{#plus}_{c} candidates (matched);prong 0 (#Xi^{#mp}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisDCA, axisPt}}); + registry.add("hd0Prong0RecBg", "#Xi^{#plus}_{c} candidates (unmatched);prong 0 (#Xi^{#mp}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisDCA, axisPt}}); + registry.add("hd0Prong1RecSig", "#Xi^{#plus}_{c} candidates (matched);prong 1 (#pi^{#pm}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisDCA, axisPt}}); + registry.add("hd0Prong1RecBg", "#Xi^{#plus}_{c} candidates (unmatched);prong 1 (#pi^{#pm}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisDCA, axisPt}}); + registry.add("hd0Prong2RecSig", "#Xi^{#plus}_{c} candidates (matched);prong 2 (#pi^{#pm}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisDCA, axisPt}}); + registry.add("hd0Prong2RecBg", "#Xi^{#plus}_{c} candidates (unmatched);prong 2 (#pi^{#pm}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisDCA, axisPt}}); + registry.add("hImpParErrRecSig", "#Xi^{#plus}_{c} candidates (matched);prongs impact parameter error (cm);entries", {HistType::kTH2F, {axisImpParErr, axisPt}}); + registry.add("hImpParErrRecBg", "#Xi^{#plus}_{c} candidates (unmatched);prongs impact parameter error (cm);entries", {HistType::kTH2F, {axisImpParErr, axisPt}}); + registry.add("hChi2PCARecSig", "#Xi^{#plus}_{c} candidates (matched);sum of distances of the secondary vertex to its prongs;entries", {HistType::kTH2F, {{240, -0.01, 0.1}, axisPt}}); + registry.add("hChi2PCARecBg", "#Xi^{#plus}_{c} candidates (unmatched);sum of distances of the secondary vertex to its prongs;entries", {HistType::kTH2F, {{240, -0.01, 0.1}, axisPt}}); + registry.add("hCPAXiRecSig", "#Xi^{#plus}_{c} candidates (matched);#Xi^{#minus} cosine of pointing angle;entries", {HistType::kTH2F, {{220, -1.1, 1.1}, axisPt}}); + registry.add("hCPAXiRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Xi^{#minus} cosine of pointing angle;entries", {HistType::kTH2F, {{220, -1.1, 1.1}, axisPt}}); + registry.add("hCPAxyXiRecSig", "#Xi^{#plus}_{c} candidates (matched);#Xi^{#minus} candidate cosine of pointing angle xy;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, axisPt}}); + registry.add("hCPAxyXiRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Xi^{#minus} candidate cosine of pointing angle xy;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, axisPt}}); + registry.add("hCPALambdaRecSig", "#Xi^{#plus}_{c} candidates (matched);#Lambda candidate cosine of pointing angle;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, axisPt}}); + registry.add("hCPALambdaRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Lambda candidate cosine of pointing angle;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, axisPt}}); + registry.add("hCPAxyLambdaRecSig", "#Xi^{#plus}_{c} candidates (matched);#Lambda candidate cosine of pointing angle xy;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, axisPt}}); + registry.add("hCPAxyLambdaRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Lambda candidate cosine of pointing angle xy;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, axisPt}}); + registry.add("hMassXiPi1RecSig", "#Xi^{#plus}_{c} candidates (matched);inv. mass #Xi^{#mp} #pi^{#pm} (prong 1) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{300, 1.0, 2.0}, axisPt}}); + registry.add("hMassXiPi1RecBg", "#Xi^{#plus}_{c} candidates (unmatched);inv. mass #Xi^{#mp} #pi^{#pm} (prong 1) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{300, 1.0, 2.0}, axisPt}}); + registry.add("hMassXiPi2RecSig", "#Xi^{#plus}_{c} candidates (matched);inv. mass #Xi^{#mp} #pi^{#pm} (prong 2) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{300, 1.0, 2.0}, axisPt}}); + registry.add("hMassXiPi2RecBg", "#Xi^{#plus}_{c} candidates (unmatched);inv. mass #Xi^{#mp} #pi^{#pm} (prong 2) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{300, 1.0, 2.0}, axisPt}}); + // MC reconstructed with KFParticle + if (doprocessMcWithKFParticle || doprocessMcWithKFParticleAndML) { + registry.add("hChi2topoToPVRecSig", "#Xi^{#plus}_{c} candidates (matched);#Xi^{#plus}_{c} candidate #chi^{2}_{topo} to PV;entries", {HistType::kTH2F, {axisChi2, axisPt}}); + registry.add("hChi2topoToPVRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Xi^{#plus}_{c} candidate #chi^{2}_{topo} to PV;entries", {HistType::kTH2F, {axisChi2, axisPt}}); + registry.add("hChi2geoXiRecSig", "#Xi^{#plus}_{c} candidates (matched);#Xi^{#mp} #chi^{2}_{geo};entries", {HistType::kTH2F, {axisChi2, axisPt}}); + registry.add("hChi2geoXiRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Xi^{#mp} #chi^{2}_{geo};entries", {HistType::kTH2F, {axisChi2, axisPt}}); + registry.add("hChi2geoLamRecSig", "#Xi^{#plus}_{c} candidates (matched);#Lambda #chi^{2}_{geo};entries", {HistType::kTH2F, {axisChi2, axisPt}}); + registry.add("hChi2geoLamRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Lambda #chi^{2}_{geo};entries", {HistType::kTH2F, {axisChi2, axisPt}}); + registry.add("hChi2topoXiToXicPlusRecSig", "#Xi^{#plus}_{c} candidates (matched);#Xi^{#mp} candidate #chi^{2}_{topo} to #Xi^{#plus}_{c};entries", {HistType::kTH2F, {axisChi2, axisPt}}); + registry.add("hChi2topoXiToXicPlusRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#Xi^{#mp} candidate #chi^{2}_{topo} to #Xi^{#plus}_{c};entries", {HistType::kTH2F, {axisChi2, axisPt}}); + } + // MC generated + registry.add("hPtProng0Gen", "MC particles (generated);prong 0 (#Xi^{#mp}) #it{p}_{T}^{gen} (GeV/#it{c});entries", {HistType::kTH2F, {{300, 0., 30.}, axisPt}}); + registry.add("hPtProng1Gen", "MC particles (generated);prong 1 (#pi^{#pm}) #it{p}_{T}^{gen} (GeV/#it{c});entries", {HistType::kTH2F, {{200, 0., 20.}, axisPt}}); + registry.add("hPtProng2Gen", "MC particles (generated);prong 2 (#pi^{#pm}) #it{p}_{T}^{gen} (GeV/#it{c});entries", {HistType::kTH2F, {{200, 0., 20.}, axisPt}}); + registry.add("hEtaProng0Gen", "MC particles (generated);prong 0 (#Xi^{#mp}) #it{#eta}^{gen};entries", {HistType::kTH2F, {{100, -2, 2}, axisPt}}); + registry.add("hEtaProng1Gen", "MC particles (generated);prong 1 (#pi^{#pm}) #it{#eta}^{gen};entries", {HistType::kTH2F, {{100, -2, 2}, axisPt}}); + registry.add("hEtaProng2Gen", "MC particles (generated);prong 2 (#pi^{#pm}) #it{#eta}^{gen};entries", {HistType::kTH2F, {{100, -2, 2}, axisPt}}); + registry.add("hYProng0Gen", "MC particles (generated);prong 0 (#Xi^{#mp}) #it{y}^{gen};entries", {HistType::kTH2F, {{100, -2, 2}, axisPt}}); + registry.add("hYProng1Gen", "MC particles (generated);prong 1 (#pi^{#pm}) #it{y}^{gen};entries", {HistType::kTH2F, {{100, -2, 2}, axisPt}}); + registry.add("hYProng2Gen", "MC particles (generated);prong 2 (#pi^{#pm}) #it{y}^{gen};entries", {HistType::kTH2F, {{100, -2, 2}, axisPt}}); + registry.add("hPtGen", "MC particles (generated);candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 30.}}}); + registry.add("hEtaGen", "MC particles (generated);#Xi^{#plus}_{c} candidate #it{#eta}^{gen};entries", {HistType::kTH2F, {{100, -2., 2.}, axisPt}}); + registry.add("hYGen", "MC particles (generated);#Xi^{#plus}_{c} candidate #it{y}^{gen};entries", {HistType::kTH2F, {{100, -2., 2.}, axisPt}}); + registry.add("hSVxGen", "#Xi^{#plus}_{c} candidates (generated);#Xi^{#plus}_{c} candidate secondary vertex position x (cm);entries", {HistType::kTH2F, {axisSV, axisPt}}); + registry.add("hSVyGen", "#Xi^{#plus}_{c} candidates (generated);#Xi^{#plus}_{c} candidate secondary vertex position y (cm);entries", {HistType::kTH2F, {axisSV, axisPt}}); + registry.add("hSVzGen", "#Xi^{#plus}_{c} candidates (generated);#Xi^{#plus}_{c} candidate secondary vertex position z (cm);entries", {HistType::kTH2F, {axisSV, axisPt}}); + registry.add("hPtGenWithProngsInAcceptance", "MC particles (generated-daughters in acceptance);candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 30.}}}); + registry.add("hEtaGenWithProngsInAcceptance", "MC particles (generated-daughters in acceptance);#Xi^{#plus}_{c} candidate #it{#eta}^{gen};entries", {HistType::kTH2F, {{100, -2., 2.}, axisPt}}); + registry.add("hYGenWithProngsInAcceptance", "MC particles (generated-daughters in acceptance);#Xi^{#plus}_{c} candidate #it{y}^{gen};entries", {HistType::kTH2F, {{100, -2., 2.}, axisPt}}); + } + + if (checkDecayTypeMc) { + constexpr uint8_t kNBinsDecayTypeMc = hf_cand_xic_to_xi_pi_pi::DecayType::NDecayType + 1; + TString labels[kNBinsDecayTypeMc]; + labels[hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiPiPi] = "#Xi^{+}_{c} #rightarrow #Xi^{#minus} #pi^{#plus}) #pi^{#plus}"; + labels[hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiResPiToXiPiPi] = "#Xi^{+}_{c} #rightarrow #Xi(1530)^{0} #pi^{#plus} #rightarrow #Xi^{#minus} #pi^{#plus}) #pi^{#plus}"; + labels[hf_cand_xic_to_xi_pi_pi::DecayType::NDecayType] = "Other decays"; + static const AxisSpec axisDecayType = {kNBinsDecayTypeMc, 0.5, kNBinsDecayTypeMc + 0.5, ""}; + registry.add("hDecayTypeMc", "DecayType", {HistType::kTH3F, {axisDecayType, axisMassXic, axisPt}}); + for (uint8_t iBin = 0; iBin < kNBinsDecayTypeMc; ++iBin) { + registry.get(HIST("hDecayTypeMc"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin]); + } + } + + if (enableTHn) { + const AxisSpec thnAxisPt{thnConfigAxisPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisMass{thnConfigAxisMass, "inv. mass #Xi^{#mp} #pi^{#pm} #pi^{#pm}"}; + const AxisSpec thnAxisChi2PCA{thnConfigAxisChi2PCA, "Chi2PCA to sec. vertex (cm)"}; + const AxisSpec thnAxisDecLength{thnConfigAxisDecLength, "decay length (cm)"}; + const AxisSpec thnAxisDecLengthXY{thnConfigAxisDecLengthXY, "decay length xy (cm)"}; + const AxisSpec thnAxisCPA{thnConfigAxisCPA, "#Xi^{#plus}_{c} candidate cosine of pointing angle"}; + const AxisSpec thnAxisBdtScoreBkg{thnConfigAxisBdtScoreBkg, "BDT score of background"}; + const AxisSpec thnAxisBdtScorePrompt{thnConfigAxisBdtScorePrompt, "BDT score of prompt #Xi^{#plus}_{c}"}; + const AxisSpec thnAxisBdtScoreNonPrompt{thnConfigAxisBdtScoreNonPrompt, "BDT score of non-prompt #Xi^{#plus}_{c}"}; + + if (doprocessWithKFParticleAndML || doprocessWithDCAFitterAndML || doprocessMcWithKFParticleAndML || doprocessMcWithDCAFitterAndML) { + // with ML information + registry.add("hXicToXiPiPiVarsWithML", "THnSparse for Xic with ML", HistType::kTHnSparseF, {thnAxisPt, thnAxisMass, thnAxisChi2PCA, thnAxisDecLength, thnAxisDecLengthXY, thnAxisCPA, thnAxisBdtScoreBkg, thnAxisBdtScorePrompt, thnAxisBdtScoreNonPrompt}); + } else { + // without ML information + registry.add("hXicToXiPiPiVars", "THnSparse for Xic", HistType::kTHnSparseF, {thnAxisPt, thnAxisMass, thnAxisChi2PCA, thnAxisDecLength, thnAxisDecLengthXY, thnAxisCPA}); + } + } // enable THnSpare + } // end init + + /// Fill THnSpare depending on whether ML selection is used + // \param candidate is candidate + template + void fillTHnSparse(const T1& candidate) + { + if (!enableTHn) { + return; + } + + if constexpr (useMl) { + // with ML information + double outputBkg = -99.; // bkg score + double outputPrompt = -99.; // prompt score + double outputFD = -99.; // non-prompt score + int scoreSize = candidate.mlProbXicToXiPiPi().size(); + if (scoreSize > 0) { + outputBkg = candidate.mlProbXicToXiPiPi()[0]; + outputPrompt = candidate.mlProbXicToXiPiPi()[1]; + if (scoreSize == 3) { + outputFD = candidate.mlProbXicToXiPiPi()[2]; + } + } + registry.get(HIST("hXicToXiPiPiVarsWithML"))->Fill(candidate.pt(), candidate.invMassXicPlus(), candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa(), outputBkg, outputPrompt, outputFD); + } else { + // without ML information + registry.get(HIST("hXicToXiPiPiVars"))->Fill(candidate.pt(), candidate.invMassXicPlus(), candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa()); + } + } + + /// Selection of Xic daughter in geometrical acceptance + /// \param etaProng is the pseudorapidity of Xic prong + /// \param ptProng is the pT of Xic prong + /// \return true if prong is in geometrical acceptance + template + bool isProngInAcceptance(const T& etaProng, const T& ptProng) + { + return std::abs(etaProng) <= etaTrackMax && ptProng >= ptTrackMin; + } + + /// Function to fill histograms + template + void fillHistograms(TCanTable const& candidates) + { + for (const auto& candidate : candidates) { + auto yCandXic = candidate.y(o2::constants::physics::MassXiCPlus); + if (yCandRecoMax >= 0. && std::abs(yCandXic) > yCandRecoMax) { + continue; + } + + auto ptCandXic = candidate.pt(); + + registry.fill(HIST("hPt"), ptCandXic); + registry.fill(HIST("hPtProng0"), candidate.ptProng0()); + registry.fill(HIST("hPtProng1"), candidate.ptProng1()); + registry.fill(HIST("hPtProng2"), candidate.ptProng2()); + registry.fill(HIST("hEta"), candidate.eta(), ptCandXic); + registry.fill(HIST("hRapidity"), yCandXic, ptCandXic); + registry.fill(HIST("hCPA"), candidate.cpa(), ptCandXic); + registry.fill(HIST("hCPAxy"), candidate.cpaXY(), ptCandXic); + registry.fill(HIST("hMass"), candidate.invMassXicPlus(), ptCandXic); + registry.fill(HIST("hDecLength"), candidate.decayLength(), ptCandXic); + registry.fill(HIST("hErrDecLength"), candidate.errorDecayLength(), ptCandXic); + registry.fill(HIST("hDecLengthXY"), candidate.decayLengthXY(), ptCandXic); + registry.fill(HIST("hErrDecLengthXY"), candidate.errorDecayLengthXY(), ptCandXic); + registry.fill(HIST("hSVx"), candidate.xSecondaryVertex(), ptCandXic); + registry.fill(HIST("hSVy"), candidate.ySecondaryVertex(), ptCandXic); + registry.fill(HIST("hSVz"), candidate.zSecondaryVertex(), ptCandXic); + registry.fill(HIST("hPtProng0vsPt"), candidate.ptProng0(), ptCandXic); + registry.fill(HIST("hPtProng1vsPt"), candidate.ptProng1(), ptCandXic); + registry.fill(HIST("hPtProng2vsPt"), candidate.ptProng2(), ptCandXic); + registry.fill(HIST("hd0Prong0"), candidate.impactParameter0(), ptCandXic); + registry.fill(HIST("hd0Prong1"), candidate.impactParameter1(), ptCandXic); + registry.fill(HIST("hd0Prong2"), candidate.impactParameter2(), ptCandXic); + registry.fill(HIST("hImpParErr"), candidate.errorImpactParameter0(), ptCandXic); + registry.fill(HIST("hImpParErr"), candidate.errorImpactParameter1(), ptCandXic); + registry.fill(HIST("hImpParErr"), candidate.errorImpactParameter2(), ptCandXic); + registry.fill(HIST("hChi2PCA"), candidate.chi2PCA(), ptCandXic); + registry.fill(HIST("hCPAXi"), candidate.cosPaXi(), ptCandXic); + registry.fill(HIST("hCPAxyXi"), candidate.cosPaXYXi(), ptCandXic); + registry.fill(HIST("hCPALambda"), candidate.cosPaLambda(), ptCandXic); + registry.fill(HIST("hCPAxyLambda"), candidate.cosPaLambda(), ptCandXic); + registry.fill(HIST("hMassXiPi1"), candidate.invMassXiPi0(), ptCandXic); + registry.fill(HIST("hMassXiPi2"), candidate.invMassXiPi1(), ptCandXic); + + // fill KFParticle specific histograms + if constexpr (useKfParticle) { + registry.fill(HIST("hChi2topoToPV"), candidate.chi2TopoXicPlusToPV(), ptCandXic); + registry.fill(HIST("hChi2topoXiToXicPlus"), candidate.chi2TopoXiToXicPlus(), ptCandXic); + registry.fill(HIST("hChi2geoXi"), candidate.kfCascadeChi2(), ptCandXic); + registry.fill(HIST("hChi2geoLam"), candidate.kfV0Chi2(), ptCandXic); + } + + // fill THnSparse + if (enableTHn) { + if constexpr (useMl) { + fillTHnSparse(candidate); + } else { + fillTHnSparse(candidate); + } + } + } // candidate loop + } + + /// Function for MC analysis and histogram filling + template + void fillHistogramsMc(TCandTable const& candidates, + soa::Join const& mcParticles, + aod::TracksWMc const&) + { + std::vector arrDaughIndex; + + // MC rec + for (const auto& candidate : candidates) { + auto yCandXic = candidate.y(o2::constants::physics::MassXiCPlus); + if (yCandRecoMax >= 0. && std::abs(yCandXic) > yCandRecoMax) { + continue; + } + + auto ptCandXic = candidate.pt(); + int flagMcMatchRecXic = std::abs(candidate.flagMcMatchRec()); + + if (TESTBIT(flagMcMatchRecXic, hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiPiPi) || TESTBIT(flagMcMatchRecXic, hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiResPiToXiPiPi)) { + auto indexMother = RecoDecay::getMother(mcParticles, candidate.template pi0_as().template mcParticle_as>(), o2::constants::physics::Pdg::kXiCPlus, true); + auto particleMother = mcParticles.rawIteratorAt(indexMother); + + registry.fill(HIST("hPtGenSig"), particleMother.pt()); + registry.fill(HIST("hPtRecSig"), ptCandXic); + registry.fill(HIST("hPtProng0RecSig"), candidate.ptProng0()); + registry.fill(HIST("hPtProng1RecSig"), candidate.ptProng1()); + registry.fill(HIST("hPtProng2RecSig"), candidate.ptProng2()); + registry.fill(HIST("hPtProng0vsPtRecSig"), candidate.ptProng0(), ptCandXic); + registry.fill(HIST("hPtProng1vsPtRecSig"), candidate.ptProng1(), ptCandXic); + registry.fill(HIST("hPtProng2vsPtRecSig"), candidate.ptProng2(), ptCandXic); + registry.fill(HIST("hEtaRecSig"), candidate.eta(), ptCandXic); + registry.fill(HIST("hRapidityRecSig"), yCandXic, ptCandXic); + registry.fill(HIST("hSVxRecSig"), candidate.xSecondaryVertex(), ptCandXic); + registry.fill(HIST("hSVyRecSig"), candidate.ySecondaryVertex(), ptCandXic); + registry.fill(HIST("hSVzRecSig"), candidate.zSecondaryVertex(), ptCandXic); + registry.fill(HIST("hCPARecSig"), candidate.cpa(), ptCandXic); + registry.fill(HIST("hCPAxyRecSig"), candidate.cpaXY(), ptCandXic); + registry.fill(HIST("hMassRecSig"), candidate.invMassXicPlus(), ptCandXic); + registry.fill(HIST("hDecLengthRecSig"), candidate.decayLength(), ptCandXic); + registry.fill(HIST("hErrDecLengthRecSig"), candidate.errorDecayLength(), ptCandXic); + registry.fill(HIST("hDecLengthXYRecSig"), candidate.decayLengthXY(), ptCandXic); + registry.fill(HIST("hErrDecLengthXYRecSig"), candidate.errorDecayLengthXY(), ptCandXic); + registry.fill(HIST("hd0Prong0RecSig"), candidate.impactParameter0(), ptCandXic); + registry.fill(HIST("hd0Prong1RecSig"), candidate.impactParameter1(), ptCandXic); + registry.fill(HIST("hd0Prong2RecSig"), candidate.impactParameter2(), ptCandXic); + registry.fill(HIST("hImpParErrRecSig"), candidate.errorImpactParameter0(), ptCandXic); + registry.fill(HIST("hImpParErrRecSig"), candidate.errorImpactParameter1(), ptCandXic); + registry.fill(HIST("hImpParErrRecSig"), candidate.errorImpactParameter2(), ptCandXic); + registry.fill(HIST("hChi2PCARecSig"), candidate.chi2PCA(), ptCandXic); + registry.fill(HIST("hCPAXiRecSig"), candidate.cosPaXi(), ptCandXic); + registry.fill(HIST("hCPAxyXiRecSig"), candidate.cosPaXYXi(), ptCandXic); + registry.fill(HIST("hCPALambdaRecSig"), candidate.cosPaLambda(), ptCandXic); + registry.fill(HIST("hCPAxyLambdaRecSig"), candidate.cosPaLambda(), ptCandXic); + + // fill KFParticle specific histograms + if constexpr (useKfParticle) { + registry.fill(HIST("hChi2topoToPVRecSig"), candidate.chi2TopoXicPlusToPV(), ptCandXic); + registry.fill(HIST("hChi2topoXiToXicPlusRecSig"), candidate.chi2TopoXiToXicPlus(), ptCandXic); + registry.fill(HIST("hChi2geoXiRecSig"), candidate.kfCascadeChi2(), ptCandXic); + registry.fill(HIST("hChi2geoLamRecSig"), candidate.kfV0Chi2(), ptCandXic); + } + } else { + registry.fill(HIST("hPtRecBg"), ptCandXic); + registry.fill(HIST("hPtProng0RecBg"), candidate.ptProng0()); + registry.fill(HIST("hPtProng1RecBg"), candidate.ptProng1()); + registry.fill(HIST("hPtProng2RecBg"), candidate.ptProng2()); + registry.fill(HIST("hPtProng0vsPtRecBg"), candidate.ptProng0(), ptCandXic); + registry.fill(HIST("hPtProng1vsPtRecBg"), candidate.ptProng1(), ptCandXic); + registry.fill(HIST("hPtProng2vsPtRecBg"), candidate.ptProng2(), ptCandXic); + registry.fill(HIST("hEtaRecBg"), candidate.eta(), ptCandXic); + registry.fill(HIST("hRapidityRecBg"), yCandXic, ptCandXic); + registry.fill(HIST("hSVxRecBg"), candidate.xSecondaryVertex(), ptCandXic); + registry.fill(HIST("hSVyRecBg"), candidate.ySecondaryVertex(), ptCandXic); + registry.fill(HIST("hSVzRecBg"), candidate.zSecondaryVertex(), ptCandXic); + registry.fill(HIST("hCPARecBg"), candidate.cpa(), ptCandXic); + registry.fill(HIST("hCPAxyRecBg"), candidate.cpaXY(), ptCandXic); + registry.fill(HIST("hMassRecBg"), candidate.invMassXicPlus(), ptCandXic); + registry.fill(HIST("hDecLengthRecBg"), candidate.decayLength(), ptCandXic); + registry.fill(HIST("hErrDecLengthRecBg"), candidate.errorDecayLength(), ptCandXic); + registry.fill(HIST("hDecLengthXYRecBg"), candidate.decayLengthXY(), ptCandXic); + registry.fill(HIST("hErrDecLengthXYRecBg"), candidate.errorDecayLengthXY(), ptCandXic); + registry.fill(HIST("hd0Prong0RecBg"), candidate.impactParameter0(), ptCandXic); + registry.fill(HIST("hd0Prong1RecBg"), candidate.impactParameter1(), ptCandXic); + registry.fill(HIST("hd0Prong2RecBg"), candidate.impactParameter2(), ptCandXic); + registry.fill(HIST("hImpParErrRecBg"), candidate.errorImpactParameter0(), ptCandXic); + registry.fill(HIST("hImpParErrRecBg"), candidate.errorImpactParameter1(), ptCandXic); + registry.fill(HIST("hImpParErrRecBg"), candidate.errorImpactParameter2(), ptCandXic); + registry.fill(HIST("hChi2PCARecBg"), candidate.chi2PCA(), ptCandXic); + registry.fill(HIST("hCPAXiRecBg"), candidate.cosPaXi(), ptCandXic); + registry.fill(HIST("hCPAxyXiRecBg"), candidate.cosPaXYXi(), ptCandXic); + registry.fill(HIST("hCPALambdaRecBg"), candidate.cosPaLambda(), ptCandXic); + registry.fill(HIST("hCPAxyLambdaRecBg"), candidate.cosPaLambda(), ptCandXic); + + // fill KFParticle specific histograms + if constexpr (useKfParticle) { + registry.fill(HIST("hChi2topoToPVRecBg"), candidate.chi2TopoXicPlusToPV(), ptCandXic); + registry.fill(HIST("hChi2topoXiToXicPlusRecBg"), candidate.chi2TopoXiToXicPlus(), ptCandXic); + registry.fill(HIST("hChi2geoXiRecBg"), candidate.kfCascadeChi2(), ptCandXic); + registry.fill(HIST("hChi2geoLamRecBg"), candidate.kfV0Chi2(), ptCandXic); + } + } + + if (checkDecayTypeMc) { + if (TESTBIT(flagMcMatchRecXic, hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiPiPi)) { + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiPiPi, candidate.invMassXicPlus(), ptCandXic); + } else if (TESTBIT(flagMcMatchRecXic, hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiResPiToXiPiPi)) { + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiResPiToXiPiPi, candidate.invMassXicPlus(), ptCandXic); + } else { + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_xic_to_xi_pi_pi::DecayType::NDecayType, candidate.invMassXicPlus(), ptCandXic); + } + } + // fill THnSparse + if (enableTHn) { + if constexpr (useMl) { + fillTHnSparse(candidate); + } else { + fillTHnSparse(candidate); + } + } + + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + if (TESTBIT(std::abs(particle.flagMcMatchGen()), hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiPiPi) || TESTBIT(std::abs(particle.flagMcMatchGen()), hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiResPiToXiPiPi)) { + arrDaughIndex.clear(); + + auto ptParticle = particle.pt(); + auto yParticle = RecoDecay::y(particle.pVector(), o2::constants::physics::MassXiCPlus); + if (yCandGenMax >= 0. && std::abs(yParticle) > yCandGenMax) { + continue; + } + + // get kinematic variables of Ξ π π + std::array ptProngs; + std::array yProngs; + std::array etaProngs; + std::array prodVtxXProngs; + std::array prodVtxYProngs; + std::array prodVtxZProngs; + int counter = 0; + RecoDecay::getDaughters(particle, &arrDaughIndex, std::array{+kXiMinus, +kPiPlus, +kPiPlus}, 2); + for (auto iProng = 0u; iProng < arrDaughIndex.size(); ++iProng) { + auto daughI = mcParticles.rawIteratorAt(arrDaughIndex[iProng]); + ptProngs[counter] = daughI.pt(); + etaProngs[counter] = daughI.eta(); + yProngs[counter] = RecoDecay::y(daughI.pVector(), pdg->Mass(daughI.pdgCode())); + prodVtxXProngs[counter] = daughI.vx(); + prodVtxYProngs[counter] = daughI.vy(); + prodVtxZProngs[counter] = daughI.vz(); + counter++; + } + + registry.fill(HIST("hPtProng0Gen"), ptProngs[0], ptParticle); + registry.fill(HIST("hPtProng1Gen"), ptProngs[1], ptParticle); + registry.fill(HIST("hPtProng2Gen"), ptProngs[2], ptParticle); + registry.fill(HIST("hEtaProng0Gen"), etaProngs[0], ptParticle); + registry.fill(HIST("hEtaProng1Gen"), etaProngs[1], ptParticle); + registry.fill(HIST("hEtaProng2Gen"), etaProngs[2], ptParticle); + registry.fill(HIST("hYProng0Gen"), yProngs[0], ptParticle); + registry.fill(HIST("hYProng1Gen"), yProngs[1], ptParticle); + registry.fill(HIST("hYProng2Gen"), yProngs[2], ptParticle); + registry.fill(HIST("hPtGen"), ptParticle); + registry.fill(HIST("hYGen"), yParticle, ptParticle); + registry.fill(HIST("hEtaGen"), particle.eta(), ptParticle); + registry.fill(HIST("hSVxGen"), prodVtxXProngs[0], ptParticle); + registry.fill(HIST("hSVyGen"), prodVtxYProngs[0], ptParticle); + registry.fill(HIST("hSVzGen"), prodVtxZProngs[0], ptParticle); + + // reject Xic daughters that are not in geometrical acceptance + if (!isProngInAcceptance(etaProngs[0], ptProngs[0]) || !isProngInAcceptance(etaProngs[1], ptProngs[1]) || !isProngInAcceptance(etaProngs[2], ptProngs[2])) { + continue; + } + registry.fill(HIST("hPtGenWithProngsInAcceptance"), ptParticle); + registry.fill(HIST("hEtaGenWithProngsInAcceptance"), particle.eta(), ptParticle); + registry.fill(HIST("hYGenWithProngsInAcceptance"), yParticle, ptParticle); + } + } // gen + } + + /// Data analysis and fill histograms + void processWithDCAFitter(soa::Filtered> const& candidates) + { + fillHistograms(candidates); + } + PROCESS_SWITCH(HfTaskXicToXiPiPi, processWithDCAFitter, "Process data with DCAFitter", true); + + void processWithKFParticle(soa::Filtered> const& candidates) + { + fillHistograms(candidates); + } + PROCESS_SWITCH(HfTaskXicToXiPiPi, processWithKFParticle, "Process data with KFParticle", false); + + /// Data analysis and fill histograms with ML + void processWithDCAFitterAndML(soa::Filtered> const& candidates) + { + fillHistograms(candidates); + } + PROCESS_SWITCH(HfTaskXicToXiPiPi, processWithDCAFitterAndML, "Process data with DCAFitter and ML approach", false); + + void processWithKFParticleAndML(soa::Filtered> const& candidates) + { + fillHistograms(candidates); + } + PROCESS_SWITCH(HfTaskXicToXiPiPi, processWithKFParticleAndML, "Process data with KFParticle and ML approach", false); + + /// MC analysis and fill histograms + void processMcWithDCAFitter(soa::Filtered> const& candidates, + soa::Join const& mcParticles, + aod::TracksWMc const& tracksWMc) + { + fillHistogramsMc(candidates, mcParticles, tracksWMc); + } + PROCESS_SWITCH(HfTaskXicToXiPiPi, processMcWithDCAFitter, "Process MC with DCAFitter", false); + + /// MC analysis and fill histograms with KFParticle + void processMcWithKFParticle(soa::Filtered> const& candidates, + soa::Join const& mcParticles, + aod::TracksWMc const& tracksWMc) + { + fillHistogramsMc(candidates, mcParticles, tracksWMc); + } + PROCESS_SWITCH(HfTaskXicToXiPiPi, processMcWithKFParticle, "Process MC with KFParticle", false); + + // MC analysis and fill histograms with ML + void processMcWithDCAFitterAndML(soa::Filtered> const& candidates, + soa::Join const& mcParticles, + aod::TracksWMc const& tracksWMc) + { + fillHistogramsMc(candidates, mcParticles, tracksWMc); + } + PROCESS_SWITCH(HfTaskXicToXiPiPi, processMcWithDCAFitterAndML, "Process MC with DCAFitter and ML approach", false); + + void processMcWithKFParticleAndML(soa::Filtered> const& candidates, + soa::Join const& mcParticles, + aod::TracksWMc const& tracksWMc) + { + fillHistogramsMc(candidates, mcParticles, tracksWMc); + } + PROCESS_SWITCH(HfTaskXicToXiPiPi, processMcWithKFParticleAndML, "Process MC with KFParticle and ML approach", false); + +}; // struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/Tasks/taskXicc.cxx b/PWGHF/D2H/Tasks/taskXicc.cxx index 0e3f116081a..9e9f4999f80 100644 --- a/PWGHF/D2H/Tasks/taskXicc.cxx +++ b/PWGHF/D2H/Tasks/taskXicc.cxx @@ -16,6 +16,8 @@ /// \author Gian Michele Innocenti , CERN /// \author Jinjoo Seo , Inha University +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" diff --git a/PWGHF/D2H/Utils/utilsRedDataFormat.h b/PWGHF/D2H/Utils/utilsRedDataFormat.h new file mode 100644 index 00000000000..9740e55d372 --- /dev/null +++ b/PWGHF/D2H/Utils/utilsRedDataFormat.h @@ -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. + +/// \file utilsRedDataFormat.h +/// \brief Utilities for reduced data format analyses +/// \author Luca Aglietta , UniTO Turin + +#ifndef PWGHF_D2H_UTILS_UTILSREDDATAFORMAT_H_ +#define PWGHF_D2H_UTILS_UTILSREDDATAFORMAT_H_ + +#include "Framework/HistogramRegistry.h" + +#include "CCDB/BasicCCDBManager.h" +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Utils/utilsEvSelHf.h" + +namespace o2::hf_evsel +{ +/// Helper function to count collisions at different event selection stages +/// \tparam useEvSel use information from the EvSel table +/// \tparam centEstimator centrality estimator +/// \param collision collision to test against the selection criteria +template +void checkEvSel(Coll const& collision, o2::hf_evsel::HfEventSelection& hfEvSel, int& zvtxColl, int& sel8Coll, int& zvtxAndSel8Coll, int& zvtxAndSel8CollAndSoftTrig, int& allSelColl, o2::framework::Service const& ccdb, o2::framework::HistogramRegistry& registry) +{ + float centrality{-1.f}; + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + if (!TESTBIT(rejectionMask, o2::hf_evsel::EventRejection::Trigger)) { + sel8Coll++; + } + if (!TESTBIT(rejectionMask, o2::hf_evsel::EventRejection::PositionZ)) { + zvtxColl++; + } + if (!TESTBIT(rejectionMask, o2::hf_evsel::EventRejection::PositionZ) && !TESTBIT(rejectionMask, o2::hf_evsel::EventRejection::Trigger)) { + zvtxAndSel8Coll++; + } + if (!TESTBIT(rejectionMask, o2::hf_evsel::EventRejection::PositionZ) && !TESTBIT(rejectionMask, o2::hf_evsel::EventRejection::Trigger) && !TESTBIT(rejectionMask, o2::hf_evsel::EventRejection::SoftwareTrigger)) { + zvtxAndSel8CollAndSoftTrig++; + } + if (rejectionMask == 0) { + allSelColl++; + } +} +} // namespace o2::hf_evsel + +namespace o2::pid_tpc_tof_utils +{ +/// Helper function to retrive PID information of bachelor pion from b-hadron decay +/// \param prong1 pion track from reduced data format, soa::Join +template +float getTpcTofNSigmaPi1(const T1& prong1) +{ + float defaultNSigma = -999.f; // -999.f is the default value set in TPCPIDResponse.h and PIDTOF.h + + bool hasTpc = prong1.hasTPC(); + bool hasTof = prong1.hasTOF(); + + if (hasTpc && hasTof) { + float tpcNSigma = prong1.tpcNSigmaPi(); + float tofNSigma = prong1.tofNSigmaPi(); + return std::sqrt(.5f * tpcNSigma * tpcNSigma + .5f * tofNSigma * tofNSigma); + } + if (hasTpc) { + return std::abs(prong1.tpcNSigmaPi()); + } + if (hasTof) { + return std::abs(prong1.tofNSigmaPi()); + } + return defaultNSigma; +} +} // namespace o2::pid_tpc_tof_utils + +#endif // PWGHF_D2H_UTILS_UTILSREDDATAFORMAT_H_ diff --git a/PWGHF/DataModel/CandidateReconstructionTables.h b/PWGHF/DataModel/CandidateReconstructionTables.h index 272fe779193..754de37ec45 100644 --- a/PWGHF/DataModel/CandidateReconstructionTables.h +++ b/PWGHF/DataModel/CandidateReconstructionTables.h @@ -34,6 +34,7 @@ #include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/Utils/utilsPid.h" namespace o2::aod { @@ -61,20 +62,6 @@ using TracksPidTinyPi = soa::Join; using TracksPidTinyKa = soa::Join; using TracksPidTinyPr = soa::Join; -namespace hf_collision_centrality -{ -// centrality selection estimators -enum CentralityEstimator { - None = 0, - FT0A, - FT0C, - FT0M, - FV0A, - NTracksPV, - NCentralityEstimators -}; -} // namespace hf_collision_centrality - // namespace pid_tpc_tof_utils // { // /// Function to combine TPC and TOF NSigma (for ML purposes) @@ -258,7 +245,7 @@ DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, Tracks, "_1"); //! Index to s DECLARE_SOA_INDEX_COLUMN_FULL(Prong2, prong2, int, Tracks, "_2"); //! Index to third prong DECLARE_SOA_INDEX_COLUMN(V0, v0); //! Index to V0 prong DECLARE_SOA_INDEX_COLUMN(Cascade, cascade); //! Index to cascade prong -DECLARE_SOA_COLUMN(HFflag, hfflag, uint8_t); //! +DECLARE_SOA_COLUMN(HFflag, hfflag, uint8_t); //! Bitmap to store selection results, o2-linter: disable=name/o2-column (written to disk) DECLARE_SOA_COLUMN(FlagD0ToKPi, flagD0ToKPi, uint8_t); //! DECLARE_SOA_COLUMN(FlagJpsiToEE, flagJpsiToEE, uint8_t); //! @@ -352,11 +339,11 @@ DECLARE_SOA_TABLE(HfDstars_000, "AOD", "HFDSTAR", //! D* -> D0pi candidates (Run hf_track_index::Prong0Id, hf_track_index::ProngD0Id); -DECLARE_SOA_TABLE(HfDstars_001, "AOD", "HFDSTAR", //! D* -> D0pi candidates (Run 3 format) - o2::soa::Index<>, - hf_track_index::CollisionId, - hf_track_index::Prong0Id, - hf_track_index::ProngD0Id); +DECLARE_SOA_TABLE_VERSIONED(HfDstars_001, "AOD", "HFDSTAR", 1, //! D* -> D0pi candidates (Run 3 format) + o2::soa::Index<>, + hf_track_index::CollisionId, + hf_track_index::Prong0Id, + hf_track_index::ProngD0Id); using HfDstars = HfDstars_001; using HfDstar = HfDstars::iterator; @@ -496,7 +483,65 @@ DECLARE_SOA_COLUMN(ImpactParameterZ2, impactParameterZ2, float); DECLARE_SOA_COLUMN(ErrorImpactParameterZ2, errorImpactParameterZ2, float); //! DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterZNormalised2, impactParameterZNormalised2, //! [](float dca, float err) -> float { return dca / err; }); -DECLARE_SOA_COLUMN(NProngsContributorsPV, nProngsContributorsPV, uint8_t); //! number of prongs contributing to the primary-vertex reconstruction +/// prong PID nsigma +DECLARE_SOA_COLUMN(NProngsContributorsPV, nProngsContributorsPV, uint8_t); //! number of prongs contributing to the primary-vertex reconstruction +DECLARE_SOA_COLUMN(BitmapProngsContributorsPV, bitmapProngsContributorsPV, uint8_t); //! bitmap with booleans indicating prongs contributing to the primary-vertex reconstruction +DECLARE_SOA_COLUMN(NSigTpcPi0, nSigTpcPi0, float); //! TPC nSigma for pion hypothesis - prong 0 +DECLARE_SOA_COLUMN(NSigTpcPi1, nSigTpcPi1, float); //! TPC nSigma for pion hypothesis - prong 1 +DECLARE_SOA_COLUMN(NSigTpcPi2, nSigTpcPi2, float); //! TPC nSigma for pion hypothesis - prong 2 +DECLARE_SOA_COLUMN(NSigTpcKa0, nSigTpcKa0, float); //! TPC nSigma for kaon hypothesis - prong 0 +DECLARE_SOA_COLUMN(NSigTpcKa1, nSigTpcKa1, float); //! TPC nSigma for kaon hypothesis - prong 1 +DECLARE_SOA_COLUMN(NSigTpcKa2, nSigTpcKa2, float); //! TPC nSigma for kaon hypothesis - prong 2 +DECLARE_SOA_COLUMN(NSigTpcPr0, nSigTpcPr0, float); //! TPC nSigma for proton hypothesis - prong 0 +DECLARE_SOA_COLUMN(NSigTpcPr1, nSigTpcPr1, float); //! TPC nSigma for proton hypothesis - prong 1 +DECLARE_SOA_COLUMN(NSigTpcPr2, nSigTpcPr2, float); //! TPC nSigma for proton hypothesis - prong 2 +DECLARE_SOA_COLUMN(NSigTofPi0, nSigTofPi0, float); //! TOF nSigma for pion hypothesis - prong 0 +DECLARE_SOA_COLUMN(NSigTofPi1, nSigTofPi1, float); //! TOF nSigma for pion hypothesis - prong 1 +DECLARE_SOA_COLUMN(NSigTofPi2, nSigTofPi2, float); //! TOF nSigma for pion hypothesis - prong 2 +DECLARE_SOA_COLUMN(NSigTofKa0, nSigTofKa0, float); //! TOF nSigma for kaon hypothesis - prong 0 +DECLARE_SOA_COLUMN(NSigTofKa1, nSigTofKa1, float); //! TOF nSigma for kaon hypothesis - prong 1 +DECLARE_SOA_COLUMN(NSigTofKa2, nSigTofKa2, float); //! TOF nSigma for kaon hypothesis - prong 2 +DECLARE_SOA_COLUMN(NSigTofPr0, nSigTofPr0, float); //! TOF nSigma for proton hypothesis - prong 0 +DECLARE_SOA_COLUMN(NSigTofPr1, nSigTofPr1, float); //! TOF nSigma for proton hypothesis - prong 1 +DECLARE_SOA_COLUMN(NSigTofPr2, nSigTofPr2, float); //! TOF nSigma for proton hypothesis - prong 2 +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaPi0, tpcTofNSigmaPi0, //! Combined NSigma separation with the TPC & TOF detectors for pion - prong 0 + [](float tpcNSigmaPi0, float tofNSigmaPi0) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi0, tofNSigmaPi0); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaPi1, tpcTofNSigmaPi1, //! Combined NSigma separation with the TPC & TOF detectors for pion - prong 1 + [](float tpcNSigmaPi1, float tofNSigmaPi1) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi1, tofNSigmaPi1); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaPi2, tpcTofNSigmaPi2, //! Combined NSigma separation with the TPC & TOF detectors for pion - prong 2 + [](float tpcNSigmaPi2, float tofNSigmaPi2) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi2, tofNSigmaPi2); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaKa0, tpcTofNSigmaKa0, //! Combined NSigma separation with the TPC & TOF detectors for kaon - prong 0 + [](float tpcNSigmaKa0, float tofNSigmaKa0) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaKa0, tofNSigmaKa0); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaKa1, tpcTofNSigmaKa1, //! Combined NSigma separation with the TPC & TOF detectors for kaon - prong 1 + [](float tpcNSigmaKa1, float tofNSigmaKa1) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaKa1, tofNSigmaKa1); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaKa2, tpcTofNSigmaKa2, //! Combined NSigma separation with the TPC & TOF detectors for kaon - prong 2 + [](float tpcNSigmaKa2, float tofNSigmaKa2) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaKa2, tofNSigmaKa2); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaPr0, tpcTofNSigmaPr0, //! Combined NSigma separation with the TPC & TOF detectors for proton - prong 0 + [](float tpcNSigmaPr0, float tofNSigmaPr0) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPr0, tofNSigmaPr0); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaPr1, tpcTofNSigmaPr1, //! Combined NSigma separation with the TPC & TOF detectors for proton - prong 1 + [](float tpcNSigmaPr1, float tofNSigmaPr1) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPr1, tofNSigmaPr1); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaPr2, tpcTofNSigmaPr2, //! Combined NSigma separation with the TPC & TOF detectors for proton - prong 2 + [](float tpcNSigmaPr2, float tofNSigmaPr2) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPr2, tofNSigmaPr2); }); +// tiny (binned) option +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaTinyPi0, tpcTofNSigmaTinyPi0, //! Combined NSigma separation with the TPC & TOF detectors for pion - prong 0 + [](float tpcNSigmaPi0, float tofNSigmaPi0) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi0, tofNSigmaPi0); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaTinyPi1, tpcTofNSigmaTinyPi1, //! Combined NSigma separation with the TPC & TOF detectors for pion - prong 1 + [](float tpcNSigmaPi1, float tofNSigmaPi1) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi1, tofNSigmaPi1); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaTinyPi2, tpcTofNSigmaTinyPi2, //! Combined NSigma separation with the TPC & TOF detectors for pion - prong 2 + [](float tpcNSigmaPi2, float tofNSigmaPi2) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi2, tofNSigmaPi2); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaTinyKa0, tpcTofNSigmaTinyKa0, //! Combined NSigma separation with the TPC & TOF detectors for kaon - prong 0 + [](float tpcNSigmaKa0, float tofNSigmaKa0) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaKa0, tofNSigmaKa0); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaTinyKa1, tpcTofNSigmaTinyKa1, //! Combined NSigma separation with the TPC & TOF detectors for kaon - prong 1 + [](float tpcNSigmaKa1, float tofNSigmaKa1) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaKa1, tofNSigmaKa1); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaTinyKa2, tpcTofNSigmaTinyKa2, //! Combined NSigma separation with the TPC & TOF detectors for kaon - prong 2 + [](float tpcNSigmaKa2, float tofNSigmaKa2) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaKa2, tofNSigmaKa2); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaTinyPr0, tpcTofNSigmaTinyPr0, //! Combined NSigma separation with the TPC & TOF detectors for proton - prong 0 + [](float tpcNSigmaPr0, float tofNSigmaPr0) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPr0, tofNSigmaPr0); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaTinyPr1, tpcTofNSigmaTinyPr1, //! Combined NSigma separation with the TPC & TOF detectors for proton - prong 1 + [](float tpcNSigmaPr1, float tofNSigmaPr1) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPr1, tofNSigmaPr1); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaTinyPr2, tpcTofNSigmaTinyPr2, //! Combined NSigma separation with the TPC & TOF detectors for proton - prong 2 + [](float tpcNSigmaPr2, float tofNSigmaPr2) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPr2, tofNSigmaPr2); }); + // candidate properties DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! [](float px, float py) -> float { return RecoDecay::pt(px, py); }); @@ -528,15 +573,22 @@ DECLARE_SOA_DYNAMIC_COLUMN(DecayLengthXYNormalised, decayLengthXYNormalised, //! [](float xVtxP, float yVtxP, float xVtxS, float yVtxS, float err) -> float { return RecoDecay::distanceXY(std::array{xVtxP, yVtxP}, std::array{xVtxS, yVtxS}) / err; }); DECLARE_SOA_COLUMN(ErrorDecayLength, errorDecayLength, float); //! DECLARE_SOA_COLUMN(ErrorDecayLengthXY, errorDecayLengthXY, float); //! -DECLARE_SOA_DYNAMIC_COLUMN(CPA, cpa, //! +DECLARE_SOA_DYNAMIC_COLUMN(Cpa, cpa, //! [](float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS, float px, float py, float pz) -> float { return RecoDecay::cpa(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}, std::array{px, py, pz}); }); -DECLARE_SOA_DYNAMIC_COLUMN(CPAXY, cpaXY, //! +DECLARE_SOA_DYNAMIC_COLUMN(CpaXY, cpaXY, //! [](float xVtxP, float yVtxP, float xVtxS, float yVtxS, float px, float py) -> float { return RecoDecay::cpaXY(std::array{xVtxP, yVtxP}, std::array{xVtxS, yVtxS}, std::array{px, py}); }); DECLARE_SOA_DYNAMIC_COLUMN(Ct, ct, //! [](float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS, float px, float py, float pz, double m) -> float { return RecoDecay::ct(std::array{px, py, pz}, RecoDecay::distance(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}), m); }); DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterXY, impactParameterXY, //! [](float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS, float px, float py, float pz) -> float { return RecoDecay::impParXY(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}, std::array{px, py, pz}); }); DECLARE_SOA_COLUMN(KfTopolChi2OverNdf, kfTopolChi2OverNdf, float); //! chi2overndf of the KFParticle topological constraint +// B-hadron mother information +DECLARE_SOA_COLUMN(PtBhadMotherPart, ptBhadMotherPart, float); //! pt of the first B-hadron mother particle (only in case of non-prompt) +DECLARE_SOA_COLUMN(PdgBhadMotherPart, pdgBhadMotherPart, int); //! pdg of the first B-hadron mother particle (only in case of non-prompt) +DECLARE_SOA_COLUMN(IdxBhadMotherPart, idxBhadMotherPart, int); //! index of the first B-hadron mother particle (only in case of non-prompt) +// Kink topology and material interaction mc flags +DECLARE_SOA_COLUMN(NTracksDecayed, nTracksDecayed, int8_t); //! number of tracks matched with kinked decay topology +DECLARE_SOA_COLUMN(NInteractionsWithMaterial, nInteractionsWithMaterial, int8_t); //! number of tracks matched after interaction with material // method of secondary-vertex reconstruction enum VertexerType { DCAFitter = 0, @@ -614,7 +666,7 @@ DECLARE_SOA_TABLE(HfCand2ProngBase, "AOD", "HFCAND2PBASE", //! hf_cand::ErrorImpactParameter0, hf_cand::ErrorImpactParameter1, hf_cand::ImpactParameterZ0, hf_cand::ImpactParameterZ1, hf_cand::ErrorImpactParameterZ0, hf_cand::ErrorImpactParameterZ1, - hf_track_index::Prong0Id, hf_track_index::Prong1Id, hf_cand::NProngsContributorsPV, + hf_track_index::Prong0Id, hf_track_index::Prong1Id, hf_cand::NProngsContributorsPV, hf_cand::BitmapProngsContributorsPV, hf_track_index::HFflag, /* dynamic columns */ hf_cand_2prong::M, @@ -628,8 +680,8 @@ DECLARE_SOA_TABLE(HfCand2ProngBase, "AOD", "HFCAND2PBASE", //! hf_cand::P, hf_cand::P2, hf_cand::PVector, - hf_cand::CPA, - hf_cand::CPAXY, + hf_cand::Cpa, + hf_cand::CpaXY, hf_cand::Ct, hf_cand::ImpactParameterXY, hf_cand_2prong::MaxNormalisedDeltaIP, @@ -643,7 +695,36 @@ DECLARE_SOA_TABLE(HfCand2ProngBase, "AOD", "HFCAND2PBASE", //! DECLARE_SOA_EXTENDED_TABLE_USER(HfCand2ProngExt, HfCand2ProngBase, "HFCAND2PEXT", //! hf_cand_2prong::Px, hf_cand_2prong::Py, hf_cand_2prong::Pz); +DECLARE_SOA_TABLE(HfProng0PidPi, "AOD", "HFP0PIDPI", //! + hf_cand::NSigTpcPi0, hf_cand::NSigTofPi0, + hf_cand::TpcTofNSigmaPi0); +DECLARE_SOA_TABLE(HfProng1PidPi, "AOD", "HFP1PIDPI", //! + hf_cand::NSigTpcPi1, hf_cand::NSigTofPi1, + hf_cand::TpcTofNSigmaPi1); +DECLARE_SOA_TABLE(HfProng2PidPi, "AOD", "HFP2PIDPI", //! + hf_cand::NSigTpcPi2, hf_cand::NSigTofPi2, + hf_cand::TpcTofNSigmaPi2); +DECLARE_SOA_TABLE(HfProng0PidKa, "AOD", "HFP0PIDKA", //! + hf_cand::NSigTpcKa0, hf_cand::NSigTofKa0, + hf_cand::TpcTofNSigmaKa0); +DECLARE_SOA_TABLE(HfProng1PidKa, "AOD", "HFP1PIDKA", //! + hf_cand::NSigTpcKa1, hf_cand::NSigTofKa1, + hf_cand::TpcTofNSigmaKa1); +DECLARE_SOA_TABLE(HfProng2PidKa, "AOD", "HFP2PIDKA", //! + hf_cand::NSigTpcKa2, hf_cand::NSigTofKa2, + hf_cand::TpcTofNSigmaKa2); +DECLARE_SOA_TABLE(HfProng0PidPr, "AOD", "HFP0PIDPR", //! + hf_cand::NSigTpcPr0, hf_cand::NSigTofPr0, + hf_cand::TpcTofNSigmaPr0); +DECLARE_SOA_TABLE(HfProng1PidPr, "AOD", "HFP1PIDPR", //! + hf_cand::NSigTpcPr1, hf_cand::NSigTofPr1, + hf_cand::TpcTofNSigmaPr1); +DECLARE_SOA_TABLE(HfProng2PidPr, "AOD", "HFP2PIDPR", //! + hf_cand::NSigTpcPr2, hf_cand::NSigTofPr2, + hf_cand::TpcTofNSigmaPr2); + using HfCand2Prong = HfCand2ProngExt; +using HfCand2ProngWPid = soa::Join; DECLARE_SOA_TABLE(HfCand2ProngKF, "AOD", "HFCAND2PKF", hf_cand::KfTopolChi2OverNdf, @@ -652,12 +733,17 @@ DECLARE_SOA_TABLE(HfCand2ProngKF, "AOD", "HFCAND2PKF", // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCand2ProngMcRec, "AOD", "HFCAND2PMCREC", //! hf_cand_2prong::FlagMcMatchRec, - hf_cand_2prong::OriginMcRec); + hf_cand_2prong::OriginMcRec, + hf_cand::PtBhadMotherPart, + hf_cand::PdgBhadMotherPart, + hf_cand::NTracksDecayed, + hf_cand::NInteractionsWithMaterial); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCand2ProngMcGen, "AOD", "HFCAND2PMCGEN", //! hf_cand_2prong::FlagMcMatchGen, - hf_cand_2prong::OriginMcGen); + hf_cand_2prong::OriginMcGen, + hf_cand::IdxBhadMotherPart); // cascade decay candidate table @@ -680,9 +766,9 @@ DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); //! reconstruction l DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); //! generator level DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); //! particle origin, reconstruction level DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! particle origin, generator level -DECLARE_SOA_COLUMN(V0X, v0x, float); //! X position of V0 decay -DECLARE_SOA_COLUMN(V0Y, v0y, float); //! Y position of V0 decay -DECLARE_SOA_COLUMN(V0Z, v0z, float); //! Z position of V0 decay +DECLARE_SOA_COLUMN(V0X, v0X, float); //! X position of V0 decay +DECLARE_SOA_COLUMN(V0Y, v0Y, float); //! Y position of V0 decay +DECLARE_SOA_COLUMN(V0Z, v0Z, float); //! Z position of V0 decay } // namespace hf_cand_casc DECLARE_SOA_TABLE(HfCandCascBase, "AOD", "HFCANDCASCBASE", //! @@ -715,8 +801,8 @@ DECLARE_SOA_TABLE(HfCandCascBase, "AOD", "HFCANDCASCBASE", //! hf_cand::P, hf_cand::P2, hf_cand::PVector, - hf_cand::CPA, - hf_cand::CPAXY, + hf_cand::Cpa, + hf_cand::CpaXY, hf_cand::Ct, hf_cand::ImpactParameterXY, hf_cand_2prong::MaxNormalisedDeltaIP, @@ -748,25 +834,34 @@ using HfCandCascade = HfCandCascExt; // table with results of reconstruction level MC matching for Cascade DECLARE_SOA_TABLE(HfCandCascadeMcRec, "AOD", "HFCANDCASCMCREC", //! hf_cand_casc::FlagMcMatchRec, - hf_cand_casc::OriginMcRec); + hf_cand_casc::OriginMcRec, + hf_cand::PtBhadMotherPart, + hf_cand::PdgBhadMotherPart); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCandCascadeMcGen, "AOD", "HFCANDCASCMCGEN", //! hf_cand_casc::FlagMcMatchGen, - hf_cand_casc::OriginMcGen); + hf_cand_casc::OriginMcGen, + hf_cand::IdxBhadMotherPart); // specific BPlus candidate properties namespace hf_cand_bplus { DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfCand2Prong, "_0"); // D0 index // MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // generator level -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); // particle origin, reconstruction level -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); // particle origin, generator level -DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level +DECLARE_SOA_COLUMN(FlagWrongCollision, flagWrongCollision, int8_t); // reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // generator level +DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); // particle origin, reconstruction level +DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); // particle origin, generator level +DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level enum DecayType { BplusToD0Pi = 0 }; + +enum DecayTypeMc : uint8_t { BplusToD0PiToKPiPi = 0, + PartlyRecoDecay, + OtherDecay, + NDecayTypeMc }; } // namespace hf_cand_bplus // declare dedicated BPlus decay candidate table @@ -779,7 +874,6 @@ DECLARE_SOA_TABLE(HfCandBplusBase, "AOD", "HFCANDBPLUSBASE", hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, hf_cand::ImpactParameter0, hf_cand::ImpactParameter1, hf_cand::ErrorImpactParameter0, hf_cand::ErrorImpactParameter1, - hf_track_index::HFflag, /* dynamic columns */ hf_cand_2prong::M, hf_cand_2prong::M2, @@ -792,8 +886,8 @@ DECLARE_SOA_TABLE(HfCandBplusBase, "AOD", "HFCANDBPLUSBASE", hf_cand::P, hf_cand::P2, hf_cand::PVector, - hf_cand::CPA, - hf_cand::CPAXY, + hf_cand::Cpa, + hf_cand::CpaXY, hf_cand::Ct, hf_cand::ImpactParameterXY, hf_cand_2prong::MaxNormalisedDeltaIP, @@ -855,6 +949,8 @@ enum DecayType { DplusToPiKPi = 0, XicToPKPi, N3ProngDecays }; // always keep N3ProngDecays at the end +static constexpr int DstarToPiKPiBkg = DecayType::N3ProngDecays; + // Ds± → K± K∓ π± or D± → K± K∓ π± enum DecayChannelDToKKPi { @@ -864,6 +960,40 @@ enum DecayChannelDToKKPi { DplusToK0starK // used to describe D+ in MC production for Ds analysis }; +// KF related properties +DECLARE_SOA_COLUMN(KfXPVError, kfXPVError, float); //! error of X coordinate of the event's primary vertex +DECLARE_SOA_COLUMN(KfYPVError, kfYPVError, float); //! error of Y coordinate of the event's primary vertex +DECLARE_SOA_COLUMN(KfZPVError, kfZPVError, float); //! error of Z coordinate of the event's primary vertex +DECLARE_SOA_COLUMN(KfXError, kfXError, float); //! error of candidate's decay point X coordinate from the KFParticle fit +DECLARE_SOA_COLUMN(KfYError, kfYError, float); //! error of candidate's decay point Y coordinate from the KFParticle fit +DECLARE_SOA_COLUMN(KfZError, kfZError, float); //! error of candidate's decay point Z coordinate from the KFParticle fit +DECLARE_SOA_COLUMN(KfMassPKPi, kfMassPKPi, float); //! mass of the PKPi candidate from the KFParticle fit +DECLARE_SOA_COLUMN(KfMassPiKP, kfMassPiKP, float); //! mass of the PiKP candidate from the KFParticle fit +DECLARE_SOA_COLUMN(KfMassPiKPi, kfMassPiKPi, float); //! mass of the PiKPi candidate from the KFParticle fit +DECLARE_SOA_COLUMN(KfMassKKPi, kfMassKKPi, float); //! mass of the KKPi candidate from the KFParticle fit +DECLARE_SOA_COLUMN(KfMassPiKK, kfMassPiKK, float); //! mass of the PiKK candidate from the KFParticle fit +DECLARE_SOA_COLUMN(KfMassKPi, kfMassKPi, float); //! mass of the KPi pair from the KFParticle fit +DECLARE_SOA_COLUMN(KfMassPiK, kfMassPiK, float); //! mass of the PiK pair from the KFParticle fit +DECLARE_SOA_COLUMN(KfPx, kfPx, float); //! Px of the candidate from the KFParticle fit +DECLARE_SOA_COLUMN(KfPy, kfPy, float); //! Py of the candidate from the KFParticle fit +DECLARE_SOA_COLUMN(KfPz, kfPz, float); //! Pz of the candidate from the KFParticle fit +DECLARE_SOA_COLUMN(KfErrorPx, kfErrorPx, float); //! Px error of the candidate from the KFParticle fit +DECLARE_SOA_COLUMN(KfErrorPy, kfErrorPy, float); //! Py error of the candidate from the KFParticle fit +DECLARE_SOA_COLUMN(KfErrorPz, kfErrorPz, float); //! Pz error of the candidate from the KFParticle fit +DECLARE_SOA_COLUMN(KfChi2PrimProng0, kfChi2PrimProng0, float); //! chi2 primary of the first prong +DECLARE_SOA_COLUMN(KfChi2PrimProng1, kfChi2PrimProng1, float); //! chi2 primary of the second prong +DECLARE_SOA_COLUMN(KfChi2PrimProng2, kfChi2PrimProng2, float); //! chi2 primary of the third prong +DECLARE_SOA_COLUMN(KfDcaProng0Prong1, kfDcaProng0Prong1, float); //! DCA between first and second prongs +DECLARE_SOA_COLUMN(KfDcaProng0Prong2, kfDcaProng0Prong2, float); //! DCA between first and third prongs +DECLARE_SOA_COLUMN(KfDcaProng1Prong2, kfDcaProng1Prong2, float); //! DCA between second and third prongs +DECLARE_SOA_COLUMN(KfChi2GeoProng0Prong1, kfChi2GeoProng0Prong1, float); //! chi2 geo between first and second prongs +DECLARE_SOA_COLUMN(KfChi2GeoProng0Prong2, kfChi2GeoProng0Prong2, float); //! chi2 geo between first and third prongs +DECLARE_SOA_COLUMN(KfChi2GeoProng1Prong2, kfChi2GeoProng1Prong2, float); //! chi2 geo between second and third prongs +DECLARE_SOA_COLUMN(KfChi2Geo, kfChi2Geo, float); //! chi2 geo of the full candidate +DECLARE_SOA_COLUMN(KfChi2Topo, kfChi2Topo, float); //! chi2 topo of the full candidate (chi2prim of candidate to PV) +DECLARE_SOA_COLUMN(KfDecayLength, kfDecayLength, float); //! decay length +DECLARE_SOA_COLUMN(KfDecayLengthError, kfDecayLengthError, float); //! decay length error + } // namespace hf_cand_3prong // 3-prong decay candidate table @@ -879,7 +1009,7 @@ DECLARE_SOA_TABLE(HfCand3ProngBase, "AOD", "HFCAND3PBASE", //! hf_cand::ErrorImpactParameter0, hf_cand::ErrorImpactParameter1, hf_cand::ErrorImpactParameter2, hf_cand::ImpactParameterZ0, hf_cand::ImpactParameterZ1, hf_cand::ImpactParameterZ2, hf_cand::ErrorImpactParameterZ0, hf_cand::ErrorImpactParameterZ1, hf_cand::ErrorImpactParameterZ2, - hf_track_index::Prong0Id, hf_track_index::Prong1Id, hf_track_index::Prong2Id, hf_cand::NProngsContributorsPV, + hf_track_index::Prong0Id, hf_track_index::Prong1Id, hf_track_index::Prong2Id, hf_cand::NProngsContributorsPV, hf_cand::BitmapProngsContributorsPV, hf_track_index::HFflag, /* dynamic columns */ hf_cand_3prong::M, @@ -896,8 +1026,8 @@ DECLARE_SOA_TABLE(HfCand3ProngBase, "AOD", "HFCAND3PBASE", //! hf_cand::P, hf_cand::P2, hf_cand::PVector, - hf_cand::CPA, - hf_cand::CPAXY, + hf_cand::Cpa, + hf_cand::CpaXY, hf_cand::Ct, hf_cand::ImpactParameterXY, hf_cand_3prong::MaxNormalisedDeltaIP, @@ -913,26 +1043,45 @@ DECLARE_SOA_EXTENDED_TABLE_USER(HfCand3ProngExt, HfCand3ProngBase, "HFCAND3PEXT" using HfCand3Prong = HfCand3ProngExt; +DECLARE_SOA_TABLE(HfCand3ProngKF, "AOD", "HFCAND3PKF", + hf_cand_3prong::KfXError, hf_cand_3prong::KfYError, hf_cand_3prong::KfZError, + hf_cand_3prong::KfXPVError, hf_cand_3prong::KfYPVError, hf_cand_3prong::KfZPVError, + hf_cand_3prong::KfMassPKPi, hf_cand_3prong::KfMassPiKP, hf_cand_3prong::KfMassPiKPi, hf_cand_3prong::KfMassKKPi, hf_cand_3prong::KfMassPiKK, hf_cand_3prong::KfMassKPi, hf_cand_3prong::KfMassPiK, + hf_cand_3prong::KfPx, hf_cand_3prong::KfPy, hf_cand_3prong::KfPz, + hf_cand_3prong::KfErrorPx, hf_cand_3prong::KfErrorPy, hf_cand_3prong::KfErrorPz, + hf_cand_3prong::KfChi2PrimProng0, hf_cand_3prong::KfChi2PrimProng1, hf_cand_3prong::KfChi2PrimProng2, + hf_cand_3prong::KfDcaProng1Prong2, hf_cand_3prong::KfDcaProng0Prong2, hf_cand_3prong::KfDcaProng0Prong1, + hf_cand_3prong::KfChi2GeoProng1Prong2, hf_cand_3prong::KfChi2GeoProng0Prong2, hf_cand_3prong::KfChi2GeoProng0Prong1, + hf_cand_3prong::KfChi2Geo, hf_cand_3prong::KfDecayLength, hf_cand_3prong::KfDecayLengthError, hf_cand_3prong::KfChi2Topo); + // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCand3ProngMcRec, "AOD", "HFCAND3PMCREC", //! hf_cand_3prong::FlagMcMatchRec, hf_cand_3prong::OriginMcRec, hf_cand_3prong::IsCandidateSwapped, - hf_cand_3prong::FlagMcDecayChanRec); + hf_cand_3prong::FlagMcDecayChanRec, + hf_cand::PtBhadMotherPart, + hf_cand::PdgBhadMotherPart, + hf_cand::NTracksDecayed, + hf_cand::NInteractionsWithMaterial); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCand3ProngMcGen, "AOD", "HFCAND3PMCGEN", //! hf_cand_3prong::FlagMcMatchGen, hf_cand_3prong::OriginMcGen, - hf_cand_3prong::FlagMcDecayChanGen); + hf_cand_3prong::FlagMcDecayChanGen, + hf_cand::IdxBhadMotherPart); namespace hf_cand_casc_lf { // mapping of decay types enum DecayType2Prong { XiczeroOmegaczeroToXiPi = 0, OmegaczeroToOmegaPi, + OmegaczeroToOmegaK, N2ProngDecays }; // always keep N2ProngDecays at the end - +// mapping of construct method +enum ConstructMethod { DcaFitter = 0, + KfParticle }; // mapping of decay types enum DecayType3Prong { XicplusToXiPiPi = 0, N3ProngDecays }; // always keep N3ProngDecays at the end @@ -979,8 +1128,8 @@ DECLARE_SOA_TABLE(HfCandXBase, "AOD", "HFCANDXBASE", hf_cand::P, hf_cand::P2, hf_cand::PVector, - hf_cand::CPA, - hf_cand::CPAXY, + hf_cand::Cpa, + hf_cand::CpaXY, hf_cand::Ct, hf_cand::ImpactParameterXY, hf_cand_3prong::MaxNormalisedDeltaIP, @@ -1043,8 +1192,8 @@ DECLARE_SOA_TABLE(HfCandXiccBase, "AOD", "HFCANDXICCBASE", hf_cand::P, hf_cand::P2, hf_cand::PVector, - hf_cand::CPA, - hf_cand::CPAXY, + hf_cand::Cpa, + hf_cand::CpaXY, hf_cand::Ct, hf_cand::ImpactParameterXY, hf_cand_2prong::MaxNormalisedDeltaIP, @@ -1072,7 +1221,7 @@ DECLARE_SOA_TABLE(HfCandXiccMcGen, "AOD", "HFCANDXICCMCGEN", //! hf_cand_xicc::OriginMcGen); // specific Omegac and Xic to Xi Pi candidate properties -namespace hf_cand_toxipi +namespace hf_cand_xic0_omegac0 { // Data processing results: DECLARE_SOA_INDEX_COLUMN(Collision, collision); @@ -1101,15 +1250,15 @@ DECLARE_SOA_COLUMN(PzCharmBaryon, pzCharmBaryon, float); DECLARE_SOA_COLUMN(PxCasc, pxCasc, float); DECLARE_SOA_COLUMN(PyCasc, pyCasc, float); DECLARE_SOA_COLUMN(PzCasc, pzCasc, float); -DECLARE_SOA_COLUMN(PxPiFromCharmBaryon, pxPiFromCharmBaryon, float); -DECLARE_SOA_COLUMN(PyPiFromCharmBaryon, pyPiFromCharmBaryon, float); -DECLARE_SOA_COLUMN(PzPiFromCharmBaryon, pzPiFromCharmBaryon, float); +DECLARE_SOA_COLUMN(PxBachFromCharmBaryon, pxBachFromCharmBaryon, float); +DECLARE_SOA_COLUMN(PyBachFromCharmBaryon, pyBachFromCharmBaryon, float); +DECLARE_SOA_COLUMN(PzBachFromCharmBaryon, pzBachFromCharmBaryon, float); DECLARE_SOA_COLUMN(PxLambda, pxLambda, float); DECLARE_SOA_COLUMN(PyLambda, pyLambda, float); DECLARE_SOA_COLUMN(PzLambda, pzLambda, float); -DECLARE_SOA_COLUMN(PxPiFromCasc, pxPiFromCasc, float); -DECLARE_SOA_COLUMN(PyPiFromCasc, pyPiFromCasc, float); -DECLARE_SOA_COLUMN(PzPiFromCasc, pzPiFromCasc, float); +DECLARE_SOA_COLUMN(PxBachFromCasc, pxBachFromCasc, float); +DECLARE_SOA_COLUMN(PyBachFromCasc, pyBachFromCasc, float); +DECLARE_SOA_COLUMN(PzBachFromCasc, pzBachFromCasc, float); DECLARE_SOA_COLUMN(PxPosV0Dau, pxPosV0Dau, float); DECLARE_SOA_COLUMN(PyPosV0Dau, pyPosV0Dau, float); DECLARE_SOA_COLUMN(PzPosV0Dau, pzPosV0Dau, float); @@ -1117,34 +1266,34 @@ DECLARE_SOA_COLUMN(PxNegV0Dau, pxNegV0Dau, float); DECLARE_SOA_COLUMN(PyNegV0Dau, pyNegV0Dau, float); DECLARE_SOA_COLUMN(PzNegV0Dau, pzNegV0Dau, float); DECLARE_SOA_COLUMN(ImpactParCascXY, impactParCascXY, float); -DECLARE_SOA_COLUMN(ImpactParPiFromCharmBaryonXY, impactParPiFromCharmBaryonXY, float); +DECLARE_SOA_COLUMN(ImpactParBachFromCharmBaryonXY, impactParBachFromCharmBaryonXY, float); DECLARE_SOA_COLUMN(ImpactParCascZ, impactParCascZ, float); -DECLARE_SOA_COLUMN(ImpactParPiFromCharmBaryonZ, impactParPiFromCharmBaryonZ, float); +DECLARE_SOA_COLUMN(ImpactParBachFromCharmBaryonZ, impactParBachFromCharmBaryonZ, float); DECLARE_SOA_COLUMN(ErrImpactParCascXY, errImpactParCascXY, float); -DECLARE_SOA_COLUMN(ErrImpactParPiFromCharmBaryonXY, errImpactParPiFromCharmBaryonXY, float); +DECLARE_SOA_COLUMN(ErrImpactParBachFromCharmBaryonXY, errImpactParBachFromCharmBaryonXY, float); DECLARE_SOA_INDEX_COLUMN(V0, v0); DECLARE_SOA_INDEX_COLUMN(Cascade, cascade); -DECLARE_SOA_INDEX_COLUMN_FULL(PiFromCharmBaryon, piFromCharmBaryon, int, Tracks, "_pifromcharmbaryon"); -DECLARE_SOA_COLUMN(InvMassLambda, invMassLambda, double); -DECLARE_SOA_COLUMN(InvMassCascade, invMassCascade, double); -DECLARE_SOA_COLUMN(InvMassCharmBaryon, invMassCharmBaryon, double); -DECLARE_SOA_COLUMN(CosPAV0, cosPAV0, double); -DECLARE_SOA_COLUMN(CosPACharmBaryon, cosPACharmBaryon, double); -DECLARE_SOA_COLUMN(CosPACasc, cosPACasc, double); -DECLARE_SOA_COLUMN(CosPAXYV0, cosPAXYV0, double); -DECLARE_SOA_COLUMN(CosPAXYCharmBaryon, cosPAXYCharmBaryon, double); -DECLARE_SOA_COLUMN(CosPAXYCasc, cosPAXYCasc, double); -DECLARE_SOA_COLUMN(CTauOmegac, ctauOmegac, double); -DECLARE_SOA_COLUMN(CTauCascade, ctauCascade, double); -DECLARE_SOA_COLUMN(CTauV0, ctauV0, double); -DECLARE_SOA_COLUMN(CTauXic, ctauXic, double); -DECLARE_SOA_COLUMN(EtaV0PosDau, etaV0PosDau, double); -DECLARE_SOA_COLUMN(EtaV0NegDau, etaV0NegDau, double); -DECLARE_SOA_COLUMN(EtaPiFromCasc, etaPiFromCasc, double); -DECLARE_SOA_COLUMN(EtaPiFromCharmBaryon, etaPiFromCharmBaryon, double); -DECLARE_SOA_COLUMN(EtaCharmBaryon, etaCharmBaryon, double); -DECLARE_SOA_COLUMN(EtaCascade, etaCascade, double); -DECLARE_SOA_COLUMN(EtaV0, etaV0, double); +DECLARE_SOA_INDEX_COLUMN_FULL(BachelorFromCharmBaryon, bachelorFromCharmBaryon, int, Tracks, "_bachelorfromcharmbaryon"); +DECLARE_SOA_COLUMN(InvMassLambda, invMassLambda, float); +DECLARE_SOA_COLUMN(InvMassCascade, invMassCascade, float); +DECLARE_SOA_COLUMN(InvMassCharmBaryon, invMassCharmBaryon, float); +DECLARE_SOA_COLUMN(CosPAV0, cosPAV0, float); +DECLARE_SOA_COLUMN(CosPACharmBaryon, cosPACharmBaryon, float); +DECLARE_SOA_COLUMN(CosPACasc, cosPACasc, float); +DECLARE_SOA_COLUMN(CosPAXYV0, cosPAXYV0, float); +DECLARE_SOA_COLUMN(CosPAXYCharmBaryon, cosPAXYCharmBaryon, float); +DECLARE_SOA_COLUMN(CosPAXYCasc, cosPAXYCasc, float); +DECLARE_SOA_COLUMN(CTauOmegac, cTauOmegac, float); +DECLARE_SOA_COLUMN(CTauCascade, cTauCascade, float); +DECLARE_SOA_COLUMN(CTauV0, cTauV0, float); +DECLARE_SOA_COLUMN(CTauXic, cTauXic, float); +DECLARE_SOA_COLUMN(EtaV0PosDau, etaV0PosDau, float); +DECLARE_SOA_COLUMN(EtaV0NegDau, etaV0NegDau, float); +DECLARE_SOA_COLUMN(EtaBachFromCasc, etaBachFromCasc, float); +DECLARE_SOA_COLUMN(EtaBachFromCharmBaryon, etaBachFromCharmBaryon, float); +DECLARE_SOA_COLUMN(EtaCharmBaryon, etaCharmBaryon, float); +DECLARE_SOA_COLUMN(EtaCascade, etaCascade, float); +DECLARE_SOA_COLUMN(EtaV0, etaV0, float); DECLARE_SOA_COLUMN(DcaXYToPvV0Dau0, dcaXYToPvV0Dau0, float); // pos dau DECLARE_SOA_COLUMN(DcaXYToPvV0Dau1, dcaXYToPvV0Dau1, float); // neg dau DECLARE_SOA_COLUMN(DcaXYToPvCascDau, dcaXYToPvCascDau, float); @@ -1154,72 +1303,466 @@ DECLARE_SOA_COLUMN(DcaZToPvCascDau, dcaZToPvCascDau, float); DECLARE_SOA_COLUMN(DcaCascDau, dcaCascDau, float); DECLARE_SOA_COLUMN(DcaV0Dau, dcaV0Dau, float); DECLARE_SOA_COLUMN(DcaCharmBaryonDau, dcaCharmBaryonDau, float); -DECLARE_SOA_COLUMN(DecLenCharmBaryon, decLenCharmBaryon, double); -DECLARE_SOA_COLUMN(DecLenCascade, decLenCascade, double); -DECLARE_SOA_COLUMN(DecLenV0, decLenV0, double); +DECLARE_SOA_COLUMN(DecLenCharmBaryon, decLenCharmBaryon, float); +DECLARE_SOA_COLUMN(DecLenCascade, decLenCascade, float); +DECLARE_SOA_COLUMN(DecLenV0, decLenV0, float); DECLARE_SOA_COLUMN(ErrorDecayLengthCharmBaryon, errorDecayLengthCharmBaryon, float); DECLARE_SOA_COLUMN(ErrorDecayLengthXYCharmBaryon, errorDecayLengthXYCharmBaryon, float); +// KFParticle results +DECLARE_SOA_COLUMN(KfDcaXYPiFromOmegac, kfDcaXYPiFromOmegac, float); +DECLARE_SOA_COLUMN(KfDcaXYPiFromXic, kfDcaXYPiFromXic, float); +DECLARE_SOA_COLUMN(KfDcaXYCascToPv, kfDcaXYCascToPv, float); +DECLARE_SOA_COLUMN(Chi2GeoV0, chi2GeoV0, float); +DECLARE_SOA_COLUMN(Chi2GeoCasc, chi2GeoCasc, float); +DECLARE_SOA_COLUMN(Chi2GeoOmegac, chi2GeoOmegac, float); +DECLARE_SOA_COLUMN(Chi2GeoXic, chi2GeoXic, float); +DECLARE_SOA_COLUMN(Chi2MassV0, chi2MassV0, float); +DECLARE_SOA_COLUMN(Chi2MassCasc, chi2MassCasc, float); +DECLARE_SOA_COLUMN(V0ldl, v0ldl, float); +DECLARE_SOA_COLUMN(Cascldl, cascldl, float); +DECLARE_SOA_COLUMN(Omegacldl, omegacldl, float); +DECLARE_SOA_COLUMN(Xicldl, xicldl, float); +DECLARE_SOA_COLUMN(Chi2TopoV0ToPv, chi2TopoV0ToPv, float); +DECLARE_SOA_COLUMN(Chi2TopoCascToPv, chi2TopoCascToPv, float); +DECLARE_SOA_COLUMN(Chi2TopoPiFromOmegacToPv, chi2TopoPiFromOmegacToPv, float); +DECLARE_SOA_COLUMN(Chi2TopoPiFromXicToPv, chi2TopoPiFromXicToPv, float); +DECLARE_SOA_COLUMN(Chi2TopoOmegacToPv, chi2TopoOmegacToPv, float); +DECLARE_SOA_COLUMN(DeviationPiFromOmegacToPv, deviationPiFromOmegacToPv, float); +DECLARE_SOA_COLUMN(Chi2TopoXicToPv, chi2TopoXicToPv, float); +DECLARE_SOA_COLUMN(Chi2TopoV0ToCasc, chi2TopoV0ToCasc, float); +DECLARE_SOA_COLUMN(Chi2TopoCascToOmegac, chi2TopoCascToOmegac, float); +DECLARE_SOA_COLUMN(Chi2TopoCascToXic, chi2TopoCascToXic, float); +DECLARE_SOA_COLUMN(DecayLenXYLambda, decayLenXYLambda, float); +DECLARE_SOA_COLUMN(DecayLenXYCasc, decayLenXYCasc, float); +DECLARE_SOA_COLUMN(DecayLenXYOmegac, decayLenXYOmegac, float); +DECLARE_SOA_COLUMN(DecayLenXYXic, decayLenXYXic, float); +DECLARE_SOA_COLUMN(CosPaV0ToCasc, cosPaV0ToCasc, float); +DECLARE_SOA_COLUMN(CosPaCascToOmegac, cosPaCascToOmegac, float); +DECLARE_SOA_COLUMN(CosPaCascToXic, cosPaCascToXic, float); +DECLARE_SOA_COLUMN(CosPaXYV0ToCasc, cosPaXYV0ToCasc, float); +DECLARE_SOA_COLUMN(CosPaXYCascToOmegac, cosPaXYCascToOmegac, float); +DECLARE_SOA_COLUMN(CosPaXYCascToXic, cosPaXYCascToXic, float); +DECLARE_SOA_COLUMN(KfMassV0, kfMassV0, float); +DECLARE_SOA_COLUMN(KfMassCasc, kfMassCasc, float); +DECLARE_SOA_COLUMN(KfMassOmegac, kfMassOmegac, float); +DECLARE_SOA_COLUMN(KfRapOmegac, kfRapOmegac, float); +DECLARE_SOA_COLUMN(KfRapXic, kfRapXic, float); +DECLARE_SOA_COLUMN(KfptPiFromOmegac, kfptPiFromOmegac, float); +DECLARE_SOA_COLUMN(KfptPiFromXic, kfptPiFromXic, float); +DECLARE_SOA_COLUMN(KfptOmegac, kfptOmegac, float); +DECLARE_SOA_COLUMN(KfptXic, kfptXic, float); +DECLARE_SOA_COLUMN(CosThetaStarPiFromOmegac, cosThetaStarPiFromOmegac, float); +DECLARE_SOA_COLUMN(CosThetaStarPiFromXic, cosThetaStarPiFromXic, float); +DECLARE_SOA_COLUMN(V0Ndf, v0Ndf, float); +DECLARE_SOA_COLUMN(CascNdf, cascNdf, float); +DECLARE_SOA_COLUMN(OmegacNdf, omegacNdf, float); +DECLARE_SOA_COLUMN(XicNdf, xicNdf, float); +DECLARE_SOA_COLUMN(MassV0Ndf, massV0Ndf, float); +DECLARE_SOA_COLUMN(MassCascNdf, massCascNdf, float); +DECLARE_SOA_COLUMN(V0Chi2OverNdf, v0Chi2OverNdf, float); +DECLARE_SOA_COLUMN(CascChi2OverNdf, cascChi2OverNdf, float); +DECLARE_SOA_COLUMN(OmegacChi2OverNdf, omegacChi2OverNdf, float); +DECLARE_SOA_COLUMN(XicChi2OverNdf, xicChi2OverNdf, float); +DECLARE_SOA_COLUMN(MassV0Chi2OverNdf, massV0Chi2OverNdf, float); +DECLARE_SOA_COLUMN(MassCascChi2OverNdf, massCascChi2OverNdf, float); +DECLARE_SOA_COLUMN(CascRejectInvmass, cascRejectInvmass, float); + // MC matching result: DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // generator level DECLARE_SOA_COLUMN(CollisionMatched, collisionMatched, bool); DECLARE_SOA_COLUMN(DebugGenCharmBar, debugGenCharmBar, int8_t); -DECLARE_SOA_COLUMN(DebugGenXi, debugGenXi, int8_t); +DECLARE_SOA_COLUMN(DebugGenCasc, debugGenCasc, int8_t); DECLARE_SOA_COLUMN(DebugGenLambda, debugGenLambda, int8_t); DECLARE_SOA_COLUMN(OriginRec, originRec, int8_t); DECLARE_SOA_COLUMN(OriginGen, originGen, int8_t); DECLARE_SOA_COLUMN(PtCharmBaryonGen, ptCharmBaryonGen, float); -DECLARE_SOA_COLUMN(EtaCharmBaryonGen, etaCharmBaryonGen, float); +DECLARE_SOA_COLUMN(RapidityCharmBaryonGen, rapidityCharmBaryonGen, float); + +// dynamic columns +DECLARE_SOA_DYNAMIC_COLUMN(PtCharmBaryon, ptCharmBaryon, + [](float px, float py) -> float { return RecoDecay::pt(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(PtCasc, ptCasc, + [](float px, float py) -> float { return RecoDecay::pt(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(PtLambda, ptLambda, + [](float px, float py) -> float { return RecoDecay::pt(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(PtPiFromCharmBaryon, ptPiFromCharmBaryon, + [](float px, float py) -> float { return RecoDecay::pt(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(PtKaFromCasc, ptKaFromCasc, + [](float px, float py) -> float { return RecoDecay::pt(px, py); }); // mapping of decay types -enum DecayType { DecayToXiPi = 0, +enum DecayType { XiczeroToXiPi = 0, OmegaczeroToXiPi, - XiczeroToXiPi }; + OmegaczeroToOmegaPi, + OmegaczeroToOmegaK, + OmegaczeroToOmegaPiOneMu }; -} // end of namespace hf_cand_toxipi +} // end of namespace hf_cand_xic0_omegac0 // declare dedicated Omegac and Xic to Xi Pi candidate table DECLARE_SOA_TABLE(HfCandToXiPi, "AOD", "HFCANDTOXIPI", o2::soa::Index<>, - hf_cand_toxipi::CollisionId, hf_cand_toxipi::XPv, hf_cand_toxipi::YPv, hf_cand_toxipi::ZPv, - hf_cand_toxipi::XDecayVtxCharmBaryon, hf_cand_toxipi::YDecayVtxCharmBaryon, hf_cand_toxipi::ZDecayVtxCharmBaryon, - hf_cand_toxipi::XDecayVtxCascade, hf_cand_toxipi::YDecayVtxCascade, hf_cand_toxipi::ZDecayVtxCascade, - hf_cand_toxipi::XDecayVtxV0, hf_cand_toxipi::YDecayVtxV0, hf_cand_toxipi::ZDecayVtxV0, - hf_cand_toxipi::SignDecay, // charge pi<-cascade (neg -> omegac, pos -> antiomegac) - hf_cand_toxipi::CovVtxCharmBaryon0, hf_cand_toxipi::CovVtxCharmBaryon1, hf_cand_toxipi::CovVtxCharmBaryon2, hf_cand_toxipi::CovVtxCharmBaryon3, hf_cand_toxipi::CovVtxCharmBaryon4, hf_cand_toxipi::CovVtxCharmBaryon5, - hf_cand_toxipi::PxCharmBaryon, hf_cand_toxipi::PyCharmBaryon, hf_cand_toxipi::PzCharmBaryon, - hf_cand_toxipi::PxCasc, hf_cand_toxipi::PyCasc, hf_cand_toxipi::PzCasc, - hf_cand_toxipi::PxPiFromCharmBaryon, hf_cand_toxipi::PyPiFromCharmBaryon, hf_cand_toxipi::PzPiFromCharmBaryon, - hf_cand_toxipi::PxLambda, hf_cand_toxipi::PyLambda, hf_cand_toxipi::PzLambda, - hf_cand_toxipi::PxPiFromCasc, hf_cand_toxipi::PyPiFromCasc, hf_cand_toxipi::PzPiFromCasc, - hf_cand_toxipi::PxPosV0Dau, hf_cand_toxipi::PyPosV0Dau, hf_cand_toxipi::PzPosV0Dau, - hf_cand_toxipi::PxNegV0Dau, hf_cand_toxipi::PyNegV0Dau, hf_cand_toxipi::PzNegV0Dau, - hf_cand_toxipi::ImpactParCascXY, hf_cand_toxipi::ImpactParPiFromCharmBaryonXY, hf_cand_toxipi::ImpactParCascZ, hf_cand_toxipi::ImpactParPiFromCharmBaryonZ, - hf_cand_toxipi::ErrImpactParCascXY, hf_cand_toxipi::ErrImpactParPiFromCharmBaryonXY, - hf_cand_toxipi::V0Id, v0data::PosTrackId, v0data::NegTrackId, hf_cand_toxipi::CascadeId, hf_cand_toxipi::PiFromCharmBaryonId, cascdata::BachelorId, - hf_cand_toxipi::InvMassLambda, hf_cand_toxipi::InvMassCascade, hf_cand_toxipi::InvMassCharmBaryon, - hf_cand_toxipi::CosPAV0, hf_cand_toxipi::CosPACharmBaryon, hf_cand_toxipi::CosPACasc, hf_cand_toxipi::CosPAXYV0, hf_cand_toxipi::CosPAXYCharmBaryon, hf_cand_toxipi::CosPAXYCasc, - hf_cand_toxipi::CTauOmegac, hf_cand_toxipi::CTauCascade, hf_cand_toxipi::CTauV0, hf_cand_toxipi::CTauXic, - hf_cand_toxipi::EtaV0PosDau, hf_cand_toxipi::EtaV0NegDau, hf_cand_toxipi::EtaPiFromCasc, hf_cand_toxipi::EtaPiFromCharmBaryon, - hf_cand_toxipi::EtaCharmBaryon, hf_cand_toxipi::EtaCascade, hf_cand_toxipi::EtaV0, - hf_cand_toxipi::DcaXYToPvV0Dau0, hf_cand_toxipi::DcaXYToPvV0Dau1, hf_cand_toxipi::DcaXYToPvCascDau, - hf_cand_toxipi::DcaZToPvV0Dau0, hf_cand_toxipi::DcaZToPvV0Dau1, hf_cand_toxipi::DcaZToPvCascDau, - hf_cand_toxipi::DcaCascDau, hf_cand_toxipi::DcaV0Dau, hf_cand_toxipi::DcaCharmBaryonDau, - hf_cand_toxipi::DecLenCharmBaryon, hf_cand_toxipi::DecLenCascade, hf_cand_toxipi::DecLenV0, hf_cand_toxipi::ErrorDecayLengthCharmBaryon, hf_cand_toxipi::ErrorDecayLengthXYCharmBaryon, - hf_track_index::HFflag); + hf_cand_xic0_omegac0::CollisionId, hf_cand_xic0_omegac0::XPv, hf_cand_xic0_omegac0::YPv, hf_cand_xic0_omegac0::ZPv, + hf_cand_xic0_omegac0::XDecayVtxCharmBaryon, hf_cand_xic0_omegac0::YDecayVtxCharmBaryon, hf_cand_xic0_omegac0::ZDecayVtxCharmBaryon, + hf_cand_xic0_omegac0::XDecayVtxCascade, hf_cand_xic0_omegac0::YDecayVtxCascade, hf_cand_xic0_omegac0::ZDecayVtxCascade, + hf_cand_xic0_omegac0::XDecayVtxV0, hf_cand_xic0_omegac0::YDecayVtxV0, hf_cand_xic0_omegac0::ZDecayVtxV0, + hf_cand_xic0_omegac0::SignDecay, // charge pi<-cascade (neg -> omegac, pos -> antiomegac) + hf_cand_xic0_omegac0::CovVtxCharmBaryon0, hf_cand_xic0_omegac0::CovVtxCharmBaryon1, hf_cand_xic0_omegac0::CovVtxCharmBaryon2, hf_cand_xic0_omegac0::CovVtxCharmBaryon3, hf_cand_xic0_omegac0::CovVtxCharmBaryon4, hf_cand_xic0_omegac0::CovVtxCharmBaryon5, + hf_cand_xic0_omegac0::PxCharmBaryon, hf_cand_xic0_omegac0::PyCharmBaryon, hf_cand_xic0_omegac0::PzCharmBaryon, + hf_cand_xic0_omegac0::PxCasc, hf_cand_xic0_omegac0::PyCasc, hf_cand_xic0_omegac0::PzCasc, + hf_cand_xic0_omegac0::PxBachFromCharmBaryon, hf_cand_xic0_omegac0::PyBachFromCharmBaryon, hf_cand_xic0_omegac0::PzBachFromCharmBaryon, + hf_cand_xic0_omegac0::PxLambda, hf_cand_xic0_omegac0::PyLambda, hf_cand_xic0_omegac0::PzLambda, + hf_cand_xic0_omegac0::PxBachFromCasc, hf_cand_xic0_omegac0::PyBachFromCasc, hf_cand_xic0_omegac0::PzBachFromCasc, + hf_cand_xic0_omegac0::PxPosV0Dau, hf_cand_xic0_omegac0::PyPosV0Dau, hf_cand_xic0_omegac0::PzPosV0Dau, + hf_cand_xic0_omegac0::PxNegV0Dau, hf_cand_xic0_omegac0::PyNegV0Dau, hf_cand_xic0_omegac0::PzNegV0Dau, + hf_cand_xic0_omegac0::ImpactParCascXY, hf_cand_xic0_omegac0::ImpactParBachFromCharmBaryonXY, hf_cand_xic0_omegac0::ImpactParCascZ, hf_cand_xic0_omegac0::ImpactParBachFromCharmBaryonZ, + hf_cand_xic0_omegac0::ErrImpactParCascXY, hf_cand_xic0_omegac0::ErrImpactParBachFromCharmBaryonXY, + hf_cand_xic0_omegac0::V0Id, v0data::PosTrackId, v0data::NegTrackId, hf_cand_xic0_omegac0::CascadeId, hf_cand_xic0_omegac0::BachelorFromCharmBaryonId, cascdata::BachelorId, + hf_cand_xic0_omegac0::InvMassLambda, hf_cand_xic0_omegac0::InvMassCascade, hf_cand_xic0_omegac0::InvMassCharmBaryon, + hf_cand_xic0_omegac0::CosPAV0, hf_cand_xic0_omegac0::CosPACharmBaryon, hf_cand_xic0_omegac0::CosPACasc, hf_cand_xic0_omegac0::CosPAXYV0, hf_cand_xic0_omegac0::CosPAXYCharmBaryon, hf_cand_xic0_omegac0::CosPAXYCasc, + hf_cand_xic0_omegac0::CTauOmegac, hf_cand_xic0_omegac0::CTauCascade, hf_cand_xic0_omegac0::CTauV0, hf_cand_xic0_omegac0::CTauXic, + hf_cand_xic0_omegac0::EtaV0PosDau, hf_cand_xic0_omegac0::EtaV0NegDau, hf_cand_xic0_omegac0::EtaBachFromCasc, hf_cand_xic0_omegac0::EtaBachFromCharmBaryon, + hf_cand_xic0_omegac0::EtaCharmBaryon, hf_cand_xic0_omegac0::EtaCascade, hf_cand_xic0_omegac0::EtaV0, + hf_cand_xic0_omegac0::DcaXYToPvV0Dau0, hf_cand_xic0_omegac0::DcaXYToPvV0Dau1, hf_cand_xic0_omegac0::DcaXYToPvCascDau, + hf_cand_xic0_omegac0::DcaZToPvV0Dau0, hf_cand_xic0_omegac0::DcaZToPvV0Dau1, hf_cand_xic0_omegac0::DcaZToPvCascDau, + hf_cand_xic0_omegac0::DcaCascDau, hf_cand_xic0_omegac0::DcaV0Dau, hf_cand_xic0_omegac0::DcaCharmBaryonDau, + hf_cand_xic0_omegac0::DecLenCharmBaryon, hf_cand_xic0_omegac0::DecLenCascade, hf_cand_xic0_omegac0::DecLenV0, hf_cand_xic0_omegac0::ErrorDecayLengthCharmBaryon, hf_cand_xic0_omegac0::ErrorDecayLengthXYCharmBaryon); + +DECLARE_SOA_TABLE(HfCandToOmegaPi, "AOD", "HFCANDTOOMEGAPI", + o2::soa::Index<>, + hf_cand_xic0_omegac0::CollisionId, hf_cand_xic0_omegac0::XPv, hf_cand_xic0_omegac0::YPv, hf_cand_xic0_omegac0::ZPv, + hf_cand_xic0_omegac0::XDecayVtxCharmBaryon, hf_cand_xic0_omegac0::YDecayVtxCharmBaryon, hf_cand_xic0_omegac0::ZDecayVtxCharmBaryon, + hf_cand_xic0_omegac0::XDecayVtxCascade, hf_cand_xic0_omegac0::YDecayVtxCascade, hf_cand_xic0_omegac0::ZDecayVtxCascade, + hf_cand_xic0_omegac0::XDecayVtxV0, hf_cand_xic0_omegac0::YDecayVtxV0, hf_cand_xic0_omegac0::ZDecayVtxV0, + hf_cand_xic0_omegac0::SignDecay, // charge pi<-cascade (neg -> omegac, pos -> antiomegac) + hf_cand_xic0_omegac0::CovVtxCharmBaryon0, hf_cand_xic0_omegac0::CovVtxCharmBaryon1, hf_cand_xic0_omegac0::CovVtxCharmBaryon2, hf_cand_xic0_omegac0::CovVtxCharmBaryon3, hf_cand_xic0_omegac0::CovVtxCharmBaryon4, hf_cand_xic0_omegac0::CovVtxCharmBaryon5, + hf_cand_xic0_omegac0::PxCharmBaryon, hf_cand_xic0_omegac0::PyCharmBaryon, hf_cand_xic0_omegac0::PzCharmBaryon, + hf_cand_xic0_omegac0::PxCasc, hf_cand_xic0_omegac0::PyCasc, hf_cand_xic0_omegac0::PzCasc, + hf_cand_xic0_omegac0::PxBachFromCharmBaryon, hf_cand_xic0_omegac0::PyBachFromCharmBaryon, hf_cand_xic0_omegac0::PzBachFromCharmBaryon, + hf_cand_xic0_omegac0::PxLambda, hf_cand_xic0_omegac0::PyLambda, hf_cand_xic0_omegac0::PzLambda, + hf_cand_xic0_omegac0::PxBachFromCasc, hf_cand_xic0_omegac0::PyBachFromCasc, hf_cand_xic0_omegac0::PzBachFromCasc, + hf_cand_xic0_omegac0::PxPosV0Dau, hf_cand_xic0_omegac0::PyPosV0Dau, hf_cand_xic0_omegac0::PzPosV0Dau, + hf_cand_xic0_omegac0::PxNegV0Dau, hf_cand_xic0_omegac0::PyNegV0Dau, hf_cand_xic0_omegac0::PzNegV0Dau, + // dynamic + hf_cand_xic0_omegac0::PtCharmBaryon, + hf_cand_xic0_omegac0::PtCasc, + hf_cand_xic0_omegac0::PtPiFromCharmBaryon, + hf_cand_xic0_omegac0::PtLambda, + hf_cand_xic0_omegac0::PtKaFromCasc, + + hf_cand_xic0_omegac0::ImpactParCascXY, hf_cand_xic0_omegac0::ImpactParBachFromCharmBaryonXY, hf_cand_xic0_omegac0::ImpactParCascZ, hf_cand_xic0_omegac0::ImpactParBachFromCharmBaryonZ, + hf_cand_xic0_omegac0::ErrImpactParCascXY, hf_cand_xic0_omegac0::ErrImpactParBachFromCharmBaryonXY, + hf_cand_xic0_omegac0::V0Id, v0data::PosTrackId, v0data::NegTrackId, hf_cand_xic0_omegac0::CascadeId, hf_cand_xic0_omegac0::BachelorFromCharmBaryonId, cascdata::BachelorId, + hf_cand_xic0_omegac0::InvMassLambda, hf_cand_xic0_omegac0::InvMassCascade, hf_cand_xic0_omegac0::InvMassCharmBaryon, + hf_cand_xic0_omegac0::CosPAV0, hf_cand_xic0_omegac0::CosPACharmBaryon, hf_cand_xic0_omegac0::CosPACasc, hf_cand_xic0_omegac0::CosPAXYV0, hf_cand_xic0_omegac0::CosPAXYCharmBaryon, hf_cand_xic0_omegac0::CosPAXYCasc, + hf_cand_xic0_omegac0::CTauOmegac, hf_cand_xic0_omegac0::CTauCascade, hf_cand_xic0_omegac0::CTauV0, + hf_cand_xic0_omegac0::EtaV0PosDau, hf_cand_xic0_omegac0::EtaV0NegDau, hf_cand_xic0_omegac0::EtaBachFromCasc, hf_cand_xic0_omegac0::EtaBachFromCharmBaryon, + hf_cand_xic0_omegac0::EtaCharmBaryon, hf_cand_xic0_omegac0::EtaCascade, hf_cand_xic0_omegac0::EtaV0, + hf_cand_xic0_omegac0::DcaXYToPvV0Dau0, hf_cand_xic0_omegac0::DcaXYToPvV0Dau1, hf_cand_xic0_omegac0::DcaXYToPvCascDau, + hf_cand_xic0_omegac0::DcaZToPvV0Dau0, hf_cand_xic0_omegac0::DcaZToPvV0Dau1, hf_cand_xic0_omegac0::DcaZToPvCascDau, + hf_cand_xic0_omegac0::DcaCascDau, hf_cand_xic0_omegac0::DcaV0Dau, hf_cand_xic0_omegac0::DcaCharmBaryonDau, + hf_cand_xic0_omegac0::DecLenCharmBaryon, hf_cand_xic0_omegac0::DecLenCascade, hf_cand_xic0_omegac0::DecLenV0, hf_cand_xic0_omegac0::ErrorDecayLengthCharmBaryon, hf_cand_xic0_omegac0::ErrorDecayLengthXYCharmBaryon, hf_track_index::HFflag, + o2::soa::Marker<1>); + +DECLARE_SOA_TABLE(HfCandToOmegaK, "AOD", "HFCANDTOOMEGAK", + o2::soa::Index<>, + hf_cand_xic0_omegac0::CollisionId, hf_cand_xic0_omegac0::XPv, hf_cand_xic0_omegac0::YPv, hf_cand_xic0_omegac0::ZPv, + hf_cand_xic0_omegac0::XDecayVtxCharmBaryon, hf_cand_xic0_omegac0::YDecayVtxCharmBaryon, hf_cand_xic0_omegac0::ZDecayVtxCharmBaryon, + hf_cand_xic0_omegac0::XDecayVtxCascade, hf_cand_xic0_omegac0::YDecayVtxCascade, hf_cand_xic0_omegac0::ZDecayVtxCascade, + hf_cand_xic0_omegac0::XDecayVtxV0, hf_cand_xic0_omegac0::YDecayVtxV0, hf_cand_xic0_omegac0::ZDecayVtxV0, + hf_cand_xic0_omegac0::SignDecay, // charge pi<-cascade (neg -> omegac, pos -> antiomegac) + hf_cand_xic0_omegac0::CovVtxCharmBaryon0, hf_cand_xic0_omegac0::CovVtxCharmBaryon1, hf_cand_xic0_omegac0::CovVtxCharmBaryon2, hf_cand_xic0_omegac0::CovVtxCharmBaryon3, hf_cand_xic0_omegac0::CovVtxCharmBaryon4, hf_cand_xic0_omegac0::CovVtxCharmBaryon5, + hf_cand_xic0_omegac0::PxCharmBaryon, hf_cand_xic0_omegac0::PyCharmBaryon, hf_cand_xic0_omegac0::PzCharmBaryon, + hf_cand_xic0_omegac0::PxCasc, hf_cand_xic0_omegac0::PyCasc, hf_cand_xic0_omegac0::PzCasc, + hf_cand_xic0_omegac0::PxBachFromCharmBaryon, hf_cand_xic0_omegac0::PyBachFromCharmBaryon, hf_cand_xic0_omegac0::PzBachFromCharmBaryon, + hf_cand_xic0_omegac0::PxLambda, hf_cand_xic0_omegac0::PyLambda, hf_cand_xic0_omegac0::PzLambda, + hf_cand_xic0_omegac0::PxBachFromCasc, hf_cand_xic0_omegac0::PyBachFromCasc, hf_cand_xic0_omegac0::PzBachFromCasc, + hf_cand_xic0_omegac0::PxPosV0Dau, hf_cand_xic0_omegac0::PyPosV0Dau, hf_cand_xic0_omegac0::PzPosV0Dau, + hf_cand_xic0_omegac0::PxNegV0Dau, hf_cand_xic0_omegac0::PyNegV0Dau, hf_cand_xic0_omegac0::PzNegV0Dau, + hf_cand_xic0_omegac0::ImpactParCascXY, hf_cand_xic0_omegac0::ImpactParBachFromCharmBaryonXY, hf_cand_xic0_omegac0::ImpactParCascZ, hf_cand_xic0_omegac0::ImpactParBachFromCharmBaryonZ, + hf_cand_xic0_omegac0::ErrImpactParCascXY, hf_cand_xic0_omegac0::ErrImpactParBachFromCharmBaryonXY, + hf_cand_xic0_omegac0::V0Id, v0data::PosTrackId, v0data::NegTrackId, hf_cand_xic0_omegac0::CascadeId, hf_cand_xic0_omegac0::BachelorFromCharmBaryonId, cascdata::BachelorId, + hf_cand_xic0_omegac0::InvMassLambda, hf_cand_xic0_omegac0::InvMassCascade, hf_cand_xic0_omegac0::InvMassCharmBaryon, + hf_cand_xic0_omegac0::CosPAV0, hf_cand_xic0_omegac0::CosPACharmBaryon, hf_cand_xic0_omegac0::CosPACasc, hf_cand_xic0_omegac0::CosPAXYV0, hf_cand_xic0_omegac0::CosPAXYCharmBaryon, hf_cand_xic0_omegac0::CosPAXYCasc, + hf_cand_xic0_omegac0::CTauOmegac, hf_cand_xic0_omegac0::CTauCascade, hf_cand_xic0_omegac0::CTauV0, + hf_cand_xic0_omegac0::EtaV0PosDau, hf_cand_xic0_omegac0::EtaV0NegDau, hf_cand_xic0_omegac0::EtaBachFromCasc, hf_cand_xic0_omegac0::EtaBachFromCharmBaryon, + hf_cand_xic0_omegac0::EtaCharmBaryon, hf_cand_xic0_omegac0::EtaCascade, hf_cand_xic0_omegac0::EtaV0, + hf_cand_xic0_omegac0::DcaXYToPvV0Dau0, hf_cand_xic0_omegac0::DcaXYToPvV0Dau1, hf_cand_xic0_omegac0::DcaXYToPvCascDau, + hf_cand_xic0_omegac0::DcaZToPvV0Dau0, hf_cand_xic0_omegac0::DcaZToPvV0Dau1, hf_cand_xic0_omegac0::DcaZToPvCascDau, + hf_cand_xic0_omegac0::DcaCascDau, hf_cand_xic0_omegac0::DcaV0Dau, hf_cand_xic0_omegac0::DcaCharmBaryonDau, + hf_cand_xic0_omegac0::DecLenCharmBaryon, hf_cand_xic0_omegac0::DecLenCascade, hf_cand_xic0_omegac0::DecLenV0, hf_cand_xic0_omegac0::ErrorDecayLengthCharmBaryon, hf_cand_xic0_omegac0::ErrorDecayLengthXYCharmBaryon, + o2::soa::Marker<2>); + +// table with results of KFParticle +DECLARE_SOA_TABLE(HfOmegacKf, "AOD", "HFOMEGACKF", //! + hf_cand_xic0_omegac0::KfDcaXYPiFromOmegac, hf_cand_xic0_omegac0::KfDcaXYCascToPv, + hf_cand_xic0_omegac0::Chi2GeoV0, hf_cand_xic0_omegac0::Chi2GeoCasc, hf_cand_xic0_omegac0::Chi2GeoOmegac, + hf_cand_xic0_omegac0::Chi2MassV0, hf_cand_xic0_omegac0::Chi2MassCasc, + hf_cand_xic0_omegac0::V0ldl, hf_cand_xic0_omegac0::Cascldl, hf_cand_xic0_omegac0::Omegacldl, + hf_cand_xic0_omegac0::Chi2TopoV0ToPv, hf_cand_xic0_omegac0::Chi2TopoCascToPv, hf_cand_xic0_omegac0::Chi2TopoPiFromOmegacToPv, hf_cand_xic0_omegac0::Chi2TopoOmegacToPv, hf_cand_xic0_omegac0::DeviationPiFromOmegacToPv, + hf_cand_xic0_omegac0::Chi2TopoV0ToCasc, hf_cand_xic0_omegac0::Chi2TopoCascToOmegac, + hf_cand_xic0_omegac0::DecayLenXYLambda, hf_cand_xic0_omegac0::DecayLenXYCasc, hf_cand_xic0_omegac0::DecayLenXYOmegac, + hf_cand_xic0_omegac0::CosPaV0ToCasc, hf_cand_xic0_omegac0::CosPaCascToOmegac, hf_cand_xic0_omegac0::CosPaXYV0ToCasc, hf_cand_xic0_omegac0::CosPaXYCascToOmegac, + hf_cand_xic0_omegac0::KfRapOmegac, + hf_cand_xic0_omegac0::KfptPiFromOmegac, hf_cand_xic0_omegac0::KfptOmegac, + hf_cand_xic0_omegac0::CosThetaStarPiFromOmegac, + hf_cand_xic0_omegac0::V0Ndf, hf_cand_xic0_omegac0::CascNdf, hf_cand_xic0_omegac0::OmegacNdf, + hf_cand_xic0_omegac0::MassV0Ndf, hf_cand_xic0_omegac0::MassCascNdf, + hf_cand_xic0_omegac0::V0Chi2OverNdf, hf_cand_xic0_omegac0::CascChi2OverNdf, hf_cand_xic0_omegac0::OmegacChi2OverNdf, + hf_cand_xic0_omegac0::MassV0Chi2OverNdf, hf_cand_xic0_omegac0::MassCascChi2OverNdf, hf_cand_xic0_omegac0::CascRejectInvmass); + +DECLARE_SOA_TABLE(HfCandToXiPiKf, "AOD", "HFCANDTOXIPIKF", //! + o2::soa::Index<>, + hf_cand_xic0_omegac0::CollisionId, hf_cand_xic0_omegac0::XPv, hf_cand_xic0_omegac0::YPv, hf_cand_xic0_omegac0::ZPv, + hf_cand_xic0_omegac0::XDecayVtxCharmBaryon, hf_cand_xic0_omegac0::YDecayVtxCharmBaryon, hf_cand_xic0_omegac0::ZDecayVtxCharmBaryon, + hf_cand_xic0_omegac0::XDecayVtxCascade, hf_cand_xic0_omegac0::YDecayVtxCascade, hf_cand_xic0_omegac0::ZDecayVtxCascade, + hf_cand_xic0_omegac0::XDecayVtxV0, hf_cand_xic0_omegac0::YDecayVtxV0, hf_cand_xic0_omegac0::ZDecayVtxV0, + hf_cand_xic0_omegac0::SignDecay, + hf_cand_xic0_omegac0::CovVtxCharmBaryon0, hf_cand_xic0_omegac0::CovVtxCharmBaryon1, hf_cand_xic0_omegac0::CovVtxCharmBaryon2, hf_cand_xic0_omegac0::CovVtxCharmBaryon3, hf_cand_xic0_omegac0::CovVtxCharmBaryon4, hf_cand_xic0_omegac0::CovVtxCharmBaryon5, + hf_cand_xic0_omegac0::PxCharmBaryon, hf_cand_xic0_omegac0::PyCharmBaryon, hf_cand_xic0_omegac0::PzCharmBaryon, + hf_cand_xic0_omegac0::PxCasc, hf_cand_xic0_omegac0::PyCasc, hf_cand_xic0_omegac0::PzCasc, + hf_cand_xic0_omegac0::PxBachFromCharmBaryon, hf_cand_xic0_omegac0::PyBachFromCharmBaryon, hf_cand_xic0_omegac0::PzBachFromCharmBaryon, + hf_cand_xic0_omegac0::PxLambda, hf_cand_xic0_omegac0::PyLambda, hf_cand_xic0_omegac0::PzLambda, + hf_cand_xic0_omegac0::PxBachFromCasc, hf_cand_xic0_omegac0::PyBachFromCasc, hf_cand_xic0_omegac0::PzBachFromCasc, + hf_cand_xic0_omegac0::PxPosV0Dau, hf_cand_xic0_omegac0::PyPosV0Dau, hf_cand_xic0_omegac0::PzPosV0Dau, + hf_cand_xic0_omegac0::PxNegV0Dau, hf_cand_xic0_omegac0::PyNegV0Dau, hf_cand_xic0_omegac0::PzNegV0Dau, + hf_cand_xic0_omegac0::ImpactParCascXY, hf_cand_xic0_omegac0::ImpactParBachFromCharmBaryonXY, hf_cand_xic0_omegac0::ImpactParCascZ, hf_cand_xic0_omegac0::ImpactParBachFromCharmBaryonZ, + hf_cand_xic0_omegac0::ErrImpactParCascXY, hf_cand_xic0_omegac0::ErrImpactParBachFromCharmBaryonXY, + hf_cand_xic0_omegac0::V0Id, v0data::PosTrackId, v0data::NegTrackId, hf_cand_xic0_omegac0::CascadeId, hf_cand_xic0_omegac0::BachelorFromCharmBaryonId, cascdata::BachelorId, + hf_cand_xic0_omegac0::InvMassLambda, hf_cand_xic0_omegac0::InvMassCascade, hf_cand_xic0_omegac0::InvMassCharmBaryon, + hf_cand_xic0_omegac0::CosPAV0, hf_cand_xic0_omegac0::CosPACharmBaryon, hf_cand_xic0_omegac0::CosPACasc, hf_cand_xic0_omegac0::CosPAXYV0, hf_cand_xic0_omegac0::CosPAXYCharmBaryon, hf_cand_xic0_omegac0::CosPAXYCasc, + hf_cand_xic0_omegac0::CTauOmegac, hf_cand_xic0_omegac0::CTauCascade, hf_cand_xic0_omegac0::CTauV0, hf_cand_xic0_omegac0::CTauXic, + hf_cand_xic0_omegac0::EtaV0PosDau, hf_cand_xic0_omegac0::EtaV0NegDau, hf_cand_xic0_omegac0::EtaBachFromCasc, hf_cand_xic0_omegac0::EtaBachFromCharmBaryon, + hf_cand_xic0_omegac0::EtaCharmBaryon, hf_cand_xic0_omegac0::EtaCascade, hf_cand_xic0_omegac0::EtaV0, + hf_cand_xic0_omegac0::DcaXYToPvV0Dau0, hf_cand_xic0_omegac0::DcaXYToPvV0Dau1, hf_cand_xic0_omegac0::DcaXYToPvCascDau, + hf_cand_xic0_omegac0::DcaZToPvV0Dau0, hf_cand_xic0_omegac0::DcaZToPvV0Dau1, hf_cand_xic0_omegac0::DcaZToPvCascDau, + hf_cand_xic0_omegac0::DcaCascDau, hf_cand_xic0_omegac0::DcaV0Dau, hf_cand_xic0_omegac0::DcaCharmBaryonDau, + hf_cand_xic0_omegac0::DecLenCharmBaryon, hf_cand_xic0_omegac0::DecLenCascade, hf_cand_xic0_omegac0::DecLenV0, hf_cand_xic0_omegac0::ErrorDecayLengthCharmBaryon, hf_cand_xic0_omegac0::ErrorDecayLengthXYCharmBaryon, + hf_cand_xic0_omegac0::KfDcaXYPiFromXic, hf_cand_xic0_omegac0::KfDcaXYCascToPv, + hf_cand_xic0_omegac0::Chi2GeoV0, hf_cand_xic0_omegac0::Chi2GeoCasc, hf_cand_xic0_omegac0::Chi2GeoXic, + hf_cand_xic0_omegac0::Chi2MassV0, hf_cand_xic0_omegac0::Chi2MassCasc, + hf_cand_xic0_omegac0::V0ldl, hf_cand_xic0_omegac0::Cascldl, hf_cand_xic0_omegac0::Xicldl, + hf_cand_xic0_omegac0::Chi2TopoV0ToPv, hf_cand_xic0_omegac0::Chi2TopoCascToPv, hf_cand_xic0_omegac0::Chi2TopoPiFromXicToPv, hf_cand_xic0_omegac0::Chi2TopoXicToPv, + hf_cand_xic0_omegac0::Chi2TopoV0ToCasc, hf_cand_xic0_omegac0::Chi2TopoCascToXic, + hf_cand_xic0_omegac0::DecayLenXYLambda, hf_cand_xic0_omegac0::DecayLenXYCasc, hf_cand_xic0_omegac0::DecayLenXYXic, + hf_cand_xic0_omegac0::CosPaV0ToCasc, hf_cand_xic0_omegac0::CosPaCascToXic, hf_cand_xic0_omegac0::CosPaXYV0ToCasc, hf_cand_xic0_omegac0::CosPaXYCascToXic, + hf_cand_xic0_omegac0::KfRapXic, + hf_cand_xic0_omegac0::KfptPiFromXic, hf_cand_xic0_omegac0::KfptXic, + hf_cand_xic0_omegac0::CosThetaStarPiFromXic, + hf_cand_xic0_omegac0::V0Ndf, hf_cand_xic0_omegac0::CascNdf, hf_cand_xic0_omegac0::XicNdf, + hf_cand_xic0_omegac0::MassV0Ndf, hf_cand_xic0_omegac0::MassCascNdf, + hf_cand_xic0_omegac0::V0Chi2OverNdf, hf_cand_xic0_omegac0::CascChi2OverNdf, hf_cand_xic0_omegac0::XicChi2OverNdf, + hf_cand_xic0_omegac0::MassV0Chi2OverNdf, hf_cand_xic0_omegac0::MassCascChi2OverNdf); // table with results of reconstruction level MC matching -DECLARE_SOA_TABLE(HfToXiPiMCRec, "AOD", "HFTOXIPIMCREC", //! - hf_cand_toxipi::FlagMcMatchRec, - hf_cand_toxipi::DebugMcRec, - hf_cand_toxipi::OriginRec, - hf_cand_toxipi::CollisionMatched); +DECLARE_SOA_TABLE(HfXicToXiPiMCRec, "AOD", "HFXICXIPIMCREC", //! + hf_cand_xic0_omegac0::FlagMcMatchRec, + hf_cand_xic0_omegac0::DebugMcRec, + hf_cand_xic0_omegac0::OriginRec, + hf_cand_xic0_omegac0::CollisionMatched, + hf_cand::PtBhadMotherPart, + hf_cand::PdgBhadMotherPart, + o2::soa::Marker<1>); +DECLARE_SOA_TABLE(HfOmegacToXiPiMCRec, "AOD", "HFOMCXIPIMCREC", //! + hf_cand_xic0_omegac0::FlagMcMatchRec, + hf_cand_xic0_omegac0::DebugMcRec, + hf_cand_xic0_omegac0::OriginRec, + hf_cand_xic0_omegac0::CollisionMatched, + hf_cand::PtBhadMotherPart, + hf_cand::PdgBhadMotherPart, + o2::soa::Marker<2>); +DECLARE_SOA_TABLE(HfToOmegaPiMCRec, "AOD", "HFTOOMEPIMCREC", //! + hf_cand_xic0_omegac0::FlagMcMatchRec, + hf_cand_xic0_omegac0::DebugMcRec, + hf_cand_xic0_omegac0::OriginRec, + hf_cand_xic0_omegac0::CollisionMatched, + hf_cand::PtBhadMotherPart, + hf_cand::PdgBhadMotherPart, + o2::soa::Marker<3>); +DECLARE_SOA_TABLE(HfToOmegaKMCRec, "AOD", "HFTOOMEKMCREC", //! + hf_cand_xic0_omegac0::FlagMcMatchRec, + hf_cand_xic0_omegac0::DebugMcRec, + hf_cand_xic0_omegac0::OriginRec, + hf_cand_xic0_omegac0::CollisionMatched, + hf_cand::PtBhadMotherPart, + hf_cand::PdgBhadMotherPart, + o2::soa::Marker<4>); // table with results of generator level MC matching -DECLARE_SOA_TABLE(HfToXiPiMCGen, "AOD", "HFTOXIPIMCGEN", //! - hf_cand_toxipi::FlagMcMatchGen, hf_cand_toxipi::DebugGenCharmBar, hf_cand_toxipi::DebugGenXi, hf_cand_toxipi::DebugGenLambda, hf_cand_toxipi::PtCharmBaryonGen, hf_cand_toxipi::EtaCharmBaryonGen, hf_cand_toxipi::OriginGen); +DECLARE_SOA_TABLE(HfXicToXiPiMCGen, "AOD", "HFXICXIPIMCGEN", //! + hf_cand_xic0_omegac0::FlagMcMatchGen, hf_cand_xic0_omegac0::DebugGenCharmBar, hf_cand_xic0_omegac0::DebugGenCasc, hf_cand_xic0_omegac0::DebugGenLambda, + hf_cand_xic0_omegac0::PtCharmBaryonGen, hf_cand_xic0_omegac0::RapidityCharmBaryonGen, hf_cand_xic0_omegac0::OriginGen, hf_cand::IdxBhadMotherPart, o2::soa::Marker<1>); +DECLARE_SOA_TABLE(HfOmegacToXiPiMCGen, "AOD", "HFOMECXIPIMCGEN", //! + hf_cand_xic0_omegac0::FlagMcMatchGen, hf_cand_xic0_omegac0::DebugGenCharmBar, hf_cand_xic0_omegac0::DebugGenCasc, hf_cand_xic0_omegac0::DebugGenLambda, + hf_cand_xic0_omegac0::PtCharmBaryonGen, hf_cand_xic0_omegac0::RapidityCharmBaryonGen, hf_cand_xic0_omegac0::OriginGen, hf_cand::IdxBhadMotherPart, o2::soa::Marker<2>); +DECLARE_SOA_TABLE(HfToOmegaPiMCGen, "AOD", "HFTOOMEPIMCGEN", //! + hf_cand_xic0_omegac0::FlagMcMatchGen, hf_cand_xic0_omegac0::DebugGenCharmBar, hf_cand_xic0_omegac0::DebugGenCasc, hf_cand_xic0_omegac0::DebugGenLambda, + hf_cand_xic0_omegac0::PtCharmBaryonGen, hf_cand_xic0_omegac0::RapidityCharmBaryonGen, hf_cand_xic0_omegac0::OriginGen, hf_cand::IdxBhadMotherPart, o2::soa::Marker<3>); +DECLARE_SOA_TABLE(HfToOmegaKMCGen, "AOD", "HFTOOMEKMCGEN", //! + hf_cand_xic0_omegac0::FlagMcMatchGen, hf_cand_xic0_omegac0::DebugGenCharmBar, hf_cand_xic0_omegac0::DebugGenCasc, hf_cand_xic0_omegac0::DebugGenLambda, + hf_cand_xic0_omegac0::PtCharmBaryonGen, hf_cand_xic0_omegac0::RapidityCharmBaryonGen, hf_cand_xic0_omegac0::OriginGen, hf_cand::IdxBhadMotherPart, o2::soa::Marker<4>); + +// specific Xic to Xi Pi Pi candidate properties +namespace hf_cand_xic_to_xi_pi_pi +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Pi0, pi0, int, Tracks, "_pi0"); +DECLARE_SOA_INDEX_COLUMN_FULL(Pi1, pi1, int, Tracks, "_pi1"); +DECLARE_SOA_COLUMN(XPvErr, xPvErr, float); +DECLARE_SOA_COLUMN(YPvErr, yPvErr, float); +DECLARE_SOA_COLUMN(ZPvErr, zPvErr, float); +DECLARE_SOA_COLUMN(XSvErr, xSvErr, float); +DECLARE_SOA_COLUMN(YSvErr, ySvErr, float); +DECLARE_SOA_COLUMN(ZSvErr, zSvErr, float); +DECLARE_SOA_COLUMN(CosPaXi, cosPaXi, float); +DECLARE_SOA_COLUMN(CosPaXYXi, cosPaXYXi, float); +DECLARE_SOA_COLUMN(CosPaLambda, cosPaLambda, float); +DECLARE_SOA_COLUMN(CosPaXYLambda, cosPaXYLambda, float); +DECLARE_SOA_COLUMN(CosPaLambdaToXi, cosPaLambdaToXi, float); +DECLARE_SOA_COLUMN(CosPaXYLambdaToXi, cosPaXYLambdaToXi, float); +DECLARE_SOA_COLUMN(InvMassXicPlus, invMassXicPlus, float); +DECLARE_SOA_COLUMN(InvMassXi, invMassXi, float); +DECLARE_SOA_COLUMN(InvMassLambda, invMassLambda, float); +DECLARE_SOA_COLUMN(Sign, sign, float); +DECLARE_SOA_COLUMN(InvMassXiPi0, invMassXiPi0, float); +DECLARE_SOA_COLUMN(InvMassXiPi1, invMassXiPi1, float); +DECLARE_SOA_COLUMN(PBachelorPi, pBachelorPi, float); +DECLARE_SOA_COLUMN(PPiFromLambda, pPiFromLambda, float); +DECLARE_SOA_COLUMN(PPrFromLambda, pPrFromLambda, float); +DECLARE_SOA_COLUMN(DcaXiDaughters, dcaXiDaughters, float); +DECLARE_SOA_COLUMN(DcaV0Daughters, dcaV0Daughters, float); +DECLARE_SOA_COLUMN(DcaPosToPV, dcaPosToPV, float); +DECLARE_SOA_COLUMN(DcaNegToPV, dcaNegToPV, float); +DECLARE_SOA_COLUMN(DcaBachelorToPV, dcaBachelorToPV, float); +DECLARE_SOA_COLUMN(DcaXYCascToPV, dcaXYCascToPV, float); +DECLARE_SOA_COLUMN(DcaZCascToPV, dcaZCascToPV, float); +// KF specific columns +DECLARE_SOA_COLUMN(DcaXYPi0Pi1, dcaXYPi0Pi1, float); +DECLARE_SOA_COLUMN(DcaXYPi0Xi, dcaXYPi0Xi, float); +DECLARE_SOA_COLUMN(DcaXYPi1Xi, dcaXYPi1Xi, float); +DECLARE_SOA_COLUMN(DcaPi0Pi1, dcaPi0Pi1, float); +DECLARE_SOA_COLUMN(DcaPi0Xi, dcaPi0Xi, float); +DECLARE_SOA_COLUMN(DcaPi1Xi, dcaPi1Xi, float); +DECLARE_SOA_COLUMN(Chi2TopoXicPlusToPV, chi2TopoXicPlusToPV, float); +DECLARE_SOA_COLUMN(Chi2TopoXicPlusToPVBeforeConstraint, chi2TopoXicPlusToPVBeforeConstraint, float); +DECLARE_SOA_COLUMN(Chi2TopoXiToXicPlus, chi2TopoXiToXicPlus, float); +DECLARE_SOA_COLUMN(Chi2TopoXiToXicPlusBeforeConstraint, chi2TopoXiToXicPlusBeforeConstraint, float); +DECLARE_SOA_COLUMN(KfDecayLength, kfDecayLength, float); +DECLARE_SOA_COLUMN(KfDecayLengthNormalised, kfDecayLengthNormalised, float); +DECLARE_SOA_COLUMN(KfDecayLengthXY, kfDecayLengthXY, float); +DECLARE_SOA_COLUMN(KfDecayLengthXYNormalised, kfDecayLengthXYNormalised, float); +// PID +DECLARE_SOA_COLUMN(NSigTpcPiFromXicPlus0, nSigTpcPiFromXicPlus0, float); +DECLARE_SOA_COLUMN(NSigTpcPiFromXicPlus1, nSigTpcPiFromXicPlus1, float); +DECLARE_SOA_COLUMN(NSigTpcBachelorPi, nSigTpcBachelorPi, float); +DECLARE_SOA_COLUMN(NSigTpcPiFromLambda, nSigTpcPiFromLambda, float); +DECLARE_SOA_COLUMN(NSigTpcPrFromLambda, nSigTpcPrFromLambda, float); +DECLARE_SOA_COLUMN(NSigTofPiFromXicPlus0, nSigTofPiFromXicPlus0, float); +DECLARE_SOA_COLUMN(NSigTofPiFromXicPlus1, nSigTofPiFromXicPlus1, float); +DECLARE_SOA_COLUMN(NSigTofBachelorPi, nSigTofBachelorPi, float); +DECLARE_SOA_COLUMN(NSigTofPiFromLambda, nSigTofPiFromLambda, float); +DECLARE_SOA_COLUMN(NSigTofPrFromLambda, nSigTofPrFromLambda, float); +// MC matching result: +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // generator level +DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level +DECLARE_SOA_COLUMN(DebugMcGen, debugMcGen, int8_t); +DECLARE_SOA_COLUMN(OriginRec, originRec, int8_t); +DECLARE_SOA_COLUMN(OriginGen, originGen, int8_t); +// Dynamic columns +DECLARE_SOA_DYNAMIC_COLUMN(PProng0, pProng0, //! + [](float px, float py, float pz) -> float { return RecoDecay::p(px, py, pz); }); +DECLARE_SOA_DYNAMIC_COLUMN(PProng1, pProng1, //! + [](float px, float py, float pz) -> float { return RecoDecay::p(px, py, pz); }); +DECLARE_SOA_DYNAMIC_COLUMN(PProng2, pProng2, //! + [](float px, float py, float pz) -> float { return RecoDecay::p(px, py, pz); }); + +// mapping of decay types +enum DecayType { XicToXiPiPi = 0, // Ξc± → Ξ∓ π± π± + XicToXiResPiToXiPiPi, // Ξc± → Ξ(1530) π± → Ξ∓ π± π± + NDecayType }; +} // end of namespace hf_cand_xic_to_xi_pi_pi + +// declare dedicated Xic to Xi Pi Pi candidate table +DECLARE_SOA_TABLE(HfCandXicBase, "AOD", "HFCANDXICBASE", + hf_cand::CollisionId, + collision::PosX, collision::PosY, collision::PosZ, + hf_cand_xic_to_xi_pi_pi::XPvErr, hf_cand_xic_to_xi_pi_pi::YPvErr, hf_cand_xic_to_xi_pi_pi::ZPvErr, + // 3-prong specific columns + cascdata::CascadeId, hf_cand_xic_to_xi_pi_pi::Pi0Id, hf_cand_xic_to_xi_pi_pi::Pi1Id, + cascdata::BachelorId, cascdata::PosTrackId, cascdata::NegTrackId, + hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ZSecondaryVertex, + hf_cand_xic_to_xi_pi_pi::XSvErr, hf_cand_xic_to_xi_pi_pi::YSvErr, hf_cand_xic_to_xi_pi_pi::ZSvErr, + hf_cand::ErrorDecayLength, hf_cand::ErrorDecayLengthXY, + hf_cand::Chi2PCA, hf_cand_xic_to_xi_pi_pi::InvMassXicPlus, hf_cand_xic_to_xi_pi_pi::Sign, + hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, + hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, + hf_cand::PxProng2, hf_cand::PyProng2, hf_cand::PzProng2, + hf_cand::ImpactParameter0, hf_cand::ImpactParameter1, hf_cand::ImpactParameter2, + hf_cand::ErrorImpactParameter0, hf_cand::ErrorImpactParameter1, hf_cand::ErrorImpactParameter2, + // cascade specific columns + hf_cand_xic_to_xi_pi_pi::PBachelorPi, hf_cand_xic_to_xi_pi_pi::PPiFromLambda, hf_cand_xic_to_xi_pi_pi::PPrFromLambda, + hf_cand_xic_to_xi_pi_pi::CosPaXi, hf_cand_xic_to_xi_pi_pi::CosPaXYXi, hf_cand_xic_to_xi_pi_pi::CosPaLambda, hf_cand_xic_to_xi_pi_pi::CosPaXYLambda, hf_cand_xic_to_xi_pi_pi::CosPaLambdaToXi, hf_cand_xic_to_xi_pi_pi::CosPaXYLambdaToXi, + hf_cand_xic_to_xi_pi_pi::InvMassXi, hf_cand_xic_to_xi_pi_pi::InvMassLambda, hf_cand_xic_to_xi_pi_pi::InvMassXiPi0, hf_cand_xic_to_xi_pi_pi::InvMassXiPi1, + // DCA + hf_cand_xic_to_xi_pi_pi::DcaXiDaughters, hf_cand_xic_to_xi_pi_pi::DcaV0Daughters, hf_cand_xic_to_xi_pi_pi::DcaPosToPV, hf_cand_xic_to_xi_pi_pi::DcaNegToPV, hf_cand_xic_to_xi_pi_pi::DcaBachelorToPV, hf_cand_xic_to_xi_pi_pi::DcaXYCascToPV, hf_cand_xic_to_xi_pi_pi::DcaZCascToPV, + // PID + hf_cand_xic_to_xi_pi_pi::NSigTpcPiFromXicPlus0, hf_cand_xic_to_xi_pi_pi::NSigTpcPiFromXicPlus1, hf_cand_xic_to_xi_pi_pi::NSigTpcBachelorPi, hf_cand_xic_to_xi_pi_pi::NSigTpcPiFromLambda, hf_cand_xic_to_xi_pi_pi::NSigTpcPrFromLambda, + hf_cand_xic_to_xi_pi_pi::NSigTofPiFromXicPlus0, hf_cand_xic_to_xi_pi_pi::NSigTofPiFromXicPlus1, hf_cand_xic_to_xi_pi_pi::NSigTofBachelorPi, hf_cand_xic_to_xi_pi_pi::NSigTofPiFromLambda, hf_cand_xic_to_xi_pi_pi::NSigTofPrFromLambda, + /* dynamic columns */ + hf_cand::DecayLength, + hf_cand::DecayLengthXY, + hf_cand::DecayLengthNormalised, + hf_cand::DecayLengthXYNormalised, + hf_cand::ImpactParameterNormalised0, + hf_cand::ImpactParameterNormalised1, + hf_cand::ImpactParameterNormalised2, + /* dynamic columns that use daughter momentum components */ + hf_cand_xic_to_xi_pi_pi::PProng0, + hf_cand::PtProng0, + hf_cand_xic_to_xi_pi_pi::PProng1, + hf_cand::PtProng1, + hf_cand_xic_to_xi_pi_pi::PProng2, + hf_cand::PtProng2, + /* dynamic columns that use candidate momentum components */ + hf_cand::Pt, + hf_cand::P, + hf_cand::PVector, + hf_cand::Cpa, + hf_cand::CpaXY, + hf_cand::Ct, + hf_cand::ImpactParameterXY, + hf_cand_3prong::MaxNormalisedDeltaIP, + hf_cand::Eta, + hf_cand::Phi, + hf_cand::Y); + +// extended table with expression columns that can be used as arguments of dynamic columns +DECLARE_SOA_EXTENDED_TABLE_USER(HfCandXicExt, HfCandXicBase, "HFCANDXICEXT", + hf_cand_3prong::Px, hf_cand_3prong::Py, hf_cand_3prong::Pz); + +using HfCandXic = HfCandXicExt; + +DECLARE_SOA_TABLE(HfCandXicKF, "AOD", "HFCANDXICKF", + cascdata::KFCascadeChi2, cascdata::KFV0Chi2, + hf_cand_xic_to_xi_pi_pi::KfDecayLength, hf_cand_xic_to_xi_pi_pi::KfDecayLengthNormalised, hf_cand_xic_to_xi_pi_pi::KfDecayLengthXY, hf_cand_xic_to_xi_pi_pi::KfDecayLengthXYNormalised, + hf_cand_xic_to_xi_pi_pi::Chi2TopoXicPlusToPVBeforeConstraint, hf_cand_xic_to_xi_pi_pi::Chi2TopoXicPlusToPV, hf_cand_xic_to_xi_pi_pi::Chi2TopoXiToXicPlusBeforeConstraint, hf_cand_xic_to_xi_pi_pi::Chi2TopoXiToXicPlus, + hf_cand_xic_to_xi_pi_pi::DcaXYPi0Pi1, hf_cand_xic_to_xi_pi_pi::DcaXYPi0Xi, hf_cand_xic_to_xi_pi_pi::DcaXYPi1Xi, + hf_cand_xic_to_xi_pi_pi::DcaPi0Pi1, hf_cand_xic_to_xi_pi_pi::DcaPi0Xi, hf_cand_xic_to_xi_pi_pi::DcaPi1Xi); + +// table with results of reconstruction level MC matching +DECLARE_SOA_TABLE(HfCandXicMcRec, "AOD", "HFCANDXICMCREC", //! + hf_cand_xic_to_xi_pi_pi::FlagMcMatchRec, + hf_cand_xic_to_xi_pi_pi::DebugMcRec, + hf_cand_xic_to_xi_pi_pi::OriginRec); + +// table with results of generator level MC matching +DECLARE_SOA_TABLE(HfCandXicMcGen, "AOD", "HFCANDXICMCGEN", //! + hf_cand_xic_to_xi_pi_pi::FlagMcMatchGen, + hf_cand_xic_to_xi_pi_pi::DebugMcGen, + hf_cand_xic_to_xi_pi_pi::OriginGen); // specific chic candidate properties namespace hf_cand_chic @@ -1263,8 +1806,8 @@ DECLARE_SOA_TABLE(HfCandChicBase, "AOD", "HFCANDCHICBASE", hf_cand::P, hf_cand::P2, hf_cand::PVector, - hf_cand::CPA, - hf_cand::CPAXY, + hf_cand::Cpa, + hf_cand::CpaXY, hf_cand::Ct, hf_cand::ImpactParameterXY, hf_cand_2prong::MaxNormalisedDeltaIP, @@ -1327,8 +1870,8 @@ DECLARE_SOA_TABLE(HfCandLbBase, "AOD", "HFCANDLBBASE", hf_cand::P, hf_cand::P2, hf_cand::PVector, - hf_cand::CPA, - hf_cand::CPAXY, + hf_cand::Cpa, + hf_cand::CpaXY, hf_cand::Ct, hf_cand::ImpactParameterXY, hf_cand_2prong::MaxNormalisedDeltaIP, @@ -1360,17 +1903,19 @@ namespace hf_cand_b0 { DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfCand3Prong, "_0"); // D index // MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // generator level -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); // particle origin, reconstruction level -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); // particle origin, generator level -DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level +DECLARE_SOA_COLUMN(FlagWrongCollision, flagWrongCollision, int8_t); // reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // generator level +DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); // particle origin, reconstruction level +DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); // particle origin, generator level +DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level // mapping of decay types enum DecayType { B0ToDPi }; enum DecayTypeMc : uint8_t { B0ToDplusPiToPiKPiPi = 0, B0ToDsPiToKKPiPi, + BsToDsPiToKKPiPi, PartlyRecoDecay, OtherDecay, NDecayTypeMc }; @@ -1385,7 +1930,6 @@ DECLARE_SOA_TABLE(HfCandB0Base, "AOD", "HFCANDB0BASE", hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, hf_cand::ImpactParameter0, hf_cand::ImpactParameter1, hf_cand::ErrorImpactParameter0, hf_cand::ErrorImpactParameter1, - hf_track_index::HFflag, /* dynamic columns */ hf_cand_2prong::M, hf_cand_2prong::M2, @@ -1398,8 +1942,8 @@ DECLARE_SOA_TABLE(HfCandB0Base, "AOD", "HFCANDB0BASE", hf_cand::P, hf_cand::P2, hf_cand::PVector, - hf_cand::CPA, - hf_cand::CPAXY, + hf_cand::Cpa, + hf_cand::CpaXY, hf_cand::Ct, hf_cand::ImpactParameterXY, hf_cand_2prong::MaxNormalisedDeltaIP, @@ -1434,16 +1978,23 @@ namespace hf_cand_bs { DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfCand3Prong, "_0"); // Ds index // MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // generator level +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level +DECLARE_SOA_COLUMN(FlagWrongCollision, flagWrongCollision, int8_t); // reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // generator level +DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); // particle origin, reconstruction level +DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); // particle origin, generator level +DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level // mapping of decay types enum DecayType { BsToDsPi }; -enum DecayTypeMc : uint8_t { BsToDsPiToKKPiPi = 0, // Bs(bar) → Ds∓ π± → (Phi π∓) π± → (K- K+ π∓) π± - B0ToDsPiToKKPiPi, // B0(bar) → Ds± π∓ → (Phi π±) π∓ → (K- K+ π±) π∓ - PartlyRecoDecay, // 4 final state particles have another common b-hadron ancestor - NDecayTypeMc }; // counter of differentiated MC decay types +enum DecayTypeMc : uint8_t { BsToDsPiToPhiPiPiToKKPiPi = 0, // Bs(bar) → Ds∓ π± → (Phi π∓) π± → (K- K+ π∓) π± + BsToDsPiToK0starKPiToKKPiPi, // Bs(bar) → Ds∓ π± → (K0* K∓) π± → (K- K+ π∓) π± + B0ToDsPiToPhiPiPiToKKPiPi, // B0(bar) → Ds± π∓ → (Phi π±) π∓ → (K- K+ π±) π∓ + B0ToDsPiToK0starKPiToKKPiPi, // B0(bar) → Ds± π∓ → (K0* K±) π∓ → (K- K+ π±) π∓ + PartlyRecoDecay, // 4 final state particles have another common b-hadron ancestor + OtherDecay, + NDecayTypeMc }; // counter of differentiated MC decay types } // namespace hf_cand_bs @@ -1456,8 +2007,6 @@ DECLARE_SOA_TABLE(HfCandBsBase, "AOD", "HFCANDBSBASE", hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, hf_cand::ImpactParameter0, hf_cand::ImpactParameter1, hf_cand::ErrorImpactParameter0, hf_cand::ErrorImpactParameter1, - hf_cand_bs::Prong0Id, hf_track_index::Prong1Id, - hf_track_index::HFflag, /* dynamic columns */ hf_cand_2prong::M, hf_cand_2prong::M2, @@ -1470,8 +2019,8 @@ DECLARE_SOA_TABLE(HfCandBsBase, "AOD", "HFCANDBSBASE", hf_cand::P, hf_cand::P2, hf_cand::PVector, - hf_cand::CPA, - hf_cand::CPAXY, + hf_cand::Cpa, + hf_cand::CpaXY, hf_cand::Ct, hf_cand::ImpactParameterXY, hf_cand_2prong::MaxNormalisedDeltaIP, @@ -1479,13 +2028,17 @@ DECLARE_SOA_TABLE(HfCandBsBase, "AOD", "HFCANDBSBASE", hf_cand::Phi, hf_cand::Y, hf_cand::E, - hf_cand::E2); + hf_cand::E2, + o2::soa::Marker<1>); // extended table with expression columns that can be used as arguments of dynamic columns DECLARE_SOA_EXTENDED_TABLE_USER(HfCandBsExt, HfCandBsBase, "HFCANDBSEXT", hf_cand_2prong::Px, hf_cand_2prong::Py, hf_cand_2prong::Pz); -using HfCandBs = HfCandBsExt; +DECLARE_SOA_TABLE(HfCandBsProngs, "AOD", "HFCANDBSPRONGS", + hf_cand_bs::Prong0Id, hf_track_index::Prong1Id); + +using HfCandBs = soa::Join; // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCandBsMcRec, "AOD", "HFCANDBSMCREC", @@ -1511,7 +2064,17 @@ DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! particle origin, // mapping of decay types enum DecayType { Sc0ToPKPiPi = 0, - ScplusplusToPKPiPi }; + ScplusplusToPKPiPi, + ScStar0ToPKPiPi, + ScStarPlusPlusToPKPiPi }; +enum Species : int { Sc2455 = 0, + Sc2520, + NSpecies }; +enum Decays : int { PKPi = 0, + PiKP, + NDecays }; +constexpr int ChargeNull = 0; +constexpr int ChargePlusPlus = 2; } // namespace hf_cand_sigmac // declare dedicated Σc0,++ decay candidate table @@ -1564,12 +2127,76 @@ using HfCandSc = HfCandScExt; // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCandScMcRec, "AOD", "HFCANDSCMCREC", //! hf_cand_sigmac::FlagMcMatchRec, - hf_cand_sigmac::OriginMcRec); + hf_cand_sigmac::OriginMcRec, + hf_cand::PtBhadMotherPart, + hf_cand::PdgBhadMotherPart); // table with results of generation level MC matching DECLARE_SOA_TABLE(HfCandScMcGen, "AOD", "HFCANDSCMCGEN", //! hf_cand_sigmac::FlagMcMatchGen, - hf_cand_sigmac::OriginMcGen); + hf_cand_sigmac::OriginMcGen, + hf_cand::IdxBhadMotherPart); + +// specific Σc0,++ candidate properties in cascade channel +namespace hf_cand_sigmac_to_cascade +{ +DECLARE_SOA_INDEX_COLUMN_FULL(ProngLc, prongLc, int, HfCandCascade, ""); //! Index to a Lc prong +DECLARE_SOA_COLUMN(Charge, charge, int8_t); //! // Σc charge(either 0 or ++) +DECLARE_SOA_COLUMN(ChargeLc, chargeLc, int8_t); //! // Λc charge(+) +DECLARE_SOA_COLUMN(ChargeSoftPi, chargeSoftPi, int8_t); //! // pion charge(either - or +) +DECLARE_SOA_COLUMN(StatusSpreadLcMinvKs0PFromPDG, statusSpreadLcMinvKs0PFromPDG, int); //! // Λc Minv spread from PDG Λc mass +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfCandCascade, "_0"); //! Λc index +// MC matching result: +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); //! reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); //! generator level +DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); //! particle origin, reconstruction level +DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! particle origin, generator level +} // namespace hf_cand_sigmac_to_cascade + +// declare dedicated Σc0,++ decay candidate table +// NB: no topology for Σc0,++ (strong decay) +DECLARE_SOA_TABLE(HfCandScCasBase, "AOD", "HFCANDSCCASBASE", + o2::soa::Index<>, + // general columns + hf_cand::CollisionId, + // 2-prong specific columns + hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, + hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, + hf_cand_sigmac_to_cascade::ProngLcId, hf_track_index::Prong1Id, + hf_cand_sigmac_to_cascade::ChargeLc, + hf_cand_sigmac_to_cascade::ChargeSoftPi, + // hf_track_index::HFflag, + /* Σc0,++ specific columns */ + hf_cand_sigmac_to_cascade::Charge, + // hf_cand_sigmac_to_cascade::StatusSpreadLcMinvKs0PFromPDG, + /* prong 0 */ + hf_cand::PtProng0, + hf_cand::Pt2Prong0, + hf_cand::PVectorProng0, + /* prong 1 */ + hf_cand::PtProng1, + hf_cand::Pt2Prong1, + hf_cand::PVectorProng1, + /* dynamic columns */ + hf_cand_2prong::M, + hf_cand_2prong::M2, + /* dynamic columns that use candidate momentum components */ + hf_cand::Pt, + hf_cand::Pt2, + hf_cand::P, + hf_cand::P2, + hf_cand::PVector, + hf_cand::Eta, + hf_cand::Phi, + hf_cand::Y, + hf_cand::E, + hf_cand::E2); + +// extended table with expression columns that can be used as arguments of dynamic columns +DECLARE_SOA_EXTENDED_TABLE_USER(HfCandScCasExt, HfCandScCasBase, "HFCANDSCCASEXT", + hf_cand_2prong::Px, hf_cand_2prong::Py, hf_cand_2prong::Pz); +using HfCandScCascades = HfCandScCasExt; +using HfCandScCascade = HfCandScCascades::iterator; /// D*± → D0(bar) π± namespace hf_cand_dstar @@ -1634,9 +2261,9 @@ DECLARE_SOA_DYNAMIC_COLUMN(DecayLengthXYNormalisedD0, decayLengthXYNormalisedD0, [](float xVtxP, float yVtxP, float xVtxS, float yVtxS, float err) -> float { return RecoDecay::distanceXY(std::array{xVtxP, yVtxP}, std::array{xVtxS, yVtxS}) / err; }); DECLARE_SOA_COLUMN(ErrorDecayLengthD0, errorDecayLengthD0, float); DECLARE_SOA_COLUMN(ErrorDecayLengthXYD0, errorDecayLengthXYD0, float); -DECLARE_SOA_DYNAMIC_COLUMN(CPAD0, cpaD0, +DECLARE_SOA_DYNAMIC_COLUMN(CpaD0, cpaD0, [](float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS, float px, float py, float pz) -> float { return RecoDecay::cpa(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}, std::array{px, py, pz}); }); -DECLARE_SOA_DYNAMIC_COLUMN(CPAXYD0, cpaXYD0, +DECLARE_SOA_DYNAMIC_COLUMN(CpaXYD0, cpaXYD0, [](float xVtxP, float yVtxP, float xVtxS, float yVtxS, float px, float py) -> float { return RecoDecay::cpaXY(std::array{xVtxP, yVtxP}, std::array{xVtxS, yVtxS}, std::array{px, py}); }); DECLARE_SOA_DYNAMIC_COLUMN(CtD0, ctD0, [](float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS, float px, float py, float pz) -> float { return RecoDecay::ct(std::array{px, py, pz}, RecoDecay::distance(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}), constants::physics::MassD0); }); @@ -1648,9 +2275,13 @@ DECLARE_SOA_INDEX_COLUMN_FULL(ProngPi, prongPi, int, Tracks, ""); //! soft-pion // soft pion prong DECLARE_SOA_COLUMN(ImpParamSoftPi, impParamSoftPi, float); +DECLARE_SOA_COLUMN(ImpParamZSoftPi, impParamZSoftPi, float); DECLARE_SOA_COLUMN(ErrorImpParamSoftPi, errorImpParamSoftPi, float); +DECLARE_SOA_COLUMN(ErrorImpParamZSoftPi, errorImpParamZSoftPi, float); DECLARE_SOA_DYNAMIC_COLUMN(NormalisedImpParamSoftPi, normalisedImpParamSoftPi, [](float dca, float err) -> float { return dca / err; }); +DECLARE_SOA_DYNAMIC_COLUMN(NormalisedImpParamZSoftPi, normalisedImpParamZSoftPi, + [](float dca, float err) -> float { return dca / err; }); DECLARE_SOA_COLUMN(PxSoftPi, pxSoftPi, float); DECLARE_SOA_COLUMN(PySoftPi, pySoftPi, float); DECLARE_SOA_COLUMN(PzSoftPi, pzSoftPi, float); @@ -1672,14 +2303,19 @@ DECLARE_SOA_DYNAMIC_COLUMN(PtSoftPi, ptSoftPi, [](float pxSoftPi, float pySoftPi DECLARE_SOA_DYNAMIC_COLUMN(PVecSoftPi, pVecSoftPi, [](float px, float py, float pz) -> std::array { return std::array{px, py, pz}; }); // MC matching result: -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); //! reconstruction level -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); //! generator level -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); //! particle origin, reconstruction level -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! particle origin, generator level +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); //! reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); //! generator level +DECLARE_SOA_COLUMN(FlagMcMatchRecD0, flagMcMatchRecD0, int8_t); //! reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchGenD0, flagMcMatchGenD0, int8_t); //! generator level + +DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); //! particle origin, reconstruction level +DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! particle origin, generator level enum DecayType { DstarToD0Pi = 0, D0ToPiK, + DstarToD0PiPi0, + D0ToPiKPi0, NDstarDecayType }; @@ -1701,13 +2337,17 @@ DECLARE_SOA_TABLE(HfD0FromDstarBase, "AOD", "HFD0FRMDSTR", hf_cand_dstar::DecayLengthXYNormalisedD0, /* prong 0 */ hf_cand::ImpactParameterNormalised0, /* prong 1 */ hf_cand::ImpactParameterNormalised1, + /* prong 0 */ hf_cand::ImpactParameterZNormalised0, + /* prong 1 */ hf_cand::ImpactParameterZNormalised1, // HFCAND_COLUMNS, // 2-prong specific columns hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, hf_cand::ImpactParameter0, hf_cand::ImpactParameter1, + hf_cand::ImpactParameterZ0, hf_cand::ImpactParameterZ1, hf_cand::ErrorImpactParameter0, hf_cand::ErrorImpactParameter1, + hf_cand::ErrorImpactParameterZ0, hf_cand::ErrorImpactParameterZ1, hf_track_index::Prong0Id, hf_track_index::Prong1Id, hf_track_index::HFflag, /* dynamic columns */ @@ -1719,8 +2359,8 @@ DECLARE_SOA_TABLE(HfD0FromDstarBase, "AOD", "HFD0FRMDSTR", hf_cand_dstar::PD0, hf_cand_dstar::P2D0, hf_cand_dstar::PVectorD0, - hf_cand_dstar::CPAD0, - hf_cand_dstar::CPAXYD0, + hf_cand_dstar::CpaD0, + hf_cand_dstar::CpaXYD0, hf_cand_dstar::CtD0, hf_cand_dstar::ImpactParameterXYD0, hf_cand_dstar::DeltaIPNormalisedMaxD0, @@ -1746,7 +2386,8 @@ DECLARE_SOA_TABLE(HfCandDstarBase, "AOD", "HFCANDDSTRBASE", // Softpi hf_cand_dstar::PxSoftPi, hf_cand_dstar::PySoftPi, hf_cand_dstar::PzSoftPi, hf_cand_dstar::SignSoftPi, - hf_cand_dstar::ImpParamSoftPi, hf_cand_dstar::ErrorImpParamSoftPi, + hf_cand_dstar::ImpParamSoftPi, hf_cand_dstar::ImpParamZSoftPi, + hf_cand_dstar::ErrorImpParamSoftPi, hf_cand_dstar::ErrorImpParamZSoftPi, // Two pronges of D0 hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, @@ -1755,6 +2396,7 @@ DECLARE_SOA_TABLE(HfCandDstarBase, "AOD", "HFCANDDSTRBASE", hf_cand_dstar::PtSoftPi, hf_cand_dstar::PVecSoftPi, hf_cand_dstar::NormalisedImpParamSoftPi, + hf_cand_dstar::NormalisedImpParamZSoftPi, hf_cand::Pt, hf_cand::P, hf_cand::PVector, @@ -1787,12 +2429,19 @@ using HfCandDstar = HfCandDstars::iterator; // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCandDstarMcRec, "AOD", "HFCANDDSTRMCREC", hf_cand_dstar::FlagMcMatchRec, - hf_cand_dstar::OriginMcRec); + hf_cand_dstar::FlagMcMatchRecD0, + hf_cand_dstar::OriginMcRec, + hf_cand::PtBhadMotherPart, + hf_cand::PdgBhadMotherPart, + hf_cand::NTracksDecayed, + hf_cand::NInteractionsWithMaterial); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCandDstarMcGen, "AOD", "HFCANDDSTRMCGEN", hf_cand_dstar::FlagMcMatchGen, - hf_cand_dstar::OriginMcGen); + hf_cand_dstar::FlagMcMatchGenD0, + hf_cand_dstar::OriginMcGen, + hf_cand::IdxBhadMotherPart); #undef HFCAND_COLUMNS diff --git a/PWGHF/DataModel/CandidateSelectionTables.h b/PWGHF/DataModel/CandidateSelectionTables.h index 4776c1067d5..06dd445f98e 100644 --- a/PWGHF/DataModel/CandidateSelectionTables.h +++ b/PWGHF/DataModel/CandidateSelectionTables.h @@ -11,6 +11,8 @@ /// \file CandidateSelectionTables.h /// \brief Definitions of tables produced by candidate selectors +/// +/// \author Nima Zardoshti , CERN #ifndef PWGHF_DATAMODEL_CANDIDATESELECTIONTABLES_H_ #define PWGHF_DATAMODEL_CANDIDATESELECTIONTABLES_H_ @@ -136,11 +138,11 @@ DECLARE_SOA_TABLE(HfMlDsToKKPi, "AOD", "HFMLDS", //! namespace hf_sel_candidate_dstar { -DECLARE_SOA_COLUMN(IsSelDstarToD0Pi, isSelDstarToD0Pi, bool); //! checking if all four of following check pass -DECLARE_SOA_COLUMN(IsRecoD0Flag, isRecoD0Flag, bool); //! checking DecayType::D0ToPiK of D0prong -DECLARE_SOA_COLUMN(IsRecoTopol, isRecoTopol, bool); //! checking conjugate independent Topological selection on Dstar -DECLARE_SOA_COLUMN(IsRecoCand, isRecoCand, bool); //! checking conjugate dependent Topological selecton on Dstar -DECLARE_SOA_COLUMN(IsRecoPid, isRecoPid, bool); //! checking PID selection on daughters of D0Prong +DECLARE_SOA_COLUMN(IsSelDstarToD0Pi, isSelDstarToD0Pi, bool); //! checking if all four of following check pass +DECLARE_SOA_COLUMN(IsRecoD0Flag, isRecoD0Flag, bool); //! checking DecayType::D0ToPiK of D0prong +DECLARE_SOA_COLUMN(IsRecoTopol, isRecoTopol, bool); //! checking conjugate independent Topological selection on Dstar +DECLARE_SOA_COLUMN(IsRecoCand, isRecoCand, bool); //! checking conjugate dependent Topological selecton on Dstar +DECLARE_SOA_COLUMN(IsRecoPid, isRecoPid, bool); //! checking PID selection on daughters of D0Prong DECLARE_SOA_COLUMN(MlProbDstarToD0Pi, mlProbDstarToD0Pi, std::vector); //! ML probability for Dstar to D0Pi } // namespace hf_sel_candidate_dstar @@ -263,12 +265,16 @@ DECLARE_SOA_TABLE(HfMlBsToDsPi, "AOD", "HFMLBS", //! namespace hf_sel_candidate_bplus { -DECLARE_SOA_COLUMN(IsSelBplusToD0Pi, isSelBplusToD0Pi, int); //! +DECLARE_SOA_COLUMN(IsSelBplusToD0Pi, isSelBplusToD0Pi, int); //! selection flag on B+ candidate +DECLARE_SOA_COLUMN(MlProbBplusToD0Pi, mlProbBplusToD0Pi, float); //! ML score of B+ candidate for signal class } // namespace hf_sel_candidate_bplus DECLARE_SOA_TABLE(HfSelBplusToD0Pi, "AOD", "HFSELBPLUS", //! hf_sel_candidate_bplus::IsSelBplusToD0Pi); +DECLARE_SOA_TABLE(HfMlBplusToD0Pi, "AOD", "HFMLBPLUS", //! + hf_sel_candidate_bplus::MlProbBplusToD0Pi); + namespace hf_sel_candidate_lb { DECLARE_SOA_COLUMN(IsSelLbToLcPi, isSelLbToLcPi, int); //! @@ -297,16 +303,25 @@ DECLARE_SOA_TABLE(HfSelChicToJpsiGamma, "AOD", "HFSELCHIC", //! namespace hf_sel_candidate_xic { +// XicPlus to P K Pi DECLARE_SOA_COLUMN(IsSelXicToPKPi, isSelXicToPKPi, int); //! DECLARE_SOA_COLUMN(IsSelXicToPiKP, isSelXicToPiKP, int); //! DECLARE_SOA_COLUMN(MlProbXicToPKPi, mlProbXicToPKPi, std::vector); //! DECLARE_SOA_COLUMN(MlProbXicToPiKP, mlProbXicToPiKP, std::vector); //! +// XicPlus to Xi Pi Pi +DECLARE_SOA_COLUMN(IsSelXicToXiPiPi, isSelXicToXiPiPi, int); //! +DECLARE_SOA_COLUMN(MlProbXicToXiPiPi, mlProbXicToXiPiPi, std::vector); //! } // namespace hf_sel_candidate_xic DECLARE_SOA_TABLE(HfSelXicToPKPi, "AOD", "HFSELXIC", //! hf_sel_candidate_xic::IsSelXicToPKPi, hf_sel_candidate_xic::IsSelXicToPiKP); DECLARE_SOA_TABLE(HfMlXicToPKPi, "AOD", "HFMLXIC", //! hf_sel_candidate_xic::MlProbXicToPKPi, hf_sel_candidate_xic::MlProbXicToPiKP); +// XicPlus to Xi Pi Pi +DECLARE_SOA_TABLE(HfSelXicToXiPiPi, "AOD", "HFSELXICTOXI2PI", //! + hf_sel_candidate_xic::IsSelXicToXiPiPi); +DECLARE_SOA_TABLE(HfMlXicToXiPiPi, "AOD", "HFMLXICTOXI2PI", //! + hf_sel_candidate_xic::MlProbXicToXiPiPi); namespace hf_sel_candidate_xicc { @@ -344,6 +359,76 @@ DECLARE_SOA_TABLE(HfSelToXiPi, "AOD", "HFSELTOXIPI", hf_sel_toxipi::TpcNSigmaPiFromCharmBaryon, hf_sel_toxipi::TpcNSigmaPiFromCasc, hf_sel_toxipi::TpcNSigmaPiFromLambda, hf_sel_toxipi::TpcNSigmaPrFromLambda, hf_sel_toxipi::TofNSigmaPiFromCharmBaryon, hf_sel_toxipi::TofNSigmaPiFromCasc, hf_sel_toxipi::TofNSigmaPiFromLambda, hf_sel_toxipi::TofNSigmaPrFromLambda); +DECLARE_SOA_TABLE(HfSelToXiPiKf, "AOD", "HFSELTOXIPIKF", + hf_sel_toxipi::StatusPidCharmBaryon, hf_sel_toxipi::StatusPidCascade, hf_sel_toxipi::StatusPidLambda, + hf_sel_toxipi::StatusInvMassCharmBaryon, hf_sel_toxipi::StatusInvMassCascade, hf_sel_toxipi::StatusInvMassLambda, + hf_sel_toxipi::ResultSelections, hf_sel_toxipi::PidTpcInfoStored, hf_sel_toxipi::PidTofInfoStored, + hf_sel_toxipi::TpcNSigmaPiFromCharmBaryon, hf_sel_toxipi::TpcNSigmaPiFromCasc, hf_sel_toxipi::TpcNSigmaPiFromLambda, hf_sel_toxipi::TpcNSigmaPrFromLambda, + hf_sel_toxipi::TofNSigmaPiFromCharmBaryon, hf_sel_toxipi::TofNSigmaPiFromCasc, hf_sel_toxipi::TofNSigmaPiFromLambda, hf_sel_toxipi::TofNSigmaPrFromLambda); + +namespace hf_sel_toomegapi +{ +DECLARE_SOA_COLUMN(StatusPidLambda, statusPidLambda, bool); +DECLARE_SOA_COLUMN(StatusPidCascade, statusPidCascade, bool); +DECLARE_SOA_COLUMN(StatusPidCharmBaryon, statusPidCharmBaryon, bool); +DECLARE_SOA_COLUMN(StatusInvMassLambda, statusInvMassLambda, bool); +DECLARE_SOA_COLUMN(StatusInvMassCascade, statusInvMassCascade, bool); +DECLARE_SOA_COLUMN(StatusInvMassCharmBaryon, statusInvMassCharmBaryon, bool); +DECLARE_SOA_COLUMN(ResultSelections, resultSelections, bool); +DECLARE_SOA_COLUMN(TpcNSigmaPiFromCharmBaryon, tpcNSigmaPiFromCharmBaryon, float); +// DECLARE_SOA_COLUMN(TpcNSigmaKaFromCharmBaryon, tpcNSigmaKaFromCharmBaryon, float); +DECLARE_SOA_COLUMN(TpcNSigmaKaFromCasc, tpcNSigmaKaFromCasc, float); +DECLARE_SOA_COLUMN(TpcNSigmaPiFromLambda, tpcNSigmaPiFromLambda, float); +DECLARE_SOA_COLUMN(TpcNSigmaPrFromLambda, tpcNSigmaPrFromLambda, float); +DECLARE_SOA_COLUMN(TofNSigmaPiFromCharmBaryon, tofNSigmaPiFromCharmBaryon, float); +// DECLARE_SOA_COLUMN(TofNSigmaKaFromCharmBaryon, tofNSigmaKaFromCharmBaryon, float); +DECLARE_SOA_COLUMN(TofNSigmaKaFromCasc, tofNSigmaKaFromCasc, float); +DECLARE_SOA_COLUMN(TofNSigmaPiFromLambda, tofNSigmaPiFromLambda, float); +DECLARE_SOA_COLUMN(TofNSigmaPrFromLambda, tofNSigmaPrFromLambda, float); +DECLARE_SOA_COLUMN(PidTpcInfoStored, pidTpcInfoStored, int); +DECLARE_SOA_COLUMN(PidTofInfoStored, pidTofInfoStored, int); +// Machine learning column for omegac0 to omega pi +DECLARE_SOA_COLUMN(MlProbOmegac, mlProbOmegac, std::vector); +DECLARE_SOA_COLUMN(MlProbOmegacBar, mlProbOmegacBar, std::vector); +} // namespace hf_sel_toomegapi + +DECLARE_SOA_TABLE(HfSelToOmegaPi, "AOD", "HFSELTOOMEPI", + hf_sel_toomegapi::StatusPidLambda, hf_sel_toomegapi::StatusPidCascade, hf_sel_toomegapi::StatusPidCharmBaryon, + hf_sel_toomegapi::StatusInvMassLambda, hf_sel_toomegapi::StatusInvMassCascade, hf_sel_toomegapi::StatusInvMassCharmBaryon, + hf_sel_toomegapi::ResultSelections, hf_sel_toomegapi::PidTpcInfoStored, hf_sel_toomegapi::PidTofInfoStored, + hf_sel_toomegapi::TpcNSigmaPiFromCharmBaryon, hf_sel_toomegapi::TpcNSigmaKaFromCasc, hf_sel_toomegapi::TpcNSigmaPiFromLambda, hf_sel_toomegapi::TpcNSigmaPrFromLambda, + hf_sel_toomegapi::TofNSigmaPiFromCharmBaryon, hf_sel_toomegapi::TofNSigmaKaFromCasc, hf_sel_toomegapi::TofNSigmaPiFromLambda, hf_sel_toomegapi::TofNSigmaPrFromLambda); + +DECLARE_SOA_TABLE(HfMlSelOmegacToOmegaPi, "AOD", "HFMLOMEGAC", //! + hf_sel_toomegapi::MlProbOmegac); +namespace hf_sel_toomegaka +{ +DECLARE_SOA_COLUMN(StatusPidLambda, statusPidLambda, bool); +DECLARE_SOA_COLUMN(StatusPidCascade, statusPidCascade, bool); +DECLARE_SOA_COLUMN(StatusPidCharmBaryon, statusPidCharmBaryon, bool); +DECLARE_SOA_COLUMN(StatusInvMassLambda, statusInvMassLambda, bool); +DECLARE_SOA_COLUMN(StatusInvMassCascade, statusInvMassCascade, bool); +DECLARE_SOA_COLUMN(StatusInvMassCharmBaryon, statusInvMassCharmBaryon, bool); +DECLARE_SOA_COLUMN(ResultSelections, resultSelections, bool); +DECLARE_SOA_COLUMN(TpcNSigmaKaFromCharmBaryon, tpcNSigmaKaFromCharmBaryon, float); +DECLARE_SOA_COLUMN(TpcNSigmaKaFromCasc, tpcNSigmaKaFromCasc, float); +DECLARE_SOA_COLUMN(TpcNSigmaPiFromLambda, tpcNSigmaPiFromLambda, float); +DECLARE_SOA_COLUMN(TpcNSigmaPrFromLambda, tpcNSigmaPrFromLambda, float); +DECLARE_SOA_COLUMN(TofNSigmaKaFromCharmBaryon, tofNSigmaKaFromCharmBaryon, float); +DECLARE_SOA_COLUMN(TofNSigmaKaFromCasc, tofNSigmaKaFromCasc, float); +DECLARE_SOA_COLUMN(TofNSigmaPiFromLambda, tofNSigmaPiFromLambda, float); +DECLARE_SOA_COLUMN(TofNSigmaPrFromLambda, tofNSigmaPrFromLambda, float); +DECLARE_SOA_COLUMN(PidTpcInfoStored, pidTpcInfoStored, int); +DECLARE_SOA_COLUMN(PidTofInfoStored, pidTofInfoStored, int); +} // namespace hf_sel_toomegaka + +DECLARE_SOA_TABLE(HfSelToOmegaKa, "AOD", "HFSELTOOMEKA", + hf_sel_toomegaka::StatusPidLambda, hf_sel_toomegaka::StatusPidCascade, hf_sel_toomegaka::StatusPidCharmBaryon, + hf_sel_toomegaka::StatusInvMassLambda, hf_sel_toomegaka::StatusInvMassCascade, hf_sel_toomegaka::StatusInvMassCharmBaryon, + hf_sel_toomegaka::ResultSelections, hf_sel_toomegaka::PidTpcInfoStored, hf_sel_toomegaka::PidTofInfoStored, + hf_sel_toomegaka::TpcNSigmaKaFromCharmBaryon, hf_sel_toomegaka::TpcNSigmaKaFromCasc, hf_sel_toomegaka::TpcNSigmaPiFromLambda, hf_sel_toomegaka::TpcNSigmaPrFromLambda, + hf_sel_toomegaka::TofNSigmaKaFromCharmBaryon, hf_sel_toomegaka::TofNSigmaKaFromCasc, hf_sel_toomegaka::TofNSigmaPiFromLambda, hf_sel_toomegaka::TofNSigmaPrFromLambda) + } // namespace o2::aod #endif // PWGHF_DATAMODEL_CANDIDATESELECTIONTABLES_H_ diff --git a/PWGHF/DataModel/DerivedTables.h b/PWGHF/DataModel/DerivedTables.h index ebb8866030f..6900ef25039 100644 --- a/PWGHF/DataModel/DerivedTables.h +++ b/PWGHF/DataModel/DerivedTables.h @@ -9,208 +9,275 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file DerivedTables.h.h +/// \file DerivedTables.h /// \brief Definitions of derived tables produced by derived-data creators +/// \author Vít Kučera , Inha University #ifndef PWGHF_DATAMODEL_DERIVEDTABLES_H_ #define PWGHF_DATAMODEL_DERIVEDTABLES_H_ #include -#include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ASoA.h" #include "Common/Core/RecoDecay.h" +#include "PWGLF/DataModel/mcCentrality.h" + #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" namespace o2::aod { +// basic species: +// D0 → K− π+ +// Λc → p K− π+ +// D+ → K− π+ π+ +// Ds+ → K− K+ π+ (todo) + +// composite species +// B0 → D− π+ (todo) +// B+ → D0 π+ +// D*+ → D0 π+ (todo) + +// ================ +// Collision tables +// ================ + // Basic collision properties namespace hf_coll_base { -DECLARE_SOA_COLUMN(IsEventReject, isEventReject, int8_t); //! collision rejection flag -DECLARE_SOA_COLUMN(MultFT0M, multFT0M, float); //! FT0M multiplicity -DECLARE_SOA_COLUMN(CentFT0A, centFT0A, float); //! FT0A centrality percentile -DECLARE_SOA_COLUMN(CentFT0C, centFT0C, float); //! FT0C centrality percentile -DECLARE_SOA_COLUMN(CentFT0M, centFT0M, float); //! FT0M centrality percentile -DECLARE_SOA_COLUMN(CentFV0A, centFV0A, float); //! FT0A centrality percentile -DECLARE_SOA_COLUMN(CentFDDM, centFDDM, float); //! FDDM centrality percentile +DECLARE_SOA_COLUMN(IsEventReject, isEventReject, int8_t); //! collision rejection flag +DECLARE_SOA_COLUMN(MultFT0M, multFT0M, float); //! FT0M multiplicity +DECLARE_SOA_COLUMN(CentFT0A, centFT0A, float); //! FT0A centrality percentile +DECLARE_SOA_COLUMN(CentFT0C, centFT0C, float); //! FT0C centrality percentile +DECLARE_SOA_COLUMN(CentFT0M, centFT0M, float); //! FT0M centrality percentile +DECLARE_SOA_COLUMN(CentFV0A, centFV0A, float); //! FV0A centrality percentile +DECLARE_SOA_COLUMN(CentFDDM, centFDDM, float); //! FDDM centrality percentile DECLARE_SOA_COLUMN(MultZeqNTracksPV, multZeqNTracksPV, float); //! z-equalised barrel multiplicity } // namespace hf_coll_base -// D0 - -DECLARE_SOA_TABLE(HfD0CollBases, "AOD", "HFD0COLLBASE", //! Table with basic collision info - o2::soa::Index<>, - collision::PosX, - collision::PosY, - collision::PosZ, - collision::NumContrib, - hf_coll_base::CentFT0A, - hf_coll_base::CentFT0C, - hf_coll_base::CentFT0M, - hf_coll_base::CentFV0A, - hf_coll_base::MultZeqNTracksPV); -// hf_coll_base::IsEventReject, -// bc::RunNumber, - -using HfD0CollBase = HfD0CollBases::iterator; - -DECLARE_SOA_TABLE(StoredHfD0CollBases, "AOD1", "HFD0COLLBASE", //! Table with basic collision info (stored version) - o2::soa::Index<>, - collision::PosX, - collision::PosY, - collision::PosZ, - collision::NumContrib, - hf_coll_base::CentFT0A, - hf_coll_base::CentFT0C, - hf_coll_base::CentFT0M, - hf_coll_base::CentFV0A, - hf_coll_base::MultZeqNTracksPV, - // hf_coll_base::IsEventReject, - // bc::RunNumber, - soa::Marker<1>); - -using StoredHfD0CollBase = StoredHfD0CollBases::iterator; - -DECLARE_SOA_TABLE(HfD0CollIds, "AOD", "HFD0COLLID", //! Table with global indices for collisions - hf_cand::CollisionId); - -DECLARE_SOA_TABLE(StoredHfD0CollIds, "AOD1", "HFD0COLLID", //! Table with global indices for collisions (stored version) - hf_cand::CollisionId, - soa::Marker<1>); - -// 3-prong decays - -DECLARE_SOA_TABLE(Hf3PCollBases, "AOD", "HF3PCOLLBASE", //! Table with basic collision info - o2::soa::Index<>, - collision::PosX, - collision::PosY, - collision::PosZ, - collision::NumContrib, - hf_coll_base::CentFT0A, - hf_coll_base::CentFT0C, - hf_coll_base::CentFT0M, - hf_coll_base::CentFV0A, - hf_coll_base::MultZeqNTracksPV, - // hf_coll_base::IsEventReject, - // bc::RunNumber, - soa::Marker<2>); - -using Hf3PCollBase = Hf3PCollBases::iterator; - -DECLARE_SOA_TABLE(StoredHf3PCollBases, "AOD1", "HF3PCOLLBASE", //! Table with basic collision info (stored version) - o2::soa::Index<>, - collision::PosX, - collision::PosY, - collision::PosZ, - collision::NumContrib, - hf_coll_base::CentFT0A, - hf_coll_base::CentFT0C, - hf_coll_base::CentFT0M, - hf_coll_base::CentFV0A, - hf_coll_base::MultZeqNTracksPV, - // hf_coll_base::IsEventReject, - // bc::RunNumber, - soa::Marker<3>); - -using StoredHf3PCollBase = StoredHf3PCollBases::iterator; - -DECLARE_SOA_TABLE(Hf3PCollIds, "AOD", "HF3PCOLLID", //! Table with global indices for collisions - hf_cand::CollisionId, - soa::Marker<2>); - -DECLARE_SOA_TABLE(StoredHf3PCollIds, "AOD1", "HF3PCOLLID", //! Table with global indices for collisions (stored version) - hf_cand::CollisionId, - soa::Marker<3>); - -// Basic candidate properties -namespace hf_cand_base -{ -DECLARE_SOA_INDEX_COLUMN(HfD0CollBase, hfD0CollBase); //! collision index pointing to the derived collision table for D0 candidates -DECLARE_SOA_INDEX_COLUMN(StoredHfD0CollBase, storedHfD0CollBase); //! collision index pointing to the derived collision table for D0 candidates -DECLARE_SOA_INDEX_COLUMN(Hf3PCollBase, hf3PCollBase); //! collision index pointing to the derived collision table for 3-prong candidates -DECLARE_SOA_INDEX_COLUMN(StoredHf3PCollBase, storedHf3PCollBase); //! collision index pointing to the derived collision table for 3-prong candidates -DECLARE_SOA_INDEX_COLUMN(McCollision, mcCollision); //! MC collision of this particle -DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! MC particle -DECLARE_SOA_COLUMN(Eta, eta, float); //! pseudorapidity -DECLARE_SOA_COLUMN(M, m, float); //! invariant mass -DECLARE_SOA_COLUMN(Phi, phi, float); //! azimuth -DECLARE_SOA_COLUMN(Pt, pt, float); //! transverse momentum - -namespace functions_pt_eta_phi -{ -/// px as a function of pT, phi -/// \todo Move to RecoDecay -template -auto px(TPt pt, TPhi phi) -{ - return pt * std::cos(phi); -} - -/// py as a function of pT, phi -/// \todo Move to RecoDecay -template -auto py(TPt pt, TPhi phi) -{ - return pt * std::sin(phi); -} - -/// pz as a function of pT, eta -/// \todo Move to RecoDecay -template -auto pz(TPt pt, TEta eta) +namespace hf_mc_coll { - return pt * std::sinh(eta); -} +DECLARE_SOA_INDEX_COLUMN(McCollision, mcCollision); //! original global index of the MC collision +} // namespace hf_mc_coll + +// Declares the base table with reconstructed collisions (CollBases) and joinable tables (CollIds). +#define DECLARE_TABLES_COLL(_hf_type_, _hf_description_) \ + DECLARE_SOA_TABLE_STAGED(Hf##_hf_type_##CollBases, "HF" _hf_description_ "COLLBASE", \ + o2::soa::Index<>, \ + collision::PosX, \ + collision::PosY, \ + collision::PosZ, \ + collision::NumContrib, \ + hf_coll_base::CentFT0A, \ + hf_coll_base::CentFT0C, \ + hf_coll_base::CentFT0M, \ + hf_coll_base::CentFV0A, \ + hf_coll_base::MultZeqNTracksPV, \ + o2::soa::Marker); \ + \ + using Hf##_hf_type_##CollBase = Hf##_hf_type_##CollBases::iterator; \ + using StoredHf##_hf_type_##CollBase = StoredHf##_hf_type_##CollBases::iterator; \ + \ + DECLARE_SOA_TABLE_STAGED(Hf##_hf_type_##CollIds, "HF" _hf_description_ "COLLID", \ + hf_cand::CollisionId, \ + o2::soa::Marker); + +// Declares the base table with MC collisions (McCollBases) and joinable tables (McCollIds, McRCollIds). +#define DECLARE_TABLES_MCCOLL(_hf_type_, _hf_description_, _hf_namespace_) \ + namespace hf_mc_coll \ + { \ + namespace der_##_hf_namespace_ \ + { \ + DECLARE_SOA_ARRAY_INDEX_COLUMN_CUSTOM(Hf##_hf_type_##CollBase, hfCollBases, "HF" _hf_description_ "COLLBASES"); \ + } \ + } \ + DECLARE_SOA_TABLE_STAGED(Hf##_hf_type_##McCollBases, "HF" _hf_description_ "MCCOLLBASE", \ + o2::soa::Index<>, \ + mccollision::PosX, \ + mccollision::PosY, \ + mccollision::PosZ, \ + cent::CentFT0M, \ + o2::soa::Marker); \ + \ + using Hf##_hf_type_##McCollBase = Hf##_hf_type_##McCollBases::iterator; \ + using StoredHf##_hf_type_##McCollBase = StoredHf##_hf_type_##McCollBases::iterator; \ + \ + DECLARE_SOA_TABLE_STAGED(Hf##_hf_type_##McCollIds, "HF" _hf_description_ "MCCOLLID", \ + hf_mc_coll::McCollisionId, \ + o2::soa::Marker); \ + \ + DECLARE_SOA_TABLE_STAGED(Hf##_hf_type_##McRCollIds, "HF" _hf_description_ "MCRCOLLID", \ + hf_mc_coll::der_##_hf_namespace_::Hf##_hf_type_##CollBaseIds); + +// ================ +// Candidate tables +// ================ -/// p as a function of pT, eta -/// \todo Move to RecoDecay -template -auto p(TPt pt, TEta eta) +namespace hf_cand_base { - return pt * std::cosh(eta); -} +DECLARE_SOA_COLUMN(Eta, eta, float); //! pseudorapidity +DECLARE_SOA_COLUMN(M, m, float); //! invariant mass +DECLARE_SOA_COLUMN(Phi, phi, float); //! azimuth +DECLARE_SOA_COLUMN(Pt, pt, float); //! transverse momentum +DECLARE_SOA_COLUMN(Y, y, float); //! rapidity +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! px + [](float pt, float phi) -> float { return RecoDecayPtEtaPhi::px(pt, phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, //! py + [](float pt, float phi) -> float { return RecoDecayPtEtaPhi::py(pt, phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! px + [](float pt, float eta) -> float { return RecoDecayPtEtaPhi::pz(pt, eta); }); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! momentum + [](float pt, float eta) -> float { return RecoDecayPtEtaPhi::p(pt, eta); }); +} // namespace hf_cand_base -/// Rapidity as a function of pT, eta, mass -/// \todo Move to RecoDecay -template -auto y(TPt pt, TEta eta, TM m) +// Candidate selection flags +namespace hf_cand_sel { - return std::log((RecoDecay::sqrtSumOfSquares(m, pt * std::cosh(eta)) + pt * std::sinh(eta)) / RecoDecay::sqrtSumOfSquares(m, pt)); +DECLARE_SOA_COLUMN(CandidateSelFlag, candidateSelFlag, int8_t); //! bitmap of the selected candidate type } -/// Energy as a function of pT, eta, mass -/// \todo Move to RecoDecay -template -auto e(TPt pt, TEta eta, TM m) +// Candidate MC columns +namespace hf_cand_mc { - return RecoDecay::sqrtSumOfSquares(m, p(pt, eta)); -} -} // namespace functions_pt_eta_phi +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); //! flag for reconstruction level matching +DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); //! particle origin, reconstruction level +DECLARE_SOA_COLUMN(IsCandidateSwapped, isCandidateSwapped, int8_t); //! swapping of the prongs order +DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); //! resonant decay channel flag, reconstruction level +DECLARE_SOA_COLUMN(MlScoreSig, mlScoreSig, float); //! ML score for signal class +DECLARE_SOA_COLUMN(MlScoreBkg, mlScoreBkg, float); //! ML score for background class +DECLARE_SOA_COLUMN(MlScorePrompt, mlScorePrompt, float); //! ML score for prompt class +DECLARE_SOA_COLUMN(MlScoreNonPrompt, mlScoreNonPrompt, float); //! ML score for non-prompt class +DECLARE_SOA_COLUMN(MlScores, mlScores, std::vector); //! vector of ML scores +} // namespace hf_cand_mc -namespace d0 -{ -DECLARE_SOA_DYNAMIC_COLUMN(Y, y, //! D0 rapidity - [](float pt, float eta) -> float { return functions_pt_eta_phi::y(pt, eta, o2::constants::physics::MassD0); }); -} -namespace lc +namespace hf_mc_particle { -DECLARE_SOA_DYNAMIC_COLUMN(Y, y, //! Lambda_c rapidity - [](float pt, float eta) -> float { return functions_pt_eta_phi::y(pt, eta, o2::constants::physics::MassLambdaCPlus); }); -} -DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! px - [](float pt, float phi) -> float { return functions_pt_eta_phi::px(pt, phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Py, py, //! py - [](float pt, float phi) -> float { return functions_pt_eta_phi::py(pt, phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! px - [](float pt, float eta) -> float { return functions_pt_eta_phi::pz(pt, eta); }); -DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! momentum - [](float pt, float eta) -> float { return functions_pt_eta_phi::p(pt, eta); }); -} // namespace hf_cand_base +DECLARE_SOA_INDEX_COLUMN(McCollision, mcCollision); //! MC collision of this particle +DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! MC particle +DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); //! flag for generator level matching +DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! particle origin, generator level +DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); //! resonant decay channel flag, generator level +} // namespace hf_mc_particle + +// Declares the base table with candidates (Bases). +#define DECLARE_TABLE_CAND_BASE(_hf_type_, _hf_description_, _hf_namespace_) \ + namespace hf_cand_base \ + { \ + namespace der_##_hf_namespace_ \ + { \ + DECLARE_SOA_INDEX_COLUMN_CUSTOM(Hf##_hf_type_##CollBase, hfCollBase, "HF" _hf_description_ "COLLBASES"); \ + } \ + } \ + \ + DECLARE_SOA_TABLE_STAGED(Hf##_hf_type_##Bases, "HF" _hf_description_ "BASE", \ + o2::soa::Index<>, \ + hf_cand_base::der_##_hf_namespace_::Hf##_hf_type_##CollBaseId, \ + hf_cand_base::Pt, \ + hf_cand_base::Eta, \ + hf_cand_base::Phi, \ + hf_cand_base::M, \ + hf_cand_base::Y, \ + hf_cand_base::Px, \ + hf_cand_base::Py, \ + hf_cand_base::Pz, \ + hf_cand_base::P, \ + o2::soa::Marker); + +// Declares the table with global indices for 2-prong candidates (Ids). +#define DECLARE_TABLE_CAND_ID_2P(_hf_type_, _hf_description_) \ + DECLARE_SOA_TABLE_STAGED(Hf##_hf_type_##Ids, "HF" _hf_description_ "ID", \ + hf_cand::CollisionId, \ + hf_track_index::Prong0Id, \ + hf_track_index::Prong1Id, \ + o2::soa::Marker); + +// Declares the table with global indices for 3-prong candidates (Ids). +#define DECLARE_TABLE_CAND_ID_3P(_hf_type_, _hf_description_) \ + DECLARE_SOA_TABLE_STAGED(Hf##_hf_type_##Ids, "HF" _hf_description_ "ID", \ + hf_cand::CollisionId, \ + hf_track_index::Prong0Id, \ + hf_track_index::Prong1Id, \ + hf_track_index::Prong2Id, \ + o2::soa::Marker); + +// Declares the table with candidate selection flags (Sels). +#define DECLARE_TABLE_CAND_SEL(_hf_type_, _hf_description_) \ + DECLARE_SOA_TABLE_STAGED(Hf##_hf_type_##Sels, "HF" _hf_description_ "SEL", \ + hf_cand_sel::CandidateSelFlag, \ + o2::soa::Marker); + +// ================ +// MC particle tables +// ================ + +// Declares the base table with MC particles (PBases). +#define DECLARE_TABLE_MCPARTICLE_BASE(_hf_type_, _hf_description_, _hf_namespace_) \ + namespace hf_mc_particle \ + { \ + namespace der_##_hf_namespace_ \ + { \ + DECLARE_SOA_INDEX_COLUMN_CUSTOM(Hf##_hf_type_##McCollBase, hfMcCollBase, "HF" _hf_description_ "MCCOLLBASES"); \ + } \ + } \ + DECLARE_SOA_TABLE_STAGED(Hf##_hf_type_##PBases, "HF" _hf_description_ "PBASE", \ + o2::soa::Index<>, \ + hf_mc_particle::der_##_hf_namespace_::Hf##_hf_type_##McCollBaseId, \ + hf_cand_base::Pt, \ + hf_cand_base::Eta, \ + hf_cand_base::Phi, \ + hf_cand_base::Y, \ + hf_mc_particle::FlagMcMatchGen, \ + hf_mc_particle::OriginMcGen, \ + hf_cand_base::Px, \ + hf_cand_base::Py, \ + hf_cand_base::Pz, \ + hf_cand_base::P, \ + o2::soa::Marker); + +// Declares the table with global indices for MC particles (PIds). +#define DECLARE_TABLE_MCPARTICLE_ID(_hf_type_, _hf_description_) \ + DECLARE_SOA_TABLE_STAGED(Hf##_hf_type_##PIds, "HF" _hf_description_ "PID", \ + hf_mc_particle::McCollisionId, \ + hf_mc_particle::McParticleId, \ + o2::soa::Marker); + +// ================ +// Helper macros for combinations +// ================ + +#define DECLARE_TABLES_COMMON(_hf_type_, _hf_description_, _hf_namespace_) \ + DECLARE_TABLES_COLL(_hf_type_, _hf_description_) \ + DECLARE_TABLES_MCCOLL(_hf_type_, _hf_description_, _hf_namespace_) \ + DECLARE_TABLE_CAND_BASE(_hf_type_, _hf_description_, _hf_namespace_) \ + DECLARE_TABLE_CAND_SEL(_hf_type_, _hf_description_) \ + DECLARE_TABLE_MCPARTICLE_BASE(_hf_type_, _hf_description_, _hf_namespace_) \ + DECLARE_TABLE_MCPARTICLE_ID(_hf_type_, _hf_description_) + +#define DECLARE_TABLES_2P(_hf_type_, _hf_description_, _hf_namespace_, _marker_number_) \ + constexpr uint Marker##_hf_type_ = _marker_number_; \ + DECLARE_TABLES_COMMON(_hf_type_, _hf_description_, _hf_namespace_) \ + DECLARE_TABLE_CAND_ID_2P(_hf_type_, _hf_description_) + +#define DECLARE_TABLES_3P(_hf_type_, _hf_description_, _hf_namespace_, _marker_number_) \ + constexpr uint Marker##_hf_type_ = _marker_number_; \ + DECLARE_TABLES_COMMON(_hf_type_, _hf_description_, _hf_namespace_) \ + DECLARE_TABLE_CAND_ID_3P(_hf_type_, _hf_description_) + +// ================ +// Declarations of common tables for individual species +// ================ + +DECLARE_TABLES_2P(D0, "D0", d0, 2); +DECLARE_TABLES_3P(Lc, "LC", lc, 3); +DECLARE_TABLES_3P(Dplus, "DP", dplus, 4); +DECLARE_TABLES_3P(Bplus, "BP", bplus, 5); + +// ================ +// Additional species-specific candidate tables +// ================ // Candidate properties used for selection namespace hf_cand_par @@ -239,9 +306,13 @@ DECLARE_SOA_COLUMN(RSecondaryVertex, rSecondaryVertex, float); DECLARE_SOA_COLUMN(NSigTofKa0, nSigTofKa0, float); DECLARE_SOA_COLUMN(NSigTofKa1, nSigTofKa1, float); DECLARE_SOA_COLUMN(NSigTofKa2, nSigTofKa2, float); +DECLARE_SOA_COLUMN(NSigTofKaExpPi, nSigTofKaExpPi, float); +DECLARE_SOA_COLUMN(NSigTofKaExpKa, nSigTofKaExpKa, float); DECLARE_SOA_COLUMN(NSigTofPi0, nSigTofPi0, float); DECLARE_SOA_COLUMN(NSigTofPi1, nSigTofPi1, float); DECLARE_SOA_COLUMN(NSigTofPi2, nSigTofPi2, float); +DECLARE_SOA_COLUMN(NSigTofPiExpPi, nSigTofPiExpPi, float); +DECLARE_SOA_COLUMN(NSigTofPiExpKa, nSigTofPiExpKa, float); DECLARE_SOA_COLUMN(NSigTofPr0, nSigTofPr0, float); DECLARE_SOA_COLUMN(NSigTofPr1, nSigTofPr1, float); DECLARE_SOA_COLUMN(NSigTofPr2, nSigTofPr2, float); @@ -249,9 +320,13 @@ DECLARE_SOA_COLUMN(NSigTofPr2, nSigTofPr2, float); DECLARE_SOA_COLUMN(NSigTpcKa0, nSigTpcKa0, float); DECLARE_SOA_COLUMN(NSigTpcKa1, nSigTpcKa1, float); DECLARE_SOA_COLUMN(NSigTpcKa2, nSigTpcKa2, float); +DECLARE_SOA_COLUMN(NSigTpcKaExpPi, nSigTpcKaExpPi, float); +DECLARE_SOA_COLUMN(NSigTpcKaExpKa, nSigTpcKaExpKa, float); DECLARE_SOA_COLUMN(NSigTpcPi0, nSigTpcPi0, float); DECLARE_SOA_COLUMN(NSigTpcPi1, nSigTpcPi1, float); DECLARE_SOA_COLUMN(NSigTpcPi2, nSigTpcPi2, float); +DECLARE_SOA_COLUMN(NSigTpcPiExpPi, nSigTpcPiExpPi, float); +DECLARE_SOA_COLUMN(NSigTpcPiExpKa, nSigTpcPiExpKa, float); DECLARE_SOA_COLUMN(NSigTpcPr0, nSigTpcPr0, float); DECLARE_SOA_COLUMN(NSigTpcPr1, nSigTpcPr1, float); DECLARE_SOA_COLUMN(NSigTpcPr2, nSigTpcPr2, float); @@ -259,480 +334,403 @@ DECLARE_SOA_COLUMN(NSigTpcPr2, nSigTpcPr2, float); DECLARE_SOA_COLUMN(NSigTpcTofKa0, nSigTpcTofKa0, float); DECLARE_SOA_COLUMN(NSigTpcTofKa1, nSigTpcTofKa1, float); DECLARE_SOA_COLUMN(NSigTpcTofKa2, nSigTpcTofKa2, float); +DECLARE_SOA_COLUMN(NSigTpcTofKaExpPi, nSigTpcTofKaExpPi, float); +DECLARE_SOA_COLUMN(NSigTpcTofKaExpKa, nSigTpcTofKaExpKa, float); DECLARE_SOA_COLUMN(NSigTpcTofPi0, nSigTpcTofPi0, float); DECLARE_SOA_COLUMN(NSigTpcTofPi1, nSigTpcTofPi1, float); DECLARE_SOA_COLUMN(NSigTpcTofPi2, nSigTpcTofPi2, float); +DECLARE_SOA_COLUMN(NSigTpcTofPiExpPi, nSigTpcTofPiExpPi, float); +DECLARE_SOA_COLUMN(NSigTpcTofPiExpKa, nSigTpcTofPiExpKa, float); DECLARE_SOA_COLUMN(NSigTpcTofPr0, nSigTpcTofPr0, float); DECLARE_SOA_COLUMN(NSigTpcTofPr1, nSigTpcTofPr1, float); DECLARE_SOA_COLUMN(NSigTpcTofPr2, nSigTpcTofPr2, float); } // namespace hf_cand_par -// Candidate selection flags -namespace hf_cand_sel +// Candidate properties of the charm daughter candidate used for selection of the beauty candidate +// Copy of hf_cand_par with "Charm" suffix to make it joinable with the beauty candidate table. +// We don't want to link the charm candidate table because we want to avoid producing it. +namespace hf_cand_par_charm { -DECLARE_SOA_COLUMN(CandidateSelFlag, candidateSelFlag, int8_t); //! bitmap of the selected candidate type -} - -// MC flags -namespace hf_cand_mc +DECLARE_SOA_COLUMN(CosThetaStarCharm, cosThetaStarCharm, float); //! cosine of theta star +DECLARE_SOA_COLUMN(CpaCharm, cpaCharm, float); //! cosine of pointing angle +DECLARE_SOA_COLUMN(CpaXYCharm, cpaXYCharm, float); //! cosine of pointing angle in the transverse plane +DECLARE_SOA_COLUMN(CtCharm, ctCharm, float); //! proper lifetime times c +DECLARE_SOA_COLUMN(DecayLengthCharm, decayLengthCharm, float); //! decay length +DECLARE_SOA_COLUMN(DecayLengthNormalisedCharm, decayLengthNormalisedCharm, float); //! decay length divided by its uncertainty +DECLARE_SOA_COLUMN(DecayLengthXYCharm, decayLengthXYCharm, float); //! decay length in the transverse plane +DECLARE_SOA_COLUMN(DecayLengthXYNormalisedCharm, decayLengthXYNormalisedCharm, float); //! decay length in the transverse plane divided by its uncertainty +DECLARE_SOA_COLUMN(ImpactParameter0Charm, impactParameter0Charm, float); //! impact parameter of prong 0 +DECLARE_SOA_COLUMN(ImpactParameter1Charm, impactParameter1Charm, float); //! impact parameter of prong 1 +DECLARE_SOA_COLUMN(ImpactParameterNormalised0Charm, impactParameterNormalised0Charm, float); //! impact parameter of prong 0 divided by its uncertainty +DECLARE_SOA_COLUMN(ImpactParameterNormalised1Charm, impactParameterNormalised1Charm, float); //! impact parameter of prong 1 divided by its uncertainty +DECLARE_SOA_COLUMN(ImpactParameterNormalised2Charm, impactParameterNormalised2Charm, float); //! impact parameter of prong 2 divided by its uncertainty +DECLARE_SOA_COLUMN(ImpactParameterProductCharm, impactParameterProductCharm, float); //! product of impact parameters of prong 0 and prong 1 +DECLARE_SOA_COLUMN(MaxNormalisedDeltaIPCharm, maxNormalisedDeltaIPCharm, float); //! see RecoDecay::maxNormalisedDeltaIP +DECLARE_SOA_COLUMN(PProng0Charm, pProng0Charm, float); //! momentum magnitude of prong 0 +DECLARE_SOA_COLUMN(PProng1Charm, pProng1Charm, float); //! momentum magnitude of prong 1 +DECLARE_SOA_COLUMN(PProng2Charm, pProng2Charm, float); //! momentum magnitude of prong 2 +DECLARE_SOA_COLUMN(PtProng0Charm, ptProng0Charm, float); //! transverse momentum of prong 0 +DECLARE_SOA_COLUMN(PtProng1Charm, ptProng1Charm, float); //! transverse momentum of prong 1 +DECLARE_SOA_COLUMN(PtProng2Charm, ptProng2Charm, float); //! transverse momentum of prong 2 +DECLARE_SOA_COLUMN(RSecondaryVertexCharm, rSecondaryVertexCharm, float); //! distance of the secondary vertex from the z axis +// TOF +DECLARE_SOA_COLUMN(NSigTofKa0Charm, nSigTofKa0Charm, float); +DECLARE_SOA_COLUMN(NSigTofKa1Charm, nSigTofKa1Charm, float); +DECLARE_SOA_COLUMN(NSigTofKa2Charm, nSigTofKa2Charm, float); +DECLARE_SOA_COLUMN(NSigTofKaExpPiCharm, nSigTofKaExpPiCharm, float); +DECLARE_SOA_COLUMN(NSigTofKaExpKaCharm, nSigTofKaExpKaCharm, float); +DECLARE_SOA_COLUMN(NSigTofPi0Charm, nSigTofPi0Charm, float); +DECLARE_SOA_COLUMN(NSigTofPi1Charm, nSigTofPi1Charm, float); +DECLARE_SOA_COLUMN(NSigTofPi2Charm, nSigTofPi2Charm, float); +DECLARE_SOA_COLUMN(NSigTofPiExpPiCharm, nSigTofPiExpPiCharm, float); +DECLARE_SOA_COLUMN(NSigTofPiExpKaCharm, nSigTofPiExpKaCharm, float); +DECLARE_SOA_COLUMN(NSigTofPr0Charm, nSigTofPr0Charm, float); +DECLARE_SOA_COLUMN(NSigTofPr1Charm, nSigTofPr1Charm, float); +DECLARE_SOA_COLUMN(NSigTofPr2Charm, nSigTofPr2Charm, float); +// TPC +DECLARE_SOA_COLUMN(NSigTpcKa0Charm, nSigTpcKa0Charm, float); +DECLARE_SOA_COLUMN(NSigTpcKa1Charm, nSigTpcKa1Charm, float); +DECLARE_SOA_COLUMN(NSigTpcKa2Charm, nSigTpcKa2Charm, float); +DECLARE_SOA_COLUMN(NSigTpcKaExpPiCharm, nSigTpcKaExpPiCharm, float); +DECLARE_SOA_COLUMN(NSigTpcKaExpKaCharm, nSigTpcKaExpKaCharm, float); +DECLARE_SOA_COLUMN(NSigTpcPi0Charm, nSigTpcPi0Charm, float); +DECLARE_SOA_COLUMN(NSigTpcPi1Charm, nSigTpcPi1Charm, float); +DECLARE_SOA_COLUMN(NSigTpcPi2Charm, nSigTpcPi2Charm, float); +DECLARE_SOA_COLUMN(NSigTpcPiExpPiCharm, nSigTpcPiExpPiCharm, float); +DECLARE_SOA_COLUMN(NSigTpcPiExpKaCharm, nSigTpcPiExpKaCharm, float); +DECLARE_SOA_COLUMN(NSigTpcPr0Charm, nSigTpcPr0Charm, float); +DECLARE_SOA_COLUMN(NSigTpcPr1Charm, nSigTpcPr1Charm, float); +DECLARE_SOA_COLUMN(NSigTpcPr2Charm, nSigTpcPr2Charm, float); +// TPC+TOF +DECLARE_SOA_COLUMN(NSigTpcTofKa0Charm, nSigTpcTofKa0Charm, float); +DECLARE_SOA_COLUMN(NSigTpcTofKa1Charm, nSigTpcTofKa1Charm, float); +DECLARE_SOA_COLUMN(NSigTpcTofKa2Charm, nSigTpcTofKa2Charm, float); +DECLARE_SOA_COLUMN(NSigTpcTofKaExpPiCharm, nSigTpcTofKaExpPiCharm, float); +DECLARE_SOA_COLUMN(NSigTpcTofKaExpKaCharm, nSigTpcTofKaExpKaCharm, float); +DECLARE_SOA_COLUMN(NSigTpcTofPi0Charm, nSigTpcTofPi0Charm, float); +DECLARE_SOA_COLUMN(NSigTpcTofPi1Charm, nSigTpcTofPi1Charm, float); +DECLARE_SOA_COLUMN(NSigTpcTofPi2Charm, nSigTpcTofPi2Charm, float); +DECLARE_SOA_COLUMN(NSigTpcTofPiExpPiCharm, nSigTpcTofPiExpPiCharm, float); +DECLARE_SOA_COLUMN(NSigTpcTofPiExpKaCharm, nSigTpcTofPiExpKaCharm, float); +DECLARE_SOA_COLUMN(NSigTpcTofPr0Charm, nSigTpcTofPr0Charm, float); +DECLARE_SOA_COLUMN(NSigTpcTofPr1Charm, nSigTpcTofPr1Charm, float); +DECLARE_SOA_COLUMN(NSigTpcTofPr2Charm, nSigTpcTofPr2Charm, float); +} // namespace hf_cand_par_charm + +// Candidate MC columns of the charm daughter +namespace hf_cand_mc_charm { -DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); //! flag for reconstruction level matching -DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); //! flag for generator level matching -DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); //! particle origin, reconstruction level -DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! particle origin, generator level -DECLARE_SOA_COLUMN(IsCandidateSwapped, isCandidateSwapped, int8_t); //! swapping of the prongs order -DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); //! resonant decay channel flag, reconstruction level -DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); //! resonant decay channel flag, generator level -DECLARE_SOA_COLUMN(MlScoreBkg, mlScoreBkg, float); //! ML score for background class -DECLARE_SOA_COLUMN(MlScorePrompt, mlScorePrompt, float); //! ML score for prompt class -DECLARE_SOA_COLUMN(MlScoreNonPrompt, mlScoreNonPrompt, float); //! ML score for non-prompt class -DECLARE_SOA_COLUMN(MlScores, mlScores, std::vector); //! vector of ML scores -} // namespace hf_cand_mc - +DECLARE_SOA_COLUMN(FlagMcMatchRecCharm, flagMcMatchRecCharm, int8_t); //! flag for reconstruction level matching +DECLARE_SOA_COLUMN(OriginMcRecCharm, originMcRecCharm, int8_t); //! particle origin, reconstruction level +DECLARE_SOA_COLUMN(IsCandidateSwappedCharm, isCandidateSwappedCharm, int8_t); //! swapping of the prongs order +DECLARE_SOA_COLUMN(FlagMcDecayChanRecCharm, flagMcDecayChanRecCharm, int8_t); //! resonant decay channel flag, reconstruction level +DECLARE_SOA_COLUMN(MlScoreSigCharm, mlScoreSigCharm, float); //! ML score for signal class +DECLARE_SOA_COLUMN(MlScoreBkgCharm, mlScoreBkgCharm, float); //! ML score for background class +DECLARE_SOA_COLUMN(MlScorePromptCharm, mlScorePromptCharm, float); //! ML score for prompt class +DECLARE_SOA_COLUMN(MlScoreNonPromptCharm, mlScoreNonPromptCharm, float); //! ML score for non-prompt class +DECLARE_SOA_COLUMN(MlScoresCharm, mlScoresCharm, std::vector); //! vector of ML scores +} // namespace hf_cand_mc_charm + +// ---------------- // D0 +// ---------------- -DECLARE_SOA_TABLE(HfD0Bases, "AOD", "HFD0BASE", //! Table with basic candidate properties used in the analyses - o2::soa::Index<>, - hf_cand_base::HfD0CollBaseId, - hf_cand_base::Pt, - hf_cand_base::Eta, - hf_cand_base::Phi, - hf_cand_base::M, - hf_cand_base::d0::Y, - hf_cand_base::Px, - hf_cand_base::Py, - hf_cand_base::Pz, - hf_cand_base::P); - -DECLARE_SOA_TABLE(StoredHfD0Bases, "AOD1", "HFD0BASE", //! Table with basic candidate properties used in the analyses (stored version) - o2::soa::Index<>, - hf_cand_base::HfD0CollBaseId, - hf_cand_base::Pt, - hf_cand_base::Eta, - hf_cand_base::Phi, - hf_cand_base::M, - hf_cand_base::d0::Y, - hf_cand_base::Px, - hf_cand_base::Py, - hf_cand_base::Pz, - hf_cand_base::P, - soa::Marker<1>); +// candidates for removal: +// PxProng0, PyProng0, PzProng0,... (same for 1, 2), we can keep Pt, Eta, Phi instead +// XY: CpaXY, DecayLengthXY, ErrorDecayLengthXY +// normalised: DecayLengthNormalised, DecayLengthXYNormalised, ImpactParameterNormalised0 +DECLARE_SOA_TABLE_STAGED(HfD0Pars, "HFD0PAR", //! Table with candidate properties used for selection + hf_cand::Chi2PCA, + hf_cand_par::Cpa, + hf_cand_par::CpaXY, + hf_cand_par::DecayLength, + hf_cand_par::DecayLengthXY, + hf_cand_par::DecayLengthNormalised, + hf_cand_par::DecayLengthXYNormalised, + hf_cand_par::PtProng0, + hf_cand_par::PtProng1, + hf_cand::ImpactParameter0, + hf_cand::ImpactParameter1, + hf_cand_par::ImpactParameterNormalised0, + hf_cand_par::ImpactParameterNormalised1, + hf_cand_par::NSigTpcPiExpPi, + hf_cand_par::NSigTofPiExpPi, + hf_cand_par::NSigTpcTofPiExpPi, + hf_cand_par::NSigTpcKaExpPi, + hf_cand_par::NSigTofKaExpPi, + hf_cand_par::NSigTpcTofKaExpPi, + hf_cand_par::NSigTpcPiExpKa, + hf_cand_par::NSigTofPiExpKa, + hf_cand_par::NSigTpcTofPiExpKa, + hf_cand_par::NSigTpcKaExpKa, + hf_cand_par::NSigTofKaExpKa, + hf_cand_par::NSigTpcTofKaExpKa, + hf_cand_par::MaxNormalisedDeltaIP, + hf_cand_par::ImpactParameterProduct, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfD0ParEs, "HFD0PARE", //! Table with additional candidate properties used for selection + hf_cand::XSecondaryVertex, + hf_cand::YSecondaryVertex, + hf_cand::ZSecondaryVertex, + hf_cand::ErrorDecayLength, + hf_cand::ErrorDecayLengthXY, + hf_cand::KfTopolChi2OverNdf, + hf_cand_par::RSecondaryVertex, + hf_cand_par::PProng0, + hf_cand_par::PProng1, + hf_cand::PxProng0, + hf_cand::PyProng0, + hf_cand::PzProng0, + hf_cand::PxProng1, + hf_cand::PyProng1, + hf_cand::PzProng1, + hf_cand::ErrorImpactParameter0, + hf_cand::ErrorImpactParameter1, + hf_cand_par::CosThetaStar, + hf_cand_par::Ct, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfD0Mls, "HFD0ML", //! Table with candidate selection ML scores + hf_cand_mc::MlScores, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfD0Mcs, "HFD0MC", //! Table with MC candidate info + hf_cand_mc::FlagMcMatchRec, + hf_cand_mc::OriginMcRec, + o2::soa::Marker); + +// ---------------- +// B+ +// ---------------- // candidates for removal: // PxProng0, PyProng0, PzProng0,... (same for 1, 2), we can keep Pt, Eta, Phi instead // XY: CpaXY, DecayLengthXY, ErrorDecayLengthXY // normalised: DecayLengthNormalised, DecayLengthXYNormalised, ImpactParameterNormalised0 -DECLARE_SOA_TABLE(HfD0Pars, "AOD", "HFD0PAR", //! Table with candidate properties used for selection - hf_cand::Chi2PCA, - hf_cand_par::Cpa, - hf_cand_par::CpaXY, - hf_cand_par::DecayLength, - hf_cand_par::DecayLengthXY, - hf_cand_par::DecayLengthNormalised, - hf_cand_par::DecayLengthXYNormalised, - hf_cand_par::PtProng0, - hf_cand_par::PtProng1, - hf_cand::ImpactParameter0, - hf_cand::ImpactParameter1, - hf_cand_par::ImpactParameterNormalised0, - hf_cand_par::ImpactParameterNormalised1, - hf_cand_par::NSigTpcPi0, - hf_cand_par::NSigTpcKa0, - hf_cand_par::NSigTofPi0, - hf_cand_par::NSigTofKa0, - hf_cand_par::NSigTpcTofPi0, - hf_cand_par::NSigTpcTofKa0, - hf_cand_par::NSigTpcPi1, - hf_cand_par::NSigTpcKa1, - hf_cand_par::NSigTofPi1, - hf_cand_par::NSigTofKa1, - hf_cand_par::NSigTpcTofPi1, - hf_cand_par::NSigTpcTofKa1, - hf_cand_par::MaxNormalisedDeltaIP, - hf_cand_par::ImpactParameterProduct); - -DECLARE_SOA_TABLE(StoredHfD0Pars, "AOD1", "HFD0PAR", //! Table with candidate properties used for selection (stored version) - hf_cand::Chi2PCA, - hf_cand_par::Cpa, - hf_cand_par::CpaXY, - hf_cand_par::DecayLength, - hf_cand_par::DecayLengthXY, - hf_cand_par::DecayLengthNormalised, - hf_cand_par::DecayLengthXYNormalised, - hf_cand_par::PtProng0, - hf_cand_par::PtProng1, - hf_cand::ImpactParameter0, - hf_cand::ImpactParameter1, - hf_cand_par::ImpactParameterNormalised0, - hf_cand_par::ImpactParameterNormalised1, - hf_cand_par::NSigTpcPi0, - hf_cand_par::NSigTpcKa0, - hf_cand_par::NSigTofPi0, - hf_cand_par::NSigTofKa0, - hf_cand_par::NSigTpcTofPi0, - hf_cand_par::NSigTpcTofKa0, - hf_cand_par::NSigTpcPi1, - hf_cand_par::NSigTpcKa1, - hf_cand_par::NSigTofPi1, - hf_cand_par::NSigTofKa1, - hf_cand_par::NSigTpcTofPi1, - hf_cand_par::NSigTpcTofKa1, - hf_cand_par::MaxNormalisedDeltaIP, - hf_cand_par::ImpactParameterProduct, - soa::Marker<1>); - -DECLARE_SOA_TABLE(HfD0ParEs, "AOD", "HFD0PARE", //! Table with additional candidate properties used for selection - collision::PosX, - collision::PosY, - collision::PosZ, - hf_cand::XSecondaryVertex, - hf_cand::YSecondaryVertex, - hf_cand::ZSecondaryVertex, - hf_cand::ErrorDecayLength, - hf_cand::ErrorDecayLengthXY, - hf_cand::KfTopolChi2OverNdf, - hf_cand_par::RSecondaryVertex, - hf_cand_par::PProng0, - hf_cand_par::PProng1, - hf_cand::PxProng0, - hf_cand::PyProng0, - hf_cand::PzProng0, - hf_cand::PxProng1, - hf_cand::PyProng1, - hf_cand::PzProng1, - hf_cand::ErrorImpactParameter0, - hf_cand::ErrorImpactParameter1, - hf_cand_par::CosThetaStar, - hf_cand_par::Ct); - -DECLARE_SOA_TABLE(StoredHfD0ParEs, "AOD1", "HFD0PARE", //! Table with additional candidate properties used for selection (stored version) - collision::PosX, - collision::PosY, - collision::PosZ, - hf_cand::XSecondaryVertex, - hf_cand::YSecondaryVertex, - hf_cand::ZSecondaryVertex, - hf_cand::ErrorDecayLength, - hf_cand::ErrorDecayLengthXY, - hf_cand::KfTopolChi2OverNdf, - hf_cand_par::RSecondaryVertex, - hf_cand_par::PProng0, - hf_cand_par::PProng1, - hf_cand::PxProng0, - hf_cand::PyProng0, - hf_cand::PzProng0, - hf_cand::PxProng1, - hf_cand::PyProng1, - hf_cand::PzProng1, - hf_cand::ErrorImpactParameter0, - hf_cand::ErrorImpactParameter1, - hf_cand_par::CosThetaStar, - hf_cand_par::Ct, - soa::Marker<1>); - -DECLARE_SOA_TABLE(HfD0Sels, "AOD", "HFD0SEL", //! Table with candidate selection flags - hf_cand_sel::CandidateSelFlag); - -DECLARE_SOA_TABLE(StoredHfD0Sels, "AOD1", "HFD0SEL", //! Table with candidate selection flags (stored version) - hf_cand_sel::CandidateSelFlag, - soa::Marker<1>); - -DECLARE_SOA_TABLE(HfD0Mls, "AOD", "HFD0ML", //! Table with candidate selection ML scores - hf_cand_mc::MlScores); - -DECLARE_SOA_TABLE(StoredHfD0Mls, "AOD1", "HFD0ML", //! Table with candidate selection ML scores (stored version) - hf_cand_mc::MlScores, - soa::Marker<1>); - -DECLARE_SOA_TABLE(HfD0Ids, "AOD", "HFD0ID", //! Table with global indices for candidates - hf_cand::CollisionId, - hf_track_index::Prong0Id, - hf_track_index::Prong1Id); - -DECLARE_SOA_TABLE(StoredHfD0Ids, "AOD1", "HFD0ID", //! Table with global indices for candidates (stored version) - hf_cand::CollisionId, - hf_track_index::Prong0Id, - hf_track_index::Prong1Id, - soa::Marker<1>); - -DECLARE_SOA_TABLE(HfD0Mcs, "AOD", "HFD0MC", //! Table with MC candidate info - hf_cand_mc::FlagMcMatchRec, - hf_cand_mc::OriginMcRec); - -DECLARE_SOA_TABLE(StoredHfD0Mcs, "AOD1", "HFD0MC", //! Table with MC candidate info (stored version) - hf_cand_mc::FlagMcMatchRec, - hf_cand_mc::OriginMcRec, - soa::Marker<1>); - -DECLARE_SOA_TABLE(HfD0PBases, "AOD", "HFD0PBASE", //! Table with MC particle info - o2::soa::Index<>, - hf_cand_base::Pt, - hf_cand_base::Eta, - hf_cand_base::Phi, - hf_cand_mc::FlagMcMatchGen, - hf_cand_mc::OriginMcGen, - hf_cand_base::d0::Y, - hf_cand_base::Px, - hf_cand_base::Py, - hf_cand_base::Pz, - hf_cand_base::P); - -DECLARE_SOA_TABLE(StoredHfD0PBases, "AOD1", "HFD0PBASE", //! Table with MC particle info (stored version) - o2::soa::Index<>, - hf_cand_base::Pt, - hf_cand_base::Eta, - hf_cand_base::Phi, - hf_cand_mc::FlagMcMatchGen, - hf_cand_mc::OriginMcGen, - hf_cand_base::d0::Y, - hf_cand_base::Px, - hf_cand_base::Py, - hf_cand_base::Pz, - hf_cand_base::P, - soa::Marker<1>); - -DECLARE_SOA_TABLE(HfD0PIds, "AOD", "HFD0PID", //! Table with global indices for MC particles - hf_cand_base::McCollisionId, - hf_cand_base::McParticleId); - -DECLARE_SOA_TABLE(StoredHfD0PIds, "AOD1", "HFD0PID", //! Table with global indices for MC particles (stored version) - hf_cand_base::McCollisionId, - hf_cand_base::McParticleId, - soa::Marker<1>); - -// 3-prong decays - -DECLARE_SOA_TABLE(Hf3PBases, "AOD", "HF3PBASE", //! Table with basic candidate properties used in the analyses - o2::soa::Index<>, - hf_cand_base::Hf3PCollBaseId, - hf_cand_base::Pt, - hf_cand_base::Eta, - hf_cand_base::Phi, - hf_cand_base::M, - hf_cand_base::lc::Y, - hf_cand_base::Px, - hf_cand_base::Py, - hf_cand_base::Pz, - hf_cand_base::P); - -DECLARE_SOA_TABLE(StoredHf3PBases, "AOD1", "HF3PBASE", //! Table with basic candidate properties used in the analyses (stored version) - o2::soa::Index<>, - hf_cand_base::Hf3PCollBaseId, - hf_cand_base::Pt, - hf_cand_base::Eta, - hf_cand_base::Phi, - hf_cand_base::M, - hf_cand_base::lc::Y, - hf_cand_base::Px, - hf_cand_base::Py, - hf_cand_base::Pz, - hf_cand_base::P, - soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(HfBplusPars, "HFBPPAR", //! Table with candidate properties used for selection + hf_cand::Chi2PCA, + hf_cand_par::Cpa, + hf_cand_par::CpaXY, + hf_cand_par::DecayLength, + hf_cand_par::DecayLengthXY, + hf_cand_par::DecayLengthNormalised, + hf_cand_par::DecayLengthXYNormalised, + hf_cand_par::PtProng0, + hf_cand_par::PtProng1, + hf_cand::ImpactParameter0, + hf_cand::ImpactParameter1, + hf_cand_par::ImpactParameterNormalised0, + hf_cand_par::ImpactParameterNormalised1, + hf_cand_par::NSigTpcPiExpPi, + hf_cand_par::NSigTofPiExpPi, + hf_cand_par::NSigTpcTofPiExpPi, + hf_cand_par::NSigTpcKaExpPi, + hf_cand_par::NSigTofKaExpPi, + hf_cand_par::NSigTpcTofKaExpPi, + hf_cand_par::MaxNormalisedDeltaIP, + hf_cand_par::ImpactParameterProduct, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfBplusParD0s, "HFBPPARD0", //! Table with D0 candidate properties used for selection of B+ + hf_cand_par_charm::CpaCharm, + hf_cand_par_charm::DecayLengthCharm, + hf_cand_par_charm::ImpactParameter0Charm, + hf_cand_par_charm::ImpactParameter1Charm, + hf_cand_par_charm::ImpactParameterProductCharm, + hf_cand_par_charm::NSigTpcPiExpPiCharm, + hf_cand_par_charm::NSigTofPiExpPiCharm, + hf_cand_par_charm::NSigTpcTofPiExpPiCharm, + hf_cand_par_charm::NSigTpcKaExpPiCharm, + hf_cand_par_charm::NSigTofKaExpPiCharm, + hf_cand_par_charm::NSigTpcTofKaExpPiCharm, + hf_cand_par_charm::NSigTpcPiExpKaCharm, + hf_cand_par_charm::NSigTofPiExpKaCharm, + hf_cand_par_charm::NSigTpcTofPiExpKaCharm, + hf_cand_par_charm::NSigTpcKaExpKaCharm, + hf_cand_par_charm::NSigTofKaExpKaCharm, + hf_cand_par_charm::NSigTpcTofKaExpKaCharm); + +DECLARE_SOA_TABLE_STAGED(HfBplusParEs, "HFBPPARE", //! Table with additional candidate properties used for selection + hf_cand::XSecondaryVertex, + hf_cand::YSecondaryVertex, + hf_cand::ZSecondaryVertex, + hf_cand::ErrorDecayLength, + hf_cand::ErrorDecayLengthXY, + hf_cand_par::RSecondaryVertex, + hf_cand_par::PProng1, + hf_cand::PxProng1, + hf_cand::PyProng1, + hf_cand::PzProng1, + hf_cand::ErrorImpactParameter1, + hf_cand_par::CosThetaStar, + hf_cand_par::Ct, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfBplusMls, "HFBPML", //! Table with candidate selection ML scores + hf_cand_mc::MlScoreSig, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfBplusMlD0s, "HFBPMLD0", //! Table with D0 candidate selection ML scores + hf_cand_mc_charm::MlScoresCharm, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfBplusMcs, "HFBPMC", //! Table with MC candidate info + hf_cand_mc::FlagMcMatchRec, + hf_cand_mc::OriginMcRec, + o2::soa::Marker); + +// ---------------- +// Lc +// ---------------- // candidates for removal: // PxProng0, PyProng0, PzProng0,... (same for 1, 2), we can keep Pt, Eta, Phi instead // XY: CpaXY, DecayLengthXY, ErrorDecayLengthXY // normalised: DecayLengthNormalised, DecayLengthXYNormalised, ImpactParameterNormalised0 -DECLARE_SOA_TABLE(Hf3PPars, "AOD", "HF3PPAR", //! Table with candidate properties used for selection - hf_cand::Chi2PCA, - hf_cand::NProngsContributorsPV, - hf_cand_par::Cpa, - hf_cand_par::CpaXY, - hf_cand_par::DecayLength, - hf_cand_par::DecayLengthXY, - hf_cand_par::DecayLengthNormalised, - hf_cand_par::DecayLengthXYNormalised, - hf_cand_par::PtProng0, - hf_cand_par::PtProng1, - hf_cand_par::PtProng2, - hf_cand::ImpactParameter0, - hf_cand::ImpactParameter1, - hf_cand::ImpactParameter2, - hf_cand_par::ImpactParameterNormalised0, - hf_cand_par::ImpactParameterNormalised1, - hf_cand_par::ImpactParameterNormalised2, - hf_cand_par::NSigTpcPi0, - hf_cand_par::NSigTpcPr0, - hf_cand_par::NSigTofPi0, - hf_cand_par::NSigTofPr0, - hf_cand_par::NSigTpcTofPi0, - hf_cand_par::NSigTpcTofPr0, - hf_cand_par::NSigTpcKa1, - hf_cand_par::NSigTofKa1, - hf_cand_par::NSigTpcTofKa1, - hf_cand_par::NSigTpcPi2, - hf_cand_par::NSigTpcPr2, - hf_cand_par::NSigTofPi2, - hf_cand_par::NSigTofPr2, - hf_cand_par::NSigTpcTofPi2, - hf_cand_par::NSigTpcTofPr2); - -DECLARE_SOA_TABLE(StoredHf3PPars, "AOD1", "HF3PPAR", //! Table with candidate properties used for selection (stored version) - hf_cand::Chi2PCA, - hf_cand::NProngsContributorsPV, - hf_cand_par::Cpa, - hf_cand_par::CpaXY, - hf_cand_par::DecayLength, - hf_cand_par::DecayLengthXY, - hf_cand_par::DecayLengthNormalised, - hf_cand_par::DecayLengthXYNormalised, - hf_cand_par::PtProng0, - hf_cand_par::PtProng1, - hf_cand_par::PtProng2, - hf_cand::ImpactParameter0, - hf_cand::ImpactParameter1, - hf_cand::ImpactParameter2, - hf_cand_par::ImpactParameterNormalised0, - hf_cand_par::ImpactParameterNormalised1, - hf_cand_par::ImpactParameterNormalised2, - hf_cand_par::NSigTpcPi0, - hf_cand_par::NSigTpcPr0, - hf_cand_par::NSigTofPi0, - hf_cand_par::NSigTofPr0, - hf_cand_par::NSigTpcTofPi0, - hf_cand_par::NSigTpcTofPr0, - hf_cand_par::NSigTpcKa1, - hf_cand_par::NSigTofKa1, - hf_cand_par::NSigTpcTofKa1, - hf_cand_par::NSigTpcPi2, - hf_cand_par::NSigTpcPr2, - hf_cand_par::NSigTofPi2, - hf_cand_par::NSigTofPr2, - hf_cand_par::NSigTpcTofPi2, - hf_cand_par::NSigTpcTofPr2, - soa::Marker<1>); - -DECLARE_SOA_TABLE(Hf3PParEs, "AOD", "HF3PPARE", //! Table with additional candidate properties used for selection - collision::PosX, - collision::PosY, - collision::PosZ, - hf_cand::XSecondaryVertex, - hf_cand::YSecondaryVertex, - hf_cand::ZSecondaryVertex, - hf_cand::ErrorDecayLength, - hf_cand::ErrorDecayLengthXY, - hf_cand_par::RSecondaryVertex, - hf_cand_par::PProng0, - hf_cand_par::PProng1, - hf_cand_par::PProng2, - hf_cand::PxProng0, - hf_cand::PyProng0, - hf_cand::PzProng0, - hf_cand::PxProng1, - hf_cand::PyProng1, - hf_cand::PzProng1, - hf_cand::PxProng2, - hf_cand::PyProng2, - hf_cand::PzProng2, - hf_cand::ErrorImpactParameter0, - hf_cand::ErrorImpactParameter1, - hf_cand::ErrorImpactParameter2, - hf_cand_par::Ct); - -DECLARE_SOA_TABLE(StoredHf3PParEs, "AOD1", "HF3PPARE", //! Table with additional candidate properties used for selection (stored version) - collision::PosX, - collision::PosY, - collision::PosZ, - hf_cand::XSecondaryVertex, - hf_cand::YSecondaryVertex, - hf_cand::ZSecondaryVertex, - hf_cand::ErrorDecayLength, - hf_cand::ErrorDecayLengthXY, - hf_cand_par::RSecondaryVertex, - hf_cand_par::PProng0, - hf_cand_par::PProng1, - hf_cand_par::PProng2, - hf_cand::PxProng0, - hf_cand::PyProng0, - hf_cand::PzProng0, - hf_cand::PxProng1, - hf_cand::PyProng1, - hf_cand::PzProng1, - hf_cand::PxProng2, - hf_cand::PyProng2, - hf_cand::PzProng2, - hf_cand::ErrorImpactParameter0, - hf_cand::ErrorImpactParameter1, - hf_cand::ErrorImpactParameter2, - hf_cand_par::Ct, - soa::Marker<1>); - -DECLARE_SOA_TABLE(Hf3PSels, "AOD", "HF3PSEL", //! Table with candidate selection flags - hf_cand_sel::CandidateSelFlag, - soa::Marker<2>); - -DECLARE_SOA_TABLE(StoredHf3PSels, "AOD1", "HF3PSEL", //! Table with candidate selection flags (stored version) - hf_cand_sel::CandidateSelFlag, - soa::Marker<3>); - -DECLARE_SOA_TABLE(Hf3PMls, "AOD", "HF3PML", //! Table with candidate selection ML scores - hf_cand_mc::MlScores, - soa::Marker<2>); - -DECLARE_SOA_TABLE(StoredHf3PMls, "AOD1", "HF3PML", //! Table with candidate selection ML scores (stored version) - hf_cand_mc::MlScores, - soa::Marker<3>); - -DECLARE_SOA_TABLE(Hf3PIds, "AOD", "HF3PID", //! Table with global indices for candidates - hf_cand::CollisionId, - hf_track_index::Prong0Id, - hf_track_index::Prong1Id, - hf_track_index::Prong2Id); - -DECLARE_SOA_TABLE(StoredHf3PIds, "AOD1", "HF3PID", //! Table with global indices for candidates (stored version) - hf_cand::CollisionId, - hf_track_index::Prong0Id, - hf_track_index::Prong1Id, - hf_track_index::Prong2Id, - soa::Marker<1>); - -DECLARE_SOA_TABLE(Hf3PMcs, "AOD", "HF3PMC", //! Table with MC candidate info - hf_cand_mc::FlagMcMatchRec, - hf_cand_mc::OriginMcRec, - hf_cand_mc::IsCandidateSwapped); - -DECLARE_SOA_TABLE(StoredHf3PMcs, "AOD1", "HF3PMC", //! Table with MC candidate info (stored version) - hf_cand_mc::FlagMcMatchRec, - hf_cand_mc::OriginMcRec, - hf_cand_mc::IsCandidateSwapped, - soa::Marker<1>); - -DECLARE_SOA_TABLE(Hf3PPBases, "AOD", "HF3PPBASE", //! Table with MC particle info - o2::soa::Index<>, - hf_cand_base::Pt, - hf_cand_base::Eta, - hf_cand_base::Phi, - hf_cand_mc::FlagMcMatchGen, - hf_cand_mc::OriginMcGen, - hf_cand_base::lc::Y, - hf_cand_base::Px, - hf_cand_base::Py, - hf_cand_base::Pz, - hf_cand_base::P); - -DECLARE_SOA_TABLE(StoredHf3PPBases, "AOD1", "HF3PPBASE", //! Table with MC particle info (stored version) - o2::soa::Index<>, - hf_cand_base::Pt, - hf_cand_base::Eta, - hf_cand_base::Phi, - hf_cand_mc::FlagMcMatchGen, - hf_cand_mc::OriginMcGen, - hf_cand_base::lc::Y, - hf_cand_base::Px, - hf_cand_base::Py, - hf_cand_base::Pz, - hf_cand_base::P, - soa::Marker<1>); - -DECLARE_SOA_TABLE(Hf3PPIds, "AOD", "HF3PPID", //! Table with global indices for MC particles - hf_cand_base::McCollisionId, - hf_cand_base::McParticleId, - soa::Marker<2>); - -DECLARE_SOA_TABLE(StoredHf3PPIds, "AOD1", "HF3PPID", //! Table with global indices for MC particles (stored version) - hf_cand_base::McCollisionId, - hf_cand_base::McParticleId, - soa::Marker<3>); +DECLARE_SOA_TABLE_STAGED(HfLcPars, "HFLCPAR", //! Table with candidate properties used for selection + hf_cand::Chi2PCA, + hf_cand::NProngsContributorsPV, + hf_cand_par::Cpa, + hf_cand_par::CpaXY, + hf_cand_par::DecayLength, + hf_cand_par::DecayLengthXY, + hf_cand_par::DecayLengthNormalised, + hf_cand_par::DecayLengthXYNormalised, + hf_cand_par::PtProng0, + hf_cand_par::PtProng1, + hf_cand_par::PtProng2, + hf_cand::ImpactParameter0, + hf_cand::ImpactParameter1, + hf_cand::ImpactParameter2, + hf_cand_par::ImpactParameterNormalised0, + hf_cand_par::ImpactParameterNormalised1, + hf_cand_par::ImpactParameterNormalised2, + hf_cand_par::NSigTpcPi0, + hf_cand_par::NSigTpcPr0, + hf_cand_par::NSigTofPi0, + hf_cand_par::NSigTofPr0, + hf_cand_par::NSigTpcTofPi0, + hf_cand_par::NSigTpcTofPr0, + hf_cand_par::NSigTpcKa1, + hf_cand_par::NSigTofKa1, + hf_cand_par::NSigTpcTofKa1, + hf_cand_par::NSigTpcPi2, + hf_cand_par::NSigTpcPr2, + hf_cand_par::NSigTofPi2, + hf_cand_par::NSigTofPr2, + hf_cand_par::NSigTpcTofPi2, + hf_cand_par::NSigTpcTofPr2, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfLcParEs, "HFLCPARE", //! Table with additional candidate properties used for selection + hf_cand::XSecondaryVertex, + hf_cand::YSecondaryVertex, + hf_cand::ZSecondaryVertex, + hf_cand::ErrorDecayLength, + hf_cand::ErrorDecayLengthXY, + hf_cand_par::RSecondaryVertex, + hf_cand_par::PProng0, + hf_cand_par::PProng1, + hf_cand_par::PProng2, + hf_cand::PxProng0, + hf_cand::PyProng0, + hf_cand::PzProng0, + hf_cand::PxProng1, + hf_cand::PyProng1, + hf_cand::PzProng1, + hf_cand::PxProng2, + hf_cand::PyProng2, + hf_cand::PzProng2, + hf_cand::ErrorImpactParameter0, + hf_cand::ErrorImpactParameter1, + hf_cand::ErrorImpactParameter2, + hf_cand_par::Ct, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfLcMls, "HFLCML", //! Table with candidate selection ML scores + hf_cand_mc::MlScores, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfLcMcs, "HFLCMC", //! Table with MC candidate info + hf_cand_mc::FlagMcMatchRec, + hf_cand_mc::OriginMcRec, + hf_cand_mc::IsCandidateSwapped, + o2::soa::Marker); + +// ---------------- +// D+ +// ---------------- + +// candidates for removal: +// PxProng0, PyProng0, PzProng0,... (same for 1, 2), we can keep Pt, Eta, Phi instead +// XY: CpaXY, DecayLengthXY, ErrorDecayLengthXY +// normalised: DecayLengthNormalised, DecayLengthXYNormalised, ImpactParameterNormalised0 +DECLARE_SOA_TABLE_STAGED(HfDplusPars, "HFDPPAR", //! Table with candidate properties used for selection + hf_cand::Chi2PCA, + hf_cand::NProngsContributorsPV, + hf_cand_par::Cpa, + hf_cand_par::CpaXY, + hf_cand_par::DecayLength, + hf_cand_par::DecayLengthXY, + hf_cand_par::DecayLengthNormalised, + hf_cand_par::DecayLengthXYNormalised, + hf_cand_par::PtProng0, + hf_cand_par::PtProng1, + hf_cand_par::PtProng2, + hf_cand::ImpactParameter0, + hf_cand::ImpactParameter1, + hf_cand::ImpactParameter2, + hf_cand_par::ImpactParameterNormalised0, + hf_cand_par::ImpactParameterNormalised1, + hf_cand_par::ImpactParameterNormalised2, + hf_cand_par::NSigTpcPi0, + hf_cand_par::NSigTofPi0, + hf_cand_par::NSigTpcTofPi0, + hf_cand_par::NSigTpcKa1, + hf_cand_par::NSigTofKa1, + hf_cand_par::NSigTpcTofKa1, + hf_cand_par::NSigTpcPi2, + hf_cand_par::NSigTofPi2, + hf_cand_par::NSigTpcTofPi2, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfDplusParEs, "HFDPPARE", //! Table with additional candidate properties used for selection + hf_cand::XSecondaryVertex, + hf_cand::YSecondaryVertex, + hf_cand::ZSecondaryVertex, + hf_cand::ErrorDecayLength, + hf_cand::ErrorDecayLengthXY, + hf_cand_par::RSecondaryVertex, + hf_cand_par::PProng0, + hf_cand_par::PProng1, + hf_cand_par::PProng2, + hf_cand::PxProng0, + hf_cand::PyProng0, + hf_cand::PzProng0, + hf_cand::PxProng1, + hf_cand::PyProng1, + hf_cand::PzProng1, + hf_cand::PxProng2, + hf_cand::PyProng2, + hf_cand::PzProng2, + hf_cand::ErrorImpactParameter0, + hf_cand::ErrorImpactParameter1, + hf_cand::ErrorImpactParameter2, + hf_cand_par::Ct, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfDplusMls, "HFDPML", //! Table with candidate selection ML scores + hf_cand_mc::MlScores, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfDplusMcs, "HFDPMC", //! Table with MC candidate info + hf_cand_mc::FlagMcMatchRec, + hf_cand_mc::OriginMcRec, + hf_cand_mc::IsCandidateSwapped, // useless + hf_cand_mc::FlagMcDecayChanRec, + o2::soa::Marker); + } // namespace o2::aod #endif // PWGHF_DATAMODEL_DERIVEDTABLES_H_ diff --git a/PWGHF/HFC/DataModel/CorrelationTables.h b/PWGHF/HFC/DataModel/CorrelationTables.h index cfa2867ff99..0ffeeea8868 100644 --- a/PWGHF/HFC/DataModel/CorrelationTables.h +++ b/PWGHF/HFC/DataModel/CorrelationTables.h @@ -51,14 +51,27 @@ DECLARE_SOA_TABLE(DDbarRecoInfo, "AOD", "DDBARRECOINFO", // definition of columns and tables for D0-Hadron correlation pairs namespace hf_correlation_d0_hadron { -DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); //! DeltaPhi between D0 and Hadrons -DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); //! DeltaEta between D0 and Hadrons -DECLARE_SOA_COLUMN(PtD, ptD, float); //! Transverse momentum of D0 -DECLARE_SOA_COLUMN(PtHadron, ptHadron, float); //! Transverse momentum of Hadron -DECLARE_SOA_COLUMN(MD, mD, float); //! Invariant mass of D0 -DECLARE_SOA_COLUMN(MDbar, mDbar, float); //! Invariant mass of D0bar -DECLARE_SOA_COLUMN(SignalStatus, signalStatus, int); //! Tag for D0,D0bar -DECLARE_SOA_COLUMN(PoolBin, poolBin, int); //! Pool Bin for the MixedEvent +DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); //! DeltaPhi between D0 and Hadrons +DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); //! DeltaEta between D0 and Hadrons +DECLARE_SOA_COLUMN(PtD, ptD, float); //! Transverse momentum of D0 +DECLARE_SOA_COLUMN(PtHadron, ptHadron, float); //! Transverse momentum of Hadron +DECLARE_SOA_COLUMN(MD, mD, float); //! Invariant mass of D0 +DECLARE_SOA_COLUMN(MDbar, mDbar, float); //! Invariant mass of D0bar +DECLARE_SOA_COLUMN(MlScoreBkgD0, mlScoreBkgD0, float); //! ML background score for D0 selection +DECLARE_SOA_COLUMN(MlScoreNonPromptD0, mlScoreNonPromptD0, float); //! ML prompt score for D0 selection +DECLARE_SOA_COLUMN(MlScorePromptD0, mlScorePromptD0, float); //! ML prompt score for D0 selection +DECLARE_SOA_COLUMN(MlScoreBkgD0bar, mlScoreBkgD0bar, float); //! ML background score for D0 selection +DECLARE_SOA_COLUMN(MlScoreNonPromptD0bar, mlScoreNonPromptD0bar, float); //! ML prompt score for D0 selection +DECLARE_SOA_COLUMN(MlScorePromptD0bar, mlScorePromptD0bar, float); //! ML prompt score for D0 selection +DECLARE_SOA_COLUMN(SignalStatus, signalStatus, int); //! Tag for D0,D0bar +DECLARE_SOA_COLUMN(PoolBin, poolBin, int); //! Pool Bin for the MixedEvent +DECLARE_SOA_COLUMN(TrackDcaXY, trackDcaXY, float); //! DCA xy of the track +DECLARE_SOA_COLUMN(TrackDcaZ, trackDcaZ, float); //! DCA z of the track +DECLARE_SOA_COLUMN(TrackTPCNClsCrossedRows, trackTPCNClsCrossedRows, int); //! Number of crossed TPC Rows +DECLARE_SOA_COLUMN(IsAutoCorrelated, isAutoCorrelated, bool); //! Correlation Status +DECLARE_SOA_COLUMN(TrackOrigin, trackOrigin, int); //! Check track origin +DECLARE_SOA_COLUMN(IsPrompt, isPrompt, bool); //! Used in MC-Rec, D0 Prompt or Non-Prompt +DECLARE_SOA_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, bool); //! Used in MC-Rec, primary associated particles enum ParticleTypeData { D0Only = 1, // Identified as D0 @@ -80,28 +93,76 @@ enum ParticleTypeMcRec { }; } // namespace hf_correlation_d0_hadron -DECLARE_SOA_TABLE(DHadronPair, "AOD", "DHADRONPAIR", //! D0-Hadrons pairs Informations +DECLARE_SOA_TABLE(D0HadronPair, "AOD", "D0HPAIR", //! D0-Hadrons pairs Informations aod::hf_correlation_d0_hadron::DeltaPhi, aod::hf_correlation_d0_hadron::DeltaEta, aod::hf_correlation_d0_hadron::PtD, aod::hf_correlation_d0_hadron::PtHadron, - aod::hf_correlation_d0_hadron::PoolBin); + aod::hf_correlation_d0_hadron::PoolBin, + aod::hf_correlation_d0_hadron::IsAutoCorrelated); -DECLARE_SOA_TABLE(DHadronRecoInfo, "AOD", "DHADRONRECOINFO", //! D0-Hadrons pairs Reconstructed Informations +DECLARE_SOA_TABLE(D0HadronRecoInfo, "AOD", "D0HRECOINFO", //! D0-Hadrons pairs Reconstructed Informations aod::hf_correlation_d0_hadron::MD, aod::hf_correlation_d0_hadron::MDbar, aod::hf_correlation_d0_hadron::SignalStatus); +DECLARE_SOA_TABLE(D0HadronGenInfo, "AOD", "D0HGENINFO", //! D0-Hadrons pairs Generated Information + aod::hf_correlation_d0_hadron::IsPrompt, + aod::hf_correlation_d0_hadron::IsPhysicalPrimary, + aod::hf_correlation_d0_hadron::TrackOrigin); + +DECLARE_SOA_TABLE(D0HadronMlInfo, "AOD", "D0HMLINFO", //! D0-Hadrons pairs Machine Learning Information + aod::hf_correlation_d0_hadron::MlScoreBkgD0, + aod::hf_correlation_d0_hadron::MlScoreNonPromptD0, + aod::hf_correlation_d0_hadron::MlScorePromptD0, + aod::hf_correlation_d0_hadron::MlScoreBkgD0bar, + aod::hf_correlation_d0_hadron::MlScoreNonPromptD0bar, + aod::hf_correlation_d0_hadron::MlScorePromptD0bar); + +DECLARE_SOA_TABLE(D0CandRecoInfo, "AOD", "D0CANDRECOINFO", //! Ds candidates Reconstructed Information + aod::hf_correlation_d0_hadron::MD, + aod::hf_correlation_d0_hadron::MDbar, + aod::hf_correlation_d0_hadron::PtD, + aod::hf_correlation_d0_hadron::MlScoreBkgD0, + aod::hf_correlation_d0_hadron::MlScorePromptD0, + aod::hf_correlation_d0_hadron::MlScoreBkgD0bar, + aod::hf_correlation_d0_hadron::MlScorePromptD0bar); + +DECLARE_SOA_TABLE(D0CandGenInfo, "AOD", "D0CANDGENOINFO", //! Ds candidates Generated Information + aod::hf_correlation_d0_hadron::IsPrompt); + +DECLARE_SOA_TABLE(D0TrackRecoInfo, "AOD", "D0TRACKRECOINFO", //! Tracks Reconstructed Information + aod::hf_correlation_d0_hadron::TrackDcaXY, + aod::hf_correlation_d0_hadron::TrackDcaZ, + aod::hf_correlation_d0_hadron::TrackTPCNClsCrossedRows); + // Note: definition of columns and tables for Lc-Hadron correlation pairs namespace hf_correlation_lc_hadron { -DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); //! DeltaPhi between Lc and Hadrons -DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); //! DeltaEta between Lc and Hadrons -DECLARE_SOA_COLUMN(PtLc, ptLc, float); //! Transverse momentum of Lc -DECLARE_SOA_COLUMN(PtHadron, ptHadron, float); //! Transverse momentum of Hadron -DECLARE_SOA_COLUMN(MLc, mLc, float); //! Invariant mass of Lc -DECLARE_SOA_COLUMN(SignalStatus, signalStatus, int); //! Tag for LcToPKPi/LcToPiKP -DECLARE_SOA_COLUMN(PoolBin, poolBin, int); //! Pool Bin for the MixedEvent +DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); //! DeltaPhi between Lc and Hadrons +DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); //! DeltaEta between Lc and Hadrons +DECLARE_SOA_COLUMN(DeltaY, deltaY, float); //! DeltaY between Lc and Hadrons +DECLARE_SOA_COLUMN(PtLc, ptLc, float); //! Transverse momentum of Lc +DECLARE_SOA_COLUMN(PtHadron, ptHadron, float); //! Transverse momentum of Hadron +DECLARE_SOA_COLUMN(MLc, mLc, float); //! Invariant mass of Lc +DECLARE_SOA_COLUMN(MlScoreBkg, mlScoreBkg, float); //! ML background score for Lc selection +DECLARE_SOA_COLUMN(MlScorePrompt, mlScorePrompt, float); //! ML prompt score for Lc selection +DECLARE_SOA_COLUMN(SignalStatus, signalStatus, int); //! Tag for LcToPKPi/LcToPiKP +DECLARE_SOA_COLUMN(PoolBin, poolBin, int); //! Pool Bin for the MixedEvent +DECLARE_SOA_COLUMN(TrackDcaXY, trackDcaXY, float); //! DCA xy of the track +DECLARE_SOA_COLUMN(TrackDcaZ, trackDcaZ, float); //! DCA z of the track +DECLARE_SOA_COLUMN(TrackTPCNClsCrossedRows, trackTPCNClsCrossedRows, int); //! Number of crossed TPC Rows +DECLARE_SOA_COLUMN(TrackOrigin, trackOrigin, int); //! Number of crossed TPC Rows +DECLARE_SOA_COLUMN(IsSignal, isSignal, bool); //! Used in MC-Rec, Lc Signal +DECLARE_SOA_COLUMN(IsPrompt, isPrompt, bool); //! Used in MC-Rec, Lc Prompt or Non-Prompt +DECLARE_SOA_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, bool); //! Used in MC-Rec, primary associated particles +DECLARE_SOA_COLUMN(IsAutoCorrelated, isAutoCorrelated, bool); //! Correlation Status +DECLARE_SOA_COLUMN(PrNsigmTPC, prNsigmTPC, float); //! Associated Particle TPC nSigma proton +DECLARE_SOA_COLUMN(KaNsigmTPC, kaNsigmTPC, float); //! Associated Particle TPC nSigma Kaon +DECLARE_SOA_COLUMN(PiNsigmTPC, piNsigmTPC, float); //! Associated Particle TPC nSigma Pion +DECLARE_SOA_COLUMN(PrNsigmTOF, prNsigmTOF, float); //! Associated Particle TOF nSigma Proton +DECLARE_SOA_COLUMN(KaNsigmTOF, kaNsigmTOF, float); //! Associated Particle TOF nSigma Kaon +DECLARE_SOA_COLUMN(PiNsigmTOF, piNsigmTOF, float); //! Associated Particle TOF nSigma Pion } // namespace hf_correlation_lc_hadron DECLARE_SOA_TABLE(LcHadronPair, "AOD", "LCHPAIR", //! Lc-Hadrons pairs Informations @@ -109,12 +170,51 @@ DECLARE_SOA_TABLE(LcHadronPair, "AOD", "LCHPAIR", //! Lc-Hadrons pairs Informati aod::hf_correlation_lc_hadron::DeltaEta, aod::hf_correlation_lc_hadron::PtLc, aod::hf_correlation_lc_hadron::PtHadron, - aod::hf_correlation_lc_hadron::PoolBin); + aod::hf_correlation_lc_hadron::PoolBin, + aod::hf_correlation_lc_hadron::IsAutoCorrelated); DECLARE_SOA_TABLE(LcHadronRecoInfo, "AOD", "LCHRECOINFO", //! Lc-Hadrons pairs Reconstructed Informations aod::hf_correlation_lc_hadron::MLc, aod::hf_correlation_lc_hadron::SignalStatus); - +DECLARE_SOA_TABLE(LcHadronPairTrkPID, "AOD", "LCHPAIRPID", //! Lc-proton details + aod::hf_correlation_lc_hadron::PrNsigmTPC, + aod::hf_correlation_lc_hadron::KaNsigmTPC, + aod::hf_correlation_lc_hadron::PiNsigmTPC, + aod::hf_correlation_lc_hadron::PrNsigmTOF, + aod::hf_correlation_lc_hadron::KaNsigmTOF, + aod::hf_correlation_lc_hadron::PiNsigmTOF); +DECLARE_SOA_TABLE(LcHadronTrkPID, "AOD", "LCHTRKPID", //! Lc-proton details + aod::hf_correlation_lc_hadron::PrNsigmTPC, + aod::hf_correlation_lc_hadron::KaNsigmTPC, + aod::hf_correlation_lc_hadron::PiNsigmTPC, + aod::hf_correlation_lc_hadron::PrNsigmTOF, + aod::hf_correlation_lc_hadron::KaNsigmTOF, + aod::hf_correlation_lc_hadron::PiNsigmTOF); + +DECLARE_SOA_TABLE(LcHadronGenInfo, "AOD", "LCHGENINFO", //! Lc-Hadrons pairs Generated Information + aod::hf_correlation_lc_hadron::IsPrompt, + aod::hf_correlation_lc_hadron::IsPhysicalPrimary, + aod::hf_correlation_lc_hadron::TrackOrigin); + +DECLARE_SOA_TABLE(LcHadronMlInfo, "AOD", "LCHMLINFO", //! Lc-Hadrons pairs Machine Learning Information + aod::hf_correlation_lc_hadron::MlScoreBkg, + aod::hf_correlation_lc_hadron::MlScorePrompt); + +DECLARE_SOA_TABLE(LcRecoInfo, "AOD", "LCRECOINFO", //! Lc candidates Reconstructed Information + aod::hf_correlation_lc_hadron::MLc, + aod::hf_correlation_lc_hadron::PtLc, + aod::hf_correlation_lc_hadron::MlScoreBkg, + aod::hf_correlation_lc_hadron::MlScorePrompt); + +DECLARE_SOA_TABLE(LcGenInfo, "AOD", "LCGENOINFO", //! Lc candidates Generated Information + aod::hf_correlation_lc_hadron::IsPrompt); + +DECLARE_SOA_TABLE(TrkRecInfoLc, "AOD", "TRKRECINFOLC", //! Tracks Reconstructed Information + aod::hf_correlation_lc_hadron::TrackDcaXY, + aod::hf_correlation_lc_hadron::TrackDcaZ, + aod::hf_correlation_lc_hadron::TrackTPCNClsCrossedRows); +DECLARE_SOA_TABLE(LcHadronPairY, "AOD", "LCHPAIRY", //! Lc candidates Generated Information + aod::hf_correlation_lc_hadron::DeltaY); // definition of columns and tables for Ds-Hadron correlation pairs namespace hf_correlation_ds_hadron { @@ -129,7 +229,9 @@ DECLARE_SOA_COLUMN(TrackDcaXY, trackDcaXY, float); //! D DECLARE_SOA_COLUMN(TrackDcaZ, trackDcaZ, float); //! DCA z of the track DECLARE_SOA_COLUMN(PoolBin, poolBin, int); //! Pool Bin for the MixedEvent DECLARE_SOA_COLUMN(TrackTPCNClsCrossedRows, trackTPCNClsCrossedRows, int); //! Number of crossed TPC Rows +DECLARE_SOA_COLUMN(TrackOrigin, trackOrigin, int); //! Number of crossed TPC Rows DECLARE_SOA_COLUMN(IsSignal, isSignal, bool); //! Used in MC-Rec, Ds Signal +DECLARE_SOA_COLUMN(IsDecayChan, isDecayChan, bool); //! Used in MC-Rec, Ds decay channel check DECLARE_SOA_COLUMN(IsPrompt, isPrompt, bool); //! Used in MC-Rec, Ds Prompt or Non-Prompt DECLARE_SOA_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, bool); //! Used in MC-Rec, primary associated particles } // namespace hf_correlation_ds_hadron @@ -143,11 +245,13 @@ DECLARE_SOA_TABLE(DsHadronPair, "AOD", "DSHPAIR", //! Ds-Hadrons pairs Informati DECLARE_SOA_TABLE(DsHadronRecoInfo, "AOD", "DSHRECOINFO", //! Ds-Hadrons pairs Reconstructed Information aod::hf_correlation_ds_hadron::MD, - aod::hf_correlation_ds_hadron::IsSignal); + aod::hf_correlation_ds_hadron::IsSignal, + aod::hf_correlation_ds_hadron::IsDecayChan); DECLARE_SOA_TABLE(DsHadronGenInfo, "AOD", "DSHGENINFO", //! Ds-Hadrons pairs Generated Information aod::hf_correlation_ds_hadron::IsPrompt, - aod::hf_correlation_ds_hadron::IsPhysicalPrimary); + aod::hf_correlation_ds_hadron::IsPhysicalPrimary, + aod::hf_correlation_ds_hadron::TrackOrigin); DECLARE_SOA_TABLE(DsHadronMlInfo, "AOD", "DSHMLINFO", //! Ds-Hadrons pairs Machine Learning Information aod::hf_correlation_ds_hadron::MlScorePrompt, @@ -159,11 +263,35 @@ DECLARE_SOA_TABLE(DsCandRecoInfo, "AOD", "DSCANDRECOINFO", //! Ds candidates Rec aod::hf_correlation_ds_hadron::MlScorePrompt, aod::hf_correlation_ds_hadron::MlScoreBkg); +DECLARE_SOA_TABLE(DsCandGenInfo, "AOD", "DSCANDGENOINFO", //! Ds candidates Generated Information + aod::hf_correlation_ds_hadron::IsPrompt); + DECLARE_SOA_TABLE(TrackRecoInfo, "AOD", "TRACKRECOINFO", //! Tracks Reconstructed Information aod::hf_correlation_ds_hadron::TrackDcaXY, aod::hf_correlation_ds_hadron::TrackDcaZ, aod::hf_correlation_ds_hadron::TrackTPCNClsCrossedRows); +// definition of columns and tables for LambdaC properties +namespace hf_lc_baryon +{ +DECLARE_SOA_COLUMN(Phi, phi, float); //! Phi of Lc +DECLARE_SOA_COLUMN(Eta, eta, float); //! Eta of Lc +DECLARE_SOA_COLUMN(PtLc, ptLc, float); //! Transverse momentum of Lc +DECLARE_SOA_COLUMN(MLc, mLc, float); //! Invariant mass of Lc +DECLARE_SOA_COLUMN(PoolBin, poolBin, int); //! Pool Bin of event defined using zvtx and multiplicity +DECLARE_SOA_COLUMN(GIndexCol, gIndexCol, int); //! Global index for the collision +DECLARE_SOA_COLUMN(TimeStamp, timeStamp, int64_t); //! Timestamp for the collision +} // namespace hf_lc_baryon + +DECLARE_SOA_TABLE(Lc, "AOD", "LC", //! Lc properties + aod::hf_lc_baryon::Phi, + aod::hf_lc_baryon::Eta, + aod::hf_lc_baryon::PtLc, + aod::hf_lc_baryon::MLc, + aod::hf_lc_baryon::PoolBin, + aod::hf_lc_baryon::GIndexCol, + aod::hf_lc_baryon::TimeStamp); + // definition of columns and tables for Dplus properties namespace hf_dplus_meson { @@ -207,13 +335,23 @@ DECLARE_SOA_TABLE(Hadron, "AOD", "HADRON", //! Associated hadron properties // definition of columns and tables for Dplus-Hadron correlation pairs namespace hf_correlation_dplus_hadron { -DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); //! DeltaPhi between D+ and Hadrons -DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); //! DeltaEta between D+ and Hadrons -DECLARE_SOA_COLUMN(PtD, ptD, float); //! Transverse momentum of D+ -DECLARE_SOA_COLUMN(PtHadron, ptHadron, float); //! Transverse momentum of Hadron -DECLARE_SOA_COLUMN(MD, mD, float); //! Invariant mass of D+ -DECLARE_SOA_COLUMN(SignalStatus, signalStatus, bool); //! Used in MC-Rec, D+ Signal -DECLARE_SOA_COLUMN(PoolBin, poolBin, int); //! Pool Bin of event defined using zvtx and multiplicity +DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); //! DeltaPhi between D+ and Hadrons +DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); //! DeltaEta between D+ and Hadrons +DECLARE_SOA_COLUMN(PtD, ptD, float); //! Transverse momentum of D+ +DECLARE_SOA_COLUMN(PtHadron, ptHadron, float); //! Transverse momentum of Hadron +DECLARE_SOA_COLUMN(MD, mD, float); //! Invariant mass of D+ +DECLARE_SOA_COLUMN(MlScoreBkg, mlScoreBkg, float); //! ML background score for D+ selection +DECLARE_SOA_COLUMN(MlScorePrompt, mlScorePrompt, float); //! ML prompt score for D+ selection +DECLARE_SOA_COLUMN(SignalStatus, signalStatus, bool); //! Used in MC-Rec, D+ Signal +DECLARE_SOA_COLUMN(PoolBin, poolBin, int); //! Pool Bin of event defined using zvtx and multiplicity +DECLARE_SOA_COLUMN(TrackDcaXY, trackDcaXY, float); //! DCA xy of the track +DECLARE_SOA_COLUMN(TrackDcaZ, trackDcaZ, float); //! DCA z of the track +DECLARE_SOA_COLUMN(TrackTPCNClsCrossedRows, trackTPCNClsCrossedRows, int); //! Number of crossed TPC Rows +DECLARE_SOA_COLUMN(TrackOrigin, trackOrigin, int); //! Number of crossed TPC Rows +DECLARE_SOA_COLUMN(IsSignal, isSignal, bool); //! Used in MC-Rec, D+ Signal +DECLARE_SOA_COLUMN(IsDecayChan, isDecayChan, bool); //! Used in MC-Rec, D+ decay channel check +DECLARE_SOA_COLUMN(IsPrompt, isPrompt, bool); //! Used in MC-Rec, D+ Prompt or Non-Prompt +DECLARE_SOA_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, bool); //! Used in MC-Rec, primary associated particles } // namespace hf_correlation_dplus_hadron DECLARE_SOA_TABLE(DplusHadronPair, "AOD", "DPLUSHPAIR", //! D+-Hadrons pairs Informations @@ -227,12 +365,37 @@ DECLARE_SOA_TABLE(DplusHadronRecoInfo, "AOD", "DPLUSHRECOINFO", //! D+-Hadrons p aod::hf_correlation_dplus_hadron::MD, aod::hf_correlation_dplus_hadron::SignalStatus); +DECLARE_SOA_TABLE(DplusHadronGenInfo, "AOD", "DPLUSHGENINFO", //! Ds-Hadrons pairs Generated Information + aod::hf_correlation_dplus_hadron::IsPrompt, + aod::hf_correlation_dplus_hadron::IsPhysicalPrimary, + aod::hf_correlation_dplus_hadron::TrackOrigin); + +DECLARE_SOA_TABLE(DplusHadronMlInfo, "AOD", "DPLUSHMLINFO", //! D+-Hadrons pairs Machine Learning Information + aod::hf_correlation_dplus_hadron::MlScoreBkg, + aod::hf_correlation_dplus_hadron::MlScorePrompt); + +DECLARE_SOA_TABLE(DplusRecoInfo, "AOD", "DPLUSRECOINFO", //! D+ candidates Reconstructed Information + aod::hf_correlation_dplus_hadron::MD, + aod::hf_correlation_dplus_hadron::PtD, + aod::hf_correlation_dplus_hadron::MlScoreBkg, + aod::hf_correlation_dplus_hadron::MlScorePrompt); + +DECLARE_SOA_TABLE(DplusGenInfo, "AOD", "DPLUSGENOINFO", //! D+ candidates Generated Information + aod::hf_correlation_dplus_hadron::IsPrompt); + +DECLARE_SOA_TABLE(TrkRecInfoDplus, "AOD", "TRKRECINFODPLUS", //! Tracks Reconstructed Information + aod::hf_correlation_dplus_hadron::TrackDcaXY, + aod::hf_correlation_dplus_hadron::TrackDcaZ, + aod::hf_correlation_dplus_hadron::TrackTPCNClsCrossedRows); + // definition of columns and tables for Dstar-Hadron correlation pair namespace hf_correlation_dstar_hadron { -DECLARE_SOA_INDEX_COLUMN(Collision, collision); +DECLARE_SOA_INDEX_COLUMN(Collision, collision); // used in pair table for indexing +DECLARE_SOA_COLUMN(CollisionIdx, collisionIdx, int); // used in Dstar table for indexing // Dstar candidate properties -DECLARE_SOA_INDEX_COLUMN(HfCandDstar, hfCandDstar); +DECLARE_SOA_INDEX_COLUMN(HfCandDstar, hfCandDstar); // used in pair table for indexing +DECLARE_SOA_COLUMN(HfCandDstarIdx, hfCandDstarIdx, int); // used in Dstar table for indexing DECLARE_SOA_COLUMN(PhiDstar, phiDstar, float); DECLARE_SOA_COLUMN(EtaDstar, etaDstar, float); DECLARE_SOA_COLUMN(PtDstar, ptDstar, float); @@ -276,6 +439,18 @@ DECLARE_SOA_TABLE(DstarHadronPair, "AOD", "DSTRHPAIR", // D* Hadrons pairs Infor hf_correlation_dstar_hadron::DeltaEta, hf_correlation_dstar_hadron::DeltaM); +DECLARE_SOA_TABLE(Dstar, "AOD", "DSTAR", // Only Dstar properties + hf_correlation_dstar_hadron::CollisionIdx, + // D* only properties + hf_correlation_dstar_hadron::HfCandDstarIdx, + hf_correlation_dstar_hadron::PhiDstar, + hf_correlation_dstar_hadron::EtaDstar, + hf_correlation_dstar_hadron::PtDstar, + hf_correlation_dstar_hadron::MDstar, + hf_correlation_dstar_hadron::MD0, + hf_correlation_dstar_hadron::TimeStamp, + hf_correlation_dstar_hadron::PoolBin); + // Note: Table for selection of Lc in a collision namespace hf_selection_lc_collision { @@ -293,6 +468,45 @@ DECLARE_SOA_COLUMN(DmesonSel, dmesonSel, bool); //! Selection flag for D meson i DECLARE_SOA_TABLE(DmesonSelection, "AOD", "DINCOLL", // Selection of D meson in collisions aod::hf_selection_dmeson_collision::DmesonSel); + +// Note: definition of columns and tables for Electron Hadron correlation pairs +namespace hf_correlation_electron_hadron +{ +DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); //! DeltaPhi between Electron and Hadrons +DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); //! DeltaEta between Electron and Hadrons +DECLARE_SOA_COLUMN(PtElectron, ptElectron, float); //! Transverse momentum of Electron +DECLARE_SOA_COLUMN(PtHadron, ptHadron, float); //! Transverse momentum of Hadron; +DECLARE_SOA_COLUMN(PoolBin, poolBin, int); //! Pool Bin of event defined using zvtx and multiplicity +DECLARE_SOA_COLUMN(IsLSEHCorr, isLSEHCorr, int); //! like sign Electron hadron coorelation +DECLARE_SOA_COLUMN(IsULSEHCorr, isULSEHCorr, int); //! unLike sign Electron hadron coorelation +} // namespace hf_correlation_electron_hadron +DECLARE_SOA_TABLE(HfEHadronPair, "AOD", "HFEHADRONPAIR", //! Hfe-Hadrons pairs Informations + hf_correlation_electron_hadron::DeltaPhi, + hf_correlation_electron_hadron::DeltaEta, + hf_correlation_electron_hadron::PtElectron, + hf_correlation_electron_hadron::PtHadron, + hf_correlation_electron_hadron::PoolBin, + hf_correlation_electron_hadron::IsLSEHCorr, + hf_correlation_electron_hadron::IsULSEHCorr); + +// Note: definition of columns and tables for Electron Hadron correlation pairs for MC Gen +namespace hf_correlation_mcgenelectron_hadron +{ +DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); //! DeltaPhi between Electron and Hadrons +DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); //! DeltaEta between Electron and Hadrons +DECLARE_SOA_COLUMN(PtElectron, ptElectron, float); //! Transverse momentum of Electron +DECLARE_SOA_COLUMN(PtHadron, ptHadron, float); //! Transverse momentum of Hadron; +DECLARE_SOA_COLUMN(PoolBin, poolBin, int); //! Pool Bin of event defined using zvtx and multiplicity +DECLARE_SOA_COLUMN(IsNonHfEHCorr, isNonHfEHCorr, int); //! nonHeavy Flavour Electron hadron coorelation + +} // namespace hf_correlation_mcgenelectron_hadron +DECLARE_SOA_TABLE(HfEHadronMcPair, "AOD", "HFEHADRONMCPAIR", //! Hfe-Hadrons pairs Informations + hf_correlation_mcgenelectron_hadron::DeltaPhi, + hf_correlation_mcgenelectron_hadron::DeltaEta, + hf_correlation_mcgenelectron_hadron::PtElectron, + hf_correlation_mcgenelectron_hadron::PtHadron, + hf_correlation_mcgenelectron_hadron::PoolBin, + hf_correlation_mcgenelectron_hadron::IsNonHfEHCorr); } // namespace o2::aod #endif // PWGHF_HFC_DATAMODEL_CORRELATIONTABLES_H_ diff --git a/PWGHF/HFC/DataModel/DMesonPairsTables.h b/PWGHF/HFC/DataModel/DMesonPairsTables.h index bb149169d19..9ba4d72c78b 100644 --- a/PWGHF/HFC/DataModel/DMesonPairsTables.h +++ b/PWGHF/HFC/DataModel/DMesonPairsTables.h @@ -17,6 +17,8 @@ #ifndef PWGHF_HFC_DATAMODEL_DMESONPAIRSTABLES_H_ #define PWGHF_HFC_DATAMODEL_DMESONPAIRSTABLES_H_ +#include + #include "Framework/AnalysisDataModel.h" namespace o2::aod @@ -25,10 +27,12 @@ namespace o2::aod namespace hf_correlation_d_meson_pair { // Kinematic info -DECLARE_SOA_COLUMN(PtCand1, ptCand1, float); //! Transverse momentum of first candidate -DECLARE_SOA_COLUMN(PtCand2, ptCand2, float); //! Transverse momentum of second candidate -DECLARE_SOA_COLUMN(YCand1, yCand1, float); //! Rapidity of first candidate -DECLARE_SOA_COLUMN(YCand2, yCand2, float); //! Rapidity of second candidate +DECLARE_SOA_COLUMN(PtCand1, ptCand1, float); //! Transverse momentum of first candidate +DECLARE_SOA_COLUMN(PtCand2, ptCand2, float); //! Transverse momentum of second candidate +DECLARE_SOA_COLUMN(YCand1, yCand1, float); //! Rapidity of first candidate +DECLARE_SOA_COLUMN(YCand2, yCand2, float); //! Rapidity of second candidate +DECLARE_SOA_COLUMN(PhiCand1, phiCand1, float); //! Azimuthal angle of first candidate +DECLARE_SOA_COLUMN(PhiCand2, phiCand2, float); //! Azimuthal angle of second candidate // Invariant mass DECLARE_SOA_COLUMN(MDCand1, mDCand1, float); //! Invariant mass of first candidate as D DECLARE_SOA_COLUMN(MDbarCand1, mDbarCand1, float); //! Invariant mass of first candidate as Dbar @@ -42,6 +46,11 @@ DECLARE_SOA_COLUMN(Origin1, origin1, uint8_t); //! candidate 1 origin DECLARE_SOA_COLUMN(Origin2, origin2, uint8_t); //! candidate 2 origin DECLARE_SOA_COLUMN(MatchedMc1, matchedMc1, uint8_t); //! MC matching of candidate 1 DECLARE_SOA_COLUMN(MatchedMc2, matchedMc2, uint8_t); //! MC matching of candidate 2 +// ML info +DECLARE_SOA_COLUMN(MlProbD0Cand1, mlProbD0Cand1, std::vector); //! +DECLARE_SOA_COLUMN(MlProbD0barCand1, mlProbD0barCand1, std::vector); //! +DECLARE_SOA_COLUMN(MlProbD0Cand2, mlProbD0Cand2, std::vector); //! +DECLARE_SOA_COLUMN(MlProbD0barCand2, mlProbD0barCand2, std::vector); //! } // namespace hf_correlation_d_meson_pair // Definition of the D meson pair table. Contains the info needed at Data level. @@ -51,6 +60,8 @@ DECLARE_SOA_COLUMN(MatchedMc2, matchedMc2, uint8_t); //! MC matching of candidat hf_correlation_d_meson_pair::PtCand2, \ hf_correlation_d_meson_pair::YCand1, \ hf_correlation_d_meson_pair::YCand2, \ + hf_correlation_d_meson_pair::PhiCand1, \ + hf_correlation_d_meson_pair::PhiCand2, \ hf_correlation_d_meson_pair::MDCand1, \ hf_correlation_d_meson_pair::MDbarCand1, \ hf_correlation_d_meson_pair::MDCand2, \ @@ -65,10 +76,18 @@ DECLARE_SOA_COLUMN(MatchedMc2, matchedMc2, uint8_t); //! MC matching of candidat hf_correlation_d_meson_pair::Origin2, \ hf_correlation_d_meson_pair::MatchedMc1, \ hf_correlation_d_meson_pair::MatchedMc2); +// Definition of the table with the ML info of the D meson pair. +#define DECLARE_DMESON_PAIR_MLINFO_TABLE(_pair_type_, _marker_value_, _description_) \ + DECLARE_SOA_TABLE(_pair_type_, "AOD", _description_ "ML", o2::soa::Marker<_marker_value_>, \ + hf_correlation_d_meson_pair::MlProbD0Cand1, \ + hf_correlation_d_meson_pair::MlProbD0barCand1, \ + hf_correlation_d_meson_pair::MlProbD0Cand2, \ + hf_correlation_d_meson_pair::MlProbD0barCand2); // Creation of tables with D Meson Pairs info DECLARE_DMESON_PAIR_TABLE(D0Pair, 1, "D0PAIR"); //! D0 pairs Info DECLARE_DMESON_PAIR_MCINFO_TABLE(D0PairMcInfo, 1, "D0PAIR"); //! D0 pairs MC Rec Info +DECLARE_DMESON_PAIR_MLINFO_TABLE(D0PairMl, 1, "D0PAIR"); //! D0 pairs ML Info DECLARE_DMESON_PAIR_TABLE(D0PairMcGen, 2, "D0PAIRGEN"); //! D0 pairs MC Gen Kinematic Info DECLARE_DMESON_PAIR_MCINFO_TABLE(D0PairMcGenInfo, 2, "D0PAIRGEN"); //! D0 pairs MC Gen Info diff --git a/PWGHF/HFC/DataModel/DerivedDataCorrelationTables.h b/PWGHF/HFC/DataModel/DerivedDataCorrelationTables.h new file mode 100644 index 00000000000..9e99e6ab011 --- /dev/null +++ b/PWGHF/HFC/DataModel/DerivedDataCorrelationTables.h @@ -0,0 +1,100 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file DerivedDataCorrelationTables.h +/// \brief Tables for producing derived data for correlation analysis +/// \author Samuele Cattaruzzi + +#ifndef PWGHF_HFC_DATAMODEL_DERIVEDDATACORRELATIONTABLES_H_ +#define PWGHF_HFC_DATAMODEL_DERIVEDDATACORRELATIONTABLES_H_ + +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace hf_collisions_reduced +{ +DECLARE_SOA_COLUMN(Multiplicity, multiplicity, float); //! Event multiplicity +DECLARE_SOA_COLUMN(PosZ, posZ, float); //! Primary vertex z position + +} // namespace hf_collisions_reduced + +DECLARE_SOA_TABLE(HfcRedCollisions, "AOD", "HFCREDCOLLISION", //! Table with collision info + soa::Index<>, + aod::hf_collisions_reduced::Multiplicity, + aod::hf_collisions_reduced::PosZ); + +using HfcRedCollision = HfcRedCollisions::iterator; + +// DECLARE_SOA_TABLE(HfCandColCounts, "AOD", "HFCANDCOLCOUNT", //! Table with number of collisions which contain at least one candidate +// aod::hf_collisions_reduced::OriginalCollisionCount); + +namespace hf_candidate_reduced +{ +DECLARE_SOA_INDEX_COLUMN(HfcRedCollision, hfcRedCollision); //! ReducedCollision index +DECLARE_SOA_COLUMN(Prong0Id, prong0Id, int); //! Prong 0 index +DECLARE_SOA_COLUMN(Prong1Id, prong1Id, int); //! Prong 1 index +DECLARE_SOA_COLUMN(Prong2Id, prong2Id, int); //! Prong2 index +DECLARE_SOA_COLUMN(PhiCand, phiCand, float); //! Phi of the candidate +DECLARE_SOA_COLUMN(EtaCand, etaCand, float); //! Eta of the candidate +DECLARE_SOA_COLUMN(PtCand, ptCand, float); //! Pt of the candidate +DECLARE_SOA_COLUMN(InvMassDs, invMassDs, float); //! Invariant mass of Ds candidate +DECLARE_SOA_COLUMN(BdtScorePrompt, bdtScorePrompt, float); //! BDT output score for prompt hypothesis +DECLARE_SOA_COLUMN(BdtScoreBkg, bdtScoreBkg, float); //! BDT output score for backgronud hypothesis +} // namespace hf_candidate_reduced +DECLARE_SOA_TABLE(DsCandReduceds, "AOD", "DSCANDREDUCED", //! Table with Ds candidate info + soa::Index<>, + aod::hf_candidate_reduced::HfcRedCollisionId, + aod::hf_candidate_reduced::PhiCand, + aod::hf_candidate_reduced::EtaCand, + aod::hf_candidate_reduced::PtCand, + aod::hf_candidate_reduced::InvMassDs, + aod::hf_candidate_reduced::Prong0Id, + aod::hf_candidate_reduced::Prong1Id, + aod::hf_candidate_reduced::Prong2Id); + +DECLARE_SOA_TABLE(DsCandSelInfos, "AOD", "DSCANDSELINFO", //! Table with Ds candidate selection info + soa::Index<>, + aod::hf_candidate_reduced::HfcRedCollisionId, + aod::hf_candidate_reduced::BdtScorePrompt, + aod::hf_candidate_reduced::BdtScoreBkg); + +namespace hf_assoc_track_reduced +{ +DECLARE_SOA_COLUMN(OriginTrackId, originTrackId, int); //! Original track index +DECLARE_SOA_COLUMN(NTpcCrossedRows, nTpcCrossedRows, int); //! Number of crossed TPC Rows +DECLARE_SOA_COLUMN(ItsClusterMap, itsClusterMap, int); //! ITS cluster map, one bit per a layer, starting from the innermost +DECLARE_SOA_COLUMN(ItsNCls, itsNCls, int); //! Number of ITS clusters +DECLARE_SOA_COLUMN(EtaAssocTrack, etaAssocTrack, float); //! Eta of the track +DECLARE_SOA_COLUMN(PhiAssocTrack, phiAssocTrack, float); //! Phi of the track +DECLARE_SOA_COLUMN(PtAssocTrack, ptAssocTrack, float); //! Pt of the track +DECLARE_SOA_COLUMN(DcaXY, dcaXY, float); //! Impact parameter in XY of the track to the primary vertex +DECLARE_SOA_COLUMN(DcaZ, dcaZ, float); //! Impact parameter in Z of the track to the primary vertex +} // namespace hf_assoc_track_reduced +DECLARE_SOA_TABLE(AssocTrackReds, "AOD", "ASSOCTRACKRED", //! Table with associated track info + soa::Index<>, + aod::hf_candidate_reduced::HfcRedCollisionId, + aod::hf_assoc_track_reduced::OriginTrackId, + aod::hf_assoc_track_reduced::PhiAssocTrack, + aod::hf_assoc_track_reduced::EtaAssocTrack, + aod::hf_assoc_track_reduced::PtAssocTrack); + +DECLARE_SOA_TABLE(AssocTrackSels, "AOD", "ASSOCTRACKSEL", //! Table with associated track info + soa::Index<>, + aod::hf_candidate_reduced::HfcRedCollisionId, + aod::hf_assoc_track_reduced::NTpcCrossedRows, + aod::hf_assoc_track_reduced::ItsClusterMap, + aod::hf_assoc_track_reduced::ItsNCls, + aod::hf_assoc_track_reduced::DcaXY, + aod::hf_assoc_track_reduced::DcaZ) +} // namespace o2::aod + +#endif // PWGHF_HFC_DATAMODEL_DERIVEDDATACORRELATIONTABLES_H_ diff --git a/PWGHF/HFC/Macros/DhCorrelationExtraction.cxx b/PWGHF/HFC/Macros/DhCorrelationExtraction.cxx index 2c222fe5982..446dcfbe4a0 100644 --- a/PWGHF/HFC/Macros/DhCorrelationExtraction.cxx +++ b/PWGHF/HFC/Macros/DhCorrelationExtraction.cxx @@ -16,6 +16,9 @@ #include "DhCorrelationExtraction.h" +#include +#include + DhCorrelationExtraction::DhCorrelationExtraction() : // default constructor fFileMass(0x0), fFileSE(0x0), diff --git a/PWGHF/HFC/Macros/DhCorrelationFitter.cxx b/PWGHF/HFC/Macros/DhCorrelationFitter.cxx index d203c6ee63f..7e5157bb752 100644 --- a/PWGHF/HFC/Macros/DhCorrelationFitter.cxx +++ b/PWGHF/HFC/Macros/DhCorrelationFitter.cxx @@ -14,6 +14,12 @@ /// \author Samuele Cattaruzzi /// \author Swapnesh Santosh Khade +#include "DhCorrelationFitter.h" + +#include +#include +#include + #include #include #include @@ -34,10 +40,10 @@ #include #include #include -#include #include #include -#include "DhCorrelationFitter.h" + +using namespace std; DhCorrelationFitter::DhCorrelationFitter() : // default constructor fIsReflected(kFALSE), diff --git a/PWGHF/HFC/Macros/DhCorrelationFitter.h b/PWGHF/HFC/Macros/DhCorrelationFitter.h index 83734f44257..3832b67b645 100644 --- a/PWGHF/HFC/Macros/DhCorrelationFitter.h +++ b/PWGHF/HFC/Macros/DhCorrelationFitter.h @@ -17,6 +17,8 @@ #ifndef PWGHF_HFC_MACROS_DHCORRELATIONFITTER_H_ #define PWGHF_HFC_MACROS_DHCORRELATIONFITTER_H_ +#include + #include #include #include diff --git a/PWGHF/HFC/Macros/ExtractOutputCorrel.C b/PWGHF/HFC/Macros/ExtractOutputCorrel.C index f13116bffd6..301434f66e2 100644 --- a/PWGHF/HFC/Macros/ExtractOutputCorrel.C +++ b/PWGHF/HFC/Macros/ExtractOutputCorrel.C @@ -26,7 +26,7 @@ using namespace rapidjson; template -void readArray(const Value& jsonArray, vector& output) +void readArray(const Value& jsonArray, std::vector& output) { for (auto it = jsonArray.Begin(); it != jsonArray.End(); it++) { auto value = it->template Get(); @@ -34,7 +34,7 @@ void readArray(const Value& jsonArray, vector& output) } } -void parseStringArray(const Value& jsonArray, vector& output) +void parseStringArray(const Value& jsonArray, std::vector& output) { size_t arrayLength = jsonArray.Size(); for (size_t i = 0; i < arrayLength; i++) { @@ -45,7 +45,7 @@ void parseStringArray(const Value& jsonArray, vector& output) } void SetInputCorrelNames(DhCorrelationExtraction* plotter, TString pathFileMass, TString pathFileSE, TString pathFileME, TString dirSE, TString dirME, TString histoNameCorrSignal, TString histoNameCorrSideba); -void SetInputHistoInvMassNames(DhCorrelationExtraction* plotter, vector inputMassNames); +void SetInputHistoInvMassNames(DhCorrelationExtraction* plotter, std::vector inputMassNames); void ExtractOutputCorrel(TString cfgFileName = "config_CorrAnalysis.json") { @@ -185,7 +185,7 @@ void SetInputCorrelNames(DhCorrelationExtraction* plotter, TString pathFileMass, return; } -void SetInputHistoInvMassNames(DhCorrelationExtraction* plotter, vector inputMassNames) +void SetInputHistoInvMassNames(DhCorrelationExtraction* plotter, std::vector inputMassNames) { // to use if sgn and bkg extraction is done apart plotter->SetMassHistoNameSgn(inputMassNames[0].data()); diff --git a/PWGHF/HFC/Macros/FitCorrel.C b/PWGHF/HFC/Macros/FitCorrel.C index 591933112c6..37b36a5e1b3 100644 --- a/PWGHF/HFC/Macros/FitCorrel.C +++ b/PWGHF/HFC/Macros/FitCorrel.C @@ -31,7 +31,7 @@ using namespace rapidjson; template -void readArray(const Value& jsonArray, vector& output) +void readArray(const Value& jsonArray, std::vector& output) { for (auto it = jsonArray.Begin(); it != jsonArray.End(); it++) { auto value = it->template Get(); diff --git a/PWGHF/HFC/TableProducer/CMakeLists.txt b/PWGHF/HFC/TableProducer/CMakeLists.txt index f2291cf6ef4..5d9a5d8d9a7 100644 --- a/PWGHF/HFC/TableProducer/CMakeLists.txt +++ b/PWGHF/HFC/TableProducer/CMakeLists.txt @@ -26,7 +26,7 @@ o2physics_add_dpl_workflow(correlator-d0-hadrons o2physics_add_dpl_workflow(correlator-d-meson-pairs SOURCES correlatorDMesonPairs.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(correlator-dplus-dminus @@ -44,13 +44,27 @@ o2physics_add_dpl_workflow(correlator-ds-hadrons PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(correlator-ds-hadrons-reduced + SOURCES correlatorDsHadronsReduced.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(correlator-dstar-hadrons SOURCES correlatorDstarHadrons.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(correlator-hfe-hadrons + SOURCES correlatorHfeHadrons.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(correlator-lc-hadrons SOURCES correlatorLcHadrons.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-dream-producer + SOURCES femtoDreamProducer.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) diff --git a/PWGHF/HFC/TableProducer/correlatorD0D0bar.cxx b/PWGHF/HFC/TableProducer/correlatorD0D0bar.cxx index d51ded0baa4..294e34db2c7 100644 --- a/PWGHF/HFC/TableProducer/correlatorD0D0bar.cxx +++ b/PWGHF/HFC/TableProducer/correlatorD0D0bar.cxx @@ -14,6 +14,8 @@ /// /// \author Fabio Colamaria , INFN Bari +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" @@ -48,7 +50,7 @@ const double incrementEtaCut = 0.1; const double incrementPtThreshold = 0.5; const double epsilon = 1E-5; -const int npTBinsMassAndEfficiency = o2::analysis::hf_cuts_d0_to_pi_k::nBinsPt; +const int npTBinsMassAndEfficiency = o2::analysis::hf_cuts_d0_to_pi_k::NBinsPt; const double efficiencyDmesonDefault[npTBinsMassAndEfficiency] = {}; auto efficiencyDmeson_v = std::vector{efficiencyDmesonDefault, efficiencyDmesonDefault + npTBinsMassAndEfficiency}; @@ -304,7 +306,7 @@ struct HfCorrelatorD0D0bar { registry.fill(HIST("hSelectionStatusMCRec"), candidate1.isSelD0bar() + (candidate1.isSelD0() * 2)); } // fill invariant mass plots from D0/D0bar signal and background candidates - if (candidate1.isSelD0() >= selectionFlagD0) { // only reco as D0 + if (candidate1.isSelD0() >= selectionFlagD0) { // only reco as D0 if (candidate1.flagMcMatchRec() == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { // also matched as D0 registry.fill(HIST("hMassD0MCRecSig"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); } else if (candidate1.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { @@ -313,7 +315,7 @@ struct HfCorrelatorD0D0bar { registry.fill(HIST("hMassD0MCRecBkg"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); } } - if (candidate1.isSelD0bar() >= selectionFlagD0bar) { // only reco as D0bar + if (candidate1.isSelD0bar() >= selectionFlagD0bar) { // only reco as D0bar if (candidate1.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { // also matched as D0bar registry.fill(HIST("hMassD0barMCRecSig"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); } else if (candidate1.flagMcMatchRec() == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { @@ -475,7 +477,7 @@ struct HfCorrelatorD0D0bar { } while (ptCut < ptThresholdForMaxEtaCut - epsilon); } while (etaCut < maxEtaCut - epsilon); } // end inner loop - } // end outer loop + } // end outer loop registry.fill(HIST("hCountD0D0barPerEvent"), counterD0D0bar); } @@ -540,8 +542,8 @@ struct HfCorrelatorD0D0bar { entryD0D0barRecoInfo(1.864, 1.864, 8); // dummy information - } // end inner loop - } // end outer loop + } // end inner loop + } // end outer loop registry.fill(HIST("hCountCCbarPerEvent"), counterCCbar); registry.fill(HIST("hCountCCbarPerEventBeforeEtaCut"), counterCCbarBeforeEtasel); } diff --git a/PWGHF/HFC/TableProducer/correlatorD0D0barBarrelFullPid.cxx b/PWGHF/HFC/TableProducer/correlatorD0D0barBarrelFullPid.cxx index 26522739841..f92f8150abc 100644 --- a/PWGHF/HFC/TableProducer/correlatorD0D0barBarrelFullPid.cxx +++ b/PWGHF/HFC/TableProducer/correlatorD0D0barBarrelFullPid.cxx @@ -14,6 +14,8 @@ /// /// \author Fabio Colamaria , INFN Bari +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" @@ -48,7 +50,7 @@ const double incrementEtaCut = 0.1; const double incrementPtThreshold = 0.5; const double epsilon = 1E-5; -const int npTBinsMassAndEfficiency = o2::analysis::hf_cuts_d0_to_pi_k::nBinsPt; +const int npTBinsMassAndEfficiency = o2::analysis::hf_cuts_d0_to_pi_k::NBinsPt; const double efficiencyDmesonDefault[npTBinsMassAndEfficiency] = {}; auto efficiencyDmeson_v = std::vector{efficiencyDmesonDefault, efficiencyDmesonDefault + npTBinsMassAndEfficiency}; @@ -305,7 +307,7 @@ struct HfCorrelatorD0D0barBarrelFullPid { registry.fill(HIST("hSelectionStatusMCRec"), candidate1.isSelD0barTofPlusRichPid() + (candidate1.isSelD0TofPlusRichPid() * 2)); } // fill invariant mass plots from D0/D0bar signal and background candidates - if (candidate1.isSelD0TofPlusRichPid() >= selectionFlagD0) { // only reco as D0 + if (candidate1.isSelD0TofPlusRichPid() >= selectionFlagD0) { // only reco as D0 if (candidate1.flagMcMatchRec() == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { // also matched as D0 registry.fill(HIST("hMassD0MCRecSig"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); } else if (candidate1.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { @@ -314,7 +316,7 @@ struct HfCorrelatorD0D0barBarrelFullPid { registry.fill(HIST("hMassD0MCRecBkg"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); } } - if (candidate1.isSelD0barTofPlusRichPid() >= selectionFlagD0bar) { // only reco as D0bar + if (candidate1.isSelD0barTofPlusRichPid() >= selectionFlagD0bar) { // only reco as D0bar if (candidate1.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { // also matched as D0bar registry.fill(HIST("hMassD0barMCRecSig"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); } else if (candidate1.flagMcMatchRec() == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { @@ -476,7 +478,7 @@ struct HfCorrelatorD0D0barBarrelFullPid { } while (ptCut < ptThresholdForMaxEtaCut - epsilon); } while (etaCut < maxEtaCut - epsilon); } // end inner loop - } // end outer loop + } // end outer loop registry.fill(HIST("hCountD0D0barPerEvent"), counterD0D0bar); } @@ -541,8 +543,8 @@ struct HfCorrelatorD0D0barBarrelFullPid { entryD0D0barRecoInfo(1.864, 1.864, 8); // dummy information - } // end inner loop - } // end outer loop + } // end inner loop + } // end outer loop registry.fill(HIST("hCountCCbarPerEvent"), counterCCbar); registry.fill(HIST("hCountCCbarPerEventBeforeEtaCut"), counterCCbarBeforeEtasel); } diff --git a/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx b/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx index 6df44ae66c6..7b6517f29dc 100644 --- a/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx @@ -15,26 +15,31 @@ /// \author Samrangy Sadhu , INFN Bari /// \author Swapnesh Santosh Khade , IIT Indore +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/HFC/Utils/utilsCorrelations.h" using namespace o2; using namespace o2::analysis; using namespace o2::constants::physics; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::analysis::hf_correlations; /// /// Returns deltaPhi value in range [-pi/2., 3.*pi/2], typically used for correlation studies @@ -44,199 +49,194 @@ double getDeltaPhi(double phiHadron, double phiD) return RecoDecay::constrainAngle(phiHadron - phiD, -o2::constants::math::PIHalf); } -const int nPtBinsMassAndEfficiency = o2::analysis::hf_cuts_d0_to_pi_k::nBinsPt; -const double efficiencyDmesonDefault[nPtBinsMassAndEfficiency] = {}; -auto vecEfficiencyDmeson = std::vector{efficiencyDmesonDefault, efficiencyDmesonDefault + nPtBinsMassAndEfficiency}; - -// histogram binning definition -const int massAxisNBins = 200; -const double massAxisMin = 1.3848; -const double massAxisMax = 2.3848; -const int phiAxisNBins = 32; -const double phiAxisMin = 0.; -const double phiAxisMax = o2::constants::math::TwoPI; -const int yAxisNBins = 100; -const double yAxisMin = -5.; -const double yAxisMax = 5.; -const int ptDAxisNBins = 180; -const double ptDAxisMin = 0.; -const double ptDAxisMax = 36.; - -// definition of ME variables and new types -std::vector zBins{VARIABLE_WIDTH, -10.0, -2.5, 2.5, 10.0}; -std::vector multBins{VARIABLE_WIDTH, 0., 200., 500.0, 5000.}; -std::vector multBinsMcGen{VARIABLE_WIDTH, 0., 20., 50.0, 500.}; // In MCGen multiplicity is defined by counting primaries -using BinningType = ColumnBinningPolicy>; -BinningType corrBinning{{zBins, multBins}, true}; - -using SelectedCollisions = soa::Filtered>; -using SelectedTracks = soa::Filtered; +// Types +using BinningType = ColumnBinningPolicy>; +using BinningTypeMcGen = ColumnBinningPolicy; +using SelectedCollisions = soa::Filtered>; +using SelectedTracks = soa::Filtered>; using SelectedCandidatesData = soa::Filtered>; +using SelectedCandidatesDataMl = soa::Filtered>; +using SelectedTracksMcRec = soa::Filtered>; using SelectedCandidatesMcRec = soa::Filtered>; -using SelectedCollisionsMcGen = soa::Filtered>; -using SelectedTracksMcGen = soa::Filtered; +using SelectedCandidatesMcRecMl = soa::Filtered>; +using SelectedCollisionsMcGen = soa::Filtered>; +using SelectedParticlesMcGen = soa::Join; // Code to select collisions with at least one D0 struct HfCorrelatorD0HadronsSelection { - SliceCache cache; - - Produces d0Sel; + Produces collisionsWithSelD0; + Configurable useSel8{"useSel8", true, "Flag for applying sel8 for collision selection"}; + Configurable selNoSameBunchPileUpColl{"selNoSameBunchPileUpColl", true, "Flag for rejecting the collisions associated with the same bunch crossing"}; Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection Flag for D0bar"}; Configurable yCandMax{"yCandMax", 4.0, "max. cand. rapidity"}; Configurable ptCandMin{"ptCandMin", -1., "min. cand. pT"}; HfHelper hfHelper; + SliceCache cache; + + using SelCollisions = soa::Join; Preslice perCol = aod::hf_cand::collisionId; + Partition> selectedD0Candidates = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlagD0 || aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlagD0bar; Partition> selectedD0candidatesMc = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlagD0 || aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlagD0bar; - void processD0SelectionData(aod::Collision const& collision, + void processD0SelectionData(SelCollisions::iterator const& collision, soa::Join const&) { - bool isD0Found = 0; + bool isSelColl = true; + bool isD0Found = true; + bool isSel8 = true; + bool isNosameBunchPileUp = true; if (selectedD0Candidates.size() > 0) { auto selectedD0CandidatesGrouped = selectedD0Candidates->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); - for (const auto& candidate1 : selectedD0CandidatesGrouped) { - // check decay channel flag for candidate1 - if (!TESTBIT(candidate1.hfflag(), aod::hf_cand_2prong::DecayType::D0ToPiK)) { - continue; - } - if (yCandMax >= 0. && std::abs(hfHelper.yD0(candidate1)) > yCandMax) { + for (const auto& candidate : selectedD0CandidatesGrouped) { + // check decay channel flag for candidate + if (!TESTBIT(candidate.hfflag(), aod::hf_cand_2prong::DecayType::D0ToPiK)) { + isD0Found = false; continue; } - if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { + if (std::abs(hfHelper.yD0(candidate)) > yCandMax || candidate.pt() < ptCandMin) { + isD0Found = false; continue; } - isD0Found = 1; + isD0Found = true; + break; } } - d0Sel(isD0Found); + if (useSel8) { + isSel8 = false; + isSel8 = collision.sel8(); + } + if (selNoSameBunchPileUpColl) { + isNosameBunchPileUp = false; + isNosameBunchPileUp = static_cast(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)); + } + isSelColl = isD0Found && isSel8 && isNosameBunchPileUp; + collisionsWithSelD0(isSelColl); } PROCESS_SWITCH(HfCorrelatorD0HadronsSelection, processD0SelectionData, "Process D0 Selection Data", false); - void processD0SelectionMcRec(aod::Collision const& collision, + void processD0SelectionMcRec(SelCollisions::iterator const& collision, soa::Join const&) { - bool isD0Found = 0; + bool isSelColl = true; + bool isD0Found = true; + bool isSel8 = true; + bool isNosameBunchPileUp = true; if (selectedD0candidatesMc.size() > 0) { auto selectedD0CandidatesGroupedMc = selectedD0candidatesMc->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); - for (const auto& candidate1 : selectedD0CandidatesGroupedMc) { - // check decay channel flag for candidate1 - if (!TESTBIT(candidate1.hfflag(), aod::hf_cand_2prong::DecayType::D0ToPiK)) { + for (const auto& candidate : selectedD0CandidatesGroupedMc) { + // check decay channel flag for candidate + if (!TESTBIT(candidate.hfflag(), aod::hf_cand_2prong::DecayType::D0ToPiK)) { + isD0Found = false; continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yD0(candidate1)) > yCandMax) { + if (std::abs(hfHelper.yD0(candidate)) > yCandMax || candidate.pt() < ptCandMin) { + isD0Found = false; continue; } - if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { - continue; - } - isD0Found = 1; + isD0Found = true; + break; } } - d0Sel(isD0Found); + if (useSel8) { + isSel8 = collision.sel8(); + } + if (selNoSameBunchPileUpColl) { + isNosameBunchPileUp = static_cast(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)); + } + isSelColl = isD0Found && isSel8 && isNosameBunchPileUp; + collisionsWithSelD0(isSelColl); } PROCESS_SWITCH(HfCorrelatorD0HadronsSelection, processD0SelectionMcRec, "Process D0 Selection MCRec", true); void processD0SelectionMcGen(aod::McCollision const&, aod::McParticles const& mcParticles) { - bool isD0Found = 0; - for (const auto& particle1 : mcParticles) { - if (std::abs(particle1.pdgCode()) != Pdg::kD0) { - continue; - } - double yD = RecoDecay::y(particle1.pVector(), MassD0); - if (yCandMax >= 0. && std::abs(yD) > yCandMax) { + bool isD0Found = false; + for (const auto& particle : mcParticles) { + if (std::abs(particle.pdgCode()) != Pdg::kD0) { continue; } - if (ptCandMin >= 0. && particle1.pt() < ptCandMin) { + double yD = RecoDecay::y(particle.pVector(), MassD0); + if (std::abs(yD) > yCandMax || particle.pt() < ptCandMin) { continue; } - isD0Found = 1; + isD0Found = true; + break; } - d0Sel(isD0Found); + collisionsWithSelD0(isD0Found); } PROCESS_SWITCH(HfCorrelatorD0HadronsSelection, processD0SelectionMcGen, "Process D0 Selection MCGen", false); }; +/// D0-Hadron correlation pair builder - for real data and data-like analysis (i.e. reco-level w/o matching request via MC truth) struct HfCorrelatorD0Hadrons { - SliceCache cache; - - Produces entryD0HadronPair; - Produces entryD0HadronRecoInfo; + Produces entryD0HadronPair; + Produces entryD0HadronRecoInfo; + Produces entryD0HadronGenInfo; + Produces entryD0HadronMlInfo; + Produces entryD0CandRecoInfo; + Produces entryD0CandGenInfo; + Produces entryTrackRecoInfo; Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection Flag for D0bar"}; - Configurable yCandMax{"yCandMax", -1., "max. cand. rapidity"}; - Configurable etaTrackMax{"etaTrackMax", 4., "max. eta of tracks"}; - Configurable dcaXYTrackMax{"dcaXYTrackMax", 0.0025, "max. DCAxy of tracks"}; - Configurable dcaZTrackMax{"dcaZTrackMax", 0.0025, "max. DCAz of tracks"}; - Configurable ptCandMin{"ptCandMin", -1., "min. cand. pT"}; - Configurable ptTrackMin{"ptTrackMin", -1., "min. track pT"}; - Configurable> bins{"ptBinsForMassAndEfficiency", std::vector{o2::analysis::hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits for candidate mass plots and efficiency"}; - Configurable> efficiencyDmeson{"efficiencyDmeson", std::vector{vecEfficiencyDmeson}, "Efficiency values for D0 meson"}; - Configurable applyEfficiency{"efficiencyFlagD", 1, "Flag for applying D-meson efficiency weights"}; + Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity"}; + Configurable etaTrackMax{"etaTrackMax", 0.8, "max. eta of tracks"}; + Configurable dcaXYTrackMax{"dcaXYTrackMax", 1., "max. DCAxy of tracks"}; + Configurable dcaZTrackMax{"dcaZTrackMax", 1., "max. DCAz of tracks"}; + Configurable ptCandMin{"ptCandMin", 1., "min. cand. pT"}; + Configurable ptTrackMin{"ptTrackMin", 0.3, "min. track pT"}; + Configurable ptTrackMax{"ptTrackMax", 99., "max. track pT"}; + Configurable> binsPtD{"binsPtD", std::vector{o2::analysis::hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits for candidate mass plots"}; + Configurable> binsPtHadron{"binsPtHadron", std::vector{0.3, 2., 4., 8., 12., 50.}, "pT bin limits for assoc particle"}; + Configurable> binsPtEfficiencyD{"binsPtEfficiencyD", std::vector{o2::analysis::hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits for efficiency"}; + Configurable> efficiencyDmeson{"efficiencyDmeson", {1., 1., 1., 1., 1., 1.}, "Efficiency values for D0 meson"}; + Configurable applyEfficiency{"applyEfficiency", 1, "Flag for applying D-meson efficiency weights"}; Configurable multMin{"multMin", 0., "minimum multiplicity accepted"}; Configurable multMax{"multMax", 10000., "maximum multiplicity accepted"}; - Configurable ptSoftPionMax{"ptSoftPionMax", 3 * 800. * pow(10., -6.), "max. pT cut for soft pion identification"}; - - HfHelper hfHelper; + Configurable ptSoftPionMax{"ptSoftPionMax", 3.f * 800.f * std::pow(10.f, -6.f), "max. pT cut for soft pion identification"}; + Configurable> classMl{"classMl", {0, 1, 2}, "Indexes of ML scores to be stored. Three indexes max."}; + Configurable correlateD0WithLeadingParticle{"correlateD0WithLeadingParticle", false, "Switch for correlation of D0 mesons with leading particle only"}; + Configurable storeAutoCorrelationFlag{"storeAutoCorrelationFlag", false, "Store flag that indicates if the track is paired to its D-meson mother instead of skipping it"}; + Configurable numberEventsMixed{"numberEventsMixed", 5, "Number of events mixed in ME process"}; + int leadingIndex = 0; double massD0{0.}; double massPi{0.}; double massK{0.}; double softPiMass = 0.14543; // pion mass + Q-value of the D*->D0pi decay - Preslice perCol = aod::hf_cand::collisionId; - - Partition> selectedD0Candidates = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlagD0 || aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlagD0bar; - Partition> selectedD0candidatesMc = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlagD0 || aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlagD0bar; + HfHelper hfHelper; + SliceCache cache; - // Filters for ME Filter collisionFilter = aod::hf_selection_dmeson_collision::dmesonSel == true; - Filter trackFilter = (aod::track::eta > static_cast(-etaTrackMax)) && (aod::track::eta < static_cast(etaTrackMax)) && (aod::track::pt > static_cast(ptTrackMin)) && (aod::track::dcaXY > static_cast(-dcaXYTrackMax)) && (aod::track::dcaXY < static_cast(dcaXYTrackMax)) && - (aod::track::dcaZ > static_cast(-dcaZTrackMax)) && (aod::track::dcaZ < static_cast(dcaZTrackMax)); + Filter trackFilter = requireGlobalTrackWoDCAInFilter() && (nabs(aod::track::eta) < etaTrackMax) && (aod::track::pt > ptTrackMin) && (aod::track::pt < ptTrackMax) && (nabs(aod::track::dcaXY) < dcaXYTrackMax) && (nabs(aod::track::dcaZ) < dcaZTrackMax); Filter d0Filter = (aod::hf_sel_candidate_d0::isSelD0 >= 1) || (aod::hf_sel_candidate_d0::isSelD0bar >= 1); Filter collisionFilterGen = aod::hf_selection_dmeson_collision::dmesonSel == true; Filter particlesFilter = nabs(aod::mcparticle::pdgCode) == static_cast(Pdg::kD0) || ((aod::mcparticle::flags & (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary) == (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary); - HistogramRegistry registry{ - "registry", - // NOTE: use hMassD0 for trigger normalisation (S*0.955), and hMass2DCorrelationPairs (in final task) for 2D-sideband-subtraction purposes - {{"hPtCand", "D0,D0bar candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisNBins, ptDAxisMin, ptDAxisMax}}}}, - {"hPtProng0", "D0,D0bar candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisNBins, ptDAxisMin, ptDAxisMax}}}}, - {"hPtProng1", "D0,D0bar candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisNBins, ptDAxisMin, ptDAxisMax}}}}, - {"hSelectionStatus", "D0,D0bar candidates;selection status;entries", {HistType::kTH1F, {{4, -0.5, 3.5}}}}, - {"hEta", "D0,D0bar candidates;candidate #it{#eta};entries", {HistType::kTH1F, {{yAxisNBins, yAxisMin, yAxisMax}}}}, - {"hPhi", "D0,D0bar candidates;candidate #it{#varphi};entries", {HistType::kTH1F, {{phiAxisNBins, phiAxisMin, phiAxisMax}}}}, - {"hY", "D0,D0bar candidates;candidate #it{y};entries", {HistType::kTH1F, {{yAxisNBins, yAxisMin, yAxisMax}}}}, - {"hMultiplicityPreSelection", "multiplicity prior to selection;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}}, - {"hMultiplicity", "multiplicity;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}}, - {"hPtCandRec", "D0,D0bar candidates - MC reco;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisNBins, ptDAxisMin, ptDAxisMax}}}}, - {"hPtProng0Rec", "D0,D0bar candidates - MC reco;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisNBins, ptDAxisMin, ptDAxisMax}}}}, - {"hPtProng1Rec", "D0,D0bar candidates - MC reco;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisNBins, ptDAxisMin, ptDAxisMax}}}}, - {"hSelectionStatusRec", "D0,D0bar candidates - MC reco;selection status;entries", {HistType::kTH1F, {{4, -0.5, 3.5}}}}, - {"hSignalStatusMERec", "Signal Status - MC reco ME;candidate sidnalStatus;entries", {HistType::kTH1F, {{200, 0, 200}}}}, - {"hEtaRec", "D0,D0bar candidates - MC reco;candidate #it{#eta};entries", {HistType::kTH1F, {{yAxisNBins, yAxisMin, yAxisMax}}}}, - {"hPhiRec", "D0,D0bar candidates - MC reco;candidate #it{#varphi};entries", {HistType::kTH1F, {{phiAxisNBins, phiAxisMin, phiAxisMax}}}}, - {"hYRec", "D0,D0bar candidates - MC reco;candidate #it{y};entries", {HistType::kTH1F, {{yAxisNBins, yAxisMin, yAxisMax}}}}, - {"hEvtCountGen", "Event counter - MC gen;;entries", {HistType::kTH1F, {{1, -0.5, 0.5}}}}, - {"hPtCandGen", "D0,D0bar particles - MC gen;particle #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisNBins, ptDAxisMin, ptDAxisMax}}}}, - {"hEtaGen", "D0,D0bar particles - MC gen;particle #it{#eta};entries", {HistType::kTH1F, {{yAxisNBins, yAxisMin, yAxisMax}}}}, - {"hPhiGen", "D0,D0bar particles - MC gen;particle #it{#varphi};entries", {HistType::kTH1F, {{phiAxisNBins, phiAxisMin, phiAxisMax}}}}, - {"hYGen", "D0,D0bar candidates - MC gen;candidate #it{y};entries", {HistType::kTH1F, {{yAxisNBins, yAxisMin, yAxisMax}}}}, - {"hTrackCounter", "soft pion counter - Data", {HistType::kTH1F, {{5, 0., 5.}}}}, - {"hTrackCounterRec", "soft pion counter - MC rec", {HistType::kTH1F, {{5, 0., 5.}}}}, - {"hTrackCounterGen", "soft pion counter - MC gen", {HistType::kTH1F, {{5, 0., 5.}}}}, - {"hMultV0M", "multiplicity;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}}, - {"hZvtx", "z vertex;z vertex;entries", {HistType::kTH1F, {{200, -20., 20.}}}}, - {"hD0Bin", "D0 selected in pool Bin;pool Bin;entries", {HistType::kTH1F, {{9, 0., 9.}}}}, - {"hTracksBin", "Tracks selected in pool Bin;pool Bin;entries", {HistType::kTH1F, {{9, 0., 9.}}}}}}; + Preslice perCol = aod::hf_cand::collisionId; + + ConfigurableAxis zPoolBins{"zPoolBins", {VARIABLE_WIDTH, -10.0f, -2.5f, 2.5f, 10.0f}, "z vertex position pools"}; + ConfigurableAxis multPoolBins{"multPoolBins", {VARIABLE_WIDTH, 0.0f, 2000.0f, 6000.0f, 10000.0f}, "event multiplicity pools (FT0M)"}; + ConfigurableAxis multPoolBinsMcGen{"multPoolBinsMcGen", {VARIABLE_WIDTH, 0.0f, 20.0f, 50.0f, 500.0f}, "Mixing bins - MC multiplicity"}; // In MCGen multiplicity is defined by counting tracks + ConfigurableAxis binsMassD{"binsMassD", {200, 1.3848, 2.3848}, "inv. mass (#pi K) (GeV/#it{c}^{2});entries"}; + ConfigurableAxis binsEta{"binsEta", {100, -5., 5.}, "#it{#eta}"}; + ConfigurableAxis binsPhi{"binsPhi", {64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, "#it{#varphi}"}; + ConfigurableAxis binsMultiplicity{"binsMultiplicity", {10000, 0., 10000.}, "Multiplicity"}; + ConfigurableAxis binsMultFT0M{"binsMultFT0M", {10000, 0., 10000.}, "Multiplicity as FT0M signal amplitude"}; + ConfigurableAxis binsPosZ{"binsPosZ", {100, -10., 10.}, "primary vertex z coordinate"}; + ConfigurableAxis binsPoolBin{"binsPoolBin", {9, 0., 9.}, "PoolBin"}; + + BinningType corrBinning{{zPoolBins, multPoolBins}, true}; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext&) { @@ -244,38 +244,99 @@ struct HfCorrelatorD0Hadrons { massPi = MassPiPlus; massK = MassKPlus; - auto vbins = (std::vector)bins; - registry.add("hMass", "D0,D0bar candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisNBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hMass1D", "D0,D0bar candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{massAxisNBins, massAxisMin, massAxisMax}}}); - registry.add("hMassD01D", "D0,D0bar candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{massAxisNBins, massAxisMin, massAxisMax}}}); - registry.add("hMassD0bar1D", "D0,D0bar candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{massAxisNBins, massAxisMin, massAxisMax}}}); - // mass histogram for D0 signal only - registry.add("hMassD0RecSig", "D0 signal candidates - MC reco;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisNBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - // mass histogram for D0 Reflection candidates only - registry.add("hMassD0RecRef", "D0 reflection candidates - MC reco;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisNBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - // mass histogram for D0 background candidates only - registry.add("hMassD0RecBg", "D0 background candidates - MC reco;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisNBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - // mass histogram for D0bar signal only - registry.add("hMassD0barRecSig", "D0bar signal candidates - MC reco;inv. mass D0bar only (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisNBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - // mass histogram for D0bar Reflection candidates only - registry.add("hMassD0barRecRef", "D0bar reflection candidates - MC reco;inv. mass D0bar only (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisNBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - // mass histogram for D0bar background candidates only - registry.add("hMassD0barRecBg", "D0bar background candidates - MC reco;inv. mass D0bar only (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisNBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hCountD0TriggersGen", "D0 trigger particles - MC gen;;N of trigger D0", {HistType::kTH2F, {{1, -0.5, 0.5}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + AxisSpec axisMassD = {binsMassD, "inv. mass (#pi K) (GeV/#it{c}^{2})"}; + AxisSpec axisEta = {binsEta, "#it{#eta}"}; + AxisSpec axisPhi = {binsPhi, "#it{#varphi}"}; + AxisSpec axisRapidity = {100, -5., 5., "Rapidity"}; + AxisSpec axisPtD = {(std::vector)binsPtD, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisPtHadron = {(std::vector)binsPtHadron, "#it{p}_{T} Hadron (GeV/#it{c})"}; + AxisSpec axisMultiplicity = {binsMultiplicity, "Multiplicity"}; + AxisSpec axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; + AxisSpec axisPosZ = {binsPosZ, "PosZ"}; + AxisSpec axisPoolBin = {binsPoolBin, "PoolBin"}; + AxisSpec axisStatus = {4, -0.5, 3.5, "Selection status"}; + AxisSpec axisSignalStatus = {200, 0., 200., "Signal status"}; + AxisSpec axisEvtCount = {1, -0.5, 0.5}; + AxisSpec axisTrkCount = {5, 0., 5.}; + AxisSpec axisBdtScoreBkg = {100, 0., 1., "Bdt score background"}; + AxisSpec axisBdtScorePrompt = {100, 0., 1., "Bdt score prompt"}; + + // Histograms for Data + registry.add("hPtCand", "D0, D0bar candidates", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtProng0", "D0, D0bar candidates prong 0", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtProng1", "D0, D0bar candidates prong 1", {HistType::kTH1F, {axisPtD}}); + registry.add("hSelectionStatus", "D0, D0bar candidates selection status", {HistType::kTH1F, {axisStatus}}); + registry.add("hEta", "D0,D0bar candidates", {HistType::kTH1F, {axisEta}}); + registry.add("hPhi", "D0,D0bar candidates", {HistType::kTH1F, {axisPhi}}); + registry.add("hY", "D0,D0bar candidates", {HistType::kTH1F, {axisRapidity}}); + registry.add("hMultiplicityPreSelection", "multiplicity prior to selection;multiplicity;entries", {HistType::kTH1F, {axisMultiplicity}}); + registry.add("hMultiplicity", "multiplicity;multiplicity;entries", {HistType::kTH1F, {axisMultiplicity}}); + registry.add("hMass", "D0, D0bar candidates massVsPt", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hMass1D", "D0, D0bar candidates mass", {HistType::kTH1F, {axisMassD}}); + registry.add("hMassD01D", "D0 candidates mass", {HistType::kTH1F, {axisMassD}}); + registry.add("hMassD0bar1D", "D0bar candidates mass", {HistType::kTH1F, {axisMassD}}); + registry.add("hMLScoresVsMassVsPt", "D0, D0bar candidates massVsPt", {HistType::kTHnSparseD, {{axisBdtScoreBkg}, {axisBdtScorePrompt}, {axisMassD}, {axisPtD}}}); + // Histograms for MC Reco + registry.add("hPtCandRec", "D0, D0bar candidates - MC reco", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtProng0Rec", "D0, D0bar candidates prong 0 - MC reco", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtProng1Rec", "D0, D0bar candidates prong 1 - MC reco", {HistType::kTH1F, {axisPtD}}); + registry.add("hSelectionStatusRec", "D0, D0bar candidates selection status - MC reco", {HistType::kTH1F, {axisStatus}}); + registry.add("hSignalStatusMERec", "Signal Status - MC reco ME", {HistType::kTH1F, {axisSignalStatus}}); + registry.add("hEtaRec", "D0,D0bar candidates - MC reco", {HistType::kTH1F, {axisEta}}); + registry.add("hPhiRec", "D0,D0bar candidates - MC reco", {HistType::kTH1F, {axisPhi}}); + registry.add("hYRec", "D0,D0bar candidates - MC reco", {HistType::kTH1F, {axisRapidity}}); + registry.add("hMassD0RecSig", "D0 signal candidates massVsPt - MC reco", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hMassD0RecRef", "D0 reflection candidates massVsPt - MC reco", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hMassD0RecBg", "D0 background candidates massVsPt - MC reco", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hMassD0barRecSig", "D0bar signal candidates massVsPt - MC reco", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hMassD0barRecRef", "D0bar reflection candidates massVsPt - MC reco", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hMassD0barRecBg", "D0bar background candidates massVsPt - MC reco", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hPtCandRecSigPrompt", "D+,Hadron candidates Prompt - MC Reco", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandRecSigNonPrompt", "D+,Hadron candidates Non Prompt - MC Reco", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtVsMultiplicityRecPrompt", "Multiplicity FT0M - MC Rec Prompt", {HistType::kTH2F, {{axisPtD}, {axisMultFT0M}}}); + registry.add("hPtVsMultiplicityRecNonPrompt", "Multiplicity FT0M - MC Rec Non Prompt", {HistType::kTH2F, {{axisPtD}, {axisMultFT0M}}}); + registry.add("hPtParticleAssocVsCandRec", "Associated Particle - MC reco", {HistType::kTH2F, {{axisPtHadron}, {axisPtD}}}); + registry.add("hPtPrimaryParticleAssocVsCandRec", "Associated Particle - MC reco", {HistType::kTH2F, {{axisPtHadron}, {axisPtD}}}); + // Histograms for MC Gen + registry.add("hEvtCountGen", "Event counter - MC gen", {HistType::kTH1F, {axisEvtCount}}); + registry.add("hPtCandGen", "D0, D0bar candidates - MC gen", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandGenPrompt", "D0, D0bar candidates - MC gen prompt", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandGenNonPrompt", "D0, D0bar candidates - MC gen non prompt", {HistType::kTH1F, {axisPtD}}); + registry.add("hEtaGen", "D0,D0bar candidates - MC gen", {HistType::kTH1F, {axisEta}}); + registry.add("hPhiGen", "D0,D0bar candidates - MC gen", {HistType::kTH1F, {axisPhi}}); + registry.add("hYGen", "D0,D0bar candidates - MC gen", {HistType::kTH1F, {axisRapidity}}); + registry.add("hCountD0TriggersGen", "D0 trigger particles - MC gen;;N of trigger D0", {HistType::kTH2F, {{axisEvtCount}, {axisPtD}}}); + // Common histograms + registry.add("hTrackCounter", "Track counter", {HistType::kTH1F, {axisTrkCount}}); + registry.get(HIST("hTrackCounter"))->GetXaxis()->SetBinLabel(1, "all"); + registry.get(HIST("hTrackCounter"))->GetXaxis()->SetBinLabel(2, "before softpi"); + registry.get(HIST("hTrackCounter"))->GetXaxis()->SetBinLabel(3, "after softpi"); + registry.get(HIST("hTrackCounter"))->GetXaxis()->SetBinLabel(4, "with leading particles"); + registry.get(HIST("hTrackCounter"))->GetXaxis()->SetBinLabel(5, "fake tracks"); + registry.add("hZvtx", "z vertex", {HistType::kTH1F, {axisPosZ}}); + registry.add("hMultFT0M", "Multiplicity FT0M", {HistType::kTH1F, {axisMultFT0M}}); + registry.add("hCollisionPoolBin", "collision pool bin", {HistType::kTH1F, {axisPoolBin}}); + registry.add("hD0PoolBin", "D0 selected in pool Bin", {HistType::kTH1F, {axisPoolBin}}); + registry.add("hTracksPoolBin", "Particles associated pool bin", {HistType::kTH1F, {axisPoolBin}}); } // ======= Process starts for Data, Same event ============ /// D0-h correlation pair builder - for real data and data-like analysis (i.e. reco-level w/o matching request via MC truth) - void processData(soa::Join::iterator const& collision, - aod::TracksWDca const& tracks, - soa::Join const&) + void processData(SelectedCollisions::iterator const& collision, + SelectedTracks const& tracks, + SelectedCandidatesDataMl const& candidates) { - // protection against empty tables to be sliced - if (selectedD0Candidates.size() == 0) { - return; + // find leading particle + if (correlateD0WithLeadingParticle) { + leadingIndex = findLeadingParticle(tracks, etaTrackMax.value); } - int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFV0M())); + + int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFT0M())); + registry.fill(HIST("hCollisionPoolBin"), poolBin); + registry.fill(HIST("hZvtx"), collision.posZ()); + registry.fill(HIST("hMultFT0M"), collision.multFT0M()); + int nTracks = 0; if (collision.numContrib() > 1) { for (const auto& track : tracks) { @@ -289,106 +350,125 @@ struct HfCorrelatorD0Hadrons { } } registry.fill(HIST("hMultiplicityPreSelection"), nTracks); + if (nTracks < multMin || nTracks > multMax) { return; } registry.fill(HIST("hMultiplicity"), nTracks); + std::vector outputMlD0 = {-1., -1., -1.}; + std::vector outputMlD0bar = {-1., -1., -1.}; - auto selectedD0CandidatesGrouped = selectedD0Candidates->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); - - for (const auto& candidate1 : selectedD0CandidatesGrouped) { - if (yCandMax >= 0. && std::abs(hfHelper.yD0(candidate1)) > yCandMax) { + for (const auto& candidate : candidates) { + if (std::abs(hfHelper.yD0(candidate)) >= yCandMax || candidate.pt() <= ptCandMin || candidate.pt() >= ptTrackMax) { continue; } - if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { - continue; - } - // check decay channel flag for candidate1 - if (!TESTBIT(candidate1.hfflag(), aod::hf_cand_2prong::DecayType::D0ToPiK)) { + // check decay channel flag for candidate + if (!TESTBIT(candidate.hfflag(), aod::hf_cand_2prong::DecayType::D0ToPiK)) { continue; } // ========================== Define parameters for soft pion removal ================================ - auto ePiK = RecoDecay::e(candidate1.pVectorProng0(), massPi) + RecoDecay::e(candidate1.pVectorProng1(), massK); - auto eKPi = RecoDecay::e(candidate1.pVectorProng0(), massK) + RecoDecay::e(candidate1.pVectorProng1(), massPi); + auto ePiK = RecoDecay::e(candidate.pVectorProng0(), massPi) + RecoDecay::e(candidate.pVectorProng1(), massK); + auto eKPi = RecoDecay::e(candidate.pVectorProng0(), massK) + RecoDecay::e(candidate.pVectorProng1(), massPi); // ========================== trigger efficiency ================================ double efficiencyWeight = 1.; if (applyEfficiency) { - efficiencyWeight = 1. / efficiencyDmeson->at(o2::analysis::findBin(bins, candidate1.pt())); + efficiencyWeight = 1. / efficiencyDmeson->at(o2::analysis::findBin(binsPtEfficiencyD, candidate.pt())); } // ========================== Fill mass histo ================================ - if (candidate1.isSelD0() >= selectionFlagD0) { - registry.fill(HIST("hMass"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); - registry.fill(HIST("hMass1D"), hfHelper.invMassD0ToPiK(candidate1), efficiencyWeight); - registry.fill(HIST("hMassD01D"), hfHelper.invMassD0ToPiK(candidate1), efficiencyWeight); + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hMass"), hfHelper.invMassD0ToPiK(candidate), candidate.pt(), efficiencyWeight); + registry.fill(HIST("hMass1D"), hfHelper.invMassD0ToPiK(candidate), efficiencyWeight); + registry.fill(HIST("hMassD01D"), hfHelper.invMassD0ToPiK(candidate), efficiencyWeight); + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMlD0[iclass] = candidate.mlProbD0()[classMl->at(iclass)]; + } + registry.fill(HIST("hMLScoresVsMassVsPt"), outputMlD0[0], outputMlD0[2], hfHelper.invMassD0ToPiK(candidate), candidate.pt()); } - if (candidate1.isSelD0bar() >= selectionFlagD0bar) { - registry.fill(HIST("hMass"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); - registry.fill(HIST("hMass1D"), hfHelper.invMassD0barToKPi(candidate1), efficiencyWeight); - registry.fill(HIST("hMassD0bar1D"), hfHelper.invMassD0barToKPi(candidate1), efficiencyWeight); + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hMass"), hfHelper.invMassD0barToKPi(candidate), candidate.pt(), efficiencyWeight); + registry.fill(HIST("hMass1D"), hfHelper.invMassD0barToKPi(candidate), efficiencyWeight); + registry.fill(HIST("hMassD0bar1D"), hfHelper.invMassD0barToKPi(candidate), efficiencyWeight); + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMlD0bar[iclass] = candidate.mlProbD0bar()[classMl->at(iclass)]; + } + registry.fill(HIST("hMLScoresVsMassVsPt"), outputMlD0bar[0], outputMlD0bar[2], hfHelper.invMassD0barToKPi(candidate), candidate.pt()); } + entryD0CandRecoInfo(hfHelper.invMassD0ToPiK(candidate), hfHelper.invMassD0barToKPi(candidate), candidate.pt(), outputMlD0[0], outputMlD0[2], outputMlD0bar[0], outputMlD0bar[2]); + // ========================== Fill general histos ================================ - registry.fill(HIST("hPtCand"), candidate1.pt()); - registry.fill(HIST("hPtProng0"), candidate1.ptProng0()); - registry.fill(HIST("hPtProng1"), candidate1.ptProng1()); - registry.fill(HIST("hEta"), candidate1.eta()); - registry.fill(HIST("hPhi"), candidate1.phi()); - registry.fill(HIST("hY"), hfHelper.yD0(candidate1)); - registry.fill(HIST("hSelectionStatus"), candidate1.isSelD0bar() + (candidate1.isSelD0() * 2)); - registry.fill(HIST("hD0Bin"), poolBin); + registry.fill(HIST("hPtCand"), candidate.pt()); + registry.fill(HIST("hPtProng0"), candidate.ptProng0()); + registry.fill(HIST("hPtProng1"), candidate.ptProng1()); + registry.fill(HIST("hEta"), candidate.eta()); + registry.fill(HIST("hPhi"), candidate.phi()); + registry.fill(HIST("hY"), hfHelper.yD0(candidate)); + registry.fill(HIST("hSelectionStatus"), candidate.isSelD0bar() + (candidate.isSelD0() * 2)); + registry.fill(HIST("hD0PoolBin"), poolBin); // ============ D-h correlation dedicated section ================================== // ========================== track loop starts here ================================ for (const auto& track : tracks) { - registry.fill(HIST("hTrackCounter"), 1); // fill total no. of tracks + registry.fill(HIST("hTrackCounter"), 0); // fill total no. of tracks // Remove D0 daughters by checking track indices - if ((candidate1.prong0Id() == track.globalIndex()) || (candidate1.prong1Id() == track.globalIndex())) { - continue; + bool correlationStatus = false; + if ((candidate.prong0Id() == track.globalIndex()) || (candidate.prong1Id() == track.globalIndex())) { + if (!storeAutoCorrelationFlag) { + continue; + } + correlationStatus = true; } - if (std::abs(track.dcaXY()) >= 1. || std::abs(track.dcaZ()) >= 1.) - continue; // Remove secondary tracks - - registry.fill(HIST("hTrackCounter"), 2); // fill no. of tracks before soft pion removal + registry.fill(HIST("hTrackCounter"), 1); // fill no. of tracks before soft pion removal // ========== soft pion removal =================================================== double invMassDstar1 = 0., invMassDstar2 = 0.; bool isSoftPiD0 = false, isSoftPiD0bar = false; - auto pSum2 = RecoDecay::p2(candidate1.pVector(), track.pVector()); + auto pSum2 = RecoDecay::p2(candidate.pVector(), track.pVector()); auto ePion = track.energy(massPi); invMassDstar1 = std::sqrt((ePiK + ePion) * (ePiK + ePion) - pSum2); invMassDstar2 = std::sqrt((eKPi + ePion) * (eKPi + ePion) - pSum2); - if (candidate1.isSelD0() >= selectionFlagD0) { - if ((std::abs(invMassDstar1 - hfHelper.invMassD0ToPiK(candidate1)) - softPiMass) < ptSoftPionMax) { + if (candidate.isSelD0() >= selectionFlagD0) { + if ((std::abs(invMassDstar1 - hfHelper.invMassD0ToPiK(candidate)) - softPiMass) < ptSoftPionMax) { isSoftPiD0 = true; continue; } } - if (candidate1.isSelD0bar() >= selectionFlagD0bar) { - if ((std::abs(invMassDstar2 - hfHelper.invMassD0barToKPi(candidate1)) - softPiMass) < ptSoftPionMax) { + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + if ((std::abs(invMassDstar2 - hfHelper.invMassD0barToKPi(candidate)) - softPiMass) < ptSoftPionMax) { isSoftPiD0bar = true; continue; } } - registry.fill(HIST("hTrackCounter"), 3); // fill no. of tracks after soft pion removal + registry.fill(HIST("hTrackCounter"), 2); // fill no. of tracks after soft pion removal int signalStatus = 0; - if ((candidate1.isSelD0() >= selectionFlagD0) && !isSoftPiD0) { + if ((candidate.isSelD0() >= selectionFlagD0) && !isSoftPiD0) { signalStatus += aod::hf_correlation_d0_hadron::ParticleTypeData::D0Only; } - if ((candidate1.isSelD0bar() >= selectionFlagD0bar) && !isSoftPiD0bar) { + if ((candidate.isSelD0bar() >= selectionFlagD0bar) && !isSoftPiD0bar) { signalStatus += aod::hf_correlation_d0_hadron::ParticleTypeData::D0barOnly; } - entryD0HadronPair(getDeltaPhi(track.phi(), candidate1.phi()), - track.eta() - candidate1.eta(), - candidate1.pt(), + if (correlateD0WithLeadingParticle) { + if (track.globalIndex() != leadingIndex) { + continue; + } + registry.fill(HIST("hTrackCounter"), 3); // fill no. of tracks have leading particle + } + entryD0HadronPair(getDeltaPhi(track.phi(), candidate.phi()), + track.eta() - candidate.eta(), + candidate.pt(), track.pt(), - poolBin); - entryD0HadronRecoInfo(hfHelper.invMassD0ToPiK(candidate1), hfHelper.invMassD0barToKPi(candidate1), signalStatus); + poolBin, + correlationStatus); + entryD0HadronRecoInfo(hfHelper.invMassD0ToPiK(candidate), hfHelper.invMassD0barToKPi(candidate), signalStatus); + entryD0HadronGenInfo(false, false, 0); + entryD0HadronMlInfo(outputMlD0[0], outputMlD0[1], outputMlD0[2], outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2]); + entryTrackRecoInfo(track.dcaXY(), track.dcaZ(), track.tpcNClsCrossedRows()); } // end inner loop (tracks) @@ -398,15 +478,20 @@ struct HfCorrelatorD0Hadrons { // ================ Process starts for MCRec, same event ======================== - void processMcRec(soa::Join::iterator const& collision, - aod::TracksWDca const& tracks, - soa::Join const&) + void processMcRec(SelectedCollisions::iterator const& collision, + SelectedTracksMcRec const& tracks, + SelectedCandidatesMcRecMl const& candidates, + aod::McParticles const& mcParticles) { - // protection against empty tables to be sliced - if (selectedD0candidatesMc.size() == 0) { - return; + // find leading particle + if (correlateD0WithLeadingParticle) { + leadingIndex = findLeadingParticle(tracks, etaTrackMax.value); } - int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFV0M())); + int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFT0M())); + registry.fill(HIST("hCollisionPoolBin"), poolBin); + registry.fill(HIST("hZvtx"), collision.posZ()); + registry.fill(HIST("hMultFT0M"), collision.multFT0M()); + int nTracks = 0; if (collision.numContrib() > 1) { for (const auto& track : tracks) { @@ -425,220 +510,290 @@ struct HfCorrelatorD0Hadrons { } registry.fill(HIST("hMultiplicity"), nTracks); - auto selectedD0CandidatesGroupedMc = selectedD0candidatesMc->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); // MC reco level bool flagD0 = false; bool flagD0bar = false; - - for (const auto& candidate1 : selectedD0CandidatesGroupedMc) { - // check decay channel flag for candidate1 - if (!TESTBIT(candidate1.hfflag(), aod::hf_cand_2prong::DecayType::D0ToPiK)) { + bool isD0Prompt = false; + bool isD0NonPrompt = false; + std::vector outputMlD0 = {-1., -1., -1.}; + std::vector outputMlD0bar = {-1., -1., -1.}; + + for (const auto& candidate : candidates) { + isD0Prompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; + isD0NonPrompt = candidate.originMcRec() == RecoDecay::OriginType::NonPrompt; + // check decay channel flag for candidate + if (!TESTBIT(candidate.hfflag(), aod::hf_cand_2prong::DecayType::D0ToPiK)) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yD0(candidate1)) > yCandMax) { - continue; - } - if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { + if (std::abs(hfHelper.yD0(candidate)) >= yCandMax || candidate.pt() <= ptCandMin || candidate.pt() >= ptTrackMax) { continue; } + registry.fill(HIST("hD0PoolBin"), poolBin); + double efficiencyWeight = 1.; if (applyEfficiency) { - efficiencyWeight = 1. / efficiencyDmeson->at(o2::analysis::findBin(bins, candidate1.pt())); + efficiencyWeight = 1. / efficiencyDmeson->at(o2::analysis::findBin(binsPtEfficiencyD, candidate.pt())); } - if (std::abs(candidate1.flagMcMatchRec()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { + if (std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { // fill per-candidate distributions from D0/D0bar true candidates - registry.fill(HIST("hPtCandRec"), candidate1.pt()); - registry.fill(HIST("hPtProng0Rec"), candidate1.ptProng0()); - registry.fill(HIST("hPtProng1Rec"), candidate1.ptProng1()); - registry.fill(HIST("hEtaRec"), candidate1.eta()); - registry.fill(HIST("hPhiRec"), candidate1.phi()); - registry.fill(HIST("hYRec"), hfHelper.yD0(candidate1)); - registry.fill(HIST("hSelectionStatusRec"), candidate1.isSelD0bar() + (candidate1.isSelD0() * 2)); + registry.fill(HIST("hPtCandRec"), candidate.pt()); + registry.fill(HIST("hPtProng0Rec"), candidate.ptProng0()); + registry.fill(HIST("hPtProng1Rec"), candidate.ptProng1()); + registry.fill(HIST("hEtaRec"), candidate.eta()); + registry.fill(HIST("hPhiRec"), candidate.phi()); + registry.fill(HIST("hYRec"), hfHelper.yD0(candidate)); + registry.fill(HIST("hSelectionStatusRec"), candidate.isSelD0bar() + (candidate.isSelD0() * 2)); } // fill invariant mass plots from D0/D0bar signal and background candidates - if (candidate1.isSelD0() >= selectionFlagD0) { // only reco as D0 - if (candidate1.flagMcMatchRec() == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { // also matched as D0 - registry.fill(HIST("hMassD0RecSig"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); - } else if (candidate1.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { - registry.fill(HIST("hMassD0RecRef"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); + if (candidate.isSelD0() >= selectionFlagD0) { // only reco as D0 + if (candidate.flagMcMatchRec() == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { // also matched as D0 + registry.fill(HIST("hMassD0RecSig"), hfHelper.invMassD0ToPiK(candidate), candidate.pt(), efficiencyWeight); + if (isD0Prompt) { + registry.fill(HIST("hPtCandRecSigPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityRecPrompt"), candidate.pt(), collision.multFT0M()); + } else if (isD0NonPrompt) { + registry.fill(HIST("hPtCandRecSigNonPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityRecNonPrompt"), candidate.pt(), collision.multFT0M()); + } + } else if (candidate.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { + registry.fill(HIST("hMassD0RecRef"), hfHelper.invMassD0ToPiK(candidate), candidate.pt(), efficiencyWeight); } else { - registry.fill(HIST("hMassD0RecBg"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0RecBg"), hfHelper.invMassD0ToPiK(candidate), candidate.pt(), efficiencyWeight); + } + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMlD0[iclass] = candidate.mlProbD0()[classMl->at(iclass)]; } } - if (candidate1.isSelD0bar() >= selectionFlagD0bar) { // only reco as D0bar - if (candidate1.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { // also matched as D0bar - registry.fill(HIST("hMassD0barRecSig"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); - } else if (candidate1.flagMcMatchRec() == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { - registry.fill(HIST("hMassD0barRecRef"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); + if (candidate.isSelD0bar() >= selectionFlagD0bar) { // only reco as D0bar + if (candidate.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { // also matched as D0bar + registry.fill(HIST("hMassD0barRecSig"), hfHelper.invMassD0barToKPi(candidate), candidate.pt(), efficiencyWeight); + if (isD0Prompt) { + registry.fill(HIST("hPtCandRecSigPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityRecPrompt"), candidate.pt(), collision.multFT0M()); + } else if (isD0NonPrompt) { + registry.fill(HIST("hPtCandRecSigNonPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityRecNonPrompt"), candidate.pt(), collision.multFT0M()); + } + } else if (candidate.flagMcMatchRec() == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { + registry.fill(HIST("hMassD0barRecRef"), hfHelper.invMassD0barToKPi(candidate), candidate.pt(), efficiencyWeight); } else { - registry.fill(HIST("hMassD0barRecBg"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0barRecBg"), hfHelper.invMassD0barToKPi(candidate), candidate.pt(), efficiencyWeight); + } + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMlD0bar[iclass] = candidate.mlProbD0bar()[classMl->at(iclass)]; } } + entryD0CandRecoInfo(hfHelper.invMassD0ToPiK(candidate), hfHelper.invMassD0barToKPi(candidate), candidate.pt(), outputMlD0[0], outputMlD0[2], outputMlD0bar[0], outputMlD0bar[2]); + entryD0CandGenInfo(isD0Prompt); // ===================== Define parameters for soft pion removal ======================== - auto ePiK = RecoDecay::e(candidate1.pVectorProng0(), massPi) + RecoDecay::e(candidate1.pVectorProng1(), massK); - auto eKPi = RecoDecay::e(candidate1.pVectorProng0(), massK) + RecoDecay::e(candidate1.pVectorProng1(), massPi); + auto ePiK = RecoDecay::e(candidate.pVectorProng0(), massPi) + RecoDecay::e(candidate.pVectorProng1(), massK); + auto eKPi = RecoDecay::e(candidate.pVectorProng0(), massK) + RecoDecay::e(candidate.pVectorProng1(), massPi); // ============== D-h correlation dedicated section ==================================== - flagD0 = candidate1.flagMcMatchRec() == (1 << aod::hf_cand_2prong::DecayType::D0ToPiK); // flagD0Signal 'true' if candidate1 matched to D0 (particle) - flagD0bar = candidate1.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK); // flagD0Reflection 'true' if candidate1, selected as D0 (particle), is matched to D0bar (antiparticle) + flagD0 = candidate.flagMcMatchRec() == (1 << aod::hf_cand_2prong::DecayType::D0ToPiK); // flagD0Signal 'true' if candidate matched to D0 (particle) + flagD0bar = candidate.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK); // flagD0Reflection 'true' if candidate, selected as D0 (particle), is matched to D0bar (antiparticle) // ========== track loop starts here ======================== for (const auto& track : tracks) { - registry.fill(HIST("hTrackCounterRec"), 1); // fill total no. of tracks - if (std::abs(track.eta()) > etaTrackMax) { - continue; - } - if (track.pt() < ptTrackMin) { + registry.fill(HIST("hTrackCounter"), 0); // fill total no. of tracks + if (!track.isGlobalTrackWoDCA()) { continue; } // Removing D0 daughters by checking track indices - if ((candidate1.prong0Id() == track.globalIndex()) || (candidate1.prong1Id() == track.globalIndex())) { - continue; - } - if (std::abs(track.dcaXY()) >= 1. || std::abs(track.dcaZ()) >= 1.) { - continue; // Remove secondary tracks + bool correlationStatus = false; + if ((candidate.prong0Id() == track.globalIndex()) || (candidate.prong1Id() == track.globalIndex())) { + if (!storeAutoCorrelationFlag) { + continue; + } + correlationStatus = true; } - registry.fill(HIST("hTrackCounterRec"), 2); // fill no. of tracks before soft pion removal + registry.fill(HIST("hTrackCounter"), 1); // fill no. of tracks before soft pion removal + bool isPhysicalPrimary = false; + int trackOrigin = -1; // ===== soft pion removal =================================================== double invMassDstar1 = 0, invMassDstar2 = 0; bool isSoftPiD0 = false, isSoftPiD0bar = false; - auto pSum2 = RecoDecay::p2(candidate1.pVector(), track.pVector()); + auto pSum2 = RecoDecay::p2(candidate.pVector(), track.pVector()); auto ePion = track.energy(massPi); invMassDstar1 = std::sqrt((ePiK + ePion) * (ePiK + ePion) - pSum2); invMassDstar2 = std::sqrt((eKPi + ePion) * (eKPi + ePion) - pSum2); - if (candidate1.isSelD0() >= selectionFlagD0) { - if ((std::abs(invMassDstar1 - hfHelper.invMassD0ToPiK(candidate1)) - softPiMass) < ptSoftPionMax) { + if (candidate.isSelD0() >= selectionFlagD0) { + if ((std::abs(invMassDstar1 - hfHelper.invMassD0ToPiK(candidate)) - softPiMass) < ptSoftPionMax) { isSoftPiD0 = true; continue; } } - if (candidate1.isSelD0bar() >= selectionFlagD0bar) { - if ((std::abs(invMassDstar2 - hfHelper.invMassD0barToKPi(candidate1)) - softPiMass) < ptSoftPionMax) { + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + if ((std::abs(invMassDstar2 - hfHelper.invMassD0barToKPi(candidate)) - softPiMass) < ptSoftPionMax) { isSoftPiD0bar = true; continue; } } - registry.fill(HIST("hTrackCounterRec"), 3); // fill no. of tracks after soft pion removal + registry.fill(HIST("hTrackCounter"), 2); // fill no. of tracks after soft pion removal + + if (correlateD0WithLeadingParticle) { + if (track.globalIndex() != leadingIndex) { + continue; + } + registry.fill(HIST("hTrackCounter"), 3); // fill no. of tracks have leading particle + } int signalStatus = 0; - if (flagD0 && (candidate1.isSelD0() >= selectionFlagD0) && !isSoftPiD0) { + if (flagD0 && (candidate.isSelD0() >= selectionFlagD0) && !isSoftPiD0) { SETBIT(signalStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0Sig); } // signal case D0 - if (flagD0bar && (candidate1.isSelD0() >= selectionFlagD0) && !isSoftPiD0) { + if (flagD0bar && (candidate.isSelD0() >= selectionFlagD0) && !isSoftPiD0) { SETBIT(signalStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0Ref); } // reflection case D0 - if (!flagD0 && !flagD0bar && (candidate1.isSelD0() >= selectionFlagD0) && !isSoftPiD0) { + if (!flagD0 && !flagD0bar && (candidate.isSelD0() >= selectionFlagD0) && !isSoftPiD0) { SETBIT(signalStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0Bg); } // background case D0 - if (flagD0bar && (candidate1.isSelD0bar() >= selectionFlagD0bar) && !isSoftPiD0bar) { + if (flagD0bar && (candidate.isSelD0bar() >= selectionFlagD0bar) && !isSoftPiD0bar) { SETBIT(signalStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0barSig); } // signal case D0bar - if (flagD0 && (candidate1.isSelD0bar() >= selectionFlagD0bar) && !isSoftPiD0bar) { + if (flagD0 && (candidate.isSelD0bar() >= selectionFlagD0bar) && !isSoftPiD0bar) { SETBIT(signalStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0barRef); } // reflection case D0bar - if (!flagD0 && !flagD0bar && (candidate1.isSelD0bar() >= selectionFlagD0bar) && !isSoftPiD0bar) { + if (!flagD0 && !flagD0bar && (candidate.isSelD0bar() >= selectionFlagD0bar) && !isSoftPiD0bar) { SETBIT(signalStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0barBg); } // background case D0bar - entryD0HadronPair(getDeltaPhi(track.phi(), candidate1.phi()), - track.eta() - candidate1.eta(), - candidate1.pt(), + entryD0HadronPair(getDeltaPhi(track.phi(), candidate.phi()), + track.eta() - candidate.eta(), + candidate.pt(), track.pt(), - poolBin); - entryD0HadronRecoInfo(hfHelper.invMassD0ToPiK(candidate1), hfHelper.invMassD0barToKPi(candidate1), signalStatus); + poolBin, + correlationStatus); + entryD0HadronRecoInfo(hfHelper.invMassD0ToPiK(candidate), hfHelper.invMassD0barToKPi(candidate), signalStatus); + entryD0HadronMlInfo(outputMlD0[0], outputMlD0[1], outputMlD0[2], outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2]); + if (track.has_mcParticle()) { + auto mcParticle = track.template mcParticle_as(); + isPhysicalPrimary = mcParticle.isPhysicalPrimary(); + trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); + entryD0HadronGenInfo(isD0Prompt, isPhysicalPrimary, trackOrigin); + } else { + entryD0HadronGenInfo(isD0Prompt, isPhysicalPrimary, 0); + registry.fill(HIST("hTrackCounter"), 4); // fill no. of fake tracks + } + // for secondary particle fraction estimation + registry.fill(HIST("hPtParticleAssocVsCandRec"), track.pt(), candidate.pt()); + if (isPhysicalPrimary) { + registry.fill(HIST("hPtPrimaryParticleAssocVsCandRec"), track.pt(), candidate.pt()); + } + entryTrackRecoInfo(track.dcaXY(), track.dcaZ(), track.tpcNClsCrossedRows()); } // end inner loop (Tracks) - } // end of outer loop (D0) - registry.fill(HIST("hZvtx"), collision.posZ()); - registry.fill(HIST("hMultV0M"), collision.multFV0M()); + } // end of outer loop (D0) } PROCESS_SWITCH(HfCorrelatorD0Hadrons, processMcRec, "Process MC Reco mode", true); // ================= Process starts for MCGen, same event =================== - void processMcGen(aod::McCollision const& mcCollision, - soa::Join const& mcParticles) + void processMcGen(SelectedCollisionsMcGen::iterator const& mcCollision, + SelectedParticlesMcGen const& mcParticles) { + BinningTypeMcGen corrBinningMcGen{{zPoolBins, multPoolBinsMcGen}, true}; + int poolBin = corrBinningMcGen.getBin(std::make_tuple(mcCollision.posZ(), mcCollision.multMCFT0A())); + registry.fill(HIST("hCollisionPoolBin"), poolBin); registry.fill(HIST("hEvtCountGen"), 0); // MC gen level - for (const auto& particle1 : mcParticles) { - // check if the particle is D0 or D0bar (for general plot filling and selection, so both cases are fine) - NOTE: decay channel is not probed! - if (std::abs(particle1.pdgCode()) != Pdg::kD0) { - continue; - } - double yD = RecoDecay::y(particle1.pVector(), MassD0); - if (yCandMax >= 0. && std::abs(yD) > yCandMax) { - continue; - } - if (ptCandMin >= 0. && particle1.pt() < ptCandMin) { - continue; - } - registry.fill(HIST("hPtCandGen"), particle1.pt()); - registry.fill(HIST("hEtaGen"), particle1.eta()); - registry.fill(HIST("hPhiGen"), particle1.phi()); - registry.fill(HIST("hYGen"), yD); - - // =============== D-h correlation dedicated section ===================== + // find leading particle + if (correlateD0WithLeadingParticle) { + leadingIndex = findLeadingParticleMcGen(mcParticles, etaTrackMax.value, ptTrackMin.value); + } + bool isD0Prompt = false; + bool isD0NonPrompt = false; + int trackOrigin = -1; - if (std::abs(particle1.pdgCode()) != Pdg::kD0) { // just checking the particle PDG, not the decay channel (differently from Reco: you have a BR factor btw such levels!) + for (const auto& particleTrigg : mcParticles) { + if (std::abs(particleTrigg.pdgCode()) != Pdg::kD0) { continue; } - registry.fill(HIST("hCountD0TriggersGen"), 0, particle1.pt()); // to count trigger D0 (for normalisation) - - for (const auto& particle2 : mcParticles) { - registry.fill(HIST("hTrackCounterGen"), 1); // total no. of tracks - if (std::abs(particle2.eta()) > etaTrackMax) { - continue; - } - if (particle2.pt() < ptTrackMin) { + if (std::abs(particleTrigg.flagMcMatchGen()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { + double yD = RecoDecay::y(particleTrigg.pVector(), MassD0); + if (yCandMax >= 0. && std::abs(yD) > yCandMax) { continue; } - if ((std::abs(particle2.pdgCode()) != kElectron) && (std::abs(particle2.pdgCode()) != kMuonMinus) && (std::abs(particle2.pdgCode()) != kPiPlus) && (std::abs(particle2.pdgCode()) != kKPlus) && (std::abs(particle2.pdgCode()) != kProton)) { + if (ptCandMin >= 0. && particleTrigg.pt() < ptCandMin) { continue; } - // ==============================soft pion removal================================ - registry.fill(HIST("hTrackCounterGen"), 2); // fill before soft pi removal - // method used: indexMother = -1 by default if the mother doesn't match with given PID of the mother. We find mother of pion if it is D* and mother of D0 if it is D*. If they are both positive and they both match each other, then it is detected as a soft pion + registry.fill(HIST("hD0PoolBin"), poolBin); + registry.fill(HIST("hPtCandGen"), particleTrigg.pt()); + registry.fill(HIST("hEtaGen"), particleTrigg.eta()); + registry.fill(HIST("hPhiGen"), particleTrigg.phi()); + registry.fill(HIST("hYGen"), yD); + registry.fill(HIST("hCountD0TriggersGen"), 0, particleTrigg.pt()); // to count trigger D0 (for normalisation) + + isD0Prompt = particleTrigg.originMcGen() == RecoDecay::OriginType::Prompt; + isD0NonPrompt = particleTrigg.originMcGen() == RecoDecay::OriginType::NonPrompt; + + // prompt and non-prompt division + if (isD0Prompt) { + registry.fill(HIST("hPtCandGenPrompt"), particleTrigg.pt()); + } else if (isD0NonPrompt) { + registry.fill(HIST("hPtCandGenNonPrompt"), particleTrigg.pt()); + } - auto indexMotherPi = RecoDecay::getMother(mcParticles, particle2, Pdg::kDStar, true, nullptr, 1); // last arguement 1 is written to consider immediate decay mother only - auto indexMotherD0 = RecoDecay::getMother(mcParticles, particle1, Pdg::kDStar, true, nullptr, 1); - if (std::abs(particle2.pdgCode()) == kPiPlus && indexMotherPi >= 0 && indexMotherD0 >= 0 && indexMotherPi == indexMotherD0) - continue; + // =============== D-h correlation dedicated section ===================== + for (const auto& particleAssoc : mcParticles) { + registry.fill(HIST("hTrackCounter"), 0); // total no. of tracks + if (std::abs(particleAssoc.eta()) > etaTrackMax) { + continue; + } + if (particleAssoc.pt() < ptTrackMin) { + continue; + } + if ((std::abs(particleAssoc.pdgCode()) != kElectron) && (std::abs(particleAssoc.pdgCode()) != kMuonMinus) && (std::abs(particleAssoc.pdgCode()) != kPiPlus) && (std::abs(particleAssoc.pdgCode()) != kKPlus) && (std::abs(particleAssoc.pdgCode()) != kProton)) { + continue; + } + if (!particleAssoc.isPhysicalPrimary()) { + continue; + } + // ==============================soft pion removal================================ + registry.fill(HIST("hTrackCounter"), 1); // fill before soft pi removal + // method used: indexMother = -1 by default if the mother doesn't match with given PID of the mother. We find mother of pion if it is D* and mother of D0 if it is D*. If they are both positive and they both match each other, then it is detected as a soft pion + + auto indexMotherPi = RecoDecay::getMother(mcParticles, particleAssoc, Pdg::kDStar, true, nullptr, 1); // last arguement 1 is written to consider immediate decay mother only + auto indexMotherD0 = RecoDecay::getMother(mcParticles, particleTrigg, Pdg::kDStar, true, nullptr, 1); + bool correlationStatus = false; + if (std::abs(particleAssoc.pdgCode()) == kPiPlus && indexMotherPi >= 0 && indexMotherD0 >= 0 && indexMotherPi == indexMotherD0) { + if (!storeAutoCorrelationFlag) { + continue; + } + correlationStatus = true; + } - registry.fill(HIST("hTrackCounterGen"), 3); // fill after soft pion removal + registry.fill(HIST("hTrackCounter"), 2); // fill after soft pion removal - auto getTracksSize = [&mcParticles](aod::McCollision const& /*collision*/) { - int nTracks = 0; - for (const auto& track : mcParticles) { - if (track.isPhysicalPrimary() && std::abs(track.eta()) < 1.0) { - nTracks++; + if (correlateD0WithLeadingParticle) { + if (particleAssoc.globalIndex() != leadingIndex) { + continue; } + registry.fill(HIST("hTrackCounter"), 3); // fill no. of tracks have leading particle } - return nTracks; - }; - using BinningTypeMcGen = FlexibleBinningPolicy, aod::mccollision::PosZ, decltype(getTracksSize)>; - BinningTypeMcGen corrBinningMcGen{{getTracksSize}, {zBins, multBinsMcGen}, true}; - int poolBin = corrBinningMcGen.getBin(std::make_tuple(mcCollision.posZ(), getTracksSize(mcCollision))); - - entryD0HadronPair(getDeltaPhi(particle2.phi(), particle1.phi()), - particle2.eta() - particle1.eta(), - particle1.pt(), - particle2.pt(), - poolBin); - entryD0HadronRecoInfo(massD0, massD0, 0); // dummy info - } // end inner loop (Tracks) - } // end outer loop (D0) + trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, particleAssoc, true); + entryD0HadronPair(getDeltaPhi(particleAssoc.phi(), particleTrigg.phi()), + particleAssoc.eta() - particleTrigg.eta(), + particleTrigg.pt(), + particleAssoc.pt(), + poolBin, + correlationStatus); + entryD0HadronRecoInfo(massD0, massD0, 0); // dummy info + entryD0HadronGenInfo(isD0Prompt, particleAssoc.isPhysicalPrimary(), trackOrigin); + } // end inner loop (Tracks) + } + } // end outer loop (D0) } PROCESS_SWITCH(HfCorrelatorD0Hadrons, processMcGen, "Process MC Gen mode", false); @@ -646,61 +801,82 @@ struct HfCorrelatorD0Hadrons { // ====================== Implement Event mixing on Data =================================== void processDataMixedEvent(SelectedCollisions const& collisions, - SelectedCandidatesData const& candidates, + SelectedCandidatesDataMl const& candidates, SelectedTracks const& tracks) { + for (const auto& collision : collisions) { + registry.fill(HIST("hMultFT0M"), collision.multFT0M()); + registry.fill(HIST("hZvtx"), collision.posZ()); + } + auto tracksTuple = std::make_tuple(candidates, tracks); - Pair pairData{corrBinning, 5, -1, collisions, tracksTuple, &cache}; + Pair pairData{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; for (const auto& [c1, tracks1, c2, tracks2] : pairData) { - // LOGF(info, "Mixed event collisions: Index = (%d, %d), tracks Size: (%d, %d), Z Vertex: (%f, %f), Pool Bin: (%d, %d)", c1.globalIndex(), c2.globalIndex(), tracks1.size(), tracks2.size(), c1.posZ(), c2.posZ(), corrBinning.getBin(std::make_tuple(c1.posZ(), c1.multFV0M())),corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multFV0M()))); // For debug - int poolBin = corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multFV0M())); - for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - - if (yCandMax >= 0. && std::abs(hfHelper.yD0(t1)) > yCandMax) { + if (tracks1.size() == 0) { + continue; + } + // LOGF(info, "Mixed event collisions: Index = (%d, %d), tracks Size: (%d, %d), Z Vertex: (%f, %f), Pool Bin: (%d, %d)", c1.globalIndex(), c2.globalIndex(), tracks1.size(), tracks2.size(), c1.posZ(), c2.posZ(), corrBinning.getBin(std::make_tuple(c1.posZ(), c1.multFT0M())),corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multFT0M()))); // For debug + int poolBin = corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multFT0M())); + int poolBinD0 = corrBinning.getBin(std::make_tuple(c1.posZ(), c1.multFT0M())); + registry.fill(HIST("hTracksPoolBin"), poolBin); + registry.fill(HIST("hD0PoolBin"), poolBinD0); + for (const auto& [candidate, particleAssoc] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + + if (std::abs(hfHelper.yD0(candidate)) >= yCandMax || candidate.pt() < ptCandMin) { continue; } - // soft pion removal, signal status 1,3 for D0 and 2,3 for D0bar (SoftPi removed), signal status 11,13 for D0 and 12.13 for D0bar (only SoftPi) - auto ePiK = RecoDecay::e(t1.pVectorProng0(), massPi) + RecoDecay::e(t1.pVectorProng1(), massK); - auto eKPi = RecoDecay::e(t1.pVectorProng0(), massK) + RecoDecay::e(t1.pVectorProng1(), massPi); + // soft pion removal, signal status 1,3 for D0 and 2,3 for D0bar (SoftPi removed), signal status 11,13 for D0 and 12,13 for D0bar (only SoftPi) + auto ePiK = RecoDecay::e(candidate.pVectorProng0(), massPi) + RecoDecay::e(candidate.pVectorProng1(), massK); + auto eKPi = RecoDecay::e(candidate.pVectorProng0(), massK) + RecoDecay::e(candidate.pVectorProng1(), massPi); double invMassDstar1 = 0., invMassDstar2 = 0.; bool isSoftPiD0 = false, isSoftPiD0bar = false; - auto pSum2 = RecoDecay::p2(t1.pVector(), t2.pVector()); - auto ePion = t2.energy(massPi); + auto pSum2 = RecoDecay::p2(candidate.pVector(), particleAssoc.pVector()); + auto ePion = particleAssoc.energy(massPi); invMassDstar1 = std::sqrt((ePiK + ePion) * (ePiK + ePion) - pSum2); invMassDstar2 = std::sqrt((eKPi + ePion) * (eKPi + ePion) - pSum2); + std::vector outputMlD0 = {-1., -1., -1.}; + std::vector outputMlD0bar = {-1., -1., -1.}; - if (t1.isSelD0() >= selectionFlagD0) { - if ((std::abs(invMassDstar1 - hfHelper.invMassD0ToPiK(t1)) - softPiMass) < ptSoftPionMax) { + if (candidate.isSelD0() >= selectionFlagD0) { + if ((std::abs(invMassDstar1 - hfHelper.invMassD0ToPiK(candidate)) - softPiMass) < ptSoftPionMax) { isSoftPiD0 = true; } + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMlD0[iclass] = candidate.mlProbD0()[classMl->at(iclass)]; + } } - - if (t1.isSelD0bar() >= selectionFlagD0bar) { - if ((std::abs(invMassDstar2 - hfHelper.invMassD0barToKPi(t1)) - softPiMass) < ptSoftPionMax) { + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + if ((std::abs(invMassDstar2 - hfHelper.invMassD0barToKPi(candidate)) - softPiMass) < ptSoftPionMax) { isSoftPiD0bar = true; } + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMlD0bar[iclass] = candidate.mlProbD0bar()[classMl->at(iclass)]; + } } int signalStatus = 0; - if (t1.isSelD0() >= selectionFlagD0) { + if (candidate.isSelD0() >= selectionFlagD0) { if (!isSoftPiD0) { signalStatus += aod::hf_correlation_d0_hadron::ParticleTypeData::D0Only; } else { signalStatus += aod::hf_correlation_d0_hadron::ParticleTypeData::D0OnlySoftPi; } } - if (t1.isSelD0bar() >= selectionFlagD0bar) { + if (candidate.isSelD0bar() >= selectionFlagD0bar) { if (!isSoftPiD0bar) { signalStatus += aod::hf_correlation_d0_hadron::ParticleTypeData::D0barOnly; } else { signalStatus += aod::hf_correlation_d0_hadron::ParticleTypeData::D0barOnlySoftPi; } } - - entryD0HadronPair(getDeltaPhi(t1.phi(), t2.phi()), t1.eta() - t2.eta(), t1.pt(), t2.pt(), poolBin); - entryD0HadronRecoInfo(hfHelper.invMassD0ToPiK(t1), hfHelper.invMassD0barToKPi(t1), signalStatus); + bool correlationStatus = false; + entryD0HadronPair(getDeltaPhi(candidate.phi(), particleAssoc.phi()), candidate.eta() - particleAssoc.eta(), candidate.pt(), particleAssoc.pt(), poolBin, correlationStatus); + entryD0HadronRecoInfo(hfHelper.invMassD0ToPiK(candidate), hfHelper.invMassD0barToKPi(candidate), signalStatus); + entryD0HadronGenInfo(false, false, 0); + entryD0HadronMlInfo(outputMlD0[0], outputMlD0[1], outputMlD0[2], outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2]); + entryTrackRecoInfo(particleAssoc.dcaXY(), particleAssoc.dcaZ(), particleAssoc.tpcNClsCrossedRows()); } } } @@ -709,49 +885,77 @@ struct HfCorrelatorD0Hadrons { // ====================== Implement Event mixing on McRec =================================== void processMcRecMixedEvent(SelectedCollisions const& collisions, - SelectedCandidatesMcRec const& candidates, - SelectedTracks const& tracks) + SelectedCandidatesMcRecMl const& candidates, + SelectedTracksMcRec const& tracks, + aod::McParticles const& mcParticles) { auto tracksTuple = std::make_tuple(candidates, tracks); - Pair pairMcRec{corrBinning, 5, -1, collisions, tracksTuple, &cache}; + Pair pairMcRec{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + bool isD0Prompt = false; bool flagD0 = false; bool flagD0bar = false; + bool isPhysicalPrimary = false; + int trackOrigin = 0; for (const auto& [c1, tracks1, c2, tracks2] : pairMcRec) { - int poolBin = corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multFV0M())); + int poolBin = corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multFT0M())); + int poolBinD0 = corrBinning.getBin(std::make_tuple(c1.posZ(), c1.multFT0M())); + registry.fill(HIST("hTracksPoolBin"), poolBin); + registry.fill(HIST("hD0PoolBin"), poolBinD0); + registry.fill(HIST("hMultFT0M"), c1.multFT0M()); + registry.fill(HIST("hZvtx"), c1.posZ()); - for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + for (const auto& [candidate, particleAssoc] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - if (yCandMax >= 0. && std::abs(hfHelper.yD0(t1)) > yCandMax) { + if (std::abs(hfHelper.yD0(candidate)) >= yCandMax || candidate.pt() < ptCandMin) { continue; } - + if (!particleAssoc.isGlobalTrackWoDCA()) { + continue; + } + std::vector outputMlD0 = {-1., -1., -1.}; + std::vector outputMlD0bar = {-1., -1., -1.}; + isD0Prompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; + if (particleAssoc.has_mcParticle()) { + auto mcParticle = particleAssoc.template mcParticle_as(); + isPhysicalPrimary = mcParticle.isPhysicalPrimary(); + trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); + } + if (candidate.isSelD0() >= selectionFlagD0) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMlD0[iclass] = candidate.mlProbD0()[classMl->at(iclass)]; + } + } else if (candidate.isSelD0bar() >= selectionFlagD0bar) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMlD0bar[iclass] = candidate.mlProbD0bar()[classMl->at(iclass)]; + } + } // soft pion removal - auto ePiK = RecoDecay::e(t1.pVectorProng0(), massPi) + RecoDecay::e(t1.pVectorProng1(), massK); - auto eKPi = RecoDecay::e(t1.pVectorProng0(), massK) + RecoDecay::e(t1.pVectorProng1(), massPi); + auto ePiK = RecoDecay::e(candidate.pVectorProng0(), massPi) + RecoDecay::e(candidate.pVectorProng1(), massK); + auto eKPi = RecoDecay::e(candidate.pVectorProng0(), massK) + RecoDecay::e(candidate.pVectorProng1(), massPi); double invMassDstar1 = 0., invMassDstar2 = 0.; bool isSoftPiD0 = false, isSoftPiD0bar = false; - auto pSum2 = RecoDecay::p2(t1.pVector(), t2.pVector()); - auto ePion = t2.energy(massPi); + auto pSum2 = RecoDecay::p2(candidate.pVector(), particleAssoc.pVector()); + auto ePion = particleAssoc.energy(massPi); invMassDstar1 = std::sqrt((ePiK + ePion) * (ePiK + ePion) - pSum2); invMassDstar2 = std::sqrt((eKPi + ePion) * (eKPi + ePion) - pSum2); - if (t1.isSelD0() >= selectionFlagD0) { - if ((std::abs(invMassDstar1 - hfHelper.invMassD0ToPiK(t1)) - softPiMass) < ptSoftPionMax) { + if (candidate.isSelD0() >= selectionFlagD0) { + if ((std::abs(invMassDstar1 - hfHelper.invMassD0ToPiK(candidate)) - softPiMass) < ptSoftPionMax) { isSoftPiD0 = true; } } - if (t1.isSelD0bar() >= selectionFlagD0bar) { - if ((std::abs(invMassDstar2 - hfHelper.invMassD0barToKPi(t1)) - softPiMass) < ptSoftPionMax) { + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + if ((std::abs(invMassDstar2 - hfHelper.invMassD0barToKPi(candidate)) - softPiMass) < ptSoftPionMax) { isSoftPiD0bar = true; } } - flagD0 = t1.flagMcMatchRec() == (1 << aod::hf_cand_2prong::DecayType::D0ToPiK); // flagD0Signal 'true' if candidate1 matched to D0 (particle) - flagD0bar = t1.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK); // flagD0Reflection 'true' if candidate1, selected as D0 (particle), is matched to D0bar (antiparticle) + flagD0 = candidate.flagMcMatchRec() == (1 << aod::hf_cand_2prong::DecayType::D0ToPiK); // flagD0Signal 'true' if candidate matched to D0 (particle) + flagD0bar = candidate.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK); // flagD0Reflection 'true' if candidate, selected as D0 (particle), is matched to D0bar (antiparticle) int signalStatus = 0; - if (flagD0 && (t1.isSelD0() >= selectionFlagD0)) { + if (flagD0 && (candidate.isSelD0() >= selectionFlagD0)) { if (!isSoftPiD0) { SETBIT(signalStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0Sig); // signalStatus += 1; } else { @@ -759,7 +963,7 @@ struct HfCorrelatorD0Hadrons { } } // signal case D0 - if (flagD0bar && (t1.isSelD0() >= selectionFlagD0)) { + if (flagD0bar && (candidate.isSelD0() >= selectionFlagD0)) { if (!isSoftPiD0) { SETBIT(signalStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0Ref); // signalStatus += 2; } else { @@ -767,7 +971,7 @@ struct HfCorrelatorD0Hadrons { } } // reflection case D0 - if (!flagD0 && !flagD0bar && (t1.isSelD0() >= selectionFlagD0)) { + if (!flagD0 && !flagD0bar && (candidate.isSelD0() >= selectionFlagD0)) { if (!isSoftPiD0) { SETBIT(signalStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0Bg); // signalStatus += 4; } else { @@ -775,7 +979,7 @@ struct HfCorrelatorD0Hadrons { } } // background case D0 - if (flagD0bar && (t1.isSelD0bar() >= selectionFlagD0bar)) { + if (flagD0bar && (candidate.isSelD0bar() >= selectionFlagD0bar)) { if (!isSoftPiD0bar) { SETBIT(signalStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0barSig); // signalStatus += 8; } else { @@ -783,7 +987,7 @@ struct HfCorrelatorD0Hadrons { } } // signal case D0bar - if (flagD0 && (t1.isSelD0bar() >= selectionFlagD0bar)) { + if (flagD0 && (candidate.isSelD0bar() >= selectionFlagD0bar)) { if (!isSoftPiD0bar) { SETBIT(signalStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0barRef); // signalStatus += 16; } else { @@ -791,17 +995,20 @@ struct HfCorrelatorD0Hadrons { } } // reflection case D0bar - if (!flagD0 && !flagD0bar && (t1.isSelD0bar() >= selectionFlagD0bar)) { + if (!flagD0 && !flagD0bar && (candidate.isSelD0bar() >= selectionFlagD0bar)) { if (!isSoftPiD0bar) { SETBIT(signalStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0barBg); // signalStatus += 32; } else { SETBIT(signalStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::SoftPi); } } // background case D0bar - registry.fill(HIST("hSignalStatusMERec"), signalStatus); - entryD0HadronPair(getDeltaPhi(t1.phi(), t2.phi()), t1.eta() - t2.eta(), t1.pt(), t2.pt(), poolBin); - entryD0HadronRecoInfo(hfHelper.invMassD0ToPiK(t1), hfHelper.invMassD0barToKPi(t1), signalStatus); + bool correlationStatus = false; + entryD0HadronPair(getDeltaPhi(candidate.phi(), particleAssoc.phi()), candidate.eta() - particleAssoc.eta(), candidate.pt(), particleAssoc.pt(), poolBin, correlationStatus); + entryD0HadronRecoInfo(hfHelper.invMassD0ToPiK(candidate), hfHelper.invMassD0barToKPi(candidate), signalStatus); + entryD0HadronGenInfo(isD0Prompt, isPhysicalPrimary, trackOrigin); + entryD0HadronMlInfo(outputMlD0[0], outputMlD0[1], outputMlD0[2], outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2]); + entryTrackRecoInfo(particleAssoc.dcaXY(), particleAssoc.dcaZ(), particleAssoc.tpcNClsCrossedRows()); } } } @@ -810,60 +1017,45 @@ struct HfCorrelatorD0Hadrons { // ====================== Implement Event mixing on McGen =================================== void processMcGenMixedEvent(SelectedCollisionsMcGen const& collisions, - SelectedTracksMcGen const& mcParticles) + SelectedParticlesMcGen const& mcParticles) { - - auto getTracksSize = [&mcParticles, this](SelectedCollisionsMcGen::iterator const& collision) { - int nTracks = 0; - auto associatedTracks = mcParticles.sliceByCached(o2::aod::mcparticle::mcCollisionId, collision.globalIndex(), this->cache); - for (const auto& track : associatedTracks) { - if (track.isPhysicalPrimary() && std::abs(track.eta()) < 1.0) { - nTracks++; - } - } - return nTracks; - }; - - using BinningTypeMcGen = FlexibleBinningPolicy, aod::mccollision::PosZ, decltype(getTracksSize)>; - BinningTypeMcGen corrBinningMcGen{{getTracksSize}, {zBins, multBins}, true}; - + BinningTypeMcGen corrBinningMcGen{{zPoolBins, multPoolBinsMcGen}, true}; auto tracksTuple = std::make_tuple(mcParticles, mcParticles); - Pair pairMcGen{corrBinningMcGen, 5, -1, collisions, tracksTuple, &cache}; + Pair pairMcGen{corrBinningMcGen, numberEventsMixed, -1, collisions, tracksTuple, &cache}; for (const auto& [c1, tracks1, c2, tracks2] : pairMcGen) { - for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - - // Check track t1 is D0 - if (std::abs(t1.pdgCode()) != Pdg::kD0) { - continue; - } - - double yD = RecoDecay::y(t1.pVector(), MassD0); - if (yCandMax >= 0. && std::abs(yD) > yCandMax) { - continue; - } - if (ptCandMin >= 0. && t1.pt() < ptCandMin) { - continue; - } - - if (std::abs(t2.eta()) > etaTrackMax) { - continue; - } - if (t2.pt() < ptTrackMin) { + int poolBin = corrBinningMcGen.getBin(std::make_tuple(c1.posZ(), c1.multMCFT0A())); + for (const auto& [particleTrigg, particleAssoc] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (std::abs(particleTrigg.pdgCode()) != Pdg::kD0) { continue; } + if (std::abs(particleTrigg.flagMcMatchGen()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { + double yD = RecoDecay::y(particleTrigg.pVector(), MassD0); + if (std::abs(yD) >= yCandMax || particleTrigg.pt() <= ptCandMin || std::abs(particleAssoc.eta()) >= etaTrackMax || particleAssoc.pt() <= ptTrackMin) { + continue; + } + if ((std::abs(particleAssoc.pdgCode()) != kElectron) && (std::abs(particleAssoc.pdgCode()) != kMuonMinus) && (std::abs(particleAssoc.pdgCode()) != kPiPlus) && (std::abs(particleAssoc.pdgCode()) != kKPlus) && (std::abs(particleAssoc.pdgCode()) != kProton)) { + continue; + } + if (!particleAssoc.isPhysicalPrimary()) { + continue; + } - // ==============================soft pion removal================================ - // method used: indexMother = -1 by default if the mother doesn't match with given PID of the mother. We find mother of pion if it is D* and mother of D0 if it is D*. If they are both positive and they both match each other, then it is detected as a soft pion + // ==============================soft pion removal================================ + // method used: indexMother = -1 by default if the mother doesn't match with given PID of the mother. We find mother of pion if it is D* and mother of D0 if it is D*. If they are both positive and they both match each other, then it is detected as a soft pion - auto indexMotherPi = RecoDecay::getMother(mcParticles, t2, Pdg::kDStar, true, nullptr, 1); // last arguement 1 is written to consider immediate decay mother only - auto indexMotherD0 = RecoDecay::getMother(mcParticles, t1, Pdg::kDStar, true, nullptr, 1); - if (std::abs(t2.pdgCode()) == kPiPlus && indexMotherPi >= 0 && indexMotherD0 >= 0 && indexMotherPi == indexMotherD0) { - continue; + auto indexMotherPi = RecoDecay::getMother(mcParticles, particleAssoc, Pdg::kDStar, true, nullptr, 1); // last arguement 1 is written to consider immediate decay mother only + auto indexMotherD0 = RecoDecay::getMother(mcParticles, particleTrigg, Pdg::kDStar, true, nullptr, 1); + if (std::abs(particleAssoc.pdgCode()) == kPiPlus && indexMotherPi >= 0 && indexMotherD0 >= 0 && indexMotherPi == indexMotherD0) { + continue; + } + bool correlationStatus = false; + int trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, particleAssoc, true); + bool isD0Prompt = particleTrigg.originMcGen() == RecoDecay::OriginType::Prompt; + entryD0HadronPair(getDeltaPhi(particleAssoc.phi(), particleTrigg.phi()), particleAssoc.eta() - particleTrigg.eta(), particleTrigg.pt(), particleAssoc.pt(), poolBin, correlationStatus); + entryD0HadronRecoInfo(massD0, massD0, 0); // dummy info + entryD0HadronGenInfo(isD0Prompt, particleAssoc.isPhysicalPrimary(), trackOrigin); } - int poolBin = corrBinningMcGen.getBin(std::make_tuple(c2.posZ(), getTracksSize(c2))); - entryD0HadronPair(getDeltaPhi(t2.phi(), t1.phi()), t2.eta() - t1.eta(), t1.pt(), t2.pt(), poolBin); - entryD0HadronRecoInfo(massD0, massD0, 0); // dummy info } } } diff --git a/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx b/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx index 63827f2b89c..ef5791fadc8 100644 --- a/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx @@ -14,6 +14,9 @@ /// /// \author Andrea Tavira García , IJCLab Orsay +#include +#include + #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" @@ -22,6 +25,8 @@ #include "Common/DataModel/TrackSelectionTables.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/HfMlResponse.h" +#include "PWGHF/Core/HfMlResponseD0ToKPi.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/HFC/DataModel/DMesonPairsTables.h" @@ -52,34 +57,73 @@ enum PairTypeOfSelMassSel { using McParticlesPlus2Prong = soa::Join; struct HfCorrelatorDMesonPairs { - SliceCache cache; - Preslice perCol2Prong = aod::hf_cand::collisionId; Produces entryD0Pair; + Produces entryD0PairMl; Produces entryD0PairMcInfo; Produces entryD0PairMcGen; Produces entryD0PairMcGenInfo; Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection Flag for D0bar"}; + Configurable selectionFlagHf{"selectionFlagHf", 1, "Selection Flag for HF flagged candidates"}; Configurable yCandMax{"yCandMax", 0.8, "maxmum |y| of D0 candidates"}; Configurable ptCandMin{"ptCandMin", -1., "minimum pT of D0 candidates"}; Configurable> binsPt{"binsPt", std::vector{o2::analysis::hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits for candidate mass plots"}; Configurable selectSignalRegionOnly{"selectSignalRegionOnly", false, "only use events close to PDG peak"}; Configurable massCut{"massCut", 0.05, "Maximum deviation from PDG peak allowed for signal region"}; Configurable daughterTracksCutFlag{"daughterTracksCutFlag", false, "Flag to add cut on daughter tracks"}; + Configurable removeAmbiguous{"removeAmbiguous", false, "Flag to remove ambiguous candidates"}; + + // ML inference + Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; + Configurable> binsPtMl{"binsPtMl", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; + Configurable> cutDirMl{"cutDirMl", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; + Configurable> cutsMl{"cutsMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable nClassesMl{"nClassesMl", static_cast(hf_cuts_ml::NCutScores), "Number of classes in ML model"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; + + // ML model CCDB configuration + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"EventFiltering/PWGHF/BDTD0"}, "Paths of models on CCDB"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_D0ToKPi.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; HfHelper hfHelper; + SliceCache cache; + Preslice perCol2Prong = aod::hf_cand::collisionId; + + o2::analysis::HfMlResponseD0ToKPi hfMlResponse; + o2::ccdb::CcdbApi ccdbApi; + + std::vector outputMlD0Cand1 = {}; + std::vector outputMlD0barCand1 = {}; + + std::vector outputMlD0Cand2 = {}; + std::vector outputMlD0barCand2 = {}; - using TracksWPid = soa::Join; + // using TracksWPid = soa::Join; - Partition> selectedD0Candidates = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlagD0 || aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlagD0bar; - Partition> selectedD0CandidatesMc = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlagD0 || aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlagD0bar; + Partition> selectedD0Candidates = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlagD0 || aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlagD0bar; + Partition> selectedD0CandidatesMc = aod::hf_sel_candidate_d0::isRecoHfFlag >= selectionFlagHf; + + // ThnSparse for ML outputScores and Vars + ConfigurableAxis thnConfigAxisBkgScore{"thnConfigAxisBkgScore", {100, 0, 1}, "Bkg score bins"}; + ConfigurableAxis thnConfigAxisSignalScore{"thnConfigAxisSignalScore", {100, 0, 1}, "Signal score bins"}; + ConfigurableAxis thnConfigAxisMass{"thnConfigAxisMass", {120, 1.5848, 2.1848}, "Cand. inv-mass bins"}; + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {500, 0, 50}, "Cand. pT bins"}; + ConfigurableAxis thnConfigAxisY{"thnConfigAxisY", {20, -1, 1}, "Cand. rapidity bins"}; + ConfigurableAxis thnConfigAxisOrigin{"thnConfigAxisOrigin", {3, -0.5, 2.5}, "Cand. origin type"}; + ConfigurableAxis thnConfigAxisCandType{"thnConfigAxisCandType", {6, -0.5, 5.5}, "D0 type"}; + ConfigurableAxis thnConfigAxisNumPvContr{"thnConfigAxisNumPvContr", {200, -0.5, 199.5}, "Number of PV contributors"}; HistogramConfigSpec hTH1Pt{HistType::kTH1F, {{180, 0., 36.}}}; HistogramConfigSpec hTH1Y{HistType::kTH1F, {{100, -5., 5.}}}; + HistogramConfigSpec hTH1NContrib{HistType::kTH1F, {{200, -0.5, 199.5}}}; HistogramConfigSpec hTH1Phi{HistType::kTH1F, {{32, 0., o2::constants::math::TwoPI}}}; HistogramConfigSpec hTH2Pid{HistType::kTH2F, {{500, 0., 10.}, {400, -20., 20.}}}; + HistogramConfigSpec hTH3PtVsYVsNContrib{HistType::kTH3F, {{360, 0., 36.}, {20, -1., 1.}, {120, -0.5, 119.5}}}; HistogramRegistry registry{ "registry", @@ -90,11 +134,21 @@ struct HfCorrelatorDMesonPairs { {"hEta", "D meson candidates;candidate #it{#eta};entries", hTH1Y}, {"hPhi", "D meson candidates;candidate #it{#varphi};entries", hTH1Phi}, {"hY", "D meson candidates;candidate #it{y};entries", hTH1Y}, + {"hPVContrib", "D meson candidates;candidate Number of PV contributors;entries", hTH1NContrib}, // MC Gen plots {"hPtCandMcGen", "D meson candidates MC Gen;candidate #it{p}_{T} (GeV/#it{c});entries", hTH1Pt}, {"hPtCandAfterCutMcGen", "D meson candidates after pT cut;candidate #it{p}_{T} (GeV/#it{c});entries", hTH1Pt}, {"hEtaMcGen", "D meson candidates MC Gen;candidate #it{#eta};entries", hTH1Y}, {"hPhiMcGen", "D meson candidates MC Gen;candidate #it{#varphi};entries", hTH1Phi}, + {"hPtVsYVsNContribMcGen", "D meson candidates MC Gen;candidate #it{p}_{T} (GeV/#it{c});#it{y};Number of contributors", hTH3PtVsYVsNContrib}, + {"hPtVsYVsNContribMcGenPrompt", "D meson candidates MC Gen Prompt;candidate #it{p}_{T} (GeV/#it{c});#it{y};Number of contributors", hTH3PtVsYVsNContrib}, + {"hPtVsYVsNContribMcGenNonPrompt", "D meson candidates MC Gen Prompt;candidate #it{p}_{T} (GeV/#it{c});#it{y};Number of contributors", hTH3PtVsYVsNContrib}, + {"hNContribMcGen", "D meson candidates MC Gen;Number of PV contributors", hTH1NContrib}, + // MC Rec plots + {"hPtVsYVsNContribMcRec", "D meson candidates MC Rec;candidate #it{p}_{T} (GeV/#it{c});#it{y};Number of contributors", hTH3PtVsYVsNContrib}, + {"hPtVsYVsNContribMcRecPrompt", "D meson candidates MC Rec Prompt;candidate #it{p}_{T} (GeV/#it{c});#it{y};Number of contributors", hTH3PtVsYVsNContrib}, + {"hPtVsYVsNContribMcRecNonPrompt", "D meson candidates MC Rec Non-prompt;candidate #it{p}_{T} (GeV/#it{c});#it{y};Number of contributors", hTH3PtVsYVsNContrib}, + {"hNContribMcRec", "D meson candidates MC Rec;Number of PV contributors", hTH1NContrib}, // PID plots ----- Not definitively here {"PID/hTofNSigmaPi", "(TOFsignal-time#pi)/tofSigPid;p[GeV/c];(TOFsignal-time#pi)/tofSigPid", hTH2Pid}, {"PID/hTofNSigmaKa", "(TOFsignal-timeK)/tofSigPid;p[GeV/c];(TOFsignal-timeK)/tofSigPid", hTH2Pid}, @@ -105,6 +159,19 @@ struct HfCorrelatorDMesonPairs { void init(InitContext&) { + + if (applyMl) { + hfMlResponse.configure(binsPtMl, cutsMl, cutDirMl, nClassesMl); + if (loadModelsFromCCDB) { + ccdbApi.init(ccdbUrl); + hfMlResponse.setModelPathsCCDB(onnxFileNames, ccdbApi, modelPathsCCDB, timestampCCDB); + } else { + hfMlResponse.setModelPathsLocal(onnxFileNames); + } + hfMlResponse.cacheInputFeaturesIndices(namesInputFeatures); + hfMlResponse.init(); + } + auto vbins = (std::vector)binsPt; constexpr int kNBinsSelStatus = 25; std::string labels[kNBinsSelStatus]; @@ -201,6 +268,31 @@ struct HfCorrelatorDMesonPairs { registry.add("hInputCheckD0OrD0barMcGen", "Check on input D0 | D0bar meson candidates/event MC Gen", {HistType::kTH1F, {axisInputD0}}); registry.add("hMass", "D Meson pair candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{120, 1.5848, 2.1848}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassMcRecPrompt", "D Meson pair candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{120, 1.5848, 2.1848}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassMcRecNonPrompt", "D Meson pair candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{120, 1.5848, 2.1848}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassMcRecReflections", "D Meson pair candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{120, 1.5848, 2.1848}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + + const AxisSpec thnAxisMass{thnConfigAxisMass, "inv. mass (#pi K) (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisPt{thnConfigAxisPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisY{thnConfigAxisY, "y"}; + const AxisSpec thnAxisOrigin{thnConfigAxisOrigin, "Origin"}; + const AxisSpec thnAxisCandType{thnConfigAxisCandType, "D0 type"}; + const AxisSpec thnAxisNumPvContr{thnConfigAxisNumPvContr, "Number of PV contributors"}; + + std::vector axes = {thnAxisMass, thnAxisPt, thnAxisY, thnAxisNumPvContr, thnAxisOrigin, thnAxisCandType}; + if (applyMl) { + const AxisSpec thnAxisBkgScore{thnConfigAxisBkgScore, "BDT score bkg"}; + const AxisSpec thnAxisSignalScore{thnConfigAxisSignalScore, "BDT score signal"}; + + axes.insert(axes.begin(), thnAxisSignalScore); + axes.insert(axes.begin(), thnAxisBkgScore); + + registry.add("hnDMesonMl", "THn for D Meson candidates", HistType::kTHnSparseD, axes); + registry.get(HIST("hnDMesonMl"))->Sumw2(); + } else { + registry.add("hnDMeson", "Thn for D0 candidates", HistType::kTHnSparseD, axes); + registry.get(HIST("hnDMeson"))->Sumw2(); + } } /// Sets bits to select candidate type for D0 @@ -279,32 +371,30 @@ struct HfCorrelatorDMesonPairs { /// Fill PID related plots for D0 and D0bar /// \param candidate is candidate template - void AnalysePid(const T& candidate) + void analysePid(const T& candidate) { - auto prong0 = candidate.template prong0_as(); - auto prong1 = candidate.template prong1_as(); if (candidate.isSelD0() >= selectionFlagD0) { - registry.fill(HIST("PID/hTofNSigmaPi"), candidate.ptProng0(), prong0.tofNSigmaPi()); - registry.fill(HIST("PID/hTofNSigmaKa"), candidate.ptProng1(), prong1.tofNSigmaKa()); - registry.fill(HIST("PID/hTpcNSigmaPi"), candidate.ptProng0(), prong0.tpcNSigmaPi()); - registry.fill(HIST("PID/hTpcNSigmaKa"), candidate.ptProng1(), prong1.tpcNSigmaKa()); - registry.fill(HIST("PID/hTpcTofNSigmaPi"), candidate.ptProng0(), prong0.tpcTofNSigmaPi()); - registry.fill(HIST("PID/hTpcTofNSigmaKa"), candidate.ptProng1(), prong1.tpcTofNSigmaKa()); + registry.fill(HIST("PID/hTofNSigmaPi"), candidate.ptProng0(), candidate.nSigTofPi0()); + registry.fill(HIST("PID/hTofNSigmaKa"), candidate.ptProng1(), candidate.nSigTofKa1()); + registry.fill(HIST("PID/hTpcNSigmaPi"), candidate.ptProng0(), candidate.nSigTpcPi0()); + registry.fill(HIST("PID/hTpcNSigmaKa"), candidate.ptProng1(), candidate.nSigTpcKa1()); + registry.fill(HIST("PID/hTpcTofNSigmaPi"), candidate.ptProng0(), candidate.tpcTofNSigmaPi0()); + registry.fill(HIST("PID/hTpcTofNSigmaKa"), candidate.ptProng1(), candidate.tpcTofNSigmaKa1()); } if (candidate.isSelD0bar() >= selectionFlagD0bar) { - registry.fill(HIST("PID/hTofNSigmaPi"), candidate.ptProng1(), prong1.tofNSigmaPi()); - registry.fill(HIST("PID/hTofNSigmaKa"), candidate.ptProng0(), prong0.tofNSigmaKa()); - registry.fill(HIST("PID/hTpcNSigmaPi"), candidate.ptProng1(), prong1.tpcNSigmaPi()); - registry.fill(HIST("PID/hTpcNSigmaKa"), candidate.ptProng0(), prong0.tpcNSigmaKa()); - registry.fill(HIST("PID/hTpcTofNSigmaPi"), candidate.ptProng1(), prong1.tpcTofNSigmaPi()); - registry.fill(HIST("PID/hTpcTofNSigmaKa"), candidate.ptProng0(), prong0.tpcTofNSigmaKa()); + registry.fill(HIST("PID/hTofNSigmaPi"), candidate.ptProng1(), candidate.nSigTofPi1()); + registry.fill(HIST("PID/hTofNSigmaKa"), candidate.ptProng0(), candidate.nSigTofKa0()); + registry.fill(HIST("PID/hTpcNSigmaPi"), candidate.ptProng1(), candidate.nSigTpcPi1()); + registry.fill(HIST("PID/hTpcNSigmaKa"), candidate.ptProng0(), candidate.nSigTpcKa0()); + registry.fill(HIST("PID/hTpcTofNSigmaPi"), candidate.ptProng1(), candidate.tpcTofNSigmaPi1()); + registry.fill(HIST("PID/hTpcTofNSigmaKa"), candidate.ptProng0(), candidate.tpcTofNSigmaKa0()); } } /// Fill counters for D0 and D0bar /// \param selectedD0Candidates contains all D0 candidates template - void GetCountersPerEvent(const T& selectedD0Candidates) + void getCountersPerEvent(const T& selectedD0Candidates) { int nDevent = 0, nDbarevent = 0, nDDbarevent = 0, nDorDbarevent = 0; for (const auto& candidate : selectedD0Candidates) { @@ -316,19 +406,12 @@ struct HfCorrelatorDMesonPairs { } auto candidateType1 = assignCandidateTypeD0(candidate); // Candidate type attribution registry.fill(HIST("hPtCand"), candidate.pt()); - if (abs(hfHelper.yD0(candidate)) > yCandMax) { + if (std::abs(hfHelper.yD0(candidate)) > yCandMax) { continue; } if (ptCandMin >= 0. && candidate.pt() < ptCandMin) { continue; } - registry.fill(HIST("hPtProng0"), candidate.ptProng0()); - registry.fill(HIST("hPtProng1"), candidate.ptProng1()); - registry.fill(HIST("hEta"), candidate.eta()); - registry.fill(HIST("hPhi"), candidate.phi()); - registry.fill(HIST("hY"), candidate.y(MassD0)); - registry.fill(HIST("hPtCandAfterCut"), candidate.pt()); - registry.fill(HIST("hMass"), hfHelper.invMassD0ToPiK(candidate), candidate.pt()); bool isDCand1 = isD(candidateType1); bool isDbarCand1 = isDbar(candidateType1); @@ -370,11 +453,9 @@ struct HfCorrelatorDMesonPairs { } /// Fill selection status histogram - /// \param candidate1 is the first candidate of the pair - /// \param candidate2 is the second candidate of the pair - template - void fillEntry(const T& candidate1, const T& candidate2, const bool& isDCand1, const bool& isDbarCand1, - const bool& isDCand2, const bool& isDbarCand2, const uint8_t& candidateType1, const uint8_t& candidateType2) + void fillEntry(const bool& isDCand1, const bool& isDbarCand1, const bool& isDCand2, const bool& isDbarCand2, + const uint8_t& candidateType1, const uint8_t& candidateType2, float yCand1, float yCand2, float phiCand1, float phiCand2, + double ptCand1, double ptCand2, float massDCand1, float massDbarCand1, float massDCand2, float massDbarCand2) { /// Fill information on the D candidates @@ -399,12 +480,6 @@ struct HfCorrelatorDMesonPairs { /// Collect information on the D pairs uint8_t pairType(0); registry.fill(HIST("hSelectionStatus"), 1); - float yCand1 = hfHelper.yD0(candidate1); - float yCand2 = hfHelper.yD0(candidate2); - float massDCand1 = hfHelper.invMassD0ToPiK(candidate1); - float massDbarCand1 = hfHelper.invMassD0barToKPi(candidate1); - float massDCand2 = hfHelper.invMassD0ToPiK(candidate2); - float massDbarCand2 = hfHelper.invMassD0barToKPi(candidate2); if (isDCand1 && isDCand2) { SETBIT(pairType, DD); registry.fill(HIST("hSelectionStatus"), 14); @@ -434,31 +509,77 @@ struct HfCorrelatorDMesonPairs { } } - entryD0Pair(candidate1.pt(), candidate2.pt(), yCand1, yCand2, massDCand1, massDbarCand1, massDCand2, massDbarCand2, pairType, candidateType1, candidateType2); + entryD0Pair(ptCand1, ptCand2, yCand1, yCand2, phiCand1, phiCand2, massDCand1, massDbarCand1, massDCand2, massDbarCand2, pairType, candidateType1, candidateType2); + } + + void fillMcHistos(int8_t matchedRec1, int8_t matchedRec2, int8_t isTrueDCand1, int8_t isTrueDbarCand1, int8_t isTrueDCand2, int8_t isTrueDbarCand2) + { + // Fill hMatchingMcRec - Cand 1 + registry.fill(HIST("hMatchingMcRec"), 1); + if (matchedRec1 == 1) { + registry.fill(HIST("hMatchingMcRec"), 2); + } else if (matchedRec1 == -1) { + registry.fill(HIST("hMatchingMcRec"), 3); + } else if (matchedRec1 == 0) { + registry.fill(HIST("hMatchingMcRec"), 4); + } + // Fill hMatchingMcRec - Cand 2 + registry.fill(HIST("hMatchingMcRec"), 5); + if (matchedRec2 == 1) { + registry.fill(HIST("hMatchingMcRec"), 6); + } else if (matchedRec2 == -1) { + registry.fill(HIST("hMatchingMcRec"), 7); + } else if (matchedRec2 == 0) { + registry.fill(HIST("hMatchingMcRec"), 8); + } + // Fill True info + if (isTrueDCand1) { + registry.fill(HIST("hSelectionStatus"), 6); + } else if (isTrueDbarCand1) { + registry.fill(HIST("hSelectionStatus"), 7); + } + if (isTrueDCand2) { + registry.fill(HIST("hSelectionStatus"), 12); + } else if (isTrueDbarCand2) { + registry.fill(HIST("hSelectionStatus"), 13); + } + if (isTrueDCand1 && isTrueDCand2) { + registry.fill(HIST("hSelectionStatus"), 22); + } else if (isTrueDbarCand1 && isTrueDbarCand2) { + registry.fill(HIST("hSelectionStatus"), 23); + } else if (isTrueDCand1 && isTrueDbarCand2) { + registry.fill(HIST("hSelectionStatus"), 24); + } else if (isTrueDbarCand1 && isTrueDCand2) { + registry.fill(HIST("hSelectionStatus"), 25); + } } /// D0(bar)-D0(bar) correlation pair builder - for real data and data-like analysis (i.e. reco-level w/o matching request via MC truth) void processData(aod::Collision const& collision, - soa::Join const& candidates, TracksWPid const&) + soa::Join const& candidates, aod::Tracks const&) { for (const auto& candidate : candidates) { - AnalysePid(candidate); + analysePid(candidate); } auto selectedD0CandidatesGrouped = selectedD0Candidates->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); - GetCountersPerEvent(selectedD0CandidatesGrouped); + getCountersPerEvent(selectedD0CandidatesGrouped); // protection against empty tables to be sliced if (selectedD0Candidates.size() <= 1) { return; } for (const auto& candidate1 : selectedD0CandidatesGrouped) { - if (abs(hfHelper.yD0(candidate1)) > yCandMax) { + + outputMlD0Cand1.clear(); + outputMlD0barCand1.clear(); + + if (std::abs(hfHelper.yD0(candidate1)) > yCandMax) { continue; } if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { continue; } - auto prong0Cand1 = candidate1.template prong0_as(); - auto prong1Cand1 = candidate1.template prong1_as(); + auto prong0Cand1 = candidate1.template prong0_as(); + auto prong1Cand1 = candidate1.template prong1_as(); bool isSignalD0Cand1 = std::abs(hfHelper.invMassD0ToPiK(candidate1) - MassD0) < massCut; bool isSignalD0barCand1 = std::abs(hfHelper.invMassD0barToKPi(candidate1) - MassD0Bar) < massCut; @@ -470,15 +591,68 @@ struct HfCorrelatorDMesonPairs { bool isDCand1 = isD(candidateType1); bool isDbarCand1 = isDbar(candidateType1); + bool isSelectedMlD0Cand1 = false; + bool isSelectedMlD0barCand1 = false; + + if (applyMl) { + if (isDCand1) { + std::vector inputFeaturesD0 = hfMlResponse.getInputFeatures(candidate1, o2::constants::physics::kD0); + isSelectedMlD0Cand1 = hfMlResponse.isSelectedMl(inputFeaturesD0, candidate1.pt(), outputMlD0Cand1); + } + if (isDbarCand1) { + std::vector inputFeaturesD0bar = hfMlResponse.getInputFeatures(candidate1, o2::constants::physics::kD0Bar); + isSelectedMlD0barCand1 = hfMlResponse.isSelectedMl(inputFeaturesD0bar, candidate1.pt(), outputMlD0barCand1); + } + + // Remove non-ML selected D0 candidates + if (!isSelectedMlD0Cand1 && !isSelectedMlD0barCand1) { + continue; + } + } + + // Remove ambiguous D0 candidates if flag is true + if (removeAmbiguous && (isDCand1 && isDbarCand1)) { + continue; + } + + registry.fill(HIST("hPtProng0"), candidate1.ptProng0()); + registry.fill(HIST("hPtProng1"), candidate1.ptProng1()); + registry.fill(HIST("hEta"), candidate1.eta()); + registry.fill(HIST("hPhi"), candidate1.phi()); + registry.fill(HIST("hY"), candidate1.y(MassD0)); + registry.fill(HIST("hPtCandAfterCut"), candidate1.pt()); + registry.fill(HIST("hPVContrib"), collision.numContrib()); + + if (isDCand1) { + registry.fill(HIST("hMass"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt()); + if (applyMl) { + registry.fill(HIST("hnDMesonMl"), outputMlD0Cand1[0], outputMlD0Cand1[1], hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), candidate1.y(MassD0), collision.numContrib(), 0, candidateType1); + } else { + registry.fill(HIST("hnDMeson"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), candidate1.y(MassD0), collision.numContrib(), 0, candidateType1); + } + } + if (isDbarCand1) { + registry.fill(HIST("hMass"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt()); + if (applyMl) { + registry.fill(HIST("hnDMesonMl"), outputMlD0barCand1[0], outputMlD0barCand1[1], hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), candidate1.y(MassD0), collision.numContrib(), 0, candidateType1); + } else { + registry.fill(HIST("hnDMeson"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), candidate1.y(MassD0), collision.numContrib(), 0, candidateType1); + } + } + for (auto candidate2 = candidate1 + 1; candidate2 != selectedD0CandidatesGrouped.end(); ++candidate2) { - if (abs(hfHelper.yD0(candidate2)) > yCandMax) { + + outputMlD0Cand2.clear(); + outputMlD0barCand2.clear(); + + if (std::abs(hfHelper.yD0(candidate2)) > yCandMax) { continue; } if (ptCandMin >= 0. && candidate2.pt() < ptCandMin) { continue; } - auto prong0Cand2 = candidate2.template prong0_as(); - auto prong1Cand2 = candidate2.template prong1_as(); + auto prong0Cand2 = candidate2.template prong0_as(); + auto prong1Cand2 = candidate2.template prong1_as(); if (daughterTracksCutFlag && ((prong0Cand1 == prong0Cand2) || (prong1Cand1 == prong1Cand2) || (prong0Cand1 == prong1Cand2) || (prong1Cand1 == prong0Cand2))) { continue; } @@ -493,39 +667,84 @@ struct HfCorrelatorDMesonPairs { bool isDCand2 = isD(candidateType2); bool isDbarCand2 = isDbar(candidateType2); - fillEntry(candidate1, candidate2, isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2); + bool isSelectedMlD0Cand2 = false; + bool isSelectedMlD0barCand2 = false; + + if (applyMl) { + if (isDCand2) { + std::vector inputFeaturesD0 = hfMlResponse.getInputFeatures(candidate2, o2::constants::physics::kD0); + isSelectedMlD0Cand2 = hfMlResponse.isSelectedMl(inputFeaturesD0, candidate2.pt(), outputMlD0Cand2); + } + if (isDbarCand2) { + std::vector inputFeaturesD0bar = hfMlResponse.getInputFeatures(candidate2, o2::constants::physics::kD0Bar); + isSelectedMlD0barCand2 = hfMlResponse.isSelectedMl(inputFeaturesD0bar, candidate2.pt(), outputMlD0barCand2); + } + + // Remove non-ML selected D0 candidates + if (!isSelectedMlD0Cand2 && !isSelectedMlD0barCand2) { + continue; + } + + // Remove ambiguous D0 candidates if flag is true + if (removeAmbiguous && (isDCand2 && isDbarCand2)) { + continue; + } + + fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, hfHelper.yD0(candidate1), hfHelper.yD0(candidate2), + candidate1.phi(), candidate2.phi(), candidate1.pt(), candidate2.pt(), hfHelper.invMassD0ToPiK(candidate1), hfHelper.invMassD0barToKPi(candidate1), + hfHelper.invMassD0ToPiK(candidate2), hfHelper.invMassD0barToKPi(candidate2)); + + entryD0PairMl(outputMlD0Cand1, outputMlD0barCand1, outputMlD0Cand2, outputMlD0barCand2); + } else { + // Fill entries + fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, hfHelper.yD0(candidate1), hfHelper.yD0(candidate2), candidate1.phi(), candidate2.phi(), + candidate1.pt(), candidate2.pt(), hfHelper.invMassD0ToPiK(candidate1), hfHelper.invMassD0barToKPi(candidate1), + hfHelper.invMassD0ToPiK(candidate2), hfHelper.invMassD0barToKPi(candidate2)); + } } // end inner loop (Cand2) - } // end outer loop (Cand1) + } // end outer loop (Cand1) } PROCESS_SWITCH(HfCorrelatorDMesonPairs, processData, "Process data mode", true); - void processMcRec(aod::Collision const& collision, soa::Join const& candidates, TracksWPid const&) + void processMcRec(aod::Collision const& collision, soa::Join const& candidates, aod::Tracks const&) { for (const auto& candidate : candidates) { - AnalysePid(candidate); + analysePid(candidate); } auto selectedD0CandidatesGroupedMc = selectedD0CandidatesMc->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); - GetCountersPerEvent(selectedD0CandidatesGroupedMc); + getCountersPerEvent(selectedD0CandidatesGroupedMc); // protection against empty tables to be sliced if (selectedD0CandidatesMc.size() <= 1) { return; } for (const auto& candidate1 : selectedD0CandidatesGroupedMc) { - if (abs(hfHelper.yD0(candidate1)) > yCandMax) { + + outputMlD0Cand1.clear(); + outputMlD0barCand1.clear(); + + auto ptCandidate1 = candidate1.pt(); + auto yCandidate1 = hfHelper.yD0(candidate1); + auto phiCandidate1 = candidate1.phi(); + float massD0Cand1 = hfHelper.invMassD0ToPiK(candidate1); + float massD0barCand1 = hfHelper.invMassD0barToKPi(candidate1); + auto prong0Cand1 = candidate1.template prong0_as(); + auto prong1Cand1 = candidate1.template prong1_as(); + + if (std::abs(hfHelper.yD0(candidate1)) > yCandMax) { continue; } if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { continue; } - auto prong0Cand1 = candidate1.template prong0_as(); - auto prong1Cand1 = candidate1.template prong1_as(); - - bool isSignalD0Cand1 = std::abs(hfHelper.invMassD0ToPiK(candidate1) - MassD0) < massCut; - bool isSignalD0barCand1 = std::abs(hfHelper.invMassD0barToKPi(candidate1) - MassD0Bar) < massCut; + bool isSignalD0Cand1 = std::abs(massD0Cand1 - MassD0) < massCut; + bool isSignalD0barCand1 = std::abs(massD0barCand1 - MassD0Bar) < massCut; if (selectSignalRegionOnly && !(isSignalD0Cand1 || isSignalD0barCand1)) { continue; } + if (!(candidate1.isSelD0() >= selectionFlagD0 || candidate1.isSelD0bar() >= selectionFlagD0bar)) { + continue; + } auto candidateType1 = assignCandidateTypeD0(candidate1); // Candidate type attribution @@ -537,28 +756,111 @@ struct HfCorrelatorDMesonPairs { int8_t matchedRec1 = candidate1.flagMcMatchRec(); int8_t originRec1 = candidate1.originMcRec(); + bool isSelectedMlD0Cand1 = false; + bool isSelectedMlD0barCand1 = false; + + if (applyMl) { + if (isDCand1) { + std::vector inputFeaturesD0 = hfMlResponse.getInputFeatures(candidate1, o2::constants::physics::kD0); + isSelectedMlD0Cand1 = hfMlResponse.isSelectedMl(inputFeaturesD0, candidate1.pt(), outputMlD0Cand1); + } + if (isDbarCand1) { + std::vector inputFeaturesD0bar = hfMlResponse.getInputFeatures(candidate1, o2::constants::physics::kD0Bar); + isSelectedMlD0barCand1 = hfMlResponse.isSelectedMl(inputFeaturesD0bar, candidate1.pt(), outputMlD0barCand1); + } + // Remove non-ML selected D0 candidates + if (!isSelectedMlD0Cand1 && !isSelectedMlD0barCand1) { + continue; + } + } + + // Remove ambiguous D0 candidates if flag is true + if (removeAmbiguous && (isDCand1 && isDbarCand1)) { + continue; + } + if (isTrueDCand1) { registry.fill(HIST("hStatusSinglePart"), 5); } else if (isTrueDbarCand1) { registry.fill(HIST("hStatusSinglePart"), 6); } + registry.fill(HIST("hPtProng0"), candidate1.ptProng0()); + registry.fill(HIST("hPtProng1"), candidate1.ptProng1()); + registry.fill(HIST("hEta"), candidate1.eta()); + registry.fill(HIST("hPhi"), candidate1.phi()); + registry.fill(HIST("hY"), candidate1.y(MassD0)); + registry.fill(HIST("hPtCandAfterCut"), candidate1.pt()); + + if (isDCand1) { + if (applyMl) { + registry.fill(HIST("hnDMesonMl"), outputMlD0Cand1[0], outputMlD0Cand1[1], hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), candidate1.y(MassD0), collision.numContrib(), originRec1, candidateType1); + } else { + registry.fill(HIST("hnDMeson"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), candidate1.y(MassD0), collision.numContrib(), originRec1, candidateType1); + } + if (isTrueDCand1) { + registry.fill(HIST("hMass"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt()); + registry.fill(HIST("hPtVsYVsNContribMcRec"), candidate1.pt(), hfHelper.yD0(candidate1), collision.numContrib()); + registry.fill(HIST("hNContribMcRec"), collision.numContrib()); + if (originRec1 == 1) { + registry.fill(HIST("hMassMcRecPrompt"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt()); + registry.fill(HIST("hPtVsYVsNContribMcRecPrompt"), candidate1.pt(), hfHelper.yD0(candidate1), collision.numContrib()); + } else if (originRec1 == 2) { + registry.fill(HIST("hMassMcRecNonPrompt"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt()); + registry.fill(HIST("hPtVsYVsNContribMcRecNonPrompt"), candidate1.pt(), hfHelper.yD0(candidate1), collision.numContrib()); + } + } else if (isTrueDbarCand1) { + registry.fill(HIST("hMassMcRecReflections"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt()); + } + } + if (isDbarCand1) { + if (applyMl) { + registry.fill(HIST("hnDMesonMl"), outputMlD0barCand1[0], outputMlD0barCand1[1], hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), candidate1.y(MassD0), collision.numContrib(), originRec1, candidateType1); + } else { + registry.fill(HIST("hnDMeson"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), candidate1.y(MassD0), collision.numContrib(), originRec1, candidateType1); + } + if (isTrueDbarCand1) { + registry.fill(HIST("hMass"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt()); + registry.fill(HIST("hPtVsYVsNContribMcRec"), candidate1.pt(), hfHelper.yD0(candidate1), collision.numContrib()); + registry.fill(HIST("hNContribMcRec"), collision.numContrib()); + if (originRec1 == 1) { + registry.fill(HIST("hMassMcRecPrompt"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt()); + } else if (originRec1 == 2) { + registry.fill(HIST("hMassMcRecNonPrompt"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt()); + } + } else if (isTrueDCand1) { + registry.fill(HIST("hMassMcRecReflections"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt()); + } + } + for (auto candidate2 = candidate1 + 1; candidate2 != selectedD0CandidatesGroupedMc.end(); ++candidate2) { - if (abs(hfHelper.yD0(candidate2)) > yCandMax) { + + outputMlD0Cand2.clear(); + outputMlD0barCand2.clear(); + + auto ptCandidate2 = candidate2.pt(); + auto yCandidate2 = hfHelper.yD0(candidate2); + auto phiCandidate2 = candidate2.phi(); + float massD0Cand2 = hfHelper.invMassD0ToPiK(candidate2); + float massD0barCand2 = hfHelper.invMassD0barToKPi(candidate2); + auto prong0Cand2 = candidate2.template prong0_as(); + auto prong1Cand2 = candidate2.template prong1_as(); + + if (std::abs(hfHelper.yD0(candidate2)) > yCandMax) { continue; } if (ptCandMin >= 0. && candidate2.pt() < ptCandMin) { continue; } - auto prong0Cand2 = candidate2.template prong0_as(); - auto prong1Cand2 = candidate2.template prong1_as(); - if (daughterTracksCutFlag && ((prong0Cand1 == prong0Cand2) || (prong1Cand1 == prong1Cand2) || (prong0Cand1 == prong1Cand2) || (prong1Cand1 == prong0Cand2))) { + bool isSignalD0Cand2 = std::abs(massD0Cand2 - MassD0) < massCut; + bool isSignalD0barCand2 = std::abs(massD0barCand2 - MassD0Bar) < massCut; + if (selectSignalRegionOnly && !(isSignalD0Cand2 || isSignalD0barCand2)) { continue; } - - bool isSignalD0Cand2 = std::abs(hfHelper.invMassD0ToPiK(candidate2) - MassD0) < massCut; - bool isSignalD0barCand2 = std::abs(hfHelper.invMassD0barToKPi(candidate2) - MassD0Bar) < massCut; - if (selectSignalRegionOnly && !(isSignalD0Cand2 || isSignalD0barCand2)) { + if (!(candidate2.isSelD0() >= selectionFlagD0 || candidate2.isSelD0bar() >= selectionFlagD0bar)) { + continue; + } + if (daughterTracksCutFlag && ((prong0Cand1 == prong0Cand2) || (prong1Cand1 == prong1Cand2) || (prong0Cand1 == prong1Cand2) || (prong1Cand1 == prong0Cand2))) { continue; } auto candidateType2 = assignCandidateTypeD0(candidate2); // Candidate type attribution @@ -571,54 +873,59 @@ struct HfCorrelatorDMesonPairs { int8_t matchedRec2 = candidate2.flagMcMatchRec(); int8_t originRec2 = candidate2.originMcRec(); - // Fill hMatchingMcRec - Cand 1 - registry.fill(HIST("hMatchingMcRec"), 1); - if (matchedRec1 == 1) { - registry.fill(HIST("hMatchingMcRec"), 2); - } else if (matchedRec1 == -1) { - registry.fill(HIST("hMatchingMcRec"), 3); - } else if (matchedRec1 == 0) { - registry.fill(HIST("hMatchingMcRec"), 4); + bool isSelectedMlD0Cand2 = false; + bool isSelectedMlD0barCand2 = false; + + if (applyMl) { + if (isDCand2) { + std::vector inputFeaturesD0 = hfMlResponse.getInputFeatures(candidate2, o2::constants::physics::kD0); + isSelectedMlD0Cand2 = hfMlResponse.isSelectedMl(inputFeaturesD0, candidate2.pt(), outputMlD0Cand2); + } + if (isDbarCand2) { + std::vector inputFeaturesD0bar = hfMlResponse.getInputFeatures(candidate2, o2::constants::physics::kD0Bar); + isSelectedMlD0barCand2 = hfMlResponse.isSelectedMl(inputFeaturesD0bar, candidate2.pt(), outputMlD0barCand2); + } + + // Remove non-ML selected D0 candidates + if (!isSelectedMlD0Cand2 && !isSelectedMlD0barCand2) { + continue; + } + + // Remove ambiguous D0 candidates if flag is true + if (removeAmbiguous && (isDCand2 && isDbarCand2)) { + continue; + } + + // Fill tables + fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, yCandidate1, yCandidate2, phiCandidate1, phiCandidate2, + ptCandidate1, ptCandidate2, massD0Cand1, massD0barCand1, massD0Cand2, massD0barCand2); + fillMcHistos(matchedRec1, matchedRec2, isTrueDCand1, isTrueDbarCand1, isTrueDCand2, isTrueDbarCand2); + entryD0PairMcInfo(originRec1, originRec2, matchedRec1, matchedRec2); + entryD0PairMl(outputMlD0Cand1, outputMlD0barCand1, outputMlD0Cand2, outputMlD0barCand2); + + } else { + // Fill tables + fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, yCandidate1, yCandidate2, phiCandidate1, phiCandidate2, + ptCandidate1, ptCandidate2, massD0Cand1, massD0barCand1, massD0Cand2, massD0barCand2); + fillMcHistos(matchedRec1, matchedRec2, isTrueDCand1, isTrueDbarCand1, isTrueDCand2, isTrueDbarCand2); + entryD0PairMcInfo(originRec1, originRec2, matchedRec1, matchedRec2); } - // Fill hMatchingMcRec - Cand 2 - registry.fill(HIST("hMatchingMcRec"), 5); - if (matchedRec2 == 1) { - registry.fill(HIST("hMatchingMcRec"), 6); - } else if (matchedRec2 == -1) { - registry.fill(HIST("hMatchingMcRec"), 7); - } else if (matchedRec2 == 0) { - registry.fill(HIST("hMatchingMcRec"), 8); - } - // Fill True info - if (isTrueDCand1) { - registry.fill(HIST("hSelectionStatus"), 6); - } else if (isTrueDbarCand1) { - registry.fill(HIST("hSelectionStatus"), 7); - } - if (isTrueDCand2) { - registry.fill(HIST("hSelectionStatus"), 12); - } else if (isTrueDbarCand2) { - registry.fill(HIST("hSelectionStatus"), 13); - } - if (isTrueDCand1 && isTrueDCand2) { - registry.fill(HIST("hSelectionStatus"), 22); - } else if (isTrueDbarCand1 && isTrueDbarCand2) { - registry.fill(HIST("hSelectionStatus"), 23); - } else if (isTrueDCand1 && isTrueDbarCand2) { - registry.fill(HIST("hSelectionStatus"), 24); - } else if (isTrueDbarCand1 && isTrueDCand2) { - registry.fill(HIST("hSelectionStatus"), 25); - } - fillEntry(candidate1, candidate2, isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2); - entryD0PairMcInfo(originRec1, originRec2, matchedRec1, matchedRec2); } // end inner loop (Cand2) - } // end outer loop (Cand1) + } // end outer loop (Cand1) } PROCESS_SWITCH(HfCorrelatorDMesonPairs, processMcRec, "Process Mc reco mode", false); - void processMcGen(aod::McCollision const&, McParticlesPlus2Prong const& mcParticles) + void processMcGen(aod::McCollision const&, soa::SmallGroups> const& collisions, McParticlesPlus2Prong const& mcParticles) { + int numPvContributorsGen{0}; + for (const auto& collision : collisions) { // loop over reco collisions associated to this gen collision + int numPvContributors = collision.numContrib(); + + if (numPvContributors > numPvContributorsGen) { // we take the associated reconstructed collision with higher number of PV contributors + numPvContributorsGen = numPvContributors; + } + } // Get counters per event int nDevent = 0, nDbarevent = 0, nDDbarevent = 0, nDorDbarevent = 0; for (const auto& particle : mcParticles) { @@ -626,7 +933,7 @@ struct HfCorrelatorDMesonPairs { if (std::abs(particle.pdgCode()) != Pdg::kD0) { continue; } - if (abs(particle.y()) > yCandMax) { + if (std::abs(particle.y()) > yCandMax) { continue; } if (ptCandMin >= 0. && particle.pt() < ptCandMin) { @@ -671,7 +978,7 @@ struct HfCorrelatorDMesonPairs { } registry.fill(HIST("hPtCandMcGen"), particle1.pt()); - if (abs(particle1.y()) > yCandMax) { + if (std::abs(particle1.y()) > yCandMax) { continue; } if (ptCandMin >= 0. && particle1.pt() < ptCandMin) { @@ -702,12 +1009,21 @@ struct HfCorrelatorDMesonPairs { registry.fill(HIST("hStatusSinglePartMcGen"), 4); } + registry.fill(HIST("hPtVsYVsNContribMcGen"), particle1.pt(), particle1.y(), numPvContributorsGen); + if (originGen1 == 1) { + registry.fill(HIST("hPtVsYVsNContribMcGenPrompt"), particle1.pt(), particle1.y(), numPvContributorsGen); + } + if (originGen1 == 2) { + registry.fill(HIST("hPtVsYVsNContribMcGenNonPrompt"), particle1.pt(), particle1.y(), numPvContributorsGen); + } + registry.fill(HIST("hNContribMcGen"), numPvContributorsGen); + for (auto particle2 = particle1 + 1; particle2 != mcParticles.end(); ++particle2) { // check if the particle is D0 or D0bar if (std::abs(particle2.pdgCode()) != Pdg::kD0) { continue; } - if (abs(particle2.y()) > yCandMax) { + if (std::abs(particle2.y()) > yCandMax) { continue; } if (ptCandMin >= 0. && particle2.pt() < ptCandMin) { @@ -780,11 +1096,11 @@ struct HfCorrelatorDMesonPairs { } // Fill pair Selection Status - entryD0PairMcGen(particle1.pt(), particle2.pt(), particle1.y(), particle2.y(), massD, massDbar, massD, massDbar, pairType, particleType1, particleType2); + entryD0PairMcGen(particle1.pt(), particle2.pt(), particle1.y(), particle2.y(), particle1.phi(), particle2.phi(), massD, massDbar, massD, massDbar, pairType, particleType1, particleType2); entryD0PairMcGenInfo(originGen1, originGen2, matchedGen1, matchedGen2); } // end inner loop - } // end outer loop + } // end outer loop } PROCESS_SWITCH(HfCorrelatorDMesonPairs, processMcGen, "Process D0 Mc Gen mode", false); diff --git a/PWGHF/HFC/TableProducer/correlatorDplusDminus.cxx b/PWGHF/HFC/TableProducer/correlatorDplusDminus.cxx index cb70b35e9ad..2871d9f9793 100644 --- a/PWGHF/HFC/TableProducer/correlatorDplusDminus.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDplusDminus.cxx @@ -14,6 +14,8 @@ /// /// \author Fabio Colamaria , INFN Bari +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" @@ -48,7 +50,7 @@ const double incrementEtaCut = 0.1; const double incrementPtThreshold = 0.5; const double epsilon = 1E-5; -const int npTBinsMassAndEfficiency = o2::analysis::hf_cuts_dplus_to_pi_k_pi::nBinsPt; +const int npTBinsMassAndEfficiency = o2::analysis::hf_cuts_dplus_to_pi_k_pi::NBinsPt; const double efficiencyDmesonDefault[npTBinsMassAndEfficiency] = {}; auto efficiencyDmeson_v = std::vector{efficiencyDmesonDefault, efficiencyDmesonDefault + npTBinsMassAndEfficiency}; @@ -241,7 +243,7 @@ struct HfCorrelatorDplusDminus { } while (ptCut < ptThresholdForMaxEtaCut - epsilon); } while (etaCut < maxEtaCut - epsilon); } // end inner loop (Dminus) - } // end outer loop (Dplus) + } // end outer loop (Dplus) } PROCESS_SWITCH(HfCorrelatorDplusDminus, processData, "Process data", false); @@ -458,7 +460,7 @@ struct HfCorrelatorDplusDminus { } while (ptCut < ptThresholdForMaxEtaCut - epsilon); } while (etaCut < maxEtaCut - epsilon); } // end inner loop - } // end outer loop + } // end outer loop registry.fill(HIST("hCountDplusDminusPerEvent"), counterDplusDminus); } PROCESS_SWITCH(HfCorrelatorDplusDminus, processMcGen, "Process MC Gen mode", false); @@ -522,8 +524,8 @@ struct HfCorrelatorDplusDminus { entryDplusDminusRecoInfo(1.869, 1.869, 8); // Dummy - } // end inner loop - } // end outer loop + } // end inner loop + } // end outer loop registry.fill(HIST("hCountCCbarPerEvent"), counterCCbar); registry.fill(HIST("hCountCCbarPerEventBeforeEtaCut"), counterCCbarBeforeEtasel); } diff --git a/PWGHF/HFC/TableProducer/correlatorDplusHadrons.cxx b/PWGHF/HFC/TableProducer/correlatorDplusHadrons.cxx index 506ad6db4d8..d9ac67f59ae 100644 --- a/PWGHF/HFC/TableProducer/correlatorDplusHadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDplusHadrons.cxx @@ -12,6 +12,8 @@ /// \file correlatorDplusHadrons.cxx /// \author Shyam Kumar +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" @@ -31,6 +33,7 @@ using namespace o2; using namespace o2::analysis; using namespace o2::constants::physics; +using namespace o2::constants::math; using namespace o2::framework; using namespace o2::framework::expressions; @@ -42,89 +45,93 @@ double getDeltaPhi(double phiD, double phiHadron) } /// definition of variables for Dplus hadron pairs (in data-like, MC-reco and MC-kine tasks) -const int npTBinsMassAndEfficiency = o2::analysis::hf_cuts_dplus_to_pi_k_pi::nBinsPt; +const int npTBinsMassAndEfficiency = o2::analysis::hf_cuts_dplus_to_pi_k_pi::NBinsPt; std::vector efficiencyDmeson(npTBinsMassAndEfficiency + 1); -// histogram binning definition -const int massAxisBins = 350; -const double massAxisMin = 1.7; -const double massAxisMax = 2.05; -const int phiAxisBins = 32; -const double phiAxisMin = -o2::constants::math::PIHalf; -const double phiAxisMax = 3. * o2::constants::math::PIHalf; -const int yAxisBins = 100; -const double yAxisMin = -2.; -const double yAxisMax = 2.; -const int ptDAxisBins = 180; -const double ptDAxisMin = 0.; -const double ptDAxisMax = 36.; - // definition of ME variables using BinningType = ColumnBinningPolicy>; +using BinningTypeMcGen = ColumnBinningPolicy; // Code to select a Dmeson in a collision struct HfCorrelatorDplusHadronsDplusSelection { Produces dplusSel; - Configurable selectionFlagDplus{"selectionFlagDplus", 7, "Selection Flag for Dplus"}; // 7 corresponds to topo+PID cuts + Configurable useSel8{"useSel8", true, "Flag for applying sel8 for collision selection"}; + Configurable selNoSameBunchPileUpColl{"selNoSameBunchPileUpColl", true, "Flag for rejecting the collisions associated with the same bunch crossing"}; + Configurable doSelDplusCollision{"doSelDplusCollision", true, "Select collisions with at least one D+"}; + Configurable selectionFlagDplus{"selectionFlagDplus", 7, "Selection Flag for D+"}; Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity"}; Configurable ptCandMin{"ptCandMin", 1., "min. cand. pT"}; HfHelper hfHelper; SliceCache cache; - Partition> selectedDplusCandidates = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; - Partition> selectedDplusCandidatesMc = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; + using SelCollisions = soa::Join; + using CandidatesDplusData = soa::Filtered>; + using CandidatesDplusMcRec = soa::Filtered>; + using CandDplusMcGen = soa::Join; - void processDplusSelectionData(aod::Collision const& collision, - soa::Join const&) - { - bool isDplusFound = 0; - if (selectedDplusCandidates.size() > 0) { - auto selectedDplusCandidatesGrouped = selectedDplusCandidates->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); + // filter on selection of Dplus meson and decay channel Dplus->KPiPi + Filter dplusFilter = ((o2::aod::hf_track_index::hfflag & static_cast(1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi)) != static_cast(0)) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; - for (const auto& candidate1 : selectedDplusCandidatesGrouped) { - if (yCandMax >= 0. && std::abs(hfHelper.yDplus(candidate1)) > yCandMax) { - continue; - } - if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { + void processDplusSelectionData(SelCollisions::iterator const& collision, + CandidatesDplusData const& candidates) + { + bool isSelColl = true; + bool isDplusFound = true; + bool isSel8 = true; + bool isNosameBunchPileUp = true; + if (doSelDplusCollision) { + for (const auto& candidate : candidates) { + if (std::abs(hfHelper.yDplus(candidate)) > yCandMax || candidate.pt() < ptCandMin) { + isDplusFound = false; continue; } - isDplusFound = 1; + isDplusFound = true; break; } } - dplusSel(isDplusFound); + if (useSel8) { + isSel8 = collision.sel8(); + } + if (selNoSameBunchPileUpColl) { + isNosameBunchPileUp = static_cast(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)); + } + isSelColl = isDplusFound && isSel8 && isNosameBunchPileUp; + dplusSel(isSelColl); } PROCESS_SWITCH(HfCorrelatorDplusHadronsDplusSelection, processDplusSelectionData, "Process Dplus Selection Data", false); - void processDplusSelectionMcRec(aod::Collision const& collision, - soa::Join const&) + void processDplusSelectionMcRec(SelCollisions::iterator const& collision, + CandidatesDplusMcRec const& candidates) { - bool isDplusFound = 0; - if (selectedDplusCandidatesMc.size() > 0) { - auto selectedDplusCandidatesMcGrouped = selectedDplusCandidatesMc->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); - for (const auto& candidate1 : selectedDplusCandidatesMcGrouped) { - // check decay channel flag for candidate1 - if (!(candidate1.hfflag() & 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi)) { - continue; - } - if (yCandMax >= 0. && std::abs(hfHelper.yDplus(candidate1)) > yCandMax) { - continue; - } - if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { + bool isSelColl = true; + bool isDplusFound = false; + bool isSel8 = true; + bool isNosameBunchPileUp = true; + if (doSelDplusCollision) { + for (const auto& candidate : candidates) { + if (std::abs(hfHelper.yDplus(candidate)) >= yCandMax || candidate.pt() <= ptCandMin) { continue; } isDplusFound = 1; break; } } - dplusSel(isDplusFound); + if (useSel8) { + isSel8 = collision.sel8(); + } + if (selNoSameBunchPileUpColl) { + isNosameBunchPileUp = static_cast(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)); + } + isSelColl = isDplusFound && isSel8 && isNosameBunchPileUp; + dplusSel(isSelColl); } + PROCESS_SWITCH(HfCorrelatorDplusHadronsDplusSelection, processDplusSelectionMcRec, "Process Dplus Selection MCRec", false); void processDplusSelectionMcGen(aod::McCollision const&, - aod::McParticles const& mcParticles) + CandDplusMcGen const& mcParticles) { bool isDplusFound = 0; for (const auto& particle1 : mcParticles) { @@ -132,10 +139,7 @@ struct HfCorrelatorDplusHadronsDplusSelection { continue; } double yD = RecoDecay::y(particle1.pVector(), MassDPlus); - if (yCandMax >= 0. && std::abs(yD) > yCandMax) { - continue; - } - if (ptCandMin >= 0. && particle1.pt() < ptCandMin) { + if (std::abs(yD) >= yCandMax || particle1.pt() <= ptCandMin) { continue; } isDplusFound = 1; @@ -150,183 +154,224 @@ struct HfCorrelatorDplusHadronsDplusSelection { struct HfCorrelatorDplusHadrons { Produces entryDplusHadronPair; Produces entryDplusHadronRecoInfo; + Produces entryDplusHadronMlInfo; + Produces entryDplusCandRecoInfo; + Produces entryDplusHadronGenInfo; + Produces entryDplusCandGenInfo; + Produces entryTrackRecoInfo; Produces entryDplus; Produces entryHadron; Configurable selectionFlagDplus{"selectionFlagDplus", 7, "Selection Flag for Dplus"}; // 7 corresponds to topo+PID cuts - Configurable applyEfficiency{"applyEfficiency", 1, "Flag for applying D-meson efficiency weights"}; + Configurable numberEventsMixed{"numberEventsMixed", 5, "Number of events mixed in ME process"}; + Configurable applyEfficiency{"applyEfficiency", true, "Flag for applying D-meson efficiency weights"}; + Configurable removeDaughters{"removeDaughters", true, "Flag for removing D-meson daughters from correlations"}; Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity"}; + Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen. cand. rapidity"}; Configurable etaTrackMax{"etaTrackMax", 0.8, "max. eta of tracks"}; Configurable dcaXYTrackMax{"dcaXYTrackMax", 1., "max. DCA_xy of tracks"}; Configurable dcaZTrackMax{"dcaZTrackMax", 1., "max. DCA_z of tracks"}; Configurable ptCandMin{"ptCandMin", 1., "min. cand. pT"}; + Configurable ptCandMax{"ptCandMax", 50., "max. cand pT"}; Configurable ptTrackMin{"ptTrackMin", 0.3, "min. track pT"}; Configurable ptTrackMax{"ptTrackMax", 100., "max. track pT"}; Configurable multMin{"multMin", 0., "minimum multiplicity accepted"}; Configurable multMax{"multMax", 10000., "maximum multiplicity accepted"}; - Configurable> binsPt{"binsPt", std::vector{o2::analysis::hf_cuts_dplus_to_pi_k_pi::vecBinsPt}, "pT bin limits for candidate mass plots and efficiency"}; - Configurable> efficiencyD{"efficiencyD", std::vector{efficiencyDmeson}, "Efficiency values for Dplus meson"}; + Configurable> classMl{"classMl", {0, 1, 2}, "Indexes of ML scores to be stored. Three indexes max."}; + Configurable> binsPtD{"binsPtD", std::vector{o2::analysis::hf_cuts_dplus_to_pi_k_pi::vecBinsPt}, "pT bin limits for candidate mass plots"}; + Configurable> binsPtHadron{"binsPtHadron", std::vector{0.3, 2., 4., 8., 12., 50.}, "pT bin limits for assoc particle"}; + Configurable> binsPtEfficiencyD{"binsPtEfficiencyD", std::vector{o2::analysis::hf_cuts_dplus_to_pi_k_pi::vecBinsPt}, "pT bin limits for efficiency"}; + Configurable> efficiencyD{"efficiencyD", {1., 1., 1., 1., 1., 1.}, "efficiency values for D+ meson"}; ConfigurableAxis binsMultiplicity{"binsMultiplicity", {VARIABLE_WIDTH, 0.0f, 2000.0f, 6000.0f, 100000.0f}, "Mixing bins - multiplicity"}; ConfigurableAxis binsZVtx{"binsZVtx", {VARIABLE_WIDTH, -10.0f, -2.5f, 2.5f, 10.0f}, "Mixing bins - z-vertex"}; ConfigurableAxis binsMultiplicityMc{"binsMultiplicityMc", {VARIABLE_WIDTH, 0.0f, 20.0f, 50.0f, 500.0f}, "Mixing bins - MC multiplicity"}; // In MCGen multiplicity is defined by counting tracks + ConfigurableAxis binsBdtScore{"binsBdtScore", {100, 0., 1.}, "Bdt output scores"}; + ConfigurableAxis binsEta{"binsEta", {50, -2., 2.}, "#it{#eta}"}; + ConfigurableAxis binsPhi{"binsPhi", {64, -PIHalf, 3. * PIHalf}, "#it{#varphi}"}; + ConfigurableAxis binsPoolBin{"binsPoolBin", {9, 0., 9.}, "PoolBin"}; + ConfigurableAxis binsMultFT0M{"binsMultFT0M", {600, 0., 6000.}, "Multiplicity as FT0M signal amplitude"}; + ConfigurableAxis binsMassD{"binsMassD", {200, 1.7, 2.10}, "inv. mass (#pi^{+}K^{-}#pi^{+}) (GeV/#it{c}^{2})"}; HfHelper hfHelper; SliceCache cache; BinningType corrBinning{{binsZVtx, binsMultiplicity}, true}; // Event Mixing for the Data Mode - using SelCollisionsWithDplus = soa::Filtered>; - using TracksWithDca = soa::Filtered>; // track Selection applied - using CandidatesDplusData = soa::Filtered>; + using SelCollisionsWithDplus = soa::Filtered>; + using SelCollisionsWithDplusMc = soa::Filtered>; // collisionFilter applied + using CandidatesDplusData = soa::Filtered>; // Event Mixing for the MCRec Mode - using CandidatesDplusMcRec = soa::Filtered>; + using CandidatesDplusMcRec = soa::Filtered>; + using CandDplusMcGen = soa::Join; // flagDplusFilter applied // Event Mixing for the MCGen Mode using McCollisionsSel = soa::Filtered>; using McParticlesSel = soa::Filtered; + // Tracks used in Data and MC + using TracksData = soa::Filtered>; // trackFilter applied + using TracksWithMc = soa::Filtered>; // trackFilter applied Filter collisionFilter = aod::hf_selection_dmeson_collision::dmesonSel == true; + // filter on selection of Dplus meson and decay channel Dplus->KPiPi + Filter dplusFilter = ((o2::aod::hf_track_index::hfflag & static_cast(1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi)) != static_cast(0)) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; Filter trackFilter = (nabs(aod::track::eta) < etaTrackMax) && (nabs(aod::track::pt) > ptTrackMin) && (nabs(aod::track::dcaXY) < dcaXYTrackMax) && (nabs(aod::track::dcaZ) < dcaZTrackMax); - Filter dplusFilter = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= 1; - Filter collisionFilterGen = aod::hf_selection_dmeson_collision::dmesonSel == true; - Filter particlesFilter = nabs(aod::mcparticle::pdgCode) == 411 || ((aod::mcparticle::flags & (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary) == (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary); + // Filter particlesFilter = nabs(aod::mcparticle::pdgCode) == 411 || ((aod::mcparticle::flags & (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary) == (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary); Preslice perCol = aod::hf_cand::collisionId; - Partition> selectedDplusCandidates = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; - Partition> selectedDplusCandidatesMc = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; - - HistogramRegistry registry{ - "registry", - {{"hPtCand", "Dplus,Hadron candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisBins, ptDAxisMin, ptDAxisMax}}}}, - {"hPtProng0", "Dplus,Hadron candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisBins, ptDAxisMin, ptDAxisMax}}}}, - {"hPtProng1", "Dplus,Hadron candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisBins, ptDAxisMin, ptDAxisMax}}}}, - {"hPtProng2", "Dplus,Hadron candidates;prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisBins, ptDAxisMin, ptDAxisMax}}}}, - {"hSelectionStatus", "Dplus,Hadron candidates;selection status;entries", {HistType::kTH1F, {{4, -0.5, 3.5}}}}, - {"hEta", "Dplus,Hadron candidates;candidate #it{#eta};entries", {HistType::kTH1F, {{yAxisBins, yAxisMin, yAxisMax}}}}, - {"hPhi", "Dplus,Hadron candidates;candidate #it{#varphi};entries", {HistType::kTH1F, {{phiAxisBins, phiAxisMin, phiAxisMax}}}}, - {"hY", "Dplus,Hadron candidates;candidate #it{#y};entries", {HistType::kTH1F, {{yAxisBins, yAxisMin, yAxisMax}}}}, - {"hPtCandMCRec", "Dplus,Hadron candidates - MC reco;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisBins, ptDAxisMin, ptDAxisMax}}}}, - {"hPtProng0MCRec", "Dplus,Hadron candidates - MC reco;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisBins, ptDAxisMin, ptDAxisMax}}}}, - {"hPtProng1MCRec", "Dplus,Hadron candidates - MC reco;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisBins, ptDAxisMin, ptDAxisMax}}}}, - {"hPtProng2MCRec", "Dplus,Hadron candidates - MC reco;prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisBins, ptDAxisMin, ptDAxisMax}}}}, - {"hSelectionStatusMCRec", "Dplus,Hadron candidates - MC reco;selection status;entries", {HistType::kTH1F, {{4, -0.5, 3.5}}}}, - {"hEtaMCRec", "Dplus,Hadron candidates - MC reco;candidate #it{#eta};entries", {HistType::kTH1F, {{yAxisBins, yAxisMin, yAxisMax}}}}, - {"hPhiMCRec", "Dplus,Hadron candidates - MC reco;candidate #it{#varphi};entries", {HistType::kTH1F, {{phiAxisBins, phiAxisMin, phiAxisMax}}}}, - {"hYMCRec", "Dplus,Hadron candidates - MC reco;candidate #it{#y};entries", {HistType::kTH1F, {{yAxisBins, yAxisMin, yAxisMax}}}}, - {"hMCEvtCount", "Event counter - MC gen;;entries", {HistType::kTH1F, {{1, -0.5, 0.5}}}}, - {"hPtCandMCGen", "Dplus,Hadron particles - MC gen;particle #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisBins, ptDAxisMin, ptDAxisMax}}}}, - {"hEtaMCGen", "Dplus,Hadron particles - MC gen;particle #it{#eta};entries", {HistType::kTH1F, {{yAxisBins, yAxisMin, yAxisMax}}}}, - {"hPhiMCGen", "Dplus,Hadron particles - MC gen;particle #it{#varphi};entries", {HistType::kTH1F, {{phiAxisBins, phiAxisMin, phiAxisMax}}}}, - {"hYMCGen", "Dplus,Hadron candidates - MC gen;candidate #it{#y};entries", {HistType::kTH1F, {{yAxisBins, yAxisMin, yAxisMax}}}}, - {"hcountDplusHadronPerEvent", "Dplus,Hadron particles - MC gen;Number per event;entries", {HistType::kTH1F, {{20, 0., 20.}}}}, - {"hMultiplicityPreSelection", "multiplicity prior to selection;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}}, - {"hMultiplicity", "multiplicity;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}}, - {"hMultFT0M", "multiplicity;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}}, - {"hZvtx", "z vertex;z vertex;entries", {HistType::kTH1F, {{200, -20., 20.}}}}, - {"hDplusBin", "Dplus selected in pool Bin;pool Bin;entries", {HistType::kTH1F, {{9, 0., 9.}}}}, - {"hTracksBin", "Tracks selected in pool Bin;pool Bin;entries", {HistType::kTH1F, {{9, 0., 9.}}}}}}; + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext&) { - auto vbins = (std::vector)binsPt; - registry.add("hMassDplus_2D", "Dplus candidates;inv. mass (K^{-}#pi^{+}#pi^{+}) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hMassDplusData", "Dplus candidates;inv. mass (K^{-}#pi^{+}#pi^{+}) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{massAxisBins, massAxisMin, massAxisMax}}}); - registry.add("hMassDplusMCRec", "Dplus candidates;inv. mass (K^{-}#pi^{+}#pi^{+}) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{massAxisBins, massAxisMin, massAxisMax}}}); - registry.add("hMassDplusMCRecSig", "Dplus signal candidates - MC reco;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hMassDplusMCRecBkg", "Dplus background candidates - MC reco;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hcountDplustriggersMCGen", "Dplus trigger particles - MC gen;;N of trigger Dplus", {HistType::kTH2F, {{1, -0.5, 0.5}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + AxisSpec axisMassD = {binsMassD, "inv. mass (pi^{+}K^{-}#pi^{+}) (GeV/#it{c}^{2})"}; + AxisSpec axisEta = {binsEta, "#it{#eta}"}; + AxisSpec axisPhi = {binsPhi, "#it{#varphi}"}; + AxisSpec axisPtD = {(std::vector)binsPtD, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisPtHadron = {(std::vector)binsPtHadron, "#it{p}_{T} Hadron (GeV/#it{c})"}; + AxisSpec axisMultiplicity = {binsMultiplicity, "Multiplicity"}; + AxisSpec axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; + AxisSpec axisPosZ = {binsZVtx, "PosZ"}; + AxisSpec axisBdtScore = {binsBdtScore, "Bdt score"}; + AxisSpec axisPoolBin = {binsPoolBin, "PoolBin"}; + AxisSpec axisStatus = {15, 0.5, 15.5, "Selection status"}; + AxisSpec axisRapidity = {100, -2, 2, "Rapidity"}; + + registry.add("hPtCand", "Dplus,Hadron candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtProng0", "Dplus,Hadron candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtProng1", "Dplus,Hadron candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtProng2", "Dplus,Hadron candidates;prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtD}}); + registry.add("hSelectionStatus", "Dplus,Hadron candidates;selection status;entries", {HistType::kTH1F, {{10, -0.5, 9.5}}}); + registry.add("hEta", "Dplus,Hadron candidates;candidate #it{#eta};entries", {HistType::kTH1F, {axisEta}}); + registry.add("hPhi", "Dplus,Hadron candidates;candidate #it{#varphi};entries", {HistType::kTH1F, {axisPhi}}); + registry.add("hY", "Dplus,Hadron candidates;candidate #it{#y};entries", {HistType::kTH1F, {axisRapidity}}); + registry.add("hcountDplusHadronPerEvent", "Dplus,Hadron particles - MC gen;Number per event;entries", {HistType::kTH1F, {{20, 0., 20.}}}); + registry.add("hMultiplicityPreSelection", "multiplicity prior to selection;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}); + registry.add("hMultiplicity", "multiplicity;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}); + registry.add("hMultFT0M", "multiplicity;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}); + registry.add("hZvtx", "z vertex;z vertex;entries", {HistType::kTH1F, {{200, -20., 20.}}}); + registry.add("hDplusBin", "Dplus selected in pool Bin;pool Bin;entries", {HistType::kTH1F, {{9, 0., 9.}}}); + registry.add("hTracksBin", "Tracks selected in pool Bin;pool Bin;entries", {HistType::kTH1F, {{9, 0., 9.}}}); + registry.add("hMassDplus_2D", "Dplus candidates;inv. mass (K^{-}#pi^{+}#pi^{+}) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hMassDplusData", "Dplus candidates;inv. mass (K^{-}#pi^{+}#pi^{+}) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{axisMassD}}}); + registry.add("hDplusPoolBin", "D+ candidates pool bin", {HistType::kTH1F, {axisPoolBin}}); + registry.add("hTracksPoolBin", "Particles associated pool bin", {HistType::kTH1F, {axisPoolBin}}); + // Histograms for MC Reco analysis + registry.add("hSelectionStatusMCRec", "Dplus,Hadron candidates - MC reco;selection status;entries", {HistType::kTH1F, {{4, -0.5, 3.5}}}); + registry.add("hMCEvtCount", "Event counter - MC gen;;entries", {HistType::kTH1F, {{1, -0.5, 0.5}}}); + registry.add("hPtProng0MCRec", "Dplus,Hadron candidates - MC reco;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtProng1MCRec", "Dplus,Hadron candidates - MC reco;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtProng2MCRec", "Dplus,Hadron candidates - MC reco;prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtD}}); + registry.add("hMassDplusMcRec", "D+ candidates;inv. mass (K^{-}#pi^{+}#pi^{+}) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{axisMassD}}}); + registry.add("hMassDplusVsPtMcRec", "D+ signal candidates - MC Reco", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hMassDplusMcRecSig", "D+ signal candidates - MC reco;inv. mass (#pi K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hMassDplusMcRecBkg", "D+ background candidates - MC reco;inv. mass (#pi K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hPtCandMcRecSig", "D+,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandMcRecSigPrompt", "D+,Hadron candidates Prompt - MC Reco", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandMcRecSigNonPrompt", "D+,Hadron candidates Non Prompt - MC Reco", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandMcRecBkg", "D+,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPtD}}); + registry.add("hEtaMcRecSig", "D+,Hadron candidates - MC Reco", {HistType::kTH1F, {axisEta}}); + registry.add("hPhiMcRecSig", "D+,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPhi}}); + registry.add("hYMCRecSig", "D+,Hadron candidates - MC reco;candidate #it{#y};entries", {HistType::kTH1F, {axisRapidity}}); + registry.add("hEtaMcRecBkg", "D+,Hadron candidates - MC Reco", {HistType::kTH1F, {axisEta}}); + registry.add("hPhiMcRecBkg", "D+,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPhi}}); + registry.add("hYMCRecBkg", "Dplus,Hadron candidates - MC reco;candidate #it{#y};entries", {HistType::kTH1F, {axisRapidity}}); + registry.add("hFakeTracksMcRec", "Fake tracks - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtParticleAssocVsCandMcRec", "Associated Particle - MC Rec", {HistType::kTH2F, {{axisPtHadron}, {axisPtD}}}); + registry.add("hPtPrimaryParticleAssocVsCandMcRec", "Associated Particle - MC Rec", {HistType::kTH2F, {{axisPtHadron}, {axisPtD}}}); + registry.add("hPtVsMultiplicityMcRecPrompt", "Multiplicity FT0M - MC Rec Prompt", {HistType::kTH2F, {{axisPtD}, {axisMultFT0M}}}); + registry.add("hPtVsMultiplicityMcRecNonPrompt", "Multiplicity FT0M - MC Rec Non Prompt", {HistType::kTH2F, {{axisPtD}, {axisMultFT0M}}}); + // Histograms for MC Gen analysis + registry.add("hcountDplustriggersMCGen", "D+ trigger particles - MC gen;;N of trigger Dplus", {HistType::kTH2F, {{1, -0.5, 0.5}, {axisPtD}}}); + registry.add("hPtCandMCGen", "Dplus,Hadron particles - MC gen;particle #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtD}}); + registry.add("hYMCGen", "Dplus,Hadron candidates - MC gen;candidate #it{#y};entries", {HistType::kTH1F, {axisRapidity}}); + registry.add("hPtCandMcGenPrompt", "D+,Hadron particles - MC Gen Prompt", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandMcGenNonPrompt", "D+,Hadron particles - MC Gen Non Prompt", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtParticleAssocMcGen", "Associated Particle - MC Gen", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hEtaMcGen", "D+,Hadron particles - MC Gen", {HistType::kTH1F, {axisEta}}); + registry.add("hPhiMcGen", "D+,Hadron particles - MC Gen", {HistType::kTH1F, {axisPhi}}); + registry.add("hMultFT0AMcGen", "D+,Hadron multiplicity FT0A - MC Gen", {HistType::kTH1F, {axisMultiplicity}}); corrBinning = {{binsZVtx, binsMultiplicity}, true}; } /// Dplus-hadron correlation pair builder - for real data and data-like analysis (i.e. reco-level w/o matching request via MC truth) void processData(SelCollisionsWithDplus::iterator const& collision, - TracksWithDca const& tracks, - CandidatesDplusData const&, aod::BCsWithTimestamps const&) + TracksData const& tracks, + CandidatesDplusData const& candidates, aod::BCsWithTimestamps const&) { auto bc = collision.bc_as(); int gCollisionId = collision.globalIndex(); int64_t timeStamp = bc.timestamp(); - if (selectedDplusCandidates.size() > 0) { - int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFT0M())); + + int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFT0M())); + if (candidates.size() > 0) { int nTracks = 0; if (collision.numContrib() > 1) { for (const auto& track : tracks) { - if (std::abs(track.eta()) > etaTrackMax) { - continue; - } - if (std::abs(track.dcaXY()) > dcaXYTrackMax || std::abs(track.dcaZ()) > dcaZTrackMax) { + if (std::abs(track.eta()) >= etaTrackMax || std::abs(track.dcaXY()) >= dcaXYTrackMax || std::abs(track.dcaZ()) >= dcaZTrackMax) { continue; } nTracks++; - registry.fill(HIST("hTracksBin"), poolBin); } } - registry.fill(HIST("hMultiplicityPreSelection"), nTracks); if (nTracks < multMin || nTracks > multMax) { return; } registry.fill(HIST("hMultiplicity"), nTracks); - auto selectedDplusCandidatesGrouped = selectedDplusCandidates->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); int cntDplus = 0; - for (const auto& candidate1 : selectedDplusCandidatesGrouped) { - if (yCandMax >= 0. && std::abs(hfHelper.yDplus(candidate1)) > yCandMax) { - continue; - } - if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { - continue; - } - if (candidate1.pt() > ptTrackMax) { - continue; - } - // check decay channel flag for candidate1 - if (!(candidate1.hfflag() & 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi)) { + std::vector outputMl = {-1., -1., -1.}; + for (const auto& candidate : candidates) { + if (std::abs(hfHelper.yDplus(candidate)) >= yCandMax || candidate.pt() <= ptCandMin || candidate.pt() >= ptCandMax) { continue; } - double efficiencyWeight = 1.; + int effBinD = o2::analysis::findBin(binsPtEfficiencyD, candidate.pt()); + double efficiencyWeightD = 1.; if (applyEfficiency) { - efficiencyWeight = 1. / efficiencyD->at(o2::analysis::findBin(binsPt, candidate1.pt())); + efficiencyWeightD = 1. / efficiencyD->at(effBinD); } // fill invariant mass plots and generic info from all Dplus candidates - registry.fill(HIST("hMassDplus_2D"), hfHelper.invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); - registry.fill(HIST("hMassDplusData"), hfHelper.invMassDplusToPiKPi(candidate1), efficiencyWeight); - registry.fill(HIST("hPtCand"), candidate1.pt()); - registry.fill(HIST("hPtProng0"), candidate1.ptProng0()); - registry.fill(HIST("hPtProng1"), candidate1.ptProng1()); - registry.fill(HIST("hPtProng2"), candidate1.ptProng2()); - registry.fill(HIST("hEta"), candidate1.eta()); - registry.fill(HIST("hPhi"), RecoDecay::constrainAngle(candidate1.phi(), -o2::constants::math::PIHalf)); - registry.fill(HIST("hY"), hfHelper.yDplus(candidate1)); - registry.fill(HIST("hSelectionStatus"), candidate1.isSelDplusToPiKPi()); + registry.fill(HIST("hMassDplus_2D"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), efficiencyWeightD); + registry.fill(HIST("hMassDplusData"), hfHelper.invMassDplusToPiKPi(candidate), efficiencyWeightD); + registry.fill(HIST("hPtCand"), candidate.pt()); + registry.fill(HIST("hPtProng0"), candidate.ptProng0()); + registry.fill(HIST("hPtProng1"), candidate.ptProng1()); + registry.fill(HIST("hPtProng2"), candidate.ptProng2()); + registry.fill(HIST("hEta"), candidate.eta()); + registry.fill(HIST("hPhi"), RecoDecay::constrainAngle(candidate.phi(), -o2::constants::math::PIHalf)); + registry.fill(HIST("hY"), hfHelper.yDplus(candidate)); + registry.fill(HIST("hSelectionStatus"), candidate.isSelDplusToPiKPi()); registry.fill(HIST("hDplusBin"), poolBin); - entryDplus(candidate1.phi(), candidate1.eta(), candidate1.pt(), hfHelper.invMassDplusToPiKPi(candidate1), poolBin, gCollisionId, timeStamp); + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDplusToPiKPi()[classMl->at(iclass)]; + } + entryDplusCandRecoInfo(hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1]); // 0: BkgBDTScore, 1:PromptBDTScore + entryDplus(candidate.phi(), candidate.eta(), candidate.pt(), hfHelper.invMassDplusToPiKPi(candidate), poolBin, gCollisionId, timeStamp); + // Dplus-Hadron correlation dedicated section // if the candidate is a Dplus, search for Hadrons and evaluate correlations for (const auto& track : tracks) { + // apply track selection if (!track.isGlobalTrackWoDCA()) { continue; } - if (std::abs(track.eta()) > etaTrackMax) { - continue; - } - if (track.pt() < ptTrackMin) { - continue; - } - if (std::abs(track.dcaXY()) >= dcaXYTrackMax || std::abs(track.dcaZ()) >= dcaZTrackMax) { - continue; // Remove secondary tracks - } // Removing Dplus daughters by checking track indices - if ((candidate1.prong0Id() == track.globalIndex()) || (candidate1.prong1Id() == track.globalIndex()) || (candidate1.prong2Id() == track.globalIndex())) { - continue; + if (removeDaughters) { + if ((candidate.prong0Id() == track.globalIndex()) || (candidate.prong1Id() == track.globalIndex()) || (candidate.prong2Id() == track.globalIndex())) { + continue; + } } - entryDplusHadronPair(getDeltaPhi(track.phi(), candidate1.phi()), - track.eta() - candidate1.eta(), - candidate1.pt(), + entryDplusHadronPair(getDeltaPhi(track.phi(), candidate.phi()), + track.eta() - candidate.eta(), + candidate.pt(), track.pt(), poolBin); - entryDplusHadronRecoInfo(hfHelper.invMassDplusToPiKPi(candidate1), 0); - if (cntDplus == 0) + entryDplusHadronRecoInfo(hfHelper.invMassDplusToPiKPi(candidate), false); + entryDplusHadronGenInfo(false, false, 0); + entryDplusHadronMlInfo(outputMl[0], outputMl[1]); + entryTrackRecoInfo(track.dcaXY(), track.dcaZ(), track.tpcNClsCrossedRows()); + if (cntDplus == 0) { entryHadron(track.phi(), track.eta(), track.pt(), poolBin, gCollisionId, timeStamp); + registry.fill(HIST("hTracksBin"), poolBin); + } } // Hadron Tracks loop cntDplus++; } // end outer Dplus loop @@ -338,22 +383,19 @@ struct HfCorrelatorDplusHadrons { /// Dplus-Hadron correlation pair builder - for MC reco-level analysis (candidates matched to true signal only, but also the various bkg sources are studied) void processMcRec(SelCollisionsWithDplus::iterator const& collision, - TracksWithDca const& tracks, - CandidatesDplusMcRec const&) + TracksWithMc const& tracks, + CandidatesDplusMcRec const& candidates, + aod::McParticles const& mcParticles) { - if (selectedDplusCandidatesMc.size() > 0) { - int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFT0M())); + int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFT0M())); + if (candidates.size() > 0) { int nTracks = 0; if (collision.numContrib() > 1) { for (const auto& track : tracks) { - if (std::abs(track.eta()) > etaTrackMax) { - continue; - } - if (std::abs(track.dcaXY()) > dcaXYTrackMax || std::abs(track.dcaZ()) > dcaZTrackMax) { + if (std::abs(track.eta()) >= etaTrackMax || std::abs(track.dcaXY()) >= dcaXYTrackMax || std::abs(track.dcaZ()) >= dcaZTrackMax) { continue; } nTracks++; - registry.fill(HIST("hTracksBin"), poolBin); } } registry.fill(HIST("hMultiplicityPreSelection"), nTracks); @@ -362,72 +404,105 @@ struct HfCorrelatorDplusHadrons { } registry.fill(HIST("hMultiplicity"), nTracks); - auto selectedDplusCandidatesMcGrouped = selectedDplusCandidatesMc->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); + float multiplicityFT0M = collision.multFT0M(); + // MC reco level - bool flagDplusSignal = false; - for (const auto& candidate1 : selectedDplusCandidatesMcGrouped) { - // check decay channel flag for candidate1 - if (!(candidate1.hfflag() & 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi)) { - continue; - } - if (yCandMax >= 0. && std::abs(hfHelper.yDplus(candidate1)) > yCandMax) { + bool isDplusPrompt = false; + bool isDplusNonPrompt = false; + bool isDplusSignal = false; + for (const auto& candidate : candidates) { + // rapidity and pT selections + if (std::abs(hfHelper.yDplus(candidate)) >= yCandMax || candidate.pt() <= ptCandMin || candidate.pt() >= ptCandMax) { continue; } - if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { - continue; - } - if (candidate1.pt() >= ptTrackMax) { - continue; - } - double efficiencyWeight = 1.; + // efficiency weight determination + int effBinD = o2::analysis::findBin(binsPtEfficiencyD, candidate.pt()); + double efficiencyWeightD = 1.; if (applyEfficiency) { - efficiencyWeight = 1. / efficiencyD->at(o2::analysis::findBin(binsPt, candidate1.pt())); + efficiencyWeightD = 1. / efficiencyD->at(effBinD); } + // Dplus flag + isDplusSignal = TESTBIT(std::abs(candidate.flagMcMatchRec()), aod::hf_cand_3prong::DecayType::DplusToPiKPi); + // prompt and non-prompt division + isDplusPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; + isDplusNonPrompt = candidate.originMcRec() == RecoDecay::OriginType::NonPrompt; + + std::vector outputMl = {-1., -1., -1.}; - if (std::abs(candidate1.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi) { - // fill per-candidate distributions from Dplus true candidates - registry.fill(HIST("hPtCandMCRec"), candidate1.pt()); - registry.fill(HIST("hPtProng0MCRec"), candidate1.ptProng0()); - registry.fill(HIST("hPtProng1MCRec"), candidate1.ptProng1()); - registry.fill(HIST("hPtProng2MCRec"), candidate1.ptProng2()); - registry.fill(HIST("hEtaMCRec"), candidate1.eta()); - registry.fill(HIST("hPhiMCRec"), RecoDecay::constrainAngle(candidate1.phi(), -o2::constants::math::PIHalf)); - registry.fill(HIST("hYMCRec"), hfHelper.yDplus(candidate1)); - registry.fill(HIST("hSelectionStatusMCRec"), candidate1.isSelDplusToPiKPi()); - } // fill invariant mass plots from Dplus signal and background candidates - registry.fill(HIST("hMassDplusMCRec"), hfHelper.invMassDplusToPiKPi(candidate1), efficiencyWeight); - if (std::abs(candidate1.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi) { // also matched as Dplus - registry.fill(HIST("hMassDplusMCRecSig"), hfHelper.invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassDplusMcRec"), hfHelper.invMassDplusToPiKPi(candidate), efficiencyWeightD); + registry.fill(HIST("hDplusBin"), poolBin); + + if (isDplusSignal) { + // fill per-candidate distributions from Dplus true candidates + registry.fill(HIST("hPtProng0MCRec"), candidate.ptProng0()); + registry.fill(HIST("hPtProng1MCRec"), candidate.ptProng1()); + registry.fill(HIST("hPtProng2MCRec"), candidate.ptProng2()); + registry.fill(HIST("hMassDplusVsPtMcRec"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), efficiencyWeightD); + registry.fill(HIST("hSelectionStatusMCRec"), candidate.isSelDplusToPiKPi()); + registry.fill(HIST("hPtCandMcRecSig"), candidate.pt()); + registry.fill(HIST("hEtaMcRecSig"), candidate.eta()); + registry.fill(HIST("hYMCRecSig"), hfHelper.yDplus(candidate)); + registry.fill(HIST("hPhiMcRecSig"), RecoDecay::constrainAngle(candidate.phi(), -PIHalf)); + + // prompt and non-prompt division + if (isDplusPrompt) { + registry.fill(HIST("hPtCandMcRecSigPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityMcRecPrompt"), candidate.pt(), multiplicityFT0M); + } else if (isDplusNonPrompt) { + registry.fill(HIST("hPtCandMcRecSigNonPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityMcRecNonPrompt"), candidate.pt(), multiplicityFT0M); + } + // Storing ML scores for signal reco candidates and charm/beauty origin + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDplusToPiKPi()[classMl->at(iclass)]; + } + registry.fill(HIST("hMassDplusMcRecSig"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), efficiencyWeightD); + entryDplusCandRecoInfo(hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1]); + entryDplusCandGenInfo(isDplusPrompt); } else { - registry.fill(HIST("hMassDplusMCRecBkg"), hfHelper.invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hPtCandMcRecBkg"), candidate.pt()); + registry.fill(HIST("hEtaMcRecBkg"), candidate.eta()); + registry.fill(HIST("hPhiMcRecBkg"), RecoDecay::constrainAngle(candidate.phi(), -PIHalf)); + registry.fill(HIST("hMassDplusMcRecBkg"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), efficiencyWeightD); } - registry.fill(HIST("hDplusBin"), poolBin); + // Dplus-Hadron correlation dedicated section // if the candidate is selected as Dplus, search for Hadron and evaluate correlations - flagDplusSignal = candidate1.flagMcMatchRec() == 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi; for (const auto& track : tracks) { + bool isPhysicalPrimary = false; + int trackOrigin = -1; + // apply track selection if (!track.isGlobalTrackWoDCA()) { continue; } - if (std::abs(track.eta()) > etaTrackMax) { - continue; - } - if (track.pt() < ptTrackMin) { - continue; - } // Removing Dplus daughters by checking track indices - if ((candidate1.prong0Id() == track.globalIndex()) || (candidate1.prong1Id() == track.globalIndex()) || (candidate1.prong2Id() == track.globalIndex())) { - continue; - } - if (std::abs(track.dcaXY()) >= dcaXYTrackMax || std::abs(track.dcaZ()) >= dcaZTrackMax) { - continue; // Remove secondary tracks + if (removeDaughters) { + if ((candidate.prong0Id() == track.globalIndex()) || (candidate.prong1Id() == track.globalIndex()) || (candidate.prong2Id() == track.globalIndex())) { + continue; + } } - entryDplusHadronPair(getDeltaPhi(track.phi(), candidate1.phi()), - track.eta() - candidate1.eta(), - candidate1.pt(), + entryDplusHadronPair(getDeltaPhi(track.phi(), candidate.phi()), + track.eta() - candidate.eta(), + candidate.pt(), track.pt(), poolBin); - entryDplusHadronRecoInfo(hfHelper.invMassDplusToPiKPi(candidate1), flagDplusSignal); + entryDplusHadronRecoInfo(hfHelper.invMassDplusToPiKPi(candidate), isDplusSignal); + entryDplusHadronMlInfo(outputMl[0], outputMl[1]); + if (track.has_mcParticle()) { + auto mcParticle = track.template mcParticle_as(); + isPhysicalPrimary = mcParticle.isPhysicalPrimary(); + trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); + entryDplusHadronGenInfo(isDplusPrompt, isPhysicalPrimary, trackOrigin); + } else { + entryDplusHadronGenInfo(isDplusPrompt, false, 0); + registry.fill(HIST("hFakeTracksMcRec"), track.pt()); + } + // for secondary particle fraction estimation + registry.fill(HIST("hPtParticleAssocVsCandMcRec"), track.pt(), candidate.pt()); + if (isPhysicalPrimary) { + registry.fill(HIST("hPtPrimaryParticleAssocVsCandMcRec"), track.pt(), candidate.pt()); + } + entryTrackRecoInfo(track.dcaXY(), track.dcaZ(), track.tpcNClsCrossedRows()); } // end inner loop (Tracks) } // end outer Dplus loop @@ -438,101 +513,110 @@ struct HfCorrelatorDplusHadrons { PROCESS_SWITCH(HfCorrelatorDplusHadrons, processMcRec, "Process MC Reco mode", true); /// Dplus-Hadron correlation pair builder - for MC gen-level analysis (no filter/selection, only true signal) - void processMcGen(aod::McCollision const& mcCollision, - aod::McParticles const& mcParticles) + void processMcGen(SelCollisionsWithDplusMc::iterator const& mcCollision, + CandDplusMcGen const& mcParticles) { int counterDplusHadron = 0; registry.fill(HIST("hMCEvtCount"), 0); - auto getTracksSize = [&mcParticles](aod::McCollision const&) { - int nTracks = 0; - for (const auto& track : mcParticles) { - if (track.isPhysicalPrimary() && std::abs(track.eta()) < 1.0) { - nTracks++; - } - } - return nTracks; - }; - using BinningTypeMCGen = FlexibleBinningPolicy, aod::mccollision::PosZ, decltype(getTracksSize)>; - BinningTypeMCGen corrBinningMcGen{{getTracksSize}, {binsZVtx, binsMultiplicityMc}, true}; + BinningTypeMcGen corrBinningMcGen{{binsZVtx, binsMultiplicityMc}, true}; + int poolBin = corrBinningMcGen.getBin(std::make_tuple(mcCollision.posZ(), mcCollision.multMCFT0A())); + registry.fill(HIST("hMultFT0AMcGen"), mcCollision.multMCFT0A()); + bool isDplusPrompt = false; + bool isDplusNonPrompt = false; // MC gen level for (const auto& particle1 : mcParticles) { // check if the particle is Dplus (for general plot filling and selection, so both cases are fine) - NOTE: decay channel is not probed! if (std::abs(particle1.pdgCode()) != Pdg::kDPlus) { continue; } - double yD = RecoDecay::y(particle1.pVector(), MassDPlus); - if (yCandMax >= 0. && std::abs(yD) > yCandMax) { + if (!TESTBIT(std::abs(particle1.flagMcMatchGen()), aod::hf_cand_3prong::DecayType::DplusToPiKPi)) { continue; } - if (ptCandMin >= 0. && particle1.pt() < ptCandMin) { + double yD = RecoDecay::y(particle1.pVector(), MassDPlus); + if (std::abs(yD) >= yCandMax || particle1.pt() <= ptCandMin) { continue; } + registry.fill(HIST("hDplusBin"), poolBin); registry.fill(HIST("hPtCandMCGen"), particle1.pt()); - registry.fill(HIST("hEtaMCGen"), particle1.eta()); - registry.fill(HIST("hPhiMCGen"), RecoDecay::constrainAngle(particle1.phi(), -o2::constants::math::PIHalf)); + registry.fill(HIST("hEtaMcGen"), particle1.eta()); + registry.fill(HIST("hPhiMcGen"), RecoDecay::constrainAngle(particle1.phi(), -PIHalf)); registry.fill(HIST("hYMCGen"), yD); + + // prompt and non-prompt division + isDplusPrompt = particle1.originMcGen() == RecoDecay::OriginType::Prompt; + isDplusNonPrompt = particle1.originMcGen() == RecoDecay::OriginType::NonPrompt; + if (isDplusPrompt) { + registry.fill(HIST("hPtCandMcGenPrompt"), particle1.pt()); + } else if (isDplusNonPrompt) { + registry.fill(HIST("hPtCandMcGenNonPrompt"), particle1.pt()); + } + + // prompt and non-prompt division + std::vector listDaughters{}; + std::array arrDaughDplusPDG = {+kPiPlus, -kKPlus, kPiPlus}; + std::array prongsId; + listDaughters.clear(); + RecoDecay::getDaughters(particle1, &listDaughters, arrDaughDplusPDG, 2); + int counterDaughters = 0; + if (listDaughters.size() == 3) { + for (const auto& dauIdx : listDaughters) { + auto daughI = mcParticles.rawIteratorAt(dauIdx - mcParticles.offset()); + counterDaughters += 1; + prongsId[counterDaughters - 1] = daughI.globalIndex(); + } + } counterDplusHadron++; // Dplus Hadron correlation dedicated section // if it's a Dplus particle, search for Hadron and evaluate correlations - if (std::abs(particle1.pdgCode()) != Pdg::kDPlus) { // just checking the particle PDG, not the decay channel (differently from Reco: you have a BR factor btw such levels!) - continue; - } registry.fill(HIST("hcountDplustriggersMCGen"), 0, particle1.pt()); // to count trigger Dplus for normalisation) - for (const auto& particle2 : mcParticles) { - - // Check Mother of particle 2 - bool flagMotherFound = false; - for (const auto& m : particle2.mothers_as()) { - if (m.globalIndex() == particle1.globalIndex()) { - flagMotherFound = true; - break; - } - } - if (flagMotherFound) { + for (const auto& particleAssoc : mcParticles) { + if (std::abs(particleAssoc.eta()) > etaTrackMax || particleAssoc.pt() < ptTrackMin || particleAssoc.pt() > ptTrackMax) { continue; } - if (std::abs(particle2.eta()) > etaTrackMax) { - continue; + if (removeDaughters) { + if (particleAssoc.globalIndex() == prongsId[0] || particleAssoc.globalIndex() == prongsId[1] || particleAssoc.globalIndex() == prongsId[2]) { + continue; + } } - if (particle2.pt() < ptTrackMin) { + if ((std::abs(particleAssoc.pdgCode()) != kElectron) && (std::abs(particleAssoc.pdgCode()) != kMuonMinus) && (std::abs(particleAssoc.pdgCode()) != kPiPlus) && (std::abs(particleAssoc.pdgCode()) != kKPlus) && (std::abs(particleAssoc.pdgCode()) != kProton)) { continue; } - - if ((std::abs(particle2.pdgCode()) != 11) && (std::abs(particle2.pdgCode()) != 13) && (std::abs(particle2.pdgCode()) != 211) && (std::abs(particle2.pdgCode()) != 321) && (std::abs(particle2.pdgCode()) != 2212)) { + if (!particleAssoc.isPhysicalPrimary()) { continue; } - int poolBin = corrBinningMcGen.getBin(std::make_tuple(mcCollision.posZ(), getTracksSize(mcCollision))); - entryDplusHadronPair(getDeltaPhi(particle2.phi(), particle1.phi()), - particle2.eta() - particle1.eta(), - particle1.pt(), - particle2.pt(), poolBin); - } // end inner loop - } // end outer loop + int trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, particleAssoc, true); + registry.fill(HIST("hPtParticleAssocMcGen"), particleAssoc.pt()); + entryDplusHadronPair(getDeltaPhi(particleAssoc.phi(), particle1.phi()), + particleAssoc.eta() - particle1.eta(), + particle1.pt(), + particleAssoc.pt(), + poolBin); + entryDplusHadronRecoInfo(MassDPlus, true); + entryDplusHadronGenInfo(isDplusPrompt, particleAssoc.isPhysicalPrimary(), trackOrigin); + } // end associated loop + } // end trigger registry.fill(HIST("hcountDplusHadronPerEvent"), counterDplusHadron); registry.fill(HIST("hZvtx"), mcCollision.posZ()); - registry.fill(HIST("hMultiplicity"), getTracksSize(mcCollision)); + // registry.fill(HIST("hMultiplicity"), getTracksSize(mcCollision)); } PROCESS_SWITCH(HfCorrelatorDplusHadrons, processMcGen, "Process MC Gen mode", false); void processDataMixedEvent(SelCollisionsWithDplus const& collisions, CandidatesDplusData const& candidates, - TracksWithDca const& tracks) + TracksData const& tracks) { auto tracksTuple = std::make_tuple(candidates, tracks); - Pair pairData{corrBinning, 5, -1, collisions, tracksTuple, &cache}; + Pair pairData{corrBinning, 5, -1, collisions, tracksTuple, &cache}; for (const auto& [c1, tracks1, c2, tracks2] : pairData) { // LOGF(info, "Mixed event collisions: Index = (%d, %d), tracks Size: (%d, %d), Z Vertex: (%f, %f), Pool Bin: (%d, %d)", c1.globalIndex(), c2.globalIndex(), tracks1.size(), tracks2.size(), c1.posZ(), c2.posZ(), corrBinning.getBin(std::make_tuple(c1.posZ(), c1.multFT0M())),corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multFT0M()))); // For debug int poolBin = corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multFT0M())); for (const auto& [trigDplus, assocParticle] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - if (yCandMax >= 0. && std::abs(hfHelper.yDplus(trigDplus)) > yCandMax) { - continue; - } - if (!assocParticle.isGlobalTrackWoDCA()) { + if (!assocParticle.isGlobalTrackWoDCA() || std::abs(hfHelper.yDplus(trigDplus)) >= yCandMax) { continue; } entryDplusHadronPair(getDeltaPhi(trigDplus.phi(), assocParticle.phi()), trigDplus.eta() - assocParticle.eta(), trigDplus.pt(), assocParticle.pt(), poolBin); @@ -544,74 +628,114 @@ struct HfCorrelatorDplusHadrons { void processMcRecMixedEvent(SelCollisionsWithDplus const& collisions, CandidatesDplusMcRec const& candidates, - TracksWithDca const& tracks) + TracksWithMc const& tracks, + aod::McParticles const& mcParticles) { + BinningType corrBinning{{binsZVtx, binsMultiplicityMc}, true}; + for (const auto& candidate : candidates) { + if (std::abs(hfHelper.yDplus(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { + continue; + } + // Dplus flag + bool isDplusSignal = TESTBIT(std::abs(candidate.flagMcMatchRec()), aod::hf_cand_3prong::DecayType::DplusToPiKPi); + // prompt and non-prompt division + bool isDplusPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; + bool isDplusNonPrompt = candidate.originMcRec() == RecoDecay::OriginType::NonPrompt; + if (isDplusSignal) { + if (isDplusPrompt) { + registry.fill(HIST("hPtCandMcRecSigPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityMcRecPrompt"), candidate.pt(), 0); + } else if (isDplusNonPrompt) { + registry.fill(HIST("hPtCandMcRecSigNonPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityMcRecNonPrompt"), candidate.pt(), 0); + } + } else { + registry.fill(HIST("hPtCandMcRecBkg"), candidate.pt()); + registry.fill(HIST("hEtaMcRecBkg"), candidate.eta()); + registry.fill(HIST("hPhiMcRecBkg"), RecoDecay::constrainAngle(candidate.phi(), -PIHalf)); + } + } auto tracksTuple = std::make_tuple(candidates, tracks); - Pair pairMcRec{corrBinning, 5, -1, collisions, tracksTuple, &cache}; + Pair pairMcRec{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; for (const auto& [c1, tracks1, c2, tracks2] : pairMcRec) { int poolBin = corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multFT0M())); - for (const auto& [trigDplus, assocParticle] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - - if (yCandMax >= 0. && std::abs(hfHelper.yDplus(trigDplus)) > yCandMax) { + int poolBinDplus = corrBinning.getBin(std::make_tuple(c1.posZ(), c1.multFT0M())); + registry.fill(HIST("hMultFT0M"), c1.multFT0M()); + registry.fill(HIST("hZVtx"), c1.posZ()); + registry.fill(HIST("hTracksPoolBin"), poolBin); // note that the selections here are not yet applied + registry.fill(HIST("hDplusPoolBin"), poolBinDplus); // note that the selections here are not yet applied + for (const auto& [candidate, pAssoc] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (std::abs(hfHelper.yDplus(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { continue; } - if (!assocParticle.isGlobalTrackWoDCA()) { + if (!pAssoc.isGlobalTrackWoDCA()) { continue; } - entryDplusHadronPair(getDeltaPhi(trigDplus.phi(), assocParticle.phi()), trigDplus.eta() - assocParticle.eta(), trigDplus.pt(), assocParticle.pt(), poolBin); - entryDplusHadronRecoInfo(hfHelper.invMassDplusToPiKPi(trigDplus), 0); + std::vector outputMl = {-1., -1., -1.}; + bool isPhysicalPrimary = false; + int trackOrigin = -1; + bool isDplusSignal = std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi; + // prompt and non-prompt division + bool isDplusPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; + if (pAssoc.has_mcParticle()) { + auto mcParticle = pAssoc.template mcParticle_as(); + isPhysicalPrimary = mcParticle.isPhysicalPrimary(); + trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); + } else { + registry.fill(HIST("hFakeTracksMcRec"), pAssoc.pt()); + } + entryDplusHadronPair(getDeltaPhi(pAssoc.phi(), candidate.phi()), + pAssoc.eta() - candidate.eta(), + candidate.pt(), + pAssoc.pt(), + poolBin); + entryDplusHadronRecoInfo(hfHelper.invMassDplusToPiKPi(candidate), isDplusSignal); + entryDplusHadronGenInfo(isDplusPrompt, isPhysicalPrimary, trackOrigin); + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDplusToPiKPi()[classMl->at(iclass)]; + } + entryDplusHadronMlInfo(outputMl[0], outputMl[1]); + entryTrackRecoInfo(pAssoc.dcaXY(), pAssoc.dcaZ(), pAssoc.tpcNClsCrossedRows()); } } } PROCESS_SWITCH(HfCorrelatorDplusHadrons, processMcRecMixedEvent, "Process Mixed Event MCRec", false); - void processMcGenMixedEvent(McCollisionsSel const& collisions, - McParticlesSel const& mcParticles) + void processMcGenMixedEvent(SelCollisionsWithDplusMc const& collisions, + CandDplusMcGen const& mcParticles) { - - auto getTracksSize = [&mcParticles, this](McCollisionsSel::iterator const& collision) { - int nTracks = 0; - auto associatedTracks = mcParticles.sliceByCached(o2::aod::mcparticle::mcCollisionId, collision.globalIndex(), this->cache); - for (const auto& track : associatedTracks) { - if (track.isPhysicalPrimary() && std::abs(track.eta()) < 1.0) { - nTracks++; - } - } - return nTracks; - }; - - using BinningTypeMcGen = FlexibleBinningPolicy, aod::mccollision::PosZ, decltype(getTracksSize)>; - BinningTypeMcGen corrBinningMcGen{{getTracksSize}, {binsZVtx, binsMultiplicityMc}, true}; - + BinningTypeMcGen corrBinningMcGen{{binsZVtx, binsMultiplicityMc}, true}; auto tracksTuple = std::make_tuple(mcParticles, mcParticles); - Pair pairMcGen{corrBinningMcGen, 5, -1, collisions, tracksTuple, &cache}; - + Pair pairMcGen{corrBinningMcGen, numberEventsMixed, -1, collisions, tracksTuple, &cache}; for (const auto& [c1, tracks1, c2, tracks2] : pairMcGen) { - for (const auto& [trigDplus, assocParticle] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - - // Check track trigDplus is Dplus - if (std::abs(trigDplus.pdgCode()) != Pdg::kDPlus) { + int poolBin = corrBinningMcGen.getBin(std::make_tuple(c1.posZ(), c1.multMCFT0A())); + for (const auto& [candidate, particleAssoc] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (std::abs(candidate.pdgCode()) != Pdg::kDPlus) { continue; } - - double yD = RecoDecay::y(trigDplus.pVector(), MassDPlus); - if (yCandMax >= 0. && std::abs(yD) > yCandMax) { + double yD = RecoDecay::y(candidate.pVector(), MassDPlus); + if (std::abs(yD) > yCandGenMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { continue; } - if (ptCandMin >= 0. && trigDplus.pt() < ptCandMin) { + if (std::abs(particleAssoc.eta()) > etaTrackMax || particleAssoc.pt() < ptTrackMin || particleAssoc.pt() > ptTrackMax) { continue; } - - if (std::abs(assocParticle.eta()) > etaTrackMax) { + if ((std::abs(particleAssoc.pdgCode()) != kElectron) && (std::abs(particleAssoc.pdgCode()) != kMuonMinus) && (std::abs(particleAssoc.pdgCode()) != kPiPlus) && (std::abs(particleAssoc.pdgCode()) != kKPlus) && (std::abs(particleAssoc.pdgCode()) != kProton)) { continue; } - if (assocParticle.pt() < ptTrackMin) { + if (!particleAssoc.isPhysicalPrimary()) { continue; } - int poolBin = corrBinningMcGen.getBin(std::make_tuple(c2.posZ(), getTracksSize(c2))); - // LOGF(info, "Mixed event collisions: Index = (%d,%d), tracks Size: (%d,%d), Z Vertex: (%f), Pool Bin: (%d)", c1.globalIndex(), c2.globalIndex(), getTracksSize(c1), getTracksSize(c2), c2.posZ(), poolBin); // For debug - entryDplusHadronPair(getDeltaPhi(assocParticle.phi(), trigDplus.phi()), assocParticle.eta() - trigDplus.eta(), trigDplus.pt(), assocParticle.pt(), poolBin); + int trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, particleAssoc, true); + bool isDplusPrompt = candidate.originMcGen() == RecoDecay::OriginType::Prompt; + entryDplusHadronPair(getDeltaPhi(particleAssoc.phi(), candidate.phi()), + particleAssoc.eta() - candidate.eta(), + candidate.pt(), + particleAssoc.pt(), + poolBin); + entryDplusHadronRecoInfo(MassDPlus, true); + entryDplusHadronGenInfo(isDplusPrompt, particleAssoc.isPhysicalPrimary(), trackOrigin); } } } diff --git a/PWGHF/HFC/TableProducer/correlatorDsHadrons.cxx b/PWGHF/HFC/TableProducer/correlatorDsHadrons.cxx index ae3241dc7cd..50881aad9d2 100644 --- a/PWGHF/HFC/TableProducer/correlatorDsHadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDsHadrons.cxx @@ -14,6 +14,8 @@ /// \author Grazia Luparello /// \author Samuele Cattaruzzi +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" @@ -29,6 +31,7 @@ #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/HFC/DataModel/DerivedDataCorrelationTables.h" using namespace o2; using namespace o2::analysis; @@ -45,24 +48,25 @@ double getDeltaPhi(double phiHadron, double phiD) // binning type using BinningType = ColumnBinningPolicy>; +using BinningTypeMcGen = ColumnBinningPolicy; /// Code to select collisions with at least one Ds meson struct HfCorrelatorDsHadronsSelCollision { Produces collisionsWithSelDs; Configurable useSel8{"useSel8", true, "Flag for applying sel8 for collision selection"}; + Configurable selNoSameBunchPileUpColl{"selNoSameBunchPileUpColl", true, "Flag for rejecting the collisions associated with the same bunch crossing"}; Configurable doSelDsCollision{"doSelDsCollision", true, "Select collisions with at least one Ds"}; Configurable selectionFlagDs{"selectionFlagDs", 7, "Selection Flag for Ds"}; Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity"}; Configurable ptCandMin{"ptCandMin", 1., "min. cand. pT"}; - SliceCache cache; HfHelper hfHelper; + SliceCache cache; using SelCollisions = soa::Join; using CandDsData = soa::Filtered>; using CandDsMcReco = soa::Filtered>; - using CandDsMcGen = soa::Join; Filter dsFilter = ((o2::aod::hf_track_index::hfflag & static_cast(1 << aod::hf_cand_3prong::DecayType::DsToKKPi)) != static_cast(0)) && (aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlagDs || aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlagDs); @@ -70,75 +74,62 @@ struct HfCorrelatorDsHadronsSelCollision { void processDsSelCollisionsData(SelCollisions::iterator const& collision, CandDsData const& candidates) { - bool isDsFound = false; - bool isSel8 = false; + bool isSelColl = true; + bool isDsFound = true; + bool isSel8 = true; + bool isNosameBunchPileUp = true; if (doSelDsCollision) { + isDsFound = false; // if candidate table is empty for-loop is not performed for (const auto& candidate : candidates) { if (std::abs(hfHelper.yDs(candidate)) > yCandMax || candidate.pt() < ptCandMin) { + isDsFound = false; continue; } isDsFound = true; break; } - } else { - isDsFound = true; } if (useSel8) { + isSel8 = false; isSel8 = collision.sel8(); - isDsFound = isDsFound && isSel8; } - collisionsWithSelDs(isDsFound); + if (selNoSameBunchPileUpColl) { + isNosameBunchPileUp = false; + isNosameBunchPileUp = static_cast(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)); + } + isSelColl = isDsFound && isSel8 && isNosameBunchPileUp; + collisionsWithSelDs(isSelColl); } PROCESS_SWITCH(HfCorrelatorDsHadronsSelCollision, processDsSelCollisionsData, "Process Ds Collision Selection Data", true); - /// Code to select collisions with at least one Ds meson - for MC reco-level analysis - void processDsSelCollisionsMcRec(SelCollisions::iterator const& collision, - CandDsMcReco const& candidates) + /// Code to select collisions with at least one Ds meson - for MC-level analysis + void processDsSelCollisionsMc(SelCollisions::iterator const& collision, + CandDsMcReco const& candidates) { - bool isDsFound = false; - bool isSel8 = false; - if (doSelDsCollision) { + bool isSelColl = true; + bool isDsFound = true; + bool isSel8 = true; + bool isNosameBunchPileUp = true; + if (doSelDsCollision) { // to enable only for the MC reco part for (const auto& candidate : candidates) { if (std::abs(hfHelper.yDs(candidate)) > yCandMax || candidate.pt() < ptCandMin) { + isDsFound = false; continue; } isDsFound = true; break; } - } else { - isDsFound = true; } if (useSel8) { isSel8 = collision.sel8(); - isDsFound = isDsFound && isSel8; } - collisionsWithSelDs(isDsFound); - } - PROCESS_SWITCH(HfCorrelatorDsHadronsSelCollision, processDsSelCollisionsMcRec, "Process Ds Collision Selection MCRec", false); - - /// Code to select collisions with at least one Ds meson - for MC gen-level analysis - void processDsSelCollisionsMcGen(aod::McCollision const&, - CandDsMcGen const& mcParticles) - { - bool isDsFound = false; - if (doSelDsCollision) { - for (const auto& particle : mcParticles) { - if (std::abs(particle.pdgCode()) != Pdg::kDS) { - continue; - } - double yD = RecoDecay::y(particle.pVector(), MassDS); - if (std::abs(yD) > yCandMax || particle.pt() < ptCandMin) { - continue; - } - isDsFound = true; - break; - } - } else { - isDsFound = true; + if (selNoSameBunchPileUpColl) { + isNosameBunchPileUp = static_cast(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)); } - collisionsWithSelDs(isDsFound); + isSelColl = isDsFound && isSel8 && isNosameBunchPileUp; + collisionsWithSelDs(isSelColl); } - PROCESS_SWITCH(HfCorrelatorDsHadronsSelCollision, processDsSelCollisionsMcGen, "Process Ds Collision Selection MCGen", false); + PROCESS_SWITCH(HfCorrelatorDsHadronsSelCollision, processDsSelCollisionsMc, "Process Ds Collision Selection MCRec", false); }; /// Ds-Hadron correlation pair builder - for real data and data-like analysis (i.e. reco-level w/o matching request via MC truth) @@ -148,21 +139,31 @@ struct HfCorrelatorDsHadrons { Produces entryDsHadronGenInfo; Produces entryDsHadronMlInfo; Produces entryDsCandRecoInfo; + Produces entryDsCandGenInfo; Produces entryTrackRecoInfo; - - Configurable selectionFlagDs{"selectionFlagDs", 7, "Selection Flag for Ds"}; + Produces collReduced; + Produces candReduced; + Produces candSelInfo; + Produces assocTrackReduced; + Produces assocTrackSelInfo; + + Configurable fillHistoData{"fillHistoData", true, "Flag for filling histograms in data processes"}; + Configurable fillHistoMcRec{"fillHistoMcRec", true, "Flag for filling histograms in MC Rec processes"}; + Configurable fillHistoMcGen{"fillHistoMcGen", true, "Flag for filling histograms in MC Gen processes"}; + Configurable removeCollWSplitVtx{"removeCollWSplitVtx", false, "Flag for rejecting the splitted collisions"}; + Configurable useSel8{"useSel8", true, "Flag for applying sel8 for collision selection (used only in MC processes)"}; + Configurable selNoSameBunchPileUpColl{"selNoSameBunchPileUpColl", true, "Flag for rejecting the collisions associated with the same bunch crossing (used only in MC processes)"}; + Configurable selectionFlagDs{"selectionFlagDs", 7, "Selection Flag for Ds (avoid the case of flag = 0, no outputMlScore)"}; Configurable numberEventsMixed{"numberEventsMixed", 5, "Number of events mixed in ME process"}; - Configurable nTpcCrossedRaws{"nTpcCrossedRaws", 70, "Number of crossed TPC Rows"}; - Configurable useSel8ForTrackEff{"useSel8ForTrackEff", true, "Flag for applying sel8 for collision selection"}; + Configurable decayChannel{"decayChannel", 1, "Decay channels: 1 for Ds->PhiPi->KKpi, 2 for Ds->K0*K->KKPi"}; Configurable applyEfficiency{"applyEfficiency", true, "Flag for applying D-meson efficiency weights"}; Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity"}; Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen. cand. rapidity"}; Configurable etaTrackMax{"etaTrackMax", 0.8, "max. eta of tracks"}; - Configurable dcaXYTrackMax{"dcaXYTrackMax", 1., "max. DCA_xy of tracks"}; - Configurable dcaZTrackMax{"dcaZTrackMax", 1., "max. DCA_z of tracks"}; + Configurable dcaXYTrackMax{"dcaXYTrackMax", 2., "max. DCA_xy of tracks"}; + Configurable dcaZTrackMax{"dcaZTrackMax", 2., "max. DCA_z of tracks"}; Configurable ptCandMin{"ptCandMin", 1., "min. cand. pT"}; Configurable ptCandMax{"ptCandMax", 50., "max. cand pT"}; - Configurable ptDaughterMin{"ptDaughterMin", 0.1, "min. daughter pT"}; Configurable ptTrackMin{"ptTrackMin", 0.3, "min. track pT"}; Configurable ptTrackMax{"ptTrackMax", 50., "max. track pT"}; Configurable> classMl{"classMl", {0, 1, 2}, "Indexes of ML scores to be stored. Three indexes max."}; @@ -170,38 +171,15 @@ struct HfCorrelatorDsHadrons { Configurable> binsPtHadron{"binsPtHadron", std::vector{0.3, 2., 4., 8., 12., 50.}, "pT bin limits for assoc particle"}; Configurable> binsPtEfficiencyD{"binsPtEfficiencyD", std::vector{o2::analysis::hf_cuts_ds_to_k_k_pi::vecBinsPt}, "pT bin limits for efficiency"}; Configurable> efficiencyD{"efficiencyD", {1., 1., 1., 1., 1., 1.}, "efficiency values for Ds meson"}; - ConfigurableAxis zPoolBins{"zPoolBins", {VARIABLE_WIDTH, -10.0, -2.5, 2.5, 10.0}, "z vertex position pools"}; - ConfigurableAxis multPoolBins{"multPoolBins", {VARIABLE_WIDTH, 0., 900., 1800., 6000.}, "event multiplicity pools (FT0M)"}; - ConfigurableAxis binsMassD{"binsMassD", {200, 1.7, 2.25}, "inv. mass (K^{#pm}K^{-}#pi^{+}) (GeV/#it{c}^{2})"}; - ConfigurableAxis binsEta{"binsEta", {50, -2., 2.}, "#it{#eta}"}; - ConfigurableAxis binsPhi{"binsPhi", {64, -PIHalf, 3. * PIHalf}, "#it{#varphi}"}; - ConfigurableAxis binsMultiplicity{"binsMultiplicity", {200, 0., 800.}, "Multiplicity"}; - ConfigurableAxis binsMultFT0M{"binsMultFT0M", {600, 0., 6000.}, "Multiplicity as FT0M signal amplitude"}; - ConfigurableAxis binsPosZ{"binsPosZ", {100, -10., 10.}, "primary vertex z coordinate"}; - ConfigurableAxis binsBdtScore{"binsBdtScore", {100, 0., 1.}, "Bdt output scores"}; - ConfigurableAxis binsPoolBin{"binsPoolBin", {9, 0., 9.}, "PoolBin"}; + + int hfcReducedCollisionIndex = 0; HfHelper hfHelper; SliceCache cache; - enum CandidateStep { kCandidateStepMcGenAll = 0, - kCandidateStepMcGenDsToKKPi, - kCandidateStepMcCandInAcceptance, - kCandidateStepMcDaughtersInAcceptance, - kCandidateStepMcReco, - kCandidateStepMcRecoInAcceptance, - kCandidateNSteps }; - - enum AssocTrackStep { kAssocTrackStepMcGen = 0, - kAssocTrackStepMcGenInAcceptance, - kAssocTrackStepRecoAll, - kAssocTrackStepRecoMcMatch, - kAssocTrackStepRecoPrimaries, - kAssocTrackStepFake, - kAssocTrackNSteps }; - - using SelCollisionsWithDs = soa::Filtered>; // collisionFilter applied - using SelCollisionsWithDsMc = soa::Filtered>; // collisionFilter applied + using SelCollisionsWithDs = soa::Filtered>; // collisionFilter applied + // using SelCollisionsWithDsWithMc = soa::Filtered>; // collisionFilter applied + using SelCollisionsMc = soa::Join; using CandDsData = soa::Filtered>; // flagDsFilter applied using CandDsMcReco = soa::Filtered>; // flagDsFilter applied using CandDsMcGen = soa::Join; // flagDsFilter applied @@ -212,6 +190,22 @@ struct HfCorrelatorDsHadrons { Filter flagDsFilter = ((o2::aod::hf_track_index::hfflag & static_cast(1 << aod::hf_cand_3prong::DecayType::DsToKKPi)) != static_cast(0)) && (aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlagDs || aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlagDs); Filter trackFilter = (nabs(aod::track::eta) < etaTrackMax) && (aod::track::pt > ptTrackMin) && (aod::track::pt < ptTrackMax) && (nabs(aod::track::dcaXY) < dcaXYTrackMax) && (nabs(aod::track::dcaZ) < dcaZTrackMax); + Preslice candsDsPerCollision = aod::hf_cand::collisionId; + Preslice trackIndicesPerCollision = aod::track::collisionId; + Preslice perCollisionCandMc = o2::aod::mcparticle::mcCollisionId; + PresliceUnsorted> collPerCollMc = o2::aod::mccollisionlabel::mcCollisionId; + + ConfigurableAxis zPoolBins{"zPoolBins", {VARIABLE_WIDTH, -10.0, -2.5, 2.5, 10.0}, "z vertex position pools"}; + ConfigurableAxis multPoolBins{"multPoolBins", {VARIABLE_WIDTH, 0., 900., 1800., 6000.}, "event multiplicity pools (FT0M)"}; + ConfigurableAxis binsMassD{"binsMassD", {200, 1.7, 2.25}, "inv. mass (K^{#pm}K^{-}#pi^{+}) (GeV/#it{c}^{2})"}; + ConfigurableAxis binsEta{"binsEta", {50, -2., 2.}, "#it{#eta}"}; + + ConfigurableAxis binsPhi{"binsPhi", {64, -PIHalf, 3. * PIHalf}, "#it{#varphi}"}; + ConfigurableAxis binsMultiplicity{"binsMultiplicity", {200, 0., 800.}, "Multiplicity"}; + ConfigurableAxis binsMultFT0M{"binsMultFT0M", {600, 0., 6000.}, "Multiplicity as FT0M signal amplitude"}; + ConfigurableAxis binsPosZ{"binsPosZ", {100, -10., 10.}, "primary vertex z coordinate"}; + ConfigurableAxis binsPoolBin{"binsPoolBin", {9, 0., 9.}, "PoolBin"}; + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext&) @@ -224,66 +218,64 @@ struct HfCorrelatorDsHadrons { AxisSpec axisMultiplicity = {binsMultiplicity, "Multiplicity"}; AxisSpec axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; AxisSpec axisPosZ = {binsPosZ, "PosZ"}; - AxisSpec axisBdtScore = {binsBdtScore, "Bdt score"}; AxisSpec axisPoolBin = {binsPoolBin, "PoolBin"}; AxisSpec axisStatus = {15, 0.5, 15.5, "Selection status"}; // Histograms for data analysis - registry.add("hPtCand", "Ds candidates pt", {HistType::kTH1F, {axisPtD}}); - registry.add("hSelectionStatusDsToKKPi", "Ds candidates selection", {HistType::kTH1F, {axisStatus}}); - registry.add("hSelectionStatusDsToPiKK", "Ds candidates selection", {HistType::kTH1F, {axisStatus}}); - registry.add("hCountSelectionStatusDsToKKPiAndToPiKK", "Ds candidates selection", {HistType::kTH1F, {{1, -0.5, 0.5}}}); - registry.add("hEta", "Ds candidates eta", {HistType::kTH1F, {axisEta}}); - registry.add("hEtaVsPtCand", "Ds candidates etaVsPt", {HistType::kTH2F, {{axisEta}, {axisPtD}}}); - registry.add("hEtaVsPtPartAssoc", "Particles associated etaVsPt", {HistType::kTH2F, {{axisEta}, {axisPtHadron}}}); - registry.add("hPhi", "Ds candidates phi", {HistType::kTH1F, {axisPhi}}); - registry.add("hPhiVsPtCand", "Ds candidates phiVsPt", {HistType::kTH2F, {{axisPhi}, {axisPtD}}}); - registry.add("hPhiVsPtPartAssoc", "Particles associated phiVsPt", {HistType::kTH2F, {{axisPhi}, {axisPtHadron}}}); - registry.add("hMultiplicity", "Multiplicity", {HistType::kTH1F, {axisMultiplicity}}); - registry.add("hMultFT0M", "Multiplicity FT0M", {HistType::kTH1F, {axisMultFT0M}}); - registry.add("hZVtx", "z vertex", {HistType::kTH1F, {axisPosZ}}); - registry.add("hMassDsVsPt", "Ds candidates massVsPt", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); - registry.add("hMassDsData", "Ds candidates mass", {HistType::kTH1F, {axisMassD}}); - registry.add("hCollisionPoolBin", "Ds candidates collision pool bin", {HistType::kTH1F, {axisPoolBin}}); - registry.add("hDsPoolBin", "Ds candidates pool bin", {HistType::kTH1F, {axisPoolBin}}); - registry.add("hTracksPoolBin", "Particles associated pool bin", {HistType::kTH1F, {axisPoolBin}}); - registry.add("hCorrelSystematics", "Ds-h correlations systematic error evaluation", {HistType::kTHnSparseD, {{axisPhi}, {axisEta}, {axisPtD}, {axisPtHadron}, {axisMassD}, {axisBdtScore}, {axisBdtScore}}}); + if (fillHistoData) { + registry.add("hPtCand", "Ds candidates pt", {HistType::kTH1F, {axisPtD}}); + registry.add("hSelectionStatusDsToKKPi", "Ds candidates selection", {HistType::kTH1F, {axisStatus}}); + registry.add("hSelectionStatusDsToPiKK", "Ds candidates selection", {HistType::kTH1F, {axisStatus}}); + registry.add("hCountSelectionStatusDsToKKPiAndToPiKK", "Ds candidates selection", {HistType::kTH1F, {{1, -0.5, 0.5}}}); + registry.add("hEta", "Ds candidates eta", {HistType::kTH1F, {axisEta}}); + registry.add("hEtaVsPtCand", "Ds candidates etaVsPt", {HistType::kTH2F, {{axisEta}, {axisPtD}}}); + registry.add("hEtaVsPtPartAssoc", "Particles associated etaVsPt", {HistType::kTH2F, {{axisEta}, {axisPtHadron}}}); + registry.add("hPhi", "Ds candidates phi", {HistType::kTH1F, {axisPhi}}); + registry.add("hPhiVsPtCand", "Ds candidates phiVsPt", {HistType::kTH2F, {{axisPhi}, {axisPtD}}}); + registry.add("hPhiVsPtPartAssoc", "Particles associated phiVsPt", {HistType::kTH2F, {{axisPhi}, {axisPtHadron}}}); + registry.add("hMultiplicity", "Multiplicity", {HistType::kTH1F, {axisMultiplicity}}); + registry.add("hMultFT0M", "Multiplicity FT0M", {HistType::kTH1F, {axisMultFT0M}}); + registry.add("hZVtx", "z vertex", {HistType::kTH1F, {axisPosZ}}); + registry.add("hMassDsVsPt", "Ds candidates massVsPt", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hMassDsData", "Ds candidates mass", {HistType::kTH1F, {axisMassD}}); + registry.add("hCollisionPoolBin", "Ds candidates collision pool bin", {HistType::kTH1F, {axisPoolBin}}); + registry.add("hDsPoolBin", "Ds candidates pool bin", {HistType::kTH1F, {axisPoolBin}}); + registry.add("hTracksPoolBin", "Particles associated pool bin", {HistType::kTH1F, {axisPoolBin}}); + } // Histograms for MC Reco analysis - registry.add("hPtCandMcRecSig", "Ds,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPtD}}); - registry.add("hPtCandMcRecSigPrompt", "Ds,Hadron candidates Prompt - MC Reco", {HistType::kTH1F, {axisPtD}}); - registry.add("hPtCandMcRecSigNonPrompt", "Ds,Hadron candidates Non Prompt - MC Reco", {HistType::kTH1F, {axisPtD}}); - registry.add("hPtCandMcRecBkg", "Ds,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPtD}}); - registry.add("hPtParticleAssocMcRec", "Associated Particle - MC Rec", {HistType::kTH1F, {axisPtHadron}}); - registry.add("hPtParticleAssocVsCandMcRec", "Associated Particle - MC Rec", {HistType::kTH2F, {{axisPtHadron}, {axisPtD}}}); - registry.add("hPtPrimaryParticleAssocVsCandMcRec", "Associated Particle - MC Rec", {HistType::kTH2F, {{axisPtHadron}, {axisPtD}}}); - registry.add("hEtaMcRecSig", "Ds,Hadron candidates - MC Reco", {HistType::kTH1F, {axisEta}}); - registry.add("hPhiMcRecSig", "Ds,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPhi}}); - registry.add("hEtaMcRecBkg", "Ds,Hadron candidates - MC Reco", {HistType::kTH1F, {axisEta}}); - registry.add("hPhiMcRecBkg", "Ds,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPhi}}); - registry.add("hPtVsMultiplicityMcRecPrompt", "Multiplicity FT0M - MC Rec Prompt", {HistType::kTH2F, {{axisPtD}, {axisMultFT0M}}}); - registry.add("hPtVsMultiplicityMcRecNonPrompt", "Multiplicity FT0M - MC Rec Non Prompt", {HistType::kTH2F, {{axisPtD}, {axisMultFT0M}}}); - registry.add("hMassDsMcRec", "Ds candidates", {HistType::kTH1F, {axisMassD}}); - registry.add("hMassDsVsPtMcRec", "Ds signal candidates - MC Reco", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); - registry.add("hMassDsMcRecSig", "Ds signal candidates - MC Reco", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); - registry.add("hMassDsMcRecBkg", "Ds background candidates - MC Reco", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); - registry.add("hFakeTracksMcRec", "Fake tracks - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + if (fillHistoMcRec) { + registry.add("hPtCandMcRecSig", "Ds,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandMcRecSigPrompt", "Ds,Hadron candidates Prompt - MC Reco", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandMcRecSigNonPrompt", "Ds,Hadron candidates Non Prompt - MC Reco", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandMcRecBkg", "Ds,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPtD}}); + registry.add("hSelectionStatusDsToKKPiMcRec", "Ds candidates selection", {HistType::kTH1F, {axisStatus}}); + registry.add("hSelectionStatusDsToPiKKMcRec", "Ds candidates selection", {HistType::kTH1F, {axisStatus}}); + registry.add("hCountSelectionStatusDsToKKPiAndToPiKKMcRec", "Ds candidates selection", {HistType::kTH1F, {{1, -0.5, 0.5}}}); + registry.add("hPtParticleAssocMcRec", "Associated Particle - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtParticleAssocVsCandMcRec", "Associated Particle - MC Rec", {HistType::kTH2F, {{axisPtHadron}, {axisPtD}}}); + registry.add("hPtPrimaryParticleAssocVsCandMcRec", "Associated Particle - MC Rec", {HistType::kTH2F, {{axisPtHadron}, {axisPtD}}}); + registry.add("hEtaMcRecSig", "Ds,Hadron candidates - MC Reco", {HistType::kTH1F, {axisEta}}); + registry.add("hPhiMcRecSig", "Ds,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPhi}}); + registry.add("hEtaMcRecBkg", "Ds,Hadron candidates - MC Reco", {HistType::kTH1F, {axisEta}}); + registry.add("hPhiMcRecBkg", "Ds,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPhi}}); + registry.add("hPtVsMultiplicityMcRecPrompt", "Multiplicity FT0M - MC Rec Prompt", {HistType::kTH2F, {{axisPtD}, {axisMultFT0M}}}); + registry.add("hPtVsMultiplicityMcRecNonPrompt", "Multiplicity FT0M - MC Rec Non Prompt", {HistType::kTH2F, {{axisPtD}, {axisMultFT0M}}}); + registry.add("hMassDsMcRec", "Ds candidates", {HistType::kTH1F, {axisMassD}}); + registry.add("hMassDsVsPtMcRec", "Ds signal candidates - MC Reco", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hMassDsMcRecSig", "Ds signal candidates - MC Reco", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hMassDsMcRecBkg", "Ds background candidates - MC Reco", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hFakeTracksMcRec", "Fake tracks - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + } // Histograms for MC Gen analysis - registry.add("hPtCandMcGen", "Ds,Hadron particles - MC Gen", {HistType::kTH1F, {axisPtD}}); - registry.add("hPtCandMcGenPrompt", "Ds,Hadron particles - MC Gen Prompt", {HistType::kTH1F, {axisPtD}}); - registry.add("hPtCandMcGenNonPrompt", "Ds,Hadron particles - MC Gen Non Prompt", {HistType::kTH1F, {axisPtD}}); - registry.add("hPtParticleAssocMcGen", "Associated Particle - MC Gen", {HistType::kTH1F, {axisPtHadron}}); - registry.add("hEtaMcGen", "Ds,Hadron particles - MC Gen", {HistType::kTH1F, {axisEta}}); - registry.add("hPhiMcGen", "Ds,Hadron particles - MC Gen", {HistType::kTH1F, {axisPhi}}); - // Histograms for efficiencies - auto hCandidates = registry.add("hCandidates", "Candidate count at different steps", {HistType::kStepTHnF, {axisPtD, axisMultFT0M, {RecoDecay::OriginType::NonPrompt + 1, +RecoDecay::OriginType::None - 0.5, +RecoDecay::OriginType::NonPrompt + 0.5}}, kCandidateNSteps}); - hCandidates->GetAxis(0)->SetTitle("#it{p}_{T} (GeV/#it{c})"); - hCandidates->GetAxis(1)->SetTitle("multiplicity"); - hCandidates->GetAxis(2)->SetTitle("Charm hadron origin"); - auto hAssocTracks = registry.add("hAssocTracks", "Associated tracks at different steps", {HistType::kStepTHnF, {axisEta, axisPtHadron, axisMultFT0M, axisPosZ}, kAssocTrackNSteps}); - hAssocTracks->GetAxis(0)->SetTitle("#eta"); - hAssocTracks->GetAxis(1)->SetTitle("#it{p}_{T} (GeV/#it{c})"); - hAssocTracks->GetAxis(2)->SetTitle("multiplicity"); - hAssocTracks->GetAxis(3)->SetTitle("pos z"); + if (fillHistoMcGen) { + registry.add("hPtCandMcGen", "Ds,Hadron particles - MC Gen", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandMcGenPrompt", "Ds,Hadron particles - MC Gen Prompt", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandMcGenNonPrompt", "Ds,Hadron particles - MC Gen Non Prompt", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtParticleAssocMcGen", "Associated Particle - MC Gen", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hEtaMcGen", "Ds,Hadron particles - MC Gen", {HistType::kTH1F, {axisEta}}); + registry.add("hPhiMcGen", "Ds,Hadron particles - MC Gen", {HistType::kTH1F, {axisPhi}}); + registry.add("hMultFT0AMcGen", "Ds,Hadron multiplicity FT0A - MC Gen", {HistType::kTH1F, {axisMultiplicity}}); + } } /// Fill histograms of quantities independent from the daugther-mass hypothesis for data @@ -353,7 +345,7 @@ struct HfCorrelatorDsHadrons { /// Fill histograms of quantities for the Ds signal for MC reco-level /// \param particle is particle, Ds template - void fillHistoMcGen(const T1& particle) + void fillMcGenHisto(const T1& particle) { registry.fill(HIST("hPtCandMcGen"), particle.pt()); registry.fill(HIST("hEtaMcGen"), particle.eta()); @@ -426,8 +418,8 @@ struct HfCorrelatorDsHadrons { candidate.pt(), track.pt(), poolBin); - entryDsHadronRecoInfo(hfHelper.invMassDsToKKPi(candidate), false); - entryDsHadronGenInfo(false, false); + entryDsHadronRecoInfo(hfHelper.invMassDsToKKPi(candidate), false, false); + // entryDsHadronGenInfo(false, false, 0); entryDsHadronMlInfo(outputMl[0], outputMl[2]); entryTrackRecoInfo(track.dcaXY(), track.dcaZ(), track.tpcNClsCrossedRows()); } else if (candidate.isSelDsToPiKK() >= selectionFlagDs) { @@ -436,13 +428,13 @@ struct HfCorrelatorDsHadrons { candidate.pt(), track.pt(), poolBin); - entryDsHadronRecoInfo(hfHelper.invMassDsToPiKK(candidate), false); - entryDsHadronGenInfo(false, false); + entryDsHadronRecoInfo(hfHelper.invMassDsToPiKK(candidate), false, false); + // entryDsHadronGenInfo(false, false, 0); entryDsHadronMlInfo(outputMl[0], outputMl[2]); entryTrackRecoInfo(track.dcaXY(), track.dcaZ(), track.tpcNClsCrossedRows()); } } // end track loop - } // end candidate loop + } // end candidate loop } PROCESS_SWITCH(HfCorrelatorDsHadrons, processData, "Process data", true); @@ -450,7 +442,7 @@ struct HfCorrelatorDsHadrons { void processMcRec(SelCollisionsWithDs::iterator const& collision, CandDsMcReco const& candidates, TracksWithMc const& tracks, - aod::McParticles const&) + aod::McParticles const& mcParticles) { BinningType corrBinning{{zPoolBins, multPoolBins}, true}; registry.fill(HIST("hZVtx"), collision.posZ()); @@ -461,6 +453,8 @@ struct HfCorrelatorDsHadrons { // MC reco level bool isDsPrompt = false; bool isDsSignal = false; + bool isCorrectInvMassHypo = false; + bool isDecayChan = false; bool isAlreadyFilledEvent = false; float multiplicityFT0M = collision.multFT0M(); for (const auto& candidate : candidates) { @@ -468,49 +462,65 @@ struct HfCorrelatorDsHadrons { isDsPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; // Ds Signal isDsSignal = std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DsToKKPi; + isDecayChan = candidate.flagMcDecayChanRec() == decayChannel; if (std::abs(hfHelper.yDs(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { continue; } + auto prong0McPart = candidate.template prong0_as().template mcParticle_as(); + isCorrectInvMassHypo = ((std::abs(prong0McPart.pdgCode()) == kKPlus) && (candidate.isSelDsToKKPi() >= selectionFlagDs)) || ((std::abs(prong0McPart.pdgCode()) == kPiPlus) && (candidate.isSelDsToPiKK() >= selectionFlagDs)); + double efficiencyWeightD = 1.; if (applyEfficiency) { efficiencyWeightD = 1. / efficiencyD->at(o2::analysis::findBin(binsPtEfficiencyD, candidate.pt())); } - if (isDsSignal) { + + std::vector outputMl = {-1., -1., -1.}; + + if (isDsSignal && isDecayChan && isCorrectInvMassHypo) { fillHistoMcRecSig(candidate, multiplicityFT0M); - // DsToKKPi and DsToPiKK division if (candidate.isSelDsToKKPi() >= selectionFlagDs) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDsToKKPi()[classMl->at(iclass)]; + } registry.fill(HIST("hMassDsMcRec"), hfHelper.invMassDsToKKPi(candidate), efficiencyWeightD); registry.fill(HIST("hMassDsMcRecSig"), hfHelper.invMassDsToKKPi(candidate), candidate.pt(), efficiencyWeightD); registry.fill(HIST("hMassDsVsPtMcRec"), hfHelper.invMassDsToKKPi(candidate), candidate.pt(), efficiencyWeightD); - registry.fill(HIST("hSelectionStatusDsToKKPi"), candidate.isSelDsToKKPi()); - } - if (candidate.isSelDsToPiKK() >= selectionFlagDs) { + registry.fill(HIST("hSelectionStatusDsToKKPiMcRec"), candidate.isSelDsToKKPi()); + entryDsCandRecoInfo(hfHelper.invMassDsToKKPi(candidate), candidate.pt(), outputMl[0], outputMl[2]); + entryDsCandGenInfo(isDsPrompt); + } else if (candidate.isSelDsToPiKK() >= selectionFlagDs) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDsToPiKK()[classMl->at(iclass)]; + } registry.fill(HIST("hMassDsMcRec"), hfHelper.invMassDsToPiKK(candidate), efficiencyWeightD); registry.fill(HIST("hMassDsMcRecSig"), hfHelper.invMassDsToPiKK(candidate), candidate.pt(), efficiencyWeightD); registry.fill(HIST("hMassDsVsPtMcRec"), hfHelper.invMassDsToPiKK(candidate), candidate.pt(), efficiencyWeightD); - registry.fill(HIST("hSelectionStatusDsToPiKK"), candidate.isSelDsToPiKK()); - } - if (candidate.isSelDsToKKPi() >= selectionFlagDs && candidate.isSelDsToPiKK() >= selectionFlagDs) { - registry.fill(HIST("hCountSelectionStatusDsToKKPiAndToPiKK"), 0.); + registry.fill(HIST("hSelectionStatusDsToPiKKMcRec"), candidate.isSelDsToPiKK()); + entryDsCandRecoInfo(hfHelper.invMassDsToPiKK(candidate), candidate.pt(), outputMl[0], outputMl[2]); + entryDsCandGenInfo(isDsPrompt); } } else { fillHistoMcRecBkg(candidate); - // DsToKKPi and DsToPiKK division if (candidate.isSelDsToKKPi() >= selectionFlagDs) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDsToKKPi()[classMl->at(iclass)]; + } registry.fill(HIST("hMassDsMcRec"), hfHelper.invMassDsToKKPi(candidate), efficiencyWeightD); registry.fill(HIST("hMassDsMcRecBkg"), hfHelper.invMassDsToKKPi(candidate), candidate.pt(), efficiencyWeightD); registry.fill(HIST("hMassDsVsPtMcRec"), hfHelper.invMassDsToKKPi(candidate), candidate.pt(), efficiencyWeightD); registry.fill(HIST("hSelectionStatusDsToKKPi"), candidate.isSelDsToKKPi()); } else if (candidate.isSelDsToPiKK() >= selectionFlagDs) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDsToPiKK()[classMl->at(iclass)]; + } registry.fill(HIST("hMassDsMcRec"), hfHelper.invMassDsToPiKK(candidate), efficiencyWeightD); registry.fill(HIST("hMassDsMcRecBkg"), hfHelper.invMassDsToPiKK(candidate), candidate.pt(), efficiencyWeightD); registry.fill(HIST("hMassDsVsPtMcRec"), hfHelper.invMassDsToPiKK(candidate), candidate.pt(), efficiencyWeightD); registry.fill(HIST("hSelectionStatusDsToPiKK"), candidate.isSelDsToPiKK()); } } - std::vector outputMl = {-1., -1., -1.}; // Ds-Hadron correlation dedicated section // if the candidate is selected as Ds, search for Hadron and evaluate correlations @@ -523,24 +533,23 @@ struct HfCorrelatorDsHadrons { continue; } bool isPhysicalPrimary = false; + int trackOrigin = -1; // DsToKKPi and DsToPiKK division - if (candidate.isSelDsToKKPi() >= selectionFlagDs) { + if (isCorrectInvMassHypo && candidate.isSelDsToKKPi() >= selectionFlagDs) { entryDsHadronPair(getDeltaPhi(track.phi(), candidate.phi()), track.eta() - candidate.eta(), candidate.pt(), track.pt(), poolBin); - entryDsHadronRecoInfo(hfHelper.invMassDsToKKPi(candidate), isDsSignal); - for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { - outputMl[iclass] = candidate.mlProbDsToKKPi()[classMl->at(iclass)]; - } + entryDsHadronRecoInfo(hfHelper.invMassDsToKKPi(candidate), isDsSignal, isDecayChan); entryDsHadronMlInfo(outputMl[0], outputMl[2]); if (track.has_mcParticle()) { auto mcParticle = track.template mcParticle_as(); isPhysicalPrimary = mcParticle.isPhysicalPrimary(); - entryDsHadronGenInfo(isDsPrompt, isPhysicalPrimary); + trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); + entryDsHadronGenInfo(isDsPrompt, isPhysicalPrimary, trackOrigin); } else { - entryDsHadronGenInfo(isDsPrompt, isPhysicalPrimary); + entryDsHadronGenInfo(isDsPrompt, isPhysicalPrimary, 0); registry.fill(HIST("hFakeTracksMcRec"), track.pt()); } // for secondary particle fraction estimation @@ -551,23 +560,21 @@ struct HfCorrelatorDsHadrons { } } entryTrackRecoInfo(track.dcaXY(), track.dcaZ(), track.tpcNClsCrossedRows()); - } else if (candidate.isSelDsToPiKK() >= selectionFlagDs) { + } else if (isCorrectInvMassHypo && candidate.isSelDsToPiKK() >= selectionFlagDs) { entryDsHadronPair(getDeltaPhi(track.phi(), candidate.phi()), track.eta() - candidate.eta(), candidate.pt(), track.pt(), poolBin); - entryDsHadronRecoInfo(hfHelper.invMassDsToPiKK(candidate), isDsSignal); - for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { - outputMl[iclass] = candidate.mlProbDsToPiKK()[classMl->at(iclass)]; - } + entryDsHadronRecoInfo(hfHelper.invMassDsToPiKK(candidate), isDsSignal, isDecayChan); entryDsHadronMlInfo(outputMl[0], outputMl[2]); if (track.has_mcParticle()) { auto mcParticle = track.template mcParticle_as(); isPhysicalPrimary = mcParticle.isPhysicalPrimary(); - entryDsHadronGenInfo(isDsPrompt, isPhysicalPrimary); + trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); + entryDsHadronGenInfo(isDsPrompt, isPhysicalPrimary, trackOrigin); } else { - entryDsHadronGenInfo(isDsPrompt, false); + entryDsHadronGenInfo(isDsPrompt, false, 0); registry.fill(HIST("hFakeTracksMcRec"), track.pt()); } // for secondary particle fraction estimation @@ -585,181 +592,155 @@ struct HfCorrelatorDsHadrons { } PROCESS_SWITCH(HfCorrelatorDsHadrons, processMcRec, "Process MC Reco mode", false); - /// Ds-Hadron correlation - for calculating candidate reconstruction efficiency using MC reco-level analysis - void processMcCandEfficiency(soa::Join const&, - soa::Join const&, - CandDsMcGen const& mcParticles, - CandDsMcReco const& candidates, - aod::TracksWMc const&) + /// Ds-Hadron correlation pair builder - for MC gen-level analysis (no filter/selection, only true signal) + void processMcGen(SelCollisionsMc const& mcCollisions, + soa::Join const& collisions, + CandDsMcGen const& mcParticles) { - auto hCandidates = registry.get(HIST("hCandidates")); - - /// Gen loop - float multiplicity = -1.; - for (auto& mcParticle : mcParticles) { - // generated candidates - if (std::abs(mcParticle.pdgCode()) == Pdg::kDS) { - auto mcCollision = mcParticle.template mcCollision_as>(); - multiplicity = mcCollision.multMCFT0A() + mcCollision.multMCFT0C(); // multFT0M = multFt0A + multFT0C - hCandidates->Fill(kCandidateStepMcGenAll, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); - if (std::abs(mcParticle.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::DsToKKPi) { - hCandidates->Fill(kCandidateStepMcGenDsToKKPi, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); - auto yDs = RecoDecay::y(mcParticle.pVector(), o2::constants::physics::MassDS); - if (std::abs(yDs) <= yCandGenMax) { - hCandidates->Fill(kCandidateStepMcCandInAcceptance, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); - } - bool isDaughterInAcceptance = true; - auto daughters = mcParticle.template daughters_as(); - for (const auto& daughter : daughters) { - if (daughter.pt() < ptDaughterMin || std::abs(daughter.eta()) > etaTrackMax) { - isDaughterInAcceptance = false; - } - } - if (isDaughterInAcceptance) { - hCandidates->Fill(kCandidateStepMcDaughtersInAcceptance, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); - fillHistoMcGen(mcParticle); - } - } - } - } + BinningTypeMcGen corrBinningMcGen{{zPoolBins, multPoolBins}, true}; - // recontructed candidates loop - for (auto& candidate : candidates) { - auto collision = candidate.template collision_as>(); - multiplicity = collision.multFT0M(); - registry.fill(HIST("hMultFT0M"), multiplicity); - if (std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DsToKKPi) { - auto prong0McPart = candidate.template prong0_as().template mcParticle_as(); - // DsToKKPi and DsToPiKK division - if (((std::abs(prong0McPart.pdgCode()) == kKPlus) && (candidate.isSelDsToKKPi() >= selectionFlagDs)) || ((std::abs(prong0McPart.pdgCode()) == kPiPlus) && (candidate.isSelDsToPiKK() >= selectionFlagDs))) { - registry.fill(HIST("hPtCand"), candidate.pt()); - hCandidates->Fill(kCandidateStepMcReco, candidate.pt(), multiplicity, candidate.originMcRec()); - if (std::abs(hfHelper.yDs(candidate)) <= yCandMax) { - hCandidates->Fill(kCandidateStepMcRecoInAcceptance, candidate.pt(), multiplicity, candidate.originMcRec()); - } - } - } - } - } - PROCESS_SWITCH(HfCorrelatorDsHadrons, processMcCandEfficiency, "Process MC for calculating candidate reconstruction efficiency", false); + for (const auto& mcCollision : mcCollisions) { - /// Ds-Hadron correlation - for calculating associated particle tracking efficiency using MC reco-level analysis - void processMcTrackEfficiency(soa::Join const&, - soa::Join const&, - CandDsMcGen const& mcParticles, - TracksWithMc const& tracksData) - { - auto hAssocTracks = registry.get(HIST("hAssocTracks")); - - /// Gen loop - float multiplicity = -1.; - float posZ = -20.; - for (auto& mcParticle : mcParticles) { - // generated tracks - if (mcParticle.isPhysicalPrimary() && ((std::abs(mcParticle.pdgCode()) == kElectron) || (std::abs(mcParticle.pdgCode()) == kMuonMinus) || (std::abs(mcParticle.pdgCode()) == kPiPlus) || (std::abs(mcParticle.pdgCode()) == kKPlus) || (std::abs(mcParticle.pdgCode()) == kProton))) { - auto mcCollision = mcParticle.template mcCollision_as>(); - multiplicity = mcCollision.multMCFT0A() + mcCollision.multMCFT0C(); // multFT0M = multFt0A + multFT0C - posZ = mcCollision.posZ(); - hAssocTracks->Fill(kAssocTrackStepMcGen, mcParticle.eta(), mcParticle.pt(), multiplicity, posZ); - if (mcParticle.pt() > ptTrackMin && std::abs(mcParticle.eta()) < etaTrackMax) { - hAssocTracks->Fill(kAssocTrackStepMcGenInAcceptance, mcParticle.eta(), mcParticle.pt(), multiplicity, posZ); - registry.fill(HIST("hPtParticleAssocMcGen"), mcParticle.pt()); - } + // auto mcCollision = collision.template mcCollision_as>(); + + int poolBin = corrBinningMcGen.getBin(std::make_tuple(mcCollision.posZ(), mcCollision.multMCFT0A())); + registry.fill(HIST("hCollisionPoolBin"), poolBin); + registry.fill(HIST("hMultFT0AMcGen"), mcCollision.multMCFT0A()); + + const auto groupedMcParticles = mcParticles.sliceBy(perCollisionCandMc, mcCollision.globalIndex()); + const auto groupedCollisions = collisions.sliceBy(collPerCollMc, mcCollision.globalIndex()); + + if (groupedCollisions.size() < 1) { // Skipping MC events that have no reconstructed collisions + continue; } - } + if (groupedCollisions.size() > 1 && removeCollWSplitVtx) { // Skipping MC events that have more than one reconstructed collision + continue; + } + + /// loop over reconstructed collisions + for (const auto& collision : groupedCollisions) { - // recontructed tracks loop - for (auto& track : tracksData) { - if (track.has_collision()) { - if (!track.isGlobalTrackWoDCA() || track.dcaXY() > dcaXYTrackMax || track.dcaZ() > dcaZTrackMax || track.tpcNClsCrossedRows() < nTpcCrossedRaws) { + // reco collision selection + if (useSel8 && !collision.sel8()) { continue; } - auto collision = track.template collision_as>(); - if (useSel8ForTrackEff && !collision.sel8()) { + if (std::abs(collision.posZ()) > 10.) { continue; } - multiplicity = collision.multFT0M(); - posZ = collision.posZ(); - registry.fill(HIST("hZVtx"), posZ); - registry.fill(HIST("hMultFT0M"), multiplicity); - hAssocTracks->Fill(kAssocTrackStepRecoAll, track.eta(), track.pt(), multiplicity, posZ); - if (track.has_mcParticle()) { - auto mcParticle = track.template mcParticle_as(); - hAssocTracks->Fill(kAssocTrackStepRecoMcMatch, mcParticle.eta(), mcParticle.pt(), multiplicity, posZ); - if (mcParticle.isPhysicalPrimary()) { - hAssocTracks->Fill(kAssocTrackStepRecoPrimaries, mcParticle.eta(), mcParticle.pt(), multiplicity, posZ); - registry.fill(HIST("hPtParticleAssocMcRec"), track.pt()); - } + if (selNoSameBunchPileUpColl && !(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { + continue; } - } else { - // fake track - hAssocTracks->Fill(kAssocTrackStepFake, track.eta(), track.pt(), multiplicity, posZ); - } - } + if (!collision.has_mcCollision()) { + registry.fill(HIST("hFakeCollision"), 0.); + continue; + } + + bool isDsPrompt = false; + bool isDecayChan = false; + int trackOrigin = -1; + + // MC gen level + for (const auto& particle : groupedMcParticles) { + // check if the particle is Ds + if ((std::abs(particle.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::DsToKKPi) && (particle.flagMcDecayChanGen() == decayChannel)) { + double yD = RecoDecay::y(particle.pVector(), MassDS); + if (std::abs(yD) > yCandGenMax || particle.pt() < ptCandMin || particle.pt() > ptCandMax) { + continue; + } + fillMcGenHisto(particle); + // prompt and non-prompt division + isDsPrompt = particle.originMcGen() == RecoDecay::OriginType::Prompt; + isDecayChan = particle.flagMcDecayChanGen() == decayChannel; + std::vector listDaughters{}; + std::array arrDaughDsPDG = {+kKPlus, -kKPlus, kPiPlus}; + std::array prongsId; + listDaughters.clear(); + RecoDecay::getDaughters(particle, &listDaughters, arrDaughDsPDG, 2); + int counterDaughters = 0; + if (listDaughters.size() == 3) { + for (const auto& dauIdx : listDaughters) { + // auto daughI = mcParticles.rawIteratorAt(dauIdx - mcParticles.offset()); + auto daughI = groupedMcParticles.rawIteratorAt(dauIdx - groupedMcParticles.offset()); + counterDaughters += 1; + prongsId[counterDaughters - 1] = daughI.globalIndex(); + } + } + // Ds Hadron correlation dedicated section + for (const auto& particleAssoc : groupedMcParticles) { + if (std::abs(particleAssoc.eta()) > etaTrackMax || particleAssoc.pt() < ptTrackMin || particleAssoc.pt() > ptTrackMax) { + continue; + } + if (particleAssoc.globalIndex() == prongsId[0] || particleAssoc.globalIndex() == prongsId[1] || particleAssoc.globalIndex() == prongsId[2]) { + continue; + } + if ((std::abs(particleAssoc.pdgCode()) != kElectron) && (std::abs(particleAssoc.pdgCode()) != kMuonMinus) && (std::abs(particleAssoc.pdgCode()) != kPiPlus) && (std::abs(particleAssoc.pdgCode()) != kKPlus) && (std::abs(particleAssoc.pdgCode()) != kProton)) { + continue; + } + if (!particleAssoc.isPhysicalPrimary()) { + continue; + } + // trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, particleAssoc, true); + trackOrigin = RecoDecay::getCharmHadronOrigin(groupedMcParticles, particleAssoc, true); + registry.fill(HIST("hPtParticleAssocMcGen"), particleAssoc.pt()); + entryDsHadronPair(getDeltaPhi(particleAssoc.phi(), particle.phi()), + particleAssoc.eta() - particle.eta(), + particle.pt(), + particleAssoc.pt(), + poolBin); + entryDsHadronRecoInfo(MassDS, true, isDecayChan); + entryDsHadronGenInfo(isDsPrompt, particleAssoc.isPhysicalPrimary(), trackOrigin); + } + } // end loop generated particles + } // end loop generated Ds + } // end loop reconstructed collision + } // end loop generated collision } - PROCESS_SWITCH(HfCorrelatorDsHadrons, processMcTrackEfficiency, "Process MC for calculating associated particle tracking efficiency", false); + PROCESS_SWITCH(HfCorrelatorDsHadrons, processMcGen, "Process MC Gen mode", false); - /// Ds-Hadron correlation pair builder - for MC gen-level analysis (no filter/selection, only true signal) - void processMcGen(SelCollisionsWithDsMc::iterator const& mcCollision, - CandDsMcGen const& mcParticles) + void processDerivedDataDs(SelCollisionsWithDs const& collisions, + CandDsData const& candidates, + MyTracksData const& tracks) { - auto getTracksSize = [&mcParticles](SelCollisionsWithDsMc::iterator const&) { - int nTracks = 0; - for (const auto& track : mcParticles) { - if (track.isPhysicalPrimary() && std::abs(track.eta()) < 1.0) { - nTracks++; - } - } - return nTracks; - }; - using BinningTypeMcGen = FlexibleBinningPolicy, aod::mccollision::PosZ, decltype(getTracksSize)>; - BinningTypeMcGen corrBinningMcGen{{getTracksSize}, {zPoolBins, multPoolBins}, true}; // TODO - int poolBin = corrBinningMcGen.getBin(std::make_tuple(mcCollision.posZ(), getTracksSize(mcCollision))); // TODO - registry.fill(HIST("hCollisionPoolBin"), poolBin); - bool isDsPrompt = false; - // MC gen level - for (const auto& particle : mcParticles) { - // check if the particle is Ds - if (std::abs(particle.pdgCode()) != Pdg::kDS) { - continue; - } - if (std::abs(particle.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::DsToKKPi) { - double yD = RecoDecay::y(particle.pVector(), MassDS); // TODO - if (yCandGenMax >= 0. && std::abs(yD) > yCandGenMax) { - continue; - } - if (ptCandMin >= 0. && particle.pt() < ptCandMin) { - continue; - } - fillHistoMcGen(particle); - // prompt and non-prompt division - isDsPrompt = particle.originMcGen() == RecoDecay::OriginType::Prompt; + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsDsThisColl = candidates.sliceBy(candsDsPerCollision, thisCollId); + auto tracksThisColl = tracks.sliceBy(trackIndicesPerCollision, thisCollId); - // Ds Hadron correlation dedicated section - for (const auto& particleAssoc : mcParticles) { - if (std::abs(particleAssoc.eta()) > etaTrackMax) { - continue; - } - if (particleAssoc.pt() < ptTrackMin) { - continue; + int indexHfcReducedCollision = collReduced.lastIndex() + 1; + + // Ds fill histograms and Ds candidates information stored + for (const auto& candidate : candsDsThisColl) { + std::vector outputMl = {-1., -1., -1.}; + // candidate selected + if (candidate.isSelDsToKKPi() >= selectionFlagDs) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDsToKKPi()[classMl->at(iclass)]; } - if ((std::abs(particleAssoc.pdgCode()) != kElectron) && (std::abs(particleAssoc.pdgCode()) != kMuonMinus) && (std::abs(particleAssoc.pdgCode()) != kPiPlus) && (std::abs(particleAssoc.pdgCode()) != kKPlus) && (std::abs(particleAssoc.pdgCode()) != kProton)) { - continue; + candReduced(indexHfcReducedCollision, candidate.phi(), candidate.eta(), candidate.pt(), hfHelper.invMassDsToKKPi(candidate), candidate.prong0Id(), candidate.prong1Id(), candidate.prong2Id()); + candSelInfo(indexHfcReducedCollision, outputMl[0], outputMl[2]); + } else if (candidate.isSelDsToPiKK() >= selectionFlagDs) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDsToPiKK()[classMl->at(iclass)]; } - registry.fill(HIST("hPtParticleAssocMcGen"), particleAssoc.pt()); - entryDsHadronPair(getDeltaPhi(particleAssoc.phi(), particle.phi()), - particleAssoc.eta() - particle.eta(), - particle.pt(), - particleAssoc.pt(), - poolBin); - entryDsHadronRecoInfo(MassDS, true); - entryDsHadronGenInfo(isDsPrompt, particleAssoc.isPhysicalPrimary()); + candReduced(indexHfcReducedCollision, candidate.phi(), candidate.eta(), candidate.pt(), hfHelper.invMassDsToPiKK(candidate), candidate.prong0Id(), candidate.prong1Id(), candidate.prong2Id()); + candSelInfo(indexHfcReducedCollision, outputMl[0], outputMl[2]); } } + + // tracks information + for (const auto& track : tracksThisColl) { + if (!track.isGlobalTrackWoDCA()) { + continue; + } + assocTrackReduced(indexHfcReducedCollision, track.globalIndex(), track.phi(), track.eta(), track.pt()); + assocTrackSelInfo(indexHfcReducedCollision, track.tpcNClsCrossedRows(), track.itsClusterMap(), track.itsNCls(), track.dcaXY(), track.dcaZ()); + } + + collReduced(collision.multFT0M(), collision.posZ()); } } - PROCESS_SWITCH(HfCorrelatorDsHadrons, processMcGen, "Process MC Gen mode", false); + PROCESS_SWITCH(HfCorrelatorDsHadrons, processDerivedDataDs, "Process derived data Ds", false); // Event Mixing void processDataME(SelCollisionsWithDs const& collisions, @@ -804,8 +785,8 @@ struct HfCorrelatorDsHadrons { cand.pt(), pAssoc.pt(), poolBin); - entryDsHadronRecoInfo(hfHelper.invMassDsToKKPi(cand), false); - entryDsHadronGenInfo(false, false); + entryDsHadronRecoInfo(hfHelper.invMassDsToKKPi(cand), false, false); + // entryDsHadronGenInfo(false, false, 0); for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMl[iclass] = cand.mlProbDsToKKPi()[classMl->at(iclass)]; } @@ -818,8 +799,8 @@ struct HfCorrelatorDsHadrons { cand.pt(), pAssoc.pt(), poolBin); - entryDsHadronRecoInfo(hfHelper.invMassDsToPiKK(cand), false); - entryDsHadronGenInfo(false, false); + entryDsHadronRecoInfo(hfHelper.invMassDsToPiKK(cand), false, false); + // entryDsHadronGenInfo(false, false, 0); for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMl[iclass] = cand.mlProbDsToPiKK()[classMl->at(iclass)]; } @@ -833,7 +814,8 @@ struct HfCorrelatorDsHadrons { void processMcRecME(SelCollisionsWithDs const& collisions, CandDsMcReco const& candidates, - MyTracksData const& tracks) + TracksWithMc const& tracks, + aod::McParticles const& mcParticles) { BinningType corrBinning{{zPoolBins, multPoolBins}, true}; for (const auto& candidate : candidates) { @@ -844,20 +826,21 @@ struct HfCorrelatorDsHadrons { // DsToKKPi and DsToPiKK division if (candidate.isSelDsToKKPi() >= selectionFlagDs) { fillHistoMcRecSig(candidate, 0.); - registry.fill(HIST("hSelectionStatusMcRec"), candidate.isSelDsToKKPi()); } else if (candidate.isSelDsToPiKK() >= selectionFlagDs) { fillHistoMcRecSig(candidate, 0.); - registry.fill(HIST("hSelectionStatusMcRec"), candidate.isSelDsToPiKK()); } } else { fillHistoMcRecBkg(candidate); } } auto tracksTuple = std::make_tuple(candidates, tracks); - Pair pairMcRec{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + Pair pairMcRec{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; bool isDsPrompt = false; bool isDsSignal = false; + bool isDecayChan = false; + bool isPhysicalPrimary = false; + int trackOrigin = 0; for (const auto& [c1, tracks1, c2, tracks2] : pairMcRec) { int poolBin = corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multFT0M())); int poolBinDs = corrBinning.getBin(std::make_tuple(c1.posZ(), c1.multFT0M())); @@ -877,6 +860,14 @@ struct HfCorrelatorDsHadrons { isDsPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; // Ds Signal isDsSignal = std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DsToKKPi; + isDecayChan = candidate.flagMcDecayChanRec() == decayChannel; + if (pAssoc.has_mcParticle()) { + auto mcParticle = pAssoc.template mcParticle_as(); + isPhysicalPrimary = mcParticle.isPhysicalPrimary(); + trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); + } else { + registry.fill(HIST("hFakeTracksMcRec"), pAssoc.pt()); + } // DsToKKPi and DsToPiKK division if (candidate.isSelDsToKKPi() >= selectionFlagDs) { entryDsHadronPair(getDeltaPhi(pAssoc.phi(), candidate.phi()), @@ -884,29 +875,69 @@ struct HfCorrelatorDsHadrons { candidate.pt(), pAssoc.pt(), poolBin); - entryDsHadronRecoInfo(hfHelper.invMassDsToKKPi(candidate), isDsSignal); - entryDsHadronGenInfo(isDsPrompt, false); + entryDsHadronRecoInfo(hfHelper.invMassDsToKKPi(candidate), isDsSignal, isDecayChan); + entryDsHadronGenInfo(isDsPrompt, isPhysicalPrimary, trackOrigin); for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMl[iclass] = candidate.mlProbDsToKKPi()[classMl->at(iclass)]; } entryDsHadronMlInfo(outputMl[0], outputMl[2]); + entryTrackRecoInfo(pAssoc.dcaXY(), pAssoc.dcaZ(), pAssoc.tpcNClsCrossedRows()); } else if (candidate.isSelDsToPiKK() >= selectionFlagDs) { entryDsHadronPair(getDeltaPhi(pAssoc.phi(), candidate.phi()), pAssoc.eta() - candidate.eta(), candidate.pt(), pAssoc.pt(), poolBin); - entryDsHadronRecoInfo(hfHelper.invMassDsToPiKK(candidate), isDsSignal); - entryDsHadronGenInfo(isDsPrompt, false); + entryDsHadronRecoInfo(hfHelper.invMassDsToPiKK(candidate), isDsSignal, isDecayChan); + entryDsHadronGenInfo(isDsPrompt, isPhysicalPrimary, trackOrigin); for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMl[iclass] = candidate.mlProbDsToPiKK()[classMl->at(iclass)]; } entryDsHadronMlInfo(outputMl[0], outputMl[2]); + entryTrackRecoInfo(pAssoc.dcaXY(), pAssoc.dcaZ(), pAssoc.tpcNClsCrossedRows()); + } + } + } + } + PROCESS_SWITCH(HfCorrelatorDsHadrons, processMcRecME, "Process Mixed Event MC Rec", false); + + void processMcGenME(SelCollisionsMc const& collisions, + CandDsMcGen const& mcParticles) + { + BinningTypeMcGen corrBinningMcGen{{zPoolBins, multPoolBins}, true}; + auto tracksTuple = std::make_tuple(mcParticles, mcParticles); + Pair pairMcGen{corrBinningMcGen, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + for (const auto& [c1, tracks1, c2, tracks2] : pairMcGen) { + int poolBin = corrBinningMcGen.getBin(std::make_tuple(c1.posZ(), c1.multMCFT0A())); + for (const auto& [candidate, particleAssoc] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if ((std::abs(candidate.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::DsToKKPi) && (candidate.flagMcDecayChanGen() == decayChannel)) { + double yD = RecoDecay::y(candidate.pVector(), MassDS); + if (std::abs(yD) > yCandGenMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { + continue; + } + if (std::abs(particleAssoc.eta()) > etaTrackMax || particleAssoc.pt() < ptTrackMin || particleAssoc.pt() > ptTrackMax) { + continue; + } + if ((std::abs(particleAssoc.pdgCode()) != kElectron) && (std::abs(particleAssoc.pdgCode()) != kMuonMinus) && (std::abs(particleAssoc.pdgCode()) != kPiPlus) && (std::abs(particleAssoc.pdgCode()) != kKPlus) && (std::abs(particleAssoc.pdgCode()) != kProton)) { + continue; + } + if (!particleAssoc.isPhysicalPrimary()) { + continue; + } + int trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, particleAssoc, true); + bool isDsPrompt = candidate.originMcGen() == RecoDecay::OriginType::Prompt; + entryDsHadronPair(getDeltaPhi(particleAssoc.phi(), candidate.phi()), + particleAssoc.eta() - candidate.eta(), + candidate.pt(), + particleAssoc.pt(), + poolBin); + entryDsHadronRecoInfo(MassDS, true, true); + entryDsHadronGenInfo(isDsPrompt, particleAssoc.isPhysicalPrimary(), trackOrigin); } } } } - PROCESS_SWITCH(HfCorrelatorDsHadrons, processMcRecME, "Process Mixed Event MCRec", false); + PROCESS_SWITCH(HfCorrelatorDsHadrons, processMcGenME, "Process Mixed Event MC Gen", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/HFC/TableProducer/correlatorDsHadronsReduced.cxx b/PWGHF/HFC/TableProducer/correlatorDsHadronsReduced.cxx new file mode 100644 index 00000000000..31fd99530c2 --- /dev/null +++ b/PWGHF/HFC/TableProducer/correlatorDsHadronsReduced.cxx @@ -0,0 +1,205 @@ +// 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 correlatorDsHadronsReduced.cxx +/// \brief Ds-Hadrons correlator task for offline analysis +/// \author Samuele Cattaruzzi + +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/HFC/DataModel/DerivedDataCorrelationTables.h" + +using namespace o2; +using namespace o2::analysis; +using namespace o2::constants::physics; +using namespace o2::constants::math; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// Returns deltaPhi value in range [-pi/2., 3.*pi/2], typically used for correlation studies +double getDeltaPhi(double phiHadron, double phiD) +{ + return RecoDecay::constrainAngle(phiHadron - phiD, -PIHalf); +} + +// binning type +using BinningTypeDerived = ColumnBinningPolicy; + +/// Ds-Hadron correlation pair builder - for real data and data-like analysis (i.e. reco-level w/o matching request via MC truth) +struct HfCorrelatorDsHadronsReduced { + Produces entryDsHadronPair; + Produces entryDsHadronRecoInfo; + Produces entryDsHadronMlInfo; + Produces entryDsCandRecoInfo; + Produces entryTrackRecoInfo; + // Produces entryDsHadronGenInfo; + + Configurable fillHistoData{"fillHistoData", true, "Flag for filling histograms in data processes"}; + Configurable numberEventsMixed{"numberEventsMixed", 5, "Number of events mixed in ME process"}; + Configurable> binsPtD{"binsPtD", std::vector{1., 3., 5., 8., 16., 36.}, "pT bin limits for candidate mass plots"}; + Configurable> binsPtHadron{"binsPtHadron", std::vector{0.3, 1., 2., 50.}, "pT bin limits for assoc particle"}; + + SliceCache cache; + + // Preslice tracksPerCol = aod::hf_assoc_track_reduced::hfcRedCollisionId; + Preslice tracksPerCol = aod::hf_candidate_reduced::hfcRedCollisionId; + Preslice candPerCol = aod::hf_candidate_reduced::hfcRedCollisionId; + + ConfigurableAxis zPoolBins{"zPoolBins", {VARIABLE_WIDTH, -10.0, -2.5, 2.5, 10.0}, "z vertex position pools"}; + ConfigurableAxis multPoolBins{"multPoolBins", {VARIABLE_WIDTH, 0., 900., 1800., 6000.}, "event multiplicity pools (FT0M)"}; + ConfigurableAxis binsMultFT0M{"binsMultFT0M", {100, 0., 10000.}, "Multiplicity as FT0M signal amplitude"}; + ConfigurableAxis binsPosZ{"binsPosZ", {100, -10., 10.}, "primary vertex z coordinate"}; + ConfigurableAxis binsPoolBin{"binsPoolBin", {9, 0., 9.}, "PoolBin"}; + ConfigurableAxis binsEta{"binsEta", {50, -2., 2.}, "#it{#eta}"}; + ConfigurableAxis binsPhi{"binsPhi", {64, -PIHalf, 3. * PIHalf}, "#it{#varphi}"}; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext&) + { + AxisSpec axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; + AxisSpec axisPosZ = {binsPosZ, "PosZ"}; + AxisSpec axisPoolBin = {binsPoolBin, "PoolBin"}; + AxisSpec axisEta = {binsEta, "#it{#eta}"}; + AxisSpec axisPhi = {binsPhi, "#it{#varphi}"}; + AxisSpec axisPtD = {(std::vector)binsPtD, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisPtHadron = {(std::vector)binsPtHadron, "#it{p}_{T} Hadron (GeV/#it{c})"}; + + // Histograms for data analysis + if (fillHistoData) { + registry.add("hMultFT0M", "Multiplicity FT0M", {HistType::kTH1F, {axisMultFT0M}}); + registry.add("hZVtx", "z vertex", {HistType::kTH1F, {axisPosZ}}); + registry.add("hCollisionPoolBin", "Collision pool bin", {HistType::kTH1F, {axisPoolBin}}); + registry.add("hDsPoolBin", "Ds candidates pool bin", {HistType::kTH1F, {axisPoolBin}}); + registry.add("hPhiVsPtCand", "Ds candidates phiVsPt", {HistType::kTH2F, {{axisPhi}, {axisPtD}}}); + registry.add("hPhiVsPtPartAssoc", "Particles associated phiVsPt", {HistType::kTH3F, {{axisPhi}, {axisPtD}, {axisPtHadron}}}); + registry.add("hEtaVsPtCand", "Ds candidates etaVsPt", {HistType::kTH2F, {{axisEta}, {axisPtD}}}); + registry.add("hEtaVsPtPartAssoc", "Particles associated etaVsPt", {HistType::kTH3F, {{axisEta}, {axisPtD}, {axisPtHadron}}}); + registry.add("hTracksPoolBin", "Particles associated pool bin", {HistType::kTH1F, {axisPoolBin}}); + } + } + + void processDerivedData(aod::HfcRedCollisions const& collisions, + soa::Join const& candidates, + soa::Join const& tracks) + { + + BinningTypeDerived corrBinning{{zPoolBins, multPoolBins}, true}; + + for (const auto& collision : collisions) { + int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multiplicity())); + registry.fill(HIST("hCollisionPoolBin"), poolBin); + registry.fill(HIST("hMultFT0M"), collision.multiplicity()); + registry.fill(HIST("hZVtx"), collision.posZ()); + + auto thisCollId = collision.globalIndex(); + auto candsDsThisColl = candidates.sliceBy(candPerCol, thisCollId); + auto tracksThisColl = tracks.sliceBy(tracksPerCol, thisCollId); + + for (const auto& candidate : candsDsThisColl) { + registry.fill(HIST("hDsPoolBin"), poolBin); + registry.fill(HIST("hPhiVsPtCand"), RecoDecay::constrainAngle(candidate.phiCand(), -PIHalf), candidate.ptCand()); + registry.fill(HIST("hEtaVsPtCand"), candidate.etaCand(), candidate.ptCand()); + entryDsCandRecoInfo(candidate.invMassDs(), candidate.ptCand(), candidate.bdtScorePrompt(), candidate.bdtScoreBkg()); + for (const auto& track : tracksThisColl) { + // Removing Ds daughters by checking track indices + if ((candidate.prong0Id() == track.originTrackId()) || (candidate.prong1Id() == track.originTrackId()) || (candidate.prong2Id() == track.originTrackId())) { + continue; + } + registry.fill(HIST("hTracksPoolBin"), poolBin); + registry.fill(HIST("hPhiVsPtPartAssoc"), RecoDecay::constrainAngle(track.phiAssocTrack(), -PIHalf), candidate.ptCand(), track.ptAssocTrack()); + registry.fill(HIST("hEtaVsPtPartAssoc"), track.etaAssocTrack(), candidate.ptCand(), track.ptAssocTrack()); + + entryDsHadronPair(getDeltaPhi(track.phiAssocTrack(), candidate.phiCand()), + track.etaAssocTrack() - candidate.etaCand(), + candidate.ptCand(), + track.ptAssocTrack(), + poolBin); + entryDsHadronRecoInfo(candidate.invMassDs(), false, false); + entryDsHadronMlInfo(candidate.bdtScorePrompt(), candidate.bdtScoreBkg()); + entryTrackRecoInfo(track.dcaXY(), track.dcaZ(), track.nTpcCrossedRows()); + } + } + } + } + PROCESS_SWITCH(HfCorrelatorDsHadronsReduced, processDerivedData, "Process Derived Data", true); + + void processDerivedDataME(aod::HfcRedCollisions const& collisions, + aod::DsCandReduceds const& candidates, + aod::AssocTrackReds const& tracks) + { + + BinningTypeDerived corrBinning{{zPoolBins, multPoolBins}, true}; + + for (const auto& collision : collisions) { + int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multiplicity())); + registry.fill(HIST("hCollisionPoolBin"), poolBin); + registry.fill(HIST("hMultFT0M"), collision.multiplicity()); + registry.fill(HIST("hZVtx"), collision.posZ()); + + auto thisCollId = collision.globalIndex(); + auto candsDsThisColl = candidates.sliceBy(candPerCol, thisCollId); + auto tracksThisColl = tracks.sliceBy(tracksPerCol, thisCollId); + + for (const auto& candidate : candsDsThisColl) { + registry.fill(HIST("hDsPoolBin"), poolBin); + registry.fill(HIST("hPhiVsPtCand"), RecoDecay::constrainAngle(candidate.phiCand(), -PIHalf), candidate.ptCand()); + registry.fill(HIST("hEtaVsPtCand"), candidate.etaCand(), candidate.ptCand()); + for (const auto& track : tracksThisColl) { + registry.fill(HIST("hTracksPoolBin"), poolBin); + registry.fill(HIST("hPhiVsPtPartAssoc"), RecoDecay::constrainAngle(track.phiAssocTrack(), -PIHalf), candidate.ptCand(), track.ptAssocTrack()); + registry.fill(HIST("hEtaVsPtPartAssoc"), track.etaAssocTrack(), candidate.ptCand(), track.ptAssocTrack()); + } + } + } + + auto tracksTuple = std::make_tuple(candidates, tracks); + + Pair pairData{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + + for (const auto& [c1, tracks1, c2, tracks2] : pairData) { + if (tracks1.size() == 0) { + continue; + } + + int poolBin = corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multiplicity())); + int poolBinDs = corrBinning.getBin(std::make_tuple(c1.posZ(), c1.multiplicity())); + + if (poolBin != poolBinDs) { + LOGF(info, "Error, poolBins are diffrent"); + } + + for (const auto& [cand, pAssoc] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + // LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d), track event: (%d, %d)", cand.index(), pAssoc.index(), c1.index(), c2.index(), cand.hfcRedCollisionId(), pAssoc.hfcRedCollisionId()); + + entryDsHadronPair(getDeltaPhi(pAssoc.phiAssocTrack(), cand.phiCand()), + pAssoc.etaAssocTrack() - cand.etaCand(), + cand.ptCand(), + pAssoc.ptAssocTrack(), + poolBin); + entryDsHadronRecoInfo(cand.invMassDs(), false, false); + // entryDsHadronGenInfo(false, false, 0); + } + } + } + PROCESS_SWITCH(HfCorrelatorDsHadronsReduced, processDerivedDataME, "Process Mixed Event Derived Data", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/HFC/TableProducer/correlatorDstarHadrons.cxx b/PWGHF/HFC/TableProducer/correlatorDstarHadrons.cxx index d5ba6a10efc..849d15e9013 100644 --- a/PWGHF/HFC/TableProducer/correlatorDstarHadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDstarHadrons.cxx @@ -13,6 +13,11 @@ /// \author Deependra Sharma , IITB /// \author Fabrizio Grosa , CERN +/// \brief Correlator for D* and hadrons. This task is used to produce table for D* and hadron pairs. + +// c++ +#include + // O2 #include "CommonConstants/PhysicsConstants.h" #include "Framework/ASoAHelpers.h" @@ -26,11 +31,29 @@ #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +const int nBinsPtCorrelation = 8; + +const double binsPtCorrelationsDefault[nBinsPtCorrelation + 1] = {0., 2., 4., 6., 8., 12., 16., 24., 100.}; +auto vecBinsPtCorrelationsDefault = std::vector{binsPtCorrelationsDefault, binsPtCorrelationsDefault + nBinsPtCorrelation + 1}; + +const double signalRegionLefBoundDefault[nBinsPtCorrelation] = {0.144, 0.144, 0.144, 0.144, 0.144, 0.144, 0.144, 0.144}; +auto vecSignalRegionLefBoundDefault = std::vector{signalRegionLefBoundDefault, signalRegionLefBoundDefault + nBinsPtCorrelation}; + +const double signalRegionRightBoundDefault[nBinsPtCorrelation] = {0.146, 0.146, 0.146, 0.146, 0.146, 0.146, 0.146, 0.146}; +auto vecSignalRegionRightBoundDefault = std::vector{signalRegionRightBoundDefault, signalRegionRightBoundDefault + nBinsPtCorrelation}; + +const double sidebandRightInnerDefault[nBinsPtCorrelation] = {0.147, 0.147, 0.147, 0.147, 0.147, 0.147, 0.147, 0.147}; +auto vecSidebandRightInnerDefault = std::vector{sidebandRightInnerDefault, sidebandRightInnerDefault + nBinsPtCorrelation}; + +const double sidebandRightOuterDefault[nBinsPtCorrelation] = {0.154, 0.154, 0.154, 0.154, 0.154, 0.154, 0.154, 0.154}; +auto vecSidebandRightOuterDefault = std::vector{sidebandRightOuterDefault, sidebandRightOuterDefault + nBinsPtCorrelation}; + // flaging a collision if D* meson is found. struct HfCorrelatorDstarHadronsCollisionSelector { Produces collisionWDstar; @@ -39,19 +62,19 @@ struct HfCorrelatorDstarHadronsCollisionSelector { Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity"}; Configurable ptCandMin{"ptCandMin", 1., "min. cand. pT"}; + SliceCache cache; + using DstarCandidates = soa::Join; using FilteredCandidates = soa::Filtered; - SliceCache cache; - Preslice perColDstarCand = aod::hf_cand::collisionId; - // candidates who passed the slection criteria defined in "CandidateSelectionTables.h" Filter candidateFilter = aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == selectionFlagDstar; + Preslice perColDstarCand = aod::hf_cand::collisionId; + void processCollisionSelWDstar(aod::Collisions const& collisions, FilteredCandidates const& candidates) { - for (const auto& collision : collisions) { bool isDstarFound = false; auto candidatesPerCol = candidates.sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); @@ -73,13 +96,19 @@ struct HfCorrelatorDstarHadronsCollisionSelector { } // candidate loop // LOG(info) << "processCollisionSelWDstar: isDstarFound = " << isDstarFound; collisionWDstar(isDstarFound); // compatible with collision table (filled collision by collision) - } // collision loop + } // collision loop } PROCESS_SWITCH(HfCorrelatorDstarHadronsCollisionSelector, processCollisionSelWDstar, "process only data for dstar hadron correlation", true); }; struct HfCorrelatorDstarHadrons { Produces rowsDstarHadronPair; + Produces rowsDstar; + Produces rowsAssoTrack; + + // Enable separate tables for Dstar and Track for offline Event mixing + Configurable enableSeparateTables{"enableSeparateTables", false, "Enable separate tables for Dstar and Track for offline Event mixing"}; + // Dstar candidate related configurable Configurable selectOnlyCollisionWDstar{"selectOnlyCollisionWDstar", true, " select on collisions which have atleast a Dstar candidate"}; Configurable selectionFlagDstar{"selectionFlagDstar", true, "selection flag for Dstar"}; @@ -96,13 +125,20 @@ struct HfCorrelatorDstarHadrons { Configurable ptAssoTrackMin{"ptAssoTrackMin", 0.5, "min Pt of Associated Track"}; Configurable ptAssoTrackMax{"ptAssoTrackMax", 50.0, "max pT of Associated Track"}; - ConfigurableAxis binsMultiplicity{"binsMultiplicity", {VARIABLE_WIDTH, 0.0f, 2000.0f, 6000.0f, 100000.0f}, "Mixing bins - multiplicity"}; - ConfigurableAxis binsZVtx{"binsZVtx", {VARIABLE_WIDTH, -10.0f, -2.5f, 2.5f, 10.0f}, "Mixing bins - z-vertex"}; + Configurable> binsPtCorrelations{"binsPtCorrelations", std::vector{vecBinsPtCorrelationsDefault}, "pT bin limits for correlation plots"}; + Configurable> signalRegionLefBound{"signalRegionLefBound", std::vector{vecSignalRegionLefBoundDefault}, "left boundary of signal region vs pT"}; + Configurable> signalRegionRightBound{"signalRegionRightBound", std::vector{vecSignalRegionRightBoundDefault}, "right boundary of signal region vs pT"}; + Configurable> rightSidebandOuterBoundary{"rightSidebandOuterBoundary", std::vector{vecSidebandRightOuterDefault}, "right sideband outer baoundary vs pT"}; + Configurable> rightSidebandInnerBoundary{"rightSidebandInnerBoundary", std::vector{vecSidebandRightInnerDefault}, "right sideband inner boundary"}; - // ColumnBinningPolicy> binningScheme{{binsZVtx, binsMultiplicity},true}; - // ColumnBinningPolicy> binningScheme; - using BinningType = ColumnBinningPolicy>; - BinningType binningScheme{{binsZVtx, binsMultiplicity}, true}; + // Inv Mass of Dstar and D0 Candidate + float invMassDstarParticle; + float invMassD0Particle; + int binNumber; + SliceCache cache; + + // using BinningType = ColumnBinningPolicy>; + using BinningType = ColumnBinningPolicy>; // Collision Table using CollisionsWDstar = soa::Join; @@ -122,12 +158,21 @@ struct HfCorrelatorDstarHadrons { Filter trackFilter = nabs(aod::track::eta) <= etaAbsAssoTrackMax && aod::track::pt >= ptAssoTrackMin && aod::track::pt <= ptAssoTrackMax && aod::track::dcaXY >= dcaxyAssoTrackMin && aod::track::dcaXY <= dcaxyAssoTrackMax && aod::track::dcaZ >= dcazAssoTrackMin && aod::track::dcaZ <= dcazAssoTrackMax; - SliceCache cache; + // Preslice perColCandidates = aod::hf_cand::collisionId; Preslice perColCandidates = aod::hf_cand::collisionId; // Preslice perColTracks = aod::track::collisionId; Preslice perColTracks = aod::track::collisionId; + ConfigurableAxis binsMultiplicity{"binsMultiplicity", {VARIABLE_WIDTH, 0.0f, 2000.0f, 6000.0f, 100000.0f}, "Mixing bins - multiplicity"}; + ConfigurableAxis binsZVtx{"binsZVtx", {VARIABLE_WIDTH, -10.0f, -2.5f, 2.5f, 10.0f}, "Mixing bins - z-vertex"}; + BinningType binningScheme{{binsZVtx, binsMultiplicity}, true}; + // Eta Phi Axes + ConfigurableAxis axisEta{"axisEta", {16, -1.0, 1.0}, "Eta Axis"}; + ConfigurableAxis axisPhi{"axisPhi", {64, 0.0, 3.14}, "Phi Axis"}; + ConfigurableAxis axisDeltaEta{"axisDeltaEta", {31, -2.0, 2.0}, "Delta Eta Axis"}; + ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {64, -o2::constants::math::PIHalf, 3.0 * o2::constants::math::PIHalf}, "Delta Phi Axis"}; + HistogramRegistry registry{ "registry", {{"hTriggerColCandPairCounts", "Counts of Trigger Collision, Trigger Candidates and Pair Counts", {HistType::kTH1F, {{3, 0.0, 3.0}}}}}}; @@ -139,7 +184,28 @@ struct HfCorrelatorDstarHadrons { LOGP(fatal, "One and only one process function must be enabled at a time."); } + invMassDstarParticle = -999.0; + invMassD0Particle = -999.0; + binNumber = -2; + binningScheme = {{binsZVtx, binsMultiplicity}, true}; + + registry.add("QA/hCandsPerCol", "Candidates per Collision", {HistType::kTH1D, {{100, 0.0, 100.0}}}); + registry.add("QA/hAssoTracksPerCol", "Tracks per Collision", {HistType::kTH1D, {{1000, 0.0, 1000.0}}}); + registry.add("QA/hCandsVsTracksPerCol", "Candidates vs Tracks per Collision", {HistType::kTHnSparseF, {{100, 0.0, 100.0}, {1000, 0.0, 1000.0}}}); + registry.add("QA/hCandsSignalVsTracksPerCol", "Candidates vs Tracks per Collision", {HistType::kTHnSparseF, {{100, 0.0, 100.0}, {1000, 0.0, 1000.0}}}); + registry.add("QA/hCandsSideBandVsTracksPerCol", "Candidates vs Tracks per Collision", {HistType::kTHnSparseF, {{100, 0.0, 100.0}, {1000, 0.0, 1000.0}}}); + // eta phi single particle distribution + registry.add("QA/hPhiDstarSignal", "Phi distribution of Dstar from signal region", {HistType::kTH1D, {axisPhi}}); + registry.add("QA/hEtaDstarSignal", "Eta distribution of Dstar from signal region", {HistType::kTH1D, {axisEta}}); + registry.add("QA/hPhiDstarSideBand", "Phi distribution of Dstar from side band region", {HistType::kTH1D, {axisPhi}}); + registry.add("QA/hEtaDstarSideBand", "Eta distribution of Dstar from side band region", {HistType::kTH1D, {axisEta}}); + registry.add("QA/hPhiAssoTrack", "Phi distribution of Associated Track", {HistType::kTH1D, {axisPhi}}); + registry.add("QA/hEtaAssoTrack", "Eta distribution of Associated Track", {HistType::kTH1D, {axisEta}}); + // delta eta phi distribution + registry.add("QA/hDPhiDstarAssoTrack", "Delta Phi distribution between Dstar and Associated Track", {HistType::kTH1D, {axisDeltaPhi}}); + registry.add("QA/hDEtaDstarAssoTrack", "Delta Eta distribution between Dstar and Associated Track", {HistType::kTH1D, {axisDeltaEta}}); + registry.add("QA/hDPhiDEtaDstarAssoTrack", "Delta Phi vs Delta Eta distribution between Dstar and Associated Track", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEta}}); } void processDataSameEvent(FilteredCollisions const& collisions, // only collisions who have altleast one D* @@ -147,12 +213,12 @@ struct HfCorrelatorDstarHadrons { FilteredCandidates const& candidates, aod::BCsWithTimestamps const&) { - for (const auto& collision : collisions) { registry.fill(HIST("hTriggerColCandPairCounts"), 0); // counting trigger collision auto bc = collision.bc_as(); auto timestamp = bc.timestamp(); + binNumber = binningScheme.getBin(std::make_tuple(collision.posZ(), collision.multFT0M())); auto candidatesPerCol = candidates.sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); auto tracksPerCol = tracks.sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); @@ -161,6 +227,64 @@ struct HfCorrelatorDstarHadrons { } // endif registry.fill(HIST("hTriggerColCandPairCounts"), 1); // counting number of trigger particle + registry.fill(HIST("QA/hCandsPerCol"), candidatesPerCol.size()); + registry.fill(HIST("QA/hAssoTracksPerCol"), tracksPerCol.size()); + registry.fill(HIST("QA/hCandsVsTracksPerCol"), candidatesPerCol.size(), tracksPerCol.size()); + + int nCandsSignal = 0; + int nCandsSideBand = 0; + // Single particle distribution for canfdidates + for (const auto& cand : candidatesPerCol) { + auto gItriggerParticle = cand.globalIndex(); + if (cand.signSoftPi() > 0) { + invMassDstarParticle = cand.invMassDstar(); + invMassD0Particle = cand.invMassD0(); + } else { + invMassDstarParticle = cand.invMassAntiDstar(); + invMassD0Particle = cand.invMassD0Bar(); + } + auto ptDstar = cand.pt(); + int corrBinPtDstar = o2::analysis::findBin(binsPtCorrelations, ptDstar); + auto deltaM = cand.invMassDstar() - cand.invMassD0(); + if (deltaM > signalRegionLefBound->at(corrBinPtDstar) && deltaM < signalRegionRightBound->at(corrBinPtDstar)) { + // Signal Region + registry.fill(HIST("QA/hPhiDstarSignal"), cand.phi()); + registry.fill(HIST("QA/hEtaDstarSignal"), cand.eta()); + nCandsSignal++; + } else if (deltaM > rightSidebandInnerBoundary->at(corrBinPtDstar) && deltaM < rightSidebandOuterBoundary->at(corrBinPtDstar)) { + // Side Band Region + registry.fill(HIST("QA/hPhiDstarSideBand"), cand.phi()); + registry.fill(HIST("QA/hEtaDstarSideBand"), cand.eta()); + nCandsSideBand++; + } + registry.fill(HIST("QA/hCandsSignalVsTracksPerCol"), nCandsSignal, tracksPerCol.size()); + registry.fill(HIST("QA/hCandsSideBandVsTracksPerCol"), nCandsSideBand, tracksPerCol.size()); + + if (enableSeparateTables) { + rowsDstar(collision.globalIndex(), + gItriggerParticle, + cand.phi(), + cand.eta(), + cand.pt(), + invMassDstarParticle, + invMassD0Particle, + timestamp, + binNumber); + } + } // Dstar loop + // Single particle distribution for tracks + for (const auto& track : tracksPerCol) { + registry.fill(HIST("QA/hPhiAssoTrack"), track.phi()); + registry.fill(HIST("QA/hEtaAssoTrack"), track.eta()); + if (enableSeparateTables) { + rowsAssoTrack(track.phi(), + track.eta(), + track.pt(), + binNumber, + collision.globalIndex(), + timestamp); + } + } // Track loop // Pair creation for (const auto& [triggerParticle, assocParticle] : soa::combinations(soa::CombinationsFullIndexPolicy(candidatesPerCol, tracksPerCol))) { @@ -170,7 +294,7 @@ struct HfCorrelatorDstarHadrons { // Track rejection based on daughter index if ((triggerParticle.prong0Id() == gIassocParticle) || (triggerParticle.prong1Id() == gIassocParticle) || (triggerParticle.prongPiId() == gIassocParticle)) { continue; // rejected pair if associated particle is same as any of daughter particle - } // endif + } // endif // Trigger Particle Rejection if (triggerParticle.pt() > ptDstarMax || triggerParticle.pt() < ptDstarMin) { @@ -182,46 +306,33 @@ struct HfCorrelatorDstarHadrons { } // endif registry.fill(HIST("hTriggerColCandPairCounts"), 2); // counting number of pairs + registry.fill(HIST("QA/hDPhiDstarAssoTrack"), triggerParticle.phi() - assocParticle.phi()); + registry.fill(HIST("QA/hDEtaDstarAssoTrack"), triggerParticle.eta() - assocParticle.eta()); + registry.fill(HIST("QA/hDPhiDEtaDstarAssoTrack"), triggerParticle.phi() - assocParticle.phi(), triggerParticle.eta() - assocParticle.eta()); + + if (triggerParticle.signSoftPi() > 0) { + invMassDstarParticle = triggerParticle.invMassDstar(); + invMassD0Particle = triggerParticle.invMassD0(); + } else { + invMassDstarParticle = triggerParticle.invMassAntiDstar(); + invMassD0Particle = triggerParticle.invMassD0Bar(); + } - auto binNumber = binningScheme.getBin(std::make_tuple(collision.posZ(), collision.multFT0M())); - - // Fill table - if (triggerParticle.signSoftPi() > 0) { // Fill Dstar candidate - - /////////////////////////////////////// - triggerParticle.invMassD0(); - /////////////////////////////////////// - rowsDstarHadronPair(collision.globalIndex(), - gItriggerParticle, - triggerParticle.phi(), - triggerParticle.eta(), - triggerParticle.pt(), - triggerParticle.invMassDstar(), - triggerParticle.invMassD0(), - gIassocParticle, - assocParticle.phi(), - assocParticle.eta(), - assocParticle.pt(), - timestamp, - binNumber); - } else { // Fill AntiDstar candidate - rowsDstarHadronPair(collision.globalIndex(), - gItriggerParticle, - triggerParticle.phi(), - triggerParticle.eta(), - triggerParticle.pt(), - triggerParticle.invMassAntiDstar(), - triggerParticle.invMassD0Bar(), - gIassocParticle, - assocParticle.phi(), - assocParticle.eta(), - assocParticle.pt(), - timestamp, - binNumber); - } // endif - + // Fill Tables + rowsDstarHadronPair(collision.globalIndex(), + gItriggerParticle, + triggerParticle.phi(), + triggerParticle.eta(), + triggerParticle.pt(), + invMassDstarParticle, + invMassD0Particle, + gIassocParticle, + assocParticle.phi(), + assocParticle.eta(), + assocParticle.pt(), + timestamp, + binNumber); } // D-H pair loop - } // collision loop } // processDataSameEvent @@ -237,51 +348,40 @@ struct HfCorrelatorDstarHadrons { Pair pairData{binningScheme, 5, -1, collisions, dstarHadronTuple, &cache}; for (const auto& [c1, candidatesPerCol, c2, tracksPerCol] : pairData) { - auto bc = c2.bc_as(); auto timestamp = bc.timestamp(); - for (const auto& [triggerParticle, assocParticle] : soa::combinations(soa::CombinationsFullIndexPolicy(candidatesPerCol, tracksPerCol))) { - auto gItriggerParticle = triggerParticle.globalIndex(); auto gIassocParticle = assocParticle.globalIndex(); - auto yDstar = triggerParticle.y(constants::physics::MassDStar); if (std::abs(yDstar) > yAbsDstarMax) { continue; } // endif - int binNumber = binningScheme.getBin(std::make_tuple(c2.posZ(), c2.multFV0M())); - // Fill table - if (triggerParticle.signSoftPi() > 0) { // Fill Dstar candidate - rowsDstarHadronPair(c2.globalIndex(), // taking c2, why not c1? - gItriggerParticle, - triggerParticle.phi(), - triggerParticle.eta(), - triggerParticle.pt(), - triggerParticle.invMassDstar(), - triggerParticle.invMassD0(), - gIassocParticle, - assocParticle.phi(), - assocParticle.eta(), - assocParticle.pt(), - timestamp, - binNumber); - } else { // Fill AntiDstar candidate - rowsDstarHadronPair(c2.globalIndex(), - gItriggerParticle, - triggerParticle.phi(), - triggerParticle.eta(), - triggerParticle.pt(), - triggerParticle.invMassAntiDstar(), - triggerParticle.invMassD0Bar(), - gIassocParticle, - assocParticle.phi(), - assocParticle.eta(), - assocParticle.pt(), - timestamp, - binNumber); - } // endif + binNumber = binningScheme.getBin(std::make_tuple(c2.posZ(), c2.multFT0M())); + + if (triggerParticle.signSoftPi() > 0) { + invMassDstarParticle = triggerParticle.invMassDstar(); + invMassD0Particle = triggerParticle.invMassD0(); + } else { + invMassDstarParticle = triggerParticle.invMassAntiDstar(); + invMassD0Particle = triggerParticle.invMassD0Bar(); + } + + // Fill Table + rowsDstarHadronPair(c2.globalIndex(), // taking c2, why not c1? + gItriggerParticle, + triggerParticle.phi(), + triggerParticle.eta(), + triggerParticle.pt(), + invMassDstarParticle, + invMassD0Particle, + gIassocParticle, + assocParticle.phi(), + assocParticle.eta(), + assocParticle.pt(), + timestamp, + binNumber); } // D-H loop diff --git a/PWGHF/HFC/TableProducer/correlatorHfeHadrons.cxx b/PWGHF/HFC/TableProducer/correlatorHfeHadrons.cxx new file mode 100644 index 00000000000..2a463696be2 --- /dev/null +++ b/PWGHF/HFC/TableProducer/correlatorHfeHadrons.cxx @@ -0,0 +1,431 @@ +// 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 correlatorHfeHadrons.cxx +/// \brief Heavy Flavour electron-Hadron correaltor task - data-like, MC-reco and MC-Kine analyses. +/// \author Rashi Gupta , IIT Indore +/// \author Ravindra Singh , IIT Indore + +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/PID/TPCPIDResponse.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/HFL/DataModel/ElectronSelectionTable.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::hf_sel_electron; +std::vector zBins{VARIABLE_WIDTH, -10.0, -2.5, 2.5, 10.0}; +std::vector multBins{VARIABLE_WIDTH, 0., 200., 500.0, 5000.}; +std::vector multBinsMcGen{VARIABLE_WIDTH, 0., 20., 50.0, 500.}; // In MCGen multiplicity is defined by counting primaries +using BinningType = ColumnBinningPolicy>; +BinningType corrBinning{{zBins, multBins}, true}; +using BinningTypeMcGen = ColumnBinningPolicy; +struct HfCorrelatorHfeHadrons { + + Produces entryElectronHadronPair; + Produces entryElectronHadronPairmcGen; + // Configurables + // Event Selection + Configurable zPvPosMax{"zPvPosMax", 10., "Maximum z of the primary vertex (cm)"}; + Configurable isRun3{"isRun3", true, "Data is from Run3 or Run2"}; + + // Associated Hadron selection + Configurable ptTrackMin{"ptTrackMin", 0.1f, "Transverse momentum range for associated hadron tracks"}; + Configurable etaTrackMax{"etaTrackMax", 0.8f, "Eta range for associated hadron tracks"}; + Configurable etaTrackMin{"etaTrackMin", -0.8f, "Eta range for associated hadron tracks"}; + Configurable dcaXYTrackMax{"dcaXYTrackMax", 0.5f, "DCA XY cut"}; + Configurable dcaZTrackMax{"dcaZTrackMax", 1.0f, "DCA Z cut"}; + + // Electron hadron correlation condition + Configurable ptCondition{"ptCondition", true, "Electron pT should be greater than associate particle pT"}; + + SliceCache cache; + using TableCollisions = o2::soa::Filtered>; + using TableCollision = TableCollisions::iterator; + using TableTracks = o2::soa::Join; + using McGenTableCollisions = soa::Join; + using McGenTableCollision = McGenTableCollisions::iterator; + using McTableCollisions = o2::soa::Filtered>; + using McTableCollision = McTableCollisions::iterator; + using McTableTracks = soa::Join; + + Filter collisionFilter = nabs(aod::collision::posZ) < zPvPosMax && aod::collision::numContrib > static_cast(1); + Preslice perCol = aod::track::collisionId; + Preslice perCollision = aod::hf_sel_electron::collisionId; + + ConfigurableAxis binsDeltaEta{"binsDeltaEta", {30, -1.8, 1.8}, "#it{#Delta#eta}"}; + ConfigurableAxis binsDeltaPhi{"binsDeltaPhi", {32, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, "#it{#Delta#varphi}"}; + ConfigurableAxis binsP{"binsP", {50, 0.0, 50}, "#it{p_{T}}(GeV/#it{c})"}; + + HistogramConfigSpec hCorrelSpec{HistType::kTHnSparseD, {{binsP}, {binsP}, {binsDeltaPhi}, {binsDeltaEta}}}; + + HistogramRegistry registry{ + "registry", + {{"hInclusiveEHCorrel", "Sparse for Delta phi and Delta eta Inclusive Electron with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", hCorrelSpec}, + {"hLSEHCorrel", "Sparse for Delta phi and Delta eta Like sign Electron pair with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", hCorrelSpec}, + {"hULSEHCorrel", "Sparse for Delta phi and Delta eta UnLike sign Electron pair with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", hCorrelSpec}, + {"hMCgenNonHfEHCorrel", "Sparse for Delta phi and Delta eta Non Hf for McGen Inclusive Electron with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", hCorrelSpec}, + {"hMCgenInclusiveEHCorrl", "Sparse for Delta phi and Delta eta for McGen Electron pair with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", hCorrelSpec}, + {"hptElectron", "hptElectron", {HistType::kTH1F, {{binsP}}}}, + + {"hMixEventInclusiveEHCorrl", "Sparse for mix event Delta phi and Delta eta Inclusive Electron with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", hCorrelSpec}, + {"hMixEventLSEHCorrel", "Sparse for mix event Delta phi and Delta eta Like sign Electron pair with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", hCorrelSpec}, + {"hMixEventULSEHCorrel", "Sparse for mix event Delta phi and Delta eta Unlike sign Electron pair with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", hCorrelSpec}, + {"hMixEventMcGenInclusiveEHCorrl", "Sparse for mix event Delta phi and Delta eta Mc gen Inclusive Electron with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", hCorrelSpec}, + {"hMixEventMcGenNonHfEHCorrl", "Sparse for mix event Delta phi and Delta eta Mc gen Inclusive Electron with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", hCorrelSpec}}}; + + void init(InitContext&) + { + registry.get(HIST("hInclusiveEHCorrel"))->Sumw2(); + registry.get(HIST("hLSEHCorrel"))->Sumw2(); + registry.get(HIST("hULSEHCorrel"))->Sumw2(); + registry.get(HIST("hMCgenInclusiveEHCorrl"))->Sumw2(); + registry.get(HIST("hMCgenNonHfEHCorrel"))->Sumw2(); + registry.get(HIST("hMixEventInclusiveEHCorrl"))->Sumw2(); + registry.get(HIST("hMixEventLSEHCorrel"))->Sumw2(); + registry.get(HIST("hMixEventULSEHCorrel"))->Sumw2(); + registry.get(HIST("hMixEventMcGenInclusiveEHCorrl"))->Sumw2(); + registry.get(HIST("hMixEventMcGenNonHfEHCorrl"))->Sumw2(); + } + + // Associated Hadron Selection Cut + template + bool selAssoHadron(T const& track) + { + if (!track.isGlobalTrackWoDCA()) { + return false; + } + + if (std::abs(track.dcaXY()) > dcaXYTrackMax || std::abs(track.dcaZ()) > dcaZTrackMax) { + return false; + } + if (track.eta() < etaTrackMin || track.eta() > etaTrackMax) { + return false; + } + if (track.pt() < ptTrackMin) { + return false; + } + return true; + } + + // Electron-hadron Correlation + template + void fillCorrelation(CollisionType const& collision, ElectronType const& electron, TracksType const& tracks) + { + if (!(isRun3 ? collision.sel8() : (collision.sel7() && collision.alias_bit(kINT7)))) + return; + int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFV0M())); + + // Construct Deta Phi between electrons and hadrons + + double ptElectron = -999; + double phiElectron = -999; + double etaElectron = -999; + + for (const auto& eTrack : electron) { + ptElectron = eTrack.ptTrack(); + phiElectron = eTrack.phiTrack(); + etaElectron = eTrack.etaTrack(); + + double deltaPhi = -999; + double deltaEta = -999; + double ptHadron = -999; + double etaHadron = -999; + double phiHadron = -999; + if (!eTrack.isEmcal()) { + continue; + } + registry.fill(HIST("hptElectron"), ptElectron); + + for (const auto& hTrack : tracks) { + if (hTrack.globalIndex() == eTrack.trackId()) { + continue; + } + + // Apply Hadron cut + if (!selAssoHadron(hTrack)) { + continue; + } + + ptHadron = hTrack.pt(); + phiHadron = hTrack.phi(); + etaHadron = hTrack.eta(); + + if (ptCondition && (ptElectron < ptHadron)) { + continue; + } + + deltaPhi = RecoDecay::constrainAngle(phiElectron - phiHadron, -o2::constants::math::PIHalf); + deltaEta = etaElectron - etaHadron; + registry.fill(HIST("hInclusiveEHCorrel"), ptElectron, ptHadron, deltaPhi, deltaEta); + int isLSElectroncorr = 0; + int isULSElectroncorr = 0; + if (eTrack.isLSElectron() > 0) { + for (int i = 0; i < eTrack.isLSElectron(); ++i) { + + registry.fill(HIST("hLSEHCorrel"), ptElectron, ptHadron, deltaPhi, deltaEta); + ++isLSElectroncorr; + } + } + if (eTrack.isULSElectron() > 0) { + for (int i = 0; i < eTrack.isULSElectron(); ++i) { + + registry.fill(HIST("hULSEHCorrel"), ptElectron, ptHadron, deltaPhi, deltaEta); + ++isULSElectroncorr; + } + } + entryElectronHadronPair(deltaPhi, deltaEta, ptElectron, ptHadron, poolBin, isLSElectroncorr, isULSElectroncorr); + } + } + } + + // mix event electron-hadron correlation + + template + void fillMixCorrelation(CollisionType1 const&, CollisionType2 const& c2, ElectronType const& tracks1, TracksType const& tracks2) + { + if (!(isRun3 ? c2.sel8() : (c2.sel7() && c2.alias_bit(kINT7)))) + return; + double ptElectronMix = -999; + double phiElectronMix = -999; + double etaElectronMix = -999; + double deltaPhiMix = -999; + double deltaEtaMix = -999; + double ptHadronMix = -999; + double etaHadronMix = -999; + double phiHadronMix = -999; + int poolBin = corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multFV0M())); + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (!t1.isEmcal()) { + continue; + } + + ptHadronMix = t2.pt(); + ptElectronMix = t1.ptTrack(); + phiElectronMix = t1.phiTrack(); + phiHadronMix = t2.phi(); + etaElectronMix = t1.etaTrack(); + etaHadronMix = t2.eta(); + if (!selAssoHadron(t2)) { + continue; + } + + if (ptCondition && (ptElectronMix < ptHadronMix)) { + continue; + } + + deltaPhiMix = RecoDecay::constrainAngle(phiElectronMix - phiHadronMix, -o2::constants::math::PIHalf); + deltaEtaMix = etaElectronMix - etaHadronMix; + + registry.fill(HIST("hMixEventInclusiveEHCorrl"), ptElectronMix, ptHadronMix, deltaPhiMix, deltaEtaMix); + int isLSElectroncorr = 0; + int isULSElectroncorr = 0; + if (t1.isLSElectron() > 0) { + for (int i = 0; i < t1.isLSElectron(); ++i) { + + registry.fill(HIST("hMixEventLSEHCorrel"), ptElectronMix, ptHadronMix, deltaPhiMix, deltaEtaMix); + ++isLSElectroncorr; + } + } + if (t1.isULSElectron() > 0) { + for (int i = 0; i < t1.isULSElectron(); ++i) { + + registry.fill(HIST("hMixEventULSEHCorrel"), ptElectronMix, ptHadronMix, deltaPhiMix, deltaEtaMix); + ++isULSElectroncorr; + } + } + entryElectronHadronPair(deltaPhiMix, deltaEtaMix, ptElectronMix, ptHadronMix, poolBin, isLSElectroncorr, isULSElectroncorr); + } + } + + // ======= Process starts for Data, Same event ============ + + void processData(TableCollision const& collision, + aod::HfCorrSelEl const& electron, + TableTracks const& tracks) + { + fillCorrelation(collision, electron, tracks); + } + + PROCESS_SWITCH(HfCorrelatorHfeHadrons, processData, "Process for Data", false); + + // ======= Process starts for McRec, Same event ============ + + void processMcRec(McTableCollision const& mcCollision, + aod::HfCorrSelEl const& mcElectron, + McTableTracks const& mcTracks) + { + fillCorrelation(mcCollision, mcElectron, mcTracks); + } + + PROCESS_SWITCH(HfCorrelatorHfeHadrons, processMcRec, "Process MC Reco mode", false); + + void processMcGen(McGenTableCollision const& mcCollision, aod::McParticles const& mcParticles, aod::HfMcGenSelEl const& electron) + { + + BinningTypeMcGen corrBinningMcGen{{zBins, multBinsMcGen}, true}; + int poolBin = corrBinningMcGen.getBin(std::make_tuple(mcCollision.posZ(), mcCollision.multMCFT0A())); + + double ptElectron = 0; + double phiElectron = 0; + double etaElectron = 0; + for (const auto& electronMc : electron) { + double ptHadron = 0; + double phiHadron = 0; + double etaHadron = 0; + double deltaPhi = 0; + double deltaEta = 0; + ptElectron = electronMc.ptTrackMc(); + phiElectron = electronMc.phiTrackMc(); + etaElectron = electronMc.etaTrackMc(); + for (const auto& particleMc : mcParticles) { + if (particleMc.globalIndex() == electronMc.trackId()) { + + continue; + } + + // Associated hadron Selection ////// + if (!particleMc.isPhysicalPrimary()) { + continue; + } + + if (particleMc.eta() < etaTrackMin || particleMc.eta() > etaTrackMax) { + continue; + } + if (particleMc.pt() < ptTrackMin) { + continue; + } + ptHadron = particleMc.pt(); + phiHadron = particleMc.phi(); + etaHadron = particleMc.eta(); + if (ptCondition && (ptElectron < ptHadron)) { + return; // Apply pT condition + } + deltaPhi = RecoDecay::constrainAngle(phiElectron - phiHadron, -o2::constants::math::PIHalf); + deltaEta = etaElectron - etaHadron; + bool isNonHfeCorr = false; + if (electronMc.isNonHfeMc()) { + + registry.fill(HIST("hMCgenNonHfEHCorrel"), ptElectron, ptHadron, deltaPhi, deltaEta); + isNonHfeCorr = true; + } else { + + registry.fill(HIST("hMCgenInclusiveEHCorrl"), ptElectron, ptHadron, deltaPhi, deltaEta); + } + entryElectronHadronPairmcGen(deltaPhi, deltaEta, ptElectron, ptHadron, poolBin, isNonHfeCorr); + } + } + } + PROCESS_SWITCH(HfCorrelatorHfeHadrons, processMcGen, "Process MC Gen mode", true); + // ====================== Implement Event mixing on Data =============================== + + // ====================== Implement Event mixing on Data =================================== + + void processDataMixedEvent(TableCollisions const& collision, aod::HfCorrSelEl const& electron, TableTracks const& tracks) + { + auto tracksTuple = std::make_tuple(electron, tracks); + Pair pair{corrBinning, 5, -1, collision, tracksTuple, &cache}; + + // loop over the rows of the new table + for (const auto& [c1, tracks1, c2, tracks2] : pair) { + + fillMixCorrelation(c1, c2, tracks1, tracks2); + } + } + PROCESS_SWITCH(HfCorrelatorHfeHadrons, processDataMixedEvent, "Process Mixed Event Data", false); + + // ====================== Implement Event mixing on McRec =================================== + + void processMcRecMixedEvent(McTableCollisions const& mccollision, aod::HfCorrSelEl const& electron, McTableTracks const& mcTracks) + { + auto tracksTuple = std::make_tuple(electron, mcTracks); + Pair pairMcRec{corrBinning, 5, -1, mccollision, tracksTuple, &cache}; + + // loop over the rows of the new table + for (const auto& [c1, tracks1, c2, tracks2] : pairMcRec) { + + fillMixCorrelation(c1, c2, tracks1, tracks2); + } + } + PROCESS_SWITCH(HfCorrelatorHfeHadrons, processMcRecMixedEvent, "Process Mixed Event MC Reco mode", false); + void processMcGenMixedEvent(McGenTableCollisions const& mcCollision, aod::HfMcGenSelEl const& electrons, aod::McParticles const& mcParticles) + { + + BinningTypeMcGen corrBinningMcGen{{zBins, multBinsMcGen}, true}; + + auto tracksTuple = std::make_tuple(electrons, mcParticles); + Pair pairMcGen{corrBinningMcGen, 5, -1, mcCollision, tracksTuple, &cache}; + + // loop over the rows of the new table + double ptElectronMix = -999; + double phiElectronMix = -999; + double etaElectronMix = -999; + double deltaPhiMix = -999; + double deltaEtaMix = -999; + double ptHadronMix = -999; + double etaHadronMix = -999; + double phiHadronMix = -999; + for (const auto& [c1, tracks1, c2, tracks2] : pairMcGen) { + int poolBin = corrBinningMcGen.getBin(std::make_tuple(c1.posZ(), c1.multMCFT0A())); + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { + ptHadronMix = t2.pt(); + ptElectronMix = t1.ptTrackMc(); + phiElectronMix = t1.phiTrackMc(); + phiHadronMix = t2.phi(); + etaElectronMix = t1.etaTrackMc(); + etaHadronMix = t2.eta(); + if (t2.eta() < etaTrackMin || t2.eta() > etaTrackMax) { + continue; + } + if (t2.pt() < ptTrackMin) { + continue; + } + if (ptCondition && (ptElectronMix < ptHadronMix)) { + continue; + } + + deltaPhiMix = RecoDecay::constrainAngle(phiElectronMix - phiHadronMix, -o2::constants::math::PIHalf); + deltaEtaMix = etaElectronMix - etaHadronMix; + bool isNonHfeCorr = false; + if (t1.isNonHfeMc()) { + isNonHfeCorr = true; + registry.fill(HIST("hMixEventMcGenNonHfEHCorrl"), ptElectronMix, ptHadronMix, deltaPhiMix, deltaEtaMix); + } else { + + registry.fill(HIST("hMixEventMcGenInclusiveEHCorrl"), ptElectronMix, ptHadronMix, deltaPhiMix, deltaEtaMix); + } + + entryElectronHadronPairmcGen(deltaPhiMix, deltaEtaMix, ptElectronMix, ptHadronMix, poolBin, isNonHfeCorr); + } + } + } + PROCESS_SWITCH(HfCorrelatorHfeHadrons, processMcGenMixedEvent, "Process Mixed Event MC Gen mode", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/HFC/TableProducer/correlatorLcHadrons.cxx b/PWGHF/HFC/TableProducer/correlatorLcHadrons.cxx index e528e6fb0e9..506f98073ef 100644 --- a/PWGHF/HFC/TableProducer/correlatorLcHadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorLcHadrons.cxx @@ -14,10 +14,15 @@ /// /// \author Marianna Mazzilli /// \author Zhen Zhang +/// \author Ravindra Singh + +#include +#include "TRandom3.h" #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/runDataProcessing.h" #include "Common/Core/TrackSelection.h" @@ -30,54 +35,34 @@ #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/HFC/Utils/utilsCorrelations.h" using namespace o2; using namespace o2::analysis; using namespace o2::constants::physics; +using namespace o2::constants::math; using namespace o2::framework; using namespace o2::framework::expressions; - +using namespace o2::analysis::hf_correlations; /// /// Returns deltaPhi values in range [-pi/2., 3.*pi/2.], typically used for correlation studies /// double getDeltaPhi(double phiLc, double phiHadron) { - return RecoDecay::constrainAngle(phiHadron - phiLc, -o2::constants::math::PIHalf); + return RecoDecay::constrainAngle(phiHadron - phiLc, -PIHalf); } -/// definition of variables for Lc hadron pairs (in data-like, Mc-reco and Mc-kine tasks) -const int nBinsPtMassAndEfficiency = o2::analysis::hf_cuts_lc_to_p_k_pi::nBinsPt; -const double efficiencyLcDefault[nBinsPtMassAndEfficiency] = {}; -auto vecEfficiencyLc = std::vector{efficiencyLcDefault, efficiencyLcDefault + nBinsPtMassAndEfficiency}; - -// histogram binning definition -const int massAxisBins = 120; -const double massAxisMin = 1.98; -const double massAxisMax = 2.58; -const int phiAxisBins = 32; -const double phiAxisMin = -o2::constants::math::PIHalf; -const double phiAxisMax = 3. * o2::constants::math::PIHalf; -const int yAxisBins = 100; -const double yAxisMin = -2.; -const double yAxisMax = 2.; -const int ptLcAxisBins = 180; -const double ptLcAxisMin = 0.; -const double ptLcAxisMax = 36.; - // definition of ME variables -using BinningType = ColumnBinningPolicy>; - -using SelectedCollisions = soa::Filtered>; -using SelectedTracks = soa::Filtered; -using SelectedCandidatesData = soa::Filtered>; -using SelectedCandidatesMcRec = soa::Filtered>; -using SelectedCollisionsMcGen = soa::Filtered>; -using SelectedTracksMcGen = soa::Filtered; +using BinningType = ColumnBinningPolicy>; +using BinningTypeMcGen = ColumnBinningPolicy; // Code to select collisions with at least one Lambda_c struct HfCorrelatorLcHadronsSelection { Produces lcSel; + Configurable useSel8{"useSel8", true, "Flag for applying sel8 for collision selection"}; + Configurable selNoSameBunchPileUpColl{"selNoSameBunchPileUpColl", true, "Flag for rejecting the collisions associated with the same bunch crossing"}; + Configurable doSelLcCollision{"doSelLcCollision", true, "Select collisions with at least one Lc"}; Configurable selectionFlagLc{"selectionFlagLc", 1, "Selection Flag for Lc"}; Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity"}; Configurable ptCandMin{"ptCandMin", 1., "min. cand. pT"}; @@ -85,79 +70,86 @@ struct HfCorrelatorLcHadronsSelection { HfHelper hfHelper; SliceCache cache; - Partition> selectedLcCandidates = aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLc || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLc; - Partition> selectedLcCandidatesMc = aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLc || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLc; + using SelCollisions = soa::Join; + using CandidatesLcData = soa::Filtered>; + using CandidatesLcMcRec = soa::Filtered>; + using CandidatesLcMcGen = soa::Join; - // Returns false if the candidate does not pass cuts on decay type, y max, and pt min. Used for data and MC reco. - template - bool kinematicCuts(const T& candidate) - { - // check decay channel flag for candidate - if (!TESTBIT(candidate.hfflag(), aod::hf_cand_3prong::DecayType::LcToPKPi)) { - return false; - } - if (yCandMax >= 0. && std::abs(hfHelper.yLc(candidate)) > yCandMax) { - return false; - } - if (ptCandMin >= 0. && candidate.pt() < ptCandMin) { - return false; - } - return true; - } + // filter on selection of Lc and decay channel Lc->PKPi + Filter lcFilter = ((o2::aod::hf_track_index::hfflag & static_cast(1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) != static_cast(0)) && (aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLc || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLc); - void processLcSelectionData(aod::Collision const& collision, - soa::Join const&) + /// Code to select collisions with at least one Lc - for real data and data-like analysis + void processLcSelectionData(SelCollisions::iterator const& collision, + CandidatesLcData const& candidates) { - bool isLcFound = 0; - if (selectedLcCandidates.size() > 0) { - auto selectedLcCandidatesGrouped = selectedLcCandidates->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); - - for (const auto& candidate : selectedLcCandidatesGrouped) { - if (!kinematicCuts(candidate)) { + bool isSelColl = true; + bool isLcFound = true; + bool isSel8 = true; + bool isNosameBunchPileUp = true; + if (doSelLcCollision) { + for (const auto& candidate : candidates) { + if (std::abs(hfHelper.yLc(candidate)) > yCandMax || candidate.pt() < ptCandMin) { + isLcFound = false; continue; } - isLcFound = 1; + isLcFound = true; break; } } - lcSel(isLcFound); + if (useSel8) { + isSel8 = collision.sel8(); + } + if (selNoSameBunchPileUpColl) { + isNosameBunchPileUp = static_cast(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)); + } + isSelColl = isLcFound && isSel8 && isNosameBunchPileUp; + lcSel(isSelColl); } PROCESS_SWITCH(HfCorrelatorLcHadronsSelection, processLcSelectionData, "Process Lc Collision Selection Data", true); - void processLcSelectionMcRec(aod::Collision const& collision, - soa::Join const&) + void processLcSelectionMcRec(SelCollisions::iterator const& collision, + CandidatesLcMcRec const& candidates) { - bool isLcFound = 0; - if (selectedLcCandidatesMc.size() > 0) { - auto selectedLcCandidatesGroupedMc = selectedLcCandidatesMc->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); - for (const auto& candidate : selectedLcCandidatesGroupedMc) { - if (!kinematicCuts(candidate)) { + bool isSelColl = true; + bool isLcFound = true; + bool isSel8 = true; + bool isNosameBunchPileUp = true; + if (doSelLcCollision) { + for (const auto& candidate : candidates) { + if (std::abs(hfHelper.yLc(candidate)) > yCandMax || candidate.pt() < ptCandMin) { + isLcFound = false; continue; } - isLcFound = 1; + isLcFound = true; break; } } - lcSel(isLcFound); + if (useSel8) { + isSel8 = collision.sel8(); + } + if (selNoSameBunchPileUpColl) { + isNosameBunchPileUp = static_cast(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)); + } + isSelColl = isLcFound && isSel8 && isNosameBunchPileUp; + lcSel(isSelColl); } PROCESS_SWITCH(HfCorrelatorLcHadronsSelection, processLcSelectionMcRec, "Process Lc Selection McRec", false); void processLcSelectionMcGen(aod::McCollision const&, - aod::McParticles const& mcParticles) + CandidatesLcMcGen const& mcParticles) { - bool isLcFound = 0; + bool isLcFound = true; for (const auto& particle : mcParticles) { if (std::abs(particle.pdgCode()) != Pdg::kLambdaCPlus) { + isLcFound = false; continue; } double yL = RecoDecay::y(particle.pVector(), MassLambdaCPlus); - if (yCandMax >= 0. && std::abs(yL) > yCandMax) { - continue; - } - if (ptCandMin >= 0. && particle.pt() < ptCandMin) { + if (std::abs(yL) > yCandMax || particle.pt() < ptCandMin) { + isLcFound = false; continue; } - isLcFound = 1; + isLcFound = true; break; } lcSel(isLcFound); @@ -168,110 +160,204 @@ struct HfCorrelatorLcHadronsSelection { // Lc-Hadron correlation pair builder - for real data and data-like analysis (i.e. reco-level w/o matching request via Mc truth) struct HfCorrelatorLcHadrons { Produces entryLcHadronPair; + Produces entryLcHadronPairY; + Produces entryLcHadronPairTrkPID; Produces entryLcHadronRecoInfo; + Produces entryLcHadronMlInfo; + Produces entryLcCandRecoInfo; + Produces entryLcHadronGenInfo; + Produces entryLcCandGenInfo; + Produces entryTrackRecoInfo; + Produces entryLc; + Produces entryHadron; + Produces entryTrkPID; Configurable selectionFlagLc{"selectionFlagLc", 1, "Selection Flag for Lc"}; + Configurable numberEventsMixed{"numberEventsMixed", 5, "number of events mixed in ME process"}; Configurable applyEfficiency{"applyEfficiency", 1, "Flag for applying Lc efficiency weights"}; Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity"}; + Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen. cand. rapidity"}; Configurable etaTrackMax{"etaTrackMax", 0.8, "max. eta of tracks"}; - Configurable dcaXYTrackMax{"dcaXYTrackMax", 0.0025, "max. DCAxy of tracks"}; - Configurable dcaZTrackMax{"dcaZTrackMax", 0.0025, "max. DCAz of tracks"}; + Configurable dcaXYTrackMax{"dcaXYTrackMax", 1., "max. DCAxy of tracks"}; + Configurable dcaZTrackMax{"dcaZTrackMax", 1., "max. DCAz of tracks"}; Configurable ptCandMin{"ptCandMin", 1., "min. cand. pT"}; + Configurable ptCandMax{"ptCandMax", 50., "max. cand. pT"}; Configurable ptTrackMin{"ptTrackMin", 0.3, "min. track pT"}; Configurable ptTrackMax{"ptTrackMax", 50., "max. track pT"}; Configurable multMin{"multMin", 0., "minimum multiplicity accepted"}; Configurable multMax{"multMax", 10000., "maximum multiplicity accepted"}; - Configurable> binsPt{"binsPt", std::vector{o2::analysis::hf_cuts_lc_to_p_k_pi::vecBinsPt}, "pT bin limits for candidate mass plots and efficiency"}; - Configurable> efficiencyLc{"efficiencyLc", std::vector{vecEfficiencyLc}, "Efficiency values for Lc"}; - ConfigurableAxis binsMultiplicity{"binsMultiplicity", {VARIABLE_WIDTH, 0.0f, 2000.0f, 6000.0f, 100000.0f}, "Mixing bins - multiplicity"}; - ConfigurableAxis binsZVtx{"binsZVtx", {VARIABLE_WIDTH, -10.0f, -2.5f, 2.5f, 10.0f}, "Mixing bins - z-vertex"}; - ConfigurableAxis binsMultiplicityMc{"binsMultiplicityMc", {VARIABLE_WIDTH, 0.0f, 20.0f, 50.0f, 500.0f}, "Mixing bins - MC multiplicity"}; // In MCGen multiplicity is defined by counting tracks + Configurable> classMl{"classMl", {0, 1, 2}, "Indexes of ML scores to be stored. Three indexes max."}; + Configurable> binsPtLc{"binsPtLc", std::vector{o2::analysis::hf_cuts_lc_to_p_k_pi::vecBinsPt}, "pT bin limits for candidate mass plots"}; + Configurable> binsPtHadron{"binsPtHadron", std::vector{0.3, 2., 4., 8., 12., 50.}, "pT bin limits for assoc particle"}; + Configurable> binsPtEfficiencyLc{"binsPtEfficiencyLc", std::vector{o2::analysis::hf_cuts_lc_to_p_k_pi::vecBinsPt}, "pT bin limits for efficiency"}; + Configurable> efficiencyLc{"efficiencyLc", {1., 1., 1., 1., 1., 1.}, "efficiency values for Lc"}; + Configurable storeAutoCorrelationFlag{"storeAutoCorrelationFlag", false, "Store flag that indicates if the track is paired to its Lc mother instead of skipping it"}; + Configurable correlateLcWithLeadingParticle{"correlateLcWithLeadingParticle", false, "Switch for correlation of Lc baryons with leading particle only"}; + Configurable pidTrkApplied{"pidTrkApplied", false, "Apply PID selection for associated tracks"}; + Configurable> trkPIDspecies{"trkPIDspecies", std::vector{o2::track::PID::Proton, o2::track::PID::Pion, o2::track::PID::Kaon}, "Trk sel: Particles species for PID, proton, pion, kaon"}; + Configurable> pidTPCMax{"pidTPCMax", std::vector{3., 0., 0.}, "maximum nSigma TPC"}; + Configurable> pidTOFMax{"pidTOFMax", std::vector{3., 0., 0.}, "maximum nSigma TOF"}; + Configurable tofPIDThreshold{"tofPIDThreshold", 0.75, "minimum pT after which TOF PID is applicable"}; + Configurable fillTrkPID{"fillTrkPID", false, "fill PID information for associated tracks"}; + Configurable forceTOF{"forceTOF", false, "fill PID information for associated tracks"}; + Configurable calTrkEff{"calTrkEff", false, "fill histograms to calculate efficiency"}; + Configurable isRecTrkPhyPrimary{"isRecTrkPhyPrimary", true, "Calculate the efficiency of reconstructed primary physical tracks"}; + Configurable calEffLcEvent{"calEffLcEvent", true, "Calculate the efficiency of Lc candidate"}; + Configurable eventFractionToAnalyze{"eventFractionToAnalyze", -1, "Fraction of events to analyze (use only for ME offline on very large samples)"}; HfHelper hfHelper; SliceCache cache; - BinningType corrBinning{{binsZVtx, binsMultiplicity}, true}; + Service pdg; + int leadingIndex = 0; + bool correlationStatus = false; + static constexpr size_t nDaughters{3u}; + TRandom3* rnd = new TRandom3(0); + // Event Mixing for the Data Mode + using SelCollisionsWithLc = soa::Filtered>; + using SelCollisionsWithLcMc = soa::Filtered>; // collisionFilter applied + using CandidatesLcData = soa::Filtered>; + // Event Mixing for the MCRec Mode + using CandidatesLcMcRec = soa::Filtered>; + using CandidatesLcMcGen = soa::Join; // flagLcFilter applied + // Event Mixing for the MCGen Mode + using McCollisionsSel = soa::Filtered>; + using McParticlesSel = soa::Filtered; + // Tracks used in Data and MC + using TracksData = soa::Filtered>; // trackFilter applied + using TracksWithMc = soa::Filtered>; // trackFilter applied // Filters for ME Filter collisionFilter = aod::hf_selection_lc_collision::lcSel == true; + Filter lcFilter = ((o2::aod::hf_track_index::hfflag & static_cast(1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) != static_cast(0)) && (aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLc || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLc); Filter trackFilter = (nabs(aod::track::eta) < etaTrackMax) && (nabs(aod::track::pt) > ptTrackMin) && (nabs(aod::track::dcaXY) < dcaXYTrackMax) && (nabs(aod::track::dcaZ) < dcaZTrackMax); - Filter lcFilter = (aod::hf_sel_candidate_lc::isSelLcToPKPi >= 1) || (aod::hf_sel_candidate_lc::isSelLcToPiKP >= 1); - Filter collisionFilterGen = aod::hf_selection_lc_collision::lcSel == true; - Filter particlesFilter = nabs(aod::mcparticle::pdgCode) == 4122 || ((aod::mcparticle::flags & (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary) == (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary); - - Preslice perCol = aod::hf_cand::collisionId; - - Partition> selectedLcCandidates = aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLc || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLc; - Partition> selectedLcCandidatesMc = aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLc || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLc; - - HistogramRegistry registry{ - "registry", - {{"hPtCand", "Lc,Hadron candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptLcAxisBins, ptLcAxisMin, ptLcAxisMax}}}}, - {"hPtProng0", "Lc,Hadron candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptLcAxisBins, ptLcAxisMin, ptLcAxisMax}}}}, - {"hPtProng1", "Lc,Hadron candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptLcAxisBins, ptLcAxisMin, ptLcAxisMax}}}}, - {"hPtProng2", "Lc,Hadron candidates;prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptLcAxisBins, ptLcAxisMin, ptLcAxisMax}}}}, - {"hSelectionStatusLcToPKPi", "Lc,Hadron candidates;selection status;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, - {"hSelectionStatusLcToPiKP", "Lc,Hadron candidates;selection status;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, - {"hEta", "Lc,Hadron candidates;candidate #it{#eta};entries", {HistType::kTH1F, {{yAxisBins, yAxisMin, yAxisMax}}}}, - {"hPhi", "Lc,Hadron candidates;candidate #it{#varphi};entries", {HistType::kTH1F, {{phiAxisBins, phiAxisMin, phiAxisMax}}}}, - {"hY", "Lc,Hadron candidates;candidate #it{y};entries", {HistType::kTH1F, {{yAxisBins, yAxisMin, yAxisMax}}}}, - {"hPtCandMcRec", "Lc,Hadron candidates - Mc reco;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptLcAxisBins, ptLcAxisMin, ptLcAxisMax}}}}, - {"hPtProng0McRec", "Lc,Hadron candidates - Mc reco;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptLcAxisBins, ptLcAxisMin, ptLcAxisMax}}}}, - {"hPtProng1McRec", "Lc,Hadron candidates - Mc reco;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptLcAxisBins, ptLcAxisMin, ptLcAxisMax}}}}, - {"hPtProng2McRec", "Lc,Hadron candidates - Mc reco;prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptLcAxisBins, ptLcAxisMin, ptLcAxisMax}}}}, - {"hSelectionStatusMcRec", "Lc,Hadron candidates - Mc reco;selection status;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, - {"hEtaMcRec", "Lc,Hadron candidates - Mc reco;candidate #it{#eta};entries", {HistType::kTH1F, {{yAxisBins, yAxisMin, yAxisMax}}}}, - {"hPhiMcRec", "Lc,Hadron candidates - Mc reco;candidate #it{#varphi};entries", {HistType::kTH1F, {{phiAxisBins, phiAxisMin, phiAxisMax}}}}, - {"hYMcRec", "Lc,Hadron candidates - Mc reco;candidate #it{y};entries", {HistType::kTH1F, {{yAxisBins, yAxisMin, yAxisMax}}}}, - {"hMcEvtCount", "Event counter - Mc gen;;entries", {HistType::kTH1F, {{1, -0.5, 0.5}}}}, - {"hPtCandMcGen", "Lc,Hadron particles - Mc gen;particle #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptLcAxisBins, ptLcAxisMin, ptLcAxisMax}}}}, - {"hPtParticleAssocMcRec", "Associated Particles - Mc Rec;Hadron #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptLcAxisBins, ptLcAxisMin, ptLcAxisMax}}}}, - {"hPtParticleAssocMcGen", "Associated Particles - Mc Gen;Hadron #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptLcAxisBins, ptLcAxisMin, ptLcAxisMax}}}}, - {"hEtaMcGen", "Lc,Hadron particles - Mc Gen;particle #it{#varphi};entries", {HistType::kTH1F, {{yAxisBins, yAxisMin, yAxisMax}}}}, - {"hPhiMcGen", "Lc,Hadron particles - Mc Gen;particle #it{#varphi};entries", {HistType::kTH1F, {{phiAxisBins, phiAxisMin, phiAxisMax}}}}, - {"hYMcGen", "Lc,Hadron candidates - Mc Gen;candidate #it{y};entries", {HistType::kTH1F, {{yAxisBins, yAxisMin, yAxisMax}}}}, - {"hCountLcHadronPerEvent", "Lc,Hadron particles - Mc Gen;Number per event;entries", {HistType::kTH1F, {{21, -0.5, 20.5}}}}, - {"hMultiplicityPreSelection", "multiplicity prior to selection;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}}, - {"hMultiplicity", "multiplicity;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}}, - {"hMultV0M", "multiplicity;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}}, - {"hZvtx", "z vertex;z vertex;entries", {HistType::kTH1F, {{200, -20., 20.}}}}, - {"hLcPoolBin", "Lc selected in pool Bin;pool Bin;entries", {HistType::kTH1F, {{9, 0., 9.}}}}, - {"hTracksPoolBin", "Tracks selected in pool Bin;pool Bin;entries", {HistType::kTH1F, {{9, 0., 9.}}}}}}; + // Preslice perTrueCollision = o2::aod::mcparticle::McCollisionId; + Preslice perTrueCollision = o2::aod::mcparticle::mcCollisionId; + // configurable axis definition + ConfigurableAxis binsMultiplicity{"binsMultiplicity", {VARIABLE_WIDTH, 0.0f, 2000.0f, 6000.0f, 100000.0f}, "Mixing bins - multiplicity"}; + ConfigurableAxis binsZVtx{"binsZVtx", {VARIABLE_WIDTH, -10.0f, -2.5f, 2.5f, 10.0f}, "Mixing bins - z-vertex"}; + ConfigurableAxis binsMultiplicityMc{"binsMultiplicityMc", {VARIABLE_WIDTH, 0.0f, 20.0f, 50.0f, 500.0f}, "Mixing bins - MC multiplicity"}; // In MCGen multiplicity is defined by counting tracks + ConfigurableAxis binsBdtScore{"binsBdtScore", {100, 0., 1.}, "Bdt output scores"}; + ConfigurableAxis binsEta{"binsEta", {50, -2., 2.}, "#it{#eta}"}; + ConfigurableAxis binsPhi{"binsPhi", {64, -PIHalf, 3. * PIHalf}, "#it{#varphi}"}; + ConfigurableAxis binsPoolBin{"binsPoolBin", {9, 0., 9.}, "PoolBin"}; + ConfigurableAxis binsMultFT0M{"binsMultFT0M", {600, 0., 6000.}, "Multiplicity as FT0M signal amplitude"}; + ConfigurableAxis binsMassLc{"binsMassLc", {200, 1.98, 2.58}, "inv. mass (p K #pi) (GeV/#it{c}^{2})"}; + + BinningType corrBinning{{binsZVtx, binsMultiplicity}, true}; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext&) { - auto vbins = (std::vector)binsPt; - registry.add("hMassLcVsPt", "Lc candidates;inv. mass (p k #pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hMassLcData", "Lc candidates;inv. mass (p k #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{massAxisBins, massAxisMin, massAxisMax}}}); - registry.add("hMassLcMcRec", "Lc candidates;inv. mass (p k #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{massAxisBins, massAxisMin, massAxisMax}}}); - registry.add("hMassLcVsPtMcRec", "Lc candidates;inv. mass (p k #pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hMassLcMcRecSig", "Lc signal candidates - Mc reco;inv. mass (p k #pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - // mass histogram for Lc background candidates only - registry.add("hMassLcMcRecBkg", "Lc background candidates - Mc reco;inv. mass (p k #pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hCountLctriggersMcGen", "Lc trigger particles - Mc gen;;N of trigger Lc", {HistType::kTH2F, {{1, -0.5, 0.5}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + AxisSpec axisMassLc = {binsMassLc, "inv. mass (p K #pi) (GeV/#it{c}^{2})"}; + AxisSpec axisEta = {binsEta, "#it{eta}"}; + AxisSpec axisPhi = {binsPhi, "#it{#varphi}"}; + AxisSpec axisPtLc = {(std::vector)binsPtLc, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisPtHadron = {(std::vector)binsPtHadron, "#it{p}_{T} Hadron (GeV/#it{c})"}; + AxisSpec axisPtTrack = {500, 0, 50, "#it{p}_{T} Hadron (GeV/#it{c})"}; + AxisSpec axisMultiplicity = {binsMultiplicity, "Multiplicity"}; + AxisSpec axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; + AxisSpec axisPosZ = {binsZVtx, "PosZ"}; + AxisSpec axisBdtScore = {binsBdtScore, "Bdt score"}; + AxisSpec axisPoolBin = {binsPoolBin, "PoolBin"}; + AxisSpec axisRapidity = {100, -2, 2, "Rapidity"}; + AxisSpec axisSign = {2, -1, 1, "Sign"}; + + registry.add("hPtCand", "Lc,Hadron candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtLc}}); + registry.add("hPtProng0", "Lc,Hadron candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtLc}}); + registry.add("hPtProng1", "Lc,Hadron candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtLc}}); + registry.add("hPtProng2", "Lc,Hadron candidates;prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtLc}}); + registry.add("hSelectionStatusLcToPKPi", "Lc,Hadron candidates;selection status;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}); + registry.add("hSelectionStatusLcToPiKP", "Lc,Hadron candidates;selection status;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}); + registry.add("hEta", "Lc,Hadron candidates;candidate #it{#eta};entries", {HistType::kTH1F, {axisEta}}); + registry.add("hPhi", "Lc,Hadron candidates;candidate #it{#varphi};entries", {HistType::kTH1F, {axisPhi}}); + registry.add("hY", "Lc,Hadron candidates;candidate #it{#y};entries", {HistType::kTH1F, {axisRapidity}}); + registry.add("hCountLcHadronPerEvent", "Lc,Hadron particles - MC gen;Number per event;entries", {HistType::kTH1F, {{21, -0.5, 20.5}}}); + registry.add("hMultiplicityPreSelection", "multiplicity prior to selection;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}); + registry.add("hMultiplicity", "multiplicity;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}); + registry.add("hMultFT0M", "multiplicity;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}); + registry.add("hZvtx", "z vertex;z vertex;entries", {HistType::kTH1F, {{200, -20., 20.}}}); + registry.add("hLcBin", "Lc selected in pool Bin;pool Bin;entries", {HistType::kTH1F, {{9, 0., 9.}}}); + registry.add("hTracksBin", "Tracks selected in pool Bin;pool Bin;entries", {HistType::kTH1F, {{9, 0., 9.}}}); + registry.add("hMassLcVsPt", "Lc candidates;inv. mass (p K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{axisMassLc}, {axisPtLc}}}); + registry.add("hMassLcData", "Lc candidates;inv. mass (p K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{axisMassLc}}}); + registry.add("hLcPoolBin", "Lc candidates pool bin", {HistType::kTH1F, {axisPoolBin}}); + registry.add("hTracksPoolBin", "Particles associated pool bin", {HistType::kTH1F, {axisPoolBin}}); + // Histograms for MC Reco analysis + registry.add("hSelectionStatusLcToPKPiMcRec", "Lc,Hadron candidates - MC reco;selection status;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}); + registry.add("hSelectionStatusLcToPiKPMcRec", "Lc,Hadron candidates - MC reco;selection status;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}); + registry.add("hMcEvtCount", "Event counter - MC gen;;entries", {HistType::kTH1F, {{1, -0.5, 0.5}}}); + registry.add("hPtProng0McRec", "Lc,Hadron candidates - MC reco;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtLc}}); + registry.add("hPtProng1McRec", "Lc,Hadron candidates - MC reco;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtLc}}); + registry.add("hPtProng2McRec", "Lc,Hadron candidates - MC reco;prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtLc}}); + registry.add("hMassLcMcRec", "Lc candidates;inv. mass (P K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{axisMassLc}}}); + registry.add("hMassLcVsPtMcRec", "Lc candidates - MC Reco", {HistType::kTH2F, {{axisMassLc}, {axisPtLc}}}); + registry.add("hMassLcMcRecSig", "Lc signal candidates - MC reco;inv. mass (p K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{axisMassLc}, {axisPtLc}}}); + registry.add("hMassLcMcRecBkg", "Lc background candidates - MC reco;inv. mass (p K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{axisMassLc}, {axisPtLc}}}); + registry.add("hPtCandMcRecSig", "Lc,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPtLc}}); + registry.add("hPtCandMcRecSigPrompt", "Lc,Hadron candidates Prompt - MC Reco", {HistType::kTH1F, {axisPtLc}}); + registry.add("hPtCandMcRecSigNonPrompt", "Lc,Hadron candidates Non Prompt - MC Reco", {HistType::kTH1F, {axisPtLc}}); + registry.add("hPtCandMcRecBkg", "Lc,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPtLc}}); + registry.add("hEtaMcRecSig", "Lc,Hadron candidates - MC Reco", {HistType::kTH1F, {axisEta}}); + registry.add("hPhiMcRecSig", "Lc,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPhi}}); + registry.add("hYMcRecSig", "Lc,Hadron candidates - MC reco;candidate #it{#y};entries", {HistType::kTH1F, {axisRapidity}}); + registry.add("hEtaMcRecBkg", "Lc,Hadron candidates - MC Reco", {HistType::kTH1F, {axisEta}}); + registry.add("hPhiMcRecBkg", "Lc,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPhi}}); + registry.add("hYMcRecBkg", "Lc,Hadron candidates - MC reco;candidate #it{#y};entries", {HistType::kTH1F, {axisRapidity}}); + registry.add("hFakeTracksMcRec", "Fake tracks - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtParticleAssocVsCandMcRec", "Associated Particle - MC Rec", {HistType::kTH2F, {{axisPtHadron}, {axisPtLc}}}); + registry.add("hPtTracksVsSignRec", "Associated Particle - MC Rec", {HistType::kTH2F, {{axisPtTrack}, {axisSign}}}); + registry.add("hPtTracksVsSignRecTrue", "Associated Particle - MC Rec (True)", {HistType::kTH2F, {{axisPtTrack}, {axisSign}}}); + registry.add("hPtTracksVsSignGen", "Associated Particle - MC Gen", {HistType::kTH2F, {{axisPtTrack}, {axisSign}}}); + registry.add("hPtPrimaryParticleAssocVsCandMcRec", "Associated Particle - MC Rec", {HistType::kTH2F, {{axisPtHadron}, {axisPtLc}}}); + registry.add("hPtVsMultiplicityMcRecPrompt", "Multiplicity FT0M - MC Rec Prompt", {HistType::kTH2F, {{axisPtLc}, {axisMultFT0M}}}); + registry.add("hPtVsMultiplicityMcRecNonPrompt", "Multiplicity FT0M - MC Rec Non Prompt", {HistType::kTH2F, {{axisPtLc}, {axisMultFT0M}}}); + // Histograms for MC Gen analysis + registry.add("hcountLctriggersMcGen", "Lc trigger particles - MC gen;;N of trigger Lc", {HistType::kTH2F, {{1, -0.5, 0.5}, {axisPtLc}}}); + registry.add("hPtCandMcGen", "Lc,Hadron particles - MC gen;particle #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtLc}}); + registry.add("hYMcGen", "Lc,Hadron candidates - MC gen;candidate #it{#y};entries", {HistType::kTH1F, {axisRapidity}}); + registry.add("hPtCandMcGenPrompt", "Lc,Hadron particles - MC Gen Prompt", {HistType::kTH1F, {axisPtLc}}); + registry.add("hPtCandMcGenNonPrompt", "Lc,Hadron particles - MC Gen Non Prompt", {HistType::kTH1F, {axisPtLc}}); + registry.add("hPtParticleAssocMcGen", "Associated Particle - MC Gen", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hEtaMcGen", "Lc,Hadron particles - MC Gen", {HistType::kTH1F, {axisEta}}); + registry.add("hPhiMcGen", "Lc,Hadron particles - MC Gen", {HistType::kTH1F, {axisPhi}}); + registry.add("hMultFT0AMcGen", "Lc,Hadron multiplicity FT0A - MC Gen", {HistType::kTH1F, {axisMultiplicity}}); + corrBinning = {{binsZVtx, binsMultiplicity}, true}; } - /// Lc-h correlation pair builder - for real data and data-like analysis (i.e. reco-level w/o matching request via Mc truth) - void processData(soa::Join::iterator const& collision, - aod::TracksWDca const& tracks, - soa::Join const&) + /// Lc-hadron correlation pair builder - for real data and data-like analysis (i.e. reco-level w/o matching request via MC truth) + void processData(SelCollisionsWithLc::iterator const& collision, + TracksData const& tracks, + CandidatesLcData const& candidates, aod::BCsWithTimestamps const&) { - // protection against empty tables to be sliced - if (selectedLcCandidates.size() == 0) { + if (candidates.size() == 0) { return; } - int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFV0M())); + + bool skipMixedEventTableFilling = false; + if (eventFractionToAnalyze > 0) { + if (rnd->Uniform(0, 1) > eventFractionToAnalyze) { + skipMixedEventTableFilling = true; + } + } + + // find leading particle + if (correlateLcWithLeadingParticle) { + leadingIndex = findLeadingParticle(tracks, etaTrackMax.value); + } + auto bc = collision.bc_as(); + int gCollisionId = collision.globalIndex(); + int64_t timeStamp = bc.timestamp(); + + int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFT0M())); int nTracks = 0; if (collision.numContrib() > 1) { for (const auto& track : tracks) { - if (std::abs(track.eta()) > etaTrackMax) { - continue; - } - if (std::abs(track.dcaXY()) > dcaXYTrackMax || std::abs(track.dcaZ()) > dcaZTrackMax) { + if (std::abs(track.eta()) > etaTrackMax || std::abs(track.dcaXY()) > dcaXYTrackMax || std::abs(track.dcaZ()) > dcaZTrackMax) { continue; } nTracks++; - registry.fill(HIST("hTracksPoolBin"), poolBin); } } registry.fill(HIST("hMultiplicityPreSelection"), nTracks); @@ -280,105 +366,145 @@ struct HfCorrelatorLcHadrons { } registry.fill(HIST("hMultiplicity"), nTracks); - auto selectedLcCandidatesGrouped = selectedLcCandidates->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); + int countLc = 0; + std::vector outputMl = {-1., -1., -1.}; - for (const auto& candidate : selectedLcCandidatesGrouped) { - if (yCandMax >= 0. && std::abs(hfHelper.yLc(candidate)) > yCandMax) { - continue; - } - if (ptCandMin >= 0. && candidate.pt() < ptCandMin) { - continue; - } - if (candidate.pt() > ptTrackMax) { + for (const auto& candidate : candidates) { + if (std::abs(hfHelper.yLc(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { continue; } - // check decay channel flag for candidate - if (!TESTBIT(candidate.hfflag(), aod::hf_cand_3prong::DecayType::LcToPKPi)) { - continue; - } - - double efficiencyWeight = 1.; + double efficiencyWeightLc = 1.; if (applyEfficiency) { - efficiencyWeight = 1. / efficiencyLc->at(o2::analysis::findBin(binsPt, candidate.pt())); + efficiencyWeightLc = 1. / efficiencyLc->at(o2::analysis::findBin(binsPtEfficiencyLc, candidate.pt())); } + auto trackPos1 = candidate.template prong0_as(); // positive daughter (negative for the antiparticles) + int8_t chargeLc = trackPos1.sign(); // charge of 1st prong will be the charge of Lc candidate + registry.fill(HIST("hPtCand"), candidate.pt()); registry.fill(HIST("hPtProng0"), candidate.ptProng0()); registry.fill(HIST("hPtProng1"), candidate.ptProng1()); registry.fill(HIST("hPtProng2"), candidate.ptProng2()); registry.fill(HIST("hEta"), candidate.eta()); - registry.fill(HIST("hPhi"), RecoDecay::constrainAngle(candidate.phi(), -o2::constants::math::PIHalf)); + registry.fill(HIST("hPhi"), RecoDecay::constrainAngle(candidate.phi(), -PIHalf)); registry.fill(HIST("hY"), hfHelper.yLc(candidate)); - registry.fill(HIST("hLcPoolBin"), poolBin); + registry.fill(HIST("hLcBin"), poolBin); if (candidate.isSelLcToPKPi() >= selectionFlagLc) { - registry.fill(HIST("hMassLcVsPt"), hfHelper.invMassLcToPKPi(candidate), candidate.pt(), efficiencyWeight); - registry.fill(HIST("hMassLcData"), hfHelper.invMassLcToPKPi(candidate), efficiencyWeight); + registry.fill(HIST("hMassLcVsPt"), hfHelper.invMassLcToPKPi(candidate), candidate.pt(), efficiencyWeightLc); + registry.fill(HIST("hMassLcData"), hfHelper.invMassLcToPKPi(candidate), efficiencyWeightLc); registry.fill(HIST("hSelectionStatusLcToPKPi"), candidate.isSelLcToPKPi()); + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbLcToPKPi()[classMl->at(iclass)]; + } + entryLcCandRecoInfo(hfHelper.invMassLcToPKPi(candidate), candidate.pt() * chargeLc, outputMl[0], outputMl[1]); // 0: BkgBDTScore, 1:PromptBDTScore + entryLc(candidate.phi(), candidate.eta(), candidate.pt() * chargeLc, hfHelper.invMassLcToPKPi(candidate), poolBin, gCollisionId, timeStamp); } if (candidate.isSelLcToPiKP() >= selectionFlagLc) { - registry.fill(HIST("hMassLcVsPt"), hfHelper.invMassLcToPiKP(candidate), candidate.pt(), efficiencyWeight); - registry.fill(HIST("hMassLcData"), hfHelper.invMassLcToPiKP(candidate), efficiencyWeight); + registry.fill(HIST("hMassLcVsPt"), hfHelper.invMassLcToPiKP(candidate), candidate.pt(), efficiencyWeightLc); + registry.fill(HIST("hMassLcData"), hfHelper.invMassLcToPiKP(candidate), efficiencyWeightLc); registry.fill(HIST("hSelectionStatusLcToPiKP"), candidate.isSelLcToPiKP()); + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbLcToPiKP()[classMl->at(iclass)]; + } + entryLcCandRecoInfo(hfHelper.invMassLcToPiKP(candidate), candidate.pt() * chargeLc, outputMl[0], outputMl[1]); // 0: BkgBDTScore, 1:PromptBDTScore + if (!skipMixedEventTableFilling) { + entryLc(candidate.phi(), candidate.eta(), candidate.pt() * chargeLc, hfHelper.invMassLcToPiKP(candidate), poolBin, gCollisionId, timeStamp); + } } + // Lc-Hadron correlation dedicated section // if the candidate is a Lc, search for Hadrons and evaluate correlations - for (const auto& track : tracks) { - if (std::abs(track.eta()) > etaTrackMax) { - continue; + // Remove Lc daughters by checking track indices + if ((candidate.prong0Id() == track.globalIndex()) || (candidate.prong1Id() == track.globalIndex()) || (candidate.prong2Id() == track.globalIndex())) { + if (!storeAutoCorrelationFlag) { + continue; + } + correlationStatus = true; } - if (track.pt() < ptTrackMin) { + if (!track.isGlobalTrackWoDCA()) { continue; } - if (std::abs(track.dcaXY()) >= dcaXYTrackMax || std::abs(track.dcaZ()) >= dcaZTrackMax) { - continue; // Remove secondary tracks + if (pidTrkApplied) { + if (!passPIDSelection(track, trkPIDspecies, pidTPCMax, pidTOFMax, tofPIDThreshold, forceTOF)) + continue; } - // Remove Lc daughters by checking track indices - if ((candidate.prong0Id() == track.globalIndex()) || (candidate.prong1Id() == track.globalIndex()) || (candidate.prong2Id() == track.globalIndex())) { - continue; + if (correlateLcWithLeadingParticle) { + if (track.globalIndex() != leadingIndex) { + continue; + } } if (candidate.isSelLcToPKPi() >= selectionFlagLc) { entryLcHadronPair(getDeltaPhi(track.phi(), candidate.phi()), track.eta() - candidate.eta(), - candidate.pt(), - track.pt(), - poolBin); + candidate.pt() * chargeLc, + track.pt() * track.sign(), + poolBin, + correlationStatus); + entryLcHadronPairY(track.y() - hfHelper.yLc(candidate)); entryLcHadronRecoInfo(hfHelper.invMassLcToPKPi(candidate), false); + entryLcHadronGenInfo(false, false, 0); + entryLcHadronMlInfo(outputMl[0], outputMl[1]); + entryTrackRecoInfo(track.dcaXY(), track.dcaZ(), track.tpcNClsCrossedRows()); + if (fillTrkPID) { + entryLcHadronPairTrkPID(track.tpcNSigmaPr(), track.tpcNSigmaKa(), track.tpcNSigmaPi(), track.tofNSigmaPr(), track.tofNSigmaKa(), track.tofNSigmaPi()); + } } if (candidate.isSelLcToPiKP() >= selectionFlagLc) { entryLcHadronPair(getDeltaPhi(track.phi(), candidate.phi()), track.eta() - candidate.eta(), - candidate.pt(), - track.pt(), - poolBin); + candidate.pt() * chargeLc, + track.pt() * track.sign(), + poolBin, + correlationStatus); + entryLcHadronPairY(track.y() - hfHelper.yLc(candidate)); entryLcHadronRecoInfo(hfHelper.invMassLcToPiKP(candidate), false); + entryLcHadronGenInfo(false, false, 0); + entryLcHadronMlInfo(outputMl[0], outputMl[1]); + entryTrackRecoInfo(track.dcaXY(), track.dcaZ(), track.tpcNClsCrossedRows()); + if (fillTrkPID) { + entryLcHadronPairTrkPID(track.tpcNSigmaPr(), track.tpcNSigmaKa(), track.tpcNSigmaPi(), track.tofNSigmaPr(), track.tofNSigmaKa(), track.tofNSigmaPi()); + } + } + if (countLc == 0) { + if (!skipMixedEventTableFilling) { + entryHadron(track.phi(), track.eta(), track.pt() * track.sign(), poolBin, gCollisionId, timeStamp); + if (fillTrkPID) { + entryTrkPID(track.tpcNSigmaPr(), track.tpcNSigmaKa(), track.tpcNSigmaPi(), track.tofNSigmaPr(), track.tofNSigmaKa(), track.tofNSigmaPi()); + } + registry.fill(HIST("hTracksBin"), poolBin); + } } } // Hadron Tracks loop - } // end outer Lc loop + countLc++; + } // end outer Lc loop registry.fill(HIST("hZvtx"), collision.posZ()); - registry.fill(HIST("hMultV0M"), collision.multFV0M()); + registry.fill(HIST("hMultFT0M"), collision.multFT0M()); } PROCESS_SWITCH(HfCorrelatorLcHadrons, processData, "Process data", true); /// Lc-Hadron correlation process starts for McRec - void processMcRec(soa::Join::iterator const& collision, - aod::TracksWDca const& tracks, - soa::Join const&) + void processMcRec(SelCollisionsWithLc::iterator const& collision, + TracksWithMc const& tracks, + CandidatesLcMcRec const& candidates, + aod::McParticles const& mcParticles) { - if (selectedLcCandidatesMc.size() == 0) { + if (candidates.size() == 0) { return; } - int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFV0M())); + + // find leading particle + if (correlateLcWithLeadingParticle) { + leadingIndex = findLeadingParticle(tracks, etaTrackMax.value); + } + + int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFT0M())); int nTracks = 0; if (collision.numContrib() > 1) { for (const auto& track : tracks) { - if (std::abs(track.eta()) > etaTrackMax) { - continue; - } - if (std::abs(track.dcaXY()) > dcaXYTrackMax || std::abs(track.dcaZ()) > dcaZTrackMax) { + if (std::abs(track.eta()) >= etaTrackMax || std::abs(track.dcaXY()) > dcaXYTrackMax || std::abs(track.dcaZ()) > dcaZTrackMax) { continue; } nTracks++; - registry.fill(HIST("hTracksPoolBin"), poolBin); } } registry.fill(HIST("hMultiplicityPreSelection"), nTracks); @@ -387,313 +513,586 @@ struct HfCorrelatorLcHadrons { } registry.fill(HIST("hMultiplicity"), nTracks); - auto selectedLcCandidatesGroupedMc = selectedLcCandidatesMc->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); - + float multiplicityFT0M = collision.multFT0M(); // Mc reco level + bool isLcPrompt = false; + bool isLcNonPrompt = false; bool isLcSignal = false; - for (const auto& candidate : selectedLcCandidatesGroupedMc) { + int countLc = 1; + for (const auto& candidate : candidates) { // check decay channel flag for candidate - if (!TESTBIT(candidate.hfflag(), aod::hf_cand_3prong::DecayType::LcToPKPi)) { - continue; - } - if (yCandMax >= 0. && std::abs(hfHelper.yLc(candidate)) > yCandMax) { - continue; - } - if (ptCandMin >= 0. && candidate.pt() < ptCandMin) { + if (std::abs(hfHelper.yLc(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { continue; } - if (candidate.pt() >= ptTrackMax) { - continue; - } - double efficiencyWeight = 1.; + double efficiencyWeightLc = 1.; if (applyEfficiency) { - efficiencyWeight = 1. / efficiencyLc->at(o2::analysis::findBin(binsPt, candidate.pt())); + efficiencyWeightLc = 1. / efficiencyLc->at(o2::analysis::findBin(binsPtEfficiencyLc, candidate.pt())); } - isLcSignal = std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::LcToPKPi; + auto trackPos1 = candidate.template prong0_as(); // positive daughter (negative for the antiparticles) + auto trackPos2 = candidate.template prong2_as(); + int8_t chargeLc = trackPos1.sign(); // charge of 1st prong will be the charge of Lc candidate + isLcSignal = TESTBIT(std::abs(candidate.flagMcMatchRec()), aod::hf_cand_3prong::DecayType::LcToPKPi); + isLcPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; + isLcNonPrompt = candidate.originMcRec() == RecoDecay::OriginType::NonPrompt; + std::vector outputMl = {-1., -1., -1.}; if (isLcSignal) { - registry.fill(HIST("hPtCandMcRec"), candidate.pt()); registry.fill(HIST("hPtProng0McRec"), candidate.ptProng0()); registry.fill(HIST("hPtProng1McRec"), candidate.ptProng1()); registry.fill(HIST("hPtProng2McRec"), candidate.ptProng2()); - registry.fill(HIST("hEtaMcRec"), candidate.eta()); - registry.fill(HIST("hPhiMcRec"), RecoDecay::constrainAngle(candidate.phi(), -o2::constants::math::PIHalf)); - registry.fill(HIST("hYMcRec"), hfHelper.yLc(candidate)); + registry.fill(HIST("hPtCandMcRecSig"), candidate.pt()); + registry.fill(HIST("hEtaMcRecSig"), candidate.eta()); + registry.fill(HIST("hPhiMcRecSig"), RecoDecay::constrainAngle(candidate.phi(), -PIHalf)); + registry.fill(HIST("hYMcRecSig"), hfHelper.yLc(candidate)); // LcToPKPi and LcToPiKP division if (candidate.isSelLcToPKPi() >= selectionFlagLc) { - registry.fill(HIST("hMassLcMcRec"), hfHelper.invMassLcToPKPi(candidate), efficiencyWeight); - registry.fill(HIST("hMassLcMcRecSig"), hfHelper.invMassLcToPKPi(candidate), candidate.pt(), efficiencyWeight); - registry.fill(HIST("hMassLcVsPtMcRec"), hfHelper.invMassLcToPKPi(candidate), candidate.pt(), efficiencyWeight); - registry.fill(HIST("hSelectionStatusMcRec"), candidate.isSelLcToPKPi()); + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbLcToPKPi()[classMl->at(iclass)]; + } + // prompt and non-prompt division + if (isLcPrompt) { + registry.fill(HIST("hPtCandMcRecSigPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityMcRecPrompt"), candidate.pt(), multiplicityFT0M); + } else if (isLcNonPrompt) { + registry.fill(HIST("hPtCandMcRecSigNonPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityMcRecNonPrompt"), candidate.pt(), multiplicityFT0M); + } + registry.fill(HIST("hMassLcMcRec"), hfHelper.invMassLcToPKPi(candidate), efficiencyWeightLc); + registry.fill(HIST("hMassLcMcRecSig"), hfHelper.invMassLcToPKPi(candidate), candidate.pt(), efficiencyWeightLc); + registry.fill(HIST("hMassLcVsPtMcRec"), hfHelper.invMassLcToPKPi(candidate), candidate.pt(), efficiencyWeightLc); + registry.fill(HIST("hSelectionStatusLcToPKPiMcRec"), candidate.isSelLcToPKPi()); + entryLcCandRecoInfo(hfHelper.invMassLcToPKPi(candidate), candidate.pt() * chargeLc, outputMl[0], outputMl[1]); // 0: BkgBDTScore, 1:PromptBDTScore + entryLcCandGenInfo(isLcPrompt); } if (candidate.isSelLcToPiKP() >= selectionFlagLc) { - registry.fill(HIST("hMassLcMcRec"), hfHelper.invMassLcToPiKP(candidate), efficiencyWeight); - registry.fill(HIST("hMassLcMcRecSig"), hfHelper.invMassLcToPiKP(candidate), candidate.pt(), efficiencyWeight); - registry.fill(HIST("hMassLcVsPtMcRec"), hfHelper.invMassLcToPiKP(candidate), candidate.pt(), efficiencyWeight); - registry.fill(HIST("hSelectionStatusMcRec"), candidate.isSelLcToPiKP()); + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbLcToPiKP()[classMl->at(iclass)]; + } + if (isLcPrompt) { + registry.fill(HIST("hPtCandMcRecSigPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityMcRecPrompt"), candidate.pt(), multiplicityFT0M); + } else if (isLcNonPrompt) { + registry.fill(HIST("hPtCandMcRecSigNonPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityMcRecNonPrompt"), candidate.pt(), multiplicityFT0M); + } + registry.fill(HIST("hMassLcMcRec"), hfHelper.invMassLcToPiKP(candidate), efficiencyWeightLc); + registry.fill(HIST("hMassLcMcRecSig"), hfHelper.invMassLcToPiKP(candidate), candidate.pt(), efficiencyWeightLc); + registry.fill(HIST("hMassLcVsPtMcRec"), hfHelper.invMassLcToPiKP(candidate), candidate.pt(), efficiencyWeightLc); + registry.fill(HIST("hSelectionStatusLcToPiKPMcRec"), candidate.isSelLcToPiKP()); + entryLcCandRecoInfo(hfHelper.invMassLcToPiKP(candidate), candidate.pt() * chargeLc, outputMl[0], outputMl[1]); // 0: BkgBDTScore, 1:PromptBDTScore + entryLcCandGenInfo(isLcPrompt); } } else { - registry.fill(HIST("hPtCandMcRec"), candidate.pt()); - registry.fill(HIST("hPtProng0McRec"), candidate.ptProng0()); - registry.fill(HIST("hPtProng1McRec"), candidate.ptProng1()); - registry.fill(HIST("hPtProng2McRec"), candidate.ptProng2()); - registry.fill(HIST("hEtaMcRec"), candidate.eta()); - registry.fill(HIST("hPhiMcRec"), RecoDecay::constrainAngle(candidate.phi(), -o2::constants::math::PIHalf)); - registry.fill(HIST("hYMcRec"), hfHelper.yLc(candidate)); + registry.fill(HIST("hPtCandMcRecBkg"), candidate.pt()); + registry.fill(HIST("hEtaMcRecBkg"), candidate.eta()); + registry.fill(HIST("hPhiMcRecBkg"), RecoDecay::constrainAngle(candidate.phi(), -PIHalf)); + registry.fill(HIST("hYMcRecBkg"), hfHelper.yLc(candidate)); // LcToPKPi and LcToPiKP division if (candidate.isSelLcToPKPi() >= selectionFlagLc) { - registry.fill(HIST("hMassLcMcRec"), hfHelper.invMassLcToPKPi(candidate), efficiencyWeight); - registry.fill(HIST("hMassLcMcRecBkg"), hfHelper.invMassLcToPKPi(candidate), candidate.pt(), efficiencyWeight); - registry.fill(HIST("hMassLcVsPtMcRec"), hfHelper.invMassLcToPKPi(candidate), candidate.pt(), efficiencyWeight); - registry.fill(HIST("hSelectionStatusMcRec"), candidate.isSelLcToPKPi()); + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbLcToPKPi()[classMl->at(iclass)]; + } + registry.fill(HIST("hMassLcMcRec"), hfHelper.invMassLcToPKPi(candidate), efficiencyWeightLc); + registry.fill(HIST("hMassLcMcRecBkg"), hfHelper.invMassLcToPKPi(candidate), candidate.pt(), efficiencyWeightLc); + registry.fill(HIST("hMassLcVsPtMcRec"), hfHelper.invMassLcToPKPi(candidate), candidate.pt(), efficiencyWeightLc); + registry.fill(HIST("hSelectionStatusLcToPKPiMcRec"), candidate.isSelLcToPKPi()); } if (candidate.isSelLcToPiKP() >= selectionFlagLc) { - registry.fill(HIST("hMassLcMcRec"), hfHelper.invMassLcToPiKP(candidate), efficiencyWeight); - registry.fill(HIST("hMassLcMcRecBkg"), hfHelper.invMassLcToPiKP(candidate), candidate.pt(), efficiencyWeight); - registry.fill(HIST("hMassLcVsPtMcRec"), hfHelper.invMassLcToPiKP(candidate), candidate.pt(), efficiencyWeight); - registry.fill(HIST("hSelectionStatusMcRec"), candidate.isSelLcToPiKP()); + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbLcToPiKP()[classMl->at(iclass)]; + } + registry.fill(HIST("hMassLcMcRec"), hfHelper.invMassLcToPiKP(candidate), efficiencyWeightLc); + registry.fill(HIST("hMassLcMcRecBkg"), hfHelper.invMassLcToPiKP(candidate), candidate.pt(), efficiencyWeightLc); + registry.fill(HIST("hMassLcVsPtMcRec"), hfHelper.invMassLcToPiKP(candidate), candidate.pt(), efficiencyWeightLc); + registry.fill(HIST("hSelectionStatusLcToPiKPMcRec"), candidate.isSelLcToPiKP()); } } - registry.fill(HIST("hLcPoolBin"), poolBin); + registry.fill(HIST("hLcBin"), poolBin); + + if (calTrkEff && countLc == 1 && (isLcSignal || !calEffLcEvent)) { + // genrated tracks + decltype(trackPos1.mcParticle_as()) mctrk{}; + if (trackPos1.has_mcParticle()) { // ambiguous tracks should be small + mctrk = trackPos1.template mcParticle_as(); + } else if (trackPos2.has_mcParticle()) { + mctrk = trackPos2.template mcParticle_as(); + } else { + continue; + } + auto gentracks = mcParticles.sliceBy(perTrueCollision, mctrk.mcCollisionId()); + for (const auto& track : gentracks) { + if (std::abs(track.eta()) > etaTrackMax || track.pt() < ptTrackMin || track.pt() > ptTrackMax) { + continue; + } + if ((std::abs(track.pdgCode()) != kElectron) && (std::abs(track.pdgCode()) != kMuonMinus) && (std::abs(track.pdgCode()) != kPiPlus) && (std::abs(track.pdgCode()) != kKPlus) && (std::abs(track.pdgCode()) != kProton)) { + continue; + } + + if (pidTrkApplied && (std::abs(track.pdgCode()) != kProton)) + continue; // proton PID + + if (!track.isPhysicalPrimary()) { + continue; + } + + auto motherTrkGen = mcParticles.iteratorAt(track.mothersIds()[0]); + if (std::abs(motherTrkGen.pdgCode()) == kLambdaCPlus) + continue; + + auto chargeTrack = pdg->GetParticle(track.pdgCode())->Charge(); // Retrieve charge + registry.fill(HIST("hPtTracksVsSignGen"), track.pt(), chargeTrack / (2 * std::abs(chargeTrack))); + } + //} + } // Lc-Hadron correlation dedicated section // if the candidate is selected as Lc, search for Hadron ad evaluate correlations for (const auto& track : tracks) { - if (std::abs(track.eta()) > etaTrackMax) { + bool isPhysicalPrimary = false; + int trackOrigin = -1; + // apply track selection + if (!track.isGlobalTrackWoDCA()) { continue; } - if (track.pt() < ptTrackMin) { - continue; + if (pidTrkApplied) { + if (!passPIDSelection(track, trkPIDspecies, pidTPCMax, pidTOFMax, tofPIDThreshold, forceTOF)) + continue; } - if (std::abs(track.dcaXY()) >= dcaXYTrackMax || std::abs(track.dcaZ()) >= dcaZTrackMax) { - continue; // Remove secondary tracks + + if (calTrkEff && countLc == 1 && (isLcSignal || !calEffLcEvent) && track.has_mcParticle()) { + auto mcParticle = track.template mcParticle_as(); + if (!mcParticle.isPhysicalPrimary() && isRecTrkPhyPrimary) + continue; + + auto motherTrk = mcParticles.iteratorAt(mcParticle.mothersIds()[0]); + if (std::abs(motherTrk.pdgCode()) == kLambdaCPlus) + continue; + + registry.fill(HIST("hPtTracksVsSignRec"), track.pt(), track.sign() / 2.); + if (std::abs(mcParticle.pdgCode()) == kProton) + registry.fill(HIST("hPtTracksVsSignRecTrue"), track.pt(), track.sign() / 2.); } + // Removing Lc daughters by checking track indices if ((candidate.prong0Id() == track.globalIndex()) || (candidate.prong1Id() == track.globalIndex()) || (candidate.prong2Id() == track.globalIndex())) { - continue; + if (!storeAutoCorrelationFlag) { + continue; + } + correlationStatus = true; + } + + if (correlateLcWithLeadingParticle) { + if (track.globalIndex() != leadingIndex) { + continue; + } } - registry.fill(HIST("hPtParticleAssocMcRec"), track.pt()); if (candidate.isSelLcToPKPi() >= selectionFlagLc) { entryLcHadronPair(getDeltaPhi(track.phi(), candidate.phi()), track.eta() - candidate.eta(), - candidate.pt(), - track.pt(), - poolBin); + candidate.pt() * chargeLc, + track.pt() * track.sign(), + poolBin, + correlationStatus); + entryLcHadronPairY(track.y() - hfHelper.yLc(candidate)); entryLcHadronRecoInfo(hfHelper.invMassLcToPKPi(candidate), isLcSignal); + if (fillTrkPID) { + entryLcHadronPairTrkPID(track.tpcNSigmaPr(), track.tpcNSigmaKa(), track.tpcNSigmaPi(), track.tofNSigmaPr(), track.tofNSigmaKa(), track.tofNSigmaPi()); + } + entryLcHadronMlInfo(outputMl[0], outputMl[1]); + if (track.has_mcParticle()) { + auto mcParticle = track.template mcParticle_as(); + isPhysicalPrimary = mcParticle.isPhysicalPrimary(); + trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); + entryLcHadronGenInfo(isLcPrompt, isPhysicalPrimary, trackOrigin); + } else { + entryLcHadronGenInfo(isLcPrompt, false, 0); + registry.fill(HIST("hFakeTracksMcRec"), track.pt()); + } + + // for secondary particle fraction estimation + registry.fill(HIST("hPtParticleAssocVsCandMcRec"), track.pt(), candidate.pt()); + if (isPhysicalPrimary) { + registry.fill(HIST("hPtPrimaryParticleAssocVsCandMcRec"), track.pt(), candidate.pt()); + } + entryTrackRecoInfo(track.dcaXY(), track.dcaZ(), track.tpcNClsCrossedRows()); } if (candidate.isSelLcToPiKP() >= selectionFlagLc) { entryLcHadronPair(getDeltaPhi(track.phi(), candidate.phi()), track.eta() - candidate.eta(), - candidate.pt(), - track.pt(), - poolBin); + candidate.pt() * chargeLc, + track.pt() * track.sign(), + poolBin, + correlationStatus); + entryLcHadronPairY(track.y() - hfHelper.yLc(candidate)); entryLcHadronRecoInfo(hfHelper.invMassLcToPiKP(candidate), isLcSignal); + if (fillTrkPID) { + entryLcHadronPairTrkPID(track.tpcNSigmaPr(), track.tpcNSigmaKa(), track.tpcNSigmaPi(), track.tofNSigmaPr(), track.tofNSigmaKa(), track.tofNSigmaPi()); + } + entryLcHadronMlInfo(outputMl[0], outputMl[1]); + if (track.has_mcParticle()) { + auto mcParticle = track.template mcParticle_as(); + isPhysicalPrimary = mcParticle.isPhysicalPrimary(); + trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); + entryLcHadronGenInfo(isLcPrompt, isPhysicalPrimary, trackOrigin); + } else { + entryLcHadronGenInfo(isLcPrompt, false, 0); + registry.fill(HIST("hFakeTracksMcRec"), track.pt()); + } + // for secondary particle fraction estimation + registry.fill(HIST("hPtParticleAssocVsCandMcRec"), track.pt(), candidate.pt()); + if (isPhysicalPrimary) { + registry.fill(HIST("hPtPrimaryParticleAssocVsCandMcRec"), track.pt(), candidate.pt()); + } + entryTrackRecoInfo(track.dcaXY(), track.dcaZ(), track.tpcNClsCrossedRows()); } } // end inner loop (Tracks) - } // end outer Lc loop + countLc++; + } // end outer Lc loop registry.fill(HIST("hZvtx"), collision.posZ()); - registry.fill(HIST("hMultV0M"), collision.multFV0M()); + registry.fill(HIST("hMultFT0M"), collision.multFT0M()); } PROCESS_SWITCH(HfCorrelatorLcHadrons, processMcRec, "Process Mc Reco mode", false); - /// Lc-Hadron correlation pair builder - for Mc gen-level analysis - void processMcGen(aod::McCollision const& mcCollision, - soa::Join const& mcParticles) + /// Lc-Hadron correlation pair builder - for Mc Gen-level analysis + void processMcGen(SelCollisionsWithLcMc::iterator const& mcCollision, + CandidatesLcMcGen const& mcParticles) { int counterLcHadron = 0; registry.fill(HIST("hMcEvtCount"), 0); - auto getTracksSize = [&mcParticles](aod::McCollision const& /*collision*/) { - int nTracks = 0; - for (const auto& track : mcParticles) { - if (track.isPhysicalPrimary() && std::abs(track.eta()) < 1.0) { - nTracks++; - } - } - return nTracks; - }; - using BinningTypeMcGen = FlexibleBinningPolicy, aod::mccollision::PosZ, decltype(getTracksSize)>; - BinningTypeMcGen corrBinningMcGen{{getTracksSize}, {binsZVtx, binsMultiplicityMc}, true}; + BinningTypeMcGen corrBinningMcGen{{binsZVtx, binsMultiplicityMc}, true}; + int poolBin = corrBinningMcGen.getBin(std::make_tuple(mcCollision.posZ(), mcCollision.multMCFT0A())); + registry.fill(HIST("hMultFT0AMcGen"), mcCollision.multMCFT0A()); + + bool isLcPrompt = false; + bool isLcNonPrompt = false; - // Mc gen level + // find leading particle + if (correlateLcWithLeadingParticle) { + leadingIndex = findLeadingParticleMcGen(mcParticles, etaTrackMax.value, ptTrackMin.value); + } + + // Mc Gen level for (const auto& particle : mcParticles) { if (std::abs(particle.pdgCode()) != Pdg::kLambdaCPlus) { continue; } - if (std::abs(particle.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::LcToPKPi) { - double yL = RecoDecay::y(particle.pVector(), MassLambdaCPlus); - if (yCandMax >= 0. && std::abs(yL) > yCandMax) { - continue; + if (!TESTBIT(std::abs(particle.flagMcMatchGen()), aod::hf_cand_3prong::DecayType::LcToPKPi)) { + continue; + } + double yL = RecoDecay::y(particle.pVector(), MassLambdaCPlus); + if (std::abs(yL) > yCandGenMax || particle.pt() < ptCandMin) { + continue; + } + registry.fill(HIST("hLcBin"), poolBin); + registry.fill(HIST("hPtCandMcGen"), particle.pt()); + registry.fill(HIST("hEtaMcGen"), particle.eta()); + registry.fill(HIST("hPhiMcGen"), RecoDecay::constrainAngle(particle.phi(), -PIHalf)); + registry.fill(HIST("hYMcGen"), yL); + + isLcPrompt = particle.originMcGen() == RecoDecay::OriginType::Prompt; + isLcNonPrompt = particle.originMcGen() == RecoDecay::OriginType::NonPrompt; + if (isLcPrompt) { + registry.fill(HIST("hPtCandMcGenPrompt"), particle.pt()); + } else if (isLcNonPrompt) { + registry.fill(HIST("hPtCandMcGenNonPrompt"), particle.pt()); + } + + // prompt and non-prompt division + std::vector listDaughters{}; + std::array arrDaughLcPDG = {kProton, -kKPlus, kPiPlus}; + std::array prongsId; + listDaughters.clear(); + RecoDecay::getDaughters(particle, &listDaughters, arrDaughLcPDG, 2); + int counterDaughters = 0; + if (listDaughters.size() == nDaughters) { + for (const auto& dauIdx : listDaughters) { + auto daughI = mcParticles.rawIteratorAt(dauIdx - mcParticles.offset()); + counterDaughters += 1; + prongsId[counterDaughters - 1] = daughI.globalIndex(); } - if (ptCandMin >= 0. && particle.pt() < ptCandMin) { + } + counterLcHadron++; + // Lc Hadron correlation dedicated section + // if it's a Lc particle, search for Hadron and evalutate correlations + registry.fill(HIST("hcountLctriggersMcGen"), 0, particle.pt()); // to count trigger Lc for normalisation + for (const auto& particleAssoc : mcParticles) { + if (std::abs(particleAssoc.eta()) > etaTrackMax || particleAssoc.pt() < ptTrackMin || particleAssoc.pt() > ptTrackMax) { continue; } - registry.fill(HIST("hPtCandMcGen"), particle.pt()); - registry.fill(HIST("hEtaMcGen"), particle.eta()); - registry.fill(HIST("hPhiMcGen"), RecoDecay::constrainAngle(particle.phi(), -o2::constants::math::PIHalf)); - registry.fill(HIST("hYMcGen"), yL); - counterLcHadron++; - - for (const auto& particleAssoc : mcParticles) { - bool flagMotherFound = false; - for (const auto& m : particleAssoc.mothers_as()) { - if (m.globalIndex() == particle.globalIndex()) { - flagMotherFound = true; - break; - } - } - if (flagMotherFound) { - continue; - } - if (std::abs(particleAssoc.eta()) > etaTrackMax) { - continue; - } - if (particleAssoc.pt() < ptTrackMin) { + if (particleAssoc.globalIndex() == prongsId[0] || particleAssoc.globalIndex() == prongsId[1] || particleAssoc.globalIndex() == prongsId[2]) { + if (!storeAutoCorrelationFlag) { continue; } + correlationStatus = true; + } - if ((std::abs(particleAssoc.pdgCode()) != kElectron) && (std::abs(particleAssoc.pdgCode()) != kMuonMinus) && (std::abs(particleAssoc.pdgCode()) != kPiPlus) && (std::abs(particle.pdgCode()) != kKPlus) && (std::abs(particleAssoc.pdgCode()) != kProton)) { + if ((std::abs(particleAssoc.pdgCode()) != kElectron) && (std::abs(particleAssoc.pdgCode()) != kMuonMinus) && (std::abs(particleAssoc.pdgCode()) != kPiPlus) && (std::abs(particle.pdgCode()) != kKPlus) && (std::abs(particleAssoc.pdgCode()) != kProton)) { + continue; + } + + if (pidTrkApplied && (std::abs(particleAssoc.pdgCode()) != kProton)) + continue; // proton PID + + if (!particleAssoc.isPhysicalPrimary()) { + continue; + } + + if (correlateLcWithLeadingParticle) { + if (particleAssoc.globalIndex() != leadingIndex) { continue; } - int poolBin = corrBinningMcGen.getBin(std::make_tuple(mcCollision.posZ(), getTracksSize(mcCollision))); - registry.fill(HIST("hPtParticleAssocMcGen"), particleAssoc.pt()); - entryLcHadronPair(getDeltaPhi(particleAssoc.phi(), particle.phi()), - particleAssoc.eta() - particle.eta(), - particle.pt(), - particleAssoc.pt(), - poolBin); - entryLcHadronRecoInfo(MassLambdaCPlus, true); - } // end inner loop - } + } + + int8_t chargeLc = pdg->GetParticle(particle.pdgCode())->Charge(); // Retrieve charge + int8_t chargeAssoc = pdg->GetParticle(particleAssoc.pdgCode())->Charge(); // Retrieve charge + + int trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, particleAssoc, true); + registry.fill(HIST("hPtParticleAssocMcGen"), particleAssoc.pt()); + entryLcHadronPair(getDeltaPhi(particleAssoc.phi(), particle.phi()), + particleAssoc.eta() - particle.eta(), + particle.pt() * chargeLc / std::abs(chargeLc), + particleAssoc.pt() * chargeAssoc / std::abs(chargeAssoc), + poolBin, + correlationStatus); + entryLcHadronPairY(particleAssoc.y() - yL); + entryLcHadronRecoInfo(MassLambdaCPlus, true); + entryLcHadronGenInfo(isLcPrompt, particleAssoc.isPhysicalPrimary(), trackOrigin); + } // end inner loop } // end outer loop registry.fill(HIST("hCountLcHadronPerEvent"), counterLcHadron); registry.fill(HIST("hZvtx"), mcCollision.posZ()); - registry.fill(HIST("hMultiplicity"), getTracksSize(mcCollision)); } PROCESS_SWITCH(HfCorrelatorLcHadrons, processMcGen, "Process Mc Gen mode", false); - void processDataMixedEvent(SelectedCollisions const& collisions, - SelectedCandidatesData const& candidates, - SelectedTracks const& tracks) + void processDataMixedEvent(SelCollisionsWithLc const& collisions, + CandidatesLcData const& candidates, + TracksData const& tracks) { - if (candidates.size() == 0) { - return; - } auto tracksTuple = std::make_tuple(candidates, tracks); - Pair pairData{corrBinning, 5, -1, collisions, tracksTuple, &cache}; + Pair pairData{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; for (const auto& [c1, tracks1, c2, tracks2] : pairData) { - int poolBin = corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multFV0M())); - for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - if (!TESTBIT(t1.hfflag(), aod::hf_cand_3prong::DecayType::LcToPKPi)) { + int poolBin = corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multFT0M())); + for (const auto& [trigLc, assocParticle] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (!assocParticle.isGlobalTrackWoDCA() || std::abs(hfHelper.yLc(trigLc)) > yCandMax) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yLc(t1)) > yCandMax) { - continue; + + if (pidTrkApplied) { + if (!passPIDSelection(assocParticle, trkPIDspecies, pidTPCMax, pidTOFMax, tofPIDThreshold, forceTOF)) + continue; } + + auto trackPos1 = trigLc.template prong0_as(); // positive daughter (negative for the antiparticles) + int8_t chargeLc = trackPos1.sign(); // charge of 1st prong will be the charge of Lc candidate + + std::vector outputMl = {-1., -1., -1.}; // LcToPKPi and LcToPiKP division - if (t1.isSelLcToPKPi() >= selectionFlagLc) { - entryLcHadronPair(getDeltaPhi(t1.phi(), t2.phi()), - t1.eta() - t2.eta(), - t1.pt(), - t2.pt(), - poolBin); - entryLcHadronRecoInfo(hfHelper.invMassLcToPKPi(t1), false); - } - if (t1.isSelLcToPiKP() >= selectionFlagLc) { - entryLcHadronPair(getDeltaPhi(t1.phi(), t2.phi()), - t1.eta() - t2.eta(), - t1.pt(), - t2.pt(), - poolBin); - entryLcHadronRecoInfo(hfHelper.invMassLcToPiKP(t1), false); + if (trigLc.isSelLcToPKPi() >= selectionFlagLc) { + entryLcHadronPair(getDeltaPhi(assocParticle.phi(), trigLc.phi()), + assocParticle.eta() - trigLc.eta(), + trigLc.pt() * chargeLc, + assocParticle.pt() * assocParticle.sign(), + poolBin, + correlationStatus); + entryLcHadronPairY(assocParticle.y() - hfHelper.yLc(trigLc)); + entryLcHadronRecoInfo(hfHelper.invMassLcToPKPi(trigLc), false); + entryLcHadronGenInfo(false, false, 0); + if (fillTrkPID) { + entryLcHadronPairTrkPID(assocParticle.tpcNSigmaPr(), assocParticle.tpcNSigmaKa(), assocParticle.tpcNSigmaPi(), assocParticle.tofNSigmaPr(), assocParticle.tofNSigmaKa(), assocParticle.tofNSigmaPi()); + } + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = trigLc.mlProbLcToPKPi()[classMl->at(iclass)]; + } + entryLcHadronMlInfo(outputMl[0], outputMl[1]); + entryTrackRecoInfo(assocParticle.dcaXY(), assocParticle.dcaZ(), assocParticle.tpcNClsCrossedRows()); + } + if (trigLc.isSelLcToPiKP() >= selectionFlagLc) { + entryLcHadronPair(getDeltaPhi(assocParticle.phi(), trigLc.phi()), + assocParticle.eta() - trigLc.eta(), + trigLc.pt() * chargeLc, + assocParticle.pt() * assocParticle.sign(), + poolBin, + correlationStatus); + entryLcHadronPairY(assocParticle.y() - hfHelper.yLc(trigLc)); + entryLcHadronRecoInfo(hfHelper.invMassLcToPiKP(trigLc), false); + entryLcHadronGenInfo(false, false, 0); + if (fillTrkPID) { + entryLcHadronPairTrkPID(assocParticle.tpcNSigmaPr(), assocParticle.tpcNSigmaKa(), assocParticle.tpcNSigmaPi(), assocParticle.tofNSigmaPr(), assocParticle.tofNSigmaKa(), assocParticle.tofNSigmaPi()); + } + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = trigLc.mlProbLcToPiKP()[classMl->at(iclass)]; + } + entryLcHadronMlInfo(outputMl[0], outputMl[1]); + entryTrackRecoInfo(assocParticle.dcaXY(), assocParticle.dcaZ(), assocParticle.tpcNClsCrossedRows()); } } } } PROCESS_SWITCH(HfCorrelatorLcHadrons, processDataMixedEvent, "Process Mixed Event Data", false); - void processMcRecMixedEvent(SelectedCollisions const& collisions, - SelectedCandidatesMcRec const& candidates, - SelectedTracks const& tracks) + void processMcRecMixedEvent(SelCollisionsWithLc const& collisions, + CandidatesLcMcRec const& candidates, + TracksWithMc const& tracks, + aod::McParticles const& mcParticles) { + BinningType corrBinning{{binsZVtx, binsMultiplicityMc}, true}; + for (const auto& candidate : candidates) { + if (std::abs(hfHelper.yLc(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { + continue; + } + // Lc flag + bool isLcSignal = TESTBIT(std::abs(candidate.flagMcMatchRec()), aod::hf_cand_3prong::DecayType::LcToPKPi); + // prompt and non-prompt division + bool isLcPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; + bool isLcNonPrompt = candidate.originMcRec() == RecoDecay::OriginType::NonPrompt; + if (isLcSignal) { + if (candidate.isSelLcToPKPi() >= selectionFlagLc) { + if (isLcPrompt) { + registry.fill(HIST("hPtCandMcRecSigPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityMcRecPrompt"), candidate.pt(), 0); + } else if (isLcNonPrompt) { + registry.fill(HIST("hPtCandMcRecSigNonPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityMcRecNonPrompt"), candidate.pt(), 0); + } + } + if (candidate.isSelLcToPiKP() >= selectionFlagLc) { + if (isLcPrompt) { + registry.fill(HIST("hPtCandMcRecSigPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityMcRecPrompt"), candidate.pt(), 0); + } else if (isLcNonPrompt) { + registry.fill(HIST("hPtCandMcRecSigNonPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityMcRecNonPrompt"), candidate.pt(), 0); + } + } + } else { + registry.fill(HIST("hPtCandMcRecBkg"), candidate.pt()); + registry.fill(HIST("hEtaMcRecBkg"), candidate.eta()); + registry.fill(HIST("hPhiMcRecBkg"), RecoDecay::constrainAngle(candidate.phi(), -PIHalf)); + } + } auto tracksTuple = std::make_tuple(candidates, tracks); - Pair pairMcRec{corrBinning, 5, -1, collisions, tracksTuple, &cache}; + Pair pairMcRec{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; for (const auto& [c1, tracks1, c2, tracks2] : pairMcRec) { - int poolBin = corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multFV0M())); - for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - if (yCandMax >= 0. && std::abs(hfHelper.yLc(t1)) > yCandMax) { + int poolBin = corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multFT0M())); + int poolBinLc = corrBinning.getBin(std::make_tuple(c1.posZ(), c1.multFT0M())); + registry.fill(HIST("hMultFT0M"), c1.multFT0M()); + registry.fill(HIST("hZvtx"), c1.posZ()); + registry.fill(HIST("hTracksPoolBin"), poolBin); + registry.fill(HIST("hLcPoolBin"), poolBinLc); + for (const auto& [candidate, pAssoc] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (std::abs(hfHelper.yLc(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { + continue; + } + if (!pAssoc.isGlobalTrackWoDCA()) { continue; } - if (t1.isSelLcToPKPi() >= selectionFlagLc) { - entryLcHadronPair(getDeltaPhi(t1.phi(), t2.phi()), - t1.eta() - t2.eta(), - t1.pt(), - t2.pt(), - poolBin); - entryLcHadronRecoInfo(hfHelper.invMassLcToPKPi(t1), false); - } - if (t1.isSelLcToPiKP() >= selectionFlagLc) { - entryLcHadronPair(getDeltaPhi(t1.phi(), t2.phi()), - t1.eta() - t2.eta(), - t1.pt(), - t2.pt(), - poolBin); - entryLcHadronRecoInfo(hfHelper.invMassLcToPiKP(t1), false); + std::vector outputMl = {-1., -1., -1.}; + bool isPhysicalPrimary = false; + int trackOrigin = -1; + bool isLcSignal = std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::LcToPKPi; + bool isLcPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; + if (pidTrkApplied) { + if (!passPIDSelection(pAssoc, trkPIDspecies, pidTPCMax, pidTOFMax, tofPIDThreshold, forceTOF)) + continue; + } + auto trackPos1 = candidate.template prong0_as(); // positive daughter (negative for the antiparticles) + int8_t chargeLc = trackPos1.sign(); // charge of 1st prong will be the charge of Lc candidate + + if (pAssoc.has_mcParticle()) { + auto mcParticle = pAssoc.template mcParticle_as(); + isPhysicalPrimary = mcParticle.isPhysicalPrimary(); + trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); + } else { + registry.fill(HIST("hFakeTracksMcRec"), pAssoc.pt()); + } + if (candidate.isSelLcToPKPi() >= selectionFlagLc) { + entryLcHadronPair(getDeltaPhi(pAssoc.phi(), candidate.phi()), + pAssoc.eta() - candidate.eta(), + candidate.pt() * chargeLc, + pAssoc.pt() * pAssoc.sign(), + poolBin, + correlationStatus); + entryLcHadronPairY(pAssoc.y() - hfHelper.yLc(candidate)); + entryLcHadronRecoInfo(hfHelper.invMassLcToPKPi(candidate), isLcSignal); + entryLcHadronGenInfo(isLcPrompt, isPhysicalPrimary, trackOrigin); + if (fillTrkPID) { + entryLcHadronPairTrkPID(pAssoc.tpcNSigmaPr(), pAssoc.tpcNSigmaKa(), pAssoc.tpcNSigmaPi(), pAssoc.tofNSigmaPr(), pAssoc.tofNSigmaKa(), pAssoc.tofNSigmaPi()); + } + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbLcToPKPi()[classMl->at(iclass)]; + } + entryLcHadronMlInfo(outputMl[0], outputMl[1]); + entryTrackRecoInfo(pAssoc.dcaXY(), pAssoc.dcaZ(), pAssoc.tpcNClsCrossedRows()); + } + if (candidate.isSelLcToPiKP() >= selectionFlagLc) { + entryLcHadronPair(getDeltaPhi(pAssoc.phi(), candidate.phi()), + pAssoc.eta() - candidate.eta(), + candidate.pt() * chargeLc, + pAssoc.pt() * pAssoc.sign(), + poolBin, + correlationStatus); + entryLcHadronPairY(pAssoc.y() - hfHelper.yLc(candidate)); + entryLcHadronRecoInfo(hfHelper.invMassLcToPiKP(candidate), isLcSignal); + entryLcHadronGenInfo(isLcPrompt, isPhysicalPrimary, trackOrigin); + if (fillTrkPID) { + entryLcHadronPairTrkPID(pAssoc.tpcNSigmaPr(), pAssoc.tpcNSigmaKa(), pAssoc.tpcNSigmaPi(), pAssoc.tofNSigmaPr(), pAssoc.tofNSigmaKa(), pAssoc.tofNSigmaPi()); + } + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbLcToPiKP()[classMl->at(iclass)]; + } + entryLcHadronMlInfo(outputMl[0], outputMl[1]); + entryTrackRecoInfo(pAssoc.dcaXY(), pAssoc.dcaZ(), pAssoc.tpcNClsCrossedRows()); } } } } PROCESS_SWITCH(HfCorrelatorLcHadrons, processMcRecMixedEvent, "Process Mixed Event McRec", false); - void processMcGenMixedEvent(SelectedCollisionsMcGen const& collisions, - SelectedTracksMcGen const& mcParticles) + void processMcGenMixedEvent(SelCollisionsWithLcMc const& collisions, + CandidatesLcMcGen const& mcParticles) { - auto getTracksSize = [&mcParticles, this](SelectedCollisionsMcGen::iterator const& collision) { - int nTracks = 0; - auto associatedTracks = mcParticles.sliceByCached(o2::aod::mcparticle::mcCollisionId, collision.globalIndex(), this->cache); - for (const auto& track : associatedTracks) { - if (track.isPhysicalPrimary() && std::abs(track.eta()) < 1.0) { - nTracks++; - } - } - return nTracks; - }; - - using BinningTypeMcGen = FlexibleBinningPolicy, aod::mccollision::PosZ, decltype(getTracksSize)>; - BinningTypeMcGen corrBinningMcGen{{getTracksSize}, {binsZVtx, binsMultiplicityMc}, true}; - + BinningTypeMcGen corrBinningMcGen{{binsZVtx, binsMultiplicityMc}, true}; auto tracksTuple = std::make_tuple(mcParticles, mcParticles); - Pair pairMcGen{corrBinningMcGen, 5, -1, collisions, tracksTuple, &cache}; - + Pair pairMcGen{corrBinningMcGen, numberEventsMixed, -1, collisions, tracksTuple, &cache}; for (const auto& [c1, tracks1, c2, tracks2] : pairMcGen) { - for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - // Check track t1 is Lc - if (std::abs(t1.pdgCode()) != Pdg::kLambdaCPlus) { + int poolBin = corrBinningMcGen.getBin(std::make_tuple(c1.posZ(), c1.multMCFT0A())); + for (const auto& [candidate, particleAssoc] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (std::abs(candidate.pdgCode()) != Pdg::kLambdaCPlus) { continue; } - - double yL = RecoDecay::y(t1.pVector(), MassLambdaCPlus); - if (yCandMax >= 0. && std::abs(yL) > yCandMax) { + double yL = RecoDecay::y(candidate.pVector(), MassLambdaCPlus); + if (std::abs(yL) > yCandGenMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { continue; } - if (ptCandMin >= 0. && t1.pt() < ptCandMin) { + if (std::abs(particleAssoc.eta()) > etaTrackMax || particleAssoc.pt() < ptTrackMin || particleAssoc.pt() > ptTrackMax) { continue; } - - if (std::abs(t2.eta()) > etaTrackMax) { + if ((std::abs(particleAssoc.pdgCode()) != kElectron) && (std::abs(particleAssoc.pdgCode()) != kMuonMinus) && (std::abs(particleAssoc.pdgCode()) != kPiPlus) && (std::abs(particleAssoc.pdgCode()) != kKPlus) && (std::abs(particleAssoc.pdgCode()) != kProton)) { continue; } - if (t2.pt() < ptTrackMin) { + if (!particleAssoc.isPhysicalPrimary()) { continue; } - int poolBin = corrBinningMcGen.getBin(std::make_tuple(c2.posZ(), getTracksSize(c2))); - entryLcHadronPair(getDeltaPhi(t1.phi(), t2.phi()), - t1.eta() - t2.eta(), - t1.pt(), - t2.pt(), - poolBin); + if (pidTrkApplied && (std::abs(particleAssoc.pdgCode()) != kProton)) { + continue; // proton PID + } + int8_t chargeLc = pdg->GetParticle(candidate.pdgCode())->Charge(); // Retrieve charge + int8_t chargeAssoc = pdg->GetParticle(particleAssoc.pdgCode())->Charge(); // Retrieve charge + + int trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, particleAssoc, true); + bool isLcPrompt = candidate.originMcGen() == RecoDecay::OriginType::Prompt; + entryLcHadronPair(getDeltaPhi(particleAssoc.phi(), candidate.phi()), + particleAssoc.eta() - candidate.eta(), + candidate.pt() * chargeLc / std::abs(chargeLc), + particleAssoc.pt() * chargeAssoc / std::abs(chargeAssoc), + poolBin, + correlationStatus); + entryLcHadronPairY(particleAssoc.y() - yL); + entryLcHadronRecoInfo(MassLambdaCPlus, true); + entryLcHadronGenInfo(isLcPrompt, particleAssoc.isPhysicalPrimary(), trackOrigin); } } } diff --git a/PWGHF/HFC/TableProducer/femtoDreamProducer.cxx b/PWGHF/HFC/TableProducer/femtoDreamProducer.cxx new file mode 100644 index 00000000000..026d7d80992 --- /dev/null +++ b/PWGHF/HFC/TableProducer/femtoDreamProducer.cxx @@ -0,0 +1,578 @@ +// Copyright 2019-2022 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 femtoDreamProducer.cxx +/// \brief Tasks that produces the track tables used for the pairing +/// \author Ravindra Singh, GSI, ravindra.singh@cern.ch +/// \author Biao Zhang, Heidelberg University, biao.zhang@cern.ch + +#include +#include +#include "CCDB/BasicCCDBManager.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" + +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/Propagator.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamTrackSelection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Core/CentralityEstimation.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femtoDream; +using namespace o2::hf_evsel; +using namespace o2::hf_centrality; + +// event types +enum Event : uint8_t { + kAll = 0, + kRejEveSel, + kRejNoTracksAndCharm, + kTrackSelected, + kCharmSelected, + kPairSelected +}; + +struct HfFemtoDreamProducer { + + Produces outputCollision; + Produces rowMasks; + Produces rowCandCharmHad; + Produces rowCandMcCharmHad; + Produces rowCandCharmHadGen; + Produces outputPartsIndex; + Produces outputMcCollision; + Produces outputCollsMcLabels; + Produces outputParts; + Produces outputPartsMc; + Produces outputDebugParts; + Produces outputPartsMcLabels; + Produces outputDebugPartsMc; + Produces outputPartsExtMcLabels; + + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; + Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + + // Configurable isForceGRP{"isForceGRP", false, "Set true if the magnetic field configuration is not available in the usual CCDB directory (e.g. for Run 2 converted data or unanchorad Monte Carlo)"}; + + Configurable isDebug{"isDebug", true, "Enable Debug tables"}; + Configurable isRun3{"isRun3", true, "Running on Run3 or pilot"}; + + /// Lc table + Configurable selectionFlagLc{"selectionFlagLc", 1, "Selection Flag for Lc"}; + Configurable useCent{"useCent", false, "Enable centrality for lc"}; + + Configurable trkPDGCode{"trkPDGCode", 2212, "PDG code of the selected track for Monte Carlo truth"}; + Configurable> trkCharge{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kSign, "trk"), std::vector{-1, 1}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kSign, "Track selection: ")}; + Configurable> trkDCAxyMax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kDCAxyMax, "trk"), std::vector{0.1f, 3.5f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kDCAxyMax, "Track selection: ")}; + Configurable> trkDCAzMax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kDCAzMax, "trk"), std::vector{0.2f, 3.5f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kDCAzMax, "Track selection: ")}; + Configurable> trkEta{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kEtaMax, "trk"), std::vector{0.8f, 0.7f, 0.9f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kEtaMax, "Track selection: ")}; + Configurable> trkPIDspecies{"trkPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Kaon, o2::track::PID::Proton}, "Trk sel: Particles species for PID"}; + Configurable> trkPIDnSigmaMax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kPIDnSigmaMax, "trk"), std::vector{3.5f, 3.f, 2.5f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kPIDnSigmaMax, "Track selection: ")}; + Configurable trkPIDnSigmaOffsetTPC{"trkPIDnSigmaOffsetTPC", 0., "Offset for TPC nSigma because of bad calibration"}; + Configurable trkPIDnSigmaOffsetTOF{"trkPIDnSigmaOffsetTOF", 0., "Offset for TOF nSigma because of bad calibration"}; + Configurable> trkPtmax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kpTMax, "trk"), std::vector{5.4f, 5.6f, 5.5f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kpTMax, "Track selection: ")}; + Configurable> trkPtmin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kpTMin, "trk"), std::vector{0.5f, 0.4f, 0.6f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kpTMin, "Track selection: ")}; + Configurable> trkTPCcRowsMin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kTPCcRowsMin, "trk"), std::vector{70.f, 60.f, 80.f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kTPCcRowsMin, "Track selection: ")}; + Configurable> trkTPCfCls{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kTPCfClsMin, "trk"), std::vector{0.7f, 0.83f, 0.9f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kTPCfClsMin, "Track selection: ")}; + Configurable> trkTPCnclsMin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kTPCnClsMin, "trk"), std::vector{80.f, 70.f, 60.f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kTPCnClsMin, "Track selection: ")}; + Configurable> trkTPCsCls{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kTPCsClsMax, "trk"), std::vector{0.1f, 160.f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kTPCsClsMax, "Track selection: ")}; + Configurable> trkITSnclsIbMin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kITSnClsIbMin, "trk"), std::vector{-1.f, 1.f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kITSnClsIbMin, "Track selection: ")}; + Configurable> trkITSnclsMin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kITSnClsMin, "trk"), std::vector{-1.f, 2.f, 4.f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kITSnClsMin, "Track selection: ")}; + + using CandidateLc = soa::Join; + using CandidateLcMc = soa::Join; + + using FemtoFullCollision = soa::Join::iterator; + using FemtoFullCollisionMc = soa::Join::iterator; + using FemtoFullMcgenCollisions = soa::Join; + using FemtoFullMcgenCollision = FemtoFullMcgenCollisions::iterator; + using FemtoHFTracks = soa::Join; + using FemtoHFTrack = FemtoHFTracks::iterator; + using FemtoHFMcTracks = soa::Join; + using FemtoHFMcTrack = FemtoHFMcTracks::iterator; + + using GeneratedMc = soa::Filtered>; + + FemtoDreamTrackSelection trackCuts; + + Filter filterSelectCandidateLc = (aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLc || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLc); + + HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry TrackRegistry{"Tracks", {}, OutputObjHandlingPolicy::AnalysisObject}; + + HfHelper hfHelper; + o2::hf_evsel::HfEventSelection hfEvSel; + + float magField; + int runNumber; + + Service ccdb; /// Accessing the CCDB + o2::base::MatLayerCylSet* lut; + // if (doPvRefit){ lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut));} //! may be it useful, will check later + + void init(InitContext&) + { + std::array processes = {doprocessDataCharmHad, doprocessMcCharmHad, doprocessDataCharmHadWithML, doprocessMcCharmHadWithML, doprocessMcCharmHadGen}; + if (std::accumulate(processes.begin(), processes.end(), 0) != 1) { + LOGP(fatal, "One and only one process function must be enabled at a time."); + } + + int CutBits = 8 * sizeof(o2::aod::femtodreamparticle::cutContainerType); + TrackRegistry.add("AnalysisQA/CutCounter", "; Bit; Counter", kTH1F, {{CutBits + 1, -0.5, CutBits + 0.5}}); + + // event QA histograms + constexpr int kEventTypes = kPairSelected + 1; + std::string labels[kEventTypes]; + labels[Event::kAll] = "All events"; + labels[Event::kRejEveSel] = "rejected by event selection"; + labels[Event::kRejNoTracksAndCharm] = "rejected by no tracks and charm"; + labels[Event::kTrackSelected] = "with tracks "; + labels[Event::kCharmSelected] = "with charm hadrons "; + labels[Event::kPairSelected] = "with pairs"; + + static const AxisSpec axisEvents = {kEventTypes, 0.5, kEventTypes + 0.5, ""}; + qaRegistry.add("hEventQA", "Events;;entries", HistType::kTH1F, {axisEvents}); + for (int iBin = 0; iBin < kEventTypes; iBin++) { + qaRegistry.get(HIST("hEventQA"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); + } + + trackCuts.setSelection(trkCharge, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + trackCuts.setSelection(trkPtmin, femtoDreamTrackSelection::kpTMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(trkPtmax, femtoDreamTrackSelection::kpTMax, femtoDreamSelection::kUpperLimit); + trackCuts.setSelection(trkEta, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + trackCuts.setSelection(trkTPCnclsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(trkTPCfCls, femtoDreamTrackSelection::kTPCfClsMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(trkTPCcRowsMin, femtoDreamTrackSelection::kTPCcRowsMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(trkTPCsCls, femtoDreamTrackSelection::kTPCsClsMax, femtoDreamSelection::kUpperLimit); + trackCuts.setSelection(trkITSnclsMin, femtoDreamTrackSelection::kITSnClsMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(trkITSnclsIbMin, femtoDreamTrackSelection::kITSnClsIbMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(trkDCAxyMax, femtoDreamTrackSelection::kDCAxyMax, femtoDreamSelection::kAbsUpperLimit); + trackCuts.setSelection(trkDCAzMax, femtoDreamTrackSelection::kDCAzMax, femtoDreamSelection::kAbsUpperLimit); + trackCuts.setSelection(trkPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + trackCuts.setPIDSpecies(trkPIDspecies); + trackCuts.setnSigmaPIDOffset(trkPIDnSigmaOffsetTPC, trkPIDnSigmaOffsetTOF); + trackCuts.init(&qaRegistry, &TrackRegistry); + + runNumber = 0; + magField = 0.0; + /// Initializing CCDB + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + hfEvSel.addHistograms(qaRegistry); // collision monitoring + + int64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); + } + + /// Function to retrieve the nominal magnetic field in kG (0.1T) and convert it directly to T + void getMagneticFieldTesla(aod::BCsWithTimestamps::iterator bc) + { + initCCDB(bc, runNumber, ccdb, !isRun3 ? ccdbPathGrp : ccdbPathGrpMag, lut, !isRun3); + } + + template + void fillDebugParticle(ParticleType const& particle) + { + outputDebugParts(particle.sign(), + (uint8_t)particle.tpcNClsFound(), + particle.tpcNClsFindable(), + (uint8_t)particle.tpcNClsCrossedRows(), + particle.tpcNClsShared(), + particle.tpcInnerParam(), + particle.itsNCls(), + particle.itsNClsInnerBarrel(), + particle.dcaXY(), + particle.dcaZ(), + particle.tpcSignal(), + -999., + particle.tpcNSigmaPi(), + particle.tpcNSigmaKa(), + particle.tpcNSigmaPr(), + particle.tpcNSigmaDe(), + -999., + -999., + -999., + particle.tofNSigmaPi(), + particle.tofNSigmaKa(), + particle.tofNSigmaPr(), + particle.tofNSigmaDe(), + -999., -999., -999., -999., + -999., -999., -999., -999., + -999., -999., -999., -999., + -999., -999., -999., -999., + -999., -999., -999., -999., + -999., -999., -999.); + } + + template + void fillMcParticle(CollisionType const& col, ParticleType const& particle, o2::aod::femtodreamparticle::ParticleType fdparttype) + { + if (particle.has_mcParticle()) { + // get corresponding MC particle and its info + auto particleMc = particle.mcParticle(); + auto pdgCode = particleMc.pdgCode(); + int particleOrigin = 99; + int pdgCodeMother = -1; + // get list of mothers, but it could be empty (for example in case of injected light nuclei) + auto motherparticlesMc = particleMc.template mothers_as(); + // check pdg code + // if this fails, the particle is a fake + if (std::abs(pdgCode) == std::abs(trkPDGCode.value)) { + // check first if particle is from pile up + // check if the collision associated with the particle is the same as the analyzed collision by checking their Ids + if ((col.has_mcCollision() && (particleMc.mcCollisionId() != col.mcCollisionId())) || !col.has_mcCollision()) { + particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kWrongCollision; + // check if particle is primary + } else if (particleMc.isPhysicalPrimary()) { + particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kPrimary; + // check if particle is secondary + // particle is from a decay -> getProcess() == 4 + // particle is generated during transport -> getGenStatusCode() == -1 + // list of mothers is not empty + } else if (particleMc.getProcess() == 4 && particleMc.getGenStatusCode() == -1 && !motherparticlesMc.empty()) { + // get direct mother + auto motherparticleMc = motherparticlesMc.front(); + pdgCodeMother = motherparticleMc.pdgCode(); + particleOrigin = checkDaughterType(fdparttype, motherparticleMc.pdgCode()); + // check if particle is material + // particle is from inelastic hadronic interaction -> getProcess() == 23 + // particle is generated during transport -> getGenStatusCode() == -1 + } else if (particleMc.getProcess() == 23 && particleMc.getGenStatusCode() == -1) { + particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kMaterial; + // cross check to see if we missed a case + } else { + particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kElse; + } + // if pdg code is wrong, particle is fake + } else { + particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kFake; + } + + outputPartsMc(particleOrigin, pdgCode, particleMc.pt(), particleMc.eta(), particleMc.phi()); + outputPartsMcLabels(outputPartsMc.lastIndex()); + if (isDebug) { + outputPartsExtMcLabels(outputPartsMc.lastIndex()); + outputDebugPartsMc(pdgCodeMother); + } + } else { + outputPartsMcLabels(-1); + if (isDebug) { + outputPartsExtMcLabels(-1); + } + } + } + + template + void fillMcCollision(CollisionType const& col) + { + if (col.has_mcCollision()) { + // auto genMCcol = col.template mcCollision_as(); + // outputMcCollision(genMCcol.multMCNParticlesEta08()); + outputCollsMcLabels(outputMcCollision.lastIndex()); + } else { + outputCollsMcLabels(-1); + } + } + + template + bool fillTracksForCharmHadron(CollisionType const& col, TrackType const& tracks) + { + + std::vector childIDs = {0, 0}; // these IDs are necessary to keep track of the children + // std::vector tmpIDtrack; // this vector keeps track of the matching of the primary track table row <-> aod::track table global index + bool fIsTrackFilled = false; + + for (auto& track : tracks) { + /// if the most open selection criteria are not fulfilled there is no + /// point looking further at the track + if (!trackCuts.isSelectedMinimal(track)) { + continue; + } + + trackCuts.fillQA(track); + // the bit-wise container of the systematic variations is obtained + auto cutContainer = trackCuts.getCutContainer(track, track.pt(), track.eta(), sqrtf(powf(track.dcaXY(), 2.f) + powf(track.dcaZ(), 2.f))); + + // track global index + outputPartsIndex(track.globalIndex()); + // now the table is filled + + outputParts(outputCollision.lastIndex(), + track.pt(), + track.eta(), + track.phi(), + aod::femtodreamparticle::ParticleType::kTrack, + cutContainer.at(femtoDreamTrackSelection::TrackContainerPosition::kCuts), + cutContainer.at(femtoDreamTrackSelection::TrackContainerPosition::kPID), + track.dcaXY(), childIDs, 0, 0); + fIsTrackFilled = true; + // tmpIDtrack.push_back(track.globalIndex()); + if (isDebug.value) { + fillDebugParticle(track); + } + + if constexpr (isMc) { + fillMcParticle(col, track, o2::aod::femtodreamparticle::ParticleType::kTrack); + } + } + return fIsTrackFilled; + } + + template + void fillCharmHadronTable(CollisionType const& col, TrackType const& tracks, CandType const& candidates) + { + const auto vtxZ = col.posZ(); + const auto sizeCand = candidates.size(); + const auto spher = 2.; // dummy value for the moment + float mult = 0; + int multNtr = 0; + if (isRun3) { + if (useCent) { + mult = col.centFT0M(); + } else { + mult = 0; + } + multNtr = col.multNTracksPV(); + } else { + mult = 1; // multiplicity percentile is know in Run 2 + multNtr = col.multTracklets(); + } + + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(col, mult, ccdb, qaRegistry); + + qaRegistry.fill(HIST("hEventQA"), 1 + Event::kAll); + + /// monitor the satisfied event selections + hfEvSel.fillHistograms(col, rejectionMask, mult); + if (rejectionMask != 0) { + /// at least one event selection not satisfied --> reject the candidate + qaRegistry.fill(HIST("hEventQA"), 1 + Event::kRejEveSel); + return; + } + + if (isNoSelectedTracks(col, tracks, trackCuts) && sizeCand <= 0) { + qaRegistry.fill(HIST("hEventQA"), 1 + Event::kRejNoTracksAndCharm); + return; + } + + outputCollision(vtxZ, mult, multNtr, spher, magField); + if constexpr (isMc) { + fillMcCollision(col); + } + + // Filling candidate properties + rowCandCharmHad.reserve(sizeCand); + bool isTrackFilled = false; + for (const auto& candidate : candidates) { + std::array outputMlPKPi{-1., -1., -1.}; + std::array outputMlPiKP{-1., -1., -1.}; + if constexpr (useCharmMl) { + /// fill with ML information + /// BDT index 0: bkg score; BDT index 1: prompt score; BDT index 2: non-prompt score + if (candidate.mlProbLcToPKPi().size() > 0) { + outputMlPKPi.at(0) = candidate.mlProbLcToPKPi()[0]; /// bkg score + outputMlPKPi.at(1) = candidate.mlProbLcToPKPi()[1]; /// prompt score + outputMlPKPi.at(2) = candidate.mlProbLcToPKPi()[2]; /// non-prompt score + } + if (candidate.mlProbLcToPiKP().size() > 0) { + outputMlPiKP.at(0) = candidate.mlProbLcToPiKP()[0]; /// bkg score + outputMlPiKP.at(1) = candidate.mlProbLcToPiKP()[1]; /// prompt score + outputMlPiKP.at(2) = candidate.mlProbLcToPiKP()[2]; /// non-prompt score + } + } + auto trackPos1 = candidate.template prong0_as(); // positive daughter (negative for the antiparticles) + auto trackNeg = candidate.template prong1_as(); // negative daughter (positive for the antiparticles) + auto trackPos2 = candidate.template prong2_as(); // positive daughter (negative for the antiparticles) + + auto fillTable = [&](int CandFlag, + int FunctionSelection, + float BDTScoreBkg, + float BDTScorePrompt, + float BDTScoreFD) { + if (FunctionSelection >= 1){ + rowCandCharmHad( + outputCollision.lastIndex(), + trackPos1.sign() + trackNeg.sign() + trackPos2.sign(), + trackPos1.globalIndex(), + trackNeg.globalIndex(), + trackPos2.globalIndex(), + trackPos1.pt(), + trackNeg.pt(), + trackPos2.pt(), + trackPos1.eta(), + trackNeg.eta(), + trackPos2.eta(), + trackPos1.phi(), + trackNeg.phi(), + trackPos2.phi(), + 1 << CandFlag, + BDTScoreBkg, + BDTScorePrompt, + BDTScoreFD); + + // Row for MC candidate charm hadron (if constexpr isMc) + if constexpr (isMc) { + rowCandMcCharmHad( + candidate.flagMcMatchRec(), + candidate.originMcRec());} + } }; + + fillTable(0, candidate.isSelLcToPKPi(), outputMlPKPi.at(0), outputMlPKPi.at(1), outputMlPKPi.at(2)); + fillTable(1, candidate.isSelLcToPiKP(), outputMlPiKP.at(0), outputMlPiKP.at(1), outputMlPiKP.at(2)); + } + + if (!isTrackFilled) { + isTrackFilled = fillTracksForCharmHadron(col, tracks); + // If track filling was successful, fill the collision table + } + + aod::femtodreamcollision::BitMaskType bitTrack = 0; + if (isTrackFilled) { + bitTrack |= 1 << 0; + qaRegistry.fill(HIST("hEventQA"), 1 + Event::kTrackSelected); + } + + aod::femtodreamcollision::BitMaskType bitCand = 0; + if (sizeCand > 0) { + bitCand |= 1 << 0; + qaRegistry.fill(HIST("hEventQA"), 1 + Event::kCharmSelected); + } + + if (isTrackFilled && (sizeCand > 0)) + qaRegistry.fill(HIST("hEventQA"), 1 + Event::kPairSelected); + + rowMasks(static_cast(bitTrack), + static_cast(bitCand), + 0); + } + + // check if there is no selected track + /// \param C type of the collision + /// \param T type of the tracks + /// \param TC type of the femto track cuts + /// \return whether or not the tracks fulfills the all selections + template + bool isNoSelectedTracks(C const& /*col*/, T const& tracks, TC& trackCuts) + { + for (auto const& track : tracks) { + if (trackCuts.isSelectedMinimal(track)) { + return false; + } + } + return true; + } + + template + void fillCharmHadMcGen(ParticleType particles) + { + // Filling particle properties + rowCandCharmHadGen.reserve(particles.size()); + for (const auto& particle : particles) { + if (std::abs(particle.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::LcToPKPi) { + rowCandCharmHadGen( + particle.mcCollisionId(), + particle.flagMcMatchGen(), + particle.originMcGen()); + } + } + } + + void processDataCharmHad(FemtoFullCollision const& col, + aod::BCsWithTimestamps const&, + FemtoHFTracks const& tracks, + soa::Filtered const& candidates) + { + // get magnetic field for run + getMagneticFieldTesla(col.bc_as()); + + fillCharmHadronTable(col, tracks, candidates); + } + PROCESS_SWITCH(HfFemtoDreamProducer, processDataCharmHad, + "Provide experimental data for charm hadron femto", false); + + void processDataCharmHadWithML(FemtoFullCollision const& col, + aod::BCsWithTimestamps const&, + FemtoHFTracks const& tracks, + soa::Filtered> const& candidates) + { + + // get magnetic field for run + getMagneticFieldTesla(col.bc_as()); + + fillCharmHadronTable(col, tracks, candidates); + } + PROCESS_SWITCH(HfFemtoDreamProducer, processDataCharmHadWithML, + "Provide experimental data for charm hadron femto with ml", false); + + void processMcCharmHad(FemtoFullCollisionMc const& col, + aod::BCsWithTimestamps const&, + FemtoHFMcTracks const& tracks, + aod::McParticles const&, + CandidateLcMc const& candidates) + { + // get magnetic field for run + getMagneticFieldTesla(col.bc_as()); + + fillCharmHadronTable(col, tracks, candidates); + } + PROCESS_SWITCH(HfFemtoDreamProducer, processMcCharmHad, "Provide Mc for charm hadron", false); + + void processMcCharmHadWithML(FemtoFullCollisionMc const& col, + aod::BCsWithTimestamps const&, + FemtoHFMcTracks const& tracks, + aod::McParticles const&, + soa::Join const& candidates) + { + // get magnetic field for run + getMagneticFieldTesla(col.bc_as()); + + fillCharmHadronTable(col, tracks, candidates); + } + PROCESS_SWITCH(HfFemtoDreamProducer, processMcCharmHadWithML, "Provide Mc for charm hadron with ml", false); + + void processMcCharmHadGen(GeneratedMc const& particles) + { + + fillCharmHadMcGen(particles); + } + PROCESS_SWITCH(HfFemtoDreamProducer, processMcCharmHadGen, "Provide Mc Generated charm hadron", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/HFC/Tasks/CMakeLists.txt b/PWGHF/HFC/Tasks/CMakeLists.txt index 25acdbe1f86..ec2e1779ebf 100644 --- a/PWGHF/HFC/Tasks/CMakeLists.txt +++ b/PWGHF/HFC/Tasks/CMakeLists.txt @@ -9,6 +9,11 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +o2physics_add_dpl_workflow(task-charm-hadrons-femto-dream + SOURCES taskCharmHadronsFemtoDream.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(task-correlation-d0-hadrons SOURCES taskCorrelationD0Hadrons.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -39,6 +44,11 @@ o2physics_add_dpl_workflow(task-correlation-dstar-hadrons PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(task-correlation-hfe-hadrons + SOURCES taskCorrelationHfeHadrons.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(task-correlation-lc-hadrons SOURCES taskCorrelationLcHadrons.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore diff --git a/PWGHF/HFC/Tasks/taskCharmHadronsFemtoDream.cxx b/PWGHF/HFC/Tasks/taskCharmHadronsFemtoDream.cxx new file mode 100644 index 00000000000..5030a9f50a0 --- /dev/null +++ b/PWGHF/HFC/Tasks/taskCharmHadronsFemtoDream.cxx @@ -0,0 +1,545 @@ +// Copyright 2019-2022 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 taskCharmHadronsFemtoDream.cxx.cxx +/// \brief Tasks that reads the track tables used for the pairing and builds pairs of two tracks +/// \author Ravindra SIngh, GSI, ravindra.singh@cern.ch +/// \author Biao Zhang, Heidelberg University, biao.zhang@cern.ch + +#include +#include + +#include "Framework/Expressions.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" + +#include "PWGCF/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamEventHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h" +#include "PWGCF/FemtoDream/Core/femtoDreamContainer.h" +#include "PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h" +#include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femtoDream; + +struct HfTaskCharmHadronsFemtoDream { + + enum TrackCharge { + PositiveCharge = 1, + NegativeCharge = -1 + }; + + enum PairSign { + PairNotDefined = 0, + LikeSignPair = 1, + UnLikeSignPair = 2 + }; + + /// Binning configurables + ConfigurableAxis bin4Dkstar{"bin4Dkstar", {1500, 0., 6.}, "binning kstar for the 4Dimensional plot: k* vs multiplicity vs multiplicity percentile vs mT (set <> to true in order to use)"}; + ConfigurableAxis bin4DMult{"bin4Dmult", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f}, "multiplicity Binning for the 4Dimensional plot: k* vs multiplicity vs multiplicity percentile vs mT (set <> to true in order to use)"}; + ConfigurableAxis bin4DmT{"bin4DmT", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 4Dimensional plot: k* vs multiplicity vs multiplicity percentile vs mT (set <> to true in order to use)"}; + ConfigurableAxis bin4DmultPercentile{"bin4DmultPercentile", {10, 0.0f, 100.0f}, "multiplicity percentile Binning for the 4Dimensional plot: k* vs multiplicity vs multiplicity percentile vs mT (set <> to true in order to use)"}; + ConfigurableAxis binInvMass{"binInvMass", {400, 2.10, 2.50}, "InvMass binning"}; + ConfigurableAxis binpTCharm{"binpTCharm", {360, 0, 36}, "pT binning of charm hadron"}; + ConfigurableAxis binTempFitVarTrack{"binTempFitVarTrack", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot (Track)"}; + ConfigurableAxis binmT{"binmT", {225, 0., 7.5}, "binning mT"}; + ConfigurableAxis binmultTempFit{"binmultTempFit", {1, 0, 1}, "multiplicity Binning for the TempFitVar plot"}; + ConfigurableAxis binMulPercentile{"binMulPercentile", {10, 0.0f, 100.0f}, "multiplicity percentile Binning"}; + ConfigurableAxis binpTTrack{"binpTTrack", {50, 0.5, 10.05}, "pT binning of the pT vs. TempFitVar plot (Track)"}; + ConfigurableAxis binEta{"binEta", {{200, -1.5, 1.5}}, "eta binning"}; + ConfigurableAxis binPhi{"binPhi", {{200, 0, TMath::TwoPi()}}, "phi binning"}; + ConfigurableAxis binkT{"binkT", {150, 0., 9.}, "binning kT"}; + ConfigurableAxis binkstar{"binkstar", {1500, 0., 6.}, "binning kstar"}; + ConfigurableAxis binNSigmaTPC{"binNSigmaTPC", {1600, -8, 8}, "Binning of Nsigma TPC plot"}; + ConfigurableAxis binNSigmaTOF{"binNSigmaTOF", {3000, -15, 15}, "Binning of the Nsigma TOF plot"}; + ConfigurableAxis binNSigmaTPCTOF{"binNSigmaTPCTOF", {3000, -15, 15}, "Binning of the Nsigma TPC+TOF plot"}; + ConfigurableAxis binTPCClusters{"binTPCClusters", {163, -0.5, 162.5}, "Binning of TPC found clusters plot"}; + Configurable ConfTempFitVarMomentum{"ConfTempFitVarMomentum", 0, "Momentum used for binning: 0 -> pt; 1 -> preco; 2 -> ptpc"}; + + /// Particle 2 (Charm Hadrons) + Configurable charmHadBkgBDTmax{"charmHadBkgBDTmax", 1., "Maximum background bdt score for Charm Hadron (particle 2)"}; + Configurable charmHadCandSel{"charmHadCandSel", 1, "candidate selection for charm hadron"}; + Configurable charmHadMcSel{"charmHadMcSel", 2, "charm hadron selection for mc, partDplusToPiKPi (1), partLcToPKPi (2), partDsToKKPi (4), partXicToPKPi (8)"}; + Configurable charmHadFdBDTmin{"charmHadFdBDTmin", 0., "Minimum feed-down bdt score Charm Hadron (particle 2)"}; + Configurable charmHadFdBDTmax{"charmHadFdBDTmax", 1., "Maximum feed-down bdt score Charm Hadron (particle 2)"}; + Configurable charmHadMaxInvMass{"charmHadMaxInvMass", 2.45, "Maximum invariant mass of Charm Hadron (particle 2)"}; + Configurable charmHadMaxPt{"charmHadMaxPt", 999., "Maximum pT of Charm Hadron (particle 2)"}; + Configurable charmHadMinInvMass{"charmHadMinInvMass", 2.15, "Minimum invariant mass of Charm Hadron (particle 2)"}; + Configurable charmHadMinPt{"charmHadMinPt", 0., "Minimum pT of Charm Hadron (particle 2)"}; + Configurable charmHadPDGCode{"charmHadPDGCode", 4122, "PDG code of particle 2 Charm Hadron"}; + Configurable charmHadPromptBDTmin{"charmHadPromptBDTmin", 0., "Minimum prompt bdt score Charm Hadron (particle 2)"}; + Configurable charmHadPromptBDTmax{"charmHadPromptBDTmax", 1., "Maximum prompt bdt score Charm Hadron (particle 2)"}; + + /// General options + Configurable cprDeltaEtaMax{"cprDeltaEtaMax", 0.01, "Max. Delta Eta for Close Pair Rejection"}; + Configurable cprDeltaPhiMax{"cprDeltaPhiMax", 0.01, "Max. Delta Phi for Close Pair Rejection"}; + Configurable cprPlotPerRadii{"cprPlotPerRadii", false, "Plot CPR per radii"}; + Configurable extendedPlots{"extendedPlots", false, "Enable additional three dimensional histogramms. High memory consumption. Use for debugging"}; + Configurable highkstarCut{"highkstarCut", 100000., "Set a cut for high k*, above which the pairs are rejected"}; + Configurable isMc{"isMc", false, "Set true in the case of a MonteCarlo Run"}; + Configurable smearingByOrigin{"smearingByOrigin", false, "Obtain the smearing matrix differential in the MC origin of particle 1 and particle 2. High memory consumption. Use with care!"}; + Configurable use4D{"use4D", false, "Enable four dimensional histogramms (to be used only for analysis with high statistics): k* vs multiplicity vs multiplicity percentil vs mT"}; + Configurable useCPR{"useCPR", false, "Close Pair Rejection"}; + ConfigurableAxis dummy{"dummy", {1, 0, 1}, "dummy axis"}; + + // Mixing configurables + ConfigurableAxis mixingBinMult{"mixingBinMult", {VARIABLE_WIDTH, 0.0f, 20.0f, 60.0f, 200.0f}, "Mixing bins - multiplicity"}; + ConfigurableAxis mixingBinMultPercentile{"mixingBinMultPercentile", {VARIABLE_WIDTH, 0.0f, 100.f}, "Mixing bins - multiplicity percentile"}; + ConfigurableAxis mixingBinVztx{"mixingBinVztx", {VARIABLE_WIDTH, -10.0f, -4.f, 0.f, 4.f, 10.f}, "Mixing bins - z-vertex"}; + Configurable mixingDepth{"mixingDepth", 5, "Number of events for mixing"}; + Configurable mixingBinPolicy{"mixingBinPolicy", 0, "Binning policy for mixing - 0: multiplicity, 1: multipliciy percentile, 2: both"}; + + /// Event selection + struct : ConfigurableGroup { + std::string prefix = "eventSel"; + Configurable multMin{"multMin", 0, "Minimum Multiplicity (MultNtr)"}; + Configurable multMax{"multMax", 99999, "Maximum Multiplicity (MultNtr)"}; + Configurable multPercentileMin{"multPercentileMin", 0, "Maximum Multiplicity Percentile"}; + Configurable multPercentileMax{"multPercentileMax", 100, "Minimum Multiplicity Percentile"}; + } eventSel; + + /// Particle 1 (track) + Configurable cutBitTrack1{"cutBitTrack1", 5542474, "Particle 1 (Track) - Selection bit from cutCulator"}; + Configurable pdgCodeTrack1{"pdgCodeTrack1", 2212, "PDG code of Particle 1 (Track)"}; + Configurable pidThresTrack1{"pidThresTrack1", 0.75, "Momentum threshold for PID selection for particle 1 (Track)"}; + Configurable tpcBitTrack1{"tpcBitTrack1", 4, "PID TPC bit from cutCulator for particle 1 (Track)"}; + Configurable tpcTofBitTrack1{"tpcTofBitTrack1", 2, "PID TPCTOF bit from cutCulator for particle 1 (Track)"}; + Configurable etaTrack1Max{"etaTrack1Max", 10., "Maximum eta of partricle 1 (Track)"}; + Configurable ptTrack1Max{"ptTrack1Max", 999., "Maximum pT of partricle 1 (Track)"}; + Configurable etaTrack1Min{"etaTrack1Min", -10., "Minimum eta of partricle 1 (Track)"}; + Configurable ptTrack1Min{"ptTrack1Min", 0., "Minimum pT of partricle 1 (Track)"}; + + ColumnBinningPolicy colBinningMult{{mixingBinVztx, mixingBinMult}, true}; + ColumnBinningPolicy colBinningMultPercentile{{mixingBinVztx, mixingBinMultPercentile}, true}; + ColumnBinningPolicy colBinningMultMultPercentile{{mixingBinVztx, mixingBinMult, mixingBinMultPercentile}, true}; + + FemtoDreamContainer sameEventCont; + FemtoDreamContainer mixedEventCont; + FemtoDreamPairCleaner pairCleaner; + FemtoDreamDetaDphiStar pairCloseRejectionSE; + FemtoDreamDetaDphiStar pairCloseRejectionME; + Filter eventMultiplicity = aod::femtodreamcollision::multNtr >= eventSel.multMin && aod::femtodreamcollision::multNtr <= eventSel.multMax; + Filter eventMultiplicityPercentile = aod::femtodreamcollision::multV0M >= eventSel.multPercentileMin && aod::femtodreamcollision::multV0M <= eventSel.multPercentileMax; + Filter hfCandSelFilter = aod::fdhf::candidateSelFlag >= static_cast(charmHadCandSel.value); + Filter hfMcSelFilter = nabs(aod::fdhf::flagMc) == static_cast(charmHadMcSel.value); + Filter trackEtaFilterLow = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack), aod::femtodreamparticle::eta < etaTrack1Max, true); + Filter trackEtaFilterUp = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack), aod::femtodreamparticle::eta > etaTrack1Min, true); + Filter trackPtFilterLow = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack), aod::femtodreamparticle::pt < ptTrack1Max, true); + Filter trackPtFilterUp = ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack), aod::femtodreamparticle::pt > ptTrack1Min, true); + + using FilteredCharmCands = soa::Filtered; + using FilteredCharmCand = FilteredCharmCands::iterator; + + using FilteredCharmMcCands = soa::Filtered>; + using FilteredCharmMcCand = FilteredCharmMcCands::iterator; + + using FilteredColisions = soa::Filtered>; + using FilteredColision = FilteredColisions::iterator; + + using FilteredMcColisions = soa::Filtered>; + using FilteredMcColision = FilteredMcColisions::iterator; + + using FilteredFDMcParts = soa::Filtered>; + using FilteredFDMcPart = FilteredFDMcParts::iterator; + + using FilteredFDParticles = soa::Filtered>; + using FilteredFDParticle = FilteredFDParticles::iterator; + + femtodreamcollision::BitMaskType BitMask = 1 << 0; + + /// Histogramming for particle 1 + FemtoDreamParticleHisto allTrackHisto; + FemtoDreamParticleHisto selectedTrackHisto; + + /// Histogramming for Event + FemtoDreamEventHisto eventHisto; + /// Histogram output + HistogramRegistry registry{"CorrelationsAndQA", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryMixQa{"registryMixQa"}; + HistogramRegistry registryCharmHadronQa{"registryCharmHadronQa"}; + /// Partition for particle 1 + + Partition partitionTrk1 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && (ncheckbit(aod::femtodreamparticle::cut, cutBitTrack1)) && ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= pidThresTrack1, ncheckbit(aod::femtodreamparticle::pidcut, tpcBitTrack1), ncheckbit(aod::femtodreamparticle::pidcut, tpcTofBitTrack1)); + + Partition partitionMcTrk1 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && + (ncheckbit(aod::femtodreamparticle::cut, cutBitTrack1)) && + ifnode(aod::femtodreamparticle::pt * (nexp(aod::femtodreamparticle::eta) + nexp(-1.f * aod::femtodreamparticle::eta)) / 2.f <= pidThresTrack1, ncheckbit(aod::femtodreamparticle::pidcut, tpcBitTrack1), ncheckbit(aod::femtodreamparticle::pidcut, tpcTofBitTrack1)); + + /// Partition for particle 2 + Partition partitionCharmHadron = aod::fdhf::bdtBkg < charmHadBkgBDTmax && aod::fdhf::bdtFD < charmHadFdBDTmax && aod::fdhf::bdtFD > charmHadFdBDTmin&& aod::fdhf::bdtPrompt charmHadPromptBDTmin; + Partition partitionMcCharmHadron = aod::fdhf::originMcRec == 1 || aod::fdhf::originMcRec == 2; + + float massOne = o2::analysis::femtoDream::getMass(pdgCodeTrack1); + float massTwo = o2::analysis::femtoDream::getMass(charmHadPDGCode); + int8_t partSign = 0; + int64_t processType = 0; + + SliceCache cache; + Preslice perCol = aod::femtodreamparticle::fdCollisionId; + Produces fillFemtoResult; + + void init(InitContext& /*context*/) + { + // setup columnpolicy for binning + colBinningMult = {{mixingBinVztx, mixingBinMult}, true}; + colBinningMultPercentile = {{mixingBinVztx, mixingBinMultPercentile}, true}; + colBinningMultMultPercentile = {{mixingBinVztx, mixingBinMult, mixingBinMultPercentile}, true}; + eventHisto.init(®istry); + allTrackHisto.init(®istry, binmultTempFit, binMulPercentile, binpTTrack, binEta, binPhi, binTempFitVarTrack, binNSigmaTPC, binNSigmaTOF, binNSigmaTPCTOF, binTPCClusters, dummy, dummy, isMc, pdgCodeTrack1, true); + selectedTrackHisto.init(®istry, binmultTempFit, binMulPercentile, binpTTrack, binEta, binPhi, binTempFitVarTrack, binNSigmaTPC, binNSigmaTOF, binNSigmaTPCTOF, binTPCClusters, dummy, dummy, isMc, pdgCodeTrack1, true); + + sameEventCont.init(®istry, + binkstar, binpTTrack, binkT, binmT, mixingBinMult, mixingBinMultPercentile, + bin4Dkstar, bin4DmT, bin4DMult, bin4DmultPercentile, + isMc, use4D, extendedPlots, + highkstarCut, + smearingByOrigin, binInvMass); + + sameEventCont.setPDGCodes(pdgCodeTrack1, charmHadPDGCode); + mixedEventCont.init(®istry, + binkstar, binpTTrack, binkT, binmT, mixingBinMult, mixingBinMultPercentile, + bin4Dkstar, bin4DmT, bin4DMult, bin4DmultPercentile, + isMc, use4D, extendedPlots, + highkstarCut, + smearingByOrigin, binInvMass); + + mixedEventCont.setPDGCodes(pdgCodeTrack1, charmHadPDGCode); + registryMixQa.add("MixingQA/hSECollisionBins", "; bin; Entries", kTH1F, {{120, -0.5, 119.5}}); + registryMixQa.add("MixingQA/hSECollisionPool", "; Vz (cm); Mul", kTH2F, {{100, -10, 10}, {200, 0, 200}}); + registryMixQa.add("MixingQA/hMECollisionBins", "; bin; Entries", kTH1F, {{120, -0.5, 119.5}}); + registryCharmHadronQa.add("CharmHadronQA/hPtVsMass", "; #it{p}_{T} (GeV/#it{c}); inv. mass (GeV/#it{c}^{2})", kTH2F, {binpTCharm, binInvMass}); + + pairCleaner.init(®istry); + if (useCPR.value) { + pairCloseRejectionSE.init(®istry, ®istry, cprDeltaPhiMax.value, cprDeltaEtaMax.value, cprPlotPerRadii.value, 1); + pairCloseRejectionME.init(®istry, ®istry, cprDeltaPhiMax.value, cprDeltaEtaMax.value, cprPlotPerRadii.value, 2); + } + } + + template + void fillCollision(CollisionType const& col) + { + registryMixQa.fill(HIST("MixingQA/hSECollisionBins"), colBinningMult.getBin({col.posZ(), col.multNtr()})); + registryMixQa.fill(HIST("MixingQA/hSECollisionPool"), col.posZ(), col.multNtr()); + } + + /// This function processes the same event and takes care of all the histogramming + template + void doSameEvent(PartitionType& sliceTrk1, CandType& sliceCharmHad, TableTracks const& parts, Collision const& col) + { + fillCollision(col); + + processType = 1; // for same event + + for (auto const& [p1, p2] : combinations(CombinationsFullIndexPolicy(sliceTrk1, sliceCharmHad))) { + + if (p1.trackId() == p2.prong0Id() || p1.trackId() == p2.prong1Id() || p1.trackId() == p2.prong2Id()) + continue; + + if (useCPR.value) { + if (pairCloseRejectionSE.isClosePair(p1, p2, parts, col.magField())) { + continue; + } + } + + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + + // proton track charge + float chargeTrack = 0.; + if ((p1.cut() & 2) == 2) { + chargeTrack = PositiveCharge; + } else { + chargeTrack = NegativeCharge; + } + + int pairSign = 0; + if (chargeTrack == p2.charge()) { + pairSign = LikeSignPair; + } else { + pairSign = UnLikeSignPair; + } + + float kstar = FemtoDreamMath::getkstar(p1, massOne, p2, massTwo); + if (kstar > highkstarCut) { + continue; + } + + // if (chargeTrack == 1) { + // partSign = 1; + // } else { + // partSign = 1 << 1; + // } + + float invMass; + if (p2.candidateSelFlag() == 1) { + invMass = p2.m(std::array{o2::constants::physics::MassProton, o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); + } else { + invMass = p2.m(std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus, o2::constants::physics::MassProton}); + } + + if (invMass < charmHadMinInvMass || invMass > charmHadMaxInvMass) { + continue; + } + + if (p2.pt() < charmHadMinPt || p2.pt() > charmHadMaxPt) { + continue; + } + /// Filling QA histograms of the selected tracks + selectedTrackHisto.fillQA(p1, static_cast(ConfTempFitVarMomentum.value), col.multNtr(), col.multV0M()); + + int charmHadMc = 0; + int originType = 0; + if constexpr (isMc) { + charmHadMc = p2.flagMc(); + originType = p2.originMcRec(); + } + fillFemtoResult( + invMass, + p2.pt(), + p1.pt(), + p2.bdtBkg(), + p2.bdtPrompt(), + p2.bdtFD(), + kstar, + FemtoDreamMath::getkT(p1, massOne, p2, massTwo), + FemtoDreamMath::getmT(p1, massOne, p2, massTwo), + col.multNtr(), + col.multV0M(), + p2.charge(), + pairSign, + processType, + charmHadMc, + originType); + + sameEventCont.setPair(p1, p2, col.multNtr(), col.multV0M(), use4D, extendedPlots, smearingByOrigin); + } + } + + template + void doMixedEvent(CollisionType const& cols, PartType const& parts, PartitionType1& part1, PartitionType2& part2, BinningType policy) + { + + // Mixed events that contain the pair of interest + processType = 2; // for mixed event + + Partition PartitionMaskedCol1 = (aod::femtodreamcollision::bitmaskTrackOne & BitMask) == BitMask; + PartitionMaskedCol1.bindTable(cols); + + Partition PartitionMaskedCol2 = (aod::femtodreamcollision::bitmaskTrackTwo & BitMask) == BitMask; + PartitionMaskedCol2.bindTable(cols); + + for (auto const& [collision1, collision2] : combinations(soa::CombinationsBlockFullIndexPolicy(policy, mixingDepth.value, -1, *PartitionMaskedCol1.mFiltered, *PartitionMaskedCol2.mFiltered))) { + // make sure that tracks in the same events are not mixed + if (collision1.globalIndex() == collision2.globalIndex()) { + continue; + } + + const int multiplicityCol = collision1.multNtr(); + registryMixQa.fill(HIST("MixingQA/hMECollisionBins"), colBinningMult.getBin({collision1.posZ(), multiplicityCol})); + + auto sliceTrk1 = part1->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); + auto sliceCharmHad = part2->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(sliceTrk1, sliceCharmHad))) { + + if (useCPR.value) { + if (pairCloseRejectionME.isClosePair(p1, p2, parts, collision1.magField())) { + continue; + } + } + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + + float chargeTrack = 0.; + if ((p1.cut() & 2) == 2) { + chargeTrack = PositiveCharge; + } else { + chargeTrack = NegativeCharge; + } + + int pairSign = 0; + if (chargeTrack == p2.charge()) { + pairSign = LikeSignPair; + } else { + pairSign = UnLikeSignPair; + } + + float kstar = FemtoDreamMath::getkstar(p1, massOne, p2, massTwo); + if (kstar > highkstarCut) { + continue; + } + float invMass; + if (p2.candidateSelFlag() == 1) { + invMass = p2.m(std::array{o2::constants::physics::MassProton, o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); + } else { + invMass = p2.m(std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus, o2::constants::physics::MassProton}); + } + + if (invMass < charmHadMinInvMass || invMass > charmHadMaxInvMass) { + continue; + } + + if (p2.pt() < charmHadMinPt || p2.pt() > charmHadMaxPt) { + continue; + } + + int charmHadMc = 0; + int originType = 0; + if constexpr (isMc) { + charmHadMc = p2.flagMc(); + originType = p2.originMcRec(); + } + fillFemtoResult( + invMass, + p2.pt(), + p1.pt(), + p2.bdtBkg(), + p2.bdtPrompt(), + p2.bdtFD(), + kstar, + FemtoDreamMath::getkT(p1, massOne, p2, massTwo), + FemtoDreamMath::getmT(p1, massOne, p2, massTwo), + collision1.multNtr(), + collision1.multV0M(), + p2.charge(), + pairSign, + processType, + charmHadMc, + originType); + + // if constexpr (!isMc) mixedEventCont.setPair(p1, p2, collision1.multNtr(), collision1.multV0M(), use4D, extendedPlots, smearingByOrigin); + mixedEventCont.setPair(p1, p2, collision1.multNtr(), collision1.multV0M(), use4D, extendedPlots, smearingByOrigin); + } + } + } + + void processSameEvent(FilteredColision const& col, + FilteredFDParticles const& parts, + FilteredCharmCands const&) + { + eventHisto.fillQA(col); + auto sliceTrk1 = partitionTrk1->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + auto sliceCharmHad = partitionCharmHadron->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + /// Filling QA histograms of the all tracks and all charm hadrons before pairing + for (auto const& part : sliceTrk1) { + allTrackHisto.fillQA(part, static_cast(ConfTempFitVarMomentum.value), col.multNtr(), col.multV0M()); + } + for (auto const& part : sliceCharmHad) { + float invMass; + if (part.candidateSelFlag() == 1) { + invMass = part.m(std::array{o2::constants::physics::MassProton, o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); + } else { + invMass = part.m(std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus, o2::constants::physics::MassProton}); + } + registryCharmHadronQa.fill(HIST("CharmHadronQA/hPtVsMass"), part.pt(), invMass); + } + + if ((col.bitmaskTrackOne() & BitMask) != BitMask || (col.bitmaskTrackTwo() & BitMask) != BitMask) { + return; + } + doSameEvent(sliceTrk1, sliceCharmHad, parts, col); + } + PROCESS_SWITCH(HfTaskCharmHadronsFemtoDream, processSameEvent, "Enable processing same event", false); + + void processMixedEvent(FilteredColisions const& cols, + FilteredFDParticles const& parts, + FilteredCharmCands const&) + { + switch (mixingBinPolicy.value) { + case femtodreamcollision::kMult: + doMixedEvent(cols, parts, partitionTrk1, partitionCharmHadron, colBinningMult); + break; + case femtodreamcollision::kMultPercentile: + doMixedEvent(cols, parts, partitionTrk1, partitionCharmHadron, colBinningMultPercentile); + break; + case femtodreamcollision::kMultMultPercentile: + doMixedEvent(cols, parts, partitionTrk1, partitionCharmHadron, colBinningMultMultPercentile); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + PROCESS_SWITCH(HfTaskCharmHadronsFemtoDream, processMixedEvent, "Enable processing mixed events", false); + + /// process function for to call doSameEvent with Monte Carlo + /// \param col subscribe to the collision table (Monte Carlo Reconstructed reconstructed) + /// \param parts subscribe to joined table FemtoDreamParticles and FemtoDreamMCLables to access Monte Carlo truth + /// \param FemtoDreamMCParticles subscribe to the Monte Carlo truth table + void processSameEventMc(FilteredMcColision const& col, + FilteredFDMcParts const& parts, + o2::aod::FDMCParticles const&, + o2::aod::FDExtMCParticles const&, + FilteredCharmMcCands const&) + { + eventHisto.fillQA(col); + + auto sliceMcTrk1 = partitionMcTrk1->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + auto sliceMcCharmHad = partitionMcCharmHadron->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + + if (sliceMcTrk1.size() == 0 && sliceMcCharmHad.size() == 0) { + return; + } + /// Filling QA histograms of the all mc tracks before pairing + for (auto const& part : sliceMcTrk1) { + allTrackHisto.fillQA(part, static_cast(ConfTempFitVarMomentum.value), col.multNtr(), col.multV0M()); + } + + if ((col.bitmaskTrackOne() & BitMask) != BitMask || (col.bitmaskTrackTwo() & BitMask) != BitMask) { + return; + } + doSameEvent(sliceMcTrk1, sliceMcCharmHad, parts, col); + } + PROCESS_SWITCH(HfTaskCharmHadronsFemtoDream, processSameEventMc, "Enable processing same event for Monte Carlo", false); + + /// brief process function for to call doMixedEvent with Monte Carlo + /// @param cols subscribe to the collisions table (Monte Carlo Reconstructed reconstructed) + /// @param parts subscribe to joined table FemtoDreamParticles and FemtoDreamMCLables to access Monte Carlo truth + /// @param FemtoDreamMCParticles subscribe to the Monte Carlo truth table + void processMixedEventMc(FilteredMcColisions const& cols, + FilteredFDMcParts const& parts, + o2::aod::FDMCParticles const&, + o2::aod::FDExtMCParticles const&, + FilteredCharmMcCands const&) + { + switch (mixingBinPolicy.value) { + case femtodreamcollision::kMult: + doMixedEvent(cols, parts, partitionMcTrk1, partitionMcCharmHadron, colBinningMult); + break; + case femtodreamcollision::kMultPercentile: + doMixedEvent(cols, parts, partitionMcTrk1, partitionMcCharmHadron, colBinningMultPercentile); + break; + case femtodreamcollision::kMultMultPercentile: + doMixedEvent(cols, parts, partitionMcTrk1, partitionMcCharmHadron, colBinningMultMultPercentile); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + PROCESS_SWITCH(HfTaskCharmHadronsFemtoDream, processMixedEventMc, "Enable processing mixed events MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/HFC/Tasks/taskCorrelationD0Hadrons.cxx b/PWGHF/HFC/Tasks/taskCorrelationD0Hadrons.cxx index c6f732c2d62..2112aa91566 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationD0Hadrons.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationD0Hadrons.cxx @@ -16,42 +16,26 @@ /// \author Samrangy Sadhu , INFN Bari /// \author Swapnesh Santosh Khade , IIT Indore +#include + #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" +#include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/Utils/utilsAnalysis.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/HFC/Utils/utilsCorrelations.h" using namespace o2; +using namespace o2::constants::physics; +using namespace o2::constants::math; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::aod::hf_correlation_d0_hadron; - -namespace o2::aod -{ -using DHadronPairFull = soa::Join; -} // namespace o2::aod - -// string definitions, used for histogram axis labels -const TString stringPtD = "#it{p}_{T}^{D} (GeV/#it{c});"; -const TString stringPtHadron = "#it{p}_{T}^{Hadron} (GeV/#it{c});"; -const TString stringDeltaEta = "#it{#eta}^{Hadron}-#it{#eta}^{D};"; -const TString stringDeltaPhi = "#it{#varphi}^{Hadron}-#it{#varphi}^{D} (rad);"; -const TString stringDHadron = "D,Hadron candidates "; -const TString stringSignal = "signal region;"; -const TString stringSideband = "sidebands;"; -const TString stringMcParticles = "MC gen - D,Hadron particles;"; -const TString stringMcReco = "MC reco - D,Hadron candidates "; - -// histogram axes definition -AxisSpec axisDeltaEta = {100, -2., 2., ""}; -AxisSpec axisDeltaPhi = {64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf, ""}; -AxisSpec axisPtD = {10, 0., 10., ""}; -AxisSpec axisPtHadron = {11, 0., 11., ""}; -AxisSpec axisPoolBin = {9, 0., 9., ""}; +using namespace o2::analysis::hf_correlations; // definition of vectors for standard ptbin and invariant mass configurables const int nPtBinsCorrelations = 12; @@ -69,152 +53,255 @@ auto vecSidebandLeftInner = std::vector{sidebandLeftInnerDefault, sideba auto vecSidebandLeftOuter = std::vector{sidebandLeftOuterDefault, sidebandLeftOuterDefault + nPtBinsCorrelations}; auto vecSidebandRightInner = std::vector{sidebandRightInnerDefault, sidebandRightInnerDefault + nPtBinsCorrelations}; auto vecSidebandRightOuter = std::vector{sidebandRightOuterDefault, sidebandRightOuterDefault + nPtBinsCorrelations}; -const int nPtBinsEfficiency = o2::analysis::hf_cuts_d0_to_pi_k::nBinsPt; -const double efficiencyDmesonDefault[nPtBinsEfficiency] = {}; -auto vecEfficiencyDmeson = std::vector{efficiencyDmesonDefault, efficiencyDmesonDefault + nPtBinsEfficiency}; -const double ptHadronMax = 10.0; +const int nPtbinsPtEfficiencyD = o2::analysis::hf_cuts_d0_to_pi_k::NBinsPt; +const double efficiencyDmesonDefault[nPtbinsPtEfficiencyD] = {}; +auto vecEfficiencyDmeson = std::vector{efficiencyDmesonDefault, efficiencyDmesonDefault + nPtbinsPtEfficiencyD}; struct HfTaskCorrelationD0Hadrons { - // pT ranges for correlation plots: the default values are those embedded in hf_cuts_d0_to_pi_k (i.e. the mass pT bins), but can be redefined via json files - Configurable> binsCorrelations{"ptBinsForCorrelations", std::vector{vecPtBinsCorrelations}, "pT bin limits for correlation plots"}; - // pT bins for effiencies: same as above - Configurable> binsEfficiency{"ptBinsForEfficiency", std::vector{o2::analysis::hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits for efficiency"}; - // signal and sideband region edges, to be defined via json file (initialised to empty) + // pT ranges: the default values are those embedded in hf_cuts_d0_to_pi_k (i.e. the mass pT bins), but can be redefined via json files + Configurable> binsPtD{"binsPtD", std::vector{o2::analysis::hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits for candidate mass plots and efficiency"}; + Configurable> binsPtHadron{"binsPtHadron", std::vector{0.3, 2., 4., 8., 12., 50.}, "pT bin limits for assoc particle efficiency"}; + Configurable> binsCorrelations{"binsCorrelations", std::vector{vecPtBinsCorrelations}, "pT bin limits for correlation plots"}; + Configurable> binsPtEfficiencyD{"binsPtEfficiencyD", std::vector{o2::analysis::hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits for efficiency"}; + Configurable> binsPtEfficiencyHad{"binsPtEfficiencyHad", std::vector{0.3, 2., 4., 8., 12., 50.}, "pT bin limits for associated particle efficiency"}; + Configurable> efficiencyDmeson{"efficiencyDmeson", std::vector{vecEfficiencyDmeson}, "Efficiency values for D meson specie under study"}; + Configurable> efficiencyHad{"efficiencyHad", {1., 1., 1., 1., 1., 1.}, "efficiency values for associated particles"}; + Configurable applyEfficiency{"applyEfficiency", 1, "Flag for applying efficiency weights"}; + Configurable> classMl{"classMl", {0, 1, 2}, "Indexes of ML scores to be stored. Three indexes max."}; + Configurable> mlOutputPromptD0{"mlOutputPromptD0", {0.5, 0.5, 0.5, 0.5}, "Machine learning scores for prompt"}; + Configurable> mlOutputBkgD0{"mlOutputBkgD0", {0.5, 0.5, 0.5, 0.5}, "Machine learning scores for bkg"}; + Configurable> mlOutputPromptD0bar{"mlOutputPromptD0bar", {0.5, 0.5, 0.5, 0.5}, "Machine learning scores for prompt"}; + Configurable> mlOutputBkgD0bar{"mlOutputBkgD0bar", {0.5, 0.5, 0.5, 0.5}, "Machine learning scores for bkg"}; + Configurable ptCandMin{"ptCandMin", 1., "min. cand. pT"}; + Configurable ptCandMax{"ptCandMax", 50., "max. cand pT"}; + Configurable ptTrackMin{"ptTrackMin", 0.3, "min. track pT"}; + Configurable ptTrackMax{"ptTrackMax", 99., "max. track pT"}; + Configurable etaTrackMax{"etaTrackMax", 0.8, "max. eta of tracks"}; + Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity"}; + Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen. cand. rapidity"}; + Configurable ptDaughterMin{"ptDaughterMin", 0.1, "min. daughter pT"}; + Configurable nTpcCrossedRaws{"nTpcCrossedRaws", 70, "Number of crossed TPC Rows"}; + Configurable dcaXYTrackMax{"dcaXYTrackMax", 1., "max. DCA_xy of tracks"}; + Configurable dcaZTrackMax{"dcaZTrackMax", 1., "max. DCA_z of tracks"}; + Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0 (bar)"}; + Configurable selNoSameBunchPileUpColl{"selNoSameBunchPileUpColl", true, "Flag for rejecting the collisions associated with the same bunch crossing"}; Configurable> signalRegionLeft{"signalRegionLeft", std::vector{vecsignalRegionLeft}, "Inner values of signal region vs pT"}; Configurable> signalRegionRight{"signalRegionRight", std::vector{vecsignalRegionRight}, "Outer values of signal region vs pT"}; Configurable> sidebandLeftInner{"sidebandLeftInner", std::vector{vecSidebandLeftInner}, "Inner values of left sideband vs pT"}; Configurable> sidebandLeftOuter{"sidebandLeftOuter", std::vector{vecSidebandLeftOuter}, "Outer values of left sideband vs pT"}; Configurable> sidebandRightInner{"sidebandRightInner", std::vector{vecSidebandRightInner}, "Inner values of right sideband vs pT"}; Configurable> sidebandRightOuter{"sidebandRightOuter", std::vector{vecSidebandRightOuter}, "Outer values of right sideband vs pT"}; - Configurable> efficiencyDmeson{"efficiencyDmeson", std::vector{vecEfficiencyDmeson}, "Efficiency values for D meson specie under study"}; - Configurable applyEfficiency{"efficiencyFlagD", 1, "Flag for applying efficiency weights"}; - - HistogramRegistry registry{ - "registry", - {{"hDeltaEtaPtIntSignalRegion", stringDHadron + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSignalRegion", stringDHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hCorrel2DPtIntSignalRegion", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hCorrel2DVsPtSignalRegion", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, // note: axes 3 and 4 (the pT) are updated in the init() - {"hDeltaEtaPtIntSignalRegionSoftPi", stringDHadron + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSignalRegionSoftPi", stringDHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hCorrel2DPtIntSignalRegionSoftPi", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hCorrel2DVsPtSignalRegionSoftPi", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, // note: axes 3 and 4 (the pT) are updated in the init() - {"hDeltaEtaPtIntSidebands", stringDHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSidebands", stringDHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hCorrel2DPtIntSidebands", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hCorrel2DVsPtSidebands", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, // note: axes 3 and 4 (the pT) are updated in the init() - {"hDeltaEtaPtIntSidebandsSoftPi", stringDHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSidebandsSoftPi", stringDHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hCorrel2DPtIntSidebandsSoftPi", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hCorrel2DVsPtSidebandsSoftPi", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, // note: axes 3 and 4 (the pT) are updated in the init() - {"hCorrel2DVsPtRecSig", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, - {"hCorrel2DVsPtRecBg", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, - // correlation histograms for MCRec for signal only - {"hCorrel2DVsPtSignalRegionRecSig", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, - {"hCorrel2DVsPtSignalRegionSoftPiRecSig", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, - {"hCorrel2DPtIntSignalRegionRecSig", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hCorrel2DPtIntSignalRegionSoftPiRecSig", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hDeltaEtaPtIntSignalRegionRecSig", stringDHadron + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaEtaPtIntSignalRegionSoftPiRecSig", stringDHadron + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSignalRegionRecSig", stringDHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hDeltaPhiPtIntSignalRegionSoftPiRecSig", stringDHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hCorrel2DVsPtSidebandsRecSig", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, - {"hCorrel2DVsPtSidebandsSoftPiRecSig", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, - {"hCorrel2DPtIntSidebandsRecSig", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hCorrel2DPtIntSidebandsSoftPiRecSig", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hDeltaEtaPtIntSidebandsRecSig", stringDHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaEtaPtIntSidebandsSoftPiRecSig", stringDHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSidebandsRecSig", stringDHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hDeltaPhiPtIntSidebandsSoftPiRecSig", stringDHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - // correlation histograms for MCRec for reflection candidates only - {"hCorrel2DVsPtSignalRegionRecRef", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, - {"hCorrel2DPtIntSignalRegionRecRef", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hDeltaEtaPtIntSignalRegionRecRef", stringDHadron + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSignalRegionRecRef", stringDHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hCorrel2DVsPtSidebandsRecRef", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, - {"hCorrel2DPtIntSidebandsRecRef", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hDeltaEtaPtIntSidebandsRecRef", stringDHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSidebandsRecRef", stringDHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hCorrel2DVsPtSignalRegionSoftPiRecRef", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, - {"hCorrel2DPtIntSignalRegionSoftPiRecRef", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hDeltaEtaPtIntSignalRegionSoftPiRecRef", stringDHadron + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSignalRegionSoftPiRecRef", stringDHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hCorrel2DVsPtSidebandsSoftPiRecRef", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, - {"hCorrel2DPtIntSidebandsSoftPiRecRef", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hDeltaEtaPtIntSidebandsSoftPiRecRef", stringDHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSidebandsSoftPiRecRef", stringDHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - // correlation histograms for MCRec for background candidates only - {"hCorrel2DVsPtSignalRegionRecBg", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, - {"hCorrel2DPtIntSignalRegionRecBg", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hDeltaEtaPtIntSignalRegionRecBg", stringDHadron + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSignalRegionRecBg", stringDHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hCorrel2DVsPtSidebandsRecBg", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, - {"hCorrel2DPtIntSidebandsRecBg", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hDeltaEtaPtIntSidebandsRecBg", stringDHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSidebandsRecBg", stringDHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hCorrel2DVsPtSignalRegionSoftPiRecBg", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, - {"hCorrel2DPtIntSignalRegionSoftPiRecBg", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hDeltaEtaPtIntSignalRegionSoftPiRecBg", stringDHadron + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSignalRegionSoftPiRecBg", stringDHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hCorrel2DVsPtSidebandsSoftPiRecBg", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, - {"hCorrel2DPtIntSidebandsSoftPiRecBg", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hDeltaEtaPtIntSidebandsSoftPiRecBg", stringDHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSidebandsSoftPiRecBg", stringDHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - // correlation histograms for MCGen - {"hCorrel2DVsPtGen", stringMcParticles + stringDeltaPhi + stringDeltaEta + stringPtD + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}}, // note: axes 3 and 4 (the pT) are updated in the init(), - {"hCorrel2DPtIntGen", stringMcParticles + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hDeltaEtaPtIntGen", stringMcParticles + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntGen", stringMcParticles + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}}}; + Configurable isTowardTransverseAway{"isTowardTransverseAway", false, "Divide into three regions: toward, transverse, and away"}; + Configurable leadingParticlePtMin{"leadingParticlePtMin", 0., "Min for leading particle pt"}; + + HfHelper hfHelper; + + enum CandidateStep { kCandidateStepMcGenAll = 0, + kCandidateStepMcGenD0ToPiKPi, + kCandidateStepMcCandInAcceptance, + kCandidateStepMcDaughtersInAcceptance, + kCandidateStepMcReco, + kCandidateStepMcRecoInAcceptance, + kCandidateNSteps }; + + using D0HadronPairFull = soa::Join; + using D0HadronPairFullMl = soa::Join; + using CandD0McReco = soa::Filtered>; + using CandD0McGen = soa::Join; + using TracksWithMc = soa::Filtered>; // trackFilter applied + + Filter d0Filter = (aod::hf_sel_candidate_d0::isSelD0 >= selectionFlagD0) || (aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlagD0); + Filter trackFilter = (nabs(aod::track::eta) < etaTrackMax) && (aod::track::pt > ptTrackMin) && (aod::track::pt < ptTrackMax) && (nabs(aod::track::dcaXY) < dcaXYTrackMax) && (nabs(aod::track::dcaZ) < dcaZTrackMax); + + ConfigurableAxis binsMassD{"binsMassD", {200, 1.3848, 2.3848}, "inv. mass (#pi K) (GeV/#it{c}^{2});entries"}; + ConfigurableAxis binsBdtScore{"binsBdtScore", {100, 0., 1.}, "Bdt output scores"}; + ConfigurableAxis binsEta{"binsEta", {100, -2., 2.}, "#it{#eta}"}; + ConfigurableAxis binsPhi{"binsPhi", {64, -PIHalf, 3. * PIHalf}, "#it{#varphi}"}; + ConfigurableAxis binsMultFT0M{"binsMultFT0M", {600, 0., 8000.}, "Multiplicity as FT0M signal amplitude"}; + ConfigurableAxis binsPosZ{"binsPosZ", {100, -10., 10.}, "primary vertex z coordinate"}; + ConfigurableAxis binsPoolBin{"binsPoolBin", {9, 0., 9.}, "PoolBin"}; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext&) { - int nBinsPtAxis = binsCorrelations->size() - 1; - const double* valuesPtAxis = binsCorrelations->data(); - registry.get(HIST("hCorrel2DVsPtSignalRegion"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtSidebands"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); + AxisSpec axisMassD = {binsMassD, "inv. mass (#pi K) (GeV/#it{c}^{2})"}; + AxisSpec axisDeltaEta = {binsEta, "#it{#eta}^{Hadron}-#it{#eta}^{D}"}; + AxisSpec axisEta = {binsEta, "#it{#eta}"}; + AxisSpec axisDeltaPhi = {binsPhi, "#it{#varphi}^{Hadron}-#it{#varphi}^{D} (rad)"}; + AxisSpec axisPtD = {(std::vector)binsPtD, "#it{p}_{T}^{D} (GeV/#it{c})"}; + AxisSpec axisPtHadron = {(std::vector)binsPtHadron, "#it{p}_{T}^{Hadron} (GeV/#it{c})"}; + AxisSpec axisPoolBin = {binsPoolBin, "poolBin"}; + AxisSpec axisBdtScore = {binsBdtScore, "Bdt score"}; + AxisSpec axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; + AxisSpec axisPosZ = {binsPosZ, "PosZ"}; + AxisSpec axisD0Prompt = {2, -0.5, 1.5, "Prompt D0"}; + AxisSpec axisCorrelationState = {2, 0., 2., "correlationState"}; + + // Histograms for data + registry.add("hDeltaEtaPtIntSignalRegion", "D0-h deltaEta signal region", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSignalRegion", "D0-h deltaPhi signal region", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSignalRegion", "D0-h deltaPhi vs deltaEta signal region", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSignalRegion", "D0-h correlations signal region", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSignalRegionSoftPi", "D0-h deltaEta signal region soft pi only", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSignalRegionSoftPi", "D0-h deltaPhi signal region soft pi only", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSignalRegionSoftPi", "D0-h deltaPhi vs deltaEta signal region soft pi only", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSignalRegionSoftPi", "D0-h correlations signal region soft pi only", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSidebands", "D0-h deltaEta sidebands", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebands", "D0-h deltaPhi sidebands", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSidebands", "D0-h deltaPhi vs deltaEta sidebands", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSidebands", "D0-h correlations sidebands", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSidebandsSoftPi", "D0-h deltaEta sidebands soft pi only", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandsSoftPi", "D0-h deltaPhi sidebands soft pi only", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSidebandsSoftPi", "D0-h deltaPhi vs deltaEta sidebands soft pi only", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSidebandsSoftPi", "D0-h correlations sidebands soft pi only", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); registry.get(HIST("hCorrel2DVsPtSignalRegion"))->Sumw2(); registry.get(HIST("hCorrel2DVsPtSidebands"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSignalRegionSoftPi"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtSidebandsSoftPi"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); registry.get(HIST("hCorrel2DVsPtSignalRegionSoftPi"))->Sumw2(); registry.get(HIST("hCorrel2DVsPtSidebandsSoftPi"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSignalRegionRecSig"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtSignalRegionSoftPiRecSig"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtSidebandsRecSig"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtSidebandsSoftPiRecSig"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); + // Toward Transverse Away for Data + registry.add("hToward", "Toward", {HistType::kTH3F, {{axisMassD}, {axisPtD}, {axisCorrelationState}}}); + registry.add("hTransverse", "Transverse", {HistType::kTH3F, {{axisMassD}, {axisPtD}, {axisCorrelationState}}}); + registry.add("hAway", "Away", {HistType::kTH3F, {{axisMassD}, {axisPtD}, {axisCorrelationState}}}); + + // Histograms for MC reco + registry.add("hCorrel2DVsPtRecSig", "D0-h correlations MC reco signal", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.get(HIST("hCorrel2DVsPtRecSig"))->Sumw2(); + registry.add("hCorrel2DVsPtRecBg", "D0-h correlations MC reco background", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.get(HIST("hCorrel2DVsPtRecBg"))->Sumw2(); + // MC reco D0, D0bar signal case + registry.add("hDeltaEtaPtIntSignalRegionRecSig", "D0-h deltaEta MC reco signal region, signal", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSignalRegionRecSig", "D0-h deltaPhi MC reco signal region, signal", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSignalRegionRecSig", "D0-h deltaPhi vs deltaEta MC reco signal region, signal", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSignalRegionRecSig", "D0-h correlations MC reco signal region, signal", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisD0Prompt}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtPhysicalPrimaryRecSig", "D0-h correlations signal region (only true primary particles) MC reco", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisD0Prompt}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignalRegionPromptD0PromptHadronRecSig", "D0-h correlations signal region Prompt-NonPrompt MC reco", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignalRegionNonPromptD0NonPromptHadronRecSig", "D0-h correlations signal region NonPrompt-NonPrompt MC reco", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSignalRegionSoftPiRecSig", "D0-h deltaEta MC reco signal region, signal", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSignalRegionSoftPiRecSig", "D0-h deltaPhi MC reco signal region, signal", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSignalRegionSoftPiRecSig", "D0-h deltaPhi vs deltaEta MC reco signal region, signal", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSignalRegionSoftPiRecSig", "D0-h correlations MC reco signal region, signal", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSidebandsRecSig", "D0-h deltaEta MC reco sidebands, signal", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandsRecSig", "D0-h deltaPhi MC reco sidebands, signal", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSidebandsRecSig", "D0-h deltaPhi vs deltaEta MC reco sidebands, signal", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSidebandsRecSig", "D0-h correlations MC reco sidebands, signal", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSidebandsSoftPiRecSig", "D0-h deltaEta MC reco sidebands, signal", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandsSoftPiRecSig", "D0-h deltaPhi MC reco sidebands, signal", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSidebandsSoftPiRecSig", "D0-h deltaPhi vs deltaEta MC reco sidebands, signal", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSidebandsSoftPiRecSig", "D0-h correlations MC reco sidebands, signal", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); registry.get(HIST("hCorrel2DVsPtSignalRegionRecSig"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtPhysicalPrimaryRecSig"))->Sumw2(); registry.get(HIST("hCorrel2DVsPtSignalRegionSoftPiRecSig"))->Sumw2(); registry.get(HIST("hCorrel2DVsPtSidebandsRecSig"))->Sumw2(); registry.get(HIST("hCorrel2DVsPtSidebandsSoftPiRecSig"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSignalRegionRecRef"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtSidebandsRecRef"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); + // MC reco D0, D0bar reflection case + registry.add("hDeltaEtaPtIntSignalRegionRecRef", "D0-h deltaEta MC reco signal region, refelction", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSignalRegionRecRef", "D0-h deltaPhi MC reco signal region, refelction", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSignalRegionRecRef", "D0-h deltaPhi vs deltaEta MC reco signal region, refelction", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSignalRegionRecRef", "D0-h correlations MC reco signal region, refelction", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSignalRegionSoftPiRecRef", "D0-h deltaEta MC reco signal region, refelction", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSignalRegionSoftPiRecRef", "D0-h deltaPhi MC reco signal region, refelction", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSignalRegionSoftPiRecRef", "D0-h deltaPhi vs deltaEta MC reco signal region, refelction", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSignalRegionSoftPiRecRef", "D0-h correlations MC reco signal region, refelction", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSidebandsRecRef", "D0-h deltaEta MC reco sidebands, refelction", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandsRecRef", "D0-h deltaPhi MC reco sidebands, refelction", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSidebandsRecRef", "D0-h deltaPhi vs deltaEta MC reco sidebands, refelction", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSidebandsRecRef", "D0-h correlations MC reco sidebands, refelction", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSidebandsSoftPiRecRef", "D0-h deltaEta MC reco sidebands, refelction", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandsSoftPiRecRef", "D0-h deltaPhi MC reco sidebands, refelction", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSidebandsSoftPiRecRef", "D0-h deltaPhi vs deltaEta MC reco sidebands, refelction", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSidebandsSoftPiRecRef", "D0-h correlations MC reco sidebands, refelction", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); registry.get(HIST("hCorrel2DVsPtSignalRegionRecRef"))->Sumw2(); registry.get(HIST("hCorrel2DVsPtSidebandsRecRef"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSignalRegionSoftPiRecRef"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtSidebandsSoftPiRecRef"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); registry.get(HIST("hCorrel2DVsPtSignalRegionSoftPiRecRef"))->Sumw2(); registry.get(HIST("hCorrel2DVsPtSidebandsSoftPiRecRef"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSignalRegionRecBg"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtSidebandsRecBg"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); + // MC reco D0, D0bar background case + registry.add("hDeltaEtaPtIntSignalRegionRecBg", "D0-h deltaEta MC reco signal region, background", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSignalRegionRecBg", "D0-h deltaPhi MC reco signal region, background", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSignalRegionRecBg", "D0-h deltaPhi vs deltaEta MC reco signal region, background", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSignalRegionRecBg", "D0-h correlations MC reco signal region, background", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSignalRegionSoftPiRecBg", "D0-h deltaEta MC reco signal region, background", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSignalRegionSoftPiRecBg", "D0-h deltaPhi MC reco signal region, background", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSignalRegionSoftPiRecBg", "D0-h deltaPhi vs deltaEta MC reco signal region, background", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSignalRegionSoftPiRecBg", "D0-h correlations MC reco signal region, background", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSidebandsRecBg", "D0-h deltaEta MC reco sidebands, background", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandsRecBg", "D0-h deltaPhi MC reco sidebands, background", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSidebandsRecBg", "D0-h deltaPhi vs deltaEta MC reco sidebands, background", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSidebandsRecBg", "D0-h correlations MC reco sidebands, background", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSidebandsSoftPiRecBg", "D0-h deltaEta MC reco sidebands, background", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandsSoftPiRecBg", "D0-h deltaPhi MC reco sidebands, background", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSidebandsSoftPiRecBg", "D0-h deltaPhi vs deltaEta MC reco sidebands, background", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSidebandsSoftPiRecBg", "D0-h correlations MC reco sidebands, background", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); registry.get(HIST("hCorrel2DVsPtSignalRegionRecBg"))->Sumw2(); registry.get(HIST("hCorrel2DVsPtSidebandsRecBg"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSignalRegionSoftPiRecBg"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtSidebandsSoftPiRecBg"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); registry.get(HIST("hCorrel2DVsPtSignalRegionSoftPiRecBg"))->Sumw2(); registry.get(HIST("hCorrel2DVsPtSidebandsSoftPiRecBg"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtRecSig"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtRecSig"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtRecBg"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtRecBg"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtGen"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtGen"))->Sumw2(); + // Toward Transverse Away for McRec + registry.add("hTowardRec", "Toward", {HistType::kTH3F, {{axisMassD}, {axisPtD}, {axisCorrelationState}}}); + registry.add("hTransverseRec", "Transverse", {HistType::kTH3F, {{axisMassD}, {axisPtD}, {axisCorrelationState}}}); + registry.add("hAwayRec", "Away", {HistType::kTH3F, {{axisMassD}, {axisPtD}, {axisCorrelationState}}}); + + // Histograms for MC gen + registry.add("hDeltaEtaPtIntGen", "D0-h deltaEta MC gen", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntGen", "D0-h deltaPhi MC gen", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntGen", "D0-h deltaPhi vs deltaEta MC gen", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtGenPrompt", "D0-h correlations MC gen, prompt", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtGenNonPrompt", "D0-h correlations MC gen, non prompt", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtGenPromptD0PromptHadron", "D0-h correlations MC gen, prompt D0, non-prompt hadrons", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtGenNonPromptD0NonPromptHadron", "D0-h correlations MC gen, prompt D0, non-prompt hadrons", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.get(HIST("hCorrel2DVsPtGenPrompt"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtGenNonPrompt"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtGenPromptD0PromptHadron"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtGenNonPromptD0NonPromptHadron"))->Sumw2(); + // Toward Transverse Away for MC gen + registry.add("hTowardGen", "Toward", {HistType::kTH3F, {{axisMassD}, {axisPtD}, {axisCorrelationState}}}); + registry.add("hTransverseGen", "Transverse", {HistType::kTH3F, {{axisMassD}, {axisPtD}, {axisCorrelationState}}}); + registry.add("hAwayGen", "Away", {HistType::kTH3F, {{axisMassD}, {axisPtD}, {axisCorrelationState}}}); + + // Common histograms + registry.add("hBdtScorePromptD0", "D0 BDT prompt score", {HistType::kTH1F, {axisBdtScore}}); + registry.add("hBdtScoreBkgD0", "D0 BDT bkg score", {HistType::kTH1F, {axisBdtScore}}); + registry.add("hBdtScorePromptD0bar", "D0bar BDT prompt score", {HistType::kTH1F, {axisBdtScore}}); + registry.add("hBdtScoreBkgD0bar", "D0bar BDT bkg score", {HistType::kTH1F, {axisBdtScore}}); + + // Efficiency histograms + registry.add("hPtCandMcRecPrompt", "D0 prompt candidates pt", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandMcRecNonPrompt", "D0 non prompt candidates pt", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandMcGenPrompt", "D0,Hadron particles prompt - MC Gen", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandMcGenNonPrompt", "D0,Hadron particles non prompt - MC Gen", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandMcGenDaughterInAcc", "D0,Hadron particles non prompt - MC Gen", {HistType::kTH1F, {axisPtD}}); + + auto hCandidates = registry.add("hCandidates", "Candidate count at different steps", {HistType::kStepTHnF, {axisPtD, axisMultFT0M, {RecoDecay::OriginType::NonPrompt + 1, +RecoDecay::OriginType::None - 0.5, +RecoDecay::OriginType::NonPrompt + 0.5}}, kCandidateNSteps}); + hCandidates->GetAxis(0)->SetTitle("#it{p}_{T} (GeV/#it{c})"); + hCandidates->GetAxis(1)->SetTitle("multiplicity"); + hCandidates->GetAxis(2)->SetTitle("Charm hadron origin"); } /// D-h correlation pair filling task, from pair tables - for real data and data-like analysis (i.e. reco-level w/o matching request via MC truth) /// Works on both USL and LS analyses pair tables - void processData(aod::DHadronPairFull const& pairEntries) + void processData(D0HadronPairFullMl const& pairEntries, + aod::D0CandRecoInfo const& candidates) { + for (const auto& candidate : candidates) { + float ptD = candidate.ptD(); + float bdtScorePromptD0 = candidate.mlScorePromptD0(); + float bdtScoreBkgD0 = candidate.mlScoreBkgD0(); + float bdtScorePromptD0bar = candidate.mlScorePromptD0bar(); + float bdtScoreBkgD0bar = candidate.mlScoreBkgD0bar(); + int effBinD = o2::analysis::findBin(binsPtEfficiencyD, ptD); + + registry.fill(HIST("hBdtScorePromptD0"), bdtScorePromptD0); + registry.fill(HIST("hBdtScoreBkgD0"), bdtScoreBkgD0); + registry.fill(HIST("hBdtScorePromptD0bar"), bdtScorePromptD0bar); + registry.fill(HIST("hBdtScoreBkgD0bar"), bdtScoreBkgD0bar); + + if (bdtScorePromptD0 < mlOutputPromptD0->at(effBinD) || bdtScoreBkgD0 > mlOutputBkgD0->at(effBinD) || + bdtScorePromptD0bar < mlOutputPromptD0bar->at(effBinD) || bdtScoreBkgD0bar > mlOutputBkgD0bar->at(effBinD)) { + continue; + } + } + for (const auto& pairEntry : pairEntries) { // define variables for widely used quantities double deltaPhi = pairEntry.deltaPhi(); @@ -224,27 +311,58 @@ struct HfTaskCorrelationD0Hadrons { double massD = pairEntry.mD(); double massDbar = pairEntry.mDbar(); int signalStatus = pairEntry.signalStatus(); - int effBinD = o2::analysis::findBin(binsEfficiency, ptD); + int effBinD = o2::analysis::findBin(binsPtEfficiencyD, ptD); int ptBinD = o2::analysis::findBin(binsCorrelations, ptD); int poolBin = pairEntry.poolBin(); - + float trackDcaXY = pairEntry.trackDcaXY(); + float trackDcaZ = pairEntry.trackDcaZ(); + int trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); + bool isAutoCorrelated = pairEntry.isAutoCorrelated(); + float bdtScorePromptD0 = pairEntry.mlScorePromptD0(); + float bdtScoreBkgD0 = pairEntry.mlScoreBkgD0(); + float bdtScorePromptD0bar = pairEntry.mlScorePromptD0bar(); + float bdtScoreBkgD0bar = pairEntry.mlScoreBkgD0bar(); // reject entries outside pT ranges of interest if (ptBinD < 0 || effBinD < 0) { continue; } - if (ptHadron > ptHadronMax) { - ptHadron = ptHadronMax + 0.5; + if (bdtScorePromptD0 < mlOutputPromptD0->at(ptBinD) || bdtScoreBkgD0 > mlOutputBkgD0->at(ptBinD) || + bdtScorePromptD0bar < mlOutputPromptD0bar->at(ptBinD) || bdtScoreBkgD0bar > mlOutputBkgD0bar->at(ptBinD)) { + continue; + } + if (trackDcaXY > dcaXYTrackMax || trackDcaZ > dcaZTrackMax || trackTpcCrossedRows < nTpcCrossedRaws) { + continue; } - double efficiencyWeight = 1.; if (applyEfficiency) { - efficiencyWeight = 1. / (efficiencyDmeson->at(o2::analysis::findBin(binsEfficiency, ptD))); // ***** track efficiency to be implemented ***** + efficiencyWeight = 1. / (efficiencyDmeson->at(o2::analysis::findBin(binsPtEfficiencyD, ptD)) * efficiencyHad->at(o2::analysis::findBin(binsPtEfficiencyHad, ptHadron))); } - // reject entries outside pT ranges of interest if (ptBinD == -1) { // at least one particle outside accepted pT range continue; } + //============================================================================================================== + if (isTowardTransverseAway) { + // Divide into three regions: toward, transverse, and away + if (ptHadron < leadingParticlePtMin) { + continue; + } + Region region = getRegion(deltaPhi); + + switch (region) { + case Toward: + registry.fill(HIST("hToward"), massD, ptD, isAutoCorrelated, efficiencyWeight); + break; + case Away: + registry.fill(HIST("hAway"), massD, ptD, isAutoCorrelated, efficiencyWeight); + break; + case Transverse: + registry.fill(HIST("hTransverse"), massD, ptD, isAutoCorrelated, efficiencyWeight); + break; + default: + break; + } + } // check if correlation entry belongs to signal region, sidebands or is outside both, and fill correlation plots if ((massD > signalRegionLeft->at(ptBinD) && massD < signalRegionRight->at(ptBinD)) && ((signalStatus == ParticleTypeData::D0Only) || (signalStatus == ParticleTypeData::D0D0barBoth))) { // in signal region @@ -321,8 +439,28 @@ struct HfTaskCorrelationD0Hadrons { } PROCESS_SWITCH(HfTaskCorrelationD0Hadrons, processData, "Process data", false); - void processMcRec(aod::DHadronPairFull const& pairEntries) + void processMcRec(D0HadronPairFullMl const& pairEntries, + soa::Join const& candidates) { + for (const auto& candidate : candidates) { + float ptD = candidate.ptD(); + float bdtScorePromptD0 = candidate.mlScorePromptD0(); + float bdtScoreBkgD0 = candidate.mlScoreBkgD0(); + float bdtScorePromptD0bar = candidate.mlScorePromptD0bar(); + float bdtScoreBkgD0bar = candidate.mlScoreBkgD0bar(); + int effBinD = o2::analysis::findBin(binsPtEfficiencyD, ptD); + + registry.fill(HIST("hBdtScorePromptD0"), bdtScorePromptD0); + registry.fill(HIST("hBdtScoreBkgD0"), bdtScoreBkgD0); + registry.fill(HIST("hBdtScorePromptD0bar"), bdtScorePromptD0bar); + registry.fill(HIST("hBdtScoreBkgD0bar"), bdtScoreBkgD0bar); + + if (bdtScorePromptD0 < mlOutputPromptD0->at(effBinD) || bdtScoreBkgD0 > mlOutputBkgD0->at(effBinD) || + bdtScorePromptD0bar < mlOutputPromptD0bar->at(effBinD) || bdtScoreBkgD0bar > mlOutputBkgD0bar->at(effBinD)) { + continue; + } + } + for (const auto& pairEntry : pairEntries) { // define variables for widely used quantities double deltaPhi = pairEntry.deltaPhi(); @@ -334,12 +472,49 @@ struct HfTaskCorrelationD0Hadrons { int signalStatus = pairEntry.signalStatus(); int ptBinD = o2::analysis::findBin(binsCorrelations, ptD); int poolBin = pairEntry.poolBin(); - + float trackDcaXY = pairEntry.trackDcaXY(); + float trackDcaZ = pairEntry.trackDcaZ(); + int trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); + bool isAutoCorrelated = pairEntry.isAutoCorrelated(); + float bdtScorePromptD0 = pairEntry.mlScorePromptD0(); + float bdtScoreBkgD0 = pairEntry.mlScoreBkgD0(); + float bdtScorePromptD0bar = pairEntry.mlScorePromptD0bar(); + float bdtScoreBkgD0bar = pairEntry.mlScoreBkgD0bar(); + bool isPhysicalPrimary = pairEntry.isPhysicalPrimary(); + int statusD0Prompt = static_cast(pairEntry.isPrompt()); + int statusPromptHadron = pairEntry.trackOrigin(); + + if (bdtScorePromptD0 < mlOutputPromptD0->at(ptBinD) || bdtScoreBkgD0 > mlOutputBkgD0->at(ptBinD) || + bdtScorePromptD0bar < mlOutputPromptD0bar->at(ptBinD) || bdtScoreBkgD0bar > mlOutputBkgD0bar->at(ptBinD)) { + continue; + } + if (trackDcaXY > dcaXYTrackMax || trackDcaZ > dcaZTrackMax || trackTpcCrossedRows < nTpcCrossedRaws) { + continue; + } double efficiencyWeight = 1.; if (applyEfficiency) { - efficiencyWeight = 1. / (efficiencyDmeson->at(o2::analysis::findBin(binsEfficiency, ptD))); + efficiencyWeight = 1. / (efficiencyDmeson->at(o2::analysis::findBin(binsPtEfficiencyD, ptD)) * efficiencyHad->at(o2::analysis::findBin(binsPtEfficiencyHad, ptHadron))); + } + if (isTowardTransverseAway) { + // Divide into three regions: toward, transverse, and away + if (ptHadron < leadingParticlePtMin) { + continue; + } + Region region = getRegion(deltaPhi); + switch (region) { + case Toward: + registry.fill(HIST("hTowardRec"), massD, ptD, isAutoCorrelated, efficiencyWeight); + break; + case Away: + registry.fill(HIST("hAwayRec"), massD, ptD, isAutoCorrelated, efficiencyWeight); + break; + case Transverse: + registry.fill(HIST("hTransverseRec"), massD, ptD, isAutoCorrelated, efficiencyWeight); + break; + default: + break; + } } - // fill correlation plots for signal/bagkground correlations if (pairEntry.signalStatus()) { registry.fill(HIST("hCorrel2DVsPtRecSig"), deltaPhi, deltaEta, ptD, ptHadron, efficiencyWeight); @@ -353,18 +528,34 @@ struct HfTaskCorrelationD0Hadrons { // ---------------------- Fill plots for signal case, D0 ->1, D0bar ->8 --------------------------------------------- if ((massD > signalRegionLeft->at(ptBinD) && massD < signalRegionRight->at(ptBinD)) && (TESTBIT(signalStatus, ParticleTypeMcRec::D0Sig))) { // in signal region, tests bit ParticleTypeMcRec::D0Sig, SE-> softpi removed, ME-> inclusive - registry.fill(HIST("hCorrel2DVsPtSignalRegionRecSig"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSignalRegionRecSig"), deltaPhi, deltaEta, ptD, ptHadron, statusD0Prompt, poolBin, efficiencyWeight); registry.fill(HIST("hCorrel2DPtIntSignalRegionRecSig"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSignalRegionRecSig"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSignalRegionRecSig"), deltaPhi, efficiencyWeight); + if (isPhysicalPrimary) { + registry.fill(HIST("hCorrel2DVsPtPhysicalPrimaryRecSig"), deltaPhi, deltaEta, ptD, ptHadron, statusD0Prompt, poolBin, efficiencyWeight); + if (statusD0Prompt == 1 && statusPromptHadron == 1) { + registry.fill(HIST("hCorrel2DVsPtSignalRegionPromptD0PromptHadronRecSig"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + } else if (statusD0Prompt == 0 && statusPromptHadron == 2) { + registry.fill(HIST("hCorrel2DVsPtSignalRegionNonPromptD0NonPromptHadronRecSig"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + } + } } if ((massDbar > signalRegionLeft->at(ptBinD) && massDbar < signalRegionRight->at(ptBinD)) && (TESTBIT(signalStatus, ParticleTypeMcRec::D0barSig))) { // in signal region, tests bit ParticleTypeMcRec::D0barSig, SE-> softpi removed, ME-> inclusive - registry.fill(HIST("hCorrel2DVsPtSignalRegionRecSig"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSignalRegionRecSig"), deltaPhi, deltaEta, ptD, ptHadron, statusD0Prompt, poolBin, efficiencyWeight); registry.fill(HIST("hCorrel2DPtIntSignalRegionRecSig"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSignalRegionRecSig"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSignalRegionRecSig"), deltaPhi, efficiencyWeight); + if (isPhysicalPrimary) { + registry.fill(HIST("hCorrel2DVsPtPhysicalPrimaryRecSig"), deltaPhi, deltaEta, ptD, ptHadron, statusD0Prompt, poolBin, efficiencyWeight); + if (statusD0Prompt == 1 && statusPromptHadron == 1) { + registry.fill(HIST("hCorrel2DVsPtSignalRegionPromptD0PromptHadronRecSig"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + } else if (statusD0Prompt == 0 && statusPromptHadron == 2) { + registry.fill(HIST("hCorrel2DVsPtSignalRegionNonPromptD0NonPromptHadronRecSig"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + } + } } if ((massDbar > signalRegionLeft->at(ptBinD) && massDbar < signalRegionRight->at(ptBinD)) && (signalStatus >= static_cast(BIT(ParticleTypeMcRec::SoftPi)))) { @@ -519,7 +710,7 @@ struct HfTaskCorrelationD0Hadrons { PROCESS_SWITCH(HfTaskCorrelationD0Hadrons, processMcRec, "Process MC Reco mode", true); /// D-Hadron correlation pair filling task, from pair tables - for MC gen-level analysis (no filter/selection, only true signal) - void processMcGen(aod::DHadronPairFull const& pairEntries) + void processMcGen(D0HadronPairFull const& pairEntries) { for (const auto& pairEntry : pairEntries) { // define variables for widely used quantities @@ -528,21 +719,137 @@ struct HfTaskCorrelationD0Hadrons { double ptD = pairEntry.ptD(); double ptHadron = pairEntry.ptHadron(); int poolBin = pairEntry.poolBin(); + double massD = pairEntry.mD(); + bool isAutoCorrelated = pairEntry.isAutoCorrelated(); + int statusPromptHadron = pairEntry.trackOrigin(); + bool isD0Prompt = pairEntry.isPrompt(); + // reject entries outside pT ranges of interest if (o2::analysis::findBin(binsCorrelations, ptD) < 0) { continue; } - if (ptHadron > ptHadronMax) { - ptHadron = ptHadronMax + 0.5; + if (isTowardTransverseAway) { + // Divide into three regions: toward, transverse, and away + if (ptHadron < leadingParticlePtMin) { + continue; + } + Region region = getRegion(deltaPhi); + switch (region) { + case Toward: + registry.fill(HIST("hTowardGen"), massD, ptD, isAutoCorrelated); + break; + case Away: + registry.fill(HIST("hAwayGen"), massD, ptD, isAutoCorrelated); + break; + case Transverse: + registry.fill(HIST("hTransverseGen"), massD, ptD, isAutoCorrelated); + break; + default: + break; + } + } + if (isD0Prompt) { + registry.fill(HIST("hCorrel2DVsPtGenPrompt"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + if (statusPromptHadron == 1) { + registry.fill(HIST("hCorrel2DVsPtGenPromptD0PromptHadron"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + } + } else { + registry.fill(HIST("hCorrel2DVsPtGenNonPrompt"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + if (statusPromptHadron == 2) { + registry.fill(HIST("hCorrel2DVsPtGenNonPromptD0NonPromptHadron"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + } } - - registry.fill(HIST("hCorrel2DVsPtGen"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); registry.fill(HIST("hCorrel2DPtIntGen"), deltaPhi, deltaEta); registry.fill(HIST("hDeltaEtaPtIntGen"), deltaEta); registry.fill(HIST("hDeltaPhiPtIntGen"), deltaPhi); } // end loop } PROCESS_SWITCH(HfTaskCorrelationD0Hadrons, processMcGen, "Process MC Gen mode", false); + + /// D0 reconstruction and selection efficiency + void processMcCandEfficiency(soa::Join const&, + soa::Join const&, + CandD0McGen const& mcParticles, + CandD0McReco const& candidates, + aod::TracksWMc const&) + { + auto hCandidates = registry.get(HIST("hCandidates")); + + /// Gen loop + float multiplicity = -1.; + for (const auto& mcParticle : mcParticles) { + // generated candidates + if (std::abs(mcParticle.pdgCode()) != Pdg::kD0) { + auto mcCollision = mcParticle.template mcCollision_as>(); + multiplicity = mcCollision.multMCFT0A() + mcCollision.multMCFT0C(); // multFT0M = multFt0A + multFT0C + hCandidates->Fill(kCandidateStepMcGenAll, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); + if (std::abs(mcParticle.flagMcMatchGen()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { + hCandidates->Fill(kCandidateStepMcGenD0ToPiKPi, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); + auto yD0 = RecoDecay::y(mcParticle.pVector(), o2::constants::physics::MassD0); + if (std::abs(yD0) <= yCandGenMax) { + hCandidates->Fill(kCandidateStepMcCandInAcceptance, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); + if (mcParticle.originMcGen() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hPtCandMcGenPrompt"), mcParticle.pt()); + } + if (mcParticle.originMcGen() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("hPtCandMcGenNonPrompt"), mcParticle.pt()); + } + } + bool isDaughterInAcceptance = true; + auto daughters = mcParticle.template daughters_as(); + for (const auto& daughter : daughters) { + if (daughter.pt() < ptDaughterMin || std::abs(daughter.eta()) > etaTrackMax) { + isDaughterInAcceptance = false; + } + } + if (isDaughterInAcceptance) { + hCandidates->Fill(kCandidateStepMcDaughtersInAcceptance, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); + registry.fill(HIST("hPtCandMcGenDaughterInAcc"), mcParticle.pt()); + } + } + } + } + + // recontructed candidates loop + for (const auto& candidate : candidates) { + if (candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { + continue; + } + std::vector outputMlD0 = {-1., -1., -1.}; + std::vector outputMlD0bar = {-1., -1., -1.}; + if (candidate.isSelD0() < selectionFlagD0 || candidate.isSelD0bar() < selectionFlagD0) { + continue; + } + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMlD0[iclass] = candidate.mlProbD0()[classMl->at(iclass)]; + outputMlD0bar[iclass] = candidate.mlProbD0bar()[classMl->at(iclass)]; + } + if (outputMlD0[0] > mlOutputBkgD0->at(o2::analysis::findBin(binsPtEfficiencyD, candidate.pt())) || outputMlD0[1] < mlOutputPromptD0->at(o2::analysis::findBin(binsPtEfficiencyD, candidate.pt()))) { + continue; + } + if (outputMlD0bar[0] > mlOutputBkgD0bar->at(o2::analysis::findBin(binsPtEfficiencyD, candidate.pt())) || outputMlD0bar[1] < mlOutputPromptD0bar->at(o2::analysis::findBin(binsPtEfficiencyD, candidate.pt()))) { + continue; + } + auto collision = candidate.template collision_as>(); + if (selNoSameBunchPileUpColl && !(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { + continue; + } + multiplicity = collision.multFT0M(); + if (std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { + hCandidates->Fill(kCandidateStepMcReco, candidate.pt(), multiplicity, candidate.originMcRec()); + if (std::abs(hfHelper.yD0(candidate)) <= yCandMax) { + hCandidates->Fill(kCandidateStepMcRecoInAcceptance, candidate.pt(), multiplicity, candidate.originMcRec()); + if (candidate.originMcRec() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hPtCandMcRecPrompt"), candidate.pt()); + } + if (candidate.originMcRec() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("hPtCandMcRecNonPrompt"), candidate.pt()); + } + } + } + } + } + PROCESS_SWITCH(HfTaskCorrelationD0Hadrons, processMcCandEfficiency, "Process MC for calculating candidate reconstruction efficiency", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/HFC/Tasks/taskCorrelationDDbar.cxx b/PWGHF/HFC/Tasks/taskCorrelationDDbar.cxx index 3172d8e6e22..b45ce1b4a63 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationDDbar.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationDDbar.cxx @@ -14,6 +14,8 @@ /// /// \author Fabio Colamaria , INFN Bari +#include + #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" @@ -61,7 +63,7 @@ const TString stringSideband = "sidebands;"; const TString stringMCParticles = "MC gen - D,Dbar particles;"; const TString stringMCReco = "MC reco - D,Dbar candidates "; -//definition of vectors for standard ptbin and invariant mass configurables +// definition of vectors for standard ptbin and invariant mass configurables const int npTBinsCorrelations = 8; const double pTBinsCorrelations[npTBinsCorrelations + 1] = {0., 2., 4., 6., 8., 12., 16., 24., 99.}; auto pTBinsCorrelations_v = std::vector{pTBinsCorrelations, pTBinsCorrelations + npTBinsCorrelations + 1}; @@ -77,7 +79,7 @@ auto sidebandLeftInner_v = std::vector{sidebandLeftInnerDefault, sideban auto sidebandLeftOuter_v = std::vector{sidebandLeftOuterDefault, sidebandLeftOuterDefault + npTBinsCorrelations}; auto sidebandRightInner_v = std::vector{sidebandRightInnerDefault, sidebandRightInnerDefault + npTBinsCorrelations}; auto sidebandRightOuter_v = std::vector{sidebandRightOuterDefault, sidebandRightOuterDefault + npTBinsCorrelations}; -const int npTBinsEfficiency = o2::analysis::hf_cuts_d0_to_pi_k::nBinsPt; +const int npTBinsEfficiency = o2::analysis::hf_cuts_d0_to_pi_k::NBinsPt; const double efficiencyDmesonDefault[npTBinsEfficiency] = {}; auto efficiencyDmeson_v = std::vector{efficiencyDmesonDefault, efficiencyDmesonDefault + npTBinsEfficiency}; @@ -233,7 +235,7 @@ struct HfTaskCorrelationDDbar { void processData(aod::DDbarPairFull const& pairEntries) { for (const auto& pairEntry : pairEntries) { - //define variables for widely used quantities + // define variables for widely used quantities double deltaPhi = pairEntry.deltaPhi(); double deltaEta = pairEntry.deltaEta(); double ptD = pairEntry.ptD(); @@ -249,17 +251,17 @@ struct HfTaskCorrelationDDbar { efficiencyWeight = 1. / (efficiencyD->at(o2::analysis::findBin(binsPtEfficiency, ptD)) * efficiencyD->at(o2::analysis::findBin(binsPtEfficiency, ptDbar))); } - //fill 2D invariant mass plots + // fill 2D invariant mass plots registry.fill(HIST("hMass2DCorrelationPairs"), massD, massDbar, ptD, ptDbar, efficiencyWeight); - //reject entries outside pT ranges of interest - if (pTBinD == -1 || pTBinDbar == -1) { //at least one particle outside accepted pT range + // reject entries outside pT ranges of interest + if (pTBinD == -1 || pTBinDbar == -1) { // at least one particle outside accepted pT range continue; } - //check if correlation entry belongs to signal region, sidebands or is outside both, and fill correlation plots + // check if correlation entry belongs to signal region, sidebands or is outside both, and fill correlation plots if (massD > signalRegionInner->at(pTBinD) && massD < signalRegionOuter->at(pTBinD) && massDbar > signalRegionInner->at(pTBinDbar) && massDbar < signalRegionOuter->at(pTBinDbar)) { - //in signal region + // in signal region registry.fill(HIST("hCorrel2DVsPtSignalRegion"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); registry.fill(HIST("hCorrel2DPtIntSignalRegion"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSignalRegion"), deltaEta, efficiencyWeight); @@ -272,7 +274,7 @@ struct HfTaskCorrelationDDbar { (massD > sidebandRightInner->at(pTBinD) && massD < sidebandRightOuter->at(pTBinD) && massDbar > sidebandLeftInner->at(pTBinDbar) && massDbar < sidebandRightOuter->at(pTBinDbar)) || (massD > sidebandLeftInner->at(pTBinD) && massD < sidebandRightOuter->at(pTBinD) && massDbar > sidebandLeftInner->at(pTBinDbar) && massDbar < sidebandLeftOuter->at(pTBinDbar)) || (massD > sidebandLeftInner->at(pTBinD) && massD < sidebandRightOuter->at(pTBinD) && massDbar > sidebandRightInner->at(pTBinDbar) && massDbar < sidebandRightOuter->at(pTBinDbar))) { - //in sideband region + // in sideband region registry.fill(HIST("hCorrel2DVsPtSidebands"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); registry.fill(HIST("hCorrel2DPtIntSidebands"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSidebands"), deltaEta, efficiencyWeight); @@ -290,7 +292,7 @@ struct HfTaskCorrelationDDbar { void processMcRec(aod::DDbarPairFull const& pairEntries) { for (const auto& pairEntry : pairEntries) { - //define variables for widely used quantities + // define variables for widely used quantities double deltaPhi = pairEntry.deltaPhi(); double deltaEta = pairEntry.deltaEta(); double ptD = pairEntry.ptD(); @@ -306,81 +308,81 @@ struct HfTaskCorrelationDDbar { efficiencyWeight = 1. / (efficiencyD->at(o2::analysis::findBin(binsPtEfficiency, ptD)) * efficiencyD->at(o2::analysis::findBin(binsPtEfficiency, ptDbar))); } - //fill 2D invariant mass plots + // fill 2D invariant mass plots switch (pairEntry.signalStatus()) { - case 0: //D Bkg, Dbar Bkg + case 0: // D Bkg, Dbar Bkg registry.fill(HIST("hMass2DCorrelationPairsMCRecBkgBkg"), massD, massDbar, ptD, ptDbar, efficiencyWeight); break; - case 1: //D Bkg, Dbar Ref + case 1: // D Bkg, Dbar Ref registry.fill(HIST("hMass2DCorrelationPairsMCRecBkgRef"), massD, massDbar, ptD, ptDbar, efficiencyWeight); break; - case 2: //D Bkg, Dbar Sig + case 2: // D Bkg, Dbar Sig registry.fill(HIST("hMass2DCorrelationPairsMCRecBkgSig"), massD, massDbar, ptD, ptDbar, efficiencyWeight); break; - case 3: //D Ref, Dbar Bkg + case 3: // D Ref, Dbar Bkg registry.fill(HIST("hMass2DCorrelationPairsMCRecRefBkg"), massD, massDbar, ptD, ptDbar, efficiencyWeight); break; - case 4: //D Ref, Dbar Ref + case 4: // D Ref, Dbar Ref registry.fill(HIST("hMass2DCorrelationPairsMCRecRefRef"), massD, massDbar, ptD, ptDbar, efficiencyWeight); break; - case 5: //D Ref, Dbar Sig + case 5: // D Ref, Dbar Sig registry.fill(HIST("hMass2DCorrelationPairsMCRecRefSig"), massD, massDbar, ptD, ptDbar, efficiencyWeight); break; - case 6: //D Sig, Dbar Bkg + case 6: // D Sig, Dbar Bkg registry.fill(HIST("hMass2DCorrelationPairsMCRecSigBkg"), massD, massDbar, ptD, ptDbar, efficiencyWeight); break; - case 7: //D Sig, Dbar Ref + case 7: // D Sig, Dbar Ref registry.fill(HIST("hMass2DCorrelationPairsMCRecSigRef"), massD, massDbar, ptD, ptDbar, efficiencyWeight); break; - case 8: //D Sig, Dbar Sig + case 8: // D Sig, Dbar Sig registry.fill(HIST("hMass2DCorrelationPairsMCRecSigSig"), massD, massDbar, ptD, ptDbar, efficiencyWeight); break; - default: //should not happen for MC reco + default: // should not happen for MC reco break; } - //reject entries outside pT ranges of interest - if (pTBinD == -1 || pTBinDbar == -1) { //at least one particle outside accepted pT range + // reject entries outside pT ranges of interest + if (pTBinD == -1 || pTBinDbar == -1) { // at least one particle outside accepted pT range continue; } - //check if correlation entry belongs to signal region, sidebands or is outside both, and fill correlation plots + // check if correlation entry belongs to signal region, sidebands or is outside both, and fill correlation plots if (massD > signalRegionInner->at(pTBinD) && massD < signalRegionOuter->at(pTBinD) && massDbar > signalRegionInner->at(pTBinDbar) && massDbar < signalRegionOuter->at(pTBinDbar)) { - //in signal region + // in signal region registry.fill(HIST("hCorrel2DPtIntSignalRegionMCRec"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSignalRegionMCRec"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSignalRegionMCRec"), deltaPhi, efficiencyWeight); registry.fill(HIST("hDeltaPtDDbarSignalRegionMCRec"), ptDbar - ptD, efficiencyWeight); registry.fill(HIST("hDeltaPtMaxMinSignalRegionMCRec"), std::abs(ptDbar - ptD), efficiencyWeight); switch (pairEntry.signalStatus()) { - case 0: //D Bkg, Dbar Bkg + case 0: // D Bkg, Dbar Bkg registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecBkgBkg"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - case 1: //D Bkg, Dbar Ref + case 1: // D Bkg, Dbar Ref registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecBkgRef"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - case 2: //D Bkg, Dbar Sig + case 2: // D Bkg, Dbar Sig registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecBkgSig"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - case 3: //D Ref, Dbar Bkg + case 3: // D Ref, Dbar Bkg registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecRefBkg"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - case 4: //D Ref, Dbar Ref + case 4: // D Ref, Dbar Ref registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecRefRef"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - case 5: //D Ref, Dbar Sig + case 5: // D Ref, Dbar Sig registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecRefSig"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - case 6: //D Sig, Dbar Bkg + case 6: // D Sig, Dbar Bkg registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecSigBkg"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - case 7: //D Sig, Dbar Ref + case 7: // D Sig, Dbar Ref registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecSigRef"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - case 8: //D Sig, Dbar Sig + case 8: // D Sig, Dbar Sig registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecSigSig"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - default: //should not happen for MC reco + default: // should not happen for MC reco break; } } @@ -389,41 +391,41 @@ struct HfTaskCorrelationDDbar { (massD > sidebandRightInner->at(pTBinD) && massD < sidebandRightOuter->at(pTBinD) && massDbar > sidebandLeftInner->at(pTBinDbar) && massDbar < sidebandRightOuter->at(pTBinDbar)) || (massD > sidebandLeftInner->at(pTBinD) && massD < sidebandRightOuter->at(pTBinD) && massDbar > sidebandLeftInner->at(pTBinDbar) && massDbar < sidebandLeftOuter->at(pTBinDbar)) || (massD > sidebandLeftInner->at(pTBinD) && massD < sidebandRightOuter->at(pTBinD) && massDbar > sidebandRightInner->at(pTBinDbar) && massDbar < sidebandRightOuter->at(pTBinDbar))) { - //in sideband region + // in sideband region registry.fill(HIST("hCorrel2DPtIntSidebandsMCRec"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSidebandsMCRec"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSidebandsMCRec"), deltaPhi, efficiencyWeight); registry.fill(HIST("hDeltaPtDDbarSidebandsMCRec"), ptDbar - ptD, efficiencyWeight); registry.fill(HIST("hDeltaPtMaxMinSidebandsMCRec"), std::abs(ptDbar - ptD), efficiencyWeight); switch (pairEntry.signalStatus()) { - case 0: //D Bkg, Dbar Bkg + case 0: // D Bkg, Dbar Bkg registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecBkgBkg"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - case 1: //D Bkg, Dbar Ref + case 1: // D Bkg, Dbar Ref registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecBkgRef"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - case 2: //D Bkg, Dbar Sig + case 2: // D Bkg, Dbar Sig registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecBkgSig"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - case 3: //D Ref, Dbar Bkg + case 3: // D Ref, Dbar Bkg registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecRefBkg"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - case 4: //D Ref, Dbar Ref + case 4: // D Ref, Dbar Ref registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecRefRef"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - case 5: //D Ref, Dbar Sig + case 5: // D Ref, Dbar Sig registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecRefSig"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - case 6: //D Sig, Dbar Bkg + case 6: // D Sig, Dbar Bkg registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecSigBkg"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - case 7: //D Sig, Dbar Ref + case 7: // D Sig, Dbar Ref registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecSigRef"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - case 8: //D Sig, Dbar Sig + case 8: // D Sig, Dbar Sig registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecSigSig"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); break; - default: //should not happen for MC reco + default: // should not happen for MC reco break; } } @@ -437,13 +439,13 @@ struct HfTaskCorrelationDDbar { void processMcGen(aod::DDbarPair const& pairEntries) { for (const auto& pairEntry : pairEntries) { - //define variables for widely used quantities + // define variables for widely used quantities double deltaPhi = pairEntry.deltaPhi(); double deltaEta = pairEntry.deltaEta(); double ptD = pairEntry.ptD(); double ptDbar = pairEntry.ptDbar(); - //reject entries outside pT ranges of interest + // reject entries outside pT ranges of interest if (o2::analysis::findBin(binsPtCorrelations, ptD) == -1 || o2::analysis::findBin(binsPtCorrelations, ptDbar) == -1) { continue; } diff --git a/PWGHF/HFC/Tasks/taskCorrelationDMesonPairs.cxx b/PWGHF/HFC/Tasks/taskCorrelationDMesonPairs.cxx index 799de44bc60..41a1f77836f 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationDMesonPairs.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationDMesonPairs.cxx @@ -51,60 +51,37 @@ enum D0Type { }; } // namespace -// string definitions, used for histogram axis labels -const char stringCorrelationPairs[193] = "D meson pair candidates 2D;inv. mass D_{1} (GeV/#it{c}^{2});inv. mass D_{2} (GeV/#it{c}^{2});#it{p}_{T}^{D_{1}} (GeV/#it{c});#it{p}_{T}^{D_{2}} (GeV/#it{c});#eta D_{1};#eta D_{2};type1;type2;"; -const char stringCorrelationPairsFinerBinning[207] = "D meson pair candidates 2D Finer Binning;inv. mass D_{1} (GeV/#it{c}^{2});inv. mass D_{2} (GeV/#it{c}^{2});#it{p}_{T}^{D_{1}} (GeV/#it{c});#it{p}_{T}^{D_{2}} (GeV/#it{c});#eta D_{1};#eta D_{2};type1;type2;"; - -// definition of vectors for standard ptbin and invariant mass configurables -const int nPtBinsCorrelations = 8; -const double ptBinsCorrelations[nPtBinsCorrelations + 1] = {0., 2., 4., 6., 8., 12., 16., 24., 99.}; -auto vecPtBinsCorrelations = std::vector{ptBinsCorrelations, ptBinsCorrelations + nPtBinsCorrelations + 1}; - struct HfTaskCorrelationDMesonPairs { - // Enable histograms with finer pT and y binning - Configurable enableFinerBinning{"enableFinerBinning", false, "Enable histograms with finer pT and y binning"}; - Configurable> binsPtCorrelations{"binsPtCorrelations", std::vector{vecPtBinsCorrelations}, "pT bin limits for correlation plots"}; - - // HistoTypes - HistogramConfigSpec hTHnMass2DCorrPairs{HistType::kTHnSparseD, {{200, 1.6, 2.1}, {200, 1.6, 2.1}, {10, 0., 10.}, {10, 0., 10.}, {10, -1, 1}, {10, -1, 1}, {4, -0.5, 3.5}, {4, -0.5, 3.5}}}; // note: axes 3 and 4 (the pT) are updated in the init(); - HistogramConfigSpec hTHnMass2DCorrPairsFinerBinning{HistType::kTHnSparseD, {{200, 1.6, 2.1}, {200, 1.6, 2.1}, {60, 1., 6.}, {60, 1., 6.}, {160, -0.8, 0.8}, {160, -0.8, 0.8}, {4, -0.5, 3.5}, {4, -0.5, 3.5}}}; + // Configurables to set sparse axes + ConfigurableAxis thnConfigAxisInvMass{"thnConfigAxisInvMass", {200, 1.6, 2.1}, "Inv-mass bins"}; + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {25, 0., 24.}, "pT bins"}; + ConfigurableAxis thnConfigAxisY{"thnConfigAxisY", {10, -1, 1}, "Rapidity bins"}; + ConfigurableAxis thnConfigAxisCandType{"thnConfigAxisCandType", {4, -0.5, 3.5}, "Candidate Type"}; HistogramRegistry registry{ "registry", - {{"hMass2DCorrelationPairsLS", stringCorrelationPairs, hTHnMass2DCorrPairs}, - {"hMass2DCorrelationPairsOS", stringCorrelationPairs, hTHnMass2DCorrPairs}, - {"hMass2DCorrelationPairsLSMcGen", stringCorrelationPairs, hTHnMass2DCorrPairs}, - {"hMass2DCorrelationPairsOSMcGen", stringCorrelationPairs, hTHnMass2DCorrPairs}}}; + {}}; void init(InitContext&) { - // redefinition of pT axes for THnSparse holding correlation entries - int nBinspTaxis = binsPtCorrelations->size() - 1; - const double* valuespTaxis = binsPtCorrelations->data(); - - if (enableFinerBinning) { - registry.add("hMass2DCorrelationPairsLSFinerBinning", stringCorrelationPairsFinerBinning, hTHnMass2DCorrPairsFinerBinning); - registry.get(HIST("hMass2DCorrelationPairsLSFinerBinning"))->Sumw2(); - registry.add("hMass2DCorrelationPairsOSFinerBinning", stringCorrelationPairsFinerBinning, hTHnMass2DCorrPairsFinerBinning); - registry.get(HIST("hMass2DCorrelationPairsOSFinerBinning"))->Sumw2(); - - registry.add("hMass2DCorrelationPairsLSMcGenFinerBinning", stringCorrelationPairsFinerBinning, hTHnMass2DCorrPairsFinerBinning); - registry.get(HIST("hMass2DCorrelationPairsLSMcGenFinerBinning"))->Sumw2(); - registry.add("hMass2DCorrelationPairsOSMcGenFinerBinning", stringCorrelationPairsFinerBinning, hTHnMass2DCorrPairsFinerBinning); - registry.get(HIST("hMass2DCorrelationPairsOSMcGenFinerBinning"))->Sumw2(); - } - - for (int i = 2; i <= 3; i++) { - registry.get(HIST("hMass2DCorrelationPairsLS"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); - registry.get(HIST("hMass2DCorrelationPairsLS"))->Sumw2(); - registry.get(HIST("hMass2DCorrelationPairsOS"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); - registry.get(HIST("hMass2DCorrelationPairsOS"))->Sumw2(); - - registry.get(HIST("hMass2DCorrelationPairsLSMcGen"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); - registry.get(HIST("hMass2DCorrelationPairsLSMcGen"))->Sumw2(); - registry.get(HIST("hMass2DCorrelationPairsOSMcGen"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); - registry.get(HIST("hMass2DCorrelationPairsOSMcGen"))->Sumw2(); - } + const AxisSpec thnAxisInvMassCand1{thnConfigAxisInvMass, "inv. mass D_{1} (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisInvMassCand2{thnConfigAxisInvMass, "inv. mass D_{2} (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisPtCand1{thnConfigAxisPt, "#it{p}_{T}^{D_{1}} (GeV/#it{c})"}; + const AxisSpec thnAxisPtCand2{thnConfigAxisPt, "#it{p}_{T}^{D_{2}} (GeV/#it{c})"}; + const AxisSpec thnAxisYCand1{thnConfigAxisY, "#it{y} D_{1}"}; + const AxisSpec thnAxisYCand2{thnConfigAxisY, "#it{y} D_{2}"}; + const AxisSpec thnAxisCandType1{thnConfigAxisCandType, "Type D_{1}"}; + const AxisSpec thnAxisCandType2{thnConfigAxisCandType, "Type D_{2}"}; + + registry.add("hMass2DCorrelationPairsLS", "hMass2DCorrelationPairsLS", HistType::kTHnSparseD, {thnAxisInvMassCand1, thnAxisInvMassCand2, thnAxisPtCand1, thnAxisPtCand2, thnAxisYCand1, thnAxisYCand2, thnAxisCandType1, thnAxisCandType2}); + registry.get(HIST("hMass2DCorrelationPairsLS"))->Sumw2(); + registry.add("hMass2DCorrelationPairsOS", "hMass2DCorrelationPairsOS", HistType::kTHnSparseD, {thnAxisInvMassCand1, thnAxisInvMassCand2, thnAxisPtCand1, thnAxisPtCand2, thnAxisYCand1, thnAxisYCand2, thnAxisCandType1, thnAxisCandType2}); + registry.get(HIST("hMass2DCorrelationPairsOS"))->Sumw2(); + + registry.add("hMass2DCorrelationPairsLSMcGen", "hMass2DCorrelationPairsLSMcGen", HistType::kTHnSparseD, {thnAxisInvMassCand1, thnAxisInvMassCand2, thnAxisPtCand1, thnAxisPtCand2, thnAxisYCand1, thnAxisYCand2, thnAxisCandType1, thnAxisCandType2}); + registry.get(HIST("hMass2DCorrelationPairsLSMcGen"))->Sumw2(); + registry.add("hMass2DCorrelationPairsOSMcGen", "hMass2DCorrelationPairsOSMcGen", HistType::kTHnSparseD, {thnAxisInvMassCand1, thnAxisInvMassCand2, thnAxisPtCand1, thnAxisPtCand2, thnAxisYCand1, thnAxisYCand2, thnAxisCandType1, thnAxisCandType2}); + registry.get(HIST("hMass2DCorrelationPairsOSMcGen"))->Sumw2(); } uint getD0Type(uint const& candidateType) @@ -139,28 +116,16 @@ struct HfTaskCorrelationDMesonPairs { if (TESTBIT(pairType, DD)) { registry.fill(HIST("hMass2DCorrelationPairsLS"), massDCand1, massDCand2, ptCand1, ptCand2, yCand1, yCand2, d0Type1, d0Type2); - if (enableFinerBinning) { - registry.fill(HIST("hMass2DCorrelationPairsLSFinerBinning"), massDCand1, massDCand2, ptCand1, ptCand2, yCand1, yCand2, d0Type1, d0Type2); - } } if (TESTBIT(pairType, DbarDbar)) { registry.fill(HIST("hMass2DCorrelationPairsLS"), massDbarCand1, massDbarCand2, ptCand1, ptCand2, yCand1, yCand2, d0Type1, d0Type2); - if (enableFinerBinning) { - registry.fill(HIST("hMass2DCorrelationPairsLSFinerBinning"), massDbarCand1, massDbarCand2, ptCand1, ptCand2, yCand1, yCand2, d0Type1, d0Type2); - } } if (TESTBIT(pairType, DDbar)) { registry.fill(HIST("hMass2DCorrelationPairsOS"), massDCand1, massDbarCand2, ptCand1, ptCand2, yCand1, yCand2, d0Type1, d0Type2); - if (enableFinerBinning) { - registry.fill(HIST("hMass2DCorrelationPairsOSFinerBinning"), massDCand1, massDbarCand2, ptCand1, ptCand2, yCand1, yCand2, d0Type1, d0Type2); - } } if (TESTBIT(pairType, DbarD)) { registry.fill(HIST("hMass2DCorrelationPairsOS"), massDbarCand1, massDCand2, ptCand1, ptCand2, yCand1, yCand2, d0Type1, d0Type2); - if (enableFinerBinning) { - registry.fill(HIST("hMass2DCorrelationPairsOSFinerBinning"), massDbarCand1, massDCand2, ptCand1, ptCand2, yCand1, yCand2, d0Type1, d0Type2); - } } } } @@ -184,27 +149,15 @@ struct HfTaskCorrelationDMesonPairs { if (TESTBIT(pairType, DD)) { registry.fill(HIST("hMass2DCorrelationPairsLSMcGen"), massDParticle1, massDParticle2, ptParticle1, ptParticle2, yParticle1, yParticle2, d0Type1, d0Type2); - if (enableFinerBinning) { - registry.fill(HIST("hMass2DCorrelationPairsLSMcGenFinerBinning"), massDParticle1, massDParticle2, ptParticle1, ptParticle2, yParticle1, yParticle2, d0Type1, d0Type2); - } } if (TESTBIT(pairType, DbarDbar)) { registry.fill(HIST("hMass2DCorrelationPairsLSMcGen"), massDbarParticle1, massDbarParticle2, ptParticle1, ptParticle2, yParticle1, yParticle2, d0Type1, d0Type2); - if (enableFinerBinning) { - registry.fill(HIST("hMass2DCorrelationPairsLSMcGenFinerBinning"), massDbarParticle1, massDbarParticle2, ptParticle1, ptParticle2, yParticle1, yParticle2, d0Type1, d0Type2); - } } if (TESTBIT(pairType, DDbar)) { registry.fill(HIST("hMass2DCorrelationPairsOSMcGen"), massDParticle1, massDbarParticle2, ptParticle1, ptParticle2, yParticle1, yParticle2, d0Type1, d0Type2); - if (enableFinerBinning) { - registry.fill(HIST("hMass2DCorrelationPairsOSMcGenFinerBinning"), massDParticle1, massDbarParticle2, ptParticle1, ptParticle2, yParticle1, yParticle2, d0Type1, d0Type2); - } } if (TESTBIT(pairType, DbarD)) { registry.fill(HIST("hMass2DCorrelationPairsOSMcGen"), massDbarParticle1, massDParticle2, ptParticle1, ptParticle2, yParticle1, yParticle2, d0Type1, d0Type2); - if (enableFinerBinning) { - registry.fill(HIST("hMass2DCorrelationPairsOSMcGenFinerBinning"), massDbarParticle1, massDParticle2, ptParticle1, ptParticle2, yParticle1, yParticle2, d0Type1, d0Type2); - } } } } diff --git a/PWGHF/HFC/Tasks/taskCorrelationDplusHadrons.cxx b/PWGHF/HFC/Tasks/taskCorrelationDplusHadrons.cxx index 2d76eb36913..8ccda0a3b71 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationDplusHadrons.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationDplusHadrons.cxx @@ -11,41 +11,26 @@ /// \file taskCorrelationDplusHadrons.cxx /// \author Shyam Kumar - +#include // std::shared_ptr +#include +#include +#include "CCDB/BasicCCDBManager.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" +#include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/Utils/utilsAnalysis.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" using namespace o2; +using namespace o2::constants::math; +using namespace o2::constants::physics; using namespace o2::framework; using namespace o2::framework::expressions; -namespace o2::aod -{ -using DplusHadronPairFull = soa::Join; -} // namespace o2::aod - -/// -/// Returns deltaPhi value in range [-pi/2., 3.*pi/2], typically used for correlation studies -/// -double getDeltaPhi(double phiD, double phiHadron) -{ - return RecoDecay::constrainAngle(phiHadron - phiD, -o2::constants::math::PIHalf); -} - -/// -/// Returns phi of candidate/particle evaluated from x and y components of segment connecting primary and secondary vertices -/// -double evaluatePhiByVertex(double xVertex1, double xVertex2, double yVertex1, double yVertex2) -{ - return RecoDecay::phi(xVertex2 - xVertex1, yVertex2 - yVertex1); -} - // string definitions, used for histogram axis labels const TString stringPtD = "#it{p}_{T}^{D} (GeV/#it{c});"; const TString stringPtHadron = "#it{p}_{T}^{Hadron} (GeV/#it{c});"; @@ -56,6 +41,10 @@ const TString stringSignal = "signal region;"; const TString stringSideband = "sidebands;"; const TString stringMCParticles = "MC gen - D,Hadron particles;"; const TString stringMCReco = "MC reco - D,Hadron candidates "; +const TString stringMCRecoDPrompt = "MC reco, prompt D+;"; +const TString stringMCGenDPrompt = "MC gen, prompt D+;"; +const TString stringMCRecoDFd = "MC reco, non-prompt D+;"; +const TString stringMCGenDFd = "MC gen, non-prompt D+;"; const int npTBinsCorrelations = 8; const double pTBinsCorrelations[npTBinsCorrelations + 1] = {0., 2., 4., 6., 8., 12., 16., 24., 99.}; @@ -72,15 +61,30 @@ auto sidebandLeftInner_v = std::vector{sidebandLeftInnerDefault, sideban auto sidebandLeftOuter_v = std::vector{sidebandLeftOuterDefault, sidebandLeftOuterDefault + npTBinsCorrelations}; auto sidebandRightInner_v = std::vector{sidebandRightInnerDefault, sidebandRightInnerDefault + npTBinsCorrelations}; auto sidebandRightOuter_v = std::vector{sidebandRightOuterDefault, sidebandRightOuterDefault + npTBinsCorrelations}; -const int npTBinsEfficiency = o2::analysis::hf_cuts_dplus_to_pi_k_pi::nBinsPt; +const int npTBinsEfficiency = o2::analysis::hf_cuts_dplus_to_pi_k_pi::NBinsPt; std::vector efficiencyDmeson(npTBinsEfficiency + 1); /// Dplus-Hadron correlation pair filling task, from pair tables - for real data and data-like analysis (i.e. reco-level w/o matching request via MC truth) struct HfTaskCorrelationDplusHadrons { + Configurable fillHistoData{"fillHistoData", true, "Flag for filling histograms in data processes"}; + Configurable fillHistoMcRec{"fillHistoMcRec", true, "Flag for filling histograms in MC Rec processes"}; + Configurable fillHistoMcGen{"fillHistoMcGen", true, "Flag for filling histograms in MC Gen processes"}; + Configurable fillHistoMcEff{"fillHistoMcEff", true, "Flag for filling histograms in efficiency processes"}; Configurable applyEfficiency{"applyEfficiency", 1, "Flag for applying efficiency weights"}; + Configurable loadAccXEffFromCCDB{"loadAccXEffFromCCDB", false, "Flag for loading efficiency distributions from CCDB"}; + Configurable selectionFlagDplus{"selectionFlagDplus", 7, "Selection Flag for D+"}; // 7 corresponds to topo+PID cuts + Configurable selNoSameBunchPileUpColl{"selNoSameBunchPileUpColl", true, "Flag for rejecting the collisions associated with the same bunch crossing"}; + Configurable> classMl{"classMl", {0, 1, 2}, "Indexes of ML scores to be stored. Three indexes max."}; + Configurable> mlOutputPrompt{"mlScorePrompt", {0.5, 0.5, 0.5, 0.5}, "Machine learning scores for prompt"}; + Configurable> mlOutputBkg{"mlScoreBkg", {0.5, 0.5, 0.5, 0.5}, "Machine learning scores for bkg"}; // pT ranges for correlation plots: the default values are those embedded in hf_cuts_dplus_to_pi_k_pi (i.e. the mass pT bins), but can be redefined via json files Configurable> binsPtCorrelations{"binsPtCorrelations", std::vector{pTBinsCorrelations_v}, "pT bin limits for correlation plots"}; - Configurable> binsPtEfficiency{"binsPtEfficiency", std::vector{o2::analysis::hf_cuts_dplus_to_pi_k_pi::vecBinsPt}, "pT bin limits for efficiency"}; + Configurable> binsPtHadron{"binsPtHadron", std::vector{0.3, 2., 4., 8., 12., 50.}, "pT bin limits for assoc particle efficiency"}; + Configurable> binsPtEfficiencyD{"binsPtEfficiencyD", std::vector{o2::analysis::hf_cuts_dplus_to_pi_k_pi::vecBinsPt}, "pT bin limits for efficiency"}; + Configurable> binsPtEfficiencyHad{"binsPtEfficiencyHad", std::vector{0.3, 2., 4., 8., 12., 50.}, "pT bin limits for associated particle efficiency"}; + Configurable> efficiencyD{"efficiencyD", {1., 1., 1., 1., 1., 1.}, "efficiency values for prompt D+ meson"}; + Configurable> efficiencyFdD{"efficiencyFdD", {1., 1., 1., 1., 1., 1.}, "efficiency values for beauty feed-down D+ meson"}; + Configurable> efficiencyHad{"efficiencyHad", {1., 1., 1., 1., 1., 1.}, "efficiency values for associated particles"}; // signal and sideband region edges, to be defined via json file (initialised to empty) Configurable> signalRegionInner{"signalRegionInner", std::vector{signalRegionInner_v}, "Inner values of signal region vs pT"}; Configurable> signalRegionOuter{"signalRegionOuter", std::vector{signalRegionOuter_v}, "Outer values of signal region vs pT"}; @@ -88,81 +92,268 @@ struct HfTaskCorrelationDplusHadrons { Configurable> sidebandLeftOuter{"sidebandLeftOuter", std::vector{sidebandLeftOuter_v}, "Outer values of left sideband vs pT"}; Configurable> sidebandRightInner{"sidebandRightInner", std::vector{sidebandRightInner_v}, "Inner values of right sideband vs pT"}; Configurable> sidebandRightOuter{"sidebandRightOuter", std::vector{sidebandRightOuter_v}, "Outer values of right sideband vs pT"}; - Configurable> efficiencyD{"efficiencyD", std::vector{efficiencyDmeson}, "Efficiency values for D meson specie under study"}; - - HistogramRegistry registry{ - "registry", - { - {"hDeltaEtaPtIntSignalRegion", stringDHadron + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {{200, -10., 10.}}}}, - {"hDeltaPhiPtIntSignalRegion", stringDHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}}}}, - {"hCorrel2DPtIntSignalRegion", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {200, -10., 10.}}}}, - {"hCorrel2DVsPtSignalRegion", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {40, -2., 2.}, {10, 0., 10.}, {11, 0., 11.}, {9, 0., 9.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() - {"hDeltaEtaPtIntSidebands", stringDHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {{200, -10., 10.}}}}, - {"hDeltaPhiPtIntSidebands", stringDHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}}}}, - {"hCorrel2DPtIntSidebands", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {200, -10., 10.}}}}, - {"hCorrel2DVsPtSidebands", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {40, -2., 2.}, {10, 0., 10.}, {11, 0., 11.}, {9, 0., 9.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() - {"hDeltaEtaPtIntSignalRegionMCRec", stringDHadron + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {{200, -10., 10.}}}}, - {"hDeltaPhiPtIntSignalRegionMCRec", stringDHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}}}}, - {"hDeltaEtaPtIntSidebandsMCRec", stringDHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {{200, -10., 10.}}}}, - {"hCorrel2DPtIntSignalRegionMCRec", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {200, -10., 10.}}}}, - {"hCorrel2DVsPtSignalRegionMCRec", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {40, -2., 2.}, {10, 0., 10.}, {11, 0., 11.}, {9, 0., 9.}}}}, - {"hCorrel2DVsPtSignalMCRec", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {40, -2., 2.}, {10, 0., 10.}, {11, 0., 11.}, {9, 0., 9.}}}}, - {"hCorrel2DVsPtBkgMCRec", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {40, -2., 2.}, {10, 0., 10.}, {11, 0., 11.}, {9, 0., 9.}}}}, - {"hDeltaPhiPtIntSidebandsMCRec", stringDHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}}}}, - {"hCorrel2DPtIntSidebandsMCRec", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {200, -10., 10.}}}}, - {"hCorrel2DVsPtSidebandsMCRec", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {40, -2., 2.}, {10, 0., 10.}, {11, 0., 11.}, {9, 0., 9.}}}}, - {"hDeltaEtaPtIntMCGen", stringMCParticles + stringDeltaEta + "entries", {HistType::kTH1F, {{200, -10., 10.}}}}, - {"hDeltaPhiPtIntMCGen", stringMCParticles + stringDeltaPhi + "entries", {HistType::kTH1F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}}}}, - {"hCorrel2DPtIntMCGen", stringMCParticles + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {200, -10., 10.}}}}, - {"hCorrel2DVsPtMCGen", stringMCParticles + stringDeltaPhi + stringDeltaEta + stringPtD + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {40, -2., 2.}, {10, 0., 10.}, {11, 0., 11.}, {9, 0., 9.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() - }}; + Configurable dcaXYTrackMax{"dcaXYTrackMax", 1., "max. DCA_xy of tracks"}; + Configurable dcaZTrackMax{"dcaZTrackMax", 1., "max. DCA_z of tracks"}; + Configurable etaTrackMax{"etaTrackMax", 0.8, "max. eta of tracks"}; + Configurable ptCandMin{"ptCandMin", 1., "min. cand. pT"}; + Configurable ptCandMax{"ptCandMax", 50., "max. cand pT"}; + Configurable ptTrackMin{"ptTrackMin", 0.3, "min. track pT"}; + Configurable ptTrackMax{"ptTrackMax", 50., "max. track pT"}; + Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity"}; + Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen. cand. rapidity"}; + Configurable ptDaughterMin{"ptDaughterMin", 0.1, "min. daughter pT"}; + Configurable activateQA{"activateQA", false, "Flag to enable debug histogram"}; + Configurable nTpcCrossedRaws{"nTpcCrossedRaws", 70, "Number of crossed TPC Rows"}; + Configurable cutCollPosZMc{"cutCollPosZMc", 10., "max z-vertex position for collision acceptance"}; + // CCDB configuration + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable associatedEffCcdbPath{"associatedEffCcdbPath", "", "CCDB path for associated efficiency"}; + Configurable promptEffCcdbPath{"promptEffCcdbPath", "", "CCDB path for trigger efficiency"}; + Configurable fdEffCcdbPath{"fdEffCcdbPath", "", "CCDB path for trigger efficiency"}; + Configurable timestampCcdb{"timestampCcdb", -1, "timestamp of the efficiency files used to query in CCDB"}; + Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + // configurable axis definition + ConfigurableAxis binsMassD{"binsMassD", {200, 1.7, 2.10}, "inv. mass (#pi^{+}K^{-}#pi^{+}) (GeV/#it{c}^{2})"}; + ConfigurableAxis binsBdtScore{"binsBdtScore", {100, 0., 1.}, "Bdt output scores"}; + ConfigurableAxis binsEta{"binsEta", {100, -2., 2.}, "#it{#eta}"}; + ConfigurableAxis binsPhi{"binsPhi", {64, -PIHalf, 3. * PIHalf}, "#it{#varphi}"}; + ConfigurableAxis binsMultFT0M{"binsMultFT0M", {600, 0., 8000.}, "Multiplicity as FT0M signal amplitude"}; + ConfigurableAxis binsPoolBin{"binsPoolBin", {9, 0., 9.}, "PoolBin"}; + + Service ccdb; + std::shared_ptr mEfficiencyPrompt = nullptr; + std::shared_ptr mEfficiencyFD = nullptr; + std::shared_ptr mEfficiencyAssociated = nullptr; + + HfHelper hfHelper; + + enum CandidateStep { kCandidateStepMcGenAll = 0, + kCandidateStepMcGenDplusToPiKPi, + kCandidateStepMcCandInAcceptance, + kCandidateStepMcDaughtersInAcceptance, + kCandidateStepMcReco, + kCandidateStepMcRecoInAcceptance, + kCandidateNSteps }; + + using DplusHadronPair = soa::Join; + using DplusHadronPairFullWithMl = soa::Join; + using CandDplusMcReco = soa::Filtered>; + using CandDplusMcGen = soa::Join; + using TracksWithMc = soa::Filtered>; // trackFilter applied + + Filter dplusFilter = ((o2::aod::hf_track_index::hfflag & static_cast(1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi)) != static_cast(0)) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; + Filter trackFilter = (nabs(aod::track::eta) < etaTrackMax) && (aod::track::pt > ptTrackMin) && (aod::track::pt < ptTrackMax) && (nabs(aod::track::dcaXY) < dcaXYTrackMax) && (nabs(aod::track::dcaZ) < dcaZTrackMax); + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext&) { - // redefinition of pT axes for THnSparse holding correlation entries - int nBinspTaxis = binsPtCorrelations->size() - 1; - const double* valuespTaxis = binsPtCorrelations->data(); - - registry.get(HIST("hCorrel2DVsPtSignalRegion"))->GetAxis(2)->Set(nBinspTaxis, valuespTaxis); - registry.get(HIST("hCorrel2DVsPtSidebands"))->GetAxis(2)->Set(nBinspTaxis, valuespTaxis); - registry.get(HIST("hCorrel2DVsPtSignalRegion"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSidebands"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSignalRegionMCRec"))->GetAxis(2)->Set(nBinspTaxis, valuespTaxis); - registry.get(HIST("hCorrel2DVsPtSidebandsMCRec"))->GetAxis(2)->Set(nBinspTaxis, valuespTaxis); - registry.get(HIST("hCorrel2DVsPtSignalRegionMCRec"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSidebandsMCRec"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSignalMCRec"))->GetAxis(2)->Set(nBinspTaxis, valuespTaxis); - registry.get(HIST("hCorrel2DVsPtSignalMCRec"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtBkgMCRec"))->GetAxis(2)->Set(nBinspTaxis, valuespTaxis); - registry.get(HIST("hCorrel2DVsPtBkgMCRec"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtMCGen"))->GetAxis(2)->Set(nBinspTaxis, valuespTaxis); - registry.get(HIST("hCorrel2DVsPtMCGen"))->Sumw2(); + // Axis definition + AxisSpec axisMassD = {binsMassD, "inv. mass (#pi^{+}K^{-}#pi^{+}) (GeV/#it{c}^{2})"}; + AxisSpec axisPtCorr = {(std::vector)binsPtCorrelations, "#it{p}_{T}^{D} (GeV/#it{c})"}; + AxisSpec axisPtD = {(std::vector)binsPtEfficiencyD, "#it{p}_{T}^{D} (GeV/#it{c})"}; + AxisSpec axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; + AxisSpec axisDeltaEta = {binsEta, "#it{#eta}^{Hadron}-#it{#eta}^{D}"}; + AxisSpec axisDeltaPhi = {binsPhi, "#it{#varphi}^{Hadron}-#it{#varphi}^{D} (rad)"}; + AxisSpec axisPtHadron = {(std::vector)binsPtHadron, "#it{p}_{T}^{Hadron} (GeV/#it{c})"}; + AxisSpec axisPoolBin = {binsPoolBin, "poolBin"}; + AxisSpec axisDplusPrompt = {2, -0.5, 1.5, "Prompt D+"}; + AxisSpec axisBdtScore = {binsBdtScore, "Bdt score"}; + + // Histograms for data analysis + registry.add("hBdtScorePrompt", "D+ BDT prompt score", {HistType::kTH1F, {axisBdtScore}}); + registry.add("hBdtScoreBkg", "D+ BDT bkg score", {HistType::kTH1F, {axisBdtScore}}); + registry.add("hMassDplusVsPt", "D+ candidates massVsPt", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hMassDplusVsPtWoEff", "D+ candidates massVsPt without efficiency", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + if (fillHistoData) { + registry.add("hDeltaEtaPtIntSignalRegion", stringDHadron + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSignalRegion", stringDHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSignalRegion", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSignalRegion", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSidebands", stringDHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebands", stringDHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSidebands", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSidebands", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSidebandLeft", stringDHadron + "Left" + stringSideband + stringDeltaEta, {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandLeft", stringDHadron + "Left" + stringSideband + stringDeltaPhi, {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hDeltaEtaPtIntSidebandRight", stringDHadron + "Right" + stringSideband + stringDeltaEta, {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandRight", stringDHadron + "Right" + stringSideband + stringDeltaPhi, {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DVsPtSidebandLeft", stringDHadron + "Left" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSidebandRight", stringDHadron + "Right" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + + registry.get(HIST("hCorrel2DVsPtSignalRegion"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebands"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandLeft"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandRight"))->Sumw2(); + } + // Histograms for MC Reco analysis + if (fillHistoMcRec) { + registry.add("hMassPromptDplusVsPt", "D+ prompt candidates mass Vs Pt", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hMassNonPromptDplusVsPt", "D+ non prompt candidates mass Vs Pt", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hDeltaEtaPtIntSignalRegionMcRec", stringDHadron + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSignalRegionMcRec", stringDHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hDeltaEtaPtIntSidebandsMcRec", stringDHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hCorrel2DPtIntSignalRegionMcRec", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSignalRegionMcRec", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisDplusPrompt}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignalMcRec", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtBkgMcRec", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaPhiPtIntSidebandsMcRec", stringDHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSidebandsMcRec", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSidebandsMcRec", stringDHadron + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtPhysicalPrimaryMcRec", stringDHadron + "(only true primary particles)" + stringSignal, {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisDplusPrompt}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSidebandLeftMcRec", stringDHadron + "Left" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandLeftMcRec", stringDHadron + "Left" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DVsPtSidebandLeftMcRec", stringDHadron + "Left" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSidebandRightMcRec", stringDHadron + "Right" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandRightMcRec", stringDHadron + "Right" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DVsPtSidebandRightMcRec", stringDHadron + "Right" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignalRegionPromptDplusPromptHadronMcRec", stringDHadron + "signal region PromptD - Prompt Track MC reco", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignalRegionNonPromptDplusNonPromptHadronMcRec", stringDHadron + " signal region PromptD - NonPrompt Track MC reco", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + + registry.get(HIST("hCorrel2DVsPtSignalRegionMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandsMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtBkgMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandLeftMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandRightMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalRegionMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtPhysicalPrimaryMcRec"))->Sumw2(); + } + // Histograms for MC Gen analysis + if (fillHistoMcGen) { + registry.add("hDeltaEtaPtIntMcGen", stringMCParticles + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntMcGen", stringMCParticles + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntMcGen", stringMCParticles + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtMcGen", stringMCParticles + stringDeltaPhi + stringDeltaEta + stringPtD + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtMcGenPrompt", stringDHadron + " Prompt MC Gen", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtMcGenPromptDPromptHadron", stringDHadron + "prompt D prompt h MC Gen", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtMcGenNonPromptDNonPromptHadron", stringDHadron + " non prompt D non prompt h MC Gen", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtMcGenNonPrompt", stringDHadron + " NonPrompt MC Gen", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + + registry.get(HIST("hCorrel2DVsPtMcGen"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtMcGenPrompt"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtMcGenNonPrompt"))->Sumw2(); + } + // Histograms for efficiencies + registry.add("Efficiency/hPtCandMcRecPrompt", stringMCRecoDPrompt + stringPtD, {HistType::kTH1F, {axisPtD}}); + registry.add("Efficiency/hPtCandMcGenPrompt", stringMCGenDPrompt + stringPtD, {HistType::kTH1F, {axisPtD}}); + registry.add("Efficiency/hPtCandMcRecNonPrompt", stringMCRecoDFd + stringPtD, {HistType::kTH1F, {axisPtD}}); + registry.add("Efficiency/hPtCandMcGenNonPrompt", stringMCGenDFd + stringPtD, {HistType::kTH1F, {axisPtD}}); + registry.add("Efficiency/hPtCandMcGenDaughterInAcc", stringMCGenDFd + stringPtD, {HistType::kTH1F, {axisPtD}}); + + auto hCandidates = registry.add("hCandidates", "Candidate count at different steps", {HistType::kStepTHnF, {axisPtD, axisMultFT0M, {RecoDecay::OriginType::NonPrompt + 1, +RecoDecay::OriginType::None - 0.5, +RecoDecay::OriginType::NonPrompt + 0.5}}, kCandidateNSteps}); + hCandidates->GetAxis(0)->SetTitle("#it{p}_{T} (GeV/#it{c})"); + hCandidates->GetAxis(1)->SetTitle("multiplicity"); + hCandidates->GetAxis(2)->SetTitle("Charm hadron origin"); + + // Loading efficiency histograms from CCDB + if (applyEfficiency && loadAccXEffFromCCDB) { + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(ccdbNoLaterThan.value); + + mEfficiencyPrompt = std::shared_ptr(ccdb->getForTimeStamp(promptEffCcdbPath, timestampCcdb)); + if (mEfficiencyPrompt == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", promptEffCcdbPath.value.c_str()); + } + LOGF(info, "Loaded trigger efficiency (prompt D) histogram from %s", promptEffCcdbPath.value.c_str()); + + mEfficiencyFD = std::shared_ptr(ccdb->getForTimeStamp(fdEffCcdbPath, timestampCcdb)); + if (mEfficiencyFD == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", fdEffCcdbPath.value.c_str()); + } + LOGF(info, "Loaded feed-down D meson efficiency histogram from %s", fdEffCcdbPath.value.c_str()); + + mEfficiencyAssociated = std::shared_ptr(ccdb->getForTimeStamp(associatedEffCcdbPath, timestampCcdb)); + if (mEfficiencyAssociated == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for associated particles from %s", associatedEffCcdbPath.value.c_str()); + } + LOGF(info, "Loaded associated efficiency histogram from %s", associatedEffCcdbPath.value.c_str()); + } + + if (activateQA) { + const int regionLimits = 6; + std::string labels[regionLimits] = {"SigReg Left", "SigReg Right", "Left SB Low", "Left SB Up", "Right SB Low", "Right SB Up"}; + static const AxisSpec axisSidebandLimits = {regionLimits, 0.5, 6.5, ""}; + auto hSigSidebandLimits = registry.add("Inputs/hSigSidebandLimits", "Signal and Sideband Limits;;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisSidebandLimits, {(std::vector)binsPtCorrelations, "#it{p}_{T} (GeV/#it{c})"}}}); + for (int iLim = 0; iLim < regionLimits; iLim++) { + hSigSidebandLimits->GetXaxis()->SetBinLabel(iLim + 1, labels[iLim].data()); + } + for (size_t iPtD = 0; iPtD < binsPtCorrelations->size() - 1; iPtD++) { + hSigSidebandLimits->SetBinContent(1, iPtD + 1, signalRegionInner->at(iPtD)); + hSigSidebandLimits->SetBinContent(2, iPtD + 1, signalRegionOuter->at(iPtD)); + hSigSidebandLimits->SetBinContent(3, iPtD + 1, sidebandLeftOuter->at(iPtD)); + hSigSidebandLimits->SetBinContent(4, iPtD + 1, sidebandLeftInner->at(iPtD)); + hSigSidebandLimits->SetBinContent(5, iPtD + 1, sidebandRightInner->at(iPtD)); + hSigSidebandLimits->SetBinContent(6, iPtD + 1, sidebandRightOuter->at(iPtD)); + } + } } - void processData(aod::DplusHadronPairFull const& pairEntries) + void processData(DplusHadronPairFullWithMl const& pairEntries, aod::DplusRecoInfo const& candidates) { + for (const auto& candidate : candidates) { + float massD = candidate.mD(); + float ptD = candidate.ptD(); + float bdtScorePrompt = candidate.mlScorePrompt(); + float bdtScoreBkg = candidate.mlScoreBkg(); + int effBinD = o2::analysis::findBin(binsPtEfficiencyD, ptD); + + // reject entries outside pT ranges of interest + if (ptD < binsPtEfficiencyD->front() || ptD > binsPtEfficiencyD->back()) { + continue; + } + + if (bdtScorePrompt < mlOutputPrompt->at(effBinD) || bdtScoreBkg > mlOutputBkg->at(effBinD)) { + continue; + } + double efficiencyWeightD = 1.; + if (applyEfficiency) { + efficiencyWeightD = 1. / efficiencyD->at(o2::analysis::findBin(binsPtEfficiencyD, ptD)); + if (loadAccXEffFromCCDB) { + efficiencyWeightD = 1. / mEfficiencyPrompt->GetBinContent(mEfficiencyPrompt->FindBin(ptD)); + } + } + registry.fill(HIST("hMassDplusVsPt"), massD, ptD, efficiencyWeightD); + registry.fill(HIST("hMassDplusVsPtWoEff"), massD, ptD); + registry.fill(HIST("hBdtScorePrompt"), bdtScorePrompt); + registry.fill(HIST("hBdtScoreBkg"), bdtScoreBkg); + } + for (const auto& pairEntry : pairEntries) { // define variables for widely used quantities - double deltaPhi = pairEntry.deltaPhi(); - double deltaEta = pairEntry.deltaEta(); - double ptD = pairEntry.ptD(); - double ptHadron = pairEntry.ptHadron(); + float deltaPhi = pairEntry.deltaPhi(); + float deltaEta = pairEntry.deltaEta(); + float ptD = pairEntry.ptD(); + float ptHadron = pairEntry.ptHadron(); + float bdtScorePrompt = pairEntry.mlScorePrompt(); + float bdtScoreBkg = pairEntry.mlScoreBkg(); + float trackDcaXY = pairEntry.trackDcaXY(); + float trackDcaZ = pairEntry.trackDcaZ(); + int trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); int poolBin = pairEntry.poolBin(); double massD = pairEntry.mD(); - int effBinD = o2::analysis::findBin(binsPtEfficiency, ptD); + int effBinD = o2::analysis::findBin(binsPtEfficiencyD, ptD); int pTBinD = o2::analysis::findBin(binsPtCorrelations, ptD); // reject entries outside pT ranges of interest - if (pTBinD < 0 || effBinD < 0) { + if (ptD < binsPtEfficiencyD->front() || ptD > binsPtEfficiencyD->back()) { continue; } - if (ptHadron > 10.0) { - ptHadron = 10.5; + + if (bdtScorePrompt < mlOutputPrompt->at(effBinD) || bdtScoreBkg > mlOutputBkg->at(effBinD)) { + continue; + } + if (trackDcaXY > dcaXYTrackMax || trackDcaZ > dcaZTrackMax || trackTpcCrossedRows < nTpcCrossedRaws) { + continue; } double efficiencyWeight = 1.; - double efficiencyHadron = 1.; // Note: To be implemented later on if (applyEfficiency) { - efficiencyWeight = 1. / (efficiencyD->at(effBinD) * efficiencyHadron); + efficiencyWeight = 1. / (efficiencyD->at(effBinD) * efficiencyHad->at(o2::analysis::findBin(binsPtEfficiencyHad, ptHadron))); + if (loadAccXEffFromCCDB) { + efficiencyWeight = 1. / (mEfficiencyPrompt->GetBinContent(mEfficiencyPrompt->FindBin(ptD)) * mEfficiencyAssociated->GetBinContent(mEfficiencyAssociated->FindBin(ptHadron))); + } } // check if correlation entry belongs to signal region, sidebands or is outside both, and fill correlation plots if (massD > signalRegionInner->at(pTBinD) && massD < signalRegionOuter->at(pTBinD)) { @@ -172,10 +363,21 @@ struct HfTaskCorrelationDplusHadrons { registry.fill(HIST("hDeltaEtaPtIntSignalRegion"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSignalRegion"), deltaPhi, efficiencyWeight); } - - if ((massD > sidebandLeftOuter->at(pTBinD) && massD < sidebandLeftInner->at(pTBinD)) || - (massD > sidebandRightInner->at(pTBinD) && massD < sidebandRightOuter->at(pTBinD))) { - // in sideband region + // in sideband left region + if (massD > sidebandLeftOuter->at(pTBinD) && massD < sidebandLeftInner->at(pTBinD)) { + registry.fill(HIST("hCorrel2DVsPtSidebandLeft"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandLeft"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandLeft"), deltaPhi, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSidebands"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DPtIntSidebands"), deltaPhi, deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebands"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebands"), deltaPhi, efficiencyWeight); + } + // in sideband right region + if (massD > sidebandRightInner->at(pTBinD) && massD < sidebandRightOuter->at(pTBinD)) { + registry.fill(HIST("hCorrel2DVsPtSidebandRight"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandRight"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandRight"), deltaPhi, efficiencyWeight); registry.fill(HIST("hCorrel2DVsPtSidebands"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); registry.fill(HIST("hCorrel2DPtIntSidebands"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSidebands"), deltaEta, efficiencyWeight); @@ -186,83 +388,253 @@ struct HfTaskCorrelationDplusHadrons { PROCESS_SWITCH(HfTaskCorrelationDplusHadrons, processData, "Process data", false); /// D-Hadron correlation pair filling task, from pair tables - for MC reco-level analysis (candidates matched to true signal only, but also bkg sources are studied) - void processMcRec(aod::DplusHadronPairFull const& pairEntries) + void processMcRec(DplusHadronPairFullWithMl const& pairEntries, + soa::Join const& candidates) { + for (const auto& candidate : candidates) { + float massD = candidate.mD(); + float ptD = candidate.ptD(); + float bdtScorePrompt = candidate.mlScorePrompt(); + float bdtScoreBkg = candidate.mlScoreBkg(); + int effBinD = o2::analysis::findBin(binsPtEfficiencyD, ptD); + bool isDplusPrompt = candidate.isPrompt(); + + // reject entries outside pT ranges of interest + if (ptD < binsPtEfficiencyD->front() || ptD > binsPtEfficiencyD->back()) + continue; + + if (bdtScorePrompt < mlOutputPrompt->at(effBinD) || bdtScoreBkg > mlOutputBkg->at(effBinD)) { + continue; + } + double efficiencyWeightD = 1.; + if (applyEfficiency) { + if (isDplusPrompt) { + efficiencyWeightD = 1. / efficiencyD->at(effBinD); + if (loadAccXEffFromCCDB) { + efficiencyWeightD = 1. / mEfficiencyPrompt->GetBinContent(mEfficiencyPrompt->FindBin(ptD)); + } + registry.fill(HIST("hMassDplusVsPt"), massD, ptD, efficiencyWeightD); + registry.fill(HIST("hMassDplusVsPtWoEff"), massD, ptD); + registry.fill(HIST("hMassPromptDplusVsPt"), massD, ptD, efficiencyWeightD); + registry.fill(HIST("hBdtScorePrompt"), bdtScorePrompt); + registry.fill(HIST("hBdtScoreBkg"), bdtScoreBkg); + } else { + efficiencyWeightD = 1. / efficiencyFdD->at(effBinD); + if (loadAccXEffFromCCDB) { + efficiencyWeightD = 1. / mEfficiencyFD->GetBinContent(mEfficiencyFD->FindBin(ptD)); + } + registry.fill(HIST("hMassDplusVsPt"), massD, ptD, efficiencyWeightD); + registry.fill(HIST("hMassDplusVsPtWoEff"), massD, ptD); + registry.fill(HIST("hMassNonPromptDplusVsPt"), massD, ptD, efficiencyWeightD); + registry.fill(HIST("hBdtScorePrompt"), bdtScorePrompt); + registry.fill(HIST("hBdtScoreBkg"), bdtScoreBkg); + } + } + } + for (const auto& pairEntry : pairEntries) { // define variables for widely used quantities - double deltaPhi = pairEntry.deltaPhi(); - double deltaEta = pairEntry.deltaEta(); - double ptD = pairEntry.ptD(); - double ptHadron = pairEntry.ptHadron(); + float deltaPhi = pairEntry.deltaPhi(); + float deltaEta = pairEntry.deltaEta(); + float ptD = pairEntry.ptD(); + float ptHadron = pairEntry.ptHadron(); + float massD = pairEntry.mD(); + float bdtScorePrompt = pairEntry.mlScorePrompt(); + float bdtScoreBkg = pairEntry.mlScoreBkg(); + bool isPhysicalPrimary = pairEntry.isPhysicalPrimary(); + float trackDcaXY = pairEntry.trackDcaXY(); + float trackDcaZ = pairEntry.trackDcaZ(); + int trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); + int statusDplusPrompt = static_cast(pairEntry.isPrompt()); + int statusPromptHadron = pairEntry.trackOrigin(); int poolBin = pairEntry.poolBin(); - double massD = pairEntry.mD(); - int effBinD = o2::analysis::findBin(binsPtEfficiency, ptD); + int effBinD = o2::analysis::findBin(binsPtEfficiencyD, ptD); int pTBinD = o2::analysis::findBin(binsPtCorrelations, ptD); - if (pTBinD < 0 || effBinD < 0) { + + // reject entries outside pT ranges of interest + if (ptD < binsPtEfficiencyD->front() || ptD > binsPtEfficiencyD->back()) + continue; + + if (bdtScorePrompt < mlOutputPrompt->at(effBinD) || bdtScoreBkg > mlOutputBkg->at(effBinD)) { continue; } - if (ptHadron > 10.0) { - ptHadron = 10.5; + if (trackDcaXY > dcaXYTrackMax || trackDcaZ > dcaZTrackMax || trackTpcCrossedRows < nTpcCrossedRaws) { + continue; } double efficiencyWeight = 1.; - double efficiencyHadron = 1.; // Note: To be implemented later on + if (applyEfficiency) { - efficiencyWeight = 1. / (efficiencyD->at(effBinD) * efficiencyHadron); + if (statusDplusPrompt) { + efficiencyWeight = 1. / (efficiencyD->at(effBinD) * efficiencyHad->at(o2::analysis::findBin(binsPtEfficiencyHad, ptHadron))); + if (loadAccXEffFromCCDB) { + efficiencyWeight = 1. / (mEfficiencyPrompt->GetBinContent(mEfficiencyPrompt->FindBin(ptD)) * mEfficiencyAssociated->GetBinContent(mEfficiencyAssociated->FindBin(ptHadron))); + } + } else { + efficiencyWeight = 1. / (efficiencyFdD->at(effBinD) * efficiencyHad->at(o2::analysis::findBin(binsPtEfficiencyHad, ptHadron))); + if (loadAccXEffFromCCDB) { + efficiencyWeight = 1. / (mEfficiencyFD->GetBinContent(mEfficiencyFD->FindBin(ptD)) * mEfficiencyAssociated->GetBinContent(mEfficiencyAssociated->FindBin(ptHadron))); + } + } } + // fill correlation plots for signal/bagkground correlations if (pairEntry.signalStatus()) { - registry.fill(HIST("hCorrel2DVsPtSignalMCRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSignalMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); } else { - registry.fill(HIST("hCorrel2DVsPtBkgMCRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtBkgMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); } // reject entries outside pT ranges of interest // check if correlation entry belongs to signal region, sidebands or is outside both, and fill correlation plots if (massD > signalRegionInner->at(pTBinD) && massD < signalRegionOuter->at(pTBinD)) { // in signal region - registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); - registry.fill(HIST("hCorrel2DPtIntSignalRegionMCRec"), deltaPhi, deltaEta, efficiencyWeight); - registry.fill(HIST("hDeltaEtaPtIntSignalRegionMCRec"), deltaEta, efficiencyWeight); - registry.fill(HIST("hDeltaPhiPtIntSignalRegionMCRec"), deltaPhi, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSignalRegionMcRec"), deltaPhi, deltaEta, ptD, ptHadron, statusDplusPrompt, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DPtIntSignalRegionMcRec"), deltaPhi, deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSignalRegionMcRec"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSignalRegionMcRec"), deltaPhi, efficiencyWeight); + if (isPhysicalPrimary) { + registry.fill(HIST("hCorrel2DVsPtPhysicalPrimaryMcRec"), deltaPhi, deltaEta, ptD, ptHadron, statusDplusPrompt, poolBin, efficiencyWeight); + if (statusDplusPrompt == 1 && statusPromptHadron == 1) { + registry.fill(HIST("hCorrel2DVsPtSignalRegionPromptDplusPromptHadronMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + } else if (statusDplusPrompt == 0 && statusPromptHadron == 2) { + registry.fill(HIST("hCorrel2DVsPtSignalRegionNonPromptDplusNonPromptHadronMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + } + } } - - if (((massD > sidebandLeftOuter->at(pTBinD)) && (massD < sidebandLeftInner->at(pTBinD))) || - ((massD > sidebandRightInner->at(pTBinD) && massD < sidebandRightOuter->at(pTBinD)))) { - // in sideband region - registry.fill(HIST("hCorrel2DVsPtSidebandsMCRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); - registry.fill(HIST("hCorrel2DPtIntSidebandsMCRec"), deltaPhi, deltaEta, efficiencyWeight); - registry.fill(HIST("hDeltaEtaPtIntSidebandsMCRec"), deltaEta, efficiencyWeight); - registry.fill(HIST("hDeltaPhiPtIntSidebandsMCRec"), deltaPhi, efficiencyWeight); + // in sideband left region + if (massD > sidebandLeftOuter->at(pTBinD) && massD < sidebandLeftInner->at(pTBinD)) { + registry.fill(HIST("hCorrel2DVsPtSidebandLeftMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandLeftMcRec"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandLeftMcRec"), deltaPhi, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSidebandsMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DPtIntSidebandsMcRec"), deltaPhi, deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandsMcRec"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandsMcRec"), deltaPhi, efficiencyWeight); + } + // in sideband right region + if (massD > sidebandRightInner->at(pTBinD) && massD < sidebandRightOuter->at(pTBinD)) { + registry.fill(HIST("hCorrel2DVsPtSidebandRightMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandRightMcRec"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandRightMcRec"), deltaPhi, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSidebandsMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DPtIntSidebandsMcRec"), deltaPhi, deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandsMcRec"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandsMcRec"), deltaPhi, efficiencyWeight); } } // end loop } PROCESS_SWITCH(HfTaskCorrelationDplusHadrons, processMcRec, "Process MC Reco mode", true); /// D-Hadron correlation pair filling task, from pair tables - for MC gen-level analysis (no filter/selection, only true signal) - void processMcGen(aod::DplusHadronPair const& pairEntries) + void processMcGen(DplusHadronPair const& pairEntries) { for (const auto& pairEntry : pairEntries) { // define variables for widely used quantities - double deltaPhi = pairEntry.deltaPhi(); - double deltaEta = pairEntry.deltaEta(); - double ptD = pairEntry.ptD(); - double ptHadron = pairEntry.ptHadron(); + float deltaPhi = pairEntry.deltaPhi(); + float deltaEta = pairEntry.deltaEta(); + float ptD = pairEntry.ptD(); + float ptHadron = pairEntry.ptHadron(); int poolBin = pairEntry.poolBin(); - // reject entries outside pT ranges of interest - if (o2::analysis::findBin(binsPtCorrelations, ptD) < 0) { - continue; + int statusPromptHadron = pairEntry.trackOrigin(); + bool isDplusPrompt = pairEntry.isPrompt(); + + registry.fill(HIST("hCorrel2DVsPtMcGen"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + registry.fill(HIST("hDeltaEtaPtIntMcGen"), deltaEta); + registry.fill(HIST("hDeltaPhiPtIntMcGen"), deltaPhi); + if (isDplusPrompt) { + registry.fill(HIST("hCorrel2DVsPtMcGenPrompt"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + if (statusPromptHadron == 1) { + registry.fill(HIST("hCorrel2DVsPtMcGenPromptDPromptHadron"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + } + } else { + registry.fill(HIST("hCorrel2DVsPtMcGenNonPrompt"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + if (statusPromptHadron == 2) { + registry.fill(HIST("hCorrel2DVsPtMcGenNonPromptDNonPromptHadron"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + } } - if (ptHadron > 10.0) { - ptHadron = 10.5; + } + } + PROCESS_SWITCH(HfTaskCorrelationDplusHadrons, processMcGen, "Process MC Gen mode", false); + + /// D-Hadron correlation - reconstruction and selection efficiency + void processMcCandEfficiency(soa::Join const&, + soa::Join const&, + CandDplusMcGen const& mcParticles, + CandDplusMcReco const& candidates, + aod::TracksWMc const&) + { + auto hCandidates = registry.get(HIST("hCandidates")); + + /// Gen loop + float multiplicity = -1.; + for (const auto& mcParticle : mcParticles) { + // generated candidates + if (std::abs(mcParticle.pdgCode()) == Pdg::kDPlus) { + auto mcCollision = mcParticle.template mcCollision_as>(); + multiplicity = mcCollision.multMCFT0A() + mcCollision.multMCFT0C(); // multFT0M = multFt0A + multFT0C + hCandidates->Fill(kCandidateStepMcGenAll, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); + if (std::abs(mcParticle.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi) { + hCandidates->Fill(kCandidateStepMcGenDplusToPiKPi, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); + auto yDplus = RecoDecay::y(mcParticle.pVector(), o2::constants::physics::MassDPlus); + if (std::abs(yDplus) <= yCandGenMax) { + hCandidates->Fill(kCandidateStepMcCandInAcceptance, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); + if (mcParticle.originMcGen() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("Efficiency/hPtCandMcGenPrompt"), mcParticle.pt()); + } + if (mcParticle.originMcGen() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("Efficiency/hPtCandMcGenNonPrompt"), mcParticle.pt()); + } + } + bool isDaughterInAcceptance = true; + auto daughters = mcParticle.template daughters_as(); + for (const auto& daughter : daughters) { + if (daughter.pt() < ptDaughterMin || std::abs(daughter.eta()) > etaTrackMax) { + isDaughterInAcceptance = false; + } + } + if (isDaughterInAcceptance) { + hCandidates->Fill(kCandidateStepMcDaughtersInAcceptance, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); + registry.fill(HIST("Efficiency/hPtCandMcGenDaughterInAcc"), mcParticle.pt()); + } + } } + } - registry.fill(HIST("hCorrel2DVsPtMCGen"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); - registry.fill(HIST("hCorrel2DPtIntMCGen"), deltaPhi, deltaEta); - registry.fill(HIST("hDeltaEtaPtIntMCGen"), deltaEta); - registry.fill(HIST("hDeltaPhiPtIntMCGen"), deltaPhi); - } // end loop + // recontructed candidates loop + for (const auto& candidate : candidates) { + if (candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { + continue; + } + std::vector outputMl = {-1., -1., -1.}; + if (candidate.isSelDplusToPiKPi() < selectionFlagDplus) { + continue; + } + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDplusToPiKPi()[classMl->at(iclass)]; + } + if (outputMl[0] > mlOutputBkg->at(o2::analysis::findBin(binsPtEfficiencyD, candidate.pt())) || outputMl[1] < mlOutputPrompt->at(o2::analysis::findBin(binsPtEfficiencyD, candidate.pt()))) { + continue; + } + auto collision = candidate.template collision_as>(); + if (selNoSameBunchPileUpColl && !(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { + continue; + } + multiplicity = collision.multFT0M(); + if (std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi) { + hCandidates->Fill(kCandidateStepMcReco, candidate.pt(), multiplicity, candidate.originMcRec()); + if (std::abs(hfHelper.yDplus(candidate)) <= yCandMax) { + hCandidates->Fill(kCandidateStepMcRecoInAcceptance, candidate.pt(), multiplicity, candidate.originMcRec()); + if (candidate.originMcRec() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("Efficiency/hPtCandMcRecPrompt"), candidate.pt()); + } + if (candidate.originMcRec() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("Efficiency/hPtCandMcRecNonPrompt"), candidate.pt()); + } + } + } + } } - PROCESS_SWITCH(HfTaskCorrelationDplusHadrons, processMcGen, "Process MC Gen mode", false); + PROCESS_SWITCH(HfTaskCorrelationDplusHadrons, processMcCandEfficiency, "Process MC for calculating candidate reconstruction efficiency", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/HFC/Tasks/taskCorrelationDsHadrons.cxx b/PWGHF/HFC/Tasks/taskCorrelationDsHadrons.cxx index 22f42672945..fc4c059c61b 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationDsHadrons.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationDsHadrons.cxx @@ -14,30 +14,61 @@ /// \author Grazia Luparello /// \author Samuele Cattaruzzi +#include +#include +#include + +#include "CCDB/BasicCCDBManager.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" +#include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/Utils/utilsAnalysis.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" using namespace o2; +using namespace o2::constants::physics; using namespace o2::constants::math; using namespace o2::framework; using namespace o2::framework::expressions; /// Ds-Hadron correlation pair filling task, from pair tables - for real data and data-like analysis (i.e. reco-level w/o matching request via MC truth) struct HfTaskCorrelationDsHadrons { + Configurable fillHistoData{"fillHistoData", true, "Flag for filling histograms in data processes"}; + Configurable fillHistoMcRec{"fillHistoMcRec", true, "Flag for filling histograms in MC Rec processes"}; + Configurable fillHistoMcGen{"fillHistoMcGen", true, "Flag for filling histograms in MC Gen processes"}; + Configurable fillHistoMcEff{"fillHistoMcEff", true, "Flag for filling histograms in efficiency processes"}; Configurable applyEfficiency{"applyEfficiency", false, "Flag for applying efficiency weights"}; + Configurable useSel8ForEff{"useSel8ForEff", true, "Flag for applying sel8 for collision selection"}; + Configurable selNoSameBunchPileUpColl{"selNoSameBunchPileUpColl", true, "Flag for rejecting the collisions associated with the same bunch crossing"}; + Configurable removeCollWSplitVtx{"removeCollWSplitVtx", false, "Flag for rejecting the splitted collisions"}; + Configurable loadAccXEffFromCCDB{"loadAccXEffFromCCDB", false, "Flag for loading efficiency distributions from CCDB"}; + Configurable separateTrackOrigins{"separateTrackOrigins", false, "Flag to enable separation of track origins (from c or b)"}; + // Configurable doMcCollisionCheck{"doMcCollisionCheck", false, "Flag for applying the collision check and selection based on MC collision info"}; + Configurable selectionFlagDs{"selectionFlagDs", 7, "Selection Flag for Ds (avoid the case of flag = 0, no outputMlScore)"}; Configurable nTpcCrossedRaws{"nTpcCrossedRaws", 70, "Number of crossed TPC Rows"}; + // Configurable eventGeneratorType{"eventGeneratorType", -1, "If positive, enable event selection using subGeneratorId information. The value indicates which events to keep (0 = MB, 4 = charm triggered, 5 = beauty triggered)"}; + Configurable decayChannel{"decayChannel", 1, "Decay channels: 1 for Ds->PhiPi->KKpi, 2 for Ds->K0*K->KKPi"}; + Configurable cutCollPosZMc{"cutCollPosZMc", 10., "max z-vertex position for collision acceptance"}; Configurable dcaXYTrackMax{"dcaXYTrackMax", 1., "max. DCA_xy of tracks"}; Configurable dcaZTrackMax{"dcaZTrackMax", 1., "max. DCA_z of tracks"}; + Configurable etaTrackMax{"etaTrackMax", 0.8, "max. eta of tracks"}; + Configurable ptCandMin{"ptCandMin", 1., "min. cand. pT (used in eff. process only)"}; + Configurable ptCandMax{"ptCandMax", 50., "max. cand pT (used in eff. process only)"}; + Configurable ptTrackMin{"ptTrackMin", 0.3, "min. track pT (used in eff. process only)"}; + Configurable ptTrackMax{"ptTrackMax", 50., "max. track pT (used in eff. process only)"}; + Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity (used in eff. process only)"}; + Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen. cand. rapidity (used in eff. process only)"}; + Configurable ptDaughterMin{"ptDaughterMin", 0.1, "min. daughter pT (used in eff. process only)"}; + Configurable> classMl{"classMl", {0, 1, 2}, "Indexes of ML scores to be stored. Three indexes max."}; Configurable> binsPtD{"binsPtD", std::vector{o2::analysis::hf_cuts_ds_to_k_k_pi::vecBinsPt}, "pT bin limits for candidate mass plots and efficiency"}; Configurable> binsPtHadron{"binsPtHadron", std::vector{0.3, 2., 4., 8., 12., 50.}, "pT bin limits for assoc particle efficiency"}; - Configurable> mlOutputPrompt{"mlScorePrompt", {0.5, 0.5, 0.5, 0.5}, "Machine learning scores for prompt"}; - Configurable> mlOutputBkg{"mlScoreBkg", {0.5, 0.5, 0.5, 0.5}, "Machine learning scores for bkg"}; + Configurable> mlOutputPromptMin{"mlOutputPromptMin", {0.5, 0.5, 0.5, 0.5}, "Machine learning scores for prompt"}; + Configurable> mlOutputPromptMax{"mlOutputPromptMax", {1.0, 1.0, 1.0, 1.0}, "Machine learning scores for prompt"}; + Configurable> mlOutputBkg{"mlOutputBkg", {0.5, 0.5, 0.5, 0.5}, "Machine learning scores for bkg"}; Configurable> binsPtEfficiencyD{"binsPtEfficiencyD", std::vector{o2::analysis::hf_cuts_ds_to_k_k_pi::vecBinsPt}, "pT bin limits for D-meson efficiency"}; Configurable> binsPtEfficiencyHad{"binsPtEfficiencyHad", std::vector{0.3, 2., 4., 8., 12., 50.}, "pT bin limits for associated particle efficiency"}; Configurable> efficiencyD{"efficiencyD", {1., 1., 1., 1., 1., 1.}, "efficiency values for Ds meson"}; @@ -48,63 +79,201 @@ struct HfTaskCorrelationDsHadrons { Configurable> sidebandLeftOuter{"sidebandLeftOuter", {1.9040, 1.9040, 1.9040, 1.9040, 1.9040, 1.9040, 1.9040, 1.9040}, "Outer values of left sideband vs pT"}; Configurable> sidebandRightInner{"sidebandRightInner", {2.0000, 2.0000, 2.0000, 2.0000, 2.0000, 2.0000, 2.0000, 2.0000}, "Inner values of right sideband vs pT"}; Configurable> sidebandRightOuter{"sidebandRightOuter", {2.0320, 2.0320, 2.0320, 2.0320, 2.0320, 2.0320, 2.0320, 2.0320}, "Outer values of right sideband vs pT"}; + // CCDB configuration + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable associatedEffCcdbPath{"associatedEffCcdbPath", "", "CCDB path for associated efficiency"}; + Configurable promptEffCcdbPath{"promptEffCcdbPath", "", "CCDB path for trigger efficiency"}; + Configurable fdEffCcdbPath{"fdEffCcdbPath", "", "CCDB path for trigger efficiency"}; + Configurable timestampCcdb{"timestampCcdb", -1, "timestamp of the efficiency files used to query in CCDB"}; + + std::shared_ptr mEfficiencyD = nullptr; + std::shared_ptr mEfficiencyAssociated = nullptr; + + enum CandidateStep { + kCandidateStepMcGenDsToKKPi = 0, + kCandidateStepMcCandInAcceptance, + kCandidateStepMcDaughtersInAcceptance, + kCandidateStepMcReco, + kCandidateStepMcRecoInAcceptance, + kCandidateNSteps + }; + + enum AssocTrackStep { kAssocTrackStepMcGen = 0, + kAssocTrackStepMcGenInAcceptance, + kAssocTrackStepRecoAll, + kAssocTrackStepRecoMcMatch, + kAssocTrackStepRecoPrimaries, + kAssocTrackStepRecoSpecies, + kAssocTrackNSteps }; + + HfHelper hfHelper; + SliceCache cache; + + Service ccdb; + + using DsHadronPair = soa::Join; + using DsHadronPairFull = soa::Join; + using DsHadronPairWithMl = soa::Join; + using DsHadronPairFullWithMl = soa::Join; + using CandDsMcReco = soa::Filtered>; // flagDsFilter applied + using CandDsMcGen = soa::Join; // flagDsFilter applied + using TracksWithMc = soa::Filtered>; // trackFilter applied + + Filter flagDsFilter = ((o2::aod::hf_track_index::hfflag & static_cast(1 << aod::hf_cand_3prong::DecayType::DsToKKPi)) != static_cast(0)) && (aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlagDs || aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlagDs); + Filter trackFilter = (nabs(aod::track::eta) < etaTrackMax) && (aod::track::pt > ptTrackMin) && (aod::track::pt < ptTrackMax) && (nabs(aod::track::dcaXY) < dcaXYTrackMax) && (nabs(aod::track::dcaZ) < dcaZTrackMax); + + Preslice perCollisionCand = o2::aod::hf_cand::collisionId; + Preslice perCollisionCandMc = o2::aod::mcparticle::mcCollisionId; + Preslice perCollision = o2::aod::track::collisionId; + Preslice perCollisionMc = o2::aod::mcparticle::mcCollisionId; + PresliceUnsorted> collPerCollMc = o2::aod::mccollisionlabel::mcCollisionId; + ConfigurableAxis binsMassD{"binsMassD", {200, 1.7, 2.25}, "inv. mass (K^{#pm}K^{-}#pi^{+}) (GeV/#it{c}^{2})"}; ConfigurableAxis binsBdtScore{"binsBdtScore", {100, 0., 1.}, "Bdt output scores"}; ConfigurableAxis binsEta{"binsEta", {100, -2., 2.}, "#it{#eta}"}; ConfigurableAxis binsPhi{"binsPhi", {64, -PIHalf, 3. * PIHalf}, "#it{#varphi}"}; + ConfigurableAxis binsMultFT0M{"binsMultFT0M", {600, 0., 8000.}, "Multiplicity as FT0M signal amplitude"}; + ConfigurableAxis binsPosZ{"binsPosZ", {100, -10., 10.}, "primary vertex z coordinate"}; ConfigurableAxis binsPoolBin{"binsPoolBin", {9, 0., 9.}, "PoolBin"}; - using DsHadronPairFull = soa::Join; - using DsHadronPairFullWithMl = soa::Join; - HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext&) { AxisSpec axisMassD = {binsMassD, "inv. mass (K^{#pm}K^{-}#pi^{+}) (GeV/#it{c}^{2})"}; AxisSpec axisDetlaEta = {binsEta, "#it{#eta}^{Hadron}-#it{#eta}^{D}"}; + AxisSpec axisEta = {binsEta, "#it{#eta}"}; AxisSpec axisDetlaPhi = {binsPhi, "#it{#varphi}^{Hadron}-#it{#varphi}^{D} (rad)"}; AxisSpec axisPtD = {(std::vector)binsPtD, "#it{p}_{T}^{D} (GeV/#it{c})"}; AxisSpec axisPtHadron = {(std::vector)binsPtHadron, "#it{p}_{T}^{Hadron} (GeV/#it{c})"}; AxisSpec axisPoolBin = {binsPoolBin, "poolBin"}; AxisSpec axisBdtScore = {binsBdtScore, "Bdt score"}; + AxisSpec axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; + AxisSpec axisPosZ = {binsPosZ, "PosZ"}; AxisSpec axisDsPrompt = {2, -0.5, 1.5, "Prompt Ds"}; // Histograms for data analysis - registry.add("hMassDsVsPt", "Ds candidates massVsPt", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); registry.add("hBdtScorePrompt", "Ds BDT prompt score", {HistType::kTH1F, {axisBdtScore}}); registry.add("hBdtScoreBkg", "Ds BDT bkg score", {HistType::kTH1F, {axisBdtScore}}); - registry.add("hDeltaEtaPtIntSignalRegion", "Ds-h deltaEta signal region", {HistType::kTH1F, {axisDetlaEta}}); - registry.add("hDeltaPhiPtIntSignalRegion", "Ds-h deltaPhi signal region", {HistType::kTH1F, {axisDetlaPhi}}); - registry.add("hCorrel2DVsPtSignalRegion", "Ds-h correlations signal region", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); - registry.add("hDeltaEtaPtIntSidebands", "Ds-h deltaEta sideband region", {HistType::kTH1F, {axisDetlaEta}}); - registry.add("hDeltaPhiPtIntSidebands", "Ds-h deltaPhi sideband region", {HistType::kTH1F, {axisDetlaPhi}}); - registry.add("hCorrel2DVsPtSidebands", "Ds-h correlations sideband region", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + if (fillHistoData) { + registry.add("hMassDsVsPt", "Ds candidates massVsPt", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hDeltaEtaPtIntSignalRegion", "Ds-h deltaEta signal region", {HistType::kTH1F, {axisDetlaEta}}); + registry.add("hDeltaPhiPtIntSignalRegion", "Ds-h deltaPhi signal region", {HistType::kTH1F, {axisDetlaPhi}}); + registry.add("hCorrel2DVsPtSignalRegion", "Ds-h correlations signal region", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSidebandLeft", "Ds-h deltaEta sideband left region", {HistType::kTH1F, {axisDetlaEta}}); + registry.add("hDeltaPhiPtIntSidebandLeft", "Ds-h deltaPhi sideband left region", {HistType::kTH1F, {axisDetlaPhi}}); + registry.add("hDeltaEtaPtIntSidebandRight", "Ds-h deltaEta sideband right region", {HistType::kTH1F, {axisDetlaEta}}); + registry.add("hDeltaPhiPtIntSidebandRight", "Ds-h deltaPhi sideband right region", {HistType::kTH1F, {axisDetlaPhi}}); + registry.add("hCorrel2DVsPtSidebandLeft", "Ds-h correlations sideband left region", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSidebandRight", "Ds-h correlations sideband right region", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + + registry.get(HIST("hCorrel2DVsPtSignalRegion"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandLeft"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandRight"))->Sumw2(); + } // Histograms for MC Reco analysis - registry.add("hDeltaEtaPtIntSignalRegionMcRec", "Ds-h deltaEta signal region MC reco", {HistType::kTH1F, {axisDetlaEta}}); - registry.add("hDeltaPhiPtIntSignalRegionMcRec", "Ds-h deltaPhi signal region MC reco", {HistType::kTH1F, {axisDetlaPhi}}); - registry.add("hCorrel2DVsPtSignalRegionMcRec", "Ds-h correlations signal region MC reco", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); - registry.add("hCorrel2DVsPtPhysicalPrimaryMcRec", "Ds-h correlations signal region (only true primary particles) MC reco", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}}}); - registry.add("hCorrel2DVsPtSignalRegionMcRecPromptDivision", "Ds-h correlations signal region Prompt-NonPrompt MC reco", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisDsPrompt}, {axisPoolBin}}}); - registry.add("hDeltaEtaPtIntSidebandsMcRec", "Ds-h deltaEta sideband region MC reco", {HistType::kTH1F, {axisDetlaEta}}); - registry.add("hDeltaPhiPtIntSidebandsMcRec", "Ds-h deltaPhi sideband region MC reco", {HistType::kTH1F, {axisDetlaPhi}}); - registry.add("hCorrel2DVsPtSidebandsMcRec", "Ds-h correlations sideband region MC reco", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + if (fillHistoMcRec) { + registry.add("hMassPromptDsVsPt", "Ds prompt candidates massVsPt", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hMassNonPromptDsVsPt", "Ds non prompt candidates massVsPt", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + registry.add("hDeltaEtaPtIntSignalRegionMcRec", "Ds-h deltaEta signal region MC reco", {HistType::kTH1F, {axisDetlaEta}}); + registry.add("hDeltaPhiPtIntSignalRegionMcRec", "Ds-h deltaPhi signal region MC reco", {HistType::kTH1F, {axisDetlaPhi}}); + registry.add("hCorrel2DVsPtSignalRegionMcRec", "Ds-h correlations signal region Prompt-NonPrompt MC reco", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisDsPrompt}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignalRegionPromptDsPromptHadronMcRec", "Ds-h correlations signal region Prompt-NonPrompt MC reco", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignalRegionNonPromptDsNonPromptHadronMcRec", "Ds-h correlations signal region Prompt-NonPrompt MC reco", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtPhysicalPrimaryMcRec", "Ds-h correlations signal region (only true primary particles) MC reco", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisDsPrompt}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSidebandLeftMcRec", "Ds-h deltaEta sideband left region MC reco", {HistType::kTH1F, {axisDetlaEta}}); + registry.add("hDeltaPhiPtIntSidebandLeftMcRec", "Ds-h deltaPhi sideband left region MC reco", {HistType::kTH1F, {axisDetlaPhi}}); + registry.add("hCorrel2DVsPtSidebandLeftMcRec", "Ds-h correlations sideband left region MC reco", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSidebandRightMcRec", "Ds-h deltaEta sideband right region MC reco", {HistType::kTH1F, {axisDetlaEta}}); + registry.add("hDeltaPhiPtIntSidebandRightMcRec", "Ds-h deltaPhi sideband right region MC reco", {HistType::kTH1F, {axisDetlaPhi}}); + registry.add("hCorrel2DVsPtSidebandRightMcRec", "Ds-h correlations sideband right region MC reco", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + + registry.get(HIST("hCorrel2DVsPtSignalRegionMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtPhysicalPrimaryMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandLeftMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandRightMcRec"))->Sumw2(); + } // Histograms for MC Gen analysis - registry.add("hDeltaEtaPtIntMcGen", "Ds-h deltaEta MC Gen", {HistType::kTH1F, {axisDetlaEta}}); - registry.add("hDeltaPhiPtIntMcGen", "Ds-h deltaPhi MC Gen", {HistType::kTH1F, {axisDetlaPhi}}); - registry.add("hCorrel2DVsPtMcGen", "Ds-h correlations MC Gen", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); - registry.add("hCorrel2DVsPtMcGenPromptDivision", "Ds-h correlations Prompt-NonPrompt MC Gen", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisDsPrompt}, {axisPoolBin}}}); - - registry.get(HIST("hCorrel2DVsPtSignalRegion"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSidebands"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSignalRegionMcRec"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSidebandsMcRec"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSignalRegionMcRecPromptDivision"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtMcGen"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtMcGenPromptDivision"))->Sumw2(); + if (fillHistoMcGen) { + registry.add("hDeltaEtaPtIntMcGen", "Ds-h deltaEta MC Gen", {HistType::kTH1F, {axisDetlaEta}}); + registry.add("hDeltaPhiPtIntMcGen", "Ds-h deltaPhi MC Gen", {HistType::kTH1F, {axisDetlaPhi}}); + registry.add("hCorrel2DVsPtMcGen", "Ds-h correlations MC Gen", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtMcGenPrompt", "Ds-h correlations Prompt MC Gen", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtMcGenPromptDsPromptHadron", "Ds-h correlations prompt Ds prompt h MC Gen", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtMcGenNonPromptDsNonPromptHadron", "Ds-h correlations non prompt Ds non prompt h MC Gen", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtMcGenNonPrompt", "Ds-h correlations NonPrompt MC Gen", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + + registry.get(HIST("hCorrel2DVsPtMcGen"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtMcGenPrompt"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtMcGenNonPrompt"))->Sumw2(); + } + // Histograms for efficiencies + if (fillHistoMcEff) { + registry.add("hPtCandMcRecPrompt", "Ds prompt candidates pt", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandMcRecNonPrompt", "Ds non prompt candidates pt", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandMcGenPrompt", "Ds,Hadron particles prompt - MC Gen", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandMcGenNonPrompt", "Ds,Hadron particles non prompt - MC Gen", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtCandMcGenDaughterInAcc", "Ds,Hadron particles non prompt - MC Gen", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtParticleAssocMcRec", "Associated Particle - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtParticleAssocSpecieMcRec", "Associated Particle - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtMcParticleAssocSpecieMcRec", "Associated Particle - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtPrmPionMcRec", "Primary pions - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtPrmKaonMcRec", "Primary kaons - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtPrmProtonMcRec", "Primary protons - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtPrmElectronMcRec", "Primary electrons - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtPrmMuonMcRec", "Primary muons - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtPrmPromptPartMcRec", "Primary prompt particles - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtPrmNonPromptPartMcRec", "Primary non-prompt particles - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtParticleAssocMcGen", "Associated Particle - MC Gen", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtPrmPionMcGen", "Primary pions - MC Gen", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtPrmKaonMcGen", "Primary kaons - MC Gen", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtPrmProtonMcGen", "Primary protons - MC Gen", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtPrmElectronMcGen", "Primary electrons - MC Gen", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtPrmMuonMcGen", "Primary muons - MC Gen", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtPrmPromptPartMcGen", "Primary prompt particles - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtPrmNonPromptPartMcGen", "Primary non-prompt particles - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hFakeCollision", "Fake collision counter", {HistType::kTH1F, {{1, -0.5, 0.5, "n fake coll"}}}); + registry.add("hFakeTracks", "Fake tracks counter", {HistType::kTH1F, {{1, -0.5, 0.5, "n fake tracks"}}}); + + auto hCandidates = registry.add("hCandidates", "Candidate count at different steps", {HistType::kStepTHnF, {axisPtD, axisMultFT0M, {RecoDecay::OriginType::NonPrompt + 1, +RecoDecay::OriginType::None - 0.5, +RecoDecay::OriginType::NonPrompt + 0.5}}, kCandidateNSteps}); + hCandidates->GetAxis(0)->SetTitle("#it{p}_{T} (GeV/#it{c})"); + hCandidates->GetAxis(1)->SetTitle("multiplicity"); + hCandidates->GetAxis(2)->SetTitle("Charm hadron origin"); + auto hAssocTracks = registry.add("hAssocTracks", "Associated tracks at different steps", {HistType::kStepTHnF, {axisEta, axisPtHadron, axisMultFT0M, axisPosZ}, kAssocTrackNSteps}); + hAssocTracks->GetAxis(0)->SetTitle("#eta"); + hAssocTracks->GetAxis(1)->SetTitle("#it{p}_{T} (GeV/#it{c})"); + hAssocTracks->GetAxis(2)->SetTitle("multiplicity"); + hAssocTracks->GetAxis(3)->SetTitle("pos z"); + } + + // Loading efficiency histograms from CCDB + if (applyEfficiency && loadAccXEffFromCCDB) { + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + + mEfficiencyD = std::shared_ptr(ccdb->getForTimeStamp(promptEffCcdbPath, timestampCcdb)); + if (mEfficiencyD == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", promptEffCcdbPath.value.c_str()); + } + LOGF(info, "Loaded trigger efficiency (prompt D) histogram from %s", promptEffCcdbPath.value.c_str()); + + mEfficiencyAssociated = std::shared_ptr(ccdb->getForTimeStamp(associatedEffCcdbPath, timestampCcdb)); + if (mEfficiencyAssociated == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for associated particles from %s", associatedEffCcdbPath.value.c_str()); + } + LOGF(info, "Loaded associated efficiency histogram from %s", associatedEffCcdbPath.value.c_str()); + } } - void processData(DsHadronPairFullWithMl const& pairEntries, + bool isSelectedCandidate(const int ptBinD, const float bdtScorePrompt, const float bdtScoreBkg) + { + + return (ptBinD != -1 && bdtScorePrompt >= mlOutputPromptMin->at(ptBinD) && bdtScorePrompt <= mlOutputPromptMax->at(ptBinD) && bdtScoreBkg <= mlOutputBkg->at(ptBinD)); + } + + void processData(DsHadronPairWithMl const& pairEntries, aod::DsCandRecoInfo const& candidates) { for (const auto& candidate : candidates) { @@ -114,12 +283,16 @@ struct HfTaskCorrelationDsHadrons { float bdtScoreBkg = candidate.mlScoreBkg(); int ptBinD = o2::analysis::findBin(binsPtD, ptD); - if (bdtScorePrompt < mlOutputPrompt->at(ptBinD) || bdtScoreBkg > mlOutputBkg->at(ptBinD)) { + if (!isSelectedCandidate(ptBinD, bdtScorePrompt, bdtScoreBkg)) { continue; } + double efficiencyWeightD = 1.; if (applyEfficiency) { efficiencyWeightD = 1. / efficiencyD->at(o2::analysis::findBin(binsPtEfficiencyD, ptD)); + if (loadAccXEffFromCCDB) { + efficiencyWeightD = 1. / mEfficiencyD->GetBinContent(mEfficiencyD->FindBin(ptD)); + } } registry.fill(HIST("hMassDsVsPt"), massD, ptD, efficiencyWeightD); registry.fill(HIST("hBdtScorePrompt"), bdtScorePrompt); @@ -141,15 +314,19 @@ struct HfTaskCorrelationDsHadrons { int poolBin = pairEntry.poolBin(); int ptBinD = o2::analysis::findBin(binsPtD, ptD); - if (bdtScorePrompt < mlOutputPrompt->at(ptBinD) || bdtScoreBkg > mlOutputBkg->at(ptBinD)) { + if (!isSelectedCandidate(ptBinD, bdtScorePrompt, bdtScoreBkg)) { continue; } + if (trackDcaXY > dcaXYTrackMax || trackDcaZ > dcaZTrackMax || trackTpcCrossedRows < nTpcCrossedRaws) { continue; } double efficiencyWeight = 1.; if (applyEfficiency) { efficiencyWeight = 1. / (efficiencyD->at(o2::analysis::findBin(binsPtEfficiencyD, ptD)) * efficiencyHad->at(o2::analysis::findBin(binsPtEfficiencyHad, ptHadron))); + if (loadAccXEffFromCCDB) { + efficiencyWeight = 1. / (mEfficiencyD->GetBinContent(mEfficiencyD->FindBin(ptD)) * mEfficiencyAssociated->GetBinContent(mEfficiencyAssociated->FindBin(ptHadron))); + } } // in signal region @@ -158,20 +335,56 @@ struct HfTaskCorrelationDsHadrons { registry.fill(HIST("hDeltaEtaPtIntSignalRegion"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSignalRegion"), deltaPhi, efficiencyWeight); } - // in sideband region - if ((massD > sidebandLeftOuter->at(ptBinD) && massD < sidebandLeftInner->at(ptBinD)) || - (massD > sidebandRightInner->at(ptBinD) && massD < sidebandRightOuter->at(ptBinD))) { - registry.fill(HIST("hCorrel2DVsPtSidebands"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); - registry.fill(HIST("hDeltaEtaPtIntSidebands"), deltaEta, efficiencyWeight); - registry.fill(HIST("hDeltaPhiPtIntSidebands"), deltaPhi, efficiencyWeight); + // in sideband left region + if (massD > sidebandLeftOuter->at(ptBinD) && massD < sidebandLeftInner->at(ptBinD)) { + registry.fill(HIST("hCorrel2DVsPtSidebandLeft"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandLeft"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandLeft"), deltaPhi, efficiencyWeight); + } + // in sideband right region + if (massD > sidebandRightInner->at(ptBinD) && massD < sidebandRightOuter->at(ptBinD)) { + registry.fill(HIST("hCorrel2DVsPtSidebandRight"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandRight"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandRight"), deltaPhi, efficiencyWeight); } } } PROCESS_SWITCH(HfTaskCorrelationDsHadrons, processData, "Process data", true); /// D-Hadron correlation pair filling task, from pair tables - for MC reco-level analysis (candidates matched to true signal only, but also bkg sources are studied) - void processMcRec(DsHadronPairFullWithMl const& pairEntries) + void processMcRec(DsHadronPairFullWithMl const& pairEntries, + soa::Join const& candidates) { + for (const auto& candidate : candidates) { + float massD = candidate.mD(); + float ptD = candidate.ptD(); + float bdtScorePrompt = candidate.mlScorePrompt(); + float bdtScoreBkg = candidate.mlScoreBkg(); + int ptBinD = o2::analysis::findBin(binsPtD, ptD); + bool isDsPrompt = candidate.isPrompt(); + + if (!isSelectedCandidate(ptBinD, bdtScorePrompt, bdtScoreBkg)) { + continue; + } + + double efficiencyWeightD = 1.; + if (applyEfficiency) { + efficiencyWeightD = 1. / efficiencyD->at(o2::analysis::findBin(binsPtEfficiencyD, ptD)); + if (loadAccXEffFromCCDB) { + efficiencyWeightD = 1. / mEfficiencyD->GetBinContent(mEfficiencyD->FindBin(ptD)); + } + } + if (isDsPrompt) { + registry.fill(HIST("hMassPromptDsVsPt"), massD, ptD, efficiencyWeightD); + registry.fill(HIST("hBdtScorePrompt"), bdtScorePrompt); + registry.fill(HIST("hBdtScoreBkg"), bdtScoreBkg); + } else { + registry.fill(HIST("hMassNonPromptDsVsPt"), massD, ptD, efficiencyWeightD); + registry.fill(HIST("hBdtScorePrompt"), bdtScorePrompt); + registry.fill(HIST("hBdtScoreBkg"), bdtScoreBkg); + } + } + for (const auto& pairEntry : pairEntries) { // define variables for widely used quantities float deltaPhi = pairEntry.deltaPhi(); @@ -186,38 +399,52 @@ struct HfTaskCorrelationDsHadrons { int trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); int poolBin = pairEntry.poolBin(); int statusDsPrompt = static_cast(pairEntry.isPrompt()); + int statusPromptHadron = pairEntry.trackOrigin(); int ptBinD = o2::analysis::findBin(binsPtD, ptD); bool isPhysicalPrimary = pairEntry.isPhysicalPrimary(); - if (bdtScorePrompt < mlOutputPrompt->at(ptBinD) || bdtScoreBkg > mlOutputBkg->at(ptBinD)) { + if (!isSelectedCandidate(ptBinD, bdtScorePrompt, bdtScoreBkg)) { continue; } + if (trackDcaXY > dcaXYTrackMax || trackDcaZ > dcaZTrackMax || trackTpcCrossedRows < nTpcCrossedRaws) { continue; } double efficiencyWeight = 1.; if (applyEfficiency) { efficiencyWeight = 1. / (efficiencyD->at(o2::analysis::findBin(binsPtEfficiencyD, ptD)) * efficiencyHad->at(o2::analysis::findBin(binsPtEfficiencyHad, ptHadron))); + if (loadAccXEffFromCCDB) { + efficiencyWeight = 1. / (mEfficiencyD->GetBinContent(mEfficiencyD->FindBin(ptD)) * mEfficiencyAssociated->GetBinContent(mEfficiencyAssociated->FindBin(ptHadron))); + } } // in signal region if (massD > signalRegionInner->at(ptBinD) && massD < signalRegionOuter->at(ptBinD)) { - registry.fill(HIST("hCorrel2DVsPtSignalRegionMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); - registry.fill(HIST("hDeltaEtaPtIntSignalRegionMcRec"), deltaEta, efficiencyWeight); - registry.fill(HIST("hDeltaPhiPtIntSignalRegionMcRec"), deltaPhi, efficiencyWeight); // prompt and non-prompt division - if (pairEntry.isSignal()) { - registry.fill(HIST("hCorrel2DVsPtSignalRegionMcRecPromptDivision"), deltaPhi, deltaEta, ptD, ptHadron, statusDsPrompt, poolBin, efficiencyWeight); + if (pairEntry.isSignal() && pairEntry.isDecayChan()) { + registry.fill(HIST("hDeltaEtaPtIntSignalRegionMcRec"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSignalRegionMcRec"), deltaPhi, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSignalRegionMcRec"), deltaPhi, deltaEta, ptD, ptHadron, statusDsPrompt, poolBin, efficiencyWeight); if (isPhysicalPrimary) { - registry.fill(HIST("hCorrel2DVsPtPhysicalPrimaryMcRec"), deltaPhi, deltaEta, ptD, ptHadron, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtPhysicalPrimaryMcRec"), deltaPhi, deltaEta, ptD, ptHadron, statusDsPrompt, poolBin, efficiencyWeight); + if (statusDsPrompt == 1 && statusPromptHadron == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hCorrel2DVsPtSignalRegionPromptDsPromptHadronMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + } else if (statusDsPrompt == 0 && statusPromptHadron == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("hCorrel2DVsPtSignalRegionNonPromptDsNonPromptHadronMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + } } } } - // in sideband region - if (((massD > sidebandLeftOuter->at(ptBinD)) && (massD < sidebandLeftInner->at(ptBinD))) || - ((massD > sidebandRightInner->at(ptBinD) && massD < sidebandRightOuter->at(ptBinD)))) { - registry.fill(HIST("hCorrel2DVsPtSidebandsMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); - registry.fill(HIST("hDeltaEtaPtIntSidebandsMcRec"), deltaEta, efficiencyWeight); - registry.fill(HIST("hDeltaPhiPtIntSidebandsMcRec"), deltaPhi, efficiencyWeight); + // in sideband left region + if (massD > sidebandLeftOuter->at(ptBinD) && massD < sidebandLeftInner->at(ptBinD)) { + registry.fill(HIST("hCorrel2DVsPtSidebandLeftMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandLeftMcRec"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandLeftMcRec"), deltaPhi, efficiencyWeight); + } + // in sideband right region + if (massD > sidebandRightInner->at(ptBinD) && massD < sidebandRightOuter->at(ptBinD)) { + registry.fill(HIST("hCorrel2DVsPtSidebandRightMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandRightMcRec"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandRightMcRec"), deltaPhi, efficiencyWeight); } } } @@ -233,17 +460,28 @@ struct HfTaskCorrelationDsHadrons { float ptD = pairEntry.ptD(); float ptHadron = pairEntry.ptHadron(); int poolBin = pairEntry.poolBin(); - int statusDsPrompt = static_cast(pairEntry.isPrompt()); + int statusPromptHadron = pairEntry.trackOrigin(); + bool isDsPrompt = pairEntry.isPrompt(); registry.fill(HIST("hCorrel2DVsPtMcGen"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); - registry.fill(HIST("hCorrel2DVsPtMcGenPromptDivision"), deltaPhi, deltaEta, ptD, ptHadron, statusDsPrompt, poolBin); registry.fill(HIST("hDeltaEtaPtIntMcGen"), deltaEta); registry.fill(HIST("hDeltaPhiPtIntMcGen"), deltaPhi); + if (isDsPrompt) { + registry.fill(HIST("hCorrel2DVsPtMcGenPrompt"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + if (statusPromptHadron == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hCorrel2DVsPtMcGenPromptDsPromptHadron"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + } + } else { + registry.fill(HIST("hCorrel2DVsPtMcGenNonPrompt"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + if (statusPromptHadron == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("hCorrel2DVsPtMcGenNonPromptDsNonPromptHadron"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + } + } } } PROCESS_SWITCH(HfTaskCorrelationDsHadrons, processMcGen, "Process MC Gen mode", false); - void processDataME(DsHadronPairFullWithMl const& pairEntries) + void processDataME(DsHadronPairWithMl const& pairEntries) { for (const auto& pairEntry : pairEntries) { // define variables for widely used quantities @@ -260,15 +498,19 @@ struct HfTaskCorrelationDsHadrons { int poolBin = pairEntry.poolBin(); int ptBinD = o2::analysis::findBin(binsPtD, ptD); - if (bdtScorePrompt < mlOutputPrompt->at(ptBinD) || bdtScoreBkg > mlOutputBkg->at(ptBinD)) { + if (!isSelectedCandidate(ptBinD, bdtScorePrompt, bdtScoreBkg)) { continue; } + if (trackDcaXY > dcaXYTrackMax || trackDcaZ > dcaZTrackMax || trackTpcCrossedRows < nTpcCrossedRaws) { continue; } double efficiencyWeight = 1.; if (applyEfficiency) { efficiencyWeight = 1. / (efficiencyD->at(o2::analysis::findBin(binsPtEfficiencyD, ptD)) * efficiencyHad->at(o2::analysis::findBin(binsPtEfficiencyHad, ptHadron))); + if (loadAccXEffFromCCDB) { + efficiencyWeight = 1. / (mEfficiencyD->GetBinContent(mEfficiencyD->FindBin(ptD)) * mEfficiencyAssociated->GetBinContent(mEfficiencyAssociated->FindBin(ptHadron))); + } } // in signal region @@ -277,16 +519,456 @@ struct HfTaskCorrelationDsHadrons { registry.fill(HIST("hDeltaEtaPtIntSignalRegion"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSignalRegion"), deltaPhi, efficiencyWeight); } - // in sideband region - if ((massD > sidebandLeftOuter->at(ptBinD) && massD < sidebandLeftInner->at(ptBinD)) || - (massD > sidebandRightInner->at(ptBinD) && massD < sidebandRightOuter->at(ptBinD))) { - registry.fill(HIST("hCorrel2DVsPtSidebands"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); - registry.fill(HIST("hDeltaEtaPtIntSidebands"), deltaEta, efficiencyWeight); - registry.fill(HIST("hDeltaPhiPtIntSidebands"), deltaPhi, efficiencyWeight); + // in sideband left region + if (massD > sidebandLeftOuter->at(ptBinD) && massD < sidebandLeftInner->at(ptBinD)) { + registry.fill(HIST("hCorrel2DVsPtSidebandLeft"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandLeft"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandLeft"), deltaPhi, efficiencyWeight); + } + // in sideband right region + if (massD > sidebandRightInner->at(ptBinD) && massD < sidebandRightOuter->at(ptBinD)) { + registry.fill(HIST("hCorrel2DVsPtSidebandRight"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandRight"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandRight"), deltaPhi, efficiencyWeight); } } } PROCESS_SWITCH(HfTaskCorrelationDsHadrons, processDataME, "Process data ME", false); + + void processDerivedDataME(DsHadronPair const& pairEntries) + { + for (const auto& pairEntry : pairEntries) { + // define variables for widely used quantities + float deltaPhi = pairEntry.deltaPhi(); + float deltaEta = pairEntry.deltaEta(); + float ptD = pairEntry.ptD(); + float ptHadron = pairEntry.ptHadron(); + float massD = pairEntry.mD(); + int poolBin = pairEntry.poolBin(); + int ptBinD = o2::analysis::findBin(binsPtD, ptD); + + double efficiencyWeight = 1.; + if (applyEfficiency) { + efficiencyWeight = 1. / (efficiencyD->at(o2::analysis::findBin(binsPtEfficiencyD, ptD)) * efficiencyHad->at(o2::analysis::findBin(binsPtEfficiencyHad, ptHadron))); + if (loadAccXEffFromCCDB) { + efficiencyWeight = 1. / (mEfficiencyD->GetBinContent(mEfficiencyD->FindBin(ptD)) * mEfficiencyAssociated->GetBinContent(mEfficiencyAssociated->FindBin(ptHadron))); + } + } + + // in signal region + if (massD > signalRegionInner->at(ptBinD) && massD < signalRegionOuter->at(ptBinD)) { + registry.fill(HIST("hCorrel2DVsPtSignalRegion"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSignalRegion"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSignalRegion"), deltaPhi, efficiencyWeight); + } + // in sideband left region + if (massD > sidebandLeftOuter->at(ptBinD) && massD < sidebandLeftInner->at(ptBinD)) { + registry.fill(HIST("hCorrel2DVsPtSidebandLeft"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandLeft"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandLeft"), deltaPhi, efficiencyWeight); + } + // in sideband right region + if (massD > sidebandRightInner->at(ptBinD) && massD < sidebandRightOuter->at(ptBinD)) { + registry.fill(HIST("hCorrel2DVsPtSidebandRight"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandRight"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandRight"), deltaPhi, efficiencyWeight); + } + } + } + PROCESS_SWITCH(HfTaskCorrelationDsHadrons, processDerivedDataME, "Process derived data ME", false); + + /// D-Hadron correlation pair filling task, from pair tables - for MC reco-level analysis (candidates matched to true signal only, but also bkg sources are studied) + void processMcRecME(DsHadronPairFullWithMl const& pairEntries) + { + for (const auto& pairEntry : pairEntries) { + // define variables for widely used quantities + float deltaPhi = pairEntry.deltaPhi(); + float deltaEta = pairEntry.deltaEta(); + float ptD = pairEntry.ptD(); + float ptHadron = pairEntry.ptHadron(); + float massD = pairEntry.mD(); + float bdtScorePrompt = pairEntry.mlScorePrompt(); + float bdtScoreBkg = pairEntry.mlScoreBkg(); + float trackDcaXY = pairEntry.trackDcaXY(); + float trackDcaZ = pairEntry.trackDcaZ(); + int trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); + int poolBin = pairEntry.poolBin(); + int statusDsPrompt = static_cast(pairEntry.isPrompt()); + int statusPromptHadron = pairEntry.trackOrigin(); + int ptBinD = o2::analysis::findBin(binsPtD, ptD); + bool isPhysicalPrimary = pairEntry.isPhysicalPrimary(); + + if (!isSelectedCandidate(ptBinD, bdtScorePrompt, bdtScoreBkg)) { + continue; + } + + if (trackDcaXY > dcaXYTrackMax || trackDcaZ > dcaZTrackMax || trackTpcCrossedRows < nTpcCrossedRaws) { + continue; + } + double efficiencyWeight = 1.; + if (applyEfficiency) { + efficiencyWeight = 1. / (efficiencyD->at(o2::analysis::findBin(binsPtEfficiencyD, ptD)) * efficiencyHad->at(o2::analysis::findBin(binsPtEfficiencyHad, ptHadron))); + if (loadAccXEffFromCCDB) { + efficiencyWeight = 1. / (mEfficiencyD->GetBinContent(mEfficiencyD->FindBin(ptD)) * mEfficiencyAssociated->GetBinContent(mEfficiencyAssociated->FindBin(ptHadron))); + } + } + // in signal region + if (massD > signalRegionInner->at(ptBinD) && massD < signalRegionOuter->at(ptBinD)) { + // prompt and non-prompt division + if (pairEntry.isSignal() && pairEntry.isDecayChan()) { + registry.fill(HIST("hDeltaEtaPtIntSignalRegionMcRec"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSignalRegionMcRec"), deltaPhi, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSignalRegionMcRec"), deltaPhi, deltaEta, ptD, ptHadron, statusDsPrompt, poolBin, efficiencyWeight); + if (isPhysicalPrimary) { + registry.fill(HIST("hCorrel2DVsPtPhysicalPrimaryMcRec"), deltaPhi, deltaEta, ptD, ptHadron, statusDsPrompt, poolBin, efficiencyWeight); + if (statusDsPrompt == 1 && statusPromptHadron == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hCorrel2DVsPtSignalRegionPromptDsPromptHadronMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + } else if (statusDsPrompt == 0 && statusPromptHadron == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("hCorrel2DVsPtSignalRegionNonPromptDsNonPromptHadronMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + } + } + } + } + // in sideband left region + if (massD > sidebandLeftOuter->at(ptBinD) && massD < sidebandLeftInner->at(ptBinD)) { + registry.fill(HIST("hCorrel2DVsPtSidebandLeftMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandLeftMcRec"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandLeftMcRec"), deltaPhi, efficiencyWeight); + } + // in sideband right region + if (massD > sidebandRightInner->at(ptBinD) && massD < sidebandRightOuter->at(ptBinD)) { + registry.fill(HIST("hCorrel2DVsPtSidebandRightMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandRightMcRec"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandRightMcRec"), deltaPhi, efficiencyWeight); + } + } + } + PROCESS_SWITCH(HfTaskCorrelationDsHadrons, processMcRecME, "Process MC Reco ME", false); + + /// Ds-Hadron correlation - for calculating candidate reconstruction efficiency using MC reco-level analysis + void processMcCandEfficiency(soa::Join const& collisions, + soa::Join const& mcCollisions, + CandDsMcGen const& mcParticles, + CandDsMcReco const& candidates, + aod::TracksWMc const&) + { + auto hCandidates = registry.get(HIST("hCandidates")); + + /// loop over generated collisions + for (const auto& mcCollision : mcCollisions) { + + const auto groupedCollisions = collisions.sliceBy(collPerCollMc, mcCollision.globalIndex()); + const auto groupedMcParticles = mcParticles.sliceBy(perCollisionCandMc, mcCollision.globalIndex()); + + if (groupedCollisions.size() < 1) { // Skipping MC events that have no reconstructed collisions + continue; + } + if (groupedCollisions.size() > 1 && removeCollWSplitVtx) { // Skipping MC events that have more than one reconstructed collision + continue; + } + + /// loop over reconstructed collisions + for (const auto& collision : groupedCollisions) { + + // reco collision selection + if (useSel8ForEff && !collision.sel8()) { + continue; + } + if (std::abs(collision.posZ()) > cutCollPosZMc) { + continue; + } + if (selNoSameBunchPileUpColl && !(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { + continue; + } + if (!collision.has_mcCollision()) { + registry.fill(HIST("hFakeCollision"), 0.); + continue; + } + + float multiplicityReco = collision.multFT0M(); + float multiplicityGen = mcCollision.multMCFT0A() + mcCollision.multMCFT0C(); // multFT0M = multFt0A + multFT0C + + const auto groupedCandidates = candidates.sliceBy(perCollisionCand, collision.globalIndex()); + + // generated candidate loop + for (const auto& mcParticle : groupedMcParticles) { + if ((std::abs(mcParticle.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::DsToKKPi) && (mcParticle.flagMcDecayChanGen() == decayChannel)) { + hCandidates->Fill(kCandidateStepMcGenDsToKKPi, mcParticle.pt(), multiplicityGen, mcParticle.originMcGen()); + auto yDs = RecoDecay::y(mcParticle.pVector(), o2::constants::physics::MassDS); + if (std::abs(yDs) <= yCandGenMax) { + hCandidates->Fill(kCandidateStepMcCandInAcceptance, mcParticle.pt(), multiplicityGen, mcParticle.originMcGen()); + if (mcParticle.originMcGen() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hPtCandMcGenPrompt"), mcParticle.pt()); + } + if (mcParticle.originMcGen() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("hPtCandMcGenNonPrompt"), mcParticle.pt()); + } + } + bool isDaughterInAcceptance = true; + auto daughters = mcParticle.template daughters_as(); + for (const auto& daughter : daughters) { + if (daughter.pt() < ptDaughterMin || std::abs(daughter.eta()) > etaTrackMax) { + isDaughterInAcceptance = false; + } + } + if (isDaughterInAcceptance) { + hCandidates->Fill(kCandidateStepMcDaughtersInAcceptance, mcParticle.pt(), multiplicityGen, mcParticle.originMcGen()); + registry.fill(HIST("hPtCandMcGenDaughterInAcc"), mcParticle.pt()); + } + } + } + + // reconstructed candidate loop + for (const auto& candidate : groupedCandidates) { + if (candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { + continue; + } + std::vector outputMl = {-1., -1., -1.}; + if (candidate.isSelDsToKKPi() >= selectionFlagDs) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDsToKKPi()[classMl->at(iclass)]; + } + } else if (candidate.isSelDsToPiKK() >= selectionFlagDs) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDsToPiKK()[classMl->at(iclass)]; + } + } + if (outputMl[0] < mlOutputPromptMin->at(o2::analysis::findBin(binsPtD, candidate.pt())) || outputMl[0] < mlOutputPromptMax->at(o2::analysis::findBin(binsPtD, candidate.pt())) || outputMl[2] > mlOutputBkg->at(o2::analysis::findBin(binsPtD, candidate.pt()))) { + continue; + } + + if ((std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DsToKKPi) && (candidate.flagMcDecayChanRec() == decayChannel)) { + auto prong0McPart = candidate.template prong0_as().template mcParticle_as(); + // DsToKKPi and DsToPiKK division + if (((std::abs(prong0McPart.pdgCode()) == kKPlus) && (candidate.isSelDsToKKPi() >= selectionFlagDs)) || ((std::abs(prong0McPart.pdgCode()) == kPiPlus) && (candidate.isSelDsToPiKK() >= selectionFlagDs))) { + hCandidates->Fill(kCandidateStepMcReco, candidate.pt(), multiplicityReco, candidate.originMcRec()); + if (std::abs(hfHelper.yDs(candidate)) <= yCandMax) { + hCandidates->Fill(kCandidateStepMcRecoInAcceptance, candidate.pt(), multiplicityReco, candidate.originMcRec()); + if (candidate.originMcRec() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hPtCandMcRecPrompt"), candidate.pt()); + } + if (candidate.originMcRec() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("hPtCandMcRecNonPrompt"), candidate.pt()); + } + } + } + } + } + + } // end loop reconstructed collision + } // end loop generated collisions + } + PROCESS_SWITCH(HfTaskCorrelationDsHadrons, processMcCandEfficiency, "Process MC for calculating candidate reconstruction efficiency", false); + + void processMcCandEfficiencyWoColl(soa::Join const&, + soa::Join const&, + CandDsMcGen const& mcParticles, + CandDsMcReco const& candidates, + aod::TracksWMc const&) + { + auto hCandidates = registry.get(HIST("hCandidates")); + + /// Gen loop + float multiplicity = -1.; + for (const auto& mcParticle : mcParticles) { + // generated candidates + if ((std::abs(mcParticle.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::DsToKKPi) && (mcParticle.flagMcDecayChanGen() == decayChannel)) { + auto mcCollision = mcParticle.template mcCollision_as>(); + multiplicity = mcCollision.multMCFT0A() + mcCollision.multMCFT0C(); // multFT0M = multFt0A + multFT0C + hCandidates->Fill(kCandidateStepMcGenDsToKKPi, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); + auto yDs = RecoDecay::y(mcParticle.pVector(), o2::constants::physics::MassDS); + if (std::abs(yDs) <= yCandGenMax) { + hCandidates->Fill(kCandidateStepMcCandInAcceptance, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); + if (mcParticle.originMcGen() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hPtCandMcGenPrompt"), mcParticle.pt()); + } + if (mcParticle.originMcGen() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("hPtCandMcGenNonPrompt"), mcParticle.pt()); + } + } + bool isDaughterInAcceptance = true; + auto daughters = mcParticle.template daughters_as(); + for (const auto& daughter : daughters) { + if (daughter.pt() < ptDaughterMin || std::abs(daughter.eta()) > etaTrackMax) { + isDaughterInAcceptance = false; + } + } + if (isDaughterInAcceptance) { + hCandidates->Fill(kCandidateStepMcDaughtersInAcceptance, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); + registry.fill(HIST("hPtCandMcGenDaughterInAcc"), mcParticle.pt()); + } + } + } + + // recontructed candidates loop + for (const auto& candidate : candidates) { + if (candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { + continue; + } + std::vector outputMl = {-1., -1., -1.}; + if (candidate.isSelDsToKKPi() >= selectionFlagDs) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDsToKKPi()[classMl->at(iclass)]; + } + } else if (candidate.isSelDsToPiKK() >= selectionFlagDs) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDsToPiKK()[classMl->at(iclass)]; + } + } + if (outputMl[0] < mlOutputPromptMin->at(o2::analysis::findBin(binsPtD, candidate.pt())) || outputMl[0] < mlOutputPromptMax->at(o2::analysis::findBin(binsPtD, candidate.pt())) || outputMl[2] > mlOutputBkg->at(o2::analysis::findBin(binsPtD, candidate.pt()))) { + continue; + } + auto collision = candidate.template collision_as>(); + if (selNoSameBunchPileUpColl && !(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { + continue; + } + multiplicity = collision.multFT0M(); + if ((std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DsToKKPi) && (candidate.flagMcDecayChanRec() == decayChannel)) { + auto prong0McPart = candidate.template prong0_as().template mcParticle_as(); + // DsToKKPi and DsToPiKK division + if (((std::abs(prong0McPart.pdgCode()) == kKPlus) && (candidate.isSelDsToKKPi() >= selectionFlagDs)) || ((std::abs(prong0McPart.pdgCode()) == kPiPlus) && (candidate.isSelDsToPiKK() >= selectionFlagDs))) { + hCandidates->Fill(kCandidateStepMcReco, candidate.pt(), multiplicity, candidate.originMcRec()); + if (std::abs(hfHelper.yDs(candidate)) <= yCandMax) { + hCandidates->Fill(kCandidateStepMcRecoInAcceptance, candidate.pt(), multiplicity, candidate.originMcRec()); + if (candidate.originMcRec() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hPtCandMcRecPrompt"), candidate.pt()); + } + if (candidate.originMcRec() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("hPtCandMcRecNonPrompt"), candidate.pt()); + } + } + } + } + } + } + PROCESS_SWITCH(HfTaskCorrelationDsHadrons, processMcCandEfficiencyWoColl, "Process MC for calculating candidate reconstruction efficiency", false); + + /// Ds-Hadron correlation - for calculating associated particle tracking efficiency using MC reco-level analysis + void processMcTrackEfficiency(soa::Join const& collisions, + soa::Join const& mcCollisions, + aod::McParticles const& mcParticles, + TracksWithMc const& tracksData) + { + auto hAssocTracks = registry.get(HIST("hAssocTracks")); + + /// loop over generated collisions + for (const auto& mcCollision : mcCollisions) { + + const auto groupedCollisions = collisions.sliceBy(collPerCollMc, mcCollision.globalIndex()); + const auto groupedMcParticles = mcParticles.sliceBy(perCollisionMc, mcCollision.globalIndex()); + + if (groupedCollisions.size() < 1) { // Skipping MC events that have no reconstructed collisions + continue; + } + if (groupedCollisions.size() > 1 && removeCollWSplitVtx) { // Skipping MC events that have more than one reconstructed collision + continue; + } + + /// loop over reconstructed collisions + for (const auto& collision : groupedCollisions) { + + // reco collision selection + if (useSel8ForEff && !collision.sel8()) { + continue; + } + if (std::abs(collision.posZ()) > cutCollPosZMc) { + continue; + } + if (selNoSameBunchPileUpColl && !(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { + continue; + } + if (!collision.has_mcCollision()) { + registry.fill(HIST("hFakeCollision"), 0.); + continue; + } + + float multiplicityReco = collision.multFT0M(); + float posZReco = collision.posZ(); + float multiplicityGen = mcCollision.multMCFT0A() + mcCollision.multMCFT0C(); // multFT0M = multFt0A + multFT0C + float posZGen = mcCollision.posZ(); + + const auto groupedTracks = tracksData.sliceBy(perCollision, collision.globalIndex()); + + // generated track loop + for (const auto& mcParticle : groupedMcParticles) { + if (mcParticle.isPhysicalPrimary() && ((std::abs(mcParticle.pdgCode()) == kElectron) || (std::abs(mcParticle.pdgCode()) == kMuonMinus) || (std::abs(mcParticle.pdgCode()) == kPiPlus) || (std::abs(mcParticle.pdgCode()) == kKPlus) || (std::abs(mcParticle.pdgCode()) == kProton))) { + if (mcParticle.pt() > ptTrackMin && mcParticle.pt() < ptTrackMax) { + hAssocTracks->Fill(kAssocTrackStepMcGen, mcParticle.eta(), mcParticle.pt(), multiplicityGen, posZGen); + if (std::abs(mcParticle.eta()) < etaTrackMax) { + hAssocTracks->Fill(kAssocTrackStepMcGenInAcceptance, mcParticle.eta(), mcParticle.pt(), multiplicityGen, posZGen); + registry.fill(HIST("hPtParticleAssocMcGen"), mcParticle.pt()); + if (std::abs(mcParticle.pdgCode()) == kPiPlus) { + registry.fill(HIST("hPtPrmPionMcGen"), mcParticle.pt()); + } else if (std::abs(mcParticle.pdgCode()) == kKPlus) { + registry.fill(HIST("hPtPrmKaonMcGen"), mcParticle.pt()); + } else if (std::abs(mcParticle.pdgCode()) == kProton) { + registry.fill(HIST("hPtPrmProtonMcGen"), mcParticle.pt()); + } else if (std::abs(mcParticle.pdgCode()) == kElectron) { + registry.fill(HIST("hPtPrmElectronMcGen"), mcParticle.pt()); + } else if (std::abs(mcParticle.pdgCode()) == kMuonMinus) { + registry.fill(HIST("hPtPrmMuonMcGen"), mcParticle.pt()); + } + if (separateTrackOrigins) { + int trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); + if (trackOrigin == RecoDecay::OriginType::Prompt) { // charm orgin + registry.fill(HIST("hPtPrmPromptPartMcGen"), mcParticle.pt()); + } else if (trackOrigin == RecoDecay::OriginType::NonPrompt) { // beauty origin + registry.fill(HIST("hPtPrmNonPromptPartMcGen"), mcParticle.pt()); + } + } + } + } + } + } + + // reconstructed track loop + for (const auto& track : groupedTracks) { + if (!track.isGlobalTrackWoDCA() || track.tpcNClsCrossedRows() < nTpcCrossedRaws) { + continue; + } + if (track.has_mcParticle()) { + hAssocTracks->Fill(kAssocTrackStepRecoMcMatch, track.eta(), track.pt(), multiplicityReco, posZReco); + auto mcParticle = track.template mcParticle_as(); + if (mcParticle.isPhysicalPrimary()) { + hAssocTracks->Fill(kAssocTrackStepRecoPrimaries, track.eta(), track.pt(), multiplicityReco, posZReco); + registry.fill(HIST("hPtParticleAssocMcRec"), track.pt()); + if ((std::abs(mcParticle.pdgCode()) == kElectron) || (std::abs(mcParticle.pdgCode()) == kMuonMinus) || (std::abs(mcParticle.pdgCode()) == kPiPlus) || (std::abs(mcParticle.pdgCode()) == kKPlus) || (std::abs(mcParticle.pdgCode()) == kProton)) { + hAssocTracks->Fill(kAssocTrackStepRecoSpecies, track.eta(), track.pt(), multiplicityReco, posZReco); + registry.fill(HIST("hPtParticleAssocSpecieMcRec"), track.pt()); + // check the pt spectra of mcParticle + registry.fill(HIST("hPtMcParticleAssocSpecieMcRec"), mcParticle.pt()); + if (std::abs(mcParticle.pdgCode()) == kPiPlus) { + registry.fill(HIST("hPtPrmPionMcRec"), track.pt()); + } else if (std::abs(mcParticle.pdgCode()) == kKPlus) { + registry.fill(HIST("hPtPrmKaonMcRec"), track.pt()); + } else if (std::abs(mcParticle.pdgCode()) == kProton) { + registry.fill(HIST("hPtPrmProtonMcRec"), track.pt()); + } else if (std::abs(mcParticle.pdgCode()) == kElectron) { + registry.fill(HIST("hPtPrmElectronMcRec"), track.pt()); + } else if (std::abs(mcParticle.pdgCode()) == kMuonMinus) { + registry.fill(HIST("hPtPrmMuonMcRec"), track.pt()); + } + // check track origin + if (separateTrackOrigins) { + int trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); + if (trackOrigin == RecoDecay::OriginType::Prompt) { // charm orgin + registry.fill(HIST("hPtPrmPromptPartMcRec"), track.pt()); + } else if (trackOrigin == RecoDecay::OriginType::NonPrompt) { // beauty origin + registry.fill(HIST("hPtPrmNonPromptPartMcRec"), track.pt()); + } + } + } + } + } else { + // fake track + registry.fill(HIST("hFakeTracks"), 0.); + } + } + + } // end loop reconstructed collision + } // end loop generated collisions + } + PROCESS_SWITCH(HfTaskCorrelationDsHadrons, processMcTrackEfficiency, "Process MC for calculating associated particle tracking efficiency", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/HFC/Tasks/taskCorrelationDstarHadrons.cxx b/PWGHF/HFC/Tasks/taskCorrelationDstarHadrons.cxx index 609f213ae3a..1e002d9118d 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationDstarHadrons.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationDstarHadrons.cxx @@ -14,6 +14,8 @@ /// \author Fabrizio Grosa , CERN /// \author Shyam Kumar +#include + // Framework #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" @@ -61,7 +63,7 @@ auto vecSidebandRightInnerDefault = std::vector{sidebandRightInnerDefaul const double sidebandRightOuterDefault[nBinsPtCorrelation] = {0.154, 0.154, 0.154, 0.154, 0.154, 0.154, 0.154, 0.154}; auto vecSidebandRightOuterDefault = std::vector{sidebandRightOuterDefault, sidebandRightOuterDefault + nBinsPtCorrelation}; -const int npTBinsEfficiency = o2::analysis::hf_cuts_dstar_to_d0_pi::nBinsPt; +const int npTBinsEfficiency = o2::analysis::hf_cuts_dstar_to_d0_pi::NBinsPt; std::vector vecEfficiencyDstarDefault(npTBinsEfficiency); // line # 76 in taskCorrelationDstarHadron.cxx; why (npTBinsEfficiency+1) ? // Dstar-Hadron correlation pair diff --git a/PWGHF/HFC/Tasks/taskCorrelationHfeHadrons.cxx b/PWGHF/HFC/Tasks/taskCorrelationHfeHadrons.cxx new file mode 100644 index 00000000000..44db8479632 --- /dev/null +++ b/PWGHF/HFC/Tasks/taskCorrelationHfeHadrons.cxx @@ -0,0 +1,113 @@ +// 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 taskCorrelationHfeHadrons.cxx +/// \brief HFE-Hadrons azimuthal correlations analysis task - data-like, MC-reco and MC-Gen analyses +/// \author Rashi Gupta , IIT Indore +/// \author Ravindra Singh , IIT Indore + +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/RecoDecay.h" +#include "PWGHF/HFC/DataModel/CorrelationTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::hf_correlation_electron_hadron; + +struct HfTaskCorrelationHfeHadrons { + // Configurables + // Deltaphi binning + Configurable nBinsDeltaPhi{"nBinsDeltaPhi", 32, "Bins for #Delta#varphi bins"}; + + HistogramConfigSpec hCorrelSpec{HistType::kTHnSparseD, {{30, 0., 30.}, {20, 0., 20.}, {nBinsDeltaPhi, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {50, -1.8, 1.8}}}; + + HistogramRegistry registry{ + "registry", + {{"hInclusiveEHCorrel", "Sparse for Delta phi and Delta eta Inclusive Electron with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", hCorrelSpec}, + {"hLikeSignEHCorrel", "Sparse for Delta phi and Delta eta Likesign Electronpair with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", hCorrelSpec}, + {"hUnLikeSignEHCorrel", "Sparse for Delta phi and Delta eta UnlikeSign Electron pair with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", hCorrelSpec}, + {"hMcGenInclusiveEHCorrel", "Sparse for Delta phi and Delta eta McGen Inclusive Electron with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", hCorrelSpec}, + {"hMcGenNonHfEHCorrel", "Sparse for Delta phi and Delta eta McGen Non HF Electron with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", hCorrelSpec}}}; + + void init(InitContext&) + { + registry.get(HIST("hInclusiveEHCorrel"))->Sumw2(); + registry.get(HIST("hLikeSignEHCorrel"))->Sumw2(); + registry.get(HIST("hUnLikeSignEHCorrel"))->Sumw2(); + registry.get(HIST("hMcGenInclusiveEHCorrel"))->Sumw2(); + registry.get(HIST("hMcGenNonHfEHCorrel"))->Sumw2(); + } + + // correlation for electron hadron + void process(aod::HfEHadronPair const& pairEntries) + { + double deltaPhi = -999; + double deltaEta = -999; + double ptHadron = -999; + double ptElectron = -999; + + for (const auto& pairEntry : pairEntries) { + + deltaPhi = pairEntry.deltaPhi(); + deltaEta = pairEntry.deltaEta(); + ptElectron = pairEntry.ptElectron(); + ptHadron = pairEntry.ptHadron(); + + registry.fill(HIST("hInclusiveEHCorrel"), ptElectron, ptHadron, deltaPhi, deltaEta); + if (pairEntry.isLSEHCorr() > 0) { + for (int i = 0; i < pairEntry.isLSEHCorr(); ++i) { + + registry.fill(HIST("hLikeSignEHCorrel"), ptElectron, ptHadron, deltaPhi, deltaEta); + } + } + if (pairEntry.isULSEHCorr() > 0) { + for (int i = 0; i < pairEntry.isULSEHCorr(); ++i) { + + registry.fill(HIST("hUnlikeSignEHCorrel"), ptElectron, ptHadron, deltaPhi, deltaEta); + } + } + } + } + + PROCESS_SWITCH(HfTaskCorrelationHfeHadrons, process, "Process ", false); + + void processMcGen(aod::HfEHadronMcPair const& McGenpairEntries) + { + double deltaPhi = -999; + double deltaEta = -999; + double ptHadron = -999; + double ptElectron = -999; + + for (const auto& pairEntry : McGenpairEntries) { + + deltaPhi = pairEntry.deltaPhi(); + deltaEta = pairEntry.deltaEta(); + ptElectron = pairEntry.ptElectron(); + ptHadron = pairEntry.ptHadron(); + + registry.fill(HIST("hMcGenInclusiveEHCorrel"), ptElectron, ptHadron, deltaPhi, deltaEta); + if (pairEntry.isNonHfEHCorr()) { + + registry.fill(HIST("hMcGenNonHfEHCorrel"), ptElectron, ptHadron, deltaPhi, deltaEta); + } + } + } + PROCESS_SWITCH(HfTaskCorrelationHfeHadrons, processMcGen, "Process for Mc Gen ", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/HFC/Tasks/taskCorrelationLcHadrons.cxx b/PWGHF/HFC/Tasks/taskCorrelationLcHadrons.cxx index 889ded1486e..2c7e3dd3e80 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationLcHadrons.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationLcHadrons.cxx @@ -14,53 +14,45 @@ /// \author Marianna Mazzilli /// \author Zhen Zhang +#include // std::shared_ptr +#include +#include +#include "CCDB/BasicCCDBManager.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" +#include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/Utils/utilsAnalysis.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/HFC/Utils/utilsCorrelations.h" using namespace o2; +using namespace o2::constants::math; +using namespace o2::constants::physics; using namespace o2::framework; using namespace o2::framework::expressions; - -/// -/// Returns deltaPhi value in range [-pi/2., 3.*pi/2], typically used for correlation studies -/// -double getDeltaPhi(double phiLc, double phiHadron) -{ - return RecoDecay::constrainAngle(phiHadron - phiLc, -o2::constants::math::PIHalf); -} - -/// -/// Returns phi of candidate/particle evaluated from x and y components of segment connecting primary and secondary vertices -/// -double evaluatePhiByVertex(double xVertex1, double xVertex2, double yVertex1, double yVertex2) -{ - return RecoDecay::phi(xVertex2 - xVertex1, yVertex2 - yVertex1); -} +using namespace o2::analysis::hf_correlations; // string definitions, used for histogram axis labels const TString stringPtLc = "#it{p}_{T}^{#Lambda_c} (GeV/#it{c});"; const TString stringPtHadron = "#it{p}_{T}^{Hadron} (GeV/#it{c});"; -const TString stringPoolBin = "poolBin;"; +const TString stringSign = "pairSign;"; +const TString stringMass = "M_{pK#pi} (GeV/#it{c^2});"; const TString stringDeltaEta = "#it{#eta}^{Hadron}-#it{#eta}^{#Lambda_c};"; const TString stringDeltaPhi = "#it{#varphi}^{Hadron}-#it{#varphi}^{#Lambda_c} (rad);"; const TString stringLcHadron = "#Lambda_c,Hadron candidates "; const TString stringSignal = "signal region;"; +const TString stringSignMass = "sign and invMass;"; const TString stringSideband = "sidebands;"; -const TString stringMcParticles = "Mc gen - #Lambda_c,Hadron particles;"; -const TString stringMcReco = "Mc reco - #Lambda_c,Hadron candidates "; - -// histogram axes definition -AxisSpec axisDeltaEta = {100, -2., 2.}; -AxisSpec axisDeltaPhi = {64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}; -AxisSpec axisPtLc = {10, 0., 10.}; -AxisSpec axisPtHadron = {11, 0., 11.}; -AxisSpec axisPoolBin = {9, 0., 9.}; +const TString stringMcParticles = "MC gen - #Lambda_c,Hadron particles;"; +const TString stringMcReco = "MC reco - #Lambda_c,Hadron candidates "; +const TString stringMcRecoLcPrompt = "MC reco, prompt #Lambda_c;"; +const TString stringMcGenLcPrompt = "MC gen, prompt #Lambda_c;"; +const TString stringMcRecoLcFd = "MC reco, non-prompt #Lambda_c;"; +const TString stringMcGenLcFd = "MC gen, non-prompt #Lambda_c;"; // definition of vectors for standard ptbin and invariant mass configurables const int nPtBinsCorrelations = 8; @@ -78,16 +70,28 @@ auto vecSidebandLeftInner = std::vector{sidebandLeftInnerDefault, sideba auto vecSidebandLeftOuter = std::vector{sidebandLeftOuterDefault, sidebandLeftOuterDefault + nPtBinsCorrelations}; auto vecSidebandRightInner = std::vector{sidebandRightInnerDefault, sidebandRightInnerDefault + nPtBinsCorrelations}; auto vecSidebandRightOuter = std::vector{sidebandRightOuterDefault, sidebandRightOuterDefault + nPtBinsCorrelations}; -const int nPtBinsEfficiency = o2::analysis::hf_cuts_lc_to_p_k_pi::nBinsPt; -const double efficiencyLcDefault[nPtBinsEfficiency] = {}; -auto vecEfficiencyLc = std::vector{efficiencyLcDefault, efficiencyLcDefault + nPtBinsEfficiency}; /// Lc-Hadron correlation pair filling task, from pair tables - for real data and data-like analysis (i.e. reco-level w/o matching request via Mc truth) struct HfTaskCorrelationLcHadrons { - // Pt ranges for correlation plots: the default values are those embedded in hf_cuts_lc_to_p_k_pi (i.e. the mass Pt bins), but can be redefined via json files + Configurable fillHistoData{"fillHistoData", true, "Flag for filling histograms in data processes"}; + Configurable fillHistoMcRec{"fillHistoMcRec", true, "Flag for filling histograms in MC Rec processes"}; + Configurable fillHistoMcGen{"fillHistoMcGen", true, "Flag for filling histograms in MC Gen processes"}; + Configurable fillHistoMcEff{"fillHistoMcEff", true, "Flag for filling histograms in efficiency processes"}; Configurable applyEfficiency{"applyEfficiency", 1, "Flag for applying efficiency weights"}; + Configurable loadAccXEffFromCCDB{"loadAccXEffFromCCDB", false, "Flag for loading efficiency distributions from CCDB"}; + Configurable selectionFlagLc{"selectionFlagLc", 1, "Selection Flag for Lc"}; + Configurable selNoSameBunchPileUpColl{"selNoSameBunchPileUpColl", true, "Flag for rejecting the collisions associated with the same bunch crossing"}; + Configurable> classMl{"classMl", {0, 1, 2}, "Indexes of ML scores to be stored. Three indexes max."}; + Configurable> mlOutputPrompt{"mlOutputPrompt", {0.5, 0.5, 0.5, 0.5}, "Machine learning scores for prompt"}; + Configurable> mlOutputBkg{"mlOutputBkg", {0.5, 0.5, 0.5, 0.5}, "Machine learning scores for bkg"}; + // Pt ranges for correlation plots: the default values are those embedded in hf_cuts_lc_to_p_k_pi (i.e. the mass Pt bins), but can be redefined via json files Configurable> binsPtCorrelations{"binsPtCorrelations", std::vector{vecBinsPtCorrelations}, "Pt bin limits for correlation plots"}; - Configurable> binsPtEfficiency{"binsPtEfficiency", std::vector{o2::analysis::hf_cuts_lc_to_p_k_pi::vecBinsPt}, "Pt bin limits for efficiency"}; + Configurable> binsPtHadron{"binsPtHadron", std::vector{0.3, 2., 4., 8., 12., 50.}, "Pt bin limits for assoc particle efficiency"}; + Configurable> binsPtEfficiencyLc{"binsPtEfficiencyLc", std::vector{o2::analysis::hf_cuts_lc_to_p_k_pi::vecBinsPt}, "Pt bin limits for efficiency"}; + Configurable> binsPtEfficiencyHad{"binsPtEfficiencyHad", std::vector{0.3, 2., 4., 8., 12., 50.}, "pT bin limits for associated particle efficiency"}; + Configurable> efficiencyLc{"efficiencyLc", {1., 1., 1., 1., 1., 1.}, "efficiency values for prompt Lc"}; + Configurable> efficiencyFdLc{"efficiencyFdLc", {1., 1., 1., 1., 1., 1.}, "efficiency values for beauty feed-down Lc"}; + Configurable> efficiencyHad{"efficiencyHad", {1., 1., 1., 1., 1., 1.}, "efficiency values for associated particles"}; // signal and sideband region edges, to be defined via json file (initialised to empty) Configurable> signalRegionInner{"signalRegionInner", std::vector{vecSignalRegionInner}, "Inner values of signal region vs Pt"}; Configurable> signalRegionOuter{"signalRegionOuter", std::vector{vecSignalRegionOuter}, "Outer values of signal region vs Pt"}; @@ -95,95 +99,417 @@ struct HfTaskCorrelationLcHadrons { Configurable> sidebandLeftOuter{"sidebandLeftOuter", std::vector{vecSidebandLeftOuter}, "Outer values of left sideband vs Pt"}; Configurable> sidebandRightInner{"sidebandRightInner", std::vector{vecSidebandRightInner}, "Inner values of right sideband vs Pt"}; Configurable> sidebandRightOuter{"sidebandRightOuter", std::vector{vecSidebandRightOuter}, "Outer values of right sideband vs Pt"}; - Configurable> efficiencyLc{"efficiencyLc", std::vector{vecEfficiencyLc}, "Efficiency values for Lc "}; - - using LcHadronPairFull = soa::Join; - - HistogramRegistry registry{ - "registry", - { - {"hDeltaEtaPtIntSignalRegion", stringLcHadron + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSignalRegion", stringLcHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hCorrel2DPtIntSignalRegion", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hCorrel2DVsPtSignalRegion", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + stringPoolBin + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}}}}, // note: axes 3 and 4 (the Pt) are updated in the init() - {"hDeltaEtaPtIntSidebands", stringLcHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSidebands", stringLcHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hCorrel2DPtIntSidebands", stringLcHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hCorrel2DVsPtSidebands", stringLcHadron + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + stringPoolBin + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}}}}, // note: axes 3 and 4 (the Pt) are updated in the init() - {"hDeltaEtaPtIntSignalRegionMcRec", stringLcHadron + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSignalRegionMcRec", stringLcHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hCorrel2DPtIntSignalRegionMcRec", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hCorrel2DVsPtSignalRegionMcRec", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + stringPoolBin + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}}}}, - {"hCorrel2DVsPtSignalMcRec", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + stringPoolBin + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}}}}, - {"hCorrel2DVsPtBkgMcRec", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + stringPoolBin + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}}}}, - {"hDeltaEtaPtIntSidebandsMcRec", stringLcHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntSidebandsMcRec", stringLcHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hCorrel2DPtIntSidebandsMcRec", stringLcHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hCorrel2DVsPtSidebandsMcRec", stringLcHadron + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + stringPoolBin + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}}}}, - {"hDeltaEtaPtIntMcGen", stringMcParticles + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}}, - {"hDeltaPhiPtIntMcGen", stringMcParticles + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}}, - {"hCorrel2DPtIntMcGen", stringMcParticles + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}}, - {"hCorrel2DVsPtMcGen", stringMcParticles + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPoolBin + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}}}}, // note: axes 3 and 4 (the Pt) are updated in the init() - }}; + Configurable isTowardTransverseAway{"isTowardTransverseAway", false, "Divide into three regions: toward, transverse, and away"}; + Configurable leadingParticlePtMin{"leadingParticlePtMin", 0., "Min for leading particle pt"}; + Configurable dcaXYTrackMax{"dcaXYTrackMax", 1., "max. DCA_xy of tracks"}; + Configurable dcaZTrackMax{"dcaZTrackMax", 1., "max. DCA_z of tracks"}; + Configurable etaTrackMax{"etaTrackMax", 0.8, "max. eta of tracks"}; + Configurable ptCandMin{"ptCandMin", 1., "min. cand. pT"}; + Configurable ptCandMax{"ptCandMax", 50., "max. cand pT"}; + Configurable ptTrackMin{"ptTrackMin", 0.3, "min. track pT"}; + Configurable ptTrackMax{"ptTrackMax", 50., "max. track pT"}; + Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity"}; + Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen. cand. rapidity"}; + Configurable ptDaughterMin{"ptDaughterMin", 0.1, "min. daughter pT"}; + Configurable activateQA{"activateQA", false, "Flag to enable debug histogram"}; + Configurable nTpcCrossedRaws{"nTpcCrossedRaws", 70, "Number of crossed TPC Rows"}; + // sign and invMasss + Configurable fillSignAndMass{"fillSignAndMass", false, "flag to select Lc-h corr with Lc invarient mass and sign of pairs"}; + Configurable calSign{"calSign", false, "flag to calculate sign of pairs"}; + Configurable fillSign{"fillSign", false, "flag to fill sign of pairs in ThnSparse"}; + + // CCDB configuration + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable associatedEffCcdbPath{"associatedEffCcdbPath", "", "CCDB path for associated efficiency"}; + Configurable promptEffCcdbPath{"promptEffCcdbPath", "", "CCDB path for trigger efficiency"}; + Configurable fdEffCcdbPath{"fdEffCcdbPath", "", "CCDB path for trigger efficiency"}; + Configurable timestampCcdb{"timestampCcdb", -1, "timestamp of the efficiency files used to query in CCDB"}; + Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + + std::shared_ptr mEfficiencyPrompt = nullptr; + std::shared_ptr mEfficiencyFD = nullptr; + std::shared_ptr mEfficiencyAssociated = nullptr; + + HfHelper hfHelper; + Service ccdb; + + enum CandidateStep { kCandidateStepMcGenAll = 0, + kCandidateStepMcGenLcToPKPi, + kCandidateStepMcCandInAcceptance, + kCandidateStepMcDaughtersInAcceptance, + kCandidateStepMcReco, + kCandidateStepMcRecoInAcceptance, + kCandidateNSteps }; + + using LcHadronPair = soa::Join; + using LcHadronPairFullWithMl = soa::Join; + using CandLcMcReco = soa::Filtered>; + using CandLcMcGen = soa::Join; + using TracksWithMc = soa::Filtered>; // trackFilter applied + + Filter lcFilter = ((o2::aod::hf_track_index::hfflag & static_cast(1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) != static_cast(0)) && (aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLc || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLc); + Filter trackFilter = (nabs(aod::track::eta) < etaTrackMax) && (aod::track::pt > ptTrackMin) && (aod::track::pt < ptTrackMax) && (nabs(aod::track::dcaXY) < dcaXYTrackMax) && (nabs(aod::track::dcaZ) < dcaZTrackMax); + + // configurable axis definition + ConfigurableAxis binsMassLc{"binsMassLc", {200, 1.98, 2.58}, "inv. mass (p K #pi) (GeV/#it{c}^{2})"}; + ConfigurableAxis binsBdtScore{"binsBdtScore", {100, 0., 1.}, "Bdt output scores"}; + ConfigurableAxis binsEta{"binsEta", {100, -2., 2.}, "#it{#eta}"}; + ConfigurableAxis binsPhi{"binsPhi", {64, -PIHalf, 3. * PIHalf}, "#it{#varphi}"}; + ConfigurableAxis binsMultFT0M{"binsMultFT0M", {600, 0., 8000.}, "Multiplicity as FT0M signal amplitude"}; + ConfigurableAxis binsPoolBin{"binsPoolBin", {9, 0., 9.}, "PoolBin"}; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext&) { - // redefinition of Pt axes for THnSparse holding correlation entries - int nBinsPtAxis = binsPtCorrelations->size() - 1; - const double* valuesPtAxis = binsPtCorrelations->data(); - - registry.get(HIST("hCorrel2DVsPtSignalRegion"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtSidebands"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtSignalRegion"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSidebands"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSignalRegionMcRec"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtSidebandsMcRec"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtSignalRegionMcRec"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSidebandsMcRec"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtSignalMcRec"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtSignalMcRec"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtBkgMcRec"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtBkgMcRec"))->Sumw2(); - registry.get(HIST("hCorrel2DVsPtMcGen"))->GetAxis(2)->Set(nBinsPtAxis, valuesPtAxis); - registry.get(HIST("hCorrel2DVsPtMcGen"))->Sumw2(); + // Axis definition + AxisSpec axisMassLc = {binsMassLc, "inv. mass (p K #pi) (GeV/#it{c}^{2})"}; + AxisSpec axisPtCorr = {(std::vector)binsPtCorrelations, "#it{p}_{T}^{#Lambda_c} (GeV/#it{c})"}; + AxisSpec axisPtLc = {(std::vector)binsPtEfficiencyLc, "#it{p}_{T}^{#Lambda_c} (GeV/#it{c})"}; + AxisSpec axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; + AxisSpec axisDeltaEta = {binsEta, "#it{#eta}^{Hadron}-#it{#eta}^{#Lambda_c}"}; + AxisSpec axisDeltaPhi = {binsPhi, "#it{#varphi}^{Hadron}-#it{#varphi}^{#Lambda_c} (rad)"}; + AxisSpec axisPtHadron = {(std::vector)binsPtHadron, "#it{p}_{T}^{Hadron} (GeV/#it{c})"}; + AxisSpec axisPoolBin = {binsPoolBin, "poolBin"}; + AxisSpec axisLcPrompt = {2, -0.5, 1.5, "Prompt #Lambda_c"}; + AxisSpec axisBdtScore = {binsBdtScore, "Bdt score"}; + AxisSpec axisCorrelationState = {2, 0., 2., ""}; + AxisSpec axisSignPair = {4, 1., 5.}; + // Histograms for data analysis + registry.add("hBdtScorePrompt", "Lc BDT prompt score", {HistType::kTH1F, {axisBdtScore}}); + registry.add("hBdtScoreBkg", "Lc BDT bkg score", {HistType::kTH1F, {axisBdtScore}}); + registry.add("hMassLcVsPt", "Lc candidates massVsPt", {HistType::kTH2F, {{axisMassLc}, {axisPtLc}}}); + registry.add("hMassLcVsPtWoEff", "Lc candidates massVsPt without efficiency", {HistType::kTH2F, {{axisMassLc}, {axisPtLc}}}); + if (fillHistoData) { + registry.add("hDeltaEtaPtIntSignalRegion", stringLcHadron + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSignalRegion", stringLcHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSignalRegion", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hDeltaEtaPtIntSidebands", stringLcHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebands", stringLcHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSidebands", stringLcHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSidebands", stringLcHadron + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSidebandLeft", stringLcHadron + "Left" + stringSideband + stringDeltaEta, {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandLeft", stringLcHadron + "Left" + stringSideband + stringDeltaPhi, {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hDeltaEtaPtIntSidebandRight", stringLcHadron + "Right" + stringSideband + stringDeltaEta, {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandRight", stringLcHadron + "Right" + stringSideband + stringDeltaPhi, {HistType::kTH1F, {axisDeltaPhi}}); + + if (!fillSign) { + registry.add("hCorrel2DVsPtSidebandLeft", stringLcHadron + "Left" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSidebandRight", stringLcHadron + "Right" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignalRegion", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisPoolBin}}}); + registry.get(HIST("hCorrel2DVsPtSidebandLeft"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandRight"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalRegion"))->Sumw2(); + + } else { + registry.add("hCorrel2DVsPtSignSidebandLeft", stringLcHadron + "Left" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + stringSign + "entries", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisSignPair}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignSidebandRight", stringLcHadron + "Right" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + stringSign + "entries", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisSignPair}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignSignalRegion", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + stringSign + "entries", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisSignPair}, {axisPoolBin}}}); + registry.get(HIST("hCorrel2DVsPtSignSidebandLeft"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignSidebandRight"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignSignalRegion"))->Sumw2(); + } + // Toward Transverse Away + registry.add("hToward", "Toward invmass; ptLc; correlationState;entries", {HistType::kTH3F, {{axisMassLc}, {axisPtLc}, {axisCorrelationState}}}); + registry.add("hTransverse", "Transverse invmass; ptLc; correlationState;entries", {HistType::kTH3F, {{axisMassLc}, {axisPtLc}, {axisCorrelationState}}}); + registry.add("hAway", "Away invmass; ptLc; correlationState;entries", {HistType::kTH3F, {{axisMassLc}, {axisPtLc}, {axisCorrelationState}}}); + + registry.get(HIST("hCorrel2DVsPtSidebands"))->Sumw2(); + + if (fillSignAndMass) { + registry.add("hCorrel2DVsPtSignMass", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + stringSignMass + "entries", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisMassLc}, {axisSignPair}, {axisPoolBin}}}); + registry.get(HIST("hCorrel2DVsPtSignMass"))->Sumw2(); + } + } + // Histograms for MC Reco analysis + if (fillHistoMcRec) { + registry.add("hMassPromptLcVsPt", "Lc prompt candidates mass Vs Pt", {HistType::kTH2F, {{axisMassLc}, {axisPtLc}}}); + registry.add("hMassNonPromptLcVsPt", "Lc non prompt candidates mass Vs Pt", {HistType::kTH2F, {{axisMassLc}, {axisPtLc}}}); + registry.add("hDeltaEtaPtIntSignalRegionMcRec", stringLcHadron + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSignalRegionMcRec", stringLcHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hDeltaEtaPtIntSidebandsMcRec", stringLcHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hCorrel2DPtIntSignalRegionMcRec", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hDeltaPhiPtIntSidebandsMcRec", stringLcHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSidebandsMcRec", stringLcHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSidebandsMcRec", stringLcHadron + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtPhysicalPrimaryMcRec", stringLcHadron + "(only true primary particles)" + stringSignal, {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisLcPrompt}, {axisPoolBin}}}); + registry.add("hDeltaEtaPtIntSidebandLeftMcRec", stringLcHadron + "Left" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandLeftMcRec", stringLcHadron + "Left" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hDeltaEtaPtIntSidebandRightMcRec", stringLcHadron + "Right" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandRightMcRec", stringLcHadron + "Right" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTH1F, {axisDeltaPhi}}); + + if (!fillSign) { + registry.add("hCorrel2DVsPtSidebandLeftMcRec", stringLcHadron + "Left" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSidebandRightMcRec", stringLcHadron + "Right" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignalRegionPromptLcPromptHadronMcRec", stringLcHadron + "signal region PromptLc - Prompt Track MC reco", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignalRegionNonPromptLcNonPromptHadronMcRec", stringLcHadron + " signal region PromptLc - NonPrompt Track MC reco", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignalMcRec", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignalRegionMcRec", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisLcPrompt}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtBkgMcRec", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisPoolBin}}}); + + registry.get(HIST("hCorrel2DVsPtSidebandLeftMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandRightMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalRegionPromptLcPromptHadronMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalRegionNonPromptLcNonPromptHadronMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalRegionMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtBkgMcRec"))->Sumw2(); + + } else { + registry.add("hCorrel2DVsPtSignSidebandLeftMcRec", stringLcHadron + "Left" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + stringSign + "entries", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisSignPair}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignSidebandRightMcRec", stringLcHadron + "Right" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + stringSign + "entries", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisSignPair}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignSignalRegionPromptLcPromptHadronMcRec", stringLcHadron + "signal region PromptLc - Prompt Track MC reco", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisSignPair}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignSignalRegionNonPromptLcNonPromptHadronMcRec", stringLcHadron + " signal region PromptLc - NonPrompt Track MC reco", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisSignPair}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignSignalMcRec", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + stringSign + "entries", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisSignPair}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignSignalRegionMcRec", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + stringSign + "entries", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisSignPair}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignBkgMcRec", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + stringSign + "entries", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisSignPair}, {axisPoolBin}}}); + + registry.get(HIST("hCorrel2DVsPtSignSidebandLeftMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignSidebandRightMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignSignalMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignSignalRegionPromptLcPromptHadronMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignSignalRegionNonPromptLcNonPromptHadronMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignSignalRegionMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignBkgMcRec"))->Sumw2(); + } + + if (fillSignAndMass) { + registry.add("hCorrel2DVsPtSignMassMcRec", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + stringSignMass + "entries", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisMassLc}, {axisSignPair}, {axisPoolBin}}}); + registry.get(HIST("hCorrel2DVsPtSignMassMcRec"))->Sumw2(); + } + + // Toward Transverse Away for McRec + registry.add("hTowardRec", "Toward invmass; ptLc; correlationState;entries", {HistType::kTH3F, {{axisMassLc}, {axisPtLc}, {axisCorrelationState}}}); + registry.add("hTransverseRec", "Transverse invmass; ptLc; correlationState;entries", {HistType::kTH3F, {{axisMassLc}, {axisPtLc}, {axisCorrelationState}}}); + registry.add("hAwayRec", "Away invmass; ptLc; correlationState;entries", {HistType::kTH3F, {{axisMassLc}, {axisPtLc}, {axisCorrelationState}}}); + + registry.get(HIST("hCorrel2DVsPtSidebandsMcRec"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtPhysicalPrimaryMcRec"))->Sumw2(); + } + // Histograms for MC Gen analysis + if (fillHistoMcGen) { + registry.add("hDeltaEtaPtIntMcGen", stringMcParticles + stringDeltaEta + "entries", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntMcGen", stringMcParticles + stringDeltaPhi + "entries", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntMcGen", stringMcParticles + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + + if (!fillSign) { + registry.add("hCorrel2DVsPtMcGen", stringMcParticles + stringDeltaPhi + stringDeltaEta + stringPtLc + "entries", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtMcGenPrompt", stringLcHadron + " Prompt MC Gen", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtMcGenPromptLcPromptHadron", stringLcHadron + "prompt Lc prompt h MC Gen", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtMcGenNonPromptLcNonPromptHadron", stringLcHadron + " non prompt Lc non prompt h MC Gen", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtMcGenNonPrompt", stringLcHadron + " NonPrompt MC Gen", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}}}); + + registry.get(HIST("hCorrel2DVsPtMcGenPrompt"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtMcGenPromptLcPromptHadron"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtMcGenNonPromptLcNonPromptHadron"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtMcGenNonPrompt"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtMcGen"))->Sumw2(); + } else { + registry.add("hCorrel2DVsPtSignMcGenPrompt", stringLcHadron + " Prompt MC Gen", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisSignPair}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignMcGenPromptLcPromptHadron", stringLcHadron + "prompt Lc prompt h MC Gen", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisSignPair}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignMcGenNonPromptLcNonPromptHadron", stringLcHadron + " non prompt Lc non prompt h MC Gen", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisSignPair}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignMcGenNonPrompt", stringLcHadron + " NonPrompt MC Gen", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisSignPair}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSignMcGen", stringMcParticles + stringDeltaPhi + stringDeltaEta + stringPtLc + stringSign + "entries", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisSignPair}, {axisPoolBin}}}); + + registry.get(HIST("hCorrel2DVsPtSignMcGenPrompt"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignMcGenPromptLcPromptHadron"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignMcGenNonPromptLcNonPromptHadron"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignMcGenNonPrompt"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignMcGen"))->Sumw2(); + } + + // Toward Transverse Away for McGen + registry.add("hTowardGen", "Toward invmass; ptLc; correlationState;entries", {HistType::kTH3F, {{axisMassLc}, {axisPtLc}, {axisCorrelationState}}}); + registry.add("hTransverseGen", "Transverse invmass; ptLc; correlationState;entries", {HistType::kTH3F, {{axisMassLc}, {axisPtLc}, {axisCorrelationState}}}); + registry.add("hAwayGen", "Away invmass; ptLc; correlationState;entries", {HistType::kTH3F, {{axisMassLc}, {axisPtLc}, {axisCorrelationState}}}); + } + // Histograms for efficiencies + registry.add("Efficiency/hPtCandMcRecPrompt", stringMcRecoLcPrompt + stringPtLc, {HistType::kTH1F, {axisPtLc}}); + registry.add("Efficiency/hPtCandMcGenPrompt", stringMcGenLcPrompt + stringPtLc, {HistType::kTH1F, {axisPtLc}}); + registry.add("Efficiency/hPtCandMcRecNonPrompt", stringMcRecoLcFd + stringPtLc, {HistType::kTH1F, {axisPtLc}}); + registry.add("Efficiency/hPtCandMcGenNonPrompt", stringMcGenLcFd + stringPtLc, {HistType::kTH1F, {axisPtLc}}); + registry.add("Efficiency/hPtCandMcGenDaughterInAcc", stringMcGenLcFd + stringPtLc, {HistType::kTH1F, {axisPtLc}}); + + auto hCandidates = registry.add("hCandidates", "Candidate count at different steps", {HistType::kStepTHnF, {axisPtLc, axisMultFT0M, {RecoDecay::OriginType::NonPrompt + 1, +RecoDecay::OriginType::None - 0.5, +RecoDecay::OriginType::NonPrompt + 0.5}}, kCandidateNSteps}); + hCandidates->GetAxis(0)->SetTitle("#it{p}_{T} (GeV/#it{c})"); + hCandidates->GetAxis(1)->SetTitle("multiplicity"); + hCandidates->GetAxis(2)->SetTitle("Charm hadron origin"); + + // Loading efficiency histograms from CCDB + if (applyEfficiency && loadAccXEffFromCCDB) { + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(ccdbNoLaterThan.value); + + mEfficiencyPrompt = std::shared_ptr(ccdb->getForTimeStamp(promptEffCcdbPath, timestampCcdb)); + if (mEfficiencyPrompt == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", promptEffCcdbPath.value.c_str()); + } + LOGF(info, "Loaded trigger efficiency (prompt Lc) histogram from %s", promptEffCcdbPath.value.c_str()); + + mEfficiencyFD = std::shared_ptr(ccdb->getForTimeStamp(fdEffCcdbPath, timestampCcdb)); + if (mEfficiencyFD == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", fdEffCcdbPath.value.c_str()); + } + LOGF(info, "Loaded feed-down Lc efficiency histogram from %s", fdEffCcdbPath.value.c_str()); + + mEfficiencyAssociated = std::shared_ptr(ccdb->getForTimeStamp(associatedEffCcdbPath, timestampCcdb)); + if (mEfficiencyAssociated == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for associated particles from %s", associatedEffCcdbPath.value.c_str()); + } + LOGF(info, "Loaded associated efficiency histogram from %s", associatedEffCcdbPath.value.c_str()); + } + + if (activateQA) { + const int regionLimits = 6; + std::string labels[regionLimits] = {"SigReg Left", "SigReg Right", "Left SB Low", "Left SB Up", "Right SB Low", "Right SB Up"}; + static const AxisSpec axisSidebandLimits = {regionLimits, 0.5, 6.5, ""}; + auto hSigSidebandLimits = registry.add("Inputs/hSigSidebandLimits", "Signal and Sideband Limits;;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisSidebandLimits, {(std::vector)binsPtCorrelations, "#it{p}_{T} (GeV/#it{c})"}}}); + for (int iLim = 0; iLim < regionLimits; iLim++) { + hSigSidebandLimits->GetXaxis()->SetBinLabel(iLim + 1, labels[iLim].data()); + } + for (size_t iPtLc = 0; iPtLc < binsPtCorrelations->size() - 1; iPtLc++) { + hSigSidebandLimits->SetBinContent(1, iPtLc + 1, signalRegionInner->at(iPtLc)); + hSigSidebandLimits->SetBinContent(2, iPtLc + 1, signalRegionOuter->at(iPtLc)); + hSigSidebandLimits->SetBinContent(3, iPtLc + 1, sidebandLeftOuter->at(iPtLc)); + hSigSidebandLimits->SetBinContent(4, iPtLc + 1, sidebandLeftInner->at(iPtLc)); + hSigSidebandLimits->SetBinContent(5, iPtLc + 1, sidebandRightInner->at(iPtLc)); + hSigSidebandLimits->SetBinContent(6, iPtLc + 1, sidebandRightOuter->at(iPtLc)); + } + } } - void processData(LcHadronPairFull const& pairEntries) + void processData(LcHadronPairFullWithMl const& pairEntries, aod::LcRecoInfo const& candidates) { + for (const auto& candidate : candidates) { + float massLc = candidate.mLc(); + float ptLc = std::abs(candidate.ptLc()); + float bdtScorePrompt = candidate.mlScorePrompt(); + float bdtScoreBkg = candidate.mlScoreBkg(); + int effBinLc = o2::analysis::findBin(binsPtEfficiencyLc, ptLc); + + // reject entries outside Pt ranges of interest + if (ptLc < binsPtEfficiencyLc->front() || ptLc > binsPtEfficiencyLc->back()) { + continue; + } + + if (bdtScorePrompt < mlOutputPrompt->at(effBinLc) || bdtScoreBkg > mlOutputBkg->at(effBinLc)) { + continue; + } + double efficiencyWeightLc = 1.; + if (applyEfficiency) { + efficiencyWeightLc = 1. / efficiencyLc->at(o2::analysis::findBin(binsPtEfficiencyLc, ptLc)); + if (loadAccXEffFromCCDB) { + efficiencyWeightLc = 1. / mEfficiencyPrompt->GetBinContent(mEfficiencyPrompt->FindBin(ptLc)); + } + } + registry.fill(HIST("hMassLcVsPt"), massLc, ptLc, efficiencyWeightLc); + registry.fill(HIST("hMassLcVsPtWoEff"), massLc, ptLc); + registry.fill(HIST("hBdtScorePrompt"), bdtScorePrompt); + registry.fill(HIST("hBdtScoreBkg"), bdtScoreBkg); + } + for (const auto& pairEntry : pairEntries) { // define variables for widely used quantities - double deltaPhi = pairEntry.deltaPhi(); - double deltaEta = pairEntry.deltaEta(); - double ptLc = pairEntry.ptLc(); - double ptHadron = pairEntry.ptHadron(); + float deltaPhi = pairEntry.deltaPhi(); + float deltaEta = pairEntry.deltaEta(); + double ptLc = std::abs(pairEntry.ptLc()); + double ptHadron = std::abs(pairEntry.ptHadron()); + float bdtScorePrompt = pairEntry.mlScorePrompt(); + float bdtScoreBkg = pairEntry.mlScoreBkg(); + float trackDcaXY = pairEntry.trackDcaXY(); + float trackDcaZ = pairEntry.trackDcaZ(); + int trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); + int poolBin = pairEntry.poolBin(); double massLc = pairEntry.mLc(); - int effBinLc = o2::analysis::findBin(binsPtEfficiency, ptLc); + int effBinLc = o2::analysis::findBin(binsPtEfficiencyLc, ptLc); int ptBinLc = o2::analysis::findBin(binsPtCorrelations, ptLc); - int poolBin = pairEntry.poolBin(); + bool isAutoCorrelated = pairEntry.isAutoCorrelated(); + int signPair = 0; // reject entries outside Pt ranges of interest if (ptBinLc < 0 || effBinLc < 0) { continue; } - if (ptHadron > 10.0) { - ptHadron = 10.5; + + if (bdtScorePrompt < mlOutputPrompt->at(effBinLc) || bdtScoreBkg > mlOutputBkg->at(effBinLc)) { + continue; + } + if (trackDcaXY > dcaXYTrackMax || trackDcaZ > dcaZTrackMax || trackTpcCrossedRows < nTpcCrossedRaws) { + continue; } + double efficiencyWeight = 1.; - double efficiencyHadron = 1.; // Note: To be implemented later on if (applyEfficiency) { - efficiencyWeight = 1. / (efficiencyLc->at(effBinLc) * efficiencyHadron); + efficiencyWeight = 1. / (efficiencyLc->at(effBinLc) * efficiencyHad->at(o2::analysis::findBin(binsPtEfficiencyHad, ptHadron))); + if (loadAccXEffFromCCDB) { + efficiencyWeight = 1. / (mEfficiencyPrompt->GetBinContent(mEfficiencyPrompt->FindBin(ptLc)) * mEfficiencyAssociated->GetBinContent(mEfficiencyAssociated->FindBin(ptHadron))); + } + } + + // Divide into three regions: toward, transverse, and away + if (isTowardTransverseAway) { + if (ptHadron < leadingParticlePtMin) { + continue; + } + Region region = getRegion(deltaPhi); + switch (region) { + case Toward: + registry.fill(HIST("hToward"), massLc, ptLc, isAutoCorrelated, efficiencyWeight); + break; + case Away: + registry.fill(HIST("hAway"), massLc, ptLc, isAutoCorrelated, efficiencyWeight); + break; + case Transverse: + registry.fill(HIST("hTransverse"), massLc, ptLc, isAutoCorrelated, efficiencyWeight); + break; + default: + break; + } + } + + if (calSign) { + signPair = signCalulation(pairEntry.ptLc(), pairEntry.ptHadron()); } + if (fillSignAndMass) { + registry.fill(HIST("hCorrel2DVsPtSignMass"), deltaPhi, deltaEta, ptLc, ptHadron, massLc, signPair, poolBin, efficiencyWeight); + } + // check if correlation entry belongs to signal region, sidebands or is outside both, and fill correlation plots if (massLc > signalRegionInner->at(ptBinLc) && massLc < signalRegionOuter->at(ptBinLc)) { // in signal region - registry.fill(HIST("hCorrel2DVsPtSignalRegion"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); + if (fillSign) { + registry.fill(HIST("hCorrel2DVsPtSignSignalRegion"), deltaPhi, deltaEta, ptLc, ptHadron, signPair, poolBin, efficiencyWeight); + } else { + registry.fill(HIST("hCorrel2DVsPtSignalRegion"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); + } registry.fill(HIST("hCorrel2DPtIntSignalRegion"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSignalRegion"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSignalRegion"), deltaPhi, efficiencyWeight); } - - if ((massLc > sidebandLeftOuter->at(ptBinLc) && massLc < sidebandLeftInner->at(ptBinLc)) || - (massLc > sidebandRightInner->at(ptBinLc) && massLc < sidebandRightOuter->at(ptBinLc))) { - // in sideband region + // in sideband left region + if (massLc > sidebandLeftOuter->at(ptBinLc) && massLc < sidebandLeftInner->at(ptBinLc)) { + if (fillSign) { + registry.fill(HIST("hCorrel2DVsPtSignSidebandLeft"), deltaPhi, deltaEta, ptLc, ptHadron, signPair, poolBin, efficiencyWeight); + } else { + registry.fill(HIST("hCorrel2DVsPtSidebandLeft"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); + } + registry.fill(HIST("hDeltaEtaPtIntSidebandLeft"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandLeft"), deltaPhi, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSidebands"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DPtIntSidebands"), deltaPhi, deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebands"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebands"), deltaPhi, efficiencyWeight); + } + // in sideband right region + if (massLc > sidebandRightInner->at(ptBinLc) && massLc < sidebandRightOuter->at(ptBinLc)) { + if (fillSign) { + registry.fill(HIST("hCorrel2DVsPtSignSidebandRight"), deltaPhi, deltaEta, ptLc, ptHadron, signPair, poolBin, efficiencyWeight); + } else { + registry.fill(HIST("hCorrel2DVsPtSidebandRight"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); + } + registry.fill(HIST("hDeltaEtaPtIntSidebandRight"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandRight"), deltaPhi, efficiencyWeight); registry.fill(HIST("hCorrel2DVsPtSidebands"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); registry.fill(HIST("hCorrel2DPtIntSidebands"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSidebands"), deltaEta, efficiencyWeight); @@ -194,49 +520,192 @@ struct HfTaskCorrelationLcHadrons { PROCESS_SWITCH(HfTaskCorrelationLcHadrons, processData, "Process data", true); /// Lc-Hadron correlation pair filling task, from pair tables - for Mc reco-level analysis (candidates matched to true signal only, but also bkg sources are studied) - void processMcRec(LcHadronPairFull const& pairEntries) + void processMcRec(LcHadronPairFullWithMl const& pairEntries, + soa::Join const& candidates) { + for (const auto& candidate : candidates) { + float massLc = candidate.mLc(); + float ptLc = std::abs(candidate.ptLc()); + float bdtScorePrompt = candidate.mlScorePrompt(); + float bdtScoreBkg = candidate.mlScoreBkg(); + int effBinLc = o2::analysis::findBin(binsPtEfficiencyLc, ptLc); + bool isLcPrompt = candidate.isPrompt(); + + // reject entries outside pT ranges of interest + if (ptLc < binsPtEfficiencyLc->front() || ptLc > binsPtEfficiencyLc->back()) + continue; + + if (bdtScorePrompt < mlOutputPrompt->at(effBinLc) || bdtScoreBkg > mlOutputBkg->at(effBinLc)) { + continue; + } + double efficiencyWeightLc = 1.; + if (applyEfficiency) { + if (isLcPrompt) { + efficiencyWeightLc = 1. / efficiencyLc->at(effBinLc); + if (loadAccXEffFromCCDB) { + efficiencyWeightLc = 1. / mEfficiencyPrompt->GetBinContent(mEfficiencyPrompt->FindBin(ptLc)); + } + registry.fill(HIST("hMassLcVsPt"), massLc, ptLc, efficiencyWeightLc); + registry.fill(HIST("hMassLcVsPtWoEff"), massLc, ptLc); + registry.fill(HIST("hMassPromptLcVsPt"), massLc, ptLc, efficiencyWeightLc); + registry.fill(HIST("hBdtScorePrompt"), bdtScorePrompt); + registry.fill(HIST("hBdtScoreBkg"), bdtScoreBkg); + } else { + efficiencyWeightLc = 1. / efficiencyFdLc->at(effBinLc); + if (loadAccXEffFromCCDB) { + efficiencyWeightLc = 1. / mEfficiencyFD->GetBinContent(mEfficiencyFD->FindBin(ptLc)); + } + registry.fill(HIST("hMassLcVsPt"), massLc, ptLc, efficiencyWeightLc); + registry.fill(HIST("hMassLcVsPtWoEff"), massLc, ptLc); + registry.fill(HIST("hMassNonPromptLcVsPt"), massLc, ptLc, efficiencyWeightLc); + registry.fill(HIST("hBdtScorePrompt"), bdtScorePrompt); + registry.fill(HIST("hBdtScoreBkg"), bdtScoreBkg); + } + } + } + for (const auto& pairEntry : pairEntries) { // define variables for widely used quantities - double deltaPhi = pairEntry.deltaPhi(); - double deltaEta = pairEntry.deltaEta(); - double ptLc = pairEntry.ptLc(); - double ptHadron = pairEntry.ptHadron(); - double massLc = pairEntry.mLc(); - double efficiencyWeight = 1.; - double efficiencyHadron = 1.; - int effBinLc = o2::analysis::findBin(binsPtEfficiency, ptLc); - int ptBinLc = o2::analysis::findBin(binsPtCorrelations, ptLc); + float deltaPhi = pairEntry.deltaPhi(); + float deltaEta = pairEntry.deltaEta(); + float ptLc = std::abs(pairEntry.ptLc()); + float ptHadron = std::abs(pairEntry.ptHadron()); + float massLc = pairEntry.mLc(); + float bdtScorePrompt = pairEntry.mlScorePrompt(); + float bdtScoreBkg = pairEntry.mlScoreBkg(); + bool isPhysicalPrimary = pairEntry.isPhysicalPrimary(); + float trackDcaXY = pairEntry.trackDcaXY(); + float trackDcaZ = pairEntry.trackDcaZ(); + int trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); + int statusLcPrompt = static_cast(pairEntry.isPrompt()); + int statusPromptHadron = pairEntry.trackOrigin(); int poolBin = pairEntry.poolBin(); - if (ptBinLc < 0 || effBinLc < 0) { + int effBinLc = o2::analysis::findBin(binsPtEfficiencyLc, ptLc); + int ptBinLc = o2::analysis::findBin(binsPtCorrelations, ptLc); + bool isAutoCorrelated = pairEntry.isAutoCorrelated(); + int signPair = 0; + + // reject entries outside pT ranges of interest + if (ptLc < binsPtEfficiencyLc->front() || ptLc > binsPtEfficiencyLc->back()) + continue; + + if (bdtScorePrompt < mlOutputPrompt->at(effBinLc) || bdtScoreBkg > mlOutputBkg->at(effBinLc)) { continue; } - if (ptHadron > 10.0) { - ptHadron = 10.5; + if (trackDcaXY > dcaXYTrackMax || trackDcaZ > dcaZTrackMax || trackTpcCrossedRows < nTpcCrossedRaws) { + continue; } + double efficiencyWeight = 1.; + if (applyEfficiency) { - efficiencyWeight = 1. / (efficiencyLc->at(effBinLc) * efficiencyHadron); + if (statusLcPrompt) { + efficiencyWeight = 1. / (efficiencyLc->at(effBinLc) * efficiencyHad->at(o2::analysis::findBin(binsPtEfficiencyHad, ptHadron))); + if (loadAccXEffFromCCDB) { + efficiencyWeight = 1. / (mEfficiencyPrompt->GetBinContent(mEfficiencyPrompt->FindBin(ptLc)) * mEfficiencyAssociated->GetBinContent(mEfficiencyAssociated->FindBin(ptHadron))); + } + } else { + efficiencyWeight = 1. / (efficiencyFdLc->at(effBinLc) * efficiencyHad->at(o2::analysis::findBin(binsPtEfficiencyHad, ptHadron))); + if (loadAccXEffFromCCDB) { + efficiencyWeight = 1. / (mEfficiencyFD->GetBinContent(mEfficiencyFD->FindBin(ptLc)) * mEfficiencyAssociated->GetBinContent(mEfficiencyAssociated->FindBin(ptHadron))); + } + } + } + + // Divide into three regions: toward, transverse, and away + if (isTowardTransverseAway) { + if (ptHadron < leadingParticlePtMin) { + continue; + } + Region region = getRegion(deltaPhi); + switch (region) { + case Toward: + registry.fill(HIST("hTowardRec"), massLc, ptLc, isAutoCorrelated, efficiencyWeight); + break; + case Away: + registry.fill(HIST("hAwayRec"), massLc, ptLc, isAutoCorrelated, efficiencyWeight); + break; + case Transverse: + registry.fill(HIST("hTransverseRec"), massLc, ptLc, isAutoCorrelated, efficiencyWeight); + break; + default: + break; + } } + + if (calSign) { + signPair = signCalulation(pairEntry.ptLc(), pairEntry.ptHadron()); + } + if (fillSignAndMass) { + registry.fill(HIST("hCorrel2DVsPtSignMassMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, massLc, signPair, poolBin, efficiencyWeight); + } + // fill correlation plots for signal/bagkground correlations if (pairEntry.signalStatus()) { - registry.fill(HIST("hCorrel2DVsPtSignalMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); + if (fillSign) { + registry.fill(HIST("hCorrel2DVsPtSignSignalMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, signPair, poolBin, efficiencyWeight); + } else { + registry.fill(HIST("hCorrel2DVsPtSignalMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); + } } else { - registry.fill(HIST("hCorrel2DVsPtBkgMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); + if (fillSign) { + registry.fill(HIST("hCorrel2DVsPtSignBkgMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, signPair, poolBin, efficiencyWeight); + } else { + registry.fill(HIST("hCorrel2DVsPtBkgMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); + } } // reject entries outside Pt ranges of interest // check if correlation entry belongs to signal region, sidebands or is outside both, and fill correlation plots if (massLc > signalRegionInner->at(ptBinLc) && massLc < signalRegionOuter->at(ptBinLc)) { // in signal region - registry.fill(HIST("hCorrel2DVsPtSignalRegionMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); + if (fillSign) { + registry.fill(HIST("hCorrel2DVsPtSignSignalRegionMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, signPair, poolBin, efficiencyWeight); + } else { + registry.fill(HIST("hCorrel2DVsPtSignalRegionMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, statusLcPrompt, poolBin, efficiencyWeight); + } registry.fill(HIST("hCorrel2DPtIntSignalRegionMcRec"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSignalRegionMcRec"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSignalRegionMcRec"), deltaPhi, efficiencyWeight); + if (isPhysicalPrimary) { + registry.fill(HIST("hCorrel2DVsPtPhysicalPrimaryMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, statusLcPrompt, poolBin, efficiencyWeight); + if (statusLcPrompt == 1 && statusPromptHadron == 1) { + if (fillSign) { + registry.fill(HIST("hCorrel2DVsPtSignSignalRegionPromptLcPromptHadronMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, signPair, poolBin, efficiencyWeight); + } else { + registry.fill(HIST("hCorrel2DVsPtSignalRegionPromptLcPromptHadronMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); + } + } else if (statusLcPrompt == 0 && statusPromptHadron == 2) { + if (fillSign) { + registry.fill(HIST("hCorrel2DVsPtSignSignalRegionNonPromptLcNonPromptHadronMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, signPair, poolBin, efficiencyWeight); + } else { + registry.fill(HIST("hCorrel2DVsPtSignalRegionNonPromptLcNonPromptHadronMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); + } + } + } } - - if (((massLc > sidebandLeftOuter->at(ptBinLc)) && (massLc < sidebandLeftInner->at(ptBinLc))) || - ((massLc > sidebandRightInner->at(ptBinLc) && massLc < sidebandRightOuter->at(ptBinLc)))) { - // in sideband region + // in sideband left region + if (massLc > sidebandLeftOuter->at(ptBinLc) && massLc < sidebandLeftInner->at(ptBinLc)) { + if (fillSign) { + registry.fill(HIST("hCorrel2DVsPtSignSidebandLeftMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, signPair, poolBin, efficiencyWeight); + } else { + registry.fill(HIST("hCorrel2DVsPtSidebandLeftMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); + } + registry.fill(HIST("hDeltaEtaPtIntSidebandLeftMcRec"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandLeftMcRec"), deltaPhi, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSidebandsMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DPtIntSidebandsMcRec"), deltaPhi, deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandsMcRec"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandsMcRec"), deltaPhi, efficiencyWeight); + } + // in sideband right region + if (massLc > sidebandRightInner->at(ptBinLc) && massLc < sidebandRightOuter->at(ptBinLc)) { + if (fillSign) { + registry.fill(HIST("hCorrel2DVsPtSignSidebandRightMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, signPair, poolBin, efficiencyWeight); + } else { + registry.fill(HIST("hCorrel2DVsPtSidebandRightMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); + } + registry.fill(HIST("hDeltaEtaPtIntSidebandRightMcRec"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandRightMcRec"), deltaPhi, efficiencyWeight); registry.fill(HIST("hCorrel2DVsPtSidebandsMcRec"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); registry.fill(HIST("hCorrel2DPtIntSidebandsMcRec"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSidebandsMcRec"), deltaEta, efficiencyWeight); @@ -247,30 +716,165 @@ struct HfTaskCorrelationLcHadrons { PROCESS_SWITCH(HfTaskCorrelationLcHadrons, processMcRec, "Process Mc Reco mode", false); /// Lc-Hadron correlation pair filling task, from pair tables - for Mc gen-level analysis (no filter/selection, only true signal) - void processMcGen(aod::LcHadronPair const& pairEntries) + void processMcGen(LcHadronPair const& pairEntries) { for (const auto& pairEntry : pairEntries) { // define variables for widely used quantities - double deltaPhi = pairEntry.deltaPhi(); - double deltaEta = pairEntry.deltaEta(); - double ptLc = pairEntry.ptLc(); - double ptHadron = pairEntry.ptHadron(); + float deltaPhi = pairEntry.deltaPhi(); + float deltaEta = pairEntry.deltaEta(); + float ptLc = std::abs(pairEntry.ptLc()); + float ptHadron = std::abs(pairEntry.ptHadron()); int poolBin = pairEntry.poolBin(); - // reject entries outside Pt ranges of interest - if (o2::analysis::findBin(binsPtCorrelations, ptLc) < 0) { - continue; + int statusPromptHadron = pairEntry.trackOrigin(); + bool isLcPrompt = pairEntry.isPrompt(); + bool isAutoCorrelated = pairEntry.isAutoCorrelated(); + int signPair = 0; + + if (isTowardTransverseAway) { + // Divide into three regions: toward, transverse, and away + if (ptHadron < leadingParticlePtMin) { + continue; + } + Region region = getRegion(deltaPhi); + switch (region) { + case Toward: + registry.fill(HIST("hTowardRec"), o2::constants::physics::MassLambdaCPlus, ptLc, isAutoCorrelated); + break; + case Away: + registry.fill(HIST("hAwayRec"), o2::constants::physics::MassLambdaCPlus, ptLc, isAutoCorrelated); + break; + case Transverse: + registry.fill(HIST("hTransverseRec"), o2::constants::physics::MassLambdaCPlus, ptLc, isAutoCorrelated); + break; + default: + break; + } } - if (ptHadron > 10.0) { - ptHadron = 10.5; + if (calSign) { + signPair = signCalulation(pairEntry.ptLc(), pairEntry.ptHadron()); + } + if (fillSign) { + registry.fill(HIST("hCorrel2DVsPtSignMcGen"), deltaPhi, deltaEta, ptLc, ptHadron, signPair, poolBin); + } else { + registry.fill(HIST("hCorrel2DVsPtMcGen"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin); } - - registry.fill(HIST("hCorrel2DVsPtMcGen"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin); registry.fill(HIST("hCorrel2DPtIntMcGen"), deltaPhi, deltaEta); registry.fill(HIST("hDeltaEtaPtIntMcGen"), deltaEta); registry.fill(HIST("hDeltaPhiPtIntMcGen"), deltaPhi); + if (isLcPrompt) { + if (fillSign) { + registry.fill(HIST("hCorrel2DVsPtSignMcGenPrompt"), deltaPhi, deltaEta, ptLc, ptHadron, signPair, poolBin); + } else { + registry.fill(HIST("hCorrel2DVsPtMcGenPrompt"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin); + } + if (statusPromptHadron == 1) { + if (fillSign) { + registry.fill(HIST("hCorrel2DVsPtSignMcGenPromptLcPromptHadron"), deltaPhi, deltaEta, ptLc, ptHadron, signPair, poolBin); + } else { + registry.fill(HIST("hCorrel2DVsPtMcGenPromptLcPromptHadron"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin); + } + } + } else { + if (fillSign) { + registry.fill(HIST("hCorrel2DVsPtSignMcGenNonPrompt"), deltaPhi, deltaEta, ptLc, ptHadron, signPair, poolBin); + } else { + registry.fill(HIST("hCorrel2DVsPtMcGenNonPrompt"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin); + } + if (statusPromptHadron == 2) { + if (fillSign) { + registry.fill(HIST("hCorrel2DVsPtSignMcGenNonPromptLcNonPromptHadron"), deltaPhi, deltaEta, ptLc, ptHadron, signPair, poolBin); + } else { + registry.fill(HIST("hCorrel2DVsPtMcGenNonPromptLcNonPromptHadron"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin); + } + } + } } // end loop } PROCESS_SWITCH(HfTaskCorrelationLcHadrons, processMcGen, "Process Mc Gen mode", false); + + /// Lc-Hadron correlation - reconstruction and selection efficiency + void processMcCandEfficiency(soa::Join const&, + soa::Join const&, + CandLcMcGen const& mcParticles, + CandLcMcReco const& candidates, + aod::TracksWMc const&) + { + auto hCandidates = registry.get(HIST("hCandidates")); + + /// Gen loop + float multiplicity = -1.; + for (const auto& mcParticle : mcParticles) { + // generated candidates + if (std::abs(mcParticle.pdgCode()) == Pdg::kLambdaCPlus) { + auto mcCollision = mcParticle.template mcCollision_as>(); + multiplicity = mcCollision.multMCFT0A() + mcCollision.multMCFT0C(); // multFT0M = multFt0A + multFT0C + hCandidates->Fill(kCandidateStepMcGenAll, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); + if (std::abs(mcParticle.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::LcToPKPi) { + hCandidates->Fill(kCandidateStepMcGenLcToPKPi, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); + auto yL = RecoDecay::y(mcParticle.pVector(), o2::constants::physics::MassLambdaCPlus); + if (std::abs(yL) <= yCandGenMax) { + hCandidates->Fill(kCandidateStepMcCandInAcceptance, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); + if (mcParticle.originMcGen() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("Efficiency/hPtCandMcGenPrompt"), mcParticle.pt()); + } + if (mcParticle.originMcGen() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("Efficiency/hPtCandMcGenNonPrompt"), mcParticle.pt()); + } + } + bool isDaughterInAcceptance = true; + auto daughters = mcParticle.template daughters_as(); + for (const auto& daughter : daughters) { + if (daughter.pt() < ptDaughterMin || std::abs(daughter.eta()) > etaTrackMax) { + isDaughterInAcceptance = false; + } + } + if (isDaughterInAcceptance) { + hCandidates->Fill(kCandidateStepMcDaughtersInAcceptance, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); + registry.fill(HIST("Efficiency/hPtCandMcGenDaughterInAcc"), mcParticle.pt()); + } + } + } + } + + // recontructed candidates loop + for (const auto& candidate : candidates) { + if (candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { + continue; + } + std::vector outputMl = {-1., -1., -1.}; + if (candidate.isSelLcToPKPi() >= selectionFlagLc) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbLcToPKPi()[classMl->at(iclass)]; + } + } + if (candidate.isSelLcToPiKP() >= selectionFlagLc) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbLcToPiKP()[classMl->at(iclass)]; + } + } + if (outputMl[0] > mlOutputBkg->at(o2::analysis::findBin(binsPtEfficiencyLc, candidate.pt())) || outputMl[1] < mlOutputPrompt->at(o2::analysis::findBin(binsPtEfficiencyLc, candidate.pt()))) { + continue; + } + auto collision = candidate.template collision_as>(); + if (selNoSameBunchPileUpColl && !(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { + continue; + } + multiplicity = collision.multFT0M(); + if (std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::LcToPKPi) { + hCandidates->Fill(kCandidateStepMcReco, candidate.pt(), multiplicity, candidate.originMcRec()); + if (std::abs(hfHelper.yLc(candidate)) <= yCandMax) { + hCandidates->Fill(kCandidateStepMcRecoInAcceptance, candidate.pt(), multiplicity, candidate.originMcRec()); + if (candidate.originMcRec() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("Efficiency/hPtCandMcRecPrompt"), candidate.pt()); + } + if (candidate.originMcRec() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("Efficiency/hPtCandMcRecNonPrompt"), candidate.pt()); + } + } + } + } + } + PROCESS_SWITCH(HfTaskCorrelationLcHadrons, processMcCandEfficiency, "Process MC for calculating candidate reconstruction efficiency", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/HFC/Tasks/taskFlow.cxx b/PWGHF/HFC/Tasks/taskFlow.cxx index 6cb685f25ca..9050b5ac4f2 100644 --- a/PWGHF/HFC/Tasks/taskFlow.cxx +++ b/PWGHF/HFC/Tasks/taskFlow.cxx @@ -10,9 +10,14 @@ // or submit itself to any jurisdiction. /// \file taskFlow.cxx +/// \brief HF-h correlations in TPC-TPC and TPC-MFT +/// \author Alexian Lejeune , Czech Technical University in Prague /// \author Katarina Krizkova Gajdosova , CERN /// \author Maja Kabus , CERN +#include +#include + #include #include #include @@ -23,6 +28,8 @@ #include "Framework/AnalysisTask.h" #include "Framework/ASoAHelpers.h" #include "Framework/HistogramRegistry.h" +#include "Framework/Logger.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/runDataProcessing.h" #include "Framework/RunningWorkflowInfo.h" #include "Framework/StepTHn.h" @@ -47,46 +54,110 @@ using namespace o2::framework; using namespace o2::framework::expressions; struct HfTaskFlow { + // configurables for processing options + Configurable doReferenceFlow{"doReferenceFlow", false, "Flag to know if reference flow should be done"}; Configurable processRun2{"processRun2", false, "Flag to run on Run 2 data"}; Configurable processRun3{"processRun3", true, "Flag to run on Run 3 data"}; Configurable processMc{"processMc", false, "Flag to run on MC"}; Configurable nMixedEvents{"nMixedEvents", 5, "Number of mixed events per event"}; // configurables for collisions Configurable zVertexMax{"zVertexMax", 7.0f, "Accepted z-vertex range"}; - // configurables for associated particles - Configurable etaTrackAssocMax{"etaTrackAssocMax", 0.8f, "max. eta of associated tracks"}; - Configurable ptTrackAssocMin{"ptTrackAssocMin", 0.5f, "min. pT of associated tracks"}; + // configurables for TPC tracks + Configurable etaTpcTrackMax{"etaTpcTrackMax", 0.8f, "max. eta of TPC tracks"}; + Configurable ptTpcTrackMin{"ptTpcTrackMin", 0.5f, "min. pT of TPC tracks"}; // configurables for HF candidates + Configurable etaCandidateMax{"etaCandidateMax", 0.8f, "max. eta of HF candidate"}; Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection Flag for D0bar"}; - Configurable yCandMax{"yCandMax", -1., "max. cand. rapidity"}; + Configurable selectionFlagLcToPKPi{"selectionFlagLcToPKPi", 1, "Selection Flag for LambdaC"}; + Configurable selectionFlagLcToPiKP{"selectionFlagLcToPiKP", 1, "Selection Flag for LambdaC bar"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits"}; + // configurables for MFT tracks + Configurable etaMftTrackMax{"etaMftTrackMax", 0, "Maximum value for the eta of MFT tracks"}; + Configurable etaMftTrackMin{"etaMftTrackMin", -5, "Minimum value for the eta of MFT tracks"}; + Configurable nClustersMftTrack{"nClustersMftTrack", 5, "Minimum number of clusters for the reconstruction of MFT tracks"}; HfHelper hfHelper; SliceCache cache; + Service pdg; + + // ========================= + // using declarations : DATA + // ========================= + + using FilteredCollisionsWSelMult = soa::Filtered>; + using HfCandidatesSelD0 = soa::Filtered>; + using HfCandidatesSelLc = soa::Filtered>; + using TracksWDcaSel = soa::Filtered>; + + // ========================= + // using declarations : MC + // ========================= + + // Even add McCollisions in the join ? + // Kata adds subscribes to it but do not add it in the join + // using FilteredCollisionsWSelMultMC = soa::Filtered>; + using FilteredCollisionsWSelMultMC = soa::Filtered>; + using FilteredMcCollisions = soa::Filtered>; + using FilteredMcParticles = soa::Filtered; + using TracksWDcaSelMC = soa::Filtered>; + + // Remnants, need Katarina's info + // using FilteredCollisionsWDcaSelMcLabels = soa::Filtered>; + // using FilteredTracksWDcaSelMcLabels = soa::Filtered>; + + // ========================= + // Filters & partitions : DATA + // ========================= + + // HF candidate filter + // TODO: use Partition instead of filter + Filter candidateFilterD0 = (aod::hf_sel_candidate_d0::isSelD0 >= selectionFlagD0) || + (aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlagD0bar); - using MyCollisions = soa::Filtered>; - using MyTracks = soa::Filtered>; - using HfCandidatesSel = soa::Filtered>; + Filter candidateFilterLc = (aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLcToPKPi) || + (aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLcToPiKP); // Collision filters // FIXME: The filter is applied also on the candidates! Beware! Filter collisionVtxZFilter = nabs(aod::collision::posZ) < zVertexMax; - // Charged track filters - Filter trackFilter = (nabs(aod::track::eta) < etaTrackAssocMax) && - (aod::track::pt > ptTrackAssocMin) && + + Filter trackFilter = (nabs(aod::track::eta) < etaTpcTrackMax) && + (aod::track::pt > ptTpcTrackMin) && requireGlobalTrackWoPtEtaInFilter(); - // HF candidate filter - // TODO: use Partition instead of filter - Filter candidateFilter = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlagD0 || aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlagD0bar; - Preslice perCol = aod::track::collisionId; + // ========================= + // Filters & partitions : MC + // ========================= + + // From Katarina's code, but not sure if I use it + Filter mcCollisionFilter = nabs(aod::mccollision::posZ) < zVertexMax; + + // From Katarina's code + Filter mcParticlesFilter = (nabs(aod::mcparticle::eta) < etaTpcTrackMax) && + (aod::mcparticle::pt > ptTpcTrackMin); //&& + //(aod::mcparticle::sign != 0) + + // ========================= + // Preslice : DATA + // ========================= + + Preslice dataPerCol = aod::track::collisionId; + + // ========================= + // Preslice : MC + // ========================= + + Preslice mcTruthPerCol = aod::mcparticle::mcCollisionId; + // Do I have to adapt this preslice to MC ? How does it work exactly ? + // Preslice mcRecPerCol = aod::track::collisionId; // configurables for containers ConfigurableAxis axisVertex{"axisVertex", {14, -7, 7}, "vertex axis for histograms"}; ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {72, -PIHalf, PIHalf * 3}, "delta phi axis for histograms"}; ConfigurableAxis axisDeltaEta{"axisDeltaEta", {48, -2.4, 2.4}, "delta eta axis for histograms"}; + ConfigurableAxis axisPt{"axisPt", {72, 0, 36}, "pt axis for histograms"}; ConfigurableAxis axisPtTrigger{"axisPtTrigger", {VARIABLE_WIDTH, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 8.0}, "pt trigger axis for histograms"}; ConfigurableAxis axisPtAssoc{"axisPtAssoc", {VARIABLE_WIDTH, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0}, "pt associated axis for histograms"}; ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 100.1}, "multiplicity axis for histograms"}; @@ -96,93 +167,242 @@ struct HfTaskFlow { // TODO: flow of HF will need to be done vs. invariant mass, in the signal and side-band regions // either 1) add invariant mass axis or 2) define several containers for different inv. mass regions // Note: don't forget to check inv. mass separately for D0 and D0bar candidate - ConfigurableAxis axisMass{"axisMass", {30, 1.7, 2.0}, "axis of invariant mass of HF candidates"}; + ConfigurableAxis axisMass{"axisMass", {120, 1.5848, 2.1848}, "axis of invariant mass of candidates"}; + ConfigurableAxis binsMixingVertex{"binsMixingVertex", {14, -7, 7}, "vertex bins for event mixing"}; + ConfigurableAxis binsMixingMultiplicity{"binsMixingMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 100.1}, "multiplicity bins for event mixing"}; HistogramRegistry registry{"registry"}; - OutputObj sameTPCTPCCh{"sameEventTPCTPCChHadrons"}; - OutputObj sameTPCMFTCh{"sameEventTPCMFTChHadrons"}; - OutputObj sameHF{"sameEventHFHadrons"}; - OutputObj mixedTPCTPCCh{"mixedEventTPCTPCChHadrons"}; - OutputObj mixedHF{"mixedEventHFHadrons"}; + // Correlation containers used for data + OutputObj sameEvent{"sameEvent"}; + OutputObj mixedEvent{"mixedEvent"}; + OutputObj sameEventHf{"sameEventHf"}; + OutputObj mixedEventHf{"mixedEventHf"}; + + // Correlation containers used for Monte-Carlo + // OutputObj sameTPCTPCChChMC{"sameTPCTPCChChMC"}; + // OutputObj mixedTPCTPCChChMC{"mixedTPCTPCChChMC"}; // ========================= // init() // ========================= void init(InitContext&) { - // EVENT HISTOGRAMS - constexpr int kNBinsEvents = 3; - registry.add("hEventCounter", "hEventCounter", {HistType::kTH1F, {{kNBinsEvents, 0.5, 0.5 + kNBinsEvents}}}); + // ========================= + // Event histograms + // TO-DO : do i have to separate event histograms between DATA and MC ? + // ========================= + constexpr int kNBinsEvents = 2; + registry.add("Data/hEventCounter", "hEventCounter", {HistType::kTH1F, {{kNBinsEvents, 0.5, 0.5 + kNBinsEvents}}}); // set axes of the event counter histogram std::string labels[kNBinsEvents]; labels[0] = "all"; - labels[1] = "after trigger selection (Run 2)"; - labels[2] = "after Physics selection"; + labels[1] = "after Physics selection"; + + const int nBinsMix = axisMultiplicity->size() * 14; // 14 bins for z-vertex + for (int iBin = 0; iBin < kNBinsEvents; iBin++) { - registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); + registry.get(HIST("Data/hEventCounter"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); } - registry.add("hMultiplicity", "hMultiplicity", {HistType::kTH1F, {{500, 0, 500}}}); - registry.add("hVtxZ", "hVtxZ", {HistType::kTH1F, {{400, -50, 50}}}); - registry.add("hNtracks", "hNtracks", {HistType::kTH1F, {{500, 0, 500}}}); - - // histograms for event mixing - const int maxMixBin = axisMultiplicity->size() * 14; // 14 bins for z-vertex - registry.add("hEventCountMixing", "bin", {HistType::kTH1F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}}}); - registry.add("hEventCountHFMixing", "bin", {HistType::kTH1F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}}}); - registry.add("hEventCountSame", "bin", {HistType::kTH1F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}}}); - registry.add("hMultiplicityMixing", "hMultiplicityMixing", {HistType::kTH1F, {{500, 0, 500}}}); - registry.add("hVtxZMixing", "hVtxZMixing", {HistType::kTH1F, {{100, -10, 10}}}); - registry.add("hNtracksMixing", "hNtracksMixing", {HistType::kTH1F, {{500, 0, 500}}}); - registry.add("hMultiplicityHFMixing", "hMultiplicityHFMixing", {HistType::kTH1F, {{500, 0, 500}}}); - registry.add("hVtxZHFMixing", "hVtxZHFMixing", {HistType::kTH1F, {{100, -10, 10}}}); - registry.add("hNtracksHFMixing", "hNtracksHFMixing", {HistType::kTH1F, {{500, 0, 500}}}); - - // TRACK HISTOGRAMS - // histograms for associated particles - registry.add("hYields", "multiplicity vs pT vs eta", {HistType::kTH3F, {{200, 0, 200, "multiplicity"}, {40, 0, 20, "p_{T}"}, {100, -2, 2, "#eta"}}}); - registry.add("hEtaPhi", "multiplicity vs eta vs phi", {HistType::kTH3F, {{200, 0, 200, "multiplicity"}, {100, -2, 2, "#eta"}, {200, 0, TwoPI, "#varphi"}}}); - registry.add("hPt", "pT", {HistType::kTH1F, {{100, 0, 10, "p_{T}"}}}); - registry.add("hEta", "eta", {HistType::kTH1F, {{100, -4, 4, "#eta"}}}); - registry.add("hPhi", "phi", {HistType::kTH1F, {{100, 0, TwoPI, "#varphi"}}}); - - // histograms for particles in event mixing - registry.add("hPtMixing", "pT", {HistType::kTH1F, {{100, 0, 10, "p_{T}"}}}); - registry.add("hEtaMixing", "eta", {HistType::kTH1F, {{100, -4, 4, "#eta"}}}); - registry.add("hPhiMixing", "phi", {HistType::kTH1F, {{100, 0, TwoPI, "#varphi"}}}); - - // histograms for MFT tracks - registry.add("hEtaPhiMFT", "multiplicity vs eta vs phi in MFT", {HistType::kTH3F, {{200, 0, 200, "multiplicity"}, {100, -2, 2, "#eta"}, {200, 0, TwoPI, "#varphi"}}}); - registry.add("hEtaMFT", "etaMFT", {HistType::kTH1F, {{100, -4, 4, "#eta"}}}); - registry.add("hPhiMFT", "phiMFT", {HistType::kTH1F, {{100, 0, TwoPI, "#varphi"}}}); - - // histograms for candidates + + // ========================= + // DATA : histograms for TPC-TPC h-h case + // ========================= + + // DATA : event histograms for TPC-TPC h-h same event + registry.add("Data/TpcTpc/HadronHadron/SameEvent/hMultiplicity", "hMultiplicity", {HistType::kTH1F, {axisMultiplicity}}); + registry.add("Data/TpcTpc/HadronHadron/SameEvent/hVtxZ", "hVtxZ", {HistType::kTH1F, {axisVertex}}); + registry.add("Data/TpcTpc/HadronHadron/SameEvent/hEventCountSame", "bin", {HistType::kTH1F, {{nBinsMix + 2, -2.5, -0.5 + nBinsMix, "bin"}}}); + + // DATA : associated particles histograms for TPC-TPC h-h same event + registry.add("Data/TpcTpc/HadronHadron/SameEvent/hPt", "pT", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcTpc/HadronHadron/SameEvent/hEta", "eta", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("Data/TpcTpc/HadronHadron/SameEvent/hPhi", "phi", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("Data/TpcTpc/HadronHadron/SameEvent/hYields", "multiplicity vs pT vs eta", {HistType::kTH3F, {axisMultiplicity, axisPt, axisDeltaEta}}); + registry.add("Data/TpcTpc/HadronHadron/SameEvent/hEtaPhi", "multiplicity vs eta vs phi", {HistType::kTH3F, {axisMultiplicity, axisDeltaEta, axisDeltaPhi}}); + // registry.add("Data/TpcTpc/HadronHadron/SameEvent/hNtracks", "hNtracks", {HistType::kTH1F, {{500, 0, 500}}}); + + // Katarina had this : + registry.add("Data/TpcTpc/HadronHadron/SameEvent/hVzEta", "eta vs. Vz", {HistType::kTH2F, {axisDeltaEta, axisVertex}}); + + // DATA : event mixing histograms for TPC-TPC h-h mixed event + registry.add("Data/TpcTpc/HadronHadron/MixedEvent/hEventCountMixing", "bin", {HistType::kTH1F, {{nBinsMix + 2, -2.5, -0.5 + nBinsMix, "bin"}}}); + + // ========================= + // DATA : histograms for TPC-TPC HF-h case for 2PRONG + // ========================= + + // DATA : event histograms for TPC-TPC HF-h same event + registry.add("Data/TpcTpc/HfHadron/SameEvent/hPt", "pT", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/hEta", "eta", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/hPhi", "phi", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/hYields", "multiplicity vs pT vs eta", {HistType::kTH3F, {axisMultiplicity, axisPt, axisDeltaEta}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/hEtaPhi", "multiplicity vs eta vs phi", {HistType::kTH3F, {axisMultiplicity, axisDeltaEta, axisDeltaPhi}}); + + registry.add("Data/TpcTpc/HfHadron/SameEvent/2Prong/hEventCountSame", "bin", {HistType::kTH1F, {{nBinsMix + 2, -2.5, -0.5 + nBinsMix, "bin"}}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/2Prong/hEta", "eta", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/2Prong/hPhi", "phi", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/2Prong/hMultiplicity", "multiplicity;multiplicity;entries", {HistType::kTH1F, {axisMultiplicity}}); + registry.add("Data/TpcTpc/HfHadron/MixedEvent/hEventCountHFMixing", "bin", {HistType::kTH1F, {{nBinsMix + 2, -2.5, -0.5 + nBinsMix, "bin"}}}); + + // DATA : trigger particles (candidates) histograms for TPC-TPC D0-h same event auto vbins = (std::vector)binsPt; + registry.add("Data/TpcTpc/HfHadron/SameEvent/2Prong/hPtCandidate", "2-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/2Prong/hPtProng0", "2-prong candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/2Prong/hPtProng1", "2-prong candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/2Prong/hMassVsPt", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisMass, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/2Prong/hMass", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMass}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/2Prong/hEtaCandVsPt", "2-prong candidates;candidate #it{#eta};entries", {HistType::kTH2F, {axisDeltaEta, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/2Prong/hSelectionStatus", "2-prong candidates;selection status;entries", {HistType::kTH2F, {{5, -0.5, 4.5}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + + // ========================= + // DATA : histograms for TPC-TPC HF-h case for 3PRONG + // =================== + + registry.add("Data/TpcTpc/HfHadron/SameEvent/3Prong/hEventCountSame", "bin", {HistType::kTH1F, {{nBinsMix + 2, -2.5, -0.5 + nBinsMix, "bin"}}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/3Prong/hMassVsPt", "3-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisMass, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/3Prong/hMass", "3-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMass}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/3Prong/hMassVsPtVsMult", "3-prong candidates;inv. mass (p K #pi) (GeV/#it{c}^{2}); p_{T}; multiplicity", {HistType::kTH3F, {axisMass, {vbins, "#it{p}_{T} (GeV/#it{c})"}, axisMultiplicity}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/3Prong/hMultiplicity", "multiplicity;multiplicity;entries", {HistType::kTH1F, {axisMultiplicity}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/3Prong/hPt", "3-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/3Prong/hPtProng0", "3-prong candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/3Prong/hPtProng1", "3-prong candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/3Prong/hPtProng2", "3-prong candidates;prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/3Prong/hEta", "3-prong candidates;#it{#eta};entries", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/3Prong/hPhi", "3-prong candidates;#it{#Phi};entries", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/3Prong/hEtaVsPt", "3-prong candidates;candidate #it{#eta};entries", {HistType::kTH2F, {axisDeltaEta, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/3Prong/hPhiVsPt", "3-prong candidates;candidate #it{#Phi};entries", {HistType::kTH2F, {axisDeltaPhi, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/TpcTpc/HfHadron/SameEvent/3Prong/hSelectionStatus", "3-prong candidates;selection status;entries", {HistType::kTH2F, {{5, -0.5, 4.5}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + + // ========================= + // DATA : histograms for TPC-MFT h-h case + // ========================= + + // DATA : trigger particles (TPC tracks) histograms for TPC-MFT h-h same event + registry.add("Data/TpcMft/HadronHadron/SameEvent/hEventCountSame", "bin", {HistType::kTH1F, {{nBinsMix + 2, -2.5, -0.5 + nBinsMix, "bin"}}}); + registry.add("Data/TpcMft/HadronHadron/SameEvent/hEtaPhiTPC", "multiplicity vs eta vs phi in TPC", {HistType::kTH3F, {axisMultiplicity, axisDeltaEta, axisDeltaPhi}}); + registry.add("Data/TpcMft/HadronHadron/SameEvent/hEtaTPC", "etaTPC", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("Data/TpcMft/HadronHadron/SameEvent/hPhiTPC", "phiTPC", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("Data/TpcMft/HadronHadron/SameEvent/hPtTPC", "pT", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcMft/HadronHadron/SameEvent/hYieldsTPC", "multiplicity vs pT vs eta", {HistType::kTH3F, {axisMultiplicity, axisPt, axisDeltaEta}}); + registry.add("Data/TpcMft/HadronHadron/SameEvent/hMultiplicityTPC", "multiplicity;multiplicity;entries", {HistType::kTH1F, {axisMultiplicity}}); + + // DATA : associated particles (MFT tracks) histograms for TPC-MFT h-h same event + registry.add("Data/TpcMft/HadronHadron/SameEvent/hEtaPhiMFT", "multiplicity vs eta vs phi in MFT", {HistType::kTH3F, {axisMultiplicity, axisDeltaEta, axisDeltaPhi}}); + registry.add("Data/TpcMft/HadronHadron/SameEvent/hEtaMFT", "etaMFT", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("Data/TpcMft/HadronHadron/SameEvent/hPhiMFT", "phiMFT", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("Data/TpcMft/HadronHadron/SameEvent/hPtMFT", "pT", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcMft/HadronHadron/SameEvent/hYieldsMFT", "multiplicity vs pT vs eta", {HistType::kTH3F, {axisMultiplicity, axisPt, axisDeltaEta}}); + + // DATA : histograms for TPC-MFT h-h event mixing for events QA + registry.add("Data/TpcMft/HadronHadron/MixedEvent/hEventCountMixing", "bin", {HistType::kTH1F, {{nBinsMix + 2, -2.5, -0.5 + nBinsMix, "bin"}}}); + + // ========================= + // DATA : histograms for TPC-MFT HF-h case FOR 2PRONG + // ========================= + + // DATA : trigger particles (candidates) histograms for TPC-MFT HF-h same event + registry.add("Data/TpcMft/HfHadron/SameEvent/2Prong/hEventCountSame", "bin", {HistType::kTH1F, {{nBinsMix + 2, -2.5, -0.5 + nBinsMix, "bin"}}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/2Prong/hEtaPhiCandidate", "multiplicity vs eta vs phi in TPC", {HistType::kTH3F, {axisMultiplicity, axisDeltaEta, axisDeltaPhi}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/2Prong/hEtaCandidate", "etaTPC", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/2Prong/hPhiCandidate", "phiTPC", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/2Prong/hYieldsCandidate", "multiplicity vs pT vs eta", {HistType::kTH3F, {axisMultiplicity, axisPt, axisDeltaEta}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/2Prong/hMultiplicityCandidate", "multiplicity;multiplicity;entries", {HistType::kTH1F, {axisMultiplicity}}); + + // DATA : trigger particles (candidates) histograms for TPC-MFT HF-h same event + registry.add("Data/TpcMft/HfHadron/SameEvent/2Prong/hPtCandidate", "2-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/2Prong/hPtProng0", "2-prong candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/2Prong/hPtProng1", "2-prong candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/2Prong/hMassVsPt", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisMass, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/2Prong/hMass", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMass}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/2Prong/hEtaCandVsPt", "2-prong candidates;candidate #it{#eta};entries", {HistType::kTH2F, {axisDeltaEta, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/2Prong/hSelectionStatus", "2-prong candidates;selection status;entries", {HistType::kTH2F, {{5, -0.5, 4.5}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + + // DATA : associated particles (MFT tracks) histograms for TPC-MFT h-h same event + registry.add("Data/TpcMft/HfHadron/SameEvent/hEtaPhiMFT", "multiplicity vs eta vs phi in MFT", {HistType::kTH3F, {axisMultiplicity, axisDeltaEta, axisDeltaPhi}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/hEtaMFT", "etaMFT", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/hPhiMFT", "phiMFT", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/hPtMFT", "pT", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/hYieldsMFT", "multiplicity vs pT vs eta", {HistType::kTH3F, {axisMultiplicity, axisPt, axisDeltaEta}}); + + // DATA : histograms for TPC-MFT h-h event mixing for events QA + registry.add("Data/TpcMft/HfHadron/MixedEvent/hEventCountMixing", "bin", {HistType::kTH1F, {{nBinsMix + 2, -2.5, -0.5 + nBinsMix, "bin"}}}); + + // ========================= + // DATA : histograms for TPC-MFT HF-h case FOR 3PRONG + // ========================= + + registry.add("Data/TpcMft/HfHadron/SameEvent/3Prong/hEventCountSame", "bin", {HistType::kTH1F, {{nBinsMix + 2, -2.5, -0.5 + nBinsMix, "bin"}}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/3Prong/hYieldsCandidate", "multiplicity vs pT vs eta", {HistType::kTH3F, {axisMultiplicity, axisPt, axisDeltaEta}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/3Prong/hMultiplicityCandidate", "multiplicity;multiplicity;entries", {HistType::kTH1F, {axisMultiplicity}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/3Prong/hEtaPhiCandidate", "multiplicity vs eta vs phi in TPC", {HistType::kTH3F, {axisMultiplicity, axisDeltaEta, axisDeltaPhi}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/3Prong/hMassVsPt", "3-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisMass, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/3Prong/hMass", "3-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMass}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/3Prong/hMassVsPtVsMult", "3-prong candidates;inv. mass (p K #pi) (GeV/#it{c}^{2}); p_{T}; multiplicity", {HistType::kTH3F, {axisMass, {vbins, "#it{p}_{T} (GeV/#it{c})"}, axisMultiplicity}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/3Prong/hPt", "3-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/3Prong/hPtProng0", "3-prong candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/3Prong/hPtProng1", "3-prong candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/3Prong/hPtProng2", "3-prong candidates;prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/3Prong/hEta", "3-prong candidates;#it{#eta};entries", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/3Prong/hPhi", "3-prong candidates;#it{#Phi};entries", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/3Prong/hEtaVsPt", "3-prong candidates;candidate #it{#eta};entries", {HistType::kTH2F, {axisDeltaEta, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/3Prong/hPhiVsPt", "3-prong candidates;candidate #it{#Phi};entries", {HistType::kTH2F, {axisDeltaPhi, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/TpcMft/HfHadron/SameEvent/3Prong/hSelectionStatus", "3-prong candidates;selection status;entries", {HistType::kTH2F, {{5, -0.5, 4.5}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + + // ========================= + // MC : histograms for TPC-TPC h-h case + // ========================= + + // MC reconstructed + + registry.add("MC/Rec/TpcTpc/HadronHadron/SameEvent/hMultiplicity", "hMultiplicity", {HistType::kTH1F, {axisMultiplicity}}); + registry.add("MC/Rec/TpcTpc/HadronHadron/SameEvent/hVtxZ", "hVtxZ", {HistType::kTH1F, {axisVertex}}); + registry.add("MC/Rec/TpcTpc/HadronHadron/SameEvent/hEventCountSame", "bin", {HistType::kTH1F, {{nBinsMix + 2, -2.5, -0.5 + nBinsMix, "bin"}}}); + // Katarina had this : + registry.add("MC/Rec/TpcTpc/HadronHadron/SameEvent/hMultiplicityPrimary", "hMultiplicityPrimary", {HistType::kTH1F, {axisMultiplicity}}); + // histograms for MC associated particles + registry.add("MC/Rec/TpcTpc/HadronHadron/SameEvent/hPt", "pT", {HistType::kTH1F, {axisPt}}); + registry.add("MC/Rec/TpcTpc/HadronHadron/SameEvent/hEta", "eta", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("MC/Rec/TpcTpc/HadronHadron/SameEvent/hPhi", "phi", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("MC/Rec/TpcTpc/HadronHadron/SameEvent/hYields", "multiplicity vs pT vs eta", {HistType::kTH3F, {axisMultiplicity, axisPt, axisDeltaEta}}); + registry.add("MC/Rec/TpcTpc/HadronHadron/SameEvent/hEtaPhi", "multiplicity vs eta vs phi", {HistType::kTH3F, {axisMultiplicity, axisDeltaEta, axisDeltaPhi}}); + registry.add("MC/Rec/TpcTpc/HadronHadron/SameEvent/hNtracks", "hNtracks", {HistType::kTH1F, {axisMultiplicity}}); + // histograms for MC particles in event mixing + registry.add("MC/Rec/TpcTpc/HadronHadron/MixedEvent/hEventCountMixing", "bin", {HistType::kTH1F, {{nBinsMix + 2, -2.5, -0.5 + nBinsMix, "bin"}}}); + registry.add("MC/Rec/TpcTpc/HadronHadron/MixedEvent/hMultiplicityMixing", "hMultiplicityMixing", {HistType::kTH1F, {axisMultiplicity}}); + registry.add("MC/Rec/TpcTpc/HadronHadron/MixedEvent/hVtxZMixing", "hVtxZMixing", {HistType::kTH1F, {axisVertex}}); + registry.add("MC/Rec/TpcTpc/HadronHadron/MixedEvent/hPtMixing", "pT", {HistType::kTH1F, {axisPt}}); + registry.add("MC/Rec/TpcTpc/HadronHadron/MixedEvent/hEtaMixing", "eta", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("MC/Rec/TpcTpc/HadronHadron/MixedEvent/hPhiMixing", "phi", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("MC/Rec/TpcTpc/HadronHadron/MixedEvent/hNtracksMixing", "hNtracksMixing", {HistType::kTH1F, {axisMultiplicity}}); + + // MC Truth + + registry.add("MC/Gen/TpcTpc/HadronHadron/SameEvent/hMultiplicity", "hMultiplicity", {HistType::kTH1F, {axisMultiplicity}}); + registry.add("MC/Gen/TpcTpc/HadronHadron/SameEvent/hVtxZ", "hVtxZ", {HistType::kTH1F, {axisVertex}}); + registry.add("MC/Gen/TpcTpc/HadronHadron/SameEvent/hEventCountSame", "bin", {HistType::kTH1F, {{nBinsMix + 2, -2.5, -0.5 + nBinsMix, "bin"}}}); + // Katarina had this : + registry.add("MC/Gen/TpcTpc/HadronHadron/SameEvent/hMultiplicityPrimary", "hMultiplicityPrimary", {HistType::kTH1F, {axisMultiplicity}}); + // histograms for MC associated particles + registry.add("MC/Gen/TpcTpc/HadronHadron/SameEvent/hPt", "pT", {HistType::kTH1F, {axisPt}}); + registry.add("MC/Gen/TpcTpc/HadronHadron/SameEvent/hEta", "eta", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("MC/Gen/TpcTpc/HadronHadron/SameEvent/hPhi", "phi", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("MC/Gen/TpcTpc/HadronHadron/SameEvent/hYields", "multiplicity vs pT vs eta", {HistType::kTH3F, {axisMultiplicity, axisPt, axisDeltaEta}}); + registry.add("MC/Gen/TpcTpc/HadronHadron/SameEvent/hEtaPhi", "multiplicity vs eta vs phi", {HistType::kTH3F, {axisMultiplicity, axisDeltaEta, axisDeltaPhi}}); + registry.add("MC/Gen/TpcTpc/HadronHadron/SameEvent/hNtracks", "hNtracks", {HistType::kTH1F, {axisMultiplicity}}); + // histograms for MC particles in event mixing + registry.add("MC/Gen/TpcTpc/HadronHadron/MixedEvent/hEventCountMixing", "bin", {HistType::kTH1F, {{nBinsMix + 2, -2.5, -0.5 + nBinsMix, "bin"}}}); + registry.add("MC/Gen/TpcTpc/HadronHadron/MixedEvent/hMultiplicityMixing", "hMultiplicityMixing", {HistType::kTH1F, {axisMultiplicity}}); + registry.add("MC/Gen/TpcTpc/HadronHadron/MixedEvent/hVtxZMixing", "hVtxZMixing", {HistType::kTH1F, {axisVertex}}); + registry.add("MC/Gen/TpcTpc/HadronHadron/MixedEvent/hPtMixing", "pT", {HistType::kTH1F, {axisPt}}); + registry.add("MC/Gen/TpcTpc/HadronHadron/MixedEvent/hEtaMixing", "eta", {HistType::kTH1F, {axisDeltaEta}}); + registry.add("MC/Gen/TpcTpc/HadronHadron/MixedEvent/hPhiMixing", "phi", {HistType::kTH1F, {axisDeltaPhi}}); + registry.add("MC/Gen/TpcTpc/HadronHadron/MixedEvent/hNtracksMixing", "hNtracksMixing", {HistType::kTH1F, {axisMultiplicity}}); + + // ========================= + // Declaration of correlation containers and their respective axis + // ========================= - registry.add("hPtCand", "2-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0, 10.}}}); - registry.add("hPtProng0", "2-prong candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0, 10.}}}); - registry.add("hPtProng1", "2-prong candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0, 10.}}}); - registry.add("hMass", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{500, 0., 5.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hDecLength", "2-prong candidates;decay length (cm);entries", {HistType::kTH2F, {{200, 0., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hDecLengthXY", "2-prong candidates;decay length xy (cm);entries", {HistType::kTH2F, {{200, 0., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hd0Prong0", "2-prong candidates;prong 0 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hd0Prong1", "2-prong candidates;prong 1 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hd0d0", "2-prong candidates;product of DCAxy to prim. vertex (cm^{2});entries", {HistType::kTH2F, {{500, -1., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hCTS", "2-prong candidates;cos #it{#theta}* (D^{0});entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hCt", "2-prong candidates;proper lifetime (D^{0}) * #it{c} (cm);entries", {HistType::kTH2F, {{120, -20., 100.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hCPA", "2-prong candidates;cosine of pointing angle;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hEtaCand", "2-prong candidates;candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hSelectionStatus", "2-prong candidates;selection status;entries", {HistType::kTH2F, {{5, -0.5, 4.5}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hImpParErr", "2-prong candidates;impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hDecLenErr", "2-prong candidates;decay length error (cm);entries", {HistType::kTH2F, {{100, 0., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("hDecLenXYErr", "2-prong candidates;decay length xy error (cm);entries", {HistType::kTH2F, {{100, 0., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - - // histograms for candidates in event mixing - registry.add("hPtHFMixing", "pT", {HistType::kTH1F, {{100, 0, 10, "p_{T}"}}}); - registry.add("hEtaHFMixing", "eta", {HistType::kTH1F, {{100, -4, 4, "#eta"}}}); - registry.add("hPhiHFMixing", "phi", {HistType::kTH1F, {{100, 0, TwoPI, "#varphi"}}}); - - // set axes of the correlation container std::vector corrAxis = {{axisDeltaEta, "#Delta#eta"}, {axisPtAssoc, "p_{T} (GeV/c)"}, {axisPtTrigger, "p_{T} (GeV/c)"}, @@ -194,166 +414,343 @@ struct HfTaskFlow { {axisVertexEfficiency, "z-vtx (cm)"}}; std::vector userAxis = {{axisMass, "m_{inv} (GeV/c^{2})"}}; - sameTPCTPCCh.setObject(new CorrelationContainer("sameEventTPCTPCChHadrons", "sameEventTPCTPCChHadrons", corrAxis, effAxis, {})); - sameTPCMFTCh.setObject(new CorrelationContainer("sameEventTPCMFTChHadrons", "sameEventTPCMFTChHadrons", corrAxis, effAxis, {})); - sameHF.setObject(new CorrelationContainer("sameEventHFHadrons", "sameEventHFHadrons", corrAxis, effAxis, userAxis)); - mixedTPCTPCCh.setObject(new CorrelationContainer("mixedEventTPCTPCChHadrons", "mixedEventTPCTPCChHadrons", corrAxis, effAxis, {})); - mixedHF.setObject(new CorrelationContainer("mixedEventHFHadrons", "mixedEventHFHadrons", corrAxis, effAxis, userAxis)); + // initialization of correlation containers for data + sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); + sameEventHf.setObject(new CorrelationContainer("sameEventHf", "sameEventHf", corrAxis, effAxis, userAxis)); + mixedEventHf.setObject(new CorrelationContainer("mixedEventHf", "mixedEventHf", corrAxis, effAxis, userAxis)); + + // initialization of correlation containes for monte-carlo + // sameTPCTPCChChMC.setObject(new CorrelationContainer("sameTPCTPCChChMC", "sameTPCTPCChChMC", corrAxis, effAxis, {})); + // mixedTPCTPCChChMC.setObject(new CorrelationContainer("mixedTPCTPCChChMC", "mixedTPCTPCChChMC", corrAxis, effAxis, {})); + } // End of init() function + + // ========================= + // Quality Assesment plots for Same Event + // ========================= + + // ---- DATA : TPC-TPC h-h Same Event QA ---- + template + void fillTpcTpcChChSameEventQa(float multiplicity, TTrack const& track) + { + registry.fill(HIST("Data/TpcTpc/HadronHadron/SameEvent/hPt"), track.pt()); + registry.fill(HIST("Data/TpcTpc/HadronHadron/SameEvent/hEta"), track.eta()); + registry.fill(HIST("Data/TpcTpc/HadronHadron/SameEvent/hPhi"), track.phi()); + registry.fill(HIST("Data/TpcTpc/HadronHadron/SameEvent/hYields"), multiplicity, track.pt(), track.eta()); + registry.fill(HIST("Data/TpcTpc/HadronHadron/SameEvent/hEtaPhi"), multiplicity, track.eta(), track.phi()); } - // --------------- - // templates - // FIXME: Some collisions are rejected here, what causes (part of) differences with the D0 task - // --------------- - template - bool isCollisionSelected(TCollision const& collision, bool fillHistograms = false) + template + void fillTpcTpcHfChSameEventQa(float multiplicity, TTrack const& track) { - if (processRun2 == true) { - // Run 2: trigger selection for data case - if (fillHistograms) - registry.fill(HIST("hEventCounter"), 1); - if (!processMc) { - if (!collision.alias_bit(kINT7)) { - return false; - } - } - // Run 2: further offline selection - if (fillHistograms) - registry.fill(HIST("hEventCounter"), 2); - if (!collision.sel7()) { - return false; - } - if (fillHistograms) - registry.fill(HIST("hEventCounter"), 3); - } else { - // Run 3: selection - if (fillHistograms) - registry.fill(HIST("hEventCounter"), 1); - if (!collision.sel8()) { - return false; - } - if (fillHistograms) - registry.fill(HIST("hEventCounter"), 3); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/hPt"), track.pt()); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/hEta"), track.eta()); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/hPhi"), track.phi()); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/hYields"), multiplicity, track.pt(), track.eta()); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/hEtaPhi"), multiplicity, track.eta(), track.phi()); + } + + // ---- MC REC : TPC-TPC h-h Same Event QA ---- + template + void fillTpcTpcChChSameEventQaMc(float multiplicity, TTrack const& track) + { + if constexpr (std::is_same_v) { // if MC Rec + registry.fill(HIST("MC/Rec/TpcTpc/HadronHadron/SameEvent/hPt"), track.pt()); + registry.fill(HIST("MC/Rec/TpcTpc/HadronHadron/SameEvent/hEta"), track.eta()); + registry.fill(HIST("MC/Rec/TpcTpc/HadronHadron/SameEvent/hPhi"), track.phi()); + registry.fill(HIST("MC/Rec/TpcTpc/HadronHadron/SameEvent/hYields"), multiplicity, track.pt(), track.eta()); + registry.fill(HIST("MC/Rec/TpcTpc/HadronHadron/SameEvent/hEtaPhi"), multiplicity, track.eta(), track.phi()); + } else { // if MC Gen + registry.fill(HIST("MC/Gen/TpcTpc/HadronHadron/SameEvent/hPt"), track.pt()); + registry.fill(HIST("MC/Gen/TpcTpc/HadronHadron/SameEvent/hEta"), track.eta()); + registry.fill(HIST("MC/Gen/TpcTpc/HadronHadron/SameEvent/hPhi"), track.phi()); + registry.fill(HIST("MC/Gen/TpcTpc/HadronHadron/SameEvent/hYields"), multiplicity, track.pt(), track.eta()); + registry.fill(HIST("MC/Gen/TpcTpc/HadronHadron/SameEvent/hEtaPhi"), multiplicity, track.eta(), track.phi()); } - return true; } - template - void fillQA(float multiplicity, TTracks const& tracks) + // ---- DATA : TPC-MFT h-h Same Event QA ---- + template + void fillTpcMftChChSameEventQa(float multiplicity, TTrack const& track, bool isTPC) { - int Ntracks = 0; - for (const auto& track1 : tracks) { - Ntracks++; - registry.fill(HIST("hPt"), track1.pt()); - registry.fill(HIST("hEta"), track1.eta()); - registry.fill(HIST("hPhi"), track1.phi()); - registry.fill(HIST("hYields"), multiplicity, track1.pt(), track1.eta()); - registry.fill(HIST("hEtaPhi"), multiplicity, track1.eta(), track1.phi()); + float phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + + if (isTPC) { // trigger hadron from TPC + registry.fill(HIST("Data/TpcMft/HadronHadron/SameEvent/hEtaTPC"), track.eta()); + registry.fill(HIST("Data/TpcMft/HadronHadron/SameEvent/hPhiTPC"), phi); + registry.fill(HIST("Data/TpcMft/HadronHadron/SameEvent/hEtaPhiTPC"), multiplicity, track.eta(), phi); + registry.fill(HIST("Data/TpcMft/HadronHadron/SameEvent/hPtTPC"), track.pt()); + registry.fill(HIST("Data/TpcMft/HadronHadron/SameEvent/hYieldsTPC"), multiplicity, track.pt(), track.eta()); + registry.fill(HIST("Data/TpcMft/HadronHadron/SameEvent/hMultiplicityTPC"), multiplicity); + // add multiplicity plot? + } else { // associated hadron from MFT + registry.fill(HIST("Data/TpcMft/HadronHadron/SameEvent/hEtaMFT"), track.eta()); + registry.fill(HIST("Data/TpcMft/HadronHadron/SameEvent/hPhiMFT"), phi); + registry.fill(HIST("Data/TpcMft/HadronHadron/SameEvent/hEtaPhiMFT"), multiplicity, track.eta(), phi); + registry.fill(HIST("Data/TpcMft/HadronHadron/SameEvent/hPtMFT"), track.pt()); + registry.fill(HIST("Data/TpcMft/HadronHadron/SameEvent/hYieldsMFT"), multiplicity, track.pt(), track.eta()); } - registry.fill(HIST("hNtracks"), Ntracks); } - template - void fillMixingQA(float multiplicity, float vz, TTracks const& tracks) + // ---- DATA : TPC-MFT HF-h Same Event QA ---- + + template + void fillTpcMftHfChSameEventQa(float multiplicity, TTrack const& track) + { + // Used to fill QA plots for associated track from MFT when doing TPC-MFT HF-h correlations + float phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/hEtaMFT"), track.eta()); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/hPhiMFT"), phi); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/hEtaPhiMFT"), multiplicity, track.eta(), phi); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/hPtMFT"), track.pt()); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/hYieldsMFT"), multiplicity, track.pt(), track.eta()); + // add plot for multiplicity ? + } + + // ---- DATA : TPC-TPC HF-h Same Event (Candidates) QA ---- + // TODO: Note: we do not need all these plots since they are in D0 and Lc task -> remove it after we are sure this works + template + void fillTpcTpcD0CandidateQa(float multiplicity, TTrack const& candidate) + { + float phi = candidate.phi(); + o2::math_utils::bringTo02Pi(phi); + + auto pt = candidate.pt(); + + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/2Prong/hMassVsPt"), hfHelper.invMassD0ToPiK(candidate), pt); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/2Prong/hMass"), hfHelper.invMassD0ToPiK(candidate)); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/2Prong/hMassVsPt"), hfHelper.invMassD0barToKPi(candidate), pt); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/2Prong/hMass"), hfHelper.invMassD0barToKPi(candidate)); + } + + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/2Prong/hMultiplicity"), multiplicity); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/2Prong/hEta"), candidate.eta()); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/2Prong/hPhi"), phi); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/2Prong/hPtCandidate"), pt); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/2Prong/hPtProng0"), candidate.ptProng0()); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/2Prong/hPtProng1"), candidate.ptProng1()); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/2Prong/hEtaCandVsPt"), candidate.eta(), pt); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/2Prong/hSelectionStatus"), candidate.isSelD0() + (candidate.isSelD0bar() * 2), pt); + } + + // ---- DATA : TPC-TPC HF-h Same Event (Candidates) QA ---- + // TODO: Note: we do not need all these plots since they are in D0 and Lc task -> remove it after we are sure this works + template + void fillTpcTpcLcCandidateQa(float multiplicity, TTrack const& candidate) + { + float phi = candidate.phi(); + o2::math_utils::bringTo02Pi(phi); + + auto pt = candidate.pt(); + auto ptProng0 = candidate.ptProng0(); + auto ptProng1 = candidate.ptProng1(); + auto ptProng2 = candidate.ptProng2(); + + if (candidate.isSelLcToPKPi() >= selectionFlagLcToPKPi) { + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hMass"), hfHelper.invMassLcToPKPi(candidate)); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hMassVsPtVsMult"), hfHelper.invMassLcToPKPi(candidate), pt, multiplicity); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hMassVsPt"), hfHelper.invMassLcToPKPi(candidate), pt); + } + if (candidate.isSelLcToPiKP() >= selectionFlagLcToPiKP) { + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hMass"), hfHelper.invMassLcToPiKP(candidate)); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hMassVsPtVsMult"), hfHelper.invMassLcToPiKP(candidate), pt, multiplicity); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hMassVsPt"), hfHelper.invMassLcToPiKP(candidate), pt); + } + + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hMultiplicity"), multiplicity); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hPt"), pt); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hPtProng0"), ptProng0); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hPtProng1"), ptProng1); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hPtProng2"), ptProng2); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hEta"), candidate.eta()); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hEtaVsPt"), candidate.eta(), pt); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hPhi"), phi); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hPhiVsPt"), phi, pt); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hSelectionStatus"), candidate.isSelLcToPKPi(), pt); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hSelectionStatus"), candidate.isSelLcToPiKP(), pt); + } + + // ---- DATA : TPC-MFT HF-h Same Event (Candidates) QA ---- + // TODO: Note: we do not need all these plots since they are in D0 and Lc task -> remove it after we are sure this works + template + void fillTpcMftD0CandidateQa(float multiplicity, TTrack const& candidate) { - registry.fill(HIST("hMultiplicityMixing"), multiplicity); - registry.fill(HIST("hVtxZMixing"), vz); - - int Ntracks = 0; - for (const auto& track1 : tracks) { - Ntracks++; - registry.fill(HIST("hPtMixing"), track1.pt()); - registry.fill(HIST("hEtaMixing"), track1.eta()); - registry.fill(HIST("hPhiMixing"), track1.phi()); + float phi = candidate.phi(); + auto pt = candidate.pt(); + o2::math_utils::bringTo02Pi(phi); + + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/2Prong/hMassVsPt"), hfHelper.invMassD0ToPiK(candidate), pt); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/2Prong/hMass"), hfHelper.invMassD0ToPiK(candidate)); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/2Prong/hMassVsPt"), hfHelper.invMassD0barToKPi(candidate), pt); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/2Prong/hMass"), hfHelper.invMassD0barToKPi(candidate)); } - registry.fill(HIST("hNtracksMixing"), Ntracks); + + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/2Prong/hEtaCandidate"), candidate.eta()); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/2Prong/hPhiCandidate"), phi); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/2Prong/hMultiplicityCandidate"), multiplicity); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/2Prong/hEtaPhiCandidate"), multiplicity, candidate.eta(), phi); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/2Prong/hYieldsCandidate"), multiplicity, pt, candidate.eta()); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/2Prong/hPtCandidate"), pt); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/2Prong/hPtProng0"), candidate.ptProng0()); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/2Prong/hPtProng1"), candidate.ptProng1()); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/2Prong/hEtaCandVsPt"), candidate.eta(), pt); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/2Prong/hSelectionStatus"), candidate.isSelD0() + (candidate.isSelD0bar() * 2), pt); } - template - void fillHFMixingQA(float multiplicity, float vz, TTracks const& tracks) + // ---- DATA : TPC-MFT HF-h Same Event (Candidates) QA ---- + // TODO: Note: we do not need all these plots since they are in D0 and Lc task -> remove it after we are sure this works + + template + void fillTpcMftLcCandidateQa(float multiplicity, TTrack const& candidate) { - registry.fill(HIST("hMultiplicityHFMixing"), multiplicity); - registry.fill(HIST("hVtxZHFMixing"), vz); - - int Ntracks = 0; - for (const auto& track1 : tracks) { - Ntracks++; - registry.fill(HIST("hPtHFMixing"), track1.pt()); - registry.fill(HIST("hEtaHFMixing"), track1.eta()); - registry.fill(HIST("hPhiHFMixing"), track1.phi()); + auto pt = candidate.pt(); + auto ptProng0 = candidate.ptProng0(); + auto ptProng1 = candidate.ptProng1(); + auto ptProng2 = candidate.ptProng2(); + float phi = candidate.phi(); + o2::math_utils::bringTo02Pi(phi); + + if (candidate.isSelLcToPKPi() >= selectionFlagLcToPKPi) { + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hMass"), hfHelper.invMassLcToPKPi(candidate)); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hMassVsPtVsMult"), hfHelper.invMassLcToPKPi(candidate), pt, multiplicity); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hMassVsPt"), hfHelper.invMassLcToPKPi(candidate), pt); + } + if (candidate.isSelLcToPiKP() >= selectionFlagLcToPiKP) { + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hMass"), hfHelper.invMassLcToPiKP(candidate)); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hMassVsPtVsMult"), hfHelper.invMassLcToPiKP(candidate), pt, multiplicity); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hMassVsPt"), hfHelper.invMassLcToPiKP(candidate), pt); } - registry.fill(HIST("hNtracksHFMixing"), Ntracks); + + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hYieldsCandidate"), multiplicity, pt, candidate.eta()); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hEtaPhiCandidate"), multiplicity, candidate.eta(), phi); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hMultiplicityCandidate"), multiplicity); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hPt"), pt); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hPtProng0"), ptProng0); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hPtProng1"), ptProng1); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hPtProng2"), ptProng2); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hEta"), candidate.eta()); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hEtaVsPt"), candidate.eta(), pt); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hPhi"), candidate.phi()); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hPhiVsPt"), candidate.phi(), pt); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hSelectionStatus"), candidate.isSelLcToPKPi(), pt); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hSelectionStatus"), candidate.isSelLcToPiKP(), pt); } - template - void fillMFTQA(float multiplicity, TTracks const& tracks) + // ========================= + // Cuts with functions + // ========================= + + // FIXME: Some collisions are rejected here, what causes (part of) differences with the D0 task + template + bool isAcceptedCollision(TCollision const& collision, bool fillHistograms = false) { - for (const auto& track1 : tracks) { - registry.fill(HIST("hEtaMFT"), track1.eta()); - float phi = track1.phi(); - o2::math_utils::bringTo02Pi(phi); - registry.fill(HIST("hPhiMFT"), phi); - registry.fill(HIST("hEtaPhiMFT"), multiplicity, track1.eta(), phi); + if (fillHistograms) { + registry.fill(HIST("Data/hEventCounter"), 1); + } + + if (processMc == false) { + if (!collision.sel8()) { + return false; + } + } + + if (fillHistograms) { + registry.fill(HIST("Data/hEventCounter"), 2); } + + return true; } // TODO: Check how to put this into a Filter template bool isAcceptedCandidate(TTrack const& candidate) { - if (!(candidate.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { + auto etaCandidate = candidate.eta(); + + if constexpr (std::is_same_v) { // For now, that means we do LambdaC + if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) { + return false; + } + if (etaCandidateMax >= 0. && std::abs(etaCandidate) > etaCandidateMax) { + return false; + } + return true; + } else { // For now, that means we do D0 + if (!(candidate.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { + return false; + } + if (etaCandidateMax >= 0. && std::abs(etaCandidate) > etaCandidateMax) { + return false; + } + return true; + } + } + + // TODO: Check how to put this into a Filter + // I tried to put it as a filter, but filters for normal TPC tracks also apply to MFT tracks I think + // and it seems that they are not compatible + template + bool isAcceptedMftTrack(TTrack const& mftTrack) + { + // cut on the eta of MFT tracks + if (mftTrack.eta() > etaMftTrackMax || mftTrack.eta() < etaMftTrackMin) { return false; } - if (yCandMax >= 0. && std::abs(hfHelper.yD0(candidate)) > yCandMax) { + + // cut on the number of clusters of the reconstructed MFT track + if (mftTrack.nClusters() < nClustersMftTrack) { return false; } + return true; } - // TODO: Note: we do not need all these plots since they are in D0 and Lc task -> remove it after we are sure this works - template - void fillCandidateQA(TTracks const& candidates) + // I am not sure if to template McParticles is useful, I'll address this when doing the MC Gen case of HF-h correlations + template + bool isMcParticleSelected(TMcParticles& mcParticles) { - for (const auto& candidate : candidates) { - if (!isAcceptedCandidate(candidate)) { - continue; - } - - if (candidate.isSelD0() >= selectionFlagD0) { - registry.fill(HIST("hMass"), hfHelper.invMassD0ToPiK(candidate), candidate.pt()); - } - if (candidate.isSelD0bar() >= selectionFlagD0bar) { - registry.fill(HIST("hMass"), hfHelper.invMassD0barToKPi(candidate), candidate.pt()); + // remove MC particles with charge = 0 + TParticlePDG* pdgparticle = pdg->GetParticle(mcParticles.pdgCode()); + if (pdgparticle != nullptr) { + if (pdgparticle->Charge() == 0) { + return false; } + } - registry.fill(HIST("hPtCand"), candidate.pt()); - registry.fill(HIST("hPtProng0"), candidate.ptProng0()); - registry.fill(HIST("hPtProng1"), candidate.ptProng1()); - registry.fill(HIST("hDecLength"), candidate.decayLength(), candidate.pt()); - registry.fill(HIST("hDecLengthXY"), candidate.decayLengthXY(), candidate.pt()); - registry.fill(HIST("hd0Prong0"), candidate.impactParameter0(), candidate.pt()); - registry.fill(HIST("hd0Prong1"), candidate.impactParameter1(), candidate.pt()); - registry.fill(HIST("hd0d0"), candidate.impactParameterProduct(), candidate.pt()); - registry.fill(HIST("hCTS"), hfHelper.cosThetaStarD0(candidate), candidate.pt()); - registry.fill(HIST("hCt"), hfHelper.ctD0(candidate), candidate.pt()); - registry.fill(HIST("hCPA"), candidate.cpa(), candidate.pt()); - registry.fill(HIST("hEtaCand"), candidate.eta(), candidate.pt()); - registry.fill(HIST("hSelectionStatus"), candidate.isSelD0() + (candidate.isSelD0bar() * 2), candidate.pt()); - registry.fill(HIST("hImpParErr"), candidate.errorImpactParameter0(), candidate.pt()); - registry.fill(HIST("hImpParErr"), candidate.errorImpactParameter1(), candidate.pt()); - registry.fill(HIST("hDecLenErr"), candidate.errorDecayLength(), candidate.pt()); - registry.fill(HIST("hDecLenXYErr"), candidate.errorDecayLengthXY(), candidate.pt()); + // MC particle has to be primary + if constexpr (step <= CorrelationContainer::kCFStepAnaTopology) { + return mcParticles.isPhysicalPrimary(); } + return true; } - template - void fillCorrelations(TTarget target, TTracksTrig const& tracks1, TTracksAssoc const& tracks2, float multiplicity, float posZ) + // ========================= + // Correlation functions + // ========================= + + template + void fillCorrelations(TTarget target, TTracksTrig const& tracks1, TTracksAssoc const& tracks2, float multiplicity, float posZ, bool sameEvent) { auto triggerWeight = 1; auto associatedWeight = 1; + // To avoid filling associated tracks QA many times + // I fill it only for the first trigger track of the collision + auto loopCounter = 0; + for (const auto& track1 : tracks1) { + loopCounter++; + float eta1 = track1.eta(); float pt1 = track1.pt(); float phi1 = track1.phi(); @@ -363,26 +760,79 @@ struct HfTaskFlow { // calculating inv. mass to be filled into the container below // Note: this is needed only in case of HF-hadron correlations + // TO DO ? Add one more if condition if its MC ? bool fillingHFcontainer = false; double invmass = 0; - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v || std::is_same_v) { // TODO: Check how to put this into a Filter if (!isAcceptedCandidate(track1)) { continue; } fillingHFcontainer = true; - invmass = hfHelper.invMassD0ToPiK(track1); + if constexpr (std::is_same_v) { // If D0 + invmass = hfHelper.invMassD0ToPiK(track1); + // Should add D0 bar ? + } else { // If Lc + invmass = hfHelper.invMassLcToPKPi(track1); + // Should add Lc bar ? (maybe not its the same mass right ?) + } + } + + // From Katarina's code + // in case of MC-generated, do additional selection on MCparticles : charge and isPhysicalPrimary + // if (processMc) { + // NOTE : this version with FilteredMcParticles is only for MC truth + if constexpr (std::is_same_v || std::is_same_v) { + if (!isMcParticleSelected(track1)) { + continue; + } + // TO-DO : add other if constexpr conditions when I will have more MC cases } // fill single-track distributions - if (!fillingHFcontainer) { - target->getTriggerHist()->Fill(CorrelationContainer::kCFStepReconstructed, pt1, multiplicity, posZ, triggerWeight); + if (!fillingHFcontainer) { // if not HF-h case + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, triggerWeight); } else { - target->getTriggerHist()->Fill(CorrelationContainer::kCFStepReconstructed, pt1, multiplicity, posZ, invmass, triggerWeight); + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, invmass, triggerWeight); + } + + // FILL QA PLOTS for trigger particle + if (sameEvent) { + if (processMc == false) { // If DATA + if constexpr (!std::is_same_v) { // IF TPC-TPC case + if constexpr (std::is_same_v) { // IF D0 CASE -> TPC-TPC D0-h + fillTpcTpcD0CandidateQa(multiplicity, track1); + } else if constexpr (std::is_same_v) { // IF LC CASE -> TPC-TPC Lc-h + fillTpcTpcLcCandidateQa(multiplicity, track1); + } else { // IF NEITHER D0 NOR LC -> TPC-TPC h-h + fillTpcTpcChChSameEventQa(multiplicity, track1); + } + } else { // IF TPC-MFT case + if constexpr (std::is_same_v) { // IF D0 CASE -> TPC-MFT D0-h + fillTpcMftD0CandidateQa(multiplicity, track1); + } else if constexpr (std::is_same_v) { // IF LC CASE -> TPC-MFT Lc-h + fillTpcMftLcCandidateQa(multiplicity, track1); + } else { // IF NEITHER D0 NOR LC -> TPC-MFT h-h + fillTpcMftChChSameEventQa(multiplicity, track1, true); + } // end of if condition for TPC-TPC or TPC-MFT case + } + // Maybe I won't need it for MC (first files are way lighter in MC, but also I need to loop over all tracks in MC GEN) + } else { // If MC (add cases later) + if constexpr (!std::is_same_v) { // IF TPC-TPC case + fillTpcTpcChChSameEventQaMc(multiplicity, track1); + } + } } for (const auto& track2 : tracks2) { + // apply cuts for MFT tracks + if constexpr (std::is_same_v) { + if (!isAcceptedMftTrack(track2)) { + continue; + } + } + // case of h-h correlations where the two types of tracks are the same // this avoids autocorrelations and double counting of particle pairs if constexpr (std::is_same_v) { @@ -392,11 +842,27 @@ struct HfTaskFlow { } // in case of HF-h correlations, remove candidate daughters from the pool of associated hadrons - // with which the candidate is being correlated - if constexpr (std::is_same_v) { - if ((track1.prong0Id() == track2.globalIndex()) || (track1.prong1Id() == track2.globalIndex())) { + // with which the candidate is being correlated (will not have to do it for TPC-MFT case) + if constexpr (!std::is_same_v) { // if NOT TPC-MFT case -> TPC-TPC case + if constexpr (std::is_same_v) { // Remove the 2 prong daughters + if ((track1.prong0Id() == track2.globalIndex()) || (track1.prong1Id() == track2.globalIndex())) { + continue; + } + } + if constexpr (std::is_same_v) { // Remove the 3 prong daughters + if ((track1.prong0Id() == track2.globalIndex()) || (track1.prong1Id() == track2.globalIndex()) || (track1.prong2Id() == track2.globalIndex())) { + continue; + } + } + } + + // in case of MC-generated, do additional selection on MCparticles : charge and isPhysicalPrimary + // if (processMc) { + if constexpr (std::is_same_v || std::is_same_v) { + if (!isMcParticleSelected(track2)) { continue; } + // Note : no need for HF if condition as this will always be normal track, but maybe for MFT } float eta2 = track2.eta(); @@ -414,62 +880,126 @@ struct HfTaskFlow { if (!fillingHFcontainer) { // fill pair correlations - target->getPairHist()->Fill(CorrelationContainer::kCFStepReconstructed, - eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, + target->getPairHist()->Fill(step, eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, triggerWeight * associatedWeight); } else { - target->getPairHist()->Fill(CorrelationContainer::kCFStepReconstructed, - eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, invmass, + target->getPairHist()->Fill(step, eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, invmass, triggerWeight * associatedWeight); } - } - } + + // FILL QA PLOTS for associated particle + if (sameEvent && (loopCounter == 1)) { + // if constexpr (std::is_same_v) { // If DATA + if constexpr (!std::is_same_v) { // IF TPC-TPC case + if constexpr (std::is_same_v) { // IF D0 CASE -> TPC-TPC D0-h + fillTpcTpcHfChSameEventQa(multiplicity, track2); + } else if constexpr (std::is_same_v) { // IF LC CASE -> TPC-TPC Lc-h + fillTpcTpcHfChSameEventQa(multiplicity, track2); + } + // No if condition if it is h-h, because it would be the same plots than for the trigger particle + } else { // IF TPC-MFT case + if constexpr (std::is_same_v) { // IF D0 CASE -> TPC-MFT D0-h + fillTpcMftHfChSameEventQa(multiplicity, track2); + } else if constexpr (std::is_same_v) { // IF LC CASE -> TPC-MFT Lc-h + fillTpcMftHfChSameEventQa(multiplicity, track2); + } else { // IF NEITHER D0 NOR LC -> TPC-MFT h-h + fillTpcMftChChSameEventQa(multiplicity, track2, false); + } // end of if condition for TPC-TPC or TPC-MFT case + } + //} else { // If MC (add cases later) + // fillTpcTpcChChSameEventQaMc(multiplicityTracks2, vz, tracks1); + //} + } + + } // end of loop over tracks2 + } // end of loop over tracks 1 } - template - void mixCollisions(MyCollisions const& collisions, TTracksTrig const& tracks1, TTracksAssoc const& tracks2, TLambda getPartsSize, OutputObj& corrContainer) + template + void mixCollisions(TCollisions const& collisions, TTracksTrig const& tracks1, TTracksAssoc const& tracks2, TLambda getPartsSize, OutputObj& corrContainer) { - using BinningType = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getPartsSize)>; - BinningType binningWithTracksSize{{getPartsSize}, {axisVertex, axisMultiplicity}, true}; + // The first one that I call "Data" should work for data and mc rec + using BinningTypeData = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getPartsSize)>; + BinningTypeData binningWithTracksSize{{getPartsSize}, {binsMixingVertex, binsMixingMultiplicity}, true}; auto tracksTuple = std::make_tuple(tracks1, tracks2); - Pair pair{binningWithTracksSize, nMixedEvents, -1, collisions, tracksTuple, &cache}; + Pair pair{binningWithTracksSize, nMixedEvents, -1, collisions, tracksTuple, &cache}; for (const auto& [collision1, tracks1, collision2, tracks2] : pair) { - if (!(isCollisionSelected(collision1, false))) { - continue; + if constexpr (!std::is_same_v) { // if NOT MC -> do collision cut + if (!(isAcceptedCollision(collision1, false))) { + continue; + } + if (!(isAcceptedCollision(collision2, false))) { + continue; + } } - if (!(isCollisionSelected(collision2, false))) { - continue; + + auto binningValues = binningWithTracksSize.getBinningValues(collision1, collisions); + int bin = binningWithTracksSize.getBin(binningValues); + + const auto multiplicityTracks1 = getPartsSize(collision1); + + if constexpr (std::is_same_v) { // If MC + registry.fill(HIST("MC/Rec/TpcTpc/HadronHadron/MixedEvent/hEventCountMixing"), bin); + } else { // If not MC + if constexpr (std::is_same_v) { // IF TPC-MFT case + if constexpr (std::is_same_v || std::is_same_v) { // IF HF-h case -> TPC-MFT HF-h + registry.fill(HIST("Data/TpcMft/HfHadron/MixedEvent/hEventCountMixing"), bin); + } else { // IF h-h case -> TPC-MFT h-h case + registry.fill(HIST("Data/TpcMft/HadronHadron/MixedEvent/hEventCountMixing"), bin); + } + } else { // IF TPC-TPC case + if constexpr (std::is_same_v || std::is_same_v) { // IF HF-h case -> TPC-TPC HF-h + registry.fill(HIST("Data/TpcTpc/HfHadron/MixedEvent/hEventCountHFMixing"), bin); + } else { // IF h-h case -> TPC-TPC h-h case + registry.fill(HIST("Data/TpcTpc/HadronHadron/MixedEvent/hEventCountMixing"), bin); + } + } // end of if condition for TPC-TPC or TPC-MFT case } + corrContainer->fillEvent(multiplicityTracks1, CorrelationContainer::kCFStepReconstructed); + fillCorrelations(corrContainer, tracks1, tracks2, multiplicityTracks1, collision1.posZ(), false); + } + } + + // template + // void mixCollisions(FilteredCollisionsWSelMult const& collisions, TTracksTrig const& tracks1, TTracksAssoc const& tracks2, TLambda getPartsSize, OutputObj& corrContainer) + template + void mixCollisionsMcTruth(TCollisions const& collisions, TTracksTrig const& tracks1, TTracksAssoc const& tracks2, TLambda getPartsSize, OutputObj& corrContainer) + { + using BinningTypeMcTruth = FlexibleBinningPolicy, aod::mccollision::PosZ, decltype(getPartsSize)>; + + BinningTypeMcTruth binningWithTracksSize{{getPartsSize}, {axisVertex, axisMultiplicity}, true}; + auto tracksTuple = std::make_tuple(tracks1, tracks2); + Pair pair{binningWithTracksSize, nMixedEvents, -1, collisions, tracksTuple, &cache}; + + for (const auto& [collision1, tracks1, collision2, tracks2] : pair) { + auto binningValues = binningWithTracksSize.getBinningValues(collision1, collisions); int bin = binningWithTracksSize.getBin(binningValues); const auto multiplicity = tracks2.size(); // get multiplicity of charged hadrons, which is used for slicing in mixing - const auto vz = collision1.posZ(); + // const auto vz = collision1.posZ(); - if constexpr (std::is_same_v) { - registry.fill(HIST("hEventCountHFMixing"), bin); - fillHFMixingQA(multiplicity, vz, tracks1); - } else { - registry.fill(HIST("hEventCountMixing"), bin); - fillMixingQA(multiplicity, vz, tracks1); - } + // TO BE DONE : ADD ONE MORE IF CONDITION TO FILL THE MC CASE + // TODO : FILL NEW PLOTS FOR MCTRUTH ONLY + registry.fill(HIST("MC/Gen/TpcTpc/HadronHadron/MixedEvent/hEventCountMixing"), bin); - corrContainer->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelations(corrContainer, tracks1, tracks2, multiplicity, collision1.posZ()); + corrContainer->fillEvent(multiplicity, CorrelationContainer::kCFStepAll); + fillCorrelations(corrContainer, tracks1, tracks2, multiplicity, collision1.posZ(), false); } } // ===================================== - // process same event correlations: h-h case + // DATA : process same event correlations: TPC-TPC h-h case // ===================================== - void processSameTpcTpcHH(MyCollisions::iterator const& collision, - MyTracks const& tracks) + + void processSameTpcTpcChCh(FilteredCollisionsWSelMult::iterator const& collision, + TracksWDcaSel const& tracks) { - if (!(isCollisionSelected(collision, true))) { + if (!(isAcceptedCollision(collision, true))) { return; } @@ -478,94 +1008,356 @@ struct HfTaskFlow { // options are ran at the same time // temporary solution, since other correlation options always have to be ran with h-h, too // TODO: rewrite it in a more intelligent way - const auto multiplicity = tracks.size(); - registry.fill(HIST("hMultiplicity"), multiplicity); - registry.fill(HIST("hVtxZ"), collision.posZ()); + // const auto multiplicity = tracks.size(); + const auto multiplicity = collision.multNTracksPV(); + registry.fill(HIST("Data/TpcTpc/HadronHadron/SameEvent/hMultiplicity"), multiplicity); + registry.fill(HIST("Data/TpcTpc/HadronHadron/SameEvent/hVtxZ"), collision.posZ()); + + BinningPolicyBase<2> baseBinning{{axisVertex, axisMultiplicity}, true}; + int bin = baseBinning.getBin(std::make_tuple(collision.posZ(), multiplicity)); + registry.fill(HIST("Data/TpcTpc/HadronHadron/SameEvent/hEventCountSame"), bin); + + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + + // TO-DO : add if condition for when we will implant corrected correlations (kCFStepReconstructed -> kCFStepCorrected) + fillCorrelations(sameEvent, tracks, tracks, multiplicity, collision.posZ(), true); + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcTpcChCh, "DATA : Process same-event correlations for TPC-TPC h-h case", false); + + // ===================================== + // DATA : process same event correlations: TPC-TPC HF-h case for D0 + // ===================================== + + void processSameTpcTpcD0Ch(FilteredCollisionsWSelMult::iterator const& collision, + TracksWDcaSel const& tracks, + HfCandidatesSelD0 const& candidates) + { + auto fillEventSelectionPlots = true; + // When doing reference flow, two cases are used (HF-h, h-h) and thus eventSelectionPlots was filled twice + if (doReferenceFlow) + fillEventSelectionPlots = false; + + if (!(isAcceptedCollision(collision, fillEventSelectionPlots))) { + return; + } + + const auto multiplicity = collision.multNTracksPV(); BinningPolicyBase<2> baseBinning{{axisVertex, axisMultiplicity}, true}; int bin = baseBinning.getBin(std::make_tuple(collision.posZ(), multiplicity)); - registry.fill(HIST("hEventCountSame"), bin); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/2Prong/hEventCountSame"), bin); + + sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - sameTPCTPCCh->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillQA(multiplicity, tracks); - fillCorrelations(sameTPCTPCCh, tracks, tracks, multiplicity, collision.posZ()); + fillCorrelations(sameEventHf, candidates, tracks, multiplicity, collision.posZ(), true); } - PROCESS_SWITCH(HfTaskFlow, processSameTpcTpcHH, "Process same-event correlations for h-h case", true); + PROCESS_SWITCH(HfTaskFlow, processSameTpcTpcD0Ch, "DATA : Process same-event correlations for TPC-TPC D0-h case", false); // ===================================== - // process same event correlations: HF-h case + // DATA : process same event correlations: TPC-TPC HF-h case for Lc // ===================================== - void processSameHfHadrons(MyCollisions::iterator const& collision, - MyTracks const& tracks, - HfCandidatesSel const& candidates) + + void processSameTpcTpcLcCh(FilteredCollisionsWSelMult::iterator const& collision, + TracksWDcaSel const& tracks, + HfCandidatesSelLc const& candidates) { - if (!(isCollisionSelected(collision, false))) { + auto fillEventSelectionPlots = true; + + // When doing reference flow, two cases are used (HF-h, h-h) and thus eventSelectionPlots was filled twice + if (doReferenceFlow) + fillEventSelectionPlots = false; + + if (!(isAcceptedCollision(collision, fillEventSelectionPlots))) { return; } - const auto multiplicity = tracks.size(); + const auto multiplicity = collision.multNTracksPV(); + BinningPolicyBase<2> baseBinning{{axisVertex, axisMultiplicity}, true}; + int bin = baseBinning.getBin(std::make_tuple(collision.posZ(), multiplicity)); + registry.fill(HIST("Data/TpcTpc/HfHadron/SameEvent/3Prong/hEventCountSame"), bin); + + sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - sameHF->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCandidateQA(candidates); - fillCorrelations(sameHF, candidates, tracks, multiplicity, collision.posZ()); + fillCorrelations(sameEventHf, candidates, tracks, multiplicity, collision.posZ(), true); } - PROCESS_SWITCH(HfTaskFlow, processSameHfHadrons, "Process same-event correlations for HF-h case", true); + PROCESS_SWITCH(HfTaskFlow, processSameTpcTpcLcCh, "DATA : Process same-event correlations for TPC-TPC Lc-h case", false); // ===================================== - // process same event correlations: h-MFT case + // DATA : process same event correlations: TPC-MFT h-h case // ===================================== - void processSameTpcMftHH(MyCollisions::iterator const& collision, - MyTracks const& tracks, - aod::MFTTracks const& mfttracks) + + void processSameTpcMftChCh(FilteredCollisionsWSelMult::iterator const& collision, + TracksWDcaSel const& tracks, + aod::MFTTracks const& mftTracks) { - if (!(isCollisionSelected(collision, false))) { + if (!(isAcceptedCollision(collision, true))) { return; } - const auto multiplicity = tracks.size(); + const auto multiplicity = collision.multNTracksPV(); + BinningPolicyBase<2> baseBinning{{axisVertex, axisMultiplicity}, true}; + int bin = baseBinning.getBin(std::make_tuple(collision.posZ(), multiplicity)); + registry.fill(HIST("Data/TpcMft/HadronHadron/SameEvent/hEventCountSame"), bin); - sameTPCMFTCh->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillMFTQA(multiplicity, mfttracks); - fillCorrelations(sameTPCMFTCh, tracks, mfttracks, multiplicity, collision.posZ()); + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + + fillCorrelations(sameEvent, tracks, mftTracks, multiplicity, collision.posZ(), true); } - PROCESS_SWITCH(HfTaskFlow, processSameTpcMftHH, "Process same-event correlations for h-MFT case", true); + PROCESS_SWITCH(HfTaskFlow, processSameTpcMftChCh, "DATA : Process same-event correlations for TPC-MFT h-h case", false); - // TODO: add also MFT option // ===================================== - // process mixed event correlations: h-h case + // DATA : process same event correlations: TPC-MFT HF-h case for D0 // ===================================== - void processMixedTpcTpcHH(MyCollisions const& collisions, - MyTracks const& tracks) + + void processSameTpcMftD0Ch(FilteredCollisionsWSelMult::iterator const& collision, + HfCandidatesSelD0 const& candidates, + TracksWDcaSel const& /*tracks*/, + aod::MFTTracks const& mftTracks) + { + auto fillEventSelectionPlots = true; + + // When doing reference flow, two cases are used (HF-h, h-h) and thus eventSelectionPlots was filled twice + if (doReferenceFlow) + fillEventSelectionPlots = false; + + if (!(isAcceptedCollision(collision, fillEventSelectionPlots))) { + return; + } + + const auto multiplicity = collision.multNTracksPV(); + BinningPolicyBase<2> baseBinning{{axisVertex, axisMultiplicity}, true}; + int bin = baseBinning.getBin(std::make_tuple(collision.posZ(), multiplicity)); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/2Prong/hEventCountSame"), bin); + + sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + + fillCorrelations(sameEventHf, candidates, mftTracks, multiplicity, collision.posZ(), true); + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcMftD0Ch, "DATA : Process same-event correlations for TPC-MFT D0-h case", false); + + // ===================================== + // DATA : process same event correlations: TPC-MFT HF-h case for Lc + // ===================================== + + void processSameTpcMftLcCh(FilteredCollisionsWSelMult::iterator const& collision, + HfCandidatesSelLc const& candidates, + TracksWDcaSel const& /*tracks*/, + aod::MFTTracks const& mftTracks) + { + auto fillEventSelectionPlots = true; + + // When doing reference flow, two cases are used (HF-h, h-h) and thus eventSelectionPlots was filled twice + if (doReferenceFlow) + fillEventSelectionPlots = false; + + if (!(isAcceptedCollision(collision, fillEventSelectionPlots))) { + return; + } + + const auto multiplicity = collision.multNTracksPV(); + BinningPolicyBase<2> baseBinning{{axisVertex, axisMultiplicity}, true}; + int bin = baseBinning.getBin(std::make_tuple(collision.posZ(), multiplicity)); + registry.fill(HIST("Data/TpcMft/HfHadron/SameEvent/3Prong/hEventCountSame"), bin); + + sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + + fillCorrelations(sameEventHf, candidates, mftTracks, multiplicity, collision.posZ(), true); + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcMftLcCh, "DATA : Process same-event correlations for TPC-MFT Lc-h case", false); + + // ===================================== + // MONTE-CARLO : process same event correlations: TPC-TPC h-h case + // ===================================== + + // Katarina's version = MC Truth + void processSameTpcTpcChChmcGEN(FilteredMcCollisions::iterator const& mcCollision, + FilteredMcParticles const& mcParticles) + { + + // Not sure why to use this + // if (collisions.size() == 0) { + // return; + //} + + // if (!collision.has_mcCollision()) { + // LOGF(info, "No MC collision for this collision, skip..."); + // return; + // } + + // TODO : check if I have to get my multiplicity based on multNTracksPV or mcParticles.size() + // const auto multiplicity = mcParticles.size(); // Note: these are all MC particles after selection (not only primary) + const auto multiplicity = mcCollision.multMCPVz(); + registry.fill(HIST("MC/Gen/TpcTpc/HadronHadron/SameEvent/hMultiplicity"), multiplicity); + registry.fill(HIST("MC/Gen/TpcTpc/HadronHadron/SameEvent/hVtxZ"), mcCollision.posZ()); + + // fill correlations for all MC collisions + // In Katka's code, the first time doing this does not fill the histograms, right now will be filled two times.. + // auto multPrimaryCharge0 = fillTpcTpcChChSameEventQaMc(multiplicity, mcParticles); + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepAll); + fillCorrelations(sameEvent, mcParticles, mcParticles, multiplicity, mcCollision.posZ(), true); + + // TO-DO : fill correlation container for MC collisions that have a reconstructed collision + // got rid of the second const auto for multPrimaryCharge0 + // This line below for sure induce that some plots are filled two times + // multPrimaryCharge0 = fillTpcTpcChChSameEventQaMc(multiplicity, mcParticles); + // sameTPCTPCChChMC->fillEvent(multPrimaryCharge0, CorrelationContainer::kCFStepVertex); + // fillCorrelations(sameTPCTPCChChMC, mcParticles, mcParticles, multPrimaryCharge0, mcCollision.posZ(), true); + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcTpcChChmcGEN, "MONTE-CARLO : Process same-event correlations for TPC-TPC h-h case", false); + + // ===================================== + // DATA : process mixed event correlations:TPC-TPC h-h case + // ===================================== + // TO BECOME DATA & MC REC ? + + void processMixedTpcTpcChCh(FilteredCollisionsWSelMult const& collisions, + TracksWDcaSel const& tracks) { // we want to group collisions based on charged-track multiplicity - auto getTracksSize = [&tracks, this](MyCollisions::iterator const& col) { - auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, col.globalIndex(), this->cache); // it's cached, so slicing/grouping happens only once - auto size = associatedTracks.size(); - return size; + // auto getTracksSize = [&tracks, this](FilteredCollisionsWSelMult::iterator const& col) { + // auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, col.globalIndex(), this->cache); // it's cached, so slicing/grouping happens only once + // auto size = associatedTracks.size(); + // return size; + // }; + + auto getMultiplicity = [](FilteredCollisionsWSelMult::iterator const& collision) { + auto multiplicity = collision.numContrib(); + return multiplicity; }; - mixCollisions(collisions, tracks, tracks, getTracksSize, mixedTPCTPCCh); + // mixCollisions(collisions, tracks, tracks, getTracksSize, mixedEvent); + mixCollisions(collisions, tracks, tracks, getMultiplicity, mixedEvent); } - PROCESS_SWITCH(HfTaskFlow, processMixedTpcTpcHH, "Process mixed-event correlations for h-h case", true); + PROCESS_SWITCH(HfTaskFlow, processMixedTpcTpcChCh, "DATA : Process mixed-event correlations for TPC-TPC h-h case", false); // ===================================== - // process mixed event correlations: h-h case + // DATA : process mixed event correlations: TPC-TPC HF-h case for D0 // ===================================== - void processMixedHfHadrons(MyCollisions const& collisions, - MyTracks const& tracks, - HfCandidatesSel const& candidates) + + void processMixedTpcTpcD0Ch(FilteredCollisionsWSelMult const& collisions, + TracksWDcaSel const& tracks, + HfCandidatesSelD0 const& candidates) { // we want to group collisions based on charged-track multiplicity - auto getTracksSize = [&tracks, this](MyCollisions::iterator const& col) { + auto getMultiplicity = [](FilteredCollisionsWSelMult::iterator const& collision) { + auto multiplicity = collision.numContrib(); + return multiplicity; + }; + + mixCollisions(collisions, candidates, tracks, getMultiplicity, mixedEventHf); + } + PROCESS_SWITCH(HfTaskFlow, processMixedTpcTpcD0Ch, "DATA : Process mixed-event correlations for TPC-TPC D0-h case", false); + + // ===================================== + // DATA : process mixed event correlations: TPC-TPC HF-h case for Lc + // ===================================== + + void processMixedTpcTpcLcCh(FilteredCollisionsWSelMult const& collisions, + TracksWDcaSel const& tracks, + HfCandidatesSelLc const& candidates) + { + // we want to group collisions based on charged-track multiplicity + auto getTracksSize = [&tracks, this](FilteredCollisionsWSelMult::iterator const& col) { + // Still o2::aod::track::collisionId with HF ??? -> I don't think so auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, col.globalIndex(), this->cache); auto size = associatedTracks.size(); return size; }; - mixCollisions(collisions, candidates, tracks, getTracksSize, mixedHF); + mixCollisions(collisions, candidates, tracks, getTracksSize, mixedEventHf); + } + PROCESS_SWITCH(HfTaskFlow, processMixedTpcTpcLcCh, "DATA : Process mixed-event correlations for TPC-TPC Lc-h case", false); + + // ===================================== + // DATA : process mixed event correlations: TPC-MFT h-h case + // ===================================== + + void processMixedTpcMftChCh(FilteredCollisionsWSelMult const& collisions, + TracksWDcaSel const& tracks, + aod::MFTTracks const& mftTracks) + { + // we want to group collisions based on charged-track multiplicity + // auto getTracksSize = [&tracks, this](FilteredCollisionsWSelMult::iterator const& col) { + // auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, col.globalIndex(), this->cache); + // auto size = associatedTracks.size(); + // return size; + // }; + + auto getMultiplicity = [](FilteredCollisionsWSelMult::iterator const& collision) { + auto multiplicity = collision.numContrib(); + return multiplicity; + }; + + mixCollisions(collisions, tracks, mftTracks, getMultiplicity, mixedEvent); + } + PROCESS_SWITCH(HfTaskFlow, processMixedTpcMftChCh, "DATA : Process mixed-event correlations for TPC-MFT h-h case", false); + + // ===================================== + // DATA : process mixed event correlations: TPC-MFT HF-h case for D0 + // ===================================== + + void processMixedTpcMftD0Ch(FilteredCollisionsWSelMult const& collisions, + HfCandidatesSelD0 const& candidates, + aod::MFTTracks const& mftTracks, + TracksWDcaSel const& /*tracks*/) + { + // we want to group collisions based on charged-track multiplicity + auto getMultiplicity = [](FilteredCollisionsWSelMult::iterator const& collision) { + auto multiplicity = collision.numContrib(); + return multiplicity; + }; + + mixCollisions(collisions, candidates, mftTracks, getMultiplicity, mixedEventHf); + } + PROCESS_SWITCH(HfTaskFlow, processMixedTpcMftD0Ch, "DATA : Process mixed-event correlations for TPC-MFT D0-h case", false); + + // ===================================== + // DATA : process mixed event correlations: TPC-MFT HF-h case + // ===================================== + + void processMixedTpcMftLcCh(FilteredCollisionsWSelMult const& collisions, + HfCandidatesSelLc const& candidates, + aod::MFTTracks const& mftTracks) + { + + // we want to group collisions based on charged-track multiplicity + auto getMultiplicity = [](FilteredCollisionsWSelMult::iterator const& collision) { + auto multiplicity = collision.numContrib(); + return multiplicity; + }; + + mixCollisions(collisions, candidates, mftTracks, getMultiplicity, mixedEventHf); + } + PROCESS_SWITCH(HfTaskFlow, processMixedTpcMftLcCh, "DATA : Process mixed-event correlations for TPC-MFT Lc-h case", false); + + // ===================================== + // MONTE-CARLO : process mixed event correlations: TPC-TPC h-h case + // ===================================== + + // MC gen + void processMixedTpcTpcChChmcGEN(FilteredMcCollisions const& mcCollisions, + FilteredMcParticles const& mcParticles) + { + // use normal index instead of globalIndex for MixedEvent ?? + + // we want to group collisions based on charged-track multiplicity + // auto getTracksSize = [&mcParticles, this](FilteredMcCollisions::iterator const& mcCol) { + // auto associatedTracks = mcParticles.sliceByCached(o2::aod::mcparticle::mcCollisionId, mcCol.globalIndex(), this->cache); // it's cached, so slicing/grouping happens only once + // auto size = associatedTracks.size(); + // return size; + //}; + + auto getMultiplicity = [](FilteredMcCollisions::iterator const& mcCollision) { + auto multiplicity = mcCollision.multMCPVz(); + return multiplicity; + }; + + mixCollisionsMcTruth(mcCollisions, mcParticles, mcParticles, getMultiplicity, mixedEvent); + + // TO-DO : mixed event for particles that have a reconstructed collision kCFStepVertex } - PROCESS_SWITCH(HfTaskFlow, processMixedHfHadrons, "Process mixed-event correlations for HF-h case", true); -}; + PROCESS_SWITCH(HfTaskFlow, processMixedTpcTpcChChmcGEN, "MONTE-CARLO : Process mixed-event correlations for TPC-TPC h-h case", false); +}; // End of struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGHF/HFC/Utils/utilsCorrelations.h b/PWGHF/HFC/Utils/utilsCorrelations.h new file mode 100644 index 00000000000..a38e36f7fc1 --- /dev/null +++ b/PWGHF/HFC/Utils/utilsCorrelations.h @@ -0,0 +1,153 @@ +// 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 utilsCorrelations.h +/// \brief Utilities for HFC analyses +/// \author Xu Wang + +#ifndef PWGHF_HFC_UTILS_UTILSCORRELATIONS_H_ +#define PWGHF_HFC_UTILS_UTILSCORRELATIONS_H_ + +#include +#include + +#include "CommonConstants/PhysicsConstants.h" + +namespace o2::analysis::hf_correlations +{ +enum Region { + Default = 0, + Toward, + Away, + Transverse +}; + +enum PairSign { + SignNotDefined = 0, + LcPosTrkPos, + LcPosTrkNeg, + LcNegTrkPos, + LcNegTrkNeg +}; + +template +Region getRegion(T const deltaPhi) +{ + if (std::abs(deltaPhi) < o2::constants::math::PIThird) { + return Toward; + } else if (deltaPhi > 2. * o2::constants::math::PIThird && deltaPhi < 4. * o2::constants::math::PIThird) { + return Away; + } else { + return Transverse; + } +} + +// Pair Sign Calculation +template +int signCalulation(TrgPt const& trigPt, TrkPt const& assocPt) +{ + int sign = 0; + if (trigPt > 0. && assocPt > 0.) { + sign = LcPosTrkPos; + } else if (trigPt > 0. && assocPt < 0.) { + sign = LcPosTrkNeg; + } else if (trigPt < 0. && assocPt > 0.) { + sign = LcNegTrkPos; + } else if (trigPt < 0. && assocPt < 0.) { + sign = LcNegTrkNeg; + } else { + sign = SignNotDefined; + } + return sign; +} + +template +bool passPIDSelection(Atrack const& track, SpeciesContainer const mPIDspecies, + T1 const maxTPC, T2 const maxTOF, double ptThreshold = 0.75, bool tofForced = false) +{ + // Ensure size consistency + if (mPIDspecies.value.size() != maxTPC.value.size() || mPIDspecies.value.size() != maxTOF.value.size()) { + LOGF(error, "Size of particle species and corresponding nSigma selection arrays should be the same"); + return false; // Early exit on error + } + + for (size_t speciesIndex = 0; speciesIndex < mPIDspecies.value.size(); ++speciesIndex) { + auto const& pid = mPIDspecies->at(speciesIndex); + auto nSigmaTPC = o2::aod::pidutils::tpcNSigma(pid, track); + + if (tofForced && !track.hasTOF()) + return false; + + if (speciesIndex == 0) { // First species logic + if (std::abs(nSigmaTPC) > maxTPC->at(speciesIndex)) { + return false; // TPC check failed + } + if (tofForced || (track.pt() > ptThreshold && track.hasTOF())) { + auto nSigmaTOF = o2::aod::pidutils::tofNSigma(pid, track); + if (std::abs(nSigmaTOF) > maxTOF->at(speciesIndex)) { + return false; // TOF check failed + } + } + } else { // Other species logic + if (std::abs(nSigmaTPC) < maxTPC->at(speciesIndex)) { // Check TPC nSigma first + if (track.hasTOF()) { + auto nSigmaTOF = o2::aod::pidutils::tofNSigma(pid, track); + if (std::abs(nSigmaTOF) < maxTOF->at(speciesIndex)) { + return false; // Reject if both TPC and TOF are within thresholds + } + } else { + return false; // Reject if only TPC is within threshold and TOF is unavailable + } + } + } + } + return true; // Passed all checks +} + +// ========= Find Leading Particle ============== +template //// FIXME: 14 days +int findLeadingParticle(TTracks const& tracks, T1 const etaTrackMax) +{ + auto leadingParticle = tracks.begin(); + for (auto const& track : tracks) { + if (std::abs(track.eta()) > etaTrackMax) { + continue; + } + if (track.pt() > leadingParticle.pt()) { + leadingParticle = track; + } + } + return leadingParticle.globalIndex(); +} + +// ======= Find Leading Particle for McGen ============ +template +int findLeadingParticleMcGen(TMcParticles const& mcParticles, T1 const etaTrackMax, T2 const ptTrackMin) +{ + auto leadingParticle = mcParticles.begin(); + for (auto const& mcParticle : mcParticles) { + if (std::abs(mcParticle.eta()) > etaTrackMax) { + continue; + } + if (mcParticle.pt() < ptTrackMin) { + continue; + } + if ((std::abs(mcParticle.pdgCode()) != kElectron) && (std::abs(mcParticle.pdgCode()) != kMuonMinus) && (std::abs(mcParticle.pdgCode()) != kPiPlus) && (std::abs(mcParticle.pdgCode()) != kKPlus) && (std::abs(mcParticle.pdgCode()) != kProton)) { + continue; + } + if (mcParticle.pt() > leadingParticle.pt()) { + leadingParticle = mcParticle; + } + } + return leadingParticle.globalIndex(); +} +} // namespace o2::analysis::hf_correlations +#endif // PWGHF_HFC_UTILS_UTILSCORRELATIONS_H_ diff --git a/PWGHF/HFL/CMakeLists.txt b/PWGHF/HFL/CMakeLists.txt index 99ff0609258..27656177186 100644 --- a/PWGHF/HFL/CMakeLists.txt +++ b/PWGHF/HFL/CMakeLists.txt @@ -9,4 +9,6 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +add_subdirectory(TableProducer) add_subdirectory(Tasks) + diff --git a/PWGHF/HFL/DataModel/ElectronSelectionTable.h b/PWGHF/HFL/DataModel/ElectronSelectionTable.h new file mode 100644 index 00000000000..0afb342831a --- /dev/null +++ b/PWGHF/HFL/DataModel/ElectronSelectionTable.h @@ -0,0 +1,126 @@ +// 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 ElectronSelectionTable.h +/// \brief Definitions of tables produced by Electron Selection + +/// \author Rashi Gupta , IIT Indore +/// \author Ravindra Singh , IIT Indore + +#ifndef PWGHF_HFL_DATAMODEL_ELECTRONSELECTIONTABLE_H_ +#define PWGHF_HFL_DATAMODEL_ELECTRONSELECTIONTABLE_H_ + +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +// definition of columns and tables for electron selection +namespace hf_sel_electron +{ +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! collisioniD of the electron track +DECLARE_SOA_INDEX_COLUMN(Track, track); //! trackid of of the electron track +DECLARE_SOA_COLUMN(EtaTrack, etaTrack, float); //! pseudorapidity of the electron track +DECLARE_SOA_COLUMN(PhiTrack, phiTrack, float); //! azimuth of the electron track +DECLARE_SOA_COLUMN(PtTrack, ptTrack, float); //! transverse momentum of the electron track +DECLARE_SOA_COLUMN(PTrack, pTrack, float); //! momentum of the electron track +DECLARE_SOA_COLUMN(RapidityTrack, rapidityTrack, float); //! rapidity of the electron track +DECLARE_SOA_COLUMN(DcaXYTrack, dcaXYTrack, float); //! dca of the electron in xy direction +DECLARE_SOA_COLUMN(DcaZTrack, dcaZTrack, float); //! dca of the electron in z direction +DECLARE_SOA_COLUMN(TpcNSigmaElTrack, tpcNSigmaElTrack, float); //! tpcNSigma of the electron track(TPC PID) +DECLARE_SOA_COLUMN(TofNSigmaElTrack, tofNSigmaElTrack, float); //! tofNSigma of the electron track(TOF PID) + +// EMCal cluster values +DECLARE_SOA_COLUMN(EnergyEmcCluster, energyEmcCluster, float); //! energy of the EMCal cluster +DECLARE_SOA_COLUMN(EtaEmcCluster, etaEmcCluster, float); //! pseudorapidity of the EMCal cluster +DECLARE_SOA_COLUMN(PhiEmcCluster, phiEmcCluster, float); //! azimuth of the EMCal cluster +DECLARE_SOA_COLUMN(M02EmcCluster, m02EmcCluster, float); //! shower shape long axis of the EMCal cluster +DECLARE_SOA_COLUMN(M20EmcCluster, m20EmcCluster, float); //! shower shape short axis of the EMCal cluster +DECLARE_SOA_COLUMN(NCellsEmcCluster, nCellsEmcCluster, uint8_t); //! number of cells of the EMCal cluster +DECLARE_SOA_COLUMN(TimeEmcCluster, timeEmcCluster, float); //! time of the EMCal cluster (ns) + +DECLARE_SOA_COLUMN(DeltaEtaMatch, deltaEtaMatch, float); //! dEta matched track to EMCal cluster +DECLARE_SOA_COLUMN(DeltaPhiMatch, deltaPhiMatch, float); //! dPhi matched track to EMCal cluster +DECLARE_SOA_COLUMN(IsEmcal, isEmcal, bool); //! electron information with Emcal +} // namespace hf_sel_electron +DECLARE_SOA_TABLE(HfSelEl, "AOD", "HFSELEL", //! Electron Informations + o2::soa::Index<>, + hf_sel_electron::CollisionId, + hf_sel_electron::TrackId, + hf_sel_electron::EtaTrack, + hf_sel_electron::PhiTrack, + hf_sel_electron::PtTrack, + hf_sel_electron::PTrack, + hf_sel_electron::RapidityTrack, + hf_sel_electron::DcaXYTrack, + hf_sel_electron::DcaZTrack, + hf_sel_electron::TpcNSigmaElTrack, + hf_sel_electron::TofNSigmaElTrack, + hf_sel_electron::EnergyEmcCluster, + hf_sel_electron::EtaEmcCluster, + hf_sel_electron::PhiEmcCluster, + hf_sel_electron::M02EmcCluster, + hf_sel_electron::M20EmcCluster, + hf_sel_electron::NCellsEmcCluster, + hf_sel_electron::TimeEmcCluster, + hf_sel_electron::DeltaEtaMatch, + hf_sel_electron::DeltaPhiMatch, + hf_sel_electron::IsEmcal); +// definition of columns and tables for HfcorrElectron Selection +namespace hf_corr_sel_electron +{ +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! collisioniD of the electron track +DECLARE_SOA_INDEX_COLUMN(Track, track); //! trackid of of the electron track +DECLARE_SOA_COLUMN(EtaTrack, etaTrack, float); //! pseudorapidity of the electron track +DECLARE_SOA_COLUMN(PhiTrack, phiTrack, float); //! azimuth of the electron track +DECLARE_SOA_COLUMN(PtTrack, ptTrack, float); //! transverse momentum of the electron track +DECLARE_SOA_COLUMN(TpcNSigmaElTrack, tpcNSigmaElTrack, float); //! tpcNSigma of the electron track(TPC PID) +DECLARE_SOA_COLUMN(TofNSigmaElTrack, tofNSigmaElTrack, float); //! tofNSigma of the electron track(TOF PID) +DECLARE_SOA_COLUMN(IsLSElectron, isLSElectron, int); //! Like sign electron information +DECLARE_SOA_COLUMN(IsULSElectron, isULSElectron, int); //! Unlike sign electron information +DECLARE_SOA_COLUMN(IsEmcal, isEmcal, bool); //! electron information +} // namespace hf_corr_sel_electron + +DECLARE_SOA_TABLE(HfCorrSelEl, "AOD", "HfCORRSELEL", //! Electron Informations + o2::soa::Index<>, + hf_corr_sel_electron::CollisionId, + hf_corr_sel_electron::TrackId, + hf_corr_sel_electron::EtaTrack, + hf_corr_sel_electron::PhiTrack, + hf_corr_sel_electron::PtTrack, + hf_corr_sel_electron::TpcNSigmaElTrack, + hf_corr_sel_electron::TofNSigmaElTrack, + hf_corr_sel_electron::IsLSElectron, + hf_corr_sel_electron::IsULSElectron, + hf_corr_sel_electron::IsEmcal); + +// definition of columns and tables for Mc Gen HfElectron Selection +namespace hf_mcgen_sel_electron +{ +DECLARE_SOA_INDEX_COLUMN(McCollision, mcCollision); //! collisioniD of the electron track +DECLARE_SOA_INDEX_COLUMN(Track, track); //! trackid of of the electron track +DECLARE_SOA_COLUMN(EtaTrackMc, etaTrackMc, float); //! pseudorapidity of the electron track +DECLARE_SOA_COLUMN(PhiTrackMc, phiTrackMc, float); //! azimuth of the electron track +DECLARE_SOA_COLUMN(PtTrackMc, ptTrackMc, float); //! transverse momentum of the electron track +DECLARE_SOA_COLUMN(IsNonHfeMc, isNonHfeMc, bool); //! Non-Heavy flavour electron information + +} // namespace hf_mcgen_sel_electron + +DECLARE_SOA_TABLE(HfMcGenSelEl, "AOD", "HFMCGENSELEL", //! Electron Informations + o2::soa::Index<>, + hf_mcgen_sel_electron::McCollisionId, + hf_mcgen_sel_electron::TrackId, + hf_mcgen_sel_electron::EtaTrackMc, + hf_mcgen_sel_electron::PhiTrackMc, + hf_mcgen_sel_electron::PtTrackMc, + hf_mcgen_sel_electron::IsNonHfeMc); +} // namespace o2::aod + +#endif // PWGHF_HFL_DATAMODEL_ELECTRONSELECTIONTABLE_H_ diff --git a/PWGLF/TableProducer/converters/CMakeLists.txt b/PWGHF/HFL/TableProducer/CMakeLists.txt similarity index 70% rename from PWGLF/TableProducer/converters/CMakeLists.txt rename to PWGHF/HFL/TableProducer/CMakeLists.txt index 764ec4c26e9..69f571377c8 100644 --- a/PWGLF/TableProducer/converters/CMakeLists.txt +++ b/PWGHF/HFL/TableProducer/CMakeLists.txt @@ -9,12 +9,12 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. -o2physics_add_dpl_workflow(stradautracksconverter - SOURCES stradautracksconverter.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore +o2physics_add_dpl_workflow(electron-selection-with-tpc-emcal + SOURCES electronSelectionWithTpcEmcal.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore KFParticle::KFParticle COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(strarawcentsconverter - SOURCES strarawcentsconverter.cxx +o2physics_add_dpl_workflow(tree-creator-electron-d-c-a + SOURCES treeCreatorElectronDCA.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) \ No newline at end of file + COMPONENT_NAME Analysis) diff --git a/PWGHF/HFL/TableProducer/electronSelectionWithTpcEmcal.cxx b/PWGHF/HFL/TableProducer/electronSelectionWithTpcEmcal.cxx new file mode 100644 index 00000000000..971200a7105 --- /dev/null +++ b/PWGHF/HFL/TableProducer/electronSelectionWithTpcEmcal.cxx @@ -0,0 +1,612 @@ +// 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 electronSelectionWithTpcEmcal.cxx +/// \brief Task used to electron selection with tpc and emcal. +/// \author Rashi Gupta , IIT Indore +/// \author Ravindra Singh , IIT Indore + +#include "THnSparse.h" +#include "TPDGCode.h" + +#include "DataFormatsEMCAL/AnalysisCluster.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/PID/TPCPIDResponse.h" +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Tools/KFparticle/KFUtilities.h" + +#include "PWGJE/DataModel/EMCALClusters.h" + +#include "PWGHF/HFL/DataModel/ElectronSelectionTable.h" + +using namespace o2; +using namespace o2::constants::physics; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +const int kEta = 221; + +struct HfElectronSelectionWithTpcEmcal { + + Produces electronSel; + Produces hfElectronSelection; + Produces hfGenElectronSel; + // Configurables + // EMCal Cluster information + KFParticle kfNonHfe; + Configurable fillEmcClusterInfo{"fillEmcClusterInfo", true, "Fill histograms with EMCal cluster info before and after track match"}; + Configurable fillTrackInfo{"fillTrackInfo", true, "Fill histograms with Track Information info before track match"}; + + // Event Selection + Configurable zPvPosMax{"zPvPosMax", 10., "Maximum z of the primary vertex (cm)"}; + Configurable isRun3{"isRun3", true, "Data is from Run3 or Run2"}; + + // Track selection + Configurable dcaXYTrackMax{"dcaXYTrackMax", 0.5f, "DCA XY cut"}; + Configurable dcaZTrackMax{"dcaZTrackMax", 1.0f, "DCA Z cut"}; + Configurable etaTrackMax{"etaTrackMax", 0.6f, "Eta range for electron tracks"}; + Configurable etaTrackMin{"etaTrackMin", -0.6f, "Eta range for electron tracks"}; + Configurable ptTrackMin{"ptTrackMin", 3.0f, "Transverse MOmentum range for electron tracks"}; + + // Associated electron selection cut + Configurable etaAssoTrackMax{"etaAssoTrackMax", 0.9f, "Eta range for Associatred electron tracks"}; + Configurable etaAssoTrackMin{"etaAssoTrackMin", -0.9f, "Eta range for Associatred electron tracks"}; + Configurable ptAssoTrackMin{"ptAssoTrackMin", 0.2f, "Transverse MOmentum range for Associatred electron tracks"}; + Configurable tpcNsigmaAssoElectronMin{"tpcNsigmaAssoElectronMin", -3.0f, "min Associated Electron TPCnsigma"}; + Configurable tpcNsigmaAssoElectronMax{"tpcNsigmaAssoElectronMax", 3.0f, "max Associated Electron TPCnsigma"}; + Configurable invariantMass{"invariantMass", 0.14f, "max Invariant Mass for Photonic electron"}; + Configurable chiSquareMax{"chiSquareMax", 3.0f, "chiSquare on the reconstructed parent particle"}; + + // EMcal and Dcal selection cut + Configurable etaTrackDCalNegativeMax{"etaTrackDCalNegativeMax", -0.22f, "Eta range for electron Dcal tracks"}; + Configurable etaTrackDCalNegativeMin{"etaTrackDCalNegativeMin", -0.6f, "Eta range for electron tracks"}; + Configurable etaTrackDCalPositiveMax{"etaTrackDCalPositiveMax", 0.6f, "Eta range for electron Dcal tracks"}; + Configurable etaTrackDCalPositiveMin{"etaTrackDCalPositiveMin", 0.22f, "Eta range for electron tracks"}; + Configurable phiTrackDCalMax{"phiTrackDCalMax", 3.3621f, "phi range for electron tracks associated Dcal"}; + Configurable phiTrackDCalMin{"phiTrackDCalMin", 1.3955f, "phi range for electron tracks associated Dcal"}; + Configurable phiTrackEMCalMax{"phiTrackEMCalMax", 5.708f, "phi range for electron tracks associated Emcal"}; + Configurable phiTrackEMCalMin{"phiTrackEMCalMin", 4.5355f, "phi range for electron tracks associated Emcal"}; + + // Track and EMCal Cluster matching cut + Configurable deltaEtaMatchMin{"deltaEtaMatchMin", -0.013f, "Min Eta distance of EMCAL cluster to its closest track"}; + Configurable deltaEtaMatchMax{"deltaEtaMatchMax", 0.0171f, "Max Eta distance of EMCAL cluster to its closest track"}; + Configurable deltaPhiMatchMin{"deltaPhiMatchMin", -0.022f, "Min Phi distance of EMCAL cluster to its closest track"}; + Configurable deltaPhiMatchMax{"deltaPhiMatchMax", 0.028f, "Max Phi distance of EMCAL cluster to its closest track"}; + Configurable timeEmcClusterMax{"timeEmcClusterMax", 50.f, "EMCal Cluster time"}; + + // Inclusive electron selection cut + Configurable eopElectronMin{"eopElectronMin", 0.8f, "Minimum E/p for electron tracks"}; + Configurable eopElectronMax{"eopElectronMax", 1.2f, "Maximum E/p for electron tracks"}; + Configurable m02EmcClusterElectronMax{"m02EmcClusterElectronMax", 0.9f, "max Electron EMCal Cluster M02"}; + Configurable m02EmcClusterElectronMin{"m02EmcClusterElectronMin", 0.02f, "min Electron EMCal Cluster M02"}; + Configurable m20EmcClusterElectronMax{"m20EmcClusterElectronMax", 1000.f, "max Electron EMCal Cluster M20"}; + Configurable m20EmcClusterElectronMin{"m20EmcClusterElectronMin", 0.0f, "min Electron EMCal Cluster M20"}; + Configurable tpcNsigmaElectronMin{"tpcNsigmaElectronMin", -0.5f, "min Electron TPCnsigma"}; + Configurable tpcNsigmaElectronMax{"tpcNsigmaElectronMax", 3.0f, "max Electron TPCnsigma"}; + + using TableCollisions = o2::soa::Filtered>; + using TableCollision = TableCollisions::iterator; + using TableTracks = o2::soa::Join; + + using McTableCollisions = o2::soa::Filtered>; + using McTableCollision = McTableCollisions::iterator; + using McGenTableCollisions = soa::Join; + using McGenTableCollision = McGenTableCollisions::iterator; + using McTableTracks = soa::Join; + using McTableEmcals = soa::Join; + + Filter collisionFilter = nabs(aod::collision::posZ) < zPvPosMax && aod::collision::numContrib > static_cast(1); + PresliceUnsorted perClusterMatchedTracks = o2::aod::emcalmatchedtrack::trackId; + + // configurable axis + + ConfigurableAxis binsPosZ{"binsPosZ", {100, -10., 10.}, "primary vertex z coordinate"}; + ConfigurableAxis binsEta{"binsEta", {100, -2.0, 2.}, "#it{#eta}"}; + ConfigurableAxis binsPhi{"binsPhi", {32, 0.0, o2::constants::math::TwoPI}, "#it{#varphi}"}; + ConfigurableAxis binsPt{"binsPt", {50, 0.0, 50}, "#it{p_{T}}(GeV/#it{c})"}; + ConfigurableAxis binsdEdx{"binsdEdx", {160, 0., 160.}, "dE/dX"}; + ConfigurableAxis binsnSigma{"binsnSigma", {30, -15., 15.}, "#it{#sigma_{TPC}}"}; + ConfigurableAxis binsM02{"binsM02", {50, 0., 2.0}, "M02; entries"}; + ConfigurableAxis binsM20{"binsM20", {50, 0., 2.0}, "M20; entries"}; + ConfigurableAxis binsEoP{"binsEoP", {30, 0., 3.}, "e/p"}; + ConfigurableAxis binsEmcEnergy{"binsEmcEnergy", {50, 0., 50.}, "Cluster Energy (GeV/#it{c}^{2})"}; + ConfigurableAxis binsEmcClsNCells{"binsEmcClsNCells", {50, 0., 50.}, "nCells"}; + ConfigurableAxis binsEmcClsTime{"binsEmcClsTime", {1800, -900.0, 900.}, "Cluster Time"}; + ConfigurableAxis binsPassEMcal{"binsPassEMcal", {3, 0.0, 3.}, "Pass EMcal"}; + + ConfigurableAxis binsDeltaEta{"binsDeltaEta", {20, -0.2, 0.2}, "Track Cluser Match #Delta #eta"}; + ConfigurableAxis binsDeltaPhi{"binsDeltaPhi", {20, -0.2, 0.2}, "Track Cluser Match #Delta #varphi"}; + ConfigurableAxis binsMass{"binsMass", {100, 0.0, 2.0}, "Mass (GeV/#it{c}^{2}); entries"}; + + HistogramConfigSpec hEmcClusterEnergySpec{HistType::kTH1F, {{binsEmcEnergy}}}; + HistogramConfigSpec hEmcClusterEtaPhiSpec{HistType::kTH2F, {{binsEta}, {binsPhi}}}; + HistogramConfigSpec hEmcClusterEnergyCellSpec{HistType::kTH2F, {{binsEmcEnergy}, {binsEmcClsNCells}}}; + HistogramConfigSpec hEmcClusterEnergyTimeSpec{HistType::kTH2F, {{binsEmcEnergy}, {binsEmcClsTime}}}; + + HistogramConfigSpec hDeltaPhiDeltaEtaEmcClusterTrackTime{HistType::kTH3F, {{binsDeltaEta}, {binsDeltaPhi}, {binsEmcClsTime}}}; + HistogramConfigSpec hAfterMatchEoPSigamSpec{HistType::kTHnSparseD, {{binsEoP}, {binsPt}, {binsnSigma}, {binsM02}, {binsM20}}}; + + HistogramConfigSpec hTrackEnergyLossSpec{HistType::kTH3F, {{binsdEdx}, {binsPt}, {binsPassEMcal}}}; + + HistogramConfigSpec hTracknSigmaSpec{HistType::kTH3F, {{binsnSigma}, {binsPt}, {binsPassEMcal}}}; + + HistogramRegistry registry{ + "registry", + {{"hNevents", "No of events", {HistType::kTH1F, {{3, 1, 4}}}}, + {"hZvertex", "z vertex", {HistType::kTH1F, {{binsPosZ}}}}, + {"hLikeMass", "Like mass", {HistType::kTH1F, {{binsMass}}}}, + {"hUnLikeMass", "unLike mass", {HistType::kTH1F, {{binsMass}}}}, + {"hLikeSignPt", "Like sign Momentum ", {HistType::kTH1F, {{binsPt}}}}, + {"hUnLikeSignPt", "UnLike sign Momentum", {HistType::kTH1F, {{binsPt}}}}, + {"hMcgenInElectron", "Mc Gen Inclusive Electron", {HistType::kTH1F, {{binsPt}}}}, + {"hMcgenAllNonHfeElectron", "Mc Gen All NonHf Electron", {HistType::kTH1F, {{binsPt}}}}, + {"hMcgenNonHfeElectron", "Mc Gen NonHf Electron with mother", {HistType::kTH1F, {{binsPt}}}}, + {"hPi0eEmbTrkPt", "Mc Gen Pi0 mother NonHf Electron", {HistType::kTH1F, {{binsPt}}}}, + + {"hEtaeEmbTrkPt", "Mc Gen Eta mother NonHf Electron", {HistType::kTH1F, {{binsPt}}}}, + {"hEmcClusterM02", "m02", {HistType::kTH1F, {{binsM02}}}}, + {"hEmcClusterM20", "m20", {HistType::kTH1F, {{binsM20}}}}, + {"hTrackEtaPhi", "TPC EtaPhi Info; #eta;#varphi;passEMcal;", {HistType::kTH3F, {{binsEta}, {binsPhi}, {binsPassEMcal}}}}, + {"hTrackEnergyLossVsP", " TPC Energy loss info vs P; dE/dx;#it{p} (GeV#it{/c});passEMcal;", hTrackEnergyLossSpec}, + {"hTrackEnergyLossVsPt", " TPC Energy loss info vs Pt; dE/dx;#it{p}_{T} (GeV#it{/c});passEMcal;", hTrackEnergyLossSpec}, + {"hTracknSigmaVsP", " TPC nSigma info vs P; n#sigma;#it{p} (GeV#it{/c});passEMcal;", hTracknSigmaSpec}, + {"hTracknSigmaVsPt", " TPC nSigma info vs Pt; n#sigma;#it{p}_{T} (GeV#it{/c});passEMcal;", hTracknSigmaSpec}, + {"hEmcClusterEnergy", "EMCal Cluster Info before match Energy; Energy (GeV)", hEmcClusterEnergySpec}, + {"hEmcClusterEtaPhi", "EMCal Cluster Info before match Eta and Phi; #eta;#varphi;", hEmcClusterEtaPhiSpec}, + {"hEmcClusterEnergyCell", "EMCal Cluster Info before match Energy vs nCells; Energy (GeV);ncell;", hEmcClusterEnergyCellSpec}, + {"hEmcClusterEnergyTime", "EMCal Cluster Info before match Energy vs time; Energy (GeV); sec;", hEmcClusterEnergyTimeSpec}, + {"hEmcClusterAfterMatchEnergy", "EMCal Cluster Info After match Energy; Energy (GeV)", hEmcClusterEnergySpec}, + {"hEmcClusterAfterMatchEtaPhi", "EMCal Cluster Info After match Eta and Phi; #eta;#varphi;", hEmcClusterEtaPhiSpec}, + {"hEmcClusterAfterMatchEnergyCells", "EMCal Cluster Info After match Energy vs nCells; Energy (GeV);ncell;", hEmcClusterEnergyCellSpec}, + {"hEmcClusterAfterMatchEnergyTime", "EMCal Cluster Info After match Energy vs time; Energy (GeV); sec;", hEmcClusterEnergyTimeSpec}, + + {"hAfterMatchSigmaVsEoP", "PID Info after match EoP vs Sigma ; E/P;#it{p}_{T} (GeV#it{/c});n#sigma; m02; m20;", hAfterMatchEoPSigamSpec}, + {"hAfterMatchEoPVsP", "PID Info after match EoP vs P; E/P;#it{p} (GeV#it{/c});", {HistType::kTH2F, {{binsEoP}, {binsPt}}}}, + {"hAfterMatchSigmaVsP", "PID Info after match Sigma vs Momentum ; n#sigma; #it{p} (GeV#it{/c}; ", {HistType::kTH2F, {{binsnSigma}, {binsPt}}}}, + {"hAfterMatchEtaPhi", "PID Info after match Eta vs Phi ; #eta; #varphi; ", {HistType::kTH2F, {{binsEta}, {binsPhi}}}}, + {"hAfterMatchEnergyLossVsP", "PID Info after match Energy loss info vs P ; dE/dx;#it{p} (GeV#it{/c});; ", {HistType::kTH2F, {{binsdEdx}, {binsPt}}}}, + {"hAfterMatchEnergyLossVsPt", "PID Info after match Energy loss info vs Pt ;dE/dx;#it{p}_{T} (GeV#it{/c}); ", {HistType::kTH2F, {{binsdEdx}, {binsPt}}}}, + + {"hAfterPIDEtaPhi", "PID Info after PID Cuts Eta vs Phi ; #eta; #varphi; ", {HistType::kTH2F, {{binsEta}, {binsPhi}}}}, + {"hEPRatioAfterPID", "E/P Ratio after PID Cuts apply only trackwodca filter", {HistType::kTH2F, {{binsPt}, {binsEmcEnergy}}}}, + {"hPIDAfterPIDCuts", "PID Info after PID cuts; E/P;#it{p}_{T} (GeV#it{/c});n#sigma;m02; m20;", hAfterMatchEoPSigamSpec}, + {"hEmcClsTrkEtaPhiDiffTime", "EmcClsTrkEtaPhiDiffTime;#Delta#eta;#Delta#varphi;Sec;", hDeltaPhiDeltaEtaEmcClusterTrackTime}}}; + + void init(o2::framework::InitContext&) + { + registry.get(HIST("hAfterMatchSigmaVsEoP"))->Sumw2(); + registry.get(HIST("hPIDAfterPIDCuts"))->Sumw2(); + } + // Track Selection Cut + template + bool selTracks(T const& track) + { + if (!track.isGlobalTrackWoDCA()) { + return false; + } + if (std::abs(track.dcaXY()) > dcaXYTrackMax || std::abs(track.dcaZ()) > dcaZTrackMax) { + return false; + } + if (track.eta() < etaTrackMin || track.eta() > etaTrackMax) { + return false; + } + if ((track.phi() < phiTrackEMCalMin || track.phi() > phiTrackEMCalMax) && (track.phi() < phiTrackDCalMin || track.phi() > phiTrackDCalMax)) { + return false; + } + if (track.pt() < ptTrackMin) { + return false; + } + return true; + } + // Associated electron Selection Cut + template + bool selAssoTracks(T const& track) + { + if (!track.isGlobalTrackWoDCA()) { + return false; + } + if (std::abs(track.dcaXY()) > dcaXYTrackMax || std::abs(track.dcaZ()) > dcaZTrackMax) { + return false; + } + if (track.eta() < etaAssoTrackMin || track.eta() > etaAssoTrackMax) { + return false; + } + + if (track.pt() < ptAssoTrackMin) { + return false; + } + if (track.tpcNSigmaEl() < tpcNsigmaAssoElectronMin || track.tpcNSigmaEl() > tpcNsigmaAssoElectronMax) { + return false; + } + + return true; + } + + // mc gen particle selection cut + template + bool mcGensel(T const& track) + { + if (track.eta() < etaTrackMin || track.eta() > etaTrackMax) { + return false; + } + if ((track.phi() < phiTrackEMCalMin || track.phi() > phiTrackEMCalMax) && (track.phi() < phiTrackDCalMin || track.phi() > phiTrackDCalMax)) { + return false; + } + if (track.pt() < ptTrackMin) { + return false; + } + return true; + } + // nonHfe Identification + + template + void nonHfe(ElectronType const& electron, TracksType const& tracks, bool isEMcal) + { + int isLSElectronFound = 0; + int isULSElectronFound = 0; + bool isLSElectron = false; + bool isULSElectron = false; + float invMassElectron = 0.; + float massLike = 0; + float massUnLike = 0; + + for (const auto& pTrack : tracks) { + if (pTrack.globalIndex() == electron.globalIndex()) { + continue; + } + // Apply partner electron selection + + if (!selAssoTracks(pTrack)) { + continue; + } + if (electron.pt() <= pTrack.pt()) { + continue; + } + int pdgE1 = kElectron; + int pdgE2 = kElectron; + if (electron.sign() > 0) { + pdgE1 = kPositron; + } + + if (pTrack.sign() > 0) { + pdgE2 = kPositron; + } + + KFPTrack kfpTrack = createKFPTrackFromTrack(electron); + KFPTrack kfpAssociatedTrack = createKFPTrackFromTrack(pTrack); + KFParticle kfTrack(kfpTrack, pdgE1); + KFParticle kfAssociatedTrack(kfpAssociatedTrack, pdgE2); + const KFParticle* electronPairs[2] = {&kfTrack, &kfAssociatedTrack}; + kfNonHfe.SetConstructMethod(2); + kfNonHfe.Construct(electronPairs, 2); + + int ndf = kfNonHfe.GetNDF(); + double chi2recg = kfNonHfe.GetChi2() / ndf; + if (ndf < 1.0) { + continue; + } + + if (std::sqrt(std::abs(chi2recg)) > chiSquareMax) { + continue; + } + + invMassElectron = RecoDecay::m(std::array{pTrack.pVector(), electron.pVector()}, std::array{MassElectron, MassElectron}); + + // for like charge + if (pTrack.sign() == electron.sign()) { + massLike = invMassElectron; + isLSElectron = true; + if (isEMcal) { + registry.fill(HIST("hLikeMass"), massLike); + } + } + // for unlike charge + if (pTrack.sign() != electron.sign()) { + massUnLike = invMassElectron; + isULSElectron = true; + if (isEMcal) { + registry.fill(HIST("hUnLikeMass"), massUnLike); + } + } + + // for like charge + if (isLSElectron && (invMassElectron <= invariantMass)) { + massLike = invMassElectron; + ++isLSElectronFound; + if (isEMcal) { + registry.fill(HIST("hLikeSignPt"), electron.pt()); + } + } + // for unlike charge + if (isULSElectron && (invMassElectron <= invariantMass)) { + massUnLike = invMassElectron; + ++isULSElectronFound; + if (isEMcal) { + registry.fill(HIST("hUnLikeSignPt"), electron.pt()); + } + } + } + // Pass multiplicities and other required parameters for this electron + hfElectronSelection(electron.collisionId(), electron.globalIndex(), electron.eta(), electron.phi(), electron.pt(), electron.tpcNSigmaEl(), electron.tofNSigmaEl(), isLSElectronFound, isULSElectronFound, isEMcal); + } + // Electron Identification + template + void fillElectronTrack(CollisionType const& collision, TracksType const& tracks, EmcClusterType const& emcClusters, MatchType const& matchedTracks, ParticleType const& /*particlemc*/) + { + if (!(isRun3 ? collision.sel8() : (collision.sel7() && collision.alias_bit(kINT7)))) + return; + + registry.fill(HIST("hNevents"), 1); + registry.fill(HIST("hZvertex"), collision.posZ()); + + ///////////////////////////////// + // EMCal cluster info before match /// + /////////////////////////////// + if (fillEmcClusterInfo) { + for (const auto& emcClusterBefore : emcClusters) { + registry.fill(HIST("hEmcClusterEnergy"), emcClusterBefore.energy()); // track etaphi infor after filter bit + registry.fill(HIST("hEmcClusterEtaPhi"), emcClusterBefore.eta(), emcClusterBefore.phi()); // track etaphi infor after filter bit + registry.fill(HIST("hEmcClusterEnergyCell"), emcClusterBefore.energy(), emcClusterBefore.nCells()); // track etaphi infor after filter bit + registry.fill(HIST("hEmcClusterEnergyTime"), emcClusterBefore.energy(), emcClusterBefore.time()); // track etaphi infor after filter bit + registry.fill(HIST("hEmcClusterM02"), emcClusterBefore.m02()); + registry.fill(HIST("hEmcClusterM20"), emcClusterBefore.m20()); + } + } + int passEMCal; + float phiTrack = -999; + float etaTrack = -999; + float pTrack = -999; + float ptTrack = -999; + float dcaxyTrack = -999; + float dcazTrack = -999; + float tpcNsigmaTrack = -999; + + for (const auto& track : tracks) { + phiTrack = track.phi(); + etaTrack = track.eta(); + pTrack = track.p(); + ptTrack = track.pt(); + dcaxyTrack = track.dcaXY(); + dcazTrack = track.dcaZ(); + tpcNsigmaTrack = track.tpcNSigmaEl(); + // Apply Track Selection + if (!selTracks(track)) { + continue; + } + passEMCal = 0; + + if ((phiTrack > phiTrackEMCalMin && phiTrack < phiTrackEMCalMax) && (etaTrack > etaTrackMin && etaTrack < etaTrackMax)) + passEMCal = 1; // EMcal acceptance passed + if ((phiTrack > phiTrackDCalMin && phiTrack < phiTrackDCalMax) && ((etaTrack > etaTrackDCalPositiveMin && etaTrack < etaTrackDCalPositiveMax) || (etaTrack > etaTrackDCalNegativeMin && etaTrack < etaTrackDCalNegativeMax))) + passEMCal = 2; // Dcal acceptance passed + if (fillTrackInfo) { + registry.fill(HIST("hTrackEtaPhi"), etaTrack, phiTrack, passEMCal); // track etaphi infor after filter bit + registry.fill(HIST("hTrackEnergyLossVsP"), track.tpcSignal(), pTrack, passEMCal); // track etaphi infor after filter bit + registry.fill(HIST("hTrackEnergyLossVsPt"), track.tpcSignal(), ptTrack, passEMCal); // track etaphi infor after filter bit + registry.fill(HIST("hTracknSigmaVsP"), tpcNsigmaTrack, pTrack, passEMCal); // track etaphi infor after filter bit + registry.fill(HIST("hTracknSigmaVsPt"), tpcNsigmaTrack, ptTrack, passEMCal); // track etaphi infor after filter bit + } + auto tracksofcluster = matchedTracks.sliceBy(perClusterMatchedTracks, track.globalIndex()); + float phiMatchTrack = -999; + float etaMatchTrack = -999; + float pMatchTrack = -999; + float ptMatchTrack = -999; + float tpcNsigmaMatchTrack = -999; + float phiMatchEmcCluster = -999; + float etaMatchEmcCluster = -999; + float eMatchEmcCluster = -999; + float m02MatchEmcCluster = -999; + float m20MatchEmcCluster = -999; + float timeEmcCluster = -999; + float cellEmcCluster = -999; + float deltaPhiMatch = -999.; + float deltaEtaMatch = -999.; + float eop = -999; + bool isEMcal = false; + + float trackRapidity = track.rapidity(MassElectron); + + for (const auto& ematchTrack : tracksofcluster) { + + auto matchTrack = ematchTrack.template track_as(); + + auto emcCluster = ematchTrack.template emcalcluster_as(); + + phiMatchTrack = matchTrack.phi(); + etaMatchTrack = matchTrack.eta(); + pMatchTrack = matchTrack.p(); + ptMatchTrack = matchTrack.pt(); + tpcNsigmaMatchTrack = matchTrack.tpcNSigmaEl(); + phiMatchEmcCluster = emcCluster.phi(); + etaMatchEmcCluster = emcCluster.eta(); + eMatchEmcCluster = emcCluster.energy(); + m02MatchEmcCluster = emcCluster.m02(); + m20MatchEmcCluster = emcCluster.m20(); + timeEmcCluster = emcCluster.time(); + cellEmcCluster = emcCluster.nCells(); + + deltaPhiMatch = matchTrack.trackPhiEmcal() - phiMatchEmcCluster; + deltaEtaMatch = matchTrack.trackEtaEmcal() - etaMatchEmcCluster; + + // Track and EMCal cluster Matching + if (std::abs(timeEmcCluster) > timeEmcClusterMax) { + continue; + } + if (deltaPhiMatch < deltaPhiMatchMin || deltaPhiMatch > deltaPhiMatchMax || deltaEtaMatch < deltaEtaMatchMin || deltaEtaMatch > deltaEtaMatchMax) { + continue; + } + + registry.fill(HIST("hEmcClsTrkEtaPhiDiffTime"), deltaEtaMatch, deltaPhiMatch, timeEmcCluster); + + if (fillEmcClusterInfo) { + registry.fill(HIST("hEmcClusterAfterMatchEnergy"), emcCluster.energy()); // track etaphi infor after filter bit + registry.fill(HIST("hEmcClusterAfterMatchEtaPhi"), emcCluster.eta(), emcCluster.phi()); // track etaphi infor after filter bit + registry.fill(HIST("hEmcClusterAfterMatchEnergyCells"), emcCluster.energy(), emcCluster.nCells()); // track etaphi infor after filter bit + registry.fill(HIST("hEmcClusterAfterMatchEnergyTime"), emcCluster.energy(), emcCluster.time()); // track etaphi infor after filter bit + } + + eop = eMatchEmcCluster / pMatchTrack; + + registry.fill(HIST("hAfterMatchSigmaVsEoP"), eop, ptMatchTrack, tpcNsigmaMatchTrack, m02MatchEmcCluster, m20MatchEmcCluster); + registry.fill(HIST("hAfterMatchEoPVsP"), eop, pMatchTrack); + registry.fill(HIST("hAfterMatchSigmaVsP"), tpcNsigmaMatchTrack, pMatchTrack); + registry.fill(HIST("hAfterMatchEtaPhi"), etaMatchTrack, phiMatchTrack); + registry.fill(HIST("hAfterMatchEnergyLossVsP"), matchTrack.tpcSignal(), pMatchTrack); + registry.fill(HIST("hAfterMatchEnergyLossVsPt"), matchTrack.tpcSignal(), ptMatchTrack); + // Apply Electron Identification cuts + + if ((tpcNsigmaMatchTrack < tpcNsigmaElectronMin || tpcNsigmaMatchTrack > tpcNsigmaElectronMax) || (m02MatchEmcCluster < m02EmcClusterElectronMin || m02MatchEmcCluster > m02EmcClusterElectronMax) || (m20MatchEmcCluster < m20EmcClusterElectronMin || m20MatchEmcCluster > m20EmcClusterElectronMax)) { + continue; + } + + registry.fill(HIST("hPIDAfterPIDCuts"), eop, ptMatchTrack, tpcNsigmaMatchTrack, m02MatchEmcCluster, m20MatchEmcCluster); + registry.fill(HIST("hEPRatioAfterPID"), pMatchTrack, eMatchEmcCluster); + registry.fill(HIST("hAfterPIDEtaPhi"), etaMatchTrack, phiMatchTrack); + if (eop < eopElectronMin || eop > eopElectronMax) { + continue; + } + + ///////////////// NonHf electron Selection with Emcal //////////////////////// + + nonHfe(matchTrack, tracks, true); + + electronSel(track.collisionId(), matchTrack.globalIndex(), etaMatchTrack, phiMatchTrack, ptMatchTrack, pMatchTrack, trackRapidity, matchTrack.dcaXY(), matchTrack.dcaZ(), matchTrack.tpcNSigmaEl(), matchTrack.tofNSigmaEl(), + eMatchEmcCluster, etaMatchEmcCluster, phiMatchEmcCluster, m02MatchEmcCluster, m20MatchEmcCluster, cellEmcCluster, timeEmcCluster, deltaEtaMatch, deltaPhiMatch, isEMcal); + } + /// Electron information without Emcal and use TPC and TOF + if (isEMcal) { + continue; + } + nonHfe(track, tracks, false); + ///////////////// NonHf electron Selection without Emcal //////////////////////// + electronSel(track.collisionId(), track.globalIndex(), etaTrack, phiTrack, ptTrack, pTrack, trackRapidity, dcaxyTrack, dcazTrack, track.tpcNSigmaEl(), track.tofNSigmaEl(), + eMatchEmcCluster, etaMatchEmcCluster, phiMatchEmcCluster, m02MatchEmcCluster, m20MatchEmcCluster, cellEmcCluster, timeEmcCluster, deltaEtaMatch, deltaPhiMatch, isEMcal); + } + } + + /// Electron selection - for real data and data-like analysis + void processData(TableCollision const& collision, + TableTracks const& tracks, + aod::EMCALClusters const& emcClusters, + o2::aod::EMCALMatchedTracks const& matchedTracks) + { + fillElectronTrack(collision, tracks, emcClusters, matchedTracks, 0); + } + PROCESS_SWITCH(HfElectronSelectionWithTpcEmcal, processData, "process Data info only", true); + /// Electron selection - for MC reco-level analysis + void processMcRec(McTableCollision const& mcCollision, + McTableTracks const& mcTracks, + McTableEmcals const& mcEmcClusters, + o2::aod::EMCALMatchedTracks const& matchedTracks, + aod::McParticles const& mcParticles) + { + fillElectronTrack(mcCollision, mcTracks, mcEmcClusters, matchedTracks, mcParticles); + } + PROCESS_SWITCH(HfElectronSelectionWithTpcEmcal, processMcRec, "Process MC Reco mode", false); + + void processMcGen(McGenTableCollision const& mcCollision, aod::McParticles const& mcParticles) + { + + ///// electron identification + bool isNonHfe = false; + for (const auto& particleMc : mcParticles) { + + if (!particleMc.isPhysicalPrimary()) + continue; + if (!mcGensel(particleMc)) { + continue; + } + if (std::abs(particleMc.pdgCode()) == kElectron) { + + registry.fill(HIST("hMcgenInElectron"), particleMc.pt()); + bool isEmbEta = false; + bool isEmbPi0 = false; + + if (particleMc.has_mothers()) { + // Check first mother + auto const& mother = particleMc.mothers_first_as(); + + if (std::abs(mother.pdgCode()) == kEta || std::abs(mother.pdgCode()) == kPi0 || std::abs(mother.pdgCode()) == kGamma) { + registry.fill(HIST("hMcgenAllNonHfeElectron"), particleMc.pt()); + if (mother.has_mothers()) { + auto const& gmother = mother.mothers_first_as(); + if (gmother.has_mothers()) { + auto const& ggmother = gmother.mothers_first_as(); + + // cases to consider: eta->e, eta->pi0->e, eta->gamma->e, eta->pi0->gamma->e, pi0->e, pi0->gamma->e + + //================= eta->e ====================================== + if (std::abs(mother.pdgCode()) == kEta) { + isEmbEta = true; + } + //================= eta->pi0->e ====================================== + + if (std::abs(mother.pdgCode()) == kPi0) { + isEmbPi0 = true; // pi0 -> e + + if (std::abs(gmother.pdgCode()) == kEta) { + isEmbEta = true; // eta->pi0-> e + } + } + + /// ==================================== eta->gamma->e and eta->pi0->gamma->e============ + if (std::abs(mother.pdgCode()) == kGamma) { + if (std::abs(gmother.pdgCode()) == kEta) { + isEmbEta = true; // eta->gamma-> e + } + + if (std::abs(gmother.pdgCode()) == kPi0) { + isEmbPi0 = true; // pi0-> gamma-> e + + if (std::abs(ggmother.pdgCode()) == kEta) { + + isEmbEta = true; // eta->pi0->gamma-> e + } + } + } + } + } + } + } + if (isEmbPi0 || isEmbEta) { + registry.fill(HIST("hMcgenNonHfeElectron"), particleMc.pt()); + isNonHfe = true; + if (isEmbPi0) { + + registry.fill(HIST("hPi0eEmbTrkPt"), particleMc.pt()); + } + if (isEmbEta) { + registry.fill(HIST("hEtaeEmbTrkPt"), particleMc.pt()); + } + } + hfGenElectronSel(mcCollision.globalIndex(), particleMc.globalIndex(), particleMc.eta(), particleMc.phi(), particleMc.pt(), isNonHfe); + } + } + } + + PROCESS_SWITCH(HfElectronSelectionWithTpcEmcal, processMcGen, "Process MC Gen mode", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/HFL/TableProducer/treeCreatorElectronDCA.cxx b/PWGHF/HFL/TableProducer/treeCreatorElectronDCA.cxx new file mode 100644 index 00000000000..b8faca73bf7 --- /dev/null +++ b/PWGHF/HFL/TableProducer/treeCreatorElectronDCA.cxx @@ -0,0 +1,142 @@ +// 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 treeCreatorElectronDCA.cxx +/// \brief Basic electron DCA analysis task +/// +/// \author Martin Voelkl , University of Birmingham + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include "Common/DataModel/Centrality.h" + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace o2::aod +{ +namespace hf_ele_mc_red +{ +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(SourcePdg, sourcePdg, int); +DECLARE_SOA_COLUMN(DcaXY, dcaXY, float); +DECLARE_SOA_COLUMN(ProductionRadius, productionRadius, float); + +} // namespace hf_ele_mc_red +DECLARE_SOA_TABLE(HFeleMCRedTable, "AOD", "HFELERED", + hf_ele_mc_red::Eta, hf_ele_mc_red::Phi, hf_ele_mc_red::Pt, hf_ele_mc_red::SourcePdg, hf_ele_mc_red::DcaXY, hf_ele_mc_red::ProductionRadius); +} // namespace o2::aod + +/// Electron DCA analysis task +struct HfTreeCreatorElectronDCA { + Produces hfEleTable; + + Configurable etaRange{"etaRange", 0.5, "pseudorapidity range"}; + Configurable pTMin{"pTMin", 0.5, "min pT"}; + + HfHelper hfHelper; + Service pdg; + + using TracksWExt = soa::Join; + using TracksWExtMc = soa::Join; + + HistogramRegistry registry{ + "registry", + {{"hZVertex", "z Vertex;z_{vtx};counts", {HistType::kTH1F, {{100, -20., 20.}}}}, + {"hpTTracks", "pT of tracks; p_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 10.}}}}, + {"hpTElectrons", "pT of electrons; p_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 10.}}}}}}; + + void init(InitContext&) + { + } + + void processData(aod::Collisions::iterator const& collision) + { + registry.get(HIST("hZVertex"))->Fill(collision.posZ()); + } + PROCESS_SWITCH(HfTreeCreatorElectronDCA, processData, "Process Data", true); + + void processMc(aod::Collisions::iterator const& collision, + TracksWExtMc const& tracks, + aod::McParticles const&) + { + registry.get(HIST("hZVertex"))->Fill(collision.posZ()); + int pdgCode = 0, absPDGCode = 0, sourcePDG = 0; + for (const auto& track : tracks) { + if (!track.trackCutFlagFb3()) + continue; + registry.get(HIST("hpTTracks"))->Fill(track.pt()); + if (track.pt() < pTMin) + continue; + if (std::abs(track.eta()) > etaRange) + continue; + if (track.mcParticleId() < 1) + continue; + auto mcTrack = track.mcParticle(); + if (std::abs(mcTrack.pdgCode()) == kElectron) { + bool isConversion = false; + bool isBeauty = false; + bool isCharm = false; + double productionRadius = RecoDecay::sqrtSumOfSquares(mcTrack.vx(), mcTrack.vy()); + registry.get(HIST("hpTElectrons"))->Fill(track.pt()); + auto motherTracks = mcTrack.mothers_as(); + int numberOfMothers = motherTracks.size(); + // Categorise the electron sources + int firstMotherPDG = motherTracks[0].pdgCode(); + if (firstMotherPDG == kGamma) + isConversion = true; + while (numberOfMothers == 1) // loop through all generations + { + pdgCode = motherTracks[0].pdgCode(); + absPDGCode = std::abs(pdgCode); + if (static_cast(absPDGCode / 100) == 4 || static_cast(absPDGCode / 1000) == 4) { + isCharm = true; + sourcePDG = pdgCode; + } + if (static_cast(absPDGCode / 100) == 5 || static_cast(absPDGCode / 1000) == 5) { + isBeauty = true; + sourcePDG = pdgCode; // already in order, since beauty would decay to charm + } + auto firstMother = motherTracks[0]; + motherTracks = firstMother.mothers_as(); + numberOfMothers = motherTracks.size(); + } + if (!isBeauty && !isCharm) { + if (isConversion) + sourcePDG = kGamma; + else + sourcePDG = firstMotherPDG; + } + hfEleTable(track.eta(), track.phi(), track.pt(), sourcePDG, track.dcaXY(), productionRadius); + } + } + } + PROCESS_SWITCH(HfTreeCreatorElectronDCA, processMc, "Process MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/HFL/Tasks/CMakeLists.txt b/PWGHF/HFL/Tasks/CMakeLists.txt index 08579ab236e..8a6c9ab4285 100644 --- a/PWGHF/HFL/Tasks/CMakeLists.txt +++ b/PWGHF/HFL/Tasks/CMakeLists.txt @@ -9,6 +9,11 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +o2physics_add_dpl_workflow(task-electron-weak-boson + SOURCES taskElectronWeakBoson.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(task-muon-charm-beauty-separation SOURCES taskMuonCharmBeautySeparation.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -19,12 +24,17 @@ o2physics_add_dpl_workflow(task-single-muon PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(task-single-muon-source - SOURCES taskSingleMuonSource.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(task-single-muon-reader SOURCES taskSingleMuonReader.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGDQCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(task-single-muon-reader-assoc + SOURCES taskSingleMuonReaderAssoc.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGDQCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(task-single-muon-source + SOURCES taskSingleMuonSource.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGHF/HFL/Tasks/taskElectronWeakBoson.cxx b/PWGHF/HFL/Tasks/taskElectronWeakBoson.cxx new file mode 100644 index 00000000000..ceb92e5e61c --- /dev/null +++ b/PWGHF/HFL/Tasks/taskElectronWeakBoson.cxx @@ -0,0 +1,409 @@ +// 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 taskElectronWeakBoson.cxx +/// \brief task for WeakBoson (W/Z) based on electron in mid-rapidity +/// \author S. Sakai & S. Ito (Univ. of Tsukuba) +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" + +#include "EMCALBase/Geometry.h" +#include "EMCALCalib/BadChannelMap.h" + +#include "DataFormatsEMCAL/Cell.h" +#include "DataFormatsEMCAL/Constants.h" +#include "DataFormatsEMCAL/AnalysisCluster.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/PIDResponse.h" + +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGHF/Core/HfHelper.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct HfTaskElectronWeakBoson { + + // configurable parameters + Configurable nBinsPt{"nBinsPt", 100, "N bins in pt registry"}; + Configurable binPtmax{"binPtmax", 100.0, "maximum pt registry"}; + Configurable nBinsE{"nBinsE", 100, "N bins in E registry"}; + Configurable binEmax{"binEmax", 100.0, "maximum E registry"}; + + Configurable vtxZ{"vtxZ", 10.f, ""}; + + Configurable etaTrLow{"etaTrLow", -0.6f, "minimun track eta"}; + Configurable etaTrUp{"etaTrUp", 0.6f, "maximum track eta"}; + Configurable dcaxyMax{"dcaxyMax", 2.0f, "mximum DCA xy"}; + Configurable chi2ItsMax{"chi2ItsMax", 15.0f, "its chi2 cut"}; + Configurable ptMin{"ptMin", 3.0f, "minimum pT cut"}; + Configurable ptZeeMin{"ptZeeMin", 20.0f, "minimum pT cut for Zee"}; + Configurable chi2TpcMax{"chi2TpcMax", 4.0f, "tpc chi2 cut"}; + Configurable nclItsMin{"nclItsMin", 2.0f, "its # of cluster cut"}; + Configurable nclTpcMin{"nclTpcMin", 100.0f, "tpc # if cluster cut"}; + Configurable nclcrossTpcMin{"nclcrossTpcMin", 100.0f, "tpc # of crossedRows cut"}; + Configurable nsigTpcMinLose{"nsigTpcMinLose", -3.0, "tpc Nsig lose lower cut"}; + Configurable nsigTpcMin{"nsigTpcMin", -1.0, "tpc Nsig lower cut"}; + Configurable nsigTpcMax{"nsigTpcMax", 3.0, "tpc Nsig upper cut"}; + + Configurable phiEmcMin{"phiEmcMin", 1.39, "EMC phi acc min"}; + Configurable phiEmcMax{"phiEmcMax", 3.36, "EMC phi acc max"}; + Configurable clusterDefinition{"clusterDefinition", 10, "cluster definition to be selected, e.g. 10=kV3Default"}; + Configurable timeEmcMin{"timeEmcMin", -25., "Minimum EMCcluster timing"}; + Configurable timeEmcMax{"timeEmcMax", +20., "Maximum EMCcluster timing"}; + Configurable m02Min{"m02Min", 0.1, "Minimum M02"}; + Configurable m02Max{"m02Max", 0.9, "Maximum M02"}; + Configurable rMatchMax{"rMatchMax", 0.05, "cluster - track matching cut"}; + Configurable eopMin{"eopMin", 0.9, "Minimum eop"}; + Configurable eopMax{"eopMax", 1.3, "Maximum eop"}; + + Configurable rIsolation{"rIsolation", 0.3, "cone radius for isolation cut"}; + Configurable energyIsolationMax{"energyIsolationMax", 0.1, "isolation cut on energy"}; + Configurable trackIsolationMax{"trackIsolationMax", 3, "Maximum number of tracks in isolation cone"}; + + struct HfElectronCandidate { + float pt, eta, phi, energy; + int charge; + HfElectronCandidate(float ptr, float e, float ph, float en, int ch) + : pt(ptr), eta(e), phi(ph), energy(en), charge(ch) {} + + int sign() const { return charge; } + }; + std::vector selectedElectronsIso; + std::vector selectedElectronsAss; + + using SelectedClusters = o2::aod::EMCALClusters; + // PbPb + using TrackEle = o2::soa::Join; + + // pp + // using TrackEle = o2::soa::Filtered>; + + // Filter + Filter eventFilter = (o2::aod::evsel::sel8 == true); + Filter posZFilter = (nabs(o2::aod::collision::posZ) < vtxZ); + + Filter etafilter = (aod::track::eta < etaTrUp) && (aod::track::eta > etaTrLow); + Filter dcaxyfilter = (nabs(aod::track::dcaXY) < dcaxyMax); + Filter filterGlobalTr = requireGlobalTrackInFilter(); + + Filter clusterDefinitionSelection = (o2::aod::emcalcluster::definition == clusterDefinition) && (o2::aod::emcalcluster::time >= timeEmcMin) && (o2::aod::emcalcluster::time <= timeEmcMax) && (o2::aod::emcalcluster::m02 > m02Min) && (o2::aod::emcalcluster::m02 < m02Max); + + // Data Handling Objects + Preslice perCluster = o2::aod::emcalclustercell::emcalclusterId; + Preslice perClusterAmb = o2::aod::emcalclustercell::emcalambiguousclusterId; + PresliceUnsorted perClusterMatchedTracks = o2::aod::emcalmatchedtrack::trackId; + + // Histogram registry: an object to hold your registrygrams + HistogramRegistry registry{"registry"}; + + void init(InitContext const&) + { + + // define axes you want to use + const AxisSpec axisZvtx{400, -20, 20, "Zvtx"}; + const AxisSpec axisCounter{1, 0, 1, "events"}; + const AxisSpec axisEta{200, -1.0, 1.0, "#eta"}; + const AxisSpec axisPt{nBinsPt, 0, binPtmax, "p_{T}"}; + const AxisSpec axisNsigma{100, -5, 5, "N#sigma"}; + const AxisSpec axisE{nBinsE, 0, binEmax, "Energy"}; + const AxisSpec axisM02{100, 0, 1, "M02"}; + const AxisSpec axisdPhi{200, -1, 1, "dPhi"}; + const AxisSpec axisdEta{200, -1, 1, "dEta"}; + const AxisSpec axisPhi{350, 0, 7, "Phi"}; + const AxisSpec axisEop{200, 0, 2, "Eop"}; + const AxisSpec axisChi2{500, 0.0, 50.0, "#chi^{2}"}; + const AxisSpec axisCluster{100, 0.0, 200.0, "counts"}; + const AxisSpec axisITSNCls{20, 0.0, 20, "counts"}; + const AxisSpec axisEMCtime{200, -100.0, 100, "EMC time"}; + const AxisSpec axisIsoEnergy{100, 0, 1, "Isolation energy(GeV/C)"}; + const AxisSpec axisIsoTrack{20, -0.5, 19.5, "Isolation Track"}; + const AxisSpec axisInvMassZ{200, 0, 200, "M_{ee} (GeV/c^{2})"}; + const AxisSpec axisInvMassDy{200, 0, 2, "M_{ee} (GeV/c^{2})"}; + + // create registrygrams + registry.add("hZvtx", "Z vertex", kTH1F, {axisZvtx}); + registry.add("hEventCounter", "hEventCounter", kTH1F, {axisCounter}); + registry.add("hITSchi2", "ITS #chi^{2}", kTH1F, {axisChi2}); + registry.add("hTPCchi2", "TPC #chi^{2}", kTH1F, {axisChi2}); + registry.add("hTPCnCls", "TPC NCls", kTH1F, {axisCluster}); + registry.add("hITSnCls", "ITS NCls", kTH1F, {axisITSNCls}); + registry.add("hTPCnClsCrossedRows", "TPC NClsCrossedRows", kTH1F, {axisCluster}); + registry.add("hEta", "track eta", kTH1F, {axisEta}); + registry.add("hPt", "track pt", kTH1F, {axisPt}); + registry.add("hTPCNsigma", "TPC electron Nsigma", kTH2F, {{axisPt}, {axisNsigma}}); + registry.add("hEnergy", "EMC cluster energy", kTH1F, {axisE}); + registry.add("hM02", "EMC M02", kTH2F, {{axisNsigma}, {axisM02}}); + registry.add("hM20", "EMC M20", kTH2F, {{axisNsigma}, {axisM02}}); + registry.add("hTrMatch", "Track EMC Match", kTH2F, {{axisdPhi}, {axisdEta}}); + registry.add("hTrMatch_mim", "Track EMC Match minimu minimumm", kTH2F, {{axisdPhi}, {axisdEta}}); + registry.add("hMatchPhi", "Match in Phi", kTH2F, {{axisPhi}, {axisPhi}}); + registry.add("hMatchEta", "Match in Eta", kTH2F, {{axisEta}, {axisEta}}); + registry.add("hEop", "energy momentum match", kTH2F, {{axisPt}, {axisEop}}); + registry.add("hEopIsolation", "energy momentum match after isolation", kTH2F, {{axisPt}, {axisEop}}); + registry.add("hEopIsolationTr", "energy momentum match after isolationTr", kTH2F, {{axisPt}, {axisEop}}); + registry.add("hEopNsigTPC", "Eop vs. Nsigma", kTH2F, {{axisNsigma}, {axisEop}}); + registry.add("hEMCtime", "EMC timing", kTH1F, {axisEMCtime}); + registry.add("hIsolationEnergy", "Isolation Energy", kTH2F, {{axisE}, {axisIsoEnergy}}); + registry.add("hIsolationTrack", "Isolation Track", kTH2F, {{axisE}, {axisIsoTrack}}); + registry.add("hInvMassZeeLs", "invariant mass for Z LS pair", kTH2F, {{axisPt}, {axisInvMassZ}}); + registry.add("hInvMassZeeUls", "invariant mass for Z ULS pair", kTH2F, {{axisPt}, {axisInvMassZ}}); + } + bool isIsolatedCluster(const o2::aod::EMCALCluster& cluster, + const SelectedClusters& clusters) + { + float energySum = 0.0; + float isoEnergy = 10.0; + float etaAssCluster = cluster.eta(); + float phiAssCluster = cluster.phi(); + + for (const auto& associateCluster : clusters) { + // Calculate angular distances + double dEta = associateCluster.eta() - etaAssCluster; + double dPhi = associateCluster.phi() - phiAssCluster; + + // Normalize φ difference + dPhi = RecoDecay::constrainAngle(dPhi, -o2::constants::math::PI); + + // Calculate ΔR + double deltaR = std::sqrt(dEta * dEta + dPhi * dPhi); + + // Sum energy within isolation cone + if (deltaR < rIsolation) { + energySum += associateCluster.energy(); + } + } + + if (energySum > 0) { + isoEnergy = energySum / cluster.energy() - 1.0; + } + + registry.fill(HIST("hIsolationEnergy"), cluster.energy(), isoEnergy); + + return (isoEnergy < energyIsolationMax); + } + bool isIsolatedTrack(double etaEle, + double phiEle, + float ptEle, + TrackEle const& tracks) + { + int trackCount = 0; + + for (const auto& track : tracks) { + // skip the reference track + if (std::abs(track.pt() - ptEle) < 1e-4) + continue; + + double dEta = track.eta() - etaEle; + double dPhi = track.phi() - phiEle; + dPhi = RecoDecay::constrainAngle(dPhi, -o2::constants::math::PI); + + double deltaR = std::sqrt(dEta * dEta + dPhi * dPhi); + + if (deltaR < rIsolation) { + trackCount++; + } + } + + registry.fill(HIST("hIsolationTrack"), ptEle, trackCount); + + return (trackCount <= trackIsolationMax); + } + + void process(soa::Filtered::iterator const& collision, + SelectedClusters const& emcClusters, + TrackEle const& tracks, + o2::aod::EMCALMatchedTracks const& matchedtracks) + { + registry.fill(HIST("hEventCounter"), 0.5); + + // LOGF(info, "Collision index : %d", collision.index()); + // LOGF(info, "Number of tracks: %d", tracks.size()); + // LOGF(info, "Number of clusters: %d", clusters.size()); + + registry.fill(HIST("hZvtx"), collision.posZ()); + + for (const auto& track : tracks) { + + if (std::abs(track.eta()) > etaTrUp) + continue; + if (track.tpcNClsCrossedRows() < nclcrossTpcMin) + continue; + if (std::abs(track.dcaXY()) > dcaxyMax) + continue; + if (track.itsChi2NCl() > chi2ItsMax) + continue; + if (track.tpcChi2NCl() > chi2TpcMax) + continue; + if (track.tpcNClsFound() < nclTpcMin) + continue; + if (track.itsNCls() < nclItsMin) + continue; + if (track.pt() < ptMin) + continue; + + registry.fill(HIST("hEta"), track.eta()); + registry.fill(HIST("hITSchi2"), track.itsChi2NCl()); + registry.fill(HIST("hTPCchi2"), track.tpcChi2NCl()); + registry.fill(HIST("hTPCnCls"), track.tpcNClsFound()); + registry.fill(HIST("hITSnCls"), track.itsNCls()); + registry.fill(HIST("hTPCnClsCrossedRows"), track.tpcNClsCrossedRows()); + registry.fill(HIST("hPt"), track.pt()); + registry.fill(HIST("hTPCNsigma"), track.p(), track.tpcNSigmaEl()); + + float energyTrk = 0.0; + + if (track.tpcNSigmaEl() > nsigTpcMinLose && track.tpcNSigmaEl() < nsigTpcMax && track.pt() > ptZeeMin) { + selectedElectronsAss.emplace_back( + track.pt(), + track.eta(), + track.phi(), + energyTrk, + track.sign()); + } + + // track - match + + // continue; + if (track.phi() < phiEmcMin || track.phi() > phiEmcMax) + continue; + auto tracksofcluster = matchedtracks.sliceBy(perClusterMatchedTracks, track.globalIndex()); + + // LOGF(info, "Number of matched track: %d", tracksofcluster.size()); + + double rMin = 999.9; + double dPhiMin = 999.9; + double dEtaMin = 999.9; + bool isIsolated = false; + bool isIsolatedTr = false; + + if (tracksofcluster.size()) { + int nMatch = 0; + for (const auto& match : tracksofcluster) { + if (match.emcalcluster_as().time() < timeEmcMin || match.emcalcluster_as().time() > timeEmcMax) + continue; + if (match.emcalcluster_as().m02() < m02Min || match.emcalcluster_as().m02() > m02Max) + continue; + + float m20Emc = match.emcalcluster_as().m20(); + float m02Emc = match.emcalcluster_as().m02(); + float energyEmc = match.emcalcluster_as().energy(); + double phiEmc = match.emcalcluster_as().phi(); + double etaEmc = match.emcalcluster_as().eta(); + double timeEmc = match.emcalcluster_as().time(); + // LOG(info) << "tr phi0 = " << match.track_as().phi(); + // LOG(info) << "tr phi1 = " << track.phi(); + // LOG(info) << "emc phi = " << phiEmc; + + if (nMatch == 0) { + double dEta = match.track_as().trackEtaEmcal() - etaEmc; + double dPhi = match.track_as().trackPhiEmcal() - phiEmc; + dPhi = RecoDecay::constrainAngle(dPhi, -o2::constants::math::PI); + + registry.fill(HIST("hMatchPhi"), phiEmc, match.track_as().trackPhiEmcal()); + registry.fill(HIST("hMatchEta"), etaEmc, match.track_as().trackEtaEmcal()); + + double r = RecoDecay::sqrtSumOfSquares(dPhi, dEta); + if (r < rMin) { + rMin = r; + dPhiMin = dPhi; + dEtaMin = dEta; + } + registry.fill(HIST("hTrMatch"), dPhi, dEta); + registry.fill(HIST("hEMCtime"), timeEmc); + registry.fill(HIST("hEnergy"), energyEmc); + + if (r > rMatchMax) + continue; + + const auto& cluster = match.emcalcluster_as(); + + double eop = energyEmc / match.track_as().p(); + + // LOG(info) << "E/p" << eop; + registry.fill(HIST("hEopNsigTPC"), match.track_as().tpcNSigmaEl(), eop); + registry.fill(HIST("hM02"), match.track_as().tpcNSigmaEl(), m02Emc); + registry.fill(HIST("hM20"), match.track_as().tpcNSigmaEl(), m20Emc); + if (match.track_as().tpcNSigmaEl() > nsigTpcMin && match.track_as().tpcNSigmaEl() < nsigTpcMax) { + registry.fill(HIST("hEop"), match.track_as().pt(), eop); + + if (eop > eopMin && eop < eopMax) { + isIsolated = isIsolatedCluster(cluster, emcClusters); + isIsolatedTr = isIsolatedTrack(track.phi(), track.eta(), track.pt(), tracks); + } + + if (isIsolated) { + registry.fill(HIST("hEopIsolation"), match.track_as().pt(), eop); + + if (match.track_as().pt() > ptZeeMin) { + + selectedElectronsIso.emplace_back( + match.track_as().pt(), + match.track_as().eta(), + match.track_as().phi(), + energyEmc, + match.track_as().sign()); + } + } + if (isIsolatedTr) { + registry.fill(HIST("hEopIsolationTr"), match.track_as().pt(), eop); + } + } + } + + nMatch++; + } + } + + if (rMin < rMatchMax) { + // LOG(info) << "R mim = " << rMin; + registry.fill(HIST("hTrMatch_mim"), dPhiMin, dEtaMin); + } + + } // end of track loop + + // calculate inv. mass + if (selectedElectronsIso.size() > 0) { + for (size_t i = 0; i < selectedElectronsIso.size(); i++) { + const auto& e1 = selectedElectronsIso[i]; + for (size_t j = 0; j < selectedElectronsAss.size(); j++) { + const auto& e2 = selectedElectronsAss[j]; + + float ptIso = e1.pt; + float ptAss = e2.pt; + if (ptIso == ptAss) + continue; + auto arr1 = RecoDecayPtEtaPhi::pVector(e1.pt, e1.eta, e1.phi); + auto arr2 = RecoDecayPtEtaPhi::pVector(e2.pt, e2.eta, e2.phi); + double mass = RecoDecay::m(std::array{arr1, arr2}, std::array{o2::constants::physics::MassElectron, o2::constants::physics::MassElectron}); + + if (e1.sign() * e2.sign() > 0) { + registry.fill(HIST("hInvMassZeeLs"), ptIso, mass); + } else { + registry.fill(HIST("hInvMassZeeUls"), ptIso, mass); + } + } + } + } // end of inv. mass calculation + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/HFL/Tasks/taskSingleMuon.cxx b/PWGHF/HFL/Tasks/taskSingleMuon.cxx index fc70cfecc35..73445124ae9 100644 --- a/PWGHF/HFL/Tasks/taskSingleMuon.cxx +++ b/PWGHF/HFL/Tasks/taskSingleMuon.cxx @@ -56,8 +56,8 @@ struct HfTaskSingleMuonSelectionAmbiguousMftIndexBuilder { }; struct HfTaskSingleMuon { - Configurable trkType{"trkType", 0, "Muon track type, valid values are 0, 1, 2, 3 and 4"}; - Configurable mcMaskSelection{"mcMaskSelection", 0, "McMask for correct match, valid values are 0 and 128"}; + Configurable trkType{"trkType", 0u, "Muon track type, valid values are 0, 1, 2, 3 and 4"}; + Configurable mcMaskSelection{"mcMaskSelection", 0u, "McMask for correct match, valid values are 0 and 128"}; Configurable etaMin{"etaMin", -3.6, "eta minimum value"}; Configurable etaMax{"etaMax", -2.5, "eta maximum value"}; Configurable pDcaMin{"pDcaMin", 324., "p*DCA maximum value for small Rabs"}; diff --git a/PWGHF/HFL/Tasks/taskSingleMuonReader.cxx b/PWGHF/HFL/Tasks/taskSingleMuonReader.cxx index 50c5ea13cf0..7d04bead362 100644 --- a/PWGHF/HFL/Tasks/taskSingleMuonReader.cxx +++ b/PWGHF/HFL/Tasks/taskSingleMuonReader.cxx @@ -31,6 +31,7 @@ using namespace o2::framework::expressions; using MyCollisions = soa::Join; using MyMuons = soa::Join; +using MyMcMuons = soa::Join; namespace o2::aod { @@ -39,8 +40,9 @@ namespace single_muon DECLARE_SOA_COLUMN(Pt, pt, float); DECLARE_SOA_COLUMN(DcaXY, dcaXY, float); DECLARE_SOA_COLUMN(DeltaPt, deltaPt, float); +DECLARE_SOA_COLUMN(Chi2, chi2, float); } // namespace single_muon -DECLARE_SOA_TABLE(HfSingleMuon, "AOD", "SINGLEMUON", single_muon::Pt, single_muon::DcaXY, single_muon::DeltaPt); +DECLARE_SOA_TABLE(HfSingleMuon, "AOD", "SINGLEMUON", single_muon::Pt, single_muon::DcaXY, single_muon::DeltaPt, single_muon::Chi2); } // namespace o2::aod struct HfTaskSingleMuonReader { @@ -53,6 +55,7 @@ struct HfTaskSingleMuonReader { Configurable rAbsMax{"rAbsMax", 89.5, "R at absorber end maximum value"}; Configurable rAbsMin{"rAbsMin", 26.5, "R at absorber end minimum value"}; Configurable zVtx{"zVtx", 10., "Z edge of primary vertex [cm]"}; + Configurable fillMcHist{"fillMcHist", false, "fill MC-related histograms"}; o2::framework::HistogramRegistry registry{ "registry", @@ -65,20 +68,63 @@ struct HfTaskSingleMuonReader { { AxisSpec axisPt{200, 0., 100., "#it{p}_{T} (GeV/#it{c})"}; AxisSpec axisEta{100, -4., -2., "#it{#eta}"}; - AxisSpec axisDCA{400, 0., 4., "#it{DCA}_{xy} (cm)"}; + AxisSpec axisDCA{2000, 0., 2., "#it{DCA}_{xy} (cm)"}; AxisSpec axisChi2MatchMCHMFT{100, 0., 100., "MCH-MFT matching #chi^{2}"}; AxisSpec axisSign{5, -2.5, 2.5, "Charge"}; + AxisSpec axisRabs{1000, 0, 100, "R at Absorber End (cm)"}; AxisSpec axisDeltaPt{10000, -50, 50, "#Delta #it{p}_{T} (GeV/#it{c})"}; AxisSpec axisVtxZ{80, -20., 20., "#it{z}_{vtx} (cm)"}; - HistogramConfigSpec hTHnMu{HistType::kTHnSparseF, {axisPt, axisEta, axisDCA, axisSign, axisChi2MatchMCHMFT, axisDeltaPt}, 6}; + HistogramConfigSpec hTHnMu{HistType::kTHnSparseF, {axisPt, axisEta, axisDCA, axisRabs, axisSign, axisChi2MatchMCHMFT, axisDeltaPt}, 7}; HistogramConfigSpec hVtxZ{HistType::kTH1F, {axisVtxZ}}; registry.add("hMuAfterCuts", "", hTHnMu); + if (fillMcHist) { + registry.add("hMuAfterCutsTrue", "", hTHnMu); + registry.add("hMuAfterCutsFake", "", hTHnMu); + } registry.add("hVtxZ", "", hVtxZ); } - void process(MyCollisions::iterator const& collision, MyMuons const& muons) + template + void runMuonSel(TCollision const& collision, TMuons const& muons) + { + registry.fill(HIST("hVtxZ"), collision.posZ()); + for (const auto& muon : muons) { + if (muon.trackType() != trkType) { + continue; + } + + const auto eta(muon.eta()), pDca(muon.pDca()); + const auto rAbs(muon.rAtAbsorberEnd()); + const auto dcaXY(RecoDecay::sqrtSumOfSquares(muon.fwdDcaX(), muon.fwdDcaY())); + const auto pt(muon.pt()); + const auto charge(muon.sign()); + const auto chi2(muon.chi2MatchMCHMFT()); + + if ((eta >= etaMax) || (eta < etaMin)) { + continue; + } + + if ((rAbs >= rAbsMax) || (rAbs < rAbsMin)) { + continue; + } + if (pDca >= pDcaMax) { + continue; + } + + // histograms after acceptance cuts + if (muon.has_matchMCHTrack()) { + auto muonType3 = muon.template matchMCHTrack_as(); + auto Dpt = muonType3.pt() - pt; + + singleMuon(pt, dcaXY, Dpt, chi2); + registry.fill(HIST("hMuAfterCuts"), pt, eta, dcaXY, rAbs, charge, chi2, Dpt); + } + } + } + template + void runMuonSelMc(TCollision const& collision, TMuons const& muons) { registry.fill(HIST("hVtxZ"), collision.posZ()); for (const auto& muon : muons) { @@ -96,6 +142,7 @@ struct HfTaskSingleMuonReader { if ((eta >= etaMax) || (eta < etaMin)) { continue; } + if ((rAbs >= rAbsMax) || (rAbs < rAbsMin)) { continue; } @@ -105,13 +152,31 @@ struct HfTaskSingleMuonReader { // histograms after acceptance cuts if (muon.has_matchMCHTrack()) { - auto muonType3 = muon.matchMCHTrack_as(); + auto muonType3 = muon.template matchMCHTrack_as(); auto Dpt = muonType3.pt() - pt; - singleMuon(pt, dcaXY, Dpt); - registry.fill(HIST("hMuAfterCuts"), pt, eta, dcaXY, charge, chi2, Dpt); + + singleMuon(pt, dcaXY, Dpt, chi2); + registry.fill(HIST("hMuAfterCuts"), pt, eta, dcaXY, rAbs, charge, chi2, Dpt); + if (muon.mcMask() == 0) { + registry.fill(HIST("hMuAfterCutsTrue"), pt, eta, dcaXY, rAbs, charge, chi2, Dpt); + } + if (muon.mcMask() == 128) { + registry.fill(HIST("hMuAfterCutsFake"), pt, eta, dcaXY, rAbs, charge, chi2, Dpt); + } } } } + void processMuon(MyCollisions::iterator const& collision, MyMuons const& muons) + { + runMuonSel(collision, muons); + } + void processMuonMc(MyCollisions::iterator const& collision, MyMcMuons const& muons) + { + runMuonSelMc(collision, muons); + } + + PROCESS_SWITCH(HfTaskSingleMuonReader, processMuon, "run muon selection with real data", true); + PROCESS_SWITCH(HfTaskSingleMuonReader, processMuonMc, "run muon selection with MC data", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/HFL/Tasks/taskSingleMuonReaderAssoc.cxx b/PWGHF/HFL/Tasks/taskSingleMuonReaderAssoc.cxx new file mode 100644 index 00000000000..03fa6efb5a5 --- /dev/null +++ b/PWGHF/HFL/Tasks/taskSingleMuonReaderAssoc.cxx @@ -0,0 +1,187 @@ +// 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 taskSingleMuonReaderAssoc.cxx +/// \brief Task used to read the derived table produced by the tableMaker-association of DQ framework and extract observables on single muons needed for the HF-muon analysis. +/// \author Maolin Zhang , CCNU + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/TrackFwd.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using MyCollisions = soa::Join; +using MyMuons = soa::Join; +using MyMcMuons = soa::Join; + +namespace o2::aod +{ +namespace single_muon +{ +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(DcaXY, dcaXY, float); +DECLARE_SOA_COLUMN(DeltaPt, deltaPt, float); +DECLARE_SOA_COLUMN(Chi2, chi2, float); +} // namespace single_muon +DECLARE_SOA_TABLE(HfSingleMuon, "AOD", "SINGLEMUON", single_muon::Pt, single_muon::DcaXY, single_muon::DeltaPt, single_muon::Chi2); +} // namespace o2::aod + +struct HfTaskSingleMuonReaderAssoc { + Produces singleMuon; + + Configurable trkType{"trkType", 0, "Muon track type, valid values are 0, 1, 2, 3 and 4"}; + Configurable etaMin{"etaMin", -3.6, "eta minimum value"}; + Configurable etaMax{"etaMax", -2.5, "eta maximum value"}; + Configurable pDcaMax{"pDcaMax", 594., "p*DCA maximum value"}; + Configurable rAbsMax{"rAbsMax", 89.5, "R at absorber end maximum value"}; + Configurable rAbsMin{"rAbsMin", 26.5, "R at absorber end minimum value"}; + Configurable fillMcHist{"fillMcHist", false, "fill MC-related histograms"}; + + HistogramRegistry registry{"registry"}; + + void init(InitContext&) + { + AxisSpec axisPt{200, 0., 100., "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisEta{100, -4., -2., "#it{#eta}"}; + AxisSpec axisDCA{2000, 0., 2., "#it{DCA}_{xy} (cm)"}; + AxisSpec axisChi2MatchMCHMFT{100, 0., 100., "MCH-MFT matching #chi^{2}"}; + AxisSpec axisSign{5, -2.5, 2.5, "Charge"}; + AxisSpec axisRabs{1000, 0, 100, "R at Absorber End (cm)"}; + AxisSpec axisDeltaPt{10000, -50, 50, "#Delta #it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisVtxZ{80, -20., 20., "#it{z}_{vtx} (cm)"}; + + HistogramConfigSpec hTHnMu{HistType::kTHnSparseF, {axisPt, axisEta, axisDCA, axisRabs, axisSign, axisChi2MatchMCHMFT, axisDeltaPt}, 7}; + HistogramConfigSpec hVtxZ{HistType::kTH1F, {axisVtxZ}}; + + registry.add("hMuAfterCuts", "", hTHnMu); + if (fillMcHist) { + registry.add("hMuAfterCutsTrue", "", hTHnMu); + registry.add("hMuAfterCutsFake", "", hTHnMu); + } + registry.add("hVtxZ", "", hVtxZ); + } + + template + void runMuonSelAssoc(ReducedMuonsAssoc const& assocs, TCollisions const& collisions, TMuons const&) + { + for (const auto& collision : collisions) { + registry.fill(HIST("hVtxZ"), collision.posZ()); + } + for (const auto& assoc : assocs) { + auto muon = assoc.template reducedmuon_as(); + if (muon.trackType() != trkType) { + continue; + } + + const auto eta(muon.eta()), pDca(muon.pDca()); + const auto rAbs(muon.rAtAbsorberEnd()); + const auto dcaXY(RecoDecay::sqrtSumOfSquares(muon.fwdDcaX(), muon.fwdDcaY())); + const auto pt(muon.pt()); + const auto charge(muon.sign()); + const auto chi2(muon.chi2MatchMCHMFT()); + + if ((eta >= etaMax) || (eta < etaMin)) { + continue; + } + if ((rAbs >= rAbsMax) || (rAbs < rAbsMin)) { + continue; + } + if (pDca >= pDcaMax) { + continue; + } + + // histograms after acceptance cuts + if (muon.has_matchMCHTrack()) { + auto muonType3 = muon.template matchMCHTrack_as(); + auto Dpt = muonType3.pt() - pt; + + singleMuon(pt, dcaXY, Dpt, chi2); + registry.fill(HIST("hMuAfterCuts"), pt, eta, dcaXY, rAbs, charge, chi2, Dpt); + } + } + } + + template + void runMuonSelMcAssoc(ReducedMuonsAssoc const& assocs, TCollisions const& collisions, TMuons const&) + { + for (const auto& collision : collisions) { + registry.fill(HIST("hVtxZ"), collision.posZ()); + } + for (const auto& assoc : assocs) { + auto muon = assoc.template reducedmuon_as(); + if (muon.trackType() != trkType) { + continue; + } + + const auto eta(muon.eta()), pDca(muon.pDca()); + const auto rAbs(muon.rAtAbsorberEnd()); + const auto dcaXY(RecoDecay::sqrtSumOfSquares(muon.fwdDcaX(), muon.fwdDcaY())); + const auto pt(muon.pt()); + const auto charge(muon.sign()); + const auto chi2(muon.chi2MatchMCHMFT()); + + if ((eta >= etaMax) || (eta < etaMin)) { + continue; + } + if ((rAbs >= rAbsMax) || (rAbs < rAbsMin)) { + continue; + } + if (pDca >= pDcaMax) { + continue; + } + + // histograms after acceptance cuts + if (muon.has_matchMCHTrack()) { + auto muonType3 = muon.template matchMCHTrack_as(); + auto Dpt = muonType3.pt() - pt; + + singleMuon(pt, dcaXY, Dpt, chi2); + registry.fill(HIST("hMuAfterCuts"), pt, eta, dcaXY, rAbs, charge, chi2, Dpt); + if (muon.mcMask() == 0) { + registry.fill(HIST("hMuAfterCutsTrue"), pt, eta, dcaXY, rAbs, charge, chi2, Dpt); + } + if (muon.mcMask() == 128) { + registry.fill(HIST("hMuAfterCutsFake"), pt, eta, dcaXY, rAbs, charge, chi2, Dpt); + } + } + } + } + + void processMuon(ReducedMuonsAssoc const& assocs, MyCollisions const& collisions, MyMuons const& muons) + { + runMuonSelAssoc(assocs, collisions, muons); + } + PROCESS_SWITCH(HfTaskSingleMuonReaderAssoc, processMuon, "run muon selection with real data", true); + + void processMuonMc(ReducedMuonsAssoc const& assocs, MyCollisions const& collisions, MyMcMuons const& muons) + { + runMuonSelMcAssoc(assocs, collisions, muons); + } + PROCESS_SWITCH(HfTaskSingleMuonReaderAssoc, processMuonMc, "run muon selection with MC data", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/HFL/Tasks/taskSingleMuonSource.cxx b/PWGHF/HFL/Tasks/taskSingleMuonSource.cxx index 8fe5020cb9e..d60a04f80d0 100644 --- a/PWGHF/HFL/Tasks/taskSingleMuonSource.cxx +++ b/PWGHF/HFL/Tasks/taskSingleMuonSource.cxx @@ -65,6 +65,7 @@ struct HfTaskSingleMuonSource { Configurable mcMaskSelection{"mcMaskSelection", 0, "McMask for correct match, valid values are 0 and 128"}; Configurable trackType{"trackType", 0, "Muon track type, validated values are 0, 1, 2, 3 and 4"}; + Configurable charge{"charge", -1, "Muon track charge, validated values are 0, 1 and -1, 0 represents both 1 and -1"}; double pDcaMax = 594.0; // p*DCA maximum value for large Rabs double rAbsMin = 26.5; // R at absorber end minimum value @@ -87,21 +88,24 @@ struct HfTaskSingleMuonSource { "NonpromptCharmMu", "PromptCharmMu", "LightDecayMu", + "QuarkoniumDecayMu", "SecondaryMu", "Hadron", "Unidentified"}; - AxisSpec axisColNumber{1, 0., 1., "Selected collisions"}; + AxisSpec axisColNumber{1, 0.5, 1.5, "Selected collisions"}; AxisSpec axisDCA{5000, 0., 5., "DCA (cm)"}; AxisSpec axisChi2{500, 0., 100., "#chi^{2} of MCH-MFT matching"}; AxisSpec axisPt{200, 0., 100., "#it{p}_{T,reco} (GeV/#it{c})"}; AxisSpec axisDeltaPt{1000, -50., 50., "#Delta #it{p}_{T} (GeV/#it{c})"}; + HistogramConfigSpec h1ColNumber{HistType::kTH1F, {axisColNumber}}; HistogramConfigSpec h1Pt{HistType::kTH1F, {axisPt}}; HistogramConfigSpec h2PtDCA{HistType::kTH2F, {axisPt, axisDCA}}; HistogramConfigSpec h2PtChi2{HistType::kTH2F, {axisPt, axisChi2}}; HistogramConfigSpec h2PtDeltaPt{HistType::kTH2F, {axisPt, axisDeltaPt}}; + registry.add("h1ColNumber", "", h1ColNumber); for (const auto& src : muonSources) { registry.add(Form("h1%sPt", src.Data()), "", h1Pt); registry.add(Form("h2%sPtDCA", src.Data()), "", h2PtDCA); @@ -216,6 +220,12 @@ struct HfTaskSingleMuonSource { return (isMuon(mask) && TESTBIT(mask, HasLightParent) && (!TESTBIT(mask, IsSecondary)) && (!TESTBIT(mask, HasQuarkoniumParent))); } + // this muon comes from quarkonium decay + bool isQuarkoniumDecayMu(const uint8_t& mask) + { + return (isMuon(mask) && TESTBIT(mask, HasQuarkoniumParent) && (!TESTBIT(mask, HasBeautyParent)) && (!TESTBIT(mask, HasCharmParent))); + } + // this muon comes from transport bool isSecondaryMu(const uint8_t& mask) { @@ -266,6 +276,10 @@ struct HfTaskSingleMuonSource { registry.fill(HIST("h2LightDecayMuPtDCA"), pt, dca); registry.fill(HIST("h2LightDecayMuPtChi2"), pt, chi2); registry.fill(HIST("h2LightDecayMuPtDeltaPt"), pt, deltaPt); + } else if (isQuarkoniumDecayMu(mask)) { + registry.fill(HIST("h2QuarkoniumDecayMuPtDCA"), pt, dca); + registry.fill(HIST("h2QuarkoniumDecayMuPtChi2"), pt, chi2); + registry.fill(HIST("h2QuarkoniumDecayMuPtDeltaPt"), pt, deltaPt); } else if (isSecondaryMu(mask)) { registry.fill(HIST("h2SecondaryMuPtDCA"), pt, dca); registry.fill(HIST("h2SecondaryMuPtChi2"), pt, chi2); @@ -288,6 +302,8 @@ struct HfTaskSingleMuonSource { registry.fill(HIST("h1PromptCharmMuPt"), pt); } else if (isLightDecayMu(mask)) { registry.fill(HIST("h1LightDecayMuPt"), pt); + } else if (isQuarkoniumDecayMu(mask)) { + registry.fill(HIST("h1QuarkoniumDecayMuPt"), pt); } else if (isSecondaryMu(mask)) { registry.fill(HIST("h1SecondaryMuPt"), pt); } else if (isHadron(mask)) { @@ -306,6 +322,7 @@ struct HfTaskSingleMuonSource { if (std::abs(collision.posZ()) > edgeZ) { return; } + registry.fill(HIST("h1ColNumber"), 1.); for (const auto& muon : muons) { // muon selections @@ -328,6 +345,9 @@ struct HfTaskSingleMuonSource { if ((muon.chi2() >= 1e6) || (muon.chi2() < 0)) { continue; } + if (charge != 0 && muon.sign() != charge) { + continue; + } fillHistograms(muon); } // loop over muons } diff --git a/PWGHF/Macros/computeFonllPlusPythiaPredictions.C b/PWGHF/Macros/computeFonllPlusPythiaPredictions.C new file mode 100644 index 00000000000..bdd8f1ca7e2 --- /dev/null +++ b/PWGHF/Macros/computeFonllPlusPythiaPredictions.C @@ -0,0 +1,364 @@ +// 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 +/// \brief macro for the calculation of FONLL+PYTHIA predictions for non-prompt charm hadrons +/// +/// \author Fabrizio Grosa , CERN + +#if !defined(__CINT__) || defined(__CLING__) + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" + +#include "CommonConstants/MathConstants.h" +#include "Framework/Logger.h" + +#include "Pythia8/Pythia.h" + +#endif + +enum Bhadrons { + Bplus = 0, + Bzero, + Bs, + Lb, + NBeautyHadrons +}; + +enum Chadrons { + Dplus = 0, + Dzero, + Ds, + Lc, + DstarPlus, + NCharmHadrons +}; + +enum BeautyFragFracOptions { + EpEm = 0, + PPbar, + LHCb, + LHCbMin, + LHCbMax, + NBeutyFragFracOptions +}; + +const std::array beautyFragFracEpEm = {0.408, 0.408, 0.100, 0.084}; +const std::array beautyFragFracPPbar = {0.344, 0.344, 0.115, 0.198}; +const std::array charmFragFracEpEm = {0.542, 0.225, 0.092, 0.057, 0.236}; // Values from e+e- ARXIV:1404.3888 (D0, D+, Ds, Lc, D*+) +const std::array beautyHadPdgs = {511, 521, 531, 5122}; +const std::array charmHadPdgs = {411, 421, 431, 4122, 413}; +const std::array beautyHadNames = {"Bzero", "Bplus", "Bs", "Lb"}; +const std::array charmHadNames = {"Dplus", "Dzero", "Ds", "Lc", "DstarPlus"}; +std::array namesFonll = {"Central", "Min", "Max"}; + +// FUNCTION PROTOTYPES +//__________________________________________________________________________________________________ +void computeFonllPlusPythiaPredictions(int nDecays = 10000000, + int seed = 42, + std::string inFileFonllBhad = "fonll_bhadron_5dot5teV_y1.txt", + int fragFracOpt = EpEm, + bool addPromptCharmHadrons = true, + std::string inFileFonllPromptDzero = "fonll_prompt_dzero_5dot5teV_y05.txt", + std::string inFileFonllPromptDplus = "fonll_prompt_dplus_5dot5teV_y05.txt", + std::string inFileFonllPromptDstarPlus = "fonll_prompt_dstar_5dot5teV_y05.txt", + std::string outFileName = "fonll_pythia_beautyFFee_charmhadrons_5dot5tev_y0dot5.root"); +std::vector splitString(const std::string& str, char delimiter); +std::array readFonll(std::string inFile, std::string histName = "hFonllBhadron"); + +// FUNCTION IMPLEMENTATIONS +//__________________________________________________________________________________________________ +std::vector splitString(const std::string& str, char delimiter) +{ + std::vector tokens; + std::stringstream ss(str); + std::string token; + + while (std::getline(ss, token, delimiter)) { + tokens.push_back(token); + } + tokens.erase(std::remove_if(tokens.begin(), tokens.end(), [](const std::string& str) { + return str.find_first_not_of(' ') == std::string::npos; // Check if the string contains only spaces + }), + tokens.end()); + + return tokens; +} + +//__________________________________________________________________________________________________ +std::array readFonll(std::string inFile, std::string histName) +{ + + std::array hFonll{nullptr, nullptr, nullptr}; + + std::ifstream inputFile(inFile); + + if (!inputFile) { + LOGP(fatal, "Error opening file {}", inFile); + return hFonll; + } + + std::string line; + + std::vector ptCent{}; + std::vector crossSecCent{}; + std::vector crossSecMin{}; + std::vector crossSecMax{}; + while (std::getline(inputFile, line)) { + if (line.find("#") != std::string::npos) { + continue; + } + std::vector elements = splitString(line, ' '); + ptCent.push_back(std::stof(elements[0])); + crossSecCent.push_back(std::stof(elements[1])); + crossSecMin.push_back(std::stof(elements[2])); + crossSecMax.push_back(std::stof(elements[3])); + } + inputFile.close(); + + if (ptCent.size() < 2) { + LOGP(fatal, "Only one pT value in FONLL file {}, cannot deduce binning.", inFile); + } + + float ptWidth = ptCent[1] - ptCent[0]; + float ptMin = ptCent.front() - ptWidth / 2; + float ptMax = ptCent.back() + ptWidth / 2; + + hFonll[0] = new TH1D(Form("%sCentral", histName.data()), ";#it{p}_{T} (GeV/#it{c});d#sigma/d#it{p}_{T} (#it{c}/GeV)", ptCent.size(), ptMin, ptMax); + hFonll[1] = new TH1D(Form("%sMin", histName.data()), ";#it{p}_{T} (GeV/#it{c});d#sigma/d#it{p}_{T} (#it{c}/GeV)", ptCent.size(), ptMin, ptMax); + hFonll[2] = new TH1D(Form("%sMax", histName.data()), ";#it{p}_{T} (GeV/#it{c});d#sigma/d#it{p}_{T} (#it{c}/GeV)", ptCent.size(), ptMin, ptMax); + for (auto iPt{0u}; iPt < ptCent.size(); ++iPt) { + hFonll[0]->SetBinContent(iPt + 1, crossSecCent[iPt]); + hFonll[1]->SetBinContent(iPt + 1, crossSecMin[iPt]); + hFonll[2]->SetBinContent(iPt + 1, crossSecMax[iPt]); + } + + return hFonll; +} + +//__________________________________________________________________________________________________ +void computeFonllPlusPythiaPredictions(int nDecays, int seed, std::string inFileFonllBhad, int fragFracOpt, bool addPromptCharmHadrons, std::string inFileFonllPromptDzero, std::string inFileFonllPromptDplus, std::string inFileFonllPromptDstarPlus, std::string outFileName) +{ + + gROOT->SetBatch(true); + gRandom->SetSeed(seed); + + if (fragFracOpt >= NBeutyFragFracOptions) { + LOGP(fatal, "Fragmentation fraction option not supported! Exit"); + } + + // init pythia object for the decayer + Pythia8::Pythia pythia; + pythia.readString("SoftQCD:inelastic = on"); + pythia.readString("Tune:pp = 14"); + pythia.readString("Random:setSeed = on"); + pythia.readString(Form("Random:seed %d", seed)); + pythia.init(); + + // get histograms from FONLL + auto hFonllBhad = readFonll(inFileFonllBhad); + if (!hFonllBhad[0]) { + return; + } + + std::map> hFonllPromptChad{}; + if (addPromptCharmHadrons) { + hFonllPromptChad[411] = readFonll(inFileFonllPromptDplus, "hFonllPromptDplus"); + hFonllPromptChad[421] = readFonll(inFileFonllPromptDzero, "hFonllPromptDzero"); + hFonllPromptChad[413] = readFonll(inFileFonllPromptDstarPlus, "hFonllPromptDstarPlus"); + // TODO: cook something for Ds and Lc + hFonllPromptChad[431] = {nullptr, nullptr, nullptr}; + hFonllPromptChad[4122] = {nullptr, nullptr, nullptr}; + for (auto iChad{0}; iChad < NCharmHadrons; ++iChad) { + if (charmHadPdgs[iChad] == 431 || charmHadPdgs[iChad] == 4122) { + continue; + } + for (auto iFonll{0}; iFonll < 3; ++iFonll) { + hFonllPromptChad[charmHadPdgs[iChad]][iFonll]->Scale(charmFragFracEpEm[iChad]); + } + } + } + + // initialise histograms for non-prompt charm hadrons + std::map, NBeautyHadrons + 1>> hFonllPythiaNonPromptChad{}; + for (auto iChad{0}; iChad < NCharmHadrons; ++iChad) { + for (auto iBhad{0}; iBhad < NBeautyHadrons; ++iBhad) { + for (auto iFonll{0}; iFonll < 3; ++iFonll) { + hFonllPythiaNonPromptChad[charmHadPdgs[iChad]][iBhad][iFonll] = new TH1D( + Form("hFonll%sFrom%s%s", charmHadNames[iChad].data(), beautyHadNames[iBhad].data(), namesFonll[iFonll].data()), + ";#it{p}_{T} (GeV/#it{c});d#sigma/d#it{p}_{T} (#it{c}/GeV)", 1000, 0., 100.); + hFonllPythiaNonPromptChad[charmHadPdgs[iChad]][iBhad][iFonll]->Sumw2(); + } + } + } + + // compute fractions for normalisation + std::array fragFracs{}; + std::array, NBeautyHadrons> fragFracFuncs{}; // used in case of LHCb due to the pT dependence + if (fragFracOpt == EpEm) { + fragFracs = beautyFragFracEpEm; + } else if (fragFracOpt == PPbar) { + fragFracs = beautyFragFracPPbar; + } else { // LHCb + for (int iPar{0}; iPar < 15; ++iPar) { + fragFracFuncs[0][iPar] = new TF1(Form("fracBz_%d", iPar), "1 / (2 * (([0] * ([1] + [2] * (x - [3]))) + ([4] * ([5] + exp([6] + [7] * x))) + 1) )", 0.f, 300.f); // B0 + fragFracFuncs[1][iPar] = new TF1(Form("fracBp_%d", iPar), "1 / (2 * (([0] * ([1] + [2] * (x - [3]))) + ([4] * ([5] + exp([6] + [7] * x))) + 1) )", 0.f, 300.f); // B+ + fragFracFuncs[2][iPar] = new TF1(Form("fracBs_%d", iPar), "([0] * ([1] + [2] * (x - [3]))) / (([0] * [1] + [2] * (x - [3])) + ([4] * ([5] + exp([6] + [7] * x))) + 1)", 0.f, 300.f); // Bs0 + fragFracFuncs[3][iPar] = new TF1(Form("fracLb_%d", iPar), "([4] * ([5] + exp([6] + [7] * x))) / (([0] * ([1] + [2] * (x - [3]))) + ([4] * ([5] + exp([6] + [7] * x))) + 1)", 0.f, 300.f); // Lb + + // parameters from https://arxiv.org/pdf/1902.06794.pdf + float sign = (iPar < 8) ? 1.f : -1.f; + float parLbA = 1.f + ((iPar == 1 || iPar == 8) ? sign * 0.061f : 0.f); + float parLbp1 = 0.0793f + ((iPar == 2 || iPar == 9) ? sign * 0.0141f : 0.f); + float parLbp2 = -1.022f + ((iPar == 3 || iPar == 10) ? sign * 0.0047f : 0.f); + float parLbp3 = -0.107f + ((iPar == 4 || iPar == 11) ? sign * 0.002f : 0.f); + float parBsA = 1.f + ((iPar == 5 || iPar == 12) ? sign * 0.043f : 0.f); + float parBsp1 = 0.119f + ((iPar == 6 || iPar == 13) ? sign * 0.001f : 0.f); + float parBsp2 = -0.00091f + ((iPar == 7 || iPar == 14) ? sign * 0.00025f : 0.f); + float parBsAvePt = 10.1f; + + for (int iBhad{0}; iBhad < NBeautyHadrons; ++iBhad) { + fragFracFuncs[iBhad][iPar]->SetParameters(parBsA, parBsp1, parBsp2, parBsAvePt, parLbA, parLbp1, parLbp2, parLbp3); + } + } + } + + std::array beautyHadMasses{}; + for (auto iFonll{0}; iFonll < 3; ++iFonll) { + for (auto iBhad{0}; iBhad < NBeautyHadrons; ++iBhad) { + beautyHadMasses[iBhad] = TDatabasePDG::Instance()->GetParticle(beautyHadPdgs[iBhad])->Mass(); + for (auto iDecay{0}; iDecay < nDecays; ++iDecay) { + auto ptB = hFonllBhad[iFonll]->GetRandom(); + auto yB = gRandom->Uniform(-1., 1.); // we might consider to use more realistic shape from FONLL in the future + auto phiB = gRandom->Rndm() * o2::constants::math::TwoPI; + auto pxB = ptB * std::cos(phiB); + auto pyB = ptB * std::sin(phiB); + auto mtB = std::sqrt(beautyHadMasses[iBhad] * beautyHadMasses[iBhad] + ptB * ptB); + auto pzB = mtB * std::sinh(yB); + auto pB = std::sqrt(ptB * ptB + pzB * pzB); + auto eB = std::sqrt(beautyHadMasses[iBhad] * beautyHadMasses[iBhad] + pB * pB); + + Pythia8::Particle Bhad; + Bhad.id(beautyHadPdgs[iBhad]); + Bhad.status(81); + Bhad.m(beautyHadMasses[iBhad]); + Bhad.xProd(0.); + Bhad.yProd(0.); + Bhad.zProd(0.); + Bhad.tProd(0.); + Bhad.e(eB); + Bhad.px(pxB); + Bhad.py(pyB); + Bhad.pz(pzB); + + pythia.event.reset(); + pythia.event.append(Bhad); + auto idPart = pythia.event[1].id(); + pythia.particleData.mayDecay(idPart, true); + pythia.moreDecays(); + + auto fracB = fragFracs[iBhad]; + if (fragFracOpt == LHCb) { + fracB = fragFracFuncs[iBhad][0]->Eval(ptB > 5.f ? ptB : 5); + } else if (fragFracOpt == LHCbMin) { + fracB = 2.f; + for (int iPar{0}; iPar < 15; ++iPar) { + auto tmpFrac = fragFracFuncs[iBhad][iPar]->Eval(ptB > 5.f ? ptB : 5); + if (tmpFrac < fracB) { + fracB = tmpFrac; + } + } + } else if (fragFracOpt == LHCbMax) { + fracB = -1.f; + for (int iPar{0}; iPar < 15; ++iPar) { + auto tmpFrac = fragFracFuncs[iBhad][iPar]->Eval(ptB > 5.f ? ptB : 5); + if (tmpFrac > fracB) { + fracB = tmpFrac; + } + } + } + + for (int iPart{1}; iPart < pythia.event.size(); ++iPart) { + if (std::abs(pythia.event[iPart].y()) > 0.5) { + continue; + } + auto absPdg = std::abs(pythia.event[iPart].id()); + if (std::find(charmHadPdgs.begin(), charmHadPdgs.end(), absPdg) != charmHadPdgs.end()) { // we found a charm hadron, let's fill the corresponding histogram + hFonllPythiaNonPromptChad[absPdg][iBhad][iFonll]->Fill(pythia.event[iPart].pT(), fracB); + } + } + } + } + } + + std::array normCrossSec{}; + for (auto iFonll{0}; iFonll < 3; ++iFonll) { + normCrossSec[iFonll] = hFonllBhad[iFonll]->Integral(); + for (auto iChad{0}; iChad < NCharmHadrons; ++iChad) { + hFonllPythiaNonPromptChad[charmHadPdgs[iChad]][NBeautyHadrons][iFonll] = reinterpret_cast(hFonllPythiaNonPromptChad[charmHadPdgs[iChad]][0][iFonll]->Clone(Form("hFonllNonPrompt%s%s", charmHadNames[iChad].data(), namesFonll[iFonll].data()))); + hFonllPythiaNonPromptChad[charmHadPdgs[iChad]][NBeautyHadrons][iFonll]->Reset(); + for (auto iBhad{0}; iBhad < NBeautyHadrons; ++iBhad) { + hFonllPythiaNonPromptChad[charmHadPdgs[iChad]][iBhad][iFonll]->Scale(normCrossSec[iFonll] / nDecays); + hFonllPythiaNonPromptChad[charmHadPdgs[iChad]][NBeautyHadrons][iFonll]->Add(hFonllPythiaNonPromptChad[charmHadPdgs[iChad]][iBhad][iFonll]); + } + } + } + + TFile outFile(outFileName.data(), "recreate"); + for (auto iFonll{0}; iFonll < 3; ++iFonll) { + hFonllBhad[iFonll]->Write(); + } + auto dirNonPrompt = new TDirectoryFile("NonPrompt", "NonPrompt"); + dirNonPrompt->Write(); + for (auto iChad{0}; iChad < NCharmHadrons; ++iChad) { + dirNonPrompt->cd(); + auto dirCharmHad = new TDirectoryFile(charmHadNames[iChad].data(), charmHadNames[iChad].data()); + dirCharmHad->Write(); + dirCharmHad->cd(); + for (auto iBhad{0}; iBhad < NBeautyHadrons + 1; ++iBhad) { + for (auto iFonll{0}; iFonll < 3; ++iFonll) { + hFonllPythiaNonPromptChad[charmHadPdgs[iChad]][iBhad][iFonll]->Write(); + } + } + } + if (addPromptCharmHadrons) { + outFile.cd(); + auto dirPrompt = new TDirectoryFile("Prompt", "Prompt"); + dirPrompt->Write(); + for (auto iChad{0}; iChad < NCharmHadrons; ++iChad) { + dirPrompt->cd(); + auto dirCharmHad = new TDirectoryFile(charmHadNames[iChad].data(), charmHadNames[iChad].data()); + dirCharmHad->Write(); + dirCharmHad->cd(); + for (auto iFonll{0}; iFonll < 3; ++iFonll) { + if (hFonllPromptChad[charmHadPdgs[iChad]][iFonll]) { + hFonllPromptChad[charmHadPdgs[iChad]][iFonll]->Write(); + } + } + } + } + outFile.Close(); +} diff --git a/PWGHF/TableProducer/CMakeLists.txt b/PWGHF/TableProducer/CMakeLists.txt index 83069f34109..22895a583ce 100644 --- a/PWGHF/TableProducer/CMakeLists.txt +++ b/PWGHF/TableProducer/CMakeLists.txt @@ -13,7 +13,7 @@ o2physics_add_dpl_workflow(track-index-skim-creator SOURCES trackIndexSkimCreator.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsVertexing O2::DCAFitter O2Physics::AnalysisCCDB O2Physics::MLCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsVertexing O2::DCAFitter O2Physics::AnalysisCCDB O2Physics::MLCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) # Helpers @@ -28,16 +28,21 @@ o2physics_add_dpl_workflow(pid-creator PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(mc-pid-tof + SOURCES mcPidTof.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::TOFWorkflowUtils + COMPONENT_NAME Analysis) + # Candidate creators o2physics_add_dpl_workflow(candidate-creator-2prong SOURCES candidateCreator2Prong.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(candidate-creator-3prong SOURCES candidateCreator3Prong.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(candidate-creator-b0 @@ -57,12 +62,12 @@ o2physics_add_dpl_workflow(candidate-creator-bs o2physics_add_dpl_workflow(candidate-creator-cascade SOURCES candidateCreatorCascade.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(candidate-creator-dstar SOURCES candidateCreatorDstar.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(candidate-creator-lb @@ -75,16 +80,31 @@ o2physics_add_dpl_workflow(candidate-creator-sigmac0plusplus PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(candidate-creator-to-xi-pi - SOURCES candidateCreatorToXiPi.cxx +o2physics_add_dpl_workflow(candidate-creator-sigmac0plusplus-cascade + SOURCES candidateCreatorSigmac0plusplusCascade.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(candidate-creator-xic0-omegac0 + SOURCES candidateCreatorXic0Omegac0.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter O2Physics::EventFilteringUtils KFParticle::KFParticle + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(candidate-creator-xic-to-xi-pi-pi + SOURCES candidateCreatorXicToXiPiPi.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(candidate-creator-xicc SOURCES candidateCreatorXicc.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(candidate-creator-mc-gen + SOURCES candidateCreatorMcGen.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + # Candidate selectors o2physics_add_dpl_workflow(candidate-selector-b0-to-d-pi @@ -94,7 +114,7 @@ o2physics_add_dpl_workflow(candidate-selector-b0-to-d-pi o2physics_add_dpl_workflow(candidate-selector-bplus-to-d0-pi SOURCES candidateSelectorBplusToD0Pi.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(candidate-selector-bs-to-ds-pi @@ -142,6 +162,21 @@ o2physics_add_dpl_workflow(candidate-selector-lc-to-k0s-p PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(candidate-selector-omegac0-to-omega-ka + SOURCES candidateSelectorOmegac0ToOmegaKa.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(candidate-selector-omegac0-to-omega-pi + SOURCES candidateSelectorOmegac0ToOmegaPi.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(candidate-selector-xic0-to-xi-pi-kf + SOURCES candidateSelectorXic0ToXiPiKf.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(candidate-selector-to-xi-pi SOURCES candidateSelectorToXiPi.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -152,6 +187,11 @@ o2physics_add_dpl_workflow(candidate-selector-xic-to-p-k-pi PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(candidate-selector-xic-to-xi-pi-pi + SOURCES candidateSelectorXicToXiPiPi.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(candidate-selector-xicc-to-p-k-pi-pi SOURCES candidateSelectorXiccToPKPiPi.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -206,7 +246,17 @@ o2physics_add_dpl_workflow(tree-creator-lc-to-p-k-pi o2physics_add_dpl_workflow(tree-creator-omegac-st SOURCES treeCreatorOmegacSt.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(tree-creator-omegac0-to-omega-ka + SOURCES treeCreatorOmegacToOmegaKa.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(tree-creator-omegac0-to-omega-pi + SOURCES treeCreatorOmegacToOmegaPi.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(tree-creator-to-xi-pi @@ -214,11 +264,21 @@ o2physics_add_dpl_workflow(tree-creator-to-xi-pi PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(tree-creator-xic0-to-xi-pi-kf + SOURCES treeCreatorXic0ToXiPiKf.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(tree-creator-xic-to-p-k-pi SOURCES treeCreatorXicToPKPi.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(tree-creator-xic-to-xi-pi-pi + SOURCES treeCreatorXicToXiPiPi.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(tree-creator-xicc-to-p-k-pi-pi SOURCES treeCreatorXiccToPKPiPi.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -229,14 +289,35 @@ o2physics_add_dpl_workflow(tree-creator-dstar-to-d0-pi PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(tree-creator-tcc-to-d0-d0-pi + SOURCES treeCreatorTccToD0D0Pi.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) # Derived-data creators +o2physics_add_dpl_workflow(derived-data-creator-bplus-to-d0-pi + SOURCES derivedDataCreatorBplusToD0Pi.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(derived-data-creator-d0-to-k-pi SOURCES derivedDataCreatorD0ToKPi.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(derived-data-creator-dplus-to-pi-k-pi + SOURCES derivedDataCreatorDplusToPiKPi.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(derived-data-creator-lc-to-p-k-pi SOURCES derivedDataCreatorLcToPKPi.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +# Converters + +o2physics_add_dpl_workflow(converter-dstar-indices + SOURCES converterDstarIndices.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGHF/TableProducer/candidateCreator2Prong.cxx b/PWGHF/TableProducer/candidateCreator2Prong.cxx index e80fbf366d4..576e5413c11 100644 --- a/PWGHF/TableProducer/candidateCreator2Prong.cxx +++ b/PWGHF/TableProducer/candidateCreator2Prong.cxx @@ -17,9 +17,13 @@ /// \author Pengzhong Lu , GSI Darmstadt, USTC #ifndef HomogeneousField -#define HomogeneousField +#define HomogeneousField // o2-linter: disable=name/macro (required by KFParticle) #endif +#include +#include +#include + #include #include #include @@ -33,37 +37,40 @@ #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" #include "ReconstructionDataFormats/DCA.h" #include "Common/Core/trackUtilities.h" #include "Tools/KFparticle/KFUtilities.h" +#include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" #include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsPid.h" #include "PWGHF/Utils/utilsTrkCandHf.h" +#include "PWGHF/Utils/utilsMcGen.h" using namespace o2; using namespace o2::analysis; using namespace o2::hf_evsel; using namespace o2::hf_trkcandsel; using namespace o2::aod::hf_cand_2prong; -using namespace o2::aod::hf_collision_centrality; +using namespace o2::hf_centrality; +using namespace o2::hf_occupancy; using namespace o2::constants::physics; using namespace o2::framework; +using namespace o2::aod::pid_tpc_tof_utils; /// Reconstruction of heavy-flavour 2-prong decay candidates struct HfCandidateCreator2Prong { Produces rowCandidateBase; + Produces rowProng0PidPi; + Produces rowProng0PidKa; + Produces rowProng1PidPi; + Produces rowProng1PidKa; Produces rowCandidateKF; - // centrality - Configurable centralityMin{"centralityMin", 0., "Minimum centrality"}; - Configurable centralityMax{"centralityMax", 100., "Maximum centrality"}; - // event selection - Configurable useSel8Trigger{"useSel8Trigger", true, "apply the sel8 event selection"}; - Configurable zPvPosMax{"zPvPosMax", 10.f, "max. PV posZ (cm)"}; - Configurable useTimeFrameBorderCut{"useTimeFrameBorderCut", true, "apply TF border cut"}; // vertexing Configurable constrainKfToPv{"constrainKfToPv", true, "constraint KFParticle to PV"}; Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; @@ -77,14 +84,14 @@ struct HfCandidateCreator2Prong { // magnetic field setting from CCDB Configurable isRun2{"isRun2", false, "enable Run 2 or Run 3 GRP objects for magnetic field"}; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + HfEventSelection hfEvSel; // event selection and monitoring o2::vertexing::DCAFitterN<2> df; // 2-prong vertex fitter Service ccdb; - o2::base::MatLayerCylSet* lut; - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + + using TracksWCovExtraPidPiKa = soa::Join; int runNumber{0}; float toMicrometers = 10000.; // from cm to µm @@ -94,7 +101,7 @@ struct HfCandidateCreator2Prong { double massKPi{0.}; double bz{0.}; - std::shared_ptr hCollisions, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel, hCandidates; + std::shared_ptr hCandidates; HistogramRegistry registry{"registry"}; void init(InitContext const&) @@ -139,13 +146,8 @@ struct HfCandidateCreator2Prong { registry.add("hDcaXYProngs", "DCAxy of 2-prong candidate daughters;#it{p}_{T} (GeV/#it{c};#it{d}_{xy}) (#mum);entries", {HistType::kTH2F, {{100, 0., 20.}, {200, -500., 500.}}}); registry.add("hDcaZProngs", "DCAz of 2-prong candidate daughters;#it{p}_{T} (GeV/#it{c};#it{d}_{z}) (#mum);entries", {HistType::kTH2F, {{100, 0., 20.}, {200, -500., 500.}}}); registry.add("hVertexerType", "Use KF or DCAFitterN;Vertexer type;entries", {HistType::kTH1D, {{2, -0.5, 1.5}}}); // See o2::aod::hf_cand::VertexerType - hCollisions = registry.add("hCollisions", "HF event counter;;entries", {HistType::kTH1D, {axisEvents}}); - hPosZBeforeEvSel = registry.add("hPosZBeforeEvSel", "all events;#it{z}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{400, -20., 20.}}}); - hPosZAfterEvSel = registry.add("hPosZAfterEvSel", "selected events;#it{z}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{400, -20., 20.}}}); - hPosXAfterEvSel = registry.add("hPosXAfterEvSel", "selected events;#it{x}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{200, -0.5, 0.5}}}); - hPosYAfterEvSel = registry.add("hPosYAfterEvSel", "selected events;#it{y}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{200, -0.5, 0.5}}}); - hNumPvContributorsAfterSel = registry.add("hNumPvContributorsAfterSel", "selected events;#it{y}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{500, -0.5, 499.5}}}); hCandidates = registry.add("hCandidates", "candidates counter", {HistType::kTH1D, {axisCands}}); + hfEvSel.addHistograms(registry); // collision monitoring massPi = MassPiPlus; massK = MassKPlus; @@ -169,21 +171,17 @@ struct HfCandidateCreator2Prong { ccdb->setURL(ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); runNumber = 0; - /// collision monitoring - setLabelHistoEvSel(hCollisions); - /// candidate monitoring setLabelHistoCands(hCandidates); } - template + template void runCreator2ProngWithDCAFitterN(Coll const&, CandType const& rowsTrackIndexProng2, TTracks const&, - aod::BCsWithTimestamps const&) + aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { // loop over pairs of track indices for (const auto& rowTrackIndexProng2 : rowsTrackIndexProng2) { @@ -191,7 +189,7 @@ struct HfCandidateCreator2Prong { /// reject candidates not satisfying the event selections auto collision = rowTrackIndexProng2.template collision_as(); float centrality{-1.f}; - const auto rejectionMask = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, -1, useTimeFrameBorderCut, -zPvPosMax, zPvPosMax, 0, -1.f); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); if (rejectionMask != 0) { /// at least one event selection not satisfied --> reject the candidate continue; @@ -208,7 +206,7 @@ struct HfCandidateCreator2Prong { auto bc = collision.template bc_as(); if (runNumber != bc.runNumber()) { LOG(info) << ">>>>>>>>>>>> Current run number: " << runNumber; - initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, lut, isRun2); + initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, nullptr, isRun2); bz = o2::base::Propagator::Instance()->getNominalBz(); LOG(info) << ">>>>>>>>>>>> Magnetic field: " << bz; // df.setBz(bz); /// put it outside the 'if'! Otherwise we have a difference wrt bz Configurable (< 1 permille) in Run2 conv. data @@ -223,7 +221,7 @@ struct HfCandidateCreator2Prong { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN cannot work, skipping the candidate."; + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; hCandidates->Fill(SVFitting::Fail); continue; } @@ -285,13 +283,14 @@ struct HfCandidateCreator2Prong { auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); auto indexCollision = collision.globalIndex(); - uint8_t nProngsContributorsPV = 0; + uint8_t bitmapProngsContributorsPV = 0; if (indexCollision == track0.collisionId() && track0.isPVContributor()) { - nProngsContributorsPV += 1; + SETBIT(bitmapProngsContributorsPV, 0); } if (indexCollision == track1.collisionId() && track1.isPVContributor()) { - nProngsContributorsPV += 1; + SETBIT(bitmapProngsContributorsPV, 1); } + uint8_t nProngsContributorsPV = hf_trkcandsel::countOnesInBinary(bitmapProngsContributorsPV); // fill candidate table rows rowCandidateBase(indexCollision, @@ -305,9 +304,15 @@ struct HfCandidateCreator2Prong { std::sqrt(impactParameter0.getSigmaY2()), std::sqrt(impactParameter1.getSigmaY2()), impactParameter0.getZ(), impactParameter1.getZ(), std::sqrt(impactParameter0.getSigmaZ2()), std::sqrt(impactParameter1.getSigmaZ2()), - rowTrackIndexProng2.prong0Id(), rowTrackIndexProng2.prong1Id(), nProngsContributorsPV, + rowTrackIndexProng2.prong0Id(), rowTrackIndexProng2.prong1Id(), nProngsContributorsPV, bitmapProngsContributorsPV, rowTrackIndexProng2.hfflag()); + // fill candidate prong PID rows + fillProngPid(track0, rowProng0PidPi); + fillProngPid(track0, rowProng0PidKa); + fillProngPid(track1, rowProng1PidPi); + fillProngPid(track1, rowProng1PidKa); + // fill histograms if (fillHistograms) { // calculate invariant masses @@ -320,11 +325,11 @@ struct HfCandidateCreator2Prong { } } - template + template void runCreator2ProngWithKFParticle(Coll const&, CandType const& rowsTrackIndexProng2, TTracks const&, - aod::BCsWithTimestamps const&) + aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { for (const auto& rowTrackIndexProng2 : rowsTrackIndexProng2) { @@ -332,7 +337,7 @@ struct HfCandidateCreator2Prong { /// reject candidates in collisions not satisfying the event selections auto collision = rowTrackIndexProng2.template collision_as(); float centrality{-1.f}; - const auto rejectionMask = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, -1, useTimeFrameBorderCut, -zPvPosMax, zPvPosMax, 0, -1.f); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); if (rejectionMask != 0) { /// at least one event selection not satisfied --> reject the candidate continue; @@ -347,7 +352,7 @@ struct HfCandidateCreator2Prong { auto bc = collision.template bc_as(); if (runNumber != bc.runNumber()) { LOG(info) << ">>>>>>>>>>>> Current run number: " << runNumber; - initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, lut, isRun2); + initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, nullptr, isRun2); bz = o2::base::Propagator::Instance()->getNominalBz(); LOG(info) << ">>>>>>>>>>>> Magnetic field: " << bz; // df.setBz(bz); /// put it outside the 'if'! Otherwise we have a difference wrt bz Configurable (< 1 permille) in Run2 conv. data @@ -367,7 +372,7 @@ struct HfCandidateCreator2Prong { kfpVertex.SetCovarianceMatrix(rowTrackIndexProng2.pvRefitSigmaX2(), rowTrackIndexProng2.pvRefitSigmaXY(), rowTrackIndexProng2.pvRefitSigmaY2(), rowTrackIndexProng2.pvRefitSigmaXZ(), rowTrackIndexProng2.pvRefitSigmaYZ(), rowTrackIndexProng2.pvRefitSigmaZ2()); } kfpVertex.GetCovarianceMatrix(covMatrixPV); - KFParticle KFPV(kfpVertex); + KFParticle kfpV(kfpVertex); registry.fill(HIST("hCovPVXX"), covMatrixPV[0]); registry.fill(HIST("hCovPVYY"), covMatrixPV[2]); registry.fill(HIST("hCovPVXZ"), covMatrixPV[3]); @@ -382,16 +387,16 @@ struct HfCandidateCreator2Prong { KFParticle kfNegKaon(kfpTrack1, kKPlus); float impactParameter0XY = 0., errImpactParameter0XY = 0., impactParameter1XY = 0., errImpactParameter1XY = 0.; - if (!kfPosPion.GetDistanceFromVertexXY(KFPV, impactParameter0XY, errImpactParameter0XY)) { + if (!kfPosPion.GetDistanceFromVertexXY(kfpV, impactParameter0XY, errImpactParameter0XY)) { registry.fill(HIST("hDcaXYProngs"), track0.pt(), impactParameter0XY * toMicrometers); - registry.fill(HIST("hDcaZProngs"), track0.pt(), std::sqrt(kfPosPion.GetDistanceFromVertex(KFPV) * kfPosPion.GetDistanceFromVertex(KFPV) - impactParameter0XY * impactParameter0XY) * toMicrometers); + registry.fill(HIST("hDcaZProngs"), track0.pt(), std::sqrt(kfPosPion.GetDistanceFromVertex(kfpV) * kfPosPion.GetDistanceFromVertex(kfpV) - impactParameter0XY * impactParameter0XY) * toMicrometers); } else { registry.fill(HIST("hDcaXYProngs"), track0.pt(), -999.f); registry.fill(HIST("hDcaZProngs"), track0.pt(), -999.f); } - if (!kfNegPion.GetDistanceFromVertexXY(KFPV, impactParameter1XY, errImpactParameter1XY)) { + if (!kfNegPion.GetDistanceFromVertexXY(kfpV, impactParameter1XY, errImpactParameter1XY)) { registry.fill(HIST("hDcaXYProngs"), track1.pt(), impactParameter1XY * toMicrometers); - registry.fill(HIST("hDcaZProngs"), track1.pt(), std::sqrt(kfNegPion.GetDistanceFromVertex(KFPV) * kfNegPion.GetDistanceFromVertex(KFPV) - impactParameter1XY * impactParameter1XY) * toMicrometers); + registry.fill(HIST("hDcaZProngs"), track1.pt(), std::sqrt(kfNegPion.GetDistanceFromVertex(kfpV) * kfNegPion.GetDistanceFromVertex(kfpV) - impactParameter1XY * impactParameter1XY) * toMicrometers); } else { registry.fill(HIST("hDcaXYProngs"), track1.pt(), -999.f); registry.fill(HIST("hDcaZProngs"), track1.pt(), -999.f); @@ -417,7 +422,7 @@ struct HfCandidateCreator2Prong { auto covMatrixSV = kfCandD0.CovarianceMatrix(); double phi, theta; - getPointDirection(std::array{KFPV.GetX(), KFPV.GetY(), KFPV.GetZ()}, std::array{kfCandD0.GetX(), kfCandD0.GetY(), kfCandD0.GetZ()}, phi, theta); + getPointDirection(std::array{kfpV.GetX(), kfpV.GetY(), kfpV.GetZ()}, std::array{kfCandD0.GetX(), kfCandD0.GetY(), kfCandD0.GetZ()}, phi, theta); auto errorDecayLength = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixSV, phi, theta)); auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixSV, phi, 0.)); @@ -425,22 +430,23 @@ struct HfCandidateCreator2Prong { KFParticle kfCandD0Topol2PV; if (constrainKfToPv) { kfCandD0Topol2PV = kfCandD0; - kfCandD0Topol2PV.SetProductionVertex(KFPV); + kfCandD0Topol2PV.SetProductionVertex(kfpV); topolChi2PerNdfD0 = kfCandD0Topol2PV.GetChi2() / kfCandD0Topol2PV.GetNDF(); } auto indexCollision = collision.globalIndex(); - uint8_t nProngsContributorsPV = 0; + uint8_t bitmapProngsContributorsPV = 0; if (indexCollision == track0.collisionId() && track0.isPVContributor()) { - nProngsContributorsPV += 1; + SETBIT(bitmapProngsContributorsPV, 0); } if (indexCollision == track1.collisionId() && track1.isPVContributor()) { - nProngsContributorsPV += 1; + SETBIT(bitmapProngsContributorsPV, 1); } + uint8_t nProngsContributorsPV = hf_trkcandsel::countOnesInBinary(bitmapProngsContributorsPV); // fill candidate table rows rowCandidateBase(indexCollision, - KFPV.GetX(), KFPV.GetY(), KFPV.GetZ(), + kfpV.GetX(), kfpV.GetY(), kfpV.GetZ(), kfCandD0.GetX(), kfCandD0.GetY(), kfCandD0.GetZ(), errorDecayLength, errorDecayLengthXY, // TODO: much different from the DCAFitterN one kfCandD0.GetChi2() / kfCandD0.GetNDF(), // TODO: to make sure it should be chi2 only or chi2/ndf, much different from the DCAFitterN one @@ -450,8 +456,16 @@ struct HfCandidateCreator2Prong { errImpactParameter0XY, errImpactParameter1XY, 0.f, 0.f, 0.f, 0.f, - rowTrackIndexProng2.prong0Id(), rowTrackIndexProng2.prong1Id(), nProngsContributorsPV, + rowTrackIndexProng2.prong0Id(), rowTrackIndexProng2.prong1Id(), nProngsContributorsPV, bitmapProngsContributorsPV, rowTrackIndexProng2.hfflag()); + + // fill candidate prong PID rows + fillProngPid(track0, rowProng0PidPi); + fillProngPid(track0, rowProng0PidKa); + fillProngPid(track1, rowProng1PidPi); + fillProngPid(track1, rowProng1PidKa); + + // fill KF info rowCandidateKF(topolChi2PerNdfD0, massD0, massD0bar); @@ -472,7 +486,7 @@ struct HfCandidateCreator2Prong { /// @brief process function using DCA fitter w/ PV refit and w/o centrality selections void processPvRefitWithDCAFitterN(soa::Join const& collisions, soa::Join const& rowsTrackIndexProng2, - aod::TracksWCovExtra const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator2ProngWithDCAFitterN(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); @@ -482,7 +496,7 @@ struct HfCandidateCreator2Prong { /// @brief process function using DCA fitter w/o PV refit and w/o centrality selections void processNoPvRefitWithDCAFitterN(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexProng2, - aod::TracksWCovExtra const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator2ProngWithDCAFitterN(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); @@ -492,7 +506,7 @@ struct HfCandidateCreator2Prong { /// @brief process function using KFParticle package w/ PV refit and w/o centrality selections void processPvRefitWithKFParticle(soa::Join const& collisions, soa::Join const& rowsTrackIndexProng2, - aod::TracksWCovExtra const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator2ProngWithKFParticle(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); @@ -502,7 +516,7 @@ struct HfCandidateCreator2Prong { /// @brief process function using KFParticle package w/o PV refit and w/o centrality selections void processNoPvRefitWithKFParticle(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexProng2, - aod::TracksWCovExtra const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator2ProngWithKFParticle(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); @@ -518,7 +532,7 @@ struct HfCandidateCreator2Prong { /// @brief process function using DCA fitter w/ PV refit and w/ centrality selection on FT0C void processPvRefitWithDCAFitterNCentFT0C(soa::Join const& collisions, soa::Join const& rowsTrackIndexProng2, - aod::TracksWCovExtra const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator2ProngWithDCAFitterN(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); @@ -528,7 +542,7 @@ struct HfCandidateCreator2Prong { /// @brief process function using DCA fitter w/o PV refit and w/ centrality selection FT0C void processNoPvRefitWithDCAFitterNCentFT0C(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexProng2, - aod::TracksWCovExtra const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator2ProngWithDCAFitterN(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); @@ -538,7 +552,7 @@ struct HfCandidateCreator2Prong { /// @brief process function using KFParticle package w/ PV refit and w/ centrality selection on FT0C void processPvRefitWithKFParticleCentFT0C(soa::Join const& collisions, soa::Join const& rowsTrackIndexProng2, - aod::TracksWCovExtra const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator2ProngWithKFParticle(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); @@ -548,7 +562,7 @@ struct HfCandidateCreator2Prong { /// @brief process function using KFParticle package w/o PV refit and w/o centrality selections void processNoPvRefitWithKFParticleCentFT0C(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexProng2, - aod::TracksWCovExtra const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator2ProngWithKFParticle(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); @@ -564,7 +578,7 @@ struct HfCandidateCreator2Prong { /// @brief process function using DCA fitter w/ PV refit and w/ centrality selection on FT0M void processPvRefitWithDCAFitterNCentFT0M(soa::Join const& collisions, soa::Join const& rowsTrackIndexProng2, - aod::TracksWCovExtra const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator2ProngWithDCAFitterN(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); @@ -574,7 +588,7 @@ struct HfCandidateCreator2Prong { /// @brief process function using DCA fitter w/o PV refit and w/ centrality selection FT0M void processNoPvRefitWithDCAFitterNCentFT0M(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexProng2, - aod::TracksWCovExtra const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator2ProngWithDCAFitterN(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); @@ -584,7 +598,7 @@ struct HfCandidateCreator2Prong { /// @brief process function using KFParticle package w/ PV refit and w/ centrality selection on FT0M void processPvRefitWithKFParticleCentFT0M(soa::Join const& collisions, soa::Join const& rowsTrackIndexProng2, - aod::TracksWCovExtra const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator2ProngWithKFParticle(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); @@ -594,7 +608,7 @@ struct HfCandidateCreator2Prong { /// @brief process function using KFParticle package w/o PV refit and w/o centrality selections void processNoPvRefitWithKFParticleCentFT0M(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexProng2, - aod::TracksWCovExtra const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator2ProngWithKFParticle(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); @@ -608,51 +622,54 @@ struct HfCandidateCreator2Prong { /////////////////////////////////////////////////////////// /// @brief process function to monitor collisions - no centrality - void processCollisions(soa::Join const& collisions) + void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { /// bitmask with event. selection info float centrality{-1.f}; - const auto rejectionMask = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, -1, useTimeFrameBorderCut, -zPvPosMax, zPvPosMax, 0, -1.f); + float occupancy = getOccupancyColl(collision, OccupancyEstimator::Its); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); /// monitor the satisfied event selections - monitorCollision(collision, rejectionMask, hCollisions, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy); } /// end loop over collisions } PROCESS_SWITCH(HfCandidateCreator2Prong, processCollisions, "Collision monitoring - no centrality", true); /// @brief process function to monitor collisions - FT0C centrality - void processCollisionsCentFT0C(soa::Join const& collisions) + void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { /// bitmask with event. selection info float centrality{-1.f}; - const auto rejectionMask = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, -1, useTimeFrameBorderCut, -zPvPosMax, zPvPosMax, 0, -1.f); + float occupancy = getOccupancyColl(collision, OccupancyEstimator::Its); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); /// monitor the satisfied event selections - monitorCollision(collision, rejectionMask, hCollisions, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy); } /// end loop over collisions } PROCESS_SWITCH(HfCandidateCreator2Prong, processCollisionsCentFT0C, "Collision monitoring - FT0C centrality", false); /// @brief process function to monitor collisions - FT0M centrality - void processCollisionsCentFT0M(soa::Join const& collisions) + void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { /// bitmask with event. selection info float centrality{-1.f}; - const auto rejectionMask = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, -1, useTimeFrameBorderCut, -zPvPosMax, zPvPosMax, 0, -1.f); + float occupancy = getOccupancyColl(collision, OccupancyEstimator::Its); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); /// monitor the satisfied event selections - monitorCollision(collision, rejectionMask, hCollisions, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy); } /// end loop over collisions } @@ -665,11 +682,51 @@ struct HfCandidateCreator2ProngExpressions { Produces rowMcMatchRec; Produces rowMcMatchGen; - void init(InitContext const&) {} + // Configuration + Configurable rejectBackground{"rejectBackground", true, "Reject particles from background events"}; + Configurable matchKinkedDecayTopology{"matchKinkedDecayTopology", false, "Match also candidates with tracks that decay with kinked topology"}; + Configurable matchInteractionsWithMaterial{"matchInteractionsWithMaterial", false, "Match also candidates with tracks that interact with material"}; + + HfEventSelectionMc hfEvSelMc; // mc event selection and monitoring + + using McCollisionsNoCents = soa::Join; + using McCollisionsFT0Cs = soa::Join; + using McCollisionsFT0Ms = soa::Join; + using McCollisionsCentFT0Ms = soa::Join; + using BCsInfo = soa::Join; + + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + PresliceUnsorted colPerMcCollisionFT0C = aod::mccollisionlabel::mcCollisionId; + PresliceUnsorted colPerMcCollisionFT0M = aod::mccollisionlabel::mcCollisionId; + + HistogramRegistry registry{"registry"}; + + // inspect for which zPvPosMax cut was set for reconstructed + void init(InitContext& initContext) + { + std::array procCollisions = {doprocessMc, doprocessMcCentFT0C, doprocessMcCentFT0M}; + if (std::accumulate(procCollisions.begin(), procCollisions.end(), 0) > 1) { + LOGP(fatal, "At most one process function for collision study can be enabled at a time."); + } + + const auto& workflows = initContext.services().get(); + for (const DeviceSpec& device : workflows.devices) { + if (device.name.compare("hf-candidate-creator-2prong") == 0) { + hfEvSelMc.configureFromDevice(device); + break; + } + } + hfEvSelMc.addHistograms(registry); // particles monitoring + } /// Performs MC matching. - void processMc(aod::TracksWMc const& tracks, - aod::McParticles const& mcParticles) + template + void runCreator2ProngMc(aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles, + CCs const& collInfos, + McCollisions const& mcCollisions, + BCsInfo const&) { rowCandidateProng2->bindExternalIndices(&tracks); @@ -677,6 +734,8 @@ struct HfCandidateCreator2ProngExpressions { int8_t sign = 0; int8_t flag = 0; int8_t origin = 0; + int8_t nKinkedTracks = 0; + int8_t nInteractionsWithMaterial = 0; // Match reconstructed candidates. // Spawned table can be used directly @@ -685,15 +744,46 @@ struct HfCandidateCreator2ProngExpressions { origin = 0; auto arrayDaughters = std::array{candidate.prong0_as(), candidate.prong1_as()}; + // Check whether the particle is from background events. If so, reject it. + if (rejectBackground) { + bool fromBkg{false}; + for (const auto& daughter : arrayDaughters) { + if (daughter.has_mcParticle()) { + auto mcParticle = daughter.mcParticle(); + if (mcParticle.fromBackgroundEvent()) { + fromBkg = true; + break; + } + } + } + if (fromBkg) { + rowMcMatchRec(flag, origin, -1.f, 0, 0, 0); + continue; + } + } + std::vector idxBhadMothers{}; + // D0(bar) → π± K∓ - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign); + if (matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign, 1, &nKinkedTracks, &nInteractionsWithMaterial); + } else if (matchKinkedDecayTopology && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign, 1, &nKinkedTracks); + } else if (!matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign, 1, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign); + } if (indexRec > -1) { flag = sign * (1 << DecayType::D0ToPiK); } // J/ψ → e+ e− if (flag == 0) { - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kJPsi, std::array{+kElectron, -kElectron}, true); + if (matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kJPsi, std::array{+kElectron, -kElectron}, true, &sign, 1, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kJPsi, std::array{+kElectron, -kElectron}, true); + } if (indexRec > -1) { flag = 1 << DecayType::JpsiToEE; } @@ -701,7 +791,11 @@ struct HfCandidateCreator2ProngExpressions { // J/ψ → μ+ μ− if (flag == 0) { - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kJPsi, std::array{+kMuonPlus, -kMuonPlus}, true); + if (matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kJPsi, std::array{+kMuonPlus, -kMuonPlus}, true, &sign, 1, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kJPsi, std::array{+kMuonPlus, -kMuonPlus}, true); + } if (indexRec > -1) { flag = 1 << DecayType::JpsiToMuMu; } @@ -710,51 +804,81 @@ struct HfCandidateCreator2ProngExpressions { // Check whether the particle is non-prompt (from a b quark). if (flag != 0) { auto particle = mcParticles.rawIteratorAt(indexRec); - origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle); + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + } + if (origin == RecoDecay::OriginType::NonPrompt) { + auto bHadMother = mcParticles.rawIteratorAt(idxBhadMothers[0]); + rowMcMatchRec(flag, origin, bHadMother.pt(), bHadMother.pdgCode(), nKinkedTracks, nInteractionsWithMaterial); + } else { + rowMcMatchRec(flag, origin, -1.f, 0, nKinkedTracks, nInteractionsWithMaterial); } - - rowMcMatchRec(flag, origin); } - // Match generated particles. - for (const auto& particle : mcParticles) { - flag = 0; - origin = 0; - - // D0(bar) → π± K∓ - if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign)) { - flag = sign * (1 << DecayType::D0ToPiK); - } + for (const auto& mcCollision : mcCollisions) { - // J/ψ → e+ e− - if (flag == 0) { - if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kJPsi, std::array{+kElectron, -kElectron}, true)) { - flag = 1 << DecayType::JpsiToEE; - } + // Slice the particles table to get the particles for the current MC collision + const auto mcParticlesPerMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, mcCollision.globalIndex()); + // Slice the collisions table to get the collision info for the current MC collision + float centrality{-1.f}; + uint16_t rejectionMask{0}; + int nSplitColl = 0; + if constexpr (centEstimator == CentralityEstimator::FT0C) { + const auto collSlice = collInfos.sliceBy(colPerMcCollisionFT0C, mcCollision.globalIndex()); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } else if constexpr (centEstimator == CentralityEstimator::FT0M) { + const auto collSlice = collInfos.sliceBy(colPerMcCollisionFT0M, mcCollision.globalIndex()); + nSplitColl = collSlice.size(); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } else if constexpr (centEstimator == CentralityEstimator::None) { + const auto collSlice = collInfos.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); } - - // J/ψ → μ+ μ− - if (flag == 0) { - if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kJPsi, std::array{+kMuonPlus, -kMuonPlus}, true)) { - flag = 1 << DecayType::JpsiToMuMu; + hfEvSelMc.fillHistograms(mcCollision, rejectionMask, nSplitColl); + if (rejectionMask != 0) { + // at least one event selection not satisfied --> reject all particles from this collision + for (unsigned int i = 0; i < mcParticlesPerMcColl.size(); ++i) { + rowMcMatchGen(0, 0, -1); } + continue; } + hf_mc_gen::fillMcMatchGen2Prong(mcParticles, mcParticlesPerMcColl, rowMcMatchGen, rejectBackground); + } + } - // Check whether the particle is non-prompt (from a b quark). - if (flag != 0) { - origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle); - } + void processMc(aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions, + BCsInfo const& BCsInfo) + { + runCreator2ProngMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + } + PROCESS_SWITCH(HfCandidateCreator2ProngExpressions, processMc, "Process MC - no centrality", false); - rowMcMatchGen(flag, origin); - } + void processMcCentFT0C(aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisionsFT0Cs const& collInfos, + aod::McCollisions const& mcCollisions, + BCsInfo const& BCsInfo) + { + runCreator2ProngMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); } + PROCESS_SWITCH(HfCandidateCreator2ProngExpressions, processMcCentFT0C, "Process MC - FT0c centrality", false); - PROCESS_SWITCH(HfCandidateCreator2ProngExpressions, processMc, "Process MC", false); + void processMcCentFT0M(aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisionsFT0Ms const& collInfos, + McCollisionsCentFT0Ms const& mcCollisions, + BCsInfo const& BCsInfo) + { + runCreator2ProngMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + } + PROCESS_SWITCH(HfCandidateCreator2ProngExpressions, processMcCentFT0M, "Process MC - FT0m centrality", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"hf-candidate-creator-2prong"}), - adaptAnalysisTask(cfgc, TaskName{"hf-candidate-creator-2prong-expressions"})}; + adaptAnalysisTask(cfgc, TaskName{"hf-candidate-creator-2prong"}), // o2-linter: disable=name/o2-task (wrong hyphenation) + adaptAnalysisTask(cfgc, TaskName{"hf-candidate-creator-2prong-expressions"})}; // o2-linter: disable=name/o2-task (wrong hyphenation) } diff --git a/PWGHF/TableProducer/candidateCreator3Prong.cxx b/PWGHF/TableProducer/candidateCreator3Prong.cxx index d14b3a8f46f..24d9496630c 100644 --- a/PWGHF/TableProducer/candidateCreator3Prong.cxx +++ b/PWGHF/TableProducer/candidateCreator3Prong.cxx @@ -15,6 +15,21 @@ /// /// \author Vít Kučera , CERN +#ifndef HomogeneousField +#define HomogeneousField // o2-linter: disable=name/macro (required by KFParticle) +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + #include #include "CommonConstants/PhysicsConstants.h" @@ -26,18 +41,22 @@ #include "ReconstructionDataFormats/DCA.h" #include "Common/Core/trackUtilities.h" +#include "Tools/KFparticle/KFUtilities.h" +#include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" #include "PWGHF/Utils/utilsEvSelHf.h" #include "PWGHF/Utils/utilsTrkCandHf.h" +#include "PWGHF/Utils/utilsMcGen.h" using namespace o2; using namespace o2::analysis; using namespace o2::hf_evsel; using namespace o2::hf_trkcandsel; using namespace o2::aod::hf_cand_3prong; -using namespace o2::aod::hf_collision_centrality; +using namespace o2::hf_centrality; +using namespace o2::hf_occupancy; using namespace o2::constants::physics; using namespace o2::framework; using namespace o2::framework::expressions; @@ -45,14 +64,8 @@ using namespace o2::framework::expressions; /// Reconstruction of heavy-flavour 3-prong decay candidates struct HfCandidateCreator3Prong { Produces rowCandidateBase; + Produces rowCandidateKF; - // centrality - Configurable centralityMin{"centralityMin", 0., "Minimum centrality"}; - Configurable centralityMax{"centralityMax", 100., "Maximum centrality"}; - // event selection - Configurable useSel8Trigger{"useSel8Trigger", true, "apply the sel8 event selection"}; - Configurable zPvPosMax{"zPvPosMax", 10.f, "max. PV posZ (cm)"}; - Configurable useTimeFrameBorderCut{"useTimeFrameBorderCut", true, "apply TF border cut"}; // vertexing Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; Configurable useAbsDCA{"useAbsDCA", false, "Minimise abs. distance rather than chi2"}; @@ -65,7 +78,6 @@ struct HfCandidateCreator3Prong { // magnetic field setting from CCDB Configurable isRun2{"isRun2", false, "enable Run 2 or Run 3 GRP objects for magnetic field"}; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; // flags to enable creation for different particle species separately @@ -74,33 +86,44 @@ struct HfCandidateCreator3Prong { Configurable createLc{"createLc", false, "enable Lc+/- candidate creation"}; Configurable createXic{"createXic", false, "enable Xic+/- candidate creation"}; + HfEventSelection hfEvSel; // event selection and monitoring o2::vertexing::DCAFitterN<3> df; // 3-prong vertex fitter Service ccdb; - o2::base::MatLayerCylSet* lut; - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; int runNumber{0}; float toMicrometers = 10000.; // from cm to µm + double massP{0.}; double massPi{0.}; double massK{0.}; + double massPKPi{0.}; + double massPiKP{0.}; double massPiKPi{0.}; + double massKKPi{0.}; + double massPiKK{0.}; + double massKPi{0.}; + double massPiK{0.}; double bz{0.}; + constexpr static float UndefValueFloat{-999.f}; + using FilteredHf3Prongs = soa::Filtered; using FilteredPvRefitHf3Prongs = soa::Filtered>; // filter candidates Filter filterSelected3Prongs = (createDplus && (o2::aod::hf_track_index::hfflag & static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi))) != static_cast(0)) || (createDs && (o2::aod::hf_track_index::hfflag & static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi))) != static_cast(0)) || (createLc && (o2::aod::hf_track_index::hfflag & static_cast(BIT(aod::hf_cand_3prong::DecayType::LcToPKPi))) != static_cast(0)) || (createXic && (o2::aod::hf_track_index::hfflag & static_cast(BIT(aod::hf_cand_3prong::DecayType::XicToPKPi))) != static_cast(0)); - std::shared_ptr hCollisions, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel, hCandidates; + std::shared_ptr hCandidates; HistogramRegistry registry{"registry"}; void init(InitContext const&) { - std::array processes = {doprocessPvRefit, doprocessNoPvRefit, - doprocessPvRefitCentFT0C, doprocessNoPvRefitCentFT0C, - doprocessPvRefitCentFT0M, doprocessNoPvRefitCentFT0M}; - if (std::accumulate(processes.begin(), processes.end(), 0) != 1) { + std::array doprocessDF{doprocessPvRefitWithDCAFitterN, doprocessNoPvRefitWithDCAFitterN, + doprocessPvRefitWithDCAFitterNCentFT0C, doprocessNoPvRefitWithDCAFitterNCentFT0C, + doprocessPvRefitWithDCAFitterNCentFT0M, doprocessNoPvRefitWithDCAFitterNCentFT0M}; + std::array doprocessKF{doprocessPvRefitWithKFParticle, doprocessNoPvRefitWithKFParticle, + doprocessPvRefitWithKFParticleCentFT0C, doprocessNoPvRefitWithKFParticleCentFT0C, + doprocessPvRefitWithKFParticleCentFT0M, doprocessNoPvRefitWithKFParticleCentFT0M}; + if ((std::accumulate(doprocessDF.begin(), doprocessDF.end(), 0) + std::accumulate(doprocessKF.begin(), doprocessKF.end(), 0)) != 1) { LOGP(fatal, "One and only one process function must be enabled at a time."); } @@ -110,13 +133,13 @@ struct HfCandidateCreator3Prong { LOGP(fatal, "At most one process function for collision monitoring can be enabled at a time."); } if (nProcessesCollisions == 1) { - if ((doprocessPvRefit || doprocessNoPvRefit) && !doprocessCollisions) { + if ((doprocessPvRefitWithDCAFitterN || doprocessNoPvRefitWithDCAFitterN || doprocessPvRefitWithKFParticle || doprocessNoPvRefitWithKFParticle) && !doprocessCollisions) { LOGP(fatal, "Process function for collision monitoring not correctly enabled. Did you enable \"processCollisions\"?"); } - if ((doprocessPvRefitCentFT0C || doprocessNoPvRefitCentFT0C) && !doprocessCollisionsCentFT0C) { + if ((doprocessPvRefitWithDCAFitterNCentFT0C || doprocessNoPvRefitWithDCAFitterNCentFT0C || doprocessPvRefitWithKFParticleCentFT0C || doprocessNoPvRefitWithKFParticleCentFT0C) && !doprocessCollisionsCentFT0C) { LOGP(fatal, "Process function for collision monitoring not correctly enabled. Did you enable \"processCollisionsCentFT0C\"?"); } - if ((doprocessPvRefitCentFT0M || doprocessNoPvRefitCentFT0M) && !doprocessCollisionsCentFT0M) { + if ((doprocessPvRefitWithDCAFitterNCentFT0M || doprocessNoPvRefitWithDCAFitterNCentFT0M || doprocessPvRefitWithKFParticleCentFT0M || doprocessNoPvRefitWithKFParticleCentFT0M) && !doprocessCollisionsCentFT0M) { LOGP(fatal, "Process function for collision monitoring not correctly enabled. Did you enable \"processCollisionsCentFT0M\"?"); } } @@ -127,7 +150,13 @@ struct HfCandidateCreator3Prong { } // histograms - registry.add("hMass3", "3-prong candidates;inv. mass (#pi K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 1.6, 2.1}}}); + registry.add("hMass3PKPi", "3-prong candidates;inv. mass (pK#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{1200, 1.8, 3.0}}}); + registry.add("hMass3PiKP", "3-prong candidates;inv. mass (#pi Kp) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{1200, 1.8, 3.0}}}); + registry.add("hMass3PiKPi", "3-prong candidates;inv. mass (#pi K#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{600, 1.6, 2.2}}}); + registry.add("hMass3KKPi", "3-prong candidates;inv. mass (KK #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{600, 1.7, 2.3}}}); + registry.add("hMass3PiKK", "3-prong candidates;inv. mass (#pi KK) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{600, 1.7, 2.3}}}); + registry.add("hMass2KPi", "2-prong pairs;inv. mass (K#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{1200, 0.8, 2.0}}}); + registry.add("hMass2PiK", "2-prong pairs;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{1200, 0.8, 2.0}}}); registry.add("hCovPVXX", "3-prong candidates;XX element of cov. matrix of prim. vtx. position (cm^{2});entries", {HistType::kTH1F, {{100, 0., 1.e-4}}}); registry.add("hCovSVXX", "3-prong candidates;XX element of cov. matrix of sec. vtx. position (cm^{2});entries", {HistType::kTH1F, {{100, 0., 0.2}}}); registry.add("hCovPVYY", "3-prong candidates;YY element of cov. matrix of prim. vtx. position (cm^{2});entries", {HistType::kTH1F, {{100, 0., 1.e-4}}}); @@ -138,14 +167,10 @@ struct HfCandidateCreator3Prong { registry.add("hCovSVZZ", "3-prong candidates;ZZ element of cov. matrix of sec. vtx. position (cm^{2});entries", {HistType::kTH1F, {{100, 0., 0.2}}}); registry.add("hDcaXYProngs", "DCAxy of 3-prong candidate daughters;#it{p}_{T} (GeV/#it{c};#it{d}_{xy}) (#mum);entries", {HistType::kTH2F, {{100, 0., 20.}, {200, -500., 500.}}}); registry.add("hDcaZProngs", "DCAz of 3-prong candidate daughters;#it{p}_{T} (GeV/#it{c};#it{d}_{z}) (#mum);entries", {HistType::kTH2F, {{100, 0., 20.}, {200, -500., 500.}}}); - hCollisions = registry.add("hCollisions", "HF event counter;;entries", {HistType::kTH1D, {axisEvents}}); - hPosZBeforeEvSel = registry.add("hPosZBeforeEvSel", "all events;#it{z}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{400, -20., 20.}}}); - hPosZAfterEvSel = registry.add("hPosZAfterEvSel", "selected events;#it{z}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{400, -20., 20.}}}); - hPosXAfterEvSel = registry.add("hPosXAfterEvSel", "selected events;#it{x}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{200, -0.5, 0.5}}}); - hPosYAfterEvSel = registry.add("hPosYAfterEvSel", "selected events;#it{y}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{200, -0.5, 0.5}}}); - hNumPvContributorsAfterSel = registry.add("hNumPvContributorsAfterSel", "selected events;#it{y}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{500, -0.5, 499.5}}}); hCandidates = registry.add("hCandidates", "candidates counter", {HistType::kTH1D, {axisCands}}); + hfEvSel.addHistograms(registry); // collision monitoring + massP = MassProton; massPi = MassPiPlus; massK = MassKPlus; @@ -162,21 +187,17 @@ struct HfCandidateCreator3Prong { ccdb->setURL(ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); runNumber = 0; - /// collision monitoring - setLabelHistoEvSel(hCollisions); - /// candidate monitoring setLabelHistoCands(hCandidates); } - template - void runCreator3Prong(Coll const&, - Cand const& rowsTrackIndexProng3, - aod::TracksWCovExtra const&, - aod::BCsWithTimestamps const&) + template + void runCreator3ProngWithDCAFitterN(Coll const&, + Cand const& rowsTrackIndexProng3, + aod::TracksWCovExtra const&, + aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { // loop over triplets of track indices for (const auto& rowTrackIndexProng3 : rowsTrackIndexProng3) { @@ -184,7 +205,7 @@ struct HfCandidateCreator3Prong { /// reject candidates in collisions not satisfying the event selections auto collision = rowTrackIndexProng3.template collision_as(); float centrality{-1.f}; - const auto rejectionMask = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, -1, useTimeFrameBorderCut, -zPvPosMax, zPvPosMax, 0, -1.f); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); if (rejectionMask != 0) { /// at least one event selection not satisfied --> reject the candidate continue; @@ -203,7 +224,7 @@ struct HfCandidateCreator3Prong { auto bc = collision.template bc_as(); if (runNumber != bc.runNumber()) { LOG(info) << ">>>>>>>>>>>> Current run number: " << runNumber; - initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, lut, isRun2); + initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, nullptr, isRun2); bz = o2::base::Propagator::Instance()->getNominalBz(); LOG(info) << ">>>>>>>>>>>> Magnetic field: " << bz; // df.setBz(bz); /// put it outside the 'if'! Otherwise we have a difference wrt bz Configurable (< 1 permille) in Run2 conv. data @@ -218,7 +239,7 @@ struct HfCandidateCreator3Prong { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN cannot work, skipping the candidate."; + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; hCandidates->Fill(SVFitting::Fail); continue; } @@ -287,16 +308,17 @@ struct HfCandidateCreator3Prong { auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); auto indexCollision = collision.globalIndex(); - uint8_t nProngsContributorsPV = 0; + uint8_t bitmapProngsContributorsPV = 0; if (indexCollision == track0.collisionId() && track0.isPVContributor()) { - nProngsContributorsPV += 1; + SETBIT(bitmapProngsContributorsPV, 0); } if (indexCollision == track1.collisionId() && track1.isPVContributor()) { - nProngsContributorsPV += 1; + SETBIT(bitmapProngsContributorsPV, 1); } if (indexCollision == track2.collisionId() && track2.isPVContributor()) { - nProngsContributorsPV += 1; + SETBIT(bitmapProngsContributorsPV, 2); } + uint8_t nProngsContributorsPV = hf_trkcandsel::countOnesInBinary(bitmapProngsContributorsPV); // fill candidate table rows rowCandidateBase(indexCollision, @@ -311,15 +333,246 @@ struct HfCandidateCreator3Prong { std::sqrt(impactParameter0.getSigmaY2()), std::sqrt(impactParameter1.getSigmaY2()), std::sqrt(impactParameter2.getSigmaY2()), impactParameter0.getZ(), impactParameter1.getZ(), impactParameter2.getZ(), std::sqrt(impactParameter0.getSigmaZ2()), std::sqrt(impactParameter1.getSigmaZ2()), std::sqrt(impactParameter2.getSigmaZ2()), - rowTrackIndexProng3.prong0Id(), rowTrackIndexProng3.prong1Id(), rowTrackIndexProng3.prong2Id(), nProngsContributorsPV, + rowTrackIndexProng3.prong0Id(), rowTrackIndexProng3.prong1Id(), rowTrackIndexProng3.prong2Id(), nProngsContributorsPV, bitmapProngsContributorsPV, rowTrackIndexProng3.hfflag()); // fill histograms if (fillHistograms) { // calculate invariant mass auto arrayMomenta = std::array{pvec0, pvec1, pvec2}; - massPiKPi = RecoDecay::m(std::move(arrayMomenta), std::array{massPi, massK, massPi}); - registry.fill(HIST("hMass3"), massPiKPi); + massPKPi = RecoDecay::m(arrayMomenta, std::array{massP, massK, massPi}); + massPiKP = RecoDecay::m(arrayMomenta, std::array{massPi, massK, massP}); + massPiKPi = RecoDecay::m(arrayMomenta, std::array{massPi, massK, massPi}); + massKKPi = RecoDecay::m(arrayMomenta, std::array{massK, massK, massPi}); + massPiKK = RecoDecay::m(arrayMomenta, std::array{massPi, massK, massK}); + massKPi = RecoDecay::m(std::array{arrayMomenta.at(1), arrayMomenta.at(2)}, std::array{massK, massPi}); + massPiK = RecoDecay::m(std::array{arrayMomenta.at(0), arrayMomenta.at(1)}, std::array{massPi, massK}); + registry.fill(HIST("hMass3PiKPi"), massPiKPi); + registry.fill(HIST("hMass3PKPi"), massPKPi); + registry.fill(HIST("hMass3PiKP"), massPiKP); + registry.fill(HIST("hMass3KKPi"), massKKPi); + registry.fill(HIST("hMass3PiKK"), massPiKK); + registry.fill(HIST("hMass2KPi"), massKPi); + registry.fill(HIST("hMass2PiK"), massPiK); + } + } + } + + template + void runCreator3ProngWithKFParticle(Coll const&, + Cand const& rowsTrackIndexProng3, + aod::TracksWCovExtra const&, + aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + { + for (const auto& rowTrackIndexProng3 : rowsTrackIndexProng3) { + /// reject candidates in collisions not satisfying the event selections + auto collision = rowTrackIndexProng3.template collision_as(); + float centrality{-1.f}; + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + if (rejectionMask != 0) { + /// at least one event selection not satisfied --> reject the candidate + continue; + } + + auto track0 = rowTrackIndexProng3.template prong0_as(); + auto track1 = rowTrackIndexProng3.template prong1_as(); + auto track2 = rowTrackIndexProng3.template prong2_as(); + + /// Set the magnetic field from ccdb. + /// The static instance of the propagator was already modified in the HFTrackIndexSkimCreator, + /// but this is not true when running on Run2 data/MC already converted into AO2Ds. + auto bc = collision.template bc_as(); + if (runNumber != bc.runNumber()) { + LOG(info) << ">>>>>>>>>>>> Current run number: " << runNumber; + initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, nullptr, isRun2); + bz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << ">>>>>>>>>>>> Magnetic field: " << bz; + // df.setBz(bz); /// put it outside the 'if'! Otherwise we have a difference wrt bz Configurable (< 1 permille) in Run2 conv. data + // df.print(); + } + float covMatrixPV[6]; + + KFParticle::SetField(bz); + KFPVertex kfpVertex = createKFPVertexFromCollision(collision); + + if constexpr (doPvRefit) { + /// use PV refit + /// Using it in the rowCandidateBase all dynamic columns shall take it into account + // coordinates + kfpVertex.SetXYZ(rowTrackIndexProng3.pvRefitX(), rowTrackIndexProng3.pvRefitY(), rowTrackIndexProng3.pvRefitZ()); + // covariance matrix + kfpVertex.SetCovarianceMatrix(rowTrackIndexProng3.pvRefitSigmaX2(), rowTrackIndexProng3.pvRefitSigmaXY(), rowTrackIndexProng3.pvRefitSigmaY2(), rowTrackIndexProng3.pvRefitSigmaXZ(), rowTrackIndexProng3.pvRefitSigmaYZ(), rowTrackIndexProng3.pvRefitSigmaZ2()); + } + kfpVertex.GetCovarianceMatrix(covMatrixPV); + KFParticle kfpV(kfpVertex); + registry.fill(HIST("hCovPVXX"), covMatrixPV[0]); + registry.fill(HIST("hCovPVYY"), covMatrixPV[2]); + registry.fill(HIST("hCovPVXZ"), covMatrixPV[3]); + registry.fill(HIST("hCovPVZZ"), covMatrixPV[5]); + + KFPTrack kfpTrack0 = createKFPTrackFromTrack(track0); + KFPTrack kfpTrack1 = createKFPTrackFromTrack(track1); + KFPTrack kfpTrack2 = createKFPTrackFromTrack(track2); + + KFParticle kfFirstProton(kfpTrack0, kProton); + KFParticle kfFirstPion(kfpTrack0, kPiPlus); + KFParticle kfFirstKaon(kfpTrack0, kKPlus); + KFParticle kfSecondKaon(kfpTrack1, kKPlus); + KFParticle kfThirdProton(kfpTrack2, kProton); + KFParticle kfThirdPion(kfpTrack2, kPiPlus); + KFParticle kfThirdKaon(kfpTrack2, kKPlus); + + float impactParameter0XY = 0., errImpactParameter0XY = 0., impactParameter1XY = 0., errImpactParameter1XY = 0., impactParameter2XY = 0., errImpactParameter2XY = 0.; + if (!kfFirstProton.GetDistanceFromVertexXY(kfpV, impactParameter0XY, errImpactParameter0XY)) { + registry.fill(HIST("hDcaXYProngs"), track0.pt(), impactParameter0XY * toMicrometers); + registry.fill(HIST("hDcaZProngs"), track0.pt(), std::sqrt(kfFirstProton.GetDistanceFromVertex(kfpV) * kfFirstProton.GetDistanceFromVertex(kfpV) - impactParameter0XY * impactParameter0XY) * toMicrometers); + } else { + registry.fill(HIST("hDcaXYProngs"), track0.pt(), UndefValueFloat); + registry.fill(HIST("hDcaZProngs"), track0.pt(), UndefValueFloat); + } + if (!kfSecondKaon.GetDistanceFromVertexXY(kfpV, impactParameter1XY, errImpactParameter1XY)) { + registry.fill(HIST("hDcaXYProngs"), track1.pt(), impactParameter1XY * toMicrometers); + registry.fill(HIST("hDcaZProngs"), track1.pt(), std::sqrt(kfSecondKaon.GetDistanceFromVertex(kfpV) * kfSecondKaon.GetDistanceFromVertex(kfpV) - impactParameter1XY * impactParameter1XY) * toMicrometers); + } else { + registry.fill(HIST("hDcaXYProngs"), track1.pt(), UndefValueFloat); + registry.fill(HIST("hDcaZProngs"), track1.pt(), UndefValueFloat); + } + if (!kfThirdProton.GetDistanceFromVertexXY(kfpV, impactParameter2XY, errImpactParameter2XY)) { + registry.fill(HIST("hDcaXYProngs"), track2.pt(), impactParameter2XY * toMicrometers); + registry.fill(HIST("hDcaZProngs"), track2.pt(), std::sqrt(kfThirdProton.GetDistanceFromVertex(kfpV) * kfThirdProton.GetDistanceFromVertex(kfpV) - impactParameter2XY * impactParameter2XY) * toMicrometers); + } else { + registry.fill(HIST("hDcaXYProngs"), track2.pt(), UndefValueFloat); + registry.fill(HIST("hDcaZProngs"), track2.pt(), UndefValueFloat); + } + + auto [impactParameter0Z, errImpactParameter0Z] = kfCalculateImpactParameterZ(kfFirstProton, kfpV); + auto [impactParameter1Z, errImpactParameter1Z] = kfCalculateImpactParameterZ(kfSecondKaon, kfpV); + auto [impactParameter2Z, errImpactParameter2Z] = kfCalculateImpactParameterZ(kfThirdProton, kfpV); + + const float chi2primFirst = kfCalculateChi2ToPrimaryVertex(kfFirstProton, kfpV); + const float chi2primSecond = kfCalculateChi2ToPrimaryVertex(kfSecondKaon, kfpV); + const float chi2primThird = kfCalculateChi2ToPrimaryVertex(kfThirdPion, kfpV); + + const float dcaSecondThird = kfCalculateDistanceBetweenParticles(kfSecondKaon, kfThirdPion); + const float dcaFirstThird = kfCalculateDistanceBetweenParticles(kfFirstProton, kfThirdPion); + const float dcaFirstSecond = kfCalculateDistanceBetweenParticles(kfFirstProton, kfSecondKaon); + + const float chi2geoSecondThird = kfCalculateChi2geoBetweenParticles(kfSecondKaon, kfThirdPion); + const float chi2geoFirstThird = kfCalculateChi2geoBetweenParticles(kfFirstProton, kfThirdPion); + const float chi2geoFirstSecond = kfCalculateChi2geoBetweenParticles(kfFirstProton, kfSecondKaon); + + // Λc± → p± K∓ π±, Ξc± → p± K∓ π± + KFParticle kfCandPKPi; + const KFParticle* kfDaughtersPKPi[3] = {&kfFirstProton, &kfSecondKaon, &kfThirdPion}; + kfCandPKPi.SetConstructMethod(2); + kfCandPKPi.Construct(kfDaughtersPKPi, 3); + KFParticle kfCandPiKP; + const KFParticle* kfDaughtersPiKP[3] = {&kfFirstPion, &kfSecondKaon, &kfThirdProton}; + kfCandPiKP.SetConstructMethod(2); + kfCandPiKP.Construct(kfDaughtersPiKP, 3); + + // D± → π± K∓ π± + KFParticle kfCandPiKPi; + const KFParticle* kfDaughtersPiKPi[3] = {&kfFirstPion, &kfSecondKaon, &kfThirdPion}; + kfCandPiKPi.SetConstructMethod(2); + kfCandPiKPi.Construct(kfDaughtersPiKPi, 3); + + // Ds± → K± K∓ π± + KFParticle kfCandKKPi; + const KFParticle* kfDaughtersKKPi[3] = {&kfFirstKaon, &kfSecondKaon, &kfThirdPion}; + kfCandKKPi.SetConstructMethod(2); + kfCandKKPi.Construct(kfDaughtersKKPi, 3); + KFParticle kfCandPiKK; + const KFParticle* kfDaughtersPiKK[3] = {&kfFirstPion, &kfSecondKaon, &kfThirdKaon}; + kfCandPiKK.SetConstructMethod(2); + kfCandPiKK.Construct(kfDaughtersPiKK, 3); + + KFParticle kfPairKPi; + const KFParticle* kfDaughtersKPi[3] = {&kfSecondKaon, &kfThirdPion}; + kfPairKPi.SetConstructMethod(2); + kfPairKPi.Construct(kfDaughtersKPi, 2); + + KFParticle kfPairPiK; + const KFParticle* kfDaughtersPiK[3] = {&kfFirstPion, &kfSecondKaon}; + kfPairPiK.SetConstructMethod(2); + kfPairPiK.Construct(kfDaughtersPiK, 2); + + const float massPKPi = kfCandPKPi.GetMass(); + const float massPiKP = kfCandPiKP.GetMass(); + const float massPiKPi = kfCandPiKPi.GetMass(); + const float massKKPi = kfCandKKPi.GetMass(); + const float massPiKK = kfCandPiKK.GetMass(); + const float massKPi = kfPairKPi.GetMass(); + const float massPiK = kfPairPiK.GetMass(); + + const float chi2geo = kfCandPKPi.Chi2() / kfCandPKPi.NDF(); + const float chi2topo = kfCalculateChi2ToPrimaryVertex(kfCandPKPi, kfpV); + const std::pair ldl = kfCalculateLdL(kfCandPKPi, kfpV); + + std::array pProng0 = kfCalculateProngMomentumInSecondaryVertex(kfFirstProton, kfCandPiKP); + std::array pProng1 = kfCalculateProngMomentumInSecondaryVertex(kfSecondKaon, kfCandPiKP); + std::array pProng2 = kfCalculateProngMomentumInSecondaryVertex(kfThirdPion, kfCandPiKP); + + registry.fill(HIST("hCovSVXX"), kfCandPKPi.Covariance(0, 0)); + registry.fill(HIST("hCovSVYY"), kfCandPKPi.Covariance(1, 1)); + registry.fill(HIST("hCovSVXZ"), kfCandPKPi.Covariance(2, 0)); + registry.fill(HIST("hCovSVZZ"), kfCandPKPi.Covariance(2, 2)); + + auto covMatrixSV = kfCandPKPi.CovarianceMatrix(); + double phi, theta; + getPointDirection(std::array{kfpV.GetX(), kfpV.GetY(), kfpV.GetZ()}, std::array{kfCandPKPi.GetX(), kfCandPKPi.GetY(), kfCandPKPi.GetZ()}, phi, theta); + auto errorDecayLength = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixSV, phi, theta)); + auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixSV, phi, 0.)); + + auto indexCollision = collision.globalIndex(); + uint8_t bitmapProngsContributorsPV = 0; + if (indexCollision == track0.collisionId() && track0.isPVContributor()) { + SETBIT(bitmapProngsContributorsPV, 0); + } + if (indexCollision == track1.collisionId() && track1.isPVContributor()) { + SETBIT(bitmapProngsContributorsPV, 1); + } + if (indexCollision == track2.collisionId() && track2.isPVContributor()) { + SETBIT(bitmapProngsContributorsPV, 2); + } + uint8_t nProngsContributorsPV = hf_trkcandsel::countOnesInBinary(bitmapProngsContributorsPV); + + // fill candidate table rows + rowCandidateBase(indexCollision, + kfpV.GetX(), kfpV.GetY(), kfpV.GetZ(), + kfCandPKPi.GetX(), kfCandPKPi.GetY(), kfCandPKPi.GetZ(), + errorDecayLength, errorDecayLengthXY, + kfCandPKPi.GetChi2() / kfCandPKPi.GetNDF(), + pProng0.at(0), pProng0.at(1), pProng0.at(2), + pProng1.at(0), pProng1.at(1), pProng1.at(2), + pProng2.at(0), pProng2.at(1), pProng2.at(2), + impactParameter0XY, impactParameter1XY, impactParameter2XY, + errImpactParameter0XY, errImpactParameter1XY, errImpactParameter2XY, + impactParameter0Z, impactParameter1Z, impactParameter2Z, + errImpactParameter0Z, errImpactParameter1Z, errImpactParameter2Z, + rowTrackIndexProng3.prong0Id(), rowTrackIndexProng3.prong1Id(), rowTrackIndexProng3.prong2Id(), nProngsContributorsPV, bitmapProngsContributorsPV, + rowTrackIndexProng3.hfflag()); + + // fill KF info + rowCandidateKF(kfCandPKPi.GetErrX(), kfCandPKPi.GetErrY(), kfCandPKPi.GetErrZ(), + std::sqrt(kfpV.Covariance(0, 0)), std::sqrt(kfpV.Covariance(1, 1)), std::sqrt(kfpV.Covariance(2, 2)), + massPKPi, massPiKP, massPiKPi, massKKPi, massPiKK, massKPi, massPiK, + kfCandPKPi.GetPx(), kfCandPKPi.GetPy(), kfCandPKPi.GetPz(), + kfCandPKPi.GetErrPx(), kfCandPKPi.GetErrPy(), kfCandPKPi.GetErrPz(), + chi2primFirst, chi2primSecond, chi2primThird, + dcaSecondThird, dcaFirstThird, dcaFirstSecond, + chi2geoSecondThird, chi2geoFirstThird, chi2geoFirstSecond, + chi2geo, ldl.first, ldl.second, chi2topo); + + // fill histograms + if (fillHistograms) { + registry.fill(HIST("hMass3PiKPi"), massPiKPi); + registry.fill(HIST("hMass3PKPi"), massPKPi); + registry.fill(HIST("hMass3PiKP"), massPiKP); + registry.fill(HIST("hMass3KKPi"), massKKPi); + registry.fill(HIST("hMass3PiKK"), massPiKK); + registry.fill(HIST("hMass2KPi"), massKPi); + registry.fill(HIST("hMass2PiK"), massPiK); } } } @@ -330,25 +583,45 @@ struct HfCandidateCreator3Prong { /// /// /////////////////////////////////// - /// @brief process function w/ PV refit and w/o centrality selections - void processPvRefit(soa::Join const& collisions, - FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, - aod::TracksWCovExtra const& tracks, - aod::BCsWithTimestamps const& bcWithTimeStamps) + /// @brief process function using DCA fitter w/ PV refit and w/o centrality selections + void processPvRefitWithDCAFitterN(soa::Join const& collisions, + FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, + aod::TracksWCovExtra const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) + { + runCreator3ProngWithDCAFitterN(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + } + PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithDCAFitterN, "Run candidate creator using DCA fitter with PV refit and w/o centrality selections", false); + + /// @brief process function using DCA fitter w/o PV refit and w/o centrality selections + void processNoPvRefitWithDCAFitterN(soa::Join const& collisions, + FilteredHf3Prongs const& rowsTrackIndexProng3, + aod::TracksWCovExtra const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) + { + runCreator3ProngWithDCAFitterN(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + } + PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitWithDCAFitterN, "Run candidate creator using DCA fitter without PV refit and w/o centrality selections", true); + + /// @brief process function using KFParticle package w/ PV refit and w/o centrality selections + void processPvRefitWithKFParticle(soa::Join const& collisions, + FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, + aod::TracksWCovExtra const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) { - runCreator3Prong(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + runCreator3ProngWithKFParticle(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); } - PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefit, "Run candidate creator with PV refit and w/o centrality selections", false); + PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithKFParticle, "Run candidate creator using KFParticle package with PV refit and w/o centrality selections", false); - /// @brief process function w/o PV refit and w/o centrality selections - void processNoPvRefit(soa::Join const& collisions, - FilteredHf3Prongs const& rowsTrackIndexProng3, - aod::TracksWCovExtra const& tracks, - aod::BCsWithTimestamps const& bcWithTimeStamps) + /// @brief process function using KFParticle package w/o PV refit and w/o centrality selections + void processNoPvRefitWithKFParticle(soa::Join const& collisions, + FilteredHf3Prongs const& rowsTrackIndexProng3, + aod::TracksWCovExtra const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) { - runCreator3Prong(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + runCreator3ProngWithKFParticle(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); } - PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefit, "Run candidate creator without PV refit and w/o centrality selections", true); + PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitWithKFParticle, "Run candidate creator using KFParticle package without PV refit and w/o centrality selections", false); ///////////////////////////////////////////// /// /// @@ -356,25 +629,45 @@ struct HfCandidateCreator3Prong { /// /// ///////////////////////////////////////////// - /// @brief process function w/ PV refit and w/ centrality selection on FT0C - void processPvRefitCentFT0C(soa::Join const& collisions, - FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, - aod::TracksWCovExtra const& tracks, - aod::BCsWithTimestamps const& bcWithTimeStamps) + /// @brief process function using DCA fitter w/ PV refit and w/ centrality selection on FT0C + void processPvRefitWithDCAFitterNCentFT0C(soa::Join const& collisions, + FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, + aod::TracksWCovExtra const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) { - runCreator3Prong(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + runCreator3ProngWithDCAFitterN(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); } - PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitCentFT0C, "Run candidate creator with PV refit and w/ centrality selection on FT0C", false); + PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithDCAFitterNCentFT0C, "Run candidate creator using DCA fitter with PV refit and w/ centrality selection on FT0C", false); - /// @brief process function w/o PV refit and w/ centrality selection on FT0C - void processNoPvRefitCentFT0C(soa::Join const& collisions, - FilteredHf3Prongs const& rowsTrackIndexProng3, - aod::TracksWCovExtra const& tracks, - aod::BCsWithTimestamps const& bcWithTimeStamps) + /// @brief process function using DCA fitter w/o PV refit and w/ centrality selection on FT0C + void processNoPvRefitWithDCAFitterNCentFT0C(soa::Join const& collisions, + FilteredHf3Prongs const& rowsTrackIndexProng3, + aod::TracksWCovExtra const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) { - runCreator3Prong(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + runCreator3ProngWithDCAFitterN(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); } - PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitCentFT0C, "Run candidate creator without PV refit and w/ centrality selection on FT0C", false); + PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitWithDCAFitterNCentFT0C, "Run candidate creator using DCA fitter without PV refit and w/ centrality selection on FT0C", false); + + /// @brief process function using KFParticle package w/ PV refit and w/ centrality selection on FT0C + void processPvRefitWithKFParticleCentFT0C(soa::Join const& collisions, + FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, + aod::TracksWCovExtra const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) + { + runCreator3ProngWithKFParticle(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + } + PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithKFParticleCentFT0C, "Run candidate creator using KFParticle package with PV refit and w/ centrality selection on FT0C", false); + + /// @brief process function using KFParticle package w/o PV refit and w/ centrality selection on FT0C + void processNoPvRefitWithKFParticleCentFT0C(soa::Join const& collisions, + FilteredHf3Prongs const& rowsTrackIndexProng3, + aod::TracksWCovExtra const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) + { + runCreator3ProngWithKFParticle(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + } + PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitWithKFParticleCentFT0C, "Run candidate creator using KFParticle package without PV refit and w/ centrality selection on FT0C", false); ///////////////////////////////////////////// /// /// @@ -382,25 +675,45 @@ struct HfCandidateCreator3Prong { /// /// ///////////////////////////////////////////// - /// @brief process function w/ PV refit and w/ centrality selection on FT0M - void processPvRefitCentFT0M(soa::Join const& collisions, - FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, - aod::TracksWCovExtra const& tracks, - aod::BCsWithTimestamps const& bcWithTimeStamps) + /// @brief process function using DCA fitter w/ PV refit and w/ centrality selection on FT0M + void processPvRefitWithDCAFitterNCentFT0M(soa::Join const& collisions, + FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, + aod::TracksWCovExtra const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) { - runCreator3Prong(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + runCreator3ProngWithDCAFitterN(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); } - PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitCentFT0M, "Run candidate creator with PV refit and w/ centrality selection on FT0M", false); + PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithDCAFitterNCentFT0M, "Run candidate creator using DCA fitter with PV refit and w/ centrality selection on FT0M", false); - /// @brief process function w/o PV refit and w/ centrality selection on FT0M - void processNoPvRefitCentFT0M(soa::Join const& collisions, - FilteredHf3Prongs const& rowsTrackIndexProng3, - aod::TracksWCovExtra const& tracks, - aod::BCsWithTimestamps const& bcWithTimeStamps) + /// @brief process function using DCA fitter w/o PV refit and w/ centrality selection on FT0M + void processNoPvRefitWithDCAFitterNCentFT0M(soa::Join const& collisions, + FilteredHf3Prongs const& rowsTrackIndexProng3, + aod::TracksWCovExtra const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) { - runCreator3Prong(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + runCreator3ProngWithDCAFitterN(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); } - PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitCentFT0M, "Run candidate creator without PV refit and w/ centrality selection on FT0M", false); + PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitWithDCAFitterNCentFT0M, "Run candidate creator using DCA fitter without PV refit and w/ centrality selection on FT0M", false); + + /// @brief process function using KFParticle package w/ PV refit and w/ centrality selection on FT0M + void processPvRefitWithKFParticleCentFT0M(soa::Join const& collisions, + FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, + aod::TracksWCovExtra const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) + { + runCreator3ProngWithKFParticle(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + } + PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithKFParticleCentFT0M, "Run candidate creator using KFParticle package with PV refit and w/ centrality selection on FT0M", false); + + /// @brief process function using KFParticle package w/o PV refit and w/ centrality selection on FT0M + void processNoPvRefitWithKFParticleCentFT0M(soa::Join const& collisions, + FilteredHf3Prongs const& rowsTrackIndexProng3, + aod::TracksWCovExtra const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) + { + runCreator3ProngWithKFParticle(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + } + PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitWithKFParticleCentFT0M, "Run candidate creator using KFParticle package without PV refit and w/ centrality selection on FT0M", false); /////////////////////////////////////////////////////////// /// /// @@ -409,51 +722,54 @@ struct HfCandidateCreator3Prong { /////////////////////////////////////////////////////////// /// @brief process function to monitor collisions - no centrality - void processCollisions(soa::Join const& collisions) + void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { /// bitmask with event. selection info float centrality{-1.f}; - const auto rejectionMask = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, -1, useTimeFrameBorderCut, -zPvPosMax, zPvPosMax, 0, -1.f); + float occupancy = getOccupancyColl(collision, OccupancyEstimator::Its); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); /// monitor the satisfied event selections - monitorCollision(collision, rejectionMask, hCollisions, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy); } /// end loop over collisions } PROCESS_SWITCH(HfCandidateCreator3Prong, processCollisions, "Collision monitoring - no centrality", true); /// @brief process function to monitor collisions - FT0C centrality - void processCollisionsCentFT0C(soa::Join const& collisions) + void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { /// bitmask with event. selection info float centrality{-1.f}; - const auto rejectionMask = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, -1, useTimeFrameBorderCut, -zPvPosMax, zPvPosMax, 0, -1.f); + float occupancy = getOccupancyColl(collision, OccupancyEstimator::Its); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); /// monitor the satisfied event selections - monitorCollision(collision, rejectionMask, hCollisions, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy); } /// end loop over collisions } PROCESS_SWITCH(HfCandidateCreator3Prong, processCollisionsCentFT0C, "Collision monitoring - FT0C centrality", false); /// @brief process function to monitor collisions - FT0M centrality - void processCollisionsCentFT0M(soa::Join const& collisions) + void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { /// bitmask with event. selection info float centrality{-1.f}; - const auto rejectionMask = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, -1, useTimeFrameBorderCut, -zPvPosMax, zPvPosMax, 0, -1.f); + float occupancy = getOccupancyColl(collision, OccupancyEstimator::Its); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); /// monitor the satisfied event selections - monitorCollision(collision, rejectionMask, hCollisions, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy); } /// end loop over collisions } @@ -466,42 +782,52 @@ struct HfCandidateCreator3ProngExpressions { Produces rowMcMatchRec; Produces rowMcMatchGen; - bool createDplus{false}; - bool createDs{false}; - bool createLc{false}; - bool createXic{false}; + // Configuration + Configurable rejectBackground{"rejectBackground", true, "Reject particles from background events"}; + Configurable matchKinkedDecayTopology{"matchKinkedDecayTopology", false, "Match also candidates with tracks that decay with kinked topology"}; + Configurable matchInteractionsWithMaterial{"matchInteractionsWithMaterial", false, "Match also candidates with tracks that interact with material"}; + + HfEventSelectionMc hfEvSelMc; // mc event selection and monitoring + + using BCsInfo = soa::Join; + using McCollisionsNoCents = soa::Join; + using McCollisionsFT0Cs = soa::Join; + using McCollisionsFT0Ms = soa::Join; + using McCollisionsCentFT0Ms = soa::Join; + + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + PresliceUnsorted colPerMcCollisionFT0C = aod::mccollisionlabel::mcCollisionId; + PresliceUnsorted colPerMcCollisionFT0M = aod::mccollisionlabel::mcCollisionId; + + HistogramRegistry registry{"registry"}; void init(InitContext& initContext) { + std::array procCollisions = {doprocessMc, doprocessMcCentFT0C, doprocessMcCentFT0M}; + if (std::accumulate(procCollisions.begin(), procCollisions.end(), 0) > 1) { + LOGP(fatal, "At most one process function for collision study can be enabled at a time."); + } - // inspect for which particle species the candidates were created - auto& workflows = initContext.services().get(); + // inspect for which particle species the candidates were created and which zPvPosMax cut was set for reconstructed + const auto& workflows = initContext.services().get(); for (const DeviceSpec& device : workflows.devices) { if (device.name.compare("hf-candidate-creator-3prong") == 0) { - for (const auto& option : device.options) { - if (option.name.compare("createDplus") == 0) { - createDplus = option.defaultValue.get(); - } else if (option.name.compare("createDs") == 0) { - createDs = option.defaultValue.get(); - } else if (option.name.compare("createLc") == 0) { - createLc = option.defaultValue.get(); - } else if (option.name.compare("createXic") == 0) { - createXic = option.defaultValue.get(); - } - } + hfEvSelMc.configureFromDevice(device); + break; } } - LOGP(info, "Flags for candidate creation from the reco workflow:"); - LOGP(info, " --> createDplus = {}", createDplus); - LOGP(info, " --> createDs = {}", createDs); - LOGP(info, " --> createLc = {}", createLc); - LOGP(info, " --> createXic = {}", createXic); + hfEvSelMc.addHistograms(registry); // particles monitoring } /// Performs MC matching. - void processMc(aod::TracksWMc const& tracks, - aod::McParticles const& mcParticles) + template + void runCreator3ProngMc(aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles, + CCs const& collInfos, + McCollisions const& mcCollisions, + BCsInfo const&) { rowCandidateProng3->bindExternalIndices(&tracks); @@ -511,11 +837,13 @@ struct HfCandidateCreator3ProngExpressions { int8_t origin = 0; int8_t swapping = 0; int8_t channel = 0; + int8_t nKinkedTracks = 0; + int8_t nInteractionsWithMaterial = 0; std::vector arrDaughIndex; std::array arrPDGDaugh; std::array arrPDGResonant1 = {kProton, 313}; // Λc± → p± K* std::array arrPDGResonant2 = {2224, kKPlus}; // Λc± → Δ(1232)±± K∓ - std::array arrPDGResonant3 = {3124, kPiPlus}; // Λc± → Λ(1520) π± + std::array arrPDGResonant3 = {102134, kPiPlus}; // Λc± → Λ(1520) π± std::array arrPDGResonantDPhiPi = {333, kPiPlus}; // Ds± → Phi π± and D± → Phi π± std::array arrPDGResonantDKstarK = {313, kKPlus}; // Ds± → K*(892)0bar K± and D± → K*(892)0bar K± @@ -527,23 +855,66 @@ struct HfCandidateCreator3ProngExpressions { swapping = 0; channel = 0; arrDaughIndex.clear(); + std::vector idxBhadMothers{}; auto arrayDaughters = std::array{candidate.prong0_as(), candidate.prong1_as(), candidate.prong2_as()}; + // Check whether the particle is from background events. If so, reject it. + if (rejectBackground) { + bool fromBkg{false}; + for (const auto& daughter : arrayDaughters) { + if (daughter.has_mcParticle()) { + auto mcParticle = daughter.mcParticle(); + if (mcParticle.fromBackgroundEvent()) { + fromBkg = true; + break; + } + } + } + if (fromBkg) { + rowMcMatchRec(flag, origin, swapping, channel, -1.f, 0, 0, 0); + continue; + } + } + // D± → π± K∓ π± - if (createDplus) { - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, std::array{+kPiPlus, -kKPlus, +kPiPlus}, true, &sign, 2); + if (flag == 0) { + if (matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, std::array{+kPiPlus, -kKPlus, +kPiPlus}, true, &sign, 2, &nKinkedTracks, &nInteractionsWithMaterial); + } else if (matchKinkedDecayTopology && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, std::array{+kPiPlus, -kKPlus, +kPiPlus}, true, &sign, 2, &nKinkedTracks); + } else if (!matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, std::array{+kPiPlus, -kKPlus, +kPiPlus}, true, &sign, 2, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, std::array{+kPiPlus, -kKPlus, +kPiPlus}, true, &sign, 2); + } if (indexRec > -1) { flag = sign * (1 << DecayType::DplusToPiKPi); } } // Ds± → K± K∓ π± and D± → K± K∓ π± - if (flag == 0 && createDs) { + if (flag == 0) { bool isDplus = false; - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDS, std::array{+kKPlus, -kKPlus, +kPiPlus}, true, &sign, 2); + if (matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDS, std::array{+kKPlus, -kKPlus, +kPiPlus}, true, &sign, 2, &nKinkedTracks, &nInteractionsWithMaterial); + } else if (matchKinkedDecayTopology && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDS, std::array{+kKPlus, -kKPlus, +kPiPlus}, true, &sign, 2, &nKinkedTracks); + } else if (!matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDS, std::array{+kKPlus, -kKPlus, +kPiPlus}, true, &sign, 2, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDS, std::array{+kKPlus, -kKPlus, +kPiPlus}, true, &sign, 2); + } if (indexRec == -1) { isDplus = true; - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, std::array{+kKPlus, -kKPlus, +kPiPlus}, true, &sign, 2); + if (matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, std::array{+kKPlus, -kKPlus, +kPiPlus}, true, &sign, 2, &nKinkedTracks, &nInteractionsWithMaterial); + } else if (matchKinkedDecayTopology && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, std::array{+kKPlus, -kKPlus, +kPiPlus}, true, &sign, 2, &nKinkedTracks); + } else if (!matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, std::array{+kKPlus, -kKPlus, +kPiPlus}, true, &sign, 2, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, std::array{+kKPlus, -kKPlus, +kPiPlus}, true, &sign, 2); + } } if (indexRec > -1) { // DecayType::DsToKKPi is used to flag both Ds± → K± K∓ π± and D± → K± K∓ π± @@ -567,9 +938,30 @@ struct HfCandidateCreator3ProngExpressions { } } + // D* → D0π → Kππ + if (flag == 0) { + if (matchKinkedDecayTopology) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDStar, std::array{+kPiPlus, +kPiPlus, -kKPlus}, true, &sign, 2, &nKinkedTracks); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDStar, std::array{+kPiPlus, +kPiPlus, -kKPlus}, true, &sign, 2); + } + if (indexRec > -1) { + flag = sign * (1 << DstarToPiKPiBkg); + channel = 1; + } + } + // Λc± → p± K∓ π± - if (flag == 0 && createLc) { - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); + if (flag == 0) { + if (matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2, &nKinkedTracks, &nInteractionsWithMaterial); + } else if (matchKinkedDecayTopology && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2, &nKinkedTracks); + } else if (!matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); + } if (indexRec > -1) { flag = sign * (1 << DecayType::LcToPKPi); @@ -595,110 +987,102 @@ struct HfCandidateCreator3ProngExpressions { } // Ξc± → p± K∓ π± - if (flag == 0 && createXic) { - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kXiCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); + if (flag == 0) { + if (matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kXiCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2, &nKinkedTracks, &nInteractionsWithMaterial); + } else if (matchKinkedDecayTopology && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kXiCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2, &nKinkedTracks); + } else if (!matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kXiCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kXiCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); + } if (indexRec > -1) { flag = sign * (1 << DecayType::XicToPKPi); + if (arrayDaughters[0].has_mcParticle()) { + swapping = int8_t(std::abs(arrayDaughters[0].mcParticle().pdgCode()) == kPiPlus); + } } } // Check whether the particle is non-prompt (from a b quark). if (flag != 0) { auto particle = mcParticles.rawIteratorAt(indexRec); - origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle); + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); } - - rowMcMatchRec(flag, origin, swapping, channel); - } - - // Match generated particles. - for (const auto& particle : mcParticles) { - flag = 0; - origin = 0; - channel = 0; - arrDaughIndex.clear(); - - // D± → π± K∓ π± - if (createDplus) { - if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kDPlus, std::array{+kPiPlus, -kKPlus, +kPiPlus}, true, &sign, 2)) { - flag = sign * (1 << DecayType::DplusToPiKPi); - } - } - - // Ds± → K± K∓ π± and D± → K± K∓ π± - if (flag == 0 && createDs) { - bool isDplus = false; - if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kDS, std::array{+kKPlus, -kKPlus, +kPiPlus}, true, &sign, 2)) { - // DecayType::DsToKKPi is used to flag both Ds± → K± K∓ π± and D± → K± K∓ π± - // TODO: move to different and explicit flags - flag = sign * (1 << DecayType::DsToKKPi); - } else if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kDPlus, std::array{+kKPlus, -kKPlus, +kPiPlus}, true, &sign, 2)) { - // DecayType::DsToKKPi is used to flag both Ds± → K± K∓ π± and D± → K± K∓ π± - // TODO: move to different and explicit flags - flag = sign * (1 << DecayType::DsToKKPi); - isDplus = true; - } - if (flag != 0) { - RecoDecay::getDaughters(particle, &arrDaughIndex, std::array{0}, 1); - if (arrDaughIndex.size() == 2) { - for (auto jProng = 0u; jProng < arrDaughIndex.size(); ++jProng) { - auto daughJ = mcParticles.rawIteratorAt(arrDaughIndex[jProng]); - arrPDGDaugh[jProng] = std::abs(daughJ.pdgCode()); - } - if ((arrPDGDaugh[0] == arrPDGResonantDPhiPi[0] && arrPDGDaugh[1] == arrPDGResonantDPhiPi[1]) || (arrPDGDaugh[0] == arrPDGResonantDPhiPi[1] && arrPDGDaugh[1] == arrPDGResonantDPhiPi[0])) { - channel = isDplus ? DecayChannelDToKKPi::DplusToPhiPi : DecayChannelDToKKPi::DsToPhiPi; - } else if ((arrPDGDaugh[0] == arrPDGResonantDKstarK[0] && arrPDGDaugh[1] == arrPDGResonantDKstarK[1]) || (arrPDGDaugh[0] == arrPDGResonantDKstarK[1] && arrPDGDaugh[1] == arrPDGResonantDKstarK[0])) { - channel = isDplus ? DecayChannelDToKKPi::DplusToK0starK : DecayChannelDToKKPi::DsToK0starK; - } - } - } + if (origin == RecoDecay::OriginType::NonPrompt) { + auto bHadMother = mcParticles.rawIteratorAt(idxBhadMothers[0]); + rowMcMatchRec(flag, origin, swapping, channel, bHadMother.pt(), bHadMother.pdgCode(), nKinkedTracks, nInteractionsWithMaterial); + } else { + rowMcMatchRec(flag, origin, swapping, channel, -1.f, 0, nKinkedTracks, nInteractionsWithMaterial); } + } - // Λc± → p± K∓ π± - if (flag == 0 && createLc) { - if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2)) { - flag = sign * (1 << DecayType::LcToPKPi); + for (const auto& mcCollision : mcCollisions) { - // Flagging the different Λc± → p± K∓ π± decay channels - RecoDecay::getDaughters(particle, &arrDaughIndex, std::array{0}, 1); - if (arrDaughIndex.size() == 2) { - for (auto jProng = 0u; jProng < arrDaughIndex.size(); ++jProng) { - auto daughJ = mcParticles.rawIteratorAt(arrDaughIndex[jProng]); - arrPDGDaugh[jProng] = std::abs(daughJ.pdgCode()); - } - if ((arrPDGDaugh[0] == arrPDGResonant1[0] && arrPDGDaugh[1] == arrPDGResonant1[1]) || (arrPDGDaugh[0] == arrPDGResonant1[1] && arrPDGDaugh[1] == arrPDGResonant1[0])) { - channel = 1; - } else if ((arrPDGDaugh[0] == arrPDGResonant2[0] && arrPDGDaugh[1] == arrPDGResonant2[1]) || (arrPDGDaugh[0] == arrPDGResonant2[1] && arrPDGDaugh[1] == arrPDGResonant2[0])) { - channel = 2; - } else if ((arrPDGDaugh[0] == arrPDGResonant3[0] && arrPDGDaugh[1] == arrPDGResonant3[1]) || (arrPDGDaugh[0] == arrPDGResonant3[1] && arrPDGDaugh[1] == arrPDGResonant3[0])) { - channel = 3; - } - } - } + // Slice the particles table to get the particles for the current MC collision + const auto mcParticlesPerMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, mcCollision.globalIndex()); + // Slice the collisions table to get the collision info for the current MC collision + float centrality{-1.f}; + uint16_t rejectionMask{0}; + int nSplitColl = 0; + if constexpr (centEstimator == CentralityEstimator::FT0C) { + const auto collSlice = collInfos.sliceBy(colPerMcCollisionFT0C, mcCollision.globalIndex()); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } else if constexpr (centEstimator == CentralityEstimator::FT0M) { + const auto collSlice = collInfos.sliceBy(colPerMcCollisionFT0M, mcCollision.globalIndex()); + nSplitColl = collSlice.size(); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } else if constexpr (centEstimator == CentralityEstimator::None) { + const auto collSlice = collInfos.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); } - - // Ξc± → p± K∓ π± - if (flag == 0 && createXic) { - if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kXiCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2)) { - flag = sign * (1 << DecayType::XicToPKPi); + hfEvSelMc.fillHistograms(mcCollision, rejectionMask, nSplitColl); + if (rejectionMask != 0) { + // at least one event selection not satisfied --> reject all gen particles from this collision + for (unsigned int i = 0; i < mcParticlesPerMcColl.size(); ++i) { + rowMcMatchGen(0, 0, 0, -1); } + continue; } + hf_mc_gen::fillMcMatchGen3Prong(mcParticles, mcParticlesPerMcColl, rowMcMatchGen, rejectBackground); + } + } - // Check whether the particle is non-prompt (from a b quark). - if (flag != 0) { - origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle); - } + void processMc(aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions, + BCsInfo const& BCsInfo) + { + runCreator3ProngMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + } + PROCESS_SWITCH(HfCandidateCreator3ProngExpressions, processMc, "Process MC - no centrality", false); - rowMcMatchGen(flag, origin, channel); - } + void processMcCentFT0C(aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisionsFT0Cs const& collInfos, + aod::McCollisions const& mcCollisions, + BCsInfo const& BCsInfo) + { + runCreator3ProngMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); } + PROCESS_SWITCH(HfCandidateCreator3ProngExpressions, processMcCentFT0C, "Process MC - FT0c centrality", false); - PROCESS_SWITCH(HfCandidateCreator3ProngExpressions, processMc, "Process MC", false); + void processMcCentFT0M(aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisionsFT0Ms const& collInfos, + McCollisionsCentFT0Ms const& mcCollisions, + BCsInfo const& BCsInfo) + { + runCreator3ProngMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + } + PROCESS_SWITCH(HfCandidateCreator3ProngExpressions, processMcCentFT0M, "Process MC - FT0m centrality", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"hf-candidate-creator-3prong"}), - adaptAnalysisTask(cfgc, TaskName{"hf-candidate-creator-3prong-expressions"})}; + adaptAnalysisTask(cfgc, TaskName{"hf-candidate-creator-3prong"}), // o2-linter: disable=name/o2-task (wrong hyphenation) + adaptAnalysisTask(cfgc, TaskName{"hf-candidate-creator-3prong-expressions"})}; // o2-linter: disable=name/o2-task (wrong hyphenation) } diff --git a/PWGHF/TableProducer/candidateCreatorB0.cxx b/PWGHF/TableProducer/candidateCreatorB0.cxx index 7fea6b97b20..6caca925a2d 100644 --- a/PWGHF/TableProducer/candidateCreatorB0.cxx +++ b/PWGHF/TableProducer/candidateCreatorB0.cxx @@ -15,6 +15,10 @@ /// /// \author Alexandre Bigot , IPHC Strasbourg +#include +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "DCAFitter/DCAFitterN.h" #include "Framework/AnalysisTask.h" @@ -30,6 +34,7 @@ #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" #include "PWGHF/Utils/utilsTrkCandHf.h" +#include "PWGHF/Utils/utilsMcGen.h" using namespace o2; using namespace o2::analysis; @@ -57,7 +62,7 @@ struct HfCandidateCreatorB0 { Configurable usePionIsGlobalTrackWoDCA{"usePionIsGlobalTrackWoDCA", true, "check isGlobalTrackWoDCA status for pions, for Run3 studies"}; Configurable ptPionMin{"ptPionMin", 0.5, "minimum pion pT threshold (GeV/c)"}; Configurable> binsPtPion{"binsPtPion", std::vector{hf_cuts_single_track::vecBinsPtTrack}, "track pT bin limits for pion DCA XY pT-dependent cut"}; - Configurable> cutsTrackPionDCA{"cutsTrackPionDCA", {hf_cuts_single_track::cutsTrack[0], hf_cuts_single_track::nBinsPtTrack, hf_cuts_single_track::nCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for pions"}; + Configurable> cutsTrackPionDCA{"cutsTrackPionDCA", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for pions"}; Configurable invMassWindowB0{"invMassWindowB0", 0.3, "invariant-mass window for B0 candidates"}; Configurable selectionFlagD{"selectionFlagD", 1, "Selection Flag for D"}; // magnetic field setting from CCDB @@ -93,6 +98,9 @@ struct HfCandidateCreatorB0 { Preslice candsDPerCollision = aod::track_association::collisionId; Preslice trackIndicesPerCollision = aod::track_association::collisionId; + std::shared_ptr hCandidatesD, hCandidatesB; + HistogramRegistry registry{"registry"}; + OutputObj hMassDToPiKPi{TH1F("hMassDToPiKPi", "D^{#minus} candidates;inv. mass (p^{#minus} K^{#plus} #pi^{#minus}) (GeV/#it{c}^{2});entries", 500, 0., 5.)}; OutputObj hPtD{TH1F("hPtD", "D^{#minus} candidates;D^{#minus} candidate #it{p}_{T} (GeV/#it{c});entries", 100, 0., 10.)}; OutputObj hPtPion{TH1F("hPtPion", "#pi^{#plus} candidates;#pi^{#plus} candidate #it{p}_{T} (GeV/#it{c});entries", 100, 0., 10.)}; @@ -101,9 +109,6 @@ struct HfCandidateCreatorB0 { OutputObj hCovPVXX{TH1F("hCovPVXX", "2-prong candidates;XX element of cov. matrix of prim. vtx. position (cm^{2});entries", 100, 0., 1.e-4)}; OutputObj hCovSVXX{TH1F("hCovSVXX", "2-prong candidates;XX element of cov. matrix of sec. vtx. position (cm^{2});entries", 100, 0., 0.2)}; - std::shared_ptr hCandidatesD, hCandidatesB; - HistogramRegistry registry{"registry"}; - void init(InitContext const&) { // invariant-mass window cut @@ -241,7 +246,7 @@ struct HfCandidateCreatorB0 { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN for D cannot work, skipping the candidate."; + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN for D cannot work, skipping the candidate."; hCandidatesD->Fill(SVFitting::Fail); continue; } @@ -303,7 +308,7 @@ struct HfCandidateCreatorB0 { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN for B cannot work, skipping the candidate."; + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN for B cannot work, skipping the candidate."; hCandidatesB->Fill(SVFitting::Fail); continue; } @@ -342,8 +347,6 @@ struct HfCandidateCreatorB0 { auto errorDecayLength = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); - int hfFlag = BIT(hf_cand_b0::DecayType::B0ToDPi); - // fill the candidate table for the B0 here: rowCandidateBase(thisCollId, collision.posX(), collision.posY(), collision.posZ(), @@ -353,15 +356,14 @@ struct HfCandidateCreatorB0 { pVecD[0], pVecD[1], pVecD[2], pVecPion[0], pVecPion[1], pVecPion[2], dcaD.getY(), dcaPion.getY(), - std::sqrt(dcaD.getSigmaY2()), std::sqrt(dcaPion.getSigmaY2()), - hfFlag); + std::sqrt(dcaD.getSigmaY2()), std::sqrt(dcaPion.getSigmaY2())); rowCandidateProngs(candD.globalIndex(), trackPion.globalIndex()); } // pi loop - } // D loop - } // collision loop - } // process -}; // struct + } // D loop + } // collision loop + } // process +}; // struct /// Extends the base table with expression columns and performs MC matching. struct HfCandidateCreatorB0Expressions { @@ -451,21 +453,8 @@ struct HfCandidateCreatorB0Expressions { rowMcMatchRec(flag, origin, debug); } // rec - // Match generated particles. - for (const auto& particle : mcParticles) { - flag = 0; - origin = 0; - // B0 → D- π+ - if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kB0, std::array{-static_cast(Pdg::kDPlus), +kPiPlus}, true)) { - // D- → π- K+ π- - auto candDMC = mcParticles.rawIteratorAt(particle.daughtersIds().front()); - if (RecoDecay::isMatchedMCGen(mcParticles, candDMC, -static_cast(Pdg::kDPlus), std::array{-kPiPlus, +kKPlus, -kPiPlus}, true, &sign)) { - flag = sign * BIT(hf_cand_b0::DecayType::B0ToDPi); - } - } - rowMcMatchGen(flag, origin); - } // gen - } // processMc + hf_mc_gen::fillMcMatchGenB0(mcParticles, rowMcMatchGen); // gen + } // processMc PROCESS_SWITCH(HfCandidateCreatorB0Expressions, processMc, "Process MC", false); }; // struct diff --git a/PWGHF/TableProducer/candidateCreatorBplus.cxx b/PWGHF/TableProducer/candidateCreatorBplus.cxx index c780cf972e2..f1d306cad12 100644 --- a/PWGHF/TableProducer/candidateCreatorBplus.cxx +++ b/PWGHF/TableProducer/candidateCreatorBplus.cxx @@ -18,6 +18,10 @@ /// \author Deepa Thomas , UT Austin /// \author Antonio Palasciano , Università degli Studi di Bari & INFN, Sezione di Bari +#include +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "DCAFitter/DCAFitterN.h" #include "Framework/AnalysisTask.h" @@ -33,6 +37,7 @@ #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" #include "PWGHF/Utils/utilsTrkCandHf.h" +#include "PWGHF/Utils/utilsMcGen.h" using namespace o2; using namespace o2::analysis; @@ -60,7 +65,7 @@ struct HfCandidateCreatorBplus { Configurable usePionIsGlobalTrackWoDCA{"usePionIsGlobalTrackWoDCA", true, "check isGlobalTrackWoDCA status for pions, for Run3 studies"}; Configurable ptPionMin{"ptPionMin", 0.2, "minimum pion pT threshold (GeV/c)"}; Configurable> binsPtPion{"binsPtPion", std::vector{hf_cuts_single_track::vecBinsPtTrack}, "track pT bin limits for pion DCA XY pT-dependent cut"}; - Configurable> cutsTrackPionDCA{"cutsTrackPionDCA", {hf_cuts_single_track::cutsTrack[0], hf_cuts_single_track::nBinsPtTrack, hf_cuts_single_track::nCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for pions"}; + Configurable> cutsTrackPionDCA{"cutsTrackPionDCA", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for pions"}; Configurable invMassWindowBplus{"invMassWindowBplus", 0.3, "invariant-mass window for B^{+} candidates"}; Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection Flag for D0bar"}; @@ -79,9 +84,6 @@ struct HfCandidateCreatorBplus { o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; int runNumber; - double massPi{0.}; - double massD0{0.}; - double massBplus{0.}; double invMass2D0PiMin{0.}; double invMass2D0PiMax{0.}; double bz{0.}; @@ -98,23 +100,20 @@ struct HfCandidateCreatorBplus { Preslice candsDPerCollision = aod::track_association::collisionId; Preslice trackIndicesPerCollision = aod::track_association::collisionId; + std::shared_ptr hCandidatesD, hCandidatesB; + HistogramRegistry registry{"registry"}; + OutputObj hCovPVXX{TH1F("hCovPVXX", "2-prong candidates;XX element of cov. matrix of prim. vtx. position (cm^{2});entries", 100, 0., 1.e-4)}; OutputObj hCovSVXX{TH1F("hCovSVXX", "2-prong candidates;XX element of cov. matrix of sec. vtx. position (cm^{2});entries", 100, 0., 0.2)}; OutputObj hRapidityD0{TH1F("hRapidityD0", "D0 candidates;#it{y};entries", 100, -2, 2)}; OutputObj hEtaPi{TH1F("hEtaPi", "Pion track;#it{#eta};entries", 400, -2., 2.)}; OutputObj hMassBplusToD0Pi{TH1F("hMassBplusToD0Pi", "2-prong candidates;inv. mass (B^{+} #rightarrow #bar{D^{0}}#pi^{+}) (GeV/#it{c}^{2});entries", 500, 3., 8.)}; - std::shared_ptr hCandidatesD, hCandidatesB; - HistogramRegistry registry{"registry"}; - void init(InitContext const&) { // invariant-mass window cut - massPi = MassPiPlus; - massD0 = MassD0; - massBplus = MassBPlus; - invMass2D0PiMin = (massBplus - invMassWindowBplus) * (massBplus - invMassWindowBplus); - invMass2D0PiMax = (massBplus + invMassWindowBplus) * (massBplus + invMassWindowBplus); + invMass2D0PiMin = (MassBPlus - invMassWindowBplus) * (MassBPlus - invMassWindowBplus); + invMass2D0PiMax = (MassBPlus + invMassWindowBplus) * (MassBPlus + invMassWindowBplus); // Initialise fitter for B vertex dfB.setPropagateToPCA(propagateToPCA); @@ -173,16 +172,8 @@ struct HfCandidateCreatorBplus { aod::BCsWithTimestamps const&) { - static int nCol = 0; - for (const auto& collision : collisions) { auto primaryVertex = getPrimaryVertex(collision); - - if (nCol % 10000 == 0) { - LOG(debug) << nCol << " collisions parsed"; - } - nCol++; - /// Set the magnetic field from ccdb. /// The static instance of the propagator was already modified in the HFTrackIndexSkimCreator, /// but this is not true when running on Run2 data/MC already converted into AO2Ds. @@ -236,7 +227,7 @@ struct HfCandidateCreatorBplus { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN for D cannot work, skipping the candidate."; + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN for D cannot work, skipping the candidate."; hCandidatesD->Fill(SVFitting::Fail); continue; } @@ -294,7 +285,6 @@ struct HfCandidateCreatorBplus { auto trackParCovPi = getTrackParCov(trackPion); std::array pVecD0 = {0., 0., 0.}; std::array pVecBach = {0., 0., 0.}; - std::array pVecBCand = {0., 0., 0.}; // find the DCA between the D0 and the bachelor track, for B+ hCandidatesB->Fill(SVFitting::BeforeFit); @@ -303,7 +293,7 @@ struct HfCandidateCreatorBplus { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN for B cannot work, skipping the candidate."; + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN for B cannot work, skipping the candidate."; hCandidatesB->Fill(SVFitting::Fail); continue; } @@ -318,8 +308,6 @@ struct HfCandidateCreatorBplus { auto covMatrixPCA = dfB.calcPCACovMatrixFlat(); hCovSVXX->Fill(covMatrixPCA[0]); // FIXME: Calculation of errorDecayLength(XY) gives wrong values without this line. - pVecBCand = RecoDecay::pVec(pVecD0, pVecBach); - // get track impact parameters // This modifies track momenta! auto covMatrixPV = primaryVertex.getCov(); @@ -335,10 +323,8 @@ struct HfCandidateCreatorBplus { auto errorDecayLength = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); - int hfFlag = BIT(hf_cand_bplus::DecayType::BplusToD0Pi); - // compute invariant mass square and apply selection - auto invMass2D0Pi = RecoDecay::m2(std::array{pVecD0, pVecBach}, std::array{massD0, massPi}); + auto invMass2D0Pi = RecoDecay::m2(std::array{pVecD0, pVecBach}, std::array{MassD0, MassPiPlus}); if ((invMass2D0Pi < invMass2D0PiMin) || (invMass2D0Pi > invMass2D0PiMax)) { continue; } @@ -353,15 +339,14 @@ struct HfCandidateCreatorBplus { pVecD0[0], pVecD0[1], pVecD0[2], pVecBach[0], pVecBach[1], pVecBach[2], impactParameter0.getY(), impactParameter1.getY(), - std::sqrt(impactParameter0.getSigmaY2()), std::sqrt(impactParameter1.getSigmaY2()), - hfFlag); + std::sqrt(impactParameter0.getSigmaY2()), std::sqrt(impactParameter1.getSigmaY2())); rowCandidateProngs(candD0.globalIndex(), trackPion.globalIndex()); // index D0 and bachelor - } // track loop - } // D0 cand loop - } // collision - } // process -}; // struct + } // track loop + } // D0 cand loop + } // collision + } // process +}; // struct /// Extends the base table with expression columns and performs MC matching struct HfCandidateCreatorBplusExpressions { @@ -381,7 +366,6 @@ struct HfCandidateCreatorBplusExpressions { int8_t signB = 0, signD0 = 0; int8_t flag = 0; int8_t origin = 0; - int kD0pdg = Pdg::kD0; // Match reconstructed candidates. // Spawned table can be used directly @@ -402,32 +386,8 @@ struct HfCandidateCreatorBplusExpressions { } rowMcMatchRec(flag, origin); } - - // Match generated particles. - for (const auto& particle : mcParticles) { - flag = 0; - origin = 0; - signB = 0; - signD0 = 0; - int indexGenD0 = -1; - - // B± → D0bar(D0) π± → (K± π∓) π± - std::vector arrayDaughterB; - if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kBPlus, std::array{-kD0pdg, +kPiPlus}, true, &signB, 1, &arrayDaughterB)) { - // D0(bar) → π± K∓ - for (auto iD : arrayDaughterB) { - auto candDaughterMC = mcParticles.rawIteratorAt(iD); - if (std::abs(candDaughterMC.pdgCode()) == kD0pdg) { - indexGenD0 = RecoDecay::isMatchedMCGen(mcParticles, candDaughterMC, Pdg::kD0, std::array{-kKPlus, +kPiPlus}, true, &signD0, 1); - } - } - if (indexGenD0 > -1) { - flag = signB * (1 << hf_cand_bplus::DecayType::BplusToD0Pi); - } - } - rowMcMatchGen(flag, origin); - } // B candidate - } // process + hf_mc_gen::fillMcMatchGenBplus(mcParticles, rowMcMatchGen); // gen + } // process PROCESS_SWITCH(HfCandidateCreatorBplusExpressions, processMc, "Process MC", false); }; // struct diff --git a/PWGHF/TableProducer/candidateCreatorBs.cxx b/PWGHF/TableProducer/candidateCreatorBs.cxx index 7d8ad642fc2..5ce38797762 100644 --- a/PWGHF/TableProducer/candidateCreatorBs.cxx +++ b/PWGHF/TableProducer/candidateCreatorBs.cxx @@ -15,6 +15,10 @@ /// /// \author Phil Stahlhut +#include +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "DCAFitter/DCAFitterN.h" #include "Framework/AnalysisTask.h" @@ -41,7 +45,8 @@ using namespace o2::hf_trkcandsel; /// Reconstruction of Bs candidates struct HfCandidateCreatorBs { - Produces rowCandidateBase; // table defined in CandidateReconstructionTables.h + Produces rowCandidateBase; // table defined in CandidateReconstructionTables.h + Produces rowCandidateProngs; // table defined in CandidateReconstructionTables.h // vertexing Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; @@ -56,7 +61,7 @@ struct HfCandidateCreatorBs { Configurable usePionIsGlobalTrackWoDCA{"usePionIsGlobalTrackWoDCA", true, "check isGlobalTrackWoDCA status for pions, for Run3 studies"}; Configurable ptPionMin{"ptPionMin", 0.5, "minimum pion pT threshold (GeV/c)"}; Configurable> binsPtPion{"binsPtPion", std::vector{hf_cuts_single_track::vecBinsPtTrack}, "track pT bin limits for pion DCA XY pT-dependent cut"}; - Configurable> cutsTrackPionDCA{"cutsTrackPionDCA", {hf_cuts_single_track::cutsTrack[0], hf_cuts_single_track::nBinsPtTrack, hf_cuts_single_track::nCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for pions"}; + Configurable> cutsTrackPionDCA{"cutsTrackPionDCA", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for pions"}; Configurable invMassWindowBs{"invMassWindowBs", 0.3, "invariant-mass window for Bs candidates"}; Configurable selectionFlagDs{"selectionFlagDs", 1, "Selection Flag for Ds"}; // magnetic field setting from CCDB @@ -88,6 +93,9 @@ struct HfCandidateCreatorBs { Preslice candsDsPerCollision = aod::track_association::collisionId; Preslice trackIndicesPerCollision = aod::track_association::collisionId; + std::shared_ptr hCandidatesD, hCandidatesB; + HistogramRegistry registry{"registry"}; + OutputObj hMassDsToKKPi{TH1F("hMassDsToKKPi", "D_{s} candidates;inv. mass (K K #pi) (GeV/#it{c}^{2});entries", 500, 0., 5.)}; OutputObj hPtDs{TH1F("hPtDs", "D_{s} candidates;D_{s} candidate #it{p}_{T} (GeV/#it{c});entries", 100, 0., 10.)}; OutputObj hPtPion{TH1F("hPtPion", "#pi candidates;#pi candidate #it{p}_{T} (GeV/#it{c});entries", 100, 0., 10.)}; @@ -96,9 +104,6 @@ struct HfCandidateCreatorBs { OutputObj hCovPVXX{TH1F("hCovPVXX", "2-prong candidates;XX element of cov. matrix of prim. vtx. position (cm^{2});entries", 100, 0., 1.e-4)}; OutputObj hCovSVXX{TH1F("hCovSVXX", "2-prong candidates;XX element of cov. matrix of sec. vtx. position (cm^{2});entries", 100, 0., 0.2)}; - std::shared_ptr hCandidatesD, hCandidatesB; - HistogramRegistry registry{"registry"}; - void init(InitContext const&) { massPi = MassPiPlus; @@ -221,7 +226,7 @@ struct HfCandidateCreatorBs { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN for D cannot work, skipping the candidate."; + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN for D cannot work, skipping the candidate."; hCandidatesD->Fill(SVFitting::Fail); continue; } @@ -284,7 +289,7 @@ struct HfCandidateCreatorBs { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN for B cannot work, skipping the candidate."; + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN for B cannot work, skipping the candidate."; hCandidatesB->Fill(SVFitting::Fail); continue; } @@ -320,8 +325,6 @@ struct HfCandidateCreatorBs { auto errorDecayLength = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); - int hfFlag = BIT(hf_cand_bs::DecayType::BsToDsPi); - // fill output histograms for Bs candidates hMassDsToKKPi->Fill(hfHelper.invMassDsToKKPi(candDs), candDs.pt()); hCovSVXX->Fill(covMatrixPCA[0]); @@ -340,14 +343,14 @@ struct HfCandidateCreatorBs { pVecDs[0], pVecDs[1], pVecDs[2], pVecPion[0], pVecPion[1], pVecPion[2], dcaDs.getY(), dcaPion.getY(), - std::sqrt(dcaDs.getSigmaY2()), std::sqrt(dcaPion.getSigmaY2()), - candDs.globalIndex(), trackPion.globalIndex(), - hfFlag); + std::sqrt(dcaDs.getSigmaY2()), std::sqrt(dcaPion.getSigmaY2())); + + rowCandidateProngs(candDs.globalIndex(), trackPion.globalIndex()); } // pi loop - } // Ds loop - } // collision loop - } // process -}; // struct + } // Ds loop + } // collision loop + } // process +}; // struct /// Extends the base table with expression columns and performs MC matching. struct HfCandidateCreatorBsExpressions { @@ -357,13 +360,11 @@ struct HfCandidateCreatorBsExpressions { void init(InitContext const&) {} - void processMc(aod::HfCand3Prong const& ds, - aod::TracksWMc const& tracks, - aod::McParticles const& mcParticles) + void processMc(aod::HfCand3Prong const&, + aod::TracksWMc const&, + aod::McParticles const& mcParticles, + aod::HfCandBsProngs const& candsBs) { - rowCandidateBs->bindExternalIndices(&tracks); - rowCandidateBs->bindExternalIndices(&ds); - int indexRec = -1; int8_t sign = 0; int8_t flag = 0; @@ -372,8 +373,7 @@ struct HfCandidateCreatorBsExpressions { std::array arrPDGResonantDsPhiPi = {Pdg::kPhi, kPiPlus}; // Ds± → Phi π± // Match reconstructed candidates. - // Spawned table can be used directly - for (const auto& candidate : *rowCandidateBs) { + for (const auto& candidate : candsBs) { flag = 0; arrDaughDsIndex.clear(); auto candDs = candidate.prong0(); @@ -398,7 +398,7 @@ struct HfCandidateCreatorBsExpressions { arrPDGDaughDs[iProng] = std::abs(daughI.pdgCode()); } if ((arrPDGDaughDs[0] == arrPDGResonantDsPhiPi[0] && arrPDGDaughDs[1] == arrPDGResonantDsPhiPi[1]) || (arrPDGDaughDs[0] == arrPDGResonantDsPhiPi[1] && arrPDGDaughDs[1] == arrPDGResonantDsPhiPi[0])) { - flag = sign * BIT(hf_cand_bs::DecayTypeMc::BsToDsPiToKKPiPi); + flag = sign * BIT(hf_cand_bs::DecayTypeMc::BsToDsPiToPhiPiPiToKKPiPi); } } } @@ -418,7 +418,7 @@ struct HfCandidateCreatorBsExpressions { arrPDGDaughDs[iProng] = std::abs(daughI.pdgCode()); } if ((arrPDGDaughDs[0] == arrPDGResonantDsPhiPi[0] && arrPDGDaughDs[1] == arrPDGResonantDsPhiPi[1]) || (arrPDGDaughDs[0] == arrPDGResonantDsPhiPi[1] && arrPDGDaughDs[1] == arrPDGResonantDsPhiPi[0])) { - flag = sign * BIT(hf_cand_bs::DecayTypeMc::B0ToDsPiToKKPiPi); + flag = sign * BIT(hf_cand_bs::DecayTypeMc::B0ToDsPiToPhiPiPiToKKPiPi); } } } @@ -471,7 +471,7 @@ struct HfCandidateCreatorBsExpressions { arrPDGDaughDs[jProng] = std::abs(daughJ.pdgCode()); } if ((arrPDGDaughDs[0] == arrPDGResonantDsPhiPi[0] && arrPDGDaughDs[1] == arrPDGResonantDsPhiPi[1]) || (arrPDGDaughDs[0] == arrPDGResonantDsPhiPi[1] && arrPDGDaughDs[1] == arrPDGResonantDsPhiPi[0])) { - flag = sign * BIT(hf_cand_bs::DecayTypeMc::BsToDsPiToKKPiPi); + flag = sign * BIT(hf_cand_bs::DecayTypeMc::BsToDsPiToPhiPiPiToKKPiPi); } } } @@ -490,7 +490,7 @@ struct HfCandidateCreatorBsExpressions { arrPDGDaughDs[jProng] = std::abs(daughJ.pdgCode()); } if ((arrPDGDaughDs[0] == arrPDGResonantDsPhiPi[0] && arrPDGDaughDs[1] == arrPDGResonantDsPhiPi[1]) || (arrPDGDaughDs[0] == arrPDGResonantDsPhiPi[1] && arrPDGDaughDs[1] == arrPDGResonantDsPhiPi[0])) { - flag = sign * BIT(hf_cand_bs::DecayTypeMc::B0ToDsPiToKKPiPi); + flag = sign * BIT(hf_cand_bs::DecayTypeMc::B0ToDsPiToPhiPiPiToKKPiPi); } } } @@ -499,7 +499,7 @@ struct HfCandidateCreatorBsExpressions { rowMcMatchGen(flag); } // gen - } // processMc + } // processMc PROCESS_SWITCH(HfCandidateCreatorBsExpressions, processMc, "Process MC", false); }; // struct diff --git a/PWGHF/TableProducer/candidateCreatorCascade.cxx b/PWGHF/TableProducer/candidateCreatorCascade.cxx index f3bb5526750..23c26f7ae7c 100644 --- a/PWGHF/TableProducer/candidateCreatorCascade.cxx +++ b/PWGHF/TableProducer/candidateCreatorCascade.cxx @@ -15,6 +15,10 @@ /// \author Chiara Zampolli, , CERN /// Paul Buehler, , Vienna +#include +#include +#include + #include #include "CommonConstants/PhysicsConstants.h" @@ -22,11 +26,14 @@ #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" #include "ReconstructionDataFormats/DCA.h" #include "ReconstructionDataFormats/V0.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" #include "Common/Core/trackUtilities.h" +#include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" #include "PWGHF/Utils/utilsEvSelHf.h" @@ -36,7 +43,7 @@ using namespace o2; using namespace o2::analysis; using namespace o2::hf_evsel; using namespace o2::hf_trkcandsel; -using namespace o2::aod::hf_collision_centrality; +using namespace o2::hf_centrality; using namespace o2::constants::physics; using namespace o2::framework; @@ -44,13 +51,6 @@ using namespace o2::framework; struct HfCandidateCreatorCascade { Produces rowCandidateBase; - // centrality - Configurable centralityMin{"centralityMin", 0., "Minimum centrality"}; - Configurable centralityMax{"centralityMax", 100., "Maximum centrality"}; - // event selection - Configurable useSel8Trigger{"useSel8Trigger", true, "apply the sel8 event selection"}; - Configurable zPvPosMax{"zPvPosMax", 10.f, "max. PV posZ (cm)"}; - Configurable useTimeFrameBorderCut{"useTimeFrameBorderCut", true, "apply TF border cut"}; // vertexing // Configurable bz{"bz", 5., "magnetic field"}; Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; @@ -69,6 +69,7 @@ struct HfCandidateCreatorCascade { Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + HfEventSelection hfEvSel; // event selection and monitoring o2::vertexing::DCAFitterN<2> df; // 2-prong vertex fitter Service ccdb; o2::base::MatLayerCylSet* lut; @@ -82,7 +83,10 @@ struct HfCandidateCreatorCascade { double mass2K0sP{0.}; double bz = 0.; - std::shared_ptr hCollisions, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel, hCandidates; + using V0full = soa::Join; + using V0fCfull = soa::Join; + + std::shared_ptr hCandidates; HistogramRegistry registry{"registry"}; void init(InitContext const&) @@ -113,13 +117,8 @@ struct HfCandidateCreatorCascade { registry.add("hMass2", "2-prong candidates;inv. mass (p K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 2.05, 2.55}}}); registry.add("hCovPVXX", "2-prong candidates;XX element of cov. matrix of prim. vtx. position (cm^{2});entries", {HistType::kTH1F, {{100, 0., 1.e-4}}}); registry.add("hCovSVXX", "2-prong candidates;XX element of cov. matrix of sec. vtx. position (cm^{2});entries", {HistType::kTH1F, {{100, 0., 0.2}}}); - hCollisions = registry.add("hCollisions", "HF event counter;;entries", {HistType::kTH1D, {axisEvents}}); - hPosZBeforeEvSel = registry.add("hPosZBeforeEvSel", "all events;#it{z}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{400, -20., 20.}}}); - hPosZAfterEvSel = registry.add("hPosZAfterEvSel", "selected events;#it{z}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{400, -20., 20.}}}); - hPosXAfterEvSel = registry.add("hPosXAfterEvSel", "selected events;#it{x}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{200, -0.5, 0.5}}}); - hPosYAfterEvSel = registry.add("hPosYAfterEvSel", "selected events;#it{y}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{200, -0.5, 0.5}}}); - hNumPvContributorsAfterSel = registry.add("hNumPvContributorsAfterSel", "selected events;#it{y}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{500, -0.5, 499.5}}}); hCandidates = registry.add("hCandidates", "candidates counter", {HistType::kTH1D, {axisCands}}); + hfEvSel.addHistograms(registry); // collision monitoring massP = MassProton; massK0s = MassK0Short; @@ -141,29 +140,27 @@ struct HfCandidateCreatorCascade { lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); runNumber = 0; - /// collision monitoring - setLabelHistoEvSel(hCollisions); - /// candidate monitoring setLabelHistoCands(hCandidates); } - template + template void runCreatorCascade(Coll const&, aod::HfCascades const& rowsTrackIndexCasc, aod::V0sLinked const&, - aod::V0Datas const&, - aod::V0fCDatas const&, + V0full const&, + V0fCfull const&, aod::TracksWCov const&, - aod::BCsWithTimestamps const&) + aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { + // loop over pairs of track indices for (const auto& casc : rowsTrackIndexCasc) { - /// reject candidates in collisions not satisfying the event selections auto collision = casc.template collision_as(); + /// reject candidates in collisions not satisfying the event selections float centrality{-1.f}; - const auto rejectionMask = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, -1, useTimeFrameBorderCut, -zPvPosMax, zPvPosMax, 0, -1.f); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); if (rejectionMask != 0) { /// at least one event selection not satisfied --> reject the candidate continue; @@ -177,26 +174,22 @@ struct HfCandidateCreatorCascade { } int posGlobalIndex = -1, negGlobalIndex = -1; - float v0x, v0y, v0z, v0px, v0py, v0pz; + float v0X, v0Y, v0Z, v0px, v0py, v0pz; float v0PosPx, v0PosPy, v0PosPz, v0NegPx, v0NegPy, v0NegPz; float dcaV0dau, dcaPosToPV, dcaNegToPV, v0cosPA; - float posTrackX, negTrackX; - o2::track::TrackParCov trackParCovV0DaughPos; - o2::track::TrackParCov trackParCovV0DaughNeg; + std::array covV = {0.}; - auto v0index = casc.v0_as(); + auto v0index = casc.template v0_as(); if (v0index.has_v0Data()) { // this V0 passed both standard V0 and cascade V0 selections - auto v0row = v0index.v0Data(); + auto v0row = v0index.template v0Data_as(); const auto& trackV0DaughPos = v0row.posTrack_as(); const auto& trackV0DaughNeg = v0row.negTrack_as(); - trackParCovV0DaughPos = getTrackParCov(trackV0DaughPos); // check that aod::TracksWCov does not need TracksDCA! - trackParCovV0DaughNeg = getTrackParCov(trackV0DaughNeg); // check that aod::TracksWCov does not need TracksDCA! posGlobalIndex = trackV0DaughPos.globalIndex(); negGlobalIndex = trackV0DaughNeg.globalIndex(); - v0x = v0row.x(); - v0y = v0row.y(); - v0z = v0row.z(); + v0X = v0row.x(); + v0Y = v0row.y(); + v0Z = v0row.z(); v0px = v0row.px(); v0py = v0row.py(); v0pz = v0row.pz(); @@ -210,20 +203,22 @@ struct HfCandidateCreatorCascade { dcaPosToPV = v0row.dcapostopv(); dcaNegToPV = v0row.dcanegtopv(); v0cosPA = v0row.v0cosPA(); - posTrackX = v0row.posX(); - negTrackX = v0row.negX(); + + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 6; i++) { + covV[MomInd[i]] = v0row.momentumCovMat()[i]; + covV[i] = v0row.positionCovMat()[i]; + } } else if (v0index.has_v0fCData()) { // this V0 passes only V0-for-cascade selections, use that instead - auto v0row = v0index.v0fCData(); + auto v0row = v0index.template v0fCData_as(); const auto& trackV0DaughPos = v0row.posTrack_as(); const auto& trackV0DaughNeg = v0row.negTrack_as(); - trackParCovV0DaughPos = getTrackParCov(trackV0DaughPos); // check that aod::TracksWCov does not need TracksDCA! - trackParCovV0DaughNeg = getTrackParCov(trackV0DaughNeg); // check that aod::TracksWCov does not need TracksDCA! posGlobalIndex = trackV0DaughPos.globalIndex(); negGlobalIndex = trackV0DaughNeg.globalIndex(); - v0x = v0row.x(); - v0y = v0row.y(); - v0z = v0row.z(); + v0X = v0row.x(); + v0Y = v0row.y(); + v0Z = v0row.z(); v0px = v0row.px(); v0py = v0row.py(); v0pz = v0row.pz(); @@ -237,8 +232,12 @@ struct HfCandidateCreatorCascade { dcaPosToPV = v0row.dcapostopv(); dcaNegToPV = v0row.dcanegtopv(); v0cosPA = v0row.v0cosPA(); - posTrackX = v0row.posX(); - negTrackX = v0row.negX(); + + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 6; i++) { + covV[MomInd[i]] = v0row.momentumCovMat()[i]; + covV[i] = v0row.positionCovMat()[i]; + } } else { LOGF(warning, "V0Data/V0fCData not there for V0 %d in HF cascade %d. Skipping candidate.", casc.v0Id(), casc.globalIndex()); continue; // this was inadequately linked, should not happen @@ -255,24 +254,24 @@ struct HfCandidateCreatorCascade { } df.setBz(bz); - auto trackParCovBach = getTrackParCov(bach); - trackParCovV0DaughPos.propagateTo(posTrackX, bz); // propagate the track to the X closest to the V0 vertex - trackParCovV0DaughNeg.propagateTo(negTrackX, bz); // propagate the track to the X closest to the V0 vertex - const std::array vertexV0 = {v0x, v0y, v0z}; + auto trackBach = getTrackParCov(bach); + const std::array vertexV0 = {v0X, v0Y, v0Z}; const std::array momentumV0 = {v0px, v0py, v0pz}; // we build the neutral track to then build the cascade - auto trackV0 = o2::dataformats::V0(vertexV0, momentumV0, {0, 0, 0, 0, 0, 0}, trackParCovV0DaughPos, trackParCovV0DaughNeg); // build the V0 track (indices for v0 daughters set to 0 for now) + auto trackV0 = o2::track::TrackParCov(vertexV0, momentumV0, covV, 0, true); + trackV0.setAbsCharge(0); + trackV0.setPID(o2::track::PID::K0); // reconstruct the cascade secondary vertex hCandidates->Fill(SVFitting::BeforeFit); try { - if (df.process(trackV0, trackParCovBach) == 0) { + if (df.process(trackV0, trackBach) == 0) { continue; } else { - // LOG(info) << "Vertexing succeeded for Lc candidate"; + LOG(debug) << "Vertexing succeeded for Lc candidate"; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN cannot work, skipping the candidate."; + LOG(debug) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; hCandidates->Fill(SVFitting::Fail); continue; } @@ -319,8 +318,7 @@ struct HfCandidateCreatorCascade { impactParameterBach.getY(), impactParameterV0.getY(), std::sqrt(impactParameterBach.getSigmaY2()), std::sqrt(impactParameterV0.getSigmaY2()), casc.prong0Id(), casc.v0Id(), - v0x, v0y, v0z, - // v0.posTrack(), v0.negTrack(), // why this was not fine? + v0X, v0Y, v0Z, posGlobalIndex, negGlobalIndex, v0PosPx, v0PosPy, v0PosPz, v0NegPx, v0NegPy, v0NegPz, @@ -344,12 +342,12 @@ struct HfCandidateCreatorCascade { void processNoCent(soa::Join const& collisions, aod::HfCascades const& rowsTrackIndexCasc, aod::V0sLinked const& v0sLinked, - aod::V0Datas const& v0Data, - aod::V0fCDatas const& v0fCDatas, + V0full const& v0Full, + V0fCfull const& v0fcFull, aod::TracksWCov const& tracks, aod::BCsWithTimestamps const& bcs) { - runCreatorCascade(collisions, rowsTrackIndexCasc, v0sLinked, v0Data, v0fCDatas, tracks, bcs); + runCreatorCascade(collisions, rowsTrackIndexCasc, v0sLinked, v0Full, v0fcFull, tracks, bcs); } PROCESS_SWITCH(HfCandidateCreatorCascade, processNoCent, " Run candidate creator w/o centrality selections", true); @@ -357,12 +355,12 @@ struct HfCandidateCreatorCascade { void processCentFT0C(soa::Join const& collisions, aod::HfCascades const& rowsTrackIndexCasc, aod::V0sLinked const& v0sLinked, - aod::V0Datas const& v0Data, - aod::V0fCDatas const& v0fCDatas, + V0full const& v0Full, + V0fCfull const& v0fcFull, aod::TracksWCov const& tracks, aod::BCsWithTimestamps const& bcs) { - runCreatorCascade(collisions, rowsTrackIndexCasc, v0sLinked, v0Data, v0fCDatas, tracks, bcs); + runCreatorCascade(collisions, rowsTrackIndexCasc, v0sLinked, v0Full, v0fcFull, tracks, bcs); } PROCESS_SWITCH(HfCandidateCreatorCascade, processCentFT0C, " Run candidate creator w/ centrality selection on FT0C", false); @@ -370,12 +368,12 @@ struct HfCandidateCreatorCascade { void processCentFT0M(soa::Join const& collisions, aod::HfCascades const& rowsTrackIndexCasc, aod::V0sLinked const& v0sLinked, - aod::V0Datas const& v0Data, - aod::V0fCDatas const& v0fCDatas, + V0full const& v0Full, + V0fCfull const& v0fcFull, aod::TracksWCov const& tracks, aod::BCsWithTimestamps const& bcs) { - runCreatorCascade(collisions, rowsTrackIndexCasc, v0sLinked, v0Data, v0fCDatas, tracks, bcs); + runCreatorCascade(collisions, rowsTrackIndexCasc, v0sLinked, v0Full, v0fcFull, tracks, bcs); } PROCESS_SWITCH(HfCandidateCreatorCascade, processCentFT0M, " Run candidate creator w/ centrality selection on FT0M", false); @@ -386,51 +384,51 @@ struct HfCandidateCreatorCascade { /////////////////////////////////////////////////////////// /// @brief process function to monitor collisions - no centrality - void processCollisions(soa::Join const& collisions) + void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { /// bitmask with event. selection info float centrality{-1.f}; - const auto rejectionMask = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, -1, useTimeFrameBorderCut, -zPvPosMax, zPvPosMax, 0, -1.f); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); /// monitor the satisfied event selections - monitorCollision(collision, rejectionMask, hCollisions, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel); + hfEvSel.fillHistograms(collision, rejectionMask, centrality); } /// end loop over collisions } PROCESS_SWITCH(HfCandidateCreatorCascade, processCollisions, "Collision monitoring - no centrality", true); /// @brief process function to monitor collisions - FT0C centrality - void processCollisionsCentFT0C(soa::Join const& collisions) + void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { /// bitmask with event. selection info float centrality{-1.f}; - const auto rejectionMask = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, -1, useTimeFrameBorderCut, -zPvPosMax, zPvPosMax, 0, -1.f); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); /// monitor the satisfied event selections - monitorCollision(collision, rejectionMask, hCollisions, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel); + hfEvSel.fillHistograms(collision, rejectionMask, centrality); } /// end loop over collisions } PROCESS_SWITCH(HfCandidateCreatorCascade, processCollisionsCentFT0C, "Collision monitoring - FT0C centrality", false); /// @brief process function to monitor collisions - FT0M centrality - void processCollisionsCentFT0M(soa::Join const& collisions) + void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { /// bitmask with event. selection info float centrality{-1.f}; - const auto rejectionMask = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, -1, useTimeFrameBorderCut, -zPvPosMax, zPvPosMax, 0, -1.f); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); /// monitor the satisfied event selections - monitorCollision(collision, rejectionMask, hCollisions, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel); + hfEvSel.fillHistograms(collision, rejectionMask, centrality); } /// end loop over collisions } @@ -443,23 +441,59 @@ struct HfCandidateCreatorCascadeMc { Produces rowMcMatchRec; Produces rowMcMatchGen; + // Configuration + Configurable rejectBackground{"rejectBackground", true, "Reject particles from background events"}; + + HfEventSelectionMc hfEvSelMc; // mc event selection and monitoring + using MyTracksWMc = soa::Join; + using BCsInfo = soa::Join; + using McCollisionsNoCents = soa::Join; + using McCollisionsFT0Cs = soa::Join; + using McCollisionsFT0Ms = soa::Join; + using McCollisionsCentFT0Ms = soa::Join; - void processMc(MyTracksWMc const& tracks, - aod::McParticles const& mcParticles) + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + PresliceUnsorted colPerMcCollisionFT0C = aod::mccollisionlabel::mcCollisionId; + PresliceUnsorted colPerMcCollisionFT0M = aod::mccollisionlabel::mcCollisionId; + + HistogramRegistry registry{"registry"}; + + // inspect for which zPvPosMax cut was set for reconstructed + void init(InitContext& initContext) { - int8_t sign = 0; - int8_t origin = 0; - int indexRec = -1; - std::vector arrDaughLcIndex; - std::array arrDaughLcPDG; - std::array arrDaughLcPDGRef = {+kProton, +kPiPlus, -kPiPlus}; + std::array procCollisions = {doprocessMc, doprocessMcCentFT0C, doprocessMcCentFT0M}; + if (std::accumulate(procCollisions.begin(), procCollisions.end(), 0) > 1) { + LOGP(fatal, "At most one process function for collision study can be enabled at a time."); + } + + const auto& workflows = initContext.services().get(); + for (const DeviceSpec& device : workflows.devices) { + if (device.name.compare("hf-candidate-creator-cascade") == 0) { + hfEvSelMc.configureFromDevice(device); + break; + } + } + hfEvSelMc.addHistograms(registry); // particles monitoring + } + template + void runCreatorCascMc(MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + CCs const& collInfos, + McCollisions const& mcCollisions, + BCsInfo const&) + { // Match reconstructed candidates. rowCandidateCasc->bindExternalIndices(&tracks); for (const auto& candidate : *rowCandidateCasc) { - origin = 0; + int8_t sign = 0; + int8_t origin = 0; + int indexRec = -1; + + std::vector idxBhadMothers{}; const auto& bach = candidate.prong0_as(); const auto& trackV0DaughPos = candidate.posTrack_as(); @@ -467,63 +501,148 @@ struct HfCandidateCreatorCascadeMc { auto arrayDaughtersV0 = std::array{trackV0DaughPos, trackV0DaughNeg}; auto arrayDaughtersLc = std::array{bach, trackV0DaughPos, trackV0DaughNeg}; + // Check whether the particle is from background events. If so, reject it. + if (rejectBackground) { + bool fromBkg{false}; + for (const auto& daughter : arrayDaughtersLc) { + if (daughter.has_mcParticle()) { + auto mcParticle = daughter.mcParticle(); + if (mcParticle.fromBackgroundEvent()) { + fromBkg = true; + break; + } + } + } + if (fromBkg) { + rowMcMatchRec(sign, origin, -1.f, 0); + continue; + } + } - // First we check the K0s - LOG(debug) << "\n"; - LOG(debug) << "Checking MC for candidate!"; - LOG(debug) << "Looking for K0s"; - - // if (isLc) { - RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, kK0Short, std::array{+kPiPlus, -kPiPlus}, false, &sign, 1); - if (sign != 0) { // we have already positively checked the K0s + int indexK0SRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, kK0Short, std::array{+kPiPlus, -kPiPlus}, false, &sign, 1); + if (indexK0SRec >= 0) { // we have already positively checked the K0s // then we check the Lc - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersLc, Pdg::kLambdaCPlus, std::array{+kProton, +kPiPlus, -kPiPlus}, true, &sign, 3); // 3-levels Lc --> p + K0 --> p + K0s --> p + pi+ pi- + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersLc, Pdg::kLambdaCPlus, std::array{+kProton, +kPiPlus, -kPiPlus}, true, &sign, 3); // 3-levels Lc --> p + K0 --> p + K0s --> p + pi+ pi- } // Check whether the particle is non-prompt (from a b quark). - if (sign != 0) { + if (indexRec >= 0) { auto particle = mcParticles.rawIteratorAt(indexRec); - origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle); + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + } + if (origin == RecoDecay::OriginType::NonPrompt) { + auto bHadMother = mcParticles.rawIteratorAt(idxBhadMothers[0]); + rowMcMatchRec(sign, origin, bHadMother.pt(), bHadMother.pdgCode()); + } else { + rowMcMatchRec(sign, origin, -1.f, 0); } - - rowMcMatchRec(sign, origin); } - //} - - // Match generated particles. - for (const auto& particle : mcParticles) { - origin = 0; - // checking if I have a Lc --> K0S + p - RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kLambdaCPlus, std::array{+kProton, +kK0Short}, false, &sign, 2); - if (sign == 0) { // now check for anti-Lc - RecoDecay::isMatchedMCGen(mcParticles, particle, -Pdg::kLambdaCPlus, std::array{-kProton, +kK0Short}, false, &sign, 2); - sign = -sign; + + for (const auto& mcCollision : mcCollisions) { + + // Slice the MC particles table to get the particles for the current MC collision + const auto mcParticlesPerMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, mcCollision.globalIndex()); + // Slice the collisions table to get the collision info for the current MC collision + float centrality{-1.f}; + uint16_t rejectionMask{0}; + int nSplitColl = 0; + if constexpr (centEstimator == CentralityEstimator::FT0C) { + const auto collSlice = collInfos.sliceBy(colPerMcCollisionFT0C, mcCollision.globalIndex()); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } else if constexpr (centEstimator == CentralityEstimator::FT0M) { + const auto collSlice = collInfos.sliceBy(colPerMcCollisionFT0M, mcCollision.globalIndex()); + nSplitColl = collSlice.size(); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } else if constexpr (centEstimator == CentralityEstimator::None) { + const auto collSlice = collInfos.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); } - if (sign != 0) { - arrDaughLcIndex.clear(); - // checking that the final daughters (decay depth = 3) are p, pi+, pi- - RecoDecay::getDaughters(particle, &arrDaughLcIndex, arrDaughLcPDGRef, 3); // best would be to check the K0S daughters - if (arrDaughLcIndex.size() == 3) { - for (std::size_t iProng = 0; iProng < arrDaughLcIndex.size(); ++iProng) { - auto daughI = mcParticles.rawIteratorAt(arrDaughLcIndex[iProng]); - arrDaughLcPDG[iProng] = daughI.pdgCode(); - } - if (!(arrDaughLcPDG[0] == sign * arrDaughLcPDGRef[0] && arrDaughLcPDG[1] == arrDaughLcPDGRef[1] && arrDaughLcPDG[2] == arrDaughLcPDGRef[2])) { // this should be the condition, first bach, then v0 - sign = 0; - } else { - LOG(debug) << "Lc --> K0S+p found in MC table"; - } + hfEvSelMc.fillHistograms(mcCollision, rejectionMask, nSplitColl); + if (rejectionMask != 0) { + // at least one event selection not satisfied --> reject all particles from this collision + for (unsigned int i = 0; i < mcParticlesPerMcColl.size(); ++i) { + rowMcMatchGen(0, 0, -1); } + continue; } - // Check whether the particle is non-prompt (from a b quark). - if (sign != 0) { - origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle); + + // Match generated particles. + for (const auto& particle : mcParticlesPerMcColl) { + + int8_t sign = 0; + int8_t origin = 0; + int8_t flag = 0; + + std::vector idxBhadMothers{}; + // Reject particles from background events + if (particle.fromBackgroundEvent() && rejectBackground) { + rowMcMatchGen(sign, origin, -1); + continue; + } + // checking if I have a Lc --> K0S + p + RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kLambdaCPlus, std::array{+kProton, +kK0Short}, false, &sign, 2); + if (sign == 0) { // now check for anti-Lc + RecoDecay::isMatchedMCGen(mcParticles, particle, -Pdg::kLambdaCPlus, std::array{-kProton, +kK0Short}, false, &sign, 2); + sign = -sign; + } + if (sign != 0) { + // we check the K0S + for (const auto& daughterK0 : particle.template daughters_as()) { + if (std::abs(daughterK0.pdgCode()) != kK0) { + continue; + } + for (const auto& daughterK0S : daughterK0.template daughters_as()) { + if (daughterK0S.pdgCode() != kK0Short) { + continue; + } + if (RecoDecay::isMatchedMCGen(mcParticles, daughterK0S, kK0Short, std::array{+kPiPlus, -kPiPlus}, true)) { + flag = sign; + } + } + } + } + // Check whether the particle is non-prompt (from a b quark). + if (flag != 0) { + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + } + if (origin == RecoDecay::OriginType::NonPrompt) { + rowMcMatchGen(flag, origin, idxBhadMothers[0]); + } else { + rowMcMatchGen(flag, origin, -1); + } } - rowMcMatchGen(sign, origin); } } - PROCESS_SWITCH(HfCandidateCreatorCascadeMc, processMc, "Process MC data", false); + void processMc(MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions, + BCsInfo const& BCsInfo) + { + runCreatorCascMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + } + PROCESS_SWITCH(HfCandidateCreatorCascadeMc, processMc, "Process MC - no centrality", false); + + void processMcCentFT0C(MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisionsFT0Cs const& collInfos, + aod::McCollisions const& mcCollisions, + BCsInfo const& BCsInfo) + { + runCreatorCascMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + } + PROCESS_SWITCH(HfCandidateCreatorCascadeMc, processMcCentFT0C, "Process MC - FT0c centrality", false); + + void processMcCentFT0M(MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisionsFT0Ms const& collInfos, + McCollisionsCentFT0Ms const& mcCollisions, + BCsInfo const& BCsInfo) + { + runCreatorCascMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + } + PROCESS_SWITCH(HfCandidateCreatorCascadeMc, processMcCentFT0M, "Process MC - FT0m centrality", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/TableProducer/candidateCreatorDstar.cxx b/PWGHF/TableProducer/candidateCreatorDstar.cxx index 524d7982884..110edad7cfb 100644 --- a/PWGHF/TableProducer/candidateCreatorDstar.cxx +++ b/PWGHF/TableProducer/candidateCreatorDstar.cxx @@ -15,7 +15,10 @@ /// \author Vít Kučera , CERN /// \author Deependra Sharma , IITB /// \author Fabrizio Grosa , CERN - +// std +#include +#include +#include // ROOT #include // O2 @@ -24,9 +27,11 @@ #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" // O2Physics #include "Common/Core/trackUtilities.h" // PWGHF +#include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" #include "PWGHF/Utils/utilsEvSelHf.h" @@ -35,7 +40,7 @@ using namespace o2; using namespace o2::hf_evsel; using namespace o2::hf_trkcandsel; -using namespace o2::aod::hf_collision_centrality; +using namespace o2::hf_centrality; using namespace o2::constants::physics; using namespace o2::framework; @@ -58,15 +63,6 @@ struct HfCandidateCreatorDstar { Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; - // centrality - Configurable centralityMin{"centralityMin", 0., "Minimum centrality"}; - Configurable centralityMax{"centralityMax", 100., "Maximum centrality"}; - - // event selection - Configurable useSel8Trigger{"useSel8Trigger", true, "apply the sel8 event selection"}; - Configurable zPvPosMax{"zPvPosMax", 10.f, "max. PV posZ (cm)"}; - Configurable useTimeFrameBorderCut{"useTimeFrameBorderCut", true, "apply TF border cut"}; - // vertexing Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; // ........... what is unit of this? @@ -76,6 +72,7 @@ struct HfCandidateCreatorDstar { Configurable useAbsDCA{"useAbsDCA", false, "Minimise abs. distance rather than chi2"}; Configurable useWeightedFinalPCA{"useWeightedFinalPCA", false, "Recalculate vertex position using track covariances, effective only if useAbsDCA is true"}; + HfEventSelection hfEvSel; // event selection and monitoring Service ccdb; // From utilsBfieldCCDB.h o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; // D0-prong vertex fitter @@ -88,7 +85,7 @@ struct HfCandidateCreatorDstar { AxisSpec ptAxis = {100, 0., 2.0, "#it{p}_{T} (GeV/#it{c}"}; AxisSpec dcaAxis = {200, -500., 500., "#it{d}_{xy,z} (#mum)"}; - std::shared_ptr hCollisions, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel, hCandidates; + std::shared_ptr hCandidates; HistogramRegistry registry{ "registry", {{"Refit/hCovPVXX", "2-prong candidates;XX element of cov. matrix of prim. vtx. position (cm^{2});entries", {HistType::kTH1F, {{100, 0., 1.e-4}}}}, @@ -138,14 +135,8 @@ struct HfCandidateCreatorDstar { } } - // histograms (evSel) - hCollisions = registry.add("EvSel/hCollisions", "HF event counter;;entries", {HistType::kTH1D, {axisEvents}}); - hPosZBeforeEvSel = registry.add("EvSel/hPosZBeforeEvSel", "all events;#it{z}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{400, -20., 20.}}}); - hPosZAfterEvSel = registry.add("EvSel/hPosZAfterEvSel", "selected events;#it{z}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{400, -20., 20.}}}); - hPosXAfterEvSel = registry.add("EvSel/hPosXAfterEvSel", "selected events;#it{x}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{200, -0.5, 0.5}}}); - hPosYAfterEvSel = registry.add("EvSel/hPosYAfterEvSel", "selected events;#it{y}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{200, -0.5, 0.5}}}); - hNumPvContributorsAfterSel = registry.add("EvSel/hNumPvContributorsAfterSel", "selected events;#it{y}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{500, -0.5, 499.5}}}); hCandidates = registry.add("hCandidates", "candidates counter", {HistType::kTH1D, {axisCands}}); + hfEvSel.addHistograms(registry); // collision monitoring // LOG(info) << "Init Function Invoked"; massPi = MassPiPlus; @@ -167,9 +158,6 @@ struct HfCandidateCreatorDstar { runNumber = 0; bz = 0; - /// collision monitoring - setLabelHistoEvSel(hCollisions); - /// candidate monitoring setLabelHistoCands(hCandidates); } @@ -182,12 +170,12 @@ struct HfCandidateCreatorDstar { /// @param rowsTrackIndexD0 D0 table object from trackIndexSkimCreator.cxx /// @param tracks track table with Cov object /// @param bcWithTimeStamps Bunch Crossing with timestamps - template + template void runCreatorDstar(Coll const&, CandsDstar const& rowsTrackIndexDstar, aod::Hf2Prongs const&, aod::TracksWCov const&, - aod::BCsWithTimestamps const&) + aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { // LOG(info) << "runCreatorDstar function called"; // LOG(info) << "candidate loop starts"; @@ -197,7 +185,7 @@ struct HfCandidateCreatorDstar { /// reject candidates in collisions not satisfying the event selections auto collision = rowTrackIndexDstar.template collision_as(); float centrality{-1.f}; - const auto rejectionMask = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, -1, useTimeFrameBorderCut, -zPvPosMax, zPvPosMax, 0, -1.f); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); if (rejectionMask != 0) { /// at least one event selection not satisfied --> reject the candidate continue; @@ -245,7 +233,7 @@ struct HfCandidateCreatorDstar { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN cannot work, skipping the candidate."; + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; hCandidates->Fill(SVFitting::Fail); continue; } @@ -337,7 +325,8 @@ struct HfCandidateCreatorDstar { rowTrackIndexDstar.prong0Id(), rowTrackIndexDstar.prongD0Id(), pVecSoftPi[0], pVecSoftPi[1], pVecSoftPi[2], signSoftPi, - impactParameterPi.getY(), std::sqrt(impactParameterPi.getSigmaY2()), + impactParameterPi.getY(), impactParameterPi.getZ(), + std::sqrt(impactParameterPi.getSigmaY2()), std::sqrt(impactParameterPi.getSigmaZ2()), pVecD0Prong0[0], pVecD0Prong0[1], pVecD0Prong0[2], pVecD0Prong1[0], pVecD0Prong1[1], pVecD0Prong1[2], prongD0.prong0Id(), prongD0.prong1Id()); @@ -350,7 +339,9 @@ struct HfCandidateCreatorDstar { pVecD0Prong0[0], pVecD0Prong0[1], pVecD0Prong0[2], pVecD0Prong1[0], pVecD0Prong1[1], pVecD0Prong1[2], impactParameter0.getY(), impactParameter1.getY(), + impactParameter0.getZ(), impactParameter1.getZ(), std::sqrt(impactParameter0.getSigmaY2()), std::sqrt(impactParameter1.getSigmaY2()), + std::sqrt(impactParameter0.getSigmaZ2()), std::sqrt(impactParameter1.getSigmaZ2()), prongD0.prong0Id(), prongD0.prong1Id(), prongD0.hfflag()); @@ -456,51 +447,51 @@ struct HfCandidateCreatorDstar { /////////////////////////////////////////////////////////// /// @brief process function to monitor collisions - no centrality - void processCollisions(soa::Join const& collisions) + void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { /// bitmask with event. selection info float centrality{-1.f}; - const auto rejectionMask = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, -1, useTimeFrameBorderCut, -zPvPosMax, zPvPosMax, 0, -1.f); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); /// monitor the satisfied event selections - monitorCollision(collision, rejectionMask, hCollisions, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel); + hfEvSel.fillHistograms(collision, rejectionMask, centrality); } /// end loop over collisions } PROCESS_SWITCH(HfCandidateCreatorDstar, processCollisions, "Collision monitoring - no centrality", true); /// @brief process function to monitor collisions - FT0C centrality - void processCollisionsCentFT0C(soa::Join const& collisions) + void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { /// bitmask with event. selection info float centrality{-1.f}; - const auto rejectionMask = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, -1, useTimeFrameBorderCut, -zPvPosMax, zPvPosMax, 0, -1.f); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); /// monitor the satisfied event selections - monitorCollision(collision, rejectionMask, hCollisions, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel); + hfEvSel.fillHistograms(collision, rejectionMask, centrality); } /// end loop over collisions } PROCESS_SWITCH(HfCandidateCreatorDstar, processCollisionsCentFT0C, "Collision monitoring - FT0C centrality", false); /// @brief process function to monitor collisions - FT0M centrality - void processCollisionsCentFT0M(soa::Join const& collisions) + void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { /// bitmask with event. selection info float centrality{-1.f}; - const auto rejectionMask = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, -1, useTimeFrameBorderCut, -zPvPosMax, zPvPosMax, 0, -1.f); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); /// monitor the satisfied event selections - monitorCollision(collision, rejectionMask, hCollisions, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel); + hfEvSel.fillHistograms(collision, rejectionMask, centrality); } /// end loop over collisions } @@ -509,18 +500,54 @@ struct HfCandidateCreatorDstar { struct HfCandidateCreatorDstarExpressions { Spawns rowsCandidateD0; - Produces rowsMcMatchRecD0; - Produces rowsMcMatchGenD0; - Spawns rowsCandidateDstar; Produces rowsMcMatchRecDstar; Produces rowsMcMatchGenDstar; - void init(InitContext const&) {} + // Configuration + Configurable rejectBackground{"rejectBackground", true, "Reject particles from background events"}; + Configurable matchKinkedDecayTopology{"matchKinkedDecayTopology", false, "Match also candidates with tracks that decay with kinked topology"}; + Configurable matchInteractionsWithMaterial{"matchInteractionsWithMaterial", false, "Match also candidates with tracks that interact with material"}; + + using McCollisionsNoCents = soa::Join; + using McCollisionsFT0Cs = soa::Join; + using McCollisionsFT0Ms = soa::Join; + using McCollisionsCentFT0Ms = soa::Join; + using BCsInfo = soa::Join; + + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + PresliceUnsorted colPerMcCollisionFT0C = aod::mccollisionlabel::mcCollisionId; + PresliceUnsorted colPerMcCollisionFT0M = aod::mccollisionlabel::mcCollisionId; + + HfEventSelectionMc hfEvSelMc; // mc event selection and monitoring + HistogramRegistry registry{"registry"}; + + // inspect for which zPvPosMax cut was set for reconstructed + void init(InitContext& initContext) + { + std::array procCollisions = {doprocessMc, doprocessMcCentFT0C, doprocessMcCentFT0M}; + if (std::accumulate(procCollisions.begin(), procCollisions.end(), 0) > 1) { + LOGP(fatal, "At most one process function for collision study can be enabled at a time."); + } + + const auto& workflows = initContext.services().get(); + for (const DeviceSpec& device : workflows.devices) { + if (device.name.compare("hf-candidate-creator-dstar") == 0) { + hfEvSelMc.configureFromDevice(device); + break; + } + } + hfEvSelMc.addHistograms(registry); // particles monitoring + } /// Perform MC Matching. - void processMc(aod::TracksWMc const& tracks, - aod::McParticles const& mcParticles) + template + void runCreatorDstarMc(aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles, + CCs const& collInfos, + McCollisions const& mcCollisions, + BCsInfo const&) { rowsCandidateD0->bindExternalIndices(&tracks); rowsCandidateDstar->bindExternalIndices(&tracks); @@ -528,14 +555,16 @@ struct HfCandidateCreatorDstarExpressions { int indexRecDstar = -1, indexRecD0 = -1; int8_t signDstar = 0, signD0 = 0; int8_t flagDstar = 0, flagD0 = 0; - int8_t originDstar = 0, originD0 = 0; + int8_t originDstar = 0; + int8_t nKinkedTracksDstar = 0, nKinkedTracksD0 = 0; + int8_t nInteractionsWithMaterialDstar = 0, nInteractionsWithMaterialD0 = 0; // Match reconstructed candidates. for (const auto& rowCandidateDstar : *rowsCandidateDstar) { flagDstar = 0; flagD0 = 0; originDstar = 0; - originD0 = 0; + std::vector idxBhadMothers{}; auto indexDstar = rowCandidateDstar.globalIndex(); auto candD0 = rowsCandidateD0->iteratorAt(indexDstar); @@ -544,10 +573,45 @@ struct HfCandidateCreatorDstarExpressions { auto arrayDaughtersDstar = std::array{candSoftPi, candD0.prong0_as(), candD0.prong1_as()}; auto arrayDaughtersofD0 = std::array{candD0.prong0_as(), candD0.prong1_as()}; - // D*± → D0(bar) π± - indexRecDstar = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersDstar, Pdg::kDStar, std::array{+kPiPlus, +kPiPlus, -kKPlus}, true, &signDstar, 2); - // D0(bar) → π± K∓ - indexRecD0 = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersofD0, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &signD0); + // Check whether the particle is from background events. If so, reject it. + if (rejectBackground) { + bool fromBkg{false}; + for (const auto& daughter : arrayDaughtersDstar) { + if (daughter.has_mcParticle()) { + auto mcParticle = daughter.mcParticle(); + if (mcParticle.fromBackgroundEvent()) { + fromBkg = true; + break; + } + } + } + if (fromBkg) { + rowsMcMatchRecDstar(flagDstar, flagD0, originDstar, -1.f, 0, 0, 0); + continue; + } + } + + if (matchKinkedDecayTopology && matchInteractionsWithMaterial) { + // D*± → D0(bar) π± + indexRecDstar = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersDstar, Pdg::kDStar, std::array{+kPiPlus, +kPiPlus, -kKPlus}, true, &signDstar, 2, &nKinkedTracksDstar, &nInteractionsWithMaterialDstar); + // D0(bar) → π± K∓ + indexRecD0 = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersofD0, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &signD0, 1, &nKinkedTracksD0, &nInteractionsWithMaterialD0); + } else if (matchKinkedDecayTopology && !matchInteractionsWithMaterial) { + // D*± → D0(bar) π± + indexRecDstar = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersDstar, Pdg::kDStar, std::array{+kPiPlus, +kPiPlus, -kKPlus}, true, &signDstar, 2, &nKinkedTracksDstar); + // D0(bar) → π± K∓ + indexRecD0 = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersofD0, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &signD0, 1, &nKinkedTracksD0); + } else if (!matchKinkedDecayTopology && matchInteractionsWithMaterial) { + // D*± → D0(bar) π± + indexRecDstar = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersDstar, Pdg::kDStar, std::array{+kPiPlus, +kPiPlus, -kKPlus}, true, &signDstar, 2, nullptr, &nInteractionsWithMaterialDstar); + // D0(bar) → π± K∓ + indexRecD0 = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersofD0, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &signD0, 1, nullptr, &nInteractionsWithMaterialD0); + } else { + // D*± → D0(bar) π± + indexRecDstar = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersDstar, Pdg::kDStar, std::array{+kPiPlus, +kPiPlus, -kKPlus}, true, &signDstar, 2); + // D0(bar) → π± K∓ + indexRecD0 = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersofD0, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &signD0); + } if (indexRecDstar > -1) { flagDstar = signDstar * (BIT(aod::hf_cand_dstar::DecayType::DstarToD0Pi)); @@ -556,47 +620,177 @@ struct HfCandidateCreatorDstarExpressions { flagD0 = signD0 * (BIT(aod::hf_cand_dstar::DecayType::D0ToPiK)); } + // check partly reconstructed decays, namely D0->Kpipi0 + if (indexRecDstar < 0 && indexRecD0) { + if (matchKinkedDecayTopology && matchInteractionsWithMaterial) { + // D*± → D0(bar) π± + indexRecDstar = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersDstar, Pdg::kDStar, std::array{+kPiPlus, +kPiPlus, -kKPlus}, true, &signDstar, 2, &nKinkedTracksDstar, &nInteractionsWithMaterialDstar); + // D0(bar) → π± K∓ + indexRecD0 = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersofD0, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &signD0, 1, &nKinkedTracksD0, &nInteractionsWithMaterialD0); + } else if (matchKinkedDecayTopology && !matchInteractionsWithMaterial) { + // D*± → D0(bar) π± + indexRecDstar = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersDstar, Pdg::kDStar, std::array{+kPiPlus, +kPiPlus, -kKPlus}, true, &signDstar, 2, &nKinkedTracksDstar); + // D0(bar) → π± K∓ + indexRecD0 = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersofD0, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &signD0, 1, &nKinkedTracksD0); + } else if (!matchKinkedDecayTopology && matchInteractionsWithMaterial) { + // D*± → D0(bar) π± + indexRecDstar = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersDstar, Pdg::kDStar, std::array{+kPiPlus, +kPiPlus, -kKPlus}, true, &signDstar, 2, nullptr, &nInteractionsWithMaterialDstar); + // D0(bar) → π± K∓ + indexRecD0 = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersofD0, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &signD0, 1, nullptr, &nInteractionsWithMaterialD0); + } else { + // D*± → D0(bar) π± + indexRecDstar = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersDstar, Pdg::kDStar, std::array{+kPiPlus, +kPiPlus, -kKPlus}, true, &signDstar, 2); + // D0(bar) → π± K∓ + indexRecD0 = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersofD0, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &signD0); + } + + if (indexRecDstar > -1) { + // D*± → D0(bar) π± π0 + auto motherParticleDstar = mcParticles.rawIteratorAt(indexRecDstar); + if (signDstar > 0) { + if (RecoDecay::isMatchedMCGen(mcParticles, motherParticleDstar, Pdg::kDStar, std::array{+kPiPlus, +kPiPlus, -kKPlus, +kPi0}, false, &signDstar, 2)) { + flagDstar = signDstar * (BIT(aod::hf_cand_dstar::DecayType::DstarToD0PiPi0)); + } + } else { + if (RecoDecay::isMatchedMCGen(mcParticles, motherParticleDstar, -Pdg::kDStar, std::array{-kPiPlus, -kPiPlus, +kKPlus, +kPi0}, false, &signDstar, 2)) { + flagDstar = signDstar * (BIT(aod::hf_cand_dstar::DecayType::DstarToD0PiPi0)); + } + } + } + if (indexRecD0 > -1) { + // D0(bar) → π± K∓ π0 + auto motherParticleD0 = mcParticles.rawIteratorAt(indexRecD0); + if (signD0 > 0) { + if (RecoDecay::isMatchedMCGen(mcParticles, motherParticleD0, Pdg::kD0, std::array{+kPiPlus, -kKPlus, +kPi0}, false, &signD0)) { + flagD0 = signD0 * (BIT(aod::hf_cand_dstar::DecayType::D0ToPiKPi0)); + } + } else { + if (RecoDecay::isMatchedMCGen(mcParticles, motherParticleD0, -Pdg::kD0, std::array{-kPiPlus, +kKPlus, +kPi0}, false, &signD0)) { + flagD0 = signD0 * (BIT(aod::hf_cand_dstar::DecayType::D0ToPiKPi0)); + } + } + } + } + // check wether the particle is non-promt (from a B0 hadron) if (flagDstar != 0) { auto particleDstar = mcParticles.iteratorAt(indexRecDstar); - originDstar = RecoDecay::getCharmHadronOrigin(mcParticles, particleDstar); + originDstar = RecoDecay::getCharmHadronOrigin(mcParticles, particleDstar, false, &idxBhadMothers); } - if (flagD0 != 0) { - auto particleD0 = mcParticles.iteratorAt(indexRecD0); - originD0 = RecoDecay::getCharmHadronOrigin(mcParticles, particleD0); + if (originDstar == RecoDecay::OriginType::NonPrompt) { + auto bHadMother = mcParticles.rawIteratorAt(idxBhadMothers[0]); + rowsMcMatchRecDstar(flagDstar, flagD0, originDstar, bHadMother.pt(), bHadMother.pdgCode(), nKinkedTracksDstar, nInteractionsWithMaterialDstar); + } else { + rowsMcMatchRecDstar(flagDstar, flagD0, originDstar, -1.f, 0, nKinkedTracksDstar, nInteractionsWithMaterialDstar); } - rowsMcMatchRecDstar(flagDstar, originDstar); - rowsMcMatchRecD0(flagD0, originD0); } - // Match generated particles. - for (const auto& particle : mcParticles) { - flagDstar = 0; - flagD0 = 0; - originDstar = 0; - originD0 = 0; - - // D*± → D0(bar) π± - if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kDStar, std::array{+kPiPlus, +kPiPlus, -kKPlus}, true, &signDstar, 2)) { - flagDstar = signDstar * (BIT(aod::hf_cand_dstar::DecayType::DstarToD0Pi)); + for (const auto& mcCollision : mcCollisions) { + // Slice the MC particles table to get the particles for the current MC collision + const auto mcParticlesPerMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, mcCollision.globalIndex()); + // Slice the collisions table to get the collision info for the current MC collision + float centrality{-1.f}; + uint16_t rejectionMask{0}; + int nSplitColl = 0; + if constexpr (centEstimator == CentralityEstimator::FT0C) { + const auto collSlice = collInfos.sliceBy(colPerMcCollisionFT0C, mcCollision.globalIndex()); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } else if constexpr (centEstimator == CentralityEstimator::FT0M) { + const auto collSlice = collInfos.sliceBy(colPerMcCollisionFT0M, mcCollision.globalIndex()); + nSplitColl = collSlice.size(); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } else if constexpr (centEstimator == CentralityEstimator::None) { + const auto collSlice = collInfos.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); } - // D0(bar) → π± K∓ - if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &signD0)) { - flagD0 = signD0 * (BIT(aod::hf_cand_dstar::DecayType::D0ToPiK)); + hfEvSelMc.fillHistograms(mcCollision, rejectionMask, nSplitColl); + if (rejectionMask != 0) { + // at least one event selection not satisfied --> reject all particles from this collision + for (unsigned int i = 0; i < mcParticlesPerMcColl.size(); ++i) { + rowsMcMatchGenDstar(0, 0, 0, -1); + } + continue; } - // check wether the particle is non-promt (from a B0 hadron) - if (flagDstar != 0) { - originDstar = RecoDecay::getCharmHadronOrigin(mcParticles, particle); - } - if (flagD0 != 0) { - originD0 = RecoDecay::getCharmHadronOrigin(mcParticles, particle); + // Match generated particles. + for (const auto& particle : mcParticlesPerMcColl) { + flagDstar = 0; + flagD0 = 0; + originDstar = 0; + std::vector idxBhadMothers{}; + // Reject particles from background events + if (particle.fromBackgroundEvent() && rejectBackground) { + rowsMcMatchGenDstar(flagDstar, flagD0, originDstar, -1); + continue; + } + + // D*± → D0(bar) π± + std::vector listIndexDaughters{}; + bool isDstarToDzeroPi = RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kDStar, std::array{+Pdg::kD0, +kPiPlus}, true, &signDstar, 1, &listIndexDaughters); + + // D0(bar) → π± K∓ + if (isDstarToDzeroPi) { + aod::McParticles::iterator particleD0; + for (const auto& dauIdx : listIndexDaughters) { + if (dauIdx >= 0) { + particleD0 = mcParticles.rawIteratorAt(dauIdx); + if (std::abs(particleD0.pdgCode()) == Pdg::kD0) { + break; + } + } + } + if (RecoDecay::isMatchedMCGen(mcParticles, particleD0, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &signD0)) { + flagDstar = signDstar * (BIT(aod::hf_cand_dstar::DecayType::DstarToD0Pi)); + flagD0 = signD0 * (BIT(aod::hf_cand_dstar::DecayType::D0ToPiK)); + } else if (RecoDecay::isMatchedMCGen(mcParticles, particleD0, Pdg::kD0, std::array{+kPiPlus, -kKPlus, +kPi0}, false, &signD0) || RecoDecay::isMatchedMCGen(mcParticles, particleD0, -Pdg::kD0, std::array{-kPiPlus, +kKPlus, +kPi0}, false, &signD0)) { + flagDstar = signDstar * (BIT(aod::hf_cand_dstar::DecayType::DstarToD0PiPi0)); + flagD0 = signD0 * (BIT(aod::hf_cand_dstar::DecayType::D0ToPiKPi0)); + } + } + + // check wether the particle is non-prompt (from a B0 hadron) + if (flagDstar != 0) { + originDstar = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + } + + if (originDstar == RecoDecay::OriginType::NonPrompt) { + rowsMcMatchGenDstar(flagDstar, flagD0, originDstar, idxBhadMothers[0]); + } else { + rowsMcMatchGenDstar(flagDstar, flagD0, originDstar, -1); + } } - rowsMcMatchGenDstar(flagDstar, originDstar); - rowsMcMatchGenD0(flagD0, originD0); } } - PROCESS_SWITCH(HfCandidateCreatorDstarExpressions, processMc, "Process MC", false); + + void processMc(aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions, + BCsInfo const& BCsInfo) + { + runCreatorDstarMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + } + PROCESS_SWITCH(HfCandidateCreatorDstarExpressions, processMc, "Process MC - no centrality", false); + + void processMcCentFT0C(aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisionsFT0Cs const& collInfos, + aod::McCollisions const& mcCollisions, + BCsInfo const& BCsInfo) + { + runCreatorDstarMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + } + PROCESS_SWITCH(HfCandidateCreatorDstarExpressions, processMcCentFT0C, "Process MC - FT0c centrality", false); + + void processMcCentFT0M(aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisionsFT0Ms const& collInfos, + McCollisionsCentFT0Ms const& mcCollisions, + BCsInfo const& BCsInfo) + { + runCreatorDstarMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + } + PROCESS_SWITCH(HfCandidateCreatorDstarExpressions, processMcCentFT0M, "Process MC - FT0m centrality", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/TableProducer/candidateCreatorLb.cxx b/PWGHF/TableProducer/candidateCreatorLb.cxx index cfdb723cac3..44062fca4f5 100644 --- a/PWGHF/TableProducer/candidateCreatorLb.cxx +++ b/PWGHF/TableProducer/candidateCreatorLb.cxx @@ -15,9 +15,13 @@ /// /// \author Panos Christakoglou , Nikhef +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "DCAFitter/DCAFitterN.h" #include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/DCA.h" #include "ReconstructionDataFormats/V0.h" @@ -36,31 +40,23 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::hf_trkcandsel; -void customize(std::vector& workflowOptions) -{ - ConfigParamSpec optionDoMC{"doMC", VariantType::Bool, true, {"Perform MC matching."}}; - workflowOptions.push_back(optionDoMC); -} - -#include "Framework/runDataProcessing.h" - /// Reconstruction of Λb candidates struct HfCandidateCreatorLb { Produces rowCandidateBase; // vertexing - Configurable bz{"bz", 20., "magnetic field"}; + Configurable bz{"bz", 20., "magnetic field"}; Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; Configurable useAbsDCA{"useAbsDCA", false, "Minimise abs. distance rather than chi2"}; Configurable useWeightedFinalPCA{"useWeightedFinalPCA", false, "Recalculate vertex position using track covariances, effective only if useAbsDCA is true"}; - Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; - Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; - Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any Lb is smaller than this"}; - Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations is chi2/chi2old > this"}; + Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; + Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; + Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any Lb is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations is chi2/chi2old > this"}; // selection - Configurable ptPionMin{"ptPionMin", 0.5, "minimum pion pT threshold (GeV/c)"}; + Configurable ptPionMin{"ptPionMin", 0.5, "minimum pion pT threshold (GeV/c)"}; Configurable selectionFlagLc{"selectionFlagLc", 1, "Selection Flag for Lc"}; - Configurable yCandMax{"yCandMax", -1., "max. cand. rapidity"}; + Configurable yCandMax{"yCandMax", -1., "max. cand. rapidity"}; o2::vertexing::DCAFitterN<2> df2; // 2-prong vertex fitter o2::vertexing::DCAFitterN<3> df3; // 3-prong vertex fitter (to rebuild Lc vertex) @@ -72,6 +68,9 @@ struct HfCandidateCreatorLb { Filter filterSelectCandidates = (aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLc || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLc); + std::shared_ptr hCandidatesLc, hCandidatesLb; + HistogramRegistry registry{"registry"}; + OutputObj hMassLcToPKPi{TH1F("hMassLcToPKPi", "#Lambda_{c}^{#plus} candidates;inv. mass (pK^{#minus} #pi^{#plus}) (GeV/#it{c}^{2});entries", 500, 0., 5.)}; OutputObj hPtLc{TH1F("hPtLc", "#Lambda_{c}^{#plus} candidates;#Lambda_{c}^{#plus} candidate #it{p}_{T} (GeV/#it{c});entries", 100, 0., 10.)}; OutputObj hPtPion{TH1F("hPtPion", "#pi^{#minus} candidates;#pi^{#minus} candidate #it{p}_{T} (GeV/#it{c});entries", 100, 0., 10.)}; @@ -80,9 +79,6 @@ struct HfCandidateCreatorLb { OutputObj hCovPVXX{TH1F("hCovPVXX", "2-prong candidates;XX element of cov. matrix of prim. vtx. position (cm^{2});entries", 100, 0., 1.e-4)}; OutputObj hCovSVXX{TH1F("hCovSVXX", "2-prong candidates;XX element of cov. matrix of sec. vtx. position (cm^{2});entries", 100, 0., 0.2)}; - std::shared_ptr hCandidatesLc, hCandidatesLb; - HistogramRegistry registry{"registry"}; - void init(InitContext const&) { massPi = MassPiMinus; @@ -139,7 +135,7 @@ struct HfCandidateCreatorLb { auto trackParVar0 = getTrackParCov(track0); auto trackParVar1 = getTrackParCov(track1); auto trackParVar2 = getTrackParCov(track2); - auto collision = track0.collision(); + auto collision = lcCand.collision(); // reconstruct the 3-prong secondary vertex hCandidatesLc->Fill(SVFitting::BeforeFit); @@ -148,7 +144,7 @@ struct HfCandidateCreatorLb { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN cannot work, skipping the candidate."; + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; hCandidatesLc->Fill(SVFitting::Fail); continue; } @@ -190,7 +186,7 @@ struct HfCandidateCreatorLb { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN cannot work, skipping the candidate."; + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; hCandidatesLb->Fill(SVFitting::Fail); continue; } @@ -246,26 +242,24 @@ struct HfCandidateCreatorLb { hMassLbToLcPi->Fill(massLcPi); } } // pi- loop - } // Lc loop - } // process -}; // struct + } // Lc loop + } // process +}; // struct /// Extends the base table with expression columns. struct HfCandidateCreatorLbExpressions { Spawns rowCandidateLb; + Produces rowMcMatchRec; + Produces rowMcMatchGen; void init(InitContext const&) {} -}; -/// Performs MC matching. -struct HfCandidateCreatorLbMc { - Produces rowMcMatchRec; - Produces rowMcMatchGen; + /// @brief dummy process function, to be run on data + void process(aod::Tracks const&) {} - void process(aod::HfCandLb const& candidates, - aod::HfCand3Prong const&, - aod::TracksWMc const&, - aod::McParticles const& mcParticles) + void processMc(aod::HfCand3Prong const& lcCandidates, + aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles) { int indexRec = -1; int8_t sign = 0; @@ -273,8 +267,11 @@ struct HfCandidateCreatorLbMc { int8_t origin = 0; int8_t debug = 0; + rowCandidateLb->bindExternalIndices(&tracks); + rowCandidateLb->bindExternalIndices(&lcCandidates); + // Match reconstructed candidates. - for (const auto& candidate : candidates) { + for (const auto& candidate : *rowCandidateLb) { flag = 0; origin = 0; debug = 0; @@ -308,14 +305,15 @@ struct HfCandidateCreatorLbMc { // Λb → Λc+ π- if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kLambdaB0, std::array{static_cast(Pdg::kLambdaCPlus), -kPiPlus}, true)) { // Λc+ → p K- π+ - auto LcCandMC = mcParticles.rawIteratorAt(particle.daughtersIds().front()); - if (RecoDecay::isMatchedMCGen(mcParticles, LcCandMC, static_cast(Pdg::kLambdaCPlus), std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign)) { + auto candLcMc = mcParticles.rawIteratorAt(particle.daughtersIds().front()); + if (RecoDecay::isMatchedMCGen(mcParticles, candLcMc, static_cast(Pdg::kLambdaCPlus), std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign)) { flag = sign * (1 << hf_cand_lb::DecayType::LbToLcPi); } } rowMcMatchGen(flag, origin); } } + PROCESS_SWITCH(HfCandidateCreatorLbExpressions, processMc, "Process MC", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) @@ -323,9 +321,5 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec workflow{ adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc)}; - const bool doMC = cfgc.options().get("doMC"); - if (doMC) { - workflow.push_back(adaptAnalysisTask(cfgc)); - } return workflow; } diff --git a/PWGHF/TableProducer/candidateCreatorMcGen.cxx b/PWGHF/TableProducer/candidateCreatorMcGen.cxx new file mode 100644 index 00000000000..c27a2f8b734 --- /dev/null +++ b/PWGHF/TableProducer/candidateCreatorMcGen.cxx @@ -0,0 +1,78 @@ +// 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 candidateCreatorMcGen.cxx +/// \brief McGen only selection of heavy-flavour particles +/// +/// \author Nima Zardoshti, nima.zardoshti@cern.ch, CERN + +#include +#include +#include + +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/Utils/utilsMcGen.h" + +using namespace o2; +using namespace o2::analysis; +using namespace o2::framework; + +/// Reconstruction of heavy-flavour 2-prong decay candidates +struct HfCandidateCreatorMcGen { + + Produces rowMcMatchGen2Prong; + Produces rowMcMatchGen3Prong; + Produces rowMcMatchGenBplus; + Produces rowMcMatchGenB0; + Configurable fill2Prong{"fill2Prong", false, "fill table for 2 prong candidates"}; + Configurable fill3Prong{"fill3Prong", false, "fill table for 3 prong candidates"}; + Configurable fillBplus{"fillBplus", false, "fill table for for B+ candidates"}; + Configurable fillB0{"fillB0", false, "fill table for B0 candidates"}; + Configurable rejectBackground2Prong{"rejectBackground2Prong", false, "Reject particles from PbPb background for 2 prong candidates"}; + Configurable rejectBackground3Prong{"rejectBackground3Prong", false, "Reject particles from PbPb background for 3 prong candidates"}; + + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + + void process(aod::McCollisions const& mcCollisions, + aod::McParticles const& mcParticles) + { + + for (const auto& mcCollision : mcCollisions) { + const auto mcParticlesPerMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, mcCollision.globalIndex()); + if (fill2Prong) { + hf_mc_gen::fillMcMatchGen2Prong(mcParticles, mcParticlesPerMcColl, rowMcMatchGen2Prong, rejectBackground2Prong); + } + if (fill3Prong) { + hf_mc_gen::fillMcMatchGen3Prong(mcParticles, mcParticlesPerMcColl, rowMcMatchGen3Prong, rejectBackground3Prong); + } + } + if (fillBplus) { + hf_mc_gen::fillMcMatchGenBplus(mcParticles, rowMcMatchGenBplus); + } + if (fillB0) { + hf_mc_gen::fillMcMatchGenB0(mcParticles, rowMcMatchGenB0); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/candidateCreatorSigmac0plusplus.cxx b/PWGHF/TableProducer/candidateCreatorSigmac0plusplus.cxx index e9957d61886..c3cfe2d6049 100644 --- a/PWGHF/TableProducer/candidateCreatorSigmac0plusplus.cxx +++ b/PWGHF/TableProducer/candidateCreatorSigmac0plusplus.cxx @@ -15,6 +15,10 @@ /// /// \author Mattia Faggin , University and INFN PADOVA +#include +#include +#include + #include "CCDB/BasicCCDBManager.h" // for dca recalculation #include "CommonConstants/PhysicsConstants.h" #include "DataFormatsParameters/GRPMagField.h" // for dca recalculation @@ -24,6 +28,7 @@ #include "DetectorsVertexing/PVertexer.h" // for dca recalculation #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/trackUtilities.h" @@ -34,6 +39,7 @@ #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" // for dca recalculation +#include "PWGHF/Utils/utilsEvSelHf.h" using namespace o2; using namespace o2::analysis; @@ -50,7 +56,7 @@ struct HfCandidateCreatorSigmac0plusplus { Configurable selectionFlagLc{"selectionFlagLc", 1, "Selection Flag for Lc"}; Configurable yCandLcMax{"yCandLcMax", -1., "max. candLc. Lc rapidity"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_sigmac_to_p_k_pi::vecBinsPt}, "pT bin limits"}; - Configurable> cutsMassLcMax{"cutsMassLcMax", {hf_cuts_sigmac_to_p_k_pi::cuts[0], hf_cuts_sigmac_to_p_k_pi::nBinsPt, hf_cuts_sigmac_to_p_k_pi::nCutVars, hf_cuts_sigmac_to_p_k_pi::labelsPt, hf_cuts_sigmac_to_p_k_pi::labelsCutVar}, "Lc candidate selection per pT bin"}; + Configurable> cutsMassLcMax{"cutsMassLcMax", {hf_cuts_sigmac_to_p_k_pi::Cuts[0], hf_cuts_sigmac_to_p_k_pi::NBinsPt, hf_cuts_sigmac_to_p_k_pi::NCutVars, hf_cuts_sigmac_to_p_k_pi::labelsPt, hf_cuts_sigmac_to_p_k_pi::labelsCutVar}, "Lc candidate selection per pT bin"}; /// Selections on candidate soft π-,+ Configurable applyGlobalTrkWoDcaCutsSoftPi{"applyGlobalTrkWoDcaCutsSoftPi", false, "Switch on the application of the global-track w/o dca cuts for soft pion BEFORE ALL OTHER CUSTOM CUTS"}; @@ -137,7 +143,8 @@ struct HfCandidateCreatorSigmac0plusplus { softPiCuts.SetMaxChi2PerClusterITS(softPiChi2Max); // ITS hitmap std::set setSoftPiItsHitMap; // = {}; - for (int idItsLayer = 0; idItsLayer < 7; idItsLayer++) { + constexpr std::size_t NLayersIts = 7; + for (std::size_t idItsLayer = 0u; idItsLayer < NLayersIts; idItsLayer++) { if (TESTBIT(softPiItsHitMap, idItsLayer)) { setSoftPiItsHitMap.insert(static_cast(idItsLayer)); } @@ -173,7 +180,7 @@ struct HfCandidateCreatorSigmac0plusplus { /// keep only the candidates flagged as possible Λc+ (and charge conj.) decaying into a charged pion, kaon and proton /// if not selected, skip it and go to the next one - if (!(candLc.hfflag() & 1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) { + if (!(candLc.hfflag() & BIT(aod::hf_cand_3prong::DecayType::LcToPKPi))) { continue; } /// keep only the candidates Λc+ (and charge conj.) within the desired rapidity @@ -229,7 +236,7 @@ struct HfCandidateCreatorSigmac0plusplus { int chargeLc = candLc.template prong0_as().sign() + candLc.template prong1_as().sign() + candLc.template prong2_as().sign(); int chargeSoftPi = trackSoftPi.sign(); int8_t chargeSigmac = chargeLc + chargeSoftPi; - if (std::abs(chargeSigmac) != 0 && std::abs(chargeSigmac) != 2) { + if (std::abs(chargeSigmac) != o2::aod::hf_cand_sigmac::ChargeNull && std::abs(chargeSigmac) != o2::aod::hf_cand_sigmac::ChargePlusPlus) { /// this shall never happen LOG(fatal) << ">>> Sc candidate with charge +1 built, not possible! Charge Lc: " << chargeLc << ", charge soft pion: " << chargeSoftPi; } @@ -247,7 +254,7 @@ struct HfCandidateCreatorSigmac0plusplus { chargeSigmac, statusSpreadMinvPKPiFromPDG, statusSpreadMinvPiKPFromPDG); } /// end loop over Λc+ → pK-π+ (and charge conj.) candidates - } /// end makeSoftPiLcPair + } /// end makeSoftPiLcPair /// @brief function to loop over candidate soft pions and, for each of them, over candidate Λc+ for Σc0,++ → Λc+(→pK-π+) π- candidate reconstruction /// @param collision is a o2::aod::Collisions @@ -382,11 +389,32 @@ struct HfCandidateSigmac0plusplusMc { Produces rowMCMatchScRec; Produces rowMCMatchScGen; + o2::hf_evsel::HfEventSelectionMc hfEvSelMc; // mc event selection and monitoring + + using BCsInfo = soa::Join; using LambdacMc = soa::Join; // using LambdacMcGen = soa::Join; + using McCollisionsNoCents = soa::Join; + + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + + HistogramRegistry registry{"registry"}; /// @brief init function - void init(InitContext const&) {} + void init(InitContext& initContext) + { + const auto& workflows = initContext.services().get(); + for (const DeviceSpec& device : workflows.devices) { + // here we assume that the hf-candidate-creator-3prong is in the workflow + // configure the ev. sel from that workflow + if (device.name.compare("hf-candidate-creator-3prong") == 0) { + hfEvSelMc.configureFromDevice(device); + break; + } + } + + hfEvSelMc.addHistograms(registry); // particles monitoring + } /// @brief dummy process function, to be run on data /// @param @@ -397,7 +425,10 @@ struct HfCandidateSigmac0plusplusMc { /// @param mcParticles table of generated particles void processMc(aod::McParticles const& mcParticles, aod::TracksWMc const& tracks, - LambdacMc const& candsLc /*, const LambdacMcGen&*/) + LambdacMc const& candsLc /*, const LambdacMcGen&*/, + McCollisionsNoCents const& collInfos, + aod::McCollisions const&, + BCsInfo const&) { // Match reconstructed candidates. @@ -409,7 +440,6 @@ struct HfCandidateSigmac0plusplusMc { int8_t flag = 0; int8_t origin = 0; int8_t chargeSigmac = 10; - // std::vector arrDaughIndex; /// index of daughters of MC particle /// Match reconstructed Σc0,++ candidates for (const auto& candSigmac : *candidatesSigmac) { @@ -417,12 +447,12 @@ struct HfCandidateSigmac0plusplusMc { sign = 0; flag = 0; origin = 0; - // arrDaughIndex.clear(); + std::vector idxBhadMothers{}; /// skip immediately the candidate Σc0,++ w/o a Λc+ matched to MC auto candLc = candSigmac.prongLc_as(); - if (!(std::abs(candLc.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) { /// (*) - rowMCMatchScRec(flag, origin); + if (!(std::abs(candLc.flagMcMatchRec()) == BIT(aod::hf_cand_3prong::DecayType::LcToPKPi))) { /// (*) + rowMCMatchScRec(flag, origin, -1.f, 0); continue; } @@ -432,89 +462,163 @@ struct HfCandidateSigmac0plusplusMc { candLc.prong2_as(), candSigmac.prong1_as()}; chargeSigmac = candSigmac.charge(); - if (chargeSigmac == 0) { + if (chargeSigmac == o2::aod::hf_cand_sigmac::ChargeNull) { /// candidate Σc0 /// 3 levels: /// 1. Σc0 → Λc+ π-,+ /// 2. Λc+ → pK-π+ direct (i) or Λc+ → resonant channel Λc± → p± K*, Λc± → Δ(1232)±± K∓ or Λc± → Λ(1520) π± (ii) /// 3. in case of (ii): resonant channel to pK-π+ + + /// look for Σc0(2455) indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kSigmaC0, std::array{+kProton, -kKPlus, +kPiPlus, -kPiPlus}, true, &sign, 3); if (indexRec > -1) { /// due to (*) no need to check anything for LambdaC - flag = sign * (1 << aod::hf_cand_sigmac::DecayType::Sc0ToPKPiPi); + flag = sign * BIT(aod::hf_cand_sigmac::DecayType::Sc0ToPKPiPi); + } + + /// look for Σc0(2520) + if (flag == 0) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kSigmaCStar0, std::array{+kProton, -kKPlus, +kPiPlus, -kPiPlus}, true, &sign, 3); + if (indexRec > -1) { /// due to (*) no need to check anything for LambdaC + flag = sign * BIT(aod::hf_cand_sigmac::DecayType::ScStar0ToPKPiPi); + } } - } else if (std::abs(chargeSigmac) == 2) { + + } else if (std::abs(chargeSigmac) == o2::aod::hf_cand_sigmac::ChargePlusPlus) { /// candidate Σc++ /// 3 levels: /// 1. Σc0 → Λc+ π-,+ /// 2. Λc+ → pK-π+ direct (i) or Λc+ → resonant channel Λc± → p± K*, Λc± → Δ(1232)±± K∓ or Λc± → Λ(1520) π± (ii) /// 3. in case of (ii): resonant channel to pK-π+ + + /// look for Σc++(2455) indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kSigmaCPlusPlus, std::array{+kProton, -kKPlus, +kPiPlus, +kPiPlus}, true, &sign, 3); if (indexRec > -1) { /// due to (*) no need to check anything for LambdaC - flag = sign * (1 << aod::hf_cand_sigmac::DecayType::ScplusplusToPKPiPi); + flag = sign * BIT(aod::hf_cand_sigmac::DecayType::ScplusplusToPKPiPi); + } + + /// look for Σc++(2520) + if (flag == 0) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kSigmaCStarPlusPlus, std::array{+kProton, -kKPlus, +kPiPlus, +kPiPlus}, true, &sign, 3); + if (indexRec > -1) { /// due to (*) no need to check anything for LambdaC + flag = sign * BIT(aod::hf_cand_sigmac::DecayType::ScStarPlusPlusToPKPiPi); + } } } /// check the origin (prompt vs. non-prompt) if (flag != 0) { auto particle = mcParticles.rawIteratorAt(indexRec); - origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle); + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); } - /// fill the table with results of reconstruction level MC matching - rowMCMatchScRec(flag, origin); + if (origin == RecoDecay::OriginType::NonPrompt) { + auto bHadMother = mcParticles.rawIteratorAt(idxBhadMothers[0]); + rowMCMatchScRec(flag, origin, bHadMother.pt(), bHadMother.pdgCode()); + } else { + rowMCMatchScRec(flag, origin, -1.f, 0); + } } /// end loop over reconstructed Σc0,++ candidates /// Match generated Σc0,++ candidates for (const auto& particle : mcParticles) { flag = 0; origin = 0; + std::vector idxBhadMothers{}; + + /// MC ev. selection done w/o centrality estimator + /// In case of need, readapt the code templetizing the function + auto mcCollision = particle.mcCollision(); + float centrality{-1.f}; + uint16_t rejectionMask{0}; + const auto collSlice = collInfos.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + hfEvSelMc.fillHistograms(mcCollision, rejectionMask, 0); + if (rejectionMask != 0) { + // at least one event selection not satisfied --> reject gen particles from this collision + rowMCMatchScGen(flag, origin, -1); + continue; + } /// 3 levels: /// 1. Σc0 → Λc+ π-,+ /// 2. Λc+ → pK-π+ direct (i) or Λc+ → resonant channel Λc± → p± K*, Λc± → Δ(1232)±± K∓ or Λc± → Λ(1520) π± (ii) /// 3. in case of (ii): resonant channel to pK-π+ /// → here we check level 1. first, and then levels 2. and 3. are inherited by the Λc+ → pK-π+ MC matching in candidateCreator3Prong.cxx + + /// look for Σc0,++(2455) if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kSigmaC0, std::array{static_cast(Pdg::kLambdaCPlus), static_cast(kPiMinus)}, true, &sign, 1)) { - // generated Σc0 - // for (const auto& daughter : particle.daughters_as()) { + // generated Σc0(2455) for (const auto& daughter : particle.daughters_as()) { // look for Λc+ daughter decaying in pK-π+ if (std::abs(daughter.pdgCode()) != Pdg::kLambdaCPlus) continue; - // if (std::abs(daughter.flagMcMatchGen()) == (1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) { - if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2)) { + if (RecoDecay::isMatchedMCGen(mcParticles, daughter, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2)) { /// Λc+ daughter decaying in pK-π+ found! - flag = sign * (1 << aod::hf_cand_sigmac::DecayType::Sc0ToPKPiPi); + flag = sign * BIT(aod::hf_cand_sigmac::DecayType::Sc0ToPKPiPi); break; } } } else if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kSigmaCPlusPlus, std::array{static_cast(Pdg::kLambdaCPlus), static_cast(kPiPlus)}, true, &sign, 1)) { - // generated Σc++ - // for (const auto& daughter : particle.daughters_as()) { + // generated Σc++(2455) for (const auto& daughter : particle.daughters_as()) { // look for Λc+ daughter decaying in pK-π+ if (std::abs(daughter.pdgCode()) != Pdg::kLambdaCPlus) continue; - // if (std::abs(daughter.flagMcMatchGen()) == (1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) { - if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2)) { + if (RecoDecay::isMatchedMCGen(mcParticles, daughter, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2)) { /// Λc+ daughter decaying in pK-π+ found! - flag = sign * (1 << aod::hf_cand_sigmac::DecayType::ScplusplusToPKPiPi); + flag = sign * BIT(aod::hf_cand_sigmac::DecayType::ScplusplusToPKPiPi); break; } } } + /// look for Σc0,++(2520) + if (flag == 0) { + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kSigmaCStar0, std::array{static_cast(Pdg::kLambdaCPlus), static_cast(kPiMinus)}, true, &sign, 1)) { + // generated Σc0(2520) + for (const auto& daughter : particle.daughters_as()) { + // look for Λc+ daughter decaying in pK-π+ + if (std::abs(daughter.pdgCode()) != Pdg::kLambdaCPlus) + continue; + if (RecoDecay::isMatchedMCGen(mcParticles, daughter, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2)) { + /// Λc+ daughter decaying in pK-π+ found! + flag = sign * BIT(aod::hf_cand_sigmac::DecayType::ScStar0ToPKPiPi); + break; + } + } + } else if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kSigmaCStarPlusPlus, std::array{static_cast(Pdg::kLambdaCPlus), static_cast(kPiPlus)}, true, &sign, 1)) { + // generated Σc++(2520) + for (const auto& daughter : particle.daughters_as()) { + // look for Λc+ daughter decaying in pK-π+ + if (std::abs(daughter.pdgCode()) != Pdg::kLambdaCPlus) + continue; + if (RecoDecay::isMatchedMCGen(mcParticles, daughter, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2)) { + /// Λc+ daughter decaying in pK-π+ found! + flag = sign * BIT(aod::hf_cand_sigmac::DecayType::ScStarPlusPlusToPKPiPi); + break; + } + } + } + } + /// check the origin (prompt vs. non-prompt) if (flag != 0) { - auto particle = mcParticles.rawIteratorAt(indexRec); - origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle); + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); } - /// fill the table with results of generation level MC matching - rowMCMatchScGen(flag, origin); + if (origin == RecoDecay::OriginType::NonPrompt) { + rowMCMatchScGen(flag, origin, idxBhadMothers[0]); + } else { + rowMCMatchScGen(flag, origin, -1); + } + + // debug + // if(origin != RecoDecay::OriginType::Prompt && origin != RecoDecay::OriginType::NonPrompt) { + // LOG(info) << " --> origin " << static_cast(origin) << ", flag " << static_cast(flag); + //} } /// end loop over mcParticles - } /// end processMc + } /// end processMc PROCESS_SWITCH(HfCandidateSigmac0plusplusMc, processMc, "Process MC", false); }; diff --git a/PWGHF/TableProducer/candidateCreatorSigmac0plusplusCascade.cxx b/PWGHF/TableProducer/candidateCreatorSigmac0plusplusCascade.cxx new file mode 100644 index 00000000000..857e8b68bf9 --- /dev/null +++ b/PWGHF/TableProducer/candidateCreatorSigmac0plusplusCascade.cxx @@ -0,0 +1,351 @@ +// 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 candidateCreatorSigmac0plusplusCascade.cxx +/// \brief Σc0,++ → Λc(→ K0sP) + π-,+ candidate builder +/// \note Here the Lc from the cascade channel is obtained using the task taskLcToK0sP.cxx +/// \author Rutuparna Rath , INFN BOLOGNA and GSI Darmstadt +/// In collaboration with Andrea Alici , INFN BOLOGNA + +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelectionDefaults.h" + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +using namespace o2; +using namespace o2::analysis; +using namespace o2::constants::physics; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct HfCandidateCreatorSigmac0plusplusCascade { + + /// Table with Σc0,++ info + Produces rowScCandidates; + + Configurable trkMinPt{"trkMinPt", 0.15, "track min pT"}; + Configurable trkMaxEta{"trkMaxEta", 0.8, "track max Eta"}; + Configurable maxDCAxyToPVcut{"maxDCAxyToPVcut", 2.0, "Track DCAxy cut to PV Maximum"}; + Configurable maxDCAzToPVcut{"maxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; + Configurable nTpcNClsFound{"nTpcNClsFound", 120, "nFindable TPC Clusters"}; + Configurable nTPCCrossedRows{"nTPCCrossedRows", 70, "nCrossed TPC Rows"}; + Configurable nTPCChi2{"nTPCChi2", 4.0, "nTPC Chi2 per Cluster"}; + Configurable nITSChi2{"nITSChi2", 36.0, "nITS Chi2 per Cluster"}; + Configurable tpcnSigmaPi{"tpcnSigmaPi", 3.0, "TPC nSigma selection"}; + + /// Selection of candidates Λc+ + Configurable selectionFlagLc{"selectionFlagLc", 1, "Selection Flag for Lc"}; + Configurable yCandLcMax{"yCandLcMax", -1., "max. candLc. Lc rapidity"}; + Configurable selectionFlagLcToK0sP{"selectionFlagLcToK0sP", 1, "Selection Flag for Lc"}; + Configurable selectionFlagLcbarToK0sP{"selectionFlagLcbarToK0sP", 1, "Selection Flag for Lcbar"}; + Configurable cutsMassLcMax{"cutsMassLcMax", 0.08, "Lc candidate mass selection"}; + Configurable> binsPt{"binsPt", std::vector{hf_cuts_sigmac_to_p_k_pi::vecBinsPt}, "pT bin limits"}; + + /// Selections on candidate soft π-,+ + Configurable applyGlobalTrkWoDcaCutsSoftPi{"applyGlobalTrkWoDcaCutsSoftPi", false, "Switch on the application of the global-track w/o dca cuts for soft pion BEFORE ALL OTHER CUSTOM CUTS"}; + Configurable softPiEtaMax{"softPiEtaMax", 0.9f, "Soft pion max value for pseudorapidity (abs vale)"}; + Configurable softPiChi2Max{"softPiChi2Max", 36.f, "Soft pion max value for chi2 ITS"}; + Configurable softPiItsHitMap{"softPiItsHitMap", 127, "Soft pion ITS hitmap"}; + Configurable softPiItsHitsMin{"softPiItsHitsMin", 1, "Minimum number of ITS layers crossed by the soft pion among those in \"softPiItsHitMap\""}; + Configurable softPiDcaXYMax{"softPiDcaXYMax", 0.065, "Soft pion max dcaXY (cm)"}; + Configurable softPiDcaZMax{"softPiDcaZMax", 0.065, "Soft pion max dcaZ (cm)"}; + Configurable addQA{"addQA", true, "Switch for the qa PLOTS"}; + + HfHelper hfHelper; + + using TracksWithPID = soa::Join; + + /// Filter the candidate Λc+ used for the Σc0,++ creation + Filter filterSelectCandidateLc = (aod::hf_sel_candidate_lc_to_k0s_p::isSelLcToK0sP >= selectionFlagLcToK0sP || + aod::hf_sel_candidate_lc_to_k0s_p::isSelLcToK0sP >= selectionFlagLcbarToK0sP); + + // slice by hand the assoc. track with the Λc+ collisionId + Preslice trackIndicesPerCollision = aod::track::collisionId; + + HistogramRegistry registry; + + void init(InitContext&) + { + // axes + AxisSpec axisBinsPt = {binsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisPt = {300, 0.0f, 30.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisEta = {500, -2.0f, 2.0f, "#it{#eta}"}; + AxisSpec axisPhi = {100, 0.f, 6.3f, "#it{#phi}"}; + AxisSpec axisMassCand = {600, 1.98f, 2.58f, "inv. mass (p K_{S}^{0}) (GeV/#it{c}^{2})"}; + AxisSpec axisd0 = {500, -0.5f, 0.5f, "DCAxy (cm)"}; + AxisSpec axisd0V0Daughters = {1000, -5.0f, 5.0f, "DCAxy (cm)"}; + AxisSpec axisV0CPA = {500, 0.98f, 1.0001f, "v0 cos pointing angle"}; + AxisSpec axisV0Radius = {1000, 0.f, 40.f, "V0 radius (cm)"}; + AxisSpec axisV0DCADaughters = {200, 0.f, 2.f, "DCA (cm)"}; + AxisSpec axisMassK0Short = {500, 0.4f, 0.6f, "#it{m}(K_{S}^{0}) (GeV/#it{c}^{2})"}; + AxisSpec axisMassLambda = {500, 1.0f, 1.2f, "#it{m}(#Lambda) (GeV/#it{c}^{2})"}; + AxisSpec axisMassGamma = {500, 0.0f, 0.4f, "#it{m}(#gamma) (GeV/#it{c}^{2})"}; + AxisSpec axisCPACand = {110, -1.1f, 1.1f, "candiate cos pointing angle"}; + AxisSpec axisDecLength = {200, 0.f, 2.0f, "decay length (cm)"}; + AxisSpec axisProperLifetime = {100, 0.f, 0.2f, "#it{c#tau} (cm)"}; + AxisSpec axisProperLifetimeV0 = {1000, 0.f, 80.f, "#it{c#tau} (cm)"}; + AxisSpec axisNSigma = {100, -6.f, 6.f, "n#it{#sigma}_{p}"}; + AxisSpec axisPidP = {100, 0.f, 10.0f, "#it{p} (GeV/#it{c})"}; + + auto h = registry.add("candidateStat", "", kTH1D, {{3, 0.5, 3.5}}); + h->GetXaxis()->SetBinLabel(1, "Lc candidates"); + h->GetXaxis()->SetBinLabel(2, "soft #pi (before cuts)"); + h->GetXaxis()->SetBinLabel(3, "soft #pi (after track cuts)"); + // data + if (addQA) { + registry.add("lc/hPtCand", "cascade candidates;candidateLc #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("lc/hEtaCand", "cascade candidates;candidateLc #it{#eta};entries", {HistType::kTH1F, {axisEta}}); + registry.add("lc/hEtaCandVsPtCand", "cascade candidates;candidateLc #it{#eta};p_{T}", {HistType::kTH2F, {axisEta, axisBinsPt}}); + registry.add("lc/hPhiCand", "cascade candidates;candidateLc #it{#phi};entries", {HistType::kTH1F, {axisPhi}}); + registry.add("lc/hPhiCandVsPtCand", "cascade candidates;candidateLc #it{#phi};p_{T}", {HistType::kTH2F, {axisPhi, axisBinsPt}}); + registry.add("lc/hMass", "cascade candidates;inv. mass (p K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMassCand}}); + registry.add("lc/hMassVsPtCand", "cascade candidates;inv. mass (p K_{S}^{0}) (GeV/#it{c}^{2});p_{T}", {HistType::kTH2F, {axisMassCand, axisBinsPt}}); + registry.add("lc/hPtBach", "cascade candidates;bachelor #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("lc/hPtBachVsPtCand", "cascade candidates;bachelor #it{p}_{T} (GeV/#it{c});p_{T}", {HistType::kTH2F, {axisPt, axisBinsPt}}); + registry.add("lc/hPtV0", "cascade candidates;v0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("lc/hPtV0VsPtCand", "cascade candidates;v0 #it{p}_{T} (GeV/#it{c});p_{T}", {HistType::kTH2F, {axisPt, axisBinsPt}}); + registry.add("lc/hd0Bach", "cascade candidates;bachelor DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {axisd0}}); + registry.add("lc/hd0BachVsPtCand", "cascade candidates;bachelor DCAxy to prim. vertex (cm);p_{T}", {HistType::kTH2F, {axisd0, axisBinsPt}}); + registry.add("lc/hd0V0", "cascade candidates;V0 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {axisd0}}); + registry.add("lc/hd0V0VsPtCand", "cascade candidates;V0 DCAxy to prim. vertex (cm);p_{T}", {HistType::kTH2F, {axisd0, axisBinsPt}}); + registry.add("lc/hd0V0pos", "cascade candidates;pos daugh v0 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {axisd0V0Daughters}}); + registry.add("lc/hd0V0posVsPtCand", "cascade candidates;pos daugh v0 DCAxy to prim. vertex (cm);p_{T}", {HistType::kTH2F, {axisd0V0Daughters, axisBinsPt}}); + registry.add("lc/hd0V0neg", "cascade candidates;neg daugh v0 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {axisd0V0Daughters}}); + registry.add("lc/hd0V0negVsPtCand", "cascade candidates;neg daugh v0 DCAxy to prim. vertex (cm);p_{T}", {HistType::kTH2F, {axisd0V0Daughters, axisBinsPt}}); + registry.add("lc/hPtV0pos", "cascade candidates;pos daugh v0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("lc/hPtV0posVsPtCand", "cascade candidates;pos daugh v0 #it{p}_{T} (GeV/#it{c});p_{T}", {HistType::kTH2F, {axisPt, axisBinsPt}}); + registry.add("lc/hPtV0neg", "cascade candidates;neg daugh v0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("lc/hPtV0negVsPtCand", "cascade candidates;neg daugh v0 #it{p}_{T} (GeV/#it{c});p_{T}", {HistType::kTH2F, {axisPt, axisBinsPt}}); + registry.add("lc/hV0CPA", "cascade candidates;v0 cosine of pointing angle;entries", {HistType::kTH1F, {axisV0CPA}}); + registry.add("lc/hV0CPAVsPtCand", "cascade candidates;v0 cosine of pointing angle;p_{T}", {HistType::kTH2F, {axisV0CPA, axisBinsPt}}); + registry.add("lc/hV0Radius", "cascade candidates;v0 radius (cm);entries", {HistType::kTH1F, {axisV0Radius}}); + registry.add("lc/hV0RadiusVsPtCand", "cascade candidates;v0 radius (cm);p_{T}", {HistType::kTH2F, {axisV0Radius, axisBinsPt}}); + registry.add("lc/hV0DCADaughters", "cascade candidates;v0 dca daughters (cm);entries", {HistType::kTH1F, {axisV0DCADaughters}}); + registry.add("lc/hV0DCADaughtersVsPtCand", "cascade candidates;v0 dca daughters (cm);p_{T}", {HistType::kTH2F, {axisV0DCADaughters, axisBinsPt}}); + registry.add("lc/hV0MK0Short", "cascade candidates;v0 mass K0s (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMassK0Short}}); + registry.add("lc/hV0MK0ShortVsPtCand", "cascade candidates;v0 mass K0s (GeV/#it{c}^{2});p_{T}", {HistType::kTH2F, {axisMassK0Short, axisBinsPt}}); + registry.add("lc/hV0MLambda", "cascade candidates;v0 mass Lambda (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMassLambda}}); + registry.add("lc/hV0MLambdaVsPtCand", "cascade candidates;v0 mass Lambda (GeV/#it{c}^{2});p_{T}", {HistType::kTH2F, {axisMassLambda, axisBinsPt}}); + registry.add("lc/hV0MAntiLambda", "cascade candidates;v0 mass AntiLambda (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMassLambda}}); + registry.add("lc/hV0MAntiLambdaVsPtCand", "cascade candidates;v0 mass AntiLambda (GeV/#it{c}^{2});p_{T}", {HistType::kTH2F, {axisMassLambda, axisBinsPt}}); + registry.add("lc/hV0MGamma", "cascade candidates;v0 mass Gamma (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMassGamma}}); + registry.add("lc/hV0MGammaVsPtCand", "cascade candidates;v0 mass Gamma (GeV/#it{c}^{2});p_{T}", {HistType::kTH2F, {axisMassGamma, axisBinsPt}}); + registry.add("lc/hCtV0K0Short", "cascade candidates;proper lifetime (V0) * #it{c} (cm);entries", {HistType::kTH1F, {axisProperLifetimeV0}}); + registry.add("lc/hCtV0K0ShortVsPtCand", "cascade candidates;proper lifetime (V0) * #it{c} (cm);p_{T}", {HistType::kTH2F, {axisProperLifetimeV0, axisBinsPt}}); + registry.add("lc/hCtV0Lambda", "cascade candidates;proper lifetime (V0) * #it{c} (cm);entries", {HistType::kTH1F, {axisProperLifetimeV0}}); + registry.add("lc/hCtV0LambdaVsPtCand", "cascade candidates;proper lifetime (V0) * #it{c} (cm);p_{T}", {HistType::kTH2F, {axisProperLifetimeV0, axisBinsPt}}); + registry.add("lc/hCPACand", "cascade candidates;cosine pointing angle;entries", {HistType::kTH1F, {axisCPACand}}); + registry.add("lc/hCPACandVsPtCand", "cascade candidates;cosine pointing angle;p_{T}", {HistType::kTH2F, {axisCPACand, axisBinsPt}}); + registry.add("lc/hCPAxyCand", "cascade candidates;cosine pointing angle xy;entries", {HistType::kTH1F, {axisCPACand}}); + registry.add("lc/hCPAxyCandVsPtCand", "cascade candidates;cosine pointing angle xy;p_{T}", {HistType::kTH2F, {axisCPACand, axisBinsPt}}); + registry.add("lc/hDecLengthCand", "cascade candidates;decay length (cm);entries", {HistType::kTH1F, {axisDecLength}}); + registry.add("lc/hDecLengthCandVsPtCand", "cascade candidates;decay length (cm);p_{T}", {HistType::kTH2F, {axisDecLength, axisBinsPt}}); + registry.add("lc/hDecLengthXYCand", "cascade candidates;decay length xy (cm);entries", {HistType::kTH1F, {axisDecLength}}); + registry.add("lc/hDecLengthXYCandVsPtCand", "cascade candidates;decay length xy (cm);p_{T}", {HistType::kTH2F, {axisDecLength, axisBinsPt}}); + registry.add("lc/hCtCand", "cascade candidates;proper lifetime (#Lambda_{c}) * #it{c} (cm);entries", {HistType::kTH1F, {axisProperLifetime}}); + registry.add("lc/hCtCandVsPtCand", "cascade candidates;proper lifetime (#Lambda_{c}) * #it{c} (cm);p_{T}", {HistType::kTH2F, {axisProperLifetime, axisBinsPt}}); + + // soft pion + registry.add("pion/data/hPtSoftPi", "#pi candidates; #it{p}_{T}(#pi) (GeV/#it{c}); counts;", {HistType::kTH1F, {axisPt}}); + registry.add("pion/data/hEtaSoftPi", "#pi candidates; #eta ; counts;", {HistType::kTH1F, {axisEta}}); + registry.add("pion/data/hPhiSoftPi", "#pi candidates; #Phi ; counts;", {HistType::kTH1F, {axisPhi}}); + } + } + + template + bool isTrackSelected(const TrackType& track) + { + if (track.pt() < trkMinPt) + return false; + if (std::abs(track.eta()) > trkMaxEta) + return false; + if (std::abs(track.dcaXY()) > maxDCAxyToPVcut) + return false; + if (std::abs(track.dcaZ()) > maxDCAzToPVcut) + return false; + if (track.tpcNClsFound() < nTpcNClsFound) + return false; + if (track.tpcNClsCrossedRows() < nTPCCrossedRows) + return false; + if (track.tpcChi2NCl() > nTPCChi2) + return false; + if (track.itsChi2NCl() > nITSChi2) + return false; + if (track.tpcNSigmaPi() > tpcnSigmaPi) + return false; + + return true; + } + + /// @param tracks are the tracks (with dcaXY, dcaZ information) → soft-pion candidate tracks + /// @param candidatesLc are 2-prong candidates satisfying the analysis selections for Λc+ → Ks0P (and charge conj.) + void processData(soa::Filtered> const& candidates, + aod::Collisions const&, + TracksWithPID const& tracks, + aod::V0s const&) + { + for (const auto& candidateLc : candidates) { + /// slice the tracks based on the collisionId + const auto& tracksInThisCollision = tracks.sliceBy(trackIndicesPerCollision, candidateLc.collision().globalIndex()); + const auto& bachProton = candidateLc.prong0_as(); + int chargeLc = bachProton.sign(); // Lc charge depends on its bach charge (here it is proton) + + auto ptCand = candidateLc.pt(); + auto eta = candidateLc.eta(); + auto phi = candidateLc.phi(); + auto invMassLcToK0sP = hfHelper.invMassLcToK0sP(candidateLc); + auto ptProng0 = candidateLc.ptProng0(); + auto ptProng1 = candidateLc.ptProng1(); + auto impactParameter0 = candidateLc.impactParameter0(); + auto impactParameter1 = candidateLc.impactParameter1(); + auto dcaPosToPV = candidateLc.dcapostopv(); + auto dcaNegToPV = candidateLc.dcanegtopv(); + auto ptV0Pos = candidateLc.ptV0Pos(); + auto ptV0Neg = candidateLc.ptV0Neg(); + auto v0CosPA = candidateLc.v0cosPA(); + auto v0Radius = candidateLc.v0radius(); + auto dcaV0Daughters = candidateLc.dcaV0daughters(); + auto mK0Short = candidateLc.mK0Short(); + auto mLambda = candidateLc.mLambda(); + auto mAntiLambda = candidateLc.mAntiLambda(); + auto mGamma = candidateLc.mGamma(); + auto ctV0K0Short = hfHelper.ctV0K0s(candidateLc); + auto ctV0Lambda = hfHelper.ctV0Lambda(candidateLc); + auto cpa = candidateLc.cpa(); + auto cpaXY = candidateLc.cpaXY(); + auto decayLength = candidateLc.decayLength(); + auto decayLengthXY = candidateLc.decayLengthXY(); + auto ctLc = hfHelper.ctLc(candidateLc); + if (addQA) { + registry.fill(HIST("lc/hPtCand"), ptCand); + registry.fill(HIST("lc/hEtaCand"), eta); + registry.fill(HIST("lc/hEtaCandVsPtCand"), eta, ptCand); + registry.fill(HIST("lc/hPhiCand"), phi); + registry.fill(HIST("lc/hPhiCandVsPtCand"), phi, ptCand); + registry.fill(HIST("lc/hMass"), invMassLcToK0sP); + registry.fill(HIST("lc/hMassVsPtCand"), invMassLcToK0sP, ptCand); + registry.fill(HIST("lc/hPtBach"), ptProng0); + registry.fill(HIST("lc/hPtBachVsPtCand"), ptProng0, ptCand); + registry.fill(HIST("lc/hPtV0"), ptProng1); + registry.fill(HIST("lc/hPtV0VsPtCand"), ptProng1, ptCand); + registry.fill(HIST("lc/hd0Bach"), impactParameter0); + registry.fill(HIST("lc/hd0BachVsPtCand"), impactParameter0, ptCand); + registry.fill(HIST("lc/hd0V0"), impactParameter1); + registry.fill(HIST("lc/hd0V0VsPtCand"), impactParameter1, ptCand); + registry.fill(HIST("lc/hd0V0pos"), dcaPosToPV); + registry.fill(HIST("lc/hd0V0posVsPtCand"), dcaPosToPV, ptCand); + registry.fill(HIST("lc/hd0V0neg"), dcaNegToPV); + registry.fill(HIST("lc/hd0V0negVsPtCand"), dcaNegToPV, ptCand); + registry.fill(HIST("lc/hPtV0pos"), ptV0Pos); + registry.fill(HIST("lc/hPtV0posVsPtCand"), ptV0Pos, ptCand); + registry.fill(HIST("lc/hPtV0neg"), ptV0Neg); + registry.fill(HIST("lc/hPtV0negVsPtCand"), ptV0Neg, ptCand); + registry.fill(HIST("lc/hV0CPA"), v0CosPA); + registry.fill(HIST("lc/hV0CPAVsPtCand"), v0CosPA, ptCand); + registry.fill(HIST("lc/hV0Radius"), v0Radius); + registry.fill(HIST("lc/hV0RadiusVsPtCand"), v0Radius, ptCand); + registry.fill(HIST("lc/hV0DCADaughters"), dcaV0Daughters); + registry.fill(HIST("lc/hV0DCADaughtersVsPtCand"), dcaV0Daughters, ptCand); + registry.fill(HIST("lc/hV0MK0Short"), mK0Short); + registry.fill(HIST("lc/hV0MK0ShortVsPtCand"), mK0Short, ptCand); + registry.fill(HIST("lc/hV0MLambda"), mLambda); + registry.fill(HIST("lc/hV0MLambdaVsPtCand"), mLambda, ptCand); + registry.fill(HIST("lc/hV0MAntiLambda"), mAntiLambda); + registry.fill(HIST("lc/hV0MAntiLambdaVsPtCand"), mAntiLambda, ptCand); + registry.fill(HIST("lc/hV0MGamma"), mGamma); + registry.fill(HIST("lc/hV0MGammaVsPtCand"), mGamma, ptCand); + registry.fill(HIST("lc/hCtV0K0Short"), ctV0K0Short); + registry.fill(HIST("lc/hCtV0K0ShortVsPtCand"), ctV0K0Short, ptCand); + registry.fill(HIST("lc/hCtV0Lambda"), ctV0Lambda); + registry.fill(HIST("lc/hCtV0LambdaVsPtCand"), ctV0Lambda, ptCand); + registry.fill(HIST("lc/hCPACand"), cpa); + registry.fill(HIST("lc/hCPACandVsPtCand"), cpa, ptCand); + registry.fill(HIST("lc/hCPAxyCand"), cpaXY); + registry.fill(HIST("lc/hCPAxyCandVsPtCand"), cpaXY, ptCand); + registry.fill(HIST("lc/hDecLengthCand"), decayLength); + registry.fill(HIST("lc/hDecLengthCandVsPtCand"), decayLength, ptCand); + registry.fill(HIST("lc/hDecLengthXYCand"), decayLengthXY); + registry.fill(HIST("lc/hDecLengthXYCandVsPtCand"), decayLengthXY, ptCand); + registry.fill(HIST("lc/hCtCand"), ctLc); + registry.fill(HIST("lc/hCtCandVsPtCand"), ctLc, ptCand); + } + if (std::abs(invMassLcToK0sP - MassLambdaCPlus) > cutsMassLcMax) { + continue; + } + registry.fill(HIST("candidateStat"), 1); + auto k0Short = candidateLc.v0_as(); // get the soft pions for the given collId + auto pos = k0Short.template posTrack_as(); + auto neg = k0Short.template negTrack_as(); + for (const auto& trackSoftPi : tracksInThisCollision) { + int chargeSoftPi = trackSoftPi.sign(); + if (chargeSoftPi == pos.sign() && trackSoftPi.globalIndex() == pos.globalIndex()) { + continue; + } + if (chargeSoftPi == neg.sign() && trackSoftPi.globalIndex() == neg.globalIndex()) { + continue; + } + if (chargeSoftPi == bachProton.sign() && trackSoftPi.globalIndex() == bachProton.globalIndex()) { + continue; + } + registry.fill(HIST("candidateStat"), 2); + if (!isTrackSelected(trackSoftPi)) { + continue; + } + registry.fill(HIST("candidateStat"), 3); + + /// fill histograms for softpion + if (addQA) { + registry.fill(HIST("pion/data/hPtSoftPi"), trackSoftPi.pt()); + registry.fill(HIST("pion/data/hEtaSoftPi"), trackSoftPi.eta()); + registry.fill(HIST("pion/data/hPhiSoftPi"), trackSoftPi.phi()); // π ← Σc0 + } + /// determine the Σc candidate charge + int8_t chargeSigmac = chargeLc + chargeSoftPi; + + /// fill the Σc0,++ candidate table + rowScCandidates(/* general columns */ + candidateLc.collisionId(), + /* 2-prong specific columns */ + candidateLc.px(), candidateLc.py(), candidateLc.pz(), // Lc info + trackSoftPi.px(), trackSoftPi.py(), trackSoftPi.pz(), // soft pion info + candidateLc.collision().globalIndex(), trackSoftPi.globalIndex(), + chargeLc, + chargeSoftPi, + // candLc.hfflag(), + /* Σc0,++ specific columns */ + chargeSigmac); + } + } // SC candidate + } + PROCESS_SWITCH(HfCandidateCreatorSigmac0plusplusCascade, processData, "Process Data", true); +}; +struct HfCandidateCreatorSigmac0plusplusCascadeExpressions { + Spawns candidatesSigmac; + void processMc(aod::Tracks const&) {} + PROCESS_SWITCH(HfCandidateCreatorSigmac0plusplusCascadeExpressions, processMc, "Process MC tracks", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/candidateCreatorToXiPi.cxx b/PWGHF/TableProducer/candidateCreatorToXiPi.cxx deleted file mode 100644 index e3239edf798..00000000000 --- a/PWGHF/TableProducer/candidateCreatorToXiPi.cxx +++ /dev/null @@ -1,552 +0,0 @@ -// 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 candidateCreatorToXiPi.cxx -/// \brief Reconstruction of Omegac0 and Xic0 -> xi pi candidates -/// \author Federica Zanone , Heidelberg University - -#include "CCDB/BasicCCDBManager.h" -#include "CommonConstants/PhysicsConstants.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DCAFitter/DCAFitterN.h" -#include "DetectorsBase/Propagator.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/runDataProcessing.h" -#include "ReconstructionDataFormats/DCA.h" -#include "ReconstructionDataFormats/Track.h" -#include "ReconstructionDataFormats/V0.h" - -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "Common/DataModel/CollisionAssociationTables.h" -#include "Common/DataModel/EventSelection.h" - -#include "PWGLF/DataModel/LFStrangenessTables.h" - -#include "PWGHF/Core/SelectorCuts.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" -#include "PWGHF/Utils/utilsBfieldCCDB.h" - -using namespace o2; -using namespace o2::track; -using namespace o2::analysis; -using namespace o2::aod; -using namespace o2::aod::cascdata; -using namespace o2::aod::v0data; -using namespace o2::aod::hf_track_index; -using namespace o2::constants::physics; -using namespace o2::framework; -using namespace o2::framework::expressions; - -// Reconstruction of omegac0 and xic0 candidates -struct HfCandidateCreatorToXiPi { - Produces rowCandidate; - - Configurable propagateToPCA{"propagateToPCA", false, "create tracks version propagated to PCA"}; - Configurable useAbsDCA{"useAbsDCA", true, "Minimise abs. distance rather than chi2"}; - Configurable useWeightedFinalPCA{"useWeightedFinalPCA", true, "Recalculate vertex position using track covariances, effective only if useAbsDCA is true"}; - Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; - Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; - Configurable maxDXYIni{"maxDXYIni", 4., "reject (if>0) PCA candidate if tracks DXY exceeds threshold"}; - Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; - Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations is chi2/chi2old > this"}; - Configurable maxChi2{"maxChi2", 100., "discard vertices with chi2/Nprongs > this (or sum{DCAi^2}/Nprongs for abs. distance minimization)"}; - Configurable refitWithMatCorr{"refitWithMatCorr", true, "when doing propagateTracksToVertex, propagate tracks to vtx with material corrections and rerun minimization"}; - Configurable rejDiffCollTrack{"rejDiffCollTrack", true, "Reject tracks coming from different collisions"}; - - // magnetic field setting from CCDB - Configurable isRun2{"isRun2", false, "enable Run 2 or Run 3 GRP objects for magnetic field"}; - Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; - Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; - Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; - - o2::vertexing::DCAFitterN<2> df; // 2-prong vertex fitter to build the omegac/xic vertex - Service ccdb; - o2::base::MatLayerCylSet* lut; - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - int runNumber; - - using MyCascTable = soa::Join; // to use strangeness tracking, use aod::TraCascDatas instead of aod::CascDatas - using CascadesLinked = soa::Join; - using MyV0Table = soa::Join; - using MySkimIdx = soa::Filtered; - - Filter filterSelectIndexes = (aod::hf_track_index::hfflag > static_cast(0)); - - OutputObj hInvMassCharmBaryon{TH1F("hInvMassCharmBaryon", "Charm baryon invariant mass;inv mass;entries", 500, 2.2, 3.1)}; - OutputObj hFitterStatus{TH1F("hFitterStatus", "Charm DCAFitter status;status;entries", 3, -0.5, 2.5)}; // 0 --> vertex(es) found, 1 --> exception found, 2 --> no vertex found (but no exception) - OutputObj hCandidateCounter{TH1F("hCandidateCounter", "Candidate counter wrt derived data;status;entries", 4, -0.5, 3.5)}; // 0 --> candidates in derived data table, 1 --> candidates passing testbit selection, 2 --> candidates passing fitter step 3 --> candidates filled in new table - OutputObj hCascadesCounter{TH1F("hCascadesCounter", "Cascades counter wrt derived data;status;entries", 2, -0.5, 1.5)}; // 0 --> cascades in derived data table (and stored in AOD table), 1 --> cascades in derived data table and also accessible in cascData table - - void init(InitContext const&) - { - df.setPropagateToPCA(propagateToPCA); - df.setMaxR(maxR); - df.setMaxDZIni(maxDZIni); - df.setMaxDXYIni(maxDXYIni); - df.setMinParamChange(minParamChange); - df.setMinRelChi2Change(minRelChi2Change); - df.setMaxChi2(maxChi2); - df.setUseAbsDCA(useAbsDCA); - df.setWeightedFinalPCA(useWeightedFinalPCA); - df.setRefitWithMatCorr(refitWithMatCorr); - - ccdb->setURL(ccdbUrl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); - runNumber = 0; - } - - void process(aod::Collisions const&, - aod::BCsWithTimestamps const&, - TracksWCovDca const&, - MyCascTable const&, CascadesLinked const&, - MySkimIdx const& candidates) - { - double massPionFromPDG = MassPiPlus; // pdg code 211 - double massLambdaFromPDG = MassLambda0; // pdg code 3122 - double massXiFromPDG = MassXiMinus; // pdg code 3312 - double massOmegacFromPDG = MassOmegaC0; // pdg code 4332 - double massXicFromPDG = MassXiC0; // pdg code 4132 - - for (const auto& cand : candidates) { - - hCandidateCounter->Fill(0); - - if (!TESTBIT(cand.hfflag(), aod::hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi)) { - continue; - } - - hCandidateCounter->Fill(1); - - auto collision = cand.collision_as(); - - // set the magnetic field from CCDB - auto bc = collision.bc_as(); - initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, lut, isRun2); - auto magneticField = o2::base::Propagator::Instance()->getNominalBz(); // z component - df.setBz(magneticField); - - auto trackPion = cand.prong0_as(); - auto cascAodElement = cand.cascade_as(); - hCascadesCounter->Fill(0); - int v0index = cascAodElement.v0Id(); - if (!cascAodElement.has_cascData()) - continue; - auto casc = cascAodElement.cascData_as(); - hCascadesCounter->Fill(1); - auto trackXiDauCharged = casc.bachelor_as(); // pion <- xi track - auto trackV0Dau0 = casc.posTrack_as(); // V0 positive daughter track - auto trackV0Dau1 = casc.negTrack_as(); // V0 negative daughter track - - //-------------------------- V0 info--------------------------- - // pseudorapidity - double pseudorapV0Dau0 = trackV0Dau0.eta(); - double pseudorapV0Dau1 = trackV0Dau1.eta(); - - // info from LF table - std::array pVecV0 = {casc.pxlambda(), casc.pylambda(), casc.pzlambda()}; - std::array vertexV0 = {casc.xlambda(), casc.ylambda(), casc.zlambda()}; - std::array pVecV0Dau0 = {casc.pxpos(), casc.pypos(), casc.pzpos()}; - std::array pVecV0Dau1 = {casc.pxneg(), casc.pyneg(), casc.pzneg()}; - - //-------------------reconstruct cascade track------------------ - // pseudorapidity - double pseudorapPiFromCas = trackXiDauCharged.eta(); - - // info from LF table - std::array vertexCasc = {casc.x(), casc.y(), casc.z()}; - std::array pVecCasc = {casc.px(), casc.py(), casc.pz()}; - std::array covCasc = {0.}; - constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component - for (int i = 0; i < 6; i++) { - covCasc[MomInd[i]] = casc.momentumCovMat()[i]; - covCasc[i] = casc.positionCovMat()[i]; - } - // create cascade track - o2::track::TrackParCov trackCasc; - if (trackXiDauCharged.sign() > 0) { - trackCasc = o2::track::TrackParCov(vertexCasc, pVecCasc, covCasc, 1, true); - } else if (trackXiDauCharged.sign() < 0) { - trackCasc = o2::track::TrackParCov(vertexCasc, pVecCasc, covCasc, -1, true); - } else { - continue; - } - trackCasc.setAbsCharge(1); - trackCasc.setPID(o2::track::PID::XiMinus); - - std::array pVecPionFromCasc = {casc.pxbach(), casc.pybach(), casc.pzbach()}; - - //------------reconstruct charm baryon decay vtx--------------- - auto trackParVarPi = getTrackParCov(trackPion); // charm bachelor pion track to be processed with DCAFitter - - // reconstruct charm baryon with DCAFitter - int nVtxFromFitterCharmBaryon = 0; - try { - nVtxFromFitterCharmBaryon = df.process(trackCasc, trackParVarPi); - } catch (...) { - LOG(error) << "Exception caught in charm DCA fitter process call!"; - hFitterStatus->Fill(1); - continue; - } - if (nVtxFromFitterCharmBaryon == 0) { - hFitterStatus->Fill(2); - continue; - } - hFitterStatus->Fill(0); - hCandidateCounter->Fill(2); - auto vertexCharmBaryonFromFitter = df.getPCACandidate(); - std::array pVecCascAsD; - std::array pVecPionFromCharmBaryon; - df.propagateTracksToVertex(); - if (!df.isPropagateTracksToVertexDone()) { - continue; - } - df.getTrack(0).getPxPyPzGlo(pVecCascAsD); - df.getTrack(1).getPxPyPzGlo(pVecPionFromCharmBaryon); - std::array pVecCharmBaryon = {pVecCascAsD[0] + pVecPionFromCharmBaryon[0], pVecCascAsD[1] + pVecPionFromCharmBaryon[1], pVecCascAsD[2] + pVecPionFromCharmBaryon[2]}; - - std::array coordVtxCharmBaryon = df.getPCACandidatePos(); - std::array covVtxCharmBaryon = df.calcPCACovMatrixFlat(); - - // pseudorapidity - double pseudorapPiFromCharmBaryon = trackPion.eta(); - - // DCAxy (computed with propagateToDCABxByBz method) - float dcaxyV0Dau0 = trackV0Dau0.dcaXY(); - float dcaxyV0Dau1 = trackV0Dau1.dcaXY(); - float dcaxyPiFromCasc = trackXiDauCharged.dcaXY(); - - // DCAz (computed with propagateToDCABxByBz method) - float dcazV0Dau0 = trackV0Dau0.dcaZ(); - float dcazV0Dau1 = trackV0Dau1.dcaZ(); - float dcazPiFromCasc = trackXiDauCharged.dcaZ(); - - // primary vertex of the collision - auto primaryVertex = getPrimaryVertex(collision); // get the associated covariance matrix with auto covMatrixPV = primaryVertex.getCov(); - std::array pvCoord = {collision.posX(), collision.posY(), collision.posZ()}; - - // impact parameters - o2::dataformats::DCA impactParameterCasc; - o2::dataformats::DCA impactParameterPiFromCharmBaryon; - o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertex, trackCasc, 2.f, matCorr, &impactParameterCasc); - o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertex, trackParVarPi, 2.f, matCorr, &impactParameterPiFromCharmBaryon); - float impactParPiFromCharmBaryonXY = impactParameterPiFromCharmBaryon.getY(); - float impactParPiFromCharmBaryonZ = impactParameterPiFromCharmBaryon.getZ(); - - // invariant mass under the hypothesis of particles ID corresponding to the decay chain - double mLambda = casc.mLambda(); // from LF table, V0 mass under lambda hypothesis - double mCasc = casc.mXi(); - const std::array arrMassCharmBaryon = {massXiFromPDG, massPionFromPDG}; - double mCharmBaryon = RecoDecay::m(std::array{pVecCascAsD, pVecPionFromCharmBaryon}, arrMassCharmBaryon); - - // computing cosPA - double cpaV0 = casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); - double cpaCharmBaryon = RecoDecay::cpa(pvCoord, coordVtxCharmBaryon, pVecCharmBaryon); - double cpaCasc = casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()); - double cpaxyV0 = RecoDecay::cpaXY(pvCoord, vertexV0, pVecV0); - double cpaxyCharmBaryon = RecoDecay::cpaXY(pvCoord, coordVtxCharmBaryon, pVecCharmBaryon); - double cpaxyCasc = RecoDecay::cpaXY(pvCoord, vertexCasc, pVecCasc); - - // computing decay length and ctau - double decLenCharmBaryon = RecoDecay::distance(pvCoord, coordVtxCharmBaryon); - double decLenCascade = RecoDecay::distance(coordVtxCharmBaryon, vertexCasc); - double decLenV0 = RecoDecay::distance(vertexCasc, vertexV0); - - double phiCharmBaryon, thetaCharmBaryon; - getPointDirection(std::array{primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, coordVtxCharmBaryon, phiCharmBaryon, thetaCharmBaryon); - auto errorDecayLengthCharmBaryon = std::sqrt(getRotatedCovMatrixXX(primaryVertex.getCov(), phiCharmBaryon, thetaCharmBaryon) + getRotatedCovMatrixXX(covVtxCharmBaryon, phiCharmBaryon, thetaCharmBaryon)); - auto errorDecayLengthXYCharmBaryon = std::sqrt(getRotatedCovMatrixXX(primaryVertex.getCov(), phiCharmBaryon, 0.) + getRotatedCovMatrixXX(covVtxCharmBaryon, phiCharmBaryon, 0.)); - - double ctOmegac = RecoDecay::ct(pVecCharmBaryon, decLenCharmBaryon, massOmegacFromPDG); - double ctXic = RecoDecay::ct(pVecCharmBaryon, decLenCharmBaryon, massXicFromPDG); - double ctCascade = RecoDecay::ct(pVecCasc, decLenCascade, massXiFromPDG); - double ctV0 = RecoDecay::ct(pVecV0, decLenV0, massLambdaFromPDG); - - // computing eta - double pseudorapCharmBaryon = RecoDecay::eta(pVecCharmBaryon); - double pseudorapCascade = RecoDecay::eta(pVecCasc); - double pseudorapV0 = RecoDecay::eta(pVecV0); - - // DCA between daughters - float dcaCascDau = casc.dcacascdaughters(); - float dcaV0Dau = casc.dcaV0daughters(); - float dcaCharmBaryonDau = std::sqrt(df.getChi2AtPCACandidate()); - - // set hfFlag - int hfFlag = 1 << aod::hf_cand_toxipi::DecayType::DecayToXiPi; - - // fill test histograms - hInvMassCharmBaryon->Fill(mCharmBaryon); - hCandidateCounter->Fill(3); - - // fill the table - rowCandidate(collision.globalIndex(), - pvCoord[0], pvCoord[1], pvCoord[2], - vertexCharmBaryonFromFitter[0], vertexCharmBaryonFromFitter[1], vertexCharmBaryonFromFitter[2], - vertexCasc[0], vertexCasc[1], vertexCasc[2], - vertexV0[0], vertexV0[1], vertexV0[2], - trackXiDauCharged.sign(), - covVtxCharmBaryon[0], covVtxCharmBaryon[1], covVtxCharmBaryon[2], covVtxCharmBaryon[3], covVtxCharmBaryon[4], covVtxCharmBaryon[5], - pVecCharmBaryon[0], pVecCharmBaryon[1], pVecCharmBaryon[2], - pVecCasc[0], pVecCasc[1], pVecCasc[2], - pVecPionFromCharmBaryon[0], pVecPionFromCharmBaryon[1], pVecPionFromCharmBaryon[2], - pVecV0[0], pVecV0[1], pVecV0[2], - pVecPionFromCasc[0], pVecPionFromCasc[1], pVecPionFromCasc[2], - pVecV0Dau0[0], pVecV0Dau0[1], pVecV0Dau0[2], - pVecV0Dau1[0], pVecV0Dau1[1], pVecV0Dau1[2], - impactParameterCasc.getY(), impactParPiFromCharmBaryonXY, - impactParameterCasc.getZ(), impactParPiFromCharmBaryonZ, - std::sqrt(impactParameterCasc.getSigmaY2()), std::sqrt(impactParameterPiFromCharmBaryon.getSigmaY2()), - v0index, casc.posTrackId(), casc.negTrackId(), - casc.cascadeId(), trackPion.globalIndex(), casc.bachelorId(), - mLambda, mCasc, mCharmBaryon, - cpaV0, cpaCharmBaryon, cpaCasc, cpaxyV0, cpaxyCharmBaryon, cpaxyCasc, - ctOmegac, ctCascade, ctV0, ctXic, - pseudorapV0Dau0, pseudorapV0Dau1, pseudorapPiFromCas, pseudorapPiFromCharmBaryon, - pseudorapCharmBaryon, pseudorapCascade, pseudorapV0, - dcaxyV0Dau0, dcaxyV0Dau1, dcaxyPiFromCasc, - dcazV0Dau0, dcazV0Dau1, dcazPiFromCasc, - dcaCascDau, dcaV0Dau, dcaCharmBaryonDau, - decLenCharmBaryon, decLenCascade, decLenV0, errorDecayLengthCharmBaryon, errorDecayLengthXYCharmBaryon, - hfFlag); - - } // loop over LF Cascade-bachelor candidates - } // end of process -}; // end of struct - -/// Performs MC matching. -struct HfCandidateCreatorToXiPiMc { - Produces rowMCMatchRec; - Produces rowMCMatchGen; - - Configurable matchOmegacMc{"matchOmegacMc", true, "Do MC matching for Omegac0"}; - Configurable matchXicMc{"matchXicMc", false, "Do MC matching for Xic0"}; - - void init(InitContext const&) {} - - void processDoNoMc(aod::Collisions::iterator const&) - { - // dummy process function - should not be required in the future - } - PROCESS_SWITCH(HfCandidateCreatorToXiPiMc, processDoNoMc, "Do not run MC process function", true); - - void processMc(aod::HfCandToXiPi const& candidates, - aod::TracksWMc const&, - aod::McParticles const& mcParticles, - aod::McCollisionLabels const&) - { - float ptCharmBaryonGen = -999.; - float etaCharmBaryonGen = -999.; - int indexRec = -1; - int indexRecCharmBaryon = -1; - int8_t sign = -9; - int8_t signCasc = -9; - int8_t signV0 = -9; - int8_t flag = 0; - int8_t origin = 0; // to be used for prompt/non prompt - int8_t debug = 0; - int8_t debugGenCharmBar = 0; - int8_t debugGenXi = 0; - int8_t debugGenLambda = 0; - bool collisionMatched = false; - - int pdgCodeOmegac0 = Pdg::kOmegaC0; // 4332 - int pdgCodeXic0 = Pdg::kXiC0; // 4132 - int pdgCodeXiMinus = kXiMinus; // 3312 - int pdgCodeLambda = kLambda0; // 3122 - int pdgCodePiPlus = kPiPlus; // 211 - int pdgCodePiMinus = kPiMinus; // -211 - int pdgCodeProton = kProton; // 2212 - - // Match reconstructed candidates. - for (const auto& candidate : candidates) { - flag = 0; - origin = RecoDecay::OriginType::None; - debug = 0; - collisionMatched = false; - - auto arrayDaughters = std::array{candidate.piFromCharmBaryon_as(), // pi <- charm baryon - candidate.bachelor_as(), // pi <- cascade - candidate.posTrack_as(), // p <- lambda - candidate.negTrack_as()}; // pi <- lambda - auto arrayDaughtersCasc = std::array{candidate.bachelor_as(), - candidate.posTrack_as(), - candidate.negTrack_as()}; - auto arrayDaughtersV0 = std::array{candidate.posTrack_as(), - candidate.negTrack_as()}; - - // Omegac matching - if (matchOmegacMc) { - // Omegac → pi pi pi p - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, pdgCodeOmegac0, std::array{pdgCodePiPlus, pdgCodePiMinus, pdgCodeProton, pdgCodePiMinus}, true, &sign, 3); - indexRecCharmBaryon = indexRec; - if (indexRec == -1) { - debug = 1; - } - if (indexRec > -1) { - // Xi- → pi pi p - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, pdgCodeXiMinus, std::array{pdgCodePiMinus, pdgCodeProton, pdgCodePiMinus}, true, &signCasc, 2); - if (indexRec == -1) { - debug = 2; - } - if (indexRec > -1) { - // Lambda → p pi - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, pdgCodeLambda, std::array{pdgCodeProton, pdgCodePiMinus}, true, &signV0, 1); - if (indexRec == -1) { - debug = 3; - } - if (indexRec > -1) { - flag = sign * (1 << aod::hf_cand_toxipi::DecayType::OmegaczeroToXiPi); - collisionMatched = candidate.collision_as().mcCollisionId() == mcParticles.iteratorAt(indexRecCharmBaryon).mcCollisionId(); - } - } - } - - // Check whether the charm baryon is non-prompt (from a b quark). - if (flag != 0) { - auto particle = mcParticles.rawIteratorAt(indexRecCharmBaryon); - origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, true); - } - } - // Xic matching - if (matchXicMc) { - // Xic → pi pi pi p - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, pdgCodeXic0, std::array{pdgCodePiPlus, pdgCodePiMinus, pdgCodeProton, pdgCodePiMinus}, true, &sign, 3); - indexRecCharmBaryon = indexRec; - if (indexRec == -1) { - debug = 1; - } - if (indexRec > -1) { - // Xi- → pi pi p - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, pdgCodeXiMinus, std::array{pdgCodePiMinus, pdgCodeProton, pdgCodePiMinus}, true, &signCasc, 2); - if (indexRec == -1) { - debug = 2; - } - if (indexRec > -1) { - // Lambda → p pi - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, pdgCodeLambda, std::array{pdgCodeProton, pdgCodePiMinus}, true, &signV0, 1); - if (indexRec == -1) { - debug = 3; - } - if (indexRec > -1) { - flag = sign * (1 << aod::hf_cand_toxipi::DecayType::XiczeroToXiPi); - collisionMatched = candidate.collision_as().mcCollisionId() == mcParticles.iteratorAt(indexRecCharmBaryon).mcCollisionId(); - } - } - } - - // Check whether the charm baryon is non-prompt (from a b quark). - if (flag != 0) { - auto particle = mcParticles.rawIteratorAt(indexRecCharmBaryon); - origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, true); - } - } - - if (debug == 2 || debug == 3) { - LOGF(info, "WARNING: Charm baryon decays in the expected final state but the condition on the intermediate states are not fulfilled"); - } - rowMCMatchRec(flag, debug, origin, collisionMatched); - - } // close loop over candidates - - // Match generated particles. - for (const auto& particle : mcParticles) { - ptCharmBaryonGen = -999.; - etaCharmBaryonGen = -999.; - flag = 0; - sign = -9; - debugGenCharmBar = 0; - debugGenXi = 0; - debugGenLambda = 0; - origin = RecoDecay::OriginType::None; - if (matchOmegacMc) { - // Omegac → Xi pi - if (RecoDecay::isMatchedMCGen(mcParticles, particle, pdgCodeOmegac0, std::array{pdgCodeXiMinus, pdgCodePiPlus}, true, &sign)) { - debugGenCharmBar = 1; - ptCharmBaryonGen = particle.pt(); - etaCharmBaryonGen = particle.eta(); - for (const auto& daughterCharm : particle.daughters_as()) { - if (std::abs(daughterCharm.pdgCode()) != pdgCodeXiMinus) { - continue; - } - // Xi -> Lambda pi - if (RecoDecay::isMatchedMCGen(mcParticles, daughterCharm, pdgCodeXiMinus, std::array{pdgCodeLambda, pdgCodePiMinus}, true)) { - debugGenXi = 1; - for (const auto& daughterCascade : daughterCharm.daughters_as()) { - if (std::abs(daughterCascade.pdgCode()) != pdgCodeLambda) { - continue; - } - // Lambda -> p pi - if (RecoDecay::isMatchedMCGen(mcParticles, daughterCascade, pdgCodeLambda, std::array{pdgCodeProton, pdgCodePiMinus}, true)) { - debugGenLambda = 1; - flag = sign * (1 << aod::hf_cand_toxipi::DecayType::OmegaczeroToXiPi); - } - } - } - } - } - // Check whether the charm baryon is non-prompt (from a b quark) - if (flag != 0) { - origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, true); - } - } - - if (matchXicMc) { - // Xic → Xi pi - if (RecoDecay::isMatchedMCGen(mcParticles, particle, pdgCodeXic0, std::array{pdgCodeXiMinus, pdgCodePiPlus}, true, &sign)) { - debugGenCharmBar = 1; - ptCharmBaryonGen = particle.pt(); - etaCharmBaryonGen = particle.eta(); - for (const auto& daughterCharm : particle.daughters_as()) { - if (std::abs(daughterCharm.pdgCode()) != pdgCodeXiMinus) { - continue; - } - // Xi -> Lambda pi - if (RecoDecay::isMatchedMCGen(mcParticles, daughterCharm, pdgCodeXiMinus, std::array{pdgCodeLambda, pdgCodePiMinus}, true)) { - debugGenXi = 1; - for (const auto& daughterCascade : daughterCharm.daughters_as()) { - if (std::abs(daughterCascade.pdgCode()) != pdgCodeLambda) { - continue; - } - // Lambda -> p pi - if (RecoDecay::isMatchedMCGen(mcParticles, daughterCascade, pdgCodeLambda, std::array{pdgCodeProton, pdgCodePiMinus}, true)) { - debugGenLambda = 1; - flag = sign * (1 << aod::hf_cand_toxipi::DecayType::XiczeroToXiPi); - } - } - } - } - } - // Check whether the charm baryon is non-prompt (from a b quark) - if (flag != 0) { - origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, true); - } - } - - rowMCMatchGen(flag, debugGenCharmBar, debugGenXi, debugGenLambda, ptCharmBaryonGen, etaCharmBaryonGen, origin); - } - } // close process - PROCESS_SWITCH(HfCandidateCreatorToXiPiMc, processMc, "Process MC", false); -}; // close struct - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGHF/TableProducer/candidateCreatorXic0Omegac0.cxx b/PWGHF/TableProducer/candidateCreatorXic0Omegac0.cxx new file mode 100644 index 00000000000..01a52fc073e --- /dev/null +++ b/PWGHF/TableProducer/candidateCreatorXic0Omegac0.cxx @@ -0,0 +1,2545 @@ +// 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 candidateCreatorXic0Omegac0.cxx +/// \brief Reconstruction of Omegac0 and Xic0 decays candidates +/// \author Federica Zanone , Heidelberg University +/// \author Ruiqi Yin , Fudan University +/// \author Yunfan Liu , China University of Geosciences + +#ifndef HomogeneousField +#define HomogeneousField // o2-linter: disable=name/macro (required by KFParticle) +#endif + +#include +#include +#include +#include + +/// includes KFParticle +#include "KFParticle.h" +#include "KFParticleBase.h" +#include "KFPTrack.h" +#include "KFPVertex.h" +#include "KFVertex.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DCAFitter/DCAFitterN.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/V0.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Tools/KFparticle/KFUtilities.h" + +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsEvSelHf.h" + +using namespace o2; +using namespace o2::track; +using namespace o2::analysis; +using namespace o2::aod; +using namespace o2::aod::cascdata; +using namespace o2::aod::v0data; +using namespace o2::aod::hf_track_index; +using namespace o2::hf_centrality; +using namespace o2::constants::physics; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::hf_evsel; + +enum McMatchFlag : uint8_t { + None = 0, + CharmbaryonUnmatched, + CascUnmatched, + V0Unmatched +}; + +// Reconstruction of omegac0 and xic0 candidates +struct HfCandidateCreatorXic0Omegac0 { + Produces rowCandToXiPi; + Produces rowCandToOmegaPi; + Produces rowCandToOmegaK; + Produces kfCandidateData; + Produces kfCandidateXicData; + + Configurable propagateToPCA{"propagateToPCA", false, "create tracks version propagated to PCA"}; + Configurable useAbsDCA{"useAbsDCA", true, "Minimise abs. distance rather than chi2"}; + Configurable useWeightedFinalPCA{"useWeightedFinalPCA", true, "Recalculate vertex position using track covariances, effective only if useAbsDCA is true"}; + Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; + Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; + Configurable maxDXYIni{"maxDXYIni", 4., "reject (if>0) PCA candidate if tracks DXY exceeds threshold"}; + Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations is chi2/chi2old > this"}; + Configurable maxChi2{"maxChi2", 100., "discard vertices with chi2/Nprongs > this (or sum{DCAi^2}/Nprongs for abs. distance minimization)"}; + Configurable refitWithMatCorr{"refitWithMatCorr", true, "when doing propagateTracksToVertex, propagate tracks to vtx with material corrections and rerun minimization"}; + Configurable rejDiffCollTrack{"rejDiffCollTrack", true, "Reject tracks coming from different collisions"}; + Configurable fillAllHist{"fillAllHist", true, "Fill additional KF histograms to check selector cuts"}; + + // magnetic field setting from CCDB + Configurable isRun2{"isRun2", false, "enable Run 2 or Run 3 GRP objects for magnetic field"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; + Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + + // KFParticle process setting + // V0 cuts + Configurable lambdaMassWindow{"lambdaMassWindow", 0.0075, "Distance from Lambda mass"}; + // cascade cuts + Configurable massToleranceCascade{"massToleranceCascade", 0.01, "Invariant mass tolerance for cascade"}; + // for KF particle operation + Configurable kfConstructMethod{"kfConstructMethod", 2, "KF Construct Method"}; + Configurable kfUseV0MassConstraint{"kfUseV0MassConstraint", false, "KF: use Lambda mass constraint"}; + Configurable kfUseCascadeMassConstraint{"kfUseCascadeMassConstraint", false, "KF: use Cascade mass constraint"}; + + HfEventSelection hfEvSel; // event selection and monitoring + o2::vertexing::DCAFitterN<2> df; // 2-prong vertex fitter to build the omegac/xic vertex + Service ccdb; + o2::base::MatLayerCylSet* lut; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + int runNumber{-1}; + double magneticField{0.}; + + using MyCascTable = soa::Join; + using MyTraCascTable = soa::Join; // to use strangeness tracking + using CascadesLinked = soa::Join; + using TraCascadesLinked = soa::Join; + using MyV0Table = soa::Join; + using MyLFTracksWCov = soa::Join; + + using MyKfTracks = soa::Join; + using MyKfCascTable = soa::Join; + using KFCascadesLinked = soa::Join; + + std::shared_ptr hInvMassCharmBaryonToXiPi, hInvMassCharmBaryonToOmegaPi, hInvMassCharmBaryonToOmegaK, hFitterStatusToXiPi, hFitterStatusToOmegaPi, hFitterStatusToOmegaK, hCandidateCounterToXiPi, hCandidateCounterToOmegaPi, hCandidateCounterToOmegaK, hCascadesCounterToXiPi, hCascadesCounterToOmegaPi, hCascadesCounterToOmegaK; + + HistogramRegistry registry{"registry"}; + // Helper struct to pass information + struct { + float chi2GeoV0; + float ldlV0; + float chi2NdfTopoV0ToPv; + float chi2GeoCasc; + float ldlCasc; + float chi2NdfTopoCascToPv; + float decayLenXYLambda; + float decayLenXYCasc; + float cosPaV0ToCasc; + float cosPaXYV0ToCasc; + float cosPaV0ToPv; + float cosPaXYV0ToPv; + float cosPaCascToOmegac; + float cosPaXYCascToOmegac; + float cosPaCascToPv; + float cosPaXYCascToPv; + float massV0; + float massCasc; + float ptPiFromOmegac; + float ptOmegac; + float rapOmegac; + float massOmegac; + float cosThetaStarPiFromOmegac; + float chi2NdfTopoPiFromOmegacToPv; + float deviationPiFromOmegacToPv; + float kfDcaXYPiFromOmegac; + float chi2NdfTopoV0ToCasc; + float chi2NdfTopoCascToOmegac; + float decayLenXYOmegac; + float chi2GeoOmegac; + float kfDcaV0Dau; + float kfDcaCascDau; + float kfDcaOmegacDau; + float kfDcaXYCascToPv; + float chi2NdfTopoOmegacToPv; + float cosPaOmegacToPv; + float cosPaXYOmegacToPv; + float ldlOmegac; + float ctV0; + float ctCasc; + float ctOmegac; + float chi2MassV0; + float chi2MassCasc; + float etaOmegac; + float cascRejectInvmass; // rej + } kfOmegac0Candidate; + + struct { + float chi2GeoV0; + float ldlV0; + float chi2NdfTopoV0ToPv; + float chi2GeoCasc; + float ldlCasc; + float chi2NdfTopoCascToPv; + float decayLenXYLambda; + float decayLenXYCasc; + float cosPaV0ToCasc; + float cosPaXYV0ToCasc; + float cosPaV0ToPv; + float cosPaXYV0ToPv; + float cosPaCascToXic; + float cosPaXYCascToXic; + float cosPaCascToPv; + float cosPaXYCascToPv; + float massV0; + float massCasc; + float ptPiFromXic; + float ptXic; + float rapXic; + float massXic; + float cosThetaStarPiFromXic; + float chi2NdfTopoPiFromXicToPv; + float kfDcaXYPiFromXic; + float chi2NdfTopoV0ToCasc; + float chi2NdfTopoCascToXic; + float decayLenXYXic; + float chi2GeoXic; + float kfDcaV0Dau; + float kfDcaCascDau; + float kfDcaXicDau; + float kfDcaXYCascToPv; + float chi2NdfTopoXicToPv; + float cosPaXicToPv; + float cosPaXYXicToPv; + float ldlXic; + float ctV0; + float ctCasc; + float ctXic; + float ctOmegac; + float chi2MassV0; + float chi2MassCasc; + float etaXic; + } kfXic0Candidate; + void init(InitContext const&) + { + std::array allProcesses = {doprocessNoCentToXiPi, doprocessNoCentToXiPiTraCasc, doprocessCentFT0CToXiPi, doprocessCentFT0MToXiPi, doprocessNoCentToOmegaPi, doprocessOmegacToOmegaPiWithKFParticle, doprocessCentFT0CToOmegaPi, doprocessCentFT0MToOmegaPi, doprocessNoCentToOmegaK, doprocessCentFT0CToOmegaK, doprocessCentFT0MToOmegaK, doprocessXicToXiPiWithKFParticle}; + if (std::accumulate(allProcesses.begin(), allProcesses.end(), 0) == 0) { + LOGP(fatal, "No process function enabled, please select one for at least one channel."); + } + + std::array processesToXiPi = {doprocessNoCentToXiPi, doprocessNoCentToXiPiTraCasc, doprocessCentFT0CToXiPi, doprocessCentFT0MToXiPi, doprocessXicToXiPiWithKFParticle}; + if (std::accumulate(processesToXiPi.begin(), processesToXiPi.end(), 0) > 1) { + LOGP(fatal, "One and only one ToXiPi process function must be enabled at a time."); + } + std::array processesToOmegaPi = {doprocessNoCentToOmegaPi, doprocessCentFT0CToOmegaPi, doprocessCentFT0MToOmegaPi, doprocessOmegacToOmegaPiWithKFParticle}; + if (std::accumulate(processesToOmegaPi.begin(), processesToOmegaPi.end(), 0) > 1) { + LOGP(fatal, "One and only one process ToOmegaPi function must be enabled at a time."); + } + std::array processesToOmegaK = {doprocessNoCentToOmegaK, doprocessCentFT0CToOmegaK, doprocessCentFT0MToOmegaK}; + if (std::accumulate(processesToOmegaK.begin(), processesToOmegaK.end(), 0) > 1) { + LOGP(fatal, "One and only one process ToOmegaK function must be enabled at a time."); + } + + std::array processesCollisions = {doprocessCollisions, doprocessCollisionsCentFT0C, doprocessCollisionsCentFT0M}; + const int nProcessesCollisions = std::accumulate(processesCollisions.begin(), processesCollisions.end(), 0); + if (nProcessesCollisions > 1) { + LOGP(fatal, "At most one process function for collision monitoring can be enabled at a time."); + } + if (nProcessesCollisions == 1) { + if ((doprocessNoCentToXiPi && !doprocessCollisions) || (doprocessNoCentToXiPiTraCasc && !doprocessCollisions) || (doprocessNoCentToOmegaPi && !doprocessCollisions) || (doprocessNoCentToOmegaK && !doprocessCollisions) || (doprocessOmegacToOmegaPiWithKFParticle && !doprocessCollisions) || (doprocessXicToXiPiWithKFParticle && !doprocessCollisions)) { + LOGP(fatal, "Process function for collision monitoring not correctly enabled. Did you enable \"processCollisions\"?"); + } + if ((doprocessCentFT0CToXiPi && !doprocessCollisionsCentFT0C) || (doprocessCentFT0CToOmegaPi && !doprocessCollisionsCentFT0C) || (doprocessCentFT0CToOmegaK && !doprocessCollisionsCentFT0C)) { + LOGP(fatal, "Process function for collision monitoring not correctly enabled. Did you enable \"processCollisionsCentFT0C\"?"); + } + if ((doprocessCentFT0MToXiPi && !doprocessCollisionsCentFT0M) || (doprocessCentFT0MToOmegaPi && !doprocessCollisionsCentFT0M) || (doprocessCentFT0MToOmegaK && !doprocessCollisionsCentFT0M)) { + LOGP(fatal, "Process function for collision monitoring not correctly enabled. Did you enable \"processCollisionsCentFT0M\"?"); + } + } + + hInvMassCharmBaryonToXiPi = registry.add("hInvMassCharmBaryonToXiPi", "Charm baryon invariant mass - #Xi #pi decay;inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 2.2, 3.1}}}); + hInvMassCharmBaryonToOmegaPi = registry.add("hInvMassCharmBaryonToOmegaPi", "Charm baryon invariant mass - #Omega #pi decay;inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 2.2, 3.1}}}); + hInvMassCharmBaryonToOmegaK = registry.add("hInvMassCharmBaryonToOmegaK", "Charm baryon invariant mass - #Omega K decay;inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 2.2, 3.1}}}); + hFitterStatusToXiPi = registry.add("hFitterStatusToXiPi", "Charm DCAFitter status - #Xi #pi vtx;status;entries", {HistType::kTH1D, {{3, -0.5, 2.5}}}); // 0 --> vertex(es) found, 1 --> exception found, 2 --> no vertex found (but no exception) + hFitterStatusToOmegaPi = registry.add("hFitterStatusToOmegaPi", "Charm DCAFitter status - #Omega #pi vtx ;status;entries", {HistType::kTH1D, {{3, -0.5, 2.5}}}); // 0 --> vertex(es) found, 1 --> exception found, 2 --> no vertex found (but no exception) + hFitterStatusToOmegaK = registry.add("hFitterStatusToOmegaK", "Charm DCAFitter status - #Omega K vtx;status;entries", {HistType::kTH1D, {{3, -0.5, 2.5}}}); // 0 --> vertex(es) found, 1 --> exception found, 2 --> no vertex found (but no exception) + hCandidateCounterToXiPi = registry.add("hCandidateCounterToXiPi", "Candidate counter wrt derived data - #Xi #pi decay;status;entries", {HistType::kTH1D, {{4, -0.5, 3.5}}}); // 0 --> candidates in derived data table, 1 --> candidates passing testbit selection, 2 --> candidates passing fitter step 3 --> candidates filled in new table + hCandidateCounterToOmegaPi = registry.add("hCandidateCounterToOmegaPi", "Candidate counter wrt derived data - #Omega #pi decay;status;entries", {HistType::kTH1D, {{4, -0.5, 3.5}}}); // 0 --> candidates in derived data table, 1 --> candidates passing testbit selection, 2 --> candidates passing fitter step 3 --> candidates filled in new table + hCandidateCounterToOmegaK = registry.add("hCandidateCounterToOmegaK", "Candidate counter wrt derived data - #Omega K decay;status;entries", {HistType::kTH1D, {{4, -0.5, 3.5}}}); // 0 --> candidates in derived data table, 1 --> candidates passing testbit selection, 2 --> candidates passing fitter step 3 --> candidates filled in new table + hCascadesCounterToXiPi = registry.add("hCascadesCounterToXiPi", "Cascades counter wrt derived data - #Xi #pi decay;status;entries", {HistType::kTH1D, {{2, -0.5, 1.5}}}); // 0 --> cascades in derived data table (and stored in AOD table), 1 --> cascades in derived data table and also accessible in cascData table + hCascadesCounterToOmegaPi = registry.add("hCascadesCounterToOmegaPi", "Cascades counter wrt derived data - #Omega #pi decay;status;entries", {HistType::kTH1D, {{2, -0.5, 1.5}}}); // 0 --> cascades in derived data table (and stored in AOD table), 1 --> cascades in derived data table and also accessible in cascData table + hCascadesCounterToOmegaK = registry.add("hCascadesCounterToOmegaK", "Cascades counter wrt derived data - #Omega K decay;status;entries", {HistType::kTH1D, {{2, -0.5, 1.5}}}); // 0 --> cascades in derived data table (and stored in AOD table), 1 --> cascades in derived data table and also accessible in cascData table + + // KFParticle Variables Histograms + registry.add("hKFParticleV0TopoChi2", "hKFParticleV0TopoChi2", kTH1D, {{1000, -0.10f, 100.0f}}); + registry.add("hKFParticleCascTopoChi2", "hKFParticleCascTopoChi2", kTH1D, {{1000, -0.1f, 100.0f}}); + registry.add("hKfChi2TopoPiFromCharmBaryon", "hKfChi2TopoPifromCharmBaryon", kTH1F, {{2000, -0.1f, 1000.0f}}); + registry.add("hKfNdfPiFromCharmBaryon", "hKfNDfPifromCharmBaryon", kTH1F, {{2000, -0.1f, 200.0f}}); + registry.add("hKfChi2OverNdfPiFromCharmBaryon", "hKfChi2OverNdfPifromCharmBaryon", kTH1F, {{1000, -0.1f, 200.0f}}); + registry.add("hKFParticlechi2TopoOmegacToPv", "hKFParticlechi2TopoOmegacToPv", kTH1D, {{1000, -0.1f, 100.0f}}); + registry.add("hKfNdfOmegacToPv", "hKfNDfOmegacToPv", kTH1F, {{2000, -0.1f, 200.0f}}); + registry.add("hKfChi2TopoOmegacToPv", "hKfChi2TopoOmegacToPv", kTH1F, {{1000, -0.1f, 200.0f}}); + registry.add("hKfDeviationPiFromCharmBaryon", "hKfDeviationPiFromCharmBaryon", kTH1F, {{1000, -0.1f, 200.0f}}); + registry.add("hKFParticleCascBachTopoChi2", "hKFParticleCascBachTopoChi2", kTH1D, {{1000, -0.1f, 100.0f}}); + registry.add("hKFParticleDcaCharmBaryonDau", "hKFParticleDcaCharmBaryonDau", kTH1D, {{1000, -0.1f, 1.0f}}); + registry.add("hKFParticleDcaXYCascBachToPv", "hKFParticleDcaXYCascBachToPv", kTH1D, {{1000, -0.1f, 15.0f}}); + registry.add("hKfLambda_ldl", "hKfLambda_ldl", kTH1D, {{1000, 0.0f, 1000.0f}}); + registry.add("hKfOmega_ldl", "hKfOmega_ldl", kTH1D, {{1000, 0.0f, 1000.0f}}); + registry.add("hKfXi_ldl", "hKfXi_ldl", kTH1D, {{1000, 0.0f, 1000.0f}}); + registry.add("hKfOmegaC0_ldl", "hKfOmegaC0_ldl", kTH1D, {{1000, 0.0f, 1000.0f}}); + registry.add("hKfXiC0_ldl", "hKfXiC0_ldl", kTH1D, {{1000, 0.0f, 1000.0f}}); + registry.add("hDcaXYCascadeToPVKf", "hDcaXYCascadeToPVKf", kTH1D, {{1000, 0.0f, 2.0f}}); + registry.add("hInvMassOmegaMinus", "hInvMassOmegaMinus", kTH1D, {{1000, 1.6f, 2.0f}}); + registry.add("hInvMassXiMinus", "hInvMassXiMinus", kTH1D, {{1000, 1.25f, 1.65f}}); + registry.add("hInvMassXiMinus_rej", "hInvMassXiMinus_rej", kTH1D, {{1000, 1.25f, 1.65f}}); + registry.add("hKFParticlechi2TopoCascToPv", "hKFParticlechi2TopoCascToPv", kTH1D, {{1000, -0.1f, 100.0f}}); + registry.add("hKFParticleDcaXYV0DauPosToPv", "hKFParticleDcaXYV0DauPosToPv", kTH1D, {{1000, -0.1f, 30.0f}}); + registry.add("hKFParticleDcaXYV0DauNegToPv", "hKFParticleDcaXYV0DauNegToPv", kTH1D, {{1000, -0.1f, 30.0f}}); + + // Additional KFParticle Histograms + if (fillAllHist) { + registry.add("hEtaV0PosDau", "hEtaV0PosDau", kTH1D, {{1000, -5.0f, 5.0f}}); + registry.add("hEtaV0NegDau", "hEtaV0NegDau", kTH1D, {{1000, -5.0f, 5.0f}}); + registry.add("hEtaKaFromCasc", "hEtaKaFromCasc", kTH1D, {{1000, -5.0f, 5.0f}}); + registry.add("hEtaPiFromCharmBaryon", "hEtaPiFromCharmBaryon", kTH1D, {{1000, -5.0f, 5.0f}}); + registry.add("hCascradius", "hCascradius", kTH1D, {{1000, 0.0f, 50.0f}}); + registry.add("hV0radius", "hV0radius", kTH1D, {{1000, 0.0f, 50.0f}}); + registry.add("hCosPACasc", "hCosPACasc", kTH1D, {{5000, 0.8f, 1.1f}}); + registry.add("hCosPAV0", "hCosPAV0", kTH1D, {{5000, 0.8f, 1.1f}}); + registry.add("hDcaCascDau", "hDcaCascDau", kTH1D, {{1000, -0.1f, 10.0f}}); + registry.add("hDcaV0Dau", "hDcaV0Dau", kTH1D, {{1000, -0.1f, 10.0f}}); + registry.add("hDcaXYToPvKa", "hDcaXYToPvKa", kTH1D, {{1000, -0.1f, 10.0f}}); + registry.add("hImpactParBachFromCharmBaryonXY", "hImpactParBachFromCharmBaryonXY", kTH1D, {{1000, -1.0f, 1.0f}}); + registry.add("hImpactParBachFromCharmBaryonZ", "hImpactParBachFromCharmBaryonZ", kTH1D, {{1000, -2.0f, 2.0f}}); + registry.add("hImpactParCascXY", "hImpactParCascXY", kTH1D, {{1000, -4.0f, 4.0f}}); + registry.add("hImpactParCascZ", "hImpactParCascZ", kTH1D, {{1000, -5.0f, 5.0f}}); + registry.add("hPtKaFromCasc", "hPtKaFromCasc", kTH1D, {{1000, 0.0f, 5.0f}}); + registry.add("hPtPiFromCharmBaryon", "hPtPiFromCharmBaryon", kTH1D, {{1000, 0.0f, 5.0f}}); + registry.add("hCTauOmegac", "hCTauOmegac", kTH1D, {{1000, 0.0f, 0.1f}}); + registry.add("hKFGeoV0Chi2OverNdf", "hKFGeoV0Chi2OverNdf", kTH1D, {{1000, 0.0f, 100.0f}}); + registry.add("hKFGeoCascChi2OverNdf", "hKFGeoCascChi2OverNdf", kTH1D, {{1000, 0.0f, 100.0f}}); + registry.add("hKFGeoCharmbaryonChi2OverNdf", "hKFGeoCharmbaryonChi2OverNdf", kTH1D, {{1000, 0.0f, 100.0f}}); + registry.add("hKFdecayLenXYLambda", "hKFdecayLenXYLambda", kTH1D, {{1000, 0.0f, 50.0f}}); + registry.add("hKFdecayLenXYCasc", "hKFdecayLenXYCasc", kTH1D, {{1000, 0.0f, 50.0f}}); + registry.add("hKFdecayLenXYOmegac", "hKFdecayLenXYOmegac", kTH1D, {{1000, 0.0f, 50.0f}}); + registry.add("hKFcosPaV0ToCasc", "hKFcosPaV0ToCasc", kTH1D, {{5000, 0.8f, 1.1f}}); + registry.add("hKFcosPaCascToOmegac", "hKFcosPaCascToOmegac", kTH1D, {{5000, 0.8f, 1.1f}}); + } + hfEvSel.addHistograms(registry); // collision monitoring + + df.setPropagateToPCA(propagateToPCA); + df.setMaxR(maxR); + df.setMaxDZIni(maxDZIni); + df.setMaxDXYIni(maxDXYIni); + df.setMinParamChange(minParamChange); + df.setMinRelChi2Change(minRelChi2Change); + df.setMaxChi2(maxChi2); + df.setUseAbsDCA(useAbsDCA); + df.setWeightedFinalPCA(useWeightedFinalPCA); + df.setRefitWithMatCorr(refitWithMatCorr); + + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); + runNumber = 0; + } + + template + void runXic0Omegac0Creator(Coll const&, + aod::BCsWithTimestamps const& /*bcWithTimeStamps*/, + MyLFTracksWCov const& lfTracks, + TracksWCovDca const& tracks, + TCascTable const&, TCascLinkTable const&, + aod::HfCascLf2Prongs const& candidates, + Hist& hInvMassCharmBaryon, + Hist& hFitterStatus, + Hist& hCandidateCounter, + Hist& hCascadesCounter) + { + + if constexpr (decayChannel != hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi && decayChannel != hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi && decayChannel != hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK) { + LOGP(fatal, "Decay channel not recognized!"); + } + + for (const auto& cand : candidates) { + + hCandidateCounter->Fill(0); + + if constexpr (decayChannel == hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi) { + if (!TESTBIT(cand.hfflag(), aod::hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi)) { + continue; + } + } else if constexpr (decayChannel == hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi) { + if (!TESTBIT(cand.hfflag(), aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi)) { + continue; + } + } else if constexpr (decayChannel == hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK) { + if (!TESTBIT(cand.hfflag(), aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK)) { + continue; + } + } + + hCandidateCounter->Fill(1); + + auto collision = cand.collision_as(); + float centrality{-1.f}; + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + if (rejectionMask != 0) { + /// at least one event selection not satisfied --> reject the candidate + continue; + } + + // set the magnetic field from CCDB + auto bc = collision.template bc_as(); + if (runNumber != bc.runNumber()) { + LOG(info) << ">>>>>>>>>>>> Current run number: " << runNumber; + initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, lut, isRun2); + magneticField = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << ">>>>>>>>>>>> Magnetic field: " << magneticField; + runNumber = bc.runNumber(); + } + df.setBz(magneticField); + + auto trackCharmBachelorId = cand.prong0Id(); + auto trackCharmBachelor = tracks.rawIteratorAt(trackCharmBachelorId); + + auto cascAodElement = cand.template cascade_as(); + hCascadesCounter->Fill(0); + int v0index = cascAodElement.v0Id(); + + // check if the cascade from AO2D has data + bool hasData = false; + if constexpr (requires { cascAodElement.cascDataId(); }) { // check if it's the CascDataLink + if (cascAodElement.has_cascData()) { + hasData = true; + } + } + if constexpr (requires { cascAodElement.traCascDataId(); }) { // check if it's the TraCascDataLink + if (cascAodElement.has_traCascData()) { + hasData = true; + } + } + if (!hasData) { + continue; + } + + typename TCascTable::iterator casc; + if constexpr (requires { cascAodElement.cascDataId(); }) { // check if it's the CascDataLink + casc = cascAodElement.template cascData_as(); + } + if constexpr (requires { cascAodElement.traCascDataId(); }) { // check if it's the TraCascDataLink + casc = cascAodElement.template traCascData_as(); + } + + hCascadesCounter->Fill(1); + auto trackCascDauChargedId = casc.bachelorId(); // pion <- xi track + auto trackV0Dau0Id = casc.posTrackId(); // V0 positive daughter track + auto trackV0Dau1Id = casc.negTrackId(); // V0 negative daughter track + auto trackCascDauCharged = lfTracks.rawIteratorAt(trackCascDauChargedId); // pion <- xi track + auto trackV0Dau0 = lfTracks.rawIteratorAt(trackV0Dau0Id); // V0 positive daughter track + auto trackV0Dau1 = lfTracks.rawIteratorAt(trackV0Dau1Id); // V0 negative daughter track + + //-------------------------- V0 info--------------------------- + // pseudorapidity + float pseudorapV0Dau0 = casc.positiveeta(); + float pseudorapV0Dau1 = casc.negativeeta(); + + // info from LF table + std::array pVecV0 = {casc.pxlambda(), casc.pylambda(), casc.pzlambda()}; + std::array vertexV0 = {casc.xlambda(), casc.ylambda(), casc.zlambda()}; + std::array pVecV0Dau0 = {casc.pxpos(), casc.pypos(), casc.pzpos()}; + std::array pVecV0Dau1 = {casc.pxneg(), casc.pyneg(), casc.pzneg()}; + + //-------------------reconstruct cascade track------------------ + // pseudorapidity + float pseudorapCascBachelor = casc.bacheloreta(); + + // info from LF table + std::array vertexCasc = {casc.x(), casc.y(), casc.z()}; + std::array pVecCasc = {casc.px(), casc.py(), casc.pz()}; + std::array covCasc = {0.}; + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 6; i++) { + covCasc[MomInd[i]] = casc.momentumCovMat()[i]; + covCasc[i] = casc.positionCovMat()[i]; + } + // create cascade track + o2::track::TrackParCov trackCasc; + if (trackCascDauCharged.sign() > 0) { + trackCasc = o2::track::TrackParCov(vertexCasc, pVecCasc, covCasc, 1, true); + } else if (trackCascDauCharged.sign() < 0) { + trackCasc = o2::track::TrackParCov(vertexCasc, pVecCasc, covCasc, -1, true); + } else { + continue; + } + trackCasc.setAbsCharge(1); + if constexpr (decayChannel == hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi) { + trackCasc.setPID(o2::track::PID::XiMinus); + } else { + trackCasc.setPID(o2::track::PID::OmegaMinus); + } + + std::array pVecCascBachelor = {casc.pxbach(), casc.pybach(), casc.pzbach()}; + + //------------reconstruct charm baryon decay vtx--------------- + auto trackParVarCharmBachelor = getTrackParCov(trackCharmBachelor); // charm bachelor pion track to be processed with DCAFitter + + // reconstruct charm baryon with DCAFitter + int nVtxFromFitterCharmBaryon = 0; + try { + nVtxFromFitterCharmBaryon = df.process(trackCasc, trackParVarCharmBachelor); + } catch (...) { + LOG(error) << "Exception caught in charm DCA fitter process call!"; + hFitterStatus->Fill(1); + continue; + } + if (nVtxFromFitterCharmBaryon == 0) { + hFitterStatus->Fill(2); + continue; + } + hFitterStatus->Fill(0); + hCandidateCounter->Fill(2); + auto vertexCharmBaryonFromFitter = df.getPCACandidate(); + std::array pVecCascAsD; + std::array pVecCharmBachelorAsD; + df.propagateTracksToVertex(); + if (!df.isPropagateTracksToVertexDone()) { + continue; + } + df.getTrack(0).getPxPyPzGlo(pVecCascAsD); + df.getTrack(1).getPxPyPzGlo(pVecCharmBachelorAsD); + std::array pVecCharmBaryon = {pVecCascAsD[0] + pVecCharmBachelorAsD[0], pVecCascAsD[1] + pVecCharmBachelorAsD[1], pVecCascAsD[2] + pVecCharmBachelorAsD[2]}; + + std::array coordVtxCharmBaryon = df.getPCACandidatePos(); + std::array covVtxCharmBaryon = df.calcPCACovMatrixFlat(); + + // pseudorapidity + float pseudorapCharmBachelor = trackCharmBachelor.eta(); + + // primary vertex of the collision + auto primaryVertex = getPrimaryVertex(collision); // get the associated covariance matrix with auto covMatrixPV = primaryVertex.getCov(); + std::array pvCoord = {collision.posX(), collision.posY(), collision.posZ()}; + + // DCAxy and DCAz (computed with propagateToDCABxByBz method) + o2::dataformats::DCA impactParameterV0Dau0; + o2::dataformats::DCA impactParameterV0Dau1; + o2::dataformats::DCA impactParameterCascDauCharged; + auto trackParVarV0Dau0 = getTrackParCov(trackV0Dau0); + auto trackParVarV0Dau1 = getTrackParCov(trackV0Dau1); + auto trackParVarCascDauCharged = getTrackParCov(trackCascDauCharged); + o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertex, trackParVarV0Dau0, 2.f, matCorr, &impactParameterV0Dau0); + o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertex, trackParVarV0Dau1, 2.f, matCorr, &impactParameterV0Dau1); + o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertex, trackParVarCascDauCharged, 2.f, matCorr, &impactParameterCascDauCharged); + float dcaxyV0Dau0 = impactParameterV0Dau0.getY(); + float dcaxyV0Dau1 = impactParameterV0Dau1.getY(); + float dcaxyCascBachelor = impactParameterCascDauCharged.getY(); + float dcazV0Dau0 = impactParameterV0Dau0.getZ(); + float dcazV0Dau1 = impactParameterV0Dau1.getZ(); + float dcazCascBachelor = impactParameterCascDauCharged.getZ(); + + // impact parameters + o2::dataformats::DCA impactParameterCasc; + o2::dataformats::DCA impactParameterCharmBachelor; + o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertex, trackCasc, 2.f, matCorr, &impactParameterCasc); + o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertex, trackParVarCharmBachelor, 2.f, matCorr, &impactParameterCharmBachelor); + float impactParBachFromCharmBaryonXY = impactParameterCharmBachelor.getY(); + float impactParBachFromCharmBaryonZ = impactParameterCharmBachelor.getZ(); + + // invariant mass under the hypothesis of particles ID corresponding to the decay chain + float mLambda = casc.mLambda(); // from LF table, V0 mass under lambda hypothesis + float mCasc = 0.; + if constexpr (decayChannel == hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi) { + mCasc = casc.mXi(); + } else { + mCasc = casc.mOmega(); + } + auto arrMassCharmBaryon = std::array{0., 0.}; + if constexpr (decayChannel == hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi) { + arrMassCharmBaryon = {MassXiMinus, MassPiPlus}; + } else if constexpr (decayChannel == hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi) { + arrMassCharmBaryon = {MassOmegaMinus, MassPiPlus}; + } else { + arrMassCharmBaryon = {MassOmegaMinus, MassKPlus}; + } + float mCharmBaryon = RecoDecay::m(std::array{pVecCascAsD, pVecCharmBachelorAsD}, arrMassCharmBaryon); + + // computing cosPA + float cpaV0 = casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); + float cpaCharmBaryon = RecoDecay::cpa(pvCoord, coordVtxCharmBaryon, pVecCharmBaryon); + float cpaCasc = casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()); + float cpaxyV0 = RecoDecay::cpaXY(pvCoord, vertexV0, pVecV0); + float cpaxyCharmBaryon = RecoDecay::cpaXY(pvCoord, coordVtxCharmBaryon, pVecCharmBaryon); + float cpaxyCasc = RecoDecay::cpaXY(pvCoord, vertexCasc, pVecCasc); + + // computing decay length and ctau + float decLenCharmBaryon = RecoDecay::distance(pvCoord, coordVtxCharmBaryon); + float decLenCascade = RecoDecay::distance(coordVtxCharmBaryon, vertexCasc); + float decLenV0 = RecoDecay::distance(vertexCasc, vertexV0); + + double phiCharmBaryon, thetaCharmBaryon; + getPointDirection(std::array{primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, coordVtxCharmBaryon, phiCharmBaryon, thetaCharmBaryon); + auto errorDecayLengthCharmBaryon = std::sqrt(getRotatedCovMatrixXX(primaryVertex.getCov(), phiCharmBaryon, thetaCharmBaryon) + getRotatedCovMatrixXX(covVtxCharmBaryon, phiCharmBaryon, thetaCharmBaryon)); + auto errorDecayLengthXYCharmBaryon = std::sqrt(getRotatedCovMatrixXX(primaryVertex.getCov(), phiCharmBaryon, 0.) + getRotatedCovMatrixXX(covVtxCharmBaryon, phiCharmBaryon, 0.)); + + float ctOmegac = RecoDecay::ct(pVecCharmBaryon, decLenCharmBaryon, MassOmegaC0); + float ctXic = RecoDecay::ct(pVecCharmBaryon, decLenCharmBaryon, MassXiC0); + float ctCascade = 0.; + if constexpr (decayChannel == hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi) { + ctCascade = RecoDecay::ct(pVecCasc, decLenCascade, MassXiMinus); + } else { + ctCascade = RecoDecay::ct(pVecCasc, decLenCascade, MassOmegaMinus); + } + float ctV0 = RecoDecay::ct(pVecV0, decLenV0, MassLambda0); + + // computing eta + float pseudorapCharmBaryon = RecoDecay::eta(pVecCharmBaryon); + float pseudorapCascade = RecoDecay::eta(pVecCasc); + float pseudorapV0 = RecoDecay::eta(pVecV0); + + // DCA between daughters + float dcaCascDau = casc.dcacascdaughters(); + float dcaV0Dau = casc.dcaV0daughters(); + float dcaCharmBaryonDau = std::sqrt(df.getChi2AtPCACandidate()); + + // fill test histograms + hInvMassCharmBaryon->Fill(mCharmBaryon); + hCandidateCounter->Fill(3); + + // fill the table + if constexpr (decayChannel == hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi) { + rowCandToXiPi(collision.globalIndex(), + pvCoord[0], pvCoord[1], pvCoord[2], + vertexCharmBaryonFromFitter[0], vertexCharmBaryonFromFitter[1], vertexCharmBaryonFromFitter[2], + vertexCasc[0], vertexCasc[1], vertexCasc[2], + vertexV0[0], vertexV0[1], vertexV0[2], + trackCascDauCharged.sign(), + covVtxCharmBaryon[0], covVtxCharmBaryon[1], covVtxCharmBaryon[2], covVtxCharmBaryon[3], covVtxCharmBaryon[4], covVtxCharmBaryon[5], + pVecCharmBaryon[0], pVecCharmBaryon[1], pVecCharmBaryon[2], + pVecCascAsD[0], pVecCascAsD[1], pVecCascAsD[2], + pVecCharmBachelorAsD[0], pVecCharmBachelorAsD[1], pVecCharmBachelorAsD[2], + pVecV0[0], pVecV0[1], pVecV0[2], + pVecCascBachelor[0], pVecCascBachelor[1], pVecCascBachelor[2], + pVecV0Dau0[0], pVecV0Dau0[1], pVecV0Dau0[2], + pVecV0Dau1[0], pVecV0Dau1[1], pVecV0Dau1[2], + impactParameterCasc.getY(), impactParBachFromCharmBaryonXY, + impactParameterCasc.getZ(), impactParBachFromCharmBaryonZ, + std::sqrt(impactParameterCasc.getSigmaY2()), std::sqrt(impactParameterCharmBachelor.getSigmaY2()), + v0index, casc.posTrackId(), casc.negTrackId(), + casc.cascadeId(), trackCharmBachelor.globalIndex(), casc.bachelorId(), + mLambda, mCasc, mCharmBaryon, + cpaV0, cpaCharmBaryon, cpaCasc, cpaxyV0, cpaxyCharmBaryon, cpaxyCasc, + ctOmegac, ctCascade, ctV0, ctXic, + pseudorapV0Dau0, pseudorapV0Dau1, pseudorapCascBachelor, pseudorapCharmBachelor, + pseudorapCharmBaryon, pseudorapCascade, pseudorapV0, + dcaxyV0Dau0, dcaxyV0Dau1, dcaxyCascBachelor, + dcazV0Dau0, dcazV0Dau1, dcazCascBachelor, + dcaCascDau, dcaV0Dau, dcaCharmBaryonDau, + decLenCharmBaryon, decLenCascade, decLenV0, errorDecayLengthCharmBaryon, errorDecayLengthXYCharmBaryon); + + } else if constexpr (decayChannel == hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi) { + rowCandToOmegaPi(collision.globalIndex(), + pvCoord[0], pvCoord[1], pvCoord[2], + vertexCharmBaryonFromFitter[0], vertexCharmBaryonFromFitter[1], vertexCharmBaryonFromFitter[2], + vertexCasc[0], vertexCasc[1], vertexCasc[2], + vertexV0[0], vertexV0[1], vertexV0[2], + trackCascDauCharged.sign(), + covVtxCharmBaryon[0], covVtxCharmBaryon[1], covVtxCharmBaryon[2], covVtxCharmBaryon[3], covVtxCharmBaryon[4], covVtxCharmBaryon[5], + pVecCharmBaryon[0], pVecCharmBaryon[1], pVecCharmBaryon[2], + pVecCascAsD[0], pVecCascAsD[1], pVecCascAsD[2], + pVecCharmBachelorAsD[0], pVecCharmBachelorAsD[1], pVecCharmBachelorAsD[2], + pVecV0[0], pVecV0[1], pVecV0[2], + pVecCascBachelor[0], pVecCascBachelor[1], pVecCascBachelor[2], + pVecV0Dau0[0], pVecV0Dau0[1], pVecV0Dau0[2], + pVecV0Dau1[0], pVecV0Dau1[1], pVecV0Dau1[2], + impactParameterCasc.getY(), impactParBachFromCharmBaryonXY, + impactParameterCasc.getZ(), impactParBachFromCharmBaryonZ, + std::sqrt(impactParameterCasc.getSigmaY2()), std::sqrt(impactParameterCharmBachelor.getSigmaY2()), + v0index, casc.posTrackId(), casc.negTrackId(), + casc.cascadeId(), trackCharmBachelor.globalIndex(), casc.bachelorId(), + mLambda, mCasc, mCharmBaryon, + cpaV0, cpaCharmBaryon, cpaCasc, cpaxyV0, cpaxyCharmBaryon, cpaxyCasc, + ctOmegac, ctCascade, ctV0, + pseudorapV0Dau0, pseudorapV0Dau1, pseudorapCascBachelor, pseudorapCharmBachelor, + pseudorapCharmBaryon, pseudorapCascade, pseudorapV0, + dcaxyV0Dau0, dcaxyV0Dau1, dcaxyCascBachelor, + dcazV0Dau0, dcazV0Dau1, dcazCascBachelor, + dcaCascDau, dcaV0Dau, dcaCharmBaryonDau, + decLenCharmBaryon, decLenCascade, decLenV0, errorDecayLengthCharmBaryon, errorDecayLengthXYCharmBaryon, cand.hfflag()); + + } else { + rowCandToOmegaK( + collision.globalIndex(), pvCoord[0], pvCoord[1], pvCoord[2], + vertexCharmBaryonFromFitter[0], vertexCharmBaryonFromFitter[1], vertexCharmBaryonFromFitter[2], + vertexCasc[0], vertexCasc[1], vertexCasc[2], + vertexV0[0], vertexV0[1], vertexV0[2], + trackCascDauCharged.sign(), + covVtxCharmBaryon[0], covVtxCharmBaryon[1], covVtxCharmBaryon[2], covVtxCharmBaryon[3], covVtxCharmBaryon[4], covVtxCharmBaryon[5], + pVecCharmBaryon[0], pVecCharmBaryon[1], pVecCharmBaryon[2], + pVecCascAsD[0], pVecCascAsD[1], pVecCascAsD[2], + pVecCharmBachelorAsD[0], pVecCharmBachelorAsD[1], pVecCharmBachelorAsD[2], + pVecV0[0], pVecV0[1], pVecV0[2], + pVecCascBachelor[0], pVecCascBachelor[1], pVecCascBachelor[2], + pVecV0Dau0[0], pVecV0Dau0[1], pVecV0Dau0[2], + pVecV0Dau1[0], pVecV0Dau1[1], pVecV0Dau1[2], + impactParameterCasc.getY(), impactParBachFromCharmBaryonXY, + impactParameterCasc.getZ(), impactParBachFromCharmBaryonZ, + std::sqrt(impactParameterCasc.getSigmaY2()), std::sqrt(impactParameterCharmBachelor.getSigmaY2()), + v0index, casc.posTrackId(), casc.negTrackId(), + casc.cascadeId(), trackCharmBachelor.globalIndex(), casc.bachelorId(), + mLambda, mCasc, mCharmBaryon, + cpaV0, cpaCharmBaryon, cpaCasc, cpaxyV0, cpaxyCharmBaryon, cpaxyCasc, + ctOmegac, ctCascade, ctV0, + pseudorapV0Dau0, pseudorapV0Dau1, pseudorapCascBachelor, pseudorapCharmBachelor, + pseudorapCharmBaryon, pseudorapCascade, pseudorapV0, + dcaxyV0Dau0, dcaxyV0Dau1, dcaxyCascBachelor, + dcazV0Dau0, dcazV0Dau1, dcazCascBachelor, + dcaCascDau, dcaV0Dau, dcaCharmBaryonDau, + decLenCharmBaryon, decLenCascade, decLenV0, errorDecayLengthCharmBaryon, errorDecayLengthXYCharmBaryon); + } + + } // loop over LF Cascade-bachelor candidates + } // end of run function + + template + void runKfOmegac0CreatorWithKFParticle(Coll const&, + aod::BCsWithTimestamps const& /*bcWithTimeStamps*/, + MyKfTracks const&, + MyKfCascTable const&, KFCascadesLinked const&, + aod::HfCascLf2Prongs const& candidates, + Hist& hInvMassCharmBaryon, + Hist& hFitterStatus, + Hist& hCandidateCounter, + Hist& hCascadesCounter) + { + for (const auto& cand : candidates) { + hCandidateCounter->Fill(1); + + auto collision = cand.collision_as(); + + // set the magnetic field from CCDB + auto bc = collision.template bc_as(); + if (runNumber != bc.runNumber()) { + LOG(info) << ">>>>>>>>>>>> Current run number: " << runNumber; + initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, lut, isRun2); + magneticField = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << ">>>>>>>>>>>> Magnetic field: " << magneticField; + runNumber = bc.runNumber(); + } + df.setBz(magneticField); + KFParticle::SetField(magneticField); + // bachelor from Omegac0 + auto trackCharmBachelor = cand.prong0_as(); + + auto cascAodElement = cand.cascade_as(); + hCascadesCounter->Fill(0); + int v0index = cascAodElement.v0Id(); + if (!cascAodElement.has_kfCascData()) { + continue; + } + auto casc = cascAodElement.kfCascData_as(); + hCascadesCounter->Fill(1); + auto trackCascDauCharged = casc.bachelor_as(); // pion <- xi track + auto trackV0Dau0 = casc.posTrack_as(); // V0 positive daughter track + auto trackV0Dau1 = casc.negTrack_as(); // V0 negative daughter track + + auto bachCharge = trackCascDauCharged.signed1Pt() > 0 ? +1 : -1; + + //// pion & p TrackParCov + auto trackParCovV0Dau0 = getTrackParCov(trackV0Dau0); + auto trackParCovV0Dau1 = getTrackParCov(trackV0Dau1); + // kaon <- casc TrackParCov + auto omegaDauChargedTrackParCov = getTrackParCov(trackCascDauCharged); + // convert tracks into KFParticle object + KFPTrack kfTrack0 = createKFPTrackFromTrack(trackV0Dau0); + KFPTrack kfTrack1 = createKFPTrackFromTrack(trackV0Dau1); + KFPTrack kfTrackBach = createKFPTrackFromTrack(trackCascDauCharged); + + KFParticle kfPosPr(kfTrack0, kProton); + KFParticle kfNegPi(kfTrack1, kPiMinus); + KFParticle kfNegKa(kfTrackBach, kKMinus); + KFParticle kfNegPiRej(kfTrackBach, kPiMinus); // rej + KFParticle kfPosPi(kfTrack0, kPiPlus); + KFParticle kfNegPr(kfTrack1, kProton); + KFParticle kfPosKa(kfTrackBach, kKPlus); + KFParticle kfPosPiRej(kfTrackBach, kPiPlus); // rej + + KFParticle kfBachKaon; + KFParticle kfPos; + KFParticle kfNeg; + KFParticle kfBachPionRej; // rej + if (bachCharge < 0) { + kfPos = kfPosPr; + kfNeg = kfNegPi; + kfBachKaon = kfNegKa; + kfBachPionRej = kfNegPiRej; // rej + } else { + kfPos = kfPosPi; + kfNeg = kfNegPr; + kfBachKaon = kfPosKa; + kfBachPionRej = kfPosPiRej; // rej + } + + //__________________________________________ + //*>~<* step 1 : construct V0 with KF + const KFParticle* v0Daughters[2] = {&kfPos, &kfNeg}; + // construct V0 + KFParticle kfV0; + kfV0.SetConstructMethod(kfConstructMethod); + try { + kfV0.Construct(v0Daughters, 2); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to construct cascade V0 from daughter tracks: " << e.what(); + continue; + } + + // mass window cut on lambda before mass constraint + float massLam, sigLam; + kfV0.GetMass(massLam, sigLam); + if (std::abs(massLam - MassLambda0) > lambdaMassWindow) + continue; + // err_mass>0 of Lambda + if (sigLam <= 0) + continue; + kfOmegac0Candidate.chi2GeoV0 = kfV0.GetChi2(); + KFParticle kfV0MassConstrained = kfV0; + kfV0MassConstrained.SetNonlinearMassConstraint(o2::constants::physics::MassLambda); // set mass constrain to Lambda + if (kfUseV0MassConstraint) { + KFParticle kfV0 = kfV0MassConstrained; + } + kfV0.TransportToDecayVertex(); + + //__________________________________________ + //*>~<* step 2 : reconstruct cascade(Omega) with KF + const KFParticle* omegaDaugthers[2] = {&kfBachKaon, &kfV0}; + const KFParticle* omegaDaugthersRej[2] = {&kfBachPionRej, &kfV0}; // rej + // construct cascade + KFParticle kfOmega; + KFParticle kfOmegarej; // rej + kfOmega.SetConstructMethod(kfConstructMethod); + kfOmegarej.SetConstructMethod(kfConstructMethod); // rej + try { + kfOmega.Construct(omegaDaugthers, 2); + kfOmegarej.Construct(omegaDaugthersRej, 2); // rej + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to construct Omega or Omega_rej from V0 and bachelor track: " << e.what(); + continue; + } + float massCasc, sigCasc; + float massCascrej, sigCascrej; + kfOmega.GetMass(massCasc, sigCasc); + kfOmegarej.GetMass(massCascrej, sigCascrej); // rej + // err_massOmega > 0 + if (sigCasc <= 0) + continue; + if (std::abs(massCasc - MassOmegaMinus) > massToleranceCascade) + continue; + + kfOmegac0Candidate.chi2GeoCasc = kfOmega.GetChi2(); + kfOmegac0Candidate.cascRejectInvmass = massCascrej; + registry.fill(HIST("hInvMassXiMinus_rej"), massCascrej); // rej + KFParticle kfOmegaMassConstrained = kfOmega; + kfOmegaMassConstrained.SetNonlinearMassConstraint(o2::constants::physics::MassOmegaMinus); // set mass constrain to OmegaMinus + if (kfUseCascadeMassConstraint) { + // set mass constraint if requested + KFParticle kfOmega = kfOmegaMassConstrained; + } + registry.fill(HIST("hInvMassOmegaMinus"), massCasc); + kfOmega.TransportToDecayVertex(); + // rej: Add competing rejection to minimize misidentified Xi impact. Reject if kfBachPionRej is Pion and the constructed cascade has Xi's invariant mass. + + //__________________________________________ + //*>~<* step 3 : reconstruc Omegac0 with KF + // Create KF charm bach Pion from track + KFPTrack kfTrackBachPion = createKFPTrackFromTrack(trackCharmBachelor); + KFParticle kfBachPion(kfTrackBachPion, kPiPlus); + const KFParticle* omegaC0Daugthers[2] = {&kfBachPion, &kfOmega}; + + // construct OmegaC0 + KFParticle kfOmegaC0; + kfOmegaC0.SetConstructMethod(kfConstructMethod); + try { + kfOmegaC0.Construct(omegaC0Daugthers, 2); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to construct OmegaC0 from Cascade and bachelor pion track: " << e.what(); + continue; + } + float massOmegaC0, sigOmegaC0; + kfOmegaC0.GetMass(massOmegaC0, sigOmegaC0); + if (sigOmegaC0 <= 0) + continue; + + hFitterStatus->Fill(0); + hCandidateCounter->Fill(2); + kfOmegaC0.TransportToDecayVertex(); + // PV + KFPVertex kfVertex = createKFPVertexFromCollision(collision); + KFParticle kfPV(kfVertex); + + // set production vertex; + kfNeg.SetProductionVertex(kfV0); + kfPos.SetProductionVertex(kfV0); + + KFParticle kfBachKaonToOmega = kfBachKaon; + KFParticle kfV0ToCasc = kfV0; + kfBachKaonToOmega.SetProductionVertex(kfOmega); + kfV0ToCasc.SetProductionVertex(kfOmega); + + KFParticle kfOmegaToOmegaC = kfOmega; + KFParticle kfBachPionToOmegaC = kfBachPion; + kfBachPionToOmegaC.SetProductionVertex(kfOmegaC0); + kfOmegaToOmegaC.SetProductionVertex(kfOmegaC0); + + // KFParticle to PV + KFParticle kfV0ToPv = kfV0; + KFParticle kfOmegaToPv = kfOmega; + KFParticle kfOmegac0ToPv = kfOmegaC0; + KFParticle kfPiFromOmegacToPv = kfBachPion; + + kfV0ToPv.SetProductionVertex(kfPV); + kfOmegaToPv.SetProductionVertex(kfPV); + kfOmegac0ToPv.SetProductionVertex(kfPV); + kfPiFromOmegacToPv.SetProductionVertex(kfPV); + //------------get updated daughter tracks after vertex fit --------------- + auto trackParVarCharmBachelor = getTrackParCovFromKFP(kfBachPionToOmegaC, o2::track::PID::Pion, -bachCharge); // chrambaryon bach pion + trackParVarCharmBachelor.setAbsCharge(1); + + omegaDauChargedTrackParCov = getTrackParCovFromKFP(kfBachKaonToOmega, o2::track::PID::Kaon, bachCharge); // Cascade bach kaon + omegaDauChargedTrackParCov.setAbsCharge(1); + o2::track::TrackParCov trackCasc = getTrackParCovFromKFP(kfOmegaToOmegaC, kfOmegaToOmegaC.GetPDG(), bachCharge); + trackCasc.setAbsCharge(1); + + trackParCovV0Dau0 = getTrackParCovFromKFP(kfPos, kfPos.GetPDG(), 1); // V0 postive daughter + trackParCovV0Dau0.setAbsCharge(1); + trackParCovV0Dau1 = getTrackParCovFromKFP(kfNeg, kfNeg.GetPDG(), -1); // V0 negtive daughter + trackParCovV0Dau1.setAbsCharge(1); + + //-------------------------- V0 info--------------------------- + // pseudorapidity + float pseudorapV0Dau0 = kfPos.GetEta(); + float pseudorapV0Dau1 = kfNeg.GetEta(); + + // info from from KFParticle + std::array pVecV0 = {kfV0.GetPx(), kfV0.GetPy(), kfV0.GetPz()}; // pVec stands for vector containing the 3-momentum components + std::array vertexV0 = {kfV0.GetX(), kfV0.GetY(), kfV0.GetZ()}; + std::array pVecV0Dau0 = {kfPos.GetPx(), kfPos.GetPy(), kfPos.GetPz()}; + std::array pVecV0Dau1 = {kfNeg.GetPx(), kfNeg.GetPy(), kfNeg.GetPz()}; + + //-------------------reconstruct cascade track------------------ + // pseudorapidity + float pseudorapCascBachelor = kfBachKaonToOmega.GetEta(); + + // info from KFParticle + std::array vertexCasc = {kfOmega.GetX(), kfOmega.GetY(), kfOmega.GetZ()}; + std::array pVecCascBachelor = {kfBachKaonToOmega.GetPx(), kfBachKaonToOmega.GetPy(), kfBachKaonToOmega.GetPz()}; + + auto primaryVertex = getPrimaryVertex(collision); + std::array pvCoord = {collision.posX(), collision.posY(), collision.posZ()}; + std::array vertexCharmBaryonFromFitter = {0.0, 0.0, 0.0}; // This variable get from DCAfitter in default process, in KF process it is set as 0. + std::array pVecCharmBachelorAsD; + pVecCharmBachelorAsD[0] = kfBachPionToOmegaC.GetPx(); + pVecCharmBachelorAsD[1] = kfBachPionToOmegaC.GetPy(); + pVecCharmBachelorAsD[2] = kfBachPionToOmegaC.GetPz(); + + std::array pVecCharmBaryon = {kfOmegaC0.GetPx(), kfOmegaC0.GetPy(), kfOmegaC0.GetPz()}; + std::array coordVtxCharmBaryon = {kfOmegaC0.GetX(), kfOmegaC0.GetY(), kfOmegaC0.GetZ()}; + auto covVtxCharmBaryon = kfOmegaC0.CovarianceMatrix(); + float covMatrixPV[6]; + kfVertex.GetCovarianceMatrix(covMatrixPV); + + // impact parameters + gpu::gpustd::array impactParameterV0Dau0; + gpu::gpustd::array impactParameterV0Dau1; + gpu::gpustd::array impactParameterKaFromCasc; + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParCovV0Dau0, 2.f, matCorr, &impactParameterV0Dau0); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParCovV0Dau1, 2.f, matCorr, &impactParameterV0Dau1); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, omegaDauChargedTrackParCov, 2.f, matCorr, &impactParameterKaFromCasc); + float dcaxyV0Dau0 = impactParameterV0Dau0[0]; + float dcaxyV0Dau1 = impactParameterV0Dau1[0]; + float dcaxyCascBachelor = impactParameterKaFromCasc[0]; + float dcazV0Dau0 = impactParameterV0Dau0[1]; + float dcazV0Dau1 = impactParameterV0Dau1[1]; + float dcazCascBachelor = impactParameterKaFromCasc[1]; + + // pseudorapidity + float pseudorapCharmBachelor = kfBachPionToOmegaC.GetEta(); + + // impact parameters + o2::dataformats::DCA impactParameterCasc; + o2::dataformats::DCA impactParameterCharmBachelor; + o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertex, trackCasc, 2.f, matCorr, &impactParameterCasc); + o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertex, trackParVarCharmBachelor, 2.f, matCorr, &impactParameterCharmBachelor); + float impactParBachFromCharmBaryonXY = impactParameterCharmBachelor.getY(); + float impactParBachFromCharmBaryonZ = impactParameterCharmBachelor.getZ(); + + // computing decay length and ctau + float decLenCharmBaryon = RecoDecay::distance(pvCoord, coordVtxCharmBaryon); + float decLenCascade = RecoDecay::distance(coordVtxCharmBaryon, vertexCasc); + float decLenV0 = RecoDecay::distance(vertexCasc, vertexV0); + + double phiCharmBaryon, thetaCharmBaryon; + getPointDirection(std::array{kfV0.GetX(), kfV0.GetY(), kfV0.GetZ()}, coordVtxCharmBaryon, phiCharmBaryon, thetaCharmBaryon); + auto errorDecayLengthCharmBaryon = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phiCharmBaryon, thetaCharmBaryon) + getRotatedCovMatrixXX(covVtxCharmBaryon, phiCharmBaryon, thetaCharmBaryon)); + auto errorDecayLengthXYCharmBaryon = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phiCharmBaryon, 0.) + getRotatedCovMatrixXX(covVtxCharmBaryon, phiCharmBaryon, 0.)); + + // fill test histograms + hInvMassCharmBaryon->Fill(massOmegaC0); + hCandidateCounter->Fill(3); + + //// KFParticle table information + // KF chi2 + auto v0NDF = kfV0.GetNDF(); + auto v0Chi2OverNdf = kfOmegac0Candidate.chi2GeoV0 / v0NDF; + + auto cascNDF = kfOmega.GetNDF(); + auto cascChi2OverNdf = kfOmegac0Candidate.chi2GeoCasc / cascNDF; + + kfOmegac0Candidate.chi2GeoOmegac = kfOmegaC0.GetChi2(); + auto charmbaryonNDF = kfOmegaC0.GetNDF(); + auto charmbaryonChi2OverNdf = kfOmegac0Candidate.chi2GeoOmegac / charmbaryonNDF; + + kfOmegac0Candidate.chi2MassV0 = kfV0MassConstrained.GetChi2(); + auto v0Ndfm = kfV0MassConstrained.GetNDF(); + auto v0Chi2OverNdfm = kfOmegac0Candidate.chi2MassV0 / v0Ndfm; + + kfOmegac0Candidate.chi2MassCasc = kfOmegaMassConstrained.GetChi2(); + auto cascNdfm = kfOmegaMassConstrained.GetNDF(); + auto cascChi2OverNdfm = kfOmegac0Candidate.chi2MassCasc / cascNdfm; + + // KF topo Chi2 over NDF + kfOmegac0Candidate.chi2NdfTopoV0ToPv = kfV0ToPv.GetChi2() / kfV0ToPv.GetNDF(); + kfOmegac0Candidate.chi2NdfTopoCascToPv = kfOmegaToPv.GetChi2() / kfOmegaToPv.GetNDF(); + kfOmegac0Candidate.chi2NdfTopoPiFromOmegacToPv = kfPiFromOmegacToPv.GetChi2() / kfPiFromOmegacToPv.GetNDF(); + kfOmegac0Candidate.chi2NdfTopoOmegacToPv = kfOmegac0ToPv.GetChi2() / kfOmegac0ToPv.GetNDF(); + kfOmegac0Candidate.deviationPiFromOmegacToPv = kfCalculateChi2ToPrimaryVertex(kfOmegaC0, kfPV); + + auto cascBachTopoChi2Ndf = kfBachKaonToOmega.GetChi2() / kfBachKaonToOmega.GetNDF(); + kfOmegac0Candidate.chi2NdfTopoV0ToCasc = kfV0ToCasc.GetChi2() / kfV0ToCasc.GetNDF(); + kfOmegac0Candidate.chi2NdfTopoCascToOmegac = kfOmegaToOmegaC.GetChi2() / kfOmegaToOmegaC.GetNDF(); + + // KF ldl + kfOmegac0Candidate.ldlV0 = ldlFromKF(kfV0, kfPV); + kfOmegac0Candidate.ldlCasc = ldlFromKF(kfOmega, kfPV); + kfOmegac0Candidate.ldlOmegac = ldlFromKF(kfOmegaC0, kfPV); + + // KF dca + kfOmegac0Candidate.kfDcaXYPiFromOmegac = kfBachPionToOmegaC.GetDistanceFromVertexXY(kfPV); + kfOmegac0Candidate.kfDcaV0Dau = kfNeg.GetDistanceFromParticle(kfPos); + kfOmegac0Candidate.kfDcaCascDau = kfBachKaonToOmega.GetDistanceFromParticle(kfV0ToCasc); + kfOmegac0Candidate.kfDcaXYCascToPv = kfOmegaToOmegaC.GetDistanceFromVertexXY(kfPV); + kfOmegac0Candidate.kfDcaOmegacDau = kfBachPionToOmegaC.GetDistanceFromParticle(kfOmegaToOmegaC); + + // KF decay length + float decayLxyLam, errDecayLxyLam; + kfV0ToCasc.GetDecayLengthXY(decayLxyLam, errDecayLxyLam); + kfOmegac0Candidate.decayLenXYLambda = decayLxyLam; + + float decayLxyCasc, errDecayLxyCasc; + kfOmegaToOmegaC.GetDecayLengthXY(decayLxyCasc, errDecayLxyCasc); + kfOmegac0Candidate.decayLenXYCasc = decayLxyCasc; + + float decayLxyOmegac0, errDecayLxyOmegac0; + kfOmegac0ToPv.GetDecayLengthXY(decayLxyOmegac0, errDecayLxyOmegac0); + kfOmegac0Candidate.decayLenXYOmegac = decayLxyOmegac0; + + // KF cosPA + kfOmegac0Candidate.cosPaV0ToPv = cpaFromKF(kfV0, kfPV); + kfOmegac0Candidate.cosPaCascToPv = cpaFromKF(kfOmega, kfPV); + kfOmegac0Candidate.cosPaOmegacToPv = cpaFromKF(kfOmegaC0, kfPV); + kfOmegac0Candidate.cosPaXYV0ToPv = cpaXYFromKF(kfV0, kfPV); + kfOmegac0Candidate.cosPaXYCascToPv = cpaXYFromKF(kfOmega, kfPV); + kfOmegac0Candidate.cosPaXYOmegacToPv = cpaXYFromKF(kfOmegaC0, kfPV); + + kfOmegac0Candidate.cosPaV0ToCasc = cpaFromKF(kfV0, kfOmega); + kfOmegac0Candidate.cosPaCascToOmegac = cpaFromKF(kfOmega, kfOmegaC0); + kfOmegac0Candidate.cosPaXYV0ToCasc = cpaXYFromKF(kfV0, kfOmega); + kfOmegac0Candidate.cosPaXYCascToOmegac = cpaXYFromKF(kfOmega, kfOmegaC0); + // KF mass + kfOmegac0Candidate.massV0 = massLam; + kfOmegac0Candidate.massCasc = massCasc; + kfOmegac0Candidate.massOmegac = massOmegaC0; + + // KF pT + kfOmegac0Candidate.ptPiFromOmegac = kfBachPionToOmegaC.GetPt(); + kfOmegac0Candidate.ptOmegac = kfOmegaC0.GetPt(); + + // KF rapidity + kfOmegac0Candidate.rapOmegac = kfOmegaC0.GetRapidity(); + + // KF cosThetaStar + kfOmegac0Candidate.cosThetaStarPiFromOmegac = cosThetaStarFromKF(0, 4332, 211, 3312, kfBachPionToOmegaC, kfOmegaToOmegaC); + + // KF ct + kfOmegac0Candidate.ctV0 = kfV0.GetLifeTime(); + kfOmegac0Candidate.ctCasc = kfOmega.GetLifeTime(); + kfOmegac0Candidate.ctOmegac = kfOmegaC0.GetLifeTime(); + + // KF eta + kfOmegac0Candidate.etaOmegac = kfOmegaC0.GetEta(); + + // fill KF hist + registry.fill(HIST("hKFParticleCascBachTopoChi2"), cascBachTopoChi2Ndf); + registry.fill(HIST("hKFParticleV0TopoChi2"), kfOmegac0Candidate.chi2NdfTopoV0ToCasc); + registry.fill(HIST("hKFParticleCascTopoChi2"), kfOmegac0Candidate.chi2NdfTopoCascToOmegac); + registry.fill(HIST("hKFParticlechi2TopoOmegacToPv"), kfOmegac0Candidate.chi2NdfTopoOmegacToPv); + registry.fill(HIST("hKfChi2TopoOmegacToPv"), kfOmegac0ToPv.GetChi2()); + registry.fill(HIST("hKfNdfOmegacToPv"), kfOmegac0ToPv.GetNDF()); + registry.fill(HIST("hKFParticlechi2TopoCascToPv"), kfOmegac0Candidate.chi2NdfTopoCascToPv); + registry.fill(HIST("hKFParticleDcaCharmBaryonDau"), kfOmegac0Candidate.kfDcaOmegacDau); + registry.fill(HIST("hKFParticleDcaXYCascBachToPv"), dcaxyCascBachelor); + registry.fill(HIST("hKFParticleDcaXYV0DauPosToPv"), dcaxyV0Dau0); + registry.fill(HIST("hKFParticleDcaXYV0DauNegToPv"), dcaxyV0Dau1); + registry.fill(HIST("hKfLambda_ldl"), kfOmegac0Candidate.ldlV0); + registry.fill(HIST("hKfOmega_ldl"), kfOmegac0Candidate.ldlCasc); + registry.fill(HIST("hKfOmegaC0_ldl"), kfOmegac0Candidate.ldlOmegac); + registry.fill(HIST("hDcaXYCascadeToPVKf"), kfOmegac0Candidate.kfDcaXYCascToPv); + registry.fill(HIST("hKfChi2TopoPiFromCharmBaryon"), kfPiFromOmegacToPv.GetChi2()); + registry.fill(HIST("hKfNdfPiFromCharmBaryon"), kfPiFromOmegacToPv.GetNDF()); + registry.fill(HIST("hKfChi2OverNdfPiFromCharmBaryon"), kfOmegac0Candidate.chi2NdfTopoPiFromOmegacToPv); + registry.fill(HIST("hKfDeviationPiFromCharmBaryon"), kfOmegac0Candidate.deviationPiFromOmegacToPv); + // Additional histograms + if (fillAllHist) { + registry.fill(HIST("hEtaV0PosDau"), kfPos.GetEta()); + registry.fill(HIST("hEtaV0NegDau"), kfNeg.GetEta()); + registry.fill(HIST("hEtaKaFromCasc"), kfBachKaonToOmega.GetEta()); + registry.fill(HIST("hEtaPiFromCharmBaryon"), kfBachPionToOmegaC.GetEta()); + registry.fill(HIST("hCascradius"), RecoDecay::sqrtSumOfSquares(vertexCasc[0], vertexCasc[1])); + registry.fill(HIST("hV0radius"), RecoDecay::sqrtSumOfSquares(vertexV0[0], vertexV0[1])); + registry.fill(HIST("hCosPACasc"), kfOmegac0Candidate.cosPaCascToPv); + registry.fill(HIST("hCosPAV0"), kfOmegac0Candidate.cosPaV0ToPv); + registry.fill(HIST("hDcaCascDau"), kfOmegac0Candidate.kfDcaCascDau); + registry.fill(HIST("hDcaV0Dau"), kfOmegac0Candidate.kfDcaV0Dau); + registry.fill(HIST("hDcaXYToPvKa"), dcaxyCascBachelor); + registry.fill(HIST("hImpactParBachFromCharmBaryonXY"), impactParBachFromCharmBaryonXY); + registry.fill(HIST("hImpactParBachFromCharmBaryonZ"), impactParBachFromCharmBaryonZ); + registry.fill(HIST("hImpactParCascXY"), impactParameterCasc.getY()); + registry.fill(HIST("hImpactParCascZ"), impactParameterCasc.getZ()); + registry.fill(HIST("hPtKaFromCasc"), RecoDecay::sqrtSumOfSquares(pVecCascBachelor[0], pVecCascBachelor[1])); + registry.fill(HIST("hPtPiFromCharmBaryon"), RecoDecay::sqrtSumOfSquares(pVecCharmBachelorAsD[0], pVecCharmBachelorAsD[1])); + registry.fill(HIST("hCTauOmegac"), kfOmegac0Candidate.ctOmegac); + registry.fill(HIST("hKFGeoV0Chi2OverNdf"), v0Chi2OverNdf); + registry.fill(HIST("hKFGeoCascChi2OverNdf"), cascChi2OverNdf); + registry.fill(HIST("hKFGeoCharmbaryonChi2OverNdf"), charmbaryonChi2OverNdf); + registry.fill(HIST("hKFdecayLenXYLambda"), kfOmegac0Candidate.decayLenXYLambda); + registry.fill(HIST("hKFdecayLenXYCasc"), kfOmegac0Candidate.decayLenXYCasc); + registry.fill(HIST("hKFdecayLenXYOmegac"), kfOmegac0Candidate.decayLenXYOmegac); + registry.fill(HIST("hKFcosPaV0ToCasc"), kfOmegac0Candidate.cosPaV0ToCasc); + registry.fill(HIST("hKFcosPaCascToOmegac"), kfOmegac0Candidate.cosPaCascToOmegac); + } + + // fill the table + rowCandToOmegaPi(collision.globalIndex(), + pvCoord[0], pvCoord[1], pvCoord[2], + vertexCharmBaryonFromFitter[0], vertexCharmBaryonFromFitter[1], vertexCharmBaryonFromFitter[2], + vertexCasc[0], vertexCasc[1], vertexCasc[2], + vertexV0[0], vertexV0[1], vertexV0[2], + trackCascDauCharged.sign(), + covVtxCharmBaryon[0], covVtxCharmBaryon[1], covVtxCharmBaryon[2], covVtxCharmBaryon[3], covVtxCharmBaryon[4], covVtxCharmBaryon[5], + pVecCharmBaryon[0], pVecCharmBaryon[1], pVecCharmBaryon[2], + kfOmegaToOmegaC.GetPx(), kfOmegaToOmegaC.GetPy(), kfOmegaToOmegaC.GetPz(), + pVecCharmBachelorAsD[0], pVecCharmBachelorAsD[1], pVecCharmBachelorAsD[2], + pVecV0[0], pVecV0[1], pVecV0[2], + pVecCascBachelor[0], pVecCascBachelor[1], pVecCascBachelor[2], + pVecV0Dau0[0], pVecV0Dau0[1], pVecV0Dau0[2], + pVecV0Dau1[0], pVecV0Dau1[1], pVecV0Dau1[2], + impactParameterCasc.getY(), impactParBachFromCharmBaryonXY, + impactParameterCasc.getZ(), impactParBachFromCharmBaryonZ, + std::sqrt(impactParameterCasc.getSigmaY2()), std::sqrt(impactParameterCharmBachelor.getSigmaY2()), + v0index, casc.posTrackId(), casc.negTrackId(), + casc.cascadeId(), trackCharmBachelor.globalIndex(), casc.bachelorId(), + kfOmegac0Candidate.massV0, kfOmegac0Candidate.massCasc, kfOmegac0Candidate.massOmegac, + kfOmegac0Candidate.cosPaV0ToPv, kfOmegac0Candidate.cosPaOmegacToPv, kfOmegac0Candidate.cosPaCascToPv, kfOmegac0Candidate.cosPaXYV0ToPv, kfOmegac0Candidate.cosPaXYOmegacToPv, kfOmegac0Candidate.cosPaXYCascToPv, + kfOmegac0Candidate.ctOmegac, kfOmegac0Candidate.ctCasc, kfOmegac0Candidate.ctV0, + pseudorapV0Dau0, pseudorapV0Dau1, pseudorapCascBachelor, pseudorapCharmBachelor, + kfOmegac0Candidate.etaOmegac, kfOmega.GetEta(), kfV0.GetEta(), + dcaxyV0Dau0, dcaxyV0Dau1, dcaxyCascBachelor, + dcazV0Dau0, dcazV0Dau1, dcazCascBachelor, + kfOmegac0Candidate.kfDcaCascDau, kfOmegac0Candidate.kfDcaV0Dau, kfOmegac0Candidate.kfDcaOmegacDau, + decLenCharmBaryon, decLenCascade, decLenV0, errorDecayLengthCharmBaryon, errorDecayLengthXYCharmBaryon, cand.hfflag()); + // fill kf table + kfCandidateData(kfOmegac0Candidate.kfDcaXYPiFromOmegac, kfOmegac0Candidate.kfDcaXYCascToPv, + kfOmegac0Candidate.chi2GeoV0, kfOmegac0Candidate.chi2GeoCasc, kfOmegac0Candidate.chi2GeoOmegac, kfOmegac0Candidate.chi2MassV0, kfOmegac0Candidate.chi2MassCasc, + kfOmegac0Candidate.ldlV0, kfOmegac0Candidate.ldlCasc, kfOmegac0Candidate.ldlOmegac, + kfOmegac0Candidate.chi2NdfTopoV0ToPv, kfOmegac0Candidate.chi2NdfTopoCascToPv, kfOmegac0Candidate.chi2NdfTopoPiFromOmegacToPv, kfOmegac0Candidate.chi2NdfTopoOmegacToPv, kfOmegac0Candidate.deviationPiFromOmegacToPv, + kfOmegac0Candidate.chi2NdfTopoV0ToCasc, kfOmegac0Candidate.chi2NdfTopoCascToOmegac, + kfOmegac0Candidate.decayLenXYLambda, kfOmegac0Candidate.decayLenXYCasc, kfOmegac0Candidate.decayLenXYOmegac, + kfOmegac0Candidate.cosPaV0ToCasc, kfOmegac0Candidate.cosPaCascToOmegac, kfOmegac0Candidate.cosPaXYV0ToCasc, kfOmegac0Candidate.cosPaXYCascToOmegac, + kfOmegac0Candidate.rapOmegac, kfOmegac0Candidate.ptPiFromOmegac, kfOmegac0Candidate.ptOmegac, + kfOmegac0Candidate.cosThetaStarPiFromOmegac, + v0NDF, cascNDF, charmbaryonNDF, v0Ndfm, cascNdfm, + v0Chi2OverNdf, cascChi2OverNdf, charmbaryonChi2OverNdf, v0Chi2OverNdfm, cascChi2OverNdfm, kfOmegac0Candidate.cascRejectInvmass); + + } // loop over LF Cascade-bachelor candidates + } // end of run function + //========================================================== + template + void runKfXic0CreatorWithKFParticle(Coll const&, + aod::BCsWithTimestamps const& /*bcWithTimeStamps*/, + MyKfTracks const&, + MyKfCascTable const&, KFCascadesLinked const&, + aod::HfCascLf2Prongs const& candidates, + Hist& hInvMassCharmBaryon, + Hist& hFitterStatus, + Hist& hCandidateCounter, + Hist& hCascadesCounter) + { + for (const auto& cand : candidates) { + hCandidateCounter->Fill(1); + + auto collision = cand.collision_as(); + + // set the magnetic field from CCDB + auto bc = collision.template bc_as(); + if (runNumber != bc.runNumber()) { + LOG(info) << ">>>>>>>>>>>> Current run number: " << runNumber; + initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, lut, isRun2); + magneticField = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << ">>>>>>>>>>>> Magnetic field: " << magneticField; + runNumber = bc.runNumber(); + } + df.setBz(magneticField); + KFParticle::SetField(magneticField); + // bachelor from Xic0 + auto trackCharmBachelor = cand.prong0_as(); + + auto cascAodElement = cand.cascade_as(); + hCascadesCounter->Fill(0); + int v0index = cascAodElement.v0Id(); + if (!cascAodElement.has_kfCascData()) { + continue; + } + auto casc = cascAodElement.kfCascData_as(); + hCascadesCounter->Fill(1); + auto trackCascDauCharged = casc.bachelor_as(); // pion <- xi track + auto trackV0Dau0 = casc.posTrack_as(); // V0 positive daughter track + auto trackV0Dau1 = casc.negTrack_as(); // V0 negative daughter track + + auto bachCharge = trackCascDauCharged.signed1Pt() > 0 ? +1 : -1; + + //// pion & p TrackParCov + auto trackParCovV0Dau0 = getTrackParCov(trackV0Dau0); + auto trackParCovV0Dau1 = getTrackParCov(trackV0Dau1); + // pion <- casc TrackParCov + auto xiDauChargedTrackParCov = getTrackParCov(trackCascDauCharged); + + // convert tracks into KFParticle object + KFPTrack kfTrack0 = createKFPTrackFromTrack(trackV0Dau0); + KFPTrack kfTrack1 = createKFPTrackFromTrack(trackV0Dau1); + KFPTrack kfTrackBach = createKFPTrackFromTrack(trackCascDauCharged); + + KFParticle kfPosPr(kfTrack0, kProton); + KFParticle kfNegPi(kfTrack1, kPiMinus); + KFParticle kfNegBachPi(kfTrackBach, kPiMinus); + KFParticle kfPosPi(kfTrack0, kPiPlus); + KFParticle kfNegPr(kfTrack1, kProton); + KFParticle kfPosBachPi(kfTrackBach, kPiPlus); + + KFParticle kfBachPion; + KFParticle kfPos; + KFParticle kfNeg; + if (bachCharge < 0) { + kfPos = kfPosPr; + kfNeg = kfNegPi; + kfBachPion = kfNegBachPi; + } else { + kfPos = kfPosPi; + kfNeg = kfNegPr; + kfBachPion = kfPosBachPi; + } + + //__________________________________________ + //*>~<* step 1 : construct V0 with KF + const KFParticle* v0Daughters[2] = {&kfPos, &kfNeg}; + // construct V0 + KFParticle kfV0; + kfV0.SetConstructMethod(kfConstructMethod); + try { + kfV0.Construct(v0Daughters, 2); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to construct cascade V0 from daughter tracks: " << e.what(); + continue; + } + + // mass window cut on lambda before mass constraint + float massLam, sigLam; + kfV0.GetMass(massLam, sigLam); + if (std::abs(massLam - MassLambda0) > lambdaMassWindow) + continue; + + // err_mass>0 of Lambda + if (sigLam <= 0) + continue; + // chi2>0 && NDF>0 for selecting Lambda + if ((kfV0.GetNDF() <= 0 || kfV0.GetChi2() <= 0)) + continue; + + kfXic0Candidate.chi2GeoV0 = kfV0.GetChi2(); + KFParticle kfV0MassConstrained = kfV0; + kfV0MassConstrained.SetNonlinearMassConstraint(o2::constants::physics::MassLambda); // set mass constrain to Lambda + if (kfUseV0MassConstraint) { + KFParticle kfV0 = kfV0MassConstrained; + } + kfV0.TransportToDecayVertex(); + + //__________________________________________ + //*>~<* step 2 : reconstruct cascade(Xi) with KF + const KFParticle* xiDaugthers[2] = {&kfBachPion, &kfV0}; + // construct cascade + KFParticle kfXi; + kfXi.SetConstructMethod(kfConstructMethod); + try { + kfXi.Construct(xiDaugthers, 2); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to construct Xi from V0 and bachelor track: " << e.what(); + continue; + } + + float massCasc, sigCasc; + kfXi.GetMass(massCasc, sigCasc); + // err_massXi > 0 + if (sigCasc <= 0) + continue; + + if (std::abs(massCasc - MassXiMinus) > massToleranceCascade) + continue; + // chi2>0 && NDF>0 + if (kfXi.GetNDF() <= 0 || kfXi.GetChi2() <= 0) + continue; + kfXic0Candidate.chi2GeoCasc = kfXi.GetChi2(); + KFParticle kfXiMassConstrained = kfXi; + kfXiMassConstrained.SetNonlinearMassConstraint(o2::constants::physics::MassXiMinus); // set mass constrain to XiMinus + if (kfUseCascadeMassConstraint) { + // set mass constraint if requested + KFParticle kfXi = kfXiMassConstrained; + } + registry.fill(HIST("hInvMassXiMinus"), massCasc); + kfXi.TransportToDecayVertex(); + + //__________________________________________ + //*>~<* step 3 : reconstruc Xic0 with KF + // Create KF charm bach Pion from track + KFPTrack kfTrackBachPion = createKFPTrackFromTrack(trackCharmBachelor); + KFParticle kfCharmBachPion(kfTrackBachPion, kPiPlus); + const KFParticle* xiC0Daugthers[2] = {&kfCharmBachPion, &kfXi}; + + // construct XiC0 + KFParticle kfXiC0; + kfXiC0.SetConstructMethod(kfConstructMethod); + try { + kfXiC0.Construct(xiC0Daugthers, 2); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to construct XiC0 from Cascade and bachelor pion track: " << e.what(); + continue; + } + float massXiC0, sigXiC0; + kfXiC0.GetMass(massXiC0, sigXiC0); + if (sigXiC0 <= 0) + continue; + // chi2>0 && NDF>0 + if (kfXiC0.GetNDF() <= 0 || kfXiC0.GetChi2() <= 0) + continue; + + hFitterStatus->Fill(0); + hCandidateCounter->Fill(2); + kfXiC0.TransportToDecayVertex(); + // PV + KFPVertex kfVertex = createKFPVertexFromCollision(collision); + KFParticle kfPV(kfVertex); + + // set production vertex; + kfNeg.SetProductionVertex(kfV0); + kfPos.SetProductionVertex(kfV0); + + KFParticle kfBachPionToXi = kfBachPion; + KFParticle kfV0ToCasc = kfV0; + kfBachPionToXi.SetProductionVertex(kfXi); + kfV0ToCasc.SetProductionVertex(kfXi); + + KFParticle kfXiToXiC = kfXi; + KFParticle kfCharmBachPionToXiC = kfCharmBachPion; + kfCharmBachPionToXiC.SetProductionVertex(kfXiC0); + kfXiToXiC.SetProductionVertex(kfXiC0); + + // KFParticle to PV + KFParticle kfV0ToPv = kfV0; + KFParticle kfXiToPv = kfXi; + KFParticle kfXic0ToPv = kfXiC0; + KFParticle kfPiFromXicToPv = kfCharmBachPion; + + kfV0ToPv.SetProductionVertex(kfPV); + kfXiToPv.SetProductionVertex(kfPV); + kfXic0ToPv.SetProductionVertex(kfPV); + kfPiFromXicToPv.SetProductionVertex(kfPV); + //------------get updated daughter tracks after vertex fit --------------- + auto trackParVarCharmBachelor = getTrackParCovFromKFP(kfCharmBachPionToXiC, o2::track::PID::Pion, -bachCharge); // chrambaryon bach pion + trackParVarCharmBachelor.setAbsCharge(1); + + xiDauChargedTrackParCov = getTrackParCovFromKFP(kfBachPionToXi, o2::track::PID::Pion, bachCharge); // Cascade bach pion + xiDauChargedTrackParCov.setAbsCharge(1); + o2::track::TrackParCov trackCasc = getTrackParCovFromKFP(kfXiToXiC, kfXiToXiC.GetPDG(), bachCharge); + trackCasc.setAbsCharge(1); + + trackParCovV0Dau0 = getTrackParCovFromKFP(kfPos, kfPos.GetPDG(), 1); // V0 postive daughter + trackParCovV0Dau0.setAbsCharge(1); + trackParCovV0Dau1 = getTrackParCovFromKFP(kfNeg, kfNeg.GetPDG(), -1); // V0 negtive daughter + trackParCovV0Dau1.setAbsCharge(1); + + //-------------------------- V0 info--------------------------- + // pseudorapidity + float pseudorapV0Dau0 = kfPos.GetEta(); + float pseudorapV0Dau1 = kfNeg.GetEta(); + + // info from from KFParticle + std::array pVecV0 = {kfV0.GetPx(), kfV0.GetPy(), kfV0.GetPz()}; // pVec stands for vector containing the 3-momentum components + std::array vertexV0 = {kfV0.GetX(), kfV0.GetY(), kfV0.GetZ()}; + std::array pVecV0Dau0 = {kfPos.GetPx(), kfPos.GetPy(), kfPos.GetPz()}; + std::array pVecV0Dau1 = {kfNeg.GetPx(), kfNeg.GetPy(), kfNeg.GetPz()}; + + //-------------------reconstruct cascade track------------------ + // pseudorapidity + float pseudorapCascBachelor = kfBachPionToXi.GetEta(); + + // info from KFParticle + std::array vertexCasc = {kfXi.GetX(), kfXi.GetY(), kfXi.GetZ()}; + std::array pVecCascBachelor = {kfBachPionToXi.GetPx(), kfBachPionToXi.GetPy(), kfBachPionToXi.GetPz()}; + + auto primaryVertex = getPrimaryVertex(collision); + std::array pvCoord = {collision.posX(), collision.posY(), collision.posZ()}; + std::array vertexCharmBaryonFromFitter = {0.0, 0.0, 0.0}; // This variable get from DCAfitter in default process, in KF process it is set as 0. + std::array pVecCharmBachelorAsD; + pVecCharmBachelorAsD[0] = kfCharmBachPionToXiC.GetPx(); + pVecCharmBachelorAsD[1] = kfCharmBachPionToXiC.GetPy(); + pVecCharmBachelorAsD[2] = kfCharmBachPionToXiC.GetPz(); + + std::array pVecCharmBaryon = {kfXiC0.GetPx(), kfXiC0.GetPy(), kfXiC0.GetPz()}; + std::array coordVtxCharmBaryon = {kfXiC0.GetX(), kfXiC0.GetY(), kfXiC0.GetZ()}; + auto covVtxCharmBaryon = kfXiC0.CovarianceMatrix(); + float covMatrixPV[6]; + kfVertex.GetCovarianceMatrix(covMatrixPV); + + // impact parameters + gpu::gpustd::array impactParameterV0Dau0; + gpu::gpustd::array impactParameterV0Dau1; + gpu::gpustd::array impactParameterKaFromCasc; + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParCovV0Dau0, 2.f, matCorr, &impactParameterV0Dau0); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParCovV0Dau1, 2.f, matCorr, &impactParameterV0Dau1); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, xiDauChargedTrackParCov, 2.f, matCorr, &impactParameterKaFromCasc); + float dcaxyV0Dau0 = impactParameterV0Dau0[0]; + float dcaxyV0Dau1 = impactParameterV0Dau1[0]; + float dcaxyCascBachelor = impactParameterKaFromCasc[0]; + float dcazV0Dau0 = impactParameterV0Dau0[1]; + float dcazV0Dau1 = impactParameterV0Dau1[1]; + float dcazCascBachelor = impactParameterKaFromCasc[1]; + + // pseudorapidity + float pseudorapCharmBachelor = kfCharmBachPionToXiC.GetEta(); + + // impact parameters + o2::dataformats::DCA impactParameterCasc; + o2::dataformats::DCA impactParameterCharmBachelor; + o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertex, trackCasc, 2.f, matCorr, &impactParameterCasc); + o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertex, trackParVarCharmBachelor, 2.f, matCorr, &impactParameterCharmBachelor); + float impactParBachFromCharmBaryonXY = impactParameterCharmBachelor.getY(); + float impactParBachFromCharmBaryonZ = impactParameterCharmBachelor.getZ(); + + // computing decay length and ctau + float decLenCharmBaryon = RecoDecay::distance(pvCoord, coordVtxCharmBaryon); + float decLenCascade = RecoDecay::distance(coordVtxCharmBaryon, vertexCasc); + float decLenV0 = RecoDecay::distance(vertexCasc, vertexV0); + + double phiCharmBaryon, thetaCharmBaryon; + getPointDirection(std::array{kfV0.GetX(), kfV0.GetY(), kfV0.GetZ()}, coordVtxCharmBaryon, phiCharmBaryon, thetaCharmBaryon); + auto errorDecayLengthCharmBaryon = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phiCharmBaryon, thetaCharmBaryon) + getRotatedCovMatrixXX(covVtxCharmBaryon, phiCharmBaryon, thetaCharmBaryon)); + auto errorDecayLengthXYCharmBaryon = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phiCharmBaryon, 0.) + getRotatedCovMatrixXX(covVtxCharmBaryon, phiCharmBaryon, 0.)); + + // fill test histograms + hInvMassCharmBaryon->Fill(massXiC0); + hCandidateCounter->Fill(3); + + //// KFParticle table information + // KF chi2 + auto v0NDF = kfV0.GetNDF(); + auto v0Chi2OverNdf = kfXic0Candidate.chi2GeoV0 / v0NDF; + + auto cascNDF = kfXi.GetNDF(); + auto cascChi2OverNdf = kfXic0Candidate.chi2GeoCasc / cascNDF; + + kfXic0Candidate.chi2GeoXic = kfXiC0.GetChi2(); + auto charmbaryonNDF = kfXiC0.GetNDF(); + auto charmbaryonChi2OverNdf = kfXic0Candidate.chi2GeoXic / charmbaryonNDF; + + kfXic0Candidate.chi2MassV0 = kfV0MassConstrained.GetChi2(); + auto v0Ndfm = kfV0MassConstrained.GetNDF(); + auto v0Chi2OverNdfm = kfXic0Candidate.chi2MassV0 / v0Ndfm; + + kfXic0Candidate.chi2MassCasc = kfXiMassConstrained.GetChi2(); + auto cascNdfm = kfXiMassConstrained.GetNDF(); + auto cascChi2OverNdfm = kfXic0Candidate.chi2MassCasc / cascNdfm; + + // KF topo Chi2 + kfXic0Candidate.chi2NdfTopoV0ToPv = kfV0ToPv.GetChi2() / kfV0ToPv.GetNDF(); + kfXic0Candidate.chi2NdfTopoCascToPv = kfXiToPv.GetChi2() / kfXiToPv.GetNDF(); + kfXic0Candidate.chi2NdfTopoPiFromXicToPv = kfPiFromXicToPv.GetChi2() / kfPiFromXicToPv.GetNDF(); + kfXic0Candidate.chi2NdfTopoXicToPv = kfXic0ToPv.GetChi2() / kfXic0ToPv.GetNDF(); + + auto cascBachTopoChi2 = kfBachPionToXi.GetChi2(); + kfXic0Candidate.chi2NdfTopoV0ToCasc = kfV0ToCasc.GetChi2() / kfV0ToCasc.GetNDF(); + kfXic0Candidate.chi2NdfTopoCascToXic = kfXiToXiC.GetChi2() / kfXiToXiC.GetNDF(); + + // KF ldl + kfXic0Candidate.ldlV0 = ldlFromKF(kfV0, kfPV); + kfXic0Candidate.ldlCasc = ldlFromKF(kfXi, kfPV); + kfXic0Candidate.ldlXic = ldlFromKF(kfXiC0, kfPV); + + // KF dca + kfXic0Candidate.kfDcaXYPiFromXic = kfCharmBachPionToXiC.GetDistanceFromVertexXY(kfPV); + kfXic0Candidate.kfDcaV0Dau = kfNeg.GetDistanceFromParticle(kfPos); + kfXic0Candidate.kfDcaCascDau = kfBachPionToXi.GetDistanceFromParticle(kfV0ToCasc); + kfXic0Candidate.kfDcaXYCascToPv = kfXiToXiC.GetDistanceFromVertexXY(kfPV); + kfXic0Candidate.kfDcaXicDau = kfCharmBachPionToXiC.GetDistanceFromParticle(kfXiToXiC); + + // KF decay length + float decayLxyLam, errDecayLxyLam; + kfV0ToCasc.GetDecayLengthXY(decayLxyLam, errDecayLxyLam); + kfXic0Candidate.decayLenXYLambda = decayLxyLam; + + float decayLxyCasc, errDecayLxyCasc; + kfXiToXiC.GetDecayLengthXY(decayLxyCasc, errDecayLxyCasc); + kfXic0Candidate.decayLenXYCasc = decayLxyCasc; + + float decayLxyXic0, errDecayLxyXic0; + kfXic0ToPv.GetDecayLengthXY(decayLxyXic0, errDecayLxyXic0); + kfXic0Candidate.decayLenXYXic = decayLxyXic0; + + // KF cosPA + kfXic0Candidate.cosPaV0ToPv = cpaFromKF(kfV0, kfPV); + kfXic0Candidate.cosPaCascToPv = cpaFromKF(kfXi, kfPV); + kfXic0Candidate.cosPaXicToPv = cpaFromKF(kfXiC0, kfPV); + kfXic0Candidate.cosPaXYV0ToPv = cpaXYFromKF(kfV0, kfPV); + kfXic0Candidate.cosPaXYCascToPv = cpaXYFromKF(kfXi, kfPV); + kfXic0Candidate.cosPaXYXicToPv = cpaXYFromKF(kfXiC0, kfPV); + + kfXic0Candidate.cosPaV0ToCasc = cpaFromKF(kfV0, kfXi); + kfXic0Candidate.cosPaCascToXic = cpaFromKF(kfXi, kfXiC0); + kfXic0Candidate.cosPaXYV0ToCasc = cpaXYFromKF(kfV0, kfXi); + kfXic0Candidate.cosPaXYCascToXic = cpaXYFromKF(kfXi, kfXiC0); + // KF mass + kfXic0Candidate.massV0 = massLam; + kfXic0Candidate.massCasc = massCasc; + kfXic0Candidate.massXic = massXiC0; + + // KF pT + kfXic0Candidate.ptPiFromXic = kfCharmBachPionToXiC.GetPt(); + kfXic0Candidate.ptXic = kfXiC0.GetPt(); + + // KF rapidity + kfXic0Candidate.rapXic = kfXiC0.GetRapidity(); + + // KF cosThetaStar + kfXic0Candidate.cosThetaStarPiFromXic = cosThetaStarFromKF(0, 4332, 211, 3312, kfCharmBachPionToXiC, kfXiToXiC); + + // KF ct + kfXic0Candidate.ctV0 = kfV0.GetLifeTime(); + kfXic0Candidate.ctCasc = kfXi.GetLifeTime(); + kfXic0Candidate.ctXic = kfXiC0.GetLifeTime(); + kfXic0Candidate.ctOmegac = kfXiC0.GetLifeTime(); + + // KF eta + kfXic0Candidate.etaXic = kfXiC0.GetEta(); + + // fill KF hist + registry.fill(HIST("hKFParticleCascBachTopoChi2"), cascBachTopoChi2); + registry.fill(HIST("hKFParticleV0TopoChi2"), kfXic0Candidate.chi2NdfTopoV0ToCasc); + registry.fill(HIST("hKFParticleCascTopoChi2"), kfXic0Candidate.chi2NdfTopoCascToXic); + registry.fill(HIST("hKFParticleDcaCharmBaryonDau"), kfXic0Candidate.kfDcaXicDau); + registry.fill(HIST("hKFParticleDcaXYCascBachToPv"), dcaxyCascBachelor); + registry.fill(HIST("hKFParticleDcaXYV0DauPosToPv"), dcaxyV0Dau0); + registry.fill(HIST("hKFParticleDcaXYV0DauNegToPv"), dcaxyV0Dau1); + registry.fill(HIST("hKfLambda_ldl"), kfXic0Candidate.ldlV0); + registry.fill(HIST("hKfXi_ldl"), kfXic0Candidate.ldlCasc); + registry.fill(HIST("hKfXiC0_ldl"), kfXic0Candidate.ldlXic); + registry.fill(HIST("hDcaXYCascadeToPVKf"), kfXic0Candidate.kfDcaXYCascToPv); + + // fill kf table + kfCandidateXicData(collision.globalIndex(), + pvCoord[0], pvCoord[1], pvCoord[2], + vertexCharmBaryonFromFitter[0], vertexCharmBaryonFromFitter[1], vertexCharmBaryonFromFitter[2], + vertexCasc[0], vertexCasc[1], vertexCasc[2], + vertexV0[0], vertexV0[1], vertexV0[2], + trackCascDauCharged.sign(), + covVtxCharmBaryon[0], covVtxCharmBaryon[1], covVtxCharmBaryon[2], covVtxCharmBaryon[3], covVtxCharmBaryon[4], covVtxCharmBaryon[5], + pVecCharmBaryon[0], pVecCharmBaryon[1], pVecCharmBaryon[2], + kfXiToXiC.GetPx(), kfXiToXiC.GetPy(), kfXiToXiC.GetPz(), + pVecCharmBachelorAsD[0], pVecCharmBachelorAsD[1], pVecCharmBachelorAsD[2], + pVecV0[0], pVecV0[1], pVecV0[2], + pVecCascBachelor[0], pVecCascBachelor[1], pVecCascBachelor[2], + pVecV0Dau0[0], pVecV0Dau0[1], pVecV0Dau0[2], + pVecV0Dau1[0], pVecV0Dau1[1], pVecV0Dau1[2], + impactParameterCasc.getY(), impactParBachFromCharmBaryonXY, + impactParameterCasc.getZ(), impactParBachFromCharmBaryonZ, + std::sqrt(impactParameterCasc.getSigmaY2()), std::sqrt(impactParameterCharmBachelor.getSigmaY2()), + v0index, casc.posTrackId(), casc.negTrackId(), + casc.cascadeId(), trackCharmBachelor.globalIndex(), casc.bachelorId(), + kfXic0Candidate.massV0, kfXic0Candidate.massCasc, kfXic0Candidate.massXic, + kfXic0Candidate.cosPaV0ToPv, kfXic0Candidate.cosPaXicToPv, kfXic0Candidate.cosPaCascToPv, kfXic0Candidate.cosPaXYV0ToPv, kfXic0Candidate.cosPaXYXicToPv, kfXic0Candidate.cosPaXYCascToPv, + kfXic0Candidate.ctOmegac, kfXic0Candidate.ctCasc, kfXic0Candidate.ctV0, kfXic0Candidate.ctXic, + pseudorapV0Dau0, pseudorapV0Dau1, pseudorapCascBachelor, pseudorapCharmBachelor, + kfXic0Candidate.etaXic, kfXi.GetEta(), kfV0.GetEta(), + dcaxyV0Dau0, dcaxyV0Dau1, dcaxyCascBachelor, + dcazV0Dau0, dcazV0Dau1, dcazCascBachelor, + kfXic0Candidate.kfDcaCascDau, kfXic0Candidate.kfDcaV0Dau, kfXic0Candidate.kfDcaXicDau, + decLenCharmBaryon, decLenCascade, decLenV0, errorDecayLengthCharmBaryon, errorDecayLengthXYCharmBaryon, + kfXic0Candidate.kfDcaXYPiFromXic, kfXic0Candidate.kfDcaXYCascToPv, + kfXic0Candidate.chi2GeoV0, kfXic0Candidate.chi2GeoCasc, kfXic0Candidate.chi2GeoXic, kfXic0Candidate.chi2MassV0, kfXic0Candidate.chi2MassCasc, + kfXic0Candidate.ldlV0, kfXic0Candidate.ldlCasc, kfXic0Candidate.ldlXic, + kfXic0Candidate.chi2NdfTopoV0ToPv, kfXic0Candidate.chi2NdfTopoCascToPv, kfXic0Candidate.chi2NdfTopoPiFromXicToPv, kfXic0Candidate.chi2NdfTopoXicToPv, + kfXic0Candidate.chi2NdfTopoV0ToCasc, kfXic0Candidate.chi2NdfTopoCascToXic, + kfXic0Candidate.decayLenXYLambda, kfXic0Candidate.decayLenXYCasc, kfXic0Candidate.decayLenXYXic, + kfXic0Candidate.cosPaV0ToCasc, kfXic0Candidate.cosPaCascToXic, kfXic0Candidate.cosPaXYV0ToCasc, kfXic0Candidate.cosPaXYCascToXic, + kfXic0Candidate.rapXic, kfXic0Candidate.ptPiFromXic, kfXic0Candidate.ptXic, + kfXic0Candidate.cosThetaStarPiFromXic, + v0NDF, cascNDF, charmbaryonNDF, v0Ndfm, cascNdfm, + v0Chi2OverNdf, cascChi2OverNdf, charmbaryonChi2OverNdf, v0Chi2OverNdfm, cascChi2OverNdfm); + + } // loop over LF Cascade-bachelor candidates + } + /// @brief process function w/o centrality selections + void processNoCentToXiPi(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + TracksWCovDca const& tracks, + MyLFTracksWCov const& lfTracks, + MyCascTable const& cascades, + CascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runXic0Omegac0Creator(collisions, bcWithTimeStamps, lfTracks, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToXiPi, hFitterStatusToXiPi, hCandidateCounterToXiPi, hCascadesCounterToXiPi); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processNoCentToXiPi, "Run candidate creator w/o centrality selections for xi pi decay channel", true); + + void processNoCentToXiPiTraCasc(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + TracksWCovDca const& tracks, + MyLFTracksWCov const& lfTracks, + MyTraCascTable const& traCascades, + TraCascadesLinked const& traCascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runXic0Omegac0Creator(collisions, bcWithTimeStamps, lfTracks, tracks, traCascades, traCascadeLinks, candidates, hInvMassCharmBaryonToXiPi, hFitterStatusToXiPi, hCandidateCounterToXiPi, hCascadesCounterToXiPi); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processNoCentToXiPiTraCasc, "Run candidate creator w/o centrality selections for xi pi decay channel with tracked cascades", false); + + void processNoCentToOmegaPi(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + TracksWCovDca const& tracks, + MyLFTracksWCov const& lfTracks, + MyCascTable const& cascades, + CascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runXic0Omegac0Creator(collisions, bcWithTimeStamps, lfTracks, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaPi, hFitterStatusToOmegaPi, hCandidateCounterToOmegaPi, hCascadesCounterToOmegaPi); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processNoCentToOmegaPi, "Run candidate creator w/o centrality selections for omega pi decay channel", false); + + void processOmegacToOmegaPiWithKFParticle(aod::Collisions const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + MyKfTracks const& tracks, + MyKfCascTable const& cascades, + KFCascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runKfOmegac0CreatorWithKFParticle(collisions, bcWithTimeStamps, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaPi, hFitterStatusToOmegaPi, hCandidateCounterToOmegaPi, hCascadesCounterToOmegaPi); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processOmegacToOmegaPiWithKFParticle, "Run candidate creator w/o centrality selections for Omegac0 To omega pi decay channel using KFParticle", false); + + void processXicToXiPiWithKFParticle(aod::Collisions const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + MyKfTracks const& tracks, + MyKfCascTable const& cascades, + KFCascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runKfXic0CreatorWithKFParticle(collisions, bcWithTimeStamps, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToXiPi, hFitterStatusToXiPi, hCandidateCounterToXiPi, hCascadesCounterToXiPi); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processXicToXiPiWithKFParticle, "Run candidate creator w/o centrality selections for Xic0 To Xi pi decay channel using KFParticle", false); + + void processNoCentToOmegaK(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + TracksWCovDca const& tracks, + MyLFTracksWCov const& lfTracks, + MyCascTable const& cascades, + CascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runXic0Omegac0Creator(collisions, bcWithTimeStamps, lfTracks, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaK, hFitterStatusToOmegaK, hCandidateCounterToOmegaK, hCascadesCounterToOmegaK); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processNoCentToOmegaK, "Run candidate creator w/o centrality selections for omega K decay channel", false); + + /// @brief process function w/ FT0C centrality selections + void processCentFT0CToXiPi(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + TracksWCovDca const& tracks, + MyLFTracksWCov const& lfTracks, + MyCascTable const& cascades, + CascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runXic0Omegac0Creator(collisions, bcWithTimeStamps, lfTracks, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToXiPi, hFitterStatusToXiPi, hCandidateCounterToXiPi, hCascadesCounterToXiPi); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0CToXiPi, "Run candidate creator w/ centrality selection on FT0C for xi pi channel", false); + + void processCentFT0CToOmegaPi(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + TracksWCovDca const& tracks, + MyLFTracksWCov const& lfTracks, + MyCascTable const& cascades, + CascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runXic0Omegac0Creator(collisions, bcWithTimeStamps, lfTracks, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaPi, hFitterStatusToOmegaPi, hCandidateCounterToOmegaPi, hCascadesCounterToOmegaPi); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0CToOmegaPi, "Run candidate creator w/ centrality selection on FT0C for omega pi channel", false); + + void processCentFT0CToOmegaK(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + TracksWCovDca const& tracks, + MyLFTracksWCov const& lfTracks, + MyCascTable const& cascades, + CascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runXic0Omegac0Creator(collisions, bcWithTimeStamps, lfTracks, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaK, hFitterStatusToOmegaK, hCandidateCounterToOmegaK, hCascadesCounterToOmegaK); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0CToOmegaK, "Run candidate creator w/ centrality selection on FT0C for omega K channel", false); + + /// @brief process function w/ FT0M centrality selections + void processCentFT0MToXiPi(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + TracksWCovDca const& tracks, + MyLFTracksWCov const& lfTracks, + MyCascTable const& cascades, + CascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runXic0Omegac0Creator(collisions, bcWithTimeStamps, lfTracks, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToXiPi, hFitterStatusToXiPi, hCandidateCounterToXiPi, hCascadesCounterToXiPi); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0MToXiPi, "Run candidate creator w/ centrality selection on FT0M for xi pi channel", false); + + void processCentFT0MToOmegaPi(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + TracksWCovDca const& tracks, + MyLFTracksWCov const& lfTracks, + MyCascTable const& cascades, + CascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runXic0Omegac0Creator(collisions, bcWithTimeStamps, lfTracks, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaPi, hFitterStatusToOmegaPi, hCandidateCounterToOmegaPi, hCascadesCounterToOmegaPi); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0MToOmegaPi, "Run candidate creator w/ centrality selection on FT0M for omega pi channel", false); + + void processCentFT0MToOmegaK(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + TracksWCovDca const& tracks, + MyLFTracksWCov const& lfTracks, + MyCascTable const& cascades, + CascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runXic0Omegac0Creator(collisions, bcWithTimeStamps, lfTracks, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaK, hFitterStatusToOmegaK, hCandidateCounterToOmegaK, hCascadesCounterToOmegaK); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0MToOmegaK, "Run candidate creator w/ centrality selection on FT0M for omega K channel", false); + + /////////////////////////////////////////////////////////// + /// /// + /// Process functions only for collision monitoring /// + /// /// + /////////////////////////////////////////////////////////// + + /// @brief process function to monitor collisions - no centrality + void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + { + /// loop over collisions + for (const auto& collision : collisions) { + + /// bitmask with event. selection info + float centrality{-1.f}; + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + + /// monitor the satisfied event selections + hfEvSel.fillHistograms(collision, rejectionMask, centrality); + + } /// end loop over collisions + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCollisions, "Collision monitoring - no centrality", true); + + /// @brief process function to monitor collisions - FT0C centrality + void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + { + /// loop over collisions + for (const auto& collision : collisions) { + + /// bitmask with event. selection info + float centrality{-1.f}; + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + + /// monitor the satisfied event selections + hfEvSel.fillHistograms(collision, rejectionMask, centrality); + + } /// end loop over collisions + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCollisionsCentFT0C, "Collision monitoring - FT0C centrality", false); + + /// @brief process function to monitor collisions - FT0M centrality + void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + { + /// loop over collisions + for (const auto& collision : collisions) { + + /// bitmask with event. selection info + float centrality{-1.f}; + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + + /// monitor the satisfied event selections + hfEvSel.fillHistograms(collision, rejectionMask, centrality); + + } /// end loop over collisions + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCollisionsCentFT0M, "Collision monitoring - FT0M centrality", false); + +}; // end of struct + +/// Performs MC matching. +struct HfCandidateCreatorXic0Omegac0Mc { + Produces rowMCMatchRecXicToXiPi; + Produces rowMCMatchGenXicToXiPi; + Produces rowMCMatchRecOmegacToXiPi; + Produces rowMCMatchGenOmegacToXiPi; + Produces rowMCMatchRecToOmegaPi; + Produces rowMCMatchGenToOmegaPi; + Produces rowMCMatchRecToOmegaK; + Produces rowMCMatchGenToOmegaK; + + // Configuration + Configurable rejectBackground{"rejectBackground", true, "Reject particles from background events"}; + Configurable acceptTrackIntWithMaterial{"acceptTrackIntWithMaterial", false, " switch to accept candidates with final (i.e. p, K, pi) daughter tracks interacting with material"}; + + using MyTracksWMc = soa::Join; + using McCollisionsNoCents = soa::Join; + using McCollisionsFT0Cs = soa::Join; + using McCollisionsFT0Ms = soa::Join; + using McCollisionsCentFT0Ms = soa::Join; + using BCsInfo = soa::Join; + + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + PresliceUnsorted colPerMcCollisionFT0C = aod::mccollisionlabel::mcCollisionId; + PresliceUnsorted colPerMcCollisionFT0M = aod::mccollisionlabel::mcCollisionId; + + HfEventSelectionMc hfEvSelMc; // mc event selection and monitoring + + std::shared_ptr hGenCharmBaryonPtRapidityTightXicToXiPi, hGenCharmBaryonPtRapidityLooseXicToXiPi, hGenCharmBaryonPtRapidityTightOmegacToXiPi, hGenCharmBaryonPtRapidityLooseOmegacToXiPi, hGenCharmBaryonPtRapidityTightOmegacToOmegaPi, hGenCharmBaryonPtRapidityLooseOmegacToOmegaPi, hGenCharmBaryonPtRapidityTightOmegacToOmegaK, hGenCharmBaryonPtRapidityLooseOmegacToOmegaK; + + HistogramRegistry registry{"registry"}; + + // inspect for which zPvPosMax cut was set for reconstructed + void init(InitContext& initContext) + { + std::array procCollisionsXicToXiPi{doprocessMcXicToXiPi, doprocessMcXicToXiPiFT0m, doprocessMcXicToXiPiFT0c, doprocessMcXicToXiPiKf}; + if (std::accumulate(procCollisionsXicToXiPi.begin(), procCollisionsXicToXiPi.end(), 0) > 1) { + LOGP(fatal, "At most one process function for XicToXiPi collision study can be enabled at a time."); + } + std::array procCollisionsOmegacToXiPi{doprocessMcOmegacToXiPi, doprocessMcOmegacToXiPiFT0m, doprocessMcOmegacToXiPiFT0c}; + if (std::accumulate(procCollisionsOmegacToXiPi.begin(), procCollisionsOmegacToXiPi.end(), 0) > 1) { + LOGP(fatal, "At most one process function for OmegacToXiPi collision study can be enabled at a time."); + } + std::array procCollisionsOmegacToOmegaPi{doprocessMcOmegacToOmegaPi, doprocessMcOmegacToOmegaPiFT0m, doprocessMcOmegacToOmegaPiFT0c}; + if (std::accumulate(procCollisionsOmegacToOmegaPi.begin(), procCollisionsOmegacToOmegaPi.end(), 0) > 1) { + LOGP(fatal, "At most one process function for OmegacToOmegaPi collision study can be enabled at a time."); + } + std::array procCollisionsOmegacToOmegaK{doprocessMcOmegacToOmegaK, doprocessMcOmegacToOmegaKFT0m, doprocessMcOmegacToOmegaKFT0c}; + if (std::accumulate(procCollisionsOmegacToOmegaK.begin(), procCollisionsOmegacToOmegaK.end(), 0) > 1) { + LOGP(fatal, "At most one process function for OmegacToOmegaK collision study can be enabled at a time."); + } + + const auto& workflows = initContext.services().get(); + for (const DeviceSpec& device : workflows.devices) { + if (device.name.compare("hf-candidate-creator-xic0-omegac0") == 0) { + hfEvSelMc.configureFromDevice(device); + break; + } + } + hfEvSelMc.addHistograms(registry); // particles monitoring + + hGenCharmBaryonPtRapidityTightXicToXiPi = registry.add("hGenCharmBaryonPtRapidityTightXicToXiPi", "Generated charm baryon #it{p}_{T};#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {{20, 0.0, 20.0}}}); // keep track of generated candidates pt when |y|<0.5 + hGenCharmBaryonPtRapidityLooseXicToXiPi = registry.add("hGenCharmBaryonPtRapidityLooseXicToXiPi", "Generated charm baryon #it{p}_{T};#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {{20, 0.0, 20.0}}}); // keep track of generated candidates pt when |y|<0.8 + + hGenCharmBaryonPtRapidityTightOmegacToXiPi = registry.add("hGenCharmBaryonPtRapidityTightOmegacToXiPi", "Generated charm baryon #it{p}_{T};#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {{20, 0.0, 20.0}}}); + hGenCharmBaryonPtRapidityLooseOmegacToXiPi = registry.add("hGenCharmBaryonPtRapidityLooseOmegacToXiPi", "Generated charm baryon #it{p}_{T};#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {{20, 0.0, 20.0}}}); + + hGenCharmBaryonPtRapidityTightOmegacToOmegaPi = registry.add("hGenCharmBaryonPtRapidityTightOmegacToOmegaPi", "Generated charm baryon #it{p}_{T};#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {{20, 0.0, 20.0}}}); + hGenCharmBaryonPtRapidityLooseOmegacToOmegaPi = registry.add("hGenCharmBaryonPtRapidityLooseOmegacToOmegaPi", "Generated charm baryon #it{p}_{T};#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {{20, 0.0, 20.0}}}); + + hGenCharmBaryonPtRapidityTightOmegacToOmegaK = registry.add("hGenCharmBaryonPtRapidityTightOmegacToOmegaK", "Generated charm baryon #it{p}_{T};#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {{20, 0.0, 20.0}}}); + hGenCharmBaryonPtRapidityLooseOmegacToOmegaK = registry.add("hGenCharmBaryonPtRapidityLooseOmegacToOmegaK", "Generated charm baryon #it{p}_{T};#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {{20, 0.0, 20.0}}}); + } + + template + void runXic0Omegac0Mc(TMyRecoCand const& candidates, + MyTracksWMc const&, + aod::McParticles const& mcParticles, + Colls const& collsWithMcLabels, + McCollisions const& mcCollisions, + BCsInfo const&) + { + float ptCharmBaryonGen = -999.; + float rapidityCharmBaryonGen = -999.; + int indexRec = -1; + int indexRecCharmBaryon = -1; + int8_t sign = -9; + int8_t signCasc = -9; + int8_t signV0 = -9; + int8_t flag = 0; + int8_t origin = 0; // to be used for prompt/non prompt + McMatchFlag debug{McMatchFlag::None}; + int8_t debugGenCharmBar = 0; + int8_t debugGenCasc = 0; + int8_t debugGenLambda = 0; + int8_t nPiToMuV0{0}, nPiToMuCasc{0}, nPiToMuOmegac0{0}; + int8_t nKaToPiCasc{0}, nKaToPiOmegac0{0}; + bool collisionMatched = false; + + // Match reconstructed candidates. + for (const auto& candidate : candidates) { + flag = 0; + origin = RecoDecay::OriginType::None; + debug = McMatchFlag::None; + collisionMatched = false; + std::vector idxBhadMothers{}; + + auto arrayDaughters = std::array{candidate.template bachelorFromCharmBaryon_as(), // bachelor <- charm baryon + candidate.template bachelor_as(), // bachelor <- cascade + candidate.template posTrack_as(), // p <- lambda + candidate.template negTrack_as()}; // pi <- lambda + auto arrayDaughtersCasc = std::array{candidate.template bachelor_as(), + candidate.template posTrack_as(), + candidate.template negTrack_as()}; + auto arrayDaughtersV0 = std::array{candidate.template posTrack_as(), + candidate.template negTrack_as()}; + + // Check whether the particle is from background events. If so, reject it. + if (rejectBackground) { + bool fromBkg{false}; + for (const auto& daughter : arrayDaughters) { + if (daughter.has_mcParticle()) { + auto mcParticle = daughter.mcParticle(); + if (mcParticle.fromBackgroundEvent()) { + fromBkg = true; + break; + } + } + } + if (fromBkg) { + rowMCMatchRecXicToXiPi(flag, debug, origin, collisionMatched, -1.f, 0); + rowMCMatchRecOmegacToXiPi(flag, debug, origin, collisionMatched, -1.f, 0); + rowMCMatchRecToOmegaPi(flag, debug, origin, collisionMatched, -1.f, 0); + rowMCMatchRecToOmegaK(flag, debug, origin, collisionMatched, -1.f, 0); + continue; + } + } + // Xic0 -> xi pi matching + if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi) { + // Xic → pi pi pi p + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, +kXiC0, std::array{+kPiPlus, +kPiMinus, +kProton, +kPiMinus}, true, &sign, 3); + indexRecCharmBaryon = indexRec; + if (indexRec == -1) { + debug = McMatchFlag::CharmbaryonUnmatched; + } + if (indexRec > -1) { + // Xi- → pi pi p + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, +kXiMinus, std::array{+kPiMinus, +kProton, +kPiMinus}, true, &signCasc, 2); + if (indexRec == -1) { + debug = McMatchFlag::CascUnmatched; + } + if (indexRec > -1) { + // Lambda → p pi + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &signV0, 1); + if (indexRec == -1) { + debug = McMatchFlag::V0Unmatched; + } + if (indexRec > -1) { + flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi); + collisionMatched = candidate.template collision_as().mcCollisionId() == mcParticles.iteratorAt(indexRecCharmBaryon).mcCollisionId(); + } + } + } + // Check whether the charm baryon is non-prompt (from a b quark). + if (flag != 0) { + auto particle = mcParticles.rawIteratorAt(indexRecCharmBaryon); + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + } + if (origin == RecoDecay::OriginType::NonPrompt) { + auto bHadMother = mcParticles.rawIteratorAt(idxBhadMothers[0]); + rowMCMatchRecXicToXiPi(flag, debug, origin, collisionMatched, bHadMother.pt(), bHadMother.pdgCode()); + } else { + rowMCMatchRecXicToXiPi(flag, debug, origin, collisionMatched, -1.f, 0); + } + if (debug == McMatchFlag::CascUnmatched || debug == McMatchFlag::V0Unmatched) { + LOGF(info, "WARNING: Xic0ToXiPi decays in the expected final state but the condition on the intermediate states are not fulfilled"); + } + } else if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToXiPi) { // Omegac -> xi pi matching + // Omegac → pi pi pi p + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, +kOmegaC0, std::array{+kPiPlus, +kPiMinus, +kProton, +kPiMinus}, true, &sign, 3); + indexRecCharmBaryon = indexRec; + if (indexRec == -1) { + debug = McMatchFlag::CharmbaryonUnmatched; + } + if (indexRec > -1) { + // Xi- → pi pi p + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, +kXiMinus, std::array{+kPiMinus, +kProton, +kPiMinus}, true, &signCasc, 2); + if (indexRec == -1) { + debug = McMatchFlag::CascUnmatched; + } + if (indexRec > -1) { + // Lambda → p pi + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &signV0, 1); + if (indexRec == -1) { + debug = McMatchFlag::V0Unmatched; + } + if (indexRec > -1) { + flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToXiPi); + collisionMatched = candidate.template collision_as().mcCollisionId() == mcParticles.iteratorAt(indexRecCharmBaryon).mcCollisionId(); + } + } + } + // Check whether the charm baryon is non-prompt (from a b quark). + if (flag != 0) { + auto particle = mcParticles.rawIteratorAt(indexRecCharmBaryon); + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + } + if (origin == RecoDecay::OriginType::NonPrompt) { + auto bHadMother = mcParticles.rawIteratorAt(idxBhadMothers[0]); + rowMCMatchRecOmegacToXiPi(flag, debug, origin, collisionMatched, bHadMother.pt(), bHadMother.pdgCode()); + } else { + rowMCMatchRecOmegacToXiPi(flag, debug, origin, collisionMatched, -1.f, 0); + } + if (debug == McMatchFlag::CascUnmatched || debug == McMatchFlag::V0Unmatched) { + LOGF(info, "WARNING: Omegac0ToXiPi decays in the expected final state but the condition on the intermediate states are not fulfilled"); + } + } else if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi) { // Omegac0 -> omega pi matching + if (acceptTrackIntWithMaterial) { + // Omegac → pi K pi p + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, +kOmegaC0, std::array{+kPiPlus, +kKMinus, +kProton, +kPiMinus}, true, &sign, 3, &nPiToMuOmegac0, &nKaToPiOmegac0); + indexRecCharmBaryon = indexRec; + if (indexRec == -1) { + debug = McMatchFlag::CharmbaryonUnmatched; + } + if (indexRec > -1) { + // Omega- → K pi p + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, +kOmegaMinus, std::array{+kKMinus, +kProton, +kPiMinus}, true, &signCasc, 2, &nPiToMuCasc, &nKaToPiCasc); + if (indexRec == -1) { + debug = McMatchFlag::CascUnmatched; + } + if (indexRec > -1) { + // Lambda → p pi + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &signV0, 1, &nPiToMuV0); + if (indexRec == -1) { + debug = McMatchFlag::V0Unmatched; + } + if (indexRec > -1 && nPiToMuOmegac0 >= 1 && nKaToPiOmegac0 == 0) { + flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPiOneMu); + collisionMatched = candidate.template collision_as().mcCollisionId() == mcParticles.iteratorAt(indexRecCharmBaryon).mcCollisionId(); + } else if (indexRec > -1 && nPiToMuOmegac0 == 0 && nKaToPiOmegac0 == 0) { + flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi); + collisionMatched = candidate.template collision_as().mcCollisionId() == mcParticles.iteratorAt(indexRecCharmBaryon).mcCollisionId(); + } + } + } + } else { + // Omegac → pi K pi p + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, +kOmegaC0, std::array{+kPiPlus, +kKMinus, +kProton, +kPiMinus}, true, &sign, 3, &nPiToMuOmegac0, &nKaToPiOmegac0); + indexRecCharmBaryon = indexRec; + if (indexRec == -1) { + debug = McMatchFlag::CharmbaryonUnmatched; + } + if (indexRec > -1) { + // Omega- → K pi p + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, +kOmegaMinus, std::array{+kKMinus, +kProton, +kPiMinus}, true, &signCasc, 2, &nPiToMuCasc, &nKaToPiCasc); + if (indexRec == -1) { + debug = McMatchFlag::CascUnmatched; + } + if (indexRec > -1) { + // Lambda → p pi + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &signV0, 1, &nPiToMuV0); + if (indexRec == -1) { + debug = McMatchFlag::V0Unmatched; + } + if (indexRec > -1 && nPiToMuOmegac0 >= 1 && nKaToPiOmegac0 == 0) { + flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPiOneMu); + collisionMatched = candidate.template collision_as().mcCollisionId() == mcParticles.iteratorAt(indexRecCharmBaryon).mcCollisionId(); + } else if (indexRec > -1 && nPiToMuOmegac0 == 0 && nKaToPiOmegac0 == 0) { + flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi); + collisionMatched = candidate.template collision_as().mcCollisionId() == mcParticles.iteratorAt(indexRecCharmBaryon).mcCollisionId(); + } + } + } + } + // Check whether the charm baryon is non-prompt (from a b quark). + if (flag != 0) { + auto particle = mcParticles.rawIteratorAt(indexRecCharmBaryon); + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + } + if (origin == RecoDecay::OriginType::NonPrompt) { + auto bHadMother = mcParticles.rawIteratorAt(idxBhadMothers[0]); + rowMCMatchRecToOmegaPi(flag, debug, origin, collisionMatched, bHadMother.pt(), bHadMother.pdgCode()); + } else { + rowMCMatchRecToOmegaPi(flag, debug, origin, collisionMatched, -1.f, 0); + } + if (debug == McMatchFlag::CascUnmatched || debug == McMatchFlag::V0Unmatched) { + LOGF(info, "WARNING: Omegac0ToOmegaPi decays in the expected final state but the condition on the intermediate states are not fulfilled"); + } + } else if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaK) { // Omegac0 -> omega K matching + // Omegac → K K pi p + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, +kOmegaC0, std::array{+kKPlus, +kKMinus, +kProton, +kPiMinus}, true, &sign, 3); + indexRecCharmBaryon = indexRec; + if (indexRec == -1) { + debug = McMatchFlag::CharmbaryonUnmatched; + } + if (indexRec > -1) { + // Omega- → K pi p + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, +kOmegaMinus, std::array{+kKMinus, +kProton, +kPiMinus}, true, &signCasc, 2); + if (indexRec == -1) { + debug = McMatchFlag::CascUnmatched; + } + if (indexRec > -1) { + // Lambda → p pi + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &signV0, 1); + if (indexRec == -1) { + debug = McMatchFlag::V0Unmatched; + } + if (indexRec > -1) { + flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaK); + collisionMatched = candidate.template collision_as().mcCollisionId() == mcParticles.iteratorAt(indexRecCharmBaryon).mcCollisionId(); + } + } + } + // Check whether the charm baryon is non-prompt (from a b quark). + if (flag != 0) { + auto particle = mcParticles.rawIteratorAt(indexRecCharmBaryon); + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + } + if (origin == RecoDecay::OriginType::NonPrompt) { + auto bHadMother = mcParticles.rawIteratorAt(idxBhadMothers[0]); + rowMCMatchRecToOmegaK(flag, debug, origin, collisionMatched, bHadMother.pt(), bHadMother.pdgCode()); + } else { + rowMCMatchRecToOmegaK(flag, debug, origin, collisionMatched, -1.f, 0); + } + if (debug == McMatchFlag::CascUnmatched || debug == McMatchFlag::V0Unmatched) { + LOGF(info, "WARNING: Omegac0ToOmegaK decays in the expected final state but the condition on the intermediate states are not fulfilled"); + } + } + } // close loop over candidates + + for (const auto& mcCollision : mcCollisions) { + + // Slice the particles table to get the particles for the current MC collision + const auto mcParticlesPerMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, mcCollision.globalIndex()); + // Slice the collisions table to get the collision info for the current MC collision + float centrality{-1.f}; + uint16_t rejectionMask{0}; + if constexpr (centEstimator == CentralityEstimator::FT0C) { + const auto collSlice = collsWithMcLabels.sliceBy(colPerMcCollisionFT0C, mcCollision.globalIndex()); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } else if constexpr (centEstimator == CentralityEstimator::FT0M) { + const auto collSlice = collsWithMcLabels.sliceBy(colPerMcCollisionFT0M, mcCollision.globalIndex()); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } else if constexpr (centEstimator == CentralityEstimator::None) { + const auto collSlice = collsWithMcLabels.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } + hfEvSelMc.fillHistograms(mcCollision, rejectionMask); + if (rejectionMask != 0) { + /// at least one event selection not satisfied --> reject all particles from this collision + for (unsigned int i = 0; i < mcParticlesPerMcColl.size(); ++i) { + if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi) { + rowMCMatchGenXicToXiPi(0, 0, 0, 0, -999., -999., RecoDecay::OriginType::None, -1); + } else if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToXiPi) { + rowMCMatchGenOmegacToXiPi(0, 0, 0, 0, -999., -999., RecoDecay::OriginType::None, -1); + } else if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi) { + rowMCMatchGenToOmegaPi(0, 0, 0, 0, -999., -999., RecoDecay::OriginType::None, -1); + } else if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaK) { + rowMCMatchGenToOmegaK(0, 0, 0, 0, -999., -999., RecoDecay::OriginType::None, -1); + } + } + continue; + } + + // Match generated particles. + for (const auto& particle : mcParticlesPerMcColl) { + ptCharmBaryonGen = -999.; + rapidityCharmBaryonGen = -999.; + flag = 0; + sign = -9; + debugGenCharmBar = 0; + debugGenCasc = 0; + debugGenLambda = 0; + origin = RecoDecay::OriginType::None; + std::vector idxBhadMothers{}; + + // Reject particles from background events + if (particle.fromBackgroundEvent() && rejectBackground) { + if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi) { + rowMCMatchGenXicToXiPi(flag, debugGenCharmBar, debugGenCasc, debugGenLambda, ptCharmBaryonGen, rapidityCharmBaryonGen, origin, -1); + } else if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToXiPi) { + rowMCMatchGenOmegacToXiPi(flag, debugGenCharmBar, debugGenCasc, debugGenLambda, ptCharmBaryonGen, rapidityCharmBaryonGen, origin, -1); + } else if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi) { + rowMCMatchGenToOmegaPi(flag, debugGenCharmBar, debugGenCasc, debugGenLambda, ptCharmBaryonGen, rapidityCharmBaryonGen, origin, -1); + } else if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaK) { + rowMCMatchGenToOmegaK(flag, debugGenCharmBar, debugGenCasc, debugGenLambda, ptCharmBaryonGen, rapidityCharmBaryonGen, origin, -1); + } + continue; + } + + if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi) { + // Xic → Xi pi + if (RecoDecay::isMatchedMCGen(mcParticles, particle, +kXiC0, std::array{+kXiMinus, +kPiPlus}, true, &sign)) { + debugGenCharmBar = 1; + ptCharmBaryonGen = particle.pt(); + rapidityCharmBaryonGen = particle.y(); + for (const auto& daughterCharm : particle.template daughters_as()) { + if (std::abs(daughterCharm.pdgCode()) != +kXiMinus) { + continue; + } + // Xi -> Lambda pi + if (RecoDecay::isMatchedMCGen(mcParticles, daughterCharm, +kXiMinus, std::array{+kLambda0, +kPiMinus}, true)) { + debugGenCasc = 1; + for (const auto& daughterCascade : daughterCharm.template daughters_as()) { + if (std::abs(daughterCascade.pdgCode()) != +kLambda0) { + continue; + } + // Lambda -> p pi + if (RecoDecay::isMatchedMCGen(mcParticles, daughterCascade, +kLambda0, std::array{+kProton, +kPiMinus}, true)) { + debugGenLambda = 1; + flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi); + } + } + } + } + } + // Check whether the charm baryon is non-prompt (from a b quark) + if (flag != 0) { + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + if (std::abs(rapidityCharmBaryonGen) < 0.5) { + hGenCharmBaryonPtRapidityTightXicToXiPi->SetBinContent(hGenCharmBaryonPtRapidityTightXicToXiPi->FindBin(ptCharmBaryonGen), hGenCharmBaryonPtRapidityTightXicToXiPi->GetBinContent(hGenCharmBaryonPtRapidityTightXicToXiPi->FindBin(ptCharmBaryonGen)) + 1); + } + if (std::abs(rapidityCharmBaryonGen) < 0.8) { + hGenCharmBaryonPtRapidityLooseXicToXiPi->SetBinContent(hGenCharmBaryonPtRapidityLooseXicToXiPi->FindBin(ptCharmBaryonGen), hGenCharmBaryonPtRapidityLooseXicToXiPi->GetBinContent(hGenCharmBaryonPtRapidityLooseXicToXiPi->FindBin(ptCharmBaryonGen)) + 1); + } + } + if (origin == RecoDecay::OriginType::NonPrompt) { + rowMCMatchGenXicToXiPi(flag, debugGenCharmBar, debugGenCasc, debugGenLambda, ptCharmBaryonGen, rapidityCharmBaryonGen, origin, idxBhadMothers[0]); + } else { + rowMCMatchGenXicToXiPi(flag, debugGenCharmBar, debugGenCasc, debugGenLambda, ptCharmBaryonGen, rapidityCharmBaryonGen, origin, -1); + } + + } else if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToXiPi) { + // Omegac → Xi pi + if (RecoDecay::isMatchedMCGen(mcParticles, particle, +kOmegaC0, std::array{+kXiMinus, +kPiPlus}, true, &sign)) { + debugGenCharmBar = 1; + ptCharmBaryonGen = particle.pt(); + rapidityCharmBaryonGen = particle.y(); + for (const auto& daughterCharm : particle.template daughters_as()) { + if (std::abs(daughterCharm.pdgCode()) != +kXiMinus) { + continue; + } + // Xi -> Lambda pi + if (RecoDecay::isMatchedMCGen(mcParticles, daughterCharm, +kXiMinus, std::array{+kLambda0, +kPiMinus}, true)) { + debugGenCasc = 1; + for (const auto& daughterCascade : daughterCharm.template daughters_as()) { + if (std::abs(daughterCascade.pdgCode()) != +kLambda0) { + continue; + } + // Lambda -> p pi + if (RecoDecay::isMatchedMCGen(mcParticles, daughterCascade, +kLambda0, std::array{+kProton, +kPiMinus}, true)) { + debugGenLambda = 1; + flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToXiPi); + } + } + } + } + } + // Check whether the charm baryon is non-prompt (from a b quark) + if (flag != 0) { + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + if (std::abs(rapidityCharmBaryonGen) < 0.5) { + hGenCharmBaryonPtRapidityTightOmegacToXiPi->SetBinContent(hGenCharmBaryonPtRapidityTightOmegacToXiPi->FindBin(ptCharmBaryonGen), hGenCharmBaryonPtRapidityTightOmegacToXiPi->GetBinContent(hGenCharmBaryonPtRapidityTightOmegacToXiPi->FindBin(ptCharmBaryonGen)) + 1); + } + if (std::abs(rapidityCharmBaryonGen) < 0.8) { + hGenCharmBaryonPtRapidityLooseOmegacToXiPi->SetBinContent(hGenCharmBaryonPtRapidityLooseOmegacToXiPi->FindBin(ptCharmBaryonGen), hGenCharmBaryonPtRapidityLooseOmegacToXiPi->GetBinContent(hGenCharmBaryonPtRapidityLooseOmegacToXiPi->FindBin(ptCharmBaryonGen)) + 1); + } + } + if (origin == RecoDecay::OriginType::NonPrompt) { + rowMCMatchGenOmegacToXiPi(flag, debugGenCharmBar, debugGenCasc, debugGenLambda, ptCharmBaryonGen, rapidityCharmBaryonGen, origin, idxBhadMothers[0]); + } else { + rowMCMatchGenOmegacToXiPi(flag, debugGenCharmBar, debugGenCasc, debugGenLambda, ptCharmBaryonGen, rapidityCharmBaryonGen, origin, -1); + } + + } else if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi) { + // Omegac → Omega pi + if (RecoDecay::isMatchedMCGen(mcParticles, particle, +kOmegaC0, std::array{+kOmegaMinus, +kPiPlus}, true, &sign)) { + debugGenCharmBar = 1; + ptCharmBaryonGen = particle.pt(); + rapidityCharmBaryonGen = particle.y(); + for (const auto& daughterCharm : particle.template daughters_as()) { + if (std::abs(daughterCharm.pdgCode()) != +kOmegaMinus) { + continue; + } + // Omega -> Lambda K + if (RecoDecay::isMatchedMCGen(mcParticles, daughterCharm, +kOmegaMinus, std::array{+kLambda0, +kKMinus}, true)) { + debugGenCasc = 1; + for (const auto& daughterCascade : daughterCharm.template daughters_as()) { + if (std::abs(daughterCascade.pdgCode()) != +kLambda0) { + continue; + } + // Lambda -> p pi + if (RecoDecay::isMatchedMCGen(mcParticles, daughterCascade, +kLambda0, std::array{+kProton, +kPiMinus}, true)) { + debugGenLambda = 1; + flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi); + } + } + } + } + } + // Check whether the charm baryon is non-prompt (from a b quark) + if (flag != 0) { + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + if (std::abs(rapidityCharmBaryonGen) < 0.5) { + hGenCharmBaryonPtRapidityTightOmegacToOmegaPi->SetBinContent(hGenCharmBaryonPtRapidityTightOmegacToOmegaPi->FindBin(ptCharmBaryonGen), hGenCharmBaryonPtRapidityTightOmegacToOmegaPi->GetBinContent(hGenCharmBaryonPtRapidityTightOmegacToOmegaPi->FindBin(ptCharmBaryonGen)) + 1); + } + if (std::abs(rapidityCharmBaryonGen) < 0.8) { + hGenCharmBaryonPtRapidityLooseOmegacToOmegaPi->SetBinContent(hGenCharmBaryonPtRapidityLooseOmegacToOmegaPi->FindBin(ptCharmBaryonGen), hGenCharmBaryonPtRapidityLooseOmegacToOmegaPi->GetBinContent(hGenCharmBaryonPtRapidityLooseOmegacToOmegaPi->FindBin(ptCharmBaryonGen)) + 1); + } + } + if (origin == RecoDecay::OriginType::NonPrompt) { + rowMCMatchGenToOmegaPi(flag, debugGenCharmBar, debugGenCasc, debugGenLambda, ptCharmBaryonGen, rapidityCharmBaryonGen, origin, idxBhadMothers[0]); + } else { + rowMCMatchGenToOmegaPi(flag, debugGenCharmBar, debugGenCasc, debugGenLambda, ptCharmBaryonGen, rapidityCharmBaryonGen, origin, -1); + } + + } else if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaK) { + // Omegac → Omega K + if (RecoDecay::isMatchedMCGen(mcParticles, particle, +kOmegaC0, std::array{+kOmegaMinus, +kKPlus}, true, &sign)) { + debugGenCharmBar = 1; + ptCharmBaryonGen = particle.pt(); + rapidityCharmBaryonGen = particle.y(); + for (const auto& daughterCharm : particle.template daughters_as()) { + if (std::abs(daughterCharm.pdgCode()) != +kOmegaMinus) { + continue; + } + // Omega -> Lambda K + if (RecoDecay::isMatchedMCGen(mcParticles, daughterCharm, +kOmegaMinus, std::array{+kLambda0, +kKMinus}, true)) { + debugGenCasc = 1; + for (const auto& daughterCascade : daughterCharm.template daughters_as()) { + if (std::abs(daughterCascade.pdgCode()) != +kLambda0) { + continue; + } + // Lambda -> p pi + if (RecoDecay::isMatchedMCGen(mcParticles, daughterCascade, +kLambda0, std::array{+kProton, +kPiMinus}, true)) { + debugGenLambda = 1; + flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaK); + } + } + } + } + } + // Check whether the charm baryon is non-prompt (from a b quark) + if (flag != 0) { + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + if (std::abs(rapidityCharmBaryonGen) < 0.5) { + hGenCharmBaryonPtRapidityTightOmegacToOmegaK->SetBinContent(hGenCharmBaryonPtRapidityTightOmegacToOmegaK->FindBin(ptCharmBaryonGen), hGenCharmBaryonPtRapidityTightOmegacToOmegaK->GetBinContent(hGenCharmBaryonPtRapidityTightOmegacToOmegaK->FindBin(ptCharmBaryonGen)) + 1); + } + if (std::abs(rapidityCharmBaryonGen) < 0.8) { + hGenCharmBaryonPtRapidityLooseOmegacToOmegaK->SetBinContent(hGenCharmBaryonPtRapidityLooseOmegacToOmegaK->FindBin(ptCharmBaryonGen), hGenCharmBaryonPtRapidityLooseOmegacToOmegaK->GetBinContent(hGenCharmBaryonPtRapidityLooseOmegacToOmegaK->FindBin(ptCharmBaryonGen)) + 1); + } + } + if (origin == RecoDecay::OriginType::NonPrompt) { + rowMCMatchGenToOmegaK(flag, debugGenCharmBar, debugGenCasc, debugGenLambda, ptCharmBaryonGen, rapidityCharmBaryonGen, origin, idxBhadMothers[0]); + } else { + rowMCMatchGenToOmegaK(flag, debugGenCharmBar, debugGenCasc, debugGenLambda, ptCharmBaryonGen, rapidityCharmBaryonGen, origin, -1); + } + } + } // close loop on MCParticles + } // close loop on MCCollisions + } // close process + + void processDoNoMc(aod::Collisions::iterator const&) + { + // dummy process function - should not be required in the future + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processDoNoMc, "Do not run any MC process function", true); + + void processMcXicToXiPi(aod::HfCandToXiPi const& candidates, + MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcColls, + McCollisionsNoCents const& collsWithMcLabels, + BCsInfo const& bcs) + { + runXic0Omegac0Mc(candidates, tracks, mcParticles, collsWithMcLabels, mcColls, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcXicToXiPi, "Run Xic0 to xi pi MC process function - no centrality", false); + + void processMcXicToXiPiKf(aod::HfCandToXiPiKf const& candidates, + MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcColls, + McCollisionsNoCents const& collsWithMcLabels, + BCsInfo const& bcs) + { + runXic0Omegac0Mc(candidates, tracks, mcParticles, collsWithMcLabels, mcColls, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcXicToXiPiKf, "Run Xic0 to xi pi MC process function - no centrality", false); + + void processMcXicToXiPiFT0m(aod::HfCandToXiPi const& candidates, + MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisionsCentFT0Ms const& mcColls, + McCollisionsFT0Ms const& collsWithMcLabels, + BCsInfo const& bcs) + { + runXic0Omegac0Mc(candidates, tracks, mcParticles, collsWithMcLabels, mcColls, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcXicToXiPiFT0m, "Run Xic0 to xi pi MC process function - FT0M", false); + + void processMcXicToXiPiFT0c(aod::HfCandToXiPi const& candidates, + MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcColls, + McCollisionsFT0Cs const& collsWithMcLabels, + BCsInfo const& bcs) + { + runXic0Omegac0Mc(candidates, tracks, mcParticles, collsWithMcLabels, mcColls, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcXicToXiPiFT0c, "Run Xic0 to xi pi MC process function - FT0C", false); + + void processMcOmegacToXiPi(aod::HfCandToXiPi const& candidates, + MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcColls, + McCollisionsNoCents const& collsWithMcLabels, + BCsInfo const& bcs) + { + runXic0Omegac0Mc(candidates, tracks, mcParticles, collsWithMcLabels, mcColls, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcOmegacToXiPi, "Run Omegac0 to xi pi MC process function - no centrality", false); + + void processMcOmegacToXiPiFT0m(aod::HfCandToXiPi const& candidates, + MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisionsCentFT0Ms const& mcColls, + McCollisionsFT0Ms const& collsWithMcLabels, + BCsInfo const& bcs) + { + runXic0Omegac0Mc(candidates, tracks, mcParticles, collsWithMcLabels, mcColls, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcOmegacToXiPiFT0m, "Run Omegac0 to xi pi MC process function - FT0M", false); + + void processMcOmegacToXiPiFT0c(aod::HfCandToXiPi const& candidates, + MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcColls, + McCollisionsFT0Cs const& collsWithMcLabels, + BCsInfo const& bcs) + { + runXic0Omegac0Mc(candidates, tracks, mcParticles, collsWithMcLabels, mcColls, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcOmegacToXiPiFT0c, "Run Omegac0 to xi pi MC process function - FT0C", false); + + void processMcOmegacToOmegaPi(aod::HfCandToOmegaPi const& candidates, + MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcColls, + McCollisionsNoCents const& collsWithMcLabels, + BCsInfo const& bcs) + { + runXic0Omegac0Mc(candidates, tracks, mcParticles, collsWithMcLabels, mcColls, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcOmegacToOmegaPi, "Run Omegac0 to omega pi MC process function - no centrality", false); + + void processMcOmegacToOmegaPiFT0m(aod::HfCandToOmegaPi const& candidates, + MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisionsCentFT0Ms const& mcColls, + McCollisionsFT0Ms const& collsWithMcLabels, + BCsInfo const& bcs) + { + runXic0Omegac0Mc(candidates, tracks, mcParticles, collsWithMcLabels, mcColls, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcOmegacToOmegaPiFT0m, "Run Omegac0 to omega pi MC process function - FT0M", false); + + void processMcOmegacToOmegaPiFT0c(aod::HfCandToOmegaPi const& candidates, + MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcColls, + McCollisionsFT0Cs const& collsWithMcLabels, + BCsInfo const& bcs) + { + runXic0Omegac0Mc(candidates, tracks, mcParticles, collsWithMcLabels, mcColls, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcOmegacToOmegaPiFT0c, "Run Omegac0 to omega pi MC process function - FT0C", false); + + void processMcOmegacToOmegaK(aod::HfCandToOmegaK const& candidates, + MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcColls, + McCollisionsNoCents const& collsWithMcLabels, + BCsInfo const& bcs) + { + runXic0Omegac0Mc(candidates, tracks, mcParticles, collsWithMcLabels, mcColls, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcOmegacToOmegaK, "Run Omegac0 to omega K MC process function - no centrality", false); + + void processMcOmegacToOmegaKFT0m(aod::HfCandToOmegaK const& candidates, + MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisionsCentFT0Ms const& mcColls, + McCollisionsFT0Ms const& collsWithMcLabels, + BCsInfo const& bcs) + { + runXic0Omegac0Mc(candidates, tracks, mcParticles, collsWithMcLabels, mcColls, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcOmegacToOmegaKFT0m, "Run Omegac0 to omega K MC process function - FT0M", false); + + void processMcOmegacToOmegaKFT0c(aod::HfCandToOmegaK const& candidates, + MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcColls, + McCollisionsFT0Cs const& collsWithMcLabels, + BCsInfo const& bcs) + { + runXic0Omegac0Mc(candidates, tracks, mcParticles, collsWithMcLabels, mcColls, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcOmegacToOmegaKFT0c, "Run Omegac0 to omega K MC process function - FT0C", false); + +}; // close struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx b/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx new file mode 100644 index 00000000000..22b43f88061 --- /dev/null +++ b/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx @@ -0,0 +1,830 @@ +// 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 candidateCreatorXicToXiPiPi.cxx +/// \brief Reconstruction of Ξc± → (Ξ∓ → (Λ → p π∓) π∓) π± π± candidates +/// +/// \author Phil Lennart Stahlhut , Heidelberg University +/// \author Carolina Reetz , Heidelberg University +/// \author Jaeyoon Cho , Inha University +/// \author Jinjoo Seo , Heidelberg University + +#ifndef HomogeneousField +#define HomogeneousField // o2-linter: disable=name/macro (required by KFParticle) +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/DCA.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Tools/KFparticle/KFUtilities.h" + +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/Utils/utilsBfieldCCDB.h" + +using namespace o2; +using namespace o2::analysis; +using namespace o2::aod::hf_cand_xic_to_xi_pi_pi; +using namespace o2::constants::physics; +using namespace o2::framework; + +/// Reconstruction of heavy-flavour 3-prong decay candidates +struct HfCandidateCreatorXicToXiPiPi { + Produces rowCandidateBase; + Produces rowCandidateKF; + + Configurable fillHistograms{"fillHistograms", true, "do validation plots"}; + // magnetic field setting from CCDB + Configurable isRun2{"isRun2", false, "enable Run 2 or Run 3 GRP objects for magnetic field"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; + Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + // cascade preselections + Configurable doCascadePreselection{"doCascadePreselection", true, "Use invariant mass and dcaXY cuts to preselect cascade candidates"}; + Configurable massToleranceCascade{"massToleranceCascade", 0.01, "Invariant mass tolerance for cascade"}; + Configurable dcaXYToPVCascadeMax{"dcaXYToPVCascadeMax", 3, "Max cascade DCA to PV in xy plane"}; + // DCA fitter + Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; + Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; + Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; + Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations is chi2/chi2old > this"}; + Configurable useAbsDCA{"useAbsDCA", false, "Minimise abs. distance rather than chi2"}; + Configurable useWeightedFinalPCA{"useWeightedFinalPCA", false, "Recalculate vertex position using track covariances, effective only if useAbsDCA is true"}; + // KFParticle + Configurable useXiMassConstraint{"useXiMassConstraint", true, "Use mass constraint for Xi"}; + Configurable constrainXicPlusToPv{"constrainXicPlusToPv", false, "Constrain XicPlus to PV"}; + Configurable constrainXiToXicPlus{"constrainXiToXicPlus", false, "Constrain Xi to XicPlus"}; + Configurable kfConstructMethod{"kfConstructMethod", 2, "Construct method of XicPlus: 0 fast mathematics without constraint of fixed daughter particle masses, 2 daughter particle masses stay fixed in construction process"}; + Configurable rejDiffCollTrack{"rejDiffCollTrack", true, "Reject tracks coming from different collisions (effective only for KFParticle w/o derived data)"}; + + Service ccdb; + o2::base::MatLayerCylSet* lut; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + + o2::vertexing::DCAFitterN<3> df; + + int runNumber{0}; + float massXiPiPi{0.}; + float massXiPi0{0.}; + float massXiPi1{0.}; + double bz{0.}; + enum XicCandCounter { AllIdTriplets = 0, + CascPreSel, + VertexFit }; + + using CascadesLinked = soa::Join; + using CascFull = soa::Join; + using KFCascadesLinked = soa::Join; + using KFCascFull = soa::Join; + using TracksWCovDcaPidPrPi = soa::Join; + using TracksWCovExtraPidPrPi = soa::Join; + + HistogramRegistry registry{"registry"}; + + void init(InitContext const&) + { + if ((doprocessXicplusWithDcaFitter + doprocessXicplusWithKFParticle) != 1) { + LOGP(fatal, "Only one process function can be enabled at a time."); + } + + // add histograms to registry + if (fillHistograms) { + // counter + registry.add("hVertexerType", "Use KF or DCAFitterN;Vertexer type;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); // See o2::aod::hf_cand::VertexerType + registry.add("hCandCounter", "hCandCounter", {HistType::kTH1F, {{3, 0.5, 3.5}}}); + registry.get(HIST("hCandCounter"))->GetXaxis()->SetBinLabel(1 + AllIdTriplets, "total"); + registry.get(HIST("hCandCounter"))->GetXaxis()->SetBinLabel(1 + CascPreSel, "Cascade preselection"); + registry.get(HIST("hCandCounter"))->GetXaxis()->SetBinLabel(1 + VertexFit, "Successful vertex fit"); + // physical variables + registry.add("hMass3", "3-prong candidates;inv. mass (#Xi #pi #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 2.3, 2.7}}}); + registry.add("hCovPVXX", "3-prong candidates;XX element of cov. matrix of prim. vtx. position (cm^{2});entries", {HistType::kTH1D, {{100, 0., 1.e-4}}}); + registry.add("hCovSVXX", "3-prong candidates;XX element of cov. matrix of sec. vtx. position (cm^{2});entries", {HistType::kTH1D, {{100, 0., 0.2}}}); + registry.add("hCovPVYY", "3-prong candidates;YY element of cov. matrix of prim. vtx. position (cm^{2});entries", {HistType::kTH1D, {{100, 0., 1.e-4}}}); + registry.add("hCovSVYY", "3-prong candidates;YY element of cov. matrix of sec. vtx. position (cm^{2});entries", {HistType::kTH1D, {{100, 0., 0.2}}}); + registry.add("hCovPVXZ", "3-prong candidates;XZ element of cov. matrix of prim. vtx. position (cm^{2});entries", {HistType::kTH1D, {{100, -1.e-4, 1.e-4}}}); + registry.add("hCovSVXZ", "3-prong candidates;XZ element of cov. matrix of sec. vtx. position (cm^{2});entries", {HistType::kTH1D, {{100, -1.e-4, 0.2}}}); + registry.add("hCovPVZZ", "3-prong candidates;ZZ element of cov. matrix of prim. vtx. position (cm^{2});entries", {HistType::kTH1D, {{100, 0., 1.e-4}}}); + registry.add("hCovSVZZ", "3-prong candidates;ZZ element of cov. matrix of sec. vtx. position (cm^{2});entries", {HistType::kTH1D, {{100, 0., 0.2}}}); + registry.add("hDcaXYProngs", "DCAxy of 3-prong candidates;#it{p}_{T} (GeV/#it{c};#it{d}_{xy}) (#mum);entries", {HistType::kTH2D, {{100, 0., 20.}, {200, -500., 500.}}}); + registry.add("hDcaZProngs", "DCAz of 3-prong candidates;#it{p}_{T} (GeV/#it{c};#it{d}_{z}) (#mum);entries", {HistType::kTH2D, {{100, 0., 20.}, {200, -500., 500.}}}); + } + + // fill hVertexerType histogram + if (doprocessXicplusWithDcaFitter && fillHistograms) { + registry.fill(HIST("hVertexerType"), aod::hf_cand::VertexerType::DCAFitter); + } + if (doprocessXicplusWithKFParticle && fillHistograms) { + registry.fill(HIST("hVertexerType"), aod::hf_cand::VertexerType::KfParticle); + } + + // initialize CCDB + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); + runNumber = 0; + + // initialize 3-prong vertex fitter + df.setPropagateToPCA(propagateToPCA); + df.setMaxR(maxR); + df.setMaxDZIni(maxDZIni); + df.setMinParamChange(minParamChange); + df.setMinRelChi2Change(minRelChi2Change); + df.setUseAbsDCA(useAbsDCA); + df.setWeightedFinalPCA(useWeightedFinalPCA); + } + + void processXicplusWithDcaFitter(aod::Collisions const&, + aod::HfCascLf3Prongs const& rowsTrackIndexXicPlus, + CascadesLinked const&, + CascFull const&, + TracksWCovDcaPidPrPi const&, + aod::BCsWithTimestamps const&) + { + // loop over triplets of track indices + for (const auto& rowTrackIndexXicPlus : rowsTrackIndexXicPlus) { + auto cascAodElement = rowTrackIndexXicPlus.cascade_as(); + if (!cascAodElement.has_cascData()) { + continue; + } + auto casc = cascAodElement.cascData_as(); + auto trackCharmBachelor0 = rowTrackIndexXicPlus.prong0_as(); + auto trackCharmBachelor1 = rowTrackIndexXicPlus.prong1_as(); + auto collision = rowTrackIndexXicPlus.collision(); + if (fillHistograms) { + registry.fill(HIST("hCandCounter"), 1 + AllIdTriplets); + } + + // preselect cascade candidates + if (doCascadePreselection) { + if (std::abs(casc.dcaXYCascToPV()) > dcaXYToPVCascadeMax) { + continue; + } + if (std::abs(casc.mXi() - MassXiMinus) > massToleranceCascade) { + continue; + } + } + if (fillHistograms) { + registry.fill(HIST("hCandCounter"), 1 + CascPreSel); + } + + //----------------------Set the magnetic field from ccdb--------------------------------------- + /// The static instance of the propagator was already modified in the HFTrackIndexSkimCreator, + /// but this is not true when running on Run2 data/MC already converted into AO2Ds. + auto bc = collision.bc_as(); + if (runNumber != bc.runNumber()) { + LOG(info) << ">>>>>>>>>>>> Current run number: " << runNumber; + initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, lut, isRun2); + bz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << ">>>>>>>>>>>> Magnetic field: " << bz; + } + df.setBz(bz); + + //--------------------------info of V0 and cascades track from LF-tables--------------------------- + std::array vertexV0 = {casc.xlambda(), casc.ylambda(), casc.zlambda()}; + std::array pVecV0 = {casc.pxlambda(), casc.pylambda(), casc.pzlambda()}; + std::array vertexCasc = {casc.x(), casc.y(), casc.z()}; + std::array pVecCasc = {casc.px(), casc.py(), casc.pz()}; + std::array covCasc = {0.}; + + //----------------create cascade track------------------------------------------------------------ + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 6; i++) { + covCasc[MomInd[i]] = casc.momentumCovMat()[i]; + covCasc[i] = casc.positionCovMat()[i]; + } + // create cascade track + o2::track::TrackParCov trackCasc; + if (casc.sign() > 0) { + trackCasc = o2::track::TrackParCov(vertexCasc, pVecCasc, covCasc, 1, true); + } else if (casc.sign() < 0) { + trackCasc = o2::track::TrackParCov(vertexCasc, pVecCasc, covCasc, -1, true); + } else { + continue; + } + trackCasc.setAbsCharge(1); + trackCasc.setPID(o2::track::PID::XiMinus); + + //----------------------------fit SV and create XicPlus track------------------ + auto trackParCovCharmBachelor0 = getTrackParCov(trackCharmBachelor0); + auto trackParCovCharmBachelor1 = getTrackParCov(trackCharmBachelor1); + + // reconstruct the 3-prong secondary vertex + try { + if (df.process(trackCasc, trackParCovCharmBachelor0, trackParCovCharmBachelor1) == 0) { + continue; + } + } catch (const std::runtime_error& error) { + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; + continue; + } + if (fillHistograms) { + registry.fill(HIST("hCandCounter"), 1 + VertexFit); + } + + //----------------------------calculate physical properties----------------------- + // Charge of charm baryon + int signXic = casc.sign() < 0 ? +1 : -1; + + // get SV properties + const auto& secondaryVertex = df.getPCACandidate(); + auto chi2SV = df.getChi2AtPCACandidate(); + auto covMatrixSV = df.calcPCACovMatrixFlat(); + + // get track momenta + trackCasc = df.getTrack(0); + trackParCovCharmBachelor0 = df.getTrack(1); + trackParCovCharmBachelor1 = df.getTrack(2); + std::array pVecXi; + std::array pVecPi0; + std::array pVecPi1; + trackCasc.getPxPyPzGlo(pVecXi); + trackParCovCharmBachelor0.getPxPyPzGlo(pVecPi0); + trackParCovCharmBachelor1.getPxPyPzGlo(pVecPi1); + + // get invariant mass of Xic candidate + auto arrayMomenta = std::array{pVecXi, pVecPi0, pVecPi1}; + massXiPiPi = RecoDecay::m(std::move(arrayMomenta), std::array{MassXiMinus, MassPiPlus, MassPiPlus}); + + // get track impact parameters + // This modifies track momenta! + auto primaryVertex = getPrimaryVertex(collision); + auto covMatrixPV = primaryVertex.getCov(); + // calculate impact parameter + o2::dataformats::DCA impactParameterCasc; + o2::dataformats::DCA impactParameter0; + o2::dataformats::DCA impactParameter1; + trackCasc.propagateToDCA(primaryVertex, bz, &impactParameterCasc); + trackParCovCharmBachelor0.propagateToDCA(primaryVertex, bz, &impactParameter0); + trackParCovCharmBachelor1.propagateToDCA(primaryVertex, bz, &impactParameter1); + + // calculate cosine of pointing angle + std::array pvCoord = {collision.posX(), collision.posY(), collision.posZ()}; + float cpaLambda = casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); + float cpaXYLambda = RecoDecay::cpaXY(pvCoord, vertexV0, pVecV0); + float cpaXi = casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()); + float cpaXYXi = RecoDecay::cpaXY(pvCoord, vertexCasc, pVecCasc); + float cpaLambdaToXi = RecoDecay::cpa(vertexCasc, vertexV0, pVecV0); + float cpaXYLambdaToXi = RecoDecay::cpaXY(vertexCasc, vertexV0, pVecV0); + + // get invariant mass of Xi-pi pairs + auto arrayMomentaXiPi0 = std::array{pVecXi, pVecPi0}; + massXiPi0 = RecoDecay::m(std::move(arrayMomentaXiPi0), std::array{MassXiMinus, MassPiPlus}); + auto arrayMomentaXiPi1 = std::array{pVecXi, pVecPi1}; + massXiPi1 = RecoDecay::m(std::move(arrayMomentaXiPi1), std::array{MassXiMinus, MassPiPlus}); + + // get uncertainty of the decay length + float phi, theta; + getPointDirection(std::array{primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, secondaryVertex, phi, theta); + auto errorDecayLength = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixSV, phi, theta)); + auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixSV, phi, 0.)); + + //--------------------- get PID information----------------------- + float nSigTpcPiFromXicPlus0 = trackCharmBachelor0.tpcNSigmaPi(); + float nSigTofPiFromXicPlus0 = trackCharmBachelor0.tofNSigmaPi(); + float nSigTpcPiFromXicPlus1 = trackCharmBachelor1.tpcNSigmaPi(); + float nSigTofPiFromXicPlus1 = trackCharmBachelor1.tofNSigmaPi(); + // Bachelor pion + auto trackPionFromXi = casc.bachelor_as(); + float nSigTpcBachelorPi = trackPionFromXi.tpcNSigmaPi(); + float nSigTofBachelorPi = trackPionFromXi.tofNSigmaPi(); + // Lambda daughters + auto trackPosLambdaDaughter = casc.posTrack_as(); + auto trackNegLambdaDaughter = casc.negTrack_as(); + float pPiFromLambda, pPrFromLambda, nSigTpcPiFromLambda, nSigTofPiFromLambda, nSigTpcPrFromLambda, nSigTofPrFromLambda; + if (signXic == +1) { + pPiFromLambda = trackNegLambdaDaughter.p(); + nSigTpcPiFromLambda = trackNegLambdaDaughter.tpcNSigmaPi(); + nSigTofPiFromLambda = trackNegLambdaDaughter.tofNSigmaPi(); + pPrFromLambda = trackPosLambdaDaughter.p(); + nSigTpcPrFromLambda = trackPosLambdaDaughter.tpcNSigmaPr(); + nSigTofPrFromLambda = trackPosLambdaDaughter.tofNSigmaPr(); + } else { + pPiFromLambda = trackPosLambdaDaughter.p(); + nSigTpcPiFromLambda = trackPosLambdaDaughter.tpcNSigmaPi(); + nSigTofPiFromLambda = trackPosLambdaDaughter.tofNSigmaPi(); + pPrFromLambda = trackNegLambdaDaughter.p(); + nSigTpcPrFromLambda = trackNegLambdaDaughter.tpcNSigmaPr(); + nSigTofPrFromLambda = trackNegLambdaDaughter.tofNSigmaPr(); + } + + //--------------------------------------------fill histograms---------------------------------------------------------------- + if (fillHistograms) { + // invariant mass + registry.fill(HIST("hMass3"), massXiPiPi); + // covariance matrix elements of PV + registry.fill(HIST("hCovPVXX"), covMatrixPV[0]); + registry.fill(HIST("hCovPVYY"), covMatrixPV[2]); + registry.fill(HIST("hCovPVXZ"), covMatrixPV[3]); + registry.fill(HIST("hCovPVZZ"), covMatrixPV[5]); + // covariance matrix elements of SV + registry.fill(HIST("hCovSVXX"), covMatrixSV[0]); + registry.fill(HIST("hCovSVYY"), covMatrixSV[2]); + registry.fill(HIST("hCovSVXZ"), covMatrixSV[3]); + registry.fill(HIST("hCovSVZZ"), covMatrixSV[5]); + // DCAs of prongs + registry.fill(HIST("hDcaXYProngs"), trackCasc.getPt(), impactParameterCasc.getY()); + registry.fill(HIST("hDcaXYProngs"), trackCharmBachelor0.pt(), impactParameter0.getY()); + registry.fill(HIST("hDcaXYProngs"), trackCharmBachelor1.pt(), impactParameter1.getY()); + registry.fill(HIST("hDcaZProngs"), trackCasc.getPt(), impactParameterCasc.getZ()); + registry.fill(HIST("hDcaZProngs"), trackCharmBachelor0.pt(), impactParameter0.getZ()); + registry.fill(HIST("hDcaZProngs"), trackCharmBachelor1.pt(), impactParameter1.getZ()); + } + + //---------------------------------fill candidate table rows------------------------------------------------------------------------------------------- + rowCandidateBase(collision.globalIndex(), + primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ(), + std::sqrt(covMatrixPV[0]), std::sqrt(covMatrixPV[2]), std::sqrt(covMatrixPV[5]), + /*3-prong specific columns*/ + rowTrackIndexXicPlus.cascadeId(), rowTrackIndexXicPlus.prong0Id(), rowTrackIndexXicPlus.prong1Id(), + casc.bachelorId(), casc.posTrackId(), casc.negTrackId(), + secondaryVertex[0], secondaryVertex[1], secondaryVertex[2], + std::sqrt(covMatrixSV[0]), std::sqrt(covMatrixSV[2]), std::sqrt(covMatrixSV[5]), + errorDecayLength, errorDecayLengthXY, + chi2SV, massXiPiPi, signXic, + pVecXi[0], pVecXi[1], pVecXi[2], + pVecPi0[0], pVecPi0[1], pVecPi0[2], + pVecPi1[0], pVecPi1[1], pVecPi1[2], + impactParameterCasc.getY(), impactParameter0.getY(), impactParameter1.getY(), + std::sqrt(impactParameterCasc.getSigmaY2()), std::sqrt(impactParameter0.getSigmaY2()), std::sqrt(impactParameter1.getSigmaY2()), + /*cascade specific columns*/ + trackPionFromXi.p(), pPiFromLambda, pPrFromLambda, + cpaXi, cpaXYXi, cpaLambda, cpaXYLambda, cpaLambdaToXi, cpaXYLambdaToXi, + casc.mXi(), casc.mLambda(), massXiPi0, massXiPi1, + /*DCA information*/ + casc.dcacascdaughters(), casc.dcaV0daughters(), casc.dcapostopv(), casc.dcanegtopv(), casc.dcabachtopv(), + casc.dcaXYCascToPV(), casc.dcaZCascToPV(), + /*PID information*/ + nSigTpcPiFromXicPlus0, nSigTpcPiFromXicPlus1, nSigTpcBachelorPi, nSigTpcPiFromLambda, nSigTpcPrFromLambda, + nSigTofPiFromXicPlus0, nSigTofPiFromXicPlus1, nSigTofBachelorPi, nSigTofPiFromLambda, nSigTofPrFromLambda); + } // loop over track triplets + } + PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processXicplusWithDcaFitter, "Run candidate creator with DCAFitter.", true); + + void processXicplusWithKFParticle(aod::Collisions const&, + aod::HfCascLf3Prongs const& rowsTrackIndexXicPlus, + KFCascadesLinked const&, + KFCascFull const&, + TracksWCovExtraPidPrPi const&, + aod::BCsWithTimestamps const&) + { + // loop over triplets of track indices + for (const auto& rowTrackIndexXicPlus : rowsTrackIndexXicPlus) { + auto cascAodElement = rowTrackIndexXicPlus.cascade_as(); + if (!cascAodElement.has_kfCascData()) { + continue; + } + auto casc = cascAodElement.kfCascData_as(); + auto trackCharmBachelor0 = rowTrackIndexXicPlus.prong0_as(); + auto trackCharmBachelor1 = rowTrackIndexXicPlus.prong1_as(); + auto collision = rowTrackIndexXicPlus.collision(); + if (fillHistograms) { + registry.fill(HIST("hCandCounter"), 1 + AllIdTriplets); + } + + //-------------------preselect cascade candidates-------------------------------------- + if (doCascadePreselection) { + if (std::abs(casc.dcaXYCascToPV()) > dcaXYToPVCascadeMax) { + continue; + } + if (std::abs(casc.mXi() - MassXiMinus) > massToleranceCascade) { + continue; + } + } + if (fillHistograms) { + registry.fill(HIST("hCandCounter"), 1 + CascPreSel); + } + + //----------------------Set the magnetic field from ccdb----------------------------- + /// The static instance of the propagator was already modified in the HFTrackIndexSkimCreator, + /// but this is not true when running on Run2 data/MC already converted into AO2Ds. + auto bc = collision.bc_as(); + if (runNumber != bc.runNumber()) { + LOG(info) << ">>>>>>>>>>>> Current run number: " << runNumber; + initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, lut, isRun2); + bz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << ">>>>>>>>>>>> Magnetic field: " << bz; + } + KFParticle::SetField(bz); + + //----------------------info of V0 and cascade tracks from LF-table------------------ + std::array vertexV0 = {casc.xlambda(), casc.ylambda(), casc.zlambda()}; + std::array pVecV0 = {casc.pxlambda(), casc.pylambda(), casc.pzlambda()}; + std::array vertexCasc = {casc.x(), casc.y(), casc.z()}; + std::array pVecCasc = {casc.px(), casc.py(), casc.pz()}; + + //----------------------Create XicPlus as KFParticle object------------------------------------------- + // initialize primary vertex + KFPVertex kfpVertex = createKFPVertexFromCollision(collision); + float covMatrixPV[6]; + kfpVertex.GetCovarianceMatrix(covMatrixPV); + KFParticle kfPv(kfpVertex); // for calculation of DCAs to PV + + // convert pion tracks into KFParticle object + KFPTrack kfpTrackCharmBachelor0 = createKFPTrackFromTrack(trackCharmBachelor0); + KFPTrack kfpTrackCharmBachelor1 = createKFPTrackFromTrack(trackCharmBachelor1); + KFParticle kfCharmBachelor0(kfpTrackCharmBachelor0, kPiPlus); + KFParticle kfCharmBachelor1(kfpTrackCharmBachelor1, kPiPlus); + + // create Xi as KFParticle object + // read {X,Y,Z,Px,Py,Pz} and corresponding covariance matrix from KF cascade Tables + std::array xyzpxpypz = {casc.x(), casc.y(), casc.z(), casc.px(), casc.py(), casc.pz()}; + float parPosMom[6]; + for (int i{0}; i < 6; ++i) { + parPosMom[i] = xyzpxpypz[i]; + } + // create KFParticle + KFParticle kfXi; + float massXi = casc.mXi(); + kfXi.Create(parPosMom, casc.kfTrackCovMat(), casc.sign(), massXi); + if (useXiMassConstraint) { + kfXi.SetNonlinearMassConstraint(MassXiMinus); + } + + // create XicPlus as KFParticle object + KFParticle kfXicPlus; + const KFParticle* kfDaughtersXicPlus[3] = {&kfCharmBachelor0, &kfCharmBachelor1, &kfXi}; + kfXicPlus.SetConstructMethod(kfConstructMethod); + try { + kfXicPlus.Construct(kfDaughtersXicPlus, 3); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to construct XicPlus : " << e.what(); + continue; + } + if (fillHistograms) { + registry.fill(HIST("hCandCounter"), 1 + VertexFit); + } + + // get geometrical chi2 of XicPlus + float chi2GeoXicPlus = kfXicPlus.GetChi2() / kfXicPlus.GetNDF(); + + // topological constraint of Xic to PV + float chi2topoXicPlusToPVBeforeConstraint = kfXicPlus.GetDeviationFromVertex(kfPv); + KFParticle kfXicPlusToPV = kfXicPlus; + kfXicPlusToPV.SetProductionVertex(kfPv); + float chi2topoXicPlusToPV = kfXicPlusToPV.GetChi2() / kfXicPlusToPV.GetNDF(); + if (constrainXicPlusToPv) { + kfXicPlus = kfXicPlusToPV; + kfXicPlus.TransportToDecayVertex(); + } + + // topological constraint of Xi to XicPlus + float chi2topoXiToXicPlusBeforeConstraint = kfXi.GetDeviationFromVertex(kfXicPlus); + KFParticle kfXiToXicPlus = kfXi; + kfXiToXicPlus.SetProductionVertex(kfXicPlus); + float chi2topoXiToXicPlus = kfXiToXicPlus.GetChi2() / kfXiToXicPlus.GetNDF(); + kfXiToXicPlus.TransportToDecayVertex(); + if (constrainXiToXicPlus) { + KFParticle kfXicPlusWithXiToXicPlus; + const KFParticle* kfDaughtersXicPlusWithXiToXicPlus[3] = {&kfCharmBachelor0, &kfCharmBachelor1, &kfXiToXicPlus}; + kfXicPlusWithXiToXicPlus.SetConstructMethod(kfConstructMethod); + try { + kfXicPlusWithXiToXicPlus.Construct(kfDaughtersXicPlusWithXiToXicPlus, 3); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to construct XicPlus with Xi connstrained to XicPlus: " << e.what(); + continue; + } + kfXicPlus = kfXicPlusWithXiToXicPlus; + } + + // get covariance matrix of XicPlus + auto covMatrixXicPlus = kfXicPlus.CovarianceMatrix(); + + //---------------------calculate physical parameters of XicPlus candidate---------------------- + // sign of charm baryon + int signXic = casc.sign() < 0 ? +1 : -1; + + // transport XicPlus daughters to XicPlus decay vertex (secondary vertex) + float secondaryVertex[3] = {0.}; + secondaryVertex[0] = kfXicPlus.GetX(); + secondaryVertex[1] = kfXicPlus.GetY(); + secondaryVertex[2] = kfXicPlus.GetZ(); + kfXi.TransportToPoint(secondaryVertex); + kfCharmBachelor0.TransportToPoint(secondaryVertex); + kfCharmBachelor1.TransportToPoint(secondaryVertex); + + // get impact parameters of XicPlus daughters + float impactParameterPi0XY = 0., errImpactParameterPi0XY = 0.; + float impactParameterPi1XY = 0., errImpactParameterPi1XY = 0.; + float impactParameterXiXY = 0., errImpactParameterXiXY = 0.; + kfCharmBachelor0.GetDistanceFromVertexXY(kfPv, impactParameterPi0XY, errImpactParameterPi0XY); + kfCharmBachelor1.GetDistanceFromVertexXY(kfPv, impactParameterPi1XY, errImpactParameterPi1XY); + kfXi.GetDistanceFromVertexXY(kfPv, impactParameterXiXY, errImpactParameterXiXY); + + // calculate cosine of pointing angle + std::array pvCoord = {collision.posX(), collision.posY(), collision.posZ()}; + float cpaLambda = casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); + float cpaXYLambda = RecoDecay::cpaXY(pvCoord, vertexV0, pVecV0); + float cpaXi = casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()); + float cpaXYXi = RecoDecay::cpaXY(pvCoord, vertexCasc, pVecCasc); + float cpaLambdaToXi = RecoDecay::cpa(vertexCasc, vertexV0, pVecV0); + float cpaXYLambdaToXi = RecoDecay::cpaXY(vertexCasc, vertexV0, pVecV0); + + // get DCAs of Pi0-Pi1, Pi0-Xi, Pi1-Xi + float dcaXYPi0Pi1 = kfCharmBachelor0.GetDistanceFromParticleXY(kfCharmBachelor1); + float dcaXYPi0Xi = kfCharmBachelor0.GetDistanceFromParticleXY(kfXi); + float dcaXYPi1Xi = kfCharmBachelor1.GetDistanceFromParticleXY(kfXi); + float dcaPi0Pi1 = kfCharmBachelor0.GetDistanceFromParticle(kfCharmBachelor1); + float dcaPi0Xi = kfCharmBachelor0.GetDistanceFromParticle(kfXi); + float dcaPi1Xi = kfCharmBachelor1.GetDistanceFromParticle(kfXi); + + // mass of Xi-Pi0 pair + KFParticle kfXiPi0; + float errMassXiPi0; + const KFParticle* kfXiResonanceDaughtersPi0[2] = {&kfXi, &kfCharmBachelor0}; + kfXiPi0.SetConstructMethod(kfConstructMethod); + try { + kfXiPi0.Construct(kfXiResonanceDaughtersPi0, 2); + } catch (...) { + LOG(info) << "Failed to construct Xi(1530) with Pi 0"; + } + kfXiPi0.GetMass(massXiPi0, errMassXiPi0); + + // mass of Xi-Pi1 pair + KFParticle kfXiPi1; + float errMassXiPi1; + const KFParticle* kfXiResonanceDaughtersPi1[2] = {&kfXi, &kfCharmBachelor1}; + kfXiPi1.SetConstructMethod(kfConstructMethod); + try { + kfXiPi1.Construct(kfXiResonanceDaughtersPi1, 2); + } catch (...) { + LOG(info) << "Failed to construct Xi(1530) with Pi 1"; + } + kfXiPi1.GetMass(massXiPi1, errMassXiPi1); + + // get invariant mass of Xic candidate + float errMassXiPiPi; + kfXicPlus.GetMass(massXiPiPi, errMassXiPiPi); + + // decay length of XicPlus + // use XicPlus constrained to PV (kfXicPlusToPV), since production point must be set before calling GetDecayLength(XY) on KFParticle + float kfDecayLength = 0., errorKfDecayLength = 0., kfDecayLengthXY = 0., errorKfDecayLengthXY = 0.; + kfXicPlusToPV.GetDecayLength(kfDecayLength, errorKfDecayLength); + kfXicPlusToPV.GetDecayLengthXY(kfDecayLengthXY, errorKfDecayLengthXY); + float kfDecayLengthNormalised = ldlFromKF(kfXicPlus, kfPv); + float kfDecayLengthXYNormalised = ldlXYFromKF(kfXicPlus, kfPv); + + //--------------------- get PID information----------------------- + float nSigTpcPiFromXicPlus0 = trackCharmBachelor0.tpcNSigmaPi(); + float nSigTofPiFromXicPlus0 = trackCharmBachelor0.tofNSigmaPi(); + float nSigTpcPiFromXicPlus1 = trackCharmBachelor1.tpcNSigmaPi(); + float nSigTofPiFromXicPlus1 = trackCharmBachelor1.tofNSigmaPi(); + // Bachelor pion + auto trackPionFromXi = casc.bachelor_as(); + float nSigTpcBachelorPi = trackPionFromXi.tpcNSigmaPi(); + float nSigTofBachelorPi = trackPionFromXi.tofNSigmaPi(); + // Lambda daughters + auto trackPosLambdaDaughter = casc.posTrack_as(); + auto trackNegLambdaDaughter = casc.negTrack_as(); + float pPiFromLambda, pPrFromLambda, nSigTpcPiFromLambda, nSigTofPiFromLambda, nSigTpcPrFromLambda, nSigTofPrFromLambda; + if (signXic == +1) { + pPiFromLambda = trackNegLambdaDaughter.p(); + nSigTpcPiFromLambda = trackNegLambdaDaughter.tpcNSigmaPi(); + nSigTofPiFromLambda = trackNegLambdaDaughter.tofNSigmaPi(); + pPrFromLambda = trackPosLambdaDaughter.p(); + nSigTpcPrFromLambda = trackPosLambdaDaughter.tpcNSigmaPr(); + nSigTofPrFromLambda = trackPosLambdaDaughter.tofNSigmaPr(); + } else { + pPiFromLambda = trackPosLambdaDaughter.p(); + nSigTpcPiFromLambda = trackPosLambdaDaughter.tpcNSigmaPi(); + nSigTofPiFromLambda = trackPosLambdaDaughter.tofNSigmaPi(); + pPrFromLambda = trackNegLambdaDaughter.p(); + nSigTpcPrFromLambda = trackNegLambdaDaughter.tpcNSigmaPr(); + nSigTofPrFromLambda = trackNegLambdaDaughter.tofNSigmaPr(); + } + + //-------------------------------fill histograms-------------------------------------------- + if (fillHistograms) { + // invariant mass + registry.fill(HIST("hMass3"), massXiPiPi); + // covariance matrix elements of PV + registry.fill(HIST("hCovPVXX"), covMatrixPV[0]); + registry.fill(HIST("hCovPVYY"), covMatrixPV[2]); + registry.fill(HIST("hCovPVXZ"), covMatrixPV[3]); + registry.fill(HIST("hCovPVZZ"), covMatrixPV[5]); + // covariance matrix elements of SV + registry.fill(HIST("hCovSVXX"), covMatrixXicPlus[0]); + registry.fill(HIST("hCovSVYY"), covMatrixXicPlus[2]); + registry.fill(HIST("hCovSVXZ"), covMatrixXicPlus[3]); + registry.fill(HIST("hCovSVZZ"), covMatrixXicPlus[5]); + // DCAs of prongs + registry.fill(HIST("hDcaXYProngs"), kfXi.GetPt(), impactParameterXiXY); + registry.fill(HIST("hDcaXYProngs"), kfCharmBachelor0.GetPt(), impactParameterPi0XY); + registry.fill(HIST("hDcaXYProngs"), kfCharmBachelor1.GetPt(), impactParameterPi1XY); + } + + //------------------------------fill candidate table rows-------------------------------------- + rowCandidateBase(collision.globalIndex(), + kfPv.GetX(), kfPv.GetY(), kfPv.GetZ(), + std::sqrt(covMatrixPV[0]), std::sqrt(covMatrixPV[2]), std::sqrt(covMatrixPV[5]), + /*3-prong specific columns*/ + rowTrackIndexXicPlus.cascadeId(), rowTrackIndexXicPlus.prong0Id(), rowTrackIndexXicPlus.prong1Id(), + casc.bachelorId(), casc.posTrackId(), casc.negTrackId(), + secondaryVertex[0], secondaryVertex[1], secondaryVertex[2], + kfXicPlus.GetErrX(), kfXicPlus.GetErrY(), kfXicPlus.GetErrZ(), + errorKfDecayLength, errorKfDecayLengthXY, + chi2GeoXicPlus, massXiPiPi, signXic, + kfXi.GetPx(), kfXi.GetPy(), kfXi.GetPz(), + kfCharmBachelor0.GetPx(), kfCharmBachelor0.GetPy(), kfCharmBachelor0.GetPz(), + kfCharmBachelor1.GetPx(), kfCharmBachelor1.GetPy(), kfCharmBachelor1.GetPz(), + impactParameterXiXY, impactParameterPi0XY, impactParameterPi1XY, + errImpactParameterXiXY, errImpactParameterPi0XY, errImpactParameterPi1XY, + /*cascade specific columns*/ + trackPionFromXi.p(), pPiFromLambda, pPrFromLambda, + cpaXi, cpaXYXi, cpaLambda, cpaXYLambda, cpaLambdaToXi, cpaXYLambdaToXi, + massXi, casc.mLambda(), massXiPi0, massXiPi1, + /*DCA information*/ + casc.dcacascdaughters(), casc.dcaV0daughters(), casc.dcapostopv(), casc.dcanegtopv(), casc.dcabachtopv(), + casc.dcaXYCascToPV(), casc.dcaZCascToPV(), + /*PID information*/ + nSigTpcPiFromXicPlus0, nSigTpcPiFromXicPlus1, nSigTpcBachelorPi, nSigTpcPiFromLambda, nSigTpcPrFromLambda, + nSigTofPiFromXicPlus0, nSigTofPiFromXicPlus1, nSigTofBachelorPi, nSigTofPiFromLambda, nSigTofPrFromLambda); + rowCandidateKF(casc.kfCascadeChi2(), casc.kfV0Chi2(), + kfDecayLength, kfDecayLengthNormalised, kfDecayLengthXY, kfDecayLengthXYNormalised, + chi2topoXicPlusToPVBeforeConstraint, chi2topoXicPlusToPV, chi2topoXiToXicPlusBeforeConstraint, chi2topoXiToXicPlus, + dcaXYPi0Pi1, dcaXYPi0Xi, dcaXYPi1Xi, + dcaPi0Pi1, dcaPi0Xi, dcaPi1Xi); + } // loop over track triplets + } + PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processXicplusWithKFParticle, "Run candidate creator with KFParticle using derived data from HfTrackIndexSkimCreatorLfCascades.", false); +}; // struct + +/// Performs MC matching. +struct HfCandidateCreatorXicToXiPiPiExpressions { + Spawns rowCandidateXic; + Produces rowMcMatchRec; + Produces rowMcMatchGen; + + void init(InitContext const&) {} + + void processMc(aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles) + { + rowCandidateXic->bindExternalIndices(&tracks); + + int indexRec = -1; + int indexRecXicPlus = -1; + int8_t sign = 0; + int8_t flag = 0; + int8_t origin = 0; + int8_t debug = 0; + // for resonance matching: + std::vector arrDaughIndex; + std::array arrPDGDaugh; + std::array arrXiResonance = {3324, kPiPlus}; // 3324: Ξ(1530) + + // Match reconstructed candidates. + for (const auto& candidate : *rowCandidateXic) { + flag = 0; + sign = 0; + origin = RecoDecay::OriginType::None; + debug = 0; + arrDaughIndex.clear(); + + auto arrayDaughters = std::array{candidate.pi0_as(), // pi <- Xic + candidate.pi1_as(), // pi <- Xic + candidate.bachelor_as(), // pi <- cascade + candidate.posTrack_as(), // p <- lambda + candidate.negTrack_as()}; // pi <- lambda + auto arrayDaughtersCasc = std::array{candidate.bachelor_as(), + candidate.posTrack_as(), + candidate.negTrack_as()}; + auto arrayDaughtersV0 = std::array{candidate.posTrack_as(), + candidate.negTrack_as()}; + + // Xic → pi pi pi pi p + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kXiCPlus, std::array{+kPiPlus, +kPiPlus, +kPiMinus, +kProton, +kPiMinus}, true, &sign, 4); + indexRecXicPlus = indexRec; + if (indexRec == -1) { + debug = 1; + } + if (indexRec > -1) { + // Xi- → pi pi p + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, +kXiMinus, std::array{+kPiMinus, +kProton, +kPiMinus}, true, &sign, 2); + if (indexRec == -1) { + debug = 2; + } + if (indexRec > -1) { + // Lambda → p pi + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &sign, 1); + if (indexRec == -1) { + debug = 3; + } + if (indexRec > -1) { + RecoDecay::getDaughters(mcParticles.rawIteratorAt(indexRecXicPlus), &arrDaughIndex, std::array{0}, 1); + if (arrDaughIndex.size() == 2) { + for (auto iProng = 0u; iProng < arrDaughIndex.size(); ++iProng) { + auto daughI = mcParticles.rawIteratorAt(arrDaughIndex[iProng]); + arrPDGDaugh[iProng] = std::abs(daughI.pdgCode()); + } + if ((arrPDGDaugh[0] == arrXiResonance[0] && arrPDGDaugh[1] == arrXiResonance[1]) || (arrPDGDaugh[0] == arrXiResonance[1] && arrPDGDaugh[1] == arrXiResonance[0])) { + flag = sign * (1 << aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiResPiToXiPiPi); + } else { + debug = 4; + } + } else { + flag = sign * (1 << aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiPiPi); + } + } + } + } + + // Check whether the charm baryon is non-prompt (from a b quark). + if (flag != 0) { + auto particle = mcParticles.rawIteratorAt(indexRecXicPlus); + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false); + } + + rowMcMatchRec(flag, debug, origin); + } // close loop over candidates + + // Match generated particles. + for (const auto& particle : mcParticles) { + flag = 0; + sign = 0; + debug = 0; + origin = RecoDecay::OriginType::None; + arrDaughIndex.clear(); + + // Xic → Xi pi pi + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kXiCPlus, std::array{+kXiMinus, +kPiPlus, +kPiPlus}, true, &sign, 2)) { + debug = 1; + // Xi- -> Lambda pi + auto cascMC = mcParticles.rawIteratorAt(particle.daughtersIds().front()); + // Find Xi- from Xi(1530) -> Xi pi in case of resonant decay + RecoDecay::getDaughters(particle, &arrDaughIndex, std::array{0}, 1); + if (arrDaughIndex.size() == 2) { + auto cascStarMC = mcParticles.rawIteratorAt(particle.daughtersIds().front()); + if (RecoDecay::isMatchedMCGen(mcParticles, cascStarMC, +3324, std::array{+kXiMinus, +kPiPlus}, true)) { + cascMC = mcParticles.rawIteratorAt(cascStarMC.daughtersIds().front()); + } + } + if (RecoDecay::isMatchedMCGen(mcParticles, cascMC, +kXiMinus, std::array{+kLambda0, +kPiMinus}, true)) { + debug = 2; + // Lambda -> p pi + auto v0MC = mcParticles.rawIteratorAt(cascMC.daughtersIds().front()); + if (RecoDecay::isMatchedMCGen(mcParticles, v0MC, +kLambda0, std::array{+kProton, +kPiMinus}, true)) { + debug = 3; + if (arrDaughIndex.size() == 2) { + for (auto iProng = 0u; iProng < arrDaughIndex.size(); ++iProng) { + auto daughI = mcParticles.rawIteratorAt(arrDaughIndex[iProng]); + arrPDGDaugh[iProng] = std::abs(daughI.pdgCode()); + } + if ((arrPDGDaugh[0] == arrXiResonance[0] && arrPDGDaugh[1] == arrXiResonance[1]) || (arrPDGDaugh[0] == arrXiResonance[1] && arrPDGDaugh[1] == arrXiResonance[0])) { + flag = sign * (1 << aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiResPiToXiPiPi); + } else { + debug = 4; + } + } else { + flag = sign * (1 << aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiPiPi); + } + } + } + } + + // Check whether the charm baryon is non-prompt (from a b quark). + if (flag != 0) { + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false); + } + + rowMcMatchGen(flag, debug, origin); + } // close loop over generated particles + } // close process + PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPiExpressions, processMc, "Process MC", false); +}; // close struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/candidateSelectorB0ToDPi.cxx b/PWGHF/TableProducer/candidateSelectorB0ToDPi.cxx index c256265b341..9387fb6261b 100644 --- a/PWGHF/TableProducer/candidateSelectorB0ToDPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorB0ToDPi.cxx @@ -14,6 +14,9 @@ /// /// \author Alexandre Bigot , IPHC Strasbourg +#include +#include + #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "Framework/RunningWorkflowInfo.h" @@ -50,7 +53,7 @@ struct HfCandidateSelectorB0ToDPi { Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 5., "Nsigma cut on TOF combined with TPC"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_b0_to_d_pi::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_b0_to_d_pi::cuts[0], hf_cuts_b0_to_d_pi::nBinsPt, hf_cuts_b0_to_d_pi::nCutVars, hf_cuts_b0_to_d_pi::labelsPt, hf_cuts_b0_to_d_pi::labelsCutVar}, "B0 candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_b0_to_d_pi::Cuts[0], hf_cuts_b0_to_d_pi::NBinsPt, hf_cuts_b0_to_d_pi::NCutVars, hf_cuts_b0_to_d_pi::labelsPt, hf_cuts_b0_to_d_pi::labelsCutVar}, "B0 candidate selection per pT bin"}; // QA switch Configurable activateQA{"activateQA", false, "Flag to enable QA histogram"}; // check if selectionFlagD (defined in candidateCreatorB0.cxx) and usePid configurables are in sync @@ -118,15 +121,6 @@ struct HfCandidateSelectorB0ToDPi { int statusB0ToDPi = 0; auto ptCandB0 = hfCandB0.pt(); - // check if flagged as B0 → D π - if (!TESTBIT(hfCandB0.hfflag(), hf_cand_b0::DecayType::B0ToDPi)) { - hfSelB0ToDPiCandidate(statusB0ToDPi); - if (activateQA) { - registry.fill(HIST("hSelections"), 1, ptCandB0); - } - // LOGF(info, "B0 candidate selection failed at hfflag check"); - continue; - } SETBIT(statusB0ToDPi, SelectionStep::RecoSkims); // RecoSkims = 0 --> statusB0ToDPi = 1 if (activateQA) { registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoSkims, ptCandB0); diff --git a/PWGHF/TableProducer/candidateSelectorBplusToD0Pi.cxx b/PWGHF/TableProducer/candidateSelectorBplusToD0Pi.cxx index a5ca2557962..fb520f85b21 100644 --- a/PWGHF/TableProducer/candidateSelectorBplusToD0Pi.cxx +++ b/PWGHF/TableProducer/candidateSelectorBplusToD0Pi.cxx @@ -10,10 +10,15 @@ // or submit itself to any jurisdiction. /// \file candidateSelectorBplusToD0Pi.cxx -/// \brief B± → D0bar(D0) π± candidate selector +/// \brief B ± → D0bar (D0) π± candidate selector /// -/// \author Antonio Palasciano , Università degli Studi di Bari & INFN, Sezione di Bari +/// \author Antonio Palasciano , Università degli Studi di Bari /// \author Deepa Thomas , UT Austin +/// \author Nima Zardoshti , CERN + +#include +#include +#include #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -22,6 +27,7 @@ #include "Common/Core/TrackSelectorPID.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/HfMlResponseBplusToD0Pi.h" #include "PWGHF/Core/SelectorCuts.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" @@ -32,41 +38,70 @@ using namespace o2::framework; using namespace o2::analysis; struct HfCandidateSelectorBplusToD0Pi { - Produces hfSelBplusToD0PiCandidate; + Produces hfSelBplusToD0PiCandidate; // table defined in CandidateSelectionTables.h + Produces hfMlBplusToD0PiCandidate; // table defined in CandidateSelectionTables.h - // Configurable ptCandMin{"ptCandMin", 0., "Lower bound of candidate pT"}; - // Configurable ptCandMax{"ptCandMax", 50., "Upper bound of candidate pT"}; + Configurable ptCandMin{"ptCandMin", 0., "Lower bound of candidate pT"}; + Configurable ptCandMax{"ptCandMax", 50., "Upper bound of candidate pT"}; // Enable PID - Configurable usePid{"usePid", true, "Bool to use or not the PID at filtering level"}; + Configurable pionPidMethod{"pionPidMethod", 1, "PID selection method for the bachelor pion (0: none, 1: TPC or TOF, 2: TPC and TOF)"}; Configurable acceptPIDNotApplicable{"acceptPIDNotApplicable", true, "Switch to accept Status::NotApplicable [(NotApplicable for one detector) and (NotApplicable or Conditional for the other)] in PID selection"}; // TPC PID - Configurable ptPidTpcMin{"ptPidTpcMin", 999, "Lower bound of track pT for TPC PID"}; - Configurable ptPidTpcMax{"ptPidTpcMax", 9999, "Upper bound of track pT for TPC PID"}; + Configurable ptPidTpcMin{"ptPidTpcMin", 0.15, "Lower bound of track pT for TPC PID"}; + Configurable ptPidTpcMax{"ptPidTpcMax", 20., "Upper bound of track pT for TPC PID"}; Configurable nSigmaTpcMax{"nSigmaTpcMax", 5., "Nsigma cut on TPC only"}; Configurable nSigmaTpcCombinedMax{"nSigmaTpcCombinedMax", 5., "Nsigma cut on TPC combined with TOF"}; // TOF PID Configurable ptPidTofMin{"ptPidTofMin", 0.15, "Lower bound of track pT for TOF PID"}; - Configurable ptPidTofMax{"ptPidTofMax", 50., "Upper bound of track pT for TOF PID"}; + Configurable ptPidTofMax{"ptPidTofMax", 20., "Upper bound of track pT for TOF PID"}; Configurable nSigmaTofMax{"nSigmaTofMax", 5., "Nsigma cut on TOF only"}; - Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 999., "Nsigma cut on TOF combined with TPC"}; + Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 5., "Nsigma cut on TOF combined with TPC"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_bplus_to_d0_pi::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_bplus_to_d0_pi::cuts[0], hf_cuts_bplus_to_d0_pi::nBinsPt, hf_cuts_bplus_to_d0_pi::nCutVars, hf_cuts_bplus_to_d0_pi::labelsPt, hf_cuts_bplus_to_d0_pi::labelsCutVar}, "B+ candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_bplus_to_d0_pi::Cuts[0], hf_cuts_bplus_to_d0_pi::NBinsPt, hf_cuts_bplus_to_d0_pi::NCutVars, hf_cuts_bplus_to_d0_pi::labelsPt, hf_cuts_bplus_to_d0_pi::labelsCutVar}, "B+ candidate selection per pT bin"}; + // D0-meson ML cuts + Configurable> binsPtDmesMl{"binsPtDmesMl", std::vector{hf_cuts_ml::vecBinsPt}, "D0-meson pT bin limits for ML cuts"}; + Configurable> cutsDmesMl{"cutsDmesMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsDmesCutScore}, "D0-meson ML cuts per pT bin"}; // QA switch Configurable activateQA{"activateQA", false, "Flag to enable QA histogram"}; + // B+ ML inference + Configurable applyBplusMl{"applyBplusMl", false, "Flag to apply ML selections"}; + Configurable> binsPtBpMl{"binsPtBpMl", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; + Configurable> cutDirBpMl{"cutDirBpMl", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; + Configurable> cutsBpMl{"cutsBpMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable nClassesBpMl{"nClassesBpMl", static_cast(hf_cuts_ml::NCutScores), "Number of classes in ML model"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; + // CCDB configuration + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"path_ccdb/BDT_BPLUS/"}, "Paths of models on CCDB"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_BPLUSToD0Pi.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + + o2::analysis::HfMlResponseBplusToD0Pi hfMlResponse; + float outputMlNotPreselected = -1.; + std::vector outputMl = {}; + o2::ccdb::CcdbApi ccdbApi; - // check if selectionFlagD (defined in candidateCreatorBplus.cxx) and usePid configurables are in sync - bool selectionFlagDAndUsePidInSync = true; - TrackSelectorPi selectorPion; HfHelper hfHelper; + TrackSelectorPi selectorPion; - using TracksPidWithSel = soa::Join; + using TracksPion = soa::Join; HistogramRegistry registry{"registry"}; - void init(InitContext& initContext) + void init(InitContext const&) { - if (usePid) { + std::array doprocess{doprocessSelection, doprocessSelectionWithDmesMl}; + if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { + LOGP(fatal, "Only one process function for data should be enabled at a time."); + } + + if (pionPidMethod < 0 || pionPidMethod > 2) { + LOGP(fatal, "Invalid PID option in configurable, please set 0 (no PID), 1 (TPC or TOF), or 2 (TPC and TOF)"); + } + + if (pionPidMethod != 0) { selectorPion.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); selectorPion.setRangeNSigmaTpc(-nSigmaTpcMax, nSigmaTpcMax); selectorPion.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedMax, nSigmaTpcCombinedMax); @@ -82,6 +117,7 @@ struct HfCandidateSelectorBplusToD0Pi { labels[1 + SelectionStep::RecoSkims] = "Skims selection"; labels[1 + SelectionStep::RecoTopol] = "Skims & Topological selections"; labels[1 + SelectionStep::RecoPID] = "Skims & Topological & PID selections"; + labels[1 + aod::SelectionStep::RecoMl] = "ML selection"; static const AxisSpec axisSelections = {kNBinsSelections, 0.5, kNBinsSelections + 0.5, ""}; registry.add("hSelections", "Selections;;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisSelections, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); for (int iBin = 0; iBin < kNBinsSelections; ++iBin) { @@ -89,110 +125,140 @@ struct HfCandidateSelectorBplusToD0Pi { } } - int selectionFlagD0 = -1; - int selectionFlagD0bar = -1; - auto& workflows = initContext.services().get(); - for (const DeviceSpec& device : workflows.devices) { - if (device.name.compare("hf-candidate-creator-bplus") == 0) { - for (const auto& option : device.options) { - if (option.name.compare("selectionFlagD0") == 0) { - selectionFlagD0 = option.defaultValue.get(); - LOGF(info, "selectionFlagD0 = %d", selectionFlagD0); - } - if (option.name.compare("selectionFlagD0bar") == 0) { - selectionFlagD0bar = option.defaultValue.get(); - LOGF(info, "selectionFlagD0bar = %d", selectionFlagD0bar); - } - } + if (applyBplusMl) { + hfMlResponse.configure(binsPtBpMl, cutsBpMl, cutDirBpMl, nClassesBpMl); + if (loadModelsFromCCDB) { + ccdbApi.init(ccdbUrl); + hfMlResponse.setModelPathsCCDB(onnxFileNames, ccdbApi, modelPathsCCDB, timestampCCDB); + } else { + hfMlResponse.setModelPathsLocal(onnxFileNames); } - } - if ((usePid && !selectionFlagD0) || (usePid && !selectionFlagD0bar)) { - selectionFlagDAndUsePidInSync = false; - LOG(warning) << "PID selections required on B+ daughters (usePid=true) but no PID selections on D candidates were required a priori."; - } - if ((!usePid && selectionFlagD0) || (!usePid && selectionFlagD0bar)) { - selectionFlagDAndUsePidInSync = false; - LOG(warning) << "No PID selections required on Bp daughters (usePid=false) but PID selections on D candidates were required a priori."; + hfMlResponse.cacheInputFeaturesIndices(namesInputFeatures); + hfMlResponse.init(); } } - /// Apply PID selection - /// \param pidTrackPi is the PID status of trackPi (prong1 of B+ candidate) - /// \return true if prong1 of B+ candidate passes all selections - template - bool selectionPID(const T& pidTrackPi) + /// Main function to perform B+ candidate creation + /// \param withDmesMl is the flag to use the table with ML scores for the D- daughter (only possible if present in the derived data) + /// \param hfCandsBp B+ candidates + /// \param pionTracks pion tracks + template + void runSelection(Cands const& hfCandsBp, + CandsDmes const& /*hfCandsD0*/, + TracksPion const& /*pionTracks*/) { - if (!acceptPIDNotApplicable && pidTrackPi != TrackSelectorPID::Accepted) { - return false; - } - if (acceptPIDNotApplicable && pidTrackPi == TrackSelectorPID::Rejected) { - return false; - } - - return true; - } - - void process(aod::HfCandBplus const& hfCandBs, - soa::Join const&, - TracksPidWithSel const&) - { - - for (const auto& hfCandB : hfCandBs) { // looping over Bplus candidates + for (const auto& hfCandBp : hfCandsBp) { int statusBplus = 0; - auto ptCandB = hfCandB.pt(); + auto ptCandBplus = hfCandBp.pt(); - // check if flagged as B+ --> D0bar Pi - if (!(hfCandB.hfflag() & 1 << hf_cand_bplus::DecayType::BplusToD0Pi)) { - hfSelBplusToD0PiCandidate(statusBplus); - // LOGF(debug, "B+ candidate selection failed at hfflag check"); - continue; - } SETBIT(statusBplus, SelectionStep::RecoSkims); // RecoSkims = 0 --> statusBplus = 1 if (activateQA) { - registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoSkims, ptCandB); + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoSkims, ptCandBplus); } - // D0 is always index0 and pi is index1 by default - auto trackPi = hfCandB.prong1_as(); - // topological cuts - if (!hfHelper.selectionBplusToD0PiTopol(hfCandB, cuts, binsPt)) { + if (!hfHelper.selectionBplusToD0PiTopol(hfCandBp, cuts, binsPt)) { hfSelBplusToD0PiCandidate(statusBplus); - // LOGF(debug, "B+ candidate selection failed at topology selection"); + if (applyBplusMl) { + hfMlBplusToD0PiCandidate(outputMlNotPreselected); + } + // LOGF(info, "B+ candidate selection failed at topology selection"); continue; } + + auto trackPi = hfCandBp.template prong1_as(); + auto hfCandD = hfCandBp.template prong0_as(); + + if constexpr (withDmesMl) { + std::vector mlScoresD; + if (trackPi.sign() < 0) { + std::copy(hfCandD.mlProbD0().begin(), hfCandD.mlProbD0().end(), std::back_inserter(mlScoresD)); + } else { + std::copy(hfCandD.mlProbD0bar().begin(), hfCandD.mlProbD0bar().end(), std::back_inserter(mlScoresD)); + } + + if (!hfHelper.selectionDmesMlScoresForB(hfCandD, cutsDmesMl, binsPtDmesMl, mlScoresD)) { + hfSelBplusToD0PiCandidate(statusBplus); + if (applyBplusMl) { + hfMlBplusToD0PiCandidate(outputMlNotPreselected); + } + // LOGF(info, "B+ candidate selection failed at D0-meson ML selection"); + continue; + } + } + SETBIT(statusBplus, SelectionStep::RecoTopol); // RecoTopol = 1 --> statusBplus = 3 if (activateQA) { - registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoTopol, ptCandB); + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoTopol, ptCandBplus); } - // checking if selectionFlagD0(D0bar) and usePid are in sync - if (!selectionFlagDAndUsePidInSync) { - hfSelBplusToD0PiCandidate(statusBplus); - continue; - } // track-level PID selection - if (usePid) { - int pidTrackPi = selectorPion.statusTpcAndTof(trackPi); - if (!selectionPID(pidTrackPi)) { // FIXME use helper function + if (pionPidMethod) { + int pidTrackPi{TrackSelectorPID::Status::NotApplicable}; + if (pionPidMethod == 1) { + pidTrackPi = selectorPion.statusTpcOrTof(trackPi); + } else { + pidTrackPi = selectorPion.statusTpcAndTof(trackPi); + } + if (!hfHelper.selectionBplusToD0PiPid(pidTrackPi, acceptPIDNotApplicable.value)) { + // LOGF(info, "B+ candidate selection failed at PID selection"); hfSelBplusToD0PiCandidate(statusBplus); + if (applyBplusMl) { + hfMlBplusToD0PiCandidate(outputMlNotPreselected); + } continue; } SETBIT(statusBplus, SelectionStep::RecoPID); // RecoPID = 2 --> statusBplus = 7 if (activateQA) { - registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoPID, ptCandB); + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoPID, ptCandBplus); + } + } + if (applyBplusMl) { + // B+ ML selections + int pdgCode = o2::constants::physics::kD0; + if (trackPi.sign() > 0) { + pdgCode = -1 * pdgCode; + } + std::vector inputFeatures = hfMlResponse.getInputFeatures(hfCandBp, hfCandD, pdgCode, trackPi); + bool isSelectedMl = hfMlResponse.isSelectedMl(inputFeatures, ptCandBplus, outputMl); + hfMlBplusToD0PiCandidate(outputMl[1]); // storing ML score for signal class + + if (!isSelectedMl) { + hfSelBplusToD0PiCandidate(statusBplus); + continue; + } + SETBIT(statusBplus, SelectionStep::RecoMl); // RecoML = 3 --> statusBplus = 15 if pionPidMethod, 11 otherwise + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoMl, ptCandBplus); } } hfSelBplusToD0PiCandidate(statusBplus); - // LOGF(info, "Successful B+ candidate selection"); + // LOGF(info, "B+ candidate selection passed all selections"); } } + + void processSelection(HfCandBplus const& hfCandsBp, + aod::HfCand2ProngWPid const& hfCandsD0, + TracksPion const& pionTracks) + { + runSelection(hfCandsBp, hfCandsD0, pionTracks); + } // processSelection + + PROCESS_SWITCH(HfCandidateSelectorBplusToD0Pi, processSelection, "Process selection without ML scores of D mesons", true); + + void processSelectionWithDmesMl(HfCandBplus const& hfCandsBp, + soa::Join const& hfCandsD0, + TracksPion const& pionTracks) + { + runSelection(hfCandsBp, hfCandsD0, pionTracks); + } // processSelectionWithDmesMl + + PROCESS_SWITCH(HfCandidateSelectorBplusToD0Pi, processSelectionWithDmesMl, "Process selection with ML scores of D mesons", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGHF/TableProducer/candidateSelectorBsToDsPi.cxx b/PWGHF/TableProducer/candidateSelectorBsToDsPi.cxx index 5c0c230c11f..cfd8f418e0e 100644 --- a/PWGHF/TableProducer/candidateSelectorBsToDsPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorBsToDsPi.cxx @@ -15,6 +15,9 @@ /// /// \author Phil Stahlhut +#include +#include + #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "Framework/RunningWorkflowInfo.h" @@ -51,19 +54,19 @@ struct HfCandidateSelectorBsToDsPi { Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 5., "Nsigma cut on TOF combined with TPC"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_bs_to_ds_pi::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_bs_to_ds_pi::cuts[0], hf_cuts_bs_to_ds_pi::nBinsPt, hf_cuts_bs_to_ds_pi::nCutVars, hf_cuts_bs_to_ds_pi::labelsPt, hf_cuts_bs_to_ds_pi::labelsCutVar}, "Bs candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_bs_to_ds_pi::Cuts[0], hf_cuts_bs_to_ds_pi::NBinsPt, hf_cuts_bs_to_ds_pi::NCutVars, hf_cuts_bs_to_ds_pi::labelsPt, hf_cuts_bs_to_ds_pi::labelsCutVar}, "Bs candidate selection per pT bin"}; // QA switch Configurable activateQA{"activateQA", false, "Flag to enable QA histogram"}; // ML inference Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; Configurable> binsPtMl{"binsPtMl", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; Configurable> cutDirMl{"cutDirMl", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; - Configurable> cutsMl{"cutsMl", {hf_cuts_ml::cuts[0], hf_cuts_ml::nBinsPt, hf_cuts_ml::nCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; - Configurable nClassesMl{"nClassesMl", (int8_t)hf_cuts_ml::nCutScores, "Number of classes in ML model"}; + Configurable> cutsMl{"cutsMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable nClassesMl{"nClassesMl", static_cast(hf_cuts_ml::NCutScores), "Number of classes in ML model"}; // CCDB configuration Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"EventFiltering/PWGHF/BDTBs"}, "Paths of models on CCDB"}; - Configurable> onnxFileNames{"onnxFilesCCDB", std::vector{"ModelHandler_onnx_BsToDsPi.onnx"}, "ONNX file names on CCDB for each pT bin (if not from CCDB full path)"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_BsToDsPi.onnx"}, "ONNX file names on CCDB for each pT bin (if not from CCDB full path)"}; Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; @@ -116,7 +119,6 @@ struct HfCandidateSelectorBsToDsPi { hfMlResponse.setModelPathsLocal(onnxFileNames); } hfMlResponse.init(); - outputMl.assign(((std::vector)cutDirMl).size(), -1.f); // dummy value for ML output } int selectionFlagDs = -1; @@ -147,19 +149,9 @@ struct HfCandidateSelectorBsToDsPi { { for (const auto& hfCandBs : hfCandsBs) { int statusBsToDsPi = 0; + outputMl.clear(); auto ptCandBs = hfCandBs.pt(); - // check if flagged as Bs → Ds π - if (!TESTBIT(hfCandBs.hfflag(), hf_cand_bs::DecayType::BsToDsPi)) { - hfSelBsToDsPiCandidate(statusBsToDsPi); - if (applyMl) { - hfMlBsToDsPiCandidate(outputMl); - } - if (activateQA) { - registry.fill(HIST("hSelections"), 1, ptCandBs); - } - continue; - } SETBIT(statusBsToDsPi, SelectionStep::RecoSkims); // RecoSkims = 0 --> statusBsToDsPi = 1 if (activateQA) { registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoSkims, ptCandBs); diff --git a/PWGHF/TableProducer/candidateSelectorD0.cxx b/PWGHF/TableProducer/candidateSelectorD0.cxx index 3204a22b1e5..eda8561c6b3 100644 --- a/PWGHF/TableProducer/candidateSelectorD0.cxx +++ b/PWGHF/TableProducer/candidateSelectorD0.cxx @@ -15,6 +15,9 @@ /// \author Nima Zardoshti , CERN /// \author Vít Kučera , CERN +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -26,6 +29,7 @@ #include "PWGHF/Core/HfMlResponseD0ToKPi.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" using namespace o2; using namespace o2::analysis; @@ -38,11 +42,13 @@ struct HfCandidateSelectorD0 { Configurable ptCandMin{"ptCandMin", 0., "Lower bound of candidate pT"}; Configurable ptCandMax{"ptCandMax", 50., "Upper bound of candidate pT"}; + Configurable usePid{"usePid", true, "Use PID selection"}; // TPC PID Configurable ptPidTpcMin{"ptPidTpcMin", 0.15, "Lower bound of track pT for TPC PID"}; Configurable ptPidTpcMax{"ptPidTpcMax", 5., "Upper bound of track pT for TPC PID"}; Configurable nSigmaTpcMax{"nSigmaTpcMax", 3., "Nsigma cut on TPC only"}; Configurable nSigmaTpcCombinedMax{"nSigmaTpcCombinedMax", 5., "Nsigma cut on TPC combined with TOF"}; + Configurable usePidTpcOnly{"usePidTpcOnly", false, "Only use TPC PID"}; // TOF PID Configurable ptPidTofMin{"ptPidTofMin", 0.15, "Lower bound of track pT for TOF PID"}; Configurable ptPidTofMax{"ptPidTofMax", 5., "Upper bound of track pT for TOF PID"}; @@ -50,18 +56,26 @@ struct HfCandidateSelectorD0 { Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 5., "Nsigma cut on TOF combined with TPC"}; // AND logic for TOF+TPC PID (as in Run2) Configurable usePidTpcAndTof{"usePidTpcAndTof", false, "Use AND logic for TPC and TOF PID"}; + // ITS quality track cuts + Configurable itsNClustersFoundMin{"itsNClustersFoundMin", 0, "Minimum number of found ITS clusters"}; + Configurable itsChi2PerClusterMax{"itsChi2PerClusterMax", 1e10f, "Maximum its fit chi2 per ITS cluster"}; + // TPC quality track cuts + Configurable tpcNClustersFoundMin{"tpcNClustersFoundMin", 0, "Minimum number of found TPC clusters"}; + Configurable tpcNCrossedRowsMin{"tpcNCrossedRowsMin", 0, "Minimum number of crossed rows in TPC"}; + Configurable tpcNCrossedRowsOverFindableClustersMin{"tpcNCrossedRowsOverFindableClustersMin", 0., "Minimum ratio crossed rows / findable clusters"}; + Configurable tpcChi2PerClusterMax{"tpcChi2PerClusterMax", 1e10f, "Maximum TPC fit chi2 per TPC cluster"}; // selecting only background candidates Configurable keepOnlySidebandCandidates{"keepOnlySidebandCandidates", false, "Select only sideband candidates, for studying background cut variable distributions"}; Configurable distanceFromD0MassForSidebands{"distanceFromD0MassForSidebands", 0.15, "Minimum distance from nominal D0 mass value for sideband region"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_d0_to_pi_k::cuts[0], hf_cuts_d0_to_pi_k::nBinsPt, hf_cuts_d0_to_pi_k::nCutVars, hf_cuts_d0_to_pi_k::labelsPt, hf_cuts_d0_to_pi_k::labelsCutVar}, "D0 candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_d0_to_pi_k::Cuts[0], hf_cuts_d0_to_pi_k::NBinsPt, hf_cuts_d0_to_pi_k::NCutVars, hf_cuts_d0_to_pi_k::labelsPt, hf_cuts_d0_to_pi_k::labelsCutVar}, "D0 candidate selection per pT bin"}; // ML inference Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; Configurable> binsPtMl{"binsPtMl", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; Configurable> cutDirMl{"cutDirMl", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; - Configurable> cutsMl{"cutsMl", {hf_cuts_ml::cuts[0], hf_cuts_ml::nBinsPt, hf_cuts_ml::nCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; - Configurable nClassesMl{"nClassesMl", (int8_t)hf_cuts_ml::nCutScores, "Number of classes in ML model"}; + Configurable> cutsMl{"cutsMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable nClassesMl{"nClassesMl", static_cast(hf_cuts_ml::NCutScores), "Number of classes in ML model"}; Configurable enableDebugMl{"enableDebugMl", false, "Flag to enable histograms to monitor BDT application"}; Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; // CCDB configuration @@ -70,6 +84,8 @@ struct HfCandidateSelectorD0 { Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_D0ToKPi.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + // Mass Cut for trigger analysis + Configurable useTriggerMassCut{"useTriggerMassCut", false, "Flag to enable parametrize pT differential mass cut for triggered data"}; o2::analysis::HfMlResponseD0ToKPi hfMlResponse; std::vector outputMlD0 = {}; @@ -78,6 +94,7 @@ struct HfCandidateSelectorD0 { TrackSelectorPi selectorPion; TrackSelectorKa selectorKaon; HfHelper hfHelper; + HfTrigger2ProngCuts hfTriggerCuts; using TracksSel = soa::Join; @@ -122,6 +139,23 @@ struct HfCandidateSelectorD0 { } } + /// Single track quality cuts + /// \param track is track + /// \return true if track passes all cuts + template + bool isSelectedCandidateProng(const T& trackPos, const T& trackNeg) + { + if (!isSelectedTrackTpcQuality(trackPos, tpcNClustersFoundMin.value, tpcNCrossedRowsMin.value, tpcNCrossedRowsOverFindableClustersMin.value, tpcChi2PerClusterMax.value) || + !isSelectedTrackTpcQuality(trackNeg, tpcNClustersFoundMin.value, tpcNCrossedRowsMin.value, tpcNCrossedRowsOverFindableClustersMin.value, tpcChi2PerClusterMax.value)) { + return false; + } + if (!isSelectedTrackItsQuality(trackPos, itsNClustersFoundMin.value, itsChi2PerClusterMax.value) || + !isSelectedTrackItsQuality(trackNeg, itsNClustersFoundMin.value, itsChi2PerClusterMax.value)) { + return false; + } + return true; + } + /// Conjugate-independent topological cuts /// \param reconstructionType is the reconstruction type (DCAFitterN or KFParticle) /// \param candidate is candidate @@ -156,7 +190,9 @@ struct HfCandidateSelectorD0 { return false; } // candidate DCA - // if (candidate.chi2PCA() > cuts[pTBin][1]) return false; + if (std::abs(candidate.impactParameterXY()) > cuts->get(pTBin, "DCA")) { + return false; + } // candidate topological chi2 over ndf when using KFParticle, need to add this selection to the SelectorCuts.h // if constexpr (reconstructionType == aod::hf_cand::VertexerType::KfParticle) { @@ -207,10 +243,16 @@ struct HfCandidateSelectorD0 { if (std::abs(massD0 - o2::constants::physics::MassD0) > cuts->get(pTBin, "m")) { return false; } + if (useTriggerMassCut && !isCandidateInMassRange(massD0, o2::constants::physics::MassD0, candidate.pt(), hfTriggerCuts)) { + return false; + } } else { if (std::abs(massD0bar - o2::constants::physics::MassD0) > cuts->get(pTBin, "m")) { return false; } + if (useTriggerMassCut && !isCandidateInMassRange(massD0bar, o2::constants::physics::MassD0, candidate.pt(), hfTriggerCuts)) { + return false; + } } // cut on daughter pT @@ -280,6 +322,15 @@ struct HfCandidateSelectorD0 { auto trackPos = candidate.template prong0_as(); // positive daughter auto trackNeg = candidate.template prong1_as(); // negative daughter + // implement track quality selection for D0 daughters + if (!isSelectedCandidateProng(trackPos, trackNeg)) { + hfSelD0Candidate(statusD0, statusD0bar, statusHFFlag, statusTopol, statusCand, statusPID); + if (applyMl) { + hfMlD0Candidate(outputMlD0, outputMlD0bar); + } + continue; + } + // conjugate-independent topological selection if (!selectionTopol(candidate)) { hfSelD0Candidate(statusD0, statusD0bar, statusHFFlag, statusTopol, statusCand, statusPID); @@ -307,60 +358,86 @@ struct HfCandidateSelectorD0 { } statusCand = 1; - // track-level PID selection - int pidTrackPosKaon = -1; - int pidTrackPosPion = -1; - int pidTrackNegKaon = -1; - int pidTrackNegPion = -1; - - if (usePidTpcAndTof) { - pidTrackPosKaon = selectorKaon.statusTpcAndTof(trackPos); - pidTrackPosPion = selectorPion.statusTpcAndTof(trackPos); - pidTrackNegKaon = selectorKaon.statusTpcAndTof(trackNeg); - pidTrackNegPion = selectorPion.statusTpcAndTof(trackNeg); - } else { - pidTrackPosKaon = selectorKaon.statusTpcOrTof(trackPos); - pidTrackPosPion = selectorPion.statusTpcOrTof(trackPos); - pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg); - pidTrackNegPion = selectorPion.statusTpcOrTof(trackNeg); - } + if (usePid) { + // track-level PID selection + int pidTrackPosKaon = -1; + int pidTrackPosPion = -1; + int pidTrackNegKaon = -1; + int pidTrackNegPion = -1; + + if (usePidTpcOnly) { + /// kaon TPC PID positive daughter + pidTrackPosKaon = selectorKaon.statusTpc(trackPos, candidate.nSigTpcKa0()); + /// pion TPC PID positive daughter + pidTrackPosPion = selectorPion.statusTpc(trackPos, candidate.nSigTpcPi0()); + /// kaon TPC PID negative daughter + pidTrackNegKaon = selectorKaon.statusTpc(trackNeg, candidate.nSigTpcKa1()); + /// pion TPC PID negative daughter + pidTrackNegPion = selectorPion.statusTpc(trackNeg, candidate.nSigTpcPi1()); + } else if (usePidTpcAndTof) { + /// kaon TPC, TOF PID positive daughter + pidTrackPosKaon = selectorKaon.statusTpcAndTof(trackPos, candidate.nSigTpcKa0(), candidate.nSigTofKa0()); + /// pion TPC, TOF PID positive daughter + pidTrackPosPion = selectorPion.statusTpcAndTof(trackPos, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); + /// kaon TPC, TOF PID negative daughter + pidTrackNegKaon = selectorKaon.statusTpcAndTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); + /// pion TPC, TOF PID negative daughter + pidTrackNegPion = selectorPion.statusTpcAndTof(trackNeg, candidate.nSigTpcPi1(), candidate.nSigTofPi1()); + } else { + /// kaon TPC, TOF PID positive daughter + pidTrackPosKaon = selectorKaon.statusTpcOrTof(trackPos, candidate.nSigTpcKa0(), candidate.nSigTofKa0()); + /// pion TPC, TOF PID positive daughter + pidTrackPosPion = selectorPion.statusTpcOrTof(trackPos, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); + /// kaon TPC, TOF PID negative daughter + pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); + /// pion TPC, TOF PID negative daughter + pidTrackNegPion = selectorPion.statusTpcOrTof(trackNeg, candidate.nSigTpcPi1(), candidate.nSigTofPi1()); + } - // int pidBayesTrackPos1Pion = selectorPion.statusBayes(trackPos); + // int pidBayesTrackPos1Pion = selectorPion.statusBayes(trackPos); - int pidD0 = -1; - int pidD0bar = -1; + int pidD0 = -1; + int pidD0bar = -1; - if (pidTrackPosPion == TrackSelectorPID::Accepted && - pidTrackNegKaon == TrackSelectorPID::Accepted) { - pidD0 = 1; // accept D0 - } else if (pidTrackPosPion == TrackSelectorPID::Rejected || - pidTrackNegKaon == TrackSelectorPID::Rejected) { - pidD0 = 0; // exclude D0 - } + if (pidTrackPosPion == TrackSelectorPID::Accepted && + pidTrackNegKaon == TrackSelectorPID::Accepted) { + pidD0 = 1; // accept D0 + } else if (pidTrackPosPion == TrackSelectorPID::Rejected || + pidTrackNegKaon == TrackSelectorPID::Rejected) { + pidD0 = 0; // exclude D0 + } - if (pidTrackNegPion == TrackSelectorPID::Accepted && - pidTrackPosKaon == TrackSelectorPID::Accepted) { - pidD0bar = 1; // accept D0bar - } else if (pidTrackNegPion == TrackSelectorPID::Rejected || - pidTrackPosKaon == TrackSelectorPID::Rejected) { - pidD0bar = 0; // exclude D0bar - } + if (pidTrackNegPion == TrackSelectorPID::Accepted && + pidTrackPosKaon == TrackSelectorPID::Accepted) { + pidD0bar = 1; // accept D0bar + } else if (pidTrackNegPion == TrackSelectorPID::Rejected || + pidTrackPosKaon == TrackSelectorPID::Rejected) { + pidD0bar = 0; // exclude D0bar + } - if (pidD0 == 0 && pidD0bar == 0) { - hfSelD0Candidate(statusD0, statusD0bar, statusHFFlag, statusTopol, statusCand, statusPID); - if (applyMl) { - hfMlD0Candidate(outputMlD0, outputMlD0bar); + if (pidD0 == 0 && pidD0bar == 0) { + hfSelD0Candidate(statusD0, statusD0bar, statusHFFlag, statusTopol, statusCand, statusPID); + if (applyMl) { + hfMlD0Candidate(outputMlD0, outputMlD0bar); + } + continue; } - continue; - } - if ((pidD0 == -1 || pidD0 == 1) && topolD0) { - statusD0 = 1; // identified as D0 - } - if ((pidD0bar == -1 || pidD0bar == 1) && topolD0bar) { - statusD0bar = 1; // identified as D0bar + if ((pidD0 == -1 || pidD0 == 1) && topolD0) { + statusD0 = 1; // identified as D0 + } + if ((pidD0bar == -1 || pidD0bar == 1) && topolD0bar) { + statusD0bar = 1; // identified as D0bar + } + statusPID = 1; + } else { + if (topolD0) { + statusD0 = 1; // identified as D0 + } + if (topolD0bar) { + statusD0bar = 1; // identified as D0bar + } } - statusPID = 1; if (applyMl) { // ML selections @@ -368,11 +445,11 @@ struct HfCandidateSelectorD0 { bool isSelectedMlD0bar = false; if (statusD0 > 0) { - std::vector inputFeaturesD0 = hfMlResponse.getInputFeatures(candidate, trackPos, trackNeg, o2::constants::physics::kD0); + std::vector inputFeaturesD0 = hfMlResponse.getInputFeatures(candidate, o2::constants::physics::kD0); isSelectedMlD0 = hfMlResponse.isSelectedMl(inputFeaturesD0, ptCand, outputMlD0); } if (statusD0bar > 0) { - std::vector inputFeaturesD0bar = hfMlResponse.getInputFeatures(candidate, trackPos, trackNeg, o2::constants::physics::kD0Bar); + std::vector inputFeaturesD0bar = hfMlResponse.getInputFeatures(candidate, o2::constants::physics::kD0Bar); isSelectedMlD0bar = hfMlResponse.isSelectedMl(inputFeaturesD0bar, ptCand, outputMlD0bar); } @@ -404,13 +481,13 @@ struct HfCandidateSelectorD0 { } } - void processWithDCAFitterN(aod::HfCand2Prong const& candidates, TracksSel const& tracks) + void processWithDCAFitterN(aod::HfCand2ProngWPid const& candidates, TracksSel const& tracks) { processSel(candidates, tracks); } PROCESS_SWITCH(HfCandidateSelectorD0, processWithDCAFitterN, "process candidates selection with DCAFitterN", true); - void processWithKFParticle(soa::Join const& candidates, TracksSel const& tracks) + void processWithKFParticle(soa::Join const& candidates, TracksSel const& tracks) { processSel(candidates, tracks); } diff --git a/PWGHF/TableProducer/candidateSelectorDplusToPiKPi.cxx b/PWGHF/TableProducer/candidateSelectorDplusToPiKPi.cxx index 7bd4a061e0a..776596c9df8 100644 --- a/PWGHF/TableProducer/candidateSelectorDplusToPiKPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorDplusToPiKPi.cxx @@ -15,6 +15,9 @@ /// \author Fabio Catalano , Politecnico and INFN Torino /// \author Vít Kučera , CERN +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -25,6 +28,7 @@ #include "PWGHF/Core/HfMlResponseDplusToPiKPi.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" using namespace o2; using namespace o2::analysis; @@ -53,18 +57,20 @@ struct HfCandidateSelectorDplusToPiKPi { Configurable usePidTpcAndTof{"usePidTpcAndTof", false, "Use AND logic for TPC and TOF PID"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_dplus_to_pi_k_pi::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_dplus_to_pi_k_pi::cuts[0], hf_cuts_dplus_to_pi_k_pi::nBinsPt, hf_cuts_dplus_to_pi_k_pi::nCutVars, hf_cuts_dplus_to_pi_k_pi::labelsPt, hf_cuts_dplus_to_pi_k_pi::labelsCutVar}, "Dplus candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_dplus_to_pi_k_pi::Cuts[0], hf_cuts_dplus_to_pi_k_pi::NBinsPt, hf_cuts_dplus_to_pi_k_pi::NCutVars, hf_cuts_dplus_to_pi_k_pi::labelsPt, hf_cuts_dplus_to_pi_k_pi::labelsCutVar}, "Dplus candidate selection per pT bin"}; // DCAxy selections - Configurable> cutsSingleTrack{"cutsSingleTrack", {hf_cuts_single_track::cutsTrack[0], hf_cuts_single_track::nBinsPtTrack, hf_cuts_single_track::nCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections"}; - Configurable> binsPtTrack{"binsPtTrack", std::vector{hf_cuts_single_track::vecBinsPtTrack}, "track pT bin limits for DCA XY pT-dependent cut"}; + Configurable> cutsSingleTrack{"cutsSingleTrack", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections"}; + Configurable> binsPtTrack{"binsPtTrack", std::vector{hf_cuts_single_track::vecBinsPtTrack}, "track pT bin limits for DCA pT-dependent cut"}; // QA switch Configurable activateQA{"activateQA", false, "Flag to enable QA histogram"}; + // Correlated background from Ds and D+ + Configurable storeDsDplusBkg{"storeDsDplusBkg", false, "Flag to store correlated background from misidentified product of Ds and D+ decay"}; // ML inference Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; Configurable> binsPtMl{"binsPtMl", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; Configurable> cutDirMl{"cutDirMl", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; - Configurable> cutsMl{"cutsMl", {hf_cuts_ml::cuts[0], hf_cuts_ml::nBinsPt, hf_cuts_ml::nCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; - Configurable nClassesMl{"nClassesMl", (int8_t)hf_cuts_ml::nCutScores, "Number of classes in ML model"}; + Configurable> cutsMl{"cutsMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable nClassesMl{"nClassesMl", static_cast(hf_cuts_ml::NCutScores), "Number of classes in ML model"}; Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; // CCDB configuration Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -72,14 +78,17 @@ struct HfCandidateSelectorDplusToPiKPi { Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_DPlusToKPiPi.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + // Mass Cut for trigger analysis + Configurable useTriggerMassCut{"useTriggerMassCut", false, "Flag to enable parametrize pT differential mass cut for triggered data"}; - o2::analysis::HfMlResponseDplusToPiKPi hfMlResponse; + HfMlResponseDplusToPiKPi hfMlResponse; std::vector outputMlNotPreselected = {}; std::vector outputMl = {}; o2::ccdb::CcdbApi ccdbApi; TrackSelectorPi selectorPion; TrackSelectorKa selectorKaon; HfHelper hfHelper; + HfTrigger3ProngCuts hfTriggerCuts; using TracksSel = soa::Join; @@ -132,13 +141,13 @@ struct HfCandidateSelectorDplusToPiKPi { template bool selection(const T1& candidate, const T2& trackPion1, const T2& trackKaon, const T2& trackPion2) { - auto candpT = candidate.pt(); - int pTBin = findBin(binsPt, candpT); + auto ptCand = candidate.pt(); + int pTBin = findBin(binsPt, ptCand); if (pTBin == -1) { return false; } // check that the candidate pT is within the analysis range - if (candpT < ptCandMin || candpT > ptCandMax) { + if (ptCand < ptCandMin || ptCand > ptCandMax) { return false; } // cut on daughter pT @@ -149,6 +158,9 @@ struct HfCandidateSelectorDplusToPiKPi { if (std::abs(hfHelper.invMassDplusToPiKPi(candidate) - o2::constants::physics::MassDPlus) > cuts->get(pTBin, "deltaM")) { return false; } + if (useTriggerMassCut && !isCandidateInMassRange(hfHelper.invMassDplusToPiKPi(candidate), o2::constants::physics::MassDPlus, ptCand, hfTriggerCuts)) { + return false; + } if (candidate.decayLength() < cuts->get(pTBin, "decay length")) { return false; } @@ -164,7 +176,7 @@ struct HfCandidateSelectorDplusToPiKPi { if (std::abs(candidate.maxNormalisedDeltaIP()) > cuts->get(pTBin, "max normalized deltaIP")) { return false; } - if (!isSelectedCandidateDcaXY(candidate)) { + if (!isSelectedCandidateProngDca(candidate)) { return false; } return true; @@ -174,11 +186,11 @@ struct HfCandidateSelectorDplusToPiKPi { /// \param candidate is the Ds candidate /// \return true if all the prongs pass the selections template - bool isSelectedCandidateDcaXY(const T1& candidate) + bool isSelectedCandidateProngDca(const T1& candidate) { - return (isSelectedTrackDcaXY(binsPtTrack, cutsSingleTrack, candidate.ptProng0(), candidate.impactParameter0()) && - isSelectedTrackDcaXY(binsPtTrack, cutsSingleTrack, candidate.ptProng1(), candidate.impactParameter1()) && - isSelectedTrackDcaXY(binsPtTrack, cutsSingleTrack, candidate.ptProng2(), candidate.impactParameter2())); + return (isSelectedTrackDca(binsPtTrack, cutsSingleTrack, candidate.ptProng0(), candidate.impactParameter0(), candidate.impactParameterZ0()) && + isSelectedTrackDca(binsPtTrack, cutsSingleTrack, candidate.ptProng1(), candidate.impactParameter1(), candidate.impactParameterZ1()) && + isSelectedTrackDca(binsPtTrack, cutsSingleTrack, candidate.ptProng2(), candidate.impactParameter2(), candidate.impactParameterZ2())); } /// Apply PID selection @@ -216,7 +228,7 @@ struct HfCandidateSelectorDplusToPiKPi { auto ptCand = candidate.pt(); - if (!TESTBIT(candidate.hfflag(), aod::hf_cand_3prong::DecayType::DplusToPiKPi)) { + if (!TESTBIT(candidate.hfflag(), aod::hf_cand_3prong::DecayType::DplusToPiKPi) && !(storeDsDplusBkg && TESTBIT(candidate.hfflag(), aod::hf_cand_3prong::DecayType::DsToKKPi))) { // DecayType::DsToKKPi is used to flag both Ds± → K± K∓ π± and D± → K± K∓ π± hfSelDplusToPiKPiCandidate(statusDplusToPiKPi); if (applyMl) { hfMlDplusToPiKPiCandidate(outputMlNotPreselected); diff --git a/PWGHF/TableProducer/candidateSelectorDsToKKPi.cxx b/PWGHF/TableProducer/candidateSelectorDsToKKPi.cxx index 9127f0a7fa7..3fee66bf344 100644 --- a/PWGHF/TableProducer/candidateSelectorDsToKKPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorDsToKKPi.cxx @@ -15,6 +15,9 @@ /// \author Fabio Catalano , Universita and INFN Torino /// \author Stefano Politano , Politecnico and INFN Torino +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -25,6 +28,7 @@ #include "PWGHF/Core/HfMlResponseDsToKKPi.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" using namespace o2; using namespace o2::analysis; @@ -51,19 +55,21 @@ struct HfCandidateSelectorDsToKKPi { Configurable usePidTpcAndTof{"usePidTpcAndTof", false, "Use AND logic for TPC and TOF PID"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_ds_to_k_k_pi::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_ds_to_k_k_pi::cuts[0], hf_cuts_ds_to_k_k_pi::nBinsPt, hf_cuts_ds_to_k_k_pi::nCutVars, hf_cuts_ds_to_k_k_pi::labelsPt, hf_cuts_ds_to_k_k_pi::labelsCutVar}, "Ds candidate selection per pT bin"}; - // DCAxy selections - Configurable> cutsSingleTrack{"cutsSingleTrack", {hf_cuts_single_track::cutsTrack[0], hf_cuts_single_track::nBinsPtTrack, hf_cuts_single_track::nCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections"}; + Configurable> cuts{"cuts", {hf_cuts_ds_to_k_k_pi::Cuts[0], hf_cuts_ds_to_k_k_pi::NBinsPt, hf_cuts_ds_to_k_k_pi::NCutVars, hf_cuts_ds_to_k_k_pi::labelsPt, hf_cuts_ds_to_k_k_pi::labelsCutVar}, "Ds candidate selection per pT bin"}; + Configurable rejectCandsInDplusToPiKPiRegion{"rejectCandsInDplusToPiKPiRegion", false, "Flag to reject candidates in the D+ to PiKPi signal region"}; + Configurable deltaMRegionDplusToPiKPi{"deltaMRegionDplusToPiKPi", 0.03, "Width of the D+ to PiKPi signal region (GeV/c^2)"}; + // DCAxy and DCAz selections + Configurable> cutsSingleTrack{"cutsSingleTrack", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections"}; // pT bins for single-track cuts - Configurable> binsPtTrack{"binsPtTrack", std::vector{hf_cuts_single_track::vecBinsPtTrack}, "track pT bin limits for DCA XY pT-dependent cut"}; + Configurable> binsPtTrack{"binsPtTrack", std::vector{hf_cuts_single_track::vecBinsPtTrack}, "track pT bin limits for DCA pT-dependent cut"}; // QA switch Configurable activateQA{"activateQA", false, "Flag to enable QA histogram"}; // ML inference Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; Configurable> binsPtMl{"binsPtMl", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; Configurable> cutDirMl{"cutDirMl", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; - Configurable> cutsMl{"cutsMl", {hf_cuts_ml::cuts[0], hf_cuts_ml::nBinsPt, hf_cuts_ml::nCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; - Configurable nClassesMl{"nClassesMl", (int8_t)hf_cuts_ml::nCutScores, "Number of classes in ML model"}; + Configurable> cutsMl{"cutsMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable nClassesMl{"nClassesMl", static_cast(hf_cuts_ml::NCutScores), "Number of classes in ML model"}; Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; // CCDB configuration Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -71,6 +77,8 @@ struct HfCandidateSelectorDsToKKPi { Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_DsToKKPi.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + // Mass cut for trigger analysis + Configurable useTriggerMassCut{"useTriggerMassCut", false, "Flag to enable parametrized pT differential mass cut for triggered data"}; HfHelper hfHelper; o2::analysis::HfMlResponseDsToKKPi hfMlResponse; @@ -79,6 +87,7 @@ struct HfCandidateSelectorDsToKKPi { o2::ccdb::CcdbApi ccdbApi; TrackSelectorPi selectorPion; TrackSelectorKa selectorKaon; + HfTrigger3ProngCuts hfTriggerCuts; using TracksSel = soa::Join; @@ -126,11 +135,11 @@ struct HfCandidateSelectorDsToKKPi { /// \param candidate is the Ds candidate /// \return true if all the prongs pass the selections template - bool isSelectedCandidateDcaXY(const T1& candidate) + bool isSelectedCandidateProngDca(const T1& candidate) { - if (isSelectedTrackDcaXY(binsPtTrack, cutsSingleTrack, candidate.ptProng0(), candidate.impactParameter0()) && - isSelectedTrackDcaXY(binsPtTrack, cutsSingleTrack, candidate.ptProng1(), candidate.impactParameter1()) && - isSelectedTrackDcaXY(binsPtTrack, cutsSingleTrack, candidate.ptProng2(), candidate.impactParameter2())) { + if (isSelectedTrackDca(binsPtTrack, cutsSingleTrack, candidate.ptProng0(), candidate.impactParameter0(), candidate.impactParameterZ0()) && + isSelectedTrackDca(binsPtTrack, cutsSingleTrack, candidate.ptProng1(), candidate.impactParameter1(), candidate.impactParameterZ1()) && + isSelectedTrackDca(binsPtTrack, cutsSingleTrack, candidate.ptProng2(), candidate.impactParameter2(), candidate.impactParameterZ2())) { return true; } return false; @@ -169,7 +178,10 @@ struct HfCandidateSelectorDsToKKPi { if (candidate.chi2PCA() > cuts->get(pTBin, "chi2PCA")) { return false; } - if (!isSelectedCandidateDcaXY(candidate)) { + if (!isSelectedCandidateProngDca(candidate)) { + return false; + } + if (rejectCandsInDplusToPiKPiRegion && std::abs(hfHelper.invMassDplusToPiKPi(candidate) - o2::constants::physics::MassDPlus) < deltaMRegionDplusToPiKPi) { return false; } return true; @@ -195,6 +207,9 @@ struct HfCandidateSelectorDsToKKPi { if (std::abs(hfHelper.invMassDsToKKPi(candidate) - o2::constants::physics::MassDS) > cuts->get(pTBin, "deltaM")) { return false; } + if (useTriggerMassCut && !isCandidateInMassRange(hfHelper.invMassDsToKKPi(candidate), o2::constants::physics::MassDS, candidate.pt(), hfTriggerCuts)) { + return false; + } if (hfHelper.deltaMassPhiDsToKKPi(candidate) > cuts->get(pTBin, "deltaM Phi")) { return false; } @@ -224,6 +239,9 @@ struct HfCandidateSelectorDsToKKPi { if (std::abs(hfHelper.invMassDsToPiKK(candidate) - o2::constants::physics::MassDS) > cuts->get(pTBin, "deltaM")) { return false; } + if (useTriggerMassCut && !isCandidateInMassRange(hfHelper.invMassDsToPiKK(candidate), o2::constants::physics::MassDS, candidate.pt(), hfTriggerCuts)) { + return false; + } if (hfHelper.deltaMassPhiDsToPiKK(candidate) > cuts->get(pTBin, "deltaM Phi")) { return false; } diff --git a/PWGHF/TableProducer/candidateSelectorDstarToD0Pi.cxx b/PWGHF/TableProducer/candidateSelectorDstarToD0Pi.cxx index 7f7f8501863..a94f510f01c 100644 --- a/PWGHF/TableProducer/candidateSelectorDstarToD0Pi.cxx +++ b/PWGHF/TableProducer/candidateSelectorDstarToD0Pi.cxx @@ -15,6 +15,10 @@ /// \author Deependra Sharma , IITB /// \author Fabrizio Grosa , CERN +#include +#include +#include + // O2 #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisDataModel.h" @@ -44,13 +48,15 @@ struct HfCandidateSelectorDstarToD0Pi { Configurable ptD0CandMin{"ptD0CandMin", 0., "Minimum D0 candidate pT"}; Configurable ptD0CandMax{"ptD0CandMax", 50., "Maximum D0 candidate pT"}; Configurable> binsPtD0{"binsPtD0", std::vector{hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits for D0"}; - Configurable> cutsD0{"cutsD0", {hf_cuts_d0_to_pi_k::cuts[0], hf_cuts_d0_to_pi_k::nBinsPt, hf_cuts_d0_to_pi_k::nCutVars, hf_cuts_d0_to_pi_k::labelsPt, hf_cuts_d0_to_pi_k::labelsCutVar}, "D0 candidate selection per pT bin"}; + Configurable> cutsD0{"cutsD0", {hf_cuts_d0_to_pi_k::Cuts[0], hf_cuts_d0_to_pi_k::NBinsPt, hf_cuts_d0_to_pi_k::NCutVars, hf_cuts_d0_to_pi_k::labelsPt, hf_cuts_d0_to_pi_k::labelsCutVar}, "D0 candidate selection per pT bin"}; + // Mass Cut for trigger analysis + Configurable useTriggerMassCut{"useTriggerMassCut", false, "Flag to enable parametrize pT differential mass cut for triggered data"}; // Configurable specific to Dstar Configurable ptDstarCandMin{"ptDstarCandMin", 0., "Minimum Dstar candidate pT"}; Configurable ptDstarCandMax{"ptDstarCandMax", 50., "Maximum Dstar candidate pT"}; Configurable> binsPtDstar{"binsPtDstar", std::vector{hf_cuts_dstar_to_d0_pi::vecBinsPt}, "pT bin limits for Dstar"}; - Configurable> cutsDstar{"cutsDstar", {hf_cuts_dstar_to_d0_pi::cuts[0], hf_cuts_dstar_to_d0_pi::nBinsPt, hf_cuts_dstar_to_d0_pi::nCutVars, hf_cuts_dstar_to_d0_pi::labelsPt, hf_cuts_dstar_to_d0_pi::labelsCutVar}, "Dstar candidate selection per pT bin"}; + Configurable> cutsDstar{"cutsDstar", {hf_cuts_dstar_to_d0_pi::Cuts[0], hf_cuts_dstar_to_d0_pi::NBinsPt, hf_cuts_dstar_to_d0_pi::NCutVars, hf_cuts_dstar_to_d0_pi::labelsPt, hf_cuts_dstar_to_d0_pi::labelsCutVar}, "Dstar candidate selection per pT bin"}; // common Configurable // TPC PID @@ -78,8 +84,8 @@ struct HfCandidateSelectorDstarToD0Pi { Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; Configurable> binsPtMl{"binsPtMl", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; Configurable> cutDirMl{"cutDirMl", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; - Configurable> cutsMl{"cutsMl", {hf_cuts_ml::cuts[0], hf_cuts_ml::nBinsPt, hf_cuts_ml::nCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; - Configurable nClassesMl{"nClassesMl", (int8_t)hf_cuts_ml::nCutScores, "Number of classes in ML model"}; + Configurable> cutsMl{"cutsMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable nClassesMl{"nClassesMl", static_cast(hf_cuts_ml::NCutScores), "Number of classes in ML model"}; Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; // CCDB configuration @@ -108,6 +114,8 @@ struct HfCandidateSelectorDstarToD0Pi { AxisSpec axisSelStatus{2, -0.5f, 1.5f}; HistogramRegistry registry{"registry"}; + HfTrigger2ProngCuts hfTriggerCuts; + void init(InitContext&) { massPi = MassPiPlus; @@ -207,8 +215,7 @@ struct HfCandidateSelectorDstarToD0Pi { // decay exponentail law, with tau = beta*gamma*ctau // decay length > ctau retains (1-1/e) - double decayLengthCut = std::min((candidate.pD0() * 0.0066) + 0.01, cutsD0->get(binPt, "min decay length")); - if (candidate.decayLengthD0() * candidate.decayLengthD0() < decayLengthCut * decayLengthCut) { + if (candidate.decayLengthD0() < cutsD0->get(binPt, "min decay length")) { return false; } if (candidate.decayLengthD0() > cutsD0->get(binPt, "max decay length")) { @@ -282,6 +289,9 @@ struct HfCandidateSelectorDstarToD0Pi { if (std::abs(mInvD0 - massD0) > cutsD0->get(binPt, "m")) { return false; } + if (useTriggerMassCut && !isCandidateInMassRange(mInvD0, massD0, candidate.ptD0(), hfTriggerCuts)) { + return false; + } // cut on daughter pT auto d0prong0 = candidate.template prong0_as(); auto d0prong1 = candidate.template prong1_as(); @@ -307,6 +317,9 @@ struct HfCandidateSelectorDstarToD0Pi { if (std::abs(mInvD0Bar - massD0) > cutsD0->get(binPt, "m")) { return false; } + if (useTriggerMassCut && !isCandidateInMassRange(mInvD0Bar, massD0, candidate.ptD0(), hfTriggerCuts)) { + return false; + } // cut on daughter pT auto d0prong0 = candidate.template prong0_as(); auto d0prong1 = candidate.template prong1_as(); diff --git a/PWGHF/TableProducer/candidateSelectorLbToLcPi.cxx b/PWGHF/TableProducer/candidateSelectorLbToLcPi.cxx index af29313e40f..b1033c9555f 100644 --- a/PWGHF/TableProducer/candidateSelectorLbToLcPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorLbToLcPi.cxx @@ -14,10 +14,14 @@ /// /// \author Panos Christakoglou , Nikhef +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" +#include "Common/Core/TrackSelectorPID.h" + #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/SelectorCuts.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" @@ -31,25 +35,40 @@ using namespace o2::analysis; struct HfCandidateSelectorLbToLcPi { Produces hfSelLbToLcPiCandidate; - Configurable ptCandMin{"ptCandMin", 0., "Lower bound of candidate pT"}; - Configurable ptCandMax{"ptCandMax", 50., "Upper bound of candidate pT"}; + Configurable ptCandMin{"ptCandMin", 0., "Lower bound of candidate pT"}; + Configurable ptCandMax{"ptCandMax", 50., "Upper bound of candidate pT"}; // TPC PID - Configurable ptPidTpcMin{"ptPidTpcMin", 0.15, "Lower bound of track pT for TPC PID"}; - Configurable ptPidTpcMax{"ptPidTpcMax", 10., "Upper bound of track pT for TPC PID"}; - Configurable nSigmaTpcMax{"nSigmaTpcMax", 5., "Nsigma cut on TPC only"}; - Configurable nSigmaTpcCombinedMax{"nSigmaTpcCombinedMax", 5., "Nsigma cut on TPC combined with TOF"}; + Configurable ptPidTpcMin{"ptPidTpcMin", 0.15, "Lower bound of track pT for TPC PID"}; + Configurable ptPidTpcMax{"ptPidTpcMax", 10., "Upper bound of track pT for TPC PID"}; + Configurable nSigmaTpcMax{"nSigmaTpcMax", 5., "Nsigma cut on TPC only"}; + Configurable nSigmaTpcCombinedMax{"nSigmaTpcCombinedMax", 5., "Nsigma cut on TPC combined with TOF"}; // TOF PID - Configurable ptPidTofMin{"ptPidTofMin", 0.15, "Lower bound of track pT for TOF PID"}; - Configurable ptPidTofMax{"ptPidTofMax", 10., "Upper bound of track pT for TOF PID"}; - Configurable nSigmaTofMax{"nSigmaTofMax", 5., "Nsigma cut on TOF only"}; - Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 5., "Nsigma cut on TOF combined with TPC"}; + Configurable ptPidTofMin{"ptPidTofMin", 0.15, "Lower bound of track pT for TOF PID"}; + Configurable ptPidTofMax{"ptPidTofMax", 10., "Upper bound of track pT for TOF PID"}; + Configurable nSigmaTofMax{"nSigmaTofMax", 5., "Nsigma cut on TOF only"}; + Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 5., "Nsigma cut on TOF combined with TPC"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_lb_to_lc_pi::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_lb_to_lc_pi::cuts[0], hf_cuts_lb_to_lc_pi::nBinsPt, hf_cuts_lb_to_lc_pi::nCutVars, hf_cuts_lb_to_lc_pi::labelsPt, hf_cuts_lb_to_lc_pi::labelsCutVar}, "Lb0 candidate selection per pT bin"}; + Configurable impactParameterMaximum{"impactParameterMaximum", 0.2, "Maximum impact parameter for single tracks"}; + Configurable maxDecayLengthError{"maxDecayLengthError", 0.015, "decay length error quality selection"}; + Configurable maxDecayLengthXYError{"maxDecayLengthXYError", 0.01, "decay length xy error quality selection"}; + Configurable maxVertexDistanceLbLc{"maxVertexDistanceLbLc", 0.05, "maximum distance between Lb and Lc vertex"}; + Configurable> cuts{"cuts", {hf_cuts_lb_to_lc_pi::Cuts[0], hf_cuts_lb_to_lc_pi::NBinsPt, hf_cuts_lb_to_lc_pi::NCutVars, hf_cuts_lb_to_lc_pi::labelsPt, hf_cuts_lb_to_lc_pi::labelsCutVar}, "Lb0 candidate selection per pT bin"}; Configurable selectionFlagLc{"selectionFlagLc", 1, "Selection Flag for Lc+"}; HfHelper hfHelper; + using TracksWExt = soa::Join; + + bool passesImpactParameterResolution(float pT, float d0Resolution) + { + float expectedResolution(0.001 + 0.0052 * std::exp(-0.655 * pT)); + if (d0Resolution > expectedResolution * 1.5) + return false; + else + return true; + } // Compares to pT dependent cut on impact parameter resolution + // Apply topological cuts as defined in SelectorCuts.h; return true if candidate passes all cuts template bool selectionTopol(const T1& hfCandLb, const T2& hfCandLc, const T3& trackPi) @@ -66,7 +85,7 @@ struct HfCandidateSelectorLbToLcPi { return false; } - //Λb0 mass cut + // Λb0 mass cut if (std::abs(hfHelper.invMassLbToLcPi(hfCandLb) - o2::constants::physics::MassLambdaB0) > cuts->get(pTBin, "m")) { // LOGF(debug, "Lb topol selection failed at mass diff check"); return false; @@ -82,12 +101,18 @@ struct HfCandidateSelectorLbToLcPi { return false; } - // Lc mass - // if (trackPi.sign() < 0) { - // if (std::abs(hfHelper.invMassLcToPKPi(hfCandLc) - o2::constants::physics::MassLambdaCPlus) > cuts->get(pTBin, "DeltaMLc")) { - // return false; - // } - // } + float lcMass = 0.; + if (hfCandLc.isSelLcToPKPi()) + lcMass = hfHelper.invMassLcToPKPi(hfCandLc); + if (hfCandLc.isSelLcToPiKP()) + lcMass = hfHelper.invMassLcToPiKP(hfCandLc); + if (std::abs(lcMass - o2::constants::physics::MassLambdaCPlus) > cuts->get(pTBin, "DeltaMLc")) + return false; + + if (hfCandLb.errorDecayLengthXY() > maxDecayLengthXYError) + return false; + if (hfCandLb.errorDecayLength() > maxDecayLengthError) + return false; // Lb Decay length if (hfCandLb.decayLength() < cuts->get(pTBin, "Lb decLen")) { @@ -120,12 +145,21 @@ struct HfCandidateSelectorLbToLcPi { return false; } + // distance between Lb and Lc decay + float diffXVert = hfCandLb.xSecondaryVertex() - hfCandLc.xSecondaryVertex(); + float diffYVert = hfCandLb.ySecondaryVertex() - hfCandLc.ySecondaryVertex(); + float diffZVert = hfCandLb.zSecondaryVertex() - hfCandLc.zSecondaryVertex(); + float vertexDistance = std::sqrt(diffXVert * diffXVert + diffYVert * diffYVert + diffZVert * diffZVert); + if (vertexDistance > maxVertexDistanceLbLc) { + return false; + } + return true; } void process(aod::HfCandLb const& hfCandLbs, soa::Join const&, - aod::Tracks const&) + TracksWExt const&) { for (const auto& hfCandLb : hfCandLbs) { // looping over Lb candidates @@ -141,7 +175,25 @@ struct HfCandidateSelectorLbToLcPi { // Lc is always index0 and pi is index1 by default // auto candLc = hfCandLb.prong0(); auto candLc = hfCandLb.prong0_as>(); - auto trackPi = hfCandLb.prong1(); + auto trackPi = hfCandLb.prong1_as(); + + // Check that the impact parameter resolution is not too far from the typical + auto track0 = candLc.prong0_as(); + auto track1 = candLc.prong1_as(); + auto track2 = candLc.prong2_as(); + float reso0 = candLc.errorImpactParameter0(); + float reso1 = candLc.errorImpactParameter1(); + float reso2 = candLc.errorImpactParameter2(); + if (!passesImpactParameterResolution(track0.pt(), reso0) || !passesImpactParameterResolution(track1.pt(), reso1) || !passesImpactParameterResolution(track2.pt(), reso2) || !passesImpactParameterResolution(trackPi.pt(), hfCandLb.errorImpactParameter1())) { + hfSelLbToLcPiCandidate(statusLb); + continue; + } + + // Maximum single-track impact parameter selection to suppress strange background + if (std::abs(hfCandLb.impactParameter1()) > impactParameterMaximum || candLc.impactParameter0() > impactParameterMaximum || candLc.impactParameter1() > impactParameterMaximum || candLc.impactParameter2() > impactParameterMaximum) { + hfSelLbToLcPiCandidate(statusLb); + continue; + } // topological cuts if (!selectionTopol(hfCandLb, candLc, trackPi)) { @@ -150,6 +202,20 @@ struct HfCandidateSelectorLbToLcPi { continue; } + // PID selection for pion + if (trackPi.pt() > ptPidTpcMin && trackPi.pt() < ptPidTpcMax) { + if (std::abs(trackPi.tpcNSigmaPi()) > nSigmaTpcMax) { + hfSelLbToLcPiCandidate(statusLb); + continue; + } + } + if (trackPi.pt() > ptPidTofMin && trackPi.pt() < ptPidTofMax) { + if (std::abs(trackPi.tofNSigmaPi()) > nSigmaTofMax) { + hfSelLbToLcPiCandidate(statusLb); + continue; + } + } + hfSelLbToLcPiCandidate(1); // LOGF(debug, "Lb candidate selection successful, candidate should be selected"); } diff --git a/PWGHF/TableProducer/candidateSelectorLc.cxx b/PWGHF/TableProducer/candidateSelectorLc.cxx index 25b13bc8821..0585fd66b5f 100644 --- a/PWGHF/TableProducer/candidateSelectorLc.cxx +++ b/PWGHF/TableProducer/candidateSelectorLc.cxx @@ -17,6 +17,9 @@ /// \author Vít Kučera , CERN /// \author Grazia Luparello , INFN Trieste +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -52,22 +55,32 @@ struct HfCandidateSelectorLc { Configurable nSigmaTofMax{"nSigmaTofMax", 3., "Nsigma cut on TOF only"}; Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 5., "Nsigma cut on TOF combined with TPC"}; // Bayesian PID - Configurable usePidBayes{"usePidBayes", true, "Bool to use or not the PID based on Bayesian probability cut at filtering level"}; Configurable ptPidBayesMin{"ptPidBayesMin", 0., "Lower bound of track pT for Bayesian PID"}; Configurable ptPidBayesMax{"ptPidBayesMax", 100, "Upper bound of track pT for Bayesian PID"}; // Combined PID options Configurable usePidTpcAndTof{"usePidTpcAndTof", false, "Bool to decide how to combine TPC and TOF PID: true = both (if present, only one otherwise); false = one is enough"}; + // TPC quality track cuts + Configurable tpcNClustersFoundMin{"tpcNClustersFoundMin", 0, "min number of found TPC clusters"}; + Configurable tpcNCrossedRowsMin{"tpcNCrossedRowsMin", 0, "min number of crossed rows in TPC"}; + Configurable tpcNCrossedRowsOverFindableClustersMin{"tpcNCrossedRowsOverFindableClustersMin", 0., "min ratio crossed rows / findable clusters"}; + Configurable tpcChi2PerClusterMax{"tpcChi2PerClusterMax", 1e10f, "max tpc fit chi2 per TPC cluster"}; + // ITS quality track cuts + Configurable itsNClustersFoundMin{"itsNClustersFoundMin", 0, "min. number of found ITS clusters"}; + Configurable itsChi2PerClusterMax{"itsChi2PerClusterMax", 1e10f, "max its fit chi2 per ITS cluster"}; + // DCA track cuts + Configurable> binsPtTrack{"binsPtTrack", std::vector{hf_cuts_single_track::vecBinsPtTrack}, "track pT bin limits for DCA XY/Z pT-dependent cut"}; + Configurable> cutsSingleTrack{"cutsSingleTrack", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_lc_to_p_k_pi::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_lc_to_p_k_pi::cuts[0], hf_cuts_lc_to_p_k_pi::nBinsPt, hf_cuts_lc_to_p_k_pi::nCutVars, hf_cuts_lc_to_p_k_pi::labelsPt, hf_cuts_lc_to_p_k_pi::labelsCutVar}, "Lc candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_lc_to_p_k_pi::Cuts[0], hf_cuts_lc_to_p_k_pi::NBinsPt, hf_cuts_lc_to_p_k_pi::NCutVars, hf_cuts_lc_to_p_k_pi::labelsPt, hf_cuts_lc_to_p_k_pi::labelsCutVar}, "Lc candidate selection per pT bin"}; // QA switch Configurable activateQA{"activateQA", false, "Flag to enable QA histogram"}; // ML inference Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; Configurable> binsPtMl{"binsPtMl", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; Configurable> cutDirMl{"cutDirMl", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; - Configurable> cutsMl{"cutsMl", {hf_cuts_ml::cuts[0], hf_cuts_ml::nBinsPt, hf_cuts_ml::nCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; - Configurable nClassesMl{"nClassesMl", (int8_t)hf_cuts_ml::nCutScores, "Number of classes in ML model"}; + Configurable> cutsMl{"cutsMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable nClassesMl{"nClassesMl", static_cast(hf_cuts_ml::NCutScores), "Number of classes in ML model"}; Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; // CCDB configuration Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -86,13 +99,20 @@ struct HfCandidateSelectorLc { TrackSelectorPr selectorProton; using TracksSel = soa::Join; + aod::TracksPidPi, aod::PidTpcTofFullPi, aod::TracksPidKa, aod::PidTpcTofFullKa, aod::TracksPidPr, aod::PidTpcTofFullPr>; + using TracksSelBayesPid = soa::Join; HistogramRegistry registry{"registry"}; + double massK0Star892; + void init(InitContext const&) { + std::array processes = {doprocessNoBayesPidWithDCAFitterN, doprocessBayesPidWithDCAFitterN, doprocessNoBayesPidWithKFParticle, doprocessBayesPidWithKFParticle}; + if (std::accumulate(processes.begin(), processes.end(), 0) != 1) { + LOGP(fatal, "One and only one process function must be enabled at a time."); + } + selectorPion.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); selectorPion.setRangeNSigmaTpc(-nSigmaTpcMax, nSigmaTpcMax); selectorPion.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedMax, nSigmaTpcCombinedMax); @@ -129,6 +149,27 @@ struct HfCandidateSelectorLc { hfMlResponse.cacheInputFeaturesIndices(namesInputFeatures); hfMlResponse.init(); } + + massK0Star892 = o2::constants::physics::MassK0Star892; + } + + /// Single track quality cuts + /// \param track is track + /// \return true if track passes all cuts + template + bool isSelectedCandidateProngQuality(const T& trackPos1, const T& trackNeg, const T& trackPos2) + { + if (!isSelectedTrackTpcQuality(trackPos1, tpcNClustersFoundMin.value, tpcNCrossedRowsMin.value, tpcNCrossedRowsOverFindableClustersMin.value, tpcChi2PerClusterMax.value) || + !isSelectedTrackTpcQuality(trackNeg, tpcNClustersFoundMin.value, tpcNCrossedRowsMin.value, tpcNCrossedRowsOverFindableClustersMin.value, tpcChi2PerClusterMax.value) || + !isSelectedTrackTpcQuality(trackPos2, tpcNClustersFoundMin.value, tpcNCrossedRowsMin.value, tpcNCrossedRowsOverFindableClustersMin.value, tpcChi2PerClusterMax.value)) { + return false; + } + if (!isSelectedTrackItsQuality(trackPos1, itsNClustersFoundMin.value, itsChi2PerClusterMax.value) || + !isSelectedTrackItsQuality(trackNeg, itsNClustersFoundMin.value, itsChi2PerClusterMax.value) || + !isSelectedTrackItsQuality(trackPos2, itsNClustersFoundMin.value, itsChi2PerClusterMax.value)) { + return false; + } + return true; } /// Conjugate-independent topological cuts @@ -162,6 +203,26 @@ struct HfCandidateSelectorLc { if (candidate.decayLength() <= cuts->get(pTBin, "decay length")) { return false; } + + // candidate decay length XY + if (candidate.decayLengthXY() <= cuts->get(pTBin, "decLengthXY")) { + return false; + } + + // candidate normalized decay length XY + if (candidate.decayLengthXYNormalised() < cuts->get(pTBin, "normDecLXY")) { + return false; + } + + // candidate impact parameter XY + if (std::abs(candidate.impactParameterXY()) > cuts->get(pTBin, "impParXY")) { + return false; + } + + if (!isSelectedCandidateProngDca(candidate)) { + return false; + } + return true; } @@ -171,7 +232,7 @@ struct HfCandidateSelectorLc { /// \param trackPion is the track with the pion hypothesis /// \param trackKaon is the track with the kaon hypothesis /// \return true if candidate passes all cuts for the given Conjugate - template + template bool selectionTopolConjugate(const T1& candidate, const T2& trackProton, const T2& trackKaon, const T2& trackPion) { @@ -186,21 +247,72 @@ struct HfCandidateSelectorLc { return false; } - if (trackProton.globalIndex() == candidate.prong0Id()) { - if (std::abs(hfHelper.invMassLcToPKPi(candidate) - o2::constants::physics::MassLambdaCPlus) > cuts->get(pTBin, "m")) { - return false; + // cut on Lc->pKpi, piKp mass values + /// cut on the Kpi pair invariant mass, to study Lc->pK*(->Kpi) + float massLc, massKPi; + if constexpr (reconstructionType == aod::hf_cand::VertexerType::DCAFitter) { + if (trackProton.globalIndex() == candidate.prong0Id()) { + massLc = hfHelper.invMassLcToPKPi(candidate); + massKPi = hfHelper.invMassKPiPairLcToPKPi(candidate); + } else { + massLc = hfHelper.invMassLcToPiKP(candidate); + massKPi = hfHelper.invMassKPiPairLcToPiKP(candidate); } - } else { - if (std::abs(hfHelper.invMassLcToPiKP(candidate) - o2::constants::physics::MassLambdaCPlus) > cuts->get(pTBin, "m")) { - return false; + } else if constexpr (reconstructionType == aod::hf_cand::VertexerType::KfParticle) { + if (trackProton.globalIndex() == candidate.prong0Id()) { + massLc = candidate.kfMassPKPi(); + massKPi = candidate.kfMassKPi(); + } else { + massLc = candidate.kfMassPiKP(); + massKPi = candidate.kfMassPiK(); } } + if (std::abs(massLc - o2::constants::physics::MassLambdaCPlus) > cuts->get(pTBin, "m")) { + return false; + } + + /// cut on the Kpi pair invariant mass, to study Lc->pK*(->Kpi) + const double cutMassKPi = cuts->get(pTBin, "mass (Kpi)"); + if (cutMassKPi > 0 && std::abs(massKPi - massK0Star892) > cutMassKPi) { + return false; + } + return true; } - void process(aod::HfCand3Prong const& candidates, - TracksSel const&) + /// Single-track dca_xy and dca_z cuts + /// \param candidate is the Lc candidate + /// \return true if all the prongs pass the selections + template + bool isSelectedCandidateProngDca(const T1& candidate) + { + return (isSelectedTrackDca(binsPtTrack, cutsSingleTrack, candidate.ptProng0(), candidate.impactParameter0(), candidate.impactParameterZ0()) && + isSelectedTrackDca(binsPtTrack, cutsSingleTrack, candidate.ptProng1(), candidate.impactParameter1(), candidate.impactParameterZ1()) && + isSelectedTrackDca(binsPtTrack, cutsSingleTrack, candidate.ptProng2(), candidate.impactParameter2(), candidate.impactParameterZ2())); + } + + /// Apply PID selection + /// \param pidTrackProton is the PID status of proton candidate track + /// \param pidTrackKaon is the PID status of kaon candidate track + /// \param pidTrackPion is the PID status of pion candidate track + /// \return true if prongs pass all selections + bool isSelectedPID(const TrackSelectorPID::Status pidTrackProton, const TrackSelectorPID::Status pidTrackKaon, const TrackSelectorPID::Status pidTrackPion) + { + if (pidTrackProton == TrackSelectorPID::Rejected || + pidTrackKaon == TrackSelectorPID::Rejected || + pidTrackPion == TrackSelectorPID::Rejected) { + return false; + } + return true; + } + + /// \brief function to apply Lc selections + /// \param reconstructionType is the reconstruction type (DCAFitterN or KFParticle) + /// \param candidates Lc candidate table + /// \param tracks track table + template + void runSelectLc(CandType const& candidates, TTracks const&) { // looping over 3-prong candidates for (const auto& candidate : candidates) { @@ -229,12 +341,22 @@ struct HfCandidateSelectorLc { registry.fill(HIST("hSelections"), 2 + aod::SelectionStep::RecoSkims, ptCand); } - auto trackPos1 = candidate.prong0_as(); // positive daughter (negative for the antiparticles) - auto trackNeg = candidate.prong1_as(); // negative daughter (positive for the antiparticles) - auto trackPos2 = candidate.prong2_as(); // positive daughter (negative for the antiparticles) + auto trackPos1 = candidate.template prong0_as(); // positive daughter (negative for the antiparticles) + auto trackNeg = candidate.template prong1_as(); // negative daughter (positive for the antiparticles) + auto trackPos2 = candidate.template prong2_as(); // positive daughter (negative for the antiparticles) // implement filter bit 4 cut - should be done before this task at the track selection level + // track quality selection + bool trackQualitySel = isSelectedCandidateProngQuality(trackPos1, trackNeg, trackPos2); + if (!trackQualitySel) { + hfSelLcCandidate(statusLcToPKPi, statusLcToPiKP); + if (applyMl) { + hfMlLcToPKPiCandidate(outputMlLcToPKPi, outputMlLcToPiKP); + } + continue; + } + // conjugate-independent topological selection if (!selectionTopol(candidate)) { hfSelLcCandidate(statusLcToPKPi, statusLcToPiKP); @@ -245,9 +367,8 @@ struct HfCandidateSelectorLc { } // conjugate-dependent topological selection for Lc - - bool topolLcToPKPi = selectionTopolConjugate(candidate, trackPos1, trackNeg, trackPos2); - bool topolLcToPiKP = selectionTopolConjugate(candidate, trackPos2, trackNeg, trackPos1); + bool topolLcToPKPi = selectionTopolConjugate(candidate, trackPos1, trackNeg, trackPos2); + bool topolLcToPiKP = selectionTopolConjugate(candidate, trackPos2, trackNeg, trackPos1); if (!topolLcToPKPi && !topolLcToPiKP) { hfSelLcCandidate(statusLcToPKPi, statusLcToPiKP); @@ -261,22 +382,19 @@ struct HfCandidateSelectorLc { registry.fill(HIST("hSelections"), 2 + aod::SelectionStep::RecoTopol, candidate.pt()); } - auto pidLcToPKPi = -1; - auto pidLcToPiKP = -1; - auto pidBayesLcToPKPi = -1; - auto pidBayesLcToPiKP = -1; + // PID not applied, accepted by default + auto pidLcToPKPi = 1; + auto pidLcToPiKP = 1; + auto pidBayesLcToPKPi = 1; + auto pidBayesLcToPiKP = 1; - if (!usePid) { - // PID non applied - pidLcToPKPi = 1; - pidLcToPiKP = 1; - } else { + if (usePid) { // track-level PID selection - int pidTrackPos1Proton = 999; - int pidTrackPos2Proton = 999; - int pidTrackPos1Pion = 999; - int pidTrackPos2Pion = 999; - int pidTrackNegKaon = 999; + TrackSelectorPID::Status pidTrackPos1Proton = TrackSelectorPID::Accepted; + TrackSelectorPID::Status pidTrackPos2Proton = TrackSelectorPID::Accepted; + TrackSelectorPID::Status pidTrackPos1Pion = TrackSelectorPID::Accepted; + TrackSelectorPID::Status pidTrackPos2Pion = TrackSelectorPID::Accepted; + TrackSelectorPID::Status pidTrackNegKaon = TrackSelectorPID::Accepted; if (usePidTpcAndTof) { pidTrackPos1Proton = selectorProton.statusTpcAndTof(trackPos1); pidTrackPos2Proton = selectorProton.statusTpcAndTof(trackPos2); @@ -291,73 +409,42 @@ struct HfCandidateSelectorLc { pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg); } - if (pidTrackPos1Proton == TrackSelectorPID::Accepted && - pidTrackNegKaon == TrackSelectorPID::Accepted && - pidTrackPos2Pion == TrackSelectorPID::Accepted) { - pidLcToPKPi = 1; // accept LcToPKPi - } else if (pidTrackPos1Proton == TrackSelectorPID::Rejected || - pidTrackNegKaon == TrackSelectorPID::Rejected || - pidTrackPos2Pion == TrackSelectorPID::Rejected) { - pidLcToPKPi = 0; // exclude LcToPKPi + if (!isSelectedPID(pidTrackPos1Proton, pidTrackNegKaon, pidTrackPos2Pion)) { + pidLcToPKPi = 0; // reject LcToPKPi } - if (pidTrackPos2Proton == TrackSelectorPID::Accepted && - pidTrackNegKaon == TrackSelectorPID::Accepted && - pidTrackPos1Pion == TrackSelectorPID::Accepted) { - pidLcToPiKP = 1; // accept LcToPiKP - } else if (pidTrackPos1Pion == TrackSelectorPID::Rejected || - pidTrackNegKaon == TrackSelectorPID::Rejected || - pidTrackPos2Proton == TrackSelectorPID::Rejected) { - pidLcToPiKP = 0; // exclude LcToPiKP + if (!isSelectedPID(pidTrackPos2Proton, pidTrackNegKaon, pidTrackPos1Pion)) { + pidLcToPiKP = 0; // accept LcToPiKP } } - if (!usePidBayes) { - // PID non applied - pidBayesLcToPKPi = 1; - pidBayesLcToPiKP = 1; - } else { - int pidBayesTrackPos1Proton = selectorProton.statusBayes(trackPos1); - int pidBayesTrackPos2Proton = selectorProton.statusBayes(trackPos2); - int pidBayesTrackPos1Pion = selectorPion.statusBayes(trackPos1); - int pidBayesTrackPos2Pion = selectorPion.statusBayes(trackPos2); - int pidBayesTrackNegKaon = selectorKaon.statusBayes(trackNeg); - - if (pidBayesTrackPos1Proton == TrackSelectorPID::Accepted && - pidBayesTrackNegKaon == TrackSelectorPID::Accepted && - pidBayesTrackPos2Pion == TrackSelectorPID::Accepted) { - pidBayesLcToPKPi = 1; // accept LcToPKPi - } else if (pidBayesTrackPos1Proton == TrackSelectorPID::Rejected || - pidBayesTrackNegKaon == TrackSelectorPID::Rejected || - pidBayesTrackPos2Pion == TrackSelectorPID::Rejected) { - pidBayesLcToPKPi = 0; // exclude LcToPKPi + if constexpr (useBayesPid) { + TrackSelectorPID::Status pidBayesTrackPos1Proton = selectorProton.statusBayes(trackPos1); + TrackSelectorPID::Status pidBayesTrackPos2Proton = selectorProton.statusBayes(trackPos2); + TrackSelectorPID::Status pidBayesTrackPos1Pion = selectorPion.statusBayes(trackPos1); + TrackSelectorPID::Status pidBayesTrackPos2Pion = selectorPion.statusBayes(trackPos2); + TrackSelectorPID::Status pidBayesTrackNegKaon = selectorKaon.statusBayes(trackNeg); + + if (!isSelectedPID(pidBayesTrackPos1Proton, pidBayesTrackNegKaon, pidBayesTrackPos2Pion)) { + pidBayesLcToPKPi = 0; // reject LcToPKPi } - if (pidBayesTrackPos2Proton == TrackSelectorPID::Accepted && - pidBayesTrackNegKaon == TrackSelectorPID::Accepted && - pidBayesTrackPos1Pion == TrackSelectorPID::Accepted) { - pidBayesLcToPiKP = 1; // accept LcToPiKP - } else if (pidBayesTrackPos1Pion == TrackSelectorPID::Rejected || - pidBayesTrackNegKaon == TrackSelectorPID::Rejected || - pidBayesTrackPos2Proton == TrackSelectorPID::Rejected) { - pidBayesLcToPiKP = 0; // exclude LcToPiKP + + if (!isSelectedPID(pidBayesTrackPos2Proton, pidBayesTrackNegKaon, pidBayesTrackPos1Pion)) { + pidBayesLcToPiKP = 0; // reject LcToPiKP } } - if (pidLcToPKPi == 0 && pidLcToPiKP == 0) { + if ((pidLcToPKPi == 0 && pidLcToPiKP == 0) || (pidBayesLcToPKPi == 0 && pidBayesLcToPiKP == 0)) { hfSelLcCandidate(statusLcToPKPi, statusLcToPiKP); if (applyMl) { hfMlLcToPKPiCandidate(outputMlLcToPKPi, outputMlLcToPiKP); } continue; } + if (activateQA) { registry.fill(HIST("hSelections"), 2 + aod::SelectionStep::RecoPID, candidate.pt()); } - if (pidBayesLcToPKPi == 0 && pidBayesLcToPiKP == 0) { - hfSelLcCandidate(statusLcToPKPi, statusLcToPiKP); - continue; - } - bool isSelectedMlLcToPKPi = true; bool isSelectedMlLcToPiKP = true; if (applyMl) { @@ -365,12 +452,12 @@ struct HfCandidateSelectorLc { isSelectedMlLcToPKPi = false; isSelectedMlLcToPiKP = false; - if ((pidLcToPKPi == -1 || pidLcToPKPi == 1) && (pidBayesLcToPKPi == -1 || pidBayesLcToPKPi == 1) && topolLcToPKPi) { - std::vector inputFeaturesLcToPKPi = hfMlResponse.getInputFeatures(candidate, trackPos1, trackNeg, trackPos2); + if (pidLcToPKPi == 1 && pidBayesLcToPKPi == 1 && topolLcToPKPi) { + std::vector inputFeaturesLcToPKPi = hfMlResponse.getInputFeatures(candidate, trackPos1, trackNeg, trackPos2, true); isSelectedMlLcToPKPi = hfMlResponse.isSelectedMl(inputFeaturesLcToPKPi, candidate.pt(), outputMlLcToPKPi); } - if ((pidLcToPiKP == -1 || pidLcToPiKP == 1) && (pidBayesLcToPiKP == -1 || pidBayesLcToPiKP == 1) && topolLcToPiKP) { - std::vector inputFeaturesLcToPiKP = hfMlResponse.getInputFeatures(candidate, trackPos1, trackNeg, trackPos2); + if (pidLcToPiKP == 1 && pidBayesLcToPiKP == 1 && topolLcToPiKP) { + std::vector inputFeaturesLcToPiKP = hfMlResponse.getInputFeatures(candidate, trackPos1, trackNeg, trackPos2, false); isSelectedMlLcToPiKP = hfMlResponse.isSelectedMl(inputFeaturesLcToPiKP, candidate.pt(), outputMlLcToPiKP); } @@ -386,16 +473,56 @@ struct HfCandidateSelectorLc { } } - if ((pidLcToPKPi == -1 || pidLcToPKPi == 1) && (pidBayesLcToPKPi == -1 || pidBayesLcToPKPi == 1) && isSelectedMlLcToPKPi && topolLcToPKPi) { + if (pidLcToPKPi == 1 && pidBayesLcToPKPi == 1 && isSelectedMlLcToPKPi && topolLcToPKPi && trackQualitySel) { statusLcToPKPi = 1; // identified as LcToPKPi } - if ((pidLcToPiKP == -1 || pidLcToPiKP == 1) && (pidBayesLcToPiKP == -1 || pidBayesLcToPiKP == 1) && isSelectedMlLcToPiKP && topolLcToPiKP) { + if (pidLcToPiKP == 1 && pidBayesLcToPiKP == 1 && isSelectedMlLcToPiKP && topolLcToPiKP && trackQualitySel) { statusLcToPiKP = 1; // identified as LcToPiKP } hfSelLcCandidate(statusLcToPKPi, statusLcToPiKP); } } + + /// \brief process function w/o Bayes PID with DCAFitterN + /// \param candidates Lc candidate table + /// \param tracks track table + void processNoBayesPidWithDCAFitterN(aod::HfCand3Prong const& candidates, + TracksSel const& tracks) + { + runSelectLc(candidates, tracks); + } + PROCESS_SWITCH(HfCandidateSelectorLc, processNoBayesPidWithDCAFitterN, "Process Lc selection w/o Bayes PID with DCAFitterN", true); + + /// \brief process function with Bayes PID with DCAFitterN + /// \param candidates Lc candidate table + /// \param tracks track table with Bayes PID information + void processBayesPidWithDCAFitterN(aod::HfCand3Prong const& candidates, + TracksSelBayesPid const& tracks) + { + runSelectLc(candidates, tracks); + } + PROCESS_SWITCH(HfCandidateSelectorLc, processBayesPidWithDCAFitterN, "Process Lc selection with Bayes PID with DCAFitterN", false); + + /// \brief process function w/o Bayes PID with KFParticle + /// \param candidates Lc candidate table + /// \param tracks track table + void processNoBayesPidWithKFParticle(soa::Join const& candidates, + TracksSel const& tracks) + { + runSelectLc(candidates, tracks); + } + PROCESS_SWITCH(HfCandidateSelectorLc, processNoBayesPidWithKFParticle, "Process Lc selection w/o Bayes PID with KFParticle", false); + + /// \brief process function with Bayes PID with KFParticle + /// \param candidates Lc candidate table + /// \param tracks track table with Bayes PID information + void processBayesPidWithKFParticle(soa::Join const& candidates, + TracksSelBayesPid const& tracks) + { + runSelectLc(candidates, tracks); + } + PROCESS_SWITCH(HfCandidateSelectorLc, processBayesPidWithKFParticle, "Process Lc selection with Bayes PID with KFParticle", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/TableProducer/candidateSelectorLcPidMl.cxx b/PWGHF/TableProducer/candidateSelectorLcPidMl.cxx index bc0a03ecff3..2e127ff2829 100644 --- a/PWGHF/TableProducer/candidateSelectorLcPidMl.cxx +++ b/PWGHF/TableProducer/candidateSelectorLcPidMl.cxx @@ -17,6 +17,10 @@ /// \author Vít Kučera , CERN /// \author Maja Kabus , CERN, Warsaw University of Technology +#include +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "CCDB/CcdbApi.h" #include "Framework/AnalysisTask.h" @@ -61,7 +65,7 @@ struct HfCandidateSelectorLcPidMl { // ONNX BDT Configurable applyML{"applyML", false, "Flag to enable or disable ML application"}; Configurable onnxFileLcToPiKPConf{"onnxFileLcToPiKPConf", "/cvmfs/alice.cern.ch/data/analysis/2022/vAN-20220818/PWGHF/o2/trigger/ModelHandler_onnx_LcToPKPi.onnx", "ONNX file for ML model for Lc+ candidates"}; - Configurable> thresholdBDTScoreLcToPiKP{"thresholdBDTScoreLcToPiKP", {hf_cuts_bdt_multiclass::cuts[0], hf_cuts_bdt_multiclass::nBinsPt, hf_cuts_bdt_multiclass::nCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Lc+ candidates"}; + Configurable> thresholdBDTScoreLcToPiKP{"thresholdBDTScoreLcToPiKP", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Lc+ candidates"}; Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable mlModelPathCCDB{"mlModelPathCCDB", "Analysis/PWGHF/ML/HFTrigger/Lc", "Path on CCDB"}; @@ -123,7 +127,15 @@ struct HfCandidateSelectorLcPidMl { } if (retrieveSuccess) { auto session = model.getSession(); +#if __has_include() auto inputShapes = session->GetInputShapes(); +#else + std::vector> inputShapes; + Ort::AllocatorWithDefaultOptions tmpAllocator; + for (size_t i = 0; i < session->GetInputCount(); ++i) { + inputShapes.emplace_back(session->GetInputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape()); + } +#endif if (inputShapes[0][0] < 0) { LOGF(warning, "Model for Lc with negative input shape likely because converted with hummingbird, setting it to 1."); inputShapes[0][0] = 1; diff --git a/PWGHF/TableProducer/candidateSelectorLcToK0sP.cxx b/PWGHF/TableProducer/candidateSelectorLcToK0sP.cxx index 7e8d48085f0..f1e52a18a94 100644 --- a/PWGHF/TableProducer/candidateSelectorLcToK0sP.cxx +++ b/PWGHF/TableProducer/candidateSelectorLcToK0sP.cxx @@ -17,6 +17,9 @@ /// Daniel Samitz, , Vienna /// Elisa Meninno, , Vienna +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -56,13 +59,13 @@ struct HfCandidateSelectorLcToK0sP { Configurable probBayesMinHighP{"probBayesMinHighP", 0.8, "min. Bayes probability for bachelor at high p [%]"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_lc_to_k0s_p::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_lc_to_k0s_p::cuts[0], hf_cuts_lc_to_k0s_p::nBinsPt, hf_cuts_lc_to_k0s_p::nCutVars, hf_cuts_lc_to_k0s_p::labelsPt, hf_cuts_lc_to_k0s_p::labelsCutVar}, "Lc candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_lc_to_k0s_p::Cuts[0], hf_cuts_lc_to_k0s_p::NBinsPt, hf_cuts_lc_to_k0s_p::NCutVars, hf_cuts_lc_to_k0s_p::labelsPt, hf_cuts_lc_to_k0s_p::labelsCutVar}, "Lc candidate selection per pT bin"}; // ML inference Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; Configurable> binsPtMl{"binsPtMl", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; Configurable> cutDirMl{"cutDirMl", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; - Configurable> cutsMl{"cutsMl", {hf_cuts_ml::cuts[0], hf_cuts_ml::nBinsPt, hf_cuts_ml::nCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; - Configurable nClassesMl{"nClassesMl", (int8_t)hf_cuts_ml::nCutScores, "Number of classes in ML model"}; + Configurable> cutsMl{"cutsMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable nClassesMl{"nClassesMl", static_cast(hf_cuts_ml::NCutScores), "Number of classes in ML model"}; Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; // CCDB configuration Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; diff --git a/PWGHF/TableProducer/candidateSelectorOmegac0ToOmegaKa.cxx b/PWGHF/TableProducer/candidateSelectorOmegac0ToOmegaKa.cxx new file mode 100644 index 00000000000..ce5787b730a --- /dev/null +++ b/PWGHF/TableProducer/candidateSelectorOmegac0ToOmegaKa.cxx @@ -0,0 +1,576 @@ +// 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 candidateSelectorOmegac0ToOmegaKa.cxx +/// \brief Omegac0 → Omega Ka selection task +/// \author Federica Zanone , Heidelberg University + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectorPID.h" + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::analysis; + +enum PidInfoStored { + PiFromLam = 0, + PrFromLam, + KaFromCasc, + KaFromCharm +}; + +/// Struct for applying Omegac0 -> Omega pi selection cuts +struct HfCandidateSelectorToOmegaKa { + Produces hfSelToOmegaKa; + + // LF analysis selections + Configurable radiusCascMin{"radiusCascMin", 0.5, "Min cascade radius"}; + Configurable radiusV0Min{"radiusV0Min", 1.1, "Min V0 radius"}; + Configurable cosPAV0Min{"cosPAV0Min", 0.97, "Min valueCosPA V0"}; + Configurable cosPACascMin{"cosPACascMin", 0.97, "Min value CosPA cascade"}; + Configurable dcaCascDauMax{"dcaCascDauMax", 1.0, "Max DCA cascade daughters"}; + Configurable dcaV0DauMax{"dcaV0DauMax", 1.0, "Max DCA V0 daughters"}; + Configurable dcaBachToPvMin{"dcaBachToPvMin", 0.04, "DCA Bach To PV"}; + Configurable dcaNegToPvMin{"dcaNegToPvMin", 0.06, "DCA Neg To PV"}; + Configurable dcaPosToPvMin{"dcaPosToPvMin", 0.06, "DCA Pos To PV"}; + Configurable v0MassWindow{"v0MassWindow", 0.01, "V0 mass window"}; + Configurable cascadeMassWindow{"cascadeMassWindow", 0.01, "Cascade mass window"}; + Configurable applyTrkSelLf{"applyTrkSelLf", true, "Apply track selection for LF daughters"}; + + // limit charm baryon invariant mass spectrum + Configurable invMassCharmBaryonMin{"invMassCharmBaryonMin", 2.3, "Lower limit invariant mass spectrum charm baryon"}; // 2.4 Omegac0 only + Configurable invMassCharmBaryonMax{"invMassCharmBaryonMax", 3.1, "Upper limit invariant mass spectrum charm baryon"}; + + // kinematic selections + Configurable etaTrackCharmBachMax{"etaTrackCharmBachMax", 0.8, "Max absolute value of eta for charm baryon bachelor"}; + Configurable etaTrackLFDauMax{"etaTrackLFDauMax", 1.0, "Max absolute value of eta for V0 and cascade daughters"}; + Configurable ptKaFromCascMin{"ptKaFromCascMin", 0.15, "Min pT kaon <- casc"}; + Configurable ptKaFromCharmBaryonMin{"ptKaFromCharmBaryonMin", 0.2, "Min pT kaon <- charm baryon"}; + + Configurable impactParameterXYKaFromCharmBaryonMin{"impactParameterXYKaFromCharmBaryonMin", 0., "Min dcaxy pi from charm baryon track to PV"}; + Configurable impactParameterXYKaFromCharmBaryonMax{"impactParameterXYKaFromCharmBaryonMax", 10., "Max dcaxy pi from charm baryon track to PV"}; + Configurable impactParameterZKaFromCharmBaryonMin{"impactParameterZKaFromCharmBaryonMin", 0., "Min dcaz pi from charm baryon track to PV"}; + Configurable impactParameterZKaFromCharmBaryonMax{"impactParameterZKaFromCharmBaryonMax", 10., "Max dcaz pi from charm baryon track to PV"}; + + Configurable impactParameterXYCascMin{"impactParameterXYCascMin", 0., "Min dcaxy cascade track to PV"}; + Configurable impactParameterXYCascMax{"impactParameterXYCascMax", 10., "Max dcaxy cascade track to PV"}; + Configurable impactParameterZCascMin{"impactParameterZCascMin", 0., "Min dcaz cascade track to PV"}; + Configurable impactParameterZCascMax{"impactParameterZCascMax", 10., "Max dcaz cascade track to PV"}; + + Configurable ptCandMin{"ptCandMin", 0., "Lower bound of candidate pT"}; + Configurable ptCandMax{"ptCandMax", 50., "Upper bound of candidate pT"}; + + Configurable dcaCharmBaryonDauMax{"dcaCharmBaryonDauMax", 2.0, "Max DCA charm baryon daughters"}; + + // PID options + Configurable usePidTpcOnly{"usePidTpcOnly", false, "Perform PID using only TPC"}; + Configurable usePidTpcTofCombined{"usePidTpcTofCombined", true, "Perform PID using TPC & TOF"}; + + // PID - TPC selections + Configurable ptPiPidTpcMin{"ptPiPidTpcMin", -1, "Lower bound of track pT for TPC PID for pion selection"}; + Configurable ptPiPidTpcMax{"ptPiPidTpcMax", 9999.9, "Upper bound of track pT for TPC PID for pion selection"}; + Configurable nSigmaTpcPiMax{"nSigmaTpcPiMax", 3., "Nsigma cut on TPC only for pion selection"}; + Configurable nSigmaTpcCombinedPiMax{"nSigmaTpcCombinedPiMax", 0., "Nsigma cut on TPC combined with TOF for pion selection"}; + + Configurable ptPrPidTpcMin{"ptPrPidTpcMin", -1, "Lower bound of track pT for TPC PID for proton selection"}; + Configurable ptPrPidTpcMax{"ptPrPidTpcMax", 9999.9, "Upper bound of track pT for TPC PID for proton selection"}; + Configurable nSigmaTpcPrMax{"nSigmaTpcPrMax", 3., "Nsigma cut on TPC only for proton selection"}; + Configurable nSigmaTpcCombinedPrMax{"nSigmaTpcCombinedPrMax", 0., "Nsigma cut on TPC combined with TOF for proton selection"}; + + Configurable ptKaPidTpcMin{"ptKaPidTpcMin", -1, "Lower bound of track pT for TPC PID for kaon selection"}; + Configurable ptKaPidTpcMax{"ptKaPidTpcMax", 9999.9, "Upper bound of track pT for TPC PID for kaon selection"}; + Configurable nSigmaTpcKaMax{"nSigmaTpcKaMax", 3., "Nsigma cut on TPC only for kaon selection"}; + Configurable nSigmaTpcCombinedKaMax{"nSigmaTpcCombinedKaMax", 0., "Nsigma cut on TPC combined with TOF for kaon selection"}; + + // PID - TOF selections + Configurable ptPiPidTofMin{"ptPiPidTofMin", -1, "Lower bound of track pT for TOF PID for pion selection"}; + Configurable ptPiPidTofMax{"ptPiPidTofMax", 9999.9, "Upper bound of track pT for TOF PID for pion selection"}; + Configurable nSigmaTofPiMax{"nSigmaTofPiMax", 3., "Nsigma cut on TOF only for pion selection"}; + Configurable nSigmaTofCombinedPiMax{"nSigmaTofCombinedPiMax", 0., "Nsigma cut on TOF combined with TPC for pion selection"}; + + Configurable ptPrPidTofMin{"ptPrPidTofMin", -1, "Lower bound of track pT for TOF PID for proton selection"}; + Configurable ptPrPidTofMax{"ptPrPidTofMax", 9999.9, "Upper bound of track pT for TOF PID for proton selection"}; + Configurable nSigmaTofPrMax{"nSigmaTofPrMax", 3., "Nsigma cut on TOF only for proton selection"}; + Configurable nSigmaTofCombinedPrMax{"nSigmaTofCombinedPrMax", 0., "Nsigma cut on TOF combined with TPC for proton selection"}; + + Configurable ptKaPidTofMin{"ptKaPidTofMin", -1, "Lower bound of track pT for TOF PID for kaon selection"}; + Configurable ptKaPidTofMax{"ptKaPidTofMax", 9999.9, "Upper bound of track pT for TOF PID for kaon selection"}; + Configurable nSigmaTofKaMax{"nSigmaTofKaMax", 3., "Nsigma cut on TOF only for kaon selection"}; + Configurable nSigmaTofCombinedKaMax{"nSigmaTofCombinedKaMax", 0., "Nsigma cut on TOF combined with TOF for kaon selection"}; + + // detector clusters selections + Configurable nClustersTpcMin{"nClustersTpcMin", 70, "Minimum number of TPC clusters requirement"}; + Configurable nTpcCrossedRowsMin{"nTpcCrossedRowsMin", 70, "Minimum number of TPC crossed rows requirement"}; + Configurable tpcCrossedRowsOverFindableClustersRatioMin{"tpcCrossedRowsOverFindableClustersRatioMin", 0.8, "Minimum ratio TPC crossed rows over findable clusters requirement"}; + Configurable tpcChi2PerClusterMax{"tpcChi2PerClusterMax", 4, "Maximum value of chi2 fit over TPC clusters"}; + Configurable nClustersItsMin{"nClustersItsMin", 3, "Minimum number of ITS clusters requirement for pi <- charm baryon"}; + Configurable nClustersItsInnBarrMin{"nClustersItsInnBarrMin", 1, "Minimum number of ITS clusters in inner barrel requirement for pi <- charm baryon"}; + Configurable itsChi2PerClusterMax{"itsChi2PerClusterMax", 36, "Maximum value of chi2 fit over ITS clusters for pi <- charm baryon"}; + + TrackSelectorPi selectorPion; + TrackSelectorPr selectorProton; + TrackSelectorKa selectorKaon; + + using TracksSel = soa::Join; + using TracksSelLf = soa::Join; + + HistogramRegistry registry{"registry"}; // for QA of selections + + OutputObj hInvMassCharmBaryon{TH1F("hInvMassCharmBaryon", "Charm baryon invariant mass;inv mass;entries", 500, 2.3, 3.1)}; + + void init(InitContext const&) + { + selectorPion.setRangePtTpc(ptPiPidTpcMin, ptPiPidTpcMax); + selectorPion.setRangeNSigmaTpc(-nSigmaTpcPiMax, nSigmaTpcPiMax); + selectorPion.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedPiMax, nSigmaTpcCombinedPiMax); + selectorPion.setRangePtTof(ptPiPidTofMin, ptPiPidTofMax); + selectorPion.setRangeNSigmaTof(-nSigmaTofPiMax, nSigmaTofPiMax); + selectorPion.setRangeNSigmaTofCondTpc(-nSigmaTofCombinedPiMax, nSigmaTofCombinedPiMax); + + selectorProton.setRangePtTpc(ptPrPidTpcMin, ptPrPidTpcMax); + selectorProton.setRangeNSigmaTpc(-nSigmaTpcPrMax, nSigmaTpcPrMax); + selectorProton.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedPrMax, nSigmaTpcCombinedPrMax); + selectorProton.setRangePtTof(ptPrPidTofMin, ptPrPidTofMax); + selectorProton.setRangeNSigmaTof(-nSigmaTofPrMax, nSigmaTofPrMax); + selectorProton.setRangeNSigmaTofCondTpc(-nSigmaTofCombinedPrMax, nSigmaTofCombinedPrMax); + + selectorKaon.setRangePtTpc(ptKaPidTpcMin, ptKaPidTpcMax); + selectorKaon.setRangeNSigmaTpc(-nSigmaTpcKaMax, nSigmaTpcKaMax); + selectorKaon.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedKaMax, nSigmaTpcCombinedKaMax); + selectorKaon.setRangePtTof(ptKaPidTofMin, ptKaPidTofMax); + selectorKaon.setRangeNSigmaTof(-nSigmaTofKaMax, nSigmaTofKaMax); + selectorKaon.setRangeNSigmaTofCondTpc(-nSigmaTofCombinedKaMax, nSigmaTofCombinedKaMax); + + const AxisSpec axisSel{2, -0.5, 1.5, "status"}; + + registry.add("hSelPID", "hSelPID;status;entries", {HistType::kTH1F, {{12, 0., 12.}}}); + registry.add("hStatusCheck", "Check consecutive selections status;status;entries", {HistType::kTH1F, {{12, 0., 12.}}}); + + // for QA of the selections (bin 0 -> candidates that did not pass the selection, bin 1 -> candidates that passed the selection) + registry.add("hSelSignDec", "hSelSignDec;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelEtaPosV0Dau", "hSelEtaPosV0Dau;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelEtaNegV0Dau", "hSelEtaNegV0Dau;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelEtaKaFromCasc", "hSelEtaKaFromCasc;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelEtaKaFromCharm", "hSelEtaKaFromCharm;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelRadCasc", "hSelRadCasc;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelRadV0", "hSelRadV0;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelCosPACasc", "hSelCosPACasc;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelCosPAV0", "hSelCosPAV0;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDCACascDau", "hSelDCACascDau;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDCAV0Dau", "hSelDCAV0Dau;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDCACharmDau", "hSelDCACharmDau;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDCAXYPrimKa", "hSelDCAXYPrimKa;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDCAZPrimKa", "hSelDCAZPrimKa;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDCAXYCasc", "hSelDCAXYCasc;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDCAZCasc", "hSelDCAZCasc;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelPtKaFromCasc", "hSelPtKaFromCasc;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelPtKaFromCharm", "hSelPtKaFromCharm;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelTPCQualityKaFromCharm", "hSelTPCQualityKaFromCharm;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelTPCQualityPiFromLam", "hSelTPCQualityPiFromLam;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelTPCQualityPrFromLam", "hSelTPCQualityPrFromLam;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelTPCQualityKaFromCasc", "hSelTPCQualityKaFromCasc;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelITSQualityKaFromCharm", "hSelITSQualityKaFromCharm;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelMassLam", "hSelMassLam;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelMassCasc", "hSelMassCasc;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelMassCharmBaryon", "hSelMassCharmBaryon;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDcaXYToPvV0Daughters", "hSelDcaXYToPvV0Daughters;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDcaXYToPvKaFromCasc", "hSelDcaXYToPvKaFromCasc;status;entries", {HistType::kTH1F, {axisSel}}); + } + + void process(aod::HfCandToOmegaK const& candidates, + TracksSel const& tracks, + TracksSelLf const& lfTracks) + { + + // looping over charm baryon candidates + for (const auto& candidate : candidates) { + + bool resultSelections = true; // True if the candidate passes all the selections, False otherwise + + auto trackV0PosDauId = candidate.posTrackId(); // positive V0 daughter + auto trackV0NegDauId = candidate.negTrackId(); // negative V0 daughter + auto trackKaFromCascId = candidate.bachelorId(); // kaon <- cascade + auto trackKaFromCharmId = candidate.bachelorFromCharmBaryonId(); // pion <- charm baryon + auto trackV0PosDau = lfTracks.rawIteratorAt(trackV0PosDauId); + auto trackV0NegDau = lfTracks.rawIteratorAt(trackV0NegDauId); + auto trackKaFromCasc = lfTracks.rawIteratorAt(trackKaFromCascId); + auto trackKaFromCharm = tracks.rawIteratorAt(trackKaFromCharmId); + + auto trackPiFromLam = trackV0NegDau; + auto trackPrFromLam = trackV0PosDau; + + int8_t signDecay = candidate.signDecay(); // sign of pi <- cascade + + if (signDecay > 0) { + trackPiFromLam = trackV0PosDau; + trackPrFromLam = trackV0NegDau; + registry.fill(HIST("hSelSignDec"), 1); // anti-particle decay + } else if (signDecay < 0) { + registry.fill(HIST("hSelSignDec"), 0); // particle decay + } + + // eta selection + double etaV0PosDau = candidate.etaV0PosDau(); + double etaV0NegDau = candidate.etaV0NegDau(); + double etaKaFromCasc = candidate.etaBachFromCasc(); + double etaKaFromCharmBaryon = candidate.etaBachFromCharmBaryon(); + if (std::abs(etaV0PosDau) > etaTrackLFDauMax) { + resultSelections = false; + registry.fill(HIST("hSelEtaPosV0Dau"), 0); + } else { + registry.fill(HIST("hSelEtaPosV0Dau"), 1); + } + if (std::abs(etaV0NegDau) > etaTrackLFDauMax) { + resultSelections = false; + registry.fill(HIST("hSelEtaNegV0Dau"), 0); + } else { + registry.fill(HIST("hSelEtaNegV0Dau"), 1); + } + if (std::abs(etaKaFromCasc) > etaTrackLFDauMax) { + resultSelections = false; + registry.fill(HIST("hSelEtaKaFromCasc"), 0); + } else { + registry.fill(HIST("hSelEtaKaFromCasc"), 1); + } + if (std::abs(etaKaFromCharmBaryon) > etaTrackCharmBachMax) { + resultSelections = false; + registry.fill(HIST("hSelEtaKaFromCharm"), 0); + } else { + registry.fill(HIST("hSelEtaKaFromCharm"), 1); + } + + // minimum radius cut (LFcut) + if (RecoDecay::sqrtSumOfSquares(candidate.xDecayVtxCascade(), candidate.yDecayVtxCascade()) < radiusCascMin) { + resultSelections = false; + registry.fill(HIST("hSelRadCasc"), 0); + } else { + registry.fill(HIST("hSelRadCasc"), 1); + } + if (RecoDecay::sqrtSumOfSquares(candidate.xDecayVtxV0(), candidate.yDecayVtxV0()) < radiusV0Min) { + resultSelections = false; + registry.fill(HIST("hSelRadV0"), 0); + } else { + registry.fill(HIST("hSelRadV0"), 1); + } + + // cosPA (LFcut) + if (candidate.cosPACasc() < cosPACascMin) { + resultSelections = false; + registry.fill(HIST("hSelCosPACasc"), 0); + } else { + registry.fill(HIST("hSelCosPACasc"), 1); + } + if (candidate.cosPAV0() < cosPAV0Min) { + resultSelections = false; + registry.fill(HIST("hSelCosPAV0"), 0); + } else { + registry.fill(HIST("hSelCosPAV0"), 1); + } + + // cascade and v0 daughters dca cut (LF cut) + if (candidate.dcaCascDau() > dcaCascDauMax) { + resultSelections = false; + registry.fill(HIST("hSelDCACascDau"), 0); + } else { + registry.fill(HIST("hSelDCACascDau"), 1); + } + + if (candidate.dcaV0Dau() > dcaV0DauMax) { + resultSelections = false; + registry.fill(HIST("hSelDCAV0Dau"), 0); + } else { + registry.fill(HIST("hSelDCAV0Dau"), 1); + } + + // dca charm baryon daughters cut + if (candidate.dcaCharmBaryonDau() > dcaCharmBaryonDauMax) { + resultSelections = false; + registry.fill(HIST("hSelDCACharmDau"), 0); + } else { + registry.fill(HIST("hSelDCACharmDau"), 1); + } + + // dcaXY v0 daughters to PV cut + if (std::abs(candidate.dcaXYToPvV0Dau0()) < dcaPosToPvMin || std::abs(candidate.dcaXYToPvV0Dau1()) < dcaNegToPvMin) { + resultSelections = false; + registry.fill(HIST("hSelDcaXYToPvV0Daughters"), 0); + } else { + registry.fill(HIST("hSelDcaXYToPvV0Daughters"), 1); + } + + // dcaXY ka <-- cascade to PV cut + if (std::abs(candidate.dcaXYToPvCascDau()) < dcaBachToPvMin) { + resultSelections = false; + registry.fill(HIST("hSelDcaXYToPvKaFromCasc"), 0); + } else { + registry.fill(HIST("hSelDcaXYToPvKaFromCasc"), 1); + } + + // cut on charm bachelor kaon dcaXY and dcaZ + if ((std::abs(candidate.impactParBachFromCharmBaryonXY()) < impactParameterXYKaFromCharmBaryonMin) || (std::abs(candidate.impactParBachFromCharmBaryonXY()) > impactParameterXYKaFromCharmBaryonMax)) { + resultSelections = false; + registry.fill(HIST("hSelDCAXYPrimKa"), 0); + } else { + registry.fill(HIST("hSelDCAXYPrimKa"), 1); + } + if ((std::abs(candidate.impactParBachFromCharmBaryonZ()) < impactParameterZKaFromCharmBaryonMin) || (std::abs(candidate.impactParBachFromCharmBaryonZ()) > impactParameterZKaFromCharmBaryonMax)) { + resultSelections = false; + registry.fill(HIST("hSelDCAZPrimKa"), 0); + } else { + registry.fill(HIST("hSelDCAZPrimKa"), 1); + } + + // cut on cascade dcaXY and dcaZ + if ((std::abs(candidate.impactParCascXY()) < impactParameterXYCascMin) || (std::abs(candidate.impactParCascXY()) > impactParameterXYCascMax)) { + resultSelections = false; + registry.fill(HIST("hSelDCAXYCasc"), 0); + } else { + registry.fill(HIST("hSelDCAXYCasc"), 1); + } + if ((std::abs(candidate.impactParCascZ()) < impactParameterZCascMin) || (std::abs(candidate.impactParCascZ()) > impactParameterZCascMax)) { + resultSelections = false; + registry.fill(HIST("hSelDCAZCasc"), 0); + } else { + registry.fill(HIST("hSelDCAZCasc"), 1); + } + + // pT selections + double ptKaFromCasc = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCasc(), candidate.pyBachFromCasc()); + double ptKaFromCharmBaryon = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCharmBaryon(), candidate.pyBachFromCharmBaryon()); + if (std::abs(ptKaFromCasc) < ptKaFromCascMin) { + resultSelections = false; + registry.fill(HIST("hSelPtKaFromCasc"), 0); + } else { + registry.fill(HIST("hSelPtKaFromCasc"), 1); + } + if (std::abs(ptKaFromCharmBaryon) < ptKaFromCharmBaryonMin) { + resultSelections = false; + registry.fill(HIST("hSelPtKaFromCharm"), 0); + } else { + registry.fill(HIST("hSelPtKaFromCharm"), 1); + } + + // TPC clusters selections + if (applyTrkSelLf) { + if (!isSelectedTrackTpcQuality(trackPiFromLam, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { + resultSelections = false; + registry.fill(HIST("hSelTPCQualityPiFromLam"), 0); + } else { + registry.fill(HIST("hSelTPCQualityPiFromLam"), 1); + } + if (!isSelectedTrackTpcQuality(trackPrFromLam, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { + resultSelections = false; + registry.fill(HIST("hSelTPCQualityPrFromLam"), 0); + } else { + registry.fill(HIST("hSelTPCQualityPrFromLam"), 1); + } + if (!isSelectedTrackTpcQuality(trackKaFromCasc, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { + resultSelections = false; + registry.fill(HIST("hSelTPCQualityKaFromCasc"), 0); + } else { + registry.fill(HIST("hSelTPCQualityKaFromCasc"), 1); + } + } + if (!isSelectedTrackTpcQuality(trackKaFromCharm, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { + resultSelections = false; + registry.fill(HIST("hSelTPCQualityKaFromCharm"), 0); + } else { + registry.fill(HIST("hSelTPCQualityKaFromCharm"), 1); + } + + // ITS clusters selection + if (!isSelectedTrackItsQuality(trackKaFromCharm, nClustersItsMin, itsChi2PerClusterMax) || trackKaFromCharm.itsNClsInnerBarrel() < nClustersItsInnBarrMin) { + resultSelections = false; + registry.fill(HIST("hSelITSQualityKaFromCharm"), 0); + } else { + registry.fill(HIST("hSelITSQualityKaFromCharm"), 1); + } + + // track-level PID selection + + // for TrackSelectorPID + int statusPidPrFromLam = -999; + int statusPidPiFromLam = -999; + int statusPidKaFromCasc = -999; + int statusPidKaFromCharmBaryon = -999; + + bool statusPidLambda = false; + bool statusPidCascade = false; + bool statusPidCharmBaryon = false; + + int infoTpcStored = 0; + int infoTofStored = 0; + + if (usePidTpcOnly == usePidTpcTofCombined) { + LOGF(fatal, "Check the PID configurables, usePidTpcOnly and usePidTpcTofCombined can't have the same value"); + } + + if (trackPiFromLam.hasTPC()) { + SETBIT(infoTpcStored, PiFromLam); + } + if (trackPrFromLam.hasTPC()) { + SETBIT(infoTpcStored, PrFromLam); + } + if (trackKaFromCasc.hasTPC()) { + SETBIT(infoTpcStored, KaFromCasc); + } + if (trackKaFromCharm.hasTPC()) { + SETBIT(infoTpcStored, KaFromCharm); + } + if (trackPiFromLam.hasTOF()) { + SETBIT(infoTofStored, PiFromLam); + } + if (trackPrFromLam.hasTOF()) { + SETBIT(infoTofStored, PrFromLam); + } + if (trackKaFromCasc.hasTOF()) { + SETBIT(infoTofStored, KaFromCasc); + } + if (trackKaFromCharm.hasTOF()) { + SETBIT(infoTofStored, KaFromCharm); + } + + if (usePidTpcOnly) { + statusPidPrFromLam = selectorProton.statusTpc(trackPrFromLam); + statusPidPiFromLam = selectorPion.statusTpc(trackPiFromLam); + statusPidKaFromCasc = selectorKaon.statusTpc(trackKaFromCasc); + statusPidKaFromCharmBaryon = selectorKaon.statusTpc(trackKaFromCharm); + } else if (usePidTpcTofCombined) { + statusPidPrFromLam = selectorProton.statusTpcOrTof(trackPrFromLam); + statusPidPiFromLam = selectorPion.statusTpcOrTof(trackPiFromLam); + statusPidKaFromCasc = selectorKaon.statusTpcOrTof(trackKaFromCasc); + statusPidKaFromCharmBaryon = selectorKaon.statusTpcOrTof(trackKaFromCharm); + } + + if (statusPidPrFromLam == TrackSelectorPID::Accepted && statusPidPiFromLam == TrackSelectorPID::Accepted) { + statusPidLambda = true; + if (resultSelections) { + registry.fill(HIST("hStatusCheck"), 0.5); + } + } + + if (statusPidPrFromLam == TrackSelectorPID::Accepted && statusPidPiFromLam == TrackSelectorPID::Accepted && statusPidKaFromCasc == TrackSelectorPID::Accepted) { + statusPidCascade = true; + if (resultSelections) { + registry.fill(HIST("hStatusCheck"), 1.5); + } + } + + if (statusPidPrFromLam == TrackSelectorPID::Accepted && statusPidPiFromLam == TrackSelectorPID::Accepted && statusPidKaFromCasc == TrackSelectorPID::Accepted && statusPidKaFromCharmBaryon == TrackSelectorPID::Accepted) { + statusPidCharmBaryon = true; + if (resultSelections) { + registry.fill(HIST("hStatusCheck"), 2.5); + } + } + + // invariant mass cuts + bool statusInvMassLambda = false; + bool statusInvMassCascade = false; + bool statusInvMassCharmBaryon = false; + + double invMassLambda = candidate.invMassLambda(); + double invMassCascade = candidate.invMassCascade(); + double invMassCharmBaryon = candidate.invMassCharmBaryon(); + + if (std::abs(invMassLambda - o2::constants::physics::MassLambda0) < v0MassWindow) { + statusInvMassLambda = true; + registry.fill(HIST("hSelMassLam"), 1); + if (statusPidLambda && statusPidCascade && statusPidCharmBaryon && resultSelections) { + registry.fill(HIST("hStatusCheck"), 3.5); + } + } else { + registry.fill(HIST("hSelMassLam"), 0); + } + + if (std::abs(invMassCascade - o2::constants::physics::MassOmegaMinus) < cascadeMassWindow) { + statusInvMassCascade = true; + registry.fill(HIST("hSelMassCasc"), 1); + if (statusPidLambda && statusPidCascade && statusPidCharmBaryon && statusInvMassLambda && resultSelections) { + registry.fill(HIST("hStatusCheck"), 4.5); + } + } else { + registry.fill(HIST("hSelMassCasc"), 0); + } + + if ((invMassCharmBaryon >= invMassCharmBaryonMin) && (invMassCharmBaryon <= invMassCharmBaryonMax)) { + statusInvMassCharmBaryon = true; + registry.fill(HIST("hSelMassCharmBaryon"), 1); + if (statusPidLambda && statusPidCascade && statusPidCharmBaryon && statusInvMassLambda && statusInvMassCascade && resultSelections) { + registry.fill(HIST("hStatusCheck"), 5.5); + } + } else { + registry.fill(HIST("hSelMassCharmBaryon"), 0); + } + + hfSelToOmegaKa(statusPidLambda, statusPidCascade, statusPidCharmBaryon, statusInvMassLambda, statusInvMassCascade, statusInvMassCharmBaryon, resultSelections, infoTpcStored, infoTofStored, + trackKaFromCharm.tpcNSigmaKa(), trackKaFromCasc.tpcNSigmaKa(), trackPiFromLam.tpcNSigmaPi(), trackPrFromLam.tpcNSigmaPr(), + trackKaFromCharm.tofNSigmaKa(), trackKaFromCasc.tofNSigmaKa(), trackPiFromLam.tofNSigmaPi(), trackPrFromLam.tofNSigmaPr()); + + if (resultSelections) { + if (!statusPidLambda) { + registry.fill(HIST("hSelPID"), 0.5); + } + if (statusPidLambda) { + registry.fill(HIST("hSelPID"), 1.5); + } + if (!statusPidCascade) { + registry.fill(HIST("hSelPID"), 2.5); + } + if (statusPidCascade) { + registry.fill(HIST("hSelPID"), 3.5); + } + if (!statusPidCharmBaryon) { + registry.fill(HIST("hSelPID"), 4.5); + } + if (statusPidCharmBaryon) { + registry.fill(HIST("hSelPID"), 5.5); + } + if (!statusInvMassLambda) { + registry.fill(HIST("hSelPID"), 6.5); + } + if (statusInvMassLambda) { + registry.fill(HIST("hSelPID"), 7.5); + } + if (!statusInvMassCascade) { + registry.fill(HIST("hSelPID"), 8.5); + } + if (statusInvMassCascade) { + registry.fill(HIST("hSelPID"), 9.5); + } + if (!statusInvMassCharmBaryon) { + registry.fill(HIST("hSelPID"), 10.5); + } + if (statusInvMassCharmBaryon) { + registry.fill(HIST("hSelPID"), 11.5); + } + } + + if (statusPidLambda && statusPidCascade && statusPidCharmBaryon && statusInvMassLambda && statusInvMassCascade && statusInvMassCharmBaryon && resultSelections) { + hInvMassCharmBaryon->Fill(invMassCharmBaryon); + } + } + } // end process +}; // end struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/candidateSelectorOmegac0ToOmegaPi.cxx b/PWGHF/TableProducer/candidateSelectorOmegac0ToOmegaPi.cxx new file mode 100644 index 00000000000..7ef19ae4032 --- /dev/null +++ b/PWGHF/TableProducer/candidateSelectorOmegac0ToOmegaPi.cxx @@ -0,0 +1,830 @@ +// 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 candidateSelectorOmegac0ToOmegaPi.cxx +/// \brief Omegac0 → Omega Pi selection task +/// \author Federica Zanone , Heidelberg University +/// \author Ruiqi Yin , Fudan University +/// \author Yunfan Liu , China University of Geosciences +/// \author Fabio Catalano , University of Houston + +#include +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectorPID.h" + +#include "PWGHF/Core/HfMlResponse.h" +#include "PWGHF/Core/HfMlResponseOmegacToOmegaPi.h" + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::analysis; + +enum PidInfoStored { + PiFromLam = 0, + PrFromLam, + KaFromCasc, + PiFromCharm +}; + +/// Struct for applying Omegac0 -> Omega pi selection cuts +struct HfCandidateSelectorToOmegaPi { + Produces hfSelToOmegaPi; + Produces hfMlSelToOmegaPi; + + // LF analysis selections + Configurable radiusCascMin{"radiusCascMin", 0.5, "Min cascade radius"}; + Configurable radiusV0Min{"radiusV0Min", 1.1, "Min V0 radius"}; + Configurable cosPAV0Min{"cosPAV0Min", 0.97, "Min valueCosPA V0"}; + Configurable cosPACascMin{"cosPACascMin", 0.97, "Min value CosPA cascade"}; + Configurable dcaCascDauMax{"dcaCascDauMax", 1.0, "Max DCA cascade daughters"}; + Configurable dcaV0DauMax{"dcaV0DauMax", 1.0, "Max DCA V0 daughters"}; + Configurable dcaBachToPvMin{"dcaBachToPvMin", 0.04, "DCA Bach To PV"}; + Configurable dcaNegToPvMin{"dcaNegToPvMin", 0.06, "DCA Neg To PV"}; + Configurable dcaPosToPvMin{"dcaPosToPvMin", 0.06, "DCA Pos To PV"}; + Configurable v0MassWindow{"v0MassWindow", 0.01, "V0 mass window"}; + Configurable cascadeMassWindow{"cascadeMassWindow", 0.01, "Cascade mass window"}; + Configurable applyTrkSelLf{"applyTrkSelLf", true, "Apply track selection for LF daughters"}; + + // limit charm baryon invariant mass spectrum + Configurable invMassCharmBaryonMin{"invMassCharmBaryonMin", 2.3, "Lower limit invariant mass spectrum charm baryon"}; // 2.4 Omegac0 only + Configurable invMassCharmBaryonMax{"invMassCharmBaryonMax", 3.1, "Upper limit invariant mass spectrum charm baryon"}; + + // kinematic selections + Configurable etaTrackCharmBachMax{"etaTrackCharmBachMax", 0.8, "Max absolute value of eta for charm baryon bachelor"}; + Configurable etaTrackLFDauMax{"etaTrackLFDauMax", 1.0, "Max absolute value of eta for V0 and cascade daughters"}; + Configurable ptKaFromCascMin{"ptKaFromCascMin", 0.15, "Min pT kaon <- casc"}; + Configurable ptPiFromCharmBaryonMin{"ptPiFromCharmBaryonMin", 0.2, "Min pT pi <- charm baryon"}; + + Configurable impactParameterXYPiFromCharmBaryonMin{"impactParameterXYPiFromCharmBaryonMin", 0., "Min dcaxy pi from charm baryon track to PV"}; + Configurable impactParameterXYPiFromCharmBaryonMax{"impactParameterXYPiFromCharmBaryonMax", 10., "Max dcaxy pi from charm baryon track to PV"}; + Configurable impactParameterZPiFromCharmBaryonMin{"impactParameterZPiFromCharmBaryonMin", 0., "Min dcaz pi from charm baryon track to PV"}; + Configurable impactParameterZPiFromCharmBaryonMax{"impactParameterZPiFromCharmBaryonMax", 10., "Max dcaz pi from charm baryon track to PV"}; + Configurable ptPionMin{"ptPionMin", 0., "Lower bound of Pion from Charmbaryon pT"}; + Configurable impactParameterXYCascMin{"impactParameterXYCascMin", 0., "Min dcaxy cascade track to PV"}; + Configurable impactParameterXYCascMax{"impactParameterXYCascMax", 10., "Max dcaxy cascade track to PV"}; + Configurable impactParameterZCascMin{"impactParameterZCascMin", 0., "Min dcaz cascade track to PV"}; + Configurable impactParameterZCascMax{"impactParameterZCascMax", 10., "Max dcaz cascade track to PV"}; + + Configurable ptCandMin{"ptCandMin", 0., "Lower bound of candidate pT"}; + Configurable ptCandMax{"ptCandMax", 50., "Upper bound of candidate pT"}; + + Configurable dcaCharmBaryonDauMax{"dcaCharmBaryonDauMax", 2.0, "Max DCA charm baryon daughters"}; + + // PID options + Configurable usePidTpcOnly{"usePidTpcOnly", false, "Perform PID using only TPC"}; + Configurable usePidTpcTofCombined{"usePidTpcTofCombined", true, "Perform PID using TPC & TOF"}; + + // PID - TPC selections + Configurable ptPiPidTpcMin{"ptPiPidTpcMin", -1, "Lower bound of track pT for TPC PID for pion selection"}; + Configurable ptPiPidTpcMax{"ptPiPidTpcMax", 9999.9, "Upper bound of track pT for TPC PID for pion selection"}; + Configurable nSigmaTpcPiMax{"nSigmaTpcPiMax", 3., "Nsigma cut on TPC only for pion selection"}; + Configurable nSigmaTpcCombinedPiMax{"nSigmaTpcCombinedPiMax", 0., "Nsigma cut on TPC combined with TOF for pion selection"}; + + Configurable ptPrPidTpcMin{"ptPrPidTpcMin", -1, "Lower bound of track pT for TPC PID for proton selection"}; + Configurable ptPrPidTpcMax{"ptPrPidTpcMax", 9999.9, "Upper bound of track pT for TPC PID for proton selection"}; + Configurable nSigmaTpcPrMax{"nSigmaTpcPrMax", 3., "Nsigma cut on TPC only for proton selection"}; + Configurable nSigmaTpcCombinedPrMax{"nSigmaTpcCombinedPrMax", 0., "Nsigma cut on TPC combined with TOF for proton selection"}; + + Configurable ptKaPidTpcMin{"ptKaPidTpcMin", -1, "Lower bound of track pT for TPC PID for kaon selection"}; + Configurable ptKaPidTpcMax{"ptKaPidTpcMax", 9999.9, "Upper bound of track pT for TPC PID for kaon selection"}; + Configurable nSigmaTpcKaMax{"nSigmaTpcKaMax", 3., "Nsigma cut on TPC only for kaon selection"}; + Configurable nSigmaTpcCombinedKaMax{"nSigmaTpcCombinedKaMax", 0., "Nsigma cut on TPC combined with TOF for kaon selection"}; + + // PID - TOF selections + Configurable ptPiPidTofMin{"ptPiPidTofMin", -1, "Lower bound of track pT for TOF PID for pion selection"}; + Configurable ptPiPidTofMax{"ptPiPidTofMax", 9999.9, "Upper bound of track pT for TOF PID for pion selection"}; + Configurable nSigmaTofPiMax{"nSigmaTofPiMax", 3., "Nsigma cut on TOF only for pion selection"}; + Configurable nSigmaTofCombinedPiMax{"nSigmaTofCombinedPiMax", 0., "Nsigma cut on TOF combined with TPC for pion selection"}; + + Configurable ptPrPidTofMin{"ptPrPidTofMin", -1, "Lower bound of track pT for TOF PID for proton selection"}; + Configurable ptPrPidTofMax{"ptPrPidTofMax", 9999.9, "Upper bound of track pT for TOF PID for proton selection"}; + Configurable nSigmaTofPrMax{"nSigmaTofPrMax", 3., "Nsigma cut on TOF only for proton selection"}; + Configurable nSigmaTofCombinedPrMax{"nSigmaTofCombinedPrMax", 0., "Nsigma cut on TOF combined with TPC for proton selection"}; + + Configurable ptKaPidTofMin{"ptKaPidTofMin", -1, "Lower bound of track pT for TOF PID for kaon selection"}; + Configurable ptKaPidTofMax{"ptKaPidTofMax", 9999.9, "Upper bound of track pT for TOF PID for kaon selection"}; + Configurable nSigmaTofKaMax{"nSigmaTofKaMax", 3., "Nsigma cut on TOF only for kaon selection"}; + Configurable nSigmaTofCombinedKaMax{"nSigmaTofCombinedKaMax", 0., "Nsigma cut on TOF combined with TOF for kaon selection"}; + + // detector clusters selections + Configurable nClustersTpcMin{"nClustersTpcMin", 70, "Minimum number of TPC clusters requirement"}; + Configurable nTpcCrossedRowsMin{"nTpcCrossedRowsMin", 70, "Minimum number of TPC crossed rows requirement"}; + Configurable tpcCrossedRowsOverFindableClustersRatioMin{"tpcCrossedRowsOverFindableClustersRatioMin", 0.8, "Minimum ratio TPC crossed rows over findable clusters requirement"}; + Configurable tpcChi2PerClusterMax{"tpcChi2PerClusterMax", 4, "Maximum value of chi2 fit over TPC clusters"}; + Configurable nClustersItsMin{"nClustersItsMin", 3, "Minimum number of ITS clusters requirement for pi <- charm baryon"}; + Configurable nClustersItsInnBarrMin{"nClustersItsInnBarrMin", 1, "Minimum number of ITS clusters in inner barrel requirement for pi <- charm baryon"}; + Configurable itsChi2PerClusterMax{"itsChi2PerClusterMax", 36, "Maximum value of chi2 fit over ITS clusters for pi <- charm baryon"}; + struct : ConfigurableGroup { + //// KF selection + std::string prefix = "kfSel"; + Configurable applyKFpreselections{"applyKFpreselections", false, "Apply KFParticle related rejection"}; + Configurable applyCompetingCascRejection{"applyCompetingCascRejection", false, "Apply competing Xi(for Omegac0) rejection"}; + Configurable cascadeRejMassWindow{"cascadeRejMassWindow", 0.01, "competing Xi(for Omegac0) rejection mass window"}; + Configurable v0LdlMin{"v0LdlMin", 3., "Minimum value of l/dl of V0"}; // l/dl and Chi2 are to be determined + Configurable cascLdlMin{"cascLdlMin", 1., "Minimum value of l/dl of casc"}; + Configurable omegacLdlMax{"omegacLdlMax", 5., "Maximum value of l/dl of Omegac"}; + Configurable cTauOmegacMax{"cTauOmegacMax", 0.4, "lifetime τ of Omegac"}; + Configurable v0Chi2OverNdfMax{"v0Chi2OverNdfMax", 100., "Maximum chi2Geo/NDF of V0"}; + Configurable cascChi2OverNdfMax{"cascChi2OverNdfMax", 100., "Maximum chi2Geo/NDF of casc"}; + Configurable omegacChi2OverNdfMax{"omegacChi2OverNdfMax", 100., "Maximum chi2Geo/NDF of Omegac"}; + Configurable chi2TopoV0ToCascMax{"chi2TopoV0ToCascMax", 100., "Maximum chi2Topo/NDF of V0ToCas"}; + Configurable chi2TopoOmegacToPvMax{"chi2TopoOmegacToPvMax", 100., "Maximum chi2Topo/NDF of OmegacToPv"}; + Configurable chi2TopoCascToOmegacMax{"chi2TopoCascToOmegacMax", 100., "Maximum chi2Topo/NDF of CascToOmegac"}; + Configurable chi2TopoCascToPvMax{"chi2TopoCascToPvMax", 100., "Maximum chi2Topo/NDF of CascToPv"}; + Configurable decayLenXYOmegacMax{"decayLenXYOmegacMax", 1.5, "Maximum decay lengthXY of Omegac"}; + Configurable decayLenXYCascMin{"decayLenXYCascMin", 1., "Minimum decay lengthXY of Cascade"}; + Configurable decayLenXYLambdaMin{"decayLenXYLambdaMin", 0., "Minimum decay lengthXY of V0"}; + Configurable cosPaCascToOmegacMin{"cosPaCascToOmegacMin", 0.995, "Minimum cosPA of cascade<-Omegac"}; + Configurable cosPaV0ToCascMin{"cosPaV0ToCascMin", 0.99, "Minimum cosPA of V0<-cascade"}; + } KfconfigurableGroup; + // topological cuts + Configurable> binsPt{"binsPt", std::vector{hf_cuts_omegac_to_omega_pi::vecBinsPt}, "pT bin limits"}; + Configurable> cuts{"cuts", {hf_cuts_omegac_to_omega_pi::Cuts[0], hf_cuts_omegac_to_omega_pi::NBinsPt, hf_cuts_omegac_to_omega_pi::NCutVars, hf_cuts_omegac_to_omega_pi::labelsPt, hf_cuts_omegac_to_omega_pi::labelsCutVar}, "OmegaC0 candidate selection per pT bin"}; + // ML inference + Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; + Configurable> binsPtMl{"binsPtMl", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; + Configurable> cutDirMl{"cutDirMl", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; + Configurable> cutsMl{"cutsMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable nClassesMl{"nClassesMl", static_cast(hf_cuts_ml::NCutScores), "Number of classes in ML model"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; + // CCDB configuration + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"EventFiltering/PWGHF/BDTOmegac0"}, "Paths of models on CCDB"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_Omegac0ToOmegaPi.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + + o2::analysis::HfMlResponseOmegacToOmegaPi hfMlResponse; + std::vector outputMlOmegac = {}; + o2::ccdb::CcdbApi ccdbApi; + + TrackSelectorPi selectorPion; + TrackSelectorPr selectorProton; + TrackSelectorKa selectorKaon; + + using TracksSel = soa::Join; + using TracksSelLf = soa::Join; + + HistogramRegistry registry{"registry"}; // for QA of selections + + OutputObj hInvMassCharmBaryon{TH1D("hInvMassCharmBaryon", "Charm baryon invariant mass;inv mass;entries", 500, 2.3, 3.1)}; + OutputObj hPtCharmBaryon{TH1D("hPtCharmBaryon", "Charm baryon transverse momentum before sel;Pt;entries", 8000, 0., 80)}; + + void init(InitContext const&) + { + std::array processesSelector = {doprocessOmegac0SelectorWithDCAFitter, doprocessOmegac0SelectorWithKFParticle}; + const int nProcessesSelector = std::accumulate(processesSelector.begin(), processesSelector.end(), 0); + if (nProcessesSelector != 1) { + LOGP(fatal, "At most one process function for selector can be enabled at a time."); + } + + selectorPion.setRangePtTpc(ptPiPidTpcMin, ptPiPidTpcMax); + selectorPion.setRangeNSigmaTpc(-nSigmaTpcPiMax, nSigmaTpcPiMax); + selectorPion.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedPiMax, nSigmaTpcCombinedPiMax); + selectorPion.setRangePtTof(ptPiPidTofMin, ptPiPidTofMax); + selectorPion.setRangeNSigmaTof(-nSigmaTofPiMax, nSigmaTofPiMax); + selectorPion.setRangeNSigmaTofCondTpc(-nSigmaTofCombinedPiMax, nSigmaTofCombinedPiMax); + + selectorProton.setRangePtTpc(ptPrPidTpcMin, ptPrPidTpcMax); + selectorProton.setRangeNSigmaTpc(-nSigmaTpcPrMax, nSigmaTpcPrMax); + selectorProton.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedPrMax, nSigmaTpcCombinedPrMax); + selectorProton.setRangePtTof(ptPrPidTofMin, ptPrPidTofMax); + selectorProton.setRangeNSigmaTof(-nSigmaTofPrMax, nSigmaTofPrMax); + selectorProton.setRangeNSigmaTofCondTpc(-nSigmaTofCombinedPrMax, nSigmaTofCombinedPrMax); + + selectorKaon.setRangePtTpc(ptKaPidTpcMin, ptKaPidTpcMax); + selectorKaon.setRangeNSigmaTpc(-nSigmaTpcKaMax, nSigmaTpcKaMax); + selectorKaon.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedKaMax, nSigmaTpcCombinedKaMax); + selectorKaon.setRangePtTof(ptKaPidTofMin, ptKaPidTofMax); + selectorKaon.setRangeNSigmaTof(-nSigmaTofKaMax, nSigmaTofKaMax); + selectorKaon.setRangeNSigmaTofCondTpc(-nSigmaTofCombinedKaMax, nSigmaTofCombinedKaMax); + + const AxisSpec axisSel{2, -0.5, 1.5, "status"}; + + registry.add("hSelPID", "hSelPID;status;entries", {HistType::kTH1D, {{12, 0., 12.}}}); + registry.add("hStatusCheck", "Check consecutive selections status;status;entries", {HistType::kTH1D, {{12, 0., 12.}}}); + + // for QA of the selections (bin 0 -> candidates that did not pass the selection, bin 1 -> candidates that passed the selection) + registry.add("hSelSignDec", "hSelSignDec;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelEtaPosV0Dau", "hSelEtaPosV0Dau;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelEtaNegV0Dau", "hSelEtaNegV0Dau;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelEtaKaFromCasc", "hSelEtaKaFromCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelEtaPiFromCharm", "hSelEtaPiFromCharm;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelRadCasc", "hSelRadCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelRadV0", "hSelRadV0;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelCosPACasc", "hSelCosPACasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelCosPAV0", "hSelCosPAV0;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDCACascDau", "hSelDCACascDau;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDCAV0Dau", "hSelDCAV0Dau;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDCACharmDau", "hSelDCACharmDau;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDCAXYPrimPi", "hSelDCAXYPrimPi;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDCAZPrimPi", "hSelDCAZPrimPi;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDCAXYCasc", "hSelDCAXYCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDCAZCasc", "hSelDCAZCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelPtKaFromCasc", "hSelPtKaFromCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelPtPiFromCharm", "hSelPtPiFromCharm;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelTPCQualityPiFromCharm", "hSelTPCQualityPiFromCharm;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelTPCQualityPiFromLam", "hSelTPCQualityPiFromLam;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelTPCQualityPrFromLam", "hSelTPCQualityPrFromLam;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelTPCQualityKaFromCasc", "hSelTPCQualityKaFromCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelITSQualityPiFromCharm", "hSelITSQualityPiFromCharm;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelMassLam", "hSelMassLam;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelMassCasc", "hSelMassCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelMassCharmBaryon", "hSelMassCharmBaryon;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDcaXYToPvV0Daughters", "hSelDcaXYToPvV0Daughters;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDcaXYToPvKaFromCasc", "hSelDcaXYToPvKaFromCasc;status;entries", {HistType::kTH1D, {axisSel}}); + + if (KfconfigurableGroup.applyKFpreselections) { + registry.add("hSelPtOmegac", "hSelPtOmegac;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelCompetingCasc", "hSelCompetingCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelKFstatus", "hSelKFstatus;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelV0_Casc_Omegacldl", "hSelV0_Casc_Omegacldl;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelctauOmegac", "hSelctauOmegac;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelChi2GeooverNDFV0_Casc_Omegac", "hSelChi2GeooverNDFV0_Casc_Omegac;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelChi2TopooverNDFV0_Casc_Omegac", "hSelChi2TopooverNDFV0_Casc_Omegac;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSeldecayLenXYOmegac_Casc_V0", "hSeldecayLenXYOmegac_Casc_V0;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelcosPaCascToOmegac_V0ToCasc", "hSelcosPaCascToOmegac_V0ToCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hInvMassXiMinus_rej_cut", "hInvMassXiMinus_rej_cut", kTH1D, {{1000, 1.25f, 1.65f}}); + } + if (applyMl) { + registry.add("hBDTScoreTest1", "hBDTScoreTest1", {HistType::kTH1D, {{100, 0.0f, 1.0f, "score"}}}); + hfMlResponse.configure(binsPtMl, cutsMl, cutDirMl, nClassesMl); + if (loadModelsFromCCDB) { + ccdbApi.init(ccdbUrl); + hfMlResponse.setModelPathsCCDB(onnxFileNames, ccdbApi, modelPathsCCDB, timestampCCDB); + } else { + hfMlResponse.setModelPathsLocal(onnxFileNames); + } + hfMlResponse.cacheInputFeaturesIndices(namesInputFeatures); + hfMlResponse.init(); + } + } + // for pT-dependent cuts (other selections will move into this in futrue) + // \param hfCandOmegac is candidate + // return true if candidate passes all cuts + template + bool selectionTopol(const T1& hfCandOmegac) + { + auto candpT = hfCandOmegac.ptCharmBaryon(); + auto pionPtFromOmegac = hfCandOmegac.ptPiFromCharmBaryon(); + int pTBin = findBin(binsPt, candpT); + if (pTBin == -1) { + return false; + } + + // check that the candidate pT is within the analysis range + if (candpT <= ptCandMin || candpT >= ptCandMax) { + return false; + } + + // check that the candidate pT is within the analysis range + if (pionPtFromOmegac < cuts->get(pTBin, "pT pi from Omegac")) { + registry.fill(HIST("hSelPtPiFromCharm"), 0); + return false; + } else { + registry.fill(HIST("hSelPtPiFromCharm"), 1); + } + + return true; + } // end template + + template + void runOmegac0Selector(const Candidates& candidates, + TracksSel const& tracks, + TracksSelLf const& lfTracks) + { + // looping over charm baryon candidates + for (const auto& candidate : candidates) { + // initializing selection flags + bool statusPidLambda = false; + bool statusPidCascade = false; + bool statusPidCharmBaryon = false; + + bool statusInvMassLambda = false; + bool statusInvMassCascade = false; + bool statusInvMassCharmBaryon = false; + + bool resultSelections = true; // True if the candidate passes all the selections, False otherwise + + int infoTpcStored = 0; + int infoTofStored = 0; + + auto trackV0PosDauId = candidate.posTrackId(); // positive V0 daughter + auto trackV0NegDauId = candidate.negTrackId(); // negative V0 daughter + auto trackKaFromCascId = candidate.bachelorId(); // kaon <- cascade + auto trackPiFromCharmId = candidate.bachelorFromCharmBaryonId(); // pion <- charm baryon + auto trackV0PosDau = lfTracks.rawIteratorAt(trackV0PosDauId); + auto trackV0NegDau = lfTracks.rawIteratorAt(trackV0NegDauId); + auto trackKaFromCasc = lfTracks.rawIteratorAt(trackKaFromCascId); + auto trackPiFromCharm = tracks.rawIteratorAt(trackPiFromCharmId); + + auto trackPiFromLam = trackV0NegDau; + auto trackPrFromLam = trackV0PosDau; + + auto ptCand = candidate.ptCharmBaryon(); + int8_t signDecay = candidate.signDecay(); // sign of pi <- cascade + + if (signDecay > 0) { + trackPiFromLam = trackV0PosDau; + trackPrFromLam = trackV0NegDau; + registry.fill(HIST("hSelSignDec"), 1); // anti-particle decay + } else if (signDecay < 0) { + registry.fill(HIST("hSelSignDec"), 0); // particle decay + } + + // pt-dependent selection + if (!selectionTopol(candidate)) { + resultSelections = false; + hfSelToOmegaPi(statusPidLambda, statusPidCascade, statusPidCharmBaryon, statusInvMassLambda, statusInvMassCascade, statusInvMassCharmBaryon, resultSelections, infoTpcStored, infoTofStored, + trackPiFromCharm.tpcNSigmaPi(), trackKaFromCasc.tpcNSigmaKa(), trackPiFromLam.tpcNSigmaPi(), trackPrFromLam.tpcNSigmaPr(), + trackPiFromCharm.tofNSigmaPi(), trackKaFromCasc.tofNSigmaKa(), trackPiFromLam.tofNSigmaPi(), trackPrFromLam.tofNSigmaPr()); + if constexpr (ConstructMethod == hf_cand_casc_lf::ConstructMethod::KfParticle) { + if (applyMl) { + hfMlSelToOmegaPi(outputMlOmegac); + } + } + continue; + } + + // eta selection + double etaV0PosDau = candidate.etaV0PosDau(); + double etaV0NegDau = candidate.etaV0NegDau(); + double etaKaFromCasc = candidate.etaBachFromCasc(); + double etaPiFromCharmBaryon = candidate.etaBachFromCharmBaryon(); + if (std::abs(etaV0PosDau) > etaTrackLFDauMax) { + resultSelections = false; + registry.fill(HIST("hSelEtaPosV0Dau"), 0); + } else { + registry.fill(HIST("hSelEtaPosV0Dau"), 1); + } + if (std::abs(etaV0NegDau) > etaTrackLFDauMax) { + resultSelections = false; + registry.fill(HIST("hSelEtaNegV0Dau"), 0); + } else { + registry.fill(HIST("hSelEtaNegV0Dau"), 1); + } + if (std::abs(etaKaFromCasc) > etaTrackLFDauMax) { + resultSelections = false; + registry.fill(HIST("hSelEtaKaFromCasc"), 0); + } else { + registry.fill(HIST("hSelEtaKaFromCasc"), 1); + } + if (std::abs(etaPiFromCharmBaryon) > etaTrackCharmBachMax) { + resultSelections = false; + registry.fill(HIST("hSelEtaPiFromCharm"), 0); + } else { + registry.fill(HIST("hSelEtaPiFromCharm"), 1); + } + + // minimum radius cut (LFcut) + if (RecoDecay::sqrtSumOfSquares(candidate.xDecayVtxCascade(), candidate.yDecayVtxCascade()) < radiusCascMin) { + resultSelections = false; + registry.fill(HIST("hSelRadCasc"), 0); + } else { + registry.fill(HIST("hSelRadCasc"), 1); + } + if (RecoDecay::sqrtSumOfSquares(candidate.xDecayVtxV0(), candidate.yDecayVtxV0()) < radiusV0Min) { + resultSelections = false; + registry.fill(HIST("hSelRadV0"), 0); + } else { + registry.fill(HIST("hSelRadV0"), 1); + } + + // cosPA (LFcut) + if (candidate.cosPACasc() < cosPACascMin) { + resultSelections = false; + registry.fill(HIST("hSelCosPACasc"), 0); + } else { + registry.fill(HIST("hSelCosPACasc"), 1); + } + if (candidate.cosPAV0() < cosPAV0Min) { + resultSelections = false; + registry.fill(HIST("hSelCosPAV0"), 0); + } else { + registry.fill(HIST("hSelCosPAV0"), 1); + } + + // cascade and v0 daughters dca cut (LF cut) + if (candidate.dcaCascDau() > dcaCascDauMax) { + resultSelections = false; + registry.fill(HIST("hSelDCACascDau"), 0); + } else { + registry.fill(HIST("hSelDCACascDau"), 1); + } + + if (candidate.dcaV0Dau() > dcaV0DauMax) { + resultSelections = false; + registry.fill(HIST("hSelDCAV0Dau"), 0); + } else { + registry.fill(HIST("hSelDCAV0Dau"), 1); + } + + // dca charm baryon daughters cut + if (candidate.dcaCharmBaryonDau() > dcaCharmBaryonDauMax) { + resultSelections = false; + registry.fill(HIST("hSelDCACharmDau"), 0); + } else { + registry.fill(HIST("hSelDCACharmDau"), 1); + } + + // dcaXY v0 daughters to PV cut + if (std::abs(candidate.dcaXYToPvV0Dau0()) < dcaPosToPvMin || std::abs(candidate.dcaXYToPvV0Dau1()) < dcaNegToPvMin) { + resultSelections = false; + registry.fill(HIST("hSelDcaXYToPvV0Daughters"), 0); + } else { + registry.fill(HIST("hSelDcaXYToPvV0Daughters"), 1); + } + + // dcaXY ka <-- cascade to PV cut + if (std::abs(candidate.dcaXYToPvCascDau()) < dcaBachToPvMin) { + resultSelections = false; + registry.fill(HIST("hSelDcaXYToPvKaFromCasc"), 0); + } else { + registry.fill(HIST("hSelDcaXYToPvKaFromCasc"), 1); + } + + // cut on charm bachelor pion dcaXY and dcaZ + if ((std::abs(candidate.impactParBachFromCharmBaryonXY()) < impactParameterXYPiFromCharmBaryonMin) || (std::abs(candidate.impactParBachFromCharmBaryonXY()) > impactParameterXYPiFromCharmBaryonMax)) { + resultSelections = false; + registry.fill(HIST("hSelDCAXYPrimPi"), 0); + } else { + registry.fill(HIST("hSelDCAXYPrimPi"), 1); + } + if ((std::abs(candidate.impactParBachFromCharmBaryonZ()) < impactParameterZPiFromCharmBaryonMin) || (std::abs(candidate.impactParBachFromCharmBaryonZ()) > impactParameterZPiFromCharmBaryonMax)) { + resultSelections = false; + registry.fill(HIST("hSelDCAZPrimPi"), 0); + } else { + registry.fill(HIST("hSelDCAZPrimPi"), 1); + } + + // cut on cascade dcaXY and dcaZ + if ((std::abs(candidate.impactParCascXY()) < impactParameterXYCascMin) || (std::abs(candidate.impactParCascXY()) > impactParameterXYCascMax)) { + resultSelections = false; + registry.fill(HIST("hSelDCAXYCasc"), 0); + } else { + registry.fill(HIST("hSelDCAXYCasc"), 1); + } + if ((std::abs(candidate.impactParCascZ()) < impactParameterZCascMin) || (std::abs(candidate.impactParCascZ()) > impactParameterZCascMax)) { + resultSelections = false; + registry.fill(HIST("hSelDCAZCasc"), 0); + } else { + registry.fill(HIST("hSelDCAZCasc"), 1); + } + + // pT selections + double ptKaFromCasc = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCasc(), candidate.pyBachFromCasc()); + double ptPiFromCharmBaryon = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCharmBaryon(), candidate.pyBachFromCharmBaryon()); + if (std::abs(ptKaFromCasc) < ptKaFromCascMin) { + resultSelections = false; + registry.fill(HIST("hSelPtKaFromCasc"), 0); + } else { + registry.fill(HIST("hSelPtKaFromCasc"), 1); + } + if (std::abs(ptPiFromCharmBaryon) < ptPiFromCharmBaryonMin) { + resultSelections = false; + registry.fill(HIST("hSelPtPiFromCharm"), 0); + } else { + registry.fill(HIST("hSelPtPiFromCharm"), 1); + } + + if constexpr (ConstructMethod == hf_cand_casc_lf::ConstructMethod::KfParticle) { + // KFParticle Preselections(kfsel) + if (KfconfigurableGroup.applyKFpreselections) { + + bool inputKF = false; + if (resultSelections) { + inputKF = true; + registry.fill(HIST("hSelKFstatus"), 0); + } + + // Competing Ξ rejection(KF) Try to reject cases in which the candidate has a an inv. mass compatibler to Xi (bachelor pion) instead of Omega (bachelor kaon) + if (KfconfigurableGroup.applyCompetingCascRejection) { + if (std::abs(candidate.cascRejectInvmass() - o2::constants::physics::MassXiMinus) < KfconfigurableGroup.cascadeRejMassWindow) { + resultSelections = false; + registry.fill(HIST("hSelCompetingCasc"), 0); + } else { + registry.fill(HIST("hSelCompetingCasc"), 1); + registry.fill(HIST("hInvMassXiMinus_rej_cut"), candidate.cascRejectInvmass()); + } + } + + // Omegac Pt selection + if (std::abs(candidate.kfptOmegac()) < ptCandMin || std::abs(candidate.kfptOmegac()) > ptCandMax) { + resultSelections = false; + registry.fill(HIST("hSelPtOmegac"), 0); + } else { + registry.fill(HIST("hSelPtOmegac"), 1); + } + + // v0&Casc&Omegac ldl selection + if ((candidate.v0ldl() < KfconfigurableGroup.v0LdlMin) || (candidate.cascldl() < KfconfigurableGroup.cascLdlMin) || (candidate.omegacldl() > KfconfigurableGroup.omegacLdlMax)) { + resultSelections = false; + registry.fill(HIST("hSelV0_Casc_Omegacldl"), 0); + } else { + registry.fill(HIST("hSelV0_Casc_Omegacldl"), 1); + } + + // Omegac ctau selsection + if (candidate.cTauOmegac() > KfconfigurableGroup.cTauOmegacMax) { + resultSelections = false; + registry.fill(HIST("hSelctauOmegac"), 0); + } else { + registry.fill(HIST("hSelctauOmegac"), 1); + } + + // Chi2Geo/NDF V0&Casc&Omegac selection + if ((candidate.v0Chi2OverNdf() > KfconfigurableGroup.v0Chi2OverNdfMax) || (candidate.cascChi2OverNdf() > KfconfigurableGroup.cascChi2OverNdfMax) || (candidate.omegacChi2OverNdf() > KfconfigurableGroup.omegacChi2OverNdfMax)) { + resultSelections = false; + registry.fill(HIST("hSelChi2GeooverNDFV0_Casc_Omegac"), 0); + } else { + registry.fill(HIST("hSelChi2GeooverNDFV0_Casc_Omegac"), 1); + } + + // Chi2Topo/NDF (chi2TopoV0ToCasc chi2TopoOmegacToPv chi2TopoCascToOmegac chi2TopoCascToPv) selection (???????????/NDF of which particle????????) + if ((candidate.chi2TopoV0ToCasc() > KfconfigurableGroup.chi2TopoV0ToCascMax) || (candidate.chi2TopoOmegacToPv() > KfconfigurableGroup.chi2TopoOmegacToPvMax) || (candidate.chi2TopoCascToOmegac() > KfconfigurableGroup.chi2TopoCascToOmegacMax) || (candidate.chi2TopoCascToPv() > KfconfigurableGroup.chi2TopoCascToPvMax)) { + resultSelections = false; + registry.fill(HIST("hSelChi2TopooverNDFV0_Casc_Omegac"), 0); + } else { + registry.fill(HIST("hSelChi2TopooverNDFV0_Casc_Omegac"), 1); + } + + // DecaylengthXY of Omegac&Casc&V0 selection + if ((std::abs(candidate.decayLenXYOmegac()) > KfconfigurableGroup.decayLenXYOmegacMax) || (std::abs(candidate.decayLenXYCasc()) < KfconfigurableGroup.decayLenXYCascMin) || (std::abs(candidate.decayLenXYLambda()) < KfconfigurableGroup.decayLenXYLambdaMin)) { + resultSelections = false; + registry.fill(HIST("hSeldecayLenXYOmegac_Casc_V0"), 0); + } else { + registry.fill(HIST("hSeldecayLenXYOmegac_Casc_V0"), 1); + } + + // KFPA cut cosPaCascToOmegac cosPaV0ToCasc + if ((candidate.cosPaCascToOmegac() < KfconfigurableGroup.cosPaCascToOmegacMin) || (candidate.cosPaV0ToCasc() < KfconfigurableGroup.cosPaV0ToCascMin)) { + resultSelections = false; + registry.fill(HIST("hSelcosPaCascToOmegac_V0ToCasc"), 0); + } else { + registry.fill(HIST("hSelcosPaCascToOmegac_V0ToCasc"), 1); + } + + if (resultSelections && inputKF) { + registry.fill(HIST("hSelKFstatus"), 1); + } + } + } + + // TPC clusters selections + if (applyTrkSelLf) { + if (!isSelectedTrackTpcQuality(trackPiFromLam, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { + resultSelections = false; + registry.fill(HIST("hSelTPCQualityPiFromLam"), 0); + } else { + registry.fill(HIST("hSelTPCQualityPiFromLam"), 1); + } + if (!isSelectedTrackTpcQuality(trackPrFromLam, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { + resultSelections = false; + registry.fill(HIST("hSelTPCQualityPrFromLam"), 0); + } else { + registry.fill(HIST("hSelTPCQualityPrFromLam"), 1); + } + if (!isSelectedTrackTpcQuality(trackKaFromCasc, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { + resultSelections = false; + registry.fill(HIST("hSelTPCQualityKaFromCasc"), 0); + } else { + registry.fill(HIST("hSelTPCQualityKaFromCasc"), 1); + } + } + if (!isSelectedTrackTpcQuality(trackPiFromCharm, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { + resultSelections = false; + registry.fill(HIST("hSelTPCQualityPiFromCharm"), 0); + } else { + registry.fill(HIST("hSelTPCQualityPiFromCharm"), 1); + } + + // ITS clusters selection + if (!isSelectedTrackItsQuality(trackPiFromCharm, nClustersItsMin, itsChi2PerClusterMax) || trackPiFromCharm.itsNClsInnerBarrel() < nClustersItsInnBarrMin) { + resultSelections = false; + registry.fill(HIST("hSelITSQualityPiFromCharm"), 0); + } else { + registry.fill(HIST("hSelITSQualityPiFromCharm"), 1); + } + + // track-level PID selection + + // for TrackSelectorPID + int statusPidPrFromLam = -999; + int statusPidPiFromLam = -999; + int statusPidKaFromCasc = -999; + int statusPidPiFromCharmBaryon = -999; + + if (usePidTpcOnly == usePidTpcTofCombined) { + LOGF(fatal, "Check the PID configurables, usePidTpcOnly and usePidTpcTofCombined can't have the same value"); + } + + if (trackPiFromLam.hasTPC()) { + SETBIT(infoTpcStored, PiFromLam); + } + if (trackPrFromLam.hasTPC()) { + SETBIT(infoTpcStored, PrFromLam); + } + if (trackKaFromCasc.hasTPC()) { + SETBIT(infoTpcStored, KaFromCasc); + } + if (trackPiFromCharm.hasTPC()) { + SETBIT(infoTpcStored, PiFromCharm); + } + if (trackPiFromLam.hasTOF()) { + SETBIT(infoTofStored, PiFromLam); + } + if (trackPrFromLam.hasTOF()) { + SETBIT(infoTofStored, PrFromLam); + } + if (trackKaFromCasc.hasTOF()) { + SETBIT(infoTofStored, KaFromCasc); + } + if (trackPiFromCharm.hasTOF()) { + SETBIT(infoTofStored, PiFromCharm); + } + + if (usePidTpcOnly) { + statusPidPrFromLam = selectorProton.statusTpc(trackPrFromLam); + statusPidPiFromLam = selectorPion.statusTpc(trackPiFromLam); + statusPidKaFromCasc = selectorKaon.statusTpc(trackKaFromCasc); + statusPidPiFromCharmBaryon = selectorPion.statusTpc(trackPiFromCharm); + } else if (usePidTpcTofCombined) { + statusPidPrFromLam = selectorProton.statusTpcOrTof(trackPrFromLam); + statusPidPiFromLam = selectorPion.statusTpcOrTof(trackPiFromLam); + statusPidKaFromCasc = selectorKaon.statusTpcOrTof(trackKaFromCasc); + statusPidPiFromCharmBaryon = selectorPion.statusTpcOrTof(trackPiFromCharm); + } + + if (statusPidPrFromLam == TrackSelectorPID::Accepted && statusPidPiFromLam == TrackSelectorPID::Accepted) { + statusPidLambda = true; + if (resultSelections) { + registry.fill(HIST("hStatusCheck"), 0.5); + } + } else { + resultSelections = false; + } + + if (statusPidPrFromLam == TrackSelectorPID::Accepted && statusPidPiFromLam == TrackSelectorPID::Accepted && statusPidKaFromCasc == TrackSelectorPID::Accepted) { + statusPidCascade = true; + if (resultSelections) { + registry.fill(HIST("hStatusCheck"), 1.5); + } + } else { + resultSelections = false; + } + + if (statusPidPrFromLam == TrackSelectorPID::Accepted && statusPidPiFromLam == TrackSelectorPID::Accepted && statusPidKaFromCasc == TrackSelectorPID::Accepted && statusPidPiFromCharmBaryon == TrackSelectorPID::Accepted) { + statusPidCharmBaryon = true; + if (resultSelections) { + registry.fill(HIST("hStatusCheck"), 2.5); + } + } else { + resultSelections = false; + } + + // invariant mass cuts + double invMassLambda = candidate.invMassLambda(); + double invMassCascade = candidate.invMassCascade(); + double invMassCharmBaryon = candidate.invMassCharmBaryon(); + + if (std::abs(invMassLambda - o2::constants::physics::MassLambda0) < v0MassWindow) { + statusInvMassLambda = true; + registry.fill(HIST("hSelMassLam"), 1); + if (statusPidLambda && statusPidCascade && statusPidCharmBaryon && resultSelections) { + registry.fill(HIST("hStatusCheck"), 3.5); + } + } else { + registry.fill(HIST("hSelMassLam"), 0); + resultSelections = false; + } + + if (std::abs(invMassCascade - o2::constants::physics::MassOmegaMinus) < cascadeMassWindow) { + statusInvMassCascade = true; + registry.fill(HIST("hSelMassCasc"), 1); + if (statusPidLambda && statusPidCascade && statusPidCharmBaryon && statusInvMassLambda && resultSelections) { + registry.fill(HIST("hStatusCheck"), 4.5); + } + } else { + registry.fill(HIST("hSelMassCasc"), 0); + resultSelections = false; + } + + if ((invMassCharmBaryon >= invMassCharmBaryonMin) && (invMassCharmBaryon <= invMassCharmBaryonMax)) { + statusInvMassCharmBaryon = true; + registry.fill(HIST("hSelMassCharmBaryon"), 1); + if (statusPidLambda && statusPidCascade && statusPidCharmBaryon && statusInvMassLambda && statusInvMassCascade && resultSelections) { + registry.fill(HIST("hStatusCheck"), 5.5); + } + } else { + registry.fill(HIST("hSelMassCharmBaryon"), 0); + resultSelections = false; + } + // ML selections + if constexpr (ConstructMethod == hf_cand_casc_lf::ConstructMethod::KfParticle) { + if (applyMl) { + bool isSelectedMlOmegac = false; + std::vector inputFeaturesOmegaC = hfMlResponse.getInputFeatures(candidate, trackPiFromLam, trackKaFromCasc, trackPiFromCharm); + isSelectedMlOmegac = hfMlResponse.isSelectedMl(inputFeaturesOmegaC, ptCand, outputMlOmegac); + if (isSelectedMlOmegac) { + registry.fill(HIST("hBDTScoreTest1"), outputMlOmegac[0]); + } + hfMlSelToOmegaPi(outputMlOmegac); + } + } + + hfSelToOmegaPi(statusPidLambda, statusPidCascade, statusPidCharmBaryon, statusInvMassLambda, statusInvMassCascade, statusInvMassCharmBaryon, resultSelections, infoTpcStored, infoTofStored, + trackPiFromCharm.tpcNSigmaPi(), trackKaFromCasc.tpcNSigmaKa(), trackPiFromLam.tpcNSigmaPi(), trackPrFromLam.tpcNSigmaPr(), + trackPiFromCharm.tofNSigmaPi(), trackKaFromCasc.tofNSigmaKa(), trackPiFromLam.tofNSigmaPi(), trackPrFromLam.tofNSigmaPr()); + + if (resultSelections) { + if (!statusPidLambda) { + registry.fill(HIST("hSelPID"), 0.5); + } + if (statusPidLambda) { + registry.fill(HIST("hSelPID"), 1.5); + } + if (!statusPidCascade) { + registry.fill(HIST("hSelPID"), 2.5); + } + if (statusPidCascade) { + registry.fill(HIST("hSelPID"), 3.5); + } + if (!statusPidCharmBaryon) { + registry.fill(HIST("hSelPID"), 4.5); + } + if (statusPidCharmBaryon) { + registry.fill(HIST("hSelPID"), 5.5); + } + if (!statusInvMassLambda) { + registry.fill(HIST("hSelPID"), 6.5); + } + if (statusInvMassLambda) { + registry.fill(HIST("hSelPID"), 7.5); + } + if (!statusInvMassCascade) { + registry.fill(HIST("hSelPID"), 8.5); + } + if (statusInvMassCascade) { + registry.fill(HIST("hSelPID"), 9.5); + } + if (!statusInvMassCharmBaryon) { + registry.fill(HIST("hSelPID"), 10.5); + } + if (statusInvMassCharmBaryon) { + registry.fill(HIST("hSelPID"), 11.5); + } + } + + if (statusPidLambda && statusPidCascade && statusPidCharmBaryon && statusInvMassLambda && statusInvMassCascade && statusInvMassCharmBaryon && resultSelections) { + hInvMassCharmBaryon->Fill(invMassCharmBaryon); + if constexpr (ConstructMethod == hf_cand_casc_lf::ConstructMethod::KfParticle) { + hPtCharmBaryon->Fill(candidate.kfptOmegac()); + } else { + hPtCharmBaryon->Fill(ptCand); + } + } + } + } // end process + + void processOmegac0SelectorWithKFParticle(soa::Join const& candidates, + TracksSel const& tracks, + TracksSelLf const& lfTracks) + { + runOmegac0Selector(candidates, tracks, lfTracks); + } + PROCESS_SWITCH(HfCandidateSelectorToOmegaPi, processOmegac0SelectorWithKFParticle, "Run Omegac0 to Omega pi selector with both DCA and KFParticle related selection.", false); + + void processOmegac0SelectorWithDCAFitter(aod::HfCandToOmegaPi const& candidates, + TracksSel const& tracks, + TracksSelLf const& lfTracks) + { + runOmegac0Selector(candidates, tracks, lfTracks); + } + PROCESS_SWITCH(HfCandidateSelectorToOmegaPi, processOmegac0SelectorWithDCAFitter, "Run Omegac0 to Omega pi selector with only DCA related selection.", true); + +}; // end struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/candidateSelectorToXiPi.cxx b/PWGHF/TableProducer/candidateSelectorToXiPi.cxx index e0c6220e7ce..8f118058f3e 100644 --- a/PWGHF/TableProducer/candidateSelectorToXiPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorToXiPi.cxx @@ -22,16 +22,18 @@ #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" using namespace o2; using namespace o2::aod; using namespace o2::framework; +using namespace o2::analysis; -enum pidInfoStored { - kPiFromLam = 0, - kPrFromLam, - kPiFromCasc, - kPiFromCharm +enum PidInfoStored { + PiFromLam = 0, + PrFromLam, + PiFromCasc, + PiFromCharm }; /// Struct for applying Omegac0/Xic0 selection cuts @@ -50,6 +52,7 @@ struct HfCandidateSelectorToXiPi { Configurable dcaPosToPvMin{"dcaPosToPvMin", 0.06, "DCA Pos To PV"}; Configurable v0MassWindow{"v0MassWindow", 0.01, "V0 mass window"}; Configurable cascadeMassWindow{"cascadeMassWindow", 0.01, "Cascade mass window"}; + Configurable applyTrkSelLf{"applyTrkSelLf", true, "Apply track selection for LF daughters"}; // limit charm baryon invariant mass spectrum Configurable invMassCharmBaryonMin{"invMassCharmBaryonMin", 2.0, "Lower limit invariant mass spectrum charm baryon"}; // 2.4 Omegac0 only @@ -102,17 +105,20 @@ struct HfCandidateSelectorToXiPi { Configurable nSigmaTofPrMax{"nSigmaTofPrMax", 3., "Nsigma cut on TOF only for proton selection"}; Configurable nSigmaTofCombinedPrMax{"nSigmaTofCombinedPrMax", 0., "Nsigma cut on TOF combined with TPC for proton selection"}; - // detector clusters selections + // detector track quality selections Configurable nClustersTpcMin{"nClustersTpcMin", 70, "Minimum number of TPC clusters requirement"}; Configurable nTpcCrossedRowsMin{"nTpcCrossedRowsMin", 70, "Minimum number of TPC crossed rows requirement"}; Configurable tpcCrossedRowsOverFindableClustersRatioMin{"tpcCrossedRowsOverFindableClustersRatioMin", 0.8, "Minimum ratio TPC crossed rows over findable clusters requirement"}; + Configurable tpcChi2PerClusterMax{"tpcChi2PerClusterMax", 4, "Maximum value of chi2 fit over TPC clusters"}; Configurable nClustersItsMin{"nClustersItsMin", 3, "Minimum number of ITS clusters requirement for pi <- charm baryon"}; Configurable nClustersItsInnBarrMin{"nClustersItsInnBarrMin", 1, "Minimum number of ITS clusters in inner barrel requirement for pi <- charm baryon"}; + Configurable itsChi2PerClusterMax{"itsChi2PerClusterMax", 36, "Maximum value of chi2 fit over ITS clusters for pi <- charm baryon"}; TrackSelectorPi selectorPion; TrackSelectorPr selectorProton; using TracksSel = soa::Join; + using TracksSelLf = soa::Join; HistogramRegistry registry{"registry"}; // for QA of selections @@ -134,48 +140,45 @@ struct HfCandidateSelectorToXiPi { selectorProton.setRangeNSigmaTof(-nSigmaTofPrMax, nSigmaTofPrMax); selectorProton.setRangeNSigmaTofCondTpc(-nSigmaTofCombinedPrMax, nSigmaTofCombinedPrMax); + const AxisSpec axisSel{2, -0.5, 1.5, "status"}; + registry.add("hSelPID", "hSelPID;status;entries", {HistType::kTH1F, {{12, 0., 12.}}}); registry.add("hStatusCheck", "Check consecutive selections status;status;entries", {HistType::kTH1F, {{12, 0., 12.}}}); // for QA of the selections (bin 0 -> candidates that did not pass the selection, bin 1 -> candidates that passed the selection) - registry.add("hSelSignDec", "hSelSignDec;status;entries", {HistType::kTH1F, {{3, 0., 3.}}}); - registry.add("hSelEtaPosV0Dau", "hSelEtaPosV0Dau;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelEtaNegV0Dau", "hSelEtaNegV0Dau;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelEtaPiFromCasc", "hSelEtaPiFromCasc;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelEtaPiFromCharm", "hSelEtaPiFromCharm;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelRadCasc", "hSelRadCasc;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelRadV0", "hSelRadV0;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelCosPACasc", "hSelCosPACasc;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelCosPAV0", "hSelCosPAV0;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelDCACascDau", "hSelDCACascDau;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelDCAV0Dau", "hSelDCAV0Dau;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelDCACharmDau", "hSelDCACharmDau;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelDCAXYPrimPi", "hSelDCAXYPrimPi;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelDCAZPrimPi", "hSelDCAZPrimPi;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelDCAXYCasc", "hSelDCAXYCasc;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelDCAZCasc", "hSelDCAZCasc;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelPtPiFromCasc", "hSelPtPiFromCasc;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelPtPiFromCharm", "hSelPtPiFromCharm;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelNClsTPCPiFromCharm", "hSelNClsTPCPiFromCharm;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelNClsTPCPiFromLam", "hSelNClsTPCPiFromLam;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelNClsTPCPrFromLam", "hSelNClsTPCPrFromLam;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelNClsTPCPiFromCasc", "hSelNClsTPCPiFromCasc;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelNCrossRowsTPCPiFromCharm", "hSelNCrossRowsTPCPiFromCharm;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelNCrossRowsTPCPiFromLam", "hSelNCrossRowsTPCPiFromLam;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelNCrossRowsTPCPrFromLam", "hSelNCrossRowsTPCPrFromLam;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelNCrossRowsTPCPiFromCasc", "hSelNCrossRowsTPCPiFromCasc;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelCrossRowsOverFindClsTPCAllTracks", "hSelCrossRowsOverFindClsTPCAllTracks;status;entries", {HistType::kTH1F, {{10, 0., 10.}}}); - registry.add("hSelNClsITSPiFromCharm", "hSelNClsITSPiFromCharm;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelNClsITSInnerPiFromCharm", "hSelNClsITSInnerPiFromCharm;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelMassLam", "hSelMassLam;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelMassCasc", "hSelMassCasc;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelMassCharmBaryon", "hSelMassCharmBaryon;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelDcaXYToPvV0Daughters", "hSelDcaXYToPvV0Daughters;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); - registry.add("hSelDcaXYToPvPiFromCasc", "hSelDcaXYToPvPiFromCasc;status;entries", {HistType::kTH1F, {{5, 0., 5.}}}); + registry.add("hSelSignDec", "hSelSignDec;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelEtaPosV0Dau", "hSelEtaPosV0Dau;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelEtaNegV0Dau", "hSelEtaNegV0Dau;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelEtaPiFromCasc", "hSelEtaPiFromCasc;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelEtaPiFromCharm", "hSelEtaPiFromCharm;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelRadCasc", "hSelRadCasc;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelRadV0", "hSelRadV0;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelCosPACasc", "hSelCosPACasc;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelCosPAV0", "hSelCosPAV0;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDCACascDau", "hSelDCACascDau;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDCAV0Dau", "hSelDCAV0Dau;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDCACharmDau", "hSelDCACharmDau;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDCAXYPrimPi", "hSelDCAXYPrimPi;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDCAZPrimPi", "hSelDCAZPrimPi;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDCAXYCasc", "hSelDCAXYCasc;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDCAZCasc", "hSelDCAZCasc;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelPtPiFromCasc", "hSelPtPiFromCasc;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelPtPiFromCharm", "hSelPtPiFromCharm;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelTPCQualityPiFromCharm", "hSelTPCQualityPiFromCharm;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelTPCQualityPiFromLam", "hSelTPCQualityPiFromLam;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelTPCQualityPrFromLam", "hSelTPCQualityPrFromLam;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelTPCQualityPiFromCasc", "hSelTPCQualityPiFromCasc;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelITSQualityPiFromCharm", "hSelITSQualityPiFromCharm;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelMassLam", "hSelMassLam;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelMassCasc", "hSelMassCasc;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelMassCharmBaryon", "hSelMassCharmBaryon;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDcaXYToPvV0Daughters", "hSelDcaXYToPvV0Daughters;status;entries", {HistType::kTH1F, {axisSel}}); + registry.add("hSelDcaXYToPvPiFromCasc", "hSelDcaXYToPvPiFromCasc;status;entries", {HistType::kTH1F, {axisSel}}); } void process(aod::HfCandToXiPi const& candidates, - TracksSel const&) + TracksSel const& tracks, + TracksSelLf const& lfTracks) { double massLambdaFromPDG = o2::constants::physics::MassLambda0; @@ -186,10 +189,14 @@ struct HfCandidateSelectorToXiPi { bool resultSelections = true; // True if the candidate passes all the selections, False otherwise - auto trackV0PosDau = candidate.posTrack_as(); // positive V0 daughter - auto trackV0NegDau = candidate.negTrack_as(); // negative V0 daughter - auto trackPiFromCasc = candidate.bachelor_as(); // pion <- cascade - auto trackPiFromCharm = candidate.piFromCharmBaryon_as(); // pion <- charm baryon + auto trackV0PosDauId = candidate.posTrackId(); // positive V0 daughter + auto trackV0NegDauId = candidate.negTrackId(); // negative V0 daughter + auto trackPiFromCascId = candidate.bachelorId(); // pion <- cascade + auto trackPiFromCharmId = candidate.bachelorFromCharmBaryonId(); // pion <- charm baryon + auto trackV0PosDau = lfTracks.rawIteratorAt(trackV0PosDauId); + auto trackV0NegDau = lfTracks.rawIteratorAt(trackV0NegDauId); + auto trackPiFromCasc = lfTracks.rawIteratorAt(trackPiFromCascId); + auto trackPiFromCharm = tracks.rawIteratorAt(trackPiFromCharmId); auto trackPiFromLam = trackV0NegDau; auto trackPrFromLam = trackV0PosDau; @@ -207,8 +214,8 @@ struct HfCandidateSelectorToXiPi { // eta selection double etaV0PosDau = candidate.etaV0PosDau(); double etaV0NegDau = candidate.etaV0NegDau(); - double etaPiFromCasc = candidate.etaPiFromCasc(); - double etaPiFromCharmBaryon = candidate.etaPiFromCharmBaryon(); + double etaPiFromCasc = candidate.etaBachFromCasc(); + double etaPiFromCharmBaryon = candidate.etaBachFromCharmBaryon(); if (std::abs(etaV0PosDau) > etaTrackLFDauMax) { resultSelections = false; registry.fill(HIST("hSelEtaPosV0Dau"), 0); @@ -286,7 +293,7 @@ struct HfCandidateSelectorToXiPi { } // dcaXY v0 daughters to PV cut - if (candidate.dcaXYToPvV0Dau0() < dcaPosToPvMin || candidate.dcaXYToPvV0Dau1() < dcaNegToPvMin) { + if (std::abs(candidate.dcaXYToPvV0Dau0()) < dcaPosToPvMin || std::abs(candidate.dcaXYToPvV0Dau1()) < dcaNegToPvMin) { resultSelections = false; registry.fill(HIST("hSelDcaXYToPvV0Daughters"), 0); } else { @@ -294,7 +301,7 @@ struct HfCandidateSelectorToXiPi { } // dcaXY pi <-- cascade to PV cut - if (candidate.dcaXYToPvCascDau() < dcaBachToPvMin) { + if (std::abs(candidate.dcaXYToPvCascDau()) < dcaBachToPvMin) { resultSelections = false; registry.fill(HIST("hSelDcaXYToPvPiFromCasc"), 0); } else { @@ -302,13 +309,13 @@ struct HfCandidateSelectorToXiPi { } // cut on charm bachelor pion dcaXY and dcaZ - if ((std::abs(candidate.impactParPiFromCharmBaryonXY()) < impactParameterXYPiFromCharmBaryonMin) || (std::abs(candidate.impactParPiFromCharmBaryonXY()) > impactParameterXYPiFromCharmBaryonMax)) { + if ((std::abs(candidate.impactParBachFromCharmBaryonXY()) < impactParameterXYPiFromCharmBaryonMin) || (std::abs(candidate.impactParBachFromCharmBaryonXY()) > impactParameterXYPiFromCharmBaryonMax)) { resultSelections = false; registry.fill(HIST("hSelDCAXYPrimPi"), 0); } else { registry.fill(HIST("hSelDCAXYPrimPi"), 1); } - if ((std::abs(candidate.impactParPiFromCharmBaryonZ()) < impactParameterZPiFromCharmBaryonMin) || (std::abs(candidate.impactParPiFromCharmBaryonZ()) > impactParameterZPiFromCharmBaryonMax)) { + if ((std::abs(candidate.impactParBachFromCharmBaryonZ()) < impactParameterZPiFromCharmBaryonMin) || (std::abs(candidate.impactParBachFromCharmBaryonZ()) > impactParameterZPiFromCharmBaryonMax)) { resultSelections = false; registry.fill(HIST("hSelDCAZPrimPi"), 0); } else { @@ -330,8 +337,8 @@ struct HfCandidateSelectorToXiPi { } // pT selections - double ptPiFromCasc = RecoDecay::sqrtSumOfSquares(candidate.pxPiFromCasc(), candidate.pyPiFromCasc()); - double ptPiFromCharmBaryon = RecoDecay::sqrtSumOfSquares(candidate.pxPiFromCharmBaryon(), candidate.pyPiFromCharmBaryon()); + double ptPiFromCasc = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCasc(), candidate.pyBachFromCasc()); + double ptPiFromCharmBaryon = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCharmBaryon(), candidate.pyBachFromCharmBaryon()); if (std::abs(ptPiFromCasc) < ptPiFromCascMin) { resultSelections = false; registry.fill(HIST("hSelPtPiFromCasc"), 0); @@ -346,95 +353,39 @@ struct HfCandidateSelectorToXiPi { } // TPC clusters selections - if (trackPiFromCharm.tpcNClsFound() < nClustersTpcMin) { - resultSelections = false; - registry.fill(HIST("hSelNClsTPCPiFromCharm"), 0); - } else { - registry.fill(HIST("hSelNClsTPCPiFromCharm"), 1); - } - if (trackPiFromLam.tpcNClsFound() < nClustersTpcMin) { - resultSelections = false; - registry.fill(HIST("hSelNClsTPCPiFromLam"), 0); - } else { - registry.fill(HIST("hSelNClsTPCPiFromLam"), 1); - } - if (trackPrFromLam.tpcNClsFound() < nClustersTpcMin) { - resultSelections = false; - registry.fill(HIST("hSelNClsTPCPrFromLam"), 0); - } else { - registry.fill(HIST("hSelNClsTPCPrFromLam"), 1); - } - if (trackPiFromCasc.tpcNClsFound() < nClustersTpcMin) { - resultSelections = false; - registry.fill(HIST("hSelNClsTPCPiFromCasc"), 0); - } else { - registry.fill(HIST("hSelNClsTPCPiFromCasc"), 1); - } - - // TPC crossed rows selection - if (trackPiFromCharm.tpcNClsCrossedRows() < nTpcCrossedRowsMin) { - resultSelections = false; - registry.fill(HIST("hSelNCrossRowsTPCPiFromCharm"), 0); - } else { - registry.fill(HIST("hSelNCrossRowsTPCPiFromCharm"), 1); - } - if (trackPiFromLam.tpcNClsCrossedRows() < nTpcCrossedRowsMin) { - resultSelections = false; - registry.fill(HIST("hSelNCrossRowsTPCPiFromLam"), 0); - } else { - registry.fill(HIST("hSelNCrossRowsTPCPiFromLam"), 1); - } - if (trackPrFromLam.tpcNClsCrossedRows() < nTpcCrossedRowsMin) { - resultSelections = false; - registry.fill(HIST("hSelNCrossRowsTPCPrFromLam"), 0); - } else { - registry.fill(HIST("hSelNCrossRowsTPCPrFromLam"), 1); - } - if (trackPiFromCasc.tpcNClsCrossedRows() < nTpcCrossedRowsMin) { - resultSelections = false; - registry.fill(HIST("hSelNCrossRowsTPCPiFromCasc"), 0); - } else { - registry.fill(HIST("hSelNCrossRowsTPCPiFromCasc"), 1); - } - - // further TPC selection - if (trackPiFromCharm.tpcCrossedRowsOverFindableCls() < tpcCrossedRowsOverFindableClustersRatioMin) { - resultSelections = false; - registry.fill(HIST("hSelCrossRowsOverFindClsTPCAllTracks"), 0); - } else { - registry.fill(HIST("hSelCrossRowsOverFindClsTPCAllTracks"), 1); - } - if (trackPiFromCasc.tpcCrossedRowsOverFindableCls() < tpcCrossedRowsOverFindableClustersRatioMin) { - resultSelections = false; - registry.fill(HIST("hSelCrossRowsOverFindClsTPCAllTracks"), 2); - } else { - registry.fill(HIST("hSelCrossRowsOverFindClsTPCAllTracks"), 3); - } - if (trackPiFromLam.tpcCrossedRowsOverFindableCls() < tpcCrossedRowsOverFindableClustersRatioMin) { - resultSelections = false; - registry.fill(HIST("hSelCrossRowsOverFindClsTPCAllTracks"), 4); - } else { - registry.fill(HIST("hSelCrossRowsOverFindClsTPCAllTracks"), 5); + if (applyTrkSelLf) { + if (!isSelectedTrackTpcQuality(trackPiFromLam, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { + resultSelections = false; + registry.fill(HIST("hSelTPCQualityPiFromLam"), 0); + } else { + registry.fill(HIST("hSelTPCQualityPiFromLam"), 1); + } + if (!isSelectedTrackTpcQuality(trackPrFromLam, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { + resultSelections = false; + registry.fill(HIST("hSelTPCQualityPrFromLam"), 0); + } else { + registry.fill(HIST("hSelTPCQualityPrFromLam"), 1); + } + if (!isSelectedTrackTpcQuality(trackPiFromCasc, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { + resultSelections = false; + registry.fill(HIST("hSelTPCQualityPiFromCasc"), 0); + } else { + registry.fill(HIST("hSelTPCQualityPiFromCasc"), 1); + } } - if (trackPrFromLam.tpcCrossedRowsOverFindableCls() < tpcCrossedRowsOverFindableClustersRatioMin) { + if (!isSelectedTrackTpcQuality(trackPiFromCharm, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { resultSelections = false; - registry.fill(HIST("hSelCrossRowsOverFindClsTPCAllTracks"), 6); + registry.fill(HIST("hSelTPCQualityPiFromCharm"), 0); } else { - registry.fill(HIST("hSelCrossRowsOverFindClsTPCAllTracks"), 7); + registry.fill(HIST("hSelTPCQualityPiFromCharm"), 1); } // ITS clusters selection - if (trackPiFromCharm.itsNCls() < nClustersItsMin) { - resultSelections = false; - registry.fill(HIST("hSelNClsITSPiFromCharm"), 0); - } else { - registry.fill(HIST("hSelNClsITSPiFromCharm"), 1); - } - if (trackPiFromCharm.itsNClsInnerBarrel() < nClustersItsInnBarrMin) { + if (!isSelectedTrackItsQuality(trackPiFromCharm, nClustersItsMin, itsChi2PerClusterMax) || trackPiFromCharm.itsNClsInnerBarrel() < nClustersItsInnBarrMin) { resultSelections = false; - registry.fill(HIST("hSelNClsITSInnerPiFromCharm"), 0); + registry.fill(HIST("hSelITSQualityPiFromCharm"), 0); } else { - registry.fill(HIST("hSelNClsITSInnerPiFromCharm"), 1); + registry.fill(HIST("hSelITSQualityPiFromCharm"), 1); } // track-level PID selection @@ -457,28 +408,28 @@ struct HfCandidateSelectorToXiPi { } if (trackPiFromLam.hasTPC()) { - SETBIT(infoTpcStored, kPiFromLam); + SETBIT(infoTpcStored, PiFromLam); } if (trackPrFromLam.hasTPC()) { - SETBIT(infoTpcStored, kPrFromLam); + SETBIT(infoTpcStored, PrFromLam); } if (trackPiFromCasc.hasTPC()) { - SETBIT(infoTpcStored, kPiFromCasc); + SETBIT(infoTpcStored, PiFromCasc); } if (trackPiFromCharm.hasTPC()) { - SETBIT(infoTpcStored, kPiFromCharm); + SETBIT(infoTpcStored, PiFromCharm); } if (trackPiFromLam.hasTOF()) { - SETBIT(infoTofStored, kPiFromLam); + SETBIT(infoTofStored, PiFromLam); } if (trackPrFromLam.hasTOF()) { - SETBIT(infoTofStored, kPrFromLam); + SETBIT(infoTofStored, PrFromLam); } if (trackPiFromCasc.hasTOF()) { - SETBIT(infoTofStored, kPiFromCasc); + SETBIT(infoTofStored, PiFromCasc); } if (trackPiFromCharm.hasTOF()) { - SETBIT(infoTofStored, kPiFromCharm); + SETBIT(infoTofStored, PiFromCharm); } if (usePidTpcOnly) { @@ -601,7 +552,7 @@ struct HfCandidateSelectorToXiPi { } } } // end process -}; // end struct +}; // end struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGHF/TableProducer/candidateSelectorXic0ToXiPiKf.cxx b/PWGHF/TableProducer/candidateSelectorXic0ToXiPiKf.cxx new file mode 100644 index 00000000000..904b8c86b5b --- /dev/null +++ b/PWGHF/TableProducer/candidateSelectorXic0ToXiPiKf.cxx @@ -0,0 +1,560 @@ +// 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 candidateSelectorXic0ToXiPiKf.cxx +/// \brief Xic0 → Xi Pi selection task +/// \author Ran Tu , Fudan University + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectorPID.h" + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::analysis; + +enum PidInfoStored { + PiFromLam = 0, + PrFromLam, + PiFromCasc, + PiFromCharm +}; + +/// Struct for applying Xic0 -> Xi pi selection cuts +struct HfCandidateSelectorXic0ToXiPiKf { + Produces hfSelToXiPi; + + // LF analysis selections + Configurable radiusCascMin{"radiusCascMin", 0.5, "Min cascade radius"}; + Configurable radiusV0Min{"radiusV0Min", 1.1, "Min V0 radius"}; + Configurable cosPAV0Min{"cosPAV0Min", 0.97, "Min valueCosPA V0"}; + Configurable cosPACascMin{"cosPACascMin", 0.97, "Min value CosPA cascade"}; + Configurable dcaCascDauMax{"dcaCascDauMax", 1.0, "Max DCA cascade daughters"}; + Configurable dcaV0DauMax{"dcaV0DauMax", 1.0, "Max DCA V0 daughters"}; + Configurable dcaBachToPvMin{"dcaBachToPvMin", 0.04, "DCA Bach To PV"}; + Configurable dcaNegToPvMin{"dcaNegToPvMin", 0.06, "DCA Neg To PV"}; + Configurable dcaPosToPvMin{"dcaPosToPvMin", 0.06, "DCA Pos To PV"}; + Configurable v0MassWindow{"v0MassWindow", 0.01, "V0 mass window"}; + Configurable cascadeMassWindow{"cascadeMassWindow", 0.01, "Cascade mass window"}; + Configurable applyTrkSelLf{"applyTrkSelLf", true, "Apply track selection for LF daughters"}; + + // limit charm baryon invariant mass spectrum + Configurable invMassCharmBaryonMin{"invMassCharmBaryonMin", 2.0, "Lower limit invariant mass spectrum charm baryon"}; // 2.4 Omegac0 only + Configurable invMassCharmBaryonMax{"invMassCharmBaryonMax", 3.1, "Upper limit invariant mass spectrum charm baryon"}; + + // kinematic selections + Configurable etaTrackCharmBachMax{"etaTrackCharmBachMax", 0.8, "Max absolute value of eta for charm baryon bachelor"}; + Configurable etaTrackLFDauMax{"etaTrackLFDauMax", 1.0, "Max absolute value of eta for V0 and cascade daughters"}; + Configurable ptPiFromCascMin{"ptPiFromCascMin", 0.15, "Min pT pion <- casc"}; + Configurable ptPiFromCharmBaryonMin{"ptPiFromCharmBaryonMin", 0.2, "Min pT pi <- charm baryon"}; + + Configurable impactParameterXYPiFromCharmBaryonMin{"impactParameterXYPiFromCharmBaryonMin", 0., "Min dcaxy pi from charm baryon track to PV"}; + Configurable impactParameterXYPiFromCharmBaryonMax{"impactParameterXYPiFromCharmBaryonMax", 10., "Max dcaxy pi from charm baryon track to PV"}; + Configurable impactParameterZPiFromCharmBaryonMin{"impactParameterZPiFromCharmBaryonMin", 0., "Min dcaz pi from charm baryon track to PV"}; + Configurable impactParameterZPiFromCharmBaryonMax{"impactParameterZPiFromCharmBaryonMax", 10., "Max dcaz pi from charm baryon track to PV"}; + + Configurable impactParameterXYCascMin{"impactParameterXYCascMin", 0., "Min dcaxy cascade track to PV"}; + Configurable impactParameterXYCascMax{"impactParameterXYCascMax", 10., "Max dcaxy cascade track to PV"}; + Configurable impactParameterZCascMin{"impactParameterZCascMin", 0., "Min dcaz cascade track to PV"}; + Configurable impactParameterZCascMax{"impactParameterZCascMax", 10., "Max dcaz cascade track to PV"}; + + Configurable ptCandMin{"ptCandMin", 0., "Lower bound of candidate pT"}; + Configurable ptCandMax{"ptCandMax", 50., "Upper bound of candidate pT"}; + + Configurable dcaCharmBaryonDauMax{"dcaCharmBaryonDauMax", 2.0, "Max DCA charm baryon daughters"}; + + // PID options + Configurable usePidTpcOnly{"usePidTpcOnly", false, "Perform PID using only TPC"}; + Configurable usePidTpcTofCombined{"usePidTpcTofCombined", true, "Perform PID using TPC & TOF"}; + + // PID - TPC selections + + Configurable ptPrPidTpcMin{"ptPrPidTpcMin", -1, "Lower bound of track pT for TPC PID for proton selection"}; + Configurable ptPrPidTpcMax{"ptPrPidTpcMax", 9999.9, "Upper bound of track pT for TPC PID for proton selection"}; + Configurable nSigmaTpcPrMax{"nSigmaTpcPrMax", 3., "Nsigma cut on TPC only for proton selection"}; + Configurable nSigmaTpcCombinedPrMax{"nSigmaTpcCombinedPrMax", 0., "Nsigma cut on TPC combined with TOF for proton selection"}; + + Configurable ptPiPidTpcMin{"ptPiPidTpcMin", -1, "Lower bound of track pT for TPC PID for pion selection"}; + Configurable ptPiPidTpcMax{"ptPiPidTpcMax", 9999.9, "Upper bound of track pT for TPC PID for pion selection"}; + Configurable nSigmaTpcPiMax{"nSigmaTpcPiMax", 3., "Nsigma cut on TPC only for pion selection"}; + Configurable nSigmaTpcCombinedPiMax{"nSigmaTpcCombinedPiMax", 0., "Nsigma cut on TPC combined with TOF for pion selection"}; + + // PID - TOF selections + + Configurable ptPrPidTofMin{"ptPrPidTofMin", -1, "Lower bound of track pT for TOF PID for proton selection"}; + Configurable ptPrPidTofMax{"ptPrPidTofMax", 9999.9, "Upper bound of track pT for TOF PID for proton selection"}; + Configurable nSigmaTofPrMax{"nSigmaTofPrMax", 3., "Nsigma cut on TOF only for proton selection"}; + Configurable nSigmaTofCombinedPrMax{"nSigmaTofCombinedPrMax", 0., "Nsigma cut on TOF combined with TPC for proton selection"}; + + Configurable ptPiPidTofMin{"ptPiPidTofMin", -1, "Lower bound of track pT for TOF PID for pion selection"}; + Configurable ptPiPidTofMax{"ptPiPidTofMax", 9999.9, "Upper bound of track pT for TOF PID for pion selection"}; + Configurable nSigmaTofPiMax{"nSigmaTofPiMax", 3., "Nsigma cut on TOF only for pion selection"}; + Configurable nSigmaTofCombinedPiMax{"nSigmaTofCombinedPiMax", 0., "Nsigma cut on TOF combined with TOF for pion selection"}; + + // detector clusters selections + Configurable nClustersTpcMin{"nClustersTpcMin", 70, "Minimum number of TPC clusters requirement"}; + Configurable nTpcCrossedRowsMin{"nTpcCrossedRowsMin", 70, "Minimum number of TPC crossed rows requirement"}; + Configurable tpcCrossedRowsOverFindableClustersRatioMin{"tpcCrossedRowsOverFindableClustersRatioMin", 0.8, "Minimum ratio TPC crossed rows over findable clusters requirement"}; + Configurable tpcChi2PerClusterMax{"tpcChi2PerClusterMax", 4, "Maximum value of chi2 fit over TPC clusters"}; + Configurable nClustersItsMin{"nClustersItsMin", 3, "Minimum number of ITS clusters requirement for pi <- charm baryon"}; + Configurable nClustersItsInnBarrMin{"nClustersItsInnBarrMin", 1, "Minimum number of ITS clusters in inner barrel requirement for pi <- charm baryon"}; + Configurable itsChi2PerClusterMax{"itsChi2PerClusterMax", 36, "Maximum value of chi2 fit over ITS clusters for pi <- charm baryon"}; + + TrackSelectorPr selectorProton; + TrackSelectorPi selectorPion; + + using TracksSel = soa::Join; + using TracksSelLf = soa::Join; + + HistogramRegistry registry{"registry"}; // for QA of selections + + OutputObj hInvMassCharmBaryon{TH1D("hInvMassCharmBaryon", "Charm baryon invariant mass;inv mass;entries", 500, 2.3, 3.1)}; + + void init(InitContext const&) + { + selectorProton.setRangePtTpc(ptPrPidTpcMin, ptPrPidTpcMax); + selectorProton.setRangeNSigmaTpc(-nSigmaTpcPrMax, nSigmaTpcPrMax); + selectorProton.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedPrMax, nSigmaTpcCombinedPrMax); + selectorProton.setRangePtTof(ptPrPidTofMin, ptPrPidTofMax); + selectorProton.setRangeNSigmaTof(-nSigmaTofPrMax, nSigmaTofPrMax); + selectorProton.setRangeNSigmaTofCondTpc(-nSigmaTofCombinedPrMax, nSigmaTofCombinedPrMax); + + selectorPion.setRangePtTpc(ptPiPidTpcMin, ptPiPidTpcMax); + selectorPion.setRangeNSigmaTpc(-nSigmaTpcPiMax, nSigmaTpcPiMax); + selectorPion.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedPiMax, nSigmaTpcCombinedPiMax); + selectorPion.setRangePtTof(ptPiPidTofMin, ptPiPidTofMax); + selectorPion.setRangeNSigmaTof(-nSigmaTofPiMax, nSigmaTofPiMax); + selectorPion.setRangeNSigmaTofCondTpc(-nSigmaTofCombinedPiMax, nSigmaTofCombinedPiMax); + + const AxisSpec axisSel{2, -0.5, 1.5, "status"}; + + registry.add("hSelPID", "hSelPID;status;entries", {HistType::kTH1D, {{12, 0., 12.}}}); + registry.add("hStatusCheck", "Check consecutive selections status;status;entries", {HistType::kTH1D, {{12, 0., 12.}}}); + + // for QA of the selections (bin 0 -> candidates that did not pass the selection, bin 1 -> candidates that passed the selection) + registry.add("hSelSignDec", "hSelSignDec;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelEtaPosV0Dau", "hSelEtaPosV0Dau;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelEtaNegV0Dau", "hSelEtaNegV0Dau;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelEtaPiFromCasc", "hSelEtaPiFromCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelEtaPiFromCharm", "hSelEtaPiFromCharm;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelRadCasc", "hSelRadCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelRadV0", "hSelRadV0;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelCosPACasc", "hSelCosPACasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelCosPAV0", "hSelCosPAV0;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDCACascDau", "hSelDCACascDau;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDCAV0Dau", "hSelDCAV0Dau;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDCACharmDau", "hSelDCACharmDau;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDCAXYPrimPi", "hSelDCAXYPrimPi;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDCAZPrimPi", "hSelDCAZPrimPi;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDCAXYCasc", "hSelDCAXYCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDCAZCasc", "hSelDCAZCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelPtPiFromCasc", "hSelPtPiFromCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelPtPiFromCharm", "hSelPtPiFromCharm;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelTPCQualityPiFromCharm", "hSelTPCQualityPiFromCharm;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelTPCQualityPiFromLam", "hSelTPCQualityPiFromLam;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelTPCQualityPrFromLam", "hSelTPCQualityPrFromLam;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelTPCQualityPiFromCasc", "hSelTPCQualityPiFromCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelITSQualityPiFromCharm", "hSelITSQualityPiFromCharm;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelMassLam", "hSelMassLam;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelMassCasc", "hSelMassCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelMassCharmBaryon", "hSelMassCharmBaryon;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDcaXYToPvV0Daughters", "hSelDcaXYToPvV0Daughters;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelDcaXYToPvPiFromCasc", "hSelDcaXYToPvPiFromCasc;status;entries", {HistType::kTH1D, {axisSel}}); + } + + void process(aod::HfCandToXiPiKf const& candidates, + TracksSel const& tracks, + TracksSelLf const& lfTracks) + { + + // looping over charm baryon candidates + for (const auto& candidate : candidates) { + + bool resultSelections = true; // True if the candidate passes all the selections, False otherwise + + auto trackV0PosDauId = candidate.posTrackId(); // positive V0 daughter + auto trackV0NegDauId = candidate.negTrackId(); // negative V0 daughter + auto trackPiFromCascId = candidate.bachelorId(); // pion <- cascade + auto trackPiFromCharmId = candidate.bachelorFromCharmBaryonId(); // pion <- charm baryon + auto trackV0PosDau = lfTracks.rawIteratorAt(trackV0PosDauId); + auto trackV0NegDau = lfTracks.rawIteratorAt(trackV0NegDauId); + auto trackPiFromCasc = lfTracks.rawIteratorAt(trackPiFromCascId); + auto trackPiFromCharm = tracks.rawIteratorAt(trackPiFromCharmId); + + auto trackPiFromLam = trackV0NegDau; + auto trackPrFromLam = trackV0PosDau; + + int8_t signDecay = candidate.signDecay(); // sign of pi <- cascade + + if (signDecay > 0) { + trackPiFromLam = trackV0PosDau; + trackPrFromLam = trackV0NegDau; + registry.fill(HIST("hSelSignDec"), 1); // anti-particle decay + } else if (signDecay < 0) { + registry.fill(HIST("hSelSignDec"), 0); // particle decay + } + + // eta selection + double etaV0PosDau = candidate.etaV0PosDau(); + double etaV0NegDau = candidate.etaV0NegDau(); + double etaPiFromCasc = candidate.etaBachFromCasc(); + double etaPiFromCharmBaryon = candidate.etaBachFromCharmBaryon(); + if (std::abs(etaV0PosDau) > etaTrackLFDauMax) { + resultSelections = false; + registry.fill(HIST("hSelEtaPosV0Dau"), 0); + } else { + registry.fill(HIST("hSelEtaPosV0Dau"), 1); + } + if (std::abs(etaV0NegDau) > etaTrackLFDauMax) { + resultSelections = false; + registry.fill(HIST("hSelEtaNegV0Dau"), 0); + } else { + registry.fill(HIST("hSelEtaNegV0Dau"), 1); + } + if (std::abs(etaPiFromCasc) > etaTrackLFDauMax) { + resultSelections = false; + registry.fill(HIST("hSelEtaPiFromCasc"), 0); + } else { + registry.fill(HIST("hSelEtaPiFromCasc"), 1); + } + if (std::abs(etaPiFromCharmBaryon) > etaTrackCharmBachMax) { + resultSelections = false; + registry.fill(HIST("hSelEtaPiFromCharm"), 0); + } else { + registry.fill(HIST("hSelEtaPiFromCharm"), 1); + } + + // minimum radius cut (LFcut) + if (RecoDecay::sqrtSumOfSquares(candidate.xDecayVtxCascade(), candidate.yDecayVtxCascade()) < radiusCascMin) { + resultSelections = false; + registry.fill(HIST("hSelRadCasc"), 0); + } else { + registry.fill(HIST("hSelRadCasc"), 1); + } + if (RecoDecay::sqrtSumOfSquares(candidate.xDecayVtxV0(), candidate.yDecayVtxV0()) < radiusV0Min) { + resultSelections = false; + registry.fill(HIST("hSelRadV0"), 0); + } else { + registry.fill(HIST("hSelRadV0"), 1); + } + + // cosPA (LFcut) + if (candidate.cosPACasc() < cosPACascMin) { + resultSelections = false; + registry.fill(HIST("hSelCosPACasc"), 0); + } else { + registry.fill(HIST("hSelCosPACasc"), 1); + } + if (candidate.cosPAV0() < cosPAV0Min) { + resultSelections = false; + registry.fill(HIST("hSelCosPAV0"), 0); + } else { + registry.fill(HIST("hSelCosPAV0"), 1); + } + + // cascade and v0 daughters dca cut (LF cut) + if (candidate.dcaCascDau() > dcaCascDauMax) { + resultSelections = false; + registry.fill(HIST("hSelDCACascDau"), 0); + } else { + registry.fill(HIST("hSelDCACascDau"), 1); + } + + if (candidate.dcaV0Dau() > dcaV0DauMax) { + resultSelections = false; + registry.fill(HIST("hSelDCAV0Dau"), 0); + } else { + registry.fill(HIST("hSelDCAV0Dau"), 1); + } + + // dca charm baryon daughters cut + if (candidate.dcaCharmBaryonDau() > dcaCharmBaryonDauMax) { + resultSelections = false; + registry.fill(HIST("hSelDCACharmDau"), 0); + } else { + registry.fill(HIST("hSelDCACharmDau"), 1); + } + + // dcaXY v0 daughters to PV cut + if (std::abs(candidate.dcaXYToPvV0Dau0()) < dcaPosToPvMin || std::abs(candidate.dcaXYToPvV0Dau1()) < dcaNegToPvMin) { + resultSelections = false; + registry.fill(HIST("hSelDcaXYToPvV0Daughters"), 0); + } else { + registry.fill(HIST("hSelDcaXYToPvV0Daughters"), 1); + } + + // dcaXY ka <-- cascade to PV cut + if (std::abs(candidate.dcaXYToPvCascDau()) < dcaBachToPvMin) { + resultSelections = false; + registry.fill(HIST("hSelDcaXYToPvPiFromCasc"), 0); + } else { + registry.fill(HIST("hSelDcaXYToPvPiFromCasc"), 1); + } + + // cut on charm bachelor pion dcaXY and dcaZ + if ((std::abs(candidate.impactParBachFromCharmBaryonXY()) < impactParameterXYPiFromCharmBaryonMin) || (std::abs(candidate.impactParBachFromCharmBaryonXY()) > impactParameterXYPiFromCharmBaryonMax)) { + resultSelections = false; + registry.fill(HIST("hSelDCAXYPrimPi"), 0); + } else { + registry.fill(HIST("hSelDCAXYPrimPi"), 1); + } + if ((std::abs(candidate.impactParBachFromCharmBaryonZ()) < impactParameterZPiFromCharmBaryonMin) || (std::abs(candidate.impactParBachFromCharmBaryonZ()) > impactParameterZPiFromCharmBaryonMax)) { + resultSelections = false; + registry.fill(HIST("hSelDCAZPrimPi"), 0); + } else { + registry.fill(HIST("hSelDCAZPrimPi"), 1); + } + + // cut on cascade dcaXY and dcaZ + if ((std::abs(candidate.impactParCascXY()) < impactParameterXYCascMin) || (std::abs(candidate.impactParCascXY()) > impactParameterXYCascMax)) { + resultSelections = false; + registry.fill(HIST("hSelDCAXYCasc"), 0); + } else { + registry.fill(HIST("hSelDCAXYCasc"), 1); + } + if ((std::abs(candidate.impactParCascZ()) < impactParameterZCascMin) || (std::abs(candidate.impactParCascZ()) > impactParameterZCascMax)) { + resultSelections = false; + registry.fill(HIST("hSelDCAZCasc"), 0); + } else { + registry.fill(HIST("hSelDCAZCasc"), 1); + } + + // pT selections + double ptPiFromCasc = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCasc(), candidate.pyBachFromCasc()); + double ptPiFromCharmBaryon = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCharmBaryon(), candidate.pyBachFromCharmBaryon()); + if (std::abs(ptPiFromCasc) < ptPiFromCascMin) { + resultSelections = false; + registry.fill(HIST("hSelPtPiFromCasc"), 0); + } else { + registry.fill(HIST("hSelPtPiFromCasc"), 1); + } + if (std::abs(ptPiFromCharmBaryon) < ptPiFromCharmBaryonMin) { + resultSelections = false; + registry.fill(HIST("hSelPtPiFromCharm"), 0); + } else { + registry.fill(HIST("hSelPtPiFromCharm"), 1); + } + + // TPC clusters selections + if (applyTrkSelLf) { + if (!isSelectedTrackTpcQuality(trackPiFromLam, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { + resultSelections = false; + registry.fill(HIST("hSelTPCQualityPiFromLam"), 0); + } else { + registry.fill(HIST("hSelTPCQualityPiFromLam"), 1); + } + if (!isSelectedTrackTpcQuality(trackPrFromLam, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { + resultSelections = false; + registry.fill(HIST("hSelTPCQualityPrFromLam"), 0); + } else { + registry.fill(HIST("hSelTPCQualityPrFromLam"), 1); + } + if (!isSelectedTrackTpcQuality(trackPiFromCasc, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { + resultSelections = false; + registry.fill(HIST("hSelTPCQualityPiFromCasc"), 0); + } else { + registry.fill(HIST("hSelTPCQualityPiFromCasc"), 1); + } + } + if (!isSelectedTrackTpcQuality(trackPiFromCharm, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { + resultSelections = false; + registry.fill(HIST("hSelTPCQualityPiFromCharm"), 0); + } else { + registry.fill(HIST("hSelTPCQualityPiFromCharm"), 1); + } + + // ITS clusters selection + if (!isSelectedTrackItsQuality(trackPiFromCharm, nClustersItsMin, itsChi2PerClusterMax) || trackPiFromCharm.itsNClsInnerBarrel() < nClustersItsInnBarrMin) { + resultSelections = false; + registry.fill(HIST("hSelITSQualityPiFromCharm"), 0); + } else { + registry.fill(HIST("hSelITSQualityPiFromCharm"), 1); + } + + // track-level PID selection + + // for TrackSelectorPID + int statusPidPrFromLam = -999; + int statusPidPiFromLam = -999; + int statusPidPiFromCasc = -999; + int statusPidPiFromCharmBaryon = -999; + + bool statusPidLambda = false; + bool statusPidCascade = false; + bool statusPidCharmBaryon = false; + + int infoTpcStored = 0; + int infoTofStored = 0; + + if (usePidTpcOnly == usePidTpcTofCombined) { + LOGF(fatal, "Check the PID configurables, usePidTpcOnly and usePidTpcTofCombined can't have the same value"); + } + + if (trackPiFromLam.hasTPC()) { + SETBIT(infoTpcStored, PiFromLam); + } + if (trackPrFromLam.hasTPC()) { + SETBIT(infoTpcStored, PiFromLam); + } + if (trackPiFromCasc.hasTPC()) { + SETBIT(infoTpcStored, PiFromCasc); + } + if (trackPiFromCharm.hasTPC()) { + SETBIT(infoTpcStored, PiFromCharm); + } + if (trackPiFromLam.hasTOF()) { + SETBIT(infoTofStored, PiFromLam); + } + if (trackPrFromLam.hasTOF()) { + SETBIT(infoTofStored, PiFromLam); + } + if (trackPiFromCasc.hasTOF()) { + SETBIT(infoTofStored, PiFromCasc); + } + if (trackPiFromCharm.hasTOF()) { + SETBIT(infoTofStored, PiFromCharm); + } + + if (usePidTpcOnly) { + statusPidPrFromLam = selectorProton.statusTpc(trackPrFromLam); + statusPidPiFromLam = selectorPion.statusTpc(trackPiFromLam); + statusPidPiFromCasc = selectorPion.statusTpc(trackPiFromCasc); + statusPidPiFromCharmBaryon = selectorPion.statusTpc(trackPiFromCharm); + } else if (usePidTpcTofCombined) { + statusPidPrFromLam = selectorProton.statusTpcOrTof(trackPrFromLam); + statusPidPiFromLam = selectorPion.statusTpcOrTof(trackPiFromLam); + statusPidPiFromCasc = selectorPion.statusTpcOrTof(trackPiFromCasc); + statusPidPiFromCharmBaryon = selectorPion.statusTpcOrTof(trackPiFromCharm); + } + + if (statusPidPrFromLam == TrackSelectorPID::Accepted && statusPidPiFromLam == TrackSelectorPID::Accepted) { + statusPidLambda = true; + if (resultSelections) { + registry.fill(HIST("hStatusCheck"), 0.5); + } + } + + if (statusPidPrFromLam == TrackSelectorPID::Accepted && statusPidPiFromLam == TrackSelectorPID::Accepted && statusPidPiFromCasc == TrackSelectorPID::Accepted) { + statusPidCascade = true; + if (resultSelections) { + registry.fill(HIST("hStatusCheck"), 1.5); + } + } + + if (statusPidPrFromLam == TrackSelectorPID::Accepted && statusPidPiFromLam == TrackSelectorPID::Accepted && statusPidPiFromCasc == TrackSelectorPID::Accepted && statusPidPiFromCharmBaryon == TrackSelectorPID::Accepted) { + statusPidCharmBaryon = true; + if (resultSelections) { + registry.fill(HIST("hStatusCheck"), 2.5); + } + } + + // invariant mass cuts + bool statusInvMassLambda = false; + bool statusInvMassCascade = false; + bool statusInvMassCharmBaryon = false; + + double invMassLambda = candidate.invMassLambda(); + double invMassCascade = candidate.invMassCascade(); + double invMassCharmBaryon = candidate.invMassCharmBaryon(); + + if (std::abs(invMassLambda - o2::constants::physics::MassLambda0) < v0MassWindow) { + statusInvMassLambda = true; + registry.fill(HIST("hSelMassLam"), 1); + if (statusPidLambda && statusPidCascade && statusPidCharmBaryon && resultSelections) { + registry.fill(HIST("hStatusCheck"), 3.5); + } + } else { + registry.fill(HIST("hSelMassLam"), 0); + } + + if (std::abs(invMassCascade - o2::constants::physics::MassXiMinus) < cascadeMassWindow) { + statusInvMassCascade = true; + registry.fill(HIST("hSelMassCasc"), 1); + if (statusPidLambda && statusPidCascade && statusPidCharmBaryon && statusInvMassLambda && resultSelections) { + registry.fill(HIST("hStatusCheck"), 4.5); + } + } else { + registry.fill(HIST("hSelMassCasc"), 0); + } + + if ((invMassCharmBaryon >= invMassCharmBaryonMin) && (invMassCharmBaryon <= invMassCharmBaryonMax)) { + statusInvMassCharmBaryon = true; + registry.fill(HIST("hSelMassCharmBaryon"), 1); + if (statusPidLambda && statusPidCascade && statusPidCharmBaryon && statusInvMassLambda && statusInvMassCascade && resultSelections) { + registry.fill(HIST("hStatusCheck"), 5.5); + } + } else { + registry.fill(HIST("hSelMassCharmBaryon"), 0); + } + + hfSelToXiPi(statusPidCharmBaryon, statusPidCascade, statusPidLambda, statusInvMassCharmBaryon, statusInvMassCascade, statusInvMassLambda, resultSelections, infoTpcStored, infoTofStored, + trackPiFromCharm.tpcNSigmaPi(), trackPiFromCasc.tpcNSigmaPi(), trackPiFromLam.tpcNSigmaPi(), trackPrFromLam.tpcNSigmaPr(), + trackPiFromCharm.tofNSigmaPi(), trackPiFromCasc.tofNSigmaPi(), trackPiFromLam.tofNSigmaPi(), trackPrFromLam.tofNSigmaPr()); + + if (resultSelections) { + if (!statusPidLambda) { + registry.fill(HIST("hSelPID"), 0.5); + } + if (statusPidLambda) { + registry.fill(HIST("hSelPID"), 1.5); + } + if (!statusPidCascade) { + registry.fill(HIST("hSelPID"), 2.5); + } + if (statusPidCascade) { + registry.fill(HIST("hSelPID"), 3.5); + } + if (!statusPidCharmBaryon) { + registry.fill(HIST("hSelPID"), 4.5); + } + if (statusPidCharmBaryon) { + registry.fill(HIST("hSelPID"), 5.5); + } + if (!statusInvMassLambda) { + registry.fill(HIST("hSelPID"), 6.5); + } + if (statusInvMassLambda) { + registry.fill(HIST("hSelPID"), 7.5); + } + if (!statusInvMassCascade) { + registry.fill(HIST("hSelPID"), 8.5); + } + if (statusInvMassCascade) { + registry.fill(HIST("hSelPID"), 9.5); + } + if (!statusInvMassCharmBaryon) { + registry.fill(HIST("hSelPID"), 10.5); + } + if (statusInvMassCharmBaryon) { + registry.fill(HIST("hSelPID"), 11.5); + } + } + + if (statusPidLambda && statusPidCascade && statusPidCharmBaryon && statusInvMassLambda && statusInvMassCascade && statusInvMassCharmBaryon && resultSelections) { + hInvMassCharmBaryon->Fill(invMassCharmBaryon); + } + } + } // end process +}; // end struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/candidateSelectorXicToPKPi.cxx b/PWGHF/TableProducer/candidateSelectorXicToPKPi.cxx index 14e9bef0bd6..f9bd95d6aa7 100644 --- a/PWGHF/TableProducer/candidateSelectorXicToPKPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorXicToPKPi.cxx @@ -17,6 +17,9 @@ /// \author Vít Kučera , CERN /// \author Cristina Terrevoli , INFN BARI +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -41,6 +44,8 @@ struct HfCandidateSelectorXicToPKPi { Configurable ptCandMin{"ptCandMin", 0., "Lower bound of candidate pT"}; Configurable ptCandMax{"ptCandMax", 36., "Upper bound of candidate pT"}; Configurable usePid{"usePid", true, "Bool to use or not the PID at filtering level"}; + // Combined PID options + Configurable usePidTpcAndTof{"usePidTpcAndTof", false, "Bool to decide how to combine TPC and TOF PID: true = both (if present, only one otherwise); false = one is enough"}; // TPC PID Configurable ptPidTpcMin{"ptPidTpcMin", 0.15, "Lower bound of track pT for TPC PID"}; Configurable ptPidTpcMax{"ptPidTpcMax", 20., "Upper bound of track pT for TPC PID"}; @@ -54,13 +59,13 @@ struct HfCandidateSelectorXicToPKPi { // topological cuts Configurable decayLengthXYNormalisedMin{"decayLengthXYNormalisedMin", 3., "Min. normalised decay length XY"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_xic_to_p_k_pi::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_xic_to_p_k_pi::cuts[0], hf_cuts_xic_to_p_k_pi::nBinsPt, hf_cuts_xic_to_p_k_pi::nCutVars, hf_cuts_xic_to_p_k_pi::labelsPt, hf_cuts_xic_to_p_k_pi::labelsCutVar}, "Xic candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_xic_to_p_k_pi::Cuts[0], hf_cuts_xic_to_p_k_pi::NBinsPt, hf_cuts_xic_to_p_k_pi::NCutVars, hf_cuts_xic_to_p_k_pi::labelsPt, hf_cuts_xic_to_p_k_pi::labelsCutVar}, "Xic candidate selection per pT bin"}; // ML inference Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; Configurable> binsPtMl{"binsPtMl", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; Configurable> cutDirMl{"cutDirMl", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; - Configurable> cutsMl{"cutsMl", {hf_cuts_ml::cuts[0], hf_cuts_ml::nBinsPt, hf_cuts_ml::nCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; - Configurable nClassesMl{"nClassesMl", (int8_t)hf_cuts_ml::nCutScores, "Number of classes in ML model"}; + Configurable> cutsMl{"cutsMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable nClassesMl{"nClassesMl", static_cast(hf_cuts_ml::NCutScores), "Number of classes in ML model"}; Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; // CCDB configuration Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -68,6 +73,8 @@ struct HfCandidateSelectorXicToPKPi { Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_XicToPKPi.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + // QA switch + Configurable activateQA{"activateQA", true, "Flag to enable QA histogram"}; o2::analysis::HfMlResponseXicToPKPi hfMlResponse; std::vector outputMlXicToPKPi = {}; @@ -78,7 +85,9 @@ struct HfCandidateSelectorXicToPKPi { TrackSelectorPr selectorProton; HfHelper hfHelper; - using TracksSel = soa::Join; + using TracksSel = soa::Join; + + HistogramRegistry registry{"registry"}; void init(InitContext const&) { @@ -91,6 +100,21 @@ struct HfCandidateSelectorXicToPKPi { selectorKaon = selectorPion; selectorProton = selectorPion; + if (activateQA) { + constexpr int kNBinsSelections = 1 + aod::SelectionStep::NSelectionSteps; + std::string labels[kNBinsSelections]; + labels[0] = "No selection"; + labels[1 + aod::SelectionStep::RecoSkims] = "Skims selection"; + labels[1 + aod::SelectionStep::RecoTopol] = "Skims & Topological selections"; + labels[1 + aod::SelectionStep::RecoPID] = "Skims & Topological & PID selections"; + labels[1 + aod::SelectionStep::RecoMl] = "ML selection"; + static const AxisSpec axisSelections = {kNBinsSelections, 0.5, kNBinsSelections + 0.5, ""}; + registry.add("hSelections", "Selections;;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisSelections, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + for (int iBin = 0; iBin < kNBinsSelections; ++iBin) { + registry.get(HIST("hSelections"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); + } + } + if (applyMl) { hfMlResponse.configure(binsPtMl, cutsMl, cutDirMl, nClassesMl); if (loadModelsFromCCDB) { @@ -211,18 +235,24 @@ struct HfCandidateSelectorXicToPKPi { outputMlXicToPKPi.clear(); outputMlXicToPiKP.clear(); + auto ptCand = candidate.pt(); + if (!TESTBIT(candidate.hfflag(), aod::hf_cand_3prong::DecayType::XicToPKPi)) { hfSelXicToPKPiCandidate(statusXicToPKPi, statusXicToPiKP); if (applyMl) { hfMlXicToPKPiCandidate(outputMlXicToPKPi, outputMlXicToPiKP); } + if (activateQA) { + registry.fill(HIST("hSelections"), 1, ptCand); + } continue; } + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + aod::SelectionStep::RecoSkims, ptCand); + } SETBIT(statusXicToPKPi, aod::SelectionStep::RecoSkims); SETBIT(statusXicToPiKP, aod::SelectionStep::RecoSkims); - auto ptCand = candidate.pt(); - auto trackPos1 = candidate.prong0_as(); // positive daughter (negative for the antiparticles) auto trackNeg = candidate.prong1_as(); // negative daughter (positive for the antiparticles) auto trackPos2 = candidate.prong2_as(); // positive daughter (negative for the antiparticles) @@ -257,6 +287,10 @@ struct HfCandidateSelectorXicToPKPi { SETBIT(statusXicToPiKP, aod::SelectionStep::RecoTopol); } + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + aod::SelectionStep::RecoTopol, candidate.pt()); + } + auto pidXicToPKPi = -1; auto pidXicToPiKP = -1; @@ -266,11 +300,25 @@ struct HfCandidateSelectorXicToPKPi { pidXicToPiKP = 1; } else { // track-level PID selection - auto pidTrackPos1Proton = selectorProton.statusTpcOrTof(trackPos1); - auto pidTrackPos2Proton = selectorProton.statusTpcOrTof(trackPos2); - auto pidTrackPos1Pion = selectorPion.statusTpcOrTof(trackPos1); - auto pidTrackPos2Pion = selectorPion.statusTpcOrTof(trackPos2); - auto pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg); + TrackSelectorPID::Status pidTrackPos1Proton = TrackSelectorPID::Accepted; + TrackSelectorPID::Status pidTrackPos2Proton = TrackSelectorPID::Accepted; + TrackSelectorPID::Status pidTrackPos1Pion = TrackSelectorPID::Accepted; + TrackSelectorPID::Status pidTrackPos2Pion = TrackSelectorPID::Accepted; + TrackSelectorPID::Status pidTrackNegKaon = TrackSelectorPID::Accepted; + if (usePidTpcAndTof) { + + pidTrackPos1Proton = selectorProton.statusTpcAndTof(trackPos1); + pidTrackPos2Proton = selectorProton.statusTpcAndTof(trackPos2); + pidTrackPos1Pion = selectorPion.statusTpcAndTof(trackPos1); + pidTrackPos2Pion = selectorPion.statusTpcAndTof(trackPos2); + pidTrackNegKaon = selectorKaon.statusTpcAndTof(trackNeg); + } else { + pidTrackPos1Proton = selectorProton.statusTpcOrTof(trackPos1); + pidTrackPos2Proton = selectorProton.statusTpcOrTof(trackPos2); + pidTrackPos1Pion = selectorPion.statusTpcOrTof(trackPos1); + pidTrackPos2Pion = selectorPion.statusTpcOrTof(trackPos2); + pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg); + } if (pidTrackPos1Proton == TrackSelectorPID::Accepted && pidTrackNegKaon == TrackSelectorPID::Accepted && @@ -306,6 +354,9 @@ struct HfCandidateSelectorXicToPKPi { if ((pidXicToPiKP == -1 || pidXicToPiKP == 1) && topolXicToPiKP) { SETBIT(statusXicToPiKP, aod::SelectionStep::RecoPID); } + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + aod::SelectionStep::RecoPID, candidate.pt()); + } if (applyMl) { // ML selections @@ -313,11 +364,11 @@ struct HfCandidateSelectorXicToPKPi { bool isSelectedMlXicToPiKP = false; if (topolXicToPKPi && pidXicToPKPi) { - std::vector inputFeaturesXicToPKPi = hfMlResponse.getInputFeatures(candidate, trackPos1, trackNeg, trackPos2); + std::vector inputFeaturesXicToPKPi = hfMlResponse.getInputFeatures(candidate, trackPos1, trackNeg, trackPos2, true); isSelectedMlXicToPKPi = hfMlResponse.isSelectedMl(inputFeaturesXicToPKPi, ptCand, outputMlXicToPKPi); } if (topolXicToPiKP && pidXicToPiKP) { - std::vector inputFeaturesXicToPiKP = hfMlResponse.getInputFeatures(candidate, trackPos1, trackNeg, trackPos2); + std::vector inputFeaturesXicToPiKP = hfMlResponse.getInputFeatures(candidate, trackPos1, trackNeg, trackPos2, false); isSelectedMlXicToPiKP = hfMlResponse.isSelectedMl(inputFeaturesXicToPiKP, ptCand, outputMlXicToPiKP); } @@ -332,7 +383,10 @@ struct HfCandidateSelectorXicToPKPi { SETBIT(statusXicToPKPi, aod::SelectionStep::RecoMl); } if (isSelectedMlXicToPiKP) { - SETBIT(statusXicToPKPi, aod::SelectionStep::RecoMl); + SETBIT(statusXicToPiKP, aod::SelectionStep::RecoMl); + } + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + aod::SelectionStep::RecoMl, candidate.pt()); } } diff --git a/PWGHF/TableProducer/candidateSelectorXicToXiPiPi.cxx b/PWGHF/TableProducer/candidateSelectorXicToXiPiPi.cxx new file mode 100644 index 00000000000..745a881d7ad --- /dev/null +++ b/PWGHF/TableProducer/candidateSelectorXicToXiPiPi.cxx @@ -0,0 +1,314 @@ +// 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 candidateSelectorXicToXiPiPi.cxx +/// \brief Ξc± → Ξ∓ π± π± candidate selector +/// +/// \author Phil Lennart Stahlhut , Heidelberg University +/// \author Jaeyoon Cho , Inha University + +#include +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/TrackSelectorPID.h" + +#include "PWGHF/Core/HfMlResponseXicToXiPiPi.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" // findBin function + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::analysis; + +struct HfCandidateSelectorXicToXiPiPi { + Produces hfSelXicToXiPiPiCandidate; + Produces hfMlXicToXiPiPiCandidate; + + Configurable ptCandMin{"ptCandMin", 0., "Lower bound of candidate pT"}; + Configurable ptCandMax{"ptCandMax", 36., "Upper bound of candidate pT"}; + // topological cuts + Configurable> binsPt{"binsPt", std::vector{hf_cuts_xic_to_xi_pi_pi::vecBinsPt}, "pT bin limits"}; + Configurable> cuts{"cuts", {hf_cuts_xic_to_xi_pi_pi::Cuts[0], hf_cuts_xic_to_xi_pi_pi::NBinsPt, hf_cuts_xic_to_xi_pi_pi::NCutVars, hf_cuts_xic_to_xi_pi_pi::labelsPt, hf_cuts_xic_to_xi_pi_pi::labelsCutVar}, "Xicplus candidate selection per pT bin"}; + // QA switch + Configurable activateQA{"activateQA", false, "Flag to enable QA histogram"}; + // Enable PID + Configurable usePid{"usePid", true, "Switch for PID selection at track level"}; + Configurable acceptPIDNotApplicable{"acceptPIDNotApplicable", true, "Switch to accept Status::NotApplicable [(NotApplicable for one detector) and (NotApplicable or Conditional for the other)] in PID selection"}; + // TPC PID + Configurable ptPidTpcMin{"ptPidTpcMin", 0.15, "Lower bound of track pT for TPC PID"}; + Configurable ptPidTpcMax{"ptPidTpcMax", 20., "Upper bound of track pT for TPC PID"}; + Configurable nSigmaTpcMax{"nSigmaTpcMax", 5., "Nsigma cut on TPC only"}; + Configurable nSigmaTpcCombinedMax{"nSigmaTpcCombinedMax", 5., "Nsigma cut on TPC combined with TOF"}; + // TOF PID + Configurable ptPidTofMin{"ptPidTofMin", 0.15, "Lower bound of track pT for TOF PID"}; + Configurable ptPidTofMax{"ptPidTofMax", 20., "Upper bound of track pT for TOF PID"}; + Configurable nSigmaTofMax{"nSigmaTofMax", 5., "Nsigma cut on TOF only"}; + Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 5., "Nsigma cut on TOF combined with TPC"}; + // ML inference + Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; + Configurable> binsPtMl{"binsPtMl", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; + Configurable> cutDirMl{"cutDirMl", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; + Configurable> cutsMl{"cutsMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable nClassesMl{"nClassesMl", static_cast(hf_cuts_ml::NCutScores), "Number of classes in ML model"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; + // CCDB configuration + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"EventFiltering/PWGHF/BDTXicToXiPiPi"}, "Paths of models on CCDB"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_XicToXiPiPi.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + + o2::analysis::HfMlResponseXicToXiPiPi hfMlResponse; + std::vector outputMlXicToXiPiPi = {}; + o2::ccdb::CcdbApi ccdbApi; + TrackSelectorPi selectorPion; + TrackSelectorPr selectorProton; + + using TracksPidWithSel = soa::Join; + + HistogramRegistry registry{"registry"}; + + void init(InitContext&) + { + if (usePid) { + // pion + selectorPion.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); + selectorPion.setRangeNSigmaTpc(-nSigmaTpcMax, nSigmaTpcMax); + selectorPion.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedMax, nSigmaTpcCombinedMax); + selectorPion.setRangePtTof(ptPidTofMin, ptPidTofMax); + selectorPion.setRangeNSigmaTof(-nSigmaTofMax, nSigmaTofMax); + selectorPion.setRangeNSigmaTofCondTpc(-nSigmaTofCombinedMax, nSigmaTofCombinedMax); + // proton + selectorProton.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); + selectorProton.setRangeNSigmaTpc(-nSigmaTpcMax, nSigmaTpcMax); + selectorProton.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedMax, nSigmaTpcCombinedMax); + selectorProton.setRangePtTof(ptPidTofMin, ptPidTofMax); + selectorProton.setRangeNSigmaTof(-nSigmaTofMax, nSigmaTofMax); + selectorProton.setRangeNSigmaTofCondTpc(-nSigmaTofCombinedMax, nSigmaTofCombinedMax); + } + + if (activateQA) { + constexpr int kNBinsSelections = 1 + SelectionStep::NSelectionSteps; + std::string labels[kNBinsSelections]; + labels[0] = "No selection"; + labels[1 + SelectionStep::RecoSkims] = "Skims selection"; + labels[1 + SelectionStep::RecoTopol] = "Skims & Topological selections"; + labels[1 + SelectionStep::RecoPID] = "Skims & Topological & PID selections"; + labels[1 + SelectionStep::RecoMl] = "Skims & Topological & PID & ML selections"; + static const AxisSpec axisSelections = {kNBinsSelections, 0.5, kNBinsSelections + 0.5, ""}; + registry.add("hSelections", "Selections;;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisSelections, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + for (int iBin = 0; iBin < kNBinsSelections; ++iBin) { + registry.get(HIST("hSelections"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); + } + } + + if (applyMl) { + hfMlResponse.configure(binsPtMl, cutsMl, cutDirMl, nClassesMl); + if (loadModelsFromCCDB) { + ccdbApi.init(ccdbUrl); + hfMlResponse.setModelPathsCCDB(onnxFileNames, ccdbApi, modelPathsCCDB, timestampCCDB); + } else { + hfMlResponse.setModelPathsLocal(onnxFileNames); + } + hfMlResponse.cacheInputFeaturesIndices(namesInputFeatures); + hfMlResponse.init(); + } + } + + /// Conjugate-independent topological cuts + /// \param candidate is candidate + /// \return true if candidate passes all cuts + template + bool selectionTopol(const T1& hfCandXic) + { + auto candpT = hfCandXic.pt(); + int pTBin = findBin(binsPt, candpT); + if (pTBin == -1) { + return false; + } + + // check that the candidate pT is within the analysis range + if (candpT < ptCandMin || candpT >= ptCandMax) { + return false; + } + + // check candidate mass is within a defined mass window + if (std::abs(hfCandXic.invMassXicPlus() - o2::constants::physics::MassXiCPlus) > cuts->get(pTBin, "m")) { + return false; + } + + // cosine of pointing angle + if (hfCandXic.cpa() <= cuts->get(pTBin, "cos pointing angle")) { + return false; + } + + // cosine of pointing angle XY + if (hfCandXic.cpaXY() <= cuts->get(pTBin, "cos pointing angle XY")) { + return false; + } + + // candidate maximum decay length + if (hfCandXic.decayLength() > cuts->get(pTBin, "max decay length")) { + return false; + } + + // candidate maximum decay length XY + if (hfCandXic.decayLengthXY() > cuts->get(pTBin, "max decay length XY")) { + return false; + } + + // candidate chi2PC + if (hfCandXic.chi2PCA() > cuts->get(pTBin, "chi2PCA")) { + return false; + } + + // maximum DCA of daughters + if ((std::abs(hfCandXic.impactParameter0()) > cuts->get(pTBin, "max impParXY Xi")) || + (std::abs(hfCandXic.impactParameter1()) > cuts->get(pTBin, "max impParXY Pi0")) || + (std::abs(hfCandXic.impactParameter2()) > cuts->get(pTBin, "max impParXY Pi1"))) { + return false; + } + + // cut on daughter pT + if (hfCandXic.ptProng0() < cuts->get(pTBin, "pT Xi") || + hfCandXic.ptProng1() < cuts->get(pTBin, "pT Pi0") || + hfCandXic.ptProng2() < cuts->get(pTBin, "pT Pi1")) { + return false; + } + + return true; + } + + /// Apply PID selection + /// \param pidTrackPi0 PID status of trackPi0 (prong1 of Xic candidate) + /// \param pidTrackPi1 PID status of trackPi1 (prong2 of Xic candidate) + /// \param pidTrackPr PID status of trackPr (positive daughter of V0 candidate) + /// \param pidTrackPiLam PID status of trackPiLam (negative daughter of V0 candidate) + /// \param pidTrackPiXi PID status of trackPiXi (Bachelor of cascade candidate) + /// \param acceptPIDNotApplicable switch to accept Status::NotApplicable + /// \return true if prongs of Xic candidate pass all selections + bool selectionPid(TrackSelectorPID::Status const pidTrackPi0, + TrackSelectorPID::Status const pidTrackPi1, + TrackSelectorPID::Status const pidTrackPr, + TrackSelectorPID::Status const pidTrackPiLam, + TrackSelectorPID::Status const pidTrackPiXi, + bool const acceptPIDNotApplicable) + { + if (!acceptPIDNotApplicable && (pidTrackPi0 != TrackSelectorPID::Accepted || pidTrackPi1 != TrackSelectorPID::Accepted || pidTrackPr != TrackSelectorPID::Accepted || pidTrackPiLam != TrackSelectorPID::Accepted || pidTrackPiXi != TrackSelectorPID::Accepted)) { + return false; + } + if (acceptPIDNotApplicable && (pidTrackPi0 == TrackSelectorPID::Rejected || pidTrackPi1 == TrackSelectorPID::Rejected || pidTrackPr == TrackSelectorPID::Rejected || pidTrackPiLam == TrackSelectorPID::Rejected || pidTrackPiXi == TrackSelectorPID::Rejected)) { + return false; + } + return true; + } + + void process(aod::HfCandXic const& hfCandsXic, + TracksPidWithSel const&) + { + for (const auto& hfCandXic : hfCandsXic) { + int statusXicToXiPiPi = 0; + + outputMlXicToXiPiPi.clear(); + + auto ptCandXic = hfCandXic.pt(); + + if (activateQA) { + registry.fill(HIST("hSelections"), 1, ptCandXic); + } + + // No hfflag -> by default skim selected + SETBIT(statusXicToXiPiPi, SelectionStep::RecoSkims); // RecoSkims = 0 --> statusXicToXiPiPi = 1 + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoSkims, ptCandXic); + } + + // topological cuts + if (!selectionTopol(hfCandXic)) { + hfSelXicToXiPiPiCandidate(statusXicToXiPiPi); + if (applyMl) { + hfMlXicToXiPiPiCandidate(outputMlXicToXiPiPi); + } + continue; + } + SETBIT(statusXicToXiPiPi, SelectionStep::RecoTopol); // RecoTopol = 1 --> statusXicToXiPiPi = 3 + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoTopol, ptCandXic); + } + + // track-level PID selection + if (usePid) { + auto trackPi0 = hfCandXic.pi0_as(); + auto trackPi1 = hfCandXic.pi1_as(); + auto trackV0PosDau = hfCandXic.posTrack_as(); + auto trackV0NegDau = hfCandXic.negTrack_as(); + auto trackPiFromXi = hfCandXic.bachelor_as(); + // assign proton and pion hypothesis to V0 daughters + auto trackPr = trackV0PosDau; + auto trackPiFromLam = trackV0NegDau; + if (hfCandXic.sign() < 0) { + trackPr = trackV0NegDau; + trackPiFromLam = trackV0PosDau; + } + // PID info + TrackSelectorPID::Status pidTrackPi0 = selectorPion.statusTpcAndTof(trackPi0); + TrackSelectorPID::Status pidTrackPi1 = selectorPion.statusTpcAndTof(trackPi1); + TrackSelectorPID::Status pidTrackPr = selectorProton.statusTpcAndTof(trackPr); + TrackSelectorPID::Status pidTrackPiLam = selectorPion.statusTpcAndTof(trackPiFromLam); + TrackSelectorPID::Status pidTrackPiXi = selectorPion.statusTpcAndTof(trackPiFromXi); + + if (!selectionPid(pidTrackPi0, pidTrackPi1, pidTrackPr, pidTrackPiLam, pidTrackPiXi, acceptPIDNotApplicable.value)) { + hfSelXicToXiPiPiCandidate(statusXicToXiPiPi); + if (applyMl) { + hfMlXicToXiPiPiCandidate(outputMlXicToXiPiPi); + } + continue; + } + SETBIT(statusXicToXiPiPi, SelectionStep::RecoPID); // RecoPID = 2 --> statusXicToXiPiPi = 7 + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoPID, ptCandXic); + } + } + + // ML selection + if (applyMl) { + bool isSelectedMlXicToXiPiPi = false; + std::vector inputFeaturesXicToXiPiPi = hfMlResponse.getInputFeatures(hfCandXic); + + isSelectedMlXicToXiPiPi = hfMlResponse.isSelectedMl(inputFeaturesXicToXiPiPi, ptCandXic, outputMlXicToXiPiPi); + + hfMlXicToXiPiPiCandidate(outputMlXicToXiPiPi); + + if (!isSelectedMlXicToXiPiPi) { + hfSelXicToXiPiPiCandidate(statusXicToXiPiPi); + continue; + } + SETBIT(statusXicToXiPiPi, aod::SelectionStep::RecoMl); + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoMl, ptCandXic); + } + } + + hfSelXicToXiPiPiCandidate(statusXicToXiPiPi); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/candidateSelectorXiccToPKPiPi.cxx b/PWGHF/TableProducer/candidateSelectorXiccToPKPiPi.cxx index ce9a5f3375f..28e0035f39c 100644 --- a/PWGHF/TableProducer/candidateSelectorXiccToPKPiPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorXiccToPKPiPi.cxx @@ -14,6 +14,8 @@ /// /// \author Gian Michele Innocenti , CERN +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -47,7 +49,7 @@ struct HfCandidateSelectorXiccToPKPiPi { Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 5., "Nsigma cut on TOF combined with TPC"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_xicc_to_p_k_pi_pi::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_xicc_to_p_k_pi_pi::cuts[0], hf_cuts_xicc_to_p_k_pi_pi::nBinsPt, hf_cuts_xicc_to_p_k_pi_pi::nCutVars, hf_cuts_xicc_to_p_k_pi_pi::labelsPt, hf_cuts_xicc_to_p_k_pi_pi::labelsCutVar}, "Xicc candidate selection per pT bin"}; + Configurable> cuts{"cuts", {hf_cuts_xicc_to_p_k_pi_pi::Cuts[0], hf_cuts_xicc_to_p_k_pi_pi::NBinsPt, hf_cuts_xicc_to_p_k_pi_pi::NCutVars, hf_cuts_xicc_to_p_k_pi_pi::labelsPt, hf_cuts_xicc_to_p_k_pi_pi::labelsCutVar}, "Xicc candidate selection per pT bin"}; HfHelper hfHelper; TrackSelectorPi selectorPion; diff --git a/PWGHF/TableProducer/converterDstarIndices.cxx b/PWGHF/TableProducer/converterDstarIndices.cxx new file mode 100644 index 00000000000..9596a571498 --- /dev/null +++ b/PWGHF/TableProducer/converterDstarIndices.cxx @@ -0,0 +1,42 @@ +// 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 converterDstarIndices.cxx +/// \brief Task for conversion of HfDstars to version 001, using the collision index from the D0 daughter +/// +/// \author Fabrizio Grosa , CERN + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" + +using namespace o2; +using namespace o2::framework; + +struct HfConverterDstarIndices { + Produces dstarIndices; + + void process(aod::HfDstars_000::iterator const& candDstar, + aod::Hf2Prongs const&) + { + auto candDzero = candDstar.prongD0_as(); + dstarIndices(candDzero.collisionId(), candDstar.prong0Id(), candDstar.prongD0Id()); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGHF/TableProducer/derivedDataCreatorBplusToD0Pi.cxx b/PWGHF/TableProducer/derivedDataCreatorBplusToD0Pi.cxx new file mode 100644 index 00000000000..abaf1573166 --- /dev/null +++ b/PWGHF/TableProducer/derivedDataCreatorBplusToD0Pi.cxx @@ -0,0 +1,439 @@ +// 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 derivedDataCreatorBplusToD0Pi.cxx +/// \brief Producer of derived tables of B+ candidates, collisions and MC particles +/// \note Based on derivedDataCreatorLcToPKPi.cxx +/// +/// \author Vít Kučera , Inha University + +#include +#include +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" + +#include "PWGLF/DataModel/mcCentrality.h" + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGHF/Utils/utilsDerivedData.h" +#include "PWGHF/Utils/utilsPid.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::pid_tpc_tof_utils; +using namespace o2::analysis::hf_derived; + +/// Writes the full information in an output TTree +struct HfDerivedDataCreatorBplusToD0Pi { + HfProducesDerivedData< + o2::aod::HfBplusBases, + o2::aod::HfBplusCollBases, + o2::aod::HfBplusCollIds, + o2::aod::HfBplusMcCollBases, + o2::aod::HfBplusMcCollIds, + o2::aod::HfBplusMcRCollIds, + o2::aod::HfBplusPBases, + o2::aod::HfBplusPIds> + rowsCommon; + // Candidates + Produces rowCandidatePar; + Produces rowCandidateParD0; + Produces rowCandidateParE; + Produces rowCandidateSel; + Produces rowCandidateMl; + Produces rowCandidateMlD0; + Produces rowCandidateId; + Produces rowCandidateMc; + + // Switches for filling tables + HfConfigurableDerivedData confDerData; + Configurable fillCandidatePar{"fillCandidatePar", true, "Fill candidate parameters"}; + Configurable fillCandidateParD0{"fillCandidateParD0", true, "Fill D0 candidate parameters"}; + Configurable fillCandidateParE{"fillCandidateParE", true, "Fill candidate extended parameters"}; + Configurable fillCandidateSel{"fillCandidateSel", true, "Fill candidate selection flags"}; + Configurable fillCandidateMl{"fillCandidateMl", true, "Fill candidate selection ML scores"}; + Configurable fillCandidateMlD0{"fillCandidateMlD0", true, "Fill D0 candidate selection ML scores"}; + Configurable fillCandidateId{"fillCandidateId", true, "Fill original indices from the candidate table"}; + Configurable fillCandidateMc{"fillCandidateMc", true, "Fill candidate MC info"}; + // Parameters for production of training samples + Configurable downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of background candidates to keep for ML trainings"}; + Configurable ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"}; + + HfHelper hfHelper; + SliceCache cache; + static constexpr double mass{o2::constants::physics::MassBPlus}; + + using CollisionsWCentMult = soa::Join; + using CollisionsWMcCentMult = soa::Join; + using TracksWPid = soa::Join; + using SelectedCandidates = soa::Filtered>; + using SelectedCandidatesMc = soa::Filtered>; + using SelectedCandidatesMl = soa::Filtered>; + using SelectedCandidatesMcMl = soa::Filtered>; + using MatchedGenCandidatesMc = soa::Filtered>; + using TypeMcCollisions = soa::Join; + using THfCandDaughtersMl = soa::Join; + + Filter filterSelectCandidates = (aod::hf_sel_candidate_bplus::isSelBplusToD0Pi & static_cast(BIT(aod::SelectionStep::RecoMl - 1))) != 0; + Filter filterMcGenMatching = nabs(aod::hf_cand_bplus::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_bplus::DecayType::BplusToD0Pi)); + + Preslice candidatesPerCollision = aod::hf_cand::collisionId; + Preslice candidatesMcPerCollision = aod::hf_cand::collisionId; + Preslice candidatesMlPerCollision = aod::hf_cand::collisionId; + Preslice candidatesMcMlPerCollision = aod::hf_cand::collisionId; + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + + // trivial partitions for all candidates to allow "->sliceByCached" inside processCandidates + Partition candidatesAll = aod::hf_sel_candidate_bplus::isSelBplusToD0Pi >= 0; + Partition candidatesMcAll = aod::hf_sel_candidate_bplus::isSelBplusToD0Pi >= 0; + Partition candidatesMlAll = aod::hf_sel_candidate_bplus::isSelBplusToD0Pi >= 0; + Partition candidatesMcMlAll = aod::hf_sel_candidate_bplus::isSelBplusToD0Pi >= 0; + // partitions for signal and background + Partition candidatesMcSig = nabs(aod::hf_cand_bplus::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_bplus::DecayType::BplusToD0Pi)); + Partition candidatesMcBkg = nabs(aod::hf_cand_bplus::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_bplus::DecayType::BplusToD0Pi)); + Partition candidatesMcMlSig = nabs(aod::hf_cand_bplus::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_bplus::DecayType::BplusToD0Pi)); + Partition candidatesMcMlBkg = nabs(aod::hf_cand_bplus::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_bplus::DecayType::BplusToD0Pi)); + + void init(InitContext const&) + { + std::array doprocess{doprocessData, doprocessMcSig, doprocessMcBkg, doprocessMcAll, doprocessDataMl, doprocessMcMlSig, doprocessMcMlBkg, doprocessMcMlAll, doprocessMcGenOnly}; + if (std::accumulate(doprocess.begin(), doprocess.end(), 0) != 1) { + LOGP(fatal, "Only one process function can be enabled at a time."); + } + rowsCommon.init(confDerData); + } + + template + void fillTablesCandidate(const T& candidate, const U& prongCharm, const V& prongBachelor, int candFlag, double invMass, + double ct, double y, int8_t flagMc, int8_t origin, float mlScore, const std::vector& mlScoresCharm) + { + rowsCommon.fillTablesCandidate(candidate, invMass, y); + if (fillCandidatePar) { + rowCandidatePar( + candidate.chi2PCA(), + candidate.cpa(), + candidate.cpaXY(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.decayLengthNormalised(), + candidate.decayLengthXYNormalised(), + candidate.ptProng0(), + candidate.ptProng1(), + candidate.impactParameter0(), + candidate.impactParameter1(), + candidate.impactParameterNormalised0(), + candidate.impactParameterNormalised1(), + prongBachelor.tpcNSigmaPi(), + prongBachelor.tofNSigmaPi(), + prongBachelor.tpcTofNSigmaPi(), + prongBachelor.tpcNSigmaKa(), + prongBachelor.tofNSigmaKa(), + prongBachelor.tpcTofNSigmaKa(), + candidate.maxNormalisedDeltaIP(), + candidate.impactParameterProduct()); + } + if (fillCandidateParD0) { + std::array, 2>, 2> sigmas{}; // PID nSigma [Expected][Hypothesis][TPC/TOF/TPC+TOF] + if (candFlag == 0) { + GET_N_SIGMA_PRONG(sigmas[HfProngSpecies::Pion][HfProngSpecies::Pion], prongCharm, 0, Pi) + GET_N_SIGMA_PRONG(sigmas[HfProngSpecies::Pion][HfProngSpecies::Kaon], prongCharm, 0, Ka) + GET_N_SIGMA_PRONG(sigmas[HfProngSpecies::Kaon][HfProngSpecies::Pion], prongCharm, 1, Pi) + GET_N_SIGMA_PRONG(sigmas[HfProngSpecies::Kaon][HfProngSpecies::Kaon], prongCharm, 1, Ka) + } else if (candFlag == 1) { + GET_N_SIGMA_PRONG(sigmas[HfProngSpecies::Pion][HfProngSpecies::Pion], prongCharm, 1, Pi) + GET_N_SIGMA_PRONG(sigmas[HfProngSpecies::Pion][HfProngSpecies::Kaon], prongCharm, 1, Ka) + GET_N_SIGMA_PRONG(sigmas[HfProngSpecies::Kaon][HfProngSpecies::Pion], prongCharm, 0, Pi) + GET_N_SIGMA_PRONG(sigmas[HfProngSpecies::Kaon][HfProngSpecies::Kaon], prongCharm, 0, Ka) + } + rowCandidateParD0( + prongCharm.cpa(), + prongCharm.decayLength(), + prongCharm.impactParameter0(), + prongCharm.impactParameter1(), + prongCharm.impactParameterProduct(), + sigmas[HfProngSpecies::Pion][HfProngSpecies::Pion][0], + sigmas[HfProngSpecies::Pion][HfProngSpecies::Pion][1], + sigmas[HfProngSpecies::Pion][HfProngSpecies::Pion][2], + sigmas[HfProngSpecies::Pion][HfProngSpecies::Kaon][0], + sigmas[HfProngSpecies::Pion][HfProngSpecies::Kaon][1], + sigmas[HfProngSpecies::Pion][HfProngSpecies::Kaon][2], + sigmas[HfProngSpecies::Kaon][HfProngSpecies::Pion][0], + sigmas[HfProngSpecies::Kaon][HfProngSpecies::Pion][1], + sigmas[HfProngSpecies::Kaon][HfProngSpecies::Pion][2], + sigmas[HfProngSpecies::Kaon][HfProngSpecies::Kaon][0], + sigmas[HfProngSpecies::Kaon][HfProngSpecies::Kaon][1], + sigmas[HfProngSpecies::Kaon][HfProngSpecies::Kaon][2]); + } + if (fillCandidateParE) { + rowCandidateParE( + candidate.xSecondaryVertex(), + candidate.ySecondaryVertex(), + candidate.zSecondaryVertex(), + candidate.errorDecayLength(), + candidate.errorDecayLengthXY(), + candidate.rSecondaryVertex(), + RecoDecay::p(candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1()), + candidate.pxProng1(), + candidate.pyProng1(), + candidate.pzProng1(), + candidate.errorImpactParameter1(), + hfHelper.cosThetaStarBplus(candidate), + ct); + } + if (fillCandidateSel) { + rowCandidateSel( + BIT(candFlag)); + } + if (fillCandidateMl) { + rowCandidateMl( + mlScore); + } + if (fillCandidateMlD0) { + rowCandidateMlD0( + mlScoresCharm); + } + if (fillCandidateId) { + rowCandidateId( + candidate.collisionId(), + prongCharm.prong0Id(), + prongCharm.prong1Id(), + candidate.prong1Id()); + } + if (fillCandidateMc) { + rowCandidateMc( + flagMc, + origin); + } + } + + template + void processCandidates(CollType const& collisions, + Partition& candidates, + CandCharmType const&, + TracksWPid const&, + aod::BCs const&) + { + // Fill collision properties + if constexpr (isMc) { + if (confDerData.fillMcRCollId) { + rowsCommon.matchedCollisions.clear(); + } + } + auto sizeTableColl = collisions.size(); + rowsCommon.reserveTablesColl(sizeTableColl); + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candidatesThisColl = candidates->sliceByCached(aod::hf_cand::collisionId, thisCollId, cache); // FIXME + auto sizeTableCand = candidatesThisColl.size(); + LOGF(debug, "Rec. collision %d has %d candidates", thisCollId, sizeTableCand); + // Skip collisions without HF candidates (and without HF particles in matched MC collisions if saving indices of reconstructed collisions matched to MC collisions) + bool mcCollisionHasMcParticles{false}; + if constexpr (isMc) { + mcCollisionHasMcParticles = confDerData.fillMcRCollId && collision.has_mcCollision() && rowsCommon.hasMcParticles[collision.mcCollisionId()]; + LOGF(debug, "Rec. collision %d has MC collision %d with MC particles? %s", thisCollId, collision.mcCollisionId(), mcCollisionHasMcParticles ? "yes" : "no"); + } + if (sizeTableCand == 0 && (!confDerData.fillMcRCollId || !mcCollisionHasMcParticles)) { + LOGF(debug, "Skipping rec. collision %d", thisCollId); + continue; + } + LOGF(debug, "Filling rec. collision %d at derived index %d", thisCollId, rowsCommon.rowCollBase.lastIndex() + 1); + rowsCommon.fillTablesCollision(collision); + + // Fill candidate properties + rowsCommon.reserveTablesCandidates(sizeTableCand); + reserveTable(rowCandidatePar, fillCandidatePar, sizeTableCand); + reserveTable(rowCandidateParD0, fillCandidateParD0, sizeTableCand); + reserveTable(rowCandidateParE, fillCandidateParE, sizeTableCand); + reserveTable(rowCandidateSel, fillCandidateSel, sizeTableCand); + reserveTable(rowCandidateMl, fillCandidateMl, sizeTableCand); + reserveTable(rowCandidateMlD0, fillCandidateMlD0, sizeTableCand); + reserveTable(rowCandidateId, fillCandidateId, sizeTableCand); + if constexpr (isMc) { + reserveTable(rowCandidateMc, fillCandidateMc, sizeTableCand); + } + int8_t flagMcRec = 0, origin = 0; + for (const auto& candidate : candidatesThisColl) { + if constexpr (isMl) { + if (!TESTBIT(candidate.isSelBplusToD0Pi(), aod::SelectionStep::RecoMl)) { + continue; + } + } + if constexpr (isMc) { + flagMcRec = candidate.flagMcMatchRec(); + origin = candidate.originMcRec(); + if constexpr (onlyBkg) { + if (TESTBIT(std::abs(flagMcRec), aod::hf_cand_bplus::DecayType::BplusToD0Pi)) { + continue; + } + if (downSampleBkgFactor < 1.) { + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + } + } + if constexpr (onlySig) { + if (!TESTBIT(std::abs(flagMcRec), aod::hf_cand_bplus::DecayType::BplusToD0Pi)) { + continue; + } + } + } + auto prongCharm = candidate.template prong0_as(); + auto prongBachelor = candidate.template prong1_as(); + double ct = hfHelper.ctBplus(candidate); + double y = hfHelper.yBplus(candidate); + float massBplusToD0Pi = hfHelper.invMassBplusToD0Pi(candidate); + float mlScoreBplusToD0Pi{-1.f}; + std::vector mlScoresD0; + bool isD0 = prongBachelor.sign() < 0; + if (isD0) { // is D0 + std::copy(prongCharm.mlProbD0().begin(), prongCharm.mlProbD0().end(), std::back_inserter(mlScoresD0)); + } else { // is D0bar + std::copy(prongCharm.mlProbD0bar().begin(), prongCharm.mlProbD0bar().end(), std::back_inserter(mlScoresD0)); + } + if constexpr (isMl) { + mlScoreBplusToD0Pi = candidate.mlProbBplusToD0Pi(); + } + // flag = 0 for D0 pi-, flag = 1 for D0bar pi+ + fillTablesCandidate(candidate, prongCharm, prongBachelor, isD0 ? 0 : 1, massBplusToD0Pi, ct, y, flagMcRec, origin, mlScoreBplusToD0Pi, mlScoresD0); + } + } + } + + void processData(CollisionsWCentMult const& collisions, + SelectedCandidates const&, + THfCandDaughtersMl const& candidatesDaughters, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + processCandidates(collisions, candidatesAll, candidatesDaughters, tracks, bcs); + } + PROCESS_SWITCH(HfDerivedDataCreatorBplusToD0Pi, processData, "Process data", true); + + void processMcSig(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMc const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + THfCandDaughtersMl const& candidatesDaughters, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcSig, candidatesDaughters, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorBplusToD0Pi, processMcSig, "Process MC only for signals", false); + + void processMcBkg(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMc const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + THfCandDaughtersMl const& candidatesDaughters, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcBkg, candidatesDaughters, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorBplusToD0Pi, processMcBkg, "Process MC only for background", false); + + void processMcAll(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMc const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + THfCandDaughtersMl const& candidatesDaughters, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcAll, candidatesDaughters, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorBplusToD0Pi, processMcAll, "Process MC", false); + + // ML versions + + void processDataMl(CollisionsWCentMult const& collisions, + SelectedCandidatesMl const&, + THfCandDaughtersMl const& candidatesDaughters, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + processCandidates(collisions, candidatesMlAll, candidatesDaughters, tracks, bcs); + } + PROCESS_SWITCH(HfDerivedDataCreatorBplusToD0Pi, processDataMl, "Process data with ML", false); + + void processMcMlSig(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMcMl const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + THfCandDaughtersMl const& candidatesDaughters, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcMlSig, candidatesDaughters, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorBplusToD0Pi, processMcMlSig, "Process MC with ML only for signals", false); + + void processMcMlBkg(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMcMl const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + THfCandDaughtersMl const& candidatesDaughters, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcMlBkg, candidatesDaughters, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorBplusToD0Pi, processMcMlBkg, "Process MC with ML only for background", false); + + void processMcMlAll(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMcMl const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + THfCandDaughtersMl const& candidatesDaughters, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcMlAll, candidatesDaughters, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorBplusToD0Pi, processMcMlAll, "Process MC with ML", false); + + void processMcGenOnly(TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles) + { + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorBplusToD0Pi, processMcGenOnly, "Process MC gen. only", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/derivedDataCreatorD0ToKPi.cxx b/PWGHF/TableProducer/derivedDataCreatorD0ToKPi.cxx index 6860e29f3f3..8ddc3d4464f 100644 --- a/PWGHF/TableProducer/derivedDataCreatorD0ToKPi.cxx +++ b/PWGHF/TableProducer/derivedDataCreatorD0ToKPi.cxx @@ -15,6 +15,10 @@ /// /// \author Vít Kučera , Inha University +#include +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -23,59 +27,70 @@ #include "Common/DataModel/Centrality.h" #include "Common/DataModel/Multiplicity.h" +#include "PWGLF/DataModel/mcCentrality.h" + #include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/DataModel/DerivedTables.h" +#include "PWGHF/Utils/utilsDerivedData.h" +#include "PWGHF/Utils/utilsPid.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::aod::pid_tpc_tof_utils; +using namespace o2::analysis::hf_derived; /// Writes the full information in an output TTree struct HfDerivedDataCreatorD0ToKPi { - Produces rowCandidateBase; + HfProducesDerivedData< + o2::aod::HfD0Bases, + o2::aod::HfD0CollBases, + o2::aod::HfD0CollIds, + o2::aod::HfD0McCollBases, + o2::aod::HfD0McCollIds, + o2::aod::HfD0McRCollIds, + o2::aod::HfD0PBases, + o2::aod::HfD0PIds> + rowsCommon; + // Candidates Produces rowCandidatePar; Produces rowCandidateParE; Produces rowCandidateSel; Produces rowCandidateMl; Produces rowCandidateId; Produces rowCandidateMc; - Produces rowCollBase; - Produces rowCollId; - Produces rowParticleBase; - Produces rowParticleId; // Switches for filling tables - Configurable fillCandidateBase{"fillCandidateBase", true, "Fill candidate base properties"}; + HfConfigurableDerivedData confDerData; Configurable fillCandidatePar{"fillCandidatePar", true, "Fill candidate parameters"}; Configurable fillCandidateParE{"fillCandidateParE", true, "Fill candidate extended parameters"}; Configurable fillCandidateSel{"fillCandidateSel", true, "Fill candidate selection flags"}; Configurable fillCandidateMl{"fillCandidateMl", true, "Fill candidate selection ML scores"}; - Configurable fillCandidateId{"fillCandidateId", true, "Fill candidate indices"}; + Configurable fillCandidateId{"fillCandidateId", true, "Fill original indices from the candidate table"}; Configurable fillCandidateMc{"fillCandidateMc", true, "Fill candidate MC info"}; - Configurable fillCollBase{"fillCollBase", true, "Fill collision base properties"}; - Configurable fillCollId{"fillCollId", true, "Fill collision indices"}; - Configurable fillParticleBase{"fillParticleBase", true, "Fill particle properties"}; - Configurable fillParticleId{"fillParticleId", true, "Fill particle indices"}; // Parameters for production of training samples Configurable downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of background candidates to keep for ML trainings"}; Configurable ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"}; HfHelper hfHelper; SliceCache cache; + static constexpr double mass{o2::constants::physics::MassD0}; using CollisionsWCentMult = soa::Join; - using TracksWPid = soa::Join; - using SelectedCandidates = soa::Filtered>; - using SelectedCandidatesKf = soa::Filtered>; - using SelectedCandidatesMc = soa::Filtered>; - using SelectedCandidatesMcKf = soa::Filtered>; - using SelectedCandidatesMl = soa::Filtered>; - using SelectedCandidatesKfMl = soa::Filtered>; - using SelectedCandidatesMcMl = soa::Filtered>; - using SelectedCandidatesMcKfMl = soa::Filtered>; + using CollisionsWMcCentMult = soa::Join; + // using TracksWPid = soa::Join; + using SelectedCandidates = soa::Filtered>; + using SelectedCandidatesKf = soa::Filtered>; + using SelectedCandidatesMc = soa::Filtered>; + using SelectedCandidatesMcKf = soa::Filtered>; + using SelectedCandidatesMl = soa::Filtered>; + using SelectedCandidatesKfMl = soa::Filtered>; + using SelectedCandidatesMcMl = soa::Filtered>; + using SelectedCandidatesMcKfMl = soa::Filtered>; using MatchedGenCandidatesMc = soa::Filtered>; + using TypeMcCollisions = soa::Join; Filter filterSelectCandidates = aod::hf_sel_candidate_d0::isSelD0 >= 1 || aod::hf_sel_candidate_d0::isSelD0bar >= 1; Filter filterMcGenMatching = nabs(aod::hf_cand_2prong::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); @@ -88,6 +103,7 @@ struct HfDerivedDataCreatorD0ToKPi { Preslice candidatesKfMlPerCollision = aod::hf_cand::collisionId; Preslice candidatesMcMlPerCollision = aod::hf_cand::collisionId; Preslice candidatesMcKfMlPerCollision = aod::hf_cand::collisionId; + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; // trivial partitions for all candidates to allow "->sliceByCached" inside processCandidates Partition candidatesAll = aod::hf_sel_candidate_d0::isSelD0 >= 0; @@ -110,57 +126,32 @@ struct HfDerivedDataCreatorD0ToKPi { void init(InitContext const&) { - std::array doprocess{doprocessDataWithDCAFitterN, doprocessDataWithKFParticle, doprocessMcWithDCAFitterSig, doprocessMcWithDCAFitterBkg, doprocessMcWithDCAFitterAll, doprocessMcWithKFParticleSig, doprocessMcWithKFParticleBkg, doprocessMcWithKFParticleAll, - doprocessDataWithDCAFitterNMl, doprocessDataWithKFParticleMl, doprocessMcWithDCAFitterMlSig, doprocessMcWithDCAFitterMlBkg, doprocessMcWithDCAFitterMlAll, doprocessMcWithKFParticleMlSig, doprocessMcWithKFParticleMlBkg, doprocessMcWithKFParticleMlAll}; + std::array doprocess{doprocessDataWithDCAFitterN, doprocessDataWithKFParticle, doprocessMcWithDCAFitterSig, doprocessMcWithDCAFitterBkg, doprocessMcWithDCAFitterAll, doprocessMcWithKFParticleSig, doprocessMcWithKFParticleBkg, doprocessMcWithKFParticleAll, + doprocessDataWithDCAFitterNMl, doprocessDataWithKFParticleMl, doprocessMcWithDCAFitterMlSig, doprocessMcWithDCAFitterMlBkg, doprocessMcWithDCAFitterMlAll, doprocessMcWithKFParticleMlSig, doprocessMcWithKFParticleMlBkg, doprocessMcWithKFParticleMlAll, doprocessMcGenOnly}; if (std::accumulate(doprocess.begin(), doprocess.end(), 0) != 1) { LOGP(fatal, "Only one process function can be enabled at a time."); } + rowsCommon.init(confDerData); } template - void reserveTable(T& table, const Configurable& enabled, const uint64_t size) - { - if (enabled.value) { - table.reserve(size); - } - }; - - template - void fillTablesCollision(const T& collision, int /*isEventReject*/, int /*runNumber*/) - { - if (fillCollBase) { - rowCollBase( - collision.posX(), - collision.posY(), - collision.posZ(), - collision.numContrib(), - collision.centFT0A(), - collision.centFT0C(), - collision.centFT0M(), - collision.centFV0A(), - collision.multZeqNTracksPV()); - // isEventReject, - // runNumber); - } - if (fillCollId) { - rowCollId( - collision.globalIndex()); - } - } - - template - auto fillTablesCandidate(const T& candidate, const U& prong0, const U& prong1, int candFlag, double invMass, double cosThetaStar, double topoChi2, - double ct, int8_t flagMc, int8_t origin, const std::vector& mlScores) + void fillTablesCandidate(const T& candidate, int candFlag, double invMass, double cosThetaStar, double topoChi2, + double ct, double y, int8_t flagMc, int8_t origin, const std::vector& mlScores) { - if (fillCandidateBase) { - rowCandidateBase( - rowCollBase.lastIndex(), - candidate.pt(), - candidate.eta(), - candidate.phi(), - invMass); - } + rowsCommon.fillTablesCandidate(candidate, invMass, y); if (fillCandidatePar) { + std::array, 2>, 2> sigmas{}; // PID nSigma [Expected][Hypothesis][TPC/TOF/TPC+TOF] + if (candFlag == 0) { + GET_N_SIGMA_PRONG(sigmas[HfProngSpecies::Pion][HfProngSpecies::Pion], candidate, 0, Pi) + GET_N_SIGMA_PRONG(sigmas[HfProngSpecies::Pion][HfProngSpecies::Kaon], candidate, 0, Ka) + GET_N_SIGMA_PRONG(sigmas[HfProngSpecies::Kaon][HfProngSpecies::Pion], candidate, 1, Pi) + GET_N_SIGMA_PRONG(sigmas[HfProngSpecies::Kaon][HfProngSpecies::Kaon], candidate, 1, Ka) + } else if (candFlag == 1) { + GET_N_SIGMA_PRONG(sigmas[HfProngSpecies::Pion][HfProngSpecies::Pion], candidate, 1, Pi) + GET_N_SIGMA_PRONG(sigmas[HfProngSpecies::Pion][HfProngSpecies::Kaon], candidate, 1, Ka) + GET_N_SIGMA_PRONG(sigmas[HfProngSpecies::Kaon][HfProngSpecies::Pion], candidate, 0, Pi) + GET_N_SIGMA_PRONG(sigmas[HfProngSpecies::Kaon][HfProngSpecies::Kaon], candidate, 0, Ka) + } rowCandidatePar( candidate.chi2PCA(), candidate.cpa(), @@ -175,26 +166,23 @@ struct HfDerivedDataCreatorD0ToKPi { candidate.impactParameter1(), candidate.impactParameterNormalised0(), candidate.impactParameterNormalised1(), - prong0.tpcNSigmaPi(), - prong0.tpcNSigmaKa(), - prong0.tofNSigmaPi(), - prong0.tofNSigmaKa(), - prong0.tpcTofNSigmaPi(), - prong0.tpcTofNSigmaKa(), - prong1.tpcNSigmaPi(), - prong1.tpcNSigmaKa(), - prong1.tofNSigmaPi(), - prong1.tofNSigmaKa(), - prong1.tpcTofNSigmaPi(), - prong1.tpcTofNSigmaKa(), + sigmas[HfProngSpecies::Pion][HfProngSpecies::Pion][0], + sigmas[HfProngSpecies::Pion][HfProngSpecies::Pion][1], + sigmas[HfProngSpecies::Pion][HfProngSpecies::Pion][2], + sigmas[HfProngSpecies::Pion][HfProngSpecies::Kaon][0], + sigmas[HfProngSpecies::Pion][HfProngSpecies::Kaon][1], + sigmas[HfProngSpecies::Pion][HfProngSpecies::Kaon][2], + sigmas[HfProngSpecies::Kaon][HfProngSpecies::Pion][0], + sigmas[HfProngSpecies::Kaon][HfProngSpecies::Pion][1], + sigmas[HfProngSpecies::Kaon][HfProngSpecies::Pion][2], + sigmas[HfProngSpecies::Kaon][HfProngSpecies::Kaon][0], + sigmas[HfProngSpecies::Kaon][HfProngSpecies::Kaon][1], + sigmas[HfProngSpecies::Kaon][HfProngSpecies::Kaon][2], candidate.maxNormalisedDeltaIP(), candidate.impactParameterProduct()); } if (fillCandidateParE) { rowCandidateParE( - candidate.posX(), - candidate.posY(), - candidate.posZ(), candidate.xSecondaryVertex(), candidate.ySecondaryVertex(), candidate.zSecondaryVertex(), @@ -236,54 +224,49 @@ struct HfDerivedDataCreatorD0ToKPi { } } - template - void fillTablesParticle(const T& particle, U /*mass*/) - { - if (fillParticleBase) { - rowParticleBase( - particle.pt(), - particle.eta(), - particle.phi(), - particle.flagMcMatchGen(), - particle.originMcGen()); - } - if (fillParticleId) { - rowParticleId( - particle.mcCollisionId(), - particle.globalIndex()); - } - } - template void processCandidates(CollType const& collisions, Partition& candidates, - TracksWPid const&, + aod::Tracks const&, aod::BCs const&) { // Fill collision properties + if constexpr (isMc) { + if (confDerData.fillMcRCollId) { + rowsCommon.matchedCollisions.clear(); + } + } auto sizeTableColl = collisions.size(); - reserveTable(rowCollBase, fillCollBase, sizeTableColl); - reserveTable(rowCollId, fillCollId, sizeTableColl); + rowsCommon.reserveTablesColl(sizeTableColl); for (const auto& collision : collisions) { auto thisCollId = collision.globalIndex(); auto candidatesThisColl = candidates->sliceByCached(aod::hf_cand::collisionId, thisCollId, cache); // FIXME auto sizeTableCand = candidatesThisColl.size(); - // skip collisions without HF candidates - if (sizeTableCand == 0) { + LOGF(debug, "Rec. collision %d has %d candidates", thisCollId, sizeTableCand); + // Skip collisions without HF candidates (and without HF particles in matched MC collisions if saving indices of reconstructed collisions matched to MC collisions) + bool mcCollisionHasMcParticles{false}; + if constexpr (isMc) { + mcCollisionHasMcParticles = confDerData.fillMcRCollId && collision.has_mcCollision() && rowsCommon.hasMcParticles[collision.mcCollisionId()]; + LOGF(debug, "Rec. collision %d has MC collision %d with MC particles? %s", thisCollId, collision.mcCollisionId(), mcCollisionHasMcParticles ? "yes" : "no"); + } + if (sizeTableCand == 0 && (!confDerData.fillMcRCollId || !mcCollisionHasMcParticles)) { + LOGF(debug, "Skipping rec. collision %d", thisCollId); continue; } - fillTablesCollision(collision, 0, collision.bc().runNumber()); + LOGF(debug, "Filling rec. collision %d at derived index %d", thisCollId, rowsCommon.rowCollBase.lastIndex() + 1); + rowsCommon.fillTablesCollision(collision); // Fill candidate properties - reserveTable(rowCandidateBase, fillCandidateBase, sizeTableCand); + rowsCommon.reserveTablesCandidates(sizeTableCand); reserveTable(rowCandidatePar, fillCandidatePar, sizeTableCand); reserveTable(rowCandidateParE, fillCandidateParE, sizeTableCand); reserveTable(rowCandidateSel, fillCandidateSel, sizeTableCand); + reserveTable(rowCandidateMl, fillCandidateMl, sizeTableCand); reserveTable(rowCandidateId, fillCandidateId, sizeTableCand); if constexpr (isMc) { reserveTable(rowCandidateMc, fillCandidateMc, sizeTableCand); } - int8_t flagMcRec, origin; + int8_t flagMcRec = 0, origin = 0; for (const auto& candidate : candidatesThisColl) { if constexpr (isMc) { flagMcRec = candidate.flagMcMatchRec(); @@ -293,7 +276,7 @@ struct HfDerivedDataCreatorD0ToKPi { continue; } if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } @@ -305,12 +288,16 @@ struct HfDerivedDataCreatorD0ToKPi { } } } else { - flagMcRec = 0; - origin = 0; + if (downSampleBkgFactor < 1.) { + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + } } - auto prong0 = candidate.template prong0_as(); - auto prong1 = candidate.template prong1_as(); - double ctD = hfHelper.ctD0(candidate); + + double ct = hfHelper.ctD0(candidate); + double y = hfHelper.yD0(candidate); float massD0, massD0bar; float topolChi2PerNdf = -999.; if constexpr (reconstructionType == aod::hf_cand::VertexerType::KfParticle) { @@ -327,33 +314,18 @@ struct HfDerivedDataCreatorD0ToKPi { std::copy(candidate.mlProbD0bar().begin(), candidate.mlProbD0bar().end(), std::back_inserter(mlScoresD0bar)); } if (candidate.isSelD0()) { - fillTablesCandidate(candidate, prong0, prong1, 0, massD0, hfHelper.cosThetaStarD0(candidate), topolChi2PerNdf, ctD, flagMcRec, origin, mlScoresD0); + fillTablesCandidate(candidate, 0, massD0, hfHelper.cosThetaStarD0(candidate), topolChi2PerNdf, ct, y, flagMcRec, origin, mlScoresD0); } if (candidate.isSelD0bar()) { - fillTablesCandidate(candidate, prong0, prong1, 1, massD0bar, hfHelper.cosThetaStarD0bar(candidate), topolChi2PerNdf, ctD, flagMcRec, origin, mlScoresD0bar); + fillTablesCandidate(candidate, 1, massD0bar, hfHelper.cosThetaStarD0bar(candidate), topolChi2PerNdf, ct, y, flagMcRec, origin, mlScoresD0bar); } } } } - template - void processMcParticles(ParticleType const& mcParticles) - { - // Fill MC particle properties - auto sizeTablePart = mcParticles.size(); - reserveTable(rowParticleBase, fillParticleBase, sizeTablePart); - reserveTable(rowParticleId, fillParticleId, sizeTablePart); - for (const auto& particle : mcParticles) { - if (!TESTBIT(std::abs(particle.flagMcMatchGen()), aod::hf_cand_2prong::DecayType::D0ToPiK)) { - continue; - } - fillTablesParticle(particle, o2::constants::physics::MassD0); - } - } - void processDataWithDCAFitterN(CollisionsWCentMult const& collisions, SelectedCandidates const&, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { processCandidates(collisions, candidatesAll, tracks, bcs); @@ -362,76 +334,88 @@ struct HfDerivedDataCreatorD0ToKPi { void processDataWithKFParticle(CollisionsWCentMult const& collisions, SelectedCandidatesKf const&, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { processCandidates(collisions, candidatesKfAll, tracks, bcs); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processDataWithKFParticle, "Process data with KFParticle", false); - void processMcWithDCAFitterSig(CollisionsWCentMult const& collisions, + void processMcWithDCAFitterSig(CollisionsWMcCentMult const& collisions, SelectedCandidatesMc const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcSig, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithDCAFitterSig, "Process MC with DCAFitterN only for signals", false); - void processMcWithDCAFitterBkg(CollisionsWCentMult const& collisions, + void processMcWithDCAFitterBkg(CollisionsWMcCentMult const& collisions, SelectedCandidatesMc const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcBkg, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithDCAFitterBkg, "Process MC with DCAFitterN only for background", false); - void processMcWithDCAFitterAll(CollisionsWCentMult const& collisions, + void processMcWithDCAFitterAll(CollisionsWMcCentMult const& collisions, SelectedCandidatesMc const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcAll, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithDCAFitterAll, "Process MC with DCAFitterN", false); - void processMcWithKFParticleSig(CollisionsWCentMult const& collisions, + void processMcWithKFParticleSig(CollisionsWMcCentMult const& collisions, SelectedCandidatesMcKf const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcKfSig, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithKFParticleSig, "Process MC with KFParticle only for signals", false); - void processMcWithKFParticleBkg(CollisionsWCentMult const& collisions, + void processMcWithKFParticleBkg(CollisionsWMcCentMult const& collisions, SelectedCandidatesMcKf const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcKfBkg, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithKFParticleBkg, "Process MC with KFParticle only for background", false); - void processMcWithKFParticleAll(CollisionsWCentMult const& collisions, + void processMcWithKFParticleAll(CollisionsWMcCentMult const& collisions, SelectedCandidatesMcKf const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcKfAll, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithKFParticleAll, "Process MC with KFParticle", false); @@ -439,7 +423,7 @@ struct HfDerivedDataCreatorD0ToKPi { void processDataWithDCAFitterNMl(CollisionsWCentMult const& collisions, SelectedCandidatesMl const&, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { processCandidates(collisions, candidatesMlAll, tracks, bcs); @@ -448,78 +432,97 @@ struct HfDerivedDataCreatorD0ToKPi { void processDataWithKFParticleMl(CollisionsWCentMult const& collisions, SelectedCandidatesKfMl const&, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { processCandidates(collisions, candidatesKfMlAll, tracks, bcs); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processDataWithKFParticleMl, "Process data with KFParticle and ML", false); - void processMcWithDCAFitterMlSig(CollisionsWCentMult const& collisions, + void processMcWithDCAFitterMlSig(CollisionsWMcCentMult const& collisions, SelectedCandidatesMcMl const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcMlSig, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithDCAFitterMlSig, "Process MC with DCAFitterN and ML only for signals", false); - void processMcWithDCAFitterMlBkg(CollisionsWCentMult const& collisions, + void processMcWithDCAFitterMlBkg(CollisionsWMcCentMult const& collisions, SelectedCandidatesMcMl const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcMlBkg, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithDCAFitterMlBkg, "Process MC with DCAFitterN and ML only for background", false); - void processMcWithDCAFitterMlAll(CollisionsWCentMult const& collisions, + void processMcWithDCAFitterMlAll(CollisionsWMcCentMult const& collisions, SelectedCandidatesMcMl const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcMlAll, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithDCAFitterMlAll, "Process MC with DCAFitterN and ML", false); - void processMcWithKFParticleMlSig(CollisionsWCentMult const& collisions, + void processMcWithKFParticleMlSig(CollisionsWMcCentMult const& collisions, SelectedCandidatesMcKfMl const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcKfMlSig, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithKFParticleMlSig, "Process MC with KFParticle and ML only for signals", false); - void processMcWithKFParticleMlBkg(CollisionsWCentMult const& collisions, + void processMcWithKFParticleMlBkg(CollisionsWMcCentMult const& collisions, SelectedCandidatesMcKfMl const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcKfMlBkg, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithKFParticleMlBkg, "Process MC with KFParticle and ML only for background", false); - void processMcWithKFParticleMlAll(CollisionsWCentMult const& collisions, + void processMcWithKFParticleMlAll(CollisionsWMcCentMult const& collisions, SelectedCandidatesMcKfMl const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcKfMlAll, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithKFParticleMlAll, "Process MC with KFParticle and ML", false); + + void processMcGenOnly(TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles) + { + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcGenOnly, "Process MC gen. only", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/TableProducer/derivedDataCreatorDplusToPiKPi.cxx b/PWGHF/TableProducer/derivedDataCreatorDplusToPiKPi.cxx new file mode 100644 index 00000000000..cf4f828b498 --- /dev/null +++ b/PWGHF/TableProducer/derivedDataCreatorDplusToPiKPi.cxx @@ -0,0 +1,396 @@ +// 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 derivedDataCreatorDplusToPiKPi.cxx +/// \brief Producer of derived tables of Dplus candidates, collisions and MC particles +/// \note Based on derivedDataCreatorLcToPKPi.cxx +/// +/// \author Vít Kučera , Inha University + +#include +#include +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" + +#include "PWGLF/DataModel/mcCentrality.h" + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGHF/Utils/utilsDerivedData.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::hf_derived; + +/// Writes the full information in an output TTree +struct HfDerivedDataCreatorDplusToPiKPi { + HfProducesDerivedData< + o2::aod::HfDplusBases, + o2::aod::HfDplusCollBases, + o2::aod::HfDplusCollIds, + o2::aod::HfDplusMcCollBases, + o2::aod::HfDplusMcCollIds, + o2::aod::HfDplusMcRCollIds, + o2::aod::HfDplusPBases, + o2::aod::HfDplusPIds> + rowsCommon; + // Candidates + Produces rowCandidatePar; + Produces rowCandidateParE; + Produces rowCandidateSel; + Produces rowCandidateMl; + Produces rowCandidateId; + Produces rowCandidateMc; + + // Switches for filling tables + HfConfigurableDerivedData confDerData; + Configurable fillCandidatePar{"fillCandidatePar", true, "Fill candidate parameters"}; + Configurable fillCandidateParE{"fillCandidateParE", true, "Fill candidate extended parameters"}; + Configurable fillCandidateSel{"fillCandidateSel", true, "Fill candidate selection flags"}; + Configurable fillCandidateMl{"fillCandidateMl", true, "Fill candidate selection ML scores"}; + Configurable fillCandidateId{"fillCandidateId", true, "Fill original indices from the candidate table"}; + Configurable fillCandidateMc{"fillCandidateMc", true, "Fill candidate MC info"}; + // Parameters for production of training samples + Configurable downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of background candidates to keep for ML trainings"}; + Configurable ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"}; + + HfHelper hfHelper; + SliceCache cache; + static constexpr double mass{o2::constants::physics::MassDPlus}; + + using CollisionsWCentMult = soa::Join; + using CollisionsWMcCentMult = soa::Join; + using TracksWPid = soa::Join; + using SelectedCandidates = soa::Filtered>; + using SelectedCandidatesMc = soa::Filtered>; + using SelectedCandidatesMl = soa::Filtered>; + using SelectedCandidatesMcMl = soa::Filtered>; + using MatchedGenCandidatesMc = soa::Filtered>; + using TypeMcCollisions = soa::Join; + + Filter filterSelectCandidates = (aod::hf_sel_candidate_dplus::isSelDplusToPiKPi & static_cast(BIT(aod::SelectionStep::RecoMl - 1))) != 0; // select candidates which passed all cuts at least up to RecoMl - 1 + Filter filterMcGenMatching = nabs(aod::hf_cand_3prong::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi)); + + Preslice candidatesPerCollision = aod::hf_cand::collisionId; + Preslice candidatesMcPerCollision = aod::hf_cand::collisionId; + Preslice candidatesMlPerCollision = aod::hf_cand::collisionId; + Preslice candidatesMcMlPerCollision = aod::hf_cand::collisionId; + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + + // trivial partitions for all candidates to allow "->sliceByCached" inside processCandidates + Partition candidatesAll = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= 0; + Partition candidatesMcAll = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= 0; + Partition candidatesMlAll = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= 0; + Partition candidatesMcMlAll = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= 0; + // partitions for signal and background + Partition candidatesMcSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi)); + Partition candidatesMcBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi)); + Partition candidatesMcMlSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi)); + Partition candidatesMcMlBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi)); + + void init(InitContext const&) + { + std::array doprocess{doprocessData, doprocessMcSig, doprocessMcBkg, doprocessMcAll, doprocessDataMl, doprocessMcMlSig, doprocessMcMlBkg, doprocessMcMlAll, doprocessMcGenOnly}; + if (std::accumulate(doprocess.begin(), doprocess.end(), 0) != 1) { + LOGP(fatal, "Only one process function can be enabled at a time."); + } + rowsCommon.init(confDerData); + } + + template + void fillTablesCandidate(const T& candidate, const U& prong0, const U& prong1, const U& prong2, int candFlag, double invMass, + double ct, double y, int8_t flagMc, int8_t origin, int8_t swapping, int8_t flagDecayChan, const std::vector& mlScores) + { + rowsCommon.fillTablesCandidate(candidate, invMass, y); + if (fillCandidatePar) { + rowCandidatePar( + candidate.chi2PCA(), + candidate.nProngsContributorsPV(), + candidate.cpa(), + candidate.cpaXY(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.decayLengthNormalised(), + candidate.decayLengthXYNormalised(), + candidate.ptProng0(), + candidate.ptProng1(), + candidate.ptProng2(), + candidate.impactParameter0(), + candidate.impactParameter1(), + candidate.impactParameter2(), + candidate.impactParameterNormalised0(), + candidate.impactParameterNormalised1(), + candidate.impactParameterNormalised2(), + prong0.tpcNSigmaPi(), + prong0.tofNSigmaPi(), + prong0.tpcTofNSigmaPi(), + prong1.tpcNSigmaKa(), + prong1.tofNSigmaKa(), + prong1.tpcTofNSigmaKa(), + prong2.tpcNSigmaPi(), + prong2.tofNSigmaPi(), + prong2.tpcTofNSigmaPi()); + } + if (fillCandidateParE) { + rowCandidateParE( + candidate.xSecondaryVertex(), + candidate.ySecondaryVertex(), + candidate.zSecondaryVertex(), + candidate.errorDecayLength(), + candidate.errorDecayLengthXY(), + candidate.rSecondaryVertex(), + RecoDecay::p(candidate.pxProng0(), candidate.pyProng0(), candidate.pzProng0()), + RecoDecay::p(candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1()), + RecoDecay::p(candidate.pxProng2(), candidate.pyProng2(), candidate.pzProng2()), + candidate.pxProng0(), + candidate.pyProng0(), + candidate.pzProng0(), + candidate.pxProng1(), + candidate.pyProng1(), + candidate.pzProng1(), + candidate.pxProng2(), + candidate.pyProng2(), + candidate.pzProng2(), + candidate.errorImpactParameter0(), + candidate.errorImpactParameter1(), + candidate.errorImpactParameter2(), + ct); + } + if (fillCandidateSel) { + rowCandidateSel( + BIT(candFlag)); + } + if (fillCandidateMl) { + rowCandidateMl( + mlScores); + } + if (fillCandidateId) { + rowCandidateId( + candidate.collisionId(), + candidate.prong0Id(), + candidate.prong1Id(), + candidate.prong2Id()); + } + if (fillCandidateMc) { + rowCandidateMc( + flagMc, + origin, + swapping, + flagDecayChan); + } + } + + template + void processCandidates(CollType const& collisions, + Partition& candidates, + TracksWPid const&, + aod::BCs const&) + { + // Fill collision properties + if constexpr (isMc) { + if (confDerData.fillMcRCollId) { + rowsCommon.matchedCollisions.clear(); + } + } + auto sizeTableColl = collisions.size(); + rowsCommon.reserveTablesColl(sizeTableColl); + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candidatesThisColl = candidates->sliceByCached(aod::hf_cand::collisionId, thisCollId, cache); // FIXME + auto sizeTableCand = candidatesThisColl.size(); + LOGF(debug, "Rec. collision %d has %d candidates", thisCollId, sizeTableCand); + // Skip collisions without HF candidates (and without HF particles in matched MC collisions if saving indices of reconstructed collisions matched to MC collisions) + bool mcCollisionHasMcParticles{false}; + if constexpr (isMc) { + mcCollisionHasMcParticles = confDerData.fillMcRCollId && collision.has_mcCollision() && rowsCommon.hasMcParticles[collision.mcCollisionId()]; + LOGF(debug, "Rec. collision %d has MC collision %d with MC particles? %s", thisCollId, collision.mcCollisionId(), mcCollisionHasMcParticles ? "yes" : "no"); + } + if (sizeTableCand == 0 && (!confDerData.fillMcRCollId || !mcCollisionHasMcParticles)) { + LOGF(debug, "Skipping rec. collision %d", thisCollId); + continue; + } + LOGF(debug, "Filling rec. collision %d at derived index %d", thisCollId, rowsCommon.rowCollBase.lastIndex() + 1); + rowsCommon.fillTablesCollision(collision); + + // Fill candidate properties + rowsCommon.reserveTablesCandidates(sizeTableCand); + reserveTable(rowCandidatePar, fillCandidatePar, sizeTableCand); + reserveTable(rowCandidateParE, fillCandidateParE, sizeTableCand); + reserveTable(rowCandidateSel, fillCandidateSel, sizeTableCand); + reserveTable(rowCandidateMl, fillCandidateMl, sizeTableCand); + reserveTable(rowCandidateId, fillCandidateId, sizeTableCand); + if constexpr (isMc) { + reserveTable(rowCandidateMc, fillCandidateMc, sizeTableCand); + } + int8_t flagMcRec = 0, origin = 0, swapping = 0, flagDecayChanRec = 0; + for (const auto& candidate : candidatesThisColl) { + if constexpr (isMl) { + if (!TESTBIT(candidate.isSelDplusToPiKPi(), aod::SelectionStep::RecoMl)) { + continue; + } + } + if constexpr (isMc) { + flagMcRec = candidate.flagMcMatchRec(); + origin = candidate.originMcRec(); + swapping = candidate.isCandidateSwapped(); + flagDecayChanRec = candidate.flagMcDecayChanRec(); + if constexpr (onlyBkg) { + if (TESTBIT(std::abs(flagMcRec), aod::hf_cand_3prong::DecayType::DplusToPiKPi)) { + continue; + } + if (downSampleBkgFactor < 1.) { + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + } + } + if constexpr (onlySig) { + if (!TESTBIT(std::abs(flagMcRec), aod::hf_cand_3prong::DecayType::DplusToPiKPi)) { + continue; + } + } + } + auto prong0 = candidate.template prong0_as(); + auto prong1 = candidate.template prong1_as(); + auto prong2 = candidate.template prong2_as(); + double ct = hfHelper.ctDplus(candidate); + double y = hfHelper.yDplus(candidate); + float massDplusToPiKPi = hfHelper.invMassDplusToPiKPi(candidate); + std::vector mlScoresDplusToPiKPi; + if constexpr (isMl) { + std::copy(candidate.mlProbDplusToPiKPi().begin(), candidate.mlProbDplusToPiKPi().end(), std::back_inserter(mlScoresDplusToPiKPi)); + } + fillTablesCandidate(candidate, prong0, prong1, prong2, 0, massDplusToPiKPi, ct, y, flagMcRec, origin, swapping, flagDecayChanRec, mlScoresDplusToPiKPi); + } + } + } + + void processData(CollisionsWCentMult const& collisions, + SelectedCandidates const&, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + processCandidates(collisions, candidatesAll, tracks, bcs); + } + PROCESS_SWITCH(HfDerivedDataCreatorDplusToPiKPi, processData, "Process data", true); + + void processMcSig(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMc const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcSig, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorDplusToPiKPi, processMcSig, "Process MC only for signals", false); + + void processMcBkg(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMc const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcBkg, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorDplusToPiKPi, processMcBkg, "Process MC only for background", false); + + void processMcAll(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMc const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcAll, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorDplusToPiKPi, processMcAll, "Process MC", false); + + // ML versions + + void processDataMl(CollisionsWCentMult const& collisions, + SelectedCandidatesMl const&, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + processCandidates(collisions, candidatesMlAll, tracks, bcs); + } + PROCESS_SWITCH(HfDerivedDataCreatorDplusToPiKPi, processDataMl, "Process data with ML", false); + + void processMcMlSig(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMcMl const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcMlSig, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorDplusToPiKPi, processMcMlSig, "Process MC with ML only for signals", false); + + void processMcMlBkg(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMcMl const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcMlBkg, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorDplusToPiKPi, processMcMlBkg, "Process MC with ML only for background", false); + + void processMcMlAll(CollisionsWMcCentMult const& collisions, + SelectedCandidatesMcMl const&, + TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); + processCandidates(collisions, candidatesMcMlAll, tracks, bcs); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorDplusToPiKPi, processMcMlAll, "Process MC with ML", false); + + void processMcGenOnly(TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles) + { + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorDplusToPiKPi, processMcGenOnly, "Process MC gen. only", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/derivedDataCreatorLcToPKPi.cxx b/PWGHF/TableProducer/derivedDataCreatorLcToPKPi.cxx index 04407ab930a..61d2398a0d7 100644 --- a/PWGHF/TableProducer/derivedDataCreatorLcToPKPi.cxx +++ b/PWGHF/TableProducer/derivedDataCreatorLcToPKPi.cxx @@ -15,6 +15,10 @@ /// /// \author Vít Kučera , Inha University +#include +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -23,55 +27,64 @@ #include "Common/DataModel/Centrality.h" #include "Common/DataModel/Multiplicity.h" +#include "PWGLF/DataModel/mcCentrality.h" + #include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/DataModel/DerivedTables.h" +#include "PWGHF/Utils/utilsDerivedData.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::analysis::hf_derived; /// Writes the full information in an output TTree struct HfDerivedDataCreatorLcToPKPi { - Produces rowCandidateBase; - Produces rowCandidatePar; - Produces rowCandidateParE; - Produces rowCandidateSel; - Produces rowCandidateMl; - Produces rowCandidateId; - Produces rowCandidateMc; - Produces rowCollBase; - Produces rowCollId; - Produces rowParticleBase; - Produces rowParticleId; + HfProducesDerivedData< + o2::aod::HfLcBases, + o2::aod::HfLcCollBases, + o2::aod::HfLcCollIds, + o2::aod::HfLcMcCollBases, + o2::aod::HfLcMcCollIds, + o2::aod::HfLcMcRCollIds, + o2::aod::HfLcPBases, + o2::aod::HfLcPIds> + rowsCommon; + // Candidates + Produces rowCandidatePar; + Produces rowCandidateParE; + Produces rowCandidateSel; + Produces rowCandidateMl; + Produces rowCandidateId; + Produces rowCandidateMc; // Switches for filling tables - Configurable fillCandidateBase{"fillCandidateBase", true, "Fill candidate base properties"}; + HfConfigurableDerivedData confDerData; Configurable fillCandidatePar{"fillCandidatePar", true, "Fill candidate parameters"}; Configurable fillCandidateParE{"fillCandidateParE", true, "Fill candidate extended parameters"}; Configurable fillCandidateSel{"fillCandidateSel", true, "Fill candidate selection flags"}; Configurable fillCandidateMl{"fillCandidateMl", true, "Fill candidate selection ML scores"}; - Configurable fillCandidateId{"fillCandidateId", true, "Fill candidate indices"}; + Configurable fillCandidateId{"fillCandidateId", true, "Fill original indices from the candidate table"}; Configurable fillCandidateMc{"fillCandidateMc", true, "Fill candidate MC info"}; - Configurable fillCollBase{"fillCollBase", true, "Fill collision base properties"}; - Configurable fillCollId{"fillCollId", true, "Fill collision indices"}; - Configurable fillParticleBase{"fillParticleBase", true, "Fill particle properties"}; - Configurable fillParticleId{"fillParticleId", true, "Fill particle indices"}; // Parameters for production of training samples Configurable downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of background candidates to keep for ML trainings"}; Configurable ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"}; HfHelper hfHelper; SliceCache cache; + static constexpr double mass{o2::constants::physics::MassLambdaCPlus}; using CollisionsWCentMult = soa::Join; + using CollisionsWMcCentMult = soa::Join; using TracksWPid = soa::Join; using SelectedCandidates = soa::Filtered>; using SelectedCandidatesMc = soa::Filtered>; using SelectedCandidatesMl = soa::Filtered>; using SelectedCandidatesMcMl = soa::Filtered>; using MatchedGenCandidatesMc = soa::Filtered>; + using TypeMcCollisions = soa::Join; Filter filterSelectCandidates = aod::hf_sel_candidate_lc::isSelLcToPKPi >= 1 || aod::hf_sel_candidate_lc::isSelLcToPiKP >= 1; Filter filterMcGenMatching = nabs(aod::hf_cand_3prong::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_3prong::DecayType::LcToPKPi)); @@ -80,6 +93,7 @@ struct HfDerivedDataCreatorLcToPKPi { Preslice candidatesMcPerCollision = aod::hf_cand::collisionId; Preslice candidatesMlPerCollision = aod::hf_cand::collisionId; Preslice candidatesMcMlPerCollision = aod::hf_cand::collisionId; + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; // trivial partitions for all candidates to allow "->sliceByCached" inside processCandidates Partition candidatesAll = aod::hf_sel_candidate_lc::isSelLcToPKPi >= 0; @@ -94,56 +108,18 @@ struct HfDerivedDataCreatorLcToPKPi { void init(InitContext const&) { - std::array doprocess{doprocessData, doprocessMcSig, doprocessMcBkg, doprocessMcAll, doprocessDataMl, doprocessMcMlSig, doprocessMcMlBkg, doprocessMcMlAll}; + std::array doprocess{doprocessData, doprocessMcSig, doprocessMcBkg, doprocessMcAll, doprocessDataMl, doprocessMcMlSig, doprocessMcMlBkg, doprocessMcMlAll, doprocessMcGenOnly}; if (std::accumulate(doprocess.begin(), doprocess.end(), 0) != 1) { LOGP(fatal, "Only one process function can be enabled at a time."); } - } - - template - void reserveTable(T& table, const Configurable& enabled, const uint64_t size) - { - if (enabled.value) { - table.reserve(size); - } - }; - - template - // void fillTablesCollision(const T& collision, int isEventReject, int runNumber) - void fillTablesCollision(const T& collision) - { - if (fillCollBase) { - rowCollBase( - collision.posX(), - collision.posY(), - collision.posZ(), - collision.numContrib(), - collision.centFT0A(), - collision.centFT0C(), - collision.centFT0M(), - collision.centFV0A(), - collision.multZeqNTracksPV()); - // isEventReject, - // runNumber); - } - if (fillCollId) { - rowCollId( - collision.globalIndex()); - } + rowsCommon.init(confDerData); } template - auto fillTablesCandidate(const T& candidate, const U& prong0, const U& prong1, const U& prong2, int candFlag, double invMass, - double ct, int8_t flagMc, int8_t origin, int8_t swapping, const std::vector& mlScores) + void fillTablesCandidate(const T& candidate, const U& prong0, const U& prong1, const U& prong2, int candFlag, double invMass, + double ct, double y, int8_t flagMc, int8_t origin, int8_t swapping, const std::vector& mlScores) { - if (fillCandidateBase) { - rowCandidateBase( - rowCollBase.lastIndex(), - candidate.pt(), - candidate.eta(), - candidate.phi(), - invMass); - } + rowsCommon.fillTablesCandidate(candidate, invMass, y); if (fillCandidatePar) { rowCandidatePar( candidate.chi2PCA(), @@ -181,9 +157,6 @@ struct HfDerivedDataCreatorLcToPKPi { } if (fillCandidateParE) { rowCandidateParE( - candidate.posX(), - candidate.posY(), - candidate.posZ(), candidate.xSecondaryVertex(), candidate.ySecondaryVertex(), candidate.zSecondaryVertex(), @@ -230,24 +203,6 @@ struct HfDerivedDataCreatorLcToPKPi { } } - template - void fillTablesParticle(const T& particle, U /*mass*/) - { - if (fillParticleBase) { - rowParticleBase( - particle.pt(), - particle.eta(), - particle.phi(), - particle.flagMcMatchGen(), - particle.originMcGen()); - } - if (fillParticleId) { - rowParticleId( - particle.mcCollisionId(), - particle.globalIndex()); - } - } - template void processCandidates(CollType const& collisions, Partition& candidates, @@ -255,25 +210,37 @@ struct HfDerivedDataCreatorLcToPKPi { aod::BCs const&) { // Fill collision properties + if constexpr (isMc) { + if (confDerData.fillMcRCollId) { + rowsCommon.matchedCollisions.clear(); + } + } auto sizeTableColl = collisions.size(); - reserveTable(rowCollBase, fillCollBase, sizeTableColl); - reserveTable(rowCollId, fillCollId, sizeTableColl); + rowsCommon.reserveTablesColl(sizeTableColl); for (const auto& collision : collisions) { auto thisCollId = collision.globalIndex(); auto candidatesThisColl = candidates->sliceByCached(aod::hf_cand::collisionId, thisCollId, cache); // FIXME auto sizeTableCand = candidatesThisColl.size(); - // skip collisions without HF candidates - if (sizeTableCand == 0) { + LOGF(debug, "Rec. collision %d has %d candidates", thisCollId, sizeTableCand); + // Skip collisions without HF candidates (and without HF particles in matched MC collisions if saving indices of reconstructed collisions matched to MC collisions) + bool mcCollisionHasMcParticles{false}; + if constexpr (isMc) { + mcCollisionHasMcParticles = confDerData.fillMcRCollId && collision.has_mcCollision() && rowsCommon.hasMcParticles[collision.mcCollisionId()]; + LOGF(debug, "Rec. collision %d has MC collision %d with MC particles? %s", thisCollId, collision.mcCollisionId(), mcCollisionHasMcParticles ? "yes" : "no"); + } + if (sizeTableCand == 0 && (!confDerData.fillMcRCollId || !mcCollisionHasMcParticles)) { + LOGF(debug, "Skipping rec. collision %d", thisCollId); continue; } - // fillTablesCollision(collision, 0, collision.bc().runNumber()); - fillTablesCollision(collision); + LOGF(debug, "Filling rec. collision %d at derived index %d", thisCollId, rowsCommon.rowCollBase.lastIndex() + 1); + rowsCommon.fillTablesCollision(collision); // Fill candidate properties - reserveTable(rowCandidateBase, fillCandidateBase, sizeTableCand); + rowsCommon.reserveTablesCandidates(sizeTableCand); reserveTable(rowCandidatePar, fillCandidatePar, sizeTableCand); reserveTable(rowCandidateParE, fillCandidateParE, sizeTableCand); reserveTable(rowCandidateSel, fillCandidateSel, sizeTableCand); + reserveTable(rowCandidateMl, fillCandidateMl, sizeTableCand); reserveTable(rowCandidateId, fillCandidateId, sizeTableCand); if constexpr (isMc) { reserveTable(rowCandidateMc, fillCandidateMc, sizeTableCand); @@ -289,7 +256,7 @@ struct HfDerivedDataCreatorLcToPKPi { continue; } if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } @@ -305,6 +272,7 @@ struct HfDerivedDataCreatorLcToPKPi { auto prong1 = candidate.template prong1_as(); auto prong2 = candidate.template prong2_as(); double ct = hfHelper.ctLc(candidate); + double y = hfHelper.yLc(candidate); float massLcToPKPi = hfHelper.invMassLcToPKPi(candidate); float massLcToPiKP = hfHelper.invMassLcToPiKP(candidate); std::vector mlScoresLcToPKPi, mlScoresLcToPiKP; @@ -313,30 +281,15 @@ struct HfDerivedDataCreatorLcToPKPi { std::copy(candidate.mlProbLcToPiKP().begin(), candidate.mlProbLcToPiKP().end(), std::back_inserter(mlScoresLcToPiKP)); } if (candidate.isSelLcToPKPi()) { - fillTablesCandidate(candidate, prong0, prong1, prong2, 0, massLcToPKPi, ct, flagMcRec, origin, swapping, mlScoresLcToPKPi); + fillTablesCandidate(candidate, prong0, prong1, prong2, 0, massLcToPKPi, ct, y, flagMcRec, origin, swapping, mlScoresLcToPKPi); } if (candidate.isSelLcToPiKP()) { - fillTablesCandidate(candidate, prong0, prong1, prong2, 1, massLcToPiKP, ct, flagMcRec, origin, swapping, mlScoresLcToPiKP); + fillTablesCandidate(candidate, prong0, prong1, prong2, 1, massLcToPiKP, ct, y, flagMcRec, origin, swapping, mlScoresLcToPiKP); } } } } - template - void processMcParticles(ParticleType const& mcParticles) - { - // Fill MC particle properties - auto sizeTablePart = mcParticles.size(); - reserveTable(rowParticleBase, fillParticleBase, sizeTablePart); - reserveTable(rowParticleId, fillParticleId, sizeTablePart); - for (const auto& particle : mcParticles) { - if (!TESTBIT(std::abs(particle.flagMcMatchGen()), aod::hf_cand_3prong::DecayType::LcToPKPi)) { - continue; - } - fillTablesParticle(particle, o2::constants::physics::MassLambdaCPlus); - } - } - void processData(CollisionsWCentMult const& collisions, SelectedCandidates const&, TracksWPid const& tracks, @@ -346,36 +299,42 @@ struct HfDerivedDataCreatorLcToPKPi { } PROCESS_SWITCH(HfDerivedDataCreatorLcToPKPi, processData, "Process data", true); - void processMcSig(CollisionsWCentMult const& collisions, + void processMcSig(CollisionsWMcCentMult const& collisions, SelectedCandidatesMc const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, TracksWPid const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcSig, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorLcToPKPi, processMcSig, "Process MC only for signals", false); - void processMcBkg(CollisionsWCentMult const& collisions, + void processMcBkg(CollisionsWMcCentMult const& collisions, SelectedCandidatesMc const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, TracksWPid const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcBkg, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorLcToPKPi, processMcBkg, "Process MC only for background", false); - void processMcAll(CollisionsWCentMult const& collisions, + void processMcAll(CollisionsWMcCentMult const& collisions, SelectedCandidatesMc const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, TracksWPid const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcAll, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorLcToPKPi, processMcAll, "Process MC", false); @@ -390,38 +349,51 @@ struct HfDerivedDataCreatorLcToPKPi { } PROCESS_SWITCH(HfDerivedDataCreatorLcToPKPi, processDataMl, "Process data with ML", false); - void processMcMlSig(CollisionsWCentMult const& collisions, + void processMcMlSig(CollisionsWMcCentMult const& collisions, SelectedCandidatesMcMl const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, TracksWPid const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcMlSig, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorLcToPKPi, processMcMlSig, "Process MC with ML only for signals", false); - void processMcMlBkg(CollisionsWCentMult const& collisions, + void processMcMlBkg(CollisionsWMcCentMult const& collisions, SelectedCandidatesMcMl const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, TracksWPid const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcMlBkg, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorLcToPKPi, processMcMlBkg, "Process MC with ML only for background", false); - void processMcMlAll(CollisionsWCentMult const& collisions, + void processMcMlAll(CollisionsWMcCentMult const& collisions, SelectedCandidatesMcMl const&, + TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, TracksWPid const& tracks, aod::BCs const& bcs) { + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcMlAll, tracks, bcs); - processMcParticles(mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); } PROCESS_SWITCH(HfDerivedDataCreatorLcToPKPi, processMcMlAll, "Process MC with ML", false); + + void processMcGenOnly(TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles) + { + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorLcToPKPi, processMcGenOnly, "Process MC gen. only", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/TableProducer/mcPidTof.cxx b/PWGHF/TableProducer/mcPidTof.cxx new file mode 100644 index 00000000000..52ae2e2ebf4 --- /dev/null +++ b/PWGHF/TableProducer/mcPidTof.cxx @@ -0,0 +1,1066 @@ +// 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 mcPidTof.cxx +/// \author Fabrizio Grosa fabrizio.grosa@cern.ch +/// \brief Task to produce PID tables for TOF split for pi, K, p, copied from https://github.com/AliceO2Group/O2Physics/blob/master/Common/TableProducer/PID/pidTofMerge.cxx +/// It works only for MC and adds the possibility to apply postcalibrations for MC. +/// + +#include +#include +#include +#include +#include + +#include + +// O2 includes +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "ReconstructionDataFormats/Track.h" +#include "CCDB/BasicCCDBManager.h" +#include "TOFBase/EventTimeMaker.h" + +// O2Physics includes +#include "TableHelper.h" +#include "MetadataHelper.h" +#include "CollisionTypeHelper.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/TableProducer/PID/pidTOFBase.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::pid; +using namespace o2::framework::expressions; +using namespace o2::track; + +MetadataHelper metadataInfo; + +// Input data types +using Trks = o2::soa::Join; +using Cols = aod::Collisions; +using TrksWtof = soa::Join; +using TrksWtofWevTime = soa::Join; + +using EvTimeCollisions = soa::Join; +using EvTimeCollisionsFT0 = soa::Join; + +// Configuration common to all tasks +struct TOFCalibConfig { + template + void init(const CfgType& opt) + { + mUrl = opt.cfgUrl.value; + mPathGrpLhcIf = opt.cfgPathGrpLhcIf.value; + mTimestamp = opt.cfgTimestamp.value; + mTimeShiftCCDBPathPos = opt.cfgTimeShiftCCDBPathPos.value; + mTimeShiftCCDBPathNeg = opt.cfgTimeShiftCCDBPathNeg.value; + mTimeShiftCCDBPathPosMC = opt.cfgTimeShiftCCDBPathPosMC.value; + mTimeShiftCCDBPathNegMC = opt.cfgTimeShiftCCDBPathNegMC.value; + mParamFileName = opt.cfgParamFileName.value; + mParametrizationPath = opt.cfgParametrizationPath.value; + mReconstructionPass = opt.cfgReconstructionPass.value; + mReconstructionPassDefault = opt.cfgReconstructionPassDefault.value; + mFatalOnPassNotAvailable = opt.cfgFatalOnPassNotAvailable.value; + mEnableTimeDependentResponse = opt.cfgEnableTimeDependentResponse.value; + mCollisionSystem = opt.cfgCollisionSystem.value; + mAutoSetProcessFunctions = opt.cfgAutoSetProcessFunctions.value; + } + + template + void getCfg(o2::framework::InitContext& initContext, const std::string name, VType& v, const std::string task) + { + if (!getTaskOptionValue(initContext, task, name, v, false)) { + LOG(fatal) << "Could not get " << name << " from " << task << " task"; + } + } + + void inheritFromBaseTask(o2::framework::InitContext& initContext, const std::string task = "tof-signal") + { + mInitMode = 2; + getCfg(initContext, "ccdb-url", mUrl, task); + getCfg(initContext, "ccdb-path-grplhcif", mPathGrpLhcIf, task); + getCfg(initContext, "ccdb-timestamp", mTimestamp, task); + getCfg(initContext, "timeShiftCCDBPathPos", mTimeShiftCCDBPathPos, task); + getCfg(initContext, "timeShiftCCDBPathNeg", mTimeShiftCCDBPathNeg, task); + getCfg(initContext, "timeShiftCCDBPathPosMC", mTimeShiftCCDBPathPosMC, task); + getCfg(initContext, "timeShiftCCDBPathNegMC", mTimeShiftCCDBPathNegMC, task); + getCfg(initContext, "paramFileName", mParamFileName, task); + getCfg(initContext, "parametrizationPath", mParametrizationPath, task); + getCfg(initContext, "reconstructionPass", mReconstructionPass, task); + getCfg(initContext, "reconstructionPassDefault", mReconstructionPassDefault, task); + getCfg(initContext, "fatalOnPassNotAvailable", mFatalOnPassNotAvailable, task); + getCfg(initContext, "enableTimeDependentResponse", mEnableTimeDependentResponse, task); + getCfg(initContext, "collisionSystem", mCollisionSystem, task); + getCfg(initContext, "autoSetProcessFunctions", mAutoSetProcessFunctions, task); + } + // @brief Set up the configuration from the calibration object from the init function of the task + template + void initSetup(o2::pid::tof::TOFResoParamsV3& mRespParamsV3, + CCDBObject ccdb) + { + mInitMode = 1; + // First we set the CCDB manager + ccdb->setURL(mUrl); + ccdb->setTimestamp(mTimestamp); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + // Not later than now objects + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + + // Then the information about the metadata + if (mReconstructionPass == "metadata") { + LOG(info) << "Getting pass from metadata"; + if (metadataInfo.isMC()) { + mReconstructionPass = metadataInfo.get("AnchorPassName"); + } else { + LOG(fatal) << "This task works only for MC"; + } + LOG(info) << "Passed autodetect mode for pass. Taking '" << mReconstructionPass << "'"; + } + LOG(info) << "Using parameter collection, starting from pass '" << mReconstructionPass << "'"; + + if (!mParamFileName.empty()) { // Loading the parametrization from file + LOG(info) << "Loading exp. sigma parametrization from file " << mParamFileName << ", using param: " << mParametrizationPath << " and pass " << mReconstructionPass; + o2::tof::ParameterCollection paramCollection; + paramCollection.loadParamFromFile(mParamFileName, mParametrizationPath); + LOG(info) << "+++ Loaded parameter collection from file +++"; + if (!paramCollection.retrieveParameters(mRespParamsV3, mReconstructionPass)) { + if (mFatalOnPassNotAvailable) { + LOG(fatal) << "Pass '" << mReconstructionPass << "' not available in the retrieved object from file"; + } else { + LOG(warning) << "Pass '" << mReconstructionPass << "' not available in the retrieved object from file, fetching '" << mReconstructionPassDefault << "'"; + if (!paramCollection.retrieveParameters(mRespParamsV3, mReconstructionPassDefault)) { + paramCollection.print(); + LOG(fatal) << "Cannot get default pass for calibration " << mReconstructionPassDefault; + } else { + mRespParamsV3.setResolutionParametrization(paramCollection.getPars(mReconstructionPassDefault)); + mRespParamsV3.setMomentumChargeShiftParameters(paramCollection.getPars(mReconstructionPassDefault)); + } + } + } else { // Pass is available, load non standard parameters + mRespParamsV3.setResolutionParametrization(paramCollection.getPars(mReconstructionPass)); + mRespParamsV3.setMomentumChargeShiftParameters(paramCollection.getPars(mReconstructionPass)); + } + } else if (!mEnableTimeDependentResponse) { // Loading it from CCDB + LOG(info) << "Loading exp. sigma parametrization from CCDB, using path: " << mParametrizationPath << " for timestamp " << mTimestamp; + o2::tof::ParameterCollection* paramCollection = ccdb->template getForTimeStamp(mParametrizationPath, mTimestamp); + if (!paramCollection->retrieveParameters(mRespParamsV3, mReconstructionPass)) { // Attempt at loading the parameters with the pass defined + if (mFatalOnPassNotAvailable) { + LOG(fatal) << "Pass '" << mReconstructionPass << "' not available in the retrieved CCDB object"; + } else { + LOG(warning) << "Pass '" << mReconstructionPass << "' not available in the retrieved CCDB object, fetching '" << mReconstructionPassDefault << "'"; + if (!paramCollection->retrieveParameters(mRespParamsV3, mReconstructionPassDefault)) { + paramCollection->print(); + LOG(fatal) << "Cannot get default pass for calibration " << mReconstructionPassDefault; + } else { + mRespParamsV3.setResolutionParametrization(paramCollection->getPars(mReconstructionPassDefault)); + mRespParamsV3.setMomentumChargeShiftParameters(paramCollection->getPars(mReconstructionPassDefault)); + } + } + } else { // Pass is available, load non standard parameters + mRespParamsV3.setResolutionParametrization(paramCollection->getPars(mReconstructionPass)); + mRespParamsV3.setMomentumChargeShiftParameters(paramCollection->getPars(mReconstructionPass)); + } + } + + // Loading additional calibration objects + std::map metadata; + if (!mReconstructionPass.empty()) { + metadata["RecoPassName"] = mReconstructionPass; + } + auto updateTimeShift = [&](const std::string& nameShift, bool isPositive) { + if (nameShift.empty()) { + return; + } + const bool isFromFile = nameShift.find(".root") != std::string::npos; + if (isFromFile) { + LOG(info) << "Initializing the time shift for " << (isPositive ? "positive" : "negative") << " from file '" << nameShift << "'"; + mRespParamsV3.setTimeShiftParameters(nameShift, "ccdb_object", isPositive); + } else if (!mEnableTimeDependentResponse) { // If the response is fixed fetch it at the init time + LOG(info) << "Initializing the time shift for " << (isPositive ? "positive" : "negative") + << " from ccdb '" << nameShift << "' and timestamp " << mTimestamp + << " and pass '" << mReconstructionPass << "'"; + mRespParamsV3.setTimeShiftParameters(ccdb->template getSpecific(nameShift, mTimestamp, metadata), isPositive); + } + LOG(info) << " test getTimeShift at 0 " << (isPositive ? "pos" : "neg") << ": " + << mRespParamsV3.getTimeShift(0, isPositive); + }; + + const std::string nameShiftPos = metadataInfo.isMC() ? mTimeShiftCCDBPathPosMC : mTimeShiftCCDBPathPos; + updateTimeShift(nameShiftPos, true); + const std::string nameShiftNeg = metadataInfo.isMC() ? mTimeShiftCCDBPathNegMC : mTimeShiftCCDBPathNeg; + updateTimeShift(nameShiftNeg, true); + + // Calibration object is defined + LOG(info) << "Parametrization at init time:"; + mRespParamsV3.printFullConfig(); + } + + template + void processSetup(o2::pid::tof::TOFResoParamsV3& mRespParamsV3, + CCDBObject ccdb, + const BcType& bc) + { + LOG(debug) << "Processing setup for run number " << bc.runNumber() << " from run " << mLastRunNumber; + // First we check if this run number was already processed + if (mLastRunNumber == bc.runNumber()) { + return; + } + mLastRunNumber = bc.runNumber(); + mTimestamp = bc.timestamp(); + + // Check the beam type + if (mCollisionSystem == -1) { + o2::parameters::GRPLHCIFData* grpo = ccdb->template getSpecific(mPathGrpLhcIf, + mTimestamp); + mCollisionSystem = CollisionSystemType::getCollisionTypeFromGrp(grpo); + } else { + LOG(debug) << "Not setting collisions system as already set to " << mCollisionSystem << " " << CollisionSystemType::getCollisionSystemName(mCollisionSystem); + } + + if (!mEnableTimeDependentResponse) { + return; + } + LOG(info) << "Updating parametrization from path '" << mParametrizationPath << "' and timestamp " << mTimestamp << " and reconstruction pass '" << mReconstructionPass << "' for run number " << bc.runNumber(); + if (mParamFileName.empty()) { // Not loading if parametrization was taken from file + LOG(info) << "Updating parametrization from ccdb"; + const o2::tof::ParameterCollection* paramCollection = ccdb->template getSpecific(mParametrizationPath, mTimestamp); + if (!paramCollection->retrieveParameters(mRespParamsV3, mReconstructionPass)) { + if (mFatalOnPassNotAvailable) { + LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", mReconstructionPass.data()); + } else { + LOGF(warning, "Pass '%s' not available in the retrieved CCDB object, fetching '%s'", mReconstructionPass.data(), mReconstructionPassDefault.data()); + if (!paramCollection->retrieveParameters(mRespParamsV3, mReconstructionPassDefault)) { + paramCollection->print(); + LOG(fatal) << "Cannot get default pass for calibration " << mReconstructionPassDefault; + } else { // Found the default case + mRespParamsV3.setResolutionParametrization(paramCollection->getPars(mReconstructionPassDefault)); + mRespParamsV3.setMomentumChargeShiftParameters(paramCollection->getPars(mReconstructionPassDefault)); + } + } + } else { // Found the non default case + mRespParamsV3.setResolutionParametrization(paramCollection->getPars(mReconstructionPass)); + mRespParamsV3.setMomentumChargeShiftParameters(paramCollection->getPars(mReconstructionPass)); + } + } + + // Loading additional calibration objects + std::map metadata; + if (!mReconstructionPass.empty()) { + metadata["RecoPassName"] = mReconstructionPass; + } + auto updateTimeShift = [&](const std::string& nameShift, bool isPositive) { + if (nameShift.empty()) { + return; + } + const bool isFromFile = nameShift.find(".root") != std::string::npos; + if (isFromFile) { + return; + } + LOG(info) << "Updating the time shift for " << (isPositive ? "positive" : "negative") + << " from ccdb '" << nameShift << "' and timestamp " << mTimestamp + << " and pass '" << mReconstructionPass << "'"; + mRespParamsV3.setTimeShiftParameters(ccdb->template getSpecific(nameShift, mTimestamp, metadata), isPositive); + LOG(info) << " test getTimeShift at 0 " << (isPositive ? "pos" : "neg") << ": " + << mRespParamsV3.getTimeShift(0, isPositive); + }; + + updateTimeShift(metadataInfo.isMC() ? mTimeShiftCCDBPathPosMC : mTimeShiftCCDBPathPos, true); + updateTimeShift(metadataInfo.isMC() ? mTimeShiftCCDBPathNegMC : mTimeShiftCCDBPathNeg, false); + + LOG(info) << "Parametrization at setup time:"; + mRespParamsV3.printFullConfig(); + } + + bool autoSetProcessFunctions() const { return mAutoSetProcessFunctions; } + int collisionSystem() const { return mCollisionSystem; } + + private: + int mLastRunNumber = -1; // Last run number for which the calibration was loaded + int mInitMode = 0; // 0: no init, 1: init, 2: inherit + + // Configurable options + std::string mUrl; + std::string mPathGrpLhcIf; + int64_t mTimestamp; + std::string mTimeShiftCCDBPathPos; + std::string mTimeShiftCCDBPathNeg; + std::string mTimeShiftCCDBPathPosMC; + std::string mTimeShiftCCDBPathNegMC; + std::string mParamFileName; + std::string mParametrizationPath; + std::string mReconstructionPass; + std::string mReconstructionPassDefault; + bool mFatalOnPassNotAvailable; + bool mEnableTimeDependentResponse; + int mCollisionSystem; + bool mAutoSetProcessFunctions; +}; + +// Part 1 TOF signal definition + +/// Selection criteria for tracks used for TOF event time +bool isTrackGoodMatchForTOFPID(const Trks::iterator& tr) +{ + if (!tr.hasTOF()) { + return false; + } + return true; +} + +/// Task to produce the TOF signal from the trackTime information +struct tofSignal { + // Tables to produce + o2::framework::Produces table; + o2::framework::Produces tableFlags; + // Running flags + bool enableTableTOFSignal = false; // Flag to check if the TOF signal table is requested or not + bool enableTablepidTOFFlags = false; // Flag to check if the TOF signal flags table is requested or not + // Output histograms + Configurable enableQaHistograms{"enableQaHistograms", false, "Flag to enable the QA histograms"}; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + // Detector response and input parameters + o2::pid::tof::TOFResoParamsV3 mRespParamsV3; + Service ccdb; + struct : ConfigurableGroup { + Configurable cfgUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable cfgPathGrpLhcIf{"ccdb-path-grplhcif", "GLO/Config/GRPLHCIF", "Path on the CCDB for the GRPLHCIF object"}; + Configurable cfgTimestamp{"ccdb-timestamp", -1, "timestamp of the object"}; + Configurable cfgTimeShiftCCDBPathPos{"timeShiftCCDBPathPos", "", "Path of the TOF time shift vs eta for pos. tracks. If empty none is taken"}; + Configurable cfgTimeShiftCCDBPathNeg{"timeShiftCCDBPathNeg", "", "Path of the TOF time shift vs eta for neg. tracks. If empty none is taken"}; + Configurable cfgTimeShiftCCDBPathPosMC{"timeShiftCCDBPathPosMC", "", "Path of the TOF time shift for MC vs eta for pos. tracks. If empty none is taken"}; + Configurable cfgTimeShiftCCDBPathNegMC{"timeShiftCCDBPathNegMC", "", "Path of the TOF time shift for MC vs eta for neg. tracks. If empty none is taken"}; + Configurable cfgParamFileName{"paramFileName", "", "Path to the parametrization object. If empty the parametrization is not taken from file"}; + Configurable cfgParametrizationPath{"parametrizationPath", "TOF/Calib/Params", "Path of the TOF parametrization on the CCDB or in the file, if the paramFileName is not empty"}; + Configurable cfgReconstructionPass{"reconstructionPass", "", {"Apass to use when fetching the calibration tables. Empty (default) does not check for any pass. Use `metadata` to fetch it from the AO2D metadata. Otherwise it will override the metadata."}}; + Configurable cfgReconstructionPassDefault{"reconstructionPassDefault", "unanchored", {"Default pass to get if the standard one is not found"}}; + Configurable cfgFatalOnPassNotAvailable{"fatalOnPassNotAvailable", true, "Flag to throw a fatal if the pass is not available in the retrieved CCDB object"}; + Configurable cfgEnableTimeDependentResponse{"enableTimeDependentResponse", false, "Flag to use the collision timestamp to fetch the PID Response"}; + Configurable cfgCollisionSystem{"collisionSystem", -1, "Collision system: -1 (autoset), 0 (pp), 1 (PbPb), 2 (XeXe), 3 (pPb)"}; + Configurable cfgAutoSetProcessFunctions{"autoSetProcessFunctions", true, "Flag to autodetect the process functions to use"}; + } cfg; // Configurables (only defined here and inherited from other tasks) + + TOFCalibConfig mTOFCalibConfig; // TOF Calib configuration + + void init(o2::framework::InitContext& initContext) + { + mTOFCalibConfig.init(cfg); + // Checking that the table is requested in the workflow and enabling it + enableTableTOFSignal = isTableRequiredInWorkflow(initContext, "TOFSignal"); + if (enableTableTOFSignal) { + LOG(info) << "Table TOFSignal enabled!"; + } + enableTablepidTOFFlags = isTableRequiredInWorkflow(initContext, "pidTOFFlags"); + if (enableTablepidTOFFlags) { + LOG(info) << "Table pidTOFFlags enabled!"; + } + + // If the table is not requested, disable the task. Uless a process function is enabled from the workflow configuration + if (!enableTableTOFSignal && !enableTablepidTOFFlags) { + LOG(info) << "No table or process is enabled. Disabling task"; + return; + } + + mTOFCalibConfig.initSetup(mRespParamsV3, ccdb); // Getting the parametrization parameters + if (!enableQaHistograms) { + return; + } + histos.add("tofSignal", "tofSignal", kTH1D, {{1000, -1000, 1000000, "tofSignal (ps)"}}); + if (enableTablepidTOFFlags) { + histos.add("goodForPIDFlags", "goodForPIDFlags", kTH1D, {{3, 0, 3, "flags"}}); + } + } + + void process(Trks const& tracks) + { + if (!enableTableTOFSignal) { + return; + } + table.reserve(tracks.size()); + if (enableTablepidTOFFlags) { + tableFlags.reserve(tracks.size()); + } + for (auto const& trk : tracks) { + const float& sig = o2::pid::tof::TOFSignal::GetTOFSignal(trk); + if (enableQaHistograms) { + histos.fill(HIST("tofSignal"), sig); + } + table(sig); + if (!enableTablepidTOFFlags) { + continue; + } + const auto& b = isTrackGoodMatchForTOFPID(trk); + if (enableQaHistograms) { + histos.fill(HIST("goodForPIDFlags"), sig); + } + tableFlags(b); + } + } +}; + +/// Selection criteria for tracks used for TOF event time +float trackSampleMinMomentum = 0.5f; +float trackSampleMaxMomentum = 2.f; +template +bool filterForTOFEventTime(const trackType& tr) +{ + return (tr.hasTOF() && + tr.p() > trackSampleMinMomentum && tr.p() < trackSampleMaxMomentum && + tr.hasITS() && + tr.hasTPC() && + (tr.trackType() == o2::aod::track::TrackTypeEnum::Track || tr.trackType() == o2::aod::track::TrackTypeEnum::TrackIU)); +} // accept all + +/// Specialization of TOF event time maker +template typename response, + typename trackTypeContainer, + typename responseParametersType> +o2::tof::eventTimeContainer evTimeMakerForTracks(const trackTypeContainer& tracks, + const responseParametersType& responseParameters, + const float& diamond = 6.0) +{ + return o2::tof::evTimeMakerFromParam(tracks, responseParameters, diamond); +} + +// Part 2 event time definition + +/// Task to produce the TOF event time table +struct tofEventTime { + // Tables to produce + Produces tableEvTime; + Produces tableEvTimeTOFOnly; + Produces tableFlags; + static constexpr bool removeTOFEvTimeBias = true; // Flag to subtract the Ev. Time bias for low multiplicity events with TOF + static constexpr float diamond = 6.0; // Collision diamond used in the estimation of the TOF event time + static constexpr float errDiamond = diamond * 33.356409f; + static constexpr float weightDiamond = 1.f / (errDiamond * errDiamond); + + bool enableTableTOFEvTime = false; + bool enableTableEvTimeTOFOnly = false; + // Detector response and input parameters + o2::pid::tof::TOFResoParamsV3 mRespParamsV3; + Service ccdb; + TOFCalibConfig mTOFCalibConfig; // TOF Calib configuration + + // Event time configurations + Configurable minMomentum{"minMomentum", 0.5f, "Minimum momentum to select track sample for TOF event time"}; + Configurable maxMomentum{"maxMomentum", 2.0f, "Maximum momentum to select track sample for TOF event time"}; + Configurable maxEvTimeTOF{"maxEvTimeTOF", 100000.0f, "Maximum value of the TOF event time"}; + Configurable sel8TOFEvTime{"sel8TOFEvTime", false, "Flag to compute the ev. time only for events that pass the sel8 ev. selection"}; + Configurable mComputeEvTimeWithTOF{"computeEvTimeWithTOF", -1, "Compute ev. time with TOF. -1 (autoset), 0 no, 1 yes"}; + Configurable mComputeEvTimeWithFT0{"computeEvTimeWithFT0", -1, "Compute ev. time with FT0. -1 (autoset), 0 no, 1 yes"}; + Configurable maxNtracksInSet{"maxNtracksInSet", 10, "Size of the set to consider for the TOF ev. time computation"}; + + void init(o2::framework::InitContext& initContext) + { + mTOFCalibConfig.inheritFromBaseTask(initContext); + // Checking that the table is requested in the workflow and enabling it + enableTableTOFEvTime = isTableRequiredInWorkflow(initContext, "TOFEvTime"); + + if (!enableTableTOFEvTime) { + LOG(info) << "Table for TOF Event time (TOFEvTime) is not required, disabling it"; + } + LOG(info) << "Table TOFEvTime enabled!"; + + enableTableEvTimeTOFOnly = isTableRequiredInWorkflow(initContext, "EvTimeTOFOnly"); + if (enableTableEvTimeTOFOnly) { + LOG(info) << "Table EvTimeTOFOnly enabled!"; + } + + if (!enableTableTOFEvTime && !enableTableEvTimeTOFOnly) { + LOG(info) << "No table is enabled. Disabling task"; + return; + } + + if (metadataInfo.isFullyDefined()) { + if (!metadataInfo.isRun3()) { + LOG(fatal) << "Metadata says it is Run2, but this task supports only Run3"; + } + } + + trackSampleMinMomentum = minMomentum; + trackSampleMaxMomentum = maxMomentum; + LOG(info) << "Configuring track sample for TOF ev. time: " << trackSampleMinMomentum << " < p < " << trackSampleMaxMomentum; + + if (sel8TOFEvTime.value == true) { + LOG(info) << "TOF event time will be computed for collisions that pass the event selection only!"; + } + mTOFCalibConfig.initSetup(mRespParamsV3, ccdb); // Getting the parametrization parameters + + o2::tof::eventTimeContainer::setMaxNtracksInSet(maxNtracksInSet.value); + o2::tof::eventTimeContainer::printConfig(); + } + + /// + /// Process function to prepare the event for each track on Run 3 data without the FT0 + // Define slice per collision + Preslice perCollision = aod::track::collisionId; + template + using ResponseImplementationEvTime = o2::pid::tof::ExpTimes; + void process(TrksWtof const& tracks, + aod::FT0s const&, + EvTimeCollisionsFT0 const&, + aod::BCsWithTimestamps const& bcs) + { + if (!enableTableTOFEvTime) { + return; + } + LOG(debug) << "Processing data for TOF event time"; + + tableEvTime.reserve(tracks.size()); + tableFlags.reserve(tracks.size()); + if (enableTableEvTimeTOFOnly) { + tableEvTimeTOFOnly.reserve(tracks.size()); + } + + mTOFCalibConfig.processSetup(mRespParamsV3, ccdb, bcs.iteratorAt(0)); // Update the calibration parameters + + // Autoset the processing mode for the event time computation + if (mComputeEvTimeWithTOF == -1 || mComputeEvTimeWithFT0 == -1) { + switch (mTOFCalibConfig.collisionSystem()) { + case CollisionSystemType::kCollSyspp: // pp + mComputeEvTimeWithTOF.value = ((mComputeEvTimeWithTOF == -1) ? 0 : mComputeEvTimeWithTOF.value); + mComputeEvTimeWithFT0.value = ((mComputeEvTimeWithFT0 == -1) ? 1 : mComputeEvTimeWithFT0.value); + break; + case CollisionSystemType::kCollSysPbPb: // PbPb + mComputeEvTimeWithTOF.value = ((mComputeEvTimeWithTOF == -1) ? 1 : mComputeEvTimeWithTOF.value); + mComputeEvTimeWithFT0.value = ((mComputeEvTimeWithFT0 == -1) ? 0 : mComputeEvTimeWithFT0.value); + break; + default: + LOG(fatal) << "Collision system " << mTOFCalibConfig.collisionSystem() << " " << CollisionSystemType::getCollisionSystemName(mTOFCalibConfig.collisionSystem()) << " not supported for TOF event time computation"; + break; + } + } + LOG(debug) << "Running on " << CollisionSystemType::getCollisionSystemName(mTOFCalibConfig.collisionSystem()) << " mComputeEvTimeWithTOF " << mComputeEvTimeWithTOF.value << " mComputeEvTimeWithFT0 " << mComputeEvTimeWithFT0.value; + + if (mComputeEvTimeWithTOF == 1 && mComputeEvTimeWithFT0 == 1) { + int lastCollisionId = -1; // Last collision ID analysed + for (auto const& t : tracks) { // Loop on collisions + if (!t.has_collision() || ((sel8TOFEvTime.value == true) && !t.collision_as().sel8())) { // Track was not assigned, cannot compute event time or event did not pass the event selection + tableFlags(0); + tableEvTime(0.f, 999.f); + if (enableTableEvTimeTOFOnly) { + tableEvTimeTOFOnly((uint8_t)0, 0.f, 0.f, -1); + } + continue; + } + if (t.collisionId() == lastCollisionId) { // Event time from this collision is already in the table + continue; + } + /// Create new table for the tracks in a collision + lastCollisionId = t.collisionId(); /// Cache last collision ID + + const auto& tracksInCollision = tracks.sliceBy(perCollision, lastCollisionId); + const auto& collision = t.collision_as(); + + // Compute the TOF event time + const auto evTimeMakerTOF = evTimeMakerForTracks(tracksInCollision, mRespParamsV3, diamond); + + float t0AC[2] = {.0f, 999.f}; // Value and error of T0A or T0C or T0AC + float t0TOF[2] = {static_cast(evTimeMakerTOF.mEventTime), static_cast(evTimeMakerTOF.mEventTimeError)}; // Value and error of TOF + + uint8_t flags = 0; + int nGoodTracksForTOF = 0; + float eventTime = 0.f; + float sumOfWeights = 0.f; + float weight = 0.f; + + for (auto const& trk : tracksInCollision) { // Loop on Tracks + // Reset the flag + flags = 0; + // Reset the event time + eventTime = 0.f; + sumOfWeights = 0.f; + weight = 0.f; + // Remove the bias on TOF ev. time + if constexpr (removeTOFEvTimeBias) { + evTimeMakerTOF.removeBias(trk, nGoodTracksForTOF, t0TOF[0], t0TOF[1], 2); + } + if (t0TOF[1] < errDiamond && (maxEvTimeTOF <= 0 || std::abs(t0TOF[0]) < maxEvTimeTOF)) { + flags |= o2::aod::pidflags::enums::PIDFlags::EvTimeTOF; + + weight = 1.f / (t0TOF[1] * t0TOF[1]); + eventTime += t0TOF[0] * weight; + sumOfWeights += weight; + } + + if (collision.has_foundFT0()) { // T0 measurement is available + // const auto& ft0 = collision.foundFT0(); + if (collision.t0ACValid()) { + t0AC[0] = collision.t0AC() * 1000.f; + t0AC[1] = collision.t0resolution() * 1000.f; + flags |= o2::aod::pidflags::enums::PIDFlags::EvTimeT0AC; + } + + weight = 1.f / (t0AC[1] * t0AC[1]); + eventTime += t0AC[0] * weight; + sumOfWeights += weight; + } + + if (sumOfWeights < weightDiamond) { // avoiding sumOfWeights = 0 or worse that diamond + eventTime = 0; + sumOfWeights = weightDiamond; + tableFlags(0); + } else { + tableFlags(flags); + } + tableEvTime(eventTime / sumOfWeights, std::sqrt(1. / sumOfWeights)); + if (enableTableEvTimeTOFOnly) { + tableEvTimeTOFOnly((uint8_t)filterForTOFEventTime(trk), t0TOF[0], t0TOF[1], evTimeMakerTOF.mEventTimeMultiplicity); + } + } + } + } else if (mComputeEvTimeWithTOF == 1 && mComputeEvTimeWithFT0 == 0) { + int lastCollisionId = -1; // Last collision ID analysed + for (auto const& t : tracks) { // Loop on collisions + if (!t.has_collision() || ((sel8TOFEvTime.value == true) && !t.collision_as().sel8())) { // Track was not assigned, cannot compute event time or event did not pass the event selection + tableFlags(0); + tableEvTime(0.f, 999.f); + if (enableTableEvTimeTOFOnly) { + tableEvTimeTOFOnly((uint8_t)0, 0.f, 0.f, -1); + } + continue; + } + if (t.collisionId() == lastCollisionId) { // Event time from this collision is already in the table + continue; + } + /// Create new table for the tracks in a collision + lastCollisionId = t.collisionId(); /// Cache last collision ID + + const auto& tracksInCollision = tracks.sliceBy(perCollision, lastCollisionId); + + // First make table for event time + const auto evTimeMakerTOF = evTimeMakerForTracks(tracksInCollision, mRespParamsV3, diamond); + int nGoodTracksForTOF = 0; + float et = evTimeMakerTOF.mEventTime; + float erret = evTimeMakerTOF.mEventTimeError; + + for (auto const& trk : tracksInCollision) { // Loop on Tracks + if constexpr (removeTOFEvTimeBias) { + evTimeMakerTOF.removeBias(trk, nGoodTracksForTOF, et, erret, 2); + } + uint8_t flags = 0; + if (erret < errDiamond && (maxEvTimeTOF <= 0.f || std::abs(et) < maxEvTimeTOF)) { + flags |= o2::aod::pidflags::enums::PIDFlags::EvTimeTOF; + } else { + et = 0.f; + erret = errDiamond; + } + tableFlags(flags); + tableEvTime(et, erret); + if (enableTableEvTimeTOFOnly) { + tableEvTimeTOFOnly((uint8_t)filterForTOFEventTime(trk), et, erret, evTimeMakerTOF.mEventTimeMultiplicity); + } + } + } + } else if (mComputeEvTimeWithTOF == 0 && mComputeEvTimeWithFT0 == 1) { + for (auto const& t : tracks) { // Loop on collisions + if (enableTableEvTimeTOFOnly) { + tableEvTimeTOFOnly((uint8_t)0, 0.f, 0.f, -1); + } + if (!t.has_collision()) { // Track was not assigned, cannot compute event time + tableFlags(0); + tableEvTime(0.f, 999.f); + continue; + } + const auto& collision = t.collision_as(); + + if (collision.has_foundFT0()) { // T0 measurement is available + // const auto& ft0 = collision.foundFT0(); + if (collision.t0ACValid()) { + tableFlags(o2::aod::pidflags::enums::PIDFlags::EvTimeT0AC); + tableEvTime(collision.t0AC() * 1000.f, collision.t0resolution() * 1000.f); + continue; + } + } + tableFlags(0); + tableEvTime(0.f, 999.f); + } + } else { + LOG(fatal) << "Invalid configuration for TOF event time computation"; + } + } +}; + +// Part 3 Nsigma computation + +static constexpr int idxPi = 2; +static constexpr int idxKa = 3; +static constexpr int idxPr = 4; + +/// Task to produce the response table +struct mcPidTof { + // Tables to produce + Produces tablePIDPi; + Produces tablePIDKa; + Produces tablePIDPr; + + // Tables to produce (full) + Produces tablePIDFullPi; + Produces tablePIDFullKa; + Produces tablePIDFullPr; + + // Detector response parameters + o2::pid::tof::TOFResoParamsV3 mRespParamsV3; + Service ccdb; + TOFCalibConfig mTOFCalibConfig; // TOF Calib configuration + Configurable enableQaHistograms{"enableQaHistograms", false, "Flag to enable the QA histograms"}; + + // Histograms for QA + std::array, nSpecies> hnSigma; + std::array, nSpecies> hnSigmaFull; + + // postcalibrations to overcome MC FT0 timing issue + std::map gMcPostCalibMean{}; + std::map gMcPostCalibSigma{}; + int currentRun{0}; + struct : ConfigurableGroup { + std::string prefix = "mcRecalib"; + Configurable enable{"enable", false, "enable MC recalibration for Pi/Ka/Pr"}; + Configurable ccdbPath{"ccdbPath", "Users/f/fgrosa/RecalibmcPidTof/", "path for MC recalibration objects in CCDB"}; + } mcRecalib; + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Running variables + std::vector mEnabledParticles; // Vector of enabled PID hypotheses to loop on when making tables + std::vector mEnabledParticlesFull; // Vector of enabled PID hypotheses to loop on when making full tables + void init(o2::framework::InitContext& initContext) + { + mTOFCalibConfig.inheritFromBaseTask(initContext); + // Checking the tables are requested in the workflow and enabling them (only pi, K, p) + std::array supportedSpecies = {idxPi, idxKa, idxPr}; + for (auto iSpecie{0u}; iSpecie < supportedSpecies.size(); ++iSpecie) { + // First checking tiny + int flag = -1; + enableFlagIfTableRequired(initContext, "pidTOF" + particleNames[supportedSpecies[iSpecie]], flag); + if (flag == 1) { + mEnabledParticles.push_back(supportedSpecies[iSpecie]); + } + + // Then check full + flag = -1; + enableFlagIfTableRequired(initContext, "pidTOFFull" + particleNames[supportedSpecies[iSpecie]], flag); + if (flag == 1) { + mEnabledParticlesFull.push_back(supportedSpecies[iSpecie]); + } + } + if (mEnabledParticlesFull.size() == 0 && mEnabledParticles.size() == 0) { + LOG(info) << "No PID tables are required, disabling process function"; + doprocessFillTables.value = false; + doprocessDummy.value = true; + return; + } + if (metadataInfo.isFullyDefined()) { + if (!metadataInfo.isRun3()) { + LOG(fatal) << "Metadata says it is Run2, but this task supports only Run3 data"; + } + } + mTOFCalibConfig.initSetup(mRespParamsV3, ccdb); // Getting the parametrization parameters + + // Printing enabled tables and enabling QA histograms if needed + LOG(info) << "++ Enabled tables:"; + const AxisSpec pAxis{100, 0, 5, "#it{p} (GeV/#it{c})"}; + const AxisSpec nSigmaAxis{100, -10, 10, "N_{#sigma}^{TOF}"}; + for (const int& iSpecie : mEnabledParticles) { + LOG(info) << "++ pidTOF" << particleNames[iSpecie] << " is enabled"; + if (!enableQaHistograms) { + continue; + } + hnSigma[iSpecie] = histos.add(Form("nSigma/%s", particleNames[iSpecie].c_str()), Form("N_{#sigma}^{TOF}(%s)", particleNames[iSpecie].c_str()), kTH2F, {pAxis, nSigmaAxis}); + } + for (const int& iSpecie : mEnabledParticlesFull) { + LOG(info) << "++ pidTOFFull" << particleNames[iSpecie] << " is enabled"; + if (!enableQaHistograms) { + continue; + } + hnSigmaFull[iSpecie] = histos.add(Form("nSigmaFull/%s", particleNames[iSpecie].c_str()), Form("N_{#sigma}^{TOF}(%s)", particleNames[iSpecie].c_str()), kTH2F, {pAxis, nSigmaAxis}); + } + } + + // Reserves an empty table for the given particle ID with size of the given track table + void reserveTable(const int id, const int64_t& size, const bool fullTable = false) + { + switch (id) { + case idxPi: { + if (fullTable) { + tablePIDFullPi.reserve(size); + } else { + tablePIDPi.reserve(size); + } + break; + } + case idxKa: { + if (fullTable) { + tablePIDFullKa.reserve(size); + } else { + tablePIDKa.reserve(size); + } + break; + } + case idxPr: { + if (fullTable) { + tablePIDFullPr.reserve(size); + } else { + tablePIDPr.reserve(size); + } + break; + } + default: + LOG(fatal) << "Wrong particle ID in reserveTable() for " << (fullTable ? "full" : "tiny") << " tables"; + break; + } + } + + // Makes the table empty for the given particle ID, filling it with dummy values + void makeTableEmpty(const int id, bool fullTable = false) + { + switch (id) { + case idxPi: + if (fullTable) { + tablePIDFullPi(-999.f, -999.f); + } else { + aod::pidutils::packInTable(-999.f, + tablePIDPi); + } + break; + case idxKa: + if (fullTable) { + tablePIDFullKa(-999.f, -999.f); + } else { + aod::pidutils::packInTable(-999.f, + tablePIDKa); + } + break; + case idxPr: + if (fullTable) { + tablePIDFullPr(-999.f, -999.f); + } else { + aod::pidutils::packInTable(-999.f, + tablePIDPr); + } + break; + default: + LOG(fatal) << "Wrong particle ID in makeTableEmpty() for " << (fullTable ? "full" : "tiny") << " tables"; + break; + } + } + + /// Retrieve MC postcalibration objects from CCDB + /// \param timestamp timestamp + void retrieveMcPostCalibFromCcdb(int64_t timestamp) + { + std::map metadata; + if (metadataInfo.isFullyDefined()) { + metadata["RecoPassName"] = metadataInfo.get("AnchorPassName"); + } else { + LOGP(error, "Impossible to read metadata! Using default calibrations (2022 apass7)"); + metadata["RecoPassName"] = ""; + } + auto calibList = ccdb->getSpecific(mcRecalib.ccdbPath, timestamp, metadata); + std::vector updatedSpecies{}; + for (auto const& pidId : mEnabledParticles) { // Loop on enabled particle hypotheses (tiny) + gMcPostCalibMean[pidId] = reinterpret_cast(calibList->FindObject(Form("Mean%s", particleNames[pidId].data()))); + gMcPostCalibSigma[pidId] = reinterpret_cast(calibList->FindObject(Form("Sigma%s", particleNames[pidId].data()))); + updatedSpecies.push_back(pidId); + } + for (auto const& pidId : mEnabledParticlesFull) { // Loop on enabled particle hypotheses (full) + if (std::find(updatedSpecies.begin(), updatedSpecies.end(), pidId) != updatedSpecies.end()) { + continue; + } + gMcPostCalibMean[pidId] = reinterpret_cast(calibList->FindObject(Form("Mean%s", particleNames[pidId].data()))); + gMcPostCalibSigma[pidId] = reinterpret_cast(calibList->FindObject(Form("Sigma%s", particleNames[pidId].data()))); + } + } + + /// Apply MC postcalibrations + /// \param pidId particle id + /// \param pt track pT + template + T applyMcRecalib(int pidId, T trackPt, T nSigma) + { + if (nSigma < -998) { + return nSigma; + } + + float shift{0.f}, scaleWidth{0.f}; + int nPoints = gMcPostCalibMean[pidId]->GetN(); + double ptMin = gMcPostCalibMean[pidId]->GetX()[0]; + double ptMax = gMcPostCalibMean[pidId]->GetX()[nPoints - 1]; + if (trackPt < ptMin) { + shift = gMcPostCalibMean[pidId]->Eval(ptMin); + scaleWidth = gMcPostCalibSigma[pidId]->Eval(ptMin); + } else if (trackPt > ptMax) { + shift = gMcPostCalibMean[pidId]->Eval(ptMax); + scaleWidth = gMcPostCalibSigma[pidId]->Eval(ptMax); + } else { + shift = gMcPostCalibMean[pidId]->Eval(trackPt); + scaleWidth = gMcPostCalibSigma[pidId]->Eval(trackPt); + } + + T nSigmaCorr = (nSigma - shift) / scaleWidth; + return nSigmaCorr; + } + + void processDummy(Trks const&) {} + PROCESS_SWITCH(mcPidTof, processDummy, "Dummy process function", false); + + template + using ResponseImplementation = o2::pid::tof::ExpTimes; + void processFillTables(TrksWtofWevTime const& tracks, + Cols const&, + aod::BCsWithTimestamps const& bcs, + aod::McParticles const&) + { + constexpr auto responsePi = ResponseImplementation(); + constexpr auto responseKa = ResponseImplementation(); + constexpr auto responsePr = ResponseImplementation(); + + mTOFCalibConfig.processSetup(mRespParamsV3, ccdb, bcs.iteratorAt(0)); // Update the calibration parameters + + for (auto const& pidId : mEnabledParticles) { + reserveTable(pidId, tracks.size(), false); + } + + for (auto const& pidId : mEnabledParticlesFull) { + reserveTable(pidId, tracks.size(), true); + } + + float resolution = 1.f; // Last resolution assigned + float nSigma = 0; + for (auto const& trk : tracks) { // Loop on all tracks + if (!trk.has_collision()) { // Track was not assigned, cannot compute NSigma (no event time) -> filling with empty table + for (auto const& pidId : mEnabledParticles) { + makeTableEmpty(pidId, false); + } + for (auto const& pidId : mEnabledParticlesFull) { + makeTableEmpty(pidId, true); + } + continue; + } + + if (mcRecalib.enable) { + auto runNumber = trk.collision().bc_as().runNumber(); + if (runNumber != currentRun) { + // update postcalibration files + auto timestamp = trk.collision().bc_as().timestamp(); + retrieveMcPostCalibFromCcdb(timestamp); + } + currentRun = runNumber; + } + + for (auto const& pidId : mEnabledParticles) { // Loop on enabled particle hypotheses + switch (pidId) { + case idxPi: { + nSigma = responsePi.GetSeparation(mRespParamsV3, trk); + if (mcRecalib.enable && trk.has_mcParticle()) { + if (std::abs(trk.mcParticle().pdgCode()) == kPiPlus) { // we rescale only true signal + nSigma = applyMcRecalib(pidId, trk.pt(), nSigma); + } + } + aod::pidutils::packInTable(nSigma, tablePIDPi); + break; + } + case idxKa: { + nSigma = responseKa.GetSeparation(mRespParamsV3, trk); + if (mcRecalib.enable && trk.has_mcParticle()) { + if (std::abs(trk.mcParticle().pdgCode()) == kKPlus) { // we rescale only true signal + nSigma = applyMcRecalib(pidId, trk.pt(), nSigma); + } + } + aod::pidutils::packInTable(nSigma, tablePIDKa); + break; + } + case idxPr: { + nSigma = responsePr.GetSeparation(mRespParamsV3, trk); + if (mcRecalib.enable && trk.has_mcParticle()) { + if (std::abs(trk.mcParticle().pdgCode()) == kProton) { // we rescale only true signal + nSigma = applyMcRecalib(pidId, trk.pt(), nSigma); + } + } + aod::pidutils::packInTable(nSigma, tablePIDPr); + break; + } + default: + LOG(fatal) << "Wrong particle ID for standard tables"; + break; + } + if (enableQaHistograms) { + hnSigma[pidId]->Fill(trk.p(), nSigma); + } + } + + for (auto const& pidId : mEnabledParticlesFull) { // Loop on enabled particle hypotheses with full tables + switch (pidId) { + case idxPi: { + resolution = responsePi.GetExpectedSigma(mRespParamsV3, trk); + nSigma = responsePi.GetSeparation(mRespParamsV3, trk); + if (mcRecalib.enable && trk.has_mcParticle()) { + if (std::abs(trk.mcParticle().pdgCode()) == kPiPlus) { // we rescale only true signal + nSigma = applyMcRecalib(pidId, trk.pt(), nSigma); + } + } + tablePIDFullPi(resolution, nSigma); + break; + } + case idxKa: { + resolution = responseKa.GetExpectedSigma(mRespParamsV3, trk); + nSigma = responseKa.GetSeparation(mRespParamsV3, trk, resolution); + if (mcRecalib.enable && trk.has_mcParticle()) { + if (std::abs(trk.mcParticle().pdgCode()) == kKPlus) { // we rescale only true signal + nSigma = applyMcRecalib(pidId, trk.pt(), nSigma); + } + } + tablePIDFullKa(resolution, nSigma); + break; + } + case idxPr: { + resolution = responsePr.GetExpectedSigma(mRespParamsV3, trk); + nSigma = responsePr.GetSeparation(mRespParamsV3, trk, resolution); + if (mcRecalib.enable && trk.has_mcParticle()) { + if (std::abs(trk.mcParticle().pdgCode()) == kProton) { // we rescale only true signal + nSigma = applyMcRecalib(pidId, trk.pt(), nSigma); + } + } + tablePIDFullPr(resolution, nSigma); + break; + } + default: + LOG(fatal) << "Wrong particle ID for full tables"; + break; + } + if (enableQaHistograms) { + hnSigmaFull[pidId]->Fill(trk.p(), nSigma); + } + } + } + } + PROCESS_SWITCH(mcPidTof, processFillTables, "Process with table filling", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // Parse the metadata + metadataInfo.initMetadata(cfgc); + auto workflow = WorkflowSpec{adaptAnalysisTask(cfgc)}; + workflow.push_back(adaptAnalysisTask(cfgc)); + workflow.push_back(adaptAnalysisTask(cfgc)); + return workflow; +} diff --git a/PWGHF/TableProducer/pidCreator.cxx b/PWGHF/TableProducer/pidCreator.cxx index 3444b1936a7..57da53a0d30 100644 --- a/PWGHF/TableProducer/pidCreator.cxx +++ b/PWGHF/TableProducer/pidCreator.cxx @@ -14,6 +14,8 @@ /// /// \author Vít Kučera , Inha University +#include + #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" @@ -37,8 +39,8 @@ struct HfPidCreator { Produces trackPidFullPr; Produces trackPidTinyPr; - static constexpr float defaultNSigmaTolerance = .1f; - static constexpr float defaultNSigma = -999.f + defaultNSigmaTolerance; // -999.f is the default value set in TPCPIDResponse.h and PIDTOF.h + static constexpr float NSigmaToleranceDefault = .1f; + static constexpr float NSigmaDefault = -999.f + NSigmaToleranceDefault; // -999.f is the default value set in TPCPIDResponse.h and PIDTOF.h /// Function to check whether the process function flag matches the need for filling the table /// \param initContext workflow context (argument of the init function) @@ -85,13 +87,13 @@ struct HfPidCreator { tpcNSigma *= aod::pidtpc_tiny::binning::bin_width; tofNSigma *= aod::pidtof_tiny::binning::bin_width; } - if ((tpcNSigma > defaultNSigma) && (tofNSigma > defaultNSigma)) { // TPC and TOF + if ((tpcNSigma > NSigmaDefault) && (tofNSigma > NSigmaDefault)) { // TPC and TOF return std::sqrt(.5f * (tpcNSigma * tpcNSigma + tofNSigma * tofNSigma)); } - if (tpcNSigma > defaultNSigma) { // only TPC + if (tpcNSigma > NSigmaDefault) { // only TPC return std::abs(tpcNSigma); } - if (tofNSigma > defaultNSigma) { // only TOF + if (tofNSigma > NSigmaDefault) { // only TOF return std::abs(tofNSigma); } return tofNSigma; // no TPC nor TOF diff --git a/PWGHF/TableProducer/trackIndexSkimCreator.cxx b/PWGHF/TableProducer/trackIndexSkimCreator.cxx index eeb9ee80fa3..d5994cfbad3 100644 --- a/PWGHF/TableProducer/trackIndexSkimCreator.cxx +++ b/PWGHF/TableProducer/trackIndexSkimCreator.cxx @@ -19,6 +19,7 @@ /// \author Jinjoo Seo , Inha University /// \author Fabrizio Grosa , CERN /// \author Federica Zanone , Heidelberg University +/// \author Ruiqi Yin , Fudan University #include // std::find #include // std::distance @@ -48,6 +49,7 @@ #include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/Utils/utilsAnalysis.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" @@ -57,7 +59,7 @@ using namespace o2; using namespace o2::analysis; using namespace o2::hf_evsel; using namespace o2::aod; -using namespace o2::aod::hf_collision_centrality; +using namespace o2::hf_centrality; using namespace o2::framework; using namespace o2::framework::expressions; @@ -89,29 +91,18 @@ enum ChannelsProtonPid { NChannelsProtonPid }; // kaon PID (opposite-sign track in 3-prong decays) -constexpr int channelKaonPid = ChannelsProtonPid::NChannelsProtonPid; +constexpr int ChannelKaonPid = ChannelsProtonPid::NChannelsProtonPid; /// Event selection struct HfTrackIndexSkimCreatorTagSelCollisions { Produces rowSelectedCollision; Configurable fillHistograms{"fillHistograms", true, "fill histograms"}; - Configurable zVertexMin{"zVertexMin", -100., "min. z of primary vertex [cm]"}; - Configurable zVertexMax{"zVertexMax", 100., "max. z of primary vertex [cm]"}; - Configurable nContribMin{"nContribMin", 0, "min. number of contributors to primary-vertex reconstruction"}; - Configurable chi2Max{"chi2Max", 0., "max. chi^2 of primary-vertex reconstruction"}; - Configurable triggerClassName{"triggerClassName", "kINT7", "trigger class"}; - Configurable useSel8Trigger{"useSel8Trigger", true, "use sel8 trigger condition, for Run3 studies"}; - Configurable centralityMin{"centralityMin", 0., "Minimum centrality"}; - Configurable centralityMax{"centralityMax", 100., "Maximum centrality"}; - Configurable useTimeFrameBorderCut{"useTimeFrameBorderCut", true, "use time-frame border cut in event selection"}; - - ConfigurableAxis axisNumContributors{"axisNumContributors", {200, -0.5f, 199.5f}, "Number of PV contributors"}; - - int triggerClass; + Configurable triggerClassName{"triggerClassName", "kINT7", "Run 2 trigger class, only for Run 2 converted data"}; + HfEventSelection hfEvSel; // event selection and monitoring + Service ccdb; // needed for evSelection // QA histos - std::shared_ptr hEvents, hPrimVtxZBeforeSel, hPrimVtxZAfterSel, hPrimVtxXAfterSel, hPrimVtxYAfterSel, hNContributorsAfterSel; HistogramRegistry registry{"registry"}; void init(InitContext const&) @@ -121,18 +112,14 @@ struct HfTrackIndexSkimCreatorTagSelCollisions { LOGP(fatal, "One and only one process function for collision selection can be enabled at a time!"); } - triggerClass = std::distance(aliasLabels, std::find(aliasLabels, aliasLabels + kNaliases, triggerClassName.value.data())); + // set numerical value of the Run 2 trigger class + auto triggerAlias = std::find(aliasLabels, aliasLabels + kNaliases, triggerClassName.value.data()); + if (triggerAlias != aliasLabels + kNaliases) { + hfEvSel.triggerClass.value = std::distance(aliasLabels, triggerAlias); + } if (fillHistograms) { - hEvents = registry.add("hEvents", "Events;;entries", HistType::kTH1F, {axisEvents}); - setLabelHistoEvSel(hEvents); - - // primary vertex histograms - hPrimVtxZBeforeSel = registry.add("hPrimVtxZBeforeSel", "all events;#it{z}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{200, -20., 20.}}}); - hPrimVtxZAfterSel = registry.add("hPrimVtxZAfterSel", "selected events;#it{z}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{200, -20., 20.}}}); - hPrimVtxXAfterSel = registry.add("hPrimVtxXAfterSel", "selected events;#it{x}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{200, -0.5, 0.5}}}); - hPrimVtxYAfterSel = registry.add("hPrimVtxYAfterSel", "selected events;#it{y}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {{200, -0.5, 0.5}}}); - hNContributorsAfterSel = registry.add("hNContributorsAfterSel", "selected events;#it{y}_{prim. vtx.} (cm);entries", {HistType::kTH1D, {axisNumContributors}}); + hfEvSel.addHistograms(registry); // collision monitoring if (doprocessTrigAndCentFT0ASel || doprocessTrigAndCentFT0CSel || doprocessTrigAndCentFT0MSel || doprocessTrigAndCentFV0ASel) { AxisSpec axisCentrality{200, 0., 100., "centrality percentile"}; @@ -144,129 +131,130 @@ struct HfTrackIndexSkimCreatorTagSelCollisions { /// Collision selection /// \param collision collision table with - template - void selectCollision(const Col& collision) + template + void selectCollision(const Col& collision, const BCs&) { float centrality = -1.; - const auto statusCollision = getHfCollisionRejectionMask(collision, centrality, centralityMin, centralityMax, useSel8Trigger, triggerClass, useTimeFrameBorderCut, zVertexMin, zVertexMax, nContribMin, chi2Max); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); if (fillHistograms) { - monitorCollision(collision, statusCollision, hEvents, hPrimVtxZBeforeSel, hPrimVtxZAfterSel, hPrimVtxXAfterSel, hPrimVtxYAfterSel, hNContributorsAfterSel); + hfEvSel.fillHistograms(collision, rejectionMask, centrality); // additional centrality histos - if constexpr (centEstimator != o2::aod::hf_collision_centrality::None) { - if (statusCollision == 0) { + if constexpr (centEstimator != o2::hf_centrality::None) { + if (rejectionMask == 0) { registry.fill(HIST("hCentralitySelected"), centrality); - } else if (statusCollision == BIT(EventRejection::Centrality)) { // rejected by centrality only + } else if (rejectionMask == BIT(EventRejection::Centrality)) { // rejected by centrality only registry.fill(HIST("hCentralityRejected"), centrality); } } } // fill table row - rowSelectedCollision(statusCollision); + rowSelectedCollision(rejectionMask); } /// Event selection with trigger and FT0A centrality selection - void processTrigAndCentFT0ASel(soa::Join::iterator const& collision) + void processTrigAndCentFT0ASel(soa::Join::iterator const& collision, aod::BCsWithTimestamps const& bcs) { - selectCollision(collision); + selectCollision(collision, bcs); } PROCESS_SWITCH(HfTrackIndexSkimCreatorTagSelCollisions, processTrigAndCentFT0ASel, "Use trigger and centrality selection with FT0A", false); /// Event selection with trigger and FT0C centrality selection - void processTrigAndCentFT0CSel(soa::Join::iterator const& collision) + void processTrigAndCentFT0CSel(soa::Join::iterator const& collision, aod::BCsWithTimestamps const& bcs) { - selectCollision(collision); + selectCollision(collision, bcs); } PROCESS_SWITCH(HfTrackIndexSkimCreatorTagSelCollisions, processTrigAndCentFT0CSel, "Use trigger and centrality selection with FT0C", false); /// Event selection with trigger and FT0M centrality selection - void processTrigAndCentFT0MSel(soa::Join::iterator const& collision) + void processTrigAndCentFT0MSel(soa::Join::iterator const& collision, aod::BCsWithTimestamps const& bcs) { - selectCollision(collision); + selectCollision(collision, bcs); } PROCESS_SWITCH(HfTrackIndexSkimCreatorTagSelCollisions, processTrigAndCentFT0MSel, "Use trigger and centrality selection with FT0M", false); /// Event selection with trigger and FV0A centrality selection - void processTrigAndCentFV0ASel(soa::Join::iterator const& collision) + void processTrigAndCentFV0ASel(soa::Join::iterator const& collision, aod::BCsWithTimestamps const& bcs) { - selectCollision(collision); + selectCollision(collision, bcs); } PROCESS_SWITCH(HfTrackIndexSkimCreatorTagSelCollisions, processTrigAndCentFV0ASel, "Use trigger and centrality selection with FV0A", false); /// Event selection with trigger selection - void processTrigSel(soa::Join::iterator const& collision) + void processTrigSel(soa::Join::iterator const& collision, aod::BCsWithTimestamps const& bcs) { - selectCollision(collision); + selectCollision(collision, bcs); } PROCESS_SWITCH(HfTrackIndexSkimCreatorTagSelCollisions, processTrigSel, "Use trigger selection", false); /// Event selection without trigger selection - void processNoTrigSel(aod::Collision const& collision) + void processNoTrigSel(aod::Collision const& collision, aod::BCsWithTimestamps const& bcs) { - selectCollision(collision); + selectCollision(collision, bcs); } PROCESS_SWITCH(HfTrackIndexSkimCreatorTagSelCollisions, processNoTrigSel, "Do not use trigger selection", true); }; /// Track selection struct HfTrackIndexSkimCreatorTagSelTracks { - SliceCache cache; - Preslice perCol = aod::track::collisionId; - Produces rowSelectedTrack; Produces tabPvRefitTrack; - Configurable isRun2{"isRun2", false, "enable Run 2 or Run 3 GRP objects for magnetic field"}; - Configurable doPvRefit{"doPvRefit", false, "do PV refit excluding the considered track"}; - Configurable fillHistograms{"fillHistograms", true, "fill histograms"}; - Configurable debugPvRefit{"debugPvRefit", false, "debug lines for primary vertex refit"}; - // Configurable bz{"bz", 5., "bz field"}; - // quality cut - Configurable doCutQuality{"doCutQuality", true, "apply quality cuts"}; - Configurable useIsGlobalTrack{"useIsGlobalTrack", false, "check isGlobalTrack status for tracks, for Run3 studies"}; - Configurable useIsGlobalTrackWoDCA{"useIsGlobalTrackWoDCA", false, "check isGlobalTrackWoDCA status for tracks, for Run3 studies"}; - Configurable tpcNClsFoundMin{"tpcNClsFoundMin", 70, "min. number of found TPC clusters"}; - // pT bins for single-track cuts - Configurable> binsPtTrack{"binsPtTrack", std::vector{hf_cuts_single_track::vecBinsPtTrack}, "track pT bin limits for 2-prong DCA XY pT-dependent cut"}; - // 2-prong cuts - Configurable ptMinTrack2Prong{"ptMinTrack2Prong", -1., "min. track pT for 2 prong candidate"}; - Configurable> cutsTrack2Prong{"cutsTrack2Prong", {hf_cuts_single_track::cutsTrack[0], hf_cuts_single_track::nBinsPtTrack, hf_cuts_single_track::nCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for 2-prong candidates"}; - Configurable etaMinTrack2Prong{"etaMinTrack2Prong", -99999., "min. pseudorapidity for 2 prong candidate"}; - Configurable etaMaxTrack2Prong{"etaMaxTrack2Prong", 4., "max. pseudorapidity for 2 prong candidate"}; - // 3-prong cuts - Configurable ptMinTrack3Prong{"ptMinTrack3Prong", -1., "min. track pT for 3 prong candidate"}; - Configurable> cutsTrack3Prong{"cutsTrack3Prong", {hf_cuts_single_track::cutsTrack[0], hf_cuts_single_track::nBinsPtTrack, hf_cuts_single_track::nCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for 3-prong candidates"}; - Configurable etaMinTrack3Prong{"etaMinTrack3Prong", -99999., "min. pseudorapidity for 3 prong candidate"}; - Configurable etaMaxTrack3Prong{"etaMaxTrack3Prong", 4., "max. pseudorapidity for 3 prong candidate"}; - // bachelor cuts (V0 + bachelor decays) - Configurable ptMinTrackBach{"ptMinTrackBach", 0.3, "min. track pT for bachelor in cascade candidate"}; // 0.5 for PbPb 2015? - Configurable> cutsTrackBach{"cutsTrackBach", {hf_cuts_single_track::cutsTrack[0], hf_cuts_single_track::nBinsPtTrack, hf_cuts_single_track::nCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for the bachelor of V0-bachelor candidates"}; - Configurable etaMinTrackBach{"etaMinTrackBach", -99999., "min. pseudorapidity for bachelor in cascade candidate"}; - Configurable etaMaxTrackBach{"etaMaxTrackBach", 0.8, "max. pseudorapidity for bachelor in cascade candidate"}; - // bachelor cuts (cascade + bachelor decays) - Configurable ptMinTrackBachLfCasc{"ptMinTrackBachLfCasc", 0.1, "min. track pT for bachelor in cascade + bachelor decays"}; // 0.5 for PbPb 2015? - Configurable> cutsTrackBachLfCasc{"cutsTrackBachLfCasc", {hf_cuts_single_track::cutsTrack[0], hf_cuts_single_track::nBinsPtTrack, hf_cuts_single_track::nCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for the bachelor in cascade + bachelor decays"}; - Configurable etaMinTrackBachLfCasc{"etaMinTrackBachLfCasc", -99999., "min. pseudorapidity for bachelor in cascade + bachelor decays"}; - Configurable etaMaxTrackBachLfCasc{"etaMaxTrackBachLfCasc", 1.1, "max. pseudorapidity for bachelor in cascade + bachelor decays"}; - Configurable useIsGlobalTrackForBachLfCasc{"useIsGlobalTrackForBachLfCasc", false, "check isGlobalTrack status for bachelor in cascade + bachelor decays"}; - Configurable useIsGlobalTrackWoDCAForBachLfCasc{"useIsGlobalTrackWoDCAForBachLfCasc", false, "check isGlobalTrackWoDCA status for bachelor in cascade + bachelor decays"}; - Configurable useIsQualityTrackITSForBachLfCasc{"useIsQualityTrackITSForBachLfCasc", true, "check isQualityTrackITS status for bachelor in cascade + bachelor decays"}; - // soft pion cuts for D* - Configurable ptMinSoftPionForDstar{"ptMinSoftPionForDstar", 0.05, "min. track pT for soft pion in D* candidate"}; - Configurable etaMinSoftPionForDstar{"etaMinSoftPionForDstar", -99999., "min. pseudorapidity for soft pion in D* candidate"}; - Configurable etaMaxSoftPionForDstar{"etaMaxSoftPionForDstar", 0.8, "max. pseudorapidity for soft pion in D* candidate"}; - Configurable> cutsTrackDstar{"cutsTrackDstar", {hf_cuts_single_track::cutsTrackPrimary[0], hf_cuts_single_track::nBinsPtTrack, hf_cuts_single_track::nCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for the soft pion of D* candidates"}; - Configurable useIsGlobalTrackForSoftPion{"useIsGlobalTrackForSoftPion", false, "check isGlobalTrack status for soft pion tracks"}; - Configurable useIsGlobalTrackWoDCAForSoftPion{"useIsGlobalTrackWoDCAForSoftPion", false, "check isGlobalTrackWoDCA status for soft pion tracks"}; - Configurable useIsQualityTrackITSForSoftPion{"useIsQualityTrackITSForSoftPion", true, "check qualityTracksITS status for soft pion tracks"}; - // proton PID, applied only if corresponding process function enabled - Configurable> selectionsPid{"selectionsPid", {hf_presel_pid::cutsPid[0], 4, 6, hf_presel_pid::labelsRowsPid, hf_presel_pid::labelsCutsPid}, "PID selections for proton / kaon applied if proper process function enabled"}; - // CCDB - Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; - Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; - Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + struct : ConfigurableGroup { + Configurable isRun2{"isRun2", false, "enable Run 2 or Run 3 GRP objects for magnetic field"}; + Configurable doPvRefit{"doPvRefit", false, "do PV refit excluding the considered track"}; + Configurable fillHistograms{"fillHistograms", true, "fill histograms"}; + Configurable debugPvRefit{"debugPvRefit", false, "debug lines for primary vertex refit"}; + // Configurable bz{"bz", 5., "bz field"}; + // quality cut + Configurable doCutQuality{"doCutQuality", true, "apply quality cuts"}; + Configurable useIsGlobalTrack{"useIsGlobalTrack", false, "check isGlobalTrack status for tracks, for Run3 studies"}; + Configurable useIsGlobalTrackWoDCA{"useIsGlobalTrackWoDCA", false, "check isGlobalTrackWoDCA status for tracks, for Run3 studies"}; + Configurable tpcNClsFoundMin{"tpcNClsFoundMin", 70, "min. number of found TPC clusters"}; + // pT bins for single-track cuts + Configurable> binsPtTrack{"binsPtTrack", std::vector{hf_cuts_single_track::vecBinsPtTrack}, "track pT bin limits for 2-prong DCA XY pT-dependent cut"}; + // 2-prong cuts + Configurable ptMinTrack2Prong{"ptMinTrack2Prong", -1., "min. track pT for 2 prong candidate"}; + Configurable> cutsTrack2Prong{"cutsTrack2Prong", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for 2-prong candidates"}; + Configurable etaMinTrack2Prong{"etaMinTrack2Prong", -99999., "min. pseudorapidity for 2 prong candidate"}; + Configurable etaMaxTrack2Prong{"etaMaxTrack2Prong", 4., "max. pseudorapidity for 2 prong candidate"}; + // 3-prong cuts + Configurable ptMinTrack3Prong{"ptMinTrack3Prong", -1., "min. track pT for 3 prong candidate"}; + Configurable> cutsTrack3Prong{"cutsTrack3Prong", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for 3-prong candidates"}; + Configurable etaMinTrack3Prong{"etaMinTrack3Prong", -99999., "min. pseudorapidity for 3 prong candidate"}; + Configurable etaMaxTrack3Prong{"etaMaxTrack3Prong", 4., "max. pseudorapidity for 3 prong candidate"}; + // bachelor cuts (V0 + bachelor decays) + Configurable ptMinTrackBach{"ptMinTrackBach", 0.3, "min. track pT for bachelor in cascade candidate"}; // 0.5 for PbPb 2015? + Configurable> cutsTrackBach{"cutsTrackBach", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for the bachelor of V0-bachelor candidates"}; + Configurable etaMinTrackBach{"etaMinTrackBach", -99999., "min. pseudorapidity for bachelor in cascade candidate"}; + Configurable etaMaxTrackBach{"etaMaxTrackBach", 0.8, "max. pseudorapidity for bachelor in cascade candidate"}; + // bachelor cuts (cascade + bachelor decays) + Configurable ptMinTrackBachLfCasc{"ptMinTrackBachLfCasc", 0.1, "min. track pT for bachelor in cascade + bachelor decays"}; // 0.5 for PbPb 2015? + Configurable> cutsTrackBachLfCasc{"cutsTrackBachLfCasc", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for the bachelor in cascade + bachelor decays"}; + Configurable etaMinTrackBachLfCasc{"etaMinTrackBachLfCasc", -99999., "min. pseudorapidity for bachelor in cascade + bachelor decays"}; + Configurable etaMaxTrackBachLfCasc{"etaMaxTrackBachLfCasc", 1.1, "max. pseudorapidity for bachelor in cascade + bachelor decays"}; + Configurable useIsGlobalTrackForBachLfCasc{"useIsGlobalTrackForBachLfCasc", false, "check isGlobalTrack status for bachelor in cascade + bachelor decays"}; + Configurable useIsGlobalTrackWoDCAForBachLfCasc{"useIsGlobalTrackWoDCAForBachLfCasc", false, "check isGlobalTrackWoDCA status for bachelor in cascade + bachelor decays"}; + Configurable useIsQualityTrackITSForBachLfCasc{"useIsQualityTrackITSForBachLfCasc", true, "check isQualityTrackITS status for bachelor in cascade + bachelor decays"}; + // soft pion cuts for D* + Configurable ptMinSoftPionForDstar{"ptMinSoftPionForDstar", 0.05, "min. track pT for soft pion in D* candidate"}; + Configurable etaMinSoftPionForDstar{"etaMinSoftPionForDstar", -99999., "min. pseudorapidity for soft pion in D* candidate"}; + Configurable etaMaxSoftPionForDstar{"etaMaxSoftPionForDstar", 0.8, "max. pseudorapidity for soft pion in D* candidate"}; + Configurable> cutsTrackDstar{"cutsTrackDstar", {hf_cuts_single_track::CutsTrackPrimary[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections per pT bin for the soft pion of D* candidates"}; + Configurable useIsGlobalTrackForSoftPion{"useIsGlobalTrackForSoftPion", false, "check isGlobalTrack status for soft pion tracks"}; + Configurable useIsGlobalTrackWoDCAForSoftPion{"useIsGlobalTrackWoDCAForSoftPion", false, "check isGlobalTrackWoDCA status for soft pion tracks"}; + Configurable useIsQualityTrackITSForSoftPion{"useIsQualityTrackITSForSoftPion", true, "check qualityTracksITS status for soft pion tracks"}; + // proton PID, applied only if corresponding process function enabled + Configurable> selectionsPid{"selectionsPid", {hf_presel_pid::CutsPid[0], 4, 6, hf_presel_pid::labelsRowsPid, hf_presel_pid::labelsCutsPid}, "PID selections for proton / kaon applied if proper process function enabled"}; + // CCDB + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; + Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + } config; + + SliceCache cache; // Needed for PV refitting Service ccdb; @@ -274,6 +262,14 @@ struct HfTrackIndexSkimCreatorTagSelTracks { o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; int runNumber; + using TracksWithSelAndDca = soa::Join; + using TracksWithSelAndDcaAndPidTpc = soa::Join; + using TracksWithSelAndDcaAndPidTof = soa::Join; + using TracksWithSelAndDcaAndPidTpcTof = soa::Join; + + Preslice perCol = aod::track::collisionId; + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + // single-track cuts static const int nCuts = 4; // array of 2-prong and 3-prong cuts @@ -282,17 +278,10 @@ struct HfTrackIndexSkimCreatorTagSelTracks { std::array selectorProton; TrackSelectorKa selectorKaon; - using TracksWithSelAndDca = soa::Join; - using TracksWithSelAndDcaAndPidTpc = soa::Join; - using TracksWithSelAndDcaAndPidTof = soa::Join; - using TracksWithSelAndDcaAndPidTpcTof = soa::Join; - - Preslice trackIndicesPerCollision = aod::track_association::collisionId; - - Partition pvContributors = ((aod::track::flags & (uint32_t)aod::track::PVContributor) == (uint32_t)aod::track::PVContributor); - Partition pvContributorsWithPidTpc = ((aod::track::flags & (uint32_t)aod::track::PVContributor) == (uint32_t)aod::track::PVContributor); - Partition pvContributorsWithPidTof = ((aod::track::flags & (uint32_t)aod::track::PVContributor) == (uint32_t)aod::track::PVContributor); - Partition pvContributorsWithPidTpcTof = ((aod::track::flags & (uint32_t)aod::track::PVContributor) == (uint32_t)aod::track::PVContributor); + Partition pvContributors = ((aod::track::flags & static_cast(aod::track::PVContributor)) == static_cast(aod::track::PVContributor)); + Partition pvContributorsWithPidTpc = ((aod::track::flags & static_cast(aod::track::PVContributor)) == static_cast(aod::track::PVContributor)); + Partition pvContributorsWithPidTof = ((aod::track::flags & static_cast(aod::track::PVContributor)) == static_cast(aod::track::PVContributor)); + Partition pvContributorsWithPidTpcTof = ((aod::track::flags & static_cast(aod::track::PVContributor)) == static_cast(aod::track::PVContributor)); // QA of PV refit ConfigurableAxis axisPvRefitDeltaX{"axisPvRefitDeltaX", {1000, -0.5f, 0.5f}, "DeltaX binning PV refit"}; @@ -308,49 +297,49 @@ struct HfTrackIndexSkimCreatorTagSelTracks { LOGP(fatal, "One and only one process function for the different PID selection strategies can be enabled at a time!"); } - cutsSingleTrack = {cutsTrack2Prong, cutsTrack3Prong, cutsTrackBach, cutsTrackDstar, cutsTrackBachLfCasc}; + cutsSingleTrack = {config.cutsTrack2Prong, config.cutsTrack3Prong, config.cutsTrackBach, config.cutsTrackDstar, config.cutsTrackBachLfCasc}; - if (etaMinTrack2Prong == -99999.) { - etaMinTrack2Prong.value = -etaMaxTrack2Prong; + if (config.etaMinTrack2Prong == -99999.) { + config.etaMinTrack2Prong.value = -config.etaMaxTrack2Prong; } - if (etaMinTrack3Prong == -99999.) { - etaMinTrack3Prong.value = -etaMaxTrack3Prong; + if (config.etaMinTrack3Prong == -99999.) { + config.etaMinTrack3Prong.value = -config.etaMaxTrack3Prong; } - if (etaMinTrackBach == -99999.) { - etaMinTrackBach.value = -etaMaxTrackBach; + if (config.etaMinTrackBach == -99999.) { + config.etaMinTrackBach.value = -config.etaMaxTrackBach; } - if (etaMinSoftPionForDstar == -99999.) { - etaMinSoftPionForDstar.value = -etaMaxSoftPionForDstar; + if (config.etaMinSoftPionForDstar == -99999.) { + config.etaMinSoftPionForDstar.value = -config.etaMaxSoftPionForDstar; } - if (etaMinTrackBachLfCasc == -99999.) { - etaMinTrackBachLfCasc.value = -etaMaxTrackBachLfCasc; + if (config.etaMinTrackBachLfCasc == -99999.) { + config.etaMinTrackBachLfCasc.value = -config.etaMaxTrackBachLfCasc; } - if (fillHistograms) { + if (config.fillHistograms) { // general tracks - registry.add("hRejTracks", "Tracks;;entries", {HistType::kTH1F, {{25, 0.5, 25.5}}}); - registry.add("hPtNoCuts", "all tracks;#it{p}_{T}^{track} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}); + registry.add("hRejTracks", "Tracks;;entries", {HistType::kTH1D, {{25, 0.5, 25.5}}}); + registry.add("hPtNoCuts", "all tracks;#it{p}_{T}^{track} (GeV/#it{c});entries", {HistType::kTH1D, {{360, 0., 36.}}}); // 2-prong histograms - registry.add("hPtCuts2Prong", "tracks selected for 2-prong vertexing;#it{p}_{T}^{track} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}); - registry.add("hDCAToPrimXYVsPtCuts2Prong", "tracks selected for 2-prong vertexing;#it{p}_{T}^{track} (GeV/#it{c});DCAxy to prim. vtx. (cm);entries", {HistType::kTH2F, {{360, 0., 36.}, {400, -2., 2.}}}); - registry.add("hEtaCuts2Prong", "tracks selected for 2-prong vertexing;#it{#eta};entries", {HistType::kTH1F, {{static_cast(0.6 * (etaMaxTrack2Prong - etaMinTrack2Prong) * 100), -1.2 * etaMinTrack2Prong, 1.2 * etaMaxTrack2Prong}}}); + registry.add("hPtCuts2Prong", "tracks selected for 2-prong vertexing;#it{p}_{T}^{track} (GeV/#it{c});entries", {HistType::kTH1D, {{360, 0., 36.}}}); + registry.add("hDCAToPrimXYVsPtCuts2Prong", "tracks selected for 2-prong vertexing;#it{p}_{T}^{track} (GeV/#it{c});DCAxy to prim. vtx. (cm);entries", {HistType::kTH2D, {{360, 0., 36.}, {400, -2., 2.}}}); + registry.add("hEtaCuts2Prong", "tracks selected for 2-prong vertexing;#it{#eta};entries", {HistType::kTH1D, {{static_cast(0.6 * (config.etaMaxTrack2Prong - config.etaMinTrack2Prong) * 100), -1.2 * config.etaMinTrack2Prong, 1.2 * config.etaMaxTrack2Prong}}}); // 3-prong histograms - registry.add("hPtCuts3Prong", "tracks selected for 3-prong vertexing;#it{p}_{T}^{track} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}); - registry.add("hDCAToPrimXYVsPtCuts3Prong", "tracks selected for 3-prong vertexing;#it{p}_{T}^{track} (GeV/#it{c});DCAxy to prim. vtx. (cm);entries", {HistType::kTH2F, {{360, 0., 36.}, {400, -2., 2.}}}); - registry.add("hEtaCuts3Prong", "tracks selected for 3-prong vertexing;#it{#eta};entries", {HistType::kTH1F, {{static_cast(0.6 * (etaMaxTrack3Prong - etaMinTrack3Prong) * 100), -1.2 * etaMinTrack3Prong, 1.2 * etaMaxTrack3Prong}}}); + registry.add("hPtCuts3Prong", "tracks selected for 3-prong vertexing;#it{p}_{T}^{track} (GeV/#it{c});entries", {HistType::kTH1D, {{360, 0., 36.}}}); + registry.add("hDCAToPrimXYVsPtCuts3Prong", "tracks selected for 3-prong vertexing;#it{p}_{T}^{track} (GeV/#it{c});DCAxy to prim. vtx. (cm);entries", {HistType::kTH2D, {{360, 0., 36.}, {400, -2., 2.}}}); + registry.add("hEtaCuts3Prong", "tracks selected for 3-prong vertexing;#it{#eta};entries", {HistType::kTH1D, {{static_cast(0.6 * (config.etaMaxTrack3Prong - config.etaMinTrack3Prong) * 100), -1.2 * config.etaMinTrack3Prong, 1.2 * config.etaMaxTrack3Prong}}}); // bachelor (for V0 + bachelor decays) histograms - registry.add("hPtCutsV0bachelor", "tracks selected for V0-bachelor vertexing;#it{p}_{T}^{track} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}); - registry.add("hDCAToPrimXYVsPtCutsV0bachelor", "tracks selected for V0-bachelor vertexing;#it{p}_{T}^{track} (GeV/#it{c});DCAxy to prim. vtx. (cm);entries", {HistType::kTH2F, {{360, 0., 36.}, {400, -2., 2.}}}); - registry.add("hEtaCutsV0bachelor", "tracks selected for V0-bachelor vertexing;#it{#eta};entries", {HistType::kTH1F, {{static_cast(0.6 * (etaMaxTrackBach - etaMinTrackBach) * 100), -1.2 * etaMinTrackBach, 1.2 * etaMaxTrackBach}}}); + registry.add("hPtCutsV0bachelor", "tracks selected for V0-bachelor vertexing;#it{p}_{T}^{track} (GeV/#it{c});entries", {HistType::kTH1D, {{360, 0., 36.}}}); + registry.add("hDCAToPrimXYVsPtCutsV0bachelor", "tracks selected for V0-bachelor vertexing;#it{p}_{T}^{track} (GeV/#it{c});DCAxy to prim. vtx. (cm);entries", {HistType::kTH2D, {{360, 0., 36.}, {400, -2., 2.}}}); + registry.add("hEtaCutsV0bachelor", "tracks selected for V0-bachelor vertexing;#it{#eta};entries", {HistType::kTH1D, {{static_cast(0.6 * (config.etaMaxTrackBach - config.etaMinTrackBach) * 100), -1.2 * config.etaMinTrackBach, 1.2 * config.etaMaxTrackBach}}}); // soft pion (for D*) histograms - registry.add("hPtCutsSoftPionForDstar", "tracks selected for D* soft pion;#it{p}_{T}^{track} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}); - registry.add("hDCAToPrimXYVsPtCutsSoftPionForDstar", "tracks selected for D* soft pion;#it{p}_{T}^{track} (GeV/#it{c});DCAxy to prim. vtx. (cm);entries", {HistType::kTH2F, {{360, 0., 36.}, {400, -2., 2.}}}); - registry.add("hEtaCutsSoftPionForDstar", "tracks selected for D* soft pion;#it{#eta};entries", {HistType::kTH1F, {{static_cast(0.6 * (etaMaxSoftPionForDstar - etaMinSoftPionForDstar) * 100), -1.2 * etaMinSoftPionForDstar, 1.2 * etaMaxSoftPionForDstar}}}); + registry.add("hPtCutsSoftPionForDstar", "tracks selected for D* soft pion;#it{p}_{T}^{track} (GeV/#it{c});entries", {HistType::kTH1D, {{360, 0., 36.}}}); + registry.add("hDCAToPrimXYVsPtCutsSoftPionForDstar", "tracks selected for D* soft pion;#it{p}_{T}^{track} (GeV/#it{c});DCAxy to prim. vtx. (cm);entries", {HistType::kTH2D, {{360, 0., 36.}, {400, -2., 2.}}}); + registry.add("hEtaCutsSoftPionForDstar", "tracks selected for D* soft pion;#it{#eta};entries", {HistType::kTH1D, {{static_cast(0.6 * (config.etaMaxSoftPionForDstar - config.etaMinSoftPionForDstar) * 100), -1.2 * config.etaMinSoftPionForDstar, 1.2 * config.etaMaxSoftPionForDstar}}}); // bachelor (for cascade + bachelor decays) histograms - registry.add("hPtCutsCascadeBachelor", "tracks selected for cascade-bachelor vertexing;#it{p}_{T}^{track} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}); - registry.add("hDCAToPrimXYVsPtCutsCascadeBachelor", "tracks selected for cascade-bachelor vertexing;#it{p}_{T}^{track} (GeV/#it{c});DCAxy to prim. vtx. (cm);entries", {HistType::kTH2F, {{360, 0., 36.}, {400, -2., 2.}}}); - registry.add("hEtaCutsCascadeBachelor", "tracks selected for cascade-bachelor vertexing;#it{#eta};entries", {HistType::kTH1F, {{static_cast(0.6 * (etaMaxTrackBachLfCasc - etaMinTrackBachLfCasc) * 100), -1.2 * etaMinTrackBachLfCasc, 1.2 * etaMaxTrackBachLfCasc}}}); + registry.add("hPtCutsCascadeBachelor", "tracks selected for cascade-bachelor vertexing;#it{p}_{T}^{track} (GeV/#it{c});entries", {HistType::kTH1D, {{360, 0., 36.}}}); + registry.add("hDCAToPrimXYVsPtCutsCascadeBachelor", "tracks selected for cascade-bachelor vertexing;#it{p}_{T}^{track} (GeV/#it{c});DCAxy to prim. vtx. (cm);entries", {HistType::kTH2D, {{360, 0., 36.}, {400, -2., 2.}}}); + registry.add("hEtaCutsCascadeBachelor", "tracks selected for cascade-bachelor vertexing;#it{#eta};entries", {HistType::kTH1D, {{static_cast(0.6 * (config.etaMaxTrackBachLfCasc - config.etaMinTrackBachLfCasc) * 100), -1.2 * config.etaMinTrackBachLfCasc, 1.2 * config.etaMaxTrackBachLfCasc}}}); std::string cutNames[nCuts + 1] = {"selected", "rej pT", "rej eta", "rej track quality", "rej dca"}; std::string candNames[CandidateType::NCandidateTypes] = {"2-prong", "3-prong", "bachelor", "dstar", "lfCascBachelor"}; @@ -362,8 +351,8 @@ struct HfTrackIndexSkimCreatorTagSelTracks { } // Needed for PV refitting - if (doPvRefit) { - if (fillHistograms) { + if (config.doPvRefit) { + if (config.fillHistograms) { AxisSpec axisCollisionX{100, -20.f, 20.f, "X (cm)"}; AxisSpec axisCollisionY{100, -20.f, 20.f, "Y (cm)"}; AxisSpec axisCollisionZ{100, -20.f, 20.f, "Z (cm)"}; @@ -375,41 +364,41 @@ struct HfTrackIndexSkimCreatorTagSelTracks { AxisSpec axisCollisionDeltaY{axisPvRefitDeltaY, "#Delta y_{PV} (cm)"}; AxisSpec axisCollisionDeltaZ{axisPvRefitDeltaZ, "#Delta z_{PV} (cm)"}; - registry.add("PvRefit/hVerticesPerTrack", "", kTH1F, {{3, 0.5f, 3.5f, ""}}); + registry.add("PvRefit/hVerticesPerTrack", "", kTH1D, {{3, 0.5f, 3.5f, ""}}); registry.get(HIST("PvRefit/hVerticesPerTrack"))->GetXaxis()->SetBinLabel(1, "All PV"); registry.get(HIST("PvRefit/hVerticesPerTrack"))->GetXaxis()->SetBinLabel(2, "PV refit doable"); registry.get(HIST("PvRefit/hVerticesPerTrack"))->GetXaxis()->SetBinLabel(3, "PV refit #chi^{2}!=-1"); - registry.add("PvRefit/hPvDeltaXvsNContrib", "", kTH2F, {axisCollisionNContrib, axisCollisionDeltaX}); - registry.add("PvRefit/hPvDeltaYvsNContrib", "", kTH2F, {axisCollisionNContrib, axisCollisionDeltaY}); - registry.add("PvRefit/hPvDeltaZvsNContrib", "", kTH2F, {axisCollisionNContrib, axisCollisionDeltaZ}); - registry.add("PvRefit/hChi2vsNContrib", "", kTH2F, {axisCollisionNContrib, {102, -1.5, 100.5, "#chi^{2} PV refit"}}); - registry.add("PvRefit/hPvRefitXChi2Minus1", "PV refit with #it{#chi}^{2}==#minus1", kTH2F, {axisCollisionX, axisCollisionXOriginal}); - registry.add("PvRefit/hPvRefitYChi2Minus1", "PV refit with #it{#chi}^{2}==#minus1", kTH2F, {axisCollisionY, axisCollisionYOriginal}); - registry.add("PvRefit/hPvRefitZChi2Minus1", "PV refit with #it{#chi}^{2}==#minus1", kTH2F, {axisCollisionZ, axisCollisionZOriginal}); - registry.add("PvRefit/hNContribPvRefitNotDoable", "N. contributors for PV refit not doable", kTH1F, {axisCollisionNContrib}); - registry.add("PvRefit/hNContribPvRefitChi2Minus1", "N. contributors original PV for PV refit #it{#chi}^{2}==#minus1", kTH1F, {axisCollisionNContrib}); - } - - ccdb->setURL(ccdbUrl); + registry.add("PvRefit/hPvDeltaXvsNContrib", "", kTH2D, {axisCollisionNContrib, axisCollisionDeltaX}); + registry.add("PvRefit/hPvDeltaYvsNContrib", "", kTH2D, {axisCollisionNContrib, axisCollisionDeltaY}); + registry.add("PvRefit/hPvDeltaZvsNContrib", "", kTH2D, {axisCollisionNContrib, axisCollisionDeltaZ}); + registry.add("PvRefit/hChi2vsNContrib", "", kTH2D, {axisCollisionNContrib, {102, -1.5, 100.5, "#chi^{2} PV refit"}}); + registry.add("PvRefit/hPvRefitXChi2Minus1", "PV refit with #it{#chi}^{2}==#minus1", kTH2D, {axisCollisionX, axisCollisionXOriginal}); + registry.add("PvRefit/hPvRefitYChi2Minus1", "PV refit with #it{#chi}^{2}==#minus1", kTH2D, {axisCollisionY, axisCollisionYOriginal}); + registry.add("PvRefit/hPvRefitZChi2Minus1", "PV refit with #it{#chi}^{2}==#minus1", kTH2D, {axisCollisionZ, axisCollisionZOriginal}); + registry.add("PvRefit/hNContribPvRefitNotDoable", "N. contributors for PV refit not doable", kTH1D, {axisCollisionNContrib}); + registry.add("PvRefit/hNContribPvRefitChi2Minus1", "N. contributors original PV for PV refit #it{#chi}^{2}==#minus1", kTH1D, {axisCollisionNContrib}); + } + + ccdb->setURL(config.ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(config.ccdbPathLut)); runNumber = 0; } // configure proton PID for (auto iChannel{0u}; iChannel < ChannelsProtonPid::NChannelsProtonPid; ++iChannel) { - selectorProton[iChannel].setRangePtTpc(selectionsPid->get(iChannel, 0u), selectionsPid->get(iChannel, 1u)); // 0u == "minPtTpc", 1u == "maxPtTpc" - selectorProton[iChannel].setRangePtTof(selectionsPid->get(iChannel, 3u), selectionsPid->get(iChannel, 4u)); // 3u == "minPtTof, 4u == "maxPtTof" - selectorProton[iChannel].setRangeNSigmaTpc(-selectionsPid->get(iChannel, 2u), selectionsPid->get(iChannel, 2u)); // 2u == "nSigmaMaxTpc" - selectorProton[iChannel].setRangeNSigmaTof(-selectionsPid->get(iChannel, 5u), selectionsPid->get(iChannel, 5u)); // 5u == "nSigmaMaxTof" + selectorProton[iChannel].setRangePtTpc(config.selectionsPid->get(iChannel, 0u), config.selectionsPid->get(iChannel, 1u)); // 0u == "minPtTpc", 1u == "maxPtTpc" + selectorProton[iChannel].setRangePtTof(config.selectionsPid->get(iChannel, 3u), config.selectionsPid->get(iChannel, 4u)); // 3u == "minPtTof, 4u == "maxPtTof" + selectorProton[iChannel].setRangeNSigmaTpc(-config.selectionsPid->get(iChannel, 2u), config.selectionsPid->get(iChannel, 2u)); // 2u == "nSigmaMaxTpc" + selectorProton[iChannel].setRangeNSigmaTof(-config.selectionsPid->get(iChannel, 5u), config.selectionsPid->get(iChannel, 5u)); // 5u == "nSigmaMaxTof" } // after the proton PID we have the kaon PID - selectorKaon.setRangePtTpc(selectionsPid->get(channelKaonPid, 0u), selectionsPid->get(channelKaonPid, 1u)); // 0u == "minPtTpc", 1u == "maxPtTpc" - selectorKaon.setRangePtTof(selectionsPid->get(channelKaonPid, 3u), selectionsPid->get(channelKaonPid, 4u)); // 3u == "minPtTof, 4u == "maxPtTof" - selectorKaon.setRangeNSigmaTpc(-selectionsPid->get(channelKaonPid, 2u), selectionsPid->get(channelKaonPid, 2u)); // 2u == "nSigmaMaxTpc" - selectorKaon.setRangeNSigmaTof(-selectionsPid->get(channelKaonPid, 5u), selectionsPid->get(channelKaonPid, 5u)); // 5u == "nSigmaMaxTof" + selectorKaon.setRangePtTpc(config.selectionsPid->get(ChannelKaonPid, 0u), config.selectionsPid->get(ChannelKaonPid, 1u)); // 0u == "minPtTpc", 1u == "maxPtTpc" + selectorKaon.setRangePtTof(config.selectionsPid->get(ChannelKaonPid, 3u), config.selectionsPid->get(ChannelKaonPid, 4u)); // 3u == "minPtTof, 4u == "maxPtTof" + selectorKaon.setRangeNSigmaTpc(-config.selectionsPid->get(ChannelKaonPid, 2u), config.selectionsPid->get(ChannelKaonPid, 2u)); // 2u == "nSigmaMaxTpc" + selectorKaon.setRangeNSigmaTof(-config.selectionsPid->get(ChannelKaonPid, 5u), config.selectionsPid->get(ChannelKaonPid, 5u)); // 5u == "nSigmaMaxTof" } /// PID track cuts (for proton only) @@ -424,7 +413,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { for (auto iChannel{0u}; iChannel < ChannelsProtonPid::NChannelsProtonPid; ++iChannel) { statusPid[iChannel] = selectorProton[iChannel].statusTof(hfTrack); } - statusPid[channelKaonPid] = selectorKaon.statusTof(hfTrack); + statusPid[ChannelKaonPid] = selectorKaon.statusTof(hfTrack); } } if constexpr (pidStrategy == ProtonPidStrategy::PidTpcOnly) { @@ -432,20 +421,20 @@ struct HfTrackIndexSkimCreatorTagSelTracks { for (auto iChannel{0u}; iChannel < ChannelsProtonPid::NChannelsProtonPid; ++iChannel) { statusPid[iChannel] = selectorProton[iChannel].statusTpc(hfTrack); } - statusPid[channelKaonPid] = selectorKaon.statusTpc(hfTrack); + statusPid[ChannelKaonPid] = selectorKaon.statusTpc(hfTrack); } } if constexpr (pidStrategy == ProtonPidStrategy::PidTpcOrTof) { for (auto iChannel{0u}; iChannel < ChannelsProtonPid::NChannelsProtonPid; ++iChannel) { statusPid[iChannel] = selectorProton[iChannel].statusTpcOrTof(hfTrack); } - statusPid[channelKaonPid] = selectorKaon.statusTpcOrTof(hfTrack); + statusPid[ChannelKaonPid] = selectorKaon.statusTpcOrTof(hfTrack); } if constexpr (pidStrategy == ProtonPidStrategy::PidTpcAndTof) { for (auto iChannel{0u}; iChannel < ChannelsProtonPid::NChannelsProtonPid; ++iChannel) { statusPid[iChannel] = selectorProton[iChannel].statusTpcAndTof(hfTrack); } - statusPid[channelKaonPid] = selectorKaon.statusTpcAndTof(hfTrack); + statusPid[ChannelKaonPid] = selectorKaon.statusTpcAndTof(hfTrack); } int8_t flag = BIT(ChannelsProtonPid::NChannelsProtonPid + 1) - 1; // all bits on (including the kaon one) @@ -467,76 +456,76 @@ struct HfTrackIndexSkimCreatorTagSelTracks { template void isSelectedTrack(const T& hfTrack, const float& trackPt, const float& trackEta, const std::array& dca, int& statusProng) { - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hPtNoCuts"), trackPt); } int iCut{2}; // pT cut - if (trackPt < ptMinTrack2Prong) { + if (trackPt < config.ptMinTrack2Prong) { CLRBIT(statusProng, CandidateType::Cand2Prong); // set the nth bit to 0 - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hRejTracks"), (nCuts + 1) * CandidateType::Cand2Prong + iCut); } } - if (trackPt < ptMinTrack3Prong) { + if (trackPt < config.ptMinTrack3Prong) { CLRBIT(statusProng, CandidateType::Cand3Prong); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hRejTracks"), (nCuts + 1) * CandidateType::Cand3Prong + iCut); } } - if (trackPt < ptMinTrackBach) { + if (trackPt < config.ptMinTrackBach) { CLRBIT(statusProng, CandidateType::CandV0bachelor); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hRejTracks"), (nCuts + 1) * CandidateType::CandV0bachelor + iCut); } } - if (trackPt < ptMinSoftPionForDstar) { + if (trackPt < config.ptMinSoftPionForDstar) { CLRBIT(statusProng, CandidateType::CandDstar); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hRejTracks"), (nCuts + 1) * CandidateType::CandDstar + iCut); } } - if (trackPt < ptMinTrackBachLfCasc) { + if (trackPt < config.ptMinTrackBachLfCasc) { CLRBIT(statusProng, CandidateType::CandCascadeBachelor); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hRejTracks"), (nCuts + 1) * CandidateType::CandCascadeBachelor + iCut); } } iCut = 3; // eta cut - if (TESTBIT(statusProng, CandidateType::Cand2Prong) && (trackEta > etaMaxTrack2Prong || trackEta < etaMinTrack2Prong)) { + if (TESTBIT(statusProng, CandidateType::Cand2Prong) && (trackEta > config.etaMaxTrack2Prong || trackEta < config.etaMinTrack2Prong)) { CLRBIT(statusProng, CandidateType::Cand2Prong); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hRejTracks"), (nCuts + 1) * CandidateType::Cand2Prong + iCut); } } - if (TESTBIT(statusProng, CandidateType::Cand3Prong) && (trackEta > etaMaxTrack3Prong || trackEta < etaMinTrack3Prong)) { + if (TESTBIT(statusProng, CandidateType::Cand3Prong) && (trackEta > config.etaMaxTrack3Prong || trackEta < config.etaMinTrack3Prong)) { CLRBIT(statusProng, CandidateType::Cand3Prong); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hRejTracks"), (nCuts + 1) * CandidateType::Cand3Prong + iCut); } } - if (TESTBIT(statusProng, CandidateType::CandV0bachelor) && (trackEta > etaMaxTrackBach || trackEta < etaMinTrackBach)) { + if (TESTBIT(statusProng, CandidateType::CandV0bachelor) && (trackEta > config.etaMaxTrackBach || trackEta < config.etaMinTrackBach)) { CLRBIT(statusProng, CandidateType::CandV0bachelor); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hRejTracks"), (nCuts + 1) * CandidateType::CandV0bachelor + iCut); } } - if (TESTBIT(statusProng, CandidateType::CandDstar) && (trackEta > etaMaxSoftPionForDstar || trackEta < etaMinSoftPionForDstar)) { + if (TESTBIT(statusProng, CandidateType::CandDstar) && (trackEta > config.etaMaxSoftPionForDstar || trackEta < config.etaMinSoftPionForDstar)) { CLRBIT(statusProng, CandidateType::CandDstar); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hRejTracks"), (nCuts + 1) * CandidateType::CandDstar + iCut); } } - if (TESTBIT(statusProng, CandidateType::CandCascadeBachelor) && (trackEta > etaMaxTrackBachLfCasc || trackEta < etaMinTrackBachLfCasc)) { + if (TESTBIT(statusProng, CandidateType::CandCascadeBachelor) && (trackEta > config.etaMaxTrackBachLfCasc || trackEta < config.etaMinTrackBachLfCasc)) { CLRBIT(statusProng, CandidateType::CandCascadeBachelor); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hRejTracks"), (nCuts + 1) * CandidateType::CandCascadeBachelor + iCut); } } @@ -544,18 +533,18 @@ struct HfTrackIndexSkimCreatorTagSelTracks { // quality cut iCut = 4; bool hasGoodQuality = true; - if (doCutQuality.value && statusProng > 0) { // FIXME to make a more complete selection e.g track.flags() & o2::aod::track::TPCrefit && track.flags() & o2::aod::track::GoldenChi2 && - if (useIsGlobalTrack) { + if (config.doCutQuality.value && statusProng > 0) { // FIXME to make a more complete selection e.g track.flags() & o2::aod::track::TPCrefit && track.flags() & o2::aod::track::GoldenChi2 && + if (config.useIsGlobalTrack) { if (!hfTrack.isGlobalTrack()) { hasGoodQuality = false; } - } else if (useIsGlobalTrackWoDCA) { + } else if (config.useIsGlobalTrackWoDCA) { if (!hfTrack.isGlobalTrackWoDCA()) { hasGoodQuality = false; } } else { UChar_t clustermap = hfTrack.itsClusterMap(); - if (!(hfTrack.tpcNClsFound() >= tpcNClsFoundMin.value && // is this the number of TPC clusters? It should not be used + if (!(hfTrack.tpcNClsFound() >= config.tpcNClsFoundMin.value && // is this the number of TPC clusters? It should not be used TESTBIT(hfTrack.flags(), o2::aod::track::ITSrefit) && (TESTBIT(clustermap, 0) || TESTBIT(clustermap, 1)))) { hasGoodQuality = false; @@ -567,7 +556,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { continue; } CLRBIT(statusProng, iCandType); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hRejTracks"), (nCuts + 1) * iCandType + iCut); } } @@ -576,16 +565,16 @@ struct HfTrackIndexSkimCreatorTagSelTracks { // quality cut for soft pion hasGoodQuality = true; - if (doCutQuality.value && TESTBIT(statusProng, CandidateType::CandDstar)) { - if (useIsGlobalTrackForSoftPion) { + if (config.doCutQuality.value && TESTBIT(statusProng, CandidateType::CandDstar)) { + if (config.useIsGlobalTrackForSoftPion) { if (!hfTrack.isGlobalTrack()) { hasGoodQuality = false; } - } else if (useIsGlobalTrackWoDCAForSoftPion) { + } else if (config.useIsGlobalTrackWoDCAForSoftPion) { if (!hfTrack.isGlobalTrackWoDCA()) { hasGoodQuality = false; } - } else if (useIsQualityTrackITSForSoftPion) { + } else if (config.useIsQualityTrackITSForSoftPion) { if (!hfTrack.isQualityTrackITS()) { hasGoodQuality = false; } @@ -597,7 +586,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { } if (!hasGoodQuality) { CLRBIT(statusProng, CandidateType::CandDstar); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hRejTracks"), (nCuts + 1) * CandidateType::CandDstar + iCut); } } @@ -605,16 +594,16 @@ struct HfTrackIndexSkimCreatorTagSelTracks { // quality cut for bachelor in cascade + bachelor decays hasGoodQuality = true; - if (doCutQuality.value && TESTBIT(statusProng, CandidateType::CandCascadeBachelor)) { - if (useIsGlobalTrackForBachLfCasc) { + if (config.doCutQuality.value && TESTBIT(statusProng, CandidateType::CandCascadeBachelor)) { + if (config.useIsGlobalTrackForBachLfCasc) { if (!hfTrack.isGlobalTrack()) { hasGoodQuality = false; } - } else if (useIsGlobalTrackWoDCAForBachLfCasc) { + } else if (config.useIsGlobalTrackWoDCAForBachLfCasc) { if (!hfTrack.isGlobalTrackWoDCA()) { hasGoodQuality = false; } - } else if (useIsQualityTrackITSForBachLfCasc) { + } else if (config.useIsQualityTrackITSForBachLfCasc) { if (!hfTrack.isQualityTrackITS()) { hasGoodQuality = false; } @@ -626,7 +615,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { } if (!hasGoodQuality) { CLRBIT(statusProng, CandidateType::CandCascadeBachelor); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hRejTracks"), (nCuts + 1) * CandidateType::CandCascadeBachelor + iCut); } } @@ -636,9 +625,9 @@ struct HfTrackIndexSkimCreatorTagSelTracks { iCut = 5; if (statusProng > 0) { for (int iCandType = 0; iCandType < CandidateType::NCandidateTypes; ++iCandType) { - if (TESTBIT(statusProng, iCandType) && !isSelectedTrackDcaXY(binsPtTrack, &cutsSingleTrack[iCandType], trackPt, dca[0])) { + if (TESTBIT(statusProng, iCandType) && !isSelectedTrackDca(config.binsPtTrack, &cutsSingleTrack[iCandType], trackPt, dca[0], dca[1])) { CLRBIT(statusProng, iCandType); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hRejTracks"), (nCuts + 1) * iCandType + iCut); } } @@ -646,7 +635,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { } // fill histograms - if (fillHistograms) { + if (config.fillHistograms) { iCut = 1; if (TESTBIT(statusProng, CandidateType::Cand2Prong)) { registry.fill(HIST("hPtCuts2Prong"), trackPt); @@ -705,7 +694,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { /// Prepare the vertex refitting // set the magnetic field from CCDB auto bc = collision.bc_as(); - initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, lut, isRun2); + initCCDB(bc, runNumber, ccdb, config.isRun2 ? config.ccdbPathGrp : config.ccdbPathGrpMag, lut, config.isRun2); /*if (runNumber != bc.runNumber()) { if (isRun2) { // Run 2 GRP object @@ -744,15 +733,15 @@ struct HfTrackIndexSkimCreatorTagSelTracks { bool pvRefitDoable = vertexer.prepareVertexRefit(vecPvContributorTrackParCov, primVtx); if (!pvRefitDoable) { LOG(info) << "Not enough tracks accepted for the refit"; - if (doPvRefit && fillHistograms) { + if (config.doPvRefit && config.fillHistograms) { registry.fill(HIST("PvRefit/hNContribPvRefitNotDoable"), collision.numContrib()); } } - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "prepareVertexRefit = " << pvRefitDoable << " Ncontrib= " << vecPvContributorTrackParCov.size() << " Ntracks= " << collision.numContrib() << " Vtx= " << primVtx.asString(); } - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("PvRefit/hVerticesPerTrack"), 1); if (pvRefitDoable) { registry.fill(HIST("PvRefit/hVerticesPerTrack"), 2); @@ -761,7 +750,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { /// PV refitting, if the tracks contributed to this at the beginning o2::dataformats::VertexBase primVtxBaseRecalc; bool recalcImpPar = false; - if (doPvRefit && pvRefitDoable) { + if (config.doPvRefit && pvRefitDoable) { recalcImpPar = true; auto trackIterator = std::find(vecPvContributorGlobId.begin(), vecPvContributorGlobId.end(), trackToRemove.globalIndex()); /// track global index if (trackIterator != vecPvContributorGlobId.end()) { @@ -773,24 +762,24 @@ struct HfTrackIndexSkimCreatorTagSelTracks { auto primVtxRefitted = vertexer.refitVertex(vecPvRefitContributorUsed, primVtx); // vertex refit // LOG(info) << "refit " << cnt << "/" << ntr << " result = " << primVtxRefitted.asString(); - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "refit for track with global index " << static_cast(trackToRemove.globalIndex()) << " " << primVtxRefitted.asString(); } if (primVtxRefitted.getChi2() < 0) { - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "---> Refitted vertex has bad chi2 = " << primVtxRefitted.getChi2(); } - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("PvRefit/hPvRefitXChi2Minus1"), primVtxRefitted.getX(), collision.posX()); registry.fill(HIST("PvRefit/hPvRefitYChi2Minus1"), primVtxRefitted.getY(), collision.posY()); registry.fill(HIST("PvRefit/hPvRefitZChi2Minus1"), primVtxRefitted.getZ(), collision.posZ()); registry.fill(HIST("PvRefit/hNContribPvRefitChi2Minus1"), collision.numContrib()); } recalcImpPar = false; - } else if (fillHistograms) { + } else if (config.fillHistograms) { registry.fill(HIST("PvRefit/hVerticesPerTrack"), 3); } - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("PvRefit/hChi2vsNContrib"), primVtxRefitted.getNContributors(), primVtxRefitted.getChi2()); } @@ -801,7 +790,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { const double deltaX = primVtx.getX() - primVtxRefitted.getX(); const double deltaY = primVtx.getY() - primVtxRefitted.getY(); const double deltaZ = primVtx.getZ() - primVtxRefitted.getZ(); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("PvRefit/hPvDeltaXvsNContrib"), primVtxRefitted.getNContributors(), deltaX); registry.fill(HIST("PvRefit/hPvDeltaYvsNContrib"), primVtxRefitted.getNContributors(), deltaY); registry.fill(HIST("PvRefit/hPvDeltaZvsNContrib"), primVtxRefitted.getNContributors(), deltaZ); @@ -898,7 +887,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { std::array pvRefitPvCovMatrix{1e10f, 1e10f, 1e10f, 1e10f, 1e10f, 1e10f}; // PV refit and DCA recalculation only for tracks with an assigned collision - if (doPvRefit && track.has_collision() && track.collisionId() == thisCollId && track.isPVContributor()) { + if (config.doPvRefit && track.has_collision() && track.collisionId() == thisCollId && track.isPVContributor()) { pvRefitPvCoord = {collision.posX(), collision.posY(), collision.posZ()}; pvRefitPvCovMatrix = {collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}; @@ -910,12 +899,12 @@ struct HfTrackIndexSkimCreatorTagSelTracks { vecPvContributorGlobId.push_back(contributor.globalIndex()); vecPvContributorTrackParCov.push_back(getTrackParCov(contributor)); } - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "### vecPvContributorGlobId.size()=" << vecPvContributorGlobId.size() << ", vecPvContributorTrackParCov.size()=" << vecPvContributorTrackParCov.size() << ", N. original contributors=" << collision.numContrib(); } /// Perform the PV refit only for tracks with an assigned collision - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "[BEFORE performPvRefitTrack] track.collision().globalIndex(): " << collision.globalIndex(); } performPvRefitTrack(collision, bcWithTimeStamps, vecPvContributorGlobId, vecPvContributorTrackParCov, track, pvRefitPvCoord, pvRefitPvCovMatrix, pvRefitDcaXYDcaZ); @@ -925,7 +914,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { pvRefitPvCovMatrixPerTrack[trackIdx] = pvRefitPvCovMatrix; } else if (track.collisionId() != thisCollId) { auto bc = collision.bc_as(); - initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, lut, isRun2); + initCCDB(bc, runNumber, ccdb, config.isRun2 ? config.ccdbPathGrp : config.ccdbPathGrpMag, lut, config.isRun2); auto trackPar = getTrackPar(track); o2::gpu::gpustd::array dcaInfo{-999., -999.}; o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPar, 2.f, noMatCorr, &dcaInfo); @@ -977,7 +966,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { std::vector> pvRefitDcaPerTrack{}; std::vector> pvRefitPvCoordPerTrack{}; std::vector> pvRefitPvCovMatrixPerTrack{}; - if (doPvRefit) { + if (config.doPvRefit) { auto numTracks = tracks.size(); pvRefitDcaPerTrack.resize(numTracks); pvRefitPvCoordPerTrack.resize(numTracks); @@ -992,7 +981,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { runTagSelTracks(collision, tracks, groupedTrackIndices, pvContrCollision, bcWithTimeStamps, pvRefitDcaPerTrack, pvRefitPvCoordPerTrack, pvRefitPvCovMatrixPerTrack); } - if (doPvRefit) { /// fill table with PV refit info (it has to be filled per track and not track index) + if (config.doPvRefit) { /// fill table with PV refit info (it has to be filled per track and not track index) fillPvRefitTable(pvRefitDcaPerTrack, pvRefitPvCoordPerTrack, pvRefitPvCovMatrixPerTrack); } } @@ -1008,7 +997,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { std::vector> pvRefitDcaPerTrack{}; std::vector> pvRefitPvCoordPerTrack{}; std::vector> pvRefitPvCovMatrixPerTrack{}; - if (doPvRefit) { + if (config.doPvRefit) { auto numTracks = tracks.size(); pvRefitDcaPerTrack.resize(numTracks); pvRefitPvCoordPerTrack.resize(numTracks); @@ -1023,7 +1012,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { runTagSelTracks(collision, tracks, groupedTrackIndices, pvContrCollision, bcWithTimeStamps, pvRefitDcaPerTrack, pvRefitPvCoordPerTrack, pvRefitPvCovMatrixPerTrack); } - if (doPvRefit) { /// fill table with PV refit info (it has to be filled per track and not track index) + if (config.doPvRefit) { /// fill table with PV refit info (it has to be filled per track and not track index) fillPvRefitTable(pvRefitDcaPerTrack, pvRefitPvCoordPerTrack, pvRefitPvCovMatrixPerTrack); } } @@ -1039,7 +1028,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { std::vector> pvRefitDcaPerTrack{}; std::vector> pvRefitPvCoordPerTrack{}; std::vector> pvRefitPvCovMatrixPerTrack{}; - if (doPvRefit) { + if (config.doPvRefit) { auto numTracks = tracks.size(); pvRefitDcaPerTrack.resize(numTracks); pvRefitPvCoordPerTrack.resize(numTracks); @@ -1054,7 +1043,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { runTagSelTracks(collision, tracks, groupedTrackIndices, pvContrCollision, bcWithTimeStamps, pvRefitDcaPerTrack, pvRefitPvCoordPerTrack, pvRefitPvCovMatrixPerTrack); } - if (doPvRefit) { /// fill table with PV refit info (it has to be filled per track and not track index) + if (config.doPvRefit) { /// fill table with PV refit info (it has to be filled per track and not track index) fillPvRefitTable(pvRefitDcaPerTrack, pvRefitPvCoordPerTrack, pvRefitPvCovMatrixPerTrack); } } @@ -1070,7 +1059,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { std::vector> pvRefitDcaPerTrack{}; std::vector> pvRefitPvCoordPerTrack{}; std::vector> pvRefitPvCovMatrixPerTrack{}; - if (doPvRefit) { + if (config.doPvRefit) { auto numTracks = tracks.size(); pvRefitDcaPerTrack.resize(numTracks); pvRefitPvCoordPerTrack.resize(numTracks); @@ -1085,7 +1074,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { runTagSelTracks(collision, tracks, groupedTrackIndices, pvContrCollision, bcWithTimeStamps, pvRefitDcaPerTrack, pvRefitPvCoordPerTrack, pvRefitPvCovMatrixPerTrack); } - if (doPvRefit) { /// fill table with PV refit info (it has to be filled per track and not track index) + if (config.doPvRefit) { /// fill table with PV refit info (it has to be filled per track and not track index) fillPvRefitTable(pvRefitDcaPerTrack, pvRefitPvCoordPerTrack, pvRefitPvCovMatrixPerTrack); } } @@ -1101,7 +1090,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { std::vector> pvRefitDcaPerTrack{}; std::vector> pvRefitPvCoordPerTrack{}; std::vector> pvRefitPvCovMatrixPerTrack{}; - if (doPvRefit) { + if (config.doPvRefit) { auto numTracks = tracks.size(); pvRefitDcaPerTrack.resize(numTracks); pvRefitPvCoordPerTrack.resize(numTracks); @@ -1116,7 +1105,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { runTagSelTracks(collision, tracks, groupedTrackIndices, pvContrCollision, bcWithTimeStamps, pvRefitDcaPerTrack, pvRefitPvCoordPerTrack, pvRefitPvCovMatrixPerTrack); } - if (doPvRefit) { /// fill table with PV refit info (it has to be filled per track and not track index) + if (config.doPvRefit) { /// fill table with PV refit info (it has to be filled per track and not track index) fillPvRefitTable(pvRefitDcaPerTrack, pvRefitPvCoordPerTrack, pvRefitPvCovMatrixPerTrack); } } @@ -1140,76 +1129,78 @@ struct HfTrackIndexSkimCreator { Produces rowTrackIndexMlScoreProng2; Produces rowTrackIndexMlScoreProng3; - Configurable isRun2{"isRun2", false, "enable Run 2 or Run 3 GRP objects for magnetic field"}; - Configurable do3Prong{"do3Prong", 0, "do 3 prong"}; - Configurable doDstar{"doDstar", false, "do D* candidates"}; - Configurable debug{"debug", false, "debug mode"}; - Configurable debugPvRefit{"debugPvRefit", false, "debug lines for primary vertex refit"}; - Configurable fillHistograms{"fillHistograms", true, "fill histograms"}; - // Configurable nCollsMax{"nCollsMax", -1, "Max collisions per file"}; //can be added to run over limited collisions per file - for tesing purposes - // preselection - Configurable ptTolerance{"ptTolerance", 0.1, "pT tolerance in GeV/c for applying preselections before vertex reconstruction"}; - // preselection of 3-prongs using the decay length computed only with the first two tracks - Configurable minTwoTrackDecayLengthFor3Prongs{"minTwoTrackDecayLengthFor3Prongs", 0., "Minimum decay length computed with 2 tracks for 3-prongs to speedup combinatorial"}; - Configurable maxTwoTrackChi2PcaFor3Prongs{"maxTwoTrackChi2PcaFor3Prongs", 1.e10, "Maximum chi2 pca computed with 2 tracks for 3-prongs to speedup combinatorial"}; - // vertexing - // Configurable bz{"bz", 5., "magnetic field kG"}; - Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; - Configurable useAbsDCA{"useAbsDCA", false, "Minimise abs. distance rather than chi2"}; - Configurable useWeightedFinalPCA{"useWeightedFinalPCA", false, "Recalculate vertex position using track covariances, effective only if useAbsDCA is true"}; - Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; - Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; - Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; - Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations if chi2/chi2old > this"}; - // CCDB - Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; - Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; - Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; - - // D0 cuts - Configurable> binsPtD0ToPiK{"binsPtD0ToPiK", std::vector{hf_cuts_presel_2prong::vecBinsPt}, "pT bin limits for D0->piK pT-dependent cuts"}; - Configurable> cutsD0ToPiK{"cutsD0ToPiK", {hf_cuts_presel_2prong::cuts[0], hf_cuts_presel_2prong::nBinsPt, hf_cuts_presel_2prong::nCutVars, hf_cuts_presel_2prong::labelsPt, hf_cuts_presel_2prong::labelsCutVar}, "D0->piK selections per pT bin"}; - // Jpsi -> ee cuts - Configurable> binsPtJpsiToEE{"binsPtJpsiToEE", std::vector{hf_cuts_presel_2prong::vecBinsPt}, "pT bin limits for Jpsi->ee pT-dependent cuts"}; - Configurable> cutsJpsiToEE{"cutsJpsiToEE", {hf_cuts_presel_2prong::cuts[0], hf_cuts_presel_2prong::nBinsPt, hf_cuts_presel_2prong::nCutVars, hf_cuts_presel_2prong::labelsPt, hf_cuts_presel_2prong::labelsCutVar}, "Jpsi->ee selections per pT bin"}; - // Jpsi -> mumu cuts - Configurable> binsPtJpsiToMuMu{"binsPtJpsiToMuMu", std::vector{hf_cuts_presel_2prong::vecBinsPt}, "pT bin limits for Jpsi->mumu pT-dependent cuts"}; - Configurable> cutsJpsiToMuMu{"cutsJpsiToMuMu", {hf_cuts_presel_2prong::cuts[0], hf_cuts_presel_2prong::nBinsPt, hf_cuts_presel_2prong::nCutVars, hf_cuts_presel_2prong::labelsPt, hf_cuts_presel_2prong::labelsCutVar}, "Jpsi->mumu selections per pT bin"}; - // D+ cuts - Configurable> binsPtDplusToPiKPi{"binsPtDplusToPiKPi", std::vector{hf_cuts_presel_3prong::vecBinsPt}, "pT bin limits for D+->piKpi pT-dependent cuts"}; - Configurable> cutsDplusToPiKPi{"cutsDplusToPiKPi", {hf_cuts_presel_3prong::cuts[0], hf_cuts_presel_3prong::nBinsPt, hf_cuts_presel_3prong::nCutVars, hf_cuts_presel_3prong::labelsPt, hf_cuts_presel_3prong::labelsCutVar}, "D+->piKpi selections per pT bin"}; - // Ds+ cuts - Configurable> binsPtDsToKKPi{"binsPtDsToKKPi", std::vector{hf_cuts_presel_ds::vecBinsPt}, "pT bin limits for Ds+->KKPi pT-dependent cuts"}; - Configurable> cutsDsToKKPi{"cutsDsToKKPi", {hf_cuts_presel_ds::cuts[0], hf_cuts_presel_ds::nBinsPt, hf_cuts_presel_ds::nCutVars, hf_cuts_presel_ds::labelsPt, hf_cuts_presel_ds::labelsCutVar}, "Ds+->KKPi selections per pT bin"}; - // Lc+ cuts - Configurable> binsPtLcToPKPi{"binsPtLcToPKPi", std::vector{hf_cuts_presel_3prong::vecBinsPt}, "pT bin limits for Lc->pKpi pT-dependent cuts"}; - Configurable> cutsLcToPKPi{"cutsLcToPKPi", {hf_cuts_presel_3prong::cuts[0], hf_cuts_presel_3prong::nBinsPt, hf_cuts_presel_3prong::nCutVars, hf_cuts_presel_3prong::labelsPt, hf_cuts_presel_3prong::labelsCutVar}, "Lc->pKpi selections per pT bin"}; - // Xic+ cuts - Configurable> binsPtXicToPKPi{"binsPtXicToPKPi", std::vector{hf_cuts_presel_3prong::vecBinsPt}, "pT bin limits for Xic->pKpi pT-dependent cuts"}; - Configurable> cutsXicToPKPi{"cutsXicToPKPi", {hf_cuts_presel_3prong::cuts[0], hf_cuts_presel_3prong::nBinsPt, hf_cuts_presel_3prong::nCutVars, hf_cuts_presel_3prong::labelsPt, hf_cuts_presel_3prong::labelsCutVar}, "Xic->pKpi selections per pT bin"}; - // D*+ cuts - Configurable> binsPtDstarToD0Pi{"binsPtDstarToD0Pi", std::vector{hf_cuts_presel_dstar::vecBinsPt}, "pT bin limits for D*+->D0pi pT-dependent cuts"}; - Configurable> cutsDstarToD0Pi{"cutsDstarToD0Pi", {hf_cuts_presel_dstar::cuts[0], hf_cuts_presel_dstar::nBinsPt, hf_cuts_presel_dstar::nCutVars, hf_cuts_presel_dstar::labelsPt, hf_cuts_presel_dstar::labelsCutVar}, "D*+->D0pi selections per pT bin"}; - - // proton PID selections for Lc and Xic - Configurable applyProtonPidForLcToPKPi{"applyProtonPidForLcToPKPi", false, "Apply proton PID for Lc->pKpi"}; - Configurable applyProtonPidForXicToPKPi{"applyProtonPidForXicToPKPi", false, "Apply proton PID for Xic->pKpi"}; - Configurable applyKaonPidIn3Prongs{"applyKaonPidIn3Prongs", false, "Apply kaon PID for opposite-sign track in 3-prong and D* decays"}; - - // ML models for triggers - Configurable applyMlForHfFilters{"applyMlForHfFilters", false, "Flag to enable ML application for HF Filters"}; - Configurable mlModelPathCCDB{"mlModelPathCCDB", "EventFiltering/PWGHF/BDTSmeared", "Path on CCDB of ML models for HF Filters"}; - Configurable timestampCcdbForHfFilters{"timestampCcdbForHfFilters", 1657032422771, "timestamp of the ONNX file for ML model used to query in CCDB"}; - Configurable loadMlModelsFromCCDB{"loadMlModelsFromCCDB", true, "Flag to enable or disable the loading of ML models from CCDB"}; - - Configurable> onnxFileNames{"onnxFileNames", {hf_cuts_bdt_multiclass::onnxFileNameSpecies[0], 5, 1, hf_cuts_bdt_multiclass::labelsSpecies, hf_cuts_bdt_multiclass::labelsModels}, "ONNX file names for ML models"}; - - Configurable> thresholdMlScoreD0ToKPi{"thresholdMlScoreD0ToKPi", {hf_cuts_bdt_multiclass::cuts[0], hf_cuts_bdt_multiclass::nBinsPt, hf_cuts_bdt_multiclass::nCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for Ml output scores of D0 candidates"}; - Configurable> thresholdMlScoreDplusToPiKPi{"thresholdMlScoreDplusToPiKPi", {hf_cuts_bdt_multiclass::cuts[0], hf_cuts_bdt_multiclass::nBinsPt, hf_cuts_bdt_multiclass::nCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for Ml output scores of D+ candidates"}; - Configurable> thresholdMlScoreDsToPiKK{"thresholdMlScoreDsToPiKK", {hf_cuts_bdt_multiclass::cuts[0], hf_cuts_bdt_multiclass::nBinsPt, hf_cuts_bdt_multiclass::nCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for Ml output scores of Ds+ candidates"}; - Configurable> thresholdMlScoreLcToPiKP{"thresholdMlScoreLcToPiKP", {hf_cuts_bdt_multiclass::cuts[0], hf_cuts_bdt_multiclass::nBinsPt, hf_cuts_bdt_multiclass::nCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for Ml output scores of Lc+ candidates"}; - Configurable> thresholdMlScoreXicToPiKP{"thresholdMlScoreXicToPiKP", {hf_cuts_bdt_multiclass::cuts[0], hf_cuts_bdt_multiclass::nBinsPt, hf_cuts_bdt_multiclass::nCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for Ml output scores of Xic+ candidates"}; + struct : ConfigurableGroup { + Configurable isRun2{"isRun2", false, "enable Run 2 or Run 3 GRP objects for magnetic field"}; + Configurable do3Prong{"do3Prong", 0, "do 3 prong"}; + Configurable doDstar{"doDstar", false, "do D* candidates"}; + Configurable debug{"debug", false, "debug mode"}; + Configurable debugPvRefit{"debugPvRefit", false, "debug lines for primary vertex refit"}; + Configurable fillHistograms{"fillHistograms", true, "fill histograms"}; + // Configurable nCollsMax{"nCollsMax", -1, "Max collisions per file"}; //can be added to run over limited collisions per file - for tesing purposes + // preselection + Configurable ptTolerance{"ptTolerance", 0.1, "pT tolerance in GeV/c for applying preselections before vertex reconstruction"}; + // preselection of 3-prongs using the decay length computed only with the first two tracks + Configurable minTwoTrackDecayLengthFor3Prongs{"minTwoTrackDecayLengthFor3Prongs", 0., "Minimum decay length computed with 2 tracks for 3-prongs to speedup combinatorial"}; + Configurable maxTwoTrackChi2PcaFor3Prongs{"maxTwoTrackChi2PcaFor3Prongs", 1.e10, "Maximum chi2 pca computed with 2 tracks for 3-prongs to speedup combinatorial"}; + // vertexing + // Configurable bz{"bz", 5., "magnetic field kG"}; + Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; + Configurable useAbsDCA{"useAbsDCA", false, "Minimise abs. distance rather than chi2"}; + Configurable useWeightedFinalPCA{"useWeightedFinalPCA", false, "Recalculate vertex position using track covariances, effective only if useAbsDCA is true"}; + Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; + Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; + Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations if chi2/chi2old > this"}; + // CCDB + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; + Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + + // D0 cuts + Configurable> binsPtD0ToPiK{"binsPtD0ToPiK", std::vector{hf_cuts_presel_2prong::vecBinsPt}, "pT bin limits for D0->piK pT-dependent cuts"}; + Configurable> cutsD0ToPiK{"cutsD0ToPiK", {hf_cuts_presel_2prong::Cuts[0], hf_cuts_presel_2prong::NBinsPt, hf_cuts_presel_2prong::NCutVars, hf_cuts_presel_2prong::labelsPt, hf_cuts_presel_2prong::labelsCutVar}, "D0->piK selections per pT bin"}; + // Jpsi -> ee cuts + Configurable> binsPtJpsiToEE{"binsPtJpsiToEE", std::vector{hf_cuts_presel_2prong::vecBinsPt}, "pT bin limits for Jpsi->ee pT-dependent cuts"}; + Configurable> cutsJpsiToEE{"cutsJpsiToEE", {hf_cuts_presel_2prong::Cuts[0], hf_cuts_presel_2prong::NBinsPt, hf_cuts_presel_2prong::NCutVars, hf_cuts_presel_2prong::labelsPt, hf_cuts_presel_2prong::labelsCutVar}, "Jpsi->ee selections per pT bin"}; + // Jpsi -> mumu cuts + Configurable> binsPtJpsiToMuMu{"binsPtJpsiToMuMu", std::vector{hf_cuts_presel_2prong::vecBinsPt}, "pT bin limits for Jpsi->mumu pT-dependent cuts"}; + Configurable> cutsJpsiToMuMu{"cutsJpsiToMuMu", {hf_cuts_presel_2prong::Cuts[0], hf_cuts_presel_2prong::NBinsPt, hf_cuts_presel_2prong::NCutVars, hf_cuts_presel_2prong::labelsPt, hf_cuts_presel_2prong::labelsCutVar}, "Jpsi->mumu selections per pT bin"}; + // D+ cuts + Configurable> binsPtDplusToPiKPi{"binsPtDplusToPiKPi", std::vector{hf_cuts_presel_3prong::vecBinsPt}, "pT bin limits for D+->piKpi pT-dependent cuts"}; + Configurable> cutsDplusToPiKPi{"cutsDplusToPiKPi", {hf_cuts_presel_3prong::Cuts[0], hf_cuts_presel_3prong::NBinsPt, hf_cuts_presel_3prong::NCutVars, hf_cuts_presel_3prong::labelsPt, hf_cuts_presel_3prong::labelsCutVar}, "D+->piKpi selections per pT bin"}; + // Ds+ cuts + Configurable> binsPtDsToKKPi{"binsPtDsToKKPi", std::vector{hf_cuts_presel_ds::vecBinsPt}, "pT bin limits for Ds+->KKPi pT-dependent cuts"}; + Configurable> cutsDsToKKPi{"cutsDsToKKPi", {hf_cuts_presel_ds::Cuts[0], hf_cuts_presel_ds::NBinsPt, hf_cuts_presel_ds::NCutVars, hf_cuts_presel_ds::labelsPt, hf_cuts_presel_ds::labelsCutVar}, "Ds+->KKPi selections per pT bin"}; + // Lc+ cuts + Configurable> binsPtLcToPKPi{"binsPtLcToPKPi", std::vector{hf_cuts_presel_3prong::vecBinsPt}, "pT bin limits for Lc->pKpi pT-dependent cuts"}; + Configurable> cutsLcToPKPi{"cutsLcToPKPi", {hf_cuts_presel_3prong::Cuts[0], hf_cuts_presel_3prong::NBinsPt, hf_cuts_presel_3prong::NCutVars, hf_cuts_presel_3prong::labelsPt, hf_cuts_presel_3prong::labelsCutVar}, "Lc->pKpi selections per pT bin"}; + // Xic+ cuts + Configurable> binsPtXicToPKPi{"binsPtXicToPKPi", std::vector{hf_cuts_presel_3prong::vecBinsPt}, "pT bin limits for Xic->pKpi pT-dependent cuts"}; + Configurable> cutsXicToPKPi{"cutsXicToPKPi", {hf_cuts_presel_3prong::Cuts[0], hf_cuts_presel_3prong::NBinsPt, hf_cuts_presel_3prong::NCutVars, hf_cuts_presel_3prong::labelsPt, hf_cuts_presel_3prong::labelsCutVar}, "Xic->pKpi selections per pT bin"}; + // D*+ cuts + Configurable> binsPtDstarToD0Pi{"binsPtDstarToD0Pi", std::vector{hf_cuts_presel_dstar::vecBinsPt}, "pT bin limits for D*+->D0pi pT-dependent cuts"}; + Configurable> cutsDstarToD0Pi{"cutsDstarToD0Pi", {hf_cuts_presel_dstar::Cuts[0], hf_cuts_presel_dstar::NBinsPt, hf_cuts_presel_dstar::NCutVars, hf_cuts_presel_dstar::labelsPt, hf_cuts_presel_dstar::labelsCutVar}, "D*+->D0pi selections per pT bin"}; + + // proton PID selections for Lc and Xic + Configurable applyProtonPidForLcToPKPi{"applyProtonPidForLcToPKPi", false, "Apply proton PID for Lc->pKpi"}; + Configurable applyProtonPidForXicToPKPi{"applyProtonPidForXicToPKPi", false, "Apply proton PID for Xic->pKpi"}; + Configurable applyKaonPidIn3Prongs{"applyKaonPidIn3Prongs", false, "Apply kaon PID for opposite-sign track in 3-prong and D* decays"}; + + // ML models for triggers + Configurable applyMlForHfFilters{"applyMlForHfFilters", false, "Flag to enable ML application for HF Filters"}; + Configurable mlModelPathCCDB{"mlModelPathCCDB", "EventFiltering/PWGHF/BDTSmeared", "Path on CCDB of ML models for HF Filters"}; + Configurable timestampCcdbForHfFilters{"timestampCcdbForHfFilters", 1657032422771, "timestamp of the ONNX file for ML model used to query in CCDB"}; + Configurable loadMlModelsFromCCDB{"loadMlModelsFromCCDB", true, "Flag to enable or disable the loading of ML models from CCDB"}; + + Configurable> onnxFileNames{"onnxFileNames", {hf_cuts_bdt_multiclass::onnxFileNameSpecies[0], 5, 1, hf_cuts_bdt_multiclass::labelsSpecies, hf_cuts_bdt_multiclass::labelsModels}, "ONNX file names for ML models"}; + + Configurable> thresholdMlScoreD0ToKPi{"thresholdMlScoreD0ToKPi", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for Ml output scores of D0 candidates"}; + Configurable> thresholdMlScoreDplusToPiKPi{"thresholdMlScoreDplusToPiKPi", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for Ml output scores of D+ candidates"}; + Configurable> thresholdMlScoreDsToPiKK{"thresholdMlScoreDsToPiKK", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for Ml output scores of Ds+ candidates"}; + Configurable> thresholdMlScoreLcToPiKP{"thresholdMlScoreLcToPiKP", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for Ml output scores of Lc+ candidates"}; + Configurable> thresholdMlScoreXicToPiKP{"thresholdMlScoreXicToPiKP", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for Ml output scores of Xic+ candidates"}; + } config; SliceCache cache; o2::vertexing::DCAFitterN<2> df2; // 2-prong vertex fitter @@ -1232,8 +1223,8 @@ struct HfTrackIndexSkimCreator { static constexpr int kN2ProngDecays = hf_cand_2prong::DecayType::N2ProngDecays; // number of 2-prong hadron types static constexpr int kN3ProngDecays = hf_cand_3prong::DecayType::N3ProngDecays; // number of 3-prong hadron types - static constexpr int kNCuts2Prong[kN2ProngDecays] = {hf_cuts_presel_2prong::nCutVars, hf_cuts_presel_2prong::nCutVars, hf_cuts_presel_2prong::nCutVars}; // how many different selections are made on 2-prongs - static constexpr int kNCuts3Prong[kN3ProngDecays] = {hf_cuts_presel_3prong::nCutVars, hf_cuts_presel_3prong::nCutVars + 1, hf_cuts_presel_ds::nCutVars, hf_cuts_presel_3prong::nCutVars + 1}; // how many different selections are made on 3-prongs (Lc and Xic have also PID potentially) + static constexpr int kNCuts2Prong[kN2ProngDecays] = {hf_cuts_presel_2prong::NCutVars, hf_cuts_presel_2prong::NCutVars, hf_cuts_presel_2prong::NCutVars}; // how many different selections are made on 2-prongs + static constexpr int kNCuts3Prong[kN3ProngDecays] = {hf_cuts_presel_3prong::NCutVars, hf_cuts_presel_3prong::NCutVars + 1, hf_cuts_presel_ds::NCutVars, hf_cuts_presel_3prong::NCutVars + 1}; // how many different selections are made on 3-prongs (Lc and Xic have also PID potentially) static constexpr int kNCutsDstar = 3; // how many different selections are made on Dstars std::array, 2>, kN2ProngDecays> arrMass2Prong; std::array, 2>, kN3ProngDecays> arrMass3Prong; @@ -1255,13 +1246,12 @@ struct HfTrackIndexSkimCreator { // filter collisions Filter filterSelectCollisions = (aod::hf_sel_collision::whyRejectColl == static_cast(0)); - - // define slice of track indices per collisions - Preslice tracksPerCollision = aod::track::collisionId; // needed for PV refit - // filter track indices Filter filterSelectTrackIds = ((aod::hf_sel_track::isSelProng & static_cast(BIT(CandidateType::Cand2Prong))) != 0u) || ((aod::hf_sel_track::isSelProng & static_cast(BIT(CandidateType::Cand3Prong))) != 0u) || ((aod::hf_sel_track::isSelProng & static_cast(BIT(CandidateType::CandDstar))) != 0u); + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + // define slice of track indices per collisions + Preslice tracksPerCollision = aod::track::collisionId; // needed for PV refit // define partitions Partition positiveFor2And3Prongs = aod::hf_sel_track::isPositive == true && (((aod::hf_sel_track::isSelProng & static_cast(BIT(CandidateType::Cand2Prong))) != 0u) || ((aod::hf_sel_track::isSelProng & static_cast(BIT(CandidateType::Cand3Prong))) != 0u)); @@ -1278,7 +1268,7 @@ struct HfTrackIndexSkimCreator { void init(InitContext const&) { - if (!doprocess2And3ProngsWithPvRefit && !doprocess2And3ProngsNoPvRefit) { + if (!doprocess2And3ProngsWithPvRefit && !doprocess2And3ProngsNoPvRefit && !doprocess2And3ProngsWithPvRefitWithPidForHfFiltersBdt && !doprocess2And3ProngsNoPvRefitWithPidForHfFiltersBdt) { return; } @@ -1312,61 +1302,61 @@ struct HfTrackIndexSkimCreator { std::array{massPi, massK, massProton}}; // cuts for 2-prong decays retrieved by json. the order must be then one in hf_cand_2prong::DecayType - cut2Prong = {cutsD0ToPiK, cutsJpsiToEE, cutsJpsiToMuMu}; - pTBins2Prong = {binsPtD0ToPiK, binsPtJpsiToEE, binsPtJpsiToMuMu}; + cut2Prong = {config.cutsD0ToPiK, config.cutsJpsiToEE, config.cutsJpsiToMuMu}; + pTBins2Prong = {config.binsPtD0ToPiK, config.binsPtJpsiToEE, config.binsPtJpsiToMuMu}; // cuts for 3-prong decays retrieved by json. the order must be then one in hf_cand_3prong::DecayType - cut3Prong = {cutsDplusToPiKPi, cutsLcToPKPi, cutsDsToKKPi, cutsXicToPKPi}; - pTBins3Prong = {binsPtDplusToPiKPi, binsPtLcToPKPi, binsPtDsToKKPi, binsPtXicToPKPi}; - - df2.setPropagateToPCA(propagateToPCA); - df2.setMaxR(maxR); - df2.setMaxDZIni(maxDZIni); - df2.setMinParamChange(minParamChange); - df2.setMinRelChi2Change(minRelChi2Change); - df2.setUseAbsDCA(useAbsDCA); - df2.setWeightedFinalPCA(useWeightedFinalPCA); - - df3.setPropagateToPCA(propagateToPCA); - df3.setMaxR(maxR); - df3.setMaxDZIni(maxDZIni); - df3.setMinParamChange(minParamChange); - df3.setMinRelChi2Change(minRelChi2Change); - df3.setUseAbsDCA(useAbsDCA); - df3.setWeightedFinalPCA(useWeightedFinalPCA); - - ccdb->setURL(ccdbUrl); + cut3Prong = {config.cutsDplusToPiKPi, config.cutsLcToPKPi, config.cutsDsToKKPi, config.cutsXicToPKPi}; + pTBins3Prong = {config.binsPtDplusToPiKPi, config.binsPtLcToPKPi, config.binsPtDsToKKPi, config.binsPtXicToPKPi}; + + df2.setPropagateToPCA(config.propagateToPCA); + df2.setMaxR(config.maxR); + df2.setMaxDZIni(config.maxDZIni); + df2.setMinParamChange(config.minParamChange); + df2.setMinRelChi2Change(config.minRelChi2Change); + df2.setUseAbsDCA(config.useAbsDCA); + df2.setWeightedFinalPCA(config.useWeightedFinalPCA); + + df3.setPropagateToPCA(config.propagateToPCA); + df3.setMaxR(config.maxR); + df3.setMaxDZIni(config.maxDZIni); + df3.setMinParamChange(config.minParamChange); + df3.setMinRelChi2Change(config.minRelChi2Change); + df3.setUseAbsDCA(config.useAbsDCA); + df3.setWeightedFinalPCA(config.useWeightedFinalPCA); + + ccdb->setURL(config.ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(config.ccdbPathLut)); runNumber = 0; - if (fillHistograms) { + if (config.fillHistograms) { AxisSpec axisNumTracks{500, -0.5f, 499.5f, "Number of tracks"}; AxisSpec axisNumCands{1000, -0.5f, 999.5f, "Number of candidates"}; - registry.add("hNTracks", "Number of selected tracks;# of selected tracks;entries", {HistType::kTH1F, {axisNumTracks}}); + registry.add("hNTracks", "Number of selected tracks;# of selected tracks;entries", {HistType::kTH1D, {axisNumTracks}}); // 2-prong histograms - registry.add("hVtx2ProngX", "2-prong candidates;#it{x}_{sec. vtx.} (cm);entries", {HistType::kTH1F, {{1000, -2., 2.}}}); - registry.add("hVtx2ProngY", "2-prong candidates;#it{y}_{sec. vtx.} (cm);entries", {HistType::kTH1F, {{1000, -2., 2.}}}); - registry.add("hVtx2ProngZ", "2-prong candidates;#it{z}_{sec. vtx.} (cm);entries", {HistType::kTH1F, {{1000, -20., 20.}}}); - registry.add("hNCand2Prong", "2-prong candidates preselected;# of candidates;entries", {HistType::kTH1F, {axisNumCands}}); - registry.add("hNCand2ProngVsNTracks", "2-prong candidates preselected;# of selected tracks;# of candidates;entries", {HistType::kTH2F, {axisNumTracks, axisNumCands}}); - registry.add("hMassD0ToPiK", "D^{0} candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0., 5.}}}); - registry.add("hMassJpsiToEE", "J/#psi candidates;inv. mass (e^{#plus} e^{#minus}) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0., 5.}}}); - registry.add("hMassJpsiToMuMu", "J/#psi candidates;inv. mass (#mu^{#plus} #mu^{#minus}) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0., 5.}}}); + registry.add("hVtx2ProngX", "2-prong candidates;#it{x}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -2., 2.}}}); + registry.add("hVtx2ProngY", "2-prong candidates;#it{y}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -2., 2.}}}); + registry.add("hVtx2ProngZ", "2-prong candidates;#it{z}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -20., 20.}}}); + registry.add("hNCand2Prong", "2-prong candidates preselected;# of candidates;entries", {HistType::kTH1D, {axisNumCands}}); + registry.add("hNCand2ProngVsNTracks", "2-prong candidates preselected;# of selected tracks;# of candidates;entries", {HistType::kTH2D, {axisNumTracks, axisNumCands}}); + registry.add("hMassD0ToPiK", "D^{0} candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassJpsiToEE", "J/#psi candidates;inv. mass (e^{#plus} e^{#minus}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassJpsiToMuMu", "J/#psi candidates;inv. mass (#mu^{#plus} #mu^{#minus}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); // 3-prong histograms - registry.add("hVtx3ProngX", "3-prong candidates;#it{x}_{sec. vtx.} (cm);entries", {HistType::kTH1F, {{1000, -2., 2.}}}); - registry.add("hVtx3ProngY", "3-prong candidates;#it{y}_{sec. vtx.} (cm);entries", {HistType::kTH1F, {{1000, -2., 2.}}}); - registry.add("hVtx3ProngZ", "3-prong candidates;#it{z}_{sec. vtx.} (cm);entries", {HistType::kTH1F, {{1000, -20., 20.}}}); - registry.add("hNCand3Prong", "3-prong candidates preselected;# of candidates;entries", {HistType::kTH1F, {axisNumCands}}); - registry.add("hNCand3ProngVsNTracks", "3-prong candidates preselected;# of selected tracks;# of candidates;entries", {HistType::kTH2F, {axisNumTracks, axisNumCands}}); - registry.add("hMassDPlusToPiKPi", "D^{#plus} candidates;inv. mass (#pi K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0., 5.}}}); - registry.add("hMassLcToPKPi", "#Lambda_{c}^{#plus} candidates;inv. mass (p K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0., 5.}}}); - registry.add("hMassDsToKKPi", "D_{s}^{#plus} candidates;inv. mass (K K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0., 5.}}}); - registry.add("hMassXicToPKPi", "#Xi_{c}^{#plus} candidates;inv. mass (p K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0., 5.}}}); - registry.add("hMassDstarToD0Pi", "D^{*#plus} candidates;inv. mass (K #pi #pi) - mass (K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0.135, 0.185}}}); + registry.add("hVtx3ProngX", "3-prong candidates;#it{x}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -2., 2.}}}); + registry.add("hVtx3ProngY", "3-prong candidates;#it{y}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -2., 2.}}}); + registry.add("hVtx3ProngZ", "3-prong candidates;#it{z}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -20., 20.}}}); + registry.add("hNCand3Prong", "3-prong candidates preselected;# of candidates;entries", {HistType::kTH1D, {axisNumCands}}); + registry.add("hNCand3ProngVsNTracks", "3-prong candidates preselected;# of selected tracks;# of candidates;entries", {HistType::kTH2D, {axisNumTracks, axisNumCands}}); + registry.add("hMassDPlusToPiKPi", "D^{#plus} candidates;inv. mass (#pi K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassLcToPKPi", "#Lambda_{c}^{#plus} candidates;inv. mass (p K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassDsToKKPi", "D_{s}^{#plus} candidates;inv. mass (K K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassXicToPKPi", "#Xi_{c}^{#plus} candidates;inv. mass (p K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassDstarToD0Pi", "D^{*#plus} candidates;inv. mass (K #pi #pi) - mass (K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0.135, 0.185}}}); // needed for PV refitting - if (doprocess2And3ProngsWithPvRefit) { + if (doprocess2And3ProngsWithPvRefit || doprocess2And3ProngsWithPvRefitWithPidForHfFiltersBdt) { AxisSpec axisCollisionX{100, -20.f, 20.f, "X (cm)"}; AxisSpec axisCollisionY{100, -20.f, 20.f, "Y (cm)"}; AxisSpec axisCollisionZ{100, -20.f, 20.f, "Z (cm)"}; @@ -1377,58 +1367,58 @@ struct HfTrackIndexSkimCreator { AxisSpec axisCollisionDeltaX{axisPvRefitDeltaX, "#Delta x_{PV} (cm)"}; AxisSpec axisCollisionDeltaY{axisPvRefitDeltaY, "#Delta y_{PV} (cm)"}; AxisSpec axisCollisionDeltaZ{axisPvRefitDeltaZ, "#Delta z_{PV} (cm)"}; - registry.add("PvRefit/verticesPerCandidate", "", kTH1F, {{6, 0.5f, 6.5f, ""}}); + registry.add("PvRefit/verticesPerCandidate", "", kTH1D, {{6, 0.5f, 6.5f, ""}}); registry.get(HIST("PvRefit/verticesPerCandidate"))->GetXaxis()->SetBinLabel(1, "All PV"); registry.get(HIST("PvRefit/verticesPerCandidate"))->GetXaxis()->SetBinLabel(2, "PV refit doable"); registry.get(HIST("PvRefit/verticesPerCandidate"))->GetXaxis()->SetBinLabel(3, "PV refit #chi^{2}!=-1"); registry.get(HIST("PvRefit/verticesPerCandidate"))->GetXaxis()->SetBinLabel(4, "PV refit #it{#chi}^{2}==#minus1"); registry.get(HIST("PvRefit/verticesPerCandidate"))->GetXaxis()->SetBinLabel(5, "1 daughter contr."); registry.get(HIST("PvRefit/verticesPerCandidate"))->GetXaxis()->SetBinLabel(6, "no PV refit"); - registry.add("PvRefit/hPvDeltaXvsNContrib", "", kTH2F, {axisCollisionNContrib, axisCollisionDeltaX}); - registry.add("PvRefit/hPvDeltaYvsNContrib", "", kTH2F, {axisCollisionNContrib, axisCollisionDeltaY}); - registry.add("PvRefit/hPvDeltaZvsNContrib", "", kTH2F, {axisCollisionNContrib, axisCollisionDeltaZ}); - registry.add("PvRefit/hChi2vsNContrib", "", kTH2F, {axisCollisionNContrib, {102, -1.5, 100.5, "#chi^{2} PV refit"}}); - registry.add("PvRefit/hPvRefitXChi2Minus1", "PV refit with #it{#chi}^{2}==#minus1", kTH2F, {axisCollisionX, axisCollisionXOriginal}); - registry.add("PvRefit/hPvRefitYChi2Minus1", "PV refit with #it{#chi}^{2}==#minus1", kTH2F, {axisCollisionY, axisCollisionYOriginal}); - registry.add("PvRefit/hPvRefitZChi2Minus1", "PV refit with #it{#chi}^{2}==#minus1", kTH2F, {axisCollisionZ, axisCollisionZOriginal}); - registry.add("PvRefit/hNContribPvRefitNotDoable", "N. contributors for PV refit not doable", kTH1F, {axisCollisionNContrib}); - registry.add("PvRefit/hNContribPvRefitChi2Minus1", "N. contributors original PV for PV refit #it{#chi}^{2}==#minus1", kTH1F, {axisCollisionNContrib}); - } - - if (applyMlForHfFilters) { + registry.add("PvRefit/hPvDeltaXvsNContrib", "", kTH2D, {axisCollisionNContrib, axisCollisionDeltaX}); + registry.add("PvRefit/hPvDeltaYvsNContrib", "", kTH2D, {axisCollisionNContrib, axisCollisionDeltaY}); + registry.add("PvRefit/hPvDeltaZvsNContrib", "", kTH2D, {axisCollisionNContrib, axisCollisionDeltaZ}); + registry.add("PvRefit/hChi2vsNContrib", "", kTH2D, {axisCollisionNContrib, {102, -1.5, 100.5, "#chi^{2} PV refit"}}); + registry.add("PvRefit/hPvRefitXChi2Minus1", "PV refit with #it{#chi}^{2}==#minus1", kTH2D, {axisCollisionX, axisCollisionXOriginal}); + registry.add("PvRefit/hPvRefitYChi2Minus1", "PV refit with #it{#chi}^{2}==#minus1", kTH2D, {axisCollisionY, axisCollisionYOriginal}); + registry.add("PvRefit/hPvRefitZChi2Minus1", "PV refit with #it{#chi}^{2}==#minus1", kTH2D, {axisCollisionZ, axisCollisionZOriginal}); + registry.add("PvRefit/hNContribPvRefitNotDoable", "N. contributors for PV refit not doable", kTH1D, {axisCollisionNContrib}); + registry.add("PvRefit/hNContribPvRefitChi2Minus1", "N. contributors original PV for PV refit #it{#chi}^{2}==#minus1", kTH1D, {axisCollisionNContrib}); + } + + if (config.applyMlForHfFilters) { AxisSpec axisBdtScore{100, 0.f, 1.f}; - registry.add("ML/hMlScoreBkgD0", "Bkg ML score for D^{0} candidates;Bkg ML score;entries", kTH1F, {axisBdtScore}); - registry.add("ML/hMlScorePromptD0", "Prompt ML score for D^{0} candidates;Prompt ML score;entries", kTH1F, {axisBdtScore}); - registry.add("ML/hMlScoreNonpromptD0", "Non-prompt ML score for D^{0} candidates;Non-prompt ML score;entries", kTH1F, {axisBdtScore}); - registry.add("ML/hMlScoreBkgDplus", "Bkg ML score for D^{#plus} candidates;Bkg ML score;entries", kTH1F, {axisBdtScore}); - registry.add("ML/hMlScorePromptDplus", "Prompt ML score for D^{#plus} candidates;Prompt ML score;entries", kTH1F, {axisBdtScore}); - registry.add("ML/hMlScoreNonpromptDplus", "Non-prompt ML score for D^{#plus} candidates;Non-prompt ML score;entries", kTH1F, {axisBdtScore}); - registry.add("ML/hMlScoreBkgDs", "Bkg ML score for D_{s}^{#plus} candidates;Bkg ML score;entries", kTH1F, {axisBdtScore}); - registry.add("ML/hMlScorePromptDs", "Prompt ML score for D_{s}^{#plus} candidates;Prompt ML score;entries", kTH1F, {axisBdtScore}); - registry.add("ML/hMlScoreNonpromptDs", "Non-prompt ML score for D_{s}^{#plus} candidates;Non-prompt ML score;entries", kTH1F, {axisBdtScore}); - registry.add("ML/hMlScoreBkgLc", "Bkg ML score for #Lambda_{c}^{#plus} candidates;Bkg ML score;entries", kTH1F, {axisBdtScore}); - registry.add("ML/hMlScorePromptLc", "Prompt ML score for #Lambda_{c}^{#plus} candidates;Prompt ML score;entries", kTH1F, {axisBdtScore}); - registry.add("ML/hMlScoreNonpromptLc", "Non-prompt ML score for #Lambda_{c}^{#plus} candidates;Non-prompt ML score;entries", kTH1F, {axisBdtScore}); - registry.add("ML/hMlScoreBkgXic", "Bkg ML score for #Xi_{c}^{#plus} candidates;Bkg ML score;entries", kTH1F, {axisBdtScore}); - registry.add("ML/hMlScorePromptXic", "Prompt ML score for #Xi_{c}^{#plus} candidates;Prompt ML score;entries", kTH1F, {axisBdtScore}); - registry.add("ML/hMlScoreNonpromptXic", "Non-prompt ML score for #Xi_{c}^{#plus} candidates;Non-prompt ML score;entries", kTH1F, {axisBdtScore}); - } - } - - if (applyMlForHfFilters) { - const std::vector onnxFileNames2Prongs = {onnxFileNames->get(0u, 0u)}; - const std::array, kN3ProngDecays> onnxFileNames3Prongs = {std::vector{onnxFileNames->get(1u, 0u)}, std::vector{onnxFileNames->get(2u, 0u)}, std::vector{onnxFileNames->get(3u, 0u)}, std::vector{onnxFileNames->get(4u, 0u)}}; - const std::vector mlModelPathCcdb2Prongs = {mlModelPathCCDB.value + "D0"}; - const std::array, kN3ProngDecays> mlModelPathCcdb3Prongs = {std::vector{mlModelPathCCDB.value + "Dplus"}, std::vector{mlModelPathCCDB.value + "Lc"}, std::vector{mlModelPathCCDB.value + "Ds"}, std::vector{mlModelPathCCDB.value + "Xic"}}; + registry.add("ML/hMlScoreBkgD0", "Bkg ML score for D^{0} candidates;Bkg ML score;entries", kTH1D, {axisBdtScore}); + registry.add("ML/hMlScorePromptD0", "Prompt ML score for D^{0} candidates;Prompt ML score;entries", kTH1D, {axisBdtScore}); + registry.add("ML/hMlScoreNonpromptD0", "Non-prompt ML score for D^{0} candidates;Non-prompt ML score;entries", kTH1D, {axisBdtScore}); + registry.add("ML/hMlScoreBkgDplus", "Bkg ML score for D^{#plus} candidates;Bkg ML score;entries", kTH1D, {axisBdtScore}); + registry.add("ML/hMlScorePromptDplus", "Prompt ML score for D^{#plus} candidates;Prompt ML score;entries", kTH1D, {axisBdtScore}); + registry.add("ML/hMlScoreNonpromptDplus", "Non-prompt ML score for D^{#plus} candidates;Non-prompt ML score;entries", kTH1D, {axisBdtScore}); + registry.add("ML/hMlScoreBkgDs", "Bkg ML score for D_{s}^{#plus} candidates;Bkg ML score;entries", kTH1D, {axisBdtScore}); + registry.add("ML/hMlScorePromptDs", "Prompt ML score for D_{s}^{#plus} candidates;Prompt ML score;entries", kTH1D, {axisBdtScore}); + registry.add("ML/hMlScoreNonpromptDs", "Non-prompt ML score for D_{s}^{#plus} candidates;Non-prompt ML score;entries", kTH1D, {axisBdtScore}); + registry.add("ML/hMlScoreBkgLc", "Bkg ML score for #Lambda_{c}^{#plus} candidates;Bkg ML score;entries", kTH1D, {axisBdtScore}); + registry.add("ML/hMlScorePromptLc", "Prompt ML score for #Lambda_{c}^{#plus} candidates;Prompt ML score;entries", kTH1D, {axisBdtScore}); + registry.add("ML/hMlScoreNonpromptLc", "Non-prompt ML score for #Lambda_{c}^{#plus} candidates;Non-prompt ML score;entries", kTH1D, {axisBdtScore}); + registry.add("ML/hMlScoreBkgXic", "Bkg ML score for #Xi_{c}^{#plus} candidates;Bkg ML score;entries", kTH1D, {axisBdtScore}); + registry.add("ML/hMlScorePromptXic", "Prompt ML score for #Xi_{c}^{#plus} candidates;Prompt ML score;entries", kTH1D, {axisBdtScore}); + registry.add("ML/hMlScoreNonpromptXic", "Non-prompt ML score for #Xi_{c}^{#plus} candidates;Non-prompt ML score;entries", kTH1D, {axisBdtScore}); + } + } + + if (config.applyMlForHfFilters) { + const std::vector onnxFileNames2Prongs = {config.onnxFileNames->get(0u, 0u)}; + const std::array, kN3ProngDecays> onnxFileNames3Prongs = {std::vector{config.onnxFileNames->get(1u, 0u)}, std::vector{config.onnxFileNames->get(2u, 0u)}, std::vector{config.onnxFileNames->get(3u, 0u)}, std::vector{config.onnxFileNames->get(4u, 0u)}}; + const std::vector mlModelPathCcdb2Prongs = {config.mlModelPathCCDB.value + "D0"}; + const std::array, kN3ProngDecays> mlModelPathCcdb3Prongs = {std::vector{config.mlModelPathCCDB.value + "Dplus"}, std::vector{config.mlModelPathCCDB.value + "Lc"}, std::vector{config.mlModelPathCCDB.value + "Ds"}, std::vector{config.mlModelPathCCDB.value + "Xic"}}; const std::vector ptBinsMl = {0., 1.e10}; const std::vector cutDirMl = {o2::cuts_ml::CutDirection::CutGreater, o2::cuts_ml::CutDirection::CutSmaller, o2::cuts_ml::CutDirection::CutSmaller}; - const std::array, kN3ProngDecays> thresholdMlScore3Prongs = {thresholdMlScoreDplusToPiKPi, thresholdMlScoreLcToPiKP, thresholdMlScoreDsToPiKK, thresholdMlScoreXicToPiKP}; + const std::array, kN3ProngDecays> thresholdMlScore3Prongs = {config.thresholdMlScoreDplusToPiKPi, config.thresholdMlScoreLcToPiKP, config.thresholdMlScoreDsToPiKK, config.thresholdMlScoreXicToPiKP}; // initialise 2-prong ML response - hfMlResponse2Prongs.configure(ptBinsMl, thresholdMlScoreD0ToKPi, cutDirMl, 3); - if (loadMlModelsFromCCDB) { - ccdbApi.init(ccdbUrl); - hfMlResponse2Prongs.setModelPathsCCDB(onnxFileNames2Prongs, ccdbApi, mlModelPathCcdb2Prongs, timestampCcdbForHfFilters); + hfMlResponse2Prongs.configure(ptBinsMl, config.thresholdMlScoreD0ToKPi, cutDirMl, 3); + if (config.loadMlModelsFromCCDB) { + ccdbApi.init(config.ccdbUrl); + hfMlResponse2Prongs.setModelPathsCCDB(onnxFileNames2Prongs, ccdbApi, mlModelPathCcdb2Prongs, config.timestampCcdbForHfFilters); } else { hfMlResponse2Prongs.setModelPathsLocal(onnxFileNames2Prongs); } @@ -1441,9 +1431,9 @@ struct HfTrackIndexSkimCreator { } hasMlModel3Prong[iDecay3P] = true; hfMlResponse3Prongs[iDecay3P].configure(ptBinsMl, thresholdMlScore3Prongs[iDecay3P], cutDirMl, 3); - if (loadMlModelsFromCCDB) { - ccdbApi.init(ccdbUrl); - hfMlResponse3Prongs[iDecay3P].setModelPathsCCDB(onnxFileNames3Prongs[iDecay3P], ccdbApi, mlModelPathCcdb3Prongs[iDecay3P], timestampCcdbForHfFilters); + if (config.loadMlModelsFromCCDB) { + ccdbApi.init(config.ccdbUrl); + hfMlResponse3Prongs[iDecay3P].setModelPathsCCDB(onnxFileNames3Prongs[iDecay3P], ccdbApi, mlModelPathCcdb3Prongs[iDecay3P], config.timestampCcdbForHfFilters); } else { hfMlResponse3Prongs[iDecay3P].setModelPathsLocal(onnxFileNames3Prongs[iDecay3P]); } @@ -1468,7 +1458,7 @@ struct HfTrackIndexSkimCreator { auto arrMom = std::array{pVecTrack0, pVecTrack1}; pt2Prong = RecoDecay::pt(pVecTrack0, pVecTrack1); - auto pT = pt2Prong + ptTolerance; // add tolerance because of no reco decay vertex + auto pT = pt2Prong + config.ptTolerance; // add tolerance because of no reco decay vertex for (int iDecay2P = 0; iDecay2P < kN2ProngDecays; iDecay2P++) { @@ -1477,7 +1467,7 @@ struct HfTrackIndexSkimCreator { // return immediately if it is outside the defined pT bins if (pTBin == -1) { CLRBIT(isSelected, iDecay2P); - if (debug) { + if (config.debug) { cutStatus[iDecay2P][0] = false; } continue; @@ -1491,7 +1481,7 @@ struct HfTrackIndexSkimCreator { double min2 = minMass * minMass; double max2 = maxMass * maxMass; - if ((debug || TESTBIT(isSelected, iDecay2P)) && minMass >= 0. && maxMass > 0.) { + if ((config.debug || TESTBIT(isSelected, iDecay2P)) && minMass >= 0. && maxMass > 0.) { massHypos[0] = RecoDecay::m2(arrMom, arrMass2Prong[iDecay2P][0]); massHypos[1] = (iDecay2P == hf_cand_2prong::DecayType::D0ToPiK) ? RecoDecay::m2(arrMom, arrMass2Prong[iDecay2P][1]) : massHypos[0]; if (massHypos[0] < min2 || massHypos[0] >= max2) { @@ -1502,29 +1492,29 @@ struct HfTrackIndexSkimCreator { } if (whichHypo[iDecay2P] == 0) { CLRBIT(isSelected, iDecay2P); - if (debug) { + if (config.debug) { cutStatus[iDecay2P][1] = false; } } } // imp. par. product cut - if (debug || TESTBIT(isSelected, iDecay2P)) { + if (config.debug || TESTBIT(isSelected, iDecay2P)) { auto impParProduct = dcaTrack0 * dcaTrack1; if (impParProduct > cut2Prong[iDecay2P].get(pTBin, 3u)) { CLRBIT(isSelected, iDecay2P); - if (debug) { + if (config.debug) { cutStatus[iDecay2P][2] = false; } } } // additional check for D0 to be used in D* finding - if (iDecay2P == hf_cand_2prong::DecayType::D0ToPiK && doDstar && TESTBIT(isSelected, iDecay2P)) { - auto pTBinDstar = findBin(binsPtDstarToD0Pi, pT * 1.2); // assuming the D* pT about 20% higher than the one of the D0 to be safe + if (iDecay2P == hf_cand_2prong::DecayType::D0ToPiK && config.doDstar && TESTBIT(isSelected, iDecay2P)) { + auto pTBinDstar = findBin(config.binsPtDstarToD0Pi, pT * 1.2); // assuming the D* pT about 20% higher than the one of the D0 to be safe if (pTBinDstar >= 0) { whichHypo[kN2ProngDecays] = whichHypo[hf_cand_2prong::DecayType::D0ToPiK]; - double deltaMass = cutsDstarToD0Pi->get(pTBinDstar, 1u); + double deltaMass = config.cutsDstarToD0Pi->get(pTBinDstar, 1u); if (TESTBIT(whichHypo[iDecay2P], 0) && (massHypos[0] > (massDzero + deltaMass) * (massDzero + deltaMass) || massHypos[0] < (massDzero - deltaMass) * (massDzero - deltaMass))) { CLRBIT(whichHypo[kN2ProngDecays], 0); @@ -1564,7 +1554,7 @@ struct HfTrackIndexSkimCreator { if (whichHypo[hf_cand_3prong::DecayType::DsToKKPi] == 0) { CLRBIT(isSelected, hf_cand_3prong::DecayType::DsToKKPi); - if (debug) { + if (config.debug) { cutStatus[hf_cand_3prong::DecayType::DsToKKPi][4] = false; } } @@ -1584,13 +1574,13 @@ struct HfTrackIndexSkimCreator { { auto arrMom = std::array{pVecTrack0, pVecTrack1, pVecTrack2}; - auto pT = RecoDecay::pt(pVecTrack0, pVecTrack1, pVecTrack2) + ptTolerance; // add tolerance because of no reco decay vertex + auto pT = RecoDecay::pt(pVecTrack0, pVecTrack1, pVecTrack2) + config.ptTolerance; // add tolerance because of no reco decay vertex for (int iDecay3P = 0; iDecay3P < kN3ProngDecays; iDecay3P++) { // check proton PID for Lc and Xic whichHypo[iDecay3P] = 3; - if ((iDecay3P == hf_cand_3prong::DecayType::LcToPKPi && applyProtonPidForLcToPKPi) || (iDecay3P == hf_cand_3prong::DecayType::XicToPKPi && applyProtonPidForXicToPKPi)) { + if ((iDecay3P == hf_cand_3prong::DecayType::LcToPKPi && config.applyProtonPidForLcToPKPi) || (iDecay3P == hf_cand_3prong::DecayType::XicToPKPi && config.applyProtonPidForXicToPKPi)) { if ((iDecay3P == hf_cand_3prong::DecayType::LcToPKPi && !TESTBIT(isIdentifiedPidTrack0, ChannelsProtonPid::LcToPKPi)) || (iDecay3P == hf_cand_3prong::DecayType::XicToPKPi && !TESTBIT(isIdentifiedPidTrack0, ChannelsProtonPid::XicToPKPi))) { CLRBIT(whichHypo[iDecay3P], 0); } @@ -1599,8 +1589,8 @@ struct HfTrackIndexSkimCreator { } if (whichHypo[iDecay3P] == 0) { CLRBIT(isSelected, iDecay3P); - if (debug) { - cutStatus[iDecay3P][hf_cuts_presel_3prong::nCutVars] = false; // PID + if (config.debug) { + cutStatus[iDecay3P][hf_cuts_presel_3prong::NCutVars] = false; // PID } continue; // no need to check further for this particle hypothesis } @@ -1612,7 +1602,7 @@ struct HfTrackIndexSkimCreator { if (pTBin == -1) { CLRBIT(isSelected, iDecay3P); whichHypo[iDecay3P] = 0; - if (debug) { + if (config.debug) { cutStatus[iDecay3P][0] = false; } continue; @@ -1625,7 +1615,7 @@ struct HfTrackIndexSkimCreator { double min2 = minMass * minMass; double max2 = maxMass * maxMass; - if ((debug || TESTBIT(isSelected, iDecay3P)) && minMass >= 0. && maxMass > 0.) { // no need to check isSelected but to avoid mistakes + if ((config.debug || TESTBIT(isSelected, iDecay3P)) && minMass >= 0. && maxMass > 0.) { // no need to check isSelected but to avoid mistakes massHypos[0] = RecoDecay::m2(arrMom, arrMass3Prong[iDecay3P][0]); massHypos[1] = (iDecay3P != hf_cand_3prong::DecayType::DplusToPiKPi) ? RecoDecay::m2(arrMom, arrMass3Prong[iDecay3P][1]) : massHypos[0]; if (massHypos[0] < min2 || massHypos[0] >= max2) { @@ -1636,13 +1626,13 @@ struct HfTrackIndexSkimCreator { } if (whichHypo[iDecay3P] == 0) { CLRBIT(isSelected, iDecay3P); - if (debug) { + if (config.debug) { cutStatus[iDecay3P][1] = false; } } } - if ((debug || TESTBIT(isSelected, iDecay3P)) && iDecay3P == hf_cand_3prong::DecayType::DsToKKPi) { + if ((config.debug || TESTBIT(isSelected, iDecay3P)) && iDecay3P == hf_cand_3prong::DecayType::DsToKKPi) { applyPreselectionPhiDecay(pTBin, pVecTrack0, pVecTrack1, pVecTrack2, cutStatus, whichHypo, isSelected); } } @@ -1657,7 +1647,7 @@ struct HfTrackIndexSkimCreator { template void applySelections2Prong(const T1& pVecCand, const T2& secVtx, const T3& primVtx, T4& cutStatus, int& isSelected) { - if (debug || isSelected > 0) { + if (config.debug || isSelected > 0) { for (int iDecay2P = 0; iDecay2P < kN2ProngDecays; iDecay2P++) { @@ -1665,18 +1655,18 @@ struct HfTrackIndexSkimCreator { auto pTBin = findBin(&pTBins2Prong[iDecay2P], RecoDecay::pt(pVecCand)); if (pTBin == -1) { // cut if it is outside the defined pT bins CLRBIT(isSelected, iDecay2P); - if (debug) { + if (config.debug) { cutStatus[iDecay2P][0] = false; } continue; } // cosp - if (debug || TESTBIT(isSelected, iDecay2P)) { + if (config.debug || TESTBIT(isSelected, iDecay2P)) { auto cpa = RecoDecay::cpa(primVtx, secVtx, pVecCand); if (cpa < cut2Prong[iDecay2P].get(pTBin, 2u)) { // 2u == "cospIndex[iDecay2P]" CLRBIT(isSelected, iDecay2P); - if (debug) { + if (config.debug) { cutStatus[iDecay2P][3] = false; } } @@ -1696,7 +1686,7 @@ struct HfTrackIndexSkimCreator { } const float ptDummy = 1.; // dummy pT value (only one pT bin) bool isSelMl = hfMlResponse2Prongs.isSelectedMl(featuresCand, ptDummy, outputScores); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("ML/hMlScoreBkgD0"), outputScores[0]); registry.fill(HIST("ML/hMlScorePromptD0"), outputScores[1]); registry.fill(HIST("ML/hMlScoreNonpromptD0"), outputScores[2]); @@ -1714,11 +1704,11 @@ struct HfTrackIndexSkimCreator { template bool isTwoTrackVertexSelectedFor3Prongs(const T1& secVtx, const T2& primVtx, const T3& dcaFitter) { - if (dcaFitter.getChi2AtPCACandidate() > maxTwoTrackChi2PcaFor3Prongs) { + if (dcaFitter.getChi2AtPCACandidate() > config.maxTwoTrackChi2PcaFor3Prongs) { return false; } auto decLen = RecoDecay::distance(primVtx, secVtx); - if (decLen < minTwoTrackDecayLengthFor3Prongs) { + if (decLen < config.minTwoTrackDecayLengthFor3Prongs) { return false; } @@ -1734,7 +1724,7 @@ struct HfTrackIndexSkimCreator { template void applySelection3Prong(const T1& pVecCand, const T2& secVtx, const T3& primVtx, T4& cutStatus, int& isSelected) { - if (debug || isSelected > 0) { + if (config.debug || isSelected > 0) { auto pT = RecoDecay::pt(pVecCand); for (int iDecay3P = 0; iDecay3P < kN3ProngDecays; iDecay3P++) { @@ -1743,29 +1733,29 @@ struct HfTrackIndexSkimCreator { auto pTBin = findBin(&pTBins3Prong[iDecay3P], pT); if (pTBin == -1) { // cut if it is outside the defined pT bins CLRBIT(isSelected, iDecay3P); - if (debug) { + if (config.debug) { cutStatus[iDecay3P][0] = false; } continue; } // cosp - if ((debug || TESTBIT(isSelected, iDecay3P))) { + if ((config.debug || TESTBIT(isSelected, iDecay3P))) { auto cpa = RecoDecay::cpa(primVtx, secVtx, pVecCand); if (cpa < cut3Prong[iDecay3P].get(pTBin, 2u)) { // 2u == cospIndex[iDecay3P] CLRBIT(isSelected, iDecay3P); - if (debug) { + if (config.debug) { cutStatus[iDecay3P][2] = false; } } } // decay length - if ((debug || TESTBIT(isSelected, iDecay3P))) { + if ((config.debug || TESTBIT(isSelected, iDecay3P))) { auto decayLength = RecoDecay::distance(primVtx, secVtx); if (decayLength < cut3Prong[iDecay3P].get(pTBin, 3u)) { // 3u == decLenIndex[iDecay3P] CLRBIT(isSelected, iDecay3P); - if (debug) { + if (config.debug) { cutStatus[iDecay3P][3] = false; } } @@ -1776,9 +1766,12 @@ struct HfTrackIndexSkimCreator { /// Method to perform ML selections for 2-prong candidates after the rectangular selections /// \param featuresCand is the vector with the candidate features + /// \param featuresCandPid is the vector with the candidate PID features /// \param outputScores is the array of vectors with the output scores to be filled /// \param isSelected ia s bitmap with selection outcome - void applyMlSelectionForHfFilters3Prong(std::vector featuresCand, std::array, kN3ProngDecays>& outputScores, int& isSelected) + /// \param usePidForHfFiltersBdt is the flag to determine whether to use also the PID features for the Lc BDT + template + void applyMlSelectionForHfFilters3Prong(std::vector featuresCand, std::vector featuresCandPid, std::array, kN3ProngDecays>& outputScores, int& isSelected) { if (isSelected == 0) { return; @@ -1787,8 +1780,19 @@ struct HfTrackIndexSkimCreator { const float ptDummy = 1.; // dummy pT value (only one pT bin) for (int iDecay3P{0}; iDecay3P < kN3ProngDecays; ++iDecay3P) { if (TESTBIT(isSelected, iDecay3P) && hasMlModel3Prong[iDecay3P]) { - bool isMlSel = hfMlResponse3Prongs[iDecay3P].isSelectedMl(featuresCand, ptDummy, outputScores[iDecay3P]); - if (fillHistograms) { + bool isMlSel = false; + if constexpr (usePidForHfFiltersBdt) { + if (iDecay3P != hf_cand_3prong::DecayType::LcToPKPi && iDecay3P != hf_cand_3prong::DecayType::XicToPKPi) { + isMlSel = hfMlResponse3Prongs[iDecay3P].isSelectedMl(featuresCand, ptDummy, outputScores[iDecay3P]); + } else { + std::vector featuresCandWithPid = featuresCand; + featuresCandWithPid.insert(featuresCandWithPid.end(), featuresCandPid.begin(), featuresCandPid.end()); + isMlSel = hfMlResponse3Prongs[iDecay3P].isSelectedMl(featuresCandWithPid, ptDummy, outputScores[iDecay3P]); + } + } else { + isMlSel = hfMlResponse3Prongs[iDecay3P].isSelectedMl(featuresCand, ptDummy, outputScores[iDecay3P]); + } + if (config.fillHistograms) { switch (iDecay3P) { case hf_cand_3prong::DecayType::DplusToPiKPi: { registry.fill(HIST("ML/hMlScoreBkgDplus"), outputScores[iDecay3P][0]); @@ -1836,14 +1840,14 @@ struct HfTrackIndexSkimCreator { uint8_t isSelected{1}; auto arrMom = std::array{pVecTrack0, pVecTrack1, pVecTrack2}; auto arrMomD0 = std::array{pVecTrack0, pVecTrack1}; - auto pT = RecoDecay::pt(pVecTrack0, pVecTrack1, pVecTrack2) + ptTolerance; // add tolerance because of no reco decay vertex + auto pT = RecoDecay::pt(pVecTrack0, pVecTrack1, pVecTrack2) + config.ptTolerance; // add tolerance because of no reco decay vertex // pT - auto pTBin = findBin(binsPtDstarToD0Pi, pT); + auto pTBin = findBin(config.binsPtDstarToD0Pi, pT); // return immediately if it is outside the defined pT bins if (pTBin == -1) { isSelected = 0; - if (debug) { + if (config.debug) { CLRBIT(cutStatus, 0); } else { return isSelected; @@ -1851,23 +1855,23 @@ struct HfTrackIndexSkimCreator { } // D0 mass - double deltaMassD0 = cutsDstarToD0Pi->get(pTBin, 1u); // 1u == deltaMassD0Index + double deltaMassD0 = config.cutsDstarToD0Pi->get(pTBin, 1u); // 1u == deltaMassD0Index double invMassD0 = RecoDecay::m(arrMomD0, std::array{massPi, massK}); if (std::abs(invMassD0 - massDzero) > deltaMassD0) { isSelected = 0; - if (debug) { + if (config.debug) { CLRBIT(cutStatus, 1); } return isSelected; } // D*+ mass - double maxDeltaMass = cutsDstarToD0Pi->get(pTBin, 0u); // 0u == deltaMassIndex + double maxDeltaMass = config.cutsDstarToD0Pi->get(pTBin, 0u); // 0u == deltaMassIndex double invMassDstar = RecoDecay::m(arrMom, std::array{massPi, massK, massPi}); deltaMass = invMassDstar - invMassD0; if (deltaMass > maxDeltaMass) { isSelected = 0; - if (debug) { + if (config.debug) { CLRBIT(cutStatus, 1); } return isSelected; @@ -1897,7 +1901,7 @@ struct HfTrackIndexSkimCreator { /// Prepare the vertex refitting // set the magnetic field from CCDB auto bc = collision.bc_as(); - initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, lut, isRun2); + initCCDB(bc, runNumber, ccdb, config.isRun2 ? config.ccdbPathGrp : config.ccdbPathGrpMag, lut, config.isRun2); // build the VertexBase to initialize the vertexer o2::dataformats::VertexBase primVtx; @@ -1912,24 +1916,24 @@ struct HfTrackIndexSkimCreator { bool pvRefitDoable = vertexer.prepareVertexRefit(vecPvContributorTrackParCov, primVtx); if (!pvRefitDoable) { LOG(info) << "Not enough tracks accepted for the refit"; - if (doprocess2And3ProngsWithPvRefit && fillHistograms) { + if ((doprocess2And3ProngsWithPvRefit || doprocess2And3ProngsWithPvRefitWithPidForHfFiltersBdt) && config.fillHistograms) { registry.fill(HIST("PvRefit/hNContribPvRefitNotDoable"), collision.numContrib()); } } - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "prepareVertexRefit = " << pvRefitDoable << " Ncontrib= " << vecPvContributorTrackParCov.size() << " Ntracks= " << collision.numContrib() << " Vtx= " << primVtx.asString(); } /// PV refitting, if the tracks contributed to this at the beginning o2::dataformats::VertexBase primVtxBaseRecalc; bool recalcPvRefit = false; - if (doprocess2And3ProngsWithPvRefit && pvRefitDoable) { - if (fillHistograms) { + if ((doprocess2And3ProngsWithPvRefit || doprocess2And3ProngsWithPvRefitWithPidForHfFiltersBdt) && pvRefitDoable) { + if (config.fillHistograms) { registry.fill(HIST("PvRefit/verticesPerCandidate"), 2); } recalcPvRefit = true; int nCandContr = 0; - for (uint64_t myGlobalID : vecCandPvContributorGlobId) { + for (uint64_t myGlobalID : vecCandPvContributorGlobId) { // o2-linter: disable=const-ref-in-for-loop (small type) auto trackIterator = std::find(vecPvContributorGlobId.begin(), vecPvContributorGlobId.end(), myGlobalID); /// track global index if (trackIterator != vecPvContributorGlobId.end()) { /// this is a contributor, let's remove it for the PV refit @@ -1940,17 +1944,17 @@ struct HfTrackIndexSkimCreator { } /// do the PV refit excluding the candidate daughters that originally contributed to fit it - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "### PV refit after removing " << nCandContr << " tracks"; } auto primVtxRefitted = vertexer.refitVertex(vecPvRefitContributorUsed, primVtx); // vertex refit // LOG(info) << "refit " << cnt << "/" << ntr << " result = " << primVtxRefitted.asString(); // LOG(info) << "refit for track with global index " << static_cast(myTrack.globalIndex()) << " " << primVtxRefitted.asString(); if (primVtxRefitted.getChi2() < 0) { - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "---> Refitted vertex has bad chi2 = " << primVtxRefitted.getChi2(); } - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("PvRefit/verticesPerCandidate"), 4); registry.fill(HIST("PvRefit/hPvRefitXChi2Minus1"), primVtxRefitted.getX(), collision.posX()); registry.fill(HIST("PvRefit/hPvRefitYChi2Minus1"), primVtxRefitted.getY(), collision.posY()); @@ -1958,10 +1962,10 @@ struct HfTrackIndexSkimCreator { registry.fill(HIST("PvRefit/hNContribPvRefitChi2Minus1"), collision.numContrib()); } recalcPvRefit = false; - } else if (fillHistograms) { + } else if (config.fillHistograms) { registry.fill(HIST("PvRefit/verticesPerCandidate"), 3); } - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("PvRefit/hChi2vsNContrib"), primVtxRefitted.getNContributors(), primVtxRefitted.getChi2()); } @@ -1974,7 +1978,7 @@ struct HfTrackIndexSkimCreator { const double deltaX = primVtx.getX() - primVtxRefitted.getX(); const double deltaY = primVtx.getY() - primVtxRefitted.getY(); const double deltaZ = primVtx.getZ() - primVtxRefitted.getZ(); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("PvRefit/hPvDeltaXvsNContrib"), primVtxRefitted.getNContributors(), deltaX); registry.fill(HIST("PvRefit/hPvDeltaYvsNContrib"), primVtxRefitted.getNContributors(), deltaY); registry.fill(HIST("PvRefit/hPvDeltaZvsNContrib"), primVtxRefitted.getNContributors(), deltaZ); @@ -2012,7 +2016,7 @@ struct HfTrackIndexSkimCreator { return; } /// end of performPvRefitCandProngs function - template + template void run2And3Prongs(SelectedCollisions const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, FilteredTrackAssocSel const&, @@ -2050,15 +2054,15 @@ struct HfTrackIndexSkimCreator { vecPvContributorGlobId.push_back(trackUnfiltered.globalIndex()); vecPvContributorTrackParCov.push_back(getTrackParCov(trackUnfiltered)); nContrib++; - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "---> a contributor! stuff saved"; LOG(info) << "vec_contrib size: " << vecPvContributorTrackParCov.size() << ", nContrib: " << nContrib; } } } - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "===> nTrk: " << nTrk << ", nContrib: " << nContrib << ", nNonContrib: " << nNonContrib; - if ((uint16_t)vecPvContributorTrackParCov.size() != collision.numContrib() || (uint16_t)nContrib != collision.numContrib()) { + if (static_cast(vecPvContributorTrackParCov.size()) != collision.numContrib() || static_cast(nContrib != collision.numContrib())) { LOG(info) << "!!! Some problem here !!! vecPvContributorTrackParCov.size()= " << vecPvContributorTrackParCov.size() << ", nContrib=" << nContrib << ", collision.numContrib()" << collision.numContrib(); } } @@ -2089,7 +2093,7 @@ struct HfTrackIndexSkimCreator { // set the magnetic field from CCDB auto bc = collision.bc_as(); - initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, lut, isRun2); + initCCDB(bc, runNumber, ccdb, config.isRun2 ? config.ccdbPathGrp : config.ccdbPathGrpMag, lut, config.isRun2); df2.setBz(o2::base::Propagator::Instance()->getNominalBz()); df3.setBz(o2::base::Propagator::Instance()->getNominalBz()); @@ -2143,7 +2147,7 @@ struct HfTrackIndexSkimCreator { int isSelected2ProngCand = n2ProngBit; // bitmap for checking status of two-prong candidates (1 is true, 0 is rejected) - if (debug) { + if (config.debug) { for (int iDecay2P = 0; iDecay2P < kN2ProngDecays; iDecay2P++) { for (int iCut = 0; iCut < kNCuts2Prong[iDecay2P]; iCut++) { cutStatus2Prong[iDecay2P][iCut] = true; @@ -2183,7 +2187,7 @@ struct HfTrackIndexSkimCreator { /// PV refit excluding the candidate daughters, if contributors if constexpr (doPvRefit) { - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("PvRefit/verticesPerCandidate"), 1); } int nCandContr = 2; @@ -2193,7 +2197,7 @@ struct HfTrackIndexSkimCreator { bool isTrackSecondContr = true; if (trackFirstIt == vecPvContributorGlobId.end()) { /// This track did not contribute to the original PV refit - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "--- [2 Prong] trackPos1 with globalIndex " << trackPos1.globalIndex() << " was not a PV contributor"; } nCandContr--; @@ -2201,7 +2205,7 @@ struct HfTrackIndexSkimCreator { } if (trackSecondIt == vecPvContributorGlobId.end()) { /// This track did not contribute to the original PV refit - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "--- [2 Prong] trackNeg1 with globalIndex " << trackNeg1.globalIndex() << " was not a PV contributor"; } nCandContr--; @@ -2209,16 +2213,16 @@ struct HfTrackIndexSkimCreator { } if (nCandContr == 2) { /// Both the daughter tracks were used for the original PV refit, let's refit it after excluding them - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "### [2 Prong] Calling performPvRefitCandProngs for HF 2 prong candidate"; } performPvRefitCandProngs(collision, bcWithTimeStamps, vecPvContributorGlobId, vecPvContributorTrackParCov, {trackPos1.globalIndex(), trackNeg1.globalIndex()}, pvRefitCoord2Prong, pvRefitCovMatrix2Prong); } else if (nCandContr == 1) { /// Only one daughter was a contributor, let's use then the PV recalculated by excluding only it - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "####### [2 Prong] nCandContr==" << nCandContr << " ---> just 1 contributor!"; } - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("PvRefit/verticesPerCandidate"), 5); } if (isTrackFirstContr && !isTrackSecondContr) { @@ -2232,10 +2236,10 @@ struct HfTrackIndexSkimCreator { } } else { /// 0 contributors among the HF candidate daughters - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("PvRefit/verticesPerCandidate"), 6); } - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "####### [2 Prong] nCandContr==" << nCandContr << " ---> some of the candidate daughters did not contribute to the original PV fit, PV refit not redone"; } } @@ -2250,12 +2254,12 @@ struct HfTrackIndexSkimCreator { pvCoord2Prong[2] = pvRefitCoord2Prong[2]; } applySelections2Prong(pVecCandProng2, secondaryVertex2, pvCoord2Prong, cutStatus2Prong, isSelected2ProngCand); - if (is2ProngCandidateGoodFor3Prong && do3Prong == 1) { + if (is2ProngCandidateGoodFor3Prong && config.do3Prong == 1) { is2ProngCandidateGoodFor3Prong = isTwoTrackVertexSelectedFor3Prongs(secondaryVertex2, pvCoord2Prong, df2); } std::vector mlScoresD0{}; - if (applyMlForHfFilters) { + if (config.applyMlForHfFilters) { auto trackParVarPcaPos1 = df2.getTrack(0); auto trackParVarPcaNeg1 = df2.getTrack(1); std::vector inputFeatures{trackParVarPcaPos1.getPt(), dcaInfoPos1[0], dcaInfoPos1[1], trackParVarPcaNeg1.getPt(), dcaInfoNeg1[0], dcaInfoNeg1[1]}; @@ -2265,7 +2269,7 @@ struct HfTrackIndexSkimCreator { if (isSelected2ProngCand > 0) { // fill table row rowTrackIndexProng2(thisCollId, trackPos1.globalIndex(), trackNeg1.globalIndex(), isSelected2ProngCand); - if (applyMlForHfFilters) { + if (config.applyMlForHfFilters) { rowTrackIndexMlScoreProng2(mlScoresD0); } if (TESTBIT(isSelected2ProngCand, hf_cand_2prong::DecayType::D0ToPiK)) { @@ -2278,21 +2282,21 @@ struct HfTrackIndexSkimCreator { pvRefitCovMatrix2Prong[0], pvRefitCovMatrix2Prong[1], pvRefitCovMatrix2Prong[2], pvRefitCovMatrix2Prong[3], pvRefitCovMatrix2Prong[4], pvRefitCovMatrix2Prong[5]); } - if (debug) { - int Prong2CutStatus[kN2ProngDecays]; + if (config.debug) { + int prong2CutStatus[kN2ProngDecays]; for (int iDecay2P = 0; iDecay2P < kN2ProngDecays; iDecay2P++) { - Prong2CutStatus[iDecay2P] = nCutStatus2ProngBit[iDecay2P]; + prong2CutStatus[iDecay2P] = nCutStatus2ProngBit[iDecay2P]; for (int iCut = 0; iCut < kNCuts2Prong[iDecay2P]; iCut++) { if (!cutStatus2Prong[iDecay2P][iCut]) { - CLRBIT(Prong2CutStatus[iDecay2P], iCut); + CLRBIT(prong2CutStatus[iDecay2P], iCut); } } } - rowProng2CutStatus(Prong2CutStatus[0], Prong2CutStatus[1], Prong2CutStatus[2]); // FIXME when we can do this by looping over kN2ProngDecays + rowProng2CutStatus(prong2CutStatus[0], prong2CutStatus[1], prong2CutStatus[2]); // FIXME when we can do this by looping over kN2ProngDecays } // fill histograms - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hVtx2ProngX"), secondaryVertex2[0]); registry.fill(HIST("hVtx2ProngY"), secondaryVertex2[1]); registry.fill(HIST("hVtx2ProngZ"), secondaryVertex2[2]); @@ -2332,7 +2336,7 @@ struct HfTrackIndexSkimCreator { } // if the cut on the decay length of 3-prongs computed with the first two tracks is enabled and the vertex was not computed for the D0, we compute it now - if (do3Prong == 1 && is2ProngCandidateGoodFor3Prong && (minTwoTrackDecayLengthFor3Prongs > 0.f || maxTwoTrackChi2PcaFor3Prongs < 1.e9f) && nVtxFrom2ProngFitter == 0) { + if (config.do3Prong == 1 && is2ProngCandidateGoodFor3Prong && (config.minTwoTrackDecayLengthFor3Prongs > 0.f || config.maxTwoTrackChi2PcaFor3Prongs < 1.e9f) && nVtxFrom2ProngFitter == 0) { try { nVtxFrom2ProngFitter = df2.process(trackParVarPos1, trackParVarNeg1); } catch (...) { @@ -2346,21 +2350,21 @@ struct HfTrackIndexSkimCreator { } } - if (do3Prong == 1 && is2ProngCandidateGoodFor3Prong) { // if 3 prongs are enabled and the first 2 tracks are selected for the 3-prong channels + if (config.do3Prong == 1 && is2ProngCandidateGoodFor3Prong) { // if 3 prongs are enabled and the first 2 tracks are selected for the 3-prong channels // second loop over positive tracks for (auto trackIndexPos2 = trackIndexPos1 + 1; trackIndexPos2 != groupedTrackIndicesPos1.end(); ++trackIndexPos2) { int isSelected3ProngCand = n3ProngBit; if (!TESTBIT(trackIndexPos2.isSelProng(), CandidateType::Cand3Prong)) { // continue immediately - if (!debug) { + if (!config.debug) { continue; } else { isSelected3ProngCand = 0; } } - if (applyKaonPidIn3Prongs && !TESTBIT(trackIndexNeg1.isIdentifiedPid(), channelKaonPid)) { // continue immediately if kaon PID enabled and opposite-sign track not a kaon - if (!debug) { + if (config.applyKaonPidIn3Prongs && !TESTBIT(trackIndexNeg1.isIdentifiedPid(), ChannelKaonPid)) { // continue immediately if kaon PID enabled and opposite-sign track not a kaon + if (!config.debug) { continue; } else { isSelected3ProngCand = 0; @@ -2379,7 +2383,7 @@ struct HfTrackIndexSkimCreator { getPxPyPz(trackParVarPos2, pVecTrackPos2); } - if (debug) { + if (config.debug) { for (int iDecay3P = 0; iDecay3P < kN3ProngDecays; iDecay3P++) { for (int iCut = 0; iCut < kNCuts3Prong[iDecay3P]; iCut++) { cutStatus3Prong[iDecay3P][iCut] = true; @@ -2391,7 +2395,7 @@ struct HfTrackIndexSkimCreator { int8_t isIdentifiedPidTrackPos1 = trackIndexPos1.isIdentifiedPid(); int8_t isIdentifiedPidTrackPos2 = trackIndexPos2.isIdentifiedPid(); applyPreselection3Prong(pVecTrackPos1, pVecTrackNeg1, pVecTrackPos2, isIdentifiedPidTrackPos1, isIdentifiedPidTrackPos2, cutStatus3Prong, whichHypo3Prong, isSelected3ProngCand); - if (!debug && isSelected3ProngCand == 0) { + if (!config.debug && isSelected3ProngCand == 0) { continue; } } @@ -2400,7 +2404,7 @@ struct HfTrackIndexSkimCreator { std::array pvRefitCoord3Prong2Pos1Neg = {collision.posX(), collision.posY(), collision.posZ()}; /// initialize to the original PV std::array pvRefitCovMatrix3Prong2Pos1Neg = getPrimaryVertex(collision).getCov(); /// initialize to the original PV if constexpr (doPvRefit) { - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("PvRefit/verticesPerCandidate"), 1); } int nCandContr = 3; @@ -2412,7 +2416,7 @@ struct HfTrackIndexSkimCreator { bool isTrackThirdContr = true; if (trackFirstIt == vecPvContributorGlobId.end()) { /// This track did not contribute to the original PV refit - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "--- [3 prong] trackPos1 with globalIndex " << trackPos1.globalIndex() << " was not a PV contributor"; } nCandContr--; @@ -2420,7 +2424,7 @@ struct HfTrackIndexSkimCreator { } if (trackSecondIt == vecPvContributorGlobId.end()) { /// This track did not contribute to the original PV refit - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "--- [3 prong] trackNeg1 with globalIndex " << trackNeg1.globalIndex() << " was not a PV contributor"; } nCandContr--; @@ -2428,7 +2432,7 @@ struct HfTrackIndexSkimCreator { } if (trackThirdIt == vecPvContributorGlobId.end()) { /// This track did not contribute to the original PV refit - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "--- [3 prong] trackPos2 with globalIndex " << trackPos2.globalIndex() << " was not a PV contributor"; } nCandContr--; @@ -2449,16 +2453,16 @@ struct HfTrackIndexSkimCreator { if (nCandContr == 3 || nCandContr == 2) { /// At least two of the daughter tracks were used for the original PV refit, let's refit it after excluding them - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "### [3 prong] Calling performPvRefitCandProngs for HF 3 prong candidate, removing " << nCandContr << " daughters"; } performPvRefitCandProngs(collision, bcWithTimeStamps, vecPvContributorGlobId, vecPvContributorTrackParCov, vecCandPvContributorGlobId, pvRefitCoord3Prong2Pos1Neg, pvRefitCovMatrix3Prong2Pos1Neg); } else if (nCandContr == 1) { /// Only one daughter was a contributor, let's use then the PV recalculated by excluding only it - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "####### [3 Prong] nCandContr==" << nCandContr << " ---> just 1 contributor!"; } - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("PvRefit/verticesPerCandidate"), 5); } if (isTrackFirstContr && !isTrackSecondContr && !isTrackThirdContr) { @@ -2476,10 +2480,10 @@ struct HfTrackIndexSkimCreator { } } else { /// 0 contributors among the HF candidate daughters - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("PvRefit/verticesPerCandidate"), 6); } - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "####### [3 prong] nCandContr==" << nCandContr << " ---> some of the candidate daughters did not contribute to the original PV fit, PV refit not redone"; } } @@ -2514,18 +2518,26 @@ struct HfTrackIndexSkimCreator { applySelection3Prong(pVecCandProng3Pos, secondaryVertex3, pvRefitCoord3Prong2Pos1Neg, cutStatus3Prong, isSelected3ProngCand); std::array, kN3ProngDecays> mlScores3Prongs; - if (applyMlForHfFilters) { + if (config.applyMlForHfFilters) { std::vector inputFeatures{trackParVarPcaPos1.getPt(), dcaInfoPos1[0], dcaInfoPos1[1], trackParVarPcaNeg1.getPt(), dcaInfoNeg1[0], dcaInfoNeg1[1], trackParVarPcaPos2.getPt(), dcaInfoPos2[0], dcaInfoPos2[1]}; - applyMlSelectionForHfFilters3Prong(inputFeatures, mlScores3Prongs, isSelected3ProngCand); + std::vector inputFeaturesLcPid{}; + if constexpr (usePidForHfFiltersBdt) { + inputFeaturesLcPid.push_back(trackPos1.tpcNSigmaPr()); + inputFeaturesLcPid.push_back(trackPos2.tpcNSigmaPr()); + inputFeaturesLcPid.push_back(trackPos1.tpcNSigmaPi()); + inputFeaturesLcPid.push_back(trackPos2.tpcNSigmaPi()); + inputFeaturesLcPid.push_back(trackNeg1.tpcNSigmaKa()); + } + applyMlSelectionForHfFilters3Prong(inputFeatures, inputFeaturesLcPid, mlScores3Prongs, isSelected3ProngCand); } - if (!debug && isSelected3ProngCand == 0) { + if (!config.debug && isSelected3ProngCand == 0) { continue; } // fill table row rowTrackIndexProng3(thisCollId, trackPos1.globalIndex(), trackNeg1.globalIndex(), trackPos2.globalIndex(), isSelected3ProngCand); - if (applyMlForHfFilters) { + if (config.applyMlForHfFilters) { rowTrackIndexMlScoreProng3(mlScores3Prongs[0], mlScores3Prongs[1], mlScores3Prongs[2], mlScores3Prongs[3]); } if constexpr (doPvRefit) { @@ -2534,21 +2546,21 @@ struct HfTrackIndexSkimCreator { pvRefitCovMatrix3Prong2Pos1Neg[0], pvRefitCovMatrix3Prong2Pos1Neg[1], pvRefitCovMatrix3Prong2Pos1Neg[2], pvRefitCovMatrix3Prong2Pos1Neg[3], pvRefitCovMatrix3Prong2Pos1Neg[4], pvRefitCovMatrix3Prong2Pos1Neg[5]); } - if (debug) { - int Prong3CutStatus[kN3ProngDecays]; + if (config.debug) { + int prong3CutStatus[kN3ProngDecays]; for (int iDecay3P = 0; iDecay3P < kN3ProngDecays; iDecay3P++) { - Prong3CutStatus[iDecay3P] = nCutStatus3ProngBit[iDecay3P]; + prong3CutStatus[iDecay3P] = nCutStatus3ProngBit[iDecay3P]; for (int iCut = 0; iCut < kNCuts3Prong[iDecay3P]; iCut++) { if (!cutStatus3Prong[iDecay3P][iCut]) { - CLRBIT(Prong3CutStatus[iDecay3P], iCut); + CLRBIT(prong3CutStatus[iDecay3P], iCut); } } } - rowProng3CutStatus(Prong3CutStatus[0], Prong3CutStatus[1], Prong3CutStatus[2], Prong3CutStatus[3]); // FIXME when we can do this by looping over kN3ProngDecays + rowProng3CutStatus(prong3CutStatus[0], prong3CutStatus[1], prong3CutStatus[2], prong3CutStatus[3]); // FIXME when we can do this by looping over kN3ProngDecays } // fill histograms - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hVtx3ProngX"), secondaryVertex3[0]); registry.fill(HIST("hVtx3ProngY"), secondaryVertex3[1]); registry.fill(HIST("hVtx3ProngZ"), secondaryVertex3[2]); @@ -2596,15 +2608,15 @@ struct HfTrackIndexSkimCreator { int isSelected3ProngCand = n3ProngBit; if (!TESTBIT(trackIndexNeg2.isSelProng(), CandidateType::Cand3Prong)) { // continue immediately - if (!debug) { + if (!config.debug) { continue; } else { isSelected3ProngCand = 0; } } - if (applyKaonPidIn3Prongs && !TESTBIT(trackIndexPos1.isIdentifiedPid(), channelKaonPid)) { // continue immediately if kaon PID enabled and opposite-sign track not a kaon - if (!debug) { + if (config.applyKaonPidIn3Prongs && !TESTBIT(trackIndexPos1.isIdentifiedPid(), ChannelKaonPid)) { // continue immediately if kaon PID enabled and opposite-sign track not a kaon + if (!config.debug) { continue; } else { isSelected3ProngCand = 0; @@ -2623,7 +2635,7 @@ struct HfTrackIndexSkimCreator { getPxPyPz(trackParVarNeg2, pVecTrackNeg2); } - if (debug) { + if (config.debug) { for (int iDecay3P = 0; iDecay3P < kN3ProngDecays; iDecay3P++) { for (int iCut = 0; iCut < kNCuts3Prong[iDecay3P]; iCut++) { cutStatus3Prong[iDecay3P][iCut] = true; @@ -2635,7 +2647,7 @@ struct HfTrackIndexSkimCreator { int8_t isIdentifiedPidTrackNeg1 = trackIndexNeg1.isIdentifiedPid(); int8_t isIdentifiedPidTrackNeg2 = trackIndexNeg2.isIdentifiedPid(); applyPreselection3Prong(pVecTrackNeg1, pVecTrackPos1, pVecTrackNeg2, isIdentifiedPidTrackNeg1, isIdentifiedPidTrackNeg2, cutStatus3Prong, whichHypo3Prong, isSelected3ProngCand); - if (!debug && isSelected3ProngCand == 0) { + if (!config.debug && isSelected3ProngCand == 0) { continue; } } @@ -2644,7 +2656,7 @@ struct HfTrackIndexSkimCreator { std::array pvRefitCoord3Prong1Pos2Neg = {collision.posX(), collision.posY(), collision.posZ()}; /// initialize to the original PV std::array pvRefitCovMatrix3Prong1Pos2Neg = getPrimaryVertex(collision).getCov(); /// initialize to the original PV if constexpr (doPvRefit) { - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("PvRefit/verticesPerCandidate"), 1); } int nCandContr = 3; @@ -2656,7 +2668,7 @@ struct HfTrackIndexSkimCreator { bool isTrackThirdContr = true; if (trackFirstIt == vecPvContributorGlobId.end()) { /// This track did not contribute to the original PV refit - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "--- [3 prong] trackPos1 with globalIndex " << trackPos1.globalIndex() << " was not a PV contributor"; } nCandContr--; @@ -2664,7 +2676,7 @@ struct HfTrackIndexSkimCreator { } if (trackSecondIt == vecPvContributorGlobId.end()) { /// This track did not contribute to the original PV refit - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "--- [3 prong] trackNeg1 with globalIndex " << trackNeg1.globalIndex() << " was not a PV contributor"; } nCandContr--; @@ -2672,7 +2684,7 @@ struct HfTrackIndexSkimCreator { } if (trackThirdIt == vecPvContributorGlobId.end()) { /// This track did not contribute to the original PV refit - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "--- [3 prong] trackNeg2 with globalIndex " << trackNeg2.globalIndex() << " was not a PV contributor"; } nCandContr--; @@ -2693,16 +2705,16 @@ struct HfTrackIndexSkimCreator { if (nCandContr == 3 || nCandContr == 2) { /// At least two of the daughter tracks were used for the original PV refit, let's refit it after excluding them - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "### [3 prong] Calling performPvRefitCandProngs for HF 3 prong candidate, removing " << nCandContr << " daughters"; } performPvRefitCandProngs(collision, bcWithTimeStamps, vecPvContributorGlobId, vecPvContributorTrackParCov, vecCandPvContributorGlobId, pvRefitCoord3Prong1Pos2Neg, pvRefitCovMatrix3Prong1Pos2Neg); } else if (nCandContr == 1) { /// Only one daughter was a contributor, let's use then the PV recalculated by excluding only it - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "####### [3 Prong] nCandContr==" << nCandContr << " ---> just 1 contributor!"; } - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("PvRefit/verticesPerCandidate"), 5); } if (isTrackFirstContr && !isTrackSecondContr && !isTrackThirdContr) { @@ -2720,10 +2732,10 @@ struct HfTrackIndexSkimCreator { } } else { /// 0 contributors among the HF candidate daughters - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("PvRefit/verticesPerCandidate"), 6); } - if (debugPvRefit) { + if (config.debugPvRefit) { LOG(info) << "####### [3 prong] nCandContr==" << nCandContr << " ---> some of the candidate daughters did not contribute to the original PV fit, PV refit not redone"; } } @@ -2759,18 +2771,26 @@ struct HfTrackIndexSkimCreator { applySelection3Prong(pVecCandProng3Neg, secondaryVertex3, pvRefitCoord3Prong1Pos2Neg, cutStatus3Prong, isSelected3ProngCand); std::array, kN3ProngDecays> mlScores3Prongs; - if (applyMlForHfFilters) { + if (config.applyMlForHfFilters) { std::vector inputFeatures{trackParVarPcaNeg1.getPt(), dcaInfoNeg1[0], dcaInfoNeg1[1], trackParVarPcaPos1.getPt(), dcaInfoPos1[0], dcaInfoPos1[1], trackParVarPcaNeg2.getPt(), dcaInfoNeg2[0], dcaInfoNeg2[1]}; - applyMlSelectionForHfFilters3Prong(inputFeatures, mlScores3Prongs, isSelected3ProngCand); + std::vector inputFeaturesLcPid{}; + if constexpr (usePidForHfFiltersBdt) { + inputFeaturesLcPid.push_back(trackNeg1.tpcNSigmaPr()); + inputFeaturesLcPid.push_back(trackNeg2.tpcNSigmaPr()); + inputFeaturesLcPid.push_back(trackNeg1.tpcNSigmaPi()); + inputFeaturesLcPid.push_back(trackNeg2.tpcNSigmaPi()); + inputFeaturesLcPid.push_back(trackPos1.tpcNSigmaKa()); + } + applyMlSelectionForHfFilters3Prong(inputFeatures, inputFeaturesLcPid, mlScores3Prongs, isSelected3ProngCand); } - if (!debug && isSelected3ProngCand == 0) { + if (!config.debug && isSelected3ProngCand == 0) { continue; } // fill table row rowTrackIndexProng3(thisCollId, trackNeg1.globalIndex(), trackPos1.globalIndex(), trackNeg2.globalIndex(), isSelected3ProngCand); - if (applyMlForHfFilters) { + if (config.applyMlForHfFilters) { rowTrackIndexMlScoreProng3(mlScores3Prongs[0], mlScores3Prongs[1], mlScores3Prongs[2], mlScores3Prongs[3]); } // fill table row of coordinates of PV refit @@ -2779,21 +2799,21 @@ struct HfTrackIndexSkimCreator { pvRefitCovMatrix3Prong1Pos2Neg[0], pvRefitCovMatrix3Prong1Pos2Neg[1], pvRefitCovMatrix3Prong1Pos2Neg[2], pvRefitCovMatrix3Prong1Pos2Neg[3], pvRefitCovMatrix3Prong1Pos2Neg[4], pvRefitCovMatrix3Prong1Pos2Neg[5]); } - if (debug) { - int Prong3CutStatus[kN3ProngDecays]; + if (config.debug) { + int prong3CutStatus[kN3ProngDecays]; for (int iDecay3P = 0; iDecay3P < kN3ProngDecays; iDecay3P++) { - Prong3CutStatus[iDecay3P] = nCutStatus3ProngBit[iDecay3P]; + prong3CutStatus[iDecay3P] = nCutStatus3ProngBit[iDecay3P]; for (int iCut = 0; iCut < kNCuts3Prong[iDecay3P]; iCut++) { if (!cutStatus3Prong[iDecay3P][iCut]) { - CLRBIT(Prong3CutStatus[iDecay3P], iCut); + CLRBIT(prong3CutStatus[iDecay3P], iCut); } } } - rowProng3CutStatus(Prong3CutStatus[0], Prong3CutStatus[1], Prong3CutStatus[2], Prong3CutStatus[3]); // FIXME when we can do this by looping over kN3ProngDecays + rowProng3CutStatus(prong3CutStatus[0], prong3CutStatus[1], prong3CutStatus[2], prong3CutStatus[3]); // FIXME when we can do this by looping over kN3ProngDecays } // fill histograms - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hVtx3ProngX"), secondaryVertex3[0]); registry.fill(HIST("hVtx3ProngY"), secondaryVertex3[1]); registry.fill(HIST("hVtx3ProngZ"), secondaryVertex3[2]); @@ -2837,9 +2857,9 @@ struct HfTrackIndexSkimCreator { } } - if (doDstar && TESTBIT(isSelected2ProngCand, hf_cand_2prong::DecayType::D0ToPiK) && (pt2Prong + ptTolerance) * 1.2 > binsPtDstarToD0Pi->at(0) && whichHypo2Prong[kN2ProngDecays] != 0) { // if D* enabled and pt of the D0 is larger than the minimum of the D* one within 20% (D* and D0 momenta are very similar, always within 20% according to PYTHIA8) + if (config.doDstar && TESTBIT(isSelected2ProngCand, hf_cand_2prong::DecayType::D0ToPiK) && (pt2Prong + config.ptTolerance) * 1.2 > config.binsPtDstarToD0Pi->at(0) && whichHypo2Prong[kN2ProngDecays] != 0) { // if D* enabled and pt of the D0 is larger than the minimum of the D* one within 20% (D* and D0 momenta are very similar, always within 20% according to PYTHIA8) // second loop over positive tracks - if (TESTBIT(whichHypo2Prong[kN2ProngDecays], 0) && (!applyKaonPidIn3Prongs || TESTBIT(trackIndexNeg1.isIdentifiedPid(), channelKaonPid))) { // only for D0 candidates; moreover if kaon PID enabled, apply to the negative track + if (TESTBIT(whichHypo2Prong[kN2ProngDecays], 0) && (!config.applyKaonPidIn3Prongs || TESTBIT(trackIndexNeg1.isIdentifiedPid(), ChannelKaonPid))) { // only for D0 candidates; moreover if kaon PID enabled, apply to the negative track auto groupedTrackIndicesSoftPionsPos = positiveSoftPions->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); for (auto trackIndexPos2 = groupedTrackIndicesSoftPionsPos.begin(); trackIndexPos2 != groupedTrackIndicesSoftPionsPos.end(); ++trackIndexPos2) { if (trackIndexPos2 == trackIndexPos1) { @@ -2860,7 +2880,7 @@ struct HfTrackIndexSkimCreator { isSelectedDstar = applySelectionDstar(pVecTrackPos1, pVecTrackNeg1, pVecTrackPos2, cutStatus, deltaMass); // we do not compute the D* decay vertex at this stage because we are not interested in applying topological selections if (isSelectedDstar) { rowTrackIndexDstar(thisCollId, trackPos2.globalIndex(), lastFilledD0); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hMassDstarToD0Pi"), deltaMass); } if constexpr (doPvRefit) { @@ -2869,14 +2889,14 @@ struct HfTrackIndexSkimCreator { pvRefitCovMatrix2Prong[0], pvRefitCovMatrix2Prong[1], pvRefitCovMatrix2Prong[2], pvRefitCovMatrix2Prong[3], pvRefitCovMatrix2Prong[4], pvRefitCovMatrix2Prong[5]); } } - if (debug) { + if (config.debug) { rowDstarCutStatus(cutStatus); } } } // second loop over negative tracks - if (TESTBIT(whichHypo2Prong[kN2ProngDecays], 1) && (!applyKaonPidIn3Prongs || TESTBIT(trackIndexPos1.isIdentifiedPid(), channelKaonPid))) { // only for D0bar candidates; moreover if kaon PID enabled, apply to the positive track + if (TESTBIT(whichHypo2Prong[kN2ProngDecays], 1) && (!config.applyKaonPidIn3Prongs || TESTBIT(trackIndexPos1.isIdentifiedPid(), ChannelKaonPid))) { // only for D0bar candidates; moreover if kaon PID enabled, apply to the positive track auto groupedTrackIndicesSoftPionsNeg = negativeSoftPions->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); for (auto trackIndexNeg2 = groupedTrackIndicesSoftPionsNeg.begin(); trackIndexNeg2 != groupedTrackIndicesSoftPionsNeg.end(); ++trackIndexNeg2) { if (trackIndexNeg1 == trackIndexNeg2) { @@ -2897,7 +2917,7 @@ struct HfTrackIndexSkimCreator { isSelectedDstar = applySelectionDstar(pVecTrackNeg1, pVecTrackPos1, pVecTrackNeg2, cutStatus, deltaMass); // we do not compute the D* decay vertex at this stage because we are not interested in applying topological selections if (isSelectedDstar) { rowTrackIndexDstar(thisCollId, trackNeg2.globalIndex(), lastFilledD0); - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hMassDstarToD0Pi"), deltaMass); } if constexpr (doPvRefit) { @@ -2906,7 +2926,7 @@ struct HfTrackIndexSkimCreator { pvRefitCovMatrix2Prong[0], pvRefitCovMatrix2Prong[1], pvRefitCovMatrix2Prong[2], pvRefitCovMatrix2Prong[3], pvRefitCovMatrix2Prong[4], pvRefitCovMatrix2Prong[5]); } } - if (debug) { + if (config.debug) { rowDstarCutStatus(cutStatus); } } @@ -2920,7 +2940,7 @@ struct HfTrackIndexSkimCreator { nCand2 = rowTrackIndexProng2.lastIndex() - nCand2; // number of 2-prong candidates in this collision nCand3 = rowTrackIndexProng3.lastIndex() - nCand3; // number of 3-prong candidates in this collision - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hNTracks"), nTracks); registry.fill(HIST("hNCand2Prong"), nCand2); registry.fill(HIST("hNCand3Prong"), nCand3); @@ -2955,6 +2975,26 @@ struct HfTrackIndexSkimCreator { run2And3Prongs(collisions, bcWithTimeStamps, trackIndices, tracks); } PROCESS_SWITCH(HfTrackIndexSkimCreator, process2And3ProngsNoPvRefit, "Process 2-prong and 3-prong skim without PV refit", true); + + void process2And3ProngsWithPvRefitWithPidForHfFiltersBdt( // soa::Join::iterator const& collision, //FIXME add centrality when option for variations to the process function appears + SelectedCollisions const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + FilteredTrackAssocSel const& trackIndices, + soa::Join const& tracks) + { + run2And3Prongs(collisions, bcWithTimeStamps, trackIndices, tracks); + } + PROCESS_SWITCH(HfTrackIndexSkimCreator, process2And3ProngsWithPvRefitWithPidForHfFiltersBdt, "Process 2-prong and 3-prong skim with PV refit and PID for software trigger BDTs (Lc and Xic only)", false); + + void process2And3ProngsNoPvRefitWithPidForHfFiltersBdt( // soa::Join::iterator const& collision, //FIXME add centrality when option for variations to the process function appears + SelectedCollisions const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + FilteredTrackAssocSel const& trackIndices, + soa::Join const& tracks) + { + run2And3Prongs(collisions, bcWithTimeStamps, trackIndices, tracks); + } + PROCESS_SWITCH(HfTrackIndexSkimCreator, process2And3ProngsNoPvRefitWithPidForHfFiltersBdt, "Process 2-prong and 3-prong skim without PV refit and PID for software trigger BDTs (Lc and Xic only)", false); }; //________________________________________________________________________________________________________________________ @@ -2969,68 +3009,56 @@ struct HfTrackIndexSkimCreator { struct HfTrackIndexSkimCreatorCascades { Produces rowTrackIndexCasc; - Configurable isRun2{"isRun2", false, "enable Run 2 or Run 3 GRP objects for magnetic field"}; - Configurable fillHistograms{"fillHistograms", true, "fill histograms"}; - // event selection - // Configurable triggerindex{"triggerindex", -1, "trigger index"}; - // vertexing - // Configurable bz{"bz", 5., "magnetic field"}; - Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; - Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; - Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; - Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; - Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations if chi2/chi2old > this"}; - Configurable useAbsDCA{"useAbsDCA", true, "Minimise abs. distance rather than chi2"}; - Configurable useWeightedFinalPCA{"useWeightedFinalPCA", true, "Recalculate vertex position using track covariances, effective only if useAbsDCA is true"}; - // quality cut - Configurable doCutQuality{"doCutQuality", true, "apply quality cuts"}; - // track cuts for bachelor - Configurable tpcRefitBach{"tpcRefitBach", true, "request TPC refit bachelor"}; - Configurable nCrossedRowsMinBach{"nCrossedRowsMinBach", 50, "min crossed rows bachelor"}; - // track cuts for V0 daughters - Configurable tpcRefitV0Daugh{"tpcRefitV0Daugh", true, "request TPC refit V0 daughters"}; - Configurable nCrossedRowsMinV0Daugh{"nCrossedRowsMinV0Daugh", 50, "min crossed rows V0 daughters"}; - Configurable etaMinV0Daugh{"etaMinV0Daugh", -99999., "min. pseudorapidity V0 daughters"}; - Configurable etaMaxV0Daugh{"etaMaxV0Daugh", 1.1, "max. pseudorapidity V0 daughters"}; - Configurable ptMinV0Daugh{"ptMinV0Daugh", 0.05, "min. pT V0 daughters"}; - // bachelor cuts - // Configurable dcabachtopv{"dcabachtopv", .1, "DCA Bach To PV"}; - // Configurable ptminbach{"ptminbach", -1., "min. track pT bachelor"}; - // v0 cuts - Configurable cpaV0Min{"cpaV0Min", .995, "min. cos PA V0"}; // as in the task that create the V0s - Configurable dcaXYNegToPvMin{"dcaXYNegToPvMin", .1, "min. DCA_XY Neg To PV"}; // check: in HF Run 2, it was 0 at filtering - Configurable dcaXYPosToPvMin{"dcaXYPosToPvMin", .1, "min. DCA_XY Pos To PV"}; // check: in HF Run 2, it was 0 at filtering - Configurable cutInvMassV0{"cutInvMassV0", 0.05, "V0 candidate invariant mass difference wrt PDG"}; - // cascade cuts - Configurable ptCascCandMin{"ptCascCandMin", -1., "min. pT of the cascade candidate"}; // PbPb 2018: use 1 - Configurable cutInvMassCascLc{"cutInvMassCascLc", 1., "Lc candidate invariant mass difference wrt PDG"}; // for PbPb 2018: use 0.2 - // Configurable cutCascDCADaughters{"cutCascDCADaughters", .1, "DCA between V0 and bachelor in cascade"}; - // proton PID - Configurable applyProtonPid{"applyProtonPid", false, "Apply proton PID for Lc->pK0S"}; - - // CCDB - Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; - Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; - Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + struct : ConfigurableGroup { + Configurable isRun2{"isRun2", false, "enable Run 2 or Run 3 GRP objects for magnetic field"}; + Configurable fillHistograms{"fillHistograms", true, "fill histograms"}; + // vertexing + Configurable useDCAFitter{"useDCAFitter", true, "flag to optionally turn on/off the vertex reconstruction with the DCAFitter"}; + Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; + Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; + Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; + Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations if chi2/chi2old > this"}; + Configurable useAbsDCA{"useAbsDCA", true, "Minimise abs. distance rather than chi2"}; + Configurable useWeightedFinalPCA{"useWeightedFinalPCA", true, "Recalculate vertex position using track covariances, effective only if useAbsDCA is true"}; + // track cuts for V0 daughters + Configurable etaMinV0Daugh{"etaMinV0Daugh", -99999., "min. pseudorapidity V0 daughters"}; + Configurable etaMaxV0Daugh{"etaMaxV0Daugh", 1.1, "max. pseudorapidity V0 daughters"}; + Configurable ptMinV0Daugh{"ptMinV0Daugh", 0.05, "min. pT V0 daughters"}; + // v0 cuts + Configurable cpaV0Min{"cpaV0Min", 0.95, "min. cos PA V0"}; // as in the task that create the V0s + Configurable cutInvMassV0{"cutInvMassV0", 0.05, "V0 candidate invariant mass difference wrt PDG"}; + // cascade cuts + Configurable ptCascCandMin{"ptCascCandMin", -1., "min. pT of the cascade candidate"}; // PbPb 2018: use 1 + Configurable cutInvMassCascLc{"cutInvMassCascLc", 1., "Lc candidate invariant mass difference wrt PDG"}; // for PbPb 2018: use 0.2 + // Configurable cutCascDCADaughters{"cutCascDCADaughters", .1, "DCA between V0 and bachelor in cascade"}; + // proton PID + Configurable applyProtonPid{"applyProtonPid", false, "Apply proton PID for Lc->pK0S"}; + + // CCDB + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; + Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + } config; o2::vertexing::DCAFitterN<2> df2; // 2-prong vertex fitter // Needed for PV refitting Service ccdb; o2::base::MatLayerCylSet* lut; o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - int runNumber; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + int runNumber{0}; double massP{0.}; double massK0s{0.}; - double massPi{0.}; double massLc{0.}; using SelectedCollisions = soa::Filtered>; using FilteredTrackAssocSel = soa::Filtered>; Filter filterSelectCollisions = (aod::hf_sel_collision::whyRejectColl == static_cast(0)); - Filter filterSelectTrackIds = (aod::hf_sel_track::isSelProng & static_cast(BIT(CandidateType::CandV0bachelor))) != 0u && (applyProtonPid == false || (aod::hf_sel_track::isIdentifiedPid & static_cast(BIT(ChannelsProtonPid::LcToPK0S))) != 0u); + Filter filterSelectTrackIds = (aod::hf_sel_track::isSelProng & static_cast(BIT(CandidateType::CandV0bachelor))) != 0u && (config.applyProtonPid == false || (aod::hf_sel_track::isIdentifiedPid & static_cast(BIT(ChannelsProtonPid::LcToPK0S))) != 0u); Preslice trackIndicesPerCollision = aod::track_association::collisionId; Preslice v0sPerCollision = aod::v0data::collisionId; @@ -3044,35 +3072,34 @@ struct HfTrackIndexSkimCreatorCascades { return; } - if (etaMinV0Daugh == -99999.) { - etaMinV0Daugh.value = -etaMaxV0Daugh; + if (config.etaMinV0Daugh == -99999.) { + config.etaMinV0Daugh.value = -config.etaMaxV0Daugh; } massP = o2::constants::physics::MassProton; massK0s = o2::constants::physics::MassK0Short; - massPi = o2::constants::physics::MassPiPlus; massLc = o2::constants::physics::MassLambdaCPlus; - df2.setPropagateToPCA(propagateToPCA); - df2.setMaxR(maxR); - df2.setMinParamChange(minParamChange); - df2.setMinRelChi2Change(minRelChi2Change); - // df2.setMaxDZIni(1e9); // used in cascadeproducer.cxx, but not for the 2 prongs - // df2.setMaxChi2(1e9); // used in cascadeproducer.cxx, but not for the 2 prongs - df2.setUseAbsDCA(useAbsDCA); - df2.setWeightedFinalPCA(useWeightedFinalPCA); + if (config.useDCAFitter) { + df2.setPropagateToPCA(config.propagateToPCA); + df2.setMaxR(config.maxR); + df2.setMinParamChange(config.minParamChange); + df2.setMinRelChi2Change(config.minRelChi2Change); + df2.setMaxDZIni(config.maxDZIni); + df2.setUseAbsDCA(config.useAbsDCA); + df2.setWeightedFinalPCA(config.useWeightedFinalPCA); + } - ccdb->setURL(ccdbUrl); + ccdb->setURL(config.ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); - runNumber = 0; + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(config.ccdbPathLut)); - if (fillHistograms) { - registry.add("hVtx2ProngX", "2-prong candidates;#it{x}_{sec. vtx.} (cm);entries", {HistType::kTH1F, {{1000, -2., 2.}}}); - registry.add("hVtx2ProngY", "2-prong candidates;#it{y}_{sec. vtx.} (cm);entries", {HistType::kTH1F, {{1000, -2., 2.}}}); - registry.add("hVtx2ProngZ", "2-prong candidates;#it{z}_{sec. vtx.} (cm);entries", {HistType::kTH1F, {{1000, -2., 2.}}}); - registry.add("hMassLcToPK0S", "#Lambda_{c}^ candidates;inv. mass (p K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0., 5.}}}); + if (config.fillHistograms) { + registry.add("hVtx2ProngX", "2-prong candidates;#it{x}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -2., 2.}}}); + registry.add("hVtx2ProngY", "2-prong candidates;#it{y}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -2., 2.}}}); + registry.add("hVtx2ProngZ", "2-prong candidates;#it{z}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -2., 2.}}}); + registry.add("hMassLcToPK0S", "#Lambda_{c}^ candidates;inv. mass (p K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); } } @@ -3083,7 +3110,7 @@ struct HfTrackIndexSkimCreatorCascades { PROCESS_SWITCH(HfTrackIndexSkimCreatorCascades, processNoCascades, "Do not skim HF -> V0 cascades", true); void processCascades(SelectedCollisions const& collisions, - aod::V0Datas const& v0s, + soa::Join const& v0s, FilteredTrackAssocSel const& trackIndices, aod::TracksWCovDcaExtra const&, aod::BCsWithTimestamps const&) @@ -3091,145 +3118,135 @@ struct HfTrackIndexSkimCreatorCascades { // set the magnetic field from CCDB for (const auto& collision : collisions) { auto bc = collision.bc_as(); - initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, lut, isRun2); - df2.setBz(o2::base::Propagator::Instance()->getNominalBz()); - - // fist we loop over the bachelor candidate + initCCDB(bc, runNumber, ccdb, config.isRun2 ? config.ccdbPathGrp : config.ccdbPathGrpMag, lut, config.isRun2); + if (config.useDCAFitter) { + df2.setBz(o2::base::Propagator::Instance()->getNominalBz()); + df2.setMatCorrType(matCorr); + } const auto thisCollId = collision.globalIndex(); auto groupedBachTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + auto groupedV0s = v0s.sliceBy(v0sPerCollision, thisCollId); - // for (const auto& bach : selectedTracks) { + // fist we loop over the bachelor candidate for (const auto& bachIdx : groupedBachTrackIndices) { auto bach = bachIdx.track_as(); - - // selections on the bachelor - - // pT cut - // FIXME: this should go in the tag-sel-tracks - if (tpcRefitBach) { - if (!(bach.trackType() & o2::aod::track::TPCrefit)) { - continue; - } - } - if (bach.tpcNClsCrossedRows() < nCrossedRowsMinBach) { - continue; - } - + std::array pVecBach{bach.pVector()}; auto trackBach = getTrackParCov(bach); + if (thisCollId != bach.collisionId()) { // this is not the "default" collision for this track, we have to re-propagate it + o2::gpu::gpustd::array dcaInfoBach{bach.dcaXY(), bach.dcaZ()}; + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackBach, 2.f, noMatCorr, &dcaInfoBach); + getPxPyPz(trackBach, pVecBach); + } - auto groupedV0s = v0s.sliceBy(v0sPerCollision, thisCollId); // now we loop over the V0s for (const auto& v0 : groupedV0s) { // selections on the V0 daughters - const auto& trackV0DaughPos = v0.posTrack_as(); - const auto& trackV0DaughNeg = v0.negTrack_as(); + const auto& trackV0DaughPos = v0.posTrack_as(); // only used for indices and track cuts (TPC clusters, TPC refit) + const auto& trackV0DaughNeg = v0.negTrack_as(); // only used for indices and track cuts (TPC clusters, TPC refit) // check not to take the same track twice (as bachelor and V0 daughter) if (trackV0DaughPos.globalIndex() == bach.globalIndex() || trackV0DaughNeg.globalIndex() == bach.globalIndex()) { continue; } - if (tpcRefitV0Daugh) { - if (!(trackV0DaughPos.trackType() & o2::aod::track::TPCrefit) || - !(trackV0DaughNeg.trackType() & o2::aod::track::TPCrefit)) { - continue; - } - } - if (trackV0DaughPos.tpcNClsCrossedRows() < nCrossedRowsMinV0Daugh || - trackV0DaughNeg.tpcNClsCrossedRows() < nCrossedRowsMinV0Daugh) { - continue; - } - // - // if (trackV0DaughPos.dcaXY() < dcaXYPosToPvMin || // to the filters? - // trackV0DaughNeg.dcaXY() < dcaXYNegToPvMin) { - // continue; - // } - // - if (trackV0DaughPos.pt() < ptMinV0Daugh || // to the filters? I can't for now, it is not in the tables - trackV0DaughNeg.pt() < ptMinV0Daugh) { + std::array pVecPos = {v0.pxpos(), v0.pypos(), v0.pzpos()}; + std::array pVecNeg = {v0.pxneg(), v0.pyneg(), v0.pzneg()}; + + float ptPos = RecoDecay::pt(pVecPos); + float ptNeg = RecoDecay::pt(pVecNeg); + if (ptPos < config.ptMinV0Daugh || // to the filters? I can't for now, it is not in the tables + ptNeg < config.ptMinV0Daugh) { continue; } - if ((trackV0DaughPos.eta() > etaMaxV0Daugh || trackV0DaughPos.eta() < etaMinV0Daugh) || // to the filters? I can't for now, it is not in the tables - (trackV0DaughNeg.eta() > etaMaxV0Daugh || trackV0DaughNeg.eta() < etaMinV0Daugh)) { + + float etaPos = RecoDecay::eta(pVecPos); + float etaNeg = RecoDecay::eta(pVecNeg); + if ((etaPos > config.etaMaxV0Daugh || etaPos < config.etaMinV0Daugh) || // to the filters? I can't for now, it is not in the tables + (etaNeg > config.etaMaxV0Daugh || etaNeg < config.etaMinV0Daugh)) { continue; } // V0 invariant mass selection - if (std::abs(v0.mK0Short() - massK0s) > cutInvMassV0) { + if (std::abs(v0.mK0Short() - massK0s) > config.cutInvMassV0) { continue; // should go to the filter, but since it is a dynamic column, I cannot use it there } // V0 cosPointingAngle selection - if (v0.v0cosPA() < cpaV0Min) { + if (v0.v0cosPA() < config.cpaV0Min) { continue; } - const std::array momentumV0 = {v0.px(), v0.py(), v0.pz()}; + std::array pVecV0 = {v0.px(), v0.py(), v0.pz()}; // invariant-mass cut: we do it here, before updating the momenta of bach and V0 during the fitting to save CPU // TODO: but one should better check that the value here and after the fitter do not change significantly!!! - double mass2K0sP = RecoDecay::m(std::array{bach.pVector(), momentumV0}, std::array{massP, massK0s}); - if ((cutInvMassCascLc >= 0.) && (std::abs(mass2K0sP - massLc) > cutInvMassCascLc)) { + double mass2K0sP = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{massP, massK0s}); + if ((config.cutInvMassCascLc >= 0.) && (std::abs(mass2K0sP - massLc) > config.cutInvMassCascLc)) { continue; } - auto trackParCovV0DaughPos = getTrackParCov(trackV0DaughPos); - trackParCovV0DaughPos.propagateTo(v0.posX(), o2::base::Propagator::Instance()->getNominalBz()); // propagate the track to the X closest to the V0 vertex - auto trackParCovV0DaughNeg = getTrackParCov(trackV0DaughNeg); - trackParCovV0DaughNeg.propagateTo(v0.negX(), o2::base::Propagator::Instance()->getNominalBz()); // propagate the track to the X closest to the V0 vertex - std::array pVecV0 = {0., 0., 0.}; - std::array pVecBach = {0., 0., 0.}; - - const std::array vertexV0 = {v0.x(), v0.y(), v0.z()}; - // we build the neutral track to then build the cascade - auto trackV0 = o2::dataformats::V0(vertexV0, momentumV0, {0, 0, 0, 0, 0, 0}, trackParCovV0DaughPos, trackParCovV0DaughNeg); // build the V0 track - // now we find the DCA between the V0 and the bachelor, for the cascade - int nCand2 = 0; - try { - nCand2 = df2.process(trackV0, trackBach); - } catch (...) { - continue; - } + if (config.useDCAFitter) { + + const std::array vertexV0 = {v0.x(), v0.y(), v0.z()}; + // we build the neutral track to then build the cascade + std::array covV = {0.}; + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 6; i++) { + covV[MomInd[i]] = v0.momentumCovMat()[i]; + covV[i] = v0.positionCovMat()[i]; + } + auto trackV0 = o2::track::TrackParCov(vertexV0, pVecV0, covV, 0, true); + trackV0.setAbsCharge(0); + trackV0.setPID(o2::track::PID::K0); - if (nCand2 == 0) { - continue; + int nCand2 = 0; + try { + nCand2 = df2.process(trackV0, trackBach); + } catch (...) { + continue; + } + + if (nCand2 == 0) { + continue; + } + df2.propagateTracksToVertex(); // propagate the bach and V0 to the Lc vertex + df2.getTrack(0).getPxPyPzGlo(pVecV0); // take the momentum at the Lc vertex + df2.getTrack(1).getPxPyPzGlo(pVecBach); } - df2.propagateTracksToVertex(); // propagate the bach and V0 to the Lc vertex - df2.getTrack(0).getPxPyPzGlo(pVecV0); // take the momentum at the Lc vertex - df2.getTrack(1).getPxPyPzGlo(pVecBach); // cascade candidate pT cut auto ptCascCand = RecoDecay::pt(pVecBach, pVecV0); - if (ptCascCand < ptCascCandMin) { + if (ptCascCand < config.ptCascCandMin) { continue; } // invariant mass // re-calculate invariant masses with updated momenta, to fill the histogram mass2K0sP = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{massP, massK0s}); - std::array posCasc = {0., 0., 0.}; - const auto& cascVtx = df2.getPCACandidate(); - for (int i = 0; i < 3; i++) { - posCasc[i] = cascVtx[i]; + if (config.useDCAFitter) { + const auto& cascVtx = df2.getPCACandidate(); + for (int iCoord{0}; iCoord < 3; ++iCoord) { + posCasc[iCoord] = cascVtx[iCoord]; + } } // fill table row rowTrackIndexCasc(thisCollId, bach.globalIndex(), v0.v0Id()); // fill histograms - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hVtx2ProngX"), posCasc[0]); registry.fill(HIST("hVtx2ProngY"), posCasc[1]); registry.fill(HIST("hVtx2ProngZ"), posCasc[2]); registry.fill(HIST("hMassLcToPK0S"), mass2K0sP); } } // loop over V0s - } // loop over tracks - } // loop over collisions - } // processCascades + } // loop over tracks + } // loop over collisions + } // processCascades PROCESS_SWITCH(HfTrackIndexSkimCreatorCascades, processCascades, "Skim HF -> V0 cascades", false); }; @@ -3237,55 +3254,61 @@ struct HfTrackIndexSkimCreatorLfCascades { Produces rowTrackIndexCasc2Prong; Produces rowTrackIndexCasc3Prong; - // whether to do or not validation plots - Configurable fillHistograms{"fillHistograms", true, "fill histograms"}; - - Configurable do3Prong{"do3Prong", false, "do 3-prong cascade"}; - Configurable rejDiffCollTrack{"rejDiffCollTrack", false, "Reject tracks coming from different collisions"}; - - // charm baryon invariant mass spectra limits - Configurable massXiPiMin{"massXiPiMin", 2.1, "Invariant mass lower limit for xi pi decay channel"}; - Configurable massXiPiMax{"massXiPiMax", 3., "Invariant mass upper limit for xi pi decay channel"}; - Configurable massOmegaPiMin{"massOmegaPiMin", 2.4, "Invariant mass lower limit for omega pi decay channel"}; - Configurable massOmegaPiMax{"massOmegaPiMax", 3., "Invariant mass upper limit for omega pi decay channel"}; - Configurable massXiPiPiMin{"massXiPiPiMin", 2.1, "Invariant mass lower limit for xi pi pi decay channel"}; - Configurable massXiPiPiMax{"massXiPiPiMax", 2.8, "Invariant mass upper limit for xi pi pi decay channel"}; - - // DCAFitter settings - Configurable propagateToPCA{"propagateToPCA", false, "create tracks version propagated to PCA"}; - Configurable useAbsDCA{"useAbsDCA", true, "Minimise abs. distance rather than chi2"}; - Configurable useWeightedFinalPCA{"useWeightedFinalPCA", true, "Recalculate vertex position using track covariances, effective only if useAbsDCA is true"}; - Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; - Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; - Configurable maxDXYIni{"maxDXYIni", 4., "reject (if>0) PCA candidate if tracks DXY exceeds threshold"}; - Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; - Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations is chi2/chi2old > this"}; - Configurable maxChi2{"maxChi2", 100., "discard vertices with chi2/Nprongs > this (or sum{DCAi^2}/Nprongs for abs. distance minimization)"}; - Configurable refitWithMatCorr{"refitWithMatCorr", true, "when doing propagateTracksToVertex, propagate tracks to vtx with material corrections and rerun minimization"}; - - // Selection criteria - // selections have been set to run2 lambda dedicated cuts - // selections for cascade have been set to the loosest value between xi and omega - // a tolerance has been added to be more conservative - Configurable v0TransvRadius{"v0TransvRadius", 1.0, "V0 radius in xy plane"}; // 1.2 (xi) and 1.1 (omega) in run2 - Configurable cascTransvRadius{"cascTransvRadius", 0.4, "Cascade radius in xy plane"}; // 0.5 cm (xi) and 0.6 (omega) in run2 - Configurable dcaBachToPv{"dcaBachToPv", 0.03, "DCA Bach To PV"}; // 0.04 in run2 - Configurable dcaV0ToPv{"dcaV0ToPv", 0.02, "DCA V0 To PV"}; // 0.03 in run2 - Configurable v0CosPA{"v0CosPA", 0.95, "V0 CosPA"}; // 0.97 in run2 - KEEP LOSE to re-cut after PVRefit! - double -> N.B. dcos(x)/dx = 0 at x=0) - Configurable cascCosPA{"cascCosPA", 0.95, "Casc CosPA"}; // 0.97 in run2 - KEEP LOSE to re-cut after PVRefit! - double -> N.B. dcos(x)/dx = 0 at x=0) - Configurable dcaV0Dau{"dcaV0Dau", 2.0, "DCA V0 Daughters"}; // conservative, a cut ar 1.0 should also be fine - Configurable dcaCascDau{"dcaCascDau", 2.0, "DCA Casc Daughters"}; // conservative, a cut ar 1.0 should also be fine - Configurable dcaNegToPv{"dcaNegToPv", 0.05, "DCA Neg To PV"}; // 0.06 in run2 - Configurable dcaPosToPv{"dcaPosToPv", 0.05, "DCA Pos To PV"}; // 0.06 in run2 - Configurable v0MassWindow{"v0MassWindow", 0.01, "V0 mass window"}; // 0.008 in run2 - Configurable cascadeMassWindow{"cascadeMassWindow", 0.01, "Cascade mass window"}; - - // magnetic field setting from CCDB - Configurable isRun2{"isRun2", false, "enable Run 2 or Run 3 GRP objects for magnetic field"}; - Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; - Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; - Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + struct : ConfigurableGroup { + // whether to do or not validation plots + Configurable fillHistograms{"fillHistograms", true, "fill histograms"}; + + Configurable do3Prong{"do3Prong", false, "do 3-prong cascade"}; + Configurable rejDiffCollTrack{"rejDiffCollTrack", false, "Reject tracks coming from different collisions"}; + + // charm baryon invariant mass spectra limits + Configurable massXiPiMin{"massXiPiMin", 2.1, "Invariant mass lower limit for xi pi decay channel"}; + Configurable massXiPiMax{"massXiPiMax", 3., "Invariant mass upper limit for xi pi decay channel"}; + Configurable massOmegaCharmBachelorMin{"massOmegaCharmBachelorMin", 2.4, "Invariant mass lower limit for omega pi and omega k decay channel"}; + Configurable massOmegaCharmBachelorMax{"massOmegaCharmBachelorMax", 3., "Invariant mass upper limit for omega pi and omega k decay channel"}; + Configurable massXiPiPiMin{"massXiPiPiMin", 2.1, "Invariant mass lower limit for xi pi pi decay channel"}; + Configurable massXiPiPiMax{"massXiPiPiMax", 2.8, "Invariant mass upper limit for xi pi pi decay channel"}; + + // DCAFitter settings + Configurable propagateToPCA{"propagateToPCA", false, "create tracks version propagated to PCA"}; + Configurable useAbsDCA{"useAbsDCA", true, "Minimise abs. distance rather than chi2"}; + Configurable useWeightedFinalPCA{"useWeightedFinalPCA", true, "Recalculate vertex position using track covariances, effective only if useAbsDCA is true"}; + Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; + Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; + Configurable maxDXYIni{"maxDXYIni", 4., "reject (if>0) PCA candidate if tracks DXY exceeds threshold"}; + Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations is chi2/chi2old > this"}; + Configurable maxChi2{"maxChi2", 100., "discard vertices with chi2/Nprongs > this (or sum{DCAi^2}/Nprongs for abs. distance minimization)"}; + Configurable refitWithMatCorr{"refitWithMatCorr", true, "when doing propagateTracksToVertex, propagate tracks to vtx with material corrections and rerun minimization"}; + + // Selection criteria + // selections have been set to run2 lambda dedicated cuts + // selections for cascade have been set to the loosest value between xi and omega + // a tolerance has been added to be more conservative ptMinOmegaczeroToOmegaKaLfCasc ptMinXicZeroOmegacZeroToXiPiLfCasc + Configurable ptMinOmegacZeroToOmegaPiLfCasc{"ptMinOmegacZeroToOmegaPiLfCasc", 0.f, "min. pT for Omegaczero in Omega + Pi decays"}; + Configurable ptMinOmegaczeroToOmegaKaLfCasc{"ptMinOmegaczeroToOmegaKaLfCasc", 0.f, "min. pT for Omegaczero in Omega + Ka decays"}; + Configurable ptMinXicZeroOmegacZeroToXiPiLfCasc{"ptMinXicZeroOmegacZeroToXiPiLfCasc", 0.f, "min. pT for XicZeroOmegacZero in Xi + Pi decays"}; + Configurable ptMinXicplusLfCasc{"ptMinXicplusLfCasc", 0.f, "min. pT for Xicplus in Xi + Pi + Pi decays"}; + Configurable v0TransvRadius{"v0TransvRadius", 1.0, "V0 radius in xy plane"}; // 1.2 (xi) and 1.1 (omega) in run2 + Configurable cascTransvRadius{"cascTransvRadius", 0.4, "Cascade radius in xy plane"}; // 0.5 cm (xi) and 0.6 (omega) in run2 + Configurable dcaBachToPv{"dcaBachToPv", 0.03, "DCA Bach To PV"}; // 0.04 in run2 + Configurable dcaV0ToPv{"dcaV0ToPv", 0.02, "DCA V0 To PV"}; // 0.03 in run2 + Configurable v0CosPA{"v0CosPA", 0.95, "V0 CosPA"}; // 0.97 in run2 - KEEP LOSE to re-cut after PVRefit! - double -> N.B. dcos(x)/dx = 0 at x=0) + Configurable cascCosPA{"cascCosPA", 0.95, "Casc CosPA"}; // 0.97 in run2 - KEEP LOSE to re-cut after PVRefit! - double -> N.B. dcos(x)/dx = 0 at x=0) + Configurable dcaV0Dau{"dcaV0Dau", 2.0, "DCA V0 Daughters"}; // conservative, a cut ar 1.0 should also be fine + Configurable dcaCascDau{"dcaCascDau", 2.0, "DCA Casc Daughters"}; // conservative, a cut ar 1.0 should also be fine + Configurable dcaNegToPv{"dcaNegToPv", 0.05, "DCA Neg To PV"}; // 0.06 in run2 + Configurable dcaPosToPv{"dcaPosToPv", 0.05, "DCA Pos To PV"}; // 0.06 in run2 + Configurable v0MassWindow{"v0MassWindow", 0.01, "V0 mass window"}; // 0.008 in run2 + Configurable cascadeMassWindow{"cascadeMassWindow", 0.01, "Cascade mass window"}; + + // magnetic field setting from CCDB + Configurable isRun2{"isRun2", false, "enable Run 2 or Run 3 GRP objects for magnetic field"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; + Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + } config; o2::vertexing::DCAFitterN<2> df2; // 2-prong vertex fitter o2::vertexing::DCAFitterN<3> df3; // 3-prong vertex fitter @@ -3303,6 +3326,7 @@ struct HfTrackIndexSkimCreatorLfCascades { // PDG masses double massP{0.}; double massPi{0.}; + double massKaon{0.}; double massXi{0.}; double massOmega{0.}; double massLambda{0.}; @@ -3330,66 +3354,79 @@ struct HfTrackIndexSkimCreatorLfCascades { massP = o2::constants::physics::MassProton; massPi = o2::constants::physics::MassPiPlus; + massKaon = o2::constants::physics::MassKPlus; massXi = o2::constants::physics::MassXiMinus; massOmega = o2::constants::physics::MassOmegaMinus; massLambda = o2::constants::physics::MassLambda0; arrMass2Prong[hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi] = std::array{massXi, massPi}; arrMass2Prong[hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi] = std::array{massOmega, massPi}; + arrMass2Prong[hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK] = std::array{massOmega, massKaon}; arrMass3Prong[hf_cand_casc_lf::DecayType3Prong::XicplusToXiPiPi] = std::array{massXi, massPi, massPi}; - df2.setPropagateToPCA(propagateToPCA); - df2.setMaxR(maxR); - df2.setMaxDZIni(maxDZIni); - df2.setMinParamChange(minParamChange); - df2.setMinRelChi2Change(minRelChi2Change); - df2.setUseAbsDCA(useAbsDCA); - df2.setWeightedFinalPCA(useWeightedFinalPCA); - - df3.setPropagateToPCA(propagateToPCA); - df3.setMaxR(maxR); - df3.setMaxDZIni(maxDZIni); - df3.setMinParamChange(minParamChange); - df3.setMinRelChi2Change(minRelChi2Change); - df3.setUseAbsDCA(useAbsDCA); - df3.setWeightedFinalPCA(useWeightedFinalPCA); - - ccdb->setURL(ccdbUrl); + df2.setPropagateToPCA(config.propagateToPCA); + df2.setMaxR(config.maxR); + df2.setMaxDZIni(config.maxDZIni); + df2.setMinParamChange(config.minParamChange); + df2.setMinRelChi2Change(config.minRelChi2Change); + df2.setUseAbsDCA(config.useAbsDCA); + df2.setWeightedFinalPCA(config.useWeightedFinalPCA); + + df3.setPropagateToPCA(config.propagateToPCA); + df3.setMaxR(config.maxR); + df3.setMaxDZIni(config.maxDZIni); + df3.setMinParamChange(config.minParamChange); + df3.setMinRelChi2Change(config.minRelChi2Change); + df3.setUseAbsDCA(config.useAbsDCA); + df3.setWeightedFinalPCA(config.useWeightedFinalPCA); + + ccdb->setURL(config.ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(config.ccdbPathLut)); runNumber = 0; - if (fillHistograms) { + if (config.fillHistograms) { AxisSpec ptAxis = {400, 0.0f, 20.0f, "it{p}_{T} (GeV/c)"}; AxisSpec massAxisXi = {200, 1.222f, 1.422f, "Inv. Mass (GeV/c^{2})"}; AxisSpec massAxisOmega = {200, 1.572f, 1.772f, "Inv. Mass (GeV/c^{2})"}; - registry.add("hCandidateCounter", "hCandidateCounter", {HistType::kTH1F, {{10, 0.0f, 10.0f}}}); + registry.add("hCandidateCounter", "hCandidateCounter", {HistType::kTH1D, {{10, 0.0f, 10.0f}}}); // Cascade mass spectra - registry.add("hMassXiMinus", "hMassXiMinus", {HistType::kTH1F, {{400, 1.122f, 1.522f, "Inv. Mass (GeV/c^{2})"}}}); - registry.add("hMassXiPlus", "hMassXiPlus", {HistType::kTH1F, {{400, 1.122f, 1.522f, "Inv. Mass (GeV/c^{2}²)"}}}); - registry.add("hMassOmegaMinus", "hMassOmegaMinus", {HistType::kTH1F, {{400, 1.472f, 1.872f, "Inv. Mass (GeV/c^{2})"}}}); - registry.add("hMassOmegaPlus", "hMassOmegaPlus", {HistType::kTH1F, {{400, 1.472f, 1.872f, "Inv. Mass (GeV/c^{2})"}}}); + registry.add("hMassXiMinus", "hMassXiMinus", {HistType::kTH1D, {{400, 1.122f, 1.522f, "Inv. Mass (GeV/c^{2})"}}}); + registry.add("hMassXiPlus", "hMassXiPlus", {HistType::kTH1D, {{400, 1.122f, 1.522f, "Inv. Mass (GeV/c^{2}²)"}}}); + registry.add("hMassOmegaMinus", "hMassOmegaMinus", {HistType::kTH1D, {{400, 1.472f, 1.872f, "Inv. Mass (GeV/c^{2})"}}}); + registry.add("hMassOmegaPlus", "hMassOmegaPlus", {HistType::kTH1D, {{400, 1.472f, 1.872f, "Inv. Mass (GeV/c^{2})"}}}); // Cascade topology - registry.add("hV0Radius", "hV0Radius", {HistType::kTH1F, {{500, 0.0, 100.0, "cm"}}}); - registry.add("hCascRadius", "hCascRadius", {HistType::kTH1F, {{500, 0.0, 100.0, "cm"}}}); - registry.add("hV0CosPA", "hV0CosPA", {HistType::kTH1F, {{100, 0.9f, 1.0f}}}); - registry.add("hCascCosPA", "hCascCosPA", {HistType::kTH1F, {{100, 0.9f, 1.0f}}}); - registry.add("hDCAPosToPV", "hDCAPosToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}); - registry.add("hDCANegToPV", "hDCANegToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}); - registry.add("hDCABachToPV", "hDCABachToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}); - registry.add("hDCAV0ToPV", "hDCAV0ToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}); - registry.add("hDCAV0Dau", "hDCAV0Dau", {HistType::kTH1F, {{500, 0.0f, 5.0f, "cm^{2}"}}}); - registry.add("hDCACascDau", "hDCACascDau", {HistType::kTH1F, {{500, 0.0f, 5.0f, "cm^{2}"}}}); - registry.add("hLambdaMass", "hLambdaMass", {HistType::kTH1F, {{400, 0.916f, 1.316f, "Inv. Mass (GeV/c^{2})"}}}); + registry.add("hV0Radius", "hV0Radius", {HistType::kTH1D, {{500, 0.0, 100.0, "cm"}}}); + registry.add("hCascRadius", "hCascRadius", {HistType::kTH1D, {{500, 0.0, 100.0, "cm"}}}); + registry.add("hV0CosPA", "hV0CosPA", {HistType::kTH1D, {{100, 0.9f, 1.0f}}}); + registry.add("hCascCosPA", "hCascCosPA", {HistType::kTH1D, {{100, 0.9f, 1.0f}}}); + registry.add("hDCAPosToPV", "hDCAPosToPV", {HistType::kTH1D, {{1000, -10.0f, 10.0f, "cm"}}}); + registry.add("hDCANegToPV", "hDCANegToPV", {HistType::kTH1D, {{1000, -10.0f, 10.0f, "cm"}}}); + registry.add("hDCABachToPV", "hDCABachToPV", {HistType::kTH1D, {{1000, -10.0f, 10.0f, "cm"}}}); + registry.add("hDCAV0ToPV", "hDCAV0ToPV", {HistType::kTH1D, {{1000, -10.0f, 10.0f, "cm"}}}); + registry.add("hDCAV0Dau", "hDCAV0Dau", {HistType::kTH1D, {{500, 0.0f, 5.0f, "cm^{2}"}}}); + registry.add("hDCACascDau", "hDCACascDau", {HistType::kTH1D, {{500, 0.0f, 5.0f, "cm^{2}"}}}); + registry.add("hLambdaMass", "hLambdaMass", {HistType::kTH1D, {{400, 0.916f, 1.316f, "Inv. Mass (GeV/c^{2})"}}}); + + // pT rej + registry.add("hPtCutsXicZeroOmegacZeroToXiPi", "Omegac/Xic to Xi Pi tracks selected by pT;#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {{500, 0., 50.}}}); + registry.add("hPtCutsOmegacZeroToOmegaPi", "Omegac to Omega Pi tracks selected by pT;#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {{500, 0., 50.}}}); + registry.add("hPtCutsOmegacZeroToOmegaKa", "Omegac to Omega Ka tracks selected by pT;#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {{500, 0., 50.}}}); + registry.add("hPtCutsXicPlusToXiPiPi", "Xicplus to Xi Pi Pi tracks selected by pT;#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {{500, 0., 50.}}}); + registry.add("hRejpTStatusXicZeroOmegacZeroToXiPi", "XicZeroOmegacZeroToXiPi rejected by pT status;status;entries", {HistType::kTH1D, {{2, -0.5, 1.5}}}); // pass dcafitter --> 0, pT>pTmin --> 1 + registry.add("hRejpTStatusOmegacZeroToOmegaPi", "OmegacZeroToOmegaPi rejected by pT status;status;entries", {HistType::kTH1D, {{2, -0.5, 1.5}}}); + registry.add("hRejpTStatusOmegacZeroToOmegaKa", "OmegacZeroToOmegaKa rejected by pT status;status;entries", {HistType::kTH1D, {{2, -0.5, 1.5}}}); + registry.add("hRejpTStatusXicPlusToXiPiPi", "XicPlusToXiPiPi rejected by pT status;status;entries", {HistType::kTH1D, {{2, -0.5, 1.5}}}); // mass spectra - registry.add("hMassXicZeroOmegacZeroToXiPi", "2-prong candidates;inv. mass (#Xi #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 2., 3.}}}); - registry.add("hMassOmegacZeroToOmegaPi", "2-prong candidates;inv. mass (#Omega #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 2., 3.}}}); - registry.add("hMassXicPlusToXiPiPi", "3-prong candidates;inv. mass (#Xi #pi #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 2., 3.}}}); + registry.add("hMassXicZeroOmegacZeroToXiPi", "2-prong candidates;inv. mass (#Xi #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 2., 3.}}}); + registry.add("hMassOmegacZeroToOmegaPi", "2-prong candidates;inv. mass (#Omega #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 2., 3.}}}); + registry.add("hMassOmegacZeroToOmegaK", "2-prong candidates;inv. mass (#Omega K) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 2., 3.}}}); + registry.add("hMassXicPlusToXiPiPi", "3-prong candidates;inv. mass (#Xi #pi #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 2., 3.}}}); // dcaFitter exception counter registry.add("hFitterStatusXi2Prong", "Charm DCAFitter status (xi hyp. - 2prong);status;entries", {HistType::kTH1D, {{2, -0.5, 1.5}}}); // 0 --> successful call of DCAFitter 1 --> exception found by DCAFitter @@ -3404,21 +3441,21 @@ struct HfTrackIndexSkimCreatorLfCascades { { registry.fill(HIST("hCandidateCounter"), 2.5); - if (casc.v0cosPA(pvx, pvy, pvz) > v0CosPA && - casc.casccosPA(pvx, pvy, pvz) > cascCosPA && - casc.dcacascdaughters() < dcaCascDau && - casc.dcaV0daughters() < dcaV0Dau && - std::abs(casc.dcanegtopv()) > dcaNegToPv && - std::abs(casc.dcapostopv()) > dcaPosToPv && - std::abs(casc.dcabachtopv()) > dcaBachToPv && - std::abs(casc.dcav0topv(pvx, pvy, pvz)) > dcaV0ToPv && - casc.v0radius() > v0TransvRadius && - casc.cascradius() > cascTransvRadius && - std::abs(casc.mLambda() - massLambda) < v0MassWindow) { + if (casc.v0cosPA(pvx, pvy, pvz) > config.v0CosPA && + casc.casccosPA(pvx, pvy, pvz) > config.cascCosPA && + casc.dcacascdaughters() < config.dcaCascDau && + casc.dcaV0daughters() < config.dcaV0Dau && + std::abs(casc.dcanegtopv()) > config.dcaNegToPv && + std::abs(casc.dcapostopv()) > config.dcaPosToPv && + std::abs(casc.dcabachtopv()) > config.dcaBachToPv && + std::abs(casc.dcav0topv(pvx, pvy, pvz)) > config.dcaV0ToPv && + casc.v0radius() > config.v0TransvRadius && + casc.cascradius() > config.cascTransvRadius && + std::abs(casc.mLambda() - massLambda) < config.v0MassWindow) { registry.fill(HIST("hCandidateCounter"), 3.5); // pass cascade selections - if (fillHistograms) { + if (config.fillHistograms) { // The basic eleven! registry.fill(HIST("hV0Radius"), casc.v0radius()); registry.fill(HIST("hCascRadius"), casc.cascradius()); @@ -3465,14 +3502,14 @@ struct HfTrackIndexSkimCreatorLfCascades { // set the magnetic field from CCDB auto bc = collision.bc_as(); - initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, lut, isRun2); + initCCDB(bc, runNumber, ccdb, config.isRun2 ? config.ccdbPathGrp : config.ccdbPathGrpMag, lut, config.isRun2); auto magneticField = o2::base::Propagator::Instance()->getNominalBz(); // z component df2.setBz(magneticField); - df2.setRefitWithMatCorr(refitWithMatCorr); + df2.setRefitWithMatCorr(config.refitWithMatCorr); df3.setBz(magneticField); - df3.setRefitWithMatCorr(refitWithMatCorr); + df3.setRefitWithMatCorr(config.refitWithMatCorr); // cascade loop auto thisCollId = collision.globalIndex(); @@ -3484,23 +3521,23 @@ struct HfTrackIndexSkimCreatorLfCascades { //----------------accessing particles in the decay chain------------- // cascade daughter - charged particle - auto trackXiDauCharged = casc.bachelor_as(); // pion <- xi track + auto trackCascDauCharged = casc.bachelor_as(); // meson <- xi track // cascade daughter - V0 auto trackV0PosDau = casc.posTrack_as(); // p <- V0 track (positive track) 0 // V0 negative daughter auto trackV0NegDau = casc.negTrack_as(); // pion <- V0 track (negative track) 1 // check that particles come from the same collision - if (rejDiffCollTrack) { + if (config.rejDiffCollTrack) { if (trackV0PosDau.collisionId() != trackV0NegDau.collisionId()) { continue; } - if (trackXiDauCharged.collisionId() != trackV0PosDau.collisionId()) { + if (trackCascDauCharged.collisionId() != trackV0PosDau.collisionId()) { continue; } } - if (trackV0PosDau.globalIndex() == trackV0NegDau.globalIndex() || trackV0PosDau.globalIndex() == trackXiDauCharged.globalIndex() || trackV0NegDau.globalIndex() == trackXiDauCharged.globalIndex()) { + if (trackV0PosDau.globalIndex() == trackV0NegDau.globalIndex() || trackV0PosDau.globalIndex() == trackCascDauCharged.globalIndex() || trackV0NegDau.globalIndex() == trackCascDauCharged.globalIndex()) { continue; } @@ -3517,61 +3554,59 @@ struct HfTrackIndexSkimCreatorLfCascades { covCasc[i] = casc.positionCovMat()[i]; } // create cascade track - o2::track::TrackParCov trackCascXi2Prong; - if (trackXiDauCharged.sign() > 0) { - trackCascXi2Prong = o2::track::TrackParCov(vertexCasc, pVecCasc, covCasc, 1, true); - } else if (trackXiDauCharged.sign() < 0) { - trackCascXi2Prong = o2::track::TrackParCov(vertexCasc, pVecCasc, covCasc, -1, true); + o2::track::TrackParCov trackCascXi; + if (trackCascDauCharged.sign() > 0) { + trackCascXi = o2::track::TrackParCov(vertexCasc, pVecCasc, covCasc, 1, true); + } else if (trackCascDauCharged.sign() < 0) { + trackCascXi = o2::track::TrackParCov(vertexCasc, pVecCasc, covCasc, -1, true); } else { continue; } - trackCascXi2Prong.setAbsCharge(1); + trackCascXi.setAbsCharge(1); - auto trackCascOmega = trackCascXi2Prong; - auto trackCascXi3Prong = trackCascXi2Prong; + auto trackCascOmega = trackCascXi; - trackCascXi2Prong.setPID(o2::track::PID::XiMinus); - trackCascXi3Prong.setPID(o2::track::PID::XiMinus); + trackCascXi.setPID(o2::track::PID::XiMinus); trackCascOmega.setPID(o2::track::PID::OmegaMinus); //--------------combining cascade and pion tracks-------------- auto groupedBachTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - for (auto trackIdPion1 = groupedBachTrackIndices.begin(); trackIdPion1 != groupedBachTrackIndices.end(); ++trackIdPion1) { + for (auto trackIdCharmBachelor1 = groupedBachTrackIndices.begin(); trackIdCharmBachelor1 != groupedBachTrackIndices.end(); ++trackIdCharmBachelor1) { hfFlag = 0; isGoogForXi2Prong = true; isGoogForOmega2Prong = true; - auto trackPion1 = trackIdPion1.track_as(); + auto trackCharmBachelor1 = trackIdCharmBachelor1.track_as(); - if ((rejDiffCollTrack) && (trackXiDauCharged.collisionId() != trackPion1.collisionId())) { + if ((config.rejDiffCollTrack) && (trackCascDauCharged.collisionId() != trackCharmBachelor1.collisionId())) { continue; } // ask for opposite sign daughters - if (trackPion1.sign() * trackXiDauCharged.sign() >= 0) { + if (trackCharmBachelor1.sign() * trackCascDauCharged.sign() >= 0) { continue; } // check not to take the same particle twice in the decay chain - if (trackPion1.globalIndex() == trackXiDauCharged.globalIndex() || trackPion1.globalIndex() == trackV0PosDau.globalIndex() || trackPion1.globalIndex() == trackV0NegDau.globalIndex()) { + if (trackCharmBachelor1.globalIndex() == trackCascDauCharged.globalIndex() || trackCharmBachelor1.globalIndex() == trackV0PosDau.globalIndex() || trackCharmBachelor1.globalIndex() == trackV0NegDau.globalIndex()) { continue; } // primary pion track to be processed with DCAFitter - auto trackParVarPion1 = getTrackParCov(trackPion1); + auto trackParVarCharmBachelor1 = getTrackParCov(trackCharmBachelor1); - // find charm baryon decay using xi PID hypothesis + // find charm baryon decay using xi PID hypothesis (xi pi channel) int nVtxFrom2ProngFitterXiHyp = 0; try { - nVtxFrom2ProngFitterXiHyp = df2.process(trackCascXi2Prong, trackParVarPion1); + nVtxFrom2ProngFitterXiHyp = df2.process(trackCascXi, trackParVarCharmBachelor1); } catch (...) { - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hFitterStatusXi2Prong"), 1); } isGoogForXi2Prong = false; } - if (isGoogForXi2Prong && fillHistograms) { + if (isGoogForXi2Prong && config.fillHistograms) { registry.fill(HIST("hFitterStatusXi2Prong"), 0); } @@ -3584,34 +3619,40 @@ struct HfTrackIndexSkimCreatorLfCascades { std::array pVecPion1XiHyp = {0.}; df2.getTrack(0).getPxPyPzGlo(pVecXi); df2.getTrack(1).getPxPyPzGlo(pVecPion1XiHyp); + float ptXic = RecoDecay::pt(pVecXi, pVecPion1XiHyp); std::array, 2> arrMomToXi = {pVecXi, pVecPion1XiHyp}; auto mass2ProngXiHyp = RecoDecay::m(arrMomToXi, arrMass2Prong[hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi]); - if ((std::abs(casc.mXi() - massXi) < cascadeMassWindow) && (mass2ProngXiHyp >= massXiPiMin) && (mass2ProngXiHyp <= massXiPiMax)) { - SETBIT(hfFlag, aod::hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi); + if ((std::abs(casc.mXi() - massXi) < config.cascadeMassWindow) && (mass2ProngXiHyp >= config.massXiPiMin) && (mass2ProngXiHyp <= config.massXiPiMax)) { + registry.fill(HIST("hRejpTStatusXicZeroOmegacZeroToXiPi"), 0); + if (ptXic >= config.ptMinXicZeroOmegacZeroToXiPiLfCasc) { + SETBIT(hfFlag, aod::hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi); + registry.fill(HIST("hRejpTStatusXicZeroOmegacZeroToXiPi"), 1); + } } // fill histograms - if (fillHistograms && (TESTBIT(hfFlag, aod::hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi))) { + if (config.fillHistograms && (TESTBIT(hfFlag, aod::hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi))) { registry.fill(HIST("hMassXicZeroOmegacZeroToXiPi"), mass2ProngXiHyp); + registry.fill(HIST("hPtCutsXicZeroOmegacZeroToXiPi"), ptXic); } } else if (df2.isPropagationFailure()) { LOGF(info, "Exception caught: failed to propagate tracks (2prong - xi) to charm baryon decay vtx"); } } - // find charm baryon decay using omega PID hypothesis + // find charm baryon decay using omega PID hypothesis to be combined with the charm bachelor (either pion or kaon) int nVtxFrom2ProngFitterOmegaHyp = 0; try { - nVtxFrom2ProngFitterOmegaHyp = df2.process(trackCascOmega, trackParVarPion1); + nVtxFrom2ProngFitterOmegaHyp = df2.process(trackCascOmega, trackParVarCharmBachelor1); } catch (...) { - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hFitterStatusOmega2Prong"), 1); } isGoogForOmega2Prong = false; } - if (isGoogForOmega2Prong && fillHistograms) { + if (isGoogForOmega2Prong && config.fillHistograms) { registry.fill(HIST("hFitterStatusOmega2Prong"), 0); } @@ -3622,20 +3663,42 @@ struct HfTrackIndexSkimCreatorLfCascades { if (df2.isPropagateTracksToVertexDone()) { std::array pVecOmega = {0.}; - std::array pVecPion1OmegaHyp = {0.}; + std::array pVecCharmBachelor1OmegaHyp = {0.}; df2.getTrack(0).getPxPyPzGlo(pVecOmega); - df2.getTrack(1).getPxPyPzGlo(pVecPion1OmegaHyp); - - std::array, 2> arrMomToOmega = {pVecOmega, pVecPion1OmegaHyp}; - auto mass2ProngOmegaHyp = RecoDecay::m(arrMomToOmega, arrMass2Prong[hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi]); - - if ((std::abs(casc.mOmega() - massOmega) < cascadeMassWindow) && (mass2ProngOmegaHyp >= massOmegaPiMin) && (mass2ProngOmegaHyp <= massOmegaPiMax)) { - SETBIT(hfFlag, aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi); + df2.getTrack(1).getPxPyPzGlo(pVecCharmBachelor1OmegaHyp); + float ptOmegac = RecoDecay::pt(pVecOmega, pVecCharmBachelor1OmegaHyp); + + std::array, 2> arrMomToOmega = {pVecOmega, pVecCharmBachelor1OmegaHyp}; + auto mass2ProngOmegaPiHyp = RecoDecay::m(arrMomToOmega, arrMass2Prong[hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi]); + auto mass2ProngOmegaKHyp = RecoDecay::m(arrMomToOmega, arrMass2Prong[hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK]); + + if (std::abs(casc.mOmega() - massOmega) < config.cascadeMassWindow) { + if ((mass2ProngOmegaPiHyp >= config.massOmegaCharmBachelorMin) && (mass2ProngOmegaPiHyp <= config.massOmegaCharmBachelorMax)) { + registry.fill(HIST("hRejpTStatusOmegacZeroToOmegaPi"), 0); + if (ptOmegac >= config.ptMinOmegacZeroToOmegaPiLfCasc) { + SETBIT(hfFlag, aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi); + registry.fill(HIST("hRejpTStatusOmegacZeroToOmegaPi"), 1); + } + } + if ((mass2ProngOmegaKHyp >= config.massOmegaCharmBachelorMin) && (mass2ProngOmegaKHyp <= config.massOmegaCharmBachelorMax)) { + registry.fill(HIST("hRejpTStatusOmegacZeroToOmegaKa"), 0); + if (ptOmegac >= config.ptMinOmegaczeroToOmegaKaLfCasc) { + SETBIT(hfFlag, aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK); + registry.fill(HIST("hRejpTStatusOmegacZeroToOmegaKa"), 1); + } + } } // fill histograms - if (fillHistograms && (TESTBIT(hfFlag, aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi))) { - registry.fill(HIST("hMassOmegacZeroToOmegaPi"), mass2ProngOmegaHyp); + if (config.fillHistograms) { + if (TESTBIT(hfFlag, aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi)) { + registry.fill(HIST("hMassOmegacZeroToOmegaPi"), mass2ProngOmegaPiHyp); + registry.fill(HIST("hPtCutsOmegacZeroToOmegaPi"), ptOmegac); + } + if (TESTBIT(hfFlag, aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK)) { + registry.fill(HIST("hMassOmegacZeroToOmegaK"), mass2ProngOmegaKHyp); + registry.fill(HIST("hPtCutsOmegacZeroToOmegaKa"), ptOmegac); + } } } else if (df2.isPropagationFailure()) { LOGF(info, "Exception caught: failed to propagate tracks (2prong - omega) to charm baryon decay vtx"); @@ -3646,52 +3709,52 @@ struct HfTrackIndexSkimCreatorLfCascades { if (hfFlag != 0) { rowTrackIndexCasc2Prong(thisCollId, casc.cascadeId(), - trackPion1.globalIndex(), + trackCharmBachelor1.globalIndex(), hfFlag); } // first loop over tracks - if (do3Prong) { + if (config.do3Prong) { // second loop over positive tracks - for (auto trackIdPion2 = trackIdPion1 + 1; trackIdPion2 != groupedBachTrackIndices.end(); ++trackIdPion2) { + for (auto trackIdCharmBachelor2 = trackIdCharmBachelor1 + 1; trackIdCharmBachelor2 != groupedBachTrackIndices.end(); ++trackIdCharmBachelor2) { hfFlag = 0; - if (!TESTBIT(trackIdPion2.isSelProng(), CandidateType::CandCascadeBachelor)) { + if (!TESTBIT(trackIdCharmBachelor2.isSelProng(), CandidateType::CandCascadeBachelor)) { continue; } - auto trackPion2 = trackIdPion2.track_as(); + auto trackCharmBachelor2 = trackIdCharmBachelor2.track_as(); - if ((rejDiffCollTrack) && (trackXiDauCharged.collisionId() != trackPion2.collisionId())) { + if ((config.rejDiffCollTrack) && (trackCascDauCharged.collisionId() != trackCharmBachelor2.collisionId())) { continue; } // ask for same sign daughters - if (trackPion2.sign() * trackPion1.sign() <= 0) { + if (trackCharmBachelor2.sign() * trackCharmBachelor1.sign() <= 0) { continue; } // check not to take the same particle twice in the decay chain - if (trackPion2.globalIndex() == trackPion1.globalIndex() || trackPion2.globalIndex() == trackXiDauCharged.globalIndex() || trackPion2.globalIndex() == trackV0PosDau.globalIndex() || trackPion2.globalIndex() == trackV0NegDau.globalIndex()) { + if (trackCharmBachelor2.globalIndex() == trackCharmBachelor1.globalIndex() || trackCharmBachelor2.globalIndex() == trackCascDauCharged.globalIndex() || trackCharmBachelor2.globalIndex() == trackV0PosDau.globalIndex() || trackCharmBachelor2.globalIndex() == trackV0NegDau.globalIndex()) { continue; } // primary pion track to be processed with DCAFitter - auto trackParVarPion2 = getTrackParCov(trackPion2); + auto trackParVarPion2 = getTrackParCov(trackCharmBachelor2); // reconstruct Xic with DCAFitter int nVtxFrom3ProngFitterXiHyp = 0; try { - nVtxFrom3ProngFitterXiHyp = df3.process(trackCascXi3Prong, trackParVarPion1, trackParVarPion2); + nVtxFrom3ProngFitterXiHyp = df3.process(trackCascXi, trackParVarCharmBachelor1, trackParVarPion2); } catch (...) { - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hFitterStatusXi3Prong"), 1); } continue; } - if (fillHistograms) { + if (config.fillHistograms) { registry.fill(HIST("hFitterStatusXi3Prong"), 0); } @@ -3707,17 +3770,23 @@ struct HfTrackIndexSkimCreatorLfCascades { df3.getTrack(0).getPxPyPzGlo(pVec1); // take the momentum at the Xic vertex df3.getTrack(1).getPxPyPzGlo(pVec2); df3.getTrack(2).getPxPyPzGlo(pVec3); + float ptXic3Prong = RecoDecay::pt(pVec1, pVec2, pVec3); std::array, 3> arr3Mom = {pVec1, pVec2, pVec3}; auto mass3Prong = RecoDecay::m(arr3Mom, arrMass3Prong[hf_cand_casc_lf::DecayType3Prong::XicplusToXiPiPi]); - if ((std::abs(casc.mXi() - massXi) < cascadeMassWindow) && (mass3Prong >= massXiPiPiMin) && (mass3Prong <= massXiPiPiMax)) { - SETBIT(hfFlag, aod::hf_cand_casc_lf::DecayType3Prong::XicplusToXiPiPi); + if ((std::abs(casc.mXi() - massXi) < config.cascadeMassWindow) && (mass3Prong >= config.massXiPiPiMin) && (mass3Prong <= config.massXiPiPiMax)) { + registry.fill(HIST("hRejpTStatusXicPlusToXiPiPi"), 0); + if (ptXic3Prong >= config.ptMinXicplusLfCasc) { + SETBIT(hfFlag, aod::hf_cand_casc_lf::DecayType3Prong::XicplusToXiPiPi); + registry.fill(HIST("hRejpTStatusXicPlusToXiPiPi"), 1); + } } // fill histograms - if (fillHistograms && (TESTBIT(hfFlag, aod::hf_cand_casc_lf::DecayType3Prong::XicplusToXiPiPi))) { + if (config.fillHistograms && (TESTBIT(hfFlag, aod::hf_cand_casc_lf::DecayType3Prong::XicplusToXiPiPi))) { registry.fill(HIST("hMassXicPlusToXiPiPi"), mass3Prong); + registry.fill(HIST("hPtCutsXicPlusToXiPiPi"), ptXic3Prong); } } else if (df3.isPropagationFailure()) { LOGF(info, "Exception caught: failed to propagate tracks (3prong) to charm baryon decay vtx"); @@ -3728,17 +3797,17 @@ struct HfTrackIndexSkimCreatorLfCascades { if (hfFlag != 0) { rowTrackIndexCasc3Prong(thisCollId, casc.cascadeId(), - trackPion1.globalIndex(), - trackPion2.globalIndex()); + trackCharmBachelor1.globalIndex(), + trackCharmBachelor2.globalIndex()); } } // end 3prong loop - } // end 3prong condition + } // end 3prong condition } // loop over pion - } // loop over cascade - } // loop over collisions - } // processLfCascades + } // loop over cascade + } // loop over collisions + } // processLfCascades PROCESS_SWITCH(HfTrackIndexSkimCreatorLfCascades, processLfCascades, "Skim HF -> LF cascade + bachelor", false); }; diff --git a/PWGHF/TableProducer/treeCreatorB0ToDPi.cxx b/PWGHF/TableProducer/treeCreatorB0ToDPi.cxx index f6c717e6e08..0288f19cac9 100644 --- a/PWGHF/TableProducer/treeCreatorB0ToDPi.cxx +++ b/PWGHF/TableProducer/treeCreatorB0ToDPi.cxx @@ -162,7 +162,7 @@ struct HfTreeCreatorB0ToDPi { Produces rowCandidateFullParticles; Produces rowCandidateLite; - Configurable selectionFlagB0{"selectionB0", 1, "Selection Flag for B0"}; + Configurable selectionFlagB0{"selectionFlagB0", 1, "Selection Flag for B0"}; Configurable fillCandidateLiteTable{"fillCandidateLiteTable", false, "Switch to fill lite table with candidate properties"}; // parameters for production of training samples Configurable fillOnlySignal{"fillOnlySignal", false, "Flag to fill derived tables with signal for ML trainings"}; @@ -300,7 +300,7 @@ struct HfTreeCreatorB0ToDPi { } for (const auto& candidate : candidates) { if (fillOnlyBackground) { - float pseudoRndm = candidate.ptProng1() * 1000. - (int64_t)(candidate.ptProng1() * 1000); + float pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } @@ -340,7 +340,7 @@ struct HfTreeCreatorB0ToDPi { rowCandidateLite.reserve(recBg.size()); } for (const auto& candidate : recBg) { - float pseudoRndm = candidate.ptProng1() * 1000. - (int64_t)(candidate.ptProng1() * 1000); + float pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } diff --git a/PWGHF/TableProducer/treeCreatorBplusToD0Pi.cxx b/PWGHF/TableProducer/treeCreatorBplusToD0Pi.cxx index 64c7a8990c8..7b2c1145c3f 100644 --- a/PWGHF/TableProducer/treeCreatorBplusToD0Pi.cxx +++ b/PWGHF/TableProducer/treeCreatorBplusToD0Pi.cxx @@ -26,42 +26,38 @@ #include "PWGHF/DataModel/CandidateSelectionTables.h" using namespace o2; -using namespace o2::aod; using namespace o2::framework; +using namespace o2::framework::expressions; namespace o2::aod { namespace full { -DECLARE_SOA_COLUMN(RSecondaryVertex, rSecondaryVertex, float); -DECLARE_SOA_COLUMN(PtProng0, ptProng0, float); -DECLARE_SOA_COLUMN(PProng0, pProng0, float); -DECLARE_SOA_COLUMN(PtProng1, ptProng1, float); -DECLARE_SOA_COLUMN(PProng1, pProng1, float); -// DECLARE_SOA_COLUMN(CandidateSelFlag, candidateSelFlag, int8_t); -DECLARE_SOA_COLUMN(M, m, float); -DECLARE_SOA_COLUMN(Pt, pt, float); -DECLARE_SOA_COLUMN(P, p, float); -DECLARE_SOA_COLUMN(Eta, eta, float); -DECLARE_SOA_COLUMN(Phi, phi, float); -DECLARE_SOA_COLUMN(Y, y, float); -DECLARE_SOA_COLUMN(DecayLength, decayLength, float); -DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); -DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); -DECLARE_SOA_COLUMN(DecayLengthXYNormalised, decayLengthXYNormalised, float); -DECLARE_SOA_COLUMN(CPA, cpa, float); -DECLARE_SOA_COLUMN(CPAXY, cpaXY, float); -DECLARE_SOA_COLUMN(ImpactParameterProduct, impactParameterProduct, float); -DECLARE_SOA_COLUMN(ImpactParameter0, impactParameter0, float); -DECLARE_SOA_COLUMN(ImpactParameter1, impactParameter1, float); -DECLARE_SOA_COLUMN(ImpactParameterNormalised0, impactParameterNormalised0, float); -DECLARE_SOA_COLUMN(ImpactParameterNormalised1, impactParameterNormalised1, float); +DECLARE_SOA_COLUMN(RSecondaryVertex, rSecondaryVertex, float); //! Radius of secondary vertex (cm) +DECLARE_SOA_COLUMN(PtProng0, ptProng0, float); //! Transverse momentum of prong0 (GeV/c) +DECLARE_SOA_COLUMN(PProng0, pProng0, float); //! Momentum of prong0 (GeV/c) +DECLARE_SOA_COLUMN(ImpactParameterNormalised0, impactParameterNormalised0, float); //! Normalised impact parameter of prong0 +DECLARE_SOA_COLUMN(PtProng1, ptProng1, float); //! Transverse momentum of prong1 (GeV/c) +DECLARE_SOA_COLUMN(PProng1, pProng1, float); //! Momentum of prong1 (in GeV/c) +DECLARE_SOA_COLUMN(ImpactParameterNormalised1, impactParameterNormalised1, float); //! Normalised impact parameter of prong1 +DECLARE_SOA_COLUMN(CandidateSelFlag, candidateSelFlag, int); //! Selection flag of candidate (output of candidateSelector) +DECLARE_SOA_COLUMN(M, m, float); //! Invariant mass of candidate (GeV/c2) +DECLARE_SOA_COLUMN(Pt, pt, float); //! Transverse momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(P, p, float); //! Momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(Y, y, float); //! Rapidity of candidate +DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity of candidate +DECLARE_SOA_COLUMN(Phi, phi, float); //! Azimuth angle of candidate +DECLARE_SOA_COLUMN(E, e, float); //! Energy of candidate (GeV) +DECLARE_SOA_COLUMN(NSigTpcPi1, nSigTpcPi1, float); //! TPC Nsigma separation for prong1 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTofPi1, nSigTofPi1, float); //! TOF Nsigma separation for prong1 with pion mass hypothesis +DECLARE_SOA_COLUMN(DecayLength, decayLength, float); //! Decay length of candidate (cm) +DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); //! Transverse decay length of candidate (cm) +DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); //! Normalised decay length of candidate +DECLARE_SOA_COLUMN(DecayLengthXYNormalised, decayLengthXYNormalised, float); //! Normalised transverse decay length of candidate +DECLARE_SOA_COLUMN(Cpa, cpa, float); //! Cosine pointing angle of candidate +DECLARE_SOA_COLUMN(CpaXY, cpaXY, float); //! Cosine pointing angle of candidate in transverse plane +DECLARE_SOA_COLUMN(MaxNormalisedDeltaIP, maxNormalisedDeltaIP, float); //! Maximum normalized difference between measured and expected impact parameter of candidate prongs DECLARE_SOA_COLUMN(Ct, ct, float); -DECLARE_SOA_COLUMN(Chi2PCA, chi2PCA, float); -DECLARE_SOA_COLUMN(NSigmaTOFBachPi, nSigmaTOFBachPi, float); -DECLARE_SOA_COLUMN(NSigmaTOFBachKa, nSigmaTOFBachKa, float); -DECLARE_SOA_COLUMN(NSigmaTPCBachPi, nSigmaTPCBachPi, float); -DECLARE_SOA_COLUMN(NSigmaTPCBachKa, nSigmaTPCBachKa, float); DECLARE_SOA_COLUMN(MCflag, mcflag, int8_t); // D0 (Prong0) selection variable DECLARE_SOA_COLUMN(D0M, d0M, float); @@ -93,49 +89,57 @@ DECLARE_SOA_COLUMN(NSigmaTPCTrk1Pi, nSigmaTPCTrk1Pi, float); // Events DECLARE_SOA_COLUMN(IsEventReject, isEventReject, int); DECLARE_SOA_COLUMN(RunNumber, runNumber, int); -DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfCandBplus, "_0"); -DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); -DECLARE_SOA_INDEX_COLUMN(McCollision, mcCollision); } // namespace full // put the arguments into the table DECLARE_SOA_TABLE(HfCandBpFulls, "AOD", "HFCANDBPFULL", + collision::BCId, + collision::NumContrib, + collision::PosX, + collision::PosY, + collision::PosZ, + hf_cand::XSecondaryVertex, + hf_cand::YSecondaryVertex, + hf_cand::ZSecondaryVertex, + hf_cand::ErrorDecayLength, + hf_cand::ErrorDecayLengthXY, + hf_cand::Chi2PCA, full::RSecondaryVertex, - full::PtProng0, - full::PProng0, - full::PtProng1, - full::PProng1, - // full::CandidateSelFlag, - full::M, - full::Pt, - full::P, - full::Ct, - full::Eta, - full::Phi, - full::Y, full::DecayLength, full::DecayLengthXY, full::DecayLengthNormalised, full::DecayLengthXYNormalised, - full::CPA, - full::CPAXY, - full::ImpactParameterProduct, - hf_cand::ImpactParameter0, - hf_cand::ImpactParameter1, full::ImpactParameterNormalised0, + full::PtProng0, + full::PProng0, full::ImpactParameterNormalised1, + full::PtProng1, + full::PProng1, hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, - hf_cand::Chi2PCA, - full::NSigmaTOFBachPi, - full::NSigmaTOFBachKa, - full::NSigmaTPCBachPi, - full::NSigmaTPCBachKa, - full::MCflag, + hf_cand::ImpactParameter0, + hf_cand::ImpactParameter1, + hf_cand::ErrorImpactParameter0, + hf_cand::ErrorImpactParameter1, + full::NSigTpcPi1, + full::NSigTofPi1, + full::CandidateSelFlag, + full::M, + full::Pt, + full::P, + full::Cpa, + full::CpaXY, + full::MaxNormalisedDeltaIP, + full::Ct, + full::Eta, + full::Phi, + full::Y, + full::E, + hf_cand_2prong::FlagMcMatchRec, full::D0M, full::D0PtProng0, full::D0PtProng1, @@ -160,8 +164,7 @@ DECLARE_SOA_TABLE(HfCandBpFulls, "AOD", "HFCANDBPFULL", full::NSigmaTOFTrk1Pi, full::NSigmaTOFTrk1Ka, full::NSigmaTPCTrk1Pi, - full::NSigmaTPCTrk1Ka, - full::CandidateId); + full::NSigmaTPCTrk1Ka); DECLARE_SOA_TABLE(HfCandBpFullEvs, "AOD", "HFCANDBPFULLEV", collision::BCId, @@ -174,13 +177,36 @@ DECLARE_SOA_TABLE(HfCandBpFullEvs, "AOD", "HFCANDBPFULLEV", DECLARE_SOA_TABLE(HfCandBpFullPs, "AOD", "HFCANDBPFULLP", collision::BCId, - full::McCollisionId, full::Pt, full::Eta, full::Phi, full::Y, - full::MCflag, - full::McParticleId); + hf_cand_2prong::FlagMcMatchRec, + hf_cand_2prong::OriginMcGen); + +DECLARE_SOA_TABLE(HfCandBpLites, "AOD", "HFCANDBPLITE", + hf_cand::Chi2PCA, + full::DecayLength, + full::DecayLengthXY, + full::DecayLengthNormalised, + full::DecayLengthXYNormalised, + full::PtProng0, + full::PtProng1, + hf_cand::ImpactParameter0, + hf_cand::ImpactParameter1, + full::NSigTpcPi1, + full::NSigTofPi1, + full::CandidateSelFlag, + full::M, + full::Pt, + full::Cpa, + full::CpaXY, + full::MaxNormalisedDeltaIP, + full::Eta, + full::Phi, + full::Y, + hf_cand_2prong::FlagMcMatchRec, + hf_cand_2prong::OriginMcRec); } // namespace o2::aod @@ -189,153 +215,258 @@ struct HfTreeCreatorBplusToD0Pi { Produces rowCandidateFull; Produces rowCandidateFullEvents; Produces rowCandidateFullParticles; + Produces rowCandidateLite; - Configurable isSignal{"isSignal", 1, "save only MC matched candidates"}; + Configurable selectionFlagBplus{"selectionBplus", 1, "Selection Flag for B+"}; + Configurable fillCandidateLiteTable{"fillCandidateLiteTable", false, "Switch to fill lite table with candidate properties"}; + // parameters for production of training samples + Configurable fillOnlySignal{"fillOnlySignal", false, "Flag to fill derived tables with signal for ML trainings"}; + Configurable fillOnlyBackground{"fillOnlyBackground", false, "Flag to fill derived tables with background for ML trainings"}; + Configurable downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of background candidates to keep for ML trainings"}; + Configurable ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"}; HfHelper hfHelper; + using SelectedCandidatesMc = soa::Filtered>; using TracksWPid = soa::Join; + Filter filterSelectCandidates = aod::hf_sel_candidate_bplus::isSelBplusToD0Pi >= selectionFlagBplus; + + Partition recSig = nabs(aod::hf_cand_bplus::flagMcMatchRec) == (int8_t)BIT(aod::hf_cand_bplus::DecayTypeMc::BplusToD0PiToKPiPi); + Partition recBg = nabs(aod::hf_cand_bplus::flagMcMatchRec) != (int8_t)BIT(aod::hf_cand_bplus::DecayTypeMc::BplusToD0PiToKPiPi); + void init(InitContext const&) { } - void process(aod::Collisions const& collisions, - aod::McCollisions const&, - soa::Join const& candidates, - soa::Join const& particles, - TracksWPid const&, - aod::HfCand2Prong const&) + template + void fillEvent(const T& collision, int isEventReject, int runNumber) { + rowCandidateFullEvents( + collision.bcId(), + collision.numContrib(), + collision.posX(), + collision.posY(), + collision.posZ(), + isEventReject, + runNumber); + } + + template + void fillCandidateTable(const T& candidate, const U& prong1) + { + int8_t flagMc = 0; + int8_t originMc = 0; + if constexpr (doMc) { + flagMc = candidate.flagMcMatchRec(); + originMc = candidate.originMcRec(); + } + auto d0Cand = candidate.prong0(); + // adding D0 daughters to the table + auto d0Daughter0 = d0Cand.template prong0_as(); + auto d0Daughter1 = d0Cand.template prong1_as(); + auto invMassD0 = 0.; + if (prong1.signed1Pt() > 0) { + invMassD0 = hfHelper.invMassD0barToKPi(d0Cand); + } else if (prong1.signed1Pt() < 0) { + invMassD0 = hfHelper.invMassD0ToPiK(d0Cand); + } + if (fillCandidateLiteTable) { + rowCandidateLite( + candidate.chi2PCA(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.decayLengthNormalised(), + candidate.decayLengthXYNormalised(), + candidate.ptProng0(), + candidate.ptProng1(), + candidate.impactParameter0(), + candidate.impactParameter1(), + prong1.tpcNSigmaPi(), + prong1.tofNSigmaPi(), + candidate.isSelBplusToD0Pi(), + hfHelper.invMassBplusToD0Pi(candidate), + candidate.pt(), + candidate.cpa(), + candidate.cpaXY(), + candidate.maxNormalisedDeltaIP(), + candidate.eta(), + candidate.phi(), + hfHelper.yBplus(candidate), + flagMc, + originMc); + } else { + rowCandidateFull( + prong1.collision().bcId(), + prong1.collision().numContrib(), + candidate.posX(), + candidate.posY(), + candidate.posZ(), + candidate.xSecondaryVertex(), + candidate.ySecondaryVertex(), + candidate.zSecondaryVertex(), + candidate.errorDecayLength(), + candidate.errorDecayLengthXY(), + candidate.chi2PCA(), + candidate.rSecondaryVertex(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.decayLengthNormalised(), + candidate.decayLengthXYNormalised(), + candidate.impactParameterNormalised0(), + candidate.ptProng0(), + RecoDecay::p(candidate.pxProng0(), candidate.pyProng0(), candidate.pzProng0()), + candidate.impactParameterNormalised1(), + candidate.ptProng1(), + RecoDecay::p(candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1()), + candidate.pxProng0(), + candidate.pyProng0(), + candidate.pzProng0(), + candidate.pxProng1(), + candidate.pyProng1(), + candidate.pzProng1(), + candidate.impactParameter0(), + candidate.impactParameter1(), + candidate.errorImpactParameter0(), + candidate.errorImpactParameter1(), + prong1.tpcNSigmaPi(), + prong1.tofNSigmaPi(), + candidate.isSelBplusToD0Pi(), + hfHelper.invMassBplusToD0Pi(candidate), + candidate.pt(), + candidate.p(), + candidate.cpa(), + candidate.cpaXY(), + candidate.maxNormalisedDeltaIP(), + hfHelper.ctBplus(candidate), + candidate.eta(), + candidate.phi(), + hfHelper.yBplus(candidate), + hfHelper.eBplus(candidate), + flagMc, + invMassD0, + d0Cand.ptProng0(), + d0Cand.ptProng1(), + hfHelper.yD0(d0Cand), + d0Cand.eta(), + d0Cand.cpa(), + d0Cand.cpaXY(), + d0Cand.chi2PCA(), + d0Cand.decayLength(), + d0Cand.decayLengthXY(), + d0Cand.decayLengthNormalised(), + d0Cand.decayLengthXYNormalised(), + d0Cand.impactParameterProduct(), + d0Cand.impactParameter0(), + d0Cand.impactParameter1(), + d0Cand.impactParameterNormalised0(), + d0Cand.impactParameterNormalised1(), + d0Daughter0.tofNSigmaPi(), + d0Daughter0.tofNSigmaKa(), + d0Daughter0.tpcNSigmaPi(), + d0Daughter0.tpcNSigmaKa(), + d0Daughter1.tofNSigmaPi(), + d0Daughter1.tofNSigmaKa(), + d0Daughter1.tpcNSigmaPi(), + d0Daughter1.tpcNSigmaKa()); + } + } + void processData(aod::Collisions const& collisions, + soa::Filtered> const& candidates, + TracksWPid const&) + { // Filling event properties rowCandidateFullEvents.reserve(collisions.size()); for (const auto& collision : collisions) { - rowCandidateFullEvents( - collision.bcId(), - collision.numContrib(), - collision.posX(), - collision.posY(), - collision.posZ(), - 0, - 1); + fillEvent(collision, 0, 1); } // Filling candidate properties rowCandidateFull.reserve(candidates.size()); + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(candidates.size()); + } for (const auto& candidate : candidates) { - auto fillTable = [&](int /*CandFlag*/, - // int FunctionSelection, - float FunctionInvMass, - float FunctionCt, - float FunctionY) { - auto d0Cand = candidate.prong0(); - auto piCand = candidate.prong1_as(); - // adding D0 daughters to the table - auto d0Daughter0 = d0Cand.prong0_as(); - auto d0Daughter1 = d0Cand.prong1_as(); - - auto invMassD0 = 0.; - if (piCand.sign() > 0) { - invMassD0 = hfHelper.invMassD0barToKPi(d0Cand); - } else if (piCand.sign() < 0) { - invMassD0 = hfHelper.invMassD0ToPiK(d0Cand); + if (fillOnlyBackground) { + float pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; } + } + auto prong1 = candidate.prong1_as(); + fillCandidateTable(candidate, prong1); + } + } - // if (FunctionSelection >= 1) { - if (std::abs(candidate.flagMcMatchRec()) >= isSignal) { + PROCESS_SWITCH(HfTreeCreatorBplusToD0Pi, processData, "Process data", true); - rowCandidateFull( - candidate.rSecondaryVertex(), - candidate.ptProng0(), - RecoDecay::p(candidate.pxProng0(), candidate.pyProng0(), candidate.pzProng0()), - candidate.ptProng1(), - RecoDecay::p(candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1()), - // 1 << CandFlag, - FunctionInvMass, - candidate.pt(), - candidate.p(), - FunctionCt, - candidate.eta(), - candidate.phi(), - FunctionY, - candidate.decayLength(), - candidate.decayLengthXY(), - candidate.decayLengthNormalised(), - candidate.decayLengthXYNormalised(), - candidate.cpa(), - candidate.cpaXY(), - candidate.impactParameterProduct(), - candidate.impactParameter0(), - candidate.impactParameter1(), - candidate.impactParameterNormalised0(), - candidate.impactParameterNormalised1(), - candidate.pxProng0(), - candidate.pyProng0(), - candidate.pzProng0(), - candidate.pxProng1(), - candidate.pyProng1(), - candidate.pzProng1(), - candidate.chi2PCA(), - piCand.tofNSigmaPi(), - piCand.tofNSigmaKa(), - piCand.tpcNSigmaPi(), - piCand.tpcNSigmaKa(), - candidate.flagMcMatchRec(), - invMassD0, - d0Cand.ptProng0(), - d0Cand.ptProng1(), - hfHelper.yD0(d0Cand), - d0Cand.eta(), - d0Cand.cpa(), - d0Cand.cpaXY(), - d0Cand.chi2PCA(), - d0Cand.decayLength(), - d0Cand.decayLengthXY(), - d0Cand.decayLengthNormalised(), - d0Cand.decayLengthXYNormalised(), - d0Cand.impactParameterProduct(), - d0Cand.impactParameter0(), - d0Cand.impactParameter1(), - d0Cand.impactParameterNormalised0(), - d0Cand.impactParameterNormalised1(), - d0Daughter0.tofNSigmaPi(), - d0Daughter0.tofNSigmaKa(), - d0Daughter0.tpcNSigmaPi(), - d0Daughter0.tpcNSigmaKa(), - d0Daughter1.tofNSigmaPi(), - d0Daughter1.tofNSigmaKa(), - d0Daughter1.tpcNSigmaPi(), - d0Daughter1.tpcNSigmaKa(), - candidate.globalIndex()); - } - }; + void processMc(aod::Collisions const& collisions, + aod::McCollisions const&, + SelectedCandidatesMc const& candidates, + soa::Join const& particles, + TracksWPid const&) + { + // Filling event properties + rowCandidateFullEvents.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, 0, 1); + } - // fillTable(0, candidate.isSelBplusToD0Pi(), hfHelper.invMassBplusToD0Pi(candidate), hfHelper.ctBplus(candidate), hfHelper.yBplus(candidate)); - fillTable(0, hfHelper.invMassBplusToD0Pi(candidate), hfHelper.ctBplus(candidate), hfHelper.yBplus(candidate)); + // Filling candidate properties + if (fillOnlySignal) { + rowCandidateFull.reserve(recSig.size()); + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(recSig.size()); + } + for (const auto& candidate : recSig) { + auto prong1 = candidate.prong1_as(); + fillCandidateTable(candidate, prong1); + } + } else if (fillOnlyBackground) { + rowCandidateFull.reserve(recBg.size()); + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(recBg.size()); + } + for (const auto& candidate : recBg) { + float pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + auto prong1 = candidate.prong1_as(); + fillCandidateTable(candidate, prong1); + } + } else { + rowCandidateFull.reserve(candidates.size()); + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(candidates.size()); + } + for (const auto& candidate : candidates) { + auto prong1 = candidate.prong1_as(); + fillCandidateTable(candidate, prong1); + } } // Filling particle properties rowCandidateFullParticles.reserve(particles.size()); for (const auto& particle : particles) { - if (std::abs(particle.flagMcMatchGen()) == 1 << aod::hf_cand_bplus::DecayType::BplusToD0Pi) { + if (std::abs(particle.flagMcMatchGen()) == 1 << aod::hf_cand_bplus::DecayTypeMc::BplusToD0PiToKPiPi) { rowCandidateFullParticles( particle.mcCollision().bcId(), particle.mcCollisionId(), particle.pt(), particle.eta(), particle.phi(), - RecoDecay::y(particle.pVector(), o2::constants::physics::MassBPlus), - particle.flagMcMatchGen(), - particle.globalIndex()); + RecoDecay::y(std::array{particle.px(), particle.py(), particle.pz()}, o2::constants::physics::MassBPlus), + particle.flagMcMatchGen()); } } } + + PROCESS_SWITCH(HfTreeCreatorBplusToD0Pi, processMc, "Process MC", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - WorkflowSpec workflow; - workflow.push_back(adaptAnalysisTask(cfgc)); - return workflow; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGHF/TableProducer/treeCreatorBsToDsPi.cxx b/PWGHF/TableProducer/treeCreatorBsToDsPi.cxx index aac534e265e..bdbf09cfbed 100644 --- a/PWGHF/TableProducer/treeCreatorBsToDsPi.cxx +++ b/PWGHF/TableProducer/treeCreatorBsToDsPi.cxx @@ -172,8 +172,8 @@ struct HfTreeCreatorBsToDsPi { Filter filterSelectCandidates = aod::hf_sel_candidate_bs::isSelBsToDsPi >= selectionFlagBs; - Partition recSig = nabs(aod::hf_cand_bs::flagMcMatchRec) == (int8_t)BIT(aod::hf_cand_bs::DecayTypeMc::BsToDsPiToKKPiPi); - Partition recBg = nabs(aod::hf_cand_bs::flagMcMatchRec) != (int8_t)BIT(aod::hf_cand_bs::DecayTypeMc::BsToDsPiToKKPiPi); + Partition recSig = nabs(aod::hf_cand_bs::flagMcMatchRec) == (int8_t)BIT(aod::hf_cand_bs::DecayTypeMc::BsToDsPiToPhiPiPiToKKPiPi); + Partition recBg = nabs(aod::hf_cand_bs::flagMcMatchRec) != (int8_t)BIT(aod::hf_cand_bs::DecayTypeMc::BsToDsPiToPhiPiPiToKKPiPi); void init(InitContext const&) { @@ -290,7 +290,7 @@ struct HfTreeCreatorBsToDsPi { } for (const auto& candidate : candidates) { if (fillOnlyBackground && downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng1() * 1000. - (int64_t)(candidate.ptProng1() * 1000); + float pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); if (pseudoRndm >= downSampleBkgFactor && candidate.pt() < ptMaxForDownSample) { continue; } @@ -330,7 +330,7 @@ struct HfTreeCreatorBsToDsPi { rowCandidateLite.reserve(recBg.size()); } for (const auto& candidate : recBg) { - float pseudoRndm = candidate.ptProng1() * 1000. - (int64_t)(candidate.ptProng1() * 1000); + float pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } @@ -351,7 +351,7 @@ struct HfTreeCreatorBsToDsPi { // Filling particle properties rowCandidateFullParticles.reserve(particles.size()); for (const auto& particle : particles) { - if (TESTBIT(std::abs(particle.flagMcMatchGen()), aod::hf_cand_bs::DecayTypeMc::BsToDsPiToKKPiPi)) { + if (TESTBIT(std::abs(particle.flagMcMatchGen()), aod::hf_cand_bs::DecayTypeMc::BsToDsPiToPhiPiPiToKKPiPi)) { rowCandidateFullParticles( particle.mcCollision().bcId(), particle.pt(), diff --git a/PWGHF/TableProducer/treeCreatorD0ToKPi.cxx b/PWGHF/TableProducer/treeCreatorD0ToKPi.cxx index 3487f1615dd..233b1055ea6 100644 --- a/PWGHF/TableProducer/treeCreatorD0ToKPi.cxx +++ b/PWGHF/TableProducer/treeCreatorD0ToKPi.cxx @@ -81,6 +81,12 @@ DECLARE_SOA_COLUMN(IsEventReject, isEventReject, int); DECLARE_SOA_COLUMN(RunNumber, runNumber, int); DECLARE_SOA_INDEX_COLUMN(McCollision, mcCollision); } // namespace full +namespace ml +{ +DECLARE_SOA_COLUMN(BdtOutputBkg, bdtOutputBkg, float); +DECLARE_SOA_COLUMN(BdtOutputPrompt, bdtOutputPrompt, float); +DECLARE_SOA_COLUMN(BdtOutputNonPrompt, bdtOutputNonPrompt, float); +} // namespace ml DECLARE_SOA_TABLE(HfCandD0Lites, "AOD", "HFCANDD0LITE", hf_cand::Chi2PCA, @@ -201,6 +207,11 @@ DECLARE_SOA_TABLE(HfCandD0FullPs, "AOD", "HFCANDD0FULLP", full::OriginMcGen, full::McParticleId); +DECLARE_SOA_TABLE(HfCandD0Mls, "AOD", "HFCANDD0ML", + ml::BdtOutputBkg, + ml::BdtOutputNonPrompt, + ml::BdtOutputPrompt); + } // namespace o2::aod /// Writes the full information in an output TTree @@ -209,6 +220,7 @@ struct HfTreeCreatorD0ToKPi { Produces rowCandidateFullEvents; Produces rowCandidateFullParticles; Produces rowCandidateLite; + Produces rowCandidateMl; Configurable fillCandidateLiteTable{"fillCandidateLiteTable", false, "Switch to fill lite table with candidate properties"}; // parameters for production of training samples @@ -217,9 +229,11 @@ struct HfTreeCreatorD0ToKPi { HfHelper hfHelper; - using TracksWPid = soa::Join; - using SelectedCandidatesMc = soa::Filtered>; - using SelectedCandidatesMcKf = soa::Filtered>; + // using TracksWPid = soa::Join; + using SelectedCandidatesMc = soa::Filtered>; + using SelectedCandidatesMcMl = soa::Filtered>; + using SelectedCandidatesMcKf = soa::Filtered>; + using SelectedCandidatesMcKfMl = soa::Filtered>; using MatchedGenCandidatesMc = soa::Filtered>; Filter filterSelectCandidates = aod::hf_sel_candidate_d0::isSelD0 >= 1 || aod::hf_sel_candidate_d0::isSelD0bar >= 1; @@ -230,9 +244,17 @@ struct HfTreeCreatorD0ToKPi { Partition reconstructedCandSigKF = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); Partition reconstructedCandBkgKF = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); + Partition reconstructedCandSigMl = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); + Partition reconstructedCandBkgMl = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); + Partition reconstructedCandSigKFMl = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); + Partition reconstructedCandBkgKFMl = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); + void init(InitContext const&) { - std::array doprocess{doprocessDataWithDCAFitterN, doprocessDataWithKFParticle, doprocessMcWithDCAFitterOnlySig, doprocessMcWithDCAFitterOnlyBkg, doprocessMcWithDCAFitterAll, doprocessMcWithKFParticleOnlySig, doprocessMcWithKFParticleOnlyBkg, doprocessMcWithKFParticleAll}; + std::array doprocess{doprocessDataWithDCAFitterN, doprocessDataWithKFParticle, doprocessMcWithDCAFitterOnlySig, doprocessMcWithDCAFitterOnlyBkg, + doprocessMcWithDCAFitterAll, doprocessMcWithKFParticleOnlySig, doprocessMcWithKFParticleOnlyBkg, doprocessMcWithKFParticleAll, + doprocessDataWithDCAFitterNMl, doprocessDataWithKFParticleMl, doprocessMcWithDCAFitterOnlySigMl, doprocessMcWithDCAFitterOnlyBkgMl, + doprocessMcWithDCAFitterAllMl, doprocessMcWithKFParticleOnlySigMl, doprocessMcWithKFParticleOnlyBkgMl, doprocessMcWithKFParticleAllMl}; if (std::accumulate(doprocess.begin(), doprocess.end(), 0) != 1) { LOGP(fatal, "Only one process function can be enabled at a time."); } @@ -251,8 +273,8 @@ struct HfTreeCreatorD0ToKPi { runNumber); } - template - auto fillTable(const T& candidate, const U& prong0, const U& prong1, int candFlag, double invMass, double cosThetaStar, double topoChi2, + template + auto fillTable(const T& candidate, int candFlag, double invMass, double topoChi2, double ct, double y, double e, int8_t flagMc, int8_t origin) { if (fillCandidateLiteTable) { @@ -268,18 +290,18 @@ struct HfTreeCreatorD0ToKPi { candidate.impactParameter1(), candidate.impactParameterNormalised0(), candidate.impactParameterNormalised1(), - prong0.tpcNSigmaPi(), - prong0.tpcNSigmaKa(), - prong0.tofNSigmaPi(), - prong0.tofNSigmaKa(), - prong0.tpcTofNSigmaPi(), - prong0.tpcTofNSigmaKa(), - prong1.tpcNSigmaPi(), - prong1.tpcNSigmaKa(), - prong1.tofNSigmaPi(), - prong1.tofNSigmaKa(), - prong1.tpcTofNSigmaPi(), - prong1.tpcTofNSigmaKa(), + candidate.nSigTpcPi0(), + candidate.nSigTpcKa0(), + candidate.nSigTofPi0(), + candidate.nSigTofKa0(), + candidate.tpcTofNSigmaPi0(), + candidate.tpcTofNSigmaKa0(), + candidate.nSigTpcPi1(), + candidate.nSigTpcKa1(), + candidate.nSigTofPi1(), + candidate.nSigTofKa1(), + candidate.tpcTofNSigmaPi1(), + candidate.tpcTofNSigmaKa1(), 1 << candFlag, invMass, candidate.pt(), @@ -293,6 +315,7 @@ struct HfTreeCreatorD0ToKPi { flagMc, origin); } else { + double cosThetaStar = candFlag == 0 ? hfHelper.cosThetaStarD0(candidate) : hfHelper.cosThetaStarD0bar(candidate); rowCandidateFull( candidate.collisionId(), candidate.posX(), @@ -326,18 +349,18 @@ struct HfTreeCreatorD0ToKPi { candidate.impactParameter1(), candidate.errorImpactParameter0(), candidate.errorImpactParameter1(), - prong0.tpcNSigmaPi(), - prong0.tpcNSigmaKa(), - prong0.tofNSigmaPi(), - prong0.tofNSigmaKa(), - prong0.tpcTofNSigmaPi(), - prong0.tpcTofNSigmaKa(), - prong1.tpcNSigmaPi(), - prong1.tpcNSigmaKa(), - prong1.tofNSigmaPi(), - prong1.tofNSigmaKa(), - prong1.tpcTofNSigmaPi(), - prong1.tpcTofNSigmaKa(), + candidate.nSigTpcPi0(), + candidate.nSigTpcKa0(), + candidate.nSigTofPi0(), + candidate.nSigTofKa0(), + candidate.tpcTofNSigmaPi0(), + candidate.tpcTofNSigmaKa0(), + candidate.nSigTpcPi1(), + candidate.nSigTpcKa1(), + candidate.nSigTofPi1(), + candidate.nSigTofKa1(), + candidate.tpcTofNSigmaPi1(), + candidate.tpcTofNSigmaKa1(), 1 << candFlag, invMass, candidate.maxNormalisedDeltaIP(), @@ -356,12 +379,25 @@ struct HfTreeCreatorD0ToKPi { origin, candidate.globalIndex()); } + if constexpr (applyMl) { + if (candFlag == 0) { + rowCandidateMl( + candidate.mlProbD0()[0], + candidate.mlProbD0()[1], + candidate.mlProbD0()[2]); + } else if (candFlag == 1) { + rowCandidateMl( + candidate.mlProbD0bar()[0], + candidate.mlProbD0bar()[1], + candidate.mlProbD0bar()[2]); + } + } } - template + template void processData(aod::Collisions const& collisions, CandType const& candidates, - TracksWPid const&, aod::BCs const&) + aod::Tracks const&, aod::BCs const&) { // Filling event properties rowCandidateFullEvents.reserve(collisions.size()); @@ -375,15 +411,16 @@ struct HfTreeCreatorD0ToKPi { } else { rowCandidateFull.reserve(candidates.size()); } + if constexpr (applyMl) { + rowCandidateMl.reserve(candidates.size()); + } for (const auto& candidate : candidates) { if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } } - auto prong0 = candidate.template prong0_as(); - auto prong1 = candidate.template prong1_as(); double yD = hfHelper.yD0(candidate); double eD = hfHelper.eD0(candidate); double ctD = hfHelper.ctD0(candidate); @@ -398,38 +435,56 @@ struct HfTreeCreatorD0ToKPi { massD0bar = hfHelper.invMassD0barToKPi(candidate); } if (candidate.isSelD0()) { - fillTable(candidate, prong0, prong1, 0, massD0, hfHelper.cosThetaStarD0(candidate), topolChi2PerNdf, ctD, yD, eD, 0, 0); + fillTable(candidate, 0, massD0, topolChi2PerNdf, ctD, yD, eD, 0, 0); } if (candidate.isSelD0bar()) { - fillTable(candidate, prong0, prong1, 1, massD0bar, hfHelper.cosThetaStarD0bar(candidate), topolChi2PerNdf, ctD, yD, eD, 0, 0); + fillTable(candidate, 1, massD0bar, topolChi2PerNdf, ctD, yD, eD, 0, 0); } } } void processDataWithDCAFitterN(aod::Collisions const& collisions, - soa::Filtered> const& candidates, - TracksWPid const& tracks, + soa::Filtered> const& candidates, + aod::Tracks const& tracks, aod::BCs const& bcs) { - processData(collisions, candidates, tracks, bcs); + processData(collisions, candidates, tracks, bcs); } PROCESS_SWITCH(HfTreeCreatorD0ToKPi, processDataWithDCAFitterN, "Process data with DCAFitterN", true); + void processDataWithDCAFitterNMl(aod::Collisions const& collisions, + soa::Filtered> const& candidates, + aod::Tracks const& tracks, + aod::BCs const& bcs) + { + processData(collisions, candidates, tracks, bcs); + } + PROCESS_SWITCH(HfTreeCreatorD0ToKPi, processDataWithDCAFitterNMl, "Process data with DCAFitterN and ML", false); + void processDataWithKFParticle(aod::Collisions const& collisions, - soa::Filtered> const& candidates, - TracksWPid const& tracks, + soa::Filtered> const& candidates, + aod::Tracks const& tracks, aod::BCs const& bcs) { - processData(collisions, candidates, tracks, bcs); + processData(collisions, candidates, tracks, bcs); } PROCESS_SWITCH(HfTreeCreatorD0ToKPi, processDataWithKFParticle, "Process data with KFParticle", false); - template + void processDataWithKFParticleMl(aod::Collisions const& collisions, + soa::Filtered> const& candidates, + aod::Tracks const& tracks, + aod::BCs const& bcs) + { + processData(collisions, candidates, tracks, bcs); + } + PROCESS_SWITCH(HfTreeCreatorD0ToKPi, processDataWithKFParticleMl, "Process data with KFParticle and ML", false); + + template void processMc(aod::Collisions const& collisions, aod::McCollisions const&, CandType const& candidates, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const&, + aod::Tracks const&, aod::BCs const&) { // Filling event properties @@ -444,13 +499,16 @@ struct HfTreeCreatorD0ToKPi { } else { rowCandidateFull.reserve(candidates.size()); } + if constexpr (applyMl) { + rowCandidateMl.reserve(candidates.size()); + } for (const auto& candidate : candidates) { if constexpr (onlyBkg) { if (TESTBIT(std::abs(candidate.flagMcMatchRec()), aod::hf_cand_2prong::DecayType::D0ToPiK)) { continue; } if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } @@ -461,8 +519,6 @@ struct HfTreeCreatorD0ToKPi { continue; } } - auto prong0 = candidate.template prong0_as(); - auto prong1 = candidate.template prong1_as(); double yD = hfHelper.yD0(candidate); double eD = hfHelper.eD0(candidate); double ctD = hfHelper.ctD0(candidate); @@ -477,10 +533,10 @@ struct HfTreeCreatorD0ToKPi { massD0bar = hfHelper.invMassD0barToKPi(candidate); } if (candidate.isSelD0()) { - fillTable(candidate, prong0, prong1, 0, massD0, hfHelper.cosThetaStarD0(candidate), topolChi2PerNdf, ctD, yD, eD, candidate.flagMcMatchRec(), candidate.originMcRec()); + fillTable(candidate, 0, massD0, topolChi2PerNdf, ctD, yD, eD, candidate.flagMcMatchRec(), candidate.originMcRec()); } if (candidate.isSelD0bar()) { - fillTable(candidate, prong0, prong1, 1, massD0bar, hfHelper.cosThetaStarD0bar(candidate), topolChi2PerNdf, ctD, yD, eD, candidate.flagMcMatchRec(), candidate.originMcRec()); + fillTable(candidate, 1, massD0bar, topolChi2PerNdf, ctD, yD, eD, candidate.flagMcMatchRec(), candidate.originMcRec()); } } @@ -505,67 +561,133 @@ struct HfTreeCreatorD0ToKPi { aod::McCollisions const& mcCollisions, SelectedCandidatesMc const&, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - processMc(collisions, mcCollisions, reconstructedCandSig, mcParticles, tracks, bcs); + processMc(collisions, mcCollisions, reconstructedCandSig, mcParticles, tracks, bcs); } PROCESS_SWITCH(HfTreeCreatorD0ToKPi, processMcWithDCAFitterOnlySig, "Process MC with DCAFitterN only for signals", false); + void processMcWithDCAFitterOnlySigMl(aod::Collisions const& collisions, + aod::McCollisions const& mcCollisions, + SelectedCandidatesMcMl const&, + MatchedGenCandidatesMc const& mcParticles, + aod::Tracks const& tracks, + aod::BCs const& bcs) + { + processMc(collisions, mcCollisions, reconstructedCandSigMl, mcParticles, tracks, bcs); + } + PROCESS_SWITCH(HfTreeCreatorD0ToKPi, processMcWithDCAFitterOnlySigMl, "Process MC with DCAFitterN only for signals and ML", false); + void processMcWithDCAFitterOnlyBkg(aod::Collisions const& collisions, aod::McCollisions const& mcCollisions, SelectedCandidatesMc const&, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - processMc(collisions, mcCollisions, reconstructedCandBkg, mcParticles, tracks, bcs); + processMc(collisions, mcCollisions, reconstructedCandBkg, mcParticles, tracks, bcs); } PROCESS_SWITCH(HfTreeCreatorD0ToKPi, processMcWithDCAFitterOnlyBkg, "Process MC with DCAFitterN only for background", false); + void processMcWithDCAFitterOnlyBkgMl(aod::Collisions const& collisions, + aod::McCollisions const& mcCollisions, + SelectedCandidatesMcMl const&, + MatchedGenCandidatesMc const& mcParticles, + aod::Tracks const& tracks, + aod::BCs const& bcs) + { + processMc(collisions, mcCollisions, reconstructedCandBkgMl, mcParticles, tracks, bcs); + } + PROCESS_SWITCH(HfTreeCreatorD0ToKPi, processMcWithDCAFitterOnlyBkgMl, "Process MC with DCAFitterN only for background with ML", false); + void processMcWithDCAFitterAll(aod::Collisions const& collisions, aod::McCollisions const& mcCollisions, SelectedCandidatesMc const& candidates, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - processMc(collisions, mcCollisions, candidates, mcParticles, tracks, bcs); + processMc(collisions, mcCollisions, candidates, mcParticles, tracks, bcs); } PROCESS_SWITCH(HfTreeCreatorD0ToKPi, processMcWithDCAFitterAll, "Process MC with DCAFitterN", false); + void processMcWithDCAFitterAllMl(aod::Collisions const& collisions, + aod::McCollisions const& mcCollisions, + SelectedCandidatesMcMl const& candidates, + MatchedGenCandidatesMc const& mcParticles, + aod::Tracks const& tracks, + aod::BCs const& bcs) + { + processMc(collisions, mcCollisions, candidates, mcParticles, tracks, bcs); + } + PROCESS_SWITCH(HfTreeCreatorD0ToKPi, processMcWithDCAFitterAllMl, "Process MC with DCAFitterN with ML", false); + void processMcWithKFParticleOnlySig(aod::Collisions const& collisions, aod::McCollisions const& mcCollisions, SelectedCandidatesMcKf const&, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - processMc(collisions, mcCollisions, reconstructedCandSigKF, mcParticles, tracks, bcs); + processMc(collisions, mcCollisions, reconstructedCandSigKF, mcParticles, tracks, bcs); } PROCESS_SWITCH(HfTreeCreatorD0ToKPi, processMcWithKFParticleOnlySig, "Process MC with KFParticle only for signals", false); + void processMcWithKFParticleOnlySigMl(aod::Collisions const& collisions, + aod::McCollisions const& mcCollisions, + SelectedCandidatesMcKfMl const&, + MatchedGenCandidatesMc const& mcParticles, + aod::Tracks const& tracks, + aod::BCs const& bcs) + { + processMc(collisions, mcCollisions, reconstructedCandSigKFMl, mcParticles, tracks, bcs); + } + PROCESS_SWITCH(HfTreeCreatorD0ToKPi, processMcWithKFParticleOnlySigMl, "Process MC with KFParticle only for signals with ML", false); + void processMcWithKFParticleOnlyBkg(aod::Collisions const& collisions, aod::McCollisions const& mcCollisions, SelectedCandidatesMcKf const&, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - processMc(collisions, mcCollisions, reconstructedCandBkgKF, mcParticles, tracks, bcs); + processMc(collisions, mcCollisions, reconstructedCandBkgKF, mcParticles, tracks, bcs); } PROCESS_SWITCH(HfTreeCreatorD0ToKPi, processMcWithKFParticleOnlyBkg, "Process MC with KFParticle only for background", false); + void processMcWithKFParticleOnlyBkgMl(aod::Collisions const& collisions, + aod::McCollisions const& mcCollisions, + SelectedCandidatesMcKfMl const&, + MatchedGenCandidatesMc const& mcParticles, + aod::Tracks const& tracks, + aod::BCs const& bcs) + { + processMc(collisions, mcCollisions, reconstructedCandBkgKFMl, mcParticles, tracks, bcs); + } + PROCESS_SWITCH(HfTreeCreatorD0ToKPi, processMcWithKFParticleOnlyBkgMl, "Process MC with KFParticle only for background with ML", false); + void processMcWithKFParticleAll(aod::Collisions const& collisions, aod::McCollisions const& mcCollisions, SelectedCandidatesMcKf const& candidates, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - processMc(collisions, mcCollisions, candidates, mcParticles, tracks, bcs); + processMc(collisions, mcCollisions, candidates, mcParticles, tracks, bcs); } PROCESS_SWITCH(HfTreeCreatorD0ToKPi, processMcWithKFParticleAll, "Process MC with KFParticle", false); + + void processMcWithKFParticleAllMl(aod::Collisions const& collisions, + aod::McCollisions const& mcCollisions, + SelectedCandidatesMcKfMl const& candidates, + MatchedGenCandidatesMc const& mcParticles, + aod::Tracks const& tracks, + aod::BCs const& bcs) + { + processMc(collisions, mcCollisions, candidates, mcParticles, tracks, bcs); + } + PROCESS_SWITCH(HfTreeCreatorD0ToKPi, processMcWithKFParticleAllMl, "Process MC with KFParticle with ML", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/TableProducer/treeCreatorDplusToPiKPi.cxx b/PWGHF/TableProducer/treeCreatorDplusToPiKPi.cxx index b7e66144251..8a8705cacce 100644 --- a/PWGHF/TableProducer/treeCreatorDplusToPiKPi.cxx +++ b/PWGHF/TableProducer/treeCreatorDplusToPiKPi.cxx @@ -16,17 +16,21 @@ /// /// \author Alexandre Bigot , IPHC Strasbourg +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::hf_centrality; namespace o2::aod { @@ -50,6 +54,7 @@ DECLARE_SOA_COLUMN(Y, y, float); DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity of candidate DECLARE_SOA_COLUMN(Phi, phi, float); //! Azimuth angle of candidate DECLARE_SOA_COLUMN(E, e, float); //! Energy of candidate (GeV) +DECLARE_SOA_COLUMN(Centrality, centrality, float); //! Collision centrality DECLARE_SOA_COLUMN(NSigTpcPi0, nSigTpcPi0, float); //! TPC Nsigma separation for prong0 with pion mass hypothesis DECLARE_SOA_COLUMN(NSigTpcKa0, nSigTpcKa0, float); //! TPC Nsigma separation for prong0 with kaon mass hypothesis DECLARE_SOA_COLUMN(NSigTofPi0, nSigTofPi0, float); //! TOF Nsigma separation for prong0 with pion mass hypothesis @@ -79,7 +84,13 @@ DECLARE_SOA_COLUMN(Ct, ct, float); // Events DECLARE_SOA_COLUMN(IsEventReject, isEventReject, int); //! Event rejection flag DECLARE_SOA_COLUMN(RunNumber, runNumber, int); //! Run number +// ML scores +DECLARE_SOA_COLUMN(MlScore0, mlScore0, float); //! ML score of the first configured index +DECLARE_SOA_COLUMN(MlScore1, mlScore1, float); //! ML score of the second configured index } // namespace full +DECLARE_SOA_TABLE(HfCandDpMls, "AOD", "HFCANDDPML", + full::MlScore0, + full::MlScore1) DECLARE_SOA_TABLE(HfCandDpLites, "AOD", "HFCANDDPLITE", hf_cand::Chi2PCA, @@ -123,8 +134,10 @@ DECLARE_SOA_TABLE(HfCandDpLites, "AOD", "HFCANDDPLITE", full::Eta, full::Phi, full::Y, + full::Centrality, hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcRec) + hf_cand_3prong::OriginMcRec, + hf_cand_3prong::FlagMcDecayChanRec) DECLARE_SOA_TABLE(HfCandDpFulls, "AOD", "HFCANDDPFULL", collision::BCId, @@ -203,8 +216,10 @@ DECLARE_SOA_TABLE(HfCandDpFulls, "AOD", "HFCANDDPFULL", full::Phi, full::Y, full::E, + full::Centrality, hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcRec); + hf_cand_3prong::OriginMcRec, + hf_cand_3prong::FlagMcDecayChanRec); DECLARE_SOA_TABLE(HfCandDpFullEvs, "AOD", "HFCANDDPFULLEV", collision::BCId, @@ -231,26 +246,34 @@ struct HfTreeCreatorDplusToPiKPi { Produces rowCandidateFullEvents; Produces rowCandidateFullParticles; Produces rowCandidateLite; + Produces rowCandidateMl; Configurable selectionFlagDplus{"selectionFlagDplus", 1, "Selection Flag for Dplus"}; Configurable fillCandidateLiteTable{"fillCandidateLiteTable", false, "Switch to fill lite table with candidate properties"}; // parameters for production of training samples Configurable fillOnlySignal{"fillOnlySignal", false, "Flag to fill derived tables with signal for ML trainings"}; + Configurable fillOnlySignalMl{"fillOnlySignalMl", false, "Flag to fill derived tables with MC and ML info"}; Configurable fillOnlyBackground{"fillOnlyBackground", false, "Flag to fill derived tables with background for ML trainings"}; Configurable downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of background candidates to keep for ML trainings"}; Configurable ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"}; + Configurable> classMlIndexes{"classMlIndexes", {0, 2}, "Indexes of ML bkg and non-prompt scores."}; + Configurable centEstimator{"centEstimator", 0, "Centrality estimation (None: 0, FT0C: 2, FT0M: 3)"}; HfHelper hfHelper; using SelectedCandidatesMc = soa::Filtered>; using MatchedGenCandidatesMc = soa::Filtered>; + using SelectedCandidatesMcWithMl = soa::Filtered>; using TracksWPid = soa::Join; + using CollisionsCent = soa::Join; + Filter filterSelectCandidates = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; Filter filterMcGenMatching = nabs(o2::aod::hf_cand_3prong::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi)); - Partition reconstructedCandSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi)); + Partition reconstructedCandSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi)) || nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi)); // DecayType::DsToKKPi is used to flag both Ds± → K± K∓ π± and D± → K± K∓ π± Partition reconstructedCandBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi)); + Partition reconstructedCandSigMl = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi)) || nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi)) || nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DstarToPiKPiBkg)); // DecayType::DsToKKPi is used to flag both Ds± → K± K∓ π± and D± → K± K∓ π± void init(InitContext const&) { @@ -269,20 +292,38 @@ struct HfTreeCreatorDplusToPiKPi { runNumber); } - template + template void fillCandidateTable(const T& candidate) { int8_t flagMc = 0; int8_t originMc = 0; + int8_t channelMc = 0; if constexpr (doMc) { flagMc = candidate.flagMcMatchRec(); originMc = candidate.originMcRec(); + channelMc = candidate.flagMcDecayChanRec(); + } + + std::vector outputMl = {-999., -999.}; + if constexpr (doMl) { + for (unsigned int iclass = 0; iclass < classMlIndexes->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDplusToPiKPi()[classMlIndexes->at(iclass)]; + } + rowCandidateMl( + outputMl[0], + outputMl[1]); } auto prong0 = candidate.template prong0_as(); auto prong1 = candidate.template prong1_as(); auto prong2 = candidate.template prong2_as(); + float cent{-1.}; + auto coll = candidate.template collision_as(); + if (std::is_same_v && centEstimator != CentralityEstimator::None) { + cent = getCentralityColl(coll, centEstimator); + } + if (fillCandidateLiteTable) { rowCandidateLite( candidate.chi2PCA(), @@ -326,12 +367,14 @@ struct HfTreeCreatorDplusToPiKPi { candidate.eta(), candidate.phi(), hfHelper.yDplus(candidate), + cent, flagMc, - originMc); + originMc, + channelMc); } else { rowCandidateFull( - candidate.collision().bcId(), - candidate.collision().numContrib(), + coll.bcId(), + coll.numContrib(), candidate.posX(), candidate.posY(), candidate.posZ(), @@ -406,8 +449,10 @@ struct HfTreeCreatorDplusToPiKPi { candidate.phi(), hfHelper.yDplus(candidate), hfHelper.eDplus(candidate), + cent, flagMc, - originMc); + originMc, + channelMc); } } @@ -429,12 +474,12 @@ struct HfTreeCreatorDplusToPiKPi { } for (const auto& candidate : candidates) { if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } } - fillCandidateTable(candidate); + fillCandidateTable(candidate); } } @@ -444,6 +489,7 @@ struct HfTreeCreatorDplusToPiKPi { aod::McCollisions const&, SelectedCandidatesMc const& candidates, MatchedGenCandidatesMc const& particles, + SelectedCandidatesMcWithMl const&, TracksWPid const&) { // Filling event properties @@ -460,7 +506,23 @@ struct HfTreeCreatorDplusToPiKPi { rowCandidateFull.reserve(reconstructedCandSig.size()); } for (const auto& candidate : reconstructedCandSig) { - fillCandidateTable(candidate); + fillCandidateTable(candidate); + } + } else if (fillOnlySignalMl) { + rowCandidateMl.reserve(reconstructedCandSigMl.size()); + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(reconstructedCandSigMl.size()); + } else { + rowCandidateFull.reserve(reconstructedCandSigMl.size()); + } + for (const auto& candidate : reconstructedCandSigMl) { + if (downSampleBkgFactor < 1.) { + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + } + fillCandidateTable(candidate); } } else if (fillOnlyBackground) { if (fillCandidateLiteTable) { @@ -470,12 +532,12 @@ struct HfTreeCreatorDplusToPiKPi { } for (const auto& candidate : reconstructedCandBkg) { if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } } - fillCandidateTable(candidate); + fillCandidateTable(candidate); } } else { if (fillCandidateLiteTable) { @@ -484,7 +546,7 @@ struct HfTreeCreatorDplusToPiKPi { rowCandidateFull.reserve(candidates.size()); } for (const auto& candidate : candidates) { - fillCandidateTable(candidate); + fillCandidateTable(candidate); } } @@ -503,6 +565,116 @@ struct HfTreeCreatorDplusToPiKPi { } PROCESS_SWITCH(HfTreeCreatorDplusToPiKPi, processMc, "Process MC", false); + + void processDataWCent(CollisionsCent const& collisions, + soa::Filtered> const& candidates, + TracksWPid const&) + { + // Filling event properties + rowCandidateFullEvents.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, 0, 1); + } + + // Filling candidate properties + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(candidates.size()); + } else { + rowCandidateFull.reserve(candidates.size()); + } + for (const auto& candidate : candidates) { + if (downSampleBkgFactor < 1.) { + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + } + fillCandidateTable(candidate); + } + } + + PROCESS_SWITCH(HfTreeCreatorDplusToPiKPi, processDataWCent, "Process data with cent", false); + + void processMcWCent(CollisionsCent const& collisions, + aod::McCollisions const&, + SelectedCandidatesMc const& candidates, + MatchedGenCandidatesMc const& particles, + SelectedCandidatesMcWithMl const&, + TracksWPid const&) + { + // Filling event properties + rowCandidateFullEvents.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, 0, 1); + } + + // Filling candidate properties + if (fillOnlySignal) { + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(reconstructedCandSig.size()); + } else { + rowCandidateFull.reserve(reconstructedCandSig.size()); + } + for (const auto& candidate : reconstructedCandSig) { + fillCandidateTable(candidate); + } + } else if (fillOnlySignalMl) { + rowCandidateMl.reserve(reconstructedCandSigMl.size()); + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(reconstructedCandSigMl.size()); + } else { + rowCandidateFull.reserve(reconstructedCandSigMl.size()); + } + for (const auto& candidate : reconstructedCandSigMl) { + if (downSampleBkgFactor < 1.) { + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + } + fillCandidateTable(candidate); + } + } else if (fillOnlyBackground) { + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(reconstructedCandBkg.size()); + } else { + rowCandidateFull.reserve(reconstructedCandBkg.size()); + } + for (const auto& candidate : reconstructedCandBkg) { + if (downSampleBkgFactor < 1.) { + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + } + fillCandidateTable(candidate); + } + } else { + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(candidates.size()); + } else { + rowCandidateFull.reserve(candidates.size()); + } + for (const auto& candidate : candidates) { + fillCandidateTable(candidate); + } + } + + // Filling particle properties + rowCandidateFullParticles.reserve(particles.size()); + for (const auto& particle : particles) { + rowCandidateFullParticles( + particle.mcCollision().bcId(), + particle.pt(), + particle.eta(), + particle.phi(), + RecoDecay::y(particle.pVector(), o2::constants::physics::MassDPlus), + particle.flagMcMatchGen(), + particle.originMcGen()); + } + } + + PROCESS_SWITCH(HfTreeCreatorDplusToPiKPi, processMcWCent, "Process MC with cent", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/TableProducer/treeCreatorDsToKKPi.cxx b/PWGHF/TableProducer/treeCreatorDsToKKPi.cxx index 4e7e3fb7471..bb854c441fb 100644 --- a/PWGHF/TableProducer/treeCreatorDsToKKPi.cxx +++ b/PWGHF/TableProducer/treeCreatorDsToKKPi.cxx @@ -22,6 +22,7 @@ #include "Framework/runDataProcessing.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" @@ -77,10 +78,11 @@ DECLARE_SOA_COLUMN(MaxNormalisedDeltaIP, maxNormalisedDeltaIP, float); //! DECLARE_SOA_COLUMN(ImpactParameterXY, impactParameterXY, float); //! Transverse impact parameter of candidate (cm) DECLARE_SOA_COLUMN(DeltaMassPhi, deltaMassPhi, float); //! Absolute mass difference between kaon-pair and phi-meson invariant mass (Gev/c2) DECLARE_SOA_COLUMN(AbsCos3PiK, absCos3PiK, float); //! Cube of absolute value of the cosine of pion-kaon angle in the phi rest frame +DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! Sign of the candidate // Events DECLARE_SOA_COLUMN(IsEventReject, isEventReject, int); //! Event rejection flag DECLARE_SOA_COLUMN(RunNumber, runNumber, int); //! Run number -DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! Sign +DECLARE_SOA_COLUMN(Centrality, centrality, float); //! Centrality (or multiplicity) percentile } // namespace full DECLARE_SOA_TABLE(HfCandDsLites, "AOD", "HFCANDDSLITE", @@ -126,9 +128,12 @@ DECLARE_SOA_TABLE(HfCandDsLites, "AOD", "HFCANDDSLITE", full::DeltaMassPhi, full::AbsCos3PiK, hf_cand::Chi2PCA, + full::Centrality, + collision::NumContrib, hf_cand_3prong::FlagMcMatchRec, hf_cand_3prong::OriginMcRec, hf_cand_3prong::FlagMcDecayChanRec, + hf_cand_3prong::IsCandidateSwapped, full::Sign); DECLARE_SOA_TABLE(HfCandDsFulls, "AOD", "HFCANDDSFULL", @@ -197,9 +202,11 @@ DECLARE_SOA_TABLE(HfCandDsFulls, "AOD", "HFCANDDSFULL", full::DeltaMassPhi, full::AbsCos3PiK, hf_cand::Chi2PCA, + full::Centrality, hf_cand_3prong::FlagMcMatchRec, hf_cand_3prong::OriginMcRec, hf_cand_3prong::FlagMcDecayChanRec, + hf_cand_3prong::IsCandidateSwapped, full::Sign); DECLARE_SOA_TABLE(HfCandDsFullEvs, "AOD", "HFCANDDSFULLEV", @@ -208,6 +215,7 @@ DECLARE_SOA_TABLE(HfCandDsFullEvs, "AOD", "HFCANDDSFULLEV", collision::PosX, collision::PosY, collision::PosZ, + full::Centrality, full::IsEventReject, full::RunNumber); @@ -245,6 +253,10 @@ struct HfTreeCreatorDsToKKPi { using CandDsMcGen = soa::Filtered>; using TracksWPid = soa::Join; + using CollisionsWithFT0C = soa::Join; + using CollisionsWithFT0M = soa::Join; + using CollisionsWithNTracksPV = soa::Join; + int offsetDplusDecayChannel = aod::hf_cand_3prong::DecayChannelDToKKPi::DplusToPhiPi - aod::hf_cand_3prong::DecayChannelDToKKPi::DsToPhiPi; // Offset between Dplus and Ds to use the same decay channel. See aod::hf_cand_3prong::DecayChannelDToKKPi Filter filterSelectCandidates = aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlagDs || aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlagDs; @@ -269,6 +281,7 @@ struct HfTreeCreatorDsToKKPi { collision.posX(), collision.posY(), collision.posZ(), + o2::hf_centrality::getCentralityColl(collision), isEventReject, runNumber); } @@ -277,12 +290,13 @@ struct HfTreeCreatorDsToKKPi { /// \param doMc true to fill MC information /// \param massHypo mass hypothesis considered: 0 = KKPi, 1 = PiKK /// \param candidate is candidate - template + template void fillCandidateTable(const T& candidate) { int8_t flagMc = 0; int8_t originMc = 0; int8_t channelMc = 0; + int8_t isSwapped = massHypo; // 0 if KKPi, 1 if PiKK float yCand = 0; float eCand = 0; float ctCand = 0; @@ -290,6 +304,7 @@ struct HfTreeCreatorDsToKKPi { flagMc = candidate.flagMcMatchRec(); originMc = candidate.originMcRec(); channelMc = candidate.flagMcDecayChanRec(); + isSwapped = candidate.isCandidateSwapped(); if (fillDplusMc && candidate.flagMcDecayChanRec() == (decayChannel + offsetDplusDecayChannel)) { yCand = hfHelper.yDplus(candidate); eCand = hfHelper.eDplus(candidate); @@ -314,6 +329,9 @@ struct HfTreeCreatorDsToKKPi { absCos3PiKDs = hfHelper.absCos3PiKDsToPiKK(candidate); } + auto const& collision = candidate.template collision_as(); + float centrality = o2::hf_centrality::getCentralityColl(collision); + auto prong0 = candidate.template prong0_as(); auto prong1 = candidate.template prong1_as(); auto prong2 = candidate.template prong2_as(); @@ -344,8 +362,8 @@ struct HfTreeCreatorDsToKKPi { prong2.tofNSigmaKa(), prong2.tpcTofNSigmaPi(), prong2.tpcTofNSigmaKa(), - candidate.isSelDsToKKPi(), - candidate.isSelDsToPiKK(), + massHypo == 0 ? candidate.isSelDsToKKPi() : -1, + massHypo == 1 ? candidate.isSelDsToPiKK() : -1, invMassDs, candidate.pt(), candidate.eta(), @@ -362,14 +380,17 @@ struct HfTreeCreatorDsToKKPi { deltaMassPhiKK, absCos3PiKDs, candidate.chi2PCA(), + centrality, + candidate.template collision_as().numContrib(), flagMc, originMc, channelMc, + isSwapped, prong0.sign() + prong1.sign() + prong2.sign()); } else { rowCandidateFull( - candidate.collision().bcId(), - candidate.collision().numContrib(), + candidate.template collision_as().bcId(), + candidate.template collision_as().numContrib(), candidate.posX(), candidate.posY(), candidate.posZ(), @@ -409,8 +430,8 @@ struct HfTreeCreatorDsToKKPi { prong2.tofNSigmaKa(), prong2.tpcTofNSigmaPi(), prong2.tpcTofNSigmaKa(), - candidate.isSelDsToKKPi(), - candidate.isSelDsToPiKK(), + massHypo == 0 ? candidate.isSelDsToKKPi() : -1, + massHypo == 1 ? candidate.isSelDsToPiKK() : -1, candidate.xSecondaryVertex(), candidate.ySecondaryVertex(), candidate.zSecondaryVertex(), @@ -433,16 +454,18 @@ struct HfTreeCreatorDsToKKPi { deltaMassPhiKK, absCos3PiKDs, candidate.chi2PCA(), + centrality, flagMc, originMc, channelMc, + isSwapped, prong0.sign() + prong1.sign() + prong2.sign()); } } - void processData(aod::Collisions const& collisions, - CandDsData const&, - TracksWPid const&) + template + void runData(Coll const& collisions, + CandDsData const&) { // Filling event properties rowCandidateFullEvents.reserve(collisions.size()); @@ -459,32 +482,30 @@ struct HfTreeCreatorDsToKKPi { for (const auto& candidate : selectedDsToKKPiCand) { if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } } - fillCandidateTable(candidate); + fillCandidateTable(candidate); } for (const auto& candidate : selectedDsToPiKKCand) { if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } } - fillCandidateTable(candidate); + fillCandidateTable(candidate); } } - PROCESS_SWITCH(HfTreeCreatorDsToKKPi, processData, "Process data", true); - - void processMc(aod::Collisions const& collisions, - aod::McCollisions const&, - CandDsMcReco const&, - CandDsMcGen const& mcParticles, - TracksWPid const&) + template + void runMc(Coll const& collisions, + aod::McCollisions const&, + CandDsMcReco const&, + CandDsMcGen const& mcParticles) { // Filling event properties rowCandidateFullEvents.reserve(collisions.size()); @@ -502,10 +523,10 @@ struct HfTreeCreatorDsToKKPi { for (const auto& candidate : reconstructedCandSig) { if (candidate.isCandidateSwapped() == 0) { - fillCandidateTable(candidate); + fillCandidateTable(candidate); } if (candidate.isCandidateSwapped() == 1) { - fillCandidateTable(candidate); + fillCandidateTable(candidate); } } } else if (fillOnlyBackground) { @@ -517,17 +538,17 @@ struct HfTreeCreatorDsToKKPi { for (const auto& candidate : reconstructedCandBkg) { if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } } // Bkg candidates are not matched to MC so rely on selections only if (candidate.isSelDsToKKPi() >= selectionFlagDs) { - fillCandidateTable(candidate); + fillCandidateTable(candidate); } if (candidate.isSelDsToPiKK() >= selectionFlagDs) { - fillCandidateTable(candidate); + fillCandidateTable(candidate); } } } else { @@ -539,20 +560,20 @@ struct HfTreeCreatorDsToKKPi { for (const auto& candidate : reconstructedCandSig) { if (candidate.isCandidateSwapped() == 0) { - fillCandidateTable(candidate); + fillCandidateTable(candidate); } if (candidate.isCandidateSwapped() == 1) { - fillCandidateTable(candidate); + fillCandidateTable(candidate); } } for (const auto& candidate : reconstructedCandBkg) { // Bkg candidates are not matched to MC so rely on selections only if (candidate.isSelDsToKKPi() >= selectionFlagDs) { - fillCandidateTable(candidate); + fillCandidateTable(candidate); } if (candidate.isSelDsToPiKK() >= selectionFlagDs) { - fillCandidateTable(candidate); + fillCandidateTable(candidate); } } } @@ -571,7 +592,77 @@ struct HfTreeCreatorDsToKKPi { } } - PROCESS_SWITCH(HfTreeCreatorDsToKKPi, processMc, "Process MC", false); + void processDataWithFT0C(CollisionsWithFT0C const& collisions, + CandDsData const& candsDs, + TracksWPid const&) + { + runData(collisions, candsDs); + } + PROCESS_SWITCH(HfTreeCreatorDsToKKPi, processDataWithFT0C, "Process data with centrality information from FT0C", false); + + void processDataWithFT0M(CollisionsWithFT0M const& collisions, + CandDsData const& candsDs, + TracksWPid const&) + { + runData(collisions, candsDs); + } + PROCESS_SWITCH(HfTreeCreatorDsToKKPi, processDataWithFT0M, "Process data with centrality information from FT0M", false); + + void processDataWithNTracksPV(CollisionsWithNTracksPV const& collisions, + CandDsData const& candsDs, + TracksWPid const&) + { + runData(collisions, candsDs); + } + PROCESS_SWITCH(HfTreeCreatorDsToKKPi, processDataWithNTracksPV, "Process data with centrality information from NTracksPV", false); + + void processData(soa::Join const& collisions, + CandDsData const& candsDs, + TracksWPid const&) + { + runData>(collisions, candsDs); + } + PROCESS_SWITCH(HfTreeCreatorDsToKKPi, processData, "Process data without centrality information", true); + + void processMcWithFT0C(CollisionsWithFT0C const& collisions, + aod::McCollisions const& mcCollisions, + CandDsMcReco const& mcRecoCands, + CandDsMcGen const& mcParticles, + TracksWPid const&) + { + runMc(collisions, mcCollisions, mcRecoCands, mcParticles); + } + PROCESS_SWITCH(HfTreeCreatorDsToKKPi, processMcWithFT0C, "Process MC with centrality information from FT0C", false); + + void processMcWithFT0M(CollisionsWithFT0M const& collisions, + aod::McCollisions const& mcCollisions, + CandDsMcReco const& mcRecoCands, + CandDsMcGen const& mcParticles, + TracksWPid const&) + { + runMc(collisions, mcCollisions, mcRecoCands, mcParticles); + } + PROCESS_SWITCH(HfTreeCreatorDsToKKPi, processMcWithFT0M, "Process MC with centrality information from FT0M", false); + + void processMcWithNTracksPV(CollisionsWithNTracksPV const& collisions, + aod::McCollisions const& mcCollisions, + CandDsMcReco const& mcRecoCands, + CandDsMcGen const& mcParticles, + TracksWPid const&) + { + runMc(collisions, mcCollisions, mcRecoCands, mcParticles); + } + PROCESS_SWITCH(HfTreeCreatorDsToKKPi, processMcWithNTracksPV, "Process MC with centrality information from NTracksPV", false); + + void processMc(soa::Join const& collisions, + aod::McCollisions const& mcCollisions, + CandDsMcReco const& mcRecoCands, + CandDsMcGen const& mcParticles, + TracksWPid const&) + { + runMc(collisions, mcCollisions, mcRecoCands, mcParticles); + } + PROCESS_SWITCH(HfTreeCreatorDsToKKPi, processMc, "Process MC without centrality information", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/TableProducer/treeCreatorDstarToD0Pi.cxx b/PWGHF/TableProducer/treeCreatorDstarToD0Pi.cxx index 06d77fa4e04..fd11fad78b1 100644 --- a/PWGHF/TableProducer/treeCreatorDstarToD0Pi.cxx +++ b/PWGHF/TableProducer/treeCreatorDstarToD0Pi.cxx @@ -86,6 +86,7 @@ DECLARE_SOA_COLUMN(Phi, phi, float); DECLARE_SOA_COLUMN(Y, y, float); DECLARE_SOA_COLUMN(E, e, float); DECLARE_SOA_COLUMN(CandidateSelFlag, candidateSelFlag, int8_t); +DECLARE_SOA_COLUMN(PtBhadMother, ptBhadMother, float); // Events DECLARE_SOA_COLUMN(IsEventReject, isEventReject, int); @@ -142,10 +143,11 @@ DECLARE_SOA_TABLE(HfCandDstLites, "AOD", "HFCANDDSTLITE", full::Y, full::CandidateSelFlag, hf_cand_dstar::FlagMcMatchRec, - hf_cand_dstar::OriginMcRec) + hf_cand_dstar::OriginMcRec, + full::PtBhadMother) DECLARE_SOA_TABLE(HfCandDstFulls, "AOD", "HFCANDDSTFULL", - full::CollisionId, + collision::BCId, collision::NumContrib, collision::PosX, collision::PosY, @@ -214,7 +216,8 @@ DECLARE_SOA_TABLE(HfCandDstFulls, "AOD", "HFCANDDSTFULL", full::E, full::CandidateSelFlag, hf_cand_dstar::FlagMcMatchRec, - hf_cand_dstar::OriginMcRec); + hf_cand_dstar::OriginMcRec, + full::PtBhadMother); DECLARE_SOA_TABLE(HfCandDstFullEvs, "AOD", "HFCANDDSTFULLEV", collision::BCId, @@ -232,7 +235,8 @@ DECLARE_SOA_TABLE(HfCandDstFullPs, "AOD", "HFCANDDSTFULLP", full::Phi, full::Y, hf_cand_dstar::FlagMcMatchGen, - hf_cand_dstar::OriginMcGen); + hf_cand_dstar::OriginMcGen, + full::PtBhadMother); } // namespace o2::aod @@ -280,7 +284,7 @@ struct HfTreeCreatorDstarToD0Pi { } template - void fillCandidateTable(const T& candidate) + void fillCandidateTable(const T& candidate, float ptBhadMotherPart = -1) { int8_t flagMc{0}; int8_t originMc{0}; @@ -289,21 +293,50 @@ struct HfTreeCreatorDstarToD0Pi { originMc = candidate.originMcRec(); } - auto prong0 = candidate.template prong0_as(); - auto prong1 = candidate.template prong1_as(); + TracksWPid::iterator prong0; + TracksWPid::iterator prong1; auto prongSoftPi = candidate.template prongPi_as(); float massD0{-1.f}; float massDStar{-1.f}; float cosThetaD0{-1.f}; + float impParameterProng0{-999.}, impParameterProng1{-999.}; + // float errorImpParameterProng0{-999.}, errorImpParameterProng1{-999.}; + float impParameterNormalisedProng0{-999.}, impParameterNormalisedProng1{-999.}; + float ptProng0{-999.}, ptProng1{-999.}; + float pProng0{-999.}, pProng1{-999.}; if (candidate.signSoftPi() > 0) { massD0 = candidate.invMassD0(); massDStar = candidate.invMassDstar(); cosThetaD0 = candidate.cosThetaStarD0(); + prong0 = candidate.template prong0_as(); // pion + prong1 = candidate.template prong1_as(); // kaon + ptProng0 = candidate.ptProng0(); + ptProng1 = candidate.ptProng1(); + impParameterProng0 = candidate.impactParameter0(); + impParameterProng1 = candidate.impactParameter1(); + // errorImpParameterProng0 = candidate.errorImpactParameter0(); + // errorImpParameterProng1 = candidate.errorImpactParameter1(); + impParameterNormalisedProng0 = candidate.impactParameterNormalised0(); + impParameterNormalisedProng1 = candidate.impactParameterNormalised1(); + pProng0 = RecoDecay::p(candidate.pxProng0(), candidate.pyProng0(), candidate.pzProng0()); + pProng1 = RecoDecay::p(candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1()); } else { massD0 = candidate.invMassD0Bar(); massDStar = candidate.invMassAntiDstar(); cosThetaD0 = candidate.cosThetaStarD0Bar(); + prong0 = candidate.template prong1_as(); // pion + prong1 = candidate.template prong0_as(); // kaon + ptProng0 = candidate.ptProng1(); + ptProng1 = candidate.ptProng0(); + impParameterProng0 = candidate.impactParameter1(); + impParameterProng1 = candidate.impactParameter0(); + // errorImpParameterProng0 = candidate.errorImpactParameter1(); + // errorImpParameterProng1 = candidate.errorImpactParameter0(); + impParameterNormalisedProng0 = candidate.impactParameterNormalised1(); + impParameterNormalisedProng1 = candidate.impactParameterNormalised0(); + pProng0 = RecoDecay::p(candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1()); + pProng1 = RecoDecay::p(candidate.pxProng0(), candidate.pyProng0(), candidate.pzProng0()); } if (fillCandidateLiteTable) { @@ -318,14 +351,14 @@ struct HfTreeCreatorDstarToD0Pi { candidate.deltaIPNormalisedMaxD0(), candidate.impactParameterProductD0(), cosThetaD0, - candidate.ptProng0(), - candidate.ptProng1(), + ptProng0, + ptProng1, candidate.ptSoftPi(), - candidate.impactParameter0(), - candidate.impactParameter1(), + impParameterProng0, + impParameterProng1, candidate.impParamSoftPi(), - candidate.impactParameterNormalised0(), - candidate.impactParameterNormalised1(), + impParameterNormalisedProng0, + impParameterNormalisedProng1, candidate.normalisedImpParamSoftPi(), prong0.tpcNSigmaPi(), prong0.tpcNSigmaKa(), @@ -357,7 +390,8 @@ struct HfTreeCreatorDstarToD0Pi { candidate.y(constants::physics::MassDStar), candidate.isSelDstarToD0Pi(), flagMc, - originMc); + originMc, + ptBhadMotherPart); } else { rowCandidateFull( candidate.collision().bcId(), @@ -380,17 +414,17 @@ struct HfTreeCreatorDstarToD0Pi { candidate.deltaIPNormalisedMaxD0(), candidate.impactParameterProductD0(), cosThetaD0, - RecoDecay::p(candidate.pxProng0(), candidate.pyProng0(), candidate.pzProng0()), - RecoDecay::p(candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1()), + pProng0, + pProng1, RecoDecay::p(candidate.pxSoftPi(), candidate.pySoftPi(), candidate.pzSoftPi()), - candidate.ptProng0(), - candidate.ptProng1(), + ptProng0, + ptProng1, candidate.ptSoftPi(), - candidate.impactParameter0(), - candidate.impactParameter1(), + impParameterProng0, + impParameterProng1, candidate.impParamSoftPi(), - candidate.impactParameterNormalised0(), - candidate.impactParameterNormalised1(), + impParameterNormalisedProng0, + impParameterNormalisedProng1, candidate.normalisedImpParamSoftPi(), candidate.errorImpactParameter0(), candidate.errorImpactParameter1(), @@ -429,7 +463,8 @@ struct HfTreeCreatorDstarToD0Pi { candidate.e(constants::physics::MassDStar), candidate.isSelDstarToD0Pi(), flagMc, - originMc); + originMc, + ptBhadMotherPart); } } @@ -451,7 +486,7 @@ struct HfTreeCreatorDstarToD0Pi { } for (const auto& candidate : candidates) { if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } @@ -482,7 +517,7 @@ struct HfTreeCreatorDstarToD0Pi { rowCandidateFull.reserve(reconstructedCandSig.size()); } for (const auto& candidate : reconstructedCandSig) { - fillCandidateTable(candidate); + fillCandidateTable(candidate, candidate.ptBhadMotherPart()); } } else if (fillOnlyBackground) { if (fillCandidateLiteTable) { @@ -492,7 +527,7 @@ struct HfTreeCreatorDstarToD0Pi { } for (const auto& candidate : reconstructedCandBkg) { if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } @@ -506,13 +541,20 @@ struct HfTreeCreatorDstarToD0Pi { rowCandidateFull.reserve(candidates.size()); } for (const auto& candidate : candidates) { - fillCandidateTable(candidate); + fillCandidateTable(candidate, candidate.ptBhadMotherPart()); } } // Filling particle properties rowCandidateFullParticles.reserve(particles.size()); for (const auto& particle : particles) { + + float ptBhadMother{-1.f}; + if (particle.originMcGen() == RecoDecay::OriginType::NonPrompt) { + auto bHadMother = particles.rawIteratorAt(particle.idxBhadMotherPart()); + ptBhadMother = bHadMother.pt(); + } + rowCandidateFullParticles( particle.mcCollision().bcId(), particle.pt(), @@ -520,7 +562,8 @@ struct HfTreeCreatorDstarToD0Pi { particle.phi(), RecoDecay::y(particle.pVector(), o2::constants::physics::MassDStar), particle.flagMcMatchGen(), - particle.originMcGen()); + particle.originMcGen(), + ptBhadMother); } } diff --git a/PWGHF/TableProducer/treeCreatorLbToLcPi.cxx b/PWGHF/TableProducer/treeCreatorLbToLcPi.cxx index 42e8001022f..d69de17d4e8 100644 --- a/PWGHF/TableProducer/treeCreatorLbToLcPi.cxx +++ b/PWGHF/TableProducer/treeCreatorLbToLcPi.cxx @@ -21,8 +21,6 @@ #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" -#include "ALICE3/DataModel/RICH.h" - #include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" @@ -34,6 +32,7 @@ namespace o2::aod { namespace full { +DECLARE_SOA_COLUMN(ImpactParameterXY, impactParameterXY, float); DECLARE_SOA_COLUMN(RSecondaryVertex, rSecondaryVertex, float); DECLARE_SOA_COLUMN(PtProng0, ptProng0, float); DECLARE_SOA_COLUMN(PProng0, pProng0, float); @@ -52,20 +51,23 @@ DECLARE_SOA_COLUMN(DecayLength, decayLength, float); DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); DECLARE_SOA_COLUMN(DecayLengthXYNormalised, decayLengthXYNormalised, float); -DECLARE_SOA_COLUMN(CPA, cpa, float); -DECLARE_SOA_COLUMN(CPAXY, cpaXY, float); +DECLARE_SOA_COLUMN(CPA, cPA, float); +DECLARE_SOA_COLUMN(CPAXY, cPAXY, float); DECLARE_SOA_COLUMN(Ct, ct, float); -DECLARE_SOA_COLUMN(MCflag, mcflag, int8_t); +DECLARE_SOA_COLUMN(McFlag, mcFlag, int8_t); DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); -DECLARE_SOA_COLUMN(NSigRICHTrk0Pi, nsigRICHTrk0Pi, float); -DECLARE_SOA_COLUMN(NSigfRICHTrk0Pi, nsigfRICHTrk0Pi, float); -DECLARE_SOA_COLUMN(NSigTOFTrk0Pi, nsigTOFTrk0Pi, float); +DECLARE_SOA_COLUMN(SignTrk0, signTrk0, int16_t); +DECLARE_SOA_COLUMN(NSigTOFTrk0Pi, nSigTOFTrk0Pi, float); +DECLARE_SOA_COLUMN(NSigTPCTrk0Pi, nSigTPCTrk0Pi, float); // Lc selection parameters DECLARE_SOA_COLUMN(LcM, lcM, float); DECLARE_SOA_COLUMN(LcCt, lcCt, float); DECLARE_SOA_COLUMN(LcY, lcY, float); DECLARE_SOA_COLUMN(LcE, lcE, float); DECLARE_SOA_COLUMN(LcEta, lcEta, float); +DECLARE_SOA_COLUMN(LcVertexX, lcVertexX, float); +DECLARE_SOA_COLUMN(LcVertexY, lcVertexY, float); +DECLARE_SOA_COLUMN(LcVertexZ, lcVertexZ, float); DECLARE_SOA_COLUMN(LcCPA, lcCPA, float); DECLARE_SOA_COLUMN(LcCPAXY, lcCPAXY, float); DECLARE_SOA_COLUMN(LcChi2PCA, lcChi2PCA, float); @@ -73,39 +75,58 @@ DECLARE_SOA_COLUMN(LcDecayLength, lcDecayLength, float); DECLARE_SOA_COLUMN(LcDecayLengthXY, lcDecayLengthXY, float); DECLARE_SOA_COLUMN(LcDecayLengthNormalised, lcDecayLengthNormalised, float); DECLARE_SOA_COLUMN(LcImpactParameter0, lcImpactParameter0, float); +DECLARE_SOA_COLUMN(LcImpactParameterError0, lcImpactParameterError0, float); DECLARE_SOA_COLUMN(LcImpactParameter1, lcImpactParameter1, float); +DECLARE_SOA_COLUMN(LcImpactParameterError1, lcImpactParameterError1, float); DECLARE_SOA_COLUMN(LcImpactParameter2, lcImpactParameter2, float); -DECLARE_SOA_COLUMN(NSigRICHTrk1Pi, nSigRICHTrk1Pi, float); -DECLARE_SOA_COLUMN(NSigRICHTrk1Pr, nSigRICHTrk1Pr, float); -DECLARE_SOA_COLUMN(NSigRICHTrk2Ka, nSigRICHTrk2Ka, float); -DECLARE_SOA_COLUMN(NSigRICHTrk3Pi, nSigRICHTrk3Pi, float); -DECLARE_SOA_COLUMN(NSigRICHTrk3Pr, nSigRICHTrk3Pr, float); -DECLARE_SOA_COLUMN(NSigfRICHTrk1Pi, nSigfRICHTrk1Pi, float); -DECLARE_SOA_COLUMN(NSigfRICHTrk1Pr, nSigfRICHTrk1Pr, float); -DECLARE_SOA_COLUMN(NSigfRICHTrk2Ka, nSigfRICHTrk2Ka, float); -DECLARE_SOA_COLUMN(NSigfRICHTrk3Pi, nSigfRICHTrk3Pi, float); -DECLARE_SOA_COLUMN(NSigfRICHTrk3Pr, nSigfRICHTrk3Pr, float); -DECLARE_SOA_COLUMN(NSigTOFTrk1Pi, nSigTOFrk1Pi, float); -DECLARE_SOA_COLUMN(NSigTOFTrk1Pr, nSigTOFrk1Pr, float); -DECLARE_SOA_COLUMN(NSigTOFTrk2Ka, nSigTOFrk2Ka, float); -DECLARE_SOA_COLUMN(NSigTOFTrk3Pi, nSigTOFrk3Pi, float); -DECLARE_SOA_COLUMN(NSigTOFTrk3Pr, nSigTOFrk3Pr, float); +DECLARE_SOA_COLUMN(LcImpactParameterError2, lcImpactParameterError2, float); +DECLARE_SOA_COLUMN(LcPx0, lcPx0, float); +DECLARE_SOA_COLUMN(LcPy0, lcPy0, float); +DECLARE_SOA_COLUMN(LcPz0, lcPz0, float); +DECLARE_SOA_COLUMN(LcPx1, lcPx1, float); +DECLARE_SOA_COLUMN(LcPy1, lcPy1, float); +DECLARE_SOA_COLUMN(LcPz1, lcPz1, float); +DECLARE_SOA_COLUMN(LcPx2, lcPx2, float); +DECLARE_SOA_COLUMN(LcPy2, lcPy2, float); +DECLARE_SOA_COLUMN(LcPz2, lcPz2, float); +DECLARE_SOA_COLUMN(LcSignProng0, lcSignProng0, int16_t); +DECLARE_SOA_COLUMN(LcSignProng1, lcSignProng1, int16_t); +DECLARE_SOA_COLUMN(LcSignProng2, lcSignProng2, int16_t); +DECLARE_SOA_COLUMN(LcNSigTPCPi0, lcNSigTPCPi0, float); +DECLARE_SOA_COLUMN(LcNSigTPCK0, lcNSigTPCK0, float); +DECLARE_SOA_COLUMN(LcNSigTPCPr0, lcNSigTPCPr0, float); +DECLARE_SOA_COLUMN(LcNSigTPCPi1, lcNSigTPCPi1, float); +DECLARE_SOA_COLUMN(LcNSigTPCK1, lcNSigTPCK1, float); +DECLARE_SOA_COLUMN(LcNSigTPCPr1, lcNSigTPCPr1, float); +DECLARE_SOA_COLUMN(LcNSigTPCPi2, lcNSigTPCPi2, float); +DECLARE_SOA_COLUMN(LcNSigTPCK2, lcNSigTPCK2, float); +DECLARE_SOA_COLUMN(LcNSigTPCPr2, lcNSigTPCPr2, float); +DECLARE_SOA_COLUMN(LcNSigTOFPr0, lcNSigTOFPr0, float); +DECLARE_SOA_COLUMN(LcNSigTOFK1, lcNSigTOFK1, float); +DECLARE_SOA_COLUMN(LcNSigTOFPi2, lcNSigTOFPi2, float); } // namespace full // put the arguments into the table DECLARE_SOA_TABLE(HfCandLbFulls, "AOD", "HFCANDLBFULL", + collision::PosX, collision::PosY, collision::PosZ, + hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ZSecondaryVertex, + hf_cand::ErrorDecayLength, hf_cand::ErrorDecayLengthXY, + hf_cand::Chi2PCA, + full::ImpactParameterXY, full::RSecondaryVertex, full::DecayLength, full::DecayLengthXY, full::DecayLengthNormalised, full::DecayLengthXYNormalised, - hf_cand::Chi2PCA, full::ImpactParameterNormalised0, full::PtProng0, full::PProng0, full::ImpactParameterNormalised1, full::PtProng1, full::PProng1, + full::SignTrk0, + full::NSigTOFTrk0Pi, + full::NSigTPCTrk0Pi, hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, @@ -116,29 +137,20 @@ DECLARE_SOA_TABLE(HfCandLbFulls, "AOD", "HFCANDLBFULL", hf_cand::ImpactParameter1, hf_cand::ErrorImpactParameter0, hf_cand::ErrorImpactParameter1, - full::NSigTOFTrk0Pi, - full::NSigRICHTrk0Pi, - full::NSigRICHTrk1Pi, - full::NSigRICHTrk1Pr, - full::NSigRICHTrk2Ka, - full::NSigRICHTrk3Pi, - full::NSigRICHTrk3Pr, - full::NSigfRICHTrk0Pi, - full::NSigfRICHTrk1Pi, - full::NSigfRICHTrk1Pr, - full::NSigfRICHTrk2Ka, - full::NSigfRICHTrk3Pi, - full::NSigfRICHTrk3Pr, - full::NSigTOFTrk1Pi, - full::NSigTOFTrk1Pr, - full::NSigTOFTrk2Ka, - full::NSigTOFTrk3Pi, - full::NSigTOFTrk3Pr, + full::LcNSigTPCPi0, full::LcNSigTPCK0, full::LcNSigTPCPr0, + full::LcNSigTPCPi1, full::LcNSigTPCK1, full::LcNSigTPCPr1, + full::LcNSigTPCPi2, full::LcNSigTPCK2, full::LcNSigTPCPr2, + full::LcNSigTOFPr0, + full::LcNSigTOFK1, + full::LcNSigTOFPi2, full::LcM, full::LcCt, full::LcY, full::LcE, full::LcEta, + full::LcVertexX, + full::LcVertexY, + full::LcVertexZ, full::LcCPA, full::LcCPAXY, full::LcChi2PCA, @@ -146,8 +158,17 @@ DECLARE_SOA_TABLE(HfCandLbFulls, "AOD", "HFCANDLBFULL", full::LcDecayLengthXY, full::LcDecayLengthNormalised, full::LcImpactParameter0, + full::LcImpactParameterError0, full::LcImpactParameter1, + full::LcImpactParameterError1, full::LcImpactParameter2, + full::LcImpactParameterError2, + full::LcPx0, full::LcPy0, full::LcPz0, + full::LcPx1, full::LcPy1, full::LcPz1, + full::LcPx2, full::LcPy2, full::LcPz2, + full::LcSignProng0, + full::LcSignProng1, + full::LcSignProng2, full::CandidateSelFlag, full::M, full::Pt, @@ -158,47 +179,22 @@ DECLARE_SOA_TABLE(HfCandLbFulls, "AOD", "HFCANDLBFULL", full::Eta, full::Phi, full::Y, - full::MCflag, + full::McFlag, full::OriginMcRec); } // namespace o2::aod -namespace o2::aod -{ -namespace hf_track_index_alice3_pid -{ -DECLARE_SOA_INDEX_COLUMN(Track, track); //! -DECLARE_SOA_INDEX_COLUMN(RICH, rich); //! -DECLARE_SOA_INDEX_COLUMN(FRICH, frich); //! -} // namespace hf_track_index_alice3_pid - -DECLARE_SOA_INDEX_TABLE_USER(HfTrackIndexALICE3PID, Tracks, "HFTRKIDXA3PID", //! - hf_track_index_alice3_pid::TrackId, - hf_track_index_alice3_pid::RICHId, - hf_track_index_alice3_pid::FRICHId); -} // namespace o2::aod - -struct HfTreeCreatorLbToLcPiAlice3PidIndexBuilder { - Builds index; - - void init(InitContext&) {} -}; - /// Writes the full information in an output TTree struct HfTreeCreatorLbToLcPi { Produces rowCandidateFull; - HfHelper hfHelper; - using TracksWPid = soa::Join; + using TracksWPid = soa::Join; - void process(soa::Join const& candidates, - soa::Join const&, - TracksWPid const&, - aod::FRICHs const&, - aod::RICHs const&) + void process(soa::Join const& candidates, + soa::Join const&, + TracksWPid const&) { - // Filling candidate properties rowCandidateFull.reserve(candidates.size()); for (const auto& candidate : candidates) { @@ -206,121 +202,97 @@ struct HfTreeCreatorLbToLcPi { float FunctionInvMass, float FunctionCt, float FunctionY) { - if (FunctionSelection >= 1) { - auto candLc = candidate.prong0_as>(); - auto track0 = candidate.prong1_as(); // daughter pion track - auto track1 = candLc.prong0_as(); // granddaughter tracks (lc decay particles) - auto track2 = candLc.prong1_as(); - auto track3 = candLc.prong2_as(); - - auto RICHTrk0Pi = -5000.0; - auto RICHTrk1Pi = -5000.0; - auto RICHTrk1P = -5000.0; - auto RICHTrk2K = -5000.0; - auto RICHTrk3Pi = -5000.0; - auto RICHTrk3P = -5000.0; - - auto fRICHTrk0Pi = -5000.0; - auto fRICHTrk1Pi = -5000.0; - auto fRICHTrk1P = -5000.0; - auto fRICHTrk2K = -5000.0; - auto fRICHTrk3Pi = -5000.0; - auto fRICHTrk3P = -5000.0; - - if (track0.has_rich()) - RICHTrk0Pi = track0.rich().richNsigmaPi(); - if (track1.has_rich()) { - RICHTrk1Pi = track1.rich().richNsigmaPi(); - RICHTrk1P = track1.rich().richNsigmaPr(); - } - if (track2.has_rich()) - RICHTrk2K = track2.rich().richNsigmaKa(); - if (track3.has_rich()) { - RICHTrk3Pi = track3.rich().richNsigmaPi(); - RICHTrk3P = track3.rich().richNsigmaPr(); - } + auto candLc = candidate.prong0_as>(); + auto track0 = candidate.prong1_as(); // daughter pion track + auto track1 = candLc.prong0_as(); // granddaughter tracks (lc decay particles) + auto track2 = candLc.prong1_as(); + auto track3 = candLc.prong2_as(); - if (track0.has_frich()) - fRICHTrk0Pi = track0.frich().frichNsigmaPi(); - if (track1.has_frich()) { - fRICHTrk1Pi = track1.frich().frichNsigmaPi(); - fRICHTrk1P = track1.frich().frichNsigmaPr(); - } - if (track2.has_frich()) - fRICHTrk2K = track2.frich().frichNsigmaKa(); - if (track3.has_frich()) { - fRICHTrk3Pi = track3.frich().frichNsigmaPi(); - fRICHTrk3P = track3.frich().frichNsigmaPr(); - } + auto tempConst = -1; // For data - rowCandidateFull( - candidate.rSecondaryVertex(), - candidate.decayLength(), - candidate.decayLengthXY(), - candidate.decayLengthNormalised(), - candidate.decayLengthXYNormalised(), - candidate.chi2PCA(), - candidate.impactParameterNormalised0(), - candidate.ptProng0(), - RecoDecay::p(candidate.pxProng0(), candidate.pyProng0(), candidate.pzProng0()), - candidate.impactParameterNormalised1(), - candidate.ptProng1(), - RecoDecay::p(candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1()), - candidate.pxProng0(), - candidate.pyProng0(), - candidate.pzProng0(), - candidate.pxProng1(), - candidate.pyProng1(), - candidate.pzProng1(), - candidate.impactParameter0(), - candidate.impactParameter1(), - candidate.errorImpactParameter0(), - candidate.errorImpactParameter1(), - track0.tofNSigmaPi(), - RICHTrk0Pi, - RICHTrk1Pi, - RICHTrk1P, - RICHTrk2K, - RICHTrk3Pi, - RICHTrk3P, - fRICHTrk0Pi, - fRICHTrk1Pi, - fRICHTrk1P, - fRICHTrk2K, - fRICHTrk3Pi, - fRICHTrk3P, - track1.tofNSigmaPi(), - track1.tofNSigmaPr(), - track2.tofNSigmaKa(), - track3.tofNSigmaPi(), - track3.tofNSigmaPr(), - hfHelper.invMassLcToPKPi(candLc), - hfHelper.ctLc(candLc), - hfHelper.yLc(candLc), - hfHelper.eLc(candLc), - candLc.eta(), - candLc.cpa(), - candLc.cpaXY(), - candLc.chi2PCA(), - candLc.decayLength(), - candLc.decayLengthXY(), - candLc.decayLengthXYNormalised(), - candLc.impactParameter0(), - candLc.impactParameter1(), - candLc.impactParameter2(), - FunctionSelection, - FunctionInvMass, - candidate.pt(), - candidate.p(), - candidate.cpa(), - candidate.cpaXY(), - FunctionCt, - candidate.eta(), - candidate.phi(), - FunctionY, - candidate.flagMcMatchRec(), - candidate.originMcRec()); - } + rowCandidateFull( + candidate.posX(), + candidate.posY(), + candidate.posZ(), + candidate.xSecondaryVertex(), + candidate.ySecondaryVertex(), + candidate.zSecondaryVertex(), + candidate.errorDecayLength(), + candidate.errorDecayLengthXY(), + candidate.chi2PCA(), + candidate.impactParameterXY(), + candidate.rSecondaryVertex(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.decayLengthNormalised(), + candidate.decayLengthXYNormalised(), + candidate.impactParameterNormalised0(), + candidate.ptProng0(), + RecoDecay::p(candidate.pxProng0(), candidate.pyProng0(), candidate.pzProng0()), + candidate.impactParameterNormalised1(), + candidate.ptProng1(), + RecoDecay::p(candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1()), + track0.sign(), + track0.tofNSigmaPi(), + track0.tpcNSigmaPi(), + candidate.pxProng0(), + candidate.pyProng0(), + candidate.pzProng0(), + candidate.pxProng1(), + candidate.pyProng1(), + candidate.pzProng1(), + candidate.impactParameter0(), + candidate.impactParameter1(), + candidate.errorImpactParameter0(), + candidate.errorImpactParameter1(), + track1.tpcNSigmaPi(), + track1.tpcNSigmaKa(), + track1.tpcNSigmaPr(), + track2.tpcNSigmaPi(), + track2.tpcNSigmaKa(), + track2.tpcNSigmaPr(), + track3.tpcNSigmaPi(), + track3.tpcNSigmaKa(), + track3.tpcNSigmaPr(), + track1.tofNSigmaPr(), + track2.tofNSigmaKa(), + track3.tofNSigmaPi(), + hfHelper.invMassLcToPKPi(candLc), + hfHelper.ctLc(candLc), + hfHelper.yLc(candLc), + hfHelper.eLc(candLc), + candLc.eta(), + candLc.xSecondaryVertex(), + candLc.ySecondaryVertex(), + candLc.zSecondaryVertex(), + candLc.cpa(), + candLc.cpaXY(), + candLc.chi2PCA(), + candLc.decayLength(), + candLc.decayLengthXY(), + candLc.decayLengthXYNormalised(), + candLc.impactParameter0(), + candLc.errorImpactParameter0(), + candLc.impactParameter1(), + candLc.errorImpactParameter1(), + candLc.impactParameter2(), + candLc.errorImpactParameter2(), + track1.px(), track1.py(), track1.pz(), + track2.px(), track2.py(), track2.pz(), + track3.px(), track3.py(), track3.pz(), + track1.sign(), track2.sign(), track3.sign(), + FunctionSelection, + FunctionInvMass, + candidate.pt(), + candidate.p(), + candidate.cpa(), + candidate.cpaXY(), + FunctionCt, + candidate.eta(), + candidate.phi(), + FunctionY, + tempConst, + tempConst); }; fillTable(candidate.isSelLbToLcPi(), hfHelper.invMassLbToLcPi(candidate), hfHelper.ctLb(candidate), hfHelper.yLb(candidate)); } @@ -330,7 +302,6 @@ struct HfTreeCreatorLbToLcPi { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow; - workflow.push_back(adaptAnalysisTask(cfgc)); workflow.push_back(adaptAnalysisTask(cfgc)); return workflow; } diff --git a/PWGHF/TableProducer/treeCreatorLcToK0sP.cxx b/PWGHF/TableProducer/treeCreatorLcToK0sP.cxx index 4dfde61847f..35e15a7cb9f 100644 --- a/PWGHF/TableProducer/treeCreatorLcToK0sP.cxx +++ b/PWGHF/TableProducer/treeCreatorLcToK0sP.cxx @@ -27,6 +27,8 @@ using namespace o2; using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; namespace o2::aod { @@ -213,10 +215,17 @@ struct HfTreeCreatorLcToK0sP { Configurable fillCandidateLiteTable{"fillCandidateLiteTable", false, "Switch to fill lite table with candidate properties"}; Configurable downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of candidates to store in the tree"}; Configurable ptMaxForDownSample{"ptMaxForDownSample", 24., "Maximum pt for the application of the downsampling factor"}; + Configurable fillOnlySignal{"fillOnlySignal", false, "Flag to fill derived tables with signal for ML trainings"}; + Configurable fillOnlyBackground{"fillOnlyBackground", false, "Flag to fill derived tables with background for ML trainings"}; HfHelper hfHelper; + Filter filterSelectCandidates = aod::hf_sel_candidate_lc_to_k0s_p::isSelLcToK0sP >= 1; using TracksWPid = soa::Join; + using SelectedCandidatesMc = soa::Filtered>; + + Partition recSig = nabs(aod::hf_cand_casc::flagMcMatchRec) != int8_t(0); + Partition recBkg = nabs(aod::hf_cand_casc::flagMcMatchRec) == int8_t(0); void init(InitContext const&) { @@ -298,9 +307,9 @@ struct HfTreeCreatorLcToK0sP { candidate.impactParameter1(), candidate.errorImpactParameter0(), candidate.errorImpactParameter1(), - candidate.v0x(), - candidate.v0y(), - candidate.v0z(), + candidate.v0X(), + candidate.v0Y(), + candidate.v0Z(), candidate.v0radius(), candidate.v0cosPA(), candidate.mLambda(), @@ -349,7 +358,7 @@ struct HfTreeCreatorLcToK0sP { void processMc(aod::Collisions const& collisions, aod::McCollisions const&, - soa::Join const& candidates, + SelectedCandidatesMc const& candidates, soa::Join const& particles, TracksWPid const&) { @@ -360,21 +369,41 @@ struct HfTreeCreatorLcToK0sP { fillEvent(collision); } - // Filling candidate properties - if (fillCandidateLiteTable) { - rowCandidateLite.reserve(candidates.size()); - } else { - rowCandidateFull.reserve(candidates.size()); - } - for (const auto& candidate : candidates) { - auto bach = candidate.prong0_as(); // bachelor - if (downSampleBkgFactor < 1.) { - double pseudoRndm = bach.pt() * 1000. - (int16_t)(bach.pt() * 1000); - if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { - continue; + if (fillOnlySignal) { + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(recSig.size()); + } else { + rowCandidateFull.reserve(recSig.size()); + } + for (const auto& candidate : recSig) { + auto bach = candidate.prong0_as(); // bachelor + fillCandidate(candidate, bach, candidate.flagMcMatchRec(), candidate.originMcRec()); + } + } else if (fillOnlyBackground) { + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(recBkg.size()); + } else { + rowCandidateFull.reserve(recBkg.size()); + } + for (const auto& candidate : recBkg) { + if (downSampleBkgFactor < 1.) { + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } } + auto bach = candidate.prong0_as(); // bachelor + fillCandidate(candidate, bach, candidate.flagMcMatchRec(), candidate.originMcRec()); + } + } else { + // Filling candidate properties + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(candidates.size()); + } else { + rowCandidateFull.reserve(candidates.size()); } - if (candidate.isSelLcToK0sP() >= 1) { + for (const auto& candidate : candidates) { + auto bach = candidate.prong0_as(); // bachelor fillCandidate(candidate, bach, candidate.flagMcMatchRec(), candidate.originMcRec()); } } @@ -416,7 +445,7 @@ struct HfTreeCreatorLcToK0sP { } for (const auto& candidate : candidates) { auto bach = candidate.prong0_as(); // bachelor - double pseudoRndm = bach.pt() * 1000. - (int16_t)(bach.pt() * 1000); + double pseudoRndm = bach.pt() * 1000. - static_cast(bach.pt() * 1000); if (candidate.isSelLcToK0sP() >= 1 && pseudoRndm < downSampleBkgFactor) { fillCandidate(candidate, bach, 0, 0); } diff --git a/PWGHF/TableProducer/treeCreatorLcToPKPi.cxx b/PWGHF/TableProducer/treeCreatorLcToPKPi.cxx index 13bf5a0bb52..5b2c5225ba0 100644 --- a/PWGHF/TableProducer/treeCreatorLcToPKPi.cxx +++ b/PWGHF/TableProducer/treeCreatorLcToPKPi.cxx @@ -30,6 +30,7 @@ using namespace o2; using namespace o2::framework; +using namespace o2::constants::physics; namespace o2::aod { @@ -48,6 +49,7 @@ DECLARE_SOA_COLUMN(PProng2, pProng2, float); DECLARE_SOA_COLUMN(ImpactParameterNormalised2, impactParameterNormalised2, float); DECLARE_SOA_COLUMN(CandidateSelFlag, candidateSelFlag, int8_t); DECLARE_SOA_COLUMN(M, m, float); +DECLARE_SOA_COLUMN(MassKPi, massKPi, float); // invariant mass of the candidate Kpi daughters DECLARE_SOA_COLUMN(Pt, pt, float); DECLARE_SOA_COLUMN(P, p, float); DECLARE_SOA_COLUMN(Eta, eta, float); @@ -64,11 +66,11 @@ DECLARE_SOA_COLUMN(NSigTpcPi2, nSigTpcPi2, float); DECLARE_SOA_COLUMN(NSigTpcPr2, nSigTpcPr2, float); DECLARE_SOA_COLUMN(NSigTofPi2, nSigTofPi2, float); DECLARE_SOA_COLUMN(NSigTofPr2, nSigTofPr2, float); -DECLARE_SOA_COLUMN(NSigTpcTofPr0, nSigTpcTofPi0, float); -DECLARE_SOA_COLUMN(NSigTpcTofPi0, nSigTpcTofPr0, float); +DECLARE_SOA_COLUMN(NSigTpcTofPr0, nSigTpcTofPr0, float); +DECLARE_SOA_COLUMN(NSigTpcTofPi0, nSigTpcTofPi0, float); DECLARE_SOA_COLUMN(NSigTpcTofKa1, nSigTpcTofKa1, float); -DECLARE_SOA_COLUMN(NSigTpcTofPr2, nSigTpcTofPi2, float); -DECLARE_SOA_COLUMN(NSigTpcTofPi2, nSigTpcTofPr2, float); +DECLARE_SOA_COLUMN(NSigTpcTofPr2, nSigTpcTofPr2, float); +DECLARE_SOA_COLUMN(NSigTpcTofPi2, nSigTpcTofPi2, float); DECLARE_SOA_COLUMN(DecayLength, decayLength, float); DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); @@ -82,6 +84,7 @@ DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); DECLARE_SOA_COLUMN(IsCandidateSwapped, isCandidateSwapped, int8_t); DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfCand3Prong, "_0"); DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); +DECLARE_SOA_COLUMN(Channel, channel, int8_t); // direct or resonant // Events DECLARE_SOA_INDEX_COLUMN(McCollision, mcCollision); DECLARE_SOA_COLUMN(IsEventReject, isEventReject, int); @@ -94,30 +97,87 @@ DECLARE_SOA_COLUMN(CentFDDM, centFDDM, float); DECLARE_SOA_COLUMN(MultZeqNTracksPV, multZeqNTracksPV, float); } // namespace full +namespace kf +{ +DECLARE_SOA_COLUMN(X, x, float); //! decay vertex X coordinate +DECLARE_SOA_COLUMN(Y, y, float); //! decay vertex Y coordinate +DECLARE_SOA_COLUMN(Z, z, float); //! decay vertex Z coordinate +DECLARE_SOA_COLUMN(ErrX, errX, float); //! decay vertex X coordinate error +DECLARE_SOA_COLUMN(ErrY, errY, float); //! decay vertex Y coordinate error +DECLARE_SOA_COLUMN(ErrZ, errZ, float); //! decay vertex Z coordinate error +DECLARE_SOA_COLUMN(ErrPVX, errPVX, float); //! event vertex X coordinate error +DECLARE_SOA_COLUMN(ErrPVY, errPVY, float); //! event vertex Y coordinate error +DECLARE_SOA_COLUMN(ErrPVZ, errPVZ, float); //! event vertex Z coordinate error +DECLARE_SOA_COLUMN(Chi2PrimProton, chi2PrimProton, float); //! Chi2 of prong's approach to the PV +DECLARE_SOA_COLUMN(Chi2PrimKaon, chi2PrimKaon, float); //! Chi2 of prong's approach to the PV +DECLARE_SOA_COLUMN(Chi2PrimPion, chi2PrimPion, float); //! Chi2 of prong's approach to the PV +DECLARE_SOA_COLUMN(DcaProtonKaon, dcaProtonKaon, float); //! Distance of closest approach between 2 prongs, cm +DECLARE_SOA_COLUMN(DcaProtonPion, dcaProtonPion, float); //! Distance of closest approach between 2 prongs, cm +DECLARE_SOA_COLUMN(DcaPionKaon, dcaPionKaon, float); //! Distance of closest approach between 2 prongs, cm +DECLARE_SOA_COLUMN(Chi2GeoProtonKaon, chi2GeoProtonKaon, float); //! Chi2 of two prongs' approach to each other +DECLARE_SOA_COLUMN(Chi2GeoProtonPion, chi2GeoProtonPion, float); //! Chi2 of two prongs' approach to each other +DECLARE_SOA_COLUMN(Chi2GeoPionKaon, chi2GeoPionKaon, float); //! Chi2 of two prongs' approach to each other +DECLARE_SOA_COLUMN(Chi2Geo, chi2Geo, float); //! chi2 geo of the full candidate +DECLARE_SOA_COLUMN(Chi2Topo, chi2Topo, float); //! chi2 topo of the full candidate (chi2prim of candidate to PV) +DECLARE_SOA_COLUMN(DecayLength, decayLength, float); //! decay length, cm +DECLARE_SOA_COLUMN(DecayLengthError, decayLengthError, float); //! decay length error +DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); //! decay length over its error +DECLARE_SOA_COLUMN(T, t, float); //! proper lifetime, ps +DECLARE_SOA_COLUMN(ErrT, errT, float); //! lifetime error +DECLARE_SOA_COLUMN(MassInv, massInv, float); //! invariant mass +DECLARE_SOA_COLUMN(P, p, float); //! momentum +DECLARE_SOA_COLUMN(Pt, pt, float); //! transverse momentum +DECLARE_SOA_COLUMN(ErrP, errP, float); //! momentum error +DECLARE_SOA_COLUMN(ErrPt, errPt, float); //! transverse momentum error +DECLARE_SOA_COLUMN(IsSelected, isSelected, int); //! flag whether candidate was selected in candidateSelectorLc task +DECLARE_SOA_COLUMN(SigBgStatus, sigBgStatus, int); //! 0 bg, 1 prompt, 2 non-prompt, 3 wrong order of prongs, -1 default value (impossible, should not be the case), -999 for data +} // namespace kf + +namespace mc_match +{ +DECLARE_SOA_COLUMN(P, p, float); //! Momentum, GeV/c +DECLARE_SOA_COLUMN(Pt, pt, float); //! Transverse momentum, GeV/c +DECLARE_SOA_COLUMN(XDecay, xDecay, float); //! Secondary (decay) vertex X coordinate, cm +DECLARE_SOA_COLUMN(YDecay, yDecay, float); //! Secondary (decay) vertex Y coordinate, cm +DECLARE_SOA_COLUMN(ZDecay, zDecay, float); //! Secondary (decay) vertex Z coordinate, cm +DECLARE_SOA_COLUMN(LDecay, lDecay, float); //! Decay length, cm (distance between PV and SV, curvature is neglected) +DECLARE_SOA_COLUMN(TDecay, tDecay, float); //! Proper lifetime, ps +DECLARE_SOA_COLUMN(XEvent, xEvent, float); //! Primary (event) vertex X coordinate, cm +DECLARE_SOA_COLUMN(YEvent, yEvent, float); //! Primary (event) vertex Y coordinate, cm +DECLARE_SOA_COLUMN(ZEvent, zEvent, float); //! Primary (event) vertex Z coordinate, cm +} // namespace mc_match + +DECLARE_SOA_TABLE(HfCandLcMCs, "AOD", "HFCANDLCMC", + mc_match::P, mc_match::Pt, + mc_match::XDecay, mc_match::YDecay, mc_match::ZDecay, mc_match::LDecay, + mc_match::TDecay, + mc_match::XEvent, mc_match::YEvent, mc_match::ZEvent) + +DECLARE_SOA_TABLE(HfCandLcKFs, "AOD", "HFCANDLCKF", + kf::X, kf::Y, kf::Z, kf::ErrX, kf::ErrY, kf::ErrZ, + kf::ErrPVX, kf::ErrPVY, kf::ErrPVZ, + kf::Chi2PrimProton, kf::Chi2PrimKaon, kf::Chi2PrimPion, + kf::DcaProtonKaon, kf::DcaProtonPion, kf::DcaPionKaon, + kf::Chi2GeoProtonKaon, kf::Chi2GeoProtonPion, kf::Chi2GeoPionKaon, + kf::Chi2Geo, kf::Chi2Topo, kf::DecayLength, kf::DecayLengthError, kf::DecayLengthNormalised, kf::T, kf::ErrT, + kf::MassInv, kf::P, kf::Pt, kf::ErrP, kf::ErrPt, + kf::IsSelected, kf::SigBgStatus); + DECLARE_SOA_TABLE(HfCandLcLites, "AOD", "HFCANDLCLITE", collision::PosX, collision::PosY, collision::PosZ, hf_cand::NProngsContributorsPV, - // hf_cand::ErrorDecayLength, - // hf_cand::ErrorDecayLengthXY, + hf_cand::BitmapProngsContributorsPV, hf_cand::Chi2PCA, full::DecayLength, full::DecayLengthXY, - // full::DecayLengthNormalised, - // full::DecayLengthXYNormalised, - // full::ImpactParameterNormalised0, full::PtProng0, - // full::ImpactParameterNormalised1, full::PtProng1, - // full::ImpactParameterNormalised2, full::PtProng2, hf_cand::ImpactParameter0, hf_cand::ImpactParameter1, hf_cand::ImpactParameter2, - // hf_cand::ErrorImpactParameter0, - // hf_cand::ErrorImpactParameter1, - // hf_cand::ErrorImpactParameter2, full::NSigTpcPi0, full::NSigTpcPr0, full::NSigTofPi0, @@ -144,7 +204,9 @@ DECLARE_SOA_TABLE(HfCandLcLites, "AOD", "HFCANDLCLITE", full::Y, full::FlagMc, full::OriginMcRec, - full::IsCandidateSwapped); + full::IsCandidateSwapped, + full::Channel, + full::MassKPi); DECLARE_SOA_TABLE(HfCollIdLCLite, "AOD", "HFCOLLIDLCLITE", full::CollisionId); @@ -155,6 +217,7 @@ DECLARE_SOA_TABLE(HfCandLcFulls, "AOD", "HFCANDLCFULL", collision::PosY, collision::PosZ, hf_cand::NProngsContributorsPV, + hf_cand::BitmapProngsContributorsPV, hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ZSecondaryVertex, @@ -219,7 +282,9 @@ DECLARE_SOA_TABLE(HfCandLcFulls, "AOD", "HFCANDLCFULL", full::FlagMc, full::OriginMcRec, full::IsCandidateSwapped, - full::CandidateId); + full::CandidateId, + full::Channel, + full::MassKPi); DECLARE_SOA_TABLE(HfCandLcFullEvs, "AOD", "HFCANDLCFULLEV", full::CollisionId, @@ -238,14 +303,12 @@ DECLARE_SOA_TABLE(HfCandLcFullEvs, "AOD", "HFCANDLCFULLEV", full::MultZeqNTracksPV); DECLARE_SOA_TABLE(HfCandLcFullPs, "AOD", "HFCANDLCFULLP", - full::McCollisionId, full::Pt, full::Eta, full::Phi, full::Y, full::FlagMc, - full::OriginMcGen, - full::McParticleId); + full::OriginMcGen); } // namespace o2::aod @@ -253,36 +316,121 @@ DECLARE_SOA_TABLE(HfCandLcFullPs, "AOD", "HFCANDLCFULLP", struct HfTreeCreatorLcToPKPi { Produces rowCandidateFull; Produces rowCandidateLite; + Produces rowCandidateKF; + Produces rowCandidateMC; Produces rowCollisionId; Produces rowCandidateFullEvents; Produces rowCandidateFullParticles; + Configurable selectionFlagLc{"selectionFlagLc", 1, "Selection Flag for Lc"}; Configurable fillCandidateLiteTable{"fillCandidateLiteTable", false, "Switch to fill lite table with candidate properties"}; Configurable fillCollIdTable{"fillCollIdTable", false, "Fill a single-column table with collision index"}; + Configurable fillCandidateMcTable{"fillCandidateMcTable", false, "Switch to fill a table with MC particles matched to candidates"}; Configurable keepOnlySignalMc{"keepOnlySignalMc", false, "Fill MC tree only with signal candidates"}; Configurable keepOnlyBkg{"keepOnlyBkg", false, "Fill MC tree only with background candidates"}; Configurable downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of candidates to store in the tree"}; Configurable downSampleBkgPtMax{"downSampleBkgPtMax", 100.f, "Max. pt for background downsampling"}; + constexpr static float UndefValueFloat = -999.f; + constexpr static int UndefValueInt = -999; + constexpr static float NanoToPico = 1000.f; + HfHelper hfHelper; using TracksWPid = soa::Join; using Cents = soa::Join; + // number showing MC status of the candidate (signal or background, prompt or non-prompt etc.) + enum SigBgStatus : int { + Background = 0, // combinatorial background, at least one of the prongs do not originate from the Lc decay + Prompt, // signal with Lc produced directly in the event + NonPrompt, // signal with Lc produced aftewards the event, e.g. during decay of beauty particle + WrongOrder, // all the prongs are from Lc decay, but proton and pion hypothesis are swapped + Default = -1 // impossible, should not be the case, to catch logical error if any + }; + + /// \brief function which determines if the candidate corresponds to MC-particle or belongs to a combinatorial background + /// \param candidate candidate to be checked for being signal or background + /// \param CandFlag 0 for PKPi hypothesis and 1 for PiKP hypothesis + /// \return SigBgStatus enum with value encoding MC status of the candidate + template + SigBgStatus determineSignalBgStatus(const CandType& candidate, int CandFlag) + { + const int flag = candidate.flagMcMatchRec(); + const int origin = candidate.originMcRec(); + const int swapped = candidate.isCandidateSwapped(); + + SigBgStatus status{Default}; + + if (std::abs(flag) == (1 << o2::aod::hf_cand_3prong::DecayType::LcToPKPi)) { + if (swapped == 0) { + if (CandFlag == 0) { + if (origin == RecoDecay::OriginType::Prompt) + status = Prompt; + else if (origin == RecoDecay::OriginType::NonPrompt) + status = NonPrompt; + } else { + status = WrongOrder; + } + } else { + if (CandFlag == 1) { + if (origin == RecoDecay::OriginType::Prompt) + status = Prompt; + else if (origin == RecoDecay::OriginType::NonPrompt) + status = NonPrompt; + } else { + status = WrongOrder; + } + } + } else { + status = Background; + } + + return status; + } + void init(InitContext const&) { + std::array processes = {doprocessDataNoCentralityWithDCAFitterN, doprocessDataWithCentralityWithDCAFitterN, doprocessDataNoCentralityWithKFParticle, doprocessDataWithCentralityWithKFParticle, + doprocessMcNoCentralityWithDCAFitterN, doprocessMcWithCentralityWithDCAFitterN, doprocessMcNoCentralityWithKFParticle, doprocessMcWithCentralityWithKFParticle}; + if (std::accumulate(processes.begin(), processes.end(), 0) != 1) { + LOGP(fatal, "One and only one process function must be enabled at a time."); + } + if (std::accumulate(processes.begin(), processes.begin() + 4, 0) && fillCandidateMcTable) { + LOGP(fatal, "fillCandidateMcTable can be activated only in case of MC processing."); + } } - void processMc(soa::Join const& collisions, - aod::McCollisions const&, - soa::Join const& candidates, - soa::Join const& particles, - TracksWPid const&, aod::BCs const&) + /// \brief core function to fill tables in MC + /// \param collisions Collision table + /// \param mcCollisions MC collision table + /// \param candidates Lc->pKpi candidate table + /// \param particles Generated particle table + template + void fillTablesMc(Colls const& collisions, + aod::McCollisions const&, + CandType const& candidates, + soa::Join const& particles, + soa::Join const&, aod::BCs const&) { // Filling event properties rowCandidateFullEvents.reserve(collisions.size()); for (const auto& collision : collisions) { + + float centFT0A = -1.f; + float centFT0C = -1.f; + float centFT0M = -1.f; + float centFV0A = -1.f; + float centFDDM = -1.f; + if constexpr (useCentrality) { + centFT0A = collision.centFT0A(); + centFT0C = collision.centFT0C(); + centFT0M = collision.centFT0M(); + centFV0A = collision.centFV0A(); + centFDDM = collision.centFDDM(); + } + rowCandidateFullEvents( collision.globalIndex(), collision.mcCollisionId(), @@ -292,62 +440,68 @@ struct HfTreeCreatorLcToPKPi { collision.posZ(), 0, collision.bc().runNumber(), - collision.centFT0A(), - collision.centFT0C(), - collision.centFT0M(), - collision.centFV0A(), - collision.centFDDM(), + centFT0A, + centFT0C, + centFT0M, + centFV0A, + centFDDM, collision.multZeqNTracksPV()); } // Filling candidate properties - if (fillCandidateLiteTable) { - rowCandidateLite.reserve(candidates.size()); + if constexpr (reconstructionType == aod::hf_cand::VertexerType::DCAFitter) { + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(candidates.size() * 2); + } else { + rowCandidateFull.reserve(candidates.size() * 2); + } } else { - rowCandidateFull.reserve(candidates.size()); + rowCandidateKF.reserve(candidates.size() * 2); } if (fillCollIdTable) { /// save also candidate collision indices rowCollisionId.reserve(candidates.size()); } + if (fillCandidateMcTable) { + rowCandidateMC.reserve(candidates.size() * 2); + } for (const auto& candidate : candidates) { - auto trackPos1 = candidate.prong0_as(); // positive daughter (negative for the antiparticles) - auto trackNeg = candidate.prong1_as(); // negative daughter (positive for the antiparticles) - auto trackPos2 = candidate.prong2_as(); // positive daughter (negative for the antiparticles) - bool isMcCandidateSignal = std::abs(candidate.flagMcMatchRec()) == (1 << o2::aod::hf_cand_3prong::DecayType::LcToPKPi); - auto fillTable = [&](int CandFlag, - int FunctionSelection, - float FunctionInvMass, - float FunctionCt, - float FunctionY, - float FunctionE) { - double pseudoRndm = trackPos1.pt() * 1000. - (int64_t)(trackPos1.pt() * 1000); - if (FunctionSelection >= 1 && (/*keep all*/ (!keepOnlySignalMc && !keepOnlyBkg) || /*keep only signal*/ (keepOnlySignalMc && isMcCandidateSignal) || /*keep only background and downsample it*/ (keepOnlyBkg && !isMcCandidateSignal && (candidate.pt() > downSampleBkgPtMax || (pseudoRndm < downSampleBkgFactor && candidate.pt() < downSampleBkgPtMax))))) { + auto trackPos1 = candidate.template prong0_as>(); // positive daughter (negative for the antiparticles) + auto trackNeg = candidate.template prong1_as>(); // negative daughter (positive for the antiparticles) + auto trackPos2 = candidate.template prong2_as>(); // positive daughter (negative for the antiparticles) + auto fillTable = [&](int CandFlag) { + double pseudoRndm = trackPos1.pt() * 1000. - static_cast(trackPos1.pt() * 1000); + const int FunctionSelection = CandFlag == 0 ? candidate.isSelLcToPKPi() : candidate.isSelLcToPiKP(); + const int sigbgstatus = determineSignalBgStatus(candidate, CandFlag); + bool isMcCandidateSignal = (sigbgstatus == Prompt) || (sigbgstatus == NonPrompt); + if (FunctionSelection >= selectionFlagLc && (/*keep all*/ (!keepOnlySignalMc && !keepOnlyBkg) || /*keep only signal*/ (keepOnlySignalMc && isMcCandidateSignal) || /*keep only background and downsample it*/ (keepOnlyBkg && !isMcCandidateSignal && (candidate.pt() > downSampleBkgPtMax || (pseudoRndm < downSampleBkgFactor && candidate.pt() < downSampleBkgPtMax))))) { + float FunctionInvMass, FunctionInvMassKPi; + if constexpr (reconstructionType == aod::hf_cand::VertexerType::DCAFitter) { + FunctionInvMass = CandFlag == 0 ? hfHelper.invMassLcToPKPi(candidate) : hfHelper.invMassLcToPiKP(candidate); + FunctionInvMassKPi = CandFlag == 0 ? hfHelper.invMassKPiPairLcToPKPi(candidate) : hfHelper.invMassKPiPairLcToPiKP(candidate); + } else { + FunctionInvMass = CandFlag == 0 ? candidate.kfMassPKPi() : candidate.kfMassPiKP(); + FunctionInvMassKPi = CandFlag == 0 ? candidate.kfMassKPi() : candidate.kfMassPiK(); + } + const float FunctionCt = hfHelper.ctLc(candidate); + const float FunctionY = hfHelper.yLc(candidate); + const float FunctionE = hfHelper.eLc(candidate); if (fillCandidateLiteTable) { rowCandidateLite( candidate.posX(), candidate.posY(), candidate.posZ(), candidate.nProngsContributorsPV(), - // candidate.errorDecayLength(), - // candidate.errorDecayLengthXY(), + candidate.bitmapProngsContributorsPV(), candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), - // candidate.decayLengthNormalised(), - // candidate.decayLengthXYNormalised(), - // candidate.impactParameterNormalised0(), candidate.ptProng0(), - // candidate.impactParameterNormalised1(), candidate.ptProng1(), - // candidate.impactParameterNormalised2(), candidate.ptProng2(), candidate.impactParameter0(), candidate.impactParameter1(), candidate.impactParameter2(), - // candidate.errorImpactParameter0(), - // candidate.errorImpactParameter1(), - // candidate.errorImpactParameter2(), trackPos1.tpcNSigmaPi(), trackPos1.tpcNSigmaPr(), trackPos1.tofNSigmaPi(), @@ -374,14 +528,14 @@ struct HfTreeCreatorLcToPKPi { FunctionY, candidate.flagMcMatchRec(), candidate.originMcRec(), - candidate.isCandidateSwapped()); - // candidate.globalIndex()); + candidate.isCandidateSwapped(), + candidate.flagMcDecayChanRec(), + FunctionInvMassKPi); if (fillCollIdTable) { /// save also candidate collision indices rowCollisionId(candidate.collisionId()); } - } else { rowCandidateFull( candidate.collisionId(), @@ -389,6 +543,7 @@ struct HfTreeCreatorLcToPKPi { candidate.posY(), candidate.posZ(), candidate.nProngsContributorsPV(), + candidate.bitmapProngsContributorsPV(), candidate.xSecondaryVertex(), candidate.ySecondaryVertex(), candidate.zSecondaryVertex(), @@ -453,13 +608,96 @@ struct HfTreeCreatorLcToPKPi { candidate.flagMcMatchRec(), candidate.originMcRec(), candidate.isCandidateSwapped(), - candidate.globalIndex()); + candidate.globalIndex(), + candidate.flagMcDecayChanRec(), + FunctionInvMassKPi); + } + + if constexpr (reconstructionType == aod::hf_cand::VertexerType::KfParticle) { + const float svX = candidate.xSecondaryVertex(); + const float svY = candidate.ySecondaryVertex(); + const float svZ = candidate.zSecondaryVertex(); + const float svErrX = candidate.kfXError(); + const float svErrY = candidate.kfYError(); + const float svErrZ = candidate.kfZError(); + const float pvErrX = candidate.kfXPVError(); + const float pvErrY = candidate.kfYPVError(); + const float pvErrZ = candidate.kfZPVError(); + const float chi2primProton = CandFlag == 0 ? candidate.kfChi2PrimProng0() : candidate.kfChi2PrimProng2(); + const float chi2primKaon = candidate.kfChi2PrimProng1(); + const float chi2primPion = CandFlag == 0 ? candidate.kfChi2PrimProng2() : candidate.kfChi2PrimProng0(); + const float dcaProtonKaon = CandFlag == 0 ? candidate.kfDcaProng0Prong1() : candidate.kfDcaProng1Prong2(); + const float dcaProtonPion = candidate.kfDcaProng0Prong2(); + const float dcaPionKaon = CandFlag == 0 ? candidate.kfDcaProng1Prong2() : candidate.kfDcaProng0Prong1(); + const float chi2GeoProtonKaon = CandFlag == 0 ? candidate.kfChi2GeoProng0Prong1() : candidate.kfChi2GeoProng1Prong2(); + const float chi2GeoProtonPion = candidate.kfChi2GeoProng0Prong2(); + const float chi2GeoPionKaon = CandFlag == 0 ? candidate.kfChi2GeoProng1Prong2() : candidate.kfChi2GeoProng0Prong1(); + const float chi2Geo = candidate.kfChi2Geo(); + const float chi2Topo = candidate.kfChi2Topo(); + const float l = candidate.kfDecayLength(); + const float dl = candidate.kfDecayLengthError(); + const float pt = std::sqrt(candidate.kfPx() * candidate.kfPx() + candidate.kfPy() * candidate.kfPy()); + const float deltaPt = std::sqrt(candidate.kfPx() * candidate.kfPx() * candidate.kfErrorPx() * candidate.kfErrorPx() + + candidate.kfPy() * candidate.kfPy() * candidate.kfErrorPy() * candidate.kfErrorPy()) / + pt; + const float p = std::sqrt(pt * pt + candidate.kfPz() * candidate.kfPz()); + const float deltaP = std::sqrt(pt * pt * deltaPt * deltaPt + + candidate.kfPz() * candidate.kfPz() * candidate.kfErrorPz() * candidate.kfErrorPz()) / + p; + const float t = l * MassLambdaCPlus / LightSpeedCm2PS / p; + const float deltaT = dl * MassLambdaCPlus / LightSpeedCm2PS / p; + const float mass = CandFlag == 0 ? candidate.kfMassPKPi() : candidate.kfMassPiKP(); + rowCandidateKF( + svX, svY, svZ, svErrX, svErrY, svErrZ, + pvErrX, pvErrY, pvErrZ, + chi2primProton, chi2primKaon, chi2primPion, + dcaProtonKaon, dcaProtonPion, dcaPionKaon, + chi2GeoProtonKaon, chi2GeoProtonPion, chi2GeoPionKaon, + chi2Geo, chi2Topo, l, dl, l / dl, t, deltaT, + mass, p, pt, deltaP, deltaPt, + FunctionSelection, sigbgstatus); + } + if (fillCandidateMcTable) { + float p, pt, svX, svY, svZ, pvX, pvY, pvZ, l, t; + if (!isMcCandidateSignal) { + p = UndefValueFloat; + pt = UndefValueFloat; + svX = UndefValueFloat; + svY = UndefValueFloat; + svZ = UndefValueFloat; + pvX = UndefValueFloat; + pvY = UndefValueFloat; + pvZ = UndefValueFloat; + l = UndefValueFloat; + t = UndefValueFloat; + } else { + auto mcParticleProng0 = candidate.template prong0_as>().template mcParticle_as>(); + auto indexMother = RecoDecay::getMother(particles, mcParticleProng0, o2::constants::physics::Pdg::kLambdaCPlus, true); + auto particleMother = particles.rawIteratorAt(indexMother); + auto mcCollision = particleMother.template mcCollision_as(); + p = particleMother.p(); + pt = particleMother.pt(); + const float p2m = p / MassLambdaCPlus; + const float gamma = std::sqrt(1 + p2m * p2m); // mother's particle Lorentz factor + pvX = mcCollision.posX(); + pvY = mcCollision.posY(); + pvZ = mcCollision.posZ(); + svX = mcParticleProng0.vx(); + svY = mcParticleProng0.vy(); + svZ = mcParticleProng0.vz(); + l = std::sqrt((svX - pvX) * (svX - pvX) + (svY - pvY) * (svY - pvY) + (svZ - pvZ) * (svZ - pvZ)); + t = mcParticleProng0.vt() * NanoToPico / gamma; // from ns to ps * from lab time to proper time + } + rowCandidateMC( + p, pt, + svX, svY, svZ, l, t, + pvX, pvY, pvZ); } } }; - fillTable(0, candidate.isSelLcToPKPi(), hfHelper.invMassLcToPKPi(candidate), hfHelper.ctLc(candidate), hfHelper.yLc(candidate), hfHelper.eLc(candidate)); - fillTable(1, candidate.isSelLcToPiKP(), hfHelper.invMassLcToPiKP(candidate), hfHelper.ctLc(candidate), hfHelper.yLc(candidate), hfHelper.eLc(candidate)); + fillTable(0); + fillTable(1); } // Filling particle properties @@ -467,27 +705,108 @@ struct HfTreeCreatorLcToPKPi { for (const auto& particle : particles) { if (std::abs(particle.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::LcToPKPi) { rowCandidateFullParticles( - particle.mcCollisionId(), particle.pt(), particle.eta(), particle.phi(), RecoDecay::y(particle.pVector(), o2::constants::physics::MassLambdaCPlus), particle.flagMcMatchGen(), - particle.originMcGen(), - particle.globalIndex()); + particle.originMcGen()); } } } - PROCESS_SWITCH(HfTreeCreatorLcToPKPi, processMc, "Process MC tree writer", true); - void processData(soa::Join const& collisions, - soa::Join const& candidates, - TracksWPid const&, aod::BCs const&) + /// \brief process function for MC w/o centrality + /// \param collisions Collision table w/o join of the centrality table + /// \param mcCollisions MC collision table + /// \param candidates Lc->pKpi candidate table + /// \param particles Generated particle table + /// \param tracks Track table + /// \param bcs Bunch-crossing table + void processMcNoCentralityWithDCAFitterN(soa::Join const& collisions, + aod::McCollisions const& mcCollisions, + soa::Join const& candidates, + soa::Join const& particles, + soa::Join const& tracks, aod::BCs const& bcs) + { + fillTablesMc(collisions, mcCollisions, candidates, particles, tracks, bcs); + } + PROCESS_SWITCH(HfTreeCreatorLcToPKPi, processMcNoCentralityWithDCAFitterN, "Process MC tree writer w/o centrality with DCAFitterN", false); + + /// \brief process function for MC with centrality + /// \param collisions Collision table with join of the centrality table + /// \param mcCollisions MC collision table + /// \param candidates Lc->pKpi candidate table + /// \param tracks Track table + /// \param bcs Bunch-crossing table + void processMcWithCentralityWithDCAFitterN(soa::Join const& collisions, + aod::McCollisions const& mcCollisions, + soa::Join const& candidates, + soa::Join const& particles, + soa::Join const& tracks, aod::BCs const& bcs) + { + fillTablesMc(collisions, mcCollisions, candidates, particles, tracks, bcs); + } + PROCESS_SWITCH(HfTreeCreatorLcToPKPi, processMcWithCentralityWithDCAFitterN, "Process MC tree writer with centrality with DCAFitterN", false); + + /// \brief process function for MC w/o centrality + /// \param collisions Collision table w/o join of the centrality table + /// \param mcCollisions MC collision table + /// \param candidates Lc->pKpi candidate table + /// \param particles Generated particle table + /// \param tracks Track table + /// \param bcs Bunch-crossing table + void processMcNoCentralityWithKFParticle(soa::Join const& collisions, + aod::McCollisions const& mcCollisions, + soa::Join const& candidates, + soa::Join const& particles, + soa::Join const& tracks, aod::BCs const& bcs) + { + fillTablesMc(collisions, mcCollisions, candidates, particles, tracks, bcs); + } + PROCESS_SWITCH(HfTreeCreatorLcToPKPi, processMcNoCentralityWithKFParticle, "Process MC tree writer w/o centrality with KFParticle", false); + + /// \brief process function for MC with centrality + /// \param collisions Collision table with join of the centrality table + /// \param mcCollisions MC collision table + /// \param candidates Lc->pKpi candidate table + /// \param tracks Track table + /// \param bcs Bunch-crossing table + void processMcWithCentralityWithKFParticle(soa::Join const& collisions, + aod::McCollisions const& mcCollisions, + soa::Join const& candidates, + soa::Join const& particles, + soa::Join const& tracks, aod::BCs const& bcs) + { + fillTablesMc(collisions, mcCollisions, candidates, particles, tracks, bcs); + } + PROCESS_SWITCH(HfTreeCreatorLcToPKPi, processMcWithCentralityWithKFParticle, "Process MC tree writer with centrality with KFParticle", false); + + /// \brief core function to fill tables in data + /// \param collisions Collision table + /// \param candidates Lc->pKpi candidate table + template + void fillTablesData(Colls const& collisions, + CandType const& candidates, + TracksWPid const&, aod::BCs const&) { // Filling event properties rowCandidateFullEvents.reserve(collisions.size()); for (const auto& collision : collisions) { + + float centFT0A = -1.f; + float centFT0C = -1.f; + float centFT0M = -1.f; + float centFV0A = -1.f; + float centFDDM = -1.f; + if constexpr (useCentrality) { + centFT0A = collision.centFT0A(); + centFT0C = collision.centFT0C(); + centFT0M = collision.centFT0M(); + centFV0A = collision.centFV0A(); + centFDDM = collision.centFDDM(); + } + rowCandidateFullEvents( collision.globalIndex(), -1, @@ -497,61 +816,63 @@ struct HfTreeCreatorLcToPKPi { collision.posZ(), 0, collision.bc().runNumber(), - collision.centFT0A(), - collision.centFT0C(), - collision.centFT0M(), - collision.centFV0A(), - collision.centFDDM(), + centFT0A, + centFT0C, + centFT0M, + centFV0A, + centFDDM, collision.multZeqNTracksPV()); } // Filling candidate properties - if (fillCandidateLiteTable) { - rowCandidateLite.reserve(candidates.size()); + if constexpr (reconstructionType == aod::hf_cand::VertexerType::DCAFitter) { + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(candidates.size() * 2); + } else { + rowCandidateFull.reserve(candidates.size() * 2); + } } else { - rowCandidateFull.reserve(candidates.size()); + rowCandidateKF.reserve(candidates.size() * 2); } if (fillCollIdTable) { /// save also candidate collision indices rowCollisionId.reserve(candidates.size()); } for (const auto& candidate : candidates) { - auto trackPos1 = candidate.prong0_as(); // positive daughter (negative for the antiparticles) - auto trackNeg = candidate.prong1_as(); // negative daughter (positive for the antiparticles) - auto trackPos2 = candidate.prong2_as(); // positive daughter (negative for the antiparticles) - auto fillTable = [&](int CandFlag, - int FunctionSelection, - float FunctionInvMass, - float FunctionCt, - float FunctionY, - float FunctionE) { - double pseudoRndm = trackPos1.pt() * 1000. - (int64_t)(trackPos1.pt() * 1000); - if (FunctionSelection >= 1 && (candidate.pt() > downSampleBkgPtMax || (pseudoRndm < downSampleBkgFactor && candidate.pt() < downSampleBkgPtMax))) { + auto trackPos1 = candidate.template prong0_as(); // positive daughter (negative for the antiparticles) + auto trackNeg = candidate.template prong1_as(); // negative daughter (positive for the antiparticles) + auto trackPos2 = candidate.template prong2_as(); // positive daughter (negative for the antiparticles) + auto fillTable = [&](int CandFlag) { + double pseudoRndm = trackPos1.pt() * 1000. - static_cast(trackPos1.pt() * 1000); + const int FunctionSelection = CandFlag == 0 ? candidate.isSelLcToPKPi() : candidate.isSelLcToPiKP(); + if (FunctionSelection >= selectionFlagLc && (candidate.pt() > downSampleBkgPtMax || (pseudoRndm < downSampleBkgFactor && candidate.pt() < downSampleBkgPtMax))) { + float FunctionInvMass, FunctionInvMassKPi; + if constexpr (reconstructionType == aod::hf_cand::VertexerType::DCAFitter) { + FunctionInvMass = CandFlag == 0 ? hfHelper.invMassLcToPKPi(candidate) : hfHelper.invMassLcToPiKP(candidate); + FunctionInvMassKPi = CandFlag == 0 ? hfHelper.invMassKPiPairLcToPKPi(candidate) : hfHelper.invMassKPiPairLcToPiKP(candidate); + } else { + FunctionInvMass = CandFlag == 0 ? candidate.kfMassPKPi() : candidate.kfMassPiKP(); + FunctionInvMassKPi = CandFlag == 0 ? candidate.kfMassKPi() : candidate.kfMassPiK(); + } + const float FunctionCt = hfHelper.ctLc(candidate); + const float FunctionY = hfHelper.yLc(candidate); + const float FunctionE = hfHelper.eLc(candidate); if (fillCandidateLiteTable) { rowCandidateLite( candidate.posX(), candidate.posY(), candidate.posZ(), candidate.nProngsContributorsPV(), - // candidate.errorDecayLength(), - // candidate.errorDecayLengthXY(), + candidate.bitmapProngsContributorsPV(), candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), - // candidate.decayLengthNormalised(), - // candidate.decayLengthXYNormalised(), - // candidate.impactParameterNormalised0(), candidate.ptProng0(), - // candidate.impactParameterNormalised1(), candidate.ptProng1(), - // candidate.impactParameterNormalised2(), candidate.ptProng2(), candidate.impactParameter0(), candidate.impactParameter1(), candidate.impactParameter2(), - // candidate.errorImpactParameter0(), - // candidate.errorImpactParameter1(), - // candidate.errorImpactParameter2(), trackPos1.tpcNSigmaPi(), trackPos1.tpcNSigmaPr(), trackPos1.tofNSigmaPi(), @@ -578,8 +899,9 @@ struct HfTreeCreatorLcToPKPi { FunctionY, 0., 0., - 0.); - // candidate.globalIndex()); + 0., + -1, + FunctionInvMassKPi); if (fillCollIdTable) { /// save also candidate collision indices @@ -593,6 +915,7 @@ struct HfTreeCreatorLcToPKPi { candidate.posY(), candidate.posZ(), candidate.nProngsContributorsPV(), + candidate.bitmapProngsContributorsPV(), candidate.xSecondaryVertex(), candidate.ySecondaryVertex(), candidate.zSecondaryVertex(), @@ -657,16 +980,114 @@ struct HfTreeCreatorLcToPKPi { 0., 0., 0., - candidate.globalIndex()); + candidate.globalIndex(), + -1, + FunctionInvMassKPi); + } + + if constexpr (reconstructionType == aod::hf_cand::VertexerType::KfParticle) { + const float X = candidate.xSecondaryVertex(); + const float Y = candidate.ySecondaryVertex(); + const float Z = candidate.zSecondaryVertex(); + const float ErrX = candidate.kfXError(); + const float ErrY = candidate.kfYError(); + const float ErrZ = candidate.kfZError(); + const float ErrPVX = candidate.kfXPVError(); + const float ErrPVY = candidate.kfYPVError(); + const float ErrPVZ = candidate.kfZPVError(); + const float chi2prim_proton = CandFlag == 0 ? candidate.kfChi2PrimProng0() : candidate.kfChi2PrimProng2(); + const float chi2prim_kaon = candidate.kfChi2PrimProng1(); + const float chi2prim_pion = CandFlag == 0 ? candidate.kfChi2PrimProng2() : candidate.kfChi2PrimProng0(); + const float dca_proton_kaon = CandFlag == 0 ? candidate.kfDcaProng0Prong1() : candidate.kfDcaProng1Prong2(); + const float dca_proton_pion = candidate.kfDcaProng0Prong2(); + const float dca_pion_kaon = CandFlag == 0 ? candidate.kfDcaProng1Prong2() : candidate.kfDcaProng0Prong1(); + const float chi2Geo_proton_kaon = CandFlag == 0 ? candidate.kfChi2GeoProng0Prong1() : candidate.kfChi2GeoProng1Prong2(); + const float chi2Geo_proton_pion = candidate.kfChi2GeoProng0Prong2(); + const float chi2Geo_pion_kaon = CandFlag == 0 ? candidate.kfChi2GeoProng1Prong2() : candidate.kfChi2GeoProng0Prong1(); + const float chi2Geo = candidate.kfChi2Geo(); + const float chi2Topo = candidate.kfChi2Topo(); + const float l = candidate.kfDecayLength(); + const float dl = candidate.kfDecayLengthError(); + const float pt = std::sqrt(candidate.kfPx() * candidate.kfPx() + candidate.kfPy() * candidate.kfPy()); + const float deltaPt = std::sqrt(candidate.kfPx() * candidate.kfPx() * candidate.kfErrorPx() * candidate.kfErrorPx() + + candidate.kfPy() * candidate.kfPy() * candidate.kfErrorPy() * candidate.kfErrorPy()) / + pt; + const float p = std::sqrt(pt * pt + candidate.kfPz() * candidate.kfPz()); + const float deltaP = std::sqrt(pt * pt * deltaPt * deltaPt + + candidate.kfPz() * candidate.kfPz() * candidate.kfErrorPz() * candidate.kfErrorPz()) / + p; + const float T = l * MassLambdaCPlus / LightSpeedCm2PS / p; + const float deltaT = dl * MassLambdaCPlus / LightSpeedCm2PS / p; + const float mass = CandFlag == 0 ? candidate.kfMassPKPi() : candidate.kfMassPiKP(); + rowCandidateKF( + X, Y, Z, ErrX, ErrY, ErrZ, + ErrPVX, ErrPVY, ErrPVZ, + chi2prim_proton, chi2prim_kaon, chi2prim_pion, + dca_proton_kaon, dca_proton_pion, dca_pion_kaon, + chi2Geo_proton_kaon, chi2Geo_proton_pion, chi2Geo_pion_kaon, + chi2Geo, chi2Topo, l, dl, l / dl, T, deltaT, + mass, p, pt, deltaP, deltaPt, + FunctionSelection, UndefValueInt); } } }; - fillTable(0, candidate.isSelLcToPKPi(), hfHelper.invMassLcToPKPi(candidate), hfHelper.ctLc(candidate), hfHelper.yLc(candidate), hfHelper.eLc(candidate)); - fillTable(1, candidate.isSelLcToPiKP(), hfHelper.invMassLcToPiKP(candidate), hfHelper.ctLc(candidate), hfHelper.yLc(candidate), hfHelper.eLc(candidate)); + fillTable(0); + fillTable(1); } } - PROCESS_SWITCH(HfTreeCreatorLcToPKPi, processData, "Process data tree writer", false); + + /// \brief process function for data w/o centrality + /// \param collisions Collision table w/o join of the centrality table + /// \param candidates Lc->pKpi candidate table + /// \param tracks Track table + /// \param bcs Bunch-crossing table + void processDataNoCentralityWithDCAFitterN(soa::Join const& collisions, + soa::Join const& candidates, + TracksWPid const& tracks, aod::BCs const& bcs) + { + fillTablesData(collisions, candidates, tracks, bcs); + } + PROCESS_SWITCH(HfTreeCreatorLcToPKPi, processDataNoCentralityWithDCAFitterN, "Process data tree writer w/o centrality with DCAFitterN", false); + + /// \brief process function for data with centrality + /// \param collisions Collision table with join of the centrality table + /// \param candidates Lc->pKpi candidate table + /// \param tracks Track table + /// \param bcs Bunch-crossing table + void processDataWithCentralityWithDCAFitterN(soa::Join const& collisions, + soa::Join const& candidates, + TracksWPid const& tracks, aod::BCs const& bcs) + { + fillTablesData(collisions, candidates, tracks, bcs); + } + PROCESS_SWITCH(HfTreeCreatorLcToPKPi, processDataWithCentralityWithDCAFitterN, "Process data tree writer with centrality with DCAFitterN", true); + + /// \brief process function for data w/o centrality + /// \param collisions Collision table w/o join of the centrality table + /// \param candidates Lc->pKpi candidate table + /// \param tracks Track table + /// \param bcs Bunch-crossing table + void processDataNoCentralityWithKFParticle(soa::Join const& collisions, + soa::Join const& candidates, + TracksWPid const& tracks, aod::BCs const& bcs) + { + fillTablesData(collisions, candidates, tracks, bcs); + } + PROCESS_SWITCH(HfTreeCreatorLcToPKPi, processDataNoCentralityWithKFParticle, "Process data tree writer w/o centrality with KFParticle", false); + + /// \brief process function for data with centrality + /// \param collisions Collision table with join of the centrality table + /// \param candidates Lc->pKpi candidate table + /// \param tracks Track table + /// \param bcs Bunch-crossing table + void processDataWithCentralityWithKFParticle(soa::Join const& collisions, + soa::Join const& candidates, + TracksWPid const& tracks, aod::BCs const& bcs) + { + fillTablesData(collisions, candidates, tracks, bcs); + } + PROCESS_SWITCH(HfTreeCreatorLcToPKPi, processDataWithCentralityWithKFParticle, "Process data tree writer with centrality with KFParticle", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/TableProducer/treeCreatorOmegacSt.cxx b/PWGHF/TableProducer/treeCreatorOmegacSt.cxx index d8985b6314a..2203536b195 100644 --- a/PWGHF/TableProducer/treeCreatorOmegacSt.cxx +++ b/PWGHF/TableProducer/treeCreatorOmegacSt.cxx @@ -14,7 +14,10 @@ /// /// \author Jochen Klein -#include +#include +#include +#include + #include #include "CCDB/BasicCCDBManager.h" @@ -23,6 +26,8 @@ #include "DataFormatsParameters/GRPObject.h" #include "DCAFitter/DCAFitterN.h" #include "DetectorsBase/Propagator.h" +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/ASoA.h" @@ -48,10 +53,40 @@ using namespace o2::hf_trkcandsel; namespace o2::aod { +namespace hf_st_charmed_baryon_gen +{ +DECLARE_SOA_COLUMN(PxCharmedBaryon, pxCharmedBaryon, float); +DECLARE_SOA_COLUMN(PyCharmedBaryon, pyCharmedBaryon, float); +DECLARE_SOA_COLUMN(PzCharmedBaryon, pzCharmedBaryon, float); +DECLARE_SOA_COLUMN(PdgCodeCharmedBaryon, pdgCodeCharmedBaryon, int); +DECLARE_SOA_COLUMN(PxCasc, pxCasc, float); +DECLARE_SOA_COLUMN(PyCasc, pyCasc, float); +DECLARE_SOA_COLUMN(PzCasc, pzCasc, float); +DECLARE_SOA_COLUMN(PdgCodeCasc, pdgCodeCasc, int); +DECLARE_SOA_COLUMN(DecayLengthCharmedBaryon, decayLengthCharmedBaryon, float); +DECLARE_SOA_COLUMN(DecayLengthXYCharmedBaryon, decayLengthXYCharmedBaryon, float); +DECLARE_SOA_COLUMN(DecayLengthCasc, decayLengthCasc, float); +DECLARE_SOA_COLUMN(DecayLengthXYCasc, decayLengthXYCasc, float); +} // namespace hf_st_charmed_baryon_gen + +DECLARE_SOA_TABLE(HfStChBarGens, "AOD", "HFSTCHBARGEN", + hf_st_charmed_baryon_gen::PxCharmedBaryon, + hf_st_charmed_baryon_gen::PyCharmedBaryon, + hf_st_charmed_baryon_gen::PzCharmedBaryon, + hf_st_charmed_baryon_gen::PdgCodeCharmedBaryon, + hf_st_charmed_baryon_gen::PxCasc, + hf_st_charmed_baryon_gen::PyCasc, + hf_st_charmed_baryon_gen::PzCasc, + hf_st_charmed_baryon_gen::PdgCodeCasc, + hf_st_charmed_baryon_gen::DecayLengthCharmedBaryon, + hf_st_charmed_baryon_gen::DecayLengthXYCharmedBaryon, + hf_st_charmed_baryon_gen::DecayLengthCasc, + hf_st_charmed_baryon_gen::DecayLengthXYCasc); + // CharmedBaryon -> Casc + Pion // -> Lambda + BachPi/BachKa // -> Pr + Pi -namespace st_omegac +namespace hf_st_charmed_baryon { DECLARE_SOA_COLUMN(MassOmega, massOmega, float); DECLARE_SOA_COLUMN(MassXi, massXi, float); @@ -97,92 +132,73 @@ DECLARE_SOA_COLUMN(Chi2TopologicalCharmedBaryon, chi2TopologicalCharmedBaryon, f DECLARE_SOA_COLUMN(Chi2TopologicalCasc, chi2TopologicalCasc, float); DECLARE_SOA_COLUMN(DecayLengthCharmedBaryon, decayLengthCharmedBaryon, float); DECLARE_SOA_COLUMN(DecayLengthXYCharmedBaryon, decayLengthXYCharmedBaryon, float); +DECLARE_SOA_COLUMN(DecayLengthCharmedBaryonUntracked, decayLengthCharmedBaryonUntracked, float); +DECLARE_SOA_COLUMN(DecayLengthXYCharmedBaryonUntracked, decayLengthXYCharmedBaryonUntracked, float); DECLARE_SOA_COLUMN(DecayLengthCasc, decayLengthCasc, float); DECLARE_SOA_COLUMN(DecayLengthXYCasc, decayLengthXYCasc, float); -} // namespace st_omegac - -namespace st_omegac_gen -{ -DECLARE_SOA_COLUMN(PxOmegac, pxOmegac, float); -DECLARE_SOA_COLUMN(PyOmegac, pyOmegac, float); -DECLARE_SOA_COLUMN(PzOmegac, pzOmegac, float); -DECLARE_SOA_COLUMN(IsPositiveOmegac, isPositiveOmegac, bool); -DECLARE_SOA_COLUMN(PxOmega, pxOmega, float); -DECLARE_SOA_COLUMN(PyOmega, pyOmega, float); -DECLARE_SOA_COLUMN(PzOmega, pzOmega, float); -DECLARE_SOA_COLUMN(IsPositiveOmega, isPositiveOmega, bool); -DECLARE_SOA_COLUMN(DecayLengthOmegac, decayLengthOmegac, float); -DECLARE_SOA_COLUMN(DecayLengthXYOmegac, decayLengthXYOmegac, float); -DECLARE_SOA_COLUMN(DecayLengthOmega, decayLengthOmega, float); -DECLARE_SOA_COLUMN(DecayLengthXYOmega, decayLengthXYOmega, float); -} // namespace st_omegac_gen - -DECLARE_SOA_TABLE(HfOmegacSt, "AOD", "HFOMEGACST", - st_omegac::MassOmega, - st_omegac::MassXi, - st_omegac::MassLambda, - st_omegac::NSigmaTpcPion, - st_omegac::NSigmaTofPion, - st_omegac::NSigmaTpcV0Pr, - st_omegac::NSigmaTofV0Pr, - st_omegac::NSigmaTpcV0Pi, - st_omegac::NSigmaTofV0Pi, - st_omegac::NSigmaTpcBachPi, - st_omegac::NSigmaTofBachPi, - st_omegac::NSigmaTpcBachKa, - st_omegac::NSigmaTofBachKa, - st_omegac::PxCasc, - st_omegac::PyCasc, - st_omegac::PzCasc, - st_omegac::IsPositiveCasc, - st_omegac::PxPion, - st_omegac::PyPion, - st_omegac::PzPion, - st_omegac::IsPositivePion, - st_omegac::ITSClusterMapPion, - st_omegac::CpaCharmedBaryon, - st_omegac::CpaXYCharmedBaryon, - st_omegac::CpaCasc, - st_omegac::CpaXYCasc, - st_omegac::DcaXYCasc, - st_omegac::DcaXYUncCasc, - st_omegac::DcaZCasc, - st_omegac::DcaZUncCasc, - st_omegac::DcaXYPion, - st_omegac::DcaXYUncPion, - st_omegac::DcaZPion, - st_omegac::DcaZUncPion, - st_omegac::DcaXYPr, - st_omegac::DcaZPr, - st_omegac::DcaXYKa, - st_omegac::DcaZKa, - st_omegac::DcaXYPi, - st_omegac::DcaZPi, - st_omegac::Chi2TopologicalCharmedBaryon, - st_omegac::Chi2TopologicalCasc, - st_omegac::DecayLengthCharmedBaryon, - st_omegac::DecayLengthXYCharmedBaryon, - st_omegac::DecayLengthCasc, - st_omegac::DecayLengthXYCasc); - -DECLARE_SOA_TABLE(HfOmegaStGen, "AOD", "HFOMEGACSTGEN", - st_omegac_gen::PxOmegac, - st_omegac_gen::PyOmegac, - st_omegac_gen::PzOmegac, - st_omegac_gen::IsPositiveOmegac, - st_omegac_gen::PxOmega, - st_omegac_gen::PyOmega, - st_omegac_gen::PzOmega, - st_omegac_gen::IsPositiveOmega, - st_omegac_gen::DecayLengthOmegac, - st_omegac_gen::DecayLengthXYOmegac, - st_omegac_gen::DecayLengthOmega, - st_omegac_gen::DecayLengthXYOmega); +DECLARE_SOA_INDEX_COLUMN_FULL(MotherCasc, motherCasc, int, HfStChBarGens, "_Casc"); +DECLARE_SOA_INDEX_COLUMN_FULL(MotherPion, motherPion, int, HfStChBarGens, "_Pion"); +} // namespace hf_st_charmed_baryon + +DECLARE_SOA_TABLE(HfStChBars, "AOD", "HFSTCHBAR", + hf_st_charmed_baryon::MassOmega, + hf_st_charmed_baryon::MassXi, + hf_st_charmed_baryon::MassLambda, + hf_st_charmed_baryon::NSigmaTpcPion, + hf_st_charmed_baryon::NSigmaTofPion, + hf_st_charmed_baryon::NSigmaTpcV0Pr, + hf_st_charmed_baryon::NSigmaTofV0Pr, + hf_st_charmed_baryon::NSigmaTpcV0Pi, + hf_st_charmed_baryon::NSigmaTofV0Pi, + hf_st_charmed_baryon::NSigmaTpcBachPi, + hf_st_charmed_baryon::NSigmaTofBachPi, + hf_st_charmed_baryon::NSigmaTpcBachKa, + hf_st_charmed_baryon::NSigmaTofBachKa, + hf_st_charmed_baryon::PxCasc, + hf_st_charmed_baryon::PyCasc, + hf_st_charmed_baryon::PzCasc, + hf_st_charmed_baryon::IsPositiveCasc, + hf_st_charmed_baryon::PxPion, + hf_st_charmed_baryon::PyPion, + hf_st_charmed_baryon::PzPion, + hf_st_charmed_baryon::IsPositivePion, + hf_st_charmed_baryon::ITSClusterMapPion, + hf_st_charmed_baryon::CpaCharmedBaryon, + hf_st_charmed_baryon::CpaXYCharmedBaryon, + hf_st_charmed_baryon::CpaCasc, + hf_st_charmed_baryon::CpaXYCasc, + hf_st_charmed_baryon::DcaXYCasc, + hf_st_charmed_baryon::DcaXYUncCasc, + hf_st_charmed_baryon::DcaZCasc, + hf_st_charmed_baryon::DcaZUncCasc, + hf_st_charmed_baryon::DcaXYPion, + hf_st_charmed_baryon::DcaXYUncPion, + hf_st_charmed_baryon::DcaZPion, + hf_st_charmed_baryon::DcaZUncPion, + hf_st_charmed_baryon::DcaXYPr, + hf_st_charmed_baryon::DcaZPr, + hf_st_charmed_baryon::DcaXYKa, + hf_st_charmed_baryon::DcaZKa, + hf_st_charmed_baryon::DcaXYPi, + hf_st_charmed_baryon::DcaZPi, + hf_st_charmed_baryon::Chi2TopologicalCharmedBaryon, + hf_st_charmed_baryon::Chi2TopologicalCasc, + hf_st_charmed_baryon::DecayLengthCharmedBaryon, + hf_st_charmed_baryon::DecayLengthXYCharmedBaryon, + hf_st_charmed_baryon::DecayLengthCharmedBaryonUntracked, + hf_st_charmed_baryon::DecayLengthXYCharmedBaryonUntracked, + hf_st_charmed_baryon::DecayLengthCasc, + hf_st_charmed_baryon::DecayLengthXYCasc, + hf_st_charmed_baryon::MotherCascId, + hf_st_charmed_baryon::MotherPionId); } // namespace o2::aod struct HfTreeCreatorOmegacSt { - Produces outputTable; - Produces outputTableGen; + Produces outputTable; + Produces outputTableGen; + + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; Configurable materialCorrectionType{"materialCorrectionType", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrLUT), "Type of material correction"}; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -191,6 +207,7 @@ struct HfTreeCreatorOmegacSt { Configurable matLutPath{"matLutPath", "GLO/Param/MatLUT", "Path of the material LUT"}; Configurable propToDCA{"propToDCA", true, "create tracks version propagated to PCA"}; Configurable useAbsDCA{"useAbsDCA", true, "Minimise abs. distance rather than chi2"}; + Configurable skimmedProcessing{"skimmedProcessing", false, "Put true if you are processing apass*_skimmed datasets"}; Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; @@ -218,6 +235,7 @@ struct HfTreeCreatorOmegacSt { float bz = 0.; int runNumber{0}; + std::map mapMcPartToGenTable; using Collisions = soa::Filtered>; using TracksExt = soa::Join; @@ -227,8 +245,8 @@ struct HfTreeCreatorOmegacSt { (filterCollisions.node() == 8 && o2::aod::evsel::sel8 == true); // Preslice perCol = aod::track::collisionId; - Preslice trackIndicesPerCollision = aod::track_association::collisionId; - Preslice assignedTrackedCascadesPerCollision = aod::track::collisionId; + PresliceUnsorted trackIndicesPerCollision = aod::track_association::collisionId; + PresliceUnsorted assignedTrackedCascadesPerCollision = aod::track::collisionId; std::shared_ptr hCandidatesPrPi, hCandidatesV0Pi, hCandidatesCascPi; HistogramRegistry registry{ @@ -289,36 +307,81 @@ struct HfTreeCreatorOmegacSt { // processData: loop over reconstructed objects, no MC information // processGen: loop over reconstructed objects, use MC information (mutually exclusive? combine?) - void processMc(aod::McCollision const&, + void processMc(aod::McCollisions const&, aod::McParticles const& mcParticles) { + mapMcPartToGenTable.clear(); for (const auto& mcParticle : mcParticles) { - if ((mcParticle.pdgCode() == kOmegaMinus) && - mcParticle.has_mothers() && - (mcParticle.mothers_first_as().pdgCode() == constants::physics::Pdg::kOmegaC0)) { - const auto& mcColl = mcParticle.mcCollision(); - std::array primaryVertexPosGen = {mcColl.posX(), mcColl.posY(), mcColl.posZ()}; - std::array secondaryVertexGen = {mcParticle.vx(), mcParticle.vy(), mcParticle.vz()}; - const auto decayLengthGen = RecoDecay::distance(secondaryVertexGen, primaryVertexPosGen); - registry.fill(HIST("hDecayLengthScaledMc"), decayLengthGen * o2::constants::physics::MassOmegaC0 / mcParticle.mothers_first_as().p() * 1e4); + const bool isOmegaC = std::abs(mcParticle.pdgCode()) == constants::physics::Pdg::kOmegaC0; + const bool isXiC = std::abs(mcParticle.pdgCode()) == constants::physics::Pdg::kXiC0; + if (isOmegaC || isXiC) { + const auto daughters = mcParticle.daughters_as(); + if (daughters.size() == 2) { + int idxPionDaughter = -1; + int idxCascDaughter = -1; + const auto daughters = mcParticle.daughters_as(); + for (const auto& daughter : daughters) { + if (idxCascDaughter < 0 && (std::abs(daughter.pdgCode()) == (isOmegaC ? kOmegaMinus : kXiMinus))) { + idxCascDaughter = daughter.globalIndex(); + } + if (idxPionDaughter < 0 && (std::abs(daughter.pdgCode()) == kPiPlus)) { + idxPionDaughter = daughter.globalIndex(); + } + } + if ((idxPionDaughter >= 0) && (idxCascDaughter >= 0)) { + const auto& cascDaughter = mcParticles.iteratorAt(idxCascDaughter); + const auto& mcColl = mcParticle.mcCollision(); + std::array primaryVertexPosGen = {mcColl.posX(), mcColl.posY(), mcColl.posZ()}; + std::array secondaryVertexGen = {cascDaughter.vx(), cascDaughter.vy(), cascDaughter.vz()}; + float decayLengthCascGen = -1.; + float decayLengthXYCascGen = -1.; + if (cascDaughter.has_daughters()) { + const auto& cascDecayDaughter = cascDaughter.daughters_as().iteratorAt(0); + std::array tertiaryVertexGen = {cascDecayDaughter.vx(), cascDecayDaughter.vy(), cascDecayDaughter.vz()}; + decayLengthCascGen = RecoDecay::distance(tertiaryVertexGen, primaryVertexPosGen); + decayLengthXYCascGen = RecoDecay::distanceXY(tertiaryVertexGen, primaryVertexPosGen); + } + const auto decayLengthGen = RecoDecay::distance(secondaryVertexGen, primaryVertexPosGen); + const auto decayLengthXYGen = RecoDecay::distanceXY(secondaryVertexGen, primaryVertexPosGen); + registry.fill(HIST("hDecayLengthScaledMc"), decayLengthGen * o2::constants::physics::MassOmegaC0 / mcParticle.mothers_first_as().p() * 1e4); + outputTableGen( + mcParticle.px(), + mcParticle.py(), + mcParticle.pz(), + mcParticle.pdgCode(), + cascDaughter.px(), + cascDaughter.py(), + cascDaughter.pz(), + cascDaughter.pdgCode(), + decayLengthGen, + decayLengthXYGen, + decayLengthCascGen, + decayLengthXYCascGen); + mapMcPartToGenTable[mcParticle.globalIndex()] = outputTableGen.lastIndex(); + } + } } } } PROCESS_SWITCH(HfTreeCreatorOmegacSt, processMc, "Process MC", true); - void processData(Collisions const& collisions, - aod::AssignedTrackedCascades const& trackedCascades, - aod::TrackAssoc const& trackIndices, - aod::Cascades const&, - aod::V0s const&, - TracksExt const&, - aod::BCsWithTimestamps const&) + template + void fillTable(Collisions const& collisions, + aod::AssignedTrackedCascades const& trackedCascades, + aod::TrackAssoc const& trackIndices) { const auto matCorr = static_cast(materialCorrectionType.value); for (const auto& collision : collisions) { const auto bc = collision.bc_as(); if (runNumber != bc.runNumber()) { + if (skimmedProcessing) { + if (runNumber == 0) { + zorroSummary.setObject(zorro.getZorroSummary()); + } + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), "fTrackedOmega"); + zorro.populateHistRegistry(registry, bc.runNumber()); + } runNumber = bc.runNumber(); auto timestamp = bc.timestamp(); @@ -333,6 +396,9 @@ struct HfTreeCreatorOmegacSt { } df2.setBz(bz); } + if (skimmedProcessing) { + zorro.isSelected(collision.bc().globalBC()); + } const auto primaryVertex = getPrimaryVertex(collision); const std::array primaryVertexPos = {primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}; @@ -343,7 +409,15 @@ struct HfTreeCreatorOmegacSt { o2::dataformats::DCA impactParameterCasc; for (const auto& trackedCascade : groupedTrackedCascades) { - const auto trackCasc = trackedCascade.track_as(); + const auto trackCasc = trackedCascade.track_as(); + int trackCascMotherId = -1; + if constexpr (std::is_same::value) { + if (trackCasc.has_mcParticle() && trackCasc.mcParticle().has_mothers()) { + if (auto res = mapMcPartToGenTable.find(trackCasc.mcParticle().mothersIds()[0]); res != mapMcPartToGenTable.end()) { + trackCascMotherId = res->second; + } + } + } auto trackParCovCasc = getTrackParCov(trackCasc); if (bzOnly) { o2::base::Propagator::Instance()->propagateToDCA(primaryVertex, trackParCovCasc, bz, 2.f, matCorr, &impactParameterCasc); @@ -352,10 +426,10 @@ struct HfTreeCreatorOmegacSt { } const auto& casc = trackedCascade.cascade(); - const auto& bachelor = casc.bachelor_as(); + const auto& bachelor = casc.bachelor_as(); const auto& v0 = casc.v0(); - const auto& v0TrackPos = v0.posTrack_as(); - const auto& v0TrackNeg = v0.negTrack_as(); + const auto& v0TrackPos = v0.posTrack_as(); + const auto& v0TrackNeg = v0.negTrack_as(); if (!v0TrackPos.hasTPC() || !v0TrackNeg.hasTPC() || !bachelor.hasTPC() || v0TrackPos.tpcNClsFindable() < minNoClsTrackedCascade || @@ -374,7 +448,7 @@ struct HfTreeCreatorOmegacSt { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN for Pr-Pi cannot work, skipping the candidate."; + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN for Pr-Pi cannot work, skipping the candidate."; hCandidatesPrPi->Fill(SVFitting::Fail); continue; } @@ -395,7 +469,7 @@ struct HfTreeCreatorOmegacSt { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN for V0-bachelor cannot work, skipping the candidate."; + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN for V0-bachelor cannot work, skipping the candidate."; hCandidatesV0Pi->Fill(SVFitting::Fail); continue; } @@ -409,8 +483,9 @@ struct HfTreeCreatorOmegacSt { std::array, 2> momentaCascDaughters; trackParV0.getPxPyPzGlo(momentaCascDaughters[0]); trackParBachelor.getPxPyPzGlo(momentaCascDaughters[1]); + o2::track::TrackParCov trackParCovCascUntracked = df2.createParentTrackParCov(0); std::array pCasc; - df2.createParentTrackParCov().getPxPyPzGlo(pCasc); + trackParCovCascUntracked.getPxPyPzGlo(pCasc); const auto cpaCasc = RecoDecay::cpa(primaryVertexPos, df2.getPCACandidate(), pCasc); const auto cpaXYCasc = RecoDecay::cpaXY(primaryVertexPos, df2.getPCACandidate(), pCasc); @@ -454,7 +529,7 @@ struct HfTreeCreatorOmegacSt { } for (auto trackId : groupedTrackIds) { - const auto track = trackId.template track_as(); + const auto track = trackId.template track_as(); if (track.globalIndex() == v0TrackPr.globalIndex() || track.globalIndex() == v0TrackPi.globalIndex() || track.globalIndex() == bachelor.globalIndex()) { @@ -468,6 +543,14 @@ struct HfTreeCreatorOmegacSt { (track.itsChi2NCl() <= 36.f) && (std::abs(track.tpcNSigmaPi()) < maxNSigmaPion)) { LOGF(debug, " .. combining with pion candidate %d", track.globalIndex()); + int trackMotherId = -1; + if constexpr (std::is_same::value) { + if (track.has_mcParticle() && track.mcParticle().has_mothers()) { + if (auto res = mapMcPartToGenTable.find(track.mcParticle().mothersIds()[0]); res != mapMcPartToGenTable.end()) { + trackMotherId = res->second; + } + } + } auto trackParCovCasc = getTrackParCov(trackCasc); auto trackParCovPion = getTrackParCov(track); o2::dataformats::DCA impactParameterPion; @@ -479,6 +562,13 @@ struct HfTreeCreatorOmegacSt { hCandidatesCascPi->Fill(SVFitting::BeforeFit); try { + auto decayLengthUntracked = -1.; + auto decayLengthXYUntracked = -1.; + if (df2.process(trackParCovCascUntracked, trackParCovPion)) { + const auto& secondaryVertexUntracked = df2.getPCACandidate(); + decayLengthUntracked = RecoDecay::distance(secondaryVertexUntracked, primaryVertexPos); + decayLengthXYUntracked = RecoDecay::distanceXY(secondaryVertexUntracked, primaryVertexPos); + } if (df2.process(trackParCovCasc, trackParCovPion)) { const auto& secondaryVertex = df2.getPCACandidate(); const auto decayLength = RecoDecay::distance(secondaryVertex, primaryVertexPos); @@ -544,14 +634,18 @@ struct HfTreeCreatorOmegacSt { trackedCascade.topologyChi2(), decayLength, decayLengthXY, + decayLengthUntracked, + decayLengthXYUntracked, decayLengthCasc, - decayLengthCascXY); + decayLengthCascXY, + trackCascMotherId, + trackMotherId); } } else { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN for Casc-Pi cannot work, skipping the candidate."; + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN for Casc-Pi cannot work, skipping the candidate."; hCandidatesCascPi->Fill(SVFitting::Fail); continue; } @@ -563,11 +657,37 @@ struct HfTreeCreatorOmegacSt { } } } + + void processData(Collisions const& collisions, + soa::SmallGroups const& trackedCascades, + aod::TrackAssoc const& trackIndices, + aod::Cascades const&, + aod::V0s const&, + TracksExt const&, + aod::BCsWithTimestamps const&) + { + fillTable(collisions, trackedCascades, trackIndices); + } PROCESS_SWITCH(HfTreeCreatorOmegacSt, processData, "Process data", true); + void processMcRec(Collisions const& collisions, + aod::McCollisions const&, + soa::SmallGroups const& trackedCascades, + aod::TrackAssoc const& trackIndices, + aod::Cascades const&, + aod::V0s const&, + // TracksExt const& tracks, // TODO: should be TracksExtMc + TracksExtMc const&, + aod::McParticles const&, + aod::BCsWithTimestamps const&) + { + fillTable(collisions, trackedCascades, trackIndices); + } + PROCESS_SWITCH(HfTreeCreatorOmegacSt, processMcRec, "Process MC reco", true); + void processMcGen(aod::Collision const& collision, aod::McCollisions const&, - aod::AssignedTrackedCascades const& trackedCascades, + soa::SmallGroups const& trackedCascades, aod::Cascades const&, aod::V0s const&, TracksExtMc const& tracks, @@ -677,7 +797,7 @@ struct HfTreeCreatorOmegacSt { hCandidatesCascPi->Fill(SVFitting::FitOk); } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCFitterN for Casc-Pi cannot work, skipping the candidate."; + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN for Casc-Pi cannot work, skipping the candidate."; hCandidatesCascPi->Fill(SVFitting::Fail); continue; } diff --git a/PWGHF/TableProducer/treeCreatorOmegacToOmegaKa.cxx b/PWGHF/TableProducer/treeCreatorOmegacToOmegaKa.cxx new file mode 100644 index 00000000000..0330cabc861 --- /dev/null +++ b/PWGHF/TableProducer/treeCreatorOmegacToOmegaKa.cxx @@ -0,0 +1,269 @@ +// 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 treeCreatorOmegacToOmegaKa.cxx +/// \brief Writer of the omegac0 to Omega Ka candidates in the form of flat tables to be stored in TTrees. +/// In this file are defined and filled the output tables +/// +/// \author Federica Zanone , Heidelberg University + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/RecoDecay.h" + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +using namespace o2; +using namespace o2::framework; + +namespace o2::aod +{ +namespace full +{ +// collision info +DECLARE_SOA_COLUMN(IsEventSel8, isEventSel8, bool); +DECLARE_SOA_COLUMN(IsEventSelZ, isEventSelZ, bool); +// from creator +DECLARE_SOA_COLUMN(XPv, xPv, float); +DECLARE_SOA_COLUMN(YPv, yPv, float); +DECLARE_SOA_COLUMN(ZPv, zPv, float); +DECLARE_SOA_COLUMN(XDecayVtxCharmBaryon, xDecayVtxCharmBaryon, float); +DECLARE_SOA_COLUMN(YDecayVtxCharmBaryon, yDecayVtxCharmBaryon, float); +DECLARE_SOA_COLUMN(ZDecayVtxCharmBaryon, zDecayVtxCharmBaryon, float); +DECLARE_SOA_COLUMN(XDecayVtxCascade, xDecayVtxCascade, float); +DECLARE_SOA_COLUMN(YDecayVtxCascade, yDecayVtxCascade, float); +DECLARE_SOA_COLUMN(ZDecayVtxCascade, zDecayVtxCascade, float); +DECLARE_SOA_COLUMN(XDecayVtxV0, xDecayVtxV0, float); +DECLARE_SOA_COLUMN(YDecayVtxV0, yDecayVtxV0, float); +DECLARE_SOA_COLUMN(ZDecayVtxV0, zDecayVtxV0, float); +DECLARE_SOA_COLUMN(SignDecay, signDecay, int8_t); // sign of ka <- omega +DECLARE_SOA_COLUMN(PxCharmBaryon, pxCharmBaryon, float); +DECLARE_SOA_COLUMN(PyCharmBaryon, pyCharmBaryon, float); +DECLARE_SOA_COLUMN(PzCharmBaryon, pzCharmBaryon, float); +DECLARE_SOA_COLUMN(PxKaFromCharmBaryon, pxKaFromCharmBaryon, float); +DECLARE_SOA_COLUMN(PyKaFromCharmBaryon, pyKaFromCharmBaryon, float); +DECLARE_SOA_COLUMN(PzKaFromCharmBaryon, pzKaFromCharmBaryon, float); +DECLARE_SOA_COLUMN(PxKaFromCasc, pxKaFromCasc, float); +DECLARE_SOA_COLUMN(PyKaFromCasc, pyKaFromCasc, float); +DECLARE_SOA_COLUMN(PzKaFromCasc, pzKaFromCasc, float); +DECLARE_SOA_COLUMN(PxPosV0Dau, pxPosV0Dau, float); +DECLARE_SOA_COLUMN(PyPosV0Dau, pyPosV0Dau, float); +DECLARE_SOA_COLUMN(PzPosV0Dau, pzPosV0Dau, float); +DECLARE_SOA_COLUMN(PxNegV0Dau, pxNegV0Dau, float); +DECLARE_SOA_COLUMN(PyNegV0Dau, pyNegV0Dau, float); +DECLARE_SOA_COLUMN(PzNegV0Dau, pzNegV0Dau, float); +DECLARE_SOA_COLUMN(ImpactParCascXY, impactParCascXY, float); +DECLARE_SOA_COLUMN(ImpactParKaFromCharmBaryonXY, impactParKaFromCharmBaryonXY, float); +DECLARE_SOA_COLUMN(ErrImpactParCascXY, errImpactParCascXY, float); +DECLARE_SOA_COLUMN(ErrImpactParKaFromCharmBaryonXY, errImpactParKaFromCharmBaryonXY, float); +DECLARE_SOA_COLUMN(InvMassLambda, invMassLambda, float); +DECLARE_SOA_COLUMN(InvMassCascade, invMassCascade, float); +DECLARE_SOA_COLUMN(InvMassCharmBaryon, invMassCharmBaryon, float); +DECLARE_SOA_COLUMN(EtaV0PosDau, etaV0PosDau, float); +DECLARE_SOA_COLUMN(EtaV0NegDau, etaV0NegDau, float); +DECLARE_SOA_COLUMN(EtaKaFromCasc, etaKaFromCasc, float); +DECLARE_SOA_COLUMN(EtaKaFromCharmBaryon, etaKaFromCharmBaryon, float); +DECLARE_SOA_COLUMN(DcaXYToPvV0Dau0, dcaXYToPvV0Dau0, float); +DECLARE_SOA_COLUMN(DcaXYToPvV0Dau1, dcaXYToPvV0Dau1, float); +DECLARE_SOA_COLUMN(DcaXYToPvCascDau, dcaXYToPvCascDau, float); +DECLARE_SOA_COLUMN(DcaCascDau, dcaCascDau, float); +DECLARE_SOA_COLUMN(DcaV0Dau, dcaV0Dau, float); +DECLARE_SOA_COLUMN(DcaCharmBaryonDau, dcaCharmBaryonDau, float); +DECLARE_SOA_COLUMN(ErrorDecayLengthCharmBaryon, errorDecayLengthCharmBaryon, float); +DECLARE_SOA_COLUMN(NormImpParCascade, normImpParCascade, double); +DECLARE_SOA_COLUMN(NormImpParKaFromCharmBar, normImpParKaFromCharmBar, double); +DECLARE_SOA_COLUMN(IsKaonGlbTrkWoDca, isKaonGlbTrkWoDca, bool); +DECLARE_SOA_COLUMN(KaonItsNCls, kaonItsNCls, uint8_t); +// from creator - MC +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level +DECLARE_SOA_COLUMN(OriginRec, originRec, int8_t); +DECLARE_SOA_COLUMN(CollisionMatched, collisionMatched, bool); +// from selector +DECLARE_SOA_COLUMN(PidTpcInfoStored, pidTpcInfoStored, int); +DECLARE_SOA_COLUMN(PidTofInfoStored, pidTofInfoStored, int); +DECLARE_SOA_COLUMN(TpcNSigmaKaFromCharmBaryon, tpcNSigmaKaFromCharmBaryon, float); +DECLARE_SOA_COLUMN(TpcNSigmaKaFromCasc, tpcNSigmaKaFromCasc, float); +DECLARE_SOA_COLUMN(TpcNSigmaPiFromLambda, tpcNSigmaPiFromLambda, float); +DECLARE_SOA_COLUMN(TpcNSigmaPrFromLambda, tpcNSigmaPrFromLambda, float); +DECLARE_SOA_COLUMN(TofNSigmaKaFromCharmBaryon, tofNSigmaKaFromCharmBaryon, float); +DECLARE_SOA_COLUMN(TofNSigmaKaFromCasc, tofNSigmaKaFromCasc, float); +DECLARE_SOA_COLUMN(TofNSigmaPiFromLambda, tofNSigmaPiFromLambda, float); +DECLARE_SOA_COLUMN(TofNSigmaPrFromLambda, tofNSigmaPrFromLambda, float); + +} // namespace full + +DECLARE_SOA_TABLE(HfToOmegaKaEvs, "AOD", "HFTOOMEKAEV", + full::IsEventSel8, full::IsEventSelZ); + +DECLARE_SOA_TABLE(HfOmegac0ToOmegaKaLites, "AOD", "HFTOOMEKALITE", + full::XPv, full::YPv, full::ZPv, collision::NumContrib, collision::Chi2, + full::XDecayVtxCharmBaryon, full::YDecayVtxCharmBaryon, full::ZDecayVtxCharmBaryon, + full::XDecayVtxCascade, full::YDecayVtxCascade, full::ZDecayVtxCascade, + full::XDecayVtxV0, full::YDecayVtxV0, full::ZDecayVtxV0, + full::SignDecay, + full::PxCharmBaryon, full::PyCharmBaryon, full::PzCharmBaryon, + full::PxKaFromCharmBaryon, full::PyKaFromCharmBaryon, full::PzKaFromCharmBaryon, + full::PxKaFromCasc, full::PyKaFromCasc, full::PzKaFromCasc, + full::PxPosV0Dau, full::PyPosV0Dau, full::PzPosV0Dau, + full::PxNegV0Dau, full::PyNegV0Dau, full::PzNegV0Dau, + full::ImpactParCascXY, full::ImpactParKaFromCharmBaryonXY, + full::ErrImpactParCascXY, full::ErrImpactParKaFromCharmBaryonXY, + full::InvMassLambda, full::InvMassCascade, full::InvMassCharmBaryon, + full::EtaV0PosDau, full::EtaV0NegDau, full::EtaKaFromCasc, full::EtaKaFromCharmBaryon, + full::DcaXYToPvV0Dau0, full::DcaXYToPvV0Dau1, full::DcaXYToPvCascDau, + full::DcaCascDau, full::DcaV0Dau, full::DcaCharmBaryonDau, + full::ErrorDecayLengthCharmBaryon, full::NormImpParCascade, full::NormImpParKaFromCharmBar, + full::IsKaonGlbTrkWoDca, full::KaonItsNCls, + full::PidTpcInfoStored, full::PidTofInfoStored, + full::TpcNSigmaKaFromCharmBaryon, full::TpcNSigmaKaFromCasc, full::TpcNSigmaPiFromLambda, full::TpcNSigmaPrFromLambda, + full::TofNSigmaKaFromCharmBaryon, full::TofNSigmaKaFromCasc, full::TofNSigmaPiFromLambda, full::TofNSigmaPrFromLambda, + full::FlagMcMatchRec, full::OriginRec, full::CollisionMatched); + +} // namespace o2::aod + +/// Writes the full information in an output TTree +struct HfTreeCreatorOmegac0ToOmegaKa { + + Produces rowCandidateLite; + Produces rowEv; + + Configurable zPvCut{"zPvCut", 10., "Cut on absolute value of primary vertex z coordinate"}; + + using MyTrackTable = soa::Join; + using MyEventTable = soa::Join; + + void init(InitContext const&) + { + } + + template + void fillEvent(const T& collision, float cutZPv) + { + rowEv(collision.sel8(), std::abs(collision.posZ()) < cutZPv); + } + + template + void fillCandidateLite(const T& candidate, int8_t flagMc, int8_t originMc, bool collisionMatched) + { + if (candidate.resultSelections() && candidate.statusPidCharmBaryon() && candidate.statusInvMassLambda() && candidate.statusInvMassCascade() && candidate.statusInvMassCharmBaryon()) { + + rowCandidateLite( + candidate.xPv(), + candidate.yPv(), + candidate.zPv(), + candidate.template collision_as().numContrib(), + candidate.template collision_as().chi2(), + candidate.xDecayVtxCharmBaryon(), + candidate.yDecayVtxCharmBaryon(), + candidate.zDecayVtxCharmBaryon(), + candidate.xDecayVtxCascade(), + candidate.yDecayVtxCascade(), + candidate.zDecayVtxCascade(), + candidate.xDecayVtxV0(), + candidate.yDecayVtxV0(), + candidate.zDecayVtxV0(), + candidate.signDecay(), + candidate.pxCharmBaryon(), + candidate.pyCharmBaryon(), + candidate.pzCharmBaryon(), + candidate.pxBachFromCharmBaryon(), + candidate.pyBachFromCharmBaryon(), + candidate.pzBachFromCharmBaryon(), + candidate.pxBachFromCasc(), + candidate.pyBachFromCasc(), + candidate.pzBachFromCasc(), + candidate.pxPosV0Dau(), + candidate.pyPosV0Dau(), + candidate.pzPosV0Dau(), + candidate.pxNegV0Dau(), + candidate.pyNegV0Dau(), + candidate.pzNegV0Dau(), + candidate.impactParCascXY(), + candidate.impactParBachFromCharmBaryonXY(), + candidate.errImpactParCascXY(), + candidate.errImpactParBachFromCharmBaryonXY(), + candidate.invMassLambda(), + candidate.invMassCascade(), + candidate.invMassCharmBaryon(), + candidate.etaV0PosDau(), + candidate.etaV0NegDau(), + candidate.etaBachFromCasc(), + candidate.etaBachFromCharmBaryon(), + candidate.dcaXYToPvV0Dau0(), + candidate.dcaXYToPvV0Dau1(), + candidate.dcaXYToPvCascDau(), + candidate.dcaCascDau(), + candidate.dcaV0Dau(), + candidate.dcaCharmBaryonDau(), + candidate.errorDecayLengthCharmBaryon(), + candidate.impactParCascXY() / candidate.errImpactParCascXY(), + candidate.impactParBachFromCharmBaryonXY() / candidate.errImpactParBachFromCharmBaryonXY(), + candidate.template bachelorFromCharmBaryon_as().isGlobalTrackWoDCA(), + candidate.template bachelorFromCharmBaryon_as().itsNCls(), + candidate.pidTpcInfoStored(), + candidate.pidTofInfoStored(), + candidate.tpcNSigmaKaFromCharmBaryon(), + candidate.tpcNSigmaKaFromCasc(), + candidate.tpcNSigmaPiFromLambda(), + candidate.tpcNSigmaPrFromLambda(), + candidate.tofNSigmaKaFromCharmBaryon(), + candidate.tofNSigmaKaFromCasc(), + candidate.tofNSigmaPiFromLambda(), + candidate.tofNSigmaPrFromLambda(), + flagMc, + originMc, + collisionMatched); + } + } + + void processDataLite(MyEventTable const& collisions, MyTrackTable const&, + soa::Join const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowCandidateLite.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillCandidateLite(candidate, -7, RecoDecay::OriginType::None, true); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegac0ToOmegaKa, processDataLite, "Process data", true); + + void processMcLite(MyEventTable const& collisions, MyTrackTable const&, + soa::Join const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowCandidateLite.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillCandidateLite(candidate, candidate.flagMcMatchRec(), candidate.originRec(), candidate.collisionMatched()); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegac0ToOmegaKa, processMcLite, "Process MC", false); + +}; // end of struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/treeCreatorOmegacToOmegaPi.cxx b/PWGHF/TableProducer/treeCreatorOmegacToOmegaPi.cxx new file mode 100644 index 00000000000..369b5374f7e --- /dev/null +++ b/PWGHF/TableProducer/treeCreatorOmegacToOmegaPi.cxx @@ -0,0 +1,550 @@ +// 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 treeCreatorOmegacToOmegaPi.cxx +/// \brief Writer of the omegac0 to Omega Pi candidates in the form of flat tables to be stored in TTrees. +/// In this file are defined and filled the output tables +/// +/// \author Federica Zanone , Heidelberg University +/// \author Yunfan Liu , China University of Geosciences +/// \author Fabio Catalano , University of Houston + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/RecoDecay.h" + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace o2::aod +{ +namespace full +{ +// collision info +DECLARE_SOA_COLUMN(IsEventSel8, isEventSel8, bool); +DECLARE_SOA_COLUMN(IsEventSelZ, isEventSelZ, bool); +// from creator +DECLARE_SOA_COLUMN(XPv, xPv, float); +DECLARE_SOA_COLUMN(YPv, yPv, float); +DECLARE_SOA_COLUMN(ZPv, zPv, float); +DECLARE_SOA_COLUMN(XDecayVtxCharmBaryon, xDecayVtxCharmBaryon, float); +DECLARE_SOA_COLUMN(YDecayVtxCharmBaryon, yDecayVtxCharmBaryon, float); +DECLARE_SOA_COLUMN(ZDecayVtxCharmBaryon, zDecayVtxCharmBaryon, float); +DECLARE_SOA_COLUMN(XDecayVtxCascade, xDecayVtxCascade, float); +DECLARE_SOA_COLUMN(YDecayVtxCascade, yDecayVtxCascade, float); +DECLARE_SOA_COLUMN(ZDecayVtxCascade, zDecayVtxCascade, float); +DECLARE_SOA_COLUMN(XDecayVtxV0, xDecayVtxV0, float); +DECLARE_SOA_COLUMN(YDecayVtxV0, yDecayVtxV0, float); +DECLARE_SOA_COLUMN(ZDecayVtxV0, zDecayVtxV0, float); +DECLARE_SOA_COLUMN(SignDecay, signDecay, int8_t); // sign of ka <- omega +DECLARE_SOA_COLUMN(PxCharmBaryon, pxCharmBaryon, float); +DECLARE_SOA_COLUMN(PyCharmBaryon, pyCharmBaryon, float); +DECLARE_SOA_COLUMN(PzCharmBaryon, pzCharmBaryon, float); +DECLARE_SOA_COLUMN(PxPiFromCharmBaryon, pxPiFromCharmBaryon, float); +DECLARE_SOA_COLUMN(PyPiFromCharmBaryon, pyPiFromCharmBaryon, float); +DECLARE_SOA_COLUMN(PzPiFromCharmBaryon, pzPiFromCharmBaryon, float); +DECLARE_SOA_COLUMN(PxKaFromCasc, pxKaFromCasc, float); +DECLARE_SOA_COLUMN(PyKaFromCasc, pyKaFromCasc, float); +DECLARE_SOA_COLUMN(PzKaFromCasc, pzKaFromCasc, float); +DECLARE_SOA_COLUMN(PxPosV0Dau, pxPosV0Dau, float); +DECLARE_SOA_COLUMN(PyPosV0Dau, pyPosV0Dau, float); +DECLARE_SOA_COLUMN(PzPosV0Dau, pzPosV0Dau, float); +DECLARE_SOA_COLUMN(PxNegV0Dau, pxNegV0Dau, float); +DECLARE_SOA_COLUMN(PyNegV0Dau, pyNegV0Dau, float); +DECLARE_SOA_COLUMN(PzNegV0Dau, pzNegV0Dau, float); +DECLARE_SOA_COLUMN(ImpactParCascXY, impactParCascXY, float); +DECLARE_SOA_COLUMN(ImpactParPiFromCharmBaryonXY, impactParPiFromCharmBaryonXY, float); +DECLARE_SOA_COLUMN(ErrImpactParCascXY, errImpactParCascXY, float); +DECLARE_SOA_COLUMN(ErrImpactParPiFromCharmBaryonXY, errImpactParPiFromCharmBaryonXY, float); +DECLARE_SOA_COLUMN(InvMassLambda, invMassLambda, float); +DECLARE_SOA_COLUMN(InvMassCascade, invMassCascade, float); +DECLARE_SOA_COLUMN(InvMassCharmBaryon, invMassCharmBaryon, float); +DECLARE_SOA_COLUMN(EtaV0PosDau, etaV0PosDau, float); +DECLARE_SOA_COLUMN(EtaV0NegDau, etaV0NegDau, float); +DECLARE_SOA_COLUMN(EtaKaFromCasc, etaKaFromCasc, float); +DECLARE_SOA_COLUMN(EtaPiFromCharmBaryon, etaPiFromCharmBaryon, float); +DECLARE_SOA_COLUMN(DcaXYToPvV0Dau0, dcaXYToPvV0Dau0, float); +DECLARE_SOA_COLUMN(DcaXYToPvV0Dau1, dcaXYToPvV0Dau1, float); +DECLARE_SOA_COLUMN(DcaXYToPvCascDau, dcaXYToPvCascDau, float); +DECLARE_SOA_COLUMN(DcaCascDau, dcaCascDau, float); +DECLARE_SOA_COLUMN(DcaV0Dau, dcaV0Dau, float); +DECLARE_SOA_COLUMN(DcaCharmBaryonDau, dcaCharmBaryonDau, float); +DECLARE_SOA_COLUMN(ErrorDecayLengthCharmBaryon, errorDecayLengthCharmBaryon, float); +DECLARE_SOA_COLUMN(NormImpParCascade, normImpParCascade, double); +DECLARE_SOA_COLUMN(NormImpParPiFromCharmBar, normImpParPiFromCharmBar, double); +DECLARE_SOA_COLUMN(IsPionGlbTrkWoDca, isPionGlbTrkWoDca, bool); +DECLARE_SOA_COLUMN(PionItsNCls, pionItsNCls, uint8_t); +// from creator - MC +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level +DECLARE_SOA_COLUMN(OriginRec, originRec, int8_t); +DECLARE_SOA_COLUMN(CollisionMatched, collisionMatched, bool); +// from selector +DECLARE_SOA_COLUMN(PidTpcInfoStored, pidTpcInfoStored, int); +DECLARE_SOA_COLUMN(PidTofInfoStored, pidTofInfoStored, int); +DECLARE_SOA_COLUMN(TpcNSigmaPiFromCharmBaryon, tpcNSigmaPiFromCharmBaryon, float); +DECLARE_SOA_COLUMN(TpcNSigmaKaFromCasc, tpcNSigmaKaFromCasc, float); +DECLARE_SOA_COLUMN(TpcNSigmaPiFromLambda, tpcNSigmaPiFromLambda, float); +DECLARE_SOA_COLUMN(TpcNSigmaPrFromLambda, tpcNSigmaPrFromLambda, float); +DECLARE_SOA_COLUMN(TofNSigmaPiFromCharmBaryon, tofNSigmaPiFromCharmBaryon, float); +DECLARE_SOA_COLUMN(TofNSigmaKaFromCasc, tofNSigmaKaFromCasc, float); +DECLARE_SOA_COLUMN(TofNSigmaPiFromLambda, tofNSigmaPiFromLambda, float); +DECLARE_SOA_COLUMN(TofNSigmaPrFromLambda, tofNSigmaPrFromLambda, float); +// from creator KF +DECLARE_SOA_COLUMN(NSigmaTPCPiFromOmegac, nSigmaTPCPiFromOmegac, float); +DECLARE_SOA_COLUMN(NSigmaTOFPiFromOmegac, nSigmaTOFPiFromOmegac, float); +DECLARE_SOA_COLUMN(NSigmaTPCKaFromCasc, nSigmaTPCKaFromCasc, float); +DECLARE_SOA_COLUMN(NSigmaTOFKaFromCasc, nSigmaTOFKaFromCasc, float); +DECLARE_SOA_COLUMN(NSigmaTPCPiFromV0, nSigmaTPCPiFromV0, float); +DECLARE_SOA_COLUMN(NSigmaTPCPrFromV0, nSigmaTPCPrFromV0, float); +DECLARE_SOA_COLUMN(KfDcaXYPiFromOmegac, kfDcaXYPiFromOmegac, float); +DECLARE_SOA_COLUMN(KfDcaXYCascToPv, kfDcaXYCascToPv, float); +DECLARE_SOA_COLUMN(Chi2GeoV0, chi2GeoV0, float); +DECLARE_SOA_COLUMN(Chi2GeoCasc, chi2GeoCasc, float); +DECLARE_SOA_COLUMN(Chi2GeoOmegac, chi2GeoOmegac, float); +DECLARE_SOA_COLUMN(Chi2MassV0, chi2MassV0, float); +DECLARE_SOA_COLUMN(Chi2MassCasc, chi2MassCasc, float); +DECLARE_SOA_COLUMN(V0ldl, v0ldl, float); +DECLARE_SOA_COLUMN(Cascldl, cascldl, float); +DECLARE_SOA_COLUMN(Omegacldl, omegacldl, float); +DECLARE_SOA_COLUMN(Chi2TopoV0ToPv, chi2TopoV0ToPv, float); +DECLARE_SOA_COLUMN(Chi2TopoCascToPv, chi2TopoCascToPv, float); +DECLARE_SOA_COLUMN(Chi2TopoPiFromOmegacToPv, chi2TopoPiFromOmegacToPv, float); +DECLARE_SOA_COLUMN(Chi2TopoOmegacToPv, chi2TopoOmegacToPv, float); +DECLARE_SOA_COLUMN(DeviationPiFromOmegacToPv, deviationPiFromOmegacToPv, float); +DECLARE_SOA_COLUMN(Chi2TopoV0ToCasc, chi2TopoV0ToCasc, float); +DECLARE_SOA_COLUMN(Chi2TopoCascToOmegac, chi2TopoCascToOmegac, float); +DECLARE_SOA_COLUMN(DecayLenXYLambda, decayLenXYLambda, float); +DECLARE_SOA_COLUMN(DecayLenXYCasc, decayLenXYCasc, float); +DECLARE_SOA_COLUMN(DecayLenXYOmegac, decayLenXYOmegac, float); +DECLARE_SOA_COLUMN(CosPaV0ToCasc, cosPaV0ToCasc, float); +DECLARE_SOA_COLUMN(CosPaV0ToPv, cosPaV0ToPv, float); +DECLARE_SOA_COLUMN(CosPaCascToOmegac, cosPaCascToOmegac, float); +DECLARE_SOA_COLUMN(CosPaCascToPv, cosPaCascToPv, float); +DECLARE_SOA_COLUMN(CosPaOmegacToPv, cosPaOmegacToPv, float); +DECLARE_SOA_COLUMN(KfRapOmegac, kfRapOmegac, float); +DECLARE_SOA_COLUMN(KfptPiFromOmegac, kfptPiFromOmegac, float); +DECLARE_SOA_COLUMN(KfptOmegac, kfptOmegac, float); +DECLARE_SOA_COLUMN(CosThetaStarPiFromOmegac, cosThetaStarPiFromOmegac, float); +DECLARE_SOA_COLUMN(CtOmegac, ctOmegac, float); +DECLARE_SOA_COLUMN(EtaOmegac, etaOmegac, float); +DECLARE_SOA_COLUMN(V0Ndf, v0Ndf, float); +DECLARE_SOA_COLUMN(CascNdf, cascNdf, float); +DECLARE_SOA_COLUMN(OmegacNdf, omegacNdf, float); +DECLARE_SOA_COLUMN(MassV0Ndf, massV0Ndf, float); +DECLARE_SOA_COLUMN(MassCascNdf, massCascNdf, float); +DECLARE_SOA_COLUMN(V0Chi2OverNdf, v0Chi2OverNdf, float); +DECLARE_SOA_COLUMN(CascChi2OverNdf, cascChi2OverNdf, float); +DECLARE_SOA_COLUMN(OmegacChi2OverNdf, omegacChi2OverNdf, float); +DECLARE_SOA_COLUMN(MassV0Chi2OverNdf, massV0Chi2OverNdf, float); +DECLARE_SOA_COLUMN(MassCascChi2OverNdf, massCascChi2OverNdf, float); +DECLARE_SOA_COLUMN(CascRejectInvmass, cascRejectInvmass, float); +} // namespace full + +DECLARE_SOA_TABLE(HfToOmegaPiEvs, "AOD", "HFTOOMEPIEV", + full::IsEventSel8, full::IsEventSelZ); + +DECLARE_SOA_TABLE(HfOmegac0ToOmegaPiLites, "AOD", "HFTOOMEPILITE", + full::XPv, full::YPv, full::ZPv, collision::NumContrib, collision::Chi2, + full::XDecayVtxCharmBaryon, full::YDecayVtxCharmBaryon, full::ZDecayVtxCharmBaryon, + full::XDecayVtxCascade, full::YDecayVtxCascade, full::ZDecayVtxCascade, + full::XDecayVtxV0, full::YDecayVtxV0, full::ZDecayVtxV0, + full::SignDecay, + full::PxCharmBaryon, full::PyCharmBaryon, full::PzCharmBaryon, + full::PxPiFromCharmBaryon, full::PyPiFromCharmBaryon, full::PzPiFromCharmBaryon, + full::PxKaFromCasc, full::PyKaFromCasc, full::PzKaFromCasc, + full::PxPosV0Dau, full::PyPosV0Dau, full::PzPosV0Dau, + full::PxNegV0Dau, full::PyNegV0Dau, full::PzNegV0Dau, + full::ImpactParCascXY, full::ImpactParPiFromCharmBaryonXY, + full::ErrImpactParCascXY, full::ErrImpactParPiFromCharmBaryonXY, + full::InvMassLambda, full::InvMassCascade, full::InvMassCharmBaryon, + full::EtaV0PosDau, full::EtaV0NegDau, full::EtaKaFromCasc, full::EtaPiFromCharmBaryon, + full::DcaXYToPvV0Dau0, full::DcaXYToPvV0Dau1, full::DcaXYToPvCascDau, + full::DcaCascDau, full::DcaV0Dau, full::DcaCharmBaryonDau, + full::ErrorDecayLengthCharmBaryon, full::NormImpParCascade, full::NormImpParPiFromCharmBar, + full::IsPionGlbTrkWoDca, full::PionItsNCls, + full::PidTpcInfoStored, full::PidTofInfoStored, + full::TpcNSigmaPiFromCharmBaryon, full::TpcNSigmaKaFromCasc, full::TpcNSigmaPiFromLambda, full::TpcNSigmaPrFromLambda, + full::TofNSigmaPiFromCharmBaryon, full::TofNSigmaKaFromCasc, full::TofNSigmaPiFromLambda, full::TofNSigmaPrFromLambda, + full::FlagMcMatchRec, full::OriginRec, full::CollisionMatched, hf_track_index::HFflag); + +DECLARE_SOA_TABLE(HfKfOmegacFulls, "AOD", "HFKFOMEGACFULL", + full::NSigmaTPCPiFromOmegac, full::NSigmaTOFPiFromOmegac, full::NSigmaTPCKaFromCasc, full::NSigmaTOFKaFromCasc, + full::NSigmaTPCPiFromV0, full::NSigmaTPCPrFromV0, + full::KfDcaXYPiFromOmegac, full::DcaCascDau, full::DcaCharmBaryonDau, full::KfDcaXYCascToPv, + full::DcaXYToPvV0Dau0, full::DcaXYToPvV0Dau1, full::DcaXYToPvCascDau, + full::Chi2GeoV0, full::Chi2GeoCasc, full::Chi2GeoOmegac, + full::Chi2MassV0, full::Chi2MassCasc, + full::V0ldl, full::Cascldl, full::Omegacldl, + full::Chi2TopoV0ToPv, full::Chi2TopoCascToPv, full::Chi2TopoPiFromOmegacToPv, full::Chi2TopoOmegacToPv, full::DeviationPiFromOmegacToPv, + full::Chi2TopoV0ToCasc, full::Chi2TopoCascToOmegac, + full::DecayLenXYLambda, full::DecayLenXYCasc, full::DecayLenXYOmegac, + full::CosPaV0ToCasc, full::CosPaV0ToPv, full::CosPaCascToOmegac, full::CosPaCascToPv, full::CosPaOmegacToPv, + full::InvMassLambda, full::InvMassCascade, full::InvMassCharmBaryon, + full::KfRapOmegac, full::KfptPiFromOmegac, full::KfptOmegac, + full::CosThetaStarPiFromOmegac, full::CtOmegac, full::EtaOmegac, + full::V0Ndf, full::CascNdf, full::OmegacNdf, + full::MassV0Ndf, full::MassCascNdf, + full::V0Chi2OverNdf, full::CascChi2OverNdf, full::OmegacChi2OverNdf, + full::MassV0Chi2OverNdf, full::MassCascChi2OverNdf, full::CascRejectInvmass, + full::FlagMcMatchRec, full::OriginRec, full::CollisionMatched, hf_track_index::HFflag); + +DECLARE_SOA_TABLE(HfKfOmegacLites, "AOD", "HFKFOMEGACLITE", + full::NSigmaTPCPiFromOmegac, full::NSigmaTOFPiFromOmegac, full::NSigmaTPCKaFromCasc, full::NSigmaTOFKaFromCasc, + full::NSigmaTPCPiFromV0, full::NSigmaTPCPrFromV0, + full::KfDcaXYPiFromOmegac, full::DcaCharmBaryonDau, full::KfDcaXYCascToPv, full::DcaCascDau, + full::V0ldl, full::Cascldl, full::Omegacldl, full::Chi2TopoPiFromOmegacToPv, full::Chi2TopoOmegacToPv, full::DeviationPiFromOmegacToPv, + full::DecayLenXYOmegac, + full::CosPaCascToPv, full::CosPaOmegacToPv, + full::InvMassCascade, full::InvMassCharmBaryon, + full::KfptPiFromOmegac, full::KfptOmegac, + full::CosThetaStarPiFromOmegac, full::CtOmegac, full::EtaOmegac, + full::V0Chi2OverNdf, full::CascChi2OverNdf, full::OmegacChi2OverNdf, + full::CascRejectInvmass, + full::FlagMcMatchRec, full::OriginRec, full::CollisionMatched, hf_track_index::HFflag); +} // namespace o2::aod + +/// Writes the full information in an output TTree +struct HfTreeCreatorOmegacToOmegaPi { + + Produces rowCandidateLite; + Produces rowKfCandidateFull; + Produces rowKfCandidateLite; + Produces rowEv; + + Configurable zPvCut{"zPvCut", 10., "Cut on absolute value of primary vertex z coordinate"}; + Configurable keepOnlyMcSignal{"keepOnlyMcSignal", true, "Fill MC tree only with signal candidates"}; + + using Tracks = soa::Join; + using Colls = soa::Join; + using CandKfSel = soa::Filtered>; + using CascKfMcSel = soa::Filtered>; + + Filter filterOmegaCToOmegaPiFlag = (o2::aod::hf_track_index::hfflag & static_cast(BIT(aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi))) != static_cast(0); + + void init(InitContext const&) + { + } + + template + void fillEvent(const T& collision, float cutZPv) + { + rowEv(collision.sel8(), std::abs(collision.posZ()) < cutZPv); + } + + template + void fillCandidateLite(const T& candidate, int8_t flagMc, int8_t originMc, bool collisionMatched) + { + if (candidate.resultSelections() && candidate.statusPidCharmBaryon() && candidate.statusInvMassLambda() && candidate.statusInvMassCascade() && candidate.statusInvMassCharmBaryon()) { + + rowCandidateLite( + candidate.xPv(), + candidate.yPv(), + candidate.zPv(), + candidate.template collision_as().numContrib(), + candidate.template collision_as().chi2(), + candidate.xDecayVtxCharmBaryon(), + candidate.yDecayVtxCharmBaryon(), + candidate.zDecayVtxCharmBaryon(), + candidate.xDecayVtxCascade(), + candidate.yDecayVtxCascade(), + candidate.zDecayVtxCascade(), + candidate.xDecayVtxV0(), + candidate.yDecayVtxV0(), + candidate.zDecayVtxV0(), + candidate.signDecay(), + candidate.pxCharmBaryon(), + candidate.pyCharmBaryon(), + candidate.pzCharmBaryon(), + candidate.pxBachFromCharmBaryon(), + candidate.pyBachFromCharmBaryon(), + candidate.pzBachFromCharmBaryon(), + candidate.pxBachFromCasc(), + candidate.pyBachFromCasc(), + candidate.pzBachFromCasc(), + candidate.pxPosV0Dau(), + candidate.pyPosV0Dau(), + candidate.pzPosV0Dau(), + candidate.pxNegV0Dau(), + candidate.pyNegV0Dau(), + candidate.pzNegV0Dau(), + candidate.impactParCascXY(), + candidate.impactParBachFromCharmBaryonXY(), + candidate.errImpactParCascXY(), + candidate.errImpactParBachFromCharmBaryonXY(), + candidate.invMassLambda(), + candidate.invMassCascade(), + candidate.invMassCharmBaryon(), + candidate.etaV0PosDau(), + candidate.etaV0NegDau(), + candidate.etaBachFromCasc(), + candidate.etaBachFromCharmBaryon(), + candidate.dcaXYToPvV0Dau0(), + candidate.dcaXYToPvV0Dau1(), + candidate.dcaXYToPvCascDau(), + candidate.dcaCascDau(), + candidate.dcaV0Dau(), + candidate.dcaCharmBaryonDau(), + candidate.errorDecayLengthCharmBaryon(), + candidate.impactParCascXY() / candidate.errImpactParCascXY(), + candidate.impactParBachFromCharmBaryonXY() / candidate.errImpactParBachFromCharmBaryonXY(), + candidate.template bachelorFromCharmBaryon_as().isGlobalTrackWoDCA(), + candidate.template bachelorFromCharmBaryon_as().itsNCls(), + candidate.pidTpcInfoStored(), + candidate.pidTofInfoStored(), + candidate.tpcNSigmaPiFromCharmBaryon(), + candidate.tpcNSigmaKaFromCasc(), + candidate.tpcNSigmaPiFromLambda(), + candidate.tpcNSigmaPrFromLambda(), + candidate.tofNSigmaPiFromCharmBaryon(), + candidate.tofNSigmaKaFromCasc(), + candidate.tofNSigmaPiFromLambda(), + candidate.tofNSigmaPrFromLambda(), + flagMc, + originMc, + collisionMatched, + candidate.hfflag()); + } + } + + template + void fillKfCandidate(const T& candidate, int8_t flagMc, int8_t originMc, bool collisionMatched) + { + if (candidate.resultSelections() && candidate.statusPidCharmBaryon() && candidate.statusInvMassLambda() && candidate.statusInvMassCascade() && candidate.statusInvMassCharmBaryon()) { + + rowKfCandidateFull( + candidate.tpcNSigmaPiFromCharmBaryon(), + candidate.tofNSigmaPiFromCharmBaryon(), + candidate.tpcNSigmaKaFromCasc(), + candidate.tofNSigmaKaFromCasc(), + candidate.tpcNSigmaPiFromLambda(), + candidate.tpcNSigmaPrFromLambda(), + candidate.kfDcaXYPiFromOmegac(), + candidate.dcaCascDau(), + candidate.dcaCharmBaryonDau(), + candidate.kfDcaXYCascToPv(), + candidate.dcaXYToPvV0Dau0(), + candidate.dcaXYToPvV0Dau1(), + candidate.dcaXYToPvCascDau(), + candidate.chi2GeoV0(), + candidate.chi2GeoCasc(), + candidate.chi2GeoOmegac(), + candidate.chi2MassV0(), + candidate.chi2MassCasc(), + candidate.v0ldl(), + candidate.cascldl(), + candidate.omegacldl(), + candidate.chi2TopoV0ToPv(), + candidate.chi2TopoCascToPv(), + candidate.chi2TopoPiFromOmegacToPv(), + candidate.chi2TopoOmegacToPv(), + candidate.deviationPiFromOmegacToPv(), + candidate.chi2TopoV0ToCasc(), + candidate.chi2TopoCascToOmegac(), + candidate.decayLenXYLambda(), + candidate.decayLenXYCasc(), + candidate.decayLenXYOmegac(), + candidate.cosPaV0ToCasc(), + candidate.cosPAV0(), + candidate.cosPaCascToOmegac(), + candidate.cosPACasc(), + candidate.cosPACharmBaryon(), + candidate.invMassLambda(), + candidate.invMassCascade(), + candidate.invMassCharmBaryon(), + candidate.kfRapOmegac(), + candidate.kfptPiFromOmegac(), + candidate.kfptOmegac(), + candidate.cosThetaStarPiFromOmegac(), + candidate.cTauOmegac(), + candidate.etaCharmBaryon(), + candidate.v0Ndf(), + candidate.cascNdf(), + candidate.omegacNdf(), + candidate.massV0Ndf(), + candidate.massCascNdf(), + candidate.v0Chi2OverNdf(), + candidate.cascChi2OverNdf(), + candidate.omegacChi2OverNdf(), + candidate.massV0Chi2OverNdf(), + candidate.massCascChi2OverNdf(), + candidate.cascRejectInvmass(), + flagMc, + originMc, + collisionMatched, + candidate.hfflag()); + } + } + + template + void fillKfCandidateLite(const T& candidate, int8_t flagMc, int8_t originMc, bool collisionMatched) + { + if (candidate.resultSelections() && candidate.statusPidCharmBaryon() && candidate.statusInvMassLambda() && candidate.statusInvMassCascade() && candidate.statusInvMassCharmBaryon()) { + + rowKfCandidateLite( + candidate.tpcNSigmaPiFromCharmBaryon(), + candidate.tofNSigmaPiFromCharmBaryon(), + candidate.tpcNSigmaKaFromCasc(), + candidate.tofNSigmaKaFromCasc(), + candidate.tpcNSigmaPiFromLambda(), + candidate.tpcNSigmaPrFromLambda(), + candidate.kfDcaXYPiFromOmegac(), + candidate.dcaCharmBaryonDau(), + candidate.kfDcaXYCascToPv(), + candidate.dcaCascDau(), + candidate.v0ldl(), + candidate.cascldl(), + candidate.omegacldl(), + candidate.chi2TopoPiFromOmegacToPv(), + candidate.chi2TopoOmegacToPv(), + candidate.deviationPiFromOmegacToPv(), + candidate.decayLenXYOmegac(), + candidate.cosPACasc(), + candidate.cosPACharmBaryon(), + candidate.invMassCascade(), + candidate.invMassCharmBaryon(), + candidate.kfptPiFromOmegac(), + candidate.kfptOmegac(), + candidate.cosThetaStarPiFromOmegac(), + candidate.cTauOmegac(), + candidate.etaCharmBaryon(), + candidate.v0Chi2OverNdf(), + candidate.cascChi2OverNdf(), + candidate.omegacChi2OverNdf(), + candidate.cascRejectInvmass(), + flagMc, + originMc, + collisionMatched, + candidate.hfflag()); + } + } // fillKfCandidateLite end + + void processDataLite(Colls const& collisions, Tracks const&, + soa::Filtered> const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowCandidateLite.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillCandidateLite(candidate, -7, RecoDecay::OriginType::None, false); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegacToOmegaPi, processDataLite, "Process data", true); + + void processKfDataFull(Colls const& collisions, Tracks const&, CandKfSel const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowKfCandidateFull.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillKfCandidate(candidate, -7, RecoDecay::OriginType::None, false); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegacToOmegaPi, processKfDataFull, "Process KF data", false); + + void processKfDataLite(Colls const& collisions, Tracks const&, CandKfSel const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowKfCandidateFull.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillKfCandidateLite(candidate, -7, RecoDecay::OriginType::None, false); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegacToOmegaPi, processKfDataLite, "Process KF data Lite", false); + + void processMcLite(Colls const& collisions, Tracks const&, + soa::Filtered> const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowCandidateLite.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillCandidateLite(candidate, candidate.flagMcMatchRec(), candidate.originRec(), candidate.collisionMatched()); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegacToOmegaPi, processMcLite, "Process MC", false); + + void processKFMcFull(Colls const& collisions, Tracks const&, CascKfMcSel const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowCandidateLite.reserve(candidates.size()); + for (const auto& candidate : candidates) { + if (keepOnlyMcSignal) { + if (candidate.originRec() != 0) { + fillKfCandidate(candidate, candidate.flagMcMatchRec(), candidate.originRec(), candidate.collisionMatched()); + } + } else { + fillKfCandidate(candidate, candidate.flagMcMatchRec(), candidate.originRec(), candidate.collisionMatched()); + } + } + } + PROCESS_SWITCH(HfTreeCreatorOmegacToOmegaPi, processKFMcFull, "Process KF MC", false); + + void processKFMcLite(Colls const& collisions, Tracks const&, CascKfMcSel const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowCandidateLite.reserve(candidates.size()); + for (const auto& candidate : candidates) { + if (keepOnlyMcSignal) { + if (candidate.originRec() != 0) { + fillKfCandidateLite(candidate, candidate.flagMcMatchRec(), candidate.originRec(), candidate.collisionMatched()); + } + } else { + fillKfCandidateLite(candidate, candidate.flagMcMatchRec(), candidate.originRec(), candidate.collisionMatched()); + } + } + } + PROCESS_SWITCH(HfTreeCreatorOmegacToOmegaPi, processKFMcLite, "Process KF MC Lite", false); + +}; // end of struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/treeCreatorTccToD0D0Pi.cxx b/PWGHF/TableProducer/treeCreatorTccToD0D0Pi.cxx new file mode 100644 index 00000000000..75526481a29 --- /dev/null +++ b/PWGHF/TableProducer/treeCreatorTccToD0D0Pi.cxx @@ -0,0 +1,474 @@ +// 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 treeCreatorTccToD0D0Pi.cxx +/// \brief tree creator for studying the charm exotic state Tcc to D0D0pi +/// \author Biao Zhang , Heidelberg University +/// \author Fabrizio Grosa , CERN + +#include +#include +#include +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/DCA.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/Core/TrackSelectionDefaults.h" + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/Utils/utilsTrkCandHf.h" +#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" + +using namespace o2; +using namespace o2::analysis; +using namespace o2::constants::physics; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::hf_trkcandsel; + +namespace o2::aod +{ +namespace full +{ +DECLARE_SOA_INDEX_COLUMN(Collision, collision); +DECLARE_SOA_COLUMN(PtD1, ptD1, float); +DECLARE_SOA_COLUMN(PtD2, ptD2, float); +DECLARE_SOA_COLUMN(PtPi, ptPi, float); +DECLARE_SOA_COLUMN(PxProng0D1, pxProng0D1, float); +DECLARE_SOA_COLUMN(PxProng1D1, pxProng1D1, float); +DECLARE_SOA_COLUMN(PyProng0D1, pyProng0D1, float); +DECLARE_SOA_COLUMN(PyProng1D1, pyProng1D1, float); +DECLARE_SOA_COLUMN(PzProng0D1, pzProng0D1, float); +DECLARE_SOA_COLUMN(PzProng1D1, pzProng1D1, float); +DECLARE_SOA_COLUMN(PxProng0D2, pxProng0D2, float); +DECLARE_SOA_COLUMN(PxProng1D2, pxProng1D2, float); +DECLARE_SOA_COLUMN(PyProng0D2, pyProng0D2, float); +DECLARE_SOA_COLUMN(PyProng1D2, pyProng1D2, float); +DECLARE_SOA_COLUMN(PzProng0D2, pzProng0D2, float); +DECLARE_SOA_COLUMN(PzProng1D2, pzProng1D2, float); +DECLARE_SOA_COLUMN(PxSoftPi, pxSoftPi, float); +DECLARE_SOA_COLUMN(PySoftPi, pySoftPi, float); +DECLARE_SOA_COLUMN(PzSoftPi, pzSoftPi, float); +DECLARE_SOA_COLUMN(SelFlagD1, selFlagD1, int8_t); +DECLARE_SOA_COLUMN(SelFlagD2, selFlagD2, int8_t); +DECLARE_SOA_COLUMN(MD1, mD1, float); +DECLARE_SOA_COLUMN(MD2, mD2, float); +DECLARE_SOA_COLUMN(DeltaMD1, deltaMD1, float); +DECLARE_SOA_COLUMN(DeltaMD2, deltaMD2, float); +DECLARE_SOA_COLUMN(MDD, mDD, float); +DECLARE_SOA_COLUMN(MDPi1, mDPi1, float); +DECLARE_SOA_COLUMN(MDPi2, mDPi2, float); +DECLARE_SOA_COLUMN(MDDPi, mDDPi, float); +DECLARE_SOA_COLUMN(DeltaMDDPi, deltaMDDPi, float); +DECLARE_SOA_COLUMN(EtaD1, etaD1, float); +DECLARE_SOA_COLUMN(EtaD2, etaD2, float); +DECLARE_SOA_COLUMN(EtaSoftPi, etaSoftPi, float); +DECLARE_SOA_COLUMN(PhiD1, phiD1, float); +DECLARE_SOA_COLUMN(PhiD2, phiD2, float); +DECLARE_SOA_COLUMN(PhiSoftPi, phiSoftPi, float); +DECLARE_SOA_COLUMN(YD1, yD1, float); +DECLARE_SOA_COLUMN(YD2, yD2, float); +DECLARE_SOA_COLUMN(YSoftPi, ySoftPi, float); +DECLARE_SOA_COLUMN(NSigTpcSoftPi, nSigTpcSoftPi, float); +DECLARE_SOA_COLUMN(NSigTofSoftPi, nSigTofSoftPi, float); +DECLARE_SOA_COLUMN(MlScoreD1, mlScoreD1, float); +DECLARE_SOA_COLUMN(MlScoreD2, mlScoreD2, float); +DECLARE_SOA_COLUMN(DecayLengthD1, decayLengthD1, float); +DECLARE_SOA_COLUMN(DecayLengthD2, decayLengthD2, float); +DECLARE_SOA_COLUMN(CpaD1, cpaD1, float); +DECLARE_SOA_COLUMN(CpaD2, cpaD2, float); +DECLARE_SOA_COLUMN(SignSoftPi, signSoftPi, float); +DECLARE_SOA_COLUMN(DcaXYSoftPi, dcaXYSoftPi, float); +DECLARE_SOA_COLUMN(DcaZSoftPi, dcaZSoftPi, float); +DECLARE_SOA_COLUMN(NITSClsSoftPi, nITSClsSoftPi, float); +DECLARE_SOA_COLUMN(NTPCClsCrossedRowsSoftPi, nTPCClsCrossedRowsSoftPi, float); +DECLARE_SOA_COLUMN(NTPCChi2NClSoftPi, nTPCChi2NClSoftPi, float); +DECLARE_SOA_COLUMN(CentOfCand, centOfCand, float); +// Events +DECLARE_SOA_COLUMN(IsEventReject, isEventReject, int); +DECLARE_SOA_COLUMN(RunNumber, runNumber, int); +} // namespace full + +DECLARE_SOA_TABLE(HfCandTccLites, "AOD", "HFCANDTCCLITE", + full::PtD1, + full::PtD2, + full::PtPi, + full::PxProng0D1, + full::PxProng1D1, + full::PyProng0D1, + full::PyProng1D1, + full::PzProng0D1, + full::PzProng1D1, + full::PxProng0D2, + full::PxProng1D2, + full::PyProng0D2, + full::PyProng1D2, + full::PzProng0D2, + full::PzProng1D2, + full::PxSoftPi, + full::PySoftPi, + full::PzSoftPi, + full::SelFlagD1, + full::SelFlagD2, + full::MD1, + full::MD2, + full::DeltaMD1, + full::DeltaMD2, + full::MDD, + full::MDPi1, + full::MDPi2, + full::MDDPi, + full::DeltaMDDPi, + full::EtaD1, + full::EtaD2, + full::EtaSoftPi, + full::PhiD1, + full::PhiD2, + full::PhiSoftPi, + full::YD1, + full::YD2, + full::YSoftPi, + full::NSigTpcSoftPi, + full::NSigTofSoftPi, + full::MlScoreD1, + full::MlScoreD2, + full::DecayLengthD1, + full::DecayLengthD2, + full::CpaD1, + full::CpaD2, + full::SignSoftPi, + full::DcaXYSoftPi, + full::DcaZSoftPi, + full::NITSClsSoftPi, + full::NTPCClsCrossedRowsSoftPi, + full::NTPCChi2NClSoftPi, + full::CentOfCand); + +DECLARE_SOA_TABLE(HfCandTccFullEvs, "AOD", "HFCANDTCCFULLEV", + full::CollisionId, + collision::NumContrib, + collision::PosX, + collision::PosY, + collision::PosZ, + full::IsEventReject, + full::RunNumber); +} // namespace o2::aod + +/// Writes the full information in an output TTree +struct HfTreeCreatorTccToD0D0Pi { + Produces rowCandidateLite; + Produces rowCandidateFullEvents; + + Configurable ptMinSoftPion{"ptMinSoftPion", 0.0, "Min pt for the soft pion"}; + Configurable usePionIsGlobalTrackWoDCA{"usePionIsGlobalTrackWoDCA", true, "check isGlobalTrackWoDCA status for pions"}; + + // Configurable softPiEtaMax{"softPiEtaMax", 0.9f, "Soft pion max value for pseudorapidity (abs vale)"}; + // Configurable softPiChi2Max{"softPiChi2Max", 36.f, "Soft pion max value for chi2 ITS"}; + // Configurable softPiItsHitMap{"softPiItsHitMap", 127, "Soft pion ITS hitmap"}; + // Configurable softPiItsHitsMin{"softPiItsHitsMin", 1, "Minimum number of ITS layers crossed by the soft pion among those in \"softPiItsHitMap\""}; + Configurable softPiDcaXYMax{"softPiDcaXYMax", 0.065, "Soft pion max dcaXY (cm)"}; + Configurable softPiDcaZMax{"softPiDcaZMax", 0.065, "Soft pion max dcaZ (cm)"}; + Configurable deltaMassCanMax{"deltaMassCanMax", 2, "delta candidate max mass (DDPi-D0D0) ((GeV/c2)"}; + Configurable massCanMax{"massCanMax", 4.0, "candidate max mass (DDPi) ((GeV/c2)"}; + + HfHelper hfHelper; + + using TracksPid = soa::Join; + using TracksWPid = soa::Join; + + using Collisions = soa::Join; + using CollisionsWithFT0C = soa::Join; + using CollisionsWithFT0M = soa::Join; + + using SelectedCandidatesMl = soa::Filtered>; + + Filter filterSelectCandidates = aod::hf_sel_candidate_d0::isSelD0 >= 1 || aod::hf_sel_candidate_d0::isSelD0bar >= 1; + + Preslice candsD0PerCollisionWithMl = aod::track_association::collisionId; + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + // Partition candidatesMlAll = aod::hf_sel_candidate_d0::isSelD0 >= 0; + + void init(InitContext const&) + { + + std::array doprocess{doprocessDataWithMl, doprocessDataWithMlWithFT0C, doprocessDataWithMlWithFT0M}; + if (std::accumulate(doprocess.begin(), doprocess.end(), 0) != 1) { + LOGP(fatal, "Only one process function can be enabled at a time."); + } + } + + template + void fillEvent(const T& collision, int isEventReject, int runNumber) + { + rowCandidateFullEvents( + collision.globalIndex(), + collision.numContrib(), + collision.posX(), + collision.posY(), + collision.posZ(), + isEventReject, + runNumber); + } + + /// Evaluate centrality/multiplicity percentile (centrality estimator is automatically selected based on the used table) + /// \param candidate is candidate + /// \return centrality/multiplicity percentile of the collision + template + float evaluateCentralityColl(const Coll& collision) + { + return o2::hf_centrality::getCentralityColl(collision); + } + + template + void runCandCreatorData(CollType const& collision, + CandType const& candidates, + aod::TrackAssoc const& trackIndices, + TrkType const& track, aod::BCs const&) + { + for (const auto& candidateD1 : candidates) { + for (auto candidateD2 = candidateD1 + 1; candidateD2 != candidates.end(); ++candidateD2) { + for (const auto& trackId : trackIndices) { + auto trackPion = trackId.template track_as(); + if (usePionIsGlobalTrackWoDCA && !trackPion.isGlobalTrackWoDCA()) { + continue; + } + // minimum pT selection + if (trackPion.pt() < ptMinSoftPion) { + continue; + } + if (std::abs(trackPion.dcaXY()) > softPiDcaXYMax || std::abs(trackPion.dcaZ()) > softPiDcaZMax) { + continue; + } + // avoid shared tracks + if ( + (candidateD1.prong0Id() == candidateD2.prong0Id()) || + (candidateD1.prong0Id() == candidateD2.prong1Id()) || + (candidateD1.prong1Id() == candidateD2.prong0Id()) || + (candidateD1.prong1Id() == candidateD2.prong1Id()) || + (candidateD1.prong0Id() == trackPion.globalIndex()) || + (candidateD1.prong1Id() == trackPion.globalIndex()) || + (candidateD2.prong0Id() == trackPion.globalIndex()) || + (candidateD2.prong1Id() == trackPion.globalIndex())) { + continue; + } + // Retrieve properties of the two D0 candidates + float yD1 = hfHelper.yD0(candidateD1); + float yD2 = hfHelper.yD0(candidateD2); + float massD01 = -999; + float massD02 = -999; + float deltaMassD01 = -999; + float deltaMassD02 = -999; + int candFlagD1 = -999; + int candFlagD2 = -999; + float cent = evaluateCentralityColl(collision); + + std::vector mlScoresD1; + std::vector mlScoresD2; + + if (candidateD1.isSelD0()) { + candFlagD1 = (candidateD1.isSelD0bar()) ? 3 : 1; + std::copy(candidateD1.mlProbD0().begin(), candidateD1.mlProbD0().end(), std::back_inserter(mlScoresD1)); + massD01 = hfHelper.invMassD0ToPiK(candidateD1); + } + if (candidateD1.isSelD0bar()) { + candFlagD1 = 2; + std::copy(candidateD1.mlProbD0bar().begin(), candidateD1.mlProbD0bar().end(), std::back_inserter(mlScoresD1)); + massD01 = hfHelper.invMassD0barToKPi(candidateD1); + } + + if (candidateD2.isSelD0()) { + candFlagD2 = (candidateD2.isSelD0bar()) ? 3 : 1; + std::copy(candidateD2.mlProbD0().begin(), candidateD2.mlProbD0().end(), std::back_inserter(mlScoresD2)); + massD02 = hfHelper.invMassD0ToPiK(candidateD2); + } + if (candidateD2.isSelD0bar()) { + candFlagD2 = 2; + std::copy(candidateD2.mlProbD0bar().begin(), candidateD2.mlProbD0bar().end(), std::back_inserter(mlScoresD2)); + massD02 = hfHelper.invMassD0barToKPi(candidateD2); + } + + // LOG(info) << " candidateD1.collisionId() " << candidateD1.collisionId()<<" massD01 "< pVecPosD1Dau{trackPosD1Dau.pVector()}; + std::array pVecNegD1Dau{trackNegD1Dau.pVector()}; + std::array pVecPosD2Dau{trackPosD2Dau.pVector()}; + std::array pVecNegD2Dau{trackNegD2Dau.pVector()}; + std::array pVecSoftPion = {trackPion.pVector()}; + std::array massD1Daus{MassPiPlus, MassKPlus}; + std::array massD2Daus{MassPiPlus, MassKPlus}; + + if (candidateD1.isSelD0bar()) { + + massD1Daus[0] = MassKPlus; + massD1Daus[1] = MassPiPlus; + } + if (candidateD2.isSelD0bar()) { + massD2Daus[0] = MassKPlus; + massD2Daus[1] = MassPiPlus; + } + + auto massKpipi1 = RecoDecay::m(std::array{pVecPosD1Dau, pVecNegD1Dau, pVecSoftPion}, std::array{massD1Daus[0], massD1Daus[1], MassPiPlus}); + auto massKpipi2 = RecoDecay::m(std::array{pVecPosD2Dau, pVecNegD2Dau, pVecSoftPion}, std::array{massD2Daus[0], massD2Daus[1], MassPiPlus}); + + deltaMassD01 = massKpipi1 - massD01; + deltaMassD02 = massKpipi2 - massD02; + + std::array pVecD1{candidateD1.px(), candidateD1.py(), candidateD1.pz()}; + std::array pVecD2{candidateD2.px(), candidateD2.py(), candidateD2.pz()}; + auto arrayMomentaDDpi = std::array{pVecD1, pVecD2, pVecSoftPion}; + const auto massD0D0Pi = RecoDecay::m(std::move(arrayMomentaDDpi), std::array{MassD0, MassD0, MassPiPlus}); + const auto deltaMassD0D0Pi = massD0D0Pi - (massD01 + massD02); + const auto massD0D0Pair = RecoDecay::m(std::array{pVecD1, pVecD2}, std::array{MassD0, MassD0}); + + if (deltaMassD0D0Pi > deltaMassCanMax || massD0D0Pi > massCanMax) { + continue; + } + + rowCandidateLite( + candidateD1.pt(), + candidateD2.pt(), + trackPion.pt(), + candidateD1.pxProng0(), + candidateD1.pxProng1(), + candidateD1.pyProng0(), + candidateD1.pyProng1(), + candidateD1.pzProng0(), + candidateD1.pzProng1(), + candidateD2.pxProng0(), + candidateD2.pxProng1(), + candidateD2.pyProng0(), + candidateD2.pyProng1(), + candidateD2.pzProng0(), + candidateD2.pzProng1(), + trackPion.px(), + trackPion.py(), + trackPion.pz(), + candFlagD1, + candFlagD2, + massD01, + massD02, + deltaMassD01, + deltaMassD02, + massD0D0Pair, + massKpipi1, + massKpipi2, + massD0D0Pi, + deltaMassD0D0Pi, + candidateD1.eta(), + candidateD2.eta(), + trackPion.eta(), + candidateD1.phi(), + candidateD2.phi(), + trackPion.phi(), + yD1, + yD2, + trackPion.y(), + trackPion.tpcNSigmaPi(), + trackPion.tofNSigmaPi(), + mlScoresD1[0], + mlScoresD2[0], + candidateD1.decayLength(), + candidateD2.decayLength(), + candidateD1.cpa(), + candidateD2.cpa(), + trackPion.sign(), + trackPion.dcaXY(), + trackPion.dcaZ(), + trackPion.itsNCls(), + trackPion.tpcNClsCrossedRows(), + trackPion.tpcChi2NCl(), + cent); + } // end of loop track + } // end of loop second D0 + } // end of loop first D0 + } + + void processDataWithMl(Collisions const& collisions, + SelectedCandidatesMl const& candidates, + aod::TrackAssoc const& trackIndices, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowCandidateFullEvents.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, 0, collision.bc().runNumber()); + auto thisCollId = collision.globalIndex(); + auto candwD0ThisColl = candidates.sliceBy(candsD0PerCollisionWithMl, thisCollId); + if (candwD0ThisColl.size() <= 1) + continue; // only loop the collision that include at least 2 D candidates + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runCandCreatorData(collision, candwD0ThisColl, trackIdsThisCollision, tracks, bcs); + } + } + PROCESS_SWITCH(HfTreeCreatorTccToD0D0Pi, processDataWithMl, "Process data with DCAFitterN with the ML method and without centrality", false); + + void processDataWithMlWithFT0C(CollisionsWithFT0C const& collisions, + SelectedCandidatesMl const& candidates, + aod::TrackAssoc const& trackIndices, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowCandidateFullEvents.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, 0, collision.bc().runNumber()); + auto thisCollId = collision.globalIndex(); + auto candwD0ThisColl = candidates.sliceBy(candsD0PerCollisionWithMl, thisCollId); + if (candwD0ThisColl.size() <= 1) + continue; // only loop the collision that include at least 2 D candidates + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runCandCreatorData(collision, candwD0ThisColl, trackIdsThisCollision, tracks, bcs); + } + } + PROCESS_SWITCH(HfTreeCreatorTccToD0D0Pi, processDataWithMlWithFT0C, "Process data with DCAFitterN with the ML method and with FT0C centrality", true); + + void processDataWithMlWithFT0M(CollisionsWithFT0M const& collisions, + SelectedCandidatesMl const& candidates, + aod::TrackAssoc const& trackIndices, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + rowCandidateFullEvents.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, 0, collision.bc().runNumber()); + auto thisCollId = collision.globalIndex(); + auto candwD0ThisColl = candidates.sliceBy(candsD0PerCollisionWithMl, thisCollId); + if (candwD0ThisColl.size() <= 1) + continue; // only loop the collision that include at least 2 D candidates + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runCandCreatorData(collision, candwD0ThisColl, trackIdsThisCollision, tracks, bcs); + } + } + PROCESS_SWITCH(HfTreeCreatorTccToD0D0Pi, processDataWithMlWithFT0M, "Process data with DCAFitterN with the ML method and with FT0M centrality", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/treeCreatorToXiPi.cxx b/PWGHF/TableProducer/treeCreatorToXiPi.cxx index 159208c66b6..f19642f5151 100644 --- a/PWGHF/TableProducer/treeCreatorToXiPi.cxx +++ b/PWGHF/TableProducer/treeCreatorToXiPi.cxx @@ -20,6 +20,8 @@ #include "Common/Core/RecoDecay.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" @@ -33,6 +35,7 @@ namespace full // collision info DECLARE_SOA_COLUMN(IsEventSel8, isEventSel8, bool); DECLARE_SOA_COLUMN(IsEventSelZ, isEventSelZ, bool); +DECLARE_SOA_COLUMN(Centrality, centrality, float); // from creator DECLARE_SOA_COLUMN(XPv, xPv, float); DECLARE_SOA_COLUMN(YPv, yPv, float); @@ -77,26 +80,26 @@ DECLARE_SOA_COLUMN(ImpactParCascZ, impactParCascZ, float); DECLARE_SOA_COLUMN(ImpactParPiFromCharmBaryonZ, impactParPiFromCharmBaryonZ, float); DECLARE_SOA_COLUMN(ErrImpactParCascXY, errImpactParCascXY, float); DECLARE_SOA_COLUMN(ErrImpactParPiFromCharmBaryonXY, errImpactParPiFromCharmBaryonXY, float); -DECLARE_SOA_COLUMN(InvMassLambda, invMassLambda, double); -DECLARE_SOA_COLUMN(InvMassCascade, invMassCascade, double); -DECLARE_SOA_COLUMN(InvMassCharmBaryon, invMassCharmBaryon, double); -DECLARE_SOA_COLUMN(CosPAV0, cosPAV0, double); -DECLARE_SOA_COLUMN(CosPACharmBaryon, cosPACharmBaryon, double); -DECLARE_SOA_COLUMN(CosPACasc, cosPACasc, double); -DECLARE_SOA_COLUMN(CosPAXYV0, cosPAXYV0, double); -DECLARE_SOA_COLUMN(CosPAXYCharmBaryon, cosPAXYCharmBaryon, double); -DECLARE_SOA_COLUMN(CosPAXYCasc, cosPAXYCasc, double); -DECLARE_SOA_COLUMN(CTauOmegac, ctauOmegac, double); -DECLARE_SOA_COLUMN(CTauCascade, ctauCascade, double); -DECLARE_SOA_COLUMN(CTauV0, ctauV0, double); -DECLARE_SOA_COLUMN(CTauXic, ctauXic, double); -DECLARE_SOA_COLUMN(EtaV0PosDau, etaV0PosDau, double); -DECLARE_SOA_COLUMN(EtaV0NegDau, etaV0NegDau, double); -DECLARE_SOA_COLUMN(EtaPiFromCasc, etaPiFromCasc, double); -DECLARE_SOA_COLUMN(EtaPiFromCharmBaryon, etaPiFromCharmBaryon, double); -DECLARE_SOA_COLUMN(EtaCharmBaryon, etaCharmBaryon, double); -DECLARE_SOA_COLUMN(EtaCascade, etaCascade, double); -DECLARE_SOA_COLUMN(EtaV0, etaV0, double); +DECLARE_SOA_COLUMN(InvMassLambda, invMassLambda, float); +DECLARE_SOA_COLUMN(InvMassCascade, invMassCascade, float); +DECLARE_SOA_COLUMN(InvMassCharmBaryon, invMassCharmBaryon, float); +DECLARE_SOA_COLUMN(CosPAV0, cosPAV0, float); +DECLARE_SOA_COLUMN(CosPACharmBaryon, cosPACharmBaryon, float); +DECLARE_SOA_COLUMN(CosPACasc, cosPACasc, float); +DECLARE_SOA_COLUMN(CosPAXYV0, cosPAXYV0, float); +DECLARE_SOA_COLUMN(CosPAXYCharmBaryon, cosPAXYCharmBaryon, float); +DECLARE_SOA_COLUMN(CosPAXYCasc, cosPAXYCasc, float); +DECLARE_SOA_COLUMN(CTauOmegac, cTauOmegac, float); +DECLARE_SOA_COLUMN(CTauCascade, cTauCascade, float); +DECLARE_SOA_COLUMN(CTauV0, cTauV0, float); +DECLARE_SOA_COLUMN(CTauXic, cTauXic, float); +DECLARE_SOA_COLUMN(EtaV0PosDau, etaV0PosDau, float); +DECLARE_SOA_COLUMN(EtaV0NegDau, etaV0NegDau, float); +DECLARE_SOA_COLUMN(EtaPiFromCasc, etaPiFromCasc, float); +DECLARE_SOA_COLUMN(EtaPiFromCharmBaryon, etaPiFromCharmBaryon, float); +DECLARE_SOA_COLUMN(EtaCharmBaryon, etaCharmBaryon, float); +DECLARE_SOA_COLUMN(EtaCascade, etaCascade, float); +DECLARE_SOA_COLUMN(EtaV0, etaV0, float); DECLARE_SOA_COLUMN(DcaXYToPvV0Dau0, dcaXYToPvV0Dau0, float); DECLARE_SOA_COLUMN(DcaXYToPvV0Dau1, dcaXYToPvV0Dau1, float); DECLARE_SOA_COLUMN(DcaXYToPvCascDau, dcaXYToPvCascDau, float); @@ -106,9 +109,9 @@ DECLARE_SOA_COLUMN(DcaZToPvCascDau, dcaZToPvCascDau, float); DECLARE_SOA_COLUMN(DcaCascDau, dcaCascDau, float); DECLARE_SOA_COLUMN(DcaV0Dau, dcaV0Dau, float); DECLARE_SOA_COLUMN(DcaCharmBaryonDau, dcaCharmBaryonDau, float); -DECLARE_SOA_COLUMN(DecLenCharmBaryon, decLenCharmBaryon, double); -DECLARE_SOA_COLUMN(DecLenCascade, decLenCascade, double); -DECLARE_SOA_COLUMN(DecLenV0, decLenV0, double); +DECLARE_SOA_COLUMN(DecLenCharmBaryon, decLenCharmBaryon, float); +DECLARE_SOA_COLUMN(DecLenCascade, decLenCascade, float); +DECLARE_SOA_COLUMN(DecLenV0, decLenV0, float); DECLARE_SOA_COLUMN(ErrorDecayLengthCharmBaryon, errorDecayLengthCharmBaryon, float); DECLARE_SOA_COLUMN(ErrorDecayLengthXYCharmBaryon, errorDecayLengthXYCharmBaryon, float); DECLARE_SOA_COLUMN(NormImpParCascade, normImpParCascade, double); @@ -116,6 +119,10 @@ DECLARE_SOA_COLUMN(NormImpParPiFromCharmBar, normImpParPiFromCharmBar, double); DECLARE_SOA_COLUMN(NormDecayLenCharmBar, normDecayLenCharmBar, double); DECLARE_SOA_COLUMN(IsPionGlbTrkWoDca, isPionGlbTrkWoDca, bool); DECLARE_SOA_COLUMN(PionItsNCls, pionItsNCls, uint8_t); +DECLARE_SOA_COLUMN(NTpcRowsPion, nTpcRowsPion, int16_t); +DECLARE_SOA_COLUMN(NTpcRowsPiFromCasc, nTpcRowsPiFromCasc, int16_t); +DECLARE_SOA_COLUMN(NTpcRowsPosV0Dau, nTpcRowsPosV0Dau, int16_t); +DECLARE_SOA_COLUMN(NTpcRowsNegV0Dau, nTpcRowsNegV0Dau, int16_t); // from creator - MC DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level @@ -146,7 +153,7 @@ DECLARE_SOA_TABLE(HfToXiPiEvs, "AOD", "HFTOXIPIEV", full::IsEventSel8, full::IsEventSelZ); DECLARE_SOA_TABLE(HfToXiPiFulls, "AOD", "HFTOXIPIFULL", - full::XPv, full::YPv, full::ZPv, collision::NumContrib, collision::Chi2, + full::XPv, full::YPv, full::ZPv, full::Centrality, collision::NumContrib, collision::Chi2, full::XDecayVtxCharmBaryon, full::YDecayVtxCharmBaryon, full::ZDecayVtxCharmBaryon, full::XDecayVtxCascade, full::YDecayVtxCascade, full::ZDecayVtxCascade, full::XDecayVtxV0, full::YDecayVtxV0, full::ZDecayVtxV0, @@ -172,6 +179,7 @@ DECLARE_SOA_TABLE(HfToXiPiFulls, "AOD", "HFTOXIPIFULL", full::DcaCascDau, full::DcaV0Dau, full::DcaCharmBaryonDau, full::DecLenCharmBaryon, full::DecLenCascade, full::DecLenV0, full::ErrorDecayLengthCharmBaryon, full::ErrorDecayLengthXYCharmBaryon, full::NormImpParCascade, full::NormImpParPiFromCharmBar, full::NormDecayLenCharmBar, full::IsPionGlbTrkWoDca, full::PionItsNCls, + full::NTpcRowsPion, full::NTpcRowsPiFromCasc, full::NTpcRowsPosV0Dau, full::NTpcRowsNegV0Dau, full::StatusPidLambda, full::StatusPidCascade, full::StatusPidCharmBaryon, full::StatusInvMassLambda, full::StatusInvMassCascade, full::StatusInvMassCharmBaryon, full::ResultSelections, full::PidTpcInfoStored, full::PidTofInfoStored, full::TpcNSigmaPiFromCharmBaryon, full::TpcNSigmaPiFromCasc, full::TpcNSigmaPiFromLambda, full::TpcNSigmaPrFromLambda, @@ -179,7 +187,7 @@ DECLARE_SOA_TABLE(HfToXiPiFulls, "AOD", "HFTOXIPIFULL", full::FlagMcMatchRec, full::DebugMcRec, full::OriginRec, full::CollisionMatched); DECLARE_SOA_TABLE(HfToXiPiLites, "AOD", "HFTOXIPILITE", - full::XPv, full::YPv, full::ZPv, collision::NumContrib, collision::Chi2, + full::XPv, full::YPv, full::ZPv, full::Centrality, collision::NumContrib, collision::Chi2, full::XDecayVtxCharmBaryon, full::YDecayVtxCharmBaryon, full::ZDecayVtxCharmBaryon, full::XDecayVtxCascade, full::YDecayVtxCascade, full::ZDecayVtxCascade, full::XDecayVtxV0, full::YDecayVtxV0, full::ZDecayVtxV0, @@ -197,6 +205,7 @@ DECLARE_SOA_TABLE(HfToXiPiLites, "AOD", "HFTOXIPILITE", full::DcaCascDau, full::DcaV0Dau, full::DcaCharmBaryonDau, full::ErrorDecayLengthCharmBaryon, full::NormImpParCascade, full::NormImpParPiFromCharmBar, full::IsPionGlbTrkWoDca, full::PionItsNCls, + full::NTpcRowsPion, full::NTpcRowsPiFromCasc, full::NTpcRowsPosV0Dau, full::NTpcRowsNegV0Dau, full::PidTpcInfoStored, full::PidTofInfoStored, full::TpcNSigmaPiFromCharmBaryon, full::TpcNSigmaPiFromCasc, full::TpcNSigmaPiFromLambda, full::TpcNSigmaPrFromLambda, full::TofNSigmaPiFromCharmBaryon, full::TofNSigmaPiFromCasc, full::TofNSigmaPiFromLambda, full::TofNSigmaPrFromLambda, @@ -213,28 +222,44 @@ struct HfTreeCreatorToXiPi { Configurable zPvCut{"zPvCut", 10., "Cut on absolute value of primary vertex z coordinate"}; + using Cents = soa::Join; using MyTrackTable = soa::Join; using MyEventTable = soa::Join; + using MyEventTableWithFT0C = soa::Join; + using MyEventTableWithFT0M = soa::Join; + using MyEventTableWithNTracksPV = soa::Join; void init(InitContext const&) { + if ((doprocessMcLiteXic0 && doprocessMcLiteOmegac0) || (doprocessMcFullXic0 && doprocessMcFullOmegac0)) { + LOGF(fatal, "Both Xic0 and Omegac0 MC processes enabled, please choose ONLY one!"); + } } - template + template void fillEvent(const T& collision, float cutZPv) { - rowEv(collision.sel8(), std::abs(collision.posZ()) < cutZPv); + rowEv( + collision.sel8(), std::abs(collision.posZ()) < cutZPv); } - template + template void fillCandidate(const T& candidate, int8_t flagMc, int8_t debugMc, int8_t originMc, bool collisionMatched) { + + float centrality = -999.f; + if constexpr (useCentrality) { + auto const& collision = candidate.template collision_as(); + centrality = o2::hf_centrality::getCentralityColl(collision); + } + rowCandidateFull( candidate.xPv(), candidate.yPv(), candidate.zPv(), - candidate.template collision_as().numContrib(), - candidate.template collision_as().chi2(), + centrality, + candidate.template collision_as().numContrib(), + candidate.template collision_as().chi2(), candidate.xDecayVtxCharmBaryon(), candidate.yDecayVtxCharmBaryon(), candidate.zDecayVtxCharmBaryon(), @@ -254,15 +279,15 @@ struct HfTreeCreatorToXiPi { candidate.pxCasc(), candidate.pyCasc(), candidate.pzCasc(), - candidate.pxPiFromCharmBaryon(), - candidate.pyPiFromCharmBaryon(), - candidate.pzPiFromCharmBaryon(), + candidate.pxBachFromCharmBaryon(), + candidate.pyBachFromCharmBaryon(), + candidate.pzBachFromCharmBaryon(), candidate.pxLambda(), candidate.pyLambda(), candidate.pzLambda(), - candidate.pxPiFromCasc(), - candidate.pyPiFromCasc(), - candidate.pzPiFromCasc(), + candidate.pxBachFromCasc(), + candidate.pyBachFromCasc(), + candidate.pzBachFromCasc(), candidate.pxPosV0Dau(), candidate.pyPosV0Dau(), candidate.pzPosV0Dau(), @@ -270,11 +295,11 @@ struct HfTreeCreatorToXiPi { candidate.pyNegV0Dau(), candidate.pzNegV0Dau(), candidate.impactParCascXY(), - candidate.impactParPiFromCharmBaryonXY(), + candidate.impactParBachFromCharmBaryonXY(), candidate.impactParCascZ(), - candidate.impactParPiFromCharmBaryonZ(), + candidate.impactParBachFromCharmBaryonZ(), candidate.errImpactParCascXY(), - candidate.errImpactParPiFromCharmBaryonXY(), + candidate.errImpactParBachFromCharmBaryonXY(), candidate.invMassLambda(), candidate.invMassCascade(), candidate.invMassCharmBaryon(), @@ -284,14 +309,14 @@ struct HfTreeCreatorToXiPi { candidate.cosPAXYV0(), candidate.cosPAXYCharmBaryon(), candidate.cosPAXYCasc(), - candidate.ctauOmegac(), - candidate.ctauCascade(), - candidate.ctauV0(), - candidate.ctauXic(), + candidate.cTauOmegac(), + candidate.cTauCascade(), + candidate.cTauV0(), + candidate.cTauXic(), candidate.etaV0PosDau(), candidate.etaV0NegDau(), - candidate.etaPiFromCasc(), - candidate.etaPiFromCharmBaryon(), + candidate.etaBachFromCasc(), + candidate.etaBachFromCharmBaryon(), candidate.etaCharmBaryon(), candidate.etaCascade(), candidate.etaV0(), @@ -310,10 +335,14 @@ struct HfTreeCreatorToXiPi { candidate.errorDecayLengthCharmBaryon(), candidate.errorDecayLengthXYCharmBaryon(), candidate.impactParCascXY() / candidate.errImpactParCascXY(), - candidate.impactParPiFromCharmBaryonXY() / candidate.errImpactParPiFromCharmBaryonXY(), + candidate.impactParBachFromCharmBaryonXY() / candidate.errImpactParBachFromCharmBaryonXY(), candidate.decLenCharmBaryon() / candidate.errorDecayLengthCharmBaryon(), - candidate.template piFromCharmBaryon_as().isGlobalTrackWoDCA(), - candidate.template piFromCharmBaryon_as().itsNCls(), + candidate.template bachelorFromCharmBaryon_as().isGlobalTrackWoDCA(), + candidate.template bachelorFromCharmBaryon_as().itsNCls(), + candidate.template bachelorFromCharmBaryon_as().tpcNClsCrossedRows(), + candidate.template bachelor_as().tpcNClsCrossedRows(), + candidate.template posTrack_as().tpcNClsCrossedRows(), + candidate.template negTrack_as().tpcNClsCrossedRows(), candidate.statusPidLambda(), candidate.statusPidCascade(), candidate.statusPidCharmBaryon(), @@ -337,17 +366,24 @@ struct HfTreeCreatorToXiPi { collisionMatched); } - template + template void fillCandidateLite(const T& candidate, int8_t flagMc, int8_t originMc, bool collisionMatched) { if (candidate.resultSelections() && candidate.statusPidCharmBaryon() && candidate.statusInvMassLambda() && candidate.statusInvMassCascade() && candidate.statusInvMassCharmBaryon()) { + float centrality = -999.f; + if constexpr (useCentrality) { + auto const& collision = candidate.template collision_as(); + centrality = o2::hf_centrality::getCentralityColl(collision); + } + rowCandidateLite( candidate.xPv(), candidate.yPv(), candidate.zPv(), - candidate.template collision_as().numContrib(), - candidate.template collision_as().chi2(), + centrality, + candidate.template collision_as().numContrib(), + candidate.template collision_as().chi2(), candidate.xDecayVtxCharmBaryon(), candidate.yDecayVtxCharmBaryon(), candidate.zDecayVtxCharmBaryon(), @@ -361,12 +397,12 @@ struct HfTreeCreatorToXiPi { candidate.pxCharmBaryon(), candidate.pyCharmBaryon(), candidate.pzCharmBaryon(), - candidate.pxPiFromCharmBaryon(), - candidate.pyPiFromCharmBaryon(), - candidate.pzPiFromCharmBaryon(), - candidate.pxPiFromCasc(), - candidate.pyPiFromCasc(), - candidate.pzPiFromCasc(), + candidate.pxBachFromCharmBaryon(), + candidate.pyBachFromCharmBaryon(), + candidate.pzBachFromCharmBaryon(), + candidate.pxBachFromCasc(), + candidate.pyBachFromCasc(), + candidate.pzBachFromCasc(), candidate.pxPosV0Dau(), candidate.pyPosV0Dau(), candidate.pzPosV0Dau(), @@ -374,16 +410,16 @@ struct HfTreeCreatorToXiPi { candidate.pyNegV0Dau(), candidate.pzNegV0Dau(), candidate.impactParCascXY(), - candidate.impactParPiFromCharmBaryonXY(), + candidate.impactParBachFromCharmBaryonXY(), candidate.errImpactParCascXY(), - candidate.errImpactParPiFromCharmBaryonXY(), + candidate.errImpactParBachFromCharmBaryonXY(), candidate.invMassLambda(), candidate.invMassCascade(), candidate.invMassCharmBaryon(), candidate.etaV0PosDau(), candidate.etaV0NegDau(), - candidate.etaPiFromCasc(), - candidate.etaPiFromCharmBaryon(), + candidate.etaBachFromCasc(), + candidate.etaBachFromCharmBaryon(), candidate.dcaXYToPvV0Dau0(), candidate.dcaXYToPvV0Dau1(), candidate.dcaXYToPvCascDau(), @@ -392,9 +428,13 @@ struct HfTreeCreatorToXiPi { candidate.dcaCharmBaryonDau(), candidate.errorDecayLengthCharmBaryon(), candidate.impactParCascXY() / candidate.errImpactParCascXY(), - candidate.impactParPiFromCharmBaryonXY() / candidate.errImpactParPiFromCharmBaryonXY(), - candidate.template piFromCharmBaryon_as().isGlobalTrackWoDCA(), - candidate.template piFromCharmBaryon_as().itsNCls(), + candidate.impactParBachFromCharmBaryonXY() / candidate.errImpactParBachFromCharmBaryonXY(), + candidate.template bachelorFromCharmBaryon_as().isGlobalTrackWoDCA(), + candidate.template bachelorFromCharmBaryon_as().itsNCls(), + candidate.template bachelorFromCharmBaryon_as().tpcNClsCrossedRows(), + candidate.template bachelor_as().tpcNClsCrossedRows(), + candidate.template posTrack_as().tpcNClsCrossedRows(), + candidate.template negTrack_as().tpcNClsCrossedRows(), candidate.pidTpcInfoStored(), candidate.pidTofInfoStored(), candidate.tpcNSigmaPiFromCharmBaryon(), @@ -417,33 +457,50 @@ struct HfTreeCreatorToXiPi { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowCandidateFull.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillCandidate(candidate, -7, -7, RecoDecay::OriginType::None, false); + } + } + PROCESS_SWITCH(HfTreeCreatorToXiPi, processDataFull, "Process data with full information w/o centrality", true); + + void processMcFullXic0(MyEventTable const& collisions, MyTrackTable const&, + soa::Join const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); } // Filling candidate properties rowCandidateFull.reserve(candidates.size()); for (const auto& candidate : candidates) { - fillCandidate(candidate, -7, -7, RecoDecay::OriginType::None, false); + fillCandidate(candidate, candidate.flagMcMatchRec(), candidate.debugMcRec(), candidate.originRec(), candidate.collisionMatched()); } } - PROCESS_SWITCH(HfTreeCreatorToXiPi, processDataFull, "Process data with full information", true); + PROCESS_SWITCH(HfTreeCreatorToXiPi, processMcFullXic0, "Process MC with full information for xic0 w/o centrality", false); - void processMcFull(MyEventTable const& collisions, MyTrackTable const&, - soa::Join const& candidates) + void processMcFullOmegac0(MyEventTable const& collisions, MyTrackTable const&, + soa::Join const& candidates) { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision, zPvCut); } // Filling candidate properties rowCandidateFull.reserve(candidates.size()); for (const auto& candidate : candidates) { - fillCandidate(candidate, candidate.flagMcMatchRec(), candidate.debugMcRec(), candidate.originRec(), candidate.collisionMatched()); + fillCandidate(candidate, candidate.flagMcMatchRec(), candidate.debugMcRec(), candidate.originRec(), candidate.collisionMatched()); } } - PROCESS_SWITCH(HfTreeCreatorToXiPi, processMcFull, "Process MC with full information", false); + PROCESS_SWITCH(HfTreeCreatorToXiPi, processMcFullOmegac0, "Process MC with full information for omegac0", false); void processDataLite(MyEventTable const& collisions, MyTrackTable const&, soa::Join const& candidates) @@ -451,33 +508,152 @@ struct HfTreeCreatorToXiPi { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision, zPvCut); } // Filling candidate properties rowCandidateLite.reserve(candidates.size()); for (const auto& candidate : candidates) { - fillCandidateLite(candidate, -7, RecoDecay::OriginType::None, false); + fillCandidateLite(candidate, -7, RecoDecay::OriginType::None, false); } } PROCESS_SWITCH(HfTreeCreatorToXiPi, processDataLite, "Process data and produce lite table version", false); - void processMcLite(MyEventTable const& collisions, MyTrackTable const&, - soa::Join const& candidates) + void processDataLiteWithFT0M(MyEventTableWithFT0M const& collisions, MyTrackTable const&, + soa::Join const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowCandidateLite.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillCandidateLite(candidate, -7, RecoDecay::OriginType::None, false); + } + } + PROCESS_SWITCH(HfTreeCreatorToXiPi, processDataLiteWithFT0M, "Process data and produce lite table version with FT0M", false); + + void processDataLiteWithFT0C(MyEventTableWithFT0C const& collisions, MyTrackTable const&, + soa::Join const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowCandidateLite.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillCandidateLite(candidate, -7, RecoDecay::OriginType::None, false); + } + } + PROCESS_SWITCH(HfTreeCreatorToXiPi, processDataLiteWithFT0C, "Process data and produce lite table version with FT0C", false); + + void processDataLiteWithNTracksPV(MyEventTableWithNTracksPV const& collisions, MyTrackTable const&, + soa::Join const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowCandidateLite.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillCandidateLite(candidate, -7, RecoDecay::OriginType::None, false); + } + } + PROCESS_SWITCH(HfTreeCreatorToXiPi, processDataLiteWithNTracksPV, "Process data and produce lite table version with NTracksPV", false); + + void processMcLiteXic0(MyEventTable const& collisions, MyTrackTable const&, + soa::Join const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowCandidateLite.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillCandidateLite(candidate, candidate.flagMcMatchRec(), candidate.originRec(), candidate.collisionMatched()); + } + } + PROCESS_SWITCH(HfTreeCreatorToXiPi, processMcLiteXic0, "Process MC and produce lite table version for xic0", false); + + void processMcLiteXic0WithFT0C(MyEventTableWithFT0C const& collisions, MyTrackTable const&, + soa::Join const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowCandidateLite.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillCandidateLite(candidate, candidate.flagMcMatchRec(), candidate.originRec(), candidate.collisionMatched()); + } + } + PROCESS_SWITCH(HfTreeCreatorToXiPi, processMcLiteXic0WithFT0C, "Process MC and produce lite table version for Xic0 with FT0C", false); + + void processMcLiteXic0WithFT0M(MyEventTableWithFT0M const& collisions, MyTrackTable const&, + soa::Join const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowCandidateLite.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillCandidateLite(candidate, candidate.flagMcMatchRec(), candidate.originRec(), candidate.collisionMatched()); + } + } + PROCESS_SWITCH(HfTreeCreatorToXiPi, processMcLiteXic0WithFT0M, "Process MC and produce lite table version for Xic0 with FT0M", false); + + void processMcLiteXic0WithNTracksPV(MyEventTableWithNTracksPV const& collisions, MyTrackTable const&, + soa::Join const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowCandidateLite.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillCandidateLite(candidate, candidate.flagMcMatchRec(), candidate.originRec(), candidate.collisionMatched()); + } + } + PROCESS_SWITCH(HfTreeCreatorToXiPi, processMcLiteXic0WithNTracksPV, "Process MC and produce lite table version for Xic0 with NTracksPV", false); + + void processMcLiteOmegac0(MyEventTable const& collisions, MyTrackTable const&, + soa::Join const& candidates) { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision, zPvCut); } // Filling candidate properties rowCandidateLite.reserve(candidates.size()); for (const auto& candidate : candidates) { - fillCandidateLite(candidate, candidate.flagMcMatchRec(), candidate.originRec(), candidate.collisionMatched()); + fillCandidateLite(candidate, candidate.flagMcMatchRec(), candidate.originRec(), candidate.collisionMatched()); } } - PROCESS_SWITCH(HfTreeCreatorToXiPi, processMcLite, "Process MC and produce lite table version", false); + PROCESS_SWITCH(HfTreeCreatorToXiPi, processMcLiteOmegac0, "Process MC and produce lite table version for omegac0", false); }; // end of struct diff --git a/PWGHF/TableProducer/treeCreatorXic0ToXiPiKf.cxx b/PWGHF/TableProducer/treeCreatorXic0ToXiPiKf.cxx new file mode 100644 index 00000000000..e763724e501 --- /dev/null +++ b/PWGHF/TableProducer/treeCreatorXic0ToXiPiKf.cxx @@ -0,0 +1,231 @@ +// 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 treeCreatorXic0ToXiPiKf.cxx +/// \brief Writer of the xic0 to Xi Pi candidates in the form of flat tables to be stored in TTrees. +/// In this file are defined and filled the output tables +/// +/// \author Ran Tu , Fudan University + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/RecoDecay.h" + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +using namespace o2; +using namespace o2::framework; + +namespace o2::aod +{ +namespace full +{ +DECLARE_SOA_COLUMN(InvMassLambda, invMassLambda, float); +DECLARE_SOA_COLUMN(InvMassCascade, invMassCascade, float); +DECLARE_SOA_COLUMN(InvMassCharmBaryon, invMassCharmBaryon, float); +DECLARE_SOA_COLUMN(DcaXYToPvV0Dau0, dcaXYToPvV0Dau0, float); +DECLARE_SOA_COLUMN(DcaXYToPvV0Dau1, dcaXYToPvV0Dau1, float); +DECLARE_SOA_COLUMN(DcaXYToPvCascDau, dcaXYToPvCascDau, float); +DECLARE_SOA_COLUMN(DcaCascDau, dcaCascDau, float); +DECLARE_SOA_COLUMN(DcaCharmBaryonDau, dcaCharmBaryonDau, float); +// from creator - MC +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level +DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level +DECLARE_SOA_COLUMN(OriginRec, originRec, int8_t); +DECLARE_SOA_COLUMN(CollisionMatched, collisionMatched, bool); +// from selector +DECLARE_SOA_COLUMN(TpcNSigmaPiFromCharmBaryon, tpcNSigmaPiFromCharmBaryon, float); +DECLARE_SOA_COLUMN(TpcNSigmaPiFromCasc, tpcNSigmaPiFromCasc, float); +DECLARE_SOA_COLUMN(TpcNSigmaPiFromLambda, tpcNSigmaPiFromLambda, float); +DECLARE_SOA_COLUMN(TpcNSigmaPrFromLambda, tpcNSigmaPrFromLambda, float); +DECLARE_SOA_COLUMN(TofNSigmaPiFromCharmBaryon, tofNSigmaPiFromCharmBaryon, float); +DECLARE_SOA_COLUMN(TofNSigmaPiFromCasc, tofNSigmaPiFromCasc, float); +DECLARE_SOA_COLUMN(TofNSigmaPiFromLambda, tofNSigmaPiFromLambda, float); +DECLARE_SOA_COLUMN(TofNSigmaPrFromLambda, tofNSigmaPrFromLambda, float); +// from creator KF +DECLARE_SOA_COLUMN(KfDcaXYPiFromXic, kfDcaXYPiFromXic, float); +DECLARE_SOA_COLUMN(KfDcaXYCascToPv, kfDcaXYCascToPv, float); +DECLARE_SOA_COLUMN(Chi2GeoV0, chi2GeoV0, float); +DECLARE_SOA_COLUMN(Chi2GeoCasc, chi2GeoCasc, float); +DECLARE_SOA_COLUMN(Chi2GeoXic, chi2GeoXic, float); +DECLARE_SOA_COLUMN(Chi2MassV0, chi2MassV0, float); +DECLARE_SOA_COLUMN(Chi2MassCasc, chi2MassCasc, float); +DECLARE_SOA_COLUMN(V0ldl, v0ldl, float); +DECLARE_SOA_COLUMN(Cascldl, cascldl, float); +DECLARE_SOA_COLUMN(Xicldl, xicldl, float); +DECLARE_SOA_COLUMN(Chi2TopoV0ToPv, chi2TopoV0ToPv, float); +DECLARE_SOA_COLUMN(Chi2TopoCascToPv, chi2TopoCascToPv, float); +DECLARE_SOA_COLUMN(Chi2TopoPiFromXicToPv, chi2TopoPiFromXicToPv, float); +DECLARE_SOA_COLUMN(Chi2TopoXicToPv, chi2TopoXicToPv, float); +DECLARE_SOA_COLUMN(Chi2TopoV0ToCasc, chi2TopoV0ToCasc, float); +DECLARE_SOA_COLUMN(Chi2TopoCascToXic, chi2TopoCascToXic, float); +DECLARE_SOA_COLUMN(DecayLenXYLambda, decayLenXYLambda, float); +DECLARE_SOA_COLUMN(DecayLenXYCasc, decayLenXYCasc, float); +DECLARE_SOA_COLUMN(DecayLenXYXic, decayLenXYXic, float); +DECLARE_SOA_COLUMN(CosPaV0ToCasc, cosPaV0ToCasc, float); +DECLARE_SOA_COLUMN(CosPaV0ToPv, cosPaV0ToPv, float); +DECLARE_SOA_COLUMN(CosPaCascToXic, cosPaCascToXic, float); +DECLARE_SOA_COLUMN(CosPaCascToPv, cosPaCascToPv, float); +DECLARE_SOA_COLUMN(CosPaXicToPv, cosPaXicToPv, float); +DECLARE_SOA_COLUMN(KfRapXic, kfRapXic, float); +DECLARE_SOA_COLUMN(KfptPiFromXic, kfptPiFromXic, float); +DECLARE_SOA_COLUMN(KfptXic, kfptXic, float); +DECLARE_SOA_COLUMN(CosThetaStarPiFromXic, cosThetaStarPiFromXic, float); +DECLARE_SOA_COLUMN(CtXic, ctXic, float); +DECLARE_SOA_COLUMN(EtaXic, etaXic, float); +DECLARE_SOA_COLUMN(V0Ndf, v0Ndf, float); +DECLARE_SOA_COLUMN(CascNdf, cascNdf, float); +DECLARE_SOA_COLUMN(XicNdf, xicNdf, float); +DECLARE_SOA_COLUMN(MassV0Ndf, massV0Ndf, float); +DECLARE_SOA_COLUMN(MassCascNdf, massCascNdf, float); +DECLARE_SOA_COLUMN(V0Chi2OverNdf, v0Chi2OverNdf, float); +DECLARE_SOA_COLUMN(CascChi2OverNdf, cascChi2OverNdf, float); +DECLARE_SOA_COLUMN(XicChi2OverNdf, xicChi2OverNdf, float); +DECLARE_SOA_COLUMN(MassV0Chi2OverNdf, massV0Chi2OverNdf, float); +DECLARE_SOA_COLUMN(MassCascChi2OverNdf, massCascChi2OverNdf, float); + +} // namespace full + +DECLARE_SOA_TABLE(HfKfXicFulls, "AOD", "HFKFXICFULL", + full::TpcNSigmaPiFromCharmBaryon, full::TofNSigmaPiFromCharmBaryon, full::TpcNSigmaPiFromCasc, full::TofNSigmaPiFromCasc, + full::TpcNSigmaPiFromLambda, full::TofNSigmaPiFromLambda, full::TpcNSigmaPrFromLambda, full::TofNSigmaPrFromLambda, + full::KfDcaXYPiFromXic, full::DcaCascDau, full::DcaCharmBaryonDau, full::KfDcaXYCascToPv, + full::DcaXYToPvV0Dau0, full::DcaXYToPvV0Dau1, full::DcaXYToPvCascDau, + full::Chi2GeoV0, full::Chi2GeoCasc, full::Chi2GeoXic, + full::Chi2MassV0, full::Chi2MassCasc, + full::V0ldl, full::Cascldl, full::Xicldl, + full::Chi2TopoV0ToPv, full::Chi2TopoCascToPv, full::Chi2TopoPiFromXicToPv, full::Chi2TopoXicToPv, + full::Chi2TopoV0ToCasc, full::Chi2TopoCascToXic, + full::DecayLenXYLambda, full::DecayLenXYCasc, full::DecayLenXYXic, + full::CosPaV0ToCasc, full::CosPaV0ToPv, full::CosPaCascToXic, full::CosPaCascToPv, full::CosPaXicToPv, + full::InvMassLambda, full::InvMassCascade, full::InvMassCharmBaryon, + full::KfRapXic, full::KfptPiFromXic, full::KfptXic, + full::CosThetaStarPiFromXic, full::CtXic, full::EtaXic, + full::V0Ndf, full::CascNdf, full::XicNdf, + full::MassV0Ndf, full::MassCascNdf, + full::V0Chi2OverNdf, full::CascChi2OverNdf, full::XicChi2OverNdf, + full::MassV0Chi2OverNdf, full::MassCascChi2OverNdf, + full::FlagMcMatchRec, full::DebugMcRec, full::OriginRec, full::CollisionMatched); + +} // namespace o2::aod + +/// Writes the full information in an output TTree +struct HfTreeCreatorXic0ToXiPiKf { + + Produces rowKfCandidate; + + Configurable zPvCut{"zPvCut", 10., "Cut on absolute value of primary vertex z coordinate"}; + + using MyTrackTable = soa::Join; + + void init(InitContext const&) + { + } + + template + void fillKfCandidate(const T& candidate, int8_t flagMc, int8_t debugMc, int8_t originMc, bool collisionMatched) + { + + if (candidate.resultSelections() && candidate.statusPidCharmBaryon() && candidate.statusInvMassLambda() && candidate.statusInvMassCascade() && candidate.statusInvMassCharmBaryon()) { + + rowKfCandidate( + candidate.tpcNSigmaPiFromCharmBaryon(), + candidate.tofNSigmaPiFromCharmBaryon(), + candidate.tpcNSigmaPiFromCasc(), + candidate.tofNSigmaPiFromCasc(), + candidate.tpcNSigmaPiFromLambda(), + candidate.tofNSigmaPiFromLambda(), + candidate.tpcNSigmaPrFromLambda(), + candidate.tofNSigmaPrFromLambda(), + candidate.kfDcaXYPiFromXic(), + candidate.dcaCascDau(), + candidate.dcaCharmBaryonDau(), + candidate.kfDcaXYCascToPv(), + candidate.dcaXYToPvV0Dau0(), + candidate.dcaXYToPvV0Dau1(), + candidate.dcaXYToPvCascDau(), + candidate.chi2GeoV0(), + candidate.chi2GeoCasc(), + candidate.chi2GeoXic(), + candidate.chi2MassV0(), + candidate.chi2MassCasc(), + candidate.v0ldl(), + candidate.cascldl(), + candidate.xicldl(), + candidate.chi2TopoV0ToPv(), + candidate.chi2TopoCascToPv(), + candidate.chi2TopoPiFromXicToPv(), + candidate.chi2TopoXicToPv(), + candidate.chi2TopoV0ToCasc(), + candidate.chi2TopoCascToXic(), + candidate.decayLenXYLambda(), + candidate.decayLenXYCasc(), + candidate.decayLenXYXic(), + candidate.cosPaV0ToCasc(), + candidate.cosPAV0(), + candidate.cosPaCascToXic(), + candidate.cosPACasc(), + candidate.cosPACharmBaryon(), + candidate.invMassLambda(), + candidate.invMassCascade(), + candidate.invMassCharmBaryon(), + candidate.kfRapXic(), + candidate.kfptPiFromXic(), + candidate.kfptXic(), + candidate.cosThetaStarPiFromXic(), + candidate.cTauXic(), + candidate.etaCharmBaryon(), + candidate.v0Ndf(), + candidate.cascNdf(), + candidate.xicNdf(), + candidate.massV0Ndf(), + candidate.massCascNdf(), + candidate.v0Chi2OverNdf(), + candidate.cascChi2OverNdf(), + candidate.xicChi2OverNdf(), + candidate.massV0Chi2OverNdf(), + candidate.massCascChi2OverNdf(), + flagMc, + debugMc, + originMc, + collisionMatched); + } + } + + void processKfData(MyTrackTable const&, + soa::Join const& candidates) + { + rowKfCandidate.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillKfCandidate(candidate, -7, -7, RecoDecay::OriginType::None, false); + } + } + PROCESS_SWITCH(HfTreeCreatorXic0ToXiPiKf, processKfData, "Process KF data", false); + + void processKfMcXic0(MyTrackTable const&, + soa::Join const& candidates) + { + rowKfCandidate.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillKfCandidate(candidate, candidate.flagMcMatchRec(), candidate.debugMcRec(), candidate.originRec(), candidate.collisionMatched()); + } + } + PROCESS_SWITCH(HfTreeCreatorXic0ToXiPiKf, processKfMcXic0, "Process MC with information for xic0", false); + +}; // end of struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/treeCreatorXicToPKPi.cxx b/PWGHF/TableProducer/treeCreatorXicToPKPi.cxx index ba07e2def45..915cfba1bda 100644 --- a/PWGHF/TableProducer/treeCreatorXicToPKPi.cxx +++ b/PWGHF/TableProducer/treeCreatorXicToPKPi.cxx @@ -60,11 +60,11 @@ DECLARE_SOA_COLUMN(NSigTpcPi2, nSigTpcPi2, float); DECLARE_SOA_COLUMN(NSigTpcPr2, nSigTpcPr2, float); DECLARE_SOA_COLUMN(NSigTofPi2, nSigTofPi2, float); DECLARE_SOA_COLUMN(NSigTofPr2, nSigTofPr2, float); -DECLARE_SOA_COLUMN(NSigTpcTofPr0, nSigTpcTofPi0, float); -DECLARE_SOA_COLUMN(NSigTpcTofPi0, nSigTpcTofPr0, float); +DECLARE_SOA_COLUMN(NSigTpcTofPr0, nSigTpcTofPr0, float); +DECLARE_SOA_COLUMN(NSigTpcTofPi0, nSigTpcTofPi0, float); DECLARE_SOA_COLUMN(NSigTpcTofKa1, nSigTpcTofKa1, float); -DECLARE_SOA_COLUMN(NSigTpcTofPr2, nSigTpcTofPi2, float); -DECLARE_SOA_COLUMN(NSigTpcTofPi2, nSigTpcTofPr2, float); +DECLARE_SOA_COLUMN(NSigTpcTofPr2, nSigTpcTofPr2, float); +DECLARE_SOA_COLUMN(NSigTpcTofPi2, nSigTpcTofPi2, float); DECLARE_SOA_COLUMN(DecayLength, decayLength, float); DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); @@ -75,6 +75,8 @@ DECLARE_SOA_COLUMN(Ct, ct, float); DECLARE_SOA_COLUMN(FlagMc, flagMc, int8_t); DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); +DECLARE_SOA_COLUMN(IsCandidateSwapped, isCandidateSwapped, int); + // Events DECLARE_SOA_COLUMN(IsEventReject, isEventReject, int); DECLARE_SOA_COLUMN(RunNumber, runNumber, int); @@ -116,7 +118,8 @@ DECLARE_SOA_TABLE(HfCandXicLites, "AOD", "HFCANDXICLITE", full::Eta, full::Phi, full::FlagMc, - full::OriginMcRec) + full::OriginMcRec, + full::IsCandidateSwapped) DECLARE_SOA_TABLE(HfCandXicFulls, "AOD", "HFCANDXICFULL", collision::PosX, @@ -185,7 +188,8 @@ DECLARE_SOA_TABLE(HfCandXicFulls, "AOD", "HFCANDXICFULL", full::Y, full::E, full::FlagMc, - full::OriginMcRec); + full::OriginMcRec, + full::IsCandidateSwapped); DECLARE_SOA_TABLE(HfCandXicFullEvs, "AOD", "HFCANDXICFULLEV", collision::NumContrib, @@ -261,9 +265,11 @@ struct HfTreeCreatorXicToPKPi { { int8_t flagMc = 0; int8_t originMc = 0; + int candSwapped = 0; if constexpr (doMc) { flagMc = candidate.flagMcMatchRec(); originMc = candidate.originMcRec(); + candSwapped = candidate.isCandidateSwapped(); } float invMassXic = 0; @@ -314,7 +320,8 @@ struct HfTreeCreatorXicToPKPi { candidate.eta(), candidate.phi(), flagMc, - originMc); + originMc, + candSwapped); } else { rowCandidateFull( @@ -384,7 +391,8 @@ struct HfTreeCreatorXicToPKPi { hfHelper.yXic(candidate), hfHelper.eXic(candidate), flagMc, - originMc); + originMc, + candSwapped); } } @@ -464,7 +472,7 @@ struct HfTreeCreatorXicToPKPi { for (const auto& candidate : reconstructedCandBkg) { if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } diff --git a/PWGHF/TableProducer/treeCreatorXicToXiPiPi.cxx b/PWGHF/TableProducer/treeCreatorXicToXiPiPi.cxx new file mode 100644 index 00000000000..ff17d263413 --- /dev/null +++ b/PWGHF/TableProducer/treeCreatorXicToXiPiPi.cxx @@ -0,0 +1,899 @@ +// 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 treeCreatorXicToXiPiPi.cxx +/// \brief Writer of Ξc± → Ξ∓ π± π± candidates in the form of flat tables to be stored in TTrees. +/// +/// \author Phil Lennart Stahlhut , Heidelberg University +/// \author Carolina Reetz , Heidelberg University +/// \author Jaeyoon Cho , Inha University + +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +namespace o2::aod +{ +namespace full +{ +DECLARE_SOA_COLUMN(CandidateSelFlag, candidateSelFlag, int); //! Selection flag of candidate (output of candidateSelector) +// vertices +DECLARE_SOA_COLUMN(Chi2Sv, chi2Sv, float); +DECLARE_SOA_COLUMN(Chi2XiVtx, chi2XiVtx, float); +DECLARE_SOA_COLUMN(Chi2LamVtx, chi2LamVtx, float); +// properties of XicPlus +DECLARE_SOA_COLUMN(Sign, sign, float); +DECLARE_SOA_COLUMN(E, e, float); //! Energy of candidate (GeV) +DECLARE_SOA_COLUMN(M, m, float); //! Invariant mass of candidate (GeV/c2) +DECLARE_SOA_COLUMN(P, p, float); //! Momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(Pt, pt, float); //! Transverse momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(Y, y, float); //! Rapidity of candidate +DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity of candidate +DECLARE_SOA_COLUMN(Phi, phi, float); //! Azimuth angle of candidate +DECLARE_SOA_COLUMN(Ct, ct, float); //! Proper lifetime time ctau of candidate (cm) +DECLARE_SOA_COLUMN(DecayLength, decayLength, float); //! Decay length of candidate (cm) +DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); //! Transverse decay length of candidate (cm) +DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); //! Normalised decay length of candidate +DECLARE_SOA_COLUMN(DecayLengthXYNormalised, decayLengthXYNormalised, float); //! Normalised transverse decay length of candidate +DECLARE_SOA_COLUMN(Cpa, cpa, float); //! Cosine pointing angle of candidate +DECLARE_SOA_COLUMN(CpaXY, cpaXY, float); //! Cosine pointing angle of candidate in transverse plane +DECLARE_SOA_COLUMN(Chi2TopoXicPlusToPVBeforeConstraint, chi2TopoXicPlusToPVBeforeConstraint, float); +DECLARE_SOA_COLUMN(Chi2TopoXicPlusToPV, chi2TopoXicPlusToPV, float); +DECLARE_SOA_COLUMN(Chi2TopoXiToXicPlusBeforeConstraint, chi2TopoXiToXicPlusBeforeConstraint, float); +DECLARE_SOA_COLUMN(Chi2TopoXiToXicPlus, chi2TopoXiToXicPlus, float); +// properties of daughter tracks +DECLARE_SOA_COLUMN(PtXi, ptXi, float); //! Transverse momentum of Xi (prong0) (GeV/c) +DECLARE_SOA_COLUMN(ImpactParameterXi, impactParameterXi, float); //! Impact parameter of Xi (prong0) +DECLARE_SOA_COLUMN(ImpactParameterNormalisedXi, impactParameterNormalisedXi, float); //! Normalised impact parameter of Xi (prong0) +DECLARE_SOA_COLUMN(PPi0, pPi0, float); +DECLARE_SOA_COLUMN(PtPi0, ptPi0, float); //! Transverse momentum of Pi0 (prong1) (GeV/c) +DECLARE_SOA_COLUMN(ImpactParameterPi0, impactParameterPi0, float); //! Impact parameter of Pi0 (prong1) +DECLARE_SOA_COLUMN(ImpactParameterNormalisedPi0, impactParameterNormalisedPi0, float); //! Normalised impact parameter of Pi0 (prong1) +DECLARE_SOA_COLUMN(PPi1, pPi1, float); +DECLARE_SOA_COLUMN(PtPi1, ptPi1, float); //! Transverse momentum of Pi1 (prong2) (GeV/c) +DECLARE_SOA_COLUMN(ImpactParameterPi1, impactParameterPi1, float); //! Normalised impact parameter of Pi1 (prong2) +DECLARE_SOA_COLUMN(ImpactParameterNormalisedPi1, impactParameterNormalisedPi1, float); //! Normalised impact parameter of Pi1 (prong2) +DECLARE_SOA_COLUMN(MaxNormalisedDeltaIP, maxNormalisedDeltaIP, float); //! Maximum normalized difference between measured and expected impact parameter of candidate prongs +DECLARE_SOA_COLUMN(CpaXi, cpaXi, float); +DECLARE_SOA_COLUMN(CpaXYXi, cpaXYXi, float); +DECLARE_SOA_COLUMN(CpaLam, cpaLam, float); +DECLARE_SOA_COLUMN(CpaXYLam, cpaXYLam, float); +DECLARE_SOA_COLUMN(CpaLamToXi, cpaLamToXi, float); +DECLARE_SOA_COLUMN(CpaXYLamToXi, cpaXYLamToXi, float); +DECLARE_SOA_COLUMN(DcaXYPi0Pi1, dcaXYPi0Pi1, float); +DECLARE_SOA_COLUMN(DcaXYPi0Xi, dcaXYPi0Xi, float); +DECLARE_SOA_COLUMN(DcaXYPi1Xi, dcaXYPi1Xi, float); +DECLARE_SOA_COLUMN(DcaPi0Pi1, dcaPi0Pi1, float); +DECLARE_SOA_COLUMN(DcaPi0Xi, dcaPi0Xi, float); +DECLARE_SOA_COLUMN(DcaPi1Xi, dcaPi1Xi, float); +DECLARE_SOA_COLUMN(InvMassXi, invMassXi, float); +DECLARE_SOA_COLUMN(InvMassLambda, invMassLambda, float); +DECLARE_SOA_COLUMN(InvMassXiPi0, invMassXiPi0, float); +DECLARE_SOA_COLUMN(InvMassXiPi1, invMassXiPi1, float); +DECLARE_SOA_COLUMN(PBachelorPi, pBachelorPi, float); +DECLARE_SOA_COLUMN(PPiFromLambda, pPiFromLambda, float); +DECLARE_SOA_COLUMN(PPrFromLambda, pPrFromLambda, float); +// residuals and pulls +DECLARE_SOA_COLUMN(PtResidual, ptResidual, float); +DECLARE_SOA_COLUMN(PResidual, pResidual, float); +DECLARE_SOA_COLUMN(XPvResidual, xPvResidual, float); +DECLARE_SOA_COLUMN(YPvResidual, yPvResidual, float); +DECLARE_SOA_COLUMN(ZPvResidual, zPvResidual, float); +DECLARE_SOA_COLUMN(XPvPull, xPvPull, float); +DECLARE_SOA_COLUMN(YPvPull, yPvPull, float); +DECLARE_SOA_COLUMN(ZPvPull, zPvPull, float); +DECLARE_SOA_COLUMN(XSvResidual, xSvResidual, float); +DECLARE_SOA_COLUMN(YSvResidual, ySvResidual, float); +DECLARE_SOA_COLUMN(ZSvResidual, zSvResidual, float); +DECLARE_SOA_COLUMN(XSvPull, xSvPull, float); +DECLARE_SOA_COLUMN(YSvPull, ySvPull, float); +DECLARE_SOA_COLUMN(ZSvPull, zSvPull, float); +} // namespace full + +DECLARE_SOA_TABLE(HfCandXicToXiPiPiLites, "AOD", "HFXICXI2PILITE", + hf_cand_xic_to_xi_pi_pi::FlagMcMatchRec, + hf_cand_xic_to_xi_pi_pi::DebugMcRec, + hf_cand_xic_to_xi_pi_pi::OriginRec, + full::CandidateSelFlag, + full::Sign, + full::Y, + full::Eta, + full::Phi, + full::P, + full::Pt, + full::PtXi, + full::PtPi0, + full::PtPi1, + full::M, + full::InvMassXi, + full::InvMassLambda, + full::InvMassXiPi0, + full::InvMassXiPi1, + full::Chi2Sv, + full::Ct, + full::DecayLength, + full::DecayLengthNormalised, + full::DecayLengthXY, + full::DecayLengthXYNormalised, + full::Cpa, + full::CpaXY, + full::CpaXi, + full::CpaXYXi, + full::CpaLam, + full::CpaXYLam, + full::ImpactParameterXi, + full::ImpactParameterNormalisedXi, + full::ImpactParameterPi0, + full::ImpactParameterNormalisedPi0, + full::ImpactParameterPi1, + full::ImpactParameterNormalisedPi1, + full::MaxNormalisedDeltaIP); + +DECLARE_SOA_TABLE(HfCandXicToXiPiPiLiteKfs, "AOD", "HFXICXI2PILITKF", + hf_cand_xic_to_xi_pi_pi::FlagMcMatchRec, + hf_cand_xic_to_xi_pi_pi::DebugMcRec, + hf_cand_xic_to_xi_pi_pi::OriginRec, + full::CandidateSelFlag, + full::Sign, + full::Y, + full::Eta, + full::Phi, + full::P, + full::Pt, + full::PtXi, + full::PtPi0, + full::PtPi1, + full::M, + full::InvMassXi, + full::InvMassLambda, + full::InvMassXiPi0, + full::InvMassXiPi1, + full::Chi2Sv, + full::Ct, + full::DecayLength, + full::DecayLengthNormalised, + full::DecayLengthXY, + full::DecayLengthXYNormalised, + full::Cpa, + full::CpaXY, + full::CpaXi, + full::CpaXYXi, + full::CpaLam, + full::CpaXYLam, + full::ImpactParameterXi, + full::ImpactParameterNormalisedXi, + full::ImpactParameterPi0, + full::ImpactParameterNormalisedPi0, + full::ImpactParameterPi1, + full::ImpactParameterNormalisedPi1, + full::MaxNormalisedDeltaIP, + // KF specific columns + full::Chi2XiVtx, + full::Chi2LamVtx, + full::Chi2TopoXicPlusToPVBeforeConstraint, + full::Chi2TopoXicPlusToPV, + full::Chi2TopoXiToXicPlusBeforeConstraint, + full::Chi2TopoXiToXicPlus, + full::DcaXYPi0Pi1, + full::DcaXYPi0Xi, + full::DcaXYPi1Xi, + full::DcaPi0Pi1, + full::DcaPi0Xi, + full::DcaPi1Xi); + +DECLARE_SOA_TABLE(HfCandXicToXiPiPiFulls, "AOD", "HFXICXI2PIFULL", + hf_cand_xic_to_xi_pi_pi::FlagMcMatchRec, + hf_cand_xic_to_xi_pi_pi::DebugMcRec, + hf_cand_xic_to_xi_pi_pi::OriginRec, + full::CandidateSelFlag, + full::Sign, + full::Y, + full::Eta, + full::Phi, + full::P, + full::Pt, + full::PtXi, + full::PtPi0, + full::PtPi1, + full::M, + full::InvMassXi, + full::InvMassLambda, + full::InvMassXiPi0, + full::InvMassXiPi1, + full::Chi2Sv, + full::Ct, + full::DecayLength, + full::DecayLengthNormalised, + full::DecayLengthXY, + full::DecayLengthXYNormalised, + full::Cpa, + full::CpaXY, + full::CpaXi, + full::CpaXYXi, + full::CpaLam, + full::CpaXYLam, + full::ImpactParameterXi, + full::ImpactParameterNormalisedXi, + full::ImpactParameterPi0, + full::ImpactParameterNormalisedPi0, + full::ImpactParameterPi1, + full::ImpactParameterNormalisedPi1, + full::MaxNormalisedDeltaIP, + // additional columns only stored in the full candidate table + full::CpaLamToXi, + full::CpaXYLamToXi, + full::PPi0, + full::PPi1, + full::PBachelorPi, + full::PPiFromLambda, + full::PPrFromLambda, + hf_cand_xic_to_xi_pi_pi::DcaXiDaughters, + hf_cand_xic_to_xi_pi_pi::DcaV0Daughters, + hf_cand_xic_to_xi_pi_pi::DcaPosToPV, + hf_cand_xic_to_xi_pi_pi::DcaNegToPV, + hf_cand_xic_to_xi_pi_pi::DcaBachelorToPV, + hf_cand_xic_to_xi_pi_pi::DcaXYCascToPV, + hf_cand_xic_to_xi_pi_pi::DcaZCascToPV, + hf_cand_xic_to_xi_pi_pi::NSigTpcPiFromXicPlus0, + hf_cand_xic_to_xi_pi_pi::NSigTpcPiFromXicPlus1, + hf_cand_xic_to_xi_pi_pi::NSigTpcBachelorPi, + hf_cand_xic_to_xi_pi_pi::NSigTpcPiFromLambda, + hf_cand_xic_to_xi_pi_pi::NSigTpcPrFromLambda, + hf_cand_xic_to_xi_pi_pi::NSigTofPiFromXicPlus0, + hf_cand_xic_to_xi_pi_pi::NSigTofPiFromXicPlus1, + hf_cand_xic_to_xi_pi_pi::NSigTofBachelorPi, + hf_cand_xic_to_xi_pi_pi::NSigTofPiFromLambda, + hf_cand_xic_to_xi_pi_pi::NSigTofPrFromLambda); + +DECLARE_SOA_TABLE(HfCandXicToXiPiPiFullKfs, "AOD", "HFXICXI2PIFULKF", + hf_cand_xic_to_xi_pi_pi::FlagMcMatchRec, + hf_cand_xic_to_xi_pi_pi::DebugMcRec, + hf_cand_xic_to_xi_pi_pi::OriginRec, + full::CandidateSelFlag, + full::Sign, + full::Y, + full::Eta, + full::Phi, + full::P, + full::Pt, + full::PtXi, + full::PtPi0, + full::PtPi1, + full::M, + full::InvMassXi, + full::InvMassLambda, + full::InvMassXiPi0, + full::InvMassXiPi1, + full::Chi2Sv, + full::Ct, + full::DecayLength, + full::DecayLengthNormalised, + full::DecayLengthXY, + full::DecayLengthXYNormalised, + full::Cpa, + full::CpaXY, + full::CpaXi, + full::CpaXYXi, + full::CpaLam, + full::CpaXYLam, + full::ImpactParameterXi, + full::ImpactParameterNormalisedXi, + full::ImpactParameterPi0, + full::ImpactParameterNormalisedPi0, + full::ImpactParameterPi1, + full::ImpactParameterNormalisedPi1, + full::MaxNormalisedDeltaIP, + // additional columns only stored in the full candidate table + full::CpaLamToXi, + full::CpaXYLamToXi, + full::PPi0, + full::PPi1, + full::PBachelorPi, + full::PPiFromLambda, + full::PPrFromLambda, + hf_cand_xic_to_xi_pi_pi::DcaXiDaughters, + hf_cand_xic_to_xi_pi_pi::DcaV0Daughters, + hf_cand_xic_to_xi_pi_pi::DcaPosToPV, + hf_cand_xic_to_xi_pi_pi::DcaNegToPV, + hf_cand_xic_to_xi_pi_pi::DcaBachelorToPV, + hf_cand_xic_to_xi_pi_pi::DcaXYCascToPV, + hf_cand_xic_to_xi_pi_pi::DcaZCascToPV, + hf_cand_xic_to_xi_pi_pi::NSigTpcPiFromXicPlus0, + hf_cand_xic_to_xi_pi_pi::NSigTpcPiFromXicPlus1, + hf_cand_xic_to_xi_pi_pi::NSigTpcBachelorPi, + hf_cand_xic_to_xi_pi_pi::NSigTpcPiFromLambda, + hf_cand_xic_to_xi_pi_pi::NSigTpcPrFromLambda, + hf_cand_xic_to_xi_pi_pi::NSigTofPiFromXicPlus0, + hf_cand_xic_to_xi_pi_pi::NSigTofPiFromXicPlus1, + hf_cand_xic_to_xi_pi_pi::NSigTofBachelorPi, + hf_cand_xic_to_xi_pi_pi::NSigTofPiFromLambda, + hf_cand_xic_to_xi_pi_pi::NSigTofPrFromLambda, + // KF-specific columns + full::Chi2XiVtx, + full::Chi2LamVtx, + full::Chi2TopoXicPlusToPVBeforeConstraint, + full::Chi2TopoXicPlusToPV, + full::Chi2TopoXiToXicPlusBeforeConstraint, + full::Chi2TopoXiToXicPlus, + full::DcaXYPi0Pi1, + full::DcaXYPi0Xi, + full::DcaXYPi1Xi, + full::DcaPi0Pi1, + full::DcaPi0Xi, + full::DcaPi1Xi); + +DECLARE_SOA_TABLE(HfCandXicToXiPiPiFullPs, "AOD", "HFXICXI2PIFULLP", + hf_cand_xic_to_xi_pi_pi::FlagMcMatchGen, + hf_cand_xic_to_xi_pi_pi::DebugMcGen, + hf_cand_xic_to_xi_pi_pi::OriginGen, + full::Pt, + full::Eta, + full::Phi, + full::Y); + +DECLARE_SOA_TABLE(HfCandXicToXiPiPiResiduals, "AOD", "HFXICXI2PIRESID", + hf_cand_xic_to_xi_pi_pi::OriginGen, + full::PResidual, + full::PtResidual, + full::XPvResidual, + full::YPvResidual, + full::ZPvResidual, + full::XPvPull, + full::YPvPull, + full::ZPvPull, + full::XSvResidual, + full::YSvResidual, + full::ZSvResidual, + full::XSvPull, + full::YSvPull, + full::ZSvPull); +} // namespace o2::aod + +/// Writes the full information in an output TTree +struct HfTreeCreatorXicToXiPiPi { + Produces rowCandidateLite; + Produces rowCandidateLiteKf; + Produces rowCandidateFull; + Produces rowCandidateFullKf; + Produces rowCandidateFullParticles; + Produces rowCandidateResiduals; + + Configurable selectionFlagXic{"selectionFlagXic", 1, "Selection Flag for Xic"}; + Configurable fillCandidateLiteTable{"fillCandidateLiteTable", false, "Switch to fill lite table with candidate properties"}; + Configurable fillGenParticleTable{"fillGenParticleTable", false, "Switch to fill table with MC truth for generated particles"}; + // parameters for production of training samples + Configurable fillOnlySignal{"fillOnlySignal", false, "Flag to fill derived tables with signal for ML trainings"}; + Configurable fillOnlyBackground{"fillOnlyBackground", false, "Flag to fill derived tables with background for ML trainings"}; + Configurable downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of background candidates to keep for ML trainings"}; + Configurable ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"}; + + using SelectedCandidates = soa::Filtered>; + using SelectedCandidatesKf = soa::Filtered>; + using SelectedCandidatesMc = soa::Filtered>; + using SelectedCandidatesKfMc = soa::Filtered>; + + Filter filterSelectCandidates = aod::hf_sel_candidate_xic::isSelXicToXiPiPi >= selectionFlagXic; + + Partition recSig = nabs(aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchRec) != int8_t(0); + Partition recBg = nabs(aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchRec) == int8_t(0); + Partition recSigKf = nabs(aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchRec) != int8_t(0); + Partition recBgKf = nabs(aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchRec) == int8_t(0); + + void init(InitContext const&) + { + } + + template + void fillCandidateTable(const T& candidate) + { + int8_t flagMc = 0; + int8_t debugMc = 0; + int8_t originMc = 0; + if constexpr (doMc) { + flagMc = candidate.flagMcMatchRec(); + debugMc = candidate.debugMcRec(); + originMc = candidate.originRec(); + } + if constexpr (!doKf) { + if (fillCandidateLiteTable) { + rowCandidateLite( + flagMc, + debugMc, + originMc, + candidate.isSelXicToXiPiPi(), + candidate.sign(), + candidate.y(o2::constants::physics::MassXiCPlus), + candidate.eta(), + candidate.phi(), + candidate.p(), + candidate.pt(), + candidate.ptProng0(), + candidate.ptProng1(), + candidate.ptProng2(), + candidate.invMassXicPlus(), + candidate.invMassXi(), + candidate.invMassLambda(), + candidate.invMassXiPi0(), + candidate.invMassXiPi1(), + candidate.chi2PCA(), + candidate.ct(o2::constants::physics::MassXiCPlus), + candidate.decayLength(), + candidate.decayLengthNormalised(), + candidate.decayLengthXY(), + candidate.decayLengthXYNormalised(), + candidate.cpa(), + candidate.cpaXY(), + candidate.cosPaXi(), + candidate.cosPaXYXi(), + candidate.cosPaLambda(), + candidate.cosPaXYLambda(), + candidate.impactParameter0(), + candidate.impactParameterNormalised0(), + candidate.impactParameter1(), + candidate.impactParameterNormalised1(), + candidate.impactParameter2(), + candidate.impactParameterNormalised2(), + candidate.maxNormalisedDeltaIP()); + } else { + rowCandidateFull( + flagMc, + debugMc, + originMc, + candidate.isSelXicToXiPiPi(), + candidate.sign(), + candidate.y(o2::constants::physics::MassXiCPlus), + candidate.eta(), + candidate.phi(), + candidate.p(), + candidate.pt(), + candidate.ptProng0(), + candidate.ptProng1(), + candidate.ptProng2(), + candidate.invMassXicPlus(), + candidate.invMassXi(), + candidate.invMassLambda(), + candidate.invMassXiPi0(), + candidate.invMassXiPi1(), + candidate.chi2PCA(), + candidate.ct(o2::constants::physics::MassXiCPlus), + candidate.decayLength(), + candidate.decayLengthNormalised(), + candidate.decayLengthXY(), + candidate.decayLengthXYNormalised(), + candidate.cpa(), + candidate.cpaXY(), + candidate.cosPaXi(), + candidate.cosPaXYXi(), + candidate.cosPaLambda(), + candidate.cosPaXYLambda(), + candidate.impactParameter0(), + candidate.impactParameterNormalised0(), + candidate.impactParameter1(), + candidate.impactParameterNormalised1(), + candidate.impactParameter2(), + candidate.impactParameterNormalised2(), + candidate.maxNormalisedDeltaIP(), + // additional columns only stored in the full candidate table + candidate.cosPaLambdaToXi(), + candidate.cosPaXYLambdaToXi(), + candidate.pProng1(), + candidate.pProng2(), + candidate.pBachelorPi(), + candidate.pPiFromLambda(), + candidate.pPrFromLambda(), + candidate.dcaXiDaughters(), + candidate.dcaV0Daughters(), + candidate.dcaPosToPV(), + candidate.dcaNegToPV(), + candidate.dcaBachelorToPV(), + candidate.dcaXYCascToPV(), + candidate.dcaZCascToPV(), + candidate.nSigTpcPiFromXicPlus0(), + candidate.nSigTpcPiFromXicPlus1(), + candidate.nSigTpcBachelorPi(), + candidate.nSigTpcPiFromLambda(), + candidate.nSigTpcPrFromLambda(), + candidate.nSigTofPiFromXicPlus0(), + candidate.nSigTofPiFromXicPlus1(), + candidate.nSigTofBachelorPi(), + candidate.nSigTofPiFromLambda(), + candidate.nSigTofPrFromLambda()); + } + } else { + if (fillCandidateLiteTable) { + rowCandidateLiteKf( + flagMc, + debugMc, + originMc, + candidate.isSelXicToXiPiPi(), + candidate.sign(), + candidate.y(o2::constants::physics::MassXiCPlus), + candidate.eta(), + candidate.phi(), + candidate.p(), + candidate.pt(), + candidate.ptProng0(), + candidate.ptProng1(), + candidate.ptProng2(), + candidate.invMassXicPlus(), + candidate.invMassXi(), + candidate.invMassLambda(), + candidate.invMassXiPi0(), + candidate.invMassXiPi1(), + candidate.chi2PCA(), + candidate.ct(o2::constants::physics::MassXiCPlus), + candidate.kfDecayLength(), + candidate.kfDecayLengthNormalised(), + candidate.kfDecayLengthXY(), + candidate.kfDecayLengthXYNormalised(), + candidate.cpa(), + candidate.cpaXY(), + candidate.cosPaXi(), + candidate.cosPaXYXi(), + candidate.cosPaLambda(), + candidate.cosPaXYLambda(), + candidate.impactParameter0(), + candidate.impactParameterNormalised0(), + candidate.impactParameter1(), + candidate.impactParameterNormalised1(), + candidate.impactParameter2(), + candidate.impactParameterNormalised2(), + candidate.maxNormalisedDeltaIP(), + // KF-specific columns + candidate.kfCascadeChi2(), + candidate.kfV0Chi2(), + candidate.chi2TopoXicPlusToPVBeforeConstraint(), + candidate.chi2TopoXicPlusToPV(), + candidate.chi2TopoXiToXicPlusBeforeConstraint(), + candidate.chi2TopoXiToXicPlus(), + candidate.dcaXYPi0Pi1(), + candidate.dcaXYPi0Xi(), + candidate.dcaXYPi1Xi(), + candidate.dcaPi0Pi1(), + candidate.dcaPi0Xi(), + candidate.dcaPi1Xi()); + } else { + rowCandidateFullKf( + flagMc, + debugMc, + originMc, + candidate.isSelXicToXiPiPi(), + candidate.sign(), + candidate.y(o2::constants::physics::MassXiCPlus), + candidate.eta(), + candidate.phi(), + candidate.p(), + candidate.pt(), + candidate.ptProng0(), + candidate.ptProng1(), + candidate.ptProng2(), + candidate.invMassXicPlus(), + candidate.invMassXi(), + candidate.invMassLambda(), + candidate.invMassXiPi0(), + candidate.invMassXiPi1(), + candidate.chi2PCA(), + candidate.ct(o2::constants::physics::MassXiCPlus), + candidate.kfDecayLength(), + candidate.kfDecayLengthNormalised(), + candidate.kfDecayLengthXY(), + candidate.kfDecayLengthXYNormalised(), + candidate.cpa(), + candidate.cpaXY(), + candidate.cosPaXi(), + candidate.cosPaXYXi(), + candidate.cosPaLambda(), + candidate.cosPaXYLambda(), + candidate.impactParameter0(), + candidate.impactParameterNormalised0(), + candidate.impactParameter1(), + candidate.impactParameterNormalised1(), + candidate.impactParameter2(), + candidate.impactParameterNormalised2(), + candidate.maxNormalisedDeltaIP(), + // additional columns only stored in the full candidate table + candidate.cosPaLambdaToXi(), + candidate.cosPaXYLambdaToXi(), + candidate.pProng1(), + candidate.pProng2(), + candidate.pBachelorPi(), + candidate.pPiFromLambda(), + candidate.pPrFromLambda(), + candidate.dcaXiDaughters(), + candidate.dcaV0Daughters(), + candidate.dcaPosToPV(), + candidate.dcaNegToPV(), + candidate.dcaBachelorToPV(), + candidate.dcaXYCascToPV(), + candidate.dcaZCascToPV(), + candidate.nSigTpcPiFromXicPlus0(), + candidate.nSigTpcPiFromXicPlus1(), + candidate.nSigTpcBachelorPi(), + candidate.nSigTpcPiFromLambda(), + candidate.nSigTpcPrFromLambda(), + candidate.nSigTofPiFromXicPlus0(), + candidate.nSigTofPiFromXicPlus1(), + candidate.nSigTofBachelorPi(), + candidate.nSigTofPiFromLambda(), + candidate.nSigTofPrFromLambda(), + // KF-specific columns + candidate.kfCascadeChi2(), + candidate.kfV0Chi2(), + candidate.chi2TopoXicPlusToPVBeforeConstraint(), + candidate.chi2TopoXicPlusToPV(), + candidate.chi2TopoXiToXicPlusBeforeConstraint(), + candidate.chi2TopoXiToXicPlus(), + candidate.dcaXYPi0Pi1(), + candidate.dcaXYPi0Xi(), + candidate.dcaXYPi1Xi(), + candidate.dcaPi0Pi1(), + candidate.dcaPi0Xi(), + candidate.dcaPi1Xi()); + } + } + } + + void processData(SelectedCandidates const& candidates) + { + // Filling candidate properties + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(candidates.size()); + } else { + rowCandidateFull.reserve(candidates.size()); + } + for (const auto& candidate : candidates) { + if (fillOnlyBackground && downSampleBkgFactor < 1.) { + float pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); + if (pseudoRndm >= downSampleBkgFactor && candidate.pt() < ptMaxForDownSample) { + continue; + } + } + fillCandidateTable(candidate); + } + } + PROCESS_SWITCH(HfTreeCreatorXicToXiPiPi, processData, "Process data with DCAFitter reconstruction", true); + + void processDataKf(SelectedCandidatesKf const& candidates) + { + // Filling candidate properties + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(candidates.size()); + } else { + rowCandidateFull.reserve(candidates.size()); + } + for (const auto& candidate : candidates) { + if (fillOnlyBackground && downSampleBkgFactor < 1.) { + float pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); + if (pseudoRndm >= downSampleBkgFactor && candidate.pt() < ptMaxForDownSample) { + continue; + } + } + fillCandidateTable(candidate); + } + } + PROCESS_SWITCH(HfTreeCreatorXicToXiPiPi, processDataKf, "Process data with KFParticle reconstruction", false); + + void processMc(SelectedCandidatesMc const& candidates, + soa::Join const& particles) + { + // Filling candidate properties + if (fillOnlySignal) { + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(recSig.size()); + } else { + rowCandidateFull.reserve(recSig.size()); + } + for (const auto& candidate : recSig) { + fillCandidateTable(candidate); + } + } else if (fillOnlyBackground) { + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(recBg.size()); + } else { + rowCandidateFull.reserve(recBg.size()); + } + for (const auto& candidate : recBg) { + float pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + fillCandidateTable(candidate); + } + } else { + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(candidates.size()); + } else { + rowCandidateFull.reserve(candidates.size()); + } + for (const auto& candidate : candidates) { + fillCandidateTable(candidate); + } + } + + if (fillGenParticleTable) { + rowCandidateFullParticles.reserve(particles.size()); + + for (const auto& particle : particles) { + if (TESTBIT(std::abs(particle.flagMcMatchGen()), aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiPiPi) || TESTBIT(std::abs(particle.flagMcMatchGen()), aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiResPiToXiPiPi)) { + rowCandidateFullParticles( + particle.flagMcMatchGen(), + particle.debugMcGen(), + particle.originGen(), + particle.pt(), + particle.eta(), + particle.phi(), + RecoDecay::y(particle.pVector(), o2::constants::physics::MassXiCPlus)); + } + } // loop over generated particles + } + } + PROCESS_SWITCH(HfTreeCreatorXicToXiPiPi, processMc, "Process MC with DCAFitter reconstruction", false); + + void processMcKf(SelectedCandidatesKfMc const& candidates, + soa::Join const& particles) + { + // Filling candidate properties + if (fillOnlySignal) { + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(recSigKf.size()); + } else { + rowCandidateFull.reserve(recSigKf.size()); + } + for (const auto& candidate : recSigKf) { + fillCandidateTable(candidate); + } + } else if (fillOnlyBackground) { + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(recBgKf.size()); + } else { + rowCandidateFull.reserve(recBgKf.size()); + } + for (const auto& candidate : recBgKf) { + float pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + fillCandidateTable(candidate); + } + } else { + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(candidates.size()); + } else { + rowCandidateFull.reserve(candidates.size()); + } + for (const auto& candidate : candidates) { + fillCandidateTable(candidate); + } + } + + if (fillGenParticleTable) { + rowCandidateFullParticles.reserve(particles.size()); + for (const auto& particle : particles) { + if (TESTBIT(std::abs(particle.flagMcMatchGen()), aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiPiPi) || TESTBIT(std::abs(particle.flagMcMatchGen()), aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiResPiToXiPiPi)) { + rowCandidateFullParticles( + particle.flagMcMatchGen(), + particle.debugMcGen(), + particle.originGen(), + particle.pt(), + particle.eta(), + particle.phi(), + RecoDecay::y(particle.pVector(), o2::constants::physics::MassXiCPlus)); + } + } // loop over generated particles + } + } + PROCESS_SWITCH(HfTreeCreatorXicToXiPiPi, processMcKf, "Process MC with KF Particle reconstruction", false); + + void processResiduals(SelectedCandidatesMc const&, + aod::TracksWMc const& tracks, + aod::McParticles const& particles, + aod::McCollisions const&) + { + rowCandidateResiduals.reserve(recSig.size()); + + recSig->bindExternalIndices(&tracks); + + std::vector arrDaughIndex; + int indexRecXicPlus; + int8_t sign; + int8_t origin; + std::array pvResiduals; + std::array svResiduals; + std::array pvPulls; + std::array svPulls; + + for (const auto& candidate : recSig) { + arrDaughIndex.clear(); + indexRecXicPlus = -1; + sign = 0; + origin = 0; + pvResiduals = {-9999.9}; + svResiduals = {-9999.9}; + pvPulls = {-9999.9}; + svPulls = {-9999.9}; + + auto arrayDaughters = std::array{candidate.pi0_as(), // pi <- Xic + candidate.pi1_as(), // pi <- Xic + candidate.bachelor_as(), // pi <- cascade + candidate.posTrack_as(), // p <- lambda + candidate.negTrack_as()}; // pi <- lambda + + // get XicPlus as MC particle + indexRecXicPlus = RecoDecay::getMatchedMCRec(particles, arrayDaughters, Pdg::kXiCPlus, std::array{+kPiPlus, +kPiPlus, +kPiMinus, +kProton, +kPiMinus}, true, &sign, 4); + if (indexRecXicPlus == -1) { + continue; + } + auto particleXicPlusGen = particles.rawIteratorAt(indexRecXicPlus); + origin = RecoDecay::getCharmHadronOrigin(particles, particleXicPlusGen, true); + + // get MC collision + auto mcCollision = particleXicPlusGen.mcCollision_as(); + + // get XicPlus daughters as MC particle + RecoDecay::getDaughters(particleXicPlusGen, &arrDaughIndex, std::array{+kXiMinus, +kPiPlus, +kPiPlus}, 2); + auto daugh0XicPlus = particles.rawIteratorAt(arrDaughIndex[0]); + + // calculate residuals and pulls + float pResidual = candidate.p() - particleXicPlusGen.p(); + float ptResidual = candidate.pt() - particleXicPlusGen.pt(); + pvResiduals[0] = candidate.posX() - mcCollision.posX(); + pvResiduals[1] = candidate.posY() - mcCollision.posY(); + pvResiduals[2] = candidate.posZ() - mcCollision.posZ(); + svResiduals[0] = candidate.xSecondaryVertex() - daugh0XicPlus.vx(); + svResiduals[1] = candidate.ySecondaryVertex() - daugh0XicPlus.vy(); + svResiduals[2] = candidate.zSecondaryVertex() - daugh0XicPlus.vz(); + try { + pvPulls[0] = pvResiduals[0] / candidate.xPvErr(); + pvPulls[1] = pvResiduals[1] / candidate.yPvErr(); + pvPulls[2] = pvResiduals[2] / candidate.zPvErr(); + svPulls[0] = svResiduals[0] / candidate.xSvErr(); + svPulls[1] = svResiduals[1] / candidate.ySvErr(); + svPulls[2] = svResiduals[2] / candidate.zSvErr(); + } catch (const std::runtime_error& error) { + LOG(info) << "Run time error found: " << error.what() << ". Set values of vertex pulls to -9999.9."; + } + + // fill table + rowCandidateResiduals( + origin, + pResidual, + ptResidual, + pvResiduals[0], + pvResiduals[1], + pvResiduals[2], + pvPulls[0], + pvPulls[1], + pvPulls[2], + svResiduals[0], + svResiduals[1], + svResiduals[2], + svPulls[0], + svPulls[1], + svPulls[2]); + } // loop over reconstructed signal + } + PROCESS_SWITCH(HfTreeCreatorXicToXiPiPi, processResiduals, "Process Residuals and pulls for both DCAFitter and KFParticle reconstruction", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/Tasks/CMakeLists.txt b/PWGHF/Tasks/CMakeLists.txt index bc8901298db..658988d070a 100644 --- a/PWGHF/Tasks/CMakeLists.txt +++ b/PWGHF/Tasks/CMakeLists.txt @@ -9,11 +9,16 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. -o2physics_add_dpl_workflow(task-lc-centrality - SOURCES taskLcCentrality.cxx +o2physics_add_dpl_workflow(task-charm-had-impact-par + SOURCES taskCharmHadImpactPar.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +# o2physics_add_dpl_workflow(task-lc-centrality +# SOURCES taskLcCentrality.cxx +# PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore +# COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(task-mc-efficiency SOURCES taskMcEfficiency.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -24,12 +29,27 @@ o2physics_add_dpl_workflow(task-mc-efficiency-to-xi-pi PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(task-mc-gen-pt-rap-shapes + SOURCES taskMcGenPtRapShapes.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(task-mc-validation SOURCES taskMcValidation.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(task-sel-optimisation - SOURCES taskSelOptimisation.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore +o2physics_add_dpl_workflow(task-multiplicity-estimator-correlation + SOURCES taskMultiplicityEstimatorCorrelation.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(task-pid-studies + SOURCES taskPidStudies.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) + +# o2physics_add_dpl_workflow(task-sel-optimisation +# SOURCES taskSelOptimisation.cxx +# PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore +# COMPONENT_NAME Analysis) diff --git a/PWGHF/Tasks/taskCharmHadImpactPar.cxx b/PWGHF/Tasks/taskCharmHadImpactPar.cxx new file mode 100644 index 00000000000..051fdd0b7a2 --- /dev/null +++ b/PWGHF/Tasks/taskCharmHadImpactPar.cxx @@ -0,0 +1,373 @@ +// 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 taskCharmHadImpactPar.cxx +/// \brief Analysis task to produce impact-parameter distributions of charm hadrons +/// +/// \author Fabrizio Grosa , CERN +/// \author Antonio Palasciano , INFN Bari + +#include +#include + +#include "Common/Core/RecoDecay.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsEvSelHf.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::analysis; +using namespace o2::constants::math; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::hf_centrality; +using namespace o2::hf_occupancy; + +enum Channel : uint8_t { + DplusToKPiPi = 0, + DzeroToKPi, + NChannels +}; + +namespace o2::aod +{ +namespace hf_charm_cand_lite +{ +DECLARE_SOA_COLUMN(Centrality, centrality, float); //! Centrality (or multiplicity) percentile +DECLARE_SOA_COLUMN(Occupancy, occupancy, float); //! Occupancy +DECLARE_SOA_COLUMN(M, m, float); //! Invariant mass of candidate (GeV/c2) +DECLARE_SOA_COLUMN(Pt, pt, float); //! Transverse momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(Y, y, float); //! Rapidity of candidate +DECLARE_SOA_COLUMN(Phi, phi, float); //! Azimuth angle of candidate +DECLARE_SOA_COLUMN(ImpactParameterXY, impactParameterXY, float); //! Dca XY of candidate +DECLARE_SOA_COLUMN(ImpactParameterZ, impactParameterZ, float); //! Dca Z of candidate +DECLARE_SOA_COLUMN(MlScoreBkg, mlScoreBkg, float); //! ML score for background class +DECLARE_SOA_COLUMN(MlScorePrompt, mlScorePrompt, float); //! ML Prompt score for prompt class +DECLARE_SOA_COLUMN(MlScoreNonPrompt, mlScoreNonPrompt, float); //! ML Non Prompt score for non prompt class +DECLARE_SOA_COLUMN(PtProng0, ptProng0, float); //! Pt of the 1st daughter +DECLARE_SOA_COLUMN(PtProng1, ptProng1, float); //! Pt of the 2nd daughter +DECLARE_SOA_COLUMN(PtProng2, ptProng2, float); //! Pt of the 3rd daughter (if present) +DECLARE_SOA_COLUMN(PhiProng0, phiProng0, float); //! Phi of the 1st daughter +DECLARE_SOA_COLUMN(PhiProng1, phiProng1, float); //! Phi of the 2nd daughter +DECLARE_SOA_COLUMN(PhiProng2, phiProng2, float); //! Phi of the 3rd daughter (if present) +DECLARE_SOA_COLUMN(EtaProng0, etaProng0, float); //! Eta of the 1st daughter +DECLARE_SOA_COLUMN(EtaProng1, etaProng1, float); //! Eta of the 2nd daughter +DECLARE_SOA_COLUMN(EtaProng2, etaProng2, float); //! Eta of the 3rd daughter (if present) +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); //! Flag for reconstruction level matching +} // namespace hf_charm_cand_lite + +DECLARE_SOA_TABLE(HfCharmCandLites, "AOD", "HFCHARMCANDLITE", //! Table with some charm hadron properties + collision::NumContrib, + collision::PosX, + collision::PosY, + collision::PosZ, + hf_charm_cand_lite::Centrality, + hf_charm_cand_lite::Occupancy, + hf_cand::XSecondaryVertex, + hf_cand::YSecondaryVertex, + hf_cand::ZSecondaryVertex, + hf_charm_cand_lite::M, + hf_charm_cand_lite::Pt, + hf_charm_cand_lite::Y, + hf_charm_cand_lite::Phi, + hf_charm_cand_lite::ImpactParameterXY, + hf_charm_cand_lite::ImpactParameterZ, + hf_charm_cand_lite::MlScoreBkg, + hf_charm_cand_lite::MlScorePrompt, + hf_charm_cand_lite::MlScoreNonPrompt, + hf_charm_cand_lite::PtProng0, + hf_charm_cand_lite::PtProng1, + hf_charm_cand_lite::PtProng2, + hf_charm_cand_lite::PhiProng0, + hf_charm_cand_lite::PhiProng1, + hf_charm_cand_lite::PhiProng2, + hf_charm_cand_lite::EtaProng0, + hf_charm_cand_lite::EtaProng1, + hf_charm_cand_lite::EtaProng2, + hf_charm_cand_lite::FlagMcMatchRec); +} // namespace o2::aod + +struct HfTaskCharmHadImpactPar { + Produces hfCharmCandLite; + + Configurable selectionFlag{"selectionFlag", 15, "Selection Flag for the considered charm hadron"}; + Configurable fillLightTreeCandidate{"fillLightTreeCandidate", 0, "Flag to store charm hadron features"}; + Configurable centEstimator{"centEstimator", 0, "Centrality estimation (None: 0, FT0C: 2, FT0M: 3)"}; + Configurable occEstimator{"occEstimator", 0, "Occupancy estimation (None: 0, ITS: 1, FT0C: 2)"}; + Configurable fillOnlySignal{"fillOnlySignal", false, "Flag to store only matched candidates"}; + + HfHelper hfHelper; + + using Collisions = soa::Join; + using CollisionsCent = soa::Join; + using CandDplusData = soa::Filtered>; + using CandDplusDataWithMl = soa::Filtered>; + using CandDplusMC = soa::Filtered>; + using CandDplusMCWithMl = soa::Filtered>; + using CandDzeroData = soa::Filtered>; + using CandDzeroDataWithMl = soa::Filtered>; + using CandDzeroMc = soa::Filtered>; + using CandDzeroMcWithMl = soa::Filtered>; + + Filter filterDplusFlag = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlag; + Filter filterDzeroFlag = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlag || aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlag; + + ConfigurableAxis axisPt{"axisPt", {0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 8.f, 10.f, 12.f, 16.f, 24.f, 36.f, 50.f}, "axis for pT of charm hadron"}; + ConfigurableAxis axisMass{"axisMass", {250, 1.65f, 2.15f}, "axis for mass of charm hadron"}; + ConfigurableAxis axisPhi{"axisPhi", {180, 0.f, TwoPI}, "axis for azimuthal angle of charm hadron"}; + ConfigurableAxis axisY{"axisY", {20, -1.f, 1.f}, "axis for rapidity of charm hadron"}; + ConfigurableAxis axisImpPar{"axisImpPar", {2000, -500.f, 500.f}, "axis for impact-parameter of charm hadron"}; + ConfigurableAxis axisMlScore0{"axisMlScore0", {100, 0.f, 1.f}, "axis for ML output score 0"}; + ConfigurableAxis axisMlScore1{"axisMlScore1", {100, 0.f, 1.f}, "axis for ML output score 1"}; + ConfigurableAxis axisMlScore2{"axisMlScore2", {100, 0.f, 1.f}, "axis for ML output score 2"}; + + HistogramRegistry registry{"registry"}; + + void init(InitContext&) + { + std::array doprocess{doprocessDataDplus, doprocessDataDplusWithMl, doprocessMCDplus, doprocessMCDplusWithMl, doprocessDataDzero, doprocessDataDzeroWithMl, doprocessMCDzero, doprocessMCDzeroWithMl}; + if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { + LOGP(fatal, "Only one process function should be enabled! Please check your configuration!"); + } + if (doprocessDataDplus || doprocessDataDzero || doprocessMCDplus || doprocessMCDzero) { + registry.add("hMassPtImpParPhiY", ";#it{M} (GeV/#it{c}^{2});#it{p}_{T} (GeV/#it{c});dca XY (#mum); phi; y;", HistType::kTHnSparseF, {axisMass, axisPt, axisImpPar, axisPhi, axisY}); + } else if (doprocessDataDplusWithMl || doprocessDataDzeroWithMl || doprocessMCDplusWithMl || doprocessMCDzeroWithMl) { + registry.add("hMassPtImpParPhiY", ";#it{M} (GeV/#it{c}^{2});#it{p}_{T} (GeV/#it{c});dca XY (#mum); phi; y; ML score 0;ML score 1; ML score 2;", HistType::kTHnSparseF, {axisMass, axisPt, axisImpPar, axisPhi, axisY, axisMlScore0, axisMlScore1, axisMlScore2}); + } + } + + // Fill THnSparses for the ML analysis + /// \param candidate is a particle candidate + template + void fillSparse(const CCands& candidate) + { + std::vector outputMl = {-999., -999., -999.}; + float invMass{-1.f}; + float yCand{-999.f}; + if constexpr (channel == Channel::DplusToKPiPi) { // D+ -> Kpipi + if constexpr (doMc) { + if (fillOnlySignal) { + if (std::abs(candidate.flagMcMatchRec()) != 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi) { + return; + } + } + } + invMass = hfHelper.invMassDplusToPiKPi(candidate); + yCand = hfHelper.yDplus(candidate); + if constexpr (withMl) { + for (auto iScore{0u}; iScore < candidate.mlProbDplusToPiKPi().size(); ++iScore) { + outputMl[iScore] = candidate.mlProbDplusToPiKPi()[iScore]; + } + registry.fill(HIST("hMassPtImpParPhiY"), invMass, candidate.pt(), candidate.impactParameterXY(), candidate.phi(), yCand, outputMl[0], outputMl[1], outputMl[2]); + } else { + registry.fill(HIST("hMassPtImpParPhiY"), invMass, candidate.pt(), candidate.impactParameterXY(), candidate.phi(), yCand); + } + } else if constexpr (channel == Channel::DzeroToKPi) { + if (candidate.isSelD0()) { // D0 -> Kpi + if constexpr (doMc) { + if (fillOnlySignal) { + if (std::abs(candidate.flagMcMatchRec()) != 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { + return; + } + } + } + invMass = hfHelper.invMassD0ToPiK(candidate); + yCand = hfHelper.yD0(candidate); + if constexpr (withMl) { + for (auto iScore{0u}; iScore < candidate.mlProbD0().size(); ++iScore) { + outputMl[iScore] = candidate.mlProbD0()[iScore]; + } + registry.fill(HIST("hMassPtImpParPhiY"), invMass, candidate.pt(), candidate.impactParameterXY(), candidate.phi(), yCand, outputMl[0], outputMl[1], outputMl[2]); + } else { + registry.fill(HIST("hMassPtImpParPhiY"), invMass, candidate.pt(), candidate.impactParameterXY(), candidate.phi(), yCand); + } + } + if (candidate.isSelD0bar()) { + invMass = hfHelper.invMassD0barToKPi(candidate); + yCand = hfHelper.yD0(candidate); + if constexpr (withMl) { + for (auto iScore{0u}; iScore < candidate.mlProbD0bar().size(); ++iScore) { + outputMl[iScore] = candidate.mlProbD0bar()[iScore]; + } + registry.fill(HIST("hMassPtImpParPhiY"), invMass, candidate.pt(), candidate.impactParameterXY(), candidate.phi(), yCand, outputMl[0], outputMl[1], outputMl[2]); + } else { + registry.fill(HIST("hMassPtImpParPhiY"), invMass, candidate.pt(), candidate.impactParameterXY(), candidate.phi(), yCand); + } + } + } + } + + // Fill the TTree with both event and candidate properties + /// \param candidate is a particle candidate + /// \param collision is the respective collision + template + void fillTree(const CCands& candidate, const CollType& collision) + { + std::vector outputMl = {-999., -999., -999.}; + float invMass{-1.f}; + float yCand{-999.f}; + std::array ptProngs = {candidate.ptProng0(), candidate.ptProng1(), -1.}; + std::array phiProngs = {RecoDecay::phi(std::array{candidate.pxProng0(), candidate.pyProng0()}), RecoDecay::phi(std::array{candidate.pxProng1(), candidate.pyProng1()}), 99.}; + std::array etaProngs = {RecoDecay::eta(std::array{candidate.pxProng0(), candidate.pyProng0(), candidate.pzProng0()}), RecoDecay::eta(std::array{candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1()}), 99.}; + if constexpr (channel == Channel::DplusToKPiPi) { // D+ -> Kpipi + invMass = hfHelper.invMassDplusToPiKPi(candidate); + yCand = hfHelper.yDplus(candidate); + ptProngs[2] = candidate.ptProng2(); + phiProngs[2] = RecoDecay::phi(candidate.pxProng2(), candidate.pyProng2()); + etaProngs[2] = RecoDecay::eta(std::array{candidate.pxProng2(), candidate.pyProng2(), candidate.pzProng2()}); + if constexpr (withMl) { + for (auto iScore{0u}; iScore < candidate.mlProbDplusToPiKPi().size(); ++iScore) { + outputMl[iScore] = candidate.mlProbDplusToPiKPi()[iScore]; + } + } + } else if constexpr (channel == Channel::DzeroToKPi) { + if (candidate.isSelD0()) { // D0 -> Kpi + invMass = hfHelper.invMassD0ToPiK(candidate); + yCand = hfHelper.yD0(candidate); + if constexpr (withMl) { + for (auto iScore{0u}; iScore < candidate.mlProbD0().size(); ++iScore) { + outputMl[iScore] = candidate.mlProbD0()[iScore]; + } + } + } + if (candidate.isSelD0bar()) { + invMass = hfHelper.invMassD0barToKPi(candidate); + yCand = hfHelper.yD0(candidate); + if constexpr (withMl) { + for (auto iScore{0u}; iScore < candidate.mlProbD0bar().size(); ++iScore) { + outputMl[iScore] = candidate.mlProbD0bar()[iScore]; + } + } + } + } + float centrality = 0.; + float occupancy = 0.; + if (centEstimator != CentralityEstimator::None) { + centrality = getCentralityColl(collision, centEstimator); + } + if (occEstimator != OccupancyEstimator::None) { + occupancy = getOccupancyColl(collision, occEstimator); + } + + int8_t flagMcMatchRec = 0; + if constexpr (doMc) { + flagMcMatchRec = candidate.flagMcMatchRec(); + } + double impParZ = candidate.impactParameterXY() * (-1) * candidate.pz() / candidate.pt(); + + hfCharmCandLite( + // Event features + collision.numContrib(), + collision.posX(), + collision.posY(), + collision.posZ(), + centrality, + occupancy, + // Charm candidate features + candidate.xSecondaryVertex(), + candidate.ySecondaryVertex(), + candidate.zSecondaryVertex(), + invMass, + candidate.pt(), + yCand, + candidate.phi(), + candidate.impactParameterXY(), + impParZ, + outputMl[0], + outputMl[1], + outputMl[2], + // Daughter features + ptProngs[0], + ptProngs[1], + ptProngs[2], + phiProngs[0], + phiProngs[1], + phiProngs[2], + etaProngs[0], + etaProngs[1], + etaProngs[2], + flagMcMatchRec); + } + + /// \param candidates are reconstructed candidates + template + void runAnalysis(const CCands& candidates, CollisionsCent const&) + { + for (auto const& candidate : candidates) { + auto collision = candidate.template collision_as(); + fillSparse(candidate); + if (fillLightTreeCandidate) { + fillTree(candidate, collision); + } + } + } + + // process functions + void processDataDplus(CandDplusData const& candidates, CollisionsCent const& collisions) + { + runAnalysis(candidates, collisions); + } + PROCESS_SWITCH(HfTaskCharmHadImpactPar, processDataDplus, "Process Data D+ w/o ML", false); + + void processDataDplusWithMl(CandDplusDataWithMl const& candidates, CollisionsCent const& collisions) + { + runAnalysis(candidates, collisions); + } + PROCESS_SWITCH(HfTaskCharmHadImpactPar, processDataDplusWithMl, "Process Data D+ with ML", true); + + void processMCDplus(CandDplusMC const& candidates, CollisionsCent const& collisions) + { + runAnalysis(candidates, collisions); + } + PROCESS_SWITCH(HfTaskCharmHadImpactPar, processMCDplus, "Process MC D+ w/o ML", false); + + void processMCDplusWithMl(CandDplusMCWithMl const& candidates, CollisionsCent const& collisions) + { + runAnalysis(candidates, collisions); + } + PROCESS_SWITCH(HfTaskCharmHadImpactPar, processMCDplusWithMl, "Process MC D+ with ML", false); + + void processDataDzero(CandDzeroData const& candidates, CollisionsCent const& collisions) + { + runAnalysis(candidates, collisions); + } + PROCESS_SWITCH(HfTaskCharmHadImpactPar, processDataDzero, "Process Data D0 w/o ML", false); + + void processDataDzeroWithMl(CandDzeroDataWithMl const& candidates, CollisionsCent const& collisions) + { + runAnalysis(candidates, collisions); + } + PROCESS_SWITCH(HfTaskCharmHadImpactPar, processDataDzeroWithMl, "Process Data D0 with ML", false); + + void processMCDzero(CandDzeroMc const& candidates, CollisionsCent const& collisions) + { + runAnalysis(candidates, collisions); + } + PROCESS_SWITCH(HfTaskCharmHadImpactPar, processMCDzero, "Process MC D0 w/o ML", false); + + void processMCDzeroWithMl(CandDzeroMcWithMl const& candidates, CollisionsCent const& collisions) + { + runAnalysis(candidates, collisions); + } + PROCESS_SWITCH(HfTaskCharmHadImpactPar, processMCDzeroWithMl, "Process MC D0 with ML", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/Tasks/taskLcCentrality.cxx b/PWGHF/Tasks/taskLcCentrality.cxx index aafdb93b8fe..091b70b66ec 100644 --- a/PWGHF/Tasks/taskLcCentrality.cxx +++ b/PWGHF/Tasks/taskLcCentrality.cxx @@ -16,6 +16,8 @@ /// \author Luigi Dello Stritto , University and INFN SALERNO /// \author Vít Kučera , CERN +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" diff --git a/PWGHF/Tasks/taskMcEfficiency.cxx b/PWGHF/Tasks/taskMcEfficiency.cxx index 024632dd7a1..410c3d67a8e 100644 --- a/PWGHF/Tasks/taskMcEfficiency.cxx +++ b/PWGHF/Tasks/taskMcEfficiency.cxx @@ -14,6 +14,12 @@ /// /// \author Jan Fiete Grosse-Oetringhaus, CERN +#include +#include +#include +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" @@ -39,7 +45,7 @@ struct HfTaskMcEfficiency { ConfigurableAxis axisPt{"axisPt", {10, 0, 10}, "pT axis"}; ConfigurableAxis axisMass{"axisMass", {120, 1.5848, 2.1848}, "m_inv axis"}; - ConfigurableAxis axisPdg{"axisPdg", {VARIABLE_WIDTH, -4122.5, -431.5, -421.5, -411.5, 0, 411.5, 421.5, 431.5, 4122.5}, "PDG code axis"}; + ConfigurableAxis axisPdg{"axisPdg", {VARIABLE_WIDTH, -4232.5, -4122.5, -431.5, -421.5, -411.5, 0, 411.5, 421.5, 431.5, 4122.5, 4232.5}, "PDG code axis"}; ConfigurableAxis axisCPA{"axisCPA", {102, -1.02, 1.02}, "Cosine of pointing angle axis"}; Configurable mcAcceptancePt{"mcAcceptancePt", 0.1, "MC Acceptance: lower pt limit"}; @@ -101,7 +107,7 @@ struct HfTaskMcEfficiency { return track.isGlobalTrackWoDCA(); } - template + template void candidate3ProngLoop(T1& candidates, T2& tracks, T3& mcParticles, std::vector pdgCodes) { using TracksType = std::decay_t; @@ -130,6 +136,11 @@ struct HfTaskMcEfficiency { pdgDaughters[0] = +kProton; pdgDaughters[1] = -kKPlus; pdgDaughters[2] = +kPiPlus; + } else if (pdgCode == Pdg::kXiCPlus) { + decayType = 1 << aod::hf_cand_3prong::DecayType::XicToPKPi; + pdgDaughters[0] = +kProton; + pdgDaughters[1] = -kKPlus; + pdgDaughters[2] = +kPiPlus; } else { LOGP(fatal, "Not implemented for PDG {}", pdgCode); } @@ -164,6 +175,12 @@ struct HfTaskMcEfficiency { isHypoMass2SelStep = candidate.isSelLcToPiKP(); } } + if constexpr (hasXicPlus) { + if (pdgCode == Pdg::kXiCPlus) { + isHypoMass1SelStep = candidate.isSelXicToPKPi(); + isHypoMass2SelStep = candidate.isSelXicToPiKP(); + } + } bool collisionMatched = false; int origin = RecoDecay::OriginType::None; @@ -194,6 +211,23 @@ struct HfTaskMcEfficiency { } } + if (pdgCode == Pdg::kXiCPlus) { + auto daughter = trackPos.mcParticle(); + if (std::abs(daughter.pdgCode()) == kProton) { + isHypoMass1TrackStep = true; + isHypoMass1SelStep = true; + isHypoMass2TrackStep = false; + isHypoMass2SelStep = false; + } else if (std::abs(daughter.pdgCode()) == kPiPlus) { + isHypoMass1TrackStep = false; + isHypoMass1SelStep = false; + isHypoMass2TrackStep = true; + isHypoMass2SelStep = true; + } else { + continue; + } + } + collisionMatched = candidate.template collision_as().mcCollisionId() == mcParticles.iteratorAt(indexRec).mcCollisionId(); } /// end info MC used @@ -207,6 +241,8 @@ struct HfTaskMcEfficiency { if (isHypoMass1TrackStep) { if (pdgCode == Pdg::kLambdaCPlus) { massHypo1 = hfHelper.invMassLcToPKPi(candidate); + } else if (pdgCode == Pdg::kXiCPlus) { + massHypo1 = hfHelper.invMassXicToPKPi(candidate); } else if (pdgCode == Pdg::kDPlus) { massHypo1 = hfHelper.invMassDplusToPiKPi(candidate); } else if (pdgCode == Pdg::kDS) { @@ -217,6 +253,8 @@ struct HfTaskMcEfficiency { if (isHypoMass2TrackStep) { if (pdgCode == Pdg::kLambdaCPlus) { massHypo2 = hfHelper.invMassLcToPiKP(candidate); + } else if (pdgCode == Pdg::kXiCPlus) { + massHypo2 = hfHelper.invMassXicToPiKP(candidate); } else if (pdgCode == Pdg::kDS) { massHypo2 = hfHelper.invMassDsToPiKK(candidate); } @@ -349,9 +387,9 @@ struct HfTaskMcEfficiency { /// put two 32-bit indices in a 64-bit integer int64_t hash = 0; if (candidate.prong0Id() < candidate.prong1Id()) { - hash = ((int64_t)candidate.prong0Id() << 32) | candidate.prong1Id(); + hash = (static_cast(candidate.prong0Id()) << 32) | candidate.prong1Id(); } else { - hash = ((int64_t)candidate.prong1Id() << 32) | candidate.prong0Id(); + hash = (static_cast(candidate.prong1Id()) << 32) | candidate.prong0Id(); } if (duplicates.find(hash) != duplicates.end()) { hCandidates->Fill(kHFStepTrackedDuplicates, pt, mass, pdgCode, cpa, collisionMatched, origin); @@ -481,10 +519,10 @@ struct HfTaskMcEfficiency { /// 3-prong analyses - template + template void candidate3ProngMcLoop(C const& candidates, TracksWithSelectionMC const& tracks, aod::McParticles const& mcParticles, aod::McCollisionLabels const&, std::vector pdgCodes) { - candidate3ProngLoop(candidates, tracks, mcParticles, pdgCodes); + candidate3ProngLoop(candidates, tracks, mcParticles, pdgCodes); auto hCandidates = registry.get(HIST("hCandidates")); auto hTrackablePtEta = registry.get(HIST("hTrackablePtEta")); @@ -535,6 +573,10 @@ struct HfTaskMcEfficiency { pdgDaughters[0] = +kProton; pdgDaughters[1] = -kKPlus; pdgDaughters[2] = +kPiPlus; + } else if (pdgCode == Pdg::kXiCPlus) { + pdgDaughters[0] = +kProton; + pdgDaughters[1] = -kKPlus; + pdgDaughters[2] = +kPiPlus; } else { LOGP(fatal, "Not implemented for PDG {}", pdgCode); } @@ -661,7 +703,7 @@ struct HfTaskMcEfficiency { TracksWithSelection const& tracks) { std::vector pdgCodes{Pdg::kDPlus}; - candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); + candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processDataDplus, "Process D+ data (no MC information needed)", false); @@ -669,7 +711,7 @@ struct HfTaskMcEfficiency { TracksWithSelection const& tracks) { std::vector pdgCodes{Pdg::kDS}; - candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); + candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processDataDs, "Process Ds+ data (no MC information needed)", false); @@ -677,15 +719,23 @@ struct HfTaskMcEfficiency { TracksWithSelection const& tracks) { std::vector pdgCodes{Pdg::kLambdaCPlus}; - candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); + candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processDataLc, "Process Lc data (no MC information needed)", false); + void processDataXic(soa::Join const& candidates, + TracksWithSelection const& tracks) + { + std::vector pdgCodes{Pdg::kXiCPlus}; + candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); + } + PROCESS_SWITCH(HfTaskMcEfficiency, processDataXic, "Process Xic data (no MC information needed)", false); + void processDataDplusDs(soa::Join const& candidates, TracksWithSelection const& tracks) { std::vector pdgCodes{Pdg::kDPlus, Pdg::kDS}; - candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); + candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processDataDplusDs, "Process D+ and Ds+ data (no MC information needed)", false); @@ -693,7 +743,7 @@ struct HfTaskMcEfficiency { TracksWithSelection const& tracks) { std::vector pdgCodes{Pdg::kDPlus, Pdg::kDS, Pdg::kLambdaCPlus}; - candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); + candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processDataDplusDsLc, "Process D+, Ds+, and Lc data (no MC information needed)", false); @@ -701,7 +751,7 @@ struct HfTaskMcEfficiency { TracksWithSelection const& tracks) { std::vector pdgCodes{Pdg::kDPlus, Pdg::kLambdaCPlus}; - candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); + candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processDataDplusLc, "Process D+ and Lc data (no MC information needed)", false); @@ -709,7 +759,7 @@ struct HfTaskMcEfficiency { TracksWithSelection const& tracks) { std::vector pdgCodes{Pdg::kDPlus, Pdg::kDS, Pdg::kLambdaCPlus}; - candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); + candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processDataDsLc, "Process Ds+ and Lc data (no MC information needed)", false); @@ -730,7 +780,7 @@ struct HfTaskMcEfficiency { aod::McCollisionLabels const& colls) { std::vector pdgCodes{Pdg::kDPlus}; - candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); + candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processMcDplus, "Process MC for D+ signal", false); @@ -740,7 +790,7 @@ struct HfTaskMcEfficiency { aod::McCollisionLabels const& colls) { std::vector pdgCodes{Pdg::kDS}; - candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); + candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processMcDs, "Process MC for Ds+ signal", false); @@ -750,17 +800,27 @@ struct HfTaskMcEfficiency { aod::McCollisionLabels const& colls) { std::vector pdgCodes{Pdg::kLambdaCPlus}; - candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); + candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processMcLc, "Process MC for Lc signal", false); + void processMcXic(soa::Join const& candidates, + TracksWithSelectionMC const& tracks, + aod::McParticles const& mcParticles, + aod::McCollisionLabels const& colls) + { + std::vector pdgCodes{Pdg::kXiCPlus}; + candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); + } + PROCESS_SWITCH(HfTaskMcEfficiency, processMcXic, "Process MC for Xic signal", false); + void processMcDplusDs(soa::Join const& candidates, TracksWithSelectionMC const& tracks, aod::McParticles const& mcParticles, aod::McCollisionLabels const& colls) { std::vector pdgCodes{Pdg::kDPlus, Pdg::kDS}; - candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); + candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processMcDplusDs, "Process MC for D+ and Ds+ signals", false); @@ -770,7 +830,7 @@ struct HfTaskMcEfficiency { aod::McCollisionLabels const& colls) { std::vector pdgCodes{Pdg::kDPlus, Pdg::kDS, Pdg::kLambdaCPlus}; - candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); + candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processMcDplusDsLc, "Process MC for D+, Ds+, and Lc signals", false); @@ -780,7 +840,7 @@ struct HfTaskMcEfficiency { aod::McCollisionLabels const& colls) { std::vector pdgCodes{Pdg::kDPlus, Pdg::kLambdaCPlus}; - candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); + candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processMcDplusLc, "Process MC for D+ and Lc signals", false); @@ -790,7 +850,7 @@ struct HfTaskMcEfficiency { aod::McCollisionLabels const& colls) { std::vector pdgCodes{Pdg::kDS, Pdg::kLambdaCPlus}; - candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); + candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processMcDsLc, "Process MC for Ds+ and Lc signals", false); }; diff --git a/PWGHF/Tasks/taskMcEfficiencyToXiPi.cxx b/PWGHF/Tasks/taskMcEfficiencyToXiPi.cxx index 6c8d90e9be9..1d1f6a1af22 100644 --- a/PWGHF/Tasks/taskMcEfficiencyToXiPi.cxx +++ b/PWGHF/Tasks/taskMcEfficiencyToXiPi.cxx @@ -14,6 +14,8 @@ /// /// \author Federica Zanone, Heidelberg University +#include + #include "TMCProcess.h" // for VMC Particle Production Process #include "CommonConstants/PhysicsConstants.h" @@ -34,6 +36,7 @@ using namespace o2::framework; using namespace o2::framework::expressions; struct HfTaskMcEfficiencyToXiPi { + Configurable rapidityCharmBaryonMax{"rapidityCharmBaryonMax", 0.5, "Max absolute value of rapidity for charm baryon"}; Configurable acceptanceEtaLf{"acceptanceEtaLf", 1.0, "Max absolute value of eta for LF daughters"}; Configurable acceptancePtPionFromCascade{"acceptancePtPionFromCascade", 0.2, "Min value of pt for pion <-- cascade"}; @@ -43,9 +46,6 @@ struct HfTaskMcEfficiencyToXiPi { Configurable nClustersTpcMin{"nClustersTpcMin", 70, "Minimum number of TPC clusters requirement for pion <-- charm baryon"}; Configurable nClustersItsMin{"nClustersItsMin", 3, "Minimum number of ITS clusters requirement for pion <- charm baryon"}; - Configurable matchOmegac{"matchOmegac", false, "Do MC studies for Omegac0"}; - Configurable matchXic{"matchXic", true, "Do MC studies for Xic0"}; - ConfigurableAxis axisPt{"axisPt", {200, 0, 20}, "pT axis"}; ConfigurableAxis axisMass{"axisMass", {900, 2.1, 3}, "m_inv axis"}; @@ -68,13 +68,22 @@ struct HfTaskMcEfficiencyToXiPi { kNTrackableSteps }; using TracksWithSelectionMC = soa::Join; - using CandidateInfo = soa::Join; - using ParticleInfo = soa::Join; + using Xic0CandidateInfo = soa::Join; + using Omegac0CandidateInfo = soa::Join; + using ParticleInfoXic0 = soa::Join; + using ParticleInfoOmegac0 = soa::Join; + using BCsInfo = soa::Join; HistogramRegistry registry{"registry"}; void init(InitContext&) { + if (!doprocessOmegac0 && !doprocessXic0) { + LOGF(fatal, "Neither processOmegac0 nor processXic0 enabled, please choose one!"); + } else if (doprocessOmegac0 && doprocessXic0) { + LOGF(fatal, "Both processOmegac0 and processXic0 enabled, please choose ONLY one!"); + } + auto hCandidates = registry.add("hCandidates", "Candidate count at different steps", {HistType::kStepTHnF, {axisPt, axisMass, {2, -0.5, 1.5, "collision matched"}, {RecoDecay::OriginType::NonPrompt + 1, +RecoDecay::OriginType::None - 0.5, +RecoDecay::OriginType::NonPrompt + 0.5}}, kHFNSteps}); hCandidates->GetAxis(0)->SetTitle("#it{p}_{T} (GeV/#it{c})"); hCandidates->GetAxis(1)->SetTitle("#it{m}_{inv} (GeV/#it{c}^{2})"); @@ -112,9 +121,9 @@ struct HfTaskMcEfficiencyToXiPi { int decayFlag = 0; if (pdgCode == Pdg::kXiC0) { - decayFlag = 1 << aod::hf_cand_toxipi::DecayType::XiczeroToXiPi; + decayFlag = 1 << aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi; } else if (pdgCode == Pdg::kOmegaC0) { - decayFlag = 1 << aod::hf_cand_toxipi::DecayType::OmegaczeroToXiPi; + decayFlag = 1 << aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToXiPi; } else { LOGP(fatal, "Not implemented for PDG code: ", pdgCode); } @@ -157,7 +166,7 @@ struct HfTaskMcEfficiencyToXiPi { // candidates -> join candidateCreator, candidateCreator McRec and candidateSelector tables // genParticles -> join aod::McParticles and candidateCreator McGen tables template - void candidateFullLoop(T1 const& candidates, T2 const& genParticles, TracksWithSelectionMC const& tracks, aod::McCollisionLabels const&, int pdgCode) + void candidateFullLoop(T1 const& candidates, T2 const& genParticles, TracksWithSelectionMC const& tracks, aod::McCollisions const&, BCsInfo const&, int pdgCode) { // fill hCandidates histogram candidateRecLoop(candidates, pdgCode); @@ -193,10 +202,10 @@ struct HfTaskMcEfficiencyToXiPi { int decayFlagGen = 0; if (pdgCode == Pdg::kXiC0) { - decayFlagGen = 1 << aod::hf_cand_toxipi::DecayType::XiczeroToXiPi; + decayFlagGen = 1 << aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi; mass = MassXiC0; } else if (pdgCode == Pdg::kOmegaC0) { - decayFlagGen = 1 << aod::hf_cand_toxipi::DecayType::OmegaczeroToXiPi; + decayFlagGen = 1 << aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToXiPi; mass = MassOmegaC0; } else { LOGP(fatal, "Not implemented for PDG code: ", pdgCode); @@ -364,21 +373,25 @@ struct HfTaskMcEfficiencyToXiPi { } // close candidateMcLoop // process functions - void process(CandidateInfo const& candidates, - ParticleInfo const& genParticles, - TracksWithSelectionMC const& tracks, - aod::McCollisionLabels const& colls) + void processXic0(Xic0CandidateInfo const& candidates, + ParticleInfoXic0 const& genParticles, + BCsInfo const& bcs, + TracksWithSelectionMC const& tracks, + aod::McCollisions const& colls) { - if (matchXic && matchOmegac) { - LOGP(fatal, "Can't match Omegac0 and Xic0 at the same time, please choose one"); - } else if (!matchXic && !matchOmegac) { - LOGP(fatal, "Please match either Omegac0 or Xic0"); - } else if (matchXic) { - candidateFullLoop(candidates, genParticles, tracks, colls, Pdg::kXiC0); - } else if (matchOmegac) { - candidateFullLoop(candidates, genParticles, tracks, colls, Pdg::kOmegaC0); - } + candidateFullLoop(candidates, genParticles, tracks, colls, bcs, Pdg::kXiC0); + } + PROCESS_SWITCH(HfTaskMcEfficiencyToXiPi, processXic0, "Enable Xic0 efficiency process", true); + + void processOmegac0(Omegac0CandidateInfo const& candidates, + ParticleInfoOmegac0 const& genParticles, + BCsInfo const& bcs, + TracksWithSelectionMC const& tracks, + aod::McCollisions const& colls) + { + candidateFullLoop(candidates, genParticles, tracks, colls, bcs, Pdg::kOmegaC0); } + PROCESS_SWITCH(HfTaskMcEfficiencyToXiPi, processOmegac0, "Enable Omegac0 efficiency process", false); }; // close struct diff --git a/PWGHF/Tasks/taskMcGenPtRapShapes.cxx b/PWGHF/Tasks/taskMcGenPtRapShapes.cxx new file mode 100644 index 00000000000..e3e9deda1a9 --- /dev/null +++ b/PWGHF/Tasks/taskMcGenPtRapShapes.cxx @@ -0,0 +1,103 @@ +// 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 taskMcGenPtRapShapes.cxx +/// \brief Task to check generated pt and y distributions of charm and beauty hadrons in MC productions + +/// \author Fabrizio Grosa , CERN + +#include +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/RecoDecay.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +namespace +{ +const int nCharmHadrons = 10; +static constexpr std::array pdgCodesCharm = {Pdg::kD0, Pdg::kDPlus, Pdg::kDS, Pdg::kDStar, Pdg::kLambdaCPlus, Pdg::kSigmaC0, Pdg::kSigmaCPlusPlus, Pdg::kXiC0, Pdg::kXiCPlus, Pdg::kOmegaC0}; + +const int nBeautyHadrons = 4; +static constexpr std::array pdgCodesBeauty = {Pdg::kB0, Pdg::kBPlus, Pdg::kBS, Pdg::kLambdaB0}; +} // namespace + +struct HfTaskMcGenPtRapShapes { + + ConfigurableAxis axisPtCharm{"axisPtCharm", {1000, 0.f, 100.f}, "Binning for the pT axis of charm hadrons"}; + ConfigurableAxis axisPtBeauty{"axisPtBeauty", {3000, 0.f, 300.f}, "Binning for the pT axis of beauty hadrons"}; + ConfigurableAxis axisRapCharm{"axisRapCharm", {100, -1.f, 1.f}, "Binning for the y axis of charm hadrons"}; + ConfigurableAxis axisRapBeauty{"axisRapBeauty", {100, -1.f, 1.f}, "Binning for the y axis of beauty hadrons"}; + + std::array, nCharmHadrons> histRapVsPtCharmPrompt{}; + std::array, nCharmHadrons> histRapVsPtCharmNonPrompt{}; + std::array, nCharmHadrons> histPtCharmVsPtBeautyNonPrompt{}; + std::array, nBeautyHadrons> histRapVsPtBeauty{}; + + HistogramRegistry registry{}; + + void init(InitContext&) + { + + for (auto iCharmHad{0}; iCharmHad < nCharmHadrons; ++iCharmHad) { + histRapVsPtCharmPrompt[iCharmHad] = registry.add(Form("CharmHadrons/hRapVsPtPrompt%d", pdgCodesCharm[iCharmHad]), Form("Prompt %d;#it{p}_{T} (GeV/#it{c});#it{y}", pdgCodesCharm[iCharmHad]), {HistType::kTH2F, {axisPtCharm, axisRapCharm}}); + histRapVsPtCharmNonPrompt[iCharmHad] = registry.add(Form("CharmHadrons/hRapVsPtNonPrompt%d", pdgCodesCharm[iCharmHad]), Form("Non-prompt %d;#it{p}_{T} (GeV/#it{c});#it{y}", pdgCodesCharm[iCharmHad]), {HistType::kTH2F, {axisPtCharm, axisRapCharm}}); + histPtCharmVsPtBeautyNonPrompt[iCharmHad] = registry.add(Form("CharmHadrons/hPtCharmVsPtBeautyNonPrompt%d", pdgCodesCharm[iCharmHad]), Form("Non-prompt %d;#it{p}_{T}(b-had) (GeV/#it{c});#it{p}_{T}(c-had) (GeV/#it{c})", pdgCodesCharm[iCharmHad]), {HistType::kTH2F, {axisPtBeauty, axisPtCharm}}); + } + + for (auto iBeautyHad{0}; iBeautyHad < nBeautyHadrons; ++iBeautyHad) { + histRapVsPtBeauty[iBeautyHad] = registry.add(Form("BeautyHadrons/hRapVsPt%d", pdgCodesBeauty[iBeautyHad]), Form("%d;#it{p}_{T} (GeV/#it{c});#it{y}", pdgCodesBeauty[iBeautyHad]), {HistType::kTH2F, {axisPtBeauty, axisRapBeauty}}); + } + } + + void process(aod::McParticles const& mcParticles) + { + for (auto const& mcParticle : mcParticles) { + int absPdgCode = std::abs(mcParticle.pdgCode()); + float pt = mcParticle.pt(); + float rap = mcParticle.y(); + auto itCharm = std::find(pdgCodesCharm.begin(), pdgCodesCharm.end(), absPdgCode); + auto itBeauty = std::find(pdgCodesBeauty.begin(), pdgCodesBeauty.end(), absPdgCode); + if (itCharm != pdgCodesCharm.end()) { + auto idxCharm = std::distance(pdgCodesCharm.begin(), itCharm); + std::vector idxBhadMothers{}; + auto origin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, false, &idxBhadMothers); + if (origin == RecoDecay::OriginType::Prompt) { + histRapVsPtCharmPrompt[idxCharm]->Fill(pt, rap); + } else if (origin == RecoDecay::OriginType::NonPrompt) { + histRapVsPtCharmNonPrompt[idxCharm]->Fill(pt, rap); + if (std::abs(rap) < 0.5) { + auto bMother = mcParticles.rawIteratorAt(idxBhadMothers[0]); + histPtCharmVsPtBeautyNonPrompt[idxCharm]->Fill(bMother.pt(), pt); + } + } + } else if (itBeauty != pdgCodesBeauty.end()) { + auto idxBeauty = std::distance(pdgCodesBeauty.begin(), itBeauty); + histRapVsPtBeauty[idxBeauty]->Fill(pt, rap); + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/Tasks/taskMcValidation.cxx b/PWGHF/Tasks/taskMcValidation.cxx index f2b580ad705..b1dc03cdbb2 100644 --- a/PWGHF/Tasks/taskMcValidation.cxx +++ b/PWGHF/Tasks/taskMcValidation.cxx @@ -18,21 +18,33 @@ /// \author Fabrizio Grosa , CERN /// \author Fabio Catalano , CERN +#include +#include +#include + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StaticFor.h" +#include "CCDB/BasicCCDBManager.h" #include "Common/DataModel/CollisionAssociationTables.h" +#include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsEvSelHf.h" using namespace o2; using namespace o2::analysis; using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::hf_evsel; +using namespace o2::hf_centrality; +using namespace o2::hf_occupancy; namespace { @@ -41,23 +53,51 @@ enum DecayChannels { DzeroToKPi = 0, DplusToPiKPi, DplusToPhiPiToKKPi, // resonant channel with Phi, Dplus -> PhiPi -> KKPi DsToPhiPiToKKPi, // resonant channel with Phi, Ds -> PhiPi -> KKPi + DsToK0starKToKKPi, // resonant channel with K0*, Ds -> K0*K -> KKPi + Ds1ToDStarK0s, + Ds2StarToDPlusK0s, + D10ToDStarPi, + D2Star0ToDPlusPi, + B0ToDminusPi, + BplusToD0Pi, LcToPKPi, LcToPiK0s, - XicToPKPi, - nChannels }; // always keep nChannels at the end + XiCplusToPKPi, + XiCplusToXiPiPi, + XiCzeroToXiPi, + OmegaCToOmegaPi, + OmegaCToXiPi, + nChannels +}; // always keep nChannels at the end -static const std::array PDGArrayParticle = {o2::constants::physics::Pdg::kD0, o2::constants::physics::Pdg::kDStar, o2::constants::physics::Pdg::kDPlus, o2::constants::physics::Pdg::kDPlus, - o2::constants::physics::Pdg::kDS, o2::constants::physics::Pdg::kLambdaCPlus, o2::constants::physics::Pdg::kLambdaCPlus, o2::constants::physics::Pdg::kXiCPlus}; -static const std::array nDaughters = {2, 3, 3, 3, 3, 3, 3, 3}; -static const std::array maxDepthForSearch = {1, 2, 2, 2, 2, 2, 3, 2}; +static constexpr int nCharmMesonChannels = 10; // number of charm meson channels +static constexpr int nBeautyChannels = 2; // number of beauty hadron channels +static constexpr int nCharmBaryonChannels = nChannels - nCharmMesonChannels - nBeautyChannels; // number of charm baryon channels +static constexpr int nOriginTypes = 2; // number of origin types (prompt, non-prompt; only for charm hadrons) +static constexpr std::array PDGArrayParticle = {o2::constants::physics::Pdg::kD0, o2::constants::physics::Pdg::kDStar, + o2::constants::physics::Pdg::kDPlus, o2::constants::physics::Pdg::kDPlus, + o2::constants::physics::Pdg::kDS, o2::constants::physics::Pdg::kDS, o2::constants::physics::Pdg::kDS1, o2::constants::physics::Pdg::kDS2Star, + o2::constants::physics::Pdg::kD10, o2::constants::physics::Pdg::kD2Star0, o2::constants::physics::Pdg::kB0, o2::constants::physics::Pdg::kBPlus, o2::constants::physics::Pdg::kLambdaCPlus, + o2::constants::physics::Pdg::kLambdaCPlus, o2::constants::physics::Pdg::kXiCPlus, o2::constants::physics::Pdg::kXiCPlus, o2::constants::physics::Pdg::kXiC0, + o2::constants::physics::Pdg::kOmegaC0, o2::constants::physics::Pdg::kOmegaC0}; +static constexpr std::array nDaughters = {2, 3, 3, 3, 3, 3, 5, 5, 4, 4, 4, 3, 3, 3, 3, 5, 4, 4, 4}; +static constexpr std::array maxDepthForSearch = {1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 3, 2, 4, 3, 3, 3}; // keep coherent indexing with PDGArrayParticle // FIXME: look for a better solution -static const std::array, nChannels> arrPDGFinal2Prong = {{{+kPiPlus, -kKPlus}, {}, {}, {}, {}, {}, {}, {}}}; -static const std::array, nChannels> arrPDGFinal3Prong = {{{}, {+kPiPlus, -kKPlus, +kPiPlus}, {+kPiPlus, -kKPlus, +kPiPlus}, {+kKPlus, -kKPlus, +kPiPlus}, {+kKPlus, -kKPlus, +kPiPlus}, {+kProton, -kKPlus, +kPiPlus}, {+kProton, -kPiPlus, +kPiPlus}, {+kProton, -kKPlus, +kPiPlus}}}; -static const std::array labels = {"D^{0} #rightarrow K#pi", "D*^{+} #rightarrow D^{0}#pi", "D^{+} #rightarrow K#pi#pi", "D^{+} #rightarrow KK#pi", - "D_{s}^{+} #rightarrow KK#pi", "#Lambda_{c}^{+} #rightarrow pK#pi", "#Lambda_{c}^{+} #rightarrow pK^{0}_{s}", "#Xi_{c}^{+} #rightarrow pK#pi"}; -static const std::array particleNames = {"DzeroToKPi", "DstarToDzeroPi", "DplusToPiKPi", "DplusToKKpi", "DsToKKpi", "LcToPKPi", "LcToPiK0s", "XiCplusToPKPi"}; -static const std::array originNames = {"Prompt", "NonPrompt"}; +static constexpr std::array, nChannels> arrPDGFinal2Prong = {{{+kPiPlus, -kKPlus}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}}}; +static constexpr std::array, nChannels> arrPDGFinal3Prong = {{{}, {+kPiPlus, -kKPlus, +kPiPlus}, {+kPiPlus, -kKPlus, +kPiPlus}, {+kKPlus, -kKPlus, +kPiPlus}, {+kKPlus, -kKPlus, +kPiPlus}, {+kKPlus, -kKPlus, +kPiPlus}, {}, {}, {}, {}, {}, {-kPiPlus, +kKPlus, +kPiPlus}, {+kProton, -kKPlus, +kPiPlus}, {+kProton, -kPiPlus, +kPiPlus}, {+kProton, -kKPlus, +kPiPlus}, {}, {}, {}, {}}}; +static constexpr std::array, nChannels> arrPDGFinal4Prong = {{{}, {}, {}, {}, {}, {}, {}, {}, {+kPiPlus, -kKPlus, +kPiPlus, -kPiPlus}, {+kPiPlus, -kKPlus, +kPiPlus, -kPiPlus}, {-kPiPlus, +kKPlus, -kPiPlus, +kPiPlus}, {}, {}, {}, {}, {}, {+kPiPlus, -kPiPlus, -kPiPlus, +kProton}, {+kPiPlus, -kKPlus, -kPiPlus, +kProton}, {+kPiPlus, -kPiPlus, -kPiPlus, +kProton}}}; +static constexpr std::array, nChannels> arrPDGFinal5Prong = {{{}, {}, {}, {}, {}, {}, {+kPiPlus, -kKPlus, +kPiPlus, +kPiPlus, -kPiPlus}, {+kPiPlus, -kKPlus, +kPiPlus, +kPiPlus, -kPiPlus}, {}, {}, {}, {}, {}, {}, {}, {+kPiPlus, +kPiPlus, -kPiPlus, -kPiPlus, +kProton}, {}, {}, {}}}; +static constexpr std::string_view labels[nChannels] = {"D^{0} #rightarrow K#pi", "D*^{+} #rightarrow D^{0}#pi", "D^{+} #rightarrow K#pi#pi", "D^{+} #rightarrow KK#pi", "D_{s}^{+} #rightarrow #Phi#pi #rightarrow KK#pi", + "D_{s}^{+} #rightarrow #bar{K}^{*0}K #rightarrow KK#pi", "D_{s}1 #rightarrow D*^{+}K^{0}_{s}", "D_{s}2* #rightarrow D^{+}K^{0}_{s}", "D1^{0} #rightarrow D*^{+}#pi", + "D2^{*} #rightarrow D^{+}#pi", + "B^{0} #rightarrow D^{-}#pi", "B^{+} #rightarrow D^{0}#pi", + "#Lambda_{c}^{+} #rightarrow pK#pi", + "#Lambda_{c}^{+} #rightarrow pK^{0}_{s}", "#Xi_{c}^{+} #rightarrow pK#pi", + "#Xi_{c}^{+} #rightarrow #Xi#pi#pi", "#Xi_{c}^{0} #rightarrow #Xi#pi", "#Omega_{c}^{0} #rightarrow #Omega#pi", "#Omega_{c}^{0} #rightarrow #Xi#pi"}; +static constexpr std::string_view particleNames[nChannels] = {"DzeroToKPi", "DstarToDzeroPi", "DplusToPiKPi", "DplusToPhiPiToKKPi", "DsToPhiPiToKKPi", "DsToK0starKToKKPi", "Ds1ToDStarK0s", "Ds2StarToDPlusK0s", "D10ToDStarPi", "D2Star0ToDPlusPi", "B0ToDminusPi", "BplusToD0Pi", + "LcToPKPi", "LcToPiK0s", "XiCplusToPKPi", "XiCplusToXiPiPi", "XiCzeroToXiPi", "OmegaCToOmegaPi", "OmegaCToXiPi"}; +static constexpr std::string_view originNames[nOriginTypes] = {"Prompt", "NonPrompt"}; } // namespace /// Generated Level Validation @@ -65,100 +105,169 @@ static const std::array originNames = {"Prompt", "NonPrompt"}; /// - Number of HF quarks produced per collision /// - Number of candidates per collision /// - Momentum Conservation for these particles - struct HfTaskMcValidationGen { - Configurable xVertexMin{"xVertexMin", -100., "min. x of generated primary vertex [cm]"}; - Configurable xVertexMax{"xVertexMax", 100., "max. x of generated primary vertex [cm]"}; - Configurable yVertexMin{"yVertexMin", -100., "min. y of generated primary vertex [cm]"}; - Configurable yVertexMax{"yVertexMax", 100., "max. y of generated primary vertex [cm]"}; - Configurable zVertexMin{"zVertexMin", -100., "min. z of generated primary vertex [cm]"}; - Configurable zVertexMax{"zVertexMax", 100., "max. z of generated primary vertex [cm]"}; + + using BCsInfo = soa::Join; + using CollisionsNoCents = soa::Join; + using CollisionsFT0Cs = soa::Join; + using CollisionsFT0Ms = soa::Join; + using McCollisionsCentFT0Ms = soa::Join; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + PresliceUnsorted colPerMcCollisionFT0C = aod::mccollisionlabel::mcCollisionId; + PresliceUnsorted colPerMcCollisionFT0M = aod::mccollisionlabel::mcCollisionId; + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + Configurable eventGeneratorType{"eventGeneratorType", -1, "If positive, enable event selection using subGeneratorId information. The value indicates which events to keep (0 = MB, 4 = charm triggered, 5 = beauty triggered)"}; + Configurable rejectParticlesFromBkgEvent{"rejectParticlesFromBkgEvent", true, "Reject particles"}; + Configurable storeOccupancy{"storeOccupancy", false, "Store collision occupancy for dedicated studies"}; + + HfEventSelectionMc hfEvSelMc; // mc event selection and monitoring - AxisSpec axisNhadrons{10, -0.5, 9.5}; + AxisSpec axisNhadrons{nChannels, -0.5, static_cast(nChannels) - 0.5}; AxisSpec axisNquarks{20, -0.5, 19.5}; AxisSpec axisResiduals{100, -0.01, 0.01}; AxisSpec axisPt{100, 0., 50.}; AxisSpec axisY{100, -5., 5.}; - AxisSpec axisSpecies{nChannels, -0.5, static_cast(nChannels) - 0.5}; + AxisSpec axisCent{110, 0., 110.}; + AxisSpec axisOcc{3000, 0., 15000.}; + AxisSpec axisCharmMesonSpecies{nCharmMesonChannels, -0.5, static_cast(nCharmMesonChannels) - 0.5}; + AxisSpec axisBeautySpecies{nBeautyChannels, -0.5, static_cast(nBeautyChannels) - 0.5}; + AxisSpec axisCharmBaryonSpecies{nCharmBaryonChannels, -0.5, static_cast(nCharmBaryonChannels) - 0.5}; AxisSpec axisDecLen{100, 0., 10000.}; HistogramRegistry registry{ "registry", - {{"hMomentumCheck", "Mom. Conservation (1 = true, 0 = false) (#it{#epsilon} = 1 MeV/#it{c}); Mom. Conservation result; entries", {HistType::kTH1F, {{2, -0.5, +1.5}}}}, + {{"hNevGen", "Generated events counter; Gen. events; entries", {HistType::kTH1F, {{1, -0.5, +0.5}}}}, + {"hMomentumCheck", "Mom. Conservation (1 = true, 0 = false) (#it{#epsilon} = 1 MeV/#it{c}); Mom. Conservation result; entries", {HistType::kTH1F, {{2, -0.5, +1.5}}}}, {"hPtDiffMotherDaughterGen", "Pt Difference Mother-Daughters; #Delta#it{p}_{T}^{gen} (GeV/#it{c}); entries", {HistType::kTH1F, {axisResiduals}}}, {"hPxDiffMotherDaughterGen", "Px Difference Mother-Daughters; #Delta#it{p}_{x}^{gen} (GeV/#it{c}); entries", {HistType::kTH1F, {axisResiduals}}}, {"hPyDiffMotherDaughterGen", "Py Difference Mother-Daughters; #Delta#it{p}_{y}^{gen} (GeV/#it{c}); entries", {HistType::kTH1F, {axisResiduals}}}, {"hPzDiffMotherDaughterGen", "Pz Difference Mother-Daughters; #Delta#it{p}_{z}^{gen} (GeV/#it{c}); entries", {HistType::kTH1F, {axisResiduals}}}, {"hPDiffMotherDaughterGen", "P Difference Mother-Daughters; #Delta#it{p}^{gen} (GeV/#it{c}); entries", {HistType::kTH1F, {axisResiduals}}}, - {"quarks/hCountC", "Event counter - Number of charm quarks; Events Per Collision; entries", {HistType::kTH1F, {axisNquarks}}}, - {"quarks/hCountB", "Event counter - Number of beauty quarks; Events Per Collision; entries", {HistType::kTH1F, {axisNquarks}}}, - {"quarks/hCountCbar", "Event counter - Number of anti-charm quarks; Events Per Collision; entries", {HistType::kTH1F, {axisNquarks}}}, - {"quarks/hCountBbar", "Event counter - Number of anti-beauty quarks; Events Per Collision; entries", {HistType::kTH1F, {axisNquarks}}}, - {"quarks/hPtVsYCharmQuark", "Y vs. Pt - charm quarks ; #it{p}_{T}^{gen} (GeV/#it{c}); #it{y}^{gen}", {HistType::kTH2F, {axisPt, axisY}}}, - {"quarks/hPtVsYBeautyQuark", "Y vs. Pt - beauty quarks ; #it{p}_{T}^{gen} (GeV/#it{c}); #it{y}^{gen}", {HistType::kTH2F, {axisPt, axisY}}}, - {"promptCharmHadrons/hCountPromptDzeroToKPi", "Event counter - Prompt D0 to KPi; Events Per Collision; entries", {HistType::kTH1F, {axisNhadrons}}}, - {"promptCharmHadrons/hCountPromptDstarToD0Pi", "Event counter - Prompt Dstar to D0Pi; Events Per Collision; entries", {HistType::kTH1F, {axisNhadrons}}}, - {"promptCharmHadrons/hCountPromptDplusToKPiPi", "Event counter - Prompt DPlus to KPiPi; Events Per Collision; entries", {HistType::kTH1F, {axisNhadrons}}}, - {"promptCharmHadrons/hCountPromptDplusToKKPi", "Event counter - Prompt DPlus to KKPi; Events Per Collision; entries", {HistType::kTH1F, {axisNhadrons}}}, - {"promptCharmHadrons/hCountPromptDsToKKpi", "Event counter - Prompt Ds to KKPi; Events Per Collision; entries", {HistType::kTH1F, {axisNhadrons}}}, - {"promptCharmHadrons/hCountPromptLambdaCToPKPi", "Event counter - Prompt LambdaC to PKPi; Events Per Collision; entries", {HistType::kTH1F, {axisNhadrons}}}, - {"promptCharmHadrons/hCountPromptLambdaCToPK0s", "Event counter - Prompt LambdaC to PK0s; Events Per Collision; entries", {HistType::kTH1F, {axisNhadrons}}}, - {"promptCharmHadrons/hCountPromptXiCToPKPi", "Event counter - Prompt XiC to PKPi; Events Per Collision; entries", {HistType::kTH1F, {axisNhadrons}}}, - {"nonPromptCharmHadrons/hCountNonPromptDzeroToKPi", "Event counter - Non-prompt D0 to KPi; Events Per Collision; entries", {HistType::kTH1F, {axisNhadrons}}}, - {"nonPromptCharmHadrons/hCountNonPromptDstarToD0Pi", "Event counter - Non-prompt Dstar to D0Pi; Events Per Collision; entries", {HistType::kTH1F, {axisNhadrons}}}, - {"nonPromptCharmHadrons/hCountNonPromptDplusToKPiPi", "Event counter - Non-prompt DPlus to KPiPi; Events Per Collision; entries", {HistType::kTH1F, {axisNhadrons}}}, - {"nonPromptCharmHadrons/hCountNonPromptDplusToKKPi", "Event counter - Non-prompt DPlus to KKPi; Events Per Collision; entries", {HistType::kTH1F, {axisNhadrons}}}, - {"nonPromptCharmHadrons/hCountNonPromptDsToKKpi", "Event counter - Non-prompt Ds to KKP; Events Per Collision; entries", {HistType::kTH1F, {axisNhadrons}}}, - {"nonPromptCharmHadrons/hCountNonPromptLambdaCToPKPi", "Event counter - Non-prompt LambdaC to PKPi; Events Per Collision; entries", {HistType::kTH1F, {axisNhadrons}}}, - {"nonPromptCharmHadrons/hCountNonPromptLambdaCToPK0s", "Event counter - Non-prompt LambdaC to PK0s; Events Per Collision; entries", {HistType::kTH1F, {axisNhadrons}}}, - {"nonPromptCharmHadrons/hCountNonPromptXiCToPKPi", "Event counter - Non-prompt XiC to PKPi; Events Per Collision; entries", {HistType::kTH1F, {axisNhadrons}}}, - {"promptCharmHadrons/hPromptPtDistr", "Pt distribution vs prompt charm hadron in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c})", {HistType::kTH2F, {axisSpecies, axisPt}}}, - {"promptCharmHadrons/hPromptYDistr", "Y distribution vs prompt charm hadron; ; #it{y}^{gen}", {HistType::kTH2F, {axisSpecies, axisY}}}, - {"promptCharmHadrons/hPromptDecLenDistr", "Decay length distribution vs prompt charm hadron; ; decay length (#mum)", {HistType::kTH2F, {axisSpecies, axisDecLen}}}, - {"nonPromptCharmHadrons/hNonPromptPtDistr", "Pt distribution vs non-prompt charm hadron in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c})", {HistType::kTH2F, {axisSpecies, axisPt}}}, - {"nonPromptCharmHadrons/hNonPromptYDistr", "Y distribution vs non-prompt charm hadron; ; #it{y}^{gen}", {HistType::kTH2F, {axisSpecies, axisY}}}, - {"nonPromptCharmHadrons/hNonPromptDecLenDistr", "Decay length distribution vs non-prompt charm hadron; ; decay length (#mum)", {HistType::kTH2F, {axisSpecies, axisDecLen}}}}}; + {"Quarks/hCountC", "Event counter - Number of charm quarks; Events Per Collision; entries", {HistType::kTH1F, {axisNquarks}}}, + {"Quarks/hCountB", "Event counter - Number of beauty quarks; Events Per Collision; entries", {HistType::kTH1F, {axisNquarks}}}, + {"Quarks/hCountCbar", "Event counter - Number of anti-charm quarks; Events Per Collision; entries", {HistType::kTH1F, {axisNquarks}}}, + {"Quarks/hCountBbar", "Event counter - Number of anti-beauty quarks; Events Per Collision; entries", {HistType::kTH1F, {axisNquarks}}}, + {"Quarks/hPtVsYCharmQuark", "Y vs. Pt - charm quarks ; #it{p}_{T}^{gen} (GeV/#it{c}); #it{y}^{gen}", {HistType::kTH2F, {axisPt, axisY}}}, + {"Quarks/hPtVsYBeautyQuark", "Y vs. Pt - beauty quarks ; #it{p}_{T}^{gen} (GeV/#it{c}); #it{y}^{gen}", {HistType::kTH2F, {axisPt, axisY}}}, + {"PromptCharmMesons/hPromptMesonsPtDistr", "Pt distribution vs prompt charm meson in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c})", {HistType::kTH2F, {axisCharmMesonSpecies, axisPt}}}, + {"PromptCharmMesons/hPromptMesonsPtCentDistr", "Pt vs Cent distribution vs prompt charm meson in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c}); Centrality (%)", {HistType::kTH3F, {axisCharmMesonSpecies, axisPt, axisCent}}}, + {"PromptCharmMesons/hPromptMesonsPtOccDistr", "Pt vs Occ distribution vs prompt charm meson in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c}); Occupancy", {HistType::kTH3F, {axisCharmMesonSpecies, axisPt, axisOcc}}}, + {"PromptCharmMesons/hPromptMesonsYDistr", "Y distribution vs prompt charm meson; ; #it{y}^{gen}", {HistType::kTH2F, {axisCharmMesonSpecies, axisY}}}, + {"PromptCharmMesons/hPromptMesonsDecLenDistr", "Decay length distribution vs prompt charm meson; ; decay length (#mum)", {HistType::kTH2F, {axisCharmMesonSpecies, axisDecLen}}}, + {"NonPromptCharmMesons/hNonPromptMesonsPtDistr", "Pt distribution vs non-prompt charm meson in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c})", {HistType::kTH2F, {axisCharmMesonSpecies, axisPt}}}, + {"NonPromptCharmMesons/hNonPromptMesonsPtCentDistr", "Pt vs Cent distribution vs non-prompt charm meson in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c}); Centrality (%)", {HistType::kTH3F, {axisCharmMesonSpecies, axisPt, axisCent}}}, + {"NonPromptCharmMesons/hNonPromptMesonsPtOccDistr", "Pt vs Occ distribution vs non-prompt charm meson in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c}); Occupancy", {HistType::kTH3F, {axisCharmMesonSpecies, axisPt, axisOcc}}}, + {"NonPromptCharmMesons/hNonPromptMesonsYDistr", "Y distribution vs non-prompt charm meson; ; #it{y}^{gen}", {HistType::kTH2F, {axisCharmMesonSpecies, axisY}}}, + {"NonPromptCharmMesons/hNonPromptMesonsDecLenDistr", "Decay length distribution vs non-prompt charm meson; ; decay length (#mum)", {HistType::kTH2F, {axisCharmMesonSpecies, axisDecLen}}}, + {"Beauty/hPtDistr", "Pt distribution vs beauty hadron in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c})", {HistType::kTH2F, {axisBeautySpecies, axisPt}}}, + {"Beauty/hPtCentDistr", "Pt vs Cent distribution vs beauty hadron in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c}); Centrality (%)", {HistType::kTH3F, {axisBeautySpecies, axisPt, axisCent}}}, + {"Beauty/hPtOccDistr", "Pt vs Occ distribution vs beauty hadron in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c}); Occupancy", {HistType::kTH3F, {axisBeautySpecies, axisPt, axisOcc}}}, + {"Beauty/hYDistr", "Y distribution vs beauty hadron; ; #it{y}^{gen}", {HistType::kTH2F, {axisBeautySpecies, axisY}}}, + {"Beauty/hDecLenDistr", "Decay length distribution vs beauty hadron; ; decay length (#mum)", {HistType::kTH2F, {axisBeautySpecies, axisDecLen}}}, + {"PromptCharmBaryons/hPromptBaryonsPtDistr", "Pt distribution vs prompt charm baryon in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c})", {HistType::kTH2F, {axisCharmBaryonSpecies, axisPt}}}, + {"PromptCharmBaryons/hPromptBaryonsPtCentDistr", "Pt vs Cent distribution vs prompt charm baryons in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c}); Centrality (%)", {HistType::kTH3F, {axisCharmBaryonSpecies, axisPt, axisCent}}}, + {"PromptCharmBaryons/hPromptBaryonsYDistr", "Y distribution vs prompt charm baryon; ; #it{y}^{gen}", {HistType::kTH2F, {axisCharmBaryonSpecies, axisY}}}, + {"PromptCharmBaryons/hPromptBaryonsPtOccDistr", "Pt vs Occ distribution vs prompt charm baryons in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c}); Occupancy", {HistType::kTH3F, {axisCharmBaryonSpecies, axisPt, axisOcc}}}, + {"PromptCharmBaryons/hPromptBaryonsDecLenDistr", "Decay length distribution vs prompt charm baryon; ; decay length (#mum)", {HistType::kTH2F, {axisCharmBaryonSpecies, axisDecLen}}}, + {"NonPromptCharmBaryons/hNonPromptBaryonsPtDistr", "Pt distribution vs non-prompt charm baryon in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c})", {HistType::kTH2F, {axisCharmBaryonSpecies, axisPt}}}, + {"NonPromptCharmBaryons/hNonPromptBaryonsPtCentDistr", "Pt vs Cent distribution vs prompt charm baryons in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c}); Centrality (%)", {HistType::kTH3F, {axisCharmBaryonSpecies, axisPt, axisCent}}}, + {"NonPromptCharmBaryons/hNonPromptBaryonsPtOccDistr", "Pt vs Occ distribution vs prompt charm baryons in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c}); Occupancy", {HistType::kTH3F, {axisCharmBaryonSpecies, axisPt, axisOcc}}}, + {"NonPromptCharmBaryons/hNonPromptBaryonsYDistr", "Y distribution vs non-prompt charm baryon; ; #it{y}^{gen}", {HistType::kTH2F, {axisCharmBaryonSpecies, axisY}}}, + {"NonPromptCharmBaryons/hNonPromptBaryonsDecLenDistr", "Decay length distribution vs non-prompt charm baryon; ; decay length (#mum)", {HistType::kTH2F, {axisCharmBaryonSpecies, axisDecLen}}}}}; - void init(InitContext&) + void init(InitContext& initContext) { - for (auto iBin = 1; iBin <= nChannels; ++iBin) { - registry.get(HIST("promptCharmHadrons/hPromptPtDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin - 1].data()); - registry.get(HIST("promptCharmHadrons/hPromptYDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin - 1].data()); - registry.get(HIST("promptCharmHadrons/hPromptDecLenDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin - 1].data()); - registry.get(HIST("nonPromptCharmHadrons/hNonPromptPtDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin - 1].data()); - registry.get(HIST("nonPromptCharmHadrons/hNonPromptYDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin - 1].data()); - registry.get(HIST("nonPromptCharmHadrons/hNonPromptDecLenDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin - 1].data()); + + std::array processes = {doprocessNoCentSel, doprocessCentFT0C, doprocessCentFT0M}; + if (std::accumulate(processes.begin(), processes.end(), 0) > 1) { + LOGP(fatal, "At most one process function for generated particles can be enabled at a time."); } - } - /// Primary-vertex selection - /// \param collision mcCollision table row - template - bool selectVertex(const Col& collision) - { - // x position - if (collision.posX() < xVertexMin || collision.posX() > xVertexMax) { - return false; + // add per species histograms + for (size_t iOrigin = 0; iOrigin < nOriginTypes; iOrigin++) { + for (int iChannel = 0; iChannel < nCharmMesonChannels; iChannel++) { // Charm mesons + registry.add(Form("%sCharmMesons/hCount%s%s", originNames[iOrigin].data(), originNames[iOrigin].data(), particleNames[iChannel].data()), + Form("Event counter - %s %s; Events Per Collision; entries", originNames[iOrigin].data(), labels[iChannel].data()), {HistType::kTH1F, {axisNhadrons}}); + } + for (int iChannel = nCharmMesonChannels + nBeautyChannels; iChannel < nChannels; iChannel++) { // Charm baryons + registry.add(Form("%sCharmBaryons/hCount%s%s", originNames[iOrigin].data(), originNames[iOrigin].data(), particleNames[iChannel].data()), + Form("Event counter - %s %s; Events Per Collision; entries", originNames[iOrigin].data(), labels[iChannel].data()), {HistType::kTH1F, {axisNhadrons}}); + } } - // y position - if (collision.posY() < yVertexMin || collision.posY() > yVertexMax) { - return false; + for (int iChannel = nCharmMesonChannels; iChannel < nCharmMesonChannels + nBeautyChannels; iChannel++) { // Beauty mesons + registry.add(Form("Beauty/hCount%s", particleNames[iChannel].data()), + Form("Event counter - %s; Events Per Collision; entries", labels[iChannel].data()), {HistType::kTH1F, {axisNhadrons}}); } - // z position - if (collision.posZ() < zVertexMin || collision.posZ() > zVertexMax) { - return false; + + for (auto iBin = 1; iBin <= nCharmMesonChannels; ++iBin) { + registry.get(HIST("PromptCharmMesons/hPromptMesonsPtDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin - 1].data()); + registry.get(HIST("PromptCharmMesons/hPromptMesonsPtCentDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin - 1].data()); + registry.get(HIST("PromptCharmMesons/hPromptMesonsPtOccDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin - 1].data()); + registry.get(HIST("PromptCharmMesons/hPromptMesonsYDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin - 1].data()); + registry.get(HIST("PromptCharmMesons/hPromptMesonsDecLenDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin - 1].data()); + registry.get(HIST("NonPromptCharmMesons/hNonPromptMesonsPtDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin - 1].data()); + registry.get(HIST("NonPromptCharmMesons/hNonPromptMesonsPtCentDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin - 1].data()); + registry.get(HIST("NonPromptCharmMesons/hNonPromptMesonsPtOccDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin - 1].data()); + registry.get(HIST("NonPromptCharmMesons/hNonPromptMesonsYDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin - 1].data()); + registry.get(HIST("NonPromptCharmMesons/hNonPromptMesonsDecLenDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin - 1].data()); + } + for (auto iBin = 1; iBin <= nBeautyChannels; ++iBin) { + registry.get(HIST("Beauty/hPtDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nCharmMesonChannels - 1].data()); + registry.get(HIST("Beauty/hPtCentDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nCharmMesonChannels - 1].data()); + registry.get(HIST("Beauty/hPtOccDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nCharmMesonChannels - 1].data()); + registry.get(HIST("Beauty/hYDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nCharmMesonChannels - 1].data()); + registry.get(HIST("Beauty/hDecLenDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nCharmMesonChannels - 1].data()); + } + for (auto iBin = 1; iBin <= nCharmBaryonChannels; ++iBin) { + registry.get(HIST("PromptCharmBaryons/hPromptBaryonsPtDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nCharmMesonChannels + nBeautyChannels - 1].data()); + registry.get(HIST("PromptCharmBaryons/hPromptBaryonsPtCentDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nCharmMesonChannels + nBeautyChannels - 1].data()); + registry.get(HIST("PromptCharmBaryons/hPromptBaryonsPtOccDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nCharmMesonChannels + nBeautyChannels - 1].data()); + registry.get(HIST("PromptCharmBaryons/hPromptBaryonsYDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nCharmMesonChannels + nBeautyChannels - 1].data()); + registry.get(HIST("PromptCharmBaryons/hPromptBaryonsDecLenDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nCharmMesonChannels + nBeautyChannels - 1].data()); + registry.get(HIST("NonPromptCharmBaryons/hNonPromptBaryonsPtDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nCharmMesonChannels + nBeautyChannels - 1].data()); + registry.get(HIST("NonPromptCharmBaryons/hNonPromptBaryonsPtCentDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nCharmMesonChannels + nBeautyChannels - 1].data()); + registry.get(HIST("NonPromptCharmBaryons/hNonPromptBaryonsPtOccDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nCharmMesonChannels + nBeautyChannels - 1].data()); + registry.get(HIST("NonPromptCharmBaryons/hNonPromptBaryonsYDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nCharmMesonChannels + nBeautyChannels - 1].data()); + registry.get(HIST("NonPromptCharmBaryons/hNonPromptBaryonsDecLenDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nCharmMesonChannels + nBeautyChannels - 1].data()); + } + + // inspect for which particle species the candidates were created and which zPvPosMax cut was set for reconstructed + const auto& workflows = initContext.services().get(); + for (const DeviceSpec& device : workflows.devices) { + if (device.name.compare("hf-task-mc-validation-rec") == 0) { + hfEvSelMc.configureFromDevice(device); + break; + } } - return true; + + hfEvSelMc.addHistograms(registry); // particles monitoring } - void process(aod::McCollision const& mcCollision, - aod::McParticles const& mcParticles) + template + void runCheckGenParticles(GenColl const& mcCollision, Particles const& mcParticles, RecoColls const& recoCollisions, BCsInfo const&, std::array& counterPrompt, std::array& counterNonPrompt) { if (eventGeneratorType >= 0 && mcCollision.getSubGeneratorId() != eventGeneratorType) { return; } - if (!selectVertex(mcCollision)) { + registry.fill(HIST("hNevGen"), 1); + + // Slice the collisions table to get the collision info for the current MC collision + float centrality{105.f}; + int occupancy = 0; + if (storeOccupancy) { + occupancy = getOccupancyGenColl(recoCollisions, OccupancyEstimator::Its); + } + uint16_t rejectionMask{0}; + if constexpr (centEstimator == CentralityEstimator::FT0C) { + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, recoCollisions, centrality); + } else if constexpr (centEstimator == CentralityEstimator::FT0M) { + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, recoCollisions, centrality); + } else if constexpr (centEstimator == CentralityEstimator::None) { + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, recoCollisions, centrality); + } + hfEvSelMc.fillHistograms(mcCollision, rejectionMask); + if (rejectionMask != 0) { return; } @@ -166,16 +275,20 @@ struct HfTaskMcValidationGen { int cBarPerCollision = 0; int bPerCollision = 0; int bBarPerCollision = 0; - std::array counterPrompt{0}, counterNonPrompt{0}; for (const auto& particle : mcParticles) { + + if (rejectParticlesFromBkgEvent && particle.fromBackgroundEvent()) { + continue; + } + if (!particle.has_mothers()) { continue; } int particlePdgCode = particle.pdgCode(); bool isDiffFromMothers = true; - for (const auto& mother : particle.mothers_as()) { + for (const auto& mother : particle.template mothers_as()) { if (particlePdgCode == mother.pdgCode()) { isDiffFromMothers = false; break; @@ -185,19 +298,19 @@ struct HfTaskMcValidationGen { switch (particlePdgCode) { case kCharm: cPerCollision++; - registry.fill(HIST("quarks/hPtVsYCharmQuark"), particle.pt(), particle.y()); + registry.fill(HIST("Quarks/hPtVsYCharmQuark"), particle.pt(), particle.y()); break; case kCharmBar: cBarPerCollision++; - registry.fill(HIST("quarks/hPtVsYCharmQuark"), particle.pt(), particle.y()); + registry.fill(HIST("Quarks/hPtVsYCharmQuark"), particle.pt(), particle.y()); break; case kBottom: bPerCollision++; - registry.fill(HIST("quarks/hPtVsYBeautyQuark"), particle.pt(), particle.y()); + registry.fill(HIST("Quarks/hPtVsYBeautyQuark"), particle.pt(), particle.y()); break; case kBottomBar: bBarPerCollision++; - registry.fill(HIST("quarks/hPtVsYBeautyQuark"), particle.pt(), particle.y()); + registry.fill(HIST("Quarks/hPtVsYBeautyQuark"), particle.pt(), particle.y()); break; } } @@ -215,8 +328,10 @@ struct HfTaskMcValidationGen { if (!RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], arrPDGFinal2Prong[iD], true, nullptr, maxDepthForSearch[iD], &listDaughters)) { continue; } - } else if (nDaughters[iD] == 3) { - if (!RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], arrPDGFinal3Prong[iD], true, nullptr, maxDepthForSearch[iD], &listDaughters)) { + } + + if (nDaughters[iD] == 3) { + if (!RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], arrPDGFinal3Prong[iD], true, nullptr, maxDepthForSearch[iD], &listDaughters)) { continue; } if (iD == DstarToDzeroPi && @@ -224,16 +339,75 @@ struct HfTaskMcValidationGen { continue; } if ((iD == DplusToPhiPiToKKPi || iD == DsToPhiPiToKKPi) && - !RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], std::array{+o2::constants::physics::Pdg::kPhi, +kPiPlus}) && - !RecoDecay::isMatchedMCGen(mcParticles, particle, -PDGArrayParticle[iD], std::array{+o2::constants::physics::Pdg::kPhi, -kPiPlus})) { + !RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], std::array{+o2::constants::physics::Pdg::kPhi, +kPiPlus}, false) && + !RecoDecay::isMatchedMCGen(mcParticles, particle, -PDGArrayParticle[iD], std::array{+o2::constants::physics::Pdg::kPhi, -kPiPlus}, false)) { + continue; + } + if (iD == DsToK0starKToKKPi && + !RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], std::array{-313, +kKPlus}, true)) { continue; } - // TODO: check if particles are recovered after isMatchedMCGen update to skip daughters from material if (iD == LcToPiK0s && !RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], std::array{+kK0Short, +kProton}, false, nullptr, 2) && !RecoDecay::isMatchedMCGen(mcParticles, particle, -PDGArrayParticle[iD], std::array{+kK0Short, -kProton}, false, nullptr, 2)) { continue; } + if (iD == BplusToD0Pi && + !RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], std::array{-o2::constants::physics::Pdg::kD0, +kPiPlus}, true)) { + continue; + } + } + + if (nDaughters[iD] == 4) { + if (iD != B0ToDminusPi) { + if (!RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], arrPDGFinal4Prong[iD], true, nullptr, maxDepthForSearch[iD], &listDaughters)) { + continue; + } + } else { // For B0 we consider flavour oscillations + if (!RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], arrPDGFinal4Prong[iD], true, nullptr, maxDepthForSearch[iD], &listDaughters)) { + continue; + } + } + if (iD == D10ToDStarPi && + !RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], std::array{+o2::constants::physics::Pdg::kDStar, -kPiPlus}, true)) { + continue; + } + if (iD == D2Star0ToDPlusPi && + !RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], std::array{+o2::constants::physics::Pdg::kDPlus, -kPiPlus}, true)) { + continue; + } + if ((iD == XiCzeroToXiPi || iD == OmegaCToXiPi) && + !RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], std::array{+kXiMinus, +kPiPlus}, true)) { + continue; + } + if (iD == OmegaCToOmegaPi && + !RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], std::array{+kOmegaMinus, +kPiPlus}, true)) { + continue; + } + if (iD == B0ToDminusPi && + !RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], std::array{-o2::constants::physics::Pdg::kDPlus, +kPiPlus}, true)) { + continue; + } + } + + if (nDaughters[iD] == 5) { + if (!RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], arrPDGFinal5Prong[iD], true, nullptr, maxDepthForSearch[iD], &listDaughters)) { + continue; + } + if (iD == Ds1ToDStarK0s && + !RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], std::array{+kK0Short, +o2::constants::physics::Pdg::kDStar}, false, nullptr, 2) && + !RecoDecay::isMatchedMCGen(mcParticles, particle, -PDGArrayParticle[iD], std::array{+kK0Short, -o2::constants::physics::Pdg::kDStar}, false, nullptr, 2)) { + continue; + } + if (iD == Ds2StarToDPlusK0s && + !RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], std::array{+kK0Short, +o2::constants::physics::Pdg::kDPlus}, false, nullptr, 2) && + !RecoDecay::isMatchedMCGen(mcParticles, particle, -PDGArrayParticle[iD], std::array{+kK0Short, -o2::constants::physics::Pdg::kDPlus}, false, nullptr, 2)) { + continue; + } + if (iD == XiCplusToXiPiPi && + !RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], std::array{+kXiMinus, +kPiPlus, +kPiPlus}, true, nullptr, 2)) { + continue; + } } // Check momentum conservation @@ -262,54 +436,164 @@ struct HfTaskMcValidationGen { registry.fill(HIST("hPDiffMotherDaughterGen"), pDiff); registry.fill(HIST("hPtDiffMotherDaughterGen"), ptDiff); - int origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle); - if (origin == RecoDecay::OriginType::Prompt) { - counterPrompt[iD]++; - } else if (origin == RecoDecay::OriginType::NonPrompt) { - counterNonPrompt[iD]++; + int origin{0}; + if (iD < nCharmMesonChannels || iD >= nCharmMesonChannels + nBeautyChannels) { // Charm hadrons + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle); + if (origin == RecoDecay::OriginType::Prompt) { + counterPrompt[iD]++; + } else if (origin == RecoDecay::OriginType::NonPrompt) { + counterNonPrompt[iD]++; + } } - auto daughter0 = particle.daughters_as().begin(); + auto daughter0 = particle.template daughters_as().begin(); double vertexDau[3] = {daughter0.vx(), daughter0.vy(), daughter0.vz()}; double vertexPrimary[3] = {mcCollision.posX(), mcCollision.posY(), mcCollision.posZ()}; auto decayLength = RecoDecay::distance(vertexPrimary, vertexDau); - if (origin == RecoDecay::OriginType::Prompt) { - if (std::abs(particle.y()) < 0.5) { - registry.fill(HIST("promptCharmHadrons/hPromptPtDistr"), iD, particle.pt()); + if (iD < nCharmMesonChannels) { + if (origin == RecoDecay::OriginType::Prompt) { // Prompt charm mesons + if (std::abs(particle.y()) < 0.5) { + registry.fill(HIST("PromptCharmMesons/hPromptMesonsPtDistr"), iD, particle.pt()); + registry.fill(HIST("PromptCharmMesons/hPromptMesonsPtCentDistr"), iD, particle.pt(), centrality); + if (storeOccupancy) { + registry.fill(HIST("PromptCharmMesons/hPromptMesonsPtOccDistr"), iD, particle.pt(), occupancy); + } + } + registry.fill(HIST("PromptCharmMesons/hPromptMesonsYDistr"), iD, particle.y()); + registry.fill(HIST("PromptCharmMesons/hPromptMesonsDecLenDistr"), iD, decayLength * 10000); + } else if (origin == RecoDecay::OriginType::NonPrompt) { + if (std::abs(particle.y()) < 0.5) { + registry.fill(HIST("NonPromptCharmMesons/hNonPromptMesonsPtDistr"), iD, particle.pt()); + registry.fill(HIST("NonPromptCharmMesons/hNonPromptMesonsPtCentDistr"), iD, particle.pt(), centrality); + if (storeOccupancy) { + registry.fill(HIST("NonPromptCharmMesons/hNonPromptMesonsPtOccDistr"), iD, particle.pt(), occupancy); + } + } + registry.fill(HIST("NonPromptCharmMesons/hNonPromptMesonsYDistr"), iD, particle.y()); + registry.fill(HIST("NonPromptCharmMesons/hNonPromptMesonsDecLenDistr"), iD, decayLength * 10000); } - registry.fill(HIST("promptCharmHadrons/hPromptYDistr"), iD, particle.y()); - registry.fill(HIST("promptCharmHadrons/hPromptDecLenDistr"), iD, decayLength * 10000); - } else if (origin == RecoDecay::OriginType::NonPrompt) { + } else if (iD < nCharmMesonChannels + nBeautyChannels) { // Beauty mesons if (std::abs(particle.y()) < 0.5) { - registry.fill(HIST("nonPromptCharmHadrons/hNonPromptPtDistr"), iD, particle.pt()); + registry.fill(HIST("Beauty/hPtDistr"), iD - nCharmMesonChannels, particle.pt()); + registry.fill(HIST("Beauty/hPtCentDistr"), iD - nCharmMesonChannels, particle.pt(), centrality); + } + registry.fill(HIST("Beauty/hYDistr"), iD - nCharmMesonChannels, particle.y()); + registry.fill(HIST("Beauty/hDecLenDistr"), iD - nCharmMesonChannels, decayLength * 10000); + } else { // Charm baryons + if (origin == RecoDecay::OriginType::Prompt) { + if (std::abs(particle.y()) < 0.5) { + registry.fill(HIST("PromptCharmBaryons/hPromptBaryonsPtDistr"), iD - nCharmMesonChannels - nBeautyChannels, particle.pt()); + registry.fill(HIST("PromptCharmBaryons/hPromptBaryonsPtCentDistr"), iD - nCharmMesonChannels - nBeautyChannels, particle.pt(), centrality); + if (storeOccupancy) { + registry.fill(HIST("PromptCharmBaryons/hPromptBaryonsPtOccDistr"), iD - nCharmMesonChannels - nBeautyChannels, particle.pt(), occupancy); + } + } + registry.fill(HIST("PromptCharmBaryons/hPromptBaryonsYDistr"), iD - nCharmMesonChannels - nBeautyChannels, particle.y()); + registry.fill(HIST("PromptCharmBaryons/hPromptBaryonsDecLenDistr"), iD - nCharmMesonChannels - nBeautyChannels, decayLength * 10000); + } else if (origin == RecoDecay::OriginType::NonPrompt) { + if (std::abs(particle.y()) < 0.5) { + registry.fill(HIST("NonPromptCharmBaryons/hNonPromptBaryonsPtDistr"), iD - nCharmMesonChannels - nBeautyChannels, particle.pt()); + registry.fill(HIST("NonPromptCharmBaryons/hNonPromptBaryonsPtCentDistr"), iD - nCharmMesonChannels - nBeautyChannels, particle.pt(), centrality); + if (storeOccupancy) { + registry.fill(HIST("NonPromptCharmBaryons/hNonPromptBaryonsPtOccDistr"), iD - nCharmMesonChannels - nBeautyChannels, particle.pt(), occupancy); + } + } + registry.fill(HIST("NonPromptCharmBaryons/hNonPromptBaryonsYDistr"), iD - nCharmMesonChannels - nBeautyChannels, particle.y()); + registry.fill(HIST("NonPromptCharmBaryons/hNonPromptBaryonsDecLenDistr"), iD - nCharmMesonChannels - nBeautyChannels, decayLength * 10000); } - registry.fill(HIST("nonPromptCharmHadrons/hNonPromptYDistr"), iD, particle.y()); - registry.fill(HIST("nonPromptCharmHadrons/hNonPromptDecLenDistr"), iD, decayLength * 10000); } } } // end particles - registry.fill(HIST("quarks/hCountC"), cPerCollision); - registry.fill(HIST("quarks/hCountB"), bPerCollision); - registry.fill(HIST("quarks/hCountCbar"), cBarPerCollision); - registry.fill(HIST("quarks/hCountBbar"), bBarPerCollision); - registry.fill(HIST("promptCharmHadrons/hCountPromptDzeroToKPi"), counterPrompt[DzeroToKPi]); - registry.fill(HIST("promptCharmHadrons/hCountPromptDstarToD0Pi"), counterPrompt[DstarToDzeroPi]); - registry.fill(HIST("promptCharmHadrons/hCountPromptDplusToKPiPi"), counterPrompt[DplusToPiKPi]); - registry.fill(HIST("promptCharmHadrons/hCountPromptDplusToKKPi"), counterPrompt[DplusToPhiPiToKKPi]); - registry.fill(HIST("promptCharmHadrons/hCountPromptDsToKKpi"), counterPrompt[DsToPhiPiToKKPi]); - registry.fill(HIST("promptCharmHadrons/hCountPromptLambdaCToPKPi"), counterPrompt[LcToPKPi]); - registry.fill(HIST("promptCharmHadrons/hCountPromptLambdaCToPK0s"), counterPrompt[LcToPiK0s]); - registry.fill(HIST("promptCharmHadrons/hCountPromptXiCToPKPi"), counterPrompt[XicToPKPi]); - registry.fill(HIST("nonPromptCharmHadrons/hCountNonPromptDzeroToKPi"), counterNonPrompt[DzeroToKPi]); - registry.fill(HIST("nonPromptCharmHadrons/hCountNonPromptDstarToD0Pi"), counterNonPrompt[DstarToDzeroPi]); - registry.fill(HIST("nonPromptCharmHadrons/hCountNonPromptDplusToKPiPi"), counterNonPrompt[DplusToPiKPi]); - registry.fill(HIST("nonPromptCharmHadrons/hCountNonPromptDplusToKKPi"), counterNonPrompt[DplusToPhiPiToKKPi]); - registry.fill(HIST("nonPromptCharmHadrons/hCountNonPromptDsToKKpi"), counterNonPrompt[DsToPhiPiToKKPi]); - registry.fill(HIST("nonPromptCharmHadrons/hCountNonPromptLambdaCToPKPi"), counterNonPrompt[LcToPKPi]); - registry.fill(HIST("nonPromptCharmHadrons/hCountNonPromptLambdaCToPK0s"), counterNonPrompt[LcToPiK0s]); - registry.fill(HIST("nonPromptCharmHadrons/hCountNonPromptXiCToPKPi"), counterNonPrompt[XicToPKPi]); - }; + registry.fill(HIST("Quarks/hCountC"), cPerCollision); + registry.fill(HIST("Quarks/hCountB"), bPerCollision); + registry.fill(HIST("Quarks/hCountCbar"), cBarPerCollision); + registry.fill(HIST("Quarks/hCountBbar"), bBarPerCollision); + } + + void processNoCentSel(aod::McCollisions const& mcCollisions, + aod::McParticles const& mcParticles, + CollisionsNoCents const& recoCollisions, + BCsInfo const& bcInfo) + { + for (const auto& mcCollision : mcCollisions) { + const auto recoCollsPerMcColl = recoCollisions.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + const auto mcParticlesPerMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, mcCollision.globalIndex()); + std::array counterPrompt{0}, counterNonPrompt{0}; + runCheckGenParticles(mcCollision, mcParticlesPerMcColl, recoCollsPerMcColl, bcInfo, counterPrompt, counterNonPrompt); + static_for<0, nCharmMesonChannels - 1>([&](auto i) { // Charm mesons + constexpr int index = i.value; + registry.fill(HIST("PromptCharmMesons/hCountPrompt") + HIST(particleNames[index]), counterPrompt[index]); + registry.fill(HIST("NonPromptCharmMesons/hCountNonPrompt") + HIST(particleNames[index]), counterNonPrompt[index]); + }); + static_for([&](auto i) { // Beauty hadrons + constexpr int index = i.value; + registry.fill(HIST("Beauty/hCount") + HIST(particleNames[index]), counterPrompt[index]); + }); + static_for([&](auto i) { // Charm baryons + constexpr int index = i.value; + registry.fill(HIST("PromptCharmBaryons/hCountPrompt") + HIST(particleNames[index]), counterPrompt[index]); + registry.fill(HIST("NonPromptCharmBaryons/hCountNonPrompt") + HIST(particleNames[index]), counterNonPrompt[index]); + }); + } + } // end processNoCentSel + PROCESS_SWITCH(HfTaskMcValidationGen, processNoCentSel, "Process generated collisions information without centrality selection", true); + + void processCentFT0C(aod::McCollisions const& mcCollisions, + aod::McParticles const& mcParticles, + CollisionsFT0Cs const& recoCollisions, + BCsInfo const& bcInfo) + { + for (const auto& mcCollision : mcCollisions) { + const auto recoCollsPerMcColl = recoCollisions.sliceBy(colPerMcCollisionFT0C, mcCollision.globalIndex()); + const auto mcParticlesPerMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, mcCollision.globalIndex()); + std::array counterPrompt{0}, counterNonPrompt{0}; + runCheckGenParticles(mcCollision, mcParticlesPerMcColl, recoCollsPerMcColl, bcInfo, counterPrompt, counterNonPrompt); + static_for<0, nCharmMesonChannels - 1>([&](auto i) { // Charm mesons + constexpr int index = i.value; + registry.fill(HIST("PromptCharmMesons/hCountPrompt") + HIST(particleNames[index]), counterPrompt[index]); + registry.fill(HIST("NonPromptCharmMesons/hCountNonPrompt") + HIST(particleNames[index]), counterNonPrompt[index]); + }); + static_for([&](auto i) { // Beauty + constexpr int index = i.value; + registry.fill(HIST("Beauty/hCount") + HIST(particleNames[index]), counterPrompt[index]); + }); + static_for([&](auto i) { // Charm baryons + constexpr int index = i.value; + registry.fill(HIST("PromptCharmBaryons/hCountPrompt") + HIST(particleNames[index]), counterPrompt[index]); + registry.fill(HIST("NonPromptCharmBaryons/hCountNonPrompt") + HIST(particleNames[index]), counterNonPrompt[index]); + }); + } + } // end processCentFT0C + PROCESS_SWITCH(HfTaskMcValidationGen, processCentFT0C, "Process generated collisions information with centrality selection using FT0C", false); + + void processCentFT0M(McCollisionsCentFT0Ms const& mcCollisions, + aod::McParticles const& mcParticles, + CollisionsFT0Ms const& recoCollisions, + BCsInfo const& bcInfo) + { + for (const auto& mcCollision : mcCollisions) { + const auto recoCollsPerMcColl = recoCollisions.sliceBy(colPerMcCollisionFT0M, mcCollision.globalIndex()); + const auto mcParticlesPerMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, mcCollision.globalIndex()); + std::array counterPrompt{0}, counterNonPrompt{0}; + runCheckGenParticles(mcCollision, mcParticlesPerMcColl, recoCollsPerMcColl, bcInfo, counterPrompt, counterNonPrompt); + static_for<0, nCharmMesonChannels - 1>([&](auto i) { // Charm mesons + constexpr int index = i.value; + registry.fill(HIST("PromptCharmMesons/hCountPrompt") + HIST(particleNames[index]), counterPrompt[index]); + registry.fill(HIST("NonPromptCharmMesons/hCountNonPrompt") + HIST(particleNames[index]), counterNonPrompt[index]); + }); + static_for([&](auto i) { // Beauty mesons + constexpr int index = i.value; + registry.fill(HIST("Beauty/hCount") + HIST(particleNames[index]), counterPrompt[index]); + }); + static_for([&](auto i) { // Charm baryons + constexpr int index = i.value; + registry.fill(HIST("PromptCharmBaryons/hCountPrompt") + HIST(particleNames[index]), counterPrompt[index]); + registry.fill(HIST("NonPromptCharmBaryons/hCountNonPrompt") + HIST(particleNames[index]), counterNonPrompt[index]); + }); + } + } // end processCentFT0M + PROCESS_SWITCH(HfTaskMcValidationGen, processCentFT0M, "Process generated collisions information with centrality selection using FT0M", false); }; /// Reconstruction Level Validation @@ -321,27 +605,40 @@ struct HfTaskMcValidationRec { Preslice perCol = aod::track::collisionId; Configurable eventGeneratorType{"eventGeneratorType", -1, "If positive, enable event selection using subGeneratorId information. The value indicates which events to keep (0 = MB, 4 = charm triggered, 5 = beauty triggered)"}; + Configurable storeOccupancy{"storeOccupancy", false, "Store collision occupancy for dedicated studies"}; std::array, nChannels> histDeltaPt, histDeltaPx, histDeltaPy, histDeltaPz, histDeltaSecondaryVertexX, histDeltaSecondaryVertexY, histDeltaSecondaryVertexZ, histDeltaDecayLength; - std::array, 3>, 2>, nChannels> histPtDau, histEtaDau, histImpactParameterDau; - std::array, 2>, nChannels> histPtReco; + std::array, 2>, nChannels> histPtCentReco; + std::array, 2>, nChannels> histPtOccReco; + std::array, 5>, 2>, nChannels> histPtDau, histEtaDau, histImpactParameterDau; std::array, 4> histOriginTracks; std::shared_ptr histAmbiguousTracks, histTracks; std::shared_ptr histContributors; using HfCand2ProngWithMCRec = soa::Join; using HfCand3ProngWithMCRec = soa::Join; - using CollisionsWithMCLabels = soa::Join; + using CandMcGen = soa::Join; + using CollisionsWithMCLabels = soa::Join; + using CollisionsWithMCLabelsAndCentFT0C = soa::Join; + using CollisionsWithMCLabelsAndCentFT0M = soa::Join; using TracksWithSel = soa::Join; Partition tracksFilteredGlobalTrackWoDCA = requireGlobalTrackWoDCAInFilter(); Partition tracksInAcc = requireTrackCutInFilter(TrackSelectionFlags::kInAcceptanceTracks); + Preslice cand2ProngPerCollision = aod::hf_cand::collisionId; + Preslice cand3ProngPerCollision = aod::hf_cand::collisionId; + + Service ccdb; + HfEventSelection hfEvSel; // event selection and monitoring + AxisSpec axisDeltaMom{2000, -1., 1.}; AxisSpec axisOrigin{4, -1.5, 2.5}; AxisSpec axisEta{40, -1., 1.}; AxisSpec axisPt{50, 0., 10.}; AxisSpec axisPtD{100, 0., 50.}; + AxisSpec axisCent{110, 0., 110.}; + AxisSpec axisOcc{3000, 0., 15000.}; AxisSpec axisDeltaVtx{200, -1, 1.}; AxisSpec axisDecision{2, -0.5, 1.5}; AxisSpec axisITShits{8, -0.5, 7.5}; @@ -352,14 +649,17 @@ struct HfTaskMcValidationRec { HistogramRegistry registry{ "registry", {{"histNtracks", "Number of global tracks w/o DCA requirement;#it{N}_{tracks};entries", {HistType::kTH1F, {axisMult}}}, + {"hNevReco", "Reconstructed events counter; Reco. events; entries", {HistType::kTH1F, {{1, -0.5, +0.5}}}}, {"histXvtxReco", "Position of reco PV in #it{X};#it{X}^{reco} (cm);entries", {HistType::kTH1F, {axisDeltaVtx}}}, {"histYvtxReco", "Position of reco PV in #it{Y};#it{Y}^{reco} (cm);entries", {HistType::kTH1F, {axisDeltaVtx}}}, {"histZvtxReco", "Position of reco PV in #it{Z};#it{Z}^{reco} (cm);entries", {HistType::kTH1F, {{200, -20, 20.}}}}, {"histDeltaZvtx", "Residual distribution of PV in #it{Z} as a function of number of contributors;number of contributors;#it{Z}^{reco} - #it{Z}^{gen} (cm);entries", {HistType::kTH2F, {{100, -0.5, 99.5}, {1000, -0.5, 0.5}}}}, - {"trackToCollChecks/histAmbiguousTrackNumCollisions", "Number of collisions associated to an ambiguous track;number of collisions;entries", {HistType::kTH1F, {{30, -0.5, 29.5}}}}, - {"trackToCollChecks/histAmbiguousTrackZvtxRMS", "RMS of #it{Z}^{reco} of collisions associated to a track;RMS(#it{Z}^{reco}) (cm);entries", {HistType::kTH1F, {{100, 0., 0.5}}}}, - {"trackToCollChecks/histFracGoodContributors", "Fraction of PV contributors originating from the correct collision;fraction;entries", {HistType::kTH1F, {{101, 0., 1.01}}}}, - {"trackToCollChecks/histCollisionsSameBC", "Collisions in same BC;number of contributors collision 1;number of contributors collision 2;#it{R}_{xy} collision 1 (cm);#it{R}_{xy} collision 2 (cm);number of contributors from beauty collision 1;number of contributors from beauty collision 2;", {HistType::kTHnSparseF, {axisMult, axisMult, axisR, axisR, axisSmallNum, axisSmallNum}}}}}; + {"TrackToCollChecks/histAmbiguousTrackNumCollisions", "Number of collisions associated to an ambiguous track;number of collisions;entries", {HistType::kTH1F, {{30, -0.5, 29.5}}}}, + {"TrackToCollChecks/histAmbiguousTrackZvtxRMS", "RMS of #it{Z}^{reco} of collisions associated to a track;RMS(#it{Z}^{reco}) (cm);entries", {HistType::kTH1F, {{100, 0., 0.5}}}}, + {"TrackToCollChecks/histFracGoodContributors", "Fraction of PV contributors originating from the correct collision;fraction;entries", {HistType::kTH1F, {{101, 0., 1.01}}}}, + {"TrackToCollChecks/histCollisionsSameBC", "Collisions in same BC;number of contributors collision 1;number of contributors collision 2;#it{R}_{xy} collision 1 (cm);#it{R}_{xy} collision 2 (cm);number of contributors from beauty collision 1;number of contributors from beauty collision 2;", {HistType::kTHnSparseF, {axisMult, axisMult, axisR, axisR, axisSmallNum, axisSmallNum}}}}}; + HistogramRegistry registryMesons{"registryMesons"}; + HistogramRegistry registryBaryons{"registryBaryons"}; /// RMS calculation /// \param vec vector of values to compute RMS @@ -382,8 +682,10 @@ struct HfTaskMcValidationRec { /// \param mother is mother particle /// \param whichHad int indicating charm-hadron and decay channel, see enum DecayChannels /// \param whichOrigin int indicating origin: prompt or non-prompt + /// \param centrality is collision centrality + /// \param occupancy is collision occupancy template - void fillHisto(const T& candidate, const U& mother, int whichHad, int whichOrigin) + void fillHisto(const T& candidate, const U& mother, int whichHad, int whichOrigin, float centrality, int occupancy) { histDeltaPt[whichHad]->Fill(candidate.pt() - mother.pt()); histDeltaPx[whichHad]->Fill(candidate.px() - mother.px()); @@ -405,7 +707,10 @@ struct HfTaskMcValidationRec { std::array momDau1 = {candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1()}; - histPtReco[whichHad][whichOrigin]->Fill(candidate.pt()); + histPtCentReco[whichHad][whichOrigin]->Fill(candidate.pt(), centrality); + if (storeOccupancy) { + histPtOccReco[whichHad][whichOrigin]->Fill(candidate.pt(), occupancy); + } histPtDau[whichHad][whichOrigin][0]->Fill(RecoDecay::pt(momDau0)); histEtaDau[whichHad][whichOrigin][0]->Fill(RecoDecay::eta(momDau0)); histImpactParameterDau[whichHad][whichOrigin][0]->Fill(candidate.impactParameter0()); @@ -416,17 +721,27 @@ struct HfTaskMcValidationRec { void init(InitContext&) { - histOriginTracks[0] = registry.add("trackToCollChecks/histOriginNonAssociatedTracks", ";origin;#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm); is PV contributor; has TOF; number of ITS hits", HistType::kTHnSparseF, {axisOrigin, axisPt, axisEta, axisDeltaVtx, axisDecision, axisDecision, axisITShits}); // tracks not associated to any collision - histOriginTracks[1] = registry.add("trackToCollChecks/histOriginAssociatedTracks", ";origin;#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm); is PV contributor; has TOF; number of ITS hits", HistType::kTHnSparseF, {axisOrigin, axisPt, axisEta, axisDeltaVtx, axisDecision, axisDecision, axisITShits}); // tracks associasted to a collision - histOriginTracks[2] = registry.add("trackToCollChecks/histOriginGoodAssociatedTracks", ";origin;#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm); is PV contributor; has TOF; number of ITS hits", HistType::kTHnSparseF, {axisOrigin, axisPt, axisEta, axisDeltaVtx, axisDecision, axisDecision, axisITShits}); // tracks associated to the correct collision considering only first reco collision (based on the MC collision index) - histOriginTracks[3] = registry.add("trackToCollChecks/histOriginGoodAssociatedTracksAmbiguous", ";origin;#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm); is PV contributor; has TOF; number of ITS hits", HistType::kTHnSparseF, {axisOrigin, axisPt, axisEta, axisDeltaVtx, axisDecision, axisDecision, axisITShits}); // tracks associated to the correct collision considering all ambiguous reco collisions (based on the MC collision index) + std::array procCollisions = {doprocessColl, doprocessCollWithCentFTOC, doprocessCollWithCentFTOM}; + if (std::accumulate(procCollisions.begin(), procCollisions.end(), 0) > 1) { + LOGP(fatal, "At most one process function for collision study can be enabled at a time."); + } + + std::array procCollAccoc = {doprocessCollAssoc, doprocessCollAssocWithCentFTOC, doprocessCollAssocWithCentFTOM}; + if (std::accumulate(procCollAccoc.begin(), procCollAccoc.end(), 0) > 1) { + LOGP(fatal, "At most one process for collision association study function can be enabled at a time."); + } + + histOriginTracks[0] = registry.add("TrackToCollChecks/histOriginNonAssociatedTracks", ";origin;#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm); is PV contributor; has TOF; number of ITS hits", HistType::kTHnSparseF, {axisOrigin, axisPt, axisEta, axisDeltaVtx, axisDecision, axisDecision, axisITShits}); // tracks not associated to any collision + histOriginTracks[1] = registry.add("TrackToCollChecks/histOriginAssociatedTracks", ";origin;#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm); is PV contributor; has TOF; number of ITS hits", HistType::kTHnSparseF, {axisOrigin, axisPt, axisEta, axisDeltaVtx, axisDecision, axisDecision, axisITShits}); // tracks associasted to a collision + histOriginTracks[2] = registry.add("TrackToCollChecks/histOriginGoodAssociatedTracks", ";origin;#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm); is PV contributor; has TOF; number of ITS hits", HistType::kTHnSparseF, {axisOrigin, axisPt, axisEta, axisDeltaVtx, axisDecision, axisDecision, axisITShits}); // tracks associated to the correct collision considering only first reco collision (based on the MC collision index) + histOriginTracks[3] = registry.add("TrackToCollChecks/histOriginGoodAssociatedTracksAmbiguous", ";origin;#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm); is PV contributor; has TOF; number of ITS hits", HistType::kTHnSparseF, {axisOrigin, axisPt, axisEta, axisDeltaVtx, axisDecision, axisDecision, axisITShits}); // tracks associated to the correct collision considering all ambiguous reco collisions (based on the MC collision index) for (std::size_t iHist{0}; iHist < histOriginTracks.size(); ++iHist) { histOriginTracks[iHist]->GetAxis(0)->SetBinLabel(1, "no MC particle"); histOriginTracks[iHist]->GetAxis(0)->SetBinLabel(2, "no quark"); histOriginTracks[iHist]->GetAxis(0)->SetBinLabel(3, "charm"); histOriginTracks[iHist]->GetAxis(0)->SetBinLabel(4, "beauty"); } - histAmbiguousTracks = registry.add("trackToCollChecks/histAmbiguousTracks", "Tracks that are ambiguous vs. origin;#it{p}_{T}^{reco} (GeV/#it{c});entries", HistType::kTH2F, {axisOrigin, axisPt}); + histAmbiguousTracks = registry.add("TrackToCollChecks/histAmbiguousTracks", "Tracks that are ambiguous vs. origin;#it{p}_{T}^{reco} (GeV/#it{c});entries", HistType::kTH2F, {axisOrigin, axisPt}); histTracks = registry.add("histTracks", "Tracks vs. origin;#it{p}_{T}^{reco} (GeV/#it{c});entries", HistType::kTH2F, {axisOrigin, axisPt}); histTracks->GetXaxis()->SetBinLabel(1, "no MC particle"); histTracks->GetXaxis()->SetBinLabel(2, "no quark"); @@ -437,53 +752,112 @@ struct HfTaskMcValidationRec { histAmbiguousTracks->GetXaxis()->SetBinLabel(3, "charm"); histAmbiguousTracks->GetXaxis()->SetBinLabel(4, "beauty"); for (auto iHad = 0; iHad < nChannels; ++iHad) { - histDeltaPt[iHad] = registry.add(Form("%s/histDeltaPt", particleNames[iHad].data()), Form("Pt difference reco - MC %s; #it{p}_{T}^{reco} - #it{p}_{T}^{gen} (GeV/#it{c}); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaMom}); - histDeltaPx[iHad] = registry.add(Form("%s/histDeltaPx", particleNames[iHad].data()), Form("Px difference reco - MC %s; #it{p}_{x}^{reco} - #it{p}_{x}^{gen} (GeV/#it{c}); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaMom}); - histDeltaPy[iHad] = registry.add(Form("%s/histDeltaPy", particleNames[iHad].data()), Form("Py difference reco - MC %s; #it{p}_{y}^{reco} - #it{p}_{y}^{gen} (GeV/#it{c}); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaMom}); - histDeltaPz[iHad] = registry.add(Form("%s/histDeltaPz", particleNames[iHad].data()), Form("Pz difference reco - MC %s; #it{p}_{z}^{reco} - #it{p}_{z}^{gen} (GeV/#it{c}); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaMom}); - histDeltaSecondaryVertexX[iHad] = registry.add(Form("%s/histDeltaSecondaryVertexX", particleNames[iHad].data()), Form("Sec. Vertex difference reco - MC (MC matched) - %s; #Delta x (cm); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaVtx}); - histDeltaSecondaryVertexY[iHad] = registry.add(Form("%s/histDeltaSecondaryVertexY", particleNames[iHad].data()), Form("Sec. Vertex difference reco - MC (MC matched) - %s; #Delta y (cm); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaVtx}); - histDeltaSecondaryVertexZ[iHad] = registry.add(Form("%s/histDeltaSecondaryVertexZ", particleNames[iHad].data()), Form("Sec. Vertex difference reco - MC (MC matched) - %s; #Delta z (cm); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaVtx}); - histDeltaDecayLength[iHad] = registry.add(Form("%s/histDeltaDecayLength", particleNames[iHad].data()), Form("Decay length difference reco - MC (%s); #Delta L (cm); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaVtx}); - for (auto iOrigin = 0; iOrigin < 2; ++iOrigin) { - histPtReco[iHad][iOrigin] = registry.add(Form("%s/histPtReco%s", particleNames[iHad].data(), originNames[iOrigin].data()), Form("Pt reco %s %s; #it{p}_{T}^{reco} (GeV/#it{c}); entries", originNames[iOrigin].data(), labels[iHad].data()), HistType::kTH1F, {axisPtD}); - for (unsigned int iDau = 0; iDau < nDaughters[iHad]; ++iDau) { - histPtDau[iHad][iOrigin][iDau] = registry.add(Form("%s/histPtDau%d%s", particleNames[iHad].data(), iDau, originNames[iOrigin].data()), Form("Daughter %d Pt reco - %s %s; #it{p}_{T}^{dau, reco} (GeV/#it{c}); entries", iDau, originNames[iOrigin].data(), labels[iHad].data()), HistType::kTH1F, {axisPt}); - histEtaDau[iHad][iOrigin][iDau] = registry.add(Form("%s/histEtaDau%d%s", particleNames[iHad].data(), iDau, originNames[iOrigin].data()), Form("Daughter %d Eta reco - %s %s; #it{#eta}^{dau, reco}; entries", iDau, originNames[iOrigin].data(), labels[iHad].data()), HistType::kTH1F, {{100, -1., 1.}}); - histImpactParameterDau[iHad][iOrigin][iDau] = registry.add(Form("%s/histImpactParameterDau%d%s", particleNames[iHad].data(), iDau, originNames[iOrigin].data()), Form("Daughter %d DCAxy reco - %s %s; DCAxy (cm); entries", iDau, originNames[iOrigin].data(), labels[iHad].data()), HistType::kTH1F, {axisDeltaVtx}); + if (iHad < nCharmMesonChannels) { + histDeltaPt[iHad] = registryMesons.add(Form("%s/histDeltaPt", particleNames[iHad].data()), Form("Pt difference reco - MC %s; #it{p}_{T}^{reco} - #it{p}_{T}^{gen} (GeV/#it{c}); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaMom}); + histDeltaPx[iHad] = registryMesons.add(Form("%s/histDeltaPx", particleNames[iHad].data()), Form("Px difference reco - MC %s; #it{p}_{x}^{reco} - #it{p}_{x}^{gen} (GeV/#it{c}); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaMom}); + histDeltaPy[iHad] = registryMesons.add(Form("%s/histDeltaPy", particleNames[iHad].data()), Form("Py difference reco - MC %s; #it{p}_{y}^{reco} - #it{p}_{y}^{gen} (GeV/#it{c}); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaMom}); + histDeltaPz[iHad] = registryMesons.add(Form("%s/histDeltaPz", particleNames[iHad].data()), Form("Pz difference reco - MC %s; #it{p}_{z}^{reco} - #it{p}_{z}^{gen} (GeV/#it{c}); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaMom}); + histDeltaSecondaryVertexX[iHad] = registryMesons.add(Form("%s/histDeltaSecondaryVertexX", particleNames[iHad].data()), Form("Sec. Vertex difference reco - MC (MC matched) - %s; #Delta x (cm); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaVtx}); + histDeltaSecondaryVertexY[iHad] = registryMesons.add(Form("%s/histDeltaSecondaryVertexY", particleNames[iHad].data()), Form("Sec. Vertex difference reco - MC (MC matched) - %s; #Delta y (cm); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaVtx}); + histDeltaSecondaryVertexZ[iHad] = registryMesons.add(Form("%s/histDeltaSecondaryVertexZ", particleNames[iHad].data()), Form("Sec. Vertex difference reco - MC (MC matched) - %s; #Delta z (cm); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaVtx}); + histDeltaDecayLength[iHad] = registryMesons.add(Form("%s/histDeltaDecayLength", particleNames[iHad].data()), Form("Decay length difference reco - MC (%s); #Delta L (cm); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaVtx}); + for (auto iOrigin = 0; iOrigin < 2; ++iOrigin) { + histPtCentReco[iHad][iOrigin] = registryMesons.add(Form("%s/histPtCentReco%s", particleNames[iHad].data(), originNames[iOrigin].data()), Form("Pt Cent reco %s %s; #it{p}_{T}^{reco} (GeV/#it{c}); Centrality (%%); entries", originNames[iOrigin].data(), labels[iHad].data()), HistType::kTH2F, {axisPtD, axisCent}); + if (storeOccupancy) { + histPtOccReco[iHad][iOrigin] = registryMesons.add(Form("%s/histPtOccReco%s", particleNames[iHad].data(), originNames[iOrigin].data()), Form("Pt Cent reco %s %s; #it{p}_{T}^{reco} (GeV/#it{c}); Occupancy; entries", originNames[iOrigin].data(), labels[iHad].data()), HistType::kTH2F, {axisPtD, axisOcc}); + } + for (unsigned int iDau = 0; iDau < nDaughters[iHad]; ++iDau) { + histPtDau[iHad][iOrigin][iDau] = registryMesons.add(Form("%s/histPtDau%d%s", particleNames[iHad].data(), iDau, originNames[iOrigin].data()), Form("Daughter %d Pt reco - %s %s; #it{p}_{T}^{dau, reco} (GeV/#it{c}); entries", iDau, originNames[iOrigin].data(), labels[iHad].data()), HistType::kTH1F, {axisPt}); + histEtaDau[iHad][iOrigin][iDau] = registryMesons.add(Form("%s/histEtaDau%d%s", particleNames[iHad].data(), iDau, originNames[iOrigin].data()), Form("Daughter %d Eta reco - %s %s; #it{#eta}^{dau, reco}; entries", iDau, originNames[iOrigin].data(), labels[iHad].data()), HistType::kTH1F, {{100, -1., 1.}}); + histImpactParameterDau[iHad][iOrigin][iDau] = registryMesons.add(Form("%s/histImpactParameterDau%d%s", particleNames[iHad].data(), iDau, originNames[iOrigin].data()), Form("Daughter %d DCAxy reco - %s %s; DCAxy (cm); entries", iDau, originNames[iOrigin].data(), labels[iHad].data()), HistType::kTH1F, {axisDeltaVtx}); + } + } + } else if (iHad >= nCharmMesonChannels + nBeautyChannels) { + histDeltaPt[iHad] = registryBaryons.add(Form("%s/histDeltaPt", particleNames[iHad].data()), Form("Pt difference reco - MC %s; #it{p}_{T}^{reco} - #it{p}_{T}^{gen} (GeV/#it{c}); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaMom}); + histDeltaPx[iHad] = registryBaryons.add(Form("%s/histDeltaPx", particleNames[iHad].data()), Form("Px difference reco - MC %s; #it{p}_{x}^{reco} - #it{p}_{x}^{gen} (GeV/#it{c}); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaMom}); + histDeltaPy[iHad] = registryBaryons.add(Form("%s/histDeltaPy", particleNames[iHad].data()), Form("Py difference reco - MC %s; #it{p}_{y}^{reco} - #it{p}_{y}^{gen} (GeV/#it{c}); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaMom}); + histDeltaPz[iHad] = registryBaryons.add(Form("%s/histDeltaPz", particleNames[iHad].data()), Form("Pz difference reco - MC %s; #it{p}_{z}^{reco} - #it{p}_{z}^{gen} (GeV/#it{c}); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaMom}); + histDeltaSecondaryVertexX[iHad] = registryBaryons.add(Form("%s/histDeltaSecondaryVertexX", particleNames[iHad].data()), Form("Sec. Vertex difference reco - MC (MC matched) - %s; #Delta x (cm); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaVtx}); + histDeltaSecondaryVertexY[iHad] = registryBaryons.add(Form("%s/histDeltaSecondaryVertexY", particleNames[iHad].data()), Form("Sec. Vertex difference reco - MC (MC matched) - %s; #Delta y (cm); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaVtx}); + histDeltaSecondaryVertexZ[iHad] = registryBaryons.add(Form("%s/histDeltaSecondaryVertexZ", particleNames[iHad].data()), Form("Sec. Vertex difference reco - MC (MC matched) - %s; #Delta z (cm); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaVtx}); + histDeltaDecayLength[iHad] = registryBaryons.add(Form("%s/histDeltaDecayLength", particleNames[iHad].data()), Form("Decay length difference reco - MC (%s); #Delta L (cm); entries", labels[iHad].data()), HistType::kTH1F, {axisDeltaVtx}); + for (auto iOrigin = 0; iOrigin < 2; ++iOrigin) { + histPtCentReco[iHad][iOrigin] = registryBaryons.add(Form("%s/histPtCentReco%s", particleNames[iHad].data(), originNames[iOrigin].data()), Form("Pt Cent reco %s %s; #it{p}_{T}^{reco} (GeV/#it{c}); Centrality (%%); entries", originNames[iOrigin].data(), labels[iHad].data()), HistType::kTH2F, {axisPtD, axisCent}); + if (storeOccupancy) { + histPtOccReco[iHad][iOrigin] = registryBaryons.add(Form("%s/histPtOccReco%s", particleNames[iHad].data(), originNames[iOrigin].data()), Form("Pt Cent reco %s %s; #it{p}_{T}^{reco} (GeV/#it{c}); Occupancy; entries", originNames[iOrigin].data(), labels[iHad].data()), HistType::kTH2F, {axisPtD, axisOcc}); + } + for (unsigned int iDau = 0; iDau < nDaughters[iHad]; ++iDau) { + histPtDau[iHad][iOrigin][iDau] = registryBaryons.add(Form("%s/histPtDau%d%s", particleNames[iHad].data(), iDau, originNames[iOrigin].data()), Form("Daughter %d Pt reco - %s %s; #it{p}_{T}^{dau, reco} (GeV/#it{c}); entries", iDau, originNames[iOrigin].data(), labels[iHad].data()), HistType::kTH1F, {axisPt}); + histEtaDau[iHad][iOrigin][iDau] = registryBaryons.add(Form("%s/histEtaDau%d%s", particleNames[iHad].data(), iDau, originNames[iOrigin].data()), Form("Daughter %d Eta reco - %s %s; #it{#eta}^{dau, reco}; entries", iDau, originNames[iOrigin].data(), labels[iHad].data()), HistType::kTH1F, {{100, -1., 1.}}); + histImpactParameterDau[iHad][iOrigin][iDau] = registryBaryons.add(Form("%s/histImpactParameterDau%d%s", particleNames[iHad].data(), iDau, originNames[iOrigin].data()), Form("Daughter %d DCAxy reco - %s %s; DCAxy (cm); entries", iDau, originNames[iOrigin].data(), labels[iHad].data()), HistType::kTH1F, {axisDeltaVtx}); + } } } } - histContributors = registry.add("trackToCollChecks/histContributors", "PV contributors from correct/wrong MC collision;;entries", HistType::kTH1F, {axisDecision}); + histContributors = registry.add("TrackToCollChecks/histContributors", "PV contributors from correct/wrong MC collision;;entries", HistType::kTH1F, {axisDecision}); histContributors->GetXaxis()->SetBinLabel(1, "correct MC collision"); histContributors->GetXaxis()->SetBinLabel(2, "wrong MC collision"); + hfEvSel.addHistograms(registry); // collision monitoring + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + } + + template + void checkCollisions(Coll const& collision, + aod::McCollisions const&, + aod::BCsWithTimestamps const&) + { + // apply event selection + if (!collision.has_mcCollision()) { + return; + } + + float centrality{-1.f}; + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + if (rejectionMask != 0) { + /// at least one event selection not satisfied --> reject the candidate + return; + } + + auto mcCollision = collision.template mcCollision_as(); + if (eventGeneratorType >= 0 && mcCollision.getSubGeneratorId() != eventGeneratorType) { + return; + } + + registry.fill(HIST("hNevReco"), 1); + registry.fill(HIST("histXvtxReco"), collision.posX()); + registry.fill(HIST("histYvtxReco"), collision.posY()); + registry.fill(HIST("histZvtxReco"), collision.posZ()); + registry.fill(HIST("histDeltaZvtx"), collision.numContrib(), collision.posZ() - mcCollision.posZ()); } - void process(HfCand2ProngWithMCRec const& cand2Prongs, - HfCand3ProngWithMCRec const& cand3Prongs, - TracksWithSel const&, - aod::McParticles const& mcParticles, - aod::McCollisions const&, - CollisionsWithMCLabels const& collisions, - aod::BCs const&) + template + void checkCollisionAssociation(Colls const& collisions, + TracksWithSel const&, + aod::McParticles const& mcParticles, + aod::McCollisions const&, + aod::BCsWithTimestamps const&) { // loop over collisions - for (auto collision = collisions.begin(); collision != collisions.end(); ++collision) { - if (collision.whyRejectColl() != 0) { // check that collision is selected by hf-track-index-skim-creator-tag-sel-collisions + for (const auto& collision : collisions) { + // check that collision is selected by hf-track-index-skim-creator-tag-sel-collisions + + float centrality{-1.f}; + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + if (rejectionMask != 0) { + /// at least one event selection not satisfied --> reject the candidate continue; } + if (!collision.has_mcCollision()) { continue; } - auto mcCollision = collision.mcCollision_as(); + auto mcCollision = collision.template mcCollision_as(); if (eventGeneratorType >= 0 && mcCollision.getSubGeneratorId() != eventGeneratorType) { continue; } - registry.fill(HIST("histXvtxReco"), collision.posX()); - registry.fill(HIST("histYvtxReco"), collision.posY()); - registry.fill(HIST("histZvtxReco"), collision.posZ()); - auto deltaZ = collision.posZ() - mcCollision.posZ(); - registry.fill(HIST("histDeltaZvtx"), collision.numContrib(), deltaZ); auto tracksGlobalWoDCAColl1 = tracksFilteredGlobalTrackWoDCA->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); registry.fill(HIST("histNtracks"), tracksGlobalWoDCAColl1.size()); auto tracksColl1 = tracksInAcc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); @@ -502,7 +876,7 @@ struct HfTaskMcValidationRec { } } float frac = (nContributors > 0) ? static_cast(nGoodContributors) / nContributors : 1.; - registry.fill(HIST("trackToCollChecks/histFracGoodContributors"), frac); + registry.fill(HIST("TrackToCollChecks/histFracGoodContributors"), frac); uint64_t mostProbableBC = collision.bc().globalBC(); for (auto collision2 = collision + 1; collision2 != collisions.end(); ++collision2) { uint64_t mostProbableBC2 = collision2.bc().globalBC(); @@ -529,7 +903,7 @@ struct HfTaskMcValidationRec { } } } - registry.fill(HIST("trackToCollChecks/histCollisionsSameBC"), collision.numContrib(), collision2.numContrib(), radColl1, radColl2, nFromBeautyColl1, nFromBeautyColl2); + registry.fill(HIST("TrackToCollChecks/histCollisionsSameBC"), collision.numContrib(), collision2.numContrib(), radColl1, radColl2, nFromBeautyColl1, nFromBeautyColl2); break; } } @@ -556,7 +930,7 @@ struct HfTaskMcValidationRec { histTracks->Fill(origin, track.pt()); bool isAmbiguous = (track.compatibleCollIds().size() != 1); if (isAmbiguous) { - registry.fill(HIST("trackToCollChecks/histAmbiguousTrackNumCollisions"), track.compatibleCollIds().size()); + registry.fill(HIST("TrackToCollChecks/histAmbiguousTrackNumCollisions"), track.compatibleCollIds().size()); histAmbiguousTracks->Fill(origin, track.pt()); std::vector ambCollPosZ{}; for (const auto& collIdx : track.compatibleCollIds()) { @@ -565,7 +939,7 @@ struct HfTaskMcValidationRec { } // here we are only interested to tracks associated to multiple vertices if (ambCollPosZ.size() > 0) { - registry.fill(HIST("trackToCollChecks/histAmbiguousTrackZvtxRMS"), computeRMS(ambCollPosZ)); + registry.fill(HIST("TrackToCollChecks/histAmbiguousTrackZvtxRMS"), computeRMS(ambCollPosZ)); } } float deltaZ = -999.f; @@ -600,107 +974,202 @@ struct HfTaskMcValidationRec { histOriginTracks[index]->Fill(-1.f, track.pt(), track.eta(), -999.f, track.isPVContributor(), track.hasTOF(), nITSlayers); } } + } - // loop over 2-prong candidates - for (const auto& cand2Prong : cand2Prongs) { + void processColl(CollisionsWithMCLabels::iterator const& collision, + aod::McCollisions const& mcCollisions, + aod::BCsWithTimestamps const& bcs) + { + checkCollisions(collision, mcCollisions, bcs); + } // end process + PROCESS_SWITCH(HfTaskMcValidationRec, processColl, "Process collision information without centrality selection", true); - if (cand2Prong.collision_as().has_mcCollision()) { - auto mcCollision = cand2Prong.collision_as().mcCollision_as(); - if (eventGeneratorType >= 0 && mcCollision.getSubGeneratorId() != eventGeneratorType) { - continue; - } - } + void processCollWithCentFTOC(CollisionsWithMCLabelsAndCentFT0C::iterator const& collision, + aod::McCollisions const& mcCollisions, + aod::BCsWithTimestamps const& bcs) + { + checkCollisions(collision, mcCollisions, bcs); + } // end process + PROCESS_SWITCH(HfTaskMcValidationRec, processCollWithCentFTOC, "Process collision information with centrality selection with FT0C", false); - // determine which kind of candidate it is - bool isD0Sel = TESTBIT(cand2Prong.hfflag(), o2::aod::hf_cand_2prong::DecayType::D0ToPiK); - if (!isD0Sel) { - continue; - } - int whichHad = -1; - if (isD0Sel && TESTBIT(std::abs(cand2Prong.flagMcMatchRec()), hf_cand_2prong::DecayType::D0ToPiK)) { - whichHad = DzeroToKPi; + void processCollWithCentFTOM(CollisionsWithMCLabelsAndCentFT0M::iterator const& collision, + aod::McCollisions const& mcCollisions, + aod::BCsWithTimestamps const& bcs) + { + checkCollisions(collision, mcCollisions, bcs); + } // end process + PROCESS_SWITCH(HfTaskMcValidationRec, processCollWithCentFTOM, "Process collision information with centrality selection with FT0M", false); + + void processCollAssoc(CollisionsWithMCLabels const& collisions, + TracksWithSel const& tracks, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcCollisions, + aod::BCsWithTimestamps const& bcs) + { + checkCollisionAssociation(collisions, tracks, mcParticles, mcCollisions, bcs); + } + PROCESS_SWITCH(HfTaskMcValidationRec, processCollAssoc, "Process collision-association information, requires extra table from TrackToCollisionAssociation task (fillTableOfCollIdsPerTrack=true)", false); + + void processCollAssocWithCentFTOC(CollisionsWithMCLabelsAndCentFT0C const& collisions, + TracksWithSel const& tracks, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcCollisions, + aod::BCsWithTimestamps const& bcs) + { + checkCollisionAssociation(collisions, tracks, mcParticles, mcCollisions, bcs); + } + PROCESS_SWITCH(HfTaskMcValidationRec, processCollAssocWithCentFTOC, "Process collision-association information with centrality selection with FT0C, requires extra table from TrackToCollisionAssociation task (fillTableOfCollIdsPerTrack=true)", false); + + void processCollAssocWithCentFTOM(CollisionsWithMCLabelsAndCentFT0M const& collisions, + TracksWithSel const& tracks, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcCollisions, + aod::BCsWithTimestamps const& bcs) + { + checkCollisionAssociation(collisions, tracks, mcParticles, mcCollisions, bcs); + } + PROCESS_SWITCH(HfTaskMcValidationRec, processCollAssocWithCentFTOM, "Process collision-association information with centrality selection with FT0M, requires extra table from TrackToCollisionAssociation task (fillTableOfCollIdsPerTrack=true)", false); + + template + void processEff(HfCand2ProngWithMCRec const& cand2Prongs, + HfCand3ProngWithMCRec const& cand3Prongs, + aod::TracksWMc const&, + aod::McParticles const& mcParticles, + aod::McCollisions const&, + aod::BCsWithTimestamps const&, + Coll const& collisions, + Preslice cand2ProngsPerCollision, + Preslice cand3ProngsPerCollision) + { + // loop over collisions + for (const auto& collision : collisions) { + // apply event selection + float centrality{105.f}; + int occupancy = collision.trackOccupancyInTimeRange(); + hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); // only needed to update centrality, no bitmask selection applied + if (!collision.has_mcCollision()) { + return; } - int whichOrigin; - if (cand2Prong.originMcRec() == RecoDecay::OriginType::Prompt) { - whichOrigin = 0; - } else { - whichOrigin = 1; + auto mcCollision = collision.template mcCollision_as(); + if (eventGeneratorType >= 0 && mcCollision.getSubGeneratorId() != eventGeneratorType) { + return; } - if (whichHad >= 0) { - int indexParticle = -1; - if (cand2Prong.prong0_as().has_mcParticle()) { - indexParticle = RecoDecay::getMother(mcParticles, cand2Prong.prong0_as().mcParticle(), PDGArrayParticle[whichHad], true); - } - if (indexParticle < 0) { - continue; - } - auto mother = mcParticles.rawIteratorAt(indexParticle); - fillHisto(cand2Prong, mother, whichHad, whichOrigin); - } - } // end loop on 2-prong candidates + // group 2- and 3-prongs for collision + auto thisCollId = collision.globalIndex(); + auto grouped2ProngCandidates = cand2Prongs.sliceBy(cand2ProngsPerCollision, thisCollId); + auto grouped3ProngCandidates = cand3Prongs.sliceBy(cand3ProngsPerCollision, thisCollId); - // loop over 3-prong candidates - for (const auto& cand3Prong : cand3Prongs) { + // loop over 2-prong candidates + for (const auto& cand2Prong : grouped2ProngCandidates) { - if (cand3Prong.collision_as().has_mcCollision()) { - auto mcCollision = cand3Prong.collision_as().mcCollision_as(); - if (eventGeneratorType >= 0 && mcCollision.getSubGeneratorId() != eventGeneratorType) { + // determine which kind of candidate it is + bool isD0Sel = TESTBIT(cand2Prong.hfflag(), o2::aod::hf_cand_2prong::DecayType::D0ToPiK); + if (!isD0Sel) { continue; } - } - - // determine which kind of candidate it is - bool isDPlusSel = TESTBIT(cand3Prong.hfflag(), hf_cand_3prong::DecayType::DplusToPiKPi); - bool isDStarSel = false; // FIXME: add proper check when D* will be added in HF vertexing - bool isDsSel = TESTBIT(cand3Prong.hfflag(), hf_cand_3prong::DecayType::DsToKKPi); - bool isLcSel = TESTBIT(cand3Prong.hfflag(), hf_cand_3prong::DecayType::LcToPKPi); - bool isLcToPK0sSel = false; // FIXME: add in case of integration with cascades - bool isXicSel = TESTBIT(cand3Prong.hfflag(), hf_cand_3prong::DecayType::XicToPKPi); - if (!isDPlusSel && !isDStarSel && !isDsSel && !isLcSel && !isLcToPK0sSel && !isXicSel) { - continue; - } - int whichHad = -1; - if (isDPlusSel && TESTBIT(std::abs(cand3Prong.flagMcMatchRec()), hf_cand_3prong::DecayType::DplusToPiKPi)) { - whichHad = DplusToPiKPi; - } else if (isDsSel && TESTBIT(std::abs(cand3Prong.flagMcMatchRec()), hf_cand_3prong::DecayType::DsToKKPi)) { - if (TESTBIT(std::abs(cand3Prong.flagMcDecayChanRec()), hf_cand_3prong::DecayChannelDToKKPi::DsToPhiPi)) { - whichHad = DsToPhiPiToKKPi; + int whichHad = -1; + if (isD0Sel && TESTBIT(std::abs(cand2Prong.flagMcMatchRec()), hf_cand_2prong::DecayType::D0ToPiK)) { + whichHad = DzeroToKPi; } - if (TESTBIT(std::abs(cand3Prong.flagMcDecayChanRec()), hf_cand_3prong::DecayChannelDToKKPi::DplusToPhiPi)) { - whichHad = DplusToPhiPiToKKPi; + int whichOrigin; + if (cand2Prong.originMcRec() == RecoDecay::OriginType::Prompt) { + whichOrigin = 0; + } else { + whichOrigin = 1; } - } else if (isLcSel && TESTBIT(std::abs(cand3Prong.flagMcMatchRec()), hf_cand_3prong::DecayType::LcToPKPi)) { - whichHad = LcToPKPi; - } else if (isXicSel && TESTBIT(std::abs(cand3Prong.flagMcMatchRec()), hf_cand_3prong::DecayType::XicToPKPi)) { - whichHad = XicToPKPi; - } - int whichOrigin; - if (cand3Prong.originMcRec() == RecoDecay::OriginType::Prompt) { - whichOrigin = 0; - } else { - whichOrigin = 1; - } - if (whichHad >= 0) { - int indexParticle = -1; - if (cand3Prong.prong0_as().has_mcParticle()) { - indexParticle = RecoDecay::getMother(mcParticles, cand3Prong.prong0_as().mcParticle(), PDGArrayParticle[whichHad], true); + if (whichHad >= 0) { + int indexParticle = -1; + indexParticle = RecoDecay::getMother(mcParticles, cand2Prong.template prong0_as().template mcParticle_as(), PDGArrayParticle[whichHad], true); + if (indexParticle < 0) { + continue; + } + auto mother = mcParticles.rawIteratorAt(indexParticle); + fillHisto(cand2Prong, mother, whichHad, whichOrigin, centrality, occupancy); } - if (indexParticle < 0) { + } // end loop on 2-prong candidates + + // loop over 3-prong candidates + for (const auto& cand3Prong : grouped3ProngCandidates) { + + // determine which kind of candidate it is + // FIXME: add D* and decays with cascades + bool isDPlusSel = TESTBIT(cand3Prong.hfflag(), hf_cand_3prong::DecayType::DplusToPiKPi); + bool isDsSel = TESTBIT(cand3Prong.hfflag(), hf_cand_3prong::DecayType::DsToKKPi); + bool isLcSel = TESTBIT(cand3Prong.hfflag(), hf_cand_3prong::DecayType::LcToPKPi); + bool isXicSel = TESTBIT(cand3Prong.hfflag(), hf_cand_3prong::DecayType::XicToPKPi); + if (!isDPlusSel && !isDsSel && !isLcSel && !isXicSel) { continue; } - auto mother = mcParticles.rawIteratorAt(indexParticle); - fillHisto(cand3Prong, mother, whichHad, whichOrigin); - std::array momDau2 = {cand3Prong.pxProng2(), - cand3Prong.pyProng2(), - cand3Prong.pzProng2()}; - histPtDau[whichHad][whichOrigin][2]->Fill(RecoDecay::pt(momDau2)); - histEtaDau[whichHad][whichOrigin][2]->Fill(RecoDecay::eta(momDau2)); - histImpactParameterDau[whichHad][whichOrigin][2]->Fill(cand3Prong.impactParameter2()); - } - } // end loop on 3-prong candidates - } // end process + int whichHad = -1; + if (isDPlusSel && TESTBIT(std::abs(cand3Prong.flagMcMatchRec()), hf_cand_3prong::DecayType::DplusToPiKPi)) { + whichHad = DplusToPiKPi; + } else if (isDsSel && TESTBIT(std::abs(cand3Prong.flagMcMatchRec()), hf_cand_3prong::DecayType::DsToKKPi)) { + if (cand3Prong.flagMcDecayChanRec() == hf_cand_3prong::DecayChannelDToKKPi::DsToPhiPi) { + whichHad = DsToPhiPiToKKPi; + } + if (cand3Prong.flagMcDecayChanRec() == hf_cand_3prong::DecayChannelDToKKPi::DsToK0starK) { + whichHad = DsToK0starKToKKPi; + } + if (cand3Prong.flagMcDecayChanRec() == hf_cand_3prong::DecayChannelDToKKPi::DplusToPhiPi) { + whichHad = DplusToPhiPiToKKPi; + } + } else if (isLcSel && TESTBIT(std::abs(cand3Prong.flagMcMatchRec()), hf_cand_3prong::DecayType::LcToPKPi)) { + whichHad = LcToPKPi; + } else if (isXicSel && TESTBIT(std::abs(cand3Prong.flagMcMatchRec()), hf_cand_3prong::DecayType::XicToPKPi)) { + whichHad = XiCplusToPKPi; + } + int whichOrigin; + if (cand3Prong.originMcRec() == RecoDecay::OriginType::Prompt) { + whichOrigin = 0; + } else { + whichOrigin = 1; + } + + if (whichHad >= 0) { + int indexParticle = -1; + if (cand3Prong.template prong0_as().has_mcParticle()) { + indexParticle = RecoDecay::getMother(mcParticles, cand3Prong.template prong0_as().template mcParticle_as(), PDGArrayParticle[whichHad], true); + } + if (indexParticle < 0) { + continue; + } + auto mother = mcParticles.rawIteratorAt(indexParticle); + fillHisto(cand3Prong, mother, whichHad, whichOrigin, centrality, occupancy); + std::array momDau2 = {cand3Prong.pxProng2(), + cand3Prong.pyProng2(), + cand3Prong.pzProng2()}; + histPtDau[whichHad][whichOrigin][2]->Fill(RecoDecay::pt(momDau2)); + histEtaDau[whichHad][whichOrigin][2]->Fill(RecoDecay::eta(momDau2)); + histImpactParameterDau[whichHad][whichOrigin][2]->Fill(cand3Prong.impactParameter2()); + } + } // end loop on 3-prong candidates + } // end loop on collisions + } + void processEffNoCent(HfCand2ProngWithMCRec const& cand2Prongs, + HfCand3ProngWithMCRec const& cand3Prongs, + aod::TracksWMc const& mcTracks, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcCollisions, + aod::BCsWithTimestamps const& bcs, + CollisionsWithMCLabels const& collsWithLabels) + { + processEff(cand2Prongs, cand3Prongs, mcTracks, mcParticles, mcCollisions, bcs, collsWithLabels, cand2ProngPerCollision, cand3ProngPerCollision); + } + PROCESS_SWITCH(HfTaskMcValidationRec, processEffNoCent, "Compute charm-hadron efficiencies (not all of them are implemented), requires HF candidate creators w/o information on centrality", false); + + void processEffCentFT0C(HfCand2ProngWithMCRec const& cand2Prongs, + HfCand3ProngWithMCRec const& cand3Prongs, + aod::TracksWMc const& mcTracks, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcCollisions, + aod::BCsWithTimestamps const& bcs, + CollisionsWithMCLabelsAndCentFT0C const& collsWithLabels) + { + processEff(cand2Prongs, cand3Prongs, mcTracks, mcParticles, mcCollisions, bcs, collsWithLabels, cand2ProngPerCollision, cand3ProngPerCollision); + } + PROCESS_SWITCH(HfTaskMcValidationRec, processEffCentFT0C, "Compute charm-hadron efficiencies (not all of them are implemented), requires HF candidate creators with information on centrality from FT0C", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/Tasks/taskMultiplicityEstimatorCorrelation.cxx b/PWGHF/Tasks/taskMultiplicityEstimatorCorrelation.cxx new file mode 100644 index 00000000000..a7e0515eb2f --- /dev/null +++ b/PWGHF/Tasks/taskMultiplicityEstimatorCorrelation.cxx @@ -0,0 +1,137 @@ +// 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 taskMultiplicityEstimatorCorrelation.cxx +/// \brief Task for correlating the multiplicity estimator with generated dN/deta +/// +/// \author Fabrizio Chinu , Università and INFN Torino + +#include +#include +#include + +#include "TPDGCode.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "Framework/StaticFor.h" +#include "Common/DataModel/Multiplicity.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct HfTaskMultiplicityEstimatorCorrelation { + HistogramRegistry registry{"registry", {}}; + static constexpr int8_t nEstimators = 8; + static constexpr std::array estimatorsNames = {"FV0A", "FT0A", "FT0C", "FT0M", "FDDA", "FDDC", "FDDM", "NTPV"}; + + std::vector consideredParticles = { + kElectron, + kMuonMinus, + kPiPlus, + kKPlus, + kProton}; + + ConfigurableAxis axisFV0A = {"axisFV0A", {100, 0., 20000.}, "axis for FV0A estimator"}; + ConfigurableAxis axisFT0A = {"axisFT0A", {100, 0., 10000.}, "axis for FT0A estimator"}; + ConfigurableAxis axisFT0C = {"axisFT0C", {100, 0., 5000.}, "axis for FT0C estimator"}; + ConfigurableAxis axisFT0M = {"axisFT0M", {100, 0., 10000.}, "axis for FT0M estimator"}; + ConfigurableAxis axisFDDA = {"axisFDDA", {100, 0., 20000.}, "axis for FDDA estimator"}; + ConfigurableAxis axisFDDC = {"axisFDDC", {100, 0., 5000.}, "axis for FDDC estimator"}; + ConfigurableAxis axisFDDM = {"axisFDDM", {100, 0., 20000.}, "axis for FDDM estimator"}; + ConfigurableAxis axisNTPV = {"axisNTPV", {100, 0., 100.}, "axis for NTPV estimator"}; + ConfigurableAxis axisdNdEta = {"axisdNdEta", {100, 0., 100.}, "axis for dN/deta"}; + + std::vector estimatorsAxes = {&axisFV0A, &axisFT0A, &axisFT0C, &axisFT0M, &axisFDDA, &axisFDDC, &axisFDDM, &axisNTPV}; + + Preslice particlesPerCollision = o2::aod::mcparticle::mcCollisionId; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + + using CollisionsWithMult = soa::Join; + + void init(InitContext&) + { + for (int8_t i = 0; i < nEstimators; i++) { + registry.add(("etaPFive/" + std::string(estimatorsNames[i]) + "VsdNdeta").c_str(), (std::string(estimatorsNames[i]) + "VsdNdeta;" + std::string(estimatorsNames[i]) + ";").c_str(), HistType::kTH2F, {*(estimatorsAxes[i]), axisdNdEta}); + registry.add(("etaOne/" + std::string(estimatorsNames[i]) + "VsdNdeta").c_str(), (std::string(estimatorsNames[i]) + "VsdNdeta;" + std::string(estimatorsNames[i]) + ";").c_str(), HistType::kTH2F, {*(estimatorsAxes[i]), axisdNdEta}); + } + } + + void process(CollisionsWithMult const& collisions, + aod::McCollisions const& mcCollisions, + aod::McParticles const& particles, + soa::Join const&) + { + for (auto const& collision : mcCollisions) { + + // Get multiplicity for the reconstructed collision with the highest number of contributors + unsigned maxNumContrib = 0; + CollisionsWithMult::iterator collisionMaxNumContrib; + const auto& recoCollsPerMcColl = collisions.sliceBy(colPerMcCollision, collision.globalIndex()); + for (const auto& recCol : recoCollsPerMcColl) { + if (recCol.numContrib() > maxNumContrib) { + maxNumContrib = recCol.numContrib(); + collisionMaxNumContrib = recCol; + } + } + std::vector multiplicity = { + collisionMaxNumContrib.multZeqFV0A(), + collisionMaxNumContrib.multZeqFT0A(), + collisionMaxNumContrib.multZeqFT0C(), + collisionMaxNumContrib.multZeqFT0A() + collisionMaxNumContrib.multZeqFT0C(), + collisionMaxNumContrib.multZeqFDDA(), + collisionMaxNumContrib.multZeqFDDC(), + collisionMaxNumContrib.multZeqFDDA() + collisionMaxNumContrib.multZeqFDDC(), + collisionMaxNumContrib.multZeqNTracksPV()}; + + // Get the dN/deta for the generated collision + unsigned nChargedInEtaFive = 0; + unsigned nChargedInEtaOne = 0; + const auto& particlesPerMcColl = particles.sliceBy(particlesPerCollision, collision.globalIndex()); + for (auto const& particle : particlesPerMcColl) { + if (particle.isPhysicalPrimary()) { + bool isCharged = false; + for (auto const& consideredParticle : consideredParticles) { + if (static_cast(std::abs(particle.pdgCode())) == consideredParticle) { + isCharged = true; + break; + } + } + if (!isCharged) { + continue; + } + if (std::abs(particle.eta()) < 0.5) { + nChargedInEtaFive++; + } + if (std::abs(particle.eta()) < 1.0) { + nChargedInEtaOne++; + } + } + } + + float dNdetaFive = nChargedInEtaFive; + float dNdetaOne = nChargedInEtaOne / 2.0; + for (int i = 0; i < nEstimators; i++) { + static_for<0, nEstimators - 1>([&](auto j) { + constexpr int index = j.value; + registry.fill(HIST("etaPFive/") + HIST(estimatorsNames[index]) + HIST("VsdNdeta"), multiplicity[index], dNdetaFive); + registry.fill(HIST("etaOne/") + HIST(estimatorsNames[index]) + HIST("VsdNdeta"), multiplicity[index], dNdetaOne); + }); + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/Tasks/taskPidStudies.cxx b/PWGHF/Tasks/taskPidStudies.cxx new file mode 100644 index 00000000000..55e3bef23ac --- /dev/null +++ b/PWGHF/Tasks/taskPidStudies.cxx @@ -0,0 +1,523 @@ +// 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 taskPidStudies.cxx +/// \brief task for studies of PID performance +/// +/// \author Fabrizio Chinu , Università and INFN Torino +/// \author Stefano Politanò , INFN Torino +/// \author Marcello Di Costanzo , Politecnico and INFN Torino +/// \author Luca Aglietta , Università and INFN Torino + +#include + +#include "TPDGCode.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Core/CentralityEstimation.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::hf_evsel; +using namespace o2::hf_centrality; + +namespace o2::aod +{ +namespace pid_studies +{ +enum Particle { NotMatched = 0, + K0s, + Lambda, + Omega }; +// V0s +DECLARE_SOA_COLUMN(MassK0, massK0, float); //! Candidate mass +DECLARE_SOA_COLUMN(MassLambda, massLambda, float); //! Candidate mass +DECLARE_SOA_COLUMN(MassAntiLambda, massAntiLambda, float); //! Candidate mass +DECLARE_SOA_COLUMN(Pt, pt, float); //! Transverse momentum of the candidate (GeV/c) +DECLARE_SOA_COLUMN(PtPos, ptPos, float); //! Transverse momentum of positive track (GeV/c) +DECLARE_SOA_COLUMN(PtNeg, ptNeg, float); //! Transverse momentum of negative track (GeV/c) +DECLARE_SOA_COLUMN(PtPosTpc, ptPosTpc, float); //! Transverse Momentum of positive track at inner wall of TPC (GeV/c) +DECLARE_SOA_COLUMN(PtNegTpc, ptNegTpc, float); //! Transverse Momentum of negative track at inner wall of TPC (GeV/c) +DECLARE_SOA_COLUMN(Radius, radius, float); //! Radius +DECLARE_SOA_COLUMN(Cpa, cpa, float); //! Cosine of pointing angle +DECLARE_SOA_COLUMN(DcaV0Daughters, dcaV0Daughters, float); //! DCA between V0 daughters +DECLARE_SOA_COLUMN(DcaV0ToPv, dcaV0ToPv, float); //! DCA V0 to PV +DECLARE_SOA_COLUMN(NSigmaTpcPosPi, nSigmaTpcPosPi, float); //! nSigmaTPC of positive track with pion hypothesis +DECLARE_SOA_COLUMN(NSigmaTpcNegPi, nSigmaTpcNegPi, float); //! nSigmaTPC of negative track with pion hypothesis +DECLARE_SOA_COLUMN(NSigmaTpcPosPr, nSigmaTpcPosPr, float); //! nSigmaTPC of positive track with proton hypothesis +DECLARE_SOA_COLUMN(NSigmaTpcNegPr, nSigmaTpcNegPr, float); //! nSigmaTPC of negative track with proton hypothesis +DECLARE_SOA_COLUMN(NSigmaTofPosPi, nSigmaTofPosPi, float); //! nSigmaTOF of positive track with pion hypothesis +DECLARE_SOA_COLUMN(NSigmaTofNegPi, nSigmaTofNegPi, float); //! nSigmaTOF of negative track with pion hypothesis +DECLARE_SOA_COLUMN(NSigmaTofPosPr, nSigmaTofPosPr, float); //! nSigmaTOF of positive track with proton hypothesis +DECLARE_SOA_COLUMN(NSigmaTofNegPr, nSigmaTofNegPr, float); //! nSigmaTOF of negative track with proton hypothesis +DECLARE_SOA_COLUMN(AlphaArm, alphaArm, float); //! Armenteros alpha +DECLARE_SOA_COLUMN(QtArm, qtArm, float); //! Armenteros Qt + +// Cascades +DECLARE_SOA_COLUMN(MassOmega, massOmega, float); //! Candidate mass +DECLARE_SOA_COLUMN(MassXi, massXi, float); //! Candidate mass +DECLARE_SOA_COLUMN(PtBach, ptBach, float); //! Transverse momentum of the bachelor (GeV/c) +DECLARE_SOA_COLUMN(PtBachTpc, ptBachTpc, float); //! Transverse momentum of the bachelor at inner wall of TPC (GeV/c) +DECLARE_SOA_COLUMN(MLambda, mLambda, float); //! Daughter lambda mass (GeV/c^2) +DECLARE_SOA_COLUMN(V0cosPA, v0cosPA, float); //! V0 CPA +DECLARE_SOA_COLUMN(CascCosPa, cascCosPa, float); //! Cascade CPA +DECLARE_SOA_COLUMN(NSigmaTpcBachKa, nSigmaTpcBachKa, float); //! nSigmaTPC of bachelor with kaon hypothesis +DECLARE_SOA_COLUMN(NSigmaTofBachKa, nSigmaTofBachKa, float); //! nSigmaTOF of bachelor with kaon hypothesis + +// Common columns +DECLARE_SOA_COLUMN(OccupancyFt0c, occupancyFt0c, float); //! Occupancy from FT0C +DECLARE_SOA_COLUMN(OccupancyIts, occupancyIts, float); //! Occupancy from ITS +DECLARE_SOA_COLUMN(CentralityFT0C, centralityFT0C, float); //! Centrality from FT0C +DECLARE_SOA_COLUMN(CentralityFT0M, centralityFT0M, float); //! Centrality from FT0M +DECLARE_SOA_COLUMN(CandFlag, candFlag, int); //! Flag for MC matching + +const int minTpcNClsCrossedRows = 70; // Minimum number of crossed rows in TPC +const float maxEta = 0.8; // Maximum pseudorapidity +const float minPt = 0.1; // Minimum transverse momentum +const float maxTpcChi2NCl = 4; // Maximum TPC chi2 per number of TPC clusters +const float maxItsChi2NCl = 36; // Maximum ITS chi2 per number of ITS clusters +} // namespace pid_studies + +DECLARE_SOA_TABLE(PidV0s, "AOD", "PIDV0S", //! Table with PID information + pid_studies::MassK0, + pid_studies::MassLambda, + pid_studies::MassAntiLambda, + pid_studies::Pt, + pid_studies::PtPos, + pid_studies::PtNeg, + pid_studies::PtPosTpc, + pid_studies::PtNegTpc, + pid_studies::Radius, + pid_studies::Cpa, + pid_studies::DcaV0Daughters, + pid_studies::DcaV0ToPv, + pid_studies::NSigmaTpcPosPi, + pid_studies::NSigmaTpcNegPi, + pid_studies::NSigmaTpcPosPr, + pid_studies::NSigmaTpcNegPr, + pid_studies::NSigmaTofPosPi, + pid_studies::NSigmaTofNegPi, + pid_studies::NSigmaTofPosPr, + pid_studies::NSigmaTofNegPr, + pid_studies::AlphaArm, + pid_studies::QtArm, + pid_studies::OccupancyFt0c, + pid_studies::OccupancyIts, + pid_studies::CentralityFT0C, + pid_studies::CentralityFT0M, + pid_studies::CandFlag); + +DECLARE_SOA_TABLE(PidCascades, "AOD", "PIDCASCADES", //! Table with PID information + pid_studies::MassOmega, + pid_studies::Pt, + pid_studies::PtBach, + pid_studies::PtBachTpc, + pid_studies::Radius, + pid_studies::MLambda, + pid_studies::V0cosPA, + pid_studies::MassXi, + pid_studies::CascCosPa, + pid_studies::DcaV0Daughters, + pid_studies::DcaV0ToPv, + pid_studies::NSigmaTpcBachKa, + pid_studies::NSigmaTofBachKa, + pid_studies::OccupancyFt0c, + pid_studies::OccupancyIts, + pid_studies::CentralityFT0C, + pid_studies::CentralityFT0M, + pid_studies::CandFlag); +} // namespace o2::aod + +struct HfTaskPidStudies { + Produces pidV0; + Produces pidCascade; + + Configurable applyEvSels{"applyEvSels", true, "Apply event selections"}; + Configurable applyTrackSels{"applyTrackSels", true, "Apply track selections"}; + Configurable massK0Min{"massK0Min", 0.4, "Minimum mass for K0"}; + Configurable massK0Max{"massK0Max", 0.6, "Maximum mass for K0"}; + Configurable massLambdaMin{"massLambdaMin", 1.0, "Minimum mass for lambda"}; + Configurable massLambdaMax{"massLambdaMax", 1.3, "Maximum mass for lambda"}; + Configurable massOmegaMin{"massOmegaMin", 1.5, "Minimum mass for omega"}; + Configurable massOmegaMax{"massOmegaMax", 1.8, "Maximum mass for omega"}; + Configurable radiusMax{"radiusMax", 2.3, "Maximum decay radius (cm)"}; + Configurable cosPaMin{"cosPaMin", 0.98, "Minimum cosine of pointing angle"}; + Configurable dcaV0DaughtersMax{"dcaV0DaughtersMax", 0.2, "Maximum DCA among the V0 daughters (cm)"}; + Configurable dcaV0ToPvMax{"dcaV0ToPvMax", 0.2, "Maximum DCA of the V0 from the primary vertex (cm)"}; + Configurable cosPaV0Min{"cosPaV0Min", 0.95, "Minimum cosine of pointing angle for V0 stemming from cascade decays"}; + Configurable qtArmenterosMinForK0{"qtArmenterosMinForK0", 0.12, "Minimum Armenteros' qt for K0"}; + Configurable qtArmenterosMaxForLambda{"qtArmenterosMaxForLambda", 0.12, "Minimum Armenteros' qt for (anti)Lambda"}; + Configurable downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of candidates to keep"}; + Configurable ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + using PidTracks = soa::Join; + using CollSels = soa::Join; + using CollisionsMc = soa::Join; + using V0sMcRec = soa::Join; + using CascsMcRec = soa::Join; + + HfEventSelection hfEvSel; + HfEventSelectionMc hfEvSelMc; + + o2::framework::Service ccdb; + HistogramRegistry registry{"registry", {}}; + + void init(InitContext&) + { + if ((doprocessV0Mc && doprocessV0Data) || (doprocessCascMc && doprocessCascData)) { + LOGP(fatal, "Both data and MC process functions were enabled! Please check your configuration!"); + } + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + hfEvSel.addHistograms(registry); + } + + template + void fillTree(Cand const& candidate, const int flag) + { + float pseudoRndm = candidate.pt() * 1000. - static_cast(candidate.pt() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm > downSampleBkgFactor) { + return; + } + + const auto& coll = candidate.template collision_as(); + if constexpr (isV0) { + const auto& posTrack = candidate.template posTrack_as(); + const auto& negTrack = candidate.template negTrack_as(); + pidV0( + candidate.mK0Short(), + candidate.mLambda(), + candidate.mAntiLambda(), + candidate.pt(), + posTrack.pt(), + negTrack.pt(), + posTrack.tpcInnerParam() / std::cosh(candidate.positiveeta()), + negTrack.tpcInnerParam() / std::cosh(candidate.negativeeta()), + candidate.v0radius(), + candidate.v0cosPA(), + candidate.dcaV0daughters(), + candidate.dcav0topv(), + posTrack.tpcNSigmaPi(), + negTrack.tpcNSigmaPi(), + posTrack.tpcNSigmaPr(), + negTrack.tpcNSigmaPr(), + posTrack.tofNSigmaPi(), + negTrack.tofNSigmaPi(), + posTrack.tofNSigmaPr(), + negTrack.tofNSigmaPr(), + candidate.alpha(), + candidate.qtarm(), + coll.ft0cOccupancyInTimeRange(), + coll.trackOccupancyInTimeRange(), + coll.centFT0C(), + coll.centFT0M(), + flag); + } else { + const auto& bachTrack = candidate.template bachelor_as(); + pidCascade( + candidate.mOmega(), + candidate.pt(), + candidate.bachelorpt(), + bachTrack.tpcInnerParam() / std::cosh(candidate.bacheloreta()), + candidate.cascradius(), + candidate.mLambda(), + candidate.v0cosPA(coll.posX(), coll.posY(), coll.posZ()), + candidate.mXi(), + candidate.casccosPA(coll.posX(), coll.posY(), coll.posZ()), + candidate.dcaV0daughters(), + candidate.dcav0topv(coll.posX(), coll.posY(), coll.posZ()), + bachTrack.tpcNSigmaKa(), + bachTrack.tofNSigmaKa(), + coll.ft0cOccupancyInTimeRange(), + coll.trackOccupancyInTimeRange(), + coll.centFT0C(), + coll.centFT0M(), + flag); + } + } + + template + int isMatched(const T1& cand) + { + if constexpr (std::is_same::value) { + if (!cand.has_v0MCCore()) { + return aod::pid_studies::Particle::NotMatched; + } + auto v0MC = cand.template v0MCCore_as(); + if (v0MC.pdgCode() == kK0Short && v0MC.pdgCodeNegative() == -kPiPlus && v0MC.pdgCodePositive() == kPiPlus) { + return aod::pid_studies::Particle::K0s; + } + if (v0MC.pdgCode() == kLambda0 && v0MC.pdgCodeNegative() == -kPiPlus && v0MC.pdgCodePositive() == kProton) { + return aod::pid_studies::Particle::Lambda; + } + if (v0MC.pdgCode() == -kLambda0 && v0MC.pdgCodeNegative() == -kProton && v0MC.pdgCodePositive() == kPiPlus) { + return -aod::pid_studies::Particle::Lambda; + } + } + if constexpr (std::is_same::value) { + if (!cand.has_cascMCCore()) { + return aod::pid_studies::Particle::NotMatched; + } + auto cascMC = cand.template cascMCCore_as(); + if (cascMC.pdgCode() == kOmegaMinus && + cascMC.pdgCodeBachelor() == -kKPlus && + cascMC.pdgCodeV0() == kLambda0 && + cascMC.pdgCodePositive() == kProton && + cascMC.pdgCodeNegative() == -kPiPlus) { + return aod::pid_studies::Particle::Omega; + } + if (cascMC.pdgCode() == -kOmegaMinus && + cascMC.pdgCodeBachelor() == kKPlus && + cascMC.pdgCodeV0() == -kLambda0 && + cascMC.pdgCodePositive() == kPiPlus && + cascMC.pdgCodeNegative() == -kProton) { + return -aod::pid_studies::Particle::Omega; + } + } + return aod::pid_studies::Particle::NotMatched; + } + + template + bool isCollSelected(const Coll& coll) + { + float cent{-1.f}; + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(coll, cent, ccdb, registry); + /// monitor the satisfied event selections + hfEvSel.fillHistograms(coll, rejectionMask, cent); + return rejectionMask == 0; + } + + template + bool isTrackSelected(const T1& candidate) + { + const auto& posTrack = candidate.template posTrack_as(); + const auto& negTrack = candidate.template negTrack_as(); + if (posTrack.tpcNClsCrossedRows() < o2::aod::pid_studies::minTpcNClsCrossedRows || negTrack.tpcNClsCrossedRows() < o2::aod::pid_studies::minTpcNClsCrossedRows) { + return false; + } + if (std::abs(posTrack.eta()) > o2::aod::pid_studies::maxEta || std::abs(negTrack.eta()) > o2::aod::pid_studies::maxEta) { + return false; + } + if (posTrack.pt() < o2::aod::pid_studies::minPt || negTrack.pt() < o2::aod::pid_studies::minPt) { + return false; + } + if (posTrack.tpcChi2NCl() > o2::aod::pid_studies::maxTpcChi2NCl || negTrack.tpcChi2NCl() > o2::aod::pid_studies::maxTpcChi2NCl) { + return false; + } + if (posTrack.itsChi2NCl() > o2::aod::pid_studies::maxItsChi2NCl || negTrack.itsChi2NCl() > o2::aod::pid_studies::maxItsChi2NCl) { + return false; + } + if constexpr (!isV0) { + const auto& bachTrack = candidate.template bachelor_as(); + if (bachTrack.tpcNClsCrossedRows() < o2::aod::pid_studies::minTpcNClsCrossedRows) { + return false; + } + if (std::abs(bachTrack.eta()) > o2::aod::pid_studies::maxEta) { + return false; + } + if (bachTrack.pt() < o2::aod::pid_studies::minPt) { + return false; + } + if (bachTrack.tpcChi2NCl() > o2::aod::pid_studies::maxTpcChi2NCl) { + return false; + } + if (bachTrack.itsChi2NCl() > o2::aod::pid_studies::maxItsChi2NCl) { + return false; + } + } + return true; + } + + template + bool isSelectedV0AsK0s(const V0Cand& v0) + { + if (v0.mK0Short() < massK0Min || v0.mK0Short() > massK0Max) { + return false; + } + if (v0.qtarm() < qtArmenterosMinForK0) { + return false; + } + if (v0.v0radius() > radiusMax) { + return false; + } + if (v0.v0cosPA() < cosPaMin) { + return false; + } + if (v0.dcaV0daughters() > dcaV0DaughtersMax) { + return false; + } + if (v0.dcav0topv() > dcaV0ToPvMax) { + return false; + } + return true; + } + + template + bool isSelectedV0AsLambda(const V0Cand& v0) + { + if ((v0.mLambda() < massLambdaMin || v0.mLambda() > massLambdaMax) && + (v0.mAntiLambda() < massLambdaMin || v0.mAntiLambda() > massLambdaMax)) { + return false; + } + if (v0.qtarm() > qtArmenterosMaxForLambda) { + return false; + } + if (v0.v0radius() > radiusMax) { + return false; + } + if (v0.v0cosPA() < cosPaMin) { + return false; + } + if (v0.dcaV0daughters() > dcaV0DaughtersMax) { + return false; + } + if (v0.dcav0topv() > dcaV0ToPvMax) { + return false; + } + return true; + } + + template + bool isSelectedCascAsOmega(const CascCand& casc) + { + if (casc.mOmega() < massOmegaMin || casc.mOmega() > massOmegaMax) { + return false; + } + if (casc.mLambda() < massLambdaMin || casc.mLambda() > massLambdaMax) { + return false; + } + if (casc.cascradius() > radiusMax) { + return false; + } + const auto& coll = casc.template collision_as(); + if (casc.casccosPA(coll.posX(), coll.posY(), coll.posZ()) < cosPaMin) { + return false; + } + if (casc.dcaV0daughters() > dcaV0DaughtersMax) { + return false; + } + if (casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ()) > dcaV0ToPvMax) { + return false; + } + if (casc.v0cosPA(coll.posX(), coll.posY(), coll.posZ()) < cosPaV0Min) { + return false; + } + return true; + } + + void processV0Mc(CollisionsMc const& /*mcCollisions*/, + V0sMcRec const& V0s, + aod::V0MCCores const&, + aod::McParticles const& /*particlesMc*/, + PidTracks const& /*tracks*/, + aod::BCsWithTimestamps const&) + { + for (const auto& v0 : V0s) { + if (applyEvSels && !isCollSelected(v0.collision_as())) { + return; + } + if (applyTrackSels && !isTrackSelected(v0)) { + return; + } + if (isSelectedV0AsK0s(v0) || isSelectedV0AsLambda(v0)) { + int matched = isMatched(v0); + if (matched != aod::pid_studies::Particle::NotMatched) { + fillTree(v0, matched); + } + } + } + } + PROCESS_SWITCH(HfTaskPidStudies, processV0Mc, "Process MC", true); + + void processV0Data(aod::V0Datas const& V0s, + PidTracks const&, + aod::BCsWithTimestamps const&, + CollSels const&) + { + for (const auto& v0 : V0s) { + if (applyEvSels && !isCollSelected(v0.collision_as())) { + return; + } + if (applyTrackSels && !isTrackSelected(v0)) { + return; + } + if (isSelectedV0AsK0s(v0) || isSelectedV0AsLambda(v0)) { + fillTree(v0, aod::pid_studies::Particle::NotMatched); + } + } + } + PROCESS_SWITCH(HfTaskPidStudies, processV0Data, "Process data", false); + + void processCascMc(CollisionsMc const& /*mcCollisions*/, + CascsMcRec const& cascades, + aod::CascMCCores const&, + aod::McParticles const& /*particlesMc*/, + PidTracks const&, + aod::BCsWithTimestamps const&) + { + for (const auto& casc : cascades) { + if (applyEvSels && !isCollSelected(casc.collision_as())) { + return; + } + if (applyTrackSels && !isTrackSelected(casc)) { + return; + } + if (isSelectedCascAsOmega(casc)) { + int matched = isMatched(casc); + if (matched != aod::pid_studies::Particle::NotMatched) { + fillTree(casc, matched); + } + } + } + } + PROCESS_SWITCH(HfTaskPidStudies, processCascMc, "Process MC", true); + + void processCascData(aod::CascDatas const& cascades, + PidTracks const&, + aod::BCsWithTimestamps const&, + CollSels const&) + { + for (const auto& casc : cascades) { + if (applyEvSels && !isCollSelected(casc.collision_as())) { + return; + } + if (applyTrackSels && !isTrackSelected(casc)) { + return; + } + if (isSelectedCascAsOmega(casc)) { + fillTree(casc, aod::pid_studies::Particle::NotMatched); + } + } + } + PROCESS_SWITCH(HfTaskPidStudies, processCascData, "Process data", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/Tasks/taskSelOptimisation.cxx b/PWGHF/Tasks/taskSelOptimisation.cxx index 128ef6ac0c8..8b701ea5a4c 100644 --- a/PWGHF/Tasks/taskSelOptimisation.cxx +++ b/PWGHF/Tasks/taskSelOptimisation.cxx @@ -14,6 +14,9 @@ /// /// \author Fabrizio Grosa , CERN +#include +#include + #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" diff --git a/PWGHF/Utils/utilsAnalysis.h b/PWGHF/Utils/utilsAnalysis.h index 3296113e806..ec59ec55bf0 100644 --- a/PWGHF/Utils/utilsAnalysis.h +++ b/PWGHF/Utils/utilsAnalysis.h @@ -11,20 +11,51 @@ /// \file utilsAnalysis.h /// \brief Utilities for HF analyses +/// +/// \author Vít Kučera , Inha University #ifndef PWGHF_UTILS_UTILSANALYSIS_H_ #define PWGHF_UTILS_UTILSANALYSIS_H_ #include // std::upper_bound #include // std::distance +#include //std::string + +#include "CommonConstants/PhysicsConstants.h" namespace o2::analysis { +enum BHadMothers { NotMatched = 0, + BPlus, + BZero, + Bs, + LambdaBZero }; + +/// Convert the B hadron mother PDG for non prompt candidates to a flag +/// \param pdg of the b hadron mother +/// \return integer map to specific mothers' PDG codes +BHadMothers getBHadMotherFlag(const int flagBHad) +{ + if (std::abs(flagBHad) == o2::constants::physics::kBPlus) { + return BHadMothers::BPlus; + } + if (std::abs(flagBHad) == o2::constants::physics::kB0) { + return BHadMothers::BZero; + } + if (std::abs(flagBHad) == o2::constants::physics::kBS) { + return BHadMothers::Bs; + } + if (std::abs(flagBHad) == o2::constants::physics::kLambdaB0) { + return BHadMothers::LambdaBZero; + } + return BHadMothers::NotMatched; +} + /// Finds pT bin in an array. /// \param bins array of pT bins /// \param value pT /// \return index of the pT bin -/// \note Accounts for the offset so that pt bin array can be used to also configure a histogram axis. +/// \note Accounts for the offset so that pT bin array can be used to also configure a histogram axis. template int findBin(T1 const& binsPt, T2 value) { @@ -37,14 +68,15 @@ int findBin(T1 const& binsPt, T2 value) return std::distance(binsPt->begin(), std::upper_bound(binsPt->begin(), binsPt->end(), value)) - 1; } -/// Single-track cut on DCAxy +/// Single-track cut on DCAxy and DCAz /// \param binsPt pT bins /// \param cuts cut configuration /// \param pt is the prong pT /// \param dcaXY is the prong dcaXY +/// \param dcaZ is the prong dcaZ /// \return true if track passes all cuts template -bool isSelectedTrackDcaXY(T1 const& binsPt, T2 const& cuts, const float pt, const float dcaXY) +bool isSelectedTrackDca(T1 const& binsPt, T2 const& cuts, const float pt, const float dcaXY, const float dcaZ) { auto binPt = findBin(binsPt, pt); if (binPt == -1) { @@ -56,9 +88,99 @@ bool isSelectedTrackDcaXY(T1 const& binsPt, T2 const& cuts, const float pt, cons if (std::abs(dcaXY) > cuts->get(binPt, "max_dcaxytoprimary")) { return false; // maximum DCAxy } + if (std::abs(dcaZ) < cuts->get(binPt, "min_dcaztoprimary")) { + return false; // minimum DCAz + } + if (std::abs(dcaZ) > cuts->get(binPt, "max_dcaztoprimary")) { + return false; // maximum DCAz + } return true; } +/// Single-track cut on ITS track properties +/// \param track track that has to satisfy the selection criteria +/// \param itsNClustersFoundMin is the minimum number of ITS clusters +/// \param itsChi2PerClusterMax is the maximum value of chi2 fit over ITS clusters +/// \return true if track passes all cuts +template +bool isSelectedTrackItsQuality(T const& track, const int itsNClustersFoundMin, const float itsChi2PerClusterMax) +{ + if (track.itsNCls() < itsNClustersFoundMin) { + return false; + } + if (track.itsChi2NCl() > itsChi2PerClusterMax) { + return false; + } + return true; +} + +/// Single-track cut on TPC track properties +/// \param track track that has to satisfy the selection criteria +/// \param tpcNClustersFoundMin is the minimum number of TPC clusters +/// \param tpcNCrossedRowsMin is the minimum number of crossed TPC rows +/// \param tpcNCrossedRowsOverFindableClustersMin is the minimum of TPC CrossedRows/FindableClusters value +/// \param tpcChi2PerClusterMax is the maximum value of chi2 fit over TPC clusters +/// \return true if track passes all cuts +template +bool isSelectedTrackTpcQuality(T const& track, const int tpcNClustersFoundMin, const int tpcNCrossedRowsMin, const float tpcNCrossedRowsOverFindableClustersMin, const float tpcChi2PerClusterMax) +{ + if (track.tpcNClsFound() < tpcNClustersFoundMin) { + return false; + } + if (track.tpcNClsCrossedRows() < tpcNCrossedRowsMin) { + return false; + } + if (track.tpcCrossedRowsOverFindableCls() < tpcNCrossedRowsOverFindableClustersMin) { + return false; + } + if (track.tpcChi2NCl() > tpcChi2PerClusterMax) { + return false; + } + return true; +} + +/// Mass selection of 2 or 3 prong canidates in triggered data analysis +/// \tparam nProngs switch between 2-prong and 3-prong selection +/// \param invMass is the invariant mass of the candidate +/// \param pdgMass is the pdg Mass of the candidate particle +/// \param pt is the pT of the candidate +/// \param cutConfig is the struct with the pt-dependent mass configurations +/// \return true if candidate passes selection +template +bool isCandidateInMassRange(const float& invMass, const double& pdgMass, const float& pt, Config const& cutConfig) +{ + float peakMean = (pt < cutConfig.ptDeltaMassMax.value) ? ((pdgMass + cutConfig.deltaMassPars->get("constant")) + cutConfig.deltaMassPars->get("linear") * pt) : pdgMass; + float peakWidth = cutConfig.sigmaPars->get("constant") + cutConfig.sigmaPars->get("linear") * pt; + + return (!(std::abs(invMass - peakMean) > cutConfig.nSigmaMax.value * peakWidth && pt < cutConfig.ptMassCutMax.value)); +} + +/// Configurable group to apply trigger specific cuts for 2-prong HF analysis +struct HfTrigger2ProngCuts : o2::framework::ConfigurableGroup { + std::string prefix = "hfTrigger2ProngCuts"; // JSON group name + + static constexpr float DefaultDeltaMassPars[1][2] = {{-0.0025f, 0.0001f}}; + static constexpr float DefaultSigmaPars[1][2] = {{0.01424f, 0.00178f}}; + o2::framework::Configurable nSigmaMax{"nSigmaMax", 2, "Maximum number of sigmas for pT-differential mass cut for 2-prong candidates"}; + o2::framework::Configurable ptDeltaMassMax{"ptDeltaMassMax", 10., "Max pT to apply delta mass shift to PDG mass value for 2-prong candidates"}; + o2::framework::Configurable ptMassCutMax{"ptMassCutMax", 9999., "Max pT to apply pT-differential cut for 2-prong candidates"}; + o2::framework::Configurable> deltaMassPars{"deltaMassPars", {DefaultDeltaMassPars[0], 2, {"constant", "linear"}}, "delta mass parameters for HF 2-prong trigger mass cut"}; + o2::framework::Configurable> sigmaPars{"sigmaPars", {DefaultSigmaPars[0], 2, {"constant", "linear"}}, "sigma parameters for HF 2-prong trigger mass cut"}; +}; + +/// Configurable group to apply trigger specific cuts for 3-prong HF analysis +struct HfTrigger3ProngCuts : o2::framework::ConfigurableGroup { + std::string prefix = "hfTrigger3ProngCuts"; // JSON group name + + static constexpr float DefaultDeltaMassPars[1][2] = {{-0.0025f, 0.0001f}}; + static constexpr float DefaultSigmaPars[1][2] = {{0.00796f, 0.00176f}}; + o2::framework::Configurable nSigmaMax{"nSigmaMax", 2, "Maximum number of sigmas for pT-differential mass cut for 3-prong candidates"}; + o2::framework::Configurable ptDeltaMassMax{"ptDeltaMassMax", 10., "Max pT to apply delta mass shift to PDG mass value for 3-prong candidates"}; + o2::framework::Configurable ptMassCutMax{"ptMassCutMax", 9999., "Max pT to apply pT-differential cut for 3-prong candidates"}; + o2::framework::Configurable> deltaMassPars{"deltaMassPars", {DefaultDeltaMassPars[0], 2, {"constant", "linear"}}, "delta mass parameters for HF 3-prong trigger mass cut"}; + o2::framework::Configurable> sigmaPars{"sigmaPars", {DefaultSigmaPars[0], 2, {"constant", "linear"}}, "sigma parameters for HF 3-prong trigger mass cut"}; +}; + } // namespace o2::analysis #endif // PWGHF_UTILS_UTILSANALYSIS_H_ diff --git a/PWGHF/Utils/utilsDerivedData.h b/PWGHF/Utils/utilsDerivedData.h new file mode 100644 index 00000000000..c5eb6cc3b89 --- /dev/null +++ b/PWGHF/Utils/utilsDerivedData.h @@ -0,0 +1,262 @@ +// 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 utilsDerivedData.h +/// \brief Utilities for derived-data creators +/// \author Vít Kučera , Inha University + +#ifndef PWGHF_UTILS_UTILSDERIVEDDATA_H_ +#define PWGHF_UTILS_UTILSDERIVEDDATA_H_ + +#include +#include + +#include "fairlogger/Logger.h" + +#include "Framework/AnalysisHelpers.h" +#include "Framework/Configurable.h" +#include "Framework/ASoA.h" + +#include "Common/Core/RecoDecay.h" + +#include "PWGHF/DataModel/DerivedTables.h" + +// Macro to store nSigma for prong _id_ with PID hypothesis _hyp_ in an array +#define GET_N_SIGMA_PRONG(_array_, _candidate_, _id_, _hyp_) \ + _array_[0] = _candidate_.nSigTpc##_hyp_##_id_(); \ + _array_[1] = _candidate_.nSigTof##_hyp_##_id_(); \ + _array_[2] = _candidate_.tpcTofNSigma##_hyp_##_id_(); + +namespace o2::analysis::hf_derived +{ +/// Reserve space in the filled table for all entries in the source table. +/// \param cursor cursor of the filled table +/// \param enabled switch for filling the table +/// \param size size of the source table +template +void reserveTable(T& cursor, const o2::framework::Configurable& enabled, const uint64_t size) +{ + if (enabled.value) { + cursor.reserve(size); + } +} + +struct HfConfigurableDerivedData : o2::framework::ConfigurableGroup { + // Candidates + o2::framework::Configurable fillCandidateBase{"fillCandidateBase", true, "Fill candidate base properties"}; + // Collisions + o2::framework::Configurable fillCollBase{"fillCollBase", true, "Fill collision base properties"}; + o2::framework::Configurable fillCollId{"fillCollId", true, "Fill original collision indices"}; + // MC collisions + o2::framework::Configurable fillMcCollBase{"fillMcCollBase", true, "Fill MC collision base properties"}; + o2::framework::Configurable fillMcCollId{"fillMcCollId", true, "Fill original MC collision indices"}; + o2::framework::Configurable fillMcRCollId{"fillMcRCollId", true, "Fill indices of saved derived reconstructed collisions matched to saved derived MC collisions"}; + // MC particles + o2::framework::Configurable fillParticleBase{"fillParticleBase", true, "Fill MC particle properties"}; + o2::framework::Configurable fillParticleId{"fillParticleId", true, "Fill original MC indices"}; +}; + +template < + typename HfBases, + typename HfCollBases, + typename HfCollIds, + typename HfMcCollBases, + typename HfMcCollIds, + typename HfMcRCollIds, + typename HfPBases, + typename HfPIds> +struct HfProducesDerivedData : o2::framework::ProducesGroup { + // Candidates + o2::framework::Produces rowCandidateBase; + // Collisions + o2::framework::Produces rowCollBase; + o2::framework::Produces rowCollId; + // MC collisions + o2::framework::Produces rowMcCollBase; + o2::framework::Produces rowMcCollId; + o2::framework::Produces rowMcRCollId; + // MC particles + o2::framework::Produces rowParticleBase; + o2::framework::Produces rowParticleId; + + HfConfigurableDerivedData const* conf; + std::map> matchedCollisions; // indices of derived reconstructed collisions matched to the global indices of MC collisions + std::map hasMcParticles; // flags for MC collisions with HF particles + + void init(HfConfigurableDerivedData const& c) + { + conf = &c; + } + + template + void reserveTablesCandidates(T size) + { + o2::analysis::hf_derived::reserveTable(rowCandidateBase, conf->fillCandidateBase, size); + } + + template + void reserveTablesColl(T size) + { + o2::analysis::hf_derived::reserveTable(rowCollBase, conf->fillCollBase, size); + o2::analysis::hf_derived::reserveTable(rowCollId, conf->fillCollId, size); + } + + template + void reserveTablesMcColl(T size) + { + o2::analysis::hf_derived::reserveTable(rowMcCollBase, conf->fillMcCollBase, size); + o2::analysis::hf_derived::reserveTable(rowMcCollId, conf->fillMcCollId, size); + o2::analysis::hf_derived::reserveTable(rowMcRCollId, conf->fillMcRCollId, size); + } + + template + void reserveTablesParticles(T size) + { + o2::analysis::hf_derived::reserveTable(rowParticleBase, conf->fillParticleBase, size); + o2::analysis::hf_derived::reserveTable(rowParticleId, conf->fillParticleId, size); + } + + template + void fillTablesCandidate(const T& candidate, double invMass, double y) + { + if (conf->fillCandidateBase.value) { + rowCandidateBase( + rowCollBase.lastIndex(), + candidate.pt(), + candidate.eta(), + candidate.phi(), + invMass, + y); + } + } + + template + // void fillTablesCollision(const T& collision, int isEventReject, int runNumber) + void fillTablesCollision(const T& collision) + { + if (conf->fillCollBase.value) { + rowCollBase( + collision.posX(), + collision.posY(), + collision.posZ(), + collision.numContrib(), + collision.centFT0A(), + collision.centFT0C(), + collision.centFT0M(), + collision.centFV0A(), + collision.multZeqNTracksPV()); + } + if (conf->fillCollId.value) { + rowCollId( + collision.globalIndex()); + } + if constexpr (isMC) { + if (conf->fillMcRCollId.value && collision.has_mcCollision()) { + // Save rowCollBase.lastIndex() at key collision.mcCollisionId() + LOGF(debug, "Rec. collision %d: Filling derived-collision index %d for MC collision %d", collision.globalIndex(), rowCollBase.lastIndex(), collision.mcCollisionId()); + matchedCollisions[collision.mcCollisionId()].push_back(rowCollBase.lastIndex()); // [] inserts an empty element if it does not exist + } + } + } + + template + void fillTablesMcCollision(const T& mcCollision) + { + if (conf->fillMcCollBase.value) { + rowMcCollBase( + mcCollision.posX(), + mcCollision.posY(), + mcCollision.posZ(), + mcCollision.centFT0M()); + } + if (conf->fillMcCollId.value) { + rowMcCollId( + mcCollision.globalIndex()); + } + if (conf->fillMcRCollId.value) { + // Fill the table with the vector of indices of derived reconstructed collisions matched to mcCollision.globalIndex() + rowMcRCollId( + matchedCollisions[mcCollision.globalIndex()]); + } + } + + template + void fillTablesParticle(const T& particle, U mass) + { + if (conf->fillParticleBase.value) { + rowParticleBase( + rowMcCollBase.lastIndex(), + particle.pt(), + particle.eta(), + particle.phi(), + RecoDecayPtEtaPhi::y(particle.pt(), particle.eta(), mass), + particle.flagMcMatchGen(), + particle.originMcGen()); + } + if (conf->fillParticleId.value) { + rowParticleId( + particle.mcCollisionId(), + particle.globalIndex()); + } + } + + template + void preProcessMcCollisions(CollisionType const& mcCollisions, + o2::framework::Preslice const& mcParticlesPerMcCollision, + ParticleType const& mcParticles) + { + if (!conf->fillMcRCollId.value) { + return; + } + hasMcParticles.clear(); + // Fill MC collision flags + for (const auto& mcCollision : mcCollisions) { + auto thisMcCollId = mcCollision.globalIndex(); + auto particlesThisMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, thisMcCollId); + LOGF(debug, "MC collision %d has %d MC particles (preprocess)", thisMcCollId, particlesThisMcColl.size()); + hasMcParticles[thisMcCollId] = (particlesThisMcColl.size() > 0); + } + } + + template + void processMcParticles(CollisionType const& mcCollisions, + o2::framework::Preslice const& mcParticlesPerMcCollision, + ParticleType const& mcParticles, + TMass const massParticle) + { + // Fill MC collision properties + auto sizeTableMcColl = mcCollisions.size(); + reserveTablesMcColl(sizeTableMcColl); + for (const auto& mcCollision : mcCollisions) { + auto thisMcCollId = mcCollision.globalIndex(); + auto particlesThisMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, thisMcCollId); + auto sizeTablePart = particlesThisMcColl.size(); + LOGF(debug, "MC collision %d has %d MC particles", thisMcCollId, sizeTablePart); + // Skip MC collisions without HF particles (and without HF candidates in matched reconstructed collisions if saving indices of reconstructed collisions matched to MC collisions) + LOGF(debug, "MC collision %d has %d saved derived rec. collisions", thisMcCollId, matchedCollisions[thisMcCollId].size()); + if (sizeTablePart == 0 && (!conf->fillMcRCollId.value || matchedCollisions[thisMcCollId].empty())) { + LOGF(debug, "Skipping MC collision %d", thisMcCollId); + continue; + } + LOGF(debug, "Filling MC collision %d at derived index %d", thisMcCollId, rowMcCollBase.lastIndex() + 1); + fillTablesMcCollision(mcCollision); + + // Fill MC particle properties + reserveTablesParticles(sizeTablePart); + for (const auto& particle : particlesThisMcColl) { + fillTablesParticle(particle, massParticle); + } + } + } +}; +} // namespace o2::analysis::hf_derived + +#endif // PWGHF_UTILS_UTILSDERIVEDDATA_H_ diff --git a/PWGHF/Utils/utilsEvSelHf.h b/PWGHF/Utils/utilsEvSelHf.h index 19b19f22d98..a3500da73da 100644 --- a/PWGHF/Utils/utilsEvSelHf.h +++ b/PWGHF/Utils/utilsEvSelHf.h @@ -10,170 +10,455 @@ // or submit itself to any jurisdiction. /// \file utilsEvSelHf.h -/// \brief Utility set the event selections for HF analyses +/// \brief Event selection utilities for HF analyses /// \author Mattia Faggin , CERN +/// \author Vít Kučera , Inha University +/// \author Luigi Dello Stritto , CERN #ifndef PWGHF_UTILS_UTILSEVSELHF_H_ #define PWGHF_UTILS_UTILSEVSELHF_H_ +#include // std::shared_ptr +#include // std::string + +#include "Framework/Configurable.h" +#include "Framework/HistogramRegistry.h" #include "Framework/HistogramSpec.h" +#include "Framework/OutputObjHeader.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGHF/Core/CentralityEstimation.h" + +namespace o2::hf_occupancy +{ +// centrality selection estimators +enum OccupancyEstimator { None = 0, + Its, + Ft0c }; + +/// Get the occupancy +/// \param collision is the collision with the occupancy information +/// \return collision occupancy +template +float getOccupancyColl(Coll const& collision, int occEstimator) +{ + switch (occEstimator) { + case OccupancyEstimator::Its: + return collision.trackOccupancyInTimeRange(); + case OccupancyEstimator::Ft0c: + return collision.ft0cOccupancyInTimeRange(); + default: + LOG(fatal) << "Occupancy estimator not valid. Possible values are ITS or FT0C."; + break; + } + return -999.f; +}; + +/// \brief Function to get MC collision occupancy +/// \param collSlice collection of reconstructed collisions associated to a generated one +/// \return generated MC collision occupancy +template +int getOccupancyGenColl(CCs const& collSlice, int occEstimator) +{ + float multiplicity{0.f}; + int occupancy = 0; + for (const auto& collision : collSlice) { + float collMult{0.f}; + collMult = collision.numContrib(); + if (collMult > multiplicity) { + occupancy = getOccupancyColl(collision, occEstimator); + multiplicity = collMult; + } + } // end loop over collisions + return occupancy; +}; +} // namespace o2::hf_occupancy namespace o2::hf_evsel { // event rejection types enum EventRejection { None = 0, + SoftwareTrigger, Centrality, Trigger, + TvxTrigger, TimeFrameBorderCut, + ItsRofBorderCut, + IsGoodZvtxFT0vsPV, + NoSameBunchPileup, + Occupancy, NContrib, Chi2, PositionZ, + NoCollInTimeRangeNarrow, + NoCollInTimeRangeStandard, + NoCollInRofStandard, NEventRejection }; -o2::framework::AxisSpec axisEvents = {EventRejection::NEventRejection, -0.5f, static_cast(EventRejection::NEventRejection) - 0.5f, ""}; +o2::framework::AxisSpec axisEvents = {EventRejection::NEventRejection, -0.5f, +EventRejection::NEventRejection - 0.5f, ""}; -/// @brief Function to put labels on collision monitoring histogram -/// \param hCollisions is the histogram +/// \brief Function to put labels on monitoring histogram +/// \param hRejection monitoring histogram +/// \param softwareTriggerLabel bin label for software trigger rejection template -void setLabelHistoEvSel(Histo& hCollisions) +void setEventRejectionLabels(Histo& hRejection, std::string softwareTriggerLabel = "") { - hCollisions->SetTitle("HF event counter;;accepted collisions"); - hCollisions->GetXaxis()->SetBinLabel(EventRejection::None + 1, "All collisions"); - hCollisions->GetXaxis()->SetBinLabel(EventRejection::Centrality + 1, "Centrality"); - hCollisions->GetXaxis()->SetBinLabel(EventRejection::Trigger + 1, "Trigger"); - hCollisions->GetXaxis()->SetBinLabel(EventRejection::TimeFrameBorderCut + 1, "TF border"); - hCollisions->GetXaxis()->SetBinLabel(EventRejection::NContrib + 1, "# of PV contributors"); - hCollisions->GetXaxis()->SetBinLabel(EventRejection::Chi2 + 1, "PV #it{#chi}^{2}"); - hCollisions->GetXaxis()->SetBinLabel(EventRejection::PositionZ + 1, "PV #it{z}"); + // Puts labels on the collision monitoring histogram. + hRejection->GetXaxis()->SetBinLabel(EventRejection::None + 1, "All"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::SoftwareTrigger + 1, softwareTriggerLabel.data()); + hRejection->GetXaxis()->SetBinLabel(EventRejection::Centrality + 1, "Centrality"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::Trigger + 1, "Trigger"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::TvxTrigger + 1, "TVX Trigger"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::TimeFrameBorderCut + 1, "TF border"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::ItsRofBorderCut + 1, "ITS ROF border"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::IsGoodZvtxFT0vsPV + 1, "PV #it{z} consistency FT0 timing"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::NoSameBunchPileup + 1, "No same-bunch pile-up"); // POTENTIALLY BAD FOR BEAUTY ANALYSES + hRejection->GetXaxis()->SetBinLabel(EventRejection::Occupancy + 1, "Occupancy"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::NContrib + 1, "# of PV contributors"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::Chi2 + 1, "PV #it{#chi}^{2}"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::PositionZ + 1, "PV #it{z}"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::NoCollInTimeRangeNarrow + 1, "No coll timerange narrow"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::NoCollInTimeRangeStandard + 1, "No coll timerange strict"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::NoCollInRofStandard + 1, "No coll in ROF std"); } -/// \brief Function to apply event selections in HF analyses -/// \param applyEvSel template argument to use information from the EvSel table -/// \param centEstimator template argument to select the centrality estimator -/// \param collision collision that has to satisfy the selection criteria -/// \param centrality collision centrality to be initialised in this function -/// \param centralityMin minimum centrality accepted -/// \param centralityMax maximum centrality accepted -/// \param useSel8Trigger switch to activate the sel8() event selection -/// \param triggerClass trigger class different from sel8 (e.g. kINT7 for Run2) used only if useSel8Trigger is false -/// \param useTimeFrameBorderCut switch to activate the time frame border cut -/// \param zPvPosMin minimum primary-vertex z -/// \param zPvPosMax maximum primary-vertex z -/// \param nPvContributorsMin minimum number of PV contributors -/// \param chi2PvMax maximum PV chi2 -/// \return a bitmask with the event selections not satisfied by the analysed collision -template -uint16_t getHfCollisionRejectionMask(const Coll& collision, float& centrality, float centralityMin, float centralityMax, bool useSel8Trigger, int triggerClass, bool useTimeFrameBorderCut, float zPvPosMin, float zPvPosMax, int nPvContributorsMin, float chi2PvMax) -{ +struct HfEventSelection : o2::framework::ConfigurableGroup { + std::string prefix = "hfEvSel"; // JSON group name + // event selection parameters (in chronological order of application) + o2::framework::Configurable centralityMin{"centralityMin", 0., "Minimum centrality"}; + o2::framework::Configurable centralityMax{"centralityMax", 100., "Maximum centrality"}; + o2::framework::Configurable useSel8Trigger{"useSel8Trigger", true, "Apply the sel8 event selection"}; + o2::framework::Configurable triggerClass{"triggerClass", -1, "Trigger class different from sel8 (e.g. kINT7 for Run2) used only if useSel8Trigger is false"}; + o2::framework::Configurable useTvxTrigger{"useTvxTrigger", true, "Apply TVX trigger sel"}; + o2::framework::Configurable useTimeFrameBorderCut{"useTimeFrameBorderCut", true, "Apply TF border cut"}; + o2::framework::Configurable useItsRofBorderCut{"useItsRofBorderCut", true, "Apply ITS ROF border cut"}; + o2::framework::Configurable useIsGoodZvtxFT0vsPV{"useIsGoodZvtxFT0vsPV", false, "Check consistency between PVz from central barrel with that from FT0 timing"}; + o2::framework::Configurable useNoSameBunchPileup{"useNoSameBunchPileup", false, "Exclude collisions in bunches with more than 1 reco. PV"}; // POTENTIALLY BAD FOR BEAUTY ANALYSES + o2::framework::Configurable useOccupancyCut{"useOccupancyCut", false, "Apply occupancy selection (num. ITS tracks with at least 5 clusters or num. of signals in FT0c in +-100us from current collision)"}; + o2::framework::Configurable occEstimator{"occEstimator", 1, "Occupancy estimation (1: ITS, 2: FT0C)"}; + o2::framework::Configurable occupancyMin{"occupancyMin", 0, "Minimum occupancy"}; + o2::framework::Configurable occupancyMax{"occupancyMax", 1000000, "Maximum occupancy"}; + o2::framework::Configurable nPvContributorsMin{"nPvContributorsMin", 0, "Minimum number of PV contributors"}; + o2::framework::Configurable chi2PvMax{"chi2PvMax", -1.f, "Maximum PV chi2"}; + o2::framework::Configurable zPvPosMin{"zPvPosMin", -10.f, "Minimum PV posZ (cm)"}; + o2::framework::Configurable zPvPosMax{"zPvPosMax", 10.f, "Maximum PV posZ (cm)"}; + o2::framework::Configurable useNoCollInTimeRangeNarrow{"useNoCollInTimeRangeNarrow", false, "Reject collisions in time range narrow"}; + o2::framework::Configurable useNoCollInTimeRangeStandard{"useNoCollInTimeRangeStandard", false, "Reject collisions in time range strict"}; + o2::framework::Configurable useNoCollInRofStandard{"useNoCollInRofStandard", false, "Reject collisions in ROF standard"}; + o2::framework::Configurable softwareTrigger{"softwareTrigger", "", "Label of software trigger. Multiple triggers can be selected dividing them by a comma. Set None if you want bcs that are not selected by any trigger"}; + o2::framework::Configurable bcMarginForSoftwareTrigger{"bcMarginForSoftwareTrigger", 100, "Number of BCs of margin for software triggers"}; + o2::framework::Configurable ccdbPathSoftwareTrigger{"ccdbPathSoftwareTrigger", "Users/m/mpuccio/EventFiltering/OTS/Chunked/", "ccdb path for ZORRO objects"}; + o2::framework::ConfigurableAxis th2ConfigAxisCent{"th2ConfigAxisCent", {100, 0., 100.}, ""}; + o2::framework::ConfigurableAxis th2ConfigAxisOccupancy{"th2ConfigAxisOccupancy", {14, 0, 14000}, ""}; - uint16_t statusCollision{0}; // 16 bits, in case new ev. selections will be added + // histogram names + static constexpr char NameHistCollisions[] = "hCollisions"; + static constexpr char NameHistSelCollisionsCent[] = "hSelCollisionsCent"; + static constexpr char NameHistPosZBeforeEvSel[] = "hPosZBeforeEvSel"; + static constexpr char NameHistPosZAfterEvSel[] = "hPosZAfterEvSel"; + static constexpr char NameHistPosXAfterEvSel[] = "hPosXAfterEvSel"; + static constexpr char NameHistPosYAfterEvSel[] = "hPosYAfterEvSel"; + static constexpr char NameHistNumPvContributorsAfterSel[] = "hNumPvContributorsAfterSel"; + static constexpr char NameHistCollisionsCentOcc[] = "hCollisionsCentOcc"; - if constexpr (centEstimator != o2::aod::hf_collision_centrality::CentralityEstimator::None) { - if constexpr (centEstimator == o2::aod::hf_collision_centrality::CentralityEstimator::FT0A) { - centrality = collision.centFT0A(); - } else if constexpr (centEstimator == o2::aod::hf_collision_centrality::CentralityEstimator::FT0C) { - centrality = collision.centFT0C(); - } else if constexpr (centEstimator == o2::aod::hf_collision_centrality::CentralityEstimator::FT0M) { - centrality = collision.centFT0M(); - } else if constexpr (centEstimator == o2::aod::hf_collision_centrality::CentralityEstimator::FV0A) { - centrality = collision.centFV0A(); - } else { - LOGP(fatal, "Centrality estimator different from FT0A, FT0C, FT0M, and FV0A, fix it!"); - } - if (centrality < centralityMin || centrality > centralityMax) { - SETBIT(statusCollision, EventRejection::Centrality); + std::shared_ptr hCollisions, hSelCollisionsCent, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel; + std::shared_ptr hCollisionsCentOcc; + + // util to retrieve trigger mask in case of software triggers + Zorro zorro; + o2::framework::OutputObj zorroSummary{"zorroSummary"}; + int currentRun{-1}; + + /// \brief Adds collision monitoring histograms in the histogram registry. + /// \param registry reference to the histogram registry + void addHistograms(o2::framework::HistogramRegistry& registry) + { + hCollisions = registry.add(NameHistCollisions, "HF event counter;;# of accepted collisions", {o2::framework::HistType::kTH1D, {axisEvents}}); + hSelCollisionsCent = registry.add(NameHistSelCollisionsCent, "HF event counter;T0M;# of accepted collisions", {o2::framework::HistType::kTH1D, {{100, 0., 100.}}}); + hPosZBeforeEvSel = registry.add(NameHistPosZBeforeEvSel, "all events;#it{z}_{prim. vtx.} (cm);entries", {o2::framework::HistType::kTH1D, {{400, -20., 20.}}}); + hPosZAfterEvSel = registry.add(NameHistPosZAfterEvSel, "selected events;#it{z}_{prim. vtx.} (cm);entries", {o2::framework::HistType::kTH1D, {{400, -20., 20.}}}); + hPosXAfterEvSel = registry.add(NameHistPosXAfterEvSel, "selected events;#it{x}_{prim. vtx.} (cm);entries", {o2::framework::HistType::kTH1D, {{200, -0.5, 0.5}}}); + hPosYAfterEvSel = registry.add(NameHistPosYAfterEvSel, "selected events;#it{y}_{prim. vtx.} (cm);entries", {o2::framework::HistType::kTH1D, {{200, -0.5, 0.5}}}); + hNumPvContributorsAfterSel = registry.add(NameHistNumPvContributorsAfterSel, "selected events;#it{y}_{prim. vtx.} (cm);entries", {o2::framework::HistType::kTH1D, {{500, -0.5, 499.5}}}); + setEventRejectionLabels(hCollisions, softwareTrigger); + + const o2::framework::AxisSpec th2AxisCent{th2ConfigAxisCent, "Centrality"}; + const o2::framework::AxisSpec th2AxisOccupancy{th2ConfigAxisOccupancy, "Occupancy"}; + hCollisionsCentOcc = registry.add(NameHistCollisionsCentOcc, "selected events;Centrality; Occupancy", {o2::framework::HistType::kTH2D, {th2AxisCent, th2AxisOccupancy}}); + + // we initialise the summary object + if (softwareTrigger.value != "") { + zorroSummary.setObject(zorro.getZorroSummary()); } } - if constexpr (applyEvSel) { - /// trigger condition - if ((useSel8Trigger && !collision.sel8()) || (!useSel8Trigger && triggerClass > -1 && !collision.alias_bit(triggerClass))) { - SETBIT(statusCollision, EventRejection::Trigger); + /// \brief Applies event selection. + /// \tparam useEvSel use information from the EvSel table + /// \tparam centEstimator centrality estimator + /// \param collision collision to test against the selection criteria + /// \param centrality collision centrality variable to be set in this function + /// \param ccdb ccdb service needed to retrieve the needed info for zorro + /// \param registry reference to the histogram registry needed for zorro + /// \return bitmask with the event selection criteria not satisfied by the collision + template + uint16_t getHfCollisionRejectionMask(const Coll& collision, float& centrality, o2::framework::Service const& ccdb, o2::framework::HistogramRegistry& registry) + { + uint16_t rejectionMask{0}; // 16 bits, in case new ev. selections will be added + + if constexpr (centEstimator != o2::hf_centrality::CentralityEstimator::None) { + centrality = o2::hf_centrality::getCentralityColl(collision, centEstimator); + if (centrality < centralityMin || centrality > centralityMax) { + SETBIT(rejectionMask, EventRejection::Centrality); + } } - /// time frame border cut - if (useTimeFrameBorderCut && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { - SETBIT(statusCollision, EventRejection::TimeFrameBorderCut); + + if constexpr (useEvSel) { + /// trigger condition + if ((useSel8Trigger && !collision.sel8()) || (!useSel8Trigger && triggerClass > -1 && !collision.alias_bit(triggerClass))) { + SETBIT(rejectionMask, EventRejection::Trigger); + } + /// TVX trigger selection + if (useTvxTrigger && !collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + SETBIT(rejectionMask, EventRejection::TvxTrigger); + } + /// time frame border cut + if (useTimeFrameBorderCut && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + SETBIT(rejectionMask, EventRejection::TimeFrameBorderCut); + } + /// ITS rof border cut + if (useItsRofBorderCut && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + SETBIT(rejectionMask, EventRejection::ItsRofBorderCut); + } + /// PVz consistency tracking - FT0 timing + if (useIsGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + SETBIT(rejectionMask, EventRejection::IsGoodZvtxFT0vsPV); + } + /// remove collisions in bunches with more than 1 reco collision + /// POTENTIALLY BAD FOR BEAUTY ANALYSES + if (useNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + SETBIT(rejectionMask, EventRejection::NoSameBunchPileup); + } + /// No collisions in time range narrow + if (useNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + SETBIT(rejectionMask, EventRejection::NoCollInTimeRangeNarrow); + } + /// No collisions in time range strict + if (useNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + SETBIT(rejectionMask, EventRejection::NoCollInTimeRangeStandard); + } + /// No collisions in ROF standard + if (useNoCollInRofStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + SETBIT(rejectionMask, EventRejection::NoCollInRofStandard); + } + if (useOccupancyCut) { + float occupancy = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); + if (occupancy < occupancyMin || occupancy > occupancyMax) { + SETBIT(rejectionMask, EventRejection::Occupancy); + } + } } - } - /// primary vertex z - if (collision.posZ() < zPvPosMin || collision.posZ() > zPvPosMax) { - SETBIT(statusCollision, EventRejection::PositionZ); - } + /// number of PV contributors + if (collision.numContrib() < nPvContributorsMin) { + SETBIT(rejectionMask, EventRejection::NContrib); + } - /// number of PV contributors - if (collision.numContrib() < nPvContributorsMin) { - SETBIT(statusCollision, EventRejection::NContrib); - } + /// max PV chi2 + if (chi2PvMax > 0. && collision.chi2() > chi2PvMax) { + SETBIT(rejectionMask, EventRejection::Chi2); + } - /// max PV chi2 - if (chi2PvMax > 0. && collision.chi2() > chi2PvMax) { - SETBIT(statusCollision, EventRejection::Chi2); - } + /// primary vertex z + if (collision.posZ() < zPvPosMin || collision.posZ() > zPvPosMax) { + SETBIT(rejectionMask, EventRejection::PositionZ); + } - return statusCollision; -} + if (softwareTrigger.value != "") { + // we might have to update it from CCDB + auto bc = collision.template bc_as(); -/// @brief function to monitor the event selection satisfied by collisions used for HF analyses -/// \param collision is the analysed collision -/// \param rejectionMask is the bitmask storing the info about which ev. selections are not satisfied by the collision -/// \param hCollisions is a histogram to keep track of the satisfied event selections -/// \param hPosZBeforeEvSel is a histogram for the PV position Z for all analysed collisions -/// \param hPosZAfterEvSel is a histogram for the PV position Z only for collisions satisfying the event selections -/// \param hPosXAfterEvSel is a histogram for the PV position X only for collisions satisfying the event selections -/// \param hPosYAfterEvSel is a histogram for the PV position Y only for collisions satisfying the event selections -/// \param hNumContributors is a histogram for the number of PV contributors only for collisions satisfying the event selections -template -void monitorCollision(Coll const& collision, const uint16_t rejectionMask, Hist& hCollisions, Hist& hPosZBeforeEvSel, Hist& hPosZAfterEvSel, Hist& hPosXAfterEvSel, Hist& hPosYAfterEvSel, Hist& hNumContributors) -{ + int runNumber = bc.runNumber(); + if (runNumber != currentRun) { // We might need to update Zorro from CCDB if the run number changes + zorro.setCCDBpath(ccdbPathSoftwareTrigger); + zorro.setBCtolerance(bcMarginForSoftwareTrigger); + zorro.initCCDB(ccdb.service, runNumber, bc.timestamp(), softwareTrigger.value); + currentRun = runNumber; + } + zorro.populateHistRegistry(registry, runNumber); - hCollisions->Fill(EventRejection::None); // all collisions - const float posZ = collision.posZ(); - hPosZBeforeEvSel->Fill(posZ); + if (softwareTrigger.value != "None") { + if (!zorro.isSelected(bc.globalBC(), bcMarginForSoftwareTrigger)) { /// Just let Zorro do the accounting + SETBIT(rejectionMask, EventRejection::SoftwareTrigger); + } + } else { + if (!zorro.isNotSelectedByAny(bc.globalBC(), bcMarginForSoftwareTrigger)) { /// Just let Zorro do the accounting of not selected BCs + SETBIT(rejectionMask, EventRejection::SoftwareTrigger); + } + } + } - /// centrality - if (TESTBIT(rejectionMask, EventRejection::Centrality)) { - return; + return rejectionMask; } - hCollisions->Fill(EventRejection::Centrality); // Centrality ok - /// sel8() - if (TESTBIT(rejectionMask, EventRejection::Trigger)) { - return; - } - hCollisions->Fill(EventRejection::Trigger); // Centrality + sel8 ok + /// \brief Fills histograms for monitoring event selections satisfied by the collision. + /// \param collision analysed collision + /// \param rejectionMask bitmask storing the info about which ev. selections are not satisfied by the collision + template + void fillHistograms(Coll const& collision, const uint16_t rejectionMask, float& centrality, float occupancy = -1) + { + hCollisions->Fill(EventRejection::None); + const float posZ = collision.posZ(); + hPosZBeforeEvSel->Fill(posZ); - /// Time Frame border cut - if (TESTBIT(rejectionMask, EventRejection::TimeFrameBorderCut)) { - return; + for (std::size_t reason = 1; reason < EventRejection::NEventRejection; reason++) { + if (TESTBIT(rejectionMask, reason)) { + return; + } + hCollisions->Fill(reason); + } + + hPosXAfterEvSel->Fill(collision.posX()); + hPosYAfterEvSel->Fill(collision.posY()); + hPosZAfterEvSel->Fill(posZ); + hNumPvContributorsAfterSel->Fill(collision.numContrib()); + hSelCollisionsCent->Fill(centrality); + hCollisionsCentOcc->Fill(centrality, occupancy); } - hCollisions->Fill(EventRejection::TimeFrameBorderCut); // Centrality + sel8 + TF border ok +}; - /// PV contributors - if (TESTBIT(rejectionMask, EventRejection::NContrib)) { - return; +struct HfEventSelectionMc { + // event selection parameters (in chronological order of application) + bool useSel8Trigger{false}; // Apply the Sel8 selection + bool useTvxTrigger{false}; // Apply the TVX trigger + bool useTimeFrameBorderCut{true}; // Apply TF border cut + bool useItsRofBorderCut{false}; // Apply the ITS RO frame border cut + float zPvPosMin{-1000.f}; // Minimum PV posZ (cm) + float zPvPosMax{1000.f}; // Maximum PV posZ (cm) + float centralityMin{0.f}; // Minimum centrality + float centralityMax{100.f}; // Maximum centrality + + // histogram names + static constexpr char NameHistGenCollisionsCent[] = "hGenCollisionsCent"; + std::shared_ptr hGenCollisionsCent; + static constexpr char NameHistRecCollisionsCentMc[] = "hRecCollisionsCentMc"; + std::shared_ptr hRecCollisionsCentMc; + static constexpr char NameHistNSplitVertices[] = "hNSplitVertices"; + std::shared_ptr hNSplitVertices; + static constexpr char NameHistParticles[] = "hParticles"; + std::shared_ptr hParticles; + + /// \brief Adds collision monitoring histograms in the histogram registry. + /// \param registry reference to the histogram registry + void addHistograms(o2::framework::HistogramRegistry& registry) + { + hGenCollisionsCent = registry.add(NameHistGenCollisionsCent, "HF event counter;T0M;# of generated collisions", {o2::framework::HistType::kTH1D, {{100, 0., 100.}}}); + hRecCollisionsCentMc = registry.add(NameHistRecCollisionsCentMc, "HF event counter;T0M;# of reconstructed collisions", {o2::framework::HistType::kTH1D, {{100, 0., 100.}}}); + hNSplitVertices = registry.add(NameHistNSplitVertices, "HF split vertices counter;;# of reconstructed collisions per mc collision", {o2::framework::HistType::kTH1D, {{4, 1., 5.}}}); + hParticles = registry.add(NameHistParticles, "HF particle counter;;# of accepted particles", {o2::framework::HistType::kTH1D, {axisEvents}}); + // Puts labels on the collision monitoring histogram. + setEventRejectionLabels(hParticles); } - hCollisions->Fill(EventRejection::NContrib); // Centrality + sel8 + TF border + PV contr ok - /// PV chi2 - if (TESTBIT(rejectionMask, EventRejection::Chi2)) { - return; + void configureFromDevice(const o2::framework::DeviceSpec& device) + { + for (const auto& option : device.options) { + if (option.name.compare("hfEvSel.useSel8Trigger") == 0) { + useSel8Trigger = option.defaultValue.get(); + } else if (option.name.compare("hfEvSel.useTvxTrigger") == 0) { + useTvxTrigger = option.defaultValue.get(); + } else if (option.name.compare("hfEvSel.useTimeFrameBorderCut") == 0) { + useTimeFrameBorderCut = option.defaultValue.get(); + } else if (option.name.compare("hfEvSel.useItsRofBorderCut") == 0) { + useItsRofBorderCut = option.defaultValue.get(); + } else if (option.name.compare("hfEvSel.zPvPosMin") == 0) { + zPvPosMin = option.defaultValue.get(); + } else if (option.name.compare("hfEvSel.zPvPosMax") == 0) { + zPvPosMax = option.defaultValue.get(); + } else if (option.name.compare("hfEvSel.centralityMin") == 0) { + centralityMin = option.defaultValue.get(); + } else if (option.name.compare("hfEvSel.centralityMax") == 0) { + centralityMax = option.defaultValue.get(); + } + } } - hCollisions->Fill(EventRejection::Chi2); // Centrality + sel8 + TF border + PV contr + chi2 ok - /// PV position Z - if (TESTBIT(rejectionMask, EventRejection::PositionZ)) { - return; + /// \brief Function to apply event selections to generated MC collisions + /// \param mcCollision MC collision to test against the selection criteria + /// \param collSlice collection of reconstructed collisions + /// \param centrality centrality variable to be set in this function + /// \return a bitmask with the event selections not satisfied by the analysed collision + template + uint16_t getHfMcCollisionRejectionMask(TMcColl const& mcCollision, CCs const& collSlice, float& centrality) + { + uint16_t rejectionMask{0}; + float zPv = mcCollision.posZ(); + auto bc = mcCollision.template bc_as(); + + if constexpr (centEstimator != o2::hf_centrality::CentralityEstimator::None) { + centrality = o2::hf_centrality::getCentralityGenColl(collSlice, centEstimator); + /// centrality selection + if (centrality < centralityMin || centrality > centralityMax) { + SETBIT(rejectionMask, EventRejection::Centrality); + } + } + /// Sel8 trigger selection + if (useSel8Trigger && (!bc.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + SETBIT(rejectionMask, EventRejection::Trigger); + } + /// TVX trigger selection + if (useTvxTrigger && !bc.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + SETBIT(rejectionMask, EventRejection::TvxTrigger); + } + /// time frame border cut + if (useTimeFrameBorderCut && !bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + SETBIT(rejectionMask, EventRejection::TimeFrameBorderCut); + } + /// ITS RO frame border cut + if (useItsRofBorderCut && !bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + SETBIT(rejectionMask, EventRejection::ItsRofBorderCut); + } + /// primary vertex z + if (zPv < zPvPosMin || zPv > zPvPosMax) { + SETBIT(rejectionMask, EventRejection::PositionZ); + } + + return rejectionMask; } - hCollisions->Fill(EventRejection::PositionZ); // Centrality + sel8 + TF border + PV contr + chi2 + posZ ok - hPosXAfterEvSel->Fill(collision.posX()); - hPosYAfterEvSel->Fill(collision.posY()); - hPosZAfterEvSel->Fill(posZ); - hNumContributors->Fill(collision.numContrib()); -} + /// \brief Fills histogram for monitoring event selections satisfied by the collision. + /// \param collision analysed collision + /// \param rejectionMask bitmask storing the info about which ev. selections are not satisfied by the collision + template + void fillHistograms(Coll const& mcCollision, const uint16_t rejectionMask, int nSplitColl = 0) + { + hParticles->Fill(EventRejection::None); + + if constexpr (centEstimator == o2::hf_centrality::CentralityEstimator::FT0M) { + if (!TESTBIT(rejectionMask, EventRejection::TimeFrameBorderCut) && !TESTBIT(rejectionMask, EventRejection::ItsRofBorderCut) && !TESTBIT(rejectionMask, EventRejection::PositionZ)) { + hGenCollisionsCent->Fill(mcCollision.centFT0M()); + } + } + + for (std::size_t reason = 1; reason < EventRejection::NEventRejection; reason++) { + if (TESTBIT(rejectionMask, reason)) { + return; + } + hParticles->Fill(reason); + } + + if constexpr (centEstimator == o2::hf_centrality::CentralityEstimator::FT0M) { + hNSplitVertices->Fill(nSplitColl); + for (int nColl = 0; nColl < nSplitColl; nColl++) { + hRecCollisionsCentMc->Fill(mcCollision.centFT0M()); + } + } + } +}; } // namespace o2::hf_evsel #endif // PWGHF_UTILS_UTILSEVSELHF_H_ diff --git a/PWGHF/Utils/utilsMcGen.h b/PWGHF/Utils/utilsMcGen.h new file mode 100644 index 00000000000..863d7041102 --- /dev/null +++ b/PWGHF/Utils/utilsMcGen.h @@ -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. + +/// \file utilsMcGen.h +/// \brief utility functions for HF Mc gen. workflows +/// +/// \author Nima Zardoshti, nima.zardoshti@cern.ch, CERN + +#ifndef PWGHF_UTILS_UTILSMCGEN_H_ +#define PWGHF_UTILS_UTILSMCGEN_H_ + +#include + +#include + +#include "CommonConstants/PhysicsConstants.h" + +#include "Common/Core/RecoDecay.h" + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" + +namespace hf_mc_gen +{ + +template +void fillMcMatchGen2Prong(T const& mcParticles, U const& mcParticlesPerMcColl, V& rowMcMatchGen, bool rejectBackground) +{ + using namespace o2::constants::physics; + + // Match generated particles. + for (const auto& particle : mcParticlesPerMcColl) { + int8_t flag = 0; + int8_t origin = 0; + int8_t sign = 0; + std::vector idxBhadMothers{}; + // Reject particles from background events + if (particle.fromBackgroundEvent() && rejectBackground) { + rowMcMatchGen(flag, origin, -1); + continue; + } + + // D0(bar) → π± K∓ + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign)) { + flag = sign * (1 << o2::aod::hf_cand_2prong::DecayType::D0ToPiK); + } + + // J/ψ → e+ e− + if (flag == 0) { + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kJPsi, std::array{+kElectron, -kElectron}, true)) { + flag = 1 << o2::aod::hf_cand_2prong::DecayType::JpsiToEE; + } + } + + // J/ψ → μ+ μ− + if (flag == 0) { + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kJPsi, std::array{+kMuonPlus, -kMuonPlus}, true)) { + flag = 1 << o2::aod::hf_cand_2prong::DecayType::JpsiToMuMu; + } + } + + // Check whether the particle is non-prompt (from a b quark). + if (flag != 0) { + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + } + if (origin == RecoDecay::OriginType::NonPrompt) { + rowMcMatchGen(flag, origin, idxBhadMothers[0]); + } else { + rowMcMatchGen(flag, origin, -1); + } + } +} + +template +void fillMcMatchGen3Prong(T const& mcParticles, U const& mcParticlesPerMcColl, V& rowMcMatchGen, bool rejectBackground) +{ + using namespace o2::constants::physics; + + // Match generated particles. + for (const auto& particle : mcParticlesPerMcColl) { + int8_t flag = 0; + int8_t origin = 0; + int8_t channel = 0; + int8_t sign = 0; + std::vector arrDaughIndex; + std::vector idxBhadMothers{}; + std::array arrPDGDaugh; + std::array arrPDGResonant1 = {kProton, 313}; // Λc± → p± K* + std::array arrPDGResonant2 = {2224, kKPlus}; // Λc± → Δ(1232)±± K∓ + std::array arrPDGResonant3 = {102134, kPiPlus}; // Λc± → Λ(1520) π± + std::array arrPDGResonantDPhiPi = {333, kPiPlus}; // Ds± → Phi π± and D± → Phi π± + std::array arrPDGResonantDKstarK = {313, kKPlus}; // Ds± → K*(892)0bar K± and D± → K*(892)0bar K± + // Reject particles from background events + if (particle.fromBackgroundEvent() && rejectBackground) { + rowMcMatchGen(flag, origin, channel, -1); + continue; + } + + // D± → π± K∓ π± + if (flag == 0) { + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kDPlus, std::array{+kPiPlus, -kKPlus, +kPiPlus}, true, &sign, 2)) { + flag = sign * (1 << o2::aod::hf_cand_3prong::DecayType::DplusToPiKPi); + } + } + + // Ds± → K± K∓ π± and D± → K± K∓ π± + if (flag == 0) { + bool isDplus = false; + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kDS, std::array{+kKPlus, -kKPlus, +kPiPlus}, true, &sign, 2)) { + // DecayType::DsToKKPi is used to flag both Ds± → K± K∓ π± and D± → K± K∓ π± + // TODO: move to different and explicit flags + flag = sign * (1 << o2::aod::hf_cand_3prong::DecayType::DsToKKPi); + } else if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kDPlus, std::array{+kKPlus, -kKPlus, +kPiPlus}, true, &sign, 2)) { + // DecayType::DsToKKPi is used to flag both Ds± → K± K∓ π± and D± → K± K∓ π± + // TODO: move to different and explicit flags + flag = sign * (1 << o2::aod::hf_cand_3prong::DecayType::DsToKKPi); + isDplus = true; + } + if (flag != 0) { + RecoDecay::getDaughters(particle, &arrDaughIndex, std::array{0}, 1); + if (arrDaughIndex.size() == 2) { + for (auto jProng = 0u; jProng < arrDaughIndex.size(); ++jProng) { + auto daughJ = mcParticles.rawIteratorAt(arrDaughIndex[jProng]); + arrPDGDaugh[jProng] = std::abs(daughJ.pdgCode()); + } + if ((arrPDGDaugh[0] == arrPDGResonantDPhiPi[0] && arrPDGDaugh[1] == arrPDGResonantDPhiPi[1]) || (arrPDGDaugh[0] == arrPDGResonantDPhiPi[1] && arrPDGDaugh[1] == arrPDGResonantDPhiPi[0])) { + channel = isDplus ? o2::aod::hf_cand_3prong::DecayChannelDToKKPi::DplusToPhiPi : o2::aod::hf_cand_3prong::DecayChannelDToKKPi::DsToPhiPi; + } else if ((arrPDGDaugh[0] == arrPDGResonantDKstarK[0] && arrPDGDaugh[1] == arrPDGResonantDKstarK[1]) || (arrPDGDaugh[0] == arrPDGResonantDKstarK[1] && arrPDGDaugh[1] == arrPDGResonantDKstarK[0])) { + channel = isDplus ? o2::aod::hf_cand_3prong::DecayChannelDToKKPi::DplusToK0starK : o2::aod::hf_cand_3prong::DecayChannelDToKKPi::DsToK0starK; + } + } + } + } + + // D*± → D0(bar) π± + if (flag == 0) { + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kDStar, std::array{+kPiPlus, +kPiPlus, -kKPlus}, true, &sign, 2)) { + flag = sign * (1 << o2::aod::hf_cand_3prong::DstarToPiKPiBkg); + } + } + + // Λc± → p± K∓ π± + if (flag == 0) { + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2)) { + flag = sign * (1 << o2::aod::hf_cand_3prong::DecayType::LcToPKPi); + + // Flagging the different Λc± → p± K∓ π± decay channels + RecoDecay::getDaughters(particle, &arrDaughIndex, std::array{0}, 1); + if (arrDaughIndex.size() == 2) { + for (auto jProng = 0u; jProng < arrDaughIndex.size(); ++jProng) { + auto daughJ = mcParticles.rawIteratorAt(arrDaughIndex[jProng]); + arrPDGDaugh[jProng] = std::abs(daughJ.pdgCode()); + } + if ((arrPDGDaugh[0] == arrPDGResonant1[0] && arrPDGDaugh[1] == arrPDGResonant1[1]) || (arrPDGDaugh[0] == arrPDGResonant1[1] && arrPDGDaugh[1] == arrPDGResonant1[0])) { + channel = 1; + } else if ((arrPDGDaugh[0] == arrPDGResonant2[0] && arrPDGDaugh[1] == arrPDGResonant2[1]) || (arrPDGDaugh[0] == arrPDGResonant2[1] && arrPDGDaugh[1] == arrPDGResonant2[0])) { + channel = 2; + } else if ((arrPDGDaugh[0] == arrPDGResonant3[0] && arrPDGDaugh[1] == arrPDGResonant3[1]) || (arrPDGDaugh[0] == arrPDGResonant3[1] && arrPDGDaugh[1] == arrPDGResonant3[0])) { + channel = 3; + } + } + } + } + + // Ξc± → p± K∓ π± + if (flag == 0) { + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kXiCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2)) { + flag = sign * (1 << o2::aod::hf_cand_3prong::DecayType::XicToPKPi); + } + } + + // Check whether the particle is non-prompt (from a b quark). + if (flag != 0) { + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + } + if (origin == RecoDecay::OriginType::NonPrompt) { + rowMcMatchGen(flag, origin, channel, idxBhadMothers[0]); + } else { + rowMcMatchGen(flag, origin, channel, -1); + } + } +} + +template +void fillMcMatchGenBplus(T const& mcParticles, U& rowMcMatchGen) +{ + using namespace o2::constants::physics; + + // Match generated particles. + for (const auto& particle : mcParticles) { + int8_t flag = 0; + int8_t origin = 0; + int8_t signB = 0; + int8_t signD0 = 0; + int indexGenD0 = -1; + + // B± → D0bar(D0) π± → (K± π∓) π± + std::vector arrayDaughterB; + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kBPlus, std::array{-Pdg::kD0, +kPiPlus}, true, &signB, 1, &arrayDaughterB)) { + // D0(bar) → π± K∓ + for (const auto iD : arrayDaughterB) { // o2-linter: disable=const-ref-in-for-loop (int values) + auto candDaughterMC = mcParticles.rawIteratorAt(iD); + if (std::abs(candDaughterMC.pdgCode()) == Pdg::kD0) { + indexGenD0 = RecoDecay::isMatchedMCGen(mcParticles, candDaughterMC, Pdg::kD0, std::array{-kKPlus, +kPiPlus}, true, &signD0, 1); + } + } + if (indexGenD0 > -1) { + flag = signB * (1 << o2::aod::hf_cand_bplus::DecayType::BplusToD0Pi); + } + } + rowMcMatchGen(flag, origin); + } // B candidate +} + +template +void fillMcMatchGenB0(T const& mcParticles, U& rowMcMatchGen) +{ + using namespace o2::constants::physics; + + // Match generated particles. + for (const auto& particle : mcParticles) { + int8_t flag = 0; + int8_t origin = 0; + int8_t sign = 0; + // B0 → D- π+ + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kB0, std::array{-static_cast(Pdg::kDPlus), +kPiPlus}, true)) { + // D- → π- K+ π- + auto candDMC = mcParticles.rawIteratorAt(particle.daughtersIds().front()); + if (RecoDecay::isMatchedMCGen(mcParticles, candDMC, -static_cast(Pdg::kDPlus), std::array{-kPiPlus, +kKPlus, -kPiPlus}, true, &sign)) { + flag = sign * BIT(o2::aod::hf_cand_b0::DecayType::B0ToDPi); + } + } + rowMcMatchGen(flag, origin); + } // gen +} + +} // namespace hf_mc_gen + +#endif // PWGHF_UTILS_UTILSMCGEN_H_ diff --git a/PWGHF/Utils/utilsPid.h b/PWGHF/Utils/utilsPid.h new file mode 100644 index 00000000000..5fd2b95ef1e --- /dev/null +++ b/PWGHF/Utils/utilsPid.h @@ -0,0 +1,101 @@ +// 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 utilsPid.h +/// \brief PID utilities for HF analyses +/// +/// \author Mattia Faggin , CERN + +#ifndef PWGHF_UTILS_UTILSPID_H_ +#define PWGHF_UTILS_UTILSPID_H_ + +namespace o2::aod::pid_tpc_tof_utils +{ +enum HfProngSpecies : uint8_t { Pion = 0, + Kaon, + Proton }; + +/// Function to combine TPC and TOF NSigma +/// \param tiny switch between full and tiny (binned) PID tables +/// \param tpcNSigma is the (binned) NSigma separation in TPC (if tiny = true) +/// \param tofNSigma is the (binned) NSigma separation in TOF (if tiny = true) +/// \return combined NSigma of TPC and TOF +template +T1 combineNSigma(T1 tpcNSigma, T1 tofNSigma) +{ + static constexpr float DefaultNSigmaTolerance = .1f; + static constexpr float DefaultNSigma = -999.f + DefaultNSigmaTolerance; // -999.f is the default value set in TPCPIDResponse.h and PIDTOF.h + + if constexpr (tiny) { + tpcNSigma *= aod::pidtpc_tiny::binning::bin_width; + tofNSigma *= aod::pidtof_tiny::binning::bin_width; + } + + if ((tpcNSigma > DefaultNSigma) && (tofNSigma > DefaultNSigma)) { // TPC and TOF + return std::sqrt(.5f * (tpcNSigma * tpcNSigma + tofNSigma * tofNSigma)); + } + if (tpcNSigma > DefaultNSigma) { // only TPC + return std::abs(tpcNSigma); + } + if (tofNSigma > DefaultNSigma) { // only TOF + return std::abs(tofNSigma); + } + return tofNSigma; // no TPC nor TOF +} + +/// @brief Function to fill tables with HF prong PID information +/// @tparam TRK datatype of the prong track +/// @tparam ROW datatype of the prong PID table to fill +/// @tparam specPid particle species +/// @param track prong track +/// @param rowPid cursor of the prong PID table to fill +template +void fillProngPid(TRK const& track, ROW& rowPid) +{ + + // get PID information for the daughter tracks + // TODO: add here the code for a possible PID post-calibrations in MC + float nSigTpc = -999.f; + float nSigTof = -999.f; + if constexpr (specPid == HfProngSpecies::Pion) { + // pion PID + if (track.hasTPC()) { + nSigTpc = track.tpcNSigmaPi(); + } + if (track.hasTOF()) { + nSigTof = track.tofNSigmaPi(); + } + } else if constexpr (specPid == HfProngSpecies::Kaon) { + // kaon PID + if (track.hasTPC()) { + nSigTpc = track.tpcNSigmaKa(); + } + if (track.hasTOF()) { + nSigTof = track.tofNSigmaKa(); + } + } else if constexpr (specPid == HfProngSpecies::Proton) { + // proton PID + if (track.hasTPC()) { + nSigTpc = track.tpcNSigmaPr(); + } + if (track.hasTOF()) { + nSigTof = track.tofNSigmaPr(); + } + } else { + LOG(fatal) << "Unsupported PID. Supported species in HF framework: HfProngSpecies::Pion, HfProngSpecies::Kaon, HfProngSpecies::Proton"; + } + + // fill candidate prong PID rows + rowPid(nSigTpc, nSigTof); +} +} // namespace o2::aod::pid_tpc_tof_utils + +#endif // PWGHF_UTILS_UTILSPID_H_ diff --git a/PWGHF/Utils/utilsTrkCandHf.h b/PWGHF/Utils/utilsTrkCandHf.h index 073e416236d..a1d1b41c10f 100644 --- a/PWGHF/Utils/utilsTrkCandHf.h +++ b/PWGHF/Utils/utilsTrkCandHf.h @@ -41,6 +41,19 @@ void setLabelHistoCands(Histo& hCandidates) hCandidates->GetXaxis()->SetBinLabel(SVFitting::Fail + 1, "Run-time error in secondary vertexing"); } +/// @brief Function to evaluate number of ones in a binary representation of the argument +/// \param num is the input argument +int countOnesInBinary(uint8_t num) +{ + int count = 0; + + for (int iBit = 0; iBit < 8; iBit++) { + count += TESTBIT(num, iBit); + } + + return count; +} + } // namespace o2::hf_trkcandsel #endif // PWGHF_UTILS_UTILSTRKCANDHF_H_ diff --git a/PWGJE/Core/CMakeLists.txt b/PWGJE/Core/CMakeLists.txt index 592e1686ff5..95895ddc442 100644 --- a/PWGJE/Core/CMakeLists.txt +++ b/PWGJE/Core/CMakeLists.txt @@ -14,7 +14,7 @@ o2physics_add_library(PWGJECore SOURCES FastJetUtilities.cxx JetFinder.cxx JetBkgSubUtils.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore FastJet::FastJet FastJet::Contrib) + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore FastJet::FastJet FastJet::Contrib ONNXRuntime::ONNXRuntime) o2physics_target_root_dictionary(PWGJECore HEADERS JetFinder.h diff --git a/PWGJE/Core/FastJetUtilities.cxx b/PWGJE/Core/FastJetUtilities.cxx index 8e678a75130..ba7acabbdf3 100644 --- a/PWGJE/Core/FastJetUtilities.cxx +++ b/PWGJE/Core/FastJetUtilities.cxx @@ -15,7 +15,7 @@ void fastjetutilities::setFastJetUserInfo(std::vector& const { fastjet_user_info* user_info = new fastjet_user_info(status, index); // FIXME: can setting this as a pointer be avoided? constituents.back().set_user_info(user_info); - if (index != -99999999) { // FIXME: needed for constituent subtraction as user_info is not propagated, but need to be quite careful to make sure indices dont overlap between tracks, clusters and HF candidates. Current solution might not be optimal + if (index != -99999999) { // FIXME: in principle needed for constituent subtraction, particularly when clusters are added to the subtraction. However since the HF particle is not subtracted then we dont need to check for it in this manner int i = index; if (status == static_cast(JetConstituentStatus::track)) { i = i + 1; @@ -23,7 +23,7 @@ void fastjetutilities::setFastJetUserInfo(std::vector& const if (status == static_cast(JetConstituentStatus::cluster)) { i = -1 * (i + 1); } - if (status == static_cast(JetConstituentStatus::candidateHF)) { + if (status == static_cast(JetConstituentStatus::candidate)) { i = 0; } constituents.back().set_user_index(i); // FIXME: needed for constituent subtraction, but need to be quite careful to make sure indices dont overlap between tracks, clusters and HF candidates. Current solution might not be optimal diff --git a/PWGJE/Core/FastJetUtilities.h b/PWGJE/Core/FastJetUtilities.h index bce39428c10..e6d4b2b3794 100644 --- a/PWGJE/Core/FastJetUtilities.h +++ b/PWGJE/Core/FastJetUtilities.h @@ -30,7 +30,7 @@ enum class JetConstituentStatus { track = 0, cluster = 1, - candidateHF = 2 + candidate = 2 }; namespace fastjetutilities @@ -85,7 +85,7 @@ void setFastJetUserInfo(std::vector& constituents, int index template void fillTracks(const T& constituent, std::vector& constituents, int index = -99999999, int status = static_cast(JetConstituentStatus::track), float mass = mPion) { - if (status == static_cast(JetConstituentStatus::track) || status == static_cast(JetConstituentStatus::candidateHF)) { + if (status == static_cast(JetConstituentStatus::track) || status == static_cast(JetConstituentStatus::candidate)) { // auto p = std::sqrt((constituent.px() * constituent.px()) + (constituent.py() * constituent.py()) + (constituent.pz() * constituent.pz())); auto energy = std::sqrt((constituent.p() * constituent.p()) + (mass * mass)); constituents.emplace_back(constituent.px(), constituent.py(), constituent.pz(), energy); @@ -103,11 +103,27 @@ void fillTracks(const T& constituent, std::vector& constitue */ template -void fillClusters(const T& constituent, std::vector& constituents, int index = -99999999, int status = static_cast(JetConstituentStatus::cluster)) +void fillClusters(const T& constituent, std::vector& constituents, int index = -99999999, int hadronicCorrectionType = 0, int status = static_cast(JetConstituentStatus::cluster)) { if (status == static_cast(JetConstituentStatus::cluster)) { - double clusterpt = constituent.energy() / std::cosh(constituent.eta()); - constituents.emplace_back(clusterpt * std::cos(constituent.phi()), clusterpt * std::sin(constituent.phi()), clusterpt * std::sinh(constituent.eta()), constituent.energy()); + float constituentEnergy = 0.0; + if (hadronicCorrectionType == 0) { + constituentEnergy = constituent.energy(); + } + if (hadronicCorrectionType == 1) { + constituentEnergy = constituent.energyCorrectedOneTrack1(); + } + if (hadronicCorrectionType == 2) { + constituentEnergy = constituent.energyCorrectedOneTrack2(); + } + if (hadronicCorrectionType == 3) { + constituentEnergy = constituent.energyCorrectedAllTracks1(); + } + if (hadronicCorrectionType == 4) { + constituentEnergy = constituent.energyCorrectedAllTracks2(); + } + float constituentPt = constituentEnergy / std::cosh(constituent.eta()); + constituents.emplace_back(constituentPt * std::cos(constituent.phi()), constituentPt * std::sin(constituent.phi()), constituentPt * std::sinh(constituent.eta()), constituentEnergy); } setFastJetUserInfo(constituents, index, status); } diff --git a/PWGJE/Core/JetBkgSubUtils.cxx b/PWGJE/Core/JetBkgSubUtils.cxx index 336ebf9f67c..281feccc66c 100644 --- a/PWGJE/Core/JetBkgSubUtils.cxx +++ b/PWGJE/Core/JetBkgSubUtils.cxx @@ -159,7 +159,6 @@ fastjet::PseudoJet JetBkgSubUtils::doRhoAreaSub(fastjet::PseudoJet& jet, double std::vector JetBkgSubUtils::doEventConstSub(std::vector& inputParticles, double rhoParam, double rhoMParam) { - JetBkgSubUtils::initialise(); fastjet::contrib::ConstituentSubtractor constituentSub(rhoParam, rhoMParam); constituentSub.set_distance_type(fastjet::contrib::ConstituentSubtractor::deltaR); /// deltaR=sqrt((y_i-y_j)^2+(phi_i-phi_j)^2)), longitudinal Lorentz invariant diff --git a/PWGJE/Core/JetCandidateUtilities.h b/PWGJE/Core/JetCandidateUtilities.h new file mode 100644 index 00000000000..ad7f178b9f0 --- /dev/null +++ b/PWGJE/Core/JetCandidateUtilities.h @@ -0,0 +1,420 @@ +// 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 JetCandidateUtilities.h +/// \brief Jet candidate related utilities +/// +/// \author Nima Zardoshti + +#ifndef PWGJE_CORE_JETCANDIDATEUTILITIES_H_ +#define PWGJE_CORE_JETCANDIDATEUTILITIES_H_ + +#include +#include +#include +#include +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/O2DatabasePDGPlugin.h" + +#include "Framework/Logger.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGJE/DataModel/EMCALClusters.h" + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/DerivedTables.h" + +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetHFUtilities.h" +#include "PWGJE/Core/JetDQUtilities.h" +#include "PWGJE/Core/JetV0Utilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/DataModel/Jet.h" + +namespace jetcandidateutilities +{ + +/** + * returns true if the candidate is from a candidate table + * * @param candidate candidate that is being checked + */ +template +constexpr bool isCandidate() +{ + if constexpr (jethfutilities::isHFCandidate()) { + return true; + } else if constexpr (jetv0utilities::isV0Candidate()) { + return true; + } else if constexpr (jetdqutilities::isDielectronCandidate()) { + return true; + } else { + return false; + } +} + +/** + * returns true if the candidate is from a MC candidate table + * * @param candidate candidate that is being checked + */ +template +constexpr bool isMcCandidate() +{ + if constexpr (jethfutilities::isHFMcCandidate()) { + return true; + } else if constexpr (jetv0utilities::isV0McCandidate()) { + return true; + } else if constexpr (jetdqutilities::isDielectronMcCandidate()) { + return true; + } else { + return false; + } +} + +/** + * returns true if the table type is a candidate table + */ +template +constexpr bool isCandidateTable() +{ + if constexpr (jethfutilities::isHFTable()) { + return true; + } else if constexpr (jetv0utilities::isV0Table()) { + return true; + } else if constexpr (jetdqutilities::isDielectronTable()) { + return true; + } else { + return false; + } +} + +/** + * returns true if the table type is a candidate table + */ +template +constexpr bool isCandidateMcTable() +{ + if constexpr (jethfutilities::isHFMcTable()) { + return true; + } else if constexpr (jetv0utilities::isV0McTable()) { + return true; + } else if constexpr (jetdqutilities::isDielectronMcTable()) { + return true; + } else { + return false; + } +} + +/** + * returns true if the candidate is matched to a reconstructed level candidate with the correct decay + * * @param candidate candidate that is being checked + */ +template +constexpr bool isMatchedCandidate(T const& candidate) +{ + if constexpr (jethfutilities::isHFCandidate() || jethfutilities::isHFMcCandidate()) { + return jethfutilities::isMatchedHFCandidate(candidate); + } else if constexpr (jetdqutilities::isDielectronCandidate() || jetdqutilities::isDielectronMcCandidate()) { + return jetdqutilities::isMatchedDielectronCandidate(candidate); + } else { + return false; + } +} + +/** + * returns true if the track is a daughter of the candidate + * + * @param track track that is being checked + * @param candidate candidate that is being checked + * @param tracks the track table + */ +template +bool isDaughterTrack(T& track, U& candidate, V const& tracks) +{ + if constexpr (jethfutilities::isHFCandidate
()) { + return jethfutilities::isHFDaughterTrack(track, candidate, tracks); + } else if constexpr (jetv0utilities::isV0Candidate()) { + return jetv0utilities::isV0DaughterTrack(track, candidate, tracks); + } else if constexpr (jetdqutilities::isDielectronCandidate()) { + return jetdqutilities::isDielectronDaughterTrack(track, candidate, tracks); + } else { + return false; + } +} + +/** + * returns true if the particle has any daughters with the given global index + * + * @param candidate mother hf particle that is being checked + * @param globalIndex global index of potnetial daughter particle + */ +template +bool isDaughterParticle(const T& particle, int globalIndex) +{ + if (!particle.has_daughters()) { + return false; + } + for (auto daughter : particle.template daughters_as::parent_t>()) { + if (daughter.globalIndex() == globalIndex) { + return true; + } + if (isDaughterParticle(daughter, globalIndex)) { + return true; + } + } + return false; +} + +/** + * returns the index of the JMcParticle matched to the candidate + * + * @param candidate hf candidate that is being checked + * @param tracks track table + * @param particles particle table + */ +template +auto matchedParticleId(const T& candidate, const U& tracks, const V& particles) +{ + if constexpr (jethfutilities::isHFCandidate()) { + return jethfutilities::matchedHFParticleId(candidate, tracks, particles); + } else if constexpr (jetv0utilities::isV0Candidate()) { + return jetv0utilities::matchedV0ParticleId(candidate, tracks, particles); + } else if constexpr (jetdqutilities::isDielectronCandidate()) { + return jetdqutilities::matchedDielectronParticleId(candidate, tracks, particles); + } else { + return -1; + } +} + +/** + * returns the JMcParticle matched to the candidate + * + * @param candidate hf candidate that is being checked + * @param tracks track table + * @param particles particle table + */ +template +auto matchedParticle(const T& candidate, const U& tracks, const V& particles) +{ + if constexpr (jethfutilities::isHFCandidate()) { + return jethfutilities::matchedHFParticle(candidate, tracks, particles); + } else if constexpr (jetv0utilities::isV0Candidate()) { + return jetv0utilities::matchedV0Particle(candidate, tracks, particles); + } else if constexpr (jetdqutilities::isDielectronCandidate()) { + return jetdqutilities::matchedDielectronParticle(candidate, tracks, particles); + } else { + return jethfutilities::matchedHFParticle(candidate, tracks, particles); // this is a dummy output which should never be triggered + } +} + +/** + * returns a slice of the table depending on the index of the candidate + * + * @param candidate candidate that is being checked + * @param table the table to be sliced + */ +template +auto slicedPerCandidate(T const& table, U const& candidate, V const& perD0Candidate, M const& perDplusCandidate, N const& perLcCandidate, O const& perBplusCandidate, P const& perDielectronCandidate) +{ + if constexpr (jethfutilities::isHFCandidate()) { + return jethfutilities::slicedPerHFCandidate(table, candidate, perD0Candidate, perDplusCandidate, perLcCandidate, perBplusCandidate); + } else if constexpr (jetdqutilities::isDielectronCandidate()) { + return jetdqutilities::slicedPerDielectronCandidate(table, candidate, perDielectronCandidate); + } else { + return table; + } +} + +/** + * returns a slice of the table depending on the index of the candidate + * @param CandidateTable candidtae table type + * @param jet jet that the slice is based on + * @param table the table to be sliced + */ +template +auto slicedPerJet(T const& table, U const& jet, V const& perD0Jet, M const& perDplusJet, N const& perLcJet, O const& perBplusJet, P const& perDielectronJet) +{ + if constexpr (jethfutilities::isHFTable() || jethfutilities::isHFMcTable()) { + return jethfutilities::slicedPerHFJet(table, jet, perD0Jet, perDplusJet, perLcJet, perBplusJet); + } else if constexpr (jetdqutilities::isDielectronTable() || jetdqutilities::isDielectronMcTable()) { + return jetdqutilities::slicedPerDielectronJet(table, jet, perDielectronJet); + } else { + return table; + } +} + +/** + * returns the candidate collision Id of candidate based on type of candidate + * + * @param candidate candidate that is being checked + */ +template +int getCandidateCollisionId(T const& candidate) +{ + if constexpr (jethfutilities::isHFCandidate()) { + return jethfutilities::getHFCandidateCollisionId(candidate); + } else if constexpr (jetdqutilities::isDielectronCandidate()) { + return jetdqutilities::getDielectronCandidateCollisionId(candidate); + } else { + return -1; + } +} + +/** + * returns the candidate Mc collision Id of candidate based on type of candidate + * + * @param candidate candidate that is being checked + */ +template +int getMcCandidateCollisionId(T const& candidate) +{ + if constexpr (jethfutilities::isHFMcCandidate()) { + return jethfutilities::getHFMcCandidateCollisionId(candidate); + } else if constexpr (jetdqutilities::isDielectronMcCandidate()) { + return jetdqutilities::getDielectronMcCandidateCollisionId(candidate); + } else { + return -1; + } +} + +/** + * returns the PDG of the candidate based on Table + * + * @param candidate candidate that is being checked + */ + +template +int getCandidatePDG(T const& candidate) +{ + if constexpr (jethfutilities::isHFCandidate() || jethfutilities::isHFMcCandidate()) { + return jethfutilities::getHFCandidatePDG(candidate); + } else if constexpr (jetdqutilities::isDielectronCandidate() || jetdqutilities::isDielectronMcCandidate()) { + return jetdqutilities::getDielectronCandidatePDG(candidate); + } else { + return 0; + } +} + +/** + * returns the PDG of the candidates in the table type + */ +template +int getTablePDG() +{ + if constexpr (jethfutilities::isHFTable() || jethfutilities::isHFMcTable()) { + return jethfutilities::getHFTablePDG(); + } else if constexpr (jetdqutilities::isDielectronTable() || jetdqutilities::isDielectronMcTable()) { + return jetdqutilities::getDielectronTablePDG(); + } else { + return 0; + } +} + +/** + * returns the pdg mass of the candidate based on Table + * + * @param candidate candidate that is being checked + */ +template +float getCandidatePDGMass(T const& candidate) +{ + if constexpr (jethfutilities::isHFCandidate() || jethfutilities::isHFMcCandidate()) { + return jethfutilities::getHFCandidatePDGMass(candidate); + } else if constexpr (jetdqutilities::isDielectronCandidate() || jetdqutilities::isDielectronMcCandidate()) { + return jetdqutilities::getDielectronCandidatePDGMass(candidate); + } else { + return -1.0; + } +} + +/** + * returns the pdg mass of the candidates in the table type + * + */ +template +float getTablePDGMass() +{ + if constexpr (jethfutilities::isHFTable() || jethfutilities::isHFMcTable()) { + return jethfutilities::getHFTablePDGMass(); + } else if constexpr (jetdqutilities::isDielectronTable() || jetdqutilities::isDielectronMcTable()) { + return jetdqutilities::getDielectronTablePDGMass(); + } else { + return -1.0; + } +} + +/** + * returns the invariant mass of the candidate based on Table + * + * @param candidate candidate that is being checked + */ +template +float getCandidateInvariantMass(T const& candidate) +{ + if constexpr (jethfutilities::isHFCandidate()) { + return jethfutilities::getHFCandidateInvariantMass(candidate); + } else if constexpr (jetdqutilities::isDielectronCandidate()) { + return jetdqutilities::getDielectronCandidateInvariantMass(candidate); + } else { + return -1.0; + } +} + +template +void fillCandidateCollisionTable(T const& collision, U const& /*candidates*/, V& CandiateCollisionTable) +{ + if constexpr (jethfutilities::isHFTable()) { + jethfutilities::fillHFCollisionTable(collision, CandiateCollisionTable); + } else if constexpr (jetdqutilities::isDielectronTable()) { + jetdqutilities::fillDielectronCollisionTable(collision, CandiateCollisionTable); // if more dilepton tables are added we would need a fillDQCollisionTable + } +} + +template +void fillCandidateMcCollisionTable(T const& mcCollision, U const& /*candidates*/, V& CandiateMcCollisionTable) +{ + if constexpr (jethfutilities::isHFMcTable()) { + jethfutilities::fillHFMcCollisionTable(mcCollision, CandiateMcCollisionTable); + } else if constexpr (jetdqutilities::isDielectronMcTable()) { + jetdqutilities::fillDielectronMcCollisionTable(mcCollision, CandiateMcCollisionTable); + } +} + +template +void fillCandidateTable(T const& candidate, int32_t collisionIndex, U& BaseTable, V& HFParTable, M& HFParETable, N& HFParDaughterTable, O& HFSelectionFlagTable, P& HFMlTable, Q& HFMlDaughterTable, S& HFMCDTable) +{ + if constexpr (jethfutilities::isHFCandidate()) { + jethfutilities::fillHFCandidateTable(candidate, collisionIndex, BaseTable, HFParTable, HFParETable, HFParDaughterTable, HFSelectionFlagTable, HFMlTable, HFMlDaughterTable, HFMCDTable); + } else if constexpr (jetdqutilities::isDielectronCandidate()) { + jetdqutilities::fillDielectronCandidateTable(candidate, collisionIndex, BaseTable); + } +} + +template +void fillCandidateMcTable(T const& candidate, int32_t mcCollisionIndex, U& BaseMcTable) +{ + if constexpr (jethfutilities::isHFMcCandidate()) { + jethfutilities::fillHFCandidateMcTable(candidate, mcCollisionIndex, BaseMcTable); + } else if constexpr (jetdqutilities::isDielectronMcCandidate()) { + jetdqutilities::fillDielectronCandidateMcTable(candidate, mcCollisionIndex, BaseMcTable); + } +} + +}; // namespace jetcandidateutilities + +#endif // PWGJE_CORE_JETCANDIDATEUTILITIES_H_ diff --git a/PWGJE/Core/JetDQUtilities.h b/PWGJE/Core/JetDQUtilities.h new file mode 100644 index 00000000000..c5fb2117e81 --- /dev/null +++ b/PWGJE/Core/JetDQUtilities.h @@ -0,0 +1,340 @@ +// 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 JetDQUtilities.h +/// \brief Jet DQ related utilities +/// +/// \author Nima Zardoshti + +#ifndef PWGJE_CORE_JETDQUTILITIES_H_ +#define PWGJE_CORE_JETDQUTILITIES_H_ + +#include +#include +#include +#include + +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/O2DatabasePDGPlugin.h" + +#include "Framework/Logger.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/DataModel/Jet.h" + +namespace jetdqutilities +{ + +/** + * returns true if the candidate is from a Dielectron table + */ +template +constexpr bool isDielectronCandidate() +{ + return std::is_same_v, o2::aod::CandidatesDielectronData::iterator> || std::is_same_v, o2::aod::CandidatesDielectronData::filtered_iterator> || std::is_same_v, o2::aod::CandidatesDielectronMCD::iterator> || std::is_same_v, o2::aod::CandidatesDielectronMCD::filtered_iterator>; +} + +/** + * returns true if the candidate is from a MC Dielectron table + */ +template +constexpr bool isDielectronMcCandidate() +{ + return std::is_same_v, o2::aod::CandidatesDielectronMCP::iterator> || std::is_same_v, o2::aod::CandidatesDielectronMCP::filtered_iterator>; +} + +/** + * returns true if the table is a Dielectron table + */ +template +constexpr bool isDielectronTable() +{ + return isDielectronCandidate() || isDielectronCandidate(); +} + +/** + * returns true if the table is a Dielectron MC table + */ +template +constexpr bool isDielectronMcTable() +{ + return isDielectronMcCandidate() || isDielectronMcCandidate(); +} + +/** + * returns true if the candidate is matched to a reconstructed level candidate with the correct decay + * * @param candidate candidate that is being checked + */ +template +constexpr bool isMatchedDielectronCandidate(T const& /*candidate*/) +{ + if constexpr (isDielectronCandidate()) { + // For now the decision to select signals is done in the DQ framework + return true; + } else if constexpr (isDielectronMcCandidate()) { + return true; // this is true because we always only select Jpsi in our decay channel. If more channels are added this needs to be expanded + } else { + return false; + } +} + +/** + * returns true if the track is a daughter of the dielectron candidate + * + * @param track track that is being checked + * @param candidate Dielectron candidate that is being checked + * @param tracks the track table + */ +template +bool isDielectronDaughterTrack(T& track, U& candidate, V const& /*tracks*/) +{ + if constexpr (isDielectronCandidate()) { + if (candidate.prong0Id() == track.globalIndex() || candidate.prong1Id() == track.globalIndex()) { + return true; + } else { + return false; + } + } else { + return false; + } +} + +/** + * returns the index of the JMcParticle matched to the Dielectron candidate + * + * @param candidate dielectron candidate that is being checked + * @param tracks track table + * @param particles particle table + */ +template +auto matchedDielectronParticleId(const T& candidate, const U& /*tracks*/, const V& /*particles*/) +{ + const auto candidateDaughterParticle = candidate.template prong1_as().template mcParticle_as(); + return candidateDaughterParticle.template mothers_first_as().globalIndex(); // can we get the Id directly? +} + +/** + * returns the JMcParticle matched to the Dielectron candidate + * + * @param candidate dielectron candidate that is being checked + * @param tracks track table + * @param particles particle table + */ +template +auto matchedDielectronParticle(const T& candidate, const U& /*tracks*/, const V& /*particles*/) +{ + const auto candidateDaughterParticle = candidate.template prong1_as().template mcParticle_as(); + return candidateDaughterParticle.template mothers_first_as(); +} + +/** + * returns a slice of the table depending on the index of the Dielectron candidate + * + * @param candidate dielectron candidate that is being checked + * @param table the table to be sliced + */ +template +auto slicedPerDielectronCandidate(T const& table, U const& candidate, V const& perDielectronCandidate) +{ + if constexpr (isDielectronCandidate()) { + return table.sliceBy(perDielectronCandidate, candidate.globalIndex()); + } else { + return table; + } +} + +/** + * returns a slice of the table depending on the index of the Dielectron jet + * @param DielectronTable dielectron table type + * @param jet jet that the slice is based on + * @param table the table to be sliced + */ +template +auto slicedPerDielectronJet(T const& table, U const& jet, V const& perDielectronJet) +{ + if constexpr (isDielectronTable() || isDielectronMcTable()) { + return table.sliceBy(perDielectronJet, jet.globalIndex()); + } else { + return table; + } +} + +/** + * returns the Dielectron collision Id of candidate based on type of Dielectron candidate + * + * @param candidate dielectron candidate that is being checked + */ +template +int getDielectronCandidateCollisionId(T const& candidate) +{ + return candidate.reducedeventId(); +} + +/** + * returns the Dielectron Mc collision Id of candidate based on type of Dielectron candidate + * + * @param candidate dielectron candidate that is being checked + */ +template +int getDielectronMcCandidateCollisionId(T const& candidate) +{ + if constexpr (isDielectronMcCandidate()) { + return candidate.dielectronmccollisionId(); + } else { + return -1; + } +} + +/** + * returns the PDG of the candidate based on Dielectron Table + * + * @param candidate dielectron candidate that is being checked + */ +template +int getDielectronCandidatePDG(T const& /*candidate*/) +{ + if constexpr (isDielectronCandidate() || isDielectronMcCandidate()) { + return static_cast(o2::constants::physics::Pdg::kJPsi); + } else { + return 0; + } +} + +/** + * returns the PDG of the candidates in the table type + */ +template +int getDielectronTablePDG() +{ + if constexpr (isDielectronTable() || isDielectronMcTable()) { + return static_cast(o2::constants::physics::Pdg::kJPsi); + } else { + return 0; + } +} + +/** + * returns the mass of the candidate based on Dielectron Table + * + * @param candidate dielectron candidate that is being checked + */ +template +float getDielectronCandidatePDGMass(T const& /*candidate*/) +{ + if constexpr (isDielectronCandidate() || isDielectronMcCandidate()) { + return static_cast(o2::constants::physics::MassJPsi); + } else { + return -1.0; + } +} + +/** + * returns the mass of the candidates in the table type + * + */ +template +float getDielectronTablePDGMass() +{ + if constexpr (isDielectronTable() || isDielectronMcTable()) { + return static_cast(o2::constants::physics::MassJPsi); + } else { + return -1.0; + } +} + +/** + * returns the mass of the candidate based on Dielectron Table + * + * @param candidate dielectron candidate that is being checked + */ +template +float getDielectronCandidateInvariantMass(T const& candidate) +{ + return candidate.mass(); +} + +template +bool isDielectronParticle(T const& particles, U const& particle) +{ + return RecoDecay::isMatchedMCGen(particles, particle, o2::constants::physics::Pdg::kJPsi, std::array{+kElectron, -kElectron}, true); +} + +enum JDielectronParticleDecays { + JPsiToEE = 0, +}; + +template +bool selectDielectronParticleDecay(T const& dielectronParticle, int dielectronParticleDecaySelection = -1) +{ + if (dielectronParticleDecaySelection == -1) { + return true; + } + return (dielectronParticle.decayFlag() & (1 << dielectronParticleDecaySelection)); +} + +int initialiseDielectronParticleDecaySelection(std::string dielectronParticleDecaySelection) +{ + if (dielectronParticleDecaySelection == "JPsiToEE") { + return JDielectronParticleDecays::JPsiToEE; + } + return -1; +} + +template +uint8_t setDielectronParticleDecayBit(T const& particles, U const& particle) +{ + uint8_t bit = 0; + if (RecoDecay::isMatchedMCGen(particles, particle, o2::constants::physics::Pdg::kJPsi, std::array{+kElectron, -kElectron}, true)) { + SETBIT(bit, JDielectronParticleDecays::JPsiToEE); + } + return bit; +} + +template +void fillDielectronCollisionTable(T const& collision, U& DielectronCollisionTable) +{ + DielectronCollisionTable(collision.tag_raw(), collision.runNumber(), collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), collision.collisionTime(), collision.collisionTimeRes()); +} + +template +void fillDielectronMcCollisionTable(T const& mcCollision, U& DielectronMcCollisionTable) +{ + DielectronMcCollisionTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ()); +} + +template +void fillDielectronCandidateTable(T const& candidate, int32_t collisionIndex, U& DielectronTable) +{ + DielectronTable(collisionIndex, candidate.mass(), candidate.pt(), candidate.eta(), candidate.phi(), candidate.sign(), candidate.filterMap_raw(), candidate.mcDecision()); +} + +template +void fillDielectronCandidateMcTable(T const& candidate, int32_t mcCollisionIndex, U& DielectronMcTable) +{ + DielectronMcTable(mcCollisionIndex, candidate.pt(), candidate.eta(), candidate.phi(), candidate.y(), candidate.e(), candidate.m(), candidate.pdgCode(), candidate.getGenStatusCode(), candidate.getHepMCStatusCode(), candidate.isPhysicalPrimary(), candidate.decayFlag(), candidate.origin()); +} + +}; // namespace jetdqutilities + +#endif // PWGJE_CORE_JETDQUTILITIES_H_ diff --git a/PWGJE/Core/JetDerivedDataUtilities.h b/PWGJE/Core/JetDerivedDataUtilities.h index 0e6e1e9e5ec..b526dc53fc1 100644 --- a/PWGJE/Core/JetDerivedDataUtilities.h +++ b/PWGJE/Core/JetDerivedDataUtilities.h @@ -17,6 +17,7 @@ #ifndef PWGJE_CORE_JETDERIVEDDATAUTILITIES_H_ #define PWGJE_CORE_JETDERIVEDDATAUTILITIES_H_ +#include #include #include "Common/CCDB/TriggerAliases.h" #include "Common/CCDB/EventSelectionParams.h" @@ -28,45 +29,153 @@ static constexpr float mPion = 0.139; // TDatabasePDG::Instance()->GetParticle(2 enum JCollisionSel { sel8 = 0, - sel8Full = 1, - sel7 = 2 + sel7 = 1, + selKINT7 = 2, + selTVX = 3, + selNoTimeFrameBorder = 4, + selNoITSROFrameBorder = 5, + selNoSameBunchPileup = 6, + selIsGoodZvtxFT0vsPV = 7, + selNoCollInTimeRangeStandard = 8, + selNoCollInRofStandard = 9 +}; + +enum JCollisionSubGeneratorId { + none = -1, + mbGap = 0 }; template -bool selectCollision(T const& collision, int eventSelection = -1) +bool selectCollision(T const& collision, std::vector eventSelectionMaskBits, bool skipMBGapEvents = true) { - if (eventSelection == -1) { + if (skipMBGapEvents && collision.subGeneratorId() == JCollisionSubGeneratorId::mbGap) { + return false; + } + if (eventSelectionMaskBits.size() == 0) { return true; } - return (collision.eventSel() & (1 << eventSelection)); + for (auto eventSelectionMaskBit : eventSelectionMaskBits) { + if (!(collision.eventSel() & (1 << eventSelectionMaskBit))) { + return false; + } + } + return true; +} + +bool eventSelectionMasksContainSelection(std::string eventSelectionMasks, std::string selection) +{ + size_t position = 0; + while ((position = eventSelectionMasks.find(selection, position)) != std::string::npos) { + bool validStart = (position == 0 || eventSelectionMasks[position - 1] == '+'); + bool validEnd = (position + selection.length() == eventSelectionMasks.length() || eventSelectionMasks[position + selection.length()] == '+'); + if (validStart && validEnd) { + return true; + } + position += selection.length(); + } + return false; } -int initialiseEventSelection(std::string eventSelection) +std::vector initialiseEventSelectionBits(std::string eventSelectionMasks) { - if (eventSelection == "sel8") { - return JCollisionSel::sel8; + std::vector eventSelectionMaskBits; + if (eventSelectionMasksContainSelection(eventSelectionMasks, "sel8")) { + eventSelectionMaskBits.push_back(JCollisionSel::sel8); } - if (eventSelection == "sel8Full") { - return JCollisionSel::sel8Full; + if (eventSelectionMasksContainSelection(eventSelectionMasks, "sel7")) { + eventSelectionMaskBits.push_back(JCollisionSel::sel7); } - if (eventSelection == "sel7") { - return JCollisionSel::sel7; + if (eventSelectionMasksContainSelection(eventSelectionMasks, "selKINT7")) { + eventSelectionMaskBits.push_back(JCollisionSel::selKINT7); } - return -1; + if (eventSelectionMasksContainSelection(eventSelectionMasks, "TVX")) { + eventSelectionMaskBits.push_back(JCollisionSel::selTVX); + } + if (eventSelectionMasksContainSelection(eventSelectionMasks, "NoTimeFrameBorder")) { + eventSelectionMaskBits.push_back(JCollisionSel::selNoTimeFrameBorder); + } + if (eventSelectionMasksContainSelection(eventSelectionMasks, "NoITSROFrameBorder")) { + eventSelectionMaskBits.push_back(JCollisionSel::selNoITSROFrameBorder); + } + if (eventSelectionMasksContainSelection(eventSelectionMasks, "NoSameBunchPileup")) { + eventSelectionMaskBits.push_back(JCollisionSel::selNoSameBunchPileup); + } + if (eventSelectionMasksContainSelection(eventSelectionMasks, "IsGoodZvtxFT0vsPV")) { + eventSelectionMaskBits.push_back(JCollisionSel::selIsGoodZvtxFT0vsPV); + } + if (eventSelectionMasksContainSelection(eventSelectionMasks, "NoCollInTimeRangeStandard")) { + eventSelectionMaskBits.push_back(JCollisionSel::selNoCollInTimeRangeStandard); + } + if (eventSelectionMasksContainSelection(eventSelectionMasks, "NoCollInRofStandard")) { + eventSelectionMaskBits.push_back(JCollisionSel::selNoCollInRofStandard); + } + + if (eventSelectionMasksContainSelection(eventSelectionMasks, "sel8Full")) { + eventSelectionMaskBits.push_back(JCollisionSel::sel8); + eventSelectionMaskBits.push_back(JCollisionSel::selNoSameBunchPileup); + } + if (eventSelectionMasksContainSelection(eventSelectionMasks, "sel8FullPbPb")) { + eventSelectionMaskBits.push_back(JCollisionSel::sel8); + eventSelectionMaskBits.push_back(JCollisionSel::selNoCollInTimeRangeStandard); + eventSelectionMaskBits.push_back(JCollisionSel::selNoCollInRofStandard); + } + if (eventSelectionMasksContainSelection(eventSelectionMasks, "selUnanchoredMC")) { + eventSelectionMaskBits.push_back(JCollisionSel::selTVX); + } + if (eventSelectionMasksContainSelection(eventSelectionMasks, "selMC")) { + eventSelectionMaskBits.push_back(JCollisionSel::selTVX); + eventSelectionMaskBits.push_back(JCollisionSel::selNoTimeFrameBorder); + } + if (eventSelectionMasksContainSelection(eventSelectionMasks, "selMCFull")) { + eventSelectionMaskBits.push_back(JCollisionSel::selTVX); + eventSelectionMaskBits.push_back(JCollisionSel::selNoTimeFrameBorder); + eventSelectionMaskBits.push_back(JCollisionSel::selNoSameBunchPileup); + } + if (eventSelectionMasksContainSelection(eventSelectionMasks, "selMCFullPbPb")) { + eventSelectionMaskBits.push_back(JCollisionSel::selTVX); + eventSelectionMaskBits.push_back(JCollisionSel::selNoCollInTimeRangeStandard); + eventSelectionMaskBits.push_back(JCollisionSel::selNoCollInRofStandard); + } + if (eventSelectionMasksContainSelection(eventSelectionMasks, "sel7KINT7")) { + eventSelectionMaskBits.push_back(JCollisionSel::sel7); + eventSelectionMaskBits.push_back(JCollisionSel::selKINT7); + } + return eventSelectionMaskBits; } template -uint8_t setEventSelectionBit(T const& collision) +uint16_t setEventSelectionBit(T const& collision) { - uint8_t bit = 0; + uint16_t bit = 0; if (collision.sel8()) { SETBIT(bit, JCollisionSel::sel8); - if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup) && collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { - SETBIT(bit, JCollisionSel::sel8Full); - } } if (collision.sel7()) { SETBIT(bit, JCollisionSel::sel7); + } + if (collision.alias_bit(kINT7)) { + SETBIT(bit, JCollisionSel::selKINT7); + } + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + SETBIT(bit, JCollisionSel::selTVX); + } + if (collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + SETBIT(bit, JCollisionSel::selNoTimeFrameBorder); + } + if (collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + SETBIT(bit, JCollisionSel::selNoITSROFrameBorder); + } + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + SETBIT(bit, JCollisionSel::selNoSameBunchPileup); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + SETBIT(bit, JCollisionSel::selIsGoodZvtxFT0vsPV); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + SETBIT(bit, JCollisionSel::selNoCollInTimeRangeStandard); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + SETBIT(bit, JCollisionSel::selNoCollInRofStandard); } return bit; } @@ -86,10 +195,154 @@ bool eventEMCAL(T const& collision) return found; } +inline const std::string JTriggerMasks = "fJetChLowPt,fJetChHighPt,fTrackLowPt,fTrackHighPt,fJetD0ChLowPt,fJetD0ChHighPt,fJetLcChLowPt,fJetLcChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt,fJetNeutralHighPt,fJetNeutralLowPt,fGammaVeryHighPtEMCAL,fGammaVeryHighPtDCAL,fGammaHighPtEMCAL,fGammaHighPtDCAL,fGammaLowPtEMCAL,fGammaLowPtDCAL,fGammaVeryLowPtEMCAL,fGammaVeryLowPtDCAL"; + +enum JTrigSel { + noTrigSel = 0, + JetChLowPt = 1, + JetChHighPt = 2, + TrackLowPt = 3, + TrackHighPt = 4, + JetD0ChLowPt = 5, + JetD0ChHighPt = 6, + JetLcChLowPt = 7, + JetLcChHighPt = 8, + EMCALReadout = 9, + JetFullHighPt = 10, + JetFullLowPt = 11, + JetNeutralHighPt = 12, + JetNeutralLowPt = 13, + GammaVeryHighPtEMCAL = 14, + GammaVeryHighPtDCAL = 15, + GammaHighPtEMCAL = 16, + GammaHighPtDCAL = 17, + GammaLowPtEMCAL = 18, + GammaLowPtDCAL = 19, + GammaVeryLowPtEMCAL = 20, + GammaVeryLowPtDCAL = 21 +}; + +template +bool selectTrigger(T const& collision, std::vector triggerMaskBits) +{ + if (triggerMaskBits.size() == 0) { + return true; + } + for (auto triggerMaskBit : triggerMaskBits) { + if (collision.triggerSel() & (1 << triggerMaskBit)) { + return true; + } + } + return false; +} + +template +bool selectTrigger(T const& collision, int triggerMaskBit) +{ + if (triggerMaskBit == -1) { + return false; + } + return collision.triggerSel() & (1 << triggerMaskBit); +} + +bool triggerMasksContainTrigger(std::string triggerMasks, std::string trigger) +{ + size_t position = 0; + while ((position = triggerMasks.find(trigger, position)) != std::string::npos) { + bool validStart = (position == 0 || triggerMasks[position - 1] == ','); + bool validEnd = (position + trigger.length() == triggerMasks.length() || triggerMasks[position + trigger.length()] == ','); + if (validStart && validEnd) { + return true; + } + position += trigger.length(); + } + return false; +} + +std::vector initialiseTriggerMaskBits(std::string triggerMasks) +{ + std::vector triggerMaskBits; + if (triggerMasksContainTrigger(triggerMasks, "fJetChLowPt")) { + triggerMaskBits.push_back(JTrigSel::JetChLowPt); + } + if (triggerMasksContainTrigger(triggerMasks, "fJetChHighPt")) { + triggerMaskBits.push_back(JTrigSel::JetChHighPt); + } + if (triggerMasksContainTrigger(triggerMasks, "fTrackLowPt")) { + triggerMaskBits.push_back(JTrigSel::TrackLowPt); + } + if (triggerMasksContainTrigger(triggerMasks, "fTrackHighPt")) { + triggerMaskBits.push_back(JTrigSel::TrackHighPt); + } + if (triggerMasksContainTrigger(triggerMasks, "fJetD0ChLowPt")) { + triggerMaskBits.push_back(JTrigSel::JetD0ChLowPt); + } + if (triggerMasksContainTrigger(triggerMasks, "fJetD0ChHighPt")) { + triggerMaskBits.push_back(JTrigSel::JetD0ChHighPt); + } + if (triggerMasksContainTrigger(triggerMasks, "fJetLcChLowPt")) { + triggerMaskBits.push_back(JTrigSel::JetLcChLowPt); + } + if (triggerMasksContainTrigger(triggerMasks, "fJetLcChHighPt")) { + triggerMaskBits.push_back(JTrigSel::JetLcChHighPt); + } + if (triggerMasksContainTrigger(triggerMasks, "fEMCALReadout")) { + triggerMaskBits.push_back(JTrigSel::EMCALReadout); + } + if (triggerMasksContainTrigger(triggerMasks, "fJetFullHighPt")) { + triggerMaskBits.push_back(JTrigSel::JetFullHighPt); + } + if (triggerMasksContainTrigger(triggerMasks, "fJetFullLowPt")) { + triggerMaskBits.push_back(JTrigSel::JetFullLowPt); + } + if (triggerMasksContainTrigger(triggerMasks, "fJetNeutralHighPt")) { + triggerMaskBits.push_back(JTrigSel::JetNeutralHighPt); + } + if (triggerMasksContainTrigger(triggerMasks, "fJetNeutralLowPt")) { + triggerMaskBits.push_back(JTrigSel::JetNeutralLowPt); + } + if (triggerMasksContainTrigger(triggerMasks, "fGammaVeryHighPtEMCAL")) { + triggerMaskBits.push_back(JTrigSel::GammaVeryHighPtEMCAL); + } + if (triggerMasksContainTrigger(triggerMasks, "fGammaVeryHighPtDCAL")) { + triggerMaskBits.push_back(JTrigSel::GammaVeryHighPtDCAL); + } + if (triggerMasksContainTrigger(triggerMasks, "fGammaHighPtEMCAL")) { + triggerMaskBits.push_back(JTrigSel::GammaHighPtEMCAL); + } + if (triggerMasksContainTrigger(triggerMasks, "fGammaHighPtDCAL")) { + triggerMaskBits.push_back(JTrigSel::GammaHighPtDCAL); + } + if (triggerMasksContainTrigger(triggerMasks, "fGammaLowPtEMCAL")) { + triggerMaskBits.push_back(JTrigSel::GammaLowPtEMCAL); + } + if (triggerMasksContainTrigger(triggerMasks, "fGammaLowPtDCAL")) { + triggerMaskBits.push_back(JTrigSel::GammaLowPtDCAL); + } + if (triggerMasksContainTrigger(triggerMasks, "fGammaVeryLowPtEMCAL")) { + triggerMaskBits.push_back(JTrigSel::GammaVeryLowPtEMCAL); + } + if (triggerMasksContainTrigger(triggerMasks, "fGammaVeryLowPtDCAL")) { + triggerMaskBits.push_back(JTrigSel::GammaVeryLowPtDCAL); + } + return triggerMaskBits; +} + +uint64_t setTriggerSelectionBit(std::vector triggerDecisions) +{ + uint64_t bit = 0; + for (std::vector::size_type i = 0; i < triggerDecisions.size(); i++) { + if (triggerDecisions[i]) { + SETBIT(bit, i + 1); + } + } + return bit; +} + enum JTrigSelCh { noChargedTigger = 0, - chargedLow = 1, - chargedHigh = 2, + jetChLowPt = 1, + jetChHighPt = 2, trackLowPt = 3, trackHighPt = 4 }; @@ -105,11 +358,11 @@ bool selectChargedTrigger(T const& collision, int triggerSelection) int initialiseChargedTriggerSelection(std::string triggerSelection) { - if (triggerSelection == "chargedLow") { - return JTrigSelCh::chargedLow; + if (triggerSelection == "jetChLowPt") { + return JTrigSelCh::jetChLowPt; } - if (triggerSelection == "chargedHigh") { - return JTrigSelCh::chargedHigh; + if (triggerSelection == "jetChHighPt") { + return JTrigSelCh::jetChHighPt; } if (triggerSelection == "trackLowPt") { return JTrigSelCh::trackLowPt; @@ -127,10 +380,10 @@ uint8_t setChargedTriggerSelectionBit(T const& collision) uint8_t bit = 0; if (collision.hasJetChLowPt()) { - SETBIT(bit, JTrigSelCh::chargedLow); + SETBIT(bit, JTrigSelCh::jetChLowPt); } if (collision.hasJetChHighPt()) { - SETBIT(bit, JTrigSelCh::chargedHigh); + SETBIT(bit, JTrigSelCh::jetChHighPt); } if (collision.hasTrackLowPt()) { SETBIT(bit, JTrigSelCh::trackLowPt); @@ -144,18 +397,19 @@ uint8_t setChargedTriggerSelectionBit(T const& collision) enum JTrigSelFull { noFullTrigger = 0, - fullHigh = 1, - fullLow = 2, - neutralHigh = 3, - neutralLow = 4, - gammaVeryHighEMCAL = 5, - gammaHighEMCAL = 6, - gammaLowEMCAL = 7, - gammaVeryLowEMCAL = 8, - gammaVeryHighDCAL = 9, - gammaHighDCAL = 10, - gammaLowDCAL = 11, - gammaVeryLowDCAL = 12 + emcalReadout = 1, + jetFullHighPt = 2, + jetFullLowPt = 3, + jetNeutralHighPt = 4, + jetNeutralLowPt = 5, + gammaVeryHighPtEMCAL = 6, + gammaVeryHighPtDCAL = 7, + gammaHighPtEMCAL = 8, + gammaHighPtDCAL = 9, + gammaLowPtEMCAL = 10, + gammaLowPtDCAL = 11, + gammaVeryLowPtEMCAL = 12, + gammaVeryLowPtDCAL = 13 }; template @@ -169,30 +423,32 @@ bool selectFullTrigger(T const& collision, int triggerSelection) int initialiseFullTriggerSelection(std::string triggerSelection) { - if (triggerSelection == "fullHigh") { - return JTrigSelFull::fullHigh; - } else if (triggerSelection == "fullLow") { - return JTrigSelFull::fullLow; - } else if (triggerSelection == "neutralHigh") { - return JTrigSelFull::neutralHigh; - } else if (triggerSelection == "neutralLow") { - return JTrigSelFull::neutralLow; - } else if (triggerSelection == "gammaVeryHighEMCAL") { - return JTrigSelFull::gammaVeryHighEMCAL; - } else if (triggerSelection == "gammaHighEMCAL") { - return JTrigSelFull::gammaHighEMCAL; - } else if (triggerSelection == "gammaLowEMCAL") { - return JTrigSelFull::gammaLowEMCAL; - } else if (triggerSelection == "gammaVeryLowEMCAL") { - return JTrigSelFull::gammaVeryLowEMCAL; - } else if (triggerSelection == "gammaVeryHighDCAL") { - return JTrigSelFull::gammaVeryHighDCAL; - } else if (triggerSelection == "gammaHighDCAL") { - return JTrigSelFull::gammaHighDCAL; - } else if (triggerSelection == "gammaLowDCAL") { - return JTrigSelFull::gammaLowDCAL; - } else if (triggerSelection == "gammaVeryLowDCAL") { - return JTrigSelFull::gammaVeryLowDCAL; + if (triggerSelection == "emcalReadout") { + return JTrigSelFull::emcalReadout; + } else if (triggerSelection == "jetFullHighPt") { + return JTrigSelFull::jetFullHighPt; + } else if (triggerSelection == "jetFullLowPt") { + return JTrigSelFull::jetFullLowPt; + } else if (triggerSelection == "jetNeutralHighPt") { + return JTrigSelFull::jetNeutralHighPt; + } else if (triggerSelection == "jetNeutralLowPt") { + return JTrigSelFull::jetNeutralLowPt; + } else if (triggerSelection == "gammaVeryHighPtEMCAL") { + return JTrigSelFull::gammaVeryHighPtEMCAL; + } else if (triggerSelection == "gammaVeryHighPtDCAL") { + return JTrigSelFull::gammaVeryHighPtDCAL; + } else if (triggerSelection == "gammaHighPtEMCAL") { + return JTrigSelFull::gammaHighPtEMCAL; + } else if (triggerSelection == "gammaHighPtDCAL") { + return JTrigSelFull::gammaHighPtDCAL; + } else if (triggerSelection == "gammaLowPtEMCAL") { + return JTrigSelFull::gammaLowPtEMCAL; + } else if (triggerSelection == "gammaLowPtDCAL") { + return JTrigSelFull::gammaLowPtDCAL; + } else if (triggerSelection == "gammaVeryLowPtEMCAL") { + return JTrigSelFull::gammaVeryLowPtEMCAL; + } else if (triggerSelection == "gammaVeryLowPtDCAL") { + return JTrigSelFull::gammaVeryLowPtDCAL; } return -1; } @@ -201,51 +457,54 @@ template uint32_t setFullTriggerSelectionBit(T const& collision) { uint32_t bit = 0; + if (collision.hasEMCALinReadout()) { + SETBIT(bit, JTrigSelFull::emcalReadout); + } if (collision.hasJetFullHighPt()) { - SETBIT(bit, JTrigSelFull::fullHigh); + SETBIT(bit, JTrigSelFull::jetFullHighPt); } if (collision.hasJetFullLowPt()) { - SETBIT(bit, JTrigSelFull::fullLow); + SETBIT(bit, JTrigSelFull::jetFullLowPt); } if (collision.hasJetNeutralHighPt()) { - SETBIT(bit, JTrigSelFull::neutralHigh); + SETBIT(bit, JTrigSelFull::jetNeutralHighPt); } if (collision.hasJetNeutralLowPt()) { - SETBIT(bit, JTrigSelFull::neutralLow); + SETBIT(bit, JTrigSelFull::jetNeutralLowPt); } if (collision.hasGammaVeryHighPtEMCAL()) { - SETBIT(bit, JTrigSelFull::gammaVeryHighEMCAL); - } - if (collision.hasGammaHighPtEMCAL()) { - SETBIT(bit, JTrigSelFull::gammaHighEMCAL); - } - if (collision.hasGammaLowPtEMCAL()) { - SETBIT(bit, JTrigSelFull::gammaLowEMCAL); - } - if (collision.hasGammaVeryLowPtEMCAL()) { - SETBIT(bit, JTrigSelFull::gammaVeryLowEMCAL); + SETBIT(bit, JTrigSelFull::gammaVeryHighPtEMCAL); } if (collision.hasGammaVeryHighPtDCAL()) { - SETBIT(bit, JTrigSelFull::gammaVeryHighDCAL); + SETBIT(bit, JTrigSelFull::gammaVeryHighPtDCAL); + } + if (collision.hasGammaHighPtEMCAL()) { + SETBIT(bit, JTrigSelFull::gammaHighPtEMCAL); } if (collision.hasGammaHighPtDCAL()) { - SETBIT(bit, JTrigSelFull::gammaHighDCAL); + SETBIT(bit, JTrigSelFull::gammaHighPtDCAL); + } + if (collision.hasGammaLowPtEMCAL()) { + SETBIT(bit, JTrigSelFull::gammaLowPtEMCAL); } if (collision.hasGammaLowPtDCAL()) { - SETBIT(bit, JTrigSelFull::gammaLowDCAL); + SETBIT(bit, JTrigSelFull::gammaLowPtDCAL); + } + if (collision.hasGammaVeryLowPtEMCAL()) { + SETBIT(bit, JTrigSelFull::gammaVeryLowPtEMCAL); } if (collision.hasGammaVeryLowPtDCAL()) { - SETBIT(bit, JTrigSelFull::gammaVeryLowDCAL); + SETBIT(bit, JTrigSelFull::gammaVeryLowPtDCAL); } return bit; } enum JTrigSelChHF { noChargedHFTigger = 0, - chargedD0Low = 1, - chargedD0High = 2, - chargedLcLow = 3, - chargedLcHigh = 4 + jetD0ChLowPt = 1, + jetD0ChHighPt = 2, + jetLcChLowPt = 3, + jetLcChHighPt = 4 }; template @@ -259,17 +518,17 @@ bool selectChargedHFTrigger(T const& collision, int triggerSelection) int initialiseChargedHFTriggerSelection(std::string triggerSelection) { - if (triggerSelection == "chargedD0Low") { - return JTrigSelChHF::chargedD0Low; + if (triggerSelection == "jetD0ChLowPt") { + return JTrigSelChHF::jetD0ChLowPt; } - if (triggerSelection == "chargedD0High") { - return JTrigSelChHF::chargedD0High; + if (triggerSelection == "jetD0ChHighPt") { + return JTrigSelChHF::jetD0ChHighPt; } - if (triggerSelection == "chargedLcLow") { - return JTrigSelChHF::chargedLcLow; + if (triggerSelection == "jetLcChLowPt") { + return JTrigSelChHF::jetLcChLowPt; } - if (triggerSelection == "chargedLcHigh") { - return JTrigSelChHF::chargedLcHigh; + if (triggerSelection == "jetLcChHighPt") { + return JTrigSelChHF::jetLcChHighPt; } return -1; } @@ -280,16 +539,16 @@ uint8_t setChargedHFTriggerSelectionBit(T const& collision) uint8_t bit = 0; if (collision.hasJetD0ChLowPt()) { - SETBIT(bit, JTrigSelChHF::chargedD0Low); + SETBIT(bit, JTrigSelChHF::jetD0ChLowPt); } if (collision.hasJetD0ChHighPt()) { - SETBIT(bit, JTrigSelChHF::chargedD0High); + SETBIT(bit, JTrigSelChHF::jetD0ChHighPt); } if (collision.hasJetLcChLowPt()) { - SETBIT(bit, JTrigSelChHF::chargedLcLow); + SETBIT(bit, JTrigSelChHF::jetLcChLowPt); } if (collision.hasJetLcChHighPt()) { - SETBIT(bit, JTrigSelChHF::chargedLcHigh); + SETBIT(bit, JTrigSelChHF::jetLcChHighPt); } return bit; } @@ -298,7 +557,8 @@ enum JTrackSel { trackSign = 0, // warning : this number is hardcoded in the sign coloumn in the JTracks table so should not be changed without changing it there too globalTrack = 1, qualityTrack = 2, - hybridTrack = 3 + qualityTrackWDCA = 3, + hybridTrack = 4 }; template @@ -325,14 +585,16 @@ int initialiseTrackSelection(std::string trackSelection) return JTrackSel::globalTrack; } else if (trackSelection == "QualityTracks") { return JTrackSel::qualityTrack; - } else if (trackSelection == "hybridTracksJE") { + } else if (trackSelection == "QualityTracksWDCA") { + return JTrackSel::qualityTrackWDCA; + } else if (trackSelection == "hybridTracks") { return JTrackSel::hybridTrack; } return -1; } template -uint8_t setTrackSelectionBit(T const& track) +uint8_t setTrackSelectionBit(T const& track, float trackDCAZ, float maxDCAZ) { uint8_t bit = 0; @@ -345,11 +607,13 @@ uint8_t setTrackSelectionBit(T const& track) } if (track.isQualityTrack()) { SETBIT(bit, JTrackSel::qualityTrack); + if (std::abs(trackDCAZ) < maxDCAZ) { + SETBIT(bit, JTrackSel::qualityTrackWDCA); + } } if (track.trackCutFlagFb5()) { SETBIT(bit, JTrackSel::hybridTrack); } - return bit; } @@ -368,6 +632,12 @@ float trackEnergy(T const& track, float mass = mPion) return std::sqrt((track.p() * track.p()) + (mass * mass)); } +template +bool selectTrackDcaZ(T const& track, double dcaZmax = 99.) +{ + return abs(track.dcaZ()) < dcaZmax; +} + } // namespace jetderiveddatautilities #endif // PWGJE_CORE_JETDERIVEDDATAUTILITIES_H_ diff --git a/PWGJE/Core/JetFinder.cxx b/PWGJE/Core/JetFinder.cxx index 940a201bb92..03583a9e622 100644 --- a/PWGJE/Core/JetFinder.cxx +++ b/PWGJE/Core/JetFinder.cxx @@ -37,7 +37,11 @@ void JetFinder::setParams() // selGhosts =fastjet::SelectorRapRange(ghostEtaMin,ghostEtaMax) && fastjet::SelectorPhiRange(phiMin,phiMax); // ghostAreaSpec=fastjet::GhostedAreaSpec(selGhosts,ghostRepeatN,ghostArea,gridScatter,ktScatter,ghostktMean); ghostAreaSpec = fastjet::GhostedAreaSpec(ghostEtaMax, ghostRepeatN, ghostArea, gridScatter, ktScatter, ghostktMean); // the first argument is rapidity not pseudorapidity, to be checked - jetDef = fastjet::JetDefinition(algorithm, jetR, recombScheme, strategy); + jetDef = fastjet::JetDefinition(fastjet::antikt_algorithm, jetR, recombScheme, strategy); + if (fastjetExtraParam > -98.0) { + jetDef.set_extra_param(fastjetExtraParam); + } + jetDef.set_jet_algorithm(algorithm); areaDef = fastjet::AreaDefinition(areaType, ghostAreaSpec); selJets = fastjet::SelectorPtRange(jetPtMin, jetPtMax) && fastjet::SelectorEtaRange(jetEtaMin, jetEtaMax) && fastjet::SelectorPhiRange(jetPhiMin, jetPhiMax); } diff --git a/PWGJE/Core/JetFinder.h b/PWGJE/Core/JetFinder.h index bdb03434b2a..26b4a3c5f0f 100644 --- a/PWGJE/Core/JetFinder.h +++ b/PWGJE/Core/JetFinder.h @@ -82,6 +82,7 @@ class JetFinder fastjet::AreaDefinition areaDef; fastjet::Selector selJets; fastjet::Selector selGhosts; + double fastjetExtraParam = -99.0; /// Sets the jet finding parameters void setParams(); diff --git a/PWGJE/Core/JetFindingUtilities.h b/PWGJE/Core/JetFindingUtilities.h index 0724e679cbc..6fb2716965c 100644 --- a/PWGJE/Core/JetFindingUtilities.h +++ b/PWGJE/Core/JetFindingUtilities.h @@ -22,11 +22,14 @@ #include #include #include +#include +#include #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ASoA.h" #include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/HistogramRegistry.h" #include "Framework/Logger.h" #include "Common/Core/TrackSelection.h" @@ -42,12 +45,50 @@ #include "PWGJE/Core/FastJetUtilities.h" #include "PWGJE/Core/JetDerivedDataUtilities.h" #include "PWGJE/Core/JetFinder.h" -#include "PWGJE/Core/JetHFUtilities.h" #include "PWGJE/DataModel/Jet.h" +#include "PWGJE/Core/JetCandidateUtilities.h" +#include "PWGJE/Core/JetHFUtilities.h" + namespace jetfindingutilities { +/** + * returns true if the object is from the JDummys table + */ +template +constexpr bool isDummy() +{ + return std::is_same_v, o2::aod::JDummys::iterator> || std::is_same_v, o2::aod::JDummys::filtered_iterator>; +} + +/** + * returns true if the table is a JDummys table + */ +template +constexpr bool isDummyTable() +{ + return isDummy() || isDummy(); +} + +/** + * returns true if the cluster is from an EMCAL table + */ +template +constexpr bool isEMCALCluster() +{ + return std::is_same_v, o2::aod::JetClusters::iterator> || std::is_same_v, o2::aod::JetClusters::filtered_iterator> || std::is_same_v, o2::aod::JetClustersMCD::iterator> || std::is_same_v, o2::aod::JetClustersMCD::filtered_iterator>; +} + +/** + * returns true if the table is an EMCAL table + */ +template +constexpr bool isEMCALClusterTable() +{ + return isEMCALCluster() || isEMCALCluster(); +} + /** * Adds tracks to a fastjet inputParticles list * @@ -58,7 +99,7 @@ namespace jetfindingutilities */ template -void analyseTracks(std::vector& inputParticles, T const& tracks, int trackSelection, std::optional const& candidate = std::nullopt) +void analyseTracks(std::vector& inputParticles, T const& tracks, int trackSelection, double trackingEfficinecy, std::optional const& candidate = std::nullopt) { for (auto& track : tracks) { if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { @@ -66,7 +107,44 @@ void analyseTracks(std::vector& inputParticles, T const& tra } if (candidate != std::nullopt) { auto cand = candidate.value(); - if (jethfutilities::isDaughterTrack(track, cand, tracks)) { + if (jetcandidateutilities::isDaughterTrack(track, cand, tracks)) { + continue; + } + } + if (trackingEfficinecy < 0.999) { // this code is a bit ugly but it stops us needing to do the random generation unless asked for + TRandom3 randomNumber(0); + if (randomNumber.Rndm() > trackingEfficinecy) { // Is Rndm ok to use? + continue; + } + } + fastjetutilities::fillTracks(track, inputParticles, track.globalIndex()); + } +} + +/** + * Adds tracks to a fastjet inputParticles list for the case where there are multiple candidates per event + * + * @param inputParticles fastjet container + * @param tracks track table to be added + * @param trackSelection track selection to be applied to tracks + * @param candidates candidiates + */ + +template +void analyseTracksMultipleCandidates(std::vector& inputParticles, T const& tracks, int trackSelection, double trackingEfficinecy, U const& candidates) +{ + for (auto& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + for (auto& candidate : candidates) { + if (jetcandidateutilities::isDaughterTrack(track, candidate, tracks)) { + continue; + } + } + if (trackingEfficinecy < 0.999) { // this code is a bit ugly but it stops us needing to do the random generation unless asked for + TRandom3 randomNumber(0); + if (randomNumber.Rndm() > trackingEfficinecy) { // Is Rndm ok to use? continue; } } @@ -81,11 +159,11 @@ void analyseTracks(std::vector& inputParticles, T const& tra * @param clusters track table to be added */ template -void analyseClusters(std::vector& inputParticles, T const& clusters) +void analyseClusters(std::vector& inputParticles, T const& clusters, int hadronicCorrectionType = 0) { for (auto& cluster : *clusters) { // add cluster selections - fastjetutilities::fillClusters(cluster, inputParticles, cluster.globalIndex()); + fastjetutilities::fillClusters(cluster, inputParticles, cluster.globalIndex(), hadronicCorrectionType); } } @@ -102,8 +180,8 @@ void analyseClusters(std::vector& inputParticles, T const& c template bool analyseCandidate(std::vector& inputParticles, T const& candidate, float candPtMin, float candPtMax, float candYMin, float candYMax) { - auto candMass = jethfutilities::getCandidatePDGMass(candidate); - if (isnan(candidate.y())) { + auto candMass = jetcandidateutilities::getCandidatePDGMass(candidate); + if (std::isnan(candidate.y())) { return false; } if (candidate.y() < candYMin || candidate.y() > candYMax) { @@ -112,7 +190,7 @@ bool analyseCandidate(std::vector& inputParticles, T const& if (candidate.pt() < candPtMin || candidate.pt() >= candPtMax) { return false; } - fastjetutilities::fillTracks(candidate, inputParticles, candidate.globalIndex(), static_cast(JetConstituentStatus::candidateHF), candMass); + fastjetutilities::fillTracks(candidate, inputParticles, candidate.globalIndex(), static_cast(JetConstituentStatus::candidate), candMass); return true; } @@ -130,12 +208,62 @@ bool analyseCandidate(std::vector& inputParticles, T const& template bool analyseCandidateMC(std::vector& inputParticles, T const& candidate, float candPtMin, float candPtMax, float candYMin, float candYMax, bool rejectBackgroundMCCandidates) { - if (rejectBackgroundMCCandidates && !jethfutilities::isMatchedHFCandidate(candidate)) { + if (rejectBackgroundMCCandidates && !jetcandidateutilities::isMatchedCandidate(candidate)) { return false; } return analyseCandidate(inputParticles, candidate, candPtMin, candPtMax, candYMin, candYMax); } +/** + * Adds hf candidates to a fastjet inputParticles list (for data) + * + * @param inputParticles fastjet container + * @param v0Mass pdg mass of v0 candidate + * @param v0PtMin minimum pT of v0 candidate + * @param v0PtMax maximum pT of v candidate + * @param v0EtaMin minimum eta of v0 candidate + * @param v0EtaMax maximum eta of v0 candidate + * @param v0s V0 candidates + */ +template +bool analyseV0s(std::vector& inputParticles, T const& v0s, float v0PtMin, float v0PtMax, float v0YMin, float v0YMax, int v0Index) +{ + float v0Mass = 0; + float v0Y = -10.0; + + int nSelectedV0s = 0; + for (auto const& v0 : v0s) { + if constexpr (jetv0utilities::isV0McTable()) { + v0Mass = v0.m(); + v0Y = v0.y(); + } else { + if (v0Index == 0) { + v0Mass = o2::constants::physics::MassKaonNeutral; + } + if (v0Index == 1) { + v0Mass = o2::constants::physics::MassLambda0; + } + v0Y = v0.rapidity(v0Index); + } + if (std::isnan(v0Y)) { + continue; + } + if (v0Y < v0YMin || v0Y > v0YMax) { + continue; + } + if (v0.pt() < v0PtMin || v0.pt() >= v0PtMax) { + continue; + } + fastjetutilities::fillTracks(v0, inputParticles, v0.globalIndex(), static_cast(JetConstituentStatus::candidate), v0Mass); + nSelectedV0s++; + } + if (nSelectedV0s > 0) { + return true; + } else { + return false; + } +} + /** * Performs jet finding and fills jet tables * @@ -148,7 +276,7 @@ bool analyseCandidateMC(std::vector& inputParticles, T const * @param doHFJetFinding set whether only jets containing a HF candidate are saved */ template -void findJets(JetFinder& jetFinder, std::vector& inputParticles, float jetPtMin, float jetPtMax, std::vector jetRadius, float jetAreaFractionMin, T const& collision, U& jetsTable, V& constituentsTable, bool doHFJetFinding = false) +void findJets(JetFinder& jetFinder, std::vector& inputParticles, float jetPtMin, float jetPtMax, std::vector jetRadius, float jetAreaFractionMin, T const& collision, U& jetsTable, V& constituentsTable, std::shared_ptr thnSparseJet, bool fillThnSparse, bool doCandidateJetFinding = false) { auto jetRValues = static_cast>(jetRadius); jetFinder.jetPtMin = jetPtMin; @@ -158,38 +286,42 @@ void findJets(JetFinder& jetFinder, std::vector& inputPartic std::vector jets; fastjet::ClusterSequenceArea clusterSeq(jetFinder.findJets(inputParticles, jets)); for (const auto& jet : jets) { - bool isHFJet = false; - if (doHFJetFinding) { + if (jet.has_area() && jet.area() < jetAreaFractionMin * M_PI * R * R) { + continue; + } + if (fillThnSparse) { + thnSparseJet->Fill(R, jet.pt(), jet.eta(), jet.phi()); // important for normalisation in V0Jet analyses to store all jets, including those that aren't V0s + } + bool isCandidateJet = false; + if (doCandidateJetFinding) { for (const auto& constituent : jet.constituents()) { - if (constituent.template user_info().getStatus() == static_cast(JetConstituentStatus::candidateHF)) { - isHFJet = true; + auto constituentStatus = constituent.template user_info().getStatus(); + if (constituentStatus == static_cast(JetConstituentStatus::candidate)) { // note currently we cannot run V0 and HF in the same jet. If we ever need to we can seperate the loops + isCandidateJet = true; break; } } - if (!isHFJet) { + if (!isCandidateJet) { continue; } } - if (jet.has_area() && jet.area() < jetAreaFractionMin * M_PI * R * R) { - continue; - } - std::vector trackconst; - std::vector candconst; - std::vector clusterconst; + std::vector tracks; + std::vector cands; + std::vector clusters; jetsTable(collision.globalIndex(), jet.pt(), jet.eta(), jet.phi(), jet.E(), jet.rapidity(), jet.m(), jet.has_area() ? jet.area() : 0., std::round(R * 100)); for (const auto& constituent : sorted_by_pt(jet.constituents())) { if (constituent.template user_info().getStatus() == static_cast(JetConstituentStatus::track)) { - trackconst.push_back(constituent.template user_info().getIndex()); + tracks.push_back(constituent.template user_info().getIndex()); } if (constituent.template user_info().getStatus() == static_cast(JetConstituentStatus::cluster)) { - clusterconst.push_back(constituent.template user_info().getIndex()); + clusters.push_back(constituent.template user_info().getIndex()); } - if (constituent.template user_info().getStatus() == static_cast(JetConstituentStatus::candidateHF)) { - candconst.push_back(constituent.template user_info().getIndex()); + if (constituent.template user_info().getStatus() == static_cast(JetConstituentStatus::candidate)) { + cands.push_back(constituent.template user_info().getIndex()); } } - constituentsTable(jetsTable.lastIndex(), trackconst, clusterconst, candconst); + constituentsTable(jetsTable.lastIndex(), tracks, clusters, cands); } } } @@ -204,7 +336,7 @@ void findJets(JetFinder& jetFinder, std::vector& inputPartic * @param pdgDatabase database of pdg codes * @param candidate optional hf candidiate */ -template +template void analyseParticles(std::vector& inputParticles, std::string particleSelection, int jetTypeParticleLevel, T const& particles, o2::framework::Service pdgDatabase, std::optional const& candidate = std::nullopt) { for (auto& particle : particles) { @@ -217,7 +349,7 @@ void analyseParticles(std::vector& inputParticles, std::stri } else if (particleSelection == "PhysicalPrimaryAndHepMCStatus" && (!particle.isPhysicalPrimary() || particle.getHepMCStatusCode() != 1)) { continue; } - if (isinf(particle.eta())) { + if (std::isinf(particle.eta())) { continue; } auto pdgParticle = pdgDatabase->GetParticle(particle.pdgCode()); @@ -228,15 +360,31 @@ void analyseParticles(std::vector& inputParticles, std::stri if (jetTypeParticleLevel == static_cast(JetType::neutral) && pdgCharge != 0.0) { continue; } - if constexpr (jethfutilities::isHFMcCandidate()) { + if constexpr (jetcandidateutilities::isMcCandidate() && !jetv0utilities::isV0McCandidate()) { if (candidate != std::nullopt) { auto cand = candidate.value(); if (cand.mcParticleId() == particle.globalIndex()) { continue; } - auto hfParticle = cand.template mcParticle_as(); - if (jethfutilities::isDaughterParticle(hfParticle, particle.globalIndex())) { - continue; + if constexpr (checkIsDaughter) { + auto hfParticle = cand.template mcParticle_as(); + if (jetcandidateutilities::isDaughterParticle(hfParticle, particle.globalIndex())) { + continue; + } + } + } + } + if constexpr (jetv0utilities::isV0McTable()) { // note that for V0s the candidate table is given to this function, not a single candidate + if (candidate != std::nullopt) { + auto cands = candidate.value(); + for (auto const& cand : cands) { + if (cand.mcParticleId() == particle.globalIndex()) { + continue; + } + auto v0Particle = cand.template mcParticle_as(); + if (jetcandidateutilities::isDaughterParticle(v0Particle, particle.globalIndex())) { + continue; + } } } } diff --git a/PWGJE/Core/JetHFUtilities.h b/PWGJE/Core/JetHFUtilities.h index 666d4d77420..97394dd6a70 100644 --- a/PWGJE/Core/JetHFUtilities.h +++ b/PWGJE/Core/JetHFUtilities.h @@ -53,7 +53,7 @@ namespace jethfutilities template constexpr bool isD0Candidate() { - return std::is_same_v, CandidatesD0Data::iterator> || std::is_same_v, CandidatesD0Data::filtered_iterator> || std::is_same_v, CandidatesD0MCD::iterator> || std::is_same_v, CandidatesD0MCD::filtered_iterator>; + return std::is_same_v, o2::aod::CandidatesD0Data::iterator> || std::is_same_v, o2::aod::CandidatesD0Data::filtered_iterator> || std::is_same_v, o2::aod::CandidatesD0MCD::iterator> || std::is_same_v, o2::aod::CandidatesD0MCD::filtered_iterator>; } /** @@ -62,7 +62,7 @@ constexpr bool isD0Candidate() template constexpr bool isD0McCandidate() { - return std::is_same_v, CandidatesD0MCP::iterator> || std::is_same_v, CandidatesD0MCP::filtered_iterator>; + return std::is_same_v, o2::aod::CandidatesD0MCP::iterator> || std::is_same_v, o2::aod::CandidatesD0MCP::filtered_iterator>; } /** @@ -71,7 +71,6 @@ constexpr bool isD0McCandidate() template constexpr bool isD0Table() { - return isD0Candidate() || isD0Candidate(); } @@ -81,17 +80,52 @@ constexpr bool isD0Table() template constexpr bool isD0McTable() { - return isD0McCandidate() || isD0McCandidate(); } +/** + * returns true if the candidate is from a D+ table + */ +template +constexpr bool isDplusCandidate() +{ + return std::is_same_v, o2::aod::CandidatesDplusData::iterator> || std::is_same_v, o2::aod::CandidatesDplusData::filtered_iterator> || std::is_same_v, o2::aod::CandidatesDplusMCD::iterator> || std::is_same_v, o2::aod::CandidatesDplusMCD::filtered_iterator>; +} + +/** + * returns true if the particle is from a D+ MC table + */ +template +constexpr bool isDplusMcCandidate() +{ + return std::is_same_v, o2::aod::CandidatesDplusMCP::iterator> || std::is_same_v, o2::aod::CandidatesDplusMCP::filtered_iterator>; +} + +/** + * returns true if the table is a D+ table + */ +template +constexpr bool isDplusTable() +{ + return isDplusCandidate() || isDplusCandidate(); +} + +/** + * returns true if the table is a D+ MC table + */ +template +constexpr bool isDplusMcTable() +{ + return isDplusMcCandidate() || isDplusMcCandidate(); +} + /** * returns true if the candidate is from a Lc table */ template constexpr bool isLcCandidate() { - return std::is_same_v, CandidatesLcData::iterator> || std::is_same_v, CandidatesLcData::filtered_iterator> || std::is_same_v, CandidatesLcMCD::iterator> || std::is_same_v, CandidatesLcMCD::filtered_iterator>; + return std::is_same_v, o2::aod::CandidatesLcData::iterator> || std::is_same_v, o2::aod::CandidatesLcData::filtered_iterator> || std::is_same_v, o2::aod::CandidatesLcMCD::iterator> || std::is_same_v, o2::aod::CandidatesLcMCD::filtered_iterator>; } /** @@ -100,7 +134,7 @@ constexpr bool isLcCandidate() template constexpr bool isLcMcCandidate() { - return std::is_same_v, CandidatesLcMCP::iterator> || std::is_same_v, CandidatesLcMCP::filtered_iterator>; + return std::is_same_v, o2::aod::CandidatesLcMCP::iterator> || std::is_same_v, o2::aod::CandidatesLcMCP::filtered_iterator>; } /** @@ -127,7 +161,7 @@ constexpr bool isLcMcTable() template constexpr bool isBplusCandidate() { - return std::is_same_v, CandidatesBplusData::iterator> || std::is_same_v, CandidatesBplusData::filtered_iterator> || std::is_same_v, CandidatesBplusMCD::iterator> || std::is_same_v, CandidatesBplusMCD::filtered_iterator>; + return std::is_same_v, o2::aod::CandidatesBplusData::iterator> || std::is_same_v, o2::aod::CandidatesBplusData::filtered_iterator> || std::is_same_v, o2::aod::CandidatesBplusMCD::iterator> || std::is_same_v, o2::aod::CandidatesBplusMCD::filtered_iterator>; } /** @@ -136,7 +170,7 @@ constexpr bool isBplusCandidate() template constexpr bool isBplusMcCandidate() { - return std::is_same_v, CandidatesBplusMCP::iterator> || std::is_same_v, CandidatesBplusMCP::filtered_iterator>; + return std::is_same_v, o2::aod::CandidatesBplusMCP::iterator> || std::is_same_v, o2::aod::CandidatesBplusMCP::filtered_iterator>; } /** @@ -166,6 +200,8 @@ constexpr bool isHFCandidate() { if constexpr (isD0Candidate()) { return true; + } else if constexpr (isDplusCandidate()) { + return true; } else if constexpr (isLcCandidate()) { return true; } else if constexpr (isBplusCandidate()) { @@ -176,15 +212,16 @@ constexpr bool isHFCandidate() } /** - * returns true if the candidate is from a MC HF table + * returns true if the candidate is from a HF MC candidate table * * @param candidate candidate that is being checked */ template constexpr bool isHFMcCandidate() { - if constexpr (isD0McCandidate()) { return true; + } else if constexpr (isDplusMcCandidate()) { + return true; } else if constexpr (isLcMcCandidate()) { return true; } else if constexpr (isBplusMcCandidate()) { @@ -200,9 +237,10 @@ constexpr bool isHFMcCandidate() template constexpr bool isHFTable() { - if constexpr (isD0Candidate() || isD0Candidate()) { return true; + } else if constexpr (isDplusCandidate() || isDplusCandidate()) { + return true; } else if constexpr (isLcCandidate() || isLcCandidate()) { return true; } else if constexpr (isBplusCandidate() || isBplusCandidate()) { @@ -213,14 +251,15 @@ constexpr bool isHFTable() } /** - * returns true if the table type is a HF table + * returns true if the table type is a HF MC table */ template constexpr bool isHFMcTable() { - if constexpr (isD0McCandidate() || isD0McCandidate()) { return true; + } else if constexpr (isDplusMcCandidate() || isDplusMcCandidate()) { + return true; } else if constexpr (isLcMcCandidate() || isLcMcCandidate()) { return true; } else if constexpr (isBplusMcCandidate() || isBplusMcCandidate()) { @@ -237,13 +276,18 @@ constexpr bool isHFMcTable() template constexpr bool isMatchedHFCandidate(T const& candidate) { - if constexpr (isD0Candidate()) { if (std::abs(candidate.flagMcMatchRec()) == 1 << o2::aod::hf_cand_2prong::DecayType::D0ToPiK) { return true; } else { return false; } + } else if constexpr (isDplusCandidate()) { + if (std::abs(candidate.flagMcMatchRec()) == 1 << o2::aod::hf_cand_3prong::DecayType::DplusToPiKPi) { + return true; + } else { + return false; + } } else if constexpr (isLcCandidate()) { if (std::abs(candidate.flagMcMatchRec()) == 1 << o2::aod::hf_cand_3prong::DecayType::LcToPKPi) { return true; @@ -262,6 +306,12 @@ constexpr bool isMatchedHFCandidate(T const& candidate) } else { return false; } + } else if constexpr (isDplusMcCandidate()) { + if (std::abs(candidate.flagMcMatchGen()) == 1 << o2::aod::hf_cand_3prong::DecayType::DplusToPiKPi) { + return true; + } else { + return false; + } } else if constexpr (isLcMcCandidate()) { if (std::abs(candidate.flagMcMatchGen()) == 1 << o2::aod::hf_cand_3prong::DecayType::LcToPKPi) { return true; @@ -287,15 +337,20 @@ constexpr bool isMatchedHFCandidate(T const& candidate) * @param tracks the track table */ template -bool isDaughterTrack(T& track, U& candidate, V const& /*tracks*/) +bool isHFDaughterTrack(T& track, U& candidate, V const& /*tracks*/) { - if constexpr (isD0Candidate()) { if (candidate.prong0Id() == track.globalIndex() || candidate.prong1Id() == track.globalIndex()) { return true; } else { return false; } + } else if constexpr (isDplusCandidate()) { + if (candidate.prong0Id() == track.globalIndex() || candidate.prong1Id() == track.globalIndex() || candidate.prong2Id() == track.globalIndex()) { + return true; + } else { + return false; + } } else if constexpr (isLcCandidate()) { if (candidate.prong0Id() == track.globalIndex() || candidate.prong1Id() == track.globalIndex() || candidate.prong2Id() == track.globalIndex()) { return true; @@ -303,7 +358,7 @@ bool isDaughterTrack(T& track, U& candidate, V const& /*tracks*/) return false; } } else if constexpr (isBplusCandidate()) { - if (candidate.template prong0_as().template prong0_as().globalIndex() == track.globalIndex() || candidate.template prong0_as().template prong1_as().globalIndex() == track.globalIndex() || candidate.template prong1_as().globalIndex() == track.globalIndex()) { + if (candidate.prong0Id() == track.globalIndex() || candidate.prong1Id() == track.globalIndex() || candidate.prong2Id() == track.globalIndex()) { return true; } else { return false; @@ -314,37 +369,46 @@ bool isDaughterTrack(T& track, U& candidate, V const& /*tracks*/) } /** - * returns true if the particle has any daughters with the given global index + * returns the index of the JMcParticle matched to the HF candidate * - * @param candidate mother hf particle that is being checked - * @param globalIndex global index of potnetial daughter particle + * @param candidate hf candidate that is being checked + * @param tracks track table + * @param particles particle table */ -template -bool isDaughterParticle(const T& particle, int globalIndex) +template +auto matchedHFParticleId(const T& candidate, const U& /*tracks*/, const V& /*particles*/) { - for (auto daughter : particle.template daughters_as::parent_t>()) { - if (daughter.globalIndex() == globalIndex) { - return true; - } - if (isDaughterParticle(daughter, globalIndex)) { - return true; - } - } - return false; + const auto candidateDaughterParticle = candidate.template prong1_as().template mcParticle_as(); + return candidateDaughterParticle.template mothers_first_as().globalIndex(); // can we get the Id directly? +} + +/** + * returns the JMcParticle matched to the HF candidate + * + * @param candidate hf candidate that is being checked + * @param tracks track table + * @param particles particle table + */ +template +auto matchedHFParticle(const T& candidate, const U& /*tracks*/, const V& /*particles*/) +{ + const auto candidateDaughterParticle = candidate.template prong1_as().template mcParticle_as(); + return candidateDaughterParticle.template mothers_first_as(); } /** - * returns a slice of the table depending on the index of the candidate + * returns a slice of the table depending on the index of the HF candidate * * @param candidate HF candidate that is being checked * @param table the table to be sliced */ -template -auto slicedPerCandidate(T const& table, U const& candidate, V const& perD0Candidate, M const& perLcCandidate, N const& perBplusCandidate) +template +auto slicedPerHFCandidate(T const& table, U const& candidate, V const& perD0Candidate, M const& perDplusCandidate, N const& perLcCandidate, O const& perBplusCandidate) { - if constexpr (isD0Candidate()) { return table.sliceBy(perD0Candidate, candidate.globalIndex()); + } else if constexpr (isDplusCandidate()) { + return table.sliceBy(perDplusCandidate, candidate.globalIndex()); } else if constexpr (isLcCandidate()) { return table.sliceBy(perLcCandidate, candidate.globalIndex()); } else if constexpr (isBplusCandidate()) { @@ -354,106 +418,158 @@ auto slicedPerCandidate(T const& table, U const& candidate, V const& perD0Candid } } +/** + * returns a slice of the table depending on the index of the HF candidate + * + * @param HFTable HF table type + * @param jet jet that is being sliced based on + * @param table the table to be sliced + */ +template +auto slicedPerHFJet(T const& table, U const& jet, V const& perD0Jet, M const& perDplusJet, N const& perLcJet, O const& perBplusJet) +{ + if constexpr (isD0Table() || isD0McTable()) { + return table.sliceBy(perD0Jet, jet.globalIndex()); + } else if constexpr (isDplusTable() || isDplusMcTable()) { + return table.sliceBy(perDplusJet, jet.globalIndex()); + } else if constexpr (isLcTable() || isLcMcTable()) { + return table.sliceBy(perLcJet, jet.globalIndex()); + } else if constexpr (isBplusTable() || isBplusMcTable()) { + return table.sliceBy(perBplusJet, jet.globalIndex()); + } else { + return table; + } +} + +/** + * returns the HF collision Id of candidate based on type of HF candidate + * + * @param candidate HF candidate that is being checked + */ +template +int getHFCandidateCollisionId(T const& candidate) +{ + return candidate.hfCollBaseId(); +} + +/** + * returns the HF Mc collision Id of candidate based on type of HF candidate + * + * @param candidate HF candidate that is being checked + */ template -int getCandidatePDG(T const& /*candidate*/) +int getHFMcCandidateCollisionId(T const& candidate) { + return candidate.hfMcCollBaseId(); +} +/** + * returns the PDG of the candidate based on HF Table + * + * @param candidate HF candidate that is being checked + */ +template +int getHFCandidatePDG(T const& /*candidate*/) +{ if constexpr (isD0Candidate() || isD0McCandidate()) { return static_cast(o2::constants::physics::Pdg::kD0); - } - if constexpr (isLcCandidate() || isLcMcCandidate()) { + } else if constexpr (isDplusCandidate() || isDplusMcCandidate()) { + return static_cast(o2::constants::physics::Pdg::kDPlus); + } else if constexpr (isLcCandidate() || isLcMcCandidate()) { return static_cast(o2::constants::physics::Pdg::kLambdaCPlus); - } - if constexpr (isBplusCandidate() || isBplusMcCandidate()) { + } else if constexpr (isBplusCandidate() || isBplusMcCandidate()) { return static_cast(o2::constants::physics::Pdg::kBPlus); } else { return 0; } } +/** + * returns the PDG of the candidates in the table type + */ template -int getTablePDG() +int getHFTablePDG() { - if constexpr (isD0Table() || isD0McTable()) { return static_cast(o2::constants::physics::Pdg::kD0); - } - if constexpr (isLcTable() || isLcMcTable()) { + } else if constexpr (isDplusTable() || isDplusMcTable()) { + return static_cast(o2::constants::physics::Pdg::kDPlus); + } else if constexpr (isLcTable() || isLcMcTable()) { return static_cast(o2::constants::physics::Pdg::kLambdaCPlus); - } - if constexpr (isBplusTable() || isBplusMcTable()) { + } else if constexpr (isBplusTable() || isBplusMcTable()) { return static_cast(o2::constants::physics::Pdg::kBPlus); } else { return 0; } } +/** + * returns the mass of the candidate based on HF Table + * + * @param candidate HF candidate that is being checked + */ template -float getCandidatePDGMass(T const& /*candidate*/) +float getHFCandidatePDGMass(T const& /*candidate*/) { - if constexpr (isD0Candidate() || isD0McCandidate()) { return static_cast(o2::constants::physics::MassD0); - } - if constexpr (isLcCandidate() || isLcMcCandidate()) { + } else if constexpr (isDplusCandidate() || isDplusMcCandidate()) { + return static_cast(o2::constants::physics::MassDPlus); + } else if constexpr (isLcCandidate() || isLcMcCandidate()) { return static_cast(o2::constants::physics::MassLambdaCPlus); - } - if constexpr (isBplusCandidate() || isBplusMcCandidate()) { + } else if constexpr (isBplusCandidate() || isBplusMcCandidate()) { return static_cast(o2::constants::physics::MassBPlus); } else { - return 0.; + return -1.0; } } +/** + * returns the mass of the candidates in the table type + * + */ template -float getTablePDGMass() +float getHFTablePDGMass() { - if constexpr (isD0Table() || isD0McTable()) { return static_cast(o2::constants::physics::MassD0); - } - if constexpr (isLcTable() || isLcMcTable()) { + } else if constexpr (isDplusTable() || isDplusMcTable()) { + return static_cast(o2::constants::physics::MassDPlus); + } else if constexpr (isLcTable() || isLcMcTable()) { return static_cast(o2::constants::physics::MassLambdaCPlus); - } - if constexpr (isBplusTable() || isBplusMcTable()) { + } else if constexpr (isBplusTable() || isBplusMcTable()) { return static_cast(o2::constants::physics::MassBPlus); } else { - return 0.; + return -1.0; } } -template -void fillD0CollisionTable(T const& collision, U& D0CollisionTable, int32_t& D0CollisionTableIndex) +/** + * returns the mass of the candidate based on HF Table + * + * @param candidate HF candidate that is being checked + */ +template +float getHFCandidateInvariantMass(T const& candidate) { - D0CollisionTable(collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), collision.centFV0A(), collision.multZeqNTracksPV()); - D0CollisionTableIndex = D0CollisionTable.lastIndex(); + return candidate.m(); } template -void fillLcCollisionTable(T const& collision, U& LcCollisionTable, int32_t& LcCollisionTableIndex) +void fillHFCollisionTable(T const& collision, U& HFCollisionTable) { - - LcCollisionTable(collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), collision.centFV0A(), collision.multZeqNTracksPV()); - LcCollisionTableIndex = LcCollisionTable.lastIndex(); + HFCollisionTable(collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), collision.centFV0A(), collision.multZeqNTracksPV()); } -template -void fillHFCollisionTable(T const& collision, U const& /*candidates*/, V& HFCollisionTable, int32_t& HFCollisionTableIndex) +template +void fillHFMcCollisionTable(T const& mcCollision, U& HFMcCollisionTable) { - if constexpr (isD0Table()) { - fillD0CollisionTable(collision, HFCollisionTable, HFCollisionTableIndex); - } - if constexpr (isLcTable()) { - fillLcCollisionTable(collision, HFCollisionTable, HFCollisionTableIndex); - } + HFMcCollisionTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.centFT0M()); } -template -void fillD0CandidateTable(T const& candidate, int32_t collisionIndex, U& D0BaseTable, V& D0ParTable, M& D0ParETable, N& D0SelectionFlagTable, O& D0MlTable, P& D0MCDTable, int32_t& D0CandidateTableIndex) +template +void fillD0CandidateTable(T const& candidate, U& D0ParTable, V& D0ParETable, M& D0MlTable, N& D0MCDTable) { - - D0BaseTable(collisionIndex, candidate.pt(), candidate.eta(), candidate.phi(), candidate.m()); - D0ParTable( candidate.chi2PCA(), candidate.cpa(), @@ -468,25 +584,22 @@ void fillD0CandidateTable(T const& candidate, int32_t collisionIndex, U& D0BaseT candidate.impactParameter1(), candidate.impactParameterNormalised0(), candidate.impactParameterNormalised1(), - candidate.nSigTpcPi0(), - candidate.nSigTpcKa0(), - candidate.nSigTofPi0(), - candidate.nSigTofKa0(), - candidate.nSigTpcTofPi0(), - candidate.nSigTpcTofKa0(), - candidate.nSigTpcPi1(), - candidate.nSigTpcKa1(), - candidate.nSigTofPi1(), - candidate.nSigTofKa1(), - candidate.nSigTpcTofPi1(), - candidate.nSigTpcTofKa1(), + candidate.nSigTpcPiExpPi(), + candidate.nSigTofPiExpPi(), + candidate.nSigTpcTofPiExpPi(), + candidate.nSigTpcKaExpPi(), + candidate.nSigTofKaExpPi(), + candidate.nSigTpcTofKaExpPi(), + candidate.nSigTpcPiExpKa(), + candidate.nSigTofPiExpKa(), + candidate.nSigTpcTofPiExpKa(), + candidate.nSigTpcKaExpKa(), + candidate.nSigTofKaExpKa(), + candidate.nSigTpcTofKaExpKa(), candidate.maxNormalisedDeltaIP(), candidate.impactParameterProduct()); D0ParETable( - candidate.posX(), - candidate.posY(), - candidate.posZ(), candidate.xSecondaryVertex(), candidate.ySecondaryVertex(), candidate.zSecondaryVertex(), @@ -507,25 +620,86 @@ void fillD0CandidateTable(T const& candidate, int32_t collisionIndex, U& D0BaseT candidate.cosThetaStar(), candidate.ct()); - D0SelectionFlagTable(candidate.candidateSelFlag()); + std::vector mlScoresVector; + auto mlScoresSpan = candidate.mlScores(); + std::copy(mlScoresSpan.begin(), mlScoresSpan.end(), std::back_inserter(mlScoresVector)); + D0MlTable(mlScoresVector); + if constexpr (isMc) { D0MCDTable(candidate.flagMcMatchRec(), candidate.originMcRec()); } +} + +template +void fillDplusCandidateTable(T const& candidate, U& DplusParTable, V& DplusParETable, M& DplusMlTable, N& DplusMCDTable) +{ + + DplusParTable( + candidate.chi2PCA(), + candidate.nProngsContributorsPV(), + candidate.cpa(), + candidate.cpaXY(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.decayLengthNormalised(), + candidate.decayLengthXYNormalised(), + candidate.ptProng0(), + candidate.ptProng1(), + candidate.ptProng2(), + candidate.impactParameter0(), + candidate.impactParameter1(), + candidate.impactParameter2(), + candidate.impactParameterNormalised0(), + candidate.impactParameterNormalised1(), + candidate.impactParameterNormalised2(), + candidate.nSigTpcPi0(), + candidate.nSigTofPi0(), + candidate.nSigTpcTofPi0(), + candidate.nSigTpcKa1(), + candidate.nSigTofKa1(), + candidate.nSigTpcTofKa1(), + candidate.nSigTpcPi2(), + candidate.nSigTofPi2(), + candidate.nSigTpcTofPi2()); + + DplusParETable( + candidate.xSecondaryVertex(), + candidate.ySecondaryVertex(), + candidate.zSecondaryVertex(), + candidate.errorDecayLength(), + candidate.errorDecayLengthXY(), + candidate.rSecondaryVertex(), + candidate.pProng0(), + candidate.pProng1(), + candidate.pProng2(), + candidate.pxProng0(), + candidate.pyProng0(), + candidate.pzProng0(), + candidate.pxProng1(), + candidate.pyProng1(), + candidate.pzProng1(), + candidate.pxProng2(), + candidate.pyProng2(), + candidate.pzProng2(), + candidate.errorImpactParameter0(), + candidate.errorImpactParameter1(), + candidate.errorImpactParameter2(), + candidate.ct()); std::vector mlScoresVector; auto mlScoresSpan = candidate.mlScores(); std::copy(mlScoresSpan.begin(), mlScoresSpan.end(), std::back_inserter(mlScoresVector)); - D0MlTable(mlScoresVector); + DplusMlTable(mlScoresVector); - D0CandidateTableIndex = D0BaseTable.lastIndex(); + if constexpr (isMc) { + DplusMCDTable(candidate.flagMcMatchRec(), candidate.originMcRec(), candidate.isCandidateSwapped(), candidate.flagMcDecayChanRec()); + } } -template -void fillLcCandidateTable(T const& candidate, int32_t collisionIndex, U& LcBaseTable, V& LcParTable, M& LcParETable, N& LcSelectionFlagTable, O& LcMlTable, P& LcMCDTable, int32_t& LcCandidateTableIndex) +template +void fillLcCandidateTable(T const& candidate, U& LcParTable, V& LcParETable, M& LcMlTable, N& LcMCDTable) { - LcBaseTable(collisionIndex, candidate.pt(), candidate.eta(), candidate.phi(), candidate.m()); - LcParTable( candidate.chi2PCA(), candidate.nProngsContributorsPV(), @@ -561,9 +735,6 @@ void fillLcCandidateTable(T const& candidate, int32_t collisionIndex, U& LcBaseT candidate.nSigTpcTofPr2()); LcParETable( - candidate.posX(), - candidate.posY(), - candidate.posZ(), candidate.xSecondaryVertex(), candidate.ySecondaryVertex(), candidate.zSecondaryVertex(), @@ -587,64 +758,116 @@ void fillLcCandidateTable(T const& candidate, int32_t collisionIndex, U& LcBaseT candidate.errorImpactParameter2(), candidate.ct()); - LcSelectionFlagTable(candidate.candidateSelFlag()); - if constexpr (isMc) { - LcMCDTable(candidate.flagMcMatchRec(), candidate.originMcRec(), candidate.isCandidateSwapped()); - } - std::vector mlScoresVector; auto mlScoresSpan = candidate.mlScores(); std::copy(mlScoresSpan.begin(), mlScoresSpan.end(), std::back_inserter(mlScoresVector)); LcMlTable(mlScoresVector); - LcCandidateTableIndex = LcBaseTable.lastIndex(); + if constexpr (isMc) { + LcMCDTable(candidate.flagMcMatchRec(), candidate.originMcRec(), candidate.isCandidateSwapped()); + } } +// need to update this template -void fillCandidateTable(T const& candidate, int32_t collisionIndex, U& HFBaseTable, V& HFParTable, M& HFParETable, N& HFSelectionFlagTable, O& HFMlTable, P& HFMCDTable, int32_t& HFCandidateTableIndex) +void fillBplusCandidateTable(T const& candidate, U& BplusParTable, V& BplusParETable, M& BplusParD0Table, N& BplusMlTable, O& BplusMlD0Table, P& BplusMCDTable) { - if constexpr (isD0Candidate()) { - fillD0CandidateTable(candidate, collisionIndex, HFBaseTable, HFParTable, HFParETable, HFSelectionFlagTable, HFMlTable, HFMCDTable, HFCandidateTableIndex); - } - if constexpr (isLcCandidate()) { - fillLcCandidateTable(candidate, collisionIndex, HFBaseTable, HFParTable, HFParETable, HFSelectionFlagTable, HFMlTable, HFMCDTable, HFCandidateTableIndex); + + BplusParTable( + candidate.chi2PCA(), + candidate.cpa(), + candidate.cpaXY(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.decayLengthNormalised(), + candidate.decayLengthXYNormalised(), + candidate.ptProng0(), + candidate.ptProng1(), + candidate.impactParameter0(), + candidate.impactParameter1(), + candidate.impactParameterNormalised0(), + candidate.impactParameterNormalised1(), + candidate.nSigTpcPiExpPi(), + candidate.nSigTofPiExpPi(), + candidate.nSigTpcTofPiExpPi(), + candidate.nSigTpcKaExpPi(), + candidate.nSigTofKaExpPi(), + candidate.nSigTpcTofKaExpPi(), + candidate.maxNormalisedDeltaIP(), + candidate.impactParameterProduct()); + + BplusParETable( + candidate.xSecondaryVertex(), + candidate.ySecondaryVertex(), + candidate.zSecondaryVertex(), + candidate.errorDecayLength(), + candidate.errorDecayLengthXY(), + candidate.rSecondaryVertex(), + candidate.pProng1(), + candidate.pxProng1(), + candidate.pyProng1(), + candidate.pzProng1(), + candidate.errorImpactParameter1(), + candidate.cosThetaStar(), + candidate.ct()); + + BplusParD0Table( + candidate.cpaCharm(), + candidate.decayLengthCharm(), + candidate.impactParameter0Charm(), + candidate.impactParameter1Charm(), + candidate.impactParameterProductCharm(), + candidate.nSigTpcPiExpPiCharm(), + candidate.nSigTofPiExpPiCharm(), + candidate.nSigTpcTofPiExpPiCharm(), + candidate.nSigTpcKaExpPiCharm(), + candidate.nSigTofKaExpPiCharm(), + candidate.nSigTpcTofKaExpPiCharm(), + candidate.nSigTpcPiExpKaCharm(), + candidate.nSigTofPiExpKaCharm(), + candidate.nSigTpcTofPiExpKaCharm(), + candidate.nSigTpcKaExpKaCharm(), + candidate.nSigTofKaExpKaCharm(), + candidate.nSigTpcTofKaExpKaCharm()); + + // BplusSelectionFlagTable(candidate.candidateSelFlag()); + + BplusMlTable(candidate.mlScoreSig()); + + std::vector mlScoresCharmVector; + auto mlScoresCharmSpan = candidate.mlScoresCharm(); + std::copy(mlScoresCharmSpan.begin(), mlScoresCharmSpan.end(), std::back_inserter(mlScoresCharmVector)); + BplusMlD0Table(mlScoresCharmVector); + + if constexpr (isMc) { + BplusMCDTable(candidate.flagMcMatchRec(), candidate.originMcRec()); } } -template -void fillD0CandidateMcTable(T const& candidate, U& D0PBaseTable, int32_t& D0CandidateTableIndex) -{ - D0PBaseTable(candidate.pt(), candidate.eta(), candidate.phi(), candidate.flagMcMatchGen(), candidate.originMcGen()); - D0CandidateTableIndex = D0PBaseTable.lastIndex(); -} -template -void fillLcCandidateMcTable(T const& candidate, U& LcPBaseTable, int32_t& LcCandidateTableIndex) +template +void fillHFCandidateTable(T const& candidate, int32_t collisionIndex, U& HFBaseTable, V& HFParTable, M& HFParETable, N& HFParDaughterTable, O& HFSelectionFlagTable, P& HFMlTable, Q& HFMlDaughterTable, S& HFMCDTable) { - LcPBaseTable(candidate.pt(), candidate.eta(), candidate.phi(), candidate.flagMcMatchGen(), candidate.originMcGen()); - LcCandidateTableIndex = LcPBaseTable.lastIndex(); -} + HFBaseTable(collisionIndex, candidate.pt(), candidate.eta(), candidate.phi(), candidate.m(), candidate.y()); + HFSelectionFlagTable(candidate.candidateSelFlag()); -template -void fillCandidateMcTable(T const& candidate, U& BaseMcTable, int32_t& candidateTableIndex) -{ - if constexpr (isD0McCandidate()) { - fillD0CandidateMcTable(candidate, BaseMcTable, candidateTableIndex); + if constexpr (isD0Candidate()) { + fillD0CandidateTable(candidate, HFParTable, HFParETable, HFMlTable, HFMCDTable); } - if constexpr (isLcMcCandidate()) { - fillLcCandidateMcTable(candidate, BaseMcTable, candidateTableIndex); + if constexpr (isDplusCandidate()) { + fillDplusCandidateTable(candidate, HFParTable, HFParETable, HFMlTable, HFMCDTable); + } + if constexpr (isLcCandidate()) { + fillLcCandidateTable(candidate, HFParTable, HFParETable, HFMlTable, HFMCDTable); + } + if constexpr (isBplusCandidate()) { + fillBplusCandidateTable(candidate, HFParTable, HFParETable, HFParDaughterTable, HFMlTable, HFMlDaughterTable, HFMCDTable); } } template -auto getCandidateCollision(T const& candidate, U const& /*candidateCollisions*/) +void fillHFCandidateMcTable(T const& candidate, int32_t mcCollisionIndex, U& BaseMcTable) { - if constexpr (isD0Candidate()) { // make sure this actually is working - return candidate.template hfD0CollBase_as(); - } else if constexpr (isLcCandidate()) { // make sure this actually is working - return candidate.template hf3PCollBase_as(); - } else { - return candidate.template hfD0CollBase_as(); - } + BaseMcTable(mcCollisionIndex, candidate.pt(), candidate.eta(), candidate.phi(), candidate.y(), candidate.flagMcMatchGen(), candidate.originMcGen()); } }; // namespace jethfutilities diff --git a/PWGJE/Core/JetMatchingUtilities.h b/PWGJE/Core/JetMatchingUtilities.h index 783985eced8..1c499686638 100644 --- a/PWGJE/Core/JetMatchingUtilities.h +++ b/PWGJE/Core/JetMatchingUtilities.h @@ -25,6 +25,7 @@ #include #include #include +#include #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -37,11 +38,9 @@ #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/TrackSelectionTables.h" #include "PWGJE/DataModel/EMCALClusters.h" - -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" - #include "PWGJE/DataModel/Jet.h" +#include "PWGJE/Core/JetCandidateUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" namespace jetmatchingutilities { @@ -363,19 +362,24 @@ void MatchGeo(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std:: // function that does the HF matching of jets from jetsBasePerColl and jets from jetsTagPerColl; assumes both jetsBasePerColl and jetsTagPerColl have access to Mc information template -void MatchHF(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std::vector>& baseToTagMatchingHF, std::vector>& tagToBaseMatchingHF, V const& /*candidatesBase*/, M const& /*candidatesTag*/, N const& /*tracksBase*/, O const& /*tracksTag*/) +void MatchHF(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std::vector>& baseToTagMatchingHF, std::vector>& tagToBaseMatchingHF, V const& /*candidatesBase*/, M const& /*candidatesTag*/, N const& tracksBase, O const& tracksTag) { for (const auto& jetBase : jetsBasePerCollision) { - const auto candidateBase = jetBase.template hfcandidates_first_as(); + if (jetBase.candidatesIds().size() == 0) { + continue; + } + const auto candidateBase = jetBase.template candidates_first_as(); for (const auto& jetTag : jetsTagPerCollision) { + if (jetTag.candidatesIds().size() == 0) { + continue; + } if (std::round(jetBase.r()) != std::round(jetTag.r())) { continue; } if constexpr (jetsBaseIsMc || jetsTagIsMc) { - if (jethfutilities::isMatchedHFCandidate(candidateBase)) { - const auto candidateBaseDaughterParticle = candidateBase.template prong1_as().template mcParticle_as(); - const auto candidateBaseMcId = candidateBaseDaughterParticle.template mothers_first_as().globalIndex(); - const auto candidateTag = jetTag.template hfcandidates_first_as(); + if (jetcandidateutilities::isMatchedCandidate(candidateBase)) { + const auto candidateBaseMcId = jetcandidateutilities::matchedParticleId(candidateBase, tracksBase, tracksTag); + const auto candidateTag = jetTag.template candidates_first_as(); const auto candidateTagId = candidateTag.mcParticleId(); if (candidateBaseMcId == candidateTagId) { baseToTagMatchingHF[jetBase.globalIndex()].push_back(jetTag.globalIndex()); @@ -383,7 +387,7 @@ void MatchHF(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std::v } } } else { - const auto candidateTag = jetTag.template hfcandidates_first_as(); + const auto candidateTag = jetTag.template candidates_first_as(); if (candidateBase.globalIndex() == candidateTag.globalIndex()) { baseToTagMatchingHF[jetBase.globalIndex()].push_back(jetTag.globalIndex()); tagToBaseMatchingHF[jetTag.globalIndex()].push_back(jetBase.globalIndex()); @@ -394,7 +398,7 @@ void MatchHF(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std::v } template -auto constexpr getTrackId(T const& track) +auto constexpr getConstituentId(T const& track) { if constexpr (isMc) { @@ -409,16 +413,101 @@ auto constexpr getTrackId(T const& track) } } -template -float getPtSum(T const& tracksBase, U const& tracksTag) +template +float getPtSum(T const& tracksBase, U const& candidatesBase, V const& clustersBase, O const& tracksTag, P const& candidatesTag, Q const& clustersTag, R const& fullTracksBase, S const& fullTracksTag) { + std::vector particleTracker; float ptSum = 0.; for (const auto& trackBase : tracksBase) { - auto trackBaseId = getTrackId(trackBase); + auto trackBaseId = getConstituentId(trackBase); for (const auto& trackTag : tracksTag) { - auto trackTagId = getTrackId(trackTag); + auto trackTagId = getConstituentId(trackTag); if (trackBaseId != -1 && trackBaseId == trackTagId) { ptSum += trackBase.pt(); + if constexpr (jetsBaseIsMc) { + particleTracker.push_back(trackBaseId); + } + break; + } + } + } + if constexpr (isEMCAL) { + if constexpr (jetsTagIsMc) { + for (const auto& clusterBase : clustersBase) { + for (const auto& clusterBaseParticleId : clusterBase.mcParticlesIds()) { + bool isClusterMatched = false; + for (const auto& trackTag : tracksTag) { + if (clusterBaseParticleId != -1 && clusterBaseParticleId == trackTag.globalIndex()) { + ptSum += clusterBase.energy() / std::cosh(clusterBase.eta()); + isClusterMatched = true; + break; + } + } + if (isClusterMatched) { + break; + } + } + } + } + if constexpr (jetsBaseIsMc) { + for (const auto& trackBase : tracksBase) { + if (std::find(particleTracker.begin(), particleTracker.end(), trackBase.globalIndex()) != particleTracker.end()) { + continue; + } + auto trackBaseId = trackBase.globalIndex(); + for (const auto& clusterTag : clustersTag) { + bool isClusterMatched = false; + for (const auto& clusterTagParticleId : clusterTag.mcParticlesIds()) { + if (trackBaseId != -1 && trackBaseId == clusterTagParticleId) { + ptSum += trackBase.pt(); + isClusterMatched = true; + break; + } + } + if (isClusterMatched) { + break; + } + } + } + } + } + if constexpr (isCandidate) { + if constexpr (jetsTagIsMc) { + for (auto const& candidateBase : candidatesBase) { + if (jetcandidateutilities::isMatchedCandidate(candidateBase)) { + const auto candidateBaseMcId = jetcandidateutilities::matchedParticleId(candidateBase, fullTracksBase, fullTracksTag); + for (auto const& candidateTag : candidatesTag) { + const auto candidateTagId = candidateTag.mcParticleId(); + if (candidateBaseMcId == candidateTagId) { + ptSum += candidateBase.pt(); + } + break; // should only be one + } + } + break; + } + } else if constexpr (jetsBaseIsMc) { + for (auto const& candidateTag : candidatesTag) { + if (jetcandidateutilities::isMatchedCandidate(candidateTag)) { + const auto candidateTagMcId = jetcandidateutilities::matchedParticleId(candidateTag, fullTracksTag, fullTracksBase); + for (auto const& candidateBase : candidatesBase) { + const auto candidateBaseId = candidateBase.mcParticleId(); + if (candidateTagMcId == candidateBaseId) { + ptSum += candidateTag.pt(); + } + break; // should only be one + } + } + break; + } + } else { + for (auto const& candidateBase : candidatesBase) { + for (auto const& candidateTag : candidatesTag) { + if (candidateBase.globalIndex() == candidateTag.globalIndex()) { + ptSum += candidateBase.pt(); + } + break; // should only be one + } break; } } @@ -426,21 +515,39 @@ float getPtSum(T const& tracksBase, U const& tracksTag) return ptSum; } -template -void MatchPt(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std::vector>& baseToTagMatchingPt, std::vector>& tagToBaseMatchingPt, V const& /*tracksBase*/, M const& /*tracksTag*/, float minPtFraction) +template +auto getConstituents(T const& jet, U const& /*constituents*/) +{ + if constexpr (jetfindingutilities::isEMCALClusterTable()) { + return jet.template clusters_as(); + } else if constexpr (jetcandidateutilities::isCandidateTable() || jetcandidateutilities::isCandidateMcTable()) { + return jet.template candidates_as(); + } else if constexpr (jetfindingutilities::isDummyTable() || std::is_same_v || std::is_same_v) { // this is for the case where EMCal clusters or candidates are tested but no clusters or candidates exist and dummy tables are used, like in the case of charged jet analyses + return nullptr; + } else { + return jet.template tracks_as(); + } +} + +template +void MatchPt(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std::vector>& baseToTagMatchingPt, std::vector>& tagToBaseMatchingPt, V const& tracksBase, M const& candidatesBase, N const& clustersBase, O const& tracksTag, P const& candidatesTag, Q const& clustersTag, float minPtFraction) { float ptSumBase; float ptSumTag; for (const auto& jetBase : jetsBasePerCollision) { - auto jetBaseTracks = jetBase.template tracks_as(); + auto jetBaseTracks = getConstituents(jetBase, tracksBase); + auto jetBaseClusters = getConstituents(jetBase, clustersBase); + auto jetBaseCandidates = getConstituents(jetBase, candidatesBase); for (const auto& jetTag : jetsTagPerCollision) { if (std::round(jetBase.r()) != std::round(jetTag.r())) { continue; } - auto jetTagTracks = jetTag.template tracks_as(); + auto jetTagTracks = getConstituents(jetTag, tracksTag); + auto jetTagClusters = getConstituents(jetTag, clustersTag); + auto jetTagCandidates = getConstituents(jetTag, candidatesTag); - ptSumBase = getPtSum(jetBaseTracks, jetTagTracks); - ptSumTag = getPtSum(jetTagTracks, jetBaseTracks); + ptSumBase = getPtSum < jetfindingutilities::isEMCALClusterTable() || jetfindingutilities::isEMCALClusterTable(), (jetcandidateutilities::isCandidateTable() || jetcandidateutilities::isCandidateMcTable()) && (jetcandidateutilities::isCandidateTable

() || jetcandidateutilities::isCandidateMcTable

()), jetsBaseIsMc, jetsTagIsMc > (jetBaseTracks, jetBaseCandidates, jetBaseClusters, jetTagTracks, jetTagCandidates, jetTagClusters, tracksBase, tracksTag); + ptSumTag = getPtSum < jetfindingutilities::isEMCALClusterTable() || jetfindingutilities::isEMCALClusterTable(), (jetcandidateutilities::isCandidateTable() || jetcandidateutilities::isCandidateMcTable()) && (jetcandidateutilities::isCandidateTable

() || jetcandidateutilities::isCandidateMcTable

()), jetsTagIsMc, jetsBaseIsMc > (jetTagTracks, jetTagCandidates, jetTagClusters, jetBaseTracks, jetBaseCandidates, jetBaseClusters, tracksTag, tracksBase); if (ptSumBase > jetBase.pt() * minPtFraction) { baseToTagMatchingPt[jetBase.globalIndex()].push_back(jetTag.globalIndex()); } @@ -452,8 +559,8 @@ void MatchPt(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std::v } // function that calls all the Match functions -template -void doAllMatching(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std::vector>& baseToTagMatchingGeo, std::vector>& baseToTagMatchingPt, std::vector>& baseToTagMatchingHF, std::vector>& tagToBaseMatchingGeo, std::vector>& tagToBaseMatchingPt, std::vector>& tagToBaseMatchingHF, V const& candidatesBase, M const& candidatesTag, N const& tracksBase, O const& tracksTag, bool doMatchingGeo, bool doMatchingHf, bool doMatchingPt, float maxMatchingDistance, float minPtFraction) +template +void doAllMatching(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std::vector>& baseToTagMatchingGeo, std::vector>& baseToTagMatchingPt, std::vector>& baseToTagMatchingHF, std::vector>& tagToBaseMatchingGeo, std::vector>& tagToBaseMatchingPt, std::vector>& tagToBaseMatchingHF, V const& candidatesBase, M const& tracksBase, N const& clustersBase, O const& candidatesTag, P const& tracksTag, R const& clustersTag, bool doMatchingGeo, bool doMatchingHf, bool doMatchingPt, float maxMatchingDistance, float minPtFraction) { // geometric matching if (doMatchingGeo) { @@ -461,14 +568,179 @@ void doAllMatching(T const& jetsBasePerCollision, U const& jetsTagPerCollision, } // pt matching if (doMatchingPt) { - MatchPt(jetsBasePerCollision, jetsTagPerCollision, baseToTagMatchingPt, tagToBaseMatchingPt, tracksBase, tracksTag, minPtFraction); + MatchPt(jetsBasePerCollision, jetsTagPerCollision, baseToTagMatchingPt, tagToBaseMatchingPt, tracksBase, candidatesBase, clustersBase, tracksTag, candidatesTag, clustersTag, minPtFraction); } // HF matching - if constexpr (jethfutilities::isHFTable()) { + if constexpr (jetcandidateutilities::isCandidateTable() || jetcandidateutilities::isCandidateMcTable()) { if (doMatchingHf) { MatchHF(jetsBasePerCollision, jetsTagPerCollision, baseToTagMatchingHF, tagToBaseMatchingHF, candidatesBase, candidatesTag, tracksBase, tracksTag); } } } + +// function that does pair matching +template +void doPairMatching(T const& pairsBase, U const& pairsTag, std::vector>& baseToTagMatching, std::vector>& tagToBaseMatching, V const& /*candidatesBase*/, M const& tracksBase, N const& /*candidatesTag*/, O const& tracksTag) +{ + bool hasTrackBase1 = false; + bool hasTrackBase2 = false; + bool hasCandidateBase1 = false; + bool hasCandidateBase2 = false; + std::vector pairsTagIndices; + for (auto i = 0; i < pairsTag.size(); i++) { + pairsTagIndices.push_back(i); + } + for (const auto& pairBase : pairsBase) { + if (pairBase.has_track1()) { + hasTrackBase1 = true; + } + if (pairBase.has_track2()) { + hasTrackBase2 = true; + } + if (pairBase.has_candidate1()) { + hasCandidateBase1 = true; + } + if (pairBase.has_candidate2()) { + hasCandidateBase2 = true; + } + int matchedPairTagIndex = -1; + for (auto pairTagIndex : pairsTagIndices) { + const auto& pairTag = pairsTag.iteratorAt(pairTagIndex); + if (hasTrackBase1 && !pairTag.has_track1()) { + continue; + } + if (hasTrackBase2 && !pairTag.has_track2()) { + continue; + } + if (hasCandidateBase1 && !pairTag.has_candidate1()) { + continue; + } + if (hasCandidateBase2 && !pairTag.has_candidate2()) { + continue; + } + int nMatched = 0; + bool isMatched = false; + if (hasTrackBase1) { + const auto& trackBase1 = pairBase.template track1_as(); + const auto& trackTag1 = pairTag.template track1_as(); + if constexpr (jetsTagIsMc) { + if (trackBase1.mcParticleId() == trackTag1.globalIndex()) { + nMatched++; + isMatched = true; + } + } else if constexpr (jetsBaseIsMc) { + if (trackBase1.globalIndex() == trackTag1.mcParticleId()) { + nMatched++; + isMatched = true; + } + } else { + if (trackBase1.globalIndex() == trackTag1.globalIndex()) { + nMatched++; + isMatched = true; + } + } + if (!isMatched) { + continue; + } + } + isMatched = false; + + if (hasTrackBase2) { + const auto& trackBase2 = pairBase.template track2_as(); + const auto& trackTag2 = pairTag.template track2_as(); + if constexpr (jetsTagIsMc) { + if (trackBase2.mcParticleId() == trackTag2.globalIndex()) { + nMatched++; + isMatched = true; + } + } else if constexpr (jetsBaseIsMc) { + if (trackBase2.globalIndex() == trackTag2.mcParticleId()) { + nMatched++; + isMatched = true; + } + } else { + if (trackBase2.globalIndex() == trackTag2.globalIndex()) { + nMatched++; + isMatched = true; + } + } + if (!isMatched) { + continue; + } + } + isMatched = false; + if (hasCandidateBase1) { + const auto& candidateBase1 = pairBase.template candidate1_as(); + const auto& candidateTag1 = pairTag.template candidate1_as(); + if constexpr (jetsTagIsMc) { + if (jetcandidateutilities::isMatchedCandidate(candidateBase1)) { + const auto candidateBaseMcId = jetcandidateutilities::matchedParticleId(candidateBase1, tracksBase, tracksTag); + if (candidateBaseMcId == candidateTag1.globalIndex()) { + nMatched++; + isMatched = true; + } + } + } else if constexpr (jetsBaseIsMc) { + if (jetcandidateutilities::isMatchedCandidate(candidateTag1)) { + const auto candidateTagMcId = jetcandidateutilities::matchedParticleId(candidateTag1, tracksTag, tracksBase); + if (candidateTagMcId == candidateBase1.globalIndex()) { + nMatched++; + isMatched = true; + } + } + } else { + if (candidateBase1.globalIndex() == candidateTag1.globalIndex()) { + nMatched++; + isMatched = true; + } + } + if (!isMatched) { + continue; + } + } + isMatched = false; + if (hasCandidateBase2) { + const auto& candidateBase2 = pairBase.template candidate2_as(); + const auto& candidateTag2 = pairTag.template candidate2_as(); + if constexpr (jetsTagIsMc) { + if (jetcandidateutilities::isMatchedCandidate(candidateBase2)) { + const auto candidateBaseMcId = jetcandidateutilities::matchedParticleId(candidateBase2, tracksBase, tracksTag); + if (candidateBaseMcId == candidateTag2.globalIndex()) { + nMatched++; + isMatched = true; + } + } + } else if constexpr (jetsBaseIsMc) { + if (jetcandidateutilities::isMatchedCandidate(candidateTag2)) { + const auto candidateTagMcId = jetcandidateutilities::matchedParticleId(candidateTag2, tracksTag, tracksBase); + if (candidateTagMcId == candidateBase2.globalIndex()) { + nMatched++; + isMatched = true; + } + } + } else { + if (candidateBase2.globalIndex() == candidateTag2.globalIndex()) { + nMatched++; + isMatched = true; + } + } + if (!isMatched) { + continue; + } + } + + if (nMatched == 2) { + baseToTagMatching[pairBase.globalIndex()].push_back(pairTag.globalIndex()); + tagToBaseMatching[pairTag.globalIndex()].push_back(pairBase.globalIndex()); + matchedPairTagIndex = pairTagIndex; + break; // can only be one match per jet + } + } + if (matchedPairTagIndex != -1) { + pairsTagIndices.erase(std::find(pairsTagIndices.begin(), pairsTagIndices.end(), matchedPairTagIndex)); + } + } +} + }; // namespace jetmatchingutilities #endif // PWGJE_CORE_JETMATCHINGUTILITIES_H_ diff --git a/PWGJE/Core/JetSubstructureUtilities.h b/PWGJE/Core/JetSubstructureUtilities.h index 27946659967..a430d492be9 100644 --- a/PWGJE/Core/JetSubstructureUtilities.h +++ b/PWGJE/Core/JetSubstructureUtilities.h @@ -33,7 +33,7 @@ #include "PWGJE/Core/FastJetUtilities.h" #include "PWGJE/Core/JetDerivedDataUtilities.h" #include "PWGJE/Core/JetFinder.h" -#include "PWGJE/Core/JetHFUtilities.h" +#include "PWGJE/Core/JetCandidateUtilities.h" #include "PWGJE/DataModel/Jet.h" #include "fastjet/contrib/Nsubjettiness.hh" #include "fastjet/contrib/AxesDefinition.hh" @@ -53,20 +53,20 @@ namespace jetsubstructureutilities * @param pseudoJet converted pseudoJet object which is passed by reference */ template -fastjet::ClusterSequenceArea jetToPseudoJet(T const& jet, U const& /*tracks*/, V const& /*clusters*/, O const& /*candidates*/, fastjet::PseudoJet& pseudoJet) +fastjet::ClusterSequenceArea jetToPseudoJet(T const& jet, U const& /*tracks*/, V const& /*clusters*/, O const& /*candidates*/, fastjet::PseudoJet& pseudoJet, int hadronicCorrectionType = 0) { std::vector jetConstituents; for (auto& jetConstituent : jet.template tracks_as()) { fastjetutilities::fillTracks(jetConstituent, jetConstituents, jetConstituent.globalIndex()); } - if constexpr (std::is_same_v, JetClusters::iterator> || std::is_same_v, JetClusters::filtered_iterator>) { + if constexpr (std::is_same_v, o2::aod::JetClusters::iterator> || std::is_same_v, o2::aod::JetClusters::filtered_iterator>) { for (auto& jetClusterConstituent : jet.template clusters_as()) { - fastjetutilities::fillClusters(jetClusterConstituent, jetConstituents, jetClusterConstituent.globalIndex()); + fastjetutilities::fillClusters(jetClusterConstituent, jetConstituents, jetClusterConstituent.globalIndex(), hadronicCorrectionType); } } - if constexpr (jethfutilities::isHFTable() || jethfutilities::isHFMcTable()) { - for (auto& jetHFConstituent : jet.template hfcandidates_as()) { - fastjetutilities::fillTracks(jetHFConstituent, jetConstituents, jetHFConstituent.globalIndex(), static_cast(JetConstituentStatus::candidateHF), jethfutilities::getTablePDGMass()); + if constexpr (jetcandidateutilities::isCandidateTable() || jetcandidateutilities::isCandidateMcTable()) { + for (auto& jetHFConstituent : jet.template candidates_as()) { + fastjetutilities::fillTracks(jetHFConstituent, jetConstituents, jetHFConstituent.globalIndex(), static_cast(JetConstituentStatus::candidate), jetcandidateutilities::getTablePDGMass()); } } std::vector jetReclustered; @@ -96,21 +96,21 @@ fastjet::ClusterSequenceArea jetToPseudoJet(T const& jet, U const& /*tracks*/, V // function that returns the N-subjettiness ratio and the distance betewwen the two axes considered for tau2, in the form of a vector template -std::vector getNSubjettiness(T const& jet, U const& tracks, V const& clusters, O const& candidates, int nMax, M const& reclusteringAlgorithm, bool doSoftDrop = false, float zCut = 0.1, float beta = 0.0) +std::vector getNSubjettiness(T const& jet, U const& tracks, V const& clusters, O const& candidates, std::vector::size_type nMax, M const& reclusteringAlgorithm, bool doSoftDrop = false, float zCut = 0.1, float beta = 0.0, int hadronicCorrectionType = 0) { std::vector result; fastjet::PseudoJet pseudoJet; - fastjet::ClusterSequenceArea clusterSeq(jetToPseudoJet(jet, tracks, clusters, candidates, pseudoJet)); + fastjet::ClusterSequenceArea clusterSeq(jetToPseudoJet(jet, tracks, clusters, candidates, pseudoJet, hadronicCorrectionType)); if (doSoftDrop) { fastjet::contrib::SoftDrop softDrop(beta, zCut); pseudoJet = softDrop(pseudoJet); } - for (auto n = 0; n < nMax + 1; n++) { + for (std::vector::size_type n = 0; n < nMax + 1; n++) { result.push_back(-1.0 * (n + 1)); } - for (auto n = 1; n <= nMax; n++) { + for (std::vector::size_type n = 1; n <= nMax; n++) { if (pseudoJet.constituents().size() < n) { // Tau_N needs at least N tracks return result; } diff --git a/PWGJE/Core/JetTaggingUtilities.h b/PWGJE/Core/JetTaggingUtilities.h index bd33bdf1cb8..885db9ff3c3 100644 --- a/PWGJE/Core/JetTaggingUtilities.h +++ b/PWGJE/Core/JetTaggingUtilities.h @@ -26,10 +26,16 @@ #include #include #include +#include +#include + +#include +#include "CommonConstants/PhysicsConstants.h" #include "TF1.h" #include "Framework/Logger.h" #include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" #include "PWGJE/Core/JetUtilities.h" enum JetTaggingSpecies { @@ -41,10 +47,92 @@ enum JetTaggingSpecies { gluon = 5 }; +enum BJetTaggingMethod { + IPsN1 = 0, + IPsN2 = 1, + IPsN3 = 2, + IPs3DN1 = 3, + IPs3DN2 = 4, + IPs3DN3 = 5, + SV = 6, + SV3D = 7 +}; + namespace jettaggingutilities { const int cmTomum = 10000; // using cm -> #mum for impact parameter (dca) +struct BJetParams { + float jetpT = 0.0; + float jetEta = 0.0; + float jetPhi = 0.0; + int nTracks = -1; + int nSV = -1; + float jetMass = 0.0; +}; + +struct BJetTrackParams { + double trackpT = 0.0; + double trackEta = 0.0; + double dotProdTrackJet = 0.0; + double dotProdTrackJetOverJet = 0.0; + double deltaRJetTrack = 0.0; + double signedIP2D = 0.0; + double signedIP2DSign = 0.0; + double signedIP3D = 0.0; + double signedIP3DSign = 0.0; + double momFraction = 0.0; + double deltaRTrackVertex = 0.0; + double trackPhi = 0.0; + double trackCharge = 0.0; + double trackITSChi2NCl = 0.0; + double trackTPCChi2NCl = 0.0; + double trackITSNCls = 0.0; + double trackTPCNCls = 0.0; + double trackTPCNCrossedRows = 0.0; + int trackOrigin = -1; + int trackVtxIndex = -1; +}; + +struct BJetSVParams { + double svpT = 0.0; + double deltaRSVJet = 0.0; + double svMass = 0.0; + double svfE = 0.0; + double svIPxy = 0.0; + double svCPA = 0.0; + double svChi2PCA = 0.0; + double dispersion = 0.0; + double decayLength2D = 0.0; + double decayLength2DError = 0.0; + double decayLength3D = 0.0; + double decayLength3DError = 0.0; +}; + +//________________________________________________________________________ +bool isBHadron(int pc) +{ + using o2::constants::physics::Pdg; + std::vector bPdG = {Pdg::kB0, Pdg::kBPlus, 10511, 10521, 513, 523, 10513, 10523, 20513, 20523, 20513, 20523, 515, 525, Pdg::kBS, 10531, 533, 10533, + 20533, 535, 541, 10541, 543, 10543, 20543, 545, 551, 10551, 100551, 110551, 200551, 210551, 553, 10553, 20553, + 30553, 100553, 110553, 120553, 130553, 200553, 210553, 220553, 300553, 9000533, 9010553, 555, 10555, 20555, + 100555, 110555, 120555, 200555, 557, 100557, Pdg::kLambdaB0, 5112, 5212, 5222, 5114, 5214, 5224, 5132, Pdg::kXiB0, 5312, 5322, + 5314, 5324, 5332, 5334, 5142, 5242, 5412, 5422, 5414, 5424, 5342, 5432, 5434, 5442, 5444, 5512, 5522, 5514, 5524, + 5532, 5534, 5542, 5544, 5554}; + + return (std::find(bPdG.begin(), bPdG.end(), std::abs(pc)) != bPdG.end()); +} +//________________________________________________________________________ +bool isCHadron(int pc) +{ + using o2::constants::physics::Pdg; + std::vector bPdG = {Pdg::kDPlus, Pdg::kD0, Pdg::kD0StarPlus, Pdg::kD0Star0, 413, 423, 10413, 10423, 20431, 20423, Pdg::kD2StarPlus, Pdg::kD2Star0, Pdg::kDS, 10431, Pdg::kDSStar, Pdg::kDS1, 20433, Pdg::kDS2Star, 441, + 10441, 100441, Pdg::kJPsi, 10443, Pdg::kChiC1, 100443, 30443, 9000443, 9010443, 9020443, 445, 100445, Pdg::kLambdaCPlus, Pdg::kSigmaCPlusPlus, 4212, Pdg::kSigmaC0, + 4224, 4214, 4114, Pdg::kXiCPlus, Pdg::kXiC0, 4322, 4312, 4324, 4314, Pdg::kOmegaC0, 4334, 4412, Pdg::kXiCCPlusPlus, 4414, 4424, 4432, 4434, 4444}; + + return (std::find(bPdG.begin(), bPdG.end(), std::abs(pc)) != bPdG.end()); +} + /** * returns the globalIndex of the earliest mother of a particle in the shower. returns -1 if a suitable mother is not found * @@ -108,18 +196,19 @@ int getOriginalHFMotherIndex(const typename T::iterator& hfparticle) * @param hftrack track passed as reference which is then replaced by the first track that originated from an HF shower */ template -int jetTrackFromHFShower(T const& jet, U const& /*tracks*/, V const& particles, typename U::iterator& hftrack) +int jetTrackFromHFShower(T const& jet, U const& /*tracks*/, V const& particles, typename U::iterator& hftrack, bool searchUpToQuark) { bool hasMcParticle = false; int origin = -1; - for (auto& track : jet.template tracks_as()) { + for (auto const& track : jet.template tracks_as()) { + hftrack = track; // for init if origin is 1 or 2, the track is not hftrack if (!track.has_mcParticle()) { continue; } hasMcParticle = true; auto const& particle = track.template mcParticle_as(); - origin = RecoDecay::getCharmHadronOrigin(particles, particle, true); + origin = RecoDecay::getParticleOrigin(particles, particle, searchUpToQuark); if (origin == 1 || origin == 2) { // 1=charm , 2=beauty hftrack = track; if (origin == 1) { @@ -130,6 +219,7 @@ int jetTrackFromHFShower(T const& jet, U const& /*tracks*/, V const& particles, } } } + if (hasMcParticle) { return JetTaggingSpecies::lightflavour; } else { @@ -145,12 +235,13 @@ int jetTrackFromHFShower(T const& jet, U const& /*tracks*/, V const& particles, * @param hfparticle particle passed as reference which is then replaced by the first track that originated from an HF shower */ template -int jetParticleFromHFShower(T const& jet, U const& particles, typename U::iterator& hfparticle) +int jetParticleFromHFShower(T const& jet, U const& particles, typename U::iterator& hfparticle, bool searchUpToQuark) { int origin = -1; - for (auto& particle : jet.template tracks_as()) { - origin = RecoDecay::getCharmHadronOrigin(particles, particle, true); + for (const auto& particle : jet.template tracks_as()) { + hfparticle = particle; // for init if origin is 1 or 2, the particle is not hfparticle + origin = RecoDecay::getParticleOrigin(particles, particle, searchUpToQuark); if (origin == 1 || origin == 2) { // 1=charm , 2=beauty hfparticle = particle; if (origin == 1) { @@ -173,11 +264,11 @@ int jetParticleFromHFShower(T const& jet, U const& particles, typename U::iterat */ template -int mcdJetFromHFShower(T const& jet, U const& tracks, V const& particles, float dRMax = 0.25) +int mcdJetFromHFShower(T const& jet, U const& tracks, V const& particles, float dRMax = 0.25, bool searchUpToQuark = false) { typename U::iterator hftrack; - int origin = jetTrackFromHFShower(jet, tracks, particles, hftrack); + int origin = jetTrackFromHFShower(jet, tracks, particles, hftrack, searchUpToQuark); if (origin == JetTaggingSpecies::charm || origin == JetTaggingSpecies::beauty) { if (!hftrack.has_mcParticle()) { return JetTaggingSpecies::none; @@ -213,12 +304,12 @@ int mcdJetFromHFShower(T const& jet, U const& tracks, V const& particles, float * @param dRMax maximum distance in eta-phi of initiating heavy-flavour quark from the jet axis */ -template -int mcpJetFromHFShower(T const& jet, U const& particles, float dRMax = 0.25) +template +int mcpJetFromHFShower(T const& jet, U const& particles, float dRMax = 0.25, bool searchUpToQuark = false) { typename U::iterator hfparticle; - int origin = jetParticleFromHFShower(jet, particles, hfparticle); + int origin = jetParticleFromHFShower(jet, particles, hfparticle, searchUpToQuark); if (origin == JetTaggingSpecies::charm || origin == JetTaggingSpecies::beauty) { int originalHFMotherIndex = getOriginalHFMotherIndex(hfparticle); @@ -256,7 +347,7 @@ int jetOrigin(T const& jet, U const& particles, float dRMax = 0.25) bool firstPartonFound = false; typename U::iterator parton1; typename U::iterator parton2; - for (auto& particle : particles) { + for (auto const& particle : particles) { if (std::abs(particle.getGenStatusCode() == 23)) { if (!firstPartonFound) { parton1 = particle; @@ -282,23 +373,132 @@ int jetOrigin(T const& jet, U const& particles, float dRMax = 0.25) return 0; } +/** + * return the jet flavor: 0 for lf-jet, 1 for c-jet, 2 for b-jet + * + * @param AnyJet the jet that we need to study its flavor + * @param AllMCParticles a vector of all the mc particles stack + */ +template +int16_t getJetFlavor(AnyJet const& jet, AllMCParticles const& mcparticles) +{ + bool charmQuark = false; + for (auto const& mcpart : mcparticles) { + int pdgcode = mcpart.pdgCode(); + if (std::abs(pdgcode) == 21 || (std::abs(pdgcode) >= 1 && std::abs(pdgcode) <= 5)) { + double dR = jetutilities::deltaR(jet, mcpart); + + if (dR < jet.r() / 100.f) { + if (std::abs(pdgcode) == 5) { + return JetTaggingSpecies::beauty; // Beauty jet + } else if (std::abs(pdgcode) == 4) { + charmQuark = true; + } + } + } + } + + if (charmQuark) { + return JetTaggingSpecies::charm; // Charm jet + } + + return JetTaggingSpecies::lightflavour; // Light flavor jet +} + +/** + * return the jet flavor if it finds a HF hadron inside the jet: 0 for lf-jet, 1 for c-jet, 2 for b-jet + * + * @param AnyJet the jet that we need to study its flavor + * @param AllMCParticles a vector of all the mc particles stack + */ +template +int16_t getJetFlavorHadron(AnyJet const& jet, AllMCParticles const& mcparticles) +{ + bool charmHadron = false; + + for (auto const& mcpart : mcparticles) { + int pdgcode = mcpart.pdgCode(); + if (isBHadron(pdgcode) || isCHadron(pdgcode)) { + double dR = jetutilities::deltaR(jet, mcpart); + + if (dR < jet.r() / 100.f) { + if (isBHadron(pdgcode)) { + return JetTaggingSpecies::beauty; // Beauty jet + } else if (isCHadron(pdgcode)) { + charmHadron = true; + } + } + } + } + + if (charmHadron) { + return JetTaggingSpecies::charm; // Charm jet + } + + return JetTaggingSpecies::lightflavour; // Light flavor jet +} + +/** + * return acceptance of track about DCA xy and z due to cut for QualityTracks + */ +template +bool trackAcceptanceWithDca(T const& track, float trackDcaXYMax, float trackDcaZMax) +{ + if (std::abs(track.dcaXY()) > trackDcaXYMax) + return false; + if (std::abs(track.dcaZ()) > trackDcaZMax) + return false; + return true; +} + +/** + * retrun acceptance of prong due to cut for high quality secondary vertex + */ +template +bool prongAcceptance(T const& prong, float prongChi2PCAMin, float prongChi2PCAMax, float prongsigmaLxyMax, float prongIPxyMin, float prongIPxyMax, bool doXYZ) +{ + if (prong.chi2PCA() < prongChi2PCAMin) + return false; + if (prong.chi2PCA() > prongChi2PCAMax) + return false; + if (std::abs(prong.impactParameterXY()) < prongIPxyMin) + return false; + if (std::abs(prong.impactParameterXY()) > prongIPxyMax) + return false; + + if (!doXYZ) { + if (prong.errorDecayLengthXY() > prongsigmaLxyMax) + return false; + } else { + if (prong.errorDecayLength() > prongsigmaLxyMax) + return false; + } + return true; +} + +/** + * retrun acceptance of secondary vertex due to cut for high quality secondary vertex + */ +template +bool svAcceptance(T const& sv, float svDispersionMax) +{ + if (sv.dispersion() > svDispersionMax) + return false; + return true; +} + /** * return geometric sign which is calculated scalar product between jet axis with DCA (track propagated to PV ) * positive and negative value are expected from primary vertex * positive value is expected from secondary vertex * - * @param collision which is needed external table of collision due to postion X and Y * @param jet - * @param track which is needed each DCA_X and Y which is measured in jettaggerhfExtension.cxx + * @param track which is needed aod::JTrackExtras */ -template -int getGeoSign(T const& collision, U const& jet, V const& track) +template +int getGeoSign(T const& jet, U const& track) { - auto trackPar = getTrackPar(track); - auto xyz = trackPar.getXYZGlo(); - auto dcaX = xyz.X() - collision.posX(); - auto dcaY = xyz.Y() - collision.posY(); - auto sign = TMath::Sign(1, dcaX * jet.px() + dcaY * jet.py() + track.dcaZ() * jet.pz()); + auto sign = TMath::Sign(1, track.dcaX() * jet.px() + track.dcaY() * jet.py() + track.dcaZ() * jet.pz()); if (sign < -1 || sign > 1) LOGF(info, Form("Sign is %d", sign)); return sign; @@ -308,38 +508,52 @@ int getGeoSign(T const& collision, U const& jet, V const& track) * Orders the tracks associated with a jet based on signed impact parameter significance and stores them * in a vector in descending order. */ -template > -void orderForIPJetTracks(T const& collision, U const& jet, V const& /*jtracks*/, W const& /*tracks*/, Vec& vecSignImpSig) +template > +void orderForIPJetTracks(T const& jet, U const& /*tracks*/, float trackDcaXYMax, float trackDcaZMax, Vec& vecSignImpSig, bool useIPxyz) { - for (auto& jtrack : jet.template tracks_as()) { - auto track = jtrack.template track_as(); - auto geoSign = getGeoSign(collision, jet, track); - auto varSignImpXYSig = geoSign * TMath::Abs(track.dcaXY()) / TMath::Sqrt(track.sigmaDcaXY2()); - vecSignImpSig.push_back(varSignImpXYSig); + for (auto const& track : jet.template tracks_as()) { + if (!trackAcceptanceWithDca(track, trackDcaXYMax, trackDcaZMax)) + continue; + auto geoSign = getGeoSign(jet, track); + float varSignImpSig; + if (!useIPxyz) { + varSignImpSig = geoSign * std::abs(track.dcaXY()) / track.sigmadcaXY(); + } else { + varSignImpSig = geoSign * std::abs(track.dcaXYZ()) / track.sigmadcaXYZ(); + } + vecSignImpSig.push_back(varSignImpSig); } std::sort(vecSignImpSig.begin(), vecSignImpSig.end(), std::greater()); } /** * Checks if a jet is greater than the given tagging working point based on the signed impact parameter significances + * return (true, true, true) if the jet is tagged by the 1st, 2nd and 3rd largest IPs */ -template -bool isGreaterThanTaggingPoint(T const& collision, U const& jet, V const& jtracks, W const& tracks, X const& taggingPoint = 1.0, Y const& cnt = 1) +template +std::tuple isGreaterThanTaggingPoint(T const& jet, U const& tracks, float trackDcaXYMax, float trackDcaZMax, float taggingPoint = 1.0, bool useIPxyz = false) { - if (cnt == 0) - return true; // untagged + bool taggedIPsN1 = false; + bool taggedIPsN2 = false; + bool taggedIPsN3 = false; std::vector vecSignImpSig; - orderForIPJetTracks(collision, jet, jtracks, tracks, vecSignImpSig); - if (vecSignImpSig.size() > cnt - 1) { - for (int i = 0; i < cnt; i++) { - if (0 < vecSignImpSig[i] && vecSignImpSig[i] < taggingPoint) { // tagger point set - return false; - } + orderForIPJetTracks(jet, tracks, trackDcaXYMax, trackDcaZMax, vecSignImpSig, useIPxyz); + if (vecSignImpSig.size() > 0) { + if (vecSignImpSig[0] > taggingPoint) { // tagger point set + taggedIPsN1 = true; } - } else { - return false; } - return true; + if (vecSignImpSig.size() > 1) { + if (vecSignImpSig[1] > taggingPoint) { // tagger point set + taggedIPsN2 = true; + } + } + if (vecSignImpSig.size() > 2) { + if (vecSignImpSig[2] > taggingPoint) { // tagger point set + taggedIPsN3 = true; + } + } + return std::make_tuple(taggedIPsN1, taggedIPsN2, taggedIPsN3); } /** @@ -353,7 +567,7 @@ template std::unique_ptr setResolutionFunction(T const& vecParams) { std::unique_ptr fResoFunc(new TF1("fResoFunc", "gaus(0)+expo(3)+expo(5)+expo(7)", -40, 0)); - for (int i = 0; i < vecParams.size(); i++) { + for (typename T::size_type i = 0; i < vecParams.size(); i++) { fResoFunc->SetParameter(i, vecParams[i]); } @@ -368,20 +582,20 @@ std::unique_ptr setResolutionFunction(T const& vecParams) * * @param fResoFuncjet The resolution function for the jet, used to model the distribution of impact * parameter significances for tracks associated with the jet. - * @param collision The collision event data, providing context for calculating geometric signs. - * @param jet The specific jet being analyzed. * @param track The track for which the probability is being calculated. * @param minSignImpXYSig The minimum significance of the impact parameter in the XY plane, used as - * the lower limit for integration of the resolution function. Defaults to -10. + * the lower limit for integration of the resolution function. Defaults to -40. * @return The calculated probability of the track being associated with the jet, based on its * impact parameter significance. */ -template -float getTrackProbability(T const& fResoFuncjet, U const& collision, V const& jet, W const& track, const float& minSignImpXYSig = -10) +template +float getTrackProbability(T const& fResoFuncjet, U const& track, float minSignImpXYSig = -40) { - float probTrack = 0.; - auto varSignImpXYSig = getGeoSign(collision, jet, track) * TMath::Abs(track.dcaXY()) / TMath::Sqrt(track.sigmaDcaXY2()); - probTrack = fResoFuncjet->Integral(minSignImpXYSig, -1 * TMath::Abs(varSignImpXYSig)) / fResoFuncjet->Integral(minSignImpXYSig, 0); + float probTrack = 0; + auto varSignImpXYSig = std::abs(track.dcaXY()) / track.sigmadcaXY(); + if (-varSignImpXYSig < minSignImpXYSig) + varSignImpXYSig = -minSignImpXYSig - 0.01; // To avoid overflow for integral + probTrack = fResoFuncjet->Integral(minSignImpXYSig, -varSignImpXYSig) / fResoFuncjet->Integral(minSignImpXYSig, 0); return probTrack; } @@ -396,8 +610,7 @@ float getTrackProbability(T const& fResoFuncjet, U const& collision, V const& je * assess its probability based on the impact parameter significance. * @param collision: The collision event data, necessary for geometric sign calculations. * @param jet: The jet for which the probability is being calculated. - * @param jtracks: Tracks in jets - * @param tracks: The original tracks to transform from jtracks. + * @param tracks: Tracks in jets * @param cnt: ordering number of impact parameter cnt=0: untagged, cnt=1: first, cnt=2: seconde, cnt=3: third. * @param tagPoint: tagging working point which is selected by condiered efficiency and puriy * @param minSignImpXYSig: To avoid over fitting @@ -405,38 +618,489 @@ float getTrackProbability(T const& fResoFuncjet, U const& collision, V const& je * specific flavor. Returns -1 if the jet contains fewer than two tracks with a positive * geometric sign. */ -template -float getJetProbability(T const& fResoFuncjet, U const& collision, V const& jet, W const& jtracks, X const& tracks, const int& cnt, const float& tagPoint = 1.0, const float& minSignImpXYSig = -10) +template +float getJetProbability(T const& fResoFuncjet, U const& jet, V const& /*tracks*/, float trackDcaXYMax, float trackDcaZMax, float minSignImpXYSig = -10) { - if (!(isGreaterThanTaggingPoint(collision, jet, jtracks, tracks, tagPoint, cnt))) + std::vector jetTracksPt; + float trackjetProb = 1.; + + for (auto const& track : jet.template tracks_as()) { + if (!trackAcceptanceWithDca(track, trackDcaXYMax, trackDcaZMax)) + continue; + + float probTrack = getTrackProbability(fResoFuncjet, track, minSignImpXYSig); + + auto geoSign = getGeoSign(jet, track); + if (geoSign > 0) { // only take positive sign track for JP calculation + trackjetProb *= probTrack; + jetTracksPt.push_back(track.pt()); + } + } + + float jetProb = -1.; + if (jetTracksPt.size() < 2) return -1; + float sumjetProb = 0.; + for (std::vector::size_type i = 0; i < jetTracksPt.size(); i++) { + sumjetProb += (std::pow(-1 * std::log(trackjetProb), static_cast(i)) / TMath::Factorial(i)); + } + + jetProb = trackjetProb * sumjetProb; + return jetProb; +} + +// overloading for the case of using resolution function for each pt range +template +float getJetProbability(std::vector> const& fResoFuncjets, U const& jet, V const& /*tracks*/, float trackDcaXYMax, float trackDcaZMax, float minSignImpXYSig = -10) +{ std::vector jetTracksPt; float trackjetProb = 1.; - for (auto& jtrack : jet.template tracks_as()) { - auto track = jtrack.template track_as(); + for (auto const& track : jet.template tracks_as()) { + if (!trackAcceptanceWithDca(track, trackDcaXYMax, trackDcaZMax)) + continue; - float probTrack = getTrackProbability(fResoFuncjet, collision, jet, track, minSignImpXYSig); + float probTrack = -1; + // choose the proper resolution function for the track based on its pt. + if (track.pt() >= 0.0 && track.pt() < 0.5) { + probTrack = getTrackProbability(fResoFuncjets.at(0), track, minSignImpXYSig); + } else if (track.pt() >= 0.5 && track.pt() < 1.0) { + probTrack = getTrackProbability(fResoFuncjets.at(1), track, minSignImpXYSig); + } else if (track.pt() >= 1.0 && track.pt() < 2.0) { + probTrack = getTrackProbability(fResoFuncjets.at(2), track, minSignImpXYSig); + } else if (track.pt() >= 2.0 && track.pt() < 4.0) { + probTrack = getTrackProbability(fResoFuncjets.at(3), track, minSignImpXYSig); + } else if (track.pt() >= 4.0 && track.pt() < 6.0) { + probTrack = getTrackProbability(fResoFuncjets.at(4), track, minSignImpXYSig); + } else if (track.pt() >= 6.0 && track.pt() < 9.0) { + probTrack = getTrackProbability(fResoFuncjets.at(5), track, minSignImpXYSig); + } else if (track.pt() >= 9.0) { + probTrack = getTrackProbability(fResoFuncjets.at(6), track, minSignImpXYSig); + } - auto geoSign = getGeoSign(collision, jet, track); + auto geoSign = getGeoSign(jet, track); if (geoSign > 0) { // only take positive sign track for JP calculation trackjetProb *= probTrack; jetTracksPt.push_back(track.pt()); } } - float JP = -1.; + float jetProb = -1.; if (jetTracksPt.size() < 2) return -1; float sumjetProb = 0.; - for (int i = 0; i < jetTracksPt.size(); i++) { - sumjetProb += (TMath::Power(-1 * TMath::Log(trackjetProb), i) / TMath::Factorial(i)); + for (std::vector::size_type i = 0; i < jetTracksPt.size(); i++) { + sumjetProb += (std::pow(-1 * std::log(trackjetProb), static_cast(i)) / TMath::Factorial(i)); + } + + jetProb = trackjetProb * sumjetProb; + return jetProb; +} + +// For secaondy vertex method utilites +template +typename ProngType::iterator jetFromProngMaxDecayLength(const JetType& jet, float const& prongChi2PCAMin, float prongChi2PCAMax, float prongsigmaLxyMax, float prongIPxyMin, float prongIPxyMax, bool doXYZ = false, bool* checkSv = nullptr) +{ + if (checkSv) + *checkSv = false; + float maxSxy = -1.0f; + typename ProngType::iterator bjetCand; + for (const auto& prong : jet.template secondaryVertices_as()) { + if (!prongAcceptance(prong, prongChi2PCAMin, prongChi2PCAMax, prongsigmaLxyMax, prongIPxyMin, prongIPxyMax, doXYZ)) + continue; + *checkSv = true; + float sxy = -1.0f; + if (!doXYZ) { + sxy = prong.decayLengthXY() / prong.errorDecayLengthXY(); + } else { + sxy = prong.decayLength() / prong.errorDecayLength(); + } + if (maxSxy < sxy) { + maxSxy = sxy; + bjetCand = prong; + } + } + return bjetCand; +} + +template +bool isTaggedJetSV(T const jet, U const& /*prongs*/, float prongChi2PCAMin, float prongChi2PCAMax, float prongsigmaLxyMax, float prongIPxyMin, float prongIPxyMax, float svDispersionMax, float doXYZ = false, float tagPointForSV = 15.) +{ + bool checkSv = false; + auto bjetCand = jetFromProngMaxDecayLength(jet, prongChi2PCAMin, prongChi2PCAMax, prongsigmaLxyMax, prongIPxyMin, prongIPxyMax, doXYZ, &checkSv); + if (!(checkSv && svAcceptance(bjetCand, svDispersionMax))) + return false; + if (!doXYZ) { + auto maxSxy = bjetCand.decayLengthXY() / bjetCand.errorDecayLengthXY(); + if (maxSxy < tagPointForSV) + return false; + } else { + auto maxSxyz = bjetCand.decayLength() / bjetCand.errorDecayLength(); + if (maxSxyz < tagPointForSV) + return false; + } + return true; +} + +template +uint16_t setTaggingIPBit(T const& jet, U const& tracks, V trackDcaXYMax, V trackDcaZMax, V tagPointForIP) +{ + uint16_t bit = 0; + auto [taggedIPsN1, taggedIPsN2, taggedIPsN3] = isGreaterThanTaggingPoint(jet, tracks, trackDcaXYMax, trackDcaZMax, tagPointForIP, false); + if (taggedIPsN1) { + SETBIT(bit, BJetTaggingMethod::IPsN1); + } + if (taggedIPsN2) { + SETBIT(bit, BJetTaggingMethod::IPsN2); + } + if (taggedIPsN3) { + SETBIT(bit, BJetTaggingMethod::IPsN3); + } + + auto [taggedIPs3DN1, taggedIPs3DN2, taggedIPs3DN3] = isGreaterThanTaggingPoint(jet, tracks, trackDcaXYMax, trackDcaZMax, tagPointForIP, true); + if (taggedIPs3DN1) { + SETBIT(bit, BJetTaggingMethod::IPs3DN1); + } + if (taggedIPs3DN2) { + SETBIT(bit, BJetTaggingMethod::IPs3DN2); + } + if (taggedIPs3DN3) { + SETBIT(bit, BJetTaggingMethod::IPs3DN3); + } + return bit; +} + +template +uint16_t setTaggingSVBit(T const& jet, U const& prongs, V prongChi2PCAMin, V prongChi2PCAMax, V prongsigmaLxyMax, float prongIPxyMin, float prongIPxyMax, V svDispersionMax, V tagPointForSV) +{ + uint16_t bit = 0; + if (isTaggedJetSV(jet, prongs, prongChi2PCAMin, prongChi2PCAMax, prongsigmaLxyMax, prongIPxyMin, prongIPxyMax, svDispersionMax, false, tagPointForSV)) { + SETBIT(bit, BJetTaggingMethod::SV); + } + if (isTaggedJetSV(jet, prongs, prongChi2PCAMin, prongChi2PCAMax, prongsigmaLxyMax, prongIPxyMin, prongIPxyMax, svDispersionMax, true, tagPointForSV)) { + SETBIT(bit, BJetTaggingMethod::SV3D); + } + return bit; +} + +/** + * Clusters jet constituent tracks into groups of tracks originating from same mcParticle position (trkVtxIndex), and finds each track origin (trkOrigin). (for GNN b-jet tagging) + * @param trkLabels Track labels for GNN vertex and track origin predictions. trkVtxIndex: The index value of each vertex (cluster) which is determined by the function. trkOrigin: The category of the track origin (0: not physical primary, 1: charm, 2: beauty, 3: primary vertex, 4: other secondary vertex). + * @param vtxResParam Vertex resolution parameter which determines the cluster size. (cm) + * @param trackPtMin Minimum value of track pT. + * @return The number of vertices (clusters) in the jet. + */ +template +int vertexClustering(AnyCollision const& collision, AnalysisJet const& jet, AnyTracks const&, AnyParticles const& particles, AnyOriginalParticles const&, std::unordered_map>& trkLabels, bool searchUpToQuark, float vtxResParam = 0.01 /* 0.01cm = 100um */, float trackPtMin = 0.5) +{ + const auto& tracks = jet.template tracks_as(); + const int nTrks = tracks.size(); + + // trkVtxIndex + + std::vector tempTrkVtxIndex; + + int i = 0; + for (const auto& constituent : tracks) { + if (!constituent.has_mcParticle() || !constituent.template mcParticle_as().isPhysicalPrimary() || constituent.pt() < trackPtMin) + tempTrkVtxIndex.push_back(-1); + else + tempTrkVtxIndex.push_back(i++); + } + tempTrkVtxIndex.push_back(i); // temporary index for PV + if (nTrks < 1) { // the process should be done for nTrks == 1 as well + trkLabels["trkVtxIndex"] = tempTrkVtxIndex; + return nTrks; + } + + int nPos = nTrks + 1; + std::vector dists(nPos * (nPos - 1) / 2); + auto trkPairIdx = [nPos](int ti, int tj) { + if (ti == tj || ti >= nPos || tj >= nPos || ti < 0 || tj < 0) { + LOGF(info, "Track pair index out of range"); + return -1; + } else { + return (ti < tj) ? (ti * nPos - (ti * (ti + 1)) / 2 + tj - ti - 1) : (tj * nPos - (tj * (tj + 1)) / 2 + ti - tj - 1); + } + }; // index nTrks is for PV + + for (int ti = 0; ti < nPos - 1; ti++) + for (int tj = ti + 1; tj < nPos; tj++) { + std::array posi, posj; + + if (tj < nTrks) { + if (tracks[tj].has_mcParticle()) { + const auto& pj = tracks[tj].template mcParticle_as().template mcParticle_as(); + posj = std::array{pj.vx(), pj.vy(), pj.vz()}; + } else { + dists[trkPairIdx(ti, tj)] = std::numeric_limits::max(); + continue; + } + } else { + posj = std::array{collision.posX(), collision.posY(), collision.posZ()}; + } + + if (tracks[ti].has_mcParticle()) { + const auto& pi = tracks[ti].template mcParticle_as().template mcParticle_as(); + posi = std::array{pi.vx(), pi.vy(), pi.vz()}; + } else { + dists[trkPairIdx(ti, tj)] = std::numeric_limits::max(); + continue; + } + + dists[trkPairIdx(ti, tj)] = RecoDecay::distance(posi, posj); + } + + int clusteri = -1, clusterj = -1; + float minMinDist = -1.f; // If there is an not-merge-able minDist pair, check the 2nd-minDist pair. + while (true) { + + float minDist = -1.f; // Get minDist pair + for (int ti = 0; ti < nPos - 1; ti++) + for (int tj = ti + 1; tj < nPos; tj++) + if (tempTrkVtxIndex[ti] != tempTrkVtxIndex[tj] && tempTrkVtxIndex[ti] >= 0 && tempTrkVtxIndex[tj] >= 0) { + float dist = dists[trkPairIdx(ti, tj)]; + if ((dist < minDist || minDist < 0.f) && dist > minMinDist) { + minDist = dist; + clusteri = ti; + clusterj = tj; + } + } + if (clusteri < 0 || clusterj < 0) + break; + + bool mrg = true; // Merge-ability check + for (int ti = 0; ti < nPos && mrg; ti++) + if (tempTrkVtxIndex[ti] == tempTrkVtxIndex[clusteri] && tempTrkVtxIndex[ti] >= 0) { + for (int tj = 0; tj < nPos && mrg; tj++) + if (tj != ti && tempTrkVtxIndex[tj] == tempTrkVtxIndex[clusterj] && tempTrkVtxIndex[tj] >= 0) { + if (dists[trkPairIdx(ti, tj)] > vtxResParam) { // If there is more distant pair compared to vtx_res between two clusters, they cannot be merged. + mrg = false; + minMinDist = minDist; + } + } + } + if (minDist > vtxResParam || minDist < 0.f) + break; + + if (mrg) { // Merge two clusters + int oldIndex = tempTrkVtxIndex[clusterj]; + for (int t = 0; t < nPos; t++) + if (tempTrkVtxIndex[t] == oldIndex) + tempTrkVtxIndex[t] = tempTrkVtxIndex[clusteri]; + } + } + + int nVertices = 0; + + // Sort the indices from PV (as 0) to the most distant SV (as 1~). + int idxPV = tempTrkVtxIndex[nTrks]; + for (int t = 0; t < nTrks; t++) + if (tempTrkVtxIndex[t] == idxPV) { + tempTrkVtxIndex[t] = -2; + nVertices = 1; // There is a track originating from PV + } + + std::unordered_map avgDistances; + std::unordered_map count; + for (int t = 0; t < nTrks; t++) { + if (tempTrkVtxIndex[t] >= 0) { + avgDistances[tempTrkVtxIndex[t]] += dists[trkPairIdx(t, nTrks)]; + count[tempTrkVtxIndex[t]]++; + } + } + + trkLabels["trkVtxIndex"] = std::vector(nTrks, -1); + if (count.size() != 0) { // If there is any SV cluster not only PV cluster + for (auto& [idx, avgDistance] : avgDistances) // o2-linter: disable=const-ref-in-for-loop + avgDistance /= count[idx]; + + nVertices += avgDistances.size(); + + std::vector> sortedIndices(avgDistances.begin(), avgDistances.end()); + std::sort(sortedIndices.begin(), sortedIndices.end(), [](const auto& a, const auto& b) { return a.second < b.second; }); + int rank = 1; + for (auto const& [idx, avgDistance] : sortedIndices) { + bool found = false; + for (int t = 0; t < nTrks; t++) + if (tempTrkVtxIndex[t] == idx) { + trkLabels["trkVtxIndex"][t] = rank; + found = true; + } + rank += found; + } + } + + for (int t = 0; t < nTrks; t++) + if (tempTrkVtxIndex[t] == -2) + trkLabels["trkVtxIndex"][t] = 0; + + // trkOrigin + + int trkIdx = 0; + for (auto const& constituent : jet.template tracks_as()) { + if (!constituent.has_mcParticle() || !constituent.template mcParticle_as().isPhysicalPrimary() || constituent.pt() < trackPtMin) { + trkLabels["trkOrigin"].push_back(0); + } else { + const auto& particle = constituent.template mcParticle_as(); + int orig = RecoDecay::getParticleOrigin(particles, particle, searchUpToQuark); + trkLabels["trkOrigin"].push_back((orig > 0) ? orig : (trkLabels["trkVtxIndex"][trkIdx] == 0) ? 3 + : 4); + } + + trkIdx++; + } + + return nVertices; +} + +// Looping over the SV info and putting them in the input vector +template +void analyzeJetSVInfo4ML(AnalysisJet const& myJet, AnyTracks const& /*allTracks*/, SecondaryVertices const& /*allSVs*/, std::vector& svsParams, float svPtMin = 1.0, int svReductionFactor = 3) +{ + using SVType = typename SecondaryVertices::iterator; + + // Min-heap to store the top 30 SVs by decayLengthXY/errorDecayLengthXY + auto compare = [](SVType& sv1, SVType& sv2) { + return (sv1.decayLengthXY() / sv1.errorDecayLengthXY()) > (sv2.decayLengthXY() / sv2.errorDecayLengthXY()); + }; + + auto svs = myJet.template secondaryVertices_as(); + + // Sort the SVs based on their decay length significance in descending order + // This is needed in order to select longest SVs since some jets could have thousands of SVs + std::sort(svs.begin(), svs.end(), compare); + + for (const auto& candSV : svs) { + + if (candSV.pt() < svPtMin) { + continue; + } + + double deltaRJetSV = jetutilities::deltaR(myJet, candSV); + double massSV = candSV.m(); + double energySV = candSV.e(); + + if (svsParams.size() < (svReductionFactor * myJet.template tracks_as().size())) { + svsParams.emplace_back(BJetSVParams{candSV.pt(), deltaRJetSV, massSV, energySV / myJet.energy(), candSV.impactParameterXY(), candSV.cpa(), candSV.chi2PCA(), candSV.dispersion(), candSV.decayLengthXY(), candSV.errorDecayLengthXY(), candSV.decayLength(), candSV.errorDecayLength()}); + } + } +} + +// Looping over the track info and putting them in the input vector +template +void analyzeJetTrackInfo4ML(AnalysisJet const& analysisJet, AnyTracks const& /*allTracks*/, SecondaryVertices const& /*allSVs*/, std::vector& tracksParams, float trackPtMin = 0.5) +{ + for (const auto& constituent : analysisJet.template tracks_as()) { + + if (constituent.pt() < trackPtMin) { + continue; + } + + double deltaRJetTrack = jetutilities::deltaR(analysisJet, constituent); + double dotProduct = RecoDecay::dotProd(std::array{analysisJet.px(), analysisJet.py(), analysisJet.pz()}, std::array{constituent.px(), constituent.py(), constituent.pz()}); + int sign = getGeoSign(analysisJet, constituent); + + float rClosestSV = 10.; + for (const auto& candSV : analysisJet.template secondaryVertices_as()) { + double deltaRTrackSV = jetutilities::deltaR(constituent, candSV); + if (deltaRTrackSV < rClosestSV) { + rClosestSV = deltaRTrackSV; + } + } + + tracksParams.emplace_back(BJetTrackParams{constituent.pt(), constituent.eta(), dotProduct, dotProduct / analysisJet.p(), deltaRJetTrack, std::abs(constituent.dcaXY()) * sign, constituent.sigmadcaXY(), std::abs(constituent.dcaXYZ()) * sign, constituent.sigmadcaXYZ(), constituent.p() / analysisJet.p(), rClosestSV}); + } + + auto compare = [](BJetTrackParams& tr1, BJetTrackParams& tr2) { + return (tr1.signedIP2D / tr1.signedIP2DSign) > (tr2.signedIP2D / tr2.signedIP2DSign); + }; + + // Sort the tracks based on their IP significance in descending order + std::sort(tracksParams.begin(), tracksParams.end(), compare); +} + +// Looping over the track info and putting them in the input vector without using any SV info +template +void analyzeJetTrackInfo4MLnoSV(AnalysisJet const& analysisJet, AnyTracks const& /*allTracks*/, std::vector& tracksParams, float trackPtMin = 0.5) +{ + for (const auto& constituent : analysisJet.template tracks_as()) { + + if (constituent.pt() < trackPtMin) { + continue; + } + + double deltaRJetTrack = jetutilities::deltaR(analysisJet, constituent); + double dotProduct = RecoDecay::dotProd(std::array{analysisJet.px(), analysisJet.py(), analysisJet.pz()}, std::array{constituent.px(), constituent.py(), constituent.pz()}); + int sign = getGeoSign(analysisJet, constituent); + + tracksParams.emplace_back(BJetTrackParams{constituent.pt(), constituent.eta(), dotProduct, dotProduct / analysisJet.p(), deltaRJetTrack, std::abs(constituent.dcaXY()) * sign, constituent.sigmadcaXY(), std::abs(constituent.dcaXYZ()) * sign, constituent.sigmadcaXYZ(), constituent.p() / analysisJet.p(), 0.0}); + } + + auto compare = [](BJetTrackParams& tr1, BJetTrackParams& tr2) { + return (tr1.signedIP2D / tr1.signedIP2DSign) > (tr2.signedIP2D / tr2.signedIP2DSign); + }; + + // Sort the tracks based on their IP significance in descending order + std::sort(tracksParams.begin(), tracksParams.end(), compare); +} + +// Looping over the track info and putting them in the input vector (for GNN b-jet tagging) +template +void analyzeJetTrackInfo4GNN(AnalysisJet const& analysisJet, AnyTracks const& /*allTracks*/, AnyOriginalTracks const& /*origTracks*/, std::vector>& tracksParams, float trackPtMin = 0.5, int64_t nMaxConstit = 40) +{ + for (const auto& constituent : analysisJet.template tracks_as()) { + + if (constituent.pt() < trackPtMin) { + continue; + } + + int sign = getGeoSign(analysisJet, constituent); + + auto origConstit = constituent.template track_as(); + + if (static_cast(tracksParams.size()) < nMaxConstit) { + tracksParams.emplace_back(std::vector{constituent.pt(), origConstit.phi(), constituent.eta(), static_cast(constituent.sign()), std::abs(constituent.dcaXY()) * sign, constituent.sigmadcaXY(), std::abs(constituent.dcaXYZ()) * sign, constituent.sigmadcaXYZ(), static_cast(origConstit.itsNCls()), static_cast(origConstit.tpcNClsFound()), static_cast(origConstit.tpcNClsCrossedRows()), origConstit.itsChi2NCl(), origConstit.tpcChi2NCl()}); + } else { + // If there are more than nMaxConstit constituents in the jet, select only nMaxConstit constituents with the highest DCA_XY significance. + size_t minIdx = 0; + for (size_t i = 0; i < tracksParams.size(); ++i) { + if (tracksParams[i][4] / tracksParams[i][5] < tracksParams[minIdx][4] / tracksParams[minIdx][5]) + minIdx = i; + } + if (std::abs(constituent.dcaXY()) * sign / constituent.sigmadcaXY() > tracksParams[minIdx][4] / tracksParams[minIdx][5]) + tracksParams[minIdx] = std::vector{constituent.pt(), origConstit.phi(), constituent.eta(), static_cast(constituent.sign()), std::abs(constituent.dcaXY()) * sign, constituent.sigmadcaXY(), std::abs(constituent.dcaXYZ()) * sign, constituent.sigmadcaXYZ(), static_cast(origConstit.itsNCls()), static_cast(origConstit.tpcNClsFound()), static_cast(origConstit.tpcNClsCrossedRows()), origConstit.itsChi2NCl(), origConstit.tpcChi2NCl()}; + } + } +} + +// Discriminant value for GNN b-jet tagging +template +T getDb(const std::vector& logits, double fC = 0.018) +{ + auto softmax = [](const std::vector& logits) { + std::vector res; + T maxLogit = *std::max_element(logits.begin(), logits.end()); + T sumLogit = 0.; + for (size_t i = 0; i < logits.size(); ++i) { + res.push_back(std::exp(logits[i] - maxLogit)); + sumLogit += res[i]; + } + for (size_t i = 0; i < logits.size(); ++i) { + res[i] /= sumLogit; + } + return res; + }; + + std::vector softmaxLogits = softmax(logits); + + if (softmaxLogits[1] == 0. && softmaxLogits[2] == 0.) { + LOG(debug) << "jettaggingutilities::Db, Divide by zero: softmaxLogits = (" << softmaxLogits[0] << ", " << softmaxLogits[1] << ", " << softmaxLogits[2] << ")"; } - JP = trackjetProb * sumjetProb; - return JP; + return std::log(softmaxLogits[0] / (fC * softmaxLogits[1] + (1. - fC) * softmaxLogits[2])); } }; // namespace jettaggingutilities diff --git a/PWGJE/Core/JetUtilities.h b/PWGJE/Core/JetUtilities.h index a681d76bf89..f1db864ef25 100644 --- a/PWGJE/Core/JetUtilities.h +++ b/PWGJE/Core/JetUtilities.h @@ -144,9 +144,17 @@ float deltaR(T const& A, U const& B) float dPhi = RecoDecay::constrainAngle(A.phi() - B.phi(), -M_PI); float dEta = A.eta() - B.eta(); - return TMath::Sqrt(dEta * dEta + dPhi * dPhi); + return std::sqrt(dEta * dEta + dPhi * dPhi); } +// same as deltaR but explicit specification of the eta and phi components +template +float deltaR(T const& eta1, U const& phi1, V const& eta2, W const& phi2) +{ + float dPhi = RecoDecay::constrainAngle(phi1 - phi2, -M_PI); + float dEta = eta1 - eta2; + return std::sqrt(dEta * dEta + dPhi * dPhi); +} }; // namespace jetutilities #endif // PWGJE_CORE_JETUTILITIES_H_ diff --git a/PWGJE/Core/JetV0Utilities.h b/PWGJE/Core/JetV0Utilities.h new file mode 100644 index 00000000000..3d12cd5d0a3 --- /dev/null +++ b/PWGJE/Core/JetV0Utilities.h @@ -0,0 +1,198 @@ +// 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 JetV0Utilities.h +/// \brief Jet V0 related utilities +/// +/// \author Nima Zardoshti + +#ifndef PWGJE_CORE_JETV0UTILITIES_H_ +#define PWGJE_CORE_JETV0UTILITIES_H_ + +#include +#include +#include +#include + +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/O2DatabasePDGPlugin.h" + +#include "Framework/Logger.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGJE/DataModel/EMCALClusters.h" + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/DerivedTables.h" + +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/DataModel/Jet.h" + +namespace jetv0utilities +{ + +/** + * returns true if the candidate is from a V0 table + */ +template +constexpr bool isV0Candidate() +{ + return std::is_same_v, o2::aod::CandidatesV0Data::iterator> || std::is_same_v, o2::aod::CandidatesV0Data::filtered_iterator> || std::is_same_v, o2::aod::CandidatesV0MCD::iterator> || std::is_same_v, o2::aod::CandidatesV0MCD::filtered_iterator>; +} + +/** + * returns true if the candidate is from a MC V0 table + */ +template +constexpr bool isV0McCandidate() +{ + return std::is_same_v, o2::aod::CandidatesV0MCP::iterator> || std::is_same_v, o2::aod::CandidatesV0MCP::filtered_iterator>; +} + +/** + * returns true if the table is a V0 table + */ +template +constexpr bool isV0Table() +{ + + return isV0Candidate() || isV0Candidate(); +} + +/** + * returns true if the table is a V0 MC table + */ +template +constexpr bool isV0McTable() +{ + return std::is_same_v, o2::aod::CandidatesV0MCP> || std::is_same_v, o2::soa::Filtered>; // note not optimal way but needed for jetfindingutilities::analyseParticles() +} + +/** + * returns true if the track is a daughter of the V0 candidate + * + * @param track track that is being checked + * @param candidate V0 candidate that is being checked + * @param tracks the track table + */ +template +bool isV0DaughterTrack(T& track, U& candidate, V const& /*tracks*/) +{ + if constexpr (isV0Candidate()) { + if (candidate.posTrackId() == track.globalIndex() || candidate.negTrackId() == track.globalIndex()) { + return true; + } else { + return false; + } + } else { + return false; + } +} + +/** + * returns the index of the JMcParticle matched to the V0 candidate + * + * @param candidate V0 candidate that is being checked + * @param tracks track table + * @param particles particle table + */ +template +auto matchedV0ParticleId(const T& candidate, const U& /*tracks*/, const V& /*particles*/) +{ + const auto candidateDaughterParticle = candidate.template posTrack_as().template mcParticle_as(); + return candidateDaughterParticle.template mothers_first_as().globalIndex(); // can we get the Id directly? +} + +/** + * returns the JMcParticle matched to the V0 candidate + * + * @param candidate v0 candidate that is being checked + * @param tracks track table + * @param particles particle table + */ +template +auto matchedV0Particle(const T& candidate, const U& /*tracks*/, const V& /*particles*/) +{ + const auto candidateDaughterParticle = candidate.template posTrack_as().template mcParticle_as(); + return candidateDaughterParticle.template mothers_first_as(); +} + +/** + * returns a slice of the table depending on the index of the V0 candidate + * + * @param candidate v0 candidate that is being checked + * @param table the table to be sliced + */ +template +auto slicedPerV0Candidate(T const& table, U const& candidate, V const& perV0Candidate) +{ + if constexpr (isV0Candidate()) { + return table.sliceBy(perV0Candidate, candidate.globalIndex()); + } else { + return table; + } +} + +template +bool isV0Particle(T const& particles, U const& particle) +{ + return RecoDecay::isMatchedMCGen(particles, particle, +kK0Short, std::array{+kPiPlus, -kPiPlus}, true) || RecoDecay::isMatchedMCGen(particles, particle, +kLambda0, std::array{+kProton, -kPiPlus}, true) || RecoDecay::isMatchedMCGen(particles, particle, -kLambda0, std::array{-kProton, +kPiPlus}, true); +} + +enum JV0ParticleDecays { + K0sToPiPi = 0, + LambdaToPPi = 1 +}; + +template +bool selectV0ParticleDecay(T const& v0Particle, int v0ParticleDecaySelection = -1) +{ + if (v0ParticleDecaySelection == -1) { + return true; + } + return (v0Particle.decayFlag() & (1 << v0ParticleDecaySelection)); +} + +int initialiseV0ParticleDecaySelection(std::string v0ParticleDecaySelection) +{ + if (v0ParticleDecaySelection == "K0sToPiPi") { + return JV0ParticleDecays::K0sToPiPi; + } else if (v0ParticleDecaySelection == "LambdaToPPi") { + return JV0ParticleDecays::LambdaToPPi; + } + return -1; +} + +template +uint8_t setV0ParticleDecayBit(T const& particles, U const& particle) +{ + uint8_t bit = 0; + if (RecoDecay::isMatchedMCGen(particles, particle, +kK0Short, std::array{+kPiPlus, -kPiPlus}, true)) { + SETBIT(bit, JV0ParticleDecays::K0sToPiPi); + } + if (RecoDecay::isMatchedMCGen(particles, particle, +kLambda0, std::array{+kProton, -kPiPlus}, true) || RecoDecay::isMatchedMCGen(particles, particle, -kLambda0, std::array{-kProton, +kPiPlus}, true)) { + SETBIT(bit, JV0ParticleDecays::LambdaToPPi); + } + return bit; +} + +}; // namespace jetv0utilities + +#endif // PWGJE_CORE_JETV0UTILITIES_H_ diff --git a/PWGJE/Core/MlResponseHfTagging.h b/PWGJE/Core/MlResponseHfTagging.h new file mode 100644 index 00000000000..8db76fe8d38 --- /dev/null +++ b/PWGJE/Core/MlResponseHfTagging.h @@ -0,0 +1,453 @@ +// 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 MlResponseHfTagging.h +/// \brief Class to compute the ML response for b-jet analysis +/// \author Hadi Hassan , University of Jyväskylä + +#ifndef PWGJE_CORE_MLRESPONSEHFTAGGING_H_ +#define PWGJE_CORE_MLRESPONSEHFTAGGING_H_ + +#include +#include +#include + +#include "Tools/ML/MlResponse.h" +#include "PWGJE/Core/JetTaggingUtilities.h" + +#if __has_include() +#include +#else +#include +#endif + +// Fill the map of available input features +// the key is the feature's name (std::string) +// the value is the corresponding value in EnumInputFeatures +#define FILL_MAP_BJET(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesBTag::FEATURE) \ + } + +// Check if the index of mCachedIndices (index associated to a FEATURE) +// matches the entry in EnumInputFeatures associated to this FEATURE +// if so, the VECTOR vector is filled with the FEATURE's value +// by calling the corresponding GETTER from OBJECT +#define CHECK_AND_FILL_VEC_BTAG_FULL(VECTOR, OBJECT, FEATURE, GETTER) \ + case static_cast(InputFeaturesBTag::FEATURE): { \ + VECTOR.emplace_back(OBJECT.GETTER); \ + break; \ + } + +// Specific case of CHECK_AND_FILL_VEC_BTAG_FULL(VECTOR, OBJECT, FEATURE, GETTER) +// where FEATURE = GETTER +#define CHECK_AND_FILL_VEC_BTAG(VECTOR, OBJECT, GETTER) \ + case static_cast(InputFeaturesBTag::GETTER): { \ + VECTOR.emplace_back(OBJECT.GETTER); \ + break; \ + } + +namespace o2::analysis +{ +enum class InputFeaturesBTag : uint8_t { + jetpT = 0, + jetEta, + jetPhi, + nTracks, + nSV, + jetMass, + trackpT, + trackEta, + dotProdTrackJet, + dotProdTrackJetOverJet, + deltaRJetTrack, + signedIP2D, + signedIP2DSign, + signedIP3D, + signedIP3DSign, + momFraction, + deltaRTrackVertex, + trackPhi, + trackCharge, + trackITSChi2NCl, + trackTPCChi2NCl, + trackITSNCls, + trackTPCNCls, + trackTPCNCrossedRows, + trackOrigin, + trackVtxIndex, + svpT, + deltaRSVJet, + svMass, + svfE, + svIPxy, + svCPA, + svChi2PCA, + dispersion, + decayLength2D, + decayLength2DError, + decayLength3D, + decayLength3DError, +}; + +template +class MlResponseHfTagging : public MlResponse +{ + public: + /// Default constructor + MlResponseHfTagging() = default; + /// Default destructor + virtual ~MlResponseHfTagging() = default; + + /// @brief Method to get the input shape of the model + /// @return A vector of input shapes + std::vector> getInputShape() const { return this->mModels[0].getInputShapes(); } + + /// Method to fill the inputs of jet, tracks and secondary vertices + /// \param jet is the b-jet candidate + /// \param tracks is the vector of tracks associated to the jet + /// \param svs is the vector of secondary vertices associated to the jet + /// \param jetInput the jet input features vector to be filled + /// \param trackInput the tracks input features vector to be filled + /// \param svInput the SVs input features vector to be filled + template + void fillInputFeatures(T1 const& jet, std::vector const& tracks, std::vector const& svs, std::vector& jetInput, std::vector& trackInput, std::vector& svInput) + { + + // Jet features + for (const auto& idx : MlResponse::mCachedIndices) { + switch (idx) { + CHECK_AND_FILL_VEC_BTAG(jetInput, jet, jetpT) + CHECK_AND_FILL_VEC_BTAG(jetInput, jet, jetEta) + CHECK_AND_FILL_VEC_BTAG(jetInput, jet, jetPhi) + CHECK_AND_FILL_VEC_BTAG(jetInput, jet, nTracks) + CHECK_AND_FILL_VEC_BTAG(jetInput, jet, nSV) + CHECK_AND_FILL_VEC_BTAG(jetInput, jet, jetMass) + + default: + break; + } + } + + // Track features + for (const auto& track : tracks) { + for (const auto& idx : MlResponse::mCachedIndices) { + switch (idx) { + CHECK_AND_FILL_VEC_BTAG(trackInput, track, trackpT) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, trackEta) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, dotProdTrackJet) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, dotProdTrackJetOverJet) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, deltaRJetTrack) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, signedIP2D) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, signedIP2DSign) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, signedIP3D) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, signedIP3DSign) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, momFraction) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, deltaRTrackVertex) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, trackPhi) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, trackCharge) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, trackITSChi2NCl) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, trackTPCChi2NCl) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, trackITSNCls) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, trackTPCNCls) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, trackTPCNCrossedRows) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, trackOrigin) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, trackVtxIndex) + + default: + break; + } + } + } + + // Secondary vertex features + for (const auto& sv : svs) { + for (const auto& idx : MlResponse::mCachedIndices) { + switch (idx) { + CHECK_AND_FILL_VEC_BTAG(svInput, sv, svpT) + CHECK_AND_FILL_VEC_BTAG(svInput, sv, deltaRSVJet) + CHECK_AND_FILL_VEC_BTAG(svInput, sv, svMass) + CHECK_AND_FILL_VEC_BTAG(svInput, sv, svfE) + CHECK_AND_FILL_VEC_BTAG(svInput, sv, svIPxy) + CHECK_AND_FILL_VEC_BTAG(svInput, sv, svCPA) + CHECK_AND_FILL_VEC_BTAG(svInput, sv, svChi2PCA) + CHECK_AND_FILL_VEC_BTAG(svInput, sv, dispersion) + CHECK_AND_FILL_VEC_BTAG(svInput, sv, decayLength2D) + CHECK_AND_FILL_VEC_BTAG(svInput, sv, decayLength2DError) + CHECK_AND_FILL_VEC_BTAG(svInput, sv, decayLength3D) + CHECK_AND_FILL_VEC_BTAG(svInput, sv, decayLength3DError) + + default: + break; + } + } + } + } + + /// Method to get the input features vector needed for ML inference in a 2D vector + /// \param jet is the b-jet candidate + /// \param tracks is the vector of tracks associated to the jet + /// \param svs is the vector of secondary vertices associated to the jet + /// \return inputFeatures vector + template + std::vector> getInputFeatures2D(T1 const& jet, std::vector const& tracks, std::vector const& svs) + { + + std::vector jetInput; + std::vector trackInput; + std::vector svInput; + + fillInputFeatures(jet, tracks, svs, jetInput, trackInput, svInput); + + std::vector> inputFeatures; + + inputFeatures.push_back(jetInput); + inputFeatures.push_back(trackInput); + inputFeatures.push_back(svInput); + + return inputFeatures; + } + + /// Method to get the input features vector needed for ML inference in a 1D vector + /// \param jet is the b-jet candidate + /// \param tracks is the vector of tracks associated to the jet + /// \param svs is the vector of secondary vertices associated to the jet + /// \return inputFeatures vector + template + std::vector getInputFeatures1D(T1 const& jet, std::vector const& tracks, std::vector const& svs) + { + + std::vector jetInput; + std::vector trackInput; + std::vector svInput; + + fillInputFeatures(jet, tracks, svs, jetInput, trackInput, svInput); + + std::vector inputFeatures; + + inputFeatures.insert(inputFeatures.end(), jetInput.begin(), jetInput.end()); + inputFeatures.insert(inputFeatures.end(), trackInput.begin(), trackInput.end()); + inputFeatures.insert(inputFeatures.end(), svInput.begin(), svInput.end()); + + return inputFeatures; + } + + protected: + /// Method to fill the map of available input features + void setAvailableInputFeatures() + { + MlResponse::mAvailableInputFeatures = { + // Jet features + FILL_MAP_BJET(jetpT), + FILL_MAP_BJET(jetEta), + FILL_MAP_BJET(jetPhi), + FILL_MAP_BJET(nTracks), + FILL_MAP_BJET(nSV), + FILL_MAP_BJET(jetMass), + + // Track features + FILL_MAP_BJET(trackpT), + FILL_MAP_BJET(trackEta), + FILL_MAP_BJET(dotProdTrackJet), + FILL_MAP_BJET(dotProdTrackJetOverJet), + FILL_MAP_BJET(deltaRJetTrack), + FILL_MAP_BJET(signedIP2D), + FILL_MAP_BJET(signedIP2DSign), + FILL_MAP_BJET(signedIP3D), + FILL_MAP_BJET(signedIP3DSign), + FILL_MAP_BJET(momFraction), + FILL_MAP_BJET(deltaRTrackVertex), + FILL_MAP_BJET(trackPhi), + FILL_MAP_BJET(trackCharge), + FILL_MAP_BJET(trackITSChi2NCl), + FILL_MAP_BJET(trackTPCChi2NCl), + FILL_MAP_BJET(trackITSNCls), + FILL_MAP_BJET(trackTPCNCls), + FILL_MAP_BJET(trackTPCNCrossedRows), + FILL_MAP_BJET(trackOrigin), + FILL_MAP_BJET(trackVtxIndex), + + // Secondary vertex features + FILL_MAP_BJET(svpT), + FILL_MAP_BJET(deltaRSVJet), + FILL_MAP_BJET(svMass), + FILL_MAP_BJET(svfE), + FILL_MAP_BJET(svIPxy), + FILL_MAP_BJET(svCPA), + FILL_MAP_BJET(svChi2PCA), + FILL_MAP_BJET(dispersion), + FILL_MAP_BJET(decayLength2D), + FILL_MAP_BJET(decayLength2DError), + FILL_MAP_BJET(decayLength3D), + FILL_MAP_BJET(decayLength3DError)}; + } +}; + +// ONNX Runtime tensor (Ort::Value) allocator for using customized inputs of ML models. +class TensorAllocator +{ + protected: +#if !__has_include() + Ort::MemoryInfo memInfo; +#endif + public: + TensorAllocator() +#if !__has_include() + : memInfo(Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault)) +#endif + { + } + ~TensorAllocator() = default; + template + Ort::Value createTensor(std::vector& input, std::vector& inputShape) + { +#if __has_include() + return Ort::Experimental::Value::CreateTensor(input.data(), input.size(), inputShape); +#else + return Ort::Value::CreateTensor(memInfo, input.data(), input.size(), inputShape.data(), inputShape.size()); +#endif + } +}; + +// TensorAllocator for GNN b-jet tagger +class GNNBjetAllocator : public TensorAllocator +{ + private: + int64_t nJetFeat; + int64_t nTrkFeat; + int64_t nFlav; + int64_t nTrkOrigin; + int64_t maxNNodes; + + std::vector tfJetMean; + std::vector tfJetStdev; + std::vector tfTrkMean; + std::vector tfTrkStdev; + + std::vector> edgesList; + + // Jet feature normalization + template + T jetFeatureTransform(T feat, int idx) const + { + return (feat - tfJetMean[idx]) / tfJetStdev[idx]; + } + + // Track feature normalization + template + T trkFeatureTransform(T feat, int idx) const + { + return (feat - tfTrkMean[idx]) / tfTrkStdev[idx]; + } + + // Edge input of GNN (fully-connected graph) + void setEdgesList(void) + { + for (int64_t nNodes = 0; nNodes <= maxNNodes; ++nNodes) { + std::vector> edges; + // Generate all permutations of (i, j) where i != j + for (int64_t i = 0; i < nNodes; ++i) { + for (int64_t j = 0; j < nNodes; ++j) { + if (i != j) { + edges.emplace_back(i, j); + } + } + } + // Add self-loops (i, i) + for (int64_t i = 0; i < nNodes; ++i) { + edges.emplace_back(i, i); + } + // Flatten + std::vector flattenedEdges; + for (const auto& edge : edges) { + flattenedEdges.push_back(edge.first); + } + for (const auto& edge : edges) { + flattenedEdges.push_back(edge.second); + } + edgesList.push_back(flattenedEdges); + } + } + + // Replace NaN in a vector into value + template + static int replaceNaN(std::vector& vec, T value) + { + int numNaN = 0; + for (auto& el : vec) { // o2-linter: disable=const-ref-in-for-loop + if (std::isnan(el)) { + el = value; + ++numNaN; + } + } + return numNaN; + } + + public: + GNNBjetAllocator() : TensorAllocator(), nJetFeat(4), nTrkFeat(13), nFlav(3), nTrkOrigin(5), maxNNodes(40) {} + GNNBjetAllocator(int64_t nJetFeat, int64_t nTrkFeat, int64_t nFlav, int64_t nTrkOrigin, std::vector& tfJetMean, std::vector& tfJetStdev, std::vector& tfTrkMean, std::vector& tfTrkStdev, int64_t maxNNodes = 40) + : TensorAllocator(), nJetFeat(nJetFeat), nTrkFeat(nTrkFeat), nFlav(nFlav), nTrkOrigin(nTrkOrigin), maxNNodes(maxNNodes), tfJetMean(tfJetMean), tfJetStdev(tfJetStdev), tfTrkMean(tfTrkMean), tfTrkStdev(tfTrkStdev) + { + setEdgesList(); + } + ~GNNBjetAllocator() = default; + + // Copy operator for initializing GNNBjetAllocator using Configurable values + GNNBjetAllocator& operator=(const GNNBjetAllocator& other) + { + nJetFeat = other.nJetFeat; + nTrkFeat = other.nTrkFeat; + nFlav = other.nFlav; + nTrkOrigin = other.nTrkOrigin; + maxNNodes = other.maxNNodes; + tfJetMean = other.tfJetMean; + tfJetStdev = other.tfJetStdev; + tfTrkMean = other.tfTrkMean; + tfTrkStdev = other.tfTrkStdev; + setEdgesList(); + return *this; + } + + // Allocate & Return GNN input tensors (std::vector) + template + void getGNNInput(std::vector& jetFeat, std::vector>& trkFeat, std::vector& feat, std::vector& gnnInput) + { + int64_t nNodes = trkFeat.size(); + + std::vector edgesShape{2, nNodes * nNodes}; + gnnInput.emplace_back(createTensor(edgesList[nNodes], edgesShape)); + + std::vector featShape{nNodes, nJetFeat + nTrkFeat}; + + int numNaN = replaceNaN(jetFeat, 0.f); + for (auto& aTrkFeat : trkFeat) { // o2-linter: disable=const-ref-in-for-loop + for (size_t i = 0; i < jetFeat.size(); ++i) + feat.push_back(jetFeatureTransform(jetFeat[i], i)); + numNaN += replaceNaN(aTrkFeat, 0.f); + for (size_t i = 0; i < aTrkFeat.size(); ++i) + feat.push_back(trkFeatureTransform(aTrkFeat[i], i)); + } + + gnnInput.emplace_back(createTensor(feat, featShape)); + + if (numNaN > 0) { + LOGF(info, "NaN found in GNN input feature, number of NaN: %d", numNaN); + } + } +}; + +} // namespace o2::analysis + +#undef FILL_MAP_BJET +#undef CHECK_AND_FILL_VEC_BTAG_FULL +#undef CHECK_AND_FILL_VEC_BTAG + +#endif // PWGJE_CORE_MLRESPONSEHFTAGGING_H_ diff --git a/PWGJE/Core/utilsBcSelEMC.h b/PWGJE/Core/utilsBcSelEMC.h new file mode 100644 index 00000000000..1796d130d7f --- /dev/null +++ b/PWGJE/Core/utilsBcSelEMC.h @@ -0,0 +1,185 @@ +// 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 utilsBcSelEMC.h +/// \brief BC selection utilities for EMCal QA +/// \author Marvin Hemmer , Goethe-University + +#ifndef PWGJE_CORE_UTILSBCSELEMC_H_ +#define PWGJE_CORE_UTILSBCSELEMC_H_ + +#include // std::shared_ptr +#include // std::string + +#include "Framework/Configurable.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" +#include "Framework/OutputObjHeader.h" + +#include "Common/CCDB/EventSelectionParams.h" + +namespace o2::emc_evsel +{ +// event rejection types +enum EventRejection { + None = 0, + Trigger, + TvxTrigger, + TimeFrameBorderCut, + ItsRofBorderCut, + IsGoodZvtxFT0vsPV, + NoSameBunchPileup, + NoCollInTimeRangeNarrow, + NoCollInTimeRangeStandard, + NoCollInRofStandard, + NEventRejection +}; + +o2::framework::AxisSpec axisEvents = {EventRejection::NEventRejection, -0.5f, +EventRejection::NEventRejection - 0.5f, ""}; + +/// \brief Function to put labels on monitoring histogram +/// \param hRejection monitoring histogram +template +void setEventRejectionLabels(Histo& hRejection) +{ + // Puts labels on the bc monitoring histogram. + hRejection->GetXaxis()->SetBinLabel(EventRejection::None + 1, "All"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::Trigger + 1, "Sel8"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::TvxTrigger + 1, "TVX Trigger"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::TimeFrameBorderCut + 1, "TF border"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::ItsRofBorderCut + 1, "ITS ROF border"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::IsGoodZvtxFT0vsPV + 1, "PV #it{z} consistency FT0 timing"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::NoSameBunchPileup + 1, "No same-bunch pile-up"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::NoCollInTimeRangeNarrow + 1, "No coll timerange narrow"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::NoCollInTimeRangeStandard + 1, "No coll timerange strict"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::NoCollInRofStandard + 1, "No coll in ROF std"); +} + +struct EMCEventSelection : o2::framework::ConfigurableGroup { + std::string prefix = "emcBcSel"; // JSON group name + // event selection parameters (in chronological order of application) + o2::framework::Configurable useSel8Trigger{"useSel8Trigger", true, "Apply the sel8 event selection"}; + o2::framework::Configurable triggerClass{"triggerClass", -1, "Trigger class different from sel8 (e.g. kINT7 for Run2) used only if useSel8Trigger is false"}; + o2::framework::Configurable useTvxTrigger{"useTvxTrigger", true, "Apply TVX trigger sel"}; + o2::framework::Configurable useTimeFrameBorderCut{"useTimeFrameBorderCut", true, "Apply TF border cut"}; + o2::framework::Configurable useItsRofBorderCut{"useItsRofBorderCut", true, "Apply ITS ROF border cut"}; + o2::framework::Configurable useIsGoodZvtxFT0vsPV{"useIsGoodZvtxFT0vsPV", false, "Check consistency between PVz from central barrel with that from FT0 timing"}; + o2::framework::Configurable useNoSameBunchPileup{"useNoSameBunchPileup", false, "Exclude collisions in bunches with more than 1 reco. PV"}; + o2::framework::Configurable useNoCollInTimeRangeNarrow{"useNoCollInTimeRangeNarrow", false, "Reject collisions in time range narrow"}; + o2::framework::Configurable useNoCollInTimeRangeStandard{"useNoCollInTimeRangeStandard", false, "Reject collisions in time range strict"}; + o2::framework::Configurable useNoCollInRofStandard{"useNoCollInRofStandard", false, "Reject collisions in ROF standard"}; + + // histogram names + static constexpr char NameHistBCs[] = "hBCs"; + + std::shared_ptr hBCs; + + int currentRun{-1}; + + /// \brief Adds bc monitoring histograms in the histogram registry. + /// \param registry reference to the histogram registry + void addHistograms(o2::framework::HistogramRegistry& registry) + { + hBCs = registry.add(NameHistBCs, "EMC event counter;;# of accepted collisions", {o2::framework::HistType::kTH1D, {axisEvents}}); + setEventRejectionLabels(hBCs); + } + + /// \brief Applies event selection. + /// \tparam useEvSel use information from the EvSel table + /// \param bc bc to test against the selection criteria + /// \return bitmask with the event selection criteria not satisfied by the bc + template + uint16_t getEMCCollisionRejectionMask(const Bc& bc) + { + uint16_t rejectionMask{0}; // 16 bits, in case new ev. selections will be added + + if constexpr (useEvSel) { + /// trigger condition + bool sel8 = bc.selection_bit(o2::aod::evsel::kIsBBT0A) && bc.selection_bit(o2::aod::evsel::kIsBBT0C); + if ((useSel8Trigger && sel8) || (!useSel8Trigger && triggerClass > -1 && !bc.alias_bit(triggerClass))) { + SETBIT(rejectionMask, EventRejection::Trigger); + } + /// TVX trigger selection + if (useTvxTrigger && !bc.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + SETBIT(rejectionMask, EventRejection::TvxTrigger); + } + /// time frame border cut + if (useTimeFrameBorderCut && !bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + SETBIT(rejectionMask, EventRejection::TimeFrameBorderCut); + } + /// ITS rof border cut + if (useItsRofBorderCut && !bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + SETBIT(rejectionMask, EventRejection::ItsRofBorderCut); + } + /// PVz consistency tracking - FT0 timing + if (useIsGoodZvtxFT0vsPV && !bc.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + SETBIT(rejectionMask, EventRejection::IsGoodZvtxFT0vsPV); + } + /// remove collisions in bunches with more than 1 reco bc + /// POTENTIALLY BAD FOR BEAUTY ANALYSES + if (useNoSameBunchPileup && !bc.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + SETBIT(rejectionMask, EventRejection::NoSameBunchPileup); + } + /// No collisions in time range narrow + if (useNoCollInTimeRangeNarrow && !bc.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + SETBIT(rejectionMask, EventRejection::NoCollInTimeRangeNarrow); + } + /// No collisions in time range strict + if (useNoCollInTimeRangeStandard && !bc.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + SETBIT(rejectionMask, EventRejection::NoCollInTimeRangeStandard); + } + /// No collisions in ROF standard + if (useNoCollInRofStandard && !bc.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + SETBIT(rejectionMask, EventRejection::NoCollInRofStandard); + } + } + return rejectionMask; + } + + /// \brief Fills histograms for monitoring event selections satisfied by the bc. + /// \param rejectionMask bitmask storing the info about which ev. selections are not satisfied by the bc + void fillHistograms(const uint16_t rejectionMask) + { + hBCs->Fill(EventRejection::None); + for (std::size_t reason = 1; reason < EventRejection::NEventRejection; reason++) { + if (TESTBIT(rejectionMask, reason)) { + return; + } + hBCs->Fill(reason); + } + } +}; + +struct EMCEventSelectionMc { + // event selection parameters (in chronological order of application) + bool useSel8Trigger{false}; // Apply the Sel8 selection + bool useTvxTrigger{false}; // Apply the TVX trigger + bool useTimeFrameBorderCut{true}; // Apply TF border cut + bool useItsRofBorderCut{false}; // Apply the ITS RO frame border cut + + void configureFromDevice(const o2::framework::DeviceSpec& device) + { + for (const auto& option : device.options) { + if (option.name.compare("emcEvSel.useSel8Trigger") == 0) { + useSel8Trigger = option.defaultValue.get(); + } else if (option.name.compare("emcEvSel.useTvxTrigger") == 0) { + useTvxTrigger = option.defaultValue.get(); + } else if (option.name.compare("emcEvSel.useTimeFrameBorderCut") == 0) { + useTimeFrameBorderCut = option.defaultValue.get(); + } else if (option.name.compare("emcEvSel.useItsRofBorderCut") == 0) { + useItsRofBorderCut = option.defaultValue.get(); + } + } + } +}; +} // namespace o2::emc_evsel + +#endif // PWGJE_CORE_UTILSBCSELEMC_H_ diff --git a/PWGJE/DataModel/EMCALClusterDefinition.h b/PWGJE/DataModel/EMCALClusterDefinition.h index d3480c29366..ead4a14dde7 100644 --- a/PWGJE/DataModel/EMCALClusterDefinition.h +++ b/PWGJE/DataModel/EMCALClusterDefinition.h @@ -9,11 +9,9 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -// Class for the cluster definition, i.e. what is considered a cluster by the clusterizer. -// The cluster definition contains information about the used algorithm, seed threshold, -// cell energy, gradient as well as timing cut -// -/// \author Florian Jonas +/// \file EMCALClusterDefinition.h +/// \brief Class for the cluster definition, i.e. what is considered a cluster by the clusterizer. The cluster definition contains information about the used algorithm, seed threshold, cell energy, gradient as well as timing cut +/// \author Florian Jonas , Marvin Hemmer #ifndef PWGJE_DATAMODEL_EMCALCLUSTERDEFINITION_H_ #define PWGJE_DATAMODEL_EMCALCLUSTERDEFINITION_H_ @@ -38,15 +36,17 @@ struct EMCALClusterDefinition { std::string name = "kUndefined"; // name of the cluster definition double seedEnergy = 0.1; // seed threshold (GeV) double minCellEnergy = 0.05; // minimum cell energy (GeV) - double timeMin = -10000; // minimum time (ns) - double timeMax = 10000; // maximum time (ns) + double timeMin = -10000.; // minimum time (ns) + double timeMax = 10000.; // maximum time (ns) + double timeDiff = 20000.; // maximum time difference (ns) between seed cell and aggregation cell bool doGradientCut = true; // apply gradient cut if true double gradientCut = -1; // gradient cut + bool recalcShowerShape5x5 = false; // recalculate shower shape using 5x5 cells // default constructor EMCALClusterDefinition() = default; // constructor - EMCALClusterDefinition(ClusterAlgorithm_t pAlgorithm, int pStorageID, int pSelectedCellType, std::string pName, double pSeedEnergy, double pMinCellEnergy, double pTimeMin, double pTimeMax, bool pDoGradientCut, double pGradientCut) + EMCALClusterDefinition(ClusterAlgorithm_t pAlgorithm, int pStorageID, int pSelectedCellType, std::string pName, double pSeedEnergy, double pMinCellEnergy, double pTimeMin, double pTimeMax, double ptimeDiff, bool pDoGradientCut, double pGradientCut, bool precalcShowerShape5x5) { algorithm = pAlgorithm; storageID = pStorageID; @@ -56,14 +56,16 @@ struct EMCALClusterDefinition { minCellEnergy = pMinCellEnergy; timeMin = pTimeMin; timeMax = pTimeMax; + timeDiff = ptimeDiff; doGradientCut = pDoGradientCut; gradientCut = pGradientCut; + recalcShowerShape5x5 = precalcShowerShape5x5; } // implement comparison operators for int std::string and ClusterAlgorithm_t bool operator==(const EMCALClusterDefinition& rhs) const { - return (algorithm == rhs.algorithm && storageID == rhs.storageID && name == rhs.name && seedEnergy == rhs.seedEnergy && minCellEnergy == rhs.minCellEnergy && timeMin == rhs.timeMin && timeMax == rhs.timeMax && gradientCut == rhs.gradientCut && doGradientCut == rhs.doGradientCut); + return (algorithm == rhs.algorithm && storageID == rhs.storageID && name == rhs.name && seedEnergy == rhs.seedEnergy && minCellEnergy == rhs.minCellEnergy && timeMin == rhs.timeMin && timeMax == rhs.timeMax && timeDiff == rhs.timeDiff && gradientCut == rhs.gradientCut && doGradientCut == rhs.doGradientCut && recalcShowerShape5x5 == rhs.recalcShowerShape5x5); } bool operator!=(const EMCALClusterDefinition& rhs) const { diff --git a/PWGJE/DataModel/EMCALClusters.h b/PWGJE/DataModel/EMCALClusters.h index c3aa23fac84..c634b4b017e 100644 --- a/PWGJE/DataModel/EMCALClusters.h +++ b/PWGJE/DataModel/EMCALClusters.h @@ -9,8 +9,8 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -// Table definitions for EMCAL analysis clusters -// +/// \file EMCALClusters.h +/// \brief Table definitions for EMCAL analysis clusters /// \author Raymond Ehlers , ORNL #ifndef PWGJE_DATAMODEL_EMCALCLUSTERS_H_ @@ -27,32 +27,64 @@ namespace emcalcluster { // define global cluster definitions -// the V1 algorithm is not yet implemented, but the V3 algorithm is // New definitions should be added here! -const EMCALClusterDefinition kV1Default(ClusterAlgorithm_t::kV1, 0, 1, "kV1Default", 0.5, 0.1, -10000, 10000, true, 0.03); // dummy -const EMCALClusterDefinition kV1Variation1(ClusterAlgorithm_t::kV3, 1, 1, "kV1Variation1", 0.3, 0.1, -10000, 10000, true, 0.03); // dummy -const EMCALClusterDefinition kV1Variation2(ClusterAlgorithm_t::kV3, 2, 1, "kV1Variation2", 0.2, 0.1, -10000, 10000, true, 0.03); // dummy -const EMCALClusterDefinition kV3Default(ClusterAlgorithm_t::kV3, 10, 1, "kV3Default", 0.5, 0.1, -10000, 10000, true, 0.03); -const EMCALClusterDefinition kV3Variation1(ClusterAlgorithm_t::kV3, 11, 1, "kV3Variation1", 0.5, 0.1, -10000, 10000, true, 0.); -const EMCALClusterDefinition kV3Variation2(ClusterAlgorithm_t::kV3, 12, 1, "kV3Variation2", 0.5, 0.1, -10000, 10000, false, 0.); +const EMCALClusterDefinition kV3NoSplit(ClusterAlgorithm_t::kV3, 0, 1, "kV3NoSplit", 0.5, 0.1, -10000, 10000, 20000, false, 0., false); +const EMCALClusterDefinition kV3NoSplitLowSeed(ClusterAlgorithm_t::kV3, 1, 1, "kV3NoSplitLowSeed", 0.3, 0.1, -10000, 10000, 20000, false, 0., false); +const EMCALClusterDefinition kV3NoSplitLowerSeed(ClusterAlgorithm_t::kV3, 2, 1, "kV3NoSplitLowerSeed", 0.2, 0.1, -10000, 10000, 20000, false, 0., false); +const EMCALClusterDefinition kV3Default(ClusterAlgorithm_t::kV3, 10, 1, "kV3Default", 0.5, 0.1, -10000, 10000, 20000, true, 0.03, false); +const EMCALClusterDefinition kV3MostSplit(ClusterAlgorithm_t::kV3, 11, 1, "kV3MostSplit", 0.5, 0.1, -10000, 10000, 20000, true, 0., false); +const EMCALClusterDefinition kV3LowSeed(ClusterAlgorithm_t::kV3, 12, 1, "kV3LowSeed", 0.3, 0.1, -10000, 10000, 20000, true, 0.03, false); +const EMCALClusterDefinition kV3MostSplitLowSeed(ClusterAlgorithm_t::kV3, 13, 1, "kV3MostSplitLowSeed", 0.3, 0.1, -10000, 10000, 20000, true, 0., false); +const EMCALClusterDefinition kV3StrictTime(ClusterAlgorithm_t::kV3, 20, 1, "kV3StrictTime", 0.5, 0.1, -500, 500, 20000, true, 0.03, false); +const EMCALClusterDefinition kV3StricterTime(ClusterAlgorithm_t::kV3, 21, 1, "kV3StricterTime", 0.5, 0.1, -100, 100, 20000, true, 0.03, false); +const EMCALClusterDefinition kV3MostStrictTime(ClusterAlgorithm_t::kV3, 22, 1, "kV3MostStrictTime", 0.5, 0.1, -50, 50, 20000, true, 0.03, false); +const EMCALClusterDefinition kV3Default5x5(ClusterAlgorithm_t::kV3, 30, 1, "kV3Default5x5", 0.5, 0.1, -10000, 10000, 20000, true, 0.03, true); +const EMCALClusterDefinition kV3SmallTimeDiff(ClusterAlgorithm_t::kV3, 40, 1, "kV3SmallTimeDiff", 0.5, 0.1, -10000, 10000, 500, true, 0.03, false); +const EMCALClusterDefinition kV3SmallerTimeDiff(ClusterAlgorithm_t::kV3, 41, 1, "kV3SmallerTimeDiff", 0.5, 0.1, -10000, 10000, 100, true, 0.03, false); +const EMCALClusterDefinition kV3SmallestTimeDiff(ClusterAlgorithm_t::kV3, 42, 1, "kV3SmallestTimeDiff", 0.5, 0.1, -10000, 10000, 50, true, 0.03, false); +const EMCALClusterDefinition kV3MostSplitSmallTimeDiff(ClusterAlgorithm_t::kV3, 43, 1, "kV3MostSplitSmallTimeDiff", 0.5, 0.1, -10000, 10000, 500, true, 0., false); +const EMCALClusterDefinition kV3MostSplitSmallerTimeDiff(ClusterAlgorithm_t::kV3, 44, 1, "kV3MostSplitSmallerTimeDiff", 0.5, 0.1, -10000, 10000, 100, true, 0., false); +const EMCALClusterDefinition kV3MostSplitSmallestTimeDiff(ClusterAlgorithm_t::kV3, 45, 1, "kV3MostSplitSmallestTimeDiff", 0.5, 0.1, -10000, 10000, 50, true, 0., false); /// \brief function returns EMCALClusterDefinition for the given name /// \param name name of the cluster definition /// \return EMCALClusterDefinition for the given name const EMCALClusterDefinition getClusterDefinitionFromString(const std::string& clusterDefinitionName) { - if (clusterDefinitionName == "kV1Default") { - return kV1Default; - } else if (clusterDefinitionName == "kV1Variation1") { - return kV1Variation1; - } else if (clusterDefinitionName == "kV1Variation2") { - return kV1Variation2; + if (clusterDefinitionName == "kV3NoSplit") { + return kV3NoSplit; + } else if (clusterDefinitionName == "kV3NoSplitLowSeed") { + return kV3NoSplitLowSeed; + } else if (clusterDefinitionName == "kV3NoSplitLowerSeed") { + return kV3NoSplitLowerSeed; } else if (clusterDefinitionName == "kV3Default") { return kV3Default; - } else if (clusterDefinitionName == "kV3Variation1") { - return kV3Variation1; - } else if (clusterDefinitionName == "kV3Variation2") { - return kV3Variation2; + } else if (clusterDefinitionName == "kV3MostSplit") { + return kV3MostSplit; + } else if (clusterDefinitionName == "kV3LowSeed") { + return kV3LowSeed; + } else if (clusterDefinitionName == "kV3MostSplitLowSeed") { + return kV3MostSplitLowSeed; + } else if (clusterDefinitionName == "kV3StrictTime") { + return kV3StrictTime; + } else if (clusterDefinitionName == "kV3StricterTime") { + return kV3StricterTime; + } else if (clusterDefinitionName == "kV3MostStrictTime") { + return kV3MostStrictTime; + } else if (clusterDefinitionName == "kV3Default5x5") { + return kV3Default5x5; + } else if (clusterDefinitionName == "kV3SmallTimeDiff") { + return kV3SmallTimeDiff; + } else if (clusterDefinitionName == "kV3SmallerTimeDiff") { + return kV3SmallerTimeDiff; + } else if (clusterDefinitionName == "kV3SmallestTimeDiff") { + return kV3SmallestTimeDiff; + } else if (clusterDefinitionName == "kV3MostSplitSmallTimeDiff") { + return kV3MostSplitSmallTimeDiff; + } else if (clusterDefinitionName == "kV3MostSplitSmallerTimeDiff") { + return kV3MostSplitSmallerTimeDiff; + } else if (clusterDefinitionName == "kV3MostSplitSmallestTimeDiff") { + return kV3MostSplitSmallestTimeDiff; } else { throw std::invalid_argument("Cluster definition name not recognized"); } @@ -103,6 +135,12 @@ DECLARE_SOA_TABLE(EMCALMCClusters, "AOD", "EMCALMCCLUSTERS", //! using EMCALMCCluster = EMCALMCClusters::iterator; +// table of cluster MC info that could not be matched to a collision +DECLARE_SOA_TABLE(EMCALAmbiguousMCClusters, "AOD", "EMCALAMBMCCLS", //! + emcalclustermc::McParticleIds, emcalclustermc::AmplitudeA); + +using EMCALAmbiguousMCCluster = EMCALAmbiguousMCClusters::iterator; + namespace emcalclustercell { // declare index column pointing to cluster table diff --git a/PWGJE/DataModel/GammaJetAnalysisTree.h b/PWGJE/DataModel/GammaJetAnalysisTree.h new file mode 100644 index 00000000000..7d468a339e7 --- /dev/null +++ b/PWGJE/DataModel/GammaJetAnalysisTree.h @@ -0,0 +1,80 @@ +// 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 Table definitions for gamma-jet analyses +/// +/// \author Florian Jonas + +#ifndef PWGJE_DATAMODEL_GAMMAJETANALYSISTREE_H_ +#define PWGJE_DATAMODEL_GAMMAJETANALYSISTREE_H_ + +#include "Framework/AnalysisDataModel.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" + +namespace o2::aod +{ + +namespace gjevent +{ // TODO add rho //! event index +DECLARE_SOA_COLUMN(Multiplicity, multiplicity, float); +DECLARE_SOA_COLUMN(Centrality, centrality, float); +DECLARE_SOA_COLUMN(Rho, rho, float); +DECLARE_SOA_COLUMN(EventSel, eventSel, uint8_t); +DECLARE_SOA_COLUMN(Occupancy, occupancy, int); +DECLARE_SOA_BITMAP_COLUMN(Alias, alias, 32); +} // namespace gjevent +DECLARE_SOA_TABLE(GjEvents, "AOD", "GJEVENT", o2::soa::Index<>, gjevent::Multiplicity, gjevent::Centrality, gjevent::Rho, gjevent::EventSel, gjevent::Occupancy, gjevent::Alias) + +using GjEvent = GjEvents::iterator; + +namespace gjgamma +{ +DECLARE_SOA_INDEX_COLUMN(GjEvent, gjevent); //! event index +DECLARE_SOA_COLUMN(Energy, energy, float); //! cluster energy (GeV) +DECLARE_SOA_COLUMN(Definition, definition, int); //! cluster definition, see EMCALClusterDefinition.h +DECLARE_SOA_COLUMN(Eta, eta, float); //! cluster pseudorapidity (calculated using vertex) +DECLARE_SOA_COLUMN(Phi, phi, float); //! cluster azimuthal angle (calculated using vertex) +DECLARE_SOA_COLUMN(M02, m02, float); //! shower shape long axis +DECLARE_SOA_COLUMN(M20, m20, float); //! shower shape short axis +DECLARE_SOA_COLUMN(NCells, nCells, ushort); //! number of cells in cluster +DECLARE_SOA_COLUMN(Time, time, float); //! cluster time (ns) +DECLARE_SOA_COLUMN(IsExotic, isExotic, bool); //! flag to mark cluster as exotic +DECLARE_SOA_COLUMN(DistanceToBadChannel, distanceToBadChannel, float); //! distance to bad channel +DECLARE_SOA_COLUMN(NLM, nlm, ushort); //! number of local maxima +DECLARE_SOA_COLUMN(IsoRaw, isoraw, ushort); //! isolation in cone not corrected for Rho +DECLARE_SOA_COLUMN(PerpConeRho, perpconerho, float); //! rho in perpendicular cone +DECLARE_SOA_COLUMN(TMdeltaPhi, tmdeltaphi, float); //! delta phi between cluster and closest match +DECLARE_SOA_COLUMN(TMdeltaEta, tmdeltaeta, float); //! delta eta between cluster and closest match +DECLARE_SOA_COLUMN(TMtrackP, tmtrackp, float); //! track momentum of closest match, -1 if no match found +} // namespace gjgamma +DECLARE_SOA_TABLE(GjGammas, "AOD", "GJGAMMA", + gjgamma::GjEventId, gjgamma::Energy, gjgamma::Definition, gjgamma::Eta, gjgamma::Phi, gjgamma::M02, gjgamma::M20, gjgamma::NCells, gjgamma::Time, gjgamma::IsExotic, gjgamma::DistanceToBadChannel, gjgamma::NLM, gjgamma::IsoRaw, gjgamma::PerpConeRho, gjgamma::TMdeltaPhi, gjgamma::TMdeltaEta, gjgamma::TMtrackP) +namespace gjchjet +{ +DECLARE_SOA_INDEX_COLUMN(GjEvent, gjevent); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Radius, radius, float); +DECLARE_SOA_COLUMN(Energy, energy, float); +DECLARE_SOA_COLUMN(Mass, mass, float); +DECLARE_SOA_COLUMN(Area, area, float); +DECLARE_SOA_COLUMN(LeadingTrackPt, leadingtrackpt, float); +DECLARE_SOA_COLUMN(PerpConeRho, perpconerho, float); +DECLARE_SOA_COLUMN(NConstituents, nConstituents, ushort); +} // namespace gjchjet +DECLARE_SOA_TABLE(GjChargedJets, "AOD", "GJCHJET", gjchjet::GjEventId, gjchjet::Pt, gjchjet::Eta, gjchjet::Phi, gjchjet::Radius, gjchjet::Energy, gjchjet::Mass, gjchjet::Area, gjchjet::LeadingTrackPt, gjchjet::PerpConeRho, gjchjet::NConstituents) +} // namespace o2::aod + +#endif // PWGJE_DATAMODEL_GAMMAJETANALYSISTREE_H_ diff --git a/PWGJE/DataModel/Jet.h b/PWGJE/DataModel/Jet.h index a4cbdc03c09..8db401ffc48 100644 --- a/PWGJE/DataModel/Jet.h +++ b/PWGJE/DataModel/Jet.h @@ -28,10 +28,14 @@ #include "PWGJE/DataModel/EMCALClusters.h" #include "PWGJE/DataModel/JetReducedData.h" #include "PWGJE/DataModel/JetReducedDataHF.h" +#include "PWGJE/DataModel/JetReducedDataV0.h" +#include "PWGJE/DataModel/JetReducedDataDQ.h" #include "PWGJE/DataModel/JetSubtraction.h" #include "PWGHF/DataModel/DerivedTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" namespace o2::aod { @@ -57,7 +61,6 @@ DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! absolute p [](float pt, float eta) -> float { return pt * std::cosh(eta); }); } // namespace jet -} // namespace o2::aod // Defines the jet table definition #define DECLARE_JET_TABLE(_collision_name_, _jet_type_, _name_, _description_) \ @@ -95,19 +98,19 @@ DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! absolute p DECLARE_SOA_ARRAY_INDEX_COLUMN_FULL(_jet_type_, matchedJetCand, int32_t, _jet_type_##s, "_hf"); \ } -#define DECLARE_CONSTITUENTS_TABLE(_jet_type_, _name_, _Description_, _track_type_, _cand_type_) \ - namespace _name_##constituents \ - { \ - DECLARE_SOA_INDEX_COLUMN(_jet_type_, jet); \ - DECLARE_SOA_ARRAY_INDEX_COLUMN(_track_type_, tracks); \ - DECLARE_SOA_ARRAY_INDEX_COLUMN(JCluster, clusters); \ - DECLARE_SOA_ARRAY_INDEX_COLUMN_FULL(HfCandidates, hfcandidates, int32_t, _cand_type_, "_hfcand"); \ - } \ - DECLARE_SOA_TABLE(_jet_type_##Constituents, "AOD", _Description_ "C", \ - _name_##constituents::_jet_type_##Id, \ - _name_##constituents::_track_type_##Ids, \ - _name_##constituents::JClusterIds, \ - _name_##constituents::HfCandidatesIds); +#define DECLARE_CONSTITUENTS_TABLE(_jet_type_, _name_, _Description_, _track_type_, _cand_type_) \ + namespace _name_##constituents \ + { \ + DECLARE_SOA_INDEX_COLUMN(_jet_type_, jet); \ + DECLARE_SOA_ARRAY_INDEX_COLUMN(_track_type_, tracks); \ + DECLARE_SOA_ARRAY_INDEX_COLUMN(JCluster, clusters); \ + DECLARE_SOA_ARRAY_INDEX_COLUMN_FULL(Candidates, candidates, int32_t, _cand_type_, "_cand"); \ + } \ + DECLARE_SOA_TABLE(_jet_type_##Constituents, "AOD", _Description_ "C", \ + _name_##constituents::_jet_type_##Id, \ + _name_##constituents::_track_type_##Ids, \ + _name_##constituents::JClusterIds, \ + _name_##constituents::CandidatesIds); // combine definition of tables for jets, constituents #define DECLARE_JET_TABLES(_collision_name_, _jet_type_, _track_type_, _hfcand_type_, _description_) \ @@ -149,51 +152,112 @@ DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! absolute p DECLARE_JETMATCHING_TABLE(_jet_type_##MCParticleLevel, _jet_type_##MCDetectorLevel, _shortname_ "JETP2D") \ DECLARE_MCEVENTWEIGHT_TABLE(_jet_type_##MCDetectorLevel, _jet_type_##MCDetectorLevel, _shortname_ "DJETMW") \ DECLARE_MCEVENTWEIGHT_TABLE(_jet_type_##MCParticleLevel, _jet_type_##MCParticleLevel, _shortname_ "PETMPW") \ - DECLARE_JET_TABLES(JCollision, _jet_type_##EventWiseSubtracted, _subtracted_track_type_, _hfcand_type_, _shortname_ "JETEWS") \ + DECLARE_JET_TABLES(JCollision, _jet_type_##EventWiseSubtracted, _subtracted_track_type_, _hfcand_type_, _shortname_ "EWSJET") \ DECLARE_JETMATCHING_TABLE(_jet_type_, _jet_type_##EventWiseSubtracted, _shortname_ "JET2EWS") \ - DECLARE_JETMATCHING_TABLE(_jet_type_##EventWiseSubtracted, _jet_type_, _shortname_ "JETEWS2") \ - DECLARE_JET_TABLES(JCollision, _jet_type_##MCDetectorLevelEventWiseSubtracted, _subtracted_track_type_, _hfcand_type_, _shortname_ "DJETEWS") \ + DECLARE_JETMATCHING_TABLE(_jet_type_##EventWiseSubtracted, _jet_type_, _shortname_ "EWSJET2") \ + DECLARE_JET_TABLES(JCollision, _jet_type_##MCDetectorLevelEventWiseSubtracted, _subtracted_track_type_, _hfcand_type_, _shortname_ "DEWSJET") \ DECLARE_MCEVENTWEIGHT_TABLE(_jet_type_##MCDetectorLevelEventWiseSubtracted, _jet_type_##MCDetectorLevelEventWiseSubtracted, _shortname_ "DJETEWSW") \ DECLARE_JETMATCHING_TABLE(_jet_type_##MCDetectorLevel, _jet_type_##MCDetectorLevelEventWiseSubtracted, _shortname_ "DJET2DEWS") \ - DECLARE_JETMATCHING_TABLE(_jet_type_##MCDetectorLevelEventWiseSubtracted, _jet_type_##MCDetectorLevel, _shortname_ "JETDEWS2D") \ - DECLARE_JET_TABLES(JMcCollision, _jet_type_##MCParticleLevelEventWiseSubtracted, _subtracted_track_type_, _hfparticle_type_, _shortname_ "PJETEWS") -namespace o2::aod -{ + DECLARE_JETMATCHING_TABLE(_jet_type_##MCDetectorLevelEventWiseSubtracted, _jet_type_##MCDetectorLevel, _shortname_ "DEWSJET2D") \ + DECLARE_JET_TABLES(JMcCollision, _jet_type_##MCParticleLevelEventWiseSubtracted, _subtracted_track_type_, _hfparticle_type_, _shortname_ "PEWSJET") + +#define STRINGIFY(x) #x + +// add duplicate tables for each predefined jet table so that the same jets can be run with multiple settings +#define DECLARE_JET_DUPLICATE_TABLES_LEVELS(_jet_type_, _subtracted_track_type_, _hfcand_type_, _hfparticle_type_, _shortname_, _duplicatenumber_) \ + DECLARE_JET_TABLES_LEVELS(_jet_type_##_duplicatenumber_, _subtracted_track_type_, _hfcand_type_, _hfparticle_type_, _shortname_ STRINGIFY(_duplicatenumber_)) \ + DECLARE_JETMATCHING_TABLE(_jet_type_, _jet_type_##_duplicatenumber_, _shortname_ "JET2" STRINGIFY(_duplicatenumber_)) \ + DECLARE_JETMATCHING_TABLE(_jet_type_##_duplicatenumber_, _jet_type_, _shortname_ "JET" STRINGIFY(_duplicatenumber_) "2") \ + DECLARE_JETMATCHING_TABLE(_jet_type_##MCDetectorLevel, _jet_type_##_duplicatenumber_##MCDetectorLevel, _shortname_ "JETD2" STRINGIFY(_duplicatenumber_)) \ + DECLARE_JETMATCHING_TABLE(_jet_type_##_duplicatenumber_##MCDetectorLevel, _jet_type_##MCDetectorLevel, _shortname_ "JET" STRINGIFY(_duplicatenumber_) "2D") \ + DECLARE_JETMATCHING_TABLE(_jet_type_##MCParticleLevel, _jet_type_##_duplicatenumber_##MCParticleLevel, _shortname_ "JETP2" STRINGIFY(_duplicatenumber_)) \ + DECLARE_JETMATCHING_TABLE(_jet_type_##_duplicatenumber_##MCParticleLevel, _jet_type_##MCParticleLevel, _shortname_ "JET" STRINGIFY(_duplicatenumber_) "2P") \ + DECLARE_JETMATCHING_TABLE(_jet_type_##EventWiseSubtracted, _jet_type_##_duplicatenumber_##EventWiseSubtracted, _shortname_ "JETEWS2" STRINGIFY(_duplicatenumber_)) \ + DECLARE_JETMATCHING_TABLE(_jet_type__duplicatenumber_##EventWiseSubtracted, _jet_type_##EventWiseSubtracted, _shortname_ "JET" STRINGIFY(_duplicatenumber_) "2EWS") + DECLARE_JET_TABLES_LEVELS(Charged, JTrackSub, HfD0Bases, HfD0PBases, "C"); DECLARE_JET_TABLES_LEVELS(Full, JTrackSub, HfD0Bases, HfD0PBases, "F"); DECLARE_JET_TABLES_LEVELS(Neutral, JTrackSub, HfD0Bases, HfD0PBases, "N"); DECLARE_JET_TABLES_LEVELS(D0Charged, JTrackD0Sub, HfD0Bases, HfD0PBases, "D0"); -DECLARE_JET_TABLES_LEVELS(LcCharged, JTrackLcSub, Hf3PBases, Hf3PPBases, "Lc"); -DECLARE_JET_TABLES_LEVELS(BplusCharged, JTrackBplusSub, HfCandBplus, HfD0PBases, "BPl"); +DECLARE_JET_TABLES_LEVELS(DplusCharged, JTrackDplusSub, HfDplusBases, HfDplusPBases, "DP"); +DECLARE_JET_TABLES_LEVELS(LcCharged, JTrackLcSub, HfLcBases, HfLcPBases, "Lc"); +DECLARE_JET_TABLES_LEVELS(BplusCharged, JTrackBplusSub, HfBplusBases, HfBplusPBases, "BP"); +DECLARE_JET_TABLES_LEVELS(V0Charged, JTrackSub, V0Cores, JV0Mcs, "V0"); +DECLARE_JET_TABLES_LEVELS(DielectronCharged, JTrackSub, Dielectrons, JDielectronMcs, "DIEL"); -} // namespace o2::aod +// duplicate jet tables (added as needed for analyses) +DECLARE_JET_DUPLICATE_TABLES_LEVELS(Charged, JTrackSub, HfD0Bases, HfD0PBases, "C", 1); + +#undef DECLARE_JET_TABLE +#undef DECLARE_CONSTITUENTS_TABLE +#undef DECLARE_JET_TABLES +#undef DECLARE_JETMATCHING_TABLE +#undef DECLARE_MCEVENTWEIGHT_TABLE +#undef DECLARE_JET_TABLES_LEVELS +#undef STRINGIFY +#undef DECLARE_JET_DUPLICATE_TABLES_LEVELS -using JetCollisions = o2::aod::JCollisions; +using JetCollisions = o2::soa::Join; using JetCollision = JetCollisions::iterator; -using JetCollisionsMCD = o2::soa::Join; -using JetTracks = o2::aod::JTracks; -using JetTracksMCD = o2::soa::Join; -using JetTracksSub = o2::aod::JTrackSubs; -using JetClusters = o2::aod::JClusters; +using JetCollisionsMCD = o2::soa::Join; +using JetCollisionMCD = o2::soa::Join::iterator; +using JetTracks = JTracks; +using JetTracksMCD = o2::soa::Join; +using JetTracksSub = JTrackSubs; +using JetClusters = o2::soa::Join; +using JetClustersMCD = o2::soa::Join; -using JetMcCollisions = o2::aod::JMcCollisions; +using JetMcCollisions = JMcCollisions; using JetMcCollision = JetMcCollisions::iterator; -using JetParticles = o2::aod::JMcParticles; +using JetParticles = JMcParticles; +using JetParticlesSub = JMcParticleSubs; + +using CollisionsD0 = o2::soa::Join; +using CandidatesD0Data = o2::soa::Join; +using CandidatesD0MCD = o2::soa::Join; +using JetTracksSubD0 = JTrackD0Subs; +using JetParticlesSubD0 = JMcParticleD0Subs; +using McCollisionsD0 = o2::soa::Join; +using CandidatesD0MCP = o2::soa::Join; -using CandidatesD0MCP = o2::soa::Join; -using CandidatesLcMCP = o2::soa::Join; -using CandidatesBplusMCP = o2::soa::Join; +using CollisionsDplus = o2::soa::Join; +using CandidatesDplusData = o2::soa::Join; +using CandidatesDplusMCD = o2::soa::Join; +using JetTracksSubDplus = JTrackDplusSubs; +using JetParticlesSubDplus = JMcParticleDplusSubs; +using McCollisionsDplus = o2::soa::Join; +using CandidatesDplusMCP = o2::soa::Join; -using CandidatesD0Data = o2::soa::Join; -using CandidatesD0MCD = o2::soa::Join; -using JetTracksSubD0 = o2::aod::JTrackD0Subs; +using CollisionsLc = o2::soa::Join; +using CandidatesLcData = o2::soa::Join; +using CandidatesLcMCD = o2::soa::Join; +using JetTracksSubLc = JTrackLcSubs; +using JetParticlesSubLc = JMcParticleLcSubs; +using McCollisionsLc = o2::soa::Join; +using CandidatesLcMCP = o2::soa::Join; -using CandidatesBplusData = o2::soa::Join; -using CandidatesBplusMCD = o2::soa::Join; -using JetTracksSubBplus = o2::aod::JTrackBplusSubs; +using CollisionsBplus = o2::soa::Join; +using CandidatesBplusData = o2::soa::Join; +using CandidatesBplusMCD = o2::soa::Join; +using JetTracksSubBplus = JTrackBplusSubs; +using JetParticlesSubBplus = JMcParticleBplusSubs; +using McCollisionsBplus = o2::soa::Join; +using CandidatesBplusMCP = o2::soa::Join; -using CandidatesLcData = o2::soa::Join; -using CandidatesLcMCD = o2::soa::Join; -using JetTracksSubLc = o2::aod::JTrackLcSubs; +using CandidatesV0Data = o2::soa::Join; +using CandidatesV0MCD = o2::soa::Join; +// using V0Daughters = DauTrackExtras; +using McCollisionsV0 = o2::soa::Join; +using CandidatesV0MCP = o2::soa::Join; + +using CollisionsDielectron = o2::soa::Join; +using CandidatesDielectronData = o2::soa::Join; +using CandidatesDielectronMCD = o2::soa::Join; +using JetTracksSubDielectron = JTrackDielectronSubs; +using JetParticlesSubDielectron = JMcParticleDielectronSubs; +using McCollisionsDielectron = o2::soa::Join; +using CandidatesDielectronMCP = o2::soa::Join; + +} // namespace o2::aod #endif // PWGJE_DATAMODEL_JET_H_ diff --git a/PWGJE/DataModel/JetReducedData.h b/PWGJE/DataModel/JetReducedData.h index 59cad1a22d8..5b97e41ab74 100644 --- a/PWGJE/DataModel/JetReducedData.h +++ b/PWGJE/DataModel/JetReducedData.h @@ -32,31 +32,33 @@ DECLARE_SOA_INDEX_COLUMN(BC, bc); DECLARE_SOA_COLUMN(RunNumber, runNumber, int); DECLARE_SOA_COLUMN(GlobalBC, globalBC, uint64_t); DECLARE_SOA_COLUMN(Timestamp, timestamp, uint64_t); +DECLARE_SOA_BITMAP_COLUMN(Alias, alias, 32); +DECLARE_SOA_BITMAP_COLUMN(Selection, selection, 64); +DECLARE_SOA_COLUMN(ReadCounts, readCounts, std::vector); +DECLARE_SOA_COLUMN(ReadCountsWithTVX, readCountsWithTVX, std::vector); +DECLARE_SOA_COLUMN(ReadCountsWithTVXAndNoTFB, readCountsWithTVXAndNoTFB, std::vector); +DECLARE_SOA_COLUMN(ReadCountsWithTVXAndNoTFBAndNoITSROFB, readCountsWithTVXAndNoTFBAndNoITSROFB, std::vector); } // namespace jbc -DECLARE_SOA_TABLE(JBCs, "AOD", "JBC", - o2::soa::Index<>, - jbc::RunNumber, - jbc::GlobalBC, - jbc::Timestamp); +DECLARE_SOA_TABLE_STAGED(JBCs, "JBC", + o2::soa::Index<>, + jbc::RunNumber, + jbc::GlobalBC, + jbc::Timestamp, + jbc::Alias, + jbc::Selection); using JBC = JBCs::iterator; - -DECLARE_SOA_TABLE(StoredJBCs, "AOD1", "JBC", - o2::soa::Index<>, - jbc::RunNumber, - jbc::GlobalBC, - jbc::Timestamp, - o2::soa::Marker<1>); - using StoredJBC = StoredJBCs::iterator; -DECLARE_SOA_TABLE(JBCPIs, "AOD", "JBCPI", - jbc::BCId); +DECLARE_SOA_TABLE_STAGED(JBCPIs, "JBCPI", + jbc::BCId); -DECLARE_SOA_TABLE(StoredJBCPIs, "AOD1", "JBCPI", - jbc::BCId, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(BCCounts, "BCCOUNT", + jbc::ReadCounts, + jbc::ReadCountsWithTVX, + jbc::ReadCountsWithTVXAndNoTFB, + jbc::ReadCountsWithTVXAndNoTFBAndNoITSROFB); namespace jcollision { @@ -67,83 +69,90 @@ DECLARE_SOA_COLUMN(PosY, posY, float); DECLARE_SOA_COLUMN(PosZ, posZ, float); DECLARE_SOA_COLUMN(Multiplicity, multiplicity, float); DECLARE_SOA_COLUMN(Centrality, centrality, float); -DECLARE_SOA_COLUMN(EventSel, eventSel, uint8_t); +DECLARE_SOA_COLUMN(CentralityVariant1, centralityVariant1, float); +DECLARE_SOA_COLUMN(HadronicRate, hadronicRate, float); +DECLARE_SOA_COLUMN(Weight, weight, float); +DECLARE_SOA_COLUMN(SubGeneratorId, subGeneratorId, int); +DECLARE_SOA_COLUMN(EventSel, eventSel, uint16_t); DECLARE_SOA_BITMAP_COLUMN(Alias, alias, 32); +DECLARE_SOA_COLUMN(TrackOccupancyInTimeRange, trackOccupancyInTimeRange, int); +DECLARE_SOA_COLUMN(TriggerSel, triggerSel, uint64_t); DECLARE_SOA_COLUMN(ChargedTriggerSel, chargedTriggerSel, uint8_t); DECLARE_SOA_COLUMN(FullTriggerSel, fullTriggerSel, uint32_t); DECLARE_SOA_COLUMN(ChargedHFTriggerSel, chargedHFTriggerSel, uint8_t); DECLARE_SOA_COLUMN(ReadCounts, readCounts, std::vector); -DECLARE_SOA_COLUMN(WrittenCounts, writtenCounts, std::vector); +DECLARE_SOA_COLUMN(ReadCountsWithTVX, readCountsWithTVX, std::vector); +DECLARE_SOA_COLUMN(ReadCountsWithTVXAndZVertexAndSel8, readCountsWithTVXAndZVertexAndSel8, std::vector); +DECLARE_SOA_COLUMN(ReadCountsWithTVXAndZVertexAndSel8Full, readCountsWithTVXAndZVertexAndSel8Full, std::vector); +DECLARE_SOA_COLUMN(ReadCountsWithTVXAndZVertexAndSel8FullPbPb, readCountsWithTVXAndZVertexAndSel8FullPbPb, std::vector); +DECLARE_SOA_COLUMN(ReadCountsWithTVXAndZVertexAndSelMC, readCountsWithTVXAndZVertexAndSelMC, std::vector); +DECLARE_SOA_COLUMN(ReadCountsWithTVXAndZVertexAndSelMCFull, readCountsWithTVXAndZVertexAndSelMCFull, std::vector); +DECLARE_SOA_COLUMN(ReadCountsWithTVXAndZVertexAndSelMCFullPbPb, readCountsWithTVXAndZVertexAndSelMCFullPbPb, std::vector); +DECLARE_SOA_COLUMN(ReadCountsWithTVXAndZVertexAndSelUnanchoredMC, readCountsWithTVXAndZVertexAndSelUnanchoredMC, std::vector); +DECLARE_SOA_COLUMN(ReadCountsWithTVXAndZVertexAndSelTVX, readCountsWithTVXAndZVertexAndSelTVX, std::vector); +DECLARE_SOA_COLUMN(ReadCountsWithTVXAndZVertexAndSel7, readCountsWithTVXAndZVertexAndSel7, std::vector); +DECLARE_SOA_COLUMN(ReadCountsWithTVXAndZVertexAndSel7KINT7, readCountsWithTVXAndZVertexAndSel7KINT7, std::vector); +DECLARE_SOA_COLUMN(ReadCountsWithCustom, readCountsWithCustom, std::vector); +DECLARE_SOA_COLUMN(IsAmbiguous, isAmbiguous, bool); +DECLARE_SOA_COLUMN(IsEMCALReadout, isEmcalReadout, bool); } // namespace jcollision -DECLARE_SOA_TABLE(JCollisions, "AOD", "JCOLLISION", - o2::soa::Index<>, - jcollision::PosX, - jcollision::PosY, - jcollision::PosZ, - jcollision::Multiplicity, - jcollision::Centrality, - jcollision::EventSel, - jcollision::Alias); +DECLARE_SOA_TABLE_STAGED(JCollisions, "JCOLLISION", + o2::soa::Index<>, + jcollision::PosX, + jcollision::PosY, + jcollision::PosZ, + jcollision::Multiplicity, + jcollision::Centrality, + jcollision::CentralityVariant1, + jcollision::HadronicRate, + jcollision::TrackOccupancyInTimeRange, + jcollision::EventSel, + jcollision::Alias, + jcollision::TriggerSel); using JCollision = JCollisions::iterator; +using StoredJCollision = StoredJCollisions::iterator; -DECLARE_SOA_TABLE(StoredJCollisions, "AOD1", "JCOLLISION", - o2::soa::Index<>, - jcollision::PosX, - jcollision::PosY, - jcollision::PosZ, - jcollision::Multiplicity, - jcollision::Centrality, - jcollision::EventSel, - jcollision::Alias, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JCollisionMcInfos, "JCOLLISIONMCINFO", + jcollision::Weight, + jcollision::SubGeneratorId); -using StoredJCollision = StoredJCollisions::iterator; +DECLARE_SOA_TABLE_STAGED(JEMCCollisionLbs, "JEMCCOLLISIONLB", + jcollision::IsAmbiguous, + jcollision::IsEMCALReadout); +using JEMCCollisionLb = JEMCCollisionLbs::iterator; +using StoredJEMCCollisionLb = StoredJEMCCollisionLbs::iterator; -DECLARE_SOA_TABLE(JCollisionPIs, "AOD", "JCOLLISIONPI", - jcollision::CollisionId); +DECLARE_SOA_TABLE_STAGED(JCollisionPIs, "JCOLLISIONPI", + jcollision::CollisionId); -DECLARE_SOA_TABLE(StoredJCollisionPIs, "AOD1", "JCOLLISIONPI", - jcollision::CollisionId, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JCollisionBCs, "JCOLLISIONBC", + jcollision::JBCId); DECLARE_SOA_TABLE(JChTrigSels, "AOD", "JCHTRIGSEL", jcollision::ChargedTriggerSel); -DECLARE_SOA_TABLE(StoredJChTrigSels, "AOD1", "JCHTRIGSEL", - jcollision::ChargedTriggerSel, - o2::soa::Marker<1>); - DECLARE_SOA_TABLE(JFullTrigSels, "AOD", "JFULLTRIGSEL", jcollision::FullTriggerSel); -DECLARE_SOA_TABLE(StoredJFullTrigSels, "AOD1", "JFULLTRIGSEL", - jcollision::FullTriggerSel, - o2::soa::Marker<1>); - DECLARE_SOA_TABLE(JChHFTrigSels, "AOD", "JCHHFTRIGSEL", jcollision::ChargedHFTriggerSel); -DECLARE_SOA_TABLE(StoredJChHFTrigSels, "AOD1", "JCHHFTRIGSEL", - jcollision::ChargedHFTriggerSel, - o2::soa::Marker<1>); - -DECLARE_SOA_TABLE(JCollisionBCs, "AOD", "JCOLLISIONBC", - jcollision::JBCId); - -DECLARE_SOA_TABLE(StoredJCollisionBCs, "AOD1", "JCOLLISIONBC", - jcollision::JBCId, - o2::soa::Marker<1>); - -DECLARE_SOA_TABLE(CollisionCounts, "AOD", "COLLCOUNT", - jcollision::ReadCounts, - jcollision::WrittenCounts); - -DECLARE_SOA_TABLE(StoredCollisionCounts, "AOD1", "COLLCOUNT", - jcollision::ReadCounts, - jcollision::WrittenCounts, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(CollisionCounts, "COLLCOUNT", + jcollision::ReadCounts, + jcollision::ReadCountsWithTVX, + jcollision::ReadCountsWithTVXAndZVertexAndSel8, + jcollision::ReadCountsWithTVXAndZVertexAndSel8Full, + jcollision::ReadCountsWithTVXAndZVertexAndSel8FullPbPb, + jcollision::ReadCountsWithTVXAndZVertexAndSelMC, + jcollision::ReadCountsWithTVXAndZVertexAndSelMCFull, + jcollision::ReadCountsWithTVXAndZVertexAndSelMCFullPbPb, + jcollision::ReadCountsWithTVXAndZVertexAndSelUnanchoredMC, + jcollision::ReadCountsWithTVXAndZVertexAndSelTVX, + jcollision::ReadCountsWithTVXAndZVertexAndSel7, + jcollision::ReadCountsWithTVXAndZVertexAndSel7KINT7, + jcollision::ReadCountsWithCustom); namespace jmccollision { @@ -152,44 +161,37 @@ DECLARE_SOA_COLUMN(PosX, posX, float); DECLARE_SOA_COLUMN(PosY, posY, float); DECLARE_SOA_COLUMN(PosZ, posZ, float); DECLARE_SOA_COLUMN(Weight, weight, float); +DECLARE_SOA_COLUMN(SubGeneratorId, subGeneratorId, int); +DECLARE_SOA_COLUMN(Accepted, accepted, uint64_t); +DECLARE_SOA_COLUMN(Attempted, attempted, uint64_t); +DECLARE_SOA_COLUMN(XsectGen, xsectGen, float); +DECLARE_SOA_COLUMN(XsectErr, xsectErr, float); } // namespace jmccollision -DECLARE_SOA_TABLE(JMcCollisions, "AOD", "JMCCOLLISION", - o2::soa::Index<>, - jmccollision::PosX, - jmccollision::PosY, - jmccollision::PosZ, - jmccollision::Weight); +DECLARE_SOA_TABLE_STAGED(JMcCollisions, "JMCCOLLISION", + o2::soa::Index<>, + jmccollision::PosX, + jmccollision::PosY, + jmccollision::PosZ, + jmccollision::Weight, + jmccollision::SubGeneratorId, + jmccollision::Accepted, + jmccollision::Attempted, + jmccollision::XsectGen, + jmccollision::XsectErr); using JMcCollision = JMcCollisions::iterator; - -DECLARE_SOA_TABLE(StoredJMcCollisions, "AOD1", "JMCCOLLISION", - o2::soa::Index<>, - jmccollision::PosX, - jmccollision::PosY, - jmccollision::PosZ, - jmccollision::Weight, - o2::soa::Marker<1>); - using StoredJMcCollision = StoredJMcCollisions::iterator; -DECLARE_SOA_TABLE(JMcCollisionPIs, "AOD", "JMCCOLLISIONPI", - jmccollision::McCollisionId); - -DECLARE_SOA_TABLE(StoredJMcCollisionPIs, "AOD1", "JMCCOLLISIONPI", - jmccollision::McCollisionId, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JMcCollisionPIs, "JMCCOLLISIONPI", + jmccollision::McCollisionId); namespace jmccollisionlb { DECLARE_SOA_INDEX_COLUMN(JMcCollision, mcCollision); } -DECLARE_SOA_TABLE(JMcCollisionLbs, "AOD", "JMCCOLLISIONLB", - jmccollisionlb::JMcCollisionId); - -DECLARE_SOA_TABLE(StoredJMcCollisionLbs, "AOD1", "JMCCOLLISIONLB", - jmccollisionlb::JMcCollisionId, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JMcCollisionLbs, "JMCCOLLISIONLB", + jmccollisionlb::JMcCollisionId); namespace jtrack { @@ -198,6 +200,15 @@ DECLARE_SOA_INDEX_COLUMN(Track, track); DECLARE_SOA_COLUMN(Pt, pt, float); DECLARE_SOA_COLUMN(Eta, eta, float); DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(DCAX, dcaX, float); +DECLARE_SOA_COLUMN(DCAY, dcaY, float); +DECLARE_SOA_COLUMN(DCAZ, dcaZ, float); +DECLARE_SOA_COLUMN(DCAXY, dcaXY, float); +DECLARE_SOA_COLUMN(DCAXYZ, dcaXYZ, float); +DECLARE_SOA_COLUMN(SigmaDCAZ, sigmadcaZ, float); +DECLARE_SOA_COLUMN(SigmaDCAXY, sigmadcaXY, float); +DECLARE_SOA_COLUMN(SigmaDCAXYZ, sigmadcaXYZ, float); +DECLARE_SOA_COLUMN(Sigma1Pt, sigma1Pt, float); DECLARE_SOA_COLUMN(TrackSel, trackSel, uint8_t); DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) -> float { return pt * std::cos(phi); }); @@ -210,48 +221,57 @@ DECLARE_SOA_DYNAMIC_COLUMN(P, p, DECLARE_SOA_DYNAMIC_COLUMN(Energy, energy, [](float pt, float eta) -> float { return std::sqrt((pt * std::cosh(eta) * pt * std::cosh(eta)) + (jetderiveddatautilities::mPion * jetderiveddatautilities::mPion)); }); DECLARE_SOA_DYNAMIC_COLUMN(Sign, sign, - [](uint8_t trackSel) -> int { if (trackSel & (1 << jetderiveddatautilities::JTrackSel::trackSign)){ return 1;} else{return -1;} }); + [](uint8_t trackSel) -> int { + if (trackSel & (1 << jetderiveddatautilities::JTrackSel::trackSign)) { + return 1; + } else { + return -1; + } + }); } // namespace jtrack -DECLARE_SOA_TABLE(JTracks, "AOD", "JTRACK", - o2::soa::Index<>, - jtrack::JCollisionId, - jtrack::Pt, - jtrack::Eta, - jtrack::Phi, - jtrack::TrackSel, - jtrack::Px, - jtrack::Py, - jtrack::Pz, - jtrack::P, - jtrack::Energy, - jtrack::Sign); +DECLARE_SOA_TABLE_STAGED(JTracks, "JTRACK", + o2::soa::Index<>, + jtrack::JCollisionId, + jtrack::Pt, + jtrack::Eta, + jtrack::Phi, + jtrack::TrackSel, + jtrack::Px, + jtrack::Py, + jtrack::Pz, + jtrack::P, + jtrack::Energy, + jtrack::Sign); using JTrack = JTracks::iterator; - -DECLARE_SOA_TABLE(StoredJTracks, "AOD1", "JTRACK", - o2::soa::Index<>, - jtrack::JCollisionId, - jtrack::Pt, - jtrack::Eta, - jtrack::Phi, - jtrack::TrackSel, - jtrack::Px, - jtrack::Py, - jtrack::Pz, - jtrack::P, - jtrack::Energy, - jtrack::Sign, - o2::soa::Marker<1>); - using StoredJTrack = StoredJTracks::iterator; -DECLARE_SOA_TABLE(JTrackPIs, "AOD", "JTRACKPI", - jtrack::TrackId); +DECLARE_SOA_TABLE_STAGED(JTrackExtras, "JTRACKEXTRA", + jtrack::DCAX, + jtrack::DCAY, + jtrack::DCAZ, + jtrack::DCAXY, + jtrack::DCAXYZ, + jtrack::SigmaDCAZ, + jtrack::SigmaDCAXY, + jtrack::SigmaDCAXYZ, + jtrack::Sigma1Pt); + +DECLARE_SOA_TABLE_STAGED(JTrackPIs, "JTRACKPI", + jtrack::TrackId); + +namespace jemctrack +{ +DECLARE_SOA_INDEX_COLUMN(JTrack, track); +DECLARE_SOA_COLUMN(EtaEMCAL, etaEmcal, float); +DECLARE_SOA_COLUMN(PhiEMCAL, phiEmcal, float); +} // namespace jemctrack -DECLARE_SOA_TABLE(StoredJTrackPIs, "AOD1", "JTRACKPI", - jtrack::TrackId, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JEMCTracks, "JEMCTrack", + jemctrack::JTrackId, + jemctrack::EtaEMCAL, + jemctrack::PhiEMCAL); namespace jmcparticle { @@ -280,69 +300,39 @@ DECLARE_SOA_DYNAMIC_COLUMN(Energy, energy, [](float e) -> float { return e; }); } // namespace jmcparticle -DECLARE_SOA_TABLE(JMcParticles, "AOD", "JMCPARTICLE", - o2::soa::Index<>, - jmcparticle::JMcCollisionId, - jmcparticle::Pt, - jmcparticle::Eta, - jmcparticle::Phi, - jmcparticle::Y, - jmcparticle::E, - jmcparticle::PdgCode, - jmcparticle::GenStatusCode, - jmcparticle::HepMCStatusCode, - jmcparticle::IsPhysicalPrimary, - jmcparticle::MothersIds, - jmcparticle::DaughtersIdSlice, - jmcparticle::Px, - jmcparticle::Py, - jmcparticle::Pz, - jmcparticle::P, - jmcparticle::Energy); +DECLARE_SOA_TABLE_STAGED(JMcParticles, "JMCPARTICLE", + o2::soa::Index<>, + jmcparticle::JMcCollisionId, + jmcparticle::Pt, + jmcparticle::Eta, + jmcparticle::Phi, + jmcparticle::Y, + jmcparticle::E, + jmcparticle::PdgCode, + jmcparticle::GenStatusCode, + jmcparticle::HepMCStatusCode, + jmcparticle::IsPhysicalPrimary, + jmcparticle::MothersIds, + jmcparticle::DaughtersIdSlice, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy); using JMcParticle = JMcParticles::iterator; - -DECLARE_SOA_TABLE(StoredJMcParticles, "AOD1", "JMCPARTICLE", - o2::soa::Index<>, - jmcparticle::JMcCollisionId, - jmcparticle::Pt, - jmcparticle::Eta, - jmcparticle::Phi, - jmcparticle::Y, - jmcparticle::E, - jmcparticle::PdgCode, - jmcparticle::GenStatusCode, - jmcparticle::HepMCStatusCode, - jmcparticle::IsPhysicalPrimary, - jmcparticle::MothersIds, - jmcparticle::DaughtersIdSlice, - jmcparticle::Px, - jmcparticle::Py, - jmcparticle::Pz, - jmcparticle::P, - jmcparticle::Energy, - o2::soa::Marker<1>); - using StoredJMcParticle = StoredJMcParticles::iterator; -DECLARE_SOA_TABLE(JMcParticlePIs, "AOD", "JMCPARTICLEPI", - jmcparticle::McParticleId); - -DECLARE_SOA_TABLE(StoredJMcParticlePIs, "AOD1", "JMCPARTICLEPI", - jmcparticle::McParticleId, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JMcParticlePIs, "JMCPARTICLEPI", + jmcparticle::McParticleId); namespace jmctracklb { DECLARE_SOA_INDEX_COLUMN(JMcParticle, mcParticle); } -DECLARE_SOA_TABLE(JMcTrackLbs, "AOD", "JMCTRACKLB", //! Table joined to the track table containing the MC index - jmctracklb::JMcParticleId); - -DECLARE_SOA_TABLE(StoredJMcTrackLbs, "AOD1", "JMCTRACKLB", //! Table joined to the track table containing the MC index - jmctracklb::JMcParticleId, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JMcTrackLbs, "JMCTRACKLB", //! Table joined to the track table containing the MC index + jmctracklb::JMcParticleId); namespace jcluster { @@ -370,38 +360,44 @@ DECLARE_SOA_COLUMN(SubleadingCellNumber, subleadingCellNumber, int); //! energ } // namespace jcluster -DECLARE_SOA_TABLE(JClusters, "AOD", "JCLUSTER", //! - o2::soa::Index<>, jcluster::JCollisionId, jcluster::ID, jcluster::Energy, - jcluster::CoreEnergy, jcluster::RawEnergy, jcluster::Eta, jcluster::Phi, - jcluster::M02, jcluster::M20, jcluster::NCells, jcluster::Time, - jcluster::IsExotic, jcluster::DistanceToBadChannel, jcluster::NLM, jcluster::Definition, - jcluster::LeadingCellEnergy, jcluster::SubleadingCellEnergy, jcluster::LeadingCellNumber, jcluster::SubleadingCellNumber); +DECLARE_SOA_TABLE_STAGED(JClusters, "JCLUSTER", //! + o2::soa::Index<>, jcluster::JCollisionId, jcluster::ID, jcluster::Energy, + jcluster::CoreEnergy, jcluster::RawEnergy, jcluster::Eta, jcluster::Phi, + jcluster::M02, jcluster::M20, jcluster::NCells, jcluster::Time, + jcluster::IsExotic, jcluster::DistanceToBadChannel, jcluster::NLM, jcluster::Definition, + jcluster::LeadingCellEnergy, jcluster::SubleadingCellEnergy, jcluster::LeadingCellNumber, jcluster::SubleadingCellNumber); using JCluster = JClusters::iterator; - -DECLARE_SOA_TABLE(StoredJClusters, "AOD1", "JCLUSTER", - o2::soa::Index<>, jcluster::JCollisionId, jcluster::ID, jcluster::Energy, - jcluster::CoreEnergy, jcluster::RawEnergy, jcluster::Eta, jcluster::Phi, - jcluster::M02, jcluster::M20, jcluster::NCells, jcluster::Time, - jcluster::IsExotic, jcluster::DistanceToBadChannel, jcluster::NLM, jcluster::Definition, - jcluster::LeadingCellEnergy, jcluster::SubleadingCellEnergy, jcluster::LeadingCellNumber, jcluster::SubleadingCellNumber, - o2::soa::Marker<1>); - using StoredJCluster = StoredJClusters::iterator; -DECLARE_SOA_TABLE(JClusterPIs, "AOD", "JCLUSTERPI", - jcluster::EMCALClusterId); +DECLARE_SOA_TABLE_STAGED(JClusterPIs, "JCLUSTERPI", + jcluster::EMCALClusterId); -DECLARE_SOA_TABLE(StoredJClusterPIs, "AOD1", "JCLUSTERPI", - jcluster::EMCALClusterId, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JClusterTracks, "JCLUSTERTRACK", //! + jcluster::JTrackIds); -DECLARE_SOA_TABLE(JClusterTracks, "AOD", "JCLUSTERTRACK", //! - jcluster::JTrackIds); +namespace jclusterhadroniccorrection +{ +DECLARE_SOA_COLUMN(EnergyCorrectedOneTrack1, energyCorrectedOneTrack1, float); //! with hadronic correction fraction (100%) for one matched track +DECLARE_SOA_COLUMN(EnergyCorrectedOneTrack2, energyCorrectedOneTrack2, float); //! with hadronic correction fraction (70%) for one matched track - systematic studies +DECLARE_SOA_COLUMN(EnergyCorrectedAllTracks1, energyCorrectedAllTracks1, float); //! with hadronic correction fraction (100%) for all matched tracks +DECLARE_SOA_COLUMN(EnergyCorrectedAllTracks2, energyCorrectedAllTracks2, float); //! with hadronic correction fraction (70%) for all matched tracks - for systematic studies +} // namespace jclusterhadroniccorrection + +DECLARE_SOA_TABLE_STAGED(JClustersCorrectedEnergies, "JCLUSTERCORRE", //! if this table changes it needs to be reflected in FastJetUtilities.h!! + jclusterhadroniccorrection::EnergyCorrectedOneTrack1, // corrected cluster energy for 1 matched track (f = 100%) + jclusterhadroniccorrection::EnergyCorrectedOneTrack2, // corrected cluster energy for 1 matched track (f = 70%) + jclusterhadroniccorrection::EnergyCorrectedAllTracks1, // corrected cluster energy for all matched tracks (f = 100%) + jclusterhadroniccorrection::EnergyCorrectedAllTracks2); // corrected cluster energy for all matched tracks (f = 70%) + +namespace jmcclusterlb +{ +DECLARE_SOA_ARRAY_INDEX_COLUMN(JMcParticle, mcParticles); +DECLARE_SOA_COLUMN(AmplitudeA, amplitudeA, std::vector); +} // namespace jmcclusterlb -DECLARE_SOA_TABLE(StoredJClusterTracks, "AOD1", "JCLUSTERTRACK", //! - jcluster::JTrackIds, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JMcClusterLbs, "JMCCLUSTERLB", //! + jmcclusterlb::JMcParticleIds, jmcclusterlb::AmplitudeA); namespace jdummy { @@ -409,14 +405,9 @@ namespace jdummy DECLARE_SOA_COLUMN(Dummy, dummy, bool); } // namespace jdummy -DECLARE_SOA_TABLE(JDummys, "AOD", "JDUMMY", - o2::soa::Index<>, - jdummy::Dummy); - -DECLARE_SOA_TABLE(StoredJDummys, "AOD1", "JDUMMY", - o2::soa::Index<>, - jdummy::Dummy, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JDummys, "JDUMMY", + o2::soa::Index<>, + jdummy::Dummy); } // namespace o2::aod diff --git a/PWGJE/DataModel/JetReducedDataDQ.h b/PWGJE/DataModel/JetReducedDataDQ.h new file mode 100644 index 00000000000..bbf2e464cf9 --- /dev/null +++ b/PWGJE/DataModel/JetReducedDataDQ.h @@ -0,0 +1,159 @@ +// 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 Table definitions for reduced data model for dq jets +/// +/// \author Nima Zardoshti + +#ifndef PWGJE_DATAMODEL_JETREDUCEDDATADQ_H_ +#define PWGJE_DATAMODEL_JETREDUCEDDATADQ_H_ + +#include +#include +#include "Framework/AnalysisDataModel.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetReducedDataHF.h" + +namespace o2::aod +{ +namespace jdielectronmccollision +{ +DECLARE_SOA_COLUMN(DummyDQ, dummyDQ, bool); +} // namespace jdielectronmccollision + +DECLARE_SOA_TABLE_STAGED(JDielectronMcCollisions, "JDIELMCCOLL", + o2::soa::Index<>, + jmccollision::PosX, + jmccollision::PosY, + jmccollision::PosZ); + +DECLARE_SOA_TABLE_STAGED(JDielectronMcRCollDummys, "JDIELMCRCOLLDUM", + jdielectronmccollision::DummyDQ); + +namespace jdielectronindices +{ +DECLARE_SOA_INDEX_COLUMN_CUSTOM(JDielectronMcCollision, dielectronmccollision, "JDIELMCCOLLS"); +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, JTracks, "_0"); +DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, JTracks, "_1"); +} // namespace jdielectronindices + +DECLARE_SOA_TABLE_STAGED(JDielectronCollisionIds, "JDIELCOLLID", + jcandidateindices::JCollisionId, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(JDielectronMcCollisionIds, "JDIELMCCOLLID", + jcandidateindices::JMcCollisionId, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(JDielectronIds, "JDIELID", + jcandidateindices::JCollisionId, + jdielectronindices::Prong0Id, + jdielectronindices::Prong1Id, + o2::soa::Marker); + +namespace jdielectronmc +{ +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Y, y, float); +DECLARE_SOA_COLUMN(E, e, float); +DECLARE_SOA_COLUMN(M, m, float); +DECLARE_SOA_COLUMN(PdgCode, pdgCode, int); +DECLARE_SOA_COLUMN(GenStatusCode, getGenStatusCode, int); // TODO : We can look at combining this with the two below +DECLARE_SOA_COLUMN(HepMCStatusCode, getHepMCStatusCode, int); +DECLARE_SOA_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, bool); +DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(Mothers, mothers); +DECLARE_SOA_SELF_SLICE_INDEX_COLUMN(Daughters, daughters); +DECLARE_SOA_COLUMN(DecayFlag, decayFlag, int8_t); +DECLARE_SOA_COLUMN(Origin, origin, int); +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, + [](float pt, float phi) -> float { return pt * std::cos(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, + [](float pt, float phi) -> float { return pt * std::sin(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, + [](float pt, float eta) -> float { return pt * std::sinh(eta); }); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, + [](float pt, float eta) -> float { return pt * std::cosh(eta); }); +} // namespace jdielectronmc + +DECLARE_SOA_TABLE_STAGED(JDielectronMcs, "JDIELMC", + o2::soa::Index<>, + jdielectronindices::JDielectronMcCollisionId, + jdielectronmc::Pt, + jdielectronmc::Eta, + jdielectronmc::Phi, + jdielectronmc::Y, + jdielectronmc::E, + jdielectronmc::M, + jdielectronmc::PdgCode, + jdielectronmc::GenStatusCode, + jdielectronmc::HepMCStatusCode, + jdielectronmc::IsPhysicalPrimary, + jdielectronmc::DecayFlag, + jdielectronmc::Origin, + jdielectronmc::Px, + jdielectronmc::Py, + jdielectronmc::Pz, + jdielectronmc::P); + +using JDielectronMc = JDielectronMcs::iterator; +using StoredJDielectronMc = StoredJDielectronMcs::iterator; + +DECLARE_SOA_TABLE_STAGED(JDielectronMcIds, "JDIELMCID", + jcandidateindices::JMcCollisionId, + jcandidateindices::JMcParticleId, + jdielectronmc::MothersIds, + jdielectronmc::DaughtersIdSlice); + +namespace jdummydq +{ + +DECLARE_SOA_COLUMN(DummyDQ, dummyDQ, bool); + +} // namespace jdummydq +DECLARE_SOA_TABLE(JDielectron1Dummys, "AOD", "JDIEL1DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<1>); + +DECLARE_SOA_TABLE(JDielectron2Dummys, "AOD", "JDIEL2DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<2>); + +DECLARE_SOA_TABLE(JDielectron3Dummys, "AOD", "JDIEL3DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<3>); + +DECLARE_SOA_TABLE(JDielectron4Dummys, "AOD", "JDIEL4DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<4>); + +DECLARE_SOA_TABLE(JDielectron5Dummys, "AOD", "JDIEL5DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<5>); + +DECLARE_SOA_TABLE(JDielectron6Dummys, "AOD", "JDIEL6DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<6>); + +DECLARE_SOA_TABLE(JDielectron7Dummys, "AOD", "JDIEL7DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<7>); + +DECLARE_SOA_TABLE(JDielectron8Dummys, "AOD", "JDIEL8DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<8>); + +} // namespace o2::aod + +#endif // PWGJE_DATAMODEL_JETREDUCEDDATADQ_H_ diff --git a/PWGJE/DataModel/JetReducedDataHF.h b/PWGJE/DataModel/JetReducedDataHF.h index c079e897ee1..cdb2a933d20 100644 --- a/PWGJE/DataModel/JetReducedDataHF.h +++ b/PWGJE/DataModel/JetReducedDataHF.h @@ -26,86 +26,161 @@ namespace o2::aod { -namespace jd0indices +constexpr uint JMarkerD0 = 1; +constexpr uint JMarkerDplus = 2; +constexpr uint JMarkerLc = 3; +constexpr uint JMarkerBplus = 4; +constexpr uint JMarkerDielectron = 5; + +namespace jcandidateindices { DECLARE_SOA_INDEX_COLUMN(JCollision, collision); -DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, JTracks, "_0"); -DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, JTracks, "_1"); DECLARE_SOA_INDEX_COLUMN(JMcCollision, mcCollision); DECLARE_SOA_INDEX_COLUMN(JMcParticle, mcParticle); +} // namespace jcandidateindices + +namespace jd0indices +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, JTracks, "_0"); +DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, JTracks, "_1"); } // namespace jd0indices -namespace d0collisioncounter +DECLARE_SOA_TABLE_STAGED(JD0CollisionIds, "JD0COLLID", + jcandidateindices::JCollisionId, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(JD0McCollisionIds, "JD0MCCOLLID", + jcandidateindices::JMcCollisionId, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(JD0Ids, "JD0ID", + jcandidateindices::JCollisionId, + jd0indices::Prong0Id, + jd0indices::Prong1Id); + +DECLARE_SOA_TABLE_STAGED(JD0PIds, "JD0PID", + jcandidateindices::JMcCollisionId, + jcandidateindices::JMcParticleId, + o2::soa::Marker); + +namespace jdummyd0 { -DECLARE_SOA_COLUMN(ReadCounts, readCounts, std::vector); -DECLARE_SOA_COLUMN(WrittenCounts, writtenCounts, std::vector); -} // namespace d0collisioncounter - -DECLARE_SOA_TABLE(JD0Ids, "AOD", "JD0ID", - jd0indices::JCollisionId, - jd0indices::Prong0Id, - jd0indices::Prong1Id); - -DECLARE_SOA_TABLE(StoredJD0Ids, "AOD1", "JD0ID", - jd0indices::JCollisionId, - jd0indices::Prong0Id, - jd0indices::Prong1Id, +DECLARE_SOA_COLUMN(DummyD0, dummyD0, bool); +} // namespace jdummyd0 + +DECLARE_SOA_TABLE(JDumD0ParDaus, "AOD", "JDUMD0PARDAU", + jdummyd0::DummyD0, o2::soa::Marker<1>); -DECLARE_SOA_TABLE(JD0PIds, "AOD", "JD0PID", - jd0indices::JMcCollisionId, - jd0indices::JMcParticleId); +DECLARE_SOA_TABLE(JDumD0MlDaus, "AOD", "JDumD0MLDAU", + jdummyd0::DummyD0, + o2::soa::Marker<2>); + +namespace jdplusindices +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, JTracks, "_0"); +DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, JTracks, "_1"); +DECLARE_SOA_INDEX_COLUMN_FULL(Prong2, prong2, int, JTracks, "_2"); +} // namespace jdplusindices + +DECLARE_SOA_TABLE_STAGED(JDplusCollisionIds, "JDPCOLLID", + jcandidateindices::JCollisionId, + o2::soa::Marker); -DECLARE_SOA_TABLE(StoredJD0PIds, "AOD1", "JD0PID", - jd0indices::JMcCollisionId, - jd0indices::JMcParticleId, +DECLARE_SOA_TABLE_STAGED(JDplusMcCollisionIds, "JDPMCCOLLID", + jcandidateindices::JMcCollisionId, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(JDplusIds, "JDPID", + jcandidateindices::JCollisionId, + jdplusindices::Prong0Id, + jdplusindices::Prong1Id, + jdplusindices::Prong2Id); + +DECLARE_SOA_TABLE_STAGED(JDplusPIds, "JDPPID", + jcandidateindices::JMcCollisionId, + jcandidateindices::JMcParticleId, + o2::soa::Marker); + +namespace jdummydplus +{ + +DECLARE_SOA_COLUMN(DummyDplus, dummyDplus, bool); + +} // namespace jdummydplus +DECLARE_SOA_TABLE(JDumDplusParDaus, "AOD", "JDUMDPPARDAU", + jdummydplus::DummyDplus, o2::soa::Marker<1>); -DECLARE_SOA_TABLE(D0CollisionCounts, "AOD", "D0COLLCOUNT", - d0collisioncounter::ReadCounts, - d0collisioncounter::WrittenCounts); +DECLARE_SOA_TABLE(JDumDplusMlDaus, "AOD", "JDUMDPMLDAU", + jdummydplus::DummyDplus, + o2::soa::Marker<2>); namespace jlcindices { -DECLARE_SOA_INDEX_COLUMN(JCollision, collision); DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, JTracks, "_0"); DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, JTracks, "_1"); DECLARE_SOA_INDEX_COLUMN_FULL(Prong2, prong2, int, JTracks, "_2"); -DECLARE_SOA_INDEX_COLUMN(JMcCollision, mcCollision); -DECLARE_SOA_INDEX_COLUMN(JMcParticle, mcParticle); } // namespace jlcindices -namespace lccollisioncounter +DECLARE_SOA_TABLE_STAGED(JLcCollisionIds, "JLCCOLLID", + jcandidateindices::JCollisionId, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(JLcMcCollisionIds, "JLCMCCOLLID", + jcandidateindices::JMcCollisionId, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(JLcIds, "JLCID", + jcandidateindices::JCollisionId, + jlcindices::Prong0Id, + jlcindices::Prong1Id, + jlcindices::Prong2Id); + +DECLARE_SOA_TABLE_STAGED(JLcPIds, "JLCPID", + jcandidateindices::JMcCollisionId, + jcandidateindices::JMcParticleId, + o2::soa::Marker); + +namespace jdummylc { -DECLARE_SOA_COLUMN(ReadCounts, readCounts, std::vector); -DECLARE_SOA_COLUMN(WrittenCounts, writtenCounts, std::vector); -} // namespace lccollisioncounter - -DECLARE_SOA_TABLE(JLcIds, "AOD", "JLCID", - jlcindices::JCollisionId, - jlcindices::Prong0Id, - jlcindices::Prong1Id, - jlcindices::Prong2Id); - -DECLARE_SOA_TABLE(StoredJLcIds, "AOD1", "JLCID", - jlcindices::JCollisionId, - jlcindices::Prong0Id, - jlcindices::Prong1Id, - jlcindices::Prong2Id, - o2::soa::Marker<1>); -DECLARE_SOA_TABLE(JLcPIds, "AOD", "JLCPID", - jlcindices::JMcCollisionId, - jlcindices::JMcParticleId); +DECLARE_SOA_COLUMN(DummyLc, dummyLc, bool); -DECLARE_SOA_TABLE(StoredJLcPIds, "AOD1", "JLCPID", - jlcindices::JMcCollisionId, - jlcindices::JMcParticleId, +} // namespace jdummylc +DECLARE_SOA_TABLE(JDumLcParDaus, "AOD", "JDUMLCPARDAU", + jdummylc::DummyLc, o2::soa::Marker<1>); -DECLARE_SOA_TABLE(LcCollisionCounts, "AOD", "LcCOLLCOUNT", - lccollisioncounter::ReadCounts, - lccollisioncounter::WrittenCounts); +DECLARE_SOA_TABLE(JDumLcMlDaus, "AOD", "JDUMLCMLDAU", + jdummylc::DummyLc, + o2::soa::Marker<2>); + +namespace jbplusindices +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, JTracks, "_0"); +DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, JTracks, "_1"); +DECLARE_SOA_INDEX_COLUMN_FULL(Prong2, prong2, int, JTracks, "_2"); +} // namespace jbplusindices + +DECLARE_SOA_TABLE_STAGED(JBplusCollisionIds, "JBPCOLLID", + jcandidateindices::JCollisionId, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(JBplusMcCollisionIds, "JBPMCCOLLID", + jcandidateindices::JMcCollisionId, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(JBplusIds, "JBPID", + jcandidateindices::JCollisionId, + jbplusindices::Prong0Id, + jbplusindices::Prong1Id, + jbplusindices::Prong2Id); + +DECLARE_SOA_TABLE_STAGED(JBplusPIds, "JBPPID", + jcandidateindices::JMcCollisionId, + jcandidateindices::JMcParticleId, + o2::soa::Marker); } // namespace o2::aod diff --git a/PWGJE/DataModel/JetReducedDataSelector.h b/PWGJE/DataModel/JetReducedDataSelector.h new file mode 100644 index 00000000000..4e6b07a955b --- /dev/null +++ b/PWGJE/DataModel/JetReducedDataSelector.h @@ -0,0 +1,39 @@ +// 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 Table definitions for selectors for writing out reduced data model for jets +/// +/// \author Nima Zardoshti + +#ifndef PWGJE_DATAMODEL_JETREDUCEDDATASELECTOR_H_ +#define PWGJE_DATAMODEL_JETREDUCEDDATASELECTOR_H_ + +#include +#include +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace jetreduceddataselector +{ +DECLARE_SOA_COLUMN(IsCollisionSelected, isCollisionSelected, bool); +DECLARE_SOA_COLUMN(IsMcCollisionSelected, isMcCollisionSelected, bool); + +} // namespace jetreduceddataselector +DECLARE_SOA_TABLE(JCollisionSelections, "AOD", "JCOLLSELECTION", + jetreduceddataselector::IsCollisionSelected); + +DECLARE_SOA_TABLE(JMcCollisionSelections, "AOD", "JMCCOLLSELECTION", + jetreduceddataselector::IsMcCollisionSelected); +} // namespace o2::aod + +#endif // PWGJE_DATAMODEL_JETREDUCEDDATASELECTOR_H_ diff --git a/PWGJE/DataModel/JetReducedDataV0.h b/PWGJE/DataModel/JetReducedDataV0.h new file mode 100644 index 00000000000..d904403b532 --- /dev/null +++ b/PWGJE/DataModel/JetReducedDataV0.h @@ -0,0 +1,112 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \brief Table definitions for reduced data model for lf jets +/// +/// \author Nima Zardoshti + +#ifndef PWGJE_DATAMODEL_JETREDUCEDDATAV0_H_ +#define PWGJE_DATAMODEL_JETREDUCEDDATAV0_H_ + +#include +#include +#include "Framework/AnalysisDataModel.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/DataModel/JetReducedData.h" + +namespace o2::aod +{ + +DECLARE_SOA_TABLE_STAGED(JV0McCollisions, "JV0MCCOLL", + o2::soa::Index<>, + jmccollision::PosX, + jmccollision::PosY, + jmccollision::PosZ, + o2::soa::Marker<3>); + +namespace jv0indices +{ +DECLARE_SOA_INDEX_COLUMN(JCollision, collision); +DECLARE_SOA_INDEX_COLUMN(JV0McCollision, v0mccollision); +DECLARE_SOA_INDEX_COLUMN_FULL(PosTrack, posTrack, int, JTracks, "_0"); +DECLARE_SOA_INDEX_COLUMN_FULL(NegTrack, negTrack, int, JTracks, "_1"); +DECLARE_SOA_INDEX_COLUMN(JMcCollision, mcCollision); +DECLARE_SOA_INDEX_COLUMN(JMcParticle, mcParticle); +} // namespace jv0indices + +DECLARE_SOA_TABLE_STAGED(JV0CollisionIds, "JV0COLLID", + jv0indices::JCollisionId); + +DECLARE_SOA_TABLE_STAGED(JV0McCollisionIds, "JV0MCCOLLID", + jv0indices::JMcCollisionId); + +DECLARE_SOA_TABLE(JV0Ids, "AOD", "JV0ID", + jv0indices::JCollisionId, + jv0indices::PosTrackId, + jv0indices::NegTrackId); + +namespace jv0mc +{ +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Y, y, float); +DECLARE_SOA_COLUMN(E, e, float); +DECLARE_SOA_COLUMN(M, m, float); +DECLARE_SOA_COLUMN(PdgCode, pdgCode, int); +DECLARE_SOA_COLUMN(GenStatusCode, getGenStatusCode, int); // TODO : We can look at combining this with the two below +DECLARE_SOA_COLUMN(HepMCStatusCode, getHepMCStatusCode, int); +DECLARE_SOA_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, bool); +DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(Mothers, mothers); +DECLARE_SOA_SELF_SLICE_INDEX_COLUMN(Daughters, daughters); +DECLARE_SOA_COLUMN(DecayFlag, decayFlag, int8_t); +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, + [](float pt, float phi) -> float { return pt * std::cos(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, + [](float pt, float phi) -> float { return pt * std::sin(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, + [](float pt, float eta) -> float { return pt * std::sinh(eta); }); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, + [](float pt, float eta) -> float { return pt * std::cosh(eta); }); +} // namespace jv0mc + +DECLARE_SOA_TABLE_STAGED(JV0Mcs, "JV0MC", + o2::soa::Index<>, + jv0indices::JV0McCollisionId, + jv0mc::Pt, + jv0mc::Eta, + jv0mc::Phi, + jv0mc::Y, + jv0mc::E, + jv0mc::M, + jv0mc::PdgCode, + jv0mc::GenStatusCode, + jv0mc::HepMCStatusCode, + jv0mc::IsPhysicalPrimary, + jv0mc::DecayFlag, + jv0mc::Px, + jv0mc::Py, + jv0mc::Pz, + jv0mc::P); + +using JV0Mc = JV0Mcs::iterator; +using StoredJV0Mc = StoredJV0Mcs::iterator; + +DECLARE_SOA_TABLE_STAGED(JV0McIds, "JV0MCID", + jv0indices::JMcCollisionId, + jv0indices::JMcParticleId, + jv0mc::MothersIds, + jv0mc::DaughtersIdSlice); + +} // namespace o2::aod + +#endif // PWGJE_DATAMODEL_JETREDUCEDDATAV0_H_ diff --git a/PWGJE/DataModel/JetSubstructure.h b/PWGJE/DataModel/JetSubstructure.h index 56cc31a19fc..fcbf2987e52 100644 --- a/PWGJE/DataModel/JetSubstructure.h +++ b/PWGJE/DataModel/JetSubstructure.h @@ -23,8 +23,7 @@ #include "PWGJE/DataModel/EMCALClusters.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGJE/DataModel/Jet.h" - -using namespace o2::analysis; +#include "PWGJE/DataModel/JetReducedData.h" namespace o2::aod { @@ -34,8 +33,19 @@ namespace jetcollision DECLARE_SOA_COLUMN(PosZ, posZ, float); //! DECLARE_SOA_COLUMN(Centrality, centrality, float); //! DECLARE_SOA_COLUMN(EventSel, eventSel, uint8_t); //! +DECLARE_SOA_COLUMN(EventWeight, eventWeight, float); //! } // namespace jetcollision +namespace jetmccollision +{ +DECLARE_SOA_COLUMN(PosZ, posZ, float); //! +DECLARE_SOA_COLUMN(Accepted, accepted, uint64_t); //! +DECLARE_SOA_COLUMN(Attempted, attempted, uint64_t); //! +DECLARE_SOA_COLUMN(XsectGen, xsectGen, float); //! +DECLARE_SOA_COLUMN(XsectErr, xsectErr, float); //! +DECLARE_SOA_COLUMN(EventWeight, eventWeight, float); //! +} // namespace jetmccollision + namespace jetsubstructure { //! DECLARE_SOA_COLUMN(EnergyMother, energyMother, std::vector); //! @@ -45,8 +55,101 @@ DECLARE_SOA_COLUMN(Theta, theta, std::vector); //! DECLARE_SOA_COLUMN(NSub2DR, nSub2DR, float); //! DECLARE_SOA_COLUMN(NSub1, nSub1, float); //! DECLARE_SOA_COLUMN(NSub2, nSub2, float); //! +DECLARE_SOA_COLUMN(PairJetPt, pairJetPt, std::vector); //! +DECLARE_SOA_COLUMN(PairJetEnergy, pairJetEnergy, std::vector); //! +DECLARE_SOA_COLUMN(PairJetTheta, pairJetTheta, std::vector); //! +DECLARE_SOA_COLUMN(PairJetPerpCone1Pt, pairJetPerpCone1Pt, std::vector); //! +DECLARE_SOA_COLUMN(PairJetPerpCone1Energy, pairJetPerpCone1Energy, std::vector); //! +DECLARE_SOA_COLUMN(PairJetPerpCone1Theta, pairJetPerpCone1Theta, std::vector); //! +DECLARE_SOA_COLUMN(PairPerpCone1PerpCone1Pt, pairPerpCone1PerpCone1Pt, std::vector); //! +DECLARE_SOA_COLUMN(PairPerpCone1PerpCone1Energy, pairPerpCone1PerpCone1Energy, std::vector); //! +DECLARE_SOA_COLUMN(PairPerpCone1PerpCone1Theta, pairPerpCone1PerpCone1Theta, std::vector); //! +DECLARE_SOA_COLUMN(PairPerpCone1PerpCone2Pt, pairPerpCone1PerpCone2Pt, std::vector); //! +DECLARE_SOA_COLUMN(PairPerpCone1PerpCone2Energy, pairPerpCone1PerpCone2Energy, std::vector); //! +DECLARE_SOA_COLUMN(PairPerpCone1PerpCone2Theta, pairPerpCone1PerpCone2Theta, std::vector); //! +DECLARE_SOA_COLUMN(Angularity, angularity, float); //! +DECLARE_SOA_COLUMN(PtLeadingConstituent, ptLeadingConstituent, float); //! +DECLARE_SOA_COLUMN(PerpConeRho, perpConeRho, float); //! +DECLARE_SOA_COLUMN(SplittingMatchingGeo, splittingMatchingGeo, std::vector); //! +DECLARE_SOA_COLUMN(SplittingMatchingPt, splittingMatchingPt, std::vector); //! +DECLARE_SOA_COLUMN(SplittingMatchingHF, splittingMatchingHF, std::vector); //! +DECLARE_SOA_COLUMN(PairMatching, pairMatching, std::vector); //! } // namespace jetsubstructure +namespace splitting +{ //! +DECLARE_SOA_COLUMN(Pt, pt, float); //! +DECLARE_SOA_COLUMN(Eta, eta, float); //! +DECLARE_SOA_COLUMN(Phi, phi, float); //! +DECLARE_SOA_COLUMN(R, r, int); //! +DECLARE_SOA_COLUMN(SplittingMatchingGeo, splittingMatchingGeo, std::vector); //! +DECLARE_SOA_COLUMN(SplittingMatchingPt, splittingMatchingPt, std::vector); //! +DECLARE_SOA_COLUMN(SplittingMatchingHF, splittingMatchingHF, std::vector); //! +} // namespace splitting + +// Defines the jet table definition +#define JETSPLITTING_TABLE_DEF(_jet_type_, _jet_description_, _name_, _track_type_, _cand_type_) \ + \ + namespace _name_##splitting \ + { \ + DECLARE_SOA_INDEX_COLUMN(_jet_type_##Jet, jet); \ + } \ + namespace _name_##splittingconstituents \ + { \ + DECLARE_SOA_ARRAY_INDEX_COLUMN_FULL(Tracks, tracks, int32_t, _track_type_, "_tracks"); \ + DECLARE_SOA_ARRAY_INDEX_COLUMN_FULL(Clusters, clusters, int32_t, JClusters, "_clusters"); \ + DECLARE_SOA_ARRAY_INDEX_COLUMN_FULL(Candidates, candidates, int32_t, _cand_type_, "_cand"); \ + } \ + DECLARE_SOA_TABLE(_jet_type_##SPs, "AOD", _jet_description_ "SP", \ + o2::soa::Index<>, \ + _name_##splitting::_jet_type_##JetId, \ + _name_##splittingconstituents::TracksIds, \ + _name_##splittingconstituents::ClustersIds, \ + _name_##splittingconstituents::CandidatesIds, \ + splitting::Pt, \ + splitting::Eta, \ + splitting::Phi, \ + splitting::R); + +#define JETSPLITTINGMATCHING_TABLE_DEF(_jet_type_base_, _jet_type_tag_, _description_) \ + \ + DECLARE_SOA_TABLE(_jet_type_base_##SPsMatchedTo##_jet_type_tag_##SPs, "AOD", _description_ "SP", \ + splitting::SplittingMatchingGeo, \ + splitting::SplittingMatchingPt, \ + splitting::SplittingMatchingHF); + +namespace pair +{ //! +DECLARE_SOA_COLUMN(PairMatching, pairMatching, std::vector); //! +} // namespace pair + +// Defines the jet table definition +#define JETPAIR_TABLE_DEF(_jet_type_, _jet_description_, _name_, _track_type_, _cand_type_) \ + \ + namespace _name_##pair \ + { \ + DECLARE_SOA_INDEX_COLUMN(_jet_type_##Jet, jet); \ + } \ + namespace _name_##pairconstituents \ + { \ + DECLARE_SOA_INDEX_COLUMN_FULL(Track1, track1, int32_t, _track_type_, "_track1"); \ + DECLARE_SOA_INDEX_COLUMN_FULL(Track2, track2, int32_t, _track_type_, "_track2"); \ + DECLARE_SOA_INDEX_COLUMN_FULL(Candidate1, candidate1, int32_t, _cand_type_, "_cand1"); \ + DECLARE_SOA_INDEX_COLUMN_FULL(Candidate2, candidate2, int32_t, _cand_type_, "_cand2"); \ + } \ + DECLARE_SOA_TABLE(_jet_type_##PRs, "AOD", _jet_description_ "PR", \ + o2::soa::Index<>, \ + _name_##pair::_jet_type_##JetId, \ + _name_##pairconstituents::Track1Id, \ + _name_##pairconstituents::Track2Id, \ + _name_##pairconstituents::Candidate1Id, \ + _name_##pairconstituents::Candidate2Id); + +#define JETPAIRMATCHING_TABLE_DEF(_jet_type_base_, _jet_type_tag_, _description_) \ + \ + DECLARE_SOA_TABLE(_jet_type_base_##PRsMatchedTo##_jet_type_tag_##PRs, "AOD", _description_ "PR", \ + pair::PairMatching); + namespace jetoutput { DECLARE_SOA_COLUMN(JetPt, jetPt, float); //! @@ -54,73 +157,108 @@ DECLARE_SOA_COLUMN(JetPhi, jetPhi, float); //! DECLARE_SOA_COLUMN(JetEta, jetEta, float); //! DECLARE_SOA_COLUMN(JetY, jetY, float); //! DECLARE_SOA_COLUMN(JetR, jetR, float); //! +DECLARE_SOA_COLUMN(JetArea, jetArea, float); //! +DECLARE_SOA_COLUMN(JetRho, jetRho, float); //! +DECLARE_SOA_COLUMN(JetPerpConeRho, jetPerpConeRho, float); //! DECLARE_SOA_COLUMN(JetNConstituents, jetNConstituents, int); //! - } // namespace jetoutput +#define MCCOLL_TABLE_DEF(_jet_type_, _jet_description_, _name_) \ + namespace _name_##mccollisionoutput \ + { \ + DECLARE_SOA_DYNAMIC_COLUMN(Dummy##_jet_type_, dummy##_jet_type_, []() -> int { return 0; }); \ + } \ + DECLARE_SOA_TABLE(_jet_type_##MCCOs, "AOD", _jet_description_ "MCCO", \ + jetmccollision::PosZ, \ + jetmccollision::Accepted, \ + jetmccollision::Attempted, \ + jetmccollision::XsectGen, \ + jetmccollision::XsectErr, \ + jetmccollision::EventWeight, \ + _name_##mccollisionoutput::Dummy##_jet_type_<>); + // Defines the jet substrcuture table definition -#define JETSUBSTRUCTURE_TABLE_DEF(_jet_type_, _cand_type_, _name_, _description_) \ - \ - namespace _name_##collisionoutput \ - { \ - DECLARE_SOA_DYNAMIC_COLUMN(Dummy##_jet_type_, dummy##_jet_type_, []() -> int { return 0; }); \ - } \ - \ - DECLARE_SOA_TABLE(_jet_type_##COs, "AOD", _description_ "CO", jetcollision::PosZ, jetcollision::Centrality, jetcollision::EventSel, _name_##collisionoutput::Dummy##_jet_type_<>); \ - using _jet_type_##CO = _jet_type_##COs::iterator; \ - \ - namespace _name_##jetoutput \ - { \ - DECLARE_SOA_INDEX_COLUMN(_jet_type_##CO, collision); \ - DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, _cand_type_, "_0"); \ - } \ - DECLARE_SOA_TABLE(_jet_type_##Os, "AOD", _description_ "O", _name_##jetoutput::_jet_type_##COId, _name_##jetoutput::CandidateId, jetoutput::JetPt, jetoutput::JetPhi, jetoutput::JetEta, jetoutput::JetY, jetoutput::JetR, jetoutput::JetNConstituents); \ - using _jet_type_##O = _jet_type_##Os::iterator; \ - namespace _name_##substructure \ - { \ - DECLARE_SOA_INDEX_COLUMN(_jet_type_##O, outputTable); \ - DECLARE_SOA_DYNAMIC_COLUMN(Dummy##_jet_type_, dummy##_jet_type_, []() -> int { return 0; }); \ - } \ - \ - DECLARE_SOA_TABLE(_jet_type_##SSs, "AOD", _description_ "SS", jetsubstructure::EnergyMother, jetsubstructure::PtLeading, jetsubstructure::PtSubLeading, jetsubstructure::Theta, jetsubstructure::NSub2DR, jetsubstructure::NSub1, jetsubstructure::NSub2, _name_##substructure::Dummy##_jet_type_<>); \ - DECLARE_SOA_TABLE(_jet_type_##SSOs, "AOD", _description_ "SSO", _name_##substructure::_jet_type_##OId, jetsubstructure::EnergyMother, jetsubstructure::PtLeading, jetsubstructure::PtSubLeading, jetsubstructure::Theta, jetsubstructure::NSub2DR, jetsubstructure::NSub1, jetsubstructure::NSub2); \ - \ - using _jet_type_##O = _jet_type_##Os::iterator; \ +#define JETSUBSTRUCTURE_TABLE_DEF(_jet_type_, _jet_description_, _name_, _cand_type_, _cand_description_) \ + \ + namespace _name_##collisionoutput \ + { \ + DECLARE_SOA_DYNAMIC_COLUMN(Dummy##_jet_type_, dummy##_jet_type_, []() -> int { return 0; }); \ + } \ + \ + DECLARE_SOA_TABLE(_jet_type_##COs, "AOD", _jet_description_ "CO", jetcollision::PosZ, jetcollision::Centrality, jetcollision::EventSel, jetcollision::EventWeight, _name_##collisionoutput::Dummy##_jet_type_<>); \ + using _jet_type_##CO = _jet_type_##COs::iterator; \ + \ + namespace _name_##jetoutput \ + { \ + DECLARE_SOA_INDEX_COLUMN_CUSTOM(_jet_type_##CO, collision, _jet_description_ "COS"); \ + DECLARE_SOA_INDEX_COLUMN_FULL_CUSTOM(Candidate, candidate, int, _cand_type_, _cand_description_ "S", "_0"); \ + } \ + DECLARE_SOA_TABLE(_jet_type_##Os, "AOD", _jet_description_ "O", _name_##jetoutput::_jet_type_##COId, _name_##jetoutput::CandidateId, jetoutput::JetPt, jetoutput::JetPhi, jetoutput::JetEta, jetoutput::JetY, jetoutput::JetR, jetoutput::JetArea, jetoutput::JetRho, jetoutput::JetPerpConeRho, jetoutput::JetNConstituents); \ + using _jet_type_##O = _jet_type_##Os::iterator; \ + namespace _name_##substructure \ + { \ + DECLARE_SOA_INDEX_COLUMN_CUSTOM(_jet_type_##O, outputTable, _jet_description_ "OS"); \ + DECLARE_SOA_DYNAMIC_COLUMN(Dummy##_jet_type_, dummy##_jet_type_, []() -> int { return 0; }); \ + } \ + \ + DECLARE_SOA_TABLE(_jet_type_##SSs, "AOD", _jet_description_ "SS", jetsubstructure::EnergyMother, jetsubstructure::PtLeading, jetsubstructure::PtSubLeading, jetsubstructure::Theta, jetsubstructure::NSub2DR, jetsubstructure::NSub1, jetsubstructure::NSub2, jetsubstructure::PairJetPt, jetsubstructure::PairJetEnergy, jetsubstructure::PairJetTheta, jetsubstructure::PairJetPerpCone1Pt, jetsubstructure::PairJetPerpCone1Energy, jetsubstructure::PairJetPerpCone1Theta, jetsubstructure::PairPerpCone1PerpCone1Pt, jetsubstructure::PairPerpCone1PerpCone1Energy, jetsubstructure::PairPerpCone1PerpCone1Theta, jetsubstructure::PairPerpCone1PerpCone2Pt, jetsubstructure::PairPerpCone1PerpCone2Energy, jetsubstructure::PairPerpCone1PerpCone2Theta, jetsubstructure::Angularity, jetsubstructure::PtLeadingConstituent, jetsubstructure::PerpConeRho, _name_##substructure::Dummy##_jet_type_<>); \ + DECLARE_SOA_TABLE(_jet_type_##SSOs, "AOD", _jet_description_ "SSO", _name_##substructure::_jet_type_##OId, jetsubstructure::EnergyMother, jetsubstructure::PtLeading, jetsubstructure::PtSubLeading, jetsubstructure::Theta, jetsubstructure::NSub2DR, jetsubstructure::NSub1, jetsubstructure::NSub2, jetsubstructure::PairJetPt, jetsubstructure::PairJetEnergy, jetsubstructure::PairJetTheta, jetsubstructure::PairJetPerpCone1Pt, jetsubstructure::PairJetPerpCone1Energy, jetsubstructure::PairJetPerpCone1Theta, jetsubstructure::PairPerpCone1PerpCone1Pt, jetsubstructure::PairPerpCone1PerpCone1Energy, jetsubstructure::PairPerpCone1PerpCone1Theta, jetsubstructure::PairPerpCone1PerpCone2Pt, jetsubstructure::PairPerpCone1PerpCone2Energy, jetsubstructure::PairPerpCone1PerpCone2Theta, jetsubstructure::Angularity, jetsubstructure::PtLeadingConstituent, jetsubstructure::SplittingMatchingGeo, jetsubstructure::SplittingMatchingPt, jetsubstructure::SplittingMatchingHF, jetsubstructure::PairMatching); \ + \ + using _jet_type_##O = _jet_type_##Os::iterator; \ using _jet_type_##SSO = _jet_type_##SSOs::iterator; // define the mathcing table definition -#define JETMATCHING_TABLE_DEF(_jet_type_, _matched_jet_type_, _name_, _description_) \ +#define JETMATCHING_TABLE_DEF(_jet_type_, _matched_jet_type_, _matched_jet_description_, _name_, _description_) \ namespace _name_##geomatched \ { \ - DECLARE_SOA_ARRAY_INDEX_COLUMN_FULL(_matched_jet_type_, matchedJetGeo, int32_t, _matched_jet_type_##Os, "_geo"); \ + DECLARE_SOA_ARRAY_INDEX_COLUMN_FULL_CUSTOM(_matched_jet_type_, matchedJetGeo, int32_t, _matched_jet_type_##Os, _matched_jet_description_ "OS", "_geo"); \ } \ \ namespace _name_##ptmatched \ { \ - DECLARE_SOA_ARRAY_INDEX_COLUMN_FULL(_matched_jet_type_, matchedJetPt, int32_t, _matched_jet_type_##Os, "_pt"); \ + DECLARE_SOA_ARRAY_INDEX_COLUMN_FULL_CUSTOM(_matched_jet_type_, matchedJetPt, int32_t, _matched_jet_type_##Os, _matched_jet_description_ "OS", "_pt"); \ } \ \ namespace _name_##candmatched \ { \ - DECLARE_SOA_ARRAY_INDEX_COLUMN_FULL(_matched_jet_type_, matchedJetCand, int32_t, _matched_jet_type_##Os, "_hf"); \ + DECLARE_SOA_ARRAY_INDEX_COLUMN_FULL_CUSTOM(_matched_jet_type_, matchedJetCand, int32_t, _matched_jet_type_##Os, _matched_jet_description_ "OS", "_hf"); \ } \ DECLARE_SOA_TABLE(_jet_type_##MOs, "AOD", _description_ "MO", _name_##substructure::_jet_type_##OId, _name_##geomatched::_matched_jet_type_##Ids, _name_##ptmatched::_matched_jet_type_##Ids, _name_##candmatched::_matched_jet_type_##Ids); \ using _jet_type_##MO = _jet_type_##MOs::iterator; -#define JETSUBSTRUCTURE_TABLES_DEF(_jet_type_, _cand_type_data_, _cand_type_ewsdata_, _cand_type_mcd_, _hfparticle_type_, _description_) \ - JETSUBSTRUCTURE_TABLE_DEF(_jet_type_##Jet, _cand_type_data_, _jet_type_##jet, _description_ "JET") \ - JETSUBSTRUCTURE_TABLE_DEF(_jet_type_##EWSJet, _cand_type_ewsdata_, _jet_type_##ewsjet, _description_ "EWSJET") \ - JETMATCHING_TABLE_DEF(_jet_type_##Jet, _jet_type_##EWSJet, _jet_type_##jet, _description_ "JET") \ - JETMATCHING_TABLE_DEF(_jet_type_##EWSJet, _jet_type_##Jet, _jet_type_##ewsjet, _description_ "EWSJET") \ - JETSUBSTRUCTURE_TABLE_DEF(_jet_type_##MCDJet, _cand_type_mcd_, _jet_type_##mcdjet, _description_ "MCDJET") \ - JETSUBSTRUCTURE_TABLE_DEF(_jet_type_##MCPJet, _hfparticle_type_, _jet_type_##mcpjet, _description_ "MCPJET") \ - JETMATCHING_TABLE_DEF(_jet_type_##MCDJet, _jet_type_##MCPJet, _jet_type_##mcdjet, _description_ "MCDJET") \ - JETMATCHING_TABLE_DEF(_jet_type_##MCPJet, _jet_type_##MCDJet, _jet_type_##mcpjet, _description_ "MCPJET") - -JETSUBSTRUCTURE_TABLES_DEF(C, CJetCOs, CEWSJetCOs, CMCDJetCOs, CMCPJetCOs, "C"); -JETSUBSTRUCTURE_TABLES_DEF(D0C, HfD0Bases, HfD0Bases, HfD0Bases, HfD0PBases, "D0C"); -JETSUBSTRUCTURE_TABLES_DEF(LcC, Hf3PBases, Hf3PBases, Hf3PBases, Hf3PPBases, "LCC"); -JETSUBSTRUCTURE_TABLES_DEF(BplusC, HfD0Bases, HfD0Bases, HfD0Bases, HfD0PBases, "BPLUSC"); +#define JETSUBSTRUCTURE_TABLES_DEF(_jet_type_, _jet_description_, _jet_type_full_, _jet_full_description_, _track_type_data_, _cand_type_data_, _cand_description_data_, _track_type_ewsdata_, _cand_type_ewsdata_, _cand_description_ewsdata_, _track_type_mcd_, _cand_type_mcd_, _cand_description_mcd_, _particle_type_, _hfparticle_type_, _hfparticle_description_) \ + JETSUBSTRUCTURE_TABLE_DEF(_jet_type_##Jet, _jet_description_ "JET", _jet_type_##jet, _cand_type_data_, _cand_description_data_) \ + JETSUBSTRUCTURE_TABLE_DEF(_jet_type_##EWSJet, _jet_description_ "EWSJET", _jet_type_##ewsjet, _cand_type_ewsdata_, _cand_description_ewsdata_) \ + JETMATCHING_TABLE_DEF(_jet_type_##Jet, _jet_type_##EWSJet, _jet_description_ "EWSJET", _jet_type_##jet, _jet_description_ "JET") \ + JETMATCHING_TABLE_DEF(_jet_type_##EWSJet, _jet_type_##Jet, _jet_description_ "JET", _jet_type_##ewsjet, _jet_description_ "EWSJET") \ + JETSPLITTING_TABLE_DEF(_jet_type_full_, _jet_description_, _jet_full_description_, _track_type_data_, _cand_type_data_) \ + JETSPLITTING_TABLE_DEF(_jet_type_full_##EventWiseSubtracted, _jet_description_ "EWS", _jet_full_description_##eventwisesubtracted, _cand_type_ewsdata_, _cand_type_ewsdata_) \ + JETSPLITTINGMATCHING_TABLE_DEF(_jet_type_full_, _jet_type_full_##EventWiseSubtracted, _jet_description_ "SP2EWS") \ + JETSPLITTINGMATCHING_TABLE_DEF(_jet_type_full_##EventWiseSubtracted, _jet_type_full_, _jet_description_ "EWSSP2") \ + JETPAIR_TABLE_DEF(_jet_type_full_, _jet_description_, _jet_full_description_, _track_type_data_, _cand_type_data_) \ + JETPAIR_TABLE_DEF(_jet_type_full_##EventWiseSubtracted, _jet_description_ "EWS", _jet_full_description_##eventwisesubtracted, _cand_type_ewsdata_, _cand_type_ewsdata_) \ + JETPAIRMATCHING_TABLE_DEF(_jet_type_full_, _jet_type_full_##EventWiseSubtracted, _jet_description_ "SP2EWS") \ + JETPAIRMATCHING_TABLE_DEF(_jet_type_full_##EventWiseSubtracted, _jet_type_full_, _jet_description_ "EWSSP2") \ + JETSUBSTRUCTURE_TABLE_DEF(_jet_type_##MCDJet, _jet_description_ "MCDJET", _jet_type_##mcdjet, _cand_type_mcd_, _cand_description_mcd_) \ + JETSUBSTRUCTURE_TABLE_DEF(_jet_type_##MCPJet, _jet_description_ "MCPJET", _jet_type_##mcpjet, _hfparticle_type_, _hfparticle_description_) \ + MCCOLL_TABLE_DEF(_jet_type_##MCPJet, _jet_description_ "MCPJET", _jet_type_##mcpjet) \ + JETMATCHING_TABLE_DEF(_jet_type_##MCDJet, _jet_type_##MCPJet, _jet_description_ "MCPJET", _jet_type_##mcdjet, _jet_description_ "MCDJET") \ + JETMATCHING_TABLE_DEF(_jet_type_##MCPJet, _jet_type_##MCDJet, _jet_description_ "MCDJET", _jet_type_##mcpjet, _jet_description_ "MCPJET") \ + JETSPLITTING_TABLE_DEF(_jet_type_full_##MCDetectorLevel, _jet_description_ "D", _jet_full_description_##mcdetectorlevel, _track_type_mcd_, _cand_type_mcd_) \ + JETSPLITTING_TABLE_DEF(_jet_type_full_##MCParticleLevel, _jet_description_ "P", _jet_full_description_##mcparticlelevel, _particle_type_, _hfparticle_type_) \ + JETSPLITTINGMATCHING_TABLE_DEF(_jet_type_full_##MCDetectorLevel, _jet_type_full_##MCParticleLevel, _jet_description_ "DSP2P") \ + JETSPLITTINGMATCHING_TABLE_DEF(_jet_type_full_##MCParticleLevel, _jet_type_full_##MCDetectorLevel, _jet_description_ "PSP2D") \ + JETPAIR_TABLE_DEF(_jet_type_full_##MCDetectorLevel, _jet_description_ "D", _jet_full_description_##mcdetectorlevel, _track_type_mcd_, _cand_type_mcd_) \ + JETPAIR_TABLE_DEF(_jet_type_full_##MCParticleLevel, _jet_description_ "P", _jet_full_description_##mcparticlelevel, _particle_type_, _hfparticle_type_) \ + JETPAIRMATCHING_TABLE_DEF(_jet_type_full_##MCDetectorLevel, _jet_type_full_##MCParticleLevel, _jet_description_ "DSP2P") \ + JETPAIRMATCHING_TABLE_DEF(_jet_type_full_##MCParticleLevel, _jet_type_full_##MCDetectorLevel, _jet_description_ "PSP2D") + +JETSUBSTRUCTURE_TABLES_DEF(C, "C", Charged, charged, JTracks, CJetCOs, "CJETCO", JTrackSubs, CEWSJetCOs, "CEWSJETCO", JTracks, CMCDJetCOs, "CMCDJETCO", JMcParticles, CMCPJetCOs, "CMCPJETCO"); +JETSUBSTRUCTURE_TABLES_DEF(D0C, "D0C", D0Charged, d0charged, JTracks, HfD0Bases, "HFD0BASE", JTrackD0Subs, HfD0Bases, "HFD0BASE", JTracks, HfD0Bases, "HFD0BASE", JMcParticles, HfD0PBases, "HFD0PBASE"); +JETSUBSTRUCTURE_TABLES_DEF(DplusC, "DPC", DplusCharged, dpluscharged, JTracks, HfDplusBases, "HFDPBASE", JTrackDplusSubs, HfDplusBases, "HFDPBASE", JTracks, HfDplusBases, "HFDPBASE", JMcParticles, HfDplusPBases, "HFDPPBASE"); +JETSUBSTRUCTURE_TABLES_DEF(LcC, "LCC", LcCharged, lccharged, JTracks, HfLcBases, "HFLCBASE", JTrackLcSubs, HfLcBases, "HFLCBASE", JTracks, HfLcBases, "HFLCBASE", JMcParticles, HfLcPBases, "HFLCPBASE"); +JETSUBSTRUCTURE_TABLES_DEF(BplusC, "BPC", BplusCharged, bpluscharged, JTracks, HfBplusBases, "HFBPBASE", JTrackBplusSubs, HfBplusBases, "HFBPBASE", JTracks, HfBplusBases, "HFBPBASE", JMcParticles, HfBplusPBases, "HFBPPBASE"); +JETSUBSTRUCTURE_TABLES_DEF(DielectronC, "DIELC", DielectronCharged, dielectroncharged, JTracks, Dielectrons, "RTDIELECTRON", JTrackDielectronSubs, Dielectrons, "RTDIELECTRON", JTracks, Dielectrons, "RTDIELECTRON", JMcParticles, JDielectronMcs, "JDIELMC"); } // namespace o2::aod diff --git a/PWGJE/DataModel/JetSubtraction.h b/PWGJE/DataModel/JetSubtraction.h index e7c58f44867..55879d009c1 100644 --- a/PWGJE/DataModel/JetSubtraction.h +++ b/PWGJE/DataModel/JetSubtraction.h @@ -22,8 +22,10 @@ #include "Framework/AnalysisDataModel.h" #include "PWGJE/DataModel/EMCALClusters.h" #include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetReducedDataDQ.h" #include "PWGHF/DataModel/DerivedTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" namespace o2::aod { @@ -37,6 +39,7 @@ DECLARE_SOA_COLUMN(RhoM, rhoM, float); //! namespace bkgcharged { DECLARE_SOA_INDEX_COLUMN(JCollision, collision); +DECLARE_SOA_INDEX_COLUMN(JMcCollision, mcCollision); } // namespace bkgcharged namespace bkgd0 @@ -44,118 +47,332 @@ namespace bkgd0 DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfD0Bases, "_0"); } // namespace bkgd0 +namespace bkgd0mc +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfD0PBases, "_0"); +} // namespace bkgd0mc + +namespace bkgdplus +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfDplusBases, "_0"); +} // namespace bkgdplus + +namespace bkgdplusmc +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfDplusPBases, "_0"); +} // namespace bkgdplusmc + namespace bkglc { -DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, Hf3PBases, "_0"); +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfLcBases, "_0"); } // namespace bkglc +namespace bkglcmc +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfLcPBases, "_0"); +} // namespace bkglcmc + namespace bkgbplus { -DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfCandBplus, "_0"); +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfBplusBases, "_0"); } // namespace bkgbplus +namespace bkgbplusmc +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfBplusPBases, "_0"); +} // namespace bkgbplusmc + +namespace bkgdielectron +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, Dielectrons, "_0"); +} // namespace bkgdielectron + +namespace bkgdielectronmc +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, JDielectronMcs, "_0"); +} // namespace bkgdielectronmc + DECLARE_SOA_TABLE(BkgChargedRhos, "AOD", "BkgCRho", o2::soa::Index<>, - bkgcharged::JCollisionId, bkgrho::Rho, bkgrho::RhoM); +DECLARE_SOA_TABLE(BkgChargedMcRhos, "AOD", "BkgCMcRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<1>); + DECLARE_SOA_TABLE(BkgD0Rhos, "AOD", "BkgD0Rho", o2::soa::Index<>, - bkgd0::CandidateId, bkgrho::Rho, - bkgrho::RhoM); + bkgrho::RhoM, + o2::soa::Marker<2>); -DECLARE_SOA_TABLE(BkgLcRhos, "AOD", "BkgLcRho", +DECLARE_SOA_TABLE(BkgD0McRhos, "AOD", "BkgD0McRho", o2::soa::Index<>, - bkglc::CandidateId, bkgrho::Rho, - bkgrho::RhoM); + bkgrho::RhoM, + o2::soa::Marker<3>); -DECLARE_SOA_TABLE(BkgBplusRhos, "AOD", "BkgBPlRho", +DECLARE_SOA_TABLE(BkgDplusRhos, "AOD", "BkgDPRho", o2::soa::Index<>, - bkgbplus::CandidateId, bkgrho::Rho, - bkgrho::RhoM); + bkgrho::RhoM, + o2::soa::Marker<4>); -namespace jtracksub -{ +DECLARE_SOA_TABLE(BkgDplusMcRhos, "AOD", "BkgDPMcRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<5>); -DECLARE_SOA_COLUMN(Pt, pt, float); -DECLARE_SOA_COLUMN(Eta, eta, float); -DECLARE_SOA_COLUMN(Phi, phi, float); -DECLARE_SOA_COLUMN(Energy, energy, float); -DECLARE_SOA_COLUMN(TrackSel, trackSel, uint8_t); -DECLARE_SOA_DYNAMIC_COLUMN(Px, px, - [](float pt, float phi) -> float { return pt * std::cos(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Py, py, - [](float pt, float phi) -> float { return pt * std::sin(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, - [](float pt, float eta) -> float { return pt * std::sinh(eta); }); -DECLARE_SOA_DYNAMIC_COLUMN(P, p, - [](float pt, float eta) -> float { return pt * std::cosh(eta); }); -} // namespace jtracksub +DECLARE_SOA_TABLE(BkgLcRhos, "AOD", "BkgLCRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<4>); + +DECLARE_SOA_TABLE(BkgLcMcRhos, "AOD", "BkgLCMcRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<5>); + +DECLARE_SOA_TABLE(BkgBplusRhos, "AOD", "BkgBPRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<6>); + +DECLARE_SOA_TABLE(BkgBplusMcRhos, "AOD", "BkgBPMcRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<7>); + +DECLARE_SOA_TABLE(BkgDielectronRhos, "AOD", "BkgDIELRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<8>); + +DECLARE_SOA_TABLE(BkgDielectronMcRhos, "AOD", "BkgDIELMcRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<9>); DECLARE_SOA_TABLE(JTrackSubs, "AOD", "JTrackSubs", o2::soa::Index<>, bkgcharged::JCollisionId, - jtracksub::Pt, - jtracksub::Eta, - jtracksub::Phi, - jtracksub::Energy, - jtracksub::TrackSel, - jtracksub::Px, - jtracksub::Py, - jtracksub::Pz, - jtracksub::P); + jtrack::Pt, + jtrack::Eta, + jtrack::Phi, + jtrack::TrackSel, + jtrack::Px, + jtrack::Py, + jtrack::Pz, + jtrack::P, + jtrack::Energy); using JTrackSub = JTrackSubs::iterator; +DECLARE_SOA_TABLE(JMcParticleSubs, "AOD", "JMcPartSubs", + o2::soa::Index<>, + bkgcharged::JMcCollisionId, + jmcparticle::Pt, + jmcparticle::Eta, + jmcparticle::Phi, + jmcparticle::Y, + jmcparticle::E, + jmcparticle::PdgCode, + jmcparticle::GenStatusCode, + jmcparticle::HepMCStatusCode, + jmcparticle::IsPhysicalPrimary, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy); + +using JMcParticleSub = JMcParticleSubs::iterator; + DECLARE_SOA_TABLE(JTrackD0Subs, "AOD", "JTrackD0Subs", o2::soa::Index<>, bkgd0::CandidateId, - jtracksub::Pt, - jtracksub::Eta, - jtracksub::Phi, - jtracksub::Energy, - jtracksub::TrackSel, - jtracksub::Px, - jtracksub::Py, - jtracksub::Pz, - jtracksub::P); + jtrack::Pt, + jtrack::Eta, + jtrack::Phi, + jtrack::TrackSel, + jtrack::Px, + jtrack::Py, + jtrack::Pz, + jtrack::P, + jtrack::Energy); using JTrackD0Sub = JTrackD0Subs::iterator; -DECLARE_SOA_TABLE(JTrackLcSubs, "AOD", "JTrackLcSubs", +DECLARE_SOA_TABLE(JMcParticleD0Subs, "AOD", "JMcPartD0Subs", + o2::soa::Index<>, + bkgd0mc::CandidateId, + jmcparticle::Pt, + jmcparticle::Eta, + jmcparticle::Phi, + jmcparticle::Y, + jmcparticle::E, + jmcparticle::PdgCode, + jmcparticle::GenStatusCode, + jmcparticle::HepMCStatusCode, + jmcparticle::IsPhysicalPrimary, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy); + +using JMcParticleD0Sub = JMcParticleD0Subs::iterator; + +DECLARE_SOA_TABLE(JTrackDplusSubs, "AOD", "JTrackDPSubs", + o2::soa::Index<>, + bkglc::CandidateId, + jtrack::Pt, + jtrack::Eta, + jtrack::Phi, + jtrack::TrackSel, + jtrack::Px, + jtrack::Py, + jtrack::Pz, + jtrack::P, + jtrack::Energy); + +using JTrackDplusSub = JTrackDplusSubs::iterator; + +DECLARE_SOA_TABLE(JMcParticleDplusSubs, "AOD", "JMcPartDPSubs", + o2::soa::Index<>, + bkglcmc::CandidateId, + jmcparticle::Pt, + jmcparticle::Eta, + jmcparticle::Phi, + jmcparticle::Y, + jmcparticle::E, + jmcparticle::PdgCode, + jmcparticle::GenStatusCode, + jmcparticle::HepMCStatusCode, + jmcparticle::IsPhysicalPrimary, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy); + +using JMcParticleDplusSub = JMcParticleDplusSubs::iterator; + +DECLARE_SOA_TABLE(JTrackLcSubs, "AOD", "JTrackLCSubs", o2::soa::Index<>, bkglc::CandidateId, - jtracksub::Pt, - jtracksub::Eta, - jtracksub::Phi, - jtracksub::Energy, - jtracksub::TrackSel, - jtracksub::Px, - jtracksub::Py, - jtracksub::Pz, - jtracksub::P); + jtrack::Pt, + jtrack::Eta, + jtrack::Phi, + jtrack::TrackSel, + jtrack::Px, + jtrack::Py, + jtrack::Pz, + jtrack::P, + jtrack::Energy); using JTrackLcSub = JTrackLcSubs::iterator; -DECLARE_SOA_TABLE(JTrackBplusSubs, "AOD", "JTrackBPlSubs", +DECLARE_SOA_TABLE(JMcParticleLcSubs, "AOD", "JMcPartLCSubs", + o2::soa::Index<>, + bkglcmc::CandidateId, + jmcparticle::Pt, + jmcparticle::Eta, + jmcparticle::Phi, + jmcparticle::Y, + jmcparticle::E, + jmcparticle::PdgCode, + jmcparticle::GenStatusCode, + jmcparticle::HepMCStatusCode, + jmcparticle::IsPhysicalPrimary, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy); + +using JMcParticleLcSub = JMcParticleLcSubs::iterator; + +DECLARE_SOA_TABLE(JTrackBplusSubs, "AOD", "JTrackBPSubs", o2::soa::Index<>, bkgbplus::CandidateId, - jtracksub::Pt, - jtracksub::Eta, - jtracksub::Phi, - jtracksub::Energy, - jtracksub::TrackSel, - jtracksub::Px, - jtracksub::Py, - jtracksub::Pz, - jtracksub::P); + jtrack::Pt, + jtrack::Eta, + jtrack::Phi, + jtrack::TrackSel, + jtrack::Px, + jtrack::Py, + jtrack::Pz, + jtrack::P, + jtrack::Energy); using JTrackBplusSub = JTrackBplusSubs::iterator; +DECLARE_SOA_TABLE(JMcParticleBplusSubs, "AOD", "JMcPartBPSubs", + o2::soa::Index<>, + bkgbplusmc::CandidateId, + jmcparticle::Pt, + jmcparticle::Eta, + jmcparticle::Phi, + jmcparticle::Y, + jmcparticle::E, + jmcparticle::PdgCode, + jmcparticle::GenStatusCode, + jmcparticle::HepMCStatusCode, + jmcparticle::IsPhysicalPrimary, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy); + +using JMcParticleBplusSub = JMcParticleBplusSubs::iterator; + +DECLARE_SOA_TABLE(JTrackDielectronSubs, "AOD", "JTrackDIELSubs", + o2::soa::Index<>, + bkgdielectron::CandidateId, + jtrack::Pt, + jtrack::Eta, + jtrack::Phi, + jtrack::TrackSel, + jtrack::Px, + jtrack::Py, + jtrack::Pz, + jtrack::P, + jtrack::Energy); + +using JTrackDielectronSub = JTrackDielectronSubs::iterator; + +DECLARE_SOA_TABLE(JMcParticleDielectronSubs, "AOD", "JMcPartDIELSubs", + o2::soa::Index<>, + bkgdielectronmc::CandidateId, + jmcparticle::Pt, + jmcparticle::Eta, + jmcparticle::Phi, + jmcparticle::Y, + jmcparticle::E, + jmcparticle::PdgCode, + jmcparticle::GenStatusCode, + jmcparticle::HepMCStatusCode, + jmcparticle::IsPhysicalPrimary, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy); + +using JMcParticleDielectronSub = JMcParticleDielectronSubs::iterator; + } // namespace o2::aod #endif // PWGJE_DATAMODEL_JETSUBTRACTION_H_ diff --git a/PWGJE/DataModel/JetTagging.h b/PWGJE/DataModel/JetTagging.h index 9893742bb4d..b84d9f01964 100644 --- a/PWGJE/DataModel/JetTagging.h +++ b/PWGJE/DataModel/JetTagging.h @@ -9,10 +9,11 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// +/// \file JetTagging.h /// \brief Table definitions for hf jet tagging /// /// \author Nima Zardoshti +/// \author Hanseo Park #ifndef PWGJE_DATAMODEL_JETTAGGING_H_ #define PWGJE_DATAMODEL_JETTAGGING_H_ @@ -21,8 +22,7 @@ #include #include "Framework/AnalysisDataModel.h" #include "PWGJE/DataModel/Jet.h" - -using namespace o2::analysis; +#include "PWGJE/Core/JetTaggingUtilities.h" namespace o2::aod { @@ -40,28 +40,122 @@ DECLARE_SOA_TABLE(JTracksTag, "AOD", "JTracksTag", using JTrackTag = JTracksTag::iterator; -// Defines the jet substrcuture table definition -#define JETTAGGING_TABLE_DEF(_jet_type_, _name_, _description_) \ - namespace _name_##tagging \ - { \ - DECLARE_SOA_COLUMN(Origin, origin, int); \ - DECLARE_SOA_COLUMN(JetProb, jetProb, std::vector); \ - DECLARE_SOA_COLUMN(Algorithm2, algorithm2, int); \ - DECLARE_SOA_COLUMN(Algorithm3, algorithm3, int); \ - } \ - DECLARE_SOA_TABLE(_jet_type_##Tags, "AOD", _description_ "Tags", _name_##tagging::Origin, _name_##tagging::JetProb, _name_##tagging::Algorithm2, _name_##tagging::Algorithm3); - -#define JETTAGGING_TABLES_DEF(_jet_type_, _description_) \ - JETTAGGING_TABLE_DEF(_jet_type_##Jet, _jet_type_##jet, _description_) \ - JETTAGGING_TABLE_DEF(_jet_type_##MCDetectorLevelJet, _jet_type_##mcdetectorleveljet, _description_ "MCD") \ +namespace secondary_vertex_params +{ +DECLARE_SOA_COLUMN(XPrimaryVertex, xPVertex, float); // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(YPrimaryVertex, yPVertex, float); // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(ZPrimaryVertex, zPVertex, float); // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(XSecondaryVertex, xSecondaryVertex, float); +DECLARE_SOA_COLUMN(YSecondaryVertex, ySecondaryVertex, float); +DECLARE_SOA_COLUMN(ZSecondaryVertex, zSecondaryVertex, float); +DECLARE_SOA_COLUMN(Px, px, float); +DECLARE_SOA_COLUMN(Py, py, float); +DECLARE_SOA_COLUMN(Pz, pz, float); +DECLARE_SOA_COLUMN(E, e, float); +DECLARE_SOA_COLUMN(M, m, float); +DECLARE_SOA_COLUMN(Chi2PCA, chi2PCA, float); +DECLARE_SOA_COLUMN(Dispersion, dispersion, float); +DECLARE_SOA_COLUMN(ErrorDecayLength, errorDecayLength, float); +DECLARE_SOA_COLUMN(ErrorDecayLengthXY, errorDecayLengthXY, float); +DECLARE_SOA_DYNAMIC_COLUMN(RSecondaryVertex, rSecondaryVertex, [](float xVtxS, float yVtxS) -> float { return RecoDecay::sqrtSumOfSquares(xVtxS, yVtxS); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float px, float py) -> float { return RecoDecay::pt(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float px, float py, float pz) -> float { return RecoDecay::p(px, py, pz); }); +DECLARE_SOA_DYNAMIC_COLUMN(PVector, pVector, [](float px, float py, float pz) -> std::array { return std::array{px, py, pz}; }); +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, [](float px, float py, float pz) -> float { return RecoDecay::eta(std::array{px, py, pz}); }); +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, [](float px, float py) -> float { return RecoDecay::phi(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(Y, y, [](float px, float py, float pz, double m) -> float { return RecoDecay::y(std::array{px, py, pz}, m); }); +DECLARE_SOA_DYNAMIC_COLUMN(DecayLength, decayLength, [](float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS) -> float { return RecoDecay::distance(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}); }); +DECLARE_SOA_DYNAMIC_COLUMN(DecayLengthXY, decayLengthXY, [](float xVtxP, float yVtxP, float xVtxS, float yVtxS) -> float { return RecoDecay::distanceXY(std::array{xVtxP, yVtxP}, std::array{xVtxS, yVtxS}); }); +DECLARE_SOA_DYNAMIC_COLUMN(DecayLengthNormalised, decayLengthNormalised, [](float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS, float err) -> float { return RecoDecay::distance(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}) / err; }); +DECLARE_SOA_DYNAMIC_COLUMN(DecayLengthXYNormalised, decayLengthXYNormalised, [](float xVtxP, float yVtxP, float xVtxS, float yVtxS, float err) -> float { return RecoDecay::distanceXY(std::array{xVtxP, yVtxP}, std::array{xVtxS, yVtxS}) / err; }); +DECLARE_SOA_DYNAMIC_COLUMN(CPA, cpa, [](float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS, float px, float py, float pz) -> float { return RecoDecay::cpa(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}, std::array{px, py, pz}); }); // o2-linter: disable=name/o2-column +DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterXY, impactParameterXY, [](float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS, float px, float py, float pz) -> float { return RecoDecay::impParXY(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}, std::array{px, py, pz}); }); +} // namespace secondary_vertex_params + +#define DECLARE_SV_TABLE(_jet_type_, _name_, _description_, _datatype_) \ + namespace _datatype_##_name_##parameters \ + { \ + DECLARE_SOA_INDEX_COLUMN(_jet_type_, jetIndex); \ + } \ + DECLARE_SOA_TABLE(_datatype_##_name_##s, "AOD", _description_, \ + o2::soa::Index<>, \ + _datatype_##_name_##parameters::_jet_type_##Id, \ + secondary_vertex_params::XPrimaryVertex, \ + secondary_vertex_params::YPrimaryVertex, \ + secondary_vertex_params::ZPrimaryVertex, \ + secondary_vertex_params::XSecondaryVertex, \ + secondary_vertex_params::YSecondaryVertex, \ + secondary_vertex_params::ZSecondaryVertex, \ + secondary_vertex_params::Px, \ + secondary_vertex_params::Py, \ + secondary_vertex_params::Pz, \ + secondary_vertex_params::E, \ + secondary_vertex_params::M, \ + secondary_vertex_params::Chi2PCA, \ + secondary_vertex_params::Dispersion, \ + secondary_vertex_params::ErrorDecayLength, \ + secondary_vertex_params::ErrorDecayLengthXY, \ + secondary_vertex_params::RSecondaryVertex, \ + secondary_vertex_params::Pt, \ + secondary_vertex_params::P, \ + secondary_vertex_params::PVector, \ + secondary_vertex_params::Eta, \ + secondary_vertex_params::Phi, \ + secondary_vertex_params::Y, \ + secondary_vertex_params::DecayLength, \ + secondary_vertex_params::DecayLengthXY, \ + secondary_vertex_params::DecayLengthNormalised, \ + secondary_vertex_params::DecayLengthXYNormalised, \ + secondary_vertex_params::CPA, \ + secondary_vertex_params::ImpactParameterXY); \ + namespace _name_##indices \ + { \ + DECLARE_SOA_ARRAY_INDEX_COLUMN(_datatype_##_name_, secondaryVertices); \ + } \ + DECLARE_SOA_TABLE(_datatype_##_name_##Indices, "AOD", _description_ "SVs", _name_##indices::_datatype_##_name_##Ids); + +#define JETSV_TABLES_DEF(_jet_type_, _name_, _description_) \ + DECLARE_SV_TABLE(_jet_type_##Jet, _name_, _description_, Data) \ + DECLARE_SV_TABLE(_jet_type_##MCDetectorLevelJet, _name_, _description_ "MCD", MCD) + +JETSV_TABLES_DEF(Charged, SecondaryVertex3Prong, "3PRONG"); +JETSV_TABLES_DEF(Charged, SecondaryVertex2Prong, "2PRONG"); + +// Defines the jet tagging table definition +namespace jettagging +{ +namespace flavourdef +{ +DECLARE_SOA_COLUMN(Origin, origin, int8_t); +} // namespace flavourdef +DECLARE_SOA_COLUMN(BitTaggedjet, bitTaggedjet, uint16_t); +DECLARE_SOA_COLUMN(JetProb, jetProb, float); +DECLARE_SOA_COLUMN(ScoreML, scoreML, float); +DECLARE_SOA_DYNAMIC_COLUMN(IsTagged, isTagged, [](uint16_t bit, BJetTaggingMethod method) -> bool { return TESTBIT(bit, method); }); +} // namespace jettagging + +#define JETFLAVOURDEF_TABLE_DEF(_jet_type_, _name_, _description_) \ + DECLARE_SOA_TABLE(_jet_type_##FlavourDef, "AOD", _description_ "FlavourDef", jettagging::flavourdef::Origin); + +#define JETTAGGING_TABLE_DEF(_jet_type_, _name_, _description_) \ + namespace _name_##util \ + { \ + DECLARE_SOA_DYNAMIC_COLUMN(Dummy##_jet_type_##tagging, dummy##_jet_type##tagging, \ + []() -> int { return 0; }); \ + } \ + DECLARE_SOA_TABLE(_jet_type_##Tags, "AOD", _description_ "Tags", \ + jettagging::BitTaggedjet, jettagging::JetProb, \ + jettagging::ScoreML, jettagging::IsTagged, _name_##util::Dummy##_jet_type_##tagging<>); + +#define JETTAGGING_TABLES_DEF(_jet_type_, _description_) \ + JETTAGGING_TABLE_DEF(_jet_type_##Jet, _jet_type_##jet, _description_) \ + JETFLAVOURDEF_TABLE_DEF(_jet_type_##MCDetectorLevelJet, _jet_type_##mcdetectorleveljet, _description_ "MCD") \ + JETTAGGING_TABLE_DEF(_jet_type_##MCDetectorLevelJet, _jet_type_##mcdetectorleveljet, _description_ "MCD") \ + JETFLAVOURDEF_TABLE_DEF(_jet_type_##MCParticleLevelJet, _jet_type_##mcparticleleveljet, _description_ "MCP") \ JETTAGGING_TABLE_DEF(_jet_type_##MCParticleLevelJet, _jet_type_##mcparticleleveljet, _description_ "MCP") JETTAGGING_TABLES_DEF(Charged, "C"); JETTAGGING_TABLES_DEF(Full, "F"); -JETTAGGING_TABLES_DEF(Neutral, "N"); -JETTAGGING_TABLES_DEF(D0Charged, "D0"); -JETTAGGING_TABLES_DEF(LcCharged, "Lc"); -JETTAGGING_TABLES_DEF(BplusCharged, "BPL"); } // namespace o2::aod diff --git a/PWGJE/DataModel/TrackJetQa.h b/PWGJE/DataModel/TrackJetQa.h index 858aa53b0db..913f43c29b0 100644 --- a/PWGJE/DataModel/TrackJetQa.h +++ b/PWGJE/DataModel/TrackJetQa.h @@ -32,11 +32,6 @@ #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" -using namespace o2; -using namespace o2::track; -using namespace o2::framework; -using namespace o2::framework::expressions; - // Derived data model for track optimization (and cut variation) namespace o2::aod { diff --git a/PWGJE/JetFinders/CMakeLists.txt b/PWGJE/JetFinders/CMakeLists.txt index bacf90a238d..a050f9d3fef 100644 --- a/PWGJE/JetFinders/CMakeLists.txt +++ b/PWGJE/JetFinders/CMakeLists.txt @@ -9,84 +9,144 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +add_subdirectory(Duplicates) if(FastJet_FOUND) o2physics_add_dpl_workflow(jet-finder-data-charged - SOURCES jetfinderdatacharged.cxx + SOURCES jetFinderDataCharged.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-mcd-charged - SOURCES jetfindermcdcharged.cxx + SOURCES jetFinderMCDCharged.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-mcp-charged - SOURCES jetfindermcpcharged.cxx + SOURCES jetFinderMCPCharged.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-data-full - SOURCES jetfinderdatafull.cxx + SOURCES jetFinderDataFull.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-mcd-full - SOURCES jetfindermcdfull.cxx + SOURCES jetFinderMCDFull.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-mcp-full - SOURCES jetfindermcpfull.cxx + SOURCES jetFinderMCPFull.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-data-neutral - SOURCES jetfinderdataneutral.cxx + SOURCES jetFinderDataNeutral.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-mcd-neutral - SOURCES jetfindermcdneutral.cxx + SOURCES jetFinderMCDNeutral.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-mcp-neutral - SOURCES jetfindermcpneutral.cxx + SOURCES jetFinderMCPNeutral.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-d0-data-charged - SOURCES jetfinderD0datacharged.cxx + SOURCES jetFinderD0DataCharged.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-d0-mcd-charged - SOURCES jetfinderD0mcdcharged.cxx + SOURCES jetFinderD0MCDCharged.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-d0-mcp-charged - SOURCES jetfinderD0mcpcharged.cxx + SOURCES jetFinderD0MCPCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-dplus-data-charged + SOURCES jetFinderDplusDataCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-dplus-mcd-charged + SOURCES jetFinderDplusMCDCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-dplus-mcp-charged + SOURCES jetFinderDplusMCPCharged.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-lc-data-charged - SOURCES jetfinderLcdatacharged.cxx + SOURCES jetFinderLcDataCharged.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-lc-mcd-charged - SOURCES jetfinderLcmcdcharged.cxx + SOURCES jetFinderLcMCDCharged.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-lc-mcp-charged - SOURCES jetfinderLcmcpcharged.cxx + SOURCES jetFinderLcMCPCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-bplus-data-charged + SOURCES jetFinderBplusDataCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-bplus-mcd-charged + SOURCES jetFinderBplusMCDCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-bplus-mcp-charged + SOURCES jetFinderBplusMCPCharged.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(jet-finder-v0-data-charged + SOURCES jetFinderV0DataCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-v0-mcd-charged + SOURCES jetFinderV0MCDCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-v0-mcp-charged + SOURCES jetFinderV0MCPCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-dielectron-data-charged + SOURCES jetFinderDielectronDataCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-dielectron-mcd-charged + SOURCES jetFinderDielectronMCDCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-dielectron-mcp-charged + SOURCES jetFinderDielectronMCPCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) endif() diff --git a/PWGJE/JetFinders/Duplicates/CMakeLists.txt b/PWGJE/JetFinders/Duplicates/CMakeLists.txt new file mode 100644 index 00000000000..4270de9f221 --- /dev/null +++ b/PWGJE/JetFinders/Duplicates/CMakeLists.txt @@ -0,0 +1,31 @@ +# 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. + + +if(FastJet_FOUND) + +o2physics_add_dpl_workflow(jet-finder-data-charged-1 + SOURCES jetFinderDataCharged1.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-mcd-charged-1 + SOURCES jetFinderMCDCharged1.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-mcp-charged-1 + SOURCES jetFinderMCPCharged1.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + + +endif() diff --git a/PWGJE/JetFinders/Duplicates/jetFinderDataCharged1.cxx b/PWGJE/JetFinders/Duplicates/jetFinderDataCharged1.cxx new file mode 100644 index 00000000000..46f2dd88df8 --- /dev/null +++ b/PWGJE/JetFinders/Duplicates/jetFinderDataCharged1.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet finder data charged 1 task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinder.cxx" + +using JetFinderDataCharged1 = JetFinderTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back( + adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJets", true}}}, TaskName{"jet-finder-data-charged-1"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/Duplicates/jetFinderMCDCharged1.cxx b/PWGJE/JetFinders/Duplicates/jetFinderMCDCharged1.cxx new file mode 100644 index 00000000000..4a13537a48b --- /dev/null +++ b/PWGJE/JetFinders/Duplicates/jetFinderMCDCharged1.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet finder mcd charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinder.cxx" + +using JetFinderMCDetectorLevelCharged1 = JetFinderTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back( + adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJets", true}}}, TaskName{"jet-finder-mcd-charged-1"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/Duplicates/jetFinderMCPCharged1.cxx b/PWGJE/JetFinders/Duplicates/jetFinderMCPCharged1.cxx new file mode 100644 index 00000000000..68e3f861ae6 --- /dev/null +++ b/PWGJE/JetFinders/Duplicates/jetFinderMCPCharged1.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet finder mcp charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinder.cxx" + +using JetFinderMCParticleLevelCharged1 = JetFinderTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back( + adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processParticleLevelChargedJets", true}}}, TaskName{"jet-finder-mcp-charged-1"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinder.cxx b/PWGJE/JetFinders/jetFinder.cxx new file mode 100644 index 00000000000..4482509804b --- /dev/null +++ b/PWGJE/JetFinders/jetFinder.cxx @@ -0,0 +1,240 @@ +// 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. + +// jet finder task +// +/// \author Nima Zardoshti +/// \author Jochen Klein +/// \author Raymond Ehlers , ORNL + +#include + +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; + +template +struct JetFinderTask { + Produces jetsTable; + Produces constituentsTable; + Produces jetsEvtWiseSubTable; + Produces constituentsEvtWiseSubTable; + + HistogramRegistry registry; + + // event level configurables + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + Configurable centralityMin{"centralityMin", -999.0, "minimum centrality"}; + Configurable centralityMax{"centralityMax", 999.0, "maximum centrality"}; + Configurable trackOccupancyInTimeRangeMax{"trackOccupancyInTimeRangeMax", 999999, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable triggerMasks{"triggerMasks", "", "possible JE Trigger masks: fJetChLowPt,fJetChHighPt,fTrackLowPt,fTrackHighPt,fJetD0ChLowPt,fJetD0ChHighPt,fJetLcChLowPt,fJetLcChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt,fJetNeutralHighPt,fJetNeutralLowPt,fGammaVeryHighPtEMCAL,fGammaVeryHighPtDCAL,fGammaHighPtEMCAL,fGammaHighPtDCAL,fGammaLowPtEMCAL,fGammaLowPtDCAL,fGammaVeryLowPtEMCAL,fGammaVeryLowPtDCAL"}; + Configurable skipMBGapEvents{"skipMBGapEvents", true, "decide to run over MB gap events or not"}; + + // track level configurables + Configurable trackPtMin{"trackPtMin", 0.15, "minimum track pT"}; + Configurable trackPtMax{"trackPtMax", 1000.0, "maximum track pT"}; + Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum track eta"}; + Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track eta"}; + Configurable trackPhiMin{"trackPhiMin", -999, "minimum track phi"}; + Configurable trackPhiMax{"trackPhiMax", 999, "maximum track phi"}; + Configurable trackingEfficiency{"trackingEfficiency", 1.0, "tracking efficiency applied to jet finding"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + Configurable particleSelections{"particleSelections", "PhysicalPrimary", "set particle selections"}; + + // cluster level configurables + Configurable clusterDefinitionS{"clusterDefinition", "kV3Default", "cluster definition to be selected, e.g. V3Default"}; + Configurable clusterEtaMin{"clusterEtaMin", -0.71, "minimum cluster eta"}; // For ECMAL: |eta| < 0.7, phi = 1.40 - 3.26 + Configurable clusterEtaMax{"clusterEtaMax", 0.71, "maximum cluster eta"}; // For ECMAL: |eta| < 0.7, phi = 1.40 - 3.26 + Configurable clusterPhiMin{"clusterPhiMin", 1.39, "minimum cluster phi"}; + Configurable clusterPhiMax{"clusterPhiMax", 3.27, "maximum cluster phi"}; + Configurable clusterEnergyMin{"clusterEnergyMin", 0.5, "minimum cluster energy in EMCAL (GeV)"}; + Configurable clusterTimeMin{"clusterTimeMin", -25., "minimum Cluster time (ns)"}; + Configurable clusterTimeMax{"clusterTimeMax", 25., "maximum Cluster time (ns)"}; + Configurable clusterRejectExotics{"clusterRejectExotics", true, "Reject exotic clusters"}; + Configurable hadronicCorrectionType{"hadronicCorrectionType", 0, "0 = no correction, 1 = CorrectedOneTrack1, 2 = CorrectedOneTrack2, 3 = CorrectedAllTracks1, 4 = CorrectedAllTracks2"}; + Configurable doEMCALEventSelection{"doEMCALEventSelection", true, "apply the selection to the event alias_bit for full and neutral jets"}; + Configurable doEMCALEventSelectionChargedJets{"doEMCALEventSelectionChargedJets", false, "apply the selection to the event alias_bit for charged jets"}; + + // jet level configurables + Configurable> jetRadius{"jetRadius", {0.4}, "jet resolution parameters"}; + Configurable jetPtMin{"jetPtMin", 0.0, "minimum jet pT"}; + Configurable jetPtMax{"jetPtMax", 1000.0, "maximum jet pT"}; + Configurable jetEWSPtMin{"jetEWSPtMin", 0.0, "minimum event-wise subtracted jet pT"}; + Configurable jetEWSPtMax{"jetEWSPtMax", 1000.0, "maximum event-wise subtracted jet pT"}; + Configurable jetEtaMin{"jetEtaMin", -99.0, "minimum jet pseudorapidity"}; + Configurable jetEtaMax{"jetEtaMax", 99.0, "maximum jet pseudorapidity"}; + Configurable jetAlgorithm{"jetAlgorithm", 2, "jet clustering algorithm. 0 = kT, 1 = C/A, 2 = Anti-kT"}; + Configurable jetRecombScheme{"jetRecombScheme", 0, "jet recombination scheme. 0 = E-scheme, 1 = pT-scheme, 2 = pT2-scheme"}; + Configurable jetGhostArea{"jetGhostArea", 0.005, "jet ghost area"}; + Configurable ghostRepeat{"ghostRepeat", 1, "set to 0 to gain speed if you dont need area calculation"}; + Configurable DoTriggering{"DoTriggering", false, "used for the charged jet trigger to remove the eta constraint on the jet axis"}; + Configurable jetAreaFractionMin{"jetAreaFractionMin", -99.0, "used to make a cut on the jet areas"}; + Configurable jetPtBinWidth{"jetPtBinWidth", 5, "used to define the width of the jetPt bins for the THnSparse"}; + Configurable fillTHnSparse{"fillTHnSparse", false, "switch to fill the THnSparse"}; + Configurable jetExtraParam{"jetExtraParam", -99.0, "sets the _extra_param in fastjet"}; + + Service pdgDatabase; + int trackSelection = -1; + std::vector eventSelectionBits; + std::string particleSelection; + + JetFinder jetFinder; + std::vector inputParticles; + + std::vector triggerMaskBits; + + void init(InitContext const&) + { + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(triggerMasks); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + particleSelection = static_cast(particleSelections); + + jetFinder.etaMin = trackEtaMin; + jetFinder.etaMax = trackEtaMax; + jetFinder.jetEtaMin = jetEtaMin; + jetFinder.jetEtaMax = jetEtaMax; + if (jetEtaMin < -98.0) { + jetFinder.jetEtaDefault = true; + } + jetFinder.algorithm = static_cast(static_cast(jetAlgorithm)); + jetFinder.recombScheme = static_cast(static_cast(jetRecombScheme)); + jetFinder.ghostArea = jetGhostArea; + jetFinder.ghostRepeatN = ghostRepeat; + if (DoTriggering) { + jetFinder.isTriggering = true; + } + jetFinder.fastjetExtraParam = jetExtraParam; + + auto jetRadiiBins = (std::vector)jetRadius; + if (jetRadiiBins.size() > 1) { + jetRadiiBins.push_back(jetRadiiBins[jetRadiiBins.size() - 1] + (TMath::Abs(jetRadiiBins[jetRadiiBins.size() - 1] - jetRadiiBins[jetRadiiBins.size() - 2]))); + } else { + jetRadiiBins.push_back(jetRadiiBins[jetRadiiBins.size() - 1] + 0.1); + } + std::vector jetPtBins; + int jetPtMaxInt = static_cast(jetPtMax); + int jetPtMinInt = static_cast(jetPtMin); + jetPtMinInt = (jetPtMinInt / jetPtBinWidth) * jetPtBinWidth; + jetPtMaxInt = ((jetPtMaxInt + jetPtBinWidth - 1) / jetPtBinWidth) * jetPtBinWidth; + int jetPtBinNumber = (jetPtMaxInt - jetPtMinInt) / jetPtBinWidth; + double jetPtMinDouble = static_cast(jetPtMinInt); + double jetPtMaxDouble = static_cast(jetPtMaxInt); + + if (fillTHnSparse) { + registry.add("hJet", "sparse for data or mcd jets", {HistType::kTHnC, {{jetRadiiBins, ""}, {jetPtBinNumber, jetPtMinDouble, jetPtMaxDouble}, {40, -1.0, 1.0}, {18, 0.0, 7.0}}}); + registry.add("hJetEWS", "sparse for data or mcd event-wise subtracted jets", {HistType::kTHnC, {{jetRadiiBins, ""}, {jetPtBinNumber, jetPtMinDouble, jetPtMaxDouble}, {40, -1.0, 1.0}, {18, 0.0, 7.0}}}); + registry.add("hJetMCP", "sparse for mcp jets", {HistType::kTHnC, {{jetRadiiBins, ""}, {jetPtBinNumber, jetPtMinDouble, jetPtMaxDouble}, {40, -1.0, 1.0}, {18, 0.0, 7.0}}}); + } + } + + aod::EMCALClusterDefinition clusterDefinition = aod::emcalcluster::getClusterDefinitionFromString(clusterDefinitionS.value); + Filter collisionFilter = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax && aod::jcollision::trackOccupancyInTimeRange <= trackOccupancyInTimeRangeMax && ((skipMBGapEvents.node() == false) || (aod::jcollision::subGeneratorId != static_cast(jetderiveddatautilities::JCollisionSubGeneratorId::mbGap)))); + Filter mcCollisionFilter = ((skipMBGapEvents.node() == false) || (aod::jmccollision::subGeneratorId != static_cast(jetderiveddatautilities::JCollisionSubGeneratorId::mbGap))); // should we add a posZ vtx cut here or leave it to analysers? + Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta >= trackEtaMin && aod::jtrack::eta <= trackEtaMax && aod::jtrack::phi >= trackPhiMin && aod::jtrack::phi <= trackPhiMax); // do we need eta cut both here and in globalselection? + Filter partCuts = (aod::jmcparticle::pt >= trackPtMin && aod::jmcparticle::pt < trackPtMax && aod::jmcparticle::eta >= trackEtaMin && aod::jmcparticle::eta <= trackEtaMax && aod::jmcparticle::phi >= trackPhiMin && aod::jmcparticle::phi <= trackPhiMax); + Filter clusterFilter = (aod::jcluster::definition == static_cast(clusterDefinition) && aod::jcluster::eta >= clusterEtaMin && aod::jcluster::eta <= clusterEtaMax && aod::jcluster::phi >= clusterPhiMin && aod::jcluster::phi <= clusterPhiMax && aod::jcluster::energy >= clusterEnergyMin && aod::jcluster::time > clusterTimeMin && aod::jcluster::time < clusterTimeMax && (clusterRejectExotics && aod::jcluster::isExotic != true)); + + void processChargedJets(soa::Filtered::iterator const& collision, + soa::Filtered const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || !jetderiveddatautilities::selectTrigger(collision, triggerMaskBits) || (doEMCALEventSelectionChargedJets && !jetderiveddatautilities::eventEMCAL(collision))) { + return; + } + inputParticles.clear(); + jetfindingutilities::analyseTracks, soa::Filtered::iterator>(inputParticles, tracks, trackSelection, trackingEfficiency); + jetfindingutilities::findJets(jetFinder, inputParticles, jetPtMin, jetPtMax, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable, fillTHnSparse ? registry.get(HIST("hJet")) : std::shared_ptr(nullptr), fillTHnSparse); + } + + PROCESS_SWITCH(JetFinderTask, processChargedJets, "Data and reco level jet finding for charged jets", false); + + void processChargedEvtWiseSubJets(soa::Filtered::iterator const& collision, + soa::Filtered const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || !jetderiveddatautilities::selectTrigger(collision, triggerMaskBits) || (doEMCALEventSelectionChargedJets && !jetderiveddatautilities::eventEMCAL(collision))) { + return; + } + inputParticles.clear(); + jetfindingutilities::analyseTracks, soa::Filtered::iterator>(inputParticles, tracks, trackSelection, trackingEfficiency); + jetfindingutilities::findJets(jetFinder, inputParticles, jetEWSPtMin, jetEWSPtMax, jetRadius, jetAreaFractionMin, collision, jetsEvtWiseSubTable, constituentsEvtWiseSubTable, fillTHnSparse ? registry.get(HIST("hJetEWS")) : std::shared_ptr(nullptr), fillTHnSparse); + } + + PROCESS_SWITCH(JetFinderTask, processChargedEvtWiseSubJets, "Data and reco level jet finding for charged jets with event-wise constituent subtraction", false); + + void processNeutralJets(soa::Filtered::iterator const& collision, + soa::Filtered const& clusters) + { + if ((doEMCALEventSelection && !jetderiveddatautilities::eventEMCAL(collision)) || !jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + inputParticles.clear(); + jetfindingutilities::analyseClusters(inputParticles, &clusters); + jetfindingutilities::findJets(jetFinder, inputParticles, jetPtMin, jetPtMax, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable, fillTHnSparse ? registry.get(HIST("hJet")) : std::shared_ptr(nullptr), fillTHnSparse); + } + PROCESS_SWITCH(JetFinderTask, processNeutralJets, "Data and reco level jet finding for neutral jets", false); + + void processFullJets(soa::Filtered::iterator const& collision, + soa::Filtered const& tracks, + soa::Filtered const& clusters) + { + if ((doEMCALEventSelection && !jetderiveddatautilities::eventEMCAL(collision)) || !jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + inputParticles.clear(); + jetfindingutilities::analyseTracks, soa::Filtered::iterator>(inputParticles, tracks, trackSelection, trackingEfficiency); + jetfindingutilities::analyseClusters(inputParticles, &clusters, hadronicCorrectionType); + jetfindingutilities::findJets(jetFinder, inputParticles, jetPtMin, jetPtMax, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable, fillTHnSparse ? registry.get(HIST("hJet")) : std::shared_ptr(nullptr), fillTHnSparse); + } + PROCESS_SWITCH(JetFinderTask, processFullJets, "Data and reco level jet finding for full and neutral jets", false); + + void processParticleLevelChargedJets(soa::Filtered::iterator const& collision, soa::Filtered const& particles) + { + // TODO: MC event selection? + inputParticles.clear(); + jetfindingutilities::analyseParticles, soa::Filtered::iterator>(inputParticles, particleSelection, 1, particles, pdgDatabase); + jetfindingutilities::findJets(jetFinder, inputParticles, jetPtMin, jetPtMax, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable, fillTHnSparse ? registry.get(HIST("hJetMCP")) : std::shared_ptr(nullptr), fillTHnSparse); + } + PROCESS_SWITCH(JetFinderTask, processParticleLevelChargedJets, "Particle level charged jet finding", false); + + void processParticleLevelChargedEvtWiseSubJets(soa::Filtered::iterator const& collision, soa::Filtered const& particles) + { + // TODO: MC event selection? + inputParticles.clear(); + jetfindingutilities::analyseParticles, soa::Filtered::iterator>(inputParticles, particleSelection, 1, particles, pdgDatabase); + jetfindingutilities::findJets(jetFinder, inputParticles, jetPtMin, jetPtMax, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable, fillTHnSparse ? registry.get(HIST("hJetMCP")) : std::shared_ptr(nullptr), fillTHnSparse); + } + PROCESS_SWITCH(JetFinderTask, processParticleLevelChargedEvtWiseSubJets, "Particle level charged with event-wise constituent subtraction jet finding", false); + + void processParticleLevelNeutralJets(soa::Filtered::iterator const& collision, soa::Filtered const& particles) + { + // TODO: MC event selection? + inputParticles.clear(); + jetfindingutilities::analyseParticles, soa::Filtered::iterator>(inputParticles, particleSelection, 2, particles, pdgDatabase); + jetfindingutilities::findJets(jetFinder, inputParticles, jetPtMin, jetPtMax, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable, fillTHnSparse ? registry.get(HIST("hJetMCP")) : std::shared_ptr(nullptr), fillTHnSparse); + } + PROCESS_SWITCH(JetFinderTask, processParticleLevelNeutralJets, "Particle level neutral jet finding", false); + + void processParticleLevelFullJets(soa::Filtered::iterator const& collision, soa::Filtered const& particles) + { + // TODO: MC event selection? + inputParticles.clear(); + jetfindingutilities::analyseParticles, soa::Filtered::iterator>(inputParticles, particleSelection, 0, particles, pdgDatabase); + jetfindingutilities::findJets(jetFinder, inputParticles, jetPtMin, jetPtMax, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable, fillTHnSparse ? registry.get(HIST("hJetMCP")) : std::shared_ptr(nullptr), fillTHnSparse); + } + + PROCESS_SWITCH(JetFinderTask, processParticleLevelFullJets, "Particle level full jet finding", false); +}; diff --git a/PWGJE/JetFinders/jetFinderBplusDataCharged.cxx b/PWGJE/JetFinders/jetFinderBplusDataCharged.cxx new file mode 100644 index 00000000000..402527211fb --- /dev/null +++ b/PWGJE/JetFinders/jetFinderBplusDataCharged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet finder B+ data charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +using JetFinderBplusDataCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsData", true}}}, + TaskName{"jet-finder-bplus-data-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderBplusMCDCharged.cxx b/PWGJE/JetFinders/jetFinderBplusMCDCharged.cxx new file mode 100644 index 00000000000..4eed52e30b3 --- /dev/null +++ b/PWGJE/JetFinders/jetFinderBplusMCDCharged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet finder B+ mcd charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +using JetFinderBplusMCDetectorLevelCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsMCD", true}}}, + TaskName{"jet-finder-bplus-mcd-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderBplusMCPCharged.cxx b/PWGJE/JetFinders/jetFinderBplusMCPCharged.cxx new file mode 100644 index 00000000000..83a1e7c9d60 --- /dev/null +++ b/PWGJE/JetFinders/jetFinderBplusMCPCharged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet finder B+ mcp charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +using JetFinderBplusMCParticleLevelCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsMCP", true}}}, + TaskName{"jet-finder-bplus-mcp-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetfinderD0datacharged.cxx b/PWGJE/JetFinders/jetFinderD0DataCharged.cxx similarity index 75% rename from PWGJE/JetFinders/jetfinderD0datacharged.cxx rename to PWGJE/JetFinders/jetFinderD0DataCharged.cxx index 7bdd6e87d9d..29ab757dbce 100644 --- a/PWGJE/JetFinders/jetfinderD0datacharged.cxx +++ b/PWGJE/JetFinders/jetFinderD0DataCharged.cxx @@ -13,9 +13,9 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderhf.cxx" +#include "PWGJE/JetFinders/jetFinderHF.cxx" -using JetFinderD0DataCharged = JetFinderHFTask; +using JetFinderD0DataCharged = JetFinderHFTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetfinderD0mcdcharged.cxx b/PWGJE/JetFinders/jetFinderD0MCDCharged.cxx similarity index 72% rename from PWGJE/JetFinders/jetfinderD0mcdcharged.cxx rename to PWGJE/JetFinders/jetFinderD0MCDCharged.cxx index 1471e00ffa3..46847bf8651 100644 --- a/PWGJE/JetFinders/jetfinderD0mcdcharged.cxx +++ b/PWGJE/JetFinders/jetFinderD0MCDCharged.cxx @@ -13,9 +13,9 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderhf.cxx" +#include "PWGJE/JetFinders/jetFinderHF.cxx" -using JetFinderD0MCDetectorLevelCharged = JetFinderHFTask; +using JetFinderD0MCDetectorLevelCharged = JetFinderHFTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetfinderD0mcpcharged.cxx b/PWGJE/JetFinders/jetFinderD0MCPCharged.cxx similarity index 72% rename from PWGJE/JetFinders/jetfinderD0mcpcharged.cxx rename to PWGJE/JetFinders/jetFinderD0MCPCharged.cxx index 27764256e04..a21aceff347 100644 --- a/PWGJE/JetFinders/jetfinderD0mcpcharged.cxx +++ b/PWGJE/JetFinders/jetFinderD0MCPCharged.cxx @@ -13,9 +13,9 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderhf.cxx" +#include "PWGJE/JetFinders/jetFinderHF.cxx" -using JetFinderD0MCParticleLevelCharged = JetFinderHFTask; +using JetFinderD0MCParticleLevelCharged = JetFinderHFTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetfinderdatacharged.cxx b/PWGJE/JetFinders/jetFinderDataCharged.cxx similarity index 96% rename from PWGJE/JetFinders/jetfinderdatacharged.cxx rename to PWGJE/JetFinders/jetFinderDataCharged.cxx index df740ad2dba..e713eb4fa7c 100644 --- a/PWGJE/JetFinders/jetfinderdatacharged.cxx +++ b/PWGJE/JetFinders/jetFinderDataCharged.cxx @@ -13,7 +13,7 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" using JetFinderDataCharged = JetFinderTask; diff --git a/PWGJE/JetFinders/jetfinderdatafull.cxx b/PWGJE/JetFinders/jetFinderDataFull.cxx similarity index 96% rename from PWGJE/JetFinders/jetfinderdatafull.cxx rename to PWGJE/JetFinders/jetFinderDataFull.cxx index a75896212be..07d103d93b2 100644 --- a/PWGJE/JetFinders/jetfinderdatafull.cxx +++ b/PWGJE/JetFinders/jetFinderDataFull.cxx @@ -13,7 +13,7 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" using JetFinderDataFull = JetFinderTask; diff --git a/PWGJE/JetFinders/jetfinderdataneutral.cxx b/PWGJE/JetFinders/jetFinderDataNeutral.cxx similarity index 96% rename from PWGJE/JetFinders/jetfinderdataneutral.cxx rename to PWGJE/JetFinders/jetFinderDataNeutral.cxx index a325de11bbd..28a1b898a15 100644 --- a/PWGJE/JetFinders/jetfinderdataneutral.cxx +++ b/PWGJE/JetFinders/jetFinderDataNeutral.cxx @@ -13,7 +13,7 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" using JetFinderDataNeutral = JetFinderTask; diff --git a/PWGJE/JetFinders/jetFinderDielectronDataCharged.cxx b/PWGJE/JetFinders/jetFinderDielectronDataCharged.cxx new file mode 100644 index 00000000000..2b040080579 --- /dev/null +++ b/PWGJE/JetFinders/jetFinderDielectronDataCharged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet finder dielectron data charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +using JetFinderDielectronDataCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsData", true}}}, + TaskName{"jet-finder-dielectron-data-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderDielectronMCDCharged.cxx b/PWGJE/JetFinders/jetFinderDielectronMCDCharged.cxx new file mode 100644 index 00000000000..105b58d459a --- /dev/null +++ b/PWGJE/JetFinders/jetFinderDielectronMCDCharged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet finder dielectron mcd charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +using JetFinderDielectronMCDetectorLevelCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsMCD", true}}}, + TaskName{"jet-finder-dielectron-mcd-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderDielectronMCPCharged.cxx b/PWGJE/JetFinders/jetFinderDielectronMCPCharged.cxx new file mode 100644 index 00000000000..b6aa797e80e --- /dev/null +++ b/PWGJE/JetFinders/jetFinderDielectronMCPCharged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet finder dielectron mcp charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +using JetFinderDielectronMCParticleLevelCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsMCP", true}}}, + TaskName{"jet-finder-dielectron-mcp-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderDplusDataCharged.cxx b/PWGJE/JetFinders/jetFinderDplusDataCharged.cxx new file mode 100644 index 00000000000..a0cdbdf2a24 --- /dev/null +++ b/PWGJE/JetFinders/jetFinderDplusDataCharged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet finder D+ data charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +using JetFinderDplusDataCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsData", true}}}, + TaskName{"jet-finder-dplus-data-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderDplusMCDCharged.cxx b/PWGJE/JetFinders/jetFinderDplusMCDCharged.cxx new file mode 100644 index 00000000000..0a401d330ef --- /dev/null +++ b/PWGJE/JetFinders/jetFinderDplusMCDCharged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet finder D+ mcd charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +using JetFinderDplusMCDetectorLevelCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsMCD", true}}}, + TaskName{"jet-finder-dplus-mcd-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderDplusMCPCharged.cxx b/PWGJE/JetFinders/jetFinderDplusMCPCharged.cxx new file mode 100644 index 00000000000..4c5cb4a604d --- /dev/null +++ b/PWGJE/JetFinders/jetFinderDplusMCPCharged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet finder D+ mcp charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +using JetFinderDplusMCParticleLevelCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsMCP", true}}}, + TaskName{"jet-finder-dplus-mcp-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetfinderhf.cxx b/PWGJE/JetFinders/jetFinderHF.cxx similarity index 55% rename from PWGJE/JetFinders/jetfinderhf.cxx rename to PWGJE/JetFinders/jetFinderHF.cxx index 4cfcd51791e..0b8fc666607 100644 --- a/PWGJE/JetFinders/jetfinderhf.cxx +++ b/PWGJE/JetFinders/jetFinderHF.cxx @@ -14,9 +14,12 @@ /// \author Nima Zardoshti /// \author Jochen Klein +#include + #include "CommonConstants/PhysicsConstants.h" #include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" #include "Common/Core/RecoDecay.h" using namespace o2; @@ -24,36 +27,26 @@ using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; -/* -void customize(std::vector& workflowOptions) -{ - std::vector hfjetworkflows{{"d0-data-charged", VariantType::Int, 1, {"D0 jets charged data"}}, - {"d0-mcd-charged", VariantType::Int, 0, {"D0 jets charged MCD"}}, - {"d0-mcp-charged", VariantType::Int, 0, {"D0 jets charged MCD"}}, - {"bplus-data-charged", VariantType::Int, 0, {"B+ jets charged MCD"}}, - {"bplus-mcd-charged", VariantType::Int, 0, {"B+ jets charged MCD"}}, - {"bplus-mcp-charged", VariantType::Int, 0, {"B+ jets charged MCD"}}, - {"lc-data-charged", VariantType::Int, 0, {"Lc jets charged MCD"}}, - {"lc-mcd-charged", VariantType::Int, 0, {"Lc jets charged MCD"}}, - {"lc-mcp-charged", VariantType::Int, 0, {"Lc jets charged MCD"}}}; - std::swap(workflowOptions, hfjetworkflows); -} -*/ - // NB: runDataProcessing.h must be included after customize! #include "Framework/runDataProcessing.h" -template +template struct JetFinderHFTask { Produces jetsTable; Produces constituentsTable; Produces jetsEvtWiseSubTable; Produces constituentsEvtWiseSubTable; + HistogramRegistry registry; + // event level configurables Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; Configurable centralityMin{"centralityMin", -999.0, "minimum centrality"}; Configurable centralityMax{"centralityMax", 999.0, "maximum centrality"}; + Configurable trackOccupancyInTimeRangeMax{"trackOccupancyInTimeRangeMax", 999999, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable triggerMasks{"triggerMasks", "", "possible JE Trigger masks: fJetChLowPt,fJetChHighPt,fTrackLowPt,fTrackHighPt,fJetD0ChLowPt,fJetD0ChHighPt,fJetLcChLowPt,fJetLcChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt,fJetNeutralHighPt,fJetNeutralLowPt,fGammaVeryHighPtEMCAL,fGammaVeryHighPtDCAL,fGammaHighPtEMCAL,fGammaHighPtDCAL,fGammaLowPtEMCAL,fGammaLowPtDCAL,fGammaVeryLowPtEMCAL,fGammaVeryLowPtDCAL"}; + Configurable skipMBGapEvents{"skipMBGapEvents", true, "decide to run over MB gap events or not"}; // track level configurables Configurable trackPtMin{"trackPtMin", 0.15, "minimum track pT"}; @@ -62,8 +55,8 @@ struct JetFinderHFTask { Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track eta"}; Configurable trackPhiMin{"trackPhiMin", -999, "minimum track phi"}; Configurable trackPhiMax{"trackPhiMax", 999, "maximum track phi"}; + Configurable trackingEfficiency{"trackingEfficiency", 1.0, "tracking efficiency applied to jet finding"}; Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; - Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; Configurable particleSelections{"particleSelections", "PhysicalPrimary", "set particle selections"}; // cluster level configurables @@ -99,20 +92,27 @@ struct JetFinderHFTask { Configurable jetRecombScheme{"jetRecombScheme", 0, "jet recombination scheme. 0 = E-scheme, 1 = pT-scheme, 2 = pT2-scheme"}; Configurable jetGhostArea{"jetGhostArea", 0.005, "jet ghost area"}; Configurable ghostRepeat{"ghostRepeat", 1, "set to 0 to gain speed if you dont need area calculation"}; + Configurable DoTriggering{"DoTriggering", false, "used for the charged jet trigger to remove the eta constraint on the jet axis"}; Configurable jetAreaFractionMin{"jetAreaFractionMin", -99.0, "used to make a cut on the jet areas"}; + Configurable jetPtBinWidth{"jetPtBinWidth", 5, "used to define the width of the jetPt bins for the THnSparse"}; + Configurable fillTHnSparse{"fillTHnSparse", false, "switch to fill the THnSparse"}; + Configurable jetExtraParam{"jetExtraParam", -99.0, "sets the _extra_param in fastjet"}; Service pdgDatabase; int trackSelection = -1; - int eventSelection = -1; + std::vector eventSelectionBits; std::string particleSelection; JetFinder jetFinder; std::vector inputParticles; + std::vector triggerMaskBits; + void init(InitContext const&) { trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(eventSelections)); + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(triggerMasks); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); particleSelection = static_cast(particleSelections); jetFinder.etaMin = trackEtaMin; @@ -128,53 +128,82 @@ struct JetFinderHFTask { jetFinder.recombScheme = static_cast(static_cast(jetRecombScheme)); jetFinder.ghostArea = jetGhostArea; jetFinder.ghostRepeatN = ghostRepeat; + if (DoTriggering) { + jetFinder.isTriggering = true; + } + jetFinder.fastjetExtraParam = jetExtraParam; + + auto jetRadiiBins = (std::vector)jetRadius; + if (jetRadiiBins.size() > 1) { + jetRadiiBins.push_back(jetRadiiBins[jetRadiiBins.size() - 1] + (TMath::Abs(jetRadiiBins[jetRadiiBins.size() - 1] - jetRadiiBins[jetRadiiBins.size() - 2]))); + } else { + jetRadiiBins.push_back(jetRadiiBins[jetRadiiBins.size() - 1] + 0.1); + } + std::vector jetPtBins; + int jetPtMaxInt = static_cast(jetPtMax); + int jetPtMinInt = static_cast(jetPtMin); + jetPtMinInt = (jetPtMinInt / jetPtBinWidth) * jetPtBinWidth; + jetPtMaxInt = ((jetPtMaxInt + jetPtBinWidth - 1) / jetPtBinWidth) * jetPtBinWidth; + int jetPtBinNumber = (jetPtMaxInt - jetPtMinInt) / jetPtBinWidth; + double jetPtMinDouble = static_cast(jetPtMinInt); + double jetPtMaxDouble = static_cast(jetPtMaxInt); + + registry.add("hJet", "sparse for data or mcd jets", {HistType::kTHnC, {{jetRadiiBins, ""}, {jetPtBinNumber, jetPtMinDouble, jetPtMaxDouble}, {40, -1.0, 1.0}, {18, 0.0, 7.0}}}); + registry.add("hJetMCP", "sparse for mcp jets", {HistType::kTHnC, {{jetRadiiBins, ""}, {jetPtBinNumber, jetPtMinDouble, jetPtMaxDouble}, {40, -1.0, 1.0}, {18, 0.0, 7.0}}}); } aod::EMCALClusterDefinition clusterDefinition = aod::emcalcluster::getClusterDefinitionFromString(clusterDefinitionS.value); - Filter collisionFilter = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax); - Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax && aod::jtrack::phi >= trackPhiMin && aod::jtrack::phi <= trackPhiMax); - Filter trackSubCuts = (aod::jtracksub::pt >= trackPtMin && aod::jtracksub::pt < trackPtMax && aod::jtracksub::eta > trackEtaMin && aod::jtracksub::eta < trackEtaMax && aod::jtracksub::phi >= trackPhiMin && aod::jtracksub::phi <= trackPhiMax); - Filter partCuts = (aod::jmcparticle::pt >= trackPtMin && aod::jmcparticle::pt < trackPtMax); - Filter clusterFilter = (aod::jcluster::definition == static_cast(clusterDefinition) && aod::jcluster::eta > clusterEtaMin && aod::jcluster::eta < clusterEtaMax && aod::jcluster::phi >= clusterPhiMin && aod::jcluster::phi <= clusterPhiMax && aod::jcluster::energy >= clusterEnergyMin && aod::jcluster::time > clusterTimeMin && aod::jcluster::time < clusterTimeMax && (clusterRejectExotics && aod::jcluster::isExotic != true)); + Filter collisionFilter = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax && aod::jcollision::trackOccupancyInTimeRange <= trackOccupancyInTimeRangeMax && ((skipMBGapEvents.node() == false) || (aod::jcollision::subGeneratorId != static_cast(jetderiveddatautilities::JCollisionSubGeneratorId::mbGap)))); + Filter mcCollisionFilter = ((skipMBGapEvents.node() == false) || (aod::jmccollision::subGeneratorId != static_cast(jetderiveddatautilities::JCollisionSubGeneratorId::mbGap))); // should we add a posZ vtx cut here or leave it to analysers? + Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta >= trackEtaMin && aod::jtrack::eta <= trackEtaMax && aod::jtrack::phi >= trackPhiMin && aod::jtrack::phi <= trackPhiMax); + Filter partCuts = (aod::jmcparticle::pt >= trackPtMin && aod::jmcparticle::pt < trackPtMax && aod::jmcparticle::eta >= trackEtaMin && aod::jmcparticle::eta <= trackEtaMax && aod::jmcparticle::phi >= trackPhiMin && aod::jmcparticle::phi <= trackPhiMax); + Filter clusterFilter = (aod::jcluster::definition == static_cast(clusterDefinition) && aod::jcluster::eta >= clusterEtaMin && aod::jcluster::eta <= clusterEtaMax && aod::jcluster::phi >= clusterPhiMin && aod::jcluster::phi <= clusterPhiMax && aod::jcluster::energy >= clusterEnergyMin && aod::jcluster::time > clusterTimeMin && aod::jcluster::time < clusterTimeMax && (clusterRejectExotics && aod::jcluster::isExotic != true)); // Filter candidateCuts = (aod::hfcand::pt >= candPtMin && aod::hfcand::pt < candPtMax && aod::hfcand::y >= candYMin && aod::hfcand::y < candYMax); PresliceOptional> perD0Candidate = aod::bkgd0::candidateId; + PresliceOptional> perD0McCandidate = aod::bkgd0mc::candidateId; + PresliceOptional> perDplusCandidate = aod::bkgdplus::candidateId; + PresliceOptional> perDplusMcCandidate = aod::bkgdplusmc::candidateId; PresliceOptional> perLcCandidate = aod::bkglc::candidateId; + PresliceOptional> perLcMcCandidate = aod::bkglcmc::candidateId; PresliceOptional> perBplusCandidate = aod::bkgbplus::candidateId; + PresliceOptional> perBplusMcCandidate = aod::bkgbplusmc::candidateId; + PresliceOptional> perDielectronCandidate = aod::bkgdielectron::candidateId; + PresliceOptional> perDielectronMcCandidate = aod::bkgdielectronmc::candidateId; // function that generalically processes Data and reco level events template void analyseCharged(T const& collision, U const& tracks, V const& candidate, M& jetsTableInput, N& constituentsTableInput, O& /*originalTracks*/, float minJetPt, float maxJetPt) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || !jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { return; } inputParticles.clear(); - if constexpr (jethfutilities::isHFCandidate()) { + if constexpr (jetcandidateutilities::isCandidate()) { if (!jetfindingutilities::analyseCandidate(inputParticles, candidate, candPtMin, candPtMax, candYMin, candYMax)) { return; } } - if constexpr (jethfutilities::isHFMcCandidate()) { + if constexpr (jetcandidateutilities::isMcCandidate()) { if (!jetfindingutilities::analyseCandidateMC(inputParticles, candidate, candPtMin, candPtMax, candYMin, candYMax, rejectBackgroundMCDCandidates)) { return; } } if constexpr (isEvtWiseSub) { - jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection); + jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, trackingEfficiency); } else { - jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, std::optional{candidate}); + jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, trackingEfficiency, std::optional{candidate}); } - jetfindingutilities::findJets(jetFinder, inputParticles, minJetPt, maxJetPt, jetRadius, jetAreaFractionMin, collision, jetsTableInput, constituentsTableInput, true); + jetfindingutilities::findJets(jetFinder, inputParticles, minJetPt, maxJetPt, jetRadius, jetAreaFractionMin, collision, jetsTableInput, constituentsTableInput, registry.get(HIST("hJet")), fillTHnSparse, true); } // function that generalically processes gen level events - template + template void analyseMCP(T const& collision, U const& particles, V const& candidate, int jetTypeParticleLevel, float minJetPt, float maxJetPt) { - if (rejectIncorrectDecaysMCP && !jethfutilities::isMatchedHFCandidate(candidate)) { // is this even needed in the new derived format? it means any simulations run have to force the decay channel + if (rejectIncorrectDecaysMCP && !jetcandidateutilities::isMatchedCandidate(candidate)) { // is this even needed in the new derived format? it means any simulations run have to force the decay channel return; } @@ -182,16 +211,20 @@ struct JetFinderHFTask { if (!jetfindingutilities::analyseCandidate(inputParticles, candidate, candPtMin, candPtMax, candYMin, candYMax)) { return; } - jetfindingutilities::analyseParticles(inputParticles, particleSelection, jetTypeParticleLevel, particles, pdgDatabase, std::optional{candidate}); - jetfindingutilities::findJets(jetFinder, inputParticles, minJetPt, maxJetPt, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable, true); + if constexpr (checkIsDaughter) { + jetfindingutilities::analyseParticles(inputParticles, particleSelection, jetTypeParticleLevel, particles, pdgDatabase, std::optional{candidate}); + } else { + jetfindingutilities::analyseParticles(inputParticles, particleSelection, jetTypeParticleLevel, particles, pdgDatabase, std::optional{candidate}); + } + jetfindingutilities::findJets(jetFinder, inputParticles, minJetPt, maxJetPt, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable, registry.get(HIST("hJetMCP")), fillTHnSparse, true); } - void processDummy(JetCollisions const&) + void processDummy(aod::JetCollisions const&) { } PROCESS_SWITCH(JetFinderHFTask, processDummy, "Dummy process function turned on by default", true); - void processChargedJetsData(soa::Filtered::iterator const& collision, soa::Filtered const& tracks, CandidateTableData const& candidates) + void processChargedJetsData(soa::Filtered::iterator const& collision, soa::Filtered const& tracks, CandidateTableData const& candidates) { for (typename CandidateTableData::iterator const& candidate : candidates) { // why can the type not be auto? try const auto analyseCharged(collision, tracks, candidate, jetsTable, constituentsTable, tracks, jetPtMin, jetPtMax); @@ -199,15 +232,15 @@ struct JetFinderHFTask { } PROCESS_SWITCH(JetFinderHFTask, processChargedJetsData, "charged hf jet finding on data", false); - void processChargedEvtWiseSubJetsData(soa::Filtered::iterator const& collision, soa::Filtered const& tracks, CandidateTableData const& candidates) + void processChargedEvtWiseSubJetsData(soa::Filtered::iterator const& collision, soa::Filtered const& tracks, CandidateTableData const& candidates) { for (typename CandidateTableData::iterator const& candidate : candidates) { - analyseCharged(collision, jethfutilities::slicedPerCandidate(tracks, candidate, perD0Candidate, perLcCandidate, perBplusCandidate), candidate, jetsEvtWiseSubTable, constituentsEvtWiseSubTable, tracks, jetEWSPtMin, jetEWSPtMax); + analyseCharged(collision, jetcandidateutilities::slicedPerCandidate(tracks, candidate, perD0Candidate, perDplusCandidate, perLcCandidate, perBplusCandidate, perDielectronCandidate), candidate, jetsEvtWiseSubTable, constituentsEvtWiseSubTable, tracks, jetEWSPtMin, jetEWSPtMax); } } PROCESS_SWITCH(JetFinderHFTask, processChargedEvtWiseSubJetsData, "charged hf jet finding on data with event-wise constituent subtraction", false); - void processChargedJetsMCD(soa::Filtered::iterator const& collision, soa::Filtered const& tracks, CandidateTableMCD const& candidates) + void processChargedJetsMCD(soa::Filtered::iterator const& collision, soa::Filtered const& tracks, CandidateTableMCD const& candidates) { for (typename CandidateTableMCD::iterator const& candidate : candidates) { analyseCharged(collision, tracks, candidate, jetsTable, constituentsTable, tracks, jetPtMin, jetPtMax); @@ -215,21 +248,31 @@ struct JetFinderHFTask { } PROCESS_SWITCH(JetFinderHFTask, processChargedJetsMCD, "charged hf jet finding on MC detector level", false); - void processChargedEvtWiseSubJetsMCD(soa::Filtered::iterator const& collision, soa::Filtered const& tracks, CandidateTableMCD const& candidates) + void processChargedEvtWiseSubJetsMCD(soa::Filtered::iterator const& collision, soa::Filtered const& tracks, CandidateTableMCD const& candidates) { for (typename CandidateTableMCD::iterator const& candidate : candidates) { - analyseCharged(collision, jethfutilities::slicedPerCandidate(tracks, candidate, perD0Candidate, perLcCandidate, perBplusCandidate), candidate, jetsEvtWiseSubTable, constituentsEvtWiseSubTable, tracks, jetEWSPtMin, jetEWSPtMax); + analyseCharged(collision, jetcandidateutilities::slicedPerCandidate(tracks, candidate, perD0Candidate, perDplusCandidate, perLcCandidate, perBplusCandidate, perDielectronCandidate), candidate, jetsEvtWiseSubTable, constituentsEvtWiseSubTable, tracks, jetEWSPtMin, jetEWSPtMax); } } PROCESS_SWITCH(JetFinderHFTask, processChargedEvtWiseSubJetsMCD, "charged hf jet finding on MC detector level with event-wise constituent subtraction", false); - void processChargedJetsMCP(JetMcCollision const& collision, - soa::Filtered const& particles, + void processChargedJetsMCP(soa::Filtered::iterator const& collision, + soa::Filtered const& particles, CandidateTableMCP const& candidates) { for (typename CandidateTableMCP::iterator const& candidate : candidates) { - analyseMCP(collision, particles, candidate, 1, jetPtMin, jetPtMax); + analyseMCP(collision, particles, candidate, 1, jetPtMin, jetPtMax); } } PROCESS_SWITCH(JetFinderHFTask, processChargedJetsMCP, "hf jet finding on MC particle level", false); + + void processChargedEvtWiseSubJetsMCP(soa::Filtered::iterator const& collision, + soa::Filtered const& particles, + CandidateTableMCP const& candidates) + { + for (typename CandidateTableMCP::iterator const& candidate : candidates) { + analyseMCP(collision, jetcandidateutilities::slicedPerCandidate(particles, candidate, perD0McCandidate, perDplusMcCandidate, perLcMcCandidate, perBplusMcCandidate, perDielectronMcCandidate), candidate, 1, jetPtMin, jetPtMax); + } + } + PROCESS_SWITCH(JetFinderHFTask, processChargedEvtWiseSubJetsMCP, "hf jet finding on MC particle level", false); }; diff --git a/PWGJE/JetFinders/jetfinderLcdatacharged.cxx b/PWGJE/JetFinders/jetFinderLcDataCharged.cxx similarity index 75% rename from PWGJE/JetFinders/jetfinderLcdatacharged.cxx rename to PWGJE/JetFinders/jetFinderLcDataCharged.cxx index 44af0addc98..821cbd87df8 100644 --- a/PWGJE/JetFinders/jetfinderLcdatacharged.cxx +++ b/PWGJE/JetFinders/jetFinderLcDataCharged.cxx @@ -13,9 +13,9 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderhf.cxx" +#include "PWGJE/JetFinders/jetFinderHF.cxx" -using JetFinderLcDataCharged = JetFinderHFTask; +using JetFinderLcDataCharged = JetFinderHFTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetfinderLcmcdcharged.cxx b/PWGJE/JetFinders/jetFinderLcMCDCharged.cxx similarity index 72% rename from PWGJE/JetFinders/jetfinderLcmcdcharged.cxx rename to PWGJE/JetFinders/jetFinderLcMCDCharged.cxx index fa5e0aa2d86..c25f35c0efb 100644 --- a/PWGJE/JetFinders/jetfinderLcmcdcharged.cxx +++ b/PWGJE/JetFinders/jetFinderLcMCDCharged.cxx @@ -13,9 +13,9 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderhf.cxx" +#include "PWGJE/JetFinders/jetFinderHF.cxx" -using JetFinderLcMCDetectorLevelCharged = JetFinderHFTask; +using JetFinderLcMCDetectorLevelCharged = JetFinderHFTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetfinderLcmcpcharged.cxx b/PWGJE/JetFinders/jetFinderLcMCPCharged.cxx similarity index 72% rename from PWGJE/JetFinders/jetfinderLcmcpcharged.cxx rename to PWGJE/JetFinders/jetFinderLcMCPCharged.cxx index 4c018ce1cfe..41607ed57d9 100644 --- a/PWGJE/JetFinders/jetfinderLcmcpcharged.cxx +++ b/PWGJE/JetFinders/jetFinderLcMCPCharged.cxx @@ -13,9 +13,9 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderhf.cxx" +#include "PWGJE/JetFinders/jetFinderHF.cxx" -using JetFinderLcMCParticleLevelCharged = JetFinderHFTask; +using JetFinderLcMCParticleLevelCharged = JetFinderHFTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetfindermcdcharged.cxx b/PWGJE/JetFinders/jetFinderMCDCharged.cxx similarity index 96% rename from PWGJE/JetFinders/jetfindermcdcharged.cxx rename to PWGJE/JetFinders/jetFinderMCDCharged.cxx index 6f248edcaf8..d8558a57770 100644 --- a/PWGJE/JetFinders/jetfindermcdcharged.cxx +++ b/PWGJE/JetFinders/jetFinderMCDCharged.cxx @@ -13,7 +13,7 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" using JetFinderMCDetectorLevelCharged = JetFinderTask; diff --git a/PWGJE/JetFinders/jetfindermcdfull.cxx b/PWGJE/JetFinders/jetFinderMCDFull.cxx similarity index 96% rename from PWGJE/JetFinders/jetfindermcdfull.cxx rename to PWGJE/JetFinders/jetFinderMCDFull.cxx index 29464e814c9..0123b75d823 100644 --- a/PWGJE/JetFinders/jetfindermcdfull.cxx +++ b/PWGJE/JetFinders/jetFinderMCDFull.cxx @@ -13,7 +13,7 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" using JetFinderMCDetectorLevelFull = JetFinderTask; diff --git a/PWGJE/JetFinders/jetfindermcdneutral.cxx b/PWGJE/JetFinders/jetFinderMCDNeutral.cxx similarity index 96% rename from PWGJE/JetFinders/jetfindermcdneutral.cxx rename to PWGJE/JetFinders/jetFinderMCDNeutral.cxx index f58cc09492d..9e8225b0c5f 100644 --- a/PWGJE/JetFinders/jetfindermcdneutral.cxx +++ b/PWGJE/JetFinders/jetFinderMCDNeutral.cxx @@ -13,7 +13,7 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" using JetFinderMCDetectorLevelNeutral = JetFinderTask; diff --git a/PWGJE/JetFinders/jetfindermcpcharged.cxx b/PWGJE/JetFinders/jetFinderMCPCharged.cxx similarity index 96% rename from PWGJE/JetFinders/jetfindermcpcharged.cxx rename to PWGJE/JetFinders/jetFinderMCPCharged.cxx index 41981a193f1..9cba0092a53 100644 --- a/PWGJE/JetFinders/jetfindermcpcharged.cxx +++ b/PWGJE/JetFinders/jetFinderMCPCharged.cxx @@ -13,7 +13,7 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" using JetFinderMCParticleLevelCharged = JetFinderTask; diff --git a/PWGJE/JetFinders/jetfindermcpfull.cxx b/PWGJE/JetFinders/jetFinderMCPFull.cxx similarity index 96% rename from PWGJE/JetFinders/jetfindermcpfull.cxx rename to PWGJE/JetFinders/jetFinderMCPFull.cxx index cd0bda48730..ff9c26e4d91 100644 --- a/PWGJE/JetFinders/jetfindermcpfull.cxx +++ b/PWGJE/JetFinders/jetFinderMCPFull.cxx @@ -13,7 +13,7 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" using JetFinderMCParticleLevelFull = JetFinderTask; diff --git a/PWGJE/JetFinders/jetfindermcpneutral.cxx b/PWGJE/JetFinders/jetFinderMCPNeutral.cxx similarity index 96% rename from PWGJE/JetFinders/jetfindermcpneutral.cxx rename to PWGJE/JetFinders/jetFinderMCPNeutral.cxx index e4f8c00683f..8593fb1f644 100644 --- a/PWGJE/JetFinders/jetfindermcpneutral.cxx +++ b/PWGJE/JetFinders/jetFinderMCPNeutral.cxx @@ -13,7 +13,7 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" using JetFinderMCParticleLevelNeutral = JetFinderTask; diff --git a/PWGJE/JetFinders/jetFinderV0.cxx b/PWGJE/JetFinders/jetFinderV0.cxx new file mode 100644 index 00000000000..60c1f63bef4 --- /dev/null +++ b/PWGJE/JetFinders/jetFinderV0.cxx @@ -0,0 +1,213 @@ +// 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. + +// jet finder V0 task +// +/// \author Nima Zardoshti + +#include + +#include "CommonConstants/PhysicsConstants.h" + +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "Common/Core/RecoDecay.h" + +using namespace o2; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// NB: runDataProcessing.h must be included after customize! +#include "Framework/runDataProcessing.h" + +template +struct JetFinderV0Task { + + Produces jetsTable; + Produces constituentsTable; + + HistogramRegistry registry; + + // event level configurables + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + Configurable centralityMin{"centralityMin", -999.0, "minimum centrality"}; + Configurable centralityMax{"centralityMax", 999.0, "maximum centrality"}; + Configurable trackOccupancyInTimeRangeMax{"trackOccupancyInTimeRangeMax", 999999, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable triggerMasks{"triggerMasks", "", "possible JE Trigger masks: fJetChLowPt,fJetChHighPt,fTrackLowPt,fTrackHighPt,fJetD0ChLowPt,fJetD0ChHighPt,fJetLcChLowPt,fJetLcChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt,fJetNeutralHighPt,fJetNeutralLowPt,fGammaVeryHighPtEMCAL,fGammaVeryHighPtDCAL,fGammaHighPtEMCAL,fGammaHighPtDCAL,fGammaLowPtEMCAL,fGammaLowPtDCAL,fGammaVeryLowPtEMCAL,fGammaVeryLowPtDCAL"}; + Configurable skipMBGapEvents{"skipMBGapEvents", true, "decide to run over MB gap events or not"}; + + // track level configurables + Configurable trackPtMin{"trackPtMin", 0.15, "minimum track pT"}; + Configurable trackPtMax{"trackPtMax", 1000.0, "maximum track pT"}; + Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum track eta"}; + Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track eta"}; + Configurable trackPhiMin{"trackPhiMin", -999, "minimum track phi"}; + Configurable trackPhiMax{"trackPhiMax", 999, "maximum track phi"}; + Configurable trackingEfficiency{"trackingEfficiency", 1.0, "tracking efficiency applied to jet finding"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + Configurable particleSelections{"particleSelections", "PhysicalPrimary", "set particle selections"}; + + // V0 candidate level configurables + Configurable candPtMin{"candPtMin", 0.0, "minimum candidate pT"}; + Configurable candPtMax{"candPtMax", 100.0, "maximum candidate pT"}; + Configurable candYMin{"candYMin", -0.8, "minimum candidate eta"}; + Configurable candYMax{"candYMax", 0.8, "maximum candidate eta"}; + Configurable candPDG{"candPDG", 310, "candidate PDG for mass in clustering"}; + + // jet level configurables + Configurable> jetRadius{"jetRadius", {0.4}, "jet resolution parameters"}; + Configurable jetPtMin{"jetPtMin", 0.0, "minimum jet pT"}; + Configurable jetPtMax{"jetPtMax", 1000.0, "maximum jet pT"}; + Configurable jetEtaMin{"jetEtaMin", -99.0, "minimum jet pseudorapidity"}; + Configurable jetEtaMax{"jetEtaMax", 99.0, "maximum jet pseudorapidity"}; + Configurable jetTypeParticleLevel{"jetTypeParticleLevel", 1, "Type of stored jets. 0 = full, 1 = charged, 2 = neutral"}; + Configurable jetAlgorithm{"jetAlgorithm", 2, "jet clustering algorithm. 0 = kT, 1 = C/A, 2 = Anti-kT"}; + Configurable jetRecombScheme{"jetRecombScheme", 0, "jet recombination scheme. 0 = E-scheme, 1 = pT-scheme, 2 = pT2-scheme"}; + Configurable jetGhostArea{"jetGhostArea", 0.005, "jet ghost area"}; + Configurable ghostRepeat{"ghostRepeat", 1, "set to 0 to gain speed if you dont need area calculation"}; + Configurable DoTriggering{"DoTriggering", false, "used for the charged jet trigger to remove the eta constraint on the jet axis"}; + Configurable jetAreaFractionMin{"jetAreaFractionMin", -99.0, "used to make a cut on the jet areas"}; + Configurable jetPtBinWidth{"jetPtBinWidth", 5, "used to define the width of the jetPt bins for the THnSparse"}; + Configurable fillTHnSparse{"fillTHnSparse", true, "switch to fill the THnSparse"}; + Configurable jetExtraParam{"jetExtraParam", -99.0, "sets the _extra_param in fastjet"}; + + Service pdgDatabase; + int trackSelection = -1; + std::vector eventSelectionBits; + std::string particleSelection; + + JetFinder jetFinder; + std::vector inputParticles; + + std::vector triggerMaskBits; + + int candIndex; + + void init(InitContext const&) + { + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(triggerMasks); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + particleSelection = static_cast(particleSelections); + + jetFinder.etaMin = trackEtaMin; + jetFinder.etaMax = trackEtaMax; + jetFinder.jetPtMin = jetPtMin; + jetFinder.jetPtMax = jetPtMax; + jetFinder.jetEtaMin = jetEtaMin; + jetFinder.jetEtaMax = jetEtaMax; + if (jetEtaMin < -98.0) { + jetFinder.jetEtaDefault = true; + } + jetFinder.algorithm = static_cast(static_cast(jetAlgorithm)); + jetFinder.recombScheme = static_cast(static_cast(jetRecombScheme)); + jetFinder.ghostArea = jetGhostArea; + jetFinder.ghostRepeatN = ghostRepeat; + if (DoTriggering) { + jetFinder.isTriggering = true; + } + jetFinder.fastjetExtraParam = jetExtraParam; + + if (candPDG == 310) { + candIndex = 0; + } + if (candPDG == 3122) { + candIndex = 1; + } + + auto jetRadiiBins = (std::vector)jetRadius; + if (jetRadiiBins.size() > 1) { + jetRadiiBins.push_back(jetRadiiBins[jetRadiiBins.size() - 1] + (TMath::Abs(jetRadiiBins[jetRadiiBins.size() - 1] - jetRadiiBins[jetRadiiBins.size() - 2]))); + } else { + jetRadiiBins.push_back(jetRadiiBins[jetRadiiBins.size() - 1] + 0.1); + } + std::vector jetPtBins; + int jetPtMaxInt = static_cast(jetPtMax); + int jetPtMinInt = static_cast(jetPtMin); + jetPtMinInt = (jetPtMinInt / jetPtBinWidth) * jetPtBinWidth; + jetPtMaxInt = ((jetPtMaxInt + jetPtBinWidth - 1) / jetPtBinWidth) * jetPtBinWidth; + int jetPtBinNumber = (jetPtMaxInt - jetPtMinInt) / jetPtBinWidth; + double jetPtMinDouble = static_cast(jetPtMinInt); + double jetPtMaxDouble = static_cast(jetPtMaxInt); + + registry.add("hJet", "sparse for data or mcd jets", {HistType::kTHnC, {{jetRadiiBins, ""}, {jetPtBinNumber, jetPtMinDouble, jetPtMaxDouble}, {40, -1.0, 1.0}, {18, 0.0, 7.0}}}); + registry.add("hJetMCP", "sparse for mcp jets", {HistType::kTHnC, {{jetRadiiBins, ""}, {jetPtBinNumber, jetPtMinDouble, jetPtMaxDouble}, {40, -1.0, 1.0}, {18, 0.0, 7.0}}}); + } + + Filter collisionFilter = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax && aod::jcollision::trackOccupancyInTimeRange <= trackOccupancyInTimeRangeMax && ((skipMBGapEvents.node() == false) || (aod::jcollision::subGeneratorId != static_cast(jetderiveddatautilities::JCollisionSubGeneratorId::mbGap)))); + Filter mcCollisionFilter = ((skipMBGapEvents.node() == false) || (aod::jmccollision::subGeneratorId != static_cast(jetderiveddatautilities::JCollisionSubGeneratorId::mbGap))); // should we add a posZ vtx cut here or leave it to analysers? + Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta >= trackEtaMin && aod::jtrack::eta <= trackEtaMax && aod::jtrack::phi >= trackPhiMin && aod::jtrack::phi <= trackPhiMax); + Filter partCuts = (aod::jmcparticle::pt >= trackPtMin && aod::jmcparticle::pt < trackPtMax && aod::jmcparticle::eta >= trackEtaMin && aod::jmcparticle::eta <= trackEtaMax && aod::jmcparticle::phi >= trackPhiMin && aod::jmcparticle::phi <= trackPhiMax); + // Filter candidateCuts = (aod::hfcand::pt >= candPtMin && aod::hfcand::pt < candPtMax && aod::hfcand::y >= candYMin && aod::hfcand::y < candYMax); + + // function that generalically processes Data and reco level events + template + void analyseCharged(T const& collision, U const& tracks, V const& candidates, M& jetsTableInput, N& constituentsTableInput, float minJetPt, float maxJetPt) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || !jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + inputParticles.clear(); + if (!jetfindingutilities::analyseV0s(inputParticles, candidates, candPtMin, candPtMax, candYMin, candYMax, candIndex)) { + return; + } + + /* + if constexpr (jethfutilities::isHFMcCandidate()) { + if (!jetfindingutilities::analyseCandidateMC(inputParticles, candidate, candPtMin, candPtMax, candYMin, candYMax, rejectBackgroundMCDCandidates)) { + return; + } + } + */ + jetfindingutilities::analyseTracksMultipleCandidates(inputParticles, tracks, trackSelection, trackingEfficiency, candidates); + + jetfindingutilities::findJets(jetFinder, inputParticles, minJetPt, maxJetPt, jetRadius, jetAreaFractionMin, collision, jetsTableInput, constituentsTableInput, registry.get(HIST("hJet")), fillTHnSparse, true); + } + + template + void analyseMCP(T const& collision, U const& particles, V const& candidates, int jetTypeParticleLevel, float minJetPt, float maxJetPt) + { + + inputParticles.clear(); + if (!jetfindingutilities::analyseV0s(inputParticles, candidates, candPtMin, candPtMax, candYMin, candYMax, candIndex)) { + return; + } + jetfindingutilities::analyseParticles(inputParticles, particleSelection, jetTypeParticleLevel, particles, pdgDatabase, std::optional{candidates}); + jetfindingutilities::findJets(jetFinder, inputParticles, minJetPt, maxJetPt, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable, registry.get(HIST("hJetMCP")), fillTHnSparse, true); + } + + void processDummy(aod::JetCollisions const&) + { + } + PROCESS_SWITCH(JetFinderV0Task, processDummy, "Dummy process function turned on by default", true); + + void processChargedJetsData(soa::Filtered::iterator const& collision, soa::Filtered const& tracks, CandidateTableData const& candidates) + { + analyseCharged(collision, tracks, candidates, jetsTable, constituentsTable, jetPtMin, jetPtMax); + } + PROCESS_SWITCH(JetFinderV0Task, processChargedJetsData, "charged hf jet finding on data", false); + + void processChargedJetsMCD(soa::Filtered::iterator const& collision, soa::Filtered const& tracks, CandidateTableMCD const& candidates) + { + analyseCharged(collision, tracks, candidates, jetsTable, constituentsTable, jetPtMin, jetPtMax); + } + PROCESS_SWITCH(JetFinderV0Task, processChargedJetsMCD, "charged hf jet finding on MC detector level", false); + + void processChargedJetsMCP(soa::Filtered::iterator const& collision, + soa::Filtered const& particles, + CandidateTableMCP const& candidates) + { + analyseMCP(collision, particles, candidates, 1, jetPtMin, jetPtMax); + } + PROCESS_SWITCH(JetFinderV0Task, processChargedJetsMCP, "hf jet finding on MC particle level", false); +}; diff --git a/PWGJE/JetFinders/jetFinderV0DataCharged.cxx b/PWGJE/JetFinders/jetFinderV0DataCharged.cxx new file mode 100644 index 00000000000..7b1ac0a261f --- /dev/null +++ b/PWGJE/JetFinders/jetFinderV0DataCharged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet finder V0 data charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderV0.cxx" + +using JetFinderV0DataCharged = JetFinderV0Task; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsData", true}}}, + TaskName{"jet-finder-v0-data-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderV0MCDCharged.cxx b/PWGJE/JetFinders/jetFinderV0MCDCharged.cxx new file mode 100644 index 00000000000..30442208085 --- /dev/null +++ b/PWGJE/JetFinders/jetFinderV0MCDCharged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet finder V0 mcd charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderV0.cxx" + +using JetFinderV0MCDetectorLevelCharged = JetFinderV0Task; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsMCD", true}}}, + TaskName{"jet-finder-v0-mcd-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderV0MCPCharged.cxx b/PWGJE/JetFinders/jetFinderV0MCPCharged.cxx new file mode 100644 index 00000000000..27de0bdbc3c --- /dev/null +++ b/PWGJE/JetFinders/jetFinderV0MCPCharged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet finder v0 mcp charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderV0.cxx" + +using JetFinderV0MCParticleLevelCharged = JetFinderV0Task; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsMCP", true}}}, + TaskName{"jet-finder-v0-mcp-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetfinder.cxx b/PWGJE/JetFinders/jetfinder.cxx deleted file mode 100644 index c72ee89167d..00000000000 --- a/PWGJE/JetFinders/jetfinder.cxx +++ /dev/null @@ -1,192 +0,0 @@ -// 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. - -// jet finder task -// -/// \author Nima Zardoshti -/// \author Jochen Klein -/// \author Raymond Ehlers , ORNL - -#include "PWGJE/Core/JetFindingUtilities.h" -#include "Framework/runDataProcessing.h" - -using namespace o2; -using namespace o2::analysis; -using namespace o2::framework; -using namespace o2::framework::expressions; - -template -struct JetFinderTask { - Produces jetsTable; - Produces constituentsTable; - Produces jetsEvtWiseSubTable; - Produces constituentsEvtWiseSubTable; - - // event level configurables - Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; - Configurable centralityMin{"centralityMin", -999.0, "minimum centrality"}; - Configurable centralityMax{"centralityMax", 999.0, "maximum centrality"}; - - // track level configurables - Configurable trackPtMin{"trackPtMin", 0.15, "minimum track pT"}; - Configurable trackPtMax{"trackPtMax", 1000.0, "maximum track pT"}; - Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum track eta"}; - Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track eta"}; - Configurable trackPhiMin{"trackPhiMin", -999, "minimum track phi"}; - Configurable trackPhiMax{"trackPhiMax", 999, "maximum track phi"}; - Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; - Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; - Configurable particleSelections{"particleSelections", "PhysicalPrimary", "set particle selections"}; - - // cluster level configurables - Configurable clusterDefinitionS{"clusterDefinition", "kV3Default", "cluster definition to be selected, e.g. V3Default"}; - Configurable clusterEtaMin{"clusterEtaMin", -0.71, "minimum cluster eta"}; // For ECMAL: |eta| < 0.7, phi = 1.40 - 3.26 - Configurable clusterEtaMax{"clusterEtaMax", 0.71, "maximum cluster eta"}; // For ECMAL: |eta| < 0.7, phi = 1.40 - 3.26 - Configurable clusterPhiMin{"clusterPhiMin", 1.39, "minimum cluster phi"}; - Configurable clusterPhiMax{"clusterPhiMax", 3.27, "maximum cluster phi"}; - Configurable clusterEnergyMin{"clusterEnergyMin", 0.5, "minimum cluster energy in EMCAL (GeV)"}; - Configurable clusterTimeMin{"clusterTimeMin", -25., "minimum Cluster time (ns)"}; - Configurable clusterTimeMax{"clusterTimeMax", 25., "maximum Cluster time (ns)"}; - Configurable clusterRejectExotics{"clusterRejectExotics", true, "Reject exotic clusters"}; - - // jet level configurables - Configurable> jetRadius{"jetRadius", {0.4}, "jet resolution parameters"}; - Configurable jetPtMin{"jetPtMin", 0.0, "minimum jet pT"}; - Configurable jetPtMax{"jetPtMax", 1000.0, "maximum jet pT"}; - Configurable jetEWSPtMin{"jetEWSPtMin", 0.0, "minimum event-wise subtracted jet pT"}; - Configurable jetEWSPtMax{"jetEWSPtMax", 1000.0, "maximum event-wise subtracted jet pT"}; - Configurable jetEtaMin{"jetEtaMin", -99.0, "minimum jet pseudorapidity"}; - Configurable jetEtaMax{"jetEtaMax", 99.0, "maximum jet pseudorapidity"}; - Configurable jetAlgorithm{"jetAlgorithm", 2, "jet clustering algorithm. 0 = kT, 1 = C/A, 2 = Anti-kT"}; - Configurable jetRecombScheme{"jetRecombScheme", 0, "jet recombination scheme. 0 = E-scheme, 1 = pT-scheme, 2 = pT2-scheme"}; - Configurable jetGhostArea{"jetGhostArea", 0.005, "jet ghost area"}; - Configurable ghostRepeat{"ghostRepeat", 1, "set to 0 to gain speed if you dont need area calculation"}; - Configurable DoTriggering{"DoTriggering", false, "used for the charged jet trigger to remove the eta constraint on the jet axis"}; - Configurable jetAreaFractionMin{"jetAreaFractionMin", -99.0, "used to make a cut on the jet areas"}; - - Service pdgDatabase; - int trackSelection = -1; - int eventSelection = -1; - std::string particleSelection; - - JetFinder jetFinder; - std::vector inputParticles; - - void init(InitContext const&) - { - trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(eventSelections)); - particleSelection = static_cast(particleSelections); - - jetFinder.etaMin = trackEtaMin; - jetFinder.etaMax = trackEtaMax; - jetFinder.jetEtaMin = jetEtaMin; - jetFinder.jetEtaMax = jetEtaMax; - if (jetEtaMin < -98.0) { - jetFinder.jetEtaDefault = true; - } - jetFinder.algorithm = static_cast(static_cast(jetAlgorithm)); - jetFinder.recombScheme = static_cast(static_cast(jetRecombScheme)); - jetFinder.ghostArea = jetGhostArea; - jetFinder.ghostRepeatN = ghostRepeat; - if (DoTriggering) { - jetFinder.isTriggering = true; - } - } - - aod::EMCALClusterDefinition clusterDefinition = aod::emcalcluster::getClusterDefinitionFromString(clusterDefinitionS.value); - Filter collisionFilter = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax); - Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax && aod::jtrack::phi >= trackPhiMin && aod::jtrack::phi <= trackPhiMax); // do we need eta cut both here and in globalselection? - Filter trackSubCuts = (aod::jtracksub::pt >= trackPtMin && aod::jtracksub::pt < trackPtMax && aod::jtracksub::eta > trackEtaMin && aod::jtracksub::eta < trackEtaMax && aod::jtracksub::phi >= trackPhiMin && aod::jtracksub::phi <= trackPhiMax); - - Filter partCuts = (aod::jmcparticle::pt >= trackPtMin && aod::jmcparticle::pt < trackPtMax && aod::jmcparticle::eta > trackEtaMin && aod::jmcparticle::eta < trackEtaMax); - Filter clusterFilter = (aod::jcluster::definition == static_cast(clusterDefinition) && aod::jcluster::eta > clusterEtaMin && aod::jcluster::eta < clusterEtaMax && aod::jcluster::phi >= clusterPhiMin && aod::jcluster::phi <= clusterPhiMax && aod::jcluster::energy >= clusterEnergyMin && aod::jcluster::time > clusterTimeMin && aod::jcluster::time < clusterTimeMax && (clusterRejectExotics && aod::jcluster::isExotic != true)); - - void processChargedJets(soa::Filtered::iterator const& collision, - soa::Filtered const& tracks) - { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { - return; - } - inputParticles.clear(); - jetfindingutilities::analyseTracks, soa::Filtered::iterator>(inputParticles, tracks, trackSelection); - jetfindingutilities::findJets(jetFinder, inputParticles, jetPtMin, jetPtMax, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable); - } - - PROCESS_SWITCH(JetFinderTask, processChargedJets, "Data and reco level jet finding for charged jets", false); - - void processChargedEvtWiseSubJets(soa::Filtered::iterator const& collision, - soa::Filtered const& tracks) - { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { - return; - } - inputParticles.clear(); - jetfindingutilities::analyseTracks, soa::Filtered::iterator>(inputParticles, tracks, trackSelection); - jetfindingutilities::findJets(jetFinder, inputParticles, jetEWSPtMin, jetEWSPtMax, jetRadius, jetAreaFractionMin, collision, jetsEvtWiseSubTable, constituentsEvtWiseSubTable); - } - - PROCESS_SWITCH(JetFinderTask, processChargedEvtWiseSubJets, "Data and reco level jet finding for charged jets with event-wise constituent subtraction", false); - - void processNeutralJets(soa::Filtered::iterator const& collision, - soa::Filtered const& clusters) - { - if (!jetderiveddatautilities::eventEMCAL(collision)) { - return; - } - inputParticles.clear(); - jetfindingutilities::analyseClusters(inputParticles, &clusters); - jetfindingutilities::findJets(jetFinder, inputParticles, jetPtMin, jetPtMax, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable); - } - PROCESS_SWITCH(JetFinderTask, processNeutralJets, "Data and reco level jet finding for neutral jets", false); - - void processFullJets(soa::Filtered::iterator const& collision, - soa::Filtered const& tracks, - soa::Filtered const& clusters) - { - if (!jetderiveddatautilities::eventEMCAL(collision)) { - return; - } - inputParticles.clear(); - jetfindingutilities::analyseTracks, soa::Filtered::iterator>(inputParticles, tracks, trackSelection); - jetfindingutilities::analyseClusters(inputParticles, &clusters); - jetfindingutilities::findJets(jetFinder, inputParticles, jetPtMin, jetPtMax, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable); - } - PROCESS_SWITCH(JetFinderTask, processFullJets, "Data and reco level jet finding for full and neutral jets", false); - - void processParticleLevelChargedJets(JetMcCollision const& collision, soa::Filtered const& particles) - { - // TODO: MC event selection? - inputParticles.clear(); - jetfindingutilities::analyseParticles, soa::Filtered::iterator>(inputParticles, particleSelection, 1, particles, pdgDatabase); - jetfindingutilities::findJets(jetFinder, inputParticles, jetPtMin, jetPtMax, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable); - } - PROCESS_SWITCH(JetFinderTask, processParticleLevelChargedJets, "Particle level charged jet finding", false); - - void processParticleLevelNeutralJets(JetMcCollision const& collision, soa::Filtered const& particles) - { - // TODO: MC event selection? - inputParticles.clear(); - jetfindingutilities::analyseParticles, soa::Filtered::iterator>(inputParticles, particleSelection, 2, particles, pdgDatabase); - jetfindingutilities::findJets(jetFinder, inputParticles, jetPtMin, jetPtMax, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable); - } - PROCESS_SWITCH(JetFinderTask, processParticleLevelNeutralJets, "Particle level neutral jet finding", false); - - void processParticleLevelFullJets(JetMcCollision const& collision, soa::Filtered const& particles) - { - // TODO: MC event selection? - inputParticles.clear(); - jetfindingutilities::analyseParticles, soa::Filtered::iterator>(inputParticles, particleSelection, 0, particles, pdgDatabase); - jetfindingutilities::findJets(jetFinder, inputParticles, jetPtMin, jetPtMax, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable); - } - - PROCESS_SWITCH(JetFinderTask, processParticleLevelFullJets, "Particle level full jet finding", false); -}; diff --git a/PWGJE/TableProducer/CMakeLists.txt b/PWGJE/TableProducer/CMakeLists.txt index 378ea7b1a01..2a82a7f0466 100644 --- a/PWGJE/TableProducer/CMakeLists.txt +++ b/PWGJE/TableProducer/CMakeLists.txt @@ -9,74 +9,65 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +add_subdirectory(Matching) if(FastJet_FOUND) o2physics_add_dpl_workflow(jet-deriveddata-producer - SOURCES jetderiveddataproducer.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + SOURCES derivedDataProducer.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2Physics::EventFilteringUtils O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-deriveddata-trigger-producer - SOURCES jetderiveddatatriggerproducer.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(jet-deriveddata-producer-dummy - SOURCES jetderiveddataproducerdummy.cxx + SOURCES derivedDataTriggerProducer.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(jet-deriveddata-producer-dummy-d0 - SOURCES jetderiveddataproducerdummyd0.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(jet-deriveddata-producer-dummy-lc - SOURCES jetderiveddataproducerdummylc.cxx +o2physics_add_dpl_workflow(jet-deriveddata-selector + SOURCES derivedDataSelector.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-deriveddata-writer - SOURCES jetderiveddatawriter.cxx + SOURCES derivedDataWriter.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(jet-matching-mc - SOURCES jetmatchingmc.cxx +o2physics_add_dpl_workflow(jet-luminosity-producer + SOURCES luminosityProducer.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(jet-matching-sub - SOURCES jetmatchingsub.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(jet-matching-mc-sub - SOURCES jetmatchingmcsub.cxx +o2physics_add_dpl_workflow(jet-luminosity-calculator + SOURCES luminosityCalculator.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-eventweight-mcd - SOURCES jeteventweightmcd.cxx + SOURCES jetEventWeightMCD.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-eventweight-mcp - SOURCES jeteventweightmcp.cxx + SOURCES jetEventWeightMCP.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-track-derived - SOURCES jettrackderived.cxx + SOURCES jetTrackDerived.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(jet-taggerhf - SOURCES jettaggerhf.cxx +o2physics_add_dpl_workflow(jet-hf-definition + SOURCES heavyFlavourDefinition.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(jet-taggerhf + SOURCES jetTaggerHF.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2Physics::MLCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(estimator-rho SOURCES rhoEstimator.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore @@ -86,6 +77,12 @@ o2physics_add_dpl_workflow(subtractor-eventwiseconstituent SOURCES eventwiseConstituentSubtractor.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-sv-reconstruction + SOURCES secondaryVertexReconstruction.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + endif() @@ -98,3 +95,8 @@ o2physics_add_dpl_workflow(emcal-matchedtracks-writer SOURCES emcalMatchedTracksTask.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2::EMCALBase O2::EMCALReconstruction COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(emcal-cluster-hadronic-correction-task + SOURCES emcalClusterHadronicCorrectionTask.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2::EMCALBase O2::EMCALReconstruction + COMPONENT_NAME Analysis) diff --git a/PWGJE/TableProducer/Matching/CMakeLists.txt b/PWGJE/TableProducer/Matching/CMakeLists.txt new file mode 100644 index 00000000000..beab5a4fdd6 --- /dev/null +++ b/PWGJE/TableProducer/Matching/CMakeLists.txt @@ -0,0 +1,122 @@ +# 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. + +add_subdirectory(Duplicates) +add_subdirectory(Substructure) + +if(FastJet_FOUND) + +o2physics_add_dpl_workflow(jet-matching-mc-ch + SOURCES jetMatchingMCCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mc-full + SOURCES jetMatchingMCFull.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mc-neutral + SOURCES jetMatchingMCNeutral.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mc-d0-ch + SOURCES jetMatchingMCD0Charged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mc-dplus-ch + SOURCES jetMatchingMCDplusCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mc-lc-ch + SOURCES jetMatchingMCLcCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mc-bplus-ch + SOURCES jetMatchingMCBplusCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mc-dielectron-ch + SOURCES jetMatchingMCDielectronCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mc-v0-ch + SOURCES jetMatchingMCV0Charged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mc-sub-ch + SOURCES jetMatchingMCSubCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mc-sub-d0-ch + SOURCES jetMatchingMCSubD0Charged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mc-sub-dplus-ch + SOURCES jetMatchingMCSubDplusCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mc-sub-lc-ch + SOURCES jetMatchingMCSubLcCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mc-sub-bplus-ch + SOURCES jetMatchingMCSubBplusCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mc-sub-dielectron-ch + SOURCES jetMatchingMCSubDielectronCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-sub-ch + SOURCES jetMatchingSubCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-sub-d0-ch + SOURCES jetMatchingSubD0Charged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-sub-dplus-ch + SOURCES jetMatchingSubDplusCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-sub-lc-ch + SOURCES jetMatchingSubLcCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-sub-bplus-ch + SOURCES jetMatchingSubBplusCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-sub-dielectron-ch + SOURCES jetMatchingSubDielectronCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +endif() diff --git a/PWGJE/TableProducer/Matching/Duplicates/CMakeLists.txt b/PWGJE/TableProducer/Matching/Duplicates/CMakeLists.txt new file mode 100644 index 00000000000..52a7a0377c9 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Duplicates/CMakeLists.txt @@ -0,0 +1,29 @@ +# 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. + +if(FastJet_FOUND) + +o2physics_add_dpl_workflow(jet-matching-data-ch-1 + SOURCES jetMatchingDuplicatesChargedData1.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mcd-ch-1 + SOURCES jetMatchingDuplicatesChargedMCD1.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mcp-ch-1 + SOURCES jetMatchingDuplicatesChargedMCP1.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +endif() diff --git a/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicates.cxx b/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicates.cxx new file mode 100644 index 00000000000..1155c169f55 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicates.cxx @@ -0,0 +1,90 @@ +// 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 jetmatching.cxx +/// \brief matching duplicate jets +/// \author Nima Zardoshti + +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/runDataProcessing.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/Core/JetMatchingUtilities.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +template +struct JetMatchingDuplicates { + + Configurable doMatchingGeo{"doMatchingGeo", true, "Enable geometric matching"}; + Configurable doMatchingPt{"doMatchingPt", true, "Enable pt matching"}; + Configurable doMatchingHf{"doMatchingHf", false, "Enable HF matching"}; + Configurable maxMatchingDistance{"maxMatchingDistance", 0.24f, "Max matching distance"}; + Configurable minPtFraction{"minPtFraction", 0.5f, "Minimum pt fraction for pt matching"}; + + Produces jetsBasetoTagMatchingTable; + Produces jetsTagtoBaseMatchingTable; + + // preslicing jet collections, only for Mc-based collection + static constexpr bool jetsBaseIsMc = o2::soa::relatedByIndex(); + static constexpr bool jetsTagIsMc = o2::soa::relatedByIndex(); + + Preslice baseJetsPerCollision = jetsBaseIsMc ? aod::jet::mcCollisionId : aod::jet::collisionId; + Preslice tagJetsPerCollision = jetsTagIsMc ? aod::jet::mcCollisionId : aod::jet::collisionId; + + void init(InitContext const&) + { + } + + void processJets(aod::JetCollisions const& collisions, + JetsBase const& jetsBase, JetsTag const& jetsTag, + Tracks const& tracks, Candidates const& candidates) + { + + // initialise objects used to store the matching index arrays (array in case a mcCollision is split) before filling the matching tables + std::vector> jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF; + std::vector> jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF; + // waiting for framework fix to make sliced collection of same type as original collection: + jetsBasetoTagMatchingGeo.assign(jetsBase.size(), {}); + jetsBasetoTagMatchingPt.assign(jetsBase.size(), {}); + jetsBasetoTagMatchingHF.assign(jetsBase.size(), {}); + jetsTagtoBaseMatchingGeo.assign(jetsTag.size(), {}); + jetsTagtoBaseMatchingPt.assign(jetsTag.size(), {}); + jetsTagtoBaseMatchingHF.assign(jetsTag.size(), {}); + + for (const auto& collision : collisions) { + + const auto jetsBasePerColl = jetsBase.sliceBy(baseJetsPerCollision, collision.globalIndex()); + const auto jetsTagPerColl = jetsTag.sliceBy(tagJetsPerCollision, collision.globalIndex()); + // initialise template parameters as false since even if they are Mc we are not matching between detector and particle level + jetmatchingutilities::doAllMatching(jetsBasePerColl, jetsTagPerColl, jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF, jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF, candidates, tracks, tracks, candidates, tracks, tracks, doMatchingGeo, doMatchingHf, doMatchingPt, maxMatchingDistance, minPtFraction); + } + + for (auto i = 0; i < jetsBase.size(); ++i) { + jetsBasetoTagMatchingTable(jetsBasetoTagMatchingGeo[i], jetsBasetoTagMatchingPt[i], jetsBasetoTagMatchingHF[i]); // is (and needs to) be filled in order + } + for (auto i = 0; i < jetsTag.size(); i++) { + jetsTagtoBaseMatchingTable(jetsTagtoBaseMatchingGeo[i], jetsTagtoBaseMatchingPt[i], jetsTagtoBaseMatchingHF[i]); // is (and needs to) be filled in order + } + } + PROCESS_SWITCH(JetMatchingDuplicates, processJets, "Perform jet matching", true); +}; diff --git a/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicatesChargedData1.cxx b/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicatesChargedData1.cxx new file mode 100644 index 00000000000..8115c95bf04 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicatesChargedData1.cxx @@ -0,0 +1,30 @@ +// 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. + +// jet matching duplicates charged data task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicates.cxx" + +using Charged1JetDataMatchingDupliacates = JetMatchingDuplicates, + soa::Join, + aod::ChargedJetsMatchedToCharged1Jets, + aod::Charged1JetsMatchedToChargedJets, + aod::JTracks, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-matching-data-ch-1"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicatesChargedMCD1.cxx b/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicatesChargedMCD1.cxx new file mode 100644 index 00000000000..96033d17d4e --- /dev/null +++ b/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicatesChargedMCD1.cxx @@ -0,0 +1,30 @@ +// 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. + +// jet matching duplicates charged mcd task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicates.cxx" + +using Charged1JetMCDMatchingDupliacates = JetMatchingDuplicates, + soa::Join, + aod::ChargedMCDetectorLevelJetsMatchedToCharged1MCDetectorLevelJets, + aod::Charged1MCDetectorLevelJetsMatchedToChargedMCDetectorLevelJets, + aod::JTracks, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-matching-mcd-ch-1"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicatesChargedMCP1.cxx b/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicatesChargedMCP1.cxx new file mode 100644 index 00000000000..11b39822bcb --- /dev/null +++ b/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicatesChargedMCP1.cxx @@ -0,0 +1,30 @@ +// 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. + +// jet matching duplicates charged mcp task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicates.cxx" + +using Charged1JetMCPMatchingDupliacates = JetMatchingDuplicates, + soa::Join, + aod::ChargedMCParticleLevelJetsMatchedToCharged1MCParticleLevelJets, + aod::Charged1MCParticleLevelJetsMatchedToChargedMCParticleLevelJets, + aod::JMcParticles, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-matching-mcp-ch-1"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Substructure/CMakeLists.txt b/PWGJE/TableProducer/Matching/Substructure/CMakeLists.txt new file mode 100644 index 00000000000..c507c8995ef --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/CMakeLists.txt @@ -0,0 +1,75 @@ +# 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. + + +if(FastJet_FOUND) + +o2physics_add_dpl_workflow(jet-substructure-matching-mc-ch + SOURCES jetSubstructureMatchingMCCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-substructure-matching-mc-d0-ch + SOURCES jetSubstructureMatchingMCD0Charged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-substructure-matching-mc-dplus-ch + SOURCES jetSubstructureMatchingMCDplusCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-substructure-matching-mc-lc-ch + SOURCES jetSubstructureMatchingMCLcCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-substructure-matching-mc-bplus-ch + SOURCES jetSubstructureMatchingMCBplusCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-substructure-matching-mc-dielectron-ch + SOURCES jetSubstructureMatchingMCDielectronCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-substructure-matching-sub-ch + SOURCES jetSubstructureMatchingSubCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-substructure-matching-sub-d0-ch + SOURCES jetSubstructureMatchingSubD0Charged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-substructure-matching-sub-dplus-ch + SOURCES jetSubstructureMatchingSubDplusCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-substructure-matching-sub-lc-ch + SOURCES jetSubstructureMatchingSubLcCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-substructure-matching-sub-bplus-ch + SOURCES jetSubstructureMatchingSubBplusCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-substructure-matching-sub-dielectron-ch + SOURCES jetSubstructureMatchingSubDielectronCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +endif() diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx new file mode 100644 index 00000000000..6d72dbf880f --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx @@ -0,0 +1,278 @@ +// 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. + +// jet analysis tasks (subscribing to jet finder task) +// +/// \author Nima Zardoshti +// + +#include + +#include "fastjet/PseudoJet.hh" +#include "fastjet/ClusterSequenceArea.hh" + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/Core/JetSubstructureUtilities.h" +#include "PWGJE/Core/JetMatchingUtilities.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +#include "Framework/runDataProcessing.h" + +template +struct JetSubstructureMatching { + + Produces splittingsBasetoTagMatchingTable; + Produces splittingsTagtoBaseMatchingTable; + + Produces pairsBasetoTagMatchingTable; + Produces pairsTagtoBaseMatchingTable; + + Configurable doMatchingGeo{"doMatchingGeo", true, "Enable geometric matching"}; + Configurable doMatchingPt{"doMatchingPt", true, "Enable pt matching"}; + Configurable doMatchingHf{"doMatchingHf", false, "Enable HF matching"}; + Configurable maxMatchingDistance{"maxMatchingDistance", 0.24f, "Max matching distance"}; + Configurable minPtFraction{"minPtFraction", 0.5f, "Minimum pt fraction for pt matching"}; + Configurable requireGeoMatchedJets{"requireGeoMatchedJets", false, "require jets are geo matched as well"}; + Configurable requirePtMatchedJets{"requirePtMatchedJets", false, "require jets are pT matched as well"}; + Configurable requireHFMatchedJets{"requireHFMatchedJets", false, "require jets are HF matched as well"}; + + static constexpr bool jetsBaseIsMc = o2::soa::relatedByIndex(); + static constexpr bool jetsTagIsMc = o2::soa::relatedByIndex(); + + void init(InitContext const&) + { + } + + PresliceOptional BaseSplittingsPerBaseJetInclusive = aod::chargedmcdetectorlevelsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetInclusive = aod::chargedmcparticlelevelsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetD0 = aod::d0chargedmcdetectorlevelsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetD0 = aod::d0chargedmcparticlelevelsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetDplus = aod::dpluschargedmcdetectorlevelsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetDplus = aod::dpluschargedmcparticlelevelsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetLc = aod::lcchargedmcdetectorlevelsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetLc = aod::lcchargedmcparticlelevelsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetBplus = aod::bpluschargedmcdetectorlevelsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetBplus = aod::bpluschargedmcparticlelevelsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetDielectron = aod::dielectronchargedmcdetectorlevelsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetDielectron = aod::dielectronchargedmcparticlelevelsplitting::jetId; + + PresliceOptional BasePairsPerBaseJetInclusive = aod::chargedmcdetectorlevelpair::jetId; + PresliceOptional TagPairsPerTagJetInclusive = aod::chargedmcparticlelevelpair::jetId; + PresliceOptional BasePairsPerBaseJetD0 = aod::d0chargedmcdetectorlevelpair::jetId; + PresliceOptional TagPairsPerTagJetD0 = aod::d0chargedmcparticlelevelpair::jetId; + PresliceOptional BasePairsPerBaseJetDplus = aod::dpluschargedmcdetectorlevelpair::jetId; + PresliceOptional TagPairsPerTagJetDplus = aod::dpluschargedmcparticlelevelpair::jetId; + PresliceOptional BasePairsPerBaseJetLc = aod::lcchargedmcdetectorlevelpair::jetId; + PresliceOptional TagPairsPerTagJetLc = aod::lcchargedmcparticlelevelpair::jetId; + PresliceOptional BasePairsPerBaseJetBplus = aod::bpluschargedmcdetectorlevelpair::jetId; + PresliceOptional TagPairsPerTagJetBplus = aod::bpluschargedmcparticlelevelpair::jetId; + PresliceOptional BasePairsPerBaseJetDielectron = aod::dielectronchargedmcdetectorlevelpair::jetId; + PresliceOptional TagPairsPerTagJetDielectron = aod::dielectronchargedmcparticlelevelpair::jetId; + + // workaround till binding nodes can be passed as template arguments + template + auto slicedPerJetForMatching(T const& table, U const& jet, V const& perIncluisveJet, M const& perD0Jet, N const& perDplusJet, O const& perLcJet, P const& perBplusJet, Q const& perDielectronJet) + { + if constexpr (jethfutilities::isHFTable() || jethfutilities::isHFMcTable()) { + return jethfutilities::slicedPerHFJet(table, jet, perD0Jet, perDplusJet, perLcJet, perBplusJet); + } else if constexpr (jetdqutilities::isDielectronTable() || jetdqutilities::isDielectronMcTable()) { + return jetdqutilities::slicedPerDielectronJet(table, jet, perDielectronJet); + } else { + return table.sliceBy(perIncluisveJet, jet.globalIndex()); + } + } + + template + auto defaultMatchedJets(T const& jetTag) + { + if constexpr (jetcandidateutilities::isCandidateTable()) { + return jetTag.template matchedJetCand_as(); + } else { + return jetTag.template matchedJetGeo_as(); + } + } + + void processData(JetsTag const& jetsTag, + JetsBase const&, + SplittingsBase const& jetsBaseSplittings, + SplittingsTag const& jetsTagSplittings, + PairsBase const& jetsBasePairs, + PairsTag const& jetsTagPairs, + CandidatesBase const& candidatesBase, + CandidatesTag const& candidatesTag, + ClustersBase const& clustersBase, + TracksBase const& tracksBase, TracksTag const& tracksTag) + { + std::vector> jetsBasetoTagSplittingsMatchingGeo, jetsBasetoTagSplittingsMatchingPt, jetsBasetoTagSplittingsMatchingHF; + jetsBasetoTagSplittingsMatchingGeo.assign(jetsBaseSplittings.size(), {}); + jetsBasetoTagSplittingsMatchingPt.assign(jetsBaseSplittings.size(), {}); + jetsBasetoTagSplittingsMatchingHF.assign(jetsBaseSplittings.size(), {}); + + std::vector> jetsTagtoBaseSplittingsMatchingGeo, jetsTagtoBaseSplittingsMatchingPt, jetsTagtoBaseSplittingsMatchingHF; + jetsTagtoBaseSplittingsMatchingGeo.assign(jetsTagSplittings.size(), {}); + jetsTagtoBaseSplittingsMatchingPt.assign(jetsTagSplittings.size(), {}); + jetsTagtoBaseSplittingsMatchingHF.assign(jetsTagSplittings.size(), {}); + + std::vector jetTagSplittingsMap; + std::vector jetBaseSplittingsMap; + jetTagSplittingsMap.resize(jetsTagSplittings.size(), -1); + jetBaseSplittingsMap.resize(jetsBaseSplittings.size(), -1); + + std::vector> jetsBasetoTagPairsMatching; + std::vector> jetsTagtoBasePairsMatching; + jetsBasetoTagPairsMatching.assign(jetsBasePairs.size(), {}); + jetsTagtoBasePairsMatching.assign(jetsTagPairs.size(), {}); + + std::vector jetTagPairsMap; + std::vector jetBasePairsMap; + jetTagPairsMap.resize(jetsTagPairs.size(), -1); + jetBasePairsMap.resize(jetsBasePairs.size(), -1); + + for (auto jetTag : jetsTag) { + bool hasMatchedJet = false; + if constexpr (jetcandidateutilities::isCandidateTable()) { + hasMatchedJet = jetTag.has_matchedJetCand(); + } else { + hasMatchedJet = jetTag.has_matchedJetGeo(); + } + if (hasMatchedJet) { + // auto const& jetTagSplittings = jetsTagSplittings.sliceBy(TagSplittingsPerTagJet, jetTag.globalIndex()); + auto const& jetTagSplittings = slicedPerJetForMatching(jetsTagSplittings, jetTag, TagSplittingsPerTagJetInclusive, TagSplittingsPerTagJetD0, TagSplittingsPerTagJetDplus, TagSplittingsPerTagJetLc, TagSplittingsPerTagJetBplus, TagSplittingsPerTagJetDielectron); + int tagSplittingIndex = 0; + for (auto const& jetTagSplitting : jetTagSplittings) { + jetTagSplittingsMap[jetTagSplitting.globalIndex()] = tagSplittingIndex; + tagSplittingIndex++; + } + // auto const& jetTagPairs = jetsTagPairs.sliceBy(TagPairsPerTagJet, jetTag.globalIndex()); + auto const& jetTagPairs = slicedPerJetForMatching(jetsTagPairs, jetTag, TagPairsPerTagJetInclusive, TagPairsPerTagJetD0, TagPairsPerTagJetDplus, TagPairsPerTagJetLc, TagPairsPerTagJetBplus, TagPairsPerTagJetDielectron); + int tagPairIndex = 0; + for (auto const& jetTagPair : jetTagPairs) { + jetTagPairsMap[jetTagPair.globalIndex()] = tagPairIndex; + tagPairIndex++; + } + for (auto& jetBase : defaultMatchedJets(jetTag)) { + if (requireGeoMatchedJets) { + bool jetsMatchedWithGeo = false; + for (auto& jetBaseForMatchGeo : jetTag.template matchedJetGeo_as()) { + if (jetBaseForMatchGeo.globalIndex() == jetBase.globalIndex()) { + jetsMatchedWithGeo = true; + } + } + if (!jetsMatchedWithGeo) { + continue; + } + } + if (requirePtMatchedJets) { + bool jetsMatchedWithPt = false; + for (auto& jetBaseForMatchPt : jetTag.template matchedJetPt_as()) { + if (jetBaseForMatchPt.globalIndex() == jetBase.globalIndex()) { + jetsMatchedWithPt = true; + } + } + if (!jetsMatchedWithPt) { + continue; + } + } + if (requireHFMatchedJets) { + bool jetsMatchedWithHF = false; + for (auto& jetBaseForMatchHF : jetTag.template matchedJetCand_as()) { + if (jetBaseForMatchHF.globalIndex() == jetBase.globalIndex()) { + jetsMatchedWithHF = true; + } + } + if (!jetsMatchedWithHF) { + continue; + } + } + // auto const& jetBaseSplittings = jetsBaseSplittings.sliceBy(BaseSplittingsPerBaseJet, jetBase.globalIndex()); + auto const& jetBaseSplittings = slicedPerJetForMatching(jetsBaseSplittings, jetBase, BaseSplittingsPerBaseJetInclusive, BaseSplittingsPerBaseJetD0, BaseSplittingsPerBaseJetDplus, BaseSplittingsPerBaseJetLc, BaseSplittingsPerBaseJetBplus, BaseSplittingsPerBaseJetDielectron); + int baseSplittingIndex = 0; + for (auto const& jetBaseSplitting : jetBaseSplittings) { + jetBaseSplittingsMap[jetBaseSplitting.globalIndex()] = baseSplittingIndex; + baseSplittingIndex++; + } + jetmatchingutilities::doAllMatching(jetBaseSplittings, jetTagSplittings, jetsBasetoTagSplittingsMatchingGeo, jetsBasetoTagSplittingsMatchingPt, jetsBasetoTagSplittingsMatchingHF, jetsTagtoBaseSplittingsMatchingGeo, jetsTagtoBaseSplittingsMatchingPt, jetsTagtoBaseSplittingsMatchingHF, candidatesBase, tracksBase, clustersBase, candidatesTag, tracksTag, tracksTag, doMatchingGeo, doMatchingHf, doMatchingPt, maxMatchingDistance, minPtFraction); + // auto const& jetBasePairs = jetsBasePairs.sliceBy(BasePairsPerBaseJet, jetBase.globalIndex()); + auto const& jetBasePairs = slicedPerJetForMatching(jetsBasePairs, jetBase, BasePairsPerBaseJetInclusive, BasePairsPerBaseJetD0, BasePairsPerBaseJetDplus, BasePairsPerBaseJetLc, BasePairsPerBaseJetBplus, BasePairsPerBaseJetDielectron); + int basePairIndex = 0; + for (auto const& jetBasePair : jetBasePairs) { + jetBasePairsMap[jetBasePair.globalIndex()] = basePairIndex; + basePairIndex++; + } + jetmatchingutilities::doPairMatching(jetBasePairs, jetTagPairs, jetsBasetoTagPairsMatching, jetsTagtoBasePairsMatching, candidatesBase, tracksBase, candidatesTag, tracksTag); + } + } + } + for (auto jetsTagSplitting : jetsTagSplittings) { + std::vector tagToBaseMatchingGeoIndex; + std::vector tagToBaseMatchingPtIndex; + std::vector tagToBaseMatchingHFIndex; + for (auto jetBaseSplittingIndex : jetsTagtoBaseSplittingsMatchingGeo[jetsTagSplitting.globalIndex()]) { + tagToBaseMatchingGeoIndex.push_back(jetBaseSplittingsMap[jetBaseSplittingIndex]); + } + for (auto jetBaseSplittingIndex : jetsTagtoBaseSplittingsMatchingPt[jetsTagSplitting.globalIndex()]) { + tagToBaseMatchingPtIndex.push_back(jetBaseSplittingsMap[jetBaseSplittingIndex]); + } + for (auto jetBaseSplittingIndex : jetsTagtoBaseSplittingsMatchingHF[jetsTagSplitting.globalIndex()]) { + tagToBaseMatchingHFIndex.push_back(jetBaseSplittingsMap[jetBaseSplittingIndex]); + } + splittingsTagtoBaseMatchingTable(tagToBaseMatchingGeoIndex, tagToBaseMatchingPtIndex, tagToBaseMatchingHFIndex); + } + for (auto jetsBaseSplitting : jetsBaseSplittings) { + std::vector baseToTagMatchingGeoIndex; + std::vector baseToTagMatchingPtIndex; + std::vector baseToTagMatchingHFIndex; + for (auto jetTagSplittingIndex : jetsBasetoTagSplittingsMatchingGeo[jetsBaseSplitting.globalIndex()]) { + baseToTagMatchingGeoIndex.push_back(jetTagSplittingsMap[jetTagSplittingIndex]); + } + for (auto jetTagSplittingIndex : jetsBasetoTagSplittingsMatchingPt[jetsBaseSplitting.globalIndex()]) { + baseToTagMatchingPtIndex.push_back(jetTagSplittingsMap[jetTagSplittingIndex]); + } + for (auto jetTagSplittingIndex : jetsBasetoTagSplittingsMatchingHF[jetsBaseSplitting.globalIndex()]) { + baseToTagMatchingHFIndex.push_back(jetTagSplittingsMap[jetTagSplittingIndex]); + } + splittingsBasetoTagMatchingTable(baseToTagMatchingGeoIndex, baseToTagMatchingPtIndex, baseToTagMatchingHFIndex); + } + for (auto jetsTagPair : jetsTagPairs) { + std::vector tagToBaseMatchingIndex; + for (auto jetBasePairIndex : jetsTagtoBasePairsMatching[jetsTagPair.globalIndex()]) { + tagToBaseMatchingIndex.push_back(jetBasePairsMap[jetBasePairIndex]); + } + pairsTagtoBaseMatchingTable(tagToBaseMatchingIndex); + } + for (auto jetsBasePair : jetsBasePairs) { + std::vector baseToTagMatchingIndex; + for (auto jetTagPairIndex : jetsBasetoTagPairsMatching[jetsBasePair.globalIndex()]) { + baseToTagMatchingIndex.push_back(jetTagPairsMap[jetTagPairIndex]); + } + pairsBasetoTagMatchingTable(baseToTagMatchingIndex); + } + } + PROCESS_SWITCH(JetSubstructureMatching, processData, "charged jet substructure", true); +}; diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCBplusCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCBplusCharged.cxx new file mode 100644 index 00000000000..06e1fe45729 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCBplusCharged.cxx @@ -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. + +// Bplus substructure matching mc charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx" + +using BplusChargedJetSubstructureMatchingMC = JetSubstructureMatching, + soa::Join, + aod::BplusChargedMCDetectorLevelSPsMatchedToBplusChargedMCParticleLevelSPs, + aod::BplusChargedMCParticleLevelSPsMatchedToBplusChargedMCDetectorLevelSPs, + aod::BplusChargedMCDetectorLevelPRsMatchedToBplusChargedMCParticleLevelPRs, + aod::BplusChargedMCParticleLevelPRsMatchedToBplusChargedMCDetectorLevelPRs, + aod::BplusChargedMCDetectorLevelSPs, + aod::BplusChargedMCParticleLevelSPs, + aod::BplusChargedMCDetectorLevelPRs, + aod::BplusChargedMCParticleLevelPRs, + aod::CandidatesBplusMCD, + aod::CandidatesBplusMCP, + aod::JetTracksMCD, + aod::JetParticles, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-mc-bplus-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCCharged.cxx new file mode 100644 index 00000000000..42df0f0bb10 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCCharged.cxx @@ -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. + +// substructure matching mc charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx" + +using ChargedJetSubstructureMatchingMC = JetSubstructureMatching, + soa::Join, + aod::ChargedMCDetectorLevelSPsMatchedToChargedMCParticleLevelSPs, + aod::ChargedMCParticleLevelSPsMatchedToChargedMCDetectorLevelSPs, + aod::ChargedMCDetectorLevelPRsMatchedToChargedMCParticleLevelPRs, + aod::ChargedMCParticleLevelPRsMatchedToChargedMCDetectorLevelPRs, + aod::ChargedMCDetectorLevelSPs, + aod::ChargedMCParticleLevelSPs, + aod::ChargedMCDetectorLevelPRs, + aod::ChargedMCParticleLevelPRs, + aod::JCollisions, + aod::JMcCollisions, + aod::JetTracksMCD, + aod::JetParticles, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-mc-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCD0Charged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCD0Charged.cxx new file mode 100644 index 00000000000..1781ed34392 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCD0Charged.cxx @@ -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. + +// D0 substructure matching mc charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx" + +using D0ChargedJetSubstructureMatchingMC = JetSubstructureMatching, + soa::Join, + aod::D0ChargedMCDetectorLevelSPsMatchedToD0ChargedMCParticleLevelSPs, + aod::D0ChargedMCParticleLevelSPsMatchedToD0ChargedMCDetectorLevelSPs, + aod::D0ChargedMCDetectorLevelPRsMatchedToD0ChargedMCParticleLevelPRs, + aod::D0ChargedMCParticleLevelPRsMatchedToD0ChargedMCDetectorLevelPRs, + aod::D0ChargedMCDetectorLevelSPs, + aod::D0ChargedMCParticleLevelSPs, + aod::D0ChargedMCDetectorLevelPRs, + aod::D0ChargedMCParticleLevelPRs, + aod::CandidatesD0MCD, + aod::CandidatesD0MCP, + aod::JetTracksMCD, + aod::JetParticles, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-mc-d0-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCDielectronCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCDielectronCharged.cxx new file mode 100644 index 00000000000..f063d263478 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCDielectronCharged.cxx @@ -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. + +// Dielectron substructure matching mc charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx" + +using DielectronChargedJetSubstructureMatchingMC = JetSubstructureMatching, + soa::Join, + aod::DielectronChargedMCDetectorLevelSPsMatchedToDielectronChargedMCParticleLevelSPs, + aod::DielectronChargedMCParticleLevelSPsMatchedToDielectronChargedMCDetectorLevelSPs, + aod::DielectronChargedMCDetectorLevelPRsMatchedToDielectronChargedMCParticleLevelPRs, + aod::DielectronChargedMCParticleLevelPRsMatchedToDielectronChargedMCDetectorLevelPRs, + aod::DielectronChargedMCDetectorLevelSPs, + aod::DielectronChargedMCParticleLevelSPs, + aod::DielectronChargedMCDetectorLevelPRs, + aod::DielectronChargedMCParticleLevelPRs, + aod::CandidatesDielectronMCD, + aod::CandidatesDielectronMCP, + aod::JetTracksMCD, + aod::JetParticles, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-mc-dielectron-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCDplusCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCDplusCharged.cxx new file mode 100644 index 00000000000..34f4f145f13 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCDplusCharged.cxx @@ -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. + +// Dplus substructure matching mc charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx" + +using DplusChargedJetSubstructureMatchingMC = JetSubstructureMatching, + soa::Join, + aod::DplusChargedMCDetectorLevelSPsMatchedToDplusChargedMCParticleLevelSPs, + aod::DplusChargedMCParticleLevelSPsMatchedToDplusChargedMCDetectorLevelSPs, + aod::DplusChargedMCDetectorLevelPRsMatchedToDplusChargedMCParticleLevelPRs, + aod::DplusChargedMCParticleLevelPRsMatchedToDplusChargedMCDetectorLevelPRs, + aod::DplusChargedMCDetectorLevelSPs, + aod::DplusChargedMCParticleLevelSPs, + aod::DplusChargedMCDetectorLevelPRs, + aod::DplusChargedMCParticleLevelPRs, + aod::CandidatesDplusMCD, + aod::CandidatesDplusMCP, + aod::JetTracksMCD, + aod::JetParticles, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-mc-dplus-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCLcCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCLcCharged.cxx new file mode 100644 index 00000000000..b5b5bb302a5 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCLcCharged.cxx @@ -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. + +// Lc substructure matching mc charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx" + +using LcChargedJetSubstructureMatchingMC = JetSubstructureMatching, + soa::Join, + aod::LcChargedMCDetectorLevelSPsMatchedToLcChargedMCParticleLevelSPs, + aod::LcChargedMCParticleLevelSPsMatchedToLcChargedMCDetectorLevelSPs, + aod::LcChargedMCDetectorLevelPRsMatchedToLcChargedMCParticleLevelPRs, + aod::LcChargedMCParticleLevelPRsMatchedToLcChargedMCDetectorLevelPRs, + aod::LcChargedMCDetectorLevelSPs, + aod::LcChargedMCParticleLevelSPs, + aod::LcChargedMCDetectorLevelPRs, + aod::LcChargedMCParticleLevelPRs, + aod::CandidatesLcMCD, + aod::CandidatesLcMCP, + aod::JetTracksMCD, + aod::JetParticles, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-mc-lc-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx new file mode 100644 index 00000000000..5c1382671d2 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx @@ -0,0 +1,280 @@ +// 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. + +// jet analysis tasks (subscribing to jet finder task) +// this file should be removed once we can pass coloumns as templates!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// +/// \author Nima Zardoshti +// + +#include + +#include "fastjet/PseudoJet.hh" +#include "fastjet/ClusterSequenceArea.hh" + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/Core/JetSubstructureUtilities.h" +#include "PWGJE/Core/JetMatchingUtilities.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +#include "Framework/runDataProcessing.h" + +template +struct JetSubstructureMatchingSub { + + Produces splittingsBasetoTagMatchingTable; + Produces splittingsTagtoBaseMatchingTable; + + Produces pairsBasetoTagMatchingTable; + Produces pairsTagtoBaseMatchingTable; + + Configurable doMatchingGeo{"doMatchingGeo", true, "Enable geometric matching"}; + Configurable doMatchingPt{"doMatchingPt", true, "Enable pt matching"}; + Configurable doMatchingHf{"doMatchingHf", false, "Enable HF matching"}; + Configurable maxMatchingDistance{"maxMatchingDistance", 0.24f, "Max matching distance"}; + Configurable minPtFraction{"minPtFraction", 0.5f, "Minimum pt fraction for pt matching"}; + Configurable requireGeoMatchedJets{"requireGeoMatchedJets", false, "require jets are geo matched as well"}; + Configurable requirePtMatchedJets{"requirePtMatchedJets", false, "require jets are pT matched as well"}; + Configurable requireHFMatchedJets{"requireHFMatchedJets", false, "require jets are HF matched as well"}; + + static constexpr bool jetsBaseIsMc = o2::soa::relatedByIndex(); + static constexpr bool jetsTagIsMc = o2::soa::relatedByIndex(); + + void init(InitContext const&) + { + } + + PresliceOptional BaseSplittingsPerBaseJetInclusive = aod::chargedsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetInclusive = aod::chargedeventwisesubtractedsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetD0 = aod::d0chargedsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetD0 = aod::d0chargedeventwisesubtractedsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetDplus = aod::dpluschargedsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetDplus = aod::dpluschargedeventwisesubtractedsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetLc = aod::lcchargedsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetLc = aod::lcchargedeventwisesubtractedsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetBplus = aod::bpluschargedsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetBplus = aod::bpluschargedeventwisesubtractedsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetDielectron = aod::dielectronchargedsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetDielectron = aod::dielectronchargedeventwisesubtractedsplitting::jetId; + + PresliceOptional BasePairsPerBaseJetInclusive = aod::chargedpair::jetId; + PresliceOptional TagPairsPerTagJetInclusive = aod::chargedeventwisesubtractedpair::jetId; + PresliceOptional BasePairsPerBaseJetD0 = aod::d0chargedpair::jetId; + PresliceOptional TagPairsPerTagJetD0 = aod::d0chargedeventwisesubtractedpair::jetId; + PresliceOptional BasePairsPerBaseJetDplus = aod::dpluschargedpair::jetId; + PresliceOptional TagPairsPerTagJetDplus = aod::dpluschargedeventwisesubtractedpair::jetId; + PresliceOptional BasePairsPerBaseJetLc = aod::lcchargedpair::jetId; + PresliceOptional TagPairsPerTagJetLc = aod::lcchargedeventwisesubtractedpair::jetId; + PresliceOptional BasePairsPerBaseJetBplus = aod::bpluschargedpair::jetId; + PresliceOptional TagPairsPerTagJetBplus = aod::bpluschargedeventwisesubtractedpair::jetId; + PresliceOptional BasePairsPerBaseJetDielectron = aod::dielectronchargedpair::jetId; + PresliceOptional TagPairsPerTagJetDielectron = aod::dielectronchargedeventwisesubtractedpair::jetId; + + // workaround till binding nodes can be passed as template arguments + template + auto slicedPerJetForMatching(T const& table, U const& jet, V const& perIncluisveJet, M const& perD0Jet, N const& perDplusJet, O const& perLcJet, P const& perBplusJet, Q const& perDielectronJet) + { + if constexpr (jethfutilities::isHFTable() || jethfutilities::isHFMcTable()) { + return jethfutilities::slicedPerHFJet(table, jet, perD0Jet, perDplusJet, perLcJet, perBplusJet); + } else if constexpr (jetdqutilities::isDielectronTable() || jetdqutilities::isDielectronMcTable()) { + return jetdqutilities::slicedPerDielectronJet(table, jet, perDielectronJet); + } else { + return table.sliceBy(perIncluisveJet, jet.globalIndex()); + } + } + + template + auto defaultMatchedJets(T const& jetTag) + { + if constexpr (jetcandidateutilities::isCandidateTable()) { + return jetTag.template matchedJetCand_as(); + } else { + return jetTag.template matchedJetGeo_as(); + } + } + + void processData(JetsTag const& jetsTag, + JetsBase const&, + SplittingsBase const& jetsBaseSplittings, + SplittingsTag const& jetsTagSplittings, + PairsBase const& jetsBasePairs, + PairsTag const& jetsTagPairs, + Candidates const& candidates, + ClustersBase const& clustersBase, + TracksBase const& tracksBase, TracksTag const& tracksTag) + { + + std::vector> jetsBasetoTagSplittingsMatchingGeo, jetsBasetoTagSplittingsMatchingPt, jetsBasetoTagSplittingsMatchingHF; + jetsBasetoTagSplittingsMatchingGeo.assign(jetsBaseSplittings.size(), {}); + jetsBasetoTagSplittingsMatchingPt.assign(jetsBaseSplittings.size(), {}); + jetsBasetoTagSplittingsMatchingHF.assign(jetsBaseSplittings.size(), {}); + + std::vector> jetsTagtoBaseSplittingsMatchingGeo, jetsTagtoBaseSplittingsMatchingPt, jetsTagtoBaseSplittingsMatchingHF; + jetsTagtoBaseSplittingsMatchingGeo.assign(jetsTagSplittings.size(), {}); + jetsTagtoBaseSplittingsMatchingPt.assign(jetsTagSplittings.size(), {}); + jetsTagtoBaseSplittingsMatchingHF.assign(jetsTagSplittings.size(), {}); + + std::vector jetTagSplittingsMap; + std::vector jetBaseSplittingsMap; + jetTagSplittingsMap.resize(jetsTagSplittings.size(), -1); + jetBaseSplittingsMap.resize(jetsBaseSplittings.size(), -1); + + std::vector> jetsBasetoTagPairsMatching; + std::vector> jetsTagtoBasePairsMatching; + jetsBasetoTagPairsMatching.assign(jetsBasePairs.size(), {}); + jetsTagtoBasePairsMatching.assign(jetsTagPairs.size(), {}); + + std::vector jetTagPairsMap; + std::vector jetBasePairsMap; + jetTagPairsMap.resize(jetsTagPairs.size(), -1); + jetBasePairsMap.resize(jetsBasePairs.size(), -1); + + for (auto jetTag : jetsTag) { + bool hasMatchedJet = false; + if constexpr (jetcandidateutilities::isCandidateTable()) { + hasMatchedJet = jetTag.has_matchedJetCand(); + } else { + hasMatchedJet = jetTag.has_matchedJetGeo(); + } + if (hasMatchedJet) { + // auto const& jetTagSplittings = jetsTagSplittings.sliceBy(TagSplittingsPerTagJet, jetTag.globalIndex()); + auto const& jetTagSplittings = slicedPerJetForMatching(jetsTagSplittings, jetTag, TagSplittingsPerTagJetInclusive, TagSplittingsPerTagJetD0, TagSplittingsPerTagJetDplus, TagSplittingsPerTagJetLc, TagSplittingsPerTagJetBplus, TagSplittingsPerTagJetDielectron); + int tagSplittingIndex = 0; + for (auto const& jetTagSplitting : jetTagSplittings) { + jetTagSplittingsMap[jetTagSplitting.globalIndex()] = tagSplittingIndex; + tagSplittingIndex++; + } + // auto const& jetTagPairs = jetsTagPairs.sliceBy(TagPairsPerTagJet, jetTag.globalIndex()); + auto const& jetTagPairs = slicedPerJetForMatching(jetsTagPairs, jetTag, TagPairsPerTagJetInclusive, TagPairsPerTagJetD0, TagPairsPerTagJetDplus, TagPairsPerTagJetLc, TagPairsPerTagJetBplus, TagPairsPerTagJetDielectron); + int tagPairIndex = 0; + for (auto const& jetTagPair : jetTagPairs) { + jetTagPairsMap[jetTagPair.globalIndex()] = tagPairIndex; + tagPairIndex++; + } + for (auto& jetBase : defaultMatchedJets(jetTag)) { + if (requireGeoMatchedJets) { + bool jetsMatchedWithGeo = false; + for (auto& jetBaseForMatchGeo : jetTag.template matchedJetGeo_as()) { + if (jetBaseForMatchGeo.globalIndex() == jetBase.globalIndex()) { + jetsMatchedWithGeo = true; + } + } + if (!jetsMatchedWithGeo) { + continue; + } + } + if (requirePtMatchedJets) { + bool jetsMatchedWithPt = false; + for (auto& jetBaseForMatchPt : jetTag.template matchedJetPt_as()) { + if (jetBaseForMatchPt.globalIndex() == jetBase.globalIndex()) { + jetsMatchedWithPt = true; + } + } + if (!jetsMatchedWithPt) { + continue; + } + } + if (requireHFMatchedJets) { + bool jetsMatchedWithHF = false; + for (auto& jetBaseForMatchHF : jetTag.template matchedJetCand_as()) { + if (jetBaseForMatchHF.globalIndex() == jetBase.globalIndex()) { + jetsMatchedWithHF = true; + } + } + if (!jetsMatchedWithHF) { + continue; + } + } + // auto const& jetBaseSplittings = jetsBaseSplittings.sliceBy(BaseSplittingsPerBaseJet, jetBase.globalIndex()); + auto const& jetBaseSplittings = slicedPerJetForMatching(jetsBaseSplittings, jetBase, BaseSplittingsPerBaseJetInclusive, BaseSplittingsPerBaseJetD0, BaseSplittingsPerBaseJetDplus, BaseSplittingsPerBaseJetLc, BaseSplittingsPerBaseJetBplus, BaseSplittingsPerBaseJetDielectron); + int baseSplittingIndex = 0; + for (auto const& jetBaseSplitting : jetBaseSplittings) { + jetBaseSplittingsMap[jetBaseSplitting.globalIndex()] = baseSplittingIndex; + baseSplittingIndex++; + } + jetmatchingutilities::doAllMatching(jetBaseSplittings, jetTagSplittings, jetsBasetoTagSplittingsMatchingGeo, jetsBasetoTagSplittingsMatchingPt, jetsBasetoTagSplittingsMatchingHF, jetsTagtoBaseSplittingsMatchingGeo, jetsTagtoBaseSplittingsMatchingPt, jetsTagtoBaseSplittingsMatchingHF, candidates, tracksBase, clustersBase, candidates, tracksTag, tracksTag, doMatchingGeo, doMatchingHf, doMatchingPt, maxMatchingDistance, minPtFraction); + // auto const& jetBasePairs = jetsBasePairs.sliceBy(BasePairsPerBaseJet, jetBase.globalIndex()); + auto const& jetBasePairs = slicedPerJetForMatching(jetsBasePairs, jetBase, BasePairsPerBaseJetInclusive, BasePairsPerBaseJetD0, BasePairsPerBaseJetDplus, BasePairsPerBaseJetLc, BasePairsPerBaseJetBplus, BasePairsPerBaseJetDielectron); + int basePairIndex = 0; + for (auto const& jetBasePair : jetBasePairs) { + jetBasePairsMap[jetBasePair.globalIndex()] = basePairIndex; + basePairIndex++; + } + jetmatchingutilities::doPairMatching(jetBasePairs, jetTagPairs, jetsBasetoTagPairsMatching, jetsTagtoBasePairsMatching, candidates, tracksBase, candidates, tracksTag); + } + } + } + + for (auto jetsTagSplitting : jetsTagSplittings) { + std::vector tagToBaseMatchingGeoIndex; + std::vector tagToBaseMatchingPtIndex; + std::vector tagToBaseMatchingHFIndex; + for (auto jetBaseSplittingIndex : jetsTagtoBaseSplittingsMatchingGeo[jetsTagSplitting.globalIndex()]) { + tagToBaseMatchingGeoIndex.push_back(jetBaseSplittingsMap[jetBaseSplittingIndex]); + } + for (auto jetBaseSplittingIndex : jetsTagtoBaseSplittingsMatchingPt[jetsTagSplitting.globalIndex()]) { + tagToBaseMatchingPtIndex.push_back(jetBaseSplittingsMap[jetBaseSplittingIndex]); + } + for (auto jetBaseSplittingIndex : jetsTagtoBaseSplittingsMatchingHF[jetsTagSplitting.globalIndex()]) { + tagToBaseMatchingHFIndex.push_back(jetBaseSplittingsMap[jetBaseSplittingIndex]); + } + splittingsTagtoBaseMatchingTable(tagToBaseMatchingGeoIndex, tagToBaseMatchingPtIndex, tagToBaseMatchingHFIndex); + } + for (auto jetsBaseSplitting : jetsBaseSplittings) { + std::vector baseToTagMatchingGeoIndex; + std::vector baseToTagMatchingPtIndex; + std::vector baseToTagMatchingHFIndex; + for (auto jetTagSplittingIndex : jetsBasetoTagSplittingsMatchingGeo[jetsBaseSplitting.globalIndex()]) { + baseToTagMatchingGeoIndex.push_back(jetTagSplittingsMap[jetTagSplittingIndex]); + } + for (auto jetTagSplittingIndex : jetsBasetoTagSplittingsMatchingPt[jetsBaseSplitting.globalIndex()]) { + baseToTagMatchingPtIndex.push_back(jetTagSplittingsMap[jetTagSplittingIndex]); + } + for (auto jetTagSplittingIndex : jetsBasetoTagSplittingsMatchingHF[jetsBaseSplitting.globalIndex()]) { + baseToTagMatchingHFIndex.push_back(jetTagSplittingsMap[jetTagSplittingIndex]); + } + splittingsBasetoTagMatchingTable(baseToTagMatchingGeoIndex, baseToTagMatchingPtIndex, baseToTagMatchingHFIndex); + } + for (auto jetsTagPair : jetsTagPairs) { + std::vector tagToBaseMatchingIndex; + for (auto jetBasePairIndex : jetsTagtoBasePairsMatching[jetsTagPair.globalIndex()]) { + tagToBaseMatchingIndex.push_back(jetBasePairsMap[jetBasePairIndex]); + } + pairsTagtoBaseMatchingTable(tagToBaseMatchingIndex); + } + for (auto jetsBasePair : jetsBasePairs) { + std::vector baseToTagMatchingIndex; + for (auto jetTagPairIndex : jetsBasetoTagPairsMatching[jetsBasePair.globalIndex()]) { + baseToTagMatchingIndex.push_back(jetTagPairsMap[jetTagPairIndex]); + } + pairsBasetoTagMatchingTable(baseToTagMatchingIndex); + } + } + PROCESS_SWITCH(JetSubstructureMatchingSub, processData, "charged jet substructure", true); +}; diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubBplusCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubBplusCharged.cxx new file mode 100644 index 00000000000..901ff6226a3 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubBplusCharged.cxx @@ -0,0 +1,39 @@ +// 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. + +// substructure matching event-wise subtracted Bplus charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx" + +using BplusChargedJetSubstructureMatchingSub = JetSubstructureMatchingSub, + soa::Join, + aod::BplusChargedSPsMatchedToBplusChargedEventWiseSubtractedSPs, + aod::BplusChargedEventWiseSubtractedSPsMatchedToBplusChargedSPs, + aod::BplusChargedPRsMatchedToBplusChargedEventWiseSubtractedPRs, + aod::BplusChargedEventWiseSubtractedPRsMatchedToBplusChargedPRs, + aod::BplusChargedSPs, + aod::BplusChargedEventWiseSubtractedSPs, + aod::BplusChargedPRs, + aod::BplusChargedEventWiseSubtractedPRs, + aod::CandidatesBplusData, + aod::JetTracks, + aod::JetTracksSubBplus, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-sub-bplus-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubCharged.cxx new file mode 100644 index 00000000000..618d55d7c5b --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubCharged.cxx @@ -0,0 +1,39 @@ +// 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. + +// substructure matching event-wise subtracted charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx" + +using ChargedJetSubstructureMatchingSub = JetSubstructureMatchingSub, + soa::Join, + aod::ChargedSPsMatchedToChargedEventWiseSubtractedSPs, + aod::ChargedEventWiseSubtractedSPsMatchedToChargedSPs, + aod::ChargedPRsMatchedToChargedEventWiseSubtractedPRs, + aod::ChargedEventWiseSubtractedPRsMatchedToChargedPRs, + aod::ChargedSPs, + aod::ChargedEventWiseSubtractedSPs, + aod::ChargedPRs, + aod::ChargedEventWiseSubtractedPRs, + aod::JCollisions, + aod::JetTracks, + aod::JetTracksSub, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-sub-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubD0Charged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubD0Charged.cxx new file mode 100644 index 00000000000..f53ebf3ae39 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubD0Charged.cxx @@ -0,0 +1,39 @@ +// 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. + +// substructure matching event-wise subtracted D0 charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx" + +using D0ChargedJetSubstructureMatchingSub = JetSubstructureMatchingSub, + soa::Join, + aod::D0ChargedSPsMatchedToD0ChargedEventWiseSubtractedSPs, + aod::D0ChargedEventWiseSubtractedSPsMatchedToD0ChargedSPs, + aod::D0ChargedPRsMatchedToD0ChargedEventWiseSubtractedPRs, + aod::D0ChargedEventWiseSubtractedPRsMatchedToD0ChargedPRs, + aod::D0ChargedSPs, + aod::D0ChargedEventWiseSubtractedSPs, + aod::D0ChargedPRs, + aod::D0ChargedEventWiseSubtractedPRs, + aod::CandidatesD0Data, + aod::JetTracks, + aod::JetTracksSubD0, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-sub-d0-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubDielectronCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubDielectronCharged.cxx new file mode 100644 index 00000000000..71fad02021d --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubDielectronCharged.cxx @@ -0,0 +1,39 @@ +// 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. + +// substructure matching event-wise subtracted Dielectron charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx" + +using DielectronChargedJetSubstructureMatchingSub = JetSubstructureMatchingSub, + soa::Join, + aod::DielectronChargedSPsMatchedToDielectronChargedEventWiseSubtractedSPs, + aod::DielectronChargedEventWiseSubtractedSPsMatchedToDielectronChargedSPs, + aod::DielectronChargedPRsMatchedToDielectronChargedEventWiseSubtractedPRs, + aod::DielectronChargedEventWiseSubtractedPRsMatchedToDielectronChargedPRs, + aod::DielectronChargedSPs, + aod::DielectronChargedEventWiseSubtractedSPs, + aod::DielectronChargedPRs, + aod::DielectronChargedEventWiseSubtractedPRs, + aod::CandidatesDielectronData, + aod::JetTracks, + aod::JetTracksSubDielectron, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-sub-dielectron-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubDplusCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubDplusCharged.cxx new file mode 100644 index 00000000000..662b227b08a --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubDplusCharged.cxx @@ -0,0 +1,39 @@ +// 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. + +// substructure matching event-wise subtracted Dplus charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx" + +using DplusChargedJetSubstructureMatchingSub = JetSubstructureMatchingSub, + soa::Join, + aod::DplusChargedSPsMatchedToDplusChargedEventWiseSubtractedSPs, + aod::DplusChargedEventWiseSubtractedSPsMatchedToDplusChargedSPs, + aod::DplusChargedPRsMatchedToDplusChargedEventWiseSubtractedPRs, + aod::DplusChargedEventWiseSubtractedPRsMatchedToDplusChargedPRs, + aod::DplusChargedSPs, + aod::DplusChargedEventWiseSubtractedSPs, + aod::DplusChargedPRs, + aod::DplusChargedEventWiseSubtractedPRs, + aod::CandidatesDplusData, + aod::JetTracks, + aod::JetTracksSubDplus, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-sub-dplus-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubLcCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubLcCharged.cxx new file mode 100644 index 00000000000..9ab84673b9c --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubLcCharged.cxx @@ -0,0 +1,39 @@ +// 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. + +// substructure matching event-wise subtracted Lc charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx" + +using LcChargedJetSubstructureMatchingSub = JetSubstructureMatchingSub, + soa::Join, + aod::LcChargedSPsMatchedToLcChargedEventWiseSubtractedSPs, + aod::LcChargedEventWiseSubtractedSPsMatchedToLcChargedSPs, + aod::LcChargedPRsMatchedToLcChargedEventWiseSubtractedPRs, + aod::LcChargedEventWiseSubtractedPRsMatchedToLcChargedPRs, + aod::LcChargedSPs, + aod::LcChargedEventWiseSubtractedSPs, + aod::LcChargedPRs, + aod::LcChargedEventWiseSubtractedPRs, + aod::CandidatesLcData, + aod::JetTracks, + aod::JetTracksSubLc, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-sub-lc-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/jetmatchingmc.cxx b/PWGJE/TableProducer/Matching/jetMatchingMC.cxx similarity index 54% rename from PWGJE/TableProducer/jetmatchingmc.cxx rename to PWGJE/TableProducer/Matching/jetMatchingMC.cxx index 6452b493d4b..72206247c50 100644 --- a/PWGJE/TableProducer/jetmatchingmc.cxx +++ b/PWGJE/TableProducer/Matching/jetMatchingMC.cxx @@ -17,6 +17,8 @@ /// \author Aimeric Lanodu /// \author Nima Zardoshti +#include + #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ASoA.h" @@ -34,7 +36,7 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -template +template struct JetMatchingMc { Configurable doMatchingGeo{"doMatchingGeo", true, "Enable geometric matching"}; @@ -47,31 +49,26 @@ struct JetMatchingMc { Produces jetsTagtoBaseMatchingTable; // preslicing jet collections, only for Mc-based collection - static constexpr bool jetsBaseIsMc = o2::soa::relatedByIndex(); - static constexpr bool jetsTagIsMc = o2::soa::relatedByIndex(); + static constexpr bool jetsBaseIsMc = o2::soa::relatedByIndex(); + static constexpr bool jetsTagIsMc = o2::soa::relatedByIndex(); Preslice baseJetsPerCollision = jetsBaseIsMc ? aod::jet::mcCollisionId : aod::jet::collisionId; Preslice tagJetsPerCollision = jetsTagIsMc ? aod::jet::mcCollisionId : aod::jet::collisionId; - PresliceUnsorted CollisionsPerMcCollision = aod::jmccollisionlb::mcCollisionId; + PresliceUnsorted CollisionsPerMcCollision = aod::jmccollisionlb::mcCollisionId; void init(InitContext const&) { } - void processDummy(JetMcCollisions const&) - { - } - PROCESS_SWITCH(JetMatchingMc, processDummy, "Dummy process", true); - - void processJets(JetMcCollisions const& mcCollisions, JetCollisionsMCD const& collisions, + void processJets(aod::JetMcCollisions const& mcCollisions, aod::JetCollisionsMCD const& collisions, JetsBase const& jetsBase, JetsTag const& jetsTag, - JetTracksMCD const& tracks, - JetParticles const& particles, + aod::JetTracksMCD const& tracks, + ClustersBase const& clusters, + aod::JetParticles const& particles, CandidatesBase const& candidatesBase, CandidatesTag const& candidatesTag) { - // initialise objects used to store the matching index arrays (array in case a mcCollision is split) before filling the matching tables std::vector> jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF; std::vector> jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF; @@ -92,7 +89,7 @@ struct JetMatchingMc { const auto jetsBasePerColl = jetsBase.sliceBy(baseJetsPerCollision, jetsBaseIsMc ? mcCollision.globalIndex() : collision.globalIndex()); const auto jetsTagPerColl = jetsTag.sliceBy(tagJetsPerCollision, jetsTagIsMc ? mcCollision.globalIndex() : collision.globalIndex()); - jetmatchingutilities::doAllMatching(jetsBasePerColl, jetsTagPerColl, jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF, jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF, candidatesBase, candidatesTag, tracks, particles, doMatchingGeo, doMatchingHf, doMatchingPt, maxMatchingDistance, minPtFraction); + jetmatchingutilities::doAllMatching(jetsBasePerColl, jetsTagPerColl, jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF, jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF, candidatesBase, tracks, clusters, candidatesTag, particles, particles, doMatchingGeo, doMatchingHf, doMatchingPt, maxMatchingDistance, minPtFraction); } } for (auto i = 0; i < jetsBase.size(); ++i) { @@ -102,42 +99,5 @@ struct JetMatchingMc { jetsTagtoBaseMatchingTable(jetsTagtoBaseMatchingGeo[i], jetsTagtoBaseMatchingPt[i], jetsTagtoBaseMatchingHF[i]); // is (and needs to) be filled in order } } - PROCESS_SWITCH(JetMatchingMc, processJets, "Perform jet matching", false); + PROCESS_SWITCH(JetMatchingMc, processJets, "Perform jet matching", true); }; - -using ChargedJetMatching = JetMatchingMc, - soa::Join, - aod::ChargedMCDetectorLevelJetsMatchedToChargedMCParticleLevelJets, - aod::ChargedMCParticleLevelJetsMatchedToChargedMCDetectorLevelJets, - aod::JCollisions, - aod::JMcCollisions>; -using D0ChargedJetMatching = JetMatchingMc, - soa::Join, - aod::D0ChargedMCDetectorLevelJetsMatchedToD0ChargedMCParticleLevelJets, - aod::D0ChargedMCParticleLevelJetsMatchedToD0ChargedMCDetectorLevelJets, - CandidatesD0MCD, - CandidatesD0MCP>; -using LcChargedJetMatching = JetMatchingMc, - soa::Join, - aod::LcChargedMCDetectorLevelJetsMatchedToLcChargedMCParticleLevelJets, - aod::LcChargedMCParticleLevelJetsMatchedToLcChargedMCDetectorLevelJets, - CandidatesLcMCD, - CandidatesLcMCP>; -/*using BplusChargedJetMatching = JetMatchingMc, - soa::Join, - aod::BplusChargedMCDetectorLevelJetsMatchedToBplusChargedMCParticleLevelJets, - aod::BplusChargedMCParticleLevelJetsMatchedToBplusChargedMCDetectorLevelJets, - CandidatesBplusMCD, - CandidatesBplusMCP>;*/ - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - std::vector tasks; - - tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-matching-mc-ch"})); - tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-d0-ch"})); - tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-lc-ch"})); - // tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-bplus-ch"})); - - return WorkflowSpec{tasks}; -} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCBplusCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCBplusCharged.cxx new file mode 100644 index 00000000000..8a5705f273f --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCBplusCharged.cxx @@ -0,0 +1,31 @@ +// 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. + +// jet matching mc B+ charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +using BplusChargedJetMatchingMC = JetMatchingMc, + soa::Join, + aod::BplusChargedMCDetectorLevelJetsMatchedToBplusChargedMCParticleLevelJets, + aod::BplusChargedMCParticleLevelJetsMatchedToBplusChargedMCDetectorLevelJets, + aod::CandidatesBplusMCD, + aod::CandidatesBplusMCP, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-bplus-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCCharged.cxx new file mode 100644 index 00000000000..fe951be4566 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCCharged.cxx @@ -0,0 +1,31 @@ +// 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. + +// jet matching mc charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +using ChargedJetMatchingMC = JetMatchingMc, + soa::Join, + aod::ChargedMCDetectorLevelJetsMatchedToChargedMCParticleLevelJets, + aod::ChargedMCParticleLevelJetsMatchedToChargedMCDetectorLevelJets, + aod::JCollisions, + aod::JMcCollisions, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-matching-mc-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCD0Charged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCD0Charged.cxx new file mode 100644 index 00000000000..64abc51c79d --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCD0Charged.cxx @@ -0,0 +1,31 @@ +// 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. + +// jet matching mc D0 charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +using D0ChargedJetMatchingMC = JetMatchingMc, + soa::Join, + aod::D0ChargedMCDetectorLevelJetsMatchedToD0ChargedMCParticleLevelJets, + aod::D0ChargedMCParticleLevelJetsMatchedToD0ChargedMCDetectorLevelJets, + aod::CandidatesD0MCD, + aod::CandidatesD0MCP, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-d0-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCDielectronCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCDielectronCharged.cxx new file mode 100644 index 00000000000..7d284ecbee4 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCDielectronCharged.cxx @@ -0,0 +1,31 @@ +// 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. + +// jet matching mc Dielectron charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +using DielectronChargedJetMatchingMC = JetMatchingMc, + soa::Join, + aod::DielectronChargedMCDetectorLevelJetsMatchedToDielectronChargedMCParticleLevelJets, + aod::DielectronChargedMCParticleLevelJetsMatchedToDielectronChargedMCDetectorLevelJets, + aod::CandidatesDielectronMCD, + aod::CandidatesDielectronMCP, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-dielectron-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCDplusCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCDplusCharged.cxx new file mode 100644 index 00000000000..31c3391533b --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCDplusCharged.cxx @@ -0,0 +1,31 @@ +// 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. + +// jet matching mc D+ charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +using DplusChargedJetMatchingMC = JetMatchingMc, + soa::Join, + aod::DplusChargedMCDetectorLevelJetsMatchedToDplusChargedMCParticleLevelJets, + aod::DplusChargedMCParticleLevelJetsMatchedToDplusChargedMCDetectorLevelJets, + aod::CandidatesDplusMCD, + aod::CandidatesDplusMCP, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-dplus-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCFull.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCFull.cxx new file mode 100644 index 00000000000..e4bf6f3979d --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCFull.cxx @@ -0,0 +1,31 @@ +// 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. + +// jet matching mc full task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +using FullJetMatchingMC = JetMatchingMc, + soa::Join, + aod::FullMCDetectorLevelJetsMatchedToFullMCParticleLevelJets, + aod::FullMCParticleLevelJetsMatchedToFullMCDetectorLevelJets, + aod::JCollisions, + aod::JMcCollisions, + aod::JetClustersMCD>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-matching-mc-full"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCLcCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCLcCharged.cxx new file mode 100644 index 00000000000..9be7e169e57 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCLcCharged.cxx @@ -0,0 +1,31 @@ +// 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. + +// jet matching mc Lc charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +using LcChargedJetMatchingMC = JetMatchingMc, + soa::Join, + aod::LcChargedMCDetectorLevelJetsMatchedToLcChargedMCParticleLevelJets, + aod::LcChargedMCParticleLevelJetsMatchedToLcChargedMCDetectorLevelJets, + aod::CandidatesLcMCD, + aod::CandidatesLcMCP, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-lc-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCNeutral.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCNeutral.cxx new file mode 100644 index 00000000000..8af1d2513bc --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCNeutral.cxx @@ -0,0 +1,31 @@ +// 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. + +// jet matching neutral task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +using NeutralJetMatchingMC = JetMatchingMc, + soa::Join, + aod::NeutralMCDetectorLevelJetsMatchedToNeutralMCParticleLevelJets, + aod::NeutralMCParticleLevelJetsMatchedToNeutralMCDetectorLevelJets, + aod::JCollisions, + aod::JMcCollisions, + aod::JetClustersMCD>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-matching-mc-neutral"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/jetmatchingmcsub.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx similarity index 54% rename from PWGJE/TableProducer/jetmatchingmcsub.cxx rename to PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx index 9f3ced35e01..45e57923721 100644 --- a/PWGJE/TableProducer/jetmatchingmcsub.cxx +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx @@ -13,6 +13,8 @@ /// \brief matching event-wise constituent subtracted detector level and unsubtracted generated level jets (this is usseful as a template for embedding matching) /// \author Nima Zardoshti +#include + #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ASoA.h" @@ -53,15 +55,10 @@ struct JetMatchingMcSub { { } - void processDummy(JetCollisions const&) - { - } - PROCESS_SWITCH(JetMatchingMcSub, processDummy, "Dummy process", true); - - void processJets(JetCollisions const& collisions, + void processJets(aod::JetCollisions const& collisions, JetsBase const& jetsBase, JetsTag const& jetsTag, - JetTracks const& tracks, - JetTracksSub const& tracksSub, + aod::JetTracks const& tracks, + aod::JetTracksSub const& tracksSub, Candidates const& candidates) { @@ -81,7 +78,7 @@ struct JetMatchingMcSub { const auto jetsBasePerColl = jetsBase.sliceBy(baseJetsPerCollision, collision.globalIndex()); const auto jetsTagPerColl = jetsTag.sliceBy(tagJetsPerCollision, collision.globalIndex()); - jetmatchingutilities::doAllMatching(jetsBasePerColl, jetsTagPerColl, jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF, jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF, candidates, candidates, tracks, tracksSub, doMatchingGeo, doMatchingHf, doMatchingPt, maxMatchingDistance, minPtFraction); + jetmatchingutilities::doAllMatching(jetsBasePerColl, jetsTagPerColl, jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF, jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF, candidates, tracks, tracks, candidates, tracksSub, tracksSub, doMatchingGeo, doMatchingHf, doMatchingPt, maxMatchingDistance, minPtFraction); } for (auto i = 0; i < jetsBase.size(); ++i) { @@ -91,38 +88,5 @@ struct JetMatchingMcSub { jetsTagtoBaseMatchingTable(jetsTagtoBaseMatchingGeo[i], jetsTagtoBaseMatchingPt[i], jetsTagtoBaseMatchingHF[i]); // is (and needs to) be filled in order } } - PROCESS_SWITCH(JetMatchingMcSub, processJets, "Perform jet matching", false); + PROCESS_SWITCH(JetMatchingMcSub, processJets, "Perform jet matching", true); }; - -using ChargedJetMatching = JetMatchingMcSub, - soa::Join, - aod::ChargedMCDetectorLevelJetsMatchedToChargedMCDetectorLevelEventWiseSubtractedJets, - aod::ChargedMCDetectorLevelEventWiseSubtractedJetsMatchedToChargedMCDetectorLevelJets, - aod::JDummys>; -using D0ChargedJetMatching = JetMatchingMcSub, - soa::Join, - aod::D0ChargedMCDetectorLevelJetsMatchedToD0ChargedMCDetectorLevelEventWiseSubtractedJets, - aod::D0ChargedMCDetectorLevelEventWiseSubtractedJetsMatchedToD0ChargedMCDetectorLevelJets, - CandidatesD0MCD>; -using LcChargedJetMatching = JetMatchingMcSub, - soa::Join, - aod::LcChargedMCDetectorLevelJetsMatchedToLcChargedMCDetectorLevelEventWiseSubtractedJets, - aod::LcChargedMCDetectorLevelEventWiseSubtractedJetsMatchedToLcChargedMCDetectorLevelJets, - CandidatesLcMCD>; -/*using BplusChargedJetMatching = JetMatchingMcSub, - soa::Join, - aod::BplusChargedMCDetectorLevelJetsMatchedToBplusChargedMCDetectorLevelEventWiseSubtractedJets, - aod::BplusChargedMCDetectorLevelEventWiseSubtractedJetsMatchedToBplusChargedMCDetectorLevelJets, - CandidatesBplusMCD>;*/ - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - std::vector tasks; - - tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-matching-mc-sub-ch"})); - tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-sub-d0-ch"})); - tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-sub-lc-ch"})); - // tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-sub-bplus-ch"})); - - return WorkflowSpec{tasks}; -} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCSubBplusCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCSubBplusCharged.cxx new file mode 100644 index 00000000000..86db7221aa6 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSubBplusCharged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet matching mc subtracted B+ charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx" + +using D0ChargedJetMatchingMCSub = JetMatchingMcSub, + soa::Join, + aod::D0ChargedMCDetectorLevelJetsMatchedToD0ChargedMCDetectorLevelEventWiseSubtractedJets, + aod::D0ChargedMCDetectorLevelEventWiseSubtractedJetsMatchedToD0ChargedMCDetectorLevelJets, + aod::CandidatesD0MCD>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-sub-d0-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCSubCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCSubCharged.cxx new file mode 100644 index 00000000000..2b0c5c19992 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSubCharged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet matching mc subtracted charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx" + +using ChargedJetMatchingMCSub = JetMatchingMcSub, + soa::Join, + aod::ChargedMCDetectorLevelJetsMatchedToChargedMCDetectorLevelEventWiseSubtractedJets, + aod::ChargedMCDetectorLevelEventWiseSubtractedJetsMatchedToChargedMCDetectorLevelJets, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-matching-mc-sub-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCSubD0Charged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCSubD0Charged.cxx new file mode 100644 index 00000000000..92a71c20900 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSubD0Charged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet matching mc subtracted D0 charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx" + +using D0ChargedJetMatchingMCSub = JetMatchingMcSub, + soa::Join, + aod::D0ChargedMCDetectorLevelJetsMatchedToD0ChargedMCDetectorLevelEventWiseSubtractedJets, + aod::D0ChargedMCDetectorLevelEventWiseSubtractedJetsMatchedToD0ChargedMCDetectorLevelJets, + aod::CandidatesD0MCD>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-sub-d0-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCSubDielectronCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCSubDielectronCharged.cxx new file mode 100644 index 00000000000..376e904f473 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSubDielectronCharged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet matching mc subtracted Dielectron charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx" + +using DielectronChargedJetMatchingMCSub = JetMatchingMcSub, + soa::Join, + aod::DielectronChargedMCDetectorLevelJetsMatchedToDielectronChargedMCDetectorLevelEventWiseSubtractedJets, + aod::DielectronChargedMCDetectorLevelEventWiseSubtractedJetsMatchedToDielectronChargedMCDetectorLevelJets, + aod::CandidatesDielectronMCD>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-sub-dielectron-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCSubDplusCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCSubDplusCharged.cxx new file mode 100644 index 00000000000..d8b0e0aaf50 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSubDplusCharged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet matching mc subtracted D+ charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx" + +using DplusChargedJetMatchingMCSub = JetMatchingMcSub, + soa::Join, + aod::DplusChargedMCDetectorLevelJetsMatchedToDplusChargedMCDetectorLevelEventWiseSubtractedJets, + aod::DplusChargedMCDetectorLevelEventWiseSubtractedJetsMatchedToDplusChargedMCDetectorLevelJets, + aod::CandidatesDplusMCD>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-sub-dplus-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCSubLcCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCSubLcCharged.cxx new file mode 100644 index 00000000000..6a9456eb241 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSubLcCharged.cxx @@ -0,0 +1,29 @@ +// 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. + +// jet matching mc subtracted Lc charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx" + +using LcChargedJetMatchingMCSub = JetMatchingMcSub, + soa::Join, + aod::LcChargedMCDetectorLevelJetsMatchedToLcChargedMCDetectorLevelEventWiseSubtractedJets, + aod::LcChargedMCDetectorLevelEventWiseSubtractedJetsMatchedToLcChargedMCDetectorLevelJets, + aod::CandidatesLcMCD>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-sub-lc-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCV0Charged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCV0Charged.cxx new file mode 100644 index 00000000000..d0910abc488 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCV0Charged.cxx @@ -0,0 +1,31 @@ +// 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. + +// jet matching V0 charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +using V0ChargedJetMatchingMC = JetMatchingMc, + soa::Join, + aod::V0ChargedMCDetectorLevelJetsMatchedToV0ChargedMCParticleLevelJets, + aod::V0ChargedMCParticleLevelJetsMatchedToV0ChargedMCDetectorLevelJets, + aod::CandidatesV0MCD, + aod::CandidatesV0MCP, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-v0-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/jetmatchingsub.cxx b/PWGJE/TableProducer/Matching/jetMatchingSub.cxx similarity index 56% rename from PWGJE/TableProducer/jetmatchingsub.cxx rename to PWGJE/TableProducer/Matching/jetMatchingSub.cxx index bc9fa27b454..002fedd3a0d 100644 --- a/PWGJE/TableProducer/jetmatchingsub.cxx +++ b/PWGJE/TableProducer/Matching/jetMatchingSub.cxx @@ -13,6 +13,8 @@ /// \brief matching event-wise constituent subtracted data jets and unsubtracted data jets /// \author Nima Zardoshti +#include + #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ASoA.h" @@ -53,14 +55,9 @@ struct JetMatchingSub { { } - void processDummy(JetCollisions const&) - { - } - PROCESS_SWITCH(JetMatchingSub, processDummy, "Dummy process", true); - - void processJets(JetCollisions const& collisions, + void processJets(aod::JetCollisions const& collisions, JetsBase const& jetsBase, JetsTag const& jetsTag, - JetTracks const& tracks, TracksTag const& tracksSub, Candidates const& candidates) + aod::JetTracks const& tracks, TracksTag const& tracksSub, Candidates const& candidates) { // initialise objects used to store the matching index arrays (array in case a mcCollision is split) before filling the matching tables @@ -79,7 +76,7 @@ struct JetMatchingSub { const auto jetsBasePerColl = jetsBase.sliceBy(baseJetsPerCollision, collision.globalIndex()); const auto jetsTagPerColl = jetsTag.sliceBy(tagJetsPerCollision, collision.globalIndex()); - jetmatchingutilities::doAllMatching(jetsBasePerColl, jetsTagPerColl, jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF, jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF, candidates, candidates, tracks, tracksSub, doMatchingGeo, doMatchingHf, doMatchingPt, maxMatchingDistance, minPtFraction); + jetmatchingutilities::doAllMatching(jetsBasePerColl, jetsTagPerColl, jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF, jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF, candidates, tracks, tracks, candidates, tracksSub, tracksSub, doMatchingGeo, doMatchingHf, doMatchingPt, maxMatchingDistance, minPtFraction); } for (auto i = 0; i < jetsBase.size(); ++i) { @@ -89,42 +86,5 @@ struct JetMatchingSub { jetsTagtoBaseMatchingTable(jetsTagtoBaseMatchingGeo[i], jetsTagtoBaseMatchingPt[i], jetsTagtoBaseMatchingHF[i]); // is (and needs to) be filled in order } } - PROCESS_SWITCH(JetMatchingSub, processJets, "Perform jet matching", false); + PROCESS_SWITCH(JetMatchingSub, processJets, "Perform jet matching", true); }; - -using ChargedJetMatching = JetMatchingSub, - soa::Join, - aod::ChargedJetsMatchedToChargedEventWiseSubtractedJets, - aod::ChargedEventWiseSubtractedJetsMatchedToChargedJets, - aod::JTrackSubs, - aod::JDummys>; -using D0ChargedJetMatching = JetMatchingSub, - soa::Join, - aod::D0ChargedJetsMatchedToD0ChargedEventWiseSubtractedJets, - aod::D0ChargedEventWiseSubtractedJetsMatchedToD0ChargedJets, - aod::JTrackD0Subs, - CandidatesD0Data>; -using LcChargedJetMatching = JetMatchingSub, - soa::Join, - aod::LcChargedJetsMatchedToLcChargedEventWiseSubtractedJets, - aod::LcChargedEventWiseSubtractedJetsMatchedToLcChargedJets, - aod::JTrackLcSubs, - CandidatesLcData>; -/*using BplusChargedJetMatching = JetMatchingSub, - soa::Join, - aod::BplusChargedJetsMatchedToBplusChargedEventWiseSubtractedJets, - aod::BplusChargedEventWiseSubtractedJetsMatchedToBplusChargedJets, - aod::JTrackBplusSubs, - CandidatesBplusData>;*/ - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - std::vector tasks; - - tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-matching-sub-ch"})); - tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-sub-d0-ch"})); - tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-sub-lc-ch"})); - // tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-sub-bplus-ch"})); - - return WorkflowSpec{tasks}; -} diff --git a/PWGJE/TableProducer/Matching/jetMatchingSubBplusCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingSubBplusCharged.cxx new file mode 100644 index 00000000000..a24b7c6de6f --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingSubBplusCharged.cxx @@ -0,0 +1,30 @@ +// 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. + +// jet matching subtracted B+ charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingSub.cxx" + +using BplusChargedJetMatchingSub = JetMatchingSub, + soa::Join, + aod::BplusChargedJetsMatchedToBplusChargedEventWiseSubtractedJets, + aod::BplusChargedEventWiseSubtractedJetsMatchedToBplusChargedJets, + aod::JTrackBplusSubs, + aod::CandidatesBplusData>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-sub-bplus-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingSubCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingSubCharged.cxx new file mode 100644 index 00000000000..4d12c3c0448 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingSubCharged.cxx @@ -0,0 +1,30 @@ +// 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. + +// jet matching subtracted charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingSub.cxx" + +using ChargedJetMatchingSub = JetMatchingSub, + soa::Join, + aod::ChargedJetsMatchedToChargedEventWiseSubtractedJets, + aod::ChargedEventWiseSubtractedJetsMatchedToChargedJets, + aod::JTrackSubs, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-matching-sub-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingSubD0Charged.cxx b/PWGJE/TableProducer/Matching/jetMatchingSubD0Charged.cxx new file mode 100644 index 00000000000..d07f5186d95 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingSubD0Charged.cxx @@ -0,0 +1,30 @@ +// 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. + +// jet matching subtracted D0 charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingSub.cxx" + +using D0ChargedJetMatchingSub = JetMatchingSub, + soa::Join, + aod::D0ChargedJetsMatchedToD0ChargedEventWiseSubtractedJets, + aod::D0ChargedEventWiseSubtractedJetsMatchedToD0ChargedJets, + aod::JTrackD0Subs, + aod::CandidatesD0Data>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-sub-d0-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingSubDielectronCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingSubDielectronCharged.cxx new file mode 100644 index 00000000000..94960e214d8 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingSubDielectronCharged.cxx @@ -0,0 +1,30 @@ +// 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. + +// jet matching subtracted Dielectron charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingSub.cxx" + +using DielectronChargedJetMatchingSub = JetMatchingSub, + soa::Join, + aod::DielectronChargedJetsMatchedToDielectronChargedEventWiseSubtractedJets, + aod::DielectronChargedEventWiseSubtractedJetsMatchedToDielectronChargedJets, + aod::JTrackDielectronSubs, + aod::CandidatesDielectronData>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-sub-dielectron-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingSubDplusCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingSubDplusCharged.cxx new file mode 100644 index 00000000000..181bd2a93a2 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingSubDplusCharged.cxx @@ -0,0 +1,30 @@ +// 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. + +// jet matching subtracted D+ charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingSub.cxx" + +using DplusChargedJetMatchingSub = JetMatchingSub, + soa::Join, + aod::DplusChargedJetsMatchedToDplusChargedEventWiseSubtractedJets, + aod::DplusChargedEventWiseSubtractedJetsMatchedToDplusChargedJets, + aod::JTrackDplusSubs, + aod::CandidatesDplusData>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-sub-dplus-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingSubLcCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingSubLcCharged.cxx new file mode 100644 index 00000000000..eabc5209fa8 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingSubLcCharged.cxx @@ -0,0 +1,30 @@ +// 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. + +// jet matching subtracted Lc charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingSub.cxx" + +using LcChargedJetMatchingSub = JetMatchingSub, + soa::Join, + aod::LcChargedJetsMatchedToLcChargedEventWiseSubtractedJets, + aod::LcChargedEventWiseSubtractedJetsMatchedToLcChargedJets, + aod::JTrackLcSubs, + aod::CandidatesLcData>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-sub-lc-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/derivedDataProducer.cxx b/PWGJE/TableProducer/derivedDataProducer.cxx new file mode 100644 index 00000000000..a946d93b997 --- /dev/null +++ b/PWGJE/TableProducer/derivedDataProducer.cxx @@ -0,0 +1,691 @@ +// 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. + +// task to produce a self contained data format for jet analyses from the full AO2D +// +/// \author Nima Zardoshti + +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "TDatabasePDG.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsVertexing/PVertexer.h" +#include "ReconstructionDataFormats/Vertex.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/Core/RecoDecay.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "PWGJE/DataModel/EMCALClusters.h" + +#include "EventFiltering/filterTables.h" +#include "EventFiltering/Zorro.h" + +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/EMCALMatchedCollisions.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetHFUtilities.h" +#include "PWGJE/Core/JetV0Utilities.h" +#include "PWGJE/Core/JetDQUtilities.h" + +#include "PWGHF/Utils/utilsBfieldCCDB.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct JetDerivedDataProducerTask { + struct : ProducesGroup { + Produces bcCountsTable; + Produces collisionCountsTable; + Produces jDummysTable; + Produces jBCsTable; + Produces jBCParentIndexTable; + Produces jCollisionsTable; + Produces jCollisionMcInfosTable; + Produces jCollisionsParentIndexTable; + Produces jCollisionsBunchCrossingIndexTable; + Produces jCollisionsEMCalLabelTable; + Produces jMcCollisionsLabelTable; + Produces jMcCollisionsTable; + Produces jMcCollisionsParentIndexTable; + Produces jTracksTable; + Produces jTracksExtraTable; + Produces jTracksEMCalTable; + Produces jTracksParentIndexTable; + Produces jMcTracksLabelTable; + Produces jMcParticlesTable; + Produces jParticlesParentIndexTable; + Produces jClustersTable; + Produces jClustersParentIndexTable; + Produces jClustersMatchedTracksTable; + Produces jMcClustersLabelTable; + Produces jD0CollisionIdsTable; + Produces jD0McCollisionIdsTable; + Produces jD0IdsTable; + Produces jD0ParticleIdsTable; + Produces jDplusCollisionIdsTable; + Produces jDplusMcCollisionIdsTable; + Produces jDplusIdsTable; + Produces jDplusParticleIdsTable; + Produces jLcCollisionIdsTable; + Produces jLcMcCollisionIdsTable; + Produces jLcIdsTable; + Produces jLcParticleIdsTable; + Produces jBplusCollisionIdsTable; + Produces jBplusMcCollisionIdsTable; + Produces jBplusIdsTable; + Produces jBplusParticleIdsTable; + Produces jV0IdsTable; + Produces jV0McCollisionsTable; + Produces jV0McCollisionIdsTable; + Produces jV0McsTable; + Produces jV0McIdsTable; + Produces jDielectronCollisionIdsTable; + Produces jDielectronIdsTable; + Produces jDielectronMcCollisionsTable; + Produces jDielectronMcCollisionIdsTable; + Produces JDielectronMcRCollDummysTable; + Produces jDielectronMcsTable; + Produces jDielectronMcIdsTable; + } products; + + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; + Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + Configurable dcaZMax{"dcaZMax", 0.2, "maximum DCAZ selection for tracks - only applied for reassociation"}; + + Configurable ccdbURL{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable includeTriggers{"includeTriggers", false, "fill the collision information with software trigger decisions"}; + Configurable includeHadronicRate{"includeHadronicRate", true, "fill the collision information with the hadronic rate"}; + + Preslice perClusterCells = aod::emcalclustercell::emcalclusterId; + Preslice perClusterTracks = aod::emcalclustercell::emcalclusterId; + Preslice perCollisionTrackIndices = aod::track_association::collisionId; + + std::map, int32_t> trackCollisionMapping; + Service ccdb; + o2::base::MatLayerCylSet* lut; + o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + Service pdgDatabase; + Zorro triggerDecider; + + ctpRateFetcher rateFetcher; + int runNumber; + float hadronicRate; + bool withCollisionAssociator; + void init(InitContext const&) + { + hadronicRate = -1.0; + if (doprocessTracksWithCollisionAssociator || includeHadronicRate || includeTriggers) { + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + runNumber = 0; + if (doprocessTracksWithCollisionAssociator) { + withCollisionAssociator = true; + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); + } else { + withCollisionAssociator = false; + } + } + } + + void processClearMaps(aod::Collisions const& collisions) + { + trackCollisionMapping.clear(); + if (!doprocessMcCollisionLabels) { + for (int i = 0; i < collisions.size(); i++) { + products.jCollisionMcInfosTable(-1.0, jetderiveddatautilities::JCollisionSubGeneratorId::none); // fill a dummy weights table if not MC + } + } + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processClearMaps, "clears all maps", true); + + void processBunchCrossings(soa::Join::iterator const& bc) + { + products.jBCsTable(bc.runNumber(), bc.globalBC(), bc.timestamp(), bc.alias_raw(), bc.selection_raw()); + products.jBCParentIndexTable(bc.globalIndex()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processBunchCrossings, "produces derived bunch crossing table", false); + + void processCollisions(soa::Join::iterator const& collision, soa::Join const&) + { + auto bc = collision.bc_as>(); + if (includeHadronicRate) { + if (runNumber != bc.runNumber()) { + runNumber = bc.runNumber(); + hadronicRate = rateFetcher.fetch(ccdb.service, bc.timestamp(), runNumber, "ZNC hadronic") * 0.001; + } + } + uint64_t triggerBit = 0; + if (includeTriggers) { + triggerDecider.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), jetderiveddatautilities::JTriggerMasks); + triggerBit = jetderiveddatautilities::setTriggerSelectionBit(triggerDecider.getTriggerOfInterestResults(bc.globalBC())); + } + products.jCollisionsTable(collision.posX(), collision.posY(), collision.posZ(), collision.multFT0C(), collision.centFT0C(), collision.centFT0CVariant1(), hadronicRate, collision.trackOccupancyInTimeRange(), jetderiveddatautilities::setEventSelectionBit(collision), collision.alias_raw(), triggerBit); // note change multFT0C to multFT0M when problems with multFT0A are fixed + products.jCollisionsParentIndexTable(collision.globalIndex()); + products.jCollisionsBunchCrossingIndexTable(collision.bcId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processCollisions, "produces derived collision tables", true); + + void processCollisionsWithoutCentralityAndMultiplicity(soa::Join::iterator const& collision, soa::Join const&) + { + uint64_t triggerBit = 0; + if (includeTriggers) { + auto bc = collision.bc_as>(); + triggerDecider.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), jetderiveddatautilities::JTriggerMasks); + triggerBit = jetderiveddatautilities::setTriggerSelectionBit(triggerDecider.getTriggerOfInterestResults(bc.globalBC())); + } + products.jCollisionsTable(collision.posX(), collision.posY(), collision.posZ(), -1.0, -1.0, -1.0, -1.0, -1, jetderiveddatautilities::setEventSelectionBit(collision), collision.alias_raw(), triggerBit); + products.jCollisionsParentIndexTable(collision.globalIndex()); + products.jCollisionsBunchCrossingIndexTable(collision.bcId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processCollisionsWithoutCentralityAndMultiplicity, "produces derived collision tables without centrality or multiplicity", false); + + void processCollisionsRun2(soa::Join::iterator const& collision) + { + products.jCollisionsTable(collision.posX(), collision.posY(), collision.posZ(), collision.multFT0C(), collision.centRun2V0M(), -1.0, -1.0, -1, jetderiveddatautilities::setEventSelectionBit(collision), collision.alias_raw(), 0); // note change multFT0C to multFT0M when problems with multFT0A are fixed + products.jCollisionsParentIndexTable(collision.globalIndex()); + products.jCollisionsBunchCrossingIndexTable(collision.bcId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processCollisionsRun2, "produces derived collision tables for Run 2 data", false); + + void processCollisionsALICE3(aod::Collision const& collision) + { + products.jCollisionsTable(collision.posX(), collision.posY(), collision.posZ(), -1.0, -1.0, -1.0, -1.0, -1, -1.0, 0, 0); + products.jCollisionsParentIndexTable(collision.globalIndex()); + products.jCollisionsBunchCrossingIndexTable(-1); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processCollisionsALICE3, "produces derived collision tables for ALICE 3 simulations", false); + + void processWithoutEMCalCollisionLabels(aod::Collision const&) + { + products.jCollisionsEMCalLabelTable(false, false); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processWithoutEMCalCollisionLabels, "produces dummy derived collision labels for EMCal", true); + + void processEMCalCollisionLabels(aod::EMCALMatchedCollision const& collision) + { + products.jCollisionsEMCalLabelTable(collision.ambiguous(), collision.isemcreadout()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processEMCalCollisionLabels, "produces derived collision labels for EMCal", false); + + void processMcCollisionLabels(soa::Join::iterator const& collision, aod::McCollisions const&) + { + if (collision.has_mcCollision()) { + products.jMcCollisionsLabelTable(collision.mcCollisionId()); + products.jCollisionMcInfosTable(collision.mcCollision().weight(), collision.mcCollision().getSubGeneratorId()); + } else { + products.jMcCollisionsLabelTable(-1); + products.jCollisionMcInfosTable(-1.0, jetderiveddatautilities::JCollisionSubGeneratorId::none); + } + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processMcCollisionLabels, "produces derived MC collision labels table", false); + + void processMcCollisions(aod::McCollision const& mcCollision) + { + products.jMcCollisionsTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.weight(), mcCollision.getSubGeneratorId(), 1, 1, 1.0, 1.0); + products.jMcCollisionsParentIndexTable(mcCollision.globalIndex()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processMcCollisions, "produces derived MC collision table", false); + + void processMcCollisionsWithXsection(soa::Join::iterator const& mcCollision) + { + products.jMcCollisionsTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.weight(), mcCollision.getSubGeneratorId(), mcCollision.accepted(), mcCollision.attempted(), mcCollision.xsectGen(), mcCollision.xsectErr()); + products.jMcCollisionsParentIndexTable(mcCollision.globalIndex()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processMcCollisionsWithXsection, "produces derived MC collision table with cross section information", false); + + void processTracks(soa::Join::iterator const& track, aod::Collisions const&) + { + products.jTracksTable(track.collisionId(), track.pt(), track.eta(), track.phi(), jetderiveddatautilities::setTrackSelectionBit(track, track.dcaZ(), dcaZMax)); + auto trackParCov = getTrackParCov(track); + auto xyzTrack = trackParCov.getXYZGlo(); + float sigmaDCAXYZ2; + float dcaXYZ = getDcaXYZ(track, &sigmaDCAXYZ2); + float dcaX = -99.0; + float dcaY = -99.0; + if (track.collisionId() >= 0) { + auto const& collision = track.collision_as(); + dcaX = xyzTrack.X() - collision.posX(); + dcaY = xyzTrack.Y() - collision.posY(); + } + + products.jTracksExtraTable(dcaX, dcaY, track.dcaZ(), track.dcaXY(), dcaXYZ, std::sqrt(track.sigmaDcaZ2()), std::sqrt(track.sigmaDcaXY2()), std::sqrt(sigmaDCAXYZ2), track.sigma1Pt()); // why is this getSigmaZY + products.jTracksParentIndexTable(track.globalIndex()); + trackCollisionMapping[{track.globalIndex(), track.collisionId()}] = products.jTracksTable.lastIndex(); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processTracks, "produces derived track table", true); + + void processTracksWithCollisionAssociator(aod::Collisions const& collisions, soa::Join const&, soa::Join const&, aod::TrackAssoc const& assocCollisions) + { + runNumber = 0; + for (auto const& collision : collisions) { + auto collisionTrackIndices = assocCollisions.sliceBy(perCollisionTrackIndices, collision.globalIndex()); + for (auto const& collisionTrackIndex : collisionTrackIndices) { + auto track = collisionTrackIndex.track_as>(); + auto trackParCov = getTrackParCov(track); + if (track.collisionId() == collision.globalIndex()) { + products.jTracksTable(collision.globalIndex(), track.pt(), track.eta(), track.phi(), jetderiveddatautilities::setTrackSelectionBit(track, track.dcaZ(), dcaZMax)); + products.jTracksParentIndexTable(track.globalIndex()); + auto xyzTrack = trackParCov.getXYZGlo(); + float sigmaDCAXYZ2; + float dcaXYZ = getDcaXYZ(track, &sigmaDCAXYZ2); + products.jTracksExtraTable(xyzTrack.X() - collision.posX(), xyzTrack.Y() - collision.posY(), track.dcaZ(), track.dcaXY(), dcaXYZ, std::sqrt(track.sigmaDcaZ2()), std::sqrt(track.sigmaDcaXY2()), std::sqrt(sigmaDCAXYZ2), track.sigma1Pt()); // why is this getSigmaZY + } else { + auto bc = collision.bc_as>(); + initCCDB(bc, runNumber, ccdb, doprocessCollisionsRun2 ? ccdbPathGrp : ccdbPathGrpMag, lut, doprocessCollisionsRun2); + o2::dataformats::DCA dcaCovInfo; + dcaCovInfo.set(-999., -999., -999., -999., -999.); + o2::dataformats::VertexBase collisionInfo; + collisionInfo.setPos({collision.posX(), collision.posY(), collision.posZ()}); + collisionInfo.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + o2::base::Propagator::Instance()->propagateToDCABxByBz(collisionInfo, trackParCov, 2.f, noMatCorr, &dcaCovInfo); + products.jTracksTable(collision.globalIndex(), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), jetderiveddatautilities::setTrackSelectionBit(track, dcaCovInfo.getZ(), dcaZMax)); // only qualitytracksWDCA are a reliable selection + products.jTracksParentIndexTable(track.globalIndex()); + auto xyzTrack = trackParCov.getXYZGlo(); + float dcaXY = dcaCovInfo.getY(); + float dcaZ = dcaCovInfo.getZ(); + float dcaXYZ = std::sqrt(dcaXY * dcaXY + dcaZ * dcaZ); + float covYY = dcaCovInfo.getSigmaY2(); + float covZZ = dcaCovInfo.getSigmaZ2(); + float covYZ = dcaCovInfo.getSigmaYZ(); + float sigmaDCAXYZ; + if (dcaXYZ < o2::constants::math::Almost0) { + sigmaDCAXYZ = o2::constants::math::VeryBig; // Protection against division by zero + } else { + sigmaDCAXYZ = covYY * (2.f * dcaXY / dcaXYZ) * (2.f * dcaXY / dcaXYZ) + covZZ * (2.f * dcaZ / dcaXYZ) * (2.f * dcaZ / dcaXYZ) + 2.f * covYZ * (2.f * dcaXY / dcaXYZ) * (2.f * dcaZ / dcaXYZ); + } + products.jTracksExtraTable(xyzTrack.X() - collision.posX(), xyzTrack.Y() - collision.posY(), dcaZ, dcaXY, dcaXYZ, std::sqrt(covZZ), std::sqrt(covYY), std::sqrt(sigmaDCAXYZ), std::sqrt(trackParCov.getSigma1Pt2())); + } + trackCollisionMapping[{track.globalIndex(), collision.globalIndex()}] = products.jTracksTable.lastIndex(); + } + } + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processTracksWithCollisionAssociator, "produces derived track table taking into account track-to-collision associations", false); + + void processTracksRun2(soa::Join::iterator const& track) + { + // TracksDCACov table is not yet available for Run 2 converted data. Remove this process function and use only processTracks when that becomes available. + products.jTracksTable(track.collisionId(), track.pt(), track.eta(), track.phi(), jetderiveddatautilities::setTrackSelectionBit(track, track.dcaZ(), dcaZMax)); + float sigmaDCAXYZ2 = 0.0; + float dcaXYZ = getDcaXYZ(track, &sigmaDCAXYZ2); + float dcaX = -99.0; + float dcaY = -99.0; + + products.jTracksExtraTable(dcaX, dcaY, track.dcaZ(), track.dcaXY(), dcaXYZ, std::sqrt(1.), std::sqrt(1.), std::sqrt(sigmaDCAXYZ2), track.sigma1Pt()); // dummy values - will be fixed when TracksDCACov table is available for Run 2 + products.jTracksParentIndexTable(track.globalIndex()); + trackCollisionMapping[{track.globalIndex(), track.collisionId()}] = products.jTracksTable.lastIndex(); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processTracksRun2, "produces derived track table for Run2 AO2Ds", false); + + void processMcTrackLabels(soa::Join::iterator const& track) + { + if (track.has_mcParticle()) { + products.jMcTracksLabelTable(track.mcParticleId()); + } else { + products.jMcTracksLabelTable(-1); + } + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processMcTrackLabels, "produces derived track labels table", false); + + void processMcTrackLabelsWithCollisionAssociator(aod::Collisions const& collisions, soa::Join const&, aod::TrackAssoc const& assocCollisions) + { + for (auto const& collision : collisions) { + auto collisionTrackIndices = assocCollisions.sliceBy(perCollisionTrackIndices, collision.globalIndex()); + for (auto const& collisionTrackIndex : collisionTrackIndices) { + auto track = collisionTrackIndex.track_as>(); + if (track.collisionId() == collision.globalIndex() && track.has_mcParticle()) { + products.jMcTracksLabelTable(track.mcParticleId()); + } else { + products.jMcTracksLabelTable(-1); + } + } + } + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processMcTrackLabelsWithCollisionAssociator, "produces derived track labels table taking into account track-to-collision associations", false); + + void processParticles(aod::McParticle const& particle) + { + std::vector mothersId; + if (particle.has_mothers()) { + auto mothersIdTemps = particle.mothersIds(); + for (auto mothersIdTemp : mothersIdTemps) { + mothersId.push_back(mothersIdTemp); + } + } + int daughtersId[2] = {-1, -1}; + auto i = 0; + if (particle.has_daughters()) { + for (auto daughterId : particle.daughtersIds()) { + if (i > 1) { + break; + } + daughtersId[i] = daughterId; + i++; + } + } + products.jMcParticlesTable(particle.mcCollisionId(), particle.pt(), particle.eta(), particle.phi(), particle.y(), particle.e(), particle.pdgCode(), particle.getGenStatusCode(), particle.getHepMCStatusCode(), particle.isPhysicalPrimary(), mothersId, daughtersId); + products.jParticlesParentIndexTable(particle.globalIndex()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processParticles, "produces derived parrticle table", false); + + void processClusters(aod::Collision const&, aod::EMCALClusters const& clusters, aod::EMCALClusterCells const& cells, aod::Calos const&, aod::EMCALMatchedTracks const& matchedTracks, soa::Join const&) + { + + for (auto cluster : clusters) { + + auto const clusterCells = cells.sliceBy(perClusterCells, cluster.globalIndex()); + + float leadingCellEnergy = -1.0; + float subleadingCellEnergy = -1.0; + float cellAmplitude = -1.0; + int leadingCellNumber = -1; + int subleadingCellNumber = -1; + int cellNumber = -1; + for (auto const& clutserCell : clusterCells) { + cellAmplitude = clutserCell.calo().amplitude(); + cellNumber = clutserCell.calo().cellNumber(); + if (cellAmplitude > subleadingCellEnergy) { + subleadingCellEnergy = cellAmplitude; + subleadingCellNumber = cellNumber; + } + if (subleadingCellEnergy > leadingCellEnergy) { + std::swap(leadingCellEnergy, subleadingCellEnergy); + std::swap(leadingCellNumber, subleadingCellNumber); + } + } + + products.jClustersTable(cluster.collisionId(), cluster.id(), cluster.energy(), cluster.coreEnergy(), cluster.rawEnergy(), cluster.eta(), cluster.phi(), cluster.m02(), cluster.m20(), cluster.nCells(), cluster.time(), cluster.isExotic(), cluster.distanceToBadChannel(), cluster.nlm(), cluster.definition(), leadingCellEnergy, subleadingCellEnergy, leadingCellNumber, subleadingCellNumber); + products.jClustersParentIndexTable(cluster.globalIndex()); + + auto const clusterTracks = matchedTracks.sliceBy(perClusterTracks, cluster.globalIndex()); + std::vector clusterTrackIDs; + for (const auto& clusterTrack : clusterTracks) { + auto JClusterID = trackCollisionMapping.find({clusterTrack.trackId(), cluster.collisionId()}); // does EMCal use its own associator? + clusterTrackIDs.push_back(JClusterID->second); + auto emcTrack = clusterTrack.track_as>(); + products.jTracksEMCalTable(JClusterID->second, emcTrack.trackEtaEmcal(), emcTrack.trackPhiEmcal()); + } + products.jClustersMatchedTracksTable(clusterTrackIDs); + } + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processClusters, "produces derived cluster tables", false); + + void processMcClusterLabels(aod::EMCALMCCluster const& cluster) + { + std::vector particleIds; + for (auto particleId : cluster.mcParticleIds()) { + particleIds.push_back(particleId); + } + std::vector amplitudeA; + auto amplitudeASpan = cluster.amplitudeA(); + std::copy(amplitudeASpan.begin(), amplitudeASpan.end(), std::back_inserter(amplitudeA)); + products.jMcClustersLabelTable(particleIds, amplitudeA); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processMcClusterLabels, "produces derived cluster particle label table", false); + + void processD0Collisions(aod::HfD0CollIds::iterator const& D0Collision) + { + products.jD0CollisionIdsTable(D0Collision.collisionId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processD0Collisions, "produces derived index for D0 collisions", false); + + void processD0McCollisions(aod::HfD0McCollIds::iterator const& D0McCollision) + { + products.jD0McCollisionIdsTable(D0McCollision.mcCollisionId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processD0McCollisions, "produces derived index for D0 MC collisions", false); + + void processD0(aod::HfD0Ids::iterator const& D0, aod::Tracks const&) + { + auto JProng0ID = trackCollisionMapping.find({D0.prong0Id(), D0.prong0_as().collisionId()}); + auto JProng1ID = trackCollisionMapping.find({D0.prong1Id(), D0.prong1_as().collisionId()}); + if (withCollisionAssociator) { + JProng0ID = trackCollisionMapping.find({D0.prong0Id(), D0.collisionId()}); + JProng1ID = trackCollisionMapping.find({D0.prong1Id(), D0.collisionId()}); + } + products.jD0IdsTable(D0.collisionId(), JProng0ID->second, JProng1ID->second); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processD0, "produces derived index for D0 candidates", false); + + void processD0MC(aod::HfD0PIds::iterator const& D0) + { + products.jD0ParticleIdsTable(D0.mcCollisionId(), D0.mcParticleId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processD0MC, "produces derived index for D0 particles", false); + + void processDplusCollisions(aod::HfDplusCollIds::iterator const& DplusCollision) + { + products.jDplusCollisionIdsTable(DplusCollision.collisionId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processDplusCollisions, "produces derived index for Dplus collisions", false); + + void processDplusMcCollisions(aod::HfDplusMcCollIds::iterator const& DplusMcCollision) + { + products.jDplusMcCollisionIdsTable(DplusMcCollision.mcCollisionId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processDplusMcCollisions, "produces derived index for Dplus MC collisions", false); + + void processDplus(aod::HfDplusIds::iterator const& Dplus, aod::Tracks const&) + { + auto JProng0ID = trackCollisionMapping.find({Dplus.prong0Id(), Dplus.prong0_as().collisionId()}); + auto JProng1ID = trackCollisionMapping.find({Dplus.prong1Id(), Dplus.prong1_as().collisionId()}); + auto JProng2ID = trackCollisionMapping.find({Dplus.prong2Id(), Dplus.prong2_as().collisionId()}); + if (withCollisionAssociator) { + JProng0ID = trackCollisionMapping.find({Dplus.prong0Id(), Dplus.collisionId()}); + JProng1ID = trackCollisionMapping.find({Dplus.prong1Id(), Dplus.collisionId()}); + JProng2ID = trackCollisionMapping.find({Dplus.prong2Id(), Dplus.collisionId()}); + } + products.jDplusIdsTable(Dplus.collisionId(), JProng0ID->second, JProng1ID->second, JProng2ID->second); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processDplus, "produces derived index for Dplus candidates", false); + + void processDplusMC(aod::HfDplusPIds::iterator const& Dplus) + { + products.jDplusParticleIdsTable(Dplus.mcCollisionId(), Dplus.mcParticleId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processDplusMC, "produces derived index for Dplus particles", false); + + void processLcCollisions(aod::HfLcCollIds::iterator const& LcCollision) + { + products.jLcCollisionIdsTable(LcCollision.collisionId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processLcCollisions, "produces derived index for Lc collisions", false); + + void processLcMcCollisions(aod::HfLcMcCollIds::iterator const& LcMcCollision) + { + products.jLcMcCollisionIdsTable(LcMcCollision.mcCollisionId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processLcMcCollisions, "produces derived index for Lc MC collisions", false); + + void processLc(aod::HfLcIds::iterator const& Lc, aod::Tracks const&) + { + auto JProng0ID = trackCollisionMapping.find({Lc.prong0Id(), Lc.prong0_as().collisionId()}); + auto JProng1ID = trackCollisionMapping.find({Lc.prong1Id(), Lc.prong1_as().collisionId()}); + auto JProng2ID = trackCollisionMapping.find({Lc.prong2Id(), Lc.prong2_as().collisionId()}); + if (withCollisionAssociator) { + JProng0ID = trackCollisionMapping.find({Lc.prong0Id(), Lc.collisionId()}); + JProng1ID = trackCollisionMapping.find({Lc.prong1Id(), Lc.collisionId()}); + JProng2ID = trackCollisionMapping.find({Lc.prong2Id(), Lc.collisionId()}); + } + products.jLcIdsTable(Lc.collisionId(), JProng0ID->second, JProng1ID->second, JProng2ID->second); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processLc, "produces derived index for Lc candidates", false); + + void processLcMC(aod::HfLcPIds::iterator const& Lc) + { + products.jLcParticleIdsTable(Lc.mcCollisionId(), Lc.mcParticleId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processLcMC, "produces derived index for Lc particles", false); + + void processBplusCollisions(aod::HfBplusCollIds::iterator const& BplusCollision) + { + products.jBplusCollisionIdsTable(BplusCollision.collisionId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processBplusCollisions, "produces derived index for Bplus collisions", false); + + void processBplusMcCollisions(aod::HfBplusMcCollIds::iterator const& BplusMcCollision) + { + products.jBplusMcCollisionIdsTable(BplusMcCollision.mcCollisionId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processBplusMcCollisions, "produces derived index for Bplus MC collisions", false); + + void processBplus(aod::HfBplusIds::iterator const& Bplus, aod::Tracks const&) + { + auto JProng0ID = trackCollisionMapping.find({Bplus.prong0Id(), Bplus.prong0_as().collisionId()}); + auto JProng1ID = trackCollisionMapping.find({Bplus.prong1Id(), Bplus.prong1_as().collisionId()}); + auto JProng2ID = trackCollisionMapping.find({Bplus.prong2Id(), Bplus.prong2_as().collisionId()}); + if (withCollisionAssociator) { + JProng0ID = trackCollisionMapping.find({Bplus.prong0Id(), Bplus.collisionId()}); + JProng1ID = trackCollisionMapping.find({Bplus.prong1Id(), Bplus.collisionId()}); + JProng2ID = trackCollisionMapping.find({Bplus.prong2Id(), Bplus.collisionId()}); + } + products.jBplusIdsTable(Bplus.collisionId(), JProng0ID->second, JProng1ID->second, JProng2ID->second); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processBplus, "produces derived index for Bplus candidates", false); + + void processBplusMC(aod::HfBplusPIds::iterator const& Bplus) + { + products.jBplusParticleIdsTable(Bplus.mcCollisionId(), Bplus.mcParticleId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processBplusMC, "produces derived index for Bplus particles", false); + + void processV0(aod::V0Indices::iterator const& V0, aod::Tracks const&) + { + auto JPosTrackID = trackCollisionMapping.find({V0.posTrackId(), V0.posTrack_as().collisionId()}); + auto JNegTrackID = trackCollisionMapping.find({V0.negTrackId(), V0.negTrack_as().collisionId()}); + if (withCollisionAssociator) { + JPosTrackID = trackCollisionMapping.find({V0.posTrackId(), V0.collisionId()}); + JNegTrackID = trackCollisionMapping.find({V0.negTrackId(), V0.collisionId()}); + } + products.jV0IdsTable(V0.collisionId(), JPosTrackID->second, JNegTrackID->second); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processV0, "produces derived index for V0 candidates", false); + + void processV0MC(aod::McCollision const& mcCollision, aod::McParticles const& particles) + { // can loop over McV0Labels tables if we want to only store matched V0Particles + bool filledV0McCollisionTable = false; + for (auto const& particle : particles) { + if (jetv0utilities::isV0Particle(particles, particle)) { + if (!filledV0McCollisionTable) { + products.jV0McCollisionsTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ()); + products.jV0McCollisionIdsTable(mcCollision.globalIndex()); + filledV0McCollisionTable = true; + } + std::vector mothersId; + if (particle.has_mothers()) { + auto mothersIdTemps = particle.mothersIds(); + for (auto mothersIdTemp : mothersIdTemps) { + mothersId.push_back(mothersIdTemp); + } + } + int daughtersId[2] = {-1, -1}; + auto i = 0; + if (particle.has_daughters()) { + for (auto daughterId : particle.daughtersIds()) { + if (i > 1) { + break; + } + daughtersId[i] = daughterId; + i++; + } + } + auto pdgParticle = pdgDatabase->GetParticle(particle.pdgCode()); + products.jV0McsTable(products.jV0McCollisionsTable.lastIndex(), particle.pt(), particle.eta(), particle.phi(), particle.y(), particle.e(), pdgParticle->Mass(), particle.pdgCode(), particle.getGenStatusCode(), particle.getHepMCStatusCode(), particle.isPhysicalPrimary(), jetv0utilities::setV0ParticleDecayBit(particles, particle)); + products.jV0McIdsTable(mcCollision.globalIndex(), particle.globalIndex(), mothersId, daughtersId); + } + } + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processV0MC, "produces V0 particles", false); + + void processDielectronCollisions(aod::ReducedEventsInfo::iterator const& DielectronCollision) + { + products.jDielectronCollisionIdsTable(DielectronCollision.collisionId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processDielectronCollisions, "produces derived index for Dielectron collisions", false); + + void processDielectron(aod::DielectronInfo const& Dielectron, aod::Tracks const&) + { + auto JProng0ID = trackCollisionMapping.find({Dielectron.prong0Id(), Dielectron.prong0_as().collisionId()}); + auto JProng1ID = trackCollisionMapping.find({Dielectron.prong1Id(), Dielectron.prong1_as().collisionId()}); + if (withCollisionAssociator) { + JProng0ID = trackCollisionMapping.find({Dielectron.prong0Id(), Dielectron.collisionId()}); + JProng1ID = trackCollisionMapping.find({Dielectron.prong1Id(), Dielectron.collisionId()}); + } + products.jDielectronIdsTable(Dielectron.collisionId(), JProng0ID->second, JProng1ID->second); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processDielectron, "produces derived index for Dielectron candidates", false); + + void processDielectronMc(aod::McCollision const& mcCollision, aod::McParticles const& particles) + { + bool filledDielectronMcCollisionTable = false; + for (auto const& particle : particles) { + if (jetdqutilities::isDielectronParticle(particles, particle)) { + if (!filledDielectronMcCollisionTable) { + products.jDielectronMcCollisionsTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ()); + products.jDielectronMcCollisionIdsTable(mcCollision.globalIndex()); + filledDielectronMcCollisionTable = true; + } + std::vector mothersId; + if (particle.has_mothers()) { + auto mothersIdTemps = particle.mothersIds(); + for (auto mothersIdTemp : mothersIdTemps) { + mothersId.push_back(mothersIdTemp); + } + } + int daughtersId[2] = {-1, -1}; + auto i = 0; + if (particle.has_daughters()) { + for (auto daughterId : particle.daughtersIds()) { + if (i > 1) { + break; + } + daughtersId[i] = daughterId; + i++; + } + } + auto pdgParticle = pdgDatabase->GetParticle(particle.pdgCode()); + products.jDielectronMcsTable(products.jDielectronMcCollisionsTable.lastIndex(), particle.pt(), particle.eta(), particle.phi(), particle.y(), particle.e(), pdgParticle->Mass(), particle.pdgCode(), particle.getGenStatusCode(), particle.getHepMCStatusCode(), particle.isPhysicalPrimary(), jetdqutilities::setDielectronParticleDecayBit(particles, particle), RecoDecay::getCharmHadronOrigin(particles, particle, false)); // Todo: should the last thing be false? + products.jDielectronMcIdsTable(mcCollision.globalIndex(), particle.globalIndex(), mothersId, daughtersId); + products.JDielectronMcRCollDummysTable(false); + } + } + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processDielectronMc, "produces Dielectron mccollisions and particles", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"jet-deriveddata-producer"})}; +} diff --git a/PWGJE/TableProducer/derivedDataSelector.cxx b/PWGJE/TableProducer/derivedDataSelector.cxx new file mode 100644 index 00000000000..f4336b228a2 --- /dev/null +++ b/PWGJE/TableProducer/derivedDataSelector.cxx @@ -0,0 +1,345 @@ +// 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 jetderiveddataselector.cxx +/// \brief Task to store decision of which events to skim for producing jet framework tables (aod::JetCollisions, aod::JetTracks, aod::JetClusters, ...) +/// while adjusting indices accordingly +/// +/// \author Nima Zardoshti +/// \author Jochen Klein + +#include +#include +#include +#include + +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/runDataProcessing.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetReducedDataSelector.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct JetDerivedDataSelector { + + Produces collisionSelectionsTable; + Produces mcCollisionSelectionsTable; + + struct : ConfigurableGroup { + Configurable thresholdChargedJetPtMin{"thresholdChargedJetPtMin", 0.0, "Minimum charged jet pt to accept event"}; + Configurable thresholdChargedEventWiseSubtractedJetPtMin{"thresholdChargedEventWiseSubtractedJetPtMin", 0.0, "Minimum charged event-wise subtracted jet pt to accept event"}; + Configurable thresholdChargedMCPJetPtMin{"thresholdChargedMCPJetPtMin", 0.0, "Minimum charged mcp jet pt to accept event"}; + Configurable thresholdNeutralJetPtMin{"thresholdNeutralJetPtMin", 0.0, "Minimum neutral jet pt to accept event"}; + Configurable thresholdNeutralMCPJetPtMin{"thresholdNeutralMCPJetPtMin", 0.0, "Minimum neutal mcp jet pt to accept event"}; + Configurable thresholdFullJetPtMin{"thresholdFullJetPtMin", 0.0, "Minimum full jet pt to accept event"}; + Configurable thresholdFullMCPJetPtMin{"thresholdFullMCPJetPtMin", 0.0, "Minimum full mcp jet pt to accept event"}; + Configurable thresholdChargedD0JetPtMin{"thresholdChargedD0JetPtMin", 0.0, "Minimum charged D0 jet pt to accept event"}; + Configurable thresholdChargedEventWiseSubtractedD0JetPtMin{"thresholdChargedEventWiseSubtractedD0JetPtMin", 0.0, "Minimum charged event-wise subtracted D0 jet pt to accept event"}; + Configurable thresholdChargedD0MCPJetPtMin{"thresholdChargedD0MCPJetPtMin", 0.0, "Minimum charged D0 mcp jet pt to accept event"}; + Configurable thresholdChargedDplusJetPtMin{"thresholdChargedDplusJetPtMin", 0.0, "Minimum charged Dplus jet pt to accept event"}; + Configurable thresholdChargedEventWiseSubtractedDplusJetPtMin{"thresholdChargedEventWiseSubtractedDplusJetPtMin", 0.0, "Minimum charged event-wise subtracted Dplus jet pt to accept event"}; + Configurable thresholdChargedDplusMCPJetPtMin{"thresholdChargedDplusMCPJetPtMin", 0.0, "Minimum charged Dplus mcp jet pt to accept event"}; + Configurable thresholdChargedLcJetPtMin{"thresholdChargedLcJetPtMin", 0.0, "Minimum charged Lc jet pt to accept event"}; + Configurable thresholdChargedEventWiseSubtractedLcJetPtMin{"thresholdChargedEventWiseSubtractedLcJetPtMin", 0.0, "Minimum charged event-wise subtracted Lc jet pt to accept event"}; + Configurable thresholdChargedLcMCPJetPtMin{"thresholdChargedLcMCPJetPtMin", 0.0, "Minimum charged Lc mcp jet pt to accept event"}; + Configurable thresholdChargedBplusJetPtMin{"thresholdChargedBplusJetPtMin", 0.0, "Minimum charged Bplus jet pt to accept event"}; + Configurable thresholdChargedEventWiseSubtractedBplusJetPtMin{"thresholdChargedEventWiseSubtractedBplusJetPtMin", 0.0, "Minimum charged event-wise subtracted Bplus jet pt to accept event"}; + Configurable thresholdChargedBplusMCPJetPtMin{"thresholdChargedBplusMCPJetPtMin", 0.0, "Minimum charged Bplus mcp jet pt to accept event"}; + Configurable thresholdChargedDielectronJetPtMin{"thresholdChargedDielectronJetPtMin", 0.0, "Minimum charged Dielectron jet pt to accept event"}; + Configurable thresholdChargedEventWiseSubtractedDielectronJetPtMin{"thresholdChargedEventWiseSubtractedDielectronJetPtMin", 0.0, "Minimum charged event-wise subtracted Dielectron jet pt to accept event"}; + Configurable thresholdChargedDielectronMCPJetPtMin{"thresholdChargedDielectronMCPJetPtMin", 0.0, "Minimum charged Dielectron mcp jet pt to accept event"}; + Configurable thresholdTriggerTrackPtMin{"thresholdTriggerTrackPtMin", 0.0, "Minimum trigger track pt to accept event"}; + Configurable thresholdClusterEnergyMin{"thresholdClusterEnergyMin", 0.0, "Minimum cluster energy to accept event"}; + Configurable downscaleFactor{"downscaleFactor", 1, "random downscale of selected events"}; + + Configurable vertexZCut{"vertexZCut", 10.0, "z-vertex cut on event"}; + Configurable centralityMin{"centralityMin", -999.0, "minimum centrality"}; + Configurable centralityMax{"centralityMax", 999.0, "maximum centrality"}; + Configurable trackOccupancyInTimeRangeMax{"trackOccupancyInTimeRangeMax", 999999, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable performTrackSelection{"performTrackSelection", true, "only save tracks that pass one of the track selections"}; + Configurable trackPtSelectionMin{"trackPtSelectionMin", 0.15, "only save tracks that have a pT larger than this pT"}; + Configurable trackEtaSelectionMax{"trackEtaSelectionMax", 0.9, "only save tracks that have an eta smaller than this eta"}; + + Configurable triggerMasks{"triggerMasks", "", "possible JE Trigger masks: fJetChLowPt,fJetChHighPt,fTrackLowPt,fTrackHighPt,fJetD0ChLowPt,fJetD0ChHighPt,fJetLcChLowPt,fJetLcChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt,fJetNeutralHighPt,fJetNeutralLowPt,fGammaVeryHighPtEMCAL,fGammaVeryHighPtDCAL,fGammaHighPtEMCAL,fGammaHighPtDCAL,fGammaLowPtEMCAL,fGammaLowPtDCAL,fGammaVeryLowPtEMCAL,fGammaVeryLowPtDCAL"}; + } config; + + std::vector collisionFlag; + std::vector McCollisionFlag; + + TRandom3 randomNumber; + + std::vector triggerMaskBits; + void init(InitContext&) + { + randomNumber.SetSeed(0); + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(config.triggerMasks); + } + + PresliceUnsorted> CollisionsPerMcCollision = aod::jmccollisionlb::mcCollisionId; + + void processSetupCollisions(aod::JCollisions const& collisions) + { + collisionFlag.clear(); + collisionFlag.resize(collisions.size(), false); + } + + void processSetupMcCollisions(aod::JMcCollisions const& mcCollisions) + { + McCollisionFlag.clear(); + McCollisionFlag.resize(mcCollisions.size(), false); + } + + void processSelectMcCollisionsPerCollision(aod::JMcCollisions const& mcCollisions, soa::Join const& collisions) + { + for (auto mcCollision : mcCollisions) { + const auto collisionsPerMcCollision = collisions.sliceBy(CollisionsPerMcCollision, mcCollision.globalIndex()); + for (auto collision : collisionsPerMcCollision) { + if (collisionFlag[collision.globalIndex()]) { + McCollisionFlag[mcCollision.globalIndex()] = true; + } + } + } + } + + void processSelectCollisionsPerMcCollision(soa::Join::iterator const& collision) + { + if (McCollisionFlag[collision.mcCollisionId()]) { + collisionFlag[collision.globalIndex()] = true; + } + } + + void processSetupAllCollisionsWithDownscaling(aod::JCollisions const& collisions) + { + collisionFlag.clear(); + collisionFlag.resize(collisions.size(), false); + for (const auto& collision : collisions) { + if (randomNumber.Integer(config.downscaleFactor) == 0) { + collisionFlag[collision.globalIndex()] = true; + } + } + } + + void processSetupAllMcCollisionsWithDownscaling(aod::JMcCollisions const& mcCollisions) + { + McCollisionFlag.clear(); + McCollisionFlag.resize(mcCollisions.size(), false); + for (const auto& mcCollision : mcCollisions) { + if (randomNumber.Integer(config.downscaleFactor) == 0) { + McCollisionFlag[mcCollision.globalIndex()] = true; + } + } + } + + template + void processDoDownscaling(T const& collisions) + { + for (const auto& collision : collisions) { + if constexpr (std::is_same_v, aod::JCollisions>) { + if (collisionFlag[collision.globalIndex()] && randomNumber.Integer(config.downscaleFactor) != 0) { + collisionFlag[collision.globalIndex()] = false; + } + } + if constexpr (std::is_same_v, aod::JMcCollisions>) { + if (McCollisionFlag[collision.globalIndex()] && randomNumber.Integer(config.downscaleFactor) != 0) { + McCollisionFlag[collision.globalIndex()] = false; + } + } + } + } + + void processSetupEventTriggering(aod::JCollision const& collision) + { + if (jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + collisionFlag[collision.globalIndex()] = true; + } + } + + void processDoCollisionSelections(aod::JCollision const& collision) + { // can also add event selection like sel8 but goes a little against the derived data idea + if (collision.centrality() < config.centralityMin || collision.centrality() >= config.centralityMax || collision.trackOccupancyInTimeRange() > config.trackOccupancyInTimeRangeMax || std::abs(collision.posZ()) > config.vertexZCut) { + collisionFlag[collision.globalIndex()] = false; + } + } + + template + void processSelectionObjects(T& selectionObjects) + { + float selectionObjectPtMin = 0.0; + if constexpr (std::is_same_v, aod::ChargedJets> || std::is_same_v, aod::ChargedMCDetectorLevelJets>) { + selectionObjectPtMin = config.thresholdChargedJetPtMin; + } else if constexpr (std::is_same_v, aod::ChargedEventWiseSubtractedJets> || std::is_same_v, aod::ChargedMCDetectorLevelEventWiseSubtractedJets>) { + selectionObjectPtMin = config.thresholdChargedEventWiseSubtractedJetPtMin; + } else if constexpr (std::is_same_v, aod::ChargedMCParticleLevelJets>) { + selectionObjectPtMin = config.thresholdChargedMCPJetPtMin; + } else if constexpr (std::is_same_v, aod::NeutralJets> || std::is_same_v, aod::NeutralMCDetectorLevelJets>) { + selectionObjectPtMin = config.thresholdNeutralJetPtMin; + } else if constexpr (std::is_same_v, aod::NeutralMCParticleLevelJets>) { + selectionObjectPtMin = config.thresholdNeutralMCPJetPtMin; + } else if constexpr (std::is_same_v, aod::FullJets> || std::is_same_v, aod::FullMCDetectorLevelJets>) { + selectionObjectPtMin = config.thresholdFullJetPtMin; + } else if constexpr (std::is_same_v, aod::FullMCParticleLevelJets>) { + selectionObjectPtMin = config.thresholdFullMCPJetPtMin; + } else if constexpr (std::is_same_v, aod::D0ChargedJets> || std::is_same_v, aod::D0ChargedMCDetectorLevelJets>) { + selectionObjectPtMin = config.thresholdChargedD0JetPtMin; + } else if constexpr (std::is_same_v, aod::D0ChargedEventWiseSubtractedJets> || std::is_same_v, aod::D0ChargedMCDetectorLevelEventWiseSubtractedJets>) { + selectionObjectPtMin = config.thresholdChargedEventWiseSubtractedD0JetPtMin; + } else if constexpr (std::is_same_v, aod::D0ChargedMCParticleLevelJets>) { + selectionObjectPtMin = config.thresholdChargedD0MCPJetPtMin; + } else if constexpr (std::is_same_v, aod::DplusChargedJets> || std::is_same_v, aod::DplusChargedMCDetectorLevelJets>) { + selectionObjectPtMin = config.thresholdChargedDplusJetPtMin; + } else if constexpr (std::is_same_v, aod::DplusChargedEventWiseSubtractedJets> || std::is_same_v, aod::DplusChargedMCDetectorLevelEventWiseSubtractedJets>) { + selectionObjectPtMin = config.thresholdChargedEventWiseSubtractedDplusJetPtMin; + } else if constexpr (std::is_same_v, aod::DplusChargedMCParticleLevelJets>) { + selectionObjectPtMin = config.thresholdChargedDplusMCPJetPtMin; + } else if constexpr (std::is_same_v, aod::LcChargedJets> || std::is_same_v, aod::LcChargedMCDetectorLevelJets>) { + selectionObjectPtMin = config.thresholdChargedLcJetPtMin; + } else if constexpr (std::is_same_v, aod::LcChargedEventWiseSubtractedJets> || std::is_same_v, aod::LcChargedMCDetectorLevelEventWiseSubtractedJets>) { + selectionObjectPtMin = config.thresholdChargedEventWiseSubtractedLcJetPtMin; + } else if constexpr (std::is_same_v, aod::LcChargedMCParticleLevelJets>) { + selectionObjectPtMin = config.thresholdChargedLcMCPJetPtMin; + } else if constexpr (std::is_same_v, aod::BplusChargedJets> || std::is_same_v, aod::BplusChargedMCDetectorLevelJets>) { + selectionObjectPtMin = config.thresholdChargedBplusJetPtMin; + } else if constexpr (std::is_same_v, aod::BplusChargedEventWiseSubtractedJets> || std::is_same_v, aod::BplusChargedMCDetectorLevelEventWiseSubtractedJets>) { + selectionObjectPtMin = config.thresholdChargedEventWiseSubtractedBplusJetPtMin; + } else if constexpr (std::is_same_v, aod::BplusChargedMCParticleLevelJets>) { + selectionObjectPtMin = config.thresholdChargedBplusMCPJetPtMin; + } else if constexpr (std::is_same_v, aod::DielectronChargedJets> || std::is_same_v, aod::DielectronChargedMCDetectorLevelJets>) { + selectionObjectPtMin = config.thresholdChargedDielectronJetPtMin; + } else if constexpr (std::is_same_v, aod::DielectronChargedEventWiseSubtractedJets> || std::is_same_v, aod::DielectronChargedMCDetectorLevelEventWiseSubtractedJets>) { + selectionObjectPtMin = config.thresholdChargedEventWiseSubtractedDielectronJetPtMin; + } else if constexpr (std::is_same_v, aod::DielectronChargedMCParticleLevelJets>) { + selectionObjectPtMin = config.thresholdChargedDielectronMCPJetPtMin; + } else if constexpr (std::is_same_v, aod::JTracks>) { + selectionObjectPtMin = config.thresholdTriggerTrackPtMin; + } else if constexpr (std::is_same_v, aod::JClusters>) { + selectionObjectPtMin = config.thresholdClusterEnergyMin; + } else { + selectionObjectPtMin = 0.0; + } + for (const auto& selectionObject : selectionObjects) { + bool isTriggerObject = false; + if constexpr (std::is_same_v, aod::JClusters>) { + if (selectionObject.energy() >= selectionObjectPtMin) { + isTriggerObject = true; + } + } else { + if constexpr (std::is_same_v, aod::JTracks>) { + if (config.performTrackSelection && !(selectionObject.trackSel() & ~(1 << jetderiveddatautilities::JTrackSel::trackSign))) { + continue; + } + if (selectionObject.pt() < config.trackPtSelectionMin || std::abs(selectionObject.eta()) > config.trackEtaSelectionMax) { + continue; + } + } + if (selectionObject.pt() >= selectionObjectPtMin) { + isTriggerObject = true; + } + } + if (isTriggerObject) { + if constexpr (std::is_same_v, aod::ChargedMCParticleLevelJets> || std::is_same_v, aod::NeutralMCParticleLevelJets> || std::is_same_v, aod::FullMCParticleLevelJets> || std::is_same_v, aod::D0ChargedMCParticleLevelJets> || std::is_same_v, aod::DplusChargedMCParticleLevelJets> || std::is_same_v, aod::LcChargedMCParticleLevelJets> || std::is_same_v, aod::BplusChargedMCParticleLevelJets> || std::is_same_v, aod::DielectronChargedMCParticleLevelJets>) { + if (selectionObject.mcCollisionId() >= 0) { + McCollisionFlag[selectionObject.mcCollisionId()] = true; + } + } else { + if (selectionObject.collisionId() >= 0) { + collisionFlag[selectionObject.collisionId()] = true; + } + } + } + } + } + // Todo : Check memory consumption of having so many Process Switches + PROCESS_SWITCH(JetDerivedDataSelector, processSetupCollisions, "setup the writing for data and MCD based on collisions", true); + PROCESS_SWITCH(JetDerivedDataSelector, processSetupMcCollisions, "setup the writing for MCP based on mcCollisions", false); + PROCESS_SWITCH(JetDerivedDataSelector, processSetupAllCollisionsWithDownscaling, "setup the writing of untriggered collisions with downscaling", false); + PROCESS_SWITCH(JetDerivedDataSelector, processSetupAllMcCollisionsWithDownscaling, "setup the writing of untriggered mccollisions with downscaling", false); + PROCESS_SWITCH(JetDerivedDataSelector, processSetupEventTriggering, "process software triggers", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingChargedJets, "process charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingChargedEventWiseSubtractedJets, "process charged event-wise subtracted jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingChargedMCDJets, "process charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingChargedMCDetectorLevelEventWiseSubtractedJets, "process charged event-wise subtracted mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingChargedMCPJets, "process charged mcp jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingNeutralJets, "process neutral jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingNeutralMCDJets, "process neutral mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingNeutralMCPJets, "process neutral mcp jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingFullJets, "process full jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingFullMCDJets, "process full mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingFullMCPJets, "process full mcp jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingD0ChargedJets, "process D0 charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingD0ChargedEventWiseSubtractedJets, "process D0 event-wise subtracted charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingD0ChargedMCDJets, "process D0 charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingD0ChargedMCDetectorLevelEventWiseSubtractedJets, "process D0 event-wise subtracted charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingD0ChargedMCPJets, "process D0 charged mcp jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDplusChargedJets, "process Dplus charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDplusChargedEventWiseSubtractedJets, "process Dplus event-wise subtracted charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDplusChargedMCDJets, "process Dplus charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDplusChargedMCDetectorLevelEventWiseSubtractedJets, "process Dplus event-wise subtracted charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDplusChargedMCPJets, "process Dplus charged mcp jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingLcChargedJets, "process Lc charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingLcChargedEventWiseSubtractedJets, "process Lc event-wise subtracted charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingLcChargedMCDJets, "process Lc charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingLcChargedMCDetectorLevelEventWiseSubtractedJets, "process Lc event-wise subtracted charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingLcChargedMCPJets, "process Lc charged mcp jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingBplusChargedJets, "process Bplus charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingBplusChargedEventWiseSubtractedJets, "process Bplus event-wise subtracted charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingBplusChargedMCDJets, "process Bplus charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingBplusChargedMCDetectorLevelEventWiseSubtractedJets, "process Bplus event-wise subtracted charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingBplusChargedMCPJets, "process Bplus charged mcp jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDielectronChargedJets, "process Dielectron charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDielectronChargedEventWiseSubtractedJets, "process Dielectron event-wise subtracted charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDielectronChargedMCDJets, "process Dielectron charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDielectronChargedMCDetectorLevelEventWiseSubtractedJets, "process Dielectron event-wise subtracted charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDielectronChargedMCPJets, "process Dielectron charged mcp jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingClusters, "process EMCal clusters", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingTracks, "process high pt tracks", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processDoDownscaling, processCollisionDownscaling, "process downsaling of triggered collisions", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processDoDownscaling, processMcCollisionDownscaling, "process downsaling of triggered mccollisions", false); + PROCESS_SWITCH(JetDerivedDataSelector, processDoCollisionSelections, "process event selections for saved events", false); + PROCESS_SWITCH(JetDerivedDataSelector, processSelectMcCollisionsPerCollision, "select McCollisions due to a triggered reconstructed collision", false); + PROCESS_SWITCH(JetDerivedDataSelector, processSelectCollisionsPerMcCollision, "select collisions due to a triggered McCollision", false); + + void processStoreCollisionDecision(aod::JCollision const& collision) + { + if (collisionFlag[collision.globalIndex()]) { + collisionSelectionsTable(true); + } else { + collisionSelectionsTable(false); + } + } + PROCESS_SWITCH(JetDerivedDataSelector, processStoreCollisionDecision, "write out decision of storing collision", true); + + void processStoreMcCollisionDecision(aod::JMcCollision const& mcCollision) + { + if (McCollisionFlag[mcCollision.globalIndex()]) { + mcCollisionSelectionsTable(true); + } else { + mcCollisionSelectionsTable(false); + } + } + PROCESS_SWITCH(JetDerivedDataSelector, processStoreMcCollisionDecision, "write out decision of storing mcCollision", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-deriveddata-selector"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/jetderiveddatatriggerproducer.cxx b/PWGJE/TableProducer/derivedDataTriggerProducer.cxx similarity index 73% rename from PWGJE/TableProducer/jetderiveddatatriggerproducer.cxx rename to PWGJE/TableProducer/derivedDataTriggerProducer.cxx index 4d7dcccce96..a1a1636dd1b 100644 --- a/PWGJE/TableProducer/jetderiveddatatriggerproducer.cxx +++ b/PWGJE/TableProducer/derivedDataTriggerProducer.cxx @@ -47,35 +47,17 @@ struct JetDerivedDataTriggerProducerTask { } PROCESS_SWITCH(JetDerivedDataTriggerProducerTask, processChargedJetTriggers, "produces derived charged trigger table", false); - void processNoChargedJetTriggers(aod::Collision const&) - { - jChargedTriggerSelsTable(jetderiveddatautilities::JTrigSelCh::noChargedTigger); - } - PROCESS_SWITCH(JetDerivedDataTriggerProducerTask, processNoChargedJetTriggers, "produces derived charged trigger table when sample is not triggered", true); - void processFullJetTriggers(soa::Join::iterator const& collision) { jFullTriggerSelsTable(jetderiveddatautilities::setFullTriggerSelectionBit(collision)); } PROCESS_SWITCH(JetDerivedDataTriggerProducerTask, processFullJetTriggers, "produces derived full trigger table", false); - void processNoFullJetTriggers(aod::Collision const&) - { - jFullTriggerSelsTable(jetderiveddatautilities::JTrigSelFull::noFullTrigger); - } - PROCESS_SWITCH(JetDerivedDataTriggerProducerTask, processNoFullJetTriggers, "produces derived full trigger table table when sample is not triggered", true); - void processChargedHFJetTriggers(soa::Join::iterator const& collision) { jChargedHFTriggerSelsTable(jetderiveddatautilities::setChargedHFTriggerSelectionBit(collision)); } PROCESS_SWITCH(JetDerivedDataTriggerProducerTask, processChargedHFJetTriggers, "produces derived charged hf trigger table", false); - - void processNoChargedHFJetTriggers(aod::Collision const&) - { - jChargedHFTriggerSelsTable(jetderiveddatautilities::JTrigSelChHF::noChargedHFTigger); - } - PROCESS_SWITCH(JetDerivedDataTriggerProducerTask, processNoChargedHFJetTriggers, "produces derived charged hf trigger table when sample is not triggered", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGJE/TableProducer/derivedDataWriter.cxx b/PWGJE/TableProducer/derivedDataWriter.cxx new file mode 100644 index 00000000000..dfd1c82b200 --- /dev/null +++ b/PWGJE/TableProducer/derivedDataWriter.cxx @@ -0,0 +1,705 @@ +// 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 jetderiveddatawriter.cxx +/// \brief Task to skim jet framework tables (aod::JetCollisions, aod::JetTracks, aod::JetClusters, ...) +/// while adjusting indices accordingly +/// +/// \author Jochen Klein +/// \author Nima Zardoshti + +#include +#include +#include +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/runDataProcessing.h" + +#include "PWGJE/Core/JetHFUtilities.h" +#include "PWGJE/Core/JetDQUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetReducedDataSelector.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct JetDerivedDataWriter { + + struct : ConfigurableGroup { + Configurable performTrackSelection{"performTrackSelection", true, "only save tracks that pass one of the track selections"}; + Configurable trackPtSelectionMin{"trackPtSelectionMin", 0.15, "only save tracks that have a pT larger than this pT"}; + Configurable trackEtaSelectionMax{"trackEtaSelectionMax", 0.9, "only save tracks that have an eta smaller than this eta"}; + + Configurable triggerMasks{"triggerMasks", "", "possible JE Trigger masks: fJetChLowPt,fJetChHighPt,fTrackLowPt,fTrackHighPt,fJetD0ChLowPt,fJetD0ChHighPt,fJetLcChLowPt,fJetLcChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt,fJetNeutralHighPt,fJetNeutralLowPt,fGammaVeryHighPtEMCAL,fGammaVeryHighPtDCAL,fGammaHighPtEMCAL,fGammaHighPtDCAL,fGammaLowPtEMCAL,fGammaLowPtDCAL,fGammaVeryLowPtEMCAL,fGammaVeryLowPtDCAL"}; + } config; + + struct : ProducesGroup { + Produces storedJDummysTable; + Produces storedJBCsTable; + Produces storedJBCParentIndexTable; + Produces storedJCollisionsTable; + Produces storedJCollisionMcInfosTable; + Produces storedJCollisionsParentIndexTable; + Produces storedJCollisionsBunchCrossingIndexTable; + Produces storedJCollisionsEMCalLabelTable; + Produces storedJMcCollisionsLabelTable; + Produces storedJMcCollisionsTable; + Produces storedJMcCollisionsParentIndexTable; + Produces storedJTracksTable; + Produces storedJTracksExtraTable; + Produces storedJTracksEMCalTable; + Produces storedJTracksParentIndexTable; + Produces storedJMcTracksLabelTable; + Produces storedJMcParticlesTable; + Produces storedJParticlesParentIndexTable; + Produces storedJClustersTable; + Produces storedJClustersCorrectedEnergiesTable; + Produces storedJClustersParentIndexTable; + Produces storedJClustersMatchedTracksTable; + Produces storedJMcClustersLabelTable; + + Produces storedD0CollisionsTable; + Produces storedD0CollisionIdsTable; + Produces storedD0sTable; + Produces storedD0ParsTable; + Produces storedD0ParExtrasTable; + Produces storedD0ParDaughtersDummyTable; + Produces storedD0SelsTable; + Produces storedD0MlsTable; + Produces storedD0MlDughtersDummyTable; + Produces storedD0McsTable; + Produces storedD0IdsTable; + Produces storedD0McCollisionsTable; + Produces storedD0McCollisionIdsTable; + Produces storedD0McCollisionsMatchingTable; + Produces storedD0ParticlesTable; + Produces storedD0ParticleIdsTable; + + Produces storedDplusCollisionsTable; + Produces storedDplusCollisionIdsTable; + Produces storedDplussTable; + Produces storedDplusParsTable; + Produces storedDplusParExtrasTable; + Produces storedDplusParDaughtersDummyTable; + Produces storedDplusSelsTable; + Produces storedDplusMlsTable; + Produces storedDplusMlDughtersDummyTable; + Produces storedDplusMcsTable; + Produces storedDplusIdsTable; + Produces storedDplusMcCollisionsTable; + Produces storedDplusMcCollisionIdsTable; + Produces storedDplusMcCollisionsMatchingTable; + Produces storedDplusParticlesTable; + Produces storedDplusParticleIdsTable; + + Produces storedLcCollisionsTable; + Produces storedLcCollisionIdsTable; + Produces storedLcsTable; + Produces storedLcParsTable; + Produces storedLcParExtrasTable; + Produces storedLcParDaughtersDummyTable; + Produces storedLcSelsTable; + Produces storedLcMlsTable; + Produces storedLcMlDughtersDummyTable; + Produces storedLcMcsTable; + Produces storedLcIdsTable; + Produces storedLcMcCollisionsTable; + Produces storedLcMcCollisionIdsTable; + Produces storedLcMcCollisionsMatchingTable; + Produces storedLcParticlesTable; + Produces storedLcParticleIdsTable; + + Produces storedBplusCollisionsTable; + Produces storedBplusCollisionIdsTable; + Produces storedBplussTable; + Produces storedBplusParsTable; + Produces storedBplusParExtrasTable; + Produces storedBplusParD0sTable; + Produces storedBplusSelsTable; + Produces storedBplusMlsTable; + Produces storedBplusMlD0sTable; + Produces storedBplusMcsTable; + Produces storedBplusIdsTable; + Produces storedBplusMcCollisionsTable; + Produces storedBplusMcCollisionIdsTable; + Produces storedBplusMcCollisionsMatchingTable; + Produces storedBplusParticlesTable; + Produces storedBplusParticleIdsTable; + + Produces storedDielectronCollisionsTable; + Produces storedDielectronCollisionIdsTable; + Produces storedDielectronsTable; + Produces storedDielectronIdsTable; + Produces storedDielectronMcCollisionsTable; + Produces storedDielectronMcCollisionIdsTable; + Produces storedDielectronMcRCollDummysTable; + Produces storedDielectronParticlesTable; + Produces storedDielectronParticleIdsTable; + } products; + + Preslice> TracksPerCollisionData = aod::jtrack::collisionId; + + Preslice> ParticlesPerMcCollision = aod::jmcparticle::mcCollisionId; + Preslice> TracksPerCollision = aod::jtrack::collisionId; + Preslice D0McCollisionsPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice DplusMcCollisionsPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice LcMcCollisionsPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice BplusMcCollisionsPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice DielectronMcCollisionsPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice D0ParticlesPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice DplusParticlesPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice LcParticlesPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice BplusParticlesPerMcCollision = aod::jcandidateindices::mcCollisionId; + PresliceUnsorted EMCTrackPerTrack = aod::jemctrack::trackId; + + uint32_t precisionPositionMask; + uint32_t precisionMomentumMask; + + void init(InitContext&) + { + precisionPositionMask = 0xFFFFFC00; // 13 bits + precisionMomentumMask = 0xFFFFFC00; // 13 bits this is currently keept at 13 bits wihich gives roughly a resolution of 1/8000. This can be increased to 15 bits if really needed + } + + template + bool trackSelection(T const& track) + { + if (config.performTrackSelection && !(track.trackSel() & ~(1 << jetderiveddatautilities::JTrackSel::trackSign))) { // skips tracks that pass no selections. This might cause a problem with tracks matched with clusters. We should generate a track selection purely for cluster matched tracks so that they are kept. This includes also the track pT selction. + return false; + } + if (track.pt() < config.trackPtSelectionMin || std::abs(track.eta()) > config.trackEtaSelectionMax) { + return false; + } + return true; + } + + template + void storeD0(soa::Join::iterator const& collision, aod::JTracks const&, aod::CollisionsD0 const& D0Collisions, T const& D0s) + { + + if (collision.isCollisionSelected()) { + for (const auto& D0Collision : D0Collisions) { // should only ever be one + jethfutilities::fillHFCollisionTable(D0Collision, products.storedD0CollisionsTable); + products.storedD0CollisionIdsTable(collisionMapping[collision.globalIndex()]); + } + for (const auto& D0 : D0s) { + jethfutilities::fillHFCandidateTable(D0, products.storedD0CollisionsTable.lastIndex(), products.storedD0sTable, products.storedD0ParsTable, products.storedD0ParExtrasTable, products.storedD0ParDaughtersDummyTable, products.storedD0SelsTable, products.storedD0MlsTable, products.storedD0MlDughtersDummyTable, products.storedD0McsTable); + products.storedD0IdsTable(collisionMapping[collision.globalIndex()], trackMapping[D0.prong0Id()], trackMapping[D0.prong1Id()]); + } + } + } + + template + void storeDplus(soa::Join::iterator const& collision, aod::JTracks const&, aod::CollisionsDplus const& DplusCollisions, T const& Dpluss) + { + if (collision.isCollisionSelected()) { + for (const auto& DplusCollision : DplusCollisions) { // should only ever be one + jethfutilities::fillHFCollisionTable(DplusCollision, products.storedDplusCollisionsTable); + products.storedDplusCollisionIdsTable(collisionMapping[collision.globalIndex()]); + } + for (const auto& Dplus : Dpluss) { + jethfutilities::fillHFCandidateTable(Dplus, products.storedDplusCollisionsTable.lastIndex(), products.storedDplussTable, products.storedDplusParsTable, products.storedDplusParExtrasTable, products.storedDplusParDaughtersDummyTable, products.storedDplusSelsTable, products.storedDplusMlsTable, products.storedDplusMlDughtersDummyTable, products.storedDplusMcsTable); + products.storedDplusIdsTable(collisionMapping[collision.globalIndex()], trackMapping[Dplus.prong0Id()], trackMapping[Dplus.prong1Id()], trackMapping[Dplus.prong2Id()]); + } + } + } + + template + void storeLc(soa::Join::iterator const& collision, aod::JTracks const&, aod::CollisionsLc const& LcCollisions, T const& Lcs) + { + if (collision.isCollisionSelected()) { + for (const auto& LcCollision : LcCollisions) { // should only ever be one + jethfutilities::fillHFCollisionTable(LcCollision, products.storedLcCollisionsTable); + products.storedLcCollisionIdsTable(collisionMapping[collision.globalIndex()]); + } + for (const auto& Lc : Lcs) { + jethfutilities::fillHFCandidateTable(Lc, products.storedLcCollisionsTable.lastIndex(), products.storedLcsTable, products.storedLcParsTable, products.storedLcParExtrasTable, products.storedLcParDaughtersDummyTable, products.storedLcSelsTable, products.storedLcMlsTable, products.storedLcMlDughtersDummyTable, products.storedLcMcsTable); + products.storedLcIdsTable(collisionMapping[collision.globalIndex()], trackMapping[Lc.prong0Id()], trackMapping[Lc.prong1Id()], trackMapping[Lc.prong2Id()]); + } + } + } + + template + void storeBplus(soa::Join::iterator const& collision, aod::JTracks const&, aod::CollisionsBplus const& BplusCollisions, T const& Bpluss) + { + if (collision.isCollisionSelected()) { + for (const auto& BplusCollision : BplusCollisions) { // should only ever be one + jethfutilities::fillHFCollisionTable(BplusCollision, products.storedBplusCollisionsTable); + products.storedBplusCollisionIdsTable(collisionMapping[collision.globalIndex()]); + } + for (const auto& Bplus : Bpluss) { + jethfutilities::fillHFCandidateTable(Bplus, products.storedBplusCollisionsTable.lastIndex(), products.storedBplussTable, products.storedBplusParsTable, products.storedBplusParExtrasTable, products.storedBplusParD0sTable, products.storedBplusSelsTable, products.storedBplusMlsTable, products.storedBplusMlD0sTable, products.storedBplusMcsTable); + products.storedBplusIdsTable(collisionMapping[collision.globalIndex()], trackMapping[Bplus.prong0Id()], trackMapping[Bplus.prong1Id()], trackMapping[Bplus.prong2Id()]); + } + } + } + + void processDummyTable(aod::JDummys const&) + { + products.storedJDummysTable(1); + } + PROCESS_SWITCH(JetDerivedDataWriter, processDummyTable, "write out dummy output table", true); + + std::vector collisionMapping; + std::vector bcMapping; + std::vector trackMapping; + std::vector mcCollisionMapping; + std::vector particleMapping; + std::vector d0McCollisionMapping; + std::vector dplusMcCollisionMapping; + std::vector lcMcCollisionMapping; + std::vector bplusMcCollisionMapping; + std::vector dielectronMcCollisionMapping; + + void processBCs(soa::Join const& collisions, soa::Join const& bcs) + { + std::vector bcIndicies; + bcMapping.clear(); + bcMapping.resize(bcs.size(), -1); + + for (auto const& collision : collisions) { + if (collision.isCollisionSelected()) { + auto bc = collision.bc_as>(); + if (std::find(bcIndicies.begin(), bcIndicies.end(), bc.globalIndex()) == bcIndicies.end()) { + products.storedJBCsTable(bc.runNumber(), bc.globalBC(), bc.timestamp(), bc.alias_raw(), bc.selection_raw()); + products.storedJBCParentIndexTable(bc.bcId()); + bcIndicies.push_back(bc.globalIndex()); + bcMapping[bc.globalIndex()] = products.storedJBCsTable.lastIndex(); + } + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processBCs, "write out output tables for Bunch crossings", true); + + void processColllisons(soa::Join const& collisions) + { + collisionMapping.clear(); + collisionMapping.resize(collisions.size(), -1); + + for (auto const& collision : collisions) { + if (collision.isCollisionSelected()) { + + products.storedJCollisionsTable(collision.posX(), collision.posY(), collision.posZ(), collision.multiplicity(), collision.centrality(), collision.centralityVariant1(), collision.hadronicRate(), collision.trackOccupancyInTimeRange(), collision.eventSel(), collision.alias_raw(), collision.triggerSel()); + collisionMapping[collision.globalIndex()] = products.storedJCollisionsTable.lastIndex(); + products.storedJCollisionMcInfosTable(collision.weight(), collision.subGeneratorId()); + products.storedJCollisionsParentIndexTable(collision.collisionId()); + if (doprocessBCs) { + products.storedJCollisionsBunchCrossingIndexTable(bcMapping[collision.bcId()]); + } + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processColllisons, "write out output tables for collisions", true); + + void processTracks(soa::Join const& collisions, soa::Join const& tracks) + { + trackMapping.clear(); + trackMapping.resize(tracks.size(), -1); + + for (auto const& collision : collisions) { + if (collision.isCollisionSelected()) { + const auto tracksPerCollision = tracks.sliceBy(TracksPerCollisionData, collision.globalIndex()); + for (const auto& track : tracksPerCollision) { + if (!trackSelection(track)) { // skips tracks that pass no selections. This might cause a problem with tracks matched with clusters. We should generate a track selection purely for cluster matched tracks so that they are kept. This includes also the track pT selction. + continue; + } + products.storedJTracksTable(collisionMapping[collision.globalIndex()], o2::math_utils::detail::truncateFloatFraction(track.pt(), precisionMomentumMask), o2::math_utils::detail::truncateFloatFraction(track.eta(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(track.phi(), precisionPositionMask), track.trackSel()); + products.storedJTracksExtraTable(o2::math_utils::detail::truncateFloatFraction(track.dcaX(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(track.dcaY(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(track.dcaZ(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(track.dcaXY(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(track.dcaXYZ(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(track.sigmadcaZ(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(track.sigmadcaXY(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(track.sigmadcaXYZ(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(track.sigma1Pt(), precisionMomentumMask)); + products.storedJTracksParentIndexTable(track.trackId()); + trackMapping[track.globalIndex()] = products.storedJTracksTable.lastIndex(); + } + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processTracks, "write out output tables for tracks", true); + + void processClusters(soa::Join::iterator const& collision, aod::JTracks const&, aod::JEMCTracks const& emcTracks, soa::Join const& clusters) + { + if (collision.isCollisionSelected()) { + products.storedJCollisionsEMCalLabelTable(collision.isAmbiguous(), collision.isEmcalReadout()); + for (const auto& cluster : clusters) { + products.storedJClustersTable(collisionMapping[collision.globalIndex()], cluster.id(), cluster.energy(), cluster.coreEnergy(), cluster.rawEnergy(), + cluster.eta(), cluster.phi(), cluster.m02(), cluster.m20(), cluster.nCells(), cluster.time(), cluster.isExotic(), cluster.distanceToBadChannel(), + cluster.nlm(), cluster.definition(), cluster.leadingCellEnergy(), cluster.subleadingCellEnergy(), cluster.leadingCellNumber(), cluster.subleadingCellNumber()); + products.storedJClustersCorrectedEnergiesTable(cluster.energyCorrectedOneTrack1(), cluster.energyCorrectedOneTrack2(), cluster.energyCorrectedAllTracks1(), cluster.energyCorrectedAllTracks2()); + products.storedJClustersParentIndexTable(cluster.clusterId()); + + std::vector clusterStoredJTrackIDs; + for (const auto& clusterTrack : cluster.matchedTracks_as()) { + clusterStoredJTrackIDs.push_back(trackMapping[clusterTrack.globalIndex()]); + auto emcTracksPerTrack = emcTracks.sliceBy(EMCTrackPerTrack, clusterTrack.globalIndex()); + auto emcTrackPerTrack = emcTracksPerTrack.iteratorAt(0); + products.storedJTracksEMCalTable(trackMapping[clusterTrack.globalIndex()], emcTrackPerTrack.etaEmcal(), emcTrackPerTrack.phiEmcal()); + } + products.storedJClustersMatchedTracksTable(clusterStoredJTrackIDs); + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processClusters, "write out output tables for clusters", false); + + //!!!!!!!!!! need to add the hadronic corrected energy and delete the new dummy process function + + void processD0Data(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsD0 const& D0Collisions, aod::CandidatesD0Data const& D0s) + { + storeD0(collision, tracks, D0Collisions, D0s); + } + PROCESS_SWITCH(JetDerivedDataWriter, processD0Data, "write out data output tables for D0", false); + + void processD0MCD(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsD0 const& D0Collisions, aod::CandidatesD0MCD const& D0s) + { + storeD0(collision, tracks, D0Collisions, D0s); + } + PROCESS_SWITCH(JetDerivedDataWriter, processD0MCD, "write out mcd output tables for D0", false); + + void processDplusData(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsDplus const& DplusCollisions, aod::CandidatesDplusData const& Dpluss) + { + storeDplus(collision, tracks, DplusCollisions, Dpluss); + } + PROCESS_SWITCH(JetDerivedDataWriter, processDplusData, "write out data output tables for Dplus", false); + + void processDplusMCD(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsDplus const& DplusCollisions, aod::CandidatesDplusMCD const& Dpluss) + { + storeDplus(collision, tracks, DplusCollisions, Dpluss); + } + PROCESS_SWITCH(JetDerivedDataWriter, processDplusMCD, "write out mcd output tables for Dplus", false); + + void processLcData(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsLc const& LcCollisions, aod::CandidatesLcData const& Lcs) + { + storeLc(collision, tracks, LcCollisions, Lcs); + } + PROCESS_SWITCH(JetDerivedDataWriter, processLcData, "write out data output tables for Lc", false); + + void processLcMCD(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsLc const& LcCollisions, aod::CandidatesLcMCD const& Lcs) + { + storeLc(collision, tracks, LcCollisions, Lcs); + } + PROCESS_SWITCH(JetDerivedDataWriter, processLcMCD, "write out mcd output tables for Lc", false); + + void processBplusData(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsBplus const& BplusCollisions, aod::CandidatesBplusData const& Bpluss) + { + storeBplus(collision, tracks, BplusCollisions, Bpluss); + } + PROCESS_SWITCH(JetDerivedDataWriter, processBplusData, "write out data output tables for bplus", false); + + void processBplusMCD(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsBplus const& BplusCollisions, aod::CandidatesBplusMCD const& Bpluss) + { + storeBplus(collision, tracks, BplusCollisions, Bpluss); + } + PROCESS_SWITCH(JetDerivedDataWriter, processBplusMCD, "write out mcd output tables for bplus", false); + + void processDielectron(soa::Join::iterator const& collision, aod::JTracks const&, aod::CollisionsDielectron const& DielectronCollisions, aod::CandidatesDielectronData const& Dielectrons) + { + if (collision.isCollisionSelected()) { + for (const auto& DielectronCollision : DielectronCollisions) { // should only ever be one + jetdqutilities::fillDielectronCollisionTable(DielectronCollision, products.storedDielectronCollisionsTable); + products.storedDielectronCollisionIdsTable(collisionMapping[collision.globalIndex()]); + } + for (const auto& Dielectron : Dielectrons) { + jetdqutilities::fillDielectronCandidateTable(Dielectron, products.storedDielectronCollisionsTable.lastIndex(), products.storedDielectronsTable); + products.storedDielectronIdsTable(collisionMapping[collision.globalIndex()], trackMapping[Dielectron.prong0Id()], trackMapping[Dielectron.prong1Id()]); + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processDielectron, "write out data output tables for dielectrons", false); + + void processMcCollisions(soa::Join const& mcCollisions) + { + mcCollisionMapping.clear(); + mcCollisionMapping.resize(mcCollisions.size(), -1); + for (auto const& mcCollision : mcCollisions) { + if (mcCollision.isMcCollisionSelected()) { + products.storedJMcCollisionsTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.weight(), mcCollision.subGeneratorId(), mcCollision.accepted(), mcCollision.attempted(), mcCollision.xsectGen(), mcCollision.xsectErr()); + products.storedJMcCollisionsParentIndexTable(mcCollision.mcCollisionId()); + mcCollisionMapping[mcCollision.globalIndex()] = products.storedJMcCollisionsTable.lastIndex(); + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processMcCollisions, "write out mcCollision output tables", false); + + void processMcParticles(soa::Join const& mcCollisions, soa::Join const& particles) + { + particleMapping.clear(); + particleMapping.resize(particles.size(), -1); + int particleTableIndex = 0; + for (auto const& mcCollision : mcCollisions) { + if (mcCollision.isMcCollisionSelected()) { + + const auto particlesPerMcCollision = particles.sliceBy(ParticlesPerMcCollision, mcCollision.globalIndex()); + + for (auto particle : particlesPerMcCollision) { + particleMapping[particle.globalIndex()] = particleTableIndex; + particleTableIndex++; + } + for (auto particle : particlesPerMcCollision) { + + std::vector mothersIds; + if (particle.has_mothers()) { + auto mothersIdTemps = particle.mothersIds(); + for (auto mothersIdTemp : mothersIdTemps) { + mothersIds.push_back(particleMapping[mothersIdTemp]); + } + } + int daughtersIds[2] = {-1, -1}; + auto i = 0; + if (particle.has_daughters()) { + for (auto daughterId : particle.daughtersIds()) { + if (i > 1) { + break; + } + daughtersIds[i] = particleMapping[daughterId]; + i++; + } + } + products.storedJMcParticlesTable(mcCollisionMapping[mcCollision.globalIndex()], o2::math_utils::detail::truncateFloatFraction(particle.pt(), precisionMomentumMask), o2::math_utils::detail::truncateFloatFraction(particle.eta(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(particle.phi(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(particle.y(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(particle.e(), precisionMomentumMask), particle.pdgCode(), particle.getGenStatusCode(), particle.getHepMCStatusCode(), particle.isPhysicalPrimary(), mothersIds, daughtersIds); + products.storedJParticlesParentIndexTable(particle.mcParticleId()); + } + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processMcParticles, "write out mcParticle output tables", false); + + void processD0MCP(soa::Join const& mcCollisions, aod::McCollisionsD0 const& D0McCollisions, aod::CandidatesD0MCP const& D0Particles) + { + d0McCollisionMapping.clear(); + d0McCollisionMapping.resize(D0McCollisions.size(), -1); + for (auto const& mcCollision : mcCollisions) { + if (mcCollision.isMcCollisionSelected()) { + const auto d0McCollisionsPerMcCollision = D0McCollisions.sliceBy(D0McCollisionsPerMcCollision, mcCollision.globalIndex()); + for (const auto& d0McCollisionPerMcCollision : d0McCollisionsPerMcCollision) { + jethfutilities::fillHFMcCollisionTable(d0McCollisionPerMcCollision, products.storedD0McCollisionsTable); + products.storedD0McCollisionIdsTable(mcCollisionMapping[mcCollision.globalIndex()]); + d0McCollisionMapping[d0McCollisionPerMcCollision.globalIndex()] = products.storedD0McCollisionsTable.lastIndex(); + } + const auto d0ParticlesPerMcCollision = D0Particles.sliceBy(D0ParticlesPerMcCollision, mcCollision.globalIndex()); + for (const auto& D0Particle : d0ParticlesPerMcCollision) { + jethfutilities::fillHFCandidateMcTable(D0Particle, products.storedD0McCollisionsTable.lastIndex(), products.storedD0ParticlesTable); + products.storedD0ParticleIdsTable(mcCollisionMapping[mcCollision.globalIndex()], particleMapping[D0Particle.mcParticleId()]); + } + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processD0MCP, "write out D0 mcp output tables", false); + + void processDplusMCP(soa::Join const& mcCollisions, aod::McCollisionsDplus const& DplusMcCollisions, aod::CandidatesDplusMCP const& DplusParticles) + { + dplusMcCollisionMapping.clear(); + dplusMcCollisionMapping.resize(DplusMcCollisions.size(), -1); + for (auto const& mcCollision : mcCollisions) { + if (mcCollision.isMcCollisionSelected()) { + const auto dplusMcCollisionsPerMcCollision = DplusMcCollisions.sliceBy(DplusMcCollisionsPerMcCollision, mcCollision.globalIndex()); + for (const auto& dplusMcCollisionPerMcCollision : dplusMcCollisionsPerMcCollision) { // should only ever be one + jethfutilities::fillHFMcCollisionTable(dplusMcCollisionPerMcCollision, products.storedDplusMcCollisionsTable); + products.storedDplusMcCollisionIdsTable(mcCollisionMapping[mcCollision.globalIndex()]); + dplusMcCollisionMapping[dplusMcCollisionPerMcCollision.globalIndex()] = products.storedDplusMcCollisionsTable.lastIndex(); + } + const auto dplusParticlesPerMcCollision = DplusParticles.sliceBy(DplusParticlesPerMcCollision, mcCollision.globalIndex()); + for (const auto& DplusParticle : dplusParticlesPerMcCollision) { + jethfutilities::fillHFCandidateMcTable(DplusParticle, products.storedDplusMcCollisionsTable.lastIndex(), products.storedDplusParticlesTable); + products.storedDplusParticleIdsTable(mcCollisionMapping[mcCollision.globalIndex()], particleMapping[DplusParticle.mcParticleId()]); + } + } + } + } + + PROCESS_SWITCH(JetDerivedDataWriter, processDplusMCP, "write out Dplus mcp output tables", false); + + void processLcMCP(soa::Join const& mcCollisions, aod::McCollisionsLc const& LcMcCollisions, aod::CandidatesLcMCP const& LcParticles) + { + lcMcCollisionMapping.clear(); + lcMcCollisionMapping.resize(LcMcCollisions.size(), -1); + for (auto const& mcCollision : mcCollisions) { + if (mcCollision.isMcCollisionSelected()) { + const auto lcMcCollisionsPerMcCollision = LcMcCollisions.sliceBy(LcMcCollisionsPerMcCollision, mcCollision.globalIndex()); + for (const auto& lcMcCollisionPerMcCollision : lcMcCollisionsPerMcCollision) { // should only ever be one + jethfutilities::fillHFMcCollisionTable(lcMcCollisionPerMcCollision, products.storedLcMcCollisionsTable); + products.storedLcMcCollisionIdsTable(mcCollisionMapping[mcCollision.globalIndex()]); + lcMcCollisionMapping[lcMcCollisionPerMcCollision.globalIndex()] = products.storedLcMcCollisionsTable.lastIndex(); + } + const auto lcParticlesPerMcCollision = LcParticles.sliceBy(LcParticlesPerMcCollision, mcCollision.globalIndex()); + for (const auto& LcParticle : lcParticlesPerMcCollision) { + jethfutilities::fillHFCandidateMcTable(LcParticle, products.storedLcMcCollisionsTable.lastIndex(), products.storedLcParticlesTable); + products.storedLcParticleIdsTable(mcCollisionMapping[mcCollision.globalIndex()], particleMapping[LcParticle.mcParticleId()]); + } + } + } + } + + PROCESS_SWITCH(JetDerivedDataWriter, processLcMCP, "write out Lc mcp output tables", false); + + void processBplusMCP(soa::Join const& mcCollisions, aod::McCollisionsBplus const& BplusMcCollisions, aod::CandidatesBplusMCP const& BplusParticles) + { + bplusMcCollisionMapping.clear(); + bplusMcCollisionMapping.resize(BplusMcCollisions.size(), -1); + for (auto const& mcCollision : mcCollisions) { + if (mcCollision.isMcCollisionSelected()) { + const auto bplusMcCollisionsPerMcCollision = BplusMcCollisions.sliceBy(BplusMcCollisionsPerMcCollision, mcCollision.globalIndex()); + for (const auto& bplusMcCollisionPerMcCollision : bplusMcCollisionsPerMcCollision) { // should only ever be one + jethfutilities::fillHFMcCollisionTable(bplusMcCollisionPerMcCollision, products.storedBplusMcCollisionsTable); + products.storedBplusMcCollisionIdsTable(mcCollisionMapping[mcCollision.globalIndex()]); + bplusMcCollisionMapping[bplusMcCollisionPerMcCollision.globalIndex()] = products.storedBplusMcCollisionsTable.lastIndex(); + } + const auto bplusParticlesPerMcCollision = BplusParticles.sliceBy(BplusParticlesPerMcCollision, mcCollision.globalIndex()); + for (const auto& BplusParticle : bplusParticlesPerMcCollision) { + jethfutilities::fillHFCandidateMcTable(BplusParticle, products.storedBplusMcCollisionsTable.lastIndex(), products.storedBplusParticlesTable); + products.storedBplusParticleIdsTable(mcCollisionMapping[mcCollision.globalIndex()], particleMapping[BplusParticle.mcParticleId()]); + } + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processBplusMCP, "write out Bplus mcp output tables", false); + + void processDielectronMCP(soa::Join::iterator const& mcCollision, aod::JMcParticles const&, soa::Join const& DielectronMcCollisions, aod::CandidatesDielectronMCP const& DielectronParticles) + { + if (mcCollision.isMcCollisionSelected()) { + + const auto dielectronMcCollisionsPerMcCollision = DielectronMcCollisions.sliceBy(DielectronMcCollisionsPerMcCollision, mcCollision.globalIndex()); + for (const auto& dielectronMcCollisionPerMcCollision : dielectronMcCollisionsPerMcCollision) { // should only ever be one + jetdqutilities::fillDielectronMcCollisionTable(dielectronMcCollisionPerMcCollision, products.storedDielectronMcCollisionsTable); + products.storedDielectronMcCollisionIdsTable(mcCollisionMapping[mcCollision.globalIndex()]); + products.storedDielectronMcRCollDummysTable(dielectronMcCollisionPerMcCollision.dummyDQ()); + } + for (const auto& DielectronParticle : DielectronParticles) { + jetdqutilities::fillDielectronCandidateMcTable(DielectronParticle, products.storedDielectronMcCollisionsTable.lastIndex(), products.storedDielectronParticlesTable); + std::vector DielectronMothersIds; + int DielectronDaughtersId[2]; + if (DielectronParticle.has_mothers()) { + for (auto const& DielectronMother : DielectronParticle.template mothers_as()) { + DielectronMothersIds.push_back(particleMapping[DielectronMother.globalIndex()]); + } + } + auto i = 0; + if (DielectronParticle.has_daughters()) { + for (auto const& DielectronDaughter : DielectronParticle.template daughters_as()) { + if (i > 1) { + break; + } + DielectronDaughtersId[i] = particleMapping[DielectronDaughter.globalIndex()]; + i++; + } + } + products.storedDielectronParticleIdsTable(mcCollisionMapping[mcCollision.globalIndex()], particleMapping[DielectronParticle.mcParticleId()], DielectronMothersIds, DielectronDaughtersId); + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processDielectronMCP, "write out Dielectron mcp output tables", false); + + void processColllisonsMcCollisionLabel(soa::Join::iterator const& collision) + { + if (collision.isCollisionSelected()) { + products.storedJMcCollisionsLabelTable(mcCollisionMapping[collision.mcCollisionId()]); + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processColllisonsMcCollisionLabel, "write out collision mcCollision label output tables", false); + + void processTracksMcParticleLabel(soa::Join::iterator const& collision, soa::Join const& tracks) + { + if (collision.isCollisionSelected()) { + for (const auto& track : tracks) { + if (!trackSelection(track)) { + continue; + } + if (track.has_mcParticle()) { + products.storedJMcTracksLabelTable(particleMapping[track.mcParticleId()]); + } else { + products.storedJMcTracksLabelTable(-1); + } + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processTracksMcParticleLabel, "write out track mcParticle label output tables", false); + + void processClusterMcLabel(soa::Join::iterator const& collision, soa::Join const& clusters) + { + if (collision.isCollisionSelected()) { + for (const auto& cluster : clusters) { + std::vector clusterStoredJParticleIDs; + for (const auto& clusterParticleId : cluster.mcParticlesIds()) { + clusterStoredJParticleIDs.push_back(particleMapping[clusterParticleId]); + } + std::vector amplitudeA; + auto amplitudeASpan = cluster.amplitudeA(); + std::copy(amplitudeASpan.begin(), amplitudeASpan.end(), std::back_inserter(amplitudeA)); + products.storedJMcClustersLabelTable(clusterStoredJParticleIDs, amplitudeA); + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processClusterMcLabel, "write out cluster mc label output tables", false); + + void processD0McCollisionMatch(soa::Join::iterator const& mcCollision, soa::Join const& D0McCollisions, aod::CollisionsD0 const&) + { + if (mcCollision.isMcCollisionSelected()) { + for (const auto& D0McCollision : D0McCollisions) { // should just be one + std::vector d0CollisionIDs; + for (auto const& d0CollisionPerMcCollision : D0McCollision.hfCollBases_as()) { + d0CollisionIDs.push_back(d0McCollisionMapping[d0CollisionPerMcCollision.globalIndex()]); + } + products.storedD0McCollisionsMatchingTable(d0CollisionIDs); + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processD0McCollisionMatch, "write out D0 McCollision collision label output tables", false); + + void processDplusMcCollisionMatch(soa::Join::iterator const& mcCollision, soa::Join const& DplusMcCollisions, aod::CollisionsDplus const&) + { + if (mcCollision.isMcCollisionSelected()) { + for (const auto& DplusMcCollision : DplusMcCollisions) { // should just be one + std::vector dplusCollisionIDs; + for (auto const& dplusCollisionPerMcCollision : DplusMcCollision.hfCollBases_as()) { + dplusCollisionIDs.push_back(dplusMcCollisionMapping[dplusCollisionPerMcCollision.globalIndex()]); + } + products.storedDplusMcCollisionsMatchingTable(dplusCollisionIDs); + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processDplusMcCollisionMatch, "write out Dplus McCollision collision label output tables", false); + + void processLcMcCollisionMatch(soa::Join::iterator const& mcCollision, soa::Join const& LcMcCollisions, aod::CollisionsLc const&) + { + if (mcCollision.isMcCollisionSelected()) { + for (const auto& LcMcCollision : LcMcCollisions) { // should just be one + std::vector lcCollisionIDs; + for (auto const& lcCollisionPerMcCollision : LcMcCollision.hfCollBases_as()) { + lcCollisionIDs.push_back(lcMcCollisionMapping[lcCollisionPerMcCollision.globalIndex()]); + } + products.storedLcMcCollisionsMatchingTable(lcCollisionIDs); + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processLcMcCollisionMatch, "write out Lc McCollision collision label output tables", false); + + void processBplusMcCollisionMatch(soa::Join::iterator const& mcCollision, soa::Join const& BplusMcCollisions, aod::CollisionsBplus const&) + { + if (mcCollision.isMcCollisionSelected()) { + for (const auto& BplusMcCollision : BplusMcCollisions) { // should just be one + std::vector bplusCollisionIDs; + for (auto const& bplusCollisionPerMcCollision : BplusMcCollision.hfCollBases_as()) { + bplusCollisionIDs.push_back(bplusMcCollisionMapping[bplusCollisionPerMcCollision.globalIndex()]); + } + products.storedBplusMcCollisionsMatchingTable(bplusCollisionIDs); + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processBplusMcCollisionMatch, "write out Bplus McCollision collision label output tables", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-deriveddata-writer"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/emcalClusterHadronicCorrectionTask.cxx b/PWGJE/TableProducer/emcalClusterHadronicCorrectionTask.cxx new file mode 100644 index 00000000000..69e1f1051dc --- /dev/null +++ b/PWGJE/TableProducer/emcalClusterHadronicCorrectionTask.cxx @@ -0,0 +1,292 @@ +// 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. + +// **Hadronic Correction in the EMCAL framework: to avoid the double counting of the charged particles' contribution in jets** +/// \author Archita Rani Dash + +#include +#include +#include +#include +#include +#include +#include "TVector2.h" + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/HistogramRegistry.h" + +#include "DetectorsBase/GeometryManager.h" + +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/Jet.h" + +#include "PWGJE/Core/JetUtilities.h" + +#include "CommonDataFormat/InteractionRecord.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct EmcalClusterHadronicCorrectionTask { + Produces clusterEnergyCorrectedTable; + + HistogramRegistry registry; + // Configurables for Histogram Binning + PresliceUnsorted perTrackMatchedTrack = aod::jemctrack::trackId; + + // define configurables here + Configurable clusterDefinitionS{"clusterDefinition", "kV3Default", "cluster definition to be selected, e.g. V3Default"}; + + Configurable minTime{"minTime", -25., "Minimum cluster time for time cut"}; + Configurable maxTime{"maxTime", 20., "Maximum cluster time for time cut"}; + Configurable minM02{"minM02", 0.1, "Minimum M02 for M02 cut"}; + Configurable maxM02{"maxM02", 0.9, "Maximum M02 for M02 cut"}; + Configurable minTrackPt{"minTrackPt", 0.15, "Minimum pT for tracks"}; + Configurable hadCorr1{"hadCorr1", 1., "hadronic correction fraction for complete cluster energy subtraction for one matched track"}; // 100% - default + Configurable hadCorr2{"hadCorr2", 0.7, "hadronic correction fraction for systematic studies for one matched track"}; // 70% + Configurable hadCorralltrks1{"hadCorralltrks1", 1., "hadronic correction fraction for complete cluster energy subtraction for all matched tracks"}; // 100% - all tracks + Configurable hadCorralltrks2{"hadCorralltrks2", 0.7, "hadronic correction fraction for systematic studies for all matched tracks"}; // 70% + Configurable minDEta{"minDEta", 0.01, "Minimum dEta between track and cluster"}; + Configurable minDPhi{"minDPhi", 0.01, "Minimum dPhi between track and cluster"}; + Configurable constantSubtractionValue{"constantSubtractionValue", 0.236, "Value to be used for constant MIP subtraction (only applicable if using constant subtraction in M02 scheme)"}; + + // pT-dependent track-matching configurables + Configurable eta0{"eta0", 0.04, "Param 0 in eta for pt-dependent matching"}; + Configurable eta1{"eta1", 0.010, "Param 1 in eta for pt-dependent matching"}; + Configurable eta2{"eta2", 2.5, "Param 2 in eta for pt-dependent matching"}; + Configurable phi0{"phi0", 0.09, "Param 0 in phi for pt-dependent matching"}; + Configurable phi1{"phi1", 0.015, "Param 1 in phi for pt-dependent matching"}; + Configurable phi2{"phi2", 2.0, "Param 2 in phi for pt-dependent matching"}; + + Configurable doHadCorrSyst{"doHadCorrSyst", false, "Do hadronic correction for systematic studies"}; + Configurable doMomDepMatching{"doMomDepMatching", true, "Do momentum dependent track matching"}; // to be always set to true in Run 3 + Configurable useM02SubtractionScheme1{"useM02SubtractionScheme1", false, "Flag to enable hadronic correction scheme using cluster M02 value for clusterE1 and clusterEAll1"}; + Configurable useM02SubtractionScheme2{"useM02SubtractionScheme2", false, "Flag to enable hadronic correction scheme using cluster M02 value for clusterE2 and clusterEAll2"}; + Configurable useFraction1{"useFraction1", false, "Fractional momentum subtraction for clusterE1 and clusterEAll1"}; + Configurable useFraction2{"useFraction2", false, "Fractional momentum subtraction for clusterE2 and clusterEAll2"}; + + void init(o2::framework::InitContext&) + { + // Event histograms + registry.add("h_allcollisions", "Total events; event status;entries", {HistType::kTH1F, {{1, 0.5, 1.5}}}); + + // Matched-Cluster histograms + registry.add("h_matchedclusters", "Total matched clusters; cluster status;entries", {HistType::kTH1F, {{1, 0.5, 1.5}}}); + registry.add("h_ClsE", "; Cls E w/o correction (GeV); entries", {HistType::kTH1F, {{350, 0., 350.}}}); + registry.add("h_Ecluster1", "; Ecluster1 (GeV); entries", {HistType::kTH1F, {{350, 0., 350.}}}); + registry.add("h_Ecluster2", "; Ecluster2 (GeV); entries", {HistType::kTH1F, {{350, 0., 350.}}}); + registry.add("h_EclusterAll1", "; EclusterAll1 (GeV); entries", {HistType::kTH1F, {{350, 0., 350.}}}); + registry.add("h_EclusterAll2", "; EclusterAll2 (GeV); entries", {HistType::kTH1F, {{350, 0., 350.}}}); + registry.add("h_ClsTime", "Cluster time distribution of uncorrected cluster E; #it{t}_{cls} (ns); entries", {HistType::kTH1F, {{500, -250., 250.}}}); + registry.add("h_ClsM02", "Cluster M02 distribution of uncorrected cluster E; #it{M}_{02}; entries", {HistType::kTH1F, {{400, 0., 5.}}}); + registry.add("h2_ClsEvsNmatches", "Original cluster energy vs Nmatches; Cls E w/o correction (GeV); Nmatches", {HistType::kTH2F, {{350, 0., 350.}, {100, -0.5, 21.}}}); + registry.add("h2_ClsEvsEcluster1", "; Cls E w/o correction (GeV); Ecluster1 (GeV)", {HistType::kTH2F, {{350, 0., 350.}, {350, 0., 350.}}}); + registry.add("h2_ClsEvsEcluster2", "; Cls E w/o correction (GeV); Ecluster2 (GeV)", {HistType::kTH2F, {{350, 0., 350.}, {350, 0., 350.}}}); + registry.add("h2_ClsEvsEclusterAll1", "; Cls E w/o correction (GeV); EclusterAll1 (GeV)", {HistType::kTH2F, {{350, 0., 350.}, {350, 0., 350.}}}); + registry.add("h2_ClsEvsEclusterAll2", "; Cls E w/o correction (GeV); EclusterAll2 (GeV)", {HistType::kTH2F, {{350, 0., 350.}, {350, 0., 350.}}}); + + // Matched-Track histograms + registry.add("h_matchedtracks", "Total matched tracks; track status;entries", {HistType::kTH1F, {{1, 0.5, 1.5}}}); + } + + aod::EMCALClusterDefinition clusterDefinition = aod::emcalcluster::getClusterDefinitionFromString(clusterDefinitionS.value); + Filter clusterDefinitionSelection = (aod::jcluster::definition == static_cast(clusterDefinition)); + + // The matching of clusters and tracks is already centralised in the EMCAL framework. + // One only needs to apply a filter on matched clusters + // Here looping over all collisions matched to EMCAL clusters + void processMatchedCollisions(aod::JetCollision const&, soa::Filtered> const& clusters, aod::JEMCTracks const& emcTracks, aod::JetTracks const&) + { + registry.fill(HIST("h_allcollisions"), 1); + + // skip events with no clusters + if (clusters.size() == 0) { + return; + } + + // Looping over all clusters matched to the collision + for (const auto& cluster : clusters) { + registry.fill(HIST("h_matchedclusters"), 1); + + double clusterE1; + double clusterE2; + double clusterEAll1; + double clusterEAll2; + clusterE1 = clusterE2 = clusterEAll1 = clusterEAll2 = cluster.energy(); + + registry.fill(HIST("h_ClsE"), cluster.energy()); + registry.fill(HIST("h_ClsM02"), cluster.m02()); + registry.fill(HIST("h_ClsTime"), cluster.time()); + + int nMatches = 0; // counter for closest matched track + double closestTrkP = 0.0; // closest track momentum + double totalTrkP = 0.0; // total track momentum + + // pT-dependent track-matching instead of PID based track-matching to be adapted from Run 2 - suggested by Markus Fasel + + TF1 funcPtDepEta("func", "[1] + 1 / pow(x + pow(1 / ([0] - [1]), 1 / [2]), [2])"); + funcPtDepEta.SetParameters(eta0, eta1, eta2); + TF1 funcPtDepPhi("func", "[1] + 1 / pow(x + pow(1 / ([0] - [1]), 1 / [2]), [2])"); + funcPtDepEta.SetParameters(phi0, phi1, phi2); + + // No matched tracks (trackless case) + if (cluster.matchedTracks().size() == 0) { + // Use original cluster energy values, no subtraction needed. + registry.fill(HIST("h2_ClsEvsNmatches"), cluster.energy(), 0); + registry.fill(HIST("h_Ecluster1"), clusterE1); + registry.fill(HIST("h_Ecluster2"), clusterE2); + registry.fill(HIST("h_EclusterAll1"), clusterEAll1); + registry.fill(HIST("h_EclusterAll2"), clusterEAll2); + registry.fill(HIST("h2_ClsEvsEcluster1"), cluster.energy(), clusterE1); + registry.fill(HIST("h2_ClsEvsEcluster2"), cluster.energy(), clusterE2); + registry.fill(HIST("h2_ClsEvsEclusterAll1"), cluster.energy(), clusterEAll1); + registry.fill(HIST("h2_ClsEvsEclusterAll2"), cluster.energy(), clusterEAll2); + clusterEnergyCorrectedTable(clusterE1, clusterE2, clusterEAll1, clusterEAll2); + continue; + } + + // Looping over all matched tracks for the cluster + // Total number of matched tracks = 20 (hard-coded) + for (const auto& matchedTrack : cluster.matchedTracks_as()) { + if (matchedTrack.pt() < minTrackPt) { + continue; + } + double mom = abs(matchedTrack.p()); + registry.fill(HIST("h_matchedtracks"), 1); + + // CASE 1: skip tracks with a very low pT + if (mom < 1e-6) { + continue; + } // end CASE 1 + + // CASE 2: + // a) If one matched track -> 100% energy subtraction + // b) If more than one matched track -> 100% energy subtraction + // c) If you want to do systematic studies -> perform the above two checks a) and b), and then subtract 70% energy instead of 100% + + // Perform dEta/dPhi matching + auto emcTrack = (emcTracks.sliceBy(perTrackMatchedTrack, matchedTrack.globalIndex())).iteratorAt(0); + double dEta = emcTrack.etaEmcal() - cluster.eta(); + double dPhi = TVector2::Phi_mpi_pi(emcTrack.phiEmcal() - cluster.phi()); + + // Apply the eta and phi matching thresholds + // dEta and dPhi cut : ensures that the matched track is within the desired eta/phi window + + // Do pT-dependent track matching + if (doMomDepMatching) { + auto trackEtaMax = funcPtDepEta.Eval(mom); + auto trackPhiHigh = +funcPtDepPhi.Eval(mom); + auto trackPhiLow = -funcPtDepPhi.Eval(mom); + + if ((dPhi < trackPhiHigh && dPhi > trackPhiLow) && fabs(dEta) < trackEtaMax) { + if (nMatches == 0) { + closestTrkP = mom; + } + totalTrkP += mom; + nMatches++; + } + } else { + // Do fixed dEta/dPhi matching (non-pT dependent) + if (fabs(dEta) >= minDEta || fabs(dPhi) >= minDPhi) { + continue; // Skip this track if outside the fixed cut region + } + + // If track passes fixed dEta/dPhi cuts, process it + if (nMatches == 0) { + closestTrkP = mom; // Closest track match + } + totalTrkP += mom; // Accumulate momentum + nMatches++; // Count this match + } + + } // End of track loop + registry.fill(HIST("h2_ClsEvsNmatches"), cluster.energy(), nMatches); + + if (nMatches >= 1) { + if (useM02SubtractionScheme1) { + // Do M02-based correction if enabled + clusterE1 = subtractM02ClusterEnergy(cluster.m02(), clusterE1, nMatches, closestTrkP, hadCorr1, useFraction1); + clusterEAll1 = subtractM02ClusterEnergy(cluster.m02(), clusterEAll1, nMatches, totalTrkP, hadCorralltrks1, useFraction1); + } else { + // Default energy subtraction (100% and 70%) + clusterE1 = subtractClusterEnergy(clusterE1, closestTrkP, hadCorr1, nMatches, useFraction1); + clusterEAll1 = subtractClusterEnergy(clusterEAll1, totalTrkP, hadCorralltrks1, nMatches, useFraction1); + } + + if (useM02SubtractionScheme2) { + // Do M02-based correction if enabled + clusterE2 = subtractM02ClusterEnergy(cluster.m02(), clusterE2, nMatches, closestTrkP, hadCorr2, useFraction2); + clusterEAll2 = subtractM02ClusterEnergy(cluster.m02(), clusterEAll2, nMatches, totalTrkP, hadCorralltrks2, useFraction2); + } else { + // Default energy subtraction (100% and 70%) + clusterE2 = subtractClusterEnergy(clusterE2, closestTrkP, hadCorr2, nMatches, useFraction2); + clusterEAll2 = subtractClusterEnergy(clusterEAll2, totalTrkP, hadCorralltrks2, nMatches, useFraction2); + } + } + registry.fill(HIST("h_Ecluster1"), clusterE1); + registry.fill(HIST("h_Ecluster2"), clusterE2); + registry.fill(HIST("h_EclusterAll1"), clusterEAll1); + registry.fill(HIST("h_EclusterAll2"), clusterEAll2); + registry.fill(HIST("h2_ClsEvsEcluster1"), cluster.energy(), clusterE1); + registry.fill(HIST("h2_ClsEvsEcluster2"), cluster.energy(), clusterE2); + registry.fill(HIST("h2_ClsEvsEclusterAll1"), cluster.energy(), clusterEAll1); + registry.fill(HIST("h2_ClsEvsEclusterAll2"), cluster.energy(), clusterEAll2); + + // Fill the table with all four corrected energies + clusterEnergyCorrectedTable(clusterE1, clusterE2, clusterEAll1, clusterEAll2); + + } // End of cluster loop + } // process function ends + PROCESS_SWITCH(EmcalClusterHadronicCorrectionTask, processMatchedCollisions, "hadronic correction", true); + + // Helper function to prevent negative energy subtraction + double subtractClusterEnergy(double clusterE, double mom, double correctionFactor, int nMatches, bool useFraction) + { + double corrE = clusterE; + + // if (UseConstantSubtractionValue) { + if (!useFraction) { + corrE = clusterE - constantSubtractionValue * nMatches; // Use constant value for MIP-subtraction (regardless of the cluster-shape) + } else { + corrE = clusterE - correctionFactor * mom; // Fractional momentum subtraction + } + return (corrE < 0) ? 0 : corrE; + } + + // Helper function for M02-based energy subtraction (based on cluster-shape) + double subtractM02ClusterEnergy(double m02, double clusterE, int nMatches, double totalTrkP, double correctionFactor, bool useFraction) + { + double corrE = clusterE; + + // For M02 in the single photon region, the signal is primarily: Single photons, single electrons, single MIPs + if (m02 > 0.1 && m02 < 0.4) { // circular clusters(electron/photon) + corrE = 0; // Single electron, single MIP + } else if (m02 > 0.4) { + // Large M02 region (M02 > 0.4), more complex overlaps and hadronic showers. + // The signal is primarily: Single hadronic shower, photon-photon overlap, photon-MIP overlap, MIP-MIP overlap, + // MIP-hadronic shower overlap, hadronic shower - hadronic shower overlap) + + if (!useFraction) { + corrE = clusterE - constantSubtractionValue * nMatches; // Use constant value for MIP-subtraction (regardless of the cluster-shape) + } else { + corrE = clusterE - correctionFactor * totalTrkP; // Fractional momentum subtraction + } + } + return (corrE < 0) ? 0 : corrE; // Prevent negative energy + } + +}; // end of struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"emcal-cluster-hadronic-correction-task"})}; } diff --git a/PWGJE/TableProducer/emcalCorrectionTask.cxx b/PWGJE/TableProducer/emcalCorrectionTask.cxx index c0a63f1795a..bf72e3275d6 100644 --- a/PWGJE/TableProducer/emcalCorrectionTask.cxx +++ b/PWGJE/TableProducer/emcalCorrectionTask.cxx @@ -8,17 +8,24 @@ // 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. - -// EMCAL Correction Task -// -/// \author Raymond Ehlers , ORNL -/// \author Florian Jonas +/// +/// EMCAL Correction Task +/// +/// \file emcalCorrectionTask.cxx +/// +/// \brief Task that provides EMCal clusters and applies necessary corrections +/// +/// \author Raymond Ehlers (raymond.ehlers@cern.ch) ORNL, Florian Jonas (florian.jonas@cern.ch) +/// #include -#include #include #include #include +#include +#include +#include +#include #include "CCDB/BasicCCDBManager.h" #include "Framework/runDataProcessing.h" @@ -47,40 +54,40 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -using myGlobTracks = o2::soa::Join; -using bcEvSels = o2::soa::Join; -using collEventSels = o2::soa::Join; -using filteredCells = o2::soa::Filtered; -using mcCells = o2::soa::Join; -using filteredMCCells = o2::soa::Filtered; +using MyGlobTracks = o2::soa::Join; +using BcEvSels = o2::soa::Join; +using CollEventSels = o2::soa::Join; +using FilteredCells = o2::soa::Filtered; +using McCells = o2::soa::Join; +using FilteredMcCells = o2::soa::Filtered; struct EmcalCorrectionTask { Produces clusters; Produces mcclusters; Produces clustersAmbiguous; + Produces mcclustersAmbiguous; Produces clustercells; // cells belonging to given cluster Produces clustercellsambiguous; Produces matchedTracks; Produces emcalcollisionmatch; // Preslices - Preslice perCollision = o2::aod::track::collisionId; - PresliceUnsorted collisionsPerFoundBC = aod::evsel::foundBCId; + Preslice perCollision = o2::aod::track::collisionId; + PresliceUnsorted collisionsPerFoundBC = aod::evsel::foundBCId; Preslice collisionsPerBC = aod::collision::bcId; - Preslice cellsPerFoundBC = aod::calo::bcId; - Preslice mcCellsPerFoundBC = aod::calo::bcId; + Preslice cellsPerFoundBC = aod::calo::bcId; + Preslice mcCellsPerFoundBC = aod::calo::bcId; // Options for the clusterization // 1 corresponds to EMCAL cells based on the Run2 definition. Configurable selectedCellType{"selectedCellType", 1, "EMCAL Cell type"}; - Configurable clusterDefinitions{"clusterDefinition", "kV3Default", "cluster definition to be selected, e.g. V3Default. Multiple definitions can be specified separated by comma"}; + Configurable clusterDefinitions{"clusterDefinitions", "kV3Default", "cluster definition to be selected, e.g. V3Default. Multiple definitions can be specified separated by comma"}; Configurable maxMatchingDistance{"maxMatchingDistance", 0.4f, "Max matching distance track-cluster"}; - Configurable hasPropagatedTracks{"hasPropagatedTracks", false, "temporary flag, only set to true when running over data which has the tracks propagated to EMCal/PHOS!"}; - Configurable nonlinearityFunction{"nonlinearityFunction", "DATA_TestbeamFinal", "Nonlinearity correction at cluster level"}; + Configurable nonlinearityFunction{"nonlinearityFunction", "DATA_TestbeamFinal_NoScale", "Nonlinearity correction at cluster level. Default for data should be DATA_TestbeamFinal_NoScale. Default for MC should be MC_TestbeamFinal."}; Configurable disableNonLin{"disableNonLin", false, "Disable NonLin correction if set to true"}; Configurable hasShaperCorrection{"hasShaperCorrection", true, "Apply correction for shaper saturation"}; Configurable applyCellAbsScale{"applyCellAbsScale", 0, "Enable absolute cell energy scale to correct for energy loss in material in front of EMCal"}; - Configurable> vCellAbsScaleFactor{"cellAbsScaleFactor", {1.f}, "values for absolute cell energy calibration. Different values correspond to different regions or SM types of EMCal"}; + Configurable> cellAbsScaleFactors{"cellAbsScaleFactors", {1.f}, "values for absolute cell energy calibration. Different values correspond to different regions or SM types of EMCal"}; Configurable logWeight{"logWeight", 4.5, "logarithmic weight for the cluster center of gravity calculation"}; Configurable exoticCellFraction{"exoticCellFraction", 0.97, "Good cell if fraction < 1-ecross/ecell"}; Configurable exoticCellDiffTime{"exoticCellDiffTime", 1.e6, "If time of candidate to exotic and close cell is larger than exoticCellDiffTime (in ns), it must be noisy, set amp to 0"}; @@ -88,6 +95,8 @@ struct EmcalCorrectionTask { Configurable exoticCellInCrossMinAmplitude{"exoticCellInCrossMinAmplitude", 0.1, "Minimum energy of cells in cross, if lower not considered in cross"}; Configurable useWeightExotic{"useWeightExotic", false, "States if weights should be used for exotic cell cut"}; Configurable isMC{"isMC", false, "States if run over MC"}; + Configurable applyCellTimeCorrection{"applyCellTimeCorrection", true, "apply a correction to the cell time for data and MC: Shift both average cell times to 0 and smear MC time distribution to fit data better. For MC requires isMC to be true"}; + Configurable trackMinPt{"trackMinPt", 0.3, "Minimum pT for tracks to perform track matching, to reduce computing time. Tracks below a certain pT will be loopers anyway."}; // Require EMCAL cells (CALO type 1) Filter emccellfilter = aod::calo::caloType == selectedCellType; @@ -109,6 +118,14 @@ struct EmcalCorrectionTask { // QA o2::framework::HistogramRegistry mHistManager{"EMCALCorrectionTaskQAHistograms"}; + // Random number generator to draw cell time smearing for MC + std::random_device rd{}; + std::mt19937_64 rdgen{rd()}; + std::normal_distribution<> normalgaus{0, 1}; // mean = 0, stddev = 1 (apply amplitude of smearing after drawing random for performance reasons) + + // EMCal geometry + o2::emcal::Geometry* geometry; + void init(InitContext const&) { LOG(debug) << "Start init!"; @@ -125,7 +142,7 @@ struct EmcalCorrectionTask { mCcdbManager->get("GLO/Config/Geometry"); } LOG(debug) << "After load geometry!"; - o2::emcal::Geometry* geometry = o2::emcal::Geometry::GetInstanceFromRunNumber(223409); + geometry = o2::emcal::Geometry::GetInstanceFromRunNumber(223409); if (!geometry) { LOG(error) << "Failure accessing geometry"; } @@ -147,17 +164,18 @@ struct EmcalCorrectionTask { mClusterFactories.setExoticCellMinAmplitude(exoticCellMinAmplitude); mClusterFactories.setExoticCellInCrossMinAmplitude(exoticCellInCrossMinAmplitude); mClusterFactories.setUseWeightExotic(useWeightExotic); - for (auto& clusterDefinition : mClusterDefinitions) { - mClusterizers.emplace_back(std::make_unique>(1E9, clusterDefinition.timeMin, clusterDefinition.timeMax, clusterDefinition.gradientCut, clusterDefinition.doGradientCut, clusterDefinition.seedEnergy, clusterDefinition.minCellEnergy)); + for (const auto& clusterDefinition : mClusterDefinitions) { + mClusterizers.emplace_back(std::make_unique>(clusterDefinition.timeDiff, clusterDefinition.timeMin, clusterDefinition.timeMax, clusterDefinition.gradientCut, clusterDefinition.doGradientCut, clusterDefinition.seedEnergy, clusterDefinition.minCellEnergy)); LOG(info) << "Cluster definition initialized: " << clusterDefinition.toString(); LOG(info) << "timeMin: " << clusterDefinition.timeMin; LOG(info) << "timeMax: " << clusterDefinition.timeMax; + LOG(info) << "timeDiff: " << clusterDefinition.timeDiff; LOG(info) << "gradientCut: " << clusterDefinition.gradientCut; LOG(info) << "seedEnergy: " << clusterDefinition.seedEnergy; LOG(info) << "minCellEnergy: " << clusterDefinition.minCellEnergy; - LOG(info) << "storageID" << clusterDefinition.storageID; + LOG(info) << "storageID: " << clusterDefinition.storageID; } - for (auto& clusterizer : mClusterizers) { + for (const auto& clusterizer : mClusterizers) { clusterizer->setGeometry(geometry); } @@ -171,34 +189,54 @@ struct EmcalCorrectionTask { LOG(debug) << "Completed init!"; + // Define the cell energy binning + std::vector cellEnergyBins; + for (int i = 0; i < 51; i++) + cellEnergyBins.emplace_back(0.1 * (i - 0) + 0.0); // from 0 to 5 GeV/c, every 0.1 GeV + for (int i = 51; i < 76; i++) + cellEnergyBins.emplace_back(0.2 * (i - 51) + 5.2); // from 5.2 to 10.0 GeV, every 0.2 GeV + for (int i = 76; i < 166; i++) + cellEnergyBins.emplace_back(1. * (i - 76) + 11.); // from 11.0 to 100. GeV, every 1 GeV + // Setup QA hists. // NOTE: This is not comprehensive. - using o2HistType = o2::framework::HistType; - using o2Axis = o2::framework::AxisSpec; - o2Axis energyAxis{200, 0., 100., "E (GeV)"}, + using O2HistType = o2::framework::HistType; + o2::framework::AxisSpec energyAxis{200, 0., 100., "E (GeV)"}, + timeAxis{300, -100, 200., "t (ns)"}, etaAxis{160, -0.8, 0.8, "#eta"}, - phiAxis{72, 0, 2 * 3.14159, "phi"}; - mHistManager.add("hCellE", "hCellE", o2HistType::kTH1F, {energyAxis}); - mHistManager.add("hCellTowerID", "hCellTowerID", o2HistType::kTH1I, {{20000, 0, 20000}}); - mHistManager.add("hCellEtaPhi", "hCellEtaPhi", o2HistType::kTH2F, {etaAxis, phiAxis}); + phiAxis{72, 0, 2 * 3.14159, "phi"}, + nlmAxis{50, -0.5, 49.5, "NLM"}; + mHistManager.add("hCellE", "hCellE", O2HistType::kTH1F, {energyAxis}); + mHistManager.add("hCellTowerID", "hCellTowerID", O2HistType::kTH1D, {{20000, 0, 20000}}); + mHistManager.add("hCellEtaPhi", "hCellEtaPhi", O2HistType::kTH2F, {etaAxis, phiAxis}); + mHistManager.add("hHGCellTimeEnergy", "hCellTime", O2HistType::kTH2F, {{300, -30, 30}, cellEnergyBins}); // Cell time vs energy for high gain cells (low energies) + mHistManager.add("hLGCellTimeEnergy", "hCellTime", O2HistType::kTH2F, {{300, -30, 30}, cellEnergyBins}); // Cell time vs energy for low gain cells (high energies) // NOTE: Reversed column and row because it's more natural for presentation. - mHistManager.add("hCellRowCol", "hCellRowCol;Column;Row", o2HistType::kTH2I, {{97, 0, 97}, {600, 0, 600}}); - mHistManager.add("hClusterE", "hClusterE", o2HistType::kTH1F, {energyAxis}); - mHistManager.add("hClusterEtaPhi", "hClusterEtaPhi", o2HistType::kTH2F, {etaAxis, phiAxis}); - mHistManager.add("hGlobalTrackEtaPhi", "hGlobalTrackEtaPhi", o2HistType::kTH2F, {etaAxis, phiAxis}); - mHistManager.add("hGlobalTrackMult", "hGlobalTrackMult", o2HistType::kTH1I, {{200, -0.5, 199.5, "N_{trk}"}}); - mHistManager.add("hCollisionType", "hCollisionType;;#it{count}", o2HistType::kTH1I, {{3, -0.5, 2.5}}); + mHistManager.add("hCellRowCol", "hCellRowCol;Column;Row", O2HistType::kTH2D, {{96, -0.5, 95.5}, {208, -0.5, 207.5}}); + mHistManager.add("hClusterE", "hClusterE", O2HistType::kTH1F, {energyAxis}); + mHistManager.add("hClusterNLM", "hClusterNLM", O2HistType::kTH1F, {nlmAxis}); + mHistManager.add("hClusterEtaPhi", "hClusterEtaPhi", O2HistType::kTH2F, {etaAxis, phiAxis}); + mHistManager.add("hClusterTime", "hClusterTime", O2HistType::kTH1F, {timeAxis}); + mHistManager.add("hGlobalTrackEtaPhi", "hGlobalTrackEtaPhi", O2HistType::kTH2F, {etaAxis, phiAxis}); + mHistManager.add("hGlobalTrackMult", "hGlobalTrackMult", O2HistType::kTH1D, {{200, -0.5, 199.5, "N_{trk}"}}); + mHistManager.add("hCollisionType", "hCollisionType;;#it{count}", O2HistType::kTH1D, {{3, -0.5, 2.5}}); auto hCollisionType = mHistManager.get(HIST("hCollisionType")); hCollisionType->GetXaxis()->SetBinLabel(1, "no collision"); hCollisionType->GetXaxis()->SetBinLabel(2, "normal collision"); hCollisionType->GetXaxis()->SetBinLabel(3, "mult. collisions"); - mHistManager.add("hClusterType", "hClusterType;;#it{count}", o2HistType::kTH1I, {{3, -0.5, 2.5}}); + mHistManager.add("hBCMatchErrors", "hBCMatchErrors;;#it{N}_{BC}", O2HistType::kTH1D, {{3, -0.5, 2.5}}); + auto hBCMatchErrors = mHistManager.get(HIST("hBCMatchErrors")); + hBCMatchErrors->GetXaxis()->SetBinLabel(1, "Normal"); + hBCMatchErrors->GetXaxis()->SetBinLabel(2, "Wrong collisionID order"); + hBCMatchErrors->GetXaxis()->SetBinLabel(3, "foundBCId != globalIndex"); + mHistManager.add("hClusterType", "hClusterType;;#it{count}", O2HistType::kTH1D, {{3, -0.5, 2.5}}); auto hClusterType = mHistManager.get(HIST("hClusterType")); hClusterType->GetXaxis()->SetBinLabel(1, "no collision"); hClusterType->GetXaxis()->SetBinLabel(2, "normal collision"); hClusterType->GetXaxis()->SetBinLabel(3, "mult. collisions"); - mHistManager.add("hCollPerBC", "hCollPerBC;#it{N}_{coll.};#it{count}", o2HistType::kTH1I, {{100, -0.5, 99.5}}); - mHistManager.add("hBC", "hBC;;#it{count}", o2HistType::kTH1I, {{8, -0.5, 7.5}}); + mHistManager.add("hCollPerBC", "hCollPerBC;#it{N}_{coll.};#it{count}", O2HistType::kTH1D, {{100, -0.5, 99.5}}); + mHistManager.add("hBC", "hBC;;#it{count}", O2HistType::kTH1D, {{8, -0.5, 7.5}}); + mHistManager.add("hCollisionTimeReso", "hCollisionTimeReso;#Delta t_{coll};#it{count}", O2HistType::kTH1D, {{2000, 0, 2000}}); auto hBC = mHistManager.get(HIST("hBC")); hBC->GetXaxis()->SetBinLabel(1, "with EMCal cells"); hBC->GetXaxis()->SetBinLabel(2, "with EMCal cells but no collision"); @@ -209,8 +247,8 @@ struct EmcalCorrectionTask { hBC->GetXaxis()->SetBinLabel(7, "no EMCal cells and mult. collisions"); hBC->GetXaxis()->SetBinLabel(8, "all BC"); if (isMC) { - mHistManager.add("hContributors", "hContributors;contributor per cell hit;#it{counts}", o2HistType::kTH1I, {{20, 0, 20}}); - mHistManager.add("hMCParticleEnergy", "hMCParticleEnergy;#it{E} (GeV/#it{c});#it{counts}", o2HistType::kTH1F, {energyAxis}); + mHistManager.add("hContributors", "hContributors;contributor per cell hit;#it{counts}", O2HistType::kTH1I, {{20, 0, 20}}); + mHistManager.add("hMCParticleEnergy", "hMCParticleEnergy;#it{E} (GeV/#it{c});#it{counts}", O2HistType::kTH1F, {energyAxis}); } } @@ -219,15 +257,16 @@ struct EmcalCorrectionTask { // void process(aod::BCs const& bcs, aod::Collision const& collision, aod::Calos const& cells) // Appears to need the BC to be accessed to be available in the collision table... - void processFull(bcEvSels const& bcs, collEventSels const& collisions, myGlobTracks const& tracks, filteredCells const& cells) + void processFull(BcEvSels const& bcs, CollEventSels const& collisions, MyGlobTracks const& tracks, FilteredCells const& cells) { LOG(debug) << "Starting process full."; + int previousCollisionId = 0; // Collision ID of the last unique BC. Needed to skip unordered collisions to ensure ordered collisionIds in the cluster table int nBCsProcessed = 0; int nCellsProcessed = 0; std::unordered_map numberCollsInBC; // Number of collisions mapped to the global BC index of all BCs std::unordered_map numberCellsInBC; // Number of cells mapped to the global BC index of all BCs to check whether EMCal was readout - for (auto bc : bcs) { + for (const auto& bc : bcs) { LOG(debug) << "Next BC"; // Convert aod::Calo to o2::emcal::Cell which can be used with the clusterizer. // In particular, we need to filter only EMCAL cells. @@ -248,17 +287,17 @@ struct EmcalCorrectionTask { countBC(collisionsInFoundBC.size(), true); std::vector cellsBC; std::vector cellIndicesBC; - for (auto& cell : cellsInBC) { + for (const auto& cell : cellsInBC) { auto amplitude = cell.amplitude(); - if (static_cast(hasShaperCorrection)) { + if (static_cast(hasShaperCorrection) && emcal::intToChannelType(cell.cellType()) == emcal::ChannelType_t::LOW_GAIN) { // Apply shaper correction to LG cells amplitude = o2::emcal::NonlinearityHandler::evaluateShaperCorrectionCellEnergy(amplitude); } if (applyCellAbsScale) { - amplitude *= GetAbsCellScale(cell.cellNumber()); + amplitude *= getAbsCellScale(cell.cellNumber()); } cellsBC.emplace_back(cell.cellNumber(), amplitude, - cell.time(), + cell.time() + getCellTimeShift(cell.cellNumber(), amplitude, o2::emcal::intToChannelType(cell.cellType())), o2::emcal::intToChannelType(cell.cellType())); cellIndicesBC.emplace_back(cell.globalIndex()); } @@ -269,7 +308,7 @@ struct EmcalCorrectionTask { // TODO: Helpful for now, but should be removed. LOG(debug) << "Converted EMCAL cells"; - for (auto& cell : cellsBC) { + for (const auto& cell : cellsBC) { LOG(debug) << cell.getTower() << ": E: " << cell.getEnergy() << ", time: " << cell.getTimeStamp() << ", type: " << cell.getType(); } @@ -283,20 +322,29 @@ struct EmcalCorrectionTask { if (collisionsInFoundBC.size() == 1) { // dummy loop to get the first collision for (const auto& col : collisionsInFoundBC) { + if (previousCollisionId > col.globalIndex()) { + mHistManager.fill(HIST("hBCMatchErrors"), 1); + continue; + } + previousCollisionId = col.globalIndex(); if (col.foundBCId() == bc.globalIndex()) { + mHistManager.fill(HIST("hBCMatchErrors"), 0); // CollisionID ordered and foundBC matches -> Fill as healthy + mHistManager.fill(HIST("hCollisionTimeReso"), col.collisionTimeRes()); mHistManager.fill(HIST("hCollPerBC"), 1); mHistManager.fill(HIST("hCollisionType"), 1); - math_utils::Point3D vertex_pos = {col.posX(), col.posY(), col.posZ()}; + math_utils::Point3D vertexPos = {col.posX(), col.posY(), col.posZ()}; std::vector> clusterToTrackIndexMap; std::vector> trackToClusterIndexMap; - std::tuple>, std::vector>> IndexMapPair{clusterToTrackIndexMap, trackToClusterIndexMap}; + std::tuple>, std::vector>> indexMapPair{clusterToTrackIndexMap, trackToClusterIndexMap}; std::vector trackGlobalIndex; - doTrackMatching(col, tracks, IndexMapPair, vertex_pos, trackGlobalIndex); + doTrackMatching(col, tracks, indexMapPair, vertexPos, trackGlobalIndex); // Store the clusters in the table where a matching collision could // be identified. - FillClusterTable(col, vertex_pos, iClusterizer, cellIndicesBC, IndexMapPair, trackGlobalIndex); + fillClusterTable(col, vertexPos, iClusterizer, cellIndicesBC, indexMapPair, trackGlobalIndex); + } else { + mHistManager.fill(HIST("hBCMatchErrors"), 2); } } } else { // ambiguous @@ -309,7 +357,7 @@ struct EmcalCorrectionTask { hasCollision = true; mHistManager.fill(HIST("hCollisionType"), 2); } - FillAmbigousClusterTable(bc, iClusterizer, cellIndicesBC, hasCollision); + fillAmbigousClusterTable(bc, iClusterizer, cellIndicesBC, hasCollision); } LOG(debug) << "Cluster loop done for clusterizer " << iClusterizer; @@ -320,7 +368,7 @@ struct EmcalCorrectionTask { // Loop through all collisions and fill emcalcollisionmatch with a boolean stating, whether the collision was ambiguous (not the only collision in its BC) for (const auto& collision : collisions) { - auto globalbcid = collision.foundBC_as().globalIndex(); + auto globalbcid = collision.foundBC_as().globalIndex(); auto foundColls = numberCollsInBC.find(globalbcid); auto foundCells = numberCellsInBC.find(globalbcid); if (foundColls != numberCollsInBC.end() && foundCells != numberCellsInBC.end()) { @@ -334,15 +382,16 @@ struct EmcalCorrectionTask { } PROCESS_SWITCH(EmcalCorrectionTask, processFull, "run full analysis", true); - void processMCFull(bcEvSels const& bcs, collEventSels const& collisions, myGlobTracks const& tracks, filteredMCCells const& cells, aod::StoredMcParticles_001 const&) + void processMCFull(BcEvSels const& bcs, CollEventSels const& collisions, MyGlobTracks const& tracks, FilteredMcCells const& cells, aod::StoredMcParticles_001 const&) { LOG(debug) << "Starting process full."; + int previousCollisionId = 0; // Collision ID of the last unique BC. Needed to skip unordered collisions to ensure ordered collisionIds in the cluster table int nBCsProcessed = 0; int nCellsProcessed = 0; std::unordered_map numberCollsInBC; // Number of collisions mapped to the global BC index of all BCs std::unordered_map numberCellsInBC; // Number of cells mapped to the global BC index of all BCs to check whether EMCal was readout - for (auto bc : bcs) { + for (const auto& bc : bcs) { LOG(debug) << "Next BC"; // Convert aod::Calo to o2::emcal::Cell which can be used with the clusterizer. // In particular, we need to filter only EMCAL cells. @@ -364,19 +413,19 @@ struct EmcalCorrectionTask { std::vector cellsBC; std::vector cellIndicesBC; std::vector cellLabels; - for (auto& cell : cellsInBC) { + for (const auto& cell : cellsInBC) { mHistManager.fill(HIST("hContributors"), cell.mcParticle_as().size()); auto cellParticles = cell.mcParticle_as(); - for (auto& cellparticle : cellParticles) { + for (const auto& cellparticle : cellParticles) { mHistManager.fill(HIST("hMCParticleEnergy"), cellparticle.e()); } auto amplitude = cell.amplitude(); - if (static_cast(hasShaperCorrection)) { + if (static_cast(hasShaperCorrection) && emcal::intToChannelType(cell.cellType()) == emcal::ChannelType_t::LOW_GAIN) { // Apply shaper correction to LG cells amplitude = o2::emcal::NonlinearityHandler::evaluateShaperCorrectionCellEnergy(amplitude); } cellsBC.emplace_back(cell.cellNumber(), amplitude, - cell.time(), + cell.time() + getCellTimeShift(cell.cellNumber(), amplitude, o2::emcal::intToChannelType(cell.cellType())), o2::emcal::intToChannelType(cell.cellType())); cellIndicesBC.emplace_back(cell.globalIndex()); cellLabels.emplace_back(cell.mcParticleIds(), cell.amplitudeA()); @@ -388,7 +437,7 @@ struct EmcalCorrectionTask { // TODO: Helpful for now, but should be removed. LOG(debug) << "Converted EMCAL cells"; - for (auto& cell : cellsBC) { + for (const auto& cell : cellsBC) { LOG(debug) << cell.getTower() << ": E: " << cell.getEnergy() << ", time: " << cell.getTimeStamp() << ", type: " << cell.getType(); } @@ -402,20 +451,28 @@ struct EmcalCorrectionTask { if (collisionsInFoundBC.size() == 1) { // dummy loop to get the first collision for (const auto& col : collisionsInFoundBC) { + if (previousCollisionId > col.globalIndex()) { + mHistManager.fill(HIST("hBCMatchErrors"), 1); + continue; + } + previousCollisionId = col.globalIndex(); if (col.foundBCId() == bc.globalIndex()) { + mHistManager.fill(HIST("hBCMatchErrors"), 0); // CollisionID ordered and foundBC matches -> Fill as healthy mHistManager.fill(HIST("hCollPerBC"), 1); mHistManager.fill(HIST("hCollisionType"), 1); - math_utils::Point3D vertex_pos = {col.posX(), col.posY(), col.posZ()}; + math_utils::Point3D vertexPos = {col.posX(), col.posY(), col.posZ()}; std::vector> clusterToTrackIndexMap; std::vector> trackToClusterIndexMap; - std::tuple>, std::vector>> IndexMapPair{clusterToTrackIndexMap, trackToClusterIndexMap}; + std::tuple>, std::vector>> indexMapPair{clusterToTrackIndexMap, trackToClusterIndexMap}; std::vector trackGlobalIndex; - doTrackMatching(col, tracks, IndexMapPair, vertex_pos, trackGlobalIndex); + doTrackMatching(col, tracks, indexMapPair, vertexPos, trackGlobalIndex); // Store the clusters in the table where a matching collision could // be identified. - FillClusterTable(col, vertex_pos, iClusterizer, cellIndicesBC, IndexMapPair, trackGlobalIndex); + fillClusterTable(col, vertexPos, iClusterizer, cellIndicesBC, indexMapPair, trackGlobalIndex); + } else { + mHistManager.fill(HIST("hBCMatchErrors"), 2); } } } else { // ambiguous @@ -428,7 +485,7 @@ struct EmcalCorrectionTask { hasCollision = true; mHistManager.fill(HIST("hCollisionType"), 2); } - FillAmbigousClusterTable(bc, iClusterizer, cellIndicesBC, hasCollision); + fillAmbigousClusterTable(bc, iClusterizer, cellIndicesBC, hasCollision); } LOG(debug) << "Cluster loop done for clusterizer " << iClusterizer; } // end of clusterizer loop @@ -438,7 +495,7 @@ struct EmcalCorrectionTask { // Loop through all collisions and fill emcalcollisionmatch with a boolean stating, whether the collision was ambiguous (not the only collision in its BC) for (const auto& collision : collisions) { - auto globalbcid = collision.foundBC_as().globalIndex(); + auto globalbcid = collision.foundBC_as().globalIndex(); auto foundColls = numberCollsInBC.find(globalbcid); auto foundCells = numberCellsInBC.find(globalbcid); if (foundColls != numberCollsInBC.end() && foundCells != numberCellsInBC.end()) { @@ -451,12 +508,13 @@ struct EmcalCorrectionTask { LOG(detail) << "Processed " << nBCsProcessed << " BCs with " << nCellsProcessed << " cells"; } PROCESS_SWITCH(EmcalCorrectionTask, processMCFull, "run full analysis with MC info", false); - void processStandalone(aod::BCs const& bcs, aod::Collisions const& collisions, filteredCells const& cells) + void processStandalone(aod::BCs const& bcs, aod::Collisions const& collisions, FilteredCells const& cells) { LOG(debug) << "Starting process standalone."; + int previousCollisionId = 0; // Collision ID of the last unique BC. Needed to skip unordered collisions to ensure ordered collisionIds in the cluster table int nBCsProcessed = 0; int nCellsProcessed = 0; - for (auto bc : bcs) { + for (const auto& bc : bcs) { LOG(debug) << "Next BC"; // Convert aod::Calo to o2::emcal::Cell which can be used with the clusterizer. // In particular, we need to filter only EMCAL cells. @@ -475,10 +533,10 @@ struct EmcalCorrectionTask { countBC(collisionsInBC.size(), true); std::vector cellsBC; std::vector cellIndicesBC; - for (auto& cell : cellsInBC) { + for (const auto& cell : cellsInBC) { cellsBC.emplace_back(cell.cellNumber(), cell.amplitude(), - cell.time(), + cell.time() + getCellTimeShift(cell.cellNumber(), cell.amplitude(), o2::emcal::intToChannelType(cell.cellType())), o2::emcal::intToChannelType(cell.cellType())); cellIndicesBC.emplace_back(cell.globalIndex()); } @@ -489,7 +547,7 @@ struct EmcalCorrectionTask { // TODO: Helpful for now, but should be removed. LOG(debug) << "Converted EMCAL cells"; - for (auto& cell : cellsBC) { + for (const auto& cell : cellsBC) { LOG(debug) << cell.getTower() << ": E: " << cell.getEnergy() << ", time: " << cell.getTimeStamp() << ", type: " << cell.getType(); } @@ -504,13 +562,19 @@ struct EmcalCorrectionTask { if (collisionsInBC.size() == 1) { // dummy loop to get the first collision for (const auto& col : collisionsInBC) { + if (previousCollisionId > col.globalIndex()) { + mHistManager.fill(HIST("hBCMatchErrors"), 1); + continue; + } + previousCollisionId = col.globalIndex(); + mHistManager.fill(HIST("hBCMatchErrors"), 0); // CollisionID ordered and foundBC matches -> Fill as healthy mHistManager.fill(HIST("hCollPerBC"), 1); mHistManager.fill(HIST("hCollisionType"), 1); - math_utils::Point3D vertex_pos = {col.posX(), col.posY(), col.posZ()}; + math_utils::Point3D vertexPos = {col.posX(), col.posY(), col.posZ()}; // Store the clusters in the table where a matching collision could // be identified. - FillClusterTable(col, vertex_pos, iClusterizer, cellIndicesBC); + fillClusterTable(col, vertexPos, iClusterizer, cellIndicesBC); } } else { // ambiguous // LOG(warning) << "No vertex found for event. Assuming (0,0,0)."; @@ -522,7 +586,7 @@ struct EmcalCorrectionTask { hasCollision = true; mHistManager.fill(HIST("hCollisionType"), 2); } - FillAmbigousClusterTable(bc, iClusterizer, cellIndicesBC, hasCollision); + fillAmbigousClusterTable(bc, iClusterizer, cellIndicesBC, hasCollision); } LOG(debug) << "Cluster loop done for clusterizer " << iClusterizer; @@ -548,6 +612,8 @@ struct EmcalCorrectionTask { mAnalysisClusters.clear(); mClusterLabels.clear(); mClusterFactories.reset(); + // in preparation for future O2 changes + // mClusterFactories.setClusterizerSettings(mClusterDefinitions.at(iClusterizer).minCellEnergy, mClusterDefinitions.at(iClusterizer).timeMin, mClusterDefinitions.at(iClusterizer).timeMax, mClusterDefinitions.at(iClusterizer).recalcShowerShape5x5); if (cellLabels) { mClusterFactories.setContainer(*emcalClusters, cellsBC, *emcalClustersInputIndices, cellLabels); } else { @@ -568,7 +634,7 @@ struct EmcalCorrectionTask { } template - void FillClusterTable(Collision const& col, math_utils::Point3D const& vertex_pos, size_t iClusterizer, const gsl::span cellIndicesBC, std::optional>, std::vector>>> const& IndexMapPair = std::nullopt, std::optional> const& trackGlobalIndex = std::nullopt) + void fillClusterTable(Collision const& col, math_utils::Point3D const& vertexPos, size_t iClusterizer, const gsl::span cellIndicesBC, std::optional>, std::vector>>> const& indexMapPair = std::nullopt, std::optional> const& trackGlobalIndex = std::nullopt) { // we found a collision, put the clusters into the none ambiguous table clusters.reserve(mAnalysisClusters.size()); @@ -580,7 +646,7 @@ struct EmcalCorrectionTask { for (const auto& cluster : mAnalysisClusters) { // Determine the cluster eta, phi, correcting for the vertex position. auto pos = cluster.getGlobalPosition(); - pos = pos - vertex_pos; + pos = pos - vertexPos; // Normalize the vector and rescale by energy. pos *= (cluster.E() / std::sqrt(pos.Mag2())); @@ -617,12 +683,14 @@ struct EmcalCorrectionTask { } // end of cells of cluser loop // fill histograms mHistManager.fill(HIST("hClusterE"), cluster.E()); + mHistManager.fill(HIST("hClusterNLM"), cluster.getNExMax()); + mHistManager.fill(HIST("hClusterTime"), cluster.getClusterTime()); mHistManager.fill(HIST("hClusterEtaPhi"), pos.Eta(), TVector2::Phi_0_2pi(pos.Phi())); - if (IndexMapPair && trackGlobalIndex) { - for (unsigned int iTrack = 0; iTrack < std::get<0>(*IndexMapPair)[iCluster].size(); iTrack++) { - if (std::get<0>(*IndexMapPair)[iCluster][iTrack] >= 0) { - LOG(debug) << "Found track " << (*trackGlobalIndex)[std::get<0>(*IndexMapPair)[iCluster][iTrack]] << " in cluster " << cluster.getID(); - matchedTracks(clusters.lastIndex(), (*trackGlobalIndex)[std::get<0>(*IndexMapPair)[iCluster][iTrack]]); + if (indexMapPair && trackGlobalIndex) { + for (unsigned int iTrack = 0; iTrack < std::get<0>(*indexMapPair)[iCluster].size(); iTrack++) { + if (std::get<0>(*indexMapPair)[iCluster][iTrack] >= 0) { + LOG(debug) << "Found track " << (*trackGlobalIndex)[std::get<0>(*indexMapPair)[iCluster][iTrack]] << " in cluster " << cluster.getID(); + matchedTracks(clusters.lastIndex(), (*trackGlobalIndex)[std::get<0>(*indexMapPair)[iCluster][iTrack]]); } } } @@ -631,10 +699,14 @@ struct EmcalCorrectionTask { } template - void FillAmbigousClusterTable(BC const& bc, size_t iClusterizer, const gsl::span cellIndicesBC, bool hasCollision) + void fillAmbigousClusterTable(BC const& bc, size_t iClusterizer, const gsl::span cellIndicesBC, bool hasCollision) { int cellindex = -1; clustersAmbiguous.reserve(mAnalysisClusters.size()); + if (mClusterLabels.size() > 0) { + mcclustersAmbiguous.reserve(mClusterLabels.size()); + } + unsigned int iCluster = 0; for (const auto& cluster : mAnalysisClusters) { auto pos = cluster.getGlobalPosition(); pos = pos - math_utils::Point3D{0., 0., 0.}; @@ -663,33 +735,37 @@ struct EmcalCorrectionTask { cluster.getM20(), cluster.getNCells(), cluster.getClusterTime(), cluster.getIsExotic(), cluster.getDistanceToBadChannel(), cluster.getNExMax(), static_cast(mClusterDefinitions.at(iClusterizer))); + if (mClusterLabels.size() > 0) { + mcclustersAmbiguous(mClusterLabels[iCluster].getLabels(), mClusterLabels[iCluster].getEnergyFractions()); + } clustercellsambiguous.reserve(cluster.getNCells()); for (int ncell = 0; ncell < cluster.getNCells(); ncell++) { cellindex = cluster.getCellIndex(ncell); clustercellsambiguous(clustersAmbiguous.lastIndex(), cellIndicesBC[cellindex]); } // end of cells of cluster loop - } // end of cluster loop + iCluster++; + } // end of cluster loop } template - void doTrackMatching(Collision const& col, myGlobTracks const& tracks, std::tuple>, std::vector>>& IndexMapPair, math_utils::Point3D& vertex_pos, std::vector& trackGlobalIndex) + void doTrackMatching(Collision const& col, MyGlobTracks const& tracks, std::tuple>, std::vector>>& indexMapPair, math_utils::Point3D& vertexPos, std::vector& trackGlobalIndex) { auto groupedTracks = tracks.sliceBy(perCollision, col.globalIndex()); - int NTracksInCol = groupedTracks.size(); + int nTracksInCol = groupedTracks.size(); std::vector trackPhi; std::vector trackEta; // reserve memory to reduce on the fly memory allocation - trackPhi.reserve(NTracksInCol); - trackEta.reserve(NTracksInCol); - trackGlobalIndex.reserve(NTracksInCol); - FillTrackInfo(groupedTracks, trackPhi, trackEta, trackGlobalIndex); + trackPhi.reserve(nTracksInCol); + trackEta.reserve(nTracksInCol); + trackGlobalIndex.reserve(nTracksInCol); + fillTrackInfo(groupedTracks, trackPhi, trackEta, trackGlobalIndex); - int NClusterInCol = mAnalysisClusters.size(); + int nClusterInCol = mAnalysisClusters.size(); std::vector clusterPhi; std::vector clusterEta; - clusterPhi.reserve(NClusterInCol); - clusterEta.reserve(NClusterInCol); + clusterPhi.reserve(nClusterInCol); + clusterEta.reserve(nClusterInCol); // TODO one loop that could in principle be combined with the other // loop to improve performance @@ -697,48 +773,48 @@ struct EmcalCorrectionTask { // Determine the cluster eta, phi, correcting for the vertex // position. auto pos = cluster.getGlobalPosition(); - pos = pos - vertex_pos; + pos = pos - vertexPos; // Normalize the vector and rescale by energy. pos *= (cluster.E() / std::sqrt(pos.Mag2())); clusterPhi.emplace_back(TVector2::Phi_0_2pi(pos.Phi())); clusterEta.emplace_back(pos.Eta()); } - IndexMapPair = + indexMapPair = jetutilities::MatchClustersAndTracks(clusterPhi, clusterEta, trackPhi, trackEta, maxMatchingDistance, 20); } template - void FillTrackInfo(Tracks const& tracks, std::vector& trackPhi, std::vector& trackEta, std::vector& trackGlobalIndex) + void fillTrackInfo(Tracks const& tracks, std::vector& trackPhi, std::vector& trackEta, std::vector& trackGlobalIndex) { - int NTrack = 0; - for (auto& track : tracks) { + int nTrack = 0; + for (const auto& track : tracks) { // TODO only consider tracks in current emcal/dcal acceptanc if (!track.isGlobalTrack()) { // only global tracks continue; } - NTrack++; - if (hasPropagatedTracks) { // only temporarily while not every data - // has the tracks propagated to EMCal/PHOS - trackPhi.emplace_back(TVector2::Phi_0_2pi(track.trackPhiEmcal())); - trackEta.emplace_back(track.trackEtaEmcal()); - mHistManager.fill(HIST("hGlobalTrackEtaPhi"), track.trackEtaEmcal(), - TVector2::Phi_0_2pi(track.trackPhiEmcal())); - } else { - trackPhi.emplace_back(TVector2::Phi_0_2pi(track.phi())); - trackEta.emplace_back(track.eta()); - mHistManager.fill(HIST("hGlobalTrackEtaPhi"), track.eta(), - TVector2::Phi_0_2pi(track.phi())); + // Tracks that do not point to the EMCal/DCal/PHOS get default values of -999 + // This way we can cut out tracks that do not point to the EMCal+DCal + if (track.trackEtaEmcal() < -900 || track.trackPhiEmcal() < -900) { + continue; + } + if (trackMinPt > 0 && track.pt() < trackMinPt) { + continue; } + nTrack++; + trackPhi.emplace_back(TVector2::Phi_0_2pi(track.trackPhiEmcal())); + trackEta.emplace_back(track.trackEtaEmcal()); + mHistManager.fill(HIST("hGlobalTrackEtaPhi"), track.trackEtaEmcal(), + TVector2::Phi_0_2pi(track.trackPhiEmcal())); trackGlobalIndex.emplace_back(track.globalIndex()); } - mHistManager.fill(HIST("hGlobalTrackMult"), NTrack); + mHistManager.fill(HIST("hGlobalTrackMult"), nTrack); } - void countBC(int numberOfCollisions, bool hasEMCcells) + void countBC(int numberOfCollisions, bool hasEMCCells) { - int emcDataOffset = hasEMCcells ? 0 : 3; + int emcDataOffset = hasEMCCells ? 0 : 3; int collisionOffset = 2; switch (numberOfCollisions) { case 0: @@ -752,7 +828,7 @@ struct EmcalCorrectionTask { break; } mHistManager.fill(HIST("hBC"), 7); // All collisions - if (hasEMCcells) { + if (hasEMCCells) { mHistManager.fill(HIST("hBC"), 0); } mHistManager.fill(HIST("hBC"), 1 + emcDataOffset + collisionOffset); @@ -762,8 +838,12 @@ struct EmcalCorrectionTask { { // Cell QA // For convenience, use the clusterizer stored geometry to get the eta-phi - for (auto& cell : cellsBC) { + for (const auto& cell : cellsBC) { mHistManager.fill(HIST("hCellE"), cell.getEnergy()); + if (cell.getLowGain()) + mHistManager.fill(HIST("hLGCellTimeEnergy"), cell.getTimeStamp(), cell.getEnergy()); + else if (cell.getHighGain()) + mHistManager.fill(HIST("hHGCellTimeEnergy"), cell.getTimeStamp(), cell.getEnergy()); mHistManager.fill(HIST("hCellTowerID"), cell.getTower()); auto res = mClusterizers.at(0)->getGeometry()->EtaPhiFromIndex(cell.getTower()); mHistManager.fill(HIST("hCellEtaPhi"), std::get<0>(res), TVector2::Phi_0_2pi(std::get<1>(res))); @@ -773,26 +853,70 @@ struct EmcalCorrectionTask { } } - float GetAbsCellScale(const int cellID) + float getAbsCellScale(const int cellID) { // Apply cell scale based on SM types (Full, Half (not used), EMC 1/3, DCal, DCal 1/3) // Same as in Run2 data if (applyCellAbsScale == 1) { int iSM = mClusterizers.at(0)->getGeometry()->GetSuperModuleNumber(cellID); - return vCellAbsScaleFactor.value[mClusterizers.at(0)->getGeometry()->GetSMType(iSM)]; + return cellAbsScaleFactors.value[mClusterizers.at(0)->getGeometry()->GetSMType(iSM)]; // Apply cell scale based on columns to accoutn for material of TRD structures } else if (applyCellAbsScale == 2) { auto res = mClusterizers.at(0)->getGeometry()->GlobalRowColFromIndex(cellID); - return vCellAbsScaleFactor.value[std::get<1>(res)]; + return cellAbsScaleFactors.value[std::get<1>(res)]; } else { return 1.f; } } + + // Apply shift of the cell time in data and MC + // In MC this has to be done to shift the cell time, which is not calibrated to 0 due to the flight time of the particles to the EMCal surface (~15ns) + // In data this is done to correct for the time walk effect + float getCellTimeShift(const int16_t cellID, const float cellEnergy, const emcal::ChannelType_t cellType) + { + if (!applyCellTimeCorrection) { + return 0.f; + } + float timeshift = 0.f; + float timesmear = 0.f; + if (isMC) { // ---> MC + // Shift the time to 0, as the TOF was simulated -> eta dependent shift (as larger eta values are further away from collision point) + // Use distance between vertex and EMCal (at eta = 0) and distance on EMCal surface (cell size times column) to calculate distance to cell + // 0.2 is cell size in m (0.06) divided by the speed of light in m/ns (0.3) - 47.5 is the "middle" of the EMCal (2*48 cells in one column) + float timeCol = 0.2f * (geometry->GlobalCol(cellID) - 47.5f); // calculate time to get to specific column + timeshift = -std::sqrt(215.f + timeCol * timeCol); // 215 is 14.67ns^2 (time it takes to get the cell at eta = 0) + + // Also smear the time to account for the broader time resolution in data than in MC + if (cellEnergy < 0.3) // Cells with tless than 300 MeV cannot be the leading cell in the cluster, so their time does not require precise calibration + timesmear = 0.; // They will therefore not be smeared and only get their shift + else if (cellType == emcal::ChannelType_t::HIGH_GAIN) // High gain cells -> Low energies + timesmear = normalgaus(rdgen) * (1.6 + 9.5 * std::exp(-3. * cellEnergy)); // Parameters extracted from LHC24f3b & LHC22o (pp), but also usable for other periods + else if (cellType == emcal::ChannelType_t::LOW_GAIN) // Low gain cells -> High energies + timesmear = normalgaus(rdgen) * (5.0); // Parameters extracted from LHC24g4 & LHC24aj (pp), but also usable for other periods + + } else { // ---> Data + if (cellEnergy < 0.3) { // Cells with tless than 300 MeV cannot be the leading cell in the cluster, so their time does not require precise calibration + timeshift = 0.; // In data they will not be shifted (they are close to 0 anyways) + } else if (cellType == emcal::ChannelType_t::HIGH_GAIN) { // High gain cells -> Low energies + if (cellEnergy < 4.) // Low energy regime + timeshift = 0.8 * std::log(2.7 * cellEnergy); // Parameters extracted from LHC22o (pp), but also usable for other periods + else // Medium energy regime + timeshift = 1.5 * std::log(0.9 * cellEnergy); // Parameters extracted from LHC22o (pp), but also usable for other periods + } else if (cellType == emcal::ChannelType_t::LOW_GAIN) { // Low gain cells -> High energies + if (cellEnergy < 30.) // High energy regime + timeshift = 1.9 * std::log(0.09 * cellEnergy); // Parameters extracted from LHC24aj (pp), but also usable for other periods + else // Very high energy regime + timeshift = 1.9; // Parameters extracted from LHC24aj (pp), but also usable for other periods + } + LOG(debug) << "Shift the cell time by " << timeshift << " + " << timesmear << " ns"; + } + return timeshift + timesmear; + }; }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"emcal-correction-task"})}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGJE/TableProducer/eventwiseConstituentSubtractor.cxx b/PWGJE/TableProducer/eventwiseConstituentSubtractor.cxx index 4545796031c..cf545ba8295 100644 --- a/PWGJE/TableProducer/eventwiseConstituentSubtractor.cxx +++ b/PWGJE/TableProducer/eventwiseConstituentSubtractor.cxx @@ -31,9 +31,19 @@ using namespace o2::framework::expressions; struct eventWiseConstituentSubtractorTask { Produces trackSubtractedTable; + Produces particleSubtractedTable; Produces trackSubtractedD0Table; + Produces particleSubtractedD0Table; + Produces trackSubtractedDplusTable; + Produces particleSubtractedDplusTable; Produces trackSubtractedLcTable; + Produces particleSubtractedLcTable; Produces trackSubtractedBplusTable; + Produces particleSubtractedBplusTable; + Produces trackSubtractedDielectronTable; + Produces particleSubtractedDielectronTable; + + Configurable skipMBGapEvents{"skipMBGapEvents", true, "decide to run over MB gap events or not"}; Configurable trackPtMin{"trackPtMin", 0.15, "minimum track pT"}; Configurable trackPtMax{"trackPtMax", 1000.0, "maximum track pT"}; @@ -41,8 +51,11 @@ struct eventWiseConstituentSubtractorTask { Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track eta"}; Configurable trackPhiMin{"trackPhiMin", -999, "minimum track phi"}; Configurable trackPhiMax{"trackPhiMax", 999, "maximum track phi"}; + Configurable trackingEfficiency{"trackingEfficiency", 1.0, "tracking efficiency applied to jet finding"}; Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + Configurable particleSelections{"particleSelections", "PhysicalPrimary", "set particle selections"}; + Configurable alpha{"alpha", 1.0, "exponent of transverse momentum in calculating the distance measure between pairs"}; Configurable rMax{"rMax", 0.24, "maximum distance of subtraction"}; Configurable eventEtaMax{"eventEtaMax", 0.9, "maximum pseudorapidity of event"}; @@ -54,9 +67,14 @@ struct eventWiseConstituentSubtractorTask { std::vector tracksSubtracted; int trackSelection = -1; + std::string particleSelection; + + Service pdgDatabase; + void init(o2::framework::InitContext&) { trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + particleSelection = static_cast(particleSelections); eventWiseConstituentSubtractor.setDoRhoMassSub(doRhoMassSub); eventWiseConstituentSubtractor.setConstSubAlphaRMax(alpha, rMax); @@ -64,64 +82,131 @@ struct eventWiseConstituentSubtractorTask { } Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax && aod::jtrack::phi >= trackPhiMin && aod::jtrack::phi <= trackPhiMax); + Filter partCuts = (aod::jmcparticle::pt >= trackPtMin && aod::jmcparticle::pt < trackPtMax && aod::jmcparticle::eta >= trackEtaMin && aod::jmcparticle::eta <= trackEtaMax && aod::jmcparticle::phi >= trackPhiMin && aod::jmcparticle::phi <= trackPhiMax); - Preslice perD0Candidate = aod::bkgd0::candidateId; - Preslice perLcCandidate = aod::bkglc::candidateId; - Preslice perBplusCandidate = aod::bkgbplus::candidateId; - - template - void analyseHF(T const& tracks, U const& candidates, V const& bkgRhos, M& trackSubtractedTable) + template + void analyseHF(T const& tracks, U const& candidates, V& trackSubTable) { - for (auto& candidate : candidates) { + inputParticles.clear(); + tracksSubtracted.clear(); + jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, trackingEfficiency, std::optional{candidate}); - auto const bkgRhosSliced = jethfutilities::slicedPerCandidate(bkgRhos, candidate, perD0Candidate, perLcCandidate, perBplusCandidate); - auto const bkgRho = bkgRhosSliced.iteratorAt(0); + tracksSubtracted = eventWiseConstituentSubtractor.JetBkgSubUtils::doEventConstSub(inputParticles, candidate.rho(), candidate.rhoM()); + for (auto const& trackSubtracted : tracksSubtracted) { + trackSubTable(candidate.globalIndex(), trackSubtracted.pt(), trackSubtracted.eta(), trackSubtracted.phi(), jetderiveddatautilities::setSingleTrackSelectionBit(trackSelection)); + } + } + } + template + void analyseHFMc(T const& particles, U const& candidates, V& particleSubTable) + { + for (auto& candidate : candidates) { inputParticles.clear(); tracksSubtracted.clear(); - jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, std::optional{candidate}); + jetfindingutilities::analyseParticles(inputParticles, particleSelection, 1, particles, pdgDatabase, std::optional{candidate}); // currently only works for charged analyses - tracksSubtracted = eventWiseConstituentSubtractor.JetBkgSubUtils::doEventConstSub(inputParticles, bkgRho.rho(), bkgRho.rhoM()); + tracksSubtracted = eventWiseConstituentSubtractor.JetBkgSubUtils::doEventConstSub(inputParticles, candidate.rho(), candidate.rhoM()); for (auto const& trackSubtracted : tracksSubtracted) { - - trackSubtractedTable(candidate.globalIndex(), trackSubtracted.pt(), trackSubtracted.eta(), trackSubtracted.phi(), trackSubtracted.E(), jetderiveddatautilities::setSingleTrackSelectionBit(trackSelection)); + particleSubTable(candidate.globalIndex(), trackSubtracted.pt(), trackSubtracted.eta(), trackSubtracted.phi(), trackSubtracted.rap(), trackSubtracted.e(), 211, 1, 1, 1); // everything after phi is artificial and should not be used for analyses } } } - void processCollisions(soa::Join::iterator const& collision, soa::Filtered const& tracks) + void processCollisions(soa::Join::iterator const& collision, soa::Filtered const& tracks) { - + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } inputParticles.clear(); tracksSubtracted.clear(); - jetfindingutilities::analyseTracks, soa::Filtered::iterator>(inputParticles, tracks, trackSelection); + jetfindingutilities::analyseTracks, soa::Filtered::iterator>(inputParticles, tracks, trackSelection, trackingEfficiency); tracksSubtracted = eventWiseConstituentSubtractor.JetBkgSubUtils::doEventConstSub(inputParticles, collision.rho(), collision.rhoM()); for (auto const& trackSubtracted : tracksSubtracted) { - trackSubtractedTable(collision.globalIndex(), trackSubtracted.pt(), trackSubtracted.eta(), trackSubtracted.phi(), trackSubtracted.E(), jetderiveddatautilities::setSingleTrackSelectionBit(trackSelection)); + trackSubtractedTable(collision.globalIndex(), trackSubtracted.pt(), trackSubtracted.eta(), trackSubtracted.phi(), jetderiveddatautilities::setSingleTrackSelectionBit(trackSelection)); } } PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processCollisions, "Fill table of subtracted tracks for collisions", true); - void processD0Collisions(JetCollision const&, aod::BkgD0Rhos const& bkgRhos, soa::Filtered const& tracks, CandidatesD0Data const& candidates) + void processMcCollisions(soa::Join::iterator const& mcCollision, soa::Filtered const& particles) + { + if (skipMBGapEvents && mcCollision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + inputParticles.clear(); + tracksSubtracted.clear(); + jetfindingutilities::analyseParticles, soa::Filtered::iterator>(inputParticles, particleSelection, 1, particles, pdgDatabase); + + tracksSubtracted = eventWiseConstituentSubtractor.JetBkgSubUtils::doEventConstSub(inputParticles, mcCollision.rho(), mcCollision.rhoM()); + + for (auto const& trackSubtracted : tracksSubtracted) { + particleSubtractedTable(mcCollision.globalIndex(), trackSubtracted.pt(), trackSubtracted.eta(), trackSubtracted.phi(), trackSubtracted.rap(), trackSubtracted.e(), 211, 1, 1, 1); // everything after phi is artificial and should not be used for analyses + } + } + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processMcCollisions, "Fill table of subtracted tracks for Mc collisions", false); + + void processD0Collisions(aod::JetCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) { - analyseHF(tracks, candidates, bkgRhos, trackSubtractedD0Table); + analyseHF(tracks, candidates, trackSubtractedD0Table); } PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processD0Collisions, "Fill table of subtracted tracks for collisions with D0 candidates", false); - void processLcCollisions(JetCollision const&, aod::BkgLcRhos const& bkgRhos, soa::Filtered const& tracks, CandidatesLcData const& candidates) + void processD0McCollisions(aod::JetMcCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) + { + analyseHFMc(tracks, candidates, particleSubtractedD0Table); + } + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processD0McCollisions, "Fill table of subtracted tracks for collisions with D0 MCP candidates", false); + + void processDplusCollisions(aod::JetCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) + { + analyseHF(tracks, candidates, trackSubtractedDplusTable); + } + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processDplusCollisions, "Fill table of subtracted tracks for collisions with Dplus candidates", false); + + void processDplusMcCollisions(aod::JetMcCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) { - analyseHF(tracks, candidates, bkgRhos, trackSubtractedLcTable); + analyseHFMc(tracks, candidates, particleSubtractedDplusTable); + } + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processDplusMcCollisions, "Fill table of subtracted tracks for collisions with Dplus MCP candidates", false); + + void processLcCollisions(aod::JetCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) + { + analyseHF(tracks, candidates, trackSubtractedLcTable); } PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processLcCollisions, "Fill table of subtracted tracks for collisions with Lc candidates", false); - void processBplusCollisions(JetCollision const&, aod::BkgBplusRhos const& bkgRhos, soa::Filtered const& tracks, CandidatesBplusData const& candidates) + void processLcMcCollisions(aod::JetMcCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) + { + analyseHFMc(tracks, candidates, particleSubtractedLcTable); + } + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processLcMcCollisions, "Fill table of subtracted tracks for collisions with Lc MCP candidates", false); + + void processBplusCollisions(aod::JetCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) + { + analyseHF(tracks, candidates, trackSubtractedBplusTable); + } + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processBplusCollisions, "Fill table of subtracted tracks for collisions with Bplus candidates", false); + + void processBplusMcCollisions(aod::JetMcCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) + { + analyseHFMc(tracks, candidates, particleSubtractedBplusTable); + } + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processBplusMcCollisions, "Fill table of subtracted tracks for collisions with Bplus MCP candidates", false); + + void processDielectronCollisions(aod::JetCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) + { + analyseHF(tracks, candidates, trackSubtractedDielectronTable); + } + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processDielectronCollisions, "Fill table of subtracted tracks for collisions with Dielectron candidates", false); + + void processDielectronMcCollisions(aod::JetMcCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) { - analyseHF(tracks, candidates, bkgRhos, trackSubtractedBplusTable); + analyseHFMc(tracks, candidates, particleSubtractedDielectronTable); } - PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processBplusCollisions, "Fill table of subtracted tracks for collisions with Bplus candidates", false); + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processDielectronMcCollisions, "Fill table of subtracted tracks for collisions with Dielectron MCP candidates", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"subtractor-eventwiseconstituent"})}; } diff --git a/PWGJE/TableProducer/heavyFlavourDefinition.cxx b/PWGJE/TableProducer/heavyFlavourDefinition.cxx new file mode 100644 index 00000000000..f28368b10dc --- /dev/null +++ b/PWGJE/TableProducer/heavyFlavourDefinition.cxx @@ -0,0 +1,117 @@ +// 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 heavyFlavourDefinition.cxx +/// \brief Task to produce a table joinable to the jet tables for a flavour definition on MC +/// \author Hanseo Park + +#include +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "Common/Core/trackUtilities.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetTagging.h" +#include "PWGJE/Core/JetTaggingUtilities.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +template +struct HeavyFlavourDefinitionTask { + + Produces flavourTableMCD; + Produces flavourTableMCP; + + Configurable maxDeltaR{"maxDeltaR", 0.25, "maximum distance of jet axis from flavour initiating parton"}; + Configurable searchUpToQuark{"searchUpToQuark", true, "Finding first mother in particles to quark"}; + + using JetTracksMCD = soa::Join; + Preslice particlesPerCollision = aod::jmcparticle::mcCollisionId; + Preslice> particlesPerMcCollision = aod::jmcparticle::mcCollisionId; + + void init(InitContext const&) + { + } + + void processDummy(aod::JetCollisions const&) + { + } + PROCESS_SWITCH(HeavyFlavourDefinitionTask, processDummy, "Dummy process", true); + + void processMCDByConstituents(aod::JetCollision const& /*collision*/, JetTableMCD const& mcdjets, JetTracksMCD const& tracks, aod::JetParticles const& particles) + { + for (auto const& mcdjet : mcdjets) { + int8_t origin = jettaggingutilities::mcdJetFromHFShower(mcdjet, tracks, particles, maxDeltaR, searchUpToQuark); + flavourTableMCD(origin); + } + } + PROCESS_SWITCH(HeavyFlavourDefinitionTask, processMCDByConstituents, "Fill definition of flavour for mcd jets using constituents", false); + + void processMCDByDistance(soa::Join::iterator const& collision, soa::Join const& mcdjets, soa::Join const& /*mcpjets*/, aod::JetParticles const& particles) // it used only for charged jets now + { + for (auto const& mcdjet : mcdjets) { + auto const particlesPerColl = particles.sliceBy(particlesPerCollision, collision.mcCollisionId()); + int8_t origin = -1; + if (mcdjet.has_matchedJetGeo()) { + for (auto const& mcpjet : mcdjet.template matchedJetGeo_as>()) { + if (searchUpToQuark) { + origin = jettaggingutilities::getJetFlavor(mcpjet, particlesPerColl); + } else { + origin = jettaggingutilities::getJetFlavorHadron(mcpjet, particlesPerColl); + } + } + } else { + origin = JetTaggingSpecies::none; + } + flavourTableMCD(origin); + } + } + PROCESS_SWITCH(HeavyFlavourDefinitionTask, processMCDByDistance, "Fill definition of flavour for mcd jets using distance of jet with particles", false); + + void processMCPByConstituents(JetTableMCP const& mcpjets, aod::JetParticles const& particles) + { + for (auto const& mcpjet : mcpjets) { + int8_t origin = jettaggingutilities::mcpJetFromHFShower(mcpjet, particles, maxDeltaR, searchUpToQuark); + flavourTableMCP(origin); + } + } + PROCESS_SWITCH(HeavyFlavourDefinitionTask, processMCPByConstituents, "Fill definition of flavour for mcp jets using constituents", false); + + void processMCPByDistance(aod::JetMcCollision const& /*mcCollision*/, JetTableMCP const& mcpjets, aod::JetParticles const& particles) + { + for (auto const& mcpjet : mcpjets) { + int8_t origin = -1; + if (searchUpToQuark) { + origin = jettaggingutilities::getJetFlavor(mcpjet, particles); + } else { + origin = jettaggingutilities::getJetFlavorHadron(mcpjet, particles); + } + flavourTableMCP(origin); + } + } + PROCESS_SWITCH(HeavyFlavourDefinitionTask, processMCPByDistance, "Fill definition of flavour for mcp jets using distance of jet with particles", false); +}; + +using JetHfDefinitionCharged = HeavyFlavourDefinitionTask, soa::Join, aod::ChargedMCDetectorLevelJetFlavourDef, aod::ChargedMCParticleLevelJetFlavourDef>; +// using JetHfDefinitionFull = HeavyFlavourDefinitionTask, soa::Join, aod::FullMCDetectorLevelJetFlavourDef, aod::FullMCParticleLevelJetFlavourDef>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"jet-hf-definition-charged"})}; // o2-linter: disable=name/o2-task +} diff --git a/PWGJE/TableProducer/jeteventweightmcd.cxx b/PWGJE/TableProducer/jetEventWeightMCD.cxx similarity index 77% rename from PWGJE/TableProducer/jeteventweightmcd.cxx rename to PWGJE/TableProducer/jetEventWeightMCD.cxx index 3f888bf2bd0..0709a362d7f 100644 --- a/PWGJE/TableProducer/jeteventweightmcd.cxx +++ b/PWGJE/TableProducer/jetEventWeightMCD.cxx @@ -32,21 +32,21 @@ struct JetEventWeightMCDTask { Produces mcDetectorLevelWeightsTable; Produces mcDetectorLevelEventWiseSubtractedWeightsTable; - void processDummy(JetCollisions const&) + void processDummy(aod::JetCollisions const&) { } PROCESS_SWITCH(JetEventWeightMCDTask, processDummy, "Dummy process", true); - void processMCDetectorLevelEventWeight(MCDetectorLevelJetTable const& jet, soa::Join const&, JetMcCollisions const&) + void processMCDetectorLevelEventWeight(MCDetectorLevelJetTable const& jet, soa::Join const&, aod::JetMcCollisions const&) { - auto collision = jet.template collision_as>(); + auto collision = jet.template collision_as>(); mcDetectorLevelWeightsTable(jet.globalIndex(), collision.mcCollision().weight()); } PROCESS_SWITCH(JetEventWeightMCDTask, processMCDetectorLevelEventWeight, "Fill event weight tables for detector level MC jets", false); - void processMCDetectorLevelEventWiseSubtractedEventWeight(MCDetectorLevelEventWiseSubtractedJetTable const& jet, soa::Join const&, JetMcCollisions const&) + void processMCDetectorLevelEventWiseSubtractedEventWeight(MCDetectorLevelEventWiseSubtractedJetTable const& jet, soa::Join const&, aod::JetMcCollisions const&) { - auto collision = jet.template collision_as>(); + auto collision = jet.template collision_as>(); mcDetectorLevelEventWiseSubtractedWeightsTable(jet.globalIndex(), collision.mcCollision().weight()); } PROCESS_SWITCH(JetEventWeightMCDTask, processMCDetectorLevelEventWiseSubtractedEventWeight, "Fill event weight tables for detector level MC jets", false); @@ -56,8 +56,10 @@ using ChargedMCJetsEventWeight = JetEventWeightMCDTask; using FullMCJetsEventWeight = JetEventWeightMCDTask; using D0ChargedMCJetsEventWeight = JetEventWeightMCDTask; +using DplusChargedMCJetsEventWeight = JetEventWeightMCDTask; using LcChargedMCJetsEventWeight = JetEventWeightMCDTask; using BplusChargedMCJetsEventWeight = JetEventWeightMCDTask; +using V0ChargedMCJetsEventWeight = JetEventWeightMCDTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { @@ -80,6 +82,10 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-d0-eventweight-mcd-charged"})); + tasks.emplace_back( + adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, TaskName{"jet-dplus-eventweight-mcd-charged"})); + tasks.emplace_back( adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-lc-eventweight-mcd-charged"})); @@ -88,5 +94,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-bplus-eventweight-mcd-charged"})); + tasks.emplace_back( + adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, TaskName{"jet-v0-eventweight-mcd-charged"})); + return WorkflowSpec{tasks}; } diff --git a/PWGJE/TableProducer/jeteventweightmcp.cxx b/PWGJE/TableProducer/jetEventWeightMCP.cxx similarity index 82% rename from PWGJE/TableProducer/jeteventweightmcp.cxx rename to PWGJE/TableProducer/jetEventWeightMCP.cxx index 4844cfa72e1..5727cf57a43 100644 --- a/PWGJE/TableProducer/jeteventweightmcp.cxx +++ b/PWGJE/TableProducer/jetEventWeightMCP.cxx @@ -31,12 +31,12 @@ template mcParticleLevelWeightsTable; - void processDummy(JetMcCollisions const&) + void processDummy(aod::JetMcCollisions const&) { } PROCESS_SWITCH(JetEventWeightMCPTask, processDummy, "Dummy process", true); - void processMCParticleLevelEventWeight(MCParticleLevelJetTable const& jet, JetMcCollisions const&) + void processMCParticleLevelEventWeight(MCParticleLevelJetTable const& jet, aod::JetMcCollisions const&) { mcParticleLevelWeightsTable(jet.globalIndex(), jet.mcCollision().weight()); } @@ -47,8 +47,10 @@ using ChargedMCJetsEventWeight = JetEventWeightMCPTask; using FullMCJetsEventWeight = JetEventWeightMCPTask; using D0ChargedMCJetsEventWeight = JetEventWeightMCPTask; +using DplusChargedMCJetsEventWeight = JetEventWeightMCPTask; using LcChargedMCJetsEventWeight = JetEventWeightMCPTask; using BplusChargedMCJetsEventWeight = JetEventWeightMCPTask; +using V0ChargedMCJetsEventWeight = JetEventWeightMCPTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { @@ -71,6 +73,10 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-d0-eventweight-mcp-charged"})); + tasks.emplace_back( + adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, TaskName{"jet-dplus-eventweight-mcp-charged"})); + tasks.emplace_back( adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-lc-eventweight-mcp-charged"})); @@ -79,5 +85,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-bplus-eventweight-mcp-charged"})); + tasks.emplace_back( + adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, TaskName{"jet-v0-eventweight-mcp-charged"})); + return WorkflowSpec{tasks}; } diff --git a/PWGJE/TableProducer/jetTaggerHF.cxx b/PWGJE/TableProducer/jetTaggerHF.cxx new file mode 100644 index 00000000000..785118fa180 --- /dev/null +++ b/PWGJE/TableProducer/jetTaggerHF.cxx @@ -0,0 +1,527 @@ +// 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 jetTaggerHF.cxx +/// \brief Task to produce a table joinable to the jet tables for hf jet tagging +/// +/// \author Nima Zardoshti +/// \author Hanseo Park +/// \author Hadi Hassan , University of Jyväskylä + +#include +#include +#include +#include +#include + +#include +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "Common/Core/trackUtilities.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetTagging.h" +#include "PWGJE/Core/JetTaggingUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/MlResponseHfTagging.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +template +struct JetTaggerHFTask { + static constexpr double DefaultCutsMl[1][2] = {{0.5, 0.5}}; + + Produces taggingTable; + + // configuration topological cut for track and sv + Configurable trackDcaXYMax{"trackDcaXYMax", 1, "minimum DCA xy acceptance for tracks [cm]"}; + Configurable trackDcaZMax{"trackDcaZMax", 2, "minimum DCA z acceptance for tracks [cm]"}; + Configurable prongsigmaLxyMax{"prongsigmaLxyMax", 100, "maximum sigma of decay length of prongs on xy plane"}; + Configurable prongsigmaLxyzMax{"prongsigmaLxyzMax", 100, "maximum sigma of decay length of prongs on xyz plane"}; + Configurable prongIPxyMin{"prongIPxyMin", 0.008, "maximum impact paramter of prongs on xy plane [cm]"}; + Configurable prongIPxyMax{"prongIPxyMax", 1, "minimum impact parmeter of prongs on xy plane [cm]"}; + Configurable prongChi2PCAMin{"prongChi2PCAMin", 4, "minimum Chi2 PCA of decay length of prongs"}; + Configurable prongChi2PCAMax{"prongChi2PCAMax", 100, "maximum Chi2 PCA of decay length of prongs"}; + Configurable svDispersionMax{"svDispersionMax", 1, "maximum dispersion of sv"}; + + // configuration about IP method + Configurable useJetProb{"useJetProb", false, "fill table for track counting algorithm"}; + Configurable trackProbQA{"trackProbQA", false, "fill track probability histograms separately for geometric positive and negative tracks for QA"}; + Configurable numCount{"numCount", 3, "number of track counting"}; + Configurable resoFuncMatching{"resoFuncMatching", 0, "matching parameters of resolution function as MC samble (0: custom, 1: custom & inc, 2: MB, 3: MB & inc, 4: JJ, 5: JJ & inc)"}; + Configurable> pathsCCDBforIPparamer{"pathsCCDBforIPparamer", std::vector{"Users/l/leehy/LHC24g4/f_inclusive_0"}, "Paths for fitting parameters of resolution functions for IP method on CCDB"}; + Configurable usepTcategorize{"usepTcategorize", false, "p_T categorize TF1 function with Inclusive jet"}; + Configurable> paramsResoFuncData{"paramsResoFuncData", std::vector{-1.0}, "parameters of gaus(0)+expo(3)+expo(5)+expo(7))"}; + Configurable> paramsResoFuncIncJetMC{"paramsResoFuncIncJetMC", std::vector{-1.0}, "parameters of gaus(0)+expo(3)+expo(5)+expo(7)))"}; + Configurable> paramsResoFuncCharmJetMC{"paramsResoFuncCharmJetMC", std::vector{-1.0}, "parameters of gaus(0)+expo(3)+expo(5)+expo(7)))"}; + Configurable> paramsResoFuncBeautyJetMC{"paramsResoFuncBeautyJetMC", std::vector{-1.0}, "parameters of gaus(0)+expo(3)+expo(5)+expo(7)))"}; + Configurable> paramsResoFuncLfJetMC{"paramsResoFuncLfJetMC", std::vector{-1.0}, "parameters of gaus(0)+expo(3)+expo(5)+expo(7)))"}; + Configurable minSignImpXYSig{"minSignImpXYSig", -40.0, "minimum of signed impact parameter significance"}; + Configurable tagPointForIP{"tagPointForIP", 2.5, "tagging working point for IP"}; + Configurable tagPointForIPxyz{"tagPointForIPxyz", 2.5, "tagging working point for IP xyz"}; + // configuration about SV method + Configurable tagPointForSV{"tagPointForSV", 40, "tagging working point for SV"}; + Configurable tagPointForSVxyz{"tagPointForSVxyz", 40, "tagging working point for SV xyz"}; + + // ML configuration + Configurable nJetConst{"nJetConst", 10, "maximum number of jet consistuents to be used for ML evaluation"}; + Configurable trackPtMin{"trackPtMin", 0.5, "minimum track pT"}; + Configurable svPtMin{"svPtMin", 0.5, "minimum SV pT"}; + + Configurable svReductionFactor{"svReductionFactor", 1.0, "factor for how many SVs to keep"}; + + Configurable> binsPtMl{"binsPtMl", std::vector{5., 1000.}, "pT bin limits for ML application"}; + Configurable> cutDirMl{"cutDirMl", std::vector{cuts_ml::CutSmaller, cuts_ml::CutNot}, "Whether to reject score values greater or smaller than the threshold"}; + Configurable> cutsMl{"cutsMl", {DefaultCutsMl[0], 1, 2, {"pT bin 0"}, {"score for default b-jet tagging", "uncer 1"}}, "ML selections per pT bin"}; + Configurable nClassesMl{"nClassesMl", 2, "Number of classes in ML model"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; + + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"Users/h/hahassan"}, "Paths of models on CCDB"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"ML_bjets/Models/LHC24g4_70_200/model.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + + // GNN configuration + Configurable fC{"fC", 0.018, "Parameter f_c for D_b calculation"}; + Configurable nJetFeat{"nJetFeat", 4, "Number of jet GNN input features"}; + Configurable nTrkFeat{"nTrkFeat", 13, "Number of track GNN input features"}; + Configurable nTrkOrigin{"nTrkOrigin", 5, "Number of track origin categories"}; + Configurable> transformFeatureJetMean{"transformFeatureJetMean", + std::vector{-999}, + "Mean values for each GNN input feature (jet)"}; + Configurable> transformFeatureJetStdev{"transformFeatureJetStdev", + std::vector{-999}, + "Stdev values for each GNN input feature (jet)"}; + Configurable> transformFeatureTrkMean{"transformFeatureTrkMean", + std::vector{-999}, + "Mean values for each GNN input feature (track)"}; + Configurable> transformFeatureTrkStdev{"transformFeatureTrkStdev", + std::vector{-999}, + "Stdev values for each GNN input feature (track)"}; + + // axis spec + ConfigurableAxis binTrackProbability{"binTrackProbability", {100, 0.f, 1.f}, ""}; + ConfigurableAxis binJetFlavour{"binJetFlavour", {6, -0.5, 5.5}, ""}; + + o2::analysis::MlResponseHfTagging bMlResponse; + o2::ccdb::CcdbApi ccdbApi; + + using JetTracksExt = soa::Join; + using OriginalTracks = soa::Join; + + bool useResoFuncFromIncJet = false; + int maxOrder = -1; + int resoFuncMatch = 0; + + std::unique_ptr fSignImpXYSigData = nullptr; + std::unique_ptr fSignImpXYSigIncJetMC = nullptr; + std::unique_ptr fSignImpXYSigCharmJetMC = nullptr; + std::unique_ptr fSignImpXYSigBeautyJetMC = nullptr; + std::unique_ptr fSignImpXYSigLfJetMC = nullptr; + + std::vector> vecParamsIncJetMcCCDB; + std::vector> vecfSignImpXYSigIncJetMcCCDB; + + std::vector decisionNonML; + std::vector scoreML; + + o2::analysis::GNNBjetAllocator tensorAlloc; + + template + float calculateJetProbability(int origin, T const& jet, U const& tracks, bool const& isMC = false) + { + float jetProb = -1.0; + if (!isMC) { + jetProb = jettaggingutilities::getJetProbability(fSignImpXYSigData, jet, tracks, trackDcaXYMax, trackDcaZMax, minSignImpXYSig); + } else { + if (useResoFuncFromIncJet) { + if (usepTcategorize) { + jetProb = jettaggingutilities::getJetProbability(vecfSignImpXYSigIncJetMcCCDB, jet, tracks, trackDcaXYMax, trackDcaZMax, minSignImpXYSig); + } else { + jetProb = jettaggingutilities::getJetProbability(fSignImpXYSigIncJetMC, jet, tracks, trackDcaXYMax, trackDcaZMax, minSignImpXYSig); + } + } else { + if (origin == JetTaggingSpecies::charm) { + jetProb = jettaggingutilities::getJetProbability(fSignImpXYSigCharmJetMC, jet, tracks, trackDcaXYMax, trackDcaZMax, minSignImpXYSig); + } else if (origin == JetTaggingSpecies::beauty) { + jetProb = jettaggingutilities::getJetProbability(fSignImpXYSigBeautyJetMC, jet, tracks, trackDcaXYMax, trackDcaZMax, minSignImpXYSig); + } else { + jetProb = jettaggingutilities::getJetProbability(fSignImpXYSigLfJetMC, jet, tracks, trackDcaXYMax, trackDcaZMax, minSignImpXYSig); + } + } + } + return jetProb; + } + + template + void evaluateTrackProbQA(int origin, T const& jet, U const& /*tracks*/, bool const& isMC = true) + { + for (const auto& track : jet.template tracks_as()) { + if (!jettaggingutilities::trackAcceptanceWithDca(track, trackDcaXYMax, trackDcaZMax)) + continue; + auto geoSign = jettaggingutilities::getGeoSign(jet, track); + float probTrack = -1; + if (!isMC) { + probTrack = jettaggingutilities::getTrackProbability(fSignImpXYSigData, track, minSignImpXYSig); + if (geoSign > 0) + registry.fill(HIST("h_pos_track_probability"), probTrack); + else + registry.fill(HIST("h_neg_track_probability"), probTrack); + } else { + if (useResoFuncFromIncJet) { + probTrack = jettaggingutilities::getTrackProbability(fSignImpXYSigIncJetMC, track, minSignImpXYSig); + } else { + if (origin == JetTaggingSpecies::charm) { + probTrack = jettaggingutilities::getTrackProbability(fSignImpXYSigCharmJetMC, track, minSignImpXYSig); + } + if (origin == JetTaggingSpecies::beauty) { + probTrack = jettaggingutilities::getTrackProbability(fSignImpXYSigBeautyJetMC, track, minSignImpXYSig); + } + if (origin == JetTaggingSpecies::lightflavour) { + probTrack = jettaggingutilities::getTrackProbability(fSignImpXYSigLfJetMC, track, minSignImpXYSig); + } + } + if (geoSign > 0) + registry.fill(HIST("h2_pos_track_probability_flavour"), probTrack, origin); + else + registry.fill(HIST("h2_neg_track_probability_flavour"), probTrack, origin); + } + } + } + + template + void fillTables(T const& jet, U const& tracks) + { + int origin = -1; + float jetProb = -1.0; + if constexpr (isMC) { + origin = jet.origin(); + } + if (useJetProb) { + if constexpr (isMC) { + jetProb = calculateJetProbability(origin, jet, tracks); + if (trackProbQA) { + evaluateTrackProbQA(origin, jet, tracks, isMC); + } + } else { + jetProb = calculateJetProbability(0, jet, tracks); + if (trackProbQA) { + evaluateTrackProbQA(0, jet, tracks, isMC); + } + } + } + if (doprocessAlgorithmGNN) { + if constexpr (isMC) { + switch (origin) { + case 2: + registry.fill(HIST("h_db_b"), scoreML[jet.globalIndex()]); + break; + case 1: + registry.fill(HIST("h_db_c"), scoreML[jet.globalIndex()]); + break; + case 0: + case 3: + registry.fill(HIST("h_db_lf"), scoreML[jet.globalIndex()]); + break; + default: + LOGF(debug, "doprocessAlgorithmGNN, Unexpected origin value: %d (%d)", origin, jet.globalIndex()); + } + } + registry.fill(HIST("h2_pt_db"), jet.pt(), scoreML[jet.globalIndex()]); + } + taggingTable(decisionNonML[jet.globalIndex()], jetProb, scoreML[jet.globalIndex()]); + } + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + void init(InitContext const&) + { + std::vector vecParamsData; + std::vector vecParamsIncJetMC; + std::vector vecParamsCharmJetMC; + std::vector vecParamsBeautyJetMC; + std::vector vecParamsLfJetMC; + std::vector resoFuncCCDB; + + ccdbApi.init(ccdbUrl); + if (usepTcategorize) { + std::map metadata; // dummy meta data (will be updated) + // fill the timestamp directly of each TF1 according to p_T track range (0, 0.5, 1, 2, 4, 6, 9) + for (int i = 0; i < 7; i++) { + resoFuncCCDB.push_back(ccdbApi.retrieveFromTFileAny(pathsCCDBforIPparamer->at(i), metadata, -1)); + } + } + + maxOrder = numCount + 1; // 0: untagged, >1 : N ordering + + // Set up the resolution function + resoFuncMatch = resoFuncMatching; + switch (resoFuncMatch) { + case 0: + vecParamsData = (std::vector)paramsResoFuncData; + vecParamsCharmJetMC = (std::vector)paramsResoFuncCharmJetMC; + vecParamsBeautyJetMC = (std::vector)paramsResoFuncBeautyJetMC; + vecParamsLfJetMC = (std::vector)paramsResoFuncLfJetMC; + LOG(info) << "defined parameters of resolution function: custom"; + break; + case 1: + vecParamsData = (std::vector)paramsResoFuncData; + vecParamsIncJetMC = (std::vector)paramsResoFuncIncJetMC; + useResoFuncFromIncJet = true; + LOG(info) << "defined parameters of resolution function: custom & use inclusive distribution"; + break; + case 2: // TODO + vecParamsData = (std::vector)paramsResoFuncData; + vecParamsCharmJetMC = {282119.753, -0.065, 0.893, 11.608, 0.945, 8.029, 0.131, 6.244, 0.027}; + vecParamsBeautyJetMC = {74901.583, -0.082, 0.874, 10.332, 0.941, 7.352, 0.097, 6.220, 0.022}; + vecParamsLfJetMC = {1539435.343, -0.061, 0.896, 13.272, 1.034, 5.884, 0.004, 7.843, 0.090}; + LOG(info) << "defined parameters of resolution function: PYTHIA8, MB, LHC23d1k"; + break; + case 3: // TODO + vecParamsData = (std::vector)paramsResoFuncData; + vecParamsIncJetMC = {1908803.027, -0.059, 0.895, 13.467, 1.005, 8.867, 0.098, 6.929, 0.011}; + LOG(info) << "defined parameters of resolution function: PYTHIA8, MB, LHC23d1k & use inclusive distribution"; + useResoFuncFromIncJet = true; + break; + case 4: // TODO + vecParamsData = (std::vector)paramsResoFuncData; + vecParamsCharmJetMC = {743719.121, -0.960, -0.240, 13.765, 1.314, 10.761, 0.293, 8.538, 0.052}; + vecParamsBeautyJetMC = {88888.418, 0.256, 1.003, 10.185, 0.740, 8.216, 0.147, 7.228, 0.040}; + vecParamsLfJetMC = {414860.372, -1.000, 0.285, 14.561, 1.464, 11.693, 0.339, 9.183, 0.052}; + LOG(info) << "defined parameters of resolution function: PYTHIA8, JJ, weighted, LHC24g4"; + break; + case 5: // TODO + vecParamsData = (std::vector)paramsResoFuncData; + vecParamsIncJetMC = {2211391.862, 0.360, 1.028, 13.019, 0.650, 11.151, 0.215, 9.462, 0.044}; + LOG(info) << "defined parameters of resolution function: PYTHIA8, JJ, weighted, LHC24g4 & use inclusive distribution"; + useResoFuncFromIncJet = true; + break; + case 6: // TODO + vecParamsData = (std::vector)paramsResoFuncData; + vecParamsIncJetMC = (std::vector)paramsResoFuncData; + for (size_t j = 0; j < resoFuncCCDB.size(); j++) { + std::vector params; + if (resoFuncCCDB[j]) { + for (int i = 0; i < 9; i++) { + params.emplace_back(resoFuncCCDB[j]->GetParameter(i)); + } + } + vecParamsIncJetMcCCDB.emplace_back(params); + } + LOG(info) << "defined parameters of resolution function from CCDB"; + useResoFuncFromIncJet = true; + break; + default: + LOG(fatal) << "undefined parameters of resolution function. Fix it!"; + break; + } + + fSignImpXYSigData = jettaggingutilities::setResolutionFunction(vecParamsData); + fSignImpXYSigIncJetMC = jettaggingutilities::setResolutionFunction(vecParamsIncJetMC); + fSignImpXYSigCharmJetMC = jettaggingutilities::setResolutionFunction(vecParamsCharmJetMC); + fSignImpXYSigBeautyJetMC = jettaggingutilities::setResolutionFunction(vecParamsBeautyJetMC); + fSignImpXYSigLfJetMC = jettaggingutilities::setResolutionFunction(vecParamsLfJetMC); + + for (const auto& params : vecParamsIncJetMcCCDB) { + vecfSignImpXYSigIncJetMcCCDB.emplace_back(jettaggingutilities::setResolutionFunction(params)); + } + + // Use QA for effectivness of track probability + if (trackProbQA) { + AxisSpec trackProbabilityAxis = {binTrackProbability, "Track proability"}; + AxisSpec jetFlavourAxis = {binJetFlavour, "Jet flavour"}; + if (doprocessFillTables) { + if (isMCD) { + registry.add("h2_pos_track_probability_flavour", "positive track probability", {HistType::kTH2F, {{trackProbabilityAxis}, {jetFlavourAxis}}}); + registry.add("h2_neg_track_probability_flavour", "negative track probability", {HistType::kTH2F, {{trackProbabilityAxis}, {jetFlavourAxis}}}); + } else { + registry.add("h_pos_track_probability", "positive track probability", {HistType::kTH1F, {{trackProbabilityAxis}}}); + registry.add("h_neg_track_probability", "negative track probability", {HistType::kTH1F, {{trackProbabilityAxis}}}); + } + } + } + + if (doprocessAlgorithmML || doprocessAlgorithmGNN) { + bMlResponse.configure(binsPtMl, cutsMl, cutDirMl, nClassesMl); + if (loadModelsFromCCDB) { + ccdbApi.init(ccdbUrl); + bMlResponse.setModelPathsCCDB(onnxFileNames, ccdbApi, modelPathsCCDB, timestampCCDB); + } else { + bMlResponse.setModelPathsLocal(onnxFileNames); + } + bMlResponse.cacheInputFeaturesIndices(namesInputFeatures); + bMlResponse.init(); + } + + if (doprocessAlgorithmGNN) { + tensorAlloc = o2::analysis::GNNBjetAllocator(nJetFeat.value, nTrkFeat.value, nClassesMl.value, nTrkOrigin.value, transformFeatureJetMean.value, transformFeatureJetStdev.value, transformFeatureTrkMean.value, transformFeatureTrkStdev.value, nJetConst); + registry.add("h_db_b", "#it{D}_{b} b-jet;#it{D}_{b}", {HistType::kTH1F, {{50, -10., 35.}}}); + registry.add("h_db_c", "#it{D}_{b} c-jet;#it{D}_{b}", {HistType::kTH1F, {{50, -10., 35.}}}); + registry.add("h_db_lf", "#it{D}_{b} lf-jet;#it{D}_{b}", {HistType::kTH1F, {{50, -10., 35.}}}); + registry.add("h2_pt_db", "#it{p}_{T} vs. #it{D}_{b};#it{p}_{T}^{ch jet} (GeV/#it{c}^{2});#it{D}_{b}", {HistType::kTH2F, {{100, 0., 200.}, {50, -10., 35.}}}); + } + } + + template + void analyzeJetAlgorithmML(AnyJets const& alljets, AnyTracks const& allTracks, SecondaryVertices const& allSVs) + { + for (const auto& analysisJet : alljets) { + + std::vector tracksParams; + std::vector svsParams; + + jettaggingutilities::analyzeJetSVInfo4ML(analysisJet, allTracks, allSVs, svsParams, svPtMin, svReductionFactor); + jettaggingutilities::analyzeJetTrackInfo4ML(analysisJet, allTracks, allSVs, tracksParams, trackPtMin); + + int nSVs = analysisJet.template secondaryVertices_as().size(); + + jettaggingutilities::BJetParams jetparam = {analysisJet.pt(), analysisJet.eta(), analysisJet.phi(), static_cast(tracksParams.size()), static_cast(nSVs), analysisJet.mass()}; + tracksParams.resize(nJetConst); // resize to the number of inputs of the ML + svsParams.resize(nJetConst); // resize to the number of inputs of the ML + + std::vector output; + + if (bMlResponse.getInputShape().size() > 1) { + auto inputML = bMlResponse.getInputFeatures2D(jetparam, tracksParams, svsParams); + bMlResponse.isSelectedMl(inputML, analysisJet.pt(), output); + } else { + auto inputML = bMlResponse.getInputFeatures1D(jetparam, tracksParams, svsParams); + bMlResponse.isSelectedMl(inputML, analysisJet.pt(), output); + } + + scoreML[analysisJet.globalIndex()] = output[0]; + } + } + + template + void analyzeJetAlgorithmMLnoSV(AnyJets const& alljets, AnyTracks const& allTracks) + { + for (const auto& analysisJet : alljets) { + + std::vector tracksParams; + std::vector svsParams; + + jettaggingutilities::analyzeJetTrackInfo4MLnoSV(analysisJet, allTracks, tracksParams, trackPtMin); + + jettaggingutilities::BJetParams jetparam = {analysisJet.pt(), analysisJet.eta(), analysisJet.phi(), static_cast(tracksParams.size()), 0, analysisJet.mass()}; + tracksParams.resize(nJetConst); // resize to the number of inputs of the ML + + std::vector output; + + if (bMlResponse.getInputShape().size() > 1) { + auto inputML = bMlResponse.getInputFeatures2D(jetparam, tracksParams, svsParams); + bMlResponse.isSelectedMl(inputML, analysisJet.pt(), output); + } else { + auto inputML = bMlResponse.getInputFeatures1D(jetparam, tracksParams, svsParams); + bMlResponse.isSelectedMl(inputML, analysisJet.pt(), output); + } + + scoreML[analysisJet.globalIndex()] = output[0]; + } + } + + template + void analyzeJetAlgorithmGNN(AnyJets const& jets, AnyTracks const& tracks, AnyOriginalTracks const& origTracks) + { + for (const auto& jet : jets) { + std::vector> trkFeat; + jettaggingutilities::analyzeJetTrackInfo4GNN(jet, tracks, origTracks, trkFeat, trackPtMin, nJetConst); + + std::vector jetFeat{jet.pt(), jet.phi(), jet.eta(), jet.mass()}; + + if (trkFeat.size() > 0) { + std::vector feat; + std::vector gnnInput; + tensorAlloc.getGNNInput(jetFeat, trkFeat, feat, gnnInput); + + auto modelOutput = bMlResponse.getModelOutput(gnnInput, 0); + scoreML[jet.globalIndex()] = jettaggingutilities::getDb(modelOutput, fC); + } else { + scoreML[jet.globalIndex()] = -999.; + LOGF(debug, "doprocessAlgorithmGNN, trkFeat.size() <= 0 (%d)", jet.globalIndex()); + } + } + } + + void processDummy(aod::JetCollisions const&) + { + } + PROCESS_SWITCH(JetTaggerHFTask, processDummy, "Dummy process", true); + + void processSetup(JetTable const& jets) + { + decisionNonML.clear(); + scoreML.clear(); + decisionNonML.resize(jets.size()); + scoreML.resize(jets.size()); + } + PROCESS_SWITCH(JetTaggerHFTask, processSetup, "Setup initialization and size of jets for filling table", false); + + void processIP(JetTable const& jets, JetTracksExt const& tracks) + { + for (const auto& jet : jets) { + uint16_t bit = jettaggingutilities::setTaggingIPBit(jet, tracks, trackDcaXYMax, trackDcaZMax, tagPointForIP); + decisionNonML[jet.globalIndex()] |= bit; + } + } + PROCESS_SWITCH(JetTaggerHFTask, processIP, "Fill tagging decision for jet with the IP algorithm", false); + + void processSV(soa::Join const& jets, SVTable const& prongs) + { + for (const auto& jet : jets) { + uint16_t bit = jettaggingutilities::setTaggingSVBit(jet, prongs, prongChi2PCAMin, prongChi2PCAMax, prongsigmaLxyMax, prongIPxyMin, prongIPxyMax, svDispersionMax, tagPointForSV); + decisionNonML[jet.globalIndex()] |= bit; + } + } + PROCESS_SWITCH(JetTaggerHFTask, processSV, "Fill tagging decision for jets with the SV", false); + + void processAlgorithmML(soa::Join const& allJets, JetTracksExt const& allTracks, SVTable const& allSVs) + { + analyzeJetAlgorithmML(allJets, allTracks, allSVs); + } + PROCESS_SWITCH(JetTaggerHFTask, processAlgorithmML, "Fill ML evaluation score for charged jets", false); + + void processAlgorithmMLnoSV(JetTable const& allJets, JetTracksExt const& allTracks) + { + analyzeJetAlgorithmMLnoSV(allJets, allTracks); + } + PROCESS_SWITCH(JetTaggerHFTask, processAlgorithmMLnoSV, "Fill ML evaluation score for charged jets but without using SVs", false); + + void processAlgorithmGNN(JetTable const& jets, JetTracksExt const& jtracks, OriginalTracks const& origTracks) + { + analyzeJetAlgorithmGNN(jets, jtracks, origTracks); + } + PROCESS_SWITCH(JetTaggerHFTask, processAlgorithmGNN, "Fill GNN evaluation score (D_b) for charged jets", false); + + void processFillTables(std::conditional_t, JetTable>::iterator const& jet, JetTracksExt const& tracks) + { + fillTables(jet, tracks); + } + PROCESS_SWITCH(JetTaggerHFTask, processFillTables, "Fill Tables for tagging decision, jet probability, and ML score on charged jets", false); +}; + +using JetTaggerhfDataCharged = JetTaggerHFTask, aod::DataSecondaryVertex3ProngIndices, aod::DataSecondaryVertex3Prongs, aod::ChargedJetTags>; +using JetTaggerhfMCDCharged = JetTaggerHFTask, aod::MCDSecondaryVertex3ProngIndices, aod::MCDSecondaryVertex3Prongs, aod::ChargedMCDetectorLevelJetTags>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + + return WorkflowSpec{ + adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-taggerhf-data-charged"}), // o2-linter: disable=name/o2-task + adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-taggerhf-mcd-charged"})}; // o2-linter: disable=name/o2-task +} diff --git a/PWGJE/TableProducer/jettrackderived.cxx b/PWGJE/TableProducer/jetTrackDerived.cxx similarity index 100% rename from PWGJE/TableProducer/jettrackderived.cxx rename to PWGJE/TableProducer/jetTrackDerived.cxx diff --git a/PWGJE/TableProducer/jetderiveddataproducer.cxx b/PWGJE/TableProducer/jetderiveddataproducer.cxx deleted file mode 100644 index 556b436140b..00000000000 --- a/PWGJE/TableProducer/jetderiveddataproducer.cxx +++ /dev/null @@ -1,242 +0,0 @@ -// 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. - -// task to produce a self contained data format for jet analyses from the full AO2D -// -/// \author Nima Zardoshti - -#include -#include - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "TDatabasePDG.h" - -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/Centrality.h" -#include "Common/Core/RecoDecay.h" -#include "PWGJE/DataModel/EMCALClusters.h" - -#include "EventFiltering/filterTables.h" - -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct JetDerivedDataProducerTask { - Produces collisionCountsTable; - Produces jDummysTable; - Produces jBCsTable; - Produces jBCParentIndexTable; - Produces jCollisionsTable; - Produces jCollisionsParentIndexTable; - Produces jCollisionsBunchCrossingIndexTable; - Produces jMcCollisionsLabelTable; - Produces jMcCollisionsTable; - Produces jMcCollisionsParentIndexTable; - Produces jTracksTable; - Produces jTracksParentIndexTable; - Produces jMcTracksLabelTable; - Produces jMcParticlesTable; - Produces jParticlesParentIndexTable; - Produces jClustersTable; - Produces jClustersParentIndexTable; - Produces jClustersMatchedTracksTable; - Produces jD0IdsTable; - Produces jD0ParticleIdsTable; - Produces jLcIdsTable; - Produces jLcParticleIdsTable; - - Preslice perClusterCells = aod::emcalclustercell::emcalclusterId; - Preslice perClusterTracks = aod::emcalclustercell::emcalclusterId; - - void init(InitContext const&) - { - } - - void processCollisionCounts(aod::Collisions const&) - { - std::vector readCounts = {0}; - std::vector writtenCounts = {0}; - collisionCountsTable(readCounts, writtenCounts); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processCollisionCounts, "produces collision counting table", false); - - void processBunchCrossings(soa::Join::iterator const& bc) - { - jBCsTable(bc.runNumber(), bc.globalBC(), bc.timestamp()); - jBCParentIndexTable(bc.globalIndex()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processBunchCrossings, "produces derived bunch crossing table", false); - - void processCollisions(soa::Join::iterator const& collision) - { - jCollisionsTable(collision.posX(), collision.posY(), collision.posZ(), collision.multFT0C(), collision.centFT0C(), jetderiveddatautilities::setEventSelectionBit(collision), collision.alias_raw()); // note change multFT0C to multFT0M when problems with multFT0A are fixed - jCollisionsParentIndexTable(collision.globalIndex()); - jCollisionsBunchCrossingIndexTable(collision.bcId()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processCollisions, "produces derived collision tables", true); - - void processCollisionsWithoutCentralityAndMultiplicity(soa::Join::iterator const& collision) - { - jCollisionsTable(collision.posX(), collision.posY(), collision.posZ(), -1.0, -1.0, jetderiveddatautilities::setEventSelectionBit(collision), collision.alias_raw()); - jCollisionsParentIndexTable(collision.globalIndex()); - jCollisionsBunchCrossingIndexTable(collision.bcId()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processCollisionsWithoutCentralityAndMultiplicity, "produces derived collision tables without centrality or multiplicity", false); - - void processCollisionsRun2(soa::Join::iterator const& collision) - { - jCollisionsTable(collision.posX(), collision.posY(), collision.posZ(), collision.multFT0C(), collision.centRun2V0M(), jetderiveddatautilities::setEventSelectionBit(collision), collision.alias_raw()); // note change multFT0C to multFT0M when problems with multFT0A are fixed - jCollisionsParentIndexTable(collision.globalIndex()); - jCollisionsBunchCrossingIndexTable(collision.bcId()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processCollisionsRun2, "produces derived collision tables for Run 2 data", false); - - void processMcCollisionLabels(soa::Join::iterator const& collision) - { - - if (collision.has_mcCollision()) { - jMcCollisionsLabelTable(collision.mcCollisionId()); - } else { - jMcCollisionsLabelTable(-1); - } - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processMcCollisionLabels, "produces derived MC collision labels table", false); - - void processMcCollisions(aod::McCollision const& McCollision) - { - jMcCollisionsTable(McCollision.posX(), McCollision.posY(), McCollision.posZ(), McCollision.weight()); - jMcCollisionsParentIndexTable(McCollision.globalIndex()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processMcCollisions, "produces derived MC collision table", false); - - void processTracks(soa::Join::iterator const& track) - { - jTracksTable(track.collisionId(), track.pt(), track.eta(), track.phi(), jetderiveddatautilities::setTrackSelectionBit(track)); - jTracksParentIndexTable(track.globalIndex()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processTracks, "produces derived track table", true); - - void processMcTrackLabels(soa::Join::iterator const& track) - { - if (track.has_mcParticle()) { - jMcTracksLabelTable(track.mcParticleId()); - } else { - jMcTracksLabelTable(-1); - } - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processMcTrackLabels, "produces derived track labels table", false); - - void processParticles(aod::McParticle const& particle) - { - std::vector mothersId; - if (particle.has_mothers()) { - auto mothersIdTemps = particle.mothersIds(); - for (auto mothersIdTemp : mothersIdTemps) { - mothersId.push_back(mothersIdTemp); - } - } - int daughtersId[2] = {-1, -1}; - auto i = 0; - if (particle.has_daughters()) { - for (auto daughterId : particle.daughtersIds()) { - if (i > 1) { - break; - } - daughtersId[i] = daughterId; - i++; - } - } - jMcParticlesTable(particle.mcCollisionId(), particle.pt(), particle.eta(), particle.phi(), particle.y(), particle.e(), particle.pdgCode(), particle.getGenStatusCode(), particle.getHepMCStatusCode(), particle.isPhysicalPrimary(), mothersId, daughtersId); - jParticlesParentIndexTable(particle.globalIndex()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processParticles, "produces derived parrticle table", false); - - void processClusters(aod::Collision const&, aod::EMCALClusters const& clusters, aod::EMCALClusterCells const& cells, aod::Calos const&, aod::EMCALMatchedTracks const& matchedTracks, aod::Tracks const&) - { - - for (auto cluster : clusters) { - - auto const clusterCells = cells.sliceBy(perClusterCells, cluster.globalIndex()); - - float leadingCellEnergy = -1.0; - float subleadingCellEnergy = -1.0; - float cellAmplitude = -1.0; - int leadingCellNumber = -1; - int subleadingCellNumber = -1; - int cellNumber = -1; - for (auto const& clutserCell : clusterCells) { - cellAmplitude = clutserCell.calo().amplitude(); - cellNumber = clutserCell.calo().cellNumber(); - if (cellAmplitude > subleadingCellEnergy) { - subleadingCellEnergy = cellAmplitude; - subleadingCellNumber = cellNumber; - } - if (subleadingCellEnergy > leadingCellEnergy) { - std::swap(leadingCellEnergy, subleadingCellEnergy); - std::swap(leadingCellNumber, subleadingCellNumber); - } - } - - jClustersTable(cluster.collisionId(), cluster.id(), cluster.energy(), cluster.coreEnergy(), cluster.rawEnergy(), cluster.eta(), cluster.phi(), cluster.m02(), cluster.m20(), cluster.nCells(), cluster.time(), cluster.isExotic(), cluster.distanceToBadChannel(), cluster.nlm(), cluster.definition(), leadingCellEnergy, subleadingCellEnergy, leadingCellNumber, subleadingCellNumber); - jClustersParentIndexTable(cluster.globalIndex()); - - auto const clusterTracks = matchedTracks.sliceBy(perClusterTracks, cluster.globalIndex()); - std::vector clusterTrackIDs; - for (const auto& clusterTrack : clusterTracks) { - clusterTrackIDs.push_back(clusterTrack.trackId()); - } - jClustersMatchedTracksTable(clusterTrackIDs); - } - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processClusters, "produces derived cluster tables", false); - - void processD0(aod::HfD0Ids::iterator const& D0, soa::Join const&, aod::Tracks const&) - { - jD0IdsTable(D0.collisionId(), D0.prong0Id(), D0.prong1Id()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processD0, "produces derived bunch crossing table for D0 candidates", false); - - void processD0MC(aod::HfD0PIds::iterator const& D0, aod::McCollisions const&, aod::McParticles const&) - { - jD0ParticleIdsTable(D0.mcCollisionId(), D0.mcParticleId()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processD0MC, "produces derived bunch crossing table for D0 particles", false); - - void processLc(aod::Hf3PIds::iterator const& Lc, soa::Join const&, aod::Tracks const&) - { - jLcIdsTable(Lc.collisionId(), Lc.prong0Id(), Lc.prong1Id(), Lc.prong2Id()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processLc, "produces derived bunch crossing table for Lc candidates", false); - - void processLcMC(aod::Hf3PPIds::iterator const& Lc, aod::McCollisions const&, aod::McParticles const&) - { - jLcParticleIdsTable(Lc.mcCollisionId(), Lc.mcParticleId()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processLcMC, "produces derived bunch crossing table for Lc particles", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"jet-deriveddata-producer"})}; -} diff --git a/PWGJE/TableProducer/jetderiveddataproducerdummy.cxx b/PWGJE/TableProducer/jetderiveddataproducerdummy.cxx deleted file mode 100644 index b7ab57efbfc..00000000000 --- a/PWGJE/TableProducer/jetderiveddataproducerdummy.cxx +++ /dev/null @@ -1,61 +0,0 @@ -// 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. - -// temporary task to produce HF tables needed when making inclusive derived data - should become obsolete when tables are able to be prouduced based on a configurable -// -/// \author Nima Zardoshti - -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/runDataProcessing.h" -#include "PWGJE/DataModel/JetReducedData.h" -#include "PWGHF/DataModel/DerivedTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct JetDerivedDataProducerDummyTask { - - Produces d0CollisionsTable; - Produces d0sTable; - Produces d0ParsTable; - Produces d0ParExtrasTable; - Produces d0SelsTable; - Produces d0MlsTable; - Produces d0McsTable; - Produces d0ParticlesTable; - - Produces LcCollisionsTable; - Produces LcsTable; - Produces LcParsTable; - Produces LcParExtrasTable; - Produces LcSelsTable; - Produces LcMlsTable; - Produces LcMcsTable; - Produces LcParticlesTable; - - void init(InitContext const&) - { - } - - void processDummy(aod::JDummys const&) - { - } - PROCESS_SWITCH(JetDerivedDataProducerDummyTask, processDummy, "leaves all tables empty", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"jet-deriveddata-producer-dummy"})}; -} diff --git a/PWGJE/TableProducer/jetderiveddataproducerdummyd0.cxx b/PWGJE/TableProducer/jetderiveddataproducerdummyd0.cxx deleted file mode 100644 index e9ab11164b4..00000000000 --- a/PWGJE/TableProducer/jetderiveddataproducerdummyd0.cxx +++ /dev/null @@ -1,52 +0,0 @@ -// 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. - -// temporary task to produce HF tables needed when making inclusive derived data - should become obsolete when tables are able to be prouduced based on a configurable -// -/// \author Nima Zardoshti - -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/runDataProcessing.h" -#include "PWGJE/DataModel/JetReducedData.h" -#include "PWGHF/DataModel/DerivedTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct JetDerivedDataProducerDummyD0Task { - - Produces LcCollisionsTable; - Produces LcsTable; - Produces LcParsTable; - Produces LcParExtrasTable; - Produces LcSelsTable; - Produces LcMlsTable; - Produces LcMcsTable; - Produces LcParticlesTable; - - void init(InitContext const&) - { - } - - void processDummy(aod::JDummys const&) - { - } - PROCESS_SWITCH(JetDerivedDataProducerDummyD0Task, processDummy, "leaves all tables empty", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"jet-deriveddata-producer-dummy-d0"})}; -} diff --git a/PWGJE/TableProducer/jetderiveddataproducerdummylc.cxx b/PWGJE/TableProducer/jetderiveddataproducerdummylc.cxx deleted file mode 100644 index fb56e02ca26..00000000000 --- a/PWGJE/TableProducer/jetderiveddataproducerdummylc.cxx +++ /dev/null @@ -1,52 +0,0 @@ -// 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. - -// temporary task to produce HF tables needed when making inclusive derived data - should become obsolete when tables are able to be prouduced based on a configurable -// -/// \author Nima Zardoshti - -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/runDataProcessing.h" -#include "PWGJE/DataModel/JetReducedData.h" -#include "PWGHF/DataModel/DerivedTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct JetDerivedDataProducerDummyLcTask { - - Produces d0CollisionsTable; - Produces d0sTable; - Produces d0ParsTable; - Produces d0ParExtrasTable; - Produces d0SelsTable; - Produces d0MlsTable; - Produces d0McsTable; - Produces d0ParticlesTable; - - void init(InitContext const&) - { - } - - void processDummy(aod::JDummys const&) - { - } - PROCESS_SWITCH(JetDerivedDataProducerDummyLcTask, processDummy, "leaves all tables empty", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"jet-deriveddata-producer-dummy-lc"})}; -} diff --git a/PWGJE/TableProducer/jetderiveddatawriter.cxx b/PWGJE/TableProducer/jetderiveddatawriter.cxx deleted file mode 100644 index 8f3b9174b65..00000000000 --- a/PWGJE/TableProducer/jetderiveddatawriter.cxx +++ /dev/null @@ -1,658 +0,0 @@ -// 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 jetderiveddatawriter.cxx -/// \brief Task to skim jet framework tables (JetCollisions, JetTracks, JetClusters, ...) -/// while adjusting indices accordingly -/// -/// \author Jochen Klein -/// \author Nima Zardoshti - -#include -#include - -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/runDataProcessing.h" - -#include "PWGJE/Core/JetHFUtilities.h" -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/DataModel/JetReducedData.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct JetDerivedDataWriter { - - Configurable chargedJetPtMin{"chargedJetPtMin", 0.0, "Minimum charged jet pt to accept event"}; - Configurable chargedEventWiseSubtractedJetPtMin{"chargedEventWiseSubtractedJetPtMin", 0.0, "Minimum charged event-wise subtracted jet pt to accept event"}; - Configurable chargedMCPJetPtMin{"chargedMCPJetPtMin", 0.0, "Minimum charged mcp jet pt to accept event"}; - Configurable neutralJetPtMin{"neutralJetPtMin", 0.0, "Minimum charged jet pt to accept event"}; - Configurable fullJetPtMin{"fullJetPtMin", 0.0, "Minimum full jet pt to accept event"}; - Configurable chargedEventWiseSubtractedD0JetPtMin{"chargedEventWiseSubtractedD0JetPtMin", 0.0, "Minimum charged event-wise subtracted D0 jet pt to accept event"}; - Configurable chargedD0JetPtMin{"chargedD0JetPtMin", 0.0, "Minimum charged D0 jet pt to accept event"}; - Configurable chargedEventWiseSubtractedLcJetPtMin{"chargedEventWiseSubtractedLcJetPtMin", 0.0, "Minimum charged event-wise subtracted Lc jet pt to accept event"}; - Configurable chargedLcJetPtMin{"chargedLcJetPtMin", 0.0, "Minimum charged Lc jet pt to accept event"}; - - Configurable performTrackSelection{"performTrackSelection", true, "only save tracks that pass one of the track selections"}; - Configurable saveBCsTable{"saveBCsTable", true, "save the bunch crossing table to the output"}; - Configurable saveClustersTable{"saveClustersTable", true, "save the clusters table to the output"}; - Configurable saveD0Table{"saveD0Table", false, "save the D0 table to the output"}; - Configurable saveLcTable{"saveLcTable", false, "save the Lc table to the output"}; - - Produces storedCollisionCountsTable; - Produces storedJDummysTable; - Produces storedJBCsTable; - Produces storedJBCParentIndexTable; - Produces storedJCollisionsTable; - Produces storedJCollisionsParentIndexTable; - Produces storedJCollisionsBunchCrossingIndexTable; - Produces storedJChargedTriggerSelsTable; - Produces storedJFullTriggerSelsTable; - Produces storedJChargedHFTriggerSelsTable; - Produces storedJMcCollisionsLabelTable; - Produces storedJMcCollisionsTable; - Produces storedJMcCollisionsParentIndexTable; - Produces storedJTracksTable; - Produces storedJTracksParentIndexTable; - Produces storedJMcTracksLabelTable; - Produces storedJMcParticlesTable; - Produces storedJParticlesParentIndexTable; - Produces storedJClustersTable; - Produces storedJClustersParentIndexTable; - Produces storedJClustersMatchedTracksTable; - - Produces storedD0CollisionsTable; - Produces storedD0sTable; - Produces storedD0ParsTable; - Produces storedD0ParExtrasTable; - Produces storedD0SelsTable; - Produces storedD0MlsTable; - Produces storedD0McsTable; - Produces storedD0IdsTable; - Produces storedD0ParticlesTable; - Produces storedD0ParticleIdsTable; - - Produces storedLcCollisionsTable; - Produces storedLcsTable; - Produces storedLcParsTable; - Produces storedLcParExtrasTable; - Produces storedLcSelsTable; - Produces storedLcMlsTable; - Produces storedLcMcsTable; - Produces storedLcIdsTable; - Produces storedLcParticlesTable; - Produces storedLcParticleIdsTable; - - PresliceUnsorted> CollisionsPerMcCollision = aod::jmccollisionlb::mcCollisionId; - PresliceUnsorted> ParticlesPerMcCollision = aod::jmcparticle::mcCollisionId; - Preslice> TracksPerCollision = aod::jtrack::collisionId; - Preslice> ClustersPerCollision = aod::jcluster::collisionId; - Preslice D0sPerCollision = aod::jd0indices::collisionId; - Preslice LcsPerCollision = aod::jlcindices::collisionId; - - std::vector collisionFlag; - std::vector McCollisionFlag; - std::vector bcIndicies; - - uint32_t precisionPositionMask; - uint32_t precisionMomentumMask; - - void init(InitContext&) - { - precisionPositionMask = 0xFFFFFC00; // 13 bits - precisionMomentumMask = 0xFFFFFC00; // 13 bits this is currently keept at 13 bits wihich gives roughly a resolution of 1/8000. This can be increased to 15 bits if really needed - } - - bool acceptCollision(aod::JCollision const&) - { - return true; - } - - void processCollisions(aod::JCollisions const& collisions) - { - collisionFlag.resize(collisions.size()); - std::fill(collisionFlag.begin(), collisionFlag.end(), false); - } - - void processMcCollisions(aod::JMcCollisions const& Mccollisions) - { - McCollisionFlag.resize(Mccollisions.size()); - std::fill(McCollisionFlag.begin(), McCollisionFlag.end(), false); - } - - template - void processJets(T& jets) - { - float jetPtMin = 0.0; - if constexpr (std::is_same_v, aod::ChargedJets> || std::is_same_v, aod::ChargedMCDetectorLevelJets>) { - jetPtMin = chargedJetPtMin; - } else if constexpr (std::is_same_v, aod::ChargedEventWiseSubtractedJets>) { - jetPtMin = chargedEventWiseSubtractedJetPtMin; - } else if constexpr (std::is_same_v, aod::ChargedMCParticleLevelJets>) { - jetPtMin = chargedMCPJetPtMin; - } else if constexpr (std::is_same_v, aod::NeutralJets>) { - jetPtMin = neutralJetPtMin; - } else if constexpr (std::is_same_v, aod::FullJets>) { - jetPtMin = fullJetPtMin; - } else if constexpr (std::is_same_v, aod::D0ChargedJets>) { - jetPtMin = chargedD0JetPtMin; - } else if constexpr (std::is_same_v, aod::D0ChargedEventWiseSubtractedJets>) { - jetPtMin = chargedEventWiseSubtractedD0JetPtMin; - } else if constexpr (std::is_same_v, aod::LcChargedJets>) { - jetPtMin = chargedLcJetPtMin; - } else if constexpr (std::is_same_v, aod::LcChargedEventWiseSubtractedJets>) { - jetPtMin = chargedEventWiseSubtractedLcJetPtMin; - } else { - jetPtMin = 0.0; - } - for (const auto& jet : jets) { - if (jet.pt() >= jetPtMin) { - if constexpr (std::is_same_v, aod::ChargedMCParticleLevelJets> || std::is_same_v, aod::NeutralMCParticleLevelJets> || std::is_same_v, aod::FullMCParticleLevelJets> || std::is_same_v, aod::D0ChargedMCParticleLevelJets> || std::is_same_v, aod::LcChargedMCParticleLevelJets> || std::is_same_v, aod::BplusChargedMCParticleLevelJets>) { - McCollisionFlag[jet.mcCollisionId()] = true; - } else { - collisionFlag[jet.collisionId()] = true; - } - } - } - } - PROCESS_SWITCH(JetDerivedDataWriter, processCollisions, "setup the writing for data and MCD", true); - PROCESS_SWITCH(JetDerivedDataWriter, processMcCollisions, "setup the writing for MCP", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processChargedJets, "process charged jets", true); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processChargedEventWiseSubtractedJets, "process charged event-wise subtracted jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processChargedMCDJets, "process charged mcd jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processChargedMCPJets, "process charged mcp jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processNeutralJets, "process neutral jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processFullJets, "process full jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processD0ChargedJets, "process D0 charged jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processD0ChargedEventWiseSubtractedJets, "process D0 event-wise subtracted charged jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processLcChargedJets, "process Lc charged jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processLcChargedEventWiseSubtractedJets, "process Lc event-wise subtracted charged jets", false); - - void processDummyTable(aod::JDummys const&) - { - storedJDummysTable(1); - } - PROCESS_SWITCH(JetDerivedDataWriter, processDummyTable, "write out dummy output table", true); - - void processCollisionCounting(aod::JCollisions const& collisions, aod::CollisionCounts const& collisionCounts) - { - int readCollisionCounter = 0; - int writtenCollisionCounter = 0; - for (const auto& collision : collisions) { - readCollisionCounter++; - if (collisionFlag[collision.globalIndex()]) { - writtenCollisionCounter++; - } - } - std::vector previousReadCounts = {0}; - std::vector previousWrittenCounts = {0}; - int iPreviousDataFrame = 0; - for (const auto& collisionCount : collisionCounts) { - auto readCollisionCounterSpan = collisionCount.readCounts(); - auto writtenCollisionCounterSpan = collisionCount.writtenCounts(); - if (iPreviousDataFrame == 0) { - std::copy(readCollisionCounterSpan.begin(), readCollisionCounterSpan.end(), std::back_inserter(previousReadCounts)); - std::copy(writtenCollisionCounterSpan.begin(), writtenCollisionCounterSpan.end(), std::back_inserter(previousWrittenCounts)); - } else { - for (unsigned int i = 0; i < previousReadCounts.size(); i++) { - previousReadCounts[i] += readCollisionCounterSpan[i]; - previousWrittenCounts[i] += writtenCollisionCounterSpan[i]; - } - } - iPreviousDataFrame++; - } - previousReadCounts.push_back(readCollisionCounter); - previousWrittenCounts.push_back(writtenCollisionCounter); - storedCollisionCountsTable(previousReadCounts, previousWrittenCounts); - } - PROCESS_SWITCH(JetDerivedDataWriter, processCollisionCounting, "write out collision counting output table", false); - - void processData(soa::Join::iterator const& collision, soa::Join const&, soa::Join const& tracks, soa::Join const& clusters, aod::HfD0CollBases const&, CandidatesD0Data const& D0s, aod::Hf3PCollBases const&, CandidatesLcData const& Lcs) - { - std::map bcMapping; - std::map trackMapping; - - if (collisionFlag[collision.globalIndex()]) { - if (saveBCsTable) { - auto bc = collision.bc_as>(); - if (std::find(bcIndicies.begin(), bcIndicies.end(), bc.globalIndex()) == bcIndicies.end()) { - storedJBCsTable(bc.runNumber(), bc.globalBC(), bc.timestamp()); - storedJBCParentIndexTable(bc.bcId()); - bcIndicies.push_back(bc.globalIndex()); - bcMapping.insert(std::make_pair(bc.globalIndex(), storedJBCsTable.lastIndex())); - } - } - - storedJCollisionsTable(collision.posX(), collision.posY(), collision.posZ(), collision.multiplicity(), collision.centrality(), collision.eventSel(), collision.alias_raw()); - storedJCollisionsParentIndexTable(collision.collisionId()); - if (saveBCsTable) { - int32_t storedBCID = -1; - auto JBCIndex = bcMapping.find(collision.bcId()); - if (JBCIndex != bcMapping.end()) { - storedBCID = JBCIndex->second; - } - storedJCollisionsBunchCrossingIndexTable(storedBCID); - } - storedJChargedTriggerSelsTable(collision.chargedTriggerSel()); - storedJFullTriggerSelsTable(collision.fullTriggerSel()); - storedJChargedHFTriggerSelsTable(collision.chargedHFTriggerSel()); - - for (const auto& track : tracks) { - if (performTrackSelection && !(track.trackSel() & ~(1 << jetderiveddatautilities::JTrackSel::trackSign))) { // skips tracks that pass no selections. This might cause a problem with tracks matched with clusters. We should generate a track selection purely for cluster matched tracks so that they are kept - continue; - } - storedJTracksTable(storedJCollisionsTable.lastIndex(), o2::math_utils::detail::truncateFloatFraction(track.pt(), precisionMomentumMask), o2::math_utils::detail::truncateFloatFraction(track.eta(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(track.phi(), precisionPositionMask), track.trackSel()); - storedJTracksParentIndexTable(track.trackId()); - trackMapping.insert(std::make_pair(track.globalIndex(), storedJTracksTable.lastIndex())); - } - if (saveClustersTable) { - for (const auto& cluster : clusters) { - storedJClustersTable(storedJCollisionsTable.lastIndex(), cluster.id(), cluster.energy(), cluster.coreEnergy(), cluster.rawEnergy(), - cluster.eta(), cluster.phi(), cluster.m02(), cluster.m20(), cluster.nCells(), cluster.time(), cluster.isExotic(), cluster.distanceToBadChannel(), - cluster.nlm(), cluster.definition(), cluster.leadingCellEnergy(), cluster.subleadingCellEnergy(), cluster.leadingCellNumber(), cluster.subleadingCellNumber()); - storedJClustersParentIndexTable(cluster.clusterId()); - - std::vector clusterStoredJTrackIDs; - for (const auto& clusterTrack : cluster.matchedTracks_as>()) { - auto JtrackIndex = trackMapping.find(clusterTrack.globalIndex()); - if (JtrackIndex != trackMapping.end()) { - clusterStoredJTrackIDs.push_back(JtrackIndex->second); - } - } - storedJClustersMatchedTracksTable(clusterStoredJTrackIDs); - } - } - - if (saveD0Table) { - int nD0InCollision = 0; - int32_t collisionD0Index = -1; - for (const auto& D0 : D0s) { - if (nD0InCollision == 0) { - jethfutilities::fillD0CollisionTable(D0.hfD0CollBase_as(), storedD0CollisionsTable, collisionD0Index); - } - nD0InCollision++; - - int32_t D0Index = -1; - jethfutilities::fillD0CandidateTable(D0, collisionD0Index, storedD0sTable, storedD0ParsTable, storedD0ParExtrasTable, storedD0SelsTable, storedD0MlsTable, storedD0McsTable, D0Index); - - int32_t prong0Id = -1; - int32_t prong1Id = -1; - auto JtrackIndex = trackMapping.find(D0.prong0Id()); - if (JtrackIndex != trackMapping.end()) { - prong0Id = JtrackIndex->second; - } - JtrackIndex = trackMapping.find(D0.prong1Id()); - if (JtrackIndex != trackMapping.end()) { - prong1Id = JtrackIndex->second; - } - storedD0IdsTable(storedJCollisionsTable.lastIndex(), prong0Id, prong1Id); - } - } - - if (saveLcTable) { - int nLcInCollision = 0; - int32_t collisionLcIndex = -1; - for (const auto& Lc : Lcs) { - if (nLcInCollision == 0) { - jethfutilities::fillLcCollisionTable(Lc.hf3PCollBase_as(), storedLcCollisionsTable, collisionLcIndex); - } - nLcInCollision++; - - int32_t LcIndex = -1; - jethfutilities::fillLcCandidateTable(Lc, collisionLcIndex, storedLcsTable, storedLcParsTable, storedLcParExtrasTable, storedLcSelsTable, storedLcMlsTable, storedLcMcsTable, LcIndex); - - int32_t prong0Id = -1; - int32_t prong1Id = -1; - int32_t prong2Id = -1; - auto JtrackIndex = trackMapping.find(Lc.prong0Id()); - if (JtrackIndex != trackMapping.end()) { - prong0Id = JtrackIndex->second; - } - JtrackIndex = trackMapping.find(Lc.prong1Id()); - if (JtrackIndex != trackMapping.end()) { - prong1Id = JtrackIndex->second; - } - JtrackIndex = trackMapping.find(Lc.prong2Id()); - if (JtrackIndex != trackMapping.end()) { - prong2Id = JtrackIndex->second; - } - storedLcIdsTable(storedJCollisionsTable.lastIndex(), prong0Id, prong1Id, prong2Id); - } - } - } - } - // process switch for output writing must be last - // to run after all jet selections - PROCESS_SWITCH(JetDerivedDataWriter, processData, "write out data output tables", false); - - void processMC(soa::Join const& mcCollisions, soa::Join const& collisions, soa::Join const&, soa::Join const& tracks, soa::Join const& clusters, soa::Join const& particles, aod::HfD0CollBases const&, CandidatesD0MCD const& D0s, CandidatesD0MCP const& D0Particles, aod::Hf3PCollBases const&, CandidatesLcMCD const& Lcs, CandidatesLcMCP const& LcParticles) - { - std::map bcMapping; - std::map paticleMapping; - std::map mcCollisionMapping; - int particleTableIndex = 0; - for (auto mcCollision : mcCollisions) { - bool collisionSelected = false; - const auto collisionsPerMcCollision = collisions.sliceBy(CollisionsPerMcCollision, mcCollision.globalIndex()); - for (auto collision : collisionsPerMcCollision) { - if (collisionFlag[collision.globalIndex()]) { - collisionSelected = true; - } - } - - if (McCollisionFlag[mcCollision.globalIndex()] || collisionSelected) { - - const auto particlesPerMcCollision = particles.sliceBy(ParticlesPerMcCollision, mcCollision.globalIndex()); - - storedJMcCollisionsTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.weight()); - storedJMcCollisionsParentIndexTable(mcCollision.mcCollisionId()); - mcCollisionMapping.insert(std::make_pair(mcCollision.globalIndex(), storedJMcCollisionsTable.lastIndex())); - - for (auto particle : particlesPerMcCollision) { - paticleMapping.insert(std::make_pair(particle.globalIndex(), particleTableIndex)); - particleTableIndex++; - } - for (auto particle : particlesPerMcCollision) { - - std::vector mothersId; - if (particle.has_mothers()) { - auto mothersIdTemps = particle.mothersIds(); - for (auto mothersIdTemp : mothersIdTemps) { - - auto JMotherIndex = paticleMapping.find(mothersIdTemp); - if (JMotherIndex != paticleMapping.end()) { - mothersId.push_back(JMotherIndex->second); - } - } - } - int daughtersId[2] = {-1, -1}; - auto i = 0; - if (particle.has_daughters()) { - for (auto daughterId : particle.daughtersIds()) { - if (i > 1) { - break; - } - auto JDaughterIndex = paticleMapping.find(daughterId); - if (JDaughterIndex != paticleMapping.end()) { - daughtersId[i] = JDaughterIndex->second; - } - i++; - } - } - storedJMcParticlesTable(storedJMcCollisionsTable.lastIndex(), o2::math_utils::detail::truncateFloatFraction(particle.pt(), precisionMomentumMask), o2::math_utils::detail::truncateFloatFraction(particle.eta(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(particle.phi(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(particle.y(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(particle.e(), precisionMomentumMask), particle.pdgCode(), particle.getGenStatusCode(), particle.getHepMCStatusCode(), particle.isPhysicalPrimary(), mothersId, daughtersId); - storedJParticlesParentIndexTable(particle.mcParticleId()); - } - - if (saveD0Table) { - for (const auto& D0Particle : D0Particles) { - int32_t D0ParticleIndex = -1; - jethfutilities::fillD0CandidateMcTable(D0Particle, storedD0ParticlesTable, D0ParticleIndex); - int32_t d0ParticleId = -1; - auto JParticleIndex = paticleMapping.find(D0Particle.mcParticleId()); - if (JParticleIndex != paticleMapping.end()) { - d0ParticleId = JParticleIndex->second; - } - storedD0ParticleIdsTable(storedJMcCollisionsTable.lastIndex(), d0ParticleId); - } - } - - if (saveLcTable) { - for (const auto& LcParticle : LcParticles) { - int32_t LcParticleIndex = -1; - jethfutilities::fillLcCandidateMcTable(LcParticle, storedLcParticlesTable, LcParticleIndex); - int32_t LcParticleId = -1; - auto JParticleIndex = paticleMapping.find(LcParticle.mcParticleId()); - if (JParticleIndex != paticleMapping.end()) { - LcParticleId = JParticleIndex->second; - } - storedLcParticleIdsTable(storedJMcCollisionsTable.lastIndex(), LcParticleId); - } - } - } - } - - for (auto mcCollision : mcCollisions) { - bool collisionSelected = false; - const auto collisionsPerMcCollision = collisions.sliceBy(CollisionsPerMcCollision, mcCollision.globalIndex()); - for (auto collision : collisionsPerMcCollision) { - if (collisionFlag[collision.globalIndex()]) { - collisionSelected = true; - } - } - - if (McCollisionFlag[mcCollision.globalIndex()] || collisionSelected) { - - for (auto collision : collisionsPerMcCollision) { - std::map trackMapping; - if (saveBCsTable) { - auto bc = collision.bc_as>(); - if (std::find(bcIndicies.begin(), bcIndicies.end(), bc.globalIndex()) == bcIndicies.end()) { - storedJBCsTable(bc.runNumber(), bc.globalBC(), bc.timestamp()); - storedJBCParentIndexTable(bc.bcId()); - bcIndicies.push_back(bc.globalIndex()); - bcMapping.insert(std::make_pair(bc.globalIndex(), storedJBCsTable.lastIndex())); - } - } - - storedJCollisionsTable(collision.posX(), collision.posY(), collision.posZ(), collision.multiplicity(), collision.centrality(), collision.eventSel(), collision.alias_raw()); - storedJCollisionsParentIndexTable(collision.collisionId()); - - auto JMcCollisionIndex = mcCollisionMapping.find(mcCollision.globalIndex()); - if (JMcCollisionIndex != mcCollisionMapping.end()) { - storedJMcCollisionsLabelTable(JMcCollisionIndex->second); - } - if (saveBCsTable) { - int32_t storedBCID = -1; - auto JBCIndex = bcMapping.find(collision.bcId()); - if (JBCIndex != bcMapping.end()) { - storedBCID = JBCIndex->second; - } - storedJCollisionsBunchCrossingIndexTable(storedBCID); - } - storedJChargedTriggerSelsTable(collision.chargedTriggerSel()); - storedJFullTriggerSelsTable(collision.fullTriggerSel()); - storedJChargedHFTriggerSelsTable(collision.chargedHFTriggerSel()); - - const auto tracksPerCollision = tracks.sliceBy(TracksPerCollision, collision.globalIndex()); - for (const auto& track : tracksPerCollision) { - if (performTrackSelection && !(track.trackSel() & ~(1 << jetderiveddatautilities::JTrackSel::trackSign))) { // skips tracks that pass no selections. This might cause a problem with tracks matched with clusters. We should generate a track selection purely for cluster matched tracks so that they are kept - continue; - } - storedJTracksTable(storedJCollisionsTable.lastIndex(), o2::math_utils::detail::truncateFloatFraction(track.pt(), precisionMomentumMask), o2::math_utils::detail::truncateFloatFraction(track.eta(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(track.phi(), precisionPositionMask), track.trackSel()); - storedJTracksParentIndexTable(track.trackId()); - - if (track.has_mcParticle()) { - auto JParticleIndex = paticleMapping.find(track.mcParticleId()); - if (JParticleIndex != paticleMapping.end()) { - storedJMcTracksLabelTable(JParticleIndex->second); - } else { - storedJMcTracksLabelTable(-1); // this can happen because there are some tracks that are reconstucted in a wrong collision, but their original McCollision did not pass the required cuts so that McParticle is not saved. These are very few but we should look into them further and see what to do about them - } - } else { - storedJMcTracksLabelTable(-1); - } - trackMapping.insert(std::make_pair(track.globalIndex(), storedJTracksTable.lastIndex())); - } - if (saveClustersTable) { - const auto clustersPerCollision = clusters.sliceBy(ClustersPerCollision, collision.globalIndex()); - for (const auto& cluster : clustersPerCollision) { - storedJClustersTable(storedJCollisionsTable.lastIndex(), cluster.id(), cluster.energy(), cluster.coreEnergy(), cluster.rawEnergy(), - cluster.eta(), cluster.phi(), cluster.m02(), cluster.m20(), cluster.nCells(), cluster.time(), cluster.isExotic(), cluster.distanceToBadChannel(), - cluster.nlm(), cluster.definition(), cluster.leadingCellEnergy(), cluster.subleadingCellEnergy(), cluster.leadingCellNumber(), cluster.subleadingCellNumber()); - storedJClustersParentIndexTable(cluster.clusterId()); - - std::vector clusterStoredJTrackIDs; - for (const auto& clusterTrack : cluster.matchedTracks_as>()) { - auto JtrackIndex = trackMapping.find(clusterTrack.globalIndex()); - if (JtrackIndex != trackMapping.end()) { - clusterStoredJTrackIDs.push_back(JtrackIndex->second); - } - } - storedJClustersMatchedTracksTable(clusterStoredJTrackIDs); - } - } - - if (saveD0Table) { - const auto d0sPerCollision = D0s.sliceBy(D0sPerCollision, collision.globalIndex()); - int nD0InCollision = 0; - int32_t collisionD0Index = -1; - for (const auto& D0 : d0sPerCollision) { - if (nD0InCollision == 0) { - jethfutilities::fillD0CollisionTable(D0.hfD0CollBase_as(), storedD0CollisionsTable, collisionD0Index); - } - nD0InCollision++; - - int32_t D0Index = -1; - jethfutilities::fillD0CandidateTable(D0, collisionD0Index, storedD0sTable, storedD0ParsTable, storedD0ParExtrasTable, storedD0SelsTable, storedD0MlsTable, storedD0McsTable, D0Index); - - int32_t prong0Id = -1; - int32_t prong1Id = -1; - auto JtrackIndex = trackMapping.find(D0.prong0Id()); - if (JtrackIndex != trackMapping.end()) { - prong0Id = JtrackIndex->second; - } - JtrackIndex = trackMapping.find(D0.prong1Id()); - if (JtrackIndex != trackMapping.end()) { - prong1Id = JtrackIndex->second; - } - storedD0IdsTable(storedJCollisionsTable.lastIndex(), prong0Id, prong1Id); - } - } - - if (saveLcTable) { - const auto lcsPerCollision = Lcs.sliceBy(LcsPerCollision, collision.globalIndex()); - int nLcInCollision = 0; - int32_t collisionLcIndex = -1; - for (const auto& Lc : lcsPerCollision) { - if (nLcInCollision == 0) { - jethfutilities::fillLcCollisionTable(Lc.hf3PCollBase_as(), storedLcCollisionsTable, collisionLcIndex); - } - nLcInCollision++; - - int32_t LcIndex = -1; - jethfutilities::fillLcCandidateTable(Lc, collisionLcIndex, storedLcsTable, storedLcParsTable, storedLcParExtrasTable, storedLcSelsTable, storedLcMlsTable, storedLcMcsTable, LcIndex); - - int32_t prong0Id = -1; - int32_t prong1Id = -1; - int32_t prong2Id = -1; - auto JtrackIndex = trackMapping.find(Lc.prong0Id()); - if (JtrackIndex != trackMapping.end()) { - prong0Id = JtrackIndex->second; - } - JtrackIndex = trackMapping.find(Lc.prong1Id()); - if (JtrackIndex != trackMapping.end()) { - prong1Id = JtrackIndex->second; - } - JtrackIndex = trackMapping.find(Lc.prong2Id()); - if (JtrackIndex != trackMapping.end()) { - prong2Id = JtrackIndex->second; - } - storedLcIdsTable(storedJCollisionsTable.lastIndex(), prong0Id, prong1Id, prong2Id); - } - } - } - } - } - } - // process switch for output writing must be last - // to run after all jet selections - PROCESS_SWITCH(JetDerivedDataWriter, processMC, "write out data output tables for mc", false); - - void processMCP(soa::Join const& mcCollisions, soa::Join const& particles, CandidatesD0MCP const& D0Particles, CandidatesLcMCP const& LcParticles) - { - - int particleTableIndex = 0; - for (auto mcCollision : mcCollisions) { - if (McCollisionFlag[mcCollision.globalIndex()]) { // you can also check if any of its detector level counterparts are correct - std::map paticleMapping; - - storedJMcCollisionsTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.weight()); - storedJMcCollisionsParentIndexTable(mcCollision.mcCollisionId()); - - const auto particlesPerMcCollision = particles.sliceBy(ParticlesPerMcCollision, mcCollision.globalIndex()); - - for (auto particle : particlesPerMcCollision) { - paticleMapping.insert(std::make_pair(particle.globalIndex(), particleTableIndex)); - particleTableIndex++; - } - for (auto particle : particlesPerMcCollision) { - - std::vector mothersId; - int daughtersId[2]; - if (particle.has_mothers()) { - for (auto const& mother : particle.template mothers_as>()) { - - auto JMotherIndex = paticleMapping.find(mother.globalIndex()); - if (JMotherIndex != paticleMapping.end()) { - mothersId.push_back(JMotherIndex->second); - } - } - } - auto i = 0; - if (particle.has_daughters()) { - for (auto const& daughter : particle.template daughters_as>()) { - if (i > 1) { - break; - } - auto JDaughterIndex = paticleMapping.find(daughter.globalIndex()); - if (JDaughterIndex != paticleMapping.end()) { - daughtersId[i] = JDaughterIndex->second; - } - i++; - } - } - storedJMcParticlesTable(storedJMcCollisionsTable.lastIndex(), o2::math_utils::detail::truncateFloatFraction(particle.pt(), precisionMomentumMask), o2::math_utils::detail::truncateFloatFraction(particle.eta(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(particle.phi(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(particle.y(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(particle.e(), precisionMomentumMask), particle.pdgCode(), particle.getGenStatusCode(), particle.getHepMCStatusCode(), particle.isPhysicalPrimary(), mothersId, daughtersId); - storedJParticlesParentIndexTable(particle.mcParticleId()); - } - - if (saveD0Table) { - for (const auto& D0Particle : D0Particles) { - int32_t D0ParticleIndex = -1; - jethfutilities::fillD0CandidateMcTable(D0Particle, storedD0ParticlesTable, D0ParticleIndex); - int32_t d0ParticleId = -1; - auto JParticleIndex = paticleMapping.find(D0Particle.mcParticleId()); - if (JParticleIndex != paticleMapping.end()) { - d0ParticleId = JParticleIndex->second; - } - storedD0ParticleIdsTable(storedJMcCollisionsTable.lastIndex(), d0ParticleId); - } - } - if (saveLcTable) { - for (const auto& LcParticle : LcParticles) { - int32_t LcParticleIndex = -1; - jethfutilities::fillLcCandidateMcTable(LcParticle, storedLcParticlesTable, LcParticleIndex); - int32_t LcParticleId = -1; - auto JParticleIndex = paticleMapping.find(LcParticle.mcParticleId()); - if (JParticleIndex != paticleMapping.end()) { - LcParticleId = JParticleIndex->second; - } - storedLcParticleIdsTable(storedJMcCollisionsTable.lastIndex(), LcParticleId); - } - } - } - } - } - // process switch for output writing must be last - // to run after all jet selections - PROCESS_SWITCH(JetDerivedDataWriter, processMCP, "write out data output tables for mcp", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - std::vector tasks; - - tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-deriveddata-writer"})); - - return WorkflowSpec{tasks}; -} diff --git a/PWGJE/TableProducer/jettaggerhf.cxx b/PWGJE/TableProducer/jettaggerhf.cxx deleted file mode 100644 index a13bed597dc..00000000000 --- a/PWGJE/TableProducer/jettaggerhf.cxx +++ /dev/null @@ -1,169 +0,0 @@ -// 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. - -// Task to produce a table joinable to the jet tables for hf jet tagging -// -/// \author Nima Zardoshti -/// \author Hanseo Park - -#include -#include - -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Framework/runDataProcessing.h" -#include "Common/Core/trackUtilities.h" - -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/DataModel/JetTagging.h" -#include "PWGJE/Core/JetTaggingUtilities.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -template -struct JetTaggerHFTask { - - Produces taggingTableData; - Produces taggingTableMCD; - - Configurable maxDeltaR{"maxDeltaR", 0.25, "maximum distance of jet axis from flavour initiating parton"}; - Configurable doWShower{"doWShower", false, "find jet origin included gluon spliting"}; // true:: remove gluon spliting - Configurable doTC{"doTC", false, "fill table for track counting algorithm"}; - Configurable doSV{"doSV", false, "fill table for secondary vertex algorithm"}; - Configurable numCount{"numCount", 3, "number of track counting"}; - Configurable> paramsResoFunc{"paramsResoFunc", std::vector{1117853.376, -0.092, 0.838, 9.209, 0.408, 9.209, 0.408, 13.501, 1.035}, "parameters of gaus(0)+expo(3)+expo(5)+expo(7))"}; - Configurable> paramsResoFuncMC{"paramsResoFuncMC", std::vector{53473, -0.044, 0.649, 10.152, 1.274, 5.264, 0.438, 6.326, 0.438454, 53473, -0.044, 0.649}, "parameters of gaus(0)+expo(3)+expo(5)+expo(7)))"}; - Configurable minSignImpXYSig{"minsIPs", -10.0, "minimum of signed impact parameter significance"}; - Configurable tagPoint{"tagPoint", 1.0, "tagging working point"}; - - using JetTagTracksData = soa::Join; - using JetTagTracksMCD = soa::Join; - using OriTracksData = soa::Join; - using OriTracksMCD = soa::Join; - - std::unique_ptr fSignImpXYSig = nullptr; - std::vector vecParams; - // TF1* fSignImpXYSig = nullptr; - int maxOrder = -1; - void init(InitContext const&) - { - maxOrder = numCount + 1; // 0: untagged, >1 : N ordering - if (doprocessData) { - vecParams = (std::vector)paramsResoFunc; - } - if (doprocessMCD) { - vecParams = (std::vector)paramsResoFuncMC; - } - fSignImpXYSig = jettaggingutilities::setResolutionFunction(vecParams); - } - - void processDummy(JetCollisions const&) - { - } - PROCESS_SWITCH(JetTaggerHFTask, processDummy, "Dummy process", true); - - void processData(JetCollision const& collision, JetTableData const& jets, JetTagTracksData const& jtracks, OriTracksData const& tracks) - { - for (auto& jet : jets) { - std::vector jetProb; - int algorithm2 = 0; - int algorithm3 = 0; - if (doTC) { - for (int order = 0; order < maxOrder; order++) { - jetProb.push_back(jettaggingutilities::getJetProbability(fSignImpXYSig, collision, jet, jtracks, tracks, order, tagPoint, minSignImpXYSig)); - } - } - // if (doSV) algorithm2 = jettaggingutilities::Algorithm2((mcdjet, tracks); - taggingTableData(0, jetProb, algorithm2, algorithm3); - } - } - PROCESS_SWITCH(JetTaggerHFTask, processData, "Fill tagging decision for data jets", false); - - void processMCD(JetCollision const& collision, JetTableMCD const& mcdjets, JetTagTracksMCD const& jtracks, OriTracksMCD const& tracks, JetParticles const& particles) - { - for (auto& mcdjet : mcdjets) { - typename JetTagTracksMCD::iterator hftrack; - int origin = 0; - if (!doWShower) - origin = jettaggingutilities::mcdJetFromHFShower(mcdjet, jtracks, particles, maxDeltaR); - else - origin = jettaggingutilities::jetTrackFromHFShower(mcdjet, jtracks, particles, hftrack); - std::vector jetProb; - int algorithm2 = 0; - int algorithm3 = 0; - if (doTC) { - for (int order = 0; order < maxOrder; order++) { - jetProb.push_back(jettaggingutilities::getJetProbability(fSignImpXYSig, collision, mcdjet, jtracks, tracks, order, tagPoint, minSignImpXYSig)); - } - } - // if (doSV) algorithm2 = jettaggingutilities::Algorithm2((mcdjet, tracks); - taggingTableMCD(origin, jetProb, algorithm2, algorithm3); - } - } - PROCESS_SWITCH(JetTaggerHFTask, processMCD, "Fill tagging decision for mcd jets", false); - - void processTraining(JetCollision const& /*collision*/, JetTableMCD const& /*mcdjets*/, JetTagTracksMCD const& /*tracks*/) - { - // To create table for ML - } - PROCESS_SWITCH(JetTaggerHFTask, processTraining, "Fill tagging decision for mcd jets", false); -}; - -struct JetTaggerHFExtTask { - - Produces jTracksTagTable; - - void init(InitContext const&) - { - } - - void processTracks(soa::Join::iterator const& track) - { - float sigmaDcaXYZ2 = 0; - float dcaXYZ = getDcaXYZ(track, &sigmaDcaXYZ2); - - jTracksTagTable(dcaXYZ, sigmaDcaXYZ2); - } - PROCESS_SWITCH(JetTaggerHFExtTask, processTracks, "produces derived track table for tagging", true); -}; - -using JetTaggerChargedJets = JetTaggerHFTask, soa::Join, aod::ChargedJetTags, aod::ChargedMCDetectorLevelJetTags>; -using JetTaggerFullJets = JetTaggerHFTask, soa::Join, aod::FullJetTags, aod::FullMCDetectorLevelJetTags>; -// using JetTaggerNeutralJets = JetTaggerHFTask,soa::Join, aod::NeutralJetTags, aod::NeutralMCDetectorLevelJetTags>; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - - std::vector tasks; - - tasks.emplace_back( - adaptAnalysisTask(cfgc, - SetDefaultProcesses{}, TaskName{"jet-taggerhf-extension"})); - - tasks.emplace_back( - adaptAnalysisTask(cfgc, - SetDefaultProcesses{}, TaskName{"jet-taggerhf-charged"})); - - tasks.emplace_back( - adaptAnalysisTask(cfgc, - SetDefaultProcesses{}, TaskName{"jet-taggerhf-full"})); - /* - tasks.emplace_back( - adaptAnalysisTask(cfgc, - SetDefaultProcesses{}, TaskName{"jet-taggerhf-neutral"})); - */ - return WorkflowSpec{tasks}; -} diff --git a/PWGJE/TableProducer/luminosityCalculator.cxx b/PWGJE/TableProducer/luminosityCalculator.cxx new file mode 100644 index 00000000000..b1d509ab321 --- /dev/null +++ b/PWGJE/TableProducer/luminosityCalculator.cxx @@ -0,0 +1,115 @@ +// 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 luminositycalculator.cxx +/// \brief Task to calculate luminosity of measured data. The luminosity per TVX trigger can be obtained from the eventselectiontask (at the time of writing the variable csTVX) +/// +/// \author Nima Zardoshti + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" + +#include "PWGJE/DataModel/JetReducedData.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct LuminosityCalculator { + + HistogramRegistry registry; + void init(InitContext&) + { + + std::vector histLabels = {"BC", "BC+TVX", "BC+TVX+NoTFB", "BC+TVX+NoTFB+NoITSROFB", "Coll", "Coll+TVX", "Coll+TVX+VtxZ+Sel8", "Coll+TVX+VtxZ+Sel8Full", "Coll+TVX+VtxZ+Sel8FullPbPb", "Coll+TVX+VtxZ+SelMC", "Coll+TVX+VtxZ+SelMCFull", "Coll+TVX+VtxZ+SelMCFullPbPb", "Coll+TVX+VtxZ+SelUnanchoredMC", "Coll+TVX+VtxZ+SelTVX", "Coll+TVX+VtxZ+Sel7", "Coll+TVX+VtxZ+Sel7KINT7", "custom"}; + registry.add("counter", "BCs and Collisions", HistType::kTH1D, {{static_cast(histLabels.size()), -0.5, static_cast(histLabels.size()) - 0.5}}); + auto counter = registry.get(HIST("counter")); + for (std::vector::size_type iCounter = 0; iCounter < histLabels.size(); iCounter++) { + counter->GetXaxis()->SetBinLabel(iCounter + 1, histLabels[iCounter].data()); + } + } + + void processCalculateLuminosity(aod::StoredBCCounts const& bcCounts, aod::StoredCollisionCounts const& collisionCounts) + { + int readBC = 0; + int readBCWithTVXCounter = 0; + int readBCWithTVXAndNoTFBCounter = 0; + int readBCWithTVXAndNoTFBAndNoITSROFB = 0; + + for (const auto& bcCount : bcCounts) { + readBC += bcCount.readCounts().front(); + readBCWithTVXCounter += bcCount.readCountsWithTVX().front(); + readBCWithTVXAndNoTFBCounter += bcCount.readCountsWithTVXAndNoTFB().front(); + readBCWithTVXAndNoTFBAndNoITSROFB += bcCount.readCountsWithTVXAndNoTFBAndNoITSROFB().front(); + } + + int readCollision = 0; + int readCollisionWithTVXCounter = 0; + int readCollisionWithTVXAndZVertexAndSel8Counter = 0; + int readCollisionWithTVXAndZVertexAndSel8FullCounter = 0; + int readCollisionWithTVXAndZVertexAndSel8FullPbPbCounter = 0; + int readCollisionWithTVXAndZVertexAndSelMCCounter = 0; + int readCollisionWithTVXAndZVertexAndSelMCFullCounter = 0; + int readCollisionWithTVXAndZVertexAndSelMCFullPbPbCounter = 0; + int readCollisionWithTVXAndZVertexAndSelUnanchoredMCCounter = 0; + int readCollisionWithTVXAndZVertexAndSelTVXCounter = 0; + int readCollisionWithTVXAndZVertexAndSel7Counter = 0; + int readCollisionWithTVXAndZVertexAndSel7KINT7Counter = 0; + int readCollisionWithCustomCounter = 0; + + for (const auto& collisionCount : collisionCounts) { + readCollision += collisionCount.readCounts().front(); + readCollisionWithTVXCounter += collisionCount.readCountsWithTVX().front(); + readCollisionWithTVXAndZVertexAndSel8Counter += collisionCount.readCountsWithTVXAndZVertexAndSel8().front(); + readCollisionWithTVXAndZVertexAndSel8FullCounter += collisionCount.readCountsWithTVXAndZVertexAndSel8Full().front(); + readCollisionWithTVXAndZVertexAndSel8FullPbPbCounter += collisionCount.readCountsWithTVXAndZVertexAndSel8FullPbPb().front(); + readCollisionWithTVXAndZVertexAndSelMCCounter += collisionCount.readCountsWithTVXAndZVertexAndSelMC().front(); + readCollisionWithTVXAndZVertexAndSelMCFullCounter += collisionCount.readCountsWithTVXAndZVertexAndSelMCFull().front(); + readCollisionWithTVXAndZVertexAndSelMCFullPbPbCounter += collisionCount.readCountsWithTVXAndZVertexAndSelMCFullPbPb().front(); + readCollisionWithTVXAndZVertexAndSelUnanchoredMCCounter += collisionCount.readCountsWithTVXAndZVertexAndSelUnanchoredMC().front(); + readCollisionWithTVXAndZVertexAndSelTVXCounter += collisionCount.readCountsWithTVXAndZVertexAndSelTVX().front(); + readCollisionWithTVXAndZVertexAndSel7Counter += collisionCount.readCountsWithTVXAndZVertexAndSel7().front(); + readCollisionWithTVXAndZVertexAndSel7KINT7Counter += collisionCount.readCountsWithTVXAndZVertexAndSel7KINT7().front(); + readCollisionWithCustomCounter += collisionCount.readCountsWithCustom().front(); + } + + registry.get(HIST("counter"))->SetBinContent(1, registry.get(HIST("counter"))->GetBinContent(1) + readBC); + registry.get(HIST("counter"))->SetBinContent(2, registry.get(HIST("counter"))->GetBinContent(2) + readBCWithTVXCounter); + registry.get(HIST("counter"))->SetBinContent(3, registry.get(HIST("counter"))->GetBinContent(3) + readBCWithTVXAndNoTFBCounter); + registry.get(HIST("counter"))->SetBinContent(4, registry.get(HIST("counter"))->GetBinContent(4) + readBCWithTVXAndNoTFBAndNoITSROFB); + registry.get(HIST("counter"))->SetBinContent(5, registry.get(HIST("counter"))->GetBinContent(5) + readCollision); + registry.get(HIST("counter"))->SetBinContent(6, registry.get(HIST("counter"))->GetBinContent(6) + readCollisionWithTVXCounter); + registry.get(HIST("counter"))->SetBinContent(7, registry.get(HIST("counter"))->GetBinContent(7) + readCollisionWithTVXAndZVertexAndSel8Counter); + registry.get(HIST("counter"))->SetBinContent(8, registry.get(HIST("counter"))->GetBinContent(8) + readCollisionWithTVXAndZVertexAndSel8FullCounter); + registry.get(HIST("counter"))->SetBinContent(9, registry.get(HIST("counter"))->GetBinContent(9) + readCollisionWithTVXAndZVertexAndSel8FullPbPbCounter); + registry.get(HIST("counter"))->SetBinContent(10, registry.get(HIST("counter"))->GetBinContent(10) + readCollisionWithTVXAndZVertexAndSelMCCounter); + registry.get(HIST("counter"))->SetBinContent(11, registry.get(HIST("counter"))->GetBinContent(11) + readCollisionWithTVXAndZVertexAndSelMCFullCounter); + registry.get(HIST("counter"))->SetBinContent(12, registry.get(HIST("counter"))->GetBinContent(12) + readCollisionWithTVXAndZVertexAndSelMCFullPbPbCounter); + registry.get(HIST("counter"))->SetBinContent(13, registry.get(HIST("counter"))->GetBinContent(13) + readCollisionWithTVXAndZVertexAndSelUnanchoredMCCounter); + registry.get(HIST("counter"))->SetBinContent(14, registry.get(HIST("counter"))->GetBinContent(14) + readCollisionWithTVXAndZVertexAndSelTVXCounter); + registry.get(HIST("counter"))->SetBinContent(15, registry.get(HIST("counter"))->GetBinContent(15) + readCollisionWithTVXAndZVertexAndSel7Counter); + registry.get(HIST("counter"))->SetBinContent(16, registry.get(HIST("counter"))->GetBinContent(16) + readCollisionWithTVXAndZVertexAndSel7KINT7Counter); + registry.get(HIST("counter"))->SetBinContent(16, registry.get(HIST("counter"))->GetBinContent(17) + readCollisionWithCustomCounter); + } + PROCESS_SWITCH(LuminosityCalculator, processCalculateLuminosity, "calculate ingredients for luminosity and fill a histogram", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-luminosity-calculator"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/luminosityProducer.cxx b/PWGJE/TableProducer/luminosityProducer.cxx new file mode 100644 index 00000000000..6877da8a812 --- /dev/null +++ b/PWGJE/TableProducer/luminosityProducer.cxx @@ -0,0 +1,239 @@ +// 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 luminosityproducer.cxx +/// \brief Task to produce tables needed for normalisation and luminosity calculation +/// +/// \author Nima Zardoshti + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/runDataProcessing.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct LuminosityProducer { + + Produces storedBCCountsTable; + Produces storedCollisionCountsTable; + + Configurable vertexZCutForCounting{"vertexZCutForCounting", 10.0, "choose z-vertex cut for collision counter"}; + Configurable customEventSelections{"customEventSelections", "sel8", "choose custom event selection to be added"}; + + void init(InitContext&) + { + } + + void processStoreBCCounting(aod::JBCs const& bcs, aod::BCCounts const& bcCounts) + { + int readBCCounter = 0; + int readBCWithTVXCounter = 0; + int readBCWithTVXAndNoTFBCounter = 0; + int readBCWithTVXAndNoTFBAndNoITSROFBCounter = 0; + for (const auto& bc : bcs) { + readBCCounter++; + if (bc.selection_bit(aod::evsel::EventSelectionFlags::kIsTriggerTVX)) { + readBCWithTVXCounter++; + if (bc.selection_bit(aod::evsel::EventSelectionFlags::kNoTimeFrameBorder)) { + readBCWithTVXAndNoTFBCounter++; + if (bc.selection_bit(aod::evsel::EventSelectionFlags::kNoITSROFrameBorder)) { + readBCWithTVXAndNoTFBAndNoITSROFBCounter++; + } + } + } + } + std::vector previousReadCounts; + std::vector previousReadCountsWithTVX; + std::vector previousReadCountsWithTVXAndNoTFB; + std::vector previousReadCountsWithTVXAndNoTFBAndNoITSROFB; + int iPreviousDataFrame = 0; + for (const auto& bcCount : bcCounts) { + auto readBCCounterSpan = bcCount.readCounts(); + auto readBCWithTVXCounterSpan = bcCount.readCountsWithTVX(); + auto readBCWithTVXAndNoTFBCounterSpan = bcCount.readCountsWithTVXAndNoTFB(); + auto readBCWithTVXAndNoTFBAndNoITSROFBCounterSpan = bcCount.readCountsWithTVXAndNoTFBAndNoITSROFB(); + if (iPreviousDataFrame == 0) { + std::copy(readBCCounterSpan.begin(), readBCCounterSpan.end(), std::back_inserter(previousReadCounts)); + std::copy(readBCWithTVXCounterSpan.begin(), readBCWithTVXCounterSpan.end(), std::back_inserter(previousReadCountsWithTVX)); + std::copy(readBCWithTVXAndNoTFBCounterSpan.begin(), readBCWithTVXAndNoTFBCounterSpan.end(), std::back_inserter(previousReadCountsWithTVXAndNoTFB)); + std::copy(readBCWithTVXAndNoTFBAndNoITSROFBCounterSpan.begin(), readBCWithTVXAndNoTFBAndNoITSROFBCounterSpan.end(), std::back_inserter(previousReadCountsWithTVXAndNoTFBAndNoITSROFB)); + } else { + for (unsigned int i = 0; i < previousReadCounts.size(); i++) { // in principle we only care about the first element, but might be interesting information to keep + previousReadCounts[i] += readBCCounterSpan[i]; + previousReadCountsWithTVX[i] += readBCWithTVXCounterSpan[i]; + previousReadCountsWithTVXAndNoTFB[i] += readBCWithTVXAndNoTFBCounterSpan[i]; + previousReadCountsWithTVXAndNoTFBAndNoITSROFB[i] += readBCWithTVXAndNoTFBAndNoITSROFBCounterSpan[i]; + } + } + iPreviousDataFrame++; + } + previousReadCounts.push_back(readBCCounter); + previousReadCountsWithTVX.push_back(readBCWithTVXCounter); + previousReadCountsWithTVXAndNoTFB.push_back(readBCWithTVXAndNoTFBCounter); + previousReadCountsWithTVXAndNoTFBAndNoITSROFB.push_back(readBCWithTVXAndNoTFBAndNoITSROFBCounter); + storedBCCountsTable(previousReadCounts, previousReadCountsWithTVX, previousReadCountsWithTVXAndNoTFB, previousReadCountsWithTVXAndNoTFBAndNoITSROFB); + } + PROCESS_SWITCH(LuminosityProducer, processStoreBCCounting, "write out bc counting output table", true); + + void processStoreCollisionCounting(aod::JetCollisions const& collisions, aod::CollisionCounts const& collisionCounts) + { + int readCollisionCounter = 0; + int readCollisionWithTVXCounter = 0; + int readCollisionWithTVXAndZVertexAndSel8Counter = 0; + int readCollisionWithTVXAndZVertexAndSel8FullCounter = 0; + int readCollisionWithTVXAndZVertexAndSel8FullPbPbCounter = 0; + int readCollisionWithTVXAndZVertexAndSelMCCounter = 0; + int readCollisionWithTVXAndZVertexAndSelMCFullCounter = 0; + int readCollisionWithTVXAndZVertexAndSelMCFullPbPbCounter = 0; + int readCollisionWithTVXAndZVertexAndSelUnanchoredMCCounter = 0; + int readCollisionWithTVXAndZVertexAndSelTVXCounter = 0; // redundant but we keep it + int readCollisionWithTVXAndZVertexAndSel7Counter = 0; + int readCollisionWithTVXAndZVertexAndSel7KINT7Counter = 0; + int readCollisionWithCustomCounter = 0; + for (const auto& collision : collisions) { + readCollisionCounter++; + if (jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("TVX"))) { // asuumes all selections include the TVX trigger + readCollisionWithTVXCounter++; + if (std::abs(collision.posZ()) > vertexZCutForCounting) { + continue; + } + if (jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("sel8"))) { + readCollisionWithTVXAndZVertexAndSel8Counter++; + } + if (jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("TVX"))) { + readCollisionWithTVXAndZVertexAndSelTVXCounter++; + } + if (jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("sel7"))) { + readCollisionWithTVXAndZVertexAndSel7Counter++; + } + if (jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("sel7KINT7"))) { + readCollisionWithTVXAndZVertexAndSel7KINT7Counter++; + } + if (jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("sel8Full"))) { + readCollisionWithTVXAndZVertexAndSel8FullCounter++; + } + if (jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("sel8FullPbPb"))) { + readCollisionWithTVXAndZVertexAndSel8FullPbPbCounter++; + } + if (jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("selMC"))) { + readCollisionWithTVXAndZVertexAndSelMCCounter++; + } + if (jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("selMCFull"))) { + readCollisionWithTVXAndZVertexAndSelMCFullCounter++; + } + if (jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("selMCFullPbPb"))) { + readCollisionWithTVXAndZVertexAndSelMCFullPbPbCounter++; + } + if (jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("selUnanchoredMC"))) { + readCollisionWithTVXAndZVertexAndSelUnanchoredMCCounter++; + } + if (jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits(static_cast(customEventSelections)))) { + readCollisionWithCustomCounter++; + } + } + } + std::vector previousReadCounts; + std::vector previousReadCountsWithTVX; + std::vector previousReadCountsWithTVXAndZVertexAndSel8; + std::vector previousReadCountsWithTVXAndZVertexAndSel8Full; + std::vector previousReadCountsWithTVXAndZVertexAndSel8FullPbPb; + std::vector previousReadCountsWithTVXAndZVertexAndSelMC; + std::vector previousReadCountsWithTVXAndZVertexAndSelMCFull; + std::vector previousReadCountsWithTVXAndZVertexAndSelMCFullPbPb; + std::vector previousReadCountsWithTVXAndZVertexAndSelUnanchoredMC; + std::vector previousReadCountsWithTVXAndZVertexAndSelTVX; + std::vector previousReadCountsWithTVXAndZVertexAndSel7; + std::vector previousReadCountsWithTVXAndZVertexAndSel7KINT7; + std::vector previousReadCountsWithCustom; + + int iPreviousDataFrame = 0; + for (const auto& collisionCount : collisionCounts) { + auto readCollisionCounterSpan = collisionCount.readCounts(); + auto readCollisionWithTVXCounterSpan = collisionCount.readCountsWithTVX(); + auto readCollisionWithTVXAndZVertexAndSel8CounterSpan = collisionCount.readCountsWithTVXAndZVertexAndSel8(); + auto readCollisionWithTVXAndZVertexAndSel8FullCounterSpan = collisionCount.readCountsWithTVXAndZVertexAndSel8Full(); + auto readCollisionWithTVXAndZVertexAndSel8FullPbPbCounterSpan = collisionCount.readCountsWithTVXAndZVertexAndSel8FullPbPb(); + auto readCollisionWithTVXAndZVertexAndSelMCCounterSpan = collisionCount.readCountsWithTVXAndZVertexAndSelMC(); + auto readCollisionWithTVXAndZVertexAndSelMCFullCounterSpan = collisionCount.readCountsWithTVXAndZVertexAndSelMCFull(); + auto readCollisionWithTVXAndZVertexAndSelMCFullPbPbCounterSpan = collisionCount.readCountsWithTVXAndZVertexAndSelMCFullPbPb(); + auto readCollisionWithTVXAndZVertexAndSelUnanchoredMCCounterSpan = collisionCount.readCountsWithTVXAndZVertexAndSelUnanchoredMC(); + auto readCollisionWithTVXAndZVertexAndSelTVXCounterSpan = collisionCount.readCountsWithTVXAndZVertexAndSelTVX(); + auto readCollisionWithTVXAndZVertexAndSel7CounterSpan = collisionCount.readCountsWithTVXAndZVertexAndSel7(); + auto readCollisionWithTVXAndZVertexAndSel7KINT7CounterSpan = collisionCount.readCountsWithTVXAndZVertexAndSel7KINT7(); + auto readCollisionWithCustomCounterSpan = collisionCount.readCountsWithCustom(); + + if (iPreviousDataFrame == 0) { + std::copy(readCollisionCounterSpan.begin(), readCollisionCounterSpan.end(), std::back_inserter(previousReadCounts)); + std::copy(readCollisionWithTVXCounterSpan.begin(), readCollisionWithTVXCounterSpan.end(), std::back_inserter(previousReadCountsWithTVX)); + std::copy(readCollisionWithTVXAndZVertexAndSel8CounterSpan.begin(), readCollisionWithTVXAndZVertexAndSel8CounterSpan.end(), std::back_inserter(previousReadCountsWithTVXAndZVertexAndSel8)); + std::copy(readCollisionWithTVXAndZVertexAndSel8FullCounterSpan.begin(), readCollisionWithTVXAndZVertexAndSel8FullCounterSpan.end(), std::back_inserter(previousReadCountsWithTVXAndZVertexAndSel8Full)); + std::copy(readCollisionWithTVXAndZVertexAndSel8FullPbPbCounterSpan.begin(), readCollisionWithTVXAndZVertexAndSel8FullPbPbCounterSpan.end(), std::back_inserter(previousReadCountsWithTVXAndZVertexAndSel8FullPbPb)); + std::copy(readCollisionWithTVXAndZVertexAndSelMCCounterSpan.begin(), readCollisionWithTVXAndZVertexAndSelMCCounterSpan.end(), std::back_inserter(previousReadCountsWithTVXAndZVertexAndSelMC)); + std::copy(readCollisionWithTVXAndZVertexAndSelMCFullCounterSpan.begin(), readCollisionWithTVXAndZVertexAndSelMCFullCounterSpan.end(), std::back_inserter(previousReadCountsWithTVXAndZVertexAndSelMCFull)); + std::copy(readCollisionWithTVXAndZVertexAndSelMCFullPbPbCounterSpan.begin(), readCollisionWithTVXAndZVertexAndSelMCFullPbPbCounterSpan.end(), std::back_inserter(previousReadCountsWithTVXAndZVertexAndSelMCFullPbPb)); + std::copy(readCollisionWithTVXAndZVertexAndSelUnanchoredMCCounterSpan.begin(), readCollisionWithTVXAndZVertexAndSelUnanchoredMCCounterSpan.end(), std::back_inserter(previousReadCountsWithTVXAndZVertexAndSelUnanchoredMC)); + std::copy(readCollisionWithTVXAndZVertexAndSelTVXCounterSpan.begin(), readCollisionWithTVXAndZVertexAndSelTVXCounterSpan.end(), std::back_inserter(previousReadCountsWithTVXAndZVertexAndSelTVX)); + std::copy(readCollisionWithTVXAndZVertexAndSel7CounterSpan.begin(), readCollisionWithTVXAndZVertexAndSel7CounterSpan.end(), std::back_inserter(previousReadCountsWithTVXAndZVertexAndSel7)); + std::copy(readCollisionWithTVXAndZVertexAndSel7KINT7CounterSpan.begin(), readCollisionWithTVXAndZVertexAndSel7KINT7CounterSpan.end(), std::back_inserter(previousReadCountsWithTVXAndZVertexAndSel7KINT7)); + std::copy(readCollisionWithCustomCounterSpan.begin(), readCollisionWithCustomCounterSpan.end(), std::back_inserter(previousReadCountsWithCustom)); + + } else { + for (unsigned int i = 0; i < previousReadCounts.size(); i++) { // in principle we only care about the first element, but might be interesting information to keep + previousReadCounts[i] += readCollisionCounterSpan[i]; + previousReadCountsWithTVX[i] += readCollisionWithTVXCounterSpan[i]; + previousReadCountsWithTVXAndZVertexAndSel8[i] += readCollisionWithTVXAndZVertexAndSel8CounterSpan[i]; + previousReadCountsWithTVXAndZVertexAndSel8Full[i] += readCollisionWithTVXAndZVertexAndSel8FullCounterSpan[i]; + previousReadCountsWithTVXAndZVertexAndSel8FullPbPb[i] += readCollisionWithTVXAndZVertexAndSel8FullPbPbCounterSpan[i]; + previousReadCountsWithTVXAndZVertexAndSelMC[i] += readCollisionWithTVXAndZVertexAndSelMCCounterSpan[i]; + previousReadCountsWithTVXAndZVertexAndSelMCFull[i] += readCollisionWithTVXAndZVertexAndSelMCFullCounterSpan[i]; + previousReadCountsWithTVXAndZVertexAndSelMCFullPbPb[i] += readCollisionWithTVXAndZVertexAndSelMCFullPbPbCounterSpan[i]; + previousReadCountsWithTVXAndZVertexAndSelUnanchoredMC[i] += readCollisionWithTVXAndZVertexAndSelUnanchoredMCCounterSpan[i]; + previousReadCountsWithTVXAndZVertexAndSelTVX[i] += readCollisionWithTVXAndZVertexAndSelTVXCounterSpan[i]; + previousReadCountsWithTVXAndZVertexAndSel7[i] += readCollisionWithTVXAndZVertexAndSel7CounterSpan[i]; + previousReadCountsWithTVXAndZVertexAndSel7KINT7[i] += readCollisionWithTVXAndZVertexAndSel7KINT7CounterSpan[i]; + previousReadCountsWithCustom[i] += readCollisionWithCustomCounterSpan[i]; + } + } + iPreviousDataFrame++; + } + previousReadCounts.push_back(readCollisionCounter); + previousReadCountsWithTVX.push_back(readCollisionWithTVXCounter); + previousReadCountsWithTVXAndZVertexAndSel8.push_back(readCollisionWithTVXAndZVertexAndSel8Counter); + previousReadCountsWithTVXAndZVertexAndSel8Full.push_back(readCollisionWithTVXAndZVertexAndSel8FullCounter); + previousReadCountsWithTVXAndZVertexAndSel8FullPbPb.push_back(readCollisionWithTVXAndZVertexAndSel8FullPbPbCounter); + previousReadCountsWithTVXAndZVertexAndSelMC.push_back(readCollisionWithTVXAndZVertexAndSelMCCounter); + previousReadCountsWithTVXAndZVertexAndSelMCFull.push_back(readCollisionWithTVXAndZVertexAndSelMCFullCounter); + previousReadCountsWithTVXAndZVertexAndSelMCFullPbPb.push_back(readCollisionWithTVXAndZVertexAndSelMCFullPbPbCounter); + previousReadCountsWithTVXAndZVertexAndSelUnanchoredMC.push_back(readCollisionWithTVXAndZVertexAndSelUnanchoredMCCounter); + previousReadCountsWithTVXAndZVertexAndSelTVX.push_back(readCollisionWithTVXAndZVertexAndSelTVXCounter); + previousReadCountsWithTVXAndZVertexAndSel7.push_back(readCollisionWithTVXAndZVertexAndSel7Counter); + previousReadCountsWithTVXAndZVertexAndSel7KINT7.push_back(readCollisionWithTVXAndZVertexAndSel7KINT7Counter); + previousReadCountsWithCustom.push_back(readCollisionWithCustomCounter); + + storedCollisionCountsTable(previousReadCounts, previousReadCountsWithTVX, previousReadCountsWithTVXAndZVertexAndSel8, previousReadCountsWithTVXAndZVertexAndSel8Full, previousReadCountsWithTVXAndZVertexAndSel8FullPbPb, previousReadCountsWithTVXAndZVertexAndSelMC, previousReadCountsWithTVXAndZVertexAndSelMCFull, previousReadCountsWithTVXAndZVertexAndSelMCFullPbPb, previousReadCountsWithTVXAndZVertexAndSelUnanchoredMC, previousReadCountsWithTVXAndZVertexAndSelTVX, previousReadCountsWithTVXAndZVertexAndSel7, previousReadCountsWithTVXAndZVertexAndSel7KINT7, previousReadCountsWithCustom); + } + PROCESS_SWITCH(LuminosityProducer, processStoreCollisionCounting, "write out collision counting output table", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-luminosity-producer"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/rhoEstimator.cxx b/PWGJE/TableProducer/rhoEstimator.cxx index 2e1adf810de..6e96a6e7825 100644 --- a/PWGJE/TableProducer/rhoEstimator.cxx +++ b/PWGJE/TableProducer/rhoEstimator.cxx @@ -13,6 +13,9 @@ // /// \author Nima Zardoshti +#include +#include + #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ASoA.h" @@ -31,91 +34,333 @@ using namespace o2::framework::expressions; struct RhoEstimatorTask { Produces rhoChargedTable; + Produces rhoChargedMcTable; Produces rhoD0Table; + Produces rhoD0McTable; + Produces rhoDplusTable; + Produces rhoDplusMcTable; Produces rhoLcTable; + Produces rhoLcMcTable; Produces rhoBplusTable; + Produces rhoBplusMcTable; + Produces rhoDielectronTable; + Produces rhoDielectronMcTable; + + struct : ConfigurableGroup { + + Configurable skipMBGapEvents{"skipMBGapEvents", true, "decide to run over MB gap events or not"}; + + Configurable trackPtMin{"trackPtMin", 0.15, "minimum track pT"}; + Configurable trackPtMax{"trackPtMax", 1000.0, "maximum track pT"}; + Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum track eta"}; + Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track eta"}; + Configurable trackPhiMin{"trackPhiMin", -99.0, "minimum track phi"}; + Configurable trackPhiMax{"trackPhiMax", 99.0, "maximum track phi"}; + Configurable trackingEfficiency{"trackingEfficiency", 1.0, "tracking efficiency applied to jet finding"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + + Configurable particleSelections{"particleSelections", "PhysicalPrimary", "set particle selections"}; - Configurable trackPtMin{"trackPtMin", 0.15, "minimum track pT"}; - Configurable trackPtMax{"trackPtMax", 1000.0, "maximum track pT"}; - Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum track eta"}; - Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track eta"}; - Configurable trackPhiMin{"trackPhiMin", -999, "minimum track phi"}; - Configurable trackPhiMax{"trackPhiMax", 999, "maximum track phi"}; - Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; - - Configurable bkgjetR{"bkgjetR", 0.2, "jet resolution parameter for determining background density"}; - Configurable bkgEtaMin{"bkgEtaMin", -0.9, "minimim pseudorapidity for determining background density"}; - Configurable bkgEtaMax{"bkgEtaMax", 0.9, "maximum pseudorapidity for determining background density"}; - Configurable bkgPhiMin{"bkgPhiMin", 0., "minimim phi for determining background density"}; - Configurable bkgPhiMax{"bkgPhiMax", 99.0, "maximum phi for determining background density"}; - Configurable doSparse{"doSparse", false, "perfom sparse estimation"}; + Configurable jetAlgorithm{"jetAlgorithm", 0, "jet clustering algorithm. 0 = kT, 1 = C/A, 2 = Anti-kT"}; + Configurable jetRecombScheme{"jetRecombScheme", 0, "jet recombination scheme. 0 = E-scheme, 1 = pT-scheme, 2 = pT2-scheme"}; + Configurable bkgjetR{"bkgjetR", 0.2, "jet resolution parameter for determining background density"}; + Configurable bkgEtaMin{"bkgEtaMin", -0.7, "minimim pseudorapidity for determining background density"}; + Configurable bkgEtaMax{"bkgEtaMax", 0.7, "maximum pseudorapidity for determining background density"}; + Configurable bkgPhiMin{"bkgPhiMin", -99., "minimim phi for determining background density"}; + Configurable bkgPhiMax{"bkgPhiMax", 99., "maximum phi for determining background density"}; + Configurable doSparse{"doSparse", false, "perfom sparse estimation"}; + + Configurable thresholdChargedJetPtMin{"thresholdChargedJetPtMin", 0.0, "Minimum charged jet pt to accept event"}; + Configurable thresholdNeutralJetPtMin{"thresholdNeutralJetPtMin", 0.0, "Minimum neutral jet pt to accept event"}; + Configurable thresholdFullJetPtMin{"thresholdFullJetPtMin", 0.0, "Minimum full jet pt to accept event"}; + Configurable thresholdTriggerTrackPtMin{"thresholdTriggerTrackPtMin", 0.0, "Minimum trigger track pt to accept event"}; + Configurable thresholdClusterEnergyMin{"thresholdClusterEnergyMin", 0.0, "Minimum cluster energy to accept event"}; + Configurable performTriggerTrackSelection{"performTriggerTrackSelection", false, "only accept trigger tracks that pass one of the track selections"}; + Configurable triggerTrackPtSelectionMin{"triggerTrackPtSelectionMin", 0.15, "only accept trigger tracks that have a pT larger than this pT"}; + Configurable triggerTrackEtaSelectionMax{"triggerTrackEtaSelectionMax", 0.9, "only accept trigger tracks that have an eta smaller than this eta"}; + + Configurable vertexZCut{"vertexZCut", 10.0, "z-vertex cut on event"}; + Configurable eventSelections{"eventSelections", "", "choose event selection"}; + Configurable centralityMin{"centralityMin", -999.0, "minimum centrality"}; + Configurable centralityMax{"centralityMax", 999.0, "maximum centrality"}; + Configurable trackOccupancyInTimeRangeMax{"trackOccupancyInTimeRangeMax", 999999, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + + Configurable triggerMasks{"triggerMasks", "", "possible JE Trigger masks: fJetChLowPt,fJetChHighPt,fTrackLowPt,fTrackHighPt,fJetD0ChLowPt,fJetD0ChHighPt,fJetLcChLowPt,fJetLcChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt,fJetNeutralHighPt,fJetNeutralLowPt,fGammaVeryHighPtEMCAL,fGammaVeryHighPtDCAL,fGammaHighPtEMCAL,fGammaHighPtDCAL,fGammaLowPtEMCAL,fGammaLowPtDCAL,fGammaVeryLowPtEMCAL,fGammaVeryLowPtDCAL"}; + } config; JetBkgSubUtils bkgSub; float bkgPhiMax_; + float bkgPhiMin_; std::vector inputParticles; int trackSelection = -1; + std::string particleSelection; + + std::vector collisionFlag; + Service pdgDatabase; + std::vector eventSelectionBits; + std::vector triggerMaskBits; void init(o2::framework::InitContext&) { - trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(config.trackSelections)); + particleSelection = static_cast(config.particleSelections); - bkgSub.setJetBkgR(bkgjetR); - bkgSub.setEtaMinMax(bkgEtaMin, bkgEtaMax); - if (bkgPhiMax > 98.0) { + bkgSub.setJetAlgorithmAndScheme(static_cast(static_cast(config.jetAlgorithm)), static_cast(static_cast(config.jetRecombScheme))); + bkgSub.setJetBkgR(config.bkgjetR); + bkgSub.setEtaMinMax(config.bkgEtaMin, config.bkgEtaMax); + bkgPhiMax_ = config.bkgPhiMax; + bkgPhiMin_ = config.bkgPhiMin; + if (config.bkgPhiMax > 98.0) { bkgPhiMax_ = 2.0 * M_PI; } - bkgSub.setPhiMinMax(bkgPhiMin, bkgPhiMax_); + if (config.bkgPhiMin < -98.0) { + bkgPhiMin_ = -2.0 * M_PI; + } + bkgSub.setPhiMinMax(bkgPhiMin_, bkgPhiMax_); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(config.eventSelections)); + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(config.triggerMasks); + } + + Filter trackCuts = (aod::jtrack::pt >= config.trackPtMin && aod::jtrack::pt < config.trackPtMax && aod::jtrack::eta > config.trackEtaMin && aod::jtrack::eta < config.trackEtaMax && aod::jtrack::phi >= config.trackPhiMin && aod::jtrack::phi <= config.trackPhiMax); + Filter partCuts = (aod::jmcparticle::pt >= config.trackPtMin && aod::jmcparticle::pt < config.trackPtMax && aod::jmcparticle::eta >= config.trackEtaMin && aod::jmcparticle::eta <= config.trackEtaMax && aod::jmcparticle::phi >= config.trackPhiMin && aod::jmcparticle::phi <= config.trackPhiMax); + + void processSetupCollisionSelection(aod::JCollisions const& collisions) + { + collisionFlag.clear(); + collisionFlag.resize(collisions.size(), false); + } + + void processSetupEventTriggering(aod::JCollision const& collision) + { + if (jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + collisionFlag[collision.globalIndex()] = true; + } } - Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax && aod::jtrack::phi >= trackPhiMin && aod::jtrack::phi <= trackPhiMax); + template + void processSelectionObjects(T& selectionObjects) + { + float selectionObjectPtMin = 0.0; + if constexpr (std::is_same_v, aod::ChargedJets>) { + selectionObjectPtMin = config.thresholdChargedJetPtMin; + } else if constexpr (std::is_same_v, aod::NeutralJets>) { + selectionObjectPtMin = config.thresholdNeutralJetPtMin; + } else if constexpr (std::is_same_v, aod::FullJets>) { + selectionObjectPtMin = config.thresholdFullJetPtMin; + } else if constexpr (std::is_same_v, aod::JTracks>) { + selectionObjectPtMin = config.thresholdTriggerTrackPtMin; + } else if constexpr (std::is_same_v, aod::JClusters>) { + selectionObjectPtMin = config.thresholdClusterEnergyMin; + } else { + selectionObjectPtMin = 0.0; + } + for (const auto& selectionObject : selectionObjects) { + bool isTriggerObject = false; + if constexpr (std::is_same_v, aod::JClusters>) { + if (selectionObject.energy() >= selectionObjectPtMin) { + isTriggerObject = true; + } + } else { + if constexpr (std::is_same_v, aod::JTracks>) { + if (config.performTriggerTrackSelection && !(selectionObject.trackSel() & ~(1 << jetderiveddatautilities::JTrackSel::trackSign))) { + continue; + } + if (selectionObject.pt() < config.triggerTrackPtSelectionMin || std::abs(selectionObject.eta()) > config.triggerTrackEtaSelectionMax) { + continue; + } + } + if (selectionObject.pt() >= selectionObjectPtMin) { + isTriggerObject = true; + } + } + if (isTriggerObject) { + if (selectionObject.collisionId() >= 0) { + collisionFlag[selectionObject.collisionId()] = true; + } + } + } + } + PROCESS_SWITCH(RhoEstimatorTask, processSetupCollisionSelection, "setup the writing for data based on collisions", false); + PROCESS_SWITCH(RhoEstimatorTask, processSetupEventTriggering, "process software triggers", false); + PROCESS_SWITCH_FULL(RhoEstimatorTask, processSelectionObjects, processSelectingChargedJets, "process charged jets", false); + PROCESS_SWITCH_FULL(RhoEstimatorTask, processSelectionObjects, processSelectingNeutralJets, "process neutral jets", false); + PROCESS_SWITCH_FULL(RhoEstimatorTask, processSelectionObjects, processSelectingFullJets, "process full jets", false); + PROCESS_SWITCH_FULL(RhoEstimatorTask, processSelectionObjects, processSelectingClusters, "process EMCal clusters", false); + PROCESS_SWITCH_FULL(RhoEstimatorTask, processSelectionObjects, processSelectingTracks, "process high pt tracks", false); - void processChargedCollisions(JetCollision const& collision, soa::Filtered const& tracks) + void processChargedCollisions(aod::JetCollision const& collision, soa::Filtered const& tracks) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || collision.centrality() < config.centralityMin || collision.centrality() >= config.centralityMax || collision.trackOccupancyInTimeRange() > config.trackOccupancyInTimeRangeMax || std::abs(collision.posZ()) > config.vertexZCut) { + rhoChargedTable(0.0, 0.0); + return; + } + if (collisionFlag.size() != 0 && !collisionFlag[collision.globalIndex()]) { + rhoChargedTable(0.0, 0.0); + return; + } + if (config.skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + rhoChargedTable(-1., -1.); + return; + } inputParticles.clear(); - jetfindingutilities::analyseTracks, soa::Filtered::iterator>(inputParticles, tracks, trackSelection); - auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, doSparse); - rhoChargedTable(collision.globalIndex(), rho, rhoM); + jetfindingutilities::analyseTracks, soa::Filtered::iterator>(inputParticles, tracks, trackSelection, config.trackingEfficiency); + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoChargedTable(rho, rhoM); } PROCESS_SWITCH(RhoEstimatorTask, processChargedCollisions, "Fill rho tables for collisions using charged tracks", true); - void processD0Collisions(JetCollision const&, soa::Filtered const& tracks, CandidatesD0Data const& candidates) + void processChargedMcCollisions(aod::JetMcCollision const& mcCollision, soa::Filtered const& particles) { + if (config.skipMBGapEvents && mcCollision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + rhoChargedMcTable(-1., -1.); + return; + } inputParticles.clear(); + jetfindingutilities::analyseParticles, soa::Filtered::iterator>(inputParticles, particleSelection, 1, particles, pdgDatabase); + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoChargedMcTable(rho, rhoM); + } + PROCESS_SWITCH(RhoEstimatorTask, processChargedMcCollisions, "Fill rho tables for MC collisions using charged tracks", false); + + void processD0Collisions(aod::JetCollision const& collision, soa::Filtered const& tracks, aod::CandidatesD0Data const& candidates) + { for (auto& candidate : candidates) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || collision.centrality() < config.centralityMin || collision.centrality() >= config.centralityMax || collision.trackOccupancyInTimeRange() > config.trackOccupancyInTimeRangeMax || std::abs(collision.posZ()) > config.vertexZCut) { + rhoD0Table(0.0, 0.0); + continue; + } inputParticles.clear(); - jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, std::optional{candidate}); + jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, config.trackingEfficiency, std::optional{candidate}); - auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, doSparse); - rhoD0Table(candidate.globalIndex(), rho, rhoM); + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoD0Table(rho, rhoM); } } PROCESS_SWITCH(RhoEstimatorTask, processD0Collisions, "Fill rho tables for collisions with D0 candidates", false); - void processLcCollisions(JetCollision const&, soa::Filtered const& tracks, CandidatesLcData const& candidates) + void processD0McCollisions(aod::JetMcCollision const&, soa::Filtered const& particles, aod::CandidatesD0MCP const& candidates) + { + for (auto& candidate : candidates) { + inputParticles.clear(); + jetfindingutilities::analyseParticles(inputParticles, particleSelection, 1, particles, pdgDatabase, std::optional{candidate}); + + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoD0McTable(rho, rhoM); + } + } + PROCESS_SWITCH(RhoEstimatorTask, processD0McCollisions, "Fill rho tables for collisions with D0 MCP candidates", false); + + void processDplusCollisions(aod::JetCollision const& collision, soa::Filtered const& tracks, aod::CandidatesDplusData const& candidates) + { + for (auto& candidate : candidates) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || collision.centrality() < config.centralityMin || collision.centrality() >= config.centralityMax || collision.trackOccupancyInTimeRange() > config.trackOccupancyInTimeRangeMax || std::abs(collision.posZ()) > config.vertexZCut) { + rhoDplusTable(0.0, 0.0); + continue; + } + inputParticles.clear(); + jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, config.trackingEfficiency, std::optional{candidate}); + + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoDplusTable(rho, rhoM); + } + } + PROCESS_SWITCH(RhoEstimatorTask, processDplusCollisions, "Fill rho tables for collisions with Dplus candidates", false); + + void processDplusMcCollisions(aod::JetMcCollision const&, soa::Filtered const& particles, aod::CandidatesDplusMCP const& candidates) + { + for (auto& candidate : candidates) { + inputParticles.clear(); + jetfindingutilities::analyseParticles(inputParticles, particleSelection, 1, particles, pdgDatabase, std::optional{candidate}); + + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoDplusMcTable(rho, rhoM); + } + } + PROCESS_SWITCH(RhoEstimatorTask, processDplusMcCollisions, "Fill rho tables for collisions with Dplus MCP candidates", false); + + void processLcCollisions(aod::JetCollision const& collision, soa::Filtered const& tracks, aod::CandidatesLcData const& candidates) { - inputParticles.clear(); for (auto& candidate : candidates) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || collision.centrality() < config.centralityMin || collision.centrality() >= config.centralityMax || collision.trackOccupancyInTimeRange() > config.trackOccupancyInTimeRangeMax || std::abs(collision.posZ()) > config.vertexZCut) { + rhoLcTable(0.0, 0.0); + continue; + } inputParticles.clear(); - jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, std::optional{candidate}); + jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, config.trackingEfficiency, std::optional{candidate}); - auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, doSparse); - rhoLcTable(candidate.globalIndex(), rho, rhoM); + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoLcTable(rho, rhoM); } } PROCESS_SWITCH(RhoEstimatorTask, processLcCollisions, "Fill rho tables for collisions with Lc candidates", false); - void processBplusCollisions(JetCollision const&, soa::Filtered const& tracks, CandidatesBplusData const& candidates) + void processLcMcCollisions(aod::JetMcCollision const&, soa::Filtered const& particles, aod::CandidatesLcMCP const& candidates) + { + for (auto& candidate : candidates) { + inputParticles.clear(); + jetfindingutilities::analyseParticles(inputParticles, particleSelection, 1, particles, pdgDatabase, std::optional{candidate}); + + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoLcMcTable(rho, rhoM); + } + } + PROCESS_SWITCH(RhoEstimatorTask, processLcMcCollisions, "Fill rho tables for collisions with Lc MCP candidates", false); + + void processBplusCollisions(aod::JetCollision const& collision, soa::Filtered const& tracks, aod::CandidatesBplusData const& candidates) + { + for (auto& candidate : candidates) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || collision.centrality() < config.centralityMin || collision.centrality() >= config.centralityMax || collision.trackOccupancyInTimeRange() > config.trackOccupancyInTimeRangeMax || std::abs(collision.posZ()) > config.vertexZCut) { + rhoBplusTable(0.0, 0.0); + continue; + } + inputParticles.clear(); + jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, config.trackingEfficiency, std::optional{candidate}); + + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoBplusTable(rho, rhoM); + } + } + PROCESS_SWITCH(RhoEstimatorTask, processBplusCollisions, "Fill rho tables for collisions with Bplus candidates", false); + + void processBplusMcCollisions(aod::JetMcCollision const&, soa::Filtered const& particles, aod::CandidatesBplusMCP const& candidates) + { + for (auto& candidate : candidates) { + inputParticles.clear(); + jetfindingutilities::analyseParticles(inputParticles, particleSelection, 1, particles, pdgDatabase, std::optional{candidate}); + + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoBplusMcTable(rho, rhoM); + } + } + PROCESS_SWITCH(RhoEstimatorTask, processBplusMcCollisions, "Fill rho tables for collisions with Bplus MCP candidates", false); + + void processDielectronCollisions(aod::JetCollision const& collision, soa::Filtered const& tracks, aod::CandidatesDielectronData const& candidates) + { + for (auto& candidate : candidates) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || collision.centrality() < config.centralityMin || collision.centrality() >= config.centralityMax || collision.trackOccupancyInTimeRange() > config.trackOccupancyInTimeRangeMax || std::abs(collision.posZ()) > config.vertexZCut) { + rhoDielectronTable(0.0, 0.0); + continue; + } + inputParticles.clear(); + jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, config.trackingEfficiency, std::optional{candidate}); + + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoDielectronTable(rho, rhoM); + } + } + PROCESS_SWITCH(RhoEstimatorTask, processDielectronCollisions, "Fill rho tables for collisions with Dielectron candidates", false); + + void processDielectronMcCollisions(aod::JetMcCollision const&, soa::Filtered const& particles, aod::CandidatesDielectronMCP const& candidates) { - inputParticles.clear(); for (auto& candidate : candidates) { inputParticles.clear(); - jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, std::optional{candidate}); + jetfindingutilities::analyseParticles(inputParticles, particleSelection, 1, particles, pdgDatabase, std::optional{candidate}); - auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, doSparse); - rhoBplusTable(candidate.globalIndex(), rho, rhoM); + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoDielectronMcTable(rho, rhoM); } } - PROCESS_SWITCH(RhoEstimatorTask, processBplusCollisions, "Fill rho tables for collisions with Bplus candidates", false); + PROCESS_SWITCH(RhoEstimatorTask, processDielectronMcCollisions, "Fill rho tables for collisions with Dielectron MCP candidates", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"estimator-rho"})}; } diff --git a/PWGJE/TableProducer/secondaryVertexReconstruction.cxx b/PWGJE/TableProducer/secondaryVertexReconstruction.cxx new file mode 100644 index 00000000000..de1b47cb830 --- /dev/null +++ b/PWGJE/TableProducer/secondaryVertexReconstruction.cxx @@ -0,0 +1,391 @@ +// 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 secondaryVertexReconstruction.cxx +/// \brief Task to produce a SV indices table joinable to the jet tables and 3/2-prong SV for hf jet tagging +/// \author Hadi Hassan + +#include +#include +#include +#include + +#include +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "Common/Core/trackUtilities.h" +#include "Common/Core/RecoDecay.h" + +#include "ReconstructionDataFormats/DCA.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetTagging.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" + +#include "PWGHF/Utils/utilsBfieldCCDB.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// TODO track to collision association + +struct SecondaryVertexReconstruction { + + Produces sv3prongTableData; + Produces sv3prongIndicesTableData; + + Produces sv2prongTableData; + Produces sv2prongIndicesTableData; + + Produces sv3prongTableMCD; + Produces sv3prongIndicesTableMCD; + + Produces sv2prongTableMCD; + Produces sv2prongIndicesTableMCD; + + Configurable magneticField{"magneticField", 20.0f, "magnetic field in kG"}; + Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; + Configurable useAbsDCA{"useAbsDCA", false, "Minimise abs. distance rather than chi2"}; + Configurable useWeightedFinalPCA{"useWeightedFinalPCA", false, "Recalculate vertex position using track covariances, effective only if useAbsDCA is true"}; + Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; + Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; + Configurable maxRsv{"maxRsv", 999., "max. radius of the reconstruced SV"}; + Configurable maxZsv{"maxZsv", 999., "max. Z coordinates of the reconstruced SV"}; + Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations is chi2/chi2old > this"}; + Configurable ptMinTrack{"ptMinTrack", -1., "min. track pT"}; + Configurable etaMinTrack{"etaMinTrack", -99999., "min. pseudorapidity"}; + Configurable etaMaxTrack{"etaMaxTrack", 4., "max. pseudorapidity"}; + Configurable fillHistograms{"fillHistograms", true, "do validation plots"}; + + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + + o2::vertexing::DCAFitterN<2> df2; // 2-prong vertex fitter + o2::vertexing::DCAFitterN<3> df3; // 3-prong vertex fitter + Service ccdb; + o2::base::MatLayerCylSet* lut; + + HistogramRegistry registry{"registry"}; + + int runNumber{0}; + float toMicrometers = 10000.; // from cm to µm + double bz{0.}; + + void init(InitContext const&) + { + if (fillHistograms) { + AxisSpec nProngsBins = {6, 2, 8, "nProngs"}; + registry.add("hMassNProngs", "n-prong candidates;SV inv. mass (GeV/#it{c}^{2});nProngs;entries", {HistType::kTH2F, {{500, 0., 30}, nProngsBins}}); + registry.add("hLxySNProngs", "n-prong Decay length in XY;S#it{L}_{xy};nProngs;entries", {HistType::kTH2F, {{100, 0., 100.0}, nProngsBins}}); + registry.add("hLSNProngs", "n-prong Decay length in 3D;S#it{L};nProngs;entries", {HistType::kTH2F, {{100, 0., 100.0}, nProngsBins}}); + registry.add("hFeNProngs", "n-prong Energy fraction carried by the SV from the jet;#it{f}_{E};nProngs;entries", {HistType::kTH2F, {{100, 0., 1.0}, nProngsBins}}); + registry.add("hDcaXYNProngs", "DCAxy of n-prong candidate daughters;#it{p}_{T} (GeV/#it{c});#it{d}_{xy} (#mum);nProngs;entries", {HistType::kTH3F, {{100, 0., 20.}, {200, -500., 500.}, nProngsBins}}); + registry.add("hDcaZNProngs", "DCAz of n-prong candidate daughters;#it{p}_{T} (GeV/#it{c});#it{d}_{z} (#mum);nProngs;entries", {HistType::kTH3F, {{100, 0., 20.}, {200, -500., 500.}, nProngsBins}}); + registry.add("hDispersion", "Vertex dispersion;#sigma_{vtx};nProngs;entries", {HistType::kTH2F, {{200, 0., 1.0}, nProngsBins}}); + } + + df2.setPropagateToPCA(propagateToPCA); + df2.setMaxR(maxR); + df2.setMaxDZIni(maxDZIni); + df2.setMinParamChange(minParamChange); + df2.setMinRelChi2Change(minRelChi2Change); + df2.setUseAbsDCA(useAbsDCA); + df2.setWeightedFinalPCA(useWeightedFinalPCA); + + df3.setPropagateToPCA(propagateToPCA); + df3.setMaxR(maxR); + df3.setMaxDZIni(maxDZIni); + df3.setMinParamChange(minParamChange); + df3.setMinRelChi2Change(minRelChi2Change); + df3.setUseAbsDCA(useAbsDCA); + df3.setWeightedFinalPCA(useWeightedFinalPCA); + + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); + runNumber = 0; + } + + Filter trackCuts = (aod::jtrack::pt > ptMinTrack && aod::jtrack::eta > etaMinTrack && aod::jtrack::eta < etaMaxTrack); + + using JetCollisionwPIs = soa::Join; + using JetTracksData = soa::Filtered>; + using JetTracksMCDwPIs = soa::Filtered>; + using OriginalTracks = soa::Join; + + template + void runCreatorNProng(AnyCollision const& collision, + AnyJet const& analysisJet, + AnyParticles const& listoftracks, + std::vector& svIndices, + o2::vertexing::DCAFitterN& df, + size_t prongIndex = 0, + std::vector currentCombination = {}) + { + + const auto& particles = analysisJet.template tracks_as(); + + if (currentCombination.size() == numProngs) { + // Create an array of track parameters and covariance matrices for the current combination + std::array, numProngs> trackParVars; + double energySV = 0.; + for (unsigned int inum = 0; inum < numProngs; ++inum) { + const auto& prong = particles[currentCombination[inum]].template track_as(); + energySV += prong.energy(o2::constants::physics::MassPiPlus); + trackParVars[inum] = getTrackParCov(prong); + } + + if constexpr (externalMagneticField) { + bz = magneticField; + } else { + auto bc = collision.template bc_as(); + if (runNumber != bc.runNumber()) { + initCCDB(bc, runNumber, ccdb, ccdbPathGrpMag, lut, false); + bz = o2::base::Propagator::Instance()->getNominalBz(); + } + } + + // Use a different fitter depending on the number of prongs + df.setBz(bz); + + // Reconstruct the secondary vertex + int processResult = 0; + try { + std::apply([&df, &processResult](const auto&... elems) { processResult = df.process(elems...); }, trackParVars); + } catch (const std::runtime_error& error) { + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; + return; + } + if (processResult == 0) { + return; + } + + const auto& secondaryVertex = df.getPCACandidatePos(); + if (std::sqrt(secondaryVertex[0] * secondaryVertex[0] + secondaryVertex[1] * secondaryVertex[1]) > maxRsv || std::abs(secondaryVertex[2]) > maxZsv) { + return; + } + + float dispersion = 0.; + for (unsigned int inum = 0; inum < numProngs; ++inum) { + o2::dataformats::VertexBase sv(o2::math_utils::Point3D{secondaryVertex[0], secondaryVertex[1], secondaryVertex[2]}, std::array{0}); + o2::dataformats::DCA dcaSV; + auto& prong = df.getTrack(inum); + prong.propagateToDCA(sv, bz, &dcaSV); + dispersion += (dcaSV.getY() * dcaSV.getY() + dcaSV.getZ() * dcaSV.getZ()); + } + dispersion = std::sqrt(dispersion / numProngs); + + auto chi2PCA = df.getChi2AtPCACandidate(); + auto covMatrixPCA = df.calcPCACovMatrixFlat(); + + registry.fill(HIST("hDispersion"), dispersion, numProngs); + + // get track impact parameters + // This modifies track momenta! + auto primaryVertex = getPrimaryVertex(collision); + auto covMatrixPV = primaryVertex.getCov(); + + // Get track momenta and impact parameters + std::array, numProngs> arrayMomenta; + std::array impactParameters; + for (unsigned int inum = 0; inum < numProngs; ++inum) { + trackParVars[inum].getPxPyPzGlo(arrayMomenta[inum]); + trackParVars[inum].propagateToDCA(primaryVertex, bz, &impactParameters[inum]); + + if (fillHistograms) { + const auto& prong = particles[currentCombination[inum]].template track_as(); + registry.fill(HIST("hDcaXYNProngs"), prong.pt(), impactParameters[inum].getY() * toMicrometers, numProngs); + registry.fill(HIST("hDcaZNProngs"), prong.pt(), impactParameters[inum].getZ() * toMicrometers, numProngs); + } + } + + // get uncertainty of the decay length + double phi, theta; + getPointDirection(std::array{primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, secondaryVertex, phi, theta); + auto errorDecayLength = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); + auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); + + // calculate invariant mass + std::array massArray; + std::fill(massArray.begin(), massArray.end(), o2::constants::physics::MassPiPlus); + double massSV = RecoDecay::m(std::move(arrayMomenta), massArray); + + // fill candidate table rows + if ((doprocessData3Prongs || doprocessData3ProngsExternalMagneticField) && numProngs == 3) { + sv3prongTableData(analysisJet.globalIndex(), + primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ(), + secondaryVertex[0], secondaryVertex[1], secondaryVertex[2], + arrayMomenta[0][0] + arrayMomenta[1][0] + arrayMomenta[2][0], + arrayMomenta[0][1] + arrayMomenta[1][1] + arrayMomenta[2][1], + arrayMomenta[0][2] + arrayMomenta[1][2] + arrayMomenta[2][2], + energySV, massSV, chi2PCA, dispersion, errorDecayLength, errorDecayLengthXY); + svIndices.push_back(sv3prongTableData.lastIndex()); + } else if ((doprocessData2Prongs || doprocessData2ProngsExternalMagneticField) && numProngs == 2) { + sv2prongTableData(analysisJet.globalIndex(), + primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ(), + secondaryVertex[0], secondaryVertex[1], secondaryVertex[2], + arrayMomenta[0][0] + arrayMomenta[1][0], + arrayMomenta[0][1] + arrayMomenta[1][1], + arrayMomenta[0][2] + arrayMomenta[1][2], + energySV, massSV, chi2PCA, dispersion, errorDecayLength, errorDecayLengthXY); + svIndices.push_back(sv2prongTableData.lastIndex()); + } else if ((doprocessMCD3Prongs || doprocessMCD3ProngsExternalMagneticField) && numProngs == 3) { + sv3prongTableMCD(analysisJet.globalIndex(), + primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ(), + secondaryVertex[0], secondaryVertex[1], secondaryVertex[2], + arrayMomenta[0][0] + arrayMomenta[1][0] + arrayMomenta[2][0], + arrayMomenta[0][1] + arrayMomenta[1][1] + arrayMomenta[2][1], + arrayMomenta[0][2] + arrayMomenta[1][2] + arrayMomenta[2][2], + energySV, massSV, chi2PCA, dispersion, errorDecayLength, errorDecayLengthXY); + svIndices.push_back(sv3prongTableMCD.lastIndex()); + } else if ((doprocessMCD2Prongs || doprocessMCD2ProngsExternalMagneticField) && numProngs == 2) { + sv2prongTableMCD(analysisJet.globalIndex(), + primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ(), + secondaryVertex[0], secondaryVertex[1], secondaryVertex[2], + arrayMomenta[0][0] + arrayMomenta[1][0], + arrayMomenta[0][1] + arrayMomenta[1][1], + arrayMomenta[0][2] + arrayMomenta[1][2], + energySV, massSV, chi2PCA, dispersion, errorDecayLength, errorDecayLengthXY); + svIndices.push_back(sv2prongTableMCD.lastIndex()); + } else { + LOG(error) << "No process specified\n"; + } + + // fill histograms + if (fillHistograms) { + double decayLengthNormalised = RecoDecay::distance(std::array{primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, std::array{secondaryVertex[0], secondaryVertex[1], secondaryVertex[2]}) / errorDecayLength; + double decayLengthXYNormalised = RecoDecay::distanceXY(std::array{primaryVertex.getX(), primaryVertex.getY()}, std::array{secondaryVertex[0], secondaryVertex[1]}) / errorDecayLengthXY; + + registry.fill(HIST("hMassNProngs"), massSV, numProngs); + registry.fill(HIST("hLxySNProngs"), decayLengthXYNormalised, numProngs); + registry.fill(HIST("hLSNProngs"), decayLengthNormalised, numProngs); + registry.fill(HIST("hFeNProngs"), energySV / analysisJet.energy() > 1. ? 0.99 : energySV / analysisJet.energy(), numProngs); + } + + return; + } + + // Recursive call to explore all combinations + for (size_t iprong = prongIndex; iprong < particles.size(); ++iprong) { + + const auto& testTrack = particles[iprong].template track_as(); + if (testTrack.pt() < ptMinTrack || testTrack.eta() < etaMinTrack || testTrack.eta() > etaMaxTrack) { + continue; + } + + currentCombination.push_back(iprong); + runCreatorNProng( + collision, analysisJet, listoftracks, svIndices, df, iprong + 1, currentCombination); + currentCombination.pop_back(); + } + } + + void processDummy(JetCollisionwPIs::iterator const& /*collision*/) + { + } + PROCESS_SWITCH(SecondaryVertexReconstruction, processDummy, "Dummy process", true); + + void processData3Prongs(JetCollisionwPIs::iterator const& collision, aod::Collisions const& /*realColl*/, soa::Join const& jets, JetTracksData const& tracks, OriginalTracks const& /*tracks*/, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + { + for (const auto& jet : jets) { + std::vector svIndices; + runCreatorNProng<3, false>(collision.template collision_as(), jet, tracks, svIndices, df3); + sv3prongIndicesTableData(svIndices); + } + } + PROCESS_SWITCH(SecondaryVertexReconstruction, processData3Prongs, "Reconstruct the data 3-prong secondary vertex", false); + + void processData3ProngsExternalMagneticField(JetCollisionwPIs::iterator const& collision, aod::Collisions const& /*realColl*/, soa::Join const& jets, JetTracksData const& tracks, OriginalTracks const& /*tracks*/) + { + for (const auto& jet : jets) { + std::vector svIndices; + runCreatorNProng<3, true>(collision.template collision_as(), jet, tracks, svIndices, df3); + sv3prongIndicesTableData(svIndices); + } + } + PROCESS_SWITCH(SecondaryVertexReconstruction, processData3ProngsExternalMagneticField, "Reconstruct the data 3-prong secondary vertex with external magnetic field", false); + + void processData2Prongs(JetCollisionwPIs::iterator const& collision, aod::Collisions const& /*realColl*/, soa::Join const& jets, JetTracksData const& tracks, OriginalTracks const& /*tracks*/, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + { + for (const auto& jet : jets) { + std::vector svIndices; + runCreatorNProng<2, false>(collision.template collision_as(), jet, tracks, svIndices, df2); + sv2prongIndicesTableData(svIndices); + } + } + PROCESS_SWITCH(SecondaryVertexReconstruction, processData2Prongs, "Reconstruct the data 2-prong secondary vertex", false); + + void processData2ProngsExternalMagneticField(JetCollisionwPIs::iterator const& collision, aod::Collisions const& /*realColl*/, soa::Join const& jets, JetTracksData const& tracks, OriginalTracks const& /*tracks*/) + { + for (const auto& jet : jets) { + std::vector svIndices; + runCreatorNProng<2, true>(collision.template collision_as(), jet, tracks, svIndices, df2); + sv2prongIndicesTableData(svIndices); + } + } + PROCESS_SWITCH(SecondaryVertexReconstruction, processData2ProngsExternalMagneticField, "Reconstruct the data 2-prong secondary vertex with extrernal magnetic field", false); + + void processMCD3Prongs(JetCollisionwPIs::iterator const& collision, aod::Collisions const& /*realColl*/, soa::Join const& mcdjets, JetTracksMCDwPIs const& tracks, OriginalTracks const& /*tracks*/, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + { + for (const auto& jet : mcdjets) { + std::vector svIndices; + runCreatorNProng<3, false>(collision.template collision_as(), jet, tracks, svIndices, df3); + sv3prongIndicesTableMCD(svIndices); + } + } + PROCESS_SWITCH(SecondaryVertexReconstruction, processMCD3Prongs, "Reconstruct the MCD 3-prong secondary vertex", false); + + void processMCD3ProngsExternalMagneticField(JetCollisionwPIs::iterator const& collision, aod::Collisions const& /*realColl*/, soa::Join const& mcdjets, JetTracksMCDwPIs const& tracks, OriginalTracks const& /*tracks*/) + { + for (const auto& jet : mcdjets) { + std::vector svIndices; + runCreatorNProng<3, true>(collision.template collision_as(), jet, tracks, svIndices, df3); + sv3prongIndicesTableMCD(svIndices); + } + } + PROCESS_SWITCH(SecondaryVertexReconstruction, processMCD3ProngsExternalMagneticField, "Reconstruct the MCD 3-prong secondary vertex with external magnetic field", false); + + void processMCD2Prongs(JetCollisionwPIs::iterator const& collision, aod::Collisions const& /*realColl*/, soa::Join const& mcdjets, JetTracksMCDwPIs const& tracks, OriginalTracks const& /*tracks*/, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + { + for (const auto& jet : mcdjets) { + std::vector svIndices; + runCreatorNProng<2, false>(collision.template collision_as(), jet, tracks, svIndices, df2); + sv2prongIndicesTableMCD(svIndices); + } + } + PROCESS_SWITCH(SecondaryVertexReconstruction, processMCD2Prongs, "Reconstruct the MCD 2-prong secondary vertex", false); + + void processMCD2ProngsExternalMagneticField(JetCollisionwPIs::iterator const& collision, aod::Collisions const& /*realColl*/, soa::Join const& mcdjets, JetTracksMCDwPIs const& tracks, OriginalTracks const& /*tracks*/) + { + for (const auto& jet : mcdjets) { + std::vector svIndices; + runCreatorNProng<2, true>(collision.template collision_as(), jet, tracks, svIndices, df2); + sv2prongIndicesTableMCD(svIndices); + } + } + PROCESS_SWITCH(SecondaryVertexReconstruction, processMCD2ProngsExternalMagneticField, "Reconstruct the MCD 2-prong secondary vertex with external magnetic field", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"jet-sv-reconstruction-charged"})}; // o2-linter: disable=name/o2-task +} diff --git a/PWGJE/Tasks/CMakeLists.txt b/PWGJE/Tasks/CMakeLists.txt index af3c4661c85..0b8443531f8 100644 --- a/PWGJE/Tasks/CMakeLists.txt +++ b/PWGJE/Tasks/CMakeLists.txt @@ -11,19 +11,23 @@ o2physics_add_dpl_workflow(emc-cellmonitor - SOURCES emccellmonitor.cxx + SOURCES emcCellMonitor.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore - COMPONENT_NAME Analysis) + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(emc-clustermonitor - SOURCES emcclustermonitor.cxx + SOURCES emcClusterMonitor.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(emc-eventselection-qa - SOURCES emceventselectionqa.cxx + SOURCES emcEventSelectionQA.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(emc-vertexselection-qa - SOURCES emcvertexselectionqa.cxx + SOURCES emcVertexSelectionQA.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore + COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(emcal-gamma-gamma-bc-wise + SOURCES emcalGammaGammaBcWise.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(emc-pi0-energyscale-calib @@ -31,45 +35,125 @@ o2physics_add_dpl_workflow(emc-pi0-energyscale-calib PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(emc-tmmonitor - SOURCES emctmmonitor.cxx + SOURCES emcTmMonitor.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(hadron-photon-correlation + SOURCES hadronPhotonCorrelation.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(mc-generator-studies - SOURCES mcgeneratorstudies.cxx + SOURCES mcGeneratorStudies.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore + COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(photon-isolation-qa + SOURCES photonIsolationQA.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore COMPONENT_NAME Analysis) if(FastJet_FOUND) + o2physics_add_dpl_workflow(jet-background-analysis + SOURCES jetBackgroundAnalysis.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-substructure - SOURCES jetsubstructure.cxx + SOURCES jetSubstructure.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-substructure-output - SOURCES jetsubstructureoutput.cxx + SOURCES jetSubstructureOutput.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-substructure-d0 + SOURCES jetSubstructureD0.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-substructure-dplus + SOURCES jetSubstructureDplus.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-substructure-lc + SOURCES jetSubstructureLc.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-substructure-bplus + SOURCES jetSubstructureBplus.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-substructure-dielectron + SOURCES jetSubstructureDielectron.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-substructure-d0-output + SOURCES jetSubstructureD0Output.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-substructure-dplus-output + SOURCES jetSubstructureDplusOutput.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(jet-substructure-hf - SOURCES jetsubstructurehf.cxx + o2physics_add_dpl_workflow(jet-substructure-lc-output + SOURCES jetSubstructureLcOutput.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(jet-substructure-hf-output - SOURCES jetsubstructurehfoutput.cxx + o2physics_add_dpl_workflow(jet-substructure-bplus-output + SOURCES jetSubstructureBplusOutput.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-substructure-dielectron-output + SOURCES jetSubstructureDielectronOutput.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-fragmentation - SOURCES jetfragmentation.cxx + SOURCES jetFragmentation.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-v0-spectra + SOURCES v0JetSpectra.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-v0qa + SOURCES v0QA.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-charged-qa - SOURCES jetfinderQA.cxx + SOURCES jetFinderQA.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-charged-v2 + SOURCES jetChargedV2.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-finder-d0-qa + SOURCES jetFinderD0QA.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-finder-dplus-qa + SOURCES jetFinderDplusQA.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(jet-finder-hf-qa - SOURCES jetfinderhfQA.cxx + o2physics_add_dpl_workflow(jet-finder-lc-qa + SOURCES jetFinderLcQA.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-finder-bplus-qa + SOURCES jetFinderBplusQA.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-finder-dielectron-qa + SOURCES jetFinderDielectronQA.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-full-qa - SOURCES jetfinderfullQA.cxx + SOURCES jetFinderFullQA.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-finder-v0-qa + SOURCES jetFinderV0QA.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-spectra-charged + SOURCES jetSpectraCharged.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(trigger-correlations @@ -80,16 +164,16 @@ if(FastJet_FOUND) SOURCES ChJetTriggerQATask.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(jet-full-trigger-qa - SOURCES FullJetTriggerQATask.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore - COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-full-trigger-qa + SOURCES fullJetTriggerQATask.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-matching-qa - SOURCES jetmatchingqa.cxx + SOURCES jetMatchingQA.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-validation-qa - SOURCES jetvalidationqa.cxx + SOURCES jetValidationQA.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-tutorial @@ -101,39 +185,88 @@ if(FastJet_FOUND) PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(track-jet-qa - SOURCES trackJetqa.cxx + SOURCES trackJetQA.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(track-efficiency + SOURCES trackEfficiency.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-hadron-recoil SOURCES jetHadronRecoil.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(recoil-jets + SOURCES recoilJets.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-nsubjettiness - SOURCES nSubjettiness.cxx + SOURCES nsubjettiness.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(phi-in-jets SOURCES phiInJets.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(nuclei-in-jets + SOURCES nucleiInJets.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + O2Physics::AnalysisCCDB O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-taggerhf-qa - SOURCES jettaggerhfQA.cxx + SOURCES jetTaggerHFQA.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-lund-reclustering SOURCES jetLundReclustering.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore FastJet::FastJet FastJet::Contrib COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(jet-hf-fragmentation - SOURCES hffragmentationfunction.cxx + o2physics_add_dpl_workflow(hf-fragmentation-function + SOURCES hfFragmentationFunction.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-planarflow - SOURCES jetplanarflow.cxx + SOURCES jetPlanarFlow.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-ch-corr SOURCES jetChCorr.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) -endif() + o2physics_add_dpl_workflow(bjet-tree-creator + SOURCES bjetTreeCreator.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(stat-prompt-photon + SOURCES statPromptPhoton.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(full-jet-spectra-pp + SOURCES fullJetSpectraPP.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(bjet-tagging-ml + SOURCES bjetTaggingML.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2Physics::MLCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-spectra-ese + SOURCES jetSpectraEseTask.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(gamma-jet-tree-producer + SOURCES gammaJetTreeProducer.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(dijet-finder-charged-qa + SOURCES dijetFinderQA.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(bjet-tagging-gnn + SOURCES bjetTaggingGnn.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-shape + SOURCES jetShape.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) +endif() \ No newline at end of file diff --git a/PWGJE/Tasks/ChJetTriggerQATask.cxx b/PWGJE/Tasks/ChJetTriggerQATask.cxx index c575736a8dd..6b60b68569d 100644 --- a/PWGJE/Tasks/ChJetTriggerQATask.cxx +++ b/PWGJE/Tasks/ChJetTriggerQATask.cxx @@ -44,6 +44,16 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using filteredColl = soa::Filtered>::iterator; +using filteredJTracks = soa::Filtered>; +using filteredJets = soa::Filtered>; +using joinedTracks = soa::Join; + +float DcaXYPtCut(float tracPt) +{ + return 0.0105f + 0.0350f / pow(tracPt, 1.1f); +} + // What this task should do // Event by event fill // 1) pT spectrum of tracks in TPC volume @@ -57,15 +67,10 @@ using namespace o2::framework::expressions; struct ChJetTriggerQATask { Configurable evSel{"evSel", "sel8", "choose event selection"}; - Configurable cfgVertexCut{"cfgVertexCut", 10.0, - "Accepted z-vertex range"}; - Configurable cfgTPCVolume{"cfgTPCVolume", 0.9, - "Full eta range"}; // eta range of TPC - Configurable cfgJetR{"cfgJetR", 0.4, - "jet resolution parameter"}; // jet cone radius - Configurable cfgJetPtMin{ - "cfgJetPtMin", 0.15, - "minimum jet pT constituent cut"}; // minimum jet constituent pT + Configurable cfgVertexCut{"cfgVertexCut", 10.0, "Accepted z-vertex range"}; + Configurable cfgTPCVolume{"cfgTPCVolume", 0.9, "Full eta range"}; // eta range of TPC + Configurable cfgJetR{"cfgJetR", 0.4, "jet resolution parameter"}; // jet cone radius + Configurable cfgJetPtMin{"cfgJetPtMin", 0.15, "minimum jet pT constituent cut"}; // minimum jet constituent pT Configurable cfgTrackPhiMinCut{"cfgTrackPhiMinCut", -999, "track min phi cut"}; Configurable cfgTrackPhiMaxCut{"cfgTrackPhiMaxCut", 999, "track max phi cut"}; @@ -75,19 +80,29 @@ struct ChJetTriggerQATask { Configurable bHighPtTrigger{"bHighPtTrigger", false, "charged jet high pT trigger selection"}; Configurable bTrackLowPtTrigger{"bTrackLowPtTrigger", false, "track low pT trigger selection"}; Configurable bTrackHighPtTrigger{"bTrackHighPtTrigger", false, "track high pT trigger selection"}; - Configurable bAddSupplementHistosToOutput{"bAddAdditionalHistosToOutput", false, "add supplementary histos to the output"}; + Configurable phiAngleRestriction{"phiAngleRestriction", 0.3, "angle to restrict track phi for plotting tpc momentum"}; + Configurable dcaXY_multFact{"dcaXY_multFact", 3., "mult factor to relax pT dependent dcaXY cut for quality tracks"}; + Configurable dcaZ_cut{"dcaZ_cut", 3., "cut on dcaZ for quality tracks"}; + + ConfigurableAxis dcaXY_Binning{"dcaXY_Binning", {100, -5., 5.}, ""}; + ConfigurableAxis dcaZ_Binning{"dcaZ_Binning", {100, -3., 3.}, ""}; + + ConfigurableAxis xPhiAxis{"xPhiAxis", {180, 0., TMath::TwoPi()}, ""}; + ConfigurableAxis yQ1pTAxis{"yQ1pTAxis", {200, -0.5, 0.5}, ""}; + float fiducialVolume; // 0.9 - jetR HistogramRegistry spectra; - int eventSelection = -1; + std::vector eventSelectionBits; int trackSelection = -1; - void init(o2::framework::InitContext&) + + void init(InitContext&) { fiducialVolume = static_cast(cfgTPCVolume) - static_cast(cfgJetR); - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(evSel)); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(evSel)); trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); // Basic histos @@ -103,6 +118,21 @@ struct ChJetTriggerQATask { spectra.add("ptetaLeadingJetFullVol", "pT vs eta leading jet", {HistType::kTH2F, {{100, 0., +100.}, {80, -1., 1.}}}); spectra.add("ptphiLeadingJetFullVol", "pT vs phi leading jet", {HistType::kTH2F, {{100, 0., +100.}, {60, 0, TMath::TwoPi()}}}); + spectra.add("globalP_tpcglobalPDiff_withoutcuts", "difference of global and TPC inner momentum vs global momentum without any selection applied", {HistType::kTH2F, {{100, 0., +100.}, {200, -100., +100.}}}); + spectra.add("globalP_tpcglobalPDiff", "difference of global and TPC inner momentum vs global momentum with selection applied", {HistType::kTH2F, {{100, 0., +100.}, {200, -100., +100.}}}); + spectra.add("global1overP_tpcglobalPDiff", "difference of global and TPC inner momentum vs global momentum with selection applied", {HistType::kTH2F, {{100, 0., +100.}, {500, -8., +8.}}}); + + spectra.add("globalP_tpcglobalPDiff_withoutcuts_phirestrict", "difference of global and TPC inner momentum vs global momentum without any selection applied in a restricted phi", {HistType::kTH2F, {{100, 0., +100.}, {200, -100., +100.}}}); + spectra.add("globalP_tpcglobalPDiff_phirestrict", "difference of global and TPC inner momentum vs global momentum with selection applied restricted phi", {HistType::kTH2F, {{100, 0., +100.}, {200, -100., +100.}}}); + spectra.add("global1overP_tpcglobalPDiff_phirestrict", "difference of 1/p global and TPC inner momentum vs global momentum with selection applied restricted phi", {HistType::kTH2F, {{100, 0., +100.}, {500, -8., +8.}}}); + + spectra.add("DCAxy_track_Phi_pT", "track DCAxy vs phi & pT of tracks w. nITSClusters #geq 4", kTH3F, {dcaXY_Binning, {60, 0., TMath::TwoPi()}, {100, 0., 100.}}); + spectra.add("DCAz_track_Phi_pT", "track DCAz vs phi & pT of tracks w. nITSClusters #geq 4", kTH3F, {dcaZ_Binning, {60, 0., TMath::TwoPi()}, {100, 0., 100.}}); + spectra.add("nITSClusters_TrackPt", "Number of ITS hits vs phi & pT of tracks", kTH3F, {{7, 1., 8.}, {60, 0., TMath::TwoPi()}, {100, 0., 100.}}); + spectra.add("ptphiQualityTracks", "pT vs phi of quality tracks", {HistType::kTH2F, {{100, 0., 100.}, {60, 0, TMath::TwoPi()}}}); + spectra.add("ptphiAllTracks", "pT vs phi of all tracks", {HistType::kTH2F, {{100, 0., +100.}, {60, 0, TMath::TwoPi()}}}); + spectra.add("phi_Q1pT", "Track phi vs. q/pT", kTH2F, {xPhiAxis, yQ1pTAxis}); + // Supplementary plots if (bAddSupplementHistosToOutput) { spectra.add("ptJetChInclFullVol", "inclusive charged jet pT in full volume", {HistType::kTH1F, {{200, 0., +200.}}}); @@ -127,26 +157,21 @@ struct ChJetTriggerQATask { Filter trackFilter = (nabs(aod::jtrack::eta) < static_cast(cfgTPCVolume)) && (aod::jtrack::phi > static_cast(cfgTrackPhiMinCut)) && (aod::jtrack::phi < static_cast(cfgTrackPhiMaxCut)) && (aod::jtrack::pt > static_cast(cfgJetPtMin)); // declare filters on jets - Filter jetRadiusSelection = (o2::aod::jet::r == nround(cfgJetR.node() * 100.0f)); - - using filteredJets = o2::soa::Filtered; + Filter jetRadiusSelection = (aod::jet::r == nround(cfgJetR.node() * 100.0f)); - void - process(soa::Filtered>::iterator const& collision, - soa::Filtered const& tracks, o2::soa::Filtered> const& jets) + void process(filteredColl const& collision, filteredJTracks const& tracks, filteredJets const& jets, joinedTracks const&) { if (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { return; } - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } - bool bLowPtJet = (bLowPtTrigger && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow)); - bool bHighPtJet = (bHighPtTrigger && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)); + bool bLowPtJet = (bLowPtTrigger && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::jetChLowPt)); + bool bHighPtJet = (bHighPtTrigger && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::jetChHighPt)); bool bLowPtTrack = (bTrackLowPtTrigger && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::trackLowPt)); bool bHighPtTrack = (bTrackHighPtTrigger && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::trackHighPt)); bool bMinimumBias = ((!bLowPtTrigger) && (!bHighPtTrigger) && (!bTrackLowPtTrigger) && (!bTrackHighPtTrigger)); @@ -169,36 +194,69 @@ struct ChJetTriggerQATask { spectra.fill(HIST("vertexZ"), collision.posZ()); // Inclusive Track Cross TPC Rows - for (auto& trk : tracks) { // loop over filtered tracks in full TPC volume having pT > 100 MeV + for (auto const& track : tracks) { // loop over filtered tracks in full TPC volume having pT > 100 MeV + + auto const& originalTrack = track.track_as(); - if (!jetderiveddatautilities::selectTrack(trk, trackSelection)) { + spectra.fill(HIST("globalP_tpcglobalPDiff_withoutcuts"), track.p(), track.p() - originalTrack.tpcInnerParam()); + + if (TMath::Abs(track.phi() - TMath::Pi()) < phiAngleRestriction) { + spectra.fill(HIST("globalP_tpcglobalPDiff_withoutcuts_phirestrict"), track.p(), track.p() - originalTrack.tpcInnerParam()); + } + + spectra.fill(HIST("ptphiAllTracks"), track.pt(), track.phi()); + + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { continue; } + spectra.fill(HIST("phi_Q1pT"), originalTrack.phi(), originalTrack.sign() / originalTrack.pt()); + spectra.fill(HIST("ptphiQualityTracks"), track.pt(), track.phi()); + + bool bDcaCondition = (fabs(track.dcaZ()) < dcaZ_cut) && (fabs(track.dcaXY()) < dcaXY_multFact * DcaXYPtCut(track.pt())); + if (originalTrack.itsNCls() >= 4 && bDcaCondition) { // correspond to number of track hits in ITS layers + spectra.fill(HIST("DCAxy_track_Phi_pT"), track.dcaXY(), track.phi(), track.pt()); + spectra.fill(HIST("DCAz_track_Phi_pT"), track.dcaZ(), track.phi(), track.pt()); + } + + spectra.fill(HIST("nITSClusters_TrackPt"), originalTrack.itsNCls(), track.phi(), track.pt()); + + spectra.fill(HIST("globalP_tpcglobalPDiff"), track.p(), track.p() - originalTrack.tpcInnerParam()); + if (track.p() > 0 && originalTrack.tpcInnerParam() > 0) { + spectra.fill(HIST("global1overP_tpcglobalPDiff"), track.p(), 1. / track.p() - 1. / originalTrack.tpcInnerParam()); + } + if (TMath::Abs(track.phi() - TMath::Pi()) < phiAngleRestriction) { + spectra.fill(HIST("globalP_tpcglobalPDiff_phirestrict"), track.p(), track.p() - originalTrack.tpcInnerParam()); + + if (track.p() > 0 && originalTrack.tpcInnerParam() > 0) { + spectra.fill(HIST("global1overP_tpcglobalPDiff_phirestrict"), track.p(), 1. / track.p() - 1. / originalTrack.tpcInnerParam()); + } + } + spectra.fill( - HIST("ptphiTrackInclGood"), trk.pt(), - trk.phi()); // Inclusive Track pT vs phi spectrum in TPC volume + HIST("ptphiTrackInclGood"), track.pt(), + track.phi()); // Inclusive Track pT vs phi spectrum in TPC volume spectra.fill( - HIST("ptetaTrackInclGood"), trk.pt(), - trk.eta()); // Inclusive Track pT vs eta spectrum in TPC volume + HIST("ptetaTrackInclGood"), track.pt(), + track.eta()); // Inclusive Track pT vs eta spectrum in TPC volume if (bAddSupplementHistosToOutput) { spectra.fill( - HIST("phietaTrackAllInclGood"), trk.eta(), - trk.phi()); // Inclusive Track pT vs eta spectrum in TPC volume + HIST("phietaTrackAllInclGood"), track.eta(), + track.phi()); // Inclusive Track pT vs eta spectrum in TPC volume - if (trk.pt() > 5.0) { + if (track.pt() > 5.0) { spectra.fill( - HIST("phietaTrackHighPtInclGood"), trk.eta(), - trk.phi()); // Inclusive Track pT vs eta spectrum in TPC volume + HIST("phietaTrackHighPtInclGood"), track.eta(), + track.phi()); // Inclusive Track pT vs eta spectrum in TPC volume } } - if (trk.pt() > + if (track.pt() > leadingTrackPt) { // Find leading track pT in full TPC volume - leadingTrackPt = trk.pt(); - leadingTrackEta = trk.eta(); - leadingTrackPhi = trk.phi(); + leadingTrackPt = track.pt(); + leadingTrackEta = track.eta(); + leadingTrackPhi = track.phi(); } } diff --git a/PWGJE/Tasks/bjetTaggingGnn.cxx b/PWGJE/Tasks/bjetTaggingGnn.cxx new file mode 100644 index 00000000000..9cc4e89088a --- /dev/null +++ b/PWGJE/Tasks/bjetTaggingGnn.cxx @@ -0,0 +1,486 @@ +// 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 bjetTaggingGnn.cxx +/// \brief b-jet tagging using GNN +/// +/// \author Changhwan Choi , Pusan National University + +#include +#include +#include +#include + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoA.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetTaggingUtilities.h" +#include "PWGJE/DataModel/JetTagging.h" +#include "PWGJE/DataModel/Jet.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/RecoDecay.h" + +#include "Framework/Logger.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct BjetTaggingGnn { + + HistogramRegistry registry; + + // event level configurables + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable useEventWeight{"useEventWeight", true, "Flag whether to scale histograms with the event weight"}; + + Configurable pTHatMaxMCD{"pTHatMaxMCD", 999.0, "maximum fraction of hard scattering for jet acceptance in detector MC"}; + Configurable pTHatMaxMCP{"pTHatMaxMCP", 999.0, "maximum fraction of hard scattering for jet acceptance in particle MC"}; + Configurable pTHatExponent{"pTHatExponent", 6.0, "exponent of the event weight for the calculation of pTHat"}; + + // track level configurables + Configurable trackPtMin{"trackPtMin", 0.5, "minimum track pT"}; + Configurable trackPtMax{"trackPtMax", 1000.0, "maximum track pT"}; + Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum track eta"}; + Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track eta"}; + + Configurable trackNppCrit{"trackNppCrit", 0.95, "track not physical primary ratio"}; + + // track level configurables + Configurable svPtMin{"svPtMin", 0.5, "minimum SV pT"}; + + // jet level configurables + Configurable jetPtMin{"jetPtMin", 5.0, "minimum jet pT"}; + Configurable jetPtMax{"jetPtMax", 1000.0, "maximum jet pT"}; + Configurable jetEtaMin{"jetEtaMin", -99.0, "minimum jet pseudorapidity"}; + Configurable jetEtaMax{"jetEtaMax", 99.0, "maximum jet pseudorapidity"}; + + Configurable> jetRadii{"jetRadii", std::vector{0.4}, "jet resolution parameters"}; + + Configurable doDataDriven{"doDataDriven", false, "Flag whether to use fill THnSpase for data driven methods"}; + Configurable callSumw2{"callSumw2", false, "Flag whether to call THnSparse::Sumw2() for error calculation"}; + + std::vector eventSelectionBits; + + std::vector jetRadiiValues; + + void init(InitContext const&) + { + jetRadiiValues = (std::vector)jetRadii; + + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + + registry.add("h_vertexZ", "Vertex Z;#it{Z} (cm)", {HistType::kTH1F, {{40, -20.0, 20.0}}}); + + const AxisSpec axisJetpT{200, 0., 200., "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisDb{200, -10., 20., "#it{D}_{b}"}; + const AxisSpec axisDbFine{3000, -10., 20., "#it{D}_{b}"}; + const AxisSpec axisSVMass{200, 0., 10., "#it{m}_{SV} (GeV/#it{c}^{2})"}; + const AxisSpec axisSVEnergy{200, 0., 100., "#it{E}_{SV} (GeV)"}; + const AxisSpec axisSLxy{200, 0., 100., "#it{SL}_{xy}"}; + const AxisSpec axisJetMass{200, 0., 50., "#it{m}_{jet} (GeV/#it{c}^{2})"}; + const AxisSpec axisJetProb{200, 0., 40., "-ln(JP)"}; + const AxisSpec axisNTracks{42, 0, 42, "#it{n}_{tracks}"}; + + registry.add("h_jetpT", "", {HistType::kTH1F, {axisJetpT}}); + registry.add("h_Db", "", {HistType::kTH1F, {axisDbFine}}); + registry.add("h2_jetpT_Db", "", {HistType::kTH2F, {axisJetpT, axisDb}}); + registry.add("h2_jetpT_SVMass", "", {HistType::kTH2F, {axisJetpT, axisSVMass}}); + registry.add("h2_jetpT_jetMass", "", {HistType::kTH2F, {axisJetpT, axisJetMass}}); + registry.add("h2_jetpT_jetProb", "", {HistType::kTH2F, {axisJetpT, axisJetProb}}); + registry.add("h2_jetpT_nTracks", "", {HistType::kTH2F, {axisJetpT, axisNTracks}}); + + if (doprocessMCJets) { + registry.add("h_jetpT_b", "b-jet", {HistType::kTH1F, {axisJetpT}}); + registry.add("h_jetpT_c", "c-jet", {HistType::kTH1F, {axisJetpT}}); + registry.add("h_jetpT_lf", "lf-jet", {HistType::kTH1F, {axisJetpT}}); + registry.add("h_Db_b", "b-jet", {HistType::kTH1F, {axisDbFine}}); + registry.add("h_Db_c", "c-jet", {HistType::kTH1F, {axisDbFine}}); + registry.add("h_Db_lf", "lf-jet", {HistType::kTH1F, {axisDbFine}}); + registry.add("h2_jetpT_Db_b", "b-jet", {HistType::kTH2F, {axisJetpT, axisDb}}); + registry.add("h2_jetpT_Db_c", "c-jet", {HistType::kTH2F, {axisJetpT, axisDb}}); + registry.add("h2_jetpT_Db_lf", "lf-jet", {HistType::kTH2F, {axisJetpT, axisDb}}); + registry.add("h2_jetpT_SVMass_b", "b-jet", {HistType::kTH2F, {axisJetpT, axisSVMass}}); + registry.add("h2_jetpT_SVMass_c", "c-jet", {HistType::kTH2F, {axisJetpT, axisSVMass}}); + registry.add("h2_jetpT_SVMass_lf", "lf-jet", {HistType::kTH2F, {axisJetpT, axisSVMass}}); + registry.add("h2_jetpT_jetMass_b", "b-jet", {HistType::kTH2F, {axisJetpT, axisJetMass}}); + registry.add("h2_jetpT_jetMass_c", "c-jet", {HistType::kTH2F, {axisJetpT, axisJetMass}}); + registry.add("h2_jetpT_jetMass_lf", "lf-jet", {HistType::kTH2F, {axisJetpT, axisJetMass}}); + registry.add("h2_jetpT_jetProb_b", "b-jet", {HistType::kTH2F, {axisJetpT, axisJetProb}}); + registry.add("h2_jetpT_jetProb_c", "c-jet", {HistType::kTH2F, {axisJetpT, axisJetProb}}); + registry.add("h2_jetpT_jetProb_lf", "lf-jet", {HistType::kTH2F, {axisJetpT, axisJetProb}}); + registry.add("h2_jetpT_nTracks_b", "b-jet", {HistType::kTH2F, {axisJetpT, axisNTracks}}); + registry.add("h2_jetpT_nTracks_c", "c-jet", {HistType::kTH2F, {axisJetpT, axisNTracks}}); + registry.add("h2_jetpT_nTracks_lf", "lf-jet", {HistType::kTH2F, {axisJetpT, axisNTracks}}); + registry.add("h2_Response_DetjetpT_PartjetpT", "", {HistType::kTH2F, {axisJetpT, axisJetpT}}); + registry.add("h2_Response_DetjetpT_PartjetpT_b", "b-jet", {HistType::kTH2F, {axisJetpT, axisJetpT}}); + registry.add("h2_Response_DetjetpT_PartjetpT_c", "c-jet", {HistType::kTH2F, {axisJetpT, axisJetpT}}); + registry.add("h2_Response_DetjetpT_PartjetpT_lf", "lf-jet", {HistType::kTH2F, {axisJetpT, axisJetpT}}); + registry.add("h2_jetpT_Db_lf_none", "lf-jet (none)", {HistType::kTH2F, {axisJetpT, axisDb}}); + registry.add("h2_jetpT_Db_lf_matched", "lf-jet (matched)", {HistType::kTH2F, {axisJetpT, axisDb}}); + registry.add("h2_jetpT_Db_npp", "NotPhysPrim", {HistType::kTH2F, {axisJetpT, axisDb}}); + registry.add("h2_jetpT_Db_npp_b", "NotPhysPrim b-jet", {HistType::kTH2F, {axisJetpT, axisDb}}); + registry.add("h2_jetpT_Db_npp_c", "NotPhysPrim c-jet", {HistType::kTH2F, {axisJetpT, axisDb}}); + registry.add("h2_jetpT_Db_npp_lf", "NotPhysPrim lf-jet", {HistType::kTH2F, {axisJetpT, axisDb}}); + registry.add("h_Db_npp", "NotPhysPrim", {HistType::kTH1F, {axisDbFine}}); + registry.add("h_Db_npp_b", "NotPhysPrim b-jet", {HistType::kTH1F, {axisDbFine}}); + registry.add("h_Db_npp_c", "NotPhysPrim c-jet", {HistType::kTH1F, {axisDbFine}}); + registry.add("h_Db_npp_lf", "NotPhysPrim lf-jet", {HistType::kTH1F, {axisDbFine}}); + // registry.add("h2_pT_dcaXY_pp", "tracks", {HistType::kTH2F, {axisJetpT, {200, 0., 1.}}}); + // registry.add("h2_pT_dcaXY_npp", "NotPhysPrim tracks", {HistType::kTH2F, {axisJetpT, {200, 0., 1.}}}); + // registry.add("h2_pT_dcaZ_pp", "tracks", {HistType::kTH2F, {axisJetpT, {200, 0., 2.}}}); + // registry.add("h2_pT_dcaZ_npp", "NotPhysPrim tracks", {HistType::kTH2F, {axisJetpT, {200, 0., 2.}}}); + } + + if (doprocessMCTruthJets) { + registry.add("h_jetpT_particle", "", {HistType::kTH1F, {axisJetpT}}); + registry.add("h_jetpT_particle_b", "particle b-jet", {HistType::kTH1F, {axisJetpT}}); + registry.add("h_jetpT_particle_c", "particle c-jet", {HistType::kTH1F, {axisJetpT}}); + registry.add("h_jetpT_particle_lf", "particle lf-jet", {HistType::kTH1F, {axisJetpT}}); + } + + if (doDataDriven) { + registry.add("hSparse_Incljets", "", {HistType::kTHnSparseF, {axisJetpT, axisDbFine, axisSVMass, axisJetMass, axisNTracks}}, callSumw2); + if (doprocessMCJets) { + registry.add("hSparse_bjets", "", {HistType::kTHnSparseF, {axisJetpT, axisDbFine, axisSVMass, axisJetMass, axisNTracks}}, callSumw2); + registry.add("hSparse_cjets", "", {HistType::kTHnSparseF, {axisJetpT, axisDbFine, axisSVMass, axisJetMass, axisNTracks}}, callSumw2); + registry.add("hSparse_lfjets", "", {HistType::kTHnSparseF, {axisJetpT, axisDbFine, axisSVMass, axisJetMass, axisNTracks}}, callSumw2); + registry.add("hSparse_lfjets_none", "", {HistType::kTHnSparseF, {axisJetpT, axisDbFine, axisSVMass, axisJetMass, axisNTracks}}, callSumw2); + registry.add("hSparse_lfjets_matched", "", {HistType::kTHnSparseF, {axisJetpT, axisDbFine, axisSVMass, axisJetMass, axisNTracks}}, callSumw2); + } + } + } + + Filter collisionFilter = nabs(aod::jcollision::posZ) < vertexZCut; + Filter trackCuts = (aod::jtrack::pt > trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); + Filter jetFilter = (aod::jet::pt >= jetPtMin && aod::jet::pt <= jetPtMax && aod::jet::eta < jetEtaMax - aod::jet::r / 100.f && aod::jet::eta > jetEtaMin + aod::jet::r / 100.f); + + using FilteredCollision = soa::Filtered>; + using DataJets = soa::Filtered>; + using JetTrackswID = soa::Filtered>; + using JetTracksMCDwID = soa::Filtered>; + using SVTable = aod::DataSecondaryVertex3Prongs; + using MCDSVTable = aod::MCDSecondaryVertex3Prongs; + + template + int analyzeJetTrackInfo(AnyCollision const& /*collision*/, AnalysisJet const& analysisJet, AnyTracks const& /*allTracks*/ /*, int8_t jetFlavor = 0, double weight = 1.0*/) + { + int nTracks = 0; + for (const auto& constituent : analysisJet.template tracks_as()) { + + if (constituent.pt() < trackPtMin) { + continue; + } + + // ... + + ++nTracks; + } + return nTracks; + } + + template + SecondaryVertices::iterator analyzeJetSVInfo(AnalysisJet const& analysisJet, SecondaryVertices const& allSVs, bool& checkSV /*, int8_t jetFlavor = 0, double weight = 1.0*/) + { + using SVType = typename SecondaryVertices::iterator; + + auto compare = [](SVType& sv1, SVType& sv2) { + return (sv1.decayLengthXY() / sv1.errorDecayLengthXY()) > (sv2.decayLengthXY() / sv2.errorDecayLengthXY()); + }; + + auto svs = analysisJet.template secondaryVertices_as(); + + std::sort(svs.begin(), svs.end(), compare); + + checkSV = false; + for (const auto& candSV : svs) { + + if (candSV.pt() < svPtMin) { + continue; + } + + checkSV = true; + return candSV; + } + + // No SV found + return *allSVs.begin(); + } + + void processDummy(FilteredCollision::iterator const& /*collision*/) + { + } + PROCESS_SWITCH(BjetTaggingGnn, processDummy, "Dummy process function turned on by default", true); + + void processDataJets(FilteredCollision::iterator const& collision, DataJets const& alljets, JetTrackswID const& allTracks, SVTable const& allSVs) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + + registry.fill(HIST("h_vertexZ"), collision.posZ()); + + for (const auto& analysisJet : alljets) { + + bool jetIncluded = false; + for (const auto& jetR : jetRadiiValues) { + if (analysisJet.r() == static_cast(jetR * 100)) { + jetIncluded = true; + break; + } + } + + if (!jetIncluded) { + continue; + } + + int nTracks = analyzeJetTrackInfo(collision, analysisJet, allTracks); + + float mSV = -1.f; + // float eSV = -1.f; + // float slXY = -1.f; + + bool checkSV; + // auto sv = jettaggingutilities::jetFromProngMaxDecayLength(analysisJet, prongChi2PCAMin, prongChi2PCAMax, prongsigmaLxyMax, prongIPxyMin, prongIPxyMax, false, &checkSV); + auto sv = analyzeJetSVInfo(analysisJet, allSVs, checkSV); + + if (checkSV) { + mSV = sv.m(); + // eSV = sv.e(); + // slXY = sv.decayLengthXY() / sv.errorDecayLengthXY(); + } + + registry.fill(HIST("h_jetpT"), analysisJet.pt()); + registry.fill(HIST("h_Db"), analysisJet.scoreML()); + registry.fill(HIST("h2_jetpT_Db"), analysisJet.pt(), analysisJet.scoreML()); + registry.fill(HIST("h2_jetpT_SVMass"), analysisJet.pt(), mSV); + registry.fill(HIST("h2_jetpT_jetMass"), analysisJet.pt(), analysisJet.mass()); + registry.fill(HIST("h2_jetpT_jetProb"), analysisJet.pt(), analysisJet.jetProb()); + registry.fill(HIST("h2_jetpT_nTracks"), analysisJet.pt(), nTracks); + + if (doDataDriven) { + registry.fill(HIST("hSparse_Incljets"), analysisJet.pt(), analysisJet.scoreML(), mSV, analysisJet.mass(), nTracks); + } + } + } + PROCESS_SWITCH(BjetTaggingGnn, processDataJets, "jet information in Data", false); + + using MCDJetTable = soa::Filtered>; + using MCPJetTable = soa::Filtered>; + using FilteredCollisionMCD = soa::Filtered>; + + void processMCJets(FilteredCollisionMCD::iterator const& collision, MCDJetTable const& MCDjets, MCPJetTable const& /*MCPjets*/, JetTracksMCDwID const& /*allTracks*/, MCDSVTable const& allSVs, aod::JetParticles const& /*MCParticles*/) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + + registry.fill(HIST("h_vertexZ"), collision.posZ()); + + for (const auto& analysisJet : MCDjets) { + + bool jetIncluded = false; + for (const auto& jetR : jetRadiiValues) { + if (analysisJet.r() == static_cast(jetR * 100)) { + jetIncluded = true; + break; + } + } + + if (!jetIncluded) { + continue; + } + + float weight = useEventWeight ? analysisJet.eventWeight() : 1.f; + float pTHat = 10. / (std::pow(analysisJet.eventWeight(), 1.0 / pTHatExponent)); + if (analysisJet.pt() > pTHatMaxMCD * pTHat) { + continue; + } + + int8_t jetFlavor = analysisJet.origin(); + + // int nTracks = analyzeJetTrackInfo(collision, analysisJet, allTracks /*, jetFlavor, weight*/); + int nTracks = 0; + + int nNppTracks = 0; + for (const auto& constituent : analysisJet.template tracks_as()) { + if (constituent.pt() < trackPtMin) { + continue; + } + if (!constituent.has_mcParticle() || !constituent.template mcParticle_as().isPhysicalPrimary()) { + // registry.fill(HIST("h2_pT_dcaXY_npp"), constituent.pt(), constituent.dcaXY()); + // registry.fill(HIST("h2_pT_dcaZ_npp"), constituent.pt(), constituent.dcaZ()); + ++nNppTracks; + } else { + // registry.fill(HIST("h2_pT_dcaXY_pp"), constituent.pt(), constituent.dcaXY()); + // registry.fill(HIST("h2_pT_dcaZ_pp"), constituent.pt(), constituent.dcaZ()); + } + ++nTracks; + } + + float mSV = -1.f; + // float eSV = -1.f; + // float slXY = -1.f; + + bool checkSV; + auto sv = analyzeJetSVInfo(analysisJet, allSVs, checkSV /*, jetFlavor, weight*/); + + if (checkSV) { + mSV = sv.m(); + // eSV = sv.e(); + // slXY = sv.decayLengthXY() / sv.errorDecayLengthXY(); + } + + registry.fill(HIST("h_jetpT"), analysisJet.pt(), weight); + registry.fill(HIST("h_Db"), analysisJet.scoreML(), weight); + registry.fill(HIST("h2_jetpT_Db"), analysisJet.pt(), analysisJet.scoreML(), weight); + registry.fill(HIST("h2_jetpT_SVMass"), analysisJet.pt(), mSV, weight); + registry.fill(HIST("h2_jetpT_jetMass"), analysisJet.pt(), analysisJet.mass(), weight); + registry.fill(HIST("h2_jetpT_jetProb"), analysisJet.pt(), analysisJet.jetProb(), weight); + registry.fill(HIST("h2_jetpT_nTracks"), analysisJet.pt(), nTracks, weight); + + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h_jetpT_b"), analysisJet.pt(), weight); + registry.fill(HIST("h_Db_b"), analysisJet.scoreML(), weight); + registry.fill(HIST("h2_jetpT_Db_b"), analysisJet.pt(), analysisJet.scoreML(), weight); + registry.fill(HIST("h2_jetpT_SVMass_b"), analysisJet.pt(), mSV, weight); + registry.fill(HIST("h2_jetpT_jetMass_b"), analysisJet.pt(), analysisJet.mass(), weight); + registry.fill(HIST("h2_jetpT_jetProb_b"), analysisJet.pt(), analysisJet.jetProb(), weight); + registry.fill(HIST("h2_jetpT_nTracks_b"), analysisJet.pt(), nTracks, weight); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h_jetpT_c"), analysisJet.pt(), weight); + registry.fill(HIST("h_Db_c"), analysisJet.scoreML(), weight); + registry.fill(HIST("h2_jetpT_Db_c"), analysisJet.pt(), analysisJet.scoreML(), weight); + registry.fill(HIST("h2_jetpT_SVMass_c"), analysisJet.pt(), mSV, weight); + registry.fill(HIST("h2_jetpT_jetMass_c"), analysisJet.pt(), analysisJet.mass(), weight); + registry.fill(HIST("h2_jetpT_jetProb_c"), analysisJet.pt(), analysisJet.jetProb(), weight); + registry.fill(HIST("h2_jetpT_nTracks_c"), analysisJet.pt(), nTracks, weight); + } else { + registry.fill(HIST("h_jetpT_lf"), analysisJet.pt(), weight); + registry.fill(HIST("h_Db_lf"), analysisJet.scoreML(), weight); + registry.fill(HIST("h2_jetpT_Db_lf"), analysisJet.pt(), analysisJet.scoreML(), weight); + registry.fill(HIST("h2_jetpT_SVMass_lf"), analysisJet.pt(), mSV, weight); + registry.fill(HIST("h2_jetpT_jetMass_lf"), analysisJet.pt(), analysisJet.mass(), weight); + registry.fill(HIST("h2_jetpT_jetProb_lf"), analysisJet.pt(), analysisJet.jetProb(), weight); + registry.fill(HIST("h2_jetpT_nTracks_lf"), analysisJet.pt(), nTracks, weight); + if (jetFlavor == JetTaggingSpecies::none) { + registry.fill(HIST("h2_jetpT_Db_lf_none"), analysisJet.pt(), analysisJet.scoreML(), weight); + } else { + registry.fill(HIST("h2_jetpT_Db_lf_matched"), analysisJet.pt(), analysisJet.scoreML(), weight); + } + } + + if (static_cast(nNppTracks) / nTracks > trackNppCrit) { + registry.fill(HIST("h_Db_npp"), analysisJet.scoreML(), weight); + registry.fill(HIST("h2_jetpT_Db_npp"), analysisJet.pt(), analysisJet.scoreML(), weight); + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h_Db_npp_b"), analysisJet.scoreML(), weight); + registry.fill(HIST("h2_jetpT_Db_npp_b"), analysisJet.pt(), analysisJet.scoreML(), weight); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h_Db_npp_c"), analysisJet.scoreML(), weight); + registry.fill(HIST("h2_jetpT_Db_npp_c"), analysisJet.pt(), analysisJet.scoreML(), weight); + } else { + registry.fill(HIST("h_Db_npp_lf"), analysisJet.scoreML(), weight); + registry.fill(HIST("h2_jetpT_Db_npp_lf"), analysisJet.pt(), analysisJet.scoreML(), weight); + } + } + + if (doDataDriven) { + registry.fill(HIST("hSparse_Incljets"), analysisJet.pt(), analysisJet.scoreML(), mSV, analysisJet.mass(), nTracks, weight); + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("hSparse_bjets"), analysisJet.pt(), analysisJet.scoreML(), mSV, analysisJet.mass(), nTracks, weight); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("hSparse_cjets"), analysisJet.pt(), analysisJet.scoreML(), mSV, analysisJet.mass(), nTracks, weight); + } else { + registry.fill(HIST("hSparse_lfjets"), analysisJet.pt(), analysisJet.scoreML(), mSV, analysisJet.mass(), nTracks, weight); + if (jetFlavor == JetTaggingSpecies::none) { + registry.fill(HIST("hSparse_lfjets_none"), analysisJet.pt(), analysisJet.scoreML(), mSV, analysisJet.mass(), nTracks, weight); + } else { + registry.fill(HIST("hSparse_lfjets_matched"), analysisJet.pt(), analysisJet.scoreML(), mSV, analysisJet.mass(), nTracks, weight); + } + } + } + + for (const auto& mcpjet : analysisJet.template matchedJetGeo_as()) { + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + continue; + } + + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT"), analysisJet.pt(), mcpjet.pt(), weight); + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_b"), analysisJet.pt(), mcpjet.pt(), weight); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_c"), analysisJet.pt(), mcpjet.pt(), weight); + } else { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_lf"), analysisJet.pt(), mcpjet.pt(), weight); + } + } + } + } + PROCESS_SWITCH(BjetTaggingGnn, processMCJets, "jet information in MC", false); + + Filter mccollisionFilter = nabs(aod::jmccollision::posZ) < vertexZCut; + using FilteredCollisionMCP = soa::Filtered; + + void processMCTruthJets(FilteredCollisionMCP::iterator const& /*collision*/, MCPJetTable const& MCPjets, aod::JetParticles const& /*MCParticles*/) + { + + for (const auto& mcpjet : MCPjets) { + + bool jetIncluded = false; + for (const auto& jetR : jetRadiiValues) { + if (mcpjet.r() == static_cast(jetR * 100)) { + jetIncluded = true; + break; + } + } + + if (!jetIncluded) { + continue; + } + + float weight = useEventWeight ? mcpjet.eventWeight() : 1.0; + float pTHat = 10. / (std::pow(mcpjet.eventWeight(), 1.0 / pTHatExponent)); + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + continue; + } + + int8_t jetFlavor = mcpjet.origin(); + + registry.fill(HIST("h_jetpT_particle"), mcpjet.pt(), weight); + + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h_jetpT_particle_b"), mcpjet.pt(), weight); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h_jetpT_particle_c"), mcpjet.pt(), weight); + } else { + registry.fill(HIST("h_jetpT_particle_lf"), mcpjet.pt(), weight); + } + } + } + PROCESS_SWITCH(BjetTaggingGnn, processMCTruthJets, "truth jet information", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGJE/Tasks/bjetTaggingML.cxx b/PWGJE/Tasks/bjetTaggingML.cxx new file mode 100644 index 00000000000..7b2638f37a5 --- /dev/null +++ b/PWGJE/Tasks/bjetTaggingML.cxx @@ -0,0 +1,497 @@ +// 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 bjetTaggingML.cxx +/// \brief Task for tagging the beauty jets using ML algorithm (in onnx format) loaded from ccdb +/// +/// \author Hadi Hassan , University of Jyväskylä + +#include +#include +#include + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoA.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetTaggingUtilities.h" +#include "PWGJE/DataModel/JetTagging.h" +#include "PWGJE/DataModel/Jet.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/RecoDecay.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct BJetTaggingML { + + HistogramRegistry registry; + + // event level configurables + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable useEventWeight{"useEventWeight", true, "Flag whether to scale histograms with the event weight"}; + + Configurable pTHatMaxMCD{"pTHatMaxMCD", 999.0, "maximum fraction of hard scattering for jet acceptance in detector MC"}; + Configurable pTHatMaxMCP{"pTHatMaxMCP", 999.0, "maximum fraction of hard scattering for jet acceptance in particle MC"}; + Configurable pTHatExponent{"pTHatExponent", 6.0, "exponent of the event weight for the calculation of pTHat"}; + + // track level configurables + Configurable trackPtMin{"trackPtMin", 0.5, "minimum track pT"}; + Configurable trackPtMax{"trackPtMax", 1000.0, "maximum track pT"}; + Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum track eta"}; + Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track eta"}; + + // track level configurables + Configurable svPtMin{"svPtMin", 0.5, "minimum SV pT"}; + + // jet level configurables + Configurable jetPtMin{"jetPtMin", 5.0, "minimum jet pT"}; + Configurable jetPtMax{"jetPtMax", 1000.0, "maximum jet pT"}; + Configurable jetEtaMin{"jetEtaMin", -99.0, "minimum jet pseudorapidity"}; + Configurable jetEtaMax{"jetEtaMax", 99.0, "maximum jet pseudorapidity"}; + Configurable nJetConst{"nJetConst", 10, "maximum number of jet consistuents to be used for ML evaluation"}; + + Configurable doDataDriven{"doDataDriven", false, "Flag whether to use fill THnSpase for data driven methods"}; + + Configurable> jetRadii{"jetRadii", std::vector{0.4}, "jet resolution parameters"}; + + std::vector eventSelectionBits; + + std::vector jetRadiiValues; + + void init(InitContext const&) + { + // Seed the random number generator using current time + std::srand(static_cast(std::time(nullptr))); + + jetRadiiValues = (std::vector)jetRadii; + + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + + registry.add("h_vertexZ", "Vertex Z;#it{Z} (cm)", {HistType::kTH1F, {{40, -20.0, 20.0}}}); + + registry.add("h2_score_jetpT", "ML scores for inclusive jets;#it{p}_{T,jet} (GeV/#it{c});Score", {HistType::kTH2F, {{200, 0., 200.}, {120, -0.1, 1.1}}}); + registry.add("h2_logscore_jetpT", "ML scores for inclusive jets;#it{p}_{T,jet} (GeV/#it{c});- log(1 - Score)", {HistType::kTH2F, {{200, 0., 200.}, {120, 0, 30}}}); + + registry.add("h2_nTracks_jetpT", "Number of tracks;#it{p}_{T,jet} (GeV/#it{c});nTracks", {HistType::kTH2F, {{200, 0., 200.}, {100, 0, 100.0}}}); + registry.add("h2_nSV_jetpT", "Number of secondary vertices;#it{p}_{T,jet} (GeV/#it{c});nSVs", {HistType::kTH2F, {{200, 0., 200.}, {250, 0, 250.0}}}); + + registry.add("h2_SIPs2D_jetpT", "2D IP significance;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_SIPs3D_jetpT", "3D IP significance;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_LxyS_jetpT", "Decay length in XY;#it{p}_{T,jet} (GeV/#it{c});S#it{L}_{xy}", {HistType::kTH2F, {{200, 0., 200.}, {100, 0., 100.0}}}); + registry.add("h2_Dispersion_jetpT", "SV dispersion;#it{p}_{T,jet} (GeV/#it{c});Dispersion", {HistType::kTH2F, {{200, 0., 200.}, {100, 0, 0.5}}}); + registry.add("h2_jetMass_jetpT", "Jet mass;#it{p}_{T,jet} (GeV/#it{c});#it{m}_{jet} (GeV/#it{c}^{2})", {HistType::kTH2F, {{200, 0., 200.}, {50, 0, 50.0}}}); + registry.add("h2_SVMass_jetpT", "Secondary vertex mass;#it{p}_{T,jet} (GeV/#it{c});#it{m}_{SV} (GeV/#it{c}^{2})", {HistType::kTH2F, {{200, 0., 200.}, {50, 0, 10}}}); + + if (doDataDriven) { + registry.add("hSparse_Incljets", "Inclusive jets Info;#it{p}_{T,jet} (GeV/#it{c});Score;-log(1-score);#it{m}_{jet} (GeV/#it{c}^{2});-log(JP);#it{m}_{SV} (GeV/#it{c}^{2});SVfE;", {HistType::kTHnSparseF, {{200, 0., 200.}, {120, -0.1, 1.1}, {120, 0, 30}, {50, 0, 50}, {375, 0, 30}, {50, 0, 10}, {50, 0, 1}}}); + if (doprocessMCJets) { + registry.add("hSparse_bjets", "Tagged b-jets Info;#it{p}_{T,jet} (GeV/#it{c});Score;-log(1-score);#it{m}_{jet} (GeV/#it{c}^{2});-log(JP);#it{m}_{SV} (GeV/#it{c}^{2});SVfE;", {HistType::kTHnSparseF, {{200, 0., 200.}, {120, -0.1, 1.1}, {120, 0, 30}, {50, 0, 50}, {375, 0, 30}, {50, 0, 10}, {50, 0, 1}}}); + registry.add("hSparse_cjets", "Tagged c-jets Info;#it{p}_{T,jet} (GeV/#it{c});Score;-log(1-score);#it{m}_{jet} (GeV/#it{c}^{2});-log(JP);#it{m}_{SV} (GeV/#it{c}^{2});SVfE;", {HistType::kTHnSparseF, {{200, 0., 200.}, {120, -0.1, 1.1}, {120, 0, 30}, {50, 0, 50}, {375, 0, 30}, {50, 0, 10}, {50, 0, 1}}}); + registry.add("hSparse_lfjets", "Tagged lf-jets Info;#it{p}_{T,jet} (GeV/#it{c});Score;-log(1-score);#it{m}_{jet} (GeV/#it{c}^{2});-log(JP);#it{m}_{SV} (GeV/#it{c}^{2});SVfE;", {HistType::kTHnSparseF, {{200, 0., 200.}, {120, -0.1, 1.1}, {120, 0, 30}, {50, 0, 50}, {375, 0, 30}, {50, 0, 10}, {50, 0, 1}}}); + } + } + + if (doprocessMCJets) { + + registry.add("h2_score_jetpT_bjet", "ML scores for b-jets;#it{p}_{T,jet} (GeV/#it{c});Score", {HistType::kTH2F, {{200, 0., 200.}, {120, -0.1, 1.1}}}); + registry.add("h2_logscore_jetpT_bjet", "ML scores for b-jets;#it{p}_{T,jet} (GeV/#it{c});- log(1 - Score)", {HistType::kTH2F, {{200, 0., 200.}, {120, 0, 30}}}); + registry.add("h2_SIPs2D_jetpT_bjet", "2D IP significance b-jets;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_SIPs3D_jetpT_bjet", "3D IP significance b-jets;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_LxyS_jetpT_bjet", "Decay length in XY b-jets;#it{p}_{T,jet} (GeV/#it{c});S#it{L}_{xy}", {HistType::kTH2F, {{200, 0., 200.}, {100, 0., 100.0}}}); + registry.add("h2_Dispersion_jetpT_bjet", "SV dispersion b-jets;#it{p}_{T,jet} (GeV/#it{c});Dispersion", {HistType::kTH2F, {{200, 0., 200.}, {100, 0, 0.5}}}); + registry.add("h2_jetMass_jetpT_bjet", "Jet mass b-jets;#it{p}_{T,jet} (GeV/#it{c});#it{m}_{jet} (GeV/#it{c}^{2})", {HistType::kTH2F, {{200, 0., 200.}, {50, 0, 50.0}}}); + registry.add("h2_SVMass_jetpT_bjet", "Secondary vertex mass b-jets;#it{p}_{T,jet} (GeV/#it{c});#it{m}_{SV} (GeV/#it{c}^{2})", {HistType::kTH2F, {{200, 0., 200.}, {50, 0, 10.0}}}); + + registry.add("h2_score_jetpT_cjet", "ML scores for c-jets;#it{p}_{T,jet} (GeV/#it{c});Score", {HistType::kTH2F, {{200, 0., 200.}, {120, -0.1, 1.1}}}); + registry.add("h2_logscore_jetpT_cjet", "ML scores for c-jets;#it{p}_{T,jet} (GeV/#it{c});- log(1 - Score)", {HistType::kTH2F, {{200, 0., 200.}, {120, 0, 30}}}); + registry.add("h2_SIPs2D_jetpT_cjet", "2D IP significance c-jets;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_SIPs3D_jetpT_cjet", "3D IP significance c-jets;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_LxyS_jetpT_cjet", "Decay length in XY c-jets;#it{p}_{T,jet} (GeV/#it{c});S#it{L}_{xy}", {HistType::kTH2F, {{200, 0., 200.}, {100, 0., 100.0}}}); + registry.add("h2_Dispersion_jetpT_cjet", "SV dispersion c-jets;#it{p}_{T,jet} (GeV/#it{c});Dispersion", {HistType::kTH2F, {{200, 0., 200.}, {100, 0, 0.5}}}); + registry.add("h2_jetMass_jetpT_cjet", "Jet mass c-jets;#it{p}_{T,jet} (GeV/#it{c});#it{m}_{jet} (GeV/#it{c}^{2})", {HistType::kTH2F, {{200, 0., 200.}, {50, 0, 50.0}}}); + registry.add("h2_SVMass_jetpT_cjet", "Secondary vertex mass c-jets;#it{p}_{T,jet} (GeV/#it{c});#it{m}_{SV} (GeV/#it{c}^{2})", {HistType::kTH2F, {{200, 0., 200.}, {50, 0, 10.0}}}); + + registry.add("h2_score_jetpT_lfjet", "ML scores for lf-jets;#it{p}_{T,jet} (GeV/#it{c});Score", {HistType::kTH2F, {{200, 0., 200.}, {120, -0.1, 1.1}}}); + registry.add("h2_logscore_jetpT_lfjet", "ML scores for lf-jets;#it{p}_{T,jet} (GeV/#it{c});- log(1 - Score)", {HistType::kTH2F, {{200, 0., 200.}, {120, 0, 30}}}); + registry.add("h2_SIPs2D_jetpT_lfjet", "2D IP significance lf-jet;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_SIPs3D_jetpT_lfjet", "3D IP significance lf-jet;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_LxyS_jetpT_lfjet", "Decay length in XY lf-jet;#it{p}_{T,jet} (GeV/#it{c});S#it{L}_{xy}", {HistType::kTH2F, {{200, 0., 200.}, {100, 0., 100.0}}}); + registry.add("h2_Dispersion_jetpT_lfjet", "SV dispersion lf-jet;#it{p}_{T,jet} (GeV/#it{c});Dispersion", {HistType::kTH2F, {{200, 0., 200.}, {100, 0, 0.5}}}); + registry.add("h2_jetMass_jetpT_lfjet", "Jet mass lf-jet;#it{p}_{T,jet} (GeV/#it{c});#it{m}_{jet} (GeV/#it{c}^{2})", {HistType::kTH2F, {{200, 0., 200.}, {50, 0, 50.0}}}); + registry.add("h2_SVMass_jetpT_lfjet", "Secondary vertex mass lf-jet;#it{p}_{T,jet} (GeV/#it{c});#it{m}_{SV} (GeV/#it{c}^{2})", {HistType::kTH2F, {{200, 0., 200.}, {50, 0, 10.0}}}); + + registry.add("h_jetpT_detector_bjet", "Jet transverse momentum b-jets;#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + registry.add("h_jetpT_detector_cjet", "Jet transverse momentum c-jets;#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + registry.add("h_jetpT_detector_lfjet", "Jet transverse momentum lf-jet;#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + + registry.add("h_jetpT_particle_DetColl", "Jet transverse momentum particle level inclusive jets (Detector-level collisions);#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + registry.add("h_jetpT_particle_DetColl_bjet", "Jet transverse momentum particle level b-jets (Detector-level collisions);#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + registry.add("h_jetpT_particle_DetColl_cjet", "Jet transverse momentum particle level c-jets (Detector-level collisions);#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + registry.add("h_jetpT_particle_DetColl_lfjet", "Jet transverse momentum particle level lf-jet (Detector-level collisions);#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + + registry.add("h_jetpT_particle_bjet", "Jet transverse momentum particle level b-jets;#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + registry.add("h_jetpT_particle_cjet", "Jet transverse momentum particle level c-jets;#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + registry.add("h_jetpT_particle_lfjet", "Jet transverse momentum particle level lf-jet;#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + + registry.add("h2_Response_DetjetpT_PartjetpT_bjet", "Response matrix b-jets;#it{p}_{T,jet}^{det} (GeV/#it{c});#it{p}_{T,jet}^{part} (GeV/#it{c})", {HistType::kTH2F, {{200, 0., 200.}, {200, 0., 200.}}}); + registry.add("h2_Response_DetjetpT_PartjetpT_cjet", "Response matrix c-jets;#it{p}_{T,jet}^{det} (GeV/#it{c});#it{p}_{T,jet}^{part} (GeV/#it{c})", {HistType::kTH2F, {{200, 0., 200.}, {200, 0., 200.}}}); + registry.add("h2_Response_DetjetpT_PartjetpT_lfjet", "Response matrix lf-jet;#it{p}_{T,jet}^{det} (GeV/#it{c});#it{p}_{T,jet}^{part} (GeV/#it{c})", {HistType::kTH2F, {{200, 0., 200.}, {200, 0., 200.}}}); + } + } + + // FIXME filtering only works when you loop directly over the list, but if you loop over it as a constituent they will not be filtered + Filter collisionFilter = nabs(aod::jcollision::posZ) < vertexZCut; + Filter trackCuts = (aod::jtrack::pt > trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); + Filter partCuts = (aod::jmcparticle::pt >= trackPtMin && aod::jmcparticle::pt < trackPtMax); + Filter jetFilter = (aod::jet::pt >= jetPtMin && aod::jet::pt <= jetPtMax && aod::jet::eta < jetEtaMax - aod::jet::r / 100.f && aod::jet::eta > jetEtaMin + aod::jet::r / 100.f); + + using FilteredCollision = soa::Filtered>; + using JetTrackswID = soa::Join; + using JetTracksMCDwID = soa::Join; + using DataJets = soa::Filtered>; + + // Looping over the SV info and writing them to a table + template + void analyzeJetSVInfo(AnalysisJet const& myJet, SecondaryVertices const& /*allSVs*/, std::vector& svsParams, int8_t jetFlavor = 0, double eventweight = 1.0) + { + using SVType = typename SecondaryVertices::iterator; + + // Min-heap to store the top 30 SVs by decayLengthXY/errorDecayLengthXY + auto compare = [](SVType& sv1, SVType& sv2) { + return (sv1.decayLengthXY() / sv1.errorDecayLengthXY()) > (sv2.decayLengthXY() / sv2.errorDecayLengthXY()); + }; + + auto svs = myJet.template secondaryVertices_as(); + + // Sort the SVs based on their decay length significance in descending order + // This is needed in order to select longest SVs since some jets could have thousands of SVs + std::sort(svs.begin(), svs.end(), compare); + + for (const auto& candSV : svs) { + + if (candSV.pt() < svPtMin) { + continue; + } + + double deltaRJetSV = jetutilities::deltaR(myJet, candSV); + double massSV = candSV.m(); + double energySV = candSV.e(); + + if (static_cast(svsParams.size()) < nJetConst) { + svsParams.emplace_back(jettaggingutilities::BJetSVParams{candSV.pt(), deltaRJetSV, massSV, energySV / myJet.energy(), candSV.impactParameterXY(), candSV.cpa(), candSV.chi2PCA(), candSV.dispersion(), candSV.decayLengthXY(), candSV.errorDecayLengthXY(), candSV.decayLength(), candSV.errorDecayLength()}); + } + + registry.fill(HIST("h2_LxyS_jetpT"), myJet.pt(), candSV.decayLengthXY() / candSV.errorDecayLengthXY(), eventweight); + registry.fill(HIST("h2_Dispersion_jetpT"), myJet.pt(), candSV.dispersion(), eventweight); + registry.fill(HIST("h2_SVMass_jetpT"), myJet.pt(), massSV, eventweight); + + if (doprocessMCJets) { + if (jetFlavor == 2) { + registry.fill(HIST("h2_LxyS_jetpT_bjet"), myJet.pt(), candSV.decayLengthXY() / candSV.errorDecayLengthXY(), eventweight); + registry.fill(HIST("h2_Dispersion_jetpT_bjet"), myJet.pt(), candSV.dispersion(), eventweight); + registry.fill(HIST("h2_SVMass_jetpT_bjet"), myJet.pt(), massSV, eventweight); + } else if (jetFlavor == 1) { + registry.fill(HIST("h2_LxyS_jetpT_cjet"), myJet.pt(), candSV.decayLengthXY() / candSV.errorDecayLengthXY(), eventweight); + registry.fill(HIST("h2_Dispersion_jetpT_cjet"), myJet.pt(), candSV.dispersion(), eventweight); + registry.fill(HIST("h2_SVMass_jetpT_cjet"), myJet.pt(), massSV, eventweight); + } else { + registry.fill(HIST("h2_LxyS_jetpT_lfjet"), myJet.pt(), candSV.decayLengthXY() / candSV.errorDecayLengthXY(), eventweight); + registry.fill(HIST("h2_Dispersion_jetpT_lfjet"), myJet.pt(), candSV.dispersion(), eventweight); + registry.fill(HIST("h2_SVMass_jetpT_lfjet"), myJet.pt(), massSV, eventweight); + } + } + } + svsParams.resize(nJetConst); + } + + template + void analyzeJetTrackInfo(AnalysisJet const& analysisJet, AnyTracks const& /*allTracks*/, std::vector& tracksParams, int8_t jetFlavor = 0, double eventweight = 1.0) + { + + for (const auto& constituent : analysisJet.template tracks_as()) { + + if (constituent.pt() < trackPtMin) { + continue; + } + + double deltaRJetTrack = jetutilities::deltaR(analysisJet, constituent); + double dotProduct = RecoDecay::dotProd(std::array{analysisJet.px(), analysisJet.py(), analysisJet.pz()}, std::array{constituent.px(), constituent.py(), constituent.pz()}); + int sign = jettaggingutilities::getGeoSign(analysisJet, constituent); + + float rClosestSV = -1.0; + + registry.fill(HIST("h2_SIPs2D_jetpT"), analysisJet.pt(), sign * std::abs(constituent.dcaXY()) / constituent.sigmadcaXY(), eventweight); + registry.fill(HIST("h2_SIPs3D_jetpT"), analysisJet.pt(), sign * std::abs(constituent.dcaXYZ()) / constituent.sigmadcaXYZ(), eventweight); + + if (doprocessMCJets) { + if (jetFlavor == 2) { + registry.fill(HIST("h2_SIPs2D_jetpT_bjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXY()) / constituent.sigmadcaXY(), eventweight); + registry.fill(HIST("h2_SIPs3D_jetpT_bjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXYZ()) / constituent.sigmadcaXYZ(), eventweight); + } else if (jetFlavor == 1) { + registry.fill(HIST("h2_SIPs2D_jetpT_cjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXY()) / constituent.sigmadcaXY(), eventweight); + registry.fill(HIST("h2_SIPs3D_jetpT_cjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXYZ()) / constituent.sigmadcaXYZ(), eventweight); + } else { + registry.fill(HIST("h2_SIPs2D_jetpT_lfjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXY()) / constituent.sigmadcaXY(), eventweight); + registry.fill(HIST("h2_SIPs3D_jetpT_lfjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXYZ()) / constituent.sigmadcaXYZ(), eventweight); + } + } + + tracksParams.emplace_back(jettaggingutilities::BJetTrackParams{constituent.pt(), constituent.eta(), dotProduct, dotProduct / analysisJet.p(), deltaRJetTrack, std::abs(constituent.dcaXY()) * sign, constituent.sigmadcaXY(), std::abs(constituent.dcaXYZ()) * sign, constituent.sigmadcaXYZ(), constituent.p() / analysisJet.p(), rClosestSV}); + } + + auto compare = [](jettaggingutilities::BJetTrackParams& tr1, jettaggingutilities::BJetTrackParams& tr2) { + return (tr1.signedIP2D / tr1.signedIP2DSign) > (tr2.signedIP2D / tr2.signedIP2DSign); + }; + + // Sort the tracks based on their IP significance in descending order + std::sort(tracksParams.begin(), tracksParams.end(), compare); + tracksParams.resize(nJetConst); + } + + void processDummy(FilteredCollision::iterator const& /*collision*/) + { + } + PROCESS_SWITCH(BJetTaggingML, processDummy, "Dummy process function turned on by default", true); + + void processDataJets(FilteredCollision::iterator const& collision, DataJets const& alljets, JetTrackswID const& allTracks, aod::DataSecondaryVertex3Prongs const& allSVs) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + + registry.fill(HIST("h_vertexZ"), collision.posZ()); + + for (const auto& analysisJet : alljets) { + + bool jetIncluded = false; + for (const auto& jetR : jetRadiiValues) { + if (analysisJet.r() == static_cast(jetR * 100)) { + jetIncluded = true; + break; + } + } + + if (!jetIncluded) { + continue; + } + + std::vector tracksParams; + std::vector svsParams; + + analyzeJetSVInfo(analysisJet, allSVs, svsParams); + analyzeJetTrackInfo(analysisJet, allTracks, tracksParams); + + int nSVs = analysisJet.template secondaryVertices_as().size(); + int nTracks = analysisJet.template tracks_as().size(); + + registry.fill(HIST("h2_nTracks_jetpT"), analysisJet.pt(), nTracks); + registry.fill(HIST("h2_nSV_jetpT"), analysisJet.pt(), nSVs < 250 ? nSVs : 249); + + registry.fill(HIST("h2_score_jetpT"), analysisJet.pt(), analysisJet.scoreML()); + registry.fill(HIST("h2_logscore_jetpT"), analysisJet.pt(), -1 * std::log(1 - analysisJet.scoreML())); + + registry.fill(HIST("h2_jetMass_jetpT"), analysisJet.pt(), analysisJet.mass()); + + if (doDataDriven) { + registry.fill(HIST("hSparse_Incljets"), analysisJet.pt(), analysisJet.scoreML(), -1 * std::log(1 - analysisJet.scoreML()), analysisJet.mass(), -1 * std::log(analysisJet.jetProb()), svsParams[0].svMass, svsParams[0].svfE); + } + } + } + PROCESS_SWITCH(BJetTaggingML, processDataJets, "jet information in Data", false); + + using MCDJetTable = soa::Filtered>; + using MCPJetTable = soa::Filtered>; + using FilteredCollisionMCD = soa::Filtered>; + + Preslice mcpJetsPerCollision = aod::jet::mcCollisionId; + + void processMCJets(FilteredCollisionMCD::iterator const& collision, MCDJetTable const& MCDjets, MCPJetTable const& MCPjets, JetTracksMCDwID const& allTracks, aod::JetParticles const& /*MCParticles*/, aod::MCDSecondaryVertex3Prongs const& allSVs) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + + registry.fill(HIST("h_vertexZ"), collision.posZ()); + + auto const mcPJetsPerColl = MCPjets.sliceBy(mcpJetsPerCollision, collision.mcCollisionId()); + + for (const auto& analysisJet : MCDjets) { + + bool jetIncluded = false; + for (const auto& jetR : jetRadiiValues) { + if (analysisJet.r() == static_cast(jetR * 100)) { + jetIncluded = true; + break; + } + } + + if (!jetIncluded) { + continue; + } + + float eventWeight = useEventWeight ? analysisJet.eventWeight() : 1.0; + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (analysisJet.pt() > pTHatMaxMCD * pTHat) { + continue; + } + + std::vector tracksParams; + std::vector svsParams; + + int jetFlavor = analysisJet.origin(); + + analyzeJetSVInfo(analysisJet, allSVs, svsParams, jetFlavor, eventWeight); + analyzeJetTrackInfo(analysisJet, allTracks, tracksParams, jetFlavor, eventWeight); + + int nSVs = analysisJet.template secondaryVertices_as().size(); + int nTracks = analysisJet.template tracks_as().size(); + + registry.fill(HIST("h2_nTracks_jetpT"), analysisJet.pt(), nTracks); + registry.fill(HIST("h2_nSV_jetpT"), analysisJet.pt(), nSVs < 250 ? nSVs : 249); + + registry.fill(HIST("h2_score_jetpT"), analysisJet.pt(), analysisJet.scoreML(), eventWeight); + registry.fill(HIST("h2_logscore_jetpT"), analysisJet.pt(), -1 * std::log(1 - analysisJet.scoreML()), eventWeight); + registry.fill(HIST("h2_jetMass_jetpT"), analysisJet.pt(), analysisJet.mass(), eventWeight); + + if (doDataDriven) { + registry.fill(HIST("hSparse_Incljets"), analysisJet.pt(), analysisJet.scoreML(), -1 * std::log(1 - analysisJet.scoreML()), analysisJet.mass(), -1 * std::log(analysisJet.jetProb()), svsParams[0].svMass, svsParams[0].svfE, eventWeight); + if (jetFlavor == 2) { + registry.fill(HIST("hSparse_bjets"), analysisJet.pt(), analysisJet.scoreML(), -1 * std::log(1 - analysisJet.scoreML()), analysisJet.mass(), -1 * std::log(analysisJet.jetProb()), svsParams[0].svMass, svsParams[0].svfE, eventWeight); + } else if (jetFlavor == 1) { + registry.fill(HIST("hSparse_cjets"), analysisJet.pt(), analysisJet.scoreML(), -1 * std::log(1 - analysisJet.scoreML()), analysisJet.mass(), -1 * std::log(analysisJet.jetProb()), svsParams[0].svMass, svsParams[0].svfE, eventWeight); + } else { + registry.fill(HIST("hSparse_lfjets"), analysisJet.pt(), analysisJet.scoreML(), -1 * std::log(1 - analysisJet.scoreML()), analysisJet.mass(), -1 * std::log(analysisJet.jetProb()), svsParams[0].svMass, svsParams[0].svfE, eventWeight); + } + } + + if (jetFlavor == 2) { + registry.fill(HIST("h2_score_jetpT_bjet"), analysisJet.pt(), analysisJet.scoreML(), eventWeight); + registry.fill(HIST("h2_logscore_jetpT_bjet"), analysisJet.pt(), -1 * std::log(1 - analysisJet.scoreML()), eventWeight); + registry.fill(HIST("h2_jetMass_jetpT_bjet"), analysisJet.pt(), analysisJet.mass(), eventWeight); + registry.fill(HIST("h_jetpT_detector_bjet"), analysisJet.pt(), eventWeight); + } else if (jetFlavor == 1) { + registry.fill(HIST("h2_score_jetpT_cjet"), analysisJet.pt(), analysisJet.scoreML(), eventWeight); + registry.fill(HIST("h2_logscore_jetpT_cjet"), analysisJet.pt(), -1 * std::log(1 - analysisJet.scoreML()), eventWeight); + registry.fill(HIST("h2_jetMass_jetpT_cjet"), analysisJet.pt(), analysisJet.mass(), eventWeight); + registry.fill(HIST("h_jetpT_detector_cjet"), analysisJet.pt(), eventWeight); + } else { + registry.fill(HIST("h2_score_jetpT_lfjet"), analysisJet.pt(), analysisJet.scoreML(), eventWeight); + registry.fill(HIST("h2_logscore_jetpT_lfjet"), analysisJet.pt(), -1 * std::log(1 - analysisJet.scoreML()), eventWeight); + registry.fill(HIST("h2_jetMass_jetpT_lfjet"), analysisJet.pt(), analysisJet.mass(), eventWeight); + registry.fill(HIST("h_jetpT_detector_lfjet"), analysisJet.pt(), eventWeight); + } + + for (const auto& mcpjet : analysisJet.template matchedJetGeo_as()) { + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + continue; + } + + if (jetFlavor == 2) { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_bjet"), analysisJet.pt(), mcpjet.pt(), eventWeight); + } else if (jetFlavor == 1) { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_cjet"), analysisJet.pt(), mcpjet.pt(), eventWeight); + } else { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_lfjet"), analysisJet.pt(), mcpjet.pt(), eventWeight); + } + } + } + + // For filling histograms used for the jet matching efficiency + for (const auto& mcpjet : mcPJetsPerColl) { + + bool jetIncluded = false; + for (const auto& jetR : jetRadiiValues) { + if (mcpjet.r() == static_cast(jetR * 100)) { + jetIncluded = true; + break; + } + } + + if (!jetIncluded) { + continue; + } + + float eventWeight = useEventWeight ? mcpjet.eventWeight() : 1.0; + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + continue; + } + + int8_t jetFlavor = mcpjet.origin(); + + registry.fill(HIST("h_jetpT_particle_DetColl"), mcpjet.pt(), eventWeight); + + if (jetFlavor == 2) { + registry.fill(HIST("h_jetpT_particle_DetColl_bjet"), mcpjet.pt(), eventWeight); + } else if (jetFlavor == 1) { + registry.fill(HIST("h_jetpT_particle_DetColl_cjet"), mcpjet.pt(), eventWeight); + } else { + registry.fill(HIST("h_jetpT_particle_DetColl_lfjet"), mcpjet.pt(), eventWeight); + } + } + } + PROCESS_SWITCH(BJetTaggingML, processMCJets, "jet information in MC", false); + + Filter mccollisionFilter = nabs(aod::jmccollision::posZ) < vertexZCut; + using FilteredCollisionMCP = soa::Filtered; + + void processMCTruthJets(FilteredCollisionMCP::iterator const& /*collision*/, MCPJetTable const& MCPjets, aod::JetParticles const& /*MCParticles*/) + { + + for (const auto& mcpjet : MCPjets) { + + bool jetIncluded = false; + for (const auto& jetR : jetRadiiValues) { + if (mcpjet.r() == static_cast(jetR * 100)) { + jetIncluded = true; + break; + } + } + + if (!jetIncluded) { + continue; + } + + float eventWeight = useEventWeight ? mcpjet.eventWeight() : 1.0; + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + continue; + } + + int8_t jetFlavor = mcpjet.origin(); + + if (jetFlavor == 2) { + registry.fill(HIST("h_jetpT_particle_bjet"), mcpjet.pt(), eventWeight); + } else if (jetFlavor == 1) { + registry.fill(HIST("h_jetpT_particle_cjet"), mcpjet.pt(), eventWeight); + } else { + registry.fill(HIST("h_jetpT_particle_lfjet"), mcpjet.pt(), eventWeight); + } + } + } + PROCESS_SWITCH(BJetTaggingML, processMCTruthJets, "truth jet information", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"bjet-tagging-ml"})}; // o2-linter: disable=name/o2-task,name/workflow-file +} diff --git a/PWGJE/Tasks/bjetTreeCreator.cxx b/PWGJE/Tasks/bjetTreeCreator.cxx new file mode 100644 index 00000000000..b99d6f41bd8 --- /dev/null +++ b/PWGJE/Tasks/bjetTreeCreator.cxx @@ -0,0 +1,828 @@ +// 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 bjetTreeCreator.cxx +/// \brief Task for building a TTree with information about the jet, its consistuents, and the secondary vertices inside +/// to be used for as input for machine learning b-jet identification. +/// +/// \author Hadi Hassan , University of Jyväskylä + +#include +#include +#include +#include + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoA.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetTaggingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetTagging.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/RecoDecay.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace o2::aod +{ +namespace jetInfo +{ +// DECLARE_SOA_INDEX_COLUMN(JetIndex, jetindex); //! The jet index +DECLARE_SOA_COLUMN(JetpT, jetpt, float); //! jet pT +DECLARE_SOA_COLUMN(JetEta, jeteta, float); //! jet eta +DECLARE_SOA_COLUMN(JetPhi, jetphi, float); //! jet phi +DECLARE_SOA_COLUMN(NTracks, nTracks, int16_t); //! number of charged tracks inside the jet +DECLARE_SOA_COLUMN(NSV, nSV, int16_t); //! Number of secondary vertices in the jet +DECLARE_SOA_COLUMN(JetMass, mass, float); //! The jet mass +DECLARE_SOA_COLUMN(JetFlavor, jetFl, int16_t); //! The jet flavor (b, c, or lf) +DECLARE_SOA_COLUMN(JetR, jetR, int16_t); //! The jet radius +} // namespace jetInfo + +DECLARE_SOA_TABLE(bjetParams, "AOD", "BJETPARAM", + o2::soa::Index<>, + jetInfo::JetpT, + jetInfo::JetEta, + jetInfo::JetPhi, + jetInfo::NTracks, + jetInfo::NSV, + jetInfo::JetMass, + jetInfo::JetFlavor, + jetInfo::JetR); + +using bjetParam = bjetParams::iterator; + +namespace trackInfo +{ +DECLARE_SOA_INDEX_COLUMN(bjetParam, jetindex); //! The jet index +DECLARE_SOA_COLUMN(TrackpT, trackpt, float); //! The track pT +DECLARE_SOA_COLUMN(TrackEta, tracketa, float); //! The track eta +DECLARE_SOA_COLUMN(DotProdTrackJet, trackdotjet, float); //! The dot product between the track and the jet +DECLARE_SOA_COLUMN(DotProdTrackJetOverJet, trackdotjetoverjet, float); //! The dot product between the track and the jet over the jet momentum +DECLARE_SOA_COLUMN(DeltaRJetTrack, rjettrack, float); //! The DR jet-track +DECLARE_SOA_COLUMN(SignedIP2D, ip2d, float); //! The track signed 2D IP +DECLARE_SOA_COLUMN(SignedIP2DSign, ip2dsigma, float); //! The track signed 2D IP significance +DECLARE_SOA_COLUMN(SignedIP3D, ip3d, float); //! The track signed 3D IP +DECLARE_SOA_COLUMN(SignedIP3DSign, ip3dsigma, float); //! The track signed 3D IP significance +DECLARE_SOA_COLUMN(MomFraction, momfraction, float); //! The track momentum fraction of the jets +DECLARE_SOA_COLUMN(DeltaRTrackVertex, rtrackvertex, float); //! DR between the track and the closest SV, to be decided whether to add to or not +DECLARE_SOA_COLUMN(TrackPhi, trackphi, float); //! The track phi +DECLARE_SOA_COLUMN(TrackCharge, trackcharge, float); //! The track sign (charge) +DECLARE_SOA_COLUMN(TrackITSChi2NCl, trackitschi2ncl, float); //! The track ITS Chi2NCl +DECLARE_SOA_COLUMN(TrackTPCChi2NCl, tracktpcchi2ncl, float); //! The track TPC Chi2NCl +DECLARE_SOA_COLUMN(TrackITSNCls, trackitsncls, float); //! The track ITS NCls +DECLARE_SOA_COLUMN(TrackTPCNCls, tracktpcncls, float); //! The track TPC NCls (Found) +DECLARE_SOA_COLUMN(TrackTPCNCrossedRows, tracktpcncrossedrows, float); //! The track TPC NCrossedRows +DECLARE_SOA_COLUMN(TrackOrigin, trk_origin, int); //! The track origin label for GNN track origin predictions +DECLARE_SOA_COLUMN(TrackVtxIndex, trk_vtx_index, int); //! The track vertex index for GNN vertex predictions +// DECLARE_SOA_COLUMN(DCATrackJet, dcatrackjet, float); //! The distance between track and jet, unfortunately it cannot be calculated in O2 +} // namespace trackInfo + +DECLARE_SOA_TABLE(bjetTracksParams, "AOD", "BJETTRACKSPARAM", + o2::soa::Index<>, + trackInfo::bjetParamId, + trackInfo::TrackpT, + trackInfo::TrackEta, + trackInfo::DotProdTrackJet, + trackInfo::DotProdTrackJetOverJet, + trackInfo::DeltaRJetTrack, + trackInfo::SignedIP2D, + trackInfo::SignedIP2DSign, + trackInfo::SignedIP3D, + trackInfo::SignedIP3DSign, + trackInfo::MomFraction, + trackInfo::DeltaRTrackVertex); + +using bjetTracksParam = bjetTracksParams::iterator; + +DECLARE_SOA_TABLE(bjetTracksParamsExtra, "AOD", "BJETTRACKSEXTRA", + // o2::soa::Index<>, + trackInfo::TrackPhi, + trackInfo::TrackCharge, + trackInfo::TrackITSChi2NCl, + trackInfo::TrackTPCChi2NCl, + trackInfo::TrackITSNCls, + trackInfo::TrackTPCNCls, + trackInfo::TrackTPCNCrossedRows, + trackInfo::TrackOrigin, + trackInfo::TrackVtxIndex); + +using bjetTracksParamExtra = bjetTracksParamsExtra::iterator; + +namespace SVInfo +{ +DECLARE_SOA_INDEX_COLUMN(bjetParam, jetindex); //! The jet index +DECLARE_SOA_COLUMN(SVpT, svpt, float); //! The SV pT +DECLARE_SOA_COLUMN(DeltaRSVJet, rsvjet, float); //! The DR jet-SV +DECLARE_SOA_COLUMN(SVMass, mass, float); //! The SV mass +DECLARE_SOA_COLUMN(SVfE, svfe, float); //! The SV energy fraction +DECLARE_SOA_COLUMN(IPXY, ipxy, float); //! The SV 2D IP +DECLARE_SOA_COLUMN(CPA, cpa, float); //! Cosine pointing angle between the SV direction and momentum +DECLARE_SOA_COLUMN(Chi2PCA, chi2pca, float); //! Sum of (non-weighted) distances of the secondary vertex to its prongsm +DECLARE_SOA_COLUMN(Dispersion, dispersion, float); //! The SV dispersion +DECLARE_SOA_COLUMN(DecayLength2D, lxy, float); //! The decay length of the SV in XY +DECLARE_SOA_COLUMN(DecayLength2DError, lxysigma, float); //! The decay length of the SV in XY significance +DECLARE_SOA_COLUMN(DecayLength3D, lxyz, float); //! The decay length of the SV in 3D +DECLARE_SOA_COLUMN(DecayLength3DError, lxyzsigma, float); //! The decay length of the SV in 3d significance +} // namespace SVInfo + +DECLARE_SOA_TABLE(bjetSVParams, "AOD", "BJETSVPARAM", + o2::soa::Index<>, + SVInfo::bjetParamId, + SVInfo::SVpT, + SVInfo::DeltaRSVJet, + SVInfo::SVMass, + SVInfo::SVfE, + SVInfo::IPXY, + SVInfo::CPA, + SVInfo::Chi2PCA, + SVInfo::Dispersion, + SVInfo::DecayLength2D, + SVInfo::DecayLength2DError, + SVInfo::DecayLength3D, + SVInfo::DecayLength3DError); + +using bjetSVParam = bjetSVParams::iterator; + +namespace constituents +{ +DECLARE_SOA_INDEX_COLUMN(bjetParam, jetindex); +DECLARE_SOA_ARRAY_INDEX_COLUMN(bjetTracksParam, tracks); +DECLARE_SOA_ARRAY_INDEX_COLUMN(bjetSVParam, svs); +} // namespace constituents + +DECLARE_SOA_TABLE(bjetConstituents, "AOD", "BJETCONSTIT", + constituents::bjetParamId, + constituents::bjetTracksParamIds, + constituents::bjetSVParamIds); + +} // namespace o2::aod + +struct BJetTreeCreator { + + Produces bjetParamsTable; + Produces bjetTracksParamsTable; + Produces bjetTracksExtraTable; + Produces bjetSVParamsTable; + Produces bjetConstituentsTable; + + HistogramRegistry registry; + + // event level configurables + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + + Configurable> jetPtBins{"jetPtBins", std::vector{5, 1000}, "jet pT bins for reduction"}; + Configurable> jetReductionFactors{"jetReductionFactors", std::vector{0.0}, "jet reduction factors"}; + + Configurable pTHatMaxMCD{"pTHatMaxMCD", 999.0, "maximum fraction of hard scattering for jet acceptance in detector MC"}; + Configurable pTHatMaxMCP{"pTHatMaxMCP", 999.0, "maximum fraction of hard scattering for jet acceptance in particle MC"}; + Configurable pTHatExponent{"pTHatExponent", 6.0, "exponent of the event weight for the calculation of pTHat"}; + + // track level configurables + Configurable trackPtMin{"trackPtMin", 0.5, "minimum track pT"}; + Configurable trackPtMax{"trackPtMax", 1000.0, "maximum track pT"}; + Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum track eta"}; + Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track eta"}; + + Configurable useQuarkDef{"useQuarkDef", true, "Flag whether to use quarks or hadrons for determining the jet flavor"}; + + // track level configurables + Configurable svPtMin{"svPtMin", 0.5, "minimum SV pT"}; + + // jet level configurables + Configurable jetPtMin{"jetPtMin", 5.0, "minimum jet pT"}; + Configurable jetPtMax{"jetPtMax", 1000.0, "maximum jet pT"}; + Configurable jetEtaMin{"jetEtaMin", -99.0, "minimum jet pseudorapidity"}; + Configurable jetEtaMax{"jetEtaMax", 99.0, "maximum jet pseudorapidity"}; + + Configurable maxConstSV{"maxConstSV", 999.0, "maximum number of SVs to be stored in the table"}; + + Configurable svReductionFactor{"svReductionFactor", 1.0, "factor for how many SVs to keep"}; + Configurable eventReductionFactor{"eventReductionFactor", 0.0, "Percentage of events to be removed"}; + + Configurable> jetRadii{"jetRadii", std::vector{0.4}, "jet resolution parameters"}; + + Configurable produceTree{"produceTree", true, "produce the jet TTree"}; + + Configurable vtxRes{"vtxRes", 0.01, "Vertex position resolution (cluster size) for GNN vertex predictions (cm)"}; + + std::vector eventSelectionBits; + + std::vector jetRadiiValues; + std::vector jetPtBinsReduction; + std::vector jetReductionFactorsPt; + + void init(InitContext const&) + { + // Seed the random number generator using current time + std::srand(static_cast(std::time(nullptr))); + + jetRadiiValues = (std::vector)jetRadii; + jetPtBinsReduction = (std::vector)jetPtBins; + jetReductionFactorsPt = (std::vector)jetReductionFactors; + + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + + registry.add("h_vertexZ", "Vertex Z;#it{Z} (cm)", {HistType::kTH1F, {{40, -20.0, 20.0}}}); + + registry.add("h2_nTracks_jetpT", "Number of tracks;#it{p}_{T,jet} (GeV/#it{c});nTracks", {HistType::kTH2F, {{200, 0., 200.}, {100, 0, 100.0}}}); + registry.add("h2_nSV_jetpT", "Number of secondary vertices;#it{p}_{T,jet} (GeV/#it{c});nSVs", {HistType::kTH2F, {{200, 0., 200.}, {250, 0, 250.0}}}); + + registry.add("h2_SIPs2D_jetpT", "2D IP significance;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_SIPs3D_jetpT", "3D IP significance;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_LxyS_jetpT", "Decay length in XY;#it{p}_{T,jet} (GeV/#it{c});S#it{L}_{xy}", {HistType::kTH2F, {{200, 0., 200.}, {100, 0., 100.0}}}); + registry.add("h2_Dispersion_jetpT", "SV dispersion;#it{p}_{T,jet} (GeV/#it{c});Dispersion", {HistType::kTH2F, {{200, 0., 200.}, {100, 0, 0.5}}}); + registry.add("h2_jetMass_jetpT", "Jet mass;#it{p}_{T,jet} (GeV/#it{c});#it{m}_{jet} (GeV/#it{c}^{2})", {HistType::kTH2F, {{200, 0., 200.}, {50, 0, 50.0}}}); + registry.add("h2_SVMass_jetpT", "Secondary vertex mass;#it{p}_{T,jet} (GeV/#it{c});#it{m}_{SV} (GeV/#it{c}^{2})", {HistType::kTH2F, {{200, 0., 200.}, {50, 0, 10}}}); + + if (doprocessMCJets || doprocessMCJetsForGNN) { + registry.add("h2_SIPs2D_jetpT_bjet", "2D IP significance b-jets;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_SIPs3D_jetpT_bjet", "3D IP significance b-jets;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_LxyS_jetpT_bjet", "Decay length in XY b-jets;#it{p}_{T,jet} (GeV/#it{c});S#it{L}_{xy}", {HistType::kTH2F, {{200, 0., 200.}, {100, 0., 100.0}}}); + registry.add("h2_Dispersion_jetpT_bjet", "SV dispersion b-jets;#it{p}_{T,jet} (GeV/#it{c});Dispersion", {HistType::kTH2F, {{200, 0., 200.}, {100, 0, 0.5}}}); + registry.add("h2_jetMass_jetpT_bjet", "Jet mass b-jets;#it{p}_{T,jet} (GeV/#it{c});#it{m}_{jet} (GeV/#it{c}^{2})", {HistType::kTH2F, {{200, 0., 200.}, {50, 0, 50.0}}}); + registry.add("h2_SVMass_jetpT_bjet", "Secondary vertex mass b-jets;#it{p}_{T,jet} (GeV/#it{c});#it{m}_{SV} (GeV/#it{c}^{2})", {HistType::kTH2F, {{200, 0., 200.}, {50, 0, 10.0}}}); + + registry.add("h2_SIPs2D_jetpT_cjet", "2D IP significance c-jets;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_SIPs3D_jetpT_cjet", "3D IP significance c-jets;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_LxyS_jetpT_cjet", "Decay length in XY c-jets;#it{p}_{T,jet} (GeV/#it{c});S#it{L}_{xy}", {HistType::kTH2F, {{200, 0., 200.}, {100, 0., 100.0}}}); + registry.add("h2_Dispersion_jetpT_cjet", "SV dispersion c-jets;#it{p}_{T,jet} (GeV/#it{c});Dispersion", {HistType::kTH2F, {{200, 0., 200.}, {100, 0, 0.5}}}); + registry.add("h2_jetMass_jetpT_cjet", "Jet mass c-jets;#it{p}_{T,jet} (GeV/#it{c});#it{m}_{jet} (GeV/#it{c}^{2})", {HistType::kTH2F, {{200, 0., 200.}, {50, 0, 50.0}}}); + registry.add("h2_SVMass_jetpT_cjet", "Secondary vertex mass c-jets;#it{p}_{T,jet} (GeV/#it{c});#it{m}_{SV} (GeV/#it{c}^{2})", {HistType::kTH2F, {{200, 0., 200.}, {50, 0, 10.0}}}); + + registry.add("h2_SIPs2D_jetpT_lfjet", "2D IP significance lf-jet;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_SIPs3D_jetpT_lfjet", "3D IP significance lf-jet;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_LxyS_jetpT_lfjet", "Decay length in XY lf-jet;#it{p}_{T,jet} (GeV/#it{c});S#it{L}_{xy}", {HistType::kTH2F, {{200, 0., 200.}, {100, 0., 100.0}}}); + registry.add("h2_Dispersion_jetpT_lfjet", "SV dispersion lf-jet;#it{p}_{T,jet} (GeV/#it{c});Dispersion", {HistType::kTH2F, {{200, 0., 200.}, {100, 0, 0.5}}}); + registry.add("h2_jetMass_jetpT_lfjet", "Jet mass lf-jet;#it{p}_{T,jet} (GeV/#it{c});#it{m}_{jet} (GeV/#it{c}^{2})", {HistType::kTH2F, {{200, 0., 200.}, {50, 0, 50.0}}}); + registry.add("h2_SVMass_jetpT_lfjet", "Secondary vertex mass lf-jet;#it{p}_{T,jet} (GeV/#it{c});#it{m}_{SV} (GeV/#it{c}^{2})", {HistType::kTH2F, {{200, 0., 200.}, {50, 0, 10.0}}}); + + registry.add("h_jetpT_detector_bjet", "Jet transverse momentum b-jets;#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + registry.add("h_jetpT_detector_cjet", "Jet transverse momentum c-jets;#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + registry.add("h_jetpT_detector_lfjet", "Jet transverse momentum lf-jet;#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + + registry.add("h_jetpT_particle_bjet", "Jet transverse momentum particle level b-jets;#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + registry.add("h_jetpT_particle_cjet", "Jet transverse momentum particle level c-jets;#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + registry.add("h_jetpT_particle_lfjet", "Jet transverse momentum particle level lf-jet;#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + + registry.add("h2_Response_DetjetpT_PartjetpT_bjet", "Response matrix b-jets;#it{p}_{T,jet}^{det} (GeV/#it{c});#it{p}_{T,jet}^{part} (GeV/#it{c})", {HistType::kTH2F, {{200, 0., 200.}, {200, 0., 200.}}}); + registry.add("h2_Response_DetjetpT_PartjetpT_cjet", "Response matrix c-jets;#it{p}_{T,jet}^{det} (GeV/#it{c});#it{p}_{T,jet}^{part} (GeV/#it{c})", {HistType::kTH2F, {{200, 0., 200.}, {200, 0., 200.}}}); + registry.add("h2_Response_DetjetpT_PartjetpT_lfjet", "Response matrix lf-jet;#it{p}_{T,jet}^{det} (GeV/#it{c});#it{p}_{T,jet}^{part} (GeV/#it{c})", {HistType::kTH2F, {{200, 0., 200.}, {200, 0., 200.}}}); + } + + if (doprocessMCJetsForGNN) { + //+jet + registry.add("h_jet_pt", "jet_pt;#it{p}_{T}^{ch jet} (GeV/#it{c});Entries", {HistType::kTH1F, {{200, 0., 200.}}}); + registry.add("h_jet_eta", "jet_eta;#it{#eta}_{ch jet};Entries", {HistType::kTH1F, {{200, -2., 2.}}}); + registry.add("h_jet_phi", "jet_phi;#it{#phi}_{ch jet};Entries", {HistType::kTH1F, {{200, 0., 2. * M_PI}}}); + registry.add("h_jet_flav", "jet_flav;jet flavor;Entries", {HistType::kTH1F, {{4, 0., 4.}}}); + registry.add("h_n_trks", "n_trks;#it{n}_{tracks};Entries", {HistType::kTH1F, {{50, 0., 50.}}}); + registry.add("h_jet_mass", "jet_mass;#it{m}_{jet} (GeV/#it{c}^2);Entries", {HistType::kTH1F, {{200, 0., 50.}}}); + auto h_jet_flav = registry.get(HIST("h_jet_flav")); + h_jet_flav->GetXaxis()->SetBinLabel(1, "no mcparticle"); // 0 + h_jet_flav->GetXaxis()->SetBinLabel(2, "c-jet"); // 1 + h_jet_flav->GetXaxis()->SetBinLabel(3, "b-jet"); // 2 + h_jet_flav->GetXaxis()->SetBinLabel(4, "lf-jet"); // 3 + registry.add("h_n_vertices", "n_vertices;#it{n}_{vertex};Entries", {HistType::kTH1F, {{50, 0., 50.}}}); + //+trk + registry.add("h_trk_pt", "trk_pt;#it{p}_{T} (GeV/#it{c});Entries", {HistType::kTH1F, {{200, 0., 100.}}}); + registry.add("h_trk_eta", "trk_eta;#it{#eta};Entries", {HistType::kTH1F, {{200, -2., 2.}}}); + registry.add("h_trk_phi", "trk_phi;#it{#phi};Entries", {HistType::kTH1F, {{200, 0., 2. * M_PI}}}); + registry.add("h_trk_charge", "trk_charge;#it{q};Entries", {HistType::kTH1F, {{3, -1.5, 1.5}}}); + registry.add("h_trk_dcaxy", "trk_dcaxy;#it{DCA}_{xy} (cm);Entries", {HistType::kTH1F, {{200, -0.1, 0.1}}}); + registry.add("h_trk_dcaxyz", "trk_dcaxyz;#it{DCA}_{xyz} (cm);Entries", {HistType::kTH1F, {{200, -0.1, 0.1}}}); + registry.add("h_trk_sigmadcaxy", "trk_sigmadcaxy;#it{#sigma}_{#it{DCA}_{xy}} (cm);Entries", {HistType::kTH1F, {{200, 0., 0.1}}}); + registry.add("h_trk_sigmadcaxyz", "trk_sigmadcaxyz;#it{#sigma}_{#it{DCA}_{xyz}} (cm);Entries", {HistType::kTH1F, {{200, 0., 0.1}}}); + registry.add("h_trk_itsncls", "trk_itsncls;ITS NCls;Entries", {HistType::kTH1F, {{10, 0., 10.}}}); + registry.add("h_trk_tpcncls", "trk_tpcncls;TPC NCls (Found);Entries", {HistType::kTH1F, {{200, 0., 200.}}}); + registry.add("h_trk_tpcncrs", "trk_tpcncrs;TPC NCrossedRows;Entries", {HistType::kTH1F, {{200, 0., 200.}}}); + registry.add("h_trk_itschi2ncl", "trk_itschi2ncl;ITS #it{#chi}^{2}/ndf;Entries", {HistType::kTH1F, {{200, 0., 20.}}}); + registry.add("h_trk_tpcchi2ncl", "trk_tpcchi2ncl;TPC #it{#chi}^{2}/ndf;Entries", {HistType::kTH1F, {{200, 0., 10.}}}); + registry.add("h2_trk_jtrackpt_vs_origtrackpt", "JTracks::pt vs Tracks::pt", {HistType::kTH2F, {{200, 0., 100.}, {200, 0., 100.}}}); + registry.add("h_trk_vtx_index", "trk_vtx_index;Vertex index;Entries", {HistType::kTH1F, {{20, 0., 20.}}}); + registry.add("h_trk_origin", "trk_origin;Track origin;Entries", {HistType::kTH1F, {{5, 0., 5.}}}); + auto h_trk_origin = registry.get(HIST("h_trk_origin")); + h_trk_origin->GetXaxis()->SetBinLabel(1, "NotPhysPrim"); + h_trk_origin->GetXaxis()->SetBinLabel(2, "Charm"); + h_trk_origin->GetXaxis()->SetBinLabel(3, "Beauty"); + h_trk_origin->GetXaxis()->SetBinLabel(4, "Primary"); + h_trk_origin->GetXaxis()->SetBinLabel(5, "OtherSecondary"); + } + } + + // FIXME filtering only works when you loop directly over the list, but if you loop over it as a constituent they will not be filtered + Filter collisionFilter = nabs(aod::jcollision::posZ) < vertexZCut; + Filter trackCuts = (aod::jtrack::pt > trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); + Filter partCuts = (aod::jmcparticle::pt >= trackPtMin && aod::jmcparticle::pt < trackPtMax); + Filter jetFilter = (aod::jet::pt >= jetPtMin && aod::jet::pt <= jetPtMax && aod::jet::eta < jetEtaMax - aod::jet::r / 100.f && aod::jet::eta > jetEtaMin + aod::jet::r / 100.f); + + using FilteredCollision = soa::Filtered>; + using JetTrackswID = soa::Filtered>; + using JetTracksMCDwID = soa::Filtered>; + using DataJets = soa::Filtered>; + + using OriginalTracks = soa::Join; + + // Function to get the reduction factor based on jet pT + double getReductionFactor(double jetPT) + { + // Loop through the jetPtBins vector + for (size_t ibin = 0; ibin < jetPtBinsReduction.size() - 1; ++ibin) { + if (jetPT >= jetPtBinsReduction[ibin] && jetPT < jetPtBinsReduction[ibin + 1]) { + return jetReductionFactorsPt[ibin]; + } + } + + // If jetPT is above the last bin, use the last reduction factor + if (jetPT >= jetPtBinsReduction.back()) { + return jetReductionFactorsPt.back(); + } + + // If jetPT is below the first bin, return the first reduction factor + return jetReductionFactorsPt.front(); + } + + // Looping over the SV info and writing them to a table + template + void analyzeJetSVInfo(AnalysisJet const& myJet, AnyTracks const& /*allTracks*/, SecondaryVertices const& /*allSVs*/, std::vector& svIndices, int jetFlavor = 0, double eventweight = 1.0) + { + using SVType = typename SecondaryVertices::iterator; + + // Min-heap to store the top 30 SVs by decayLengthXY/errorDecayLengthXY + auto compare = [](SVType& sv1, SVType& sv2) { + return (sv1.decayLengthXY() / sv1.errorDecayLengthXY()) > (sv2.decayLengthXY() / sv2.errorDecayLengthXY()); + }; + + auto svs = myJet.template secondaryVertices_as(); + + // Sort the SVs based on their decay length significance in descending order + // This is needed in order to select longest SVs since some jets could have thousands of SVs + std::sort(svs.begin(), svs.end(), compare); + + for (const auto& candSV : svs) { + + if (candSV.pt() < svPtMin) { + continue; + } + + double deltaRJetSV = jetutilities::deltaR(myJet, candSV); + double massSV = candSV.m(); + double energySV = candSV.e(); + + if (svIndices.size() < (svReductionFactor * myJet.template tracks_as().size()) && svIndices.size() < maxConstSV) { + if (produceTree) { + bjetSVParamsTable(bjetParamsTable.lastIndex() + 1, candSV.pt(), deltaRJetSV, massSV, energySV / myJet.energy(), candSV.impactParameterXY(), candSV.cpa(), candSV.chi2PCA(), candSV.dispersion(), candSV.decayLengthXY(), candSV.errorDecayLengthXY(), candSV.decayLength(), candSV.errorDecayLength()); + } + svIndices.push_back(bjetSVParamsTable.lastIndex()); + } + + registry.fill(HIST("h2_LxyS_jetpT"), myJet.pt(), candSV.decayLengthXY() / candSV.errorDecayLengthXY(), eventweight); + registry.fill(HIST("h2_Dispersion_jetpT"), myJet.pt(), candSV.chi2PCA(), eventweight); + registry.fill(HIST("h2_SVMass_jetpT"), myJet.pt(), massSV, eventweight); + + if (doprocessMCJets) { + if (jetFlavor == 2) { + registry.fill(HIST("h2_LxyS_jetpT_bjet"), myJet.pt(), candSV.decayLengthXY() / candSV.errorDecayLengthXY(), eventweight); + registry.fill(HIST("h2_Dispersion_jetpT_bjet"), myJet.pt(), candSV.chi2PCA(), eventweight); + registry.fill(HIST("h2_SVMass_jetpT_bjet"), myJet.pt(), massSV, eventweight); + } else if (jetFlavor == 1) { + registry.fill(HIST("h2_LxyS_jetpT_cjet"), myJet.pt(), candSV.decayLengthXY() / candSV.errorDecayLengthXY(), eventweight); + registry.fill(HIST("h2_Dispersion_jetpT_cjet"), myJet.pt(), candSV.chi2PCA(), eventweight); + registry.fill(HIST("h2_SVMass_jetpT_cjet"), myJet.pt(), massSV, eventweight); + } else { + registry.fill(HIST("h2_LxyS_jetpT_lfjet"), myJet.pt(), candSV.decayLengthXY() / candSV.errorDecayLengthXY(), eventweight); + registry.fill(HIST("h2_Dispersion_jetpT_lfjet"), myJet.pt(), candSV.chi2PCA(), eventweight); + registry.fill(HIST("h2_SVMass_jetpT_lfjet"), myJet.pt(), massSV, eventweight); + } + } + } + } + + using TrackLabelMap = std::unordered_map>; + + template + void analyzeJetTrackInfo(AnyCollision const& /*collision*/, AnalysisJet const& analysisJet, AnyTracks const& /*allTracks*/, SecondaryVertices const& /*allSVs*/, std::vector& trackIndices, int jetFlavor = 0, double eventweight = 1.0) + { + + for (auto& constituent : analysisJet.template tracks_as()) { + + if (constituent.pt() < trackPtMin) { + continue; + } + + double deltaRJetTrack = jetutilities::deltaR(analysisJet, constituent); + double dotProduct = RecoDecay::dotProd(std::array{analysisJet.px(), analysisJet.py(), analysisJet.pz()}, std::array{constituent.px(), constituent.py(), constituent.pz()}); + int sign = jettaggingutilities::getGeoSign(analysisJet, constituent); + + float RClosestSV = 10.; + for (const auto& candSV : analysisJet.template secondaryVertices_as()) { + double deltaRTrackSV = jetutilities::deltaR(constituent, candSV); + if (deltaRTrackSV < RClosestSV) { + RClosestSV = deltaRTrackSV; + } + } + + registry.fill(HIST("h2_SIPs2D_jetpT"), analysisJet.pt(), sign * std::abs(constituent.dcaXY()) / constituent.sigmadcaXY(), eventweight); + registry.fill(HIST("h2_SIPs3D_jetpT"), analysisJet.pt(), sign * std::abs(constituent.dcaXYZ()) / constituent.sigmadcaXYZ(), eventweight); + + if (doprocessMCJets) { + if (jetFlavor == 2) { + registry.fill(HIST("h2_SIPs2D_jetpT_bjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXY()) / constituent.sigmadcaXY(), eventweight); + registry.fill(HIST("h2_SIPs3D_jetpT_bjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXYZ()) / constituent.sigmadcaXYZ(), eventweight); + } else if (jetFlavor == 1) { + registry.fill(HIST("h2_SIPs2D_jetpT_cjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXY()) / constituent.sigmadcaXY(), eventweight); + registry.fill(HIST("h2_SIPs3D_jetpT_cjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXYZ()) / constituent.sigmadcaXYZ(), eventweight); + } else { + registry.fill(HIST("h2_SIPs2D_jetpT_lfjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXY()) / constituent.sigmadcaXY(), eventweight); + registry.fill(HIST("h2_SIPs3D_jetpT_lfjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXYZ()) / constituent.sigmadcaXYZ(), eventweight); + } + } + + if (produceTree) { + bjetTracksParamsTable(bjetParamsTable.lastIndex() + 1, constituent.pt(), constituent.eta(), dotProduct, dotProduct / analysisJet.p(), deltaRJetTrack, std::abs(constituent.dcaXY()) * sign, constituent.sigmadcaXY(), std::abs(constituent.dcaXYZ()) * sign, constituent.sigmadcaXYZ(), constituent.p() / analysisJet.p(), RClosestSV); + } + trackIndices.push_back(bjetTracksParamsTable.lastIndex()); + } + } + + template + void analyzeJetTrackInfoForGNN(AnyCollision const& /*collision*/, AnalysisJet const& analysisJet, AnyTracks const& /*allTracks*/, AnyOriginalTracks const&, std::vector& trackIndices, int jetFlavor = 0, double eventweight = 1.0, TrackLabelMap* trkLabels = nullptr) + { + int trkIdx = -1; + for (auto& constituent : analysisJet.template tracks_as()) { + + trkIdx++; + + if (constituent.pt() < trackPtMin) { + continue; + } + + double deltaRJetTrack = jetutilities::deltaR(analysisJet, constituent); + double dotProduct = RecoDecay::dotProd(std::array{analysisJet.px(), analysisJet.py(), analysisJet.pz()}, std::array{constituent.px(), constituent.py(), constituent.pz()}); + int sign = jettaggingutilities::getGeoSign(analysisJet, constituent); + + registry.fill(HIST("h2_SIPs2D_jetpT"), analysisJet.pt(), sign * std::abs(constituent.dcaXY()) / constituent.sigmadcaXY(), eventweight); + registry.fill(HIST("h2_SIPs3D_jetpT"), analysisJet.pt(), sign * std::abs(constituent.dcaXYZ()) / constituent.sigmadcaXYZ(), eventweight); + + if (doprocessMCJetsForGNN) { + if (jetFlavor == 2) { + registry.fill(HIST("h2_SIPs2D_jetpT_bjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXY()) / constituent.sigmadcaXY(), eventweight); + registry.fill(HIST("h2_SIPs3D_jetpT_bjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXYZ()) / constituent.sigmadcaXYZ(), eventweight); + } else if (jetFlavor == 1) { + registry.fill(HIST("h2_SIPs2D_jetpT_cjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXY()) / constituent.sigmadcaXY(), eventweight); + registry.fill(HIST("h2_SIPs3D_jetpT_cjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXYZ()) / constituent.sigmadcaXYZ(), eventweight); + } else { + registry.fill(HIST("h2_SIPs2D_jetpT_lfjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXY()) / constituent.sigmadcaXY(), eventweight); + registry.fill(HIST("h2_SIPs3D_jetpT_lfjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXYZ()) / constituent.sigmadcaXYZ(), eventweight); + } + + auto origConstit = constituent.template track_as(); + + //+ + int trkVtxIndex = 0; + int trkOrigin = 0; + if (trkLabels != nullptr) { + trkVtxIndex = (*trkLabels)["trkVtxIndex"][trkIdx]; + trkOrigin = (*trkLabels)["trkOrigin"][trkIdx]; + } + + //+trk + registry.fill(HIST("h_trk_pt"), constituent.pt(), eventweight); + registry.fill(HIST("h_trk_eta"), constituent.eta(), eventweight); + registry.fill(HIST("h_trk_phi"), origConstit.phi(), eventweight); + registry.fill(HIST("h_trk_charge"), constituent.sign(), eventweight); + registry.fill(HIST("h_trk_dcaxy"), std::abs(constituent.dcaXY()) * sign, eventweight); + registry.fill(HIST("h_trk_dcaxyz"), std::abs(constituent.dcaXYZ()) * sign, eventweight); + registry.fill(HIST("h_trk_sigmadcaxy"), constituent.sigmadcaXY(), eventweight); + registry.fill(HIST("h_trk_sigmadcaxyz"), constituent.sigmadcaXYZ(), eventweight); + registry.fill(HIST("h_trk_itsncls"), origConstit.itsNCls(), eventweight); + registry.fill(HIST("h_trk_tpcncls"), origConstit.tpcNClsFound(), eventweight); + registry.fill(HIST("h_trk_tpcncrs"), origConstit.tpcNClsCrossedRows(), eventweight); + registry.fill(HIST("h_trk_itschi2ncl"), origConstit.itsChi2NCl(), eventweight); + registry.fill(HIST("h_trk_tpcchi2ncl"), origConstit.tpcChi2NCl(), eventweight); + registry.fill(HIST("h2_trk_jtrackpt_vs_origtrackpt"), constituent.pt(), origConstit.pt(), eventweight); // jtrack & new extra table are well joined (linear correlation) + registry.fill(HIST("h_trk_vtx_index"), trkVtxIndex); + registry.fill(HIST("h_trk_origin"), trkOrigin); + + if (produceTree) { + bjetTracksExtraTable(/*bjetParamsTable.lastIndex() + 1, */ origConstit.phi(), constituent.sign(), origConstit.itsChi2NCl(), origConstit.tpcChi2NCl(), origConstit.itsNCls(), origConstit.tpcNClsFound(), origConstit.tpcNClsCrossedRows(), trkOrigin, trkVtxIndex); //+ + } + } + + if (produceTree) { + bjetTracksParamsTable(bjetParamsTable.lastIndex() + 1, constituent.pt(), constituent.eta(), dotProduct, dotProduct / analysisJet.p(), deltaRJetTrack, std::abs(constituent.dcaXY()) * sign, constituent.sigmadcaXY(), std::abs(constituent.dcaXYZ()) * sign, constituent.sigmadcaXYZ(), constituent.p() / analysisJet.p(), 0.); + } + trackIndices.push_back(bjetTracksParamsTable.lastIndex()); + } + } + + void processDummy(FilteredCollision::iterator const& /*collision*/) + { + } + PROCESS_SWITCH(BJetTreeCreator, processDummy, "Dummy process function turned on by default", true); + + void processDataJets(FilteredCollision::iterator const& collision, DataJets const& alljets, JetTrackswID const& allTracks, aod::DataSecondaryVertex3Prongs const& allSVs) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || (static_cast(std::rand()) / RAND_MAX < eventReductionFactor)) { + return; + } + + registry.fill(HIST("h_vertexZ"), collision.posZ()); + + for (const auto& analysisJet : alljets) { + + bool jetIncluded = false; + for (auto jetR : jetRadiiValues) { + if (analysisJet.r() == static_cast(jetR * 100)) { + jetIncluded = true; + break; + } + } + + if (!jetIncluded) { + continue; + } + + if (static_cast(std::rand()) / RAND_MAX < getReductionFactor(analysisJet.pt())) { + continue; + } + + std::vector tracksIndices; + std::vector SVsIndices; + + analyzeJetSVInfo(analysisJet, allTracks, allSVs, SVsIndices); + analyzeJetTrackInfo(collision, analysisJet, allTracks, allSVs, tracksIndices); + + registry.fill(HIST("h2_jetMass_jetpT"), analysisJet.pt(), analysisJet.mass()); + + int nSVs = analysisJet.template secondaryVertices_as().size(); + + registry.fill(HIST("h2_nTracks_jetpT"), analysisJet.pt(), tracksIndices.size()); + registry.fill(HIST("h2_nSV_jetpT"), analysisJet.pt(), nSVs < 250 ? nSVs : 249); + + if (produceTree) { + bjetConstituentsTable(bjetParamsTable.lastIndex() + 1, tracksIndices, SVsIndices); + bjetParamsTable(analysisJet.pt(), analysisJet.eta(), analysisJet.phi(), tracksIndices.size(), nSVs, analysisJet.mass(), 0, analysisJet.r()); + } + } + } + PROCESS_SWITCH(BJetTreeCreator, processDataJets, "jet information in Data", false); + + using MCDJetTable = soa::Filtered>; + using MCPJetTable = soa::Filtered>; + using FilteredCollisionMCD = soa::Filtered>; + + Preslice McParticlesPerCollision = aod::jmcparticle::mcCollisionId; + Preslice McPJetsPerCollision = aod::jet::mcCollisionId; + + void processMCJets(FilteredCollisionMCD::iterator const& collision, MCDJetTable const& MCDjets, MCPJetTable const& MCPjets, JetTracksMCDwID const& allTracks, aod::JetParticles const& MCParticles, aod::MCDSecondaryVertex3Prongs const& allSVs) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || (static_cast(std::rand()) / RAND_MAX < eventReductionFactor)) { + return; + } + + registry.fill(HIST("h_vertexZ"), collision.posZ()); + + auto const mcParticlesPerColl = MCParticles.sliceBy(McParticlesPerCollision, collision.mcCollisionId()); + auto const mcPJetsPerColl = MCPjets.sliceBy(McPJetsPerCollision, collision.mcCollisionId()); + + for (const auto& analysisJet : MCDjets) { + + bool jetIncluded = false; + for (auto jetR : jetRadiiValues) { + if (analysisJet.r() == static_cast(jetR * 100)) { + jetIncluded = true; + break; + } + } + + if (!jetIncluded) { + continue; + } + + float eventWeight = analysisJet.eventWeight(); + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (analysisJet.pt() > pTHatMaxMCD * pTHat) { + continue; + } + + std::vector tracksIndices; + std::vector SVsIndices; + + int16_t jetFlavor = 0; + + // JetTracksMCDwID::iterator hftrack; + // jetFlavor = jettaggingutilities::mcdJetFromHFShower(analysisJet, allTracks, mcParticlesPerColl, (float)(analysisJet.r() / 100.)); + // jetFlavor = jettaggingutilities::jetTrackFromHFShower(analysisJet, nonFilteredTracks, mcParticlesPerColl, hftrack); + + for (auto& mcpjet : analysisJet.template matchedJetGeo_as()) { + if (useQuarkDef) { + jetFlavor = jettaggingutilities::getJetFlavor(mcpjet, mcParticlesPerColl); + } else { + jetFlavor = jettaggingutilities::getJetFlavorHadron(mcpjet, mcParticlesPerColl); + // jetFlavor = jettaggingutilities::mcpJetFromHFShower(mcpjet, mcParticlesPerColl, (float)(mcpjet.r() / 100.)); + } + } + + if ((jetFlavor != JetTaggingSpecies::charm && jetFlavor != JetTaggingSpecies::beauty) && (static_cast(std::rand()) / RAND_MAX < getReductionFactor(analysisJet.pt()))) { + continue; + } + + analyzeJetSVInfo(analysisJet, allTracks, allSVs, SVsIndices, jetFlavor, eventWeight); + analyzeJetTrackInfo(collision, analysisJet, allTracks, allSVs, tracksIndices, jetFlavor, eventWeight); + + int nSVs = analysisJet.template secondaryVertices_as().size(); + + registry.fill(HIST("h2_jetMass_jetpT"), analysisJet.pt(), analysisJet.mass(), eventWeight); + + registry.fill(HIST("h2_nTracks_jetpT"), analysisJet.pt(), tracksIndices.size()); + registry.fill(HIST("h2_nSV_jetpT"), analysisJet.pt(), nSVs < 250 ? nSVs : 249); + + if (jetFlavor == 2) { + registry.fill(HIST("h2_jetMass_jetpT_bjet"), analysisJet.pt(), analysisJet.mass(), eventWeight); + registry.fill(HIST("h_jetpT_detector_bjet"), analysisJet.pt(), eventWeight); + } else if (jetFlavor == 1) { + registry.fill(HIST("h2_jetMass_jetpT_cjet"), analysisJet.pt(), analysisJet.mass(), eventWeight); + registry.fill(HIST("h_jetpT_detector_cjet"), analysisJet.pt(), eventWeight); + } else { + registry.fill(HIST("h2_jetMass_jetpT_lfjet"), analysisJet.pt(), analysisJet.mass(), eventWeight); + registry.fill(HIST("h_jetpT_detector_lfjet"), analysisJet.pt(), eventWeight); + } + + for (auto& mcpjet : analysisJet.template matchedJetGeo_as()) { + + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + continue; + } + + if (jetFlavor == 2) { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_bjet"), analysisJet.pt(), mcpjet.pt(), eventWeight); + } else if (jetFlavor == 1) { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_cjet"), analysisJet.pt(), mcpjet.pt(), eventWeight); + } else { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_lfjet"), analysisJet.pt(), mcpjet.pt(), eventWeight); + } + } + + if (produceTree) { + bjetConstituentsTable(bjetParamsTable.lastIndex() + 1, tracksIndices, SVsIndices); + bjetParamsTable(analysisJet.pt(), analysisJet.eta(), analysisJet.phi(), tracksIndices.size(), nSVs, analysisJet.mass(), jetFlavor, analysisJet.r()); + } + } + } + PROCESS_SWITCH(BJetTreeCreator, processMCJets, "jet information in MC", false); + + using MCDJetTableNoSV = soa::Filtered>; + using JetParticleswID = soa::Join; + + void processMCJetsForGNN(FilteredCollisionMCD::iterator const& collision, aod::JMcCollisions const&, MCDJetTableNoSV const& MCDjets, MCPJetTable const& MCPjets, JetTracksMCDwID const& allTracks, JetParticleswID const& MCParticles, OriginalTracks const& origTracks, aod::McParticles const& origParticles) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || (static_cast(std::rand()) / RAND_MAX < eventReductionFactor)) { + return; + } + + registry.fill(HIST("h_vertexZ"), collision.posZ()); + + auto const mcParticlesPerColl = MCParticles.sliceBy(McParticlesPerCollision, collision.mcCollisionId()); + auto const mcPJetsPerColl = MCPjets.sliceBy(McPJetsPerCollision, collision.mcCollisionId()); + + for (const auto& analysisJet : MCDjets) { + + bool jetIncluded = false; + for (auto jetR : jetRadiiValues) { + if (analysisJet.r() == static_cast(jetR * 100)) { + jetIncluded = true; + break; + } + } + + if (!jetIncluded) { + continue; + } + + std::vector tracksIndices; + std::vector SVsIndices; + + int16_t jetFlavor = 0; + + for (auto& mcpjet : analysisJet.template matchedJetGeo_as()) { + if (useQuarkDef) { + jetFlavor = jettaggingutilities::getJetFlavor(mcpjet, mcParticlesPerColl); + } else { + jetFlavor = jettaggingutilities::getJetFlavorHadron(mcpjet, mcParticlesPerColl); + } + } + + if ((jetFlavor != JetTaggingSpecies::charm && jetFlavor != JetTaggingSpecies::beauty) && (static_cast(std::rand()) / RAND_MAX < getReductionFactor(analysisJet.pt()))) { + continue; + } + + float eventWeight = analysisJet.eventWeight(); + + //+ + TrackLabelMap trkLabels{{"trkVtxIndex", {}}, {"trkOrigin", {}}}; + int nVertices = jettaggingutilities::vertexClustering(collision.template mcCollision_as(), analysisJet, allTracks, MCParticles, origParticles, trkLabels, true, vtxRes, trackPtMin); + analyzeJetTrackInfoForGNN(collision, analysisJet, allTracks, origTracks, tracksIndices, jetFlavor, eventWeight, &trkLabels); + + registry.fill(HIST("h2_jetMass_jetpT"), analysisJet.pt(), analysisJet.mass(), eventWeight); + registry.fill(HIST("h2_nTracks_jetpT"), analysisJet.pt(), tracksIndices.size()); + + //+jet + registry.fill(HIST("h_jet_pt"), analysisJet.pt()); + registry.fill(HIST("h_jet_eta"), analysisJet.eta()); + registry.fill(HIST("h_jet_phi"), analysisJet.phi()); + registry.fill(HIST("h_jet_flav"), jetFlavor); + registry.fill(HIST("h_n_trks"), tracksIndices.size()); + registry.fill(HIST("h_jet_mass"), analysisJet.mass()); + registry.fill(HIST("h_n_vertices"), nVertices); + + if (jetFlavor == 2) { + registry.fill(HIST("h2_jetMass_jetpT_bjet"), analysisJet.pt(), analysisJet.mass(), eventWeight); + registry.fill(HIST("h_jetpT_detector_bjet"), analysisJet.pt(), eventWeight); + } else if (jetFlavor == 1) { + registry.fill(HIST("h2_jetMass_jetpT_cjet"), analysisJet.pt(), analysisJet.mass(), eventWeight); + registry.fill(HIST("h_jetpT_detector_cjet"), analysisJet.pt(), eventWeight); + } else { + registry.fill(HIST("h2_jetMass_jetpT_lfjet"), analysisJet.pt(), analysisJet.mass(), eventWeight); + registry.fill(HIST("h_jetpT_detector_lfjet"), analysisJet.pt(), eventWeight); + } + + if (produceTree) { + bjetConstituentsTable(bjetParamsTable.lastIndex() + 1, tracksIndices, SVsIndices); + bjetParamsTable(analysisJet.pt(), analysisJet.eta(), analysisJet.phi(), tracksIndices.size(), nVertices, analysisJet.mass(), jetFlavor, analysisJet.r()); + } + } + } + PROCESS_SWITCH(BJetTreeCreator, processMCJetsForGNN, "jet information in MC for GNN", false); + + Filter mccollisionFilter = nabs(aod::jmccollision::posZ) < vertexZCut; + using FilteredCollisionMCP = soa::Filtered; + + void processMCTruthJets(FilteredCollisionMCP::iterator const& /*collision*/, MCPJetTable const& MCPjets, aod::JetParticles const& MCParticles) + { + + for (const auto& mcpjet : MCPjets) { + + bool jetIncluded = false; + for (auto jetR : jetRadiiValues) { + if (mcpjet.r() == static_cast(jetR * 100)) { + jetIncluded = true; + break; + } + } + + if (!jetIncluded) { + continue; + } + + float eventWeight = mcpjet.eventWeight(); + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + continue; + } + + int16_t jetFlavor = 0; + if (useQuarkDef) { + jetFlavor = jettaggingutilities::getJetFlavor(mcpjet, MCParticles); + } else { + jetFlavor = jettaggingutilities::getJetFlavorHadron(mcpjet, MCParticles); + // jetFlavor = jettaggingutilities::mcpJetFromHFShower(mcpjet, MCParticles, (float)(mcpjet.r() / 100.)); + } + + if (jetFlavor == 2) { + registry.fill(HIST("h_jetpT_particle_bjet"), mcpjet.pt(), eventWeight); + } else if (jetFlavor == 1) { + registry.fill(HIST("h_jetpT_particle_cjet"), mcpjet.pt(), eventWeight); + } else { + registry.fill(HIST("h_jetpT_particle_lfjet"), mcpjet.pt(), eventWeight); + } + } + } + PROCESS_SWITCH(BJetTreeCreator, processMCTruthJets, "truth jet information", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"bjet-tree-creator"})}; +} diff --git a/PWGJE/Tasks/dijetFinderQA.cxx b/PWGJE/Tasks/dijetFinderQA.cxx new file mode 100644 index 00000000000..4dd9292a1ac --- /dev/null +++ b/PWGJE/Tasks/dijetFinderQA.cxx @@ -0,0 +1,332 @@ +// 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. + +// dijet finder QA task +// +/// \author Dongguk Kim + +#include +#include +#include +#include + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" + +#include "PWGJE/Core/JetDerivedDataUtilities.h" + +#include "EventFiltering/filterTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct DijetFinderQATask { + + HistogramRegistry registry; + + Configurable centralityMin{"centralityMin", -999.0, "minimum centrality"}; + Configurable centralityMax{"centralityMax", 999.0, "maximum centrality"}; + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + Configurable trackPtMin{"trackPtMin", 0.15, "minimum pT acceptance for tracks"}; + Configurable trackPtMax{"trackPtMax", 1000.0, "maximum pT acceptance for tracks"}; + Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum eta acceptance for tracks"}; + Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum eta acceptance for tracks"}; + Configurable leadingConstituentPtMin{"leadingConstituentPtMin", -99.0, "minimum pT selection on jet constituent"}; + Configurable leadingConstituentPtMax{"leadingConstituentPtMax", 9999.0, "maximum pT selection on jet constituent"}; + Configurable setJetPtCut{"setJetPtCut", 20., "set jet pt minimum cut"}; + Configurable setPhiCut{"setPhiCut", 0.5, "set phicut"}; + Configurable jetR{"jetR", 0.4, "jet resolution parameter"}; + Configurable jetPtMin{"jetPtMin", 20.0, "minimum jet pT cut"}; + Configurable jetPtMax{"jetPtMax", 200., "set jet pT bin max"}; + Configurable jetEtaMin{"jetEtaMin", -0.5, "minimum jet pseudorapidity"}; + Configurable jetEtaMax{"jetEtaMax", 0.5, "maximum jet pseudorapidity"}; + Configurable jetAreaFractionMin{"jetAreaFractionMin", -99.0, "used to make a cut on the jet areas"}; + + std::vector eventSelection; + int trackSelection = -1; + + std::vector dijetMassBins; + + void init(o2::framework::InitContext&) + { + eventSelection = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + + auto dijetMassTemp = 0.0; + while (dijetMassTemp <= 2 * jetPtMax) { + dijetMassBins.push_back(dijetMassTemp); + dijetMassTemp += 5.0; + } + + AxisSpec dijetMassAxis = {dijetMassBins, "M_{jj} (GeV/#it{c}^2)"}; + + if (doprocessDijetMCP) { + registry.add("h_part_dijet_mass", "Dijet invariant mass;;entries", {HistType::kTH1F, {dijetMassAxis}}); + } + + if (doprocessDijetMCD) { + registry.add("h_detec_dijet_mass", "Dijet invariant mass;;entries", {HistType::kTH1F, {dijetMassAxis}}); + } + + if (doprocessDijetData) { + registry.add("h_data_dijet_mass", "Dijet invariant mass;;entries", {HistType::kTH1F, {dijetMassAxis}}); + } + + if (doprocessDijetMCMatched) { + registry.add("h_matched_dijet_mass", "M_{jj matched};M_{jj part}; M_{jj det}", {HistType::kTH2F, {dijetMassAxis, dijetMassAxis}}); + } + } + + /****************************************************************************************************************************************************************/ + Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); + Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax); + Filter mcCollisionsFilter = nabs(aod::jmccollision::posZ) < vertexZCut; + Filter jetCuts = aod::jet::pt > jetPtMin&& aod::jet::r == nround(jetR.node() * 100.0f); + /****************************************************************************************************************************************************************/ + + template + bool isAcceptedJet(U const& jet) + { + + if (jetAreaFractionMin > -98.0) { + if (jet.area() < jetAreaFractionMin * M_PI * (jet.r() / 100.0) * (jet.r() / 100.0)) { + return false; + } + } + bool checkConstituentPt = true; + bool checkConstituentMinPt = (leadingConstituentPtMin > -98.0); + bool checkConstituentMaxPt = (leadingConstituentPtMax < 9998.0); + if (!checkConstituentMinPt && !checkConstituentMaxPt) { + checkConstituentPt = false; + } + + if (checkConstituentPt) { + bool isMinLeadingConstituent = !checkConstituentMinPt; + bool isMaxLeadingConstituent = true; + + for (const auto& constituent : jet.template tracks_as()) { + double pt = constituent.pt(); + + if (checkConstituentMinPt && pt >= leadingConstituentPtMin) { + isMinLeadingConstituent = true; + } + if (checkConstituentMaxPt && pt > leadingConstituentPtMax) { + isMaxLeadingConstituent = false; + } + } + return isMinLeadingConstituent && isMaxLeadingConstituent; + } + + return true; + } + + template + void fillMassHistogramsMCP(T const& mass) + { + registry.fill(HIST("h_part_dijet_mass"), mass); + } + + template + void fillMassHistogramsMCD(T const& mass) + { + registry.fill(HIST("h_detec_dijet_mass"), mass); + } + + template + void fillMassHistogramsData(T const& mass) + { + registry.fill(HIST("h_data_dijet_mass"), mass); + } + + template + void fillMassHistogramsMCMatched(T const& mass_P, T const& mass_D) + { + registry.fill(HIST("h_matched_dijet_mass"), mass_P, mass_D); + } + + void processDummy(aod::JDummys const&) + { + } + PROCESS_SWITCH(DijetFinderQATask, processDummy, "dummy", false); + + void processDijetMCP(soa::Filtered::iterator const&, soa::Filtered const& jets) + { + std::vector> jetPtcuts; + for (auto& jet : jets) { + jetPtcuts.push_back({jet.pt(), jet.eta(), jet.phi()}); + } + + if (jetPtcuts.size() >= 2) { + auto& leading_jet = jetPtcuts[0]; + bool found_pair = false; + + for (size_t i = 1; i < jetPtcuts.size() && !found_pair; i++) { + auto& candidate_jet = jetPtcuts[i]; + Double_t dphi = fabs(leading_jet[2] - candidate_jet[2]); + Double_t deta = fabs(leading_jet[1] - candidate_jet[1]); + Double_t condition = fabs(dphi - M_PI); + + if (condition < setPhiCut * M_PI) { + Double_t pt1 = leading_jet[0]; + Double_t pt2 = candidate_jet[0]; + Double_t dijet_mass = sqrt(2 * pt1 * pt2 * (cosh(deta) - cos(dphi))); + fillMassHistogramsMCP(dijet_mass); + found_pair = true; + } + } + } + } + PROCESS_SWITCH(DijetFinderQATask, processDijetMCP, "QA for invariant mass of dijet in particle level MC", false); + + void processDijetMCD(soa::Filtered::iterator const& collision, soa::Filtered const& jets) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + return; + } + std::vector> jetPtcuts; + for (auto& jet : jets) { + jetPtcuts.push_back({jet.pt(), jet.eta(), jet.phi()}); + } + + if (jetPtcuts.size() >= 2) { + auto& leading_jet = jetPtcuts[0]; + bool found_pair = false; + + for (size_t i = 1; i < jetPtcuts.size() && !found_pair; i++) { + auto& candidate_jet = jetPtcuts[i]; + Double_t dphi = fabs(leading_jet[2] - candidate_jet[2]); + Double_t deta = fabs(leading_jet[1] - candidate_jet[1]); + Double_t condition = fabs(dphi - M_PI); + + if (condition < setPhiCut * M_PI) { + Double_t pt1 = leading_jet[0]; + Double_t pt2 = candidate_jet[0]; + Double_t dijet_mass = sqrt(2 * pt1 * pt2 * (cosh(deta) - cos(dphi))); + fillMassHistogramsMCD(dijet_mass); + found_pair = true; + } + } + } + } + PROCESS_SWITCH(DijetFinderQATask, processDijetMCD, "QA for invariant mass of dijet in detector level MC", false); + + void processDijetData(soa::Filtered::iterator const& collision, soa::Filtered const& jets) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + return; + } + + std::vector> jetPtcuts; + for (auto& jet : jets) { + jetPtcuts.push_back({jet.pt(), jet.eta(), jet.phi()}); + } + + if (jetPtcuts.size() >= 2) { + auto& leading_jet = jetPtcuts[0]; + bool found_pair = false; + + for (size_t i = 1; i < jetPtcuts.size() && !found_pair; i++) { + auto& candidate_jet = jetPtcuts[i]; + Double_t dphi = fabs(leading_jet[2] - candidate_jet[2]); + Double_t deta = fabs(leading_jet[1] - candidate_jet[1]); + Double_t condition = fabs(dphi - M_PI); + + if (condition < setPhiCut * M_PI) { + Double_t pt1 = leading_jet[0]; + Double_t pt2 = candidate_jet[0]; + Double_t dijet_mass = sqrt(2 * pt1 * pt2 * (cosh(deta) - cos(dphi))); + fillMassHistogramsData(dijet_mass); + found_pair = true; + } + } + } + } + PROCESS_SWITCH(DijetFinderQATask, processDijetData, "QA for invariant mass of dijet in data", false); + + using JetMCPTable = soa::Filtered>; + void processDijetMCMatched(soa::Filtered::iterator const& collision, + soa::Filtered> const& mcdjets, + JetMCPTable const&, aod::JetTracks const&, aod::JetParticles const&) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + return; + } + + std::vector> jetPtcuts_D; + std::vector> jetPtcuts_P; + + for (auto& jet : mcdjets) { + if (jet.has_matchedJetGeo()) { + for (auto& matchedJet : jet.template matchedJetPt_as()) { + if (matchedJet.pt() > setJetPtCut) { + jetPtcuts_D.push_back({jet.pt(), jet.eta(), jet.phi()}); + jetPtcuts_P.push_back({matchedJet.pt(), matchedJet.eta(), matchedJet.phi()}); + break; + } + } + } + } + + if (jetPtcuts_D.size() >= 2 && jetPtcuts_P.size() >= 2) { + auto& leading_jet_D = jetPtcuts_D[0]; + auto& leading_jet_P = jetPtcuts_P[0]; + bool found_pair = false; + + for (size_t i = 1; i < jetPtcuts_D.size() && !found_pair; i++) { + auto& candidate_jet_D = jetPtcuts_D[i]; + auto& candidate_jet_P = jetPtcuts_P[i]; + + Double_t dphi_D = fabs(leading_jet_D[2] - candidate_jet_D[2]); + Double_t deta_D = fabs(leading_jet_D[1] - candidate_jet_D[1]); + Double_t dphi_P = fabs(leading_jet_P[2] - candidate_jet_P[2]); + Double_t deta_P = fabs(leading_jet_P[1] - candidate_jet_P[1]); + Double_t condition = fabs(dphi_D - M_PI); + + if (condition < setPhiCut * M_PI) { + double pt1_D = leading_jet_D[0]; + double pt2_D = candidate_jet_D[0]; + double dijet_mass_D = sqrt(2 * pt1_D * pt2_D * (cosh(deta_D) - cos(dphi_D))); + + double pt1_P = leading_jet_P[0]; + double pt2_P = candidate_jet_P[0]; + double dijet_mass_P = sqrt(2 * pt1_P * pt2_P * (cosh(deta_P) - cos(dphi_P))); + + fillMassHistogramsMCMatched(dijet_mass_P, dijet_mass_D); + found_pair = true; + } + } + } + } + PROCESS_SWITCH(DijetFinderQATask, processDijetMCMatched, "QA for invariant mass of dijet in mcmactched", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"dijet-finder-charged-qa"})}; +} diff --git a/PWGJE/Tasks/emccellmonitor.cxx b/PWGJE/Tasks/emcCellMonitor.cxx similarity index 100% rename from PWGJE/Tasks/emccellmonitor.cxx rename to PWGJE/Tasks/emcCellMonitor.cxx diff --git a/PWGJE/Tasks/emcclustermonitor.cxx b/PWGJE/Tasks/emcClusterMonitor.cxx similarity index 76% rename from PWGJE/Tasks/emcclustermonitor.cxx rename to PWGJE/Tasks/emcClusterMonitor.cxx index b922e4cf068..9db525fe409 100644 --- a/PWGJE/Tasks/emcclustermonitor.cxx +++ b/PWGJE/Tasks/emcClusterMonitor.cxx @@ -16,6 +16,7 @@ #include #include #include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -75,6 +76,7 @@ struct ClusterMonitor { std::vector mVetoBCIDs; std::vector mSelectBCIDs; + std::vector mCellTime; /// \brief Create output histograms and initialize geometry void init(InitContext const&) @@ -94,6 +96,8 @@ struct ClusterMonitor { const o2Axis supermoduleAxis{20, -0.5, 19.5, "Supermodule ID"}; o2Axis timeAxis{mClusterTimeBinning, "t_{cl} (ns)"}; o2Axis numberClustersAxis{mNumberClusterBinning, "Number of clusters / event"}; + const AxisSpec thAxisCellTimeDiff{3000, -1500, 1500, "#Delta#it{t}_{cell} (ns)"}; + const AxisSpec thAxisCellTimeMean{1500, -600, 900, "#LT#it{t}_{cell}#GT (ns)"}; // event properties mHistManager.add("eventsAll", "Number of events", o2HistType::kTH1F, {{1, 0.5, 1.5}}); @@ -109,7 +113,6 @@ struct ClusterMonitor { mHistManager.add("numberOfClustersSMBC", "number of clusters per supermodule per bunch crossing (ambiguous BCs)", o2HistType::kTH2F, {numberClustersAxis, {20, -0.5, 19.5, "SupermoduleID"}}); // cluster properties (matched clusters) - int MaxMatched = 20; // maximum number of matched tracks, hardcoded in emcalCorrectionTask.cxx! mHistManager.add("clusterE", "Energy of cluster", o2HistType::kTH1F, {energyAxis}); mHistManager.add("clusterEMatched", "Energy of cluster (with match)", o2HistType::kTH1F, {energyAxis}); mHistManager.add("clusterESupermodule", "Energy of the cluster vs. supermoduleID", o2HistType::kTH2F, {energyAxis, supermoduleAxis}); @@ -122,33 +125,8 @@ struct ClusterMonitor { mHistManager.add("clusterDistanceToBadChannel", "Distance to bad channel", o2HistType::kTH1F, {{100, 0, 100}}); mHistManager.add("clusterTimeVsE", "Cluster time vs energy", o2HistType::kTH2F, {timeAxis, energyAxis}); mHistManager.add("clusterAmpFractionLeadingCell", "Fraction of energy in leading cell", o2HistType::kTH1F, {{100, 0, 1}}); - mHistManager.add("clusterTM_dEtadPhi", "cluster trackmatching dEta/dPhi;d#it{#eta};d#it{#varphi} (rad)", o2HistType::kTH3F, {{100, -0.4, 0.4}, {100, -0.4, 0.4}, {MaxMatched, 0.5, MaxMatched + 0.5}}); // dEta dPhi of only the Nth clostest track - mHistManager.add("clusterTM_dEtadPhi_ASide", "cluster trackmatching in A-Side dEta/dPhi;d#it{#eta};d#it{#varphi} (rad)", o2HistType::kTH2F, {{100, -0.4, 0.4}, {100, -0.4, 0.4}}); // dEta dPhi of only the clostest track in A-Aside - mHistManager.add("clusterTM_dEtadPhi_CSide", "cluster trackmatching in C-Side tracks dEta/dPhi;d#it{#eta};d#it{#varphi} (rad)", o2HistType::kTH2F, {{100, -0.4, 0.4}, {100, -0.4, 0.4}}); // dEta dPhi of only the clostest track in C-Side - mHistManager.add("clusterTM_PosdEtadPhi", "cluster trackmatching positive tracks dEta/dPhi;d#it{#eta};d#it{#varphi} (rad)", o2HistType::kTH2F, {{100, -0.4, 0.4}, {100, -0.4, 0.4}}); // dEta dPhi of only the clostest positive track - mHistManager.add("clusterTM_NegdEtadPhi", "cluster trackmatching negative tracks dEta/dPhi;d#it{#eta};d#it{#varphi} (rad)", o2HistType::kTH2F, {{100, -0.4, 0.4}, {100, -0.4, 0.4}}); // dEta dPhi of only the clostest negative track - mHistManager.add("clusterTM_PosdEtadPhi_Pl0_75", "cluster trackmatching positive tracks, p < 0.75 dEta/dPhi;d#it{#eta};d#it{#varphi} (rad)", o2HistType::kTH2F, {{100, -0.4, 0.4}, {100, -0.4, 0.4}}); // dEta dPhi of only the clostest positive track with p < 0.75 GeV/c - mHistManager.add("clusterTM_NegdEtadPhi_Pl0_75", "cluster trackmatching negative tracks, p < 0.75 dEta/dPhi;d#it{#eta};d#it{#varphi} (rad)", o2HistType::kTH2F, {{100, -0.4, 0.4}, {100, -0.4, 0.4}}); // dEta dPhi of only the clostest negative track with p < 0.75 GeV/c - mHistManager.add("clusterTM_PosdEtadPhi_0_75leqPl1_25", "cluster trackmatching positive tracks, 0.75 <= p < 1.25 dEta/dPhi;d#it{#eta};d#it{#varphi} (rad)", o2HistType::kTH2F, {{100, -0.4, 0.4}, {100, -0.4, 0.4}}); // dEta dPhi of only the clostest positive track with 0.75 <= p < 1.25 GeV/c - mHistManager.add("clusterTM_NegdEtadPhi_0_75leqPl1_25", "cluster trackmatching negative tracks, 0.75 <= p < 1.25 dEta/dPhi;d#it{#eta};d#it{#varphi} (rad)", o2HistType::kTH2F, {{100, -0.4, 0.4}, {100, -0.4, 0.4}}); // dEta dPhi of only the clostest negative track with 0.75 <= p < 1.25 GeV/c - mHistManager.add("clusterTM_PosdEtadPhi_Pgeq1_25", "cluster trackmatching positive tracks, p >= 1.25 dEta/dPhi;d#it{#eta};d#it{#varphi} (rad)", o2HistType::kTH2F, {{100, -0.4, 0.4}, {100, -0.4, 0.4}}); // dEta dPhi of only the clostest positive track with p >= 1.25 GeV/c - mHistManager.add("clusterTM_NegdEtadPhi_Pgeq1_25", "cluster trackmatching negative tracks, p >= 1.25 dEta/dPhi;d#it{#eta};d#it{#varphi} (rad)", o2HistType::kTH2F, {{100, -0.4, 0.4}, {100, -0.4, 0.4}}); // dEta dPhi of only the clostest negative track with p >= 1.25 GeV/c - mHistManager.add("clusterTM_dEtaPt", "cluster trackmatching dEta/#it{p}_{T};d#it{#eta};#it{p}_{T} (GeV/#it{c})", o2HistType::kTH2F, {{100, -0.4, 0.4}, {100, 0.0, 50.}}); // dEta vs pT of only the clostest track - mHistManager.add("clusterTM_PosdPhiPt", "cluster trackmatching positive tracks dPhi/#it{p}_{T};d#it{#varphi} (rad);#it{p}_{T} (GeV/#it{c})", o2HistType::kTH2F, {{100, -0.4, 0.4}, {100, 0.0, 50.}}); // dPhi vs pT of only the clostest positive track - mHistManager.add("clusterTM_NegdPhiPt", "cluster trackmatching negative tracks dPh/#it{p}_{T}i;d#it{#varphi} (rad);#it{p}_{T} (GeV/#it{c})", o2HistType::kTH2F, {{100, -0.4, 0.4}, {100, 0.0, 50.}}); // dPhi vs pT of only the clostest negative track - mHistManager.add("clusterTM_dEtaTN", "cluster trackmatching dEta/TN;d#it{#eta};#it{N}_{matched tracks}", o2HistType::kTH2F, {{100, -0.4, 0.4}, {MaxMatched, 0.5, MaxMatched + 0.5}}); // dEta compared to the Nth closest track - mHistManager.add("clusterTM_dPhiTN", "cluster trackmatching dPhi/TN;d#it{#varphi} (rad);#it{N}_{matched tracks}", o2HistType::kTH2F, {{100, -0.4, 0.4}, {MaxMatched, 0.5, MaxMatched + 0.5}}); // dPhi compared to the Nth closest track - mHistManager.add("clusterTM_dRTN", "cluster trackmatching dR/TN;d#it{R};#it{N}_{matched tracks}", o2HistType::kTH2F, {{100, 0.0, 0.4}, {MaxMatched, 0.5, MaxMatched + 0.5}}); // dR compared to the Nth closest track - mHistManager.add("clusterTM_NTrack", "cluster trackmatching NMatchedTracks", o2HistType::kTH1I, {{11, -0.5, 10.5}}); // how many tracks are matched - mHistManager.add("clusterTM_dEtaTNAli", "cluster trackmatching dEta/TN;d#it{#eta};#it{N}_{matched tracks}", o2HistType::kTH2F, {{100, -0.06, 0.06}, {MaxMatched, 0.5, MaxMatched + 0.5}}); // dEta compared to the Nth closest track with cuts from latest Pi0 Run2 analysis - mHistManager.add("clusterTM_dPhiTNAli", "cluster trackmatching dPhi/TN;d#it{#varphi} (rad);#it{N}_{matched tracks}", o2HistType::kTH2F, {{100, -0.1, 0.1}, {MaxMatched, 0.5, MaxMatched + 0.5}}); // dPhi compared to the Nth closest track with cuts from latest Pi0 Run2 analysis - mHistManager.add("clusterTM_dRTNAli", "cluster trackmatching dR/TN;d#it{R};#it{N}_{matched tracks}", o2HistType::kTH2F, {{100, 0.0, 0.1}, {MaxMatched, 0.5, MaxMatched + 0.5}}); // dR compared to the Nth closest track with cuts from latest Pi0 Run2 analysis - mHistManager.add("clusterTM_NTrackAli", "cluster trackmatching NMatchedTracks", o2HistType::kTH1I, {{11, -0.5, 10.5}}); // how many tracks are matched with cuts from latest Pi0 Run2 analysis - mHistManager.add("clusterTM_EoverP_E", "cluster E/p (dEtadPhi<0.05);#it{E}_{cluster}/#it{p}_{track};#it{E}_{cluster} (GeV)", o2HistType::kTH3F, {{500, 0, 10}, {200, 0, 100}, {MaxMatched, 0.5, MaxMatched + 0.5}}); // E/p vs p vs # matched track - mHistManager.add("clusterTM_EvsP", "cluster E/track p (dEtadPhi<0.05);#it{E}_{cluster} (GeV);#it{p}_{track} (GeV/#it{c})", o2HistType::kTH2F, {{500, 0, 10}, {200, 0, 100}}); // E vs p for closest track with dEta,dPhi<0.05 - mHistManager.add("clusterTM_EoverP_electron", "cluster E/electron p (dEtadPhi<0.05);#it{E}_{cluster} (GeV);#it{p}_{e^{#pm}} (GeV/#it{c})", o2HistType::kTH2F, {{500, 0, 10}, {200, 0, 100}}); // E over p vs track pT for closest electron/positron track with dEta,dPhi<0.05 - mHistManager.add("clusterTM_EoverP_hadron", "cluster E/hadron p (dEtadPhi<0.05);#it{E}_{cluster} (GeV);#it{p}_{e^{#pm}} (GeV/#it{c})", o2HistType::kTH2F, {{500, 0, 10}, {200, 0, 100}}); // E over p vs track pT for closest hadron track with dEta,dPhi<0.05 - mHistManager.add("clusterTM_EoverP_Pt", "cluster E/track vs track pT (dEtadPhi<0.05);#it{E}_{cluster}/#it{p}_{track};#it{p}_{T,track} (GeV/#it{c})", o2HistType::kTH2F, {{500, 0, 10}, {200, 0, 100}}); // E vs p vs track pTfor closest track with dEta,dPhi<0.05 + mHistManager.add("clusterCellTimeDiff", "Cell time difference in clusters", o2HistType::kTH1D, {thAxisCellTimeDiff}); + mHistManager.add("clusterCellTimeMean", "Mean cell time per cluster", o2HistType::kTH1D, {thAxisCellTimeMean}); // add histograms per supermodule for (int ism = 0; ism < 20; ++ism) { @@ -266,12 +244,21 @@ struct ClusterMonitor { auto cellsofcluster = emccluscells.sliceBy(perCluster, cluster.globalIndex()); double maxamp = 0; double ampfraction = 0; + mCellTime.clear(); + mCellTime.reserve(cellsofcluster.size()); for (const auto& cell : cellsofcluster) { // example how to get any information of the cell associated with cluster LOG(debug) << "Cell ID:" << cell.calo().amplitude() << " Time " << cell.calo().time(); if (cell.calo().amplitude() > maxamp) { maxamp = cell.calo().amplitude(); } + mCellTime.push_back(cell.calo().time()); + } // end of loop over cells + mHistManager.fill(HIST("clusterCellTimeMean"), std::accumulate(mCellTime.begin(), mCellTime.end(), 0.0f) / mCellTime.size()); + for (std::size_t iCell1 = 0; iCell1 < mCellTime.size() - 1; iCell1++) { + for (std::size_t iCell2 = iCell1 + 1; iCell2 < mCellTime.size(); iCell2++) { + mHistManager.fill(HIST("clusterCellTimeDiff"), mCellTime[iCell1] - mCellTime[iCell2]); + } } ampfraction = maxamp / cluster.energy(); mHistManager.fill(HIST("clusterAmpFractionLeadingCell"), ampfraction); diff --git a/PWGJE/Tasks/emceventselectionqa.cxx b/PWGJE/Tasks/emcEventSelectionQA.cxx similarity index 65% rename from PWGJE/Tasks/emceventselectionqa.cxx rename to PWGJE/Tasks/emcEventSelectionQA.cxx index b373371499f..53bc21b56b4 100644 --- a/PWGJE/Tasks/emceventselectionqa.cxx +++ b/PWGJE/Tasks/emcEventSelectionQA.cxx @@ -9,8 +9,8 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -// Monitoring task for EMCAL event selection -// +/// \file emcEventSelectionQA.cxx +/// \brief Monitoring task for EMCAL event selection /// \author Markus Fasel , Oak Ridge National Laoratory #include @@ -22,56 +22,72 @@ #include "Framework/HistogramRegistry.h" #include "Common/DataModel/EventSelection.h" +#include "PWGJE/Core/utilsBcSelEMC.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::emc_evsel; -using bcEvSels = o2::soa::Join; -using collEventSels = o2::soa::Join; +using BCEvSels = o2::soa::Join; +using CollEventSels = o2::soa::Join; +using FilteredCells = o2::soa::Filtered; struct EmcEventSelectionQA { + + EMCEventSelection emcEvSel; // event selection and monitoring o2::framework::HistogramRegistry mHistManager{"EMCALEventSelectionQAHistograms"}; // Require EMCAL cells (CALO type 1) Filter emccellfilter = aod::calo::caloType == 1; + const int mRun3MinNumber = 300000; + void init(o2::framework::InitContext const&) { - using o2HistType = o2::framework::HistType; - using o2Axis = o2::framework::AxisSpec; - - o2Axis matchingAxis{3, -0.5, 2.5, "matchingStatus", "Matching status"}, // 0, no vertex,1 vertex found , 2 multiple vertices found - bcAxis{4001, -0.5, 4000.5, "bcid", "BC ID"}; - - mHistManager.add("hCollisionMatching", "Collision Status", o2HistType::kTH1F, {matchingAxis}); - mHistManager.add("hCollisionMatchingReadout", "Collision Status EMCAL Readout", o2HistType::kTH1F, {matchingAxis}); - mHistManager.add("hCollisionMatchingMB", "Collision Status EMCAL MB", o2HistType::kTH1F, {matchingAxis}); - mHistManager.add("hCollisionMatching0EMC", "Collision Status EMCAL L0 trigger", o2HistType::kTH1F, {matchingAxis}); - mHistManager.add("hCollisionMatching0DMC", "Collision Status DCAL L0 tr", o2HistType::kTH1F, {matchingAxis}); - mHistManager.add("hCollisionMatchingEG1", "Collision Status EG1 trigger", o2HistType::kTH1F, {matchingAxis}); - mHistManager.add("hCollisionMatchingDG1", "Collision Status DG1 trigger", o2HistType::kTH1F, {matchingAxis}); - mHistManager.add("hCollisionMatchingEG2", "Collision Status EG2 trigger", o2HistType::kTH1F, {matchingAxis}); - mHistManager.add("hCollisionMatchingDG2", "Collision Status DG2 trigger", o2HistType::kTH1F, {matchingAxis}); - mHistManager.add("hCollisionMatchingEJ1", "Collision Status EJ1 trigger", o2HistType::kTH1F, {matchingAxis}); - mHistManager.add("hCollisionMatchingDJ1", "Collision Status DJ1 trigger", o2HistType::kTH1F, {matchingAxis}); - mHistManager.add("hCollisionMatchingEJ2", "Collision Status EJ2 trigger", o2HistType::kTH1F, {matchingAxis}); - mHistManager.add("hCollisionMatchingDJ2", "Collision Status DJ2 trigger", o2HistType::kTH1F, {matchingAxis}); - mHistManager.add("hBCCollisions", "Bunch crossings of found collisions", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("hBCEmcalReadout", "Bunch crossings with EMCAL trigger from CTP", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("hBCEmcalMB", "Bunch crossings with EMCAL MB from CTP", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("hBCEmcal0EMC", "Bunch crossings with EMCAL L0 from CTP", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("hBCEmcal0DMC", "Bunch crossings with DCAL L0 from CTP", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("hBCEmcalEG1", "Bunch crossings with EG1 trigger from CTP", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("hBCEmcalDG1", "Bunch crossings with DG1 trigger from CTP", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("hBCEmcalEG2", "Bunch crossings with EG1 trigger from CTP", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("hBCEmcalDG2", "Bunch crossings with DG2 trigger from CTP", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("hBCEmcalEJ1", "Bunch crossings with EJ1 trigger from CTP", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("hBCEmcalDJ1", "Bunch crossings with DJ1 trigger from CTP", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("hBCEmcalEJ2", "Bunch crossings with EJ2 trigger from CTP", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("hBCEmcalDJ2", "Bunch crossings with DJ2 trigger from CTP", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("hBCTVX", "Bunch crossings with FIT TVX trigger from CTP", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("hBCEmcalCellContent", "Bunch crossings with non-0 EMCAL cell content", o2HistType::kTH1F, {bcAxis}); + using O2HistType = o2::framework::HistType; + using O2Axis = o2::framework::AxisSpec; + + O2Axis matchingAxis{3, -0.5, 2.5, "Matching Status (0, 1, 2+ collisions)", "Matching status"}, // 0, no vertex,1 vertex found , 2 multiple vertices found + bcAxis{4001, -0.5, 4000.5, "bcid", "BC ID"}, + amplitudeAxisLarge{1000, 0., 100., "amplitudeLarge", "Amplitude (GeV)"}, + timeAxisLarge{1500, -600, 900, "celltime", "#it{t}_{cell} (ns)"}; + + mHistManager.add("hCollisionMatching", "Collision Status", O2HistType::kTH1F, {matchingAxis}); + mHistManager.add("hCollisionMatchingReadout", "Collision Status EMCAL Readout", O2HistType::kTH1F, {matchingAxis}); + mHistManager.add("hCollisionMatchingMB", "Collision Status EMCAL MB", O2HistType::kTH1F, {matchingAxis}); + mHistManager.add("hCollisionMatching0EMC", "Collision Status EMCAL L0 trigger", O2HistType::kTH1F, {matchingAxis}); + mHistManager.add("hCollisionMatching0DMC", "Collision Status DCAL L0 tr", O2HistType::kTH1F, {matchingAxis}); + mHistManager.add("hCollisionMatchingEG1", "Collision Status EG1 trigger", O2HistType::kTH1F, {matchingAxis}); + mHistManager.add("hCollisionMatchingDG1", "Collision Status DG1 trigger", O2HistType::kTH1F, {matchingAxis}); + mHistManager.add("hCollisionMatchingEG2", "Collision Status EG2 trigger", O2HistType::kTH1F, {matchingAxis}); + mHistManager.add("hCollisionMatchingDG2", "Collision Status DG2 trigger", O2HistType::kTH1F, {matchingAxis}); + mHistManager.add("hCollisionMatchingEJ1", "Collision Status EJ1 trigger", O2HistType::kTH1F, {matchingAxis}); + mHistManager.add("hCollisionMatchingDJ1", "Collision Status DJ1 trigger", O2HistType::kTH1F, {matchingAxis}); + mHistManager.add("hCollisionMatchingEJ2", "Collision Status EJ2 trigger", O2HistType::kTH1F, {matchingAxis}); + mHistManager.add("hCollisionMatchingDJ2", "Collision Status DJ2 trigger", O2HistType::kTH1F, {matchingAxis}); + mHistManager.add("hBCCollisions", "Bunch crossings of found collisions", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCEmcalReadout", "Bunch crossings with EMCAL trigger from CTP", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCEmcalMB", "Bunch crossings with EMCAL MB from CTP", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCEmcal0EMC", "Bunch crossings with EMCAL L0 from CTP", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCEmcal0DMC", "Bunch crossings with DCAL L0 from CTP", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCEmcalEG1", "Bunch crossings with EG1 trigger from CTP", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCEmcalDG1", "Bunch crossings with DG1 trigger from CTP", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCEmcalEG2", "Bunch crossings with EG1 trigger from CTP", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCEmcalDG2", "Bunch crossings with DG2 trigger from CTP", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCEmcalEJ1", "Bunch crossings with EJ1 trigger from CTP", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCEmcalDJ1", "Bunch crossings with DJ1 trigger from CTP", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCEmcalEJ2", "Bunch crossings with EJ2 trigger from CTP", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCEmcalDJ2", "Bunch crossings with DJ2 trigger from CTP", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCTVX", "Bunch crossings with FIT TVX trigger from CTP", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCNoTVXEmcalReadout", "Bunch crossings with no FIT TVX trigger from CTP but with EMCal im readout", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCEmcalCellContent", "Bunch crossings with non-0 EMCAL cell content", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCCollisionCounter_TVX", "Number of BCs with a certain number of rec. colls", O2HistType::kTH2F, {bcAxis, matchingAxis}); + mHistManager.add("hBCEMCalReadoutAndEmcalCellContent", "Bunch crossings with EMCAL trigger from CTP and non-0 EMCAL cell content", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCNotEMCalReadoutButEmcalCellContent", "Bunch crossings without EMCAL trigger from CTP but with non-0 EMCAL cell content", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCNotAcceptedButEMCalReadout", "Bunch crossings with EMCAL trigger from CTP but not accpeted due to BC selection", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hBCNotAcceptedButEmcalCellContent", "Bunch crossings with non-0 EMCAL cell content but not accpeted due to BC selection", O2HistType::kTH1F, {bcAxis}); + mHistManager.add("hAmplitudevsCellTimeNoReadout", "Amplitude vs cell time for bunch crossings without EMCAL trigger from CTP but with non-0 EMCAL cell content", O2HistType::kTH2D, {timeAxisLarge, amplitudeAxisLarge}); initCollisionHistogram(mHistManager.get(HIST("hCollisionMatching")).get()); initCollisionHistogram(mHistManager.get(HIST("hCollisionMatchingReadout")).get()); @@ -86,17 +102,20 @@ struct EmcEventSelectionQA { initCollisionHistogram(mHistManager.get(HIST("hCollisionMatchingDJ1")).get()); initCollisionHistogram(mHistManager.get(HIST("hCollisionMatchingEJ2")).get()); initCollisionHistogram(mHistManager.get(HIST("hCollisionMatchingDJ2")).get()); + + emcEvSel.addHistograms(mHistManager); // collision monitoring } - PresliceUnsorted perFoundBC = aod::evsel::foundBCId; + PresliceUnsorted perFoundBC = aod::evsel::foundBCId; + Preslice cellsPerFoundBC = aod::calo::bcId; - void process(bcEvSels const& bcs, collEventSels const& collisions, soa::Filtered const& cells) + void process(BCEvSels const& bcs, CollEventSels const& collisions, soa::Filtered const& cells) { std::unordered_map cellGlobalBCs; // Build map of number of cells for corrected BCs using global BCs // used later in the determination whether a BC has EMC cell content (for speed reason) for (const auto& cell : cells) { - auto globalbcid = cell.bc_as().globalBC(); + auto globalbcid = cell.bc_as().globalBC(); auto found = cellGlobalBCs.find(globalbcid); if (found != cellGlobalBCs.end()) { found->second++; @@ -109,7 +128,12 @@ struct EmcEventSelectionQA { bool isEMCALreadout = false; auto bcID = bc.globalBC() % 3564; - if (bc.runNumber() > 300000) { + // get bitmask with bc selection info + const auto rejectionMask = emcEvSel.getEMCCollisionRejectionMask(bc); + // monitor the satisfied event selections + emcEvSel.fillHistograms(rejectionMask); + + if (bc.runNumber() > mRun3MinNumber) { // in case of run3 not all BCs contain EMCAL data, require trigger selection also for min. bias // in addition select also L0/L1 triggers as triggers with EMCAL in reaodut if (bc.alias_bit(kTVXinEMC) || bc.alias_bit(kEMC7) || bc.alias_bit(kEG1) || bc.alias_bit(kEG2) || bc.alias_bit(kDG1) || bc.alias_bit(kDG2) || bc.alias_bit(kEJ1) || bc.alias_bit(kEJ2) || bc.alias_bit(kDJ1) || bc.alias_bit(kDJ2)) { @@ -123,6 +147,25 @@ struct EmcEventSelectionQA { } } + // lookup number of cells for global BC of this BC + // avoid iteration over cell table for speed reason + auto found = cellGlobalBCs.find(bc.globalBC()); + + if (rejectionMask != 0) { + // at least one event selection not satisfied --> reject the candidate + continue; + } else { + if (isEMCALreadout) { + mHistManager.fill(HIST("hBCNotAcceptedButEMCalReadout"), bcID); + } + if (found != cellGlobalBCs.end()) { + // require at least 1 cell for global BC + if (found->second > 0) { + mHistManager.fill(HIST("hBCNotAcceptedButEmcalCellContent"), bcID); + } + } + } + // Monitoring BCs with EMCAL trigger / readout / FIT trigger if (isEMCALreadout) { mHistManager.fill(HIST("hBCEmcalReadout"), bcID); @@ -162,17 +205,21 @@ struct EmcEventSelectionQA { } } - if (bc.selection_bit(aod::evsel::kIsTriggerTVX)) { - mHistManager.fill(HIST("hBCTVX"), bcID); - } - // lookup number of cells for global BC of this BC // avoid iteration over cell table for speed reason - auto found = cellGlobalBCs.find(bc.globalBC()); if (found != cellGlobalBCs.end()) { // require at least 1 cell for global BC if (found->second > 0) { mHistManager.fill(HIST("hBCEmcalCellContent"), bcID); + if (isEMCALreadout) { + mHistManager.fill(HIST("hBCEMCalReadoutAndEmcalCellContent"), bcID); + } else { + mHistManager.fill(HIST("hBCNotEMCalReadoutButEmcalCellContent"), bcID); + auto cellsInBC = cells.sliceBy(cellsPerFoundBC, bc.globalIndex()); + for (const auto& cell : cellsInBC) { + mHistManager.fill(HIST("hAmplitudevsCellTimeNoReadout"), cell.time(), cell.amplitude()); + } + } } } @@ -185,10 +232,19 @@ struct EmcEventSelectionQA { } else { collisionStatus = 2; } + + if (bc.selection_bit(aod::evsel::kIsTriggerTVX)) { + mHistManager.fill(HIST("hBCTVX"), bcID); + mHistManager.fill(HIST("hBCCollisionCounter_TVX"), bcID, collisionStatus); + } + if (collisionStatus >= 0) { mHistManager.fill(HIST("hCollisionMatching"), collisionStatus); if (isEMCALreadout) { mHistManager.fill(HIST("hCollisionMatchingReadout"), collisionStatus); + if (!bc.selection_bit(aod::evsel::kIsTriggerTVX)) { + mHistManager.fill(HIST("hBCNoTVXEmcalReadout"), bcID); + } // various triggers if (bc.alias_bit(kTVXinEMC)) { mHistManager.fill(HIST("hCollisionMatchingMB"), collisionStatus); diff --git a/PWGJE/Tasks/emctmmonitor.cxx b/PWGJE/Tasks/emcTmMonitor.cxx similarity index 99% rename from PWGJE/Tasks/emctmmonitor.cxx rename to PWGJE/Tasks/emcTmMonitor.cxx index 3b6773e7127..3a191cba635 100644 --- a/PWGJE/Tasks/emctmmonitor.cxx +++ b/PWGJE/Tasks/emcTmMonitor.cxx @@ -349,7 +349,6 @@ struct TrackMatchingMonitor { mHistManager.fill(HIST("clusterTM_EoverP_E"), eOverP, cluster.energy(), t); mHistManager.fill(HIST("clusterTM_dEtadPhi"), dEta, dPhi, t); mHistManager.fill(HIST("clusterEMatched"), cluster.energy(), t); - mHistManager.fill(HIST("clusterTM_dEtaPt"), dEta, pT, t); mHistManager.fill(HIST("clusterTM_EvsP"), cluster.energy(), abs_p, t); mHistManager.fill(HIST("clusterTM_EoverP_Pt"), eOverP, match.track_as().pt(), t); mHistManager.fill(HIST("clusterTM_NSigma"), NSigmaEl, match.track_as().pt(), t); diff --git a/PWGJE/Tasks/emcvertexselectionqa.cxx b/PWGJE/Tasks/emcVertexSelectionQA.cxx similarity index 78% rename from PWGJE/Tasks/emcvertexselectionqa.cxx rename to PWGJE/Tasks/emcVertexSelectionQA.cxx index 9d3a33a2443..4a803adc24f 100644 --- a/PWGJE/Tasks/emcvertexselectionqa.cxx +++ b/PWGJE/Tasks/emcVertexSelectionQA.cxx @@ -37,6 +37,15 @@ using FullTracksIU = soa::Join; struct EmcVertexSelectionQA { o2::framework::HistogramRegistry mHistManager{"EMCALVertexSelectionQAHistograms"}; + Configurable cfgZvtxMax{"cfgZvtxMax", 20.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", false, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", false, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + void init(o2::framework::InitContext const&) { using o2HistType = o2::framework::HistType; @@ -66,6 +75,10 @@ struct EmcVertexSelectionQA { mHistManager.add("hVertexRelDiffRobustStdDevDCA", "Relative Difference of Robust StdDev DCA to StdDev DCA of Vertex vs its Quality", o2HistType::kTH2F, {{200, 0, 2}, qualityAxis}); mHistManager.add("hVertexRelDiffRobustStdDevTrackTime", "Relative Difference of Robust Standard Deviation to Standard Deviation of Tracks Contributing to the Vertex vs its Quality", o2HistType::kTH2F, {{200, 0, 2}, qualityAxis}); + // Z vertex positions of two vertices in the same BC (to look for two collisions in the same BC with similar z-vertex positions) + mHistManager.add("hDoubleZVertex", "Z Vertex Position Correlation of two Collions in the same BC", o2HistType::kTH2F, {{300, -15., 15.}, {300, -15., 15.}}); + mHistManager.add("hZVertexDiff", "Difference Z Vertex Position of two Collions in the same BC", o2HistType::kTH1F, {{40000, -20., 20., "Z_{vtx 1}-Z_{vtx 2} (cm)"}}); + // Set axis labels and bin titles initVertexHistogram(mHistManager.get(HIST("hCollisionMatching")).get()); initVertexHistogram(mHistManager.get(HIST("hCollisionMatchingReadout")).get()); @@ -84,6 +97,8 @@ struct EmcVertexSelectionQA { mHistManager.get(HIST("hnVertexContributors")).get()->GetXaxis()->SetTitle("N_{contr} to Vtx 1"); mHistManager.get(HIST("hnVertexContributors")).get()->GetYaxis()->SetTitle("N_{contr} to Vtx 2"); + mHistManager.get(HIST("hDoubleZVertex")).get()->GetXaxis()->SetTitle("Z_{vtx 1} (cm)"); + mHistManager.get(HIST("hDoubleZVertex")).get()->GetYaxis()->SetTitle("Z_{vtx 2} (cm)"); } Preslice perCollision = aod::track::collisionId; @@ -91,23 +106,32 @@ struct EmcVertexSelectionQA { void process(bcEvSels const& bcs, collEventSels const& collisions, FullTracksIU const& tracks) { for (const auto& bc : bcs) { - bool isEMCALreadout = false; + bool isEMCALreadout = (bc.alias_bit(kTVXinEMC) || bc.alias_bit(kEMC7) || bc.alias_bit(kEG1) || bc.alias_bit(kEG2) || bc.alias_bit(kDG1) || bc.alias_bit(kDG2) || bc.alias_bit(kEJ1) || bc.alias_bit(kEJ2) || bc.alias_bit(kDJ1) || bc.alias_bit(kDJ2)); - if (bc.runNumber() > 300000) { - // in case of run3 not all BCs contain EMCAL data, require trigger selection also for min. bias - // in addition select also L0/L1 triggers as triggers with EMCAL in reaodut - if (bc.alias_bit(kTVXinEMC) || bc.alias_bit(kEMC7) || bc.alias_bit(kEG1) || bc.alias_bit(kEG2) || bc.alias_bit(kDG1) || bc.alias_bit(kDG2) || bc.alias_bit(kEJ1) || bc.alias_bit(kEJ2) || bc.alias_bit(kDJ1) || bc.alias_bit(kDJ2)) { - isEMCALreadout = true; - } - } else { - // run1/2: rely on trigger cluster, runlist must contain only runs with EMCAL in readout - // Select min. bias trigger and EMCAL L0/L1 triggers - if (bc.alias_bit(kINT7) || bc.alias_bit(kEMC7) || bc.alias_bit(kEG1) || bc.alias_bit(kEG2) || bc.alias_bit(kEJ1) || bc.alias_bit(kEJ2)) { - isEMCALreadout = true; - } + auto colsinbc = collisions.sliceBy(perFoundBC, bc.globalIndex()); + + bool isBCAccepted = true; + for (auto& col : colsinbc) { + if (cfgRequireSel8 && !col.sel8()) + isBCAccepted = false; + if (cfgRequireFT0AND && !col.selection_bit(o2::aod::evsel::kIsTriggerTVX)) + isBCAccepted = false; + if (col.posZ() < -cfgZvtxMax || col.posZ() > cfgZvtxMax) + isBCAccepted = false; + if (cfgRequireNoTFB && !col.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) + isBCAccepted = false; + if (cfgRequireNoITSROFB && !col.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) + isBCAccepted = false; + if (cfgRequireNoSameBunchPileup && !col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + isBCAccepted = false; + if (cfgRequireVertexITSTPC && !col.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) + isBCAccepted = false; + if (cfgRequireGoodZvtxFT0vsPV && !col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + isBCAccepted = false; } + if (!isBCAccepted) + continue; - auto colsinbc = collisions.sliceBy(perFoundBC, bc.globalIndex()); int collisionStatus = -1; if (!colsinbc.size()) { collisionStatus = 0; @@ -127,6 +151,7 @@ struct EmcVertexSelectionQA { if (collisionStatus > 0) { int nVtx = 0; int nVtxwithTOForTRDcontr = 0; + std::vector zVertexPositions; std::vector nVtxContributors; for (auto& col : colsinbc) { // Loop over all collisions/vertices int ivtxquality = 0; // 0: TPC/ITS contributor, 1: TRD contributor , 2: TOF contributor @@ -184,12 +209,16 @@ struct EmcVertexSelectionQA { nVtxwithTOForTRDcontr++; } nVtxContributors.push_back(nPVContributorTracks); + zVertexPositions.push_back(col.posZ()); } mHistManager.fill(HIST("hnVerticeswithTOForTRDcontr"), nVtx, nVtxwithTOForTRDcontr); if (collisionStatus == 2) { mHistManager.fill(HIST("hnVertexContributors"), nVtxContributors.at(0), nVtxContributors.at(1)); + mHistManager.fill(HIST("hDoubleZVertex"), zVertexPositions.at(0), zVertexPositions.at(1)); + mHistManager.fill(HIST("hZVertexDiff"), zVertexPositions.at(0) - zVertexPositions.at(1)); } nVtxContributors.clear(); + zVertexPositions.clear(); } } } diff --git a/PWGJE/Tasks/emcalGammaGammaBcWise.cxx b/PWGJE/Tasks/emcalGammaGammaBcWise.cxx new file mode 100644 index 00000000000..7007f94bc15 --- /dev/null +++ b/PWGJE/Tasks/emcalGammaGammaBcWise.cxx @@ -0,0 +1,250 @@ +// 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 emcalGammaGammaBcWise.cxx +/// +/// \brief This code loops over BCs to pair photons using only EMCal + TVX (no central barrel, no collisions) +/// +/// \author Nicolas Strangmann (nicolas.strangmann@cern.ch) - Goethe University Frankfurt +/// + +#include +#include +#include "TLorentzVector.h" +#include "TVector3.h" + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Common/DataModel/EventSelection.h" +#include "EMCALBase/Geometry.h" +#include "PWGJE/DataModel/EMCALClusters.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using MyBCs = soa::Join; +using MyCollisions = soa::Join; + +using SelectedUniqueClusters = soa::Filtered; // Clusters from collisions with only one collision in the BC +using SelectedAmbiguousClusters = soa::Filtered; // Clusters from BCs with multiple collisions (no vertex assignment possible) + +struct Photon { // Struct to store photons (unique and ambiguous clusters that passed the cuts) + Photon(float eta, float phi, float energy) : eta(eta), phi(phi), e(energy), theta(2 * std::atan2(std::exp(-eta), 1)), px(e * std::sin(theta) * std::cos(phi)), py(e * std::sin(theta) * std::sin(phi)), pz(e * std::cos(theta)), pt(std::sqrt(px * px + py * py)) + { + photon.SetPxPyPzE(px, py, pz, e); + } + + TLorentzVector photon; + float eta, phi, e; + float theta; + float px, py, pz, pt; +}; + +/// \brief returns if cluster is too close to edge of EMCal (using rotation background method only for EMCal!) +bool IsTooCloseToEdge(const int cellID, const int DistanceToBorder = 1, emcal::Geometry* emcalGeom = nullptr) +{ + if (DistanceToBorder <= 0) { + return false; + } + if (cellID < 0) { + return true; + } + + int iBadCell = -1; + + // check distance to border in case the cell is okay + auto [iSupMod, iMod, iPhi, iEta] = emcalGeom->GetCellIndex(cellID); + auto [irow, icol] = emcalGeom->GetCellPhiEtaIndexInSModule(iSupMod, iMod, iPhi, iEta); + + // Check rows/phi + int iRowLast = 24; + if (emcalGeom->GetSMType(iSupMod) == o2::emcal::EMCALSMType::EMCAL_HALF) { + iRowLast /= 2; // 2/3 sm case + } else if (emcalGeom->GetSMType(iSupMod) == o2::emcal::EMCALSMType::EMCAL_THIRD) { + iRowLast /= 3; // 1/3 sm case + } else if (emcalGeom->GetSMType(iSupMod) == o2::emcal::EMCALSMType::DCAL_EXT) { + iRowLast /= 3; // 1/3 sm case + } + + if (irow < DistanceToBorder || (iRowLast - irow) <= DistanceToBorder) { + iBadCell = 1; + } + + if (iBadCell > 0) { + return true; + } + return false; +} + +bool isPhotonAccepted(Photon const& p, emcal::Geometry* emcalGeom = nullptr) +{ + int cellID = 0; + try { + cellID = emcalGeom->GetAbsCellIdFromEtaPhi(p.eta, p.phi); + if (IsTooCloseToEdge(cellID, 1, emcalGeom)) + cellID = -1; + } catch (o2::emcal::InvalidPositionException& e) { + cellID = -1; + } + + if (cellID == -1) + return false; + + return true; +} + +struct Meson { + Meson(Photon p1, Photon p2) : p1(p1), p2(p2) + { + pMeson = p1.photon + p2.photon; + } + Photon p1, p2; + TLorentzVector pMeson; + + float m() const { return pMeson.M(); } + float pT() const { return pMeson.Pt(); } + float openingAngle() const { return p1.photon.Angle(p2.photon.Vect()); } +}; + +struct EmcalGammaGammaBcWise { + HistogramRegistry mHistManager{"EmcalGammaGammaBcWiseHistograms"}; + + Configurable cfgClusterDefinition{"cfgClusterDefinition", 13, "Clusterizer to be selected, e.g. 13 for kV3MostSplitLowSeed"}; + Configurable cfgMinClusterEnergy{"cfgMinClusterEnergy", 0.7, "Minimum energy of selected clusters (GeV)"}; + Configurable cfgMinM02{"cfgMinM02", 0.1, "Minimum M02 of selected clusters"}; + Configurable cfgMaxM02{"cfgMaxM02", 0.7, "Maximum M02 of selected clusters"}; + Configurable cfgMinTime{"cfgMinTime", -15, "Minimum time of selected clusters (ns)"}; + Configurable cfgMaxTime{"cfgMaxTime", 15, "Maximum time of selected clusters (ns)"}; + Configurable cfgMinOpenAngle{"cfgMinOpenAngle", 0.0202, "Minimum opening angle between photons"}; + + Filter clusterDefinitionFilter = aod::emcalcluster::definition == cfgClusterDefinition; + Filter energyFilter = aod::emcalcluster::energy > cfgMinClusterEnergy; + Filter m02Filter = (aod::emcalcluster::nCells == 1 || (aod::emcalcluster::m02 > cfgMinM02 && aod::emcalcluster::m02 < cfgMaxM02)); + Filter timeFilter = (aod::emcalcluster::time > cfgMinTime && aod::emcalcluster::time < cfgMaxTime); + + std::vector mPhotons; + + emcal::Geometry* emcalGeom; + + void init(InitContext const&) + { + emcalGeom = emcal::Geometry::GetInstanceFromRunNumber(300000); + mHistManager.add("nBCs", "Number of BCs (with (k)TVX);#bf{TVX triggered};#bf{#it{N}_{BCs}}", HistType::kTH1F, {{3, -0.5, 2.5}}); + + mHistManager.add("nCollisionsVsClusters", "Number of collisions vs number of clusters;N_{Collisions};N_{Clusters}", HistType::kTH2F, {{4, -0.5, 3.5}, {21, -0.5, 20.5}}); + + mHistManager.add("clusterE", "Energy of cluster;#bf{#it{E} (GeV)};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{200, 0, 20}}); + mHistManager.add("clusterM02", "Shape of cluster;#bf{#it{M}_{02}};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{200, 0, 2}}); + mHistManager.add("clusterTime", "Time of cluster;#bf{#it{t} (ns)};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{200, -100, 100}}); + + mHistManager.add("invMassVsPt", "Invariant mass and pT of meson candidates", HistType::kTH2F, {{400, 0., 0.8}, {200, 0., 20.}}); + mHistManager.add("invMassVsPtBackground", "Invariant mass and pT of background meson candidates", HistType::kTH2F, {{400, 0., 0.8}, {200, 0., 20.}}); + } + + PresliceUnsorted perFoundBC = aod::evsel::foundBCId; + Preslice perCol = aod::emcalcluster::collisionId; + Preslice perBC = aod::emcalcluster::bcId; + + void process(MyBCs const& bcs, MyCollisions const& collisions, SelectedUniqueClusters const& uClusters, SelectedAmbiguousClusters const& aClusters) + { + for (const auto& bc : bcs) { + mHistManager.fill(HIST("nBCs"), 0.); + if (!bc.selection_bit(aod::evsel::kIsTriggerTVX)) + continue; + mHistManager.fill(HIST("nBCs"), 1.); + if (!bc.alias_bit(kTVXinEMC)) + continue; + mHistManager.fill(HIST("nBCs"), 2.); + + auto collisionsInFoundBC = collisions.sliceBy(perFoundBC, bc.globalIndex()); + + if (collisionsInFoundBC.size() == 1) { // Unique + auto clustersInCollision = uClusters.sliceBy(perCol, collisionsInFoundBC.begin().globalIndex()); + processClusters(clustersInCollision); + } else { // Ambiguous + auto clustersInBC = aClusters.sliceBy(perBC, bc.globalIndex()); + processClusters(clustersInBC); + } + + mHistManager.fill(HIST("nCollisionsVsClusters"), collisionsInFoundBC.size(), mPhotons.size()); + + processMesons(); + } + } + + /// \brief Process EMCAL clusters (either ambigous or unique) + template + void processClusters(Clusters const& clusters) + { + mPhotons.clear(); + + // loop over all clusters from accepted collision + for (const auto& cluster : clusters) { + + mHistManager.fill(HIST("clusterE"), cluster.energy()); + mHistManager.fill(HIST("clusterM02"), cluster.m02()); + mHistManager.fill(HIST("clusterTime"), cluster.time()); + + mPhotons.push_back(Photon(cluster.eta(), cluster.phi(), cluster.energy())); + } + } + + /// \brief Process meson candidates, calculate invariant mass and pT and fill histograms + void processMesons() + { + if (mPhotons.size() < 2) // if less then 2 clusters are found, skip event + return; + + // loop over all photon combinations and build meson candidates + for (unsigned int ig1 = 0; ig1 < mPhotons.size(); ++ig1) { + for (unsigned int ig2 = ig1 + 1; ig2 < mPhotons.size(); ++ig2) { + // build meson from photons + if (mPhotons[ig1].photon.Angle(mPhotons[ig2].photon.Vect()) < cfgMinOpenAngle) + continue; + Meson meson(mPhotons[ig1], mPhotons[ig2]); + mHistManager.fill(HIST("invMassVsPt"), meson.m(), meson.pT()); + + calculateBackground(meson, ig1, ig2); // calculate background candidates (rotation background) + } + } + } + + /// \brief Calculate background (using rotation background method) + void calculateBackground(const Meson& meson, const unsigned int ig1, const unsigned int ig2) + { + if (mPhotons.size() < 3) // if less than 3 clusters are present, skip event + return; + + TVector3 lvRotationPion = (meson.pMeson).Vect(); // calculate rotation axis + for (unsigned int ig3 = 0; ig3 < mPhotons.size(); ++ig3) { + if (ig3 == ig1 || ig3 == ig2) // Skip if photon is one of the meson constituents + continue; + for (const unsigned int ig : {ig1, ig2}) { + TLorentzVector lvRotationPhoton(mPhotons[ig].px, mPhotons[ig].py, mPhotons[ig].pz, mPhotons[ig].e); + lvRotationPhoton.Rotate(constants::math::PIHalf, lvRotationPion); + Photon rotPhoton(lvRotationPhoton.Eta(), lvRotationPhoton.Phi(), lvRotationPhoton.E()); + if (!isPhotonAccepted(rotPhoton, emcalGeom)) + continue; + if (rotPhoton.photon.Angle(mPhotons[ig3].photon.Vect()) < cfgMinOpenAngle) + continue; + Meson mesonRotated(rotPhoton, mPhotons[ig3]); + mHistManager.fill(HIST("invMassVsPtBackground"), mesonRotated.m(), mesonRotated.pT()); + } + } + } +}; + +WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGJE/Tasks/emcalPi0EnergyScaleCalib.cxx b/PWGJE/Tasks/emcalPi0EnergyScaleCalib.cxx index 2a298d0a44b..610e890cf20 100644 --- a/PWGJE/Tasks/emcalPi0EnergyScaleCalib.cxx +++ b/PWGJE/Tasks/emcalPi0EnergyScaleCalib.cxx @@ -201,7 +201,7 @@ struct Pi0EnergyScaleCalibTask { Configurable mMinEnergyCut{"MinEnergyCut", 0.7, "apply min cluster energy cut"}; Configurable mMinNCellsCut{"MinNCellsCut", 1, "apply min cluster number of cell cut"}; Configurable mMinOpenAngleCut{"OpeningAngleCut", 0.0202, "apply min opening angle cut"}; - Configurable mClusterDefinition{"clusterDefinition", "kV3Default", "cluster definition to be selected, e.g. V3Default"}; + Configurable mClusterDefinition{"clusterDefinition", 10, "cluster definition to be selected, e.g. 10 = kV3Default"}; Configurable mRequireBothPhotonsFromAcceptance{"RequireBothPhotonsFromAcceptance", 0, "Require both photons to be from the same acceptance category"}; Configurable mAcceptanceRestrictionType{"AcceptanceRestrictionType", 0, "0: No restriction, 1: Ignore behind TRD, 2: Only Behind TRD, 3: Only EMCal, 4: OnlyDCal, 5: Remove clusters on edges"}; @@ -213,8 +213,7 @@ struct Pi0EnergyScaleCalibTask { // define cluster filter. It selects only those clusters which are of the type // specified in the string mClusterDefinition,e.g. kV3Default, which is V3 clusterizer with default // clusterization parameters - o2::aod::EMCALClusterDefinition clusDef = o2::aod::emcalcluster::getClusterDefinitionFromString(mClusterDefinition.value); - Filter clusterDefinitionSelection = o2::aod::emcalcluster::definition == static_cast(clusDef); + Filter clusterDefinitionSelection = o2::aod::emcalcluster::definition == mClusterDefinition; // define container for photons std::vector mPhotons; diff --git a/PWGJE/Tasks/fullJetSpectraPP.cxx b/PWGJE/Tasks/fullJetSpectraPP.cxx new file mode 100644 index 00000000000..8cdc23ebf9c --- /dev/null +++ b/PWGJE/Tasks/fullJetSpectraPP.cxx @@ -0,0 +1,943 @@ +// 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. + +// FullJet Spectra in pp +// +// +/// \author Archita Rani Dash +#include +#include +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGHF/Core/HfHelper.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/DataModel/EMCALMatchedCollisions.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" + +#include "EventFiltering/filterTables.h" + +using namespace std; +using namespace o2; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using EMCCollisions = o2::soa::Join; // needed for the workaround to access EMCAL trigger bits + +struct FullJetSpectrapp { + + HistogramRegistry registry; + + // Event configurables + Configurable VertexZCut{"VertexZCut", 10.0f, "Accepted z-vertex range"}; + Configurable centralityMin{"centralityMin", -999.0, "minimum centrality"}; + Configurable centralityMax{"centralityMax", 999.0, "maximum centrality"}; + Configurable doEMCALEventWorkaround{"doEMCALEventWorkaround", false, "apply the workaround to read the EMC trigger bit by requiring a cell content in the EMCAL"}; + Configurable doMBGapTrigger{"doMBGapTrigger", true, "set to true only when using MB-Gap Trigger JJ MC"}; + Configurable doMBMC{"doMBMC", false, "set to true only when using MB MC"}; + + // Jet configurables + Configurable selectedJetsRadius{"selectedJetsRadius", 0.4, "resolution parameter for histograms without radius"}; + Configurable> jetRadii{"jetRadii", std::vector{0.4}, "jet resolution parameters"}; + Configurable jetpTMin{"jetpTMin", 20.0, "minimum jet pT"}; + Configurable jetpTMax{"jetpTMax", 350., "maximum jet pT"}; + Configurable jetEtaMin{"jetEtaMin", -0.3, "minimum jet eta"}; // each of these jet configurables are for the fiducial emcal cuts + Configurable jetEtaMax{"jetEtaMax", 0.3, "maximum jet eta"}; // for R = 0.4 (EMCAL eta acceptance: eta_jet = 0.7 - R) + Configurable jetPhiMin{"jetPhiMin", 1.80, "minimum jet phi"}; // phi_jet_min for R = 0.4 is 1.80 + Configurable jetPhiMax{"jetPhiMax", 2.86, "maximum jet phi"}; // phi_jet_min for R = 0.4 is 2.86 + Configurable jetAreaFractionMin{"jetAreaFractionMin", -99.0, "used to make a cut on the jet areas"}; + Configurable leadingConstituentPtMin{"leadingConstituentPtMin", -99.0, "minimum pT selection on jet constituent"}; + + // Track configurables + Configurable trackpTMin{"trackpTMin", 0.15, "minimum track pT"}; + Configurable trackpTMax{"trackpTMax", 350., "maximum track pT"}; + Configurable trackEtaMin{"trackEtaMin", -0.7, "minimum track eta"}; + Configurable trackEtaMax{"trackEtaMax", 0.7, "maximum track eta"}; + Configurable trackPhiMin{"trackPhiMin", 1.396, "minimum track phi"}; + Configurable trackPhiMax{"trackPhiMax", 3.283, "maximum track phi"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + Configurable eventSelections{"eventSelections", "sel8Full", "choose event selection"}; + Configurable particleSelections{"particleSelections", "PhysicalPrimary", "set particle selections"}; + + // Cluster configurables + + Configurable clusterDefinitionS{"clusterDefinition", "kV3Default", "cluster definition to be selected, e.g. V3Default"}; + Configurable clusterEtaMin{"clusterEtaMin", -0.7, "minimum cluster eta"}; + Configurable clusterEtaMax{"clusterEtaMax", 0.7, "maximum cluster eta"}; + Configurable clusterPhiMin{"clusterPhiMin", 1.396, "minimum cluster phi"}; + Configurable clusterPhiMax{"clusterPhiMax", 3.283, "maximum cluster phi"}; + Configurable clusterEnergyMin{"clusterEnergyMin", 0.3, "minimum cluster energy in EMCAL (GeV)"}; + Configurable clusterTimeMin{"clusterTimeMin", -20., "minimum cluster time (ns)"}; + Configurable clusterTimeMax{"clusterTimeMax", 15., "maximum cluster time (ns)"}; + Configurable clusterRejectExotics{"clusterRejectExotics", true, "Reject exotic clusters"}; + + Configurable pTHatMaxMCD{"pTHatMaxMCD", 999.0, "maximum fraction of hard scattering for jet acceptance in detector MC"}; + Configurable pTHatMaxMCP{"pTHatMaxMCP", 999.0, "maximum fraction of hard scattering for jet acceptance in particle MC"}; + Configurable pTHatExponent{"pTHatExponent", 4.0, "exponent of the event weight for the calculation of pTHat"}; // 6 for MB MC and 4 for JJ MC + Configurable pTHatAbsoluteMin{"pTHatAbsoluteMin", -99.0, "minimum value of pTHat"}; + + int trackSelection = -1; + std::vector eventSelectionBits; + std::vector filledJetR; + std::vector jetRadiiValues; + + std::string particleSelection; + + Service pdgDatabase; + + // Add Collision Histograms' Bin Labels for clarity + void labelCollisionHistograms(HistogramRegistry& registry) + { + if (doprocessTracks) { + auto h_collisions_unweighted = registry.get(HIST("h_collisions_unweighted")); + h_collisions_unweighted->GetXaxis()->SetBinLabel(1, "total events"); + h_collisions_unweighted->GetXaxis()->SetBinLabel(2, "JetsData with kTVXinEMC"); + h_collisions_unweighted->GetXaxis()->SetBinLabel(3, "JetsMCD with kTVXinEMC"); + h_collisions_unweighted->GetXaxis()->SetBinLabel(4, "Tracks with kTVXinEMC"); + h_collisions_unweighted->GetXaxis()->SetBinLabel(5, "JetsMCPMCDMatched with kTVXinEMC"); + h_collisions_unweighted->GetXaxis()->SetBinLabel(6, "JetsData w/o kTVXinEMC"); + h_collisions_unweighted->GetXaxis()->SetBinLabel(7, "JetsMCD w/o kTVXinEMC"); + h_collisions_unweighted->GetXaxis()->SetBinLabel(8, "Tracks w/o kTVXinEMC"); + h_collisions_unweighted->GetXaxis()->SetBinLabel(9, "JetsMCPMCDMatched w/o kTVXinEMC"); + h_collisions_unweighted->GetXaxis()->SetBinLabel(10, "Fake Matched MCD Jets"); + h_collisions_unweighted->GetXaxis()->SetBinLabel(11, "Fake Matched MCP Jets"); + } + + if (doprocessTracksWeighted) { + auto h_collisions_weighted = registry.get(HIST("h_collisions_weighted")); + h_collisions_weighted->GetXaxis()->SetBinLabel(1, "total events"); + h_collisions_weighted->GetXaxis()->SetBinLabel(2, "JetsMCDWeighted with kTVXinEMC"); + h_collisions_weighted->GetXaxis()->SetBinLabel(3, "JetsMCPMCDMatchedWeighted with kTVXinEMC"); + h_collisions_weighted->GetXaxis()->SetBinLabel(4, "TracksWeighted with kTVXinEMC"); + h_collisions_weighted->GetXaxis()->SetBinLabel(5, "JetsMCDWeighted w/o kTVXinEMC"); + h_collisions_weighted->GetXaxis()->SetBinLabel(6, "JetsMCPMCDMatchedWeighted w/o kTVXinEMC"); + h_collisions_weighted->GetXaxis()->SetBinLabel(7, "TracksWeighted w/o kTVXinEMC"); + h_collisions_weighted->GetXaxis()->SetBinLabel(8, "Fake Matched Weighted MCD Jets"); + h_collisions_weighted->GetXaxis()->SetBinLabel(9, "Fake Matched Weighted MCP Jets"); + } + } + + void init(o2::framework::InitContext&) + { + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + particleSelection = static_cast(particleSelections); + jetRadiiValues = (std::vector)jetRadii; + + for (std::size_t iJetRadius = 0; iJetRadius < jetRadiiValues.size(); iJetRadius++) { + filledJetR.push_back(0.0); + } + auto jetRadiiBins = (std::vector)jetRadii; + if (jetRadiiBins.size() > 1) { + jetRadiiBins.push_back(jetRadiiBins[jetRadiiBins.size() - 1] + (TMath::Abs(jetRadiiBins[jetRadiiBins.size() - 1] - jetRadiiBins[jetRadiiBins.size() - 2]))); + } else { + jetRadiiBins.push_back(jetRadiiBins[jetRadiiBins.size() - 1] + 0.1); + } + + // Track QA histograms + if (doprocessTracks || doprocessTracksWeighted) { + registry.add("h_collisions_unweighted", "event status; event status;entries", {HistType::kTH1F, {{12, 0., 12.0}}}); + + registry.add("h_track_pt", "track pT;#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}); + registry.add("h_track_eta", "track #eta;#eta_{track};entries", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("h_track_phi", "track #varphi;#varphi_{track};entries", {HistType::kTH1F, {{160, 0., 7.}}}); + registry.add("h_track_energy", "track energy;Energy of tracks;entries", {HistType::kTH1F, {{400, 0., 400.}}}); + registry.add("h_track_energysum", "track energy sum;Sum of track energy per event;entries", {HistType::kTH1F, {{400, 0., 400.}}}); + + // Cluster QA histograms + registry.add("h_clusterTime", "Time of cluster", HistType::kTH1F, {{500, -250, 250, "#it{t}_{cls} (ns)"}}); + registry.add("h_cluster_pt", "cluster pT;#it{p}_{T_cluster} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); + registry.add("h_cluster_eta", "cluster #eta;#eta_{cluster};entries", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("h_cluster_phi", "cluster #varphi;#varphi_{cluster};entries", {HistType::kTH1F, {{160, 0., 7.}}}); + registry.add("h_cluster_energy", "cluster energy;Energy of cluster;entries", {HistType::kTH1F, {{400, 0., 400.}}}); + registry.add("h_cluster_energysum", "cluster energy sum;Sum of cluster energy per event;entries", {HistType::kTH1F, {{400, 0., 400.}}}); + + if (doprocessTracksWeighted) { + registry.add("h_collisions_weighted", "event status;event status;entries", {HistType::kTH1F, {{12, 0.0, 12.0}}}); + } + } + + // Jet QA histograms + if (doprocessJetsData || doprocessJetsMCD || doprocessJetsMCDWeighted) { + registry.add("h_full_jet_pt", "#it{p}_{T,jet};#it{p}_{T_jet} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}); + registry.add("h_full_jet_pt_pTHatcut", "#it{p}_{T,jet};#it{p}_{T_jet} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}); + registry.add("h_full_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("h_full_jet_phi", "jet #varphi;#varphi_{jet};entries", {HistType::kTH1F, {{160, 0., 7.}}}); + registry.add("h_full_jet_clusterTime", "Time of cluster", HistType::kTH1F, {{500, -250, 250, "#it{t}_{cls} (ns)"}}); + registry.add("h2_full_jet_NEF", "#it{p}_{T,jet} vs NEF at Det Level; #it{p}_{T,jet} (GeV/#it{c});NEF", {HistType::kTH2F, {{350, 0., 350.}, {105, 0., 1.05}}}); + registry.add("h2_full_jet_NEF_rejected", "#it{p}_{T,jet} vs NEF at Det Level for rejected events; #it{p}_{T,jet} (GeV/#it{c});NEF", {HistType::kTH2F, {{350, 0., 350.}, {105, 0., 1.05}}}); + + registry.add("h_Detjet_ntracks", "#it{p}_{T,track};#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}); + registry.add("h2_full_jet_chargedconstituents", "Number of charged constituents at Det Level;#it{p}_{T,jet} (GeV/#it{c});N_{ch}", {HistType::kTH2F, {{350, 0., 350.}, {100, 0., 100.}}}); + registry.add("h2_full_jet_neutralconstituents", "Number of neutral constituents at Det Level;#it{p}_{T,jet} (GeV/#it{c});N_{ne}", {HistType::kTH2F, {{350, 0., 350.}, {100, 0., 100.}}}); + registry.add("h_full_jet_chargedconstituents_pt", "track pT;#it{p}^{T,jet}_{track} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}); + registry.add("h_full_jet_chargedconstituents_eta", "track #eta;#eta^{jet}_{track};entries", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("h_full_jet_chargedconstituents_phi", "track #varphi;#varphi^{jet}_{track};entries", {HistType::kTH1F, {{160, 0., 7.}}}); + registry.add("h_full_jet_chargedconstituents_energy", "track energy;Energy of tracks;entries", {HistType::kTH1F, {{400, 0., 400.}}}); + registry.add("h_full_jet_chargedconstituents_energysum", "track energy sum;Sum of track energy per event;entries", {HistType::kTH1F, {{400, 0., 400.}}}); + registry.add("h_full_jet_neutralconstituents_pt", "cluster pT;#it{p}^{T,jet}_{cluster} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); + registry.add("h_full_jet_neutralconstituents_eta", "cluster #eta;#eta^{jet}_{cluster};entries", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("h_full_jet_neutralconstituents_phi", "cluster #varphi;#varphi^{jet}_{cluster};entries", {HistType::kTH1F, {{160, 0., 7.}}}); + registry.add("h_full_jet_neutralconstituents_energy", "cluster energy;Energy of cluster;entries", {HistType::kTH1F, {{400, 0., 400.}}}); + registry.add("h_full_jet_neutralconstituents_energysum", "cluster energy sum;Sum of cluster energy per event;entries", {HistType::kTH1F, {{400, 0., 400.}}}); + registry.add("h2_full_jettrack_pt", "#it{p}_{T,jet} vs #it{p}_{T,track}; #it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{350, 0., 350.}, {200, 0., 200.}}}); + registry.add("h2_full_jettrack_eta", "jet #eta vs jet_track #eta; #eta_{jet};#eta_{track}", {HistType::kTH2F, {{100, -1., 1.}, {500, -5., 5.}}}); + registry.add("h2_full_jettrack_phi", "jet #varphi vs jet_track #varphi; #varphi_{jet}; #varphi_{track}", {HistType::kTH2F, {{160, 0., 7.}, {160, -1., 7.}}}); + + registry.add("h2_track_etaphi", "jet_track #eta vs jet_track #varphi; #eta_{track};#varphi_{track}", {HistType::kTH2F, {{500, -5., 5.}, {160, -1., 7.}}}); + registry.add("h2_jet_etaphi", "jet #eta vs jet #varphi; #eta_{jet};#varphi_{jet}", {HistType::kTH2F, {{100, -1., 1.}, {160, -1., 7.}}}); + } + if (doprocessJetsMCP || doprocessJetsMCPWeighted) { + registry.add("h_full_mcpjet_tablesize", "", {HistType::kTH1F, {{4, 0., 5.}}}); + registry.add("h_full_mcpjet_ntracks", "", {HistType::kTH1F, {{200, -0.5, 200.}}}); + registry.add("h_full_jet_pt_part", "jet pT;#it{p}_{T_jet} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}); + registry.add("h_full_jet_eta_part", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("h_full_jet_phi_part", "jet #varphi;#varphi_{jet};entries", {HistType::kTH1F, {{160, 0., 7.}}}); + registry.add("h2_full_jet_NEF_part", "#it{p}_{T,jet} vs NEF at Part Level;#it{p}_{T,jet} (GeV/#it{c});NEF", {HistType::kTH2F, {{350, 0., 350.}, {105, 0., 1.05}}}); + + registry.add("h_Partjet_ntracks", "#it{p}_{T,constituent};#it{p}_{T_constituent} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}); + registry.add("h2_full_jet_chargedconstituents_part", "Number of charged constituents at Part Level;#it{p}_{T,jet} (GeV/#it{c});N_{ch}", {HistType::kTH2F, {{350, 0., 350.}, {100, 0., 100.}}}); + registry.add("h2_full_jet_neutralconstituents_part", "Number of neutral constituents at Part Level;#it{p}_{T,jet} (GeV/#it{c});N_{ne}", {HistType::kTH2F, {{350, 0., 350.}, {100, 0., 100.}}}); + registry.add("h_full_jet_neutralconstituents_pt_part", "#it{p}_{T} of neutral constituents at Part Level;#it{p}_{T,ne} (GeV/#it{c}); entries", {HistType::kTH1F, {{350, 0., 350.}}}); + registry.add("h_full_jet_neutralconstituents_eta_part", "#eta of neutral constituents at Part Level;#eta_{ne};entries", {HistType::kTH1F, {{350, 0., 350.}}}); + registry.add("h_full_jet_neutralconstituents_phi_part", "#varphi of neutral constituents at Part Level;#varphi_{ne};entries", {HistType::kTH1F, {{350, 0., 350.}}}); + registry.add("h_full_jet_neutralconstituents_energy_part", "neutral constituents' energy;Energy of neutral constituents;entries", {HistType::kTH1F, {{400, 0., 400.}}}); + registry.add("h_full_jet_neutralconstituents_energysum_part", "neutral constituents' energy sum;Sum of neutral constituents' energy per event;entries", {HistType::kTH1F, {{400, 0., 400.}}}); + + registry.add("h2_jettrack_pt_part", "#it{p}_{T,jet} vs #it{p}_{T_track}; #it{p}_{T_jet} (GeV/#it{c});#it{p}_{T_track} (GeV/#it{c})", {HistType::kTH2F, {{350, 0., 350.}, {200, 0., 200.}}}); + registry.add("h2_jettrack_eta_part", "jet #eta vs jet_track #eta; #eta_{jet};#eta_{track}", {HistType::kTH2F, {{100, -1., 1.}, {500, -5., 5.}}}); + registry.add("h2_jettrack_phi_part", "jet #varphi vs jet_track #varphi; #varphi_{jet}; #varphi_{track}", {HistType::kTH2F, {{160, 0., 7.}, {160, -1., 7.}}}); + + registry.add("h2_track_etaphi_part", "jet_track #eta vs jet_track #varphi; #eta_{track};#varphi_{track}", {HistType::kTH2F, {{500, -5., 5.}, {160, -1., 7.}}}); + registry.add("h2_jet_etaphi_part", "jet #eta vs jet #varphi; #eta_{jet};#varphi_{jet}", {HistType::kTH2F, {{100, -1., 1.}, {160, -1., 7.}}}); + } + + if (doprocessJetsMCPMCDMatched || doprocessJetsMCPMCDMatchedWeighted) { + registry.add("h_full_matchedmcdjet_tablesize", "", {HistType::kTH1F, {{350, 0., 350.}}}); + registry.add("h_full_matchedmcpjet_tablesize", "", {HistType::kTH1F, {{350, 0., 350.}}}); + registry.add("h_full_matchedmcdjet_ntracks", "", {HistType::kTH1F, {{200, -0.5, 200.}}}); + registry.add("h_full_matchedmcpjet_ntracks", "", {HistType::kTH1F, {{200, -0.5, 200.}}}); + registry.add("h_full_matchedmcdjet_eta", "Matched MCD jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("h_full_matchedmcdjet_phi", "Matched MCD jet #varphi;#varphi_{jet};entries", {HistType::kTH1F, {{160, 0., 7.}}}); + registry.add("h_full_matchedmcpjet_eta", "Matched MCP jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("h_full_matchedmcpjet_phi", "Matched MCP jet #varphi;#varphi_{jet};entries", {HistType::kTH1F, {{160, 0., 7.}}}); + registry.add("h_full_jet_deltaR", "Distance between matched Det Jet and Part Jet; #Delta R; entries", {HistType::kTH1F, {{100, 0., 1.}}}); + + registry.add("h2_full_jet_energyscaleDet", "Jet Energy Scale (det); p_{T,det} (GeV/c); (p_{T,det} - p_{T,part})/p_{T,part}", {HistType::kTH2F, {{400, 0., 400.}, {200, -1., 1.}}}); + + registry.add("h2_matchedjet_etaphiDet", "Det jet #eta vs jet #varphi; #eta_{jet};#varphi_{jet}", {HistType::kTH2F, {{100, -1., 1.}, {160, -1., 7.}}}); + registry.add("h2_matchedjet_etaphiPart", "Part jet #eta vs jet #varphi; #eta_{jet};#varphi_{jet}", {HistType::kTH2F, {{100, -1., 1.}, {160, -1., 7.}}}); + registry.add("h2_matchedjet_deltaEtaCorr", "Correlation between Det Eta and Part Eta; #eta_{jet,det}; #eta_{jet,part}", {HistType::kTH2F, {{100, -1., 1.}, {100, -1., 1.}}}); + registry.add("h2_matchedjet_deltaPhiCorr", "Correlation between Det Phi and Part Phi; #varphi_{jet,det}; #varphi_{jet,part}", {HistType::kTH2F, {{160, 0., 7.}, {160, 0., 7.}}}); + + registry.add("h2_full_jet_energyscalePart", "Jet Energy Scale (part); p_{T,part} (GeV/c); (p_{T,det} - p_{T,part})/p_{T,part}", {HistType::kTH2F, {{400, 0., 400.}, {200, -1., 1.}}}); + registry.add("h3_full_jet_energyscalePart", "R dependence of Jet Energy Scale (Part); #it{R}_{jet};p_{T,det} (GeV/c); (p_{T,det} - p_{T,part})/p_{T,part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, 0., 400.}, {200, -1., 1.}}}); + registry.add("h2_full_jet_etaresolutionPart", ";p_{T,part} (GeV/c); (#eta_{jet,det} - #eta_{jet,part})/#eta_{jet,part}", {HistType::kTH2F, {{400, 0., 400.}, {100, -1., 1.}}}); + registry.add("h2_full_jet_phiresolutionPart", ";p_{T,part} (GeV/c); (#varphi_{jet,det} - #varphi_{jet,part})/#varphi_{jet,part}", {HistType::kTH2F, {{400, 0., 400.}, {160, -1., 7.}}}); + registry.add("h2_full_jet_energyscaleChargedPart", "Jet Energy Scale (charged part); p_{T,part} (GeV/c); (p_{T,det} - p_{T,part})/p_{T,part}", {HistType::kTH2F, {{400, 0., 400.}, {200, -1., 1.}}}); + registry.add("h2_full_jet_energyscaleNeutralPart", "Jet Energy Scale (neutral part); p_{T,part} (GeV/c); (p_{T,det} - p_{T,part})/p_{T,part}", {HistType::kTH2F, {{400, 0., 400.}, {200, -1., 1.}}}); + registry.add("h2_full_jet_energyscaleChargedVsFullPart", "Jet Energy Scale (charged part, vs. full jet pt); p_{T,part} (GeV/c); (p_{T,det} - p_{T,part})/p_{T,part}", {HistType::kTH2F, {{400, 0., 400.}, {200, -1., 1.}}}); + registry.add("h2_full_jet_energyscaleNeutralVsFullPart", "Jet Energy Scale (neutral part, vs. full jet pt); p_{T,part} (GeV/c); (p_{T,det} - p_{T,part})/p_{T,part}", {HistType::kTH2F, {{400, 0., 400.}, {200, -1., 1.}}}); + registry.add("h2_full_fakemcdjets", "Fake MCD Jets; p_{T,det} (GeV/c); NCounts", {HistType::kTH2F, {{350, 0., 350.}, {100, 0., 100.}}}); + registry.add("h2_full_fakemcpjets", "Fake MCP Jets; p_{T,part} (GeV/c); NCounts", {HistType::kTH2F, {{350, 0., 350.}, {100, 0., 100.}}}); + // Response Matrix + registry.add("h_full_jet_ResponseMatrix", "Full Jets Response Matrix; p_{T,det} (GeV/c); p_{T,part} (GeV/c)", {HistType::kTH2F, {{200, 0., 200.}, {200, 0., 200.}}}); + } + + // Label the histograms + labelCollisionHistograms(registry); + + } // init + + using FullJetTableDataJoined = soa::Join; + using JetTableMCDJoined = soa::Join; + using JetTableMCDWeightedJoined = soa::Join; + using JetTableMCPJoined = soa::Join; + using JetTableMCPWeightedJoined = soa::Join; + + using JetTableMCDMatchedJoined = soa::Join; + using JetTableMCPMatchedJoined = soa::Join; + + using JetTableMCDMatchedWeightedJoined = soa::Join; + using JetTableMCPMatchedWeightedJoined = soa::Join; + + // Applying some cuts(filters) on collisions, tracks, clusters + + Filter eventCuts = (nabs(aod::jcollision::posZ) < VertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax); + // Filter EMCeventCuts = (nabs(aod::collision::posZ) < VertexZCut && aod::collision::centrality >= centralityMin && aod::collision::centrality < centralityMax); + Filter trackCuts = (aod::jtrack::pt >= trackpTMin && aod::jtrack::pt < trackpTMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax && aod::jtrack::phi >= trackPhiMin && aod::jtrack::phi <= trackPhiMax); + aod::EMCALClusterDefinition clusterDefinition = aod::emcalcluster::getClusterDefinitionFromString(clusterDefinitionS.value); + Filter clusterFilter = (aod::jcluster::definition == static_cast(clusterDefinition) && aod::jcluster::eta > clusterEtaMin && aod::jcluster::eta < clusterEtaMax && aod::jcluster::phi >= clusterPhiMin && aod::jcluster::phi <= clusterPhiMax && aod::jcluster::energy >= clusterEnergyMin && aod::jcluster::time > clusterTimeMin && aod::jcluster::time < clusterTimeMax && (clusterRejectExotics && aod::jcluster::isExotic != true)); + Preslice JetMCPPerMcCollision = aod::jet::mcCollisionId; + + template + bool isAcceptedJet(U const& jet) + { + + if (jetAreaFractionMin > -98.0) { + if (jet.area() < jetAreaFractionMin * M_PI * (jet.r() / 100.0) * (jet.r() / 100.0)) { + return false; + } + } + if (leadingConstituentPtMin > -98.0) { + bool isMinleadingConstituent = false; + for (auto& constituent : jet.template tracks_as()) { + if (constituent.pt() >= leadingConstituentPtMin) { + isMinleadingConstituent = true; + break; + } + } + + if (!isMinleadingConstituent) { + return false; + } + } + return true; + } + template + void fillJetHistograms(T const& jet, float weight = 1.0) + { + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (jet.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { // for MCD jets only to remove outliers; setting pTHatMaxMCD = 1 improves purity + return; + } + + float neutralEnergy = 0.0; + double sumtrackE = 0.0; + if (jet.r() == round(selectedJetsRadius * 100.0f)) { + registry.fill(HIST("h_full_jet_pt"), jet.pt(), weight); + registry.fill(HIST("h_full_jet_eta"), jet.eta(), weight); + registry.fill(HIST("h_full_jet_phi"), jet.phi(), weight); + registry.fill(HIST("h2_jet_etaphi"), jet.eta(), jet.phi(), weight); + + for (auto& cluster : jet.template clusters_as()) { + registry.fill(HIST("h2_full_jet_neutralconstituents"), jet.pt(), jet.clustersIds().size(), weight); + + neutralEnergy += cluster.energy(); + double clusterpt = cluster.energy() / std::cosh(cluster.eta()); + registry.fill(HIST("h_full_jet_clusterTime"), cluster.time(), weight); + registry.fill(HIST("h_full_jet_neutralconstituents_pt"), clusterpt, weight); + registry.fill(HIST("h_full_jet_neutralconstituents_eta"), cluster.eta(), weight); + registry.fill(HIST("h_full_jet_neutralconstituents_phi"), cluster.phi(), weight); + registry.fill(HIST("h_full_jet_neutralconstituents_energy"), cluster.energy(), weight); + registry.fill(HIST("h_full_jet_neutralconstituents_energysum"), neutralEnergy, weight); + } + auto NEF = neutralEnergy / jet.energy(); + registry.fill(HIST("h2_full_jet_NEF"), jet.pt(), NEF, weight); + + for (auto& jettrack : jet.template tracks_as()) { + sumtrackE += jettrack.energy(); + + registry.fill(HIST("h_Detjet_ntracks"), jettrack.pt(), weight); + registry.fill(HIST("h2_full_jet_chargedconstituents"), jet.pt(), jet.tracksIds().size(), weight); + registry.fill(HIST("h2_full_jettrack_pt"), jet.pt(), jettrack.pt(), weight); + registry.fill(HIST("h2_full_jettrack_eta"), jet.eta(), jettrack.eta(), weight); + registry.fill(HIST("h2_full_jettrack_phi"), jet.phi(), jettrack.phi(), weight); + + registry.fill(HIST("h2_track_etaphi"), jettrack.eta(), jettrack.phi(), weight); + registry.fill(HIST("h_full_jet_chargedconstituents_pt"), jettrack.pt(), weight); + registry.fill(HIST("h_full_jet_chargedconstituents_eta"), jettrack.eta(), weight); + registry.fill(HIST("h_full_jet_chargedconstituents_phi"), jettrack.phi(), weight); + registry.fill(HIST("h_full_jet_chargedconstituents_energy"), jettrack.energy(), weight); + registry.fill(HIST("h_full_jet_chargedconstituents_energysum"), sumtrackE, weight); + } + } // jet.r() + } + + // check for NEF distribution for rejected events + template + void fillRejectedJetHistograms(T const& jet, float weight = 1.0) + { + float neutralEnergy = 0.0; + if (jet.r() == round(selectedJetsRadius * 100.0f)) { + for (auto& cluster : jet.template clusters_as()) { + neutralEnergy += cluster.energy(); + } + auto NEF = neutralEnergy / jet.energy(); + registry.fill(HIST("h2_full_jet_NEF_rejected"), jet.pt(), NEF, weight); + } // jet.r() + } + + template + void fillMCPHistograms(T const& jet, float weight = 1.0) + { + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (jet.pt() > pTHatMaxMCP * pTHat || pTHat < pTHatAbsoluteMin) { // MCP outlier rejection + return; + } + float neutralEnergy = 0.0; + int neutralconsts = 0; + int chargedconsts = 0; + if (jet.r() == round(selectedJetsRadius * 100.0f)) { + registry.fill(HIST("h_full_mcpjet_tablesize"), jet.size(), weight); + registry.fill(HIST("h_full_mcpjet_ntracks"), jet.tracksIds().size(), weight); + registry.fill(HIST("h_full_jet_pt_part"), jet.pt(), weight); + registry.fill(HIST("h_full_jet_eta_part"), jet.eta(), weight); + registry.fill(HIST("h_full_jet_phi_part"), jet.phi(), weight); + registry.fill(HIST("h2_jet_etaphi_part"), jet.eta(), jet.phi(), weight); + + for (auto& constituent : jet.template tracks_as()) { + auto pdgParticle = pdgDatabase->GetParticle(constituent.pdgCode()); + if (pdgParticle->Charge() == 0) { + neutralconsts++; + neutralEnergy += constituent.e(); // neutral jet constituents at particle level + double clusterpt = constituent.e() / std::cosh(constituent.eta()); + registry.fill(HIST("h2_full_jet_neutralconstituents_part"), jet.pt(), neutralconsts, weight); + registry.fill(HIST("h_full_jet_neutralconstituents_pt_part"), clusterpt, weight); + registry.fill(HIST("h_full_jet_neutralconstituents_eta_part"), constituent.eta(), weight); + registry.fill(HIST("h_full_jet_neutralconstituents_phi_part"), constituent.phi(), weight); + registry.fill(HIST("h_full_jet_neutralconstituents_energy_part"), constituent.e(), weight); + registry.fill(HIST("h_full_jet_neutralconstituents_energysum_part"), neutralEnergy, weight); + + } else { + chargedconsts++; + registry.fill(HIST("h2_full_jet_chargedconstituents_part"), jet.pt(), chargedconsts, weight); // charged jet constituents at particle level + registry.fill(HIST("h2_jettrack_pt_part"), jet.pt(), constituent.pt(), weight); + registry.fill(HIST("h2_jettrack_eta_part"), jet.eta(), constituent.eta(), weight); + registry.fill(HIST("h2_jettrack_phi_part"), jet.phi(), constituent.phi(), weight); + registry.fill(HIST("h2_track_etaphi_part"), constituent.eta(), constituent.phi(), weight); + } + } // constituent loop + auto NEF = neutralEnergy / jet.energy(); + registry.fill(HIST("h2_full_jet_NEF_part"), jet.pt(), NEF, weight); + } + } + + template + void fillTrackHistograms(T const& tracks, U const& clusters, float weight = 1.0) + { + double sumtrackE = 0.0; + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (pTHat < pTHatAbsoluteMin) { // Track outlier rejection + return; + } + for (auto const& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + sumtrackE += track.energy(); + registry.fill(HIST("h_track_pt"), track.pt(), weight); + registry.fill(HIST("h_track_eta"), track.eta(), weight); + registry.fill(HIST("h_track_phi"), track.phi(), weight); + registry.fill(HIST("h_track_energysum"), sumtrackE, weight); + } + double sumclusterE = 0.0; + for (auto const& cluster : clusters) { + double clusterpt = cluster.energy() / std::cosh(cluster.eta()); + sumclusterE += cluster.energy(); + + registry.fill(HIST("h_clusterTime"), cluster.time()); + registry.fill(HIST("h_cluster_pt"), clusterpt, weight); + registry.fill(HIST("h_cluster_eta"), cluster.eta(), weight); + registry.fill(HIST("h_cluster_phi"), cluster.phi(), weight); + registry.fill(HIST("h_cluster_energy"), cluster.energy(), weight); + registry.fill(HIST("h_cluster_energysum"), sumclusterE, weight); + } + } + + template + void fillMatchedHistograms(T const& jetBase, float weight = 1.0) + { + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (jetBase.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { + return; + } + + if (jetBase.has_matchedJetGeo()) { // geometrical jet matching only needed for pp - here,matching Base(Det.level) with Tag (Part. level) jets + registry.fill(HIST("h_full_matchedmcdjet_tablesize"), jetBase.size(), weight); + registry.fill(HIST("h_full_matchedmcdjet_ntracks"), jetBase.tracksIds().size(), weight); + registry.fill(HIST("h2_matchedjet_etaphiDet"), jetBase.eta(), jetBase.phi(), weight); + + for (auto& jetTag : jetBase.template matchedJetGeo_as>()) { + if (jetTag.pt() > pTHatMaxMCP * pTHat || pTHat < pTHatAbsoluteMin) { // MCP outlier rejection + continue; + } + auto deltaEta = jetBase.eta() - jetTag.eta(); + auto deltaPhi = jetBase.phi() - jetTag.phi(); + auto deltaR = jetutilities::deltaR(jetBase, jetTag); + + registry.fill(HIST("h_full_jet_deltaR"), deltaR, weight); + registry.fill(HIST("h_full_matchedmcpjet_tablesize"), jetTag.size(), weight); + registry.fill(HIST("h_full_matchedmcpjet_ntracks"), jetTag.tracksIds().size(), weight); + registry.fill(HIST("h2_matchedjet_etaphiPart"), jetTag.eta(), jetTag.phi(), weight); + registry.fill(HIST("h2_matchedjet_deltaEtaCorr"), jetBase.eta(), jetTag.eta(), weight); + registry.fill(HIST("h2_matchedjet_deltaPhiCorr"), jetBase.phi(), jetTag.phi(), weight); + + // JES for fulljets + registry.fill(HIST("h2_full_jet_energyscaleDet"), jetBase.pt(), (jetBase.pt() - jetTag.pt()) / jetTag.pt(), weight); + registry.fill(HIST("h2_full_jet_energyscalePart"), jetTag.pt(), (jetBase.pt() - jetTag.pt()) / jetTag.pt(), weight); + registry.fill(HIST("h3_full_jet_energyscalePart"), jetBase.r() / 100.0, jetTag.pt(), (jetBase.pt() - jetTag.pt()) / jetTag.pt(), weight); + registry.fill(HIST("h2_full_jet_etaresolutionPart"), jetTag.pt(), deltaEta / jetTag.eta(), weight); + registry.fill(HIST("h2_full_jet_phiresolutionPart"), jetTag.pt(), deltaPhi / jetTag.phi(), weight); + + // Response Matrix + registry.fill(HIST("h_full_jet_ResponseMatrix"), jetBase.pt(), jetTag.pt(), weight); // MCD vs MCP jet pT + } // jetTag + } // jetBase + } + + void processDummy(aod::JetCollisions const&) + { + } + PROCESS_SWITCH(FullJetSpectrapp, processDummy, "dummy task", true); + + void processJetsData(soa::Filtered::iterator const& collision, FullJetTableDataJoined const& jets, aod::JetTracks const&, aod::JetClusters const&) + { + registry.fill(HIST("h_collisions_unweighted"), 1.0); // total events + bool eventAccepted = false; + + // if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + // return; + // } + + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + eventAccepted = true; + if (collision.alias_bit(kTVXinEMC)) { + registry.fill(HIST("h_collisions_unweighted"), 2.0); // JetsData with kTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("h_collisions_unweighted"), 2.0); // JetsData with kTVXinEMC + } + } + + if (!eventAccepted) { + registry.fill(HIST("h_collisions_unweighted"), 6.0); // JetsData w/o kTVXinEMC + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax) || !isAcceptedJet(jet)) { + fillRejectedJetHistograms(jet, 1.0); + } + } + return; + } + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (jet.phi() < jetPhiMin || jet.phi() > jetPhiMax) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillJetHistograms(jet); + } + } + PROCESS_SWITCH(FullJetSpectrapp, processJetsData, "Full Jets Data", false); + + void processJetsMCD(soa::Filtered>::iterator const& collision, JetTableMCDJoined const& jets, aod::JetTracks const&, aod::JetClusters const&) + { + registry.fill(HIST("h_collisions_unweighted"), 1.0); // total events + bool eventAccepted = false; + + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + eventAccepted = true; + if (collision.alias_bit(kTVXinEMC)) { + registry.fill(HIST("h_collisions_unweighted"), 3.0); // JetsMCD with kTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("h_collisions_unweighted"), 3.0); // JetsMCD with kTVXinEMC + } + } + + if (!eventAccepted) { + registry.fill(HIST("h_collisions_unweighted"), 7.0); // JetsMCD w/o kTVXinEMC + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax) || !isAcceptedJet(jet)) { + fillRejectedJetHistograms(jet, 1.0); + } + } + return; + } + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (jet.phi() < jetPhiMin || jet.phi() > jetPhiMax) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillJetHistograms(jet); + } + } + PROCESS_SWITCH(FullJetSpectrapp, processJetsMCD, "Full Jets at Detector Level", false); + + void processJetsMCDWeighted(soa::Filtered>::iterator const& collision, JetTableMCDWeightedJoined const& jets, aod::JMcCollisions const&, aod::JetTracks const&, aod::JetClusters const&) + { + registry.fill(HIST("h_collisions_weighted"), 1.0); // total events + bool eventAccepted = false; + + // if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + // return; + // } + + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + eventAccepted = true; + if (collision.alias_bit(kTVXinEMC)) { + registry.fill(HIST("h_collisions_weighted"), 2.0); // JetsMCDWeighted with kTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("h_collisions_weighted"), 2.0); // JetsMCDWeighted with kTVXinEMC + } + } + + if (!eventAccepted) { + registry.fill(HIST("h_collisions_weighted"), 5.0); // JetsMCDWeighted w/o kTVXinEMC + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax) || !isAcceptedJet(jet)) { + fillRejectedJetHistograms(jet, collision.mcCollision().weight()); + } + } + return; + } + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (jet.phi() < jetPhiMin || jet.phi() > jetPhiMax) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + if (doMBGapTrigger && collision.mcCollision().weight() == 1) { + continue; + } + + // this cut only to be used for calculating Jet Purity and not for Response Matrix + // this is mainly applied to remove all high weight jets causing big fluctuations + double pTHat = 10. / (std::pow(collision.mcCollision().weight(), 1.0 / pTHatExponent)); + if (jet.pt() > 1 * pTHat) { + registry.fill(HIST("h_full_jet_pt_pTHatcut"), jet.pt(), collision.mcCollision().weight()); + } + + fillJetHistograms(jet, collision.mcCollision().weight()); + } + } + PROCESS_SWITCH(FullJetSpectrapp, processJetsMCDWeighted, "Full Jets at Detector Level on weighted events", false); + + void processJetsMCP(typename JetTableMCPJoined::iterator const& jet, aod::JetParticles const&) + { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + return; + } + if (!isAcceptedJet(jet)) { + return; + } + fillMCPHistograms(jet); + } + PROCESS_SWITCH(FullJetSpectrapp, processJetsMCP, "Full Jets at Particle Level", false); + + void processJetsMCPWeighted(typename JetTableMCPWeightedJoined::iterator const& jet, aod::JetParticles const&, aod::JetMcCollisions const&) + { + + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + return; + } + if (!isAcceptedJet(jet)) { + return; + } + if (doMBGapTrigger && jet.eventWeight() == 1) { + return; + } + + fillMCPHistograms(jet, jet.eventWeight()); + } + PROCESS_SWITCH(FullJetSpectrapp, processJetsMCPWeighted, "Full Jets at Particle Level on weighted events", false); + + void processTracks(soa::Filtered::iterator const& collision, soa::Filtered const& tracks, soa::Filtered const& clusters) + { + registry.fill(HIST("h_collisions_unweighted"), 1.0); // total events + bool eventAccepted = false; + if (fabs(collision.posZ()) > VertexZCut) { + return; + } + // if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + // return; + // } + // needed for the workaround to access EMCAL trigger bits. - This is needed for the MC productions in which the EMC trigger bits are missing. (MB MC LHC24f3, for ex.) + // It first requires for atleast a cell in EMCAL to have energy content. + // Once it finds a cell content, + // it then checks if the collision is not an ambiguous collision (i.e. it has to be a unique collision = no bunch pile up) + // If all of these conditions are satisfied then it checks for the required trigger bit in EMCAL. + // For LHC22o, since the EMCAL didn't have hardware triggers, one would only require MB trigger (kTVXinEMC) in the EMCAL. + + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + eventAccepted = true; + if (collision.alias_bit(kTVXinEMC)) { + registry.fill(HIST("h_collisions_unweighted"), 4.0); // Tracks with kTVXinEMC + } + } + } else { + // Check if EMCAL was readout with the MB trigger(kTVXinEMC) fired. If not then reject the event and exit the function. + // This is the default check for the simulations with proper trigger flags not requiring the above workaround. + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("h_collisions_unweighted"), 4.0); // Tracks with kTVXinEMC + } + } + + if (!eventAccepted) { + registry.fill(HIST("h_collisions_unweighted"), 8.0); // Tracks w/o kTVXinEMC + return; + } + // Fill Accepted events histos + fillTrackHistograms(tracks, clusters, 1.0); + } + PROCESS_SWITCH(FullJetSpectrapp, processTracks, "Full Jet tracks", false); + + void processJetsMCPMCDMatched(soa::Filtered>::iterator const& collision, JetTableMCDMatchedJoined const& mcdjets, JetTableMCPMatchedJoined const& mcpjets, aod::JMcCollisions const&, aod::JetTracks const&, aod::JetClusters const&, aod::JetParticles const&) + { + registry.fill(HIST("h_collisions_unweighted"), 1.0); // total events + bool eventAccepted = false; + int fakemcdjet = 0; + int fakemcpjet = 0; + // float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (fabs(collision.posZ()) > VertexZCut) { // making double sure this condition is satisfied + return; + } + // if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + // return; + // } + const auto mcpJetsPerMcCollision = mcpjets.sliceBy(JetMCPPerMcCollision, collision.mcCollisionId()); + + // for (auto mcpjet : mcpJetsPerMcCollision) { + // if (mcpjet.pt() > pTHatMaxMCP * pTHat) { // outlier rejection for MCP + // return; + // } + // } + //**start of event selection** + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + eventAccepted = true; + if (collision.alias_bit(kTVXinEMC)) { + registry.fill(HIST("h_collisions_unweighted"), 5.0); // JetsMCPMCDMatched with kTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("h_collisions_unweighted"), 5.0); // JetsMCPMCDMatched with kTVXinEMC + } + } + if (!eventAccepted) { + registry.fill(HIST("h_collisions_unweighted"), 9.0); // JetsMCPMCDMatched w/o kTVXinEMC + return; + } + //**end of event selection** + + for (const auto& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + // Check if MCD jet is within the EMCAL fiducial region; if not then flag it as a fake jet + if (mcdjet.phi() < jetPhiMin || mcdjet.phi() > jetPhiMax || mcdjet.eta() < jetEtaMin || mcdjet.eta() > jetEtaMax) { + fakemcdjet++; + registry.fill(HIST("h_collisions_unweighted"), 10.0); // Fake Matched MCD Jets + registry.fill(HIST("h2_full_fakemcdjets"), mcdjet.pt(), fakemcdjet, 1.0); + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + + for (auto& mcpjet : mcdjet.template matchedJetGeo_as()) { + // apply emcal fiducial cuts to the matched particle level jets + if (mcpjet.eta() > jetEtaMax || mcpjet.eta() < jetEtaMin || mcpjet.phi() > jetPhiMax || mcpjet.phi() < jetPhiMin) { + fakemcpjet++; + registry.fill(HIST("h_collisions_unweighted"), 11.0); // Fake Matched MCP Jets + registry.fill(HIST("h2_full_fakemcpjets"), mcpjet.pt(), fakemcpjet, 1.0); + continue; + } + } // mcpjet loop + + // // Fill MCD jet histograms if a valid MCP jet match was found within the EMCAL region + // registry.fill(HIST("h_full_matchedmcpjet_eta"), mcpjet.eta(), 1.0); + // registry.fill(HIST("h_full_matchedmcpjet_phi"), mcpjet.phi(), 1.0); + fillMatchedHistograms(mcdjet); + } // mcdjet loop + } + PROCESS_SWITCH(FullJetSpectrapp, processJetsMCPMCDMatched, "Full Jet finder MCP matched to MCD", false); + + void processJetsMCPMCDMatchedWeighted(soa::Filtered>::iterator const& collision, JetTableMCDMatchedWeightedJoined const& mcdjets, JetTableMCPMatchedWeightedJoined const& mcpjets, aod::JMcCollisions const&, aod::JetTracks const&, aod::JetClusters const&, aod::JetParticles const&) + { + float eventWeight = collision.mcCollision().weight(); + + if (fabs(collision.posZ()) > VertexZCut) { // making double sure this condition is satisfied + return; + } + if (doMBGapTrigger && eventWeight == 1) { + return; + } + // if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + // return; + // } + + registry.fill(HIST("h_collisions_weighted"), 1.0, eventWeight); // total events with eventWeight!=1 + bool eventAccepted = false; + int fakemcdjet = 0; + int fakemcpjet = 0; + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + const auto mcpJetsPerMcCollision = mcpjets.sliceBy(JetMCPPerMcCollision, collision.mcCollisionId()); + + for (auto mcpjet : mcpJetsPerMcCollision) { + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { // outlier rejection for MCP + return; + } + } + + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + eventAccepted = true; + if (collision.alias_bit(kTVXinEMC)) { + registry.fill(HIST("h_collisions_weighted"), 3.0, eventWeight); // JetsMCPMCDMatchedWeighted with kTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("h_collisions_weighted"), 3.0, eventWeight); // JetsMCPMCDMatchedWeighted with kTVXinEMC + } + } + + if (!eventAccepted) { + registry.fill(HIST("h_collisions_weighted"), 6.0, eventWeight); // JetsMCPMCDMatchedWeighted w/o kTVXinEMC + return; + } + + for (const auto& mcdjet : mcdjets) { + // Check if MCD jet is within the EMCAL fiducial region; if not then flag it as a fake jet + if (mcdjet.phi() < jetPhiMin || mcdjet.phi() > jetPhiMax || mcdjet.eta() < jetEtaMin || mcdjet.eta() > jetEtaMax) { + fakemcdjet++; + registry.fill(HIST("h_collisions_weighted"), 8.0); // Fake Matched Weighted MCD Jets + registry.fill(HIST("h2_full_fakemcdjets"), mcdjet.pt(), fakemcdjet, eventWeight); + continue; + } + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + + for (auto& mcpjet : mcdjet.template matchedJetGeo_as()) { + // apply emcal fiducial cuts to the matched particle level jets + if (mcpjet.eta() > jetEtaMax || mcpjet.eta() < jetEtaMin || mcpjet.phi() > jetPhiMax || mcpjet.phi() < jetPhiMin) { + fakemcpjet++; + registry.fill(HIST("h_collisions_weighted"), 9.0); // Fake Matched Weighted MCP Jets + registry.fill(HIST("h2_full_fakemcpjets"), mcpjet.pt(), fakemcpjet, eventWeight); + continue; + } + // // If both MCD-MCP matched jet pairs are within the EMCAL fiducial region, fill these histos + registry.fill(HIST("h_full_matchedmcpjet_eta"), mcpjet.eta(), eventWeight); + registry.fill(HIST("h_full_matchedmcpjet_phi"), mcpjet.phi(), eventWeight); + } // mcpjet + // Fill MCD jet histograms if a valid MCP jet match was found within the EMCAL region + // registry.fill(HIST("h_full_matchedmcdjet_eta"), mcdjet.eta(), eventWeight); + // registry.fill(HIST("h_full_matchedmcdjet_phi"), mcdjet.phi(), eventWeight); + fillMatchedHistograms(mcdjet, mcdjet.eventWeight()); + } // mcdjet + } + PROCESS_SWITCH(FullJetSpectrapp, processJetsMCPMCDMatchedWeighted, "Full Jet finder MCP matched to MCD on weighted events", false); + + void processTracksWeighted(soa::Filtered>::iterator const& collision, + aod::JMcCollisions const&, + soa::Filtered const& tracks, + soa::Filtered const& clusters) + { + bool eventAccepted = false; + float eventWeight = collision.mcCollision().weight(); + if (fabs(collision.posZ()) > VertexZCut) { + return; + } + if (eventWeight == 1) { + return; + } + // if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + // return; + // } + // set "doMBGapTrigger" to true only if you are testing with MB Gap-triggers + if (doMBGapTrigger && eventWeight == 1) { + return; + } + registry.fill(HIST("h_collisions_weighted"), 1.0, eventWeight); // total events + + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + eventAccepted = true; + fillTrackHistograms(tracks, clusters, eventWeight); + if (collision.alias_bit(kTVXinEMC)) { + registry.fill(HIST("h_collisions_weighted"), 4.0, eventWeight); // TracksWeighted with kTVXinEMC + } + } + } else { + // Check if EMCAL was readout with the MB trigger(kTVXinEMC) fired. If not then reject the event and exit the function. + // This is the default check for the simulations with proper trigger flags not requiring the above workaround. + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("h_collisions_weighted"), 4.0, eventWeight); // TracksWeighted with kTVXinEMC + } + } + + if (!eventAccepted) { + registry.fill(HIST("h_collisions_weighted"), 7.0, eventWeight); // TracksWeighted w/o kTVXinEMC + return; + } + // registry.fill(HIST("h_gaptrig_collisions"), 1.0, eventWeight); + fillTrackHistograms(tracks, clusters, eventWeight); + } + PROCESS_SWITCH(FullJetSpectrapp, processTracksWeighted, "Full Jet tracks weighted", false); + +}; // struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"full-jet-spectra-pp"})}; +} diff --git a/PWGJE/Tasks/FullJetTriggerQATask.cxx b/PWGJE/Tasks/fullJetTriggerQATask.cxx similarity index 97% rename from PWGJE/Tasks/FullJetTriggerQATask.cxx rename to PWGJE/Tasks/fullJetTriggerQATask.cxx index 9dad8d604b5..c9a9152381d 100644 --- a/PWGJE/Tasks/FullJetTriggerQATask.cxx +++ b/PWGJE/Tasks/fullJetTriggerQATask.cxx @@ -38,7 +38,7 @@ using namespace o2::framework; using namespace o2::framework::expressions; struct JetTriggerQA { - using selectedClusters = o2::soa::Filtered; + using selectedClusters = o2::soa::Filtered; using fullJetInfos = soa::Join; using neutralJetInfos = soa::Join; using collisionWithTrigger = soa::Join::iterator; @@ -544,7 +544,7 @@ struct JetTriggerQA { } template - std::pair, std::vector> fillJetQA(const JetCollection& jets, JetTracks const& /*tracks*/, selectedClusters const& /*clusters*/, std::bitset /*hwtrg*/, const std::bitset& triggerstatus) + std::pair, std::vector> fillJetQA(const JetCollection& jets, aod::JetTracks const& /*tracks*/, selectedClusters const& /*clusters*/, std::bitset /*hwtrg*/, const std::bitset& triggerstatus) { auto isTrigger = [&triggerstatus](TriggerType_t triggertype) -> bool { return triggerstatus.test(triggertype); @@ -568,7 +568,7 @@ struct JetTriggerQA { // This gives us access to all jet substructure information // auto tracksInJet = jetTrackConstituents.sliceBy(perJetTrackConstituents, jet.globalIndex()); // for (const auto& trackList : tracksInJet) { - for (auto& track : jet.template tracks_as()) { + for (auto& track : jet.template tracks_as()) { auto trackPt = track.pt(); auto chargeFrag = track.px() * jet.px() + track.py() * jet.py() + track.pz() * jet.pz(); chargeFrag /= (jet.p() * jet.p()); @@ -647,12 +647,12 @@ struct JetTriggerQA { return std::make_pair(vecMaxJet, vecMaxJetNoFiducial); } - using JetCollisionsTable = soa::Join; + using JetCollisionsTable = soa::Join; template void runQA(collisionWithTrigger const& collision, JetCollection const& jets, - JetTracks const& tracks, + aod::JetTracks const& tracks, selectedClusters const& clusters) { std::bitset triggerstatus; @@ -688,55 +688,51 @@ struct JetTriggerQA { setTrigger(TriggerType_t::kEmcalMB); } - if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::fullHigh)) { + if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::jetFullHighPt)) { fillEventSelectionCounter(3); setTrigger(TriggerType_t::kEmcalJetFull); } - if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::fullLow)) { + if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::jetFullLowPt)) { fillEventSelectionCounter(4); setTrigger(TriggerType_t::kEmcalJetFullLow); } - if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::neutralHigh)) { + if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::jetNeutralHighPt)) { fillEventSelectionCounter(5); setTrigger(TriggerType_t::kEmcalJetNeutral); } - if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::neutralLow)) { + if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::jetNeutralLowPt)) { fillEventSelectionCounter(6); setTrigger(TriggerType_t::kEmcalJetNeutralLow); } - if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::neutralLow)) { - fillEventSelectionCounter(6); - setTrigger(TriggerType_t::kEmcalJetNeutralLow); - } - if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::gammaVeryHighEMCAL)) { + if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::gammaVeryHighPtEMCAL)) { fillEventSelectionCounter(7); setTrigger(TriggerType_t::kEmcalGammaVeryHigh); } - if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::gammaVeryHighDCAL)) { + if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::gammaVeryHighPtDCAL)) { fillEventSelectionCounter(8); setTrigger(TriggerType_t::kDcalGammaVeryHigh); } - if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::gammaHighEMCAL)) { + if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::gammaHighPtEMCAL)) { fillEventSelectionCounter(9); setTrigger(TriggerType_t::kEmcalGammaHigh); } - if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::gammaHighDCAL)) { + if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::gammaHighPtDCAL)) { fillEventSelectionCounter(10); setTrigger(TriggerType_t::kDcalGammaHigh); } - if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::gammaLowEMCAL)) { + if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::gammaLowPtEMCAL)) { fillEventSelectionCounter(11); setTrigger(TriggerType_t::kEmcalGammaLow); } - if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::gammaLowDCAL)) { + if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::gammaLowPtDCAL)) { fillEventSelectionCounter(12); setTrigger(TriggerType_t::kDcalGammaLow); } - if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::gammaVeryLowEMCAL)) { + if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::gammaVeryLowPtEMCAL)) { fillEventSelectionCounter(13); setTrigger(TriggerType_t::kEmcalGammaVeryLow); } - if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::gammaVeryLowDCAL)) { + if (jetderiveddatautilities::selectFullTrigger(collision, jetderiveddatautilities::JTrigSelFull::gammaVeryLowPtDCAL)) { fillEventSelectionCounter(14); setTrigger(TriggerType_t::kDcalGammaVeryLow); } @@ -800,8 +796,8 @@ struct JetTriggerQA { registry.fill(HIST("hJetRMaxPtJetPt"), jet.r() * 1e-2, jetPt, jet.pt()); } } // for jets - } // if maxJet.r() == std::round(f_jetR * 100) - } // for maxJet + } // if maxJet.r() == std::round(f_jetR * 100) + } // for maxJet // Fill counters for events without max jets for (std::size_t ir = 0; ir < foundMaxJet.size(); ir++) { if (!foundMaxJet[ir]) { @@ -823,14 +819,14 @@ struct JetTriggerQA { for (const auto& jet : jets) { registry.fill(HIST("hJetRMaxPtJetPtNoFiducial"), jet.r() * 1e-2, jetPt, jet.pt()); } // for jets - } // if maxJet.r() == std::round(f_jetR * 100) - } // for maxjet no fiducial + } // if maxJet.r() == std::round(f_jetR * 100) + } // for maxjet no fiducial } // process void processFullJets(collisionWithTrigger const& collision, fullJetInfos const& jets, - JetTracks const& tracks, + aod::JetTracks const& tracks, selectedClusters const& clusters) { runQA(collision, jets, tracks, clusters); @@ -839,7 +835,7 @@ struct JetTriggerQA { void processNeutralJets(collisionWithTrigger const& collision, neutralJetInfos const& jets, - JetTracks const& tracks, + aod::JetTracks const& tracks, selectedClusters const& clusters) { runQA(collision, jets, tracks, clusters); diff --git a/PWGJE/Tasks/gammaJetTreeProducer.cxx b/PWGJE/Tasks/gammaJetTreeProducer.cxx new file mode 100644 index 00000000000..351742682d0 --- /dev/null +++ b/PWGJE/Tasks/gammaJetTreeProducer.cxx @@ -0,0 +1,359 @@ +// 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. + +// C++ system headers first +#include +#include +#include + +// Framework and other headers after +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/GammaJetAnalysisTree.h" + +#include "EMCALBase/Geometry.h" +#include "EMCALCalib/BadChannelMap.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "DataFormatsEMCAL/Cell.h" +#include "DataFormatsEMCAL/Constants.h" +#include "DataFormatsEMCAL/AnalysisCluster.h" +#include "TVector2.h" + +#include "CommonDataFormat/InteractionRecord.h" + +#include "EventFiltering/filterTables.h" + +// \struct GammaJetTreeProducer +/// \brief Task to produce a tree for gamma-jet analysis, including photons (and information of isolation) and charged and full jets +/// \author Florian Jonas , UC Berkeley/LBNL +/// \since 02.08.2024 +/// +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using emcClusters = o2::soa::Join; + +#include "Framework/runDataProcessing.h" + +struct GammaJetTreeProducer { + // analysis tree + // charged jets + // photon candidates + Produces chargedJetsTable; + Produces eventsTable; + Produces gammasTable; + + HistogramRegistry mHistograms{"GammaJetTreeProducerHisto"}; + + // --------------- + // Configureables + // --------------- + + // event cuts + Configurable mVertexCut{"vertexCut", 10.0, "apply z-vertex cut with value in cm"}; + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable triggerMasks{"triggerMasks", "", "possible JE Trigger masks: fJetChLowPt,fJetChHighPt,fTrackLowPt,fTrackHighPt,fJetD0ChLowPt,fJetD0ChHighPt,fJetLcChLowPt,fJetLcChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt,fJetNeutralHighPt,fJetNeutralLowPt,fGammaVeryHighPtEMCAL,fGammaVeryHighPtDCAL,fGammaHighPtEMCAL,fGammaHighPtDCAL,fGammaLowPtEMCAL,fGammaLowPtDCAL,fGammaVeryLowPtEMCAL,fGammaVeryLowPtDCAL"}; + Configurable + trackSelections{"trackSelections", "globalTracks", "set track selections"}; + Configurable trackMinPt{"trackMinPt", 0.15, "minimum track pT cut"}; + Configurable jetPtMin{"jetPtMin", 5.0, "minimum jet pT cut"}; + Configurable isoR{"isoR", 0.4, "isolation cone radius"}; + Configurable perpConeJetR{"perpConeJetR", 0.4, "perpendicular cone radius used to calculate perp cone rho for jet"}; + Configurable trackMatchingEoverP{"trackMatchingEoverP", 2.0, "closest track is required to have E/p < value"}; + Configurable minClusterETrigger{"minClusterETrigger", 0.0, "minimum cluster energy to trigger"}; + + int mRunNumber = 0; + std::vector eventSelectionBits; + int trackSelection = -1; + + std::unordered_map collisionMapping; + std::vector triggerMaskBits; + + void init(InitContext const&) + { + using o2HistType = HistType; + using o2Axis = AxisSpec; + + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(triggerMasks); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + + // create histograms + LOG(info) << "Creating histograms"; + + const o2Axis ptAxis{100, 0, 200, "p_{T} (GeV/c)"}; + const o2Axis energyAxis{100, 0, 100, "E (GeV)"}; + const o2Axis m02Axis{100, 0, 3, "m02"}; + const o2Axis etaAxis{100, -1, 1, "#eta"}; + const o2Axis phiAxis{100, 0, 2 * TMath::Pi(), "#phi"}; + const o2Axis occupancyAxis{300, 0, 30000, "occupancy"}; + mHistograms.add("clusterE", "Energy of cluster", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("trackPt", "pT of track", o2HistType::kTH1F, {ptAxis}); + mHistograms.add("chjetPt", "pT of charged jet", o2HistType::kTH1F, {ptAxis}); + mHistograms.add("chjetPtEtaPhi", "pT of charged jet", o2HistType::kTHnSparseF, {ptAxis, etaAxis, phiAxis}); + mHistograms.add("chjetpt_vs_constpt", "pT of charged jet vs pT of constituents", o2HistType::kTH2F, {ptAxis, ptAxis}); + + // track QA THnSparse + mHistograms.add("trackPtEtaPhi", "Track QA", o2HistType::kTHnSparseF, {ptAxis, etaAxis, phiAxis}); + mHistograms.add("trackPtEtaOccupancy", "Track QA vs occupancy", o2HistType::kTHnSparseF, {ptAxis, etaAxis, occupancyAxis}); + } + + // --------------------- + // Helper functions + // --------------------- + bool isTrackSelected(const auto& track) + { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + return false; + } + if (track.pt() < trackMinPt) { + return false; + } + + return true; + } + + int getStoredColIndex(const auto& collision) + { + int32_t storedColIndex = -1; + if (auto foundCol = collisionMapping.find(collision.globalIndex()); foundCol != collisionMapping.end()) { + storedColIndex = foundCol->second; + } + return storedColIndex; + } + + bool isEventAccepted(const auto& collision, const auto& clusters) + { + + if (collision.posZ() > mVertexCut) { + return false; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return false; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return false; + } + if (!jetderiveddatautilities::eventEMCAL(collision)) { + return false; + } + + // Check if event contains a cluster with energy > minClusterETrigger + for (auto cluster : clusters) { + if (cluster.energy() > minClusterETrigger) { + return true; + } + } + return false; + } + + double ch_iso_in_cone(const auto& cluster, aod::JetTracks const& tracks, float radius = 0.4) + { + double iso = 0; + for (auto track : tracks) { + if (!isTrackSelected(track)) { + continue; + } + // make dR function live somwhere else + float dR = jetutilities::deltaR(cluster, track); + if (dR < radius) { + iso += track.pt(); + } + } + return iso; + } + + void runTrackQA(const auto& collision, aod::JetTracks const& tracks) + { + for (auto track : tracks) { + if (!isTrackSelected(track)) { + continue; + } + mHistograms.fill(HIST("trackPt"), track.pt()); + mHistograms.fill(HIST("trackPtEtaPhi"), track.pt(), track.eta(), track.phi()); + mHistograms.fill(HIST("trackPtEtaOccupancy"), track.pt(), track.eta(), collision.trackOccupancyInTimeRange()); + } + } + + double ch_perp_cone_rho(const auto& object, aod::JetTracks const& tracks, float radius = 0.4) + { + double ptSumLeft = 0; + double ptSumRight = 0; + + double cPhi = TVector2::Phi_0_2pi(object.phi()); + + // rotate cone left by 90 degrees + float cPhiLeft = cPhi - TMath::Pi() / 2; + float cPhiRight = cPhi + TMath::Pi() / 2; + + // loop over tracks + float dRLeft, dRRight; + for (auto track : tracks) { + if (!isTrackSelected(track)) { + continue; + } + dRLeft = jetutilities::deltaR(object.eta(), cPhiLeft, track.eta(), track.phi()); + dRRight = jetutilities::deltaR(object.eta(), cPhiRight, track.eta(), track.phi()); + + if (dRLeft < radius) { + ptSumLeft += track.pt(); + } + if (dRRight < radius) { + ptSumRight += track.pt(); + } + } + + float rho = (ptSumLeft + ptSumRight) / (2 * TMath::Pi() * radius * radius); + return rho; + } + + // --------------------- + // Processing functions + // --------------------- + // WARNING: This function always has to run first in the processing chain + void processClearMaps(aod::JetCollisions const&) + { + collisionMapping.clear(); + } + PROCESS_SWITCH(GammaJetTreeProducer, processClearMaps, "process function that clears all the maps in each dataframe", true); + + // WARNING: This function always has to run second in the processing chain + void processEvent(soa::Join::iterator const& collision, emcClusters const& clusters) + { + if (!isEventAccepted(collision, clusters)) { + return; + } + + eventsTable(collision.multiplicity(), collision.centrality(), collision.rho(), collision.eventSel(), collision.trackOccupancyInTimeRange(), collision.alias_raw()); + collisionMapping[collision.globalIndex()] = eventsTable.lastIndex(); + } + PROCESS_SWITCH(GammaJetTreeProducer, processEvent, "Process event", true); + + // --------------------- + // Processing functions can be safely added below this line + // --------------------- + + // define cluster filter. It selects only those clusters which are of the type + // sadly passing of the string at runtime is not possible for technical region so cluster definition is + // an integer instead + PresliceUnsorted EMCTrackPerTrack = aod::jemctrack::trackId; + // Process clusters + void processClusters(soa::Join::iterator const& collision, emcClusters const& clusters, aod::JetTracks const& tracks, aod::JEMCTracks const& emctracks) + { + // event selection + int32_t storedColIndex = getStoredColIndex(collision); + if (storedColIndex == -1) + return; + + // eventsTable(collision.multiplicity(), collision.centrality(), collision.rho(), collision.eventSel(), collision.trackOccupancyInTimeRange(), collision.alias_raw()); + // collisionMapping[collision.globalIndex()] = eventsTable.lastIndex(); + + // loop over tracks one time for QA + runTrackQA(collision, tracks); + + // loop over clusters + for (auto cluster : clusters) { + + // fill histograms + mHistograms.fill(HIST("clusterE"), cluster.energy()); + + double isoraw = ch_iso_in_cone(cluster, tracks, isoR); + double perpconerho = ch_perp_cone_rho(cluster, tracks, isoR); + + // find closest matched track + double dEta = 0; + double dPhi = 0; + // double dRMin = 100; + double p = -1; + + // do track matching + auto tracksofcluster = cluster.matchedTracks_as(); + for (auto track : tracksofcluster) { + if (!isTrackSelected(track)) { + continue; + } + auto emcTracksPerTrack = emctracks.sliceBy(EMCTrackPerTrack, track.globalIndex()); + auto emcTrack = emcTracksPerTrack.iteratorAt(0); + // find closest track that still has E/p < trackMatchingEoverP + if (cluster.energy() / track.p() > trackMatchingEoverP) { + continue; + } else { + dEta = cluster.eta() - emcTrack.etaEmcal(); + dPhi = RecoDecay::constrainAngle(RecoDecay::constrainAngle(emcTrack.phiEmcal(), -M_PI) - RecoDecay::constrainAngle(cluster.phi(), -M_PI), -M_PI); + p = track.p(); + break; + } + } + gammasTable(storedColIndex, cluster.energy(), cluster.definition(), cluster.eta(), cluster.phi(), cluster.m02(), cluster.m20(), cluster.nCells(), cluster.time(), cluster.isExotic(), cluster.distanceToBadChannel(), cluster.nlm(), isoraw, perpconerho, dPhi, dEta, p); + } + + // dummy loop over tracks + for (auto track : tracks) { + mHistograms.fill(HIST("trackPt"), track.pt()); + } + } + PROCESS_SWITCH(GammaJetTreeProducer, processClusters, "Process EMCal clusters", true); + + Filter jetCuts = aod::jet::pt > jetPtMin; + // Process charged jets + void processChargedJets(soa::Join::iterator const& collision, soa::Filtered> const& chargedJets, aod::JetTracks const& tracks) + { + // event selection + int32_t storedColIndex = getStoredColIndex(collision); + if (storedColIndex == -1) + return; + float leadingTrackPt = 0; + ushort nconst = 0; + // loop over charged jets + for (auto jet : chargedJets) { + if (jet.pt() < jetPtMin) + continue; + nconst = 0; + leadingTrackPt = 0; + // loop over constituents + for (auto& constituent : jet.template tracks_as()) { + mHistograms.fill(HIST("chjetpt_vs_constpt"), jet.pt(), constituent.pt()); + nconst++; + if (constituent.pt() > leadingTrackPt) { + leadingTrackPt = constituent.pt(); + } + } + + // calculate perp cone rho + double perpconerho = ch_perp_cone_rho(jet, tracks, perpConeJetR); + mHistograms.fill(HIST("chjetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi()); + chargedJetsTable(storedColIndex, jet.pt(), jet.eta(), jet.phi(), jet.r(), jet.energy(), jet.mass(), jet.area(), leadingTrackPt, perpconerho, nconst); + // fill histograms + mHistograms.fill(HIST("chjetPt"), jet.pt()); + } + } + PROCESS_SWITCH(GammaJetTreeProducer, processChargedJets, "Process charged jets", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc, TaskName{"gamma-jet-tree-producer"})}; + return workflow; +} diff --git a/PWGJE/Tasks/hadronPhotonCorrelation.cxx b/PWGJE/Tasks/hadronPhotonCorrelation.cxx new file mode 100644 index 00000000000..4681a8d586f --- /dev/null +++ b/PWGJE/Tasks/hadronPhotonCorrelation.cxx @@ -0,0 +1,845 @@ +// 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 hadronPhotonCorrelation.cxx +/// \author Peter Stratmann +/// \brief This code loops over JetTracks to extract pt and angular information +/// for hadrons and photons to compute angular correlations +/// + +#include +#include +#include +#include + +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/Expressions.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramSpec.h" +#include "Framework/Configurable.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/Core/trackUtilities.h" +#include "CommonConstants/PhysicsConstants.h" +#include "CommonConstants/MathConstants.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/Core/JetUtilities.h" + +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; +using namespace o2::constants::math; + +struct HadronPhotonCorrelation { + + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + + Configurable etaMax{"etaMax", 0.8, "maximum eta cut"}; + + AxisSpec axisPhi = {72, 0., TwoPI, "#phi"}; // Axis for phi distribution + AxisSpec axisDeltaPhi = {72, -PIHalf, 3 * PIHalf, "#Delta #phi"}; // Axis for Delta phi in correlations + AxisSpec axisEta = {40, -.8, .8, "#eta"}; // Axis for eta distribution + AxisSpec axisDeltaEta = {80, -1.6, 1.6, "#Delta #eta"}; // Axis for Delta eta in correlations + ConfigurableAxis axisPtTrig = {"axisPtTrig", + {VARIABLE_WIDTH, + 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 9.0f, 11.0f, 15.0f, 20.0f}, + "p_{T, trig} [GeV]"}; // Axis for trigger particle pt distribution + ConfigurableAxis axisPtAssoc = {"axisPtAssoc", + {VARIABLE_WIDTH, + 0.2, 0.5, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 9.0f, 11.0f, 15.0f}, + "p_{T, assoc} [GeV]"}; // Axis for associated particle pt distribution + AxisSpec axisDeltaPt = {200, 0., 1.2, "#Delta p_T"}; // Axis for pt ratio between neutral hadrons and decay photons + AxisSpec axisPid = {9, -3.5, 5.5, "pid"}; // Axis for PID of neutral hadrons + AxisSpec axisMult = {100, 0., 99., "N_{ch}"}; // Axis for mutplipicity + AxisSpec axisAlpha = {100, 0., 1., "alpha"}; // Axis for decay photon pt assymetry + + AxisSpec axisDeltaRDecay = {100, 0., 0.8, "#Delta R"}; // Axis for Delta R = sqrt(Delta eta^2 + Delta phi^2) between neutral hadrons and decay photons + + float ptMinTrig; + float ptMaxTrig; + float ptMinAssoc; + float ptMaxAssoc; + + HistogramRegistry registry{"histogram registry"}; + + // Particle ids for storing neutral hadrons + std::map pidCodes = { + {"pi0", 1}, // pi0 + {"eta", 2}, // eta + {"eta'", 3}, // eta' + {"phi", 4}, // phi + {"omega", 5}}; // omega + + Service pdg; + + std::vector eventSelectionBits; + int trackSelection = -1; + + void init(o2::framework::InitContext&) + { + ptMinTrig = axisPtTrig->at(1); + ptMaxTrig = axisPtTrig->back(); + ptMinAssoc = axisPtAssoc->at(1); + ptMaxAssoc = axisPtAssoc->back(); + + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + + // Generated histograms + // Triggers + registry.add("generated/triggers/hTrigMultGen", "Generated Trigger Multiplicity", kTH1F, {axisMult}); + registry.add("generated/triggers/hTrigSpectrumGen", "Generated Trigger Spectrum", kTHnSparseF, {axisPtTrig, axisEta, axisPhi}); + + // Hadrons + registry.add("generated/hadrons/hHadronCorrelGen", "Generated Trigger-Hadron Correlation", kTHnSparseF, {axisPtTrig, axisPtAssoc, axisDeltaEta, axisDeltaPhi}); + registry.add("generated/hadrons/hHadronMultGen", "Generated Hadron Multiplicity", kTH1F, {axisMult}); + registry.add("generated/hadrons/hHadronSpectrumGen", "Generated Hadron Spectrum", kTHnSparseF, {axisPtAssoc, axisEta, axisPhi}); + + // Photons + registry.add("generated/photons/hPhotonCorrelGen", "Generated Trigger-Photon Correlation", kTHnSparseF, {axisPtTrig, axisPtAssoc, axisDeltaEta, axisDeltaPhi, axisPid}); + registry.add("generated/photons/hPhotonMultGen", "Generated Photon Multiplicity", kTH1F, {axisMult}); + registry.add("generated/photons/hPhotonSpectrumGen", "Generated Photon Spectrum", kTHnSparseF, {axisPtAssoc, axisEta, axisPhi, axisPid}); + + // Charged pions + registry.add("generated/charged/hPionCorrelGen", "Generated Trigger-Pion Correlation", kTHnSparseF, {axisPtTrig, axisPtAssoc, axisDeltaEta, axisDeltaPhi}); + registry.add("generated/charged/hPionMultGen", "Generated Pion Multiplicity", kTH1F, {axisMult}); + registry.add("generated/charged/hPionSpectrumGen", "Generated Pion Spectrum", kTHnSparseF, {axisPtAssoc, axisEta, axisPhi}); + + ////Neutral particles + registry.add("generated/neutral/hNeutralCorrelGen", "Generated Trigger-Neutral Hadron Correlation", kTHnSparseF, {axisPtTrig, axisPtAssoc, axisDeltaEta, axisDeltaPhi, axisPid}); + registry.add("generated/neutral/hNeutralMultGen", "Generated Neutral Hadron Multiplicity", kTH1F, {axisMult}); + registry.add("generated/neutral/hNeutralSpectrumGen", "Generated Neutral Hadron Spectrum", kTHnSparseF, {axisPtAssoc, axisEta, axisPhi, axisPid}); // Particle ID of neutral hadrons + registry.add("generated/neutral/hNeutralDecayGen", "Generated Neutral Hadron-Decay Photon Correlation", kTHnSparseF, {axisPtAssoc, axisDeltaPt, axisDeltaRDecay, axisAlpha, axisPid}); // Correlation with decay photons + + // Reconstructed histograms + // Triggers + registry.add("reconstructed/triggers/hTrigMultReco", "Reconstructed Trigger Multiplicity", kTH1F, {axisMult}); + registry.add("reconstructed/triggers/hTrigSpectrumReco", "Reconstructed Trigger Spectrum", kTHnSparseF, {axisPtTrig, axisEta, axisPhi}); + + // Hadrons + registry.add("reconstructed/hadrons/hHadronCorrelReco", "Reconstructed Trigger-Hadron Correlation", kTHnSparseF, {axisPtTrig, axisPtAssoc, axisDeltaEta, axisDeltaPhi}); + registry.add("reconstructed/hadrons/hHadronMultReco", "Reconstructed Hadron Multiplicity", kTH1F, {axisMult}); + registry.add("reconstructed/hadrons/hHadronSpectrumReco", "Reconstructed Hadron Spectrum", kTHnSparseF, {axisPtAssoc, axisEta, axisPhi}); + registry.add("reconstructed/hadrons/hHadronPtPrimReco", "Reconstructed Primaries Spectrum", kTH1F, {axisPtAssoc}); // Primary hadron spectrum + registry.add("reconstructed/hadrons/hHadronPtSecReco", "Reconstructed Secondaries Spectrum", kTH1F, {axisPtAssoc}); // Secondary hadron spectrum + + // Photons + registry.add("reconstructed/photons/hPhotonCorrelReco", "Reconstructed Trigger-Photon Correlation", kTHnSparseF, {axisPtTrig, axisPtAssoc, axisDeltaEta, axisDeltaPhi}); + registry.add("reconstructed/photons/hPhotonMultReco", "Reconstructed Photon Multiplicity", kTH1F, {axisMult}); + registry.add("reconstructed/photons/hPhotonSpectrumReco", "Reconstructed Photon Spectrum", kTHnSparseF, {axisPtAssoc, axisEta, axisPhi}); + + // Charged Pions + registry.add("reconstructed/charged/hPionCorrelReco", "Reconstructed Trigger-Pion Correlation", kTHnSparseF, {axisPtTrig, axisPtAssoc, axisDeltaEta, axisDeltaPhi}); + registry.add("reconstructed/charged/hPionMultReco", "Reconstructed Pion Multiplicity", kTH1F, {axisMult}); + registry.add("reconstructed/charged/hPionSpectrumReco", "Reconstructed Pion Spectrum", kTHnSparseF, {axisPtAssoc, axisEta, axisPhi}); + } + + // To check if object has has_mcParticle() (i.e. is MC Track or data track) + template + struct HasHasMcParticle { + template + static auto test(U* ptr) -> decltype(ptr->has_mcParticle(), std::true_type{}); + static std::false_type test(...); + static constexpr bool Value = decltype(test(std::declval()))::value; + }; + + // Initialize track + template + bool initTrack(const T& track) + { + + // if constexpr (HasHasMcParticle) { + if constexpr (HasHasMcParticle::Value) { + if (!track.has_mcParticle()) { + return false; + } + } + + if (std::abs(track.eta()) > etaMax) { + return false; + } + + if (track.pt() < ptMinAssoc || track.pt() > ptMaxAssoc) { + return false; + } + + return true; + } + + // Initialize particle + template + bool initParticle(const T& particle, bool checkIsPrimary = true) + { + + if (checkIsPrimary && !particle.isPhysicalPrimary()) { + return false; + } + + if (std::abs(particle.eta()) > etaMax) { + return false; + } + + if (particle.pt() < ptMinAssoc || particle.pt() > ptMaxAssoc) { + return false; + } + + return true; + } + + // Initialize trigger tracks + template + bool initTrig(const T& track) + { + // if constexpr (HasHasMcParticle) { + if constexpr (HasHasMcParticle::Value) { + if (!track.has_mcParticle()) { + return false; + } + } + + if (std::abs(track.eta()) > etaMax) { + return false; + } + + if (track.pt() < ptMinTrig || track.pt() > ptMaxTrig) { + return false; + } + + return true; + } + + // Initialize trigger particles (charged) + template + bool initTrigParticle(const T& particle) + { + if (!particle.isPhysicalPrimary()) { + return false; + } + + auto pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (!pdgParticle || pdgParticle->Charge() == 0.) { + return false; + } + + if (std::abs(particle.eta()) > etaMax) { + return false; + } + + if (particle.pt() < ptMinTrig || particle.pt() > ptMaxTrig) { + return false; + } + + return true; + } + + // Initialize V0s + template + bool initV0(TV0 const& v0) + { + auto pos = v0.template posTrack_as(); + auto neg = v0.template negTrack_as(); + if (!initV0leg(pos) || !initV0leg(neg)) { + return false; + } + + return true; + } + + template + bool initV0leg(TTrack const& track) + { + if (!initTrack(track)) { + return false; + } + + if (!track.hasTPC()) { + return false; + } + + if (track.tpcNClsCrossedRows() < 70) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < 0.8) { + return false; + } + + return true; + } + + /**************************************************************************************************** + ************************************************ TRIGGER ******************************************** + ****************************************************************************************************/ + + /********************************************** DATA ***********************************************/ + + void processTrigsReco(JetCollision const& collision, + JetTracks const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + + int nTrigs = 0; + for (const auto& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + + if (!initTrig(track)) { + continue; + } + + registry.fill(HIST("reconstructed/triggers/hTrigSpectrumReco"), track.pt(), track.eta(), track.phi()); + nTrigs++; + } + registry.fill(HIST("reconstructed/triggers/hTrigMultReco"), nTrigs); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processTrigsReco, "trigger particle properties", true); + + /*********************************************** MC ************************************************/ + + void processTrigsMCReco(JetCollision const& collision, + Join const& tracks, + JetParticles const&) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + + int nTrigs = 0; + for (const auto& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + + if (!initTrig(track)) { + continue; + } + registry.fill(HIST("reconstructed/triggers/hTrigSpectrumReco"), track.pt(), track.eta(), track.phi()); + nTrigs++; + } + registry.fill(HIST("reconstructed/triggers/hTrigMultReco"), nTrigs); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processTrigsMCReco, "trigger particle mc properties", true); + + void processTrigsMCGen(JetMcCollision const&, + JetParticles const& particles) + { + + int nTrigs = 0; + for (const auto& particle : particles) { + if (!initTrigParticle(particle)) { + continue; + } + registry.fill(HIST("generated/triggers/hTrigSpectrumGen"), particle.pt(), particle.eta(), particle.phi()); + nTrigs++; + } + registry.fill(HIST("generated/triggers/hTrigMultGen"), nTrigs); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processTrigsMCGen, "trigger particle mc properties", true); + + /**************************************************************************************************** + ********************************************** PHOTONS ********************************************** + ****************************************************************************************************/ + + /********************************************** DATA ***********************************************/ + using MyTracks = soa::Join; + Preslice perCol = aod::v0::collisionId; + void processPhotonCorrelations(JetCollision const& collision, + JetTracks const& tracks, + MyTracks const&, + V0Datas const& v0s) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + + int nPhotons = 0; + auto v0PerCollision = v0s.sliceBy(perCol, collision.globalIndex()); + for (const auto& v0 : v0PerCollision) { + if (!initV0(v0)) { + continue; + } + registry.fill(HIST("reconstructed/photons/hPhotonSpectrumReco"), v0.pt(), v0.eta(), v0.phi()); + nPhotons++; + + for (const auto& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + + if (!initTrig(track)) { + continue; + } + float dphi = RecoDecay::constrainAngle(track.phi() - v0.phi(), -PIHalf); + registry.fill(HIST("reconstructed/photons/hPhotonCorrelReco"), track.pt(), v0.pt(), track.eta() - v0.eta(), dphi); + } + } + registry.fill(HIST("reconstructed/photons/hPhotonMultReco"), nPhotons); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processPhotonCorrelations, "hadron-photon correlation", true); + + /*********************************************** MC ************************************************/ + + using MyTracksMC = soa::Join; + void processPhotonCorrelationsMCReco(Join::iterator const& collision_reco, + JetMcCollisions const&, + JetTracks const& tracks_reco, + JetParticles const&, + MyTracksMC const&, + V0Datas const& v0s) + { + if (!jetderiveddatautilities::selectCollision(collision_reco, eventSelectionBits)) { + return; + } + + int nPhotons = 0; + + auto v0PerCollision = v0s.sliceBy(perCol, collision_reco.globalIndex()); + for (const auto& v0 : v0PerCollision) { + if (!initV0(v0)) { + continue; + } + registry.fill(HIST("reconstructed/photons/hPhotonSpectrumReco"), v0.pt(), v0.eta(), v0.phi()); + nPhotons++; + + for (const auto& track : tracks_reco) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + + if (!initTrig(track)) { + continue; + } + float dphi = RecoDecay::constrainAngle(track.phi() - v0.phi(), -PIHalf); + registry.fill(HIST("reconstructed/photons/hPhotonCorrelReco"), track.pt(), v0.pt(), track.eta() - v0.eta(), dphi); + } + } + registry.fill(HIST("reconstructed/photons/hPhotonMultReco"), nPhotons); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processPhotonCorrelationsMCReco, "hadron-photon correlation", true); + + void processPhotonCorrelationsMCGen(JetMcCollision const&, + JetParticles const& tracks_true) + { + int nPhotons = 0; + for (const auto& track_assoc : tracks_true) { + if (!initParticle(track_assoc, false)) { + continue; + } + if ((PDG_t)std::abs(track_assoc.pdgCode()) != kGamma) { + continue; + } + if (!track_assoc.isPhysicalPrimary() && track_assoc.getGenStatusCode() < 0) { + continue; + } + + // Iterate through mother particles until original mother is reached + auto origPhoton = track_assoc; + auto mother = track_assoc.mothers_as().at(0); + while ((PDG_t)mother.pdgCode() == kGamma) { + origPhoton = mother; + mother = mother.mothers_as().at(0); + } + + auto pdgMother = pdg->GetParticle(mother.pdgCode()); + if (!pdgMother) + continue; + int photonGeneration; + switch (std::abs(origPhoton.getGenStatusCode())) { + case 23: // prompt direct photons + case 33: + photonGeneration = -2; + break; + case 43: // shower photons + case 44: + case 51: + case 52: + photonGeneration = -1; + break; + case 91: // decay photons + photonGeneration = pidCodes[pdgMother->GetName()]; + break; + default: + photonGeneration = -3; + break; + } + + registry.fill(HIST("generated/photons/hPhotonSpectrumGen"), track_assoc.pt(), track_assoc.eta(), track_assoc.phi(), photonGeneration); + + nPhotons++; + + for (const auto& track_trig : tracks_true) { + if (!initTrigParticle(track_trig)) { + continue; + } + if (!initParticle(track_assoc)) { + continue; + } + float dphi = RecoDecay::constrainAngle(track_trig.phi() - track_assoc.phi(), -PIHalf); + registry.fill(HIST("generated/photons/hPhotonCorrelGen"), track_trig.pt(), track_assoc.pt(), track_trig.eta() - track_assoc.eta(), dphi, photonGeneration); + } + } + + registry.fill(HIST("generated/photons/hPhotonMultGen"), nPhotons); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processPhotonCorrelationsMCGen, "mc hadron-photon correlation", true); + + /**************************************************************************************************** + ***************************************** HADRONS *************************************************** + ****************************************************************************************************/ + + /********************************************** DATA ***********************************************/ + void processHadronCorrelations(JetCollision const& collision, + Join const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + + int nHadrons = 0; + for (const auto& track_assoc : tracks) { + if (!jetderiveddatautilities::selectTrack(track_assoc, trackSelection)) { + continue; + } + + if (!initTrack(track_assoc)) { + continue; + } + registry.fill(HIST("reconstructed/hadrons/hHadronSpectrumReco"), track_assoc.pt(), track_assoc.eta(), track_assoc.phi()); + nHadrons++; + + for (const auto& track_trig : tracks) { + if (!jetderiveddatautilities::selectTrack(track_trig, trackSelection)) { + continue; + } + if (track_trig == track_assoc) { + continue; + } + if (!initTrig(track_trig)) { + continue; + } + float dphi = RecoDecay::constrainAngle(track_trig.phi() - track_assoc.phi(), -PIHalf); + registry.fill(HIST("reconstructed/hadrons/hadrons/hHadronCorrelReco"), track_trig.pt(), track_assoc.pt(), track_trig.eta() - track_assoc.eta(), dphi); + } + } + registry.fill(HIST("reconstructed/hadrons/hHadronMultReco"), nHadrons); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processHadronCorrelations, "hadron-hadron correlation", true); + + /*********************************************** MC ************************************************/ + + void processHadronCorrelationsMCGen(JetMcCollision const&, + JetParticles const& tracks_true) + { + int nHadrons = 0; + for (const auto& track_assoc : tracks_true) { + if (!initParticle(track_assoc)) { + continue; + } + auto pdgParticle = pdg->GetParticle(track_assoc.pdgCode()); + if (!pdgParticle || pdgParticle->Charge() == 0.) { + continue; + } + if (std::abs(track_assoc.pdgCode()) < 100) { + continue; + } + + registry.fill(HIST("generated/hadrons/hHadronSpectrumGen"), track_assoc.pt(), track_assoc.eta(), track_assoc.phi()); + nHadrons++; + + for (const auto& track_trig : tracks_true) { + if (!initTrigParticle(track_trig)) { + continue; + } + if (track_trig == track_assoc) { + continue; + } + float dphi = RecoDecay::constrainAngle(track_trig.phi() - track_assoc.phi(), -PIHalf); + + registry.fill(HIST("generated/hadrons/hHadronCorrelGen"), track_trig.pt(), track_assoc.pt(), track_trig.eta() - track_assoc.eta(), dphi); + } + } + registry.fill(HIST("generated/hadrons/hHadronMultGen"), nHadrons); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processHadronCorrelationsMCGen, "mc hadron-hadron correlation", true); + + void processHadronCorrelationsMCReco(Join::iterator const& collision_reco, + JetMcCollisions const&, + Join const& tracks_reco, + JetParticles const&) + { + if (!jetderiveddatautilities::selectCollision(collision_reco, eventSelectionBits)) { + return; + } + + int nHadrons = 0; + for (const auto& track_assoc : tracks_reco) { + if (!jetderiveddatautilities::selectTrack(track_assoc, trackSelection)) { + continue; + } + + if (!initTrack(track_assoc)) { + continue; + } + auto particle = track_assoc.mcParticle(); + auto pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (!pdgParticle || pdgParticle->Charge() == 0.) { + continue; + } + if (std::abs(particle.pdgCode()) < 100) { + continue; + } + + registry.fill(HIST("reconstructed/hadrons/hHadronSpectrumReco"), track_assoc.pt(), track_assoc.eta(), track_assoc.phi()); + + if (particle.isPhysicalPrimary()) { + registry.fill(HIST("reconstructed/hadrons/hHadronPtPrimReco"), track_assoc.pt()); + } else { + registry.fill(HIST("reconstructed/hadrons/hHadronPtSecReco"), track_assoc.pt()); + } + nHadrons++; + + for (const auto& track_trig : tracks_reco) { + if (!jetderiveddatautilities::selectTrack(track_trig, trackSelection)) { + continue; + } + if (track_trig == track_assoc) { + continue; + } + if (!initTrig(track_trig)) { + continue; + } + float dphi = RecoDecay::constrainAngle(track_trig.phi() - track_assoc.phi(), -PIHalf); + + registry.fill(HIST("reconstructed/hadrons/hHadronCorrelReco"), track_trig.pt(), track_assoc.pt(), track_trig.eta() - track_assoc.eta(), dphi); + } + } + registry.fill(HIST("reconstructed/hadrons/hHadronMultReco"), nHadrons); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processHadronCorrelationsMCReco, "mc hadron-hadron correlation", true); + + /**************************************************************************************************** + *************************************** CHARGED PIONS *********************************************** + ****************************************************************************************************/ + + /********************************************** DATA ***********************************************/ + void processPionCorrelations(JetCollision const& collision, + Join const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + + int nPions = 0; + for (const auto& track_assoc : tracks) { + if (!jetderiveddatautilities::selectTrack(track_assoc, trackSelection)) { + continue; + } + + if (!initTrack(track_assoc)) { + continue; + } + if (std::abs(track_assoc.tpcNSigmaPi()) > 2) { + continue; + } // remove non-pions + registry.fill(HIST("reconstructed/charged/hPionSpectrumReco"), track_assoc.pt(), track_assoc.eta(), track_assoc.phi()); + nPions++; + + for (const auto& track_trig : tracks) { + if (!jetderiveddatautilities::selectTrack(track_trig, trackSelection)) { + continue; + } + if (track_trig == track_assoc) { + continue; + } + if (!initTrig(track_trig)) { + continue; + } + float dphi = RecoDecay::constrainAngle(track_trig.phi() - track_assoc.phi(), -PIHalf); + registry.fill(HIST("reconstructed/charged/hPionCorrelReco"), track_trig.pt(), track_assoc.pt(), track_trig.eta() - track_assoc.eta(), dphi); + } + } + registry.fill(HIST("reconstructed/charged/hPionMultReco"), nPions); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processPionCorrelations, "hadron-pion correlation", true); + + /*********************************************** MC ************************************************/ + + void processPionCorrelationsMCGen(JetMcCollision const&, + JetParticles const& tracks_true) + { + int nPions = 0; + for (const auto& track_assoc : tracks_true) { + if (!initParticle(track_assoc)) { + continue; + } + if ((PDG_t)std::abs(track_assoc.pdgCode()) != kPiPlus) { + continue; + } + + registry.fill(HIST("generated/charged/hPionSpectrumGen"), track_assoc.pt(), track_assoc.eta(), track_assoc.phi()); + nPions++; + + for (const auto& track_trig : tracks_true) { + if (!initTrigParticle(track_trig)) { + continue; + } + if (track_trig == track_assoc) { + continue; + } + float dphi = RecoDecay::constrainAngle(track_trig.phi() - track_assoc.phi(), -PIHalf); + + registry.fill(HIST("generated/charged/hPionCorrelGen"), track_trig.pt(), track_assoc.pt(), track_trig.eta() - track_assoc.eta(), dphi); + } + } + registry.fill(HIST("generated/charged/hPionMultGen"), nPions); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processPionCorrelationsMCGen, "mc hadron-pion correlation", true); + + void processPionCorrelationsMCReco(Join::iterator const& collision_reco, + JetMcCollisions const&, + Join const& tracks_reco, + JetParticles const&) + { + if (!jetderiveddatautilities::selectCollision(collision_reco, eventSelectionBits)) { + return; + } + + int nPions = 0; + for (const auto& track_assoc : tracks_reco) { + if (!jetderiveddatautilities::selectTrack(track_assoc, trackSelection)) { + continue; + } + + if (!initTrack(track_assoc)) { + continue; + } + if ((PDG_t)std::abs(track_assoc.mcParticle().pdgCode()) != kPiPlus) { + continue; + } + + registry.fill(HIST("reconstructed/charged/hPionSpectrumReco"), track_assoc.pt(), track_assoc.eta(), track_assoc.phi()); + nPions++; + + for (const auto& track_trig : tracks_reco) { + if (!jetderiveddatautilities::selectTrack(track_trig, trackSelection)) { + continue; + } + if (track_trig == track_assoc) { + continue; + } + + if (!initTrig(track_trig)) { + continue; + } + float dphi = RecoDecay::constrainAngle(track_trig.phi() - track_assoc.phi(), -PIHalf); + registry.fill(HIST("reconstructed/charged/hPionCorrelReco"), track_trig.pt(), track_assoc.pt(), track_trig.eta() - track_assoc.eta(), dphi); + } + } + registry.fill(HIST("reconstructed/charged/hPionMultReco"), nPions); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processPionCorrelationsMCReco, "mc hadron-pion correlation", true); + + /**************************************************************************************************** + ****************************************** NEUTRALS ************************************************* + ****************************************************************************************************/ + + /*********************************************** MC ************************************************/ + + void processNeutralCorrelationsMCGen(JetMcCollision const&, + JetParticles const& tracks_true) + { + int nNeutrals = 0; + for (const auto& track_assoc : tracks_true) { + if (!initParticle(track_assoc, false)) { + continue; + } + auto pdgParticle = pdg->GetParticle(track_assoc.pdgCode()); + if (!pdgParticle) { + continue; + } // remove unknown particles + if (pdgParticle->Charge() != 0.) { + continue; + } // remove charged particles + if (track_assoc.pdgCode() < 100 || (PDG_t)track_assoc.pdgCode() == kNeutron) { + continue; + } // remove non-hadrons and neutrons + registry.fill(HIST("generated/neutral/hNeutralSpectrumGen"), track_assoc.pt(), track_assoc.eta(), track_assoc.phi(), pidCodes[pdgParticle->GetName()]); + nNeutrals++; + + // Get correlations between neutral hadrons and their respective decay photons + auto daughters = track_assoc.daughters_as(); + double alpha = -1; + if (daughters.size() == 2) { + auto daughter = daughters.begin(); + double pt1 = daughter.pt(); + ++daughter; + double pt2 = daughter.pt(); + alpha = std::abs((pt1 - pt2) / (pt1 + pt2)); + } + + for (const auto& daughter : daughters) { + if ((PDG_t)std::abs(daughter.pdgCode()) != kGamma) + continue; + if (!initParticle(daughter, false)) + continue; + if (!daughter.isPhysicalPrimary() && daughter.getGenStatusCode() == -1) + continue; + double deltaPt = daughter.pt() / track_assoc.pt(); + double deltaEta = daughter.eta() - track_assoc.eta(); + double deltaPhi = RecoDecay::constrainAngle(daughter.phi() - track_assoc.phi(), -PIHalf); + double deltaR = std::sqrt(deltaEta * deltaEta + deltaPhi * deltaPhi); + + registry.fill(HIST("generated/neutral/hNeutralDecayGen"), track_assoc.pt(), deltaPt, deltaR, alpha, pidCodes[pdgParticle->GetName()]); + } + + // Get correlations between triggers and neutral hadrons + for (const auto& track_trig : tracks_true) { + if (!initTrigParticle(track_trig)) { + continue; + } + float dphi = RecoDecay::constrainAngle(track_assoc.phi() - track_trig.phi(), -PIHalf); + registry.fill(HIST("generated/neutral/hNeutralCorrelGen"), track_trig.pt(), track_assoc.pt(), track_assoc.eta() - track_trig.eta(), dphi, pidCodes[pdgParticle->GetName()]); + } + } + registry.fill(HIST("generated/neutral/hNeutralMultGen"), nNeutrals); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processNeutralCorrelationsMCGen, "mc hadron-pion correlation", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +}; diff --git a/PWGJE/Tasks/hfFragmentationFunction.cxx b/PWGJE/Tasks/hfFragmentationFunction.cxx new file mode 100644 index 00000000000..667baf91bf0 --- /dev/null +++ b/PWGJE/Tasks/hfFragmentationFunction.cxx @@ -0,0 +1,463 @@ +// Copyright 2019-2024 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 hfFragmentationFunction.cxx +/// \brief charm hadron hadronization task +/// \author Christian Reckziegel , Federal University of ABC +/// \since 15.03.2024 +/// +/// The task store data relevant to the calculation of hadronization observables radial +/// profile and/or jet momentum fraction for charmed hadrons +#include +#include + +#include "TVector3.h" + +#include "fastjet/PseudoJet.hh" +#include "fastjet/ClusterSequenceArea.hh" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/runDataProcessing.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetHFUtilities.h" +#include "PWGJE/Core/JetUtilities.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// calculate delta phi such that 0 < delta phi < pi +double deltaPhi(double phi1, double phi2) +{ + // Compute the absolute difference between phi1 and phi2 + double dphi = std::abs(phi1 - phi2); + + // Constrain angle between [min,min+2pi] = [-pi,-pi+2pi] + dphi = RecoDecay::constrainAngle(dphi, -o2::constants::math::PI); + + // Return absolute value of distance + return std::abs(dphi); +} + +// creating table for storing distance data +namespace o2::aod +{ +namespace jet_distance +{ +DECLARE_SOA_COLUMN(JetHfDist, jetHfDist, float); +DECLARE_SOA_COLUMN(JetPt, jetPt, float); +DECLARE_SOA_COLUMN(JetEta, jetEta, float); +DECLARE_SOA_COLUMN(JetPhi, jetPhi, float); +DECLARE_SOA_COLUMN(JetNConst, jetNConst, int); +DECLARE_SOA_COLUMN(HfPt, hfPt, float); +DECLARE_SOA_COLUMN(HfEta, hfEta, float); +DECLARE_SOA_COLUMN(HfPhi, hfPhi, float); +DECLARE_SOA_COLUMN(HfMass, hfMass, float); +DECLARE_SOA_COLUMN(HfY, hfY, float); +DECLARE_SOA_COLUMN(HfPrompt, hfPrompt, bool); +DECLARE_SOA_COLUMN(HfMatch, hfMatch, bool); +DECLARE_SOA_COLUMN(HfMlScore0, hfMlScore0, float); +DECLARE_SOA_COLUMN(HfMlScore1, hfMlScore1, float); +DECLARE_SOA_COLUMN(HfMlScore2, hfMlScore2, float); +DECLARE_SOA_COLUMN(HfMatchedFrom, hfMatchedFrom, int); +DECLARE_SOA_COLUMN(HfSelectedAs, hfSelectedAs, int); +DECLARE_SOA_COLUMN(McJetHfDist, mcJetHfDist, float); +DECLARE_SOA_COLUMN(McJetPt, mcJetPt, float); +DECLARE_SOA_COLUMN(McJetEta, mcJetEta, float); +DECLARE_SOA_COLUMN(McJetPhi, mcJetPhi, float); +DECLARE_SOA_COLUMN(McJetNConst, mcJetNConst, float); +DECLARE_SOA_COLUMN(McHfPt, mcHfPt, float); +DECLARE_SOA_COLUMN(McHfEta, mcHfEta, float); +DECLARE_SOA_COLUMN(McHfPhi, mcHfPhi, float); +DECLARE_SOA_COLUMN(McHfY, mcHfY, float); +DECLARE_SOA_COLUMN(McHfPrompt, mcHfPrompt, bool); +DECLARE_SOA_COLUMN(McHfMatch, mcHfMatch, bool); +} // namespace jet_distance +DECLARE_SOA_TABLE(JetDistanceTable, "AOD", "JETDISTTABLE", + jet_distance::JetHfDist, + jet_distance::JetPt, + jet_distance::JetEta, + jet_distance::JetPhi, + jet_distance::JetNConst, + jet_distance::HfPt, + jet_distance::HfEta, + jet_distance::HfPhi, + jet_distance::HfMass, + jet_distance::HfY, + jet_distance::HfMlScore0, + jet_distance::HfMlScore1, + jet_distance::HfMlScore2); +DECLARE_SOA_TABLE(MCPJetDistanceTable, "AOD", "MCPJETDISTTABLE", + jet_distance::McJetHfDist, + jet_distance::McJetPt, + jet_distance::McJetEta, + jet_distance::McJetPhi, + jet_distance::McJetNConst, + jet_distance::McHfPt, + jet_distance::McHfEta, + jet_distance::McHfPhi, + jet_distance::McHfY, + jet_distance::McHfPrompt, + jet_distance::McHfMatch); +DECLARE_SOA_TABLE(MCDJetDistanceTable, "AOD", "MCDJETDISTTABLE", + jet_distance::JetHfDist, + jet_distance::JetPt, + jet_distance::JetEta, + jet_distance::JetPhi, + jet_distance::JetNConst, + jet_distance::HfPt, + jet_distance::HfEta, + jet_distance::HfPhi, + jet_distance::HfMass, + jet_distance::HfY, + jet_distance::HfPrompt, + jet_distance::HfMatch, + jet_distance::HfMlScore0, + jet_distance::HfMlScore1, + jet_distance::HfMlScore2, + jet_distance::HfMatchedFrom, + jet_distance::HfSelectedAs); +DECLARE_SOA_TABLE(MatchJetDistanceTable, "AOD", "MATCHTABLE", + jet_distance::McJetHfDist, + jet_distance::McJetPt, + jet_distance::McJetEta, + jet_distance::McJetPhi, + jet_distance::McJetNConst, + jet_distance::McHfPt, + jet_distance::McHfEta, + jet_distance::McHfPhi, + jet_distance::McHfY, + jet_distance::McHfPrompt, + jet_distance::JetHfDist, + jet_distance::JetPt, + jet_distance::JetEta, + jet_distance::JetPhi, + jet_distance::JetNConst, + jet_distance::HfPt, + jet_distance::HfEta, + jet_distance::HfPhi, + jet_distance::HfMass, + jet_distance::HfY, + jet_distance::HfPrompt, + jet_distance::HfMlScore0, + jet_distance::HfMlScore1, + jet_distance::HfMlScore2, + jet_distance::HfMatchedFrom, + jet_distance::HfSelectedAs); +} // namespace o2::aod + +struct HfFragmentationFunction { + // producing new table + Produces distJetTable; + Produces mcpdistJetTable; + Produces mcddistJetTable; + Produces matchJetTable; + + // Tables for MC jet matching + using JetMCDTable = soa::Join; + using JetMCPTable = soa::Join; + + // slices for accessing proper HF mcdjets collision associated to mccollisions + PresliceUnsorted collisionsPerMCCollisionPreslice = aod::jmccollisionlb::mcCollisionId; + Preslice d0MCDJetsPerCollisionPreslice = aod::jet::collisionId; + Preslice d0MCPJetsPerMCCollisionPreslice = aod::jet::mcCollisionId; + + // Histogram registry: an object to hold your histograms + HistogramRegistry registry{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + + std::vector eventSelectionBits; + + void init(InitContext const&) + { + // initialise event selection: + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + + // create histograms + // collision system histograms + std::vector histLabels = {"mccollisions", "z_cut", "collisions", "sel8"}; + registry.add("h_collision_counter", ";# of collisions;", HistType::kTH1F, {{static_cast(histLabels.size()), 0.0, static_cast(histLabels.size())}}); + auto counter = registry.get(HIST("h_collision_counter")); + for (std::vector::size_type iCounter = 0; iCounter < histLabels.size(); iCounter++) { + counter->GetXaxis()->SetBinLabel(iCounter + 1, histLabels[iCounter].data()); + } + registry.add("h_jet_counter", ";# of jets;", {HistType::kTH1F, {{6, 0., 3.0}}}); + auto jetCounter = registry.get(HIST("h_jet_counter")); + jetCounter->GetXaxis()->SetBinLabel(1, "particle level"); + jetCounter->GetXaxis()->SetBinLabel(2, "detector level"); + jetCounter->GetXaxis()->SetBinLabel(3, "particle matched jets"); + jetCounter->GetXaxis()->SetBinLabel(4, "detector matched jets"); + jetCounter->GetXaxis()->SetBinLabel(5, "mcd matched to mcp loop"); + jetCounter->GetXaxis()->SetBinLabel(6, "mcp matched to mcd loop"); + // D0 candidate histograms from data + registry.add("h_d0_jet_projection", ";z^{D^{0},jet}_{||};dN/dz^{D^{0},jet}_{||}", {HistType::kTH1F, {{1000, 0., 10.}}}); + registry.add("h_d0_jet_distance_vs_projection", ";#DeltaR_{D^{0},jet};z^{D^{0},jet}_{||}", {HistType::kTH2F, {{1000, 0., 10.}, {1000, 0., 10.}}}); + registry.add("h_d0_jet_distance", ";#DeltaR_{D^{0},jet};dN/d(#DeltaR)", {HistType::kTH1F, {{1000, 0., 10.}}}); + registry.add("h_d0_jet_pt", ";p_{T,D^{0} jet};dN/dp_{T,D^{0} jet}", {HistType::kTH1F, {{200, 0., 10.}}}); + registry.add("h_d0_jet_eta", ";#eta_{T,D^{0} jet};dN/d#eta_{D^{0} jet}", {HistType::kTH1F, {{250, -5., 5.}}}); + registry.add("h_d0_jet_phi", ";#phi_{T,D^{0} jet};dN/d#phi_{D^{0} jet}", {HistType::kTH1F, {{250, -10., 10.}}}); + registry.add("h_d0_mass", ";m_{D^{0}} (GeV/c^{2});dN/dm_{D^{0}}", {HistType::kTH1F, {{1000, 0., 10.}}}); + registry.add("h_d0_eta", ";#eta_{D^{0}} (GeV/c^{2});dN/d#eta_{D^{0}}", {HistType::kTH1F, {{250, -5., 5.}}}); + registry.add("h_d0_phi", ";#phi_{D^{0}} (GeV/c^{2});dN/d#phi_{D^{0}}", {HistType::kTH1F, {{250, -10., 10.}}}); + } + + void processDummy(aod::TracksIU const&) {} + PROCESS_SWITCH(HfFragmentationFunction, processDummy, "Dummy process function turned on by default", true); + + void processDataChargedSubstructure(aod::JetCollision const& collision, + soa::Join const& jets, + aod::CandidatesD0Data const&, + aod::JetTracks const&) + { + // apply event selection and fill histograms for sanity check + registry.fill(HIST("h_collision_counter"), 2.0); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || !(std::abs(collision.posZ()) < vertexZCut)) { + return; + } + registry.fill(HIST("h_collision_counter"), 3.0); + + for (const auto& jet : jets) { + // fill jet counter histogram + registry.fill(HIST("h_jet_counter"), 0.5); + // obtaining jet 3-vector + TVector3 jetVector(jet.px(), jet.py(), jet.pz()); + + for (const auto& d0Candidate : jet.candidates_as()) { + + // obtaining jet 3-vector + TVector3 d0Vector(d0Candidate.px(), d0Candidate.py(), d0Candidate.pz()); + + // calculating fraction of the jet momentum carried by the D0 along the direction of the jet axis + double zParallel = (jetVector * d0Vector) / (jetVector * jetVector); + + // calculating angular distance in eta-phi plane + double axisDistance = jetutilities::deltaR(jet, d0Candidate); + + // filling histograms + registry.fill(HIST("h_d0_jet_projection"), zParallel); + registry.fill(HIST("h_d0_jet_distance_vs_projection"), axisDistance, zParallel); + registry.fill(HIST("h_d0_jet_distance"), axisDistance); + registry.fill(HIST("h_d0_jet_pt"), jet.pt()); + registry.fill(HIST("h_d0_jet_eta"), jet.eta()); + registry.fill(HIST("h_d0_jet_phi"), jet.phi()); + registry.fill(HIST("h_d0_mass"), d0Candidate.m()); + registry.fill(HIST("h_d0_eta"), d0Candidate.eta()); + registry.fill(HIST("h_d0_phi"), d0Candidate.phi()); + + // filling table + distJetTable(axisDistance, + jet.pt(), jet.eta(), jet.phi(), jet.tracks_as().size(), + d0Candidate.pt(), d0Candidate.eta(), d0Candidate.phi(), d0Candidate.m(), d0Candidate.y(), d0Candidate.mlScores()[0], d0Candidate.mlScores()[1], d0Candidate.mlScores()[2]); + + break; // get out of candidates' loop after first HF particle is found in jet + } // end of D0 candidates loop + + } // end of jets loop + + } // end of process function + PROCESS_SWITCH(HfFragmentationFunction, processDataChargedSubstructure, "charged HF jet substructure", false); + + void processMcEfficiency(aod::JetMcCollisions const& mccollisions, + aod::JetCollisionsMCD const& collisions, + JetMCDTable const& mcdjets, + JetMCPTable const& mcpjets, + aod::CandidatesD0MCD const&, + aod::CandidatesD0MCP const&, + aod::JetTracks const&, + aod::JetParticles const&) + { + for (const auto& mccollision : mccollisions) { + + registry.fill(HIST("h_collision_counter"), 0.0); + // skip collisions outside of |z| < vertexZCut + if (std::abs(mccollision.posZ()) > vertexZCut) { + continue; + } + registry.fill(HIST("h_collision_counter"), 1.0); + + // reconstructed collisions associated to same mccollision + const auto collisionsPerMCCollision = collisions.sliceBy(collisionsPerMCCollisionPreslice, mccollision.globalIndex()); + for (const auto& collision : collisionsPerMCCollision) { + + registry.fill(HIST("h_collision_counter"), 2.0); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || !(std::abs(collision.posZ()) < vertexZCut)) { + continue; + } + registry.fill(HIST("h_collision_counter"), 3.0); + + // d0 detector level jets associated to the current same collision + const auto d0mcdJetsPerCollision = mcdjets.sliceBy(d0MCDJetsPerCollisionPreslice, collision.globalIndex()); + for (const auto& mcdjet : d0mcdJetsPerCollision) { + + registry.fill(HIST("h_jet_counter"), 0.5); + + // obtain leading HF candidate in jet + auto mcdd0cand = mcdjet.candidates_first_as(); + + if (mcdjet.has_matchedJetCand()) { + registry.fill(HIST("h_jet_counter"), 1.5); + } + + // reflection information for storage: D0 = +1, D0bar = -1, neither = 0 + int matchedFrom = 0; + int decayChannel = 1 << aod::hf_cand_2prong::DecayType::D0ToPiK; + int selectedAs = 0; + + if (mcdd0cand.flagMcMatchRec() == decayChannel) { // matched to D0 on truth level + matchedFrom = 1; + } else if (mcdd0cand.flagMcMatchRec() == -decayChannel) { // matched to D0bar on truth level + matchedFrom = -1; + } + // bitwise AND operation: Checks whether BIT(i) is set, regardless of other bits + if (mcdd0cand.candidateSelFlag() & BIT(0)) { // CandidateSelFlag == BIT(0) -> selected as D0 + selectedAs = 1; + } else if (mcdd0cand.candidateSelFlag() & BIT(1)) { // CandidateSelFlag == BIT(1) -> selected as D0bar + selectedAs = -1; + } + + // store data in MC detector level table + mcddistJetTable(jetutilities::deltaR(mcdjet, mcdd0cand), + mcdjet.pt(), mcdjet.eta(), mcdjet.phi(), mcdjet.tracks_as().size(), // detector level jet + mcdd0cand.pt(), mcdd0cand.eta(), mcdd0cand.phi(), mcdd0cand.m(), mcdd0cand.y(), (mcdd0cand.originMcRec() == RecoDecay::OriginType::Prompt), // detector level D0 candidate + mcdjet.has_matchedJetCand(), mcdd0cand.mlScores()[0], mcdd0cand.mlScores()[1], mcdd0cand.mlScores()[2], // // Machine Learning PID scores: background, prompt, non-prompt + matchedFrom, selectedAs); // D0 = +1, D0bar = -1, neither = 0 + } + } + + // d0 particle level jets associated to same mccollision + const auto d0mcpJetsPerMCCollision = mcpjets.sliceBy(d0MCPJetsPerMCCollisionPreslice, mccollision.globalIndex()); + for (const auto& mcpjet : d0mcpJetsPerMCCollision) { + + registry.fill(HIST("h_jet_counter"), 0.0); + + // obtain leading HF particle in jet + auto mcpd0cand = mcpjet.candidates_first_as(); + + if (mcpjet.has_matchedJetCand()) { + registry.fill(HIST("h_jet_counter"), 1.0); + } + + // store data in MC detector level table (calculate angular distance in eta-phi plane on the fly) + mcpdistJetTable(jetutilities::deltaR(mcpjet, mcpd0cand), + mcpjet.pt(), mcpjet.eta(), mcpjet.phi(), mcpjet.tracks_as().size(), // particle level jet + mcpd0cand.pt(), mcpd0cand.eta(), mcpd0cand.phi(), mcpd0cand.y(), (mcpd0cand.originMcGen() == RecoDecay::OriginType::Prompt), // particle level D0 + mcpjet.has_matchedJetCand()); + } + } + } + PROCESS_SWITCH(HfFragmentationFunction, processMcEfficiency, "non-matched and matched MC HF and jets", false); + + void processMcChargedMatched(aod::JetMcCollisions const& mccollisions, + aod::JetCollisionsMCD const& collisions, + JetMCDTable const& mcdjets, + JetMCPTable const&, + aod::CandidatesD0MCD const&, + aod::CandidatesD0MCP const&, + aod::JetTracks const&, + aod::JetParticles const&) + { + for (const auto& mccollision : mccollisions) { + + registry.fill(HIST("h_collision_counter"), 0.0); + + // skip collisions outside of |z| < vertexZCut + if (std::abs(mccollision.posZ()) > vertexZCut) { + continue; + } + registry.fill(HIST("h_collision_counter"), 1.0); + + // reconstructed collisions associated to same mccollision + const auto collisionsPerMCCollision = collisions.sliceBy(collisionsPerMCCollisionPreslice, mccollision.globalIndex()); + for (const auto& collision : collisionsPerMCCollision) { + + registry.fill(HIST("h_collision_counter"), 2.0); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || !(std::abs(collision.posZ()) < vertexZCut)) { + continue; + } + registry.fill(HIST("h_collision_counter"), 3.0); + // d0 detector level jets associated to the current same collision + const auto d0mcdJetsPerCollision = mcdjets.sliceBy(d0MCDJetsPerCollisionPreslice, collision.globalIndex()); + for (const auto& mcdjet : d0mcdJetsPerCollision) { + + registry.fill(HIST("h_jet_counter"), 0.5); + + // comparison with fill on bin on 2.5 for sanity check + if (mcdjet.has_matchedJetCand()) { + registry.fill(HIST("h_jet_counter"), 1.5); + } + + // obtain leading HF candidate in jet + auto mcdd0cand = mcdjet.candidates_first_as(); + + // reflection information for storage: D0 = +1, D0bar = -1, neither = 0 + int matchedFrom = 0; + int decayChannel = 1 << aod::hf_cand_2prong::DecayType::D0ToPiK; + int selectedAs = 0; + + if (mcdd0cand.flagMcMatchRec() == decayChannel) { // matched to D0 on truth level + matchedFrom = 1; + } else if (mcdd0cand.flagMcMatchRec() == -decayChannel) { // matched to D0bar on truth level + matchedFrom = -1; + } + // bitwise AND operation: Checks whether BIT(i) is set, regardless of other bits + if (mcdd0cand.candidateSelFlag() & BIT(0)) { // CandidateSelFlag == BIT(0) -> selected as D0 + selectedAs = 1; + } else if (mcdd0cand.candidateSelFlag() & BIT(1)) { // CandidateSelFlag == BIT(1) -> selected as D0bar + selectedAs = -1; + } + + // loop through detector level matched to current particle level + for (const auto& mcpjet : mcdjet.matchedJetCand_as()) { + + registry.fill(HIST("h_jet_counter"), 2.5); + + // obtain leading HF candidate in jet + auto mcpd0cand = mcpjet.candidates_first_as(); + + // store matched particle and detector level data in one single table (calculate angular distance in eta-phi plane on the fly) + matchJetTable(jetutilities::deltaR(mcpjet, mcpd0cand), mcpjet.pt(), mcpjet.eta(), mcpjet.phi(), mcpjet.tracks_as().size(), // particle level jet + mcpd0cand.pt(), mcpd0cand.eta(), mcpd0cand.phi(), mcpd0cand.y(), (mcpd0cand.originMcGen() == RecoDecay::OriginType::Prompt), // particle level D0 + jetutilities::deltaR(mcdjet, mcdd0cand), mcdjet.pt(), mcdjet.eta(), mcdjet.phi(), mcdjet.tracks_as().size(), // detector level jet + mcdd0cand.pt(), mcdd0cand.eta(), mcdd0cand.phi(), mcdd0cand.m(), mcdd0cand.y(), (mcdd0cand.originMcRec() == RecoDecay::OriginType::Prompt), // detector level D0 + mcdd0cand.mlScores()[0], mcdd0cand.mlScores()[1], mcdd0cand.mlScores()[2], // Machine Learning PID scores: background, prompt, non-prompt + matchedFrom, selectedAs); // D0 = +1, D0bar = -1, neither = 0 + } + } + } + } + } + PROCESS_SWITCH(HfFragmentationFunction, processMcChargedMatched, "matched MC HF and jets", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGJE/Tasks/hffragmentationfunction.cxx b/PWGJE/Tasks/hffragmentationfunction.cxx deleted file mode 100644 index d633b9f7ec5..00000000000 --- a/PWGJE/Tasks/hffragmentationfunction.cxx +++ /dev/null @@ -1,153 +0,0 @@ -// 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. - -// charm lambda/d0 ratio hadronization task -// -/// \author Christian Reckziegel -// -#include "TVector3.h" - -#include "fastjet/PseudoJet.hh" -#include "fastjet/ClusterSequenceArea.hh" - -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Framework/HistogramRegistry.h" - -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" - -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" - -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/DataModel/JetSubstructure.h" -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/Core/FastJetUtilities.h" -#include "PWGJE/Core/JetHFUtilities.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -// creating table for storing distance data -namespace o2::aod -{ -namespace DistanceSpace -{ -DECLARE_SOA_COLUMN(JetHfDist, jethfdist, float); -DECLARE_SOA_COLUMN(JetPt, jetpt, float); -DECLARE_SOA_COLUMN(JetEta, jeteta, float); -DECLARE_SOA_COLUMN(JetPhi, jetphi, float); -DECLARE_SOA_COLUMN(HfPt, hfpt, float); -DECLARE_SOA_COLUMN(HfEta, hfeta, float); -DECLARE_SOA_COLUMN(HfPhi, hfphi, float); -DECLARE_SOA_COLUMN(HfMass, hfmass, float); -DECLARE_SOA_COLUMN(HfY, hfy, float); -} // namespace DistanceSpace -DECLARE_SOA_TABLE(JetDistanceTable, "AOD", "JETDISTTABLE", - DistanceSpace::JetHfDist, - DistanceSpace::JetPt, - DistanceSpace::JetEta, - DistanceSpace::JetPhi, - DistanceSpace::HfPt, - DistanceSpace::HfEta, - DistanceSpace::HfPhi, - DistanceSpace::HfMass, - DistanceSpace::HfY); -} // namespace o2::aod - -// NB: runDataProcessing.h must be included after customize! -#include "Framework/runDataProcessing.h" - -struct HfFragmentationFunctionTask { - // producing new table - Produces distJetTable; - - // Histogram registry: an object to hold your histograms - HistogramRegistry registry{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - void init(InitContext const&) - { - - // create histograms - // D0 candidate histograms - registry.add("h_jet_counter", ";# jets;", {HistType::kTH1F, {{2, 0., 1.}}}); - registry.add("h_d0_jet_projection", ";z^{D^{0},jet}_{||};dN/dz^{D^{0},jet}_{||}", {HistType::kTH1F, {{1000, 0., 10.}}}); - registry.add("h_d0_jet_distance_vs_projection", ";#DeltaR_{D^{0},jet};z^{D^{0},jet}_{||}", {HistType::kTH2F, {{1000, 0., 10.}, {1000, 0., 10.}}}); - registry.add("h_d0_jet_distance", ";#DeltaR_{D^{0},jet};dN/d(#DeltaR)", {HistType::kTH1F, {{1000, 0., 10.}}}); - registry.add("h_d0_jet_pt", ";p_{T,D^{0} jet};dN/dp_{T,D^{0} jet}", {HistType::kTH1F, {{200, 0., 10.}}}); - registry.add("h_d0_jet_eta", ";#eta_{T,D^{0} jet};dN/d#eta_{D^{0} jet}", {HistType::kTH1F, {{250, -5., 5.}}}); - registry.add("h_d0_jet_phi", ";#phi_{T,D^{0} jet};dN/d#phi_{D^{0} jet}", {HistType::kTH1F, {{250, -10., 10.}}}); - registry.add("h_d0_mass", ";m_{D^{0}} (GeV/c^{2});dN/dm_{D^{0}}", {HistType::kTH1F, {{1000, 0., 10.}}}); - registry.add("h_d0_eta", ";#eta_{D^{0}} (GeV/c^{2});dN/d#eta_{D^{0}}", {HistType::kTH1F, {{250, -5., 5.}}}); - registry.add("h_d0_phi", ";#phi_{D^{0}} (GeV/c^{2});dN/d#phi_{D^{0}}", {HistType::kTH1F, {{250, -10., 10.}}}); - } - - void processDummy(aod::TracksIU const&) {} - PROCESS_SWITCH(HfFragmentationFunctionTask, processDummy, "Dummy process function turned on by default", false); - - void processDataChargedSubstructure(JetCollision const&, - soa::Join const& jets, - JetTracks const&, - CandidatesD0Data const&) - { - // CandidatesLcData const& lccands) { - - double axisDistance = 0; - - for (auto& jet : jets) { - // fill jet counter histogram - registry.fill(HIST("h_jet_counter"), 0.5); - // obtaining jet 3-vector - TVector3 jetVector(jet.px(), jet.py(), jet.pz()); - - for (auto& d0Candidate : jet.hfcandidates_as()) { // for jet constituents use -> auto& jetConstituent : jet.tracks_as() - - // obtaining jet 3-vector - TVector3 d0Vector(d0Candidate.px(), d0Candidate.py(), d0Candidate.pz()); - // calculating fraction of the jet momentum carried by the D0 along the direction of the jet axis - double z_parallel = (jetVector * d0Vector) / (jetVector * jetVector); - - // calculating angular distance in eta-phi plane - axisDistance = sqrt(pow(jet.eta() - d0Candidate.eta(), 2) + pow(jet.phi() - d0Candidate.phi(), 2)); - - // filling histograms - registry.fill(HIST("h_d0_jet_projection"), z_parallel); - registry.fill(HIST("h_d0_jet_distance_vs_projection"), axisDistance, z_parallel); - registry.fill(HIST("h_d0_jet_distance"), axisDistance); - registry.fill(HIST("h_d0_jet_pt"), jet.pt()); - registry.fill(HIST("h_d0_jet_eta"), jet.eta()); - registry.fill(HIST("h_d0_jet_phi"), jet.phi()); - registry.fill(HIST("h_d0_mass"), d0Candidate.m()); - registry.fill(HIST("h_d0_eta"), d0Candidate.eta()); - registry.fill(HIST("h_d0_phi"), d0Candidate.phi()); - // filling table - distJetTable(axisDistance, jet.pt(), jet.eta(), jet.phi(), d0Candidate.pt(), d0Candidate.eta(), d0Candidate.phi(), d0Candidate.m(), d0Candidate.y()); - break; // get out of candidates' loop after first HF particle is found in jet - } // end of D0 candidates loop - - } // end of jets loop - - } // end of process function - PROCESS_SWITCH(HfFragmentationFunctionTask, processDataChargedSubstructure, "charged HF jet substructure", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"jet-charm-hadronization"})}; -} diff --git a/PWGJE/Tasks/jetBackgroundAnalysis.cxx b/PWGJE/Tasks/jetBackgroundAnalysis.cxx new file mode 100644 index 00000000000..ece360113ec --- /dev/null +++ b/PWGJE/Tasks/jetBackgroundAnalysis.cxx @@ -0,0 +1,248 @@ +// 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. + +// jet finder QA task +// +/// \author Aimeric Landou +/// \author Nima Zardoshti + +#include +#include +#include +#include +#include "TLorentzVector.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" + +#include "PWGJE/Core/JetDerivedDataUtilities.h" + +#include "EventFiltering/filterTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct JetBackgroundAnalysisTask { + HistogramRegistry registry; + + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range for collisions"}; + Configurable centralityMin{"centralityMin", -999.0, "minimum centrality for collisions"}; + Configurable centralityMax{"centralityMax", 999.0, "maximum centrality for collisions"}; + Configurable trackOccupancyInTimeRangeMax{"trackOccupancyInTimeRangeMax", 999999, "maximum track occupancy of collisions in neighbouring collisions in a given time range; only applied to reconstructed collisions (data and mcd jets), not mc collisions (mcp jets)"}; + Configurable trackOccupancyInTimeRangeMin{"trackOccupancyInTimeRangeMin", -999999, "minimum track occupancy of collisions in neighbouring collisions in a given time range; only applied to reconstructed collisions (data and mcd jets), not mc collisions (mcp jets)"}; + Configurable skipMBGapEvents{"skipMBGapEvents", false, "flag to choose to reject min. bias gap events"}; + Configurable nBinsFluct{"nBinsFluct", 1000, "number of bins for flucuations axes"}; + + Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum eta acceptance for tracks"}; + Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum eta acceptance for tracks"}; + Configurable trackPtMin{"trackPtMin", 0.15, "minimum pT acceptance for tracks"}; + Configurable trackPtMax{"trackPtMax", 100.0, "maximum pT acceptance for tracks"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + + // // If weights are implemented for MCD bkg checks, the cut on pTHatMax of jets should be introduced + // Configurable pTHatMaxMCD{"pTHatMaxMCD", 999.0, "maximum fraction of hard scattering for jet acceptance in detector MC"}; + // Configurable pTHatExponent{"pTHatExponent", 6.0, "exponent of the event weight for the calculation of pTHat"}; + + Configurable randomConeR{"randomConeR", 0.4, "size of random Cone for estimating background fluctuations"}; + Configurable randomConeLeadJetDeltaR{"randomConeLeadJetDeltaR", -99.0, "min distance between leading jet axis and random cone (RC) axis; if negative, min distance is set to automatic value of R_leadJet+R_RC "}; + + std::vector eventSelectionBits; + int trackSelection = -1; + + void init(o2::framework::InitContext&) + { + // selection settings initialisation + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + + // Axes definitions + AxisSpec bkgFluctuationsAxis = {nBinsFluct, -100.0, 100.0, "#delta #it{p}_{T} (GeV/#it{c})"}; + + // histogram definitions + + if (doprocessRho) { + registry.add("h2_centrality_ntracks", "; centrality; N_{tracks};", {HistType::kTH2F, {{1100, 0., 110.0}, {10000, 0.0, 10000.0}}}); + registry.add("h2_ntracks_rho", "; N_{tracks}; #it{rho} (GeV/area);", {HistType::kTH2F, {{10000, 0.0, 10000.0}, {400, 0.0, 400.0}}}); + registry.add("h2_ntracks_rhom", "; N_{tracks}; #it{rho}_{m} (GeV/area);", {HistType::kTH2F, {{10000, 0.0, 10000.0}, {100, 0.0, 100.0}}}); + registry.add("h2_centrality_rho", "; centrality; #it{rho} (GeV/area);", {HistType::kTH2F, {{1100, 0., 110.}, {400, 0., 400.0}}}); + registry.add("h2_centrality_rhom", ";centrality; #it{rho}_{m} (GeV/area)", {HistType::kTH2F, {{1100, 0., 110.}, {100, 0., 100.0}}}); + } + + if (doprocessBkgFluctuationsData || doprocessBkgFluctuationsMCD) { + registry.add("h2_centrality_rhorandomcone", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH2F, {{1100, 0., 110.}, bkgFluctuationsAxis}}); + registry.add("h2_centrality_rhorandomconerandomtrackdirection", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH2F, {{1100, 0., 110.}, bkgFluctuationsAxis}}); + registry.add("h2_centrality_rhorandomconewithoutleadingjet", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH2F, {{1100, 0., 110.}, bkgFluctuationsAxis}}); + registry.add("h2_centrality_rhorandomconerandomtrackdirectionwithoutoneleadingjets", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH2F, {{1100, 0., 110.}, bkgFluctuationsAxis}}); + registry.add("h2_centrality_rhorandomconerandomtrackdirectionwithouttwoleadingjets", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH2F, {{1100, 0., 110.}, bkgFluctuationsAxis}}); + } + } + + Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); + Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax); + + template + bool trackIsInJet(TTracks const& track, TJets const& jet) + { + for (auto const& constituentId : jet.tracksIds()) { + if (constituentId == track.globalIndex()) { + return true; + } + } + return false; + } + + template + void bkgFluctuationsRandomCone(TCollisions const& collision, TJets const& jets, TTracks const& tracks) + { + TRandom3 randomNumber(0); + float randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); + float randomConePhi = randomNumber.Uniform(0.0, 2 * M_PI); + float randomConePt = 0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-M_PI)); + float dEta = track.eta() - randomConeEta; + if (TMath::Sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePt += track.pt(); + } + } + } + registry.fill(HIST("h2_centrality_rhorandomcone"), collision.centrality(), randomConePt - M_PI * randomConeR * randomConeR * collision.rho()); + + // randomised eta,phi for tracks, to assess part of fluctuations coming from statistically independently emitted particles + randomConePt = 0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + float dPhi = RecoDecay::constrainAngle(randomNumber.Uniform(0.0, 2 * M_PI) - randomConePhi, static_cast(-M_PI)); // ignores actual phi of track + float dEta = randomNumber.Uniform(trackEtaMin, trackEtaMax) - randomConeEta; // ignores actual eta of track + if (TMath::Sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePt += track.pt(); + } + } + } + registry.fill(HIST("h2_centrality_rhorandomconerandomtrackdirection"), collision.centrality(), randomConePt - M_PI * randomConeR * randomConeR * collision.rho()); + + // removing the leading jet from the random cone + if (jets.size() > 0) { // if there are no jets in the acceptance (from the jetfinder cuts) then there can be no leading jet + float dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, static_cast(-M_PI)); + float dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; + + bool jetWasInCone = false; + while ((randomConeLeadJetDeltaR <= 0 && (TMath::Sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < jets.iteratorAt(0).r() / 100.0 + randomConeR)) || (randomConeLeadJetDeltaR > 0 && (TMath::Sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < randomConeLeadJetDeltaR))) { + jetWasInCone = true; + randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); + randomConePhi = randomNumber.Uniform(0.0, 2 * M_PI); + dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, static_cast(-M_PI)); + dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; + } + if (jetWasInCone) { + randomConePt = 0.0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { // if track selection is uniformTrack, dcaXY and dcaZ cuts need to be added as they aren't in the selection so that they can be studied here + float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-M_PI)); + float dEta = track.eta() - randomConeEta; + if (TMath::Sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePt += track.pt(); + } + } + } + } + } + registry.fill(HIST("h2_centrality_rhorandomconewithoutleadingjet"), collision.centrality(), randomConePt - M_PI * randomConeR * randomConeR * collision.rho()); + + // randomised eta,phi for tracks, to assess part of fluctuations coming from statistically independently emitted particles, removing tracks from 2 leading jets + double randomConePtWithoutOneLeadJet = 0; + double randomConePtWithoutTwoLeadJet = 0; + if (jets.size() > 1) { // if there are no jets, or just one, in the acceptance (from the jetfinder cuts) then one cannot find 2 leading jets + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + float dPhi = RecoDecay::constrainAngle(randomNumber.Uniform(0.0, 2 * M_PI) - randomConePhi, static_cast(-M_PI)); // ignores actual phi of track + float dEta = randomNumber.Uniform(trackEtaMin, trackEtaMax) - randomConeEta; // ignores actual eta of track + if (TMath::Sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + if (!trackIsInJet(track, jets.iteratorAt(0))) { + randomConePtWithoutOneLeadJet += track.pt(); + if (!trackIsInJet(track, jets.iteratorAt(1))) { + randomConePtWithoutTwoLeadJet += track.pt(); + } + } + } + } + } + } + registry.fill(HIST("h2_centrality_rhorandomconerandomtrackdirectionwithoutoneleadingjets"), collision.centrality(), randomConePtWithoutOneLeadJet - M_PI * randomConeR * randomConeR * collision.rho()); + registry.fill(HIST("h2_centrality_rhorandomconerandomtrackdirectionwithouttwoleadingjets"), collision.centrality(), randomConePtWithoutTwoLeadJet - M_PI * randomConeR * randomConeR * collision.rho()); + } + + void processRho(soa::Filtered>::iterator const& collision, soa::Filtered const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + int nTracks = 0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + nTracks++; + } + } + registry.fill(HIST("h2_centrality_ntracks"), collision.centrality(), nTracks); + registry.fill(HIST("h2_ntracks_rho"), nTracks, collision.rho()); + registry.fill(HIST("h2_ntracks_rhom"), nTracks, collision.rhoM()); + registry.fill(HIST("h2_centrality_rho"), collision.centrality(), collision.rho()); + registry.fill(HIST("h2_centrality_rhom"), collision.centrality(), collision.rhoM()); + } + PROCESS_SWITCH(JetBackgroundAnalysisTask, processRho, "QA for rho-area subtracted jets", false); + + void processBkgFluctuationsData(soa::Filtered>::iterator const& collision, soa::Join const& jets, soa::Filtered const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + bkgFluctuationsRandomCone(collision, jets, tracks); + } + PROCESS_SWITCH(JetBackgroundAnalysisTask, processBkgFluctuationsData, "QA for random cone estimation of background fluctuations in data", false); + + void processBkgFluctuationsMCD(soa::Filtered>::iterator const& collision, soa::Join const& jets, soa::Filtered const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + bkgFluctuationsRandomCone(collision, jets, tracks); + } + PROCESS_SWITCH(JetBackgroundAnalysisTask, processBkgFluctuationsMCD, "QA for random cone estimation of background fluctuations in mcd", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"jet-background-analysis"})}; } diff --git a/PWGJE/Tasks/jetChCorr.cxx b/PWGJE/Tasks/jetChCorr.cxx index 8d3cffd5346..43486b4567c 100644 --- a/PWGJE/Tasks/jetChCorr.cxx +++ b/PWGJE/Tasks/jetChCorr.cxx @@ -394,36 +394,36 @@ struct JetChCorr { } } - void processDummy(JetTracks const&) + void processDummy(aod::JetTracks const&) { } PROCESS_SWITCH(JetChCorr, processDummy, "Dummy process function turned on by default", true); - void processChargedJetsData(soa::Join::iterator const& jet, JetTracks const& tracks) + void processChargedJetsData(soa::Join::iterator const& jet, aod::JetTracks const& tracks) { analyseCharged(jet, tracks); } PROCESS_SWITCH(JetChCorr, processChargedJetsData, "charged jet substructure", false); void processChargedJetsEventWiseSubData(soa::Join::iterator const& jet, - JetTracksSub const& tracks) + aod::JetTracksSub const& tracks) { analyseCharged(jet, tracks); } PROCESS_SWITCH(JetChCorr, processChargedJetsEventWiseSubData, "eventwise-constituent subtracted charged jet substructure", false); void processChargedJetsMCD(typename soa::Join::iterator const& jet, - JetTracks const& tracks) + aod::JetTracks const& tracks) { analyseCharged(jet, tracks); } PROCESS_SWITCH(JetChCorr, processChargedJetsMCD, "charged jet substructure", false); void processChargedJetsMCP(typename soa::Join::iterator const& jet, - JetParticles const&) + aod::JetParticles const&) { jetConstituents.clear(); - for (auto& jetConstituent : jet.template tracks_as()) { + for (auto& jetConstituent : jet.template tracks_as()) { fastjetutilities::fillTracks(jetConstituent, jetConstituents, jetConstituent.globalIndex(), static_cast(JetConstituentStatus::track), pdg->Mass(jetConstituent.pdgCode())); } jetReclustering(jet); diff --git a/PWGJE/Tasks/jetChargedV2.cxx b/PWGJE/Tasks/jetChargedV2.cxx new file mode 100644 index 00000000000..cb98a8bef7b --- /dev/null +++ b/PWGJE/Tasks/jetChargedV2.cxx @@ -0,0 +1,926 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \author Yubiao Wang +/// \file jetChargedV2.cxx +/// \brief This file contains the implementation for the Charged Jet v2 analysis in the ALICE experiment + +#include +#include +#include +#include +#include +#include +#include +#include +#include +// o2Physics includes. +#include "CommonConstants/MathConstants.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" + +#include "Framework/runDataProcessing.h" + +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/CCDB/ctpRateFetcher.h" + +//< evt pln .h >// +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StaticFor.h" + +#include "Common/DataModel/Qvectors.h" +#include "Common/Core/EventPlaneHelper.h" +//< evt pln .h | end >// + +// o2 includes. +#include "DetectorsCommonDataFormats/AlignParam.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" + +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "EventFiltering/filterTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct JetChargedV2 { + HistogramRegistry registry; + HistogramRegistry histosQA{"histosQA", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + + Configurable> jetRadii{"jetRadii", std::vector{0.4}, "jet resolution parameters"}; + + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + Configurable trackDcaZmax{"trackDcaZmax", 99, "additional cut on dcaZ to PV for tracks; uniformTracks in particular don't cut on this at all"}; + Configurable centralityMin{"centralityMin", -999.0, "minimum centrality"}; + Configurable centralityMax{"centralityMax", 999.0, "maximum centrality"}; + Configurable trackPtMin{"trackPtMin", 0.15, "minimum pT acceptance for tracks"}; + Configurable trackPtMax{"trackPtMax", 1000., "maximum pT acceptance for tracks"}; + Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum eta acceptance for tracks"}; + Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum eta acceptance for tracks"}; + + Configurable jetAreaFractionMin{"jetAreaFractionMin", -99.0, "used to make a cut on the jet areas"}; + Configurable leadingConstituentPtMin{"leadingConstituentPtMin", -99.0, "minimum pT selection on jet constituent"}; + Configurable leadingConstituentPtMax{"leadingConstituentPtMax", 9999.0, "maximum pT selection on jet constituent"}; + Configurable jetPtMin{"jetPtMin", 0.15, "minimum pT acceptance for jets"}; + Configurable jetPtMax{"jetPtMax", 200.0, "maximum pT acceptance for jets"}; + Configurable jetEtaMin{"jetEtaMin", -0.9, "minimum eta acceptance for jets"}; + Configurable jetEtaMax{"jetEtaMax", 0.9, "maximum eta acceptance for jets"}; + Configurable jetRadius{"jetRadius", 0.2, "jet resolution parameters"}; + + Configurable localRhoFitPtMin{"localRhoFitPtMin", 0.2, "Minimum track pT used for local rho fluctuation fit"}; + Configurable localRhoFitPtMax{"localRhoFitPtMax", 5, "Maximum track pT used for local rho fluctuation fit"}; + + Configurable randomConeR{"randomConeR", 0.4, "size of random Cone for estimating background fluctuations"}; + Configurable trackOccupancyInTimeRangeMax{"trackOccupancyInTimeRangeMax", 999999, "maximum occupancy of tracks in neighbouring collisions in a given time range; only applied to reconstructed collisions (data and mcd jets), not mc collisions (mcp jets)"}; + Configurable trackOccupancyInTimeRangeMin{"trackOccupancyInTimeRangeMin", -999999, "minimum occupancy of tracks in neighbouring collisions in a given time range; only applied to reconstructed collisions (data and mcd jets), not mc collisions (mcp jets)"}; + //=====================< evt pln >=====================// + Configurable cfgAddEvtSel{"cfgAddEvtSel", true, "event selection"}; + Configurable> cfgnMods{"cfgnMods", {2}, "Modulation of interest"}; + Configurable cfgnTotalSystem{"cfgnTotalSystem", 7, "total qvector number"}; + Configurable cfgDetName{"cfgDetName", "FT0M", "The name of detector to be analyzed"}; + Configurable cfgRefAName{"cfgRefAName", "TPCpos", "The name of detector for reference A"}; + Configurable cfgRefBName{"cfgRefBName", "TPCneg", "The name of detector for reference B"}; + + ConfigurableAxis cfgAxisQvecF{"cfgAxisQvecF", {300, -1, 1}, ""}; + ConfigurableAxis cfgAxisQvec{"cfgAxisQvec", {100, -3, 3}, ""}; + ConfigurableAxis cfgAxisCent{"cfgAxisCent", {90, 0, 90}, ""}; + + ConfigurableAxis cfgAxisVnCent{"cfgAxisVnCent", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 50, 70, 100}, " % "}; + + ConfigurableAxis cfgAxisEvtfit{"cfgAxisEvtfit", {10000, 0, 10000}, ""}; + EventPlaneHelper helperEP; + int detId; + int refAId; + int refBId; + + template + int getDetId(const T& name) + { + if (name.value == "BPos" || name.value == "BNeg" || name.value == "BTot") { + LOGF(warning, "Using deprecated label: %s. Please use TPCpos, TPCneg, TPCall instead.", name.value); + } + if (name.value == "FT0C") { + return 0; + } else if (name.value == "FT0A") { + return 1; + } else if (name.value == "FT0M") { + return 2; + } else if (name.value == "FV0A") { + return 3; + } else if (name.value == "TPCpos" || name.value == "BPos") { + return 4; + } else if (name.value == "TPCneg" || name.value == "BNeg") { + return 5; + } else if (name.value == "TPCall" || name.value == "BTot") { + return 6; + } else { + return 0; + } + } + //=====================< evt pln | end >=====================// + + Configurable selectedJetsRadius{"selectedJetsRadius", 0.2, "resolution parameter for histograms without radius"}; + + std::vector jetPtBins; + std::vector jetPtBinsRhoAreaSub; + + std::vector eventSelectionBits; + int trackSelection = -1; + double evtnum = 0; + double accptTrack = 0; + double fitTrack = 0; + TH1F* hPtsumSumptFit = nullptr; + + void init(o2::framework::InitContext&) + { + detId = getDetId(cfgDetName); + refAId = getDetId(cfgRefAName); + refBId = getDetId(cfgRefBName); + if (detId == refAId || detId == refBId || refAId == refBId) { + LOGF(info, "Wrong detector configuration \n The FT0C will be used to get Q-Vector \n The TPCpos and TPCneg will be used as reference systems"); + detId = 0; + refAId = 4; + refBId = 5; + } + + auto jetPtTemp = 0.0; + jetPtBins.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(jetPtTemp); + while (jetPtTemp < jetPtMax) { + double jetPtTempA = 100.0; + double jetPtTempB = 100.0; + if (jetPtTemp < jetPtTempA) { + jetPtTemp += 1.0; + jetPtBins.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(-jetPtTemp); + } else if (jetPtTemp < jetPtTempB) { + jetPtTemp += 5.0; + jetPtBins.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(-jetPtTemp); + + } else { + jetPtTemp += 10.0; + jetPtBins.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(-jetPtTemp); + } + } + std::sort(jetPtBinsRhoAreaSub.begin(), jetPtBinsRhoAreaSub.end()); + + AxisSpec jetPtAxis = {jetPtBins, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec jetPtAxisRhoAreaSub = {jetPtBinsRhoAreaSub, "#it{p}_{T} (GeV/#it{c})"}; + + AxisSpec axisPt = {40, 0.0, 4.0}; + AxisSpec axisEta = {32, -0.8, 0.8}; + AxisSpec axixCent = {20, 0, 100}; + AxisSpec axisChID = {220, 0, 220}; + + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + + //< Track efficiency plots >// + registry.add("h_collisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + registry.add("h2_centrality_collisions", "centrality vs collisions; centrality; collisions", {HistType::kTH2F, {{120, -10., 110.}, {4, 0.0, 4.0}}}); + registry.add("h2_centrality_track_pt", "centrality vs track pT; centrality; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, 0., 200.}}}); + registry.add("h2_centrality_track_eta", "centrality vs track #eta; centrality; #eta_{track}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, -1.0, 1.0}}}); + registry.add("h2_centrality_track_phi", "centrality vs track #varphi; centrality; #varphi_{track}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {160, -1.0, 7.}}}); + registry.add("h2_centrality_track_energy", "centrality vs track energy; centrality; Energy GeV", {HistType::kTH2F, {{120, -10., 110.}, {100, 0.0, 100.0}}}); + registry.add("h2_track_pt_track_sigmapt", "#sigma(#it{p}_{T})/#it{p}_{T}; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{100, 0., 10.}, {100000, 0.0, 100.0}}}); + registry.add("h2_track_pt_high_track_sigmapt", "#sigma(#it{p}_{T})/#it{p}_{T}; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{90, 10., 100.}, {100000, 0.0, 100.0}}}); + registry.add("h2_track_pt_track_sigma1overpt", "#sigma(1/#it{p}_{T}); #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{100, 0., 10.}, {1000, 0.0, 10.0}}}); + registry.add("h2_track_pt_high_track_sigma1overpt", "#sigma(1/#it{p}_{T}); #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{90, 10., 100.}, {1000, 0.0, 10.0}}}); + + //< \sigma p_T at local rho test plot > + registry.add("h_accept_Track", "all and accept track;Track;entries", {HistType::kTH1F, {{10, 0.0, 10.0}}}); + registry.add("h_accept_Track_init", "all and accept track;Track;entries", {HistType::kTH1F, {{10, 0.0, 10.0}}}); + registry.add("h_accept_Track_Fit", "all and accept track;Track;entries", {HistType::kTH1F, {{10, 0.0, 10.0}}}); + + registry.add("h_ptsum_collnum", "ptsum collnum;collnum;entries", {HistType::kTH1F, {{40, 0.0, 40}}}); + registry.add("h_ptsum_sumpt", "jet sumpt;sum p_{T};entries", {HistType::kTH1F, {{40, 0., o2::constants::math::TwoPI}}}); + registry.add("h2_phi_track_eta", "phi vs track eta; #eta (GeV/#it{c}); #varphi", {HistType::kTH2F, {{100, -1.0, 1.0}, {40, 0., o2::constants::math::TwoPI}}}); + registry.add("h2_centrality_phi_w_pt", "centrality vs jet #varphi; centrality; entries", {HistType::kTH2F, {{100, 0.0, 100.0}, {40, 0., o2::constants::math::TwoPI}}}); + registry.add("h2_evtnum_phi_w_pt", "eventNumber vs jet #varphi; #eventNumber; entries", {HistType::kTH2F, {{1000, 0.0, 1000}, {40, 0., o2::constants::math::TwoPI}}}); + + //< fit quality >// + registry.add("h_PvalueCDF_CombinFit", "cDF #chi^{2}; entries", {HistType::kTH1F, {{50, 0, 1}}}); + registry.add("h2_PvalueCDFCent_CombinFit", "p-value cDF vs centrality; centrality; p-value", {HistType::kTH2F, {{100, 0, 100}, {40, 0, 1}}}); + registry.add("h2_Chi2Cent_CombinFit", "Chi2 vs centrality; centrality; #tilde{#chi^{2}}", {HistType::kTH2F, {{100, 0, 100}, {100, 0, 5}}}); + registry.add("h2_PChi2_CombinFit", "p-value vs #tilde{#chi^{2}}; p-value; #tilde{#chi^{2}}", {HistType::kTH2F, {{100, 0, 1}, {100, 0, 5}}}); + + registry.add("Thn_PChi2_CombinFitCent", "p-value vs #tilde{#chi^{2}}; p-value; #tilde{#chi^{2}}", {HistType::kTHnSparseF, {{100, 0.0, 100.0}, {100, 0, 1}, {100, 0, 5}}}); + registry.add("h2_PChi2_CombinFitA", "p-value vs #tilde{#chi^{2}}; p-value; #tilde{#chi^{2}}", {HistType::kTH2F, {{100, 0, 1}, {100, 0, 5}}}); + registry.add("h2_PChi2_CombinFitB", "p-value vs #tilde{#chi^{2}}; p-value; #tilde{#chi^{2}}", {HistType::kTH2F, {{100, 0, 1}, {100, 0, 5}}}); + + registry.add("h_evtnum_centrlity", "eventNumber vs centrality ; #eventNumber", {HistType::kTH1F, {{1000, 0.0, 1000}}}); + registry.add("h_evtnum_NTrk", "eventNumber vs Number of Track ; #eventNumber", {HistType::kTH1F, {{1000, 0.0, 1000}}}); + + registry.add("Thn_evtnum_phi_centrality", "eventNumber vs jet #varphi; #eventNumber; entries", {HistType::kTHnSparseF, {{1000, 0.0, 1000}, {40, 0., o2::constants::math::TwoPI}, {100, 0.0, 100.0}}}); + + registry.add("h2_evt_fitpara", "event vs fit parameter; evtnum; parameter", {HistType::kTH2F, {cfgAxisEvtfit, {5, 0., 5}}}); + + registry.add("h_v2obs_centrality", "fitparameter v2obs vs centrality ; #centrality", {HistType::kTProfile, {cfgAxisVnCent}}); + registry.add("h_v3obs_centrality", "fitparameter v3obs vs centrality ; #centrality", {HistType::kTProfile, {cfgAxisVnCent}}); + + registry.add("h_fitparaRho_evtnum", "fitparameter #rho_{0} vs evtnum ; #eventnumber", {HistType::kTH1F, {{1000, 0.0, 1000}}}); + registry.add("h_fitparaPsi2_evtnum", "fitparameter #Psi_{2} vs evtnum ; #eventnumber", {HistType::kTH1F, {{1000, 0.0, 1000}}}); + registry.add("h_fitparaPsi3_evtnum", "fitparameter #Psi_{3} vs evtnum ; #eventnumber", {HistType::kTH1F, {{1000, 0.0, 1000}}}); + registry.add("h_fitparav2obs_evtnum", "fitparameter v2obs vs evtnum ; #eventnumber", {HistType::kTH1F, {{1000, 0.0, 1000}}}); + registry.add("h_fitparav3obs_evtnum", "fitparameter v3obs vs evtnum ; #eventnumber", {HistType::kTH1F, {{1000, 0.0, 1000}}}); + + registry.add("h2_fitParaZero_cent", "#varphi vs #rho(#varphi); #cent; #fitParameter[0] ", {HistType::kTH2F, {{100, 0., 100}, {210, -10.0, 200.0}}}); + registry.add("h2_phi_rhophi", "#varphi vs #rho(#varphi); #varphi - #Psi_{EP,2}; #rho_{ch}(#varphi) ", {HistType::kTH2F, {{40, 0., o2::constants::math::TwoPI}, {210, -10.0, 200.0}}}); + registry.add("h2_phi_rholocal", "#varphi vs #rho(#varphi); #varphi - #Psi_{EP,2}; #rho(#varphi) ", {HistType::kTH2F, {{40, 0., o2::constants::math::TwoPI}, {210, -10.0, 200.0}}}); + registry.add("h2_phi_rholocal_cent", "#varphi vs #rho(#varphi); #cent; #rho(#varphi) ", {HistType::kTH2F, {{100, 0., 100}, {210, -10.0, 200.0}}}); + registry.add("h3_centrality_localrho_phi", "centrality; #rho_{local}; #Delta#varphi_{jet}", {HistType::kTH3F, {{120, -10.0, 110.0}, {200, 0.0, 200.0}, {40, 0., o2::constants::math::TwoPI}}}); + + registry.add("h3_centrality_rhovsphi_phi", "centrality; #rho(#varphi); #Delta#varphi_{jet}", {HistType::kTH3F, {{120, -10.0, 110.0}, {200, 0.0, 200.0}, {40, 0., o2::constants::math::TwoPI}}}); + //< \sigma p_T at local rho test plot | end > + + registry.add("h_jet_pt_rhoareasubtracted", "jet pT rhoareasubtracted;#it{p}_{T,jet} (GeV/#it{c}); entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + registry.add("h_jet_pt_rholocal", "jet pT rholocal;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + + registry.add("h2_centrality_jet_pt_rhoareasubtracted", "centrality vs #it{p}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, jetPtAxisRhoAreaSub}}); + + registry.add("leadJetPt", "leadJet Pt ", {HistType::kTH1F, {{200, 0., 200.0}}}); + registry.add("leadJetPhi", "leadJet constituent #phi ", {HistType::kTH1F, {{80, -1.0, 7.}}}); + registry.add("leadJetEta", "leadJet constituent #eta ", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + + //< RC test plots >// + registry.add("h3_centrality_deltapT_RandomCornPhi_rhorandomconewithoutleadingjet", "centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho}; #Delta#varphi_{jet}", {HistType::kTH3F, {{100, 0.0, 100.0}, {400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); + registry.add("h3_centrality_deltapT_RandomCornPhi_localrhovsphi", "centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho}; #Delta#varphi_{jet}", {HistType::kTH3F, {{100, 0.0, 100.0}, {400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); + registry.add("h2_centrality_deltapT_RandomCornPhi_RCprocess_rhorandomconewithoutleadingjet", "#it{p}_{T,random cone} - #it{area, random cone} * #it{rho}; #Delta#varphi_{jet}", {HistType::kTH2F, {{400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); + + registry.add("h3_centrality_deltapT_RandomCornPhi_localrhovsphiwithoutleadingjet", "centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho}(#varphi); #Delta#varphi_{jet}", {HistType::kTH3F, {{100, 0.0, 100.0}, {400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); + //< bkg sub plot | end >// + //< median rho >// + registry.add("h_jet_pt_in_plane_v2", "jet pT;#it{p}^{in-plane}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + registry.add("h_jet_pt_out_of_plane_v2", "jet pT;#it{p}^{out-of-plane}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + registry.add("h_jet_pt_in_plane_v3", "jet pT;#it{p}^{in-plane}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + registry.add("h_jet_pt_out_of_plane_v3", "jet pT;#it{p}^{out-of-plane}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + + registry.add("h2_centrality_jet_pt_in_plane_v2", "centrality vs #it{p}^{in-plane}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{120, -10.0, 110.0}, jetPtAxisRhoAreaSub}}); + registry.add("h2_centrality_jet_pt_out_of_plane_v2", "centrality vs #it{p}^{out-of-plane}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{120, -10.0, 110.0}, jetPtAxisRhoAreaSub}}); + registry.add("h2_centrality_jet_pt_in_plane_v3", "centrality vs #it{p}^{in-plane}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{120, -10.0, 110.0}, jetPtAxisRhoAreaSub}}); + registry.add("h2_centrality_jet_pt_out_of_plane_v3", "centrality vs #it{p}^{out-of-plane}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{120, -10.0, 110.0}, jetPtAxisRhoAreaSub}}); + //< rho(phi) >// + registry.add("h_jet_pt_inclusive_v2_rho", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + registry.add("h_jet_pt_in_plane_v2_rho", "jet pT;#it{p}^{in-plane}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + registry.add("h_jet_pt_out_of_plane_v2_rho", "jet pT;#it{p}^{out-of-plane}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + registry.add("h_jet_pt_in_plane_v3_rho", "jet pT;#it{p}^{in-plane}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + registry.add("h_jet_pt_out_of_plane_v3_rho", "jet pT;#it{p}^{out-of-plane}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + + registry.add("h2_centrality_jet_pt_in_plane_v2_rho", "centrality vs #it{p}^{in-plane}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{120, -10.0, 110.0}, jetPtAxisRhoAreaSub}}); + registry.add("h2_centrality_jet_pt_out_of_plane_v2_rho", "centrality vs #it{p}^{out-of-plane}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{120, -10.0, 110.0}, jetPtAxisRhoAreaSub}}); + registry.add("h2_centrality_jet_pt_in_plane_v3_rho", "centrality vs #it{p}^{in-plane}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{120, -10.0, 110.0}, jetPtAxisRhoAreaSub}}); + registry.add("h2_centrality_jet_pt_out_of_plane_v3_rho", "centrality vs #it{p}^{out-of-plane}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{120, -10.0, 110.0}, jetPtAxisRhoAreaSub}}); + + //=====================< evt pln plot >=====================// + AxisSpec axisCent{cfgAxisCent, "centrality"}; + AxisSpec axisQvec{cfgAxisQvec, "Q"}; + AxisSpec axisQvecF{cfgAxisQvecF, "Q"}; + + AxisSpec axisEvtPl{360, -constants::math::PI, constants::math::PI}; + + histosQA.add("histCent", "Centrality TrkProcess", HistType::kTH1F, {axisCent}); + + for (uint i = 0; i < cfgnMods->size(); i++) { + histosQA.add(Form("histQvecUncorV%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); + histosQA.add(Form("histQvecRectrV%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); + histosQA.add(Form("histQvecTwistV%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); + histosQA.add(Form("histQvecFinalV%d", cfgnMods->at(i)), "", {HistType::kTH3F, {axisQvec, axisQvec, axisCent}}); + + histosQA.add(Form("histEvtPlUncorV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("histEvtPlRectrV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("histEvtPlTwistV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("histEvtPlFinalV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + + histosQA.add(Form("histEvtPlRes_SigRefAV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("histEvtPlRes_SigRefBV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("histEvtPlRes_RefARefBV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + } + //=====================< evt pln plot | end >=====================// + } + + Preslice jetsPerJCollision = o2::aod::jet::collisionId; + Preslice tracksPerJCollision = o2::aod::jtrack::collisionId; + + Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); + Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax); + + template + bool isAcceptedJet(U const& jet) + { + double jetAreaFractionMinCfgMin = -98.0; + double jetAreaFractionMinCfgMax = 9998.0; + if (jetAreaFractionMin > jetAreaFractionMinCfgMin) { + if (jet.area() < jetAreaFractionMin * o2::constants::math::PI * (jet.r() / 100.0) * (jet.r() / 100.0)) { + return false; + } + } + bool checkConstituentPt = true; + bool checkConstituentMinPt = (leadingConstituentPtMin > jetAreaFractionMinCfgMin); + bool checkConstituentMaxPt = (leadingConstituentPtMax < jetAreaFractionMinCfgMax); + if (!checkConstituentMinPt && !checkConstituentMaxPt) { + checkConstituentPt = false; + } + + if (checkConstituentPt) { + bool isMinLeadingConstituent = !checkConstituentMinPt; + bool isMaxLeadingConstituent = true; + + for (const auto& constituent : jet.template tracks_as()) { + double pt = constituent.pt(); + + if (checkConstituentMinPt && pt >= leadingConstituentPtMin) { + isMinLeadingConstituent = true; + } + if (checkConstituentMaxPt && pt > leadingConstituentPtMax) { + isMaxLeadingConstituent = false; + } + } + return isMinLeadingConstituent && isMaxLeadingConstituent; + } + + return true; + } + + template + bool trackIsInJet(T const& track, U const& jet) + { + for (auto const& constituentId : jet.tracksIds()) { + if (constituentId == track.globalIndex()) { + return true; + } + } + return false; + } + + template + void fillTrackHistograms(T const& collision, U const& tracks, float weight = 1.0) + { + for (auto const& track : tracks) { + if (!(jetderiveddatautilities::selectTrack(track, trackSelection) && jetderiveddatautilities::selectTrackDcaZ(track, trackDcaZmax))) { + continue; + } + registry.fill(HIST("h2_centrality_track_pt"), collision.centrality(), track.pt(), weight); + registry.fill(HIST("h2_centrality_track_eta"), collision.centrality(), track.eta(), weight); + registry.fill(HIST("h2_centrality_track_phi"), collision.centrality(), track.phi(), weight); + registry.fill(HIST("h2_centrality_track_energy"), collision.centrality(), track.energy(), weight); + registry.fill(HIST("h2_track_pt_track_sigma1overpt"), track.pt(), track.sigma1Pt(), weight); + registry.fill(HIST("h2_track_pt_track_sigmapt"), track.pt(), track.sigma1Pt() * track.pt(), weight); + registry.fill(HIST("h2_track_pt_high_track_sigma1overpt"), track.pt(), track.sigma1Pt(), weight); + registry.fill(HIST("h2_track_pt_high_track_sigmapt"), track.pt(), track.sigma1Pt() * track.pt(), weight); + } + } + + void fillLeadingJetQA(double leadingJetPt, double leadingJetPhi, double leadingJetEta) + { + registry.fill(HIST("leadJetPt"), leadingJetPt); + registry.fill(HIST("leadJetPhi"), leadingJetPhi); + registry.fill(HIST("leadJetEta"), leadingJetEta); + } + + double chiSquareCDF(int nDF, double x) + { + return TMath::Gamma(nDF / 2., x / 2.); + } + + void processInOutJetV2(soa::Filtered>::iterator const& collision, + soa::Join const& jets, + aod::JetTracks const&) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + //=====================< evt pln [n=2->\Psi_2, n=3->\Psi_3] >=====================// + histosQA.fill(HIST("histCent"), collision.cent()); + for (uint i = 0; i < cfgnMods->size(); i++) { + int nmode = cfgnMods->at(i); + int detInd = detId * 4 + cfgnTotalSystem * 4 * (nmode - 2); + int refAInd = refAId * 4 + cfgnTotalSystem * 4 * (nmode - 2); + int refBInd = refBId * 4 + cfgnTotalSystem * 4 * (nmode - 2); + int cfgNmodA = 2; + int cfgNmodB = 3; + int evtPlnAngleA = 7; + int evtPlnAngleB = 3; + int evtPlnAngleC = 5; + if (nmode == cfgNmodA) { + if (collision.qvecAmp()[detId] > 1e-8 || collision.qvecAmp()[refAId] < 1e-8 || collision.qvecAmp()[refBId] < 1e-8) { + histosQA.fill(HIST("histQvecUncorV2"), collision.qvecRe()[detInd], collision.qvecIm()[detInd], collision.cent()); + histosQA.fill(HIST("histQvecRectrV2"), collision.qvecRe()[detInd + 1], collision.qvecIm()[detInd + 1], collision.cent()); + histosQA.fill(HIST("histQvecTwistV2"), collision.qvecRe()[detInd + 2], collision.qvecIm()[detInd + 2], collision.cent()); + histosQA.fill(HIST("histQvecFinalV2"), collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], collision.cent()); + + histosQA.fill(HIST("histEvtPlUncorV2"), helperEP.GetEventPlane(collision.qvecRe()[detInd], collision.qvecIm()[detInd], nmode), collision.cent()); + histosQA.fill(HIST("histEvtPlRectrV2"), helperEP.GetEventPlane(collision.qvecRe()[detInd + 1], collision.qvecIm()[detInd + 1], nmode), collision.cent()); + histosQA.fill(HIST("histEvtPlTwistV2"), helperEP.GetEventPlane(collision.qvecRe()[detInd + 2], collision.qvecIm()[detInd + 2], nmode), collision.cent()); + histosQA.fill(HIST("histEvtPlFinalV2"), helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode), collision.cent()); + + histosQA.fill(HIST("histEvtPlRes_SigRefAV2"), helperEP.GetResolution(helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode), helperEP.GetEventPlane(collision.qvecRe()[refAInd + 3], collision.qvecIm()[refAInd + 3], nmode), nmode), collision.cent()); + histosQA.fill(HIST("histEvtPlRes_SigRefBV2"), helperEP.GetResolution(helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode), helperEP.GetEventPlane(collision.qvecRe()[refBInd + 3], collision.qvecIm()[refBInd + 3], nmode), nmode), collision.cent()); + histosQA.fill(HIST("histEvtPlRes_RefARefBV2"), helperEP.GetResolution(helperEP.GetEventPlane(collision.qvecRe()[refAInd + 3], collision.qvecIm()[refAInd + 3], nmode), helperEP.GetEventPlane(collision.qvecRe()[refBInd + 3], collision.qvecIm()[refBInd + 3], nmode), nmode), collision.cent()); + } + } else if (nmode == cfgNmodB) { + histosQA.fill(HIST("histQvecUncorV3"), collision.qvecRe()[detInd], collision.qvecIm()[detInd], collision.cent()); + histosQA.fill(HIST("histQvecRectrV3"), collision.qvecRe()[detInd + 1], collision.qvecIm()[detInd + 1], collision.cent()); + histosQA.fill(HIST("histQvecTwistV3"), collision.qvecRe()[detInd + 2], collision.qvecIm()[detInd + 2], collision.cent()); + histosQA.fill(HIST("histQvecFinalV3"), collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], collision.cent()); + + histosQA.fill(HIST("histEvtPlUncorV3"), helperEP.GetEventPlane(collision.qvecRe()[detInd], collision.qvecIm()[detInd], nmode), collision.cent()); + histosQA.fill(HIST("histEvtPlRectrV3"), helperEP.GetEventPlane(collision.qvecRe()[detInd + 1], collision.qvecIm()[detInd + 1], nmode), collision.cent()); + histosQA.fill(HIST("histEvtPlTwistV3"), helperEP.GetEventPlane(collision.qvecRe()[detInd + 2], collision.qvecIm()[detInd + 2], nmode), collision.cent()); + histosQA.fill(HIST("histEvtPlFinalV3"), helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode), collision.cent()); + + histosQA.fill(HIST("histEvtPlRes_SigRefAV3"), helperEP.GetResolution(helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode), helperEP.GetEventPlane(collision.qvecRe()[refAInd + 3], collision.qvecIm()[refAInd + 3], nmode), nmode), collision.cent()); + histosQA.fill(HIST("histEvtPlRes_SigRefBV3"), helperEP.GetResolution(helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode), helperEP.GetEventPlane(collision.qvecRe()[refBInd + 3], collision.qvecIm()[refBInd + 3], nmode), nmode), collision.cent()); + histosQA.fill(HIST("histEvtPlRes_RefARefBV3"), helperEP.GetResolution(helperEP.GetEventPlane(collision.qvecRe()[refAInd + 3], collision.qvecIm()[refAInd + 3], nmode), helperEP.GetEventPlane(collision.qvecRe()[refBInd + 3], collision.qvecIm()[refBInd + 3], nmode), nmode), collision.cent()); + } + + if (nmode == cfgNmodA) { + double phiMinusPsi2; + if (collision.qvecAmp()[detId] < 1e-8) { + continue; + } + float ep2 = helperEP.GetEventPlane(collision.qvecRe()[detInd], collision.qvecIm()[detInd], nmode); + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + if (jet.r() != round(selectedJetsRadius * 100.0f)) { + continue; + } + registry.fill(HIST("h_jet_pt_rhoareasubtracted"), jet.pt() - (collision.rho() * jet.area()), 1.0); + registry.fill(HIST("h2_centrality_jet_pt_rhoareasubtracted"), collision.centrality(), jet.pt() - (collision.rho() * jet.area()), 1.0); + + phiMinusPsi2 = jet.phi() - ep2; + if ((phiMinusPsi2 < o2::constants::math::PIQuarter) || (phiMinusPsi2 >= evtPlnAngleA * o2::constants::math::PIQuarter) || (phiMinusPsi2 >= evtPlnAngleB * o2::constants::math::PIQuarter && phiMinusPsi2 < evtPlnAngleC * o2::constants::math::PIQuarter)) { + registry.fill(HIST("h_jet_pt_in_plane_v2"), jet.pt() - (collision.rho() * jet.area()), 1.0); + registry.fill(HIST("h2_centrality_jet_pt_in_plane_v2"), collision.centrality(), jet.pt() - (collision.rho() * jet.area()), 1.0); + } else { + registry.fill(HIST("h_jet_pt_out_of_plane_v2"), jet.pt() - (collision.rho() * jet.area()), 1.0); + registry.fill(HIST("h2_centrality_jet_pt_out_of_plane_v2"), collision.centrality(), jet.pt() - (collision.rho() * jet.area()), 1.0); + } + } + } else if (nmode == cfgNmodB) { + double phiMinusPsi3; + float ep3 = helperEP.GetEventPlane(collision.qvecRe()[detInd], collision.qvecIm()[detInd], nmode); + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + if (jet.r() != round(selectedJetsRadius * 100.0f)) { + continue; + } + phiMinusPsi3 = jet.phi() - ep3; + + if ((phiMinusPsi3 < o2::constants::math::PIQuarter) || (phiMinusPsi3 >= evtPlnAngleA * o2::constants::math::PIQuarter) || (phiMinusPsi3 >= evtPlnAngleB * o2::constants::math::PIQuarter && phiMinusPsi3 < evtPlnAngleC * o2::constants::math::PIQuarter)) { + registry.fill(HIST("h_jet_pt_in_plane_v3"), jet.pt() - (collision.rho() * jet.area()), 1.0); + registry.fill(HIST("h2_centrality_jet_pt_in_plane_v3"), collision.centrality(), jet.pt() - (collision.rho() * jet.area()), 1.0); + } else { + registry.fill(HIST("h_jet_pt_out_of_plane_v3"), jet.pt() - (collision.rho() * jet.area()), 1.0); + registry.fill(HIST("h2_centrality_jet_pt_out_of_plane_v3"), collision.centrality(), jet.pt() - (collision.rho() * jet.area()), 1.0); + } + } + } + } + } + PROCESS_SWITCH(JetChargedV2, processInOutJetV2, "Jet V2 in and out of plane", true); + + void processSigmaPt(soa::Filtered>::iterator const& collision, + soa::Join const& jets, + aod::JetTracks const& tracks) + { + registry.fill(HIST("h_collisions"), 0.5); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + registry.fill(HIST("h_collisions"), 1.5); + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + registry.fill(HIST("h_collisions"), 2.5); + double leadingJetPt = -1; + double leadingJetPhi = -1; + double leadingJetEta = -1; + for (const auto& jet : jets) { + if (jet.pt() > leadingJetPt) { + leadingJetPt = jet.pt(); + leadingJetEta = jet.eta(); + leadingJetPhi = jet.phi(); + } + } + fillLeadingJetQA(leadingJetPt, leadingJetPhi, leadingJetEta); + + int nTrk = 0; + if (jets.size() > 0) { + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection) && (std::fabs(track.eta() - leadingJetEta) > jetRadius) && track.pt() >= localRhoFitPtMin && track.pt() <= localRhoFitPtMax) { + registry.fill(HIST("h_accept_Track"), 2.5); + nTrk += 1; + } + } + registry.fill(HIST("h_evtnum_NTrk"), evtnum, nTrk); + } + + if (nTrk <= 0) { + return; + } + + hPtsumSumptFit = new TH1F("h_ptsum_sumpt_fit", "h_ptsum_sumpt fit use", TMath::CeilNint(std::sqrt(nTrk)), 0., o2::constants::math::TwoPI); + + if (jets.size() > 0) { + for (auto const& trackfit : tracks) { + registry.fill(HIST("h_accept_Track"), 0.5); + if (jetderiveddatautilities::selectTrack(trackfit, trackSelection) && (std::fabs(trackfit.eta() - leadingJetEta) > jetRadius) && trackfit.pt() >= localRhoFitPtMin && trackfit.pt() <= localRhoFitPtMax) { + registry.fill(HIST("h_accept_Track_Fit"), 0.5); + fitTrack += 1; + } + } + + for (auto const& track : tracks) { + registry.fill(HIST("h_accept_Track"), 1.5); + if (jetderiveddatautilities::selectTrack(track, trackSelection) && (std::fabs(track.eta() - leadingJetEta) > jetRadius) && track.pt() >= localRhoFitPtMin && track.pt() <= localRhoFitPtMax) { + accptTrack += 1; + registry.fill(HIST("h_accept_Track"), 2.5); + hPtsumSumptFit->Fill(track.phi(), track.pt()); + registry.fill(HIST("h2_phi_track_eta"), track.eta(), track.phi()); + registry.fill(HIST("h_ptsum_sumpt"), track.phi(), track.pt()); + registry.fill(HIST("h2_centrality_phi_w_pt"), collision.centrality(), track.phi(), track.pt()); + registry.fill(HIST("h2_evtnum_phi_w_pt"), evtnum, track.phi(), track.pt()); + registry.fill(HIST("Thn_evtnum_phi_centrality"), evtnum, track.phi(), collision.centrality()); + registry.fill(HIST("h_accept_Track_init"), accptTrack); + registry.fill(HIST("h_accept_Track_Fit"), 1.5); + } + } + } + registry.fill(HIST("h_ptsum_collnum"), 0.5); + + double ep2 = 0.; + double ep3 = 0.; + int cfgNmodA = 2; + int cfgNmodB = 3; + int evtPlnAngleA = 7; + int evtPlnAngleB = 3; + int evtPlnAngleC = 5; + for (uint i = 0; i < cfgnMods->size(); i++) { + int nmode = cfgnMods->at(i); + int detInd = detId * 4 + cfgnTotalSystem * 4 * (nmode - 2); + if (nmode == cfgNmodA) { + if (collision.qvecAmp()[detId] > 1e-8) { + ep2 = helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode); + } + } else if (nmode == cfgNmodB) { + if (collision.qvecAmp()[detId] > 1e-8) { + ep3 = helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode); + } + } + } + + TF1* fFitModulationV2v3 = 0x0; + const char* fitFunctionV2v3 = "[0] * (1. + 2. * ([1] * std::cos(2. * (x - [2])) + [3] * std::cos(3. * (x - [4]))))"; + fFitModulationV2v3 = new TF1("fit_kV3", fitFunctionV2v3, 0, o2::constants::math::TwoPI); + //=========================< set parameter >=========================// + fFitModulationV2v3->SetParameter(0, 1.); + fFitModulationV2v3->SetParameter(1, 0.01); + fFitModulationV2v3->SetParameter(3, 0.01); + + double ep2fix = 0.; + double ep3fix = 0.; + + if (ep2 < 0) { + ep2fix = RecoDecay::constrainAngle(ep2); + fFitModulationV2v3->FixParameter(2, ep2fix); + } else { + fFitModulationV2v3->FixParameter(2, ep2); + } + if (ep3 < 0) { + ep3fix = RecoDecay::constrainAngle(ep3); + fFitModulationV2v3->FixParameter(4, ep3fix); + } else { + fFitModulationV2v3->FixParameter(4, ep3); + } + + hPtsumSumptFit->Fit(fFitModulationV2v3, "Q", "ep", 0, o2::constants::math::TwoPI); + + double temppara[5]; + temppara[0] = fFitModulationV2v3->GetParameter(0); + temppara[1] = fFitModulationV2v3->GetParameter(1); + temppara[2] = fFitModulationV2v3->GetParameter(2); + temppara[3] = fFitModulationV2v3->GetParameter(3); + temppara[4] = fFitModulationV2v3->GetParameter(4); + int paraNum = 5; + for (int i = 1; i <= paraNum; i++) { + registry.fill(HIST("h2_evt_fitpara"), evtnum, i - 0.5, temppara[i - 1]); + } + + registry.fill(HIST("h_fitparaRho_evtnum"), evtnum, temppara[0]); + registry.fill(HIST("h_fitparav2obs_evtnum"), evtnum, temppara[1]); + registry.fill(HIST("h_fitparaPsi2_evtnum"), evtnum, temppara[2]); + registry.fill(HIST("h_fitparav3obs_evtnum"), evtnum, temppara[3]); + registry.fill(HIST("h_fitparaPsi3_evtnum"), evtnum, temppara[4]); + + registry.fill(HIST("h_v2obs_centrality"), collision.centrality(), temppara[1]); + registry.fill(HIST("h_v3obs_centrality"), collision.centrality(), temppara[3]); + registry.fill(HIST("h_evtnum_centrlity"), evtnum, collision.centrality()); + + if (temppara[0] == 0) { + return; + } + registry.fill(HIST("h2_fitParaZero_cent"), collision.centrality(), temppara[0], 1.0); + + int nDF = 1; + int numOfFreePara = 2; + nDF = static_cast(fFitModulationV2v3->GetXaxis()->GetNbins()) - numOfFreePara; + if (nDF == 0 || static_cast(nDF) <= 0.) + return; + double chi2 = 0.; + for (int i = 0; i < hPtsumSumptFit->GetXaxis()->GetNbins(); i++) { + if (hPtsumSumptFit->GetBinContent(i + 1) <= 0.) + continue; + chi2 += std::pow((hPtsumSumptFit->GetBinContent(i + 1) - fFitModulationV2v3->Eval(hPtsumSumptFit->GetXaxis()->GetBinCenter(1 + i))), 2) / hPtsumSumptFit->GetBinContent(i + 1); + } + + double chiSqr = 999.; + double cDF = 1.; + + chiSqr = chi2; + cDF = 1. - chiSquareCDF(nDF, chiSqr); + + registry.fill(HIST("h_PvalueCDF_CombinFit"), cDF); + registry.fill(HIST("h2_PvalueCDFCent_CombinFit"), collision.centrality(), cDF); + registry.fill(HIST("h2_Chi2Cent_CombinFit"), collision.centrality(), chiSqr / (static_cast(nDF))); + registry.fill(HIST("h2_PChi2_CombinFit"), cDF, chiSqr / (static_cast(nDF))); + registry.fill(HIST("Thn_PChi2_CombinFitCent"), collision.centrality(), cDF, chiSqr / (static_cast(nDF))); + double evtcent = collision.centrality(); + int evtCentAreaMin = 0; + int evtCentAreaMax = 5; + int evtMidAreaMin = 30; + int evtMidAreaMax = 50; + if (evtcent >= evtCentAreaMin && evtcent <= evtCentAreaMax) { + registry.fill(HIST("h2_PChi2_CombinFitA"), cDF, chiSqr / (static_cast(nDF))); + } else if (evtcent >= evtMidAreaMin && evtcent <= evtMidAreaMax) { + registry.fill(HIST("h2_PChi2_CombinFitB"), cDF, chiSqr / (static_cast(nDF))); + } + for (uint i = 0; i < cfgnMods->size(); i++) { + int nmode = cfgnMods->at(i); + int detInd = detId * 4 + cfgnTotalSystem * 4 * (nmode - 2); + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + if (jet.r() != round(selectedJetsRadius * 100.0f)) { + continue; + } + + double integralValue = fFitModulationV2v3->Integral(jet.phi() - jetRadius, jet.phi() + jetRadius); + double rholocal = collision.rho() / (2 * jetRadius * temppara[0]) * integralValue; + registry.fill(HIST("h2_phi_rhophi"), jet.phi() - ep2, fFitModulationV2v3->Eval(jet.phi()), 1.0); + registry.fill(HIST("h3_centrality_rhovsphi_phi"), collision.centrality(), fFitModulationV2v3->Eval(jet.phi()), jet.phi() - ep2); + + registry.fill(HIST("h2_phi_rholocal_cent"), collision.centrality(), rholocal, 1.0); + registry.fill(HIST("h3_centrality_localrho_phi"), collision.centrality(), rholocal, jet.phi() - ep2); + + if (nmode == cfgNmodA) { + registry.fill(HIST("h_jet_pt_rholocal"), jet.pt() - (rholocal * jet.area()), 1.0); + + double phiMinusPsi2; + if (collision.qvecAmp()[detId] < 1e-8) { + continue; + } + phiMinusPsi2 = jet.phi() - ep2; + + registry.fill(HIST("h2_phi_rholocal"), jet.phi() - ep2, rholocal, 1.0); + registry.fill(HIST("h_jet_pt_inclusive_v2_rho"), jet.pt() - (rholocal * jet.area()), 1.0); + + if ((phiMinusPsi2 < o2::constants::math::PIQuarter) || (phiMinusPsi2 >= evtPlnAngleA * o2::constants::math::PIQuarter) || (phiMinusPsi2 >= evtPlnAngleB * o2::constants::math::PIQuarter && phiMinusPsi2 < evtPlnAngleC * o2::constants::math::PIQuarter)) { + registry.fill(HIST("h_jet_pt_in_plane_v2_rho"), jet.pt() - (rholocal * jet.area()), 1.0); + registry.fill(HIST("h2_centrality_jet_pt_in_plane_v2_rho"), collision.centrality(), jet.pt() - (rholocal * jet.area()), 1.0); + } else { + registry.fill(HIST("h_jet_pt_out_of_plane_v2_rho"), jet.pt() - (rholocal * jet.area()), 1.0); + registry.fill(HIST("h2_centrality_jet_pt_out_of_plane_v2_rho"), collision.centrality(), jet.pt() - (rholocal * jet.area()), 1.0); + } + } else if (nmode == cfgNmodB) { + double phiMinusPsi3; + if (collision.qvecAmp()[detId] < 1e-8) { + continue; + } + ep3 = helperEP.GetEventPlane(collision.qvecRe()[detInd], collision.qvecIm()[detInd], nmode); + phiMinusPsi3 = jet.phi() - ep3; + + if ((phiMinusPsi3 < o2::constants::math::PIQuarter) || (phiMinusPsi3 >= evtPlnAngleA * o2::constants::math::PIQuarter) || (phiMinusPsi3 >= evtPlnAngleB * o2::constants::math::PIQuarter && phiMinusPsi3 < evtPlnAngleC * o2::constants::math::PIQuarter)) { + registry.fill(HIST("h_jet_pt_in_plane_v3_rho"), jet.pt() - (rholocal * jet.area()), 1.0); + registry.fill(HIST("h2_centrality_jet_pt_in_plane_v3_rho"), collision.centrality(), jet.pt() - (rholocal * jet.area()), 1.0); + } else { + registry.fill(HIST("h_jet_pt_out_of_plane_v3_rho"), jet.pt() - (rholocal * jet.area()), 1.0); + registry.fill(HIST("h2_centrality_jet_pt_out_of_plane_v3_rho"), collision.centrality(), jet.pt() - (rholocal * jet.area()), 1.0); + } + } + } + } + // RCpT + for (uint i = 0; i < cfgnMods->size(); i++) { + TRandom3 randomNumber(0); + float randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); + float randomConePhi = randomNumber.Uniform(0.0, o2::constants::math::TwoPI); + float randomConePt = 0; + double integralValueRC = fFitModulationV2v3->Integral(randomConePhi - randomConeR, randomConePhi + randomConeR); + double rholocalRC = collision.rho() / (2 * randomConeR * temppara[0]) * integralValueRC; + + int nmode = cfgnMods->at(i); + if (nmode == cfgNmodA) { + double rcPhiPsi2; + rcPhiPsi2 = randomConePhi - ep2; + + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-o2::constants::math::PI)); + float dEta = track.eta() - randomConeEta; + if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePt += track.pt(); + } + } + } + registry.fill(HIST("h3_centrality_deltapT_RandomCornPhi_localrhovsphi"), collision.centrality(), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * rholocalRC, rcPhiPsi2, 1.0); + + // removing the leading jet from the random cone + if (jets.size() > 0) { // if there are no jets in the acceptance (from the jetfinder cuts) then there can be no leading jet + float leadingJetEta = jets.iteratorAt(0).eta(); + float leadingJetPhi = jets.iteratorAt(0).phi(); + float etaBandWidth = 2 * randomConeR; + + bool jetWasInCone = false; + do { + randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); + randomConePhi = randomNumber.Uniform(0.0, o2::constants::math::TwoPI); + + float dEta = randomConeEta - leadingJetEta; + float dPhi = RecoDecay::constrainAngle(randomConePhi - leadingJetPhi, static_cast(-o2::constants::math::PI)); + + if (std::abs(dEta) > etaBandWidth && std::sqrt(dEta * dEta + dPhi * dPhi) > randomConeR + jets.iteratorAt(0).r() / 100.0) { + break; + } + jetWasInCone = true; + } while (true); + + if (jetWasInCone) { + randomConePt = 0.0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { // if track selection is uniformTrack, dcaXY and dcaZ cuts need to be added as they aren't in the selection so that they can be studied here + float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-o2::constants::math::PI)); + float dEta = track.eta() - randomConeEta; + if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePt += track.pt(); + } + } + } + } + } + registry.fill(HIST("h3_centrality_deltapT_RandomCornPhi_localrhovsphiwithoutleadingjet"), collision.centrality(), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * rholocalRC, rcPhiPsi2, 1.0); + registry.fill(HIST("h3_centrality_deltapT_RandomCornPhi_rhorandomconewithoutleadingjet"), collision.centrality(), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho(), rcPhiPsi2, 1.0); + } else if (nmode == cfgNmodB) { + continue; + } + } + delete hPtsumSumptFit; + evtnum += 1; + } + PROCESS_SWITCH(JetChargedV2, processSigmaPt, "Sigma pT and bkg as fcn of phi", true); + + void processRandomConeDataV2(soa::Filtered>::iterator const& collision, + soa::Join const& jets, + soa::Filtered const& tracks) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + + for (uint i = 0; i < cfgnMods->size(); i++) { + TRandom3 randomNumber(0); + float randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); + float randomConePhi = randomNumber.Uniform(0.0, o2::constants::math::TwoPI); + float randomConePt = 0; + + int nmode = cfgnMods->at(i); + int detInd = detId * 4 + cfgnTotalSystem * 4 * (nmode - 2); + int cfgNmodA = 2; + int cfgNmodB = 3; + if (nmode == cfgNmodA) { + double rcPhiPsi2; + float evtPl2 = helperEP.GetEventPlane(collision.qvecRe()[detInd], collision.qvecIm()[detInd], nmode); + rcPhiPsi2 = randomConePhi - evtPl2; + + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-o2::constants::math::PI)); + float dEta = track.eta() - randomConeEta; + if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePt += track.pt(); + } + } + } + // removing the leading jet from the random cone + if (jets.size() > 0) { // if there are no jets in the acceptance (from the jetfinder cuts) then there can be no leading jet + float dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, static_cast(-o2::constants::math::PI)); + float dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; + + bool jetWasInCone = false; + while (std::sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < jets.iteratorAt(0).r() / 100.0 + randomConeR) { + jetWasInCone = true; + randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); + randomConePhi = randomNumber.Uniform(0.0, o2::constants::math::TwoPI); + dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, static_cast(-o2::constants::math::PI)); + dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; + } + if (jetWasInCone) { + randomConePt = 0.0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-o2::constants::math::PI)); + float dEta = track.eta() - randomConeEta; + if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePt += track.pt(); + } + } + } + } + } + registry.fill(HIST("h2_centrality_deltapT_RandomCornPhi_RCprocess_rhorandomconewithoutleadingjet"), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho(), rcPhiPsi2, 1.0); + } else if (nmode == cfgNmodB) { + continue; + } + } + } + PROCESS_SWITCH(JetChargedV2, processRandomConeDataV2, "QA for random cone estimation of background fluctuations in data", true); + + void processTracksQA(soa::Filtered>::iterator const& collision, + soa::Filtered> const& tracks) + { + registry.fill(HIST("h_collisions"), 0.5); + registry.fill(HIST("h2_centrality_collisions"), collision.centrality(), 0.5); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + registry.fill(HIST("h_collisions"), 1.5); + registry.fill(HIST("h2_centrality_collisions"), collision.centrality(), 1.5); + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + registry.fill(HIST("h_collisions"), 2.5); + registry.fill(HIST("h2_centrality_collisions"), collision.centrality(), 2.5); + fillTrackHistograms(collision, tracks); + } + PROCESS_SWITCH(JetChargedV2, processTracksQA, "QA for charged tracks", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGJE/Tasks/jetFinderBplusQA.cxx b/PWGJE/Tasks/jetFinderBplusQA.cxx new file mode 100644 index 00000000000..4b7c42b4580 --- /dev/null +++ b/PWGJE/Tasks/jetFinderBplusQA.cxx @@ -0,0 +1,27 @@ +// 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. + +// jet finder B+ charged QA task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetFinderHFQA.cxx" + +using JetFinderBplusQATask = JetFinderHFQATask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-finder-charged-bplus-qa"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetFinderD0QA.cxx b/PWGJE/Tasks/jetFinderD0QA.cxx new file mode 100644 index 00000000000..2db58308d87 --- /dev/null +++ b/PWGJE/Tasks/jetFinderD0QA.cxx @@ -0,0 +1,27 @@ +// 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. + +// jet finder D0 charged QA task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetFinderHFQA.cxx" + +using JetFinderD0QATask = JetFinderHFQATask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-finder-charged-d0-qa"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetFinderDielectronQA.cxx b/PWGJE/Tasks/jetFinderDielectronQA.cxx new file mode 100644 index 00000000000..516f4501a7b --- /dev/null +++ b/PWGJE/Tasks/jetFinderDielectronQA.cxx @@ -0,0 +1,27 @@ +// 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. + +// jet finder Dielectron charged QA task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetFinderHFQA.cxx" + +using JetFinderDielectronQATask = JetFinderHFQATask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-finder-charged-dielectron-qa"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetFinderDplusQA.cxx b/PWGJE/Tasks/jetFinderDplusQA.cxx new file mode 100644 index 00000000000..bf5468eae57 --- /dev/null +++ b/PWGJE/Tasks/jetFinderDplusQA.cxx @@ -0,0 +1,27 @@ +// 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. + +// jet finder D+ charged QA task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetFinderHFQA.cxx" + +using JetFinderDplusQATask = JetFinderHFQATask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-finder-charged-dplus-qa"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetfinderfullQA.cxx b/PWGJE/Tasks/jetFinderFullQA.cxx similarity index 82% rename from PWGJE/Tasks/jetfinderfullQA.cxx rename to PWGJE/Tasks/jetFinderFullQA.cxx index 8878e772dbe..9b01d787959 100644 --- a/PWGJE/Tasks/jetfinderfullQA.cxx +++ b/PWGJE/Tasks/jetFinderFullQA.cxx @@ -54,6 +54,7 @@ struct JetFinderFullQATask { Configurable trackPtMax{"trackPtMax", 100.0, "maximum pT acceptance for tracks"}; Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + Configurable jetPtMax{"jetPtMax", 200., "set jet pT bin max"}; Configurable jetEtaMin{"jetEtaMin", -99.0, "minimum jet pseudorapidity"}; Configurable jetEtaMax{"jetEtaMax", 99.0, "maximum jet pseudorapidity"}; Configurable jetAreaFractionMin{"jetAreaFractionMin", -99.0, "used to make a cut on the jet areas"}; @@ -73,12 +74,16 @@ struct JetFinderFullQATask { Configurable pTHatMaxMCD{"pTHatMaxMCD", 999.0, "maximum fraction of hard scattering for jet acceptance in detector MC"}; Configurable pTHatMaxMCP{"pTHatMaxMCP", 999.0, "maximum fraction of hard scattering for jet acceptance in particle MC"}; Configurable pTHatExponent{"pTHatExponent", 6.0, "exponent of the event weight for the calculation of pTHat"}; + Configurable pTHatAbsoluteMin{"pTHatAbsoluteMin", -99.0, "minimum value of pTHat"}; + Configurable skipMBGapEvents{"skipMBGapEvents", false, "flag to choose to reject min. bias gap events; jet-level rejection applied at the jet finder level, here rejection is applied for collision and track process functions"}; std::vector filledJetR; std::vector jetRadiiValues; int trackSelection = -1; + std::vector jetPtBins; + Service pdgDatabase; void init(o2::framework::InitContext&) @@ -97,105 +102,125 @@ struct JetFinderFullQATask { jetRadiiBins.push_back(jetRadiiBins[jetRadiiBins.size() - 1] + 0.1); } + auto jetPtTemp = 0.0; + jetPtBins.push_back(jetPtTemp); + while (jetPtTemp < jetPtMax) { + if (jetPtTemp < 100.0) { + jetPtTemp += 1.0; + jetPtBins.push_back(jetPtTemp); + } else if (jetPtTemp < 200.0) { + jetPtTemp += 5.0; + jetPtBins.push_back(jetPtTemp); + + } else { + jetPtTemp += 10.0; + jetPtBins.push_back(jetPtTemp); + } + } + + AxisSpec jetPtAxis = {jetPtBins, "#it{p}_{T} (GeV/#it{c})"}; + if (doprocessJetsData || doprocessJetsMCD || doprocessJetsMCDWeighted) { - registry.add("h_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); - registry.add("h_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxis}}); + registry.add("h_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{500, -5.0, 5.0}}}); registry.add("h_jet_phi", "jet #varphi;#varphi_{jet};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_jet_ntracks", "jet N tracks;N_{jet tracks};entries", {HistType::kTH1F, {{200, -0.5, 199.5}}}); registry.add("h_jet_nclusters", "jet N clusters;N_{jet clusters};entries", {HistType::kTH1F, {{200, -0.5, 199.5}}}); - registry.add("h2_centrality_jet_pt", "centrality vs #it{p}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, 0., 200.}}}); - registry.add("h2_centrality_jet_eta", "centrality vs #eta_{jet}; centrality; #eta_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, -1.0, 1.0}}}); + registry.add("h2_centrality_jet_pt", "centrality vs #it{p}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, jetPtAxis}}); + registry.add("h2_centrality_jet_eta", "centrality vs #eta_{jet}; centrality; #eta_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {500, -5.0, 5.0}}}); registry.add("h2_centrality_jet_phi", "centrality vs #varphi_{jet}; centrality; #varphi_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {160, -1.0, 7.}}}); registry.add("h2_centrality_jet_ntracks", "centrality vs N_{jet tracks}; centrality; N_{jet tracks}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, -0.5, 199.5}}}); registry.add("h2_centrality_jet_nclusters", "centrality vs N_{jet clusters}; centrality; N_{jet clusters}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_centrality", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});centrality", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {1200, -10.0, 110.0}}}); - registry.add("h3_jet_r_jet_pt_jet_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_jet_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_eta_jet_phi", "#it{R}_{jet};#eta_{jet};#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_jet_ntracks", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_jet_nclusters", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});N_{jet clusters}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_jet_neutralenergyfraction", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});E_{neutral}/E_{total}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {120, 0.0, 1.2}}}); - registry.add("h3_jet_r_jet_pt_jet_area", "#it{R}_{jet}; #it{p}_{T,jet} (GeV/#it{c}); #it{area}_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {300, 0., 3.}}}); - registry.add("h3_jet_r_jet_pt_track_pt", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_track_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_track_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_cluster_pt", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,cluster} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_cluster_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{cluster}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_cluster_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{cluster}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_cluster_energy", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});E_{cluster} (GeV)", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.0}}}); + registry.add("h3_jet_r_jet_pt_centrality", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});centrality", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1200, -10.0, 110.0}}}); + registry.add("h3_jet_r_jet_pt_jet_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_jet_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_eta_jet_phi", "#it{R}_{jet};#eta_{jet};#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_jet_ntracks", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, -0.5, 199.5}}}); + registry.add("h3_jet_r_jet_pt_jet_nclusters", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});N_{jet clusters}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, -0.5, 199.5}}}); + registry.add("h3_jet_r_jet_pt_jet_neutralenergyfraction", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});E_{neutral}/E_{total}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {120, 0.0, 1.2}}}); + registry.add("h3_jet_r_jet_pt_jet_area", "#it{R}_{jet}; #it{p}_{T,jet} (GeV/#it{c}); #it{area}_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {300, 0., 3.}}}); + registry.add("h3_jet_r_jet_pt_track_pt", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_track_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_track_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_cluster_pt", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,cluster} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_cluster_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{cluster}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_cluster_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{cluster}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_cluster_energy", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});E_{cluster} (GeV)", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h_jet_phat_weighted", "jet #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0, 350}}}); } if (doprocessJetsMCP || doprocessJetsMCPWeighted) { - registry.add("h_jet_pt_part", "jet pT;#it{p}_{T,jet}^{part}(GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); - registry.add("h_jet_eta_part", "jet #eta;#eta_{jet}^{part};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_jet_pt_part", "jet pT;#it{p}_{T,jet}^{part}(GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxis}}); + registry.add("h_jet_eta_part", "jet #eta;#eta_{jet}^{part};entries", {HistType::kTH1F, {{500, -5.0, 5.0}}}); registry.add("h_jet_phi_part", "jet #varphi;#varphi_{jet}^{part};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_jet_ntracks_part", "jet N tracks;N_{jet tracks}^{part};entries", {HistType::kTH1F, {{200, -0.5, 199.5}}}); - registry.add("h3_jet_r_part_jet_pt_part_jet_eta_part", ";#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#eta_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_part_jet_pt_part_jet_phi_part", ";#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#varphi_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_part_jet_eta_part_jet_phi_part", ";#it{R}_{jet}^{part};#eta_{jet}^{part};#varphi_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_part_jet_pt_part_jet_ntracks_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});N_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_part_jet_pt_part_jet_neutralenergyfraction_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});E_{neutral}^{part}/E_{total}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {120, 0.0, 1.2}}}); - registry.add("h3_jet_r_part_jet_pt_part_track_pt_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#it{p}_{T,jet tracks}^{part} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_part_jet_pt_part_track_eta_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#eta_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_part_jet_pt_part_track_phi_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#varphi_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_part_jet_pt_part_jet_eta_part", ";#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#eta_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_part_jet_pt_part_jet_phi_part", ";#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#varphi_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_part_jet_eta_part_jet_phi_part", ";#it{R}_{jet}^{part};#eta_{jet}^{part};#varphi_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_part_jet_pt_part_jet_ntracks_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});N_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, -0.5, 199.5}}}); + registry.add("h3_jet_r_part_jet_pt_part_jet_neutralenergyfraction_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});E_{neutral}^{part}/E_{total}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {120, 0.0, 1.2}}}); + registry.add("h3_jet_r_part_jet_pt_part_track_pt_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#it{p}_{T,jet tracks}^{part} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_part_jet_pt_part_track_eta_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#eta_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_part_jet_pt_part_track_phi_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#varphi_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h_jet_phat_part_weighted", "jet #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{1000, 0, 1000}}}); } if (doprocessJetsMCPMCDMatched || doprocessJetsMCPMCDMatchedWeighted) { - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeo", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeo", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetPtAxis}}); + registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeo", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeo", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); registry.add("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeo", "#it{R}_{jet};N_{jet tracks}^{tag};N_{jet tracks}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_cluster_pt_tag_cluster_pt_base_matchedgeo", "#it{R}_{jet};#it{p}_{T,cluster}^{tag} (GeV/#it{c});#it{p}_{T,cluster}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_cluster_eta_tag_cluster_eta_base_matchedgeo", "#it{R}_{jet};#eta_{cluster}^{tag};#eta_{cluster}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_cluster_pt_tag_cluster_pt_base_matchedgeo", "#it{R}_{jet};#it{p}_{T,cluster}^{tag} (GeV/#it{c});#it{p}_{T,cluster}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_cluster_eta_tag_cluster_eta_base_matchedgeo", "#it{R}_{jet};#eta_{cluster}^{tag};#eta_{cluster}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); registry.add("h3_jet_r_cluster_phi_tag_cluster_phi_base_matchedgeo", "#it{R}_{jet};#varphi_{cluster}^{tag};#varphi_{cluster}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_cluster_energy_tag_cluster_energy_base_matchedgeo", "#it{R}_{jet};#E_{cluster}^{tag};#E_{cluster}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); - - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedpt", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedpt", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_cluster_energy_tag_cluster_energy_base_matchedgeo", "#it{R}_{jet};#E_{cluster}^{tag};#E_{cluster}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {160, -1.0, 7.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {jetPtAxis, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); + + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetPtAxis}}); + registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedpt", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedpt", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); registry.add("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedpt", "#it{R}_{jet};N_{jet tracks}^{tag};N_{jet tracks}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); registry.add("h3_jet_r_cluster_pt_tag_cluster_pt_base_matchedpt", "#it{R}_{jet};#it{p}_{T,cluster}^{tag} (GeV/#it{c});#it{p}_{T,cluster}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_cluster_eta_tag_cluster_eta_base_matchedpt", "#it{R}_{jet};#eta_{cluster}^{tag};#eta_{cluster}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_cluster_eta_tag_cluster_eta_base_matchedpt", "#it{R}_{jet};#eta_{cluster}^{tag};#eta_{cluster}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); registry.add("h3_jet_r_cluster_phi_tag_cluster_phi_base_matchedpt", "#it{R}_{jet};#varphi_{cluster}^{tag};#varphi_{cluster}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_cluster_energy_tag_cluster_energy_base_matchedpt", "#it{R}_{jet};#E_{cluster}^{tag};#E_{cluster}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); - - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeopt", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeopt", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_cluster_energy_tag_cluster_energy_base_matchedpt", "#it{R}_{jet};#E_{cluster}^{tag};#E_{cluster}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {160, -1.0, 7.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {jetPtAxis, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); + + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetPtAxis}}); + registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeopt", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeopt", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); registry.add("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeopt", "#it{R}_{jet};N_{jet tracks}^{tag};N_{jet tracks}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); registry.add("h3_jet_r_cluster_pt_tag_cluster_pt_base_matchedgeopt", "#it{R}_{jet};#it{p}_{T,cluster}^{tag} (GeV/#it{c});#it{p}_{T,cluster}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_cluster_eta_tag_cluster_eta_base_matchedgeopt", "#it{R}_{jet};#eta_{cluster}^{tag};#eta_{cluster}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_cluster_eta_tag_cluster_eta_base_matchedgeopt", "#it{R}_{jet};#eta_{cluster}^{tag};#eta_{cluster}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); registry.add("h3_jet_r_cluster_phi_tag_cluster_phi_base_matchedgeopt", "#it{R}_{jet};#varphi_{cluster}^{tag};#varphi_{cluster}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_cluster_energy_tag_cluster_energy_base_matchedgeopt", "#it{R}_{jet};#E_{cluster}^{tag};#E_{cluster}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); + registry.add("h3_jet_r_cluster_energy_tag_cluster_energy_base_matchedgeopt", "#it{R}_{jet};#E_{cluster}^{tag};#E_{cluster}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {160, -1.0, 7.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {jetPtAxis, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); } if (doprocessTracks || doprocessTracksWeighted) { registry.add("h_collisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); registry.add("h_centrality_collisions", "centrality vs collisions; centrality, collisions", {HistType::kTH2F, {{1200, -10.0, 110.0}, {4, 0.0, 4.0}}}); registry.add("h_track_pt", "track pT;#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); - registry.add("h_track_eta", "track #eta;#eta_{track};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_track_eta", "track #eta;#eta_{track};entries", {HistType::kTH1F, {{500, -5.0, 5.0}}}); registry.add("h_track_phi", "track #varphi;#varphi_{track};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_track_energy", "track energy;Energy GeV ;entries", {HistType::kTH1F, {{100, 0.0, 100.0}}}); registry.add("h_cluster_pt", "cluster pT;#it{p}_{T,cluster} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); - registry.add("h_cluster_eta", "cluster #eta;#eta_{cluster};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_cluster_eta", "cluster #eta;#eta_{cluster};entries", {HistType::kTH1F, {{500, -5.0, 5.0}}}); registry.add("h_cluster_phi", "cluster #varphi;#varphi_{cluster};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_cluster_energy", "cluster E;E_{cluster} (GeV);entries", {HistType::kTH1F, {{200, 0., 200.}}}); if (doprocessTracksWeighted) { @@ -254,9 +279,10 @@ struct JetFinderFullQATask { { float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); - if (jet.pt() > pTHatMaxMCD * pTHat) { + if (jet.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { return; } + registry.fill(HIST("h_jet_phat_weighted"), pTHat, weight); float neutralEnergy = 0.0; if (jet.r() == round(selectedJetsRadius * 100.0f)) { @@ -280,14 +306,14 @@ struct JetFinderFullQATask { registry.fill(HIST("h3_jet_r_jet_pt_jet_nclusters"), jet.r() / 100.0, jet.pt(), jet.clustersIds().size(), weight); registry.fill(HIST("h3_jet_r_jet_pt_jet_area"), jet.r() / 100.0, jet.pt(), jet.area(), weight); - for (auto& constituent : jet.template tracks_as()) { + for (auto& constituent : jet.template tracks_as()) { registry.fill(HIST("h3_jet_r_jet_pt_track_pt"), jet.r() / 100.0, jet.pt(), constituent.pt(), weight); registry.fill(HIST("h3_jet_r_jet_pt_track_eta"), jet.r() / 100.0, jet.pt(), constituent.eta(), weight); registry.fill(HIST("h3_jet_r_jet_pt_track_phi"), jet.r() / 100.0, jet.pt(), constituent.phi(), weight); } - for (auto& cluster : jet.template clusters_as()) { + for (auto& cluster : jet.template clusters_as()) { double clusterpt = cluster.energy() / std::cosh(cluster.eta()); neutralEnergy += cluster.energy(); registry.fill(HIST("h3_jet_r_jet_pt_cluster_pt"), jet.r() / 100.0, jet.pt(), clusterpt, weight); @@ -303,9 +329,10 @@ struct JetFinderFullQATask { { float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); - if (jet.pt() > pTHatMaxMCP * pTHat) { + if (jet.pt() > pTHatMaxMCP * pTHat || pTHat < pTHatAbsoluteMin) { return; } + registry.fill(HIST("h_jet_phat_part_weighted"), pTHat, weight); float neutralEnergy = 0.0; if (jet.r() == round(selectedJetsRadius * 100.0f)) { @@ -320,7 +347,7 @@ struct JetFinderFullQATask { registry.fill(HIST("h3_jet_r_part_jet_eta_part_jet_phi_part"), jet.r() / 100.0, jet.eta(), jet.phi(), weight); registry.fill(HIST("h3_jet_r_part_jet_pt_part_jet_ntracks_part"), jet.r() / 100.0, jet.pt(), jet.tracksIds().size(), weight); - for (auto& constituent : jet.template tracks_as()) { + for (auto& constituent : jet.template tracks_as()) { auto pdgParticle = pdgDatabase->GetParticle(constituent.pdgCode()); if (pdgParticle->Charge() == 0) { neutralEnergy += constituent.e(); @@ -337,7 +364,7 @@ struct JetFinderFullQATask { { float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); - if (jetBase.pt() > pTHatMaxMCD * pTHat) { + if (jetBase.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { return; } @@ -410,6 +437,10 @@ struct JetFinderFullQATask { template void fillTrackHistograms(T const& tracks, U const& clusters, float weight = 1.0) { + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (pTHat < pTHatAbsoluteMin) { + return; + } for (auto const& track : tracks) { if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { continue; @@ -428,18 +459,18 @@ struct JetFinderFullQATask { } } - void processDummy(JetCollisions const&) + void processDummy(aod::JetCollisions const&) { } PROCESS_SWITCH(JetFinderFullQATask, processDummy, "dummy task", true); - void processJetsData(soa::Filtered::iterator const& collision, JetTableDataJoined const& jets, JetTracks const&, JetClusters const&) + void processJetsData(soa::Filtered::iterator const& collision, JetTableDataJoined const& jets, aod::JetTracks const&, aod::JetClusters const&) { for (auto const& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { continue; } fillHistograms(jet, collision.centrality()); @@ -447,13 +478,13 @@ struct JetFinderFullQATask { } PROCESS_SWITCH(JetFinderFullQATask, processJetsData, "jet finder HF QA data", false); - void processJetsMCD(soa::Filtered::iterator const& collision, JetTableMCDJoined const& jets, JetTracks const&, JetClusters const&) + void processJetsMCD(soa::Filtered::iterator const& collision, JetTableMCDJoined const& jets, aod::JetTracks const&, aod::JetClusters const&) { for (auto const& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { continue; } fillHistograms(jet, collision.centrality()); @@ -461,13 +492,13 @@ struct JetFinderFullQATask { } PROCESS_SWITCH(JetFinderFullQATask, processJetsMCD, "jet finder HF QA mcd", false); - void processJetsMCDWeighted(soa::Filtered::iterator const& collision, JetTableMCDWeightedJoined const& jets, JetTracks const&, JetClusters const&) + void processJetsMCDWeighted(soa::Filtered::iterator const& collision, JetTableMCDWeightedJoined const& jets, aod::JetTracks const&, aod::JetClusters const&) { for (auto const& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { continue; } fillHistograms(jet, collision.centrality(), jet.eventWeight()); @@ -475,43 +506,43 @@ struct JetFinderFullQATask { } PROCESS_SWITCH(JetFinderFullQATask, processJetsMCDWeighted, "jet finder HF QA mcd on weighted events", false); - void processJetsMCP(typename JetTableMCPJoined::iterator const& jet, JetParticles const&) + void processJetsMCP(typename JetTableMCPJoined::iterator const& jet, aod::JetParticles const&) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { return; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { return; } fillMCPHistograms(jet); } PROCESS_SWITCH(JetFinderFullQATask, processJetsMCP, "jet finder HF QA mcp", false); - void processJetsMCPWeighted(typename JetTableMCPWeightedJoined::iterator const& jet, JetParticles const&) + void processJetsMCPWeighted(typename JetTableMCPWeightedJoined::iterator const& jet, aod::JetParticles const&) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { return; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { return; } fillMCPHistograms(jet, jet.eventWeight()); } PROCESS_SWITCH(JetFinderFullQATask, processJetsMCPWeighted, "jet finder HF QA mcp on weighted events", false); - void processJetsMCPMCDMatched(JetCollision const&, + void processJetsMCPMCDMatched(aod::JetCollision const&, JetTableMCDMatchedJoined const& mcdjets, JetTableMCPMatchedJoined const&, - JetTracks const&, - JetClusters const&, - JetParticles const&) + aod::JetTracks const&, + aod::JetClusters const&, + aod::JetParticles const&) { for (const auto& mcdjet : mcdjets) { if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(mcdjet)) { + if (!isAcceptedJet(mcdjet)) { continue; } fillMatchedHistograms(mcdjet); @@ -519,19 +550,19 @@ struct JetFinderFullQATask { } PROCESS_SWITCH(JetFinderFullQATask, processJetsMCPMCDMatched, "jet finder HF QA matched mcp and mcd", false); - void processJetsMCPMCDMatchedWeighted(JetCollision const&, + void processJetsMCPMCDMatchedWeighted(aod::JetCollision const&, JetTableMCDMatchedWeightedJoined const& mcdjets, JetTableMCPMatchedWeightedJoined const&, - JetTracks const&, - JetClusters const&, - JetParticles const&) + aod::JetTracks const&, + aod::JetClusters const&, + aod::JetParticles const&) { for (const auto& mcdjet : mcdjets) { if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(mcdjet)) { + if (!isAcceptedJet(mcdjet)) { continue; } fillMatchedHistograms(mcdjet, mcdjet.eventWeight()); @@ -539,17 +570,22 @@ struct JetFinderFullQATask { } PROCESS_SWITCH(JetFinderFullQATask, processJetsMCPMCDMatchedWeighted, "jet finder HF QA matched mcp and mcd on weighted events", false); - void processMCCollisionsWeighted(JetMcCollision const& collision) + void processMCCollisionsWeighted(aod::JetMcCollision const& collision) { - + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } registry.fill(HIST("h_collision_eventweight_part"), collision.weight()); } PROCESS_SWITCH(JetFinderFullQATask, processMCCollisionsWeighted, "collision QA for weighted events", false); - void processTracks(JetCollision const& collision, - soa::Filtered const& tracks, - soa::Filtered const& clusters) + void processTracks(aod::JetCollision const& collision, + soa::Filtered const& tracks, + soa::Filtered const& clusters) { + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } registry.fill(HIST("h_collisions"), 0.5); registry.fill(HIST("h_centrality_collisions"), collision.centrality(), 0.5); if (!jetderiveddatautilities::eventEMCAL(collision)) { @@ -561,12 +597,15 @@ struct JetFinderFullQATask { } PROCESS_SWITCH(JetFinderFullQATask, processTracks, "QA for charged tracks", false); - void processTracksWeighted(soa::Join::iterator const& collision, + void processTracksWeighted(soa::Join::iterator const& collision, aod::JMcCollisions const&, - soa::Filtered const& tracks, - soa::Filtered const& clusters) + soa::Filtered const& tracks, + soa::Filtered const& clusters) { float eventWeight = collision.mcCollision().weight(); + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } registry.fill(HIST("h_collisions"), 0.5); registry.fill(HIST("h_collisions_weighted"), 0.5, eventWeight); if (!jetderiveddatautilities::eventEMCAL(collision)) { diff --git a/PWGJE/Tasks/jetfinderhfQA.cxx b/PWGJE/Tasks/jetFinderHFQA.cxx similarity index 72% rename from PWGJE/Tasks/jetfinderhfQA.cxx rename to PWGJE/Tasks/jetFinderHFQA.cxx index b0345ca861f..a63cbef6563 100644 --- a/PWGJE/Tasks/jetfinderhfQA.cxx +++ b/PWGJE/Tasks/jetFinderHFQA.cxx @@ -60,6 +60,7 @@ struct JetFinderHFQATask { Configurable trackPtMin{"trackPtMin", 0.15, "minimum pT acceptance for tracks"}; Configurable trackPtMax{"trackPtMax", 100.0, "maximum pT acceptance for tracks"}; Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + Configurable jetPtMax{"jetPtMax", 200., "set jet pT bin max"}; Configurable jetEtaMin{"jetEtaMin", -99.0, "minimum jet pseudorapidity"}; Configurable jetEtaMax{"jetEtaMax", 99.0, "maximum jet pseudorapidity"}; Configurable jetAreaFractionMin{"jetAreaFractionMin", -99.0, "used to make a cut on the jet areas"}; @@ -67,7 +68,9 @@ struct JetFinderHFQATask { Configurable pTHatMaxMCD{"pTHatMaxMCD", 999.0, "maximum fraction of hard scattering for jet acceptance in detector MC"}; Configurable pTHatMaxMCP{"pTHatMaxMCP", 999.0, "maximum fraction of hard scattering for jet acceptance in particle MC"}; Configurable pTHatExponent{"pTHatExponent", 6.0, "exponent of the event weight for the calculation of pTHat"}; + Configurable pTHatAbsoluteMin{"pTHatAbsoluteMin", -99.0, "minimum value of pTHat"}; Configurable randomConeR{"randomConeR", 0.4, "size of random Cone for estimating background fluctuations"}; + Configurable skipMBGapEvents{"skipMBGapEvents", false, "flag to choose to reject min. bias gap events; jet-level rejection applied at the jet finder level, here rejection is applied for collision and track process functions"}; HfHelper hfHelper; std::vector filledJetR_Both; @@ -78,12 +81,15 @@ struct JetFinderHFQATask { std::vector filledJetHFR_High; std::vector jetRadiiValues; - int eventSelection = -1; + std::vector eventSelectionBits; int trackSelection = -1; + std::vector jetPtBins; + std::vector jetPtBinsRhoAreaSub; + void init(o2::framework::InitContext&) { - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(eventSelections)); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); jetRadiiValues = (std::vector)jetRadii; @@ -103,80 +109,108 @@ struct JetFinderHFQATask { jetRadiiBins.push_back(jetRadiiBins[jetRadiiBins.size() - 1] + 0.1); } + auto jetPtTemp = 0.0; + jetPtBins.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(jetPtTemp); + while (jetPtTemp < jetPtMax) { + if (jetPtTemp < 100.0) { + jetPtTemp += 1.0; + jetPtBins.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(-jetPtTemp); + } else if (jetPtTemp < 200.0) { + jetPtTemp += 5.0; + jetPtBins.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(-jetPtTemp); + + } else { + jetPtTemp += 10.0; + jetPtBins.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(-jetPtTemp); + } + } + std::sort(jetPtBinsRhoAreaSub.begin(), jetPtBinsRhoAreaSub.end()); + + AxisSpec jetPtAxis = {jetPtBins, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec jetPtAxisRhoAreaSub = {jetPtBinsRhoAreaSub, "#it{p}_{T} (GeV/#it{c})"}; + if (doprocessJetsData || doprocessJetsMCD || doprocessJetsMCDWeighted) { - registry.add("h_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); - registry.add("h_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxis}}); + registry.add("h_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{500, -5.0, 5.0}}}); registry.add("h_jet_phi", "jet #varphi;#varphi_{jet};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_jet_ntracks", "jet N tracks;N_{jet tracks};entries", {HistType::kTH1F, {{200, -0.5, 199.5}}}); - registry.add("h2_centrality_jet_pt", "centrality vs #it{p}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, 0., 200.}}}); - registry.add("h2_centrality_jet_eta", "centrality vs #eta_{jet}; centrality; #eta_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, -1.0, 1.0}}}); + registry.add("h2_centrality_jet_pt", "centrality vs #it{p}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, jetPtAxis}}); + registry.add("h2_centrality_jet_eta", "centrality vs #eta_{jet}; centrality; #eta_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {500, -5.0, 5.0}}}); registry.add("h2_centrality_jet_phi", "centrality vs #varphi_{jet}; centrality; #varphi_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {160, -1.0, 7.}}}); registry.add("h2_centrality_jet_ntracks", "centrality vs N_{jet tracks}; centrality; N_{jet tracks}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_centrality", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});centrality", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {1200, -10.0, 110.0}}}); - registry.add("h3_jet_r_jet_pt_jet_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_jet_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_eta_jet_phi", "#it{R}_{jet};#eta_{jet};#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_jet_ntracks", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_jet_area", "#it{R}_{jet}; #it{p}_{T,jet} (GeV/#it{c}); #it{area}_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {300, 0., 3.}}}); - registry.add("h3_jet_r_jet_pt_track_pt", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_track_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_track_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_candidate_pt", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_candidate_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_candidate_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_candidate_y", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_candidate_invmass_jet_pt_candidate_pt", ";#it{m}_{inv, candidate} (GeV/#it{c}^{2}); #it{p}_{T,jet} (GeV/#it{c}) ;#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{500, 0.0, 5.0}, {200, 0.0, 200.0}, {200, 0.0, 200.0}}}); - registry.add("h3_candidatebar_invmass_jet_pt_candidate_pt", ";#it{m}_{inv, candidate bar} (GeV/#it{c}^{2}); #it{p}_{T,jet} (GeV/#it{c}) ;#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{500, 0.0, 5.0}, {200, 0.0, 200.0}, {200, 0.0, 200.0}}}); - } - - if (doprocessJetsRhoAreaSubData) { - - registry.add("h_jet_pt_rhoareasubtracted", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{400, -200., 200.}}}); - registry.add("h_jet_eta_rhoareasubtracted", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h3_jet_r_jet_pt_centrality", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});centrality", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1200, -10.0, 110.0}}}); + registry.add("h3_jet_r_jet_pt_jet_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_jet_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_eta_jet_phi", "#it{R}_{jet};#eta_{jet};#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_jet_ntracks", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, -0.5, 199.5}}}); + registry.add("h3_jet_r_jet_pt_jet_area", "#it{R}_{jet}; #it{p}_{T,jet} (GeV/#it{c}); #it{area}_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {300, 0., 3.}}}); + registry.add("h3_jet_r_jet_pt_track_pt", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_track_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_track_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_candidate_pt", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_candidate_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_candidate_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_candidate_y", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_candidate_invmass_jet_pt_candidate_pt", ";#it{m}_{inv, candidate} (GeV/#it{c}^{2}); #it{p}_{T,jet} (GeV/#it{c}) ;#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{500, 0.0, 5.0}, jetPtAxis, {200, 0.0, 200.0}}}); + registry.add("h3_candidatebar_invmass_jet_pt_candidate_pt", ";#it{m}_{inv, candidate bar} (GeV/#it{c}^{2}); #it{p}_{T,jet} (GeV/#it{c}) ;#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{500, 0.0, 5.0}, jetPtAxis, {200, 0.0, 200.0}}}); + registry.add("h_jet_phat_weighted", "jet #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0, 350}}}); + } + + if (doprocessJetsRhoAreaSubData || doprocessJetsRhoAreaSubMCD) { + + registry.add("h_jet_pt_rhoareasubtracted", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + registry.add("h_jet_eta_rhoareasubtracted", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{500, -5.0, 5.0}}}); registry.add("h_jet_phi_rhoareasubtracted", "jet #varphi;#varphi_{jet};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_jet_ntracks_rhoareasubtracted", "jet N tracks;N_{jet tracks};entries", {HistType::kTH1F, {{200, -0.5, 199.5}}}); - registry.add("h2_centrality_jet_pt_rhoareasubtracted", "centrality vs #it{p}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, {400, -200., 200.}}}); - registry.add("h2_centrality_jet_eta_rhoareasubtracted", "centrality vs #eta_{jet}; centrality; #eta_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, -1.0, 1.0}}}); + registry.add("h2_centrality_jet_pt_rhoareasubtracted", "centrality vs #it{p}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, jetPtAxisRhoAreaSub}}); + registry.add("h2_centrality_jet_eta_rhoareasubtracted", "centrality vs #eta_{jet}; centrality; #eta_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {500, -5.0, 5.0}}}); registry.add("h2_centrality_jet_phi_rhoareasubtracted", "centrality vs #varphi_{jet}; centrality; #varphi_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {160, -1.0, 7.}}}); registry.add("h2_centrality_jet_ntracks_rhoareasubtracted", "centrality vs N_{jet tracks}; centrality; N_{jet tracks}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_centrality_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});centrality", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {1200, -10.0, 110.0}}}); - registry.add("h3_jet_r_jet_pt_jet_eta_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_jet_phi_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_eta_jet_phi_rhoareasubtracted", "#it{R}_{jet};#eta_{jet};#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_jet_ntracks_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_jet_area_rhoareasubtracted", "#it{R}_{jet}; #it{p}_{T,jet} (GeV/#it{c}); #it{area}_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {300, 0., 3.}}}); - registry.add("h3_jet_r_jet_pt_track_pt_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_track_eta_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_track_phi_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_jet_pt_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {400, -200., 200.}}}); - registry.add("h3_jet_r_jet_pt_candidate_pt_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_candidate_eta_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_candidate_phi_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_candidate_y_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_jet_pt_centrality_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});centrality", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {1200, -10.0, 110.0}}}); + registry.add("h3_jet_r_jet_pt_jet_eta_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_jet_phi_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_eta_jet_phi_rhoareasubtracted", "#it{R}_{jet};#eta_{jet};#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_jet_ntracks_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {200, -0.5, 199.5}}}); + registry.add("h3_jet_r_jet_pt_jet_area_rhoareasubtracted", "#it{R}_{jet}; #it{p}_{T,jet} (GeV/#it{c}); #it{area}_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {300, 0., 3.}}}); + registry.add("h3_jet_r_jet_pt_track_pt_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_track_eta_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_track_phi_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_jet_pt_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetPtAxisRhoAreaSub}}); + registry.add("h3_jet_r_jet_pt_candidate_pt_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_candidate_eta_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_candidate_phi_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_candidate_y_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {500, -5.0, 5.0}}}); } if (doprocessEvtWiseConstSubJetsData) { - registry.add("h_jet_pt_eventwiseconstituentsubtracted", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); - registry.add("h_jet_eta_eventwiseconstituentsubtracted", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_jet_pt_eventwiseconstituentsubtracted", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxis}}); + registry.add("h_jet_eta_eventwiseconstituentsubtracted", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{500, -5.0, 5.0}}}); registry.add("h_jet_phi_eventwiseconstituentsubtracted", "jet #varphi;#varphi_{jet};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_jet_ntracks_eventwiseconstituentsubtracted", "jet N tracks;N_{jet tracks};entries", {HistType::kTH1F, {{200, -0.5, 199.5}}}); - registry.add("h2_centrality_jet_pt_eventwiseconstituentsubtracted", "centrality vs #it{p}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, 0., 200.}}}); - registry.add("h2_centrality_jet_eta_eventwiseconstituentsubtracted", "centrality vs #eta_{jet}; centrality; #eta_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, -1.0, 1.0}}}); + registry.add("h2_centrality_jet_pt_eventwiseconstituentsubtracted", "centrality vs #it{p}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, jetPtAxis}}); + registry.add("h2_centrality_jet_eta_eventwiseconstituentsubtracted", "centrality vs #eta_{jet}; centrality; #eta_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {500, -5.0, 5.0}}}); registry.add("h2_centrality_jet_phi_eventwiseconstituentsubtracted", "centrality vs #varphi_{jet}; centrality; #varphi_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {160, -1.0, 7.}}}); registry.add("h2_centrality_jet_ntracks_eventwiseconstituentsubtracted", "centrality vs N_{jet tracks}; centrality; N_{jet tracks}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_centrality_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});centrality", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {1200, -10.0, 110.0}}}); - registry.add("h3_jet_r_jet_pt_jet_eta_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_jet_phi_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_eta_jet_phi_eventwiseconstituentsubtracted", "#it{R}_{jet};#eta_{jet};#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_jet_ntracks_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_jet_area_eventwiseconstituentsubtracted", "#it{R}_{jet}; #it{p}_{T,jet} (GeV/#it{c}); #it{area}_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {300, 0., 3.}}}); - registry.add("h3_jet_r_jet_pt_track_pt_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_track_eta_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_track_phi_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_candidate_pt_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_candidate_eta_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_candidate_phi_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_candidate_y_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_jet_pt_centrality_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});centrality", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1200, -10.0, 110.0}}}); + registry.add("h3_jet_r_jet_pt_jet_eta_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_jet_phi_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_eta_jet_phi_eventwiseconstituentsubtracted", "#it{R}_{jet};#eta_{jet};#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_jet_ntracks_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, -0.5, 199.5}}}); + registry.add("h3_jet_r_jet_pt_jet_area_eventwiseconstituentsubtracted", "#it{R}_{jet}; #it{p}_{T,jet} (GeV/#it{c}); #it{area}_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {300, 0., 3.}}}); + registry.add("h3_jet_r_jet_pt_track_pt_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_track_eta_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_track_phi_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_candidate_pt_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_candidate_eta_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_candidate_phi_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_candidate_y_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); } if (doprocessRho) { @@ -187,238 +221,236 @@ struct JetFinderHFQATask { registry.add("h2_centrality_rhom", ";centrality; #it{rho}_{m} (GeV/area)", {HistType::kTH2F, {{1100, 0., 110.}, {100, 0., 100.0}}}); } - if (doprocessRandomCone) { + if (doprocessRandomConeData || doprocessRandomConeMCD) { registry.add("h2_centrality_rhorandomcone", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH2F, {{1100, 0., 110.}, {800, -400.0, 400.0}}}); registry.add("h2_centrality_rhorandomconewithoutleadingjet", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH2F, {{1100, 0., 110.}, {800, -400.0, 400.0}}}); } if (doprocessJetsMCP || doprocessJetsMCPWeighted) { - registry.add("h_jet_pt_part", "jet pT;#it{p}_{T,jet}^{part}(GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); - registry.add("h_jet_eta_part", "jet #eta;#eta_{jet}^{part};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_jet_pt_part", "jet pT;#it{p}_{T,jet}^{part}(GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxis}}); + registry.add("h_jet_eta_part", "jet #eta;#eta_{jet}^{part};entries", {HistType::kTH1F, {{500, -5.0, 5.0}}}); registry.add("h_jet_phi_part", "jet #varphi;#varphi_{jet}^{part};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_jet_ntracks_part", "jet N tracks;N_{jet tracks}^{part};entries", {HistType::kTH1F, {{200, -0.5, 199.5}}}); - registry.add("h3_jet_r_part_jet_pt_part_jet_eta_part", ";#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#eta_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_part_jet_pt_part_jet_phi_part", ";#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#varphi_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_part_jet_eta_part_jet_phi_part", ";#it{R}_{jet}^{part};#eta_{jet}^{part};#varphi_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_part_jet_pt_part_jet_ntracks_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});N_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_part_jet_pt_part_track_pt_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#it{p}_{T,jet tracks}^{part} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_part_jet_pt_part_track_eta_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#eta_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_part_jet_pt_part_track_phi_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#varphi_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_part_jet_pt_part_candidate_pt_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#it{p}_{T,candidate}^{part} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_part_jet_pt_part_candidate_eta_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#eta_{candidate}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_part_jet_pt_part_candidate_phi_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#varphi{candidate}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_part_jet_pt_part_candidate_y_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});y_{candidate}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_part_jet_pt_part_jet_eta_part", ";#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#eta_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_part_jet_pt_part_jet_phi_part", ";#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#varphi_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_part_jet_eta_part_jet_phi_part", ";#it{R}_{jet}^{part};#eta_{jet}^{part};#varphi_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_part_jet_pt_part_jet_ntracks_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});N_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, -0.5, 199.5}}}); + registry.add("h3_jet_r_part_jet_pt_part_track_pt_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#it{p}_{T,jet tracks}^{part} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_part_jet_pt_part_track_eta_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#eta_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_part_jet_pt_part_track_phi_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#varphi_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_part_jet_pt_part_candidate_pt_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#it{p}_{T,candidate}^{part} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_part_jet_pt_part_candidate_eta_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#eta_{candidate}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_part_jet_pt_part_candidate_phi_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#varphi{candidate}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_part_jet_pt_part_candidate_y_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});y_{candidate}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h_jet_phat_part_weighted", "jet #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{1000, 0, 1000}}}); } if (doprocessJetsMCPMCDMatched || doprocessJetsMCPMCDMatchedWeighted || doprocessJetsSubMatched) { - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeo", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeo", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetPtAxis}}); + registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeo", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeo", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); registry.add("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeo", "#it{R}_{jet};N_{jet tracks}^{tag};N_{jet tracks}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); registry.add("h3_jet_r_candidate_pt_tag_candidate_pt_base_matchedgeo", "#it{R}_{jet};#it{p}_{T,candidate}^{tag} (GeV/#it{c});#it{p}_{T,candidate}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedgeo", "#it{R}_{jet};#eta_{candidate}^{tag};#eta_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedgeo", "#it{R}_{jet};#eta_{candidate}^{tag};#eta_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); registry.add("h3_jet_r_candidate_phi_tag_candidate_phi_base_matchedgeo", "#it{R}_{jet};#varphi_{candidate}^{tag};#varphi_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); - - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedpt", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedpt", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {160, -1.0, 7.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {jetPtAxis, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); + + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetPtAxis}}); + registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedpt", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedpt", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); registry.add("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedpt", "#it{R}_{jet};N_{jet tracks}^{tag};N_{jet tracks}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); registry.add("h3_jet_r_candidate_pt_tag_candidate_pt_base_matchedpt", "#it{R}_{jet};#it{p}_{T,candidate}^{tag} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedpt", "#it{R}_{jet};#eta_{candidate}^{tag};#eta_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedpt", "#it{R}_{jet};#eta_{candidate}^{tag};#eta_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); registry.add("h3_jet_r_candidate_phi_tag_candidate_phi_base_matchedpt", "#it{R}_{jet};#varphi_{candidate}^{tag};#varphi_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); - - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeopt", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeopt", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {160, -1.0, 7.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {jetPtAxis, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); + + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetPtAxis}}); + registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeopt", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeopt", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); registry.add("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeopt", "#it{R}_{jet};N_{jet tracks}^{tag};N_{jet tracks}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); registry.add("h3_jet_r_candidate_pt_tag_candidate_pt_base_matchedgeopt", "#it{R}_{jet};#it{p}_{T,candidate}^{tag} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedgeopt", "#it{R}_{jet};#eta_{candidate}^{tag};#eta_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedgeopt", "#it{R}_{jet};#eta_{candidate}^{tag};#eta_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); registry.add("h3_jet_r_candidate_phi_tag_candidate_phi_base_matchedgeopt", "#it{R}_{jet};#varphi_{candidate}^{tag};#varphi_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); - - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedhf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedhf", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedhf", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {160, -1.0, 7.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {jetPtAxis, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); + + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedhf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetPtAxis}}); + registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedhf", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedhf", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); registry.add("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedhf", "#it{R}_{jet};N_{jet tracks}^{tag};N_{jet tracks}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); registry.add("h3_jet_r_candidate_pt_tag_candidate_pt_base_matchedhf", "#it{R}_{jet};#it{p}_{T,candidate}^{tag} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedhf", "#it{R}_{jet};#eta_{candidate}^{tag};#eta_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedhf", "#it{R}_{jet};#eta_{candidate}^{tag};#eta_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); registry.add("h3_jet_r_candidate_phi_tag_candidate_phi_base_matchedhf", "#it{R}_{jet};#varphi_{candidate}^{tag};#varphi_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedhf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedhf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedhf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedhf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedhf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedhf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); - - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeohf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeohf", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeohf", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedhf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedhf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedhf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedhf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedhf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {160, -1.0, 7.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedhf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {jetPtAxis, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); + + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeohf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetPtAxis}}); + registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeohf", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeohf", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); registry.add("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeohf", "#it{R}_{jet};N_{jet tracks}^{tag};N_{jet tracks}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); registry.add("h3_jet_r_candidate_pt_tag_candidate_pt_base_matchedgeohf", "#it{R}_{jet};#it{p}_{T,candidate}^{tag} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedgeohf", "#it{R}_{jet};#eta_{candidate}^{tag};#eta_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedgeohf", "#it{R}_{jet};#eta_{candidate}^{tag};#eta_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); registry.add("h3_jet_r_candidate_phi_tag_candidate_phi_base_matchedgeohf", "#it{R}_{jet};#varphi_{candidate}^{tag};#varphi_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeohf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeohf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeohf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeohf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeohf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeohf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); - - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedpthf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedpthf", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedpthf", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeohf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeohf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeohf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeohf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeohf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {160, -1.0, 7.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeohf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {jetPtAxis, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); + + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedpthf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetPtAxis}}); + registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedpthf", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedpthf", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); registry.add("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedpthf", "#it{R}_{jet};N_{jet tracks}^{tag};N_{jet tracks}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); registry.add("h3_jet_r_candidate_pt_tag_candidate_pt_base_matchedpthf", "#it{R}_{jet};#it{p}_{T,candidate}^{tag} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedpthf", "#it{R}_{jet};#eta_{candidate}^{tag};#eta_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedpthf", "#it{R}_{jet};#eta_{candidate}^{tag};#eta_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); registry.add("h3_jet_r_candidate_phi_tag_candidate_phi_base_matchedpthf", "#it{R}_{jet};#varphi_{candidate}^{tag};#varphi_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedpthf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedpthf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedpthf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedpthf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedpthf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedpthf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); - - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeopthf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeopthf", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeopthf", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedpthf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedpthf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedpthf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedpthf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedpthf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {160, -1.0, 7.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedpthf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {jetPtAxis, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); + + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeopthf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetPtAxis}}); + registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeopthf", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeopthf", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); registry.add("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeopthf", "#it{R}_{jet};N_{jet tracks}^{tag};N_{jet tracks}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); registry.add("h3_jet_r_candidate_pt_tag_candidate_pt_base_matchedgeopthf", "#it{R}_{jet};#it{p}_{T,candidate}^{tag} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedgeopthf", "#it{R}_{jet};#eta_{candidate}^{tag};#eta_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedgeopthf", "#it{R}_{jet};#eta_{candidate}^{tag};#eta_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); registry.add("h3_jet_r_candidate_phi_tag_candidate_phi_base_matchedgeopthf", "#it{R}_{jet};#varphi_{candidate}^{tag};#varphi_{candidate}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeopthf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeopthf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeopthf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeopthf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeopthf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeopthf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeopthf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeopthf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeopthf", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeopthf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeopthf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {160, -1.0, 7.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeopthf", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {jetPtAxis, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); } if (doprocessTriggeredData) { registry.add("h_collision_trigger_events", "event status;event status;entries", {HistType::kTH1F, {{6, 0.0, 6.0}}}); registry.add("h_track_pt_MB", "track pT for MB events;#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0.0, 200.0}}}); - registry.add("h_track_eta_MB", "track #eta for MB events;#eta_{track};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_track_eta_MB", "track #eta for MB events;#eta_{track};entries", {HistType::kTH1F, {{500, -5.0, 5.0}}}); registry.add("h_track_phi_MB", "track #varphi for MB events;#varphi_{track};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_track_pt_Triggered_Low", "track pT for low #it{p}_{T} Triggered events;#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0.0, 200.0}}}); - registry.add("h_track_eta_Triggered_Low", "track #eta for low #it{p}_{T} Triggered events;#eta_{track};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_track_eta_Triggered_Low", "track #eta for low #it{p}_{T} Triggered events;#eta_{track};entries", {HistType::kTH1F, {{500, -5.0, 5.0}}}); registry.add("h_track_phi_Triggered_Low", "track #varphi for low #it{p}_{T} Triggered events;#varphi_{track};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_track_pt_Triggered_High", "track pT for high #it{p}_{T} Triggered events;#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0.0, 200.0}}}); - registry.add("h_track_eta_Triggered_High", "track #eta for high #it{p}_{T} Triggered events;#eta_{track};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_track_eta_Triggered_High", "track #eta for high #it{p}_{T} Triggered events;#eta_{track};entries", {HistType::kTH1F, {{500, -5.0, 5.0}}}); registry.add("h_track_phi_Triggered_High", "track #varphi for high #it{p}_{T} Triggered events;#varphi_{track};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_track_pt_Triggered_Both", "track pT for both #it{p}_{T} Triggered events;#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0.0, 200.0}}}); - registry.add("h_track_eta_Triggered_Both", "track #eta for both #it{p}_{T} Triggered events;#eta_{track};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_track_eta_Triggered_Both", "track #eta for both #it{p}_{T} Triggered events;#eta_{track};entries", {HistType::kTH1F, {{500, -5.0, 5.0}}}); registry.add("h_track_phi_Triggered_Both", "track #varphi for both #it{p}_{T} Triggered events;#varphi_{track};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_collision", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});collision trigger status", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {4, -0.5, 3.5}}}); - registry.add("h3_jet_r_jet_eta_collision", "#it{R}_{jet};#eta_{jet};collision trigger status", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {4, -0.5, 3.5}}}); + registry.add("h3_jet_r_jet_pt_collision", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});collision trigger status", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {4, -0.5, 3.5}}}); + registry.add("h3_jet_r_jet_eta_collision", "#it{R}_{jet};#eta_{jet};collision trigger status", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {4, -0.5, 3.5}}}); registry.add("h3_jet_r_jet_phi_collision", "#it{R}_{jet};#varphi_{jet};collision trigger status", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {4, -0.5, 3.5}}}); - registry.add("h2_jet_r_jet_pT_triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, {200, 0., 200.}}}); - registry.add("h2_jet_r_jet_pT_triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, {200, 0., 200.}}}); - registry.add("h2_jet_r_jet_pT_triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_track_pt_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_track_eta_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_track_phi_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_track_pt_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_track_eta_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_track_phi_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_track_pt_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_track_eta_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_track_phi_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_track_pt_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_track_eta_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_track_phi_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_candidate_pt_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_candidate_eta_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_candidate_phi_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_candidate_y_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_candidate_pt_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_candidate_eta_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_candidate_phi_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_candidate_y_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_candidate_pt_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_candidate_eta_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_candidate_phi_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_candidate_y_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_candidate_pt_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_candidate_eta_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_candidate_phi_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_candidate_y_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); + registry.add("h2_jet_r_jet_pT_triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, jetPtAxis}}); + registry.add("h2_jet_r_jet_pT_triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, jetPtAxis}}); + registry.add("h2_jet_r_jet_pT_triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, jetPtAxis}}); + registry.add("h3_jet_r_jet_pt_track_pt_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_track_eta_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_track_phi_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_track_pt_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_track_eta_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_track_phi_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_track_pt_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_track_eta_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_track_phi_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_track_pt_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_track_eta_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_track_phi_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_candidate_pt_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_candidate_eta_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_candidate_phi_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_candidate_y_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_candidate_pt_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_candidate_eta_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_candidate_phi_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_candidate_y_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_candidate_pt_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_candidate_eta_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_candidate_phi_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_candidate_y_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_candidate_pt_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_candidate_eta_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_candidate_phi_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_candidate_y_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); } if (doprocessHFTriggeredData) { registry.add("h_collision_hftrigger_events", "event status;event status;entries", {HistType::kTH1F, {{115, 0.0, 15.0}}}); registry.add("h_track_pt_all", "track pT for MB events;#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0.0, 200.0}}}); - registry.add("h_track_eta_all", "track #eta for MB events;#eta_{track};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_track_eta_all", "track #eta for MB events;#eta_{track};entries", {HistType::kTH1F, {{500, -5.0, 5.0}}}); registry.add("h_track_phi_all", "track #varphi for MB events;#varphi_{track};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_track_pt_triggered_HFlow", "track pT for low #it{p}_{T} HF Triggered events;#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0.0, 200.0}}}); - registry.add("h_track_eta_triggered_HFlow", "track #eta for low #it{p}_{T} HF Triggered events;#eta_{track};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_track_eta_triggered_HFlow", "track #eta for low #it{p}_{T} HF Triggered events;#eta_{track};entries", {HistType::kTH1F, {{500, -5.0, 5.0}}}); registry.add("h_track_phi_triggered_HFlow", "track #varphi for low #it{p}_{T} HF Triggered events;#varphi_{track};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_track_pt_triggered_HFhigh", "track pT for high #it{p}_{T} HF Triggered events;#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0.0, 200.0}}}); - registry.add("h_track_eta_triggered_HFhigh", "track #eta for high #it{p}_{T} HF Triggered events;#eta_{track};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_track_eta_triggered_HFhigh", "track #eta for high #it{p}_{T} HF Triggered events;#eta_{track};entries", {HistType::kTH1F, {{500, -5.0, 5.0}}}); registry.add("h_track_phi_triggered_HFhigh", "track #varphi for high #it{p}_{T} HF Triggered events;#varphi_{track};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); - registry.add("h2_jet_r_jet_pT_triggered_all", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, {200, 0., 200.}}}); - registry.add("h2_jet_r_jet_pT_triggered_HFlow", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, {200, 0., 200.}}}); - registry.add("h2_jet_r_jet_pT_triggered_HFhigh", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, {200, 0., 200.}}}); - registry.add("h2_jet_r_jet_pT_triggered_Lcall", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, {200, 0., 200.}}}); - registry.add("h2_jet_r_jet_pT_triggered_Lclow", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, {200, 0., 200.}}}); - registry.add("h2_jet_r_jet_pT_triggered_Lchigh", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, {200, 0., 200.}}}); - registry.add("h2_jet_r_jet_eta_triggered_HFall", "#it{R}_{jet};#eta_{jet}", {HistType::kTH2F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}}}); - registry.add("h2_jet_r_jet_eta_triggered_HFlow", "#it{R}_{jet};#eta_{jet}", {HistType::kTH2F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}}}); - registry.add("h2_jet_r_jet_eta_triggered_HFhigh", "#it{R}_{jet};#eta_{jet}", {HistType::kTH2F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}}}); - - registry.add("h3_hfjet_r_jet_pt_collision", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});collision trigger status", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {4, -0.5, 3.5}}}); - registry.add("h3_hfjet_r_jet_eta_collision", "#it{R}_{jet};#eta_{jet};collision trigger status", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {4, -0.5, 3.5}}}); + registry.add("h2_jet_r_jet_pT_triggered_all", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, jetPtAxis}}); + registry.add("h2_jet_r_jet_pT_triggered_HFlow", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, jetPtAxis}}); + registry.add("h2_jet_r_jet_pT_triggered_HFhigh", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, jetPtAxis}}); + registry.add("h2_jet_r_jet_pT_triggered_Lcall", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, jetPtAxis}}); + registry.add("h2_jet_r_jet_pT_triggered_Lclow", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, jetPtAxis}}); + registry.add("h2_jet_r_jet_pT_triggered_Lchigh", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, jetPtAxis}}); + registry.add("h2_jet_r_jet_eta_triggered_HFall", "#it{R}_{jet};#eta_{jet}", {HistType::kTH2F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}}}); + registry.add("h2_jet_r_jet_eta_triggered_HFlow", "#it{R}_{jet};#eta_{jet}", {HistType::kTH2F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}}}); + registry.add("h2_jet_r_jet_eta_triggered_HFhigh", "#it{R}_{jet};#eta_{jet}", {HistType::kTH2F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}}}); + + registry.add("h3_hfjet_r_jet_pt_collision", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});collision trigger status", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {4, -0.5, 3.5}}}); + registry.add("h3_hfjet_r_jet_eta_collision", "#it{R}_{jet};#eta_{jet};collision trigger status", {HistType::kTH3F, {{jetRadiiBins, ""}, {500, -5.0, 5.0}, {4, -0.5, 3.5}}}); registry.add("h3_hfjet_r_jet_phi_collision", "#it{R}_{jet};#varphi_{jet};collision trigger status", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {4, -0.5, 3.5}}}); - registry.add("h3_jet_r_jet_pt_candidate_pt_all", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_candidate_eta_all", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_candidate_phi_all", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_candidate_y_all", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_candidate_pt_triggered_HFlow", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_candidate_eta_triggered_HFlow", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_candidate_phi_triggered_HFlow", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_candidate_y_triggered_HFlow", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_candidate_pt_triggered_HFhigh", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_candidate_eta_triggered_HFhigh", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_candidate_phi_triggered_HFhigh", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_candidate_y_triggered_HFhigh", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_jet_pt_candidate_pt_all", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_candidate_eta_all", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_candidate_phi_all", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_candidate_y_all", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_candidate_pt_triggered_HFlow", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_candidate_eta_triggered_HFlow", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_candidate_phi_triggered_HFlow", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_candidate_y_triggered_HFlow", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_candidate_pt_triggered_HFhigh", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_candidate_eta_triggered_HFhigh", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_candidate_phi_triggered_HFhigh", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_candidate_y_triggered_HFhigh", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); } if (doprocessTracks || doprocessTracksWeighted) { registry.add("h_collisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); registry.add("h2_centrality_collisions", "centrality vs collisions; centrality; collisions", {HistType::kTH2F, {{1200, -10.0, 110.0}, {4, 0.0, 4.0}}}); - registry.add("h2_centrality_track_pt", "centrality vs track pT; centrality; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, 0., 200.}}}); - registry.add("h2_centrality_track_eta", "centrality vs track #eta; centrality; #eta_{track}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, -1.0, 1.0}}}); - registry.add("h2_centrality_track_phi", "centrality vs track #varphi; centrality; #varphi_{track}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {160, -1.0, 7.}}}); - registry.add("h2_centrality_track_energy", "centrality vs track energy; centrality; Energy GeV", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, 0.0, 100.0}}}); + registry.add("h3_centrality_track_pt_track_phi", "centrality vs track pT vs track #varphi; centrality; #it{p}_{T,track} (GeV/#it{c}); #varphi_{track}", {HistType::kTH3F, {{1200, -10.0, 110.0}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_centrality_track_pt_track_eta", "centrality vs track pT vs track #eta; centrality; #it{p}_{T,track} (GeV/#it{c}); #eta_{track}", {HistType::kTH3F, {{1200, -10.0, 110.0}, {200, 0., 200.}, {500, -5.0, 5.0}}}); + registry.add("h3_track_pt_track_eta_track_phi", "track pT vs track #eta vs track #varphi; #it{p}_{T,track} (GeV/#it{c}); #eta_{track}; #varphi_{track}", {HistType::kTH3F, {{200, 0., 200.}, {500, -5.0, 5.0}, {160, -1.0, 7.}}}); if (doprocessTracksWeighted) { registry.add("h_collisions_weighted", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); } } if (doprocessTracksSub) { - - registry.add("h2_centrality_track_pt_eventwiseconstituentsubtracted", "centrality vs track pT; centrality; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, 0., 200.}}}); - registry.add("h2_centrality_track_eta_eventwiseconstituentsubtracted", "centrality vs track #eta; centrality; #eta_{track}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, -1.0, 1.0}}}); - registry.add("h2_centrality_track_phi_eventwiseconstituentsubtracted", "centrality vs track #varphi; centrality; #varphi_{track}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {160, -1.0, 7.}}}); - registry.add("h2_centrality_track_energy_eventwiseconstituentsubtracted", "centrality vs track energy; centrality; Energy GeV", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, 0.0, 100.0}}}); + registry.add("h3_centrality_track_pt_track_phi_eventwiseconstituentsubtracted", "centrality vs track pT vs track #varphi; centrality; #it{p}_{T,track} (GeV/#it{c}); #varphi_{track}", {HistType::kTH3F, {{1200, -10.0, 110.0}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_centrality_track_pt_track_eta_eventwiseconstituentsubtracted", "centrality vs track pT vs track #eta; centrality; #it{p}_{T,track} (GeV/#it{c}); #eta_{track}", {HistType::kTH3F, {{1200, -10.0, 110.0}, {200, 0., 200.}, {500, -5.0, 5.0}}}); + registry.add("h3_track_pt_track_eta_track_phi_eventwiseconstituentsubtracted", "track pT vs track #eta vs track #varphi; #it{p}_{T,track} (GeV/#it{c}); #eta_{track}; #varphi_{track}", {HistType::kTH3F, {{200, 0., 200.}, {500, -5.0, 5.0}, {160, -1.0, 7.}}}); } if (doprocessMCCollisionsWeighted) { @@ -429,7 +461,7 @@ struct JetFinderHFQATask { if (doprocessCandidates) { registry.add("h_candidate_invmass", ";#it{m}_{inv, candidate} (GeV/#it{c}^{2});counts", {HistType::kTH1F, {{500, 0.0, 5.0}}}); registry.add("h_candidate_pt", ";#it{p}_{T,candidate} (GeV/#it{c});counts", {HistType::kTH1F, {{200, 0.0, 200.0}}}); - registry.add("h_candidate_y", ";y_{candidate};counts", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_candidate_y", ";y_{candidate};counts", {HistType::kTH1F, {{500, -5.0, 5.0}}}); registry.add("h2_centrality_ncandidates", "centrality vs N_{candidates};centrality;N_{candidates};", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, 0.0, 100.0}}}); } } @@ -450,7 +482,6 @@ struct JetFinderHFQATask { using JetTableMCPMatchedWeightedJoined = soa::Join; Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); - Filter trackSubCuts = (aod::jtracksub::pt >= trackPtMin && aod::jtracksub::pt < trackPtMax && aod::jtracksub::eta > trackEtaMin && aod::jtracksub::eta < trackEtaMax); Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax); // Filter candidateCutsD0 = (aod::hf_sel_candidate_d0::isSelD0 >= selectionFlagD0 || aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlagD0bar); @@ -458,12 +489,10 @@ struct JetFinderHFQATask { // Filter candidateCutsBplus = (aod::hf_sel_candidate_bplus::isSelBplusToD0Pi >= selectionFlagBplus); PresliceOptional> perD0CandidateTracks = aod::bkgd0::candidateId; + PresliceOptional> perDplusCandidateTracks = aod::bkgdplus::candidateId; PresliceOptional> perLcCandidateTracks = aod::bkglc::candidateId; PresliceOptional> perBplusCandidateTracks = aod::bkgbplus::candidateId; - - PresliceOptional perD0CandidateRhos = aod::bkgd0::candidateId; - PresliceOptional perLcCandidateRhos = aod::bkglc::candidateId; - PresliceOptional perBplusCandidateRhos = aod::bkgbplus::candidateId; + PresliceOptional> perDielectronCandidateTracks = aod::bkgdielectron::candidateId; template bool isAcceptedJet(V const& jet) @@ -482,7 +511,7 @@ struct JetFinderHFQATask { break; } } - for (auto& hfconstituent : jet.template hfcandidates_as()) { + for (auto& hfconstituent : jet.template candidates_as()) { if (hfconstituent.pt() >= leadingConstituentPtMin) { isMinleadingConstituent = true; break; @@ -500,49 +529,50 @@ struct JetFinderHFQATask { { float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); - if (jet.pt() > pTHatMaxMCD * pTHat) { + if (jet.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { return; } + registry.fill(HIST("h_jet_phat_weighted"), pTHat, weight); if (jet.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h_jet_pt"), jet.pt(), weight); registry.fill(HIST("h_jet_eta"), jet.eta(), weight); registry.fill(HIST("h_jet_phi"), jet.phi(), weight); - registry.fill(HIST("h_jet_ntracks"), jet.tracksIds().size() + jet.hfcandidatesIds().size(), weight); + registry.fill(HIST("h_jet_ntracks"), jet.tracksIds().size() + jet.candidatesIds().size(), weight); registry.fill(HIST("h2_centrality_jet_pt"), centrality, jet.pt(), weight); registry.fill(HIST("h2_centrality_jet_eta"), centrality, jet.eta(), weight); registry.fill(HIST("h2_centrality_jet_phi"), centrality, jet.phi(), weight); - registry.fill(HIST("h2_centrality_jet_ntracks"), centrality, jet.tracksIds().size() + jet.hfcandidatesIds().size(), weight); + registry.fill(HIST("h2_centrality_jet_ntracks"), centrality, jet.tracksIds().size() + jet.candidatesIds().size(), weight); } registry.fill(HIST("h3_jet_r_jet_pt_centrality"), jet.r() / 100.0, jet.pt(), centrality, weight); registry.fill(HIST("h3_jet_r_jet_pt_jet_eta"), jet.r() / 100.0, jet.pt(), jet.eta(), weight); registry.fill(HIST("h3_jet_r_jet_pt_jet_phi"), jet.r() / 100.0, jet.pt(), jet.phi(), weight); registry.fill(HIST("h3_jet_r_jet_eta_jet_phi"), jet.r() / 100.0, jet.eta(), jet.phi(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_jet_ntracks"), jet.r() / 100.0, jet.pt(), jet.tracksIds().size() + jet.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_jet_ntracks"), jet.r() / 100.0, jet.pt(), jet.tracksIds().size() + jet.candidatesIds().size(), weight); registry.fill(HIST("h3_jet_r_jet_pt_jet_area"), jet.r() / 100.0, jet.pt(), jet.area(), weight); - for (auto& constituent : jet.template tracks_as()) { + for (auto& constituent : jet.template tracks_as()) { registry.fill(HIST("h3_jet_r_jet_pt_track_pt"), jet.r() / 100.0, jet.pt(), constituent.pt(), weight); registry.fill(HIST("h3_jet_r_jet_pt_track_eta"), jet.r() / 100.0, jet.pt(), constituent.eta(), weight); registry.fill(HIST("h3_jet_r_jet_pt_track_phi"), jet.r() / 100.0, jet.pt(), constituent.phi(), weight); } - for (auto& hfcandidate : jet.template hfcandidates_as>()) { + for (auto& candidate : jet.template candidates_as>()) { - registry.fill(HIST("h3_jet_r_jet_pt_track_pt"), jet.r() / 100.0, jet.pt(), hfcandidate.pt(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_track_eta"), jet.r() / 100.0, jet.pt(), hfcandidate.eta(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_track_phi"), jet.r() / 100.0, jet.pt(), hfcandidate.phi(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_track_pt"), jet.r() / 100.0, jet.pt(), candidate.pt(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_track_eta"), jet.r() / 100.0, jet.pt(), candidate.eta(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_track_phi"), jet.r() / 100.0, jet.pt(), candidate.phi(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt"), jet.r() / 100.0, jet.pt(), hfcandidate.pt(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta"), jet.r() / 100.0, jet.pt(), hfcandidate.eta(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi"), jet.r() / 100.0, jet.pt(), hfcandidate.phi(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_y"), jet.r() / 100.0, jet.pt(), hfcandidate.y(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt"), jet.r() / 100.0, jet.pt(), candidate.pt(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta"), jet.r() / 100.0, jet.pt(), candidate.eta(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi"), jet.r() / 100.0, jet.pt(), candidate.phi(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_y"), jet.r() / 100.0, jet.pt(), candidate.y(), weight); if (jet.r() == round(selectedJetsRadius * 100.0f)) { - registry.fill(HIST("h3_candidate_invmass_jet_pt_candidate_pt"), hfcandidate.m(), jet.pt(), hfcandidate.pt(), weight); - registry.fill(HIST("h3_candidatebar_invmass_jet_pt_candidate_pt"), hfcandidate.m(), jet.pt(), hfcandidate.pt(), weight); + registry.fill(HIST("h3_candidate_invmass_jet_pt_candidate_pt"), jetcandidateutilities::getCandidateInvariantMass(candidate), jet.pt(), candidate.pt(), weight); + registry.fill(HIST("h3_candidatebar_invmass_jet_pt_candidate_pt"), jetcandidateutilities::getCandidateInvariantMass(candidate), jet.pt(), candidate.pt(), weight); } } } @@ -555,12 +585,12 @@ struct JetFinderHFQATask { registry.fill(HIST("h_jet_pt_rhoareasubtracted"), jet.pt() - (rho * jet.area()), weight); registry.fill(HIST("h_jet_eta_rhoareasubtracted"), jet.eta(), weight); registry.fill(HIST("h_jet_phi_rhoareasubtracted"), jet.phi(), weight); - registry.fill(HIST("h_jet_ntracks_rhoareasubtracted"), jet.tracksIds().size() + jet.hfcandidatesIds().size(), weight); + registry.fill(HIST("h_jet_ntracks_rhoareasubtracted"), jet.tracksIds().size() + jet.candidatesIds().size(), weight); registry.fill(HIST("h2_centrality_jet_pt_rhoareasubtracted"), centrality, jet.pt() - (rho * jet.area()), weight); if (jet.pt() - (rho * jet.area()) > 0) { registry.fill(HIST("h2_centrality_jet_eta_rhoareasubtracted"), centrality, jet.eta(), weight); registry.fill(HIST("h2_centrality_jet_phi_rhoareasubtracted"), centrality, jet.phi(), weight); - registry.fill(HIST("h2_centrality_jet_ntracks_rhoareasubtracted"), centrality, jet.tracksIds().size() + jet.hfcandidatesIds().size(), weight); + registry.fill(HIST("h2_centrality_jet_ntracks_rhoareasubtracted"), centrality, jet.tracksIds().size() + jet.candidatesIds().size(), weight); } } @@ -568,22 +598,22 @@ struct JetFinderHFQATask { registry.fill(HIST("h3_jet_r_jet_pt_jet_eta_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), jet.eta(), weight); registry.fill(HIST("h3_jet_r_jet_pt_jet_phi_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), jet.phi(), weight); registry.fill(HIST("h3_jet_r_jet_eta_jet_phi_rhoareasubtracted"), jet.r() / 100.0, jet.eta(), jet.phi(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_jet_ntracks_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), jet.tracksIds().size() + jet.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_jet_ntracks_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), jet.tracksIds().size() + jet.candidatesIds().size(), weight); registry.fill(HIST("h3_jet_r_jet_pt_jet_area_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), jet.area(), weight); registry.fill(HIST("h3_jet_r_jet_pt_jet_pt_rhoareasubtracted"), jet.r() / 100.0, jet.pt(), jet.pt() - (rho * jet.area()), weight); - for (auto& constituent : jet.template tracks_as()) { + for (auto& constituent : jet.template tracks_as()) { registry.fill(HIST("h3_jet_r_jet_pt_track_pt_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), constituent.pt(), weight); registry.fill(HIST("h3_jet_r_jet_pt_track_eta_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), constituent.eta(), weight); registry.fill(HIST("h3_jet_r_jet_pt_track_phi_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), constituent.phi(), weight); } - for (auto& hfcandidate : jet.template hfcandidates_as>()) { - registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), hfcandidate.pt(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), hfcandidate.eta(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), hfcandidate.phi(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), hfcandidate.y(), weight); + for (auto& candidate : jet.template candidates_as>()) { + registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), candidate.pt(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), candidate.eta(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), candidate.phi(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), candidate.y(), weight); } } @@ -594,18 +624,18 @@ struct JetFinderHFQATask { registry.fill(HIST("h_jet_pt_eventwiseconstituentsubtracted"), jet.pt(), weight); registry.fill(HIST("h_jet_eta_eventwiseconstituentsubtracted"), jet.eta(), weight); registry.fill(HIST("h_jet_phi_eventwiseconstituentsubtracted"), jet.phi(), weight); - registry.fill(HIST("h_jet_ntracks_eventwiseconstituentsubtracted"), jet.tracksIds().size() + jet.hfcandidatesIds().size(), weight); + registry.fill(HIST("h_jet_ntracks_eventwiseconstituentsubtracted"), jet.tracksIds().size() + jet.candidatesIds().size(), weight); registry.fill(HIST("h2_centrality_jet_pt_eventwiseconstituentsubtracted"), centrality, jet.pt(), weight); registry.fill(HIST("h2_centrality_jet_eta_eventwiseconstituentsubtracted"), centrality, jet.eta(), weight); registry.fill(HIST("h2_centrality_jet_phi_eventwiseconstituentsubtracted"), centrality, jet.phi(), weight); - registry.fill(HIST("h2_centrality_jet_ntracks_eventwiseconstituentsubtracted"), centrality, jet.tracksIds().size() + jet.hfcandidatesIds().size(), weight); + registry.fill(HIST("h2_centrality_jet_ntracks_eventwiseconstituentsubtracted"), centrality, jet.tracksIds().size() + jet.candidatesIds().size(), weight); } registry.fill(HIST("h3_jet_r_jet_pt_centrality_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), centrality, weight); registry.fill(HIST("h3_jet_r_jet_pt_jet_eta_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), jet.eta(), weight); registry.fill(HIST("h3_jet_r_jet_pt_jet_phi_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), jet.phi(), weight); registry.fill(HIST("h3_jet_r_jet_eta_jet_phi_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.eta(), jet.phi(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_jet_ntracks_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), jet.tracksIds().size() + jet.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_jet_ntracks_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), jet.tracksIds().size() + jet.candidatesIds().size(), weight); registry.fill(HIST("h3_jet_r_jet_pt_jet_area_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), jet.area(), weight); for (auto& constituent : jet.template tracks_as()) { @@ -615,11 +645,11 @@ struct JetFinderHFQATask { registry.fill(HIST("h3_jet_r_jet_pt_track_phi_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), constituent.phi(), weight); } - for (auto& hfcandidate : jet.template hfcandidates_as>()) { - registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), hfcandidate.pt(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), hfcandidate.eta(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), hfcandidate.phi(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), hfcandidate.y(), weight); + for (auto& candidate : jet.template candidates_as>()) { + registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), candidate.pt(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), candidate.eta(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), candidate.phi(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), candidate.y(), weight); } } @@ -628,21 +658,22 @@ struct JetFinderHFQATask { { float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); - if (jet.pt() > pTHatMaxMCP * pTHat) { + if (jet.pt() > pTHatMaxMCP * pTHat || pTHat < pTHatAbsoluteMin) { return; } + registry.fill(HIST("h_jet_phat_part_weighted"), pTHat, weight); if (jet.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h_jet_pt_part"), jet.pt(), weight); registry.fill(HIST("h_jet_eta_part"), jet.eta(), weight); registry.fill(HIST("h_jet_phi_part"), jet.phi(), weight); - registry.fill(HIST("h_jet_ntracks_part"), jet.tracksIds().size() + jet.hfcandidatesIds().size(), weight); + registry.fill(HIST("h_jet_ntracks_part"), jet.tracksIds().size() + jet.candidatesIds().size(), weight); } registry.fill(HIST("h3_jet_r_part_jet_pt_part_jet_eta_part"), jet.r() / 100.0, jet.pt(), jet.eta(), weight); registry.fill(HIST("h3_jet_r_part_jet_pt_part_jet_phi_part"), jet.r() / 100.0, jet.pt(), jet.phi(), weight); registry.fill(HIST("h3_jet_r_part_jet_eta_part_jet_phi_part"), jet.r() / 100.0, jet.eta(), jet.phi(), weight); - registry.fill(HIST("h3_jet_r_part_jet_pt_part_jet_ntracks_part"), jet.r() / 100.0, jet.pt(), jet.tracksIds().size() + jet.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_r_part_jet_pt_part_jet_ntracks_part"), jet.r() / 100.0, jet.pt(), jet.tracksIds().size() + jet.candidatesIds().size(), weight); for (auto& constituent : jet.template tracks_as>()) { @@ -651,16 +682,16 @@ struct JetFinderHFQATask { registry.fill(HIST("h3_jet_r_part_jet_pt_part_track_phi_part"), jet.r() / 100.0, jet.pt(), constituent.phi(), weight); } - for (auto& hfcandidate : jet.template hfcandidates_as>()) { + for (auto& candidate : jet.template candidates_as>()) { - registry.fill(HIST("h3_jet_r_part_jet_pt_part_track_pt_part"), jet.r() / 100.0, jet.pt(), hfcandidate.pt(), weight); - registry.fill(HIST("h3_jet_r_part_jet_pt_part_track_eta_part"), jet.r() / 100.0, jet.pt(), hfcandidate.eta(), weight); - registry.fill(HIST("h3_jet_r_part_jet_pt_part_track_phi_part"), jet.r() / 100.0, jet.pt(), hfcandidate.phi(), weight); + registry.fill(HIST("h3_jet_r_part_jet_pt_part_track_pt_part"), jet.r() / 100.0, jet.pt(), candidate.pt(), weight); + registry.fill(HIST("h3_jet_r_part_jet_pt_part_track_eta_part"), jet.r() / 100.0, jet.pt(), candidate.eta(), weight); + registry.fill(HIST("h3_jet_r_part_jet_pt_part_track_phi_part"), jet.r() / 100.0, jet.pt(), candidate.phi(), weight); - registry.fill(HIST("h3_jet_r_part_jet_pt_part_candidate_pt_part"), jet.r() / 100.0, jet.pt(), hfcandidate.pt(), weight); - registry.fill(HIST("h3_jet_r_part_jet_pt_part_candidate_eta_part"), jet.r() / 100.0, jet.pt(), hfcandidate.eta(), weight); - registry.fill(HIST("h3_jet_r_part_jet_pt_part_candidate_phi_part"), jet.r() / 100.0, jet.pt(), hfcandidate.phi(), weight); - registry.fill(HIST("h3_jet_r_part_jet_pt_part_candidate_y_part"), jet.r() / 100.0, jet.pt(), hfcandidate.y(), weight); + registry.fill(HIST("h3_jet_r_part_jet_pt_part_candidate_pt_part"), jet.r() / 100.0, jet.pt(), candidate.pt(), weight); + registry.fill(HIST("h3_jet_r_part_jet_pt_part_candidate_eta_part"), jet.r() / 100.0, jet.pt(), candidate.eta(), weight); + registry.fill(HIST("h3_jet_r_part_jet_pt_part_candidate_phi_part"), jet.r() / 100.0, jet.pt(), candidate.phi(), weight); + registry.fill(HIST("h3_jet_r_part_jet_pt_part_candidate_y_part"), jet.r() / 100.0, jet.pt(), candidate.y(), weight); } } @@ -669,7 +700,7 @@ struct JetFinderHFQATask { { float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); - if (jetBase.pt() > pTHatMaxMCD * pTHat) { + if (jetBase.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { return; } auto candidateBasePt = 0.0; @@ -679,7 +710,7 @@ struct JetFinderHFQATask { auto candidateTagPhi = 0.0; auto candidateTagEta = 0.0; - auto candidateBase = jetBase.template hfcandidates_first_as>(); + auto candidateBase = jetBase.template candidates_first_as>(); candidateBasePt = candidateBase.pt(); candidateBasePhi = candidateBase.phi(); candidateBaseEta = candidateBase.eta(); @@ -689,7 +720,7 @@ struct JetFinderHFQATask { if (jetTag.pt() > pTHatMaxMCP * pTHat) { continue; } - auto candidateTag = jetTag.template hfcandidates_first_as>(); + auto candidateTag = jetTag.template candidates_first_as>(); candidateTagPt = candidateTag.pt(); candidateTagPhi = candidateTag.phi(); candidateTagEta = candidateTag.eta(); @@ -697,7 +728,7 @@ struct JetFinderHFQATask { registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeo"), jetBase.r() / 100.0, jetTag.pt(), jetBase.pt(), weight); registry.fill(HIST("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeo"), jetBase.r() / 100.0, jetTag.eta(), jetBase.eta(), weight); registry.fill(HIST("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeo"), jetBase.r() / 100.0, jetTag.phi(), jetBase.phi(), weight); - registry.fill(HIST("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeo"), jetBase.r() / 100.0, jetTag.tracksIds().size() + jetTag.hfcandidatesIds().size(), jetBase.tracksIds().size() + jetBase.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeo"), jetBase.r() / 100.0, jetTag.tracksIds().size() + jetTag.candidatesIds().size(), jetBase.tracksIds().size() + jetBase.candidatesIds().size(), weight); registry.fill(HIST("h3_jet_r_candidate_pt_tag_candidate_pt_base_matchedgeo"), jetBase.r() / 100.0, candidateTagPt, candidateBasePt, weight); registry.fill(HIST("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedgeo"), jetBase.r() / 100.0, candidateTagEta, candidateBaseEta, weight); registry.fill(HIST("h3_jet_r_candidate_phi_tag_candidate_phi_base_matchedgeo"), jetBase.r() / 100.0, candidateTagPhi, candidateBasePhi, weight); @@ -708,7 +739,7 @@ struct JetFinderHFQATask { if (jetBase.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeo"), jetTag.pt(), jetTag.eta(), jetBase.eta(), weight); registry.fill(HIST("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeo"), jetTag.pt(), jetTag.phi(), jetBase.phi(), weight); - registry.fill(HIST("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeo"), jetTag.pt(), jetTag.tracksIds().size() + jetTag.hfcandidatesIds().size(), jetBase.tracksIds().size() + jetBase.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeo"), jetTag.pt(), jetTag.tracksIds().size() + jetTag.candidatesIds().size(), jetBase.tracksIds().size() + jetBase.candidatesIds().size(), weight); } } } @@ -718,7 +749,7 @@ struct JetFinderHFQATask { if (jetTag.pt() > pTHatMaxMCP * pTHat) { continue; } - auto candidateTag = jetTag.template hfcandidates_first_as>(); + auto candidateTag = jetTag.template candidates_first_as>(); candidateTagPt = candidateTag.pt(); candidateTagPhi = candidateTag.phi(); candidateTagEta = candidateTag.eta(); @@ -726,7 +757,7 @@ struct JetFinderHFQATask { registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_pt_base_matchedpt"), jetBase.r() / 100.0, jetTag.pt(), jetBase.pt(), weight); registry.fill(HIST("h3_jet_r_jet_eta_tag_jet_eta_base_matchedpt"), jetBase.r() / 100.0, jetTag.eta(), jetBase.eta(), weight); registry.fill(HIST("h3_jet_r_jet_phi_tag_jet_phi_base_matchedpt"), jetBase.r() / 100.0, jetTag.phi(), jetBase.phi(), weight); - registry.fill(HIST("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedpt"), jetBase.r() / 100.0, jetTag.tracksIds().size() + jetTag.hfcandidatesIds().size(), jetBase.tracksIds().size() + jetBase.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedpt"), jetBase.r() / 100.0, jetTag.tracksIds().size() + jetTag.candidatesIds().size(), jetBase.tracksIds().size() + jetBase.candidatesIds().size(), weight); registry.fill(HIST("h3_jet_r_candidate_pt_tag_candidate_pt_base_matchedpt"), jetBase.r() / 100.0, candidateTagPt, candidateBasePt, weight); registry.fill(HIST("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedpt"), jetBase.r() / 100.0, candidateTagEta, candidateBaseEta, weight); registry.fill(HIST("h3_jet_r_candidate_phi_tag_candidate_phi_base_matchedpt"), jetBase.r() / 100.0, candidateTagPhi, candidateBasePhi, weight); @@ -737,7 +768,7 @@ struct JetFinderHFQATask { if (jetBase.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedpt"), jetTag.pt(), jetTag.eta(), jetBase.eta(), weight); registry.fill(HIST("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedpt"), jetTag.pt(), jetTag.phi(), jetBase.phi(), weight); - registry.fill(HIST("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedpt"), jetTag.pt(), jetTag.tracksIds().size() + jetTag.hfcandidatesIds().size(), jetBase.tracksIds().size() + jetBase.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedpt"), jetTag.pt(), jetTag.tracksIds().size() + jetTag.candidatesIds().size(), jetBase.tracksIds().size() + jetBase.candidatesIds().size(), weight); } } } @@ -746,7 +777,7 @@ struct JetFinderHFQATask { if (jetTag.pt() > pTHatMaxMCP * pTHat) { continue; } - auto candidateTag = jetTag.template hfcandidates_first_as>(); + auto candidateTag = jetTag.template candidates_first_as>(); candidateTagPt = candidateTag.pt(); candidateTagPhi = candidateTag.phi(); candidateTagEta = candidateTag.eta(); @@ -754,7 +785,7 @@ struct JetFinderHFQATask { registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_pt_base_matchedhf"), jetBase.r() / 100.0, jetTag.pt(), jetBase.pt(), weight); registry.fill(HIST("h3_jet_r_jet_eta_tag_jet_eta_base_matchedhf"), jetBase.r() / 100.0, jetTag.eta(), jetBase.eta(), weight); registry.fill(HIST("h3_jet_r_jet_phi_tag_jet_phi_base_matchedhf"), jetBase.r() / 100.0, jetTag.phi(), jetBase.phi(), weight); - registry.fill(HIST("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedhf"), jetBase.r() / 100.0, jetTag.tracksIds().size() + jetTag.hfcandidatesIds().size(), jetBase.tracksIds().size() + jetBase.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedhf"), jetBase.r() / 100.0, jetTag.tracksIds().size() + jetTag.candidatesIds().size(), jetBase.tracksIds().size() + jetBase.candidatesIds().size(), weight); registry.fill(HIST("h3_jet_r_candidate_pt_tag_candidate_pt_base_matchedhf"), jetBase.r() / 100.0, candidateTagPt, candidateBasePt, weight); registry.fill(HIST("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedhf"), jetBase.r() / 100.0, candidateTagEta, candidateBaseEta, weight); registry.fill(HIST("h3_jet_r_candidate_phi_tag_candidate_phi_base_matchedhf"), jetBase.r() / 100.0, candidateTagPhi, candidateBasePhi, weight); @@ -765,7 +796,7 @@ struct JetFinderHFQATask { if (jetBase.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedhf"), jetTag.pt(), jetTag.eta(), jetBase.eta(), weight); registry.fill(HIST("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedhf"), jetTag.pt(), jetTag.phi(), jetBase.phi(), weight); - registry.fill(HIST("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedhf"), jetTag.pt(), jetTag.tracksIds().size() + jetTag.hfcandidatesIds().size(), jetBase.tracksIds().size() + jetBase.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedhf"), jetTag.pt(), jetTag.tracksIds().size() + jetTag.candidatesIds().size(), jetBase.tracksIds().size() + jetBase.candidatesIds().size(), weight); } } } @@ -776,7 +807,7 @@ struct JetFinderHFQATask { } if (jetBase.template matchedJetGeo_first_as>().globalIndex() == jetBase.template matchedJetPt_first_as>().globalIndex()) { // not a good way to do this - auto candidateTag = jetTag.template hfcandidates_first_as>(); + auto candidateTag = jetTag.template candidates_first_as>(); candidateTagPt = candidateTag.pt(); candidateTagPhi = candidateTag.phi(); candidateTagEta = candidateTag.eta(); @@ -784,7 +815,7 @@ struct JetFinderHFQATask { registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeopt"), jetBase.r() / 100.0, jetTag.pt(), jetBase.pt(), weight); registry.fill(HIST("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeopt"), jetBase.r() / 100.0, jetTag.eta(), jetBase.eta(), weight); registry.fill(HIST("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeopt"), jetBase.r() / 100.0, jetTag.phi(), jetBase.phi(), weight); - registry.fill(HIST("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeopt"), jetBase.r() / 100.0, jetTag.tracksIds().size() + jetTag.hfcandidatesIds().size(), jetBase.tracksIds().size() + jetBase.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeopt"), jetBase.r() / 100.0, jetTag.tracksIds().size() + jetTag.candidatesIds().size(), jetBase.tracksIds().size() + jetBase.candidatesIds().size(), weight); registry.fill(HIST("h3_jet_r_candidate_pt_tag_candidate_pt_base_matchedgeopt"), jetBase.r() / 100.0, candidateTagPt, candidateBasePt, weight); registry.fill(HIST("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedgeopt"), jetBase.r() / 100.0, candidateTagEta, candidateBaseEta, weight); registry.fill(HIST("h3_jet_r_candidate_phi_tag_candidate_phi_base_matchedgeopt"), jetBase.r() / 100.0, candidateTagPhi, candidateBasePhi, weight); @@ -795,7 +826,7 @@ struct JetFinderHFQATask { if (jetBase.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeopt"), jetTag.pt(), jetTag.eta(), jetBase.eta(), weight); registry.fill(HIST("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeopt"), jetTag.pt(), jetTag.phi(), jetBase.phi(), weight); - registry.fill(HIST("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeopt"), jetTag.pt(), jetTag.tracksIds().size() + jetTag.hfcandidatesIds().size(), jetBase.tracksIds().size() + jetBase.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeopt"), jetTag.pt(), jetTag.tracksIds().size() + jetTag.candidatesIds().size(), jetBase.tracksIds().size() + jetBase.candidatesIds().size(), weight); } } } @@ -807,7 +838,7 @@ struct JetFinderHFQATask { } if (jetBase.template matchedJetGeo_first_as>().globalIndex() == jetBase.template matchedJetCand_first_as>().globalIndex()) { // not a good way to do this - auto candidateTag = jetTag.template hfcandidates_first_as>(); + auto candidateTag = jetTag.template candidates_first_as>(); candidateTagPt = candidateTag.pt(); candidateTagPhi = candidateTag.phi(); candidateTagEta = candidateTag.eta(); @@ -815,7 +846,7 @@ struct JetFinderHFQATask { registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeohf"), jetBase.r() / 100.0, jetTag.pt(), jetBase.pt(), weight); registry.fill(HIST("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeohf"), jetBase.r() / 100.0, jetTag.eta(), jetBase.eta(), weight); registry.fill(HIST("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeohf"), jetBase.r() / 100.0, jetTag.phi(), jetBase.phi(), weight); - registry.fill(HIST("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeohf"), jetBase.r() / 100.0, jetTag.tracksIds().size() + jetTag.hfcandidatesIds().size(), jetBase.tracksIds().size() + jetBase.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeohf"), jetBase.r() / 100.0, jetTag.tracksIds().size() + jetTag.candidatesIds().size(), jetBase.tracksIds().size() + jetBase.candidatesIds().size(), weight); registry.fill(HIST("h3_jet_r_candidate_pt_tag_candidate_pt_base_matchedgeohf"), jetBase.r() / 100.0, candidateTagPt, candidateBasePt, weight); registry.fill(HIST("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedgeohf"), jetBase.r() / 100.0, candidateTagEta, candidateBaseEta, weight); registry.fill(HIST("h3_jet_r_candidate_phi_tag_candidate_phi_base_matchedgeohf"), jetBase.r() / 100.0, candidateTagPhi, candidateBasePhi, weight); @@ -826,7 +857,7 @@ struct JetFinderHFQATask { if (jetBase.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeohf"), jetTag.pt(), jetTag.eta(), jetBase.eta(), weight); registry.fill(HIST("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeohf"), jetTag.pt(), jetTag.phi(), jetBase.phi(), weight); - registry.fill(HIST("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeohf"), jetTag.pt(), jetTag.tracksIds().size() + jetTag.hfcandidatesIds().size(), jetBase.tracksIds().size() + jetBase.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeohf"), jetTag.pt(), jetTag.tracksIds().size() + jetTag.candidatesIds().size(), jetBase.tracksIds().size() + jetBase.candidatesIds().size(), weight); } } } @@ -838,7 +869,7 @@ struct JetFinderHFQATask { } if (jetBase.template matchedJetPt_first_as>().globalIndex() == jetBase.template matchedJetCand_first_as>().globalIndex()) { // not a good way to do this - auto candidateTag = jetTag.template hfcandidates_first_as>(); + auto candidateTag = jetTag.template candidates_first_as>(); candidateTagPt = candidateTag.pt(); candidateTagPhi = candidateTag.phi(); candidateTagEta = candidateTag.eta(); @@ -846,7 +877,7 @@ struct JetFinderHFQATask { registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_pt_base_matchedpthf"), jetBase.r() / 100.0, jetTag.pt(), jetBase.pt(), weight); registry.fill(HIST("h3_jet_r_jet_eta_tag_jet_eta_base_matchedpthf"), jetBase.r() / 100.0, jetTag.eta(), jetBase.eta(), weight); registry.fill(HIST("h3_jet_r_jet_phi_tag_jet_phi_base_matchedpthf"), jetBase.r() / 100.0, jetTag.phi(), jetBase.phi(), weight); - registry.fill(HIST("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedpthf"), jetBase.r() / 100.0, jetTag.tracksIds().size() + jetTag.hfcandidatesIds().size(), jetBase.tracksIds().size() + jetBase.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedpthf"), jetBase.r() / 100.0, jetTag.tracksIds().size() + jetTag.candidatesIds().size(), jetBase.tracksIds().size() + jetBase.candidatesIds().size(), weight); registry.fill(HIST("h3_jet_r_candidate_pt_tag_candidate_pt_base_matchedpthf"), jetBase.r() / 100.0, candidateTagPt, candidateBasePt, weight); registry.fill(HIST("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedpthf"), jetBase.r() / 100.0, candidateTagEta, candidateBaseEta, weight); registry.fill(HIST("h3_jet_r_candidate_phi_tag_candidate_phi_base_matchedpthf"), jetBase.r() / 100.0, candidateTagPhi, candidateBasePhi, weight); @@ -857,7 +888,7 @@ struct JetFinderHFQATask { if (jetBase.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedpthf"), jetTag.pt(), jetTag.eta(), jetBase.eta(), weight); registry.fill(HIST("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedpthf"), jetTag.pt(), jetTag.phi(), jetBase.phi(), weight); - registry.fill(HIST("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedpthf"), jetTag.pt(), jetTag.tracksIds().size() + jetTag.hfcandidatesIds().size(), jetBase.tracksIds().size() + jetBase.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedpthf"), jetTag.pt(), jetTag.tracksIds().size() + jetTag.candidatesIds().size(), jetBase.tracksIds().size() + jetBase.candidatesIds().size(), weight); } } } @@ -871,7 +902,7 @@ struct JetFinderHFQATask { if (jetBase.template matchedJetGeo_first_as>().globalIndex() == jetBase.template matchedJetPt_first_as>().globalIndex()) { if (jetBase.template matchedJetGeo_first_as>().globalIndex() == jetBase.template matchedJetCand_first_as>().globalIndex()) { // not a good way to do this - auto candidateTag = jetTag.template hfcandidates_first_as>(); + auto candidateTag = jetTag.template candidates_first_as>(); candidateTagPt = candidateTag.pt(); candidateTagPhi = candidateTag.phi(); candidateTagEta = candidateTag.eta(); @@ -879,7 +910,7 @@ struct JetFinderHFQATask { registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeopthf"), jetBase.r() / 100.0, jetTag.pt(), jetBase.pt(), weight); registry.fill(HIST("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeopthf"), jetBase.r() / 100.0, jetTag.eta(), jetBase.eta(), weight); registry.fill(HIST("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeopthf"), jetBase.r() / 100.0, jetTag.phi(), jetBase.phi(), weight); - registry.fill(HIST("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeopthf"), jetBase.r() / 100.0, jetTag.tracksIds().size() + jetTag.hfcandidatesIds().size(), jetBase.tracksIds().size() + jetBase.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeopthf"), jetBase.r() / 100.0, jetTag.tracksIds().size() + jetTag.candidatesIds().size(), jetBase.tracksIds().size() + jetBase.candidatesIds().size(), weight); registry.fill(HIST("h3_jet_r_candidate_pt_tag_candidate_pt_base_matchedgeopthf"), jetBase.r() / 100.0, candidateTagPt, candidateBasePt, weight); registry.fill(HIST("h3_jet_r_candidate_eta_tag_candidate_eta_base_matchedgeopthf"), jetBase.r() / 100.0, candidateTagEta, candidateBaseEta, weight); registry.fill(HIST("h3_jet_r_candidate_phi_tag_candidate_phi_base_matchedgeopthf"), jetBase.r() / 100.0, candidateTagPhi, candidateBasePhi, weight); @@ -890,7 +921,7 @@ struct JetFinderHFQATask { if (jetBase.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeopthf"), jetTag.pt(), jetTag.eta(), jetBase.eta(), weight); registry.fill(HIST("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeopthf"), jetTag.pt(), jetTag.phi(), jetBase.phi(), weight); - registry.fill(HIST("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeopthf"), jetTag.pt(), jetTag.tracksIds().size() + jetTag.hfcandidatesIds().size(), jetBase.tracksIds().size() + jetBase.hfcandidatesIds().size(), weight); + registry.fill(HIST("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeopthf"), jetTag.pt(), jetTag.tracksIds().size() + jetTag.candidatesIds().size(), jetBase.tracksIds().size() + jetBase.candidatesIds().size(), weight); } } } @@ -901,29 +932,86 @@ struct JetFinderHFQATask { template void fillTrackHistograms(T const& collision, U const& tracks, float weight = 1.0) { + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (pTHat < pTHatAbsoluteMin) { + return; + } for (auto const& track : tracks) { if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { continue; } - registry.fill(HIST("h2_centrality_track_pt"), collision.centrality(), track.pt(), weight); - registry.fill(HIST("h2_centrality_track_eta"), collision.centrality(), track.eta(), weight); - registry.fill(HIST("h2_centrality_track_phi"), collision.centrality(), track.phi(), weight); - registry.fill(HIST("h2_centrality_track_energy"), collision.centrality(), track.energy(), weight); + registry.fill(HIST("h3_centrality_track_pt_track_phi"), collision.centrality(), track.pt(), track.phi(), weight); + registry.fill(HIST("h3_centrality_track_pt_track_eta"), collision.centrality(), track.pt(), track.eta(), weight); + registry.fill(HIST("h3_track_pt_track_eta_track_phi"), track.pt(), track.eta(), track.phi(), weight); } } - void processDummy(JetCollisions const&) + template + void randomCone(T const& collision, U const& jets, V const& candidates, M const& tracks) + { + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + for (auto const& candidate : candidates) { + TRandom3 randomNumber(0); + float randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); + float randomConePhi = randomNumber.Uniform(0.0, 2 * M_PI); + float randomConePt = 0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-M_PI)); + float dEta = track.eta() - randomConeEta; + if (TMath::Sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePt += track.pt(); + } + } + } + registry.fill(HIST("h2_centrality_rhorandomcone"), collision.centrality(), randomConePt - M_PI * randomConeR * randomConeR * candidate.rho()); + + // removing the leading jet from the random cone + if (jets.size() > 0) { // if there are no jets in the acceptance (from the jetfinder cuts) then there can be no leading jet + float dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, static_cast(-M_PI)); + float dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; + + bool jetWasInCone = false; + while (TMath::Sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < jets.iteratorAt(0).r() / 100.0 + randomConeR) { + jetWasInCone = true; + randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); + randomConePhi = randomNumber.Uniform(0.0, 2 * M_PI); + dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, static_cast(-M_PI)); + dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; + } + if (jetWasInCone) { + randomConePt = 0.0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-M_PI)); + float dEta = track.eta() - randomConeEta; + if (TMath::Sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePt += track.pt(); + } + } + } + } + } + registry.fill(HIST("h2_centrality_rhorandomconewithoutleadingjet"), collision.centrality(), randomConePt - M_PI * randomConeR * randomConeR * candidate.rho()); + break; // currently only fills it for the first candidate in the event (not pT ordered). Jet is pT ordered so results for excluding leading jet might not be as expected + } + } + + void processDummy(aod::JetCollisions const&) { } PROCESS_SWITCH(JetFinderHFQATask, processDummy, "dummy task", true); - void processJetsData(soa::Filtered::iterator const& collision, JetTableDataJoined const& jets, CandidateTableData const&, JetTracks const&) + void processJetsData(soa::Filtered::iterator const& collision, JetTableDataJoined const& jets, CandidateTableData const&, aod::JetTracks const&) { for (auto const& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { continue; } fillHistograms(jet, collision.centrality()); @@ -931,27 +1019,43 @@ struct JetFinderHFQATask { } PROCESS_SWITCH(JetFinderHFQATask, processJetsData, "jet finder HF QA data", false); - void processJetsRhoAreaSubData(soa::Filtered::iterator const& collision, - BkgRhoTable const& bkgRhos, + void processJetsRhoAreaSubData(soa::Filtered::iterator const& collision, JetTableDataJoined const& jets, - CandidateTableData const&, - JetTracks const&) + soa::Join const&, + aod::JetTracks const&) { for (auto const& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { continue; } - auto const jetCandidate = jet.template hfcandidates_first_as(); - auto bkgRho = jethfutilities::slicedPerCandidate(bkgRhos, jetCandidate, perD0CandidateRhos, perLcCandidateRhos, perBplusCandidateRhos).iteratorAt(0); - fillRhoAreaSubtractedHistograms(jet, collision.centrality(), bkgRho.rho()); + auto const candidate = jet.template candidates_first_as>(); + fillRhoAreaSubtractedHistograms(jet, collision.centrality(), candidate.rho()); } } PROCESS_SWITCH(JetFinderHFQATask, processJetsRhoAreaSubData, "jet finder HF QA for rho-area subtracted jets", false); - void processEvtWiseConstSubJetsData(soa::Filtered::iterator const& collision, JetTableDataSubJoined const& jets, CandidateTableData const&, JetTracksDataSub const&) + void processJetsRhoAreaSubMCD(soa::Filtered::iterator const& collision, + JetTableMCDJoined const& jets, + soa::Join const&, + aod::JetTracks const&) + { + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + auto const candidate = jet.template candidates_first_as>(); + fillRhoAreaSubtractedHistograms(jet, collision.centrality(), candidate.rho()); + } + } + PROCESS_SWITCH(JetFinderHFQATask, processJetsRhoAreaSubMCD, "jet finder HF QA for rho-area subtracted mcd jets", false); + + void processEvtWiseConstSubJetsData(soa::Filtered::iterator const& collision, JetTableDataSubJoined const& jets, CandidateTableData const&, JetTracksDataSub const&) { for (auto const& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { @@ -965,16 +1069,16 @@ struct JetFinderHFQATask { } PROCESS_SWITCH(JetFinderHFQATask, processEvtWiseConstSubJetsData, "jet finder HF QA for eventwise constituent-subtracted jets data", false); - void processJetsSubMatched(soa::Filtered::iterator const&, + void processJetsSubMatched(soa::Filtered::iterator const&, JetTableDataMatchedJoined const& jets, JetTableDataSubMatchedJoined const&, - JetTracks const&, JetTracksDataSub const&, CandidateTableData const&) + aod::JetTracks const&, JetTracksDataSub const&, CandidateTableData const&) { for (const auto& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { continue; } fillMatchedHistograms(jet); @@ -982,13 +1086,13 @@ struct JetFinderHFQATask { } PROCESS_SWITCH(JetFinderHFQATask, processJetsSubMatched, "jet finder HF QA matched unsubtracted and constituent subtracted jets", false); - void processJetsMCD(soa::Filtered::iterator const& collision, JetTableMCDJoined const& jets, CandidateTableMCD const&, JetTracks const&) + void processJetsMCD(soa::Filtered::iterator const& collision, JetTableMCDJoined const& jets, CandidateTableMCD const&, aod::JetTracks const&) { for (auto const& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { continue; } fillHistograms(jet, collision.centrality()); @@ -996,13 +1100,13 @@ struct JetFinderHFQATask { } PROCESS_SWITCH(JetFinderHFQATask, processJetsMCD, "jet finder HF QA mcd", false); - void processJetsMCDWeighted(soa::Filtered::iterator const& collision, JetTableMCDWeightedJoined const& jets, CandidateTableMCD const&, JetTracks const&) + void processJetsMCDWeighted(soa::Filtered::iterator const& collision, JetTableMCDWeightedJoined const& jets, CandidateTableMCD const&, aod::JetTracks const&) { for (auto const& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { continue; } fillHistograms(jet, collision.centrality(), jet.eventWeight()); @@ -1010,35 +1114,35 @@ struct JetFinderHFQATask { } PROCESS_SWITCH(JetFinderHFQATask, processJetsMCDWeighted, "jet finder HF QA mcd on weighted events", false); - void processJetsMCP(typename JetTableMCPJoined::iterator const& jet, JetParticles const&, CandidateTableMCP const&) + void processJetsMCP(typename JetTableMCPJoined::iterator const& jet, aod::JetParticles const&, CandidateTableMCP const&) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { return; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { return; } - fillMCPHistograms(jet); + fillMCPHistograms(jet); } PROCESS_SWITCH(JetFinderHFQATask, processJetsMCP, "jet finder HF QA mcp", false); - void processJetsMCPWeighted(typename JetTableMCPWeightedJoined::iterator const& jet, JetParticles const&, CandidateTableMCP const&) + void processJetsMCPWeighted(typename JetTableMCPWeightedJoined::iterator const& jet, aod::JetParticles const&, CandidateTableMCP const&) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { return; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { return; } - fillMCPHistograms(jet, jet.eventWeight()); + fillMCPHistograms(jet, jet.eventWeight()); } PROCESS_SWITCH(JetFinderHFQATask, processJetsMCPWeighted, "jet finder HF QA mcp on weighted events", false); - void processJetsMCPMCDMatched(soa::Filtered::iterator const&, + void processJetsMCPMCDMatched(soa::Filtered::iterator const&, JetTableMCDMatchedJoined const& mcdjets, JetTableMCPMatchedJoined const&, CandidateTableMCD const&, - JetTracks const&, JetParticles const&, + aod::JetTracks const&, aod::JetParticles const&, CandidateTableMCP const&) { @@ -1046,7 +1150,7 @@ struct JetFinderHFQATask { if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(mcdjet)) { + if (!isAcceptedJet(mcdjet)) { continue; } fillMatchedHistograms(mcdjet); @@ -1054,11 +1158,11 @@ struct JetFinderHFQATask { } PROCESS_SWITCH(JetFinderHFQATask, processJetsMCPMCDMatched, "jet finder HF QA matched mcp and mcd", false); - void processJetsMCPMCDMatchedWeighted(soa::Filtered::iterator const&, + void processJetsMCPMCDMatchedWeighted(soa::Filtered::iterator const&, JetTableMCDMatchedWeightedJoined const& mcdjets, JetTableMCPMatchedWeightedJoined const&, CandidateTableMCD const&, - JetTracks const&, JetParticles const&, + aod::JetTracks const&, aod::JetParticles const&, CandidateTableMCP const&) { @@ -1066,7 +1170,7 @@ struct JetFinderHFQATask { if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(mcdjet)) { + if (!isAcceptedJet(mcdjet)) { continue; } fillMatchedHistograms(mcdjet, mcdjet.eventWeight()); @@ -1074,33 +1178,36 @@ struct JetFinderHFQATask { } PROCESS_SWITCH(JetFinderHFQATask, processJetsMCPMCDMatchedWeighted, "jet finder HF QA matched mcp and mcd on weighted events", false); - void processMCCollisionsWeighted(JetMcCollision const& collision) + void processMCCollisionsWeighted(aod::JetMcCollision const& collision) { + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } registry.fill(HIST("h_collision_eventweight_part"), collision.weight()); } PROCESS_SWITCH(JetFinderHFQATask, processMCCollisionsWeighted, "collision QA for weighted events", false); - void processTriggeredData(soa::Join::iterator const& collision, + void processTriggeredData(soa::Join::iterator const& collision, JetTableDataJoined const& jets, CandidateTableData const&, - soa::Filtered const& tracks) + soa::Filtered const& tracks) { registry.fill(HIST("h_collision_trigger_events"), 0.5); // all events if (collision.posZ() > vertexZCut) { return; } registry.fill(HIST("h_collision_trigger_events"), 1.5); // all events with z vertex cut - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } registry.fill(HIST("h_collision_trigger_events"), 2.5); // events with sel8() - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt)) { registry.fill(HIST("h_collision_trigger_events"), 3.5); // events with high pT triggered jets } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { registry.fill(HIST("h_collision_trigger_events"), 4.5); // events with high pT triggered jets } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow) && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt) && jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { registry.fill(HIST("h_collision_trigger_events"), 5.5); // events with high pT triggered jets } @@ -1112,19 +1219,19 @@ struct JetFinderHFQATask { for (auto& jet : jets) { for (std::size_t iJetRadius = 0; iJetRadius < jetRadiiValues.size(); iJetRadius++) { if (jet.r() == round(jetRadiiValues[iJetRadius] * 100.0f)) { - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow) && !filledJetR_Low[iJetRadius]) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt) && !filledJetR_Low[iJetRadius]) { filledJetR_Low[iJetRadius] = true; for (double pt = 0.0; pt <= jet.pt(); pt += 1.0) { registry.fill(HIST("h2_jet_r_jet_pT_triggered_Low"), jet.r() / 100.0, pt); } } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh) && !filledJetR_High[iJetRadius]) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt) && !filledJetR_High[iJetRadius]) { filledJetR_High[iJetRadius] = true; for (double pt = 0.0; pt <= jet.pt(); pt += 1.0) { registry.fill(HIST("h2_jet_r_jet_pT_triggered_High"), jet.r() / 100.0, pt); } } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow) && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh) && !filledJetR_Both[iJetRadius]) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt) && jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt) && !filledJetR_Both[iJetRadius]) { filledJetR_Both[iJetRadius] = true; for (double pt = 0.0; pt <= jet.pt(); pt += 1.0) { registry.fill(HIST("h2_jet_r_jet_pT_triggered_Both"), jet.r() / 100.0, pt); @@ -1141,67 +1248,67 @@ struct JetFinderHFQATask { registry.fill(HIST("h3_jet_r_jet_eta_collision"), jet.r() / 100.0, jet.eta(), 0.0); registry.fill(HIST("h3_jet_r_jet_phi_collision"), jet.r() / 100.0, jet.phi(), 0.0); - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt)) { registry.fill(HIST("h3_jet_r_jet_pt_collision"), jet.r() / 100.0, jet.pt(), 1.0); registry.fill(HIST("h3_jet_r_jet_eta_collision"), jet.r() / 100.0, jet.eta(), 1.0); registry.fill(HIST("h3_jet_r_jet_phi_collision"), jet.r() / 100.0, jet.phi(), 1.0); } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { registry.fill(HIST("h3_jet_r_jet_pt_collision"), jet.r() / 100.0, jet.pt(), 2.0); registry.fill(HIST("h3_jet_r_jet_eta_collision"), jet.r() / 100.0, jet.eta(), 2.0); registry.fill(HIST("h3_jet_r_jet_phi_collision"), jet.r() / 100.0, jet.phi(), 2.0); } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow) && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt) && jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { registry.fill(HIST("h3_jet_r_jet_pt_collision"), jet.r() / 100.0, jet.pt(), 3.0); registry.fill(HIST("h3_jet_r_jet_eta_collision"), jet.r() / 100.0, jet.eta(), 3.0); registry.fill(HIST("h3_jet_r_jet_phi_collision"), jet.r() / 100.0, jet.phi(), 3.0); } - for (auto& constituent : jet.template tracks_as>()) { + for (auto& constituent : jet.template tracks_as>()) { registry.fill(HIST("h3_jet_r_jet_pt_track_pt_MB"), jet.r() / 100.0, jet.pt(), constituent.pt()); registry.fill(HIST("h3_jet_r_jet_pt_track_eta_MB"), jet.r() / 100.0, jet.pt(), constituent.eta()); registry.fill(HIST("h3_jet_r_jet_pt_track_phi_MB"), jet.r() / 100.0, jet.pt(), constituent.phi()); - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt)) { registry.fill(HIST("h3_jet_r_jet_pt_track_pt_Triggered_Low"), jet.r() / 100.0, jet.pt(), constituent.pt()); registry.fill(HIST("h3_jet_r_jet_pt_track_eta_Triggered_Low"), jet.r() / 100.0, jet.pt(), constituent.eta()); registry.fill(HIST("h3_jet_r_jet_pt_track_phi_Triggered_Low"), jet.r() / 100.0, jet.pt(), constituent.phi()); } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { registry.fill(HIST("h3_jet_r_jet_pt_track_pt_Triggered_High"), jet.r() / 100.0, jet.pt(), constituent.pt()); registry.fill(HIST("h3_jet_r_jet_pt_track_eta_Triggered_High"), jet.r() / 100.0, jet.pt(), constituent.eta()); registry.fill(HIST("h3_jet_r_jet_pt_track_phi_Triggered_High"), jet.r() / 100.0, jet.pt(), constituent.phi()); } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow) && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt) && jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { registry.fill(HIST("h3_jet_r_jet_pt_track_pt_Triggered_Both"), jet.r() / 100.0, jet.pt(), constituent.pt()); registry.fill(HIST("h3_jet_r_jet_pt_track_eta_Triggered_Both"), jet.r() / 100.0, jet.pt(), constituent.eta()); registry.fill(HIST("h3_jet_r_jet_pt_track_phi_Triggered_Both"), jet.r() / 100.0, jet.pt(), constituent.phi()); } } - for (auto& hfcandidate : jet.template hfcandidates_as()) { - - registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_MB"), jet.r() / 100.0, jet.pt(), hfcandidate.pt()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_MB"), jet.r() / 100.0, jet.pt(), hfcandidate.eta()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_MB"), jet.r() / 100.0, jet.pt(), hfcandidate.phi()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_MB"), jet.r() / 100.0, jet.pt(), hfcandidate.y()); - - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow)) { - registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_Triggered_Low"), jet.r() / 100.0, jet.pt(), hfcandidate.pt()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_Triggered_Low"), jet.r() / 100.0, jet.pt(), hfcandidate.eta()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_Triggered_Low"), jet.r() / 100.0, jet.pt(), hfcandidate.phi()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_Triggered_Low"), jet.r() / 100.0, jet.pt(), hfcandidate.y()); + for (auto& candidate : jet.template candidates_as()) { + + registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_MB"), jet.r() / 100.0, jet.pt(), candidate.pt()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_MB"), jet.r() / 100.0, jet.pt(), candidate.eta()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_MB"), jet.r() / 100.0, jet.pt(), candidate.phi()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_MB"), jet.r() / 100.0, jet.pt(), candidate.y()); + + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt)) { + registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_Triggered_Low"), jet.r() / 100.0, jet.pt(), candidate.pt()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_Triggered_Low"), jet.r() / 100.0, jet.pt(), candidate.eta()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_Triggered_Low"), jet.r() / 100.0, jet.pt(), candidate.phi()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_Triggered_Low"), jet.r() / 100.0, jet.pt(), candidate.y()); } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { - registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_Triggered_High"), jet.r() / 100.0, jet.pt(), hfcandidate.pt()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_Triggered_High"), jet.r() / 100.0, jet.pt(), hfcandidate.eta()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_Triggered_High"), jet.r() / 100.0, jet.pt(), hfcandidate.phi()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_Triggered_High"), jet.r() / 100.0, jet.pt(), hfcandidate.y()); + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { + registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_Triggered_High"), jet.r() / 100.0, jet.pt(), candidate.pt()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_Triggered_High"), jet.r() / 100.0, jet.pt(), candidate.eta()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_Triggered_High"), jet.r() / 100.0, jet.pt(), candidate.phi()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_Triggered_High"), jet.r() / 100.0, jet.pt(), candidate.y()); } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow) && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { - registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_Triggered_Both"), jet.r() / 100.0, jet.pt(), hfcandidate.pt()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_Triggered_Both"), jet.r() / 100.0, jet.pt(), hfcandidate.eta()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_Triggered_Both"), jet.r() / 100.0, jet.pt(), hfcandidate.phi()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_Triggered_Both"), jet.r() / 100.0, jet.pt(), hfcandidate.y()); + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt) && jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { + registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_Triggered_Both"), jet.r() / 100.0, jet.pt(), candidate.pt()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_Triggered_Both"), jet.r() / 100.0, jet.pt(), candidate.eta()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_Triggered_Both"), jet.r() / 100.0, jet.pt(), candidate.phi()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_Triggered_Both"), jet.r() / 100.0, jet.pt(), candidate.y()); } } } @@ -1214,17 +1321,17 @@ struct JetFinderHFQATask { registry.fill(HIST("h_track_eta_MB"), track.eta()); registry.fill(HIST("h_track_phi_MB"), track.phi()); - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt)) { registry.fill(HIST("h_track_pt_Triggered_Low"), track.pt()); registry.fill(HIST("h_track_eta_Triggered_Low"), track.eta()); registry.fill(HIST("h_track_phi_Triggered_Low"), track.phi()); } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { registry.fill(HIST("h_track_pt_Triggered_High"), track.pt()); registry.fill(HIST("h_track_eta_Triggered_High"), track.eta()); registry.fill(HIST("h_track_phi_Triggered_High"), track.phi()); } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow) && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt) && jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { registry.fill(HIST("h_track_pt_Triggered_Both"), track.pt()); registry.fill(HIST("h_track_eta_Triggered_Both"), track.eta()); registry.fill(HIST("h_track_phi_Triggered_Both"), track.phi()); @@ -1234,21 +1341,21 @@ struct JetFinderHFQATask { PROCESS_SWITCH(JetFinderHFQATask, processTriggeredData, "QA for charged jet trigger", false); - void processHFTriggeredData(soa::Join::iterator const& collision, + void processHFTriggeredData(soa::Join::iterator const& collision, JetTableDataJoined const& jets, CandidateTableData const&, - soa::Filtered const&) + soa::Filtered const&) { int hfLowTrigger = -2; int hfHighTrigger = -2; if constexpr (jethfutilities::isD0Table()) { - hfLowTrigger = jetderiveddatautilities::JTrigSelChHF::chargedD0Low; - hfHighTrigger = jetderiveddatautilities::JTrigSelChHF::chargedD0High; + hfLowTrigger = jetderiveddatautilities::JTrigSel::JetD0ChLowPt; + hfHighTrigger = jetderiveddatautilities::JTrigSel::JetD0ChHighPt; } if constexpr (jethfutilities::isLcTable()) { - hfLowTrigger = jetderiveddatautilities::JTrigSelChHF::chargedLcLow; - hfHighTrigger = jetderiveddatautilities::JTrigSelChHF::chargedLcHigh; + hfLowTrigger = jetderiveddatautilities::JTrigSel::JetLcChLowPt; + hfHighTrigger = jetderiveddatautilities::JTrigSel::JetLcChHighPt; } registry.fill(HIST("h_collision_hftrigger_events"), 0.5); // all events @@ -1256,32 +1363,32 @@ struct JetFinderHFQATask { return; } registry.fill(HIST("h_collision_hftrigger_events"), 1.5); // all events with z vertex cut - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } registry.fill(HIST("h_collision_hftrigger_events"), 2.5); // events with sel8() - if (jetderiveddatautilities::selectChargedHFTrigger(collision, jetderiveddatautilities::JTrigSelChHF::chargedD0Low)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetD0ChLowPt)) { registry.fill(HIST("h_collision_hftrigger_events"), 3.5); // events with high pT triggered jets } - if (jetderiveddatautilities::selectChargedHFTrigger(collision, jetderiveddatautilities::JTrigSelChHF::chargedD0High)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetD0ChHighPt)) { registry.fill(HIST("h_collision_hftrigger_events"), 4.5); // events with high pT triggered jets } - if (jetderiveddatautilities::selectChargedHFTrigger(collision, jetderiveddatautilities::JTrigSelChHF::chargedD0Low) && jetderiveddatautilities::selectChargedHFTrigger(collision, jetderiveddatautilities::JTrigSelChHF::chargedD0High)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetD0ChLowPt) && jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetD0ChHighPt)) { registry.fill(HIST("h_collision_hftrigger_events"), 5.5); // events with high pT triggered jets } - if (jetderiveddatautilities::selectChargedHFTrigger(collision, jetderiveddatautilities::JTrigSelChHF::chargedLcLow)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetLcChLowPt)) { registry.fill(HIST("h_collision_hftrigger_events"), 6.5); // events with high pT triggered jets } - if (jetderiveddatautilities::selectChargedHFTrigger(collision, jetderiveddatautilities::JTrigSelChHF::chargedLcHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetLcChHighPt)) { registry.fill(HIST("h_collision_hftrigger_events"), 7.5); // events with high pT triggered jets } - if (jetderiveddatautilities::selectChargedHFTrigger(collision, jetderiveddatautilities::JTrigSelChHF::chargedLcLow) && jetderiveddatautilities::selectChargedHFTrigger(collision, jetderiveddatautilities::JTrigSelChHF::chargedLcHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetLcChLowPt) && jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetLcChHighPt)) { registry.fill(HIST("h_collision_hftrigger_events"), 8.5); // events with high pT triggered jets } - if (jetderiveddatautilities::selectChargedHFTrigger(collision, jetderiveddatautilities::JTrigSelChHF::chargedD0Low) && jetderiveddatautilities::selectChargedHFTrigger(collision, jetderiveddatautilities::JTrigSelChHF::chargedLcLow)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetD0ChLowPt) && jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetLcChLowPt)) { registry.fill(HIST("h_collision_hftrigger_events"), 9.5); // events with high pT triggered jets } - if (jetderiveddatautilities::selectChargedHFTrigger(collision, jetderiveddatautilities::JTrigSelChHF::chargedD0High) && jetderiveddatautilities::selectChargedHFTrigger(collision, jetderiveddatautilities::JTrigSelChHF::chargedLcHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetD0ChHighPt) && jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetLcChHighPt)) { registry.fill(HIST("h_collision_hftrigger_events"), 10.5); // events with high pT triggered jets } @@ -1293,13 +1400,13 @@ struct JetFinderHFQATask { for (auto& jet : jets) { for (std::size_t iJetRadius = 0; iJetRadius < jetRadiiValues.size(); iJetRadius++) { if (jet.r() == round(jetRadiiValues[iJetRadius] * 100.0f)) { - if (jetderiveddatautilities::selectChargedHFTrigger(collision, hfLowTrigger) && !filledJetHFR_Low[iJetRadius]) { + if (jetderiveddatautilities::selectTrigger(collision, hfLowTrigger) && !filledJetHFR_Low[iJetRadius]) { filledJetHFR_Low[iJetRadius] = true; for (double pt = 0.0; pt <= jet.pt(); pt += 1.0) { registry.fill(HIST("h2_jet_r_jet_pT_triggered_HFlow"), jet.r() / 100.0, pt); } } - if (jetderiveddatautilities::selectChargedHFTrigger(collision, hfHighTrigger) && !filledJetHFR_High[iJetRadius]) { + if (jetderiveddatautilities::selectTrigger(collision, hfHighTrigger) && !filledJetHFR_High[iJetRadius]) { filledJetHFR_High[iJetRadius] = true; for (double pt = 0.0; pt <= jet.pt(); pt += 1.0) { registry.fill(HIST("h2_jet_r_jet_pT_triggered_HFhigh"), jet.r() / 100.0, pt); @@ -1322,40 +1429,40 @@ struct JetFinderHFQATask { registry.fill(HIST("h3_hfjet_r_jet_eta_collision"), jet.r() / 100.0, jet.eta(), 0.0); registry.fill(HIST("h3_hfjet_r_jet_phi_collision"), jet.r() / 100.0, jet.phi(), 0.0); - if (jetderiveddatautilities::selectChargedHFTrigger(collision, hfLowTrigger)) { + if (jetderiveddatautilities::selectTrigger(collision, hfLowTrigger)) { registry.fill(HIST("h3_hfjet_r_jet_pt_collision"), jet.r() / 100.0, jet.pt(), 1.0); registry.fill(HIST("h3_hfjet_r_jet_eta_collision"), jet.r() / 100.0, jet.eta(), 1.0); registry.fill(HIST("h3_hfjet_r_jet_phi_collision"), jet.r() / 100.0, jet.phi(), 1.0); } - if (jetderiveddatautilities::selectChargedHFTrigger(collision, hfHighTrigger)) { + if (jetderiveddatautilities::selectTrigger(collision, hfHighTrigger)) { registry.fill(HIST("h3_hfjet_r_jet_pt_collision"), jet.r() / 100.0, jet.pt(), 2.0); registry.fill(HIST("h3_hfjet_r_jet_eta_collision"), jet.r() / 100.0, jet.eta(), 2.0); registry.fill(HIST("h3_hfjet_r_jet_phi_collision"), jet.r() / 100.0, jet.phi(), 2.0); } - if (jetderiveddatautilities::selectChargedHFTrigger(collision, hfLowTrigger) && jetderiveddatautilities::selectChargedHFTrigger(collision, hfHighTrigger)) { + if (jetderiveddatautilities::selectTrigger(collision, hfLowTrigger) && jetderiveddatautilities::selectTrigger(collision, hfHighTrigger)) { registry.fill(HIST("h3_hfjet_r_jet_pt_collision"), jet.r() / 100.0, jet.pt(), 3.0); registry.fill(HIST("h3_hfjet_r_jet_eta_collision"), jet.r() / 100.0, jet.eta(), 3.0); registry.fill(HIST("h3_hfjet_r_jet_phi_collision"), jet.r() / 100.0, jet.phi(), 3.0); } - for (auto& hfcandidate : jet.template hfcandidates_as()) { + for (auto& candidate : jet.template candidates_as()) { - registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_all"), jet.r() / 100.0, jet.pt(), hfcandidate.pt()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_all"), jet.r() / 100.0, jet.pt(), hfcandidate.eta()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_all"), jet.r() / 100.0, jet.pt(), hfcandidate.phi()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_all"), jet.r() / 100.0, jet.pt(), hfcandidate.y()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_all"), jet.r() / 100.0, jet.pt(), candidate.pt()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_all"), jet.r() / 100.0, jet.pt(), candidate.eta()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_all"), jet.r() / 100.0, jet.pt(), candidate.phi()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_all"), jet.r() / 100.0, jet.pt(), candidate.y()); - if (jetderiveddatautilities::selectChargedHFTrigger(collision, hfLowTrigger)) { - registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_triggered_HFlow"), jet.r() / 100.0, jet.pt(), hfcandidate.pt()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_triggered_HFlow"), jet.r() / 100.0, jet.pt(), hfcandidate.eta()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_triggered_HFlow"), jet.r() / 100.0, jet.pt(), hfcandidate.phi()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_triggered_HFlow"), jet.r() / 100.0, jet.pt(), hfcandidate.y()); + if (jetderiveddatautilities::selectTrigger(collision, hfLowTrigger)) { + registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_triggered_HFlow"), jet.r() / 100.0, jet.pt(), candidate.pt()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_triggered_HFlow"), jet.r() / 100.0, jet.pt(), candidate.eta()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_triggered_HFlow"), jet.r() / 100.0, jet.pt(), candidate.phi()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_triggered_HFlow"), jet.r() / 100.0, jet.pt(), candidate.y()); } - if (jetderiveddatautilities::selectChargedHFTrigger(collision, hfHighTrigger)) { - registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_triggered_HFhigh"), jet.r() / 100.0, jet.pt(), hfcandidate.pt()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_triggered_HFhigh"), jet.r() / 100.0, jet.pt(), hfcandidate.eta()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_triggered_HFhigh"), jet.r() / 100.0, jet.pt(), hfcandidate.phi()); - registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_triggered_HFhigh"), jet.r() / 100.0, jet.pt(), hfcandidate.y()); + if (jetderiveddatautilities::selectTrigger(collision, hfHighTrigger)) { + registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt_triggered_HFhigh"), jet.r() / 100.0, jet.pt(), candidate.pt()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta_triggered_HFhigh"), jet.r() / 100.0, jet.pt(), candidate.eta()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi_triggered_HFhigh"), jet.r() / 100.0, jet.pt(), candidate.phi()); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_y_triggered_HFhigh"), jet.r() / 100.0, jet.pt(), candidate.y()); } } } @@ -1363,12 +1470,15 @@ struct JetFinderHFQATask { PROCESS_SWITCH(JetFinderHFQATask, processHFTriggeredData, "QA for charged hf jet trigger", false); - void processTracks(soa::Filtered::iterator const& collision, - soa::Filtered const& tracks) + void processTracks(soa::Filtered::iterator const& collision, + soa::Filtered const& tracks) { + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } registry.fill(HIST("h_collisions"), 0.5); registry.fill(HIST("h2_centrality_collisions"), collision.centrality(), 0.5); - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } registry.fill(HIST("h_collisions"), 1.5); @@ -1377,14 +1487,17 @@ struct JetFinderHFQATask { } PROCESS_SWITCH(JetFinderHFQATask, processTracks, "QA for charged tracks", false); - void processTracksWeighted(soa::Join::iterator const& collision, - JetMcCollisions const&, - soa::Filtered const& tracks) + void processTracksWeighted(soa::Join::iterator const& collision, + aod::JetMcCollisions const&, + soa::Filtered const& tracks) { float eventWeight = collision.mcCollision().weight(); + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } registry.fill(HIST("h_collisions"), 0.5); registry.fill(HIST("h_collisions_weighted"), 0.5, eventWeight); - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } registry.fill(HIST("h_collisions"), 1.5); @@ -1393,33 +1506,37 @@ struct JetFinderHFQATask { } PROCESS_SWITCH(JetFinderHFQATask, processTracksWeighted, "QA for charged tracks weighted", false); - void processTracksSub(soa::Filtered::iterator const& collision, + void processTracksSub(soa::Filtered::iterator const& collision, CandidateTableData const& candidates, soa::Filtered const& tracks) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } for (auto const& candidate : candidates) { - for (auto const& track : jethfutilities::slicedPerCandidate(tracks, candidate, perD0CandidateTracks, perLcCandidateTracks, perBplusCandidateTracks)) { - registry.fill(HIST("h2_centrality_track_pt_eventwiseconstituentsubtracted"), collision.centrality(), track.pt()); - registry.fill(HIST("h2_centrality_track_eta_eventwiseconstituentsubtracted"), collision.centrality(), track.eta()); - registry.fill(HIST("h2_centrality_track_phi_eventwiseconstituentsubtracted"), collision.centrality(), track.phi()); - registry.fill(HIST("h2_centrality_track_energy_eventwiseconstituentsubtracted"), collision.centrality(), track.energy()); + for (auto const& track : jetcandidateutilities::slicedPerCandidate(tracks, candidate, perD0CandidateTracks, perDplusCandidateTracks, perLcCandidateTracks, perBplusCandidateTracks, perDielectronCandidateTracks)) { + registry.fill(HIST("h3_centrality_track_pt_track_phi_eventwiseconstituentsubtracted"), collision.centrality(), track.pt(), track.phi()); + registry.fill(HIST("h3_centrality_track_pt_track_eta_eventwiseconstituentsubtracted"), collision.centrality(), track.pt(), track.eta()); + registry.fill(HIST("h3_track_pt_track_eta_track_phi_eventwiseconstituentsubtracted"), track.pt(), track.eta(), track.phi()); } break; // currently only fills it for the first candidate in the event (not pT ordered) } } PROCESS_SWITCH(JetFinderHFQATask, processTracksSub, "QA for charged event-wise embedded subtracted tracks", false); - void processRho(JetCollision const& collision, CandidateTableData const& candidates, BkgRhoTable const& bkgRhos, soa::Filtered const& tracks) + void processRho(aod::JetCollision const& collision, soa::Join const& candidates, soa::Filtered const& tracks) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } for (auto const& candidate : candidates) { - auto bkgRho = jethfutilities::slicedPerCandidate(bkgRhos, candidate, perD0CandidateRhos, perLcCandidateRhos, perBplusCandidateRhos).iteratorAt(0); int nTracks = 0; for (auto const& track : tracks) { if (jetderiveddatautilities::selectTrack(track, trackSelection)) { @@ -1427,74 +1544,38 @@ struct JetFinderHFQATask { } } registry.fill(HIST("h2_centrality_ntracks"), collision.centrality(), nTracks); - registry.fill(HIST("h2_ntracks_rho"), nTracks, bkgRho.rho()); - registry.fill(HIST("h2_ntracks_rhom"), nTracks, bkgRho.rhoM()); - registry.fill(HIST("h2_centrality_rho"), collision.centrality(), bkgRho.rho()); - registry.fill(HIST("h2_centrality_rhom"), collision.centrality(), bkgRho.rhoM()); + registry.fill(HIST("h2_ntracks_rho"), nTracks, candidate.rho()); + registry.fill(HIST("h2_ntracks_rhom"), nTracks, candidate.rhoM()); + registry.fill(HIST("h2_centrality_rho"), collision.centrality(), candidate.rho()); + registry.fill(HIST("h2_centrality_rhom"), collision.centrality(), candidate.rhoM()); break; // currently only fills it for the first candidate in the event (not pT ordered) } } PROCESS_SWITCH(JetFinderHFQATask, processRho, "QA for rho-area subtracted jets", false); - void processRandomCone(soa::Filtered::iterator const& collision, JetTableDataSubJoined const& jets, CandidateTableData const& candidates, BkgRhoTable const& bkgRhos, soa::Filtered const& tracks) + void processRandomConeData(soa::Filtered::iterator const& collision, JetTableDataJoined const& jets, soa::Join const& candidates, soa::Filtered const& tracks) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { - return; - } - for (auto const& candidate : candidates) { - auto bkgRho = jethfutilities::slicedPerCandidate(bkgRhos, candidate, perD0CandidateRhos, perLcCandidateRhos, perBplusCandidateRhos).iteratorAt(0); - TRandom3 randomNumber(0); - float randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); - float randomConePhi = randomNumber.Uniform(0.0, 2 * M_PI); - float randomConePt = 0; - for (auto const& track : tracks) { - if (jetderiveddatautilities::selectTrack(track, trackSelection)) { - float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-M_PI)); - float dEta = track.eta() - randomConeEta; - if (TMath::Sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { - randomConePt += track.pt(); - } - } - } - registry.fill(HIST("h2_centrality_rhorandomcone"), collision.centrality(), randomConePt - M_PI * randomConeR * randomConeR * bkgRho.rho()); - - // removing the leading jet from the random cone - if (jets.size() > 0) { // if there are no jets in the acceptance (from the jetfinder cuts) then there can be no leading jet - float dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, static_cast(-M_PI)); - float dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; + randomCone(collision, jets, candidates, tracks); + } + PROCESS_SWITCH(JetFinderHFQATask, processRandomConeData, "QA for random cone estimation of background fluctuations in data", false); - bool jetWasInCone = false; - while (TMath::Sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < jets.iteratorAt(0).r() / 100.0 + randomConeR) { - jetWasInCone = true; - randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); - randomConePhi = randomNumber.Uniform(0.0, 2 * M_PI); - dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, static_cast(-M_PI)); - dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; - } - if (jetWasInCone) { - randomConePt = 0.0; - for (auto const& track : tracks) { - if (jetderiveddatautilities::selectTrack(track, trackSelection)) { - float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-M_PI)); - float dEta = track.eta() - randomConeEta; - if (TMath::Sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { - randomConePt += track.pt(); - } - } - } - } - } - registry.fill(HIST("h2_centrality_rhorandomconewithoutleadingjet"), collision.centrality(), randomConePt - M_PI * randomConeR * randomConeR * bkgRho.rho()); - break; // currently only fills it for the first candidate in the event (not pT ordered). Jet is pT ordered so results for excluding leading jet might not be as expected + void processRandomConeMCD(soa::Filtered::iterator const& collision, JetTableMCDJoined const& jets, soa::Join const& candidates, soa::Filtered const& tracks) + { + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; } + randomCone(collision, jets, candidates, tracks); } - PROCESS_SWITCH(JetFinderHFQATask, processRandomCone, "QA for random cone estimation of background fluctuations", false); + PROCESS_SWITCH(JetFinderHFQATask, processRandomConeMCD, "QA for random cone estimation of background fluctuations in mcd", false); - void processCandidates(soa::Filtered::iterator const& collision, CandidateTableData const& candidates) + void processCandidates(soa::Filtered::iterator const& collision, CandidateTableData const& candidates) { + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } for (auto const& candidate : candidates) { - registry.fill(HIST("h_candidate_invmass"), candidate.m()); + registry.fill(HIST("h_candidate_invmass"), jetcandidateutilities::getCandidateInvariantMass(candidate)); registry.fill(HIST("h_candidate_pt"), candidate.pt()); registry.fill(HIST("h_candidate_y"), candidate.y()); } @@ -1502,26 +1583,3 @@ struct JetFinderHFQATask { } PROCESS_SWITCH(JetFinderHFQATask, processCandidates, "HF candidate QA", false); }; - -using JetFinderD0QATask = JetFinderHFQATask; -using JetFinderLcQATask = JetFinderHFQATask; -// using JetFinderBplusQATask = JetFinderHFQATask; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - std::vector tasks; - - tasks.emplace_back(adaptAnalysisTask(cfgc, - SetDefaultProcesses{}, - TaskName{"jet-finder-charged-d0-qa"})); - - tasks.emplace_back(adaptAnalysisTask(cfgc, - SetDefaultProcesses{}, - TaskName{"jet-finder-charged-lc-qa"})); - - // tasks.emplace_back(adaptAnalysisTask(cfgc, - // SetDefaultProcesses{}, - // TaskName{"jet-finder-charged-bplus-qa"})); - - return WorkflowSpec{tasks}; -} diff --git a/PWGJE/Tasks/jetFinderLcQA.cxx b/PWGJE/Tasks/jetFinderLcQA.cxx new file mode 100644 index 00000000000..311086c86c8 --- /dev/null +++ b/PWGJE/Tasks/jetFinderLcQA.cxx @@ -0,0 +1,27 @@ +// 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. + +// jet finder Lc charged QA task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetFinderHFQA.cxx" + +using JetFinderLcQATask = JetFinderHFQATask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-finder-charged-lc-qa"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetfinderQA.cxx b/PWGJE/Tasks/jetFinderQA.cxx similarity index 53% rename from PWGJE/Tasks/jetfinderQA.cxx rename to PWGJE/Tasks/jetFinderQA.cxx index 3c26019296d..255cecfad63 100644 --- a/PWGJE/Tasks/jetfinderQA.cxx +++ b/PWGJE/Tasks/jetFinderQA.cxx @@ -14,6 +14,9 @@ /// \author Nima Zardoshti #include +#include +#include +#include #include #include "Framework/ASoA.h" @@ -60,23 +63,37 @@ struct JetFinderQATask { Configurable pTHatMaxMCD{"pTHatMaxMCD", 999.0, "maximum fraction of hard scattering for jet acceptance in detector MC"}; Configurable pTHatMaxMCP{"pTHatMaxMCP", 999.0, "maximum fraction of hard scattering for jet acceptance in particle MC"}; Configurable pTHatExponent{"pTHatExponent", 6.0, "exponent of the event weight for the calculation of pTHat"}; + Configurable pTHatAbsoluteMin{"pTHatAbsoluteMin", -99.0, "minimum value of pTHat"}; + Configurable jetPtMax{"jetPtMax", 200., "set jet pT bin max"}; Configurable jetEtaMin{"jetEtaMin", -99.0, "minimum jet pseudorapidity"}; Configurable jetEtaMax{"jetEtaMax", 99.0, "maximum jet pseudorapidity"}; + Configurable nBinsEta{"nBinsEta", 200, "number of bins for eta axes"}; Configurable jetAreaFractionMin{"jetAreaFractionMin", -99.0, "used to make a cut on the jet areas"}; Configurable leadingConstituentPtMin{"leadingConstituentPtMin", -99.0, "minimum pT selection on jet constituent"}; + Configurable leadingConstituentPtMax{"leadingConstituentPtMax", 9999.0, "maximum pT selection on jet constituent"}; Configurable randomConeR{"randomConeR", 0.4, "size of random Cone for estimating background fluctuations"}; + Configurable randomConeLeadJetDeltaR{"randomConeLeadJetDeltaR", -99.0, "min distance between leading jet axis and random cone (RC) axis; if negative, min distance is set to automatic value of R_leadJet+R_RC "}; + Configurable checkMcCollisionIsMatched{"checkMcCollisionIsMatched", false, "0: count whole MCcollisions, 1: select MCcollisions which only have their correspond collisions"}; + Configurable trackOccupancyInTimeRangeMax{"trackOccupancyInTimeRangeMax", 999999, "maximum occupancy of tracks in neighbouring collisions in a given time range; only applied to reconstructed collisions (data and mcd jets), not mc collisions (mcp jets)"}; + Configurable trackOccupancyInTimeRangeMin{"trackOccupancyInTimeRangeMin", -999999, "minimum occupancy of tracks in neighbouring collisions in a given time range; only applied to reconstructed collisions (data and mcd jets), not mc collisions (mcp jets)"}; + Configurable skipMBGapEvents{"skipMBGapEvents", false, "flag to choose to reject min. bias gap events; jet-level rejection applied at the jet finder level, here rejection is applied for collision and track process functions"}; + Configurable intRateNBins{"intRateNBins", 50, "number of bins for interaction rate axis"}; + Configurable intRateMax{"intRateMax", 50000.0, "maximum value of interaction rate axis"}; std::vector filledJetR_Both; std::vector filledJetR_Low; std::vector filledJetR_High; std::vector jetRadiiValues; - int eventSelection = -1; + std::vector eventSelectionBits; int trackSelection = -1; + std::vector jetPtBins; + std::vector jetPtBinsRhoAreaSub; + void init(o2::framework::InitContext&) { - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(eventSelections)); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); jetRadiiValues = (std::vector)jetRadii; @@ -92,69 +109,107 @@ struct JetFinderQATask { jetRadiiBins.push_back(jetRadiiBins[jetRadiiBins.size() - 1] + 0.1); } + auto jetPtTemp = 0.0; + jetPtBins.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(jetPtTemp); + while (jetPtTemp < jetPtMax) { + if (jetPtTemp < 100.0) { + jetPtTemp += 1.0; + jetPtBins.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(-jetPtTemp); + } else if (jetPtTemp < 200.0) { + jetPtTemp += 5.0; + jetPtBins.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(-jetPtTemp); + } else { + jetPtTemp += 10.0; + jetPtBins.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(jetPtTemp); + jetPtBinsRhoAreaSub.push_back(-jetPtTemp); + } + } + std::sort(jetPtBinsRhoAreaSub.begin(), jetPtBinsRhoAreaSub.end()); + + AxisSpec jetPtAxis = {jetPtBins, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec jetPtAxisRhoAreaSub = {jetPtBinsRhoAreaSub, "#it{p}_{T} (GeV/#it{c})"}; + + AxisSpec jetEtaAxis = {nBinsEta, jetEtaMin, jetEtaMax, "#eta"}; + AxisSpec trackEtaAxis = {nBinsEta, trackEtaMin, trackEtaMax, "#eta"}; + + AxisSpec intRateAxis = {intRateNBins, 0., intRateMax, "int. rate (kHz)"}; + if (doprocessJetsData || doprocessJetsMCD || doprocessJetsMCDWeighted) { - registry.add("h_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); - registry.add("h_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + + registry.add("h_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxis}}); + registry.add("h_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {jetEtaAxis}}); registry.add("h_jet_phi", "jet #varphi;#varphi_{jet};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_jet_ntracks", "jet N tracks;N_{jet tracks};entries", {HistType::kTH1F, {{200, -0.5, 199.5}}}); - registry.add("h2_centrality_jet_pt", "centrality vs #it{p}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, 0., 200.}}}); - registry.add("h2_centrality_jet_eta", "centrality vs #eta_{jet}; centrality; #eta_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, -1.0, 1.0}}}); + registry.add("h2_centrality_jet_pt", "centrality vs #it{p}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, jetPtAxis}}); + registry.add("h2_centrality_jet_eta", "centrality vs #eta_{jet}; centrality; #eta_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, jetEtaAxis}}); registry.add("h2_centrality_jet_phi", "centrality vs #varphi_{jet}; centrality; #varphi_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {160, -1.0, 7.}}}); registry.add("h2_centrality_jet_ntracks", "centrality vs N_{jet tracks}; centrality; N_{jet tracks}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_centrality", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});centrality", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {1200, -10.0, 110.0}}}); - registry.add("h3_jet_r_jet_pt_jet_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_jet_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_eta_jet_phi", "#it{R}_{jet};#eta_{jet};#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_jet_ntracks", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_jet_area", "#it{R}_{jet}; #it{p}_{T,jet} (GeV/#it{c}); #it{area}_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {300, 0., 3.}}}); - registry.add("h3_jet_r_jet_pt_track_pt", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_track_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_track_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_leadingtrack_pt", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c}); #it{p}_{T,leading track} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200.0}, {200, 0.0, 200.0}}}); - registry.add("h_jet_phat", "jet #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0, 350}}}); - registry.add("h_jet_ptcut", "p_{T} cut;p_{T,jet} (GeV/#it{c});N;entries", {HistType::kTH2F, {{200, 0, 200}, {20, 0, 5}}}); - } - - if (doprocessJetsRhoAreaSubData) { - - registry.add("h_jet_pt_rhoareasubtracted", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{400, -200., 200.}}}); - registry.add("h_jet_eta_rhoareasubtracted", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h3_jet_r_jet_pt_centrality", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});centrality", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1200, -10.0, 110.0}}}); + registry.add("h3_jet_r_jet_pt_jet_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetEtaAxis}}); + registry.add("h3_jet_r_jet_pt_jet_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_eta_jet_phi", "#it{R}_{jet};#eta_{jet};#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetEtaAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_jet_ntracks", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, -0.5, 199.5}}}); + registry.add("h3_jet_r_jet_pt_jet_area", "#it{R}_{jet}; #it{p}_{T,jet} (GeV/#it{c}); #it{area}_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {300, 0., 3.}}}); + registry.add("h3_jet_r_jet_pt_track_pt", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_track_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, trackEtaAxis}}); + registry.add("h3_jet_r_jet_pt_track_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_leadingtrack_pt", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c}); #it{p}_{T,leading track} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0.0, 200.0}}}); + registry.add("h_jet_phat", "jet #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{1000, 0, 1000}}}); + registry.add("h_jet_ptcut", "p_{T} cut;p_{T,jet} (GeV/#it{c});N;entries", {HistType::kTH2F, {{300, 0, 300}, {20, 0, 5}}}); + registry.add("h_jet_phat_weighted", "jet #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{1000, 0, 1000}}}); + registry.add("h3_centrality_occupancy_jet_pt", "centrality; occupancy; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH3F, {{120, -10.0, 110.0}, {60, 0, 30000}, jetPtAxis}}); + registry.add("h2_intrate_jet_pt", "int. rate vs #it{p}_{T,jet}; int. rate (kHz); #it{p}_{T,jet} (GeV/#it{c});", {HistType::kTH2F, {intRateAxis, jetPtAxis}}); + } + + if (doprocessJetsRhoAreaSubData || doprocessJetsRhoAreaSubMCD) { + + registry.add("h_jet_pt_rhoareasubtracted", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + registry.add("h_jet_eta_rhoareasubtracted", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {jetEtaAxis}}); registry.add("h_jet_phi_rhoareasubtracted", "jet #varphi;#varphi_{jet};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_jet_ntracks_rhoareasubtracted", "jet N tracks;N_{jet tracks};entries", {HistType::kTH1F, {{200, -0.5, 199.5}}}); - registry.add("h2_centrality_jet_pt_rhoareasubtracted", "centrality vs #it{p}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, {400, -200., 200.}}}); - registry.add("h2_centrality_jet_eta_rhoareasubtracted", "centrality vs #eta_{jet}; centrality; #eta_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, -1.0, 1.0}}}); + registry.add("h2_centrality_jet_pt_rhoareasubtracted", "centrality vs #it{p}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, jetPtAxisRhoAreaSub}}); + registry.add("h2_centrality_jet_eta_rhoareasubtracted", "centrality vs #eta_{jet}; centrality; #eta_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, jetEtaAxis}}); registry.add("h2_centrality_jet_phi_rhoareasubtracted", "centrality vs #varphi_{jet}; centrality; #varphi_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {160, -1.0, 7.}}}); registry.add("h2_centrality_jet_ntracks_rhoareasubtracted", "centrality vs N_{jet tracks}; centrality; N_{jet tracks}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_centrality_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});centrality", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {1200, -10.0, 110.0}}}); - registry.add("h3_jet_r_jet_pt_jet_eta_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_jet_phi_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_eta_jet_phi_rhoareasubtracted", "#it{R}_{jet};#eta_{jet};#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_jet_ntracks_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_jet_area_rhoareasubtracted", "#it{R}_{jet}; #it{p}_{T,jet} (GeV/#it{c}); #it{area}_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {300, 0., 3.}}}); - registry.add("h3_jet_r_jet_pt_track_pt_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_track_eta_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_track_phi_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {400, -200., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_jet_pt_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {400, -200., 200.}}}); - } - - if (doprocessEvtWiseConstSubJetsData) { - registry.add("h_jet_pt_eventwiseconstituentsubtracted", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); - registry.add("h_jet_eta_eventwiseconstituentsubtracted", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h3_jet_r_jet_pt_centrality_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});centrality", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {1200, -10.0, 110.0}}}); + registry.add("h3_jet_r_jet_pt_jet_eta_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, jetEtaAxis}}); + registry.add("h3_jet_r_jet_pt_jet_phi_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_eta_jet_phi_rhoareasubtracted", "#it{R}_{jet};#eta_{jet};#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetEtaAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_jet_ntracks_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {200, -0.5, 199.5}}}); + registry.add("h3_jet_r_jet_pt_jet_area_rhoareasubtracted", "#it{R}_{jet}; #it{p}_{T,jet} (GeV/#it{c}); #it{area}_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {300, 0., 3.}}}); + registry.add("h3_jet_r_jet_pt_track_pt_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_track_eta_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, trackEtaAxis}}); + registry.add("h3_jet_r_jet_pt_track_phi_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxisRhoAreaSub, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_jet_pt_rhoareasubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetPtAxisRhoAreaSub}}); + registry.add("h3_centrality_occupancy_jet_pt_rhoareasubtracted", "centrality; occupancy; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH3F, {{120, -10.0, 110.0}, {60, 0, 30000}, jetPtAxisRhoAreaSub}}); + registry.add("h2_intrate_jet_pt_rhoareasubtracted", "int. rate vs #it{p}_{T,jet}; int. rate (kHz); #it{p}_{T,jet} (GeV/#it{c});", {HistType::kTH2F, {intRateAxis, jetPtAxisRhoAreaSub}}); + } + + if (doprocessEvtWiseConstSubJetsData || doprocessEvtWiseConstSubJetsMCD) { + registry.add("h_jet_pt_eventwiseconstituentsubtracted", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxis}}); + registry.add("h_jet_eta_eventwiseconstituentsubtracted", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {jetEtaAxis}}); registry.add("h_jet_phi_eventwiseconstituentsubtracted", "jet #varphi;#varphi_{jet};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_jet_ntracks_eventwiseconstituentsubtracted", "jet N tracks;N_{jet tracks};entries", {HistType::kTH1F, {{200, -0.5, 199.5}}}); - registry.add("h2_centrality_jet_pt_eventwiseconstituentsubtracted", "centrality vs #it{p}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, 0., 200.}}}); - registry.add("h2_centrality_jet_eta_eventwiseconstituentsubtracted", "centrality vs #eta_{jet}; centrality; #eta_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, -1.0, 1.0}}}); + registry.add("h2_centrality_jet_pt_eventwiseconstituentsubtracted", "centrality vs #it{p}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, jetPtAxis}}); + registry.add("h2_centrality_jet_eta_eventwiseconstituentsubtracted", "centrality vs #eta_{jet}; centrality; #eta_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, jetEtaAxis}}); registry.add("h2_centrality_jet_phi_eventwiseconstituentsubtracted", "centrality vs #varphi_{jet}; centrality; #varphi_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {160, -1.0, 7.}}}); registry.add("h2_centrality_jet_ntracks_eventwiseconstituentsubtracted", "centrality vs N_{jet tracks}; centrality; N_{jet tracks}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_centrality_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});centrality", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {1200, -10.0, 110.0}}}); - registry.add("h3_jet_r_jet_pt_jet_eta_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_jet_phi_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_eta_jet_phi_eventwiseconstituentsubtracted", "#it{R}_{jet};#eta_{jet};#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_jet_ntracks_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_jet_area_eventwiseconstituentsubtracted", "#it{R}_{jet}; #it{p}_{T,jet} (GeV/#it{c}); #it{area}_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {300, 0., 3.}}}); - registry.add("h3_jet_r_jet_pt_track_pt_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_track_eta_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_track_phi_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_centrality_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});centrality", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1200, -10.0, 110.0}}}); + registry.add("h3_jet_r_jet_pt_jet_eta_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetEtaAxis}}); + registry.add("h3_jet_r_jet_pt_jet_phi_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_eta_jet_phi_eventwiseconstituentsubtracted", "#it{R}_{jet};#eta_{jet};#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetEtaAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_jet_ntracks_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, -0.5, 199.5}}}); + registry.add("h3_jet_r_jet_pt_jet_area_eventwiseconstituentsubtracted", "#it{R}_{jet}; #it{p}_{T,jet} (GeV/#it{c}); #it{area}_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {300, 0., 3.}}}); + registry.add("h3_jet_r_jet_pt_track_pt_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetPtAxis}}); + registry.add("h3_jet_r_jet_pt_track_eta_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, trackEtaAxis}}); + registry.add("h3_jet_r_jet_pt_track_phi_eventwiseconstituentsubtracted", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h2_intrate_jet_pt_eventwiseconstituentsubtracted", "int. rate vs #it{p}_{T,jet}; int. rate (kHz); #it{p}_{T,jet} (GeV/#it{c});", {HistType::kTH2F, {intRateAxis, jetPtAxis}}); } if (doprocessRho) { @@ -165,124 +220,159 @@ struct JetFinderQATask { registry.add("h2_centrality_rhom", ";centrality; #it{rho}_{m} (GeV/area)", {HistType::kTH2F, {{1100, 0., 110.}, {100, 0., 100.0}}}); } - if (doprocessRandomCone) { + if (doprocessRandomConeData || doprocessRandomConeMCD) { registry.add("h2_centrality_rhorandomcone", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH2F, {{1100, 0., 110.}, {800, -400.0, 400.0}}}); + registry.add("h2_centrality_rhorandomconerandomtrackdirection", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH2F, {{1100, 0., 110.}, {800, -400.0, 400.0}}}); registry.add("h2_centrality_rhorandomconewithoutleadingjet", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH2F, {{1100, 0., 110.}, {800, -400.0, 400.0}}}); + registry.add("h2_centrality_rhorandomconerandomtrackdirectionwithoutoneleadingjets", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH2F, {{1100, 0., 110.}, {800, -400.0, 400.0}}}); + registry.add("h2_centrality_rhorandomconerandomtrackdirectionwithouttwoleadingjets", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH2F, {{1100, 0., 110.}, {800, -400.0, 400.0}}}); } if (doprocessJetsMCP || doprocessJetsMCPWeighted) { - registry.add("h_jet_pt_part", "jet pT;#it{p}_{T,jet}^{part}(GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); - registry.add("h_jet_eta_part", "jet #eta;#eta_{jet}^{part};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_jet_pt_part", "jet pT;#it{p}_{T,jet}^{part}(GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxis}}); + registry.add("h_jet_eta_part", "jet #eta;#eta_{jet}^{part};entries", {HistType::kTH1F, {jetEtaAxis}}); registry.add("h_jet_phi_part", "jet #varphi;#varphi_{jet}^{part};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_jet_ntracks_part", "jet N tracks;N_{jet tracks}^{part};entries", {HistType::kTH1F, {{200, -0.5, 199.5}}}); - registry.add("h3_jet_r_part_jet_pt_part_jet_eta_part", ";#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#eta_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_part_jet_pt_part_jet_phi_part", ";#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#varphi_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_part_jet_eta_part_jet_phi_part", ";#it{R}_{jet}^{part};#eta_{jet}^{part};#varphi_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_part_jet_pt_part_jet_ntracks_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});N_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_part_jet_pt_part_track_pt_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#it{p}_{T,jet tracks}^{part} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_part_jet_pt_part_track_eta_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#eta_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_part_jet_pt_part_track_phi_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#varphi_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h_jet_phat_part", "jet #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0, 350}}}); - registry.add("h_jet_ptcut_part", "p_{T} cut;p_{T,jet}^{part} (GeV/#it{c});N;entries", {HistType::kTH2F, {{200, 0, 200}, {20, 0, 5}}}); + registry.add("h3_jet_r_part_jet_pt_part_jet_eta_part", ";#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#eta_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetEtaAxis}}); + registry.add("h3_jet_r_part_jet_pt_part_jet_phi_part", ";#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#varphi_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_part_jet_eta_part_jet_phi_part", ";#it{R}_{jet}^{part};#eta_{jet}^{part};#varphi_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetEtaAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_part_jet_pt_part_jet_ntracks_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});N_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, -0.5, 199.5}}}); + registry.add("h3_jet_r_part_jet_pt_part_track_pt_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#it{p}_{T,jet tracks}^{part} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_part_jet_pt_part_track_eta_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#eta_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, trackEtaAxis}}); + registry.add("h3_jet_r_part_jet_pt_part_track_phi_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#varphi_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h_jet_phat_part", "jet #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{1000, 0, 1000}}}); + registry.add("h_jet_ptcut_part", "p_{T} cut;p_{T,jet}^{part} (GeV/#it{c});N;entries", {HistType::kTH2F, {{300, 0, 300}, {20, 0, 5}}}); + registry.add("h_jet_phat_part_weighted", "jet #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{1000, 0, 1000}}}); } if (doprocessJetsMCPMCDMatched || doprocessJetsMCPMCDMatchedWeighted || doprocessJetsSubMatched) { - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeo", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeo", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {300, 0., 300.}, {300, 0., 300.}}}); + registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeo", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetEtaAxis, jetEtaAxis}}); + registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeo", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); registry.add("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeo", "#it{R}_{jet};N_{jet tracks}^{tag};N_{jet tracks}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); - - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedpt", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedpt", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 2.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag} - #eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag} - #varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_jet_pt_tag_leadingtrack_pt_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}{T,LT}^{tag} - #it{p}{T,LT}^{base}) / #it{p}{T,LT}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_jet_pt_tag_leadingtrack_fraction_diff_matchedgeo", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}{T,LT}^{tag} - #it{p}{T,LT}^{base}) / #it{p}{T,LT}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {100, -1.0, 1.0}}}); + registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, jetEtaAxis, jetEtaAxis}}); + registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {160, -1.0, 7.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {jetPtAxis, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); + registry.add("h3_jet_pt_tag_jet_leadingtrack_pt_tag_jet_leadingtrack_pt_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #it{p}_{T,LT}^{tag}; #it{p}_{T,LT}^{tag}", {HistType::kTH3F, {jetPtAxis, {200, 0., 100.}, {200, 0., 100.}}}); + registry.add("h3_jet_pt_tag_jet_leadingtrack_fraction_tag_jet_leadingtrack_fraction_base_matchedgeo", ";#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,LT}^{tag} / #it{p}_{T,jet}^{tag} ; #it{p}_{T,LT}^{tag} / #it{p}_{T,jet}^{base}", {HistType::kTH3F, {jetPtAxis, {50, 0., 1.}, {50, 0., 1.}}}); + + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetPtAxis}}); + registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedpt", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetEtaAxis, jetEtaAxis}}); + registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedpt", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); registry.add("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedpt", "#it{R}_{jet};N_{jet tracks}^{tag};N_{jet tracks}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); - - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeopt", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeopt", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag} - #eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag} - #varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_jet_pt_tag_leadingtrack_pt_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}{T,LT}^{tag} - #it{p}{T,LT}^{base}) / #it{p}{T,LT}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_leadingtrack_fraction_diff_matchedpt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}{T,LT}^{tag} - #it{p}{T,LT}^{base}) / #it{p}{T,LT}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {100, -1.0, 1.0}}}); + registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, jetEtaAxis, jetEtaAxis}}); + registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {160, -1.0, 7.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {jetPtAxis, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); + registry.add("h3_jet_pt_tag_jet_leadingtrack_pt_tag_jet_leadingtrack_pt_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #it{p}_{T,LT}^{tag}; #it{p}_{T,LT}^{tag}", {HistType::kTH3F, {jetPtAxis, {200, 0., 100.}, {200, 0., 100.}}}); + registry.add("h3_jet_pt_tag_jet_leadingtrack_fraction_tag_jet_leadingtrack_fraction_base_matchedpt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,LT}^{tag} / #it{p}_{T,jet}^{tag} ; #it{p}_{T,LT}^{tag} / #it{p}_{T,jet}^{base}", {HistType::kTH3F, {jetPtAxis, {50, 0., 1.}, {50, 0., 1.}}}); + + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, jetPtAxis}}); + registry.add("h3_jet_r_jet_eta_tag_jet_eta_base_matchedgeopt", "#it{R}_{jet};#eta_{jet}^{tag};#eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetEtaAxis, jetEtaAxis}}); + registry.add("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeopt", "#it{R}_{jet};#varphi_{jet}^{tag};#varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); registry.add("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeopt", "#it{R}_{jet};N_{jet tracks}^{tag};N_{jet tracks}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#eta_{jet}^{tag} - #eta_{jet}^{base}) / #eta_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#varphi_{jet}^{tag} - #varphi_{jet}^{base}) / #varphi_{jet}^{tag}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0.0, 200}, {1000, -5.0, 5.0}}}); - registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {100, -1.0, 1.0}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {160, -1.0, 7.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {{200, 0.0, 200}, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}_{T,jet}^{tag} (GeV/#it{c}) - #it{p}_{T,jet}^{base} (GeV/#it{c})) / #it{p}_{T,jet}^{tag} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {1000, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag} - #eta_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag} - #varphi_{jet}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_jet_pt_tag_leadingtrack_pt_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}{T,LT}^{tag} - #it{p}{T,LT}^{base}) / #it{p}{T,LT}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {500, -5.0, 5.0}}}); + registry.add("h3_jet_r_jet_pt_tag_leadingtrack_fraction_diff_matchedgeopt", "#it{R}_{jet};#it{p}_{T,jet}^{tag} (GeV/#it{c}); (#it{p}{T,LT}^{tag} - #it{p}{T,LT}^{base}) / #it{p}{T,LT}^{base}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {100, -1.0, 1.0}}}); + registry.add("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #eta_{jet}^{tag}; #eta_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, jetEtaAxis, jetEtaAxis}}); + registry.add("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #varphi_{jet}^{tag}; #varphi_{jet}^{base}", {HistType::kTH3F, {jetPtAxis, {160, -1.0, 7.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); N_{jet tracks}^{tag}; N_{jet tracks}^{base}", {HistType::kTH3F, {jetPtAxis, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}); + registry.add("h3_jet_pt_tag_jet_leadingtrack_pt_tag_jet_leadingtrack_pt_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c}); #it{p}_{T,LT}^{tag}; #it{p}_{T,LT}^{tag}", {HistType::kTH3F, {jetPtAxis, {200, 0., 100.}, {200, 0., 100.}}}); + registry.add("h3_jet_pt_tag_jet_leadingtrack_fraction_tag_jet_leadingtrack_fraction_base_matchedgeopt", ";#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,LT}^{tag} / #it{p}_{T,jet}^{tag} ; #it{p}_{T,LT}^{tag} / #it{p}_{T,jet}^{base}", {HistType::kTH3F, {jetPtAxis, {50, 0., 1.}, {50, 0., 1.}}}); + registry.add("h3_ptcut_jet_pt_tag_jet_pt_base_matchedgeo", "N;#it{p}_{T,jet}^{tag} (GeV/#it{c});#it{p}_{T,jet}^{base} (GeV/#it{c})", {HistType::kTH3F, {{20, 0., 5.}, {300, 0., 300.}, {300, 0., 300.}}}); } if (doprocessTriggeredData) { registry.add("h_collision_trigger_events", "event status;event status;entries", {HistType::kTH1F, {{6, 0.0, 6.0}}}); registry.add("h_track_pt_MB", "track pT for MB events;#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0.0, 200.0}}}); - registry.add("h_track_eta_MB", "track #eta for MB events;#eta_{track};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_track_eta_MB", "track #eta for MB events;#eta_{track};entries", {HistType::kTH1F, {trackEtaAxis}}); registry.add("h_track_phi_MB", "track #varphi for MB events;#varphi_{track};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_track_pt_Triggered_Low", "track pT for low #it{p}_{T} Triggered events;#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0.0, 200.0}}}); - registry.add("h_track_eta_Triggered_Low", "track #eta for low #it{p}_{T} Triggered events;#eta_{track};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_track_eta_Triggered_Low", "track #eta for low #it{p}_{T} Triggered events;#eta_{track};entries", {HistType::kTH1F, {trackEtaAxis}}); registry.add("h_track_phi_Triggered_Low", "track #varphi for low #it{p}_{T} Triggered events;#varphi_{track};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_track_pt_Triggered_High", "track pT for high #it{p}_{T} Triggered events;#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0.0, 200.0}}}); - registry.add("h_track_eta_Triggered_High", "track #eta for high #it{p}_{T} Triggered events;#eta_{track};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_track_eta_Triggered_High", "track #eta for high #it{p}_{T} Triggered events;#eta_{track};entries", {HistType::kTH1F, {trackEtaAxis}}); registry.add("h_track_phi_Triggered_High", "track #varphi for high #it{p}_{T} Triggered events;#varphi_{track};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); registry.add("h_track_pt_Triggered_Both", "track pT for both #it{p}_{T} Triggered events;#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0.0, 200.0}}}); - registry.add("h_track_eta_Triggered_Both", "track #eta for both #it{p}_{T} Triggered events;#eta_{track};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_track_eta_Triggered_Both", "track #eta for both #it{p}_{T} Triggered events;#eta_{track};entries", {HistType::kTH1F, {trackEtaAxis}}); registry.add("h_track_phi_Triggered_Both", "track #varphi for both #it{p}_{T} Triggered events;#varphi_{track};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_collision", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});collision trigger status", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {4, -0.5, 3.5}}}); - registry.add("h3_jet_r_jet_eta_collision", "#it{R}_{jet};#eta_{jet};collision trigger status", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {4, -0.5, 3.5}}}); + registry.add("h3_jet_r_jet_pt_collision", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});collision trigger status", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {4, -0.5, 3.5}}}); + registry.add("h3_jet_r_jet_eta_collision", "#it{R}_{jet};#eta_{jet};collision trigger status", {HistType::kTH3F, {{jetRadiiBins, ""}, jetEtaAxis, {4, -0.5, 3.5}}}); registry.add("h3_jet_r_jet_phi_collision", "#it{R}_{jet};#varphi_{jet};collision trigger status", {HistType::kTH3F, {{jetRadiiBins, ""}, {160, -1.0, 7.}, {4, -0.5, 3.5}}}); - registry.add("h2_jet_r_jet_pT_triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, {200, 0., 200.}}}); - registry.add("h2_jet_r_jet_pT_triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, {200, 0., 200.}}}); - registry.add("h2_jet_r_jet_pT_triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_track_pt_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_track_eta_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_track_phi_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_track_pt_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_track_eta_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_track_phi_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_track_pt_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_track_eta_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_track_phi_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); - registry.add("h3_jet_r_jet_pt_track_pt_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); - registry.add("h3_jet_r_jet_pt_track_eta_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); - registry.add("h3_jet_r_jet_pt_track_phi_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h2_jet_r_jet_pT_triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, jetPtAxis}}); + registry.add("h2_jet_r_jet_pT_triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, jetPtAxis}}); + registry.add("h2_jet_r_jet_pT_triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{jetRadiiBins, ""}, jetPtAxis}}); + registry.add("h3_jet_r_jet_pt_track_pt_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_track_eta_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, trackEtaAxis}}); + registry.add("h3_jet_r_jet_pt_track_phi_MB", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_track_pt_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_track_eta_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, trackEtaAxis}}); + registry.add("h3_jet_r_jet_pt_track_phi_Triggered_Low", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_track_pt_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_track_eta_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, trackEtaAxis}}); + registry.add("h3_jet_r_jet_pt_track_phi_Triggered_High", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_track_pt_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_track_eta_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, trackEtaAxis}}); + registry.add("h3_jet_r_jet_pt_track_phi_Triggered_Both", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, jetPtAxis, {160, -1.0, 7.}}}); } if (doprocessTracks || doprocessTracksWeighted) { registry.add("h_collisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); registry.add("h2_centrality_collisions", "centrality vs collisions; centrality; collisions", {HistType::kTH2F, {{1200, -10.0, 110.0}, {4, 0.0, 4.0}}}); - registry.add("h2_centrality_track_pt", "centrality vs track pT; centrality; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, 0., 200.}}}); - registry.add("h2_centrality_track_eta", "centrality vs track #eta; centrality; #eta_{track}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, -1.0, 1.0}}}); - registry.add("h2_centrality_track_phi", "centrality vs track #varphi; centrality; #varphi_{track}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {160, -1.0, 7.}}}); - registry.add("h2_centrality_track_energy", "centrality vs track energy; centrality; Energy GeV", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, 0.0, 100.0}}}); + registry.add("h3_centrality_track_pt_track_phi", "centrality vs track pT vs track #varphi; centrality; #it{p}_{T,track} (GeV/#it{c}); #varphi_{track}", {HistType::kTH3F, {{1200, -10.0, 110.0}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_centrality_track_pt_track_eta", "centrality vs track pT vs track #eta; centrality; #it{p}_{T,track} (GeV/#it{c}); #eta_{track}", {HistType::kTH3F, {{1200, -10.0, 110.0}, {200, 0., 200.}, trackEtaAxis}}); + registry.add("h3_centrality_track_pt_track_dcaxy", "centrality vs track pT vs track DCA_{xy}; centrality; #it{p}_{T,track} (GeV/#it{c}); track DCA_{xy}", {HistType::kTH3F, {{120, -10.0, 110.0}, {20, 0., 100.}, {200, -0.15, 0.15}}}); + registry.add("h3_track_pt_track_eta_track_phi", "track pT vs track #eta vs track #varphi; #it{p}_{T,track} (GeV/#it{c}); #eta_{track}; #varphi_{track}", {HistType::kTH3F, {{200, 0., 200.}, trackEtaAxis, {160, -1.0, 7.}}}); if (doprocessTracksWeighted) { registry.add("h_collisions_weighted", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); } } if (doprocessTracksSub) { - - registry.add("h2_centrality_track_pt_eventwiseconstituentsubtracted", "centrality vs track pT; centrality; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, 0., 200.}}}); - registry.add("h2_centrality_track_eta_eventwiseconstituentsubtracted", "centrality vs track #eta; centrality; #eta_{track}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, -1.0, 1.0}}}); - registry.add("h2_centrality_track_phi_eventwiseconstituentsubtracted", "centrality vs track #varphi; centrality; #varphi_{track}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {160, -1.0, 7.}}}); - registry.add("h2_centrality_track_energy_eventwiseconstituentsubtracted", "centrality vs track energy; centrality; Energy GeV", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, 0.0, 100.0}}}); + registry.add("h3_centrality_track_pt_track_phi_eventwiseconstituentsubtracted", "centrality vs track pT vs track #varphi; centrality; #it{p}_{T,track} (GeV/#it{c}); #varphi_{track}", {HistType::kTH3F, {{1200, -10.0, 110.0}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_centrality_track_pt_track_eta_eventwiseconstituentsubtracted", "centrality vs track pT vs track #eta; centrality; #it{p}_{T,track} (GeV/#it{c}); #eta_{track}", {HistType::kTH3F, {{1200, -10.0, 110.0}, {200, 0., 200.}, trackEtaAxis}}); + registry.add("h3_track_pt_track_eta_track_phi_eventwiseconstituentsubtracted", "track pT vs track #eta vs track #varphi; #it{p}_{T,track} (GeV/#it{c}); #eta_{track}; #varphi_{track}", {HistType::kTH3F, {{200, 0., 200.}, trackEtaAxis, {160, -1.0, 7.}}}); } if (doprocessMCCollisionsWeighted) { AxisSpec weightAxis = {{VARIABLE_WIDTH, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1.0, 10.0}, "weights"}; registry.add("h_collision_eventweight_part", "event weight;event weight;entries", {HistType::kTH1F, {weightAxis}}); + registry.add("h_accepted", "No. of Generated Events;No. of Generated Events;entries", {HistType::kTH1F, {{5000, 0., 5000.}}}); + registry.add("h_attempted", "No. of Attempted Events;No. of Attempted Events;entries", {HistType::kTH1F, {{5000, 0., 5000.}}}); + registry.add("h_xsecGen", "Cross section in pb; Cross section in pb; entries", {HistType::kTH1F, {{200000, 0., 2e11}}}); + registry.add("h_xsecErr", "Error associated with the cross section", {HistType::kTH1F, {{200000, 0., 2e11}}}); + registry.add("h_xsecGenSum", "Summed Cross section per collision in pb; Summed Cross section per collision in pb; entries", {HistType::kTH1F, {{1, 0., 1.}}}); + registry.add("h_xsecGenSumWeighted", "Summed Cross section per collision in pb with weights; Summed Cross section per collision in pb with weights; entries", {HistType::kTH1F, {{1, 0., 1.}}}); + registry.add("h_xsecErrSum", "Summed Cross section error per collision in pb; Summed Cross section error per collision in pb; entries", {HistType::kTH1F, {{1, 0., 1.}}}); + registry.add("h_xsecErrSumWeighted", "Summed Cross section error per collision in pb with weights; Summed Cross section error per collision in pb with weights; entries", {HistType::kTH1F, {{1, 0., 1.}}}); + } + + AxisSpec occupancyAxis = {142, -1.5, 14000.5, "occupancy"}; + AxisSpec nTracksAxis = {16001, -1., 16000, "n tracks"}; + + if (doprocessOccupancyQA) { + registry.add("h2_occupancy_ntracksall_presel", "occupancy vs N_{tracks}; occupancy; N_{tracks}", {HistType::kTH2I, {occupancyAxis, nTracksAxis}}); + registry.add("h2_occupancy_ntracksall_postsel", "occupancy vs N_{tracks}; occupancy; N_{tracks}", {HistType::kTH2I, {occupancyAxis, nTracksAxis}}); + registry.add("h2_occupancy_ntrackssel_presel", "occupancy vs N_{tracks}; occupancy; N_{tracks}", {HistType::kTH2I, {occupancyAxis, nTracksAxis}}); + registry.add("h2_occupancy_ntrackssel_postsel", "occupancy vs N_{tracks}; occupancy; N_{tracks}", {HistType::kTH2I, {occupancyAxis, nTracksAxis}}); + registry.add("h2_occupancy_ntracksselptetacuts_presel", "occupancy vs N_{tracks}; occupancy; N_{tracks}", {HistType::kTH2I, {occupancyAxis, nTracksAxis}}); + registry.add("h2_occupancy_ntracksselptetacuts_postsel", "occupancy vs N_{tracks}; occupancy; N_{tracks}", {HistType::kTH2I, {occupancyAxis, nTracksAxis}}); } } Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); - Filter trackSubCuts = (aod::jtracksub::pt >= trackPtMin && aod::jtracksub::pt < trackPtMax && aod::jtracksub::eta > trackEtaMin && aod::jtracksub::eta < trackEtaMax); Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax); + PresliceUnsorted> CollisionsPerMCPCollision = aod::jmccollisionlb::mcCollisionId; template bool isAcceptedJet(U const& jet) @@ -293,29 +383,54 @@ struct JetFinderQATask { return false; } } - if (leadingConstituentPtMin > -98.0) { - bool isMinleadingConstituent = false; - for (auto& constituent : jet.template tracks_as()) { - if (constituent.pt() >= leadingConstituentPtMin) { - isMinleadingConstituent = true; - break; + bool checkConstituentPt = true; + bool checkConstituentMinPt = (leadingConstituentPtMin > -98.0); + bool checkConstituentMaxPt = (leadingConstituentPtMax < 9998.0); + if (!checkConstituentMinPt && !checkConstituentMaxPt) { + checkConstituentPt = false; + } + + if (checkConstituentPt) { + bool isMinLeadingConstituent = !checkConstituentMinPt; + bool isMaxLeadingConstituent = true; + + for (const auto& constituent : jet.template tracks_as()) { + double pt = constituent.pt(); + + if (checkConstituentMinPt && pt >= leadingConstituentPtMin) { + isMinLeadingConstituent = true; + } + if (checkConstituentMaxPt && pt > leadingConstituentPtMax) { + isMaxLeadingConstituent = false; } } - if (!isMinleadingConstituent) { - return false; - } + return isMinLeadingConstituent && isMaxLeadingConstituent; } + return true; } + template + bool trackIsInJet(T const& track, U const& jet) + { + for (auto const& constituentId : jet.tracksIds()) { + if (constituentId == track.globalIndex()) { + return true; + } + } + return false; + } + template - void fillHistograms(T const& jet, float centrality, float weight = 1.0) + void fillHistograms(T const& jet, float centrality, float occupancy, float weight = 1.0) { float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); - if (jet.pt() > pTHatMaxMCD * pTHat) { + if (jet.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { return; } + registry.fill(HIST("h_jet_phat"), pTHat); + registry.fill(HIST("h_jet_phat_weighted"), pTHat, weight); if (jet.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h_jet_pt"), jet.pt(), weight); @@ -326,6 +441,8 @@ struct JetFinderQATask { registry.fill(HIST("h2_centrality_jet_eta"), centrality, jet.eta(), weight); registry.fill(HIST("h2_centrality_jet_phi"), centrality, jet.phi(), weight); registry.fill(HIST("h2_centrality_jet_ntracks"), centrality, jet.tracksIds().size(), weight); + registry.fill(HIST("h3_centrality_occupancy_jet_pt"), centrality, occupancy, jet.pt(), weight); + registry.fill(HIST("h2_intrate_jet_pt"), jet.collision().hadronicRate(), jet.pt(), weight); } registry.fill(HIST("h3_jet_r_jet_pt_centrality"), jet.r() / 100.0, jet.pt(), centrality, weight); @@ -335,7 +452,7 @@ struct JetFinderQATask { registry.fill(HIST("h3_jet_r_jet_pt_jet_ntracks"), jet.r() / 100.0, jet.pt(), jet.tracksIds().size(), weight); registry.fill(HIST("h3_jet_r_jet_pt_jet_area"), jet.r() / 100.0, jet.pt(), jet.area(), weight); - for (auto& constituent : jet.template tracks_as()) { + for (auto& constituent : jet.template tracks_as()) { registry.fill(HIST("h3_jet_r_jet_pt_track_pt"), jet.r() / 100.0, jet.pt(), constituent.pt(), weight); registry.fill(HIST("h3_jet_r_jet_pt_track_eta"), jet.r() / 100.0, jet.pt(), constituent.eta(), weight); @@ -344,7 +461,7 @@ struct JetFinderQATask { } template - void fillRhoAreaSubtractedHistograms(T const& jet, float centrality, float rho, float weight = 1.0) + void fillRhoAreaSubtractedHistograms(T const& jet, float centrality, float occupancy, float rho, float weight = 1.0) { if (jet.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h_jet_pt_rhoareasubtracted"), jet.pt() - (rho * jet.area()), weight); @@ -352,11 +469,13 @@ struct JetFinderQATask { registry.fill(HIST("h_jet_phi_rhoareasubtracted"), jet.phi(), weight); registry.fill(HIST("h_jet_ntracks_rhoareasubtracted"), jet.tracksIds().size(), weight); registry.fill(HIST("h2_centrality_jet_pt_rhoareasubtracted"), centrality, jet.pt() - (rho * jet.area()), weight); + registry.fill(HIST("h3_centrality_occupancy_jet_pt_rhoareasubtracted"), centrality, occupancy, jet.pt() - (rho * jet.area()), weight); if (jet.pt() - (rho * jet.area()) > 0) { registry.fill(HIST("h2_centrality_jet_eta_rhoareasubtracted"), centrality, jet.eta(), weight); registry.fill(HIST("h2_centrality_jet_phi_rhoareasubtracted"), centrality, jet.phi(), weight); registry.fill(HIST("h2_centrality_jet_ntracks_rhoareasubtracted"), centrality, jet.tracksIds().size(), weight); } + registry.fill(HIST("h2_intrate_jet_pt_rhoareasubtracted"), jet.collision().hadronicRate(), jet.pt() - (rho * jet.area()), weight); } registry.fill(HIST("h3_jet_r_jet_pt_centrality_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), centrality, weight); @@ -367,7 +486,7 @@ struct JetFinderQATask { registry.fill(HIST("h3_jet_r_jet_pt_jet_area_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), jet.area(), weight); registry.fill(HIST("h3_jet_r_jet_pt_jet_pt_rhoareasubtracted"), jet.r() / 100.0, jet.pt(), jet.pt() - (rho * jet.area()), weight); - for (auto& constituent : jet.template tracks_as()) { + for (auto& constituent : jet.template tracks_as()) { registry.fill(HIST("h3_jet_r_jet_pt_track_pt_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), constituent.pt(), weight); registry.fill(HIST("h3_jet_r_jet_pt_track_eta_rhoareasubtracted"), jet.r() / 100.0, jet.pt() - (rho * jet.area()), constituent.eta(), weight); @@ -387,6 +506,7 @@ struct JetFinderQATask { registry.fill(HIST("h2_centrality_jet_eta_eventwiseconstituentsubtracted"), centrality, jet.eta(), weight); registry.fill(HIST("h2_centrality_jet_phi_eventwiseconstituentsubtracted"), centrality, jet.phi(), weight); registry.fill(HIST("h2_centrality_jet_ntracks_eventwiseconstituentsubtracted"), centrality, jet.tracksIds().size(), weight); + registry.fill(HIST("h2_intrate_jet_pt_eventwiseconstituentsubtracted"), jet.collision().hadronicRate(), jet.pt(), weight); } registry.fill(HIST("h3_jet_r_jet_pt_centrality_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), centrality, weight); @@ -396,7 +516,7 @@ struct JetFinderQATask { registry.fill(HIST("h3_jet_r_jet_pt_jet_ntracks_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), jet.tracksIds().size(), weight); registry.fill(HIST("h3_jet_r_jet_pt_jet_area_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), jet.area(), weight); - for (auto& constituent : jet.template tracks_as()) { + for (auto& constituent : jet.template tracks_as()) { registry.fill(HIST("h3_jet_r_jet_pt_track_pt_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), constituent.pt(), weight); registry.fill(HIST("h3_jet_r_jet_pt_track_eta_eventwiseconstituentsubtracted"), jet.r() / 100.0, jet.pt(), constituent.eta(), weight); @@ -409,9 +529,11 @@ struct JetFinderQATask { { float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); - if (jet.pt() > pTHatMaxMCP * pTHat) { + if (jet.pt() > pTHatMaxMCP * pTHat || pTHat < pTHatAbsoluteMin) { return; } + registry.fill(HIST("h_jet_phat_part"), pTHat); + registry.fill(HIST("h_jet_phat_part_weighted"), pTHat, weight); if (jet.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h_jet_pt_part"), jet.pt(), weight); @@ -425,7 +547,7 @@ struct JetFinderQATask { registry.fill(HIST("h3_jet_r_part_jet_eta_part_jet_phi_part"), jet.r() / 100.0, jet.eta(), jet.phi(), weight); registry.fill(HIST("h3_jet_r_part_jet_pt_part_jet_ntracks_part"), jet.r() / 100.0, jet.pt(), jet.tracksIds().size(), weight); - for (auto& constituent : jet.template tracks_as()) { + for (auto& constituent : jet.template tracks_as()) { registry.fill(HIST("h3_jet_r_part_jet_pt_part_track_pt_part"), jet.r() / 100.0, jet.pt(), constituent.pt(), weight); registry.fill(HIST("h3_jet_r_part_jet_pt_part_track_eta_part"), jet.r() / 100.0, jet.pt(), constituent.eta(), weight); @@ -434,10 +556,10 @@ struct JetFinderQATask { } template - void fillMatchedHistograms(T const& jetBase, float weight = 1.0) + void fillMatchedHistograms(T const& jetBase, float leadingTrackPtBase, float weight = 1.0) { float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); - if (jetBase.pt() > pTHatMaxMCD * pTHat) { + if (jetBase.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { return; } @@ -451,13 +573,29 @@ struct JetFinderQATask { registry.fill(HIST("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeo"), jetBase.r() / 100.0, jetTag.phi(), jetBase.phi(), weight); registry.fill(HIST("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeo"), jetBase.r() / 100.0, jetTag.tracksIds().size(), jetBase.tracksIds().size(), weight); registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeo"), jetBase.r() / 100.0, jetTag.pt(), (jetTag.pt() - jetBase.pt()) / jetTag.pt(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeo"), jetBase.r() / 100.0, jetTag.pt(), (jetTag.eta() - jetBase.eta()) / jetTag.eta(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeo"), jetBase.r() / 100.0, jetTag.pt(), (jetTag.phi() - jetBase.phi()) / jetTag.phi(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeo"), jetBase.r() / 100.0, jetTag.pt(), jetTag.eta() - jetBase.eta(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeo"), jetBase.r() / 100.0, jetTag.pt(), jetTag.phi() - jetBase.phi(), weight); + float leadingTrackPtTag = 0.; + for (auto& constituent : jetTag.template tracks_as()) { + if (constituent.pt() > leadingTrackPtTag) { + leadingTrackPtTag = constituent.pt(); + } + } + registry.fill(HIST("h3_jet_r_jet_pt_tag_leadingtrack_pt_diff_matchedgeo"), jetBase.r() / 100.0, jetTag.pt(), (leadingTrackPtTag - leadingTrackPtBase) / leadingTrackPtTag, weight); + registry.fill(HIST("h3_jet_r_jet_pt_tag_leadingtrack_fraction_diff_matchedgeo"), jetBase.r() / 100.0, jetTag.pt(), (leadingTrackPtTag / jetTag.pt()) - (leadingTrackPtBase / jetBase.pt()), weight); + + for (int N = 1; N < 21; N++) { + if (jetBase.pt() < N * 0.25 * pTHat && jetTag.pt() < N * 0.25 * pTHat) { + registry.fill(HIST("h3_ptcut_jet_pt_tag_jet_pt_base_matchedgeo"), N * 0.25, jetTag.pt(), jetBase.pt(), weight); + } + } if (jetBase.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeo"), jetTag.pt(), jetTag.eta(), jetBase.eta(), weight); registry.fill(HIST("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeo"), jetTag.pt(), jetTag.phi(), jetBase.phi(), weight); registry.fill(HIST("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeo"), jetTag.pt(), jetTag.tracksIds().size(), jetBase.tracksIds().size(), weight); + registry.fill(HIST("h3_jet_pt_tag_jet_leadingtrack_pt_tag_jet_leadingtrack_pt_base_matchedgeo"), jetTag.pt(), leadingTrackPtTag, leadingTrackPtBase, weight); + registry.fill(HIST("h3_jet_pt_tag_jet_leadingtrack_fraction_tag_jet_leadingtrack_fraction_base_matchedgeo"), jetTag.pt(), leadingTrackPtTag / jetTag.pt(), leadingTrackPtBase / jetBase.pt(), weight); } } } @@ -471,13 +609,23 @@ struct JetFinderQATask { registry.fill(HIST("h3_jet_r_jet_phi_tag_jet_phi_base_matchedpt"), jetBase.r() / 100.0, jetTag.phi(), jetBase.phi(), weight); registry.fill(HIST("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedpt"), jetBase.r() / 100.0, jetTag.tracksIds().size(), jetBase.tracksIds().size(), weight); registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedpt"), jetBase.r() / 100.0, jetTag.pt(), (jetTag.pt() - jetBase.pt()) / jetTag.pt(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedpt"), jetBase.r() / 100.0, jetTag.pt(), (jetTag.eta() - jetBase.eta()) / jetTag.eta(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedpt"), jetBase.r() / 100.0, jetTag.pt(), (jetTag.phi() - jetBase.phi()) / jetTag.phi(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedpt"), jetBase.r() / 100.0, jetTag.pt(), jetTag.eta() - jetBase.eta(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedpt"), jetBase.r() / 100.0, jetTag.pt(), jetTag.phi() - jetBase.phi(), weight); + float leadingTrackPtTag = 0.; + for (auto& constituent : jetTag.template tracks_as()) { + if (constituent.pt() > leadingTrackPtTag) { + leadingTrackPtTag = constituent.pt(); + } + } + registry.fill(HIST("h3_jet_r_jet_pt_tag_leadingtrack_pt_diff_matchedpt"), jetBase.r() / 100.0, jetTag.pt(), (leadingTrackPtTag - leadingTrackPtBase) / leadingTrackPtTag, weight); + registry.fill(HIST("h3_jet_r_jet_pt_tag_leadingtrack_fraction_diff_matchedpt"), jetBase.r() / 100.0, jetTag.pt(), (leadingTrackPtTag / jetTag.pt()) - (leadingTrackPtBase / jetBase.pt()), weight); if (jetBase.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedpt"), jetTag.pt(), jetTag.eta(), jetBase.eta(), weight); registry.fill(HIST("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedpt"), jetTag.pt(), jetTag.phi(), jetBase.phi(), weight); registry.fill(HIST("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedpt"), jetTag.pt(), jetTag.tracksIds().size(), jetBase.tracksIds().size(), weight); + registry.fill(HIST("h3_jet_pt_tag_jet_leadingtrack_pt_tag_jet_leadingtrack_pt_base_matchedpt"), jetTag.pt(), leadingTrackPtTag, leadingTrackPtBase, weight); + registry.fill(HIST("h3_jet_pt_tag_jet_leadingtrack_fraction_tag_jet_leadingtrack_fraction_base_matchedpt"), jetTag.pt(), leadingTrackPtTag / jetTag.pt(), leadingTrackPtBase / jetBase.pt(), weight); } } } @@ -495,13 +643,23 @@ struct JetFinderQATask { registry.fill(HIST("h3_jet_r_jet_phi_tag_jet_phi_base_matchedgeopt"), jetBase.r() / 100.0, jetTag.phi(), jetBase.phi(), weight); registry.fill(HIST("h3_jet_r_jet_ntracks_tag_jet_ntracks_base_matchedgeopt"), jetBase.r() / 100.0, jetTag.tracksIds().size(), jetBase.tracksIds().size(), weight); registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_pt_base_diff_matchedgeopt"), jetBase.r() / 100.0, jetTag.pt(), (jetTag.pt() - jetBase.pt()) / jetTag.pt(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeopt"), jetBase.r() / 100.0, jetTag.pt(), (jetTag.eta() - jetBase.eta()) / jetTag.eta(), weight); - registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeopt"), jetBase.r() / 100.0, jetTag.pt(), (jetTag.phi() - jetBase.phi()) / jetTag.phi(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_eta_base_diff_matchedgeopt"), jetBase.r() / 100.0, jetTag.pt(), jetTag.eta() - jetBase.eta(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_tag_jet_phi_base_diff_matchedgeopt"), jetBase.r() / 100.0, jetTag.pt(), jetTag.phi() - jetBase.phi(), weight); + float leadingTrackPtTag = 0.; + for (auto& constituent : jetTag.template tracks_as()) { + if (constituent.pt() > leadingTrackPtTag) { + leadingTrackPtTag = constituent.pt(); + } + } + registry.fill(HIST("h3_jet_r_jet_pt_tag_leadingtrack_pt_diff_matchedgeopt"), jetBase.r() / 100.0, jetTag.pt(), (leadingTrackPtTag - leadingTrackPtBase) / leadingTrackPtTag, weight); + registry.fill(HIST("h3_jet_r_jet_pt_tag_leadingtrack_fraction_diff_matchedgeopt"), jetBase.r() / 100.0, jetTag.pt(), (leadingTrackPtTag / jetTag.pt()) - (leadingTrackPtBase / jetBase.pt()), weight); if (jetBase.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h3_jet_pt_tag_jet_eta_tag_jet_eta_base_matchedgeopt"), jetTag.pt(), jetTag.eta(), jetBase.eta(), weight); registry.fill(HIST("h3_jet_pt_tag_jet_phi_tag_jet_phi_base_matchedgeopt"), jetTag.pt(), jetTag.phi(), jetBase.phi(), weight); registry.fill(HIST("h3_jet_pt_tag_jet_ntracks_tag_jet_ntracks_base_matchedgeopt"), jetTag.pt(), jetTag.tracksIds().size(), jetBase.tracksIds().size(), weight); + registry.fill(HIST("h3_jet_pt_tag_jet_leadingtrack_pt_tag_jet_leadingtrack_pt_base_matchedgeopt"), jetTag.pt(), leadingTrackPtTag, leadingTrackPtBase, weight); + registry.fill(HIST("h3_jet_pt_tag_jet_leadingtrack_fraction_tag_jet_leadingtrack_fraction_base_matchedgeopt"), jetTag.pt(), leadingTrackPtTag / jetTag.pt(), leadingTrackPtBase / jetBase.pt(), weight); } } } @@ -511,54 +669,173 @@ struct JetFinderQATask { template void fillTrackHistograms(T const& collision, U const& tracks, float weight = 1.0) { + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (pTHat < pTHatAbsoluteMin) { + return; + } for (auto const& track : tracks) { if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { continue; } - registry.fill(HIST("h2_centrality_track_pt"), collision.centrality(), track.pt(), weight); - registry.fill(HIST("h2_centrality_track_eta"), collision.centrality(), track.eta(), weight); - registry.fill(HIST("h2_centrality_track_phi"), collision.centrality(), track.phi(), weight); - registry.fill(HIST("h2_centrality_track_energy"), collision.centrality(), track.energy(), weight); + registry.fill(HIST("h3_centrality_track_pt_track_phi"), collision.centrality(), track.pt(), track.phi(), weight); + registry.fill(HIST("h3_centrality_track_pt_track_eta"), collision.centrality(), track.pt(), track.eta(), weight); + registry.fill(HIST("h3_centrality_track_pt_track_dcaxy"), collision.centrality(), track.pt(), track.dcaXY(), weight); + registry.fill(HIST("h3_track_pt_track_eta_track_phi"), track.pt(), track.eta(), track.phi(), weight); + } + } + + template + void randomCone(T const& collision, U const& jets, V const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + TRandom3 randomNumber(0); + float randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); + float randomConePhi = randomNumber.Uniform(0.0, 2 * M_PI); + float randomConePt = 0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-M_PI)); + float dEta = track.eta() - randomConeEta; + if (TMath::Sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePt += track.pt(); + } + } + } + registry.fill(HIST("h2_centrality_rhorandomcone"), collision.centrality(), randomConePt - M_PI * randomConeR * randomConeR * collision.rho()); + + // randomised eta,phi for tracks, to assess part of fluctuations coming from statistically independently emitted particles + randomConePt = 0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + float dPhi = RecoDecay::constrainAngle(randomNumber.Uniform(0.0, 2 * M_PI) - randomConePhi, static_cast(-M_PI)); // ignores actual phi of track + float dEta = randomNumber.Uniform(trackEtaMin, trackEtaMax) - randomConeEta; // ignores actual eta of track + if (TMath::Sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePt += track.pt(); + } + } + } + registry.fill(HIST("h2_centrality_rhorandomconerandomtrackdirection"), collision.centrality(), randomConePt - M_PI * randomConeR * randomConeR * collision.rho()); + + // removing the leading jet from the random cone + if (jets.size() > 0) { // if there are no jets in the acceptance (from the jetfinder cuts) then there can be no leading jet + float dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, static_cast(-M_PI)); + float dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; + + bool jetWasInCone = false; + while ((randomConeLeadJetDeltaR <= 0 && (TMath::Sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < jets.iteratorAt(0).r() / 100.0 + randomConeR)) || (randomConeLeadJetDeltaR > 0 && (TMath::Sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < randomConeLeadJetDeltaR))) { + jetWasInCone = true; + randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); + randomConePhi = randomNumber.Uniform(0.0, 2 * M_PI); + dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, static_cast(-M_PI)); + dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; + } + if (jetWasInCone) { + randomConePt = 0.0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { // if track selection is uniformTrack, dcaXY and dcaZ cuts need to be added as they aren't in the selection so that they can be studied here + float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-M_PI)); + float dEta = track.eta() - randomConeEta; + if (TMath::Sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePt += track.pt(); + } + } + } + } } + + registry.fill(HIST("h2_centrality_rhorandomconewithoutleadingjet"), collision.centrality(), randomConePt - M_PI * randomConeR * randomConeR * collision.rho()); + + // randomised eta,phi for tracks, to assess part of fluctuations coming from statistically independently emitted particles, removing tracks from 2 leading jets + double randomConePtWithoutOneLeadJet = 0; + double randomConePtWithoutTwoLeadJet = 0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + float dPhi = RecoDecay::constrainAngle(randomNumber.Uniform(0.0, 2 * M_PI) - randomConePhi, static_cast(-M_PI)); // ignores actual phi of track + float dEta = randomNumber.Uniform(trackEtaMin, trackEtaMax) - randomConeEta; // ignores actual eta of track + if (TMath::Sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + if (!trackIsInJet(track, jets.iteratorAt(0))) { + randomConePtWithoutOneLeadJet += track.pt(); + if (!trackIsInJet(track, jets.iteratorAt(1))) { + randomConePtWithoutTwoLeadJet += track.pt(); + } + } + } + } + } + registry.fill(HIST("h2_centrality_rhorandomconerandomtrackdirectionwithoutoneleadingjets"), collision.centrality(), randomConePtWithoutOneLeadJet - M_PI * randomConeR * randomConeR * collision.rho()); + registry.fill(HIST("h2_centrality_rhorandomconerandomtrackdirectionwithouttwoleadingjets"), collision.centrality(), randomConePtWithoutTwoLeadJet - M_PI * randomConeR * randomConeR * collision.rho()); } - void processJetsData(soa::Filtered::iterator const& collision, soa::Join const& jets, JetTracks const&) + void processJetsData(soa::Filtered::iterator const& collision, soa::Join const& jets, aod::JetTracks const&) { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } for (auto const& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { continue; } - fillHistograms(jet, collision.centrality()); + fillHistograms(jet, collision.centrality(), collision.trackOccupancyInTimeRange()); } } PROCESS_SWITCH(JetFinderQATask, processJetsData, "jet finder QA data", false); - void processJetsRhoAreaSubData(soa::Filtered>::iterator const& collision, + void processJetsRhoAreaSubData(soa::Filtered>::iterator const& collision, soa::Join const& jets, - JetTracks const&) + aod::JetTracks const&) { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } for (auto jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { continue; } - fillRhoAreaSubtractedHistograms(jet, collision.centrality(), collision.rho()); + fillRhoAreaSubtractedHistograms(jet, collision.centrality(), collision.trackOccupancyInTimeRange(), collision.rho()); } } PROCESS_SWITCH(JetFinderQATask, processJetsRhoAreaSubData, "jet finder QA for rho-area subtracted jets", false); - void processEvtWiseConstSubJetsData(soa::Filtered::iterator const& collision, soa::Join const& jets, JetTracksSub const&) + void processJetsRhoAreaSubMCD(soa::Filtered>::iterator const& collision, + soa::Join const& jets, + aod::JetTracks const&) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillRhoAreaSubtractedHistograms(jet, collision.centrality(), collision.trackOccupancyInTimeRange(), collision.rho()); + } + } + PROCESS_SWITCH(JetFinderQATask, processJetsRhoAreaSubMCD, "jet finder QA for rho-area subtracted mcd jets", false); + + void processEvtWiseConstSubJetsData(soa::Filtered::iterator const& collision, soa::Join const& jets, aod::JetTracksSub const&) { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } for (auto const& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { continue; } fillEventWiseConstituentSubtractedHistograms(jet, collision.centrality()); @@ -566,149 +843,222 @@ struct JetFinderQATask { } PROCESS_SWITCH(JetFinderQATask, processEvtWiseConstSubJetsData, "jet finder QA for eventwise constituent-subtracted jets data", false); - void processJetsSubMatched(soa::Filtered::iterator const&, + void processEvtWiseConstSubJetsMCD(soa::Filtered::iterator const& collision, soa::Join const& jets, aod::JetTracksSub const&) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillEventWiseConstituentSubtractedHistograms(jet, collision.centrality()); + } + } + PROCESS_SWITCH(JetFinderQATask, processEvtWiseConstSubJetsMCD, "jet finder QA for eventwise constituent-subtracted mcd jets", false); + + void processJetsSubMatched(soa::Filtered::iterator const& collision, soa::Join const& jets, soa::Join const&, - JetTracks const&, JetTracksSub const&) + aod::JetTracks const&, aod::JetTracksSub const&) { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } for (const auto& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { continue; } - fillMatchedHistograms::iterator, soa::Join>(jet); + float leadingTrackPtBase = 0.; + for (auto& constituent : jet.template tracks_as()) { + if (constituent.pt() > leadingTrackPtBase) { + leadingTrackPtBase = constituent.pt(); + } + } + fillMatchedHistograms::iterator, soa::Join>(jet, leadingTrackPtBase); } } PROCESS_SWITCH(JetFinderQATask, processJetsSubMatched, "jet finder QA matched unsubtracted and constituent subtracted jets", false); - void processJetsMCD(soa::Filtered::iterator const& collision, soa::Join const& jets, JetTracks const&) + void processJetsMCD(soa::Filtered::iterator const& collision, soa::Join const& jets, aod::JetTracks const&) { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } for (auto const& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { continue; } - fillHistograms(jet, collision.centrality()); + fillHistograms(jet, collision.centrality(), collision.trackOccupancyInTimeRange()); } } PROCESS_SWITCH(JetFinderQATask, processJetsMCD, "jet finder QA mcd", false); - void processJetsMCDWeighted(soa::Filtered::iterator const& collision, soa::Join const& jets, JetTracks const&) + void processJetsMCDWeighted(soa::Filtered::iterator const& collision, soa::Join const& jets, aod::JetTracks const&) { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } for (auto const& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { continue; } - double pTHat = 10. / (std::pow(jet.eventWeight(), 1.0 / 6.0)); + double pTHat = 10. / (std::pow(jet.eventWeight(), 1.0 / pTHatExponent)); for (int N = 1; N < 21; N++) { if (jet.pt() < N * 0.25 * pTHat && jet.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h_jet_ptcut"), jet.pt(), N * 0.25, jet.eventWeight()); } } - registry.fill(HIST("h_jet_phat"), pTHat); - fillHistograms(jet, collision.centrality(), jet.eventWeight()); + fillHistograms(jet, collision.centrality(), collision.trackOccupancyInTimeRange(), jet.eventWeight()); } } PROCESS_SWITCH(JetFinderQATask, processJetsMCDWeighted, "jet finder QA mcd with weighted events", false); - void processJetsMCP(soa::Join::iterator const& jet, JetParticles const&) + void processJetsMCP(soa::Join::iterator const& jet, aod::JetParticles const&, aod::JetMcCollisions const&, soa::Filtered const& collisions) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { return; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { return; } - fillMCPHistograms(jet); + if (checkMcCollisionIsMatched) { + auto collisionspermcpjet = collisions.sliceBy(CollisionsPerMCPCollision, jet.mcCollisionId()); + if (collisionspermcpjet.size() >= 1 && jetderiveddatautilities::selectCollision(collisionspermcpjet.begin(), eventSelectionBits)) { + fillMCPHistograms(jet); + } + } else { + fillMCPHistograms(jet); + } } PROCESS_SWITCH(JetFinderQATask, processJetsMCP, "jet finder QA mcp", false); - void processJetsMCPWeighted(soa::Join::iterator const& jet, JetParticles const&) + void processJetsMCPWeighted(soa::Join::iterator const& jet, aod::JetParticles const&, aod::JetMcCollisions const&, soa::Filtered const& collisions) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { return; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { return; } - double pTHat = 10. / (std::pow(jet.eventWeight(), 1.0 / 6.0)); + double pTHat = 10. / (std::pow(jet.eventWeight(), 1.0 / pTHatExponent)); for (int N = 1; N < 21; N++) { if (jet.pt() < N * 0.25 * pTHat && jet.r() == round(selectedJetsRadius * 100.0f)) { registry.fill(HIST("h_jet_ptcut_part"), jet.pt(), N * 0.25, jet.eventWeight()); } } - registry.fill(HIST("h_jet_phat_part"), pTHat); - fillMCPHistograms(jet, jet.eventWeight()); + if (checkMcCollisionIsMatched) { + auto collisionspermcpjet = collisions.sliceBy(CollisionsPerMCPCollision, jet.mcCollisionId()); + if (collisionspermcpjet.size() >= 1 && jetderiveddatautilities::selectCollision(collisionspermcpjet.begin(), eventSelectionBits)) { + fillMCPHistograms(jet, jet.eventWeight()); + } + } else { + fillMCPHistograms(jet, jet.eventWeight()); + } } PROCESS_SWITCH(JetFinderQATask, processJetsMCPWeighted, "jet finder QA mcp with weighted events", false); - void processJetsMCPMCDMatched(soa::Filtered::iterator const&, + void processJetsMCPMCDMatched(soa::Filtered::iterator const& collision, soa::Join const& mcdjets, soa::Join const&, - JetTracks const&, JetParticles const&) + aod::JetTracks const&, aod::JetParticles const&) { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } for (const auto& mcdjet : mcdjets) { if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(mcdjet)) { + if (!isAcceptedJet(mcdjet)) { continue; } - fillMatchedHistograms::iterator, soa::Join>(mcdjet); + float leadingTrackPtBase = 0.; + for (auto& constituent : mcdjet.template tracks_as()) { + if (constituent.pt() > leadingTrackPtBase) { + leadingTrackPtBase = constituent.pt(); + } + } + fillMatchedHistograms::iterator, soa::Join>(mcdjet, leadingTrackPtBase); } } PROCESS_SWITCH(JetFinderQATask, processJetsMCPMCDMatched, "jet finder QA matched mcp and mcd", false); - void processJetsMCPMCDMatchedWeighted(soa::Filtered::iterator const&, + void processJetsMCPMCDMatchedWeighted(soa::Filtered::iterator const& collision, soa::Join const& mcdjets, soa::Join const&, - JetTracks const&, JetParticles const&) + aod::JetTracks const&, aod::JetParticles const&) { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } for (const auto& mcdjet : mcdjets) { if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(mcdjet)) { + if (!isAcceptedJet(mcdjet)) { continue; } - fillMatchedHistograms::iterator, soa::Join>(mcdjet, mcdjet.eventWeight()); + float leadingTrackPtBase = 0.; + for (auto& constituent : mcdjet.template tracks_as()) { + if (constituent.pt() > leadingTrackPtBase) { + leadingTrackPtBase = constituent.pt(); + } + } + fillMatchedHistograms::iterator, soa::Join>(mcdjet, leadingTrackPtBase, mcdjet.eventWeight()); } } PROCESS_SWITCH(JetFinderQATask, processJetsMCPMCDMatchedWeighted, "jet finder QA matched mcp and mcd with weighted events", false); - void processMCCollisionsWeighted(JetMcCollision const& collision) + void processMCCollisionsWeighted(aod::JetMcCollision const& collision) { + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } registry.fill(HIST("h_collision_eventweight_part"), collision.weight()); + registry.fill(HIST("h_accepted"), collision.accepted()); + registry.fill(HIST("h_attempted"), collision.attempted()); + registry.fill(HIST("h_xsecGen"), collision.xsectGen()); + registry.fill(HIST("h_xsecErr"), collision.xsectErr()); + registry.fill(HIST("h_xsecGenSum"), 0.5, collision.xsectGen()); + registry.fill(HIST("h_xsecGenSumWeighted"), 0.5, collision.xsectGen() * collision.weight()); + registry.fill(HIST("h_xsecErrSum"), 0.5, collision.xsectErr()); + registry.fill(HIST("h_xsecErrSumWeighted"), 0.5, collision.xsectErr() * collision.weight()); } PROCESS_SWITCH(JetFinderQATask, processMCCollisionsWeighted, "collision QA for weighted events", false); - void processTriggeredData(soa::Join::iterator const& collision, + void processTriggeredData(soa::Join::iterator const& collision, soa::Join const& jets, - soa::Filtered const& tracks) + soa::Filtered const& tracks) { registry.fill(HIST("h_collision_trigger_events"), 0.5); // all events if (collision.posZ() > vertexZCut) { return; } registry.fill(HIST("h_collision_trigger_events"), 1.5); // all events with z vertex cut - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } registry.fill(HIST("h_collision_trigger_events"), 2.5); // events with sel8() - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt)) { registry.fill(HIST("h_collision_trigger_events"), 3.5); // events with high pT triggered jets } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { registry.fill(HIST("h_collision_trigger_events"), 4.5); // events with high pT triggered jets } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow) && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt) && jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { registry.fill(HIST("h_collision_trigger_events"), 5.5); // events with high pT triggered jets } @@ -720,19 +1070,19 @@ struct JetFinderQATask { for (auto& jet : jets) { for (std::size_t iJetRadius = 0; iJetRadius < jetRadiiValues.size(); iJetRadius++) { if (jet.r() == round(jetRadiiValues[iJetRadius] * 100.0f)) { - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow) && !filledJetR_Low[iJetRadius]) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt) && !filledJetR_Low[iJetRadius]) { filledJetR_Low[iJetRadius] = true; for (double pt = 0.0; pt <= jet.pt(); pt += 1.0) { registry.fill(HIST("h2_jet_r_jet_pT_triggered_Low"), jet.r() / 100.0, pt); } } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh) && !filledJetR_High[iJetRadius]) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt) && !filledJetR_High[iJetRadius]) { filledJetR_High[iJetRadius] = true; for (double pt = 0.0; pt <= jet.pt(); pt += 1.0) { registry.fill(HIST("h2_jet_r_jet_pT_triggered_High"), jet.r() / 100.0, pt); } } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow) && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh) && !filledJetR_Both[iJetRadius]) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt) && jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt) && !filledJetR_Both[iJetRadius]) { filledJetR_Both[iJetRadius] = true; for (double pt = 0.0; pt <= jet.pt(); pt += 1.0) { registry.fill(HIST("h2_jet_r_jet_pT_triggered_Both"), jet.r() / 100.0, pt); @@ -749,38 +1099,38 @@ struct JetFinderQATask { registry.fill(HIST("h3_jet_r_jet_eta_collision"), jet.r() / 100.0, jet.eta(), 0.0); registry.fill(HIST("h3_jet_r_jet_phi_collision"), jet.r() / 100.0, jet.phi(), 0.0); - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt)) { registry.fill(HIST("h3_jet_r_jet_pt_collision"), jet.r() / 100.0, jet.pt(), 1.0); registry.fill(HIST("h3_jet_r_jet_eta_collision"), jet.r() / 100.0, jet.eta(), 1.0); registry.fill(HIST("h3_jet_r_jet_phi_collision"), jet.r() / 100.0, jet.phi(), 1.0); } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { registry.fill(HIST("h3_jet_r_jet_pt_collision"), jet.r() / 100.0, jet.pt(), 2.0); registry.fill(HIST("h3_jet_r_jet_eta_collision"), jet.r() / 100.0, jet.eta(), 2.0); registry.fill(HIST("h3_jet_r_jet_phi_collision"), jet.r() / 100.0, jet.phi(), 2.0); } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow) && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt) && jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { registry.fill(HIST("h3_jet_r_jet_pt_collision"), jet.r() / 100.0, jet.pt(), 3.0); registry.fill(HIST("h3_jet_r_jet_eta_collision"), jet.r() / 100.0, jet.eta(), 3.0); registry.fill(HIST("h3_jet_r_jet_phi_collision"), jet.r() / 100.0, jet.phi(), 3.0); } - for (auto& constituent : jet.template tracks_as>()) { + for (auto& constituent : jet.template tracks_as>()) { registry.fill(HIST("h3_jet_r_jet_pt_track_pt_MB"), jet.r() / 100.0, jet.pt(), constituent.pt()); registry.fill(HIST("h3_jet_r_jet_pt_track_eta_MB"), jet.r() / 100.0, jet.pt(), constituent.eta()); registry.fill(HIST("h3_jet_r_jet_pt_track_phi_MB"), jet.r() / 100.0, jet.pt(), constituent.phi()); - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt)) { registry.fill(HIST("h3_jet_r_jet_pt_track_pt_Triggered_Low"), jet.r() / 100.0, jet.pt(), constituent.pt()); registry.fill(HIST("h3_jet_r_jet_pt_track_eta_Triggered_Low"), jet.r() / 100.0, jet.pt(), constituent.eta()); registry.fill(HIST("h3_jet_r_jet_pt_track_phi_Triggered_Low"), jet.r() / 100.0, jet.pt(), constituent.phi()); } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { registry.fill(HIST("h3_jet_r_jet_pt_track_pt_Triggered_High"), jet.r() / 100.0, jet.pt(), constituent.pt()); registry.fill(HIST("h3_jet_r_jet_pt_track_eta_Triggered_High"), jet.r() / 100.0, jet.pt(), constituent.eta()); registry.fill(HIST("h3_jet_r_jet_pt_track_phi_Triggered_High"), jet.r() / 100.0, jet.pt(), constituent.phi()); } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow) && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt) && jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { registry.fill(HIST("h3_jet_r_jet_pt_track_pt_Triggered_Both"), jet.r() / 100.0, jet.pt(), constituent.pt()); registry.fill(HIST("h3_jet_r_jet_pt_track_eta_Triggered_Both"), jet.r() / 100.0, jet.pt(), constituent.eta()); registry.fill(HIST("h3_jet_r_jet_pt_track_phi_Triggered_Both"), jet.r() / 100.0, jet.pt(), constituent.phi()); @@ -796,17 +1146,17 @@ struct JetFinderQATask { registry.fill(HIST("h_track_eta_MB"), track.eta()); registry.fill(HIST("h_track_phi_MB"), track.phi()); - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt)) { registry.fill(HIST("h_track_pt_Triggered_Low"), track.pt()); registry.fill(HIST("h_track_eta_Triggered_Low"), track.eta()); registry.fill(HIST("h_track_phi_Triggered_Low"), track.phi()); } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { registry.fill(HIST("h_track_pt_Triggered_High"), track.pt()); registry.fill(HIST("h_track_eta_Triggered_High"), track.eta()); registry.fill(HIST("h_track_phi_Triggered_High"), track.phi()); } - if (jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow) && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)) { + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt) && jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { registry.fill(HIST("h_track_pt_Triggered_Both"), track.pt()); registry.fill(HIST("h_track_eta_Triggered_Both"), track.eta()); registry.fill(HIST("h_track_phi_Triggered_Both"), track.phi()); @@ -815,54 +1165,81 @@ struct JetFinderQATask { } PROCESS_SWITCH(JetFinderQATask, processTriggeredData, "QA for charged jet trigger", false); - void processTracks(soa::Filtered::iterator const& collision, - soa::Filtered const& tracks) + void processTracks(soa::Filtered::iterator const& collision, + soa::Filtered> const& tracks) { + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } registry.fill(HIST("h_collisions"), 0.5); registry.fill(HIST("h2_centrality_collisions"), collision.centrality(), 0.5); - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } registry.fill(HIST("h_collisions"), 1.5); registry.fill(HIST("h2_centrality_collisions"), collision.centrality(), 1.5); + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + registry.fill(HIST("h_collisions"), 2.5); + registry.fill(HIST("h2_centrality_collisions"), collision.centrality(), 2.5); fillTrackHistograms(collision, tracks); } PROCESS_SWITCH(JetFinderQATask, processTracks, "QA for charged tracks", false); - void processTracksWeighted(soa::Join::iterator const& collision, - JetMcCollisions const&, - soa::Filtered const& tracks) + void processTracksWeighted(soa::Join::iterator const& collision, + aod::JetMcCollisions const&, + soa::Filtered> const& tracks) { float eventWeight = collision.mcCollision().weight(); + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } registry.fill(HIST("h_collisions"), 0.5); registry.fill(HIST("h_collisions_weighted"), 0.5, eventWeight); - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } registry.fill(HIST("h_collisions"), 1.5); registry.fill(HIST("h_collisions_weighted"), 1.5, eventWeight); + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + registry.fill(HIST("h_collisions"), 2.5); + registry.fill(HIST("h_collisions_weighted"), 2.5, eventWeight); fillTrackHistograms(collision, tracks, eventWeight); } PROCESS_SWITCH(JetFinderQATask, processTracksWeighted, "QA for charged tracks weighted", false); - void processTracksSub(soa::Filtered::iterator const& collision, - soa::Filtered const& tracks) + void processTracksSub(soa::Filtered::iterator const& collision, + soa::Filtered const& tracks) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { return; } for (auto const& track : tracks) { - registry.fill(HIST("h2_centrality_track_pt_eventwiseconstituentsubtracted"), collision.centrality(), track.pt()); - registry.fill(HIST("h2_centrality_track_eta_eventwiseconstituentsubtracted"), collision.centrality(), track.eta()); - registry.fill(HIST("h2_centrality_track_phi_eventwiseconstituentsubtracted"), collision.centrality(), track.phi()); - registry.fill(HIST("h2_centrality_track_energy_eventwiseconstituentsubtracted"), collision.centrality(), track.energy()); + registry.fill(HIST("h3_centrality_track_pt_track_phi_eventwiseconstituentsubtracted"), collision.centrality(), track.pt(), track.phi()); + registry.fill(HIST("h3_centrality_track_pt_track_eta_eventwiseconstituentsubtracted"), collision.centrality(), track.pt(), track.eta()); + registry.fill(HIST("h3_track_pt_track_eta_track_phi_eventwiseconstituentsubtracted"), track.pt(), track.eta(), track.phi()); } } PROCESS_SWITCH(JetFinderQATask, processTracksSub, "QA for charged event-wise embedded subtracted tracks", false); - void processRho(soa::Filtered>::iterator const& collision, soa::Filtered const& tracks) + void processRho(soa::Filtered>::iterator const& collision, soa::Filtered const& tracks) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { return; } int nTracks = 0; @@ -879,56 +1256,49 @@ struct JetFinderQATask { } PROCESS_SWITCH(JetFinderQATask, processRho, "QA for rho-area subtracted jets", false); - void processRandomCone(soa::Filtered>::iterator const& collision, soa::Join const& jets, JetTracks const& tracks) + void processRandomConeData(soa::Filtered>::iterator const& collision, soa::Join const& jets, soa::Filtered const& tracks) + { + randomCone(collision, jets, tracks); + } + PROCESS_SWITCH(JetFinderQATask, processRandomConeData, "QA for random cone estimation of background fluctuations in data", false); + + void processRandomConeMCD(soa::Filtered>::iterator const& collision, soa::Join const& jets, soa::Filtered const& tracks) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { return; } - TRandom3 randomNumber(0); - float randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); - float randomConePhi = randomNumber.Uniform(0.0, 2 * M_PI); - float randomConePt = 0; + randomCone(collision, jets, tracks); + } + PROCESS_SWITCH(JetFinderQATask, processRandomConeMCD, "QA for random cone estimation of background fluctuations in mcd", false); + + void processOccupancyQA(soa::Filtered::iterator const& collision, aod::JetTracks const& tracks) + { + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + int occupancy = collision.trackOccupancyInTimeRange(); + int nTracksAll = tracks.size(); + int nTracksAllAcceptanceAndSelected = 0; + int nTracksInAcceptanceAndSelected = 0; for (auto const& track : tracks) { if (jetderiveddatautilities::selectTrack(track, trackSelection)) { - float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-M_PI)); - float dEta = track.eta() - randomConeEta; - if (TMath::Sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { - randomConePt += track.pt(); + nTracksAllAcceptanceAndSelected += 1; + if (track.pt() >= trackPtMin && track.pt() < trackPtMax && track.eta() > trackEtaMin && track.eta() < trackEtaMax) { + nTracksInAcceptanceAndSelected += 1; } } } - registry.fill(HIST("h2_centrality_rhorandomcone"), collision.centrality(), randomConePt - M_PI * randomConeR * randomConeR * collision.rho()); - - // removing the leading jet from the random cone - if (jets.size() > 0) { // if there are no jets in the acceptance (from the jetfinder cuts) then there can be no leading jet - float dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, static_cast(-M_PI)); - float dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; - bool jetWasInCone = false; - while (TMath::Sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < jets.iteratorAt(0).r() / 100.0 + randomConeR) { - jetWasInCone = true; - randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); - randomConePhi = randomNumber.Uniform(0.0, 2 * M_PI); - dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, static_cast(-M_PI)); - dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; - } - if (jetWasInCone) { - randomConePt = 0.0; - for (auto const& track : tracks) { - if (jetderiveddatautilities::selectTrack(track, trackSelection)) { - float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-M_PI)); - float dEta = track.eta() - randomConeEta; - if (TMath::Sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { - randomConePt += track.pt(); - } - } - } - } + registry.fill(HIST("h2_occupancy_ntracksall_presel"), occupancy, nTracksAll); + registry.fill(HIST("h2_occupancy_ntrackssel_presel"), occupancy, nTracksAllAcceptanceAndSelected); + registry.fill(HIST("h2_occupancy_ntracksselptetacuts_presel"), occupancy, nTracksInAcceptanceAndSelected); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + registry.fill(HIST("h2_occupancy_ntracksall_postsel"), occupancy, nTracksAll); + registry.fill(HIST("h2_occupancy_ntrackssel_postsel"), occupancy, nTracksAllAcceptanceAndSelected); + registry.fill(HIST("h2_occupancy_ntracksselptetacuts_postsel"), occupancy, nTracksInAcceptanceAndSelected); } - - registry.fill(HIST("h2_centrality_rhorandomconewithoutleadingjet"), collision.centrality(), randomConePt - M_PI * randomConeR * randomConeR * collision.rho()); } - PROCESS_SWITCH(JetFinderQATask, processRandomCone, "QA for random cone estimation of background fluctuations", false); + PROCESS_SWITCH(JetFinderQATask, processOccupancyQA, "occupancy QA on jet derived data", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"jet-finder-charged-qa"})}; } diff --git a/PWGJE/Tasks/jetFinderV0QA.cxx b/PWGJE/Tasks/jetFinderV0QA.cxx new file mode 100644 index 00000000000..9c681fa3bce --- /dev/null +++ b/PWGJE/Tasks/jetFinderV0QA.cxx @@ -0,0 +1,442 @@ +// 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. + +// jet finder v0 QA task +// +/// \author Nima Zardoshti + +#include +#include +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "PWGJE/DataModel/Jet.h" + +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetHFUtilities.h" +#include "PWGJE/Core/JetV0Utilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" + +#include "EventFiltering/filterTables.h" + +using namespace o2; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; + +template +struct JetFinderV0QATask { + HistogramRegistry registry; + + Configurable selectedJetsRadius{"selectedJetsRadius", 0.4, "resolution parameter for histograms without radius"}; + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + Configurable centralityMin{"centralityMin", -999.0, "minimum centrality"}; + Configurable centralityMax{"centralityMax", 999.0, "maximum centrality"}; + Configurable> jetRadii{"jetRadii", std::vector{0.4}, "jet resolution parameters"}; + Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum eta acceptance for tracks"}; + Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum eta acceptance for tracks"}; + Configurable trackPtMin{"trackPtMin", 0.15, "minimum pT acceptance for tracks"}; + Configurable trackPtMax{"trackPtMax", 100.0, "maximum pT acceptance for tracks"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + Configurable jetEtaMin{"jetEtaMin", -99.0, "minimum jet pseudorapidity"}; + Configurable jetEtaMax{"jetEtaMax", 99.0, "maximum jet pseudorapidity"}; + Configurable jetAreaFractionMin{"jetAreaFractionMin", -99.0, "used to make a cut on the jet areas"}; + Configurable leadingConstituentPtMin{"leadingConstituentPtMin", -99.0, "minimum pT selection on jet constituent"}; + Configurable pTHatMaxMCD{"pTHatMaxMCD", 999.0, "maximum fraction of hard scattering for jet acceptance in detector MC"}; + Configurable pTHatMaxMCP{"pTHatMaxMCP", 999.0, "maximum fraction of hard scattering for jet acceptance in particle MC"}; + Configurable pTHatExponent{"pTHatExponent", 6.0, "exponent of the event weight for the calculation of pTHat"}; + + std::vector eventSelectionBits; + int trackSelection = -1; + + void init(o2::framework::InitContext&) + { + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + + auto jetRadiiBins = (std::vector)jetRadii; + if (jetRadiiBins.size() > 1) { + jetRadiiBins.push_back(jetRadiiBins[jetRadiiBins.size() - 1] + (TMath::Abs(jetRadiiBins[jetRadiiBins.size() - 1] - jetRadiiBins[jetRadiiBins.size() - 2]))); + } else { + jetRadiiBins.push_back(jetRadiiBins[jetRadiiBins.size() - 1] + 0.1); + } + + if (doprocessJetsData || doprocessJetsMCD || doprocessJetsMCDWeighted) { + registry.add("h_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); + registry.add("h_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_jet_phi", "jet #varphi;#varphi_{jet};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); + registry.add("h_jet_ntracks", "jet N tracks;N_{jet tracks};entries", {HistType::kTH1F, {{200, -0.5, 199.5}}}); + registry.add("h2_centrality_jet_pt", "centrality vs #it{p}_{T,jet}; centrality; #it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, 0., 200.}}}); + registry.add("h2_centrality_jet_eta", "centrality vs #eta_{jet}; centrality; #eta_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, -1.0, 1.0}}}); + registry.add("h2_centrality_jet_phi", "centrality vs #varphi_{jet}; centrality; #varphi_{jet}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {160, -1.0, 7.}}}); + registry.add("h2_centrality_jet_ntracks", "centrality vs N_{jet tracks}; centrality; N_{jet tracks}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, -0.5, 199.5}}}); + registry.add("h3_jet_r_jet_pt_centrality", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});centrality", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {1200, -10.0, 110.0}}}); + registry.add("h3_jet_r_jet_pt_jet_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_jet_pt_jet_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_eta_jet_phi", "#it{R}_{jet};#eta_{jet};#varphi_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_jet_ntracks", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, -0.5, 199.5}}}); + registry.add("h3_jet_r_jet_pt_jet_area", "#it{R}_{jet}; #it{p}_{T,jet} (GeV/#it{c}); #it{area}_{jet}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {300, 0., 3.}}}); + registry.add("h3_jet_r_jet_pt_track_pt", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,jet tracks} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_track_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_jet_pt_track_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{jet tracks}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_candidate_pt", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); + registry.add("h3_jet_r_jet_pt_candidate_eta", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#eta_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_jet_pt_candidate_phi", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});#varphi_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_jet_pt_candidate_y", "#it{R}_{jet};#it{p}_{T,jet} (GeV/#it{c});y_{candidate}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); + registry.add("h3_candidate_invmass_jet_pt_candidate_pt", ";#it{m}_{inv, candidate} (GeV/#it{c}^{2}); #it{p}_{T,jet} (GeV/#it{c}) ;#it{p}_{T,candidate} (GeV/#it{c})", {HistType::kTH3F, {{500, 0.0, 5.0}, {200, 0.0, 200.0}, {200, 0.0, 200.0}}}); + } + + if (doprocessJetsMCP || doprocessJetsMCPWeighted) { + registry.add("h_jet_pt_part", "jet pT;#it{p}_{T,jet}^{part}(GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); + registry.add("h_jet_eta_part", "jet #eta;#eta_{jet}^{part};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h_jet_phi_part", "jet #varphi;#varphi_{jet}^{part};entries", {HistType::kTH1F, {{160, -1.0, 7.}}}); + registry.add("h_jet_ntracks_part", "jet N tracks;N_{jet tracks}^{part};entries", {HistType::kTH1F, {{200, -0.5, 199.5}}}); + registry.add("h3_jet_r_part_jet_pt_part_jet_eta_part", ";#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#eta_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_part_jet_pt_part_jet_phi_part", ";#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#varphi_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_part_jet_eta_part_jet_phi_part", ";#it{R}_{jet}^{part};#eta_{jet}^{part};#varphi_{jet}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {100, -1.0, 1.0}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_part_jet_pt_part_jet_ntracks_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});N_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, -0.5, 199.5}}}); + registry.add("h3_jet_r_part_jet_pt_part_track_pt_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#it{p}_{T,jet tracks}^{part} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); + registry.add("h3_jet_r_part_jet_pt_part_track_eta_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#eta_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_part_jet_pt_part_track_phi_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#varphi_{jet tracks}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_part_jet_pt_part_candidate_pt_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#it{p}_{T,candidate}^{part} (GeV/#it{c})", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {200, 0., 200.}}}); + registry.add("h3_jet_r_part_jet_pt_part_candidate_eta_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#eta_{candidate}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); + registry.add("h3_jet_r_part_jet_pt_part_candidate_phi_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});#varphi{candidate}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {160, -1.0, 7.}}}); + registry.add("h3_jet_r_part_jet_pt_part_candidate_y_part", "#it{R}_{jet}^{part};#it{p}_{T,jet}^{part} (GeV/#it{c});y_{candidate}^{part}", {HistType::kTH3F, {{jetRadiiBins, ""}, {200, 0., 200.}, {100, -1.0, 1.0}}}); + } + + if (doprocessTracks || doprocessTracksWeighted) { + registry.add("h_collisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + registry.add("h2_centrality_collisions", "centrality vs collisions; centrality; collisions", {HistType::kTH2F, {{1200, -10.0, 110.0}, {4, 0.0, 4.0}}}); + registry.add("h2_centrality_track_pt", "centrality vs track pT; centrality; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{1200, -10.0, 110.0}, {200, 0., 200.}}}); + registry.add("h2_centrality_track_eta", "centrality vs track #eta; centrality; #eta_{track}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, -1.0, 1.0}}}); + registry.add("h2_centrality_track_phi", "centrality vs track #varphi; centrality; #varphi_{track}", {HistType::kTH2F, {{1200, -10.0, 110.0}, {160, -1.0, 7.}}}); + registry.add("h2_centrality_track_energy", "centrality vs track energy; centrality; Energy GeV", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, 0.0, 100.0}}}); + if (doprocessTracksWeighted) { + registry.add("h_collisions_weighted", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + } + } + if (doprocessMCCollisionsWeighted) { + AxisSpec weightAxis = {{VARIABLE_WIDTH, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1.0, 10.0}, "weights"}; + registry.add("h_collision_eventweight_part", "event weight;event weight;entries", {HistType::kTH1F, {weightAxis}}); + } + + if (doprocessCandidates) { + registry.add("h_candidate_invmass", ";#it{m}_{inv, candidate} (GeV/#it{c}^{2});counts", {HistType::kTH1F, {{500, 0.0, 5.0}}}); + registry.add("h_candidate_pt", ";#it{p}_{T,candidate} (GeV/#it{c});counts", {HistType::kTH1F, {{200, 0.0, 200.0}}}); + registry.add("h_candidate_y", ";y_{candidate};counts", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + registry.add("h2_centrality_ncandidates", "centrality vs N_{candidates};centrality;N_{candidates};", {HistType::kTH2F, {{1200, -10.0, 110.0}, {100, 0.0, 100.0}}}); + } + } + + using JetTableDataJoined = soa::Join; + using JetTableDataMatchedJoined = soa::Join; + + using JetTableMCDJoined = soa::Join; + using JetTableMCDWeightedJoined = soa::Join; + using JetTableMCDMatchedJoined = soa::Join; + using JetTableMCDMatchedWeightedJoined = soa::Join; + + using JetTableMCPJoined = soa::Join; + using JetTableMCPWeightedJoined = soa::Join; + using JetTableMCPMatchedJoined = soa::Join; + using JetTableMCPMatchedWeightedJoined = soa::Join; + + Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); + Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax); + + template + bool isAcceptedJet(V const& jet) + { + + if (jetAreaFractionMin > -98.0) { + if (jet.area() < jetAreaFractionMin * M_PI * (jet.r() / 100.0) * (jet.r() / 100.0)) { + return false; + } + } + if (leadingConstituentPtMin > -98.0) { + bool isMinleadingConstituent = false; + for (auto& constituent : jet.template tracks_as()) { + if (constituent.pt() >= leadingConstituentPtMin) { + isMinleadingConstituent = true; + break; + } + } + for (auto& hfconstituent : jet.template candidates_as()) { + if (hfconstituent.pt() >= leadingConstituentPtMin) { + isMinleadingConstituent = true; + break; + } + } + if (!isMinleadingConstituent) { + return false; + } + } + return true; + } + + template + void fillHistograms(T const& jet, float centrality, float weight = 1.0) + { + + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (jet.pt() > pTHatMaxMCD * pTHat) { + return; + } + + if (jet.r() == round(selectedJetsRadius * 100.0f)) { + registry.fill(HIST("h_jet_pt"), jet.pt(), weight); + registry.fill(HIST("h_jet_eta"), jet.eta(), weight); + registry.fill(HIST("h_jet_phi"), jet.phi(), weight); + registry.fill(HIST("h_jet_ntracks"), jet.tracksIds().size() + jet.candidatesIds().size(), weight); + registry.fill(HIST("h2_centrality_jet_pt"), centrality, jet.pt(), weight); + registry.fill(HIST("h2_centrality_jet_eta"), centrality, jet.eta(), weight); + registry.fill(HIST("h2_centrality_jet_phi"), centrality, jet.phi(), weight); + registry.fill(HIST("h2_centrality_jet_ntracks"), centrality, jet.tracksIds().size() + jet.candidatesIds().size(), weight); + } + + registry.fill(HIST("h3_jet_r_jet_pt_centrality"), jet.r() / 100.0, jet.pt(), centrality, weight); + registry.fill(HIST("h3_jet_r_jet_pt_jet_eta"), jet.r() / 100.0, jet.pt(), jet.eta(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_jet_phi"), jet.r() / 100.0, jet.pt(), jet.phi(), weight); + registry.fill(HIST("h3_jet_r_jet_eta_jet_phi"), jet.r() / 100.0, jet.eta(), jet.phi(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_jet_ntracks"), jet.r() / 100.0, jet.pt(), jet.tracksIds().size() + jet.candidatesIds().size(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_jet_area"), jet.r() / 100.0, jet.pt(), jet.area(), weight); + + for (auto& constituent : jet.template tracks_as()) { + + registry.fill(HIST("h3_jet_r_jet_pt_track_pt"), jet.r() / 100.0, jet.pt(), constituent.pt(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_track_eta"), jet.r() / 100.0, jet.pt(), constituent.eta(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_track_phi"), jet.r() / 100.0, jet.pt(), constituent.phi(), weight); + } + + for (auto& v0candidate : jet.template candidates_as>()) { + + registry.fill(HIST("h3_jet_r_jet_pt_track_pt"), jet.r() / 100.0, jet.pt(), v0candidate.pt(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_track_eta"), jet.r() / 100.0, jet.pt(), v0candidate.eta(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_track_phi"), jet.r() / 100.0, jet.pt(), v0candidate.phi(), weight); + + registry.fill(HIST("h3_jet_r_jet_pt_candidate_pt"), jet.r() / 100.0, jet.pt(), v0candidate.pt(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_eta"), jet.r() / 100.0, jet.pt(), v0candidate.eta(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_phi"), jet.r() / 100.0, jet.pt(), v0candidate.phi(), weight); + registry.fill(HIST("h3_jet_r_jet_pt_candidate_y"), jet.r() / 100.0, jet.pt(), v0candidate.y(), weight); + + if (jet.r() == round(selectedJetsRadius * 100.0f)) { + registry.fill(HIST("h3_candidate_invmass_jet_pt_candidate_pt"), v0candidate.mLambda(), jet.pt(), v0candidate.pt(), weight); + registry.fill(HIST("h3_candidate_invmass_jet_pt_candidate_pt"), v0candidate.mAntiLambda(), jet.pt(), v0candidate.pt(), weight); + registry.fill(HIST("h3_candidate_invmass_jet_pt_candidate_pt"), v0candidate.mK0Short(), jet.pt(), v0candidate.pt(), weight); + } + } + } + + template + void fillMCPHistograms(T const& jet, float weight = 1.0) + { + + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (jet.pt() > pTHatMaxMCP * pTHat) { + return; + } + + if (jet.r() == round(selectedJetsRadius * 100.0f)) { + registry.fill(HIST("h_jet_pt_part"), jet.pt(), weight); + registry.fill(HIST("h_jet_eta_part"), jet.eta(), weight); + registry.fill(HIST("h_jet_phi_part"), jet.phi(), weight); + registry.fill(HIST("h_jet_ntracks_part"), jet.tracksIds().size() + jet.candidatesIds().size(), weight); + } + + registry.fill(HIST("h3_jet_r_part_jet_pt_part_jet_eta_part"), jet.r() / 100.0, jet.pt(), jet.eta(), weight); + registry.fill(HIST("h3_jet_r_part_jet_pt_part_jet_phi_part"), jet.r() / 100.0, jet.pt(), jet.phi(), weight); + registry.fill(HIST("h3_jet_r_part_jet_eta_part_jet_phi_part"), jet.r() / 100.0, jet.eta(), jet.phi(), weight); + registry.fill(HIST("h3_jet_r_part_jet_pt_part_jet_ntracks_part"), jet.r() / 100.0, jet.pt(), jet.tracksIds().size() + jet.candidatesIds().size(), weight); + + for (auto& constituent : jet.template tracks_as>()) { + + registry.fill(HIST("h3_jet_r_part_jet_pt_part_track_pt_part"), jet.r() / 100.0, jet.pt(), constituent.pt(), weight); + registry.fill(HIST("h3_jet_r_part_jet_pt_part_track_eta_part"), jet.r() / 100.0, jet.pt(), constituent.eta(), weight); + registry.fill(HIST("h3_jet_r_part_jet_pt_part_track_phi_part"), jet.r() / 100.0, jet.pt(), constituent.phi(), weight); + } + + for (auto& v0candidate : jet.template candidates_as>()) { + + registry.fill(HIST("h3_jet_r_part_jet_pt_part_track_pt_part"), jet.r() / 100.0, jet.pt(), v0candidate.pt(), weight); + registry.fill(HIST("h3_jet_r_part_jet_pt_part_track_eta_part"), jet.r() / 100.0, jet.pt(), v0candidate.eta(), weight); + registry.fill(HIST("h3_jet_r_part_jet_pt_part_track_phi_part"), jet.r() / 100.0, jet.pt(), v0candidate.phi(), weight); + + registry.fill(HIST("h3_jet_r_part_jet_pt_part_candidate_pt_part"), jet.r() / 100.0, jet.pt(), v0candidate.pt(), weight); + registry.fill(HIST("h3_jet_r_part_jet_pt_part_candidate_eta_part"), jet.r() / 100.0, jet.pt(), v0candidate.eta(), weight); + registry.fill(HIST("h3_jet_r_part_jet_pt_part_candidate_phi_part"), jet.r() / 100.0, jet.pt(), v0candidate.phi(), weight); + registry.fill(HIST("h3_jet_r_part_jet_pt_part_candidate_y_part"), jet.r() / 100.0, jet.pt(), v0candidate.y(), weight); + } + } + + template + void fillTrackHistograms(T const& collision, U const& tracks, float weight = 1.0) + { + for (auto const& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + registry.fill(HIST("h2_centrality_track_pt"), collision.centrality(), track.pt(), weight); + registry.fill(HIST("h2_centrality_track_eta"), collision.centrality(), track.eta(), weight); + registry.fill(HIST("h2_centrality_track_phi"), collision.centrality(), track.phi(), weight); + registry.fill(HIST("h2_centrality_track_energy"), collision.centrality(), track.energy(), weight); + } + } + + void processDummy(aod::JetCollisions const&) + { + } + PROCESS_SWITCH(JetFinderV0QATask, processDummy, "dummy task", true); + + void processJetsData(soa::Filtered::iterator const& collision, JetTableDataJoined const& jets, CandidateTableData const&, aod::JetTracks const&) + { + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillHistograms(jet, collision.centrality()); + } + } + PROCESS_SWITCH(JetFinderV0QATask, processJetsData, "jet finder HF QA data", false); + + void processJetsMCD(soa::Filtered::iterator const& collision, JetTableMCDJoined const& jets, CandidateTableMCD const&, aod::JetTracks const&) + { + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillHistograms(jet, collision.centrality()); + } + } + PROCESS_SWITCH(JetFinderV0QATask, processJetsMCD, "jet finder HF QA mcd", false); + + void processJetsMCDWeighted(soa::Filtered::iterator const& collision, JetTableMCDWeightedJoined const& jets, CandidateTableMCD const&, aod::JetTracks const&) + { + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillHistograms(jet, collision.centrality(), jet.eventWeight()); + } + } + PROCESS_SWITCH(JetFinderV0QATask, processJetsMCDWeighted, "jet finder HF QA mcd on weighted events", false); + + void processJetsMCP(typename JetTableMCPJoined::iterator const& jet, aod::JetParticles const&, CandidateTableMCP const&) + { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + return; + } + if (!isAcceptedJet(jet)) { + return; + } + fillMCPHistograms(jet); + } + PROCESS_SWITCH(JetFinderV0QATask, processJetsMCP, "jet finder HF QA mcp", false); + + void processJetsMCPWeighted(typename JetTableMCPWeightedJoined::iterator const& jet, aod::JetParticles const&, CandidateTableMCP const&) + { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + return; + } + if (!isAcceptedJet(jet)) { + return; + } + fillMCPHistograms(jet, jet.eventWeight()); + } + PROCESS_SWITCH(JetFinderV0QATask, processJetsMCPWeighted, "jet finder HF QA mcp on weighted events", false); + + void processMCCollisionsWeighted(aod::JetMcCollision const& collision) + { + registry.fill(HIST("h_collision_eventweight_part"), collision.weight()); + } + PROCESS_SWITCH(JetFinderV0QATask, processMCCollisionsWeighted, "collision QA for weighted events", false); + + void processTracks(soa::Filtered::iterator const& collision, + soa::Filtered const& tracks) + { + registry.fill(HIST("h_collisions"), 0.5); + registry.fill(HIST("h2_centrality_collisions"), collision.centrality(), 0.5); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + registry.fill(HIST("h_collisions"), 1.5); + registry.fill(HIST("h2_centrality_collisions"), collision.centrality(), 1.5); + fillTrackHistograms(collision, tracks); + } + PROCESS_SWITCH(JetFinderV0QATask, processTracks, "QA for charged tracks", false); + + void processTracksWeighted(soa::Join::iterator const& collision, + aod::JetMcCollisions const&, + soa::Filtered const& tracks) + { + float eventWeight = collision.mcCollision().weight(); + registry.fill(HIST("h_collisions"), 0.5); + registry.fill(HIST("h_collisions_weighted"), 0.5, eventWeight); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + registry.fill(HIST("h_collisions"), 1.5); + registry.fill(HIST("h_collisions_weighted"), 1.5, eventWeight); + fillTrackHistograms(collision, tracks, eventWeight); + } + PROCESS_SWITCH(JetFinderV0QATask, processTracksWeighted, "QA for charged tracks weighted", false); + + void processCandidates(soa::Filtered::iterator const& collision, CandidateTableData const& candidates) + { + + for (auto const& candidate : candidates) { + registry.fill(HIST("h_candidate_invmass"), candidate.mLambda()); + registry.fill(HIST("h_candidate_invmass"), candidate.mAntiLambda()); + registry.fill(HIST("h_candidate_invmass"), candidate.mK0Short()); + registry.fill(HIST("h_candidate_pt"), candidate.pt()); + registry.fill(HIST("h_candidate_y"), candidate.y()); + } + registry.fill(HIST("h2_centrality_ncandidates"), collision.centrality(), candidates.size()); + } + PROCESS_SWITCH(JetFinderV0QATask, processCandidates, "HF candidate QA", false); +}; + +using JetFinderV0QA = JetFinderV0QATask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-finder-charged-v0-qa"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetFragmentation.cxx b/PWGJE/Tasks/jetFragmentation.cxx new file mode 100644 index 00000000000..c181254819f --- /dev/null +++ b/PWGJE/Tasks/jetFragmentation.cxx @@ -0,0 +1,2865 @@ +// 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 jetFragmentation.cxx +/// \brief Task for jet fragmentation into V0s +/// +/// \author Gijs van Weelden + +#include +#include +#include "TH1F.h" +#include "TTree.h" + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/RunningWorkflowInfo.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" + +#include "CommonConstants/PhysicsConstants.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGLF/DataModel/V0SelectorTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// Charged jets +using MyTracks = soa::Join; +using ChargedJetsWithConstituents = soa::Join; + +using MCDJets = aod::ChargedMCDetectorLevelJets; +using MCDJetsWithConstituents = soa::Join; +using MatchedMCDJets = soa::Join; +using MatchedMCDJetsWithConstituents = soa::Join; + +using MCPJets = aod::ChargedMCParticleLevelJets; +using MatchedMCPJets = soa::Join; +using MCPJetsWithConstituents = soa::Join; +using MatchedMCPJetsWithConstituents = soa::Join; + +// V0 jets +using DataV0JetsWithConstituents = soa::Join; +using CandidatesV0DataWithFlags = soa::Join; + +using CandidatesV0MCDWithLabelsAndFlags = soa::Join; +using MCDV0Jets = aod::V0ChargedMCDetectorLevelJets; +using MCDV0JetsWithConstituents = soa::Join; +using MatchedMCDV0Jets = soa::Join; +using MatchedMCDV0JetsWithConstituents = soa::Join; + +using MCPV0Jets = aod::V0ChargedMCParticleLevelJets; +using MCPV0JetsWithConstituents = soa::Join; +using MatchedMCPV0Jets = soa::Join; +using MatchedMCPV0JetsWithConstituents = soa::Join; + +struct JetFragmentation { + HistogramRegistry registry{"registry"}; // CallSumw2 = false? + + Configurable evSel{"evSel", "sel8WithoutTimeFrameBorderCut", "choose event selection"}; + Configurable trackSel{"trackSel", "globalTracks", "choose track selection"}; + Configurable nV0Classes{"nV0Classes", 2, "Must be 2 or 4! Number of V0 signal/bkg classes"}; + Configurable doCorrectionWithTracks{"doCorrectionWithTracks", false, "add tracks during background subtraction"}; + + Configurable vertexZCut{"vertexZCut", 10.f, "vertex z cut"}; + Configurable v0EtaMin{"v0EtaMin", -0.75, "minimum data V0 eta"}; + Configurable v0EtaMax{"v0EtaMax", 0.75, "maximum data V0 eta"}; + + // Binning + ConfigurableAxis binJetPt{"binJetPt", {40, 0.f, 200.f}, ""}; + ConfigurableAxis binEta{"binEta", {20, -1.f, 1.f}, ""}; + ConfigurableAxis binPhi{"binPhi", {18 * 8, 0.f, constants::math::TwoPI}, ""}; + ConfigurableAxis binZ{"binZ", {40, 0.0001f, 1.0001f}, ""}; + ConfigurableAxis binXi{"binXi", {50, 0.f, 10.f}, ""}; + ConfigurableAxis binTheta{"binTheta", {40, -0.05f, 0.395f}, ""}; + ConfigurableAxis binJetR{"binJetR", {6, 0.05f, 0.65f}, ""}; + ConfigurableAxis binTrackPt{"binTrackPt", {200, 0.f, 100.f}, ""}; + ConfigurableAxis binVtxZ{"binVtxZ", {200, -20, 20}, ""}; + + ConfigurableAxis binPtTrackDiff{"binPtTrackDiff", {121, -20.5f, 100.5f}, ""}; + ConfigurableAxis binPtDiff{"binPtDiff", {600, -299.5f, 300.5f}, ""}; + ConfigurableAxis binEtaDiff{"binEtaDiff", {40, -0.195f, 0.205f}, ""}; + ConfigurableAxis binPhiDiff{"binPhiDiff", {40, -0.195f, 0.205f}, ""}; + ConfigurableAxis binZDiff{"binZDiff", {80, -1.05f, 0.95f}, ""}; + ConfigurableAxis binXiDiff{"binXiDiff", {100, -9.5f, 10.5f}, ""}; + ConfigurableAxis binThetaDiff{"binThetaDiff", {80, -0.35f, 0.45f}, ""}; + ConfigurableAxis binPtRatio{"binPtRatio", {50, -0.5f, 9.5f}, ""}; // Ratio of pt, eta, phi + ConfigurableAxis binMatchDist{"binMatchDist", {50, 0.f, 0.5f}, ""}; // Distance between matched jets + + ConfigurableAxis binPtRelDiff{"binPtRelDiff", {100, -9.5f, 10.5f}, ""}; + ConfigurableAxis binZRelDiff{"binZRelDiff", {100, -9.5f, 10.5f}, ""}; + + ConfigurableAxis binCount{"binCount", {1, .5f, 1.5f}, ""}; + ConfigurableAxis jetCount{"jetCount", {20, -.5f, 19.5f}, ""}; + ConfigurableAxis trackCount{"trackCount", {1000, -.5f, 999.5f}, ""}; + ConfigurableAxis v0Count{"v0Count", {50, -.5f, 49.5f}, ""}; + ConfigurableAxis v0Weight{"v0Weight", {50, 0.f, 10.0f}, ""}; + + ConfigurableAxis binV0Pt{"binV0Pt", {120, 0.0f, 60.0f}, ""}; + ConfigurableAxis binV0Eta{"binV0Eta", {20, -1.f, 1.f}, ""}; + ConfigurableAxis binV0Phi{"binV0Phi", {18 * 8, 0.f, constants::math::TwoPI}, ""}; + ConfigurableAxis binV0Ctau{"binV0Ctau", {200, 0.0f, 40.0f}, ""}; + ConfigurableAxis binV0Radius{"binV0Radius", {100, 0.0f, 100.0f}, ""}; + ConfigurableAxis binV0CosPA{"binV0CosPA", {100, 0.95f, 1.0f}, ""}; + ConfigurableAxis binV0DCA{"binV0DCA", {200, 0.0f, 1.0f}, ""}; + ConfigurableAxis binV0DCAp{"binV0DCAp", {100, -10.0f, 10.0f}, ""}; + ConfigurableAxis binV0DCAn{"binV0DCAn", {100, -10.0f, 10.0f}, ""}; + ConfigurableAxis binV0DCAd{"binV0DCAd", {100, 0.0f, 10.0f}, ""}; + + ConfigurableAxis binK0SMass{"binK0SMass", {400, 0.400f, 0.600f}, "Inv. Mass (GeV/c^{2})"}; + ConfigurableAxis binK0SMassWide{"binK0SMassWide", {400, 0.400f, 0.800f}, "Inv. Mass (GeV/c^{2})"}; // Wider version for high pt + ConfigurableAxis binLambdaMass{"binLambdaMass", {200, 1.015f, 1.215f}, "Inv. Mass (GeV/c^{2})"}; + ConfigurableAxis binLambdaMassDiff{"binLambdaMassDiff", {200, -0.199f, 0.201f}, "M(#Lambda) - M(#bar{#Lambda})"}; + ConfigurableAxis binLambdaMassRatio{"binLambdaMassRatio", {50, -0.05f, 4.95f}, "M(#bar{#Lambda}) / M(#Lambda)"}; + ConfigurableAxis binLambdaMassRelDiff{"binLambdaMassRelDiff", {200, -0.995f, 1.005f}, "(M(#Lambda) - M(#bar{#Lambda})) / M(#Lambda)"}; + + // Binning for cut variation study + ConfigurableAxis binV0RadiusCut{"binV0RadiusCut", {4, 1.0f, 1.4f}, "R"}; + ConfigurableAxis binV0CtauCut{"binV0CtauCut", {3, 15.0f, 30.0f}, "c#tau"}; + ConfigurableAxis binV0CosPACut{"binV0CosPACut", {4, 0.991f, 0.999f}, "cosPA"}; + ConfigurableAxis binV0DCApCut{"binV0DCApCut", {2, 0.05f, 0.15f}, "DCA pos"}; + ConfigurableAxis binV0DCAnCut{"binV0DCAnCut", {2, 0.05f, 0.15f}, "DCA neg"}; + ConfigurableAxis binV0DCAdCut{"binV0DCAdCut", {2, 0.5f, 1.5f}, "DCA daughters"}; + ConfigurableAxis binV0PtCut{"binV0PtCut", {60, 0.0f, 60.0f}, "p_{T, V0}"}; + ConfigurableAxis binK0SMassCut{"binK0SMassCut", {100, 0.4f, 0.6f}, "inv. mass, K0S hypothesis"}; + ConfigurableAxis binLambdaMassCut{"binLambdaMassCut", {100, 1.07f, 1.21f}, "inv. mass, Lambda hypothesis"}; + ConfigurableAxis binAntiLambdaMassCut{"binAntiLambdaMassCut", {100, 1.07f, 1.21f}, "inv. mass, AntiLambda hypothesis"}; + + Filter jetCollisionFilter = nabs(aod::jcollision::posZ) < vertexZCut; + + std::vector eventSelectionBits; + int trackSelection = -1; + + void init(InitContext&) + { + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(evSel)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSel)); + + // Axes + AxisSpec jetPtAxis = {binJetPt, "#it{p}_{T}^{ jet}"}; // Data + AxisSpec etaAxis = {binEta, "#eta"}; + AxisSpec phiAxis = {binPhi, "#phi"}; + AxisSpec zAxis = {binZ, "#it{z}"}; + AxisSpec xiAxis = {binXi, "#xi"}; + AxisSpec thetaAxis = {binTheta, "#theta"}; + + AxisSpec detJetPtAxis = {binJetPt, "#it{p}_{T}^{ jet, det}"}; // MC detector level + AxisSpec detEtaAxis = {binEta, "#eta^{ jet, det}"}; + AxisSpec detPhiAxis = {binPhi, "#phi^{ jet, det}"}; + AxisSpec detZAxis = {binZ, "#it{z}^{ det}"}; + AxisSpec detXiAxis = {binXi, "#xi^{ det}"}; + AxisSpec detThetaAxis = {binTheta, "#theta^{ det}"}; + + AxisSpec partJetPtAxis = {binJetPt, "#it{p}_{T}^{ jet, part}"}; // MC particle level + AxisSpec partEtaAxis = {binEta, "#eta^{ jet, part}"}; + AxisSpec partPhiAxis = {binPhi, "#phi^{ jet, part}"}; + AxisSpec partZAxis = {binZ, "#it{z}^{ part}"}; + AxisSpec partXiAxis = {binXi, "#xi^{ part}"}; + AxisSpec partThetaAxis = {binTheta, "#theta^{ part}"}; + + AxisSpec trackPtAxis = {binTrackPt, "#it{p}_{T}^{tr}"}; + AxisSpec ptTrackDiffAxis = {binPtTrackDiff, "#it{p}_{T}^{track} - #it{p}_{T}^{particle}"}; + AxisSpec ptDiffAxis = {binPtDiff, "#it{p}_{T}^{jet, det} - #it{p}_{T}^{jet, part}"}; + AxisSpec etaDiffAxis = {binEtaDiff, "#eta^{jet, det} - #eta^{jet, part}"}; + AxisSpec phiDiffAxis = {binPhiDiff, "#varphi^{jet, det} - #varphi^{jet, part}"}; + AxisSpec zDiffAxis = {binZDiff, "#it{z}^{det} - #it{z}^{part}"}; + AxisSpec xiDiffAxis = {binXiDiff, "#xi^{det} - #xi^{part}"}; + AxisSpec thetaDiffAxis = {binThetaDiff, "#theta^{det} - #theta^{part}"}; + AxisSpec ptRatioAxis = {binPtRatio, ""}; + AxisSpec vtxZAxis = {binVtxZ, "Collision vertex z (cm)"}; + AxisSpec matchDistAxis = {binMatchDist, "#Delta"}; + + AxisSpec ptJetRelDiffAxis = {binPtRelDiff, "(#it{p}_{T}^{jet, det} - #it{p}_{T}^{jet, part})/#it{p}_{T, jet}^{part}"}; + AxisSpec ptTrackRelDiffAxis = {binPtRelDiff, "(#it{p}_{T}^{track, det} - #it{p}_{T}^{track, part})/#it{p}_{T, track}^{part}"}; + AxisSpec zRelDiffAxis = {binZRelDiff, "(#it{p}_{T}^{jet, det} - #it{p}_{T}^{jet, part})/#it{p}_{T, jet}^{part}"}; + + AxisSpec v0PtAxis = {binV0Pt, "#it{p}_{T}^{V0}"}; + AxisSpec v0PtRatioAxis = {binPtRatio, "#it{p}_{T}^{V0, det}/#it{p}_{T, V0}^{part}"}; + AxisSpec v0PtRelDiffAxis = {binPtRelDiff, "(#it{p}_{T}^{V0, det} - #it{p}_{T}^{V0, part})/#it{p}_{T, V0}^{part}"}; + AxisSpec v0EtaAxis = {binV0Eta, "#eta^{V0}"}; + AxisSpec v0PhiAxis = {binV0Phi, "#varphi^{V0}"}; + AxisSpec v0detPtAxis = {binV0Pt, "#it{p}_{T}^{V0, det}"}; + AxisSpec v0partPtAxis = {binV0Pt, "#it{p}_{T}^{V0, part}"}; + AxisSpec v0CtauAxis = {binV0Ctau, "c#tau (cm)"}; + AxisSpec v0RadiusAxis = {binV0Radius, "R (cm)"}; + AxisSpec v0CosPAAxis = {binV0CosPA, "cos(PA)"}; + AxisSpec v0DCApAxis = {binV0DCAp, "DCA pos (cm)"}; + AxisSpec v0DCAnAxis = {binV0DCAn, "DCA neg (cm)"}; + AxisSpec v0DCAdAxis = {binV0DCAd, "DCA daughters (cm^{2})"}; + + AxisSpec k0SMassAxis = {binK0SMass, "Inv. mass (GeV/#it{c}^{2})"}; + AxisSpec k0SWideAxis = {binK0SMassWide, "Inv. mass (GeV/#it{c}^{2})"}; + AxisSpec lambdaMassAxis = {binLambdaMass, "Inv. mass (GeV/#it{c}^{2})"}; + AxisSpec lambdaMassDiffAxis = {binLambdaMassDiff, "M(#Lambda) - M(#bar{#Lambda})"}; + AxisSpec lambdaMassRatioAxis = {binLambdaMassRatio, "M(#bar{#Lambda}) / M(#Lambda)"}; + AxisSpec lambdaMassRelDiffAxis = {binLambdaMassRelDiff, "(M(#Lambda) - M(#bar{#Lambda})) / M(#Lambda)"}; + + // Cut variation study + AxisSpec rCutAxis = {binV0RadiusCut, "R"}; + AxisSpec ctauCutAxis = {binV0CtauCut, "c#tau (K0S)"}; + AxisSpec cosPACutAxis = {binV0CosPACut, "cosPA"}; + AxisSpec dcapCutAxis = {binV0DCApCut, "DCA pos (cm)"}; + AxisSpec dcanCutAxis = {binV0DCAnCut, "DCA neg (cm)"}; + AxisSpec dcadCutAxis = {binV0DCAdCut, "DCA daughters (cm^{2})"}; + AxisSpec ptCutAxis = {binV0PtCut, "p_{T, V0}"}; + AxisSpec k0SMassCutAxis = {binK0SMassCut, "Inv. mass (GeV/#it{c}^{2})"}; + AxisSpec lambdaMassCutAxis = {binLambdaMassCut, "Inv. mass (GeV/#it{c}^{2})"}; + AxisSpec antiLambdaMassCutAxis = {binAntiLambdaMassCut, "Inv. mass (GeV/#it{c}^{2})"}; + + if (doprocessDataV0) { + registry.add("data/V0/nV0sEvent", "nV0sEvent", HistType::kTH1D, {v0Count}); + registry.add("data/V0/nV0sEventAcc", "nV0s per event (accepted)", HistType::kTH1D, {v0Count}); + registry.add("data/V0/nV0sEventAccWeighted", "nV0s per event (accepted, weighted)", HistType::kTH1D, {v0Weight}, true); + + // Inclusive + registry.add("data/V0/V0PtEtaPhi", "V0PtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}); + registry.add("data/V0/V0PtCtau", "V0PtCtau", HistType::kTHnSparseD, {v0PtAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}); + registry.add("data/V0/V0PtMass", "V0PtMass", HistType::kTHnSparseD, {v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}); + registry.add("data/V0/V0PtMassWide", "V0PtMassWide", HistType::kTHnSparseD, {v0PtAxis, k0SWideAxis, lambdaMassAxis, lambdaMassAxis}); + registry.add("data/V0/V0PtLambdaMasses", "V0PtLambdaMasses", HistType::kTHnSparseD, {v0PtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}); + registry.add("data/V0/V0PtRadiusCosPA", "V0PtRadiusCosPA", HistType::kTH3D, {v0PtAxis, v0RadiusAxis, v0CosPAAxis}); + registry.add("data/V0/V0PtDCAposneg", "V0PtDCAposneg", HistType::kTH3D, {v0PtAxis, v0DCApAxis, v0DCAnAxis}); + registry.add("data/V0/V0PtDCAd", "V0PtDCAd", HistType::kTH2D, {v0PtAxis, v0DCAdAxis}); + + // Inclusive Weighted + registry.add("data/V0/V0PtEtaPhiWeighted", "V0PtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("data/V0/V0PtCtauWeighted", "V0PtCtau", HistType::kTHnSparseD, {v0PtAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}, true); + registry.add("data/V0/V0PtMassWeighted", "V0PtMass", HistType::kTHnSparseD, {v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("data/V0/V0PtMassWideWeighted", "V0PtMassWide", HistType::kTHnSparseD, {v0PtAxis, k0SWideAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("data/V0/V0PtLambdaMassesWeighted", "V0PtLambdaMasses", HistType::kTHnSparseD, {v0PtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("data/V0/V0PtRadiusCosPAWeighted", "V0PtRadiusCosPA", HistType::kTH3D, {v0PtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("data/V0/V0PtDCAposnegWeighted", "V0PtDCAposneg", HistType::kTH3D, {v0PtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("data/V0/V0PtDCAdWeighted", "V0PtDCAd", HistType::kTH2D, {v0PtAxis, v0DCAdAxis}, true); + + // K0S + registry.add("data/V0/K0SPtEtaPhi", "K0SPtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}); + registry.add("data/V0/K0SPtRadiusCosPA", "K0SPtRadiusCosPA", HistType::kTH3D, {v0partPtAxis, v0RadiusAxis, v0CosPAAxis}); + registry.add("data/V0/K0SPtDCAposneg", "K0SPtDCAposneg", HistType::kTH3D, {v0partPtAxis, v0DCApAxis, v0DCAnAxis}); + registry.add("data/V0/K0SPtDCAd", "K0SPtDCAd", HistType::kTH2D, {v0partPtAxis, v0DCAdAxis}); + registry.add("data/V0/K0SPtCtauMass", "K0SPtCtauMass", HistType::kTH3D, {v0partPtAxis, v0CtauAxis, k0SMassAxis}); + registry.add("data/V0/K0SPtRadiusMass", "K0SPtRadiusMass", HistType::kTH3D, {v0PtAxis, v0RadiusAxis, k0SMassAxis}); + registry.add("data/V0/K0SPtCosPAMass", "K0SPtCosPAMass", HistType::kTH3D, {v0PtAxis, v0CosPAAxis, k0SMassAxis}); + registry.add("data/V0/K0SPtDCAposMass", "K0SPtDCAposMass", HistType::kTH3D, {v0PtAxis, v0DCApAxis, k0SMassAxis}); + registry.add("data/V0/K0SPtDCAnegMass", "K0SPtDCAnegMass", HistType::kTH3D, {v0PtAxis, v0DCAnAxis, k0SMassAxis}); + registry.add("data/V0/K0SPtDCAdMass", "K0SPtDCAdMass", HistType::kTH3D, {v0PtAxis, v0DCAdAxis, k0SMassAxis}); + + // K0S Weighted + registry.add("data/V0/K0SPtEtaPhiWeighted", "K0SPtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("data/V0/K0SPtRadiusCosPAWeighted", "K0SPtRadiusCosPA", HistType::kTH3D, {v0partPtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("data/V0/K0SPtDCAposnegWeighted", "K0SPtDCAposneg", HistType::kTH3D, {v0partPtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("data/V0/K0SPtDCAdWeighted", "K0SPtDCAd", HistType::kTH2D, {v0partPtAxis, v0DCAdAxis}, true); + registry.add("data/V0/K0SPtCtauMassWeighted", "K0SPtCtauMass", HistType::kTH3D, {v0partPtAxis, v0CtauAxis, k0SMassAxis}, true); + registry.add("data/V0/K0SPtRadiusMassWeighted", "K0SPtRadiusMassWeighted", HistType::kTH3D, {v0PtAxis, v0RadiusAxis, k0SMassAxis}, true); + registry.add("data/V0/K0SPtCosPAMassWeighted", "K0SPtCosPAMassWeighted", HistType::kTH3D, {v0PtAxis, v0CosPAAxis, k0SMassAxis}, true); + registry.add("data/V0/K0SPtDCAposMassWeighted", "K0SPtDCAposMassWeighted", HistType::kTH3D, {v0PtAxis, v0DCApAxis, k0SMassAxis}, true); + registry.add("data/V0/K0SPtDCAnegMassWeighted", "K0SPtDCAnegMassWeighted", HistType::kTH3D, {v0PtAxis, v0DCAnAxis, k0SMassAxis}, true); + registry.add("data/V0/K0SPtDCAdMassWeighted", "K0SPtDCAdMassWeighted", HistType::kTH3D, {v0PtAxis, v0DCAdAxis, k0SMassAxis}, true); + + // Lambda + registry.add("data/V0/LambdaPtEtaPhi", "LambdaPtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}); + registry.add("data/V0/LambdaPtLambdaMasses", "LambdaPtLambdaMasses", HistType::kTHnSparseD, {v0PtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}); + registry.add("data/V0/LambdaPtRadiusCosPA", "LambdaPtRadiusCosPA", HistType::kTH3D, {v0partPtAxis, v0RadiusAxis, v0CosPAAxis}); + registry.add("data/V0/LambdaPtDCAposneg", "LambdaPtDCAposneg", HistType::kTH3D, {v0partPtAxis, v0DCApAxis, v0DCAnAxis}); + registry.add("data/V0/LambdaPtDCAd", "LambdaPtDCAd", HistType::kTH2D, {v0partPtAxis, v0DCAdAxis}); + registry.add("data/V0/LambdaPtCtauMass", "LambdaPtCtauMass", HistType::kTH3D, {v0partPtAxis, v0CtauAxis, lambdaMassAxis}); + registry.add("data/V0/LambdaPtRadiusMass", "LambdaPtRadiusMass", HistType::kTH3D, {v0PtAxis, v0RadiusAxis, lambdaMassAxis}); + registry.add("data/V0/LambdaPtCosPAMass", "LambdaPtCosPAMass", HistType::kTH3D, {v0PtAxis, v0CosPAAxis, lambdaMassAxis}); + registry.add("data/V0/LambdaPtDCAposMass", "LambdaPtDCAposMass", HistType::kTH3D, {v0PtAxis, v0DCApAxis, lambdaMassAxis}); + registry.add("data/V0/LambdaPtDCAnegMass", "LambdaPtDCAnegMass", HistType::kTH3D, {v0PtAxis, v0DCAnAxis, lambdaMassAxis}); + registry.add("data/V0/LambdaPtDCAdMass", "LambdaPtDCAdMass", HistType::kTH3D, {v0PtAxis, v0DCAdAxis, lambdaMassAxis}); + + // Lambda Weighted + registry.add("data/V0/LambdaPtEtaPhiWeighted", "LambdaPtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("data/V0/LambdaPtLambdaMassesWeighted", "LambdaPtLambdaMasses", HistType::kTHnSparseD, {v0PtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("data/V0/LambdaPtRadiusCosPAWeighted", "LambdaPtRadiusCosPA", HistType::kTH3D, {v0partPtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("data/V0/LambdaPtDCAposnegWeighted", "LambdaPtDCAposneg", HistType::kTH3D, {v0partPtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("data/V0/LambdaPtDCAdWeighted", "LambdaPtDCAd", HistType::kTH2D, {v0partPtAxis, v0DCAdAxis}, true); + registry.add("data/V0/LambdaPtCtauMassWeighted", "LambdaPtCtauMass", HistType::kTH3D, {v0partPtAxis, v0CtauAxis, lambdaMassAxis}, true); + registry.add("data/V0/LambdaPtRadiusMassWeighted", "LambdaPtRadiusMassWeighted", HistType::kTH3D, {v0PtAxis, v0RadiusAxis, lambdaMassAxis}, true); + registry.add("data/V0/LambdaPtCosPAMassWeighted", "LambdaPtCosPAMassWeighted", HistType::kTH3D, {v0PtAxis, v0CosPAAxis, lambdaMassAxis}, true); + registry.add("data/V0/LambdaPtDCAposMassWeighted", "LambdaPtDCAposMassWeighted", HistType::kTH3D, {v0PtAxis, v0DCApAxis, lambdaMassAxis}, true); + registry.add("data/V0/LambdaPtDCAnegMassWeighted", "LambdaPtDCAnegMassWeighted", HistType::kTH3D, {v0PtAxis, v0DCAnAxis, lambdaMassAxis}, true); + registry.add("data/V0/LambdaPtDCAdMassWeighted", "LambdaPtDCAdMassWeighted", HistType::kTH3D, {v0PtAxis, v0DCAdAxis, lambdaMassAxis}, true); + + // AntiLambda + registry.add("data/V0/AntiLambdaPtEtaPhi", "AntiLambdaPtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}); + registry.add("data/V0/AntiLambdaPtLambdaMasses", "AntiLambdaPtLambdaMasses", HistType::kTHnSparseD, {v0PtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}); + registry.add("data/V0/AntiLambdaPtRadiusCosPA", "AntiLambdaPtRadiusCosPA", HistType::kTH3D, {v0partPtAxis, v0RadiusAxis, v0CosPAAxis}); + registry.add("data/V0/AntiLambdaPtDCAposneg", "AntiLambdaPtDCAposneg", HistType::kTH3D, {v0partPtAxis, v0DCApAxis, v0DCAnAxis}); + registry.add("data/V0/AntiLambdaPtDCAd", "AntiLambdaPtDCAd", HistType::kTH2D, {v0partPtAxis, v0DCAdAxis}); + registry.add("data/V0/AntiLambdaPtCtauMass", "AntiLambdaPtCtauMass", HistType::kTH3D, {v0partPtAxis, v0CtauAxis, lambdaMassAxis}); + registry.add("data/V0/AntiLambdaPtRadiusMass", "AntiLambdaPtRadiusMass", HistType::kTH3D, {v0PtAxis, v0RadiusAxis, lambdaMassAxis}); + registry.add("data/V0/AntiLambdaPtCosPAMass", "AntiLambdaPtCosPAMass", HistType::kTH3D, {v0PtAxis, v0CosPAAxis, lambdaMassAxis}); + registry.add("data/V0/AntiLambdaPtDCAposMass", "AntiLambdaPtDCAposMass", HistType::kTH3D, {v0PtAxis, v0DCApAxis, lambdaMassAxis}); + registry.add("data/V0/AntiLambdaPtDCAnegMass", "AntiLambdaPtDCAnegMass", HistType::kTH3D, {v0PtAxis, v0DCAnAxis, lambdaMassAxis}); + registry.add("data/V0/AntiLambdaPtDCAdMass", "AntiLambdaPtDCAdMass", HistType::kTH3D, {v0PtAxis, v0DCAdAxis, lambdaMassAxis}); + + // AntiLambda Weighted + registry.add("data/V0/AntiLambdaPtEtaPhiWeighted", "AntiLambdaPtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("data/V0/AntiLambdaPtLambdaMassesWeighted", "AntiLambdaPtLambdaMasses", HistType::kTHnSparseD, {v0PtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("data/V0/AntiLambdaPtRadiusCosPAWeighted", "AntiLambdaPtRadiusCosPA", HistType::kTH3D, {v0partPtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("data/V0/AntiLambdaPtDCAposnegWeighted", "AntiLambdaPtDCAposneg", HistType::kTH3D, {v0partPtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("data/V0/AntiLambdaPtDCAdWeighted", "AntiLambdaPtDCAd", HistType::kTH2D, {v0partPtAxis, v0DCAdAxis}, true); + registry.add("data/V0/AntiLambdaPtCtauMassWeighted", "AntiLambdaPtCtauMass", HistType::kTH3D, {v0partPtAxis, v0CtauAxis, lambdaMassAxis}, true); + registry.add("data/V0/AntiLambdaPtRadiusMassWeighted", "AntiLambdaPtRadiusMassWeighted", HistType::kTH3D, {v0PtAxis, v0RadiusAxis, lambdaMassAxis}, true); + registry.add("data/V0/AntiLambdaPtCosPAMassWeighted", "AntiLambdaPtCosPAMassWeighted", HistType::kTH3D, {v0PtAxis, v0CosPAAxis, lambdaMassAxis}, true); + registry.add("data/V0/AntiLambdaPtDCAposMassWeighted", "AntiLambdaPtDCAposMassWeighted", HistType::kTH3D, {v0PtAxis, v0DCApAxis, lambdaMassAxis}, true); + registry.add("data/V0/AntiLambdaPtDCAnegMassWeighted", "AntiLambdaPtDCAnegMassWeighted", HistType::kTH3D, {v0PtAxis, v0DCAnAxis, lambdaMassAxis}, true); + registry.add("data/V0/AntiLambdaPtDCAdMassWeighted", "AntiLambdaPtDCAdMassWeighted", HistType::kTH3D, {v0PtAxis, v0DCAdAxis, lambdaMassAxis}, true); + + // Cut variation + registry.add("data/V0/V0CutVariation", "V0CutVariation", HistType::kTHnSparseD, {ptCutAxis, k0SMassCutAxis, lambdaMassCutAxis, antiLambdaMassCutAxis, rCutAxis, ctauCutAxis, cosPACutAxis, dcapCutAxis, dcanCutAxis, dcadCutAxis}); + } // doprocessDataV0 + + if (doprocessDataV0JetsFrag) { + registry.add("data/jets/jetPtEtaPhi", "Jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {jetPtAxis, etaAxis, phiAxis}); + + registry.add("data/jets/V0/jetPtV0TrackProj", "jetPtV0TrackProj", HistType::kTH2D, {jetPtAxis, zAxis}); + registry.add("data/jets/V0/jetPtnV0nK0SnLambdanAntiLambda", "jetPtnV0nK0SnLambdanAntiLambda", HistType::kTHnSparseD, {jetPtAxis, v0Count, v0Count, v0Count, v0Count}); + + // Inclusive + registry.add("data/jets/V0/jetPtV0PtEtaPhi", "jetPtV0PtEtaPhi", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0EtaAxis, v0PhiAxis}); + registry.add("data/jets/V0/jetPtV0PtCtau", "jetPtV0PtCtau", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}); + registry.add("data/jets/V0/jetPtV0PtMass", "jetPtV0PtMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtV0PtMassWide", "jetPtV0PtMassWide", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, k0SWideAxis, lambdaMassAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtV0PtLambdaMasses", "jetPtV0PtLambdaMasses", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}); + registry.add("data/jets/V0/jetPtV0PtRadiusCosPA", "jetPtV0PtRadiusCosPA", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0RadiusAxis, v0CosPAAxis}); + registry.add("data/jets/V0/jetPtV0PtDCAposneg", "jetPtV0PtDCAposneg", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0DCApAxis, v0DCAnAxis}); + registry.add("data/jets/V0/jetPtV0PtDCAd", "jetPtV0PtDCAd", HistType::kTH3D, {jetPtAxis, v0PtAxis, v0DCAdAxis}); + + registry.add("data/jets/V0/jetPtV0TrackProjCtau", "jetPtV0TrackProjCtau", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}); + registry.add("data/jets/V0/jetPtV0TrackProjMass", "jetPtV0TrackProjMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtV0TrackProjMassWide", "jetPtV0TrackProjMassWide", HistType::kTHnSparseD, {jetPtAxis, zAxis, k0SWideAxis, lambdaMassAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtV0TrackProjLambdaMasses", "jetPtV0TrackProjLambdaMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}); + registry.add("data/jets/V0/jetPtV0TrackProjRadiusCosPA", "jetPtV0TrackProjRadiusCosPA", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0RadiusAxis, v0CosPAAxis}); + registry.add("data/jets/V0/jetPtV0TrackProjDCAposneg", "jetPtV0TrackProjDCAposneg", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, v0DCAnAxis}); + registry.add("data/jets/V0/jetPtV0TrackProjDCAd", "jetPtV0TrackProjDCAd", HistType::kTH3D, {jetPtAxis, zAxis, v0DCAdAxis}); + + // K0S + registry.add("data/jets/V0/jetPtK0SPtCtau", "Jet #it{p}_{T}, #it{p}_{T, K^{0}_{S}}, c#tau", HistType::kTH3D, {jetPtAxis, v0PtAxis, v0CtauAxis}); + registry.add("data/jets/V0/jetPtK0SPtMass", "Jet #it{p}_{T}, #it{p}_{T, K^{0}_{S}}, mass", HistType::kTH3D, {jetPtAxis, v0PtAxis, k0SMassAxis}); + registry.add("data/jets/V0/jetPtK0SPtAllMasses", "jetPtK0SPtAllMasses", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtK0SPtRadius", "Jet #it{p}_{T}, #it{p}_{T, K^{0}_{S}}, radius", HistType::kTH3D, {jetPtAxis, v0PtAxis, v0RadiusAxis}); + registry.add("data/jets/V0/jetPtK0SPtCosPA", "Jet #it{p}_{T}, #it{p}_{T, K^{0}_{S}}, cosPA", HistType::kTH3D, {jetPtAxis, v0PtAxis, v0CosPAAxis}); + registry.add("data/jets/V0/jetPtK0SPtDCAd", "Jet #it{p}_{T}, #it{p}_{T, K^{0}_{S}}, DCA daughters", HistType::kTH3D, {jetPtAxis, v0PtAxis, v0DCAdAxis}); + registry.add("data/jets/V0/jetPtK0SPtDCAposneg", "Jet #it{p}_{T}, #it{p}_{T, K^{0}_{S}}, DCA#pm", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0DCApAxis, v0DCAnAxis}); + registry.add("data/jets/V0/jetPtK0SPtCtauMass", "jetPtK0SPtCtauMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0CtauAxis, k0SMassAxis}); + registry.add("data/jets/V0/jetPtK0SPtRadiusMass", "jetPtK0SPtRadiusMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0RadiusAxis, k0SMassAxis}); + registry.add("data/jets/V0/jetPtK0SPtCosPAMass", "jetPtK0SPtCosPAMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0CosPAAxis, k0SMassAxis}); + registry.add("data/jets/V0/jetPtK0SPtDCAposMass", "jetPtK0SPtDCAposMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0DCApAxis, k0SMassAxis}); + registry.add("data/jets/V0/jetPtK0SPtDCAnegMass", "jetPtK0SPtDCAnegMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0DCAnAxis, k0SMassAxis}); + registry.add("data/jets/V0/jetPtK0SPtDCAdMass", "jetPtK0SPtDCAdMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0DCAdAxis, k0SMassAxis}); + + registry.add("data/jets/V0/jetPtK0STrackProjCtau", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, c#tau", HistType::kTH3D, {jetPtAxis, zAxis, v0CtauAxis}); + registry.add("data/jets/V0/jetPtK0STrackProjMass", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, mass", HistType::kTH3D, {jetPtAxis, zAxis, k0SMassAxis}); + registry.add("data/jets/V0/jetPtK0STrackProjAllMasses", "jetPtK0STrackProjAllMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtK0STrackProjRadius", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, radius", HistType::kTH3D, {jetPtAxis, zAxis, v0RadiusAxis}); + registry.add("data/jets/V0/jetPtK0STrackProjCosPA", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, cosPA", HistType::kTH3D, {jetPtAxis, zAxis, v0CosPAAxis}); + registry.add("data/jets/V0/jetPtK0STrackProjDCAd", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, DCA daughters", HistType::kTH3D, {jetPtAxis, zAxis, v0DCAdAxis}); + registry.add("data/jets/V0/jetPtK0STrackProjDCAposneg", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, DCA#pm", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, v0DCAnAxis}); + registry.add("data/jets/V0/jetPtK0STrackProjCtauMass", "jetPtK0STrackProjCtauMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CtauAxis, k0SMassAxis}); + registry.add("data/jets/V0/jetPtK0STrackProjRadiusMass", "jetPtK0STrackProjRadiusMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0RadiusAxis, k0SMassAxis}); + registry.add("data/jets/V0/jetPtK0STrackProjCosPAMass", "jetPtK0STrackProjCosPAMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CosPAAxis, k0SMassAxis}); + registry.add("data/jets/V0/jetPtK0STrackProjDCAposMass", "jetPtK0STrackProjDCAposMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, k0SMassAxis}); + registry.add("data/jets/V0/jetPtK0STrackProjDCAnegMass", "jetPtK0STrackProjDCAnegMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAnAxis, k0SMassAxis}); + registry.add("data/jets/V0/jetPtK0STrackProjDCAdMass", "jetPtK0STrackProjDCAdMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAdAxis, k0SMassAxis}); + + // Lambda + registry.add("data/jets/V0/jetPtLambdaPtCtau", "Jet #it{p}_{T}, #it{p}_{T, #Lambda^{0}}, c#tau", HistType::kTH3D, {jetPtAxis, v0PtAxis, v0CtauAxis}); + registry.add("data/jets/V0/jetPtLambdaPtMass", "Jet #it{p}_{T}, #it{p}_{T, #Lambda^{0}}, mass", HistType::kTH3D, {jetPtAxis, v0PtAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtLambdaPtAllMasses", "jetPtLambdaPtAllMasses", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtLambdaPtLambdaMasses", "jetPtLambdaPtLambdaMasses", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}); + registry.add("data/jets/V0/jetPtLambdaPtRadius", "Jet #it{p}_{T}, #it{p}_{T, #Lambda^{0}}, radius", HistType::kTH3D, {jetPtAxis, v0PtAxis, v0RadiusAxis}); + registry.add("data/jets/V0/jetPtLambdaPtCosPA", "Jet #it{p}_{T}, #it{p}_{T, #Lambda^{0}}, cosPA", HistType::kTH3D, {jetPtAxis, v0PtAxis, v0CosPAAxis}); + registry.add("data/jets/V0/jetPtLambdaPtDCAd", "Jet #it{p}_{T}, #it{p}_{T, #Lambda^{0}}, DCA daughters", HistType::kTH3D, {jetPtAxis, v0PtAxis, v0DCAdAxis}); + registry.add("data/jets/V0/jetPtLambdaPtDCAposneg", "Jet #it{p}_{T}, #it{p}_{T, #Lambda^{0}}, DCA#pm", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0DCApAxis, v0DCAnAxis}); + registry.add("data/jets/V0/jetPtLambdaPtCtauMass", "jetPtLambdaPtCtauMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0CtauAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtLambdaPtRadiusMass", "jetPtLambdaPtRadiusMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0RadiusAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtLambdaPtCosPAMass", "jetPtLambdaPtCosPAMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0CosPAAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtLambdaPtDCAposMass", "jetPtLambdaPtDCAposMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0DCApAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtLambdaPtDCAnegMass", "jetPtLambdaPtDCAnegMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0DCAnAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtLambdaPtDCAdMass", "jetPtLambdaPtDCAdMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0DCAdAxis, lambdaMassAxis}); + + registry.add("data/jets/V0/jetPtLambdaTrackProjCtau", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, c#tau", HistType::kTH3D, {jetPtAxis, zAxis, v0CtauAxis}); + registry.add("data/jets/V0/jetPtLambdaTrackProjMass", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, mass", HistType::kTH3D, {jetPtAxis, zAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtLambdaTrackProjAllMasses", "jetPtLambdaTrackProjAllMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtLambdaTrackProjLambdaMasses", "jetPtLambdaTrackProjLambdaMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}); + registry.add("data/jets/V0/jetPtLambdaTrackProjRadius", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, radius", HistType::kTH3D, {jetPtAxis, zAxis, v0RadiusAxis}); + registry.add("data/jets/V0/jetPtLambdaTrackProjCosPA", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, cosPA", HistType::kTH3D, {jetPtAxis, zAxis, v0CosPAAxis}); + registry.add("data/jets/V0/jetPtLambdaTrackProjDCAd", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, DCA daughters", HistType::kTH3D, {jetPtAxis, zAxis, v0DCAdAxis}); + registry.add("data/jets/V0/jetPtLambdaTrackProjDCAposneg", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, DCA#pm", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, v0DCAnAxis}); + registry.add("data/jets/V0/jetPtLambdaTrackProjCtauMass", "jetPtLambdaTrackProjCtauMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CtauAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtLambdaTrackProjRadiusMass", "jetPtLambdaTrackProjRadiusMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0RadiusAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtLambdaTrackProjCosPAMass", "jetPtLambdaTrackProjCosPAMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CosPAAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtLambdaTrackProjDCAposMass", "jetPtLambdaTrackProjDCAposMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtLambdaTrackProjDCAnegMass", "jetPtLambdaTrackProjDCAnegMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAnAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtLambdaTrackProjDCAdMass", "jetPtLambdaTrackProjDCAdMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAdAxis, lambdaMassAxis}); + + // AntiLambda + registry.add("data/jets/V0/jetPtAntiLambdaPtCtau", "Jet #it{p}_{T}, #it{p}_{T, #bar{#Lambda}^{0}}, c#tau", HistType::kTH3D, {jetPtAxis, v0PtAxis, v0CtauAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaPtMass", "Jet #it{p}_{T}, #it{p}_{T, #bar{#Lambda}^{0}}, mass", HistType::kTH3D, {jetPtAxis, v0PtAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaPtAllMasses", "jetPtAntiLambdaPtAllMasses", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaPtLambdaMasses", "jetPtAntiLambdaPtLambdaMasses", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaPtRadius", "Jet #it{p}_{T}, #it{p}_{T, #bar{#Lambda}^{0}}, radius", HistType::kTH3D, {jetPtAxis, v0PtAxis, v0RadiusAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaPtCosPA", "Jet #it{p}_{T}, #it{p}_{T, #bar{#Lambda}^{0}}, cosPA", HistType::kTH3D, {jetPtAxis, v0PtAxis, v0CosPAAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaPtDCAd", "Jet #it{p}_{T}, #it{p}_{T, #bar{#Lambda}^{0}}, DCA daughters", HistType::kTH3D, {jetPtAxis, v0PtAxis, v0DCAdAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaPtDCAposneg", "Jet #it{p}_{T}, #it{p}_{T, #bar{#Lambda}^{0}}, DCA#pm", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0DCApAxis, v0DCAnAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaPtCtauMass", "jetPtAntiLambdaPtCtauMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0CtauAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaPtRadiusMass", "jetPtAntiLambdaPtRadiusMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0RadiusAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaPtCosPAMass", "jetPtAntiLambdaPtCosPAMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0CosPAAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaPtDCAposMass", "jetPtAntiLambdaPtDCAposMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0DCApAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaPtDCAnegMass", "jetPtAntiLambdaPtDCAnegMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0DCAnAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaPtDCAdMass", "jetPtAntiLambdaPtDCAdMass", HistType::kTHnSparseD, {jetPtAxis, v0PtAxis, v0DCAdAxis, lambdaMassAxis}); + + registry.add("data/jets/V0/jetPtAntiLambdaTrackProjCtau", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, c#tau", HistType::kTH3D, {jetPtAxis, zAxis, v0CtauAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaTrackProjMass", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, mass", HistType::kTH3D, {jetPtAxis, zAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaTrackProjAllMasses", "jetPtAntiLambdaTrackProjAllMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaTrackProjLambdaMasses", "jetPtAntiLambdaTrackProjLambdaMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaTrackProjRadius", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, radius", HistType::kTH3D, {jetPtAxis, zAxis, v0RadiusAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaTrackProjCosPA", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, cosPA", HistType::kTH3D, {jetPtAxis, zAxis, v0CosPAAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaTrackProjDCAd", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, DCA daughters", HistType::kTH3D, {jetPtAxis, zAxis, v0DCAdAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaTrackProjDCAposneg", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, DCA#pm", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, v0DCAnAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaTrackProjCtauMass", "jetPtAntiLambdaTrackProjCtauMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CtauAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaTrackProjRadiusMass", "jetPtAntiLambdaTrackProjRadiusMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0RadiusAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaTrackProjCosPAMass", "jetPtAntiLambdaTrackProjCosPAMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CosPAAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaTrackProjDCAposMass", "jetPtAntiLambdaTrackProjDCAposMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaTrackProjDCAnegMass", "jetPtAntiLambdaTrackProjDCAnegMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAnAxis, lambdaMassAxis}); + registry.add("data/jets/V0/jetPtAntiLambdaTrackProjDCAdMass", "jetPtAntiLambdaTrackProjDCAdMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAdAxis, lambdaMassAxis}); + + // Weighted histograms + registry.add("data/jets/weighted/jetPtEtaPhi", "Jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {jetPtAxis, etaAxis, phiAxis}, true); + registry.add("data/jets/weighted/V0/jetPtnV0nK0SnLambdanAntiLambda", "jetPtnV0nK0SnLambdanAntiLambda", HistType::kTHnSparseD, {jetPtAxis, v0Weight, v0Weight, v0Weight, v0Weight}, true); + + // Inclusive Weighted + registry.add("data/jets/weighted/V0/jetPtV0TrackProjCtau", "jetPtV0TrackProjCtau", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}, true); + registry.add("data/jets/weighted/V0/jetPtV0TrackProjMass", "jetPtV0TrackProjMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtV0TrackProjMassWide", "jetPtV0TrackProjMassWide", HistType::kTHnSparseD, {jetPtAxis, zAxis, k0SWideAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtV0TrackProjLambdaMasses", "jetPtV0TrackProjLambdaMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("data/jets/weighted/V0/jetPtV0TrackProjRadiusCosPA", "jetPtV0TrackProjRadiusCosPA", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("data/jets/weighted/V0/jetPtV0TrackProjDCAposneg", "jetPtV0TrackProjDCAposneg", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("data/jets/weighted/V0/jetPtV0TrackProjDCAd", "jetPtV0TrackProjDCAd", HistType::kTH3D, {jetPtAxis, zAxis, v0DCAdAxis}, true); + + // K0S Weighted + registry.add("data/jets/weighted/V0/jetPtK0STrackProjMass", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, mass", HistType::kTH3D, {jetPtAxis, zAxis, k0SMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtK0STrackProjCtau", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, c#tau", HistType::kTH3D, {jetPtAxis, zAxis, v0CtauAxis}, true); + registry.add("data/jets/weighted/V0/jetPtK0STrackProjAllMasses", "jetPtK0STrackProjAllMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtK0STrackProjRadius", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, radius", HistType::kTH3D, {jetPtAxis, zAxis, v0RadiusAxis}, true); + registry.add("data/jets/weighted/V0/jetPtK0STrackProjCosPA", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, cosPA", HistType::kTH3D, {jetPtAxis, zAxis, v0CosPAAxis}, true); + registry.add("data/jets/weighted/V0/jetPtK0STrackProjDCAd", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, DCA daughters", HistType::kTH3D, {jetPtAxis, zAxis, v0DCAdAxis}, true); + registry.add("data/jets/weighted/V0/jetPtK0STrackProjDCAposneg", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, DCA#pm", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("data/jets/weighted/V0/jetPtK0STrackProjCtauMass", "jetPtK0STrackProjCtauMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CtauAxis, k0SMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtK0STrackProjRadiusMass", "jetPtK0STrackProjRadiusMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0RadiusAxis, k0SMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtK0STrackProjCosPAMass", "jetPtK0STrackProjCosPAMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CosPAAxis, k0SMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtK0STrackProjDCAposMass", "jetPtK0STrackProjDCAposMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, k0SMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtK0STrackProjDCAnegMass", "jetPtK0STrackProjDCAnegMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAnAxis, k0SMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtK0STrackProjDCAdMass", "jetPtK0STrackProjDCAdMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAdAxis, k0SMassAxis}, true); + + // Lambda Weighted + registry.add("data/jets/weighted/V0/jetPtLambdaTrackProjMass", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, mass", HistType::kTH3D, {jetPtAxis, zAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtLambdaTrackProjCtau", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, c#tau", HistType::kTH3D, {jetPtAxis, zAxis, v0CtauAxis}, true); + registry.add("data/jets/weighted/V0/jetPtLambdaTrackProjAllMasses", "jetPtLambdaTrackProjAllMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtLambdaTrackProjLambdaMasses", "jetPtLambdaTrackProjLambdaMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("data/jets/weighted/V0/jetPtLambdaTrackProjRadius", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, radius", HistType::kTH3D, {jetPtAxis, zAxis, v0RadiusAxis}, true); + registry.add("data/jets/weighted/V0/jetPtLambdaTrackProjCosPA", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, cosPA", HistType::kTH3D, {jetPtAxis, zAxis, v0CosPAAxis}, true); + registry.add("data/jets/weighted/V0/jetPtLambdaTrackProjDCAd", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, DCA daughters", HistType::kTH3D, {jetPtAxis, zAxis, v0DCAdAxis}, true); + registry.add("data/jets/weighted/V0/jetPtLambdaTrackProjDCAposneg", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, DCA#pm", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("data/jets/weighted/V0/jetPtLambdaTrackProjCtauMass", "jetPtLambdaTrackProjCtauMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CtauAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtLambdaTrackProjRadiusMass", "jetPtLambdaTrackProjRadiusMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0RadiusAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtLambdaTrackProjCosPAMass", "jetPtLambdaTrackProjCosPAMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CosPAAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtLambdaTrackProjDCAposMass", "jetPtLambdaTrackProjDCAposMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtLambdaTrackProjDCAnegMass", "jetPtLambdaTrackProjDCAnegMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAnAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtLambdaTrackProjDCAdMass", "jetPtLambdaTrackProjDCAdMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAdAxis, lambdaMassAxis}, true); + + // AntiLambda Weighted + registry.add("data/jets/weighted/V0/jetPtAntiLambdaTrackProjMass", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, mass", HistType::kTH3D, {jetPtAxis, zAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtAntiLambdaTrackProjCtau", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, c#tau", HistType::kTH3D, {jetPtAxis, zAxis, v0CtauAxis}, true); + registry.add("data/jets/weighted/V0/jetPtAntiLambdaTrackProjAllMasses", "jetPtAntiLambdaTrackProjAllMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtAntiLambdaTrackProjLambdaMasses", "jetPtAntiLambdaTrackProjLambdaMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("data/jets/weighted/V0/jetPtAntiLambdaTrackProjRadius", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, radius", HistType::kTH3D, {jetPtAxis, zAxis, v0RadiusAxis}, true); + registry.add("data/jets/weighted/V0/jetPtAntiLambdaTrackProjCosPA", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, cosPA", HistType::kTH3D, {jetPtAxis, zAxis, v0CosPAAxis}, true); + registry.add("data/jets/weighted/V0/jetPtAntiLambdaTrackProjDCAd", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, DCA daughters", HistType::kTH3D, {jetPtAxis, zAxis, v0DCAdAxis}, true); + registry.add("data/jets/weighted/V0/jetPtAntiLambdaTrackProjDCAposneg", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, DCA#pm", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("data/jets/weighted/V0/jetPtAntiLambdaTrackProjCtauMass", "jetPtAntiLambdaTrackProjCtauMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CtauAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtAntiLambdaTrackProjRadiusMass", "jetPtAntiLambdaTrackProjRadiusMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0RadiusAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtAntiLambdaTrackProjCosPAMass", "jetPtAntiLambdaTrackProjCosPAMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CosPAAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtAntiLambdaTrackProjDCAposMass", "jetPtAntiLambdaTrackProjDCAposMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtAntiLambdaTrackProjDCAnegMass", "jetPtAntiLambdaTrackProjDCAnegMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAnAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtAntiLambdaTrackProjDCAdMass", "jetPtAntiLambdaTrackProjDCAdMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAdAxis, lambdaMassAxis}, true); + + // Background Weighted + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjMass", "jetPtBkgTrackProjMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjCtau", "jetPtBkgTrackProjCtau", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjLambdaMasses", "jetPtBkgTrackProjLambdaMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjRadiusCosPA", "jetPtBkgTrackProjRadiusCosPA", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjDCAposneg", "jetPtBkgTrackProjDCAposneg", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjDCAd", "jetPtBkgTrackProjDCAd", HistType::kTH3D, {jetPtAxis, zAxis, v0DCAdAxis}, true); + + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjCtauK0SMass", "jetPtBkgTrackProjCtauK0SMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CtauAxis, k0SMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjRadiusK0SMass", "jetPtBkgTrackProjRadiusK0SMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0RadiusAxis, k0SMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjCosPAK0SMass", "jetPtBkgTrackProjCosPAK0SMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CosPAAxis, k0SMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjDCAposK0SMass", "jetPtBkgTrackProjDCAposK0SMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, k0SMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjDCAnegK0SMass", "jetPtBkgTrackProjDCAnegK0SMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAnAxis, k0SMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjDCAdK0SMass", "jetPtBkgTrackProjDCAdK0SMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAdAxis, k0SMassAxis}, true); + + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjCtauLambdaMass", "jetPtBkgTrackProjCtauLambdaMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CtauAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjRadiusLambdaMass", "jetPtBkgTrackProjRadiusLambdaMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0RadiusAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjCosPALambdaMass", "jetPtBkgTrackProjCosPALambdaMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CosPAAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjDCAposLambdaMass", "jetPtBkgTrackProjDCAposLambdaMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjDCAnegLambdaMass", "jetPtBkgTrackProjDCAnegLambdaMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAnAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjDCAdLambdaMass", "jetPtBkgTrackProjDCAdLambdaMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAdAxis, lambdaMassAxis}, true); + + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjCtauAntiLambdaMass", "jetPtBkgTrackProjCtauAntiLambdaMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CtauAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjRadiusAntiLambdaMass", "jetPtBkgTrackProjRadiusAntiLambdaMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0RadiusAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjCosPAAntiLambdaMass", "jetPtBkgTrackProjCosPAAntiLambdaMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0CosPAAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjDCAposAntiLambdaMass", "jetPtBkgTrackProjDCAposAntiLambdaMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCApAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjDCAnegAntiLambdaMass", "jetPtBkgTrackProjDCAnegAntiLambdaMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAnAxis, lambdaMassAxis}, true); + registry.add("data/jets/weighted/V0/jetPtBkgTrackProjDCAdAntiLambdaMass", "jetPtBkgTrackProjDCAdAntiLambdaMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, v0DCAdAxis, lambdaMassAxis}, true); + } + + if (doprocessMcMatchedV0) { + // MCP + registry.add("mcp/V0/nV0sEventAcc", "nV0s per event (accepted)", HistType::kTH1D, {v0Count}, true); + registry.add("mcp/V0/nV0sEventAccWeighted", "nV0s per event (accepted, weighted)", HistType::kTH1D, {v0Weight}, true); + registry.add("mcp/V0/V0PtEtaPhi", "V0PtEtaPhi", HistType::kTH3D, {v0partPtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("mcp/V0/K0SPtEtaPhi", "K0SPtEtaPhi", HistType::kTH3D, {v0partPtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("mcp/V0/LambdaPtEtaPhi", "LambdaPtEtaPhi", HistType::kTH3D, {v0partPtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("mcp/V0/AntiLambdaPtEtaPhi", "AntiLambdaPtEtaPhi", HistType::kTH3D, {v0partPtAxis, v0EtaAxis, v0PhiAxis}, true); + + // MCD Inclusive + registry.add("mcd/V0/nV0sEventAcc", "nV0s per event (accepted)", HistType::kTH1D, {v0Count}); + registry.add("mcd/V0/nV0sEventAccWeighted", "nV0s per event (accepted, weighted)", HistType::kTH1D, {v0Weight}, true); + registry.add("mcd/V0/V0PtEtaPhi", "V0PtEtaPhi", HistType::kTH3D, {v0detPtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("mcd/V0/V0PtCtau", "V0PtCtau", HistType::kTHnSparseD, {v0detPtAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}, true); + registry.add("mcd/V0/V0PtMass", "V0PtMass", HistType::kTHnSparseD, {v0detPtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("mcd/V0/V0PtLambdaMasses", "V0PtLambdaMasses", HistType::kTHnSparseD, {v0detPtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("mcd/V0/V0PtRadiusCosPA", "V0PtRadiusCosPA", HistType::kTH3D, {v0detPtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("mcd/V0/V0PtDCAposneg", "V0PtDCAposneg", HistType::kTH3D, {v0detPtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("mcd/V0/V0PtDCAd", "V0PtDCAd", HistType::kTH2D, {v0detPtAxis, v0DCAdAxis}, true); + + // MCD K0S + registry.add("mcd/V0/K0SPtEtaPhi", "K0SPtEtaPhi", HistType::kTH3D, {v0detPtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("mcd/V0/K0SPtRadiusCosPA", "K0SPtRadiusCosPA", HistType::kTH3D, {v0detPtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("mcd/V0/K0SPtDCAposneg", "K0SPtDCAposneg", HistType::kTH3D, {v0detPtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("mcd/V0/K0SPtDCAd", "K0SPtDCAd", HistType::kTH2D, {v0detPtAxis, v0DCAdAxis}, true); + registry.add("mcd/V0/K0SPtCtauMass", "K0SPtCtauMass", HistType::kTH3D, {v0detPtAxis, v0CtauAxis, k0SMassAxis}, true); + registry.add("mcd/V0/K0SPtRadiusMass", "K0SPtRadiusMass", HistType::kTH3D, {v0detPtAxis, v0RadiusAxis, k0SMassAxis}, true); + registry.add("mcd/V0/K0SPtCosPAMass", "K0SPtCosPAMass", HistType::kTH3D, {v0detPtAxis, v0CosPAAxis, k0SMassAxis}, true); + registry.add("mcd/V0/K0SPtDCAposMass", "K0SPtDCAposMass", HistType::kTH3D, {v0detPtAxis, v0DCApAxis, k0SMassAxis}, true); + registry.add("mcd/V0/K0SPtDCAnegMass", "K0SPtDCAnegMass", HistType::kTH3D, {v0detPtAxis, v0DCAnAxis, k0SMassAxis}, true); + registry.add("mcd/V0/K0SPtDCAdMass", "K0SPtDCAdMass", HistType::kTH3D, {v0detPtAxis, v0DCAdAxis, k0SMassAxis}, true); + + // MCD Lambda + registry.add("mcd/V0/LambdaPtEtaPhi", "LambdaPtEtaPhi", HistType::kTH3D, {v0detPtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("mcd/V0/LambdaPtLambdaMasses", "LambdaPtLambdaMasses", HistType::kTHnSparseD, {v0detPtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("mcd/V0/LambdaPtRadiusCosPA", "LambdaPtRadiusCosPA", HistType::kTH3D, {v0detPtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("mcd/V0/LambdaPtDCAposneg", "LambdaPtDCAposneg", HistType::kTH3D, {v0detPtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("mcd/V0/LambdaPtDCAd", "LambdaPtDCAd", HistType::kTH2D, {v0detPtAxis, v0DCAdAxis}, true); + registry.add("mcd/V0/LambdaPtCtauMass", "LambdaPtCtauMass", HistType::kTH3D, {v0detPtAxis, v0CtauAxis, lambdaMassAxis}, true); + registry.add("mcd/V0/LambdaPtRadiusMass", "LambdaPtRadiusMass", HistType::kTH3D, {v0detPtAxis, v0RadiusAxis, lambdaMassAxis}, true); + registry.add("mcd/V0/LambdaPtCosPAMass", "LambdaPtCosPAMass", HistType::kTH3D, {v0detPtAxis, v0CosPAAxis, lambdaMassAxis}, true); + registry.add("mcd/V0/LambdaPtDCAposMass", "LambdaPtDCAposMass", HistType::kTH3D, {v0detPtAxis, v0DCApAxis, lambdaMassAxis}, true); + registry.add("mcd/V0/LambdaPtDCAnegMass", "LambdaPtDCAnegMass", HistType::kTH3D, {v0detPtAxis, v0DCAnAxis, lambdaMassAxis}, true); + registry.add("mcd/V0/LambdaPtDCAdMass", "LambdaPtDCAdMass", HistType::kTH3D, {v0detPtAxis, v0DCAdAxis, lambdaMassAxis}, true); + + // MCD AntiLambda + registry.add("mcd/V0/AntiLambdaPtEtaPhi", "AntiLambdaPtEtaPhi", HistType::kTH3D, {v0detPtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("mcd/V0/AntiLambdaPtLambdaMasses", "AntiLambdaPtLambdaMasses", HistType::kTHnSparseD, {v0detPtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("mcd/V0/AntiLambdaPtRadiusCosPA", "AntiLambdaPtRadiusCosPA", HistType::kTH3D, {v0detPtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("mcd/V0/AntiLambdaPtDCAposneg", "AntiLambdaPtDCAposneg", HistType::kTH3D, {v0detPtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("mcd/V0/AntiLambdaPtDCAd", "AntiLambdaPtDCAd", HistType::kTH2D, {v0detPtAxis, v0DCAdAxis}, true); + registry.add("mcd/V0/AntiLambdaPtCtauMass", "AntiLambdaPtCtauMass", HistType::kTH3D, {v0detPtAxis, v0CtauAxis, lambdaMassAxis}, true); + registry.add("mcd/V0/AntiLambdaPtRadiusMass", "AntiLambdaPtRadiusMass", HistType::kTH3D, {v0detPtAxis, v0RadiusAxis, lambdaMassAxis}, true); + registry.add("mcd/V0/AntiLambdaPtCosPAMass", "AntiLambdaPtCosPAMass", HistType::kTH3D, {v0detPtAxis, v0CosPAAxis, lambdaMassAxis}, true); + registry.add("mcd/V0/AntiLambdaPtDCAposMass", "AntiLambdaPtDCAposMass", HistType::kTH3D, {v0detPtAxis, v0DCApAxis, lambdaMassAxis}, true); + registry.add("mcd/V0/AntiLambdaPtDCAnegMass", "AntiLambdaPtDCAnegMass", HistType::kTH3D, {v0detPtAxis, v0DCAnAxis, lambdaMassAxis}, true); + registry.add("mcd/V0/AntiLambdaPtDCAdMass", "AntiLambdaPtDCAdMass", HistType::kTH3D, {v0detPtAxis, v0DCAdAxis, lambdaMassAxis}, true); + + // Matching - Misses + registry.add("matching/V0/missV0PtEtaPhi", "missV0PtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/V0/missK0SPtEtaPhi", "missK0SPtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/V0/missLambdaPtEtaPhi", "missLambdaPtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/V0/missAntiLambdaPtEtaPhi", "missAntiLambdaPtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + + // Matching - Fakes Inclusive + registry.add("matching/V0/fakeV0PtEtaPhi", "fakeV0PtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/V0/fakeV0PtCtau", "fakeV0PtCtau", HistType::kTHnSparseD, {v0PtAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}, true); + registry.add("matching/V0/fakeV0PtMass", "fakeV0PtMass", HistType::kTHnSparseD, {v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/V0/fakeV0PtLambdaMasses", "fakeV0PtLambdaMasses", HistType::kTHnSparseD, {v0PtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("matching/V0/fakeV0PtRadiusCosPA", "fakeV0PtRadiusCosPA", HistType::kTH3D, {v0PtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("matching/V0/fakeV0PtDCAposneg", "fakeV0PtDCAposneg", HistType::kTH3D, {v0PtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/V0/fakeV0PtDCAd", "fakeV0PtDCAd", HistType::kTH2D, {v0PtAxis, v0DCAdAxis}, true); + registry.add("matching/V0/fakeV0PosTrackPtEtaPhi", "fakeV0PosTrackPtEtaPhi", HistType::kTH3D, {trackPtAxis, etaAxis, phiAxis}, true); + registry.add("matching/V0/fakeV0NegTrackPtEtaPhi", "fakeV0NegTrackPtEtaPhi", HistType::kTH3D, {trackPtAxis, etaAxis, phiAxis}, true); + + // Matching - Fakes K0S + registry.add("matching/V0/fakeK0SPtEtaPhi", "K0SPtEtaPhi", HistType::kTH3D, {v0detPtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/V0/fakeK0SPtRadiusCosPA", "K0SPtRadiusCosPA", HistType::kTH3D, {v0detPtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("matching/V0/fakeK0SPtDCAposneg", "K0SPtDCAposneg", HistType::kTH3D, {v0detPtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/V0/fakeK0SPtDCAd", "K0SPtDCAd", HistType::kTH2D, {v0detPtAxis, v0DCAdAxis}, true); + registry.add("matching/V0/fakeK0SPtCtauMass", "K0SPtCtauMass", HistType::kTH3D, {v0detPtAxis, v0CtauAxis, k0SMassAxis}, true); + registry.add("matching/V0/fakeK0SPtRadiusMass", "K0SPtRadiusMass", HistType::kTH3D, {v0detPtAxis, v0RadiusAxis, k0SMassAxis}, true); + registry.add("matching/V0/fakeK0SPtCosPAMass", "K0SPtCosPAMass", HistType::kTH3D, {v0detPtAxis, v0CosPAAxis, k0SMassAxis}, true); + registry.add("matching/V0/fakeK0SPtDCAposMass", "K0SPtDCAposMass", HistType::kTH3D, {v0detPtAxis, v0DCApAxis, k0SMassAxis}, true); + registry.add("matching/V0/fakeK0SPtDCAnegMass", "K0SPtDCAnegMass", HistType::kTH3D, {v0detPtAxis, v0DCAnAxis, k0SMassAxis}, true); + registry.add("matching/V0/fakeK0SPtDCAdMass", "K0SPtDCAdMass", HistType::kTH3D, {v0detPtAxis, v0DCAdAxis, k0SMassAxis}, true); + registry.add("matching/V0/fakeK0SPosTrackPtEtaPhi", "fakeK0SPosTrackPtEtaPhi", HistType::kTH3D, {trackPtAxis, etaAxis, phiAxis}, true); + registry.add("matching/V0/fakeK0SPosTrackPtMass", "fakeK0SPosTrackPtMass", HistType::kTH3D, {v0detPtAxis, trackPtAxis, k0SMassAxis}, true); + registry.add("matching/V0/fakeK0SNegTrackPtEtaPhi", "fakeK0SNegTrackPtEtaPhi", HistType::kTH3D, {trackPtAxis, etaAxis, phiAxis}, true); + registry.add("matching/V0/fakeK0SNegTrackPtMass", "fakeK0SNegTrackPtMass", HistType::kTH3D, {v0detPtAxis, trackPtAxis, k0SMassAxis}, true); + + // Matching - Fakes Lambda + registry.add("matching/V0/fakeLambdaPtEtaPhi", "LambdaPtEtaPhi", HistType::kTH3D, {v0detPtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/V0/fakeLambdaPtLambdaMasses", "LambdaPtLambdaMasses", HistType::kTHnSparseD, {v0detPtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("matching/V0/fakeLambdaPtRadiusCosPA", "LambdaPtRadiusCosPA", HistType::kTH3D, {v0detPtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("matching/V0/fakeLambdaPtDCAposneg", "LambdaPtDCAposneg", HistType::kTH3D, {v0detPtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/V0/fakeLambdaPtDCAd", "LambdaPtDCAd", HistType::kTH2D, {v0detPtAxis, v0DCAdAxis}, true); + registry.add("matching/V0/fakeLambdaPtCtauMass", "LambdaPtCtauMass", HistType::kTH3D, {v0detPtAxis, v0CtauAxis, lambdaMassAxis}, true); + registry.add("matching/V0/fakeLambdaPtRadiusMass", "LambdaPtRadiusMass", HistType::kTH3D, {v0detPtAxis, v0RadiusAxis, lambdaMassAxis}, true); + registry.add("matching/V0/fakeLambdaPtCosPAMass", "LambdaPtCosPAMass", HistType::kTH3D, {v0detPtAxis, v0CosPAAxis, lambdaMassAxis}, true); + registry.add("matching/V0/fakeLambdaPtDCAposMass", "LambdaPtDCAposMass", HistType::kTH3D, {v0detPtAxis, v0DCApAxis, lambdaMassAxis}, true); + registry.add("matching/V0/fakeLambdaPtDCAnegMass", "LambdaPtDCAnegMass", HistType::kTH3D, {v0detPtAxis, v0DCAnAxis, lambdaMassAxis}, true); + registry.add("matching/V0/fakeLambdaPtDCAdMass", "LambdaPtDCAdMass", HistType::kTH3D, {v0detPtAxis, v0DCAdAxis, lambdaMassAxis}, true); + registry.add("matching/V0/fakeLambdaPosTrackPtEtaPhi", "fakeLambdaPosTrackPtEtaPhi", HistType::kTH3D, {trackPtAxis, etaAxis, phiAxis}, true); + registry.add("matching/V0/fakeLambdaPosTrackPtMass", "fakeLambdaPosTrackPtMass", HistType::kTH3D, {v0detPtAxis, trackPtAxis, lambdaMassAxis}, true); + registry.add("matching/V0/fakeLambdaNegTrackPtEtaPhi", "fakeLambdaNegTrackPtEtaPhi", HistType::kTH3D, {trackPtAxis, etaAxis, phiAxis}, true); + registry.add("matching/V0/fakeLambdaNegTrackPtMass", "fakeLambdaNegTrackPtMass", HistType::kTH3D, {v0detPtAxis, trackPtAxis, lambdaMassAxis}, true); + + // Matching - Fakes AntiLambda + registry.add("matching/V0/fakeAntiLambdaPtEtaPhi", "AntiLambdaPtEtaPhi", HistType::kTH3D, {v0detPtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/V0/fakeAntiLambdaPtLambdaMasses", "AntiLambdaPtLambdaMasses", HistType::kTHnSparseD, {v0detPtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("matching/V0/fakeAntiLambdaPtRadiusCosPA", "AntiLambdaPtRadiusCosPA", HistType::kTH3D, {v0detPtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("matching/V0/fakeAntiLambdaPtDCAposneg", "AntiLambdaPtDCAposneg", HistType::kTH3D, {v0detPtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/V0/fakeAntiLambdaPtDCAd", "AntiLambdaPtDCAd", HistType::kTH2D, {v0detPtAxis, v0DCAdAxis}, true); + registry.add("matching/V0/fakeAntiLambdaPtCtauMass", "AntiLambdaPtCtauMass", HistType::kTH3D, {v0detPtAxis, v0CtauAxis, lambdaMassAxis}, true); + registry.add("matching/V0/fakeAntiLambdaPtRadiusMass", "AntiLambdaPtRadiusMass", HistType::kTH3D, {v0detPtAxis, v0RadiusAxis, lambdaMassAxis}, true); + registry.add("matching/V0/fakeAntiLambdaPtCosPAMass", "AntiLambdaPtCosPAMass", HistType::kTH3D, {v0detPtAxis, v0CosPAAxis, lambdaMassAxis}, true); + registry.add("matching/V0/fakeAntiLambdaPtDCAposMass", "AntiLambdaPtDCAposMass", HistType::kTH3D, {v0detPtAxis, v0DCApAxis, lambdaMassAxis}, true); + registry.add("matching/V0/fakeAntiLambdaPtDCAnegMass", "AntiLambdaPtDCAnegMass", HistType::kTH3D, {v0detPtAxis, v0DCAnAxis, lambdaMassAxis}, true); + registry.add("matching/V0/fakeAntiLambdaPtDCAdMass", "AntiLambdaPtDCAdMass", HistType::kTH3D, {v0detPtAxis, v0DCAdAxis, lambdaMassAxis}, true); + registry.add("matching/V0/fakeAntiLambdaPosTrackPtEtaPhi", "fakeAntiLambdaPosTrackPtEtaPhi", HistType::kTH3D, {trackPtAxis, etaAxis, phiAxis}, true); + registry.add("matching/V0/fakeAntiLambdaPosTrackPtMass", "fakeAntiLambdaPosTrackPtMass", HistType::kTH3D, {v0detPtAxis, trackPtAxis, lambdaMassAxis}, true); + registry.add("matching/V0/fakeAntiLambdaNegTrackPtEtaPhi", "fakeAntiLambdaNegTrackPtEtaPhi", HistType::kTH3D, {trackPtAxis, etaAxis, phiAxis}, true); + registry.add("matching/V0/fakeAntiLambdaNegTrackPtMass", "fakeAntiLambdaNegTrackPtMass", HistType::kTH3D, {v0detPtAxis, trackPtAxis, lambdaMassAxis}, true); + + // Matching - Matched + registry.add("matching/V0/nV0sEvent", "nV0sDet per event", HistType::kTH1D, {v0Count}); + registry.add("matching/V0/nV0sEventWeighted", "nV0sDet per event (weighted)", HistType::kTH1D, {v0Count}, true); + registry.add("matching/V0/nV0sEventAcc", "nV0sDet per event (accepted, matched)", HistType::kTH1D, {v0Count}, true); + registry.add("matching/V0/nV0sEventAccWeighted", "nV0sDet per event (accepted, matched, weighted)", HistType::kTH1D, {v0Weight}, true); + + // Matching - Matched Inclusive + registry.add("matching/V0/V0PartPtDetPt", "V0PartPtDetPt", HistType::kTH2D, {v0partPtAxis, v0detPtAxis}, true); + registry.add("matching/V0/V0PartPtRatioPtRelDiffPt", "V0PartPtRatioRelDiffPt", HistType::kTH3D, {v0partPtAxis, v0PtRatioAxis, v0PtRelDiffAxis}, true); + + // Matching - Matched K0S + registry.add("matching/V0/K0SPtEtaPhi", "K0SPtEtaPhi", HistType::kTHnSparseD, {v0partPtAxis, v0detPtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/V0/K0SPtCtauMass", "K0SPtCtauMass", HistType::kTHnSparseD, {v0partPtAxis, v0partPtAxis, v0CtauAxis, k0SMassAxis}, true); + registry.add("matching/V0/K0SPtRadiusCosPA", "K0SPtRadiusCosPA", HistType::kTHnSparseD, {v0partPtAxis, v0partPtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("matching/V0/K0SPtDCAposneg", "K0SPtDCAposneg", HistType::kTHnSparseD, {v0partPtAxis, v0partPtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/V0/K0SPtDCAd", "K0SPtDCAd", HistType::kTH3D, {v0partPtAxis, v0detPtAxis, v0DCAdAxis}, true); + registry.add("matching/V0/K0SPtMass", "K0SPtMass", HistType::kTHnSparseD, {v0partPtAxis, v0detPtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + + // Matching - Matched Lambda + registry.add("matching/V0/LambdaPtEtaPhi", "LambdaPtEtaPhi", HistType::kTHnSparseD, {v0partPtAxis, v0detPtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/V0/LambdaPtCtauMass", "LambdaPtCtauMass", HistType::kTHnSparseD, {v0partPtAxis, v0partPtAxis, v0CtauAxis, lambdaMassAxis}, true); + registry.add("matching/V0/LambdaPtRadiusCosPA", "LambdaPtRadiusCosPA", HistType::kTHnSparseD, {v0partPtAxis, v0partPtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("matching/V0/LambdaPtDCAposneg", "LambdaPtDCAposneg", HistType::kTHnSparseD, {v0partPtAxis, v0partPtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/V0/LambdaPtDCAd", "LambdaPtDCAd", HistType::kTH3D, {v0partPtAxis, v0detPtAxis, v0DCAdAxis}, true); + registry.add("matching/V0/LambdaPtMass", "LambdaPtMass", HistType::kTHnSparseD, {v0partPtAxis, v0detPtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/V0/LambdaReflection", "pt, pt, mK, mL, maL, LambdaReflection", HistType::kTHnSparseD, {v0partPtAxis, v0detPtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + + // Matching - Matched AntiLambda + registry.add("matching/V0/AntiLambdaPtEtaPhi", "AntiLambdaPtEtaPhi", HistType::kTHnSparseD, {v0partPtAxis, v0detPtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/V0/AntiLambdaPtCtauMass", "AntiLambdaPtCtauMass", HistType::kTHnSparseD, {v0partPtAxis, v0partPtAxis, v0CtauAxis, lambdaMassAxis}, true); + registry.add("matching/V0/AntiLambdaPtRadiusCosPA", "AntiLambdaPtRadiusCosPA", HistType::kTHnSparseD, {v0partPtAxis, v0partPtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("matching/V0/AntiLambdaPtDCAposneg", "AntiLambdaPtDCAposneg", HistType::kTHnSparseD, {v0partPtAxis, v0partPtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/V0/AntiLambdaPtDCAd", "AntiLambdaPtDCAd", HistType::kTH3D, {v0partPtAxis, v0detPtAxis, v0DCAdAxis}, true); + registry.add("matching/V0/AntiLambdaPtMass", "AntiLambdaPtMass", HistType::kTHnSparseD, {v0partPtAxis, v0detPtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/V0/AntiLambdaReflection", "pt, pt, mK, mL, maL, AntiLambdaReflection", HistType::kTHnSparseD, {v0partPtAxis, v0detPtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + + // Matching - Matched Daughters + registry.add("matching/V0/V0PosPartPtRatioPtRelDiffPt", "V0PosPartPtRatioRelDiffPt", HistType::kTH3D, {trackPtAxis, ptRatioAxis, ptTrackRelDiffAxis}, true); + registry.add("matching/V0/V0NegPartPtRatioPtRelDiffPt", "V0NegPartPtRatioRelDiffPt", HistType::kTH3D, {trackPtAxis, ptRatioAxis, ptTrackRelDiffAxis}, true); + registry.add("matching/V0/K0SPosNegPtMass", "K0SPosNegPtMass", HistType::kTHnSparseD, {v0partPtAxis, trackPtAxis, trackPtAxis, k0SMassAxis}, true); + registry.add("matching/V0/LambdaPosNegPtMass", "LambdaPosNegPtMass", HistType::kTHnSparseD, {v0partPtAxis, trackPtAxis, trackPtAxis, lambdaMassAxis}, true); + registry.add("matching/V0/AntiLambdaPosNegPtMass", "AntiLambdaPosNegPtMass", HistType::kTHnSparseD, {v0partPtAxis, trackPtAxis, trackPtAxis, lambdaMassAxis}, true); + } // doprocessMcMatchedV0 + + if (doprocessMcMatchedV0JetsFrag) { + // Matching - Jets + registry.add("mcp/jets/partJetPtEtaPhi", "Particle level jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {partJetPtAxis, partEtaAxis, partPhiAxis}, true); + registry.add("mcd/jets/detJetPtEtaPhi", "Detector level jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {detJetPtAxis, detEtaAxis, detPhiAxis}, true); + + registry.add("matching/jets/matchDetJetPtEtaPhi", "Matched detector level jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {detJetPtAxis, detEtaAxis, detPhiAxis}, true); + registry.add("matching/jets/matchPartJetPtEtaPhi", "Matched particle level jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {partJetPtAxis, partEtaAxis, partPhiAxis}, true); + registry.add("matching/jets/matchPartJetPtEtaPhiMatchDist", "matchJetMatchDist", HistType::kTHnSparseD, {partJetPtAxis, partEtaAxis, partPhiAxis, matchDistAxis}, true); + registry.add("matching/jets/matchPartJetPtEnergyScale", "jetEnergyScale", HistType::kTH2D, {partJetPtAxis, ptRatioAxis}, true); + registry.add("matching/jets/matchDetJetPtPartJetPt", "matchDetJetPtPartJetPt", HistType::kTH2D, {detJetPtAxis, partJetPtAxis}, true); + registry.add("matching/jets/matchPartJetPtDetJetEtaPartJetEta", "matchPartJetPtDetJetEtaPartJetEta", HistType::kTH3D, {partJetPtAxis, detEtaAxis, partEtaAxis}, true); + registry.add("matching/jets/matchPartJetPtDetJetPhiPartJetPhi", "matchPartJetPtDetJetPhiPartJetPhi", HistType::kTH3D, {partJetPtAxis, detPhiAxis, partPhiAxis}, true); + registry.add("matching/jets/matchPartJetPtResolutionPt", "#it{p}_{T}^{jet, det} - #it{p}_{T}^{jet, part}", HistType::kTH2D, {partJetPtAxis, ptDiffAxis}, true); + registry.add("matching/jets/matchPartJetPtResolutionEta", "#eta^{jet, det} - #eta^{jet, part}", HistType::kTH3D, {partJetPtAxis, partEtaAxis, etaDiffAxis}, true); + registry.add("matching/jets/matchPartJetPtResolutionPhi", "#phi^{jet, det} - #phi^{jet, part}", HistType::kTH3D, {partJetPtAxis, partPhiAxis, phiDiffAxis}, true); + registry.add("matching/jets/matchPartJetPtRelDiffPt", "#it{p}_{T}^{jet, det} - #it{p}_{T}^{jet, part}", HistType::kTH2D, {partJetPtAxis, ptJetRelDiffAxis}, true); + + registry.add("matching/jets/V0/jetPtnV0MatchednK0SnLambdanAntiLambda", "jet Pt, nV0 matched, nK0S nLambdan AntiLambda", HistType::kTHnSparseD, {detJetPtAxis, v0Count, v0Count, v0Count, v0Count}, true); + registry.add("matching/jets/V0/partJetPtV0PtDetPt", "V0PartPtDetPt", HistType::kTH3D, {partJetPtAxis, v0partPtAxis, v0detPtAxis}, true); + registry.add("matching/jets/V0/partJetPtDetJetPtPartV0PtRatioPtRelDiffPt", "V0PartPtRatioRelDiffPt", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, v0partPtAxis, v0PtRatioAxis, v0PtRelDiffAxis}, true); + + // Matching - Matched V0s + registry.add("matching/jets/V0/matchDetJetPtV0TrackProjPartJetPtV0TrackProj", "Matched", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, partJetPtAxis, partZAxis}, true); + registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0Pt", "matched jet Pt, V0 Pt", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis}, true); + // Matching - Matched V0s: pt + registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtCtauK0S", "matched jet Pt, V0 Pt, Ctau #{K}^{0}_{S}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtCtauLambda", "matched jet Pt, V0 Pt, Ctau #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtCtauAntiLambda", "matched jet Pt, V0 Pt, Ctau #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtMassK0S", "matched jet Pt, V0 Pt, MassK0S", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, k0SMassAxis}, true); + registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtMassLambda", "matched jet Pt, V0 Pt, Mass #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtMassAntiLambda", "matched jet Pt, V0 Pt, Mass #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtRadius", "matched jet Pt, V0 Pt, Radius", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0RadiusAxis}, true); + registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtCosPA", "matched jet Pt, V0 Pt, CosPA", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0CosPAAxis}, true); + registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtDCAposneg", "matched jet Pt, V0 Pt, DCAposneg", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtDCAd", "matched jet Pt, V0 Pt, DCAd", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0DCAdAxis}, true); + // Matching - Matched V0s: z + registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjCtauK0S", "matched jet Pt, V0 z, Ctau #{K}^{0}_{S}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjCtauLambda", "matched jet Pt, V0 z, Ctau #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjCtauAntiLambda", "matched jet Pt, V0 z, Ctau #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjMassK0S", "matched jet Pt, V0 z, MassK0S", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, k0SMassAxis}, true); + registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjMassLambda", "matched jet Pt, V0 z, Mass #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjMassAntiLambda", "matched jet Pt, V0 z, Mass #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjRadius", "matched jet Pt, V0 z, Radius", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0RadiusAxis}, true); + registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjCosPA", "matched jet Pt, V0 z, CosPA", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0CosPAAxis}, true); + registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjDCAposneg", "matched jet Pt, V0 z, DCAposneg", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjDCAd", "matched jet Pt, V0 z, DCAd", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0DCAdAxis}, true); + + // Matching - Fake V0s: pt + registry.add("matching/jets/V0/fakeJetPtV0PtEtaPhi", "fake jet Pt, V0 PtEtaPhi", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/jets/V0/fakeJetPtV0TrackProj", "Fakes", HistType::kTH2D, {detJetPtAxis, detZAxis}, true); + registry.add("matching/jets/V0/fakeJetPtV0PtCtau", "fake jet Pt, V0 PtCtau", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/fakeJetPtV0PtMass", "fake jet Pt, V0 PtMass", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/fakeJetPtV0PtLambdaMasses", "fake jet Pt, V0 PtLambdaMasses", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("matching/jets/V0/fakeJetPtV0PtRadiusCosPA", "fake jet Pt, V0 PtRadiusCosPA", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("matching/jets/V0/fakeJetPtV0PtDCAposneg", "fake jet Pt, V0 PtDCAposneg", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/jets/V0/fakeJetPtV0PtDCAd", "fake jet Pt, V0 PtDCAd", HistType::kTH3D, {detJetPtAxis, v0PtAxis, v0DCAdAxis}, true); + // Matching - Fake V0s: z + registry.add("matching/jets/V0/fakeJetPtV0TrackProjCtau", "fake jet Pt, V0 zCtau", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/fakeJetPtV0TrackProjMass", "fake jet Pt, V0 zMass", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/fakeJetPtV0TrackProjLambdaMasses", "fake jet Pt, V0 zLambdaMasses", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("matching/jets/V0/fakeJetPtV0TrackProjRadiusCosPA", "fake jet Pt, V0 zRadiusCosPA", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("matching/jets/V0/fakeJetPtV0TrackProjDCAposneg", "fake jet Pt, V0 zDCAposneg", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/jets/V0/fakeJetPtV0TrackProjDCAd", "fake jet Pt, V0 zDCAd", HistType::kTH3D, {detJetPtAxis, detZAxis, v0DCAdAxis}, true); + // Matching - Missed V0s + registry.add("matching/jets/V0/missJetPtV0PtEtaPhi", "miss jet Pt, V0 PtEtaPhi", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/jets/V0/missJetPtV0TrackProj", "Misses", HistType::kTH2D, {partJetPtAxis, partZAxis}, true); + + // Matching - Matched K0S + registry.add("matching/jets/V0/matchDetJetPtK0STrackProjPartJetPtK0STrackProj", "Matched", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, partJetPtAxis, partZAxis}, true); + registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPt", "matched jet Pt, K_{S}^{0} Pt", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis}, true); + // Matching - Matched K0S: pt + registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtCtauLambda", "matched jet Pt, K^{0}_{S} Pt, Ctau #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtCtauAntiLambda", "matched jet Pt, K^{0}_{S} Pt, Ctau #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtCtauK0S", "matched jet Pt, #{K}^{0}_{S} Pt, Ctau #{K}^{0}_{S}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtMassLambda", "matched jet Pt, K^{0}_{S} Pt, Mass #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtMassAntiLambda", "matched jet Pt, K^{0}_{S} Pt Mass #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtMassK0S", "matched jet Pt, K^{0}_{S} PtMassK0S", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, k0SMassAxis}, true); + registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtAllMasses", "matched jet Pt, K^{0}_{S} Pt, Masses", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtRadius", "matched jet Pt, K^{0}_{S} Pt Radius", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0RadiusAxis}, true); + registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtCosPA", "matched jet Pt, K^{0}_{S} Pt CosPA", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0CosPAAxis}, true); + registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtDCAposneg", "matched jet Pt, K^{0}_{S} PtDCAposneg", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtDCAd", "matched jet Pt, K^{0}_{S} PtDCAd", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0DCAdAxis}, true); + // Matching - Matched K0S: z + registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjCtauLambda", "matched jet Pt, K^{0}_{S} Pt, Ctau #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjCtauAntiLambda", "matched jet Pt, K^{0}_{S} Pt, Ctau #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjCtauK0S", "matched jet Pt, #{K}^{0}_{S} Pt, Ctau #{K}^{0}_{S}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjMassLambda", "matched jet Pt, K^{0}_{S} Pt, Mass #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjMassAntiLambda", "matched jet Pt, K^{0}_{S} Pt Mass #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjMassK0S", "matched jet Pt, K^{0}_{S} PtMassK0S", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, k0SMassAxis}, true); + registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjAllMasses", "matched jet Pt, K^{0}_{S} Pt, Masses", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjRadius", "matched jet Pt, K^{0}_{S} Pt Radius", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0RadiusAxis}, true); + registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjCosPA", "matched jet Pt, K^{0}_{S} Pt CosPA", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0CosPAAxis}, true); + registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjDCAposneg", "matched jet Pt, K^{0}_{S} PtDCAposneg", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjDCAd", "matched jet Pt, K^{0}_{S} PtDCAd", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0DCAdAxis}, true); + // Matching - Fake K0S: pt + registry.add("matching/jets/V0/fakeJetPtK0SPtEtaPhi", "fake jet Pt, K^{0}_{S} PtEtaPhi", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/jets/V0/fakeJetPtK0STrackProj", "Fakes", HistType::kTH2D, {detJetPtAxis, detZAxis}, true); + registry.add("matching/jets/V0/fakeJetPtK0SPtCtau", "fake jet Pt, K^{0}_{S} PtCtau", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/fakeJetPtK0SPtMass", "fake jet Pt, K^{0}_{S} PtMass", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/fakeJetPtK0SPtLambdaMasses", "fake jet Pt, K^{0}_{S} PtLambdaMasses", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("matching/jets/V0/fakeJetPtK0SPtRadiusCosPA", "fake jet Pt, K^{0}_{S} PtRadiusCosPA", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("matching/jets/V0/fakeJetPtK0SPtDCAposneg", "fake jet Pt, K^{0}_{S} PtDCAposneg", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/jets/V0/fakeJetPtK0SPtDCAd", "fake jet Pt, K^{0}_{S} PtDCAd", HistType::kTH3D, {detJetPtAxis, v0PtAxis, v0DCAdAxis}, true); + // Matching - Fake K0S: z + registry.add("matching/jets/V0/fakeJetPtK0STrackProjCtau", "fake jet Pt, K^{0}_{S} zCtau", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/fakeJetPtK0STrackProjMass", "fake jet Pt, K^{0}_{S} zMass", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/fakeJetPtK0STrackProjLambdaMasses", "fake jet Pt, K^{0}_{S} zLambdaMasses", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("matching/jets/V0/fakeJetPtK0STrackProjRadiusCosPA", "fake jet Pt, K^{0}_{S} zRadiusCosPA", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("matching/jets/V0/fakeJetPtK0STrackProjDCAposneg", "fake jet Pt, K^{0}_{S} zDCAposneg", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/jets/V0/fakeJetPtK0STrackProjDCAd", "fake jet Pt, K^{0}_{S} zDCAd", HistType::kTH3D, {detJetPtAxis, detZAxis, v0DCAdAxis}, true); + // Matching - Missed K0S + registry.add("matching/jets/V0/missJetPtK0SPtEtaPhi", "miss jet Pt, K^{0}_{S} PtEtaPhi", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/jets/V0/missJetPtK0STrackProj", "Misses", HistType::kTH2D, {partJetPtAxis, partZAxis}, true); + + // Matching - Matched Lambda + registry.add("matching/jets/V0/matchDetJetPtLambdaTrackProjPartJetPtLambdaTrackProj", "Matched", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, partJetPtAxis, partZAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPt", "matched jet Pt, #Lambda^{0} Pt", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis}, true); + // Matching - Matched Lambda: pt + registry.add("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtCtauK0S", "matched jet Pt, #{K}^{0}_{S} Pt, Ctau #{K}^{0}_{S}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtCtauLambda", "matched jet Pt, #Lambda^{0} Pt, Ctau #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtCtauAntiLambda", "matched jet Pt, #Lambda^{0} Pt, Ctau #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtMassK0S", "matched jet Pt, #Lambda^{0} PtMassK0S", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, k0SMassAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtMassLambda", "matched jet Pt, #Lambda^{0} Pt, Mass #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtMassAntiLambda", "matched jet Pt, #Lambda^{0} Pt Mass #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtAllMasses", "matched jet Pt, #Lambda^{0} Pt, Masses", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtRadius", "matched jet Pt, #Lambda^{0} Pt Radius", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0RadiusAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtCosPA", "matched jet Pt, #Lambda^{0} Pt CosPA", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0CosPAAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtDCAposneg", "matched jet Pt, #Lambda^{0} PtDCAposneg", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtDCAd", "matched jet Pt, #Lambda^{0} PtDCAd", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0DCAdAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtLambdaReflection", "Lambda Reflection", HistType::kTHnSparseD, {partJetPtAxis, v0partPtAxis, detJetPtAxis, v0detPtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + // Matching - Matched Lambda: z + registry.add("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjCtauLambda", "matched jet Pt, #Lambda^{0} Pt, Ctau #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjCtauAntiLambda", "matched jet Pt, #Lambda^{0} Pt, Ctau #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjCtauK0S", "matched jet Pt, #{K}^{0}_{S} Pt, Ctau #{K}^{0}_{S}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjMassLambda", "matched jet Pt, #Lambda^{0} Pt, Mass #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjMassAntiLambda", "matched jet Pt, #Lambda^{0} Pt Mass #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjMassK0S", "matched jet Pt, #Lambda^{0} PtMassK0S", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, k0SMassAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjAllMasses", "matched jet Pt, #Lambda^{0} Pt, Masses", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjRadius", "matched jet Pt, #Lambda^{0} Pt Radius", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0RadiusAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjCosPA", "matched jet Pt, #Lambda^{0} Pt CosPA", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0CosPAAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjDCAposneg", "matched jet Pt, #Lambda^{0} PtDCAposneg", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjDCAd", "matched jet Pt, #Lambda^{0} PtDCAd", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0DCAdAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjLambdaReflection", "Lambda Reflection", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + // Matching - Fake Lambda: pt + registry.add("matching/jets/V0/fakeJetPtLambdaPtEtaPhi", "fake jet Pt, #Lambda^{0} PtEtaPhi", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/jets/V0/fakeJetPtLambdaTrackProj", "Fakes", HistType::kTH2D, {detJetPtAxis, detZAxis}, true); + registry.add("matching/jets/V0/fakeJetPtLambdaPtCtau", "fake jet Pt, #Lambda^{0} PtCtau", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/fakeJetPtLambdaPtMass", "fake jet Pt, #Lambda^{0} PtMass", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/fakeJetPtLambdaPtLambdaMasses", "fake jet Pt, #Lambda^{0} PtLambdaMasses", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("matching/jets/V0/fakeJetPtLambdaPtRadiusCosPA", "fake jet Pt, #Lambda^{0} PtRadiusCosPA", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("matching/jets/V0/fakeJetPtLambdaPtDCAposneg", "fake jet Pt, #Lambda^{0} PtDCAposneg", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/jets/V0/fakeJetPtLambdaPtDCAd", "fake jet Pt, #Lambda^{0} PtDCAd", HistType::kTH3D, {detJetPtAxis, v0PtAxis, v0DCAdAxis}, true); + // Matching - Fake Lambda: z + registry.add("matching/jets/V0/fakeJetPtLambdaTrackProjEtaPhi", "fake jet Pt, #Lambda^{0} zEtaPhi", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/jets/V0/fakeJetPtLambdaTrackProjCtau", "fake jet Pt, #Lambda^{0} zCtau", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/fakeJetPtLambdaTrackProjMass", "fake jet Pt, #Lambda^{0} zMass", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/fakeJetPtLambdaTrackProjLambdaMasses", "fake jet Pt, #Lambda^{0} zLambdaMasses", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("matching/jets/V0/fakeJetPtLambdaTrackProjRadiusCosPA", "fake jet Pt, #Lambda^{0} zRadiusCosPA", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("matching/jets/V0/fakeJetPtLambdaTrackProjDCAposneg", "fake jet Pt, #Lambda^{0} zDCAposneg", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/jets/V0/fakeJetPtLambdaTrackProjDCAd", "fake jet Pt, #Lambda^{0} zDCAd", HistType::kTH3D, {detJetPtAxis, detZAxis, v0DCAdAxis}, true); + // Matching - Missed Lambda + registry.add("matching/jets/V0/missJetPtLambdaPtEtaPhi", "miss jet Pt, #Lambda^{0} PtEtaPhi", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/jets/V0/missJetPtLambdaTrackProj", "Misses", HistType::kTH2D, {partJetPtAxis, partZAxis}, true); + + // Matching - Matched AntiLambda + registry.add("matching/jets/V0/matchDetJetPtAntiLambdaTrackProjPartJetPtAntiLambdaTrackProj", "Matched", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, partJetPtAxis, partZAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPt", "matched jet Pt, #bar{#Lambda}^{0} Pt", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis}, true); + // Matching - Matched AntiLambda: pt + registry.add("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtCtauK0S", "matched jet Pt, #{K}^{0}_{S} Pt, Ctau #{K}^{0}_{S}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtCtauLambda", "matched jet Pt, #bar{#Lambda}^{0} Pt, Ctau #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtCtauAntiLambda", "matched jet Pt, #bar{#Lambda}^{0} Pt, Ctau #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtMassK0S", "matched jet Pt, #bar{#Lambda}^{0} PtMassK0S", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, k0SMassAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtMassLambda", "matched jet Pt, #bar{#Lambda}^{0} Pt, Mass #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtMassAntiLambda", "matched jet Pt, #bar{#Lambda}^{0} Pt Mass #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtAllMasses", "matched jet Pt, #bar{#Lambda}^{0} Pt, Masses", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtRadius", "matched jet Pt, #bar{#Lambda}^{0} Pt Radius", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0RadiusAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtCosPA", "matched jet Pt, #bar{#Lambda}^{0} Pt CosPA", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0CosPAAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtDCAposneg", "matched jet Pt, #bar{#Lambda}^{0} PtDCAposneg", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtDCAd", "matched jet Pt, #bar{#Lambda}^{0} PtDCAd", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis, v0DCAdAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtAntiLambdaReflection", "AntiLambda Reflection", HistType::kTHnSparseD, {partJetPtAxis, v0partPtAxis, detJetPtAxis, v0detPtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + // Matching - Matched AntiLambda: z + registry.add("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjCtauLambda", "matched jet Pt, #bar{#Lambda}^{0} Pt, Ctau #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjCtauAntiLambda", "matched jet Pt, #bar{#Lambda}^{0} Pt, Ctau #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjCtauK0S", "matched jet Pt, #{K}^{0}_{S} Pt, Ctau #{K}^{0}_{S}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjMassLambda", "matched jet Pt, #bar{#Lambda}^{0} Pt, Mass #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjMassAntiLambda", "matched jet Pt, #bar{#Lambda}^{0} Pt Mass #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjMassK0S", "matched jet Pt, #bar{#Lambda}^{0} PtMassK0S", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, k0SMassAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjAllMasses", "matched jet Pt, #bar{#Lambda}^{0} Pt, Masses", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjRadius", "matched jet Pt, #bar{#Lambda}^{0} Pt Radius", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0RadiusAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjCosPA", "matched jet Pt, #bar{#Lambda}^{0} Pt CosPA", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0CosPAAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjDCAposneg", "matched jet Pt, #bar{#Lambda}^{0} PtDCAposneg", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjDCAd", "matched jet Pt, #bar{#Lambda}^{0} PtDCAd", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, v0DCAdAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjAntiLambdaReflection", "AntiLambda Reflection", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + // Matching - Fake AntiLambda: pt + registry.add("matching/jets/V0/fakeJetPtAntiLambdaPtEtaPhi", "fake jet Pt, #bar{#Lambda}^{0} PtEtaPhi", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/jets/V0/fakeJetPtAntiLambdaTrackProj", "Fakes", HistType::kTH2D, {detJetPtAxis, detZAxis}, true); + registry.add("matching/jets/V0/fakeJetPtAntiLambdaPtCtau", "fake jet Pt, #bar{#Lambda}^{0} PtCtau", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/fakeJetPtAntiLambdaPtMass", "fake jet Pt, #bar{#Lambda}^{0} PtMass", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/fakeJetPtAntiLambdaPtLambdaMasses", "fake jet Pt, #bar{#Lambda}^{0} PtLambdaMasses", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("matching/jets/V0/fakeJetPtAntiLambdaPtRadiusCosPA", "fake jet Pt, #bar{#Lambda}^{0} PtRadiusCosPA", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("matching/jets/V0/fakeJetPtAntiLambdaPtDCAposneg", "fake jet Pt, #bar{#Lambda}^{0} PtDCAposneg", HistType::kTHnSparseD, {detJetPtAxis, v0PtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/jets/V0/fakeJetPtAntiLambdaPtDCAd", "fake jet Pt, #bar{#Lambda}^{0} PtDCAd", HistType::kTH3D, {detJetPtAxis, v0PtAxis, v0DCAdAxis}, true); + // Matching - Fake AntiLambda: z + registry.add("matching/jets/V0/fakeJetPtAntiLambdaTrackProjCtau", "fake jet Pt, #bar{#Lambda}^{0} zCtau", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}, true); + registry.add("matching/jets/V0/fakeJetPtAntiLambdaTrackProjMass", "fake jet Pt, #bar{#Lambda}^{0} zMass", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/fakeJetPtAntiLambdaTrackProjLambdaMasses", "fake jet Pt, #bar{#Lambda}^{0} zLambdaMasses", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, lambdaMassDiffAxis, lambdaMassRatioAxis, lambdaMassRelDiffAxis}, true); + registry.add("matching/jets/V0/fakeJetPtAntiLambdaTrackProjRadiusCosPA", "fake jet Pt, #bar{#Lambda}^{0} zRadiusCosPA", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("matching/jets/V0/fakeJetPtAntiLambdaTrackProjDCAposneg", "fake jet Pt, #bar{#Lambda}^{0} zDCAposneg", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/jets/V0/fakeJetPtAntiLambdaTrackProjDCAd", "fake jet Pt, #bar{#Lambda}^{0} zDCAd", HistType::kTH3D, {detJetPtAxis, detZAxis, v0DCAdAxis}, true); + // Matching - Missed AntiLambda + registry.add("matching/jets/V0/missJetPtAntiLambdaPtEtaPhi", "miss jet Pt, #bar{#Lambda}^{0} PtEtaPhi", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/jets/V0/missJetPtAntiLambdaTrackProj", "Misses", HistType::kTH2D, {partJetPtAxis, partZAxis}, true); + + // Matching - Matched V0s: daughters + registry.add("matching/jets/V0/partJetPtDetJetPtPartV0PtPosPtRatioPtRelDiffPt", "V0PtPosPartPtRatioRelDiffPt", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, v0PtAxis, trackPtAxis, ptRatioAxis, ptTrackRelDiffAxis}, true); + registry.add("matching/jets/V0/partJetPtDetJetPtPartV0PtNegPtRatioPtRelDiffPt", "V0PtNegPartPtRatioRelDiffPt", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, v0PtAxis, trackPtAxis, ptRatioAxis, ptTrackRelDiffAxis}, true); + // Matching - Fake V0s: daughters non-decayed (should be empty) + registry.add("matching/V0/nonedecayedFakeV0PtMass", "nonedecayedFakeV0PtMass", HistType::kTHnSparseD, {v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/nonedecayedFakeV0PtMass", "nonedecayedFakeV0PtMass", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/nonedecayedFakeV0TrackProjMass", "nonedecayedFakeV0TrackProjMass", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, zAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + // Matching - Fake V0s: daughters both-decayed (seems unlikely: e.g. K->pi pi->mu nu mu nu) + registry.add("matching/V0/doubledecayedFakeV0PtMass", "doubledecayedFakeV0PtMass", HistType::kTHnSparseD, {v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/doubledecayedFakeV0PtMass", "doubledecayedFakeV0PtMass", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/doubledecayedFakeV0TrackProjMass", "doubledecayedFakeV0TrackProjMass", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, zAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + // Matching - Fake V0s: daughters one-decayed (e.g. K->pi pi->pi mu nu) + // Matching - Fake K0S: daughters one-decayed + registry.add("matching/V0/decayedK0SV0PtMass", "decayedK0SV0PtMass", HistType::kTHnSparseD, {v0partPtAxis, v0detPtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/decayedK0SV0PtMass", "decayedK0SV0PtMass", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, v0partPtAxis, v0detPtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/decayedK0SV0TrackProjMass", "decayedK0SV0TrackProjMass", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, partZAxis, detZAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + // Matching - Fake Lambda: daughters one-decayed + registry.add("matching/V0/decayedLambdaV0PtMass", "decayedLambdaV0PtMass", HistType::kTHnSparseD, {v0partPtAxis, v0detPtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/decayedLambdaV0PtMass", "decayedLambdaV0PtMass", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, v0partPtAxis, v0detPtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/decayedLambdaV0TrackProjMass", "decayedLambdaV0TrackProjMass", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, partZAxis, detZAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + // Matching - Fake AntiLambda: daughters one-decayed + registry.add("matching/V0/decayedAntiLambdaV0PtMass", "decayedAntiLambdaV0PtMass", HistType::kTHnSparseD, {v0partPtAxis, v0detPtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/decayedAntiLambdaV0PtMass", "decayedAntiLambdaV0PtMass", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, v0partPtAxis, v0detPtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/decayedAntiLambdaV0TrackProjMass", "decayedAntiLambdaV0TrackProjMass", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, partZAxis, detZAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + // Matching - Fake Other: daughters one-decayed + registry.add("matching/V0/decayedOtherPtV0PtMass", "decayedOtherPtV0PtMass", HistType::kTHnSparseD, {v0partPtAxis, v0detPtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/decayedOtherPtV0PtMass", "decayedOtherPtV0PtMass", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, v0partPtAxis, v0detPtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/jets/V0/decayedOtherPtV0TrackProjMass", "decayedOtherPtV0TrackProjMass", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, partZAxis, detZAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + } // doprocessMcMatchedV0JetsFrag + + if (doprocessDataV0PerpCone) { + registry.add("data/PC/JetPtEtaV0Pt", "JetPtEtaV0Pt", HistType::kTH3D, {jetPtAxis, etaAxis, v0PtAxis}); + registry.add("data/PC/V0PtEtaPhi", "V0 #it{p}_{T}, #eta, #phi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}); + registry.add("data/PC/V0PtCtau", "V0PtCtau", HistType::kTHnSparseD, {v0PtAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}); + registry.add("data/PC/V0PtMass", "V0PtMass", HistType::kTHnSparseD, {v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}); + registry.add("data/PC/V0PtMassWide", "V0PtMassWide", HistType::kTHnSparseD, {v0PtAxis, k0SWideAxis, lambdaMassAxis, lambdaMassAxis}); + registry.add("data/PC/V0PtRadiusCosPA", "V0PtRadiusCosPA", HistType::kTH3D, {v0PtAxis, v0RadiusAxis, v0CosPAAxis}); + registry.add("data/PC/V0PtDCAposneg", "V0PtDCAposneg", HistType::kTH3D, {v0PtAxis, v0DCApAxis, v0DCAnAxis}); + registry.add("data/PC/V0PtDCAd", "V0PtDCAd", HistType::kTH2D, {v0PtAxis, v0DCAdAxis}); + + // K0S + registry.add("data/PC/JetPtK0SPtMass", "JetPtK0SPtMass", HistType::kTH3D, {jetPtAxis, v0PtAxis, k0SMassAxis}); + registry.add("data/PC/JetPtEtaK0SPt", "JetPtEtaK0SPt", HistType::kTH3D, {jetPtAxis, etaAxis, v0PtAxis}); + registry.add("data/PC/K0SPtEtaPhi", "K0SPtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}); + registry.add("data/PC/K0SPtCtauMass", "K0SPtCtauMass", HistType::kTH3D, {v0PtAxis, v0CtauAxis, k0SMassAxis}); + registry.add("data/PC/K0SPtRadiusCosPA", "K0SPtRadiusCosPA", HistType::kTH3D, {v0PtAxis, v0RadiusAxis, v0CosPAAxis}); + registry.add("data/PC/K0SPtDCAposneg", "K0SPtDCAposneg", HistType::kTH3D, {v0PtAxis, v0DCApAxis, v0DCAnAxis}); + registry.add("data/PC/K0SPtDCAd", "K0SPtDCAd", HistType::kTH2D, {v0PtAxis, v0DCAdAxis}); + + // Lambda + registry.add("data/PC/JetPtLambdaPtMass", "JetPtLambdaPtMass", HistType::kTH3D, {jetPtAxis, v0PtAxis, lambdaMassAxis}); + registry.add("data/PC/JetPtEtaLambdaPt", "JetPtEtaLambdaPt", HistType::kTH3D, {jetPtAxis, etaAxis, v0PtAxis}); + registry.add("data/PC/LambdaPtEtaPhi", "LambdaPtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}); + registry.add("data/PC/LambdaPtCtauMass", "LambdaPtCtauMass", HistType::kTH3D, {v0PtAxis, v0CtauAxis, lambdaMassAxis}); + registry.add("data/PC/LambdaPtRadiusCosPA", "LambdaPtRadiusCosPA", HistType::kTH3D, {v0PtAxis, v0RadiusAxis, v0CosPAAxis}); + registry.add("data/PC/LambdaPtDCAposneg", "LambdaPtDCAposneg", HistType::kTH3D, {v0PtAxis, v0DCApAxis, v0DCAnAxis}); + registry.add("data/PC/LambdaPtDCAd", "LambdaPtDCAd", HistType::kTH2D, {v0PtAxis, v0DCAdAxis}); + + // AntiLambda + registry.add("data/PC/JetPtAntiLambdaPtMass", "JetPtAntiLambdaPtMass", HistType::kTH3D, {jetPtAxis, v0PtAxis, lambdaMassAxis}); + registry.add("data/PC/JetPtEtaAntiLambdaPt", "JetPtEtaAntiLambdaPt", HistType::kTH3D, {jetPtAxis, etaAxis, v0PtAxis}); + registry.add("data/PC/AntiLambdaPtEtaPhi", "AntiLambdaPtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}); + registry.add("data/PC/AntiLambdaPtCtauMass", "AntiLambdaPtCtauMass", HistType::kTH3D, {v0PtAxis, v0CtauAxis, lambdaMassAxis}); + registry.add("data/PC/AntiLambdaPtRadiusCosPA", "AntiLambdaPtRadiusCosPA", HistType::kTH3D, {v0PtAxis, v0RadiusAxis, v0CosPAAxis}); + registry.add("data/PC/AntiLambdaPtDCAposneg", "AntiLambdaPtDCAposneg", HistType::kTH3D, {v0PtAxis, v0DCApAxis, v0DCAnAxis}); + registry.add("data/PC/AntiLambdaPtDCAd", "AntiLambdaPtDCAd", HistType::kTH2D, {v0PtAxis, v0DCAdAxis}); + + registry.add("data/PC/nV0sConePtEta", "nV0sConePtEta", HistType::kTH3D, {v0Count, jetPtAxis, etaAxis}); + registry.add("data/PC/ConePtEtaPhi", "ConePtEtaPhi", HistType::kTH3D, {jetPtAxis, etaAxis, phiAxis}); + registry.add("data/PC/JetPtEtaConePt", "JetPtEtaConePt", HistType::kTH3D, {jetPtAxis, etaAxis, jetPtAxis}); + } // doprocessDataV0PerpCone + + if (doprocessMcV0PerpCone) { + registry.add("mcd/V0/nV0sEvent", "NV0s in event", HistType::kTH1D, {v0Count}); + registry.add("mcd/V0/nV0sEventWeighted", "NV0s in event weighted", HistType::kTH1D, {v0Count}, true); + + // PerpCone - Fake V0s in MCD jets + registry.add("mcd/PC/jetPtEtaFakeV0Pt", "JetPtEtaFakeV0Pt", HistType::kTH3D, {detJetPtAxis, etaAxis, v0PtAxis}, true); + registry.add("mcd/PC/fakeV0PtEtaPhi", "fakeV0PtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("mcd/PC/fakeV0PtCtau", "fakeV0PtCtau", HistType::kTHnSparseD, {v0PtAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}, true); + registry.add("mcd/PC/fakeV0PtMass", "fakeV0PtMass", HistType::kTHnSparseD, {v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("mcd/PC/fakeV0PtRadiusCosPA", "fakeV0PtRadiusCosPA", HistType::kTH3D, {v0PtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("mcd/PC/fakeV0PtDCAposneg", "fakeV0PtDCAposneg", HistType::kTH3D, {v0PtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("mcd/PC/fakeV0PtDCAd", "fakeV0PtDCAd", HistType::kTH2D, {v0PtAxis, v0DCAdAxis}, true); + // PerpCone - Fake V0s in cone from MCD jets + registry.add("mcd/PC/fakenV0sConePtEta", "fakenV0sConePtEta", HistType::kTH3D, {v0Count, detJetPtAxis, etaAxis}, true); + registry.add("mcd/PC/fakeConePtEtaPhi", "fakeConePtEtaPhi", HistType::kTH3D, {detJetPtAxis, etaAxis, phiAxis}, true); + registry.add("mcd/PC/fakeJetPtEtaConePt", "fakeJetPtEtaConePt", HistType::kTH3D, {detJetPtAxis, etaAxis, detJetPtAxis}, true); + // PerpCone - Matched V0s in MCD jets + registry.add("mcd/PC/jetPtEtaMatchedV0Pt", "JetPtEtaMatchedV0Pt", HistType::kTH3D, {detJetPtAxis, etaAxis, v0PtAxis}, true); + registry.add("mcd/PC/matchedV0PtEtaPhi", "matchedV0PtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("mcd/PC/matchedV0PtCtau", "matchedV0PtCtau", HistType::kTHnSparseD, {v0PtAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}, true); + registry.add("mcd/PC/matchedV0PtMass", "matchedV0PtMass", HistType::kTHnSparseD, {v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("mcd/PC/matchedV0PtRadiusCosPA", "matchedV0PtRadiusCosPA", HistType::kTH3D, {v0PtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("mcd/PC/matchedV0PtDCAposneg", "matchedV0PtDCAposneg", HistType::kTH3D, {v0PtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("mcd/PC/matchedV0PtDCAd", "matchedV0PtDCAd", HistType::kTH2D, {v0PtAxis, v0DCAdAxis}, true); + // PerpCone - Matched V0s in cone from MCD jets + registry.add("mcd/PC/matchednV0sConePtEta", "matchednV0sConePtEta", HistType::kTH3D, {v0Count, detJetPtAxis, etaAxis}, true); + registry.add("mcd/PC/matchedConePtEtaPhi", "matchedConePtEtaPhi", HistType::kTH3D, {detJetPtAxis, etaAxis, phiAxis}, true); + registry.add("mcd/PC/matchedJetPtEtaConePt", "matchedJetPtEtaConePt", HistType::kTH3D, {detJetPtAxis, etaAxis, detJetPtAxis}, true); + // PerpCone - Matched K0S in MCD jets + registry.add("mcd/PC/matchedJetPtK0SPtMass", "matchedJetPtK0SPtMass", HistType::kTH3D, {detJetPtAxis, v0PtAxis, k0SMassAxis}, true); + // PerpCone - Matched Lambda in MCD jets + registry.add("mcd/PC/matchedJetPtLambdaPtMass", "matchedJetPtLambdaPtMass", HistType::kTH3D, {detJetPtAxis, v0PtAxis, lambdaMassAxis}, true); + // PerpCone - Matched AntiLambda in MCD jets + registry.add("mcd/PC/matchedJetPtAntiLambdaPtMass", "matchedJetPtAntiLambdaPtMass", HistType::kTH3D, {detJetPtAxis, v0PtAxis, lambdaMassAxis}, true); + // PerpCone - Fake V0s in Matched jets + registry.add("matching/PC/jetPtEtaFakeV0Pt", "JetPtEtaFakeV0Pt", HistType::kTH3D, {detJetPtAxis, etaAxis, v0PtAxis}, true); + registry.add("matching/PC/jetsPtFakeV0Pt", "jetsPtFakeV0Pt", HistType::kTH3D, {partJetPtAxis, detJetPtAxis, v0PtAxis}, true); + registry.add("matching/PC/fakeV0PtEtaPhi", "fakeV0PtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/PC/fakeV0PtCtau", "fakeV0PtCtau", HistType::kTHnSparseD, {v0PtAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}, true); + registry.add("matching/PC/fakeV0PtMass", "fakeV0PtMass", HistType::kTHnSparseD, {v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/PC/fakeV0PtRadiusCosPA", "fakeV0PtRadiusCosPA", HistType::kTH3D, {v0PtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("matching/PC/fakeV0PtDCAposneg", "fakeV0PtDCAposneg", HistType::kTH3D, {v0PtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/PC/fakeV0PtDCAd", "fakeV0PtDCAd", HistType::kTH2D, {v0PtAxis, v0DCAdAxis}, true); + // PerpCone - Fake V0s in cone from Matched jets + registry.add("matching/PC/fakenV0sConePtEta", "fakenV0sConePtEta", HistType::kTH3D, {v0Count, detJetPtAxis, etaAxis}, true); + registry.add("matching/PC/fakeConePtEtaPhi", "fakeConePtEtaPhi", HistType::kTH3D, {detJetPtAxis, etaAxis, phiAxis}, true); + registry.add("matching/PC/fakeJetPtEtaConePt", "fakeJetPtEtaConePt", HistType::kTH3D, {detJetPtAxis, etaAxis, detJetPtAxis}, true); + registry.add("matching/PC/fakeJetsPtEtaConePt", "fakeJetsPtEtaConePt", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, etaAxis, detJetPtAxis}, true); + // PerpCone - Matched V0s in Matched jets + registry.add("matching/PC/jetPtEtaMatchedV0Pt", "jetPtEtaMatchedV0Pt", HistType::kTH3D, {detJetPtAxis, etaAxis, v0PtAxis}, true); + registry.add("matching/PC/jetsPtMatchedV0Pt", "jetsPtMatchedV0Pt", HistType::kTH3D, {partJetPtAxis, detJetPtAxis, v0PtAxis}, true); + registry.add("matching/PC/matchedV0PtEtaPhi", "matchedV0PtEtaPhi", HistType::kTH3D, {v0PtAxis, v0EtaAxis, v0PhiAxis}, true); + registry.add("matching/PC/matchedV0PtCtau", "matchedV0PtCtau", HistType::kTHnSparseD, {v0PtAxis, v0CtauAxis, v0CtauAxis, v0CtauAxis}, true); + registry.add("matching/PC/matchedV0PtMass", "matchedV0PtMass", HistType::kTHnSparseD, {v0PtAxis, k0SMassAxis, lambdaMassAxis, lambdaMassAxis}, true); + registry.add("matching/PC/matchedV0PtRadiusCosPA", "matchedV0PtRadiusCosPA", HistType::kTH3D, {v0PtAxis, v0RadiusAxis, v0CosPAAxis}, true); + registry.add("matching/PC/matchedV0PtDCAposneg", "matchedV0PtDCAposneg", HistType::kTH3D, {v0PtAxis, v0DCApAxis, v0DCAnAxis}, true); + registry.add("matching/PC/matchedV0PtDCAd", "matchedV0PtDCAd", HistType::kTH2D, {v0PtAxis, v0DCAdAxis}, true); + // PerpCone - Matched V0s in cone from Matched jets + registry.add("matching/PC/matchednV0sConePtEta", "matchednV0sConePtEta", HistType::kTH3D, {v0Count, detJetPtAxis, etaAxis}, true); + registry.add("matching/PC/matchedConePtEtaPhi", "matchedConePtEtaPhi", HistType::kTH3D, {detJetPtAxis, etaAxis, phiAxis}, true); + registry.add("matching/PC/matchedJetPtEtaConePt", "matchedJetPtEtaConePt", HistType::kTH3D, {detJetPtAxis, etaAxis, detJetPtAxis}, true); + registry.add("matching/PC/matchedJetsPtEtaConePt", "matchedJetsPtEtaConePt", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, etaAxis, detJetPtAxis}, true); + // PerpCone - Matched K0S in Matched jets + registry.add("matching/PC/matchedJetPtK0SPtMass", "matchedJetPtK0SPtMass", HistType::kTH3D, {detJetPtAxis, v0PtAxis, k0SMassAxis}, true); + registry.add("matching/PC/matchedJetsPtK0SPtMass", "matchedJetsPtK0SPtMass", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, v0PtAxis, k0SMassAxis}, true); + // PerpCone - Matched Lambda in Matched jets + registry.add("matching/PC/matchedJetPtLambdaPtMass", "matchedJetPtLambdaPtMass", HistType::kTH3D, {detJetPtAxis, v0PtAxis, lambdaMassAxis}, true); + registry.add("matching/PC/matchedJetsPtLambdaPtMass", "matchedJetsPtLambdaPtMass", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, v0PtAxis, lambdaMassAxis}, true); + // PerpCone - Matched AntiLambda in Matched jets + registry.add("matching/PC/matchedJetPtAntiLambdaPtMass", "matchedJetPtAntiLambdaPtMass", HistType::kTH3D, {detJetPtAxis, v0PtAxis, lambdaMassAxis}, true); + registry.add("matching/PC/matchedJetsPtAntiLambdaPtMass", "matchedJetsPtAntiLambdaPtMass", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, v0PtAxis, lambdaMassAxis}, true); + } // doprocessMcV0PerpCone + } // init + + // --------------------------------------------------- + // Implementation of background subtraction at runtime + // --------------------------------------------------- + + // Return probability for a V0 to be signal (or background) + template + float getV0SignalProb(V const& v0) + { + // TODO: This is filled with dummy values for now + // Assumes a V0 can only be of one type! + // Should be made to return purity for a V0 based on species and pt + if (v0.isK0SCandidate()) { + // return 1.; + return 0.5; + } + if (v0.isLambdaCandidate()) { + // return 1.; + return 0.5; + } + if (v0.isAntiLambdaCandidate()) { + // return 1.; + return 0.5; + } + return 0.; // Background + } + // Return a 2-length std::vector of probabilities for a particle to correspond to signal or background + template + std::vector getV0SignalProbVector2Classes(V const& v0) + { + // 0: bkg, 1: signal + if (v0.isRejectedCandidate()) + return {1., 0.}; + + double purity = getV0SignalProb(v0); + return {1. - purity, purity}; + } + // Return a 4-length std::vector of probabilities for a particle to correspond to signal types + template + std::vector getV0SignalProbVector4Classes(V const& v0) + { + // 0: bkg, 1: K0S, 2: Lambda, 3: AntiLambda + if (v0.isRejectedCandidate()) + return {1., 0., 0., 0.}; + + double purity = getV0SignalProb(v0); + if (v0.isK0SCandidate()) + return {1. - purity, purity, 0., 0.}; + if (v0.isLambdaCandidate()) + return {1. - purity, 0., purity, 0.}; + if (v0.isAntiLambdaCandidate()) + return {1. - purity, 0., 0., purity}; + + return {1., 0., 0., 0.}; + } + // Convert state from uint32_t to std::vector containing the particle classes for that weight + std::vector convertState(uint32_t state, int nParticles, int nClasses = 4) + { + // TODO: Should we cast these to uint32_t? + std::vector v(nParticles, nClasses); + int nStates = std::round(std::pow(static_cast(nClasses), static_cast(nParticles))); + int nBitsPerParticle = std::round(std::log2(nClasses)); + int nBitsPerInt = sizeof(uint32_t) * 8; + + if (nClasses <= 0) { + LOGF(warning, "Number of classes (%d) must be greater than 0", nClasses); + return v; + } + if ((nClasses & (nClasses - 1)) != 0) { + // It's likely possible to make this work for non-power of 2 classes, but it's not needed and therefore not implemented + LOGF(warning, "Number of classes (%d) must be a power of 2", nClasses); + return v; + } + // Check for overflow in number of states + if (nStates <= 0) { + LOGF(warning, "Illegal number of states (%d)! %s", nStates, (nStates == 0) ? "" : "Max = 2^31"); + return v; + } + // Check if we have enough bits to store the state + if (nParticles * nBitsPerParticle > nBitsPerInt) { + LOGF(warning, "Number of bits required to parse the state (%d * %d = %d) is too large for %d bits per int!", nParticles, nBitsPerParticle, nParticles * nBitsPerParticle, nBitsPerInt); + return v; + } + // Check if the state is valid. This should never be triggered + if (state >= static_cast(nStates)) { + LOGF(warning, "Illegal state! State %d >= %d", state, nStates); + return v; + } + + for (int ip = 0; ip < nParticles; ip++) { + int value = 0; + int startBit = ip * nBitsPerParticle; + for (int ib = 0; ib < nBitsPerParticle; ib++) { + uint32_t bit = startBit + ib; + int bitVal = ((state & (1 << bit)) > 0); + value += bitVal * std::round(std::pow(2., static_cast(ib))); + } // loop over bits for particle ip + v[ip] = value; + } + return v; + } + // Return the probability associated with a given outcome + double stateWeight(std::vector state, std::vector> weights) + { + double w = 1.; + for (uint32_t ip = 0; ip < state.size(); ip++) { + w *= weights[ip][state[ip]]; + } + return w; + } + // Return the corrected values for z and ptjet for a given state + // Scale values by the fraction of jet momentum carried by removed V0s + std::vector correctedValues(std::vector state, std::vector values) + { + // Assumes values = (z1, z2, ..., zn, ptjet) + std::vector v(values); + double r = 0; + int nParticles = state.size(); + + if (values.size() != static_cast(nParticles + 1)) { + LOGF(warning, "Number of values (%d) must be equal to the number of particles (%d) + 1!", values.size(), nParticles); + return v; + } + for (int ip = 0; ip < nParticles; ip++) { + if (state[ip] == 0) { + r += values[ip]; + } + } + for (int ip = 0; ip < nParticles; ip++) { + if (state[ip] == 0) { + v[ip] = values[ip] / (1 - r); + } + } + v[nParticles] = values[nParticles] * (1 - r); + return v; + } + // Return the corrected values for z and ptjet for a given state + // Take into account tracks that would have been included in the jet regardless of the V0s + template + std::vector correctedValuesPlusTracks(std::vector state, V const& jet) + { + int ip = 0; + double ptToSubtract = 0., ptToAdd = 0.; + + for (const auto& v0 : jet.template candidates_as()) { + if (v0.isRejectedCandidate()) + continue; + + // Background + if (state[ip] == 0) { + ptToSubtract += v0.pt(); + + // TODO: This is okay in pt-scheme jets, but should add 4-momentum for E-scheme + auto negTrack = v0.template negTrack_as(); + if (jetderiveddatautilities::selectTrack(negTrack, trackSelection) && jetutilities::deltaR(jet, negTrack) < jet.r() * 1e-2) + ptToAdd += negTrack.pt(); + + auto posTrack = v0.template posTrack_as(); + if (jetderiveddatautilities::selectTrack(posTrack, trackSelection) && jetutilities::deltaR(jet, negTrack) < jet.r() * 1e-2) + ptToAdd += posTrack.pt(); + } + ip++; + } + + double ptjet = jet.pt() - ptToSubtract + ptToAdd; + std::vector values; + + ip = 0; + for (const auto& v0 : jet.template candidates_as()) { + if (v0.isRejectedCandidate()) + continue; + + if (state[ip] == 0) // Background + values.push_back(v0.pt() / jet.pt()); + else + values.push_back(v0.pt() / ptjet); + ip++; + } + values.push_back(ptjet); + return values; + } + + // --------------------------------------------------- + // Helper functions + // --------------------------------------------------- + template + bool jetContainsV0s(JetType const& jet) + { + return (jet.candidatesIds().size() > 0); + } + template + bool v0sAreMatched(T const& v0, U const& particle, V const& /*tracks*/) + { + // FIXME: Should this check whether V0 is selected as correct species? Probably! + auto negId = v0.template negTrack_as().mcParticleId(); + auto posId = v0.template posTrack_as().mcParticleId(); + auto daughters = particle.daughtersIds(); + return ((negId == daughters[0] && posId == daughters[1]) || (posId == daughters[0] && negId == daughters[1])); + } + template + double getReflectedMass(V0Type const& v0, bool isLambda) + { + // If V0 is Lambda, posTrack = proton, negTrack = pion + // In that case, we assign pion mass to posTrack and proton mass to negTrack to calculate the reflection + // Vice versa for AntiLambda + double negM = (isLambda ? constants::physics::MassProton : constants::physics::MassPionCharged); + double posM = (isLambda ? constants::physics::MassPionCharged : constants::physics::MassProton); + double negPsq = v0.pxneg() * v0.pxneg() + v0.pyneg() * v0.pyneg() + v0.pzneg() * v0.pzneg(); + double posPsq = v0.pxpos() * v0.pxpos() + v0.pypos() * v0.pypos() + v0.pzpos() * v0.pzpos(); + double negE = std::sqrt(negM * negM + negPsq); + double posE = std::sqrt(posM * posM + posPsq); + double Esquared = (negE + posE) * (negE + posE); + double psquared = v0.p() * v0.p(); + return std::sqrt(Esquared - psquared); + } + template + double getMomFrac(Jet const& jet, Constituent const& constituent) + { + if (jet.pt() < 1e-5) + return -1.; + else + return constituent.pt() / jet.pt(); + } + template + double getMomProj(Jet const& jet, Constituent const& constituent) + { + if (jet.p() < 1e-5) + return -1.; + + double trackProj = constituent.px() * jet.px() + constituent.py() * jet.py() + constituent.pz() * jet.pz(); + trackProj /= (jet.p() * jet.p()); + return trackProj; + } + + // --------------------------------------------------- + // Histogram filling functions + // --------------------------------------------------- + // Data - Counts + template + void fillDataV0Histograms(CollisionType const& collision, V0Type const& V0s) + { + // Fill histograms unweighted. Hists will be filled with V0 counts + float nV0s = 0; + for (const auto& v0 : V0s) { + if (v0.isRejectedCandidate()) + continue; + + nV0s += 1; + double ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassLambda0; + double ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassLambda0Bar; + double ctauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassK0Short; + + double massDiff = v0.mLambda() - v0.mAntiLambda(); + double massRatio = v0.mAntiLambda() / v0.mLambda(); + double massRelDiff = (v0.mLambda() - v0.mAntiLambda()) / v0.mLambda(); + + registry.fill(HIST("data/V0/V0PtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + registry.fill(HIST("data/V0/V0PtCtau"), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda); + registry.fill(HIST("data/V0/V0PtMass"), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); + registry.fill(HIST("data/V0/V0PtMassWide"), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); + registry.fill(HIST("data/V0/V0PtLambdaMasses"), v0.pt(), massDiff, massRatio, massRelDiff); + registry.fill(HIST("data/V0/V0PtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA()); + registry.fill(HIST("data/V0/V0PtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); + registry.fill(HIST("data/V0/V0PtDCAd"), v0.pt(), v0.dcaV0daughters()); + + registry.fill(HIST("data/V0/V0CutVariation"), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), v0.v0radius(), ctauK0s, v0.v0cosPA(), std::abs(v0.dcapostopv()), std::abs(v0.dcanegtopv()), v0.dcaV0daughters()); + + if (v0.isK0SCandidate()) { + registry.fill(HIST("data/V0/K0SPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + registry.fill(HIST("data/V0/K0SPtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA()); + registry.fill(HIST("data/V0/K0SPtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); + registry.fill(HIST("data/V0/K0SPtDCAd"), v0.pt(), v0.dcaV0daughters()); + + registry.fill(HIST("data/V0/K0SPtCtauMass"), v0.pt(), ctauK0s, v0.mK0Short()); + registry.fill(HIST("data/V0/K0SPtRadiusMass"), v0.pt(), v0.v0radius(), v0.mK0Short()); + registry.fill(HIST("data/V0/K0SPtCosPAMass"), v0.pt(), v0.v0cosPA(), v0.mK0Short()); + registry.fill(HIST("data/V0/K0SPtDCAposMass"), v0.pt(), v0.dcapostopv(), v0.mK0Short()); + registry.fill(HIST("data/V0/K0SPtDCAnegMass"), v0.pt(), v0.dcanegtopv(), v0.mK0Short()); + registry.fill(HIST("data/V0/K0SPtDCAdMass"), v0.pt(), v0.dcaV0daughters(), v0.mK0Short()); + } + if (v0.isLambdaCandidate()) { + registry.fill(HIST("data/V0/LambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + registry.fill(HIST("data/V0/LambdaPtLambdaMasses"), v0.pt(), massDiff, massRatio, massRelDiff); + registry.fill(HIST("data/V0/LambdaPtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA()); + registry.fill(HIST("data/V0/LambdaPtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); + registry.fill(HIST("data/V0/LambdaPtDCAd"), v0.pt(), v0.dcaV0daughters()); + + registry.fill(HIST("data/V0/LambdaPtCtauMass"), v0.pt(), ctauLambda, v0.mLambda()); + registry.fill(HIST("data/V0/LambdaPtRadiusMass"), v0.pt(), v0.v0radius(), v0.mLambda()); + registry.fill(HIST("data/V0/LambdaPtCosPAMass"), v0.pt(), v0.v0cosPA(), v0.mLambda()); + registry.fill(HIST("data/V0/LambdaPtDCAposMass"), v0.pt(), v0.dcapostopv(), v0.mLambda()); + registry.fill(HIST("data/V0/LambdaPtDCAnegMass"), v0.pt(), v0.dcanegtopv(), v0.mLambda()); + registry.fill(HIST("data/V0/LambdaPtDCAdMass"), v0.pt(), v0.dcaV0daughters(), v0.mLambda()); + } + if (v0.isAntiLambdaCandidate()) { + registry.fill(HIST("data/V0/AntiLambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + registry.fill(HIST("data/V0/AntiLambdaPtLambdaMasses"), v0.pt(), massDiff, massRatio, massRelDiff); + registry.fill(HIST("data/V0/AntiLambdaPtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA()); + registry.fill(HIST("data/V0/AntiLambdaPtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); + registry.fill(HIST("data/V0/AntiLambdaPtDCAd"), v0.pt(), v0.dcaV0daughters()); + + registry.fill(HIST("data/V0/AntiLambdaPtCtauMass"), v0.pt(), ctauAntiLambda, v0.mAntiLambda()); + registry.fill(HIST("data/V0/AntiLambdaPtRadiusMass"), v0.pt(), v0.v0radius(), v0.mAntiLambda()); + registry.fill(HIST("data/V0/AntiLambdaPtCosPAMass"), v0.pt(), v0.v0cosPA(), v0.mAntiLambda()); + registry.fill(HIST("data/V0/AntiLambdaPtDCAposMass"), v0.pt(), v0.dcapostopv(), v0.mAntiLambda()); + registry.fill(HIST("data/V0/AntiLambdaPtDCAnegMass"), v0.pt(), v0.dcanegtopv(), v0.mAntiLambda()); + registry.fill(HIST("data/V0/AntiLambdaPtDCAdMass"), v0.pt(), v0.dcaV0daughters(), v0.mAntiLambda()); + } + } // for v0 + registry.fill(HIST("data/V0/nV0sEventAcc"), nV0s); + } + template + void fillDataJetHistograms(T const& jet) + { + registry.fill(HIST("data/jets/jetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi()); + } + template + void fillDataV0FragHistograms(CollisionType const& collision, JetType const& jet, V0Type const& v0) + { + double trackProj = getMomFrac(jet, v0); + double ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassLambda0; + double ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassLambda0Bar; + double ctauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassK0Short; + + double massDiff = v0.mLambda() - v0.mAntiLambda(); + double massRatio = v0.mAntiLambda() / v0.mLambda(); + double massRelDiff = (v0.mLambda() - v0.mAntiLambda()) / v0.mLambda(); + + registry.fill(HIST("data/jets/V0/jetPtV0PtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi()); + registry.fill(HIST("data/jets/V0/jetPtV0PtCtau"), jet.pt(), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda); + registry.fill(HIST("data/jets/V0/jetPtV0PtMass"), jet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtV0PtMassWide"), jet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtV0PtLambdaMasses"), jet.pt(), v0.pt(), massDiff, massRatio, massRelDiff); + registry.fill(HIST("data/jets/V0/jetPtV0PtRadiusCosPA"), jet.pt(), v0.pt(), v0.v0radius(), v0.v0cosPA()); + registry.fill(HIST("data/jets/V0/jetPtV0PtDCAposneg"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); + registry.fill(HIST("data/jets/V0/jetPtV0PtDCAd"), jet.pt(), v0.pt(), v0.dcaV0daughters()); + + registry.fill(HIST("data/jets/V0/jetPtV0TrackProj"), jet.pt(), trackProj); + registry.fill(HIST("data/jets/V0/jetPtV0TrackProjCtau"), jet.pt(), trackProj, ctauK0s, ctauLambda, ctauAntiLambda); + registry.fill(HIST("data/jets/V0/jetPtV0TrackProjMass"), jet.pt(), trackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtV0TrackProjMassWide"), jet.pt(), trackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtV0TrackProjLambdaMasses"), jet.pt(), trackProj, massDiff, massRatio, massRelDiff); + registry.fill(HIST("data/jets/V0/jetPtV0TrackProjRadiusCosPA"), jet.pt(), trackProj, v0.v0radius(), v0.v0cosPA()); + registry.fill(HIST("data/jets/V0/jetPtV0TrackProjDCAposneg"), jet.pt(), trackProj, v0.dcapostopv(), v0.dcanegtopv()); + registry.fill(HIST("data/jets/V0/jetPtV0TrackProjDCAd"), jet.pt(), trackProj, v0.dcaV0daughters()); + + if (v0.isK0SCandidate()) { + registry.fill(HIST("data/jets/V0/jetPtK0SPtCtau"), jet.pt(), v0.pt(), ctauK0s); + registry.fill(HIST("data/jets/V0/jetPtK0SPtMass"), jet.pt(), v0.pt(), v0.mK0Short()); + registry.fill(HIST("data/jets/V0/jetPtK0SPtAllMasses"), jet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtK0SPtRadius"), jet.pt(), v0.pt(), v0.v0radius()); + registry.fill(HIST("data/jets/V0/jetPtK0SPtCosPA"), jet.pt(), v0.pt(), v0.v0cosPA()); + registry.fill(HIST("data/jets/V0/jetPtK0SPtDCAd"), jet.pt(), v0.pt(), v0.dcaV0daughters()); + registry.fill(HIST("data/jets/V0/jetPtK0SPtDCAposneg"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); + registry.fill(HIST("data/jets/V0/jetPtK0SPtCtauMass"), jet.pt(), v0.pt(), ctauK0s, v0.mK0Short()); + registry.fill(HIST("data/jets/V0/jetPtK0SPtRadiusMass"), jet.pt(), v0.pt(), v0.v0radius(), v0.mK0Short()); + registry.fill(HIST("data/jets/V0/jetPtK0SPtCosPAMass"), jet.pt(), v0.pt(), v0.v0cosPA(), v0.mK0Short()); + registry.fill(HIST("data/jets/V0/jetPtK0SPtDCAposMass"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.mK0Short()); + registry.fill(HIST("data/jets/V0/jetPtK0SPtDCAnegMass"), jet.pt(), v0.pt(), v0.dcanegtopv(), v0.mK0Short()); + registry.fill(HIST("data/jets/V0/jetPtK0SPtDCAdMass"), jet.pt(), v0.pt(), v0.dcaV0daughters(), v0.mK0Short()); + + registry.fill(HIST("data/jets/V0/jetPtK0STrackProjCtau"), jet.pt(), trackProj, ctauK0s); + registry.fill(HIST("data/jets/V0/jetPtK0STrackProjMass"), jet.pt(), trackProj, v0.mK0Short()); + registry.fill(HIST("data/jets/V0/jetPtK0STrackProjAllMasses"), jet.pt(), trackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtK0STrackProjRadius"), jet.pt(), trackProj, v0.v0radius()); + registry.fill(HIST("data/jets/V0/jetPtK0STrackProjCosPA"), jet.pt(), trackProj, v0.v0cosPA()); + registry.fill(HIST("data/jets/V0/jetPtK0STrackProjDCAd"), jet.pt(), trackProj, v0.dcaV0daughters()); + registry.fill(HIST("data/jets/V0/jetPtK0STrackProjDCAposneg"), jet.pt(), trackProj, v0.dcapostopv(), v0.dcanegtopv()); + registry.fill(HIST("data/jets/V0/jetPtK0STrackProjCtauMass"), jet.pt(), trackProj, ctauK0s, v0.mK0Short()); + registry.fill(HIST("data/jets/V0/jetPtK0STrackProjRadiusMass"), jet.pt(), trackProj, v0.v0radius(), v0.mK0Short()); + registry.fill(HIST("data/jets/V0/jetPtK0STrackProjCosPAMass"), jet.pt(), trackProj, v0.v0cosPA(), v0.mK0Short()); + registry.fill(HIST("data/jets/V0/jetPtK0STrackProjDCAposMass"), jet.pt(), trackProj, v0.dcapostopv(), v0.mK0Short()); + registry.fill(HIST("data/jets/V0/jetPtK0STrackProjDCAnegMass"), jet.pt(), trackProj, v0.dcanegtopv(), v0.mK0Short()); + registry.fill(HIST("data/jets/V0/jetPtK0STrackProjDCAdMass"), jet.pt(), trackProj, v0.dcaV0daughters(), v0.mK0Short()); + } + if (v0.isLambdaCandidate()) { + registry.fill(HIST("data/jets/V0/jetPtLambdaPtCtau"), jet.pt(), v0.pt(), ctauLambda); + registry.fill(HIST("data/jets/V0/jetPtLambdaPtMass"), jet.pt(), v0.pt(), v0.mLambda()); + registry.fill(HIST("data/jets/V0/jetPtLambdaPtAllMasses"), jet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtLambdaPtLambdaMasses"), jet.pt(), v0.pt(), massDiff, massRatio, massRelDiff); + registry.fill(HIST("data/jets/V0/jetPtLambdaPtRadius"), jet.pt(), v0.pt(), v0.v0radius()); + registry.fill(HIST("data/jets/V0/jetPtLambdaPtCosPA"), jet.pt(), v0.pt(), v0.v0cosPA()); + registry.fill(HIST("data/jets/V0/jetPtLambdaPtDCAd"), jet.pt(), v0.pt(), v0.dcaV0daughters()); + registry.fill(HIST("data/jets/V0/jetPtLambdaPtDCAposneg"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); + registry.fill(HIST("data/jets/V0/jetPtLambdaPtCtauMass"), jet.pt(), v0.pt(), ctauLambda, v0.mLambda()); + registry.fill(HIST("data/jets/V0/jetPtLambdaPtRadiusMass"), jet.pt(), v0.pt(), v0.v0radius(), v0.mLambda()); + registry.fill(HIST("data/jets/V0/jetPtLambdaPtCosPAMass"), jet.pt(), v0.pt(), v0.v0cosPA(), v0.mLambda()); + registry.fill(HIST("data/jets/V0/jetPtLambdaPtDCAposMass"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.mLambda()); + registry.fill(HIST("data/jets/V0/jetPtLambdaPtDCAnegMass"), jet.pt(), v0.pt(), v0.dcanegtopv(), v0.mLambda()); + registry.fill(HIST("data/jets/V0/jetPtLambdaPtDCAdMass"), jet.pt(), v0.pt(), v0.dcaV0daughters(), v0.mLambda()); + + registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjCtau"), jet.pt(), trackProj, ctauLambda); + registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjMass"), jet.pt(), trackProj, v0.mLambda()); + registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjAllMasses"), jet.pt(), trackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjLambdaMasses"), jet.pt(), trackProj, massDiff, massRatio, massRelDiff); + registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjRadius"), jet.pt(), trackProj, v0.v0radius()); + registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjCosPA"), jet.pt(), trackProj, v0.v0cosPA()); + registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjDCAd"), jet.pt(), trackProj, v0.dcaV0daughters()); + registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjDCAposneg"), jet.pt(), trackProj, v0.dcapostopv(), v0.dcanegtopv()); + registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjCtauMass"), jet.pt(), trackProj, ctauLambda, v0.mLambda()); + registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjRadiusMass"), jet.pt(), trackProj, v0.v0radius(), v0.mLambda()); + registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjCosPAMass"), jet.pt(), trackProj, v0.v0cosPA(), v0.mLambda()); + registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjDCAposMass"), jet.pt(), trackProj, v0.dcapostopv(), v0.mLambda()); + registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjDCAnegMass"), jet.pt(), trackProj, v0.dcanegtopv(), v0.mLambda()); + registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjDCAdMass"), jet.pt(), trackProj, v0.dcaV0daughters(), v0.mLambda()); + } + if (v0.isAntiLambdaCandidate()) { + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtCtau"), jet.pt(), v0.pt(), ctauAntiLambda); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtMass"), jet.pt(), v0.pt(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtAllMasses"), jet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtLambdaMasses"), jet.pt(), v0.pt(), massDiff, massRatio, massRelDiff); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtRadius"), jet.pt(), v0.pt(), v0.v0radius()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtCosPA"), jet.pt(), v0.pt(), v0.v0cosPA()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtDCAd"), jet.pt(), v0.pt(), v0.dcaV0daughters()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtDCAposneg"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtCtauMass"), jet.pt(), v0.pt(), ctauAntiLambda, v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtRadiusMass"), jet.pt(), v0.pt(), v0.v0radius(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtCosPAMass"), jet.pt(), v0.pt(), v0.v0cosPA(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtDCAposMass"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtDCAnegMass"), jet.pt(), v0.pt(), v0.dcanegtopv(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtDCAdMass"), jet.pt(), v0.pt(), v0.dcaV0daughters(), v0.mAntiLambda()); + + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjCtau"), jet.pt(), trackProj, ctauAntiLambda); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjMass"), jet.pt(), trackProj, v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjAllMasses"), jet.pt(), trackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjLambdaMasses"), jet.pt(), trackProj, massDiff, massRatio, massRelDiff); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjRadius"), jet.pt(), trackProj, v0.v0radius()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjCosPA"), jet.pt(), trackProj, v0.v0cosPA()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjDCAd"), jet.pt(), trackProj, v0.dcaV0daughters()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjDCAposneg"), jet.pt(), trackProj, v0.dcapostopv(), v0.dcanegtopv()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjCtauMass"), jet.pt(), trackProj, ctauAntiLambda, v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjRadiusMass"), jet.pt(), trackProj, v0.v0radius(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjCosPAMass"), jet.pt(), trackProj, v0.v0cosPA(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjDCAposMass"), jet.pt(), trackProj, v0.dcapostopv(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjDCAnegMass"), jet.pt(), trackProj, v0.dcanegtopv(), v0.mAntiLambda()); + registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjDCAdMass"), jet.pt(), trackProj, v0.dcaV0daughters(), v0.mAntiLambda()); + } + } + template + void fillDataPerpConeHists(T const& coll, U const& jet, V const& v0s) + { + double perpConeR = jet.r() * 1e-2; + double conePhi[2] = {RecoDecay::constrainAngle(jet.phi() - constants::math::PIHalf, -constants::math::PI), + RecoDecay::constrainAngle(jet.phi() + constants::math::PIHalf, -constants::math::PI)}; + double conePt[2] = {0., 0.}; + int nV0sinCone[2] = {0, 0}; + for (const auto& v0 : v0s) { + // Need to check if v0 passed jet finder selection/preselector cuts + bool v0InCones = false; + double dEta = v0.eta() - jet.eta(); + double dPhi[2] = {RecoDecay::constrainAngle(v0.phi() - conePhi[0], -constants::math::PI), + RecoDecay::constrainAngle(v0.phi() - conePhi[1], -constants::math::PI)}; + for (int i = 0; i < 2; i++) { + if (std::sqrt(dEta * dEta + dPhi[i] * dPhi[i]) < perpConeR) { + conePt[i] += v0.pt(); + nV0sinCone[i]++; + v0InCones = true; + } + } + if (!v0InCones) { + continue; + } + + double ctauLambda = v0.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * constants::physics::MassLambda0; + double ctauAntiLambda = v0.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * constants::physics::MassLambda0Bar; + double ctauK0s = v0.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * constants::physics::MassK0Short; + + registry.fill(HIST("data/PC/JetPtEtaV0Pt"), jet.pt(), jet.eta(), v0.pt()); + registry.fill(HIST("data/PC/V0PtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + registry.fill(HIST("data/PC/V0PtCtau"), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda); + registry.fill(HIST("data/PC/V0PtMass"), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); + registry.fill(HIST("data/PC/V0PtMassWide"), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); + registry.fill(HIST("data/PC/V0PtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA()); + registry.fill(HIST("data/PC/V0PtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); + registry.fill(HIST("data/PC/V0PtDCAd"), v0.pt(), v0.dcaV0daughters()); + + if (v0.isLambdaCandidate()) { + registry.fill(HIST("data/PC/JetPtLambdaPtMass"), jet.pt(), v0.pt(), v0.mLambda()); + + registry.fill(HIST("data/PC/JetPtEtaLambdaPt"), jet.pt(), jet.eta(), v0.pt()); + registry.fill(HIST("data/PC/LambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + registry.fill(HIST("data/PC/LambdaPtCtauMass"), v0.pt(), ctauLambda, v0.mLambda()); + registry.fill(HIST("data/PC/LambdaPtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA()); + registry.fill(HIST("data/PC/LambdaPtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); + registry.fill(HIST("data/PC/LambdaPtDCAd"), v0.pt(), v0.dcaV0daughters()); + } + if (v0.isAntiLambdaCandidate()) { + registry.fill(HIST("data/PC/JetPtAntiLambdaPtMass"), jet.pt(), v0.pt(), v0.mAntiLambda()); + + registry.fill(HIST("data/PC/JetPtEtaAntiLambdaPt"), jet.pt(), jet.eta(), v0.pt()); + registry.fill(HIST("data/PC/AntiLambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + registry.fill(HIST("data/PC/AntiLambdaPtCtauMass"), v0.pt(), ctauAntiLambda, v0.mAntiLambda()); + registry.fill(HIST("data/PC/AntiLambdaPtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA()); + registry.fill(HIST("data/PC/AntiLambdaPtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); + registry.fill(HIST("data/PC/AntiLambdaPtDCAd"), v0.pt(), v0.dcaV0daughters()); + } + if (v0.isK0SCandidate()) { + registry.fill(HIST("data/PC/JetPtK0SPtMass"), jet.pt(), v0.pt(), v0.mK0Short()); + + registry.fill(HIST("data/PC/JetPtEtaK0SPt"), jet.pt(), jet.eta(), v0.pt()); + registry.fill(HIST("data/PC/K0SPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + registry.fill(HIST("data/PC/K0SPtCtauMass"), v0.pt(), ctauK0s, v0.mK0Short()); + registry.fill(HIST("data/PC/K0SPtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA()); + registry.fill(HIST("data/PC/K0SPtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); + registry.fill(HIST("data/PC/K0SPtDCAd"), v0.pt(), v0.dcaV0daughters()); + } + } + // Fill hist for Ncones: nv0s, conePt, coneEta, conePhi + for (int i = 0; i < 2; i++) { + registry.fill(HIST("data/PC/nV0sConePtEta"), nV0sinCone[i], conePt[i], jet.eta()); + registry.fill(HIST("data/PC/ConePtEtaPhi"), conePt[i], jet.eta(), conePhi[i]); + registry.fill(HIST("data/PC/JetPtEtaConePt"), jet.pt(), jet.eta(), conePt[i]); + } + } + // Data - Weighted + template + void fillDataV0HistogramsWeighted(CollisionType const& collision, V0Type const& V0s) + { + // Fill histograms with V0 signal weights + float nV0s = 0; + for (const auto& v0 : V0s) { + if (v0.isRejectedCandidate()) + continue; + + float weight = getV0SignalProb(v0); + nV0s += weight; // Sum weights (purity) of V0s + + double ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassLambda0; + double ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassLambda0Bar; + double ctauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassK0Short; + + double massDiff = v0.mLambda() - v0.mAntiLambda(); + double massRatio = v0.mAntiLambda() / v0.mLambda(); + double massRelDiff = (v0.mLambda() - v0.mAntiLambda()) / v0.mLambda(); + + registry.fill(HIST("data/V0/V0PtEtaPhiWeighted"), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("data/V0/V0PtCtauWeighted"), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda, weight); + registry.fill(HIST("data/V0/V0PtMassWeighted"), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/V0/V0PtMassWideWeighted"), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/V0/V0PtLambdaMassesWeighted"), v0.pt(), massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("data/V0/V0PtRadiusCosPAWeighted"), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("data/V0/V0PtDCAposnegWeighted"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("data/V0/V0PtDCAdWeighted"), v0.pt(), v0.dcaV0daughters(), weight); + + if (v0.isK0SCandidate()) { + registry.fill(HIST("data/V0/K0SPtEtaPhiWeighted"), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("data/V0/K0SPtRadiusCosPAWeighted"), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("data/V0/K0SPtDCAposnegWeighted"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("data/V0/K0SPtDCAdWeighted"), v0.pt(), v0.dcaV0daughters(), weight); + + registry.fill(HIST("data/V0/K0SPtCtauMassWeighted"), v0.pt(), ctauK0s, v0.mK0Short(), weight); + registry.fill(HIST("data/V0/K0SPtRadiusMassWeighted"), v0.pt(), v0.v0radius(), v0.mK0Short(), weight); + registry.fill(HIST("data/V0/K0SPtCosPAMassWeighted"), v0.pt(), v0.v0cosPA(), v0.mK0Short(), weight); + registry.fill(HIST("data/V0/K0SPtDCAposMassWeighted"), v0.pt(), v0.dcapostopv(), v0.mK0Short(), weight); + registry.fill(HIST("data/V0/K0SPtDCAnegMassWeighted"), v0.pt(), v0.dcanegtopv(), v0.mK0Short(), weight); + registry.fill(HIST("data/V0/K0SPtDCAdMassWeighted"), v0.pt(), v0.dcaV0daughters(), v0.mK0Short(), weight); + } + if (v0.isLambdaCandidate()) { + registry.fill(HIST("data/V0/LambdaPtEtaPhiWeighted"), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("data/V0/LambdaPtLambdaMassesWeighted"), v0.pt(), massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("data/V0/LambdaPtRadiusCosPAWeighted"), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("data/V0/LambdaPtDCAposnegWeighted"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("data/V0/LambdaPtDCAdWeighted"), v0.pt(), v0.dcaV0daughters(), weight); + + registry.fill(HIST("data/V0/LambdaPtCtauMassWeighted"), v0.pt(), ctauLambda, v0.mLambda(), weight); + registry.fill(HIST("data/V0/LambdaPtRadiusMassWeighted"), v0.pt(), v0.v0radius(), v0.mLambda(), weight); + registry.fill(HIST("data/V0/LambdaPtCosPAMassWeighted"), v0.pt(), v0.v0cosPA(), v0.mLambda(), weight); + registry.fill(HIST("data/V0/LambdaPtDCAposMassWeighted"), v0.pt(), v0.dcapostopv(), v0.mLambda(), weight); + registry.fill(HIST("data/V0/LambdaPtDCAnegMassWeighted"), v0.pt(), v0.dcanegtopv(), v0.mLambda(), weight); + registry.fill(HIST("data/V0/LambdaPtDCAdMassWeighted"), v0.pt(), v0.dcaV0daughters(), v0.mLambda(), weight); + } + if (v0.isAntiLambdaCandidate()) { + registry.fill(HIST("data/V0/AntiLambdaPtEtaPhiWeighted"), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("data/V0/AntiLambdaPtLambdaMassesWeighted"), v0.pt(), massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("data/V0/AntiLambdaPtRadiusCosPAWeighted"), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("data/V0/AntiLambdaPtDCAposnegWeighted"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("data/V0/AntiLambdaPtDCAdWeighted"), v0.pt(), v0.dcaV0daughters(), weight); + + registry.fill(HIST("data/V0/AntiLambdaPtCtauMassWeighted"), v0.pt(), ctauAntiLambda, v0.mAntiLambda(), weight); + registry.fill(HIST("data/V0/AntiLambdaPtRadiusMassWeighted"), v0.pt(), v0.v0radius(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/V0/AntiLambdaPtCosPAMassWeighted"), v0.pt(), v0.v0cosPA(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/V0/AntiLambdaPtDCAposMassWeighted"), v0.pt(), v0.dcapostopv(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/V0/AntiLambdaPtDCAnegMassWeighted"), v0.pt(), v0.dcanegtopv(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/V0/AntiLambdaPtDCAdMassWeighted"), v0.pt(), v0.dcaV0daughters(), v0.mAntiLambda(), weight); + } + } // for v0 + registry.fill(HIST("data/V0/nV0sEventAccWeighted"), nV0s); + } + void fillDataJetHistogramsWeighted(double jetpt, double jeteta, double jetphi, double weight = 1.) + { + registry.fill(HIST("data/jets/weighted/jetPtEtaPhi"), jetpt, jeteta, jetphi, weight); + } + template + void fillDataV0FragHistogramsWeighted(C const& collision, J const& jet, std::vector state, std::vector values, double weight) + { + double jetpt = values[values.size() - 1]; + int ip = 0; + for (const auto& v0 : jet.template candidates_as()) { + if (v0.isRejectedCandidate()) + continue; + + double z = values[ip]; + ip++; + + double ctauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassK0Short; + double ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassLambda0; + double ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassLambda0Bar; + + double massDiff = v0.mLambda() - v0.mAntiLambda(); + double massRatio = v0.mAntiLambda() / v0.mLambda(); + double massRelDiff = (v0.mLambda() - v0.mAntiLambda()) / v0.mLambda(); + + switch (state[ip]) { + case 0: // Background + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjCtau"), jetpt, z, ctauK0s, ctauLambda, ctauAntiLambda, weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjMass"), jetpt, z, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjRadiusCosPA"), jetpt, z, v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjDCAposneg"), jetpt, z, v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjDCAd"), jetpt, z, v0.dcaV0daughters(), weight); + + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjCtauK0SMass"), jetpt, z, ctauK0s, v0.mK0Short(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjRadiusK0SMass"), jetpt, z, v0.v0radius(), v0.mK0Short(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjCosPAK0SMass"), jetpt, z, v0.v0cosPA(), v0.mK0Short(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjDCAposK0SMass"), jetpt, z, v0.dcapostopv(), v0.mK0Short(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjDCAnegK0SMass"), jetpt, z, v0.dcanegtopv(), v0.mK0Short(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjDCAdK0SMass"), jetpt, z, v0.dcaV0daughters(), v0.mK0Short(), weight); + + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjCtauLambdaMass"), jetpt, z, ctauLambda, v0.mLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjRadiusLambdaMass"), jetpt, z, v0.v0radius(), v0.mLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjCosPALambdaMass"), jetpt, z, v0.v0cosPA(), v0.mLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjDCAposLambdaMass"), jetpt, z, v0.dcapostopv(), v0.mLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjDCAnegLambdaMass"), jetpt, z, v0.dcanegtopv(), v0.mLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjDCAdLambdaMass"), jetpt, z, v0.dcaV0daughters(), v0.mLambda(), weight); + + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjCtauAntiLambdaMass"), jetpt, z, ctauAntiLambda, v0.mAntiLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjRadiusAntiLambdaMass"), jetpt, z, v0.v0radius(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjCosPAAntiLambdaMass"), jetpt, z, v0.v0cosPA(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjDCAposAntiLambdaMass"), jetpt, z, v0.dcapostopv(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjDCAnegAntiLambdaMass"), jetpt, z, v0.dcanegtopv(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtBkgTrackProjDCAdAntiLambdaMass"), jetpt, z, v0.dcaV0daughters(), v0.mAntiLambda(), weight); + break; + case 1: // K0S + registry.fill(HIST("data/jets/weighted/V0/jetPtK0STrackProjMass"), jetpt, z, v0.mK0Short(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtK0STrackProjCtau"), jetpt, z, ctauK0s, weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtK0STrackProjAllMasses"), jetpt, z, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtK0STrackProjRadius"), jetpt, z, v0.v0radius(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtK0STrackProjCosPA"), jetpt, z, v0.v0cosPA(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtK0STrackProjDCAd"), jetpt, z, v0.dcaV0daughters(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtK0STrackProjDCAposneg"), jetpt, z, v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtK0STrackProjCtauMass"), jetpt, z, ctauK0s, v0.mK0Short(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtK0STrackProjRadiusMass"), jetpt, z, v0.v0radius(), v0.mK0Short(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtK0STrackProjCosPAMass"), jetpt, z, v0.v0cosPA(), v0.mK0Short(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtK0STrackProjDCAposMass"), jetpt, z, v0.dcapostopv(), v0.mK0Short(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtK0STrackProjDCAnegMass"), jetpt, z, v0.dcanegtopv(), v0.mK0Short(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtK0STrackProjDCAdMass"), jetpt, z, v0.dcaV0daughters(), v0.mK0Short(), weight); + break; + case 2: // Lambda + registry.fill(HIST("data/jets/weighted/V0/jetPtLambdaTrackProjMass"), jetpt, z, v0.mLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtLambdaTrackProjCtau"), jetpt, z, ctauLambda, weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtLambdaTrackProjAllMasses"), jetpt, z, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtLambdaTrackProjLambdaMasses"), jetpt, z, massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtLambdaTrackProjRadius"), jetpt, z, v0.v0radius(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtLambdaTrackProjCosPA"), jetpt, z, v0.v0cosPA(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtLambdaTrackProjDCAd"), jetpt, z, v0.dcaV0daughters(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtLambdaTrackProjDCAposneg"), jetpt, z, v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtLambdaTrackProjCtauMass"), jetpt, z, ctauLambda, v0.mLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtLambdaTrackProjRadiusMass"), jetpt, z, v0.v0radius(), v0.mLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtLambdaTrackProjCosPAMass"), jetpt, z, v0.v0cosPA(), v0.mLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtLambdaTrackProjDCAposMass"), jetpt, z, v0.dcapostopv(), v0.mLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtLambdaTrackProjDCAnegMass"), jetpt, z, v0.dcanegtopv(), v0.mLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtLambdaTrackProjDCAdMass"), jetpt, z, v0.dcaV0daughters(), v0.mLambda(), weight); + break; + case 3: // AntiLambda + registry.fill(HIST("data/jets/weighted/V0/jetPtAntiLambdaTrackProjMass"), jetpt, z, v0.mAntiLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtAntiLambdaTrackProjCtau"), jetpt, z, ctauAntiLambda, weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtAntiLambdaTrackProjAllMasses"), jetpt, z, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtAntiLambdaTrackProjLambdaMasses"), jetpt, z, massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtAntiLambdaTrackProjRadius"), jetpt, z, v0.v0radius(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtAntiLambdaTrackProjCosPA"), jetpt, z, v0.v0cosPA(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtAntiLambdaTrackProjDCAd"), jetpt, z, v0.dcaV0daughters(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtAntiLambdaTrackProjDCAposneg"), jetpt, z, v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtAntiLambdaTrackProjCtauMass"), jetpt, z, ctauAntiLambda, v0.mAntiLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtAntiLambdaTrackProjRadiusMass"), jetpt, z, v0.v0radius(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtAntiLambdaTrackProjCosPAMass"), jetpt, z, v0.v0cosPA(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtAntiLambdaTrackProjDCAposMass"), jetpt, z, v0.dcapostopv(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtAntiLambdaTrackProjDCAnegMass"), jetpt, z, v0.dcanegtopv(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtAntiLambdaTrackProjDCAdMass"), jetpt, z, v0.dcaV0daughters(), v0.mAntiLambda(), weight); + break; + } + registry.fill(HIST("data/jets/weighted/V0/jetPtV0TrackProjMass"), jetpt, z, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtV0TrackProjCtau"), jetpt, z, ctauK0s, ctauLambda, ctauAntiLambda, weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtV0TrackProjMassWide"), jetpt, z, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtV0TrackProjLambdaMasses"), jetpt, z, massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtV0TrackProjRadiusCosPA"), jetpt, z, v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtV0TrackProjDCAposneg"), jetpt, z, v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("data/jets/weighted/V0/jetPtV0TrackProjDCAd"), jetpt, z, v0.dcaV0daughters(), weight); + } // v0 loop + } + + // MC - Counts (or event weights) + template + void fillMCPV0Histograms(T const& pV0s, double weight = 1.) + { + float nV0s = 0; + for (const auto& pv0 : pV0s) { + int pdg = pv0.pdgCode(); + nV0s += 1; + registry.fill(HIST("mcp/V0/V0PtEtaPhi"), pv0.pt(), pv0.eta(), pv0.phi(), weight); + if (std::abs(pdg) == 310) + registry.fill(HIST("mcp/V0/K0SPtEtaPhi"), pv0.pt(), pv0.eta(), pv0.phi(), weight); + + if (pdg == 3122) + registry.fill(HIST("mcp/V0/LambdaPtEtaPhi"), pv0.pt(), pv0.eta(), pv0.phi(), weight); + + if (pdg == -3122) + registry.fill(HIST("mcp/V0/AntiLambdaPtEtaPhi"), pv0.pt(), pv0.eta(), pv0.phi(), weight); + } + registry.fill(HIST("mcp/V0/nV0sEventAcc"), nV0s); + registry.fill(HIST("mcp/V0/nV0sEventAccWeighted"), nV0s, weight); + } + template + void fillMCPJetHistograms(T const& jet, double weight = 1.) + { + registry.fill(HIST("mcp/jets/partJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi(), weight); + } + template + void fillMCDV0Histograms(T const& coll, U const& V0s, double weight = 1.) + { + float nV0s = 0; + for (const auto& v0 : V0s) { + if (v0.isRejectedCandidate()) + continue; + + nV0s += 1; + double ctauLambda = v0.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * constants::physics::MassLambda0; + double ctauAntiLambda = v0.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * constants::physics::MassLambda0Bar; + double ctauK0s = v0.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * constants::physics::MassK0Short; + + double massDiff = v0.mLambda() - v0.mAntiLambda(); + double massRatio = v0.mAntiLambda() / v0.mLambda(); + double massRelDiff = (v0.mLambda() - v0.mAntiLambda()) / v0.mLambda(); + + registry.fill(HIST("mcd/V0/V0PtEtaPhi"), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("mcd/V0/V0PtCtau"), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda, weight); + registry.fill(HIST("mcd/V0/V0PtMass"), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("mcd/V0/V0PtLambdaMasses"), v0.pt(), v0.mLambda() - v0.mAntiLambda(), v0.mAntiLambda() / v0.mLambda(), (v0.mLambda() - v0.mAntiLambda()) / v0.mLambda(), weight); + registry.fill(HIST("mcd/V0/V0PtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("mcd/V0/V0PtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("mcd/V0/V0PtDCAd"), v0.pt(), v0.dcaV0daughters(), weight); + + if (v0.isK0SCandidate()) { + registry.fill(HIST("mcd/V0/K0SPtEtaPhi"), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("mcd/V0/K0SPtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("mcd/V0/K0SPtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("mcd/V0/K0SPtDCAd"), v0.pt(), v0.dcaV0daughters(), weight); + + registry.fill(HIST("mcd/V0/K0SPtCtauMass"), v0.pt(), ctauK0s, v0.mK0Short(), weight); + registry.fill(HIST("mcd/V0/K0SPtRadiusMass"), v0.pt(), v0.v0radius(), v0.mK0Short(), weight); + registry.fill(HIST("mcd/V0/K0SPtCosPAMass"), v0.pt(), v0.v0cosPA(), v0.mK0Short(), weight); + registry.fill(HIST("mcd/V0/K0SPtDCAposMass"), v0.pt(), v0.dcapostopv(), v0.mK0Short(), weight); + registry.fill(HIST("mcd/V0/K0SPtDCAnegMass"), v0.pt(), v0.dcanegtopv(), v0.mK0Short(), weight); + registry.fill(HIST("mcd/V0/K0SPtDCAdMass"), v0.pt(), v0.dcaV0daughters(), v0.mK0Short(), weight); + } + if (v0.isLambdaCandidate()) { + registry.fill(HIST("mcd/V0/LambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("mcd/V0/LambdaPtLambdaMasses"), v0.pt(), massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("mcd/V0/LambdaPtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("mcd/V0/LambdaPtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("mcd/V0/LambdaPtDCAd"), v0.pt(), v0.dcaV0daughters(), weight); + + registry.fill(HIST("mcd/V0/LambdaPtCtauMass"), v0.pt(), ctauLambda, v0.mLambda(), weight); + registry.fill(HIST("mcd/V0/LambdaPtRadiusMass"), v0.pt(), v0.v0radius(), v0.mLambda(), weight); + registry.fill(HIST("mcd/V0/LambdaPtCosPAMass"), v0.pt(), v0.v0cosPA(), v0.mLambda(), weight); + registry.fill(HIST("mcd/V0/LambdaPtDCAposMass"), v0.pt(), v0.dcapostopv(), v0.mLambda(), weight); + registry.fill(HIST("mcd/V0/LambdaPtDCAnegMass"), v0.pt(), v0.dcanegtopv(), v0.mLambda(), weight); + registry.fill(HIST("mcd/V0/LambdaPtDCAdMass"), v0.pt(), v0.dcaV0daughters(), v0.mLambda(), weight); + } + if (v0.isAntiLambdaCandidate()) { + registry.fill(HIST("mcd/V0/AntiLambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("mcd/V0/AntiLambdaPtLambdaMasses"), v0.pt(), massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("mcd/V0/AntiLambdaPtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("mcd/V0/AntiLambdaPtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("mcd/V0/AntiLambdaPtDCAd"), v0.pt(), v0.dcaV0daughters(), weight); + + registry.fill(HIST("mcd/V0/AntiLambdaPtCtauMass"), v0.pt(), ctauAntiLambda, v0.mAntiLambda(), weight); + registry.fill(HIST("mcd/V0/AntiLambdaPtRadiusMass"), v0.pt(), v0.v0radius(), v0.mAntiLambda(), weight); + registry.fill(HIST("mcd/V0/AntiLambdaPtCosPAMass"), v0.pt(), v0.v0cosPA(), v0.mAntiLambda(), weight); + registry.fill(HIST("mcd/V0/AntiLambdaPtDCAposMass"), v0.pt(), v0.dcapostopv(), v0.mAntiLambda(), weight); + registry.fill(HIST("mcd/V0/AntiLambdaPtDCAnegMass"), v0.pt(), v0.dcanegtopv(), v0.mAntiLambda(), weight); + registry.fill(HIST("mcd/V0/AntiLambdaPtDCAdMass"), v0.pt(), v0.dcaV0daughters(), v0.mAntiLambda(), weight); + } + } // for v0 + registry.fill(HIST("mcd/V0/nV0sEventAcc"), nV0s); + registry.fill(HIST("mcd/V0/nV0sEventAccWeighted"), nV0s, weight); + } + template + void fillMCDJetHistograms(T const& jet, double weight = 1.) + { + registry.fill(HIST("mcd/jets/detJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi(), weight); + } + // Reconstructed V0s in the cone of MCD jets + template + void fillMcPerpConeHists(T const& coll, U const& mcdjet, V const& v0s, W const& /* V0 particles */, double weight = 1.) + { + double perpConeR = mcdjet.r() * 1e-2; + double conePhi[2] = {RecoDecay::constrainAngle(mcdjet.phi() - constants::math::PIHalf, -constants::math::PI), + RecoDecay::constrainAngle(mcdjet.phi() + constants::math::PIHalf, -constants::math::PI)}; + double coneMatchedPt[2] = {0., 0.}; + double coneFakePt[2] = {0., 0.}; + int nMatchedV0sinCone[2] = {0, 0}; + int nFakeV0sinCone[2] = {0, 0}; + + for (const auto& v0 : v0s) { + double dEta = v0.eta() - mcdjet.eta(); + double dPhi[2] = {RecoDecay::constrainAngle(v0.phi() - conePhi[0], -constants::math::PI), + RecoDecay::constrainAngle(v0.phi() - conePhi[1], -constants::math::PI)}; + for (int i = 0; i < 2; i++) { + if (std::sqrt(dEta * dEta + dPhi[i] * dPhi[i]) > perpConeR) { + continue; + } + + double ctauLambda = v0.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * constants::physics::MassLambda0; + double ctauAntiLambda = v0.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * constants::physics::MassLambda0Bar; + double ctauK0s = v0.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * constants::physics::MassK0Short; + + if (!v0.has_mcParticle()) { // The V0 is combinatorial background + coneFakePt[i] += v0.pt(); + nFakeV0sinCone[i]++; + registry.fill(HIST("mcd/PC/jetPtEtaFakeV0Pt"), mcdjet.pt(), mcdjet.eta(), v0.pt(), weight); + + registry.fill(HIST("mcd/PC/fakeV0PtEtaPhi"), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("mcd/PC/fakeV0PtCtau"), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda, weight); + registry.fill(HIST("mcd/PC/fakeV0PtMass"), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("mcd/PC/fakeV0PtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("mcd/PC/fakeV0PtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("mcd/PC/fakeV0PtDCAd"), v0.pt(), v0.dcaV0daughters(), weight); + } else { + coneMatchedPt[i] += v0.pt(); + nMatchedV0sinCone[i]++; + registry.fill(HIST("mcd/PC/jetPtEtaMatchedV0Pt"), mcdjet.pt(), mcdjet.eta(), v0.pt(), weight); + + registry.fill(HIST("mcd/PC/matchedV0PtEtaPhi"), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("mcd/PC/matchedV0PtCtau"), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda, weight); + registry.fill(HIST("mcd/PC/matchedV0PtMass"), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("mcd/PC/matchedV0PtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("mcd/PC/matchedV0PtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("mcd/PC/matchedV0PtDCAd"), v0.pt(), v0.dcaV0daughters(), weight); + + auto particle = v0.template mcParticle_as(); + if (std::abs(particle.pdgCode()) == 310) { // K0S + registry.fill(HIST("mcd/PC/matchedJetPtK0SPtMass"), mcdjet.pt(), v0.pt(), v0.mK0Short(), weight); + } else if (particle.pdgCode() == 3122) { // Lambda + registry.fill(HIST("mcd/PC/matchedJetPtLambdaPtMass"), mcdjet.pt(), v0.pt(), v0.mLambda(), weight); + } else if (particle.pdgCode() == -3122) { + registry.fill(HIST("mcd/PC/matchedJetPtAntiLambdaPtMass"), mcdjet.pt(), v0.pt(), v0.mAntiLambda(), weight); + } + } // if v0 has mcParticle + } // for cone + } // for v0s + for (int i = 0; i < 2; i++) { + registry.fill(HIST("mcd/PC/matchednV0sConePtEta"), nMatchedV0sinCone[i], coneMatchedPt[i], mcdjet.eta(), weight); + registry.fill(HIST("mcd/PC/matchedConePtEtaPhi"), coneMatchedPt[i], mcdjet.eta(), conePhi[i], weight); + registry.fill(HIST("mcd/PC/matchedJetPtEtaConePt"), mcdjet.pt(), mcdjet.eta(), coneMatchedPt[i], weight); + + registry.fill(HIST("mcd/PC/fakenV0sConePtEta"), nFakeV0sinCone[i], coneFakePt[i], mcdjet.eta(), weight); + registry.fill(HIST("mcd/PC/fakeConePtEtaPhi"), coneFakePt[i], mcdjet.eta(), conePhi[i], weight); + registry.fill(HIST("mcd/PC/fakeJetPtEtaConePt"), mcdjet.pt(), mcdjet.eta(), coneFakePt[i], weight); + } + } + // Reconstructed V0s in the cone of matched jets + template + void fillMcPerpConeHists(T const& coll, U const& mcdjet, V const& mcpjet, W const& v0s, X const& /* V0 particles */, double weight = 1.) + { + double perpConeR = mcdjet.r() * 1e-2; + double conePhi[2] = {RecoDecay::constrainAngle(mcdjet.phi() - constants::math::PIHalf, -constants::math::PI), + RecoDecay::constrainAngle(mcdjet.phi() + constants::math::PIHalf, -constants::math::PI)}; + double coneMatchedPt[2] = {0., 0.}; + double coneFakePt[2] = {0., 0.}; + int nMatchedV0sinCone[2] = {0, 0}; + int nFakeV0sinCone[2] = {0, 0}; + + for (const auto& v0 : v0s) { + double dEta = v0.eta() - mcdjet.eta(); + double dPhi[2] = {RecoDecay::constrainAngle(v0.phi() - conePhi[0], -constants::math::PI), + RecoDecay::constrainAngle(v0.phi() - conePhi[1], -constants::math::PI)}; + for (int i = 0; i < 2; i++) { + if (std::sqrt(dEta * dEta + dPhi[i] * dPhi[i]) > perpConeR) { + continue; + } + + double ctauLambda = v0.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * constants::physics::MassLambda0; + double ctauAntiLambda = v0.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * constants::physics::MassLambda0Bar; + double ctauK0s = v0.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * constants::physics::MassK0Short; + + if (!v0.has_mcParticle()) { // The V0 is combinatorial background + coneFakePt[i] += v0.pt(); + nFakeV0sinCone[i]++; + registry.fill(HIST("matching/PC/jetPtEtaFakeV0Pt"), mcdjet.pt(), mcdjet.eta(), v0.pt(), weight); + registry.fill(HIST("matching/PC/jetsPtFakeV0Pt"), mcpjet.pt(), mcdjet.pt(), v0.pt(), weight); + + registry.fill(HIST("matching/PC/fakeV0PtEtaPhi"), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("matching/PC/fakeV0PtCtau"), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda, weight); + registry.fill(HIST("matching/PC/fakeV0PtMass"), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/PC/fakeV0PtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/PC/fakeV0PtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/PC/fakeV0PtDCAd"), v0.pt(), v0.dcaV0daughters(), weight); + } else { + coneMatchedPt[i] += v0.pt(); + nMatchedV0sinCone[i]++; + registry.fill(HIST("matching/PC/jetPtEtaMatchedV0Pt"), mcdjet.pt(), mcdjet.eta(), v0.pt(), weight); + registry.fill(HIST("matching/PC/jetsPtMatchedV0Pt"), mcpjet.pt(), mcdjet.pt(), v0.pt(), weight); + + registry.fill(HIST("matching/PC/matchedV0PtEtaPhi"), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("matching/PC/matchedV0PtCtau"), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda, weight); + registry.fill(HIST("matching/PC/matchedV0PtMass"), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/PC/matchedV0PtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/PC/matchedV0PtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/PC/matchedV0PtDCAd"), v0.pt(), v0.dcaV0daughters(), weight); + + auto particle = v0.template mcParticle_as(); + if (std::abs(particle.pdgCode()) == 310) { // K0S + registry.fill(HIST("matching/PC/matchedJetPtK0SPtMass"), mcdjet.pt(), v0.pt(), v0.mK0Short(), weight); + registry.fill(HIST("matching/PC/matchedJetsPtK0SPtMass"), mcpjet.pt(), mcdjet.pt(), v0.pt(), v0.mK0Short(), weight); + } else if (particle.pdgCode() == 3122) { // Lambda + registry.fill(HIST("matching/PC/matchedJetPtLambdaPtMass"), mcdjet.pt(), v0.pt(), v0.mLambda(), weight); + registry.fill(HIST("matching/PC/matchedJetsPtLambdaPtMass"), mcpjet.pt(), mcdjet.pt(), v0.pt(), v0.mLambda(), weight); + } else if (particle.pdgCode() == -3122) { + registry.fill(HIST("matching/PC/matchedJetPtAntiLambdaPtMass"), mcdjet.pt(), v0.pt(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/PC/matchedJetsPtAntiLambdaPtMass"), mcpjet.pt(), mcdjet.pt(), v0.pt(), v0.mAntiLambda(), weight); + } + } // if v0 has mcParticle + } // for cone + } // for v0s + for (int i = 0; i < 2; i++) { + registry.fill(HIST("matching/PC/matchednV0sConePtEta"), nMatchedV0sinCone[i], coneMatchedPt[i], mcdjet.eta(), weight); + registry.fill(HIST("matching/PC/matchedConePtEtaPhi"), coneMatchedPt[i], mcdjet.eta(), conePhi[i], weight); + registry.fill(HIST("matching/PC/matchedJetPtEtaConePt"), mcdjet.pt(), mcdjet.eta(), coneMatchedPt[i], weight); + registry.fill(HIST("matching/PC/matchedJetsPtEtaConePt"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), coneMatchedPt[i], weight); + + registry.fill(HIST("matching/PC/fakenV0sConePtEta"), nFakeV0sinCone[i], coneFakePt[i], mcdjet.eta(), weight); + registry.fill(HIST("matching/PC/fakeConePtEtaPhi"), coneFakePt[i], mcdjet.eta(), conePhi[i], weight); + registry.fill(HIST("matching/PC/fakeJetPtEtaConePt"), mcdjet.pt(), mcdjet.eta(), coneFakePt[i], weight); + registry.fill(HIST("matching/PC/fakeJetsPtEtaConePt"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), coneFakePt[i], weight); + } + } + // Matched - Counts (or event weights) + template // Reconstructed signal for inclusive V0s + void fillMatchingV0Histograms(CollisionType const& collision, V0Type const& v0, particleType const& particle, double weight = 1.) + { + double ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassLambda0; + double ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassLambda0Bar; + double ctauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassK0Short; + + registry.fill(HIST("matching/V0/V0PartPtDetPt"), particle.pt(), v0.pt(), weight); + registry.fill(HIST("matching/V0/V0PartPtRatioPtRelDiffPt"), particle.pt(), v0.pt() / particle.pt(), (v0.pt() - particle.pt()) / particle.pt(), weight); + + if (std::abs(particle.pdgCode()) == 310) { // K0S + registry.fill(HIST("matching/V0/K0SPtEtaPhi"), particle.pt(), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("matching/V0/K0SPtCtauMass"), particle.pt(), v0.pt(), ctauK0s, v0.mK0Short(), weight); + registry.fill(HIST("matching/V0/K0SPtRadiusCosPA"), particle.pt(), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/V0/K0SPtDCAposneg"), particle.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/V0/K0SPtDCAd"), particle.pt(), v0.pt(), v0.dcaV0daughters(), weight); + registry.fill(HIST("matching/V0/K0SPtMass"), particle.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + } else if (particle.pdgCode() == 3122) { // Lambda + registry.fill(HIST("matching/V0/LambdaPtEtaPhi"), particle.pt(), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("matching/V0/LambdaPtCtauMass"), particle.pt(), v0.pt(), ctauLambda, v0.mLambda(), weight); + registry.fill(HIST("matching/V0/LambdaPtRadiusCosPA"), particle.pt(), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/V0/LambdaPtDCAposneg"), particle.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/V0/LambdaPtDCAd"), particle.pt(), v0.pt(), v0.dcaV0daughters(), weight); + registry.fill(HIST("matching/V0/LambdaPtMass"), particle.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + + // Reflection + double reflectedMass = getReflectedMass(v0, true); + registry.fill(HIST("matching/V0/LambdaReflection"), particle.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), reflectedMass, weight); + } else if (particle.pdgCode() == -3122) { // AntiLambda + registry.fill(HIST("matching/V0/AntiLambdaPtEtaPhi"), particle.pt(), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("matching/V0/AntiLambdaPtCtauMass"), particle.pt(), v0.pt(), ctauAntiLambda, v0.mAntiLambda(), weight); + registry.fill(HIST("matching/V0/AntiLambdaPtRadiusCosPA"), particle.pt(), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/V0/AntiLambdaPtDCAposneg"), particle.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/V0/AntiLambdaPtDCAd"), particle.pt(), v0.pt(), v0.dcaV0daughters(), weight); + registry.fill(HIST("matching/V0/AntiLambdaPtMass"), particle.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + + // Reflection + double reflectedMass = getReflectedMass(v0, false); + registry.fill(HIST("matching/V0/AntiLambdaReflection"), particle.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), reflectedMass, weight); + } + } + template // Reconstructed signal for inclusive V0s: daughters + void fillMatchingV0DauHistograms(V0Type const& v0, ParticleType const& pv0, double weight = 1.) + { + auto negTrack = v0.template negTrack_as(); + auto posTrack = v0.template posTrack_as(); + auto negPart = negTrack.template mcParticle_as(); + auto posPart = posTrack.template mcParticle_as(); + registry.fill(HIST("matching/V0/V0PosPartPtRatioPtRelDiffPt"), posPart.pt(), posTrack.pt() / posPart.pt(), (posTrack.pt() - posPart.pt()) / posPart.pt(), weight); + registry.fill(HIST("matching/V0/V0NegPartPtRatioPtRelDiffPt"), negPart.pt(), negTrack.pt() / negPart.pt(), (negTrack.pt() - negPart.pt()) / negPart.pt(), weight); + + if (std::abs(v0.pdgCode()) == 310) { // K0S + registry.fill(HIST("matching/V0/K0SPosNegPtMass"), pv0.pt(), posPart.pt(), negPart.pt(), v0.mK0Short(), weight); + } else if (v0.pdgCode() == 3122) { // Lambda + registry.fill(HIST("matching/V0/LambdaPosNegPtMass"), pv0.pt(), posPart.pt(), negPart.pt(), v0.mLambda(), weight); + } else if (v0.pdgCode() == -3122) { // AntiLambda + registry.fill(HIST("matching/V0/AntiLambdaPosNegPtMass"), pv0.pt(), posPart.pt(), negPart.pt(), v0.mAntiLambda(), weight); + } + } + template // Reconstructed jets + void fillMatchingHistogramsJet(DetJet const& detJet, PartJet const& partJet, double weight = 1.) + { + double deltaEta = detJet.eta() - partJet.eta(); + double deltaPhi = RecoDecay::constrainAngle(detJet.phi() - partJet.phi(), -constants::math::PI); + double dR = jetutilities::deltaR(detJet, partJet); + + registry.fill(HIST("matching/jets/matchDetJetPtEtaPhi"), detJet.pt(), detJet.eta(), detJet.phi(), weight); + registry.fill(HIST("matching/jets/matchPartJetPtEtaPhi"), partJet.pt(), partJet.eta(), partJet.phi(), weight); + registry.fill(HIST("matching/jets/matchPartJetPtEtaPhiMatchDist"), partJet.pt(), partJet.eta(), partJet.phi(), dR, weight); + registry.fill(HIST("matching/jets/matchPartJetPtEnergyScale"), partJet.pt(), detJet.pt() / partJet.pt(), weight); + registry.fill(HIST("matching/jets/matchDetJetPtPartJetPt"), detJet.pt(), partJet.pt(), weight); + registry.fill(HIST("matching/jets/matchPartJetPtDetJetEtaPartJetEta"), partJet.pt(), detJet.eta(), partJet.eta(), weight); + registry.fill(HIST("matching/jets/matchPartJetPtDetJetPhiPartJetPhi"), partJet.pt(), detJet.phi(), partJet.phi(), weight); + registry.fill(HIST("matching/jets/matchPartJetPtResolutionPt"), partJet.pt(), (detJet.pt() - partJet.pt()), weight); + registry.fill(HIST("matching/jets/matchPartJetPtResolutionEta"), partJet.pt(), partJet.eta(), deltaEta, weight); + registry.fill(HIST("matching/jets/matchPartJetPtResolutionPhi"), partJet.pt(), partJet.phi(), deltaPhi, weight); + registry.fill(HIST("matching/jets/matchPartJetPtRelDiffPt"), partJet.pt(), (detJet.pt() - partJet.pt()) / partJet.pt(), weight); + } + template // Reconstructed signal for in-jet V0s + void fillMatchingV0FragHistograms(CollisionType const& collision, DetJetType const& detJet, PartJetType const& partJet, V0Type const& v0, ParticleType const& particle, double weight = 1.) + { + double detTrackProj = getMomFrac(detJet, v0); + double partTrackProj = getMomFrac(partJet, particle); + + double ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassLambda0; + double ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassLambda0Bar; + double ctauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassK0Short; + + registry.fill(HIST("matching/jets/V0/matchDetJetPtV0TrackProjPartJetPtV0TrackProj"), detJet.pt(), detTrackProj, partJet.pt(), partTrackProj, weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0Pt"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetPt"), partJet.pt(), particle.pt(), detJet.pt(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtDetJetPtPartV0PtRatioPtRelDiffPt"), partJet.pt(), detJet.pt(), particle.pt(), v0.pt() / particle.pt(), (v0.pt() - particle.pt()) / particle.pt(), weight); + + registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtCtauLambda"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauLambda, weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtCtauAntiLambda"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauAntiLambda, weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtCtauK0S"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauK0s, weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtMassLambda"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtMassAntiLambda"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtMassK0S"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtRadius"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.v0radius(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtCosPA"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtDCAposneg"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtDCAd"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.dcaV0daughters(), weight); + + registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjCtauLambda"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauLambda, weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjCtauAntiLambda"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauAntiLambda, weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjCtauK0S"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauK0s, weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjMassLambda"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjMassAntiLambda"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjMassK0S"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjRadius"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.v0radius(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjCosPA"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.v0cosPA(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjDCAposneg"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjDCAd"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.dcaV0daughters(), weight); + + if (std::abs(particle.pdgCode()) == 310) { // K0S + registry.fill(HIST("matching/jets/V0/matchDetJetPtK0STrackProjPartJetPtK0STrackProj"), detJet.pt(), detTrackProj, partJet.pt(), partTrackProj, weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPt"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), weight); + + registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtCtauLambda"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauLambda, weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtCtauAntiLambda"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauAntiLambda, weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtCtauK0S"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauK0s, weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtMassLambda"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtMassAntiLambda"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtMassK0S"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtAllMasses"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtRadius"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.v0radius(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtCosPA"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtDCAposneg"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtDCAd"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.dcaV0daughters(), weight); + + registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjCtauLambda"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauLambda, weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjCtauAntiLambda"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauAntiLambda, weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjCtauK0S"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauK0s, weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjMassLambda"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjMassAntiLambda"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjMassK0S"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjAllMasses"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjRadius"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.v0radius(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjCosPA"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.v0cosPA(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjDCAposneg"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjDCAd"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.dcaV0daughters(), weight); + } else if (particle.pdgCode() == 3122) { // Lambda + registry.fill(HIST("matching/jets/V0/matchDetJetPtLambdaTrackProjPartJetPtLambdaTrackProj"), detJet.pt(), detTrackProj, partJet.pt(), partTrackProj, weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPt"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), weight); + + registry.fill(HIST("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtCtauLambda"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauLambda, weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtCtauAntiLambda"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauAntiLambda, weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtCtauK0S"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauK0s, weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtMassLambda"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtMassAntiLambda"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtMassK0S"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtAllMasses"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtRadius"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.v0radius(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtCosPA"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtDCAposneg"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtDCAd"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.dcaV0daughters(), weight); + + registry.fill(HIST("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjCtauLambda"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauLambda, weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjCtauAntiLambda"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauAntiLambda, weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjCtauK0S"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauK0s, weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjMassLambda"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjMassAntiLambda"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjMassK0S"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjAllMasses"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjRadius"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.v0radius(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjCosPA"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.v0cosPA(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjDCAposneg"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjDCAd"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.dcaV0daughters(), weight); + + // Reflection + double reflectedMass = getReflectedMass(v0, true); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtLambdaReflection"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), reflectedMass, weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjLambdaReflection"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), reflectedMass, weight); + } else if (particle.pdgCode() == -3122) { // AntiLambda + registry.fill(HIST("matching/jets/V0/matchDetJetPtAntiLambdaTrackProjPartJetPtAntiLambdaTrackProj"), detJet.pt(), detTrackProj, partJet.pt(), partTrackProj, weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPt"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), weight); + + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtCtauLambda"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauLambda, weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtCtauAntiLambda"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauAntiLambda, weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtCtauK0S"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauK0s, weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtMassLambda"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtMassAntiLambda"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtMassK0S"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtAllMasses"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtRadius"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.v0radius(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtCosPA"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtDCAposneg"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtDCAd"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.dcaV0daughters(), weight); + + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjCtauLambda"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauLambda, weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjCtauAntiLambda"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauAntiLambda, weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjCtauK0S"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauK0s, weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjMassLambda"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjMassAntiLambda"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjMassK0S"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjAllMasses"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjRadius"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.v0radius(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjCosPA"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.v0cosPA(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjDCAposneg"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjDCAd"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.dcaV0daughters(), weight); + + // Reflection + double reflectedMass = getReflectedMass(v0, false); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtAntiLambdaReflection"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), reflectedMass, weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjAntiLambdaReflection"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), reflectedMass, weight); + } // AntiLambda + } + template // Reconstructed signal for in-jet V0s: daughters + void fillMatchingV0DauJetHistograms(DetJetType const& detJet, PartJetType const& partJet, V0Type const& v0, ParticleType const& particle, double weight = 1.) + { + auto negTrack = v0.template negTrack_as(); + auto posTrack = v0.template posTrack_as(); + auto negPart = negTrack.template mcParticle_as(); + auto posPart = posTrack.template mcParticle_as(); + registry.fill(HIST("matching/jets/V0/partJetPtDetJetPtPartV0PtPosPtRatioPtRelDiffPt"), partJet.pt(), detJet.pt(), particle.pt(), posPart.pt(), posTrack.pt() / posPart.pt(), (posTrack.pt() - posPart.pt()) / posPart.pt(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtDetJetPtPartV0PtNegPtRatioPtRelDiffPt"), partJet.pt(), detJet.pt(), particle.pt(), negPart.pt(), negTrack.pt() / negPart.pt(), (negTrack.pt() - negPart.pt()) / negPart.pt(), weight); + } + // Misses - Counts (or event weights) + template // Missed inclusive V0s + void fillMatchingMissV0Histograms(T const& pv0, double weight = 1.) + { + int pdg = pv0.pdgCode(); + registry.fill(HIST("matching/V0/missV0PtEtaPhi"), pv0.pt(), pv0.eta(), pv0.phi(), weight); + if (std::abs(pdg) == 310) { // K0S + registry.fill(HIST("matching/V0/missK0SPtEtaPhi"), pv0.pt(), pv0.eta(), pv0.phi(), weight); + } else if (pdg == 3122) { // Lambda + registry.fill(HIST("matching/V0/missLambdaPtEtaPhi"), pv0.pt(), pv0.eta(), pv0.phi(), weight); + } else if (pdg == -3122) { // AntiLambda + registry.fill(HIST("matching/V0/missAntiLambdaPtEtaPhi"), pv0.pt(), pv0.eta(), pv0.phi(), weight); + } + } + template // Missed V0s in jets + void fillMatchingV0Miss(JetType const& jet, V0Type const& v0, double weight = 1.) + { + double trackProj = getMomFrac(jet, v0); + + registry.fill(HIST("matching/jets/V0/missJetPtV0TrackProj"), jet.pt(), trackProj, weight); + registry.fill(HIST("matching/jets/V0/missJetPtV0PtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi(), weight); + if (std::abs(v0.pdgCode()) == 310) { // K0S + registry.fill(HIST("matching/jets/V0/missJetPtK0SPtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("matching/jets/V0/missJetPtK0STrackProj"), jet.pt(), trackProj, weight); + } else if (v0.pdgCode() == 3122) { // Lambda + registry.fill(HIST("matching/jets/V0/missJetPtLambdaPtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("matching/jets/V0/missJetPtLambdaTrackProj"), jet.pt(), trackProj, weight); + } else if (v0.pdgCode() == -3122) { // AntiLambda + registry.fill(HIST("matching/jets/V0/missJetPtAntiLambdaPtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("matching/jets/V0/missJetPtAntiLambdaTrackProj"), jet.pt(), trackProj, weight); + } + } + // Fakes - Counts (or event weights) + template // Fake inclusive V0s + void fillMatchingV0FakeHistograms(T const& coll, U const& v0, double weight = 1.) + { + double ctauLambda = v0.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * constants::physics::MassLambda0; + double ctauAntiLambda = v0.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * constants::physics::MassLambda0Bar; + double ctauK0s = v0.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * constants::physics::MassK0Short; + + double massDiff = v0.mLambda() - v0.mAntiLambda(); + double massRatio = v0.mAntiLambda() / v0.mLambda(); + double massRelDiff = (v0.mLambda() - v0.mAntiLambda()) / v0.mLambda(); + + registry.fill(HIST("matching/V0/fakeV0PtEtaPhi"), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("matching/V0/fakeV0PtCtau"), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda, weight); + registry.fill(HIST("matching/V0/fakeV0PtMass"), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/V0/fakeV0PtLambdaMasses"), v0.pt(), v0.mLambda() - v0.mAntiLambda(), v0.mAntiLambda() / v0.mLambda(), (v0.mLambda() - v0.mAntiLambda()) / v0.mLambda(), weight); + registry.fill(HIST("matching/V0/fakeV0PtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/V0/fakeV0PtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/V0/fakeV0PtDCAd"), v0.pt(), v0.dcaV0daughters(), weight); + + if (v0.isK0SCandidate()) { + registry.fill(HIST("matching/V0/fakeK0SPtEtaPhi"), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("matching/V0/fakeK0SPtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/V0/fakeK0SPtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/V0/fakeK0SPtDCAd"), v0.pt(), v0.dcaV0daughters(), weight); + + registry.fill(HIST("matching/V0/fakeK0SPtCtauMass"), v0.pt(), ctauK0s, v0.mK0Short(), weight); + registry.fill(HIST("matching/V0/fakeK0SPtRadiusMass"), v0.pt(), v0.v0radius(), v0.mK0Short(), weight); + registry.fill(HIST("matching/V0/fakeK0SPtCosPAMass"), v0.pt(), v0.v0cosPA(), v0.mK0Short(), weight); + registry.fill(HIST("matching/V0/fakeK0SPtDCAposMass"), v0.pt(), v0.dcapostopv(), v0.mK0Short(), weight); + registry.fill(HIST("matching/V0/fakeK0SPtDCAnegMass"), v0.pt(), v0.dcanegtopv(), v0.mK0Short(), weight); + registry.fill(HIST("matching/V0/fakeK0SPtDCAdMass"), v0.pt(), v0.dcaV0daughters(), v0.mK0Short(), weight); + } + if (v0.isLambdaCandidate()) { + registry.fill(HIST("matching/V0/fakeLambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("matching/V0/fakeLambdaPtLambdaMasses"), v0.pt(), massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("matching/V0/fakeLambdaPtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/V0/fakeLambdaPtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/V0/fakeLambdaPtDCAd"), v0.pt(), v0.dcaV0daughters(), weight); + + registry.fill(HIST("matching/V0/fakeLambdaPtCtauMass"), v0.pt(), ctauLambda, v0.mLambda(), weight); + registry.fill(HIST("matching/V0/fakeLambdaPtRadiusMass"), v0.pt(), v0.v0radius(), v0.mLambda(), weight); + registry.fill(HIST("matching/V0/fakeLambdaPtCosPAMass"), v0.pt(), v0.v0cosPA(), v0.mLambda(), weight); + registry.fill(HIST("matching/V0/fakeLambdaPtDCAposMass"), v0.pt(), v0.dcapostopv(), v0.mLambda(), weight); + registry.fill(HIST("matching/V0/fakeLambdaPtDCAnegMass"), v0.pt(), v0.dcanegtopv(), v0.mLambda(), weight); + registry.fill(HIST("matching/V0/fakeLambdaPtDCAdMass"), v0.pt(), v0.dcaV0daughters(), v0.mLambda(), weight); + } + if (v0.isAntiLambdaCandidate()) { + registry.fill(HIST("matching/V0/fakeAntiLambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("matching/V0/fakeAntiLambdaPtLambdaMasses"), v0.pt(), massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("matching/V0/fakeAntiLambdaPtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/V0/fakeAntiLambdaPtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/V0/fakeAntiLambdaPtDCAd"), v0.pt(), v0.dcaV0daughters(), weight); + + registry.fill(HIST("matching/V0/fakeAntiLambdaPtCtauMass"), v0.pt(), ctauAntiLambda, v0.mAntiLambda(), weight); + registry.fill(HIST("matching/V0/fakeAntiLambdaPtRadiusMass"), v0.pt(), v0.v0radius(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/V0/fakeAntiLambdaPtCosPAMass"), v0.pt(), v0.v0cosPA(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/V0/fakeAntiLambdaPtDCAposMass"), v0.pt(), v0.dcapostopv(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/V0/fakeAntiLambdaPtDCAnegMass"), v0.pt(), v0.dcanegtopv(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/V0/fakeAntiLambdaPtDCAdMass"), v0.pt(), v0.dcaV0daughters(), v0.mAntiLambda(), weight); + } + } + template // Fake inclusive V0s daughters + void fillMatchingFakeV0DauHistograms(U const& v0, double weight = 1.) + { + auto negTrack = v0.template negTrack_as(); + auto posTrack = v0.template posTrack_as(); + registry.fill(HIST("matching/V0/fakeV0PosTrackPtEtaPhi"), posTrack.pt(), posTrack.eta(), posTrack.phi(), weight); + registry.fill(HIST("matching/V0/fakeV0NegTrackPtEtaPhi"), negTrack.pt(), negTrack.eta(), negTrack.phi(), weight); + + if (v0.isK0SCandidate()) { + registry.fill(HIST("matching/V0/fakeK0SPosTrackPtEtaPhi"), posTrack.pt(), posTrack.eta(), posTrack.phi(), weight); + registry.fill(HIST("matching/V0/fakeK0SPosTrackPtMass"), v0.pt(), posTrack.pt(), v0.mK0Short(), weight); + registry.fill(HIST("matching/V0/fakeK0SNegTrackPtEtaPhi"), negTrack.pt(), negTrack.eta(), negTrack.phi(), weight); + registry.fill(HIST("matching/V0/fakeK0SNegTrackPtMass"), v0.pt(), negTrack.pt(), v0.mK0Short(), weight); + } + if (v0.isLambdaCandidate()) { + registry.fill(HIST("matching/V0/fakeLambdaPosTrackPtEtaPhi"), posTrack.pt(), posTrack.eta(), posTrack.phi(), weight); + registry.fill(HIST("matching/V0/fakeLambdaPosTrackPtMass"), v0.pt(), posTrack.pt(), v0.mLambda(), weight); + registry.fill(HIST("matching/V0/fakeLambdaNegTrackPtEtaPhi"), negTrack.pt(), negTrack.eta(), negTrack.phi(), weight); + registry.fill(HIST("matching/V0/fakeLambdaNegTrackPtMass"), v0.pt(), negTrack.pt(), v0.mLambda(), weight); + } + if (v0.isAntiLambdaCandidate()) { + registry.fill(HIST("matching/V0/fakeAntiLambdaPosTrackPtEtaPhi"), posTrack.pt(), posTrack.eta(), posTrack.phi(), weight); + registry.fill(HIST("matching/V0/fakeAntiLambdaPosTrackPtMass"), v0.pt(), posTrack.pt(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/V0/fakeAntiLambdaNegTrackPtEtaPhi"), negTrack.pt(), negTrack.eta(), negTrack.phi(), weight); + registry.fill(HIST("matching/V0/fakeAntiLambdaNegTrackPtMass"), v0.pt(), negTrack.pt(), v0.mAntiLambda(), weight); + } + } + template // Check if inclusive V0 was missed because daughter decayed + void fillMatchingV0DecayedHistograms(V const& v0, double weight = 1.) + { + // Check if decayed daughter + auto posTrack = v0.template posTrack_as(); + auto negTrack = v0.template negTrack_as(); + + auto posPart = posTrack.template mcParticle_as(); + auto negPart = negTrack.template mcParticle_as(); + + auto posMom = posPart.template mothers_first_as(); + auto negMom = negPart.template mothers_first_as(); + + bool posDecayed = false; + bool negDecayed = false; + + // This should not happen. They should have been matched + if (posMom == negMom) { + registry.fill(HIST("matching/V0/nonedecayedFakeV0PtMass"), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + return; + } + + if (posMom.has_mothers()) { + auto posGrandMom = posMom.template mothers_first_as(); + if (posGrandMom == negMom) { + posDecayed = true; + } + } + if (negMom.has_mothers()) { + auto negGrandMom = negMom.template mothers_first_as(); + if (negGrandMom == posMom) { + negDecayed = true; + } + } + + // This shouldn't happen + if (posDecayed && negDecayed) { + registry.fill(HIST("matching/V0/doubledecayedFakeV0PtMass"), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + return; + } + if (posDecayed || negDecayed) { + double pt = posDecayed ? negMom.pt() : posMom.pt(); + int pdg = posDecayed ? negMom.pdgCode() : posMom.pdgCode(); + + if (std::abs(pdg) == 310) { + registry.fill(HIST("matching/V0/decayedK0SV0PtMass"), pt, v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + } else if (pdg == 3122) { + registry.fill(HIST("matching/V0/decayedLambdaV0PtMass"), pt, v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + } else if (pdg == -3122) { + registry.fill(HIST("matching/V0/decayedAntiLambdaV0PtMass"), pt, v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + } else { + registry.fill(HIST("matching/V0/decayedOtherPtV0PtMass"), pt, v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + } + } + } + template // Fake V0s in jets + void fillMatchingV0JetFakeHistograms(CollisionType const& collision, JetType const& jet, V0Type const& v0, double weight = 1.) + { + double trackProj = getMomFrac(jet, v0); + double ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassLambda0; + double ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassLambda0Bar; + double ctauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassK0Short; + double massDiff = v0.mLambda() - v0.mAntiLambda(); + double massRatio = v0.mAntiLambda() / v0.mLambda(); + double massRelDiff = (v0.mLambda() - v0.mAntiLambda()) / v0.mLambda(); + + registry.fill(HIST("matching/jets/V0/fakeJetPtV0PtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtV0TrackProj"), jet.pt(), trackProj, weight); + + registry.fill(HIST("matching/jets/V0/fakeJetPtV0PtCtau"), jet.pt(), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda, weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtV0PtMass"), jet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtV0PtLambdaMasses"), jet.pt(), v0.pt(), massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtV0PtRadiusCosPA"), jet.pt(), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtV0PtDCAposneg"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtV0PtDCAd"), jet.pt(), v0.pt(), v0.dcaV0daughters(), weight); + + registry.fill(HIST("matching/jets/V0/fakeJetPtV0TrackProjCtau"), jet.pt(), trackProj, ctauK0s, ctauLambda, ctauAntiLambda, weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtV0TrackProjMass"), jet.pt(), trackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtV0TrackProjLambdaMasses"), jet.pt(), trackProj, massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtV0TrackProjRadiusCosPA"), jet.pt(), trackProj, v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtV0TrackProjDCAposneg"), jet.pt(), trackProj, v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtV0TrackProjDCAd"), jet.pt(), trackProj, v0.dcaV0daughters(), weight); + + if (v0.isK0SCandidate()) { + registry.fill(HIST("matching/jets/V0/fakeJetPtK0SPtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtK0STrackProj"), jet.pt(), trackProj, weight); + + registry.fill(HIST("matching/jets/V0/fakeJetPtK0SPtCtau"), jet.pt(), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda, weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtK0SPtMass"), jet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtK0SPtLambdaMasses"), jet.pt(), v0.pt(), massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtK0SPtRadiusCosPA"), jet.pt(), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtK0SPtDCAposneg"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtK0SPtDCAd"), jet.pt(), v0.pt(), v0.dcaV0daughters(), weight); + + registry.fill(HIST("matching/jets/V0/fakeJetPtK0STrackProjCtau"), jet.pt(), trackProj, ctauK0s, ctauLambda, ctauAntiLambda, weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtK0STrackProjMass"), jet.pt(), trackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtK0STrackProjLambdaMasses"), jet.pt(), trackProj, massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtK0STrackProjRadiusCosPA"), jet.pt(), trackProj, v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtK0STrackProjDCAposneg"), jet.pt(), trackProj, v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtK0STrackProjDCAd"), jet.pt(), trackProj, v0.dcaV0daughters(), weight); + } + if (v0.isLambdaCandidate()) { + registry.fill(HIST("matching/jets/V0/fakeJetPtLambdaPtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtLambdaTrackProj"), jet.pt(), trackProj, weight); + + registry.fill(HIST("matching/jets/V0/fakeJetPtLambdaPtCtau"), jet.pt(), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda, weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtLambdaPtMass"), jet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtLambdaPtLambdaMasses"), jet.pt(), v0.pt(), massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtLambdaPtRadiusCosPA"), jet.pt(), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtLambdaPtDCAposneg"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtLambdaPtDCAd"), jet.pt(), v0.pt(), v0.dcaV0daughters(), weight); + + registry.fill(HIST("matching/jets/V0/fakeJetPtLambdaTrackProjEtaPhi"), jet.pt(), trackProj, v0.eta(), v0.phi(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtLambdaTrackProjCtau"), jet.pt(), trackProj, ctauK0s, ctauLambda, ctauAntiLambda, weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtLambdaTrackProjMass"), jet.pt(), trackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtLambdaTrackProjLambdaMasses"), jet.pt(), trackProj, massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtLambdaTrackProjRadiusCosPA"), jet.pt(), trackProj, v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtLambdaTrackProjDCAposneg"), jet.pt(), trackProj, v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtLambdaTrackProjDCAd"), jet.pt(), trackProj, v0.dcaV0daughters(), weight); + } + if (v0.isAntiLambdaCandidate()) { + registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambdaPtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambdaTrackProj"), jet.pt(), trackProj, weight); + + registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambdaPtCtau"), jet.pt(), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda, weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambdaPtMass"), jet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambdaPtLambdaMasses"), jet.pt(), v0.pt(), massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambdaPtRadiusCosPA"), jet.pt(), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambdaPtDCAposneg"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambdaPtDCAd"), jet.pt(), v0.pt(), v0.dcaV0daughters(), weight); + + registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambdaTrackProjCtau"), jet.pt(), trackProj, ctauK0s, ctauLambda, ctauAntiLambda, weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambdaTrackProjMass"), jet.pt(), trackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambdaTrackProjLambdaMasses"), jet.pt(), trackProj, massDiff, massRatio, massRelDiff, weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambdaTrackProjRadiusCosPA"), jet.pt(), trackProj, v0.v0radius(), v0.v0cosPA(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambdaTrackProjDCAposneg"), jet.pt(), trackProj, v0.dcapostopv(), v0.dcanegtopv(), weight); + registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambdaTrackProjDCAd"), jet.pt(), trackProj, v0.dcaV0daughters(), weight); + } + } + template // Check if V0 in jet was missed because daughter decayed + void fillMatchingV0JetDecayedHistograms(V const& partJet, W const& detJet, X const& v0, double weight = 1.) + { + // Check if decayed daughter + auto posTrack = v0.template posTrack_as(); + auto negTrack = v0.template negTrack_as(); + + auto posPart = posTrack.template mcParticle_as(); + auto negPart = negTrack.template mcParticle_as(); + + auto posMom = posPart.template mothers_first_as(); + auto negMom = negPart.template mothers_first_as(); + + bool posDecayed = false; + bool negDecayed = false; + + double zv0 = getMomFrac(detJet, v0); + + // This should not happen. They should have been matched + if (posMom == negMom) { + registry.fill(HIST("matching/jets/V0/nonedecayedFakeV0PtMass"), partJet.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/nonedecayedFakeV0TrackProjMass"), partJet.pt(), detJet.pt(), zv0, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + return; + } + + if (posMom.has_mothers()) { + auto posGrandMom = posMom.template mothers_first_as(); + if (posGrandMom == negMom) { + posDecayed = true; + } + } + if (negMom.has_mothers()) { + auto negGrandMom = negMom.template mothers_first_as(); + if (negGrandMom == posMom) { + negDecayed = true; + } + } + + // This shouldn't happen + if (posDecayed && negDecayed) { + registry.fill(HIST("matching/jets/V0/doubledecayedFakeV0PtMass"), partJet.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + registry.fill(HIST("matching/jets/V0/doubledecayedFakeV0TrackProjMass"), partJet.pt(), detJet.pt(), zv0, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + return; + } + if (posDecayed || negDecayed) { + double pt = posDecayed ? negMom.pt() : posMom.pt(); + int pdg = posDecayed ? negMom.pdgCode() : posMom.pdgCode(); + + double z = 0.; + bool partIsInJet = false; + for (auto const& part : partJet.template tracks_as()) { + if (posDecayed && (part == negMom)) { + partIsInJet = true; + z = getMomFrac(partJet, part); + break; + } + if (negDecayed && (part == posMom)) { + partIsInJet = true; + z = getMomFrac(partJet, part); + break; + } + } + + if (std::abs(pdg) == 310) { + registry.fill(HIST("matching/jets/V0/decayedK0SV0PtMass"), partJet.pt(), detJet.pt(), pt, v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + if (partIsInJet) { + registry.fill(HIST("matching/jets/V0/decayedK0SV0TrackProjMass"), partJet.pt(), detJet.pt(), z, zv0, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + } + } else if (pdg == 3122) { + registry.fill(HIST("matching/jets/V0/decayedLambdaV0PtMass"), partJet.pt(), detJet.pt(), pt, v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + if (partIsInJet) { + registry.fill(HIST("matching/jets/V0/decayedLambdaV0TrackProjMass"), partJet.pt(), detJet.pt(), z, zv0, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + } + } else if (pdg == -3122) { + registry.fill(HIST("matching/jets/V0/decayedAntiLambdaV0PtMass"), partJet.pt(), detJet.pt(), pt, v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + if (partIsInJet) { + registry.fill(HIST("matching/jets/V0/decayedAntiLambdaV0TrackProjMass"), partJet.pt(), detJet.pt(), z, zv0, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + } + } else { + registry.fill(HIST("matching/jets/V0/decayedOtherPtV0PtMass"), partJet.pt(), detJet.pt(), pt, v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + if (partIsInJet) { + registry.fill(HIST("matching/jets/V0/decayedOtherPtV0TrackProjMass"), partJet.pt(), detJet.pt(), z, zv0, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + } + } + } + } + + // --------------------------------------------------- + // Processes + // --------------------------------------------------- + void processDummy(aod::JetTracks const&) {} + PROCESS_SWITCH(JetFragmentation, processDummy, "Dummy process function turned on by default", true); + + // Data + void processDataV0(soa::Filtered::iterator const& jcoll, CandidatesV0DataWithFlags const& V0s) + { + if (!jetderiveddatautilities::selectCollision(jcoll, eventSelectionBits)) { + return; + } + registry.fill(HIST("data/V0/nV0sEvent"), V0s.size()); + fillDataV0Histograms(jcoll, V0s); + fillDataV0HistogramsWeighted(jcoll, V0s); + } + PROCESS_SWITCH(JetFragmentation, processDataV0, "Data V0", false); + + void processDataV0JetsFrag(soa::Filtered::iterator const& jcoll, DataV0JetsWithConstituents const& v0jets, CandidatesV0DataWithFlags const&, aod::JetTracks const&) + { + if (!jetderiveddatautilities::selectCollision(jcoll, eventSelectionBits)) { + return; + } + + for (const auto& jet : v0jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, -99., -99., v0EtaMin, v0EtaMax)) { + continue; + } + + if (!jetContainsV0s(jet)) // Double check if the jet contains V0s + continue; + + fillDataJetHistograms(jet); + + int nV0inJet = 0, nLambdainJet = 0, nAntiLambdainJet = 0, nK0SinJet = 0; // Counts + float wV0inJet = 0, wLambdainJet = 0, wAntiLambdainJet = 0, wK0SinJet = 0; // Weights + + std::vector values; + std::vector> weights; + for (const auto& v0 : jet.candidates_as()) { + if (v0.isRejectedCandidate()) + continue; + + float purity = getV0SignalProb(v0); + nV0inJet++; + wV0inJet += purity; + if (v0.isK0SCandidate()) { + nK0SinJet++; + wK0SinJet += purity; + } + if (v0.isLambdaCandidate()) { + nLambdainJet++; + wLambdainJet += purity; + } + if (v0.isAntiLambdaCandidate()) { + nAntiLambdainJet++; + wAntiLambdainJet += purity; + } + + fillDataV0FragHistograms(jcoll, jet, v0); + double z = getMomFrac(jet, v0); + std::vector w; + + if (nV0Classes == 2) + w = getV0SignalProbVector2Classes(v0); + else if (nV0Classes == 4) + w = getV0SignalProbVector4Classes(v0); + else + return; + + values.push_back(z); + weights.push_back(w); + } + values.push_back(jet.pt()); + registry.fill(HIST("data/jets/V0/jetPtnV0nK0SnLambdanAntiLambda"), jet.pt(), nV0inJet, nK0SinJet, nLambdainJet, nAntiLambdainJet); + registry.fill(HIST("data/jets/weighted/V0/jetPtnV0nK0SnLambdanAntiLambda"), jet.pt(), wV0inJet, wK0SinJet, wLambdainJet, wAntiLambdainJet); + + int nStates = std::round(std::pow(static_cast(nV0Classes), static_cast(nV0inJet))); + for (int M = 0; M < nStates; M++) { + std::vector state = convertState(M, nV0inJet, nV0Classes); + std::vector corrected; + if (doCorrectionWithTracks) + corrected = correctedValues(state, values); + else + corrected = correctedValuesPlusTracks(state, jet); + + double ws = stateWeight(state, weights); + double jetpt = corrected[nV0inJet]; + fillDataJetHistogramsWeighted(jetpt, jet.eta(), jet.phi(), ws); + fillDataV0FragHistogramsWeighted(jcoll, jet, state, corrected, ws); + } + } + } + PROCESS_SWITCH(JetFragmentation, processDataV0JetsFrag, "Data V0 jets fragmentation with weights", false); + + void processDataV0PerpCone(soa::Filtered::iterator const& jcoll, aod::V0ChargedJets const& v0jets, CandidatesV0DataWithFlags const& v0s) + { + if (!jetderiveddatautilities::selectCollision(jcoll, eventSelectionBits)) { + return; + } + + for (const auto& jet : v0jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, -99., -99., v0EtaMin, v0EtaMax)) { + continue; + } + fillDataPerpConeHists(jcoll, jet, v0s); + } + } + PROCESS_SWITCH(JetFragmentation, processDataV0PerpCone, "Perpendicular cone V0s in data", false); + + // Matching + void processMcMatchedV0(soa::Filtered::iterator const& jcoll, aod::JetMcCollisions const&, CandidatesV0MCDWithLabelsAndFlags const& v0s, aod::CandidatesV0MCP const& pv0s, aod::JetTracksMCD const& jTracks, aod::JetParticles const&) + { + if (!jcoll.has_mcCollision()) { + return; + } + if (!jetderiveddatautilities::selectCollision(jcoll, eventSelectionBits)) { + return; + } + double weight = jcoll.mcCollision().weight(); + registry.fill(HIST("matching/V0/nV0sEvent"), v0s.size()); + registry.fill(HIST("matching/V0/nV0sEventWeighted"), v0s.size(), weight); + + // TODO: Fill mcd and mcp hists + fillMCDV0Histograms(jcoll, v0s, weight); + fillMCPV0Histograms(pv0s, weight); + + float nV0s = 0; + for (const auto& v0 : v0s) { + if (v0.isRejectedCandidate()) + continue; + + if (!v0.has_mcParticle()) { + fillMatchingV0FakeHistograms(jcoll, v0, weight); + fillMatchingFakeV0DauHistograms(v0, weight); + fillMatchingV0DecayedHistograms(v0, weight); + continue; + } + for (const auto& pv0 : pv0s) { + if (v0sAreMatched(v0, pv0, jTracks)) { + nV0s += 1; + fillMatchingV0Histograms(jcoll, v0, pv0, weight); + fillMatchingV0DauHistograms(v0, pv0, weight); + } + } + } // Reconstructed V0s + for (const auto& pv0 : pv0s) { + for (const auto& v0 : v0s) { + if (v0sAreMatched(v0, pv0, jTracks)) { + continue; + } + // Fill histograms for missed V0s + } + } + registry.fill(HIST("matching/V0/nV0sEventAcc"), nV0s); + registry.fill(HIST("matching/V0/nV0sEventAccWeighted"), nV0s, weight); + } + PROCESS_SWITCH(JetFragmentation, processMcMatchedV0, "Monte Carlo V0", false); + + void processMcMatchedV0JetsFrag(soa::Filtered::iterator const& jcoll, aod::JetMcCollisions const&, MatchedMCDV0JetsWithConstituents const& v0jetsMCD, MatchedMCPV0JetsWithConstituents const& v0jetsMCP, CandidatesV0MCDWithLabelsAndFlags const&, aod::CandidatesV0MCP const&, aod::JetTracksMCD const& jTracks, aod::JetParticles const&) + { + if (!jcoll.has_mcCollision()) + return; + if (!jetderiveddatautilities::selectCollision(jcoll, eventSelectionBits)) + return; + + double weight = jcoll.mcCollision().weight(); + + for (const auto& detJet : v0jetsMCD) { + if (!jetfindingutilities::isInEtaAcceptance(detJet, -99., -99., v0EtaMin, v0EtaMax)) + continue; + + // Double check if the jet contains V0s + if (!jetContainsV0s(detJet)) + continue; + + fillMCDJetHistograms(detJet, weight); + + int nV0inJet = 0, nLambdainJet = 0, nAntiLambdainJet = 0, nK0SinJet = 0; + if (!detJet.has_matchedJetGeo()) { + for (const auto& detV0 : detJet.candidates_as()) { + fillMatchingV0JetFakeHistograms(jcoll, detJet, detV0, weight); + } + continue; + } // if jet not matched + + for (const auto& partJet : detJet.template matchedJetGeo_as()) { + fillMatchingHistogramsJet(detJet, partJet, weight); + for (const auto& detV0 : detJet.candidates_as()) { + if (!detV0.has_mcParticle()) { + fillMatchingV0JetFakeHistograms(jcoll, detJet, detV0, weight); + fillMatchingV0JetDecayedHistograms(partJet, detJet, detV0, weight); + continue; + } + bool isV0Matched = false; + for (const auto& partV0 : partJet.template candidates_as()) { + if (v0sAreMatched(detV0, partV0, jTracks)) { + isV0Matched = true; + nV0inJet++; + fillMatchingV0FragHistograms(jcoll, detJet, partJet, detV0, partV0, weight); + fillMatchingV0DauJetHistograms(detJet, partJet, detV0, partV0, weight); + + if (std::abs(partV0.pdgCode()) == 310) { + nK0SinJet++; + } else if (partV0.pdgCode() == 3122) { + nLambdainJet++; + } else if (partV0.pdgCode() == -3122) { + nAntiLambdainJet++; + } + break; + } // if matched + } // partV0 loop + + if (!isV0Matched) { + fillMatchingV0JetFakeHistograms(jcoll, detJet, detV0, weight); + } + } // detV0 loop + registry.fill(HIST("matching/jets/V0/jetPtnV0MatchednK0SnLambdanAntiLambda"), partJet.pt(), nV0inJet, nK0SinJet, nLambdainJet, nAntiLambdainJet, weight); + } // Matched partJet loop + } // detJet loop + + for (const auto& partJet : v0jetsMCP) { + if (!jetContainsV0s(partJet)) { + continue; + } + fillMCPJetHistograms(partJet, weight); + + if (!partJet.has_matchedJetGeo()) { + for (const auto& partV0 : partJet.candidates_as()) { + fillMatchingV0Miss(partJet, partV0, weight); + } + continue; + } // if jet not matched + + bool isJetMatched = false; + for (const auto& detJet : partJet.template matchedJetGeo_as()) { + if (!jetfindingutilities::isInEtaAcceptance(detJet, -99., -99., v0EtaMin, v0EtaMax)) { + continue; + } + isJetMatched = true; + for (const auto& partV0 : partJet.candidates_as()) { + bool isV0Matched = false; + for (const auto& detV0 : detJet.candidates_as()) { + if (v0sAreMatched(detV0, partV0, jTracks)) { + isV0Matched = true; + break; + } + } // detV0 loop + if (!isV0Matched) { + fillMatchingV0Miss(partJet, partV0, weight); + } + } // partV0 loop + } // detJet loop + + // To account for matched jets where the detector level jet is outside of the eta range (cut applied within this task) + if (!isJetMatched) { + for (const auto& partV0 : partJet.candidates_as()) { + fillMatchingV0Miss(partJet, partV0, weight); + } + } + } // partJet loop + } + PROCESS_SWITCH(JetFragmentation, processMcMatchedV0JetsFrag, "Matched V0 jets fragmentation", false); + + void processMcV0PerpCone(soa::Filtered::iterator const& jcoll, aod::JetMcCollisions const&, MatchedMCDV0Jets const& v0jets, CandidatesV0MCDWithLabelsAndFlags const& v0s, aod::McParticles const& particles) + { + if (!jetderiveddatautilities::selectCollision(jcoll, eventSelectionBits)) { + return; + } + double weight = jcoll.mcCollision().weight(); + registry.fill(HIST("mcd/V0/nV0sEvent"), v0s.size()); + registry.fill(HIST("mcd/V0/nV0sEventWeighted"), v0s.size(), weight); + + for (const auto& mcdjet : v0jets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, -99., -99., v0EtaMin, v0EtaMax)) + continue; + + fillMcPerpConeHists(jcoll, mcdjet, v0s, particles, weight); + + for (const auto& mcpjet : mcdjet.template matchedJetGeo_as()) { + fillMcPerpConeHists(jcoll, mcdjet, mcpjet, v0s, particles, weight); + break; // Make sure we only do this once + } + } + } + PROCESS_SWITCH(JetFragmentation, processMcV0PerpCone, "Perpendicular cone V0s in MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGJE/Tasks/jetHadronRecoil.cxx b/PWGJE/Tasks/jetHadronRecoil.cxx index 8639e4d2d0e..e798b406ed8 100644 --- a/PWGJE/Tasks/jetHadronRecoil.cxx +++ b/PWGJE/Tasks/jetHadronRecoil.cxx @@ -8,13 +8,13 @@ // 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. - -// h+jet analysis task // -// Authors: Daniel Jones +/// \file jetHadronRecoil.cxx +/// \brief Task for analysing hadron triggered events. +/// \author Daniel Jones -#include #include +#include #include "TRandom3.h" @@ -25,8 +25,10 @@ #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" +#include "CommonConstants/MathConstants.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" +#include "Common/Core/RecoDecay.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -43,269 +45,707 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -struct hJetAnalysis { +struct JetHadronRecoil { - Configurable eventSelections{"eventSelection", "sel8", "choose event selection"}; - Configurable trackSelections{"trackSelection", "globalTracks", "set track selections"}; + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; Configurable trackPtMin{"trackPtMin", 0.15, "minimum pT acceptance for tracks"}; Configurable trackPtMax{"trackPtMax", 100.0, "maximum pT acceptance for tracks"}; Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum eta acceptance for tracks"}; Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum eta acceptance for tracks"}; + Configurable maxLeadingTrackPt{"maxLeadingTrackPt", 1000.0, "maximum acceptance for leading track in jets"}; + Configurable centralityMin{"centralityMin", -999.0, "minimum centrality"}; + Configurable centralityMax{"centralityMax", 999.0, "maximum centrality"}; Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; - Configurable pt_TTref_min{"pt_TTref_min", 5, "reference minimum trigger track pt"}; - Configurable pt_TTref_max{"pt_TTref_max", 7, "reference maximum trigger track pt"}; - Configurable pt_TTsig_min{"pt_TTsig_min", 20, "signal minimum trigger track pt"}; - Configurable pt_TTsig_max{"pt_TTsig_max", 50, "signal maximum trigger track pt"}; - Configurable frac_sig{"frac_sig", 0.5, "fraction of events to use for signal"}; + Configurable ptTTrefMin{"ptTTrefMin", 5, "reference minimum trigger track pt"}; + Configurable ptTTrefMax{"ptTTrefMax", 7, "reference maximum trigger track pt"}; + Configurable ptTTsigMin{"ptTTsigMin", 20, "signal minimum trigger track pt"}; + Configurable ptTTsigMax{"ptTTsigMax", 50, "signal maximum trigger track pt"}; + Configurable fracSig{"fracSig", 0.9, "fraction of events to use for signal"}; Configurable jetR{"jetR", 0.4, "jet resolution parameter"}; + Configurable pTHatExponent{"pTHatExponent", 4.0, "exponent of the event weight for the calculation of pTHat"}; + Configurable pTHatMaxMCD{"pTHatMaxMCD", 999.0, "maximum fraction of hard scattering for jet acceptance in detector MC"}; + Configurable pTHatMaxMCP{"pTHatMaxMCP", 999.0, "maximum fraction of hard scattering for jet acceptance in particle MC"}; + Configurable rhoReferenceShift{"rhoReferenceShift", 0.0, "shift in rho calculated in reference events for consistency with signal events"}; + Configurable triggerMasks{"triggerMasks", "", "possible JE Trigger masks: fJetChLowPt,fJetChHighPt,fTrackLowPt,fTrackHighPt,fJetD0ChLowPt,fJetD0ChHighPt,fJetLcChLowPt,fJetLcChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt,fJetNeutralHighPt,fJetNeutralLowPt,fGammaVeryHighPtEMCAL,fGammaVeryHighPtDCAL,fGammaHighPtEMCAL,fGammaHighPtDCAL,fGammaLowPtEMCAL,fGammaLowPtDCAL,fGammaVeryLowPtEMCAL,fGammaVeryLowPtDCAL"}; + Configurable skipMBGapEvents{"skipMBGapEvents", false, "flag to choose to reject min. bias gap events; jet-level rejection applied at the jet finder level, here rejection is applied for collision and track process functions"}; + + Preslice> partJetsPerCollision = aod::jet::mcCollisionId; TRandom3* rand = new TRandom3(0); Filter jetCuts = aod::jet::r == nround(jetR.node() * 100.0f); Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); - Filter eventCuts = nabs(aod::jcollision::posZ) < vertexZCut; + Filter particleCuts = (aod::jmcparticle::pt >= trackPtMin && aod::jmcparticle::pt < trackPtMax && aod::jmcparticle::eta > trackEtaMin && aod::jmcparticle::eta < trackEtaMax); + Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax); + + std::vector ptBinningPart = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, + 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0, + 65.0, 70.0, 75.0, 80.0, 90.0, 100.0, 110.0, 120.0, 130.0, + 140.0, 150.0, 160.0, 180.0, 200.0}; + std::vector ptBinningDet = {-100.0, -70.0, -60.0, -50.0, -40.0, -35.0, -30.0, -25.0, -20.0, -15.0, -10.0, -5.0, + 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, + 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0, + 65.0, 70.0, 75.0, 80.0, 90.0, 100.0, 110.0, 120.0, 130.0, + 140.0, 150.0, 160.0, 180.0, 200.0}; + std::vector dRBinning = {0.0, 1.0e-9, 0.003, 0.006, 0.009, 0.012, 0.015, 0.018, 0.021, 0.024, + 0.027, 0.03, 0.033, 0.036, 0.039, 0.042, 0.045, 0.048, 0.051, 0.054, + 0.057, 0.06, 0.063, 0.066, 0.069, 0.072, 0.075, 0.078, 0.081, 0.084, + 0.087, 0.09, 0.093, 0.096, 0.099, 0.102, 0.105, 0.108, 0.111, 0.114, + 0.117, 0.12, 0.123, 0.126, 0.129, 0.132, 0.135, 0.138, 0.141, 0.144, + 0.147, 0.15, 0.153, 0.156, 0.159, 0.162, 0.165, 0.168, 0.171, 0.174, + 0.177, 0.18, 0.183, 0.186, 0.189, 0.192, 0.195, 0.198, 0.201, 0.204, + 0.207, 0.21, 0.213, 0.216, 0.219, 0.222, 0.225, 0.228, 0.231, 0.234, + 0.237, 0.24}; + + AxisSpec dRAxis = {dRBinning, "#Delta R"}; + + AxisSpec ptAxisDet = {ptBinningDet, "#it{p}_{T,det} (GeV/c)"}; + AxisSpec ptAxisPart = {ptBinningPart, "#it{p}_{T,part} (GeV/c)"}; + AxisSpec phiAxisDet = {100, 0.0, o2::constants::math::TwoPI, "#phi_{det}"}; + AxisSpec phiAxisPart = {100, 0.0, o2::constants::math::TwoPI, "#phi_{part}"}; + AxisSpec dRAxisDet = {dRBinning, "#Delta R_{det}"}; + AxisSpec dRAxisPart = {dRBinning, "#Delta R_{part}"}; HistogramRegistry registry{"registry", {{"hNtrig", "number of triggers;trigger type;entries", {HistType::kTH1F, {{2, 0, 2}}}}, + {"hZvtxSelected", "Z vertex position;Z_{vtx};entries", {HistType::kTH1F, {{80, -20, 20}}}}, {"hPtTrack", "Track p_{T};p_{T};entries", {HistType::kTH1F, {{200, 0, 200}}}}, {"hEtaTrack", "Track #eta;#eta;entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, - {"hPhiTrack", "Track #phi;#phi;entries", {HistType::kTH1F, {{160, -1.0, 7.0}}}}, - {"hReferencePtDPhi", "jet p_{T} vs DPhi;#Delta#phi;p_{T,jet}", {HistType::kTH2F, {{100, 0, 2 * M_PI}, {150, 0, 150}}}}, - {"hSignalPtDPhi", "jet p_{T} vs DPhi;#Delta#phi;p_{T,jet}", {HistType::kTH2F, {{100, 0, 2 * M_PI}, {150, 0, 150}}}}, - {"hReferencePt", "jet p_{T};p_{T,jet};entries", {HistType::kTH1F, {{150, 0, 150}}}}, - {"hSignalPt", "jet p_{T};p_{T,jet};entries", {HistType::kTH1F, {{150, 0, 150}}}}, - {"hSignalLeadingTrack", "leading track p_{T};p_{T,jet};#Delta#phi;leading track p_{T}", {HistType::kTH3F, {{150, 0, 150}, {100, 0, 2 * M_PI}, {150, 0, 150}}}}, - {"hReferenceLeadingTrack", "leading track p_{T};p_{T,jet};#Delta#phi;leading track p_{T}", {HistType::kTH3F, {{150, 0, 150}, {100, 0, 2 * M_PI}, {150, 0, 150}}}}, - {"hJetSignalMultiplicity", "jet multiplicity;N_{jets};entries", {HistType::kTH1F, {{10, 0, 10}}}}, - {"hJetReferenceMultiplicity", "jet multiplicity;N_{jets};entries", {HistType::kTH1F, {{10, 0, 10}}}}, - {"hJetSignalConstituentMultiplicity", "jet constituent multiplicity;p_{T,jet};#Delta#phi;N_{constituents}", {HistType::kTH3F, {{150, 0, 150}, {100, 0, 2 * M_PI}, {50, 0, 50}}}}, - {"hJetReferenceConstituentMultiplicity", "jet constituent multiplicity;p_{T,jet};#Delta#phi;N_{constituents}", {HistType::kTH3F, {{150, 0, 150}, {100, 0, 2 * M_PI}, {50, 0, 50}}}}, - {"hJetSignalConstituentPt", "jet constituent p_{T};p_{T,jet};#Delta#phi;p_{T,constituent}", {HistType::kTH3F, {{150, 0, 150}, {100, 0, 2 * M_PI}, {150, 0, 150}}}}, - {"hJetReferenceConstituentPt", "jet constituent p_{T};p_{T,jet};#Delta#phi;p_{T,constituent}", {HistType::kTH3F, {{150, 0, 150}, {100, 0, 2 * M_PI}, {150, 0, 150}}}}, + {"hPhiTrack", "Track #phi;#phi;entries", {HistType::kTH1F, {{100, 0.0, o2::constants::math::TwoPI}}}}, + {"hReferencePtDPhi", "jet p_{T} vs DPhi;#Delta#phi;p_{T,jet}", {HistType::kTH2F, {{100, 0, o2::constants::math::TwoPI}, {500, -100, 400}}}}, + {"hReferencePtDPhiShifts", "rho shifts;#Delta#phi;p_{T,jet};shifts", {HistType::kTH3F, {{100, 0, o2::constants::math::TwoPI}, {500, -100, 400}, {20, 0.0, 2.0}}}}, + {"hSignalPtDPhi", "jet p_{T} vs DPhi;#Delta#phi;p_{T,jet}", {HistType::kTH2F, {{100, 0, o2::constants::math::TwoPI}, {500, -100, 400}}}}, + {"hReferencePt", "jet p_{T};p_{T,jet};entries", {HistType::kTH1F, {{500, -100, 400}}}}, + {"hSignalPt", "jet p_{T};p_{T,jet};entries", {HistType::kTH1F, {{500, -100, 400}}}}, + {"hSignalTriggers", "trigger p_{T};p_{T,trig};entries", {HistType::kTH1F, {{150, 0, 150}}}}, + {"hReferenceTriggers", "trigger p_{T};p_{T,trig};entries", {HistType::kTH1F, {{150, 0, 150}}}}, {"hSigEventTriggers", "N_{triggers};events", {HistType::kTH1F, {{10, 0, 10}}}}, {"hRefEventTriggers", "N_{triggers};events", {HistType::kTH1F, {{10, 0, 10}}}}, - {"hJetPt", "jet p_{T};p_{T,jet};entries", {HistType::kTH1F, {{200, 0, 200}}}}, + {"hJetPt", "jet p_{T};p_{T,jet};entries", {HistType::kTH1F, {{500, -100, 400}}}}, {"hJetEta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, - {"hJetPhi", "jet #phi;#phi_{jet};entries", {HistType::kTH1F, {{160, -1.0, 7.0}}}}, + {"hJetPhi", "jet #phi;#phi_{jet};entries", {HistType::kTH1F, {{100, 0.0, o2::constants::math::TwoPI}}}}, {"hPtPart", "Particle p_{T};p_{T};entries", {HistType::kTH1F, {{200, 0, 200}}}}, {"hEtaPart", "Particle #eta;#eta;entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, - {"hPhiPart", "Particle #phi;#phi;entries", {HistType::kTH1F, {{160, -1.0, 7.0}}}}}}; - - int eventSelection = -1; + {"hPhiPart", "Particle #phi;#phi;entries", {HistType::kTH1F, {{100, 0.0, o2::constants::math::TwoPI}}}}, + {"hDeltaR", "#DeltaR;#DeltaR;#frac{dN_{jets}}{d#DeltaR}", {HistType::kTH1F, {dRAxis}}}, + {"hDeltaRPart", "Particle #DeltaR;#DeltaR;#frac{1}{N_{jets}}#frac{dN_{jets}}{d#DeltaR}", {HistType::kTH1F, {dRAxis}}}, + {"hDeltaRpT", "jet p_{T} vs #DeltaR;p_{T,jet};#DeltaR", {HistType::kTH2F, {{500, -100, 400}, dRAxis}}}, + {"hDeltaRpTPart", "Particle jet p_{T} vs #DeltaR;p_{T,jet};#DeltaR", {HistType::kTH2F, {{400, 0, 400}, dRAxis}}}, + {"hRhoSignal", "Signal Rho bkg;#rho;entries", {HistType::kTH1F, {{220, 0, 220}}}}, + {"hRhoReference", "Reference Rho bkg;#rho;entries", {HistType::kTH1F, {{220, 0, 220}}}}, + {"hRhoReferenceShift", "Testing reference shifts;#rho;shift", {HistType::kTH2F, {{220, 0, 220}, {20, 0.0, 2.0}}}}, + {"hDeltaRSignal", "#DeltaR;#DeltaR;#frac{dN_{jets}}{d#DeltaR}", {HistType::kTH1F, {dRAxis}}}, + {"hDeltaRSignalPart", "Particle #DeltaR;#DeltaR;#frac{1}{N_{jets}}#frac{dN_{jets}}{d#DeltaR}", {HistType::kTH1F, {dRAxis}}}, + {"hDeltaRpTSignal", "jet p_{T} vs #DeltaR;p_{T,jet};#DeltaR", {HistType::kTH2F, {{500, -100, 400}, dRAxis}}}, + {"hDeltaRpTSignalPart", "Particle jet p_{T} vs #DeltaR;p_{T,jet};#DeltaR", {HistType::kTH2F, {{400, 0, 400}, dRAxis}}}, + {"hDeltaRpTDPhiSignal", "jet p_{T} vs #DeltaR vs #Delta#phi;p_{T,jet};#Delta#phi;#DeltaR", {HistType::kTH3F, {{500, -100, 400}, {100, 0, o2::constants::math::TwoPI}, dRAxis}}}, + {"hDeltaRpTDPhiSignalPart", "Particle jet p_{T} vs #DeltaR vs #Delta#phi;p_{T,jet};#Delta#phi;#DeltaR", {HistType::kTH3F, {{400, 0, 400}, {100, 0, o2::constants::math::TwoPI}, dRAxis}}}, + {"hDeltaRReference", "#DeltaR;#DeltaR;#frac{dN_{jets}}{d#DeltaR}", {HistType::kTH1F, {dRAxis}}}, + {"hDeltaRPartReference", "Particle #DeltaR;#DeltaR;#frac{1}{N_{jets}}#frac{dN_{jets}}{d#DeltaR}", {HistType::kTH1F, {dRAxis}}}, + {"hDeltaRpTReference", "jet p_{T} vs #DeltaR;p_{T,jet};#DeltaR", {HistType::kTH2F, {{500, -100, 400}, dRAxis}}}, + {"hDeltaRpTPartReference", "Particle jet p_{T} vs #DeltaR;p_{T,jet};#DeltaR", {HistType::kTH2F, {{400, 0, 400}, dRAxis}}}, + {"hDeltaRpTDPhiReference", "jet p_{T} vs #DeltaR vs #Delta#phi;p_{T,jet};#Delta#phi;#DeltaR", {HistType::kTH3F, {{500, -100, 400}, {100, 0, o2::constants::math::TwoPI}, dRAxis}}}, + {"hDeltaRpTDPhiReferenceShifts", "testing shifts;p_{T,jet};#Delta#phi;#DeltaR;shifts", {HistType::kTHnSparseD, {{500, -100, 400}, {100, 0, o2::constants::math::TwoPI}, dRAxis, {20, 0.0, 2.0}}}}, + {"hDeltaRpTDPhiReferencePart", "jet p_{T} vs #DeltaR vs #Delta#phi;p_{T,jet};#Delta#phi;#DeltaR", {HistType::kTH3F, {{400, 0, 400}, {100, 0, o2::constants::math::TwoPI}, dRAxis}}}, + {"hPtMatched", "p_{T} matching;p_{T,det};p_{T,part}", {HistType::kTH2F, {{500, -100, 400}, {400, 0, 400}}}}, + {"hPhiMatched", "#phi matching;#phi_{det};#phi_{part}", {HistType::kTH2F, {{100, 0.0, o2::constants::math::TwoPI}, {100, 0.0, o2::constants::math::TwoPI}}}}, + {"hDeltaRMatched", "#DeltaR matching;#DeltaR_{det};#DeltaR_{part}", {HistType::kTH2F, {dRAxisDet, dRAxisPart}}}, + {"hPtMatched1d", "p_{T} matching 1d;p_{T,part}", {HistType::kTH1F, {{400, 0, 400}}}}, + {"hDeltaRMatched1d", "#DeltaR matching 1d;#DeltaR_{part}", {HistType::kTH1F, {dRAxisPart}}}, + {"hPtResolution", "p_{T} resolution;p_{T,part};Relative Resolution", {HistType::kTH2F, {{400, 0, 400}, {1000, -5.0, 5.0}}}}, + {"hPhiResolution", "#phi resolution;#p{T,part};Resolution", {HistType::kTH2F, {{400, 0, 400}, {1000, -7.0, 7.0}}}}, + {"hDeltaRResolution", "#DeltaR Resolution;p_{T,part};Resolution", {HistType::kTH2F, {{400, 0, 400}, {1000, -0.15, 0.15}}}}, + {"hFullMatching", "Full 6D matching;p_{T,det};p_{T,part};#phi_{det};#phi_{part};#DeltaR_{det};#DeltaR_{part}", {HistType::kTHnSparseD, {ptAxisDet, ptAxisPart, phiAxisDet, phiAxisPart, dRAxisDet, dRAxisPart}}}}}; + + std::vector eventSelectionBits; int trackSelection = -1; + std::vector triggerMaskBits; + + Service pdg; void init(InitContext const&) { - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(eventSelections)); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(triggerMasks); Filter jetCuts = aod::jet::r == nround(jetR.node() * 100.0f); Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); - Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut); - } - - float dPhi(float phi1, float phi2) - { - float dPhi = phi1 - phi2; - if (dPhi < 0) - dPhi += 2 * M_PI; - if (dPhi > 2 * M_PI) - dPhi -= 2 * M_PI; - return dPhi; + Filter particleCuts = (aod::jmcparticle::pt >= trackPtMin && aod::jmcparticle::pt < trackPtMax && aod::jmcparticle::eta > trackEtaMin && aod::jmcparticle::eta < trackEtaMax); + Filter eventTrackLevelCuts = nabs(aod::jcollision::posZ) < vertexZCut; } - template - void fillHistograms(T const& jets, U const& tracks) + template + void fillHistograms(T const& jets, W const& /*jetsWTA*/, U const& tracks, float weight = 1.0, float rho = 0.0) { - bool is_sig_col; - std::vector phi_TT_ar; - double phi_TT; - int trig_number; - int n_TT = 0; + bool isSigCol; + std::vector phiTTAr; + double phiTT = 0; + int trigNumber = 0; + int nTT = 0; double leadingPT = 0; + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + float rhoReference = rho + rhoReferenceShift; float dice = rand->Rndm(); - if (dice < frac_sig) - is_sig_col = true; + if (dice < fracSig) + isSigCol = true; else - is_sig_col = false; + isSigCol = false; - for (auto& track : tracks) { + for (const auto& track : tracks) { if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { continue; } - if (is_sig_col && track.pt() < pt_TTsig_max && track.pt() > pt_TTsig_min) { - phi_TT_ar.push_back(track.phi()); - n_TT++; + if (isSigCol && track.pt() < ptTTsigMax && track.pt() > ptTTsigMin) { + phiTTAr.push_back(track.phi()); + registry.fill(HIST("hSignalTriggers"), track.pt(), weight); + nTT++; } - if (!is_sig_col && track.pt() < pt_TTref_max && track.pt() > pt_TTref_min) { - phi_TT_ar.push_back(track.phi()); - n_TT++; + if (!isSigCol && track.pt() < ptTTrefMax && track.pt() > ptTTrefMin) { + phiTTAr.push_back(track.phi()); + registry.fill(HIST("hReferenceTriggers"), track.pt(), weight); + nTT++; } - registry.fill(HIST("hPtTrack"), track.pt()); - registry.fill(HIST("hEtaTrack"), track.eta()); - registry.fill(HIST("hPhiTrack"), track.phi()); - } - - if (n_TT > 0) { - trig_number = rand->Integer(n_TT); - phi_TT = phi_TT_ar[trig_number]; - if (is_sig_col) { - registry.fill(HIST("hNtrig"), 1.5); - registry.fill(HIST("hJetSignalMultiplicity"), jets.size()); - registry.fill(HIST("hSigEventTriggers"), n_TT); + registry.fill(HIST("hPtTrack"), track.pt(), weight); + registry.fill(HIST("hEtaTrack"), track.eta(), weight); + registry.fill(HIST("hPhiTrack"), track.phi(), weight); + } + + if (nTT > 0) { + trigNumber = rand->Integer(nTT); + phiTT = phiTTAr[trigNumber]; + if (isSigCol) { + registry.fill(HIST("hNtrig"), 1.5, weight); + registry.fill(HIST("hSigEventTriggers"), nTT, weight); + registry.fill(HIST("hRhoSignal"), rho, weight); } - if (!is_sig_col) { - registry.fill(HIST("hNtrig"), 0.5); - registry.fill(HIST("hJetReferenceMultiplicity"), jets.size()); - registry.fill(HIST("hRefEventTriggers"), n_TT); + if (!isSigCol) { + registry.fill(HIST("hNtrig"), 0.5, weight); + registry.fill(HIST("hRefEventTriggers"), nTT, weight); + registry.fill(HIST("hRhoReference"), rhoReference, weight); + for (double shift = 0.0; shift <= 2.0; shift += 0.1) { + registry.fill(HIST("hRhoReferenceShift"), rho + shift, shift, weight); + } } } - for (auto& jet : jets) { - registry.fill(HIST("hJetPt"), jet.pt()); - registry.fill(HIST("hJetEta"), jet.eta()); - registry.fill(HIST("hJetPhi"), jet.phi()); - if (n_TT > 0) { - float dphi = dPhi(jet.phi(), phi_TT); - if (is_sig_col) { - registry.fill(HIST("hSignalPtDPhi"), dphi, jet.pt()); - if (std::abs(dphi - M_PI) < 0.6) { - registry.fill(HIST("hSignalPt"), jet.pt()); - } - registry.fill(HIST("hJetSignalConstituentMultiplicity"), jet.pt(), dphi, jet.tracksIds().size()); - for (auto& constituent : jet.template tracks_as()) { - if (constituent.pt() > leadingPT) { - leadingPT = constituent.pt(); + for (const auto& jet : jets) { + for (const auto& constituent : jet.template tracks_as()) { + if (constituent.pt() > leadingPT) { + leadingPT = constituent.pt(); + } + } + if (jet.pt() > pTHatMaxMCD * pTHat) { + continue; + } + if (leadingPT > maxLeadingTrackPt) { + continue; + } + registry.fill(HIST("hJetPt"), jet.pt() - (rho * jet.area()), weight); + registry.fill(HIST("hJetEta"), jet.eta(), weight); + registry.fill(HIST("hJetPhi"), jet.phi(), weight); + for (const auto& jetWTA : jet.template matchedJetGeo_as>()) { + double deltaPhi = RecoDecay::constrainAngle(jetWTA.phi() - jet.phi(), -o2::constants::math::PI); + double deltaEta = jetWTA.eta() - jet.eta(); + double dR = RecoDecay::sqrtSumOfSquares(deltaPhi, deltaEta); + registry.fill(HIST("hDeltaR"), dR, weight); + registry.fill(HIST("hDeltaRpT"), jet.pt() - (rho * jet.area()), dR, weight); + } + if (nTT > 0) { + float dphi = RecoDecay::constrainAngle(jet.phi() - phiTT); + if (isSigCol) { + for (const auto& jetWTA : jet.template matchedJetGeo_as>()) { + double deltaPhi = RecoDecay::constrainAngle(jetWTA.phi() - jet.phi(), -o2::constants::math::PI); + double deltaEta = jetWTA.eta() - jet.eta(); + double dR = RecoDecay::sqrtSumOfSquares(deltaPhi, deltaEta); + if (std::abs(dphi - o2::constants::math::PI) < 0.6) { + registry.fill(HIST("hDeltaRpTSignal"), jet.pt() - (rho * jet.area()), dR, weight); + registry.fill(HIST("hDeltaRSignal"), dR, weight); } - registry.fill(HIST("hJetSignalConstituentPt"), jet.pt(), dphi, constituent.pt()); + registry.fill(HIST("hDeltaRpTDPhiSignal"), jet.pt() - (rho * jet.area()), dphi, dR, weight); } - registry.fill(HIST("hSignalLeadingTrack"), jet.pt(), dphi, leadingPT); - } - if (!is_sig_col) { - registry.fill(HIST("hReferencePtDPhi"), dphi, jet.pt()); - if (std::abs(dphi - M_PI) < 0.6) { - registry.fill(HIST("hReferencePt"), jet.pt()); + registry.fill(HIST("hSignalPtDPhi"), dphi, jet.pt() - (rho * jet.area()), weight); + if (std::abs(dphi - o2::constants::math::PI) < 0.6) { + registry.fill(HIST("hSignalPt"), jet.pt() - (rho * jet.area()), weight); } - registry.fill(HIST("hJetReferenceConstituentMultiplicity"), jet.pt(), dphi, jet.tracksIds().size()); - for (auto& constituent : jet.template tracks_as()) { - if (constituent.pt() > leadingPT) { - leadingPT = constituent.pt(); + } + if (!isSigCol) { + for (const auto& jetWTA : jet.template matchedJetGeo_as>()) { + double deltaPhi = RecoDecay::constrainAngle(jetWTA.phi() - jet.phi(), -o2::constants::math::PI); + double deltaEta = jetWTA.eta() - jet.eta(); + double dR = RecoDecay::sqrtSumOfSquares(deltaPhi, deltaEta); + if (std::abs(dphi - o2::constants::math::PI) < 0.6) { + registry.fill(HIST("hDeltaRpTReference"), jet.pt() - (rhoReference * jet.area()), dR, weight); + registry.fill(HIST("hDeltaRReference"), dR, weight); + } + registry.fill(HIST("hDeltaRpTDPhiReference"), jet.pt() - (rhoReference * jet.area()), dphi, dR, weight); + for (double shift = 0.0; shift <= 2.0; shift += 0.1) { + registry.fill(HIST("hDeltaRpTDPhiReferenceShifts"), jet.pt() - ((rho + shift) * jet.area()), dphi, dR, shift, weight); } - registry.fill(HIST("hJetReferenceConstituentPt"), jet.pt(), dphi, constituent.pt()); } - registry.fill(HIST("hReferenceLeadingTrack"), jet.pt(), dphi, leadingPT); + registry.fill(HIST("hReferencePtDPhi"), dphi, jet.pt() - (rhoReference * jet.area()), weight); + for (double shift = 0.0; shift <= 2.0; shift += 0.1) { + registry.fill(HIST("hReferencePtDPhiShifts"), dphi, jet.pt() - ((rho + shift) * jet.area()), shift, weight); + } + if (std::abs(dphi - o2::constants::math::PI) < 0.6) { + registry.fill(HIST("hReferencePt"), jet.pt() - (rhoReference * jet.area()), weight); + } } } } } - template - void fillMCPHistograms(T const& jets, U const& particles) + template + void fillMCPHistograms(T const& jets, W const& /*jetsWTA*/, U const& particles, float weight = 1.0) { - bool is_sig_col; - std::vector phi_TT_ar; - double phi_TT; - int trig_number; - int n_TT = 0; - double leadingPT = 0; + bool isSigCol; + std::vector phiTTAr; + double phiTT = 0; + int trigNumber = 0; + int nTT = 0; + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); float dice = rand->Rndm(); - if (dice < frac_sig) - is_sig_col = true; + if (dice < fracSig) + isSigCol = true; else - is_sig_col = false; + isSigCol = false; - for (auto& particle : particles) { - if (is_sig_col && particle.pt() < pt_TTsig_max && particle.pt() > pt_TTsig_min) { - phi_TT_ar.push_back(particle.phi()); - n_TT++; + for (const auto& particle : particles) { + auto pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (!pdgParticle) { + continue; } - if (!is_sig_col && particle.pt() < pt_TTref_max && particle.pt() > pt_TTref_min) { - phi_TT_ar.push_back(particle.phi()); - n_TT++; + if ((pdgParticle->Charge() == 0.0) || (!particle.isPhysicalPrimary())) { + continue; } - registry.fill(HIST("hPtPart"), particle.pt()); - registry.fill(HIST("hEtaPart"), particle.eta()); - registry.fill(HIST("hPhiPart"), particle.phi()); - } - - if (n_TT > 0) { - trig_number = rand->Integer(n_TT); - phi_TT = phi_TT_ar[trig_number]; - if (is_sig_col) { - registry.fill(HIST("hNtrig"), 1.5); - registry.fill(HIST("hJetSignalMultiplicity"), jets.size()); - registry.fill(HIST("hSigEventTriggers"), n_TT); + if (isSigCol && particle.pt() < ptTTsigMax && particle.pt() > ptTTsigMin) { + phiTTAr.push_back(particle.phi()); + nTT++; } - if (!is_sig_col) { - registry.fill(HIST("hNtrig"), 0.5); - registry.fill(HIST("hJetReferenceMultiplicity"), jets.size()); - registry.fill(HIST("hRefEventTriggers"), n_TT); + if (!isSigCol && particle.pt() < ptTTrefMax && particle.pt() > ptTTrefMin) { + phiTTAr.push_back(particle.phi()); + nTT++; } + registry.fill(HIST("hPtPart"), particle.pt(), weight); + registry.fill(HIST("hEtaPart"), particle.eta(), weight); + registry.fill(HIST("hPhiPart"), particle.phi(), weight); } - for (auto& jet : jets) { - registry.fill(HIST("hJetPt"), jet.pt()); - registry.fill(HIST("hJetEta"), jet.eta()); - registry.fill(HIST("hJetPhi"), jet.phi()); - if (n_TT > 0) { - float dphi = dPhi(jet.phi(), phi_TT); - if (is_sig_col) { - registry.fill(HIST("hSignalPtDPhi"), dphi, jet.pt()); - if (std::abs(dphi - M_PI) < 0.6) { - registry.fill(HIST("hSignalPt"), jet.pt()); + if (nTT > 0) { + trigNumber = rand->Integer(nTT); + phiTT = phiTTAr[trigNumber]; + if (isSigCol) { + registry.fill(HIST("hNtrig"), 1.5, weight); + registry.fill(HIST("hSigEventTriggers"), nTT, weight); + } + if (!isSigCol) { + registry.fill(HIST("hNtrig"), 0.5, weight); + registry.fill(HIST("hRefEventTriggers"), nTT, weight); + } + } + + for (const auto& jet : jets) { + if (jet.pt() > pTHatMaxMCP * pTHat) { + continue; + } + registry.fill(HIST("hJetPt"), jet.pt(), weight); + registry.fill(HIST("hJetEta"), jet.eta(), weight); + registry.fill(HIST("hJetPhi"), jet.phi(), weight); + for (const auto& jetWTA : jet.template matchedJetGeo_as>()) { + double deltaPhi = RecoDecay::constrainAngle(jetWTA.phi() - jet.phi(), -o2::constants::math::PI); + double deltaEta = jetWTA.eta() - jet.eta(); + double dR = RecoDecay::sqrtSumOfSquares(deltaPhi, deltaEta); + registry.fill(HIST("hDeltaRPart"), dR, weight); + registry.fill(HIST("hDeltaRpTPart"), jet.pt(), dR, weight); + } + if (nTT > 0) { + float dphi = RecoDecay::constrainAngle(jet.phi() - phiTT); + if (isSigCol) { + for (const auto& jetWTA : jet.template matchedJetGeo_as>()) { + double deltaPhi = RecoDecay::constrainAngle(jetWTA.phi() - jet.phi(), -o2::constants::math::PI); + double deltaEta = jetWTA.eta() - jet.eta(); + double dR = RecoDecay::sqrtSumOfSquares(deltaPhi, deltaEta); + if (std::abs(dphi - o2::constants::math::PI) < 0.6) { + registry.fill(HIST("hDeltaRpTSignalPart"), jet.pt(), dR, weight); + registry.fill(HIST("hDeltaRSignalPart"), dR, weight); + } + registry.fill(HIST("hDeltaRpTDPhiSignalPart"), jet.pt(), dphi, dR, weight); } - registry.fill(HIST("hJetSignalConstituentMultiplicity"), jet.pt(), dphi, jet.tracksIds().size()); - for (auto& constituent : jet.template tracks_as()) { - if (constituent.pt() > leadingPT) { - leadingPT = constituent.pt(); + registry.fill(HIST("hSignalPtDPhi"), dphi, jet.pt(), weight); + if (std::abs(dphi - o2::constants::math::PI) < 0.6) { + registry.fill(HIST("hSignalPt"), jet.pt(), weight); + } + } + if (!isSigCol) { + for (const auto& jetWTA : jet.template matchedJetGeo_as>()) { + double deltaPhi = RecoDecay::constrainAngle(jetWTA.phi() - jet.phi(), -o2::constants::math::PI); + double deltaEta = jetWTA.eta() - jet.eta(); + double dR = RecoDecay::sqrtSumOfSquares(deltaPhi, deltaEta); + if (std::abs(dphi - o2::constants::math::PI) < 0.6) { + registry.fill(HIST("hDeltaRpTPartReference"), jet.pt(), dR, weight); + registry.fill(HIST("hDeltaRPartReference"), dR, weight); } - registry.fill(HIST("hJetSignalConstituentPt"), jet.pt(), dphi, constituent.pt()); + registry.fill(HIST("hDeltaRpTDPhiReferencePart"), jet.pt(), dphi, dR, weight); } - registry.fill(HIST("hSignalLeadingTrack"), jet.pt(), dphi, leadingPT); + registry.fill(HIST("hReferencePtDPhi"), dphi, jet.pt(), weight); + if (std::abs(dphi - o2::constants::math::PI) < 0.6) { + registry.fill(HIST("hReferencePt"), jet.pt(), weight); + } + } + } + } + } + + template + void fillMatchedHistograms(T const& jetBase, V const& mcdjetsWTA, W const& mcpjetsWTA, U const&, float weight = 1.0, float rho = 0.0) + { + double dR = 0; + double dRp = 0; + + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (jetBase.pt() > pTHatMaxMCD * pTHat) { + return; + } + + for (const auto& mcdjetWTA : mcdjetsWTA) { + double djet = RecoDecay::sqrtSumOfSquares(RecoDecay::constrainAngle(jetBase.phi() - mcdjetWTA.phi(), -o2::constants::math::PI), jetBase.eta() - mcdjetWTA.eta()); + if (mcdjetWTA.pt() > pTHatMaxMCD * pTHat) { + continue; + } + if (djet < 0.6 * jetR) { + dR = djet; + break; + } + } + + if (jetBase.has_matchedJetGeo()) { + for (const auto& jetTag : jetBase.template matchedJetGeo_as>()) { + if (jetTag.pt() > pTHatMaxMCP * pTHat) { + continue; } - if (!is_sig_col) { - registry.fill(HIST("hReferencePtDPhi"), dphi, jet.pt()); - if (std::abs(dphi - M_PI) < 0.6) { - registry.fill(HIST("hReferencePt"), jet.pt()); + for (const auto& mcpjetWTA : mcpjetsWTA) { + double djetp = RecoDecay::sqrtSumOfSquares(RecoDecay::constrainAngle(jetTag.phi() - mcpjetWTA.phi(), -o2::constants::math::PI), jetTag.eta() - mcpjetWTA.eta()); + if (mcpjetWTA.pt() > pTHatMaxMCP * pTHat) { + continue; } - registry.fill(HIST("hJetReferenceConstituentMultiplicity"), jet.pt(), dphi, jet.tracksIds().size()); - for (auto& constituent : jet.template tracks_as()) { - if (constituent.pt() > leadingPT) { - leadingPT = constituent.pt(); - } - registry.fill(HIST("hJetReferenceConstituentPt"), jet.pt(), dphi, constituent.pt()); + if (djetp < 0.6 * jetR) { + dRp = djetp; + break; } - registry.fill(HIST("hReferenceLeadingTrack"), jet.pt(), dphi, leadingPT); } + registry.fill(HIST("hPtMatched"), jetBase.pt() - (rho * jetBase.area()), jetTag.pt(), weight); + registry.fill(HIST("hPhiMatched"), jetBase.phi(), jetTag.phi(), weight); + registry.fill(HIST("hPtResolution"), jetTag.pt(), (jetTag.pt() - (jetBase.pt() - (rho * jetBase.area()))) / jetTag.pt(), weight); + registry.fill(HIST("hPhiResolution"), jetTag.pt(), jetTag.phi() - jetBase.phi(), weight); + registry.fill(HIST("hDeltaRMatched"), dR, dRp, weight); + registry.fill(HIST("hDeltaRResolution"), jetTag.pt(), dRp - dR, weight); + registry.fill(HIST("hFullMatching"), jetBase.pt() - (rho * jetBase.area()), jetTag.pt(), jetBase.phi(), jetTag.phi(), dR, dRp, weight); + registry.fill(HIST("hPtMatched1d"), jetTag.pt(), weight); + registry.fill(HIST("hDeltaRMatched1d"), dRp, weight); } } } - void processData(soa::Filtered::iterator const& collision, soa::Filtered> const& jets, soa::Filtered const& tracks) + void processData(soa::Filtered::iterator const& collision, + soa::Filtered> const& jets, + soa::Filtered> const& jetsWTA, + soa::Filtered const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + fillHistograms(jets, jetsWTA, tracks); + } + PROCESS_SWITCH(JetHadronRecoil, processData, "process data", true); + + void processDataWithRhoSubtraction(soa::Filtered>::iterator const& collision, + soa::Filtered> const& jets, + soa::Filtered> const& jetsWTA, + soa::Filtered const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + fillHistograms(jets, jetsWTA, tracks, 1.0, collision.rho()); + } + PROCESS_SWITCH(JetHadronRecoil, processDataWithRhoSubtraction, "process data with rho subtraction", false); + + void processMCD(soa::Filtered::iterator const& collision, + soa::Filtered> const& jets, + soa::Filtered> const& jetsWTA, + soa::Filtered const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + fillHistograms(jets, jetsWTA, tracks); + } + PROCESS_SWITCH(JetHadronRecoil, processMCD, "process MC detector level", false); + + void processMCDWithRhoSubtraction(soa::Filtered>::iterator const& collision, + soa::Filtered> const& jets, + soa::Filtered> const& jetsWTA, + soa::Filtered const& tracks) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } - fillHistograms(jets, tracks); + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + fillHistograms(jets, jetsWTA, tracks, 1.0, collision.rho()); + } + PROCESS_SWITCH(JetHadronRecoil, processMCDWithRhoSubtraction, "process MC detector level with rho subtraction", false); + + void processMCDWeighted(soa::Filtered>::iterator const& collision, + aod::JMcCollisions const&, + soa::Filtered> const& jets, + soa::Filtered> const& jetsWTA, + soa::Filtered const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ(), collision.mcCollision().weight()); + fillHistograms(jets, jetsWTA, tracks, collision.mcCollision().weight()); + } + PROCESS_SWITCH(JetHadronRecoil, processMCDWeighted, "process MC detector level with event weights", false); + + void processMCDWeightedWithRhoSubtraction(soa::Filtered>::iterator const& collision, + aod::JMcCollisions const&, + soa::Filtered> const& jets, + soa::Filtered> const& jetsWTA, + soa::Filtered const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ(), collision.mcCollision().weight()); + fillHistograms(jets, jetsWTA, tracks, collision.mcCollision().weight(), collision.rho()); } - PROCESS_SWITCH(hJetAnalysis, processData, "process data", true); + PROCESS_SWITCH(JetHadronRecoil, processMCDWeightedWithRhoSubtraction, "process MC detector level with event weights and rho subtraction", false); - void processMCD(soa::Filtered::iterator const& collision, soa::Filtered> const& jets, soa::Filtered const& tracks) + void processMCP(aod::JetMcCollision const& collision, + soa::Filtered> const& jets, + soa::Filtered> const& jetsWTA, + soa::Filtered const& particles) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (std::abs(collision.posZ()) > vertexZCut) { + return; + } + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { return; } - fillHistograms(jets, tracks); + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + fillMCPHistograms(jets, jetsWTA, particles); } - PROCESS_SWITCH(hJetAnalysis, processMCD, "process MC detector level", false); + PROCESS_SWITCH(JetHadronRecoil, processMCP, "process MC particle level", false); - void processMCP(JetMcCollision const&, soa::Filtered> const& jets, JetParticles const& particles) + void processMCPWeighted(aod::JetMcCollision const& collision, + soa::Filtered> const& jets, + soa::Filtered> const& jetsWTA, + soa::Filtered const& particles) + { + if (std::abs(collision.posZ()) > vertexZCut) { + return; + } + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ(), collision.weight()); + fillMCPHistograms(jets, jetsWTA, particles, collision.weight()); + } + PROCESS_SWITCH(JetHadronRecoil, processMCPWeighted, "process MC particle level with event weights", false); + + void processJetsMCPMCDMatched(soa::Filtered::iterator const& collision, + soa::Filtered> const& mcdjets, + soa::Filtered> const& mcdjetsWTA, + soa::Filtered> const& mcpjetsWTA, + aod::JetTracks const&, + aod::JetParticles const&, + aod::JetMcCollisions const&, + soa::Filtered> const& mcpjets) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + const auto& mcpjetsWTACut = mcpjetsWTA.sliceBy(partJetsPerCollision, collision.mcCollisionId()); + for (const auto& mcdjet : mcdjets) { + fillMatchedHistograms(mcdjet, mcdjetsWTA, mcpjetsWTACut, mcpjets); + } + } + PROCESS_SWITCH(JetHadronRecoil, processJetsMCPMCDMatched, "process MC matched (inc jets)", false); + + void processJetsMCPMCDMatchedWithRhoSubtraction(soa::Filtered>::iterator const& collision, + soa::Filtered> const& mcdjets, + soa::Filtered> const& mcdjetsWTA, + soa::Filtered> const& mcpjetsWTA, + aod::JetTracks const&, + aod::JetParticles const&, + aod::JetMcCollisions const&, + soa::Filtered> const& mcpjets) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + const auto& mcpjetsWTACut = mcpjetsWTA.sliceBy(partJetsPerCollision, collision.mcCollisionId()); + for (const auto& mcdjet : mcdjets) { + fillMatchedHistograms(mcdjet, mcdjetsWTA, mcpjetsWTACut, mcpjets, 1.0, collision.rho()); + } + } + PROCESS_SWITCH(JetHadronRecoil, processJetsMCPMCDMatchedWithRhoSubtraction, "process MC matched (inc jets) with rho subtraction", false); + + void processJetsMCPMCDMatchedWeighted(soa::Filtered::iterator const& collision, + soa::Filtered> const& mcdjets, + soa::Filtered> const& mcdjetsWTA, + soa::Filtered> const& mcpjetsWTA, + aod::JetTracks const&, + aod::JetParticles const&, + aod::JetMcCollisions const&, + soa::Filtered> const& mcpjets) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + const auto& mcpjetsWTACut = mcpjetsWTA.sliceBy(partJetsPerCollision, collision.mcCollisionId()); + for (const auto& mcdjet : mcdjets) { + fillMatchedHistograms(mcdjet, mcdjetsWTA, mcpjetsWTACut, mcpjets, mcdjet.eventWeight()); + } + } + PROCESS_SWITCH(JetHadronRecoil, processJetsMCPMCDMatchedWeighted, "process MC matched with event weights (inc jets)", false); + + void processJetsMCPMCDMatchedWeightedWithRhoSubtraction(soa::Filtered>::iterator const& collision, + soa::Filtered> const& mcdjets, + soa::Filtered> const& mcdjetsWTA, + soa::Filtered> const& mcpjetsWTA, + aod::JetTracks const&, + aod::JetParticles const&, + aod::JetMcCollisions const&, + soa::Filtered> const& mcpjets) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + const auto& mcpjetsWTACut = mcpjetsWTA.sliceBy(partJetsPerCollision, collision.mcCollisionId()); + for (const auto& mcdjet : mcdjets) { + fillMatchedHistograms(mcdjet, mcdjetsWTA, mcpjetsWTACut, mcpjets, mcdjet.eventWeight(), collision.rho()); + } + } + PROCESS_SWITCH(JetHadronRecoil, processJetsMCPMCDMatchedWeightedWithRhoSubtraction, "process MC matched with event weights (inc jets) and rho subtraction", false); + + void processRecoilJetsMCPMCDMatched(soa::Filtered::iterator const& collision, + soa::Filtered> const& mcdjets, + soa::Filtered> const& mcdjetsWTA, + soa::Filtered> const& mcpjetsWTA, + soa::Filtered const& tracks, + soa::Filtered const&, + aod::JetMcCollisions const&, + soa::Filtered> const& mcpjets) { - fillMCPHistograms(jets, particles); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + const auto& mcpjetsWTACut = mcpjetsWTA.sliceBy(partJetsPerCollision, collision.mcCollisionId()); + bool ishJetEvent = false; + for (const auto& track : tracks) { + if (track.pt() < ptTTsigMax && track.pt() > ptTTsigMin) { + ishJetEvent = true; + break; + } + } + if (ishJetEvent) { + for (const auto& mcdjet : mcdjets) { + fillMatchedHistograms(mcdjet, mcdjetsWTA, mcpjetsWTACut, mcpjets); + } + } + } + PROCESS_SWITCH(JetHadronRecoil, processRecoilJetsMCPMCDMatched, "process MC matched (recoil jets)", false); + + void processRecoilJetsMCPMCDMatchedWeighted(soa::Filtered::iterator const& collision, + soa::Filtered> const& mcdjets, + soa::Filtered> const& mcdjetsWTA, + soa::Filtered> const& mcpjetsWTA, + soa::Filtered const& tracks, + soa::Filtered const&, + aod::JetMcCollisions const&, + soa::Filtered> const& mcpjets) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + const auto& mcpjetsWTACut = mcpjetsWTA.sliceBy(partJetsPerCollision, collision.mcCollisionId()); + bool ishJetEvent = false; + for (const auto& track : tracks) { + if (track.pt() < ptTTsigMax && track.pt() > ptTTsigMin) { + ishJetEvent = true; + break; + } + } + if (ishJetEvent) { + for (const auto& mcdjet : mcdjets) { + fillMatchedHistograms(mcdjet, mcdjetsWTA, mcpjetsWTACut, mcpjets, mcdjet.eventWeight()); + } + } } - PROCESS_SWITCH(hJetAnalysis, processMCP, "process MC particle level", false); + PROCESS_SWITCH(JetHadronRecoil, processRecoilJetsMCPMCDMatchedWeighted, "process MC matched with event weights (recoil jets)", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"hJetAnalysis"})}; } +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGJE/Tasks/jetLundReclustering.cxx b/PWGJE/Tasks/jetLundReclustering.cxx index ef01fad490d..c18053343cf 100644 --- a/PWGJE/Tasks/jetLundReclustering.cxx +++ b/PWGJE/Tasks/jetLundReclustering.cxx @@ -21,6 +21,7 @@ #include #include #include +#include #include "fastjet/contrib/LundGenerator.hh" #include "fastjet/PseudoJet.hh" @@ -67,11 +68,11 @@ struct JetLundReclustering { Configurable jet_max_eta{"jet_max_eta", 0.5, "maximum jet eta"}; Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; - int eventSelection = -1; + std::vector eventSelectionBits; void init(InitContext const&) { - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(eventSelections)); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); registry.add("PrimaryLundPlane_kT", "Primary Lund 3D plane;ln(R/Delta);ln(k_{t}/GeV);{p}_{t}", {HistType::kTH3F, {{100, 0, 10}, {100, -10, 10}, {20, 0, 200}}}); registry.add("PrimaryLundPlane_z", "Primary Lund 3D plane;ln(R/Delta);ln(1/z);{p}_{t}", {HistType::kTH3F, {{100, 0, 10}, {100, 0, 10}, {20, 0, 200}}}); @@ -112,23 +113,23 @@ struct JetLundReclustering { } // Dummy process - void processDummy(JetCollisions const&) + void processDummy(aod::JetCollisions const&) { } PROCESS_SWITCH(JetLundReclustering, processDummy, "Dummy process function, turned on by default", true); // Process function for charged jets - void processChargedJets(soa::Filtered::iterator const& collision, + void processChargedJets(soa::Filtered::iterator const& collision, soa::Filtered> const& jets, - JetTracks const&) + aod::JetTracks const&) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } for (const auto& jet : jets) { registry.fill(HIST("jet_PtEtaPhi"), jet.pt(), jet.eta(), jet.phi()); jetConstituents.clear(); - for (auto& jetConstituent : jet.tracks_as()) { + for (auto& jetConstituent : jet.tracks_as()) { fastjetutilities::fillTracks(jetConstituent, jetConstituents, jetConstituent.globalIndex()); } // Perform jet reclustering diff --git a/PWGJE/Tasks/jetmatchingqa.cxx b/PWGJE/Tasks/jetMatchingQA.cxx similarity index 87% rename from PWGJE/Tasks/jetmatchingqa.cxx rename to PWGJE/Tasks/jetMatchingQA.cxx index 5dc89b8536b..e752b47e2a5 100644 --- a/PWGJE/Tasks/jetmatchingqa.cxx +++ b/PWGJE/Tasks/jetMatchingQA.cxx @@ -42,6 +42,7 @@ struct JetMatchingQA { {"h_jet_match_geo_pt_zoom", "geo-matched jets", {HistType::kTH2F, {{1000, 0.0f, 10.0f, "#it{p}_{T} (particle level, GeV/#it{c})"}, {1000, 0.0f, 10.0f, "#it{p}_{T} (detector level, GeV/#it{c})"}}}}, {"h_jet_match_geo_dpt", "geo-matched jets", {HistType::kTH1F, {{100, -10.0f, 10.0f, "#Delta#it{p}_{T} (particle level vs detector level, GeV/#it{c})"}}}}, + {"h2_jet_pt_jet_match_geo_dptoverpt", "geo-matched jets", {HistType::kTH2F, {{2000, 0.0f, 200.0f, "#it{p}_{T} (detector level, GeV/#it{c})"}, {700, -5.0f, 2.0f, "(#it{p}_{T, part}-#it{p}_{T, det})/#it{p}_{T,part} (particle level vs detector level, GeV/#it{c})"}}}}, {"h_jet_match_geo_PtLeadingPart", "geo-matched jets", {HistType::kTH2F, {{1000, 0.0f, 10.0f, "#it{p}_{T}^{leading} (particle level, GeV/#it{c})"}, {1000, 0.0f, 10.0f, "#it{p}_{T}^{leading} (detector level, GeV/#it{c})"}}}}, {"h_jet_match_geo_phi", "geo-matched jets", {HistType::kTH2F, {{80, -1.0f, 7.0f, "#phi_{jet} (particle level, rad)"}, {80, -1.0f, 7.0f, "#phi_{jet} (detector level, rad)"}}}}, {"h_jet_match_geo_eta", "geo-matched jets", {HistType::kTH2F, {{70, -0.7f, 0.7f, "#it{p}_{T}^{particle level} (GeV/#it{c})"}, {70, -0.7f, 0.7f, "#it{p}_{T} (detector level, GeV/#it{c})"}}}}, @@ -76,12 +77,12 @@ struct JetMatchingQA { { } - void processDummy(JetMcCollisions const&) + void processDummy(aod::JetMcCollisions const&) { } PROCESS_SWITCH(JetMatchingQA, processDummy, "Dummy process", true); - void processMCD(JetCollision const&, JetParticles const&, JetTracksMCD const&, + void processMCD(aod::JetCollision const&, aod::JetParticles const&, aod::JetTracksMCD const&, BaseJetCollection const& djets, TagJetCollection const&) { for (const auto& djet : djets) { @@ -105,13 +106,13 @@ struct JetMatchingQA { registry.fill(HIST("h_jet_match_hf_Nconst"), pjet.tracksIds().size(), djet.tracksIds().size()); double pjet_pt_lead = 0.; - for (auto& mcparticle : pjet.template tracks_as()) { + for (auto& mcparticle : pjet.template tracks_as()) { if (mcparticle.pt() > pjet_pt_lead) { pjet_pt_lead = mcparticle.pt(); } } double djet_pt_lead = 0.; - for (auto& track : djet.template tracks_as()) { + for (auto& track : djet.template tracks_as()) { if (track.pt() > djet_pt_lead) { djet_pt_lead = track.pt(); } @@ -127,18 +128,19 @@ struct JetMatchingQA { registry.fill(HIST("h_jet_match_geo_pt_zoom"), pjet.pt(), djet.pt()); registry.fill(HIST("h_jet_match_geo_dpt"), pjet.pt() - djet.pt()); + registry.fill(HIST("h2_jet_pt_jet_match_geo_dptoverpt"), pjet.pt(), (pjet.pt() - djet.pt()) * 1. / pjet.pt()); registry.fill(HIST("h_jet_match_geo_phi"), pjet.phi(), djet.phi()); registry.fill(HIST("h_jet_match_geo_eta"), pjet.eta(), djet.eta()); registry.fill(HIST("h_jet_match_geo_Nconst"), pjet.tracksIds().size(), djet.tracksIds().size()); double pjet_pt_lead = 0.; - for (auto& mcparticle : pjet.template tracks_as()) { + for (auto& mcparticle : pjet.template tracks_as()) { if (mcparticle.pt() > pjet_pt_lead) { pjet_pt_lead = mcparticle.pt(); } } double djet_pt_lead = 0.; - for (auto& track : djet.template tracks_as()) { + for (auto& track : djet.template tracks_as()) { if (track.pt() > djet_pt_lead) { djet_pt_lead = track.pt(); } @@ -159,13 +161,13 @@ struct JetMatchingQA { registry.fill(HIST("h_jet_match_pt_Nconst"), pjet.tracksIds().size(), djet.tracksIds().size()); double pjet_pt_lead = 0.; - for (auto& mcparticle : pjet.template tracks_as()) { + for (auto& mcparticle : pjet.template tracks_as()) { if (mcparticle.pt() > pjet_pt_lead) { pjet_pt_lead = mcparticle.pt(); } } double djet_pt_lead = 0.; - for (auto& track : djet.template tracks_as()) { + for (auto& track : djet.template tracks_as()) { if (track.pt() > djet_pt_lead) { djet_pt_lead = track.pt(); } @@ -174,9 +176,9 @@ struct JetMatchingQA { } } } - PROCESS_SWITCH(JetMatchingQA, processMCD, "QA on detector-level jets", true); + PROCESS_SWITCH(JetMatchingQA, processMCD, "QA on detector-level jets", false); - void processMCP(JetMcCollision const&, + void processMCP(aod::JetMcCollision const&, TagJetCollection const& pjets, BaseJetCollection const&) { for (const auto& pjet : pjets) { @@ -188,7 +190,7 @@ struct JetMatchingQA { } } } - PROCESS_SWITCH(JetMatchingQA, processMCP, "QA on generator-level jets", true); + PROCESS_SWITCH(JetMatchingQA, processMCP, "QA on generator-level jets", false); }; using ChargedDetectorLevelJets = soa::Join; @@ -207,6 +209,10 @@ using BplusChargedDetectorLevelJets = soa::Join; using BplusChargedJetMatchingQA = JetMatchingQA; +using DielectronChargedDetectorLevelJets = soa::Join; +using DielectronChargedParticleLevelJets = soa::Join; +using DielectronChargedJetMatchingQA = JetMatchingQA; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { std::vector tasks; @@ -214,7 +220,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-matching-qa-ch"})); tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-qa-d0-ch"})); tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-qa-lc-ch"})); - tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-qa-bplus-ch"})); + // tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-qa-bplus-ch"})); + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-qa-dielectron-ch"})); return WorkflowSpec{tasks}; } diff --git a/PWGJE/Tasks/jetplanarflow.cxx b/PWGJE/Tasks/jetPlanarFlow.cxx similarity index 93% rename from PWGJE/Tasks/jetplanarflow.cxx rename to PWGJE/Tasks/jetPlanarFlow.cxx index a4c5527ac64..d54ebea1ac2 100644 --- a/PWGJE/Tasks/jetplanarflow.cxx +++ b/PWGJE/Tasks/jetPlanarFlow.cxx @@ -14,6 +14,7 @@ /// \author Nima Zardoshti // +#include #include #include "Framework/AnalysisTask.h" @@ -106,7 +107,7 @@ struct JetPlanarFlowTask { Configurable zCutSD{"zCutSD", 0.10, "SoftDrop z cut"}; int trackSelection = -1; - int eventSelection = -1; + std::vector eventSelectionBits; std::string particleSelection; uint32_t precisionMask; @@ -120,7 +121,7 @@ struct JetPlanarFlowTask { void init(o2::framework::InitContext&) { trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(eventSelections)); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); particleSelection = static_cast(particleSelections); precisionMask = 0xFFFFFC00; } @@ -228,7 +229,7 @@ struct JetPlanarFlowTask { if (particleSelection == "PhysicalPrimary" && !track.isPhysicalPrimary()) { continue; } - if (isinf(track.eta())) { + if (std::isinf(track.eta())) { continue; } } else { @@ -273,16 +274,16 @@ struct JetPlanarFlowTask { } } - void processDummy(JetTracks const&) + void processDummy(aod::JetTracks const&) { } PROCESS_SWITCH(JetPlanarFlowTask, processDummy, "Dummy process function turned on by default", true); - void processChargedJetsData(soa::Filtered::iterator const& collision, + void processChargedJetsData(soa::Filtered::iterator const& collision, soa::Join const& jets, - JetTracks const& tracks) + aod::JetTracks const& tracks) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } for (auto const& jet : jets) { @@ -296,11 +297,11 @@ struct JetPlanarFlowTask { } PROCESS_SWITCH(JetPlanarFlowTask, processChargedJetsData, "charged jet analysis", false); - void processChargedRhoAreaSubtractedJetsData(soa::Filtered>::iterator const& collision, + void processChargedRhoAreaSubtractedJetsData(soa::Filtered>::iterator const& collision, soa::Join const& jets, - JetTracks const& tracks) + aod::JetTracks const& tracks) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } for (auto const& jet : jets) { @@ -314,11 +315,11 @@ struct JetPlanarFlowTask { } PROCESS_SWITCH(JetPlanarFlowTask, processChargedRhoAreaSubtractedJetsData, "charged rho-area subtracted jet analysis", false); - void processChargedJetsEventWiseSubData(soa::Filtered::iterator const& collision, + void processChargedJetsEventWiseSubData(soa::Filtered::iterator const& collision, soa::Join const& jets, - JetTracksSub const& tracks) + aod::JetTracksSub const& tracks) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } for (auto const& jet : jets) { @@ -332,11 +333,11 @@ struct JetPlanarFlowTask { } PROCESS_SWITCH(JetPlanarFlowTask, processChargedJetsEventWiseSubData, "charged event-wise subtracted jet analysis", false); - void processChargedJetsMCD(soa::Filtered::iterator const& collision, + void processChargedJetsMCD(soa::Filtered::iterator const& collision, soa::Join const& jets, - JetTracks const& tracks) + aod::JetTracks const& tracks) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } for (auto const& jet : jets) { @@ -350,9 +351,9 @@ struct JetPlanarFlowTask { } PROCESS_SWITCH(JetPlanarFlowTask, processChargedJetsMCD, "charged detector level jet analysis", false); - void processChargedJetsMCP(JetMcCollisions const& collision, + void processChargedJetsMCP(aod::JetMcCollisions const& collision, soa::Join const& jets, - JetParticles const& particles) + aod::JetParticles const& particles) { for (auto const& jet : jets) { diff --git a/PWGJE/Tasks/jetShape.cxx b/PWGJE/Tasks/jetShape.cxx new file mode 100644 index 00000000000..d7e1f2f0557 --- /dev/null +++ b/PWGJE/Tasks/jetShape.cxx @@ -0,0 +1,284 @@ +// 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 jetShape.cxx +/// \author Yuto Nishida +/// \brief Task for measuring the dependence of the jet shape function rho(r) on the distance r from the jet axis. + +#include +#include +#include + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" + +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct JetShapeTask { + HistogramRegistry registry{"registry", + {{"tpcTofPi", "tpcTofPi", {HistType::kTHnSparseD, {{101, -10.1f, 10.1f}, {20, -10, 10}, {25, 0, 5}, {14, 0, 7}}}}, + {"tpcPi", "tpcPi", {HistType::kTH2F, {{100, 0, 5}, {401, -10.025f, 10.025f}}}}, + {"tofPi", "tofPi", {HistType::kTH2F, {{100, 0, 5}, {401, -10.025f, 10.025f}}}}, + {"tpcTofPr", "tpcTofPr", {HistType::kTHnSparseD, {{101, -10.1f, 10.1f}, {20, -10, 10}, {25, 0, 5}, {14, 0, 7}}}}, + {"tpcPr", "tpcPr", {HistType::kTH2F, {{100, 0, 5}, {401, -10.025f, 10.025f}}}}, + {"tofPr", "tofPr", {HistType::kTH2F, {{100, 0, 5}, {401, -10.025f, 10.025f}}}}, + {"tpcDedx", "tpcDedx", {HistType::kTH2F, {{500, 0, 5}, {1000, 0, 1000}}}}, + {"tofBeta", "tofBeta", {HistType::kTH2F, {{500, 0, 5}, {450, 0.2, 1.1}}}}, + {"tofMass", "tofMass", {HistType::kTH1F, {{3000, 0, 3}}}}, + {"jetPt", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, + {"jetEta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, + {"jetPhi", "jet #phi;#phi_{jet};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}, + {"area", "area", {HistType::kTH1F, {{200, 0, 4}}}}, + {"rho", "rho", {HistType::kTH1F, {{300, 0, 300}}}}, + {"ptCorr", "Corrected jet pT; p_{T}^{corr} (GeV/c); Counts", {HistType::kTH1F, {{200, 0, 200}}}}, + {"ptCorrVsDistance", "ptcorr_vs_distance", {HistType::kTH2F, {{70, 0, 0.7}, {100, 0, 100}}}}, + {"distanceVsTrackpt", "trackpt_vs_distance", {HistType::kTH2F, {{70, 0, 0.7}, {100, 0, 100}}}}, + {"ptSum", "ptSum", {HistType::kTH2F, {{14, 0, 0.7}, {300, 0, 300}}}}, + {"ptSumBg1", "ptSumBg1", {HistType::kTH2F, {{14, 0, 0.7}, {300, 0, 300}}}}, + {"ptSumBg2", "ptSumBg2", {HistType::kTH2F, {{14, 0, 0.7}, {300, 0, 300}}}}, + {"ptVsCentrality", "ptvscentrality", {HistType::kTH2F, {{100, 0, 100}, {300, 0, 300}}}}}}; + + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + + Configurable jetPtMin{"jetPtMin", 5.0, "minimum jet pT cut"}; + Configurable jetR{"jetR", 0.4, "jet resolution parameter"}; + + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + + Configurable jetAreaFractionMin{"jetAreaFractionMin", -99.0, "used to make a cut on the jet areas"}; + Configurable leadingConstituentPtMin{"leadingConstituentPtMin", 5.0, "minimum pT selection on jet constituent"}; + Configurable leadingConstituentPtMax{"leadingConstituentPtMax", 9999.0, "maximum pT selection on jet constituent"}; + + // for jet shape + Configurable> distanceCategory{"distanceCategory", {0.00f, 0.05f, 0.10f, 0.15f, 0.20f, 0.25f, 0.30f, 0.35f, 0.40f, 0.45f, 0.50f, 0.55f, 0.60f, 0.65f, 0.70f}, "distance of category"}; + + // for ppi production + Configurable maxTpcNClsCrossedRows{"maxTpcNClsCrossedRows", 70, ""}; + Configurable maxDcaXY{"maxDcaXY", 0.2, ""}; + Configurable maxItsNCls{"maxItsNCls", 2, ""}; + + Configurable triggerMasks{"triggerMasks", "", "possible JE Trigger masks: fJetChLowPt,fJetChHighPt,fTrackLowPt,fTrackHighPt,fJetD0ChLowPt,fJetD0ChHighPt,fJetLcChLowPt,fJetLcChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt,fJetNeutralHighPt,fJetNeutralLowPt,fGammaVeryHighPtEMCAL,fGammaVeryHighPtDCAL,fGammaHighPtEMCAL,fGammaHighPtDCAL,fGammaLowPtEMCAL,fGammaLowPtDCAL,fGammaVeryLowPtEMCAL,fGammaVeryLowPtDCAL"}; + + std::vector eventSelectionBits; + int trackSelection = -1; + std::vector triggerMaskBits; + + void init(o2::framework::InitContext&) + { + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(triggerMasks); + } + + template + bool isAcceptedJet(U const& jet) + { + static constexpr double kJetAreaFractionMinValue = -98.0; + if (jetAreaFractionMin > kJetAreaFractionMinValue) { + if (jet.area() < jetAreaFractionMin * o2::constants::math::PI * (jet.r() / 100.0) * (jet.r() / 100.0)) { + return false; + } + if (jet.area() < o2::constants::math::PIHalf * (jet.r() / 100.0) * (jet.r() / 100.0)) { + return false; + } + } + static constexpr double kLeadingConstituentPtMinValue = 5.0; + static constexpr double kLeadingConstituentPtMaxValue = 9998.0; + bool checkConstituentPt = true; + bool checkConstituentMinPt = (leadingConstituentPtMin > kLeadingConstituentPtMinValue); + bool checkConstituentMaxPt = (leadingConstituentPtMax < kLeadingConstituentPtMaxValue); + if (!checkConstituentMinPt && !checkConstituentMaxPt) { + checkConstituentPt = false; + } + + if (checkConstituentPt) { + bool isMinLeadingConstituent = !checkConstituentMinPt; + bool isMaxLeadingConstituent = true; + + for (const auto& constituent : jet.template tracks_as()) { + double pt = constituent.pt(); + + if (checkConstituentMinPt && pt >= leadingConstituentPtMin) { + isMinLeadingConstituent = true; + } + if (checkConstituentMaxPt && pt > leadingConstituentPtMax) { + isMaxLeadingConstituent = false; + } + } + return isMinLeadingConstituent && isMaxLeadingConstituent; + } + + return true; + } + + Filter jetCuts = aod::jet::pt > jetPtMin&& aod::jet::r == nround(jetR.node() * 100.0f); + Filter collisionFilter = nabs(aod::jcollision::posZ) < vertexZCut; + Filter mcCollisionFilter = nabs(aod::jmccollision::posZ) < vertexZCut; + + Preslice> perMcCollisionJets = aod::jet::mcCollisionId; + + void processJetShape(soa::Filtered>::iterator const& collision, aod::JetTracks const& tracks, soa::Join const& jets) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + std::vector ptDensity; + std::vector ptDensityBg1; + std::vector ptDensityBg2; + + ptDensity.reserve(distanceCategory->size() - 1); + ptDensityBg1.reserve(distanceCategory->size() - 1); + ptDensityBg2.reserve(distanceCategory->size() - 1); + + // std::cout << collision.centrality() << std::endl; + + for (auto const& jet : jets) { + if (!isAcceptedJet(jet)) { + continue; + } + + // Get underlying event subtracted jet.pt() as ptCorr + float ptCorr = jet.pt() - collision.rho() * jet.area(); + + for (const auto& track : tracks) { + float preDeltaPhi1 = track.phi() - jet.phi(); + float deltaPhi1 = RecoDecay::constrainAngle(preDeltaPhi1); + float deltaEta = track.eta() - jet.eta(); + + // calculate distance from jet axis + float distance = std::sqrt(deltaEta * deltaEta + deltaPhi1 * deltaPhi1); + + registry.fill(HIST("ptCorrVsDistance"), distance, ptCorr); + registry.fill(HIST("ptVsCentrality"), collision.centrality(), track.pt()); + + // calculate compornents of jetshapefunction rho(r) + std::vector trackPtSum; + std::vector trackPtSumBg1; + std::vector trackPtSumBg2; + trackPtSum.reserve(distanceCategory->size() - 1); + trackPtSumBg1.reserve(distanceCategory->size() - 1); + trackPtSumBg2.reserve(distanceCategory->size() - 1); + float phiBg1 = jet.phi() + (o2::constants::math::PIHalf); + float phiBg2 = jet.phi() - (o2::constants::math::PIHalf); + + float preDeltaPhiBg1 = track.phi() - phiBg1; + float preDeltaPhiBg2 = track.phi() - phiBg2; + + float deltaPhiBg1 = RecoDecay::constrainAngle(preDeltaPhiBg1); + float deltaPhiBg2 = RecoDecay::constrainAngle(preDeltaPhiBg2); + + float distanceBg1 = std::sqrt(deltaEta * deltaEta + deltaPhiBg1 * deltaPhiBg1); + float distanceBg2 = std::sqrt(deltaEta * deltaEta + deltaPhiBg2 * deltaPhiBg2); + + for (size_t i = 0; i < distanceCategory->size() - 1; i++) { + if (distance < distanceCategory->at(i + 1)) + trackPtSum[i] += track.pt(); + if (distanceBg1 < distanceCategory->at(i + 1)) + trackPtSumBg1[i] += track.pt(); + if (distanceBg2 < distanceCategory->at(i + 1)) + trackPtSumBg2[i] += track.pt(); + } + + for (size_t i = 0; i < distanceCategory->size() - 1; i++) { + ptDensity[i] += trackPtSum[i] / ((distanceCategory->at(i + 1) - distanceCategory->at(i)) * ptCorr); + ptDensityBg1[i] += trackPtSumBg1[i] / ((distanceCategory->at(i + 1) - distanceCategory->at(i)) * ptCorr); + ptDensityBg2[i] += trackPtSumBg2[i] / ((distanceCategory->at(i + 1) - distanceCategory->at(i)) * ptCorr); + } + } + + registry.fill(HIST("jetPt"), jet.pt()); + registry.fill(HIST("jetEta"), jet.eta()); + registry.fill(HIST("jetPhi"), jet.phi()); + registry.fill(HIST("area"), jet.area()); + registry.fill(HIST("rho"), collision.rho()); + registry.fill(HIST("ptCorr"), ptCorr); + + for (size_t i = 0; i < distanceCategory->size() - 1; i++) { + double jetX = (distanceCategory->at(i + 1) - distanceCategory->at(i)) * i + (distanceCategory->at(i + 1) - distanceCategory->at(i)) / 2; + double jetShapeFunction = ptDensity[i + 1]; + double jetShapeFunctionBg1 = ptDensityBg1[i + 1]; + double jetShapeFunctionBg2 = ptDensityBg2[i + 1]; + registry.fill(HIST("ptSum"), jetX, jetShapeFunction); + registry.fill(HIST("ptSumBg1"), jetX, jetShapeFunctionBg1); + registry.fill(HIST("ptSumBg2"), jetX, jetShapeFunctionBg2); + } + } + } + PROCESS_SWITCH(JetShapeTask, processJetShape, "JetShape", true); + + void processProductionRatio(soa::Filtered>::iterator const& collision, soa::Join const& tracks, soa::Join const& jets) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + + for (auto const& jet : jets) { + if (!isAcceptedJet(jet)) { + continue; + } + + // tracks conditions + for (const auto& track : tracks) { + if (track.tpcNClsCrossedRows() < maxTpcNClsCrossedRows) + continue; + if (std::fabs(track.dcaXY()) > maxDcaXY) + continue; + if (track.itsNCls() < maxItsNCls) { + continue; + } + + // PID check + registry.fill(HIST("tpcDedx"), track.pt(), track.tpcSignal()); + registry.fill(HIST("tofBeta"), track.pt(), track.beta()); + registry.fill(HIST("tofMass"), track.mass()); + + // for calculate purity + registry.fill(HIST("tpcPi"), track.pt(), track.tpcNSigmaPi()); + registry.fill(HIST("tofPi"), track.pt(), track.tofNSigmaPi()); + registry.fill(HIST("tpcPr"), track.pt(), track.tpcNSigmaPr()); + registry.fill(HIST("tofPr"), track.pt(), track.tofNSigmaPr()); + + // for calculate distance + float preDeltaPhi1 = track.phi() - jet.phi(); + float deltaPhi1 = RecoDecay::constrainAngle(preDeltaPhi1); + float deltaEta = track.eta() - jet.eta(); + + // calculate distance from jet axis + float distance = std::sqrt(deltaEta * deltaEta + deltaPhi1 * deltaPhi1); + + registry.fill(HIST("distanceVsTrackpt"), distance, track.pt()); + registry.fill(HIST("tpcTofPi"), track.tpcNSigmaPi(), track.tofNSigmaPi(), track.pt(), distance); + registry.fill(HIST("tpcTofPr"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt(), distance); + } + } + } + PROCESS_SWITCH(JetShapeTask, processProductionRatio, "production ratio", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGJE/Tasks/jetSpectraCharged.cxx b/PWGJE/Tasks/jetSpectraCharged.cxx new file mode 100644 index 00000000000..a1adc4e2f75 --- /dev/null +++ b/PWGJE/Tasks/jetSpectraCharged.cxx @@ -0,0 +1,1048 @@ +// 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 jetSpectraCharged.cxx +/// \brief Charged-particle jet spectra task +/// \author Nima Zardoshti , Aimeric Landou , Wenhui Feng + +#include +#include +#include +#include +#include +#include + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" + +#include "PWGJE/Core/JetDerivedDataUtilities.h" + +#include "EventFiltering/filterTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct JetSpectraCharged { + + using McParticleCollision = soa::Join; + using ChargedMCDMatchedJets = soa::Join; + using ChargedMCPMatchedJets = soa::Join; + using ChargedMCDMatchedJetsWeighted = soa::Join; + using ChargedMCPMatchedJetsWeighted = soa::Join; + + HistogramRegistry registry; + + Configurable selectedJetsRadius{"selectedJetsRadius", 0.2, "resolution parameter for histograms without radius"}; + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + Configurable centralityMin{"centralityMin", -999.0, "minimum centrality"}; + Configurable centralityMax{"centralityMax", 999.0, "maximum centrality"}; + Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum eta acceptance for tracks"}; + Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum eta acceptance for tracks"}; + Configurable trackPtMin{"trackPtMin", 0.15, "minimum pT acceptance for tracks"}; + Configurable trackPtMax{"trackPtMax", 100.0, "maximum pT acceptance for tracks"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + Configurable pTHatMaxMCD{"pTHatMaxMCD", 999.0, "maximum fraction of hard scattering for jet acceptance in detector MC"}; + Configurable pTHatMaxMCP{"pTHatMaxMCP", 999.0, "maximum fraction of hard scattering for jet acceptance in particle MC"}; + Configurable pTHatExponent{"pTHatExponent", 6.0, "exponent of the event weight for the calculation of pTHat"}; + Configurable pTHatAbsoluteMin{"pTHatAbsoluteMin", -99.0, "minimum value of pTHat"}; + Configurable jetPtMax{"jetPtMax", 200., "set jet pT bin max"}; + Configurable jetEtaMin{"jetEtaMin", -0.7, "minimum jet pseudorapidity"}; + Configurable jetEtaMax{"jetEtaMax", 0.7, "maximum jet pseudorapidity"}; + Configurable nBinsEta{"nBinsEta", 200, "number of bins for eta axes"}; + Configurable jetAreaFractionMin{"jetAreaFractionMin", -99.0, "used to make a cut on the jet areas"}; + Configurable leadingConstituentPtMin{"leadingConstituentPtMin", -99.0, "minimum pT selection on jet constituent"}; + Configurable leadingConstituentPtMax{"leadingConstituentPtMax", 9999.0, "maximum pT selection on jet constituent"}; + Configurable trackOccupancyInTimeRangeMax{"trackOccupancyInTimeRangeMax", 999999, "maximum track occupancy of tracks in neighbouring collisions in a given time range; only applied to reconstructed collisions (data and mcd jets), not mc collisions (mcp jets)"}; + Configurable trackOccupancyInTimeRangeMin{"trackOccupancyInTimeRangeMin", -999999, "minimum track occupancy of tracks in neighbouring collisions in a given time range; only applied to reconstructed collisions (data and mcd jets), not mc collisions (mcp jets)"}; + Configurable checkGeoMatched{"checkGeoMatched", true, "0: turn off geometry matching, 1: do geometry matching "}; + Configurable checkPtMatched{"checkPtMatched", false, "0: turn off pT matching, 1: do pT matching"}; + Configurable checkGeoPtMatched{"checkGeoPtMatched", false, "0: turn off geometry and pT matching, 1: do geometry and pT matching"}; + Configurable acceptSplitCollisions{"acceptSplitCollisions", 0, "0: only look at mcCollisions that are not split; 1: accept split mcCollisions, 2: accept split mcCollisions but only look at the first reco collision associated with it"}; + Configurable skipMBGapEvents{"skipMBGapEvents", false, "flag to choose to reject min. bias gap events; jet-level rejection can also be applied at the jet finder level for jets only, here rejection is applied for collision and track process functions for the first time, and on jets in case it was set to false at the jet finder level"}; + Configurable checkLeadConstituentPtForMcpJets{"checkLeadConstituentPtForMcpJets", false, "flag to choose whether particle level jets should have their lead track pt above leadingConstituentPtMin to be accepted; off by default, as leadingConstituentPtMin cut is only applied on MCD jets for the Pb-Pb analysis using pp MC anchored to Pb-Pb for the response matrix"}; + + std::vector eventSelectionBits; + int trackSelection = -1; + + void init(o2::framework::InitContext&) + { + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + + AxisSpec centralityAxis = {1200, -10., 110., "Centrality"}; + AxisSpec trackPtAxis = {200, -0.5, 199.5, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec trackEtaAxis = {nBinsEta, -1.0, 1.0, "#eta"}; + AxisSpec phiAxis = {160, -1.0, 7.0, "#varphi"}; + AxisSpec jetPtAxis = {200, 0., 200., "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec jetPtAxisRhoAreaSub = {400, -200., 200., "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec jetEtaAxis = {nBinsEta, -1.0, 1.0, "#eta"}; + + if (doprocessQC || doprocessQCWeighted) { + registry.add("h_track_pt", "track #it{p}_{T} ; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH1F, {trackPtAxis}}); + registry.add("h2_track_eta_track_phi", "track eta vs. track phi; #eta; #phi; counts", {HistType::kTH2F, {trackEtaAxis, phiAxis}}); + } + + if (doprocessCollisions || doprocessCollisionsWeighted) { + registry.add("h_collisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + registry.add("h_fakecollisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + registry.add("h2_centrality_occupancy", "centrality vs occupancy; centrality; occupancy", {HistType::kTH2F, {centralityAxis, {60, 0, 30000}}}); + registry.add("h_collisions_Zvertex", "position of collision ;#it{Z} (cm)", {HistType::kTH1F, {{300, -15.0, 15.0}}}); + if (doprocessCollisionsWeighted) { + registry.add("h_collisions_weighted", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + } + } + + if (doprocessSpectraData || doprocessSpectraMCD || doprocessSpectraMCDWeighted) { + registry.add("h_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c}); counts", {HistType::kTH1F, {jetPtAxis}}); + registry.add("h_jet_eta", "jet eta;#eta; counts", {HistType::kTH1F, {jetEtaAxis}}); + registry.add("h_jet_phi", "jet phi;#phi; counts", {HistType::kTH1F, {phiAxis}}); + registry.add("h2_centrality_jet_pt", "centrality vs. jet pT;centrality; #it{p}_{T,jet} (GeV/#it{c}); counts", {HistType::kTH2F, {centralityAxis, jetPtAxis}}); + registry.add("h2_centrality_jet_eta", "centrality vs. jet eta;centrality; #eta; counts", {HistType::kTH2F, {centralityAxis, jetEtaAxis}}); + registry.add("h2_centrality_jet_phi", "centrality vs. jet phi;centrality; #varphi; counts", {HistType::kTH2F, {centralityAxis, phiAxis}}); + registry.add("h2_jet_pt_jet_area", "jet #it{p}_{T,jet} vs. Area_{jet}; #it{p}_{T,jet} (GeV/#it{c}); Area_{jet}", {HistType::kTH2F, {jetPtAxis, {150, 0., 1.5}}}); + registry.add("h2_jet_pt_jet_ntracks", "jet #it{p}_{T,jet} vs. N_{jet tracks}; #it{p}_{T,jet} (GeV/#it{c}); N_{jet, tracks}", {HistType::kTH2F, {jetPtAxis, {200, -0.5, 199.5}}}); + registry.add("h2_jet_pt_track_pt", "jet #it{p}_{T,jet} vs. #it{p}_{T,track}; #it{p}_{T,jet} (GeV/#it{c}); #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, trackPtAxis}}); + registry.add("h3_jet_pt_jet_eta_jet_phi", "jet pt vs. eta vs. phi", {HistType::kTH3F, {jetPtAxis, jetEtaAxis, phiAxis}}); + if (doprocessSpectraMCDWeighted) { + registry.add("h_jet_phat", "jet #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{1000, 0, 1000}}}); + registry.add("h_jet_phat_weighted", "jet #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{1000, 0, 1000}}}); + } + } + + if (doprocessSpectraAreaSubData || doprocessSpectraAreaSubMCD) { + registry.add("h_jet_pt_rhoareasubtracted", "jet pT;#it{p}_{T,jet} (GeV/#it{c}); counts", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + registry.add("h_jet_eta_rhoareasubtracted", "jet eta;#eta; counts", {HistType::kTH1F, {jetEtaAxis}}); + registry.add("h_jet_phi_rhoareasubtracted", "jet phi;#phi; counts", {HistType::kTH1F, {phiAxis}}); + registry.add("h2_centrality_jet_pt_rhoareasubtracted", "centrality vs. jet pT;centrality; #it{p}_{T,jet} (GeV/#it{c}); counts", {HistType::kTH2F, {centralityAxis, jetPtAxisRhoAreaSub}}); + registry.add("h2_centrality_jet_eta_rhoareasubtracted", "centrality vs. jet eta;centrality; #eta; counts", {HistType::kTH2F, {centralityAxis, jetEtaAxis}}); + registry.add("h2_centrality_jet_phi_rhoareasubtracted", "centrality vs. jet phi;centrality; #varphi; counts", {HistType::kTH2F, {centralityAxis, phiAxis}}); + registry.add("h2_jet_pt_jet_area_rhoareasubtracted", "jet #it{p}_{T,jet} vs. Area_{jet}; #it{p}_{T,jet} (GeV/#it{c}); Area_{jet}", {HistType::kTH2F, {jetPtAxis, {150, 0., 1.5}}}); + registry.add("h2_jet_pt_jet_ntracks_rhoareasubtracted", "jet #it{p}_{T,jet} vs. N_{jet tracks}; #it{p}_{T,jet} (GeV/#it{c}); N_{jet, tracks}", {HistType::kTH2F, {jetPtAxis, {200, -0.5, 199.5}}}); + registry.add("h2_jet_pt_jet_corr_pt_rhoareasubtracted", "jet #it{p}_{T,jet} vs. #it{p}_{T,corr}; #it{p}_{T,jet} (GeV/#it{c}); #it{p}_{T,corr} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, jetPtAxisRhoAreaSub}}); + registry.add("h2_jet_pt_track_pt_rhoareasubtracted", "jet #it{p}_{T,jet} vs. #it{p}_{T,track}; #it{p}_{T,jet} (GeV/#it{c}); #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxisRhoAreaSub, trackPtAxis}}); + registry.add("h3_jet_pt_jet_eta_jet_phi_rhoareasubtracted", "jet_pt_eta_phi_rhoareasubtracted", {HistType::kTH3F, {jetPtAxisRhoAreaSub, jetEtaAxis, phiAxis}}); + } + + if (doprocessSpectraMCP || doprocessSpectraMCPWeighted) { + registry.add("h_mcColl_counts", " number of mc events; event status; entries", {HistType::kTH1F, {{10, 0, 10}}}); + registry.get(HIST("h_mcColl_counts"))->GetXaxis()->SetBinLabel(1, "allMcColl"); + registry.get(HIST("h_mcColl_counts"))->GetXaxis()->SetBinLabel(2, "vertexZ"); + registry.get(HIST("h_mcColl_counts"))->GetXaxis()->SetBinLabel(3, "noRecoColl"); + registry.get(HIST("h_mcColl_counts"))->GetXaxis()->SetBinLabel(4, "recoEvtSel"); + registry.get(HIST("h_mcColl_counts"))->GetXaxis()->SetBinLabel(5, "centralitycut"); + registry.get(HIST("h_mcColl_counts"))->GetXaxis()->SetBinLabel(6, "occupancycut"); + + registry.add("h_mc_zvertex", "position of collision ;#it{Z} (cm)", {HistType::kTH1F, {{300, -15.0, 15.0}}}); + registry.add("h_jet_pt_part", "partvjet pT;#it{p}_{T,jet}^{part} (GeV/#it{c}); counts", {HistType::kTH1F, {jetPtAxis}}); + registry.add("h_jet_eta_part", "part jet #eta;#eta^{part}; counts", {HistType::kTH1F, {jetEtaAxis}}); + registry.add("h_jet_phi_part", "part jet #varphi;#phi^{part}; counts", {HistType::kTH1F, {phiAxis}}); + registry.add("h2_jet_pt_part_jet_area_part", "part jet #it{p}_{T,jet} vs. Area_{jet}; #it{p}_{T,jet}^{part} (GeV/#it{c}); Area_{jet}^{part}", {HistType::kTH2F, {jetPtAxis, {150, 0., 1.5}}}); + registry.add("h2_jet_pt_part_jet_ntracks_part", "part jet #it{p}_{T,jet} vs. N_{jet tracks}; #it{p}_{T,jet}^{part} (GeV/#it{c}); N_{jet, tracks}^{part}", {HistType::kTH2F, {jetPtAxis, {200, -0.5, 199.5}}}); + registry.add("h2_jet_pt_part_track_pt_part", "part jet #it{p}_{T,jet} vs. #it{p}_{T,track}; #it{p}_{T,jet}^{part} (GeV/#it{c}); #it{p}_{T,track}^{part} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxisRhoAreaSub, trackPtAxis}}); + registry.add("h3_jet_pt_jet_eta_jet_phi_part", "part jet pt vs. eta vs. phi", {HistType::kTH3F, {jetPtAxis, jetEtaAxis, phiAxis}}); + if (doprocessSpectraMCPWeighted) { + registry.add("h_mcColl_counts_weight", " number of weighted mc events; event status; entries", {HistType::kTH1F, {{10, 0, 10}}}); + registry.get(HIST("h_mcColl_counts_weight"))->GetXaxis()->SetBinLabel(1, "allMcColl"); + registry.get(HIST("h_mcColl_counts_weight"))->GetXaxis()->SetBinLabel(2, "vertexZ"); + registry.get(HIST("h_mcColl_counts_weight"))->GetXaxis()->SetBinLabel(3, "noRecoColl"); + registry.get(HIST("h_mcColl_counts_weight"))->GetXaxis()->SetBinLabel(4, "recoEvtSel"); + registry.get(HIST("h_mcColl_counts_weight"))->GetXaxis()->SetBinLabel(5, "centralitycut"); + registry.get(HIST("h_mcColl_counts_weight"))->GetXaxis()->SetBinLabel(6, "occupancycut"); + registry.add("h2_jet_ptcut_part", "p_{T} cut;p_{T,jet}^{part} (GeV/#it{c});N;entries", {HistType::kTH2F, {{300, 0, 300}, {20, 0, 5}}}); + registry.add("h_jet_phat_part_weighted", "jet #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{1000, 0, 1000}}}); + } + } + + if (doprocessSpectraAreaSubMCP) { + registry.add("h_mcColl_counts_areasub", " number of mc events; event status; entries", {HistType::kTH1F, {{10, 0, 10}}}); + registry.get(HIST("h_mcColl_counts_areasub"))->GetXaxis()->SetBinLabel(1, "allMcColl"); + registry.get(HIST("h_mcColl_counts_areasub"))->GetXaxis()->SetBinLabel(2, "vertexZ"); + registry.get(HIST("h_mcColl_counts_areasub"))->GetXaxis()->SetBinLabel(3, "noRecoColl"); + registry.get(HIST("h_mcColl_counts_areasub"))->GetXaxis()->SetBinLabel(4, "splitColl"); + registry.get(HIST("h_mcColl_counts_areasub"))->GetXaxis()->SetBinLabel(5, "recoEvtSel"); + registry.get(HIST("h_mcColl_counts_areasub"))->GetXaxis()->SetBinLabel(6, "centralitycut"); + registry.get(HIST("h_mcColl_counts_areasub"))->GetXaxis()->SetBinLabel(7, "occupancycut"); + + registry.add("h_mcColl_rho", "mc collision rho;#rho (GeV/#it{c}); counts", {HistType::kTH1F, {{500, 0.0, 500.0}}}); + registry.add("h_jet_pt_part_rhoareasubtracted", "part jet corr pT;#it{p}_{T,jet}^{part} (GeV/#it{c}); counts", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + registry.add("h_jet_eta_part_rhoareasubtracted", "part jet #eta;#eta^{part}; counts", {HistType::kTH1F, {jetEtaAxis}}); + registry.add("h_jet_phi_part_rhoareasubtracted", "part jet #varphi;#varphi^{part}; counts", {HistType::kTH1F, {phiAxis}}); + registry.add("h2_jet_pt_part_jet_area_part_rhoareasubtracted", "part jet #it{p}_{T,jet} vs. Area_{jet}; #it{p}_{T,jet}^{part} (GeV/#it{c}); Area_{jet}^{part}", {HistType::kTH2F, {jetPtAxisRhoAreaSub, {150, 0., 1.5}}}); + registry.add("h2_jet_pt_part_jet_ntracks_part_rhoareasubtracted", "part jet #it{p}_{T,jet} vs. N_{jet tracks}; #it{p}_{T,jet}^{part} (GeV/#it{c}); N_{jet, tracks}{part}", {HistType::kTH2F, {jetPtAxisRhoAreaSub, {200, -0.5, 199.5}}}); + registry.add("h3_jet_pt_jet_eta_jet_phi_part_rhoareasubtracted", "part jet pt vs. eta vs.phi", {HistType::kTH3F, {jetPtAxisRhoAreaSub, jetEtaAxis, phiAxis}}); + } + + if (doprocessEvtWiseConstSubJetsData || doprocessEvtWiseConstSubJetsMCD) { + registry.add("h2_centrality_jet_pt_eventwiseconstituentsubtracted", "centrality vs. jet pT;centrality;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH2F, {centralityAxis, jetPtAxis}}); + registry.add("jet_observables_eventwiseconstituentsubtracted", "jet_observables_eventwiseconstituentsubtracted", HistType::kTHnSparseF, {jetPtAxis, jetEtaAxis, phiAxis}); + } + + if (doprocessJetsMatched || doprocessJetsMatchedWeighted) { + if (checkGeoMatched) { + registry.add("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_mcdetaconstraint", "pT mcd vs. pT mcp;#it{p}_{T,jet}^{mcd} (GeV/#it{c});#it{p}_{T,jet}^{mcp} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, jetPtAxis}}); + registry.add("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_mcpetaconstraint", "pT mcd vs. pT mcp;#it{p}_{T,jet}^{mcd} (GeV/#it{c});#it{p}_{T,jet}^{mcp} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, jetPtAxis}}); + registry.add("h2_jet_eta_mcd_jet_eta_mcp_matchedgeo", "Eta mcd vs. Eta mcp;#eta_{jet}^{mcd};#eta_{jet}^{mcp}", {HistType::kTH2F, {jetEtaAxis, jetEtaAxis}}); + registry.add("h2_jet_phi_mcd_jet_phi_mcp_matchedgeo_mcdetaconstraint", "Phi mcd vs. Phi mcp;#varphi_{jet}^{mcd};#varphi_{jet}^{mcp}", {HistType::kTH2F, {phiAxis, phiAxis}}); + registry.add("h2_jet_phi_mcd_jet_phi_mcp_matchedgeo_mcpetaconstraint", "Phi mcd vs. Phi mcp;#varphi_{jet}^{mcd};#varphi_{jet}^{mcp}", {HistType::kTH2F, {phiAxis, phiAxis}}); + registry.add("h2_jet_ntracks_mcd_jet_ntracks_mcp_matchedgeo", "Ntracks mcd vs. Ntracks mcp;N_{jet tracks}^{mcd};N_{jet tracks}^{mcp}", {HistType::kTH2F, {{200, -0.5, 199.5}, {200, -0.5, 199.5}}}); + registry.add("h2_jet_pt_mcp_jet_pt_diff_matchedgeo", "jet mcp pT vs. delta pT / jet mcp pt;#it{p}_{T,jet}^{mcp} (GeV/#it{c}); (#it{p}_{T,jet}^{mcp} (GeV/#it{c}) - #it{p}_{T,jet}^{mcd} (GeV/#it{c})) / #it{p}_{T,jet}^{mcp} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, {1000, -5.0, 2.0}}}); + registry.add("h2_jet_pt_mcd_jet_pt_diff_matchedgeo", "jet mcd pT vs. delta pT / jet mcd pt;#it{p}_{T,jet}^{mcd} (GeV/#it{c}); (#it{p}_{T,jet}^{mcd} (GeV/#it{c}) - #it{p}_{T,jet}^{mcp} (GeV/#it{c})) / #it{p}_{T,jet}^{mcd} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, {1000, -5.0, 2.0}}}); + registry.add("h2_jet_pt_mcp_jet_pt_ratio_matchedgeo", "jet mcp pT vs. jet mcd pT / jet mcp pt;#it{p}_{T,jet}^{mcp} (GeV/#it{c}); #it{p}_{T,jet}^{mcd} (GeV/#it{c}) / #it{p}_{T,jet}^{mcp} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, {1000, -5.0, 5.0}}}); + } + if (checkPtMatched) { + registry.add("h2_jet_pt_mcd_jet_pt_mcp_matchedpt_mcdetaconstraint", "pT mcd vs. pT mcp;#it{p}_{T,jet}^{mcd} (GeV/#it{c});#it{p}_{T,jet}^{mcp} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, jetPtAxis}}); + registry.add("h2_jet_pt_mcd_jet_pt_mcp_matchedpt_mcpetaconstraint", "pT mcd vs. pT mcp;#it{p}_{T,jet}^{mcd} (GeV/#it{c});#it{p}_{T,jet}^{mcp} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, jetPtAxis}}); + registry.add("h2_jet_eta_mcd_jet_eta_mcp_matchedpt", "Eta mcd vs. Eta mcp;#eta_{jet}^{mcd};#eta_{jet}^{mcp}", {HistType::kTH2F, {jetEtaAxis, jetEtaAxis}}); + registry.add("h2_jet_phi_mcd_jet_phi_mcp_matchedgpt_mcdetaconstraint", "Phi mcd vs. Phi mcp;#varphi_{jet}^{mcd};#varphi_{jet}^{mcp}", {HistType::kTH2F, {phiAxis, phiAxis}}); + registry.add("h2_jet_phi_mcd_jet_phi_mcp_matchedgpt_mcpetaconstraint", "Phi mcd vs. Phi mcp;#varphi_{jet}^{mcd};#varphi_{jet}^{mcp}", {HistType::kTH2F, {phiAxis, phiAxis}}); + registry.add("h2_jet_ntracks_mcd_jet_ntracks_mcp_matchedpt", "Ntracks mcd vs. Ntracks mcp;N_{jet tracks}^{mcd};N_{jet tracks}^{mcp}", {HistType::kTH2F, {{200, -0.5, 199.5}, {200, -0.5, 199.5}}}); + registry.add("h2_jet_pt_mcp_jet_pt_diff_matchedpt", "jet mcp pT vs. delta pT / jet mcp pt;#it{p}_{T,jet}^{mcp} (GeV/#it{c}); (#it{p}_{T,jet}^{mcp} (GeV/#it{c}) - #it{p}_{T,jet}^{mcd} (GeV/#it{c})) / #it{p}_{T,jet}^{mcp} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, {1000, -5.0, 2.0}}}); + registry.add("h2_jet_pt_mcd_jet_pt_diff_matchedpt", "jet mcd pT vs. delta pT / jet mcd pt;#it{p}_{T,jet}^{mcd} (GeV/#it{c}); (#it{p}_{T,jet}^{mcd} (GeV/#it{c}) - #it{p}_{T,jet}^{mcp} (GeV/#it{c})) / #it{p}_{T,jet}^{mcd} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, {1000, -5.0, 2.0}}}); + registry.add("h2_jet_pt_mcp_jet_pt_ratio_matchedpt", "jet mcp pT vs. jet mcd pT / jet mcp pt;#it{p}_{T,jet}^{mcp} (GeV/#it{c}); #it{p}_{T,jet}^{mcd} (GeV/#it{c}) / #it{p}_{T,jet}^{mcp} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, {1000, -5.0, 5.0}}}); + } + if (checkGeoPtMatched) { + registry.add("h2_jet_pt_mcd_jet_pt_mcp_matchedgeopt_mcdetaconstraint", "pT mcd vs. pT mcp;#it{p}_{T,jet}^{mcd} (GeV/#it{c});#it{p}_{T,jet}^{mcp} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, jetPtAxis}}); + registry.add("h2_jet_pt_mcd_jet_pt_mcp_matchedgeopt_mcpetaconstraint", "pT mcd vs. pT mcp;#it{p}_{T,jet}^{mcd} (GeV/#it{c});#it{p}_{T,jet}^{mcp} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, jetPtAxis}}); + registry.add("h2_jet_eta_mcd_jet_eta_mcp_matchedgeopt", "Eta mcd vs. Eta mcp;#eta_{jet}^{mcd};#eta_{jet}^{mcp}", {HistType::kTH2F, {jetEtaAxis, jetEtaAxis}}); + registry.add("h2_jet_phi_mcd_jet_phi_mcp_matchedgeopt_mcdetaconstraint", "Phi mcd vs. Phi mcp;#varphi_{jet}^{mcd};#varphi_{jet}^{mcp}", {HistType::kTH2F, {phiAxis, phiAxis}}); + registry.add("h2_jet_phi_mcd_jet_phi_mcp_matchedgeopt_mcpetaconstraint", "Phi mcd vs. Phi mcp;#varphi_{jet}^{mcd};#varphi_{jet}^{mcp}", {HistType::kTH2F, {phiAxis, phiAxis}}); + registry.add("h2_jet_ntracks_mcd_jet_ntracks_mcp_matchedgeopt", "Ntracks mcd vs. Ntracks mcp;N_{jet tracks}^{mcd};N_{jet tracks}^{mcp}", {HistType::kTH2F, {{200, -0.5, 199.5}, {200, -0.5, 199.5}}}); + registry.add("h2_jet_pt_mcp_jet_pt_diff_matchedgeopt", "jet mcp pT vs. delta pT / jet mcp pt;#it{p}_{T,jet}^{mcp} (GeV/#it{c}); (#it{p}_{T,jet}^{mcp} (GeV/#it{c}) - #it{p}_{T,jet}^{mcd} (GeV/#it{c})) / #it{p}_{T,jet}^{mcp} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, {1000, -5.0, 2.0}}}); + registry.add("h2_jet_pt_mcd_jet_pt_diff_matchedgeopt", "jet mcd pT vs. delta pT / jet mcd pt;#it{p}_{T,jet}^{mcd} (GeV/#it{c}); (#it{p}_{T,jet}^{mcd} (GeV/#it{c}) - #it{p}_{T,jet}^{mcp} (GeV/#it{c})) / #it{p}_{T,jet}^{mcd} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, {1000, -5.0, 2.0}}}); + registry.add("h2_jet_pt_mcp_jet_pt_ratio_matchedgeopt", "jet mcp pT vs. jet mcd pT / jet mcp pt;#it{p}_{T,jet}^{mcp} (GeV/#it{c}); #it{p}_{T,jet}^{mcd} (GeV/#it{c}) / #it{p}_{T,jet}^{mcp} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxis, {1000, -5.0, 5.0}}}); + } + } + + if (doprocessJetsMatchedSubtracted) { + registry.add("h_mc_collisions_matched", "mc collisions status;event status;entries", {HistType::kTH1F, {{5, 0.0, 5.0}}}); + registry.add("h_mcd_events_matched", "mcd event status;event status;entries", {HistType::kTH1F, {{5, 0.0, 5.0}}}); + registry.add("h_mc_rho_matched", "mc collision rho;#rho (GeV/#it{c}); counts", {HistType::kTH1F, {{500, -100.0, 500.0}}}); + registry.add("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_rhoareasubtracted_mcdetaconstraint", "corr pT mcd vs. corr cpT mcp;#it{p}_{T,jet}^{mcd} (GeV/#it{c});#it{p}_{T,jet}^{mcp} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxisRhoAreaSub, jetPtAxisRhoAreaSub}}); + registry.add("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_rhoareasubtracted_mcpetaconstraint", "corr pT mcd vs. corr cpT mcp;#it{p}_{T,jet}^{mcd} (GeV/#it{c});#it{p}_{T,jet}^{mcp} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxisRhoAreaSub, jetPtAxisRhoAreaSub}}); + registry.add("h2_jet_pt_mcp_jet_pt_diff_matchedgeo_rhoareasubtracted", "jet mcp corr pT vs. corr delta pT / jet mcp corr pt;#it{p}_{T,jet}^{mcp} (GeV/#it{c}); (#it{p}_{T,jet}^{mcp} (GeV/#it{c}) - #it{p}_{T,jet}^{mcd} (GeV/#it{c})) / #it{p}_{T,jet}^{mcp} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxisRhoAreaSub, {1000, -5.0, 5.0}}}); + registry.add("h2_jet_pt_mcd_jet_pt_diff_matchedgeo_rhoareasubtracted", "jet mcd corr pT vs. corr delta pT / jet mcd corr pt;#it{p}_{T,jet}^{mcd} (GeV/#it{c}); (#it{p}_{T,jet}^{mcd} (GeV/#it{c}) - #it{p}_{T,jet}^{mcp} (GeV/#it{c})) / #it{p}_{T,jet}^{mcd} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxisRhoAreaSub, {1000, -5.0, 5.0}}}); + registry.add("h2_jet_pt_mcp_jet_pt_ratio_matchedgeo_rhoareasubtracted", "jet mcp corr pT vs. jet mcd corr pT / jet mcp corr pt;#it{p}_{T,jet}^{mcp} (GeV/#it{c}); #it{p}_{T,jet}^{mcd} (GeV/#it{c}) / #it{p}_{T,jet}^{mcp} (GeV/#it{c})", {HistType::kTH2F, {jetPtAxisRhoAreaSub, {1000, -5.0, 5.0}}}); + } + } + + Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); + Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax); + Preslice mcdjetsPerJCollision = o2::aod::jet::collisionId; + + template + bool isAcceptedJet(TJets const& jet, bool mcLevelIsParticleLevel = false) + { + if (jetAreaFractionMin > -98.0) { + if (jet.area() < jetAreaFractionMin * o2::constants::math::PI * (jet.r() / 100.0) * (jet.r() / 100.0)) { + return false; + } + } + bool checkConstituentPt = true; + bool checkConstituentMinPt = (leadingConstituentPtMin > -98.0); + bool checkConstituentMaxPt = (leadingConstituentPtMax < 9998.0); + if (!checkConstituentMinPt && !checkConstituentMaxPt) { + checkConstituentPt = false; + } + if (mcLevelIsParticleLevel && !checkLeadConstituentPtForMcpJets) { + checkConstituentPt = false; + } + + if (checkConstituentPt) { + bool isMinLeadingConstituent = !checkConstituentMinPt; + bool isMaxLeadingConstituent = true; + + for (const auto& constituent : jet.template tracks_as()) { + double pt = constituent.pt(); + + if (checkConstituentMinPt && pt >= leadingConstituentPtMin) { + isMinLeadingConstituent = true; + } + if (checkConstituentMaxPt && pt > leadingConstituentPtMax) { + isMaxLeadingConstituent = false; + } + } + return isMinLeadingConstituent && isMaxLeadingConstituent; + } + return true; + } + + template + void fillJetHistograms(TJets const& jet, float centrality, float weight = 1.0) + { + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (jet.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { + return; + } + if (jet.r() == round(selectedJetsRadius * 100.0f)) { + registry.fill(HIST("h_jet_pt"), jet.pt(), weight); + registry.fill(HIST("h_jet_eta"), jet.eta(), weight); + registry.fill(HIST("h_jet_phi"), jet.phi(), weight); + registry.fill(HIST("h2_centrality_jet_pt"), centrality, jet.pt(), weight); + registry.fill(HIST("h2_centrality_jet_eta"), centrality, jet.eta(), weight); + registry.fill(HIST("h2_centrality_jet_phi"), centrality, jet.phi(), weight); + registry.fill(HIST("h2_jet_pt_jet_area"), jet.pt(), jet.area(), weight); + registry.fill(HIST("h2_jet_pt_jet_ntracks"), jet.pt(), jet.tracksIds().size(), weight); + registry.fill(HIST("h3_jet_pt_jet_eta_jet_phi"), jet.pt(), jet.eta(), jet.phi(), weight); + } + + for (const auto& constituent : jet.template tracks_as()) { + registry.fill(HIST("h2_jet_pt_track_pt"), jet.pt(), constituent.pt(), weight); + } + } + + template + void fillJetAreaSubHistograms(TJets const& jet, float centrality, float rho, float weight = 1.0) + { + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (jet.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { + return; + } + double jetcorrpt = jet.pt() - (rho * jet.area()); + if (jet.r() == round(selectedJetsRadius * 100.0f)) { + // fill jet histograms after area-based subtraction + registry.fill(HIST("h_jet_pt_rhoareasubtracted"), jetcorrpt, weight); + registry.fill(HIST("h2_centrality_jet_pt_rhoareasubtracted"), centrality, jetcorrpt, weight); + registry.fill(HIST("h2_jet_pt_jet_corr_pt_rhoareasubtracted"), jet.pt(), jetcorrpt, weight); + registry.fill(HIST("h3_jet_pt_jet_eta_jet_phi_rhoareasubtracted"), jetcorrpt, jet.eta(), jet.phi(), weight); + if (jetcorrpt > 0) { + registry.fill(HIST("h_jet_eta_rhoareasubtracted"), jet.eta(), weight); + registry.fill(HIST("h_jet_phi_rhoareasubtracted"), jet.phi(), weight); + registry.fill(HIST("h2_centrality_jet_eta_rhoareasubtracted"), centrality, jet.eta(), weight); + registry.fill(HIST("h2_centrality_jet_phi_rhoareasubtracted"), centrality, jet.phi(), weight); + registry.fill(HIST("h2_jet_pt_jet_area_rhoareasubtracted"), jetcorrpt, jet.area(), weight); + registry.fill(HIST("h2_jet_pt_jet_ntracks_rhoareasubtracted"), jetcorrpt, jet.tracksIds().size(), weight); + } + } + + for (const auto& constituent : jet.template tracks_as()) { + registry.fill(HIST("h2_jet_pt_track_pt_rhoareasubtracted"), jetcorrpt, constituent.pt(), weight); + } + } + + template + void fillMCPHistograms(TJets const& jet, float weight = 1.0) + { + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (jet.pt() > pTHatMaxMCP * pTHat || pTHat < pTHatAbsoluteMin) { + return; + } + if (jet.r() == round(selectedJetsRadius * 100.0f)) { + // fill mcp jet histograms + registry.fill(HIST("h_jet_pt_part"), jet.pt(), weight); + registry.fill(HIST("h_jet_eta_part"), jet.eta(), weight); + registry.fill(HIST("h_jet_phi_part"), jet.phi(), weight); + registry.fill(HIST("h3_jet_pt_jet_eta_jet_phi_part"), jet.pt(), jet.eta(), jet.phi(), weight); + registry.fill(HIST("h2_jet_pt_part_jet_area_part"), jet.pt(), jet.area(), weight); + registry.fill(HIST("h2_jet_pt_part_jet_ntracks_part"), jet.pt(), jet.tracksIds().size(), weight); + } + + for (const auto& constituent : jet.template tracks_as()) { + registry.fill(HIST("h2_jet_pt_part_track_pt_part"), jet.pt(), constituent.pt(), weight); + } + } + + template + void fillMCPAreaSubHistograms(TJets const& jet, float rho = 0.0, float weight = 1.0) + { + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (jet.pt() > pTHatMaxMCP * pTHat || pTHat < pTHatAbsoluteMin) { + return; + } + if (jet.r() == round(selectedJetsRadius * 100.0f)) { + // fill mcp jet histograms + double jetcorrpt = jet.pt() - (rho * jet.area()); + registry.fill(HIST("h_jet_pt_part_rhoareasubtracted"), jetcorrpt, weight); + registry.fill(HIST("h3_jet_pt_jet_eta_jet_phi_part_rhoareasubtracted"), jetcorrpt, jet.eta(), jet.phi(), weight); + if (jetcorrpt > 0) { + registry.fill(HIST("h_jet_eta_part_rhoareasubtracted"), jet.eta(), weight); + registry.fill(HIST("h_jet_phi_part_rhoareasubtracted"), jet.phi(), weight); + registry.fill(HIST("h2_jet_pt_part_jet_area_part_rhoareasubtracted"), jetcorrpt, jet.area(), weight); + registry.fill(HIST("h2_jet_pt_part_jet_ntracks_part_rhoareasubtracted"), jetcorrpt, jet.tracksIds().size(), weight); + } + } + } + + template + void fillEventWiseConstituentSubtractedHistograms(TJets const& jet, float centrality, float weight = 1.0) + { + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (jet.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { + return; + } + if (jet.r() == round(selectedJetsRadius * 100.0f)) { + registry.fill(HIST("h2_centrality_jet_pt_eventwiseconstituentsubtracted"), centrality, jet.pt(), weight); + registry.fill(HIST("jet_observables_eventwiseconstituentsubtracted"), jet.pt(), jet.eta(), jet.phi(), weight); + } + } + + template + void fillTrackHistograms(TTracks const& track, float weight = 1.0) + { + registry.fill(HIST("h_track_pt"), track.pt(), weight); + registry.fill(HIST("h2_track_eta_track_phi"), track.eta(), track.phi(), weight); + } + + template + void fillMatchedHistograms(TBase const& jetMCD, float weight = 1.0) + { + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (jetMCD.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { + return; + } + // fill geometry matched histograms + if (checkGeoMatched) { + if (jetMCD.has_matchedJetGeo()) { + for (const auto& jetMCP : jetMCD.template matchedJetGeo_as>()) { + if (jetMCP.pt() > pTHatMaxMCP * pTHat || pTHat < pTHatAbsoluteMin) { + continue; + } + if (jetMCD.r() == round(selectedJetsRadius * 100.0f)) { + double dpt = jetMCP.pt() - jetMCD.pt(); + if (jetfindingutilities::isInEtaAcceptance(jetMCD, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_mcdetaconstraint"), jetMCD.pt(), jetMCP.pt(), weight); + registry.fill(HIST("h2_jet_phi_mcd_jet_phi_mcp_matchedgeo_mcdetaconstraint"), jetMCD.phi(), jetMCP.phi(), weight); + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_diff_matchedgeo"), jetMCD.pt(), dpt / jetMCD.pt(), weight); + registry.fill(HIST("h2_jet_ntracks_mcd_jet_ntracks_mcp_matchedgeo"), jetMCD.tracksIds().size(), jetMCP.tracksIds().size(), weight); + } + if (jetfindingutilities::isInEtaAcceptance(jetMCP, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_mcpetaconstraint"), jetMCD.pt(), jetMCP.pt(), weight); + registry.fill(HIST("h2_jet_phi_mcd_jet_phi_mcp_matchedgeo_mcpetaconstraint"), jetMCD.phi(), jetMCP.phi(), weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_diff_matchedgeo"), jetMCP.pt(), dpt / jetMCP.pt(), weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_ratio_matchedgeo"), jetMCP.pt(), jetMCD.pt() / jetMCP.pt(), weight); + } + registry.fill(HIST("h2_jet_eta_mcd_jet_eta_mcp_matchedgeo"), jetMCD.eta(), jetMCP.eta(), weight); + } + } + } + } + // fill pt matched histograms + if (checkPtMatched) { + if (jetMCD.has_matchedJetPt()) { + for (const auto& jetMCP : jetMCD.template matchedJetPt_as>()) { + if (jetMCP.pt() > pTHatMaxMCP * pTHat) { + continue; + } + if (!jetfindingutilities::isInEtaAcceptance(jetMCP, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (jetMCD.r() == round(selectedJetsRadius * 100.0f)) { + double dpt = jetMCP.pt() - jetMCD.pt(); + if (jetfindingutilities::isInEtaAcceptance(jetMCD, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_mcp_matchedpt_mcdetaconstraint"), jetMCD.pt(), jetMCP.pt(), weight); + registry.fill(HIST("h2_jet_phi_mcd_jet_phi_mcp_matchedpt_mcdetaconstraint"), jetMCD.phi(), jetMCP.phi(), weight); + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_diff_matchedpt"), jetMCD.pt(), dpt / jetMCD.pt(), weight); + registry.fill(HIST("h2_jet_ntracks_mcd_jet_ntracks_mcp_matchedpt"), jetMCD.tracksIds().size(), jetMCP.tracksIds().size(), weight); + } + if (jetfindingutilities::isInEtaAcceptance(jetMCP, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_mcp_matchedpt_mcpetaconstraint"), jetMCD.pt(), jetMCP.pt(), weight); + registry.fill(HIST("h2_jet_phi_mcd_jet_phi_mcp_matchedpt_mcpetaconstraint"), jetMCD.phi(), jetMCP.phi(), weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_diff_matchedpt"), jetMCP.pt(), dpt / jetMCP.pt(), weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_ratio_matchedpt"), jetMCP.pt(), jetMCD.pt() / jetMCP.pt(), weight); + } + registry.fill(HIST("h2_jet_eta_mcd_jet_eta_mcp_matchedpt"), jetMCD.eta(), jetMCP.eta(), weight); + } + } + } + } + // fill geometry and pt histograms + if (checkGeoPtMatched) { + if (jetMCD.has_matchedJetGeo() && jetMCD.has_matchedJetPt()) { + for (const auto& jetMCP : jetMCD.template matchedJetGeo_as>()) { + if (jetMCP.pt() > pTHatMaxMCP * pTHat) { + continue; + } + if (!jetfindingutilities::isInEtaAcceptance(jetMCP, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (jetMCD.template matchedJetGeo_first_as>().globalIndex() == jetMCD.template matchedJetPt_first_as>().globalIndex()) { // not a good way to do this + double dpt = jetMCP.pt() - jetMCD.pt(); + if (jetfindingutilities::isInEtaAcceptance(jetMCD, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_mcp_matchedgeopt_mcdetaconstraint"), jetMCD.pt(), jetMCP.pt(), weight); + registry.fill(HIST("h2_jet_phi_mcd_jet_phi_mcp_matchedgeopt_mcdetaconstraint"), jetMCD.phi(), jetMCP.phi(), weight); + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_diff_matchedgeopt"), jetMCD.pt(), dpt / jetMCD.pt(), weight); + registry.fill(HIST("h2_jet_ntracks_mcd_jet_ntracks_mcp_matchedgeopt"), jetMCD.tracksIds().size(), jetMCP.tracksIds().size(), weight); + } + if (jetfindingutilities::isInEtaAcceptance(jetMCP, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_mcp_matchedgeopt_mcpetaconstraint"), jetMCD.pt(), jetMCP.pt(), weight); + registry.fill(HIST("h2_jet_phi_mcd_jet_phi_mcp_matchedgeopt_mcpetaconstraint"), jetMCD.phi(), jetMCP.phi(), weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_diff_matchedgeopt"), jetMCP.pt(), dpt / jetMCP.pt(), weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_ratio_matchedgeopt"), jetMCP.pt(), jetMCD.pt() / jetMCP.pt(), weight); + } + registry.fill(HIST("h2_jet_eta_mcd_jet_eta_mcp_matchedpt"), jetMCD.eta(), jetMCP.eta(), weight); + } + } + } + } + } + + template + void fillGeoMatchedCorrHistograms(TBase const& jetMCD, float rho, float mcrho = 0.0, float weight = 1.0) + { + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (jetMCD.pt() > pTHatMaxMCD * pTHat) { + return; + } + if (jetMCD.has_matchedJetGeo()) { + for (const auto& jetMCP : jetMCD.template matchedJetGeo_as>()) { + if (jetMCP.pt() > pTHatMaxMCD * pTHat) { + continue; + } + if (jetMCD.r() == round(selectedJetsRadius * 100.0f)) { + double corrTagjetpt = jetMCP.pt() - (mcrho * jetMCP.area()); + double corrBasejetpt = jetMCD.pt() - (rho * jetMCD.area()); + double dcorrpt = corrTagjetpt - corrBasejetpt; + if (jetfindingutilities::isInEtaAcceptance(jetMCD, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_rhoareasubtracted_mcdetaconstraint"), corrBasejetpt, corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_diff_matchedgeo_rhoareasubtracted"), corrBasejetpt, dcorrpt / corrBasejetpt, weight); + } + if (jetfindingutilities::isInEtaAcceptance(jetMCP, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_rhoareasubtracted_mcpetaconstraint"), corrBasejetpt, corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_diff_matchedgeo_rhoareasubtracted"), corrTagjetpt, dcorrpt / corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_ratio_matchedgeo_rhoareasubtracted"), corrTagjetpt, corrBasejetpt / corrTagjetpt, weight); + } + } + } + } + } + + void processQC(soa::Filtered::iterator const& collision, + soa::Filtered> const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + fillTrackHistograms(track); + } + } + PROCESS_SWITCH(JetSpectraCharged, processQC, "collisions and track QC for Data and MCD", false); + + void processQCWeighted(soa::Join::iterator const& collision, + aod::JetMcCollisions const&, + soa::Filtered> const& tracks) + { + if (!collision.has_mcCollision()) { // the collision is fake and has no associated mc coll; skip as .mccollision() cannot be called + return; + } + float eventWeight = collision.mcCollision().weight(); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + fillTrackHistograms(track, eventWeight); + } + } + PROCESS_SWITCH(JetSpectraCharged, processQCWeighted, "weighted collsions and tracks QC for MC", false); + + void processCollisions(soa::Filtered::iterator const& collision) + { + registry.fill(HIST("h_collisions"), 0.5); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + registry.fill(HIST("h_collisions"), 1.5); + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + registry.fill(HIST("h_collisions"), 2.5); + registry.fill(HIST("h2_centrality_occupancy"), collision.centrality(), collision.trackOccupancyInTimeRange()); + registry.fill(HIST("h_collisions_Zvertex"), collision.posZ()); + } + PROCESS_SWITCH(JetSpectraCharged, processCollisions, "collisions Data and MCD", true); + + void processCollisionsWeighted(soa::Join::iterator const& collision, + aod::JetMcCollisions const&) + { + if (!collision.has_mcCollision()) { // the collision is fake and has no associated mc coll; skip as .mccollision() cannot be called + registry.fill(HIST("h_fakecollisions"), 0.5); + return; + } + float eventWeight = collision.mcCollision().weight(); + registry.fill(HIST("h_collisions"), 0.5); + registry.fill(HIST("h_collisions_weighted"), 0.5, eventWeight); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + registry.fill(HIST("h_collisions"), 1.5); + registry.fill(HIST("h_collisions_weighted"), 1.5, eventWeight); + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + registry.fill(HIST("h_collisions"), 2.5); + registry.fill(HIST("h_collisions_weighted"), 2.5, eventWeight); + registry.fill(HIST("h2_centrality_occupancy"), collision.centrality(), collision.trackOccupancyInTimeRange()); + registry.fill(HIST("h_collisions_Zvertex"), collision.posZ(), eventWeight); + } + PROCESS_SWITCH(JetSpectraCharged, processCollisionsWeighted, "weighted collsions for MCD", false); + + void processSpectraData(soa::Filtered::iterator const& collision, + soa::Join const& jets, + aod::JetTracks const&) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillJetHistograms(jet, collision.centrality()); + } + } + PROCESS_SWITCH(JetSpectraCharged, processSpectraData, "jet spectra for Data", false); + + void processSpectraMCD(soa::Filtered::iterator const& collision, + soa::Join const& jets, + aod::JetTracks const&) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillJetHistograms(jet, collision.centrality()); + } + } + PROCESS_SWITCH(JetSpectraCharged, processSpectraMCD, "jet spectra for MCD", false); + + void processSpectraAreaSubData(soa::Filtered>::iterator const& collision, + soa::Join const& jets, + aod::JetTracks const&) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillJetAreaSubHistograms(jet, collision.centrality(), collision.rho()); + } + } + PROCESS_SWITCH(JetSpectraCharged, processSpectraAreaSubData, "jet spectra with rho-area subtraction for Data", false); + + void processSpectraAreaSubMCD(soa::Filtered>::iterator const& collision, + soa::Join const& jets, + aod::JetTracks const&) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillJetAreaSubHistograms(jet, collision.centrality(), collision.rho()); + } + } + PROCESS_SWITCH(JetSpectraCharged, processSpectraAreaSubMCD, "jet spectra with rho-area subtraction for MCD", false); + + void processSpectraMCDWeighted(soa::Filtered::iterator const& collision, + soa::Join const& jets, + aod::JetTracks const&) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + float jetweight = jet.eventWeight(); + float pTHat = 10. / (std::pow(jetweight, 1.0 / pTHatExponent)); + if (jet.pt() > pTHatMaxMCD * pTHat) { + return; + } + registry.fill(HIST("h_jet_phat"), pTHat); + registry.fill(HIST("h_jet_phat_weighted"), pTHat, jetweight); + fillJetHistograms(jet, collision.centrality(), jetweight); + } + } + PROCESS_SWITCH(JetSpectraCharged, processSpectraMCDWeighted, "jet finder QA mcd with weighted events", false); + + void processSpectraAreaSubMCP(McParticleCollision::iterator const& mccollision, + soa::SmallGroups const& collisions, + soa::Join const& jets, + aod::JetParticles const&) + { + bool mcLevelIsParticleLevel = true; + + registry.fill(HIST("h_mcColl_counts_areasub"), 0.5); + if (std::abs(mccollision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("h_mcColl_counts_areasub"), 1.5); + if (collisions.size() < 1) { + return; + } + registry.fill(HIST("h_mcColl_counts_areasub"), 2.5); + if (acceptSplitCollisions == 0 && collisions.size() > 1) { + return; + } + registry.fill(HIST("h_mcColl_counts_areasub"), 3.5); + + bool hasSel8Coll = false; + bool centralityIsGood = false; + bool occupancyIsGood = false; + if (acceptSplitCollisions == 2) { + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { + hasSel8Coll = true; + } + if ((centralityMin < collisions.begin().centrality()) && (collisions.begin().centrality() < centralityMax)) { + centralityIsGood = true; + } + if ((trackOccupancyInTimeRangeMin < collisions.begin().trackOccupancyInTimeRange()) && (collisions.begin().trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax)) { + occupancyIsGood = true; + } + } else { + for (auto const& collision : collisions) { + if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + hasSel8Coll = true; + } + if ((centralityMin < collision.centrality()) && (collision.centrality() < centralityMax)) { + centralityIsGood = true; + } + if ((trackOccupancyInTimeRangeMin < collision.trackOccupancyInTimeRange()) && (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax)) { + occupancyIsGood = true; + } + } + } + if (!hasSel8Coll) { + return; + } + registry.fill(HIST("h_mcColl_counts_areasub"), 4.5); + + if (!centralityIsGood) { + return; + } + registry.fill(HIST("h_mcColl_counts_areasub"), 5.5); + + if (!occupancyIsGood) { + return; + } + registry.fill(HIST("h_mcColl_counts_areasub"), 6.5); + registry.fill(HIST("h_mcColl_rho"), mccollision.rho()); + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet, mcLevelIsParticleLevel)) { + continue; + } + fillMCPAreaSubHistograms(jet, mccollision.rho()); + } + } + PROCESS_SWITCH(JetSpectraCharged, processSpectraAreaSubMCP, "jet spectra with area-based subtraction for MC particle level", false); + + void processSpectraMCP(aod::JetMcCollision const& mccollision, + soa::SmallGroups const& collisions, + soa::Join const& jets, + aod::JetParticles const&) + { + bool mcLevelIsParticleLevel = true; + + registry.fill(HIST("h_mcColl_counts"), 0.5); + if (std::abs(mccollision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("h_mcColl_counts"), 1.5); + if (collisions.size() < 1) { + return; + } + registry.fill(HIST("h_mcColl_counts"), 2.5); + + bool hasSel8Coll = false; + bool centralityIsGood = false; + bool occupancyIsGood = false; + for (auto const& collision : collisions) { + if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + hasSel8Coll = true; + } + if ((centralityMin < collision.centrality()) && (collision.centrality() < centralityMax)) { + centralityIsGood = true; + } + if ((trackOccupancyInTimeRangeMin < collision.trackOccupancyInTimeRange()) && (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax)) { + occupancyIsGood = true; + } + } + if (!hasSel8Coll) { + return; + } + registry.fill(HIST("h_mcColl_counts"), 3.5); + if (!centralityIsGood) { + return; + } + registry.fill(HIST("h_mcColl_counts"), 4.5); + if (!occupancyIsGood) { + return; + } + registry.fill(HIST("h_mcColl_counts"), 5.5); + registry.fill(HIST("h_mc_zvertex"), mccollision.posZ()); + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet, mcLevelIsParticleLevel)) { + continue; + } + fillMCPHistograms(jet); + } + } + PROCESS_SWITCH(JetSpectraCharged, processSpectraMCP, "jet spectra for MC particle level", false); + + void processSpectraMCPWeighted(aod::JetMcCollision const& mccollision, + soa::SmallGroups const& collisions, + soa::Join const& jets, + aod::JetParticles const&) + { + bool mcLevelIsParticleLevel = true; + float eventWeight = mccollision.weight(); + + registry.fill(HIST("h_mcColl_counts"), 0.5); + registry.fill(HIST("h_mcColl_counts_weight"), 0.5, eventWeight); + if (std::abs(mccollision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("h_mcColl_counts"), 1.5); + registry.fill(HIST("h_mcColl_counts_weight"), 1.5, eventWeight); + if (collisions.size() < 1) { + return; + } + registry.fill(HIST("h_mcColl_counts"), 2.5); + registry.fill(HIST("h_mcColl_counts_weight"), 2.5, eventWeight); + + bool hasSel8Coll = false; + for (auto const& collision : collisions) { + if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + hasSel8Coll = true; + } + } + if (!hasSel8Coll) { + return; + } + registry.fill(HIST("h_mcColl_counts"), 3.5); + registry.fill(HIST("h_mcColl_counts_weight"), 3.5, eventWeight); + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet, mcLevelIsParticleLevel)) { + continue; + } + float jetweight = jet.eventWeight(); + double pTHat = 10. / (std::pow(jetweight, 1.0 / pTHatExponent)); + for (int N = 1; N < 21; N++) { + if (jet.pt() < N * 0.25 * pTHat && jet.r() == round(selectedJetsRadius * 100.0f)) { + registry.fill(HIST("h2_jet_ptcut_part"), jet.pt(), N * 0.25, jetweight); + } + } + registry.fill(HIST("h_jet_phat_part_weighted"), pTHat, jetweight); + fillMCPHistograms(jet, jetweight); + } + } + PROCESS_SWITCH(JetSpectraCharged, processSpectraMCPWeighted, "jet spectra for MC particle level weighted", false); + + void processEvtWiseConstSubJetsData(soa::Filtered::iterator const& collision, + soa::Join const& jets, + aod::JetTracksSub const&) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillEventWiseConstituentSubtractedHistograms(jet, collision.centrality()); + } + } + PROCESS_SWITCH(JetSpectraCharged, processEvtWiseConstSubJetsData, "jet spectrum for eventwise constituent-subtracted jets data", false); + + void processEvtWiseConstSubJetsMCD(soa::Filtered::iterator const& collision, + soa::Join const& jets, + aod::JetTracksSub const&) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillEventWiseConstituentSubtractedHistograms(jet, collision.centrality()); + } + } + PROCESS_SWITCH(JetSpectraCharged, processEvtWiseConstSubJetsMCD, "jet spectrum for eventwise constituent-subtracted mcd jets", false); + + void processJetsMatched(soa::Filtered::iterator const& collision, + ChargedMCDMatchedJets const& mcdjets, + ChargedMCPMatchedJets const&, + aod::JetTracks const&, aod::JetParticles const&) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + + for (const auto& mcdjet : mcdjets) { + if (!isAcceptedJet(mcdjet)) { + continue; + } + fillMatchedHistograms(mcdjet); + } + } + PROCESS_SWITCH(JetSpectraCharged, processJetsMatched, "matched mcp and mcd jets", false); + + void processJetsMatchedWeighted(soa::Filtered::iterator const& collision, + ChargedMCDMatchedJetsWeighted const& mcdjets, + ChargedMCPMatchedJetsWeighted const&, + aod::JetTracks const&, aod::JetParticles const&) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (const auto& mcdjet : mcdjets) { + if (!isAcceptedJet(mcdjet)) { + continue; + } + fillMatchedHistograms(mcdjet, mcdjet.eventWeight()); + } + } + PROCESS_SWITCH(JetSpectraCharged, processJetsMatchedWeighted, "matched mcp and mcd jets with weighted events", false); + + void processJetsMatchedSubtracted(McParticleCollision::iterator const& mccollision, + soa::SmallGroups> const& collisions, + ChargedMCDMatchedJets const& mcdjets, + ChargedMCPMatchedJets const&, + aod::JetTracks const&, aod::JetParticles const&) + { + registry.fill(HIST("h_mc_collisions_matched"), 0.5); + if (mccollision.size() < 1) { + return; + } + registry.fill(HIST("h_mc_collisions_matched"), 1.5); + if (!(std::abs(mccollision.posZ()) < vertexZCut)) { + return; + } + registry.fill(HIST("h_mc_collisions_matched"), 2.5); + double mcrho = mccollision.rho(); + registry.fill(HIST("h_mc_rho_matched"), mcrho); + for (const auto& collision : collisions) { + registry.fill(HIST("h_mcd_events_matched"), 0.5); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents) || !(std::abs(collision.posZ()) < vertexZCut)) { + continue; + } + registry.fill(HIST("h_mcd_events_matched"), 1.5); + if (collision.centrality() < centralityMin || collision.centrality() > centralityMax) { + continue; + } + registry.fill(HIST("h_mcd_events_matched"), 2.5); + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + registry.fill(HIST("h_mcd_events_matched"), 3.5); + + auto collmcdjets = mcdjets.sliceBy(mcdjetsPerJCollision, collision.globalIndex()); + for (const auto& mcdjet : collmcdjets) { + if (!isAcceptedJet(mcdjet)) { + continue; + } + fillGeoMatchedCorrHistograms(mcdjet, collision.rho(), mcrho); + } + } + } + PROCESS_SWITCH(JetSpectraCharged, processJetsMatchedSubtracted, "matched mcp and mcd jets after subtraction", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGJE/Tasks/jetSpectraEseTask.cxx b/PWGJE/Tasks/jetSpectraEseTask.cxx new file mode 100644 index 00000000000..81741c3b0e1 --- /dev/null +++ b/PWGJE/Tasks/jetSpectraEseTask.cxx @@ -0,0 +1,987 @@ +// 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 jetSpectraEseTask.cxx +/// \brief jet spectra analysis framework with ESE (19/08/2024) +/// +/// \author Joachim C. K. B. Hansen, Lund University + +#include +#include +#include +#include + +#include +#include + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" + +#include "Common/DataModel/EseTable.h" +#include "Common/DataModel/Qvectors.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +#include "Framework/runDataProcessing.h" + +struct JetSpectraEseTask { + ConfigurableAxis binJetPt{"binJetPt", {250, -50., 200.}, ""}; + ConfigurableAxis bindPhi{"bindPhi", {180, -o2::constants::math::PI, o2::constants::math::PI}, ""}; + ConfigurableAxis binESE{"binESE", {100, 0, 100}, ""}; + ConfigurableAxis binCos{"binCos", {100, -1.05, 1.05}, ""}; + ConfigurableAxis binOccupancy{"binOccupancy", {5000, 0, 25000}, ""}; + ConfigurableAxis binQVec{"binQVec", {500, -3, 3}, ""}; + ConfigurableAxis binCentrality{"binCentrality", {101, -1, 100}, ""}; + ConfigurableAxis binPhi{"binPhi", {60, -1.0, 7.0}, ""}; + ConfigurableAxis binEta{"binEta", {80, -0.9, 0.9}, ""}; + ConfigurableAxis binFit0{"binFit0", {100, 0, 50}, ""}; + ConfigurableAxis binFit13{"binFit13", {100, 0, 1.4}, ""}; + ConfigurableAxis binFit24{"binFit24", {100, 0, 10}, ""}; + + Configurable jetPtMin{"jetPtMin", 5.0, "minimum jet pT cut"}; + Configurable jetR{"jetR", 0.2, "jet resolution parameter"}; + Configurable randomConeR{"randomConeR", 0.4, "size of random Cone for estimating background fluctuations"}; + Configurable randomConeLeadJetDeltaR{"randomConeLeadJetDeltaR", -99.0, "min distance between leading jet axis and random cone (RC) axis; if negative, min distance is set to automatic value of R_leadJet+R_RC "}; + Configurable vertexZCut{"vertexZCut", 10.0, "vertex z cut"}; + Configurable> centRange{"centRange", {0, 90}, "centrality region of interest"}; + Configurable cfgSelCentrality{"cfgSelCentrality", true, "Flag for centrality selection"}; + // Configurable leadingTrackPtCut{"leadingTrackPtCut", 5.0, "leading jet pT cut"}; + Configurable jetAreaFractionMin{"jetAreaFractionMin", -99, "used to make a cut on the jet areas"}; + Configurable cfgCentVariant{"cfgCentVariant", false, "Flag for centrality variant 1"}; + Configurable cfgisPbPb{"cfgisPbPb", false, "Flag for using MC centrality in PbPb"}; + Configurable cfgbkgSubMC{"cfgbkgSubMC", true, "Flag for MC background subtraction"}; + Configurable cfgUseMCEventWeights{"cfgUseMCEventWeights", false, "Flag for using MC event weights"}; + Configurable leadingConstituentPtMin{"leadingConstituentPtMin", -99.0, "minimum pT selection on jet constituent"}; + Configurable leadingConstituentPtMax{"leadingConstituentPtMax", 9999.0, "maximum pT selection on jet constituent"}; + Configurable checkLeadConstituentMinPtForMcpJets{"checkLeadConstituentMinPtForMcpJets", false, "flag to choose whether particle level jets should have their lead track pt above leadingConstituentPtMin to be accepted; off by default, as leadingConstituentPtMin cut is only applied on MCD jets for the Pb-Pb analysis using pp MC anchored to Pb-Pb for the response matrix"}; + Configurable pTHatMaxMCD{"pTHatMaxMCD", 999.0, "maximum fraction of hard scattering for jet acceptance in detector MC"}; + Configurable pTHatMaxMCP{"pTHatMaxMCP", 999.0, "maximum fraction of hard scattering for jet acceptance in particle MC"}; + Configurable pTHatExponent{"pTHatExponent", 6.0, "exponent of the event weight for the calculation of pTHat"}; + + Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum eta acceptance for tracks"}; + Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum eta acceptance for tracks"}; + Configurable trackPtMin{"trackPtMin", 0.15, "minimum pT acceptance for tracks"}; + Configurable trackPtMax{"trackPtMax", 200.0, "maximum pT acceptance for tracks"}; + + Configurable jetEtaMin{"jetEtaMin", -0.7, "minimum jet pseudorapidity"}; + Configurable jetEtaMax{"jetEtaMax", 0.7, "maximum jet pseudorapidity"}; + + Configurable eventSelections{"eventSelections", "sel8FullPbPb", "choose event selection"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + + Configurable cfgEvSelOccupancy{"cfgEvSelOccupancy", true, "Flag for occupancy cut"}; + + Configurable> cfgCutOccupancy{"cfgCutOccupancy", {0, 1000}, "Occupancy cut"}; + Configurable> cfgOccupancyPtCut{"cfgOccupancyPtCut", {0, 100}, "pT cut"}; + + Configurable cfgrhoPhi{"cfgrhoPhi", true, "Flag for rho(phi)"}; + + Configurable cfgnTotalSystem{"cfgnTotalSystem", 7, "total qvector number // look in Qvector table for this number"}; + Configurable cfgnCorrLevel{"cfgnCorrLevel", 3, "QVector step: 0 = no corr, 1 = rect, 2 = twist, 3 = full"}; + + Configurable cfgEPRefA{"cfgEPRefA", "FT0A", "EP reference A"}; + Configurable cfgEPRefB{"cfgEPRefB", "TPCpos", "EP reference B"}; + Configurable cfgEPRefC{"cfgEPRefC", "TPCneg", "EP reference C"}; + + AxisSpec jetPtAxis = {binJetPt, "#it{p}_{T,jet}"}; + AxisSpec dPhiAxis = {bindPhi, "#Delta#phi"}; + AxisSpec eseAxis = {binESE, "#it{q}_{2}"}; + AxisSpec cosAxis = {binCos, ""}; + AxisSpec occAxis = {binOccupancy, "Occupancy"}; + AxisSpec qvecAxis = {binQVec, "Q-vector"}; + AxisSpec centAxis = {binCentrality, "Centrality"}; + AxisSpec phiAxis = {binPhi, "#phi"}; + AxisSpec etaAxis = {binEta, "#eta"}; + AxisSpec fitAxis0 = {binFit0, "Fit0"}; + AxisSpec fitAxis13 = {binFit13, "Fit13"}; + AxisSpec fitAxis24 = {binFit24, "Fit24"}; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + std::vector eventSelectionBits; + int trackSelection{-1}; + + Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); + Filter jetCuts = aod::jet::pt > jetPtMin&& aod::jet::r == nround(jetR.node() * 100.0f) && nabs(aod::jet::eta) < 0.9f - jetR; + Filter colFilter = nabs(aod::jcollision::posZ) < vertexZCut; + Filter mcCollisionFilter = nabs(aod::jmccollision::posZ) < vertexZCut; + using ChargedMCDJets = soa::Filtered>; + Preslice mcdjetsPerJCollision = o2::aod::jet::collisionId; + + enum class DetID { FT0C, + FT0A, + FT0M, + FV0A, + TPCpos, + TPCneg, + TPCall }; + + struct EventPlane { + float psi2; + float psi3; + }; + + struct EventPlaneFiller { + bool psi; + bool hist; + }; + + static constexpr EventPlaneFiller PsiFillerEP = {true, true}; + static constexpr EventPlaneFiller PsiFillerEse = {true, false}; + static constexpr EventPlaneFiller PsiFillerOcc = {false, false}; + + void init(o2::framework::InitContext&) + { + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + + LOGF(info, "jetSpectraEse::init()"); + + if (doprocessESEDataCharged) { + LOGF(info, "JetSpectraEseTask::init() - ESE Data Process"); + registry.add("hEventCounter", "event status;event status;entries", {HistType::kTH1F, {{10, 0.0, 10.0}}}); + registry.add("hCentralitySel", ";Centrality;entries", {HistType::kTH1F, {{centAxis}}}); + registry.add("hCentralityAnalyzed", ";Centrality;entries", {HistType::kTH1F, {{centAxis}}}); + registry.add("hTrackCounter", "event status;event status;entries", {HistType::kTH1F, {{10, 0.0, 10.0}}}); + registry.add("hJetPt", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{jetPtAxis}}}); + registry.add("hJetPt_bkgsub", "jet pT background sub;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{jetPtAxis}}}); + registry.add("hJetEta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{etaAxis}}}); + registry.add("hJetPhi", "jet #phi;#phi_{jet};entries", {HistType::kTH1F, {{phiAxis}}}); + registry.add("hRho", ";#rho;entries", {HistType::kTH2F, {{centAxis}, {100, 0, 200.}}}); + registry.add("hRhoPhi", ";#rho;entries", {HistType::kTH2F, {{centAxis}, {100, 0, 200.}}}); + registry.add("hJetArea", ";area_{jet};entries", {HistType::kTH1F, {{80, 0, 10.}}}); + registry.add("hCentJetPtdPhiq2", "", {HistType::kTHnSparseF, {{centAxis}, {jetPtAxis}, {dPhiAxis}, {eseAxis}}}); + registry.add("hCentJetPtdPhiq2RhoPhi", "", {HistType::kTHnSparseF, {{centAxis}, {jetPtAxis}, {dPhiAxis}, {eseAxis}}}); + + registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(1, "Input event"); + registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(2, "Event selection"); + registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(3, "Occupancy cut"); + registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(4, "ESE available"); + registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(5, "Lead track"); + registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(6, "Jet loop"); + registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(7, "Centrality analyzed"); + + registry.add("hPhiPtsum", "jet sumpt;sum p_{T};entries", {HistType::kTH1F, {{40, 0., o2::constants::math::TwoPI}}}); + registry.add("hfitPar0", "", {HistType::kTH2F, {{centAxis}, {fitAxis0}}}); + registry.add("hfitPar1", "", {HistType::kTH2F, {{centAxis}, {fitAxis13}}}); + registry.add("hfitPar2", "", {HistType::kTH2F, {{centAxis}, {fitAxis24}}}); + registry.add("hfitPar3", "", {HistType::kTH2F, {{centAxis}, {fitAxis13}}}); + registry.add("hfitPar4", "", {HistType::kTH2F, {{centAxis}, {fitAxis24}}}); + registry.add("hPValueCentCDF", "p-value cDF vs centrality; centrality; p-value", {HistType::kTH2F, {{centAxis}, {40, 0, 1}}}); + registry.add("hCentChi2Ndf", "Chi2 vs centrality; centrality; #tilde{#chi^{2}}", {HistType::kTH2F, {{centAxis}, {100, 0, 5}}}); + registry.add("hCentPhi", "centrality vs #rho(#varphi); centrality; #rho(#varphi) ", {HistType::kTH2F, {{centAxis}, {210, -10.0, 200.0}}}); + registry.add("hdPhiRhoPhi", "#varphi vs #rho(#varphi); #varphi - #Psi_{EP,2}; #rho(#varphi) ", {HistType::kTH2F, {{40, -o2::constants::math::PI, o2::constants::math::PI}, {210, -10.0, 200.0}}}); + } + if (doprocessESEEPData) { + LOGF(info, "JetSpectraEseTask::init() - Event Plane Process"); + registry.add("hPsi2FT0C", ";Centrality; #Psi_{2}", {HistType::kTH2F, {{centAxis}, {150, -2.5, 2.5}}}); + registry.addClone("hPsi2FT0C", "hPsi2FT0A"); + registry.addClone("hPsi2FT0C", "hPsi2FV0A"); + registry.addClone("hPsi2FT0C", "hPsi2TPCpos"); + registry.addClone("hPsi2FT0C", "hPsi2TPCneg"); + registry.add("hCosPsi2AmC", ";Centrality;cos(2(#Psi_{2}^{A}-#Psi_{2}^{B}));#it{q}_{2}", {HistType::kTH3F, {{centAxis}, {cosAxis}, {eseAxis}}}); + registry.addClone("hCosPsi2AmC", "hCosPsi2AmB"); + registry.addClone("hCosPsi2AmC", "hCosPsi2BmC"); + registry.add("hQvecUncorV2", ";Centrality;Q_x;Q_y", {HistType::kTH3F, {{centAxis}, {qvecAxis}, {qvecAxis}}}); + registry.addClone("hQvecUncorV2", "hQvecRectrV2"); + registry.addClone("hQvecUncorV2", "hQvecTwistV2"); + registry.addClone("hQvecUncorV2", "hQvecFinalV2"); + registry.addClone("hPsi2FT0C", "hEPUncorV2"); + registry.addClone("hPsi2FT0C", "hEPRectrV2"); + registry.addClone("hPsi2FT0C", "hEPTwistV2"); + } + if (doprocessESEBackground) { + LOGF(info, "JetSpectraEseTask::init() - Background Process"); + registry.add("hCentRhoRandomCone", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH2F, {{1100, 0., 110.}, {800, -400.0, 400.0}}}); + registry.add("hCentRhoRandomConeRandomTrackDir", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH2F, {{1100, 0., 110.}, {800, -400.0, 400.0}}}); + registry.add("hCentRhoRandomConewoLeadingJet", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTHnSparseF, {{centAxis}, {800, -400.0, 400.0}, {dPhiAxis}, {eseAxis}}}); + registry.add("hCentRhoRandomConeRndTrackDirwoOneLeadingJet", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTHnSparseF, {{centAxis}, {800, -400.0, 400.0}, {dPhiAxis}, {eseAxis}}}); + registry.add("hCentRhoRandomConeRndTrackDirwoTwoLeadingJet", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTHnSparseF, {{centAxis}, {800, -400.0, 400.0}, {dPhiAxis}, {eseAxis}}}); + } + if (doprocessMCParticleLevel) { + LOGF(info, "JetSpectraEseTask::init() - MC Particle level"); + registry.add("mcp/hEventCounter", "event status;event status;entries", {HistType::kTH1F, {{10, 0.0, 10.0}}}); + registry.add("mcp/hCentralitySel", ";centr;entries", {HistType::kTH1F, {{centAxis}}}); + // registry.add("mcp/hJetSparse", ";Centrality;#it{p}_{T,jet part}; #eta; #phi", {HistType::kTHnSparseF, {{centAxis}, {jetPtAxis}, {etaAxis}, {phiAxis}}}); + registry.add("mcp/hJetSparse", ";Centrality;#it{p}_{T,jet part}; #eta; #phi", {HistType::kTHnSparseF, {{centAxis}, {jetPtAxis}, {etaAxis}, {phiAxis}}}); + // registry.add("mcp/hJetPt", "particle level jet pT;#it{p}_{T,jet part} (GeV/#it{c});entries", {HistType::kTH1F, {{jetPtAxis}}}); + // registry.add("mcp/hJetEta", "particle level jet #eta;#eta_{jet part};entries", {HistType::kTH1F, {{etaAxis}}}); + // registry.add("mcp/hJetPhi", "particle level jet #phi;#phi_{jet part};entries", {HistType::kTH1F, {{phiAxis}}}); + + registry.get(HIST("mcp/hEventCounter"))->GetXaxis()->SetBinLabel(1, "Input event"); + registry.get(HIST("mcp/hEventCounter"))->GetXaxis()->SetBinLabel(2, "Collision size < 1"); + registry.get(HIST("mcp/hEventCounter"))->GetXaxis()->SetBinLabel(3, "MCD size != 1"); + registry.get(HIST("mcp/hEventCounter"))->GetXaxis()->SetBinLabel(4, "Occupancy cut"); + } + if (doprocessMCDetectorLevel) { + LOGF(info, "JetSpectraEseTask::init() - MC Detector level"); + registry.add("mcd/hEventCounter", "event status;event status;entries", {HistType::kTH1F, {{10, 0.0, 10.0}}}); + registry.add("mcd/hCentralitySel", ";centr;entries", {HistType::kTH1F, {{centAxis}}}); + // registry.add("mcd/hJetPt", "particle level jet pT;#it{p}_{T,jet part} (GeV/#it{c});entries", {HistType::kTH1F, {{jetPtAxis}}}); + // registry.add("mcd/hJetSparse", ";Centrality;#it{p}_{T,jet det}; #eta; #phi", {HistType::kTHnSparseF, {{centAxis}, {jetPtAxis}, {etaAxis}, {phiAxis}}}); + registry.add("mcd/hJetSparse", ";Centrality;#it{p}_{T,jet det}; #eta; #phi", {HistType::kTHnSparseF, {{centAxis}, {jetPtAxis}, {etaAxis}, {phiAxis}}}); + // registry.add("mcd/hJetEta", "particle level jet #eta;#eta_{jet part};entries", {HistType::kTH1F, {{etaAxis}}}); + // registry.add("mcd/hJetPhi", "particle level jet #phi;#phi_{jet part};entries", {HistType::kTH1F, {{phiAxis}}}); + + registry.get(HIST("mcd/hEventCounter"))->GetXaxis()->SetBinLabel(1, "Input event"); + registry.get(HIST("mcd/hEventCounter"))->GetXaxis()->SetBinLabel(2, "Collision size < 1"); + registry.get(HIST("mcd/hEventCounter"))->GetXaxis()->SetBinLabel(3, "Occupancy cut"); + } + if (doprocessMCChargedMatched) { + LOGF(info, "JetSpectraEseTask::init() - MC Charged Matched"); + + registry.add("mcm/hJetSparse", ";Centrality;#it{p}_{T,jet det}; #eta; #phi", {HistType::kTHnSparseF, {{centAxis}, {jetPtAxis}, {etaAxis}, {phiAxis}}}); /* detector level */ + // registry.add("mcm/hPartSparseMatch", ";Centrality;#it{p}_{T,jet part}; #eta; #phi", {HistType::kTHnSparseF, {{centAxis}, {jetPtAxis}, {etaAxis}, {phiAxis}}}); + registry.addClone("mcm/hJetSparse", "mcm/hDetSparseMatch"); + registry.addClone("mcm/hJetSparse", "mcm/hPartSparseMatch"); + + registry.add("mcm/hMCEventCounter", "event status;event status;entries", {HistType::kTH1F, {{10, 0.0, 10.0}}}); + registry.add("mcm/hMCDMatchedEventCounter", "event status;event status;entries", {HistType::kTH1F, {{10, 0.0, 10.0}}}); + registry.add("mcm/hCentralityAnalyzed", ";Centrality;entries", {HistType::kTH1F, {{centAxis}}}); + + registry.add("mcm/hMatchedJetsPtDelta", "#it{p}_{T,jet part}; det - part", {HistType::kTH2F, {{jetPtAxis}, {100, -20., 20.0}}}); + registry.add("mcm/hGenMatchedJetsPtDeltadPt", "#it{p}_{T,jet part}; det - part / part", {HistType::kTHnSparseF, {{centAxis}, {jetPtAxis}, {200, -20., 20.0}}}); + registry.add("mcm/hRecoMatchedJetsPtDeltadPt", "#it{p}_{T,jet det}; det - part / det", {HistType::kTHnSparseF, {{centAxis}, {jetPtAxis}, {200, -20., 20.0}}}); + registry.add("mcm/hMatchedJetsEtaDelta", "#eta_{jet part}; det - part", {HistType::kTH2F, {{etaAxis}, {200, -0.8, 0.8}}}); + registry.add("mcm/hMatchedJetsPhiDelta", "#phi_{jet part}; det - part", {HistType::kTH2F, {{phiAxis}, {200, -10.0, 10.}}}); + + registry.add("mcm/hRespMcDMcPMatch", ";Centrality,#it{p}_{T, jet det}; #it{p}_{T, jet part}", {HistType::kTHnSparseF, {{centAxis}, {jetPtAxis}, {jetPtAxis}}}); + + registry.get(HIST("mcm/hMCEventCounter"))->GetXaxis()->SetBinLabel(1, "Input event"); + registry.get(HIST("mcm/hMCEventCounter"))->GetXaxis()->SetBinLabel(2, "Collision size < 1"); + registry.get(HIST("mcm/hMCEventCounter"))->GetXaxis()->SetBinLabel(3, "Vertex cut"); + registry.get(HIST("mcm/hMCEventCounter"))->GetXaxis()->SetBinLabel(4, "After analysis"); + registry.get(HIST("mcm/hMCDMatchedEventCounter"))->GetXaxis()->SetBinLabel(1, "Input event"); + registry.get(HIST("mcm/hMCDMatchedEventCounter"))->GetXaxis()->SetBinLabel(2, "Vertex cut"); + registry.get(HIST("mcm/hMCDMatchedEventCounter"))->GetXaxis()->SetBinLabel(3, "Event selection"); + registry.get(HIST("mcm/hMCDMatchedEventCounter"))->GetXaxis()->SetBinLabel(4, "Occupancy cut"); + registry.get(HIST("mcm/hMCDMatchedEventCounter"))->GetXaxis()->SetBinLabel(5, "Centrality cut1:cut2"); + registry.get(HIST("mcm/hMCDMatchedEventCounter"))->GetXaxis()->SetBinLabel(6, "After analysis"); + } + if (doprocessESEOccupancy) { + LOGF(info, "JetSpectraEseTask::init() - Occupancy QA"); + registry.add("hEventCounterOcc", "event status;event status;entries", {HistType::kTH1F, {{10, 0.0, 10.0}}}); + registry.add("hTrackPt", "track pT;#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTHnSparseF, {{centAxis}, {100, 0, 100}, {eseAxis}, {occAxis}}}); + registry.add("hTrackEta", "track #eta;#eta_{track};entries", {HistType::kTH3F, {{centAxis}, {etaAxis}, {occAxis}}}); + registry.add("hTrackPhi", "track #phi;#phi_{track};entries", {HistType::kTH3F, {{centAxis}, {phiAxis}, {occAxis}}}); + registry.add("hOccupancy", "Occupancy;Occupancy;entries", {HistType::kTH1F, {{occAxis}}}); + registry.add("hPsiOccupancy", "Occupancy;#Psi_{2};entries", {HistType::kTH3F, {{centAxis}, {150, -2.5, 2.5}, {occAxis}}}); + } + } + + void processESEDataCharged(soa::Join::iterator const& collision, + soa::Filtered> const& jets, + aod::JetTracks const& tracks) + { + float counter{0.5f}; + registry.fill(HIST("hEventCounter"), counter++); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) + return; + registry.fill(HIST("hEventCounter"), counter++); + + if (cfgEvSelOccupancy && !isOccupancyAccepted(collision)) + return; + registry.fill(HIST("hEventCounter"), counter++); + + auto centrality = cfgCentVariant ? collision.centralityVariant1() : collision.centrality(); + if (cfgSelCentrality && !isCentralitySelected(centrality)) + return; + registry.fill(HIST("hCentralitySel"), centrality); + + const auto psi{procEP(collision)}; + const auto qPerc{collision.qPERCFT0C()}; + if (qPerc[0] < 0) + return; + registry.fill(HIST("hEventCounter"), counter++); + std::unique_ptr rhoFit{nullptr}; + if (cfgrhoPhi) { + rhoFit = fitRho(collision, psi, tracks, jets); + if (!rhoFit) + return; + } + + registry.fill(HIST("hEventCounter"), counter++); + registry.fill(HIST("hRho"), centrality, collision.rho()); + registry.fill(HIST("hCentralityAnalyzed"), centrality); + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) + continue; + if (!isAcceptedJet(jet)) { + continue; + } + registry.fill(HIST("hJetPt"), jet.pt()); + registry.fill(HIST("hJetPt_bkgsub"), jet.pt() - collision.rho() * jet.area()); + registry.fill(HIST("hJetEta"), jet.eta()); + registry.fill(HIST("hJetPhi"), jet.phi()); + registry.fill(HIST("hJetArea"), jet.area()); + + float dPhi{RecoDecay::constrainAngle(jet.phi() - psi.psi2, -o2::constants::math::PI)}; + registry.fill(HIST("hCentJetPtdPhiq2"), centrality, jet.pt() - (collision.rho() * jet.area()), dPhi, qPerc[0]); + + if (cfgrhoPhi) { + auto rhoLocal = evalRho(rhoFit.get(), jetR, jet.phi(), collision.rho()); + registry.fill(HIST("hRhoPhi"), centrality, rhoLocal); + registry.fill(HIST("hCentJetPtdPhiq2RhoPhi"), centrality, jet.pt() - (rhoLocal * jet.area()), dPhi, qPerc[0]); + registry.fill(HIST("hCentPhi"), centrality, rhoFit->Eval(jet.phi())); + registry.fill(HIST("hdPhiRhoPhi"), dPhi, rhoLocal); + } + } + registry.fill(HIST("hEventCounter"), counter++); + + if (centrality < 30 || centrality > 50) + return; + registry.fill(HIST("hEventCounter"), counter++); + } + PROCESS_SWITCH(JetSpectraEseTask, processESEDataCharged, "process ese collisions", true); + + void processESEEPData(soa::Join::iterator const& collision, + soa::Filtered const&, + aod::JetTracks const&) + { + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) + return; + + if (cfgEvSelOccupancy && !isOccupancyAccepted(collision)) + return; + + [[maybe_unused]] const auto psi{procEP(collision)}; + } + PROCESS_SWITCH(JetSpectraEseTask, processESEEPData, "process ese collisions for filling EP and EPR", false); + + void processESEBackground(soa::Filtered>::iterator const& collision, + soa::Join const& jets, + aod::JetTracks const& tracks) + { + bkgFluctuationsRandomCone(collision, jets, tracks); + } + PROCESS_SWITCH(JetSpectraEseTask, processESEBackground, "process random cones with event plane and ESE", false); + + void processESEOccupancy(soa::Join::iterator const& collision, + soa::Join const& tracks) + { + float count{0.5}; + registry.fill(HIST("hEventCounterOcc"), count++); + const auto psi{procEP(collision)}; + const auto qPerc{collision.qPERCFT0C()}; + + auto occupancy{collision.trackOccupancyInTimeRange()}; + registry.fill(HIST("hPsiOccupancy"), collision.centrality(), psi.psi2, occupancy); + registry.fill(HIST("hOccupancy"), occupancy); + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) + return; + registry.fill(HIST("hEventCounterOcc"), count++); + + for (auto const& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) + continue; + + registry.fill(HIST("hTrackPt"), collision.centrality(), track.pt(), qPerc[0], occupancy); + if (track.pt() < cfgOccupancyPtCut->at(0) || track.pt() > cfgOccupancyPtCut->at(1)) + continue; + registry.fill(HIST("hTrackEta"), collision.centrality(), track.eta(), occupancy); + registry.fill(HIST("hTrackPhi"), collision.centrality(), track.phi(), occupancy); + } + } + PROCESS_SWITCH(JetSpectraEseTask, processESEOccupancy, "process occupancy", false); + + void processMCParticleLevel(soa::Filtered>::iterator const& mcCollision, + soa::SmallGroups const& collisions, + soa::Filtered> const& jets, + aod::JetParticles const&) + { + float counter{0.5f}; + registry.fill(HIST("mcp/hEventCounter"), counter++); + if (mcCollision.size() < 1) { + return; + } + registry.fill(HIST("mcp/hEventCounter"), counter++); + if (collisions.size() != 1) { + return; + } + + registry.fill(HIST("mcp/hEventCounter"), counter++); + auto centrality{-1}; + bool fOccupancy = true; + bool eventSel = true; + for (const auto& col : collisions) { + if (cfgisPbPb) + centrality = col.centrality(); + if (cfgEvSelOccupancy && !isOccupancyAccepted(col)) + fOccupancy = false; + if (!jetderiveddatautilities::selectCollision(col, eventSelectionBits)) + eventSel = false; + } + if (cfgEvSelOccupancy && !fOccupancy) + return; + if (!(std::abs(mcCollision.posZ()) < vertexZCut)) { + return; + } + if (!eventSel) + return; + + registry.fill(HIST("mcp/hEventCounter"), counter++); + + registry.fill(HIST("mcp/hCentralitySel"), centrality); + jetLoopMCP(jets, centrality, mcCollision.rho()); + } + PROCESS_SWITCH(JetSpectraEseTask, processMCParticleLevel, "jets on particle level MC", false); + + void processMCDetectorLevel(soa::Filtered>::iterator const& collision, + ChargedMCDJets const& mcdjets, + aod::JetTracks const&, + aod::JetParticles const&) + { + float counter{0.5f}; + registry.fill(HIST("mcd/hEventCounter"), counter++); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) + return; + registry.fill(HIST("mcd/hEventCounter"), counter++); + if (cfgEvSelOccupancy && !isOccupancyAccepted(collision)) + return; + registry.fill(HIST("mcd/hEventCounter"), counter++); + + if (!(std::abs(collision.posZ()) < vertexZCut)) { + return; + } + + auto centrality = cfgisPbPb ? collision.centrality() : -1; + + registry.fill(HIST("mcd/hCentralitySel"), centrality); + jetLoopMCD(mcdjets, centrality, collision.rho()); + } + PROCESS_SWITCH(JetSpectraEseTask, processMCDetectorLevel, "jets on detector level", false); + + using JetMCPTable = soa::Filtered>; + void processMCChargedMatched(soa::Filtered>::iterator const& mcCol, + soa::SmallGroups> const& collisions, + ChargedMCDJets const& mcdjets, + JetMCPTable const&, + aod::JetTracks const&, + aod::JetParticles const&) + { + float counter{0.5f}; + registry.fill(HIST("mcm/hMCEventCounter"), counter++); + if (mcCol.size() < 1) { + return; + } + if (collisions.size() != 1) { + return; + } + registry.fill(HIST("mcm/hMCEventCounter"), counter++); + if (!(std::abs(mcCol.posZ()) < vertexZCut)) { + return; + } + registry.fill(HIST("mcm/hMCEventCounter"), counter++); + + for (const auto& collision : collisions) { + float secCount{0.5f}; + registry.fill(HIST("mcm/hMCDMatchedEventCounter"), secCount++); + if (!(std::abs(collision.posZ()) < vertexZCut)) { + return; + } + registry.fill(HIST("mcm/hMCDMatchedEventCounter"), secCount++); + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) + return; + registry.fill(HIST("mcm/hMCDMatchedEventCounter"), secCount++); + + if (cfgEvSelOccupancy && !isOccupancyAccepted(collision)) + return; + registry.fill(HIST("mcm/hMCDMatchedEventCounter"), secCount++); + + auto centrality = cfgisPbPb ? collision.centrality() : -1; + if (cfgisPbPb) + if (centrality < centRange->at(0) || centrality > centRange->at(1)) + registry.fill(HIST("mcm/hMCDMatchedEventCounter"), secCount++); + + registry.fill(HIST("mcm/hCentralityAnalyzed"), centrality); + matchedJetLoop(mcdjets.sliceBy(mcdjetsPerJCollision, collision.globalIndex()), centrality, collision.rho(), mcCol.rho()); + + registry.fill(HIST("mcm/hMCDMatchedEventCounter"), secCount++); + } + registry.fill(HIST("mcm/hMCEventCounter"), counter++); + } + PROCESS_SWITCH(JetSpectraEseTask, processMCChargedMatched, "jet MC process: geometrically matched MCP and MCD for response matrix and efficiency", false); + + // template + template + EventPlane procEP(EPCol const& vec) + { + constexpr std::array AmpCut{1e-8, 0.0}; + auto computeEP = [&AmpCut](std::vector vec, auto det, float n) { return vec[2] > AmpCut[det] ? (1.0 / n) * std::atan2(vec[1], vec[0]) : 999.; }; + std::map epMap; + std::map ep3Map; + auto vec1{qVecNoESE(vec)}; + epMap["FT0A"] = computeEP(vec1, 0, 2.0); + ep3Map["FT0A"] = computeEP(vec1, 0, 3.0); + if constexpr (P.psi) { + auto vec2{qVecNoESE(vec)}; + epMap["FT0C"] = computeEP(vec2, 0, 2.0); + ep3Map["FT0C"] = computeEP(vec2, 0, 3.0); + epMap["FV0A"] = computeEP(qVecNoESE(vec), 0, 2.0); + epMap["TPCpos"] = computeEP(qVecNoESE(vec), 1, 2.0); + epMap["TPCneg"] = computeEP(qVecNoESE(vec), 1, 2.0); + if constexpr (P.hist) + fillEP(/*std::make_index_sequence<5>{},*/ vec, epMap); + auto cosPsi = [](float psiX, float psiY) { return (static_cast(psiX) == 999. || static_cast(psiY) == 999.) ? 999. : std::cos(2.0 * (psiX - psiY)); }; + std::array epCorrContainer{}; + epCorrContainer[0] = cosPsi(epMap.at(cfgEPRefA), epMap.at(cfgEPRefC)); + epCorrContainer[1] = cosPsi(epMap.at(cfgEPRefA), epMap.at(cfgEPRefB)); + epCorrContainer[2] = cosPsi(epMap.at(cfgEPRefB), epMap.at(cfgEPRefC)); + if constexpr (P.hist) + fillEPCos(/*std::make_index_sequence<3>{},*/ vec, epCorrContainer); + } + EventPlane localPlane; + localPlane.psi2 = epMap.at(cfgEPRefA); + localPlane.psi3 = ep3Map.at(cfgEPRefA); + return localPlane; + // return epMap.at(cfgEPRefA); + } + template + void fillEPCos(/*const std::index_sequence&,*/ const collision& col, const std::array& Corr) + { + // static constexpr std::string CosList[] = {"hCosPsi2AmC", "hCosPsi2AmB", "hCosPsi2BmC"}; + // (registry.fill(HIST(CosList[Idx]), col.centrality(), Corr[Idx], col.qPERCFT0C()[0]), ...); + registry.fill(HIST("hCosPsi2AmC"), col.centrality(), Corr[0], col.qPERCFT0C()[0]); + registry.fill(HIST("hCosPsi2AmB"), col.centrality(), Corr[1], col.qPERCFT0C()[0]); + registry.fill(HIST("hCosPsi2BmC"), col.centrality(), Corr[2], col.qPERCFT0C()[0]); + } + + template + void fillEP(/*const std::index_sequence&,*/ const collision& col, const std::map& epMap) + { + // static constexpr std::string_view EpList[] = {"hPsi2FT0A", "hPsi2FV0A", "hPsi2FT0C", "hPsi2TPCpos", "hPsi2TPCneg"}; + // (registry.fill(HIST(EpList[Idx]), col.centrality(), epMap.at(std::string(RemovePrefix(EpList[Idx])))), ...); + registry.fill(HIST("hPsi2FT0A"), col.centrality(), epMap.at("FT0A")); + registry.fill(HIST("hPsi2FV0A"), col.centrality(), epMap.at("FV0A")); + registry.fill(HIST("hPsi2FT0C"), col.centrality(), epMap.at("FT0C")); + registry.fill(HIST("hPsi2TPCpos"), col.centrality(), epMap.at("TPCpos")); + registry.fill(HIST("hPsi2TPCneg"), col.centrality(), epMap.at("TPCneg")); + } + constexpr std::string_view RemovePrefix(std::string_view str) + { + constexpr std::string_view Prefix{"hPsi2"}; + return str.substr(Prefix.size()); + } + + constexpr int detIDN(const DetID id) + { + switch (id) { + case DetID::FT0C: + return 0; + case DetID::FT0A: + return 1; + case DetID::FT0M: + return 2; + case DetID::FV0A: + return 3; + case DetID::TPCpos: + return 4; + case DetID::TPCneg: + return 5; + case DetID::TPCall: + return 6; + } + return -1; + } + + template + std::vector qVecNoESE(Col collision) + { + const int nmode{2}; + int detId{detIDN(id)}; + int detInd{detId * 4 + cfgnTotalSystem * 4 * (nmode - 2)}; + if constexpr (fill) { + if (collision.qvecAmp()[detInd] > 1e-8) { + registry.fill(HIST("hQvecUncorV2"), collision.centrality(), collision.qvecRe()[detInd], collision.qvecIm()[detInd]); + registry.fill(HIST("hQvecRectrV2"), collision.centrality(), collision.qvecRe()[detInd + 1], collision.qvecIm()[detInd + 1]); + registry.fill(HIST("hQvecTwistV2"), collision.centrality(), collision.qvecRe()[detInd + 2], collision.qvecIm()[detInd + 2]); + registry.fill(HIST("hQvecFinalV2"), collision.centrality(), collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3]); + registry.fill(HIST("hEPUncorV2"), collision.centrality(), 0.5 * std::atan2(collision.qvecIm()[detInd], collision.qvecRe()[detInd])); + registry.fill(HIST("hEPRectrV2"), collision.centrality(), 0.5 * std::atan2(collision.qvecIm()[detInd + 1], collision.qvecRe()[detInd + 1])); + registry.fill(HIST("hEPTwistV2"), collision.centrality(), 0.5 * std::atan2(collision.qvecIm()[detInd + 2], collision.qvecRe()[detInd + 2])); + } + } + std::vector qVec{}; + qVec.push_back(collision.qvecRe()[detInd + cfgnCorrLevel]); + qVec.push_back(collision.qvecIm()[detInd + cfgnCorrLevel]); + qVec.push_back(collision.qvecAmp()[detId]); + return qVec; + } + + template + bool isOccupancyAccepted(const col& collision) + { + auto occupancy{collision.trackOccupancyInTimeRange()}; + if (occupancy < cfgCutOccupancy->at(0) || occupancy > cfgCutOccupancy->at(1)) + return false; + else + return true; + } + + template + bool isCentralitySelected(const Cent& centrality) + { + if (centrality < centRange->at(0) || centrality > centRange->at(1)) + return false; + else + return true; + } + + template + std::unique_ptr fitRho(const Col& col, const EventPlane& ep, TTracks const& tracks, Jets const& jets) + { + float leadingJetPt = 0.0; + float leadingJetEta = 0.0; + // float leadingJetPhi = 0.0; + for (const auto& jet : jets) { + if (jet.pt() > leadingJetPt) { + leadingJetPt = jet.pt(); + leadingJetEta = jet.eta(); + // leadingJetPhi = jet.phi(); + } + } + + int nTrk{0}; + if (jets.size() > 0) { + for (const auto& track : tracks) { + if constexpr (fillHist) + registry.fill(HIST("hTrackCounter"), 0.5); + if (jetderiveddatautilities::selectTrack(track, trackSelection) && (std::fabs(track.eta() - leadingJetEta) > jetR) && track.pt() >= 0.2 && track.pt() <= 5) { + nTrk++; + if constexpr (fillHist) + registry.fill(HIST("hTrackCounter"), 1.5); + } + } + } + if (nTrk < 1) + return nullptr; + + auto hPhiPt = std::unique_ptr(new TH1F("h_ptsum_sumpt_fit", "h_ptsum_sumpt fit use", TMath::CeilNint(std::sqrt(nTrk)), 0., o2::constants::math::TwoPI)); + for (const auto& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection) && (std::fabs(track.eta() - leadingJetEta) > jetR) && track.pt() >= 0.2 && track.pt() <= 5) { + hPhiPt->Fill(track.phi(), track.pt()); + if constexpr (fillHist) { + registry.fill(HIST("hTrackCounter"), 2.5); + registry.fill(HIST("hPhiPtsum"), track.phi(), track.pt()); + } + } + } + auto modulationFit = std::unique_ptr(new TF1("fit_rholoc", "[0] * (1. + 2. * ([1] * std::cos(2. * (x - [2])) + [3] * std::cos(3. * (x - [4]))))", 0, o2::constants::math::TwoPI)); + + modulationFit->SetParameter(0, 1.0); + modulationFit->SetParameter(1, 0.01); + modulationFit->SetParameter(3, 0.01); + + modulationFit->FixParameter(2, (ep.psi2 < 0) ? RecoDecay::constrainAngle(ep.psi2) : ep.psi2); + modulationFit->FixParameter(4, (ep.psi3 < 0) ? RecoDecay::constrainAngle(ep.psi3) : ep.psi3); + + hPhiPt->Fit(modulationFit.get(), "Q", "", 0, o2::constants::math::TwoPI); + + if constexpr (fillHist) { + registry.fill(HIST("hfitPar0"), col.centrality(), modulationFit->GetParameter(0)); + registry.fill(HIST("hfitPar1"), col.centrality(), modulationFit->GetParameter(1)); + registry.fill(HIST("hfitPar2"), col.centrality(), modulationFit->GetParameter(2)); + registry.fill(HIST("hfitPar3"), col.centrality(), modulationFit->GetParameter(3)); + registry.fill(HIST("hfitPar4"), col.centrality(), modulationFit->GetParameter(4)); + } + + if (modulationFit->GetParameter(0) <= 0) + return nullptr; + + double chi2{0.}; + for (int i{0}; i < hPhiPt->GetXaxis()->GetNbins(); i++) { + if (hPhiPt->GetBinContent(i + 1) <= 0.) + continue; + chi2 += std::pow((hPhiPt->GetBinContent(i + 1) - modulationFit->Eval(hPhiPt->GetXaxis()->GetBinCenter(1 + i))), 2) / hPhiPt->GetBinContent(i + 1); + } + + int nDF{1}; + int numParams{2}; + nDF = static_cast(modulationFit->GetXaxis()->GetNbins()) - numParams; + if (nDF <= 0) + return nullptr; + + auto cDF = 1. - TMath::Gamma(nDF, chi2); + + if constexpr (fillHist) { + registry.fill(HIST("hPValueCentCDF"), col.centrality(), cDF); + registry.fill(HIST("hCentChi2Ndf"), col.centrality(), chi2 / (static_cast(nDF))); + } + + return modulationFit; + } + + template + double evalRho(TF1* fit, const float& radius, phiT const& jetPhi, rhoT const& colRho) + { + double integralValue{fit->Integral(jetPhi - radius, jetPhi + radius)}; + double rhoLocal{colRho / (2 * radius * fit->GetParameter(0)) * integralValue}; + return rhoLocal; + } + + template + void bkgFluctuationsRandomCone(TCollisions const& collision, TJets const& jets, TTracks const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (cfgEvSelOccupancy && !isOccupancyAccepted(collision)) + return; + + const auto psi{procEP(collision)}; + auto qPerc{collision.qPERCFT0C()}; + if (qPerc[0] < 0) + return; + + TRandom3 randomNumber(0); + float randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); + float randomConePhi = randomNumber.Uniform(0.0, o2::constants::math::TwoPI); + float randomConePt = 0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, -o2::constants::math::PI); + float dEta = track.eta() - randomConeEta; + if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePt += track.pt(); + } + } + } + registry.fill(HIST("hCentRhoRandomCone"), collision.centrality(), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); + + randomConePt = 0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + float dPhi = RecoDecay::constrainAngle(randomNumber.Uniform(0.0, o2::constants::math::TwoPI) - randomConePhi, -o2::constants::math::PI); + float dEta = randomNumber.Uniform(trackEtaMin, trackEtaMax) - randomConeEta; + if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePt += track.pt(); + } + } + } + registry.fill(HIST("hCentRhoRandomConeRandomTrackDir"), collision.centrality(), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); + + if (jets.size() > 0) { + float dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, -o2::constants::math::PI); + float dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; + + bool jetWasInCone = false; + while ((randomConeLeadJetDeltaR <= 0 && (std::sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < jets.iteratorAt(0).r() / 100.0 + randomConeR)) || (randomConeLeadJetDeltaR > 0 && (std::sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < randomConeLeadJetDeltaR))) { + jetWasInCone = true; + randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); + randomConePhi = randomNumber.Uniform(0.0, o2::constants::math::TwoPI); + dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, -o2::constants::math::PI); + dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; + } + if (jetWasInCone) { + randomConePt = 0.0; + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, -o2::constants::math::PI); + float dEta = track.eta() - randomConeEta; + if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePt += track.pt(); + } + } + } + } + } + auto rho = collision.rho(); + std::unique_ptr rhoFit{nullptr}; + if (cfgrhoPhi) { + rhoFit = fitRho(collision, psi, tracks, jets); + if (!rhoFit) + return; + rho = evalRho(rhoFit.get(), randomConeR, randomConePhi, rho); + } + float dPhi{RecoDecay::constrainAngle(randomConePhi - psi.psi2, -o2::constants::math::PI)}; + registry.fill(HIST("hCentRhoRandomConewoLeadingJet"), collision.centrality(), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * rho, dPhi, qPerc[0]); + + double randomConePtWithoutOneLeadJet = 0; + double randomConePtWithoutTwoLeadJet = 0; + if (jets.size() > 1) { // if there are no jets, or just one, in the acceptance (from the jetfinder cuts) then one cannot find 2 leading jets + for (auto const& track : tracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + float dPhi = RecoDecay::constrainAngle(randomNumber.Uniform(0.0, o2::constants::math::TwoPI) - randomConePhi, -o2::constants::math::PI); + float dEta = randomNumber.Uniform(trackEtaMin, trackEtaMax) - randomConeEta; + if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + if (!isTrackInJet(track, jets.iteratorAt(0))) { + randomConePtWithoutOneLeadJet += track.pt(); + if (!isTrackInJet(track, jets.iteratorAt(1))) { + randomConePtWithoutTwoLeadJet += track.pt(); + } + } + } + } + } + } + registry.fill(HIST("hCentRhoRandomConeRndTrackDirwoOneLeadingJet"), collision.centrality(), randomConePtWithoutOneLeadJet - o2::constants::math::PI * randomConeR * randomConeR * rho, dPhi, qPerc[0]); + registry.fill(HIST("hCentRhoRandomConeRndTrackDirwoTwoLeadingJet"), collision.centrality(), randomConePtWithoutTwoLeadJet - o2::constants::math::PI * randomConeR * randomConeR * rho, dPhi, qPerc[0]); + } + template + bool isTrackInJet(TTracks const& track, TJets const& jet) + { + for (auto const& constituentId : jet.tracksIds()) { + if (constituentId == track.globalIndex()) { + return true; + } + } + return false; + } + + // static constexpr std::string_view LevelJets[] = {"mcd/", "mcp/"}; + // enum JetType { MCP = 0, + // MCD = 1 + // }; + // template + template + void jetLoopMCD(const Jets& jets, const float& centrality, const float& rho) + { + float weight = 1.0; + for (const auto& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + auto pt = jet.pt(); + if (cfgbkgSubMC) { + pt = jet.pt() - (rho * jet.area()); + } + if (cfgUseMCEventWeights) { + weight = jet.eventWeight(); + } + registry.fill(/*HIST(LevelJets[jetLvl]) +*/ HIST("mcd/hJetSparse"), centrality, pt, jet.eta(), jet.phi(), weight); /* detector level mcm*/ + } + } + + template + void jetLoopMCP(const Jets& jets, const float& centrality, const float& rho) + { + bool mcLevelIsParticleLevel = true; + float weight = 1.0; + for (const auto& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet, mcLevelIsParticleLevel)) { + continue; + } + auto pt = jet.pt(); + if (cfgbkgSubMC) { + pt = jet.pt() - (rho * jet.area()); + } + if (cfgUseMCEventWeights) { + weight = jet.eventWeight(); + } + registry.fill(/*HIST(LevelJets[jetLvl]) +*/ HIST("mcp/hJetSparse"), centrality, pt, jet.eta(), jet.phi(), weight); /* detector level mcm*/ + } + } + + template + void matchedJetLoop(const Jets& jets, const float& centrality, const float& rho, const float& rho2) + { + float weight = 1.0; + for (const auto& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (jet.pt() > pTHatMaxMCD * pTHat) { + return; + } + + auto pt = jet.pt(); + if (cfgbkgSubMC) { + pt = jet.pt() - (rho * jet.area()); + } + if (cfgUseMCEventWeights) { + weight = jet.eventWeight(); + } + registry.fill(HIST("mcm/hJetSparse"), centrality, pt, jet.eta(), jet.phi(), weight); /* detector level mcm*/ + + if (jet.has_matchedJetGeo()) { + registry.fill(HIST("mcm/hDetSparseMatch"), centrality, pt, jet.eta(), jet.phi(), weight); + for (const auto& matchedJet : jet.template matchedJetGeo_as()) { + if (matchedJet.pt() > pTHatMaxMCD * pTHat) + continue; + auto matchedpt = matchedJet.pt(); + if (cfgbkgSubMC) { + matchedpt = matchedJet.pt() - (rho2 * matchedJet.area()); + } + registry.fill(HIST("mcm/hPartSparseMatch"), centrality, matchedpt, matchedJet.eta(), matchedJet.phi(), weight); + registry.fill(HIST("mcm/hMatchedJetsPtDelta"), matchedJet.pt(), jet.pt() - matchedJet.pt(), weight); + registry.fill(HIST("mcm/hMatchedJetsPhiDelta"), matchedJet.phi(), jet.phi() - matchedJet.phi(), weight); + registry.fill(HIST("mcm/hMatchedJetsEtaDelta"), matchedJet.eta(), jet.eta() - matchedJet.eta(), weight); + registry.fill(HIST("mcm/hGenMatchedJetsPtDeltadPt"), centrality, matchedpt, (pt - matchedpt) / matchedpt, weight); + registry.fill(HIST("mcm/hRecoMatchedJetsPtDeltadPt"), centrality, pt, (pt - matchedpt) / pt, weight); + registry.fill(HIST("mcm/hRespMcDMcPMatch"), centrality, pt, matchedpt, weight); + } + } + } + } + + template + bool isAcceptedJet(TJets const& jet, bool mcLevelIsParticleLevel = false) + { + if (jetAreaFractionMin > -98.0) { + if (jet.area() < jetAreaFractionMin * o2::constants::math::PI * (jet.r() / 100.0) * (jet.r() / 100.0)) { + return false; + } + } + bool checkConstituentPt = true; + bool checkConstituentMinPt = (leadingConstituentPtMin > -98.0); + bool checkConstituentMaxPt = (leadingConstituentPtMax < 9998.0); + if (!checkConstituentMinPt && !checkConstituentMaxPt) { + checkConstituentPt = false; + } + + if (checkConstituentPt) { + bool isMinLeadingConstituent = !checkConstituentMinPt; + bool isMaxLeadingConstituent = true; + + for (const auto& constituent : jet.template tracks_as()) { + double pt = constituent.pt(); + + if ((!checkLeadConstituentMinPtForMcpJets && mcLevelIsParticleLevel) || (checkConstituentMinPt && pt >= leadingConstituentPtMin)) { // if the jet is mcp level and checkLeadConstituentMinPtForMcpJets is true, then the pt of the leading track of that jet does not need to be below the defined leadingConstituentPtMin cut + isMinLeadingConstituent = true; + } + if (checkConstituentMaxPt && pt > leadingConstituentPtMax) { + isMaxLeadingConstituent = false; + } + } + return isMinLeadingConstituent && isMaxLeadingConstituent; + } + return true; + } +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGJE/Tasks/jetSubstructure.cxx b/PWGJE/Tasks/jetSubstructure.cxx new file mode 100644 index 00000000000..f6cd4c9dd72 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructure.cxx @@ -0,0 +1,373 @@ +// 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. + +// jet analysis tasks (subscribing to jet finder task) +// +/// \author Nima Zardoshti +// + +#include +#include + +#include "fastjet/PseudoJet.hh" +#include "fastjet/ClusterSequenceArea.hh" + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/Core/JetSubstructureUtilities.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +#include "Framework/runDataProcessing.h" + +struct JetSubstructureTask { + Produces jetSubstructureDataTable; + Produces jetSubstructureMCDTable; + Produces jetSubstructureMCPTable; + Produces jetSubstructureDataSubTable; + + Produces jetSplittingsDataTable; + Produces jetSplittingsMCDTable; + Produces jetSplittingsMCPTable; + Produces jetSplittingsDataSubTable; + + Produces jetPairsDataTable; + Produces jetPairsMCDTable; + Produces jetPairsMCPTable; + Produces jetPairsDataSubTable; + + Configurable zCut{"zCut", 0.1, "soft drop z cut"}; + Configurable beta{"beta", 0.0, "soft drop beta"}; + Configurable kappa{"kappa", 1.0, "angularity kappa"}; + Configurable alpha{"alpha", 1.0, "angularity alpha"}; + Configurable doPairBkg{"doPairBkg", true, "save bkg pairs"}; + Configurable pairConstituentPtMin{"pairConstituentPtMin", 1.0, "pt cut off for constituents going into pairs"}; + + Service pdg; + std::vector jetConstituents; + std::vector jetReclustered; + JetFinder jetReclusterer; + + std::vector energyMotherVec; + std::vector ptLeadingVec; + std::vector ptSubLeadingVec; + std::vector thetaVec; + std::vector nSub; + std::vector pairJetPtVec; + std::vector pairJetEnergyVec; + std::vector pairJetThetaVec; + std::vector pairJetPerpCone1PtVec; + std::vector pairJetPerpCone1EnergyVec; + std::vector pairJetPerpCone1ThetaVec; + std::vector pairPerpCone1PerpCone1PtVec; + std::vector pairPerpCone1PerpCone1EnergyVec; + std::vector pairPerpCone1PerpCone1ThetaVec; + std::vector pairPerpCone1PerpCone2PtVec; + std::vector pairPerpCone1PerpCone2EnergyVec; + std::vector pairPerpCone1PerpCone2ThetaVec; + float angularity; + float leadingConstituentPt; + float perpConeRho; + + HistogramRegistry registry; + + void init(InitContext const&) + { + registry.add("h2_jet_pt_jet_zg", ";#it{p}_{T,jet} (GeV/#it{c});#it{z}_{g}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); + registry.add("h2_jet_pt_jet_rg", ";#it{p}_{T,jet} (GeV/#it{c});#it{R}_{g}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); + registry.add("h2_jet_pt_jet_nsd", ";#it{p}_{T,jet} (GeV/#it{c});#it{n}_{SD}", {HistType::kTH2F, {{200, 0., 200.}, {15, -0.5, 14.5}}}); + + registry.add("h2_jet_pt_part_jet_zg_part", ";#it{p}_{T,jet}^{part} (GeV/#it{c});#it{z}_{g}^{part}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); + registry.add("h2_jet_pt_part_jet_rg_part", ";#it{p}_{T,jet}^{part} (GeV/#it{c});#it{R}_{g}^{part}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); + registry.add("h2_jet_pt_part_jet_nsd_part", ";#it{p}_{T,jet}^{part} (GeV/#it{c});#it{n}_{SD}^{part}", {HistType::kTH2F, {{200, 0., 200.}, {15, -0.5, 14.5}}}); + + registry.add("h2_jet_pt_jet_zg_eventwiseconstituentsubtracted", ";#it{p}_{T,jet} (GeV/#it{c});#it{z}_{g}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); + registry.add("h2_jet_pt_jet_rg_eventwiseconstituentsubtracted", ";#it{p}_{T,jet} (GeV/#it{c});#it{R}_{g}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); + registry.add("h2_jet_pt_jet_nsd_eventwiseconstituentsubtracted", ";#it{p}_{T,jet} (GeV/#it{c});#it{n}_{SD}", {HistType::kTH2F, {{200, 0., 200.}, {15, -0.5, 14.5}}}); + + jetReclusterer.isReclustering = true; + jetReclusterer.algorithm = fastjet::JetAlgorithm::cambridge_algorithm; + } + + Preslice TracksPerCollision = aod::jtrack::collisionId; + Preslice TracksPerCollisionDataSub = aod::bkgcharged::collisionId; + Preslice ParticlesPerMcCollision = aod::jmcparticle::mcCollisionId; + + template + void jetReclustering(T const& jet, U& splittingTable) + { + energyMotherVec.clear(); + ptLeadingVec.clear(); + ptSubLeadingVec.clear(); + thetaVec.clear(); + jetReclustered.clear(); + fastjet::ClusterSequenceArea clusterSeq(jetReclusterer.findJets(jetConstituents, jetReclustered)); + jetReclustered = sorted_by_pt(jetReclustered); + fastjet::PseudoJet daughterSubJet = jetReclustered[0]; + fastjet::PseudoJet parentSubJet1; + fastjet::PseudoJet parentSubJet2; + bool softDropped = false; + auto nsd = 0.0; + auto zg = -1.0; + auto rg = -1.0; + + while (daughterSubJet.has_parents(parentSubJet1, parentSubJet2)) { + if (parentSubJet1.perp() < parentSubJet2.perp()) { + std::swap(parentSubJet1, parentSubJet2); + } + std::vector tracks; + std::vector candidates; + std::vector clusters; + for (const auto& constituent : sorted_by_pt(parentSubJet2.constituents())) { + if (constituent.template user_info().getStatus() == static_cast(JetConstituentStatus::track)) { + tracks.push_back(constituent.template user_info().getIndex()); + } + } + splittingTable(jet.globalIndex(), tracks, clusters, candidates, parentSubJet2.perp(), parentSubJet2.eta(), parentSubJet2.phi(), 0); + auto z = parentSubJet2.perp() / (parentSubJet1.perp() + parentSubJet2.perp()); + auto theta = parentSubJet1.delta_R(parentSubJet2); + energyMotherVec.push_back(daughterSubJet.e()); + ptLeadingVec.push_back(parentSubJet1.pt()); + ptSubLeadingVec.push_back(parentSubJet2.pt()); + thetaVec.push_back(theta); + + if (z >= zCut * TMath::Power(theta / (jet.r() / 100.f), beta)) { + if (!softDropped) { + zg = z; + rg = theta; + if constexpr (!isSubtracted && !isMCP) { + registry.fill(HIST("h2_jet_pt_jet_zg"), jet.pt(), zg); + registry.fill(HIST("h2_jet_pt_jet_rg"), jet.pt(), rg); + } + if constexpr (!isSubtracted && isMCP) { + registry.fill(HIST("h2_jet_pt_part_jet_zg_part"), jet.pt(), zg); + registry.fill(HIST("h2_jet_pt_part_jet_rg_part"), jet.pt(), rg); + } + if constexpr (isSubtracted && !isMCP) { + registry.fill(HIST("h2_jet_pt_jet_zg_eventwiseconstituentsubtracted"), jet.pt(), zg); + registry.fill(HIST("h2_jet_pt_jet_rg_eventwiseconstituentsubtracted"), jet.pt(), rg); + } + softDropped = true; + } + nsd++; + } + daughterSubJet = parentSubJet1; + } + if constexpr (!isSubtracted && !isMCP) { + registry.fill(HIST("h2_jet_pt_jet_nsd"), jet.pt(), nsd); + } + if constexpr (!isSubtracted && isMCP) { + registry.fill(HIST("h2_jet_pt_part_jet_nsd_part"), jet.pt(), nsd); + } + if constexpr (isSubtracted && !isMCP) { + registry.fill(HIST("h2_jet_pt_jet_nsd_eventwiseconstituentsubtracted"), jet.pt(), nsd); + } + } + + template + void jetPairing(T const& jet, U const& tracks, V const& slicer, M& pairTable) + { + pairJetPtVec.clear(); + pairJetEnergyVec.clear(); + pairJetThetaVec.clear(); + std::vector tracksVec; + std::vector tracksVecIds; + for (auto const& constituent : jet.template tracks_as()) { + if (constituent.pt() >= pairConstituentPtMin) { + tracksVec.push_back(constituent); + tracksVecIds.push_back(constituent.globalIndex()); + } + } + if (tracksVec.size() >= 1) { + for (typename std::vector::size_type track1Index = 0; track1Index < tracksVec.size(); track1Index++) { + for (typename std::vector::size_type track2Index = track1Index + 1; track2Index < tracksVec.size(); track2Index++) { + pairJetPtVec.push_back(tracksVec.at(track1Index).pt() * tracksVec.at(track2Index).pt()); + pairJetEnergyVec.push_back(2.0 * tracksVec.at(track1Index).energy() * tracksVec.at(track2Index).energy()); + pairJetThetaVec.push_back(jetutilities::deltaR(tracksVec.at(track1Index), tracksVec.at(track2Index))); + pairTable(jet.globalIndex(), tracksVecIds.at(track1Index), tracksVecIds.at(track2Index), -1, -1); + } + } + } + + pairJetPerpCone1PtVec.clear(); + pairJetPerpCone1EnergyVec.clear(); + pairJetPerpCone1ThetaVec.clear(); + pairPerpCone1PerpCone1PtVec.clear(); + pairPerpCone1PerpCone1EnergyVec.clear(); + pairPerpCone1PerpCone1ThetaVec.clear(); + pairPerpCone1PerpCone2PtVec.clear(); + pairPerpCone1PerpCone2EnergyVec.clear(); + pairPerpCone1PerpCone2ThetaVec.clear(); + + int32_t collisionId = -1; + if constexpr (!isMC) { + collisionId = jet.collisionId(); + } else { + collisionId = jet.mcCollisionId(); + } + auto tracksPerCollision = tracks.sliceBy(slicer, collisionId); + + float perpCone1Phi = RecoDecay::constrainAngle(jet.phi() + (M_PI / 2.)); + float perpCone2Phi = RecoDecay::constrainAngle(jet.phi() - (M_PI / 2.)); + float perpCone1Pt = 0.0; + float perpCone2Pt = 0.0; + std::vector tracksPerpCone1Vec; + std::vector tracksPerpCone2Vec; + for (auto const& track : tracksPerCollision) { + float deltaPhi1 = track.phi() - perpCone1Phi; + deltaPhi1 = RecoDecay::constrainAngle(deltaPhi1, -M_PI); + float deltaPhi2 = track.phi() - perpCone2Phi; + deltaPhi2 = RecoDecay::constrainAngle(deltaPhi2, -M_PI); + float deltaEta = jet.eta() - track.eta(); + + if (TMath::Sqrt((deltaPhi1 * deltaPhi1) + (deltaEta * deltaEta)) <= jet.r() / 100.0) { + if (track.pt() >= pairConstituentPtMin) { + tracksPerpCone1Vec.push_back(track); + } + perpCone1Pt += track.pt(); + } + if (TMath::Sqrt((deltaPhi2 * deltaPhi2) + (deltaEta * deltaEta)) <= jet.r() / 100.0) { + if (track.pt() >= pairConstituentPtMin) { + tracksPerpCone2Vec.push_back(track); + } + perpCone2Pt += track.pt(); + } + } + perpConeRho = (perpCone1Pt + perpCone2Pt) / (2 * M_PI * (jet.r() / 100.0) * (jet.r() / 100.0)); // currently done per jet - could be better to do for leading jet if pushing to very low pT + if (doPairBkg) { + if (tracksVec.size() >= 1 && tracksPerpCone1Vec.size() >= 1) { + for (typename std::vector::size_type track1Index = 0; track1Index < tracksVec.size(); track1Index++) { + for (typename std::vector::size_type track2Index = 0; track2Index < tracksPerpCone1Vec.size(); track2Index++) { + pairJetPerpCone1PtVec.push_back(tracksVec.at(track1Index).pt() * tracksPerpCone1Vec.at(track2Index).pt()); + pairJetPerpCone1EnergyVec.push_back(2.0 * tracksVec.at(track1Index).energy() * tracksPerpCone1Vec.at(track2Index).energy()); + float dPhi = RecoDecay::constrainAngle(tracksVec.at(track1Index).phi() - (tracksPerpCone1Vec.at(track2Index).phi() - (M_PI / 2.)), -M_PI); + float dEta = tracksVec.at(track1Index).eta() - tracksPerpCone1Vec.at(track2Index).eta(); + pairJetPerpCone1ThetaVec.push_back(std::sqrt(dEta * dEta + dPhi * dPhi)); + } + } + } + + if (tracksPerpCone1Vec.size() >= 1) { + for (typename std::vector::size_type track1Index = 0; track1Index < tracksPerpCone1Vec.size(); track1Index++) { + for (typename std::vector::size_type track2Index = track1Index + 1; track2Index < tracksPerpCone1Vec.size(); track2Index++) { + pairPerpCone1PerpCone1PtVec.push_back(tracksPerpCone1Vec.at(track1Index).pt() * tracksPerpCone1Vec.at(track2Index).pt()); + pairPerpCone1PerpCone1EnergyVec.push_back(2.0 * tracksPerpCone1Vec.at(track1Index).energy() * tracksPerpCone1Vec.at(track2Index).energy()); + pairPerpCone1PerpCone1ThetaVec.push_back(jetutilities::deltaR(tracksPerpCone1Vec.at(track1Index), tracksPerpCone1Vec.at(track2Index))); + } + } + } + + if (tracksPerpCone1Vec.size() >= 1 && tracksPerpCone2Vec.size() >= 1) { + for (typename std::vector::size_type track1Index = 0; track1Index < tracksPerpCone1Vec.size(); track1Index++) { + for (typename std::vector::size_type track2Index = 0; track2Index < tracksPerpCone2Vec.size(); track2Index++) { + pairPerpCone1PerpCone2PtVec.push_back(tracksPerpCone1Vec.at(track1Index).pt() * tracksPerpCone2Vec.at(track2Index).pt()); + pairPerpCone1PerpCone2EnergyVec.push_back(2.0 * tracksPerpCone1Vec.at(track1Index).energy() * tracksPerpCone2Vec.at(track2Index).energy()); + float dPhi = RecoDecay::constrainAngle((tracksPerpCone1Vec.at(track1Index).phi() - (M_PI / 2.)) - (tracksPerpCone2Vec.at(track2Index).phi() + (M_PI / 2.)), -M_PI); + float dEta = tracksPerpCone1Vec.at(track1Index).eta() - tracksPerpCone2Vec.at(track2Index).eta(); + pairPerpCone1PerpCone2ThetaVec.push_back(std::sqrt(dEta * dEta + dPhi * dPhi)); + } + } + } + } + } + + template + void jetSubstructureSimple(T const& jet, U const& /*tracks*/) + { + angularity = 0.0; + leadingConstituentPt = 0.0; + for (auto& constituent : jet.template tracks_as()) { + if (constituent.pt() >= leadingConstituentPt) { + leadingConstituentPt = constituent.pt(); + } + angularity += std::pow(constituent.pt(), kappa) * std::pow(jetutilities::deltaR(jet, constituent), alpha); + } + angularity /= (jet.pt() * (jet.r() / 100.f)); + } + + template + void analyseCharged(T const& jet, U const& tracks, V const& trackSlicer, M& outputTable, N& splittingTable, O& pairTable) + { + jetConstituents.clear(); + for (auto& jetConstituent : jet.template tracks_as()) { + fastjetutilities::fillTracks(jetConstituent, jetConstituents, jetConstituent.globalIndex()); + } + nSub = jetsubstructureutilities::getNSubjettiness(jet, tracks, tracks, tracks, 2, fastjet::contrib::CA_Axes(), true, zCut, beta); + jetReclustering(jet, splittingTable); + jetPairing(jet, tracks, trackSlicer, pairTable); + jetSubstructureSimple(jet, tracks); + outputTable(energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec, nSub[0], nSub[1], nSub[2], pairJetPtVec, pairJetEnergyVec, pairJetThetaVec, pairJetPerpCone1PtVec, pairJetPerpCone1EnergyVec, pairJetPerpCone1ThetaVec, pairPerpCone1PerpCone1PtVec, pairPerpCone1PerpCone1EnergyVec, pairPerpCone1PerpCone1ThetaVec, pairPerpCone1PerpCone2PtVec, pairPerpCone1PerpCone2EnergyVec, pairPerpCone1PerpCone2ThetaVec, angularity, leadingConstituentPt, perpConeRho); + } + + void processDummy(aod::JetTracks const&) + { + } + PROCESS_SWITCH(JetSubstructureTask, processDummy, "Dummy process function turned on by default", true); + + void processChargedJetsData(soa::Join::iterator const& jet, + aod::JetTracks const& tracks) + { + analyseCharged(jet, tracks, TracksPerCollision, jetSubstructureDataTable, jetSplittingsDataTable, jetPairsDataTable); + } + PROCESS_SWITCH(JetSubstructureTask, processChargedJetsData, "charged jet substructure", false); + + void processChargedJetsEventWiseSubData(soa::Join::iterator const& jet, + aod::JetTracksSub const& tracks) + { + analyseCharged(jet, tracks, TracksPerCollisionDataSub, jetSubstructureDataSubTable, jetSplittingsDataSubTable, jetPairsDataSubTable); + } + PROCESS_SWITCH(JetSubstructureTask, processChargedJetsEventWiseSubData, "eventwise-constituent subtracted charged jet substructure", false); + + void processChargedJetsMCD(typename soa::Join::iterator const& jet, + aod::JetTracks const& tracks) + { + analyseCharged(jet, tracks, TracksPerCollision, jetSubstructureMCDTable, jetSplittingsMCDTable, jetPairsMCDTable); + } + PROCESS_SWITCH(JetSubstructureTask, processChargedJetsMCD, "charged jet substructure", false); + + void processChargedJetsMCP(typename soa::Join::iterator const& jet, + aod::JetParticles const& particles) + { + jetConstituents.clear(); + for (auto& jetConstituent : jet.template tracks_as()) { + fastjetutilities::fillTracks(jetConstituent, jetConstituents, jetConstituent.globalIndex(), static_cast(JetConstituentStatus::track), pdg->Mass(jetConstituent.pdgCode())); + } + nSub = jetsubstructureutilities::getNSubjettiness(jet, particles, particles, particles, 2, fastjet::contrib::CA_Axes(), true, zCut, beta); + jetReclustering(jet, jetSplittingsMCPTable); + jetPairing(jet, particles, ParticlesPerMcCollision, jetPairsMCPTable); + jetSubstructureSimple(jet, particles); + jetSubstructureMCPTable(energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec, nSub[0], nSub[1], nSub[2], pairJetPtVec, pairJetEnergyVec, pairJetThetaVec, pairJetPerpCone1PtVec, pairJetPerpCone1EnergyVec, pairJetPerpCone1ThetaVec, pairPerpCone1PerpCone1PtVec, pairPerpCone1PerpCone1EnergyVec, pairPerpCone1PerpCone1ThetaVec, pairPerpCone1PerpCone2PtVec, pairPerpCone1PerpCone2EnergyVec, pairPerpCone1PerpCone2ThetaVec, angularity, leadingConstituentPt, perpConeRho); + } + PROCESS_SWITCH(JetSubstructureTask, processChargedJetsMCP, "charged jet substructure on MC particle level", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + + return WorkflowSpec{adaptAnalysisTask( + cfgc, TaskName{"jet-substructure"})}; +} diff --git a/PWGJE/Tasks/jetSubstructureBplus.cxx b/PWGJE/Tasks/jetSubstructureBplus.cxx new file mode 100644 index 00000000000..2d6d60f3d5a --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureBplus.cxx @@ -0,0 +1,28 @@ +// 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. + +// jet substructure B+ charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/Tasks/jetSubstructureHF.cxx" + +using JetSubstructureBplus = JetSubstructureHFTask, soa::Join, soa::Join, soa::Join, aod::CandidatesBplusData, aod::CandidatesBplusMCP, aod::BplusCJetSSs, aod::BplusChargedSPs, aod::BplusChargedPRs, aod::BplusCMCDJetSSs, aod::BplusChargedMCDetectorLevelSPs, aod::BplusChargedMCDetectorLevelPRs, aod::BplusCMCPJetSSs, aod::BplusChargedMCParticleLevelSPs, aod::BplusChargedMCParticleLevelPRs, aod::BplusCEWSJetSSs, aod::BplusChargedEventWiseSubtractedSPs, aod::BplusChargedEventWiseSubtractedPRs, aod::JTrackBplusSubs>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-substructure-bplus"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetSubstructureBplusOutput.cxx b/PWGJE/Tasks/jetSubstructureBplusOutput.cxx new file mode 100644 index 00000000000..fec4c2a27ec --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureBplusOutput.cxx @@ -0,0 +1,27 @@ +// 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. + +// jet substructure output B+ charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/Tasks/jetSubstructureHFOutput.cxx" + +using JetSubstructureOutputBplus = JetSubstructureHFOutputTask, aod::McCollisionsBplus, aod::CandidatesBplusData, aod::CandidatesBplusMCD, aod::CandidatesBplusMCP, aod::BkgBplusRhos, aod::BkgBplusMcRhos, aod::JTrackBplusSubs, soa::Join, soa::Join, soa::Join, soa::Join, aod::BplusCJetCOs, aod::BplusCJetOs, aod::BplusCJetSSOs, aod::BplusCJetMOs, soa::Join, soa::Join, soa::Join, aod::BplusCMCDJetCOs, aod::BplusCMCDJetOs, aod::BplusCMCDJetSSOs, aod::BplusCMCDJetMOs, soa::Join, soa::Join, soa::Join, soa::Join, aod::BplusCMCPJetCOs, aod::BplusCMCPJetMCCOs, aod::BplusCMCPJetOs, aod::BplusCMCPJetSSOs, aod::BplusCMCPJetMOs, soa::Join, soa::Join, soa::Join, aod::BplusCEWSJetCOs, aod::BplusCEWSJetOs, aod::BplusCEWSJetSSOs, aod::BplusCEWSJetMOs, aod::StoredHfBplusCollBase, aod::StoredHfBplusBases, aod::StoredHfBplusPars, aod::StoredHfBplusParEs, aod::StoredHfBplusParD0s, aod::StoredHfBplusSels, aod::StoredHfBplusMls, aod::StoredHfBplusMlD0s, aod::StoredHfBplusMcs, aod::StoredHfBplusMcCollBases, aod::StoredHfBplusMcRCollIds, aod::StoredHfBplusPBases>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-substructure-bplus-output"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetSubstructureD0.cxx b/PWGJE/Tasks/jetSubstructureD0.cxx new file mode 100644 index 00000000000..593c5294a9c --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureD0.cxx @@ -0,0 +1,28 @@ +// 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. + +// jet substructure D0 charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/Tasks/jetSubstructureHF.cxx" + +using JetSubstructureD0 = JetSubstructureHFTask, soa::Join, soa::Join, soa::Join, aod::CandidatesD0Data, aod::CandidatesD0MCP, aod::D0CJetSSs, aod::D0ChargedSPs, aod::D0ChargedPRs, aod::D0CMCDJetSSs, aod::D0ChargedMCDetectorLevelSPs, aod::D0ChargedMCDetectorLevelPRs, aod::D0CMCPJetSSs, aod::D0ChargedMCParticleLevelSPs, aod::D0ChargedMCParticleLevelPRs, aod::D0CEWSJetSSs, aod::D0ChargedEventWiseSubtractedSPs, aod::D0ChargedEventWiseSubtractedPRs, aod::JTrackD0Subs>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-substructure-d0"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetSubstructureD0Output.cxx b/PWGJE/Tasks/jetSubstructureD0Output.cxx new file mode 100644 index 00000000000..43b909a3688 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureD0Output.cxx @@ -0,0 +1,27 @@ +// 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. + +// jet substructure output D0 charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/Tasks/jetSubstructureHFOutput.cxx" + +using JetSubstructureOutputD0 = JetSubstructureHFOutputTask, aod::McCollisionsD0, aod::CandidatesD0Data, aod::CandidatesD0MCD, aod::CandidatesD0MCP, aod::BkgD0Rhos, aod::BkgD0McRhos, aod::JTrackD0Subs, soa::Join, soa::Join, soa::Join, soa::Join, aod::D0CJetCOs, aod::D0CJetOs, aod::D0CJetSSOs, aod::D0CJetMOs, soa::Join, soa::Join, soa::Join, aod::D0CMCDJetCOs, aod::D0CMCDJetOs, aod::D0CMCDJetSSOs, aod::D0CMCDJetMOs, soa::Join, soa::Join, soa::Join, soa::Join, aod::D0CMCPJetCOs, aod::D0CMCPJetMCCOs, aod::D0CMCPJetOs, aod::D0CMCPJetSSOs, aod::D0CMCPJetMOs, soa::Join, soa::Join, soa::Join, aod::D0CEWSJetCOs, aod::D0CEWSJetOs, aod::D0CEWSJetSSOs, aod::D0CEWSJetMOs, aod::StoredHfD0CollBase, aod::StoredHfD0Bases, aod::StoredHfD0Pars, aod::StoredHfD0ParEs, aod::JDumD0ParDaus, aod::StoredHfD0Sels, aod::StoredHfD0Mls, aod::JDumD0MlDaus, aod::StoredHfD0Mcs, aod::StoredHfD0McCollBases, aod::StoredHfD0McRCollIds, aod::StoredHfD0PBases>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-substructure-d0-output"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetSubstructureDielectron.cxx b/PWGJE/Tasks/jetSubstructureDielectron.cxx new file mode 100644 index 00000000000..665d0f2f636 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureDielectron.cxx @@ -0,0 +1,28 @@ +// 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. + +// jet substructure Dielectron charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/Tasks/jetSubstructureHF.cxx" + +using JetSubstructureDielectron = JetSubstructureHFTask, soa::Join, soa::Join, soa::Join, aod::CandidatesDielectronData, aod::CandidatesDielectronMCP, aod::DielectronCJetSSs, aod::DielectronChargedSPs, aod::DielectronChargedPRs, aod::DielectronCMCDJetSSs, aod::DielectronChargedMCDetectorLevelSPs, aod::DielectronChargedMCDetectorLevelPRs, aod::DielectronCMCPJetSSs, aod::DielectronChargedMCParticleLevelSPs, aod::DielectronChargedMCParticleLevelPRs, aod::DielectronCEWSJetSSs, aod::DielectronChargedEventWiseSubtractedSPs, aod::DielectronChargedEventWiseSubtractedPRs, aod::JTrackDielectronSubs>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-substructure-dielectron"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetSubstructureDielectronOutput.cxx b/PWGJE/Tasks/jetSubstructureDielectronOutput.cxx new file mode 100644 index 00000000000..8c8d7a8980d --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureDielectronOutput.cxx @@ -0,0 +1,27 @@ +// 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. + +// jet substructure output Dielectron charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/Tasks/jetSubstructureHFOutput.cxx" + +using JetSubstructureOutputDielectron = JetSubstructureHFOutputTask, aod::McCollisionsDielectron, aod::CandidatesDielectronData, aod::CandidatesDielectronMCD, aod::CandidatesDielectronMCP, aod::BkgDielectronRhos, aod::BkgDielectronMcRhos, aod::JTrackDielectronSubs, soa::Join, soa::Join, soa::Join, soa::Join, aod::DielectronCJetCOs, aod::DielectronCJetOs, aod::DielectronCJetSSOs, aod::DielectronCJetMOs, soa::Join, soa::Join, soa::Join, aod::DielectronCMCDJetCOs, aod::DielectronCMCDJetOs, aod::DielectronCMCDJetSSOs, aod::DielectronCMCDJetMOs, soa::Join, soa::Join, soa::Join, soa::Join, aod::DielectronCMCPJetCOs, aod::DielectronCMCPJetMCCOs, aod::DielectronCMCPJetOs, aod::DielectronCMCPJetSSOs, aod::DielectronCMCPJetMOs, soa::Join, soa::Join, soa::Join, aod::DielectronCEWSJetCOs, aod::DielectronCEWSJetOs, aod::DielectronCEWSJetSSOs, aod::DielectronCEWSJetMOs, aod::StoredReducedEvents, aod::StoredDielectrons, aod::JDielectron1Dummys, aod::JDielectron2Dummys, aod::JDielectron3Dummys, aod::JDielectron4Dummys, aod::JDielectron5Dummys, aod::JDielectron6Dummys, aod::JDielectron7Dummys, aod::StoredJDielectronMcCollisions, aod::JDielectronMcRCollDummys, aod::StoredJDielectronMcs>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-substructure-dielectron-output"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetSubstructureDplus.cxx b/PWGJE/Tasks/jetSubstructureDplus.cxx new file mode 100644 index 00000000000..1aee6336c8d --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureDplus.cxx @@ -0,0 +1,28 @@ +// 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. + +// jet substructure D+ charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/Tasks/jetSubstructureHF.cxx" + +using JetSubstructureDplus = JetSubstructureHFTask, soa::Join, soa::Join, soa::Join, aod::CandidatesDplusData, aod::CandidatesDplusMCP, aod::DplusCJetSSs, aod::DplusChargedSPs, aod::DplusChargedPRs, aod::DplusCMCDJetSSs, aod::DplusChargedMCDetectorLevelSPs, aod::DplusChargedMCDetectorLevelPRs, aod::DplusCMCPJetSSs, aod::DplusChargedMCParticleLevelSPs, aod::DplusChargedMCParticleLevelPRs, aod::DplusCEWSJetSSs, aod::DplusChargedEventWiseSubtractedSPs, aod::DplusChargedEventWiseSubtractedPRs, aod::JTrackDplusSubs>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-substructure-dplus"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetSubstructureDplusOutput.cxx b/PWGJE/Tasks/jetSubstructureDplusOutput.cxx new file mode 100644 index 00000000000..e45dfc5833c --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureDplusOutput.cxx @@ -0,0 +1,27 @@ +// 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. + +// jet substructure output D+ charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/Tasks/jetSubstructureHFOutput.cxx" + +using JetSubstructureOutputDplus = JetSubstructureHFOutputTask, aod::McCollisionsDplus, aod::CandidatesDplusData, aod::CandidatesDplusMCD, aod::CandidatesDplusMCP, aod::BkgDplusRhos, aod::BkgDplusMcRhos, aod::JTrackDplusSubs, soa::Join, soa::Join, soa::Join, soa::Join, aod::DplusCJetCOs, aod::DplusCJetOs, aod::DplusCJetSSOs, aod::DplusCJetMOs, soa::Join, soa::Join, soa::Join, aod::DplusCMCDJetCOs, aod::DplusCMCDJetOs, aod::DplusCMCDJetSSOs, aod::DplusCMCDJetMOs, soa::Join, soa::Join, soa::Join, soa::Join, aod::DplusCMCPJetCOs, aod::DplusCMCPJetMCCOs, aod::DplusCMCPJetOs, aod::DplusCMCPJetSSOs, aod::DplusCMCPJetMOs, soa::Join, soa::Join, soa::Join, aod::DplusCEWSJetCOs, aod::DplusCEWSJetOs, aod::DplusCEWSJetSSOs, aod::DplusCEWSJetMOs, aod::StoredHfDplusCollBase, aod::StoredHfDplusBases, aod::StoredHfDplusPars, aod::StoredHfDplusParEs, aod::JDumDplusParDaus, aod::StoredHfDplusSels, aod::StoredHfDplusMls, aod::JDumDplusMlDaus, aod::StoredHfDplusMcs, aod::StoredHfDplusMcCollBases, aod::StoredHfDplusMcRCollIds, aod::StoredHfDplusPBases>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-substructure-dplus-output"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetSubstructureHF.cxx b/PWGJE/Tasks/jetSubstructureHF.cxx new file mode 100644 index 00000000000..3cbdbf6fd34 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureHF.cxx @@ -0,0 +1,463 @@ +// 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. + +// heavy-flavour jet substructure task (subscribing to jet finder hf task) +// +/// \author Nima Zardoshti +// + +#include +#include + +#include "fastjet/PseudoJet.hh" +#include "fastjet/ClusterSequenceArea.hh" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/Core/JetHFUtilities.h" +#include "PWGJE/Core/JetDQUtilities.h" +#include "PWGJE/Core/JetSubstructureUtilities.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// NB: runDataProcessing.h must be included after customize! +#include "Framework/runDataProcessing.h" + +template +struct JetSubstructureHFTask { + Produces jetSubstructureDataTable; + Produces jetSubstructureMCDTable; + Produces jetSubstructureMCPTable; + Produces jetSubstructureDataSubTable; + + Produces jetSplittingsDataTable; + Produces jetSplittingsMCDTable; + Produces jetSplittingsMCPTable; + Produces jetSplittingsDataSubTable; + + Produces jetPairsDataTable; + Produces jetPairsMCDTable; + Produces jetPairsMCPTable; + Produces jetPairsDataSubTable; + + // Jet level configurables + Configurable zCut{"zCut", 0.1, "soft drop z cut"}; + Configurable beta{"beta", 0.0, "soft drop beta"}; + Configurable kappa{"kappa", 1.0, "angularity kappa"}; + Configurable alpha{"alpha", 1.0, "angularity alpha"}; + Configurable doPairBkg{"doPairBkg", true, "save bkg pairs"}; + Configurable pairConstituentPtMin{"pairConstituentPtMin", 1.0, "pt cut off for constituents going into pairs"}; + + Service pdg; + float candMass; + + std::vector jetConstituents; + std::vector jetReclustered; + JetFinder jetReclusterer; + + std::vector energyMotherVec; + std::vector ptLeadingVec; + std::vector ptSubLeadingVec; + std::vector thetaVec; + std::vector nSub; + std::vector pairJetPtVec; + std::vector pairJetEnergyVec; + std::vector pairJetThetaVec; + std::vector pairJetPerpCone1PtVec; + std::vector pairJetPerpCone1EnergyVec; + std::vector pairJetPerpCone1ThetaVec; + std::vector pairPerpCone1PerpCone1PtVec; + std::vector pairPerpCone1PerpCone1EnergyVec; + std::vector pairPerpCone1PerpCone1ThetaVec; + std::vector pairPerpCone1PerpCone2PtVec; + std::vector pairPerpCone1PerpCone2EnergyVec; + std::vector pairPerpCone1PerpCone2ThetaVec; + float angularity; + float leadingConstituentPt; + float perpConeRho; + + HistogramRegistry registry; + void init(InitContext const&) + { + registry.add("h2_jet_pt_jet_zg", ";#it{p}_{T,jet} (GeV/#it{c});#it{z}_{g}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); + registry.add("h2_jet_pt_jet_rg", ";#it{p}_{T,jet} (GeV/#it{c});#it{R}_{g}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); + registry.add("h2_jet_pt_jet_nsd", ";#it{p}_{T,jet} (GeV/#it{c});#it{n}_{SD}", {HistType::kTH2F, {{200, 0., 200.}, {15, -0.5, 14.5}}}); + + registry.add("h2_jet_pt_part_jet_zg_part", ";#it{p}_{T,jet}^{part} (GeV/#it{c});#it{z}_{g}^{part}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); + registry.add("h2_jet_pt_part_jet_rg_part", ";#it{p}_{T,jet}^{part} (GeV/#it{c});#it{R}_{g}^{part}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); + registry.add("h2_jet_pt_part_jet_nsd_part", ";#it{p}_{T,jet}^{part} (GeV/#it{c});#it{n}_{SD}^{part}", {HistType::kTH2F, {{200, 0., 200.}, {15, -0.5, 14.5}}}); + + registry.add("h2_jet_pt_jet_zg_eventwiseconstituentsubtracted", ";#it{p}_{T,jet} (GeV/#it{c});#it{z}_{g}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); + registry.add("h2_jet_pt_jet_rg_eventwiseconstituentsubtracted", ";#it{p}_{T,jet} (GeV/#it{c});#it{R}_{g}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); + registry.add("h2_jet_pt_jet_nsd_eventwiseconstituentsubtracted", ";#it{p}_{T,jet} (GeV/#it{c});#it{n}_{SD}", {HistType::kTH2F, {{200, 0., 200.}, {15, -0.5, 14.5}}}); + + jetReclusterer.isReclustering = true; + jetReclusterer.algorithm = fastjet::JetAlgorithm::cambridge_algorithm; + + candMass = jetcandidateutilities::getTablePDGMass(); + } + + Preslice TracksPerCollision = aod::jtrack::collisionId; + PresliceOptional TracksPerD0DataSub = aod::bkgd0::candidateId; + PresliceOptional TracksPerDplusDataSub = aod::bkgdplus::candidateId; + PresliceOptional TracksPerLcDataSub = aod::bkglc::candidateId; + PresliceOptional TracksPerBplusDataSub = aod::bkgbplus::candidateId; + PresliceOptional TracksPerDielectronDataSub = aod::bkgdielectron::candidateId; + Preslice ParticlesPerMcCollision = aod::jmcparticle::mcCollisionId; + + template + auto selectSlicer(T const& D0Slicer, U const& DplusSlicer, V const& LcSlicer, M const& BplusSlicer, N const& DielectronSlicer) + { + if constexpr (jethfutilities::isD0Table()) { + return D0Slicer; + } else if constexpr (jethfutilities::isDplusTable()) { + return DplusSlicer; + } else if constexpr (jethfutilities::isLcTable()) { + return LcSlicer; + } else if constexpr (jethfutilities::isBplusTable()) { + return BplusSlicer; + } else if constexpr (jetdqutilities::isDielectronTable()) { + return DielectronSlicer; + } else { + return D0Slicer; + } + } + + template + void jetReclustering(T const& jet, U& splittingTable) + { + energyMotherVec.clear(); + ptLeadingVec.clear(); + ptSubLeadingVec.clear(); + thetaVec.clear(); + jetReclustered.clear(); + fastjet::ClusterSequenceArea clusterSeq(jetReclusterer.findJets(jetConstituents, jetReclustered)); + jetReclustered = sorted_by_pt(jetReclustered); + fastjet::PseudoJet daughterSubJet = jetReclustered[0]; + fastjet::PseudoJet parentSubJet1; + fastjet::PseudoJet parentSubJet2; + bool softDropped = false; + auto nsd = 0.0; + auto zg = -1.0; + auto rg = -1.0; + while (daughterSubJet.has_parents(parentSubJet1, parentSubJet2)) { + + bool isHFInSubjet1 = false; + for (auto& subjet1Constituent : parentSubJet1.constituents()) { + if (subjet1Constituent.template user_info().getStatus() == static_cast(JetConstituentStatus::candidate)) { + isHFInSubjet1 = true; + break; + } + } + if (!isHFInSubjet1) { + std::swap(parentSubJet1, parentSubJet2); + } + std::vector tracks; + std::vector candidates; + std::vector clusters; + for (const auto& constituent : sorted_by_pt(parentSubJet2.constituents())) { + if (constituent.template user_info().getStatus() == static_cast(JetConstituentStatus::track)) { + tracks.push_back(constituent.template user_info().getIndex()); + } + if (constituent.template user_info().getStatus() == static_cast(JetConstituentStatus::candidate)) { + candidates.push_back(constituent.template user_info().getIndex()); + } + } + splittingTable(jet.globalIndex(), tracks, clusters, candidates, parentSubJet2.perp(), parentSubJet2.eta(), parentSubJet2.phi(), 0); + auto z = parentSubJet2.perp() / (parentSubJet1.perp() + parentSubJet2.perp()); + auto theta = parentSubJet1.delta_R(parentSubJet2); + energyMotherVec.push_back(daughterSubJet.e()); + ptLeadingVec.push_back(parentSubJet1.pt()); + ptSubLeadingVec.push_back(parentSubJet2.pt()); + thetaVec.push_back(theta); + if (z >= zCut * TMath::Power(theta / (jet.r() / 100.f), beta)) { + if (!softDropped) { + zg = z; + rg = theta; + if constexpr (!isSubtracted && !isMCP) { + registry.fill(HIST("h2_jet_pt_jet_zg"), jet.pt(), zg); + registry.fill(HIST("h2_jet_pt_jet_rg"), jet.pt(), rg); + } + if constexpr (!isSubtracted && isMCP) { + registry.fill(HIST("h2_jet_pt_part_jet_zg_part"), jet.pt(), zg); + registry.fill(HIST("h2_jet_pt_part_jet_rg_part"), jet.pt(), rg); + } + if constexpr (isSubtracted && !isMCP) { + registry.fill(HIST("h2_jet_pt_jet_zg_eventwiseconstituentsubtracted"), jet.pt(), zg); + registry.fill(HIST("h2_jet_pt_jet_rg_eventwiseconstituentsubtracted"), jet.pt(), rg); + } + softDropped = true; + } + nsd++; + } + daughterSubJet = parentSubJet1; + } + if constexpr (!isSubtracted && !isMCP) { + registry.fill(HIST("h2_jet_pt_jet_nsd"), jet.pt(), nsd); + } + if constexpr (!isSubtracted && isMCP) { + registry.fill(HIST("h2_jet_pt_part_jet_nsd_part"), jet.pt(), nsd); + } + if constexpr (isSubtracted && !isMCP) { + registry.fill(HIST("h2_jet_pt_jet_nsd_eventwiseconstituentsubtracted"), jet.pt(), nsd); + } + } + + template + void jetPairing(T const& jet, U const& tracks, V const& /*candidates*/, M const& slicer, N& pairTable) + { + pairJetPtVec.clear(); + pairJetEnergyVec.clear(); + pairJetThetaVec.clear(); + std::vector> tracksVec; + std::vector> candidatesVec; + std::vector tracksVecIds; + std::vector candidatesVecIds; + for (auto& constituent : jet.template tracks_as()) { + if (constituent.pt() >= pairConstituentPtMin) { + tracksVec.push_back(constituent); + tracksVecIds.push_back(constituent.globalIndex()); + } + } + for (auto& candidate : jet.template candidates_as()) { + candidatesVec.push_back(candidate); + candidatesVecIds.push_back(candidate.globalIndex()); + } + if (tracksVec.size() >= 1) { + for (typename std::vector>::size_type track1Index = 0; track1Index < tracksVec.size(); track1Index++) { + for (typename std::vector>::size_type track2Index = track1Index + 1; track2Index < tracksVec.size(); track2Index++) { + pairJetPtVec.push_back(tracksVec.at(track1Index).pt() * tracksVec.at(track2Index).pt()); + pairJetEnergyVec.push_back(2.0 * tracksVec.at(track1Index).energy() * tracksVec.at(track2Index).energy()); + pairJetThetaVec.push_back(jetutilities::deltaR(tracksVec.at(track1Index), tracksVec.at(track2Index))); + pairTable(jet.globalIndex(), tracksVecIds.at(track1Index), tracksVecIds.at(track2Index), -1, -1); + } + } + } + if (candidatesVec.size() >= 1) { + for (typename std::vector>::size_type candidate1Index = 0; candidate1Index < candidatesVec.size(); candidate1Index++) { + for (typename std::vector>::size_type candidate2Index = candidate1Index + 1; candidate2Index < candidatesVec.size(); candidate2Index++) { + pairJetPtVec.push_back(candidatesVec.at(candidate1Index).pt() * candidatesVec.at(candidate2Index).pt()); + auto candidate1Energy = std::sqrt((candidatesVec.at(candidate1Index).p() * candidatesVec.at(candidate1Index).p()) + (candMass * candMass)); + auto candidate2Energy = std::sqrt((candidatesVec.at(candidate2Index).p() * candidatesVec.at(candidate2Index).p()) + (candMass * candMass)); + pairJetEnergyVec.push_back(2.0 * candidate1Energy * candidate2Energy); + pairJetThetaVec.push_back(jetutilities::deltaR(candidatesVec.at(candidate1Index), candidatesVec.at(candidate2Index))); + pairTable(jet.globalIndex(), -1, -1, candidatesVecIds.at(candidate1Index), candidatesVecIds.at(candidate2Index)); + } + } + } + if (candidatesVec.size() >= 1 && tracksVec.size() >= 1) { + for (typename std::vector>::size_type candidateIndex = 0; candidateIndex < candidatesVec.size(); candidateIndex++) { // could just directly get the candidate and tracks here but keeping it consistent with above + for (typename std::vector>::size_type trackIndex = 0; trackIndex < tracksVec.size(); trackIndex++) { + pairJetPtVec.push_back(candidatesVec.at(candidateIndex).pt() * tracksVec.at(trackIndex).pt()); + auto candidateEnergy = std::sqrt((candidatesVec.at(candidateIndex).p() * candidatesVec.at(candidateIndex).p()) + (candMass * candMass)); + pairJetEnergyVec.push_back(2.0 * candidateEnergy * tracksVec.at(trackIndex).energy()); + pairJetThetaVec.push_back(jetutilities::deltaR(candidatesVec.at(candidateIndex), tracksVec.at(trackIndex))); + pairTable(jet.globalIndex(), tracksVecIds.at(trackIndex), -1, candidatesVecIds.at(candidateIndex), -1); + } + } + } + + pairJetPerpCone1PtVec.clear(); + pairJetPerpCone1EnergyVec.clear(); + pairJetPerpCone1ThetaVec.clear(); + pairPerpCone1PerpCone1PtVec.clear(); + pairPerpCone1PerpCone1EnergyVec.clear(); + pairPerpCone1PerpCone1ThetaVec.clear(); + pairPerpCone1PerpCone2PtVec.clear(); + pairPerpCone1PerpCone2EnergyVec.clear(); + pairPerpCone1PerpCone2ThetaVec.clear(); + int32_t slicerId = -1; + if constexpr (isSubtracted) { + auto const& candidate = jet.template candidates_first_as(); + slicerId = candidate.globalIndex(); + } else { + if constexpr (!isMC) { + slicerId = jet.collisionId(); + } else { + slicerId = jet.mcCollisionId(); + } + } + auto tracksPerCollision = tracks.sliceBy(slicer, slicerId); + + float perpCone1Phi = RecoDecay::constrainAngle(jet.phi() + (M_PI / 2.)); + float perpCone2Phi = RecoDecay::constrainAngle(jet.phi() - (M_PI / 2.)); + float perpCone1Pt = 0.0; + float perpCone2Pt = 0.0; + std::vector tracksPerpCone1Vec; + std::vector tracksPerpCone2Vec; + for (auto const& track : tracksPerCollision) { + float deltaPhi1 = track.phi() - perpCone1Phi; + deltaPhi1 = RecoDecay::constrainAngle(deltaPhi1, -M_PI); + float deltaPhi2 = track.phi() - perpCone2Phi; + deltaPhi2 = RecoDecay::constrainAngle(deltaPhi2, -M_PI); + float deltaEta = jet.eta() - track.eta(); + + if (TMath::Sqrt((deltaPhi1 * deltaPhi1) + (deltaEta * deltaEta)) <= jet.r() / 100.0) { + if (track.pt() >= pairConstituentPtMin) { + tracksPerpCone1Vec.push_back(track); + } + perpCone1Pt += track.pt(); + } + if (TMath::Sqrt((deltaPhi2 * deltaPhi2) + (deltaEta * deltaEta)) <= jet.r() / 100.0) { + if (track.pt() >= pairConstituentPtMin) { + tracksPerpCone2Vec.push_back(track); + } + perpCone2Pt += track.pt(); + } + } + perpConeRho = (perpCone1Pt + perpCone2Pt) / (2 * M_PI * (jet.r() / 100.0) * (jet.r() / 100.0)); // currently done per jet - could be better to do for leading jet if pushing to very low pT + if (doPairBkg) { + if (tracksVec.size() >= 1 && tracksPerpCone1Vec.size() >= 1) { + for (typename std::vector::size_type track1Index = 0; track1Index < tracksVec.size(); track1Index++) { + for (typename std::vector::size_type track2Index = 0; track2Index < tracksPerpCone1Vec.size(); track2Index++) { + pairJetPerpCone1PtVec.push_back(tracksVec.at(track1Index).pt() * tracksPerpCone1Vec.at(track2Index).pt()); + pairJetPerpCone1EnergyVec.push_back(2.0 * tracksVec.at(track1Index).energy() * tracksPerpCone1Vec.at(track2Index).energy()); + float dPhi = RecoDecay::constrainAngle(tracksVec.at(track1Index).phi() - (tracksPerpCone1Vec.at(track2Index).phi() - (M_PI / 2.)), -M_PI); + float dEta = tracksVec.at(track1Index).eta() - tracksPerpCone1Vec.at(track2Index).eta(); + pairJetPerpCone1ThetaVec.push_back(std::sqrt(dEta * dEta + dPhi * dPhi)); + } + } + } + + if (candidatesVec.size() >= 1 && tracksPerpCone1Vec.size() >= 1) { + for (typename std::vector>::size_type candidate1Index = 0; candidate1Index < candidatesVec.size(); candidate1Index++) { + for (typename std::vector::size_type track2Index = 0; track2Index < tracksPerpCone1Vec.size(); track2Index++) { + pairJetPerpCone1PtVec.push_back(candidatesVec.at(candidate1Index).pt() * tracksPerpCone1Vec.at(track2Index).pt()); + auto candidate1Energy = std::sqrt((candidatesVec.at(candidate1Index).p() * candidatesVec.at(candidate1Index).p()) + (candMass * candMass)); + pairJetPerpCone1EnergyVec.push_back(2.0 * candidate1Energy * tracksPerpCone1Vec.at(track2Index).energy()); + float dPhi = RecoDecay::constrainAngle(candidatesVec.at(candidate1Index).phi() - (tracksPerpCone1Vec.at(track2Index).phi() - (M_PI / 2.)), -M_PI); + float dEta = candidatesVec.at(candidate1Index).eta() - tracksPerpCone1Vec.at(track2Index).eta(); + pairJetPerpCone1ThetaVec.push_back(std::sqrt(dEta * dEta + dPhi * dPhi)); + } + } + } + + if (tracksPerpCone1Vec.size() >= 1) { + for (typename std::vector::size_type track1Index = 0; track1Index < tracksPerpCone1Vec.size(); track1Index++) { + for (typename std::vector::size_type track2Index = track1Index + 1; track2Index < tracksPerpCone1Vec.size(); track2Index++) { + pairPerpCone1PerpCone1PtVec.push_back(tracksPerpCone1Vec.at(track1Index).pt() * tracksPerpCone1Vec.at(track2Index).pt()); + pairPerpCone1PerpCone1EnergyVec.push_back(2.0 * tracksPerpCone1Vec.at(track1Index).energy() * tracksPerpCone1Vec.at(track2Index).energy()); + pairPerpCone1PerpCone1ThetaVec.push_back(jetutilities::deltaR(tracksPerpCone1Vec.at(track1Index), tracksPerpCone1Vec.at(track2Index))); + } + } + } + + if (tracksPerpCone1Vec.size() >= 1 && tracksPerpCone2Vec.size() >= 1) { + for (typename std::vector::size_type track1Index = 0; track1Index < tracksPerpCone1Vec.size(); track1Index++) { + for (typename std::vector::size_type track2Index = 0; track2Index < tracksPerpCone2Vec.size(); track2Index++) { + pairPerpCone1PerpCone2PtVec.push_back(tracksPerpCone1Vec.at(track1Index).pt() * tracksPerpCone2Vec.at(track2Index).pt()); + pairPerpCone1PerpCone2EnergyVec.push_back(2.0 * tracksPerpCone1Vec.at(track1Index).energy() * tracksPerpCone2Vec.at(track2Index).energy()); + float dPhi = RecoDecay::constrainAngle((tracksPerpCone1Vec.at(track1Index).phi() - (M_PI / 2.)) - (tracksPerpCone2Vec.at(track2Index).phi() + (M_PI / 2.)), -M_PI); + float dEta = tracksPerpCone1Vec.at(track1Index).eta() - tracksPerpCone2Vec.at(track2Index).eta(); + pairPerpCone1PerpCone2ThetaVec.push_back(std::sqrt(dEta * dEta + dPhi * dPhi)); + } + } + } + } + } + + template + void jetSubstructureSimple(T const& jet, U const& /*tracks*/, V const& /*candidates*/) + { + angularity = 0.0; + leadingConstituentPt = 0.0; + for (auto& candidate : jet.template candidates_as()) { + if (candidate.pt() >= leadingConstituentPt) { + leadingConstituentPt = candidate.pt(); + } + angularity += std::pow(candidate.pt(), kappa) * std::pow(jetutilities::deltaR(jet, candidate), alpha); + } + for (auto& constituent : jet.template tracks_as()) { + if (constituent.pt() >= leadingConstituentPt) { + leadingConstituentPt = constituent.pt(); + } + angularity += std::pow(constituent.pt(), kappa) * std::pow(jetutilities::deltaR(jet, constituent), alpha); + } + angularity /= (jet.pt() * (jet.r() / 100.f)); + } + + template + void analyseCharged(T const& jet, U const& tracks, V const& candidates, M const& trackSlicer, N& outputTable, O& splittingTable, P& pairTable) + { + jetConstituents.clear(); + for (auto& jetConstituent : jet.template tracks_as()) { + fastjetutilities::fillTracks(jetConstituent, jetConstituents, jetConstituent.globalIndex()); + } + for (auto& jetHFCandidate : jet.template candidates_as()) { // should only be one at the moment + fastjetutilities::fillTracks(jetHFCandidate, jetConstituents, jetHFCandidate.globalIndex(), static_cast(JetConstituentStatus::candidate), candMass); + } + nSub = jetsubstructureutilities::getNSubjettiness(jet, tracks, tracks, candidates, 2, fastjet::contrib::CA_Axes(), true, zCut, beta); + jetReclustering(jet, splittingTable); + jetPairing(jet, tracks, candidates, trackSlicer, pairTable); + jetSubstructureSimple(jet, tracks, candidates); + outputTable(energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec, nSub[0], nSub[1], nSub[2], pairJetPtVec, pairJetEnergyVec, pairJetThetaVec, pairJetPerpCone1PtVec, pairJetPerpCone1EnergyVec, pairJetPerpCone1ThetaVec, pairPerpCone1PerpCone1PtVec, pairPerpCone1PerpCone1EnergyVec, pairPerpCone1PerpCone1ThetaVec, pairPerpCone1PerpCone2PtVec, pairPerpCone1PerpCone2EnergyVec, pairPerpCone1PerpCone2ThetaVec, angularity, leadingConstituentPt, perpConeRho); + } + + void processChargedJetsData(typename JetTableData::iterator const& jet, + CandidateTable const& candidates, + aod::JetTracks const& tracks) + { + analyseCharged(jet, tracks, candidates, TracksPerCollision, jetSubstructureDataTable, jetSplittingsDataTable, jetPairsDataTable); + } + PROCESS_SWITCH(JetSubstructureHFTask, processChargedJetsData, "HF jet substructure on data", false); + + void processChargedJetsDataSub(typename JetTableDataSub::iterator const& jet, + CandidateTable const& candidates, + TracksSub const& tracks) + { + analyseCharged(jet, tracks, candidates, selectSlicer(TracksPerD0DataSub, TracksPerDplusDataSub, TracksPerLcDataSub, TracksPerBplusDataSub, TracksPerDielectronDataSub), jetSubstructureDataSubTable, jetSplittingsDataSubTable, jetPairsDataSubTable); + } + PROCESS_SWITCH(JetSubstructureHFTask, processChargedJetsDataSub, "HF jet substructure on data", false); + + void processChargedJetsMCD(typename JetTableMCD::iterator const& jet, + CandidateTable const& candidates, + aod::JetTracks const& tracks) + { + analyseCharged(jet, tracks, candidates, TracksPerCollision, jetSubstructureMCDTable, jetSplittingsMCDTable, jetPairsMCDTable); + } + PROCESS_SWITCH(JetSubstructureHFTask, processChargedJetsMCD, "HF jet substructure on data", false); + + void processChargedJetsMCP(typename JetTableMCP::iterator const& jet, + aod::JetParticles const& particles, + CandidateTableMCP const& candidates) + { + jetConstituents.clear(); + for (auto& jetConstituent : jet.template tracks_as()) { + fastjetutilities::fillTracks(jetConstituent, jetConstituents, jetConstituent.globalIndex(), static_cast(JetConstituentStatus::track), pdg->Mass(jetConstituent.pdgCode())); + } + for (auto& jetHFCandidate : jet.template candidates_as()) { + fastjetutilities::fillTracks(jetHFCandidate, jetConstituents, jetHFCandidate.globalIndex(), static_cast(JetConstituentStatus::candidate), candMass); + } + nSub = jetsubstructureutilities::getNSubjettiness(jet, particles, particles, candidates, 2, fastjet::contrib::CA_Axes(), true, zCut, beta); + jetReclustering(jet, jetSplittingsMCPTable); + jetPairing(jet, particles, candidates, ParticlesPerMcCollision, jetPairsMCPTable); + jetSubstructureSimple(jet, particles, candidates); + jetSubstructureMCPTable(energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec, nSub[0], nSub[1], nSub[2], pairJetPtVec, pairJetEnergyVec, pairJetThetaVec, pairJetPerpCone1PtVec, pairJetPerpCone1EnergyVec, pairJetPerpCone1ThetaVec, pairPerpCone1PerpCone1PtVec, pairPerpCone1PerpCone1EnergyVec, pairPerpCone1PerpCone1ThetaVec, pairPerpCone1PerpCone2PtVec, pairPerpCone1PerpCone2EnergyVec, pairPerpCone1PerpCone2ThetaVec, angularity, leadingConstituentPt, perpConeRho); + } + PROCESS_SWITCH(JetSubstructureHFTask, processChargedJetsMCP, "HF jet substructure on MC particle level", false); +}; diff --git a/PWGJE/Tasks/jetSubstructureHFOutput.cxx b/PWGJE/Tasks/jetSubstructureHFOutput.cxx new file mode 100644 index 00000000000..ffa526f1a11 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureHFOutput.cxx @@ -0,0 +1,721 @@ +// 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. + +// heavy-flavour jet substructure tree filling task (subscribing to jet finder hf and jet substructure hf tasks) +// +/// \author Nima Zardoshti +// + +#include +#include +#include +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "TDatabasePDG.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// NB: runDataProcessing.h must be included after customize! +#include "Framework/runDataProcessing.h" + +template +struct JetSubstructureHFOutputTask { + + struct : ProducesGroup { + Produces collisionOutputTableData; + Produces jetOutputTableData; + Produces jetSubstructureOutputTableData; + Produces jetMatchingOutputTableData; + Produces collisionOutputTableDataSub; + Produces jetOutputTableDataSub; + Produces jetSubstructureOutputTableDataSub; + Produces jetMatchingOutputTableDataSub; + Produces collisionOutputTableMCD; + Produces jetOutputTableMCD; + Produces jetSubstructureOutputTableMCD; + Produces jetMatchingOutputTableMCD; + Produces collisionOutputTableMCP; + Produces hfMcOnlyCollisionsTable; + Produces jetOutputTableMCP; + Produces jetSubstructureOutputTableMCP; + Produces jetMatchingOutputTableMCP; + Produces hfCollisionsTable; + Produces candidateTable; + Produces candidateParsTable; + Produces candidateParExtrasTable; + Produces candidateParsDaughterTable; + Produces candidateSelsTable; + Produces candidateMlsTable; + Produces candidateMlsDaughterTable; + Produces candidateMcsTable; + Produces hfMcCollisionsTable; + Produces hfMcCollisionsMatchingTable; + Produces hfParticlesTable; + } products; + + struct : ConfigurableGroup { + Configurable jetPtMinData{"jetPtMinData", 0.0, "minimum jet pT cut for data jets"}; + Configurable jetPtMinDataSub{"jetPtMinDataSub", 0.0, "minimum jet pT cut for eventwise constituent subtracted data jets"}; + Configurable jetPtMinMCD{"jetPtMinMCD", 0.0, "minimum jet pT cut for mcd jets"}; + Configurable jetPtMinMCP{"jetPtMinMCP", 0.0, "minimum jet pT cut for mcp jets"}; + Configurable> jetRadii{"jetRadii", std::vector{0.4}, "jet resolution parameters"}; + Configurable jetEtaMin{"jetEtaMin", -99.0, "minimum jet pseudorapidity"}; + Configurable jetEtaMax{"jetEtaMax", 99.0, "maximum jet pseudorapidity"}; + Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum track pseudorapidity"}; + Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track pseudorapidity"}; + } configs; + + // need to add selection on pThat to post processing + + std::map jetMappingData; + std::map jetMappingDataSub; + std::map jetMappingMCD; + std::map jetMappingMCP; + std::map candidateMapping; + std::map candidateMappingMCP; + std::map candidateCollisionMapping; + std::map candidateMcCollisionMapping; + + std::vector> splittingMatchesGeoVecVecData; + std::vector> splittingMatchesPtVecVecData; + std::vector> splittingMatchesHFVecVecData; + std::vector> splittingMatchesGeoVecVecDataSub; + std::vector> splittingMatchesPtVecVecDataSub; + std::vector> splittingMatchesHFVecVecDataSub; + std::vector> splittingMatchesGeoVecVecMCD; + std::vector> splittingMatchesPtVecVecMCD; + std::vector> splittingMatchesHFVecVecMCD; + std::vector> splittingMatchesGeoVecVecMCP; + std::vector> splittingMatchesPtVecVecMCP; + std::vector> splittingMatchesHFVecVecMCP; + + std::vector> pairMatchesVecVecData; + std::vector> pairMatchesVecVecDataSub; + std::vector> pairMatchesVecVecMCD; + std::vector> pairMatchesVecVecMCP; + + std::vector jetRadiiValues; + + std::vector collisionFlag; + std::vector mcCollisionFlag; + + void init(InitContext const&) + { + jetRadiiValues = (std::vector)configs.jetRadii; + } + + PresliceUnsorted> CollisionsPerMcCollision = aod::jmccollisionlb::mcCollisionId; + PresliceOptional CandidateCollisionsPerCollision = aod::jcandidateindices::collisionId; + PresliceOptional CandidateMcCollisionsPerMcCollision = aod::jcandidateindices::mcCollisionId; + PresliceOptional CandidateMcCollisionsPerMcCollisionMCPOnly = aod::jcandidateindices::mcCollisionId; + + PresliceOptional> D0SplittingsPerJetData = aod::d0chargedsplitting::jetId; + PresliceOptional> D0SplittingsPerJetDataSub = aod::d0chargedeventwisesubtractedsplitting::jetId; + PresliceOptional> D0SplittingsPerJetMCD = aod::d0chargedmcdetectorlevelsplitting::jetId; + PresliceOptional> D0SplittingsPerJetMCP = aod::d0chargedmcparticlelevelsplitting::jetId; + + PresliceOptional> D0PairsPerJetData = aod::d0chargedpair::jetId; + PresliceOptional> D0PairsPerJetDataSub = aod::d0chargedeventwisesubtractedpair::jetId; + PresliceOptional> D0PairsPerJetMCD = aod::d0chargedmcdetectorlevelpair::jetId; + PresliceOptional> D0PairsPerJetMCP = aod::d0chargedmcparticlelevelpair::jetId; + + PresliceOptional> DplusSplittingsPerJetData = aod::dpluschargedsplitting::jetId; + PresliceOptional> DplusSplittingsPerJetDataSub = aod::dpluschargedeventwisesubtractedsplitting::jetId; + PresliceOptional> DplusSplittingsPerJetMCD = aod::dpluschargedmcdetectorlevelsplitting::jetId; + PresliceOptional> DplusSplittingsPerJetMCP = aod::dpluschargedmcparticlelevelsplitting::jetId; + + PresliceOptional> DplusPairsPerJetData = aod::dpluschargedpair::jetId; + PresliceOptional> DplusPairsPerJetDataSub = aod::dpluschargedeventwisesubtractedpair::jetId; + PresliceOptional> DplusPairsPerJetMCD = aod::dpluschargedmcdetectorlevelpair::jetId; + PresliceOptional> DplusPairsPerJetMCP = aod::dpluschargedmcparticlelevelpair::jetId; + + PresliceOptional> LcSplittingsPerJetData = aod::lcchargedsplitting::jetId; + PresliceOptional> LcSplittingsPerJetDataSub = aod::lcchargedeventwisesubtractedsplitting::jetId; + PresliceOptional> LcSplittingsPerJetMCD = aod::lcchargedmcdetectorlevelsplitting::jetId; + PresliceOptional> LcSplittingsPerJetMCP = aod::lcchargedmcparticlelevelsplitting::jetId; + + PresliceOptional> LcPairsPerJetData = aod::lcchargedpair::jetId; + PresliceOptional> LcPairsPerJetDataSub = aod::lcchargedeventwisesubtractedpair::jetId; + PresliceOptional> LcPairsPerJetMCD = aod::lcchargedmcdetectorlevelpair::jetId; + PresliceOptional> LcPairsPerJetMCP = aod::lcchargedmcparticlelevelpair::jetId; + + PresliceOptional> BplusSplittingsPerJetData = aod::bpluschargedsplitting::jetId; + PresliceOptional> BplusSplittingsPerJetDataSub = aod::bpluschargedeventwisesubtractedsplitting::jetId; + PresliceOptional> BplusSplittingsPerJetMCD = aod::bpluschargedmcdetectorlevelsplitting::jetId; + PresliceOptional> BplusSplittingsPerJetMCP = aod::bpluschargedmcparticlelevelsplitting::jetId; + + PresliceOptional> BplusPairsPerJetData = aod::bpluschargedpair::jetId; + PresliceOptional> BplusPairsPerJetDataSub = aod::bpluschargedeventwisesubtractedpair::jetId; + PresliceOptional> BplusPairsPerJetMCD = aod::bpluschargedmcdetectorlevelpair::jetId; + PresliceOptional> BplusPairsPerJetMCP = aod::bpluschargedmcparticlelevelpair::jetId; + + PresliceOptional> DielectronSplittingsPerJetData = aod::dielectronchargedsplitting::jetId; + PresliceOptional> DielectronSplittingsPerJetDataSub = aod::dielectronchargedeventwisesubtractedsplitting::jetId; + PresliceOptional> DielectronSplittingsPerJetMCD = aod::dielectronchargedmcdetectorlevelsplitting::jetId; + PresliceOptional> DielectronSplittingsPerJetMCP = aod::dielectronchargedmcparticlelevelsplitting::jetId; + + PresliceOptional> DielectronPairsPerJetData = aod::dielectronchargedpair::jetId; + PresliceOptional> DielectronPairsPerJetDataSub = aod::dielectronchargedeventwisesubtractedpair::jetId; + PresliceOptional> DielectronPairsPerJetMCD = aod::dielectronchargedmcdetectorlevelpair::jetId; + PresliceOptional> DielectronPairsPerJetMCP = aod::dielectronchargedmcparticlelevelpair::jetId; + + template + auto candidateMCCollisionSlicer(T const& McCollisionsPerMcCollision, U const& McCollisionsPerMcCollisionMCPOnly) + { + if constexpr (isMCP) { + return McCollisionsPerMcCollisionMCPOnly; + } else { + return McCollisionsPerMcCollision; + } + } + + template + void fillSplittingMatchingVectors(T const& splittingsMatches, int jetIndex, std::vector>& splittingMatchesGeoVecVec, std::vector>& splittingMatchesPtVecVec, std::vector>& splittingMatchesHFVecVec) + { + for (auto const& splittingMatches : splittingsMatches) { + auto splittingMatchesGeoSpan = splittingMatches.splittingMatchingGeo(); + auto splittingMatchesPtSpan = splittingMatches.splittingMatchingPt(); + auto splittingMatchesHFSpan = splittingMatches.splittingMatchingHF(); + std::copy(splittingMatchesGeoSpan.begin(), splittingMatchesGeoSpan.end(), std::back_inserter(splittingMatchesGeoVecVec[jetIndex])); + std::copy(splittingMatchesPtSpan.begin(), splittingMatchesPtSpan.end(), std::back_inserter(splittingMatchesPtVecVec[jetIndex])); + std::copy(splittingMatchesHFSpan.begin(), splittingMatchesHFSpan.end(), std::back_inserter(splittingMatchesHFVecVec[jetIndex])); + } + } + + template + void fillPairMatchingVectors(T const& pairsMatches, int jetIndex, std::vector>& pairMatchesVecVec) + { + for (auto const& pairMatches : pairsMatches) { + auto pairMatchesSpan = pairMatches.pairMatching(); + std::copy(pairMatchesSpan.begin(), pairMatchesSpan.end(), std::back_inserter(pairMatchesVecVec[jetIndex])); + } + } + + template + void fillJetTables(T const& jet, U const& /*cand*/, int32_t collisionIndex, int32_t candidateIndex, V& jetOutputTable, M& jetSubstructureOutputTable, std::vector>& splittingMatchesGeoVecVec, std::vector>& splittingMatchesPtVecVec, std::vector>& splittingMatchesHFVecVec, std::vector>& pairMatchesVecVec, float rho, std::map& jetMap) + { + std::vector energyMotherVec; + std::vector ptLeadingVec; + std::vector ptSubLeadingVec; + std::vector thetaVec; + std::vector pairJetPtVec; + std::vector pairJetEnergyVec; + std::vector pairJetThetaVec; + std::vector pairJetPerpCone1PtVec; + std::vector pairJetPerpCone1EnergyVec; + std::vector pairJetPerpCone1ThetaVec; + std::vector pairPerpCone1PerpCone1PtVec; + std::vector pairPerpCone1PerpCone1EnergyVec; + std::vector pairPerpCone1PerpCone1ThetaVec; + std::vector pairPerpCone1PerpCone2PtVec; + std::vector pairPerpCone1PerpCone2EnergyVec; + std::vector pairPerpCone1PerpCone2ThetaVec; + + auto energyMotherSpan = jet.energyMother(); + auto ptLeadingSpan = jet.ptLeading(); + auto ptSubLeadingSpan = jet.ptSubLeading(); + auto thetaSpan = jet.theta(); + auto pairJetPtSpan = jet.pairJetPt(); + auto pairJetEnergySpan = jet.pairJetEnergy(); + auto pairJetThetaSpan = jet.pairJetTheta(); + auto pairJetPerpCone1PtSpan = jet.pairJetPerpCone1Pt(); + auto pairJetPerpCone1EnergySpan = jet.pairJetPerpCone1Energy(); + auto pairJetPerpCone1ThetaSpan = jet.pairJetPerpCone1Theta(); + auto pairPerpCone1PerpCone1PtSpan = jet.pairPerpCone1PerpCone1Pt(); + auto pairPerpCone1PerpCone1EnergySpan = jet.pairPerpCone1PerpCone1Energy(); + auto pairPerpCone1PerpCone1ThetaSpan = jet.pairPerpCone1PerpCone1Theta(); + auto pairPerpCone1PerpCone2PtSpan = jet.pairPerpCone1PerpCone2Pt(); + auto pairPerpCone1PerpCone2EnergySpan = jet.pairPerpCone1PerpCone2Energy(); + auto pairPerpCone1PerpCone2ThetaSpan = jet.pairPerpCone1PerpCone2Theta(); + + std::copy(energyMotherSpan.begin(), energyMotherSpan.end(), std::back_inserter(energyMotherVec)); + std::copy(ptLeadingSpan.begin(), ptLeadingSpan.end(), std::back_inserter(ptLeadingVec)); + std::copy(ptSubLeadingSpan.begin(), ptSubLeadingSpan.end(), std::back_inserter(ptSubLeadingVec)); + std::copy(thetaSpan.begin(), thetaSpan.end(), std::back_inserter(thetaVec)); + std::copy(pairJetPtSpan.begin(), pairJetPtSpan.end(), std::back_inserter(pairJetPtVec)); + std::copy(pairJetEnergySpan.begin(), pairJetEnergySpan.end(), std::back_inserter(pairJetEnergyVec)); + std::copy(pairJetThetaSpan.begin(), pairJetThetaSpan.end(), std::back_inserter(pairJetThetaVec)); + std::copy(pairJetPerpCone1PtSpan.begin(), pairJetPerpCone1PtSpan.end(), std::back_inserter(pairJetPerpCone1PtVec)); + std::copy(pairJetPerpCone1EnergySpan.begin(), pairJetPerpCone1EnergySpan.end(), std::back_inserter(pairJetPerpCone1EnergyVec)); + std::copy(pairJetPerpCone1ThetaSpan.begin(), pairJetPerpCone1ThetaSpan.end(), std::back_inserter(pairJetPerpCone1ThetaVec)); + std::copy(pairPerpCone1PerpCone1PtSpan.begin(), pairPerpCone1PerpCone1PtSpan.end(), std::back_inserter(pairPerpCone1PerpCone1PtVec)); + std::copy(pairPerpCone1PerpCone1EnergySpan.begin(), pairPerpCone1PerpCone1EnergySpan.end(), std::back_inserter(pairPerpCone1PerpCone1EnergyVec)); + std::copy(pairPerpCone1PerpCone1ThetaSpan.begin(), pairPerpCone1PerpCone1ThetaSpan.end(), std::back_inserter(pairPerpCone1PerpCone1ThetaVec)); + std::copy(pairPerpCone1PerpCone2PtSpan.begin(), pairPerpCone1PerpCone2PtSpan.end(), std::back_inserter(pairPerpCone1PerpCone2PtVec)); + std::copy(pairPerpCone1PerpCone2EnergySpan.begin(), pairPerpCone1PerpCone2EnergySpan.end(), std::back_inserter(pairPerpCone1PerpCone2EnergyVec)); + std::copy(pairPerpCone1PerpCone2ThetaSpan.begin(), pairPerpCone1PerpCone2ThetaSpan.end(), std::back_inserter(pairPerpCone1PerpCone2ThetaVec)); + + std::vector splittingMatchesGeoVec; + std::vector splittingMatchesPtVec; + std::vector splittingMatchesHFVec; + std::vector pairMatchesVec; + if (doprocessOutputSubstructureMatchingData || doprocessOutputSubstructureMatchingMC) { + splittingMatchesGeoVec = splittingMatchesGeoVecVec[jet.globalIndex()]; + splittingMatchesPtVec = splittingMatchesPtVecVec[jet.globalIndex()]; + splittingMatchesHFVec = splittingMatchesHFVecVec[jet.globalIndex()]; + pairMatchesVec = pairMatchesVecVec[jet.globalIndex()]; + } + + jetOutputTable(collisionIndex, candidateIndex, jet.pt(), jet.phi(), jet.eta(), jet.y(), jet.r(), jet.area(), rho, jet.perpConeRho(), jet.tracksIds().size() + jet.candidatesIds().size()); // here we take the decision to keep the collision index consistent with the JE framework in case it is later needed to join to other tables. The candidate Index however can be linked to the HF tables + jetSubstructureOutputTable(jetOutputTable.lastIndex(), energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec, jet.nSub2DR(), jet.nSub1(), jet.nSub2(), pairJetPtVec, pairJetEnergyVec, pairJetThetaVec, pairJetPerpCone1PtVec, pairJetPerpCone1EnergyVec, pairJetPerpCone1ThetaVec, pairPerpCone1PerpCone1PtVec, pairPerpCone1PerpCone1EnergyVec, pairPerpCone1PerpCone1ThetaVec, pairPerpCone1PerpCone2PtVec, pairPerpCone1PerpCone2EnergyVec, pairPerpCone1PerpCone2ThetaVec, jet.angularity(), jet.ptLeadingConstituent(), splittingMatchesGeoVec, splittingMatchesPtVec, splittingMatchesHFVec, pairMatchesVec); + jetMap.insert(std::make_pair(jet.globalIndex(), jetOutputTable.lastIndex())); + } + + template + void analyseCharged(T const& collision, U const& jets, V const& /*candidates*/, M& collisionOutputTable, N& jetOutputTable, O& jetSubstructureOutputTable, std::vector>& splittingMatchesGeoVecVec, std::vector>& splittingMatchesPtVecVec, std::vector>& splittingMatchesHFVecVec, std::vector>& pairMatchesVecVec, std::map& jetMap, std::map& candidateMap, float jetPtMin, float eventWeight) + { + + int nJetInCollision = 0; + int32_t collisionIndex = -1; + for (const auto& jet : jets) { + if (jet.pt() < jetPtMin) { + continue; + } + if (!jetfindingutilities::isInEtaAcceptance(jet, configs.jetEtaMin, configs.jetEtaMax, configs.trackEtaMin, configs.trackEtaMax)) { + continue; + } + for (const auto& jetRadiiValue : jetRadiiValues) { + if (jet.r() == round(jetRadiiValue * 100.0f)) { + auto candidate = jet.template candidates_first_as(); + int32_t candidateIndex = -1; + auto candidateTableIndex = candidateMap.find(candidate.globalIndex()); + if (candidateTableIndex != candidateMap.end()) { + candidateIndex = candidateTableIndex->second; + } + if (nJetInCollision == 0) { + float centrality = -1.0; + uint8_t eventSel = 0.0; + if constexpr (!isMCP) { + centrality = collision.centrality(); + eventSel = collision.eventSel(); + } + collisionOutputTable(collision.posZ(), centrality, eventSel, eventWeight); + collisionIndex = collisionOutputTable.lastIndex(); + } + nJetInCollision++; + fillJetTables(jet, candidate, collisionIndex, candidateIndex, jetOutputTable, jetSubstructureOutputTable, splittingMatchesGeoVecVec, splittingMatchesPtVecVec, splittingMatchesHFVecVec, pairMatchesVecVec, candidate.rho(), jetMap); + } + } + } + } + + template + void analyseCandidates(T const& jets, U const& /*candidates*/, std::map& candidateMap, float jetPtMin) + { + for (const auto& jet : jets) { + if (jet.pt() < jetPtMin) { + continue; + } + if (!jetfindingutilities::isInEtaAcceptance(jet, configs.jetEtaMin, configs.jetEtaMax, configs.trackEtaMin, configs.trackEtaMax)) { + continue; + } + for (const auto& jetRadiiValue : jetRadiiValues) { + if (jet.r() == round(jetRadiiValue * 100.0f)) { + + auto candidate = jet.template candidates_first_as(); + + auto candidateTableIndex = candidateMap.find(candidate.globalIndex()); + if (candidateTableIndex != candidateMap.end()) { + continue; + } + int32_t candidateCollisionIndex = -1; + if constexpr (isMCP) { + auto hfMcCollisionIndex = candidateMcCollisionMapping.find(jetcandidateutilities::getMcCandidateCollisionId(candidate)); + if (hfMcCollisionIndex != candidateMcCollisionMapping.end()) { + candidateCollisionIndex = hfMcCollisionIndex->second; + } + jetcandidateutilities::fillCandidateMcTable(candidate, candidateCollisionIndex, products.hfParticlesTable); + candidateMap.insert(std::make_pair(candidate.globalIndex(), products.hfParticlesTable.lastIndex())); + } else { + auto hfCollisionIndex = candidateCollisionMapping.find(jetcandidateutilities::getCandidateCollisionId(candidate)); + if (hfCollisionIndex != candidateCollisionMapping.end()) { + candidateCollisionIndex = hfCollisionIndex->second; + } + jetcandidateutilities::fillCandidateTable(candidate, candidateCollisionIndex, products.candidateTable, products.candidateParsTable, products.candidateParExtrasTable, products.candidateParsDaughterTable, products.candidateSelsTable, products.candidateMlsTable, products.candidateMlsDaughterTable, products.candidateMcsTable); + candidateMap.insert(std::make_pair(candidate.globalIndex(), products.candidateTable.lastIndex())); + } + } + } + } + } + + template + void analyseSubstructureMatched(T const& jets, U const& allSplittings, V const& allPairs, M const& D0SplittingsPerJet, N const DplusSplittingsPerJet, O const& LcSplittingsPerJet, P const& BplusSplittingsPerJet, Q const& DielectronSplittingsPerJet, R const& D0PairsPerJet, S const DplusPairsPerJet, A const& LcPairsPerJet, B const& BplusPairsPerJet, C const& DielectronPairsPerJet, std::vector>& splittingMatchesGeoVecVec, std::vector>& splittingMatchesPtVecVec, std::vector>& splittingMatchesHFVecVec, std::vector>& pairMatchesVecVec, float jetPtMin) + { + for (const auto& jet : jets) { + if (jet.pt() < jetPtMin) { + continue; + } + if (!jetfindingutilities::isInEtaAcceptance(jet, configs.jetEtaMin, configs.jetEtaMax, configs.trackEtaMin, configs.trackEtaMax)) { + continue; + } + for (const auto& jetRadiiValue : jetRadiiValues) { + if (jet.r() == round(jetRadiiValue * 100.0f)) { + auto splittings = jetcandidateutilities::slicedPerJet(allSplittings, jet, D0SplittingsPerJet, DplusSplittingsPerJet, LcSplittingsPerJet, BplusSplittingsPerJet, DielectronSplittingsPerJet); + fillSplittingMatchingVectors(splittings, jet.globalIndex(), splittingMatchesGeoVecVec, splittingMatchesPtVecVec, splittingMatchesHFVecVec); + auto pairs = jetcandidateutilities::slicedPerJet(allPairs, jet, D0PairsPerJet, DplusPairsPerJet, LcPairsPerJet, BplusPairsPerJet, DielectronPairsPerJet); + fillPairMatchingVectors(pairs, jet.globalIndex(), pairMatchesVecVec); + } + } + } + } + + template + void analyseJetMatched(T const& jets, std::map& jetMapping, std::map& jetTagMapping, U& matchingOutputTable, float jetPtMin) + { + for (const auto& jet : jets) { + if (jet.pt() < jetPtMin) { + continue; + } + if (!jetfindingutilities::isInEtaAcceptance(jet, configs.jetEtaMin, configs.jetEtaMax, configs.trackEtaMin, configs.trackEtaMax)) { + continue; + } + for (const auto& jetRadiiValue : jetRadiiValues) { + if (jet.r() == round(jetRadiiValue * 100.0f)) { + std::vector geoMatching; + std::vector ptMatching; + std::vector candMatching; + if (jet.has_matchedJetGeo()) { + for (auto& jetTagId : jet.matchedJetGeoIds()) { + auto jetTagIndex = jetTagMapping.find(jetTagId); + if (jetTagIndex != jetTagMapping.end()) { + geoMatching.push_back(jetTagIndex->second); + } + } + } + if (jet.has_matchedJetPt()) { + for (auto& jetTagId : jet.matchedJetPtIds()) { + auto jetTagIndex = jetTagMapping.find(jetTagId); + if (jetTagIndex != jetTagMapping.end()) { + ptMatching.push_back(jetTagIndex->second); + } + } + } + if (jet.has_matchedJetCand()) { + for (auto& jetTagId : jet.matchedJetCandIds()) { + auto jetTagIndex = jetTagMapping.find(jetTagId); + if (jetTagIndex != jetTagMapping.end()) { + candMatching.push_back(jetTagIndex->second); + } + } + } + int storedJetIndex = -1; + auto jetIndex = jetMapping.find(jet.globalIndex()); + if (jetIndex != jetMapping.end()) { + storedJetIndex = jetIndex->second; + } + matchingOutputTable(storedJetIndex, geoMatching, ptMatching, candMatching); + } + } + } + } + + template + void analyseHFCollisions(T const& collisions, U const& mcCollisions, V const& hfCollisions, M const& hfMcCollisions, N const& jets, O const& jetsMCP, P const& candidates, S const& candidatesMCP, float jetPtMin, float jetPtMinMCP = 0.0) + { + collisionFlag.clear(); + collisionFlag.resize(collisions.size()); + std::fill(collisionFlag.begin(), collisionFlag.end(), false); + + mcCollisionFlag.clear(); + mcCollisionFlag.resize(mcCollisions.size()); + std::fill(mcCollisionFlag.begin(), mcCollisionFlag.end(), false); + + if constexpr (!isMCPOnly) { + for (const auto& jet : jets) { + if (jet.pt() < jetPtMin) { + continue; + } + if (!jetfindingutilities::isInEtaAcceptance(jet, configs.jetEtaMin, configs.jetEtaMax, configs.trackEtaMin, configs.trackEtaMax)) { + continue; + } + for (const auto& jetRadiiValue : jetRadiiValues) { + if (jet.r() == round(jetRadiiValue * 100.0f)) { + collisionFlag[jet.collisionId()] = true; + if constexpr (isMC) { + auto mcCollisionId = jet.template collision_as().mcCollisionId(); + if (mcCollisionId >= 0) { + mcCollisionFlag[mcCollisionId] = true; + } + } + } + } + } + } + if constexpr (isMC) { + for (const auto& jetMCP : jetsMCP) { + if (jetMCP.pt() < jetPtMinMCP) { + continue; + } + if (!jetfindingutilities::isInEtaAcceptance(jetMCP, configs.jetEtaMin, configs.jetEtaMax, configs.trackEtaMin, configs.trackEtaMax)) { + continue; + } + for (const auto& jetRadiiValue : jetRadiiValues) { + if (jetMCP.r() == round(jetRadiiValue * 100.0f)) { + + mcCollisionFlag[jetMCP.mcCollisionId()] = true; + if constexpr (!isMCPOnly) { + const auto collisionsPerMcCollision = collisions.sliceBy(CollisionsPerMcCollision, jetMCP.mcCollisionId()); + for (auto collision : collisionsPerMcCollision) { + collisionFlag[collision.globalIndex()] = true; + } + } + } + } + } + } + if constexpr (!isMCPOnly) { + for (const auto& collision : collisions) { + if (collisionFlag[collision.globalIndex()]) { + const auto hfCollisionsPerCollision = hfCollisions.sliceBy(CandidateCollisionsPerCollision, collision.globalIndex()); + for (const auto& hfCollisionPerCollision : hfCollisionsPerCollision) { // should only ever be one + auto hfCollisionTableIndex = candidateCollisionMapping.find(hfCollisionPerCollision.globalIndex()); + if (hfCollisionTableIndex != candidateCollisionMapping.end()) { + continue; + } + jetcandidateutilities::fillCandidateCollisionTable(hfCollisionPerCollision, candidates, products.hfCollisionsTable); + candidateCollisionMapping.insert(std::make_pair(hfCollisionPerCollision.globalIndex(), products.hfCollisionsTable.lastIndex())); + } + } + } + } + if constexpr (isMC) { + for (const auto& mcCollision : mcCollisions) { + if (mcCollisionFlag[mcCollision.globalIndex()]) { + const auto hfMcCollisionsPerMcCollision = hfMcCollisions.sliceBy(candidateMCCollisionSlicer(CandidateMcCollisionsPerMcCollision, CandidateMcCollisionsPerMcCollisionMCPOnly), mcCollision.globalIndex()); + for (const auto& hfMcCollisionPerMcCollision : hfMcCollisionsPerMcCollision) { // should only ever be one + auto hfMcCollisionTableIndex = candidateMcCollisionMapping.find(hfMcCollisionPerMcCollision.globalIndex()); + if (hfMcCollisionTableIndex != candidateMcCollisionMapping.end()) { + continue; + } + jetcandidateutilities::fillCandidateMcCollisionTable(hfMcCollisionPerMcCollision, candidatesMCP, products.hfMcCollisionsTable); + candidateMcCollisionMapping.insert(std::make_pair(hfMcCollisionPerMcCollision.globalIndex(), products.hfMcCollisionsTable.lastIndex())); + if constexpr (!isMCPOnly && (jethfutilities::isHFTable

() || jethfutilities::isHFMcTable())) { // the matching of mcCollision to Collision is only done for HF tables + std::vector hfCollisionIDs; + for (auto const& hfCollisionPerMcCollision : hfMcCollisionPerMcCollision.template hfCollBases_as()) { // if added for others this line needs to be templated per type + auto hfCollisionIndex = candidateCollisionMapping.find(hfCollisionPerMcCollision.globalIndex()); + if (hfCollisionIndex != candidateCollisionMapping.end()) { + hfCollisionIDs.push_back(hfCollisionIndex->second); + } + } + products.hfMcCollisionsMatchingTable(hfCollisionIDs); + } + } + } + } + } + } + + void processClearMaps(aod::JetCollisions const&) + { + candidateMapping.clear(); + jetMappingData.clear(); + jetMappingDataSub.clear(); + jetMappingMCD.clear(); + candidateCollisionMapping.clear(); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processClearMaps, "process function that clears all the non-mcp maps in each dataframe", true); + + void processClearMapsMCP(aod::JetMcCollisions const& mcCollisions) + { + candidateMappingMCP.clear(); + jetMappingMCP.clear(); + candidateMcCollisionMapping.clear(); + for (auto mcCollision : mcCollisions) { + products.hfMcOnlyCollisionsTable(mcCollision.posZ(), mcCollision.accepted(), mcCollision.attempted(), mcCollision.xsectGen(), mcCollision.xsectErr(), mcCollision.weight()); + } + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processClearMapsMCP, "process function that clears all the mcp maps in each dataframe", true); + + void processOutputCollisionsData(aod::JetCollisions const& collisions, + JetTableData const& jets, + CandidateCollisionTable const& canidateCollisions, + CandidateTable const& candidates) + { + analyseHFCollisions(collisions, collisions, canidateCollisions, canidateCollisions, jets, jets, candidates, candidates, configs.jetPtMinData); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCollisionsData, "hf collision output data", false); + + void processOutputCollisionsDataSub(aod::JetCollisions const& collisions, + JetTableDataSub const& jets, + CandidateCollisionTable const& canidateCollisions, + CandidateTable const& candidates) + { + analyseHFCollisions(collisions, collisions, canidateCollisions, canidateCollisions, jets, jets, candidates, candidates, configs.jetPtMinDataSub); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCollisionsDataSub, "hf collision output data eventwise constituent subtracted", false); + + void processOutputCollisionsMc(soa::Join const& collisions, + aod::JetMcCollisions const& mcCollisions, + JetTableMCD const& jetsMCD, + JetTableMatchedMCP const& jetsMCP, + CandidateCollisionTable const& canidateCollisions, + CandidateMcCollisionTable const& canidateMcCollisions, + CandidateTableMCD const& candidatesMCD, + CandidateTableMCP const& candidatesMCP) + { + analyseHFCollisions(collisions, mcCollisions, canidateCollisions, canidateMcCollisions, jetsMCD, jetsMCP, candidatesMCD, candidatesMCP, configs.jetPtMinMCD, configs.jetPtMinMCP); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCollisionsMc, "hf collision output MC", false); + + void processOutputCollisionsMCPOnly(aod::JetMcCollisions const& mcCollisions, + JetTableMCP const& jetsMCP, + CandidateMcOnlyCollisionTable const& canidateMcCollisions, + CandidateTableMCP const& candidatesMCP) + { + analyseHFCollisions(mcCollisions, mcCollisions, canidateMcCollisions, canidateMcCollisions, jetsMCP, jetsMCP, candidatesMCP, candidatesMCP, 0.0, configs.jetPtMinMCP); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCollisionsMCPOnly, "hf collision output MCP only", false); + + void processOutputCandidatesData(aod::JetCollision const&, + JetTableData const& jets, + CandidateTable const& candidates) + { + analyseCandidates(jets, candidates, candidateMapping, configs.jetPtMinData); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCandidatesData, "hf candidate output data", false); + + void processOutputCandidatesDataSub(aod::JetCollision const&, + JetTableDataSub const& jets, + CandidateTable const& candidates) + { + analyseCandidates(jets, candidates, candidateMapping, configs.jetPtMinDataSub); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCandidatesDataSub, "hf candidate output data eventwise constituent subtracted", false); + + void processOutputCandidatesMCD(aod::JetCollision const&, + JetTableMCD const& jets, + CandidateTableMCD const& candidates) + { + + analyseCandidates(jets, candidates, candidateMapping, configs.jetPtMinMCD); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCandidatesMCD, "hf candidate output MCD", false); + + void processOutputCandidatesMCP(aod::JetMcCollision const&, + JetTableMCP const& jets, + CandidateTableMCP const& candidates) + { + analyseCandidates(jets, candidates, candidateMappingMCP, configs.jetPtMinMCP); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCandidatesMCP, "hf candidate output MCP", false); + + void processOutputSubstructureMatchingData(JetMatchedTableData const& jets, + JetTableDataSub const& jetsSub, + CandidateTable const&, + SplittingTableData const& splittingsData, + SplittingTableDataSub const& splittingsDataSub, + PairTableData const& pairsData, + PairTableDataSub const& pairsDataSub) + { + splittingMatchesGeoVecVecData.assign(jets.size(), {}); + splittingMatchesPtVecVecData.assign(jets.size(), {}); + splittingMatchesHFVecVecData.assign(jets.size(), {}); + pairMatchesVecVecData.assign(jets.size(), {}); + analyseSubstructureMatched(jets, splittingsData, pairsData, D0SplittingsPerJetData, DplusSplittingsPerJetData, LcSplittingsPerJetData, BplusSplittingsPerJetData, DielectronSplittingsPerJetData, D0PairsPerJetData, DplusPairsPerJetData, LcPairsPerJetData, BplusPairsPerJetData, DielectronPairsPerJetData, splittingMatchesGeoVecVecData, splittingMatchesPtVecVecData, splittingMatchesHFVecVecData, pairMatchesVecVecData, configs.jetPtMinData); + splittingMatchesGeoVecVecDataSub.assign(jetsSub.size(), {}); + splittingMatchesPtVecVecDataSub.assign(jetsSub.size(), {}); + splittingMatchesHFVecVecDataSub.assign(jetsSub.size(), {}); + pairMatchesVecVecDataSub.assign(jetsSub.size(), {}); + analyseSubstructureMatched(jetsSub, splittingsDataSub, pairsDataSub, D0SplittingsPerJetDataSub, DplusSplittingsPerJetDataSub, LcSplittingsPerJetDataSub, BplusSplittingsPerJetDataSub, DielectronSplittingsPerJetDataSub, D0PairsPerJetDataSub, DplusPairsPerJetDataSub, LcPairsPerJetDataSub, BplusPairsPerJetDataSub, DielectronPairsPerJetDataSub, splittingMatchesGeoVecVecDataSub, splittingMatchesPtVecVecDataSub, splittingMatchesHFVecVecDataSub, pairMatchesVecVecDataSub, configs.jetPtMinDataSub); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputSubstructureMatchingData, "jet substructure matching output Data", false); + + void processOutputJetsData(aod::JetCollision const& collision, + JetTableData const& jets, + soa::Join const& candidates) + { + analyseCharged(collision, jets, candidates, products.collisionOutputTableData, products.jetOutputTableData, products.jetSubstructureOutputTableData, splittingMatchesGeoVecVecData, splittingMatchesPtVecVecData, splittingMatchesHFVecVecData, pairMatchesVecVecData, jetMappingData, candidateMapping, configs.jetPtMinData, 1.0); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputJetsData, "hf jet substructure output Data", false); + + void processOutputJetsDataSub(aod::JetCollision const& collision, + JetTableDataSub const& jets, + soa::Join const& candidates) + { + analyseCharged(collision, jets, candidates, products.collisionOutputTableDataSub, products.jetOutputTableDataSub, products.jetSubstructureOutputTableDataSub, splittingMatchesGeoVecVecDataSub, splittingMatchesPtVecVecDataSub, splittingMatchesHFVecVecDataSub, pairMatchesVecVecDataSub, jetMappingDataSub, candidateMapping, configs.jetPtMinDataSub, 1.0); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputJetsDataSub, "hf jet substructure output event-wise subtracted Data", false); + + void processOutputJetMatchingData(JetMatchedTableData const& jets, + JetTableDataSub const& jetsSub) + { + analyseJetMatched(jets, jetMappingData, jetMappingDataSub, products.jetMatchingOutputTableData, configs.jetPtMinData); + analyseJetMatched(jetsSub, jetMappingDataSub, jetMappingData, products.jetMatchingOutputTableDataSub, configs.jetPtMinDataSub); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputJetMatchingData, "jet matching output Data", false); + + void processOutputSubstructureMatchingMC(JetTableMCD const& jetsMCD, + JetTableMatchedMCP const& jetsMCP, + CandidateTableMCD const&, + CandidateTableMCP const&, + SplittingTableMCD const& splittingsMCD, + SplittingTableMCP const& splittingsMCP, + PairTableMCD const& pairsMCD, + PairTableMCP const& pairsMCP) + { + splittingMatchesGeoVecVecMCD.assign(jetsMCD.size(), {}); + splittingMatchesPtVecVecMCD.assign(jetsMCD.size(), {}); + splittingMatchesHFVecVecMCD.assign(jetsMCD.size(), {}); + pairMatchesVecVecMCD.assign(jetsMCD.size(), {}); + analyseSubstructureMatched(jetsMCD, splittingsMCD, pairsMCD, D0SplittingsPerJetMCD, DplusSplittingsPerJetMCD, LcSplittingsPerJetMCD, BplusSplittingsPerJetMCD, DielectronSplittingsPerJetMCD, D0PairsPerJetMCD, DplusPairsPerJetMCD, LcPairsPerJetMCD, BplusPairsPerJetMCD, DielectronPairsPerJetMCD, splittingMatchesGeoVecVecMCD, splittingMatchesPtVecVecMCD, splittingMatchesHFVecVecMCD, pairMatchesVecVecMCD, configs.jetPtMinMCD); + splittingMatchesGeoVecVecMCP.assign(jetsMCP.size(), {}); + splittingMatchesPtVecVecMCP.assign(jetsMCP.size(), {}); + splittingMatchesHFVecVecMCP.assign(jetsMCP.size(), {}); + pairMatchesVecVecMCP.assign(jetsMCP.size(), {}); + analyseSubstructureMatched(jetsMCP, splittingsMCP, pairsMCP, D0SplittingsPerJetMCP, DplusSplittingsPerJetMCP, LcSplittingsPerJetMCP, BplusSplittingsPerJetMCP, DielectronSplittingsPerJetMCP, D0PairsPerJetMCP, DplusPairsPerJetMCP, LcPairsPerJetMCP, BplusPairsPerJetMCP, DielectronPairsPerJetMCP, splittingMatchesGeoVecVecMCP, splittingMatchesPtVecVecMCP, splittingMatchesHFVecVecMCP, pairMatchesVecVecMCP, configs.jetPtMinMCP); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputSubstructureMatchingMC, "jet substructure matching output MC", false); + + void processOutputJetsMCD(aod::JetCollisionMCD const& collision, + aod::JetMcCollisions const&, + JetTableMCD const& jets, + soa::Join const& candidates) + { + analyseCharged(collision, jets, candidates, products.collisionOutputTableMCD, products.jetOutputTableMCD, products.jetSubstructureOutputTableMCD, splittingMatchesGeoVecVecMCD, splittingMatchesPtVecVecMCD, splittingMatchesHFVecVecMCD, pairMatchesVecVecMCD, jetMappingMCD, candidateMapping, configs.jetPtMinMCD, collision.mcCollision().weight()); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputJetsMCD, "hf jet substructure output MCD", false); + + void processOutputJetsMCP(aod::JetMcCollision const& collision, + JetTableMCP const& jets, + soa::Join const& candidates) + { + analyseCharged(collision, jets, candidates, products.collisionOutputTableMCP, products.jetOutputTableMCP, products.jetSubstructureOutputTableMCP, splittingMatchesGeoVecVecMCP, splittingMatchesPtVecVecMCP, splittingMatchesHFVecVecMCP, pairMatchesVecVecMCP, jetMappingMCP, candidateMappingMCP, configs.jetPtMinMCP, collision.weight()); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputJetsMCP, "hf jet substructure output MCP", false); + + void processOutputJetMatchingMC(JetTableMCD const& jetsMCD, + JetTableMatchedMCP const& jetsMCP) + { + analyseJetMatched(jetsMCD, jetMappingMCD, jetMappingMCP, products.jetMatchingOutputTableMCD, configs.jetPtMinMCD); + analyseJetMatched(jetsMCP, jetMappingMCP, jetMappingMCD, products.jetMatchingOutputTableMCP, configs.jetPtMinMCP); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputJetMatchingMC, "jet matching output MC", false); +}; diff --git a/PWGJE/Tasks/jetSubstructureLc.cxx b/PWGJE/Tasks/jetSubstructureLc.cxx new file mode 100644 index 00000000000..4f2350bb0a6 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureLc.cxx @@ -0,0 +1,28 @@ +// 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. + +// jet substructure Lc charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/Tasks/jetSubstructureHF.cxx" + +using JetSubstructureLc = JetSubstructureHFTask, soa::Join, soa::Join, soa::Join, aod::CandidatesLcData, aod::CandidatesLcMCP, aod::LcCJetSSs, aod::LcChargedSPs, aod::LcChargedPRs, aod::LcCMCDJetSSs, aod::LcChargedMCDetectorLevelSPs, aod::LcChargedMCDetectorLevelPRs, aod::LcCMCPJetSSs, aod::LcChargedMCParticleLevelSPs, aod::LcChargedMCParticleLevelPRs, aod::LcCEWSJetSSs, aod::LcChargedEventWiseSubtractedSPs, aod::LcChargedEventWiseSubtractedPRs, aod::JTrackLcSubs>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-substructure-lc"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetSubstructureLcOutput.cxx b/PWGJE/Tasks/jetSubstructureLcOutput.cxx new file mode 100644 index 00000000000..992dc6e2259 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureLcOutput.cxx @@ -0,0 +1,27 @@ +// 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. + +// jet substructure output Lc charged task +// +/// \author Nima Zardoshti + +#include +#include "PWGJE/Tasks/jetSubstructureHFOutput.cxx" + +using JetSubstructureOutputLc = JetSubstructureHFOutputTask, aod::McCollisionsLc, aod::CandidatesLcData, aod::CandidatesLcMCD, aod::CandidatesLcMCP, aod::BkgLcRhos, aod::BkgLcMcRhos, aod::JTrackLcSubs, soa::Join, soa::Join, soa::Join, soa::Join, aod::LcCJetCOs, aod::LcCJetOs, aod::LcCJetSSOs, aod::LcCJetMOs, soa::Join, soa::Join, soa::Join, aod::LcCMCDJetCOs, aod::LcCMCDJetOs, aod::LcCMCDJetSSOs, aod::LcCMCDJetMOs, soa::Join, soa::Join, soa::Join, soa::Join, aod::LcCMCPJetCOs, aod::LcCMCPJetMCCOs, aod::LcCMCPJetOs, aod::LcCMCPJetSSOs, aod::LcCMCPJetMOs, soa::Join, soa::Join, soa::Join, aod::LcCEWSJetCOs, aod::LcCEWSJetOs, aod::LcCEWSJetSSOs, aod::LcCEWSJetMOs, aod::StoredHfLcCollBase, aod::StoredHfLcBases, aod::StoredHfLcPars, aod::StoredHfLcParEs, aod::JDumLcParDaus, aod::StoredHfLcSels, aod::StoredHfLcMls, aod::JDumLcMlDaus, aod::StoredHfLcMcs, aod::StoredHfLcMcCollBases, aod::StoredHfLcMcRCollIds, aod::StoredHfLcPBases>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-substructure-lc-output"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetSubstructureOutput.cxx b/PWGJE/Tasks/jetSubstructureOutput.cxx new file mode 100644 index 00000000000..fab2581ad2a --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureOutput.cxx @@ -0,0 +1,412 @@ +// 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. + +// jet substructure tree filling task (subscribing to jet finder hf and jet substructure tasks) +// +/// \author Nima Zardoshti +// + +#include +#include +#include +#include + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "TDatabasePDG.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// NB: runDataProcessing.h must be included after customize! +#include "Framework/runDataProcessing.h" + +struct JetSubstructureOutputTask { + + Produces collisionOutputTableData; + Produces jetOutputTableData; + Produces jetSubstructureOutputTableData; + Produces jetMatchingOutputTableData; + Produces collisionOutputTableDataSub; + Produces jetOutputTableDataSub; + Produces jetSubstructureOutputTableDataSub; + Produces jetMatchingOutputTableDataSub; + Produces collisionOutputTableMCD; + Produces jetOutputTableMCD; + Produces jetSubstructureOutputTableMCD; + Produces jetMatchingOutputTableMCD; + Produces collisionOutputTableMCP; + Produces jetOutputTableMCP; + Produces jetSubstructureOutputTableMCP; + Produces jetMatchingOutputTableMCP; + Produces mcCollisionOutputTable; + + Configurable jetPtMinData{"jetPtMinData", 0.0, "minimum jet pT cut for data jets"}; + Configurable jetPtMinDataSub{"jetPtMinDataSub", 0.0, "minimum jet pT cut for eventwise constituent subtracted data jets"}; + Configurable jetPtMinMCD{"jetPtMinMCD", 0.0, "minimum jet pT cut for mcd jets"}; + Configurable jetPtMinMCP{"jetPtMinMCP", 0.0, "minimum jet pT cut for mcp jets"}; + Configurable> jetRadii{"jetRadii", std::vector{0.4}, "jet resolution parameters"}; + Configurable jetEtaMin{"jetEtaMin", -99.0, "minimum jet pseudorapidity"}; + Configurable jetEtaMax{"jetEtaMax", 99.0, "maximum jet pseudorapidity"}; + + Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum track pseudorapidity"}; + Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track pseudorapidity"}; + + std::map jetMappingData; + std::map jetMappingDataSub; + std::map jetMappingMCD; + std::map jetMappingMCP; + + std::vector> splittingMatchesGeoVecVecData; + std::vector> splittingMatchesPtVecVecData; + std::vector> splittingMatchesHFVecVecData; + std::vector> splittingMatchesGeoVecVecDataSub; + std::vector> splittingMatchesPtVecVecDataSub; + std::vector> splittingMatchesHFVecVecDataSub; + std::vector> splittingMatchesGeoVecVecMCD; + std::vector> splittingMatchesPtVecVecMCD; + std::vector> splittingMatchesHFVecVecMCD; + std::vector> splittingMatchesGeoVecVecMCP; + std::vector> splittingMatchesPtVecVecMCP; + std::vector> splittingMatchesHFVecVecMCP; + + std::vector> pairMatchesVecVecData; + std::vector> pairMatchesVecVecDataSub; + std::vector> pairMatchesVecVecMCD; + std::vector> pairMatchesVecVecMCP; + + std::vector jetRadiiValues; + + void init(InitContext const&) + { + jetRadiiValues = (std::vector)jetRadii; + } + + Preslice> splittingsPerJetData = aod::chargedsplitting::jetId; + Preslice> splittingsPerJetDataSub = aod::chargedeventwisesubtractedsplitting::jetId; + Preslice> splittingsPerJetMCD = aod::chargedmcdetectorlevelsplitting::jetId; + Preslice> splittingsPerJetMCP = aod::chargedmcparticlelevelsplitting::jetId; + + Preslice> pairsPerJetData = aod::chargedpair::jetId; + Preslice> pairsPerJetDataSub = aod::chargedeventwisesubtractedpair::jetId; + Preslice> pairsPerJetMCD = aod::chargedmcdetectorlevelpair::jetId; + Preslice> pairsPerJetMCP = aod::chargedmcparticlelevelpair::jetId; + + template + void fillSplittingMatchingVectors(T const& splittingsMatches, int jetIndex, std::vector>& splittingMatchesGeoVecVec, std::vector>& splittingMatchesPtVecVec, std::vector>& splittingMatchesHFVecVec) + { + for (auto const& splittingMatches : splittingsMatches) { + auto splittingMatchesGeoSpan = splittingMatches.splittingMatchingGeo(); + auto splittingMatchesPtSpan = splittingMatches.splittingMatchingPt(); + auto splittingMatchesHFSpan = splittingMatches.splittingMatchingHF(); + std::copy(splittingMatchesGeoSpan.begin(), splittingMatchesGeoSpan.end(), std::back_inserter(splittingMatchesGeoVecVec[jetIndex])); + std::copy(splittingMatchesPtSpan.begin(), splittingMatchesPtSpan.end(), std::back_inserter(splittingMatchesPtVecVec[jetIndex])); + std::copy(splittingMatchesHFSpan.begin(), splittingMatchesHFSpan.end(), std::back_inserter(splittingMatchesHFVecVec[jetIndex])); + } + } + + template + void fillPairMatchingVectors(T const& pairsMatches, int jetIndex, std::vector>& pairMatchesVecVec) + { + for (auto const& pairMatches : pairsMatches) { + auto pairMatchesSpan = pairMatches.pairMatching(); + std::copy(pairMatchesSpan.begin(), pairMatchesSpan.end(), std::back_inserter(pairMatchesVecVec[jetIndex])); + } + } + + template + void fillJetTables(T const& jet, int32_t collisionIndex, U& jetOutputTable, V& jetSubstructureOutputTable, std::vector>& splittingMatchesGeoVecVec, std::vector>& splittingMatchesPtVecVec, std::vector>& splittingMatchesHFVecVec, std::vector>& pairMatchesVecVec, float rho, std::map& jetMapping) + { + std::vector energyMotherVec; + std::vector ptLeadingVec; + std::vector ptSubLeadingVec; + std::vector thetaVec; + std::vector pairJetPtVec; + std::vector pairJetEnergyVec; + std::vector pairJetThetaVec; + std::vector pairJetPerpCone1PtVec; + std::vector pairJetPerpCone1EnergyVec; + std::vector pairJetPerpCone1ThetaVec; + std::vector pairPerpCone1PerpCone1PtVec; + std::vector pairPerpCone1PerpCone1EnergyVec; + std::vector pairPerpCone1PerpCone1ThetaVec; + std::vector pairPerpCone1PerpCone2PtVec; + std::vector pairPerpCone1PerpCone2EnergyVec; + std::vector pairPerpCone1PerpCone2ThetaVec; + + auto energyMotherSpan = jet.energyMother(); + auto ptLeadingSpan = jet.ptLeading(); + auto ptSubLeadingSpan = jet.ptSubLeading(); + auto thetaSpan = jet.theta(); + auto pairJetPtSpan = jet.pairJetPt(); + auto pairJetEnergySpan = jet.pairJetEnergy(); + auto pairJetThetaSpan = jet.pairJetTheta(); + auto pairJetPerpCone1PtSpan = jet.pairJetPerpCone1Pt(); + auto pairJetPerpCone1EnergySpan = jet.pairJetPerpCone1Energy(); + auto pairJetPerpCone1ThetaSpan = jet.pairJetPerpCone1Theta(); + auto pairPerpCone1PerpCone1PtSpan = jet.pairPerpCone1PerpCone1Pt(); + auto pairPerpCone1PerpCone1EnergySpan = jet.pairPerpCone1PerpCone1Energy(); + auto pairPerpCone1PerpCone1ThetaSpan = jet.pairPerpCone1PerpCone1Theta(); + auto pairPerpCone1PerpCone2PtSpan = jet.pairPerpCone1PerpCone2Pt(); + auto pairPerpCone1PerpCone2EnergySpan = jet.pairPerpCone1PerpCone2Energy(); + auto pairPerpCone1PerpCone2ThetaSpan = jet.pairPerpCone1PerpCone2Theta(); + + std::copy(energyMotherSpan.begin(), energyMotherSpan.end(), std::back_inserter(energyMotherVec)); + std::copy(ptLeadingSpan.begin(), ptLeadingSpan.end(), std::back_inserter(ptLeadingVec)); + std::copy(ptSubLeadingSpan.begin(), ptSubLeadingSpan.end(), std::back_inserter(ptSubLeadingVec)); + std::copy(thetaSpan.begin(), thetaSpan.end(), std::back_inserter(thetaVec)); + std::copy(pairJetPtSpan.begin(), pairJetPtSpan.end(), std::back_inserter(pairJetPtVec)); + std::copy(pairJetEnergySpan.begin(), pairJetEnergySpan.end(), std::back_inserter(pairJetEnergyVec)); + std::copy(pairJetThetaSpan.begin(), pairJetThetaSpan.end(), std::back_inserter(pairJetThetaVec)); + std::copy(pairJetPerpCone1PtSpan.begin(), pairJetPerpCone1PtSpan.end(), std::back_inserter(pairJetPerpCone1PtVec)); + std::copy(pairJetPerpCone1EnergySpan.begin(), pairJetPerpCone1EnergySpan.end(), std::back_inserter(pairJetPerpCone1EnergyVec)); + std::copy(pairJetPerpCone1ThetaSpan.begin(), pairJetPerpCone1ThetaSpan.end(), std::back_inserter(pairJetPerpCone1ThetaVec)); + std::copy(pairPerpCone1PerpCone1PtSpan.begin(), pairPerpCone1PerpCone1PtSpan.end(), std::back_inserter(pairPerpCone1PerpCone1PtVec)); + std::copy(pairPerpCone1PerpCone1EnergySpan.begin(), pairPerpCone1PerpCone1EnergySpan.end(), std::back_inserter(pairPerpCone1PerpCone1EnergyVec)); + std::copy(pairPerpCone1PerpCone1ThetaSpan.begin(), pairPerpCone1PerpCone1ThetaSpan.end(), std::back_inserter(pairPerpCone1PerpCone1ThetaVec)); + std::copy(pairPerpCone1PerpCone2PtSpan.begin(), pairPerpCone1PerpCone2PtSpan.end(), std::back_inserter(pairPerpCone1PerpCone2PtVec)); + std::copy(pairPerpCone1PerpCone2EnergySpan.begin(), pairPerpCone1PerpCone2EnergySpan.end(), std::back_inserter(pairPerpCone1PerpCone2EnergyVec)); + std::copy(pairPerpCone1PerpCone2ThetaSpan.begin(), pairPerpCone1PerpCone2ThetaSpan.end(), std::back_inserter(pairPerpCone1PerpCone2ThetaVec)); + + std::vector splittingMatchesGeoVec; + std::vector splittingMatchesPtVec; + std::vector splittingMatchesHFVec; + std::vector pairMatchesVec; + if (doprocessOutputSubstructureMatchingData || doprocessOutputSubstructureMatchingMC) { + splittingMatchesGeoVec = splittingMatchesGeoVecVec[jet.globalIndex()]; + splittingMatchesPtVec = splittingMatchesPtVecVec[jet.globalIndex()]; + splittingMatchesHFVec = splittingMatchesHFVecVec[jet.globalIndex()]; + pairMatchesVec = pairMatchesVecVec[jet.globalIndex()]; + } + jetOutputTable(collisionIndex, collisionIndex, jet.pt(), jet.phi(), jet.eta(), jet.y(), jet.r(), jet.area(), rho, jet.perpConeRho(), jet.tracksIds().size()); // second collision index is a dummy coloumn mirroring the hf candidate + jetSubstructureOutputTable(jetOutputTable.lastIndex(), energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec, jet.nSub2DR(), jet.nSub1(), jet.nSub2(), pairJetPtVec, pairJetEnergyVec, pairJetThetaVec, pairJetPerpCone1PtVec, pairJetPerpCone1EnergyVec, pairJetPerpCone1ThetaVec, pairPerpCone1PerpCone1PtVec, pairPerpCone1PerpCone1EnergyVec, pairPerpCone1PerpCone1ThetaVec, pairPerpCone1PerpCone2PtVec, pairPerpCone1PerpCone2EnergyVec, pairPerpCone1PerpCone2ThetaVec, jet.angularity(), jet.ptLeadingConstituent(), splittingMatchesGeoVec, splittingMatchesPtVec, splittingMatchesHFVec, pairMatchesVec); + jetMapping.insert(std::make_pair(jet.globalIndex(), jetOutputTable.lastIndex())); + } + + template + void analyseCharged(T const& collision, U const& jets, V& collisionOutputTable, M& jetOutputTable, N& jetSubstructureOutputTable, std::vector>& splittingMatchesGeoVecVec, std::vector>& splittingMatchesPtVecVec, std::vector>& splittingMatchesHFVecVec, std::vector>& pairMatchesVecVec, std::map& jetMapping, float jetPtMin, float eventWeight) + { + int nJetInCollision = 0; + int32_t collisionIndex = -1; + for (const auto& jet : jets) { + if (jet.pt() < jetPtMin) { + continue; + } + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + for (const auto& jetRadiiValue : jetRadiiValues) { + if (jet.r() == round(jetRadiiValue * 100.0f)) { + if (nJetInCollision == 0) { + float centrality = -1.0; + uint8_t eventSel = 0.0; + if constexpr (!isMCP) { + centrality = collision.centrality(); + eventSel = collision.eventSel(); + } + collisionOutputTable(collision.posZ(), centrality, eventSel, eventWeight); + collisionIndex = collisionOutputTable.lastIndex(); + } + nJetInCollision++; + fillJetTables(jet, collisionIndex, jetOutputTable, jetSubstructureOutputTable, splittingMatchesGeoVecVec, splittingMatchesPtVecVec, splittingMatchesHFVecVec, pairMatchesVecVec, collision.rho(), jetMapping); + } + } + } + } + + template + void analyseSubstructureMatched(T const& jets, U const& allSplittings, V const& allPairs, M const& splittingsSlicer, N const& pairsSlicer, std::vector>& splittingMatchesGeoVecVec, std::vector>& splittingMatchesPtVecVec, std::vector>& splittingMatchesHFVecVec, std::vector>& pairMatchesVecVec, float jetPtMin) + { + for (const auto& jet : jets) { + if (jet.pt() < jetPtMin) { + continue; + } + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + for (const auto& jetRadiiValue : jetRadiiValues) { + if (jet.r() == round(jetRadiiValue * 100.0f)) { + + auto splittings = allSplittings.sliceBy(splittingsSlicer, jet.globalIndex()); + fillSplittingMatchingVectors(splittings, jet.globalIndex(), splittingMatchesGeoVecVec, splittingMatchesPtVecVec, splittingMatchesHFVecVec); + + auto pairs = allPairs.sliceBy(pairsSlicer, jet.globalIndex()); + fillPairMatchingVectors(pairs, jet.globalIndex(), pairMatchesVecVec); + } + } + } + } + + template + void analyseJetMatched(T const& jets, std::map& jetMapping, std::map& jetTagMapping, U& matchingOutputTable, float jetPtMin) + { + std::vector candMatching; + for (const auto& jet : jets) { + if (jet.pt() < jetPtMin) { + continue; + } + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + for (const auto& jetRadiiValue : jetRadiiValues) { + if (jet.r() == round(jetRadiiValue * 100.0f)) { + std::vector geoMatching; + std::vector ptMatching; + if (jet.has_matchedJetGeo()) { + for (auto& jetTagId : jet.matchedJetGeoIds()) { + auto jetTagIndex = jetTagMapping.find(jetTagId); + if (jetTagIndex != jetTagMapping.end()) { + geoMatching.push_back(jetTagIndex->second); + } + } + } + if (jet.has_matchedJetPt()) { + for (auto& jetTagId : jet.matchedJetPtIds()) { + auto jetTagIndex = jetTagMapping.find(jetTagId); + if (jetTagIndex != jetTagMapping.end()) { + ptMatching.push_back(jetTagIndex->second); + } + } + } + int storedJetIndex = -1; + auto jetIndex = jetMapping.find(jet.globalIndex()); + if (jetIndex != jetMapping.end()) { + storedJetIndex = jetIndex->second; + } + matchingOutputTable(storedJetIndex, geoMatching, ptMatching, candMatching); + } + } + } + } + + void processClearMaps(aod::JetCollisions const&) + { + jetMappingData.clear(); + jetMappingDataSub.clear(); + jetMappingMCD.clear(); + } + PROCESS_SWITCH(JetSubstructureOutputTask, processClearMaps, "process function that clears all the non-mcp maps in each dataframe", true); + + void processClearMapsMCP(aod::JetMcCollisions const& mcCollisions) + { + jetMappingMCP.clear(); + for (auto mcCollision : mcCollisions) { + mcCollisionOutputTable(mcCollision.posZ(), mcCollision.accepted(), mcCollision.attempted(), mcCollision.xsectGen(), mcCollision.xsectErr(), mcCollision.weight()); + } + } + PROCESS_SWITCH(JetSubstructureOutputTask, processClearMapsMCP, "process function that clears all the mcp maps in each dataframe", true); + + void processOutputSubstructureMatchingData(soa::Join const& jets, + soa::Join const& jetsSub, + soa::Join const& splittingsData, + soa::Join const& splittingsDataSub, + soa::Join const& pairsData, + soa::Join const& pairsDataSub) + { + splittingMatchesGeoVecVecData.assign(jets.size(), {}); + splittingMatchesPtVecVecData.assign(jets.size(), {}); + splittingMatchesHFVecVecData.assign(jets.size(), {}); + pairMatchesVecVecData.assign(jets.size(), {}); + analyseSubstructureMatched(jets, splittingsData, pairsData, splittingsPerJetData, pairsPerJetData, splittingMatchesGeoVecVecData, splittingMatchesPtVecVecData, splittingMatchesHFVecVecData, pairMatchesVecVecData, jetPtMinData); + splittingMatchesGeoVecVecDataSub.assign(jetsSub.size(), {}); + splittingMatchesPtVecVecDataSub.assign(jetsSub.size(), {}); + splittingMatchesHFVecVecDataSub.assign(jetsSub.size(), {}); + pairMatchesVecVecDataSub.assign(jetsSub.size(), {}); + analyseSubstructureMatched(jetsSub, splittingsDataSub, pairsDataSub, splittingsPerJetDataSub, pairsPerJetDataSub, splittingMatchesGeoVecVecDataSub, splittingMatchesPtVecVecDataSub, splittingMatchesHFVecVecDataSub, pairMatchesVecVecDataSub, jetPtMinDataSub); + } + PROCESS_SWITCH(JetSubstructureOutputTask, processOutputSubstructureMatchingData, "substructure matching output Data", false); + + void processOutputData(soa::Join::iterator const& collision, + soa::Join const& jets) + { + analyseCharged(collision, jets, collisionOutputTableData, jetOutputTableData, jetSubstructureOutputTableData, splittingMatchesGeoVecVecData, splittingMatchesPtVecVecData, splittingMatchesHFVecVecData, pairMatchesVecVecData, jetMappingData, jetPtMinData, 1.0); + } + PROCESS_SWITCH(JetSubstructureOutputTask, processOutputData, "jet substructure output Data", false); + + void processOutputDataSub(soa::Join::iterator const& collision, + soa::Join const& jets) + { + analyseCharged(collision, jets, collisionOutputTableDataSub, jetOutputTableDataSub, jetSubstructureOutputTableDataSub, splittingMatchesGeoVecVecDataSub, splittingMatchesPtVecVecDataSub, splittingMatchesHFVecVecDataSub, pairMatchesVecVecDataSub, jetMappingDataSub, jetPtMinDataSub, 1.0); + } + PROCESS_SWITCH(JetSubstructureOutputTask, processOutputDataSub, "jet substructure output event-wise subtracted Data", false); + + void processOutputJetMatchingData(soa::Join const& jets, + soa::Join const& jetsSub) + { + analyseJetMatched(jets, jetMappingData, jetMappingDataSub, jetMatchingOutputTableData, jetPtMinData); + analyseJetMatched(jetsSub, jetMappingDataSub, jetMappingData, jetMatchingOutputTableDataSub, jetPtMinDataSub); + } + PROCESS_SWITCH(JetSubstructureOutputTask, processOutputJetMatchingData, "jet matching output Data", false); + + void processOutputSubstructureMatchingMC(soa::Join const& jetsMCD, + soa::Join const& jetsMCP, + soa::Join const& splittingsMCD, + soa::Join const& splittingsMCP, + soa::Join const& pairsMCD, + soa::Join const& pairsMCP) + { + splittingMatchesGeoVecVecMCD.assign(jetsMCD.size(), {}); + splittingMatchesPtVecVecMCD.assign(jetsMCD.size(), {}); + splittingMatchesHFVecVecMCD.assign(jetsMCD.size(), {}); + pairMatchesVecVecMCD.assign(jetsMCD.size(), {}); + analyseSubstructureMatched(jetsMCD, splittingsMCD, pairsMCD, splittingsPerJetMCD, pairsPerJetMCD, splittingMatchesGeoVecVecMCD, splittingMatchesPtVecVecMCD, splittingMatchesHFVecVecMCD, pairMatchesVecVecMCD, jetPtMinMCD); + splittingMatchesGeoVecVecMCP.assign(jetsMCP.size(), {}); + splittingMatchesPtVecVecMCP.assign(jetsMCP.size(), {}); + splittingMatchesHFVecVecMCP.assign(jetsMCP.size(), {}); + pairMatchesVecVecMCP.assign(jetsMCP.size(), {}); + analyseSubstructureMatched(jetsMCP, splittingsMCP, pairsMCP, splittingsPerJetMCP, pairsPerJetMCP, splittingMatchesGeoVecVecMCP, splittingMatchesPtVecVecMCP, splittingMatchesHFVecVecMCP, pairMatchesVecVecMCP, jetPtMinMCP); + } + PROCESS_SWITCH(JetSubstructureOutputTask, processOutputSubstructureMatchingMC, "substructure matching output MC", false); + + void processOutputMCD(soa::Join::iterator const& collision, aod::JetMcCollisions const&, + soa::Join const& jets) + { + analyseCharged(collision, jets, collisionOutputTableMCD, jetOutputTableMCD, jetSubstructureOutputTableMCD, splittingMatchesGeoVecVecMCD, splittingMatchesPtVecVecMCD, splittingMatchesHFVecVecMCD, pairMatchesVecVecMCD, jetMappingMCD, jetPtMinMCD, collision.mcCollision().weight()); + } + PROCESS_SWITCH(JetSubstructureOutputTask, processOutputMCD, "jet substructure output MCD", false); + + void processOutputMCP(soa::Join::iterator const& collision, + soa::Join const& jets) + { + analyseCharged(collision, jets, collisionOutputTableMCP, jetOutputTableMCP, jetSubstructureOutputTableMCP, splittingMatchesGeoVecVecMCP, splittingMatchesPtVecVecMCP, splittingMatchesHFVecVecMCP, pairMatchesVecVecMCP, jetMappingMCP, jetPtMinMCP, collision.weight()); + } + PROCESS_SWITCH(JetSubstructureOutputTask, processOutputMCP, "jet substructure output MCP", false); + + void processOutputJetMatchingMC(soa::Join const& jetsMCD, + soa::Join const& jetsMCP) + { + analyseJetMatched(jetsMCD, jetMappingMCD, jetMappingMCP, jetMatchingOutputTableMCD, jetPtMinMCD); + analyseJetMatched(jetsMCP, jetMappingMCP, jetMappingMCD, jetMatchingOutputTableMCP, jetPtMinMCP); + } + PROCESS_SWITCH(JetSubstructureOutputTask, processOutputJetMatchingMC, "jet matching output MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + + return WorkflowSpec{adaptAnalysisTask( + cfgc, TaskName{"jet-substructure-output"})}; +} diff --git a/PWGJE/Tasks/jetTaggerHFQA.cxx b/PWGJE/Tasks/jetTaggerHFQA.cxx new file mode 100644 index 00000000000..2f51f5e787f --- /dev/null +++ b/PWGJE/Tasks/jetTaggerHFQA.cxx @@ -0,0 +1,1541 @@ +// 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 jetTaggerHFQA.cxx +/// \brief Jet tagging general QA +/// +/// \author Hanseo Park + +#include +#include +#include +#include + +#include "TF1.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "Common/Core/trackUtilities.h" + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetTagging.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/Core/JetTaggingUtilities.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +template +struct JetTaggerHFQA { + + // task on/off configuration + Configurable fillIPxy{"fillIPxy", true, "process of xy plane of dca"}; + Configurable fillIPz{"fillIPz", false, "process of z plane of dca"}; + Configurable fillIPxyz{"fillIPxyz", false, "process of xyz plane of dca"}; + Configurable fillTrackCounting{"fillTrackCounting", false, "process of track counting method"}; + Configurable fillGeneralSVQA{"fillGeneralSVQA", true, "process of general QA for sv"}; + + // Cut configuration + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum eta acceptance for tracks"}; + Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum eta acceptance for tracks"}; + Configurable trackPtMin{"trackPtMin", 0.15, "minimum pT acceptance for tracks"}; + Configurable trackPtMax{"trackPtMax", 100.0, "maximum pT acceptance for tracks"}; + Configurable trackDcaXYMax{"trackDcaXYMax", 1, "minimum DCA xy acceptance for tracks [cm]"}; + Configurable trackDcaZMax{"trackDcaZMax", 2, "minimum DCA z acceptance for tracks [cm]"}; + Configurable maxDeltaR{"maxDeltaR", 0.25, "maximum distance of jet axis from flavour initiating parton"}; + Configurable jetEtaMin{"jetEtaMin", -99.0, "minimum jet pseudorapidity"}; + Configurable jetEtaMax{"jetEtaMax", 99.0, "maximum jet pseudorapidity"}; + Configurable prongChi2PCAMin{"prongChi2PCAMin", 1, "minimum Chi2 PCA of decay length of prongs"}; + Configurable prongChi2PCAMax{"prongChi2PCAMax", 100, "maximum Chi2 PCA of decay length of prongs"}; + Configurable prongsigmaLxyMax{"prongsigmaLxyMax", 100, "maximum sigma of decay length of prongs on xy plane"}; + Configurable prongsigmaLxyzMax{"prongsigmaLxyzMax", 100, "maximum sigma of decay length of prongs on xyz plane"}; + Configurable prongIPxyMin{"prongIPxyMin", 0.008, "maximum impact paramter of prongs on xy plane"}; + Configurable prongIPxyMax{"prongIPxyMax", 1, "minimum impact parmeter of prongs on xy plane"}; + Configurable svDispersionMax{"svDispersionMax", 0.03f, "maximum dispersion of sv"}; + Configurable numFlavourSpecies{"numFlavourSpecies", 6, "number of jet flavour species"}; + Configurable numOrder{"numOrder", 6, "number of ordering"}; + Configurable pTHatMaxMCD{"pTHatMaxMCD", 999.0, "maximum fraction of hard scattering for jet acceptance in detector MC"}; + Configurable pTHatMaxMCP{"pTHatMaxMCP", 999.0, "maximum fraction of hard scattering for jet acceptance in particle MC"}; + Configurable pTHatExponent{"pTHatExponent", 6.0, "exponent of the event weight for the calculation of pTHat"}; + Configurable jetAreaFractionMin{"jetAreaFractionMin", -99.0, "used to make a cut on the jet areas"}; + Configurable leadingConstituentPtMin{"leadingConstituentPtMin", -99.0, "minimum pT selection on jet constituent"}; + Configurable leadingConstituentPtMax{"leadingConstituentPtMax", 9999.0, "maximum pT selection on jet constituent"}; + Configurable checkMcCollisionIsMatched{"checkMcCollisionIsMatched", false, "0: count whole MCcollisions, 1: select MCcollisions which only have their correspond collisions"}; + Configurable trackOccupancyInTimeRangeMax{"trackOccupancyInTimeRangeMax", 999999, "maximum occupancy of tracks in neighbouring collisions in a given time range; only applied to reconstructed collisions (data and mcd jets), not mc collisions (mcp jets)"}; + Configurable trackOccupancyInTimeRangeMin{"trackOccupancyInTimeRangeMin", -999999, "minimum occupancy of tracks in neighbouring collisions in a given time range; only applied to reconstructed collisions (data and mcd jets), not mc collisions (mcp jets)"}; + Configurable useQuarkDef{"useQuarkDef", true, "Flag whether to use quarks or hadrons for determining the jet flavor"}; + + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + // Binning + ConfigurableAxis binJetFlavour{"binJetFlavour", {6, -0.5, 5.5}, ""}; + ConfigurableAxis binJetPt{"binJetPt", {200, 0., 200.}, ""}; + ConfigurableAxis binEta{"binEta", {100, -1.f, 1.f}, ""}; + ConfigurableAxis binPhi{"binPhi", {18 * 8, 0.f, o2::constants::math::TwoPI}, ""}; + ConfigurableAxis binNtracks{"binNtracks", {100, 0., 100.}, ""}; + ConfigurableAxis binTrackPt{"binTrackPt", {200, 0.f, 100.f}, ""}; + ConfigurableAxis binImpactParameterXY{"binImpactParameterXY", {801, -400.5f, 400.5f}, ""}; + ConfigurableAxis binSigmaImpactParameterXY{"binSigmaImpactParameterXY", {800, 0.f, 100.f}, ""}; + ConfigurableAxis binImpactParameterXYSignificance{"binImpactParameterXYSignificance", {801, -40.5f, 40.5f}, ""}; + ConfigurableAxis binImpactParameterZ{"binImpactParameterZ", {801, -400.5f, 400.5f}, ""}; + ConfigurableAxis binImpactParameterZSignificance{"binImpactParameterZSignificance", {801, -40.5f, 40.5f}, ""}; + ConfigurableAxis binImpactParameterXYZ{"binImpactParameterXYZ", {2001, -1000.5f, 1000.5f}, ""}; + ConfigurableAxis binImpactParameterXYZSignificance{"binImpactParameterXYZSignificance", {2001, -100.5f, 100.5f}, ""}; + ConfigurableAxis binNumOrder{"binNumOrder", {6, 0.5, 6.5}, ""}; + ConfigurableAxis binJetProbability{"binJetProbability", {100, 0.f, 1.f}, ""}; + ConfigurableAxis binJetProbabilityLog{"binJetProbabilityLog", {100, 0.f, 10.f}, ""}; + ConfigurableAxis binNprongs{"binNprongs", {100, 0., 100.}, ""}; + ConfigurableAxis binLxy{"binLxy", {200, 0, 20.f}, ""}; + ConfigurableAxis binSxy{"binSxy", {1000, 0, 1000.f}, ""}; + ConfigurableAxis binLxyz{"binLxyz", {200, 0, 20.f}, ""}; + ConfigurableAxis binSxyz{"binSxyz", {1000, 0, 1000.f}, ""}; + ConfigurableAxis binMass{"binMass", {50, 0, 10.f}, ""}; + ConfigurableAxis binSigmaLxy{"binSigmaLxy", {100, 0., 0.1}, ""}; + ConfigurableAxis binSigmaLxyz{"binSigmaLxyz", {100, 0., 0.1}, ""}; + + int numberOfJetFlavourSpecies = 6; + std::vector eventSelectionBits; + int trackSelection = -1; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext const&) + { + numberOfJetFlavourSpecies = static_cast(numFlavourSpecies); + + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + // Axis + AxisSpec axisJetFlavour = {binJetFlavour, "Jet flavour"}; + AxisSpec axisJetPt = {binJetPt, "#it{p}_{T, jet}"}; + AxisSpec axisEta = {binEta, "#eta"}; + AxisSpec axisPhi = {binPhi, "#phi"}; + AxisSpec axisNTracks = {binNtracks, "#it{N}_{tracks}"}; + AxisSpec axisTrackPt = {binTrackPt, "#it{p}_{T}^{track}"}; + AxisSpec axisImpactParameterXY = {binImpactParameterXY, "IP_{XY} [#mum]"}; + AxisSpec axisSigmaImpactParameterXY = {binSigmaImpactParameterXY, "#sigma_{XY} [#mum]"}; + AxisSpec axisImpactParameterXYSignificance = {binImpactParameterXYSignificance, "IPs_{XY}"}; + AxisSpec axisImpactParameterZ = {binImpactParameterZ, "IP_{Z} [#mum]"}; + AxisSpec axisImpactParameterZSignificance = {binImpactParameterZSignificance, "IPs_{Z}"}; + AxisSpec axisImpactParameterXYZ = {binImpactParameterXYZ, "IP_{XYZ} [#mum]"}; + AxisSpec axisImpactParameterXYZSignificance = {binImpactParameterXYZSignificance, "IPs_{XYZ}"}; + AxisSpec axisNumOrder = {binNumOrder, "N_{order}"}; + AxisSpec axisJetProbability = {binJetProbability, "JP"}; + AxisSpec axisJetProbabilityLog = {binJetProbabilityLog, "-Log(JP)"}; + AxisSpec axisNprongs = {binNprongs, "#it{N}_{SV}"}; + AxisSpec axisLxy = {binLxy, "L_{XY} [cm]"}; + AxisSpec axisSxy = {binSxy, "S_{XY}"}; + AxisSpec axisLxyz = {binLxyz, "L_{XYZ} [cm]"}; + AxisSpec axisSxyz = {binSxyz, "S_{XYZ}"}; + AxisSpec axisMass = {binMass, "#it{m}_{SV}"}; + AxisSpec axisSigmaLxy = {binSigmaLxy, "#sigma_{L_{XY}} [cm]"}; + AxisSpec axisSigmaLxyz = {binSigmaLxyz, "#sigma_{L_{XYZ}} [cm]"}; + + if (doprocessTracksDca) { + registry.add("h_impact_parameter_xy", "", {HistType::kTH1F, {{axisImpactParameterXY}}}); + registry.add("h_impact_parameter_xy_significance", "", {HistType::kTH1F, {{axisImpactParameterXYSignificance}}}); + registry.add("h_impact_parameter_z", "", {HistType::kTH1F, {{axisImpactParameterZ}}}); + registry.add("h_impact_parameter_z_significance", "", {HistType::kTH1F, {{axisImpactParameterZSignificance}}}); + registry.add("h_impact_parameter_xyz", "", {HistType::kTH1F, {{axisImpactParameterXYZ}}}); + registry.add("h_impact_parameter_xyz_significance", "", {HistType::kTH1F, {{axisImpactParameterXYZSignificance}}}); + } + if (doprocessValFlavourDefMCD) { + registry.add("h2_flavour_dist_quark_flavour_dist_hadron", "", {HistType::kTH2F, {{axisJetFlavour}, {axisJetFlavour}}}); + registry.add("h2_flavour_const_quark_flavour_const_hadron", "", {HistType::kTH2F, {{axisJetFlavour}, {axisJetFlavour}}}); + registry.add("h2_flavour_const_hadron_flavour_dist_hadron", "", {HistType::kTH2F, {{axisJetFlavour}, {axisJetFlavour}}}); + registry.add("h2_flavour_const_quark_flavour_dist_quark", "", {HistType::kTH2F, {{axisJetFlavour}, {axisJetFlavour}}}); + } + if (doprocessValFlavourDefMCP) { + registry.add("h2_part_flavour_dist_quark_part_flavour_dist_hadron", "", {HistType::kTH2F, {{axisJetFlavour}, {axisJetFlavour}}}); + registry.add("h2_part_flavour_const_quark_part_flavour_const_hadron", "", {HistType::kTH2F, {{axisJetFlavour}, {axisJetFlavour}}}); + registry.add("h2_part_flavour_const_hadron_part_flavour_dist_hadron", "", {HistType::kTH2F, {{axisJetFlavour}, {axisJetFlavour}}}); + registry.add("h2_part_flavour_const_quark_part_flavour_dist_quark", "", {HistType::kTH2F, {{axisJetFlavour}, {axisJetFlavour}}}); + } + if (doprocessIPsData) { + registry.add("h_jet_pt", "", {HistType::kTH1F, {{axisJetPt}}}); + registry.add("h_jet_eta", "", {HistType::kTH1F, {{axisEta}}}); + registry.add("h_jet_phi", "", {HistType::kTH1F, {{axisPhi}}}); + registry.add("h3_jet_pt_track_pt_track_eta", "", {HistType::kTH3F, {{axisJetPt}, {axisTrackPt}, {axisEta}}}); + registry.add("h3_jet_pt_track_pt_track_phi", "", {HistType::kTH3F, {{axisJetPt}, {axisTrackPt}, {axisPhi}}}); + if (fillIPxy) { + registry.add("h2_jet_pt_impact_parameter_xy", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterXY}}}); + registry.add("h2_jet_pt_sign_impact_parameter_xy", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterXY}}}); + registry.add("h2_jet_pt_impact_parameter_xy_significance", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterXYSignificance}}}); + registry.add("h3_jet_pt_track_pt_sign_impact_parameter_xy_significance", "", {HistType::kTH3F, {{axisJetPt}, {axisTrackPt}, {axisImpactParameterXYSignificance}}}); + } + if (fillIPz) { + registry.add("h2_jet_pt_impact_parameter_z", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterZ}}}); + registry.add("h2_jet_pt_sign_impact_parameter_z", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterZ}}}); + registry.add("h2_jet_pt_impact_parameter_z_significance", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterZSignificance}}}); + registry.add("h3_jet_pt_track_pt_sign_impact_parameter_z_significance", "", {HistType::kTH3F, {{axisJetPt}, {axisTrackPt}, {axisImpactParameterZSignificance}}}); + } + if (fillIPxyz) { + registry.add("h2_jet_pt_impact_parameter_xyz", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterXYZ}}}); + registry.add("h2_jet_pt_sign_impact_parameter_xyz", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterXYZ}}}); + registry.add("h2_jet_pt_impact_parameter_xyz_significance", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterXYZSignificance}}}); + registry.add("h3_jet_pt_track_pt_sign_impact_parameter_xyz_significance", "", {HistType::kTH3F, {{axisJetPt}, {axisTrackPt}, {axisImpactParameterXYZSignificance}}}); + } + if (fillTrackCounting) { + registry.add("h2_jet_pt_sign_impact_parameter_xy_significance_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterXYSignificance}}}); + registry.add("h2_jet_pt_sign_impact_parameter_xy_significance_N2", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterXYSignificance}}}); + registry.add("h2_jet_pt_sign_impact_parameter_xy_significance_N3", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterXYSignificance}}}); + registry.add("h2_jet_pt_sign_impact_parameter_z_significance_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterXYSignificance}}}); + registry.add("h2_jet_pt_sign_impact_parameter_z_significance_N2", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterXYSignificance}}}); + registry.add("h2_jet_pt_sign_impact_parameter_z_significance_N3", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterXYSignificance}}}); + registry.add("h2_jet_pt_sign_impact_parameter_xyz_significance_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterXYSignificance}}}); + registry.add("h2_jet_pt_sign_impact_parameter_xyz_significance_N2", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterXYSignificance}}}); + registry.add("h2_jet_pt_sign_impact_parameter_xyz_significance_N3", "", {HistType::kTH2F, {{axisJetPt}, {axisImpactParameterXYSignificance}}}); + registry.add("h3_jet_pt_sign_impact_parameter_xy_significance_tc", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXYSignificance}, {axisNumOrder}}}); + registry.add("h3_jet_pt_sign_impact_parameter_z_significance_tc", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterZSignificance}, {axisNumOrder}}}); + registry.add("h3_jet_pt_sign_impact_parameter_xyz_significance_tc", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXYZSignificance}, {axisNumOrder}}}); + registry.add("h3_track_pt_sign_impact_parameter_xy_significance_tc", "", {HistType::kTH3F, {{axisTrackPt}, {axisImpactParameterXYSignificance}, {axisNumOrder}}}); + registry.add("h3_track_pt_sign_impact_parameter_z_significance_tc", "", {HistType::kTH3F, {{axisTrackPt}, {axisImpactParameterZSignificance}, {axisNumOrder}}}); + registry.add("h3_track_pt_sign_impact_parameter_xyz_significance_tc", "", {HistType::kTH3F, {{axisTrackPt}, {axisImpactParameterXYZSignificance}, {axisNumOrder}}}); + } + } + if (doprocessIPsMCD || doprocessIPsMCDWeighted || doprocessIPsMCPMCDMatched || doprocessIPsMCPMCDMatchedWeighted) { + registry.add("h2_jet_pt_flavour", "", {HistType::kTH2F, {{axisJetPt}, {axisJetFlavour}}}); + registry.add("h2_jet_eta_flavour", "", {HistType::kTH2F, {{axisEta}, {axisJetFlavour}}}); + registry.add("h2_jet_phi_flavour", "", {HistType::kTH2F, {{axisPhi}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_track_pt_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisTrackPt}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_track_eta_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisEta}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_track_phi_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisPhi}, {axisJetFlavour}}}); + if (fillIPxy) { + registry.add("h3_jet_pt_impact_parameter_xy_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXY}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_sigma_impact_parameter_xy_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisSigmaImpactParameterXY}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_sign_impact_parameter_xy_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXY}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_impact_parameter_xy_significance_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXYSignificance}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_sign_impact_parameter_xy_significance_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXYSignificance}, {axisJetFlavour}}}); + registry.add("h3_track_pt_impact_parameter_xy_flavour", "", {HistType::kTH3F, {{axisTrackPt}, {axisImpactParameterXY}, {axisJetFlavour}}}); + registry.add("h3_track_pt_sign_impact_parameter_xy_flavour", "", {HistType::kTH3F, {{axisTrackPt}, {axisImpactParameterXY}, {axisJetFlavour}}}); + registry.add("h3_track_pt_impact_parameter_xy_significance_flavour", "", {HistType::kTH3F, {{axisTrackPt}, {axisImpactParameterXYSignificance}, {axisJetFlavour}}}); + registry.add("h3_track_pt_sign_impact_parameter_xy_significance_flavour", "", {HistType::kTH3F, {{axisTrackPt}, {axisImpactParameterXYSignificance}, {axisJetFlavour}}}); + } + if (fillIPz) { + registry.add("h3_jet_pt_impact_parameter_z_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterZ}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_sign_impact_parameter_z_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterZ}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_impact_parameter_z_significance_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterZSignificance}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_sign_impact_parameter_z_significance_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterZSignificance}, {axisJetFlavour}}}); + registry.add("h3_track_pt_impact_parameter_z_flavour", "", {HistType::kTH3F, {{axisTrackPt}, {axisImpactParameterZ}, {axisJetFlavour}}}); + registry.add("h3_track_pt_sign_impact_parameter_z_flavour", "", {HistType::kTH3F, {{axisTrackPt}, {axisImpactParameterZ}, {axisJetFlavour}}}); + registry.add("h3_track_pt_impact_parameter_z_significance_flavour", "", {HistType::kTH3F, {{axisTrackPt}, {axisImpactParameterZSignificance}, {axisJetFlavour}}}); + registry.add("h3_track_pt_sign_impact_parameter_z_significance_flavour", "", {HistType::kTH3F, {{axisTrackPt}, {axisImpactParameterZSignificance}, {axisJetFlavour}}}); + } + if (fillIPxyz) { + registry.add("h3_jet_pt_impact_parameter_xyz_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXYZ}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_sign_impact_parameter_xyz_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXYZ}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_impact_parameter_xyz_significance_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXYZSignificance}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_sign_impact_parameter_xyz_significance_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXYZSignificance}, {axisJetFlavour}}}); + registry.add("h3_track_pt_impact_parameter_xyz_flavour", "", {HistType::kTH3F, {{axisTrackPt}, {axisImpactParameterXYZ}, {axisJetFlavour}}}); + registry.add("h3_track_pt_sign_impact_parameter_xyz_flavour", "", {HistType::kTH3F, {{axisTrackPt}, {axisImpactParameterXYZ}, {axisJetFlavour}}}); + registry.add("h3_track_pt_impact_parameter_xyz_significance_flavour", "", {HistType::kTH3F, {{axisTrackPt}, {axisImpactParameterXYZSignificance}, {axisJetFlavour}}}); + registry.add("h3_track_pt_sign_impact_parameter_xyz_significance_flavour", "", {HistType::kTH3F, {{axisTrackPt}, {axisImpactParameterXYZSignificance}, {axisJetFlavour}}}); + } + if (fillTrackCounting) { + registry.add("h3_jet_pt_sign_impact_parameter_xy_significance_flavour_N1", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXYSignificance}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_sign_impact_parameter_xy_significance_flavour_N2", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXYSignificance}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_sign_impact_parameter_xy_significance_flavour_N3", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXYSignificance}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_sign_impact_parameter_z_significance_flavour_N1", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterZSignificance}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_sign_impact_parameter_z_significance_flavour_N2", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterZSignificance}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_sign_impact_parameter_z_significance_flavour_N3", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterZSignificance}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_sign_impact_parameter_xyz_significance_flavour_N1", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXYZSignificance}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_sign_impact_parameter_xyz_significance_flavour_N2", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXYZSignificance}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_sign_impact_parameter_xyz_significance_flavour_N3", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXYZSignificance}, {axisJetFlavour}}}); + registry.add("h3_sign_impact_parameter_xy_significance_tc_flavour", "", {HistType::kTH3F, {{axisImpactParameterXYSignificance}, {axisNumOrder}, {axisJetFlavour}}}); + registry.add("h3_sign_impact_parameter_z_significance_tc_flavour", "", {HistType::kTH3F, {{axisImpactParameterZSignificance}, {axisNumOrder}, {axisJetFlavour}}}); + registry.add("h3_sign_impact_parameter_xyz_significance_tc_flavour", "", {HistType::kTH3F, {{axisImpactParameterXYZSignificance}, {axisNumOrder}, {axisJetFlavour}}}); + } + } + if (doprocessIPsMCP || doprocessIPsMCPWeighted) { + registry.add("h2_jet_pt_part_flavour", "", {HistType::kTH2F, {{axisJetPt}, {axisJetFlavour}}}); + registry.add("h2_jet_eta_part_flavour", "", {HistType::kTH2F, {{axisEta}, {axisJetFlavour}}}); + registry.add("h2_jet_phi_part_flavour", "", {HistType::kTH2F, {{axisPhi}, {axisJetFlavour}}}); + } + if (doprocessIPsMCPMCDMatched || doprocessIPsMCPMCDMatchedWeighted) { + registry.add("h3_jet_pt_jet_pt_part_matchedgeo_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisJetPt}, {axisJetFlavour}}}); + } + if (doprocessJPData) { + if (!doprocessIPsData && !doprocessSV2ProngData && !doprocessSV3ProngData) { + registry.add("h_jet_pt", "", {HistType::kTH1F, {{axisJetPt}}}); + registry.add("h_jet_eta", "", {HistType::kTH1F, {{axisEta}}}); + registry.add("h_jet_phi", "", {HistType::kTH1F, {{axisPhi}}}); + } + registry.add("h2_jet_pt_JP", "jet pt jet probability untagged", {HistType::kTH2F, {{axisJetPt}, {axisJetProbability}}}); + registry.add("h2_jet_pt_neg_log_JP", "jet pt jet probabilityun tagged", {HistType::kTH2F, {{axisJetPt}, {axisJetProbabilityLog}}}); + registry.add("h2_taggedjet_pt_JP_N1", "jet pt jet probability N1", {HistType::kTH2F, {{axisJetPt}, {axisJetProbability}}}); + registry.add("h2_taggedjet_pt_neg_log_JP_N1", "jet pt jet probabilityun N1", {HistType::kTH2F, {{axisJetPt}, {axisJetProbabilityLog}}}); + registry.add("h2_taggedjet_pt_JP_N2", "jet pt jet probability N2", {HistType::kTH2F, {{axisJetPt}, {axisJetProbability}}}); + registry.add("h2_taggedjet_pt_neg_log_JP_N2", "jet pt jet probabilityun N2", {HistType::kTH2F, {{axisJetPt}, {axisJetProbabilityLog}}}); + registry.add("h2_taggedjet_pt_JP_N3", "jet pt jet probability N3", {HistType::kTH2F, {{axisJetPt}, {axisJetProbability}}}); + registry.add("h2_taggedjet_pt_neg_log_JP_N3", "jet pt jet probabilityun N3", {HistType::kTH2F, {{axisJetPt}, {axisJetProbabilityLog}}}); + } + if (doprocessJPMCD || doprocessJPMCDWeighted || doprocessJPMCPMCDMatched || doprocessJPMCPMCDMatchedWeighted) { + if (!(doprocessIPsMCD || doprocessIPsMCDWeighted || doprocessIPsMCPMCDMatched || doprocessIPsMCPMCDMatchedWeighted) && !(doprocessSV2ProngMCD || doprocessSV2ProngMCDWeighted || doprocessSV2ProngMCPMCDMatched || doprocessSV2ProngMCPMCDMatchedWeighted) && !(doprocessSV3ProngMCD || doprocessSV3ProngMCDWeighted || doprocessSV3ProngMCPMCDMatched || doprocessSV3ProngMCPMCDMatchedWeighted)) { + registry.add("h2_jet_pt_flavour", "", {HistType::kTH2F, {{axisJetPt}, {axisJetFlavour}}}); + registry.add("h2_jet_eta_flavour", "", {HistType::kTH2F, {{axisEta}, {axisJetFlavour}}}); + registry.add("h2_jet_phi_flavour", "", {HistType::kTH2F, {{axisPhi}, {axisJetFlavour}}}); + } + registry.add("h3_jet_pt_JP_flavour", "jet pt jet probability flavour untagged", {HistType::kTH3F, {{axisJetPt}, {axisJetProbability}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_neg_log_JP_flavour", "jet pt log jet probability flavour untagged", {HistType::kTH3F, {{axisJetPt}, {axisJetProbabilityLog}, {axisJetFlavour}}}); + registry.add("h3_taggedjet_pt_JP_N1_flavour", "jet pt jet probability flavour N1", {HistType::kTH3F, {{axisJetPt}, {axisJetProbability}, {axisJetFlavour}}}); + registry.add("h3_taggedjet_pt_neg_log_JP_N1_flavour", "jet pt log jet probability flavour N1", {HistType::kTH3F, {{axisJetPt}, {axisJetProbabilityLog}, {axisJetFlavour}}}); + registry.add("h3_taggedjet_pt_JP_N2_flavour", "jet pt jet probability flavour N2", {HistType::kTH3F, {{axisJetPt}, {axisJetProbability}, {axisJetFlavour}}}); + registry.add("h3_taggedjet_pt_neg_log_JP_N2_flavour", "jet pt log jet probability flavour N2", {HistType::kTH3F, {{axisJetPt}, {axisJetProbabilityLog}, {axisJetFlavour}}}); + registry.add("h3_taggedjet_pt_JP_N3_flavour", "jet pt jet probability flavour N3", {HistType::kTH3F, {{axisJetPt}, {axisJetProbability}, {axisJetFlavour}}}); + registry.add("h3_taggedjet_pt_neg_log_JP_N3_flavour", "jet pt log jet probability flavour N3", {HistType::kTH3F, {{axisJetPt}, {axisJetProbabilityLog}, {axisJetFlavour}}}); + } + if (doprocessSV2ProngData) { + if (!doprocessIPsData && !doprocessJPData && !doprocessSV3ProngData) { + registry.add("h_jet_pt", "", {HistType::kTH1F, {{axisJetPt}}}); + registry.add("h_jet_eta", "", {HistType::kTH1F, {{axisEta}}}); + registry.add("h_jet_phi", "", {HistType::kTH1F, {{axisPhi}}}); + } + if (fillGeneralSVQA) { + registry.add("h_2prong_nprongs", "", {HistType::kTH1F, {{axisNprongs}}}); + registry.add("h2_jet_pt_2prong_Lxy", "", {HistType::kTH2F, {{axisJetPt}, {axisLxy}}}); + registry.add("h2_jet_pt_2prong_sigmaLxy", "", {HistType::kTH2F, {{axisJetPt}, {axisSigmaLxy}}}); + registry.add("h2_jet_pt_2prong_Sxy", "", {HistType::kTH2F, {{axisJetPt}, {axisSxy}}}); + registry.add("h2_jet_pt_2prong_Lxyz", "", {HistType::kTH2F, {{axisJetPt}, {axisLxyz}}}); + registry.add("h2_jet_pt_2prong_sigmaLxyz", "", {HistType::kTH2F, {{axisJetPt}, {axisSigmaLxyz}}}); + registry.add("h2_jet_pt_2prong_Sxyz", "", {HistType::kTH2F, {{axisJetPt}, {axisSxyz}}}); + } + registry.add("h2_jet_pt_2prong_Sxy_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisSxy}}}); + registry.add("h2_jet_pt_2prong_Sxyz_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisSxyz}}}); + registry.add("h2_jet_pt_2prong_mass_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisMass}}}); + registry.add("h2_jet_pt_2prong_mass_xyz_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisMass}}}); + registry.add("h2_taggedjet_pt_2prong_Sxy_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisSxy}}}); + registry.add("h2_taggedjet_pt_2prong_Sxyz_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisSxyz}}}); + registry.add("h2_taggedjet_pt_2prong_mass_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisMass}}}); + registry.add("h2_taggedjet_pt_2prong_mass_xyz_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisMass}}}); + } + if (doprocessSV3ProngData) { + if (!doprocessIPsData && !doprocessJPData && !doprocessSV2ProngData) { + registry.add("h_jet_pt", "", {HistType::kTH1F, {{axisJetPt}}}); + registry.add("h_jet_eta", "", {HistType::kTH1F, {{axisEta}}}); + registry.add("h_jet_phi", "", {HistType::kTH1F, {{axisPhi}}}); + } + if (fillGeneralSVQA) { + registry.add("h_3prong_nprongs", "", {HistType::kTH1F, {{axisNprongs}}}); + registry.add("h2_jet_pt_3prong_Lxy", "", {HistType::kTH2F, {{axisJetPt}, {axisLxy}}}); + registry.add("h2_jet_pt_3prong_sigmaLxy", "", {HistType::kTH2F, {{axisJetPt}, {axisSigmaLxy}}}); + registry.add("h2_jet_pt_3prong_Sxy", "", {HistType::kTH2F, {{axisJetPt}, {axisSxy}}}); + registry.add("h2_jet_pt_3prong_Lxyz", "", {HistType::kTH2F, {{axisJetPt}, {axisLxyz}}}); + registry.add("h2_jet_pt_3prong_sigmaLxyz", "", {HistType::kTH2F, {{axisJetPt}, {axisSigmaLxyz}}}); + registry.add("h2_jet_pt_3prong_Sxyz", "", {HistType::kTH2F, {{axisJetPt}, {axisSxyz}}}); + } + registry.add("h2_jet_pt_3prong_Sxy_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisSxy}}}); + registry.add("h2_jet_pt_3prong_Sxyz_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisSxyz}}}); + registry.add("h2_jet_pt_3prong_mass_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisMass}}}); + registry.add("h2_jet_pt_3prong_mass_xyz_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisMass}}}); + registry.add("h2_taggedjet_pt_3prong_Sxy_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisSxy}}}); + registry.add("h2_taggedjet_pt_3prong_Sxyz_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisSxyz}}}); + registry.add("h2_taggedjet_pt_3prong_mass_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisMass}}}); + registry.add("h2_taggedjet_pt_3prong_mass_xyz_N1", "", {HistType::kTH2F, {{axisJetPt}, {axisMass}}}); + } + if (doprocessSV2ProngMCD || doprocessSV2ProngMCDWeighted || doprocessSV2ProngMCPMCDMatched || doprocessSV2ProngMCPMCDMatchedWeighted) { + if (!(doprocessIPsMCD || doprocessIPsMCDWeighted || doprocessIPsMCPMCDMatched || doprocessIPsMCPMCDMatchedWeighted) && !(doprocessJPMCD || doprocessJPMCDWeighted || doprocessJPMCPMCDMatched || doprocessJPMCPMCDMatchedWeighted) && !(doprocessSV3ProngMCD || doprocessSV3ProngMCDWeighted || doprocessSV3ProngMCPMCDMatched || doprocessSV3ProngMCPMCDMatchedWeighted)) { + registry.add("h2_jet_pt_flavour", "", {HistType::kTH2F, {{axisJetPt}, {axisJetFlavour}}}); + registry.add("h2_jet_eta_flavour", "", {HistType::kTH2F, {{axisEta}, {axisJetFlavour}}}); + registry.add("h2_jet_phi_flavour", "", {HistType::kTH2F, {{axisPhi}, {axisJetFlavour}}}); + } + if (fillGeneralSVQA) { + registry.add("h2_2prong_nprongs_flavour", "", {HistType::kTH2F, {{axisNprongs}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_2prong_Lxy_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisLxy}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_2prong_sigmaLxy_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisSigmaLxy}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_2prong_Sxy_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisSxy}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_2prong_Lxyz_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisLxyz}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_2prong_sigmaLxyz_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisSigmaLxyz}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_2prong_Sxyz_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisSxyz}, {axisJetFlavour}}}); + } + registry.add("h3_jet_pt_2prong_Sxy_N1_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisSxy}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_2prong_Sxyz_N1_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisSxyz}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_2prong_mass_N1_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisMass}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_2prong_mass_xyz_N1_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisMass}, {axisJetFlavour}}}); + registry.add("h3_taggedjet_pt_2prong_Sxy_N1_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisSxy}, {axisJetFlavour}}}); + registry.add("h3_taggedjet_pt_2prong_Sxyz_N1_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisSxyz}, {axisJetFlavour}}}); + registry.add("h3_taggedjet_pt_2prong_mass_N1_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisMass}, {axisJetFlavour}}}); + registry.add("h3_taggedjet_pt_2prong_mass_xyz_N1_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisMass}, {axisJetFlavour}}}); + } + if (doprocessSV3ProngMCD || doprocessSV3ProngMCDWeighted || doprocessSV3ProngMCPMCDMatched || doprocessSV3ProngMCPMCDMatchedWeighted) { + if (!(doprocessIPsMCD || doprocessIPsMCDWeighted || doprocessIPsMCPMCDMatched || doprocessIPsMCPMCDMatchedWeighted) && !(doprocessJPMCD || doprocessJPMCDWeighted || doprocessJPMCPMCDMatched || doprocessJPMCPMCDMatchedWeighted) && !(doprocessSV2ProngMCD || doprocessSV2ProngMCDWeighted || doprocessSV2ProngMCPMCDMatched || doprocessSV2ProngMCPMCDMatchedWeighted)) { + registry.add("h2_jet_pt_flavour", "", {HistType::kTH2F, {{axisJetPt}, {axisJetFlavour}}}); + registry.add("h2_jet_eta_flavour", "", {HistType::kTH2F, {{axisEta}, {axisJetFlavour}}}); + registry.add("h2_jet_phi_flavour", "", {HistType::kTH2F, {{axisPhi}, {axisJetFlavour}}}); + } + if (fillGeneralSVQA) { + registry.add("h2_3prong_nprongs_flavour", "", {HistType::kTH2F, {{axisNprongs}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_3prong_Lxy_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisLxy}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_3prong_sigmaLxy_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisSigmaLxy}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_3prong_Sxy_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisSxy}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_3prong_Lxyz_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisLxyz}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_3prong_sigmaLxyz_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisSigmaLxyz}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_3prong_Sxyz_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisSxyz}, {axisJetFlavour}}}); + } + registry.add("h3_jet_pt_3prong_Sxy_N1_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisSxy}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_3prong_Sxyz_N1_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisSxyz}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_3prong_mass_N1_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisMass}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_3prong_mass_xyz_N1_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisMass}, {axisJetFlavour}}}); + registry.add("h3_taggedjet_pt_3prong_Sxy_N1_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisSxy}, {axisJetFlavour}}}); + registry.add("h3_taggedjet_pt_3prong_Sxyz_N1_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisSxyz}, {axisJetFlavour}}}); + registry.add("h3_taggedjet_pt_3prong_mass_N1_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisMass}, {axisJetFlavour}}}); + registry.add("h3_taggedjet_pt_3prong_mass_xyz_N1_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisMass}, {axisJetFlavour}}}); + } + } + + // Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); + Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut); + PresliceUnsorted> collisionsPerMCPCollision = aod::jmccollisionlb::mcCollisionId; + Preslice particlesPerCollision = aod::jmcparticle::mcCollisionId; + + using JetTagTracksData = soa::Join; + using JetTagTracksMCD = soa::Join; + + std::function&, const std::vector&)> sortImp = + [](const std::vector& a, const std::vector& b) { + return a[0] > b[0]; + }; + + template + bool isAcceptedJet(U const& jet) + { + if (jetAreaFractionMin > -98.0) { + if (jet.area() < jetAreaFractionMin * o2::constants::math::PI * (jet.r() / 100.0) * (jet.r() / 100.0)) { + return false; + } + } + bool checkConstituentPt = true; + bool checkConstituentMinPt = (leadingConstituentPtMin > -98.0); + bool checkConstituentMaxPt = (leadingConstituentPtMax < 9998.0); + if (!checkConstituentMinPt && !checkConstituentMaxPt) { + checkConstituentPt = false; + } + + if (checkConstituentPt) { + bool isMinLeadingConstituent = !checkConstituentMinPt; + bool isMaxLeadingConstituent = true; + + for (const auto& constituent : jet.template tracks_as()) { + double pt = constituent.pt(); + + if (checkConstituentMinPt && pt >= leadingConstituentPtMin) { + isMinLeadingConstituent = true; + } + if (checkConstituentMaxPt && pt > leadingConstituentPtMax) { + isMaxLeadingConstituent = false; + } + } + return isMinLeadingConstituent && isMaxLeadingConstituent; + } + + return true; + } + + template + bool trackAcceptance(T const& track) + { + if (track.pt() < trackPtMin || track.pt() > trackPtMax) + return false; + + return true; + } + + template + void fillValidationFlavourDefMCD(T const& mcdjet, V const& tracks, W const& particles, X const& particlesPerColl, float eventWeight = 1.0) + { + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (mcdjet.pt() > pTHatMaxMCD * pTHat) { + return; + } + typename V::iterator hftrack; + int jetflavourConstQuark = jettaggingutilities::mcdJetFromHFShower(mcdjet, tracks, particles, maxDeltaR, true); + int jetflavourConstHadron = jettaggingutilities::mcdJetFromHFShower(mcdjet, tracks, particles, maxDeltaR, false); + int jetflavourDistQuark = -1; + int jetflavourDistHadron = -1; + for (auto const& mcpjet : mcdjet.template matchedJetGeo_as()) { + jetflavourDistQuark = jettaggingutilities::getJetFlavor(mcpjet, particlesPerColl); + jetflavourDistHadron = jettaggingutilities::getJetFlavorHadron(mcpjet, particlesPerColl); + } + if (jetflavourDistQuark < 0 || jetflavourDistHadron < 0) + return; + registry.fill(HIST("h2_flavour_dist_quark_flavour_dist_hadron"), jetflavourDistQuark, jetflavourDistHadron, eventWeight); + registry.fill(HIST("h2_flavour_const_quark_flavour_const_hadron"), jetflavourConstQuark, jetflavourConstHadron, eventWeight); + registry.fill(HIST("h2_flavour_const_hadron_flavour_dist_hadron"), jetflavourConstHadron, jetflavourDistHadron, eventWeight); + registry.fill(HIST("h2_flavour_const_quark_flavour_dist_quark"), jetflavourConstQuark, jetflavourDistQuark, eventWeight); + } + + template + void fillValidationFlavourDefMCP(T const& mcpjet, U const& particles, V const& particlesPerColl, float eventWeight = 1.0) + { + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + return; + } + int jetflavourConstQuark = jettaggingutilities::mcpJetFromHFShower(mcpjet, particles, maxDeltaR, true); + int jetflavourConstHadron = jettaggingutilities::mcpJetFromHFShower(mcpjet, particles, maxDeltaR, false); + int jetflavourDistQuark = jettaggingutilities::getJetFlavor(mcpjet, particlesPerColl); + int jetflavourDistHadron = jettaggingutilities::getJetFlavorHadron(mcpjet, particlesPerColl); + registry.fill(HIST("h2_part_flavour_dist_quark_part_flavour_dist_hadron"), jetflavourDistQuark, jetflavourDistHadron, eventWeight); + registry.fill(HIST("h2_part_flavour_const_quark_part_flavour_const_hadron"), jetflavourConstQuark, jetflavourConstHadron, eventWeight); + registry.fill(HIST("h2_part_flavour_const_hadron_part_flavour_dist_hadron"), jetflavourConstHadron, jetflavourDistHadron, eventWeight); + registry.fill(HIST("h2_part_flavour_const_quark_part_flavour_dist_quark"), jetflavourConstQuark, jetflavourDistQuark, eventWeight); + } + + template + void fillHistogramIPsData(T const& jet, U const& /*tracks*/) + { + float eventWeight = 1.0; + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (jet.pt() > pTHatMaxMCD * pTHat) { + return; + } + registry.fill(HIST("h_jet_pt"), jet.pt()); + registry.fill(HIST("h_jet_eta"), jet.eta()); + registry.fill(HIST("h_jet_phi"), jet.phi()); + std::vector> vecSignImpXYSig, vecSignImpZSig, vecSignImpXYZSig; + for (auto const& track : jet.template tracks_as()) { + if (!trackAcceptance(track)) + continue; + if (!jettaggingutilities::trackAcceptanceWithDca(track, trackDcaXYMax, trackDcaZMax)) + continue; + // General parameters + registry.fill(HIST("h3_jet_pt_track_pt_track_eta"), jet.pt(), track.pt(), track.eta()); + registry.fill(HIST("h3_jet_pt_track_pt_track_phi"), jet.pt(), track.pt(), track.phi()); + int geoSign = jettaggingutilities::getGeoSign(jet, track); + if (fillIPxy) { + float varImpXY, varSignImpXY, varImpXYSig, varSignImpXYSig; + varImpXY = track.dcaXY() * jettaggingutilities::cmTomum; + varSignImpXY = geoSign * std::abs(track.dcaXY()) * jettaggingutilities::cmTomum; + varImpXYSig = track.dcaXY() / track.sigmadcaXY(); + varSignImpXYSig = geoSign * std::abs(track.dcaXY()) / track.sigmadcaXY(); + registry.fill(HIST("h2_jet_pt_impact_parameter_xy"), jet.pt(), varImpXY); + registry.fill(HIST("h2_jet_pt_sign_impact_parameter_xy"), jet.pt(), varSignImpXY); + registry.fill(HIST("h2_jet_pt_impact_parameter_xy_significance"), jet.pt(), varImpXYSig); + registry.fill(HIST("h3_jet_pt_track_pt_sign_impact_parameter_xy_significance"), jet.pt(), track.pt(), varSignImpXYSig); + vecSignImpXYSig.push_back({varSignImpXYSig, track.pt()}); + } + if (fillIPz) { + float varImpZ, varSignImpZ, varImpZSig, varSignImpZSig; + varImpZ = track.dcaZ() * jettaggingutilities::cmTomum; + varSignImpZ = geoSign * std::abs(track.dcaZ()) * jettaggingutilities::cmTomum; + varImpZSig = track.dcaZ() / track.sigmadcaZ(); + varSignImpZSig = geoSign * std::abs(track.dcaZ()) / track.sigmadcaZ(); + registry.fill(HIST("h2_jet_pt_impact_parameter_z"), jet.pt(), varImpZ); + registry.fill(HIST("h2_jet_pt_sign_impact_parameter_z"), jet.pt(), varSignImpZ); + registry.fill(HIST("h2_jet_pt_impact_parameter_z_significance"), jet.pt(), varImpZSig); + registry.fill(HIST("h3_jet_pt_track_pt_sign_impact_parameter_z_significance"), jet.pt(), track.pt(), varSignImpZSig); + vecSignImpZSig.push_back({varSignImpZSig, track.pt()}); + } + if (fillIPxyz) { + float varImpXYZ, varSignImpXYZ, varImpXYZSig, varSignImpXYZSig; + varImpXYZ = track.dcaXYZ() * jettaggingutilities::cmTomum; + varSignImpXYZ = geoSign * std::abs(track.dcaXYZ()) * jettaggingutilities::cmTomum; + varImpXYZSig = track.dcaXYZ() / track.sigmadcaXYZ(); + varSignImpXYZSig = geoSign * std::abs(track.dcaXYZ()) / track.sigmadcaXYZ(); + registry.fill(HIST("h2_jet_pt_impact_parameter_xyz"), jet.pt(), varImpXYZ); + registry.fill(HIST("h2_jet_pt_sign_impact_parameter_xyz"), jet.pt(), varSignImpXYZ); + registry.fill(HIST("h2_jet_pt_impact_parameter_xyz_significance"), jet.pt(), varImpXYZSig); + registry.fill(HIST("h3_jet_pt_track_pt_sign_impact_parameter_xyz_significance"), jet.pt(), track.pt(), varSignImpXYZSig); + vecSignImpXYZSig.push_back({varSignImpXYZSig, track.pt()}); + } + } + + if (!fillTrackCounting) + return; + if (fillIPxy) + std::sort(vecSignImpXYSig.begin(), vecSignImpXYSig.end(), sortImp); + if (fillIPz) + std::sort(vecSignImpZSig.begin(), vecSignImpZSig.end(), sortImp); + if (fillIPxyz) + std::sort(vecSignImpXYZSig.begin(), vecSignImpXYZSig.end(), sortImp); + + if (vecSignImpXYSig.size() > 0) { // N1 + if (fillIPxy) + registry.fill(HIST("h2_jet_pt_sign_impact_parameter_xy_significance_N1"), jet.pt(), vecSignImpXYSig[0][0]); + if (fillIPz) + registry.fill(HIST("h2_jet_pt_sign_impact_parameter_z_significance_N1"), jet.pt(), vecSignImpZSig[0][0]); + if (fillIPxyz) + registry.fill(HIST("h2_jet_pt_sign_impact_parameter_xyz_significance_N1"), jet.pt(), vecSignImpXYZSig[0][0]); + } + if (vecSignImpXYSig.size() > 1) { // N2 + if (fillIPxy) + registry.fill(HIST("h2_jet_pt_sign_impact_parameter_xy_significance_N2"), jet.pt(), vecSignImpXYSig[1][0]); + if (fillIPz) + registry.fill(HIST("h2_jet_pt_sign_impact_parameter_z_significance_N2"), jet.pt(), vecSignImpZSig[1][0]); + if (fillIPxyz) + registry.fill(HIST("h2_jet_pt_sign_impact_parameter_xyz_significance_N2"), jet.pt(), vecSignImpXYZSig[1][0]); + } + if (vecSignImpXYSig.size() > 2) { // N3 + if (fillIPxy) + registry.fill(HIST("h2_jet_pt_sign_impact_parameter_xy_significance_N3"), jet.pt(), vecSignImpXYSig[2][0]); + if (fillIPz) + registry.fill(HIST("h2_jet_pt_sign_impact_parameter_z_significance_N3"), jet.pt(), vecSignImpZSig[2][0]); + if (fillIPxyz) + registry.fill(HIST("h2_jet_pt_sign_impact_parameter_xyz_significance_N3"), jet.pt(), vecSignImpXYZSig[2][0]); + } + if (fillIPxy && vecSignImpXYSig.empty()) + return; + for (int order = 1; order <= numOrder; order++) { + if (fillIPxy && static_cast>::size_type>(order) < vecSignImpXYSig.size()) { + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xy_significance_tc"), jet.pt(), vecSignImpXYSig[order - 1][0], order); + registry.fill(HIST("h3_track_pt_sign_impact_parameter_xy_significance_tc"), vecSignImpXYSig[order - 1][1], vecSignImpXYSig[order - 1][0], order); + } + } + if (fillIPz && vecSignImpZSig.empty()) + return; + for (int order = 1; order <= numOrder; order++) { + if (fillIPz && static_cast>::size_type>(order) < vecSignImpXYSig.size()) { + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_z_significance_tc"), jet.pt(), vecSignImpZSig[order - 1][0], order); + registry.fill(HIST("h3_track_pt_sign_impact_parameter_z_significance_tc"), vecSignImpZSig[order - 1][1], vecSignImpZSig[order - 1][0], order); + } + } + if (fillIPxyz && vecSignImpXYZSig.empty()) + return; + for (int order = 1; order <= numOrder; order++) { + if (fillIPxyz && static_cast>::size_type>(order) < vecSignImpXYSig.size()) { + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xyz_significance_tc"), jet.pt(), vecSignImpXYZSig[order - 1][0], order); + registry.fill(HIST("h3_track_pt_sign_impact_parameter_xyz_significance_tc"), vecSignImpXYZSig[order - 1][1], vecSignImpXYZSig[order - 1][0], order); + } + } + } + + template + void fillHistogramIPsMCD(T const& mcdjet, U const& /*tracks*/, float eventWeight = 1.0) + { + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (mcdjet.pt() > pTHatMaxMCD * pTHat) { + return; + } + std::vector vecImpXY[numberOfJetFlavourSpecies], vecSignImpXY[numberOfJetFlavourSpecies], vecImpXYSig[numberOfJetFlavourSpecies], vecSignImpXYSig[numberOfJetFlavourSpecies]; + std::vector vecImpZ[numberOfJetFlavourSpecies], vecSignImpZ[numberOfJetFlavourSpecies], vecImpZSig[numberOfJetFlavourSpecies], vecSignImpZSig[numberOfJetFlavourSpecies]; + std::vector vecImpXYZ[numberOfJetFlavourSpecies], vecSignImpXYZ[numberOfJetFlavourSpecies], vecImpXYZSig[numberOfJetFlavourSpecies], vecSignImpXYZSig[numberOfJetFlavourSpecies]; + std::vector> vecSignImpXYSigTC, vecSignImpZSigTC, vecSignImpXYZSigTC; + int jetflavour = mcdjet.origin(); + if (jetflavour == JetTaggingSpecies::none) { + LOGF(debug, "NOT DEFINE JET FLAVOR"); + } + if (jetflavour == -1) { + jetflavour = JetTaggingSpecies::none; + } + registry.fill(HIST("h2_jet_pt_flavour"), mcdjet.pt(), jetflavour, eventWeight); + registry.fill(HIST("h2_jet_eta_flavour"), mcdjet.eta(), jetflavour, eventWeight); + registry.fill(HIST("h2_jet_phi_flavour"), mcdjet.phi(), jetflavour, eventWeight); + for (auto const& track : mcdjet.template tracks_as()) { + if (!trackAcceptance(track)) + continue; + if (!jettaggingutilities::trackAcceptanceWithDca(track, trackDcaXYMax, trackDcaZMax)) + continue; + + // General parameters + registry.fill(HIST("h3_jet_pt_track_pt_flavour"), mcdjet.pt(), track.pt(), jetflavour, eventWeight); + registry.fill(HIST("h3_jet_pt_track_eta_flavour"), mcdjet.pt(), track.eta(), jetflavour, eventWeight); + registry.fill(HIST("h3_jet_pt_track_phi_flavour"), mcdjet.pt(), track.phi(), jetflavour, eventWeight); + int geoSign = jettaggingutilities::getGeoSign(mcdjet, track); + if (fillIPxy) { + float varImpXY, varSignImpXY, varImpXYSig, varSignImpXYSig; + varImpXY = track.dcaXY() * jettaggingutilities::cmTomum; + float varSigmaImpXY = track.dcaXY() * jettaggingutilities::cmTomum; + varSignImpXY = geoSign * std::abs(track.dcaXY()) * jettaggingutilities::cmTomum; + varImpXYSig = track.dcaXY() / track.sigmadcaXY(); + varSignImpXYSig = geoSign * std::abs(track.dcaXY()) / track.sigmadcaXY(); + registry.fill(HIST("h3_jet_pt_impact_parameter_xy_flavour"), mcdjet.pt(), varImpXY, jetflavour, eventWeight); + registry.fill(HIST("h3_jet_pt_sigma_impact_parameter_xy_flavour"), mcdjet.pt(), varSigmaImpXY, jetflavour, eventWeight); + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xy_flavour"), mcdjet.pt(), varSignImpXY, jetflavour, eventWeight); + registry.fill(HIST("h3_jet_pt_impact_parameter_xy_significance_flavour"), mcdjet.pt(), varImpXYSig, jetflavour, eventWeight); + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xy_significance_flavour"), mcdjet.pt(), varSignImpXYSig, jetflavour, eventWeight); + registry.fill(HIST("h3_track_pt_impact_parameter_xy_flavour"), track.pt(), varImpXY, jetflavour, eventWeight); + registry.fill(HIST("h3_track_pt_sign_impact_parameter_xy_flavour"), track.pt(), varSignImpXY, jetflavour, eventWeight); + registry.fill(HIST("h3_track_pt_impact_parameter_xy_significance_flavour"), track.pt(), varImpXYSig, jetflavour, eventWeight); + registry.fill(HIST("h3_track_pt_sign_impact_parameter_xy_significance_flavour"), track.pt(), varSignImpXYSig, jetflavour, eventWeight); + vecImpXY[jetflavour].push_back(varImpXY); + vecSignImpXY[jetflavour].push_back(varSignImpXY); + vecImpXYSig[jetflavour].push_back(varImpXYSig); + vecSignImpXYSig[jetflavour].push_back(varSignImpXYSig); + vecSignImpXYSigTC.push_back({varSignImpXYSig, track.pt()}); + } + if (fillIPz) { + float varImpZ, varSignImpZ, varImpZSig, varSignImpZSig; + varImpZ = track.dcaZ() * jettaggingutilities::cmTomum; + varSignImpZ = geoSign * std::abs(track.dcaZ()) * jettaggingutilities::cmTomum; + varImpZSig = track.dcaZ() / track.sigmadcaZ(); + varSignImpZSig = geoSign * std::abs(track.dcaZ()) / track.sigmadcaZ(); + registry.fill(HIST("h3_jet_pt_impact_parameter_z_flavour"), mcdjet.pt(), varImpZ, jetflavour, eventWeight); + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_z_flavour"), mcdjet.pt(), varSignImpZ, jetflavour, eventWeight); + registry.fill(HIST("h3_jet_pt_impact_parameter_z_significance_flavour"), mcdjet.pt(), varImpZSig, jetflavour, eventWeight); + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_z_significance_flavour"), mcdjet.pt(), varSignImpZSig, jetflavour, eventWeight); + registry.fill(HIST("h3_track_pt_impact_parameter_z_flavour"), track.pt(), varImpZ, jetflavour, eventWeight); + registry.fill(HIST("h3_track_pt_sign_impact_parameter_z_flavour"), track.pt(), varSignImpZ, jetflavour, eventWeight); + registry.fill(HIST("h3_track_pt_impact_parameter_z_significance_flavour"), track.pt(), varImpZSig, jetflavour, eventWeight); + registry.fill(HIST("h3_track_pt_sign_impact_parameter_z_significance_flavour"), track.pt(), varSignImpZSig, jetflavour, eventWeight); + vecImpZ[jetflavour].push_back(varImpZ); + vecSignImpZ[jetflavour].push_back(varSignImpZ); + vecImpZSig[jetflavour].push_back(varImpZSig); + vecSignImpZSig[jetflavour].push_back(varSignImpZSig); + vecSignImpZSigTC.push_back({varSignImpZSig, track.pt()}); + } + if (fillIPxyz) { + float varImpXYZ, varSignImpXYZ, varImpXYZSig, varSignImpXYZSig; + float dcaXYZ = track.dcaXYZ(); + float sigmadcaXYZ = track.sigmadcaXYZ(); + varImpXYZ = dcaXYZ * jettaggingutilities::cmTomum; + varSignImpXYZ = geoSign * std::abs(dcaXYZ) * jettaggingutilities::cmTomum; + varImpXYZSig = dcaXYZ / sigmadcaXYZ; + varSignImpXYZSig = geoSign * std::abs(dcaXYZ) / sigmadcaXYZ; + registry.fill(HIST("h3_jet_pt_impact_parameter_xyz_flavour"), mcdjet.pt(), varImpXYZ, jetflavour, eventWeight); + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xyz_flavour"), mcdjet.pt(), varSignImpXYZ, jetflavour, eventWeight); + registry.fill(HIST("h3_jet_pt_impact_parameter_xyz_significance_flavour"), mcdjet.pt(), varImpXYZSig, jetflavour, eventWeight); + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xyz_significance_flavour"), mcdjet.pt(), varSignImpXYZSig, jetflavour, eventWeight); + registry.fill(HIST("h3_track_pt_impact_parameter_xyz_flavour"), track.pt(), varImpXYZ, jetflavour, eventWeight); + registry.fill(HIST("h3_track_pt_sign_impact_parameter_xyz_flavour"), track.pt(), varSignImpXYZ, jetflavour, eventWeight); + registry.fill(HIST("h3_track_pt_impact_parameter_xyz_significance_flavour"), track.pt(), varImpXYZSig, jetflavour, eventWeight); + registry.fill(HIST("h3_track_pt_sign_impact_parameter_xyz_significance_flavour"), track.pt(), varSignImpXYZSig, jetflavour, eventWeight); + vecImpXYZ[jetflavour].push_back(varImpXYZ); + vecSignImpXYZ[jetflavour].push_back(varSignImpXYZ); + vecImpXYZSig[jetflavour].push_back(varImpXYZSig); + vecSignImpXYZSig[jetflavour].push_back(varSignImpXYZSig); + vecSignImpXYZSigTC.push_back({varSignImpXYZSig, track.pt()}); + } + } + + if (!fillTrackCounting) + return; + sort(vecSignImpXYSig[jetflavour].begin(), vecSignImpXYSig[jetflavour].end(), std::greater()); + sort(vecSignImpZSig[jetflavour].begin(), vecSignImpZSig[jetflavour].end(), std::greater()); + sort(vecSignImpXYZSig[jetflavour].begin(), vecSignImpXYZSig[jetflavour].end(), std::greater()); + + if (vecImpXY[jetflavour].size() > 0) { // N1 + if (fillIPxy) + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xy_significance_flavour_N1"), mcdjet.pt(), vecSignImpXYSig[jetflavour][0], jetflavour, eventWeight); + if (fillIPz) + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_z_significance_flavour_N1"), mcdjet.pt(), vecSignImpZSig[jetflavour][0], jetflavour, eventWeight); + if (fillIPxyz) + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xyz_significance_flavour_N1"), mcdjet.pt(), vecSignImpXYZSig[jetflavour][0], jetflavour, eventWeight); + } + if (vecImpXY[jetflavour].size() > 1) { // N2 + if (fillIPxy) + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xy_significance_flavour_N2"), mcdjet.pt(), vecSignImpXYSig[jetflavour][1], jetflavour, eventWeight); + if (fillIPz) + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_z_significance_flavour_N2"), mcdjet.pt(), vecSignImpZSig[jetflavour][1], jetflavour, eventWeight); + if (fillIPxyz) + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xyz_significance_flavour_N2"), mcdjet.pt(), vecSignImpXYZSig[jetflavour][1], jetflavour, eventWeight); + } + if (vecImpXY[jetflavour].size() > 2) { // N3 + if (fillIPxy) + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xy_significance_flavour_N3"), mcdjet.pt(), vecSignImpXYSig[jetflavour][2], jetflavour, eventWeight); + if (fillIPz) + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_z_significance_flavour_N3"), mcdjet.pt(), vecSignImpZSig[jetflavour][2], jetflavour, eventWeight); + if (fillIPxyz) + registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xyz_significance_flavour_N3"), mcdjet.pt(), vecSignImpXYZSig[jetflavour][2], jetflavour, eventWeight); + } + std::sort(vecSignImpXYSigTC.begin(), vecSignImpXYSigTC.end(), sortImp); + std::sort(vecSignImpZSigTC.begin(), vecSignImpZSigTC.end(), sortImp); + std::sort(vecSignImpXYZSigTC.begin(), vecSignImpXYZSigTC.end(), sortImp); + + if (vecSignImpXYSigTC.empty()) + return; + for (int order = 1; order <= numOrder; order++) { + if (fillIPxy && static_cast>::size_type>(order) < vecSignImpXYSigTC.size()) { + registry.fill(HIST("h3_sign_impact_parameter_xy_significance_tc_flavour"), vecSignImpXYSigTC[order - 1][0], order, jetflavour, eventWeight); + } + } + if (vecSignImpZSigTC.empty()) + return; + for (int order = 1; order <= numOrder; order++) { + if (fillIPz && static_cast>::size_type>(order) < vecSignImpXYSigTC.size()) { + registry.fill(HIST("h3_sign_impact_parameter_z_significance_tc_flavour"), vecSignImpZSigTC[order - 1][0], order, jetflavour, eventWeight); + } + } + + if (vecSignImpXYZSigTC.empty()) + return; + for (int order = 1; order <= numOrder; order++) { + if (fillIPxyz && static_cast>::size_type>(order) < vecSignImpXYSigTC.size()) { + registry.fill(HIST("h3_sign_impact_parameter_xyz_significance_tc_flavour"), vecSignImpXYZSigTC[order - 1][0], order, jetflavour, eventWeight); + } + } + } + + template + void fillHistogramIPsMCP(T const& mcpjet, float eventWeight = 1.0) + { + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + return; + } + int jetflavour = mcpjet.origin(); + if (jetflavour == JetTaggingSpecies::none) { + LOGF(debug, "NOT DEFINE JET FLAVOR"); + } + registry.fill(HIST("h2_jet_pt_part_flavour"), mcpjet.pt(), jetflavour, eventWeight); + registry.fill(HIST("h2_jet_eta_part_flavour"), mcpjet.eta(), jetflavour, eventWeight); + registry.fill(HIST("h2_jet_phi_part_flavour"), mcpjet.phi(), jetflavour, eventWeight); + } + + template + void fillHistogramJPData(T const& jet) + { + float eventWeight = 1.0; + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (jet.pt() > pTHatMaxMCD * pTHat) { + return; + } + if (!doprocessIPsData && !doprocessSV2ProngData && !doprocessSV3ProngData) { + registry.fill(HIST("h_jet_pt"), jet.pt()); + registry.fill(HIST("h_jet_eta"), jet.eta()); + registry.fill(HIST("h_jet_phi"), jet.phi()); + } + registry.fill(HIST("h2_jet_pt_JP"), jet.pt(), jet.jetProb()); + registry.fill(HIST("h2_jet_pt_neg_log_JP"), jet.pt(), -1 * std::log(jet.jetProb())); + registry.fill(HIST("h2_taggedjet_pt_JP_N1"), jet.pt(), jet.isTagged(BJetTaggingMethod::IPsN1) ? jet.jetProb() : -1); + registry.fill(HIST("h2_taggedjet_pt_neg_log_JP_N1"), jet.pt(), jet.isTagged(BJetTaggingMethod::IPsN1) ? -1 * std::log(jet.jetProb()) : -1); + registry.fill(HIST("h2_taggedjet_pt_JP_N2"), jet.pt(), jet.isTagged(BJetTaggingMethod::IPsN2) ? jet.jetProb() : -1); + registry.fill(HIST("h2_taggedjet_pt_neg_log_JP_N2"), jet.pt(), jet.isTagged(BJetTaggingMethod::IPsN2) ? -1 * std::log(jet.jetProb()) : -1); + registry.fill(HIST("h2_taggedjet_pt_JP_N3"), jet.pt(), jet.isTagged(BJetTaggingMethod::IPsN3) ? jet.jetProb() : -1); + registry.fill(HIST("h2_taggedjet_pt_neg_log_JP_N3"), jet.pt(), jet.isTagged(BJetTaggingMethod::IPsN3) ? -1 * std::log(jet.jetProb()) : -1); + } + + template + void fillHistogramJPMCD(T const& mcdjet, float eventWeight = 1.0) + { + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (mcdjet.pt() > pTHatMaxMCD * pTHat) { + return; + } + if (!((doprocessIPsMCD || doprocessIPsMCDWeighted || doprocessIPsMCPMCDMatched || doprocessIPsMCPMCDMatchedWeighted) && (doprocessSV2ProngMCD || doprocessSV2ProngMCDWeighted || doprocessSV2ProngMCPMCDMatched || doprocessSV2ProngMCPMCDMatchedWeighted) && (doprocessSV3ProngMCD || doprocessSV3ProngMCDWeighted || doprocessSV3ProngMCPMCDMatched || doprocessSV3ProngMCPMCDMatchedWeighted))) { + registry.fill(HIST("h2_jet_pt_flavour"), mcdjet.pt(), mcdjet.origin(), eventWeight); + registry.fill(HIST("h2_jet_eta_flavour"), mcdjet.eta(), mcdjet.origin(), eventWeight); + registry.fill(HIST("h2_jet_phi_flavour"), mcdjet.phi(), mcdjet.origin(), eventWeight); + } + registry.fill(HIST("h3_jet_pt_JP_flavour"), mcdjet.pt(), mcdjet.jetProb(), mcdjet.origin(), eventWeight); + registry.fill(HIST("h3_jet_pt_neg_log_JP_flavour"), mcdjet.pt(), -1 * std::log(mcdjet.jetProb()), mcdjet.origin(), eventWeight); + registry.fill(HIST("h3_taggedjet_pt_JP_N1_flavour"), mcdjet.pt(), mcdjet.isTagged(BJetTaggingMethod::IPsN1) ? mcdjet.jetProb() : -1, mcdjet.origin(), eventWeight); + registry.fill(HIST("h3_taggedjet_pt_neg_log_JP_N1_flavour"), mcdjet.pt(), mcdjet.isTagged(BJetTaggingMethod::IPsN1) ? -1 * std::log(mcdjet.jetProb()) : -1, mcdjet.origin(), eventWeight); + registry.fill(HIST("h3_taggedjet_pt_JP_N2_flavour"), mcdjet.pt(), mcdjet.isTagged(BJetTaggingMethod::IPsN2) ? mcdjet.jetProb() : -1, mcdjet.origin(), eventWeight); + registry.fill(HIST("h3_taggedjet_pt_neg_log_JP_N2_flavour"), mcdjet.pt(), mcdjet.isTagged(BJetTaggingMethod::IPsN2) ? -1 * std::log(mcdjet.jetProb()) : -1, mcdjet.origin(), eventWeight); + registry.fill(HIST("h3_taggedjet_pt_JP_N3_flavour"), mcdjet.pt(), mcdjet.isTagged(BJetTaggingMethod::IPsN3) ? mcdjet.jetProb() : -1, mcdjet.origin(), eventWeight); + registry.fill(HIST("h3_taggedjet_pt_neg_log_JP_N3_flavour"), mcdjet.pt(), mcdjet.isTagged(BJetTaggingMethod::IPsN3) ? -1 * std::log(mcdjet.jetProb()) : -1, mcdjet.origin(), eventWeight); + } + + template + void fillHistogramSV2ProngData(T const& jet, U const& /*prongs*/) + { + float eventWeight = 1.0; + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (jet.pt() > pTHatMaxMCD * pTHat) { + return; + } + if (jet.template secondaryVertices_as().size() < 1) + return; + if (!doprocessIPsData && !doprocessJPData && !doprocessSV3ProngData) { + registry.fill(HIST("h_jet_pt"), jet.pt(), eventWeight); + registry.fill(HIST("h_jet_eta"), jet.eta(), eventWeight); + registry.fill(HIST("h_jet_phi"), jet.phi(), eventWeight); + } + if (fillGeneralSVQA) { + registry.fill(HIST("h_2prong_nprongs"), jet.template secondaryVertices_as().size()); + for (const auto& prong : jet.template secondaryVertices_as()) { + registry.fill(HIST("h2_jet_pt_2prong_Lxy"), jet.pt(), prong.decayLengthXY()); + registry.fill(HIST("h2_jet_pt_2prong_Sxy"), jet.pt(), prong.decayLengthXY() / prong.errorDecayLengthXY()); + registry.fill(HIST("h2_jet_pt_2prong_Lxyz"), jet.pt(), prong.decayLength()); + registry.fill(HIST("h2_jet_pt_2prong_Sxyz"), jet.pt(), prong.decayLength() / prong.errorDecayLength()); + registry.fill(HIST("h2_jet_pt_2prong_sigmaLxy"), jet.pt(), prong.errorDecayLengthXY()); + registry.fill(HIST("h2_jet_pt_2prong_sigmaLxyz"), jet.pt(), prong.errorDecayLength()); + } + } + bool checkSv = false; + auto bjetCand = jettaggingutilities::jetFromProngMaxDecayLength(jet, prongChi2PCAMin, prongChi2PCAMax, prongsigmaLxyMax, prongIPxyMin, prongIPxyMax, false, &checkSv); + if (checkSv && jettaggingutilities::svAcceptance(bjetCand, svDispersionMax)) { + auto maxSxy = bjetCand.decayLengthXY() / bjetCand.errorDecayLengthXY(); + auto massSV = bjetCand.m(); + registry.fill(HIST("h2_jet_pt_2prong_Sxy_N1"), jet.pt(), maxSxy); + registry.fill(HIST("h2_jet_pt_2prong_mass_N1"), jet.pt(), massSV); + if (jet.isTagged(BJetTaggingMethod::SV)) { + registry.fill(HIST("h2_taggedjet_pt_2prong_Sxy_N1"), jet.pt(), maxSxy); + registry.fill(HIST("h2_taggedjet_pt_2prong_mass_N1"), jet.pt(), massSV); + } + } + auto bjetCandXYZ = jettaggingutilities::jetFromProngMaxDecayLength(jet, prongChi2PCAMin, prongChi2PCAMax, prongsigmaLxyzMax, prongIPxyMin, prongIPxyMax, true, &checkSv); + if (checkSv && jettaggingutilities::svAcceptance(bjetCand, svDispersionMax)) { + auto maxSxyz = bjetCandXYZ.decayLength() / bjetCandXYZ.errorDecayLength(); + auto massSV = bjetCandXYZ.m(); + registry.fill(HIST("h2_jet_pt_2prong_Sxyz_N1"), jet.pt(), maxSxyz); + registry.fill(HIST("h2_jet_pt_2prong_mass_xyz_N1"), jet.pt(), massSV); + if (jet.isTagged(BJetTaggingMethod::SV3D)) { + registry.fill(HIST("h2_taggedjet_pt_2prong_Sxyz_N1"), jet.pt(), maxSxyz); + registry.fill(HIST("h2_taggedjet_pt_2prong_mass_xyz_N1"), jet.pt(), massSV); + } + } + } + + template + void fillHistogramSV3ProngData(T const& jet, U const& /*prongs*/) + { + float eventWeight = 1.0; + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (jet.pt() > pTHatMaxMCD * pTHat) { + return; + } + if (jet.template secondaryVertices_as().size() < 1) + return; + if (!doprocessIPsData && !doprocessJPData && !doprocessSV2ProngData) { + registry.fill(HIST("h_jet_pt"), jet.pt(), eventWeight); + registry.fill(HIST("h_jet_eta"), jet.eta(), eventWeight); + registry.fill(HIST("h_jet_phi"), jet.phi(), eventWeight); + } + if (fillGeneralSVQA) { + registry.fill(HIST("h_3prong_nprongs"), jet.template secondaryVertices_as().size()); + for (const auto& prong : jet.template secondaryVertices_as()) { + registry.fill(HIST("h2_jet_pt_3prong_Lxy"), jet.pt(), prong.decayLengthXY()); + registry.fill(HIST("h2_jet_pt_3prong_Sxy"), jet.pt(), prong.decayLengthXY() / prong.errorDecayLengthXY()); + registry.fill(HIST("h2_jet_pt_3prong_Lxyz"), jet.pt(), prong.decayLength()); + registry.fill(HIST("h2_jet_pt_3prong_Sxyz"), jet.pt(), prong.decayLength() / prong.errorDecayLength()); + registry.fill(HIST("h2_jet_pt_3prong_sigmaLxy"), jet.pt(), prong.errorDecayLengthXY()); + registry.fill(HIST("h2_jet_pt_3prong_sigmaLxyz"), jet.pt(), prong.errorDecayLength()); + } + } + bool checkSv = false; + auto bjetCand = jettaggingutilities::jetFromProngMaxDecayLength(jet, prongChi2PCAMin, prongChi2PCAMax, prongsigmaLxyMax, prongIPxyMin, prongIPxyMax, false, &checkSv); + if (checkSv && jettaggingutilities::svAcceptance(bjetCand, svDispersionMax)) { + auto maxSxy = bjetCand.decayLengthXY() / bjetCand.errorDecayLengthXY(); + auto massSV = bjetCand.m(); + registry.fill(HIST("h2_jet_pt_3prong_Sxy_N1"), jet.pt(), maxSxy); + registry.fill(HIST("h2_jet_pt_3prong_mass_N1"), jet.pt(), massSV); + if (jet.isTagged(BJetTaggingMethod::SV)) { + registry.fill(HIST("h2_taggedjet_pt_3prong_Sxy_N1"), jet.pt(), maxSxy); + registry.fill(HIST("h2_taggedjet_pt_3prong_mass_N1"), jet.pt(), massSV); + } + } + auto bjetCandXYZ = jettaggingutilities::jetFromProngMaxDecayLength(jet, prongChi2PCAMin, prongChi2PCAMax, prongsigmaLxyzMax, prongIPxyMin, prongIPxyMax, true, &checkSv); + if (checkSv && jettaggingutilities::svAcceptance(bjetCandXYZ, svDispersionMax)) { + auto maxSxyz = bjetCandXYZ.decayLength() / bjetCandXYZ.errorDecayLength(); + auto massSV = bjetCandXYZ.m(); + registry.fill(HIST("h2_jet_pt_3prong_Sxyz_N1"), jet.pt(), maxSxyz); + registry.fill(HIST("h2_jet_pt_3prong_mass_xyz_N1"), jet.pt(), massSV); + if (jet.isTagged(BJetTaggingMethod::SV3D)) { + registry.fill(HIST("h2_taggedjet_pt_3prong_Sxyz_N1"), jet.pt(), maxSxyz); + registry.fill(HIST("h2_taggedjet_pt_3prong_mass_xyz_N1"), jet.pt(), massSV); + } + } + } + + template + void fillHistogramSV2ProngMCD(T const& mcdjet, U const& /*prongs*/, float eventWeight = 1.0) + { + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (mcdjet.pt() > pTHatMaxMCD * pTHat) { + return; + } + auto origin = mcdjet.origin(); + if (mcdjet.template secondaryVertices_as().size() < 1) + return; + if (!((doprocessIPsMCD || doprocessIPsMCDWeighted || doprocessIPsMCPMCDMatched || doprocessIPsMCPMCDMatchedWeighted) && (doprocessJPMCD || doprocessJPMCDWeighted || doprocessJPMCPMCDMatched || doprocessJPMCPMCDMatchedWeighted) && (doprocessSV3ProngMCD || doprocessSV3ProngMCDWeighted || doprocessSV3ProngMCPMCDMatched || doprocessSV3ProngMCPMCDMatchedWeighted))) { + registry.fill(HIST("h2_jet_pt_flavour"), mcdjet.pt(), origin, eventWeight); + registry.fill(HIST("h2_jet_eta_flavour"), mcdjet.eta(), origin, eventWeight); + registry.fill(HIST("h2_jet_phi_flavour"), mcdjet.phi(), origin, eventWeight); + } + if (fillGeneralSVQA) { + registry.fill(HIST("h2_2prong_nprongs_flavour"), mcdjet.template secondaryVertices_as().size(), origin, eventWeight); + for (const auto& prong : mcdjet.template secondaryVertices_as()) { + registry.fill(HIST("h3_jet_pt_2prong_Lxy_flavour"), mcdjet.pt(), prong.decayLengthXY(), origin, eventWeight); + registry.fill(HIST("h3_jet_pt_2prong_Sxy_flavour"), mcdjet.pt(), prong.decayLengthXY() / prong.errorDecayLengthXY(), origin, eventWeight); + registry.fill(HIST("h3_jet_pt_2prong_Lxyz_flavour"), mcdjet.pt(), prong.decayLength(), origin, eventWeight); + registry.fill(HIST("h3_jet_pt_2prong_Sxyz_flavour"), mcdjet.pt(), prong.decayLength() / prong.errorDecayLength(), origin, eventWeight); + registry.fill(HIST("h3_jet_pt_2prong_sigmaLxy_flavour"), mcdjet.pt(), prong.errorDecayLengthXY(), origin, eventWeight); + registry.fill(HIST("h3_jet_pt_2prong_sigmaLxyz_flavour"), mcdjet.pt(), prong.errorDecayLength(), origin, eventWeight); + } + } + bool checkSv = false; + auto bjetCand = jettaggingutilities::jetFromProngMaxDecayLength(mcdjet, prongChi2PCAMin, prongChi2PCAMax, prongsigmaLxyMax, prongIPxyMin, prongIPxyMax, false, &checkSv); + if (checkSv && jettaggingutilities::svAcceptance(bjetCand, svDispersionMax)) { + auto maxSxy = bjetCand.decayLengthXY() / bjetCand.errorDecayLengthXY(); + auto massSV = bjetCand.m(); + registry.fill(HIST("h3_jet_pt_2prong_Sxy_N1_flavour"), mcdjet.pt(), maxSxy, origin, eventWeight); + registry.fill(HIST("h3_jet_pt_2prong_mass_N1_flavour"), mcdjet.pt(), massSV, origin, eventWeight); + if (mcdjet.isTagged(BJetTaggingMethod::SV)) { + registry.fill(HIST("h3_taggedjet_pt_2prong_Sxy_N1_flavour"), mcdjet.pt(), maxSxy, origin, eventWeight); + registry.fill(HIST("h3_taggedjet_pt_2prong_mass_N1_flavour"), mcdjet.pt(), massSV, origin, eventWeight); + } + } + auto bjetCandXYZ = jettaggingutilities::jetFromProngMaxDecayLength(mcdjet, prongChi2PCAMin, prongChi2PCAMax, prongsigmaLxyzMax, prongIPxyMin, prongIPxyMax, true, &checkSv); + if (checkSv && jettaggingutilities::svAcceptance(bjetCandXYZ, svDispersionMax)) { + auto maxSxyz = bjetCandXYZ.decayLength() / bjetCandXYZ.errorDecayLength(); + auto massSV = bjetCandXYZ.m(); + registry.fill(HIST("h3_jet_pt_2prong_Sxyz_N1_flavour"), mcdjet.pt(), maxSxyz, origin, eventWeight); + registry.fill(HIST("h3_jet_pt_2prong_mass_xyz_N1_flavour"), mcdjet.pt(), massSV, origin, eventWeight); + if (mcdjet.isTagged(BJetTaggingMethod::SV3D)) { + registry.fill(HIST("h3_taggedjet_pt_2prong_Sxyz_N1_flavour"), mcdjet.pt(), maxSxyz, origin, eventWeight); + registry.fill(HIST("h3_taggedjet_pt_2prong_mass_xyz_N1_flavour"), mcdjet.pt(), massSV, origin, eventWeight); + } + } + } + + template + void fillHistogramSV3ProngMCD(T const& mcdjet, U const& /*prongs*/, float eventWeight = 1.0) + { + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (mcdjet.pt() > pTHatMaxMCD * pTHat) { + return; + } + auto origin = mcdjet.origin(); + if (mcdjet.template secondaryVertices_as().size() < 1) + return; + if (!((doprocessIPsMCD || doprocessIPsMCDWeighted || doprocessIPsMCPMCDMatched || doprocessIPsMCPMCDMatchedWeighted) && (doprocessJPMCD || doprocessJPMCDWeighted || doprocessJPMCPMCDMatched || doprocessJPMCPMCDMatchedWeighted) && (doprocessSV2ProngMCD || doprocessSV2ProngMCDWeighted || doprocessSV2ProngMCPMCDMatched || doprocessSV2ProngMCPMCDMatchedWeighted))) { + registry.fill(HIST("h2_jet_pt_flavour"), mcdjet.pt(), origin, eventWeight); + registry.fill(HIST("h2_jet_eta_flavour"), mcdjet.eta(), origin, eventWeight); + registry.fill(HIST("h2_jet_phi_flavour"), mcdjet.phi(), origin, eventWeight); + } + if (fillGeneralSVQA) { + registry.fill(HIST("h2_3prong_nprongs_flavour"), mcdjet.template secondaryVertices_as().size(), origin); + for (const auto& prong : mcdjet.template secondaryVertices_as()) { + registry.fill(HIST("h3_jet_pt_3prong_Lxy_flavour"), mcdjet.pt(), prong.decayLengthXY(), origin, eventWeight); + registry.fill(HIST("h3_jet_pt_3prong_Sxy_flavour"), mcdjet.pt(), prong.decayLengthXY() / prong.errorDecayLengthXY(), origin, eventWeight); + registry.fill(HIST("h3_jet_pt_3prong_Lxyz_flavour"), mcdjet.pt(), prong.decayLength(), origin, eventWeight); + registry.fill(HIST("h3_jet_pt_3prong_Sxyz_flavour"), mcdjet.pt(), prong.decayLength() / prong.errorDecayLength(), origin, eventWeight); + registry.fill(HIST("h3_jet_pt_3prong_sigmaLxy_flavour"), mcdjet.pt(), prong.errorDecayLengthXY(), origin, eventWeight); + registry.fill(HIST("h3_jet_pt_3prong_sigmaLxyz_flavour"), mcdjet.pt(), prong.errorDecayLength(), origin, eventWeight); + } + } + bool checkSv = false; + auto bjetCand = jettaggingutilities::jetFromProngMaxDecayLength(mcdjet, prongChi2PCAMin, prongChi2PCAMax, prongsigmaLxyMax, prongIPxyMin, prongIPxyMax, false, &checkSv); + if (checkSv && jettaggingutilities::svAcceptance(bjetCand, svDispersionMax)) { + auto maxSxy = bjetCand.decayLengthXY() / bjetCand.errorDecayLengthXY(); + auto massSV = bjetCand.m(); + registry.fill(HIST("h3_jet_pt_3prong_Sxy_N1_flavour"), mcdjet.pt(), maxSxy, origin, eventWeight); + registry.fill(HIST("h3_jet_pt_3prong_mass_N1_flavour"), mcdjet.pt(), massSV, origin, eventWeight); + if (mcdjet.isTagged(BJetTaggingMethod::SV)) { + registry.fill(HIST("h3_taggedjet_pt_3prong_Sxy_N1_flavour"), mcdjet.pt(), maxSxy, origin, eventWeight); + registry.fill(HIST("h3_taggedjet_pt_3prong_mass_N1_flavour"), mcdjet.pt(), massSV, origin, eventWeight); + } + } + auto bjetCandXYZ = jettaggingutilities::jetFromProngMaxDecayLength(mcdjet, prongChi2PCAMin, prongChi2PCAMax, prongsigmaLxyzMax, prongIPxyMin, prongIPxyMax, true, &checkSv); + if (checkSv && jettaggingutilities::svAcceptance(bjetCand, svDispersionMax)) { + auto maxSxyz = bjetCandXYZ.decayLength() / bjetCandXYZ.errorDecayLength(); + auto massSV = bjetCandXYZ.m(); + registry.fill(HIST("h3_jet_pt_3prong_Sxyz_N1_flavour"), mcdjet.pt(), maxSxyz, origin, eventWeight); + registry.fill(HIST("h3_jet_pt_3prong_mass_xyz_N1_flavour"), mcdjet.pt(), massSV, origin, eventWeight); + if (mcdjet.isTagged(BJetTaggingMethod::SV3D)) { + registry.fill(HIST("h3_taggedjet_pt_3prong_Sxyz_N1_flavour"), mcdjet.pt(), maxSxyz, origin, eventWeight); + registry.fill(HIST("h3_taggedjet_pt_3prong_mass_xyz_N1_flavour"), mcdjet.pt(), massSV, origin, eventWeight); + } + } + } + + void processDummy(aod::Collision const&, aod::Tracks const&) + { + } + PROCESS_SWITCH(JetTaggerHFQA, processDummy, "Dummy process", true); + + void processTracksDca(JetTagTracksData const& tracks) + { + for (auto const& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + float varImpXY, varImpXYSig, varImpZ, varImpZSig, varImpXYZ, varImpXYZSig; + varImpXY = track.dcaXY() * jettaggingutilities::cmTomum; + varImpXYSig = track.dcaXY() / track.sigmadcaXY(); + varImpZ = track.dcaZ() * jettaggingutilities::cmTomum; + varImpZSig = track.dcaZ() / track.sigmadcaZ(); + float dcaXYZ = track.dcaXYZ(); + float sigmadcaXYZ = track.sigmadcaXYZ(); + varImpXYZ = dcaXYZ * jettaggingutilities::cmTomum; + varImpXYZSig = dcaXYZ / sigmadcaXYZ; + + registry.fill(HIST("h_impact_parameter_xy"), varImpXY); + registry.fill(HIST("h_impact_parameter_xy_significance"), varImpXYSig); + registry.fill(HIST("h_impact_parameter_z"), varImpZ); + registry.fill(HIST("h_impact_parameter_z_significance"), varImpZSig); + registry.fill(HIST("h_impact_parameter_xyz"), varImpXYZ); + registry.fill(HIST("h_impact_parameter_xyz_significance"), varImpXYZSig); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processTracksDca, "Fill inclusive tracks' imformation for data", false); + + void processValFlavourDefMCD(soa::Filtered>::iterator const& collision, soa::Join const& mcdjets, soa::Join const& /*mcpjets*/, JetTagTracksMCD const& tracks, aod::JetParticles const& particles) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + auto const particlesPerColl = particles.sliceBy(particlesPerCollision, collision.mcCollisionId()); + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + fillValidationFlavourDefMCD>(mcdjet, tracks, particles, particlesPerColl, mcdjet.eventWeight()); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processValFlavourDefMCD, "to check the validation of jet-flavour definition when compared to distance for mcd jets", false); + + void processValFlavourDefMCP(soa::Join const& mcpjets, aod::JetParticles const& particles, aod::JetMcCollisions const&) + { + for (auto const& mcpjet : mcpjets) { + auto const particlesPerColl = particles.sliceBy(particlesPerCollision, mcpjet.globalIndex()); + if (!jetfindingutilities::isInEtaAcceptance(mcpjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcpjet)) { + continue; + } + int eventWeight = mcpjet.eventWeight(); + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (mcpjet.pt() > pTHatMaxMCD * pTHat) { + return; + } + fillValidationFlavourDefMCP(mcpjet, particles, particlesPerColl); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processValFlavourDefMCP, "to check the validation of jet-flavour definition when compared to distance for mcp jets", false); + + void processIPsData(soa::Filtered::iterator const& collision, soa::Join const& jets, JetTagTracksData const& tracks) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillHistogramIPsData(jet, tracks); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processIPsData, "Fill impact parameter imformation for data jets", false); + + void processIPsMCD(soa::Filtered::iterator const& collision, soa::Join const& mcdjets, JetTagTracksMCD const& tracks, aod::JetParticles const&) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + fillHistogramIPsMCD(mcdjet, tracks); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processIPsMCD, "Fill impact parameter imformation for mcd jets", false); + + void processIPsMCDWeighted(soa::Filtered::iterator const& collision, soa::Join const& mcdjets, JetTagTracksMCD const& tracks, aod::JetParticles const&) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + fillHistogramIPsMCD(mcdjet, tracks, mcdjet.eventWeight()); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processIPsMCDWeighted, "Fill impact parameter imformation for mcd jets", false); + + void processIPsMCP(JetTableMCP const& mcpjets, aod::JetParticles const&, aod::JetMcCollisions const&, soa::Filtered const& collisions) + { + for (auto const& mcpjet : mcpjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcpjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcpjet)) { + continue; + } + if (checkMcCollisionIsMatched) { + auto collisionspermcpjet = collisions.sliceBy(collisionsPerMCPCollision, mcpjet.mcCollisionId()); + if (collisionspermcpjet.size() >= 1 && jetderiveddatautilities::selectCollision(collisionspermcpjet.begin(), eventSelectionBits)) { + fillHistogramIPsMCP(mcpjet); + } + } else { + fillHistogramIPsMCP(mcpjet); + } + } + } + PROCESS_SWITCH(JetTaggerHFQA, processIPsMCP, "Fill impact parameter imformation for mcp jets", false); + + void processIPsMCPWeighted(soa::Join const& mcpjets, soa::Filtered const& collisions, aod::JetParticles const&) + { + for (auto const& mcpjet : mcpjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcpjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcpjet)) { + continue; + } + if (checkMcCollisionIsMatched) { + auto collisionspermcpjet = collisions.sliceBy(collisionsPerMCPCollision, mcpjet.mcCollisionId()); + if (collisionspermcpjet.size() >= 1 && jetderiveddatautilities::selectCollision(collisionspermcpjet.begin(), eventSelectionBits)) { + fillHistogramIPsMCP(mcpjet, mcpjet.eventWeight()); + } + } else { + fillHistogramIPsMCP(mcpjet, mcpjet.eventWeight()); + } + } + } + PROCESS_SWITCH(JetTaggerHFQA, processIPsMCPWeighted, "Fill impact parameter imformation for mcp jets weighted", false); + + void processIPsMCPMCDMatched(soa::Filtered>::iterator const& collision, soa::Join const& mcdjets, soa::Join const& /*mcpjets*/, JetTagTracksMCD const& tracks, aod::JetParticles const& particles) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + auto const particlesPerColl = particles.sliceBy(particlesPerCollision, collision.mcCollisionId()); + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + if (!mcdjet.has_matchedJetGeo()) + continue; + for (auto const& mcpjet : mcdjet.template matchedJetGeo_as>()) { + registry.fill(HIST("h3_jet_pt_jet_pt_part_matchedgeo_flavour"), mcdjet.pt(), mcpjet.pt(), mcdjet.origin()); + } + if (!doprocessIPsMCD) + fillHistogramIPsMCD(mcdjet, tracks); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processIPsMCPMCDMatched, "Fill impact parameter imformation for mcp mcd matched jets", false); + + void processIPsMCPMCDMatchedWeighted(soa::Filtered>::iterator const& collision, soa::Join const& mcdjets, soa::Join const& /*mcpjets*/, JetTagTracksMCD const& tracks, aod::JetParticles const& particles) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + auto const particlesPerColl = particles.sliceBy(particlesPerCollision, collision.mcCollisionId()); + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + if (!mcdjet.has_matchedJetGeo()) + continue; + float pTHat = 10. / (std::pow(mcdjet.eventWeight(), 1.0 / pTHatExponent)); + if (mcdjet.pt() > pTHatMaxMCD * pTHat) { + continue; + } + for (auto const& mcpjet : mcdjet.template matchedJetGeo_as>()) { + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + continue; + } + registry.fill(HIST("h3_jet_pt_jet_pt_part_matchedgeo_flavour"), mcdjet.pt(), mcpjet.pt(), mcdjet.origin(), mcdjet.eventWeight()); + } + if (!doprocessIPsMCDWeighted) + fillHistogramIPsMCD(mcdjet, tracks, mcdjet.eventWeight()); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processIPsMCPMCDMatchedWeighted, "Fill impact parameter imformation for mcp mcd matched jets", false); + + void processJPData(soa::Filtered::iterator const& collision, soa::Join const& jets, JetTagTracksData const&) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillHistogramJPData(jet); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processJPData, "Fill jet probability imformation for data jets", false); + + void processJPMCD(soa::Filtered::iterator const& collision, soa::Join const& mcdjets, JetTagTracksMCD const&) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + fillHistogramJPMCD(mcdjet); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processJPMCD, "Fill jet probability imformation for mcd jets", false); + + void processJPMCDWeighted(soa::Filtered::iterator const& collision, soa::Join const& mcdjets, JetTagTracksMCD const&) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + fillHistogramJPMCD(mcdjet, mcdjet.eventWeight()); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processJPMCDWeighted, "Fill jet probability imformation for mcd jets", false); + + void processJPMCPMCDMatched(soa::Filtered>::iterator const& collision, soa::Join const& mcdjets, soa::Join const& /*mcpjets*/, JetTagTracksMCD const&) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + if (!mcdjet.has_matchedJetGeo()) + return; + if (!doprocessJPMCD) + fillHistogramJPMCD(mcdjet); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processJPMCPMCDMatched, "Fill jet probability imformation for mcd jets", false); + + void processJPMCPMCDMatchedWeighted(soa::Filtered>::iterator const& collision, soa::Join const& mcdjets, soa::Join const& /*mcpjets*/, JetTagTracksMCD const&) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + if (!mcdjet.has_matchedJetGeo()) + return; + if (!doprocessJPMCDWeighted) + fillHistogramJPMCD(mcdjet, mcdjet.eventWeight()); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processJPMCPMCDMatchedWeighted, "Fill jet probability imformation for mcd jets", false); + + void processSV2ProngData(soa::Filtered::iterator const& collision, soa::Join const& jets, aod::DataSecondaryVertex2Prongs const& prongs) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillHistogramSV2ProngData(jet, prongs); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processSV2ProngData, "Fill 2prong imformation for data jets", false); + + void processSV3ProngData(soa::Filtered::iterator const& collision, soa::Join const& jets, aod::DataSecondaryVertex3Prongs const& prongs) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillHistogramSV3ProngData(jet, prongs); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processSV3ProngData, "Fill 2prong imformation for data jets", false); + + void processSV2ProngMCD(soa::Filtered::iterator const& collision, soa::Join const& mcdjets, aod::MCDSecondaryVertex2Prongs const& prongs) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + fillHistogramSV2ProngMCD(mcdjet, prongs); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processSV2ProngMCD, "Fill 2prong imformation for mcd jets", false); + + void processSV2ProngMCDWeighted(soa::Filtered::iterator const& collision, soa::Join const& mcdjets, aod::MCDSecondaryVertex2Prongs const& prongs) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + fillHistogramSV2ProngMCD(mcdjet, prongs, mcdjet.eventWeight()); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processSV2ProngMCDWeighted, "Fill 2prong imformation for mcd jets", false); + + void processSV2ProngMCPMCDMatched(soa::Filtered>::iterator const& collision, soa::Join const& mcdjets, soa::Join const& /*mcpjets*/, aod::MCDSecondaryVertex2Prongs const& prongs) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + if (!mcdjet.has_matchedJetGeo()) { + continue; + } + if (!doprocessSV2ProngMCD) + fillHistogramSV2ProngMCD(mcdjet, prongs); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processSV2ProngMCPMCDMatched, "Fill 2prong imformation for mcd jets", false); + + void processSV2ProngMCPMCDMatchedWeighted(soa::Filtered>::iterator const& collision, soa::Join const& mcdjets, soa::Join const& /*mcpjets*/, aod::MCDSecondaryVertex2Prongs const& prongs) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + if (!mcdjet.has_matchedJetGeo()) { + continue; + } + if (!doprocessSV2ProngMCDWeighted) + fillHistogramSV2ProngMCD(mcdjet, prongs, mcdjet.eventWeight()); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processSV2ProngMCPMCDMatchedWeighted, "Fill 2prong imformation for mcd jets", false); + + void processSV3ProngMCD(soa::Filtered::iterator const& collision, soa::Join const& mcdjets, aod::MCDSecondaryVertex3Prongs const& prongs) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + fillHistogramSV3ProngMCD(mcdjet, prongs); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processSV3ProngMCD, "Fill 3prong imformation for mcd jets", false); + + void processSV3ProngMCDWeighted(soa::Filtered::iterator const& collision, soa::Join const& mcdjets, aod::MCDSecondaryVertex3Prongs const& prongs) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + fillHistogramSV3ProngMCD(mcdjet, prongs, mcdjet.eventWeight()); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processSV3ProngMCDWeighted, "Fill 3prong imformation for mcd jets", false); + + void processSV3ProngMCPMCDMatched(soa::Filtered>::iterator const& collision, soa::Join const& mcdjets, soa::Join const& /*mcpjets*/, aod::MCDSecondaryVertex3Prongs const& prongs) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + if (!mcdjet.has_matchedJetGeo()) { + continue; + } + if (!doprocessSV3ProngMCD) + fillHistogramSV3ProngMCD(mcdjet, prongs); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processSV3ProngMCPMCDMatched, "Fill 3prong imformation for mcd jets", false); + + void processSV3ProngMCPMCDMatchedWeighted(soa::Filtered>::iterator const& collision, soa::Join const& mcdjets, soa::Join const& /*mcpjets*/, aod::MCDSecondaryVertex3Prongs const& prongs) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + if (!mcdjet.has_matchedJetGeo()) { + continue; + } + if (!doprocessSV3ProngMCDWeighted) + fillHistogramSV3ProngMCD(mcdjet, prongs, mcdjet.eventWeight()); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processSV3ProngMCPMCDMatchedWeighted, "Fill 3prong imformation for mcd jets", false); +}; + +using JetTaggerQAChargedDataJets = soa::Join; +using JetTaggerQAChargedMCDJets = soa::Join; +using JetTaggerQAChargedMCPJets = soa::Join; + +using JetTaggerhfQACharged = JetTaggerHFQA; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"jet-taggerhf-qa-charged"})}; // o2-linter: disable=name/o2-task +} diff --git a/PWGJE/Tasks/jetTutorial.cxx b/PWGJE/Tasks/jetTutorial.cxx index 0065726bae2..cdc02e582f1 100644 --- a/PWGJE/Tasks/jetTutorial.cxx +++ b/PWGJE/Tasks/jetTutorial.cxx @@ -9,11 +9,14 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -// jet tutorial task for hands on tutorial session (09/11/2023) +// jet tutorial task for hands on tutorial session (16/11/2024) // /// \author Nima Zardoshti // +#include +#include + #include "Framework/ASoA.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" @@ -26,6 +29,7 @@ #include "Common/DataModel/TrackSelectionTables.h" #include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetUtilities.h" #include "PWGJE/Core/JetDerivedDataUtilities.h" #include "PWGJE/DataModel/Jet.h" @@ -45,12 +49,14 @@ struct JetTutorialTask { {"h_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, {"h_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, {"h_jet_phi", "jet #phi;#phi_{jet};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}, - {"h_jet_pt_bkgsub", "jet pT bkg sub;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, + {"h_jet_pt_rhosub", "jet pT bkg sub;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, + {"h_jet_pt_constsub", "jet pT bkg sub;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, {"h_part_jet_pt", "particle level jet pT;#it{p}_{T,jet part} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, {"h_part_jet_eta", "particle level jet #eta;#eta_{jet part};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, {"h_part_jet_phi", "particle level jet #phi;#phi_{jet part};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}, {"h_jet_ntracks", "jet N tracks;N_{jet tracks};entries", {HistType::kTH1F, {{40, -0.5, 39.5}}}}, {"h_jet_angularity", "jet angularity ;#lambda_{1};entries", {HistType::kTH1F, {{5, 0.0, 0.5}}}}, + {"h_jet_angularity_constsub", "jet angularity bkg sub;#lambda_{1};entries", {HistType::kTH1F, {{5, 0.0, 0.5}}}}, {"h_full_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, {"h_full_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, {"h_full_jet_phi", "jet #phi;#phi_{jet};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}, @@ -66,28 +72,41 @@ struct JetTutorialTask { {"h_matched_jets_eta", "#eta_{jet part}; #eta_{jet det}", {HistType::kTH2F, {{100, -1.0, 1.0}, {100, -1.0, 1.0}}}}, {"h_matched_jets_phi", "#phi_{jet part}; #phi_{jet det}", {HistType::kTH2F, {{80, -1.0, 7.}, {80, -1.0, 7.}}}}}}; + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + Configurable jetPtMin{"jetPtMin", 5.0, "minimum jet pT cut"}; Configurable jetR{"jetR", 0.4, "jet resolution parameter"}; Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; - int eventSelection = -1; + Configurable kappa{"kappa", 1.0, "angularity kappa"}; + Configurable alpha{"alpha", 1.0, "angularity alpha"}; + + Configurable triggerMasks{"triggerMasks", "", "possible JE Trigger masks: fJetChLowPt,fJetChHighPt,fTrackLowPt,fTrackHighPt,fJetD0ChLowPt,fJetD0ChHighPt,fJetLcChLowPt,fJetLcChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt,fJetNeutralHighPt,fJetNeutralLowPt,fGammaVeryHighPtEMCAL,fGammaVeryHighPtDCAL,fGammaHighPtEMCAL,fGammaHighPtDCAL,fGammaLowPtEMCAL,fGammaLowPtDCAL,fGammaVeryLowPtEMCAL,fGammaVeryLowPtDCAL"}; + + std::vector eventSelectionBits; int trackSelection = -1; + std::vector triggerMaskBits; void init(o2::framework::InitContext&) { - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(eventSelections)); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(triggerMasks); } Filter jetCuts = aod::jet::pt > jetPtMin&& aod::jet::r == nround(jetR.node() * 100.0f); + Filter collisionFilter = nabs(aod::jcollision::posZ) < vertexZCut; + Filter mcCollisionFilter = nabs(aod::jmccollision::posZ) < vertexZCut; + + Preslice> perMcCollisionJets = aod::jet::mcCollisionId; - void processCollisions(JetCollision const& collision, JetTracks const& tracks) + void processCollisions(aod::JetCollision const& collision, aod::JetTracks const& tracks) { registry.fill(HIST("h_collisions"), 0.5); - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } registry.fill(HIST("h_collisions"), 1.5); @@ -100,13 +119,13 @@ struct JetTutorialTask { registry.fill(HIST("h_track_phi"), track.phi()); } } - PROCESS_SWITCH(JetTutorialTask, processCollisions, "process self contained collisions", true); + PROCESS_SWITCH(JetTutorialTask, processCollisions, "process JE collisions", false); - void processCollisionsWithExternalTracks(JetCollision const& collision, soa::Join const& tracks, soa::Join const&) + void processCollisionsWithExternalTracks(soa::Filtered::iterator const& collision, soa::Join const& tracks, soa::Join const&) { registry.fill(HIST("h_collisions"), 0.5); - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } registry.fill(HIST("h_collisions"), 1.5); @@ -121,126 +140,167 @@ struct JetTutorialTask { registry.fill(HIST("h_track_chi2PerCluster"), originalTrack.tpcChi2NCl()); } } - PROCESS_SWITCH(JetTutorialTask, processCollisionsWithExternalTracks, "process non self contained collisions", true); + PROCESS_SWITCH(JetTutorialTask, processCollisionsWithExternalTracks, "process JE collisions with access to the original track table", false); - void processDataCharged(soa::Filtered::iterator const& jet) + void processDataCharged(soa::Filtered::iterator const& collision, soa::Filtered const& jets) { - registry.fill(HIST("h_jet_pt"), jet.pt()); - registry.fill(HIST("h_jet_eta"), jet.eta()); - registry.fill(HIST("h_jet_phi"), jet.phi()); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + for (auto& jet : jets) { + registry.fill(HIST("h_jet_pt"), jet.pt()); + registry.fill(HIST("h_jet_eta"), jet.eta()); + registry.fill(HIST("h_jet_phi"), jet.phi()); + } } - PROCESS_SWITCH(JetTutorialTask, processDataCharged, "jets data", true); + PROCESS_SWITCH(JetTutorialTask, processDataCharged, "charged jets in data", false); - void processMCDetectorLevelCharged(soa::Filtered::iterator const& jet) + void processMCDetectorLevelCharged(soa::Filtered::iterator const& collision, soa::Filtered const& jets) { - registry.fill(HIST("h_jet_pt"), jet.pt()); - registry.fill(HIST("h_jet_eta"), jet.eta()); - registry.fill(HIST("h_jet_phi"), jet.phi()); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + for (auto& jet : jets) { + registry.fill(HIST("h_jet_pt"), jet.pt()); + registry.fill(HIST("h_jet_eta"), jet.eta()); + registry.fill(HIST("h_jet_phi"), jet.phi()); + } } - PROCESS_SWITCH(JetTutorialTask, processMCDetectorLevelCharged, "jets on detector level MC", false); + PROCESS_SWITCH(JetTutorialTask, processMCDetectorLevelCharged, "charged jets in detector level MC", false); - void processMCParticleLevel(soa::Filtered::iterator const& jet) + void processMCDetectorLevelWeightedCharged(soa::Filtered::iterator const& collision, aod::JetMcCollisions const&, soa::Filtered const& jets) { - registry.fill(HIST("h_part_jet_pt"), jet.pt()); - registry.fill(HIST("h_part_jet_eta"), jet.eta()); - registry.fill(HIST("h_part_jet_phi"), jet.phi()); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + for (auto& jet : jets) { + registry.fill(HIST("h_jet_pt"), jet.pt(), collision.mcCollision().weight()); + registry.fill(HIST("h_jet_eta"), jet.eta(), collision.mcCollision().weight()); + registry.fill(HIST("h_jet_phi"), jet.phi(), collision.mcCollision().weight()); + } } - PROCESS_SWITCH(JetTutorialTask, processMCParticleLevel, "jets on particle level MC", false); + PROCESS_SWITCH(JetTutorialTask, processMCDetectorLevelWeightedCharged, "charged jets in weighted detector level MC", false); - void processMCCharged(JetCollision const&, soa::Filtered const& mcdjets, soa::Filtered const& mcpjets) + void processMCParticleLevelCharged(soa::Filtered::iterator const& mcCollision, soa::Filtered const& jets) { + for (auto& jet : jets) { + registry.fill(HIST("h_part_jet_pt"), jet.pt(), mcCollision.weight()); + registry.fill(HIST("h_part_jet_eta"), jet.eta(), mcCollision.weight()); + registry.fill(HIST("h_part_jet_phi"), jet.phi(), mcCollision.weight()); + } + } + PROCESS_SWITCH(JetTutorialTask, processMCParticleLevelCharged, "charged jets in particle level MC", false); + + void processMCCharged(soa::Filtered::iterator const& collision, aod::JetMcCollisions const&, soa::Filtered const& mcdjets, soa::Filtered const& mcpjets) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } for (auto& mcdjet : mcdjets) { - registry.fill(HIST("h_jet_pt"), mcdjet.pt()); - registry.fill(HIST("h_jet_eta"), mcdjet.eta()); - registry.fill(HIST("h_jet_phi"), mcdjet.phi()); + registry.fill(HIST("h_jet_pt"), mcdjet.pt(), collision.mcCollision().weight()); + registry.fill(HIST("h_jet_eta"), mcdjet.eta(), collision.mcCollision().weight()); + registry.fill(HIST("h_jet_phi"), mcdjet.phi(), collision.mcCollision().weight()); } - for (auto& mcpjet : mcpjets) { - registry.fill(HIST("h_part_jet_pt"), mcpjet.pt()); - registry.fill(HIST("h_part_jet_eta"), mcpjet.eta()); - registry.fill(HIST("h_part_jet_phi"), mcpjet.phi()); + auto mcpjetsPerCollision = mcpjets.sliceBy(perMcCollisionJets, collision.mcCollisionId()); + for (auto& mcpjet : mcpjetsPerCollision) { + registry.fill(HIST("h_part_jet_pt"), mcpjet.pt(), collision.mcCollision().weight()); + registry.fill(HIST("h_part_jet_eta"), mcpjet.eta(), collision.mcCollision().weight()); + registry.fill(HIST("h_part_jet_phi"), mcpjet.phi(), collision.mcCollision().weight()); } } - PROCESS_SWITCH(JetTutorialTask, processMCCharged, "jets on detector and particle level MC", false); + PROCESS_SWITCH(JetTutorialTask, processMCCharged, "charged jets in detector and particle level MC", false); using JetMCPTable = soa::Filtered>; - void processMCChargedMatched(JetCollision const&, + void processMCMatchedCharged(soa::Filtered::iterator const& collision, soa::Filtered> const& mcdjets, JetMCPTable const&, - JetTracks const&, - JetParticles const&) + aod::JetTracks const&, + aod::JetParticles const&) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } for (const auto& mcdjet : mcdjets) { - for (auto& mcpjet : mcdjet.template matchedJetGeo_as()) { - // for (auto& mcpjet : mcdjet.template matchedJetPt_as()) { - - registry.fill(HIST("h_matched_jets_pt"), mcpjet.pt(), mcdjet.pt()); - registry.fill(HIST("h_matched_jets_pt"), mcpjet.phi(), mcdjet.phi()); - registry.fill(HIST("h_matched_jets_pt"), mcpjet.eta(), mcdjet.eta()); + registry.fill(HIST("h_matched_jets_pt"), mcpjet.pt(), mcdjet.pt(), collision.mcCollision().weight()); + registry.fill(HIST("h_matched_jets_pt"), mcpjet.phi(), mcdjet.phi(), collision.mcCollision().weight()); + registry.fill(HIST("h_matched_jets_pt"), mcpjet.eta(), mcdjet.eta(), collision.mcCollision().weight()); } } } - PROCESS_SWITCH(JetTutorialTask, processMCChargedMatched, "jet finder QA matched mcp and mcd", false); + PROCESS_SWITCH(JetTutorialTask, processMCMatchedCharged, "matched detector and particle level charged jets", false); - void processDataChargedSubstructure(soa::Filtered>::iterator const& jet, JetTracks const&) + void processDataSubstructureCharged(soa::Filtered::iterator const& collision, soa::Filtered> const& jets, aod::JetTracks const&) { - // add aditional selection on jet eta - registry.fill(HIST("h_jet_pt"), jet.pt()); - registry.fill(HIST("h_jet_eta"), jet.eta()); - registry.fill(HIST("h_jet_phi"), jet.phi()); - registry.fill(HIST("h_jet_ntracks"), jet.tracksIds().size()); - double angularity = 0.0; - for (auto& jetConstituent : jet.tracks_as()) { - angularity += jetConstituent.pt() * TMath::Sqrt(TMath::Power(jet.phi() - jetConstituent.phi(), 2.0) + TMath::Power(jet.eta() - jetConstituent.eta(), 2.0)); - } - registry.fill(HIST("h_jet_angularity"), angularity / (jet.pt() * round(jet.r() / 100.0f))); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + for (auto& jet : jets) { + registry.fill(HIST("h_jet_pt"), jet.pt()); + registry.fill(HIST("h_jet_eta"), jet.eta()); + registry.fill(HIST("h_jet_phi"), jet.phi()); + registry.fill(HIST("h_jet_ntracks"), jet.tracksIds().size()); + double angularity = 0.0; + for (auto& jetConstituent : jet.tracks_as()) { + angularity += std::pow(jetConstituent.pt(), kappa) * std::pow(jetutilities::deltaR(jet, jetConstituent), alpha); + } + angularity /= (jet.pt() * (jet.r() / 100.f)); + registry.fill(HIST("h_jet_angularity"), angularity); + } } - PROCESS_SWITCH(JetTutorialTask, processDataChargedSubstructure, "jet substructure charged jets", false); + PROCESS_SWITCH(JetTutorialTask, processDataSubstructureCharged, "charged jet substructure", false); - void processMCParticleSubstructure(soa::Filtered>::iterator const& jet, JetParticles const&) + void processDataFull(soa::Filtered::iterator const&, soa::Filtered const& jets) { - double angularity = 0.0; - for (auto& jetConstituents : jet.tracks_as()) { - angularity += jetConstituents.pt() * TMath::Sqrt(TMath::Power(jet.phi() - jetConstituents.phi(), 2.0) + TMath::Power(jet.eta() - jetConstituents.eta(), 2.0)); + for (auto& jet : jets) { + registry.fill(HIST("h_jet_pt"), jet.pt()); + registry.fill(HIST("h_jet_eta"), jet.eta()); + registry.fill(HIST("h_jet_phi"), jet.phi()); } - registry.fill(HIST("h_part_jet_angularity"), angularity / (jet.pt() * round(jet.r() / 100.0f))); } - PROCESS_SWITCH(JetTutorialTask, processMCParticleSubstructure, "jet substructure particle level full jets", false); + PROCESS_SWITCH(JetTutorialTask, processDataFull, "full jets in data", false); - void processDataFull(soa::Filtered::iterator const& jet) + void processDataSubstructureFull(soa::Filtered::iterator const&, soa::Filtered> const& jets, aod::JetTracks const&, aod::JetClusters const&) { - registry.fill(HIST("h_jet_pt"), jet.pt()); - registry.fill(HIST("h_jet_eta"), jet.eta()); - registry.fill(HIST("h_jet_phi"), jet.phi()); - } - PROCESS_SWITCH(JetTutorialTask, processDataFull, "jets data", true); + for (auto& jet : jets) { + registry.fill(HIST("h_full_jet_pt"), jet.pt()); + registry.fill(HIST("h_full_jet_eta"), jet.eta()); + registry.fill(HIST("h_full_jet_phi"), jet.phi()); + registry.fill(HIST("h_full_jet_ntracks"), jet.tracksIds().size()); + registry.fill(HIST("h_full_jet_nclusters"), jet.clustersIds().size()); + double angularity = 0.0; + for (auto& jetConstituent : jet.tracks_as()) { + angularity += std::pow(jetConstituent.pt(), kappa) * std::pow(jetutilities::deltaR(jet, jetConstituent), alpha); + } - void processDataFullSubstructure(soa::Filtered>::iterator const& jet, JetTracks const&, JetClusters const&) - { - // add aditional selection on jet eta - registry.fill(HIST("h_full_jet_pt"), jet.pt()); - registry.fill(HIST("h_full_jet_eta"), jet.eta()); - registry.fill(HIST("h_full_jet_phi"), jet.phi()); - registry.fill(HIST("h_full_jet_ntracks"), jet.tracksIds().size()); - registry.fill(HIST("h_full_jet_nclusters"), jet.clustersIds().size()); - double angularity = 0.0; - for (auto& jetTrack : jet.tracks_as()) { - angularity += jetTrack.pt() * TMath::Sqrt(TMath::Power(jet.phi() - jetTrack.phi(), 2.0) + TMath::Power(jet.eta() - jetTrack.eta(), 2.0)); - } + for (auto& jetCluster : jet.clusters_as()) { + angularity += std::pow(jetCluster.energy(), kappa) * std::pow(jetutilities::deltaR(jet, jetCluster), alpha); + } - for (auto& jetCluster : jet.clusters_as()) { - angularity += jetCluster.energy() * TMath::Sqrt(TMath::Power(jet.phi() - jetCluster.phi(), 2.0) + TMath::Power(jet.eta() - jetCluster.eta(), 2.0)); + registry.fill(HIST("h_full_jet_angularity"), angularity / (jet.pt() * round(jet.r() * 100.0f))); } + } + PROCESS_SWITCH(JetTutorialTask, processDataSubstructureFull, "full jet substructure", false); - registry.fill(HIST("h_full_jet_angularity"), angularity / (jet.pt() * round(jet.r() * 100.0f))); + void processMCParticleLevelSubstructureFull(soa::Filtered::iterator const& mcCollision, soa::Filtered> const& jets, aod::JetParticles const&) + { + for (auto& jet : jets) { + double angularity = 0.0; + for (auto& jetConstituent : jet.tracks_as()) { + angularity += std::pow(jetConstituent.pt(), kappa) * std::pow(jetutilities::deltaR(jet, jetConstituent), alpha); + } + angularity /= (jet.pt() * (jet.r() / 100.f)); + registry.fill(HIST("h_part_jet_angularity"), angularity, mcCollision.weight()); + } } - PROCESS_SWITCH(JetTutorialTask, processDataFullSubstructure, "jet substructure full jets", false); + PROCESS_SWITCH(JetTutorialTask, processMCParticleLevelSubstructureFull, "full particle level jet substructure", false); - void processDataRecoil(JetCollision const& collision, soa::Filtered const& jets, JetTracks const& tracks) + void processRecoilDataCharged(soa::Filtered::iterator const& collision, soa::Filtered const& jets, aod::JetTracks const& tracks) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } + bool selectedEvent = false; double leadingTrackpT = 0.0; double leadingTrackPhi = 0.0; for (auto& track : tracks) { @@ -248,13 +308,15 @@ struct JetTutorialTask { if (track.pt() > leadingTrackpT) { leadingTrackpT = track.pt(); leadingTrackPhi = track.phi(); + selectedEvent = true; } } } - if (leadingTrackpT == 0.0) + if (!selectedEvent) { return; + } for (auto& jet : jets) { - if (TMath::Abs(RecoDecay::constrainAngle(RecoDecay::constrainAngle(jet.phi(), -o2::constants::math::PIHalf) - RecoDecay::constrainAngle(leadingTrackPhi, -o2::constants::math::PIHalf), -o2::constants::math::PIHalf) > 0.6)) { + if (std::abs(RecoDecay::constrainAngle(jet.phi() - leadingTrackPhi, -o2::constants::math::PIHalf)) > 0.6) { registry.fill(HIST("h_recoil_jet_pt"), jet.pt()); registry.fill(HIST("h_recoil_jet_eta"), jet.eta()); registry.fill(HIST("h_recoil_jet_phi"), jet.phi()); @@ -262,18 +324,67 @@ struct JetTutorialTask { } } } - PROCESS_SWITCH(JetTutorialTask, processDataRecoil, "hadron-recoil jets", false); + PROCESS_SWITCH(JetTutorialTask, processRecoilDataCharged, "hadron-recoil charged jets", false); + + void processDataRhoAreaSubtractedCharged(soa::Filtered>::iterator const& collision, soa::Filtered const& jets) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + for (auto jet : jets) { + registry.fill(HIST("h_jet_pt"), jet.pt()); + registry.fill(HIST("h_jet_pt_rhosub"), jet.pt() - (collision.rho() * jet.area())); + registry.fill(HIST("h_jet_eta"), jet.eta()); + registry.fill(HIST("h_jet_phi"), jet.phi()); + } + } + PROCESS_SWITCH(JetTutorialTask, processDataRhoAreaSubtractedCharged, "charged rho-area subtracted jets", false); - /*void processDataBackgroundSubtracted(soa::Join::iterator const& collision, soa::Filtered const& jets) + void processDataConstituentSubtractedCharged(soa::Filtered::iterator const& collision, soa::Filtered const& jets) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + for (auto jet : jets) { + registry.fill(HIST("h_jet_pt_constsub"), jet.pt()); + registry.fill(HIST("h_jet_eta"), jet.eta()); + registry.fill(HIST("h_jet_phi"), jet.phi()); + } + } + PROCESS_SWITCH(JetTutorialTask, processDataConstituentSubtractedCharged, "charged constituent subtracted jets", false); + + void processDataConstituentSubtractedSubstructureCharged(soa::Filtered::iterator const& collision, soa::Filtered> const& jets, aod::JetTracksSub const&) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } for (auto jet : jets) { + registry.fill(HIST("h_jet_pt_constsub"), jet.pt()); + registry.fill(HIST("h_jet_eta"), jet.eta()); + registry.fill(HIST("h_jet_phi"), jet.phi()); + registry.fill(HIST("h_jet_ntracks"), jet.tracksIds().size()); + double angularity = 0.0; + for (auto& jetConstituent : jet.tracks_as()) { + angularity += std::pow(jetConstituent.pt(), kappa) * std::pow(jetutilities::deltaR(jet, jetConstituent), alpha); + } + angularity /= (jet.pt() * (jet.r() / 100.f)); + registry.fill(HIST("h_jet_angularity_constsub"), angularity); + } + } + PROCESS_SWITCH(JetTutorialTask, processDataConstituentSubtractedSubstructureCharged, "charged constituent subtracted jet substructure", false); + + void processDataTriggered(soa::Filtered::iterator const& collision, soa::Filtered const& jets) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || !jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + for (auto& jet : jets) { registry.fill(HIST("h_jet_pt"), jet.pt()); - registry.fill(HIST("h_jet_pt_bkgsub"), jet.pt() - (collision.rho() * jet.area())); registry.fill(HIST("h_jet_eta"), jet.eta()); registry.fill(HIST("h_jet_phi"), jet.phi()); } } - PROCESS_SWITCH(JetTutorialTask, processDataBackgroundSubtracted, "baackground subtracted jets", false);*/ + PROCESS_SWITCH(JetTutorialTask, processDataTriggered, "jets triggered", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"jet-tutorial"})}; } diff --git a/PWGJE/Tasks/jetTutorialSkeleton.cxx b/PWGJE/Tasks/jetTutorialSkeleton.cxx index ba5310ef535..df2098539e8 100644 --- a/PWGJE/Tasks/jetTutorialSkeleton.cxx +++ b/PWGJE/Tasks/jetTutorialSkeleton.cxx @@ -9,11 +9,14 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -// jet tutorial skeleton task for hands on tutorial session (09/11/2023) +// jet tutorial task for hands on tutorial session (16/11/2024) // /// \author Nima Zardoshti // +#include +#include + #include "Framework/ASoA.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" @@ -26,6 +29,7 @@ #include "Common/DataModel/TrackSelectionTables.h" #include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetUtilities.h" #include "PWGJE/Core/JetDerivedDataUtilities.h" #include "PWGJE/DataModel/Jet.h" @@ -45,12 +49,14 @@ struct JetTutorialSkeletonTask { {"h_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, {"h_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, {"h_jet_phi", "jet #phi;#phi_{jet};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}, - {"h_jet_pt_bkgsub", "jet pT bkg sub;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, + {"h_jet_pt_rhosub", "jet pT bkg sub;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, + {"h_jet_pt_constsub", "jet pT bkg sub;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, {"h_part_jet_pt", "particle level jet pT;#it{p}_{T,jet part} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, {"h_part_jet_eta", "particle level jet #eta;#eta_{jet part};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, {"h_part_jet_phi", "particle level jet #phi;#phi_{jet part};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}, {"h_jet_ntracks", "jet N tracks;N_{jet tracks};entries", {HistType::kTH1F, {{40, -0.5, 39.5}}}}, {"h_jet_angularity", "jet angularity ;#lambda_{1};entries", {HistType::kTH1F, {{5, 0.0, 0.5}}}}, + {"h_jet_angularity_constsub", "jet angularity bkg sub;#lambda_{1};entries", {HistType::kTH1F, {{5, 0.0, 0.5}}}}, {"h_full_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, {"h_full_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, {"h_full_jet_phi", "jet #phi;#phi_{jet};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}, @@ -66,92 +72,153 @@ struct JetTutorialSkeletonTask { {"h_matched_jets_eta", "#eta_{jet part}; #eta_{jet det}", {HistType::kTH2F, {{100, -1.0, 1.0}, {100, -1.0, 1.0}}}}, {"h_matched_jets_phi", "#phi_{jet part}; #phi_{jet det}", {HistType::kTH2F, {{80, -1.0, 7.}, {80, -1.0, 7.}}}}}}; + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + Configurable jetPtMin{"jetPtMin", 5.0, "minimum jet pT cut"}; Configurable jetR{"jetR", 0.4, "jet resolution parameter"}; Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; - int eventSelection = -1; + Configurable kappa{"kappa", 1.0, "angularity kappa"}; + Configurable alpha{"alpha", 1.0, "angularity alpha"}; + + Configurable triggerMasks{"triggerMasks", "", "possible JE Trigger masks: fJetChLowPt,fJetChHighPt,fTrackLowPt,fTrackHighPt,fJetD0ChLowPt,fJetD0ChHighPt,fJetLcChLowPt,fJetLcChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt,fJetNeutralHighPt,fJetNeutralLowPt,fGammaVeryHighPtEMCAL,fGammaVeryHighPtDCAL,fGammaHighPtEMCAL,fGammaHighPtDCAL,fGammaLowPtEMCAL,fGammaLowPtDCAL,fGammaVeryLowPtEMCAL,fGammaVeryLowPtDCAL"}; + + std::vector eventSelectionBits; int trackSelection = -1; + std::vector triggerMaskBits; void init(o2::framework::InitContext&) { - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(eventSelections)); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(triggerMasks); } Filter jetCuts = aod::jet::pt > jetPtMin&& aod::jet::r == nround(jetR.node() * 100.0f); + Filter collisionFilter = nabs(aod::jcollision::posZ) < vertexZCut; + Filter mcCollisionFilter = nabs(aod::jmccollision::posZ) < vertexZCut; - void processCollisions(aod::JCollision const&, aod::JTracks const&) - { - } - PROCESS_SWITCH(JetTutorialSkeletonTask, processCollisions, "process self contained collisions", true); + Preslice> perMcCollisionJets = aod::jet::mcCollisionId; - void processCollisionsWithExternalTracks(aod::JCollision const&, soa::Join const&, soa::Join const&) + void processDummy(aod::JDummys const&) { } - PROCESS_SWITCH(JetTutorialSkeletonTask, processCollisionsWithExternalTracks, "process non self contained collisions", true); + PROCESS_SWITCH(JetTutorialSkeletonTask, processDummy, "dummy process", false); - void processDataCharged(soa::Filtered::iterator const&) - { - } - PROCESS_SWITCH(JetTutorialSkeletonTask, processDataCharged, "jets data", true); + /* + void processCollisions(aod::JetCollision const& collision, aod::JetTracks const& tracks) + { - void processMCDetectorLevelCharged(soa::Filtered::iterator const&) - { - } - PROCESS_SWITCH(JetTutorialSkeletonTask, processMCDetectorLevelCharged, "jets on detector level MC", false); + } + PROCESS_SWITCH(JetTutorialSkeletonTask, processCollisions, "process JE collisions", false); - void processMCParticleLevel(soa::Filtered::iterator const&) - { - } - PROCESS_SWITCH(JetTutorialSkeletonTask, processMCParticleLevel, "jets on particle level MC", false); + void processCollisionsWithExternalTracks(soa::Filtered::iterator const& collision, soa::Join const& tracks, soa::Join const&) + { - void processMCCharged(aod::JCollisions const&, soa::Filtered const&, soa::Filtered const&) - { - } - PROCESS_SWITCH(JetTutorialSkeletonTask, processMCCharged, "jets on detector and particle level MC", false); - - using JetMCPTable = soa::Filtered>; - void processMCChargedMatched(aod::JCollision const&, - soa::Filtered> const&, - JetMCPTable const&, - aod::JTracks const&, - aod::JMcParticles const&) - { - } - PROCESS_SWITCH(JetTutorialSkeletonTask, processMCChargedMatched, "jet finder QA matched mcp and mcd", false); + } + PROCESS_SWITCH(JetTutorialSkeletonTask, processCollisionsWithExternalTracks, "process JE collisions with access to the original track table", false); - void processDataChargedSubstructure(soa::Filtered>::iterator const&, aod::JTracks const&) - { - } - PROCESS_SWITCH(JetTutorialSkeletonTask, processDataChargedSubstructure, "jet substructure charged jets", false); + void processDataCharged(soa::Filtered::iterator const& collision, soa::Filtered const& jets) + { - void processMCParticleSubstructure(soa::Filtered>::iterator const&, aod::JMcParticles const&) - { - } - PROCESS_SWITCH(JetTutorialSkeletonTask, processMCParticleSubstructure, "jet substructure particle level full jets", false); + } + PROCESS_SWITCH(JetTutorialSkeletonTask, processDataCharged, "charged jets in data", false); - void processDataFull(soa::Filtered::iterator const&) - { - } - PROCESS_SWITCH(JetTutorialSkeletonTask, processDataFull, "jets data", true); + void processMCDetectorLevelCharged(soa::Filtered::iterator const& collision, soa::Filtered const& jets) + { - void processDataFullSubstructure(soa::Filtered>::iterator const&, aod::JTracks const&, aod::JClusters const&) - { - } - PROCESS_SWITCH(JetTutorialSkeletonTask, processDataFullSubstructure, "jet substructure full jets", false); + } + PROCESS_SWITCH(JetTutorialSkeletonTask, processMCDetectorLevelCharged, "charged jets in detector level MC", false); - void processDataRecoil(aod::JCollision const&, soa::Filtered const&, aod::JTracks const&) - { - } - PROCESS_SWITCH(JetTutorialSkeletonTask, processDataRecoil, "hadron-recoil jets", false); + void processMCDetectorLevelWeightedCharged(soa::Filtered::iterator const& collision, aod::JetMcCollisions const& ,soa::Filtered const& jets) + { - /*void processDataBackgroundSubtracted(soa::Join::iterator const& collision, soa::Filtered const& jets) - { - } - PROCESS_SWITCH(JetTutorialSkeletonTask, processDataBackgroundSubtracted, "baackground subtracted jets", false);*/ + } + PROCESS_SWITCH(JetTutorialSkeletonTask, processMCDetectorLevelWeightedCharged, "charged jets in weighted detector level MC", false); + + void processMCParticleLevelCharged(soa::Filtered::iterator const& mcCollision, soa::Filtered const& jets) + { + + } + PROCESS_SWITCH(JetTutorialSkeletonTask, processMCParticleLevelCharged, "charged jets in particle level MC", false); + + void processMCCharged(soa::Filtered::iterator const& collision, aod::JetMcCollisions const& , soa::Filtered const& mcdjets, soa::Filtered const& mcpjets) + { + + } + PROCESS_SWITCH(JetTutorialSkeletonTask, processMCCharged, "charged jets in detector and particle level MC", false); + + + using JetMCPTable = soa::Filtered>; + void processMCMatchedCharged(soa::Filtered::iterator const& collision, + soa::Filtered> const& mcdjets, + JetMCPTable const&, + aod::JetTracks const&, + aod::JetParticles const&) + { + + } + PROCESS_SWITCH(JetTutorialSkeletonTask, processMCMatchedCharged, "matched detector and particle level charged jets", false); + + void processDataSubstructureCharged(soa::Filtered::iterator const& collision, soa::Filtered>const& jets, aod::JetTracks const&) + { + + } + PROCESS_SWITCH(JetTutorialSkeletonTask, processDataSubstructureCharged, "charged jet substructure", false); + + void processDataFull(soa::Filtered::iterator const& , soa::Filtered const& jets) + { + + } + PROCESS_SWITCH(JetTutorialSkeletonTask, processDataFull, "full jets in data", false); + + void processDataSubstructureFull(soa::Filtered::iterator const& , soa::Filtered> const& jets, aod::JetTracks const&, aod::JetClusters const&) + { + + } + PROCESS_SWITCH(JetTutorialSkeletonTask, processDataSubstructureFull, "full jet substructure", false); + + + void processMCParticleLevelSubstructureFull(soa::Filtered::iterator const& mcCollision, soa::Filtered> const& jets, aod::JetParticles const&) + { + + } + PROCESS_SWITCH(JetTutorialSkeletonTask, processMCParticleLevelSubstructureFull, "full particle level jet substructure", false); + + + void processRecoilDataCharged(soa::Filtered::iterator const& collision, soa::Filtered const& jets, aod::JetTracks const& tracks) + { + + } + PROCESS_SWITCH(JetTutorialSkeletonTask, processRecoilDataCharged, "hadron-recoil charged jets", false); + + void processDataRhoAreaSubtractedCharged(soa::Filtered>::iterator const& collision, soa::Filtered const& jets) + { + + } + PROCESS_SWITCH(JetTutorialSkeletonTask, processDataRhoAreaSubtractedCharged, "charged rho-area subtracted jets", false); + + void processDataConstituentSubtractedCharged(soa::Filtered::iterator const& collision, soa::Filtered const& jets) + { + + } + PROCESS_SWITCH(JetTutorialSkeletonTask, processDataConstituentSubtractedCharged, "charged constituent subtracted jets", false); + + + void processDataConstituentSubtractedSubstructureCharged(soa::Filtered::iterator const& collision, soa::Filtered>const& jets, aod::JetTracksSub const&) + { + + } + PROCESS_SWITCH(JetTutorialSkeletonTask, processDataConstituentSubtractedSubstructureCharged, "charged constituent subtracted jet substructure", false); + + void processDataTriggered(soa::Filtered::iterator const& collision, soa::Filtered const& jets) + { + + } + PROCESS_SWITCH(JetTutorialSkeletonTask, processDataTriggered, "jets triggered", false); + */ }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"jet-tutorial-skeleton"})}; } diff --git a/PWGJE/Tasks/jetvalidationqa.cxx b/PWGJE/Tasks/jetValidationQA.cxx similarity index 95% rename from PWGJE/Tasks/jetvalidationqa.cxx rename to PWGJE/Tasks/jetValidationQA.cxx index 1ef731bad09..9facbcaf6e9 100644 --- a/PWGJE/Tasks/jetvalidationqa.cxx +++ b/PWGJE/Tasks/jetValidationQA.cxx @@ -169,13 +169,13 @@ struct jetTrackCollisionQa { Filter etafilter = (aod::jtrack::eta <= etaup) && (aod::jtrack::eta >= etalow); Filter ptfilter = (aod::jtrack::pt <= ptUp) && (aod::jtrack::pt >= ptLow); using Tracks = soa::Join; - using TracksJE = soa::Filtered>; + using TracksJE = soa::Filtered>; - void processESD(JetCollision const& collision, soa::Join const& jets, TracksJE const& tracks, Tracks const&) + void processESD(aod::JetCollision const& collision, soa::Join const& jets, TracksJE const& tracks, Tracks const&) { mHistManager.fill(HIST("controlCollisionVtxZ"), collision.posZ()); if (evSel == true) { - if (!jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::JCollisionSel::sel7) || fabs(collision.posZ()) > 10) { + if (!jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("sel7")) || fabs(collision.posZ()) > 10) { return; } } else { @@ -239,10 +239,10 @@ struct jetTrackCollisionQa { PROCESS_SWITCH(jetTrackCollisionQa, processESD, "validate jet-finder output on run2 ESD", true); // process for run3 AOD's - void processRun3AOD(JetCollision const& collision, soa::Join const& jets, TracksJE const& tracks, Tracks const&) + void processRun3AOD(aod::JetCollision const& collision, soa::Join const& jets, TracksJE const& tracks, Tracks const&) { if (evSel == true) { - if (!jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::JCollisionSel::sel8) || fabs(collision.posZ()) > 10) { + if (!jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("sel8")) || fabs(collision.posZ()) > 10) { return; } } else { @@ -304,7 +304,7 @@ struct jetTrackCollisionQa { PROCESS_SWITCH(jetTrackCollisionQa, processRun3AOD, "validate jet-finder output on run3 AOD", false); // dummy process to run jetfinder validation code on ESD, but MC validation for run3 on hyperloop - void processDummy(JetCollisions const&) + void processDummy(aod::JetCollisions const&) { } PROCESS_SWITCH(jetTrackCollisionQa, processDummy, "Dummy process function turned on by default", false); @@ -437,7 +437,7 @@ struct mcJetTrackCollisionQa { mHistManager.fill(HIST("selectedTrackEta"), track.eta()); } } // end of tracks loop - } // end of mcTrack template + } // end of mcTrack template template void fillMcDetJets(detectorJet const& mcdJet) @@ -473,12 +473,12 @@ struct mcJetTrackCollisionQa { Filter etafilter = (aod::jtrack::eta < etaup) && (aod::jtrack::eta > etalow); Filter ptfilter = (aod::jtrack::pt < ptUp) && (aod::jtrack::pt > ptLow); - using MCTracksJE = soa::Filtered; + using MCTracksJE = soa::Filtered; - void processMcRun2(JetCollisionsMCD::iterator const& collision, + void processMcRun2(aod::JetCollisionsMCD::iterator const& collision, soa::Join const& mcPartJets, soa::Join const& mcDetJets, - JetParticles const&, JetMcCollisions const&, + aod::JetParticles const&, aod::JetMcCollisions const&, MCTracksJE const& tracks) { if (fabs(collision.posZ()) > 10) { @@ -491,12 +491,12 @@ struct mcJetTrackCollisionQa { for (const auto& genJet : mcPartJets) { if (genJet.mcCollisionId() == collision.globalIndex()) { fillMcPartJets(genJet); - for (auto& mcParticle : genJet.tracks_as()) { + for (auto& mcParticle : genJet.tracks_as()) { fillMcPartJetConstituents(mcParticle); } } } // end of loop particle level jets - } // end if has mc collision + } // end if has mc collision fillMcTrackHistos(tracks, collision, false); for (const auto& detJet : mcDetJets) { if (detJet.collisionId() == collision.globalIndex()) { @@ -506,13 +506,13 @@ struct mcJetTrackCollisionQa { } } } // end of loop detector level jets - } // end processMcRun2 + } // end processMcRun2 PROCESS_SWITCH(mcJetTrackCollisionQa, processMcRun2, "validate jet-finder output on converted run2 mc AOD's", false); - void processMcRun3(JetCollisionsMCD::iterator const& collision, + void processMcRun3(aod::JetCollisionsMCD::iterator const& collision, soa::Join const& mcPartJets, soa::Join const& mcDetJets, - JetParticles const&, JetMcCollisions const&, + aod::JetParticles const&, aod::JetMcCollisions const&, MCTracksJE const& tracks) { if (fabs(collision.posZ()) > 10) { @@ -525,12 +525,12 @@ struct mcJetTrackCollisionQa { for (const auto& genJet : mcPartJets) { if (genJet.mcCollisionId() == collision.globalIndex()) { fillMcPartJets(genJet); - for (auto& mcParticle : genJet.tracks_as()) { + for (auto& mcParticle : genJet.tracks_as()) { fillMcPartJetConstituents(mcParticle); } } } // end of loop particle level jets - } // end of loop if mc collision + } // end of loop if mc collision fillMcTrackHistos(tracks, collision, false); for (const auto& detJet : mcDetJets) { if (detJet.collisionId() == collision.globalIndex()) { @@ -540,11 +540,11 @@ struct mcJetTrackCollisionQa { } } } // end of loop detector level jets - } // end processMcRun3 + } // end processMcRun3 PROCESS_SWITCH(mcJetTrackCollisionQa, processMcRun3, "validate jet-finder output on run3 mc AOD's", false); // dummy process to run jetfinder validation code on AO2D's, but MC validation for run3 on hyperloop - void processDummy(JetMcCollisions const&) + void processDummy(aod::JetMcCollisions const&) { } PROCESS_SWITCH(mcJetTrackCollisionQa, processDummy, "Dummy process function turned off by default", true); diff --git a/PWGJE/Tasks/jetfragmentation.cxx b/PWGJE/Tasks/jetfragmentation.cxx deleted file mode 100644 index 4316acb8851..00000000000 --- a/PWGJE/Tasks/jetfragmentation.cxx +++ /dev/null @@ -1,1849 +0,0 @@ -// 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. - -// jet trigger QA task -// -/// \author Gijs van Weelden -// - -#include "TH1F.h" -#include "TTree.h" - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/RunningWorkflowInfo.h" - -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" - -#include "CommonConstants/PhysicsConstants.h" - -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/Core/JetUtilities.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -using McDJets = soa::Join; -using MatchedMcDJets = soa::Join; -using McPJets = soa::Join; -using MatchedMcPJets = soa::Join; -using MyTracks = soa::Join; -using ChargedJetsWithConstituents = soa::Join; - -struct JetFragmentation { - HistogramRegistry registry{"registry"}; - - Configurable evSel{"evSel", "sel8", "choose event selection"}; - Configurable vertexZCut{"vertexZCut", 10.f, "vertex z cut"}; - - Configurable matchedDetJetEtaMin{"matchedDetJetEtaMin", -0.5, "minimum matchedDetJet eta"}; - Configurable matchedDetJetEtaMax{"matchedDetJetEtaMax", 0.5, "maximum matchedDetJet eta"}; - Configurable dataJetEtaMin{"dataJetEtaMin", -0.5, "minimum data jet eta"}; - Configurable dataJetEtaMax{"dataJetEtaMax", 0.5, "maximum data jet eta"}; - Configurable v0EtaMin{"v0EtaMin", -0.75, "minimum data V0 eta"}; - Configurable v0EtaMax{"v0EtaMax", 0.75, "maximum data V0 eta"}; - - Configurable v0cospaMin{"v0cospaMin", 0.995, "V0 CosPA"}; - Configurable dcav0dauMax{"dcav0dauMax", 1.0, "DCA V0 Daughters"}; - Configurable dcaprMin{"dcaprMin", 0.1, "DCA proton To PV"}; - Configurable dcapiMin{"dcapiMin", 0.1, "DCA pion To PV"}; - Configurable v0radiusMin{"v0radiusMin", 1.2, "V0 Radius"}; - Configurable lifetimeK0SMax{"lifetimeK0SMax", 20., "lifetimeK0SMax"}; - Configurable lifetimeLambdaMax{"lifetimeLambdaMax", 25., "lifetimeLambdaMax"}; - - Configurable k0sMassAccWindow{"k0sMassAccWindow", 0.03, "k0sMassAccWindow"}; - Configurable lambdaMassAccWindow{"lambdaMassAccWindow", 0.01, "lambdaMassAccWindow"}; - Configurable antilambdaMassAccWindow{"antilambdaMassAccWindow", 0.01, "antilambdaMassAccWindow"}; - - // Binning - ConfigurableAxis binJetPt{"binJetPt", {40, 0.f, 200.f}, ""}; - ConfigurableAxis binEta{"binEta", {20, -1.f, 1.f}, ""}; - ConfigurableAxis binPhi{"binPhi", {18 * 8, 0.f, 2. * TMath::Pi()}, ""}; - ConfigurableAxis binZ{"binZ", {40, 0.0001f, 1.0001f}, ""}; - ConfigurableAxis binXi{"binXi", {50, 0.f, 10.f}, ""}; - ConfigurableAxis binTheta{"binTheta", {40, -0.05f, 0.395f}, ""}; - ConfigurableAxis binJetR{"binJetR", {6, 0.05f, 0.65f}, ""}; - ConfigurableAxis binTrackPt{"binTrackPt", {200, 0.f, 100.f}, ""}; - ConfigurableAxis binVtxZ{"binVtxZ", {200, -20, 20}, ""}; - - ConfigurableAxis binPtTrackDiff{"binPtTrackDiff", {121, -20.5f, 100.5f}, ""}; - ConfigurableAxis binPtDiff{"binPtDiff", {600, -299.5f, 300.5f}, ""}; - ConfigurableAxis binEtaDiff{"binEtaDiff", {40, -0.195f, 0.205f}, ""}; - ConfigurableAxis binPhiDiff{"binPhiDiff", {40, -0.195f, 0.205f}, ""}; - ConfigurableAxis binZDiff{"binZDiff", {80, -1.05f, 0.95f}, ""}; - ConfigurableAxis binXiDiff{"binXiDiff", {100, -9.5f, 10.5f}, ""}; - ConfigurableAxis binThetaDiff{"binThetaDiff", {80, -0.35f, 0.45f}, ""}; - ConfigurableAxis binPtRatio{"binPtRatio", {50, -0.5f, 9.5f}, ""}; // Ratio of pt, eta, phi - ConfigurableAxis binMatchDist{"binMatchDist", {50, 0.f, 0.5f}, ""}; // Distance between matched jets - - ConfigurableAxis binPtRelDiff{"binPtRelDiff", {100, -9.5f, 10.5f}, ""}; - ConfigurableAxis binZRelDiff{"binZRelDiff", {100, -9.5f, 10.5f}, ""}; - - ConfigurableAxis binCount{"binCount", {1, .5f, 1.5f}, ""}; - ConfigurableAxis jetCount{"jetCount", {20, -.5f, 19.5f}, ""}; - ConfigurableAxis trackCount{"trackCount", {1000, -.5f, 999.5f}, ""}; - ConfigurableAxis v0Count{"v0Count", {50, -.5f, 49.5f}, ""}; - - ConfigurableAxis binV0Pt{"binV0Pt", {120, 0.0f, 60.0f}, ""}; - ConfigurableAxis binV0Eta{"binV0Eta", {20, -1.f, 1.f}, ""}; - ConfigurableAxis binV0Phi{"binV0Phi", {18 * 8, 0.f, 2. * TMath::Pi()}, ""}; - ConfigurableAxis binV0Ctau{"binV0Ctau", {200, 0.0f, 40.0f}, ""}; - ConfigurableAxis binV0Radius{"binV0Radius", {100, 0.0f, 100.0f}, ""}; - ConfigurableAxis binV0CosPA{"binV0CosPA", {100, 0.95f, 1.0f}, ""}; - ConfigurableAxis binV0DCA{"binV0DCA", {200, 0.0f, 1.0f}, ""}; - ConfigurableAxis binV0DCAp{"binV0DCAp", {100, -10.0f, 10.0f}, ""}; - ConfigurableAxis binV0DCAn{"binV0DCAn", {100, -10.0f, 10.0f}, ""}; - ConfigurableAxis binV0DCAd{"binV0DCAd", {100, 0.0f, 10.0f}, ""}; - - ConfigurableAxis binK0SMass{"binK0SMass", {400, 0.400f, 0.600f}, "Inv. Mass (GeV/c^{2})"}; - ConfigurableAxis binLambdaMass{"binLambdaMass", {200, 1.015f, 1.215f}, "Inv. Mass (GeV/c^{2})"}; - ConfigurableAxis binLambdaMassDiff{"binLambdaMassDiff", {200, -0.199f, 0.201f}, "M(#Lambda) - M(#bar{#Lambda})"}; - ConfigurableAxis binLambdaMassRatio{"binLambdaMassRatio", {50, -0.05f, 4.95f}, "M(#bar{#Lambda}) / M(#Lambda)"}; - ConfigurableAxis binLambdaMassRelDiff{"binLambdaMassRelDiff", {200, -0.995f, 1.005f}, "(M(#Lambda) - M(#bar{#Lambda})) / M(#Lambda)"}; - - // Binning for cut variation study - ConfigurableAxis binV0RadiusCut{"binV0RadiusCut", {4, 1.0f, 1.4f}, "R"}; - ConfigurableAxis binV0CtauCut{"binV0CtauCut", {3, 15.0f, 30.0f}, "c#tau"}; - ConfigurableAxis binV0CosPACut{"binV0CosPACut", {4, 0.991f, 0.999f}, "cosPA"}; - ConfigurableAxis binV0DCApCut{"binV0DCApCut", {2, 0.05f, 0.15f}, "DCA pos"}; - ConfigurableAxis binV0DCAnCut{"binV0DCAnCut", {2, 0.05f, 0.15f}, "DCA neg"}; - ConfigurableAxis binV0DCAdCut{"binV0DCAdCut", {2, 0.5f, 1.5f}, "DCA daughters"}; - ConfigurableAxis binV0PtCut{"binV0PtCut", {60, 0.0f, 60.0f}, "p_{T, V0}"}; - ConfigurableAxis binK0SMassCut{"binK0SMassCut", {100, 0.4f, 0.6f}, "inv. mass, K0S hypothesis"}; - ConfigurableAxis binLambda0MassCut{"binLambda0MassCut", {100, 1.07f, 1.21f}, "inv. mass, Lambda0 hypothesis"}; - ConfigurableAxis binAntiLambda0MassCut{"binAntiLambda0MassCut", {100, 1.07f, 1.21f}, "inv. mass, AntiLambda0 hypothesis"}; - - Filter jetCollisionFilter = nabs(aod::jcollision::posZ) < vertexZCut; - Filter collisionFilter = nabs(aod::collision::posZ) < vertexZCut; - - Partition detJetEtaPartition = (aod::jet::eta > matchedDetJetEtaMin) && (aod::jet::eta < matchedDetJetEtaMax); - Partition detJetEtaV0Partition = (aod::jet::eta > v0EtaMin + aod::jet::r * 0.01f) && (aod::jet::eta < v0EtaMax - aod::jet::r * 0.01f); - - Preslice TracksPerCollision = aod::track::collisionId; - Preslice V0sPerCollision = aod::v0data::collisionId; - Preslice> McV0sPerCollision = aod::v0data::collisionId; - Preslice PartJetsPerCollision = aod::jet::mcCollisionId; - Preslice JetParticlesPerCollision = aod::jmcparticle::mcCollisionId; - Preslice ParticlesPerCollision = aod::mcparticle::mcCollisionId; - - int eventSelection = -1; - - void init(InitContext&) - { - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(evSel)); - - // Axes - AxisSpec jetPtAxis = {binJetPt, "#it{p}_{T}^{ jet}"}; // Data - AxisSpec etaAxis = {binEta, "#eta"}; - AxisSpec phiAxis = {binPhi, "#phi"}; - AxisSpec zAxis = {binZ, "#it{z}"}; - AxisSpec xiAxis = {binXi, "#xi"}; - AxisSpec thetaAxis = {binTheta, "#theta"}; - - AxisSpec detJetPtAxis = {binJetPt, "#it{p}_{T}^{ jet, det}"}; // MC detector level - AxisSpec detEtaAxis = {binEta, "#eta^{ jet, det}"}; - AxisSpec detPhiAxis = {binPhi, "#phi^{ jet, det}"}; - AxisSpec detZAxis = {binZ, "#it{z}^{ det}"}; - AxisSpec detXiAxis = {binXi, "#xi^{ det}"}; - AxisSpec detThetaAxis = {binTheta, "#theta^{ det}"}; - - AxisSpec partJetPtAxis = {binJetPt, "#it{p}_{T}^{ jet, part}"}; // MC particle level - AxisSpec partEtaAxis = {binEta, "#eta^{ jet, part}"}; - AxisSpec partPhiAxis = {binPhi, "#phi^{ jet, part}"}; - AxisSpec partZAxis = {binZ, "#it{z}^{ part}"}; - AxisSpec partXiAxis = {binXi, "#xi^{ part}"}; - AxisSpec partThetaAxis = {binTheta, "#theta^{ part}"}; - - AxisSpec trackPtAxis = {binTrackPt, "#it{p}_{T}^{tr}"}; - AxisSpec ptTrackDiffAxis = {binPtTrackDiff, "#it{p}_{T}^{track} - #it{p}_{T}^{particle}"}; - AxisSpec ptDiffAxis = {binPtDiff, "#it{p}_{T}^{jet, det} - #it{p}_{T}^{jet, part}"}; - AxisSpec etaDiffAxis = {binEtaDiff, "#eta^{jet, det} - #eta^{jet, part}"}; - AxisSpec phiDiffAxis = {binPhiDiff, "#varphi^{jet, det} - #varphi^{jet, part}"}; - AxisSpec zDiffAxis = {binZDiff, "#it{z}^{det} - #it{z}^{part}"}; - AxisSpec xiDiffAxis = {binXiDiff, "#xi^{det} - #xi^{part}"}; - AxisSpec thetaDiffAxis = {binThetaDiff, "#theta^{det} - #theta^{part}"}; - AxisSpec ptRatioAxis = {binPtRatio, ""}; - AxisSpec vtxZAxis = {binVtxZ, "Collision vertex z (cm)"}; - AxisSpec matchDistAxis = {binMatchDist, "#Delta"}; - - AxisSpec ptJetRelDiffAxis = {binPtRelDiff, "(#it{p}_{T}^{jet, det} - #it{p}_{T}^{jet, part})/#it{p}_{T, jet}^{part}"}; - AxisSpec ptTrackRelDiffAxis = {binPtRelDiff, "(#it{p}_{T}^{track, det} - #it{p}_{T}^{track, part})/#it{p}_{T, track}^{part}"}; - AxisSpec zRelDiffAxis = {binZRelDiff, "(#it{p}_{T}^{jet, det} - #it{p}_{T}^{jet, part})/#it{p}_{T, jet}^{part}"}; - - AxisSpec V0PtAxis = {binV0Pt, "#it{p}_{T}^{V0}"}; - AxisSpec V0PtRatioAxis = {binPtRatio, "#it{p}_{T}^{V0, det}/#it{p}_{T, V0}^{part}"}; - AxisSpec V0PtRelDiffAxis = {binPtRelDiff, "(#it{p}_{T}^{V0, det} - #it{p}_{T}^{V0, part})/#it{p}_{T, V0}^{part}"}; - AxisSpec V0EtaAxis = {binV0Eta, "#eta^{V0}"}; - AxisSpec V0PhiAxis = {binV0Phi, "#varphi^{V0}"}; - AxisSpec V0detPtAxis = {binV0Pt, "#it{p}_{T}^{V0, det}"}; - AxisSpec V0partPtAxis = {binV0Pt, "#it{p}_{T}^{V0, part}"}; - AxisSpec V0CtauAxis = {binV0Ctau, "c#tau (cm)"}; - AxisSpec V0RadiusAxis = {binV0Radius, "R (cm)"}; - AxisSpec V0CosPAAxis = {binV0CosPA, "cos(PA)"}; - AxisSpec V0DCApAxis = {binV0DCAp, "DCA pos (cm)"}; - AxisSpec V0DCAnAxis = {binV0DCAn, "DCA neg (cm)"}; - AxisSpec V0DCAdAxis = {binV0DCAd, "DCA daughters (cm^{2})"}; - - AxisSpec K0SMassAxis = {binK0SMass, "Inv. mass (GeV/#it{c}^{2})"}; - AxisSpec LambdaMassAxis = {binLambdaMass, "Inv. mass (GeV/#it{c}^{2})"}; - AxisSpec LambdaMassDiffAxis = {binLambdaMassDiff, "M(#Lambda) - M(#bar{#Lambda})"}; - AxisSpec LambdaMassRatioAxis = {binLambdaMassRatio, "M(#bar{#Lambda}) / M(#Lambda)"}; - AxisSpec LambdaMassRelDiffAxis = {binLambdaMassRelDiff, "(M(#Lambda) - M(#bar{#Lambda})) / M(#Lambda)"}; - - // Cut variation study - AxisSpec RcutAxis = {binV0RadiusCut, "R"}; - AxisSpec ctauCutAxis = {binV0CtauCut, "c#tau (K0S)"}; - AxisSpec cosPACutAxis = {binV0CosPACut, "cosPA"}; - AxisSpec DCApCutAxis = {binV0DCApCut, "DCA pos (cm)"}; - AxisSpec DCAnCutAxis = {binV0DCAnCut, "DCA neg (cm)"}; - AxisSpec DCAdCutAxis = {binV0DCAdCut, "DCA daughters (cm^{2})"}; - AxisSpec PtCutAxis = {binV0PtCut, "p_{T, V0}"}; - AxisSpec K0SMassCutAxis = {binK0SMassCut, "Inv. mass (GeV/#it{c}^{2})"}; - AxisSpec LambdaMassCutAxis = {binLambda0MassCut, "Inv. mass (GeV/#it{c}^{2})"}; - AxisSpec AntiLambdaMassCutAxis = {binAntiLambda0MassCut, "Inv. mass (GeV/#it{c}^{2})"}; - - if (doprocessDataRun3 || doprocessDataV0Frag) { - registry.add("data/nJetsnTracks", "nJetsnTracks; nJets; nTracks", HistType::kTH2D, {jetCount, trackCount}); - registry.add("data/collision/collisionVtxZ", "Collision vertex z (cm)", HistType::kTH1D, {binVtxZ}); - registry.add("data/tracks/trackPtEtaPhi", "trackPtEtaPhi", HistType::kTH3D, {trackPtAxis, etaAxis, phiAxis}); - - registry.add("data/jets/jetPtEtaPhi", "Jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {jetPtAxis, etaAxis, phiAxis}); - registry.add("data/jets/jetPtTrackPt", "Jet #it{p}_{T}, track #it{p}_{T}", HistType::kTH2D, {jetPtAxis, trackPtAxis}); - registry.add("data/jets/jetTrackPtEtaPhi", "Tracks in jets #it{p}_{T}, #eta, #phi", HistType::kTH3D, {trackPtAxis, etaAxis, phiAxis}); - registry.add("data/jets/jetPtFrag", "Jet #it{p}_{T}, #it{p}_{T,jet}/#it{p}_{T,tr}", HistType::kTH2D, {jetPtAxis, zAxis}); - registry.add("data/jets/jetPtTrackProj", "Jet #it{p}_{T}, #it{z}", HistType::kTH2D, {jetPtAxis, zAxis}); - registry.add("data/jets/jetPtXi", "Jet #it{p}_{T}, #xi", HistType::kTH2D, {jetPtAxis, xiAxis}); - registry.add("data/jets/jetPtTheta", "Jet #it{p}_{T}, #theta", HistType::kTH2D, {jetPtAxis, thetaAxis}); - registry.add("data/jets/jetPtXiTheta", "Jet #it{p}_{T}, #xi, #theta", HistType::kTH3D, {jetPtAxis, xiAxis, thetaAxis}); - registry.add("data/jets/jetPtZTheta", "Jet #it{p}_{T}, z, #theta", HistType::kTH3D, {jetPtAxis, zAxis, thetaAxis}); - } // doprocessDataRun3 || doprocessDataV0Frag - - if (doprocessDataV0 || doprocessDataV0Frag) { - registry.add("data/V0/nV0sEvent", "nV0sEvent", HistType::kTH1D, {v0Count}); - - // Unidentified - registry.add("data/V0/V0PtEtaPhi", "V0PtEtaPhi", HistType::kTH3D, {V0PtAxis, V0EtaAxis, V0PhiAxis}); - registry.add("data/V0/V0PtCtau", "V0PtCtau", HistType::kTHnSparseD, {V0PtAxis, V0CtauAxis, V0CtauAxis, V0CtauAxis}); - registry.add("data/V0/V0PtMass", "V0PtMass", HistType::kTHnSparseD, {V0PtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("data/V0/V0PtLambdaMasses", "V0PtLambdaMasses", HistType::kTHnSparseD, {V0PtAxis, LambdaMassDiffAxis, LambdaMassRatioAxis, LambdaMassRelDiffAxis}); - registry.add("data/V0/V0PtRadiusCosPA", "V0PtRadiusCosPA", HistType::kTH3D, {V0PtAxis, V0RadiusAxis, V0CosPAAxis}); - registry.add("data/V0/V0PtDCAposneg", "V0PtDCAposneg", HistType::kTH3D, {V0PtAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("data/V0/V0PtDCAd", "V0PtDCAd", HistType::kTH2D, {V0PtAxis, V0DCAdAxis}); - - // Identified - registry.add("data/V0/K0SPtEtaPhi", "K0SPtEtaPhi", HistType::kTH3D, {V0PtAxis, V0EtaAxis, V0PhiAxis}); - registry.add("data/V0/K0SPtCtauMass", "K0SPtCtauMass", HistType::kTH3D, {V0partPtAxis, V0CtauAxis, K0SMassAxis}); - registry.add("data/V0/K0SPtRadiusCosPA", "K0SPtRadiusCosPA", HistType::kTH3D, {V0partPtAxis, V0RadiusAxis, V0CosPAAxis}); - registry.add("data/V0/K0SPtDCAposneg", "K0SPtDCAposneg", HistType::kTH3D, {V0partPtAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("data/V0/K0SPtDCAd", "K0SPtDCAd", HistType::kTH2D, {V0partPtAxis, V0DCAdAxis}); - - registry.add("data/V0/LambdaPtEtaPhi", "LambdaPtEtaPhi", HistType::kTH3D, {V0PtAxis, V0EtaAxis, V0PhiAxis}); - registry.add("data/V0/LambdaPtCtauMass", "LambdaPtCtauMass", HistType::kTH3D, {V0partPtAxis, V0CtauAxis, LambdaMassAxis}); - registry.add("data/V0/LambdaPtLambdaMasses", "LambdaPtLambdaMasses", HistType::kTHnSparseD, {V0PtAxis, LambdaMassDiffAxis, LambdaMassRatioAxis, LambdaMassRelDiffAxis}); - registry.add("data/V0/LambdaPtRadiusCosPA", "LambdaPtRadiusCosPA", HistType::kTH3D, {V0partPtAxis, V0RadiusAxis, V0CosPAAxis}); - registry.add("data/V0/LambdaPtDCAposneg", "LambdaPtDCAposneg", HistType::kTH3D, {V0partPtAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("data/V0/LambdaPtDCAd", "LambdaPtDCAd", HistType::kTH2D, {V0partPtAxis, V0DCAdAxis}); - - registry.add("data/V0/antiLambdaPtEtaPhi", "antiLambdaPtEtaPhi", HistType::kTH3D, {V0PtAxis, V0EtaAxis, V0PhiAxis}); - registry.add("data/V0/antiLambdaPtCtauMass", "antiLambdaPtCtauMass", HistType::kTH3D, {V0partPtAxis, V0CtauAxis, LambdaMassAxis}); - registry.add("data/V0/antiLambdaPtLambdaMasses", "antiLambdaPtLambdaMasses", HistType::kTHnSparseD, {V0PtAxis, LambdaMassDiffAxis, LambdaMassRatioAxis, LambdaMassRelDiffAxis}); - registry.add("data/V0/antiLambdaPtRadiusCosPA", "antiLambdaPtRadiusCosPA", HistType::kTH3D, {V0partPtAxis, V0RadiusAxis, V0CosPAAxis}); - registry.add("data/V0/antiLambdaPtDCAposneg", "antiLambdaPtDCAposneg", HistType::kTH3D, {V0partPtAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("data/V0/antiLambdaPtDCAd", "antiLambdaPtDCAd", HistType::kTH2D, {V0partPtAxis, V0DCAdAxis}); - - registry.add("data/V0/V0CutVariation", "V0CutVariation", HistType::kTHnSparseD, {PtCutAxis, K0SMassCutAxis, LambdaMassCutAxis, AntiLambdaMassCutAxis, RcutAxis, ctauCutAxis, cosPACutAxis, DCApCutAxis, DCAnCutAxis, DCAdCutAxis}); - } // doprocessDataV0 || doprocessDataV0Frag - - if (doprocessDataV0Frag) { - registry.add("data/jets/V0/jetCorrectedPtEtaPhi", "Jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {jetPtAxis, etaAxis, phiAxis}); - registry.add("data/jets/V0/jetPtnV0", "jetPtnV0", HistType::kTH2D, {jetPtAxis, v0Count}); - registry.add("data/jets/V0/jetCorrectedPtV0TrackProj", "jetCorrectedPtV0TrackProj", HistType::kTH2D, {jetPtAxis, zAxis}); - registry.add("data/jets/V0/jetPtV0TrackProj", "jetPtV0TrackProj", HistType::kTH2D, {jetPtAxis, zAxis}); - registry.add("data/jets/V0/jetPtnV0nK0SnLambdanAntiLambda", "jetPtnV0nK0SnLambdanAntiLambda", HistType::kTHnSparseD, {jetPtAxis, v0Count, v0Count, v0Count, v0Count}); - - registry.add("data/jets/V0/jetPtV0PtEtaPhi", "jetPtV0PtEtaPhi", HistType::kTHnSparseD, {jetPtAxis, V0PtAxis, V0EtaAxis, V0PhiAxis}); - registry.add("data/jets/V0/jetPtV0PtCtau", "jetPtV0PtCtau", HistType::kTHnSparseD, {jetPtAxis, V0PtAxis, V0CtauAxis, V0CtauAxis, V0CtauAxis}); - registry.add("data/jets/V0/jetPtV0PtMass", "jetPtV0PtMass", HistType::kTHnSparseD, {jetPtAxis, V0PtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("data/jets/V0/jetPtV0PtLambdaMasses", "jetPtV0PtLambdaMasses", HistType::kTHnSparseD, {jetPtAxis, V0PtAxis, LambdaMassDiffAxis, LambdaMassRatioAxis, LambdaMassRelDiffAxis}); - registry.add("data/jets/V0/jetPtV0PtRadiusCosPA", "jetPtV0PtRadiusCosPA", HistType::kTHnSparseD, {jetPtAxis, V0PtAxis, V0RadiusAxis, V0CosPAAxis}); - registry.add("data/jets/V0/jetPtV0PtDCAposneg", "jetPtV0PtDCAposneg", HistType::kTHnSparseD, {jetPtAxis, V0PtAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("data/jets/V0/jetPtV0PtDCAd", "jetPtV0PtDCAd", HistType::kTH3D, {jetPtAxis, V0PtAxis, V0DCAdAxis}); - - registry.add("data/jets/V0/jetPtV0TrackProjCtau", "jetPtV0TrackProjCtau", HistType::kTHnSparseD, {jetPtAxis, zAxis, V0CtauAxis, V0CtauAxis, V0CtauAxis}); - registry.add("data/jets/V0/jetPtV0TrackProjMass", "jetPtV0TrackProjMass", HistType::kTHnSparseD, {jetPtAxis, zAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("data/jets/V0/jetPtV0TrackProjLambdaMasses", "jetPtV0TrackProjLambdaMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, LambdaMassDiffAxis, LambdaMassRatioAxis, LambdaMassRelDiffAxis}); - registry.add("data/jets/V0/jetPtV0TrackProjRadiusCosPA", "jetPtV0TrackProjRadiusCosPA", HistType::kTHnSparseD, {jetPtAxis, zAxis, V0RadiusAxis, V0CosPAAxis}); - registry.add("data/jets/V0/jetPtV0TrackProjDCAposneg", "jetPtV0TrackProjDCAposneg", HistType::kTHnSparseD, {jetPtAxis, zAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("data/jets/V0/jetPtV0TrackProjDCAd", "jetPtV0TrackProjDCAd", HistType::kTH3D, {jetPtAxis, zAxis, V0DCAdAxis}); - - // Identified - registry.add("data/jets/V0/jetPtnLambda", "jetPtnLambda", HistType::kTH2D, {jetPtAxis, trackCount}); - registry.add("data/jets/V0/jetPtLambdaPtCtau", "Jet #it{p}_{T}, #it{p}_{T, #Lambda^{0}}, c#tau", HistType::kTH3D, {jetPtAxis, V0PtAxis, V0CtauAxis}); - registry.add("data/jets/V0/jetPtLambdaPtMass", "Jet #it{p}_{T}, #it{p}_{T, #Lambda^{0}}, mass", HistType::kTH3D, {jetPtAxis, V0PtAxis, LambdaMassAxis}); - registry.add("data/jets/V0/jetPtLambdaPtAllMasses", "jetPtLambdaPtAllMasses", HistType::kTHnSparseD, {jetPtAxis, V0PtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("data/jets/V0/jetPtLambdaPtLambdaMasses", "jetPtLambdaPtLambdaMasses", HistType::kTHnSparseD, {jetPtAxis, V0PtAxis, LambdaMassDiffAxis, LambdaMassRatioAxis, LambdaMassRelDiffAxis}); - registry.add("data/jets/V0/jetPtLambdaPtRadius", "Jet #it{p}_{T}, #it{p}_{T, #Lambda^{0}}, radius", HistType::kTH3D, {jetPtAxis, V0PtAxis, V0RadiusAxis}); - registry.add("data/jets/V0/jetPtLambdaPtCosPA", "Jet #it{p}_{T}, #it{p}_{T, #Lambda^{0}}, cosPA", HistType::kTH3D, {jetPtAxis, V0PtAxis, V0CosPAAxis}); - registry.add("data/jets/V0/jetPtLambdaPtDCAd", "Jet #it{p}_{T}, #it{p}_{T, #Lambda^{0}}, DCA daughters", HistType::kTH3D, {jetPtAxis, V0PtAxis, V0DCAdAxis}); - registry.add("data/jets/V0/jetPtLambdaPtDCAposneg", "Jet #it{p}_{T}, #it{p}_{T, #Lambda^{0}}, DCA#pm", HistType::kTHnSparseD, {jetPtAxis, V0PtAxis, V0DCApAxis, V0DCAnAxis}); - - registry.add("data/jets/V0/jetPtLambdaTrackProjCtau", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, c#tau", HistType::kTH3D, {jetPtAxis, zAxis, V0CtauAxis}); - registry.add("data/jets/V0/jetPtLambdaTrackProjMass", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, mass", HistType::kTH3D, {jetPtAxis, zAxis, LambdaMassAxis}); - registry.add("data/jets/V0/jetPtLambdaTrackProjAllMasses", "jetPtLambdaTrackProjAllMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("data/jets/V0/jetPtLambdaTrackProjLambdaMasses", "jetPtLambdaTrackProjLambdaMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, LambdaMassDiffAxis, LambdaMassRatioAxis, LambdaMassRelDiffAxis}); - registry.add("data/jets/V0/jetPtLambdaTrackProjRadius", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, radius", HistType::kTH3D, {jetPtAxis, zAxis, V0RadiusAxis}); - registry.add("data/jets/V0/jetPtLambdaTrackProjCosPA", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, cosPA", HistType::kTH3D, {jetPtAxis, zAxis, V0CosPAAxis}); - registry.add("data/jets/V0/jetPtLambdaTrackProjDCAd", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, DCA daughters", HistType::kTH3D, {jetPtAxis, zAxis, V0DCAdAxis}); - registry.add("data/jets/V0/jetPtLambdaTrackProjDCAposneg", "Jet #it{p}_{T}, #it{z}_{#Lambda^{0}}, DCA#pm", HistType::kTHnSparseD, {jetPtAxis, zAxis, V0DCApAxis, V0DCAnAxis}); - - registry.add("data/jets/V0/jetPtnAntiLambda", "jetPtnAntiLambda", HistType::kTH2D, {jetPtAxis, trackCount}); - registry.add("data/jets/V0/jetPtAntiLambdaPtCtau", "Jet #it{p}_{T}, #it{p}_{T, #bar{#Lambda}^{0}}, c#tau", HistType::kTH3D, {jetPtAxis, V0PtAxis, V0CtauAxis}); - registry.add("data/jets/V0/jetPtAntiLambdaPtMass", "Jet #it{p}_{T}, #it{p}_{T, #bar{#Lambda}^{0}}, mass", HistType::kTH3D, {jetPtAxis, V0PtAxis, LambdaMassAxis}); - registry.add("data/jets/V0/jetPtAntiLambdaPtAllMasses", "jetPtAntiLambdaPtAllMasses", HistType::kTHnSparseD, {jetPtAxis, V0PtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("data/jets/V0/jetPtAntiLambdaPtLambdaMasses", "jetPtAntiLambdaPtLambdaMasses", HistType::kTHnSparseD, {jetPtAxis, V0PtAxis, LambdaMassDiffAxis, LambdaMassRatioAxis, LambdaMassRelDiffAxis}); - registry.add("data/jets/V0/jetPtAntiLambdaPtRadius", "Jet #it{p}_{T}, #it{p}_{T, #bar{#Lambda}^{0}}, radius", HistType::kTH3D, {jetPtAxis, V0PtAxis, V0RadiusAxis}); - registry.add("data/jets/V0/jetPtAntiLambdaPtCosPA", "Jet #it{p}_{T}, #it{p}_{T, #bar{#Lambda}^{0}}, cosPA", HistType::kTH3D, {jetPtAxis, V0PtAxis, V0CosPAAxis}); - registry.add("data/jets/V0/jetPtAntiLambdaPtDCAd", "Jet #it{p}_{T}, #it{p}_{T, #bar{#Lambda}^{0}}, DCA daughters", HistType::kTH3D, {jetPtAxis, V0PtAxis, V0DCAdAxis}); - registry.add("data/jets/V0/jetPtAntiLambdaPtDCAposneg", "Jet #it{p}_{T}, #it{p}_{T, #bar{#Lambda}^{0}}, DCA#pm", HistType::kTHnSparseD, {jetPtAxis, V0PtAxis, V0DCApAxis, V0DCAnAxis}); - - registry.add("data/jets/V0/jetPtAntiLambdaTrackProjCtau", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, c#tau", HistType::kTH3D, {jetPtAxis, zAxis, V0CtauAxis}); - registry.add("data/jets/V0/jetPtAntiLambdaTrackProjMass", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, mass", HistType::kTH3D, {jetPtAxis, zAxis, LambdaMassAxis}); - registry.add("data/jets/V0/jetPtAntiLambdaTrackProjAllMasses", "jetPtAntiLambdaTrackProjAllMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("data/jets/V0/jetPtAntiLambdaTrackProjLambdaMasses", "jetPtAntiLambdaTrackProjLambdaMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, LambdaMassDiffAxis, LambdaMassRatioAxis, LambdaMassRelDiffAxis}); - registry.add("data/jets/V0/jetPtAntiLambdaTrackProjRadius", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, radius", HistType::kTH3D, {jetPtAxis, zAxis, V0RadiusAxis}); - registry.add("data/jets/V0/jetPtAntiLambdaTrackProjCosPA", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, cosPA", HistType::kTH3D, {jetPtAxis, zAxis, V0CosPAAxis}); - registry.add("data/jets/V0/jetPtAntiLambdaTrackProjDCAd", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, DCA daughters", HistType::kTH3D, {jetPtAxis, zAxis, V0DCAdAxis}); - registry.add("data/jets/V0/jetPtAntiLambdaTrackProjDCAposneg", "Jet #it{p}_{T}, #it{z}_{#bar{#Lambda}^{0}}, DCA#pm", HistType::kTHnSparseD, {jetPtAxis, zAxis, V0DCApAxis, V0DCAnAxis}); - - registry.add("data/jets/V0/jetPtnK0S", "jetPtnK0S", HistType::kTH2D, {jetPtAxis, trackCount}); - registry.add("data/jets/V0/jetPtK0SPtCtau", "Jet #it{p}_{T}, #it{p}_{T, K^{0}_{S}}, c#tau", HistType::kTH3D, {jetPtAxis, V0PtAxis, V0CtauAxis}); - registry.add("data/jets/V0/jetPtK0SPtMass", "Jet #it{p}_{T}, #it{p}_{T, K^{0}_{S}}, mass", HistType::kTH3D, {jetPtAxis, V0PtAxis, K0SMassAxis}); - registry.add("data/jets/V0/jetPtK0SPtAllMasses", "jetPtK0SPtAllMasses", HistType::kTHnSparseD, {jetPtAxis, V0PtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("data/jets/V0/jetPtK0SPtRadius", "Jet #it{p}_{T}, #it{p}_{T, K^{0}_{S}}, radius", HistType::kTH3D, {jetPtAxis, V0PtAxis, V0RadiusAxis}); - registry.add("data/jets/V0/jetPtK0SPtCosPA", "Jet #it{p}_{T}, #it{p}_{T, K^{0}_{S}}, cosPA", HistType::kTH3D, {jetPtAxis, V0PtAxis, V0CosPAAxis}); - registry.add("data/jets/V0/jetPtK0SPtDCAd", "Jet #it{p}_{T}, #it{p}_{T, K^{0}_{S}}, DCA daughters", HistType::kTH3D, {jetPtAxis, V0PtAxis, V0DCAdAxis}); - registry.add("data/jets/V0/jetPtK0SPtDCAposneg", "Jet #it{p}_{T}, #it{p}_{T, K^{0}_{S}}, DCA#pm", HistType::kTHnSparseD, {jetPtAxis, V0PtAxis, V0DCApAxis, V0DCAnAxis}); - - registry.add("data/jets/V0/jetPtK0STrackProjCtau", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, c#tau", HistType::kTH3D, {jetPtAxis, zAxis, V0CtauAxis}); - registry.add("data/jets/V0/jetPtK0STrackProjMass", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, mass", HistType::kTH3D, {jetPtAxis, zAxis, K0SMassAxis}); - registry.add("data/jets/V0/jetPtK0STrackProjAllMasses", "jetPtK0STrackProjAllMasses", HistType::kTHnSparseD, {jetPtAxis, zAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("data/jets/V0/jetPtK0STrackProjRadius", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, radius", HistType::kTH3D, {jetPtAxis, zAxis, V0RadiusAxis}); - registry.add("data/jets/V0/jetPtK0STrackProjCosPA", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, cosPA", HistType::kTH3D, {jetPtAxis, zAxis, V0CosPAAxis}); - registry.add("data/jets/V0/jetPtK0STrackProjDCAd", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, DCA daughters", HistType::kTH3D, {jetPtAxis, zAxis, V0DCAdAxis}); - registry.add("data/jets/V0/jetPtK0STrackProjDCAposneg", "Jet #it{p}_{T}, #it{z}_{K^{0}_{S}}, DCA#pm", HistType::kTHnSparseD, {jetPtAxis, zAxis, V0DCApAxis, V0DCAnAxis}); - } // doprocessDataV0Frag - - if (doprocessMcP) { - registry.add("particle-level/nJetsnTracks", "nJetsnTracks; nJets; nTracks", HistType::kTH2D, {jetCount, trackCount}); - registry.add("particle-level/collision/partCollisionVtxZ", "Collision vertex z (cm)", HistType::kTH1D, {binVtxZ}); - registry.add("particle-level/tracks/partTrackPtEtaPhi", "partTrackPtEtaPhi", HistType::kTH3D, {trackPtAxis, etaAxis, phiAxis}); - registry.add("particle-level/jets/partJetPtEtaPhi", "Particle level jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {partJetPtAxis, partEtaAxis, partPhiAxis}); - registry.add("particle-level/jets/partJetPtTrackPt", "Particle level jet #it{p}_{T}, track #it{p}_{T}", HistType::kTH2D, {partJetPtAxis, trackPtAxis}); - registry.add("particle-level/jets/partJetTrackPtEtaPhi", "Particle level tracks in jets #it{p}_{T}, #eta, #phi", HistType::kTH3D, {trackPtAxis, partEtaAxis, partPhiAxis}); - registry.add("particle-level/jets/partJetPtFrag", "Particle level jet #it{p}_{T}, #it{p}_{T,jet}/#it{p}_{T,tr}", HistType::kTH2D, {partJetPtAxis, partZAxis}); - registry.add("particle-level/jets/partJetPtTrackProj", "Particle level jet #it{p}_{T}, #it{z}", HistType::kTH2D, {partJetPtAxis, partZAxis}); - registry.add("particle-level/jets/partJetPtXi", "Particle level jet #it{p}_{T}, #xi", HistType::kTH2D, {partJetPtAxis, partXiAxis}); - registry.add("particle-level/jets/partJetPtTheta", "Particle level jet #it{p}_{T}, #theta", HistType::kTH2D, {partJetPtAxis, partThetaAxis}); - registry.add("particle-level/jets/partJetPtXiTheta", "Particle level jet #it{p}_{T}, #xi, #theta", HistType::kTH3D, {partJetPtAxis, partXiAxis, partThetaAxis}); - registry.add("particle-level/jets/partJetPtZTheta", "Particle level jet #it{p}_{T}, z, #theta", HistType::kTH3D, {partJetPtAxis, partZAxis, partThetaAxis}); - } // doprocessMcP - - if (doprocessMcD) { - registry.add("detector-level/nJetsnTracks", "nJetsnTracks; nJets; nTracks", HistType::kTH2D, {jetCount, trackCount}); - registry.add("detector-level/collision/detCollisionVtxZ", "Collision vertex z (cm)", HistType::kTH1D, {binVtxZ}); - registry.add("detector-level/tracks/detTrackPtEtaPhi", "detTrackPtEtaPhi", HistType::kTH3D, {trackPtAxis, etaAxis, phiAxis}); - registry.add("detector-level/jets/detJetPtEtaPhi", "Detector level jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {detJetPtAxis, detEtaAxis, detPhiAxis}); - registry.add("detector-level/jets/detJetPtTrackPt", "Detector level jet #it{p}_{T}, track #it{p}_{T}", HistType::kTH2D, {detJetPtAxis, trackPtAxis}); - registry.add("detector-level/jets/detJetTrackPtEtaPhi", "Detector level tracks in jets #it{p}_{T}, #eta, #phi", HistType::kTH3D, {trackPtAxis, detEtaAxis, detPhiAxis}); - registry.add("detector-level/jets/detJetPtFrag", "Detector level jet #it{p}_{T}, #it{p}_{T,jet}/#it{p}_{T,tr}", HistType::kTH2D, {detJetPtAxis, detZAxis}); - registry.add("detector-level/jets/detJetPtTrackProj", "Detector level jet #it{p}_{T}, #it{z}", HistType::kTH2D, {detJetPtAxis, detZAxis}); - registry.add("detector-level/jets/detJetPtXi", "Detector level jet #it{p}_{T}, #xi", HistType::kTH2D, {detJetPtAxis, detXiAxis}); - registry.add("detector-level/jets/detJetPtTheta", "Detector level jet #it{p}_{T}, #theta", HistType::kTH2D, {detJetPtAxis, detThetaAxis}); - registry.add("detector-level/jets/detJetPtXiTheta", "Detector level jet #it{p}_{T}, #xi, #theta", HistType::kTH3D, {detJetPtAxis, detXiAxis, detThetaAxis}); - registry.add("detector-level/jets/detJetPtZTheta", "Detector level jet #it{p}_{T}, z, #theta", HistType::kTH3D, {detJetPtAxis, detZAxis, detThetaAxis}); - } // doprocessMcD - - if (doprocessMcMatched || doprocessMcMatchedV0Frag) { - registry.add("matching/jets/matchDetJetPtEtaPhi", "Matched detector level jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {detJetPtAxis, detEtaAxis, detPhiAxis}); - registry.add("matching/jets/matchPartJetPtEtaPhi", "Matched particle level jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {partJetPtAxis, partEtaAxis, partPhiAxis}); - registry.add("matching/jets/matchDetJetPtPartJetPt", "matchDetJetPtPartJetPt", HistType::kTH2D, {detJetPtAxis, partJetPtAxis}); - registry.add("matching/jets/matchPartJetPtDetJetEtaPartJetEta", "matchPartJetPtDetJetEtaPartJetEta", HistType::kTH3D, {partJetPtAxis, detEtaAxis, partEtaAxis}); - registry.add("matching/jets/matchPartJetPtDetJetPhiPartJetPhi", "matchPartJetPtDetJetPhiPartJetPhi", HistType::kTH3D, {partJetPtAxis, detPhiAxis, partPhiAxis}); - registry.add("matching/jets/matchPartJetPtResolutionPt", "#it{p}_{T}^{jet, det} - #it{p}_{T}^{jet, part}", HistType::kTH2D, {partJetPtAxis, ptDiffAxis}); - registry.add("matching/jets/matchPartJetPtRelDiffPt", "#it{p}_{T}^{jet, det} - #it{p}_{T}^{jet, part}", HistType::kTH2D, {partJetPtAxis, ptJetRelDiffAxis}); - registry.add("matching/jets/matchPartJetPtResolutionEta", "#eta^{jet, det} - #eta^{jet, part}", HistType::kTH3D, {partJetPtAxis, partEtaAxis, etaDiffAxis}); - registry.add("matching/jets/matchPartJetPtResolutionPhi", "#phi^{jet, det} - #phi^{jet, part}", HistType::kTH3D, {partJetPtAxis, partPhiAxis, phiDiffAxis}); - registry.add("matching/jets/matchPartJetPtEtaPhiMatchDist", "matchJetMatchDist", HistType::kTHnSparseD, {partJetPtAxis, partEtaAxis, partPhiAxis, matchDistAxis}); - registry.add("matching/jets/matchPartJetPtEnergyScale", "jetEnergyScale", HistType::kTH2D, {partJetPtAxis, ptRatioAxis}); - } // doprocessMcMatched || doprocessMcMatchedV0Frag - - if (doprocessMcMatched) { - registry.add("matching/collision/matchCollisionVtxZ", "Collision vertex z (cm)", HistType::kTH1D, {binVtxZ}); - registry.add("matching/tracks/matchDetTrackPtEtaPhi", "matchDetTrackPtEtaPhi", HistType::kTH3D, {trackPtAxis, etaAxis, phiAxis}); - registry.add("matching/tracks/matchPartTrackPtEtaPhi", "matchPartTrackPtEtaPhi", HistType::kTH3D, {trackPtAxis, etaAxis, phiAxis}); - registry.add("matching/tracks/matchDetTrackPtPartTrackPt", "matchDetTrackPtPartTrackPt", HistType::kTH2D, {trackPtAxis, trackPtAxis}); - registry.add("matching/tracks/matchDetTrackEtaPartTrackEta", "matchDetTrackEtaPartTrackEta", HistType::kTH2D, {etaAxis, etaAxis}); - registry.add("matching/tracks/matchDetTrackPhiPartTrackPhi", "matchDetTrackPhiPartTrackPhi", HistType::kTH2D, {phiAxis, phiAxis}); - registry.add("matching/tracks/trackResolutionPt", "trackResolutionPt", HistType::kTH2D, {trackPtAxis, ptDiffAxis}); - registry.add("matching/tracks/trackResolutionEta", "trackResolutionEta", HistType::kTH2D, {etaAxis, etaDiffAxis}); - registry.add("matching/tracks/trackResolutionPhi", "trackResolutionPhi", HistType::kTH2D, {phiAxis, phiDiffAxis}); - // Detector level jets with a match - registry.add("matching/jets/matchDetJetPtTrackPt", "Matched detector level jet #it{p}_{T}, track #it{p}_{T}", HistType::kTH2D, {detJetPtAxis, trackPtAxis}); - registry.add("matching/jets/matchDetJetTrackPtEtaPhi", "Matched detector level tracks in jets #it{p}_{T}, #eta, #phi", HistType::kTH3D, {trackPtAxis, detEtaAxis, detPhiAxis}); - registry.add("matching/jets/matchDetJetPtFrag", "Matched detector level jet #it{p}_{T}, #it{p}_{T,jet}/#it{p}_{T,tr}", HistType::kTH2D, {detJetPtAxis, detZAxis}); - registry.add("matching/jets/matchDetJetPtTrackProj", "Matched detector level jet #it{p}_{T}, #it{z}", HistType::kTH2D, {detJetPtAxis, detZAxis}); - registry.add("matching/jets/matchDetJetPtXi", "Matched detector level jet #it{p}_{T}, #xi", HistType::kTH2D, {detJetPtAxis, detXiAxis}); - registry.add("matching/jets/matchDetJetPtTheta", "Matched detector level jet #it{p}_{T}, #theta", HistType::kTH2D, {detJetPtAxis, detThetaAxis}); - registry.add("matching/jets/matchDetJetPtXiTheta", "Matched detector level jet #it{p}_{T}, #xi, #theta", HistType::kTH3D, {detJetPtAxis, detXiAxis, detThetaAxis}); - registry.add("matching/jets/matchDetJetPtZTheta", "Matched detector level jet #it{p}_{T}, z, #theta", HistType::kTH3D, {detJetPtAxis, detZAxis, detThetaAxis}); - // Particle level jets with a match - registry.add("matching/jets/matchPartJetPtTrackPt", "Matched particle level jet #it{p}_{T}, track #it{p}_{T}", HistType::kTH2D, {partJetPtAxis, trackPtAxis}); - registry.add("matching/jets/matchPartJetTrackPtEtaPhi", "Matched particle level tracks in jets #it{p}_{T}, #eta, #phi", HistType::kTH3D, {trackPtAxis, partEtaAxis, partPhiAxis}); - registry.add("matching/jets/matchPartJetPtFrag", "Matched particle level jet #it{p}_{T}, #it{p}_{T,jet}/#it{p}_{T,tr}", HistType::kTH2D, {partJetPtAxis, partZAxis}); - registry.add("matching/jets/matchPartJetPtTrackProj", "Matched particle level jet #it{p}_{T}, #it{z}", HistType::kTH2D, {partJetPtAxis, partZAxis}); - registry.add("matching/jets/matchPartJetPtXi", "Matched particle level jet #it{p}_{T}, #xi", HistType::kTH2D, {partJetPtAxis, partXiAxis}); - registry.add("matching/jets/matchPartJetPtTheta", "Matched particle level jet #it{p}_{T}, #theta", HistType::kTH2D, {partJetPtAxis, partThetaAxis}); - registry.add("matching/jets/matchPartJetPtXiTheta", "Matched particle level jet #it{p}_{T}, #xi, #theta", HistType::kTH3D, {partJetPtAxis, partXiAxis, partThetaAxis}); - registry.add("matching/jets/matchPartJetPtZTheta", "Matched particle level jet #it{p}_{T}, z, #theta", HistType::kTH3D, {partJetPtAxis, partZAxis, partThetaAxis}); - // Combined information of matched jets - registry.add("matching/jets/matchPartJetPtResolutionChargeFrag", "Resolution #it{p}_{T}^{tr} / #it{p}_{T}^{jet}", HistType::kTH3D, {partJetPtAxis, partZAxis, zDiffAxis}); - registry.add("matching/jets/matchPartJetPtResolutionTrackPt", "Resolution #it{p}_{T}^{track}", HistType::kTH3D, {partJetPtAxis, trackPtAxis, ptTrackDiffAxis}); - registry.add("matching/jets/matching/jets/matchPartJetPtRelDiffTrackPt", "Rel. diff #it{p}_{T}^{track}", HistType::kTHnSparseD, {partJetPtAxis, ptRatioAxis, trackPtAxis, ptTrackRelDiffAxis}); - registry.add("matching/jets/matchPartJetPtResolutionTrackProj", "Resolution #it{p}^{proj} / #it{p}^{jet}", HistType::kTH3D, {partJetPtAxis, partZAxis, zDiffAxis}); - registry.add("matching/jets/matchPartJetPtRelDiffTrackProj", "Rel. diff #it{p}^{proj} / #it{p}^{jet}", HistType::kTHnSparseD, {partJetPtAxis, ptRatioAxis, partZAxis, zRelDiffAxis}); - registry.add("matching/jets/matchPartJetPtResolutionXi", "Resolution ln(1/#it{z})", HistType::kTH3D, {partJetPtAxis, partXiAxis, xiDiffAxis}); - registry.add("matching/jets/matchPartJetPtResolutionTheta", "Resolution #theta", HistType::kTH3D, {partJetPtAxis, partThetaAxis, thetaDiffAxis}); - registry.add("matching/jets/matchPartJetPtResolutionXiResolutionTheta", "Resolution #xi, #theta", HistType::kTHnSparseD, {partJetPtAxis, partXiAxis, xiDiffAxis, partThetaAxis, thetaDiffAxis}); - registry.add("matching/jets/matchPartJetPtResolutionZResolutionTheta", "Resolution #it{z}, #theta", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, zDiffAxis, partThetaAxis, thetaDiffAxis}); - // QA histograms for fakes, misses - registry.add("matching/jets/fakeDetJetPtEtaPhi", "Fakes", HistType::kTH3D, {detJetPtAxis, detEtaAxis, detPhiAxis}); - registry.add("matching/jets/missPartJetPtEtaPhi", "Misses", HistType::kTH3D, {partJetPtAxis, partEtaAxis, partPhiAxis}); - // Response matrix, fakes, misses - registry.add("matching/jets/matchDetJetPtTrackProjPartJetPtTrackProj", "Matched", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, partJetPtAxis, partZAxis}); - registry.add("matching/jets/fakeDetJetPtTrackProj", "Fakes", HistType::kTH2D, {detJetPtAxis, detZAxis}); - registry.add("matching/jets/missPartJetPtTrackProj", "Misses", HistType::kTH2D, {partJetPtAxis, partZAxis}); - - registry.add("matching/jets/matchDetJetPtXiPartJetPtXi", "Matched", HistType::kTHnSparseD, {detJetPtAxis, detXiAxis, partJetPtAxis, partXiAxis}); - registry.add("matching/jets/fakeDetJetPtXi", "Fakes", HistType::kTH2D, {detJetPtAxis, detXiAxis}); - registry.add("matching/jets/missPartJetPtXi", "Misses", HistType::kTH2D, {partJetPtAxis, partXiAxis}); - - registry.add("matching/jets/matchDetJetPtFragPartJetPtFrag", "Matched", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, partJetPtAxis, partZAxis}); - registry.add("matching/jets/fakeDetJetPtFrag", "Fakes", HistType::kTH2D, {detJetPtAxis, detZAxis}); - registry.add("matching/jets/missPartJetPtFrag", "Misses", HistType::kTH2D, {partJetPtAxis, partZAxis}); - - registry.add("matching/jets/matchDetJetPtThetaPartJetPtTheta", "Matched", HistType::kTHnSparseD, {detJetPtAxis, detThetaAxis, partJetPtAxis, partThetaAxis}); - registry.add("matching/jets/fakeDetJetPtTheta", "Fakes", HistType::kTH2D, {detJetPtAxis, detThetaAxis}); - registry.add("matching/jets/missPartJetPtTheta", "Misses", HistType::kTH2D, {partJetPtAxis, partThetaAxis}); - - registry.add("matching/jets/matchDetJetPtXiThetaPartJetPtXiTheta", "Matched", HistType::kTHnSparseD, {detJetPtAxis, detXiAxis, detThetaAxis, partJetPtAxis, partXiAxis, partThetaAxis}); - registry.add("matching/jets/fakeDetJetPtXiTheta", "Fakes", HistType::kTH3D, {detJetPtAxis, detXiAxis, detThetaAxis}); - registry.add("matching/jets/missPartJetPtXiTheta", "Misses", HistType::kTH3D, {partJetPtAxis, partXiAxis, partThetaAxis}); - - registry.add("matching/jets/matchDetJetPtZThetaPartJetPtZTheta", "Matched", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, detThetaAxis, partJetPtAxis, partZAxis, partThetaAxis}); - registry.add("matching/jets/fakeDetJetPtZTheta", "Fakes", HistType::kTH3D, {detJetPtAxis, detZAxis, detThetaAxis}); - registry.add("matching/jets/missPartJetPtZTheta", "Misses", HistType::kTH3D, {partJetPtAxis, partZAxis, partThetaAxis}); - } // doprocessMcMatched - - if (doprocessMcMatchedV0 || doprocessMcMatchedV0Frag) { - registry.add("matching/V0/nV0sEvent", "nV0sDet per event", HistType::kTH1D, {v0Count}); - } // doprocessMcMatchedV0 || doprocessMcMatchedV0Frag - - if (doprocessMcMatchedV0) { - registry.add("matching/V0/V0PartPtDetPt", "V0PartPtDetPt", HistType::kTH2D, {V0partPtAxis, V0detPtAxis}); - registry.add("matching/V0/V0PartPtRatioPtRelDiffPt", "V0PartPtRatioRelDiffPt", HistType::kTH3D, {V0partPtAxis, V0PtRatioAxis, V0PtRelDiffAxis}); - - registry.add("matching/V0/K0SPtEtaPhi", "K0SPtEtaPhi", HistType::kTHnSparseD, {V0partPtAxis, V0detPtAxis, V0EtaAxis, V0PhiAxis}); - registry.add("matching/V0/K0SPtCtauMass", "K0SPtCtauMass", HistType::kTHnSparseD, {V0partPtAxis, V0partPtAxis, V0CtauAxis, K0SMassAxis}); - registry.add("matching/V0/K0SPtRadiusCosPA", "K0SPtRadiusCosPA", HistType::kTHnSparseD, {V0partPtAxis, V0partPtAxis, V0RadiusAxis, V0CosPAAxis}); - registry.add("matching/V0/K0SPtDCAposneg", "K0SPtDCAposneg", HistType::kTHnSparseD, {V0partPtAxis, V0partPtAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/V0/K0SPtDCAd", "K0SPtDCAd", HistType::kTH3D, {V0partPtAxis, V0detPtAxis, V0DCAdAxis}); - registry.add("matching/V0/K0SPtMass", "K0SPtMass", HistType::kTHnSparseD, {V0partPtAxis, V0detPtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - - registry.add("matching/V0/LambdaPtEtaPhi", "LambdaPtEtaPhi", HistType::kTHnSparseD, {V0partPtAxis, V0detPtAxis, V0EtaAxis, V0PhiAxis}); - registry.add("matching/V0/LambdaPtCtauMass", "LambdaPtCtauMass", HistType::kTHnSparseD, {V0partPtAxis, V0partPtAxis, V0CtauAxis, LambdaMassAxis}); - registry.add("matching/V0/LambdaPtRadiusCosPA", "LambdaPtRadiusCosPA", HistType::kTHnSparseD, {V0partPtAxis, V0partPtAxis, V0RadiusAxis, V0CosPAAxis}); - registry.add("matching/V0/LambdaPtDCAposneg", "LambdaPtDCAposneg", HistType::kTHnSparseD, {V0partPtAxis, V0partPtAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/V0/LambdaPtDCAd", "LambdaPtDCAd", HistType::kTH3D, {V0partPtAxis, V0detPtAxis, V0DCAdAxis}); - registry.add("matching/V0/LambdaPtMass", "LambdaPtMass", HistType::kTHnSparseD, {V0partPtAxis, V0detPtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - - registry.add("matching/V0/antiLambdaPtEtaPhi", "antiLambdaPtEtaPhi", HistType::kTHnSparseD, {V0partPtAxis, V0detPtAxis, V0EtaAxis, V0PhiAxis}); - registry.add("matching/V0/antiLambdaPtCtauMass", "antiLambdaPtCtauMass", HistType::kTHnSparseD, {V0partPtAxis, V0partPtAxis, V0CtauAxis, LambdaMassAxis}); - registry.add("matching/V0/antiLambdaPtRadiusCosPA", "antiLambdaPtRadiusCosPA", HistType::kTHnSparseD, {V0partPtAxis, V0partPtAxis, V0RadiusAxis, V0CosPAAxis}); - registry.add("matching/V0/antiLambdaPtDCAposneg", "antiLambdaPtDCAposneg", HistType::kTHnSparseD, {V0partPtAxis, V0partPtAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/V0/antiLambdaPtDCAd", "antiLambdaPtDCAd", HistType::kTH3D, {V0partPtAxis, V0detPtAxis, V0DCAdAxis}); - registry.add("matching/V0/antiLambdaPtMass", "antiLambdaPtMass", HistType::kTHnSparseD, {V0partPtAxis, V0detPtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - - // Reflections - registry.add("matching/V0/Lambda0Reflection", "pt, pt, mK, mL, maL, Lambda0Reflection", HistType::kTHnSparseD, {V0partPtAxis, V0detPtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/V0/antiLambda0Reflection", "pt, pt, mK, mL, maL, antiLambda0Reflection", HistType::kTHnSparseD, {V0partPtAxis, V0detPtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis, LambdaMassAxis}); - } // doprocessMcMatchedV0 - - if (doprocessMcMatchedV0Frag) { - registry.add("matching/jets/V0/jetPtnV0Matched", "jet pt, nV0 matched", HistType::kTH2D, {detJetPtAxis, v0Count}); - registry.add("matching/jets/V0/jetPtnV0MatchednK0SnLambdanAntiLambda", "jet Pt, nV0 matched, nK0S nLambdan AntiLambda", HistType::kTHnSparseD, {detJetPtAxis, v0Count, v0Count, v0Count, v0Count}); - registry.add("matching/jets/V0/partJetPtV0PtDetPt", "V0PartPtDetPt", HistType::kTH3D, {partJetPtAxis, V0partPtAxis, V0detPtAxis}); - registry.add("matching/jets/V0/partJetPtDetJetPtPartV0PtRatioPtRelDiffPt", "V0PartPtRatioRelDiffPt", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, V0partPtAxis, V0PtRatioAxis, V0PtRelDiffAxis}); - - // ----------------------------- - // Unidentified V0s - // ----------------------------- - registry.add("matching/jets/V0/matchDetJetPtV0TrackProjPartJetPtV0TrackProj", "Matched", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, partJetPtAxis, partZAxis}); - registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0Pt", "matched jet Pt, V0 Pt", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis}); - // Matched V0: pt - registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtCtauLambda0", "matched jet Pt, V0 Pt, Ctau #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtCtauAntiLambda0", "matched jet Pt, V0 Pt, Ctau #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtCtauK0S", "matched jet Pt, V0 Pt, Ctau #{K}^{0}_{S}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtMassLambda0", "matched jet Pt, V0 Pt, Mass #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtMassAntiLambda0", "matched jet Pt, V0 Pt, Mass #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtMassK0S", "matched jet Pt, V0 Pt, MassK0S", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, K0SMassAxis}); - registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtRadius", "matched jet Pt, V0 Pt, Radius", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0RadiusAxis}); - registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtCosPA", "matched jet Pt, V0 Pt, CosPA", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0CosPAAxis}); - registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtDCAposneg", "matched jet Pt, V0 Pt, DCAposneg", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/jets/V0/partJetPtV0PtDetJetPtV0PtDCAd", "matched jet Pt, V0 Pt, DCAd", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0DCAdAxis}); - // Matched Lambda0: z - registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjCtauLambda0", "matched jet Pt, V0 z, Ctau #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjCtauAntiLambda0", "matched jet Pt, V0 z, Ctau #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjCtauK0S", "matched jet Pt, V0 z, Ctau #{K}^{0}_{S}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjMassLambda0", "matched jet Pt, V0 z, Mass #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjMassAntiLambda0", "matched jet Pt, V0 z, Mass #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjMassK0S", "matched jet Pt, V0 z, MassK0S", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, K0SMassAxis}); - registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjRadius", "matched jet Pt, V0 z, Radius", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0RadiusAxis}); - registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjCosPA", "matched jet Pt, V0 z, CosPA", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0CosPAAxis}); - registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjDCAposneg", "matched jet Pt, V0 z, DCAposneg", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjDCAd", "matched jet Pt, V0 z, DCAd", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0DCAdAxis}); - // Fakes - registry.add("matching/jets/V0/fakeJetPtV0TrackProj", "Fakes", HistType::kTH2D, {detJetPtAxis, detZAxis}); - registry.add("matching/jets/V0/fakeJetPtV0PtEtaPhi", "fake jet Pt, V0 PtEtaPhi", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, V0EtaAxis, V0PhiAxis}); - registry.add("matching/jets/V0/fakeJetPtV0PtCtau", "fake jet Pt, V0 PtCtau", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, V0CtauAxis, V0CtauAxis, V0CtauAxis}); - registry.add("matching/jets/V0/fakeJetPtV0PtMass", "fake jet Pt, V0 PtMass", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/fakeJetPtV0PtLambdaMasses", "fake jet Pt, V0 PtLambdaMasses", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, LambdaMassDiffAxis, LambdaMassRatioAxis, LambdaMassRelDiffAxis}); - registry.add("matching/jets/V0/fakeJetPtV0PtRadiusCosPA", "fake jet Pt, V0 PtRadiusCosPA", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, V0RadiusAxis, V0CosPAAxis}); - registry.add("matching/jets/V0/fakeJetPtV0PtDCAposneg", "fake jet Pt, V0 PtDCAposneg", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/jets/V0/fakeJetPtV0PtDCAd", "fake jet Pt, V0 PtDCAd", HistType::kTH3D, {detJetPtAxis, V0PtAxis, V0DCAdAxis}); - registry.add("matching/jets/V0/fakeJetPtV0TrackProjCtau", "fake jet Pt, V0 zCtau", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, V0CtauAxis, V0CtauAxis, V0CtauAxis}); - registry.add("matching/jets/V0/fakeJetPtV0TrackProjMass", "fake jet Pt, V0 zMass", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/fakeJetPtV0TrackProjLambdaMasses", "fake jet Pt, V0 zLambdaMasses", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, LambdaMassDiffAxis, LambdaMassRatioAxis, LambdaMassRelDiffAxis}); - registry.add("matching/jets/V0/fakeJetPtV0TrackProjRadiusCosPA", "fake jet Pt, V0 zRadiusCosPA", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, V0RadiusAxis, V0CosPAAxis}); - registry.add("matching/jets/V0/fakeJetPtV0TrackProjDCAposneg", "fake jet Pt, V0 zDCAposneg", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/jets/V0/fakeJetPtV0TrackProjDCAd", "fake jet Pt, V0 zDCAd", HistType::kTH3D, {detJetPtAxis, detZAxis, V0DCAdAxis}); - // Misses - registry.add("matching/jets/V0/missJetPtV0PtEtaPhi", "miss jet Pt, V0 PtEtaPhi", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, V0EtaAxis, V0PhiAxis}); - registry.add("matching/jets/V0/missJetPtV0TrackProj", "Misses", HistType::kTH2D, {partJetPtAxis, partZAxis}); - - // ----------------------------- - // Lambda0 - // ----------------------------- - registry.add("matching/jets/V0/matchDetJetPtLambda0TrackProjPartJetPtLambda0TrackProj", "Matched", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, partJetPtAxis, partZAxis}); - registry.add("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0Pt", "matched jet Pt, #Lambda^{0} Pt", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis}); - // Matched Lambda0: pt - registry.add("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtCtauLambda0", "matched jet Pt, #Lambda^{0} Pt, Ctau #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtCtauAntiLambda0", "matched jet Pt, #Lambda^{0} Pt, Ctau #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtCtauK0S", "matched jet Pt, #{K}^{0}_{S} Pt, Ctau #{K}^{0}_{S}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtMassLambda0", "matched jet Pt, #Lambda^{0} Pt, Mass #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtMassAntiLambda0", "matched jet Pt, #Lambda^{0} Pt Mass #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtMassK0S", "matched jet Pt, #Lambda^{0} PtMassK0S", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, K0SMassAxis}); - registry.add("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtAllMasses", "matched jet Pt, #Lambda^{0} Pt, Masses", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtRadius", "matched jet Pt, #Lambda^{0} Pt Radius", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0RadiusAxis}); - registry.add("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtCosPA", "matched jet Pt, #Lambda^{0} Pt CosPA", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0CosPAAxis}); - registry.add("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtDCAposneg", "matched jet Pt, #Lambda^{0} PtDCAposneg", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtDCAd", "matched jet Pt, #Lambda^{0} PtDCAd", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0DCAdAxis}); - // Matched Lambda0: z - registry.add("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjCtauLambda0", "matched jet Pt, #Lambda^{0} Pt, Ctau #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjCtauAntiLambda0", "matched jet Pt, #Lambda^{0} Pt, Ctau #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjCtauK0S", "matched jet Pt, #{K}^{0}_{S} Pt, Ctau #{K}^{0}_{S}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjMassLambda0", "matched jet Pt, #Lambda^{0} Pt, Mass #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjMassAntiLambda0", "matched jet Pt, #Lambda^{0} Pt Mass #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjMassK0S", "matched jet Pt, #Lambda^{0} PtMassK0S", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, K0SMassAxis}); - registry.add("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjAllMasses", "matched jet Pt, #Lambda^{0} Pt, Masses", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjRadius", "matched jet Pt, #Lambda^{0} Pt Radius", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0RadiusAxis}); - registry.add("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjCosPA", "matched jet Pt, #Lambda^{0} Pt CosPA", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0CosPAAxis}); - registry.add("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjDCAposneg", "matched jet Pt, #Lambda^{0} PtDCAposneg", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjDCAd", "matched jet Pt, #Lambda^{0} PtDCAd", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0DCAdAxis}); - // Fake Lambda0 - registry.add("matching/jets/V0/fakeJetPtLambda0TrackProj", "Fakes", HistType::kTH2D, {detJetPtAxis, detZAxis}); - registry.add("matching/jets/V0/fakeJetPtLambda0PtEtaPhi", "fake jet Pt, #Lambda^{0} PtEtaPhi", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, V0EtaAxis, V0PhiAxis}); - registry.add("matching/jets/V0/fakeJetPtLambda0PtCtau", "fake jet Pt, #Lambda^{0} PtCtau", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, V0CtauAxis, V0CtauAxis, V0CtauAxis}); - registry.add("matching/jets/V0/fakeJetPtLambda0PtMass", "fake jet Pt, #Lambda^{0} PtMass", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/fakeJetPtLambda0PtLambdaMasses", "fake jet Pt, #Lambda^{0} PtLambdaMasses", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, LambdaMassDiffAxis, LambdaMassRatioAxis, LambdaMassRelDiffAxis}); - registry.add("matching/jets/V0/fakeJetPtLambda0PtRadiusCosPA", "fake jet Pt, #Lambda^{0} PtRadiusCosPA", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, V0RadiusAxis, V0CosPAAxis}); - registry.add("matching/jets/V0/fakeJetPtLambda0PtDCAposneg", "fake jet Pt, #Lambda^{0} PtDCAposneg", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/jets/V0/fakeJetPtLambda0PtDCAd", "fake jet Pt, #Lambda^{0} PtDCAd", HistType::kTH3D, {detJetPtAxis, V0PtAxis, V0DCAdAxis}); - registry.add("matching/jets/V0/fakeJetPtLambda0TrackProjEtaPhi", "fake jet Pt, #Lambda^{0} zEtaPhi", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, V0EtaAxis, V0PhiAxis}); - registry.add("matching/jets/V0/fakeJetPtLambda0TrackProjCtau", "fake jet Pt, #Lambda^{0} zCtau", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, V0CtauAxis, V0CtauAxis, V0CtauAxis}); - registry.add("matching/jets/V0/fakeJetPtLambda0TrackProjMass", "fake jet Pt, #Lambda^{0} zMass", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/fakeJetPtLambda0TrackProjLambdaMasses", "fake jet Pt, #Lambda^{0} zLambdaMasses", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, LambdaMassDiffAxis, LambdaMassRatioAxis, LambdaMassRelDiffAxis}); - registry.add("matching/jets/V0/fakeJetPtLambda0TrackProjRadiusCosPA", "fake jet Pt, #Lambda^{0} zRadiusCosPA", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, V0RadiusAxis, V0CosPAAxis}); - registry.add("matching/jets/V0/fakeJetPtLambda0TrackProjDCAposneg", "fake jet Pt, #Lambda^{0} zDCAposneg", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/jets/V0/fakeJetPtLambda0TrackProjDCAd", "fake jet Pt, #Lambda^{0} zDCAd", HistType::kTH3D, {detJetPtAxis, detZAxis, V0DCAdAxis}); - // Missed Lambda0 - registry.add("matching/jets/V0/missJetPtLambda0TrackProj", "Misses", HistType::kTH2D, {partJetPtAxis, partZAxis}); - registry.add("matching/jets/V0/missJetPtLambda0PtEtaPhi", "miss jet Pt, #Lambda^{0} PtEtaPhi", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, V0EtaAxis, V0PhiAxis}); - - // ----------------------------- - // AntiLambda0 - // ----------------------------- - registry.add("matching/jets/V0/matchDetJetPtAntiLambda0TrackProjPartJetPtAntiLambda0TrackProj", "Matched", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, partJetPtAxis, partZAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0Pt", "matched jet Pt, #bar{#Lambda}^{0} Pt", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis}); - // Matched AntiLambda0: pt - registry.add("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtCtauLambda0", "matched jet Pt, #bar{#Lambda}^{0} Pt, Ctau #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtCtauAntiLambda0", "matched jet Pt, #bar{#Lambda}^{0} Pt, Ctau #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtCtauK0S", "matched jet Pt, #{K}^{0}_{S} Pt, Ctau #{K}^{0}_{S}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtMassLambda0", "matched jet Pt, #bar{#Lambda}^{0} Pt, Mass #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtMassAntiLambda0", "matched jet Pt, #bar{#Lambda}^{0} Pt Mass #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtMassK0S", "matched jet Pt, #bar{#Lambda}^{0} PtMassK0S", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, K0SMassAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtAllMasses", "matched jet Pt, #bar{#Lambda}^{0} Pt, Masses", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtRadius", "matched jet Pt, #bar{#Lambda}^{0} Pt Radius", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0RadiusAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtCosPA", "matched jet Pt, #bar{#Lambda}^{0} Pt CosPA", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0CosPAAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtDCAposneg", "matched jet Pt, #bar{#Lambda}^{0} PtDCAposneg", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtDCAd", "matched jet Pt, #bar{#Lambda}^{0} PtDCAd", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0DCAdAxis}); - // Matched AntiLambda0: z - registry.add("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjCtauLambda0", "matched jet Pt, #bar{#Lambda}^{0} Pt, Ctau #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjCtauAntiLambda0", "matched jet Pt, #bar{#Lambda}^{0} Pt, Ctau #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjCtauK0S", "matched jet Pt, #{K}^{0}_{S} Pt, Ctau #{K}^{0}_{S}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjMassLambda0", "matched jet Pt, #bar{#Lambda}^{0} Pt, Mass #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjMassAntiLambda0", "matched jet Pt, #bar{#Lambda}^{0} Pt Mass #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjMassK0S", "matched jet Pt, #bar{#Lambda}^{0} PtMassK0S", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, K0SMassAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjAllMasses", "matched jet Pt, #bar{#Lambda}^{0} Pt, Masses", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjRadius", "matched jet Pt, #bar{#Lambda}^{0} Pt Radius", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0RadiusAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjCosPA", "matched jet Pt, #bar{#Lambda}^{0} Pt CosPA", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0CosPAAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjDCAposneg", "matched jet Pt, #bar{#Lambda}^{0} PtDCAposneg", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjDCAd", "matched jet Pt, #bar{#Lambda}^{0} PtDCAd", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0DCAdAxis}); - // Fake AntiLambda0 - registry.add("matching/jets/V0/fakeJetPtAntiLambda0TrackProj", "Fakes", HistType::kTH2D, {detJetPtAxis, detZAxis}); - registry.add("matching/jets/V0/fakeJetPtAntiLambda0PtEtaPhi", "fake jet Pt, #bar{#Lambda}^{0} PtEtaPhi", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, V0EtaAxis, V0PhiAxis}); - registry.add("matching/jets/V0/fakeJetPtAntiLambda0PtCtau", "fake jet Pt, #bar{#Lambda}^{0} PtCtau", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, V0CtauAxis, V0CtauAxis, V0CtauAxis}); - registry.add("matching/jets/V0/fakeJetPtAntiLambda0PtMass", "fake jet Pt, #bar{#Lambda}^{0} PtMass", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/fakeJetPtAntiLambda0PtLambdaMasses", "fake jet Pt, #bar{#Lambda}^{0} PtLambdaMasses", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, LambdaMassDiffAxis, LambdaMassRatioAxis, LambdaMassRelDiffAxis}); - registry.add("matching/jets/V0/fakeJetPtAntiLambda0PtRadiusCosPA", "fake jet Pt, #bar{#Lambda}^{0} PtRadiusCosPA", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, V0RadiusAxis, V0CosPAAxis}); - registry.add("matching/jets/V0/fakeJetPtAntiLambda0PtDCAposneg", "fake jet Pt, #bar{#Lambda}^{0} PtDCAposneg", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/jets/V0/fakeJetPtAntiLambda0PtDCAd", "fake jet Pt, #bar{#Lambda}^{0} PtDCAd", HistType::kTH3D, {detJetPtAxis, V0PtAxis, V0DCAdAxis}); - - registry.add("matching/jets/V0/fakeJetPtAntiLambda0TrackProjCtau", "fake jet Pt, #bar{#Lambda}^{0} zCtau", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, V0CtauAxis, V0CtauAxis, V0CtauAxis}); - registry.add("matching/jets/V0/fakeJetPtAntiLambda0TrackProjMass", "fake jet Pt, #bar{#Lambda}^{0} zMass", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/fakeJetPtAntiLambda0TrackProjLambdaMasses", "fake jet Pt, #bar{#Lambda}^{0} zLambdaMasses", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, LambdaMassDiffAxis, LambdaMassRatioAxis, LambdaMassRelDiffAxis}); - registry.add("matching/jets/V0/fakeJetPtAntiLambda0TrackProjRadiusCosPA", "fake jet Pt, #bar{#Lambda}^{0} zRadiusCosPA", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, V0RadiusAxis, V0CosPAAxis}); - registry.add("matching/jets/V0/fakeJetPtAntiLambda0TrackProjDCAposneg", "fake jet Pt, #bar{#Lambda}^{0} zDCAposneg", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/jets/V0/fakeJetPtAntiLambda0TrackProjDCAd", "fake jet Pt, #bar{#Lambda}^{0} zDCAd", HistType::kTH3D, {detJetPtAxis, detZAxis, V0DCAdAxis}); - // Missed AntiLambda0 - registry.add("matching/jets/V0/missJetPtAntiLambda0TrackProj", "Misses", HistType::kTH2D, {partJetPtAxis, partZAxis}); - registry.add("matching/jets/V0/missJetPtAntiLambda0PtEtaPhi", "miss jet Pt, #bar{#Lambda}^{0} PtEtaPhi", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, V0EtaAxis, V0PhiAxis}); - - // ----------------------------- - // K0S - // ----------------------------- - registry.add("matching/jets/V0/matchDetJetPtK0STrackProjPartJetPtK0STrackProj", "Matched", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, partJetPtAxis, partZAxis}); - registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPt", "matched jet Pt, K_{S}^{0} Pt", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis}); - // Matched K0S: pt - registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtCtauLambda0", "matched jet Pt, K^{0}_{S} Pt, Ctau #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtCtauAntiLambda0", "matched jet Pt, K^{0}_{S} Pt, Ctau #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtCtauK0S", "matched jet Pt, #{K}^{0}_{S} Pt, Ctau #{K}^{0}_{S}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtMassLambda0", "matched jet Pt, K^{0}_{S} Pt, Mass #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtMassAntiLambda0", "matched jet Pt, K^{0}_{S} Pt Mass #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtMassK0S", "matched jet Pt, K^{0}_{S} PtMassK0S", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, K0SMassAxis}); - registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtAllMasses", "matched jet Pt, K^{0}_{S} Pt, Masses", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtRadius", "matched jet Pt, K^{0}_{S} Pt Radius", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0RadiusAxis}); - registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtCosPA", "matched jet Pt, K^{0}_{S} Pt CosPA", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0CosPAAxis}); - registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtDCAposneg", "matched jet Pt, K^{0}_{S} PtDCAposneg", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtDCAd", "matched jet Pt, K^{0}_{S} PtDCAd", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, detJetPtAxis, V0PtAxis, V0DCAdAxis}); - // Matched K0S: z - registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjCtauLambda0", "matched jet Pt, K^{0}_{S} Pt, Ctau #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjCtauAntiLambda0", "matched jet Pt, K^{0}_{S} Pt, Ctau #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjCtauK0S", "matched jet Pt, #{K}^{0}_{S} Pt, Ctau #{K}^{0}_{S}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0CtauAxis}); - registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjMassLambda0", "matched jet Pt, K^{0}_{S} Pt, Mass #Lambda^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjMassAntiLambda0", "matched jet Pt, K^{0}_{S} Pt Mass #bar{#Lambda}^{0}", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjMassK0S", "matched jet Pt, K^{0}_{S} PtMassK0S", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, K0SMassAxis}); - registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjAllMasses", "matched jet Pt, K^{0}_{S} Pt, Masses", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjRadius", "matched jet Pt, K^{0}_{S} Pt Radius", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0RadiusAxis}); - registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjCosPA", "matched jet Pt, K^{0}_{S} Pt CosPA", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0CosPAAxis}); - registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjDCAposneg", "matched jet Pt, K^{0}_{S} PtDCAposneg", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjDCAd", "matched jet Pt, K^{0}_{S} PtDCAd", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, V0DCAdAxis}); - // Fake K0S - registry.add("matching/jets/V0/fakeJetPtK0STrackProj", "Fakes", HistType::kTH2D, {detJetPtAxis, detZAxis}); - registry.add("matching/jets/V0/fakeJetPtK0SPtEtaPhi", "fake jet Pt, K^{0}_{S} PtEtaPhi", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, V0EtaAxis, V0PhiAxis}); - registry.add("matching/jets/V0/fakeJetPtK0SPtCtau", "fake jet Pt, K^{0}_{S} PtCtau", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, V0CtauAxis, V0CtauAxis, V0CtauAxis}); - registry.add("matching/jets/V0/fakeJetPtK0SPtMass", "fake jet Pt, K^{0}_{S} PtMass", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/fakeJetPtK0SPtLambdaMasses", "fake jet Pt, K^{0}_{S} PtLambdaMasses", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, LambdaMassDiffAxis, LambdaMassRatioAxis, LambdaMassRelDiffAxis}); - registry.add("matching/jets/V0/fakeJetPtK0SPtRadiusCosPA", "fake jet Pt, K^{0}_{S} PtRadiusCosPA", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, V0RadiusAxis, V0CosPAAxis}); - registry.add("matching/jets/V0/fakeJetPtK0SPtDCAposneg", "fake jet Pt, K^{0}_{S} PtDCAposneg", HistType::kTHnSparseD, {detJetPtAxis, V0PtAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/jets/V0/fakeJetPtK0SPtDCAd", "fake jet Pt, K^{0}_{S} PtDCAd", HistType::kTH3D, {detJetPtAxis, V0PtAxis, V0DCAdAxis}); - - registry.add("matching/jets/V0/fakeJetPtK0STrackProjCtau", "fake jet Pt, K^{0}_{S} zCtau", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, V0CtauAxis, V0CtauAxis, V0CtauAxis}); - registry.add("matching/jets/V0/fakeJetPtK0STrackProjMass", "fake jet Pt, K^{0}_{S} zMass", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/fakeJetPtK0STrackProjLambdaMasses", "fake jet Pt, K^{0}_{S} zLambdaMasses", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, LambdaMassDiffAxis, LambdaMassRatioAxis, LambdaMassRelDiffAxis}); - registry.add("matching/jets/V0/fakeJetPtK0STrackProjRadiusCosPA", "fake jet Pt, K^{0}_{S} zRadiusCosPA", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, V0RadiusAxis, V0CosPAAxis}); - registry.add("matching/jets/V0/fakeJetPtK0STrackProjDCAposneg", "fake jet Pt, K^{0}_{S} zDCAposneg", HistType::kTHnSparseD, {detJetPtAxis, detZAxis, V0DCApAxis, V0DCAnAxis}); - registry.add("matching/jets/V0/fakeJetPtK0STrackProjDCAd", "fake jet Pt, K^{0}_{S} zDCAd", HistType::kTH3D, {detJetPtAxis, detZAxis, V0DCAdAxis}); - // Missed K0S - registry.add("matching/jets/V0/missJetPtK0STrackProj", "Misses", HistType::kTH2D, {partJetPtAxis, partZAxis}); - registry.add("matching/jets/V0/missJetPtK0SPtEtaPhi", "miss jet Pt, K^{0}_{S} PtEtaPhi", HistType::kTHnSparseD, {partJetPtAxis, V0PtAxis, V0EtaAxis, V0PhiAxis}); - - // Reflections - registry.add("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtLambda0Reflection", "Lambda0 Reflection", HistType::kTHnSparseD, {partJetPtAxis, V0partPtAxis, detJetPtAxis, V0detPtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjLambda0Reflection", "Lambda0 Reflection", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtAntiLambda0Reflection", "antiLambda0 Reflection", HistType::kTHnSparseD, {partJetPtAxis, V0partPtAxis, detJetPtAxis, V0detPtAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis, LambdaMassAxis}); - registry.add("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjAntiLambda0Reflection", "antiLambda0 Reflection", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis, K0SMassAxis, LambdaMassAxis, LambdaMassAxis, LambdaMassAxis}); - } // doprocessMcMatchedV0Frag - } // init - - // TODO: Can we move most/all of this stuff into a filter? - template - bool IsV0Candidate(V0Type const& v0) - { - if (v0.eta() < v0EtaMin || v0.eta() > v0EtaMax) { // TODO: Should be rapidity, mass matters! - return false; - } - if (v0.dcaV0daughters() > dcav0dauMax) { - return false; - } - if (v0.v0radius() < v0radiusMin) { - return false; - } - if (v0.v0cosPA() < v0cospaMin) { - return false; - } - return true; - } - template - bool IsK0SCandidate(CollisionType const& collision, V0Type const& v0) - { - if (!IsV0Candidate(v0)) { - return false; - } - if (v0.dcanegtopv() < dcapiMin || v0.dcapostopv() < dcapiMin) { - return false; - } - double ctauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short; - if (ctauK0s > lifetimeK0SMax) { - return false; - } - bool k0sMassCondition = (TMath::Abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < k0sMassAccWindow); - if (!k0sMassCondition) { - return false; - } - return true; - } - template - bool IsLambdaCandidate(CollisionType const& collision, V0Type const& v0) - { - if (!IsV0Candidate(v0)) { - return false; - } - if (v0.dcanegtopv() < dcapiMin || v0.dcapostopv() < dcaprMin) { - return false; - } - double ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; - if (ctauLambda > lifetimeLambdaMax) { - return false; - } - bool lambdaMassCondition = (TMath::Abs(v0.mLambda() - o2::constants::physics::MassLambda0) < lambdaMassAccWindow); - if (!lambdaMassCondition) { - return false; - } - return true; - } - template - bool IsAntiLambdaCandidate(CollisionType const& collision, V0Type const& v0) - { - if (!IsV0Candidate(v0)) { - return false; - } - if (v0.dcanegtopv() < dcaprMin || v0.dcapostopv() < dcapiMin) { - return false; - } - double ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0Bar; - if (ctauAntiLambda > lifetimeLambdaMax) { - return false; - } - bool antilambdaMassCondition = (TMath::Abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0Bar) < antilambdaMassAccWindow); - if (!antilambdaMassCondition) { - return false; - } - return true; - } - - template - double ReflectedMass(V0Type const& v0, bool isLambda) - { - // If V0 is Lambda, posTrack = proton, negTrack = pion - // In that case, we assign pion mass to posTrack and proton mass to negTrack to calculate the reflection - // Vice versa for AntiLambda - double negM = (isLambda ? o2::constants::physics::MassProton : o2::constants::physics::MassPionCharged); - double posM = (isLambda ? o2::constants::physics::MassPionCharged : o2::constants::physics::MassProton); - double negPsq = v0.pxneg() * v0.pxneg() + v0.pyneg() * v0.pyneg() + v0.pzneg() * v0.pzneg(); - double posPsq = v0.pxpos() * v0.pxpos() + v0.pypos() * v0.pypos() + v0.pzpos() * v0.pzpos(); - double negE = TMath::Sqrt(negM * negM + negPsq); - double posE = TMath::Sqrt(posM * posM + posPsq); - double Esquared = (negE + posE) * (negE + posE); - double psquared = v0.p() * v0.p(); - return TMath::Sqrt(Esquared - psquared); - } - - template - double ChargeFrag(Jet const& jet, Constituent const& constituent) - { - double chargeFrag = -1.; - chargeFrag = constituent.pt() / jet.pt(); - return chargeFrag; - } - template - double Theta(Jet const& jet, Constituent const& constituent) - { - double theta = -1.; - theta = jetutilities::deltaR(jet, constituent); - return theta; - } - template - double TrackProj(Jet const& jet, Constituent const& constituent) - { - double trackProj = -1.; - trackProj = constituent.px() * jet.px() + constituent.py() * jet.py() + constituent.pz() * jet.pz(); - trackProj /= (jet.p() * jet.p()); - return trackProj; - } - template - double Xi(Jet const& jet, Constituent const& constituent) - { - double xi = -1., trackProj = -1.; - trackProj = TrackProj(jet, constituent); - if (trackProj > 0) { - xi = TMath::Log(1. / trackProj); - } - return xi; - } - - template - void fillMcMatchedV0Histograms(collisionType const& collision, v0Type const& v0, trackType const&, particleType const&, double weight = 1.) - { - auto negTrack = v0.template negTrack_as(); - auto posTrack = v0.template posTrack_as(); - if (!negTrack.has_mcParticle() || !posTrack.has_mcParticle()) { - return; - } - auto mcNegTrack = negTrack.template mcParticle_as(); - auto mcPosTrack = posTrack.template mcParticle_as(); - if (!mcNegTrack.has_mothers() || !mcPosTrack.has_mothers()) { - return; - } - double ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; - double ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0Bar; - double ctauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short; - // Can tracks have multiple mothers? - for (auto& particleMotherOfNeg : mcNegTrack.template mothers_as()) { - for (auto& particleMotherOfPos : mcPosTrack.template mothers_as()) { - if (particleMotherOfNeg.isPhysicalPrimary() && particleMotherOfNeg == particleMotherOfPos) { - double ptPartV0 = particleMotherOfNeg.pt(); - int pdg = particleMotherOfNeg.pdgCode(); - registry.fill(HIST("matching/V0/V0PartPtDetPt"), ptPartV0, v0.pt()); - registry.fill(HIST("matching/V0/V0PartPtRatioPtRelDiffPt"), ptPartV0, v0.pt() / ptPartV0, (v0.pt() - ptPartV0) / ptPartV0); - - if (pdg == 310) { // K0S - registry.fill(HIST("matching/V0/K0SPtEtaPhi"), ptPartV0, v0.pt(), v0.eta(), v0.phi()); - registry.fill(HIST("matching/V0/K0SPtCtauMass"), ptPartV0, v0.pt(), ctauK0s, v0.mK0Short(), weight); - registry.fill(HIST("matching/V0/K0SPtRadiusCosPA"), ptPartV0, v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); - registry.fill(HIST("matching/V0/K0SPtDCAposneg"), ptPartV0, v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/V0/K0SPtDCAd"), ptPartV0, v0.pt(), v0.dcaV0daughters(), weight); - registry.fill(HIST("matching/V0/K0SPtMass"), ptPartV0, v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); - } else if (pdg == 3122) { // Lambda - registry.fill(HIST("matching/V0/LambdaPtEtaPhi"), ptPartV0, v0.pt(), v0.eta(), v0.phi()); - registry.fill(HIST("matching/V0/LambdaPtCtauMass"), ptPartV0, v0.pt(), ctauLambda, v0.mLambda(), weight); - registry.fill(HIST("matching/V0/LambdaPtRadiusCosPA"), ptPartV0, v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); - registry.fill(HIST("matching/V0/LambdaPtDCAposneg"), ptPartV0, v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/V0/LambdaPtDCAd"), ptPartV0, v0.pt(), v0.dcaV0daughters(), weight); - registry.fill(HIST("matching/V0/LambdaPtMass"), ptPartV0, v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); - - // Reflection - double reflectedMass = ReflectedMass(v0, true); - registry.fill(HIST("matching/V0/Lambda0Reflection"), ptPartV0, v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), reflectedMass, weight); - } else if (pdg == -3122) { // AntiLambda - registry.fill(HIST("matching/V0/antiLambdaPtEtaPhi"), ptPartV0, v0.pt(), v0.eta(), v0.phi()); - registry.fill(HIST("matching/V0/antiLambdaPtCtauMass"), ptPartV0, v0.pt(), ctauAntiLambda, v0.mAntiLambda(), weight); - registry.fill(HIST("matching/V0/antiLambdaPtRadiusCosPA"), ptPartV0, v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); - registry.fill(HIST("matching/V0/antiLambdaPtDCAposneg"), ptPartV0, v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/V0/antiLambdaPtDCAd"), ptPartV0, v0.pt(), v0.dcaV0daughters(), weight); - registry.fill(HIST("matching/V0/antiLambdaPtMass"), ptPartV0, v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); - - // Reflection - double reflectedMass = ReflectedMass(v0, false); - registry.fill(HIST("matching/V0/antiLambda0Reflection"), ptPartV0, v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), reflectedMass, weight); - } - } // if mothers match - } // for mothers of pos - } // for mothers of neg - } - - template - void fillDataRun3Histograms(T const& jet) - { - registry.fill(HIST("data/jets/jetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi()); - for (const auto& track : jet.template tracks_as()) { - double chargeFrag = -1., trackProj = -1., xi = -1., theta = -1.; - chargeFrag = ChargeFrag(jet, track); - trackProj = TrackProj(jet, track); - theta = Theta(jet, track); - xi = Xi(jet, track); - - registry.fill(HIST("data/jets/jetPtTrackPt"), jet.pt(), track.pt()); - registry.fill(HIST("data/jets/jetTrackPtEtaPhi"), track.pt(), track.eta(), track.phi()); - registry.fill(HIST("data/jets/jetPtFrag"), jet.pt(), chargeFrag); - registry.fill(HIST("data/jets/jetPtTrackProj"), jet.pt(), trackProj); - registry.fill(HIST("data/jets/jetPtXi"), jet.pt(), xi); - registry.fill(HIST("data/jets/jetPtTheta"), jet.pt(), theta); - registry.fill(HIST("data/jets/jetPtXiTheta"), jet.pt(), xi, theta); - registry.fill(HIST("data/jets/jetPtZTheta"), jet.pt(), trackProj, theta); - } - } - - template - void fillDataV0Histograms(CollisionType const& collision, V0Type const& V0s, TrackType const&) - { - for (const auto& v0 : V0s) { - double ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; - double ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0Bar; - double ctauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short; - - double massDiff = v0.mLambda() - v0.mAntiLambda(); - double massRatio = v0.mAntiLambda() / v0.mLambda(); - double massRelDiff = (v0.mLambda() - v0.mAntiLambda()) / v0.mLambda(); - - registry.fill(HIST("data/V0/V0PtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); - registry.fill(HIST("data/V0/V0PtCtau"), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda); - registry.fill(HIST("data/V0/V0PtMass"), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); - registry.fill(HIST("data/V0/V0PtLambdaMasses"), v0.pt(), massDiff, massRatio, massRelDiff); - registry.fill(HIST("data/V0/V0PtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA()); - registry.fill(HIST("data/V0/V0PtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); - registry.fill(HIST("data/V0/V0PtDCAd"), v0.pt(), v0.dcaV0daughters()); - - registry.fill(HIST("data/V0/V0CutVariation"), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), v0.v0radius(), ctauK0s, v0.v0cosPA(), TMath::Abs(v0.dcapostopv()), TMath::Abs(v0.dcanegtopv()), v0.dcaV0daughters()); - - if (IsLambdaCandidate(collision, v0)) { - registry.fill(HIST("data/V0/LambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); - registry.fill(HIST("data/V0/LambdaPtCtauMass"), v0.pt(), ctauLambda, v0.mLambda()); - registry.fill(HIST("data/V0/LambdaPtLambdaMasses"), v0.pt(), massDiff, massRatio, massRelDiff); - registry.fill(HIST("data/V0/LambdaPtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA()); - registry.fill(HIST("data/V0/LambdaPtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); - registry.fill(HIST("data/V0/LambdaPtDCAd"), v0.pt(), v0.dcaV0daughters()); - } - if (IsAntiLambdaCandidate(collision, v0)) { - registry.fill(HIST("data/V0/antiLambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); - registry.fill(HIST("data/V0/antiLambdaPtCtauMass"), v0.pt(), ctauAntiLambda, v0.mAntiLambda()); - registry.fill(HIST("data/V0/antiLambdaPtLambdaMasses"), v0.pt(), massDiff, massRatio, massRelDiff); - registry.fill(HIST("data/V0/antiLambdaPtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA()); - registry.fill(HIST("data/V0/antiLambdaPtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); - registry.fill(HIST("data/V0/antiLambdaPtDCAd"), v0.pt(), v0.dcaV0daughters()); - } - if (IsK0SCandidate(collision, v0)) { - registry.fill(HIST("data/V0/K0SPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); - registry.fill(HIST("data/V0/K0SPtCtauMass"), v0.pt(), ctauK0s, v0.mK0Short()); - registry.fill(HIST("data/V0/K0SPtRadiusCosPA"), v0.pt(), v0.v0radius(), v0.v0cosPA()); - registry.fill(HIST("data/V0/K0SPtDCAposneg"), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); - registry.fill(HIST("data/V0/K0SPtDCAd"), v0.pt(), v0.dcaV0daughters()); - } - } // for v0 - } - - template - void fillDataV0FragHistograms(CollisionType const& collision, JetType const& jet, V0Type const& v0) - { - double trackProj = TrackProj(jet, v0); - double ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; - double ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0Bar; - double ctauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short; - - double massDiff = v0.mLambda() - v0.mAntiLambda(); - double massRatio = v0.mAntiLambda() / v0.mLambda(); - double massRelDiff = (v0.mLambda() - v0.mAntiLambda()) / v0.mLambda(); - - registry.fill(HIST("data/jets/V0/jetPtV0PtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi()); - registry.fill(HIST("data/jets/V0/jetPtV0PtCtau"), jet.pt(), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda); - registry.fill(HIST("data/jets/V0/jetPtV0PtMass"), jet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); - registry.fill(HIST("data/jets/V0/jetPtV0PtLambdaMasses"), jet.pt(), v0.pt(), massDiff, massRatio, massRelDiff); - registry.fill(HIST("data/jets/V0/jetPtV0PtRadiusCosPA"), jet.pt(), v0.pt(), v0.v0radius(), v0.v0cosPA()); - registry.fill(HIST("data/jets/V0/jetPtV0PtDCAposneg"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); - registry.fill(HIST("data/jets/V0/jetPtV0PtDCAd"), jet.pt(), v0.pt(), v0.dcaV0daughters()); - - registry.fill(HIST("data/jets/V0/jetPtV0TrackProj"), jet.pt(), trackProj); - registry.fill(HIST("data/jets/V0/jetPtV0TrackProjCtau"), jet.pt(), trackProj, ctauK0s, ctauLambda, ctauAntiLambda); - registry.fill(HIST("data/jets/V0/jetPtV0TrackProjMass"), jet.pt(), trackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); - registry.fill(HIST("data/jets/V0/jetPtV0TrackProjLambdaMasses"), jet.pt(), trackProj, massDiff, massRatio, massRelDiff); - registry.fill(HIST("data/jets/V0/jetPtV0TrackProjRadiusCosPA"), jet.pt(), trackProj, v0.v0radius(), v0.v0cosPA()); - registry.fill(HIST("data/jets/V0/jetPtV0TrackProjDCAposneg"), jet.pt(), trackProj, v0.dcapostopv(), v0.dcanegtopv()); - registry.fill(HIST("data/jets/V0/jetPtV0TrackProjDCAd"), jet.pt(), trackProj, v0.dcaV0daughters()); - - if (IsK0SCandidate(collision, v0)) { - registry.fill(HIST("data/jets/V0/jetPtK0SPtCtau"), jet.pt(), v0.pt(), ctauK0s); - registry.fill(HIST("data/jets/V0/jetPtK0SPtMass"), jet.pt(), v0.pt(), v0.mK0Short()); - registry.fill(HIST("data/jets/V0/jetPtK0SPtAllMasses"), jet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); - registry.fill(HIST("data/jets/V0/jetPtK0SPtRadius"), jet.pt(), v0.pt(), v0.v0radius()); - registry.fill(HIST("data/jets/V0/jetPtK0SPtCosPA"), jet.pt(), v0.pt(), v0.v0cosPA()); - registry.fill(HIST("data/jets/V0/jetPtK0SPtDCAd"), jet.pt(), v0.pt(), v0.dcaV0daughters()); - registry.fill(HIST("data/jets/V0/jetPtK0SPtDCAposneg"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); - - registry.fill(HIST("data/jets/V0/jetPtK0STrackProjCtau"), jet.pt(), trackProj, ctauK0s); - registry.fill(HIST("data/jets/V0/jetPtK0STrackProjMass"), jet.pt(), trackProj, v0.mK0Short()); - registry.fill(HIST("data/jets/V0/jetPtK0STrackProjAllMasses"), jet.pt(), trackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); - registry.fill(HIST("data/jets/V0/jetPtK0STrackProjRadius"), jet.pt(), trackProj, v0.v0radius()); - registry.fill(HIST("data/jets/V0/jetPtK0STrackProjCosPA"), jet.pt(), trackProj, v0.v0cosPA()); - registry.fill(HIST("data/jets/V0/jetPtK0STrackProjDCAd"), jet.pt(), trackProj, v0.dcaV0daughters()); - registry.fill(HIST("data/jets/V0/jetPtK0STrackProjDCAposneg"), jet.pt(), trackProj, v0.dcapostopv(), v0.dcanegtopv()); - } - if (IsLambdaCandidate(collision, v0)) { - registry.fill(HIST("data/jets/V0/jetPtLambdaPtCtau"), jet.pt(), v0.pt(), ctauLambda); - registry.fill(HIST("data/jets/V0/jetPtLambdaPtMass"), jet.pt(), v0.pt(), v0.mLambda()); - registry.fill(HIST("data/jets/V0/jetPtLambdaPtAllMasses"), jet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); - registry.fill(HIST("data/jets/V0/jetPtLambdaPtLambdaMasses"), jet.pt(), v0.pt(), massDiff, massRatio, massRelDiff); - registry.fill(HIST("data/jets/V0/jetPtLambdaPtRadius"), jet.pt(), v0.pt(), v0.v0radius()); - registry.fill(HIST("data/jets/V0/jetPtLambdaPtCosPA"), jet.pt(), v0.pt(), v0.v0cosPA()); - registry.fill(HIST("data/jets/V0/jetPtLambdaPtDCAd"), jet.pt(), v0.pt(), v0.dcaV0daughters()); - registry.fill(HIST("data/jets/V0/jetPtLambdaPtDCAposneg"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); - - registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjCtau"), jet.pt(), trackProj, ctauLambda); - registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjMass"), jet.pt(), trackProj, v0.mLambda()); - registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjAllMasses"), jet.pt(), trackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); - registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjLambdaMasses"), jet.pt(), trackProj, massDiff, massRatio, massRelDiff); - registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjRadius"), jet.pt(), trackProj, v0.v0radius()); - registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjCosPA"), jet.pt(), trackProj, v0.v0cosPA()); - registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjDCAd"), jet.pt(), trackProj, v0.dcaV0daughters()); - registry.fill(HIST("data/jets/V0/jetPtLambdaTrackProjDCAposneg"), jet.pt(), trackProj, v0.dcapostopv(), v0.dcanegtopv()); - } - if (IsAntiLambdaCandidate(collision, v0)) { - registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtCtau"), jet.pt(), v0.pt(), ctauAntiLambda); - registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtMass"), jet.pt(), v0.pt(), v0.mAntiLambda()); - registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtAllMasses"), jet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); - registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtLambdaMasses"), jet.pt(), v0.pt(), massDiff, massRatio, massRelDiff); - registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtRadius"), jet.pt(), v0.pt(), v0.v0radius()); - registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtCosPA"), jet.pt(), v0.pt(), v0.v0cosPA()); - registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtDCAd"), jet.pt(), v0.pt(), v0.dcaV0daughters()); - registry.fill(HIST("data/jets/V0/jetPtAntiLambdaPtDCAposneg"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv()); - - registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjCtau"), jet.pt(), trackProj, ctauAntiLambda); - registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjMass"), jet.pt(), trackProj, v0.mAntiLambda()); - registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjAllMasses"), jet.pt(), trackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda()); - registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjLambdaMasses"), jet.pt(), trackProj, massDiff, massRatio, massRelDiff); - registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjRadius"), jet.pt(), trackProj, v0.v0radius()); - registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjCosPA"), jet.pt(), trackProj, v0.v0cosPA()); - registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjDCAd"), jet.pt(), trackProj, v0.dcaV0daughters()); - registry.fill(HIST("data/jets/V0/jetPtAntiLambdaTrackProjDCAposneg"), jet.pt(), trackProj, v0.dcapostopv(), v0.dcanegtopv()); - } - } - - template - void fillMatchingHistogramsJet(DetJet const& detJet, PartJet const& partJet, double weight = 1.) - { - double deltaEta = detJet.eta() - partJet.eta(); - double deltaPhi = RecoDecay::constrainAngle(detJet.phi() - partJet.phi(), -M_PI); - double dR = jetutilities::deltaR(detJet, partJet); - - registry.fill(HIST("matching/jets/matchDetJetPtEtaPhi"), detJet.pt(), detJet.eta(), detJet.phi(), weight); - registry.fill(HIST("matching/jets/matchPartJetPtEtaPhi"), partJet.pt(), partJet.eta(), partJet.phi(), weight); - registry.fill(HIST("matching/jets/matchPartJetPtEtaPhiMatchDist"), partJet.pt(), partJet.eta(), partJet.phi(), dR, weight); - registry.fill(HIST("matching/jets/matchPartJetPtEnergyScale"), partJet.pt(), detJet.pt() / partJet.pt(), weight); - registry.fill(HIST("matching/jets/matchDetJetPtPartJetPt"), detJet.pt(), partJet.pt(), weight); - registry.fill(HIST("matching/jets/matchPartJetPtDetJetEtaPartJetEta"), partJet.pt(), detJet.eta(), partJet.eta(), weight); - registry.fill(HIST("matching/jets/matchPartJetPtDetJetPhiPartJetPhi"), partJet.pt(), detJet.phi(), partJet.phi(), weight); - registry.fill(HIST("matching/jets/matchPartJetPtResolutionPt"), partJet.pt(), (detJet.pt() - partJet.pt()), weight); - registry.fill(HIST("matching/jets/matchPartJetPtResolutionEta"), partJet.pt(), partJet.eta(), deltaEta, weight); - registry.fill(HIST("matching/jets/matchPartJetPtResolutionPhi"), partJet.pt(), partJet.phi(), deltaPhi, weight); - registry.fill(HIST("matching/jets/matchPartJetPtRelDiffPt"), partJet.pt(), (detJet.pt() - partJet.pt()) / partJet.pt(), weight); - } - - template - void fillMatchingHistogramsConstituent(DetJet const& detJet, PartJet const& partJet, Track const& track, Particle const& particle, double weight = 1.) - { - double detChargeFrag = -1., detTrackProj = -1., detTheta = -1., detXi = -1.; - double partChargeFrag = -1., partTrackProj = -1., partTheta = -1., partXi = -1.; - - detChargeFrag = ChargeFrag(detJet, track); - detTrackProj = TrackProj(detJet, track); - detTheta = Theta(detJet, track); - detXi = Xi(detJet, track); - - partChargeFrag = ChargeFrag(partJet, particle); - partTrackProj = TrackProj(partJet, particle); - partTheta = Theta(partJet, particle); - partXi = Xi(partJet, particle); - - // Detector level - registry.fill(HIST("matching/jets/matchDetJetTrackPtEtaPhi"), track.pt(), track.eta(), track.phi(), weight); - registry.fill(HIST("matching/jets/matchDetJetPtTrackPt"), detJet.pt(), track.pt(), weight); - registry.fill(HIST("matching/jets/matchDetJetPtFrag"), detJet.pt(), detChargeFrag, weight); - registry.fill(HIST("matching/jets/matchDetJetPtTrackProj"), detJet.pt(), detTrackProj, weight); - registry.fill(HIST("matching/jets/matchDetJetPtXi"), detJet.pt(), detXi, weight); - registry.fill(HIST("matching/jets/matchDetJetPtTheta"), detJet.pt(), detTheta, weight); - registry.fill(HIST("matching/jets/matchDetJetPtXiTheta"), detJet.pt(), detXi, detTheta, weight); - registry.fill(HIST("matching/jets/matchDetJetPtZTheta"), detJet.pt(), detTrackProj, detTheta, weight); - - // Particle level - registry.fill(HIST("matching/jets/matchPartJetTrackPtEtaPhi"), particle.pt(), particle.eta(), particle.phi(), weight); - registry.fill(HIST("matching/jets/matchPartJetPtTrackPt"), partJet.pt(), particle.pt(), weight); - registry.fill(HIST("matching/jets/matchPartJetPtFrag"), partJet.pt(), partChargeFrag, weight); - registry.fill(HIST("matching/jets/matchPartJetPtTrackProj"), partJet.pt(), partTrackProj, weight); - registry.fill(HIST("matching/jets/matchPartJetPtXi"), partJet.pt(), partXi, weight); - registry.fill(HIST("matching/jets/matchPartJetPtTheta"), partJet.pt(), partTheta, weight); - registry.fill(HIST("matching/jets/matchPartJetPtXiTheta"), partJet.pt(), partXi, partTheta, weight); - registry.fill(HIST("matching/jets/matchPartJetPtZTheta"), partJet.pt(), partTrackProj, partTheta, weight); - - // Resolution - registry.fill(HIST("matching/jets/matchPartJetPtResolutionTrackPt"), partJet.pt(), particle.pt(), (particle.pt() - track.pt()), weight); - registry.fill(HIST("matching/jets/matchPartJetPtResolutionChargeFrag"), partJet.pt(), partChargeFrag, (detChargeFrag - partChargeFrag), weight); - registry.fill(HIST("matching/jets/matchPartJetPtResolutionTrackProj"), partJet.pt(), partTrackProj, (detTrackProj - partTrackProj), weight); - registry.fill(HIST("matching/jets/matchPartJetPtResolutionXi"), partJet.pt(), partXi, (detXi - partXi), weight); - registry.fill(HIST("matching/jets/matchPartJetPtResolutionTheta"), partJet.pt(), partTheta, (detTheta - partTheta), weight); - registry.fill(HIST("matching/jets/matchPartJetPtResolutionXiResolutionTheta"), partJet.pt(), partXi, (detXi - partXi), partTheta, (detTheta - partTheta), weight); - registry.fill(HIST("matching/jets/matchPartJetPtResolutionZResolutionTheta"), partJet.pt(), partTrackProj, (detTrackProj - partTrackProj), partTheta, (detTheta - partTheta), weight); - - // Relative difference - registry.fill(HIST("matching/jets/matching/jets/matchPartJetPtRelDiffTrackPt"), partJet.pt(), detJet.pt() / partJet.pt(), particle.pt(), (track.pt() - particle.pt()) / particle.pt(), weight); - registry.fill(HIST("matching/jets/matchPartJetPtRelDiffTrackProj"), partJet.pt(), detJet.pt() / partJet.pt(), partTrackProj, (detTrackProj - partTrackProj) / partTrackProj, weight); - - // Response - registry.fill(HIST("matching/jets/matchDetJetPtFragPartJetPtFrag"), detJet.pt(), detChargeFrag, partJet.pt(), partChargeFrag, weight); - registry.fill(HIST("matching/jets/matchDetJetPtTrackProjPartJetPtTrackProj"), detJet.pt(), detTrackProj, partJet.pt(), partTrackProj, weight); - registry.fill(HIST("matching/jets/matchDetJetPtXiPartJetPtXi"), detJet.pt(), detXi, partJet.pt(), partXi, weight); - registry.fill(HIST("matching/jets/matchDetJetPtThetaPartJetPtTheta"), detJet.pt(), detTheta, partJet.pt(), partTheta, weight); - registry.fill(HIST("matching/jets/matchDetJetPtXiThetaPartJetPtXiTheta"), detJet.pt(), detXi, detTheta, partJet.pt(), partXi, partTheta, weight); - registry.fill(HIST("matching/jets/matchDetJetPtZThetaPartJetPtZTheta"), detJet.pt(), detTrackProj, detTheta, partJet.pt(), partTrackProj, partTheta, weight); - } - - template - void fillMatchingFakeOrMiss(Jet const& jet, Constituent const& constituent, bool isFake, double weight = 1.) - { - double chargeFrag = -1., trackProj = -1., theta = -1., xi = -1.; - chargeFrag = ChargeFrag(jet, constituent); - trackProj = TrackProj(jet, constituent); - theta = Theta(jet, constituent); - xi = Xi(jet, constituent); - - if (isFake) { - registry.fill(HIST("matching/jets/fakeDetJetPtFrag"), jet.pt(), chargeFrag, weight); - registry.fill(HIST("matching/jets/fakeDetJetPtTrackProj"), jet.pt(), trackProj, weight); - registry.fill(HIST("matching/jets/fakeDetJetPtXi"), jet.pt(), xi, weight); - registry.fill(HIST("matching/jets/fakeDetJetPtTheta"), jet.pt(), theta, weight); - registry.fill(HIST("matching/jets/fakeDetJetPtXiTheta"), jet.pt(), xi, theta, weight); - registry.fill(HIST("matching/jets/fakeDetJetPtZTheta"), jet.pt(), trackProj, theta, weight); - } else { - registry.fill(HIST("matching/jets/missPartJetPtFrag"), jet.pt(), chargeFrag, weight); - registry.fill(HIST("matching/jets/missPartJetPtTrackProj"), jet.pt(), trackProj, weight); - registry.fill(HIST("matching/jets/missPartJetPtXi"), jet.pt(), xi, weight); - registry.fill(HIST("matching/jets/missPartJetPtTheta"), jet.pt(), theta, weight); - registry.fill(HIST("matching/jets/missPartJetPtXiTheta"), jet.pt(), xi, theta, weight); - registry.fill(HIST("matching/jets/missPartJetPtZTheta"), jet.pt(), trackProj, theta, weight); - } - } - - template - void fillMatchingV0Miss(JetType const& jet, V0Type const& v0, double weight = 1.) - { - double trackProj = TrackProj(jet, v0); - - registry.fill(HIST("matching/jets/V0/missJetPtV0TrackProj"), jet.pt(), trackProj, weight); - registry.fill(HIST("matching/jets/V0/missJetPtV0PtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi(), weight); - if (v0.pdgCode() == 310) { // K0S - registry.fill(HIST("matching/jets/V0/missJetPtK0SPtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi(), weight); - registry.fill(HIST("matching/jets/V0/missJetPtK0STrackProj"), jet.pt(), trackProj, weight); - } else if (v0.pdgCode() == 3122) { // Lambda - registry.fill(HIST("matching/jets/V0/missJetPtLambda0PtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi(), weight); - registry.fill(HIST("matching/jets/V0/missJetPtLambda0TrackProj"), jet.pt(), trackProj, weight); - } else if (v0.pdgCode() == -3122) { // AntiLambda - registry.fill(HIST("matching/jets/V0/missJetPtAntiLambda0PtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi(), weight); - registry.fill(HIST("matching/jets/V0/missJetPtAntiLambda0TrackProj"), jet.pt(), trackProj, weight); - } - } - - template - void fillMatchingV0Fake(CollisionType const& collision, JetType const& jet, V0Type const& v0, double weight = 1.) - { - double trackProj = TrackProj(jet, v0); - double ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; - double ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0Bar; - double ctauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short; - double massDiff = v0.mLambda() - v0.mAntiLambda(); - double massRatio = v0.mAntiLambda() / v0.mLambda(); - double massRelDiff = (v0.mLambda() - v0.mAntiLambda()) / v0.mLambda(); - - registry.fill(HIST("matching/jets/V0/fakeJetPtV0PtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtV0TrackProj"), jet.pt(), trackProj, weight); - - registry.fill(HIST("matching/jets/V0/fakeJetPtV0PtCtau"), jet.pt(), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda, weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtV0PtMass"), jet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtV0PtLambdaMasses"), jet.pt(), v0.pt(), massDiff, massRatio, massRelDiff, weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtV0PtRadiusCosPA"), jet.pt(), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtV0PtDCAposneg"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtV0PtDCAd"), jet.pt(), v0.pt(), v0.dcaV0daughters(), weight); - - registry.fill(HIST("matching/jets/V0/fakeJetPtV0TrackProjCtau"), jet.pt(), trackProj, ctauK0s, ctauLambda, ctauAntiLambda, weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtV0TrackProjMass"), jet.pt(), trackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtV0TrackProjLambdaMasses"), jet.pt(), trackProj, massDiff, massRatio, massRelDiff, weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtV0TrackProjRadiusCosPA"), jet.pt(), trackProj, v0.v0radius(), v0.v0cosPA(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtV0TrackProjDCAposneg"), jet.pt(), trackProj, v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtV0TrackProjDCAd"), jet.pt(), trackProj, v0.dcaV0daughters(), weight); - - if (IsLambdaCandidate(collision, v0)) { - registry.fill(HIST("matching/jets/V0/fakeJetPtLambda0PtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtLambda0TrackProj"), jet.pt(), trackProj, weight); - - registry.fill(HIST("matching/jets/V0/fakeJetPtLambda0PtCtau"), jet.pt(), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda, weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtLambda0PtMass"), jet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtLambda0PtLambdaMasses"), jet.pt(), v0.pt(), massDiff, massRatio, massRelDiff, weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtLambda0PtRadiusCosPA"), jet.pt(), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtLambda0PtDCAposneg"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtLambda0PtDCAd"), jet.pt(), v0.pt(), v0.dcaV0daughters(), weight); - - registry.fill(HIST("matching/jets/V0/fakeJetPtLambda0TrackProjCtau"), jet.pt(), trackProj, ctauK0s, ctauLambda, ctauAntiLambda, weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtLambda0TrackProjMass"), jet.pt(), trackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtLambda0TrackProjLambdaMasses"), jet.pt(), trackProj, massDiff, massRatio, massRelDiff, weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtLambda0TrackProjRadiusCosPA"), jet.pt(), trackProj, v0.v0radius(), v0.v0cosPA(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtLambda0TrackProjDCAposneg"), jet.pt(), trackProj, v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtLambda0TrackProjDCAd"), jet.pt(), trackProj, v0.dcaV0daughters(), weight); - } - if (IsAntiLambdaCandidate(collision, v0)) { - registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambda0PtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambda0TrackProj"), jet.pt(), trackProj, weight); - - registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambda0PtCtau"), jet.pt(), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda, weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambda0PtMass"), jet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambda0PtLambdaMasses"), jet.pt(), v0.pt(), massDiff, massRatio, massRelDiff, weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambda0PtRadiusCosPA"), jet.pt(), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambda0PtDCAposneg"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambda0PtDCAd"), jet.pt(), v0.pt(), v0.dcaV0daughters(), weight); - - registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambda0TrackProjCtau"), jet.pt(), trackProj, ctauK0s, ctauLambda, ctauAntiLambda, weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambda0TrackProjMass"), jet.pt(), trackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambda0TrackProjLambdaMasses"), jet.pt(), trackProj, massDiff, massRatio, massRelDiff, weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambda0TrackProjRadiusCosPA"), jet.pt(), trackProj, v0.v0radius(), v0.v0cosPA(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambda0TrackProjDCAposneg"), jet.pt(), trackProj, v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtAntiLambda0TrackProjDCAd"), jet.pt(), trackProj, v0.dcaV0daughters(), weight); - } - if (IsK0SCandidate(collision, v0)) { - registry.fill(HIST("matching/jets/V0/fakeJetPtK0SPtEtaPhi"), jet.pt(), v0.pt(), v0.eta(), v0.phi(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtK0STrackProj"), jet.pt(), trackProj, weight); - - registry.fill(HIST("matching/jets/V0/fakeJetPtK0SPtCtau"), jet.pt(), v0.pt(), ctauK0s, ctauLambda, ctauAntiLambda, weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtK0SPtMass"), jet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtK0SPtLambdaMasses"), jet.pt(), v0.pt(), massDiff, massRatio, massRelDiff, weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtK0SPtRadiusCosPA"), jet.pt(), v0.pt(), v0.v0radius(), v0.v0cosPA(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtK0SPtDCAposneg"), jet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtK0SPtDCAd"), jet.pt(), v0.pt(), v0.dcaV0daughters(), weight); - - registry.fill(HIST("matching/jets/V0/fakeJetPtK0STrackProjCtau"), jet.pt(), trackProj, ctauK0s, ctauLambda, ctauAntiLambda, weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtK0STrackProjMass"), jet.pt(), trackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtK0STrackProjLambdaMasses"), jet.pt(), trackProj, massDiff, massRatio, massRelDiff, weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtK0STrackProjRadiusCosPA"), jet.pt(), trackProj, v0.v0radius(), v0.v0cosPA(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtK0STrackProjDCAposneg"), jet.pt(), trackProj, v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/jets/V0/fakeJetPtK0STrackProjDCAd"), jet.pt(), trackProj, v0.dcaV0daughters(), weight); - } - } - - template - void fillMatchingHistogramsV0(CollisionType const& collision, DetJetType const& detJet, PartJetType const& partJet, V0Type const& v0, ParticleType const& particle, double weight = 1.) - { - double detTrackProj = TrackProj(detJet, v0); - double partTrackProj = TrackProj(partJet, particle); - - double ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; - double ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0Bar; - double ctauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short; - - registry.fill(HIST("matching/jets/V0/matchDetJetPtV0TrackProjPartJetPtV0TrackProj"), detJet.pt(), detTrackProj, partJet.pt(), partTrackProj, weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0Pt"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetPt"), partJet.pt(), particle.pt(), detJet.pt(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtDetJetPtPartV0PtRatioPtRelDiffPt"), partJet.pt(), detJet.pt(), particle.pt(), v0.pt() / particle.pt(), (v0.pt() - particle.pt()) / particle.pt(), weight); - - registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtCtauLambda0"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauLambda, weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtCtauAntiLambda0"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauAntiLambda, weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtCtauK0S"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauK0s, weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtMassLambda0"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtMassAntiLambda0"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtMassK0S"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtRadius"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.v0radius(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtCosPA"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.v0cosPA(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtDCAposneg"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0PtDetJetPtV0PtDCAd"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.dcaV0daughters(), weight); - - registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjCtauLambda0"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauLambda, weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjCtauAntiLambda0"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauAntiLambda, weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjCtauK0S"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauK0s, weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjMassLambda0"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjMassAntiLambda0"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjMassK0S"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjRadius"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.v0radius(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjCosPA"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.v0cosPA(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjDCAposneg"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtV0TrackProjDetJetPtV0TrackProjDCAd"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.dcaV0daughters(), weight); - - if (particle.pdgCode() == 310) { // K0S - registry.fill(HIST("matching/jets/V0/matchDetJetPtK0STrackProjPartJetPtK0STrackProj"), detJet.pt(), detTrackProj, partJet.pt(), partTrackProj, weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPt"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), weight); - - registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtCtauLambda0"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauLambda, weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtCtauAntiLambda0"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauAntiLambda, weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtCtauK0S"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauK0s, weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtMassLambda0"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtMassAntiLambda0"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtMassK0S"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtAllMasses"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtRadius"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.v0radius(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtCosPA"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.v0cosPA(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtDCAposneg"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtDCAd"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.dcaV0daughters(), weight); - - registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjCtauLambda0"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauLambda, weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjCtauAntiLambda0"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauAntiLambda, weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjCtauK0S"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauK0s, weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjMassLambda0"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjMassAntiLambda0"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjMassK0S"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjAllMasses"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjRadius"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.v0radius(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjCosPA"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.v0cosPA(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjDCAposneg"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjDCAd"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.dcaV0daughters(), weight); - } else if (particle.pdgCode() == 3122) { // Lambda - registry.fill(HIST("matching/jets/V0/matchDetJetPtLambda0TrackProjPartJetPtLambda0TrackProj"), detJet.pt(), detTrackProj, partJet.pt(), partTrackProj, weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0Pt"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), weight); - - registry.fill(HIST("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtCtauLambda0"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauLambda, weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtCtauAntiLambda0"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauAntiLambda, weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtCtauK0S"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauK0s, weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtMassLambda0"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtMassAntiLambda0"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtMassK0S"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtAllMasses"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtRadius"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.v0radius(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtCosPA"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.v0cosPA(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtDCAposneg"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtDCAd"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.dcaV0daughters(), weight); - - registry.fill(HIST("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjCtauLambda0"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauLambda, weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjCtauAntiLambda0"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauAntiLambda, weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjCtauK0S"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauK0s, weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjMassLambda0"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjMassAntiLambda0"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjMassK0S"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjAllMasses"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjRadius"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.v0radius(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjCosPA"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.v0cosPA(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjDCAposneg"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjDCAd"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.dcaV0daughters(), weight); - - // Reflection - double reflectedMass = ReflectedMass(v0, true); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0PtDetJetPtLambda0PtLambda0Reflection"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), reflectedMass, weight); - registry.fill(HIST("matching/jets/V0/partJetPtLambda0TrackProjDetJetPtLambda0TrackProjLambda0Reflection"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), reflectedMass, weight); - } else if (particle.pdgCode() == -3122) { // AntiLambda - registry.fill(HIST("matching/jets/V0/matchDetJetPtAntiLambda0TrackProjPartJetPtAntiLambda0TrackProj"), detJet.pt(), detTrackProj, partJet.pt(), partTrackProj, weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0Pt"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), weight); - - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtCtauLambda0"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauLambda, weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtCtauAntiLambda0"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauAntiLambda, weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtCtauK0S"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), ctauK0s, weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtMassLambda0"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtMassAntiLambda0"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtMassK0S"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtAllMasses"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtRadius"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.v0radius(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtCosPA"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.v0cosPA(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtDCAposneg"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtDCAd"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.dcaV0daughters(), weight); - - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjCtauLambda0"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauLambda, weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjCtauAntiLambda0"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauAntiLambda, weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjCtauK0S"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, ctauK0s, weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjMassLambda0"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjMassAntiLambda0"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjMassK0S"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjAllMasses"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjRadius"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.v0radius(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjCosPA"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.v0cosPA(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjDCAposneg"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.dcapostopv(), v0.dcanegtopv(), weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjDCAd"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.dcaV0daughters(), weight); - - // Reflection - double reflectedMass = ReflectedMass(v0, false); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0PtDetJetPtAntiLambda0PtAntiLambda0Reflection"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), reflectedMass, weight); - registry.fill(HIST("matching/jets/V0/partJetPtAntiLambda0TrackProjDetJetPtAntiLambda0TrackProjAntiLambda0Reflection"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), reflectedMass, weight); - } // AntiLambda - } - - template - void fillMCDHistograms(Jet const& jet, double weight = 1.) - { - registry.fill(HIST("detector-level/jets/detJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi(), weight); - for (const auto& track : jet.template tracks_as()) { - double chargeFrag = -1., trackProj = -1., theta = -1., xi = -1.; - chargeFrag = ChargeFrag(jet, track); - trackProj = TrackProj(jet, track); - theta = Theta(jet, track); - xi = Xi(jet, track); - - registry.fill(HIST("detector-level/jets/detJetPtTrackPt"), jet.pt(), track.pt(), weight); - registry.fill(HIST("detector-level/jets/detJetTrackPtEtaPhi"), track.pt(), track.eta(), track.phi(), weight); - registry.fill(HIST("detector-level/jets/detJetPtFrag"), jet.pt(), chargeFrag, weight); - registry.fill(HIST("detector-level/jets/detJetPtTrackProj"), jet.pt(), trackProj, weight); - registry.fill(HIST("detector-level/jets/detJetPtXi"), jet.pt(), xi, weight); - registry.fill(HIST("detector-level/jets/detJetPtTheta"), jet.pt(), theta, weight); - registry.fill(HIST("detector-level/jets/detJetPtXiTheta"), jet.pt(), xi, theta, weight); - registry.fill(HIST("detector-level/jets/detJetPtZTheta"), jet.pt(), trackProj, theta, weight); - } - } - - template - void fillMCPHistograms(Jet const& jet, double weight = 1.) - { - registry.fill(HIST("particle-level/jets/partJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi(), weight); - for (const auto& track : jet.template tracks_as()) { - double chargeFrag = -1., trackProj = -1., theta = -1., xi = -1.; - chargeFrag = ChargeFrag(jet, track); - trackProj = TrackProj(jet, track); - theta = Theta(jet, track); - xi = Xi(jet, track); - - registry.fill(HIST("particle-level/jets/partJetPtTrackPt"), jet.pt(), track.pt(), weight); - registry.fill(HIST("particle-level/jets/partJetTrackPtEtaPhi"), track.pt(), track.eta(), track.phi(), weight); - registry.fill(HIST("particle-level/jets/partJetPtFrag"), jet.pt(), chargeFrag, weight); - registry.fill(HIST("particle-level/jets/partJetPtTrackProj"), jet.pt(), trackProj, weight); - registry.fill(HIST("particle-level/jets/partJetPtXi"), jet.pt(), xi, weight); - registry.fill(HIST("particle-level/jets/partJetPtTheta"), jet.pt(), theta, weight); - registry.fill(HIST("particle-level/jets/partJetPtXiTheta"), jet.pt(), xi, theta, weight); - registry.fill(HIST("particle-level/jets/partJetPtZTheta"), jet.pt(), trackProj, theta, weight); - } - } - - void processDummy(JetTracks const&) {} - PROCESS_SWITCH(JetFragmentation, processDummy, "Dummy process function turned on by default", true); - - void processMcD(soa::Filtered::iterator const& collision, - JetMcCollisions const&, - McDJets const&, - JetTracks const& tracks) - { - if (!collision.has_mcCollision()) { - return; - } - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { - return; - } - double nJets = 0, nTracks = 0; - double weight = collision.mcCollision().weight(); - for (const auto& track : tracks) { - if (track.pt() > 0.1) { - nTracks++; - registry.fill(HIST("detector-level/tracks/detTrackPtEtaPhi"), track.pt(), track.eta(), track.phi(), weight); - } - } - for (const auto& jet : detJetEtaPartition) { - nJets++; - fillMCDHistograms(jet, weight); - } - registry.fill(HIST("detector-level/nJetsnTracks"), nJets, nTracks, weight); - } - PROCESS_SWITCH(JetFragmentation, processMcD, "Monte Carlo detector level", false); - - void processMcP(JetMcCollision const& mcCollision, - McPJets const& jets, - JetParticles const& particles) - { - double nJets = 0, nTracks = 0; - double weight = mcCollision.weight(); - for (const auto& particle : particles) { - if (particle.pt() > 0.1) { - nTracks++; - registry.fill(HIST("particle-level/tracks/partTrackPtEtaPhi"), particle.pt(), particle.eta(), particle.phi(), weight); - } - } - for (const auto& jet : jets) { - nJets++; - fillMCPHistograms(jet, weight); - } - registry.fill(HIST("particle-level/nJetsnTracks"), nJets, nTracks, weight); - } - PROCESS_SWITCH(JetFragmentation, processMcP, "Monte Carlo particle level", false); - - void processDataRun3(soa::Filtered::iterator const& collision, - ChargedJetsWithConstituents const& jets, - JetTracks const& tracks) - { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { - return; - } - double nJets = 0, nTracks = 0; - for (const auto& track : tracks) { - if (track.pt() > 0.1) { - nTracks++; - registry.fill(HIST("data/tracks/trackPtEtaPhi"), track.pt(), track.eta(), track.phi()); - } - } - for (const auto& jet : jets) { - if ((jet.eta() <= dataJetEtaMin) || (jet.eta() >= dataJetEtaMax)) { - continue; - } - nJets++; - fillDataRun3Histograms(jet); - } - registry.fill(HIST("data/nJetsnTracks"), nJets, nTracks); - } - PROCESS_SWITCH(JetFragmentation, processDataRun3, "Run 3 Data", false); - - void processMcMatched(soa::Filtered::iterator const& collision, - MatchedMcDJets const&, - JetTracksMCD const&, - JetMcCollisions const&, - MatchedMcPJets const& allMcPartJets, - JetParticles const&) - { - if (!collision.has_mcCollision()) { - return; - } - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { - return; - } - double weight = collision.mcCollision().weight(); - const auto& mcPartJets = allMcPartJets.sliceBy(PartJetsPerCollision, collision.mcCollision().globalIndex()); // Only jets from the same collision - bool isFake = false; - for (const auto& detJet : detJetEtaPartition) { - for (auto& partJet : detJet.template matchedJetGeo_as()) { - fillMatchingHistogramsJet(detJet, partJet, weight); - - for (const auto& track : detJet.tracks_as()) { - bool isTrackMatched = false; - if (!track.has_mcParticle()) { - isFake = true; - fillMatchingFakeOrMiss(detJet, track, isFake, weight); - continue; - } - for (const auto& particle : partJet.tracks_as()) { - if (particle.globalIndex() == track.template mcParticle_as().globalIndex()) { - isTrackMatched = true; - fillMatchingHistogramsConstituent(detJet, partJet, track, particle, weight); - break; // No need to inspect other particles - } // if track has mcParticle and particle is in matched jet - } // for particle in matched partJet - if (!isTrackMatched) { - isFake = true; - fillMatchingFakeOrMiss(detJet, track, isFake, weight); - } // if track is not matched - } // for detJet tracks - } - if (!detJet.has_matchedJetGeo()) { - isFake = true; - registry.fill(HIST("matching/jets/fakeDetJetPtEtaPhi"), detJet.pt(), detJet.eta(), detJet.phi(), weight); - for (const auto& track : detJet.tracks_as()) { - fillMatchingFakeOrMiss(detJet, track, isFake, weight); - } - } // if detJet does not have a match - } // for det jet - for (const auto& partJet : mcPartJets) { - for (const auto& detJet : partJet.template matchedJetGeo_as()) { - // Check if the matched detector level jet is outside the allowed eta range - if ((detJet.eta() <= matchedDetJetEtaMin) || (detJet.eta() >= matchedDetJetEtaMax)) { - for (const auto& particle : partJet.tracks_as()) { - isFake = false; - fillMatchingFakeOrMiss(partJet, particle, isFake, weight); - } - continue; - } - // If the jets are properly matched, we can check the particles - for (const auto& particle : partJet.tracks_as()) { - bool isParticleMatched = false; - for (const auto& track : detJet.tracks_as()) { - if (!track.has_mcParticle()) { - continue; - } - if (particle.globalIndex() == track.template mcParticle_as().globalIndex()) { - isParticleMatched = true; - } - } - // Ignore matched particles. They have been handled in the previous loop - if (!isParticleMatched) { - isFake = false; - fillMatchingFakeOrMiss(partJet, particle, isFake, weight); - } - } // for particle - } // for matched det jet - if (!partJet.has_matchedJetGeo()) { - isFake = false; - registry.fill(HIST("matching/jets/missPartJetPtEtaPhi"), partJet.pt(), partJet.eta(), partJet.phi(), weight); - for (const auto& particle : partJet.tracks_as()) { - fillMatchingFakeOrMiss(partJet, particle, isFake, weight); - } - } // if no matched jet - } // for part jet - } - PROCESS_SWITCH(JetFragmentation, processMcMatched, "Monte Carlo particle and detector level", false); - - void processMcMatchedV0(soa::Filtered>::iterator const& collision, - aod::McCollisions const&, - soa::Join const& V0s, - soa::Join const& tracks, - aod::McParticles const& mcParticles) - { - if (!collision.has_mcCollision()) { - return; - } - if (!collision.sel8()) { - return; - } - double weight = collision.mcCollision().weight(); - for (const auto& v0 : V0s) { - if (!v0.has_mcParticle()) { - continue; - } - fillMcMatchedV0Histograms(collision, v0, tracks, mcParticles, weight); - } - } - PROCESS_SWITCH(JetFragmentation, processMcMatchedV0, "Monte Carlo V0", false); - - void processMcMatchedV0Frag(soa::Filtered>::iterator const& jcoll, - MatchedMcDJets const&, - JetTracksMCD const&, - soa::Join const& allV0s, - JetMcCollisions const&, - MatchedMcPJets const& allMcPartJets, - JetParticles const&, - aod::McCollisions const&, - aod::McParticles const& allMcParticles, - aod::Collisions const&) - { - if (!jcoll.has_mcCollision()) { - return; - } - if (!jetderiveddatautilities::selectCollision(jcoll, eventSelection)) { - return; - } - double weight = jcoll.mcCollision().weight(); - // This is necessary, because jets are linked to JetCollisions, but V0s are linked to Collisions - const auto& collision = jcoll.collision_as(); - const auto& v0s = allV0s.sliceBy(V0sPerCollision, collision.globalIndex()); - const auto& mcPartJets = allMcPartJets.sliceBy(PartJetsPerCollision, jcoll.mcCollision().globalIndex()); - const auto& mcParticles = allMcParticles.sliceBy(ParticlesPerCollision, jcoll.mcCollision().globalIndex()); - - int kNV0s = v0s.size(); - bool isV0Used[kNV0s]; - for (int i = 0; i < kNV0s; i++) { - isV0Used[i] = false; - } - registry.fill(HIST("matching/V0/nV0sEvent"), kNV0s); - - int kNParticles = mcParticles.size(); - bool isParticleUsed[kNParticles]; - for (int i = 0; i < kNParticles; i++) { - isParticleUsed[i] = false; - } - - for (const auto& detJet : detJetEtaV0Partition) { - int iv0 = -1; - int nV0inJet = 0, nLambdainJet = 0, nAntiLambdainJet = 0, nK0SinJet = 0; - - for (auto& partJet : detJet.template matchedJetGeo_as()) { - fillMatchingHistogramsJet(detJet, partJet, weight); - // Jets are pt-sorted, so we prioritise matching V0s with high pt jets - for (const auto& v0 : v0s) { - iv0++; - if (isV0Used[iv0]) { - continue; - } - double dR = jetutilities::deltaR(detJet, v0); - if (dR >= detJet.r() * 1e-2) { - continue; - } - isV0Used[iv0] = true; - if (!v0.has_mcParticle()) { - fillMatchingV0Fake(collision, detJet, v0, weight); - continue; - } - const auto& particle = v0.template mcParticle_as(); - if (!((particle.pdgCode() == 310) || (particle.pdgCode() == 3122) || (particle.pdgCode() == -3122))) { - fillMatchingV0Fake(collision, detJet, v0, weight); - continue; - } - // Found a matched V0 in the jet - // TODO: How to count nK0SinJet, nLambdainJet, nAntiLambdainJet? Use pdg or v0 identification? - nV0inJet++; - fillMatchingHistogramsV0(collision, detJet, partJet, v0, particle, weight); - } // v0 loop - registry.fill(HIST("matching/jets/V0/jetPtnV0Matched"), detJet.pt(), nV0inJet, weight); - registry.fill(HIST("matching/jets/V0/jetPtnV0MatchednK0SnLambdanAntiLambda"), detJet.pt(), nV0inJet, nK0SinJet, nLambdainJet, nAntiLambdainJet, weight); - } // for partJet in matched detJet - iv0 = -1; - if (!detJet.has_matchedJetGeo()) { - for (const auto& v0 : v0s) { - iv0++; - if (isV0Used[iv0]) { - continue; - } - double dR = jetutilities::deltaR(detJet, v0); - if (dR >= detJet.r() * 1e-2) { - continue; - } - isV0Used[iv0] = true; - fillMatchingV0Fake(collision, detJet, v0, weight); - } // v0 loop - } // if no matched jet - } // det jet loop - for (const auto& partJet : mcPartJets) { - int iparticle = -1; - for (const auto& particle : mcParticles) { - iparticle++; - if (isParticleUsed[iparticle]) { - continue; - } - // Check if particle is primary and is a particle of interest that has not been used yet - // If it doesn't pass these selections, set isParticleUsed to true to skip it in the future - if (!particle.isPhysicalPrimary()) { - isParticleUsed[iparticle] = true; - continue; - } - if (!((particle.pdgCode() == 310) || (particle.pdgCode() == 3122) || (particle.pdgCode() == -3122))) { - isParticleUsed[iparticle] = true; - continue; - } - // If the particle has been used or it is not a particle of interest, skip it - if (isParticleUsed[iparticle]) { - continue; - } - if (jetutilities::deltaR(partJet, particle) >= partJet.r() * 1e-2) { - continue; - } - // Particle may be a miss, but we need to check if it is matched with a V0 in a detector level jet - // If it is, it has been treated in the loop over detector level jets above - if (!partJet.has_matchedJetGeo()) { - isParticleUsed[iparticle] = true; - fillMatchingV0Miss(partJet, particle, weight); - continue; - } - for (const auto& detJet : partJet.template matchedJetGeo_as()) { - if ((detJet.eta() <= v0EtaMin + detJet.r() * 1e-2) || (detJet.eta() >= v0EtaMax - detJet.r() * 1e-2)) { - continue; - } - for (const auto& v0 : v0s) { - if (!v0.has_mcParticle()) { - continue; - } - if (v0.template mcParticle_as().globalIndex() == particle.globalIndex()) { - if (jetutilities::deltaR(detJet, v0) < detJet.r() * 1e-2) { - // The particle is matched with a V0 and we ignore it - isParticleUsed[iparticle] = true; - } - } - } // v0 loop - } // detJet loop - if (!isParticleUsed[iparticle]) { - isParticleUsed[iparticle] = true; - fillMatchingV0Miss(partJet, particle, weight); - } - } // particle loop - } // part jet loop - } - PROCESS_SWITCH(JetFragmentation, processMcMatchedV0Frag, "Monte Carlo V0 fragmentation", false); - - void processDataV0(soa::Filtered>::iterator const& collision, - aod::V0Datas const& V0s, - MyTracks const& tracks) - { - if (!collision.sel8()) { - return; - } - registry.fill(HIST("data/V0/nV0sEvent"), V0s.size()); - fillDataV0Histograms(collision, V0s, tracks); - } - PROCESS_SWITCH(JetFragmentation, processDataV0, "Data V0", false); - - void processDataV0Frag(soa::Filtered>::iterator const& jcoll, - ChargedJetsWithConstituents const& jets, - JetTracks const&, - aod::Collisions const&, - aod::V0Datas const& allV0s, - MyTracks const& allTracks) - { - if (!jetderiveddatautilities::selectCollision(jcoll, eventSelection)) { - return; - } - // This is necessary, because jets are linked to JetCollisions, but V0s are linked to Collisions - const auto& collision = jcoll.collision_as(); - const auto& tracks = allTracks.sliceBy(TracksPerCollision, collision.globalIndex()); // Will use in future - const auto& v0s = allV0s.sliceBy(V0sPerCollision, collision.globalIndex()); - - int kNV0s = v0s.size(); - bool isV0Used[kNV0s]; - for (int i = 0; i < kNV0s; i++) { - isV0Used[i] = false; - } - registry.fill(HIST("data/V0/nV0sEvent"), kNV0s); - - fillDataV0Histograms(collision, v0s, tracks); - for (const auto& jet : jets) { - if ((jet.eta() < v0EtaMin + jet.r() * 1e-2) || (jet.eta() > v0EtaMax - jet.r() * 1e-2)) { - continue; - } - fillDataRun3Histograms(jet); - // fastjet::PseudoJet newjet(jet.px(), jet.py(), jet.pz(), jet.e()); // Jet with corrections from V0 - int iv0 = -1; - int nV0inJet = 0, nLambdainJet = 0, nAntiLambdainJet = 0, nK0SinJet = 0; - - // Jets are pt-sorted, so we prioritise matching V0s with high pt jets - // Correct jet momentum (currently only corrects for v0 in jet, not v0 outside jet, is this an issue?) - // for (const auto& v0 : v0s) { - // iv0++; - // if (isV0Used[iv0]) { - // continue; - // } - // double dR = jetutilities::deltaR(jet, v0); - // if (dR < jet.r() * 1e-2) { - // // fastjet::PseudoJet pjv0(v0.px(), v0.py(), v0.pz(), v0.e()); - // // newjet += pjv0; - // } - // } - // Loop over V0s and fill histograms - iv0 = -1; - for (const auto& v0 : v0s) { - iv0++; - if (isV0Used[iv0]) { - continue; - } - double dR = jetutilities::deltaR(jet, v0); - if (dR < jet.r() * 1e-2) { - isV0Used[iv0] = true; - nV0inJet++; - fillDataV0FragHistograms(collision, jet, v0); - if (IsK0SCandidate(collision, v0)) { - nK0SinJet++; - } - if (IsLambdaCandidate(collision, v0)) { - nLambdainJet++; - } - if (IsAntiLambdaCandidate(collision, v0)) { - nAntiLambdainJet++; - } - // double newTrackProj = TrackProj(newjet, v0); // TODO: Does this work? - // registry.fill(HIST("data/jets/V0/jetCorrectedPtV0TrackProj"), newjet.pt(), newTrackProj); - } - } // v0 loop - registry.fill(HIST("data/jets/V0/jetPtnV0"), jet.pt(), nV0inJet); - registry.fill(HIST("data/jets/V0/jetPtnLambda"), jet.pt(), nLambdainJet); - registry.fill(HIST("data/jets/V0/jetPtnAntiLambda"), jet.pt(), nAntiLambdainJet); - registry.fill(HIST("data/jets/V0/jetPtnK0S"), jet.pt(), nK0SinJet); - registry.fill(HIST("data/jets/V0/jetPtnV0nK0SnLambdanAntiLambda"), jet.pt(), nV0inJet, nK0SinJet, nLambdainJet, nAntiLambdainJet); - - // registry.fill(HIST("data/jets/V0/jetCorrectedPtEtaPhi"), newjet.pt(), newjet.eta(), newjet.phi()); - } - } - PROCESS_SWITCH(JetFragmentation, processDataV0Frag, "Data V0 fragmentation", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"jet-fragmentation"})}; -} diff --git a/PWGJE/Tasks/jetsubstructure.cxx b/PWGJE/Tasks/jetsubstructure.cxx deleted file mode 100644 index c706352f5f7..00000000000 --- a/PWGJE/Tasks/jetsubstructure.cxx +++ /dev/null @@ -1,198 +0,0 @@ -// 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. - -// jet analysis tasks (subscribing to jet finder task) -// -/// \author Nima Zardoshti -// - -#include "fastjet/PseudoJet.hh" -#include "fastjet/ClusterSequenceArea.hh" - -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Framework/HistogramRegistry.h" - -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" - -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/DataModel/JetSubstructure.h" -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/Core/FastJetUtilities.h" -#include "PWGJE/Core/JetSubstructureUtilities.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -#include "Framework/runDataProcessing.h" - -struct JetSubstructureTask { - Produces jetSubstructureDataTable; - Produces jetSubstructureMCDTable; - Produces jetSubstructureMCPTable; - Produces jetSubstructureDataSubTable; - - Configurable zCut{"zCut", 0.1, "soft drop z cut"}; - Configurable beta{"beta", 0.0, "soft drop beta"}; - - Service pdg; - std::vector jetConstituents; - std::vector jetReclustered; - JetFinder jetReclusterer; - - std::vector nSub; - - HistogramRegistry registry; - - void init(InitContext const&) - { - registry.add("h2_jet_pt_jet_zg", ";#it{p}_{T,jet} (GeV/#it{c});#it{z}_{g}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); - registry.add("h2_jet_pt_jet_rg", ";#it{p}_{T,jet} (GeV/#it{c});#it{R}_{g}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); - registry.add("h2_jet_pt_jet_nsd", ";#it{p}_{T,jet} (GeV/#it{c});#it{n}_{SD}", {HistType::kTH2F, {{200, 0., 200.}, {15, -0.5, 14.5}}}); - - registry.add("h2_jet_pt_part_jet_zg_part", ";#it{p}_{T,jet}^{part} (GeV/#it{c});#it{z}_{g}^{part}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); - registry.add("h2_jet_pt_part_jet_rg_part", ";#it{p}_{T,jet}^{part} (GeV/#it{c});#it{R}_{g}^{part}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); - registry.add("h2_jet_pt_part_jet_nsd_part", ";#it{p}_{T,jet}^{part} (GeV/#it{c});#it{n}_{SD}^{part}", {HistType::kTH2F, {{200, 0., 200.}, {15, -0.5, 14.5}}}); - - registry.add("h2_jet_pt_jet_zg_eventwiseconstituentsubtracted", ";#it{p}_{T,jet} (GeV/#it{c});#it{z}_{g}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); - registry.add("h2_jet_pt_jet_rg_eventwiseconstituentsubtracted", ";#it{p}_{T,jet} (GeV/#it{c});#it{R}_{g}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); - registry.add("h2_jet_pt_jet_nsd_eventwiseconstituentsubtracted", ";#it{p}_{T,jet} (GeV/#it{c});#it{n}_{SD}", {HistType::kTH2F, {{200, 0., 200.}, {15, -0.5, 14.5}}}); - - jetReclusterer.isReclustering = true; - jetReclusterer.algorithm = fastjet::JetAlgorithm::cambridge_algorithm; - } - - template - void jetReclustering(T const& jet, U& outputTable) - { - jetReclustered.clear(); - fastjet::ClusterSequenceArea clusterSeq(jetReclusterer.findJets(jetConstituents, jetReclustered)); - jetReclustered = sorted_by_pt(jetReclustered); - fastjet::PseudoJet daughterSubJet = jetReclustered[0]; - fastjet::PseudoJet parentSubJet1; - fastjet::PseudoJet parentSubJet2; - bool softDropped = false; - auto nsd = 0.0; - auto zg = -1.0; - auto rg = -1.0; - std::vector energyMotherVec; - std::vector ptLeadingVec; - std::vector ptSubLeadingVec; - std::vector thetaVec; - - while (daughterSubJet.has_parents(parentSubJet1, parentSubJet2)) { - if (parentSubJet1.perp() < parentSubJet2.perp()) { - std::swap(parentSubJet1, parentSubJet2); - } - auto z = parentSubJet2.perp() / (parentSubJet1.perp() + parentSubJet2.perp()); - auto theta = parentSubJet1.delta_R(parentSubJet2); - energyMotherVec.push_back(daughterSubJet.e()); - ptLeadingVec.push_back(parentSubJet1.pt()); - ptSubLeadingVec.push_back(parentSubJet2.pt()); - thetaVec.push_back(theta); - - if (z >= zCut * TMath::Power(theta / (jet.r() / 100.f), beta)) { - if (!softDropped) { - zg = z; - rg = theta; - if constexpr (!isSubtracted && !isMCP) { - registry.fill(HIST("h2_jet_pt_jet_zg"), jet.pt(), zg); - registry.fill(HIST("h2_jet_pt_jet_rg"), jet.pt(), rg); - } - if constexpr (!isSubtracted && isMCP) { - registry.fill(HIST("h2_jet_pt_part_jet_zg_part"), jet.pt(), zg); - registry.fill(HIST("h2_jet_pt_part_jet_rg_part"), jet.pt(), rg); - } - if constexpr (isSubtracted && !isMCP) { - registry.fill(HIST("h2_jet_pt_jet_zg_eventwiseconstituentsubtracted"), jet.pt(), zg); - registry.fill(HIST("h2_jet_pt_jet_rg_eventwiseconstituentsubtracted"), jet.pt(), rg); - } - softDropped = true; - } - nsd++; - } - daughterSubJet = parentSubJet1; - } - if constexpr (!isSubtracted && !isMCP) { - registry.fill(HIST("h2_jet_pt_jet_nsd"), jet.pt(), nsd); - } - if constexpr (!isSubtracted && isMCP) { - registry.fill(HIST("h2_jet_pt_part_jet_nsd_part"), jet.pt(), nsd); - } - if constexpr (isSubtracted && !isMCP) { - registry.fill(HIST("h2_jet_pt_jet_nsd_eventwiseconstituentsubtracted"), jet.pt(), nsd); - } - outputTable(energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec, nSub[0], nSub[1], nSub[2]); - } - - template - void analyseCharged(T const& jet, U const& tracks, V& outputTable) - { - jetConstituents.clear(); - for (auto& jetConstituent : jet.template tracks_as()) { - fastjetutilities::fillTracks(jetConstituent, jetConstituents, jetConstituent.globalIndex()); - } - nSub = jetsubstructureutilities::getNSubjettiness(jet, tracks, tracks, tracks, 2, fastjet::contrib::CA_Axes(), true, zCut, beta); - - jetReclustering(jet, outputTable); - } - - void processDummy(JetTracks const&) - { - } - PROCESS_SWITCH(JetSubstructureTask, processDummy, "Dummy process function turned on by default", true); - - void processChargedJetsData(soa::Join::iterator const& jet, - JetTracks const& tracks) - { - analyseCharged(jet, tracks, jetSubstructureDataTable); - } - PROCESS_SWITCH(JetSubstructureTask, processChargedJetsData, "charged jet substructure", false); - - void processChargedJetsEventWiseSubData(soa::Join::iterator const& jet, - JetTracksSub const& tracks) - { - analyseCharged(jet, tracks, jetSubstructureDataSubTable); - } - PROCESS_SWITCH(JetSubstructureTask, processChargedJetsEventWiseSubData, "eventwise-constituent subtracted charged jet substructure", false); - - void processChargedJetsMCD(typename soa::Join::iterator const& jet, - JetTracks const& tracks) - { - analyseCharged(jet, tracks, jetSubstructureMCDTable); - } - PROCESS_SWITCH(JetSubstructureTask, processChargedJetsMCD, "charged jet substructure", false); - - void processChargedJetsMCP(typename soa::Join::iterator const& jet, - JetParticles const& particles) - { - jetConstituents.clear(); - for (auto& jetConstituent : jet.template tracks_as()) { - fastjetutilities::fillTracks(jetConstituent, jetConstituents, jetConstituent.globalIndex(), static_cast(JetConstituentStatus::track), pdg->Mass(jetConstituent.pdgCode())); - } - nSub = jetsubstructureutilities::getNSubjettiness(jet, particles, particles, particles, 2, fastjet::contrib::CA_Axes(), true, zCut, beta); - jetReclustering(jet, jetSubstructureMCPTable); - } - PROCESS_SWITCH(JetSubstructureTask, processChargedJetsMCP, "charged jet substructure on MC particle level", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - - return WorkflowSpec{adaptAnalysisTask( - cfgc, TaskName{"jet-substructure"})}; -} diff --git a/PWGJE/Tasks/jetsubstructurehf.cxx b/PWGJE/Tasks/jetsubstructurehf.cxx deleted file mode 100644 index 969ddcfb44e..00000000000 --- a/PWGJE/Tasks/jetsubstructurehf.cxx +++ /dev/null @@ -1,241 +0,0 @@ -// 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. - -// heavy-flavour jet substructure task (subscribing to jet finder hf task) -// -/// \author Nima Zardoshti -// - -#include "fastjet/PseudoJet.hh" -#include "fastjet/ClusterSequenceArea.hh" - -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Framework/HistogramRegistry.h" - -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" - -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" - -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/DataModel/JetSubstructure.h" -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/Core/FastJetUtilities.h" -#include "PWGJE/Core/JetSubstructureUtilities.h" -#include "PWGJE/Core/JetHFUtilities.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -// NB: runDataProcessing.h must be included after customize! -#include "Framework/runDataProcessing.h" - -template -struct JetSubstructureHFTask { - Produces jetSubstructureDataTable; - Produces jetSubstructureMCDTable; - Produces jetSubstructureMCPTable; - Produces jetSubstructureDataSubTable; - - // Jet level configurables - Configurable zCut{"zCut", 0.1, "soft drop z cut"}; - Configurable beta{"beta", 0.0, "soft drop beta"}; - - Service pdg; - int candMass; - - std::vector jetConstituents; - std::vector jetReclustered; - JetFinder jetReclusterer; - - std::vector nSub; - - HistogramRegistry registry; - void init(InitContext const&) - { - registry.add("h2_jet_pt_jet_zg", ";#it{p}_{T,jet} (GeV/#it{c});#it{z}_{g}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); - registry.add("h2_jet_pt_jet_rg", ";#it{p}_{T,jet} (GeV/#it{c});#it{R}_{g}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); - registry.add("h2_jet_pt_jet_nsd", ";#it{p}_{T,jet} (GeV/#it{c});#it{n}_{SD}", {HistType::kTH2F, {{200, 0., 200.}, {15, -0.5, 14.5}}}); - - registry.add("h2_jet_pt_part_jet_zg_part", ";#it{p}_{T,jet}^{part} (GeV/#it{c});#it{z}_{g}^{part}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); - registry.add("h2_jet_pt_part_jet_rg_part", ";#it{p}_{T,jet}^{part} (GeV/#it{c});#it{R}_{g}^{part}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); - registry.add("h2_jet_pt_part_jet_nsd_part", ";#it{p}_{T,jet}^{part} (GeV/#it{c});#it{n}_{SD}^{part}", {HistType::kTH2F, {{200, 0., 200.}, {15, -0.5, 14.5}}}); - - registry.add("h2_jet_pt_jet_zg_eventwiseconstituentsubtracted", ";#it{p}_{T,jet} (GeV/#it{c});#it{z}_{g}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); - registry.add("h2_jet_pt_jet_rg_eventwiseconstituentsubtracted", ";#it{p}_{T,jet} (GeV/#it{c});#it{R}_{g}", {HistType::kTH2F, {{200, 0., 200.}, {22, 0.0, 1.1}}}); - registry.add("h2_jet_pt_jet_nsd_eventwiseconstituentsubtracted", ";#it{p}_{T,jet} (GeV/#it{c});#it{n}_{SD}", {HistType::kTH2F, {{200, 0., 200.}, {15, -0.5, 14.5}}}); - - jetReclusterer.isReclustering = true; - jetReclusterer.algorithm = fastjet::JetAlgorithm::cambridge_algorithm; - - candMass = jethfutilities::getTablePDGMass(); - } - - template - void jetReclustering(T const& jet, U& outputTable) - { - jetReclustered.clear(); - fastjet::ClusterSequenceArea clusterSeq(jetReclusterer.findJets(jetConstituents, jetReclustered)); - jetReclustered = sorted_by_pt(jetReclustered); - fastjet::PseudoJet daughterSubJet = jetReclustered[0]; - fastjet::PseudoJet parentSubJet1; - fastjet::PseudoJet parentSubJet2; - bool softDropped = false; - auto nsd = 0.0; - auto zg = -1.0; - auto rg = -1.0; - std::vector energyMotherVec; - std::vector ptLeadingVec; - std::vector ptSubLeadingVec; - std::vector thetaVec; - while (daughterSubJet.has_parents(parentSubJet1, parentSubJet2)) { - - bool isHFInSubjet1 = false; - for (auto& subjet1Constituent : parentSubJet1.constituents()) { - if (subjet1Constituent.template user_info().getStatus() == static_cast(JetConstituentStatus::candidateHF)) { - isHFInSubjet1 = true; - break; - } - } - if (!isHFInSubjet1) { - std::swap(parentSubJet1, parentSubJet2); - } - auto z = parentSubJet2.perp() / (parentSubJet1.perp() + parentSubJet2.perp()); - auto theta = parentSubJet1.delta_R(parentSubJet2); - energyMotherVec.push_back(daughterSubJet.e()); - ptLeadingVec.push_back(parentSubJet1.pt()); - ptSubLeadingVec.push_back(parentSubJet2.pt()); - thetaVec.push_back(theta); - if (z >= zCut * TMath::Power(theta / (jet.r() / 100.f), beta)) { - if (!softDropped) { - zg = z; - rg = theta; - if constexpr (!isSubtracted && !isMCP) { - registry.fill(HIST("h2_jet_pt_jet_zg"), jet.pt(), zg); - registry.fill(HIST("h2_jet_pt_jet_rg"), jet.pt(), rg); - } - if constexpr (!isSubtracted && isMCP) { - registry.fill(HIST("h2_jet_pt_part_jet_zg_part"), jet.pt(), zg); - registry.fill(HIST("h2_jet_pt_part_jet_rg_part"), jet.pt(), rg); - } - if constexpr (isSubtracted && !isMCP) { - registry.fill(HIST("h2_jet_pt_jet_zg_eventwiseconstituentsubtracted"), jet.pt(), zg); - registry.fill(HIST("h2_jet_pt_jet_rg_eventwiseconstituentsubtracted"), jet.pt(), rg); - } - softDropped = true; - } - nsd++; - } - daughterSubJet = parentSubJet1; - } - if constexpr (!isSubtracted && !isMCP) { - registry.fill(HIST("h2_jet_pt_jet_nsd"), jet.pt(), nsd); - } - if constexpr (!isSubtracted && isMCP) { - registry.fill(HIST("h2_jet_pt_part_jet_nsd_part"), jet.pt(), nsd); - } - if constexpr (isSubtracted && !isMCP) { - registry.fill(HIST("h2_jet_pt_jet_nsd_eventwiseconstituentsubtracted"), jet.pt(), nsd); - } - outputTable(energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec, nSub[0], nSub[1], nSub[2]); - } - - template - void analyseCharged(T const& jet, U const& tracks, V const& candidates, M& outputTable) - { - - jetConstituents.clear(); - for (auto& jetConstituent : jet.template tracks_as()) { - fastjetutilities::fillTracks(jetConstituent, jetConstituents, jetConstituent.globalIndex()); - } - for (auto& jetHFCandidate : jet.template hfcandidates_as()) { // should only be one at the moment - fastjetutilities::fillTracks(jetHFCandidate, jetConstituents, jetHFCandidate.globalIndex(), static_cast(JetConstituentStatus::candidateHF), candMass); - } - nSub = jetsubstructureutilities::getNSubjettiness(jet, tracks, tracks, candidates, 2, fastjet::contrib::CA_Axes(), true, zCut, beta); - jetReclustering(jet, outputTable); - } - - void processDummy(JetTracks const&) - { - } - PROCESS_SWITCH(JetSubstructureHFTask, processDummy, "Dummy process function turned on by default", true); - - void processChargedJetsData(typename JetTableData::iterator const& jet, - CandidateTable const& candidates, - JetTracks const& tracks) - { - analyseCharged(jet, tracks, candidates, jetSubstructureDataTable); - } - PROCESS_SWITCH(JetSubstructureHFTask, processChargedJetsData, "HF jet substructure on data", false); - - void processChargedJetsDataSub(typename JetTableDataSub::iterator const& jet, - CandidateTable const& candidates, - TracksSub const& tracks) - { - analyseCharged(jet, tracks, candidates, jetSubstructureDataSubTable); - } - PROCESS_SWITCH(JetSubstructureHFTask, processChargedJetsDataSub, "HF jet substructure on data", false); - - void processChargedJetsMCD(typename JetTableMCD::iterator const& jet, - CandidateTable const& candidates, - JetTracks const& tracks) - { - analyseCharged(jet, tracks, candidates, jetSubstructureMCDTable); - } - PROCESS_SWITCH(JetSubstructureHFTask, processChargedJetsMCD, "HF jet substructure on data", false); - - void processChargedJetsMCP(typename JetTableMCP::iterator const& jet, - JetParticles const& particles, - CandidateTableMCP const& candidates) - { - jetConstituents.clear(); - for (auto& jetConstituent : jet.template tracks_as()) { - fastjetutilities::fillTracks(jetConstituent, jetConstituents, jetConstituent.globalIndex(), static_cast(JetConstituentStatus::track), pdg->Mass(jetConstituent.pdgCode())); - } - for (auto& jetHFCandidate : jet.template hfcandidates_as()) { - fastjetutilities::fillTracks(jetHFCandidate, jetConstituents, jetHFCandidate.globalIndex(), static_cast(JetConstituentStatus::candidateHF), candMass); - } - nSub = jetsubstructureutilities::getNSubjettiness(jet, particles, particles, candidates, 2, fastjet::contrib::CA_Axes(), true, zCut, beta); - jetReclustering(jet, jetSubstructureMCPTable); - } - PROCESS_SWITCH(JetSubstructureHFTask, processChargedJetsMCP, "HF jet substructure on MC particle level", false); -}; -using JetSubstructureD0 = JetSubstructureHFTask, soa::Join, soa::Join, soa::Join, CandidatesD0Data, CandidatesD0MCP, aod::D0CJetSSs, aod::D0CMCDJetSSs, aod::D0CMCPJetSSs, aod::D0CEWSJetSSs, aod::JTrackD0Subs>; -using JetSubstructureLc = JetSubstructureHFTask, soa::Join, soa::Join, soa::Join, CandidatesLcData, CandidatesLcMCP, aod::LcCJetSSs, aod::LcCMCDJetSSs, aod::LcCMCPJetSSs, aod::LcCEWSJetSSs, aod::JTrackLcSubs>; -// using JetSubstructureBplus = JetSubstructureHFTask,soa::Join,soa::Join,soa::Join, CandidatesBplusData, CandidatesBplusMCP, aod::BplusCJetSSs,aod::BplusCMCDJetSSs,aod::BplusCMCPJetSSs, aod::BplusCEWSJetSSs, aod::JTrackBplusSubs>; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - std::vector tasks; - - tasks.emplace_back(adaptAnalysisTask(cfgc, - SetDefaultProcesses{}, - TaskName{"jet-substructure-d0"})); - - tasks.emplace_back(adaptAnalysisTask(cfgc, - SetDefaultProcesses{}, - TaskName{"jet-substructure-lc"})); - /* - - tasks.emplace_back(adaptAnalysisTask(cfgc, - SetDefaultProcesses{}, - TaskName{"jet-substructure-bplus"})); - */ - return WorkflowSpec{tasks}; -} diff --git a/PWGJE/Tasks/jetsubstructurehfoutput.cxx b/PWGJE/Tasks/jetsubstructurehfoutput.cxx deleted file mode 100644 index f6a3531207e..00000000000 --- a/PWGJE/Tasks/jetsubstructurehfoutput.cxx +++ /dev/null @@ -1,386 +0,0 @@ -// 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. - -// heavy-flavour jet substructure tree filling task (subscribing to jet finder hf and jet substructure hf tasks) -// -/// \author Nima Zardoshti -// - -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "TDatabasePDG.h" - -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" - -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" - -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/DataModel/JetSubstructure.h" -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/Core/JetFindingUtilities.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -// NB: runDataProcessing.h must be included after customize! -#include "Framework/runDataProcessing.h" - -template -struct JetSubstructureHFOutputTask { - Produces storedCollisionCountsTable; - Produces collisionOutputTableData; - Produces jetOutputTableData; - Produces jetSubstructureOutputTableData; - Produces jetMatchingOutputTableData; - Produces collisionOutputTableDataSub; - Produces jetOutputTableDataSub; - Produces jetSubstructureOutputTableDataSub; - Produces jetMatchingOutputTableDataSub; - Produces collisionOutputTableMCD; - Produces jetOutputTableMCD; - Produces jetSubstructureOutputTableMCD; - Produces jetMatchingOutputTableMCD; - Produces collisionOutputTableMCP; - Produces jetOutputTableMCP; - Produces jetSubstructureOutputTableMCP; - Produces jetMatchingOutputTableMCP; - Produces hfCollisionsTable; - Produces candidateTable; - Produces candidateParsTable; - Produces candidateParExtrasTable; - Produces candidateSelsTable; - Produces candidateMlsTable; - Produces candidateMcsTable; - Produces hfParticlesTable; - - Configurable jetPtMinData{"jetPtMinData", 0.0, "minimum jet pT cut for data jets"}; - Configurable jetPtMinDataSub{"jetPtMinDataSub", 0.0, "minimum jet pT cut for eventwise constituent subtracted data jets"}; - Configurable jetPtMinMCD{"jetPtMinMCD", 0.0, "minimum jet pT cut for mcd jets"}; - Configurable jetPtMinMCP{"jetPtMinMCP", 0.0, "minimum jet pT cut for mcp jets"}; - Configurable> jetRadii{"jetRadii", std::vector{0.4}, "jet resolution parameters"}; - Configurable jetEtaMin{"jetEtaMin", -99.0, "minimum jet pseudorapidity"}; - Configurable jetEtaMax{"jetEtaMax", 99.0, "maximum jet pseudorapidity"}; - - Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum track pseudorapidity"}; - Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track pseudorapidity"}; - - std::map candidateMapping; - std::map candidateCollisionMapping; - - std::map candidateMappingMCP; - - std::map jetMappingData; - std::map jetMappingDataSub; - std::map jetMappingMCD; - std::map jetMappingMCP; - - std::vector jetRadiiValues; - - void init(InitContext const&) - { - jetRadiiValues = (std::vector)jetRadii; - } - - template - void fillTables(T const& jet, U const& /*cand*/, int32_t collisionIndex, int32_t candidateIndex, V& jetOutputTable, M& jetSubstructureOutputTable, std::map& jetMap) - { - std::vector energyMotherVec; - std::vector ptLeadingVec; - std::vector ptSubLeadingVec; - std::vector thetaVec; - auto energyMotherSpan = jet.energyMother(); - auto ptLeadingSpan = jet.ptLeading(); - auto ptSubLeadingSpan = jet.ptSubLeading(); - auto thetaSpan = jet.theta(); - std::copy(energyMotherSpan.begin(), energyMotherSpan.end(), std::back_inserter(energyMotherVec)); - std::copy(ptLeadingSpan.begin(), ptLeadingSpan.end(), std::back_inserter(ptLeadingVec)); - std::copy(ptSubLeadingSpan.begin(), ptSubLeadingSpan.end(), std::back_inserter(ptSubLeadingVec)); - std::copy(thetaSpan.begin(), thetaSpan.end(), std::back_inserter(thetaVec)); - jetOutputTable(collisionIndex, candidateIndex, jet.pt(), jet.phi(), jet.eta(), jet.y(), jet.r(), jet.tracksIds().size() + jet.hfcandidatesIds().size()); // here we take the decision to keep the collision index consistent with the JE framework in case it is later needed to join to other tables. The candidate Index however can be linked to the HF tables - jetSubstructureOutputTable(jetOutputTable.lastIndex(), energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec, jet.nSub2DR(), jet.nSub1(), jet.nSub2()); - jetMap.insert(std::make_pair(jet.globalIndex(), jetOutputTable.lastIndex())); - } - - template - void analyseCharged(T const& collision, U const& jets, V const& /*candidates*/, M& collisionOutputTable, N& jetOutputTable, O& jetSubstructureOutputTable, std::map& jetMap, std::map& candidateMap, float jetPtMin) - { - - int nJetInCollision = 0; - int32_t collisionIndex = -1; - for (const auto& jet : jets) { - if (jet.pt() < jetPtMin) { - continue; - } - if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { - continue; - } - for (const auto& jetRadiiValue : jetRadiiValues) { - if (jet.r() == round(jetRadiiValue * 100.0f)) { - auto candidate = jet.template hfcandidates_first_as(); - int32_t candidateIndex = -1; - auto candidateTableIndex = candidateMap.find(candidate.globalIndex()); - if (candidateTableIndex != candidateMap.end()) { - candidateIndex = candidateTableIndex->second; - } - if constexpr (!isMCP) { - if (nJetInCollision == 0) { - collisionOutputTable(collision.posZ(), collision.centrality(), collision.eventSel()); - collisionIndex = collisionOutputTable.lastIndex(); - } - nJetInCollision++; - } - fillTables(jet, candidate, collisionIndex, candidateIndex, jetOutputTable, jetSubstructureOutputTable, jetMap); - } - } - } - } - - template - void analyseCandidates(T const& jets, U const& candidateCollisions, V const& candidates, std::map& candidateMap, float jetPtMin) - { - - int nJetInCollision = 0; - int32_t candidateCollisionIndex = -1; - for (const auto& jet : jets) { - if (jet.pt() < jetPtMin) { - continue; - } - if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { - continue; - } - for (const auto& jetRadiiValue : jetRadiiValues) { - if (jet.r() == round(jetRadiiValue * 100.0f)) { - - auto candidate = jet.template hfcandidates_first_as(); - - auto candidateTableIndex = candidateMap.find(candidate.globalIndex()); - if (candidateTableIndex != candidateMap.end()) { - continue; - } - if constexpr (!isMCP) { - auto candidateCollision = jethfutilities::getCandidateCollision(candidate, candidateCollisions); - if (nJetInCollision == 0) { - auto candidateCollisionTableIndex = candidateCollisionMapping.find(candidateCollision.globalIndex()); - if (candidateCollisionTableIndex == candidateCollisionMapping.end()) { - jethfutilities::fillHFCollisionTable(candidateCollision, candidates, hfCollisionsTable, candidateCollisionIndex); - candidateCollisionMapping.insert(std::make_pair(candidateCollision.globalIndex(), candidateCollisionIndex)); - } else { - candidateCollisionIndex = candidateCollisionTableIndex->second; - } - } - nJetInCollision++; - } - int32_t candidateIndex = -1; - if constexpr (isMCP) { - jethfutilities::fillCandidateMcTable(candidate, hfParticlesTable, candidateIndex); - } else { - jethfutilities::fillCandidateTable(candidate, candidateCollisionIndex, candidateTable, candidateParsTable, candidateParExtrasTable, candidateSelsTable, candidateMlsTable, candidateMcsTable, candidateIndex); - } - candidateMap.insert(std::make_pair(candidate.globalIndex(), candidateIndex)); - } - } - } - } - - template - void analyseMatched(T const& jets, U const& /*jetsTag*/, std::map& jetMapping, std::map& jetTagMapping, V& matchingOutputTable, float jetPtMin) - { - for (const auto& jet : jets) { - if (jet.pt() < jetPtMin) { - continue; - } - if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { - continue; - } - for (const auto& jetRadiiValue : jetRadiiValues) { - if (jet.r() == round(jetRadiiValue * 100.0f)) { - std::vector geoMatching; - std::vector ptMatching; - std::vector candMatching; - if (jet.has_matchedJetGeo()) { - for (auto& jetTagId : jet.matchedJetGeoIds()) { - auto jetTagIndex = jetTagMapping.find(jetTagId); - if (jetTagIndex != jetTagMapping.end()) { - geoMatching.push_back(jetTagIndex->second); - } - } - } - if (jet.has_matchedJetPt()) { - for (auto& jetTagId : jet.matchedJetPtIds()) { - auto jetTagIndex = jetTagMapping.find(jetTagId); - if (jetTagIndex != jetTagMapping.end()) { - ptMatching.push_back(jetTagIndex->second); - } - } - } - if (jet.has_matchedJetCand()) { - for (auto& jetTagId : jet.matchedJetCandIds()) { - auto jetTagIndex = jetTagMapping.find(jetTagId); - if (jetTagIndex != jetTagMapping.end()) { - candMatching.push_back(jetTagIndex->second); - } - } - } - int storedJetIndex = -1; - auto jetIndex = jetMapping.find(jet.globalIndex()); - if (jetIndex != jetMapping.end()) { - storedJetIndex = jetIndex->second; - } - matchingOutputTable(storedJetIndex, geoMatching, ptMatching, candMatching); - } - } - } - } - - void processClearMaps(JetCollisions const&) - { - candidateMapping.clear(); - candidateCollisionMapping.clear(); - candidateMappingMCP.clear(); - jetMappingData.clear(); - jetMappingDataSub.clear(); - jetMappingMCD.clear(); - jetMappingMCP.clear(); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processClearMaps, "process function that clears all the maps in each dataframe", true); - - void processCountCollisions(JetCollisions const& collisions, aod::CollisionCounts const& collisionCounts) - { - int readCollisionCounter = 0; - int writtenCollisionCounter = -1; - readCollisionCounter = collisions.size(); - std::vector previousReadCounts = {0}; - std::vector previousWrittenCounts = {0}; - int iPreviousDataFrame = 0; - for (const auto& collisionCount : collisionCounts) { - auto readCollisionCounterSpan = collisionCount.readCounts(); - auto writtenCollisionCounterSpan = collisionCount.writtenCounts(); - if (iPreviousDataFrame == 0) { - std::copy(readCollisionCounterSpan.begin(), readCollisionCounterSpan.end(), std::back_inserter(previousReadCounts)); - std::copy(writtenCollisionCounterSpan.begin(), writtenCollisionCounterSpan.end(), std::back_inserter(previousWrittenCounts)); - } else { - for (unsigned int i = 0; i < previousReadCounts.size(); i++) { - previousReadCounts[i] += readCollisionCounterSpan[i]; - previousWrittenCounts[i] += writtenCollisionCounterSpan[i]; - } - } - iPreviousDataFrame++; - } - previousReadCounts.push_back(readCollisionCounter); - previousWrittenCounts.push_back(writtenCollisionCounter); - storedCollisionCountsTable(previousReadCounts, previousWrittenCounts); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processCountCollisions, "process function that counts read in collisions", false); - - void processOutputCandidatesData(JetCollision const&, - JetTableData const& jets, - CandidateCollisionTable const& canidateCollisions, - CandidateTable const& candidates) - { - analyseCandidates(jets, canidateCollisions, candidates, candidateMapping, jetPtMinData); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCandidatesData, "hf candidate and collision output data", false); - - void processOutputCandidatesDataSub(JetCollision const&, - JetTableDataSub const& jets, - CandidateCollisionTable const& canidateCollisions, - CandidateTable const& candidates) - { - analyseCandidates(jets, canidateCollisions, candidates, candidateMapping, jetPtMinDataSub); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCandidatesDataSub, "hf candidate and collision output data eventwise constituent subtracted", false); - - void processOutputCandidatesMCD(JetCollision const&, - JetTableMCD const& jets, - CandidateCollisionTable const& canidateCollisions, - CandidateTableMCD const& candidates) - { - - analyseCandidates(jets, canidateCollisions, candidates, candidateMapping, jetPtMinMCD); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCandidatesMCD, "hf candidate and collision output MCD", false); - - void processOutputCandidatesMCP(JetMcCollision const&, - JetTableMCP const& jets, - CandidateTableMCP const& candidates) - { - analyseCandidates(jets, candidates, candidates, candidateMappingMCP, jetPtMinMCP); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCandidatesMCP, "hf candidate output MCP", false); - - void processOutputJetsData(JetCollision const& collision, - JetTableData const& jets, - CandidateTable const& candidates) - { - analyseCharged(collision, jets, candidates, collisionOutputTableData, jetOutputTableData, jetSubstructureOutputTableData, jetMappingData, candidateMapping, jetPtMinData); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputJetsData, "hf jet substructure output Data", false); - - void processOutputJetsDataSub(JetCollision const& collision, - JetTableDataSub const& jets, - CandidateTable const& candidates) - { - analyseCharged(collision, jets, candidates, collisionOutputTableDataSub, jetOutputTableDataSub, jetSubstructureOutputTableDataSub, jetMappingDataSub, candidateMapping, jetPtMinDataSub); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputJetsDataSub, "hf jet substructure output event-wise subtracted Data", false); - - void processOutputMatchingData(JetMatchedTableData const& jets, - JetTableDataSub const& jetsSub) - { - analyseMatched(jets, jetsSub, jetMappingData, jetMappingDataSub, jetMatchingOutputTableData, jetPtMinData); - analyseMatched(jetsSub, jets, jetMappingDataSub, jetMappingData, jetMatchingOutputTableDataSub, jetPtMinDataSub); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputMatchingData, "jet matching output Data", false); - - void processOutputJetsMCD(JetCollision const& collision, - JetTableMCD const& jets, - CandidateTableMCD const& candidates) - { - analyseCharged(collision, jets, candidates, collisionOutputTableMCD, jetOutputTableMCD, jetSubstructureOutputTableMCD, jetMappingMCD, candidateMapping, jetPtMinMCD); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputJetsMCD, "hf jet substructure output MCD", false); - - void processOutputJetsMCP(JetMcCollision const& collision, - JetTableMCP const& jets, - CandidateTableMCP const& candidates) - { - analyseCharged(collision, jets, candidates, collisionOutputTableMCP, jetOutputTableMCP, jetSubstructureOutputTableMCP, jetMappingMCP, candidateMappingMCP, jetPtMinMCP); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputJetsMCP, "hf jet substructure output MCP", false); - - void processOutputMatchingMC(JetTableMCD const& jetsMCD, - JetTableMCP const& jetsMCP) - { - analyseMatched(jetsMCD, jetsMCP, jetMappingMCD, jetMappingMCP, jetMatchingOutputTableMCD, jetPtMinMCD); - analyseMatched(jetsMCP, jetsMCD, jetMappingMCP, jetMappingMCD, jetMatchingOutputTableMCP, jetPtMinMCP); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputMatchingMC, "jet matching output MC", false); -}; -using JetSubstructureOutputD0 = JetSubstructureHFOutputTask, soa::Join, aod::D0CJetCOs, aod::D0CJetOs, aod::D0CJetSSOs, aod::D0CJetMOs, soa::Join, aod::D0CMCDJetCOs, aod::D0CMCDJetOs, aod::D0CMCDJetSSOs, aod::D0CMCDJetMOs, soa::Join, aod::D0CMCPJetCOs, aod::D0CMCPJetOs, aod::D0CMCPJetSSOs, aod::D0CMCPJetMOs, soa::Join, aod::D0CEWSJetCOs, aod::D0CEWSJetOs, aod::D0CEWSJetSSOs, aod::D0CEWSJetMOs, aod::StoredHfD0CollBase, aod::StoredHfD0Bases, aod::StoredHfD0Pars, aod::StoredHfD0ParEs, aod::StoredHfD0Sels, aod::StoredHfD0Mls, aod::StoredHfD0Mcs, aod::StoredHfD0PBases, aod::D0CollisionCounts>; -using JetSubstructureOutputLc = JetSubstructureHFOutputTask, soa::Join, aod::LcCJetCOs, aod::LcCJetOs, aod::LcCJetSSOs, aod::LcCJetMOs, soa::Join, aod::LcCMCDJetCOs, aod::LcCMCDJetOs, aod::LcCMCDJetSSOs, aod::LcCMCDJetMOs, soa::Join, aod::LcCMCPJetCOs, aod::LcCMCPJetOs, aod::LcCMCPJetSSOs, aod::LcCMCPJetMOs, soa::Join, aod::LcCEWSJetCOs, aod::LcCEWSJetOs, aod::LcCEWSJetSSOs, aod::LcCEWSJetMOs, aod::StoredHf3PCollBase, aod::StoredHf3PBases, aod::StoredHf3PPars, aod::StoredHf3PParEs, aod::StoredHf3PSels, aod::StoredHf3PMls, aod::StoredHf3PMcs, aod::StoredHf3PPBases, aod::LcCollisionCounts>; -// using JetSubstructureOutputBplus = JetSubstructureHFOutputTask, soa::Join, aod::BplusCJetCOs, aod::BplusCJetOs, aod::BplusCJetSSOs, aod::BplusCJetMOs, soa::Join, aod::BplusCMCDJetCOs, aod::BplusCMCDJetOs, aod::BplusCMCDJetSSOs, aod::BplusCMCDJetMOs, soa::Join, aod::BplusCMCPJetCOs, aod::BplusCMCPJetOs, aod::BplusCMCPJetSSOs, aod::BplusCMCPJetMOs, soa::Join, aod::BplusCEWSJetCOs, aod::BplusCEWSJetOs, aod::BplusCEWSJetSSOs, aod::BplusCEWSJetMOs, aod::StoredHfBplusCollBase, aod::StoredHfBplusBases, aod::StoredHfBplusPars, aod::StoredHfBplusParEs, aod::StoredHfBplusSels, aod::StoredHfBplusMls, aod::StoredHfBplusMcs, aod::StoredHfBplusPBases, aod::BplusCollisionCounts>; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - std::vector tasks; - - tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-substructure-d0-output"})); - tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-substructure-lc-output"})); - // tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-substructure-bplus-output"})); - return WorkflowSpec{tasks}; -} diff --git a/PWGJE/Tasks/jetsubstructureoutput.cxx b/PWGJE/Tasks/jetsubstructureoutput.cxx deleted file mode 100644 index 0879e9db11b..00000000000 --- a/PWGJE/Tasks/jetsubstructureoutput.cxx +++ /dev/null @@ -1,259 +0,0 @@ -// 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. - -// jet substructure tree filling task (subscribing to jet finder hf and jet substructure tasks) -// -/// \author Nima Zardoshti -// - -#include "Framework/ASoA.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "TDatabasePDG.h" - -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" - -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/Core/JetFindingUtilities.h" -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/DataModel/JetSubstructure.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -// NB: runDataProcessing.h must be included after customize! -#include "Framework/runDataProcessing.h" - -struct JetSubstructureOutputTask { - - Produces storedCollisionCountsTable; - Produces collisionOutputTableData; - Produces jetOutputTableData; - Produces jetSubstructureOutputTableData; - Produces jetMatchingOutputTableData; - Produces collisionOutputTableDataSub; - Produces jetOutputTableDataSub; - Produces jetSubstructureOutputTableDataSub; - Produces jetMatchingOutputTableDataSub; - Produces collisionOutputTableMCD; - Produces jetOutputTableMCD; - Produces jetSubstructureOutputTableMCD; - Produces jetMatchingOutputTableMCD; - Produces collisionOutputTableMCP; - Produces jetOutputTableMCP; - Produces jetSubstructureOutputTableMCP; - Produces jetMatchingOutputTableMCP; - - Configurable jetPtMinData{"jetPtMinData", 0.0, "minimum jet pT cut for data jets"}; - Configurable jetPtMinDataSub{"jetPtMinDataSub", 0.0, "minimum jet pT cut for eventwise constituent subtracted data jets"}; - Configurable jetPtMinMCD{"jetPtMinMCD", 0.0, "minimum jet pT cut for mcd jets"}; - Configurable jetPtMinMCP{"jetPtMinMCP", 0.0, "minimum jet pT cut for mcp jets"}; - Configurable> jetRadii{"jetRadii", std::vector{0.4}, "jet resolution parameters"}; - Configurable jetEtaMin{"jetEtaMin", -99.0, "minimum jet pseudorapidity"}; - Configurable jetEtaMax{"jetEtaMax", 99.0, "maximum jet pseudorapidity"}; - - Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum track pseudorapidity"}; - Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track pseudorapidity"}; - - std::map jetMappingData; - std::map jetMappingDataSub; - std::map jetMappingMCD; - std::map jetMappingMCP; - - std::vector jetRadiiValues; - - void init(InitContext const&) - { - jetRadiiValues = (std::vector)jetRadii; - } - - template - void fillTables(T const& jet, int32_t collisionIndex, U& jetOutputTable, V& jetSubstructureOutputTable, std::map& jetMapping) - { - std::vector energyMotherVec; - std::vector ptLeadingVec; - std::vector ptSubLeadingVec; - std::vector thetaVec; - auto energyMotherSpan = jet.energyMother(); - auto ptLeadingSpan = jet.ptLeading(); - auto ptSubLeadingSpan = jet.ptSubLeading(); - auto thetaSpan = jet.theta(); - std::copy(energyMotherSpan.begin(), energyMotherSpan.end(), std::back_inserter(energyMotherVec)); - std::copy(ptLeadingSpan.begin(), ptLeadingSpan.end(), std::back_inserter(ptLeadingVec)); - std::copy(ptSubLeadingSpan.begin(), ptSubLeadingSpan.end(), std::back_inserter(ptSubLeadingVec)); - std::copy(thetaSpan.begin(), thetaSpan.end(), std::back_inserter(thetaVec)); - jetOutputTable(collisionIndex, collisionIndex, jet.pt(), jet.phi(), jet.eta(), jet.y(), jet.r(), jet.tracksIds().size()); // second collision index is a dummy coloumn mirroring the hf candidate - jetSubstructureOutputTable(jetOutputTable.lastIndex(), energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec, jet.nSub2DR(), jet.nSub1(), jet.nSub2()); - jetMapping.insert(std::make_pair(jet.globalIndex(), jetOutputTable.lastIndex())); - } - - template - void analyseCharged(T const& collision, U const& jets, V& collisionOutputTable, M& jetOutputTable, N& jetSubstructureOutputTable, std::map& jetMapping, float jetPtMin) - { - int nJetInCollision = 0; - int32_t collisionIndex = -1; - for (const auto& jet : jets) { - if (jet.pt() < jetPtMin) { - continue; - } - if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { - continue; - } - for (const auto& jetRadiiValue : jetRadiiValues) { - if (jet.r() == round(jetRadiiValue * 100.0f)) { - if constexpr (!isMc) { - if (nJetInCollision == 0) { - collisionOutputTable(collision.posZ(), collision.centrality(), collision.eventSel()); - collisionIndex = collisionOutputTable.lastIndex(); - } - nJetInCollision++; - } - fillTables(jet, collisionIndex, jetOutputTable, jetSubstructureOutputTable, jetMapping); - } - } - } - } - - template - void analyseMatched(T const& jets, U const& /*jetsTag*/, std::map& jetMapping, std::map& jetTagMapping, V& matchingOutputTable, float jetPtMin) - { - std::vector candMatching; - for (const auto& jet : jets) { - if (jet.pt() < jetPtMin) { - continue; - } - if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { - continue; - } - for (const auto& jetRadiiValue : jetRadiiValues) { - if (jet.r() == round(jetRadiiValue * 100.0f)) { - std::vector geoMatching; - std::vector ptMatching; - if (jet.has_matchedJetGeo()) { - for (auto& jetTagId : jet.matchedJetGeoIds()) { - auto jetTagIndex = jetTagMapping.find(jetTagId); - if (jetTagIndex != jetTagMapping.end()) { - geoMatching.push_back(jetTagIndex->second); - } - } - } - if (jet.has_matchedJetPt()) { - for (auto& jetTagId : jet.matchedJetPtIds()) { - auto jetTagIndex = jetTagMapping.find(jetTagId); - if (jetTagIndex != jetTagMapping.end()) { - ptMatching.push_back(jetTagIndex->second); - } - } - } - int storedJetIndex = -1; - auto jetIndex = jetMapping.find(jet.globalIndex()); - if (jetIndex != jetMapping.end()) { - storedJetIndex = jetIndex->second; - } - matchingOutputTable(storedJetIndex, geoMatching, ptMatching, candMatching); - } - } - } - } - - void processClearMaps(JetCollisions const&) - { - jetMappingData.clear(); - jetMappingDataSub.clear(); - jetMappingMCD.clear(); - jetMappingMCP.clear(); - } - PROCESS_SWITCH(JetSubstructureOutputTask, processClearMaps, "process function that clears all the maps in each dataframe", true); - - void processCountCollisions(JetCollisions const& collisions, aod::CollisionCounts const& collisionCounts) - { - int readCollisionCounter = 0; - int writtenCollisionCounter = -1; - readCollisionCounter = collisions.size(); - std::vector previousReadCounts = {0}; - std::vector previousWrittenCounts = {0}; - int iPreviousDataFrame = 0; - for (const auto& collisionCount : collisionCounts) { - auto readCollisionCounterSpan = collisionCount.readCounts(); - auto writtenCollisionCounterSpan = collisionCount.writtenCounts(); - if (iPreviousDataFrame == 0) { - std::copy(readCollisionCounterSpan.begin(), readCollisionCounterSpan.end(), std::back_inserter(previousReadCounts)); - std::copy(writtenCollisionCounterSpan.begin(), writtenCollisionCounterSpan.end(), std::back_inserter(previousWrittenCounts)); - } else { - for (unsigned int i = 0; i < previousReadCounts.size(); i++) { - previousReadCounts[i] += readCollisionCounterSpan[i]; - previousWrittenCounts[i] += writtenCollisionCounterSpan[i]; - } - } - iPreviousDataFrame++; - } - previousReadCounts.push_back(readCollisionCounter); - previousWrittenCounts.push_back(writtenCollisionCounter); - storedCollisionCountsTable(previousReadCounts, previousWrittenCounts); - } - PROCESS_SWITCH(JetSubstructureOutputTask, processCountCollisions, "process function that counts read in collisions", false); - - void processOutputData(JetCollision const& collision, - soa::Join const& jets) - { - analyseCharged(collision, jets, collisionOutputTableData, jetOutputTableData, jetSubstructureOutputTableData, jetMappingData, jetPtMinData); - } - PROCESS_SWITCH(JetSubstructureOutputTask, processOutputData, "jet substructure output Data", false); - - void processOutputDataSub(JetCollision const& collision, - soa::Join const& jets) - { - analyseCharged(collision, jets, collisionOutputTableDataSub, jetOutputTableDataSub, jetSubstructureOutputTableDataSub, jetMappingDataSub, jetPtMinDataSub); - } - PROCESS_SWITCH(JetSubstructureOutputTask, processOutputDataSub, "jet substructure output event-wise subtracted Data", false); - - void processOutputMatchingData(soa::Join const& jets, - soa::Join const& jetsSub) - { - analyseMatched(jets, jetsSub, jetMappingData, jetMappingDataSub, jetMatchingOutputTableData, jetPtMinData); - analyseMatched(jetsSub, jets, jetMappingDataSub, jetMappingData, jetMatchingOutputTableDataSub, jetPtMinDataSub); - } - PROCESS_SWITCH(JetSubstructureOutputTask, processOutputMatchingData, "jet matching output Data", false); - - void processOutputMCD(JetCollision const& collision, - soa::Join const& jets) - { - analyseCharged(collision, jets, collisionOutputTableMCD, jetOutputTableMCD, jetSubstructureOutputTableMCD, jetMappingMCD, jetPtMinMCD); - } - PROCESS_SWITCH(JetSubstructureOutputTask, processOutputMCD, "jet substructure output MCD", false); - - void processOutputMCP(JetMcCollision const& collision, - soa::Join const& jets) - { - analyseCharged(collision, jets, collisionOutputTableMCP, jetOutputTableMCP, jetSubstructureOutputTableMCP, jetMappingMCP, jetPtMinMCP); - } - PROCESS_SWITCH(JetSubstructureOutputTask, processOutputMCP, "jet substructure output MCP", false); - - void processOutputMatchingMC(soa::Join const& jetsMCD, - soa::Join const& jetsMCP) - { - analyseMatched(jetsMCD, jetsMCP, jetMappingMCD, jetMappingMCP, jetMatchingOutputTableMCD, jetPtMinMCD); - analyseMatched(jetsMCP, jetsMCD, jetMappingMCP, jetMappingMCD, jetMatchingOutputTableMCP, jetPtMinMCP); - } - PROCESS_SWITCH(JetSubstructureOutputTask, processOutputMatchingMC, "jet matching output MC", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - - return WorkflowSpec{adaptAnalysisTask( - cfgc, TaskName{"jet-substructure-output"})}; -} diff --git a/PWGJE/Tasks/jettaggerhfQA.cxx b/PWGJE/Tasks/jettaggerhfQA.cxx deleted file mode 100644 index 619f5063991..00000000000 --- a/PWGJE/Tasks/jettaggerhfQA.cxx +++ /dev/null @@ -1,712 +0,0 @@ -// 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 jettaggerhfQA.cxx -/// \brief Jet tagging general QA -/// -/// \author Hanseo Park - -#include "TF1.h" - -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Framework/runDataProcessing.h" -#include "Common/Core/trackUtilities.h" - -#include "PWGHF/DataModel/CandidateReconstructionTables.h" - -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/DataModel/JetTagging.h" -#include "PWGJE/Core/JetFindingUtilities.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" -#include "PWGJE/Core/JetUtilities.h" -#include "PWGJE/Core/JetTaggingUtilities.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -template -struct JetTaggerHFQA { - - // Cut configuration - Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; - Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum eta acceptance for tracks"}; - Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum eta acceptance for tracks"}; - Configurable trackPtMin{"trackPtMin", 0.15, "minimum pT acceptance for tracks"}; - Configurable trackPtMax{"trackPtMax", 100.0, "maximum pT acceptance for tracks"}; - Configurable jetEtaMin{"jetEtaMin", -99.0, "minimum jet pseudorapidity"}; - Configurable jetEtaMax{"jetEtaMax", 99.0, "maximum jet pseudorapidity"}; - Configurable prong2LxySigmaMax{"prong2LxySigmaMax", 0.03, "maximum sigma of decay length of 2-prong on xy plane"}; - Configurable prong2SxyMin{"prong2SxyMin", 7, "minimum decay length significance of 2-prong on xy plane"}; - Configurable prong2LxyzSigmaMax{"prong2LxyzSigmazMax", 0.03, "maximum sigma of decay length of 2-prong on xyz plane"}; - Configurable prong2SxyzMin{"prong2SxyzMin", 7, "minimum decay length significance of 2-prong on xyz plane"}; - Configurable prong3LxySigmaMax{"prong3LxySigmaMax", 0.03, "maximum sigma of decay length of 3-prong on xy plane"}; - Configurable prong3SxyMin{"prong3SxyMin", 7, "minimum decay length significance of 3-prong on xy plane"}; - Configurable prong3LxyzSigmaMax{"prong3LxyzSigmazMax", 0.03, "maximum sigma of decay length of 3-prong on xyz plane"}; - Configurable prong3SxyzMin{"prong3SxyzMin", 7, "minimum decay length significance of 3-prong on xyz plane"}; - Configurable numFlavourSpecies{"numFlavourSpecies", 6, "number of jet flavour species"}; - Configurable numOrder{"numOrder", 6, "number of ordering"}; - - Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; - // Binning - ConfigurableAxis binJetFlavour{"binJetFlavour", {6, -0.5, 5.5}, ""}; - ConfigurableAxis binJetPt{"binJetPt", {200, 0., 200.}, ""}; - ConfigurableAxis binEta{"binEta", {100, -1.f, 1.f}, ""}; - ConfigurableAxis binPhi{"binPhi", {18 * 8, 0.f, 2. * TMath::Pi()}, ""}; - ConfigurableAxis binNtracks{"binNtracks", {100, 0., 100.}, ""}; - ConfigurableAxis binTrackPt{"binTrackPt", {200, 0.f, 100.f}, ""}; - ConfigurableAxis binImpactParameterXY{"binImpactParameterXY", {800, -400.5f, 400.5f}, ""}; - ConfigurableAxis binImpactParameterXYSignificance{"binImpactParameterXYSignificance", {800, -40.5f, 40.5f}, ""}; - ConfigurableAxis binImpactParameterZ{"binImpactParameterZ", {800, -400.5f, 400.5f}, ""}; - ConfigurableAxis binImpactParameterZSignificance{"binImpactParameterZSignificance", {800, -40.5f, 40.5f}, ""}; - ConfigurableAxis binImpactParameterXYZ{"binImpactParameterXYZ", {2000, -1000.5f, 1000.5f}, ""}; - ConfigurableAxis binImpactParameterXYZSignificance{"binImpactParameterXYZSignificance", {2000, -100.5f, 100.5f}, ""}; - ConfigurableAxis binNumOrder{"binNumOrder", {6, 0.5, 6.5}, ""}; - ConfigurableAxis binJetProbability{"binJetProbability", {100, 0.f, 1.f}, ""}; - ConfigurableAxis binJetProbabilityLog{"binJetProbabilityLog", {100, 0.f, 10.f}, ""}; - ConfigurableAxis binNprongs{"binNprongs", {100, 0., 100.}, ""}; - ConfigurableAxis binLxy{"binLxy", {200, 0, 20.f}, ""}; - ConfigurableAxis binSxy{"binSxy", {200, 0, 200.f}, ""}; - ConfigurableAxis binLxyz{"binLxyz", {200, 0, 20.f}, ""}; - ConfigurableAxis binSxyz{"binSxyz", {200, 0, 200.f}, ""}; - ConfigurableAxis binSigmaLxy{"binSigmaLxy", {100, 0., 0.1}, ""}; - ConfigurableAxis binSigmaLxyz{"binSigmaLxyz", {100, 0., 0.1}, ""}; - - int numberOfJetFlavourSpecies = 6; - int trackSelection = -1; - - HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; - - void init(InitContext const&) - { - - // Axis - AxisSpec jetFlavourAxis = {binJetFlavour, "Jet flavour"}; - AxisSpec jetPtAxis = {binJetPt, "#it{p}_{T, jet}"}; - AxisSpec etaAxis = {binEta, "#eta"}; - AxisSpec phiAxis = {binPhi, "#phi"}; - AxisSpec ntracksAxis = {binNtracks, "#it{N}_{tracks}"}; - AxisSpec trackPtAxis = {binTrackPt, "#it{p}_{T}^{track}"}; - AxisSpec impactParameterXYAxis = {binImpactParameterXY, "IP_{XY} [#mum]"}; - AxisSpec impactParameterXYSignificanceAxis = {binImpactParameterXYSignificance, "IPs_{XY}"}; - AxisSpec impactParameterZAxis = {binImpactParameterZ, "IP_{Z} [#mum]"}; - AxisSpec impactParameterZSignificanceAxis = {binImpactParameterZSignificance, "IPs_{Z}"}; - AxisSpec impactParameterXYZAxis = {binImpactParameterXYZ, "IP_{XYZ} [#mum]"}; - AxisSpec impactParameterXYZSignificanceAxis = {binImpactParameterXYZSignificance, "IPs_{XYZ}"}; - AxisSpec numOrderAxis = {binNumOrder, "N_{order}"}; - AxisSpec JetProbabilityAxis = {binJetProbability, "JP"}; - AxisSpec JetProbabilityLogAxis = {binJetProbabilityLog, "-Log(JP)"}; - AxisSpec nprongsAxis = {binNprongs, "#it{N}_{SV}"}; - AxisSpec LxyAxis = {binLxy, "L_{XY} [cm]"}; - AxisSpec SxyAxis = {binSxy, "S_{XY}"}; - AxisSpec LxyzAxis = {binLxyz, "L_{XYZ} [cm]"}; - AxisSpec SxyzAxis = {binSxyz, "S_{XYZ}"}; - AxisSpec sigmaLxyAxis = {binSigmaLxy, "#simga_{L_{XY}} [cm]"}; - AxisSpec sigmaLxyzAxis = {binSigmaLxyz, "#simga_{L_{XYZ}} [cm]"}; - - numberOfJetFlavourSpecies = static_cast(numFlavourSpecies); - - trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); - if (doprocessTracksDca) { - registry.add("h_impact_parameter_xy", "", {HistType::kTH1F, {{impactParameterXYAxis}}}); - registry.add("h_impact_parameter_xy_significance", "", {HistType::kTH1F, {{impactParameterXYSignificanceAxis}}}); - registry.add("h_impact_parameter_z", "", {HistType::kTH1F, {{impactParameterZAxis}}}); - registry.add("h_impact_parameter_z_significance", "", {HistType::kTH1F, {{impactParameterZSignificanceAxis}}}); - registry.add("h_impact_parameter_xyz", "", {HistType::kTH1F, {{impactParameterXYZAxis}}}); - registry.add("h_impact_parameter_xyz_significance", "", {HistType::kTH1F, {{impactParameterXYZSignificanceAxis}}}); - } - if (doprocessIPsData) { - registry.add("h3_jet_pt_track_pt_track_eta", "", {HistType::kTH3F, {{jetPtAxis}, {trackPtAxis}, {etaAxis}}}); - registry.add("h3_jet_pt_track_pt_track_phi", "", {HistType::kTH3F, {{jetPtAxis}, {trackPtAxis}, {phiAxis}}}); - registry.add("h2_jet_pt_impact_parameter_xy", "", {HistType::kTH2F, {{jetPtAxis}, {impactParameterXYAxis}}}); - registry.add("h2_jet_pt_sign_impact_parameter_xy", "", {HistType::kTH2F, {{jetPtAxis}, {impactParameterXYAxis}}}); - registry.add("h2_jet_pt_impact_parameter_xy_significance", "", {HistType::kTH2F, {{jetPtAxis}, {impactParameterXYSignificanceAxis}}}); - registry.add("h3_jet_pt_track_pt_sign_impact_parameter_xy_significance", "", {HistType::kTH3F, {{jetPtAxis}, {trackPtAxis}, {impactParameterXYSignificanceAxis}}}); - registry.add("h2_jet_pt_impact_parameter_z", "", {HistType::kTH2F, {{jetPtAxis}, {impactParameterZAxis}}}); - registry.add("h2_jet_pt_sign_impact_parameter_z", "", {HistType::kTH2F, {{jetPtAxis}, {impactParameterZAxis}}}); - registry.add("h2_jet_pt_impact_parameter_z_significance", "", {HistType::kTH2F, {{jetPtAxis}, {impactParameterZSignificanceAxis}}}); - registry.add("h3_jet_pt_track_pt_sign_impact_parameter_z_significance", "", {HistType::kTH3F, {{jetPtAxis}, {trackPtAxis}, {impactParameterZSignificanceAxis}}}); - registry.add("h2_jet_pt_impact_parameter_xyz", "", {HistType::kTH2F, {{jetPtAxis}, {impactParameterXYZAxis}}}); - registry.add("h2_jet_pt_sign_impact_parameter_xyz", "", {HistType::kTH2F, {{jetPtAxis}, {impactParameterXYZAxis}}}); - registry.add("h2_jet_pt_impact_parameter_xyz_significance", "", {HistType::kTH2F, {{jetPtAxis}, {impactParameterXYZSignificanceAxis}}}); - registry.add("h3_jet_pt_track_pt_sign_impact_parameter_xyz_significance", "", {HistType::kTH3F, {{jetPtAxis}, {trackPtAxis}, {impactParameterXYZSignificanceAxis}}}); - - // TC - registry.add("h3_jet_pt_sign_impact_parameter_xy_significance_tc", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterXYSignificanceAxis}, {numOrderAxis}}}); - registry.add("h3_jet_pt_sign_impact_parameter_z_significance_tc", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterZSignificanceAxis}, {numOrderAxis}}}); - registry.add("h3_jet_pt_sign_impact_parameter_xyz_significance_tc", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterXYZSignificanceAxis}, {numOrderAxis}}}); - registry.add("h3_track_pt_sign_impact_parameter_xy_significance_tc", "", {HistType::kTH3F, {{trackPtAxis}, {impactParameterXYSignificanceAxis}, {numOrderAxis}}}); - registry.add("h3_track_pt_sign_impact_parameter_z_significance_tc", "", {HistType::kTH3F, {{trackPtAxis}, {impactParameterZSignificanceAxis}, {numOrderAxis}}}); - registry.add("h3_track_pt_sign_impact_parameter_xyz_significance_tc", "", {HistType::kTH3F, {{trackPtAxis}, {impactParameterXYZSignificanceAxis}, {numOrderAxis}}}); - } - if (doprocessIPsMCD) { - registry.add("h2_jet_pt_flavour", "", {HistType::kTH2F, {{jetPtAxis}, {jetFlavourAxis}}}); - registry.add("h2_jet_eta_flavour", "", {HistType::kTH2F, {{etaAxis}, {jetFlavourAxis}}}); - registry.add("h2_jet_phi_flavour", "", {HistType::kTH2F, {{phiAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_track_pt_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {trackPtAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_track_eta_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {etaAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_track_phi_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {phiAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_impact_parameter_xy_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterXYAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_sign_impact_parameter_xy_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterXYAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_impact_parameter_xy_significance_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterXYSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_sign_impact_parameter_xy_significance_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterXYSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_impact_parameter_z_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterZAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_sign_impact_parameter_z_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterZAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_impact_parameter_z_significance_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterZSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_sign_impact_parameter_z_significance_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterZSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_impact_parameter_xyz_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterXYZAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_sign_impact_parameter_xyz_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterXYZAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_impact_parameter_xyz_significance_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterXYZSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_sign_impact_parameter_xyz_significance_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterXYZSignificanceAxis}, {jetFlavourAxis}}}); - - registry.add("h3_track_pt_impact_parameter_xy_flavour", "", {HistType::kTH3F, {{trackPtAxis}, {impactParameterXYAxis}, {jetFlavourAxis}}}); - registry.add("h3_track_pt_sign_impact_parameter_xy_flavour", "", {HistType::kTH3F, {{trackPtAxis}, {impactParameterXYAxis}, {jetFlavourAxis}}}); - registry.add("h3_track_pt_impact_parameter_xy_significance_flavour", "", {HistType::kTH3F, {{trackPtAxis}, {impactParameterXYSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_track_pt_sign_impact_parameter_xy_significance_flavour", "", {HistType::kTH3F, {{trackPtAxis}, {impactParameterXYSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_track_pt_impact_parameter_z_flavour", "", {HistType::kTH3F, {{trackPtAxis}, {impactParameterZAxis}, {jetFlavourAxis}}}); - registry.add("h3_track_pt_sign_impact_parameter_z_flavour", "", {HistType::kTH3F, {{trackPtAxis}, {impactParameterZAxis}, {jetFlavourAxis}}}); - registry.add("h3_track_pt_impact_parameter_z_significance_flavour", "", {HistType::kTH3F, {{trackPtAxis}, {impactParameterZSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_track_pt_sign_impact_parameter_z_significance_flavour", "", {HistType::kTH3F, {{trackPtAxis}, {impactParameterZSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_track_pt_impact_parameter_xyz_flavour", "", {HistType::kTH3F, {{trackPtAxis}, {impactParameterXYZAxis}, {jetFlavourAxis}}}); - registry.add("h3_track_pt_sign_impact_parameter_xyz_flavour", "", {HistType::kTH3F, {{trackPtAxis}, {impactParameterXYZAxis}, {jetFlavourAxis}}}); - registry.add("h3_track_pt_impact_parameter_xyz_significance_flavour", "", {HistType::kTH3F, {{trackPtAxis}, {impactParameterXYZSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_track_pt_sign_impact_parameter_xyz_significance_flavour", "", {HistType::kTH3F, {{trackPtAxis}, {impactParameterXYZSignificanceAxis}, {jetFlavourAxis}}}); - - // TC - registry.add("h3_jet_pt_sign_impact_parameter_xy_significance_flavour_N1", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterXYSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_sign_impact_parameter_xy_significance_flavour_N2", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterXYSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_sign_impact_parameter_xy_significance_flavour_N3", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterXYSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_sign_impact_parameter_z_significance_flavour_N1", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterZSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_sign_impact_parameter_z_significance_flavour_N2", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterZSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_sign_impact_parameter_z_significance_flavour_N3", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterZSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_sign_impact_parameter_xyz_significance_flavour_N1", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterXYZSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_sign_impact_parameter_xyz_significance_flavour_N2", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterXYZSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_sign_impact_parameter_xyz_significance_flavour_N3", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterXYZSignificanceAxis}, {jetFlavourAxis}}}); - registry.add("h3_sign_impact_parameter_xy_significance_tc_flavour", "", {HistType::kTH3F, {{impactParameterXYSignificanceAxis}, {numOrderAxis}, {jetFlavourAxis}}}); - registry.add("h3_sign_impact_parameter_z_significance_tc_flavour", "", {HistType::kTH3F, {{impactParameterZSignificanceAxis}, {numOrderAxis}, {jetFlavourAxis}}}); - registry.add("h3_sign_impact_parameter_xyz_significance_tc_flavour", "", {HistType::kTH3F, {{impactParameterXYZSignificanceAxis}, {numOrderAxis}, {jetFlavourAxis}}}); - } - if (doprocessJPData) { - registry.add("h2_jet_pt_JP", "jet pt jet probability untagged", {HistType::kTH2F, {{jetPtAxis}, {JetProbabilityAxis}}}); - registry.add("h2_jet_pt_neg_log_JP", "jet pt jet probabilityun tagged", {HistType::kTH2F, {{jetPtAxis}, {JetProbabilityLogAxis}}}); - registry.add("h2_jet_pt_JP_N1", "jet pt jet probability N1", {HistType::kTH2F, {{jetPtAxis}, {JetProbabilityAxis}}}); - registry.add("h2_jet_pt_neg_log_JP_N1", "jet pt jet probabilityun N1", {HistType::kTH2F, {{jetPtAxis}, {JetProbabilityLogAxis}}}); - registry.add("h2_jet_pt_JP_N2", "jet pt jet probability N2", {HistType::kTH2F, {{jetPtAxis}, {JetProbabilityAxis}}}); - registry.add("h2_jet_pt_neg_log_JP_N2", "jet pt jet probabilityun N2", {HistType::kTH2F, {{jetPtAxis}, {JetProbabilityLogAxis}}}); - registry.add("h2_jet_pt_JP_N3", "jet pt jet probability N3", {HistType::kTH2F, {{jetPtAxis}, {JetProbabilityAxis}}}); - registry.add("h2_jet_pt_neg_log_JP_N3", "jet pt jet probabilityun N3", {HistType::kTH2F, {{jetPtAxis}, {JetProbabilityLogAxis}}}); - } - if (doprocessJPMCD) { - registry.add("h3_jet_pt_JP_flavour", "jet pt jet probability flavour untagged", {HistType::kTH3F, {{jetPtAxis}, {JetProbabilityAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_neg_log_JP_flavour", "jet pt log jet probability flavour untagged", {HistType::kTH3F, {{jetPtAxis}, {JetProbabilityLogAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_JP_N1_flavour", "jet pt jet probability flavour N1", {HistType::kTH3F, {{jetPtAxis}, {JetProbabilityAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_neg_log_JP_N1_flavour", "jet pt log jet probability flavour N1", {HistType::kTH3F, {{jetPtAxis}, {JetProbabilityLogAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_JP_N2_flavour", "jet pt jet probability flavour N2", {HistType::kTH3F, {{jetPtAxis}, {JetProbabilityAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_neg_log_JP_N2_flavour", "jet pt log jet probability flavour N2", {HistType::kTH3F, {{jetPtAxis}, {JetProbabilityLogAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_JP_N3_flavour", "jet pt jet probability flavour N3", {HistType::kTH3F, {{jetPtAxis}, {JetProbabilityAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_neg_log_JP_N3_flavour", "jet pt log jet probability flavour N3", {HistType::kTH3F, {{jetPtAxis}, {JetProbabilityLogAxis}, {jetFlavourAxis}}}); - } - if (doprocessSV2ProngMCD) { - registry.add("h_2prong_nprongs", "", {HistType::kTH1F, {{nprongsAxis}}}); - registry.add("h3_jet_pt_2prong_Lxy_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {LxyAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_2prong_Sxy_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {SxyAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_2prong_Lxyz_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {LxyzAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_2prong_Sxyz_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {SxyzAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_2prong_Sxy_flavour_N1", "", {HistType::kTH3F, {{jetPtAxis}, {SxyAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_2prong_Sxyz_flavour_N1", "", {HistType::kTH3F, {{jetPtAxis}, {SxyzAxis}, {jetFlavourAxis}}}); - registry.add("h3_2prong_Sxy_sigmaLxy_flavour", "", {HistType::kTH3F, {{SxyAxis}, {sigmaLxyAxis}, {jetFlavourAxis}}}); - registry.add("h3_2prong_Sxyz_sigmaLxyz_flavour", "", {HistType::kTH3F, {{SxyzAxis}, {sigmaLxyzAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_2prong_sigmaLxy_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {sigmaLxyAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_2prong_sigmaLxyz_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {sigmaLxyzAxis}, {jetFlavourAxis}}}); - } - if (doprocessSV3ProngMCD) { - registry.add("h_3prong_nprongs", "", {HistType::kTH1F, {{nprongsAxis}}}); - registry.add("h3_jet_pt_3prong_Lxy_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {LxyAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_3prong_Sxy_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {SxyAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_3prong_Lxyz_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {LxyzAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_3prong_Sxyz_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {SxyzAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_3prong_Sxy_flavour_N1", "", {HistType::kTH3F, {{jetPtAxis}, {SxyAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_3prong_Sxyz_flavour_N1", "", {HistType::kTH3F, {{jetPtAxis}, {SxyzAxis}, {jetFlavourAxis}}}); - registry.add("h3_3prong_Sxy_sigmaLxy_flavour", "", {HistType::kTH3F, {{SxyAxis}, {sigmaLxyAxis}, {jetFlavourAxis}}}); - registry.add("h3_3prong_Sxyz_sigmaLxyz_flavour", "", {HistType::kTH3F, {{SxyzAxis}, {sigmaLxyzAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_3prong_sigmaLxy_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {sigmaLxyAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_3prong_sigmaLxyz_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {sigmaLxyzAxis}, {jetFlavourAxis}}}); - } - } - - // Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); - Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut); - - using JetTagTracksData = soa::Join; - using JetTagTracksMCD = soa::Join; - using OriTracksData = soa::Join; - using OriTracksMCD = soa::Join; - - std::function&, const std::vector&)> sortImp = - [](const std::vector& a, const std::vector& b) { - return a[0] > b[0]; - }; - - template - bool trackAcceptance(T const& track) - { - if (track.pt() < trackPtMin || track.pt() > trackPtMax) - return 0; - - return 1; - } - - template - bool prongAcceptance(T const& prong, U const& maxDecayLengthSigma, V const& minDecayLengthSig) - { - auto Sxy = prong.decayLengthXY() / prong.errorDecayLengthXY(); - if (prong.errorDecayLengthXY() < maxDecayLengthSigma || Sxy > minDecayLengthSig) - return 0; - - return 1; - } - - template - void fillHistogramIPsData(T const& collision, U const& jets, V const& /*jtracks*/, W const& /*tracks*/) - { - for (auto& jet : jets) { - if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { - continue; - } - std::vector> vecSignImpXYSig, vecSignImpZSig, vecSignImpXYZSig; - for (auto& jtrack : jet.template tracks_as()) { - auto track = jtrack.template track_as(); - if (!trackAcceptance(track)) - continue; - - // General parameters - registry.fill(HIST("h3_jet_pt_track_pt_track_eta"), jet.pt(), track.pt(), track.eta()); - registry.fill(HIST("h3_jet_pt_track_pt_track_phi"), jet.pt(), track.pt(), track.phi()); - - float varImpXY, varSignImpXY, varImpXYSig, varSignImpXYSig, varImpZ, varSignImpZ, varImpZSig, varSignImpZSig, varImpXYZ, varSignImpXYZ, varImpXYZSig, varSignImpXYZSig; - int geoSign = jettaggingutilities::getGeoSign(collision, jet, track); - varImpXY = track.dcaXY() * jettaggingutilities::cmTomum; - varSignImpXY = geoSign * TMath::Abs(track.dcaXY()) * jettaggingutilities::cmTomum; - varImpXYSig = track.dcaXY() / TMath::Sqrt(track.sigmaDcaXY2()); - varSignImpXYSig = geoSign * TMath::Abs(track.dcaXY()) / TMath::Sqrt(track.sigmaDcaXY2()); - varImpZ = track.dcaZ() * jettaggingutilities::cmTomum; - varSignImpZ = geoSign * TMath::Abs(track.dcaZ()) * jettaggingutilities::cmTomum; - varImpZSig = track.dcaZ() / TMath::Sqrt(track.sigmaDcaZ2()); - varSignImpZSig = geoSign * TMath::Abs(track.dcaZ()) / TMath::Sqrt(track.sigmaDcaZ2()); - float dcaXYZ = jtrack.dcaXYZ(); - float sigmaDcaXYZ2 = jtrack.sigmaDcaXYZ2(); - varImpXYZ = dcaXYZ * jettaggingutilities::cmTomum; - varSignImpXYZ = geoSign * TMath::Abs(dcaXYZ) * jettaggingutilities::cmTomum; - varImpXYZSig = dcaXYZ / TMath::Sqrt(sigmaDcaXYZ2); - varSignImpXYZSig = geoSign * TMath::Abs(dcaXYZ) / TMath::Sqrt(sigmaDcaXYZ2); - - registry.fill(HIST("h2_jet_pt_impact_parameter_xy"), jet.pt(), varImpXY); - registry.fill(HIST("h2_jet_pt_sign_impact_parameter_xy"), jet.pt(), varSignImpXY); - registry.fill(HIST("h2_jet_pt_impact_parameter_xy_significance"), jet.pt(), varImpXYSig); - registry.fill(HIST("h3_jet_pt_track_pt_sign_impact_parameter_xy_significance"), jet.pt(), track.pt(), varSignImpXYSig); - - registry.fill(HIST("h2_jet_pt_impact_parameter_z"), jet.pt(), varImpZ); - registry.fill(HIST("h2_jet_pt_sign_impact_parameter_z"), jet.pt(), varSignImpZ); - registry.fill(HIST("h2_jet_pt_impact_parameter_z_significance"), jet.pt(), varImpZSig); - registry.fill(HIST("h3_jet_pt_track_pt_sign_impact_parameter_z_significance"), jet.pt(), track.pt(), varSignImpZSig); - registry.fill(HIST("h2_jet_pt_impact_parameter_xyz"), jet.pt(), varImpXYZ); - registry.fill(HIST("h2_jet_pt_sign_impact_parameter_xyz"), jet.pt(), varSignImpXYZ); - registry.fill(HIST("h2_jet_pt_impact_parameter_xyz_significance"), jet.pt(), varImpXYZSig); - registry.fill(HIST("h3_jet_pt_track_pt_sign_impact_parameter_xyz_significance"), jet.pt(), track.pt(), varSignImpXYZSig); - - vecSignImpXYSig.push_back({varSignImpXYSig, track.pt()}); - vecSignImpZSig.push_back({varSignImpXYSig, track.pt()}); - vecSignImpXYZSig.push_back({varSignImpXYSig, track.pt()}); - } - - std::sort(vecSignImpXYSig.begin(), vecSignImpXYSig.end(), sortImp); - std::sort(vecSignImpZSig.begin(), vecSignImpZSig.end(), sortImp); - std::sort(vecSignImpXYZSig.begin(), vecSignImpXYZSig.end(), sortImp); - - if (vecSignImpXYSig.empty() || vecSignImpZSig.empty() || vecSignImpXYZSig.empty()) - continue; - for (int order = 1; order <= numOrder; order++) { - if (order < vecSignImpXYSig.size()) { - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xy_significance_tc"), jet.pt(), vecSignImpXYSig[order][0], order); - registry.fill(HIST("h3_track_pt_sign_impact_parameter_xy_significance_tc"), vecSignImpXYSig[order][1], vecSignImpXYSig[order][0], order); - } - if (order < vecSignImpZSig.size()) { - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_z_significance_tc"), jet.pt(), vecSignImpZSig[order][0], order); - registry.fill(HIST("h3_track_pt_sign_impact_parameter_z_significance_tc"), vecSignImpZSig[order][1], vecSignImpZSig[order][0], order); - } - if (order < vecSignImpXYZSig.size()) { - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xyz_significance_tc"), jet.pt(), vecSignImpXYZSig[order][0], order); - registry.fill(HIST("h3_track_pt_sign_impact_parameter_xyz_significance_tc"), vecSignImpXYZSig[order][1], vecSignImpXYZSig[order][0], order); - } - } - } - } - - template - void fillHistogramIPsMCD(T const& collision, U const& mcdjets, V const& /*jtracks*/, W const& /*tracks*/) - { - for (auto& mcdjet : mcdjets) { - if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { - continue; - } - std::vector vecImpXY[numberOfJetFlavourSpecies], vecSignImpXY[numberOfJetFlavourSpecies], vecImpXYSig[numberOfJetFlavourSpecies], vecSignImpXYSig[numberOfJetFlavourSpecies]; - std::vector vecImpZ[numberOfJetFlavourSpecies], vecSignImpZ[numberOfJetFlavourSpecies], vecImpZSig[numberOfJetFlavourSpecies], vecSignImpZSig[numberOfJetFlavourSpecies]; - std::vector vecImpXYZ[numberOfJetFlavourSpecies], vecSignImpXYZ[numberOfJetFlavourSpecies], vecImpXYZSig[numberOfJetFlavourSpecies], vecSignImpXYZSig[numberOfJetFlavourSpecies]; - std::vector> vecSignImpXYSigTC, vecSignImpZSigTC, vecSignImpXYZSigTC; - int jetflavour = mcdjet.origin(); - if (jetflavour == JetTaggingSpecies::none) { - LOGF(debug, "NOT DEFINE JET FLAVOR"); - } - registry.fill(HIST("h2_jet_pt_flavour"), mcdjet.pt(), jetflavour); - registry.fill(HIST("h2_jet_eta_flavour"), mcdjet.eta(), jetflavour); - registry.fill(HIST("h2_jet_phi_flavour"), mcdjet.phi(), jetflavour); - for (auto& jtrack : mcdjet.template tracks_as()) { - auto track = jtrack.template track_as(); - if (!trackAcceptance(track)) - continue; - // auto deltaR = jetutilities::deltaR(mcdjet, track); - // if (deltaR*100>40) LOG(info) << "deltaR: " << deltaR*100 << " jetR: " << mcdjet.r(); - - // General parameters - registry.fill(HIST("h3_jet_pt_track_pt_flavour"), mcdjet.pt(), track.pt(), jetflavour); - registry.fill(HIST("h3_jet_pt_track_eta_flavour"), mcdjet.pt(), track.eta(), jetflavour); - registry.fill(HIST("h3_jet_pt_track_phi_flavour"), mcdjet.pt(), track.phi(), jetflavour); - - float varImpXY, varSignImpXY, varImpXYSig, varSignImpXYSig, varImpZ, varSignImpZ, varImpZSig, varSignImpZSig, varImpXYZ, varSignImpXYZ, varImpXYZSig, varSignImpXYZSig; - int geoSign = jettaggingutilities::getGeoSign(collision, mcdjet, track); - varImpXY = track.dcaXY() * jettaggingutilities::cmTomum; - varSignImpXY = geoSign * TMath::Abs(track.dcaXY()) * jettaggingutilities::cmTomum; - varImpXYSig = track.dcaXY() / TMath::Sqrt(track.sigmaDcaXY2()); - varSignImpXYSig = geoSign * TMath::Abs(track.dcaXY()) / TMath::Sqrt(track.sigmaDcaXY2()); - varImpZ = track.dcaZ() * jettaggingutilities::cmTomum; - varSignImpZ = geoSign * TMath::Abs(track.dcaZ()) * jettaggingutilities::cmTomum; - varImpZSig = track.dcaZ() / TMath::Sqrt(track.sigmaDcaZ2()); - varSignImpZSig = geoSign * TMath::Abs(track.dcaZ()) / TMath::Sqrt(track.sigmaDcaZ2()); - float dcaXYZ = jtrack.dcaXYZ(); - float sigmaDcaXYZ2 = jtrack.sigmaDcaXYZ2(); - varImpXYZ = dcaXYZ * jettaggingutilities::cmTomum; - varSignImpXYZ = geoSign * TMath::Abs(dcaXYZ) * jettaggingutilities::cmTomum; - varImpXYZSig = dcaXYZ / TMath::Sqrt(sigmaDcaXYZ2); - varSignImpXYZSig = geoSign * TMath::Abs(dcaXYZ) / TMath::Sqrt(sigmaDcaXYZ2); - - registry.fill(HIST("h3_jet_pt_impact_parameter_xy_flavour"), mcdjet.pt(), varImpXY, jetflavour); - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xy_flavour"), mcdjet.pt(), varSignImpXY, jetflavour); - registry.fill(HIST("h3_jet_pt_impact_parameter_xy_significance_flavour"), mcdjet.pt(), varImpXYSig, jetflavour); - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xy_significance_flavour"), mcdjet.pt(), varSignImpXYSig, jetflavour); - - registry.fill(HIST("h3_jet_pt_impact_parameter_z_flavour"), mcdjet.pt(), varImpZ, jetflavour); - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_z_flavour"), mcdjet.pt(), varSignImpZ, jetflavour); - registry.fill(HIST("h3_jet_pt_impact_parameter_z_significance_flavour"), mcdjet.pt(), varImpZSig, jetflavour); - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_z_significance_flavour"), mcdjet.pt(), varSignImpZSig, jetflavour); - registry.fill(HIST("h3_jet_pt_impact_parameter_xyz_flavour"), mcdjet.pt(), varImpXYZ, jetflavour); - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xyz_flavour"), mcdjet.pt(), varSignImpXYZ, jetflavour); - registry.fill(HIST("h3_jet_pt_impact_parameter_xyz_significance_flavour"), mcdjet.pt(), varImpXYZSig, jetflavour); - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xyz_significance_flavour"), mcdjet.pt(), varSignImpXYZSig, jetflavour); - registry.fill(HIST("h3_track_pt_impact_parameter_xy_flavour"), jtrack.pt(), varImpXY, jetflavour); - registry.fill(HIST("h3_track_pt_sign_impact_parameter_xy_flavour"), jtrack.pt(), varSignImpXY, jetflavour); - registry.fill(HIST("h3_track_pt_impact_parameter_xy_significance_flavour"), jtrack.pt(), varImpXYSig, jetflavour); - registry.fill(HIST("h3_track_pt_sign_impact_parameter_xy_significance_flavour"), jtrack.pt(), varSignImpXYSig, jetflavour); - registry.fill(HIST("h3_track_pt_impact_parameter_z_flavour"), jtrack.pt(), varImpZ, jetflavour); - registry.fill(HIST("h3_track_pt_sign_impact_parameter_z_flavour"), jtrack.pt(), varSignImpZ, jetflavour); - registry.fill(HIST("h3_track_pt_impact_parameter_z_significance_flavour"), jtrack.pt(), varImpZSig, jetflavour); - registry.fill(HIST("h3_track_pt_sign_impact_parameter_z_significance_flavour"), jtrack.pt(), varSignImpZSig, jetflavour); - registry.fill(HIST("h3_track_pt_impact_parameter_xyz_flavour"), jtrack.pt(), varImpXYZ, jetflavour); - registry.fill(HIST("h3_track_pt_sign_impact_parameter_xyz_flavour"), jtrack.pt(), varSignImpXYZ, jetflavour); - registry.fill(HIST("h3_track_pt_impact_parameter_xyz_significance_flavour"), jtrack.pt(), varImpXYZSig, jetflavour); - registry.fill(HIST("h3_track_pt_sign_impact_parameter_xyz_significance_flavour"), jtrack.pt(), varSignImpXYZSig, jetflavour); - - // For TC - vecImpXY[jetflavour].push_back(varImpXY); - vecSignImpXY[jetflavour].push_back(varSignImpXY); - vecImpXYSig[jetflavour].push_back(varImpXYSig); - vecSignImpXYSig[jetflavour].push_back(varSignImpXYSig); - vecImpZ[jetflavour].push_back(varImpZ); - vecSignImpZ[jetflavour].push_back(varSignImpZ); - vecImpZSig[jetflavour].push_back(varImpZSig); - vecSignImpZSig[jetflavour].push_back(varSignImpZSig); - vecImpXYZ[jetflavour].push_back(varImpXYZ); - vecSignImpXYZ[jetflavour].push_back(varSignImpXYZ); - vecImpXYZSig[jetflavour].push_back(varImpXYZSig); - vecSignImpXYZSig[jetflavour].push_back(varSignImpXYZSig); - vecSignImpXYSigTC.push_back({varSignImpXYSig, jtrack.pt()}); - vecSignImpZSigTC.push_back({varSignImpXYSig, jtrack.pt()}); - vecSignImpXYZSigTC.push_back({varSignImpXYSig, jtrack.pt()}); - } - - // For TC - sort(vecImpXY[jetflavour].begin(), vecImpXY[jetflavour].end(), std::greater()); - sort(vecSignImpXY[jetflavour].begin(), vecSignImpXY[jetflavour].end(), std::greater()); - sort(vecImpXYSig[jetflavour].begin(), vecImpXYSig[jetflavour].end(), std::greater()); - sort(vecSignImpXYSig[jetflavour].begin(), vecSignImpXYSig[jetflavour].end(), std::greater()); - sort(vecImpZ[jetflavour].begin(), vecImpZ[jetflavour].end(), std::greater()); - sort(vecSignImpZ[jetflavour].begin(), vecSignImpZ[jetflavour].end(), std::greater()); - sort(vecImpZSig[jetflavour].begin(), vecImpZSig[jetflavour].end(), std::greater()); - sort(vecSignImpZSig[jetflavour].begin(), vecSignImpZSig[jetflavour].end(), std::greater()); - sort(vecImpXYZ[jetflavour].begin(), vecImpXYZ[jetflavour].end(), std::greater()); - sort(vecSignImpXYZ[jetflavour].begin(), vecSignImpXYZ[jetflavour].end(), std::greater()); - sort(vecImpXYZSig[jetflavour].begin(), vecImpXYZSig[jetflavour].end(), std::greater()); - sort(vecSignImpXYZSig[jetflavour].begin(), vecSignImpXYZSig[jetflavour].end(), std::greater()); - - if (vecImpXY[jetflavour].size() > 0) { // N1 - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xy_significance_flavour_N1"), mcdjet.pt(), vecSignImpXYSig[jetflavour][0], jetflavour); - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_z_significance_flavour_N1"), mcdjet.pt(), vecSignImpZSig[jetflavour][0], jetflavour); - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xyz_significance_flavour_N1"), mcdjet.pt(), vecSignImpXYZSig[jetflavour][0], jetflavour); - } - if (vecImpXY[jetflavour].size() > 1) { // N2 - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xy_significance_flavour_N2"), mcdjet.pt(), vecSignImpXYSig[jetflavour][1], jetflavour); - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_z_significance_flavour_N2"), mcdjet.pt(), vecSignImpZSig[jetflavour][1], jetflavour); - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xyz_significance_flavour_N2"), mcdjet.pt(), vecSignImpXYZSig[jetflavour][1], jetflavour); - } - if (vecImpXY[jetflavour].size() > 2) { // N3 - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xy_significance_flavour_N3"), mcdjet.pt(), vecSignImpXYSig[jetflavour][2], jetflavour); - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_z_significance_flavour_N3"), mcdjet.pt(), vecSignImpZSig[jetflavour][2], jetflavour); - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xyz_significance_flavour_N3"), mcdjet.pt(), vecSignImpXYZSig[jetflavour][2], jetflavour); - } - - std::sort(vecSignImpXYSigTC.begin(), vecSignImpXYSigTC.end(), sortImp); - std::sort(vecSignImpZSigTC.begin(), vecSignImpZSigTC.end(), sortImp); - std::sort(vecSignImpXYZSigTC.begin(), vecSignImpXYZSigTC.end(), sortImp); - - if (vecSignImpXYSigTC.empty() || vecSignImpZSigTC.empty() || vecSignImpXYZSigTC.empty()) - continue; - for (int order = 1; order <= numOrder; order++) { - if (order < vecSignImpXYSigTC.size()) { - registry.fill(HIST("h3_sign_impact_parameter_xy_significance_tc_flavour"), vecSignImpXYSigTC[order][0], order, jetflavour); - } - if (order < vecSignImpZSigTC.size()) { - registry.fill(HIST("h3_sign_impact_parameter_z_significance_tc_flavour"), vecSignImpZSigTC[order][0], order, jetflavour); - } - if (order < vecSignImpXYZSigTC.size()) { - registry.fill(HIST("h3_sign_impact_parameter_xyz_significance_tc_flavour"), vecSignImpXYZSigTC[order][0], order, jetflavour); - } - } - } - } - - template - void fillHistogramJPData(T const& /*collision*/, U const& jets) - { - for (auto& jet : jets) { - if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { - continue; - } - registry.fill(HIST("h2_jet_pt_JP"), jet.pt(), jet.jetProb()[0]); - registry.fill(HIST("h2_jet_pt_neg_log_JP"), jet.pt(), -1 * TMath::Log(jet.jetProb()[0])); - registry.fill(HIST("h2_jet_pt_JP_N1"), jet.pt(), jet.jetProb()[1]); - registry.fill(HIST("h2_jet_pt_neg_log_JP_N1"), jet.pt(), -1 * TMath::Log(jet.jetProb()[1])); - registry.fill(HIST("h2_jet_pt_JP_N2"), jet.pt(), jet.jetProb()[2]); - registry.fill(HIST("h2_jet_pt_neg_log_JP_N2"), jet.pt(), -1 * TMath::Log(jet.jetProb()[2])); - registry.fill(HIST("h2_jet_pt_JP_N3"), jet.pt(), jet.jetProb()[3]); - registry.fill(HIST("h2_jet_pt_neg_log_JP_N3"), jet.pt(), -1 * TMath::Log(jet.jetProb()[3])); - } - } - - template - void fillHistogramJPMCD(T const& /*collision*/, U const& mcdjets) - { - for (auto& mcdjet : mcdjets) { - if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { - continue; - } - registry.fill(HIST("h3_jet_pt_JP_flavour"), mcdjet.pt(), mcdjet.jetProb()[0], mcdjet.origin()); - registry.fill(HIST("h3_jet_pt_neg_log_JP_flavour"), mcdjet.pt(), -1 * TMath::Log(mcdjet.jetProb()[0]), mcdjet.origin()); - registry.fill(HIST("h3_jet_pt_JP_N1_flavour"), mcdjet.pt(), mcdjet.jetProb()[1], mcdjet.origin()); - registry.fill(HIST("h3_jet_pt_neg_log_JP_N1_flavour"), mcdjet.pt(), -1 * TMath::Log(mcdjet.jetProb()[1]), mcdjet.origin()); - registry.fill(HIST("h3_jet_pt_JP_N2_flavour"), mcdjet.pt(), mcdjet.jetProb()[2], mcdjet.origin()); - registry.fill(HIST("h3_jet_pt_neg_log_JP_N2_flavour"), mcdjet.pt(), -1 * TMath::Log(mcdjet.jetProb()[2]), mcdjet.origin()); - registry.fill(HIST("h3_jet_pt_JP_N3_flavour"), mcdjet.pt(), mcdjet.jetProb()[3], mcdjet.origin()); - registry.fill(HIST("h3_jet_pt_neg_log_JP_N3_flavour"), mcdjet.pt(), -1 * TMath::Log(mcdjet.jetProb()[3]), mcdjet.origin()); - } - } - - Preslice perColFor2Prong = aod::hf_cand::collisionId; - Preslice perColFor3Prong = aod::hf_cand::collisionId; - - template - void fillHistogramSV2ProngMCD(T const& collision, U const& mcdjets, V const& prongs) - { - int numOfSV = 0; - int maxSxy = 0; - int maxSxyz = 0; - for (const auto& mcdjet : mcdjets) { - if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { - continue; - } - auto origin = mcdjet.origin(); - auto prongsPerCol = prongs.sliceBy(perColFor2Prong, collision.globalIndex()); - for (const auto& prong : prongsPerCol) { - auto deltaR = jetutilities::deltaR(mcdjet, prong); - if (deltaR > mcdjet.r() / 100.0) { - continue; - } - numOfSV++; - auto Lxy = prong.decayLengthXY(); - auto Sxy = prong.decayLengthXY() / prong.errorDecayLengthXY(); - auto Lxyz = prong.decayLength(); - auto Sxyz = prong.decayLength() / prong.errorDecayLength(); - if (maxSxy < Sxy) - maxSxy = Sxy; - if (maxSxyz < Sxyz) - maxSxyz = Sxyz; - registry.fill(HIST("h3_jet_pt_2prong_Lxy_flavour"), mcdjet.pt(), Lxy, origin); - registry.fill(HIST("h3_jet_pt_2prong_Sxy_flavour"), mcdjet.pt(), Sxy, origin); - registry.fill(HIST("h3_jet_pt_2prong_Lxyz_flavour"), mcdjet.pt(), Lxyz, origin); - registry.fill(HIST("h3_jet_pt_2prong_Sxyz_flavour"), mcdjet.pt(), Sxyz, origin); - registry.fill(HIST("h3_2prong_Sxy_sigmaLxy_flavour"), Sxy, prong.errorDecayLengthXY(), origin); - registry.fill(HIST("h3_2prong_Sxyz_sigmaLxyz_flavour"), Sxyz, prong.errorDecayLength(), origin); - registry.fill(HIST("h3_jet_pt_2prong_sigmaLxy_flavour"), mcdjet.pt(), prong.errorDecayLengthXY(), origin); - registry.fill(HIST("h3_jet_pt_2prong_sigmaLxyz_flavour"), mcdjet.pt(), prong.errorDecayLength(), origin); - } - registry.fill(HIST("h3_jet_pt_2prong_Sxy_flavour_N1"), mcdjet.pt(), maxSxy, origin); - registry.fill(HIST("h3_jet_pt_2prong_Sxyz_flavour_N1"), mcdjet.pt(), maxSxyz, origin); - } - registry.fill(HIST("h_2prong_nprongs"), numOfSV); - } - - template - void fillHistogramSV3ProngMCD(T const& collision, U const& mcdjets, V const& prongs) - { - int numOfSV = 0; - int maxSxy = 0; - int maxSxyz = 0; - for (const auto& mcdjet : mcdjets) { - if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { - continue; - } - auto origin = mcdjet.origin(); - auto prongsPerCol = prongs.sliceBy(perColFor3Prong, collision.globalIndex()); - for (const auto& prong : prongsPerCol) { - auto deltaR = jetutilities::deltaR(mcdjet, prong); - if (deltaR > mcdjet.r() / 100.0) { - continue; - } - numOfSV++; - auto Lxy = prong.decayLengthXY(); - auto Sxy = prong.decayLengthXY() / prong.errorDecayLengthXY(); - auto Lxyz = prong.decayLength(); - auto Sxyz = prong.decayLength() / prong.errorDecayLength(); - if (maxSxy < Sxy) - maxSxy = Sxy; - if (maxSxyz < Sxyz) - maxSxyz = Sxyz; - registry.fill(HIST("h3_jet_pt_3prong_Lxy_flavour"), mcdjet.pt(), Lxy, origin); - registry.fill(HIST("h3_jet_pt_3prong_Sxy_flavour"), mcdjet.pt(), Sxy, origin); - registry.fill(HIST("h3_jet_pt_3prong_Lxyz_flavour"), mcdjet.pt(), Lxyz, origin); - registry.fill(HIST("h3_jet_pt_3prong_Sxyz_flavour"), mcdjet.pt(), Sxyz, origin); - registry.fill(HIST("h3_3prong_Sxy_sigmaLxy_flavour"), Sxy, prong.errorDecayLengthXY(), origin); - registry.fill(HIST("h3_3prong_Sxyz_sigmaLxyz_flavour"), Sxyz, prong.errorDecayLength(), origin); - registry.fill(HIST("h3_jet_pt_3prong_sigmaLxy_flavour"), mcdjet.pt(), prong.errorDecayLengthXY(), origin); - registry.fill(HIST("h3_jet_pt_3prong_sigmaLxyz_flavour"), mcdjet.pt(), prong.errorDecayLength(), origin); - } - registry.fill(HIST("h3_jet_pt_2prong_Sxy_flavour_N1"), mcdjet.pt(), maxSxy, origin); - registry.fill(HIST("h3_jet_pt_2prong_Sxyz_flavour_N1"), mcdjet.pt(), maxSxyz, origin); - } - registry.fill(HIST("h_3prong_nprongs"), numOfSV); - } - - void processDummy(aod::Collision const&, aod::Tracks const&) - { - } - PROCESS_SWITCH(JetTaggerHFQA, processDummy, "Dummy process", true); - - void processTracksDca(JetTagTracksData& jtracks, OriTracksData const&) - { - for (auto const& jtrack : jtracks) { - if (!jetderiveddatautilities::selectTrack(jtrack, trackSelection)) { - continue; - } - auto track = jtrack.track_as(); - - float varImpXY, varImpXYSig, varImpZ, varImpZSig, varImpXYZ, varImpXYZSig; - varImpXY = track.dcaXY() * jettaggingutilities::cmTomum; - varImpXYSig = track.dcaXY() / TMath::Sqrt(track.sigmaDcaXY2()); - varImpZ = track.dcaZ() * jettaggingutilities::cmTomum; - varImpZSig = track.dcaZ() / TMath::Sqrt(track.sigmaDcaZ2()); - float dcaXYZ = jtrack.dcaXYZ(); - float sigmaDcaXYZ2 = jtrack.sigmaDcaXYZ2(); - varImpXYZ = dcaXYZ * jettaggingutilities::cmTomum; - varImpXYZSig = dcaXYZ / TMath::Sqrt(sigmaDcaXYZ2); - - registry.fill(HIST("h_impact_parameter_xy"), varImpXY); - registry.fill(HIST("h_impact_parameter_xy_significance"), varImpXYSig); - registry.fill(HIST("h_impact_parameter_z"), varImpZ); - registry.fill(HIST("h_impact_parameter_z_significance"), varImpZSig); - registry.fill(HIST("h_impact_parameter_xyz"), varImpXYZ); - registry.fill(HIST("h_impact_parameter_xyz_significance"), varImpXYZSig); - } - } - PROCESS_SWITCH(JetTaggerHFQA, processTracksDca, "Fill inclusive tracks' impormation for data", false); - - void processIPsData(soa::Filtered::iterator const& jcollision, JetTagTableData const& jets, JetTagTracksData const& jtracks, OriTracksData const& tracks) - { - fillHistogramIPsData(jcollision, jets, jtracks, tracks); - } - PROCESS_SWITCH(JetTaggerHFQA, processIPsData, "Fill impact parameter impormation for data jets", false); - - void processIPsMCD(soa::Filtered::iterator const& jcollision, JetTagTableMCD const& mcdjets, JetTagTracksMCD const& jtracks, OriTracksMCD const& tracks, JetParticles&) - { - fillHistogramIPsMCD(jcollision, mcdjets, jtracks, tracks); - } - PROCESS_SWITCH(JetTaggerHFQA, processIPsMCD, "Fill impact parameter impormation for mcd jets", false); - - void processJPData(soa::Filtered::iterator const& jcollision, JetTagTableData const& jets, JetTagTracksData const&) - { - fillHistogramJPData(jcollision, jets); - } - PROCESS_SWITCH(JetTaggerHFQA, processJPData, "Fill jet probability imformation for data jets", false); - - void processJPMCD(soa::Filtered::iterator const& jcollision, JetTagTableMCD const& mcdjets, JetTagTracksMCD const&) - { - fillHistogramJPMCD(jcollision, mcdjets); - } - PROCESS_SWITCH(JetTaggerHFQA, processJPMCD, "Fill jet probability imformation for mcd jets", false); - - void processSV2ProngMCD(soa::Filtered::iterator const& jcollision, JetTagTableMCD const& mcdjets, aod::HfCand2Prong const& prongs) - { - fillHistogramSV2ProngMCD(jcollision, mcdjets, prongs); - } - PROCESS_SWITCH(JetTaggerHFQA, processSV2ProngMCD, "Fill 2prong impormation for mcd jets", false); - - void processSV3ProngMCD(soa::Filtered::iterator const& jcollision, JetTagTableMCD const& mcdjets, aod::HfCand3Prong const& prongs) - { - fillHistogramSV3ProngMCD(jcollision, mcdjets, prongs); - } - PROCESS_SWITCH(JetTaggerHFQA, processSV3ProngMCD, "Fill 3prong impormation for mcd jets", false); -}; - -using JetTaggerQAChargedDataJets = soa::Join; -using JetTaggerQAChargedMCDJets = soa::Join; -using JetTaggerQAChargedMCPJets = soa::Join; - -using JetTaggerQACharged = JetTaggerHFQA; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - - std::vector tasks; - - tasks.emplace_back( - adaptAnalysisTask(cfgc, - SetDefaultProcesses{}, TaskName{"jet-taggerhf-qa-charged"})); - /* - tasks.emplace_back( - adaptAnalysisTask(cfgc, - SetDefaultProcesses{}, TaskName{"jet-taggerhf-qa-full"})); - - tasks.emplace_back( - adaptAnalysisTask(cfgc, - SetDefaultProcesses{}, TaskName{"jet-taggerhf-qa-neutral"})); - */ - return WorkflowSpec{tasks}; -} diff --git a/PWGJE/Tasks/mcGeneratorStudies.cxx b/PWGJE/Tasks/mcGeneratorStudies.cxx new file mode 100644 index 00000000000..bef48af81a8 --- /dev/null +++ b/PWGJE/Tasks/mcGeneratorStudies.cxx @@ -0,0 +1,300 @@ +// Copyright 2019-2024 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. + +// Task that produces the generated pT spectrum of a given particle for MC studies +// +/// \author Nicolas Strangmann , Goethe University Frankfurt / Oak Ridge National Laoratory + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/HistogramRegistry.h" + +#include "PWGJE/DataModel/EMCALMatchedCollisions.h" + +#include "DetectorsBase/GeometryManager.h" +#include "EMCALBase/Geometry.h" + +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" + +#include "TDatabasePDG.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using MyMCCollisions = soa::Join; +using MyBCs = o2::soa::Join; + +struct MCGeneratorStudies { + HistogramRegistry mHistManager{"MCGeneratorStudyHistograms"}; + + Configurable mVertexCut{"vertexCut", 10.f, "apply z-vertex cut with value in cm"}; + Configurable mRapidityCut{"rapidityCut", 0.9f, "Maximum absolute rapidity of counted generated particles"}; + Configurable mSelectedParticleCode{"particlePDGCode", 111, "PDG code of the particle to be investigated (0 for all)"}; + Configurable mSelectOnlyChargedParticles{"mSelectOnlyChargedParticles", false, "set true to only count charged particles"}; + + Configurable mRequireGammaGammaDecay{"requireGammaGammaDecay", false, "Only count generated particles that decayed into two photons"}; + Configurable mRequireEMCCellContent{"requireEMCCellContent", false, "Ask forEMCal cell content instead of the kTVXinEMC trigger"}; + + Configurable mRequireTVX{"mRequireTVX", true, "require FT0AND in event cut"}; + Configurable mRequireSel8{"mRequireSel8", true, "require sel8 in event cut"}; + Configurable mRequireNoSameBunchPileup{"mRequireNoSameBunchPileup", true, "require no same bunch pileup in event cut"}; + Configurable mRequireGoodZvtxFT0vsPV{"mRequireGoodZvtxFT0vsPV", true, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable mRequireEMCReadoutInMB{"mRequireEMCReadoutInMB", true, "require the EMC to be read out in an MB collision (kTVXinEMC)"}; + + void init(InitContext const&) + { + AxisSpec pTAxis{250, 0., 25., "#it{p}_{T} (GeV/#it{c})"}; + + auto hCollisionCounter = mHistManager.add("hCollisionCounter", "Number of collisions after event cuts", HistType::kTH1F, {{7, 0.5, 7.5}}); + hCollisionCounter->GetXaxis()->SetBinLabel(1, "all"); + hCollisionCounter->GetXaxis()->SetBinLabel(2, "+TVX"); // TVX + hCollisionCounter->GetXaxis()->SetBinLabel(3, "+|z|<10cm"); // TVX with z < 10cm + hCollisionCounter->GetXaxis()->SetBinLabel(4, "+Sel8"); // TVX with z < 10cm and Sel8 + hCollisionCounter->GetXaxis()->SetBinLabel(5, "+Good z vtx"); // TVX with z < 10cm and Sel8 and good z xertex + hCollisionCounter->GetXaxis()->SetBinLabel(6, "+unique"); // TVX with z < 10cm and Sel8 and good z xertex and unique (only collision in the BC) + hCollisionCounter->GetXaxis()->SetBinLabel(7, "+EMC readout"); // TVX with z < 10cm and Sel8 and good z xertex and unique (only collision in the BC) and kTVXinEMC + + auto hBCCounter = mHistManager.add("hBCCounter", "Number of BCs after BC cuts", HistType::kTH1F, {{3, 0.5, 3.5}}); + hBCCounter->GetXaxis()->SetBinLabel(1, "all"); + hBCCounter->GetXaxis()->SetBinLabel(2, "+TVX"); + hBCCounter->GetXaxis()->SetBinLabel(3, "+Collision"); + + TString mesonLatexString = (TString)mSelectedParticleCode; + switch (mSelectedParticleCode) { + case 0: + mesonLatexString = "particles"; + break; + case 111: + mesonLatexString = "#pi^{0}"; + break; + case 221: + mesonLatexString = "#eta"; + break; + } + mHistManager.add("Yield", Form("Generated %s in all collisions", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); + mHistManager.add("Yield_Accepted", Form("Accepted %s in all collisions", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); + mHistManager.add("Yield_T", Form("Generated %s in TVX triggered collisions", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); + mHistManager.add("Yield_TZ", Form("Generated %s in TVX collisions with z < 10cm", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); + mHistManager.add("Yield_TZS", Form("Generated %s in TVX collisions with z < 10cm and Sel8", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); + mHistManager.add("Yield_TZSG", Form("Generated %s in collisions with good z < 10cm and Sel8", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); + mHistManager.add("Yield_TZSGU", Form("Generated %s in unique collisions with good z < 10cm and Sel8", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); + mHistManager.add("Yield_TZSGUE", Form("Generated %s in unique TVXinEMC collisions with good z < 10cm and Sel8", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); + mHistManager.add("Yield_TZSGUE_Accepted", Form("Accepted %s in unique TVXinEMC collisions with good z < 10cm and Sel8", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); + + mHistManager.add("Yield_BC_T", Form("Generated %s in TVX triggered BCs", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); + mHistManager.add("Yield_BC_TC", Form("Generated %s in TVX triggered BCs that have at least one collision", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); + mHistManager.add("NCollisionsMCCollisions", "Number of (MC)Collisions in the BC;#it{N}_(Collisions);#it{N}_(MC Collisions)", kTH2F, {{4, -0.5, 3.5}, {4, -0.5, 3.5}}); + mHistManager.add("NTVXCollisionsMCCollisions", "Number of (MC)Collisions in the TVX triggered BC;#it{N}_(Collisions);#it{N}_(MC Collisions)", kTH2F, {{4, -0.5, 3.5}, {4, -0.5, 3.5}}); + + auto hEMCollisionCounter = mHistManager.add("hEMCollisionCounter", "collision counter;;Number of events", kTH1F, {{13, 0.5, 13.5}}, false); + hEMCollisionCounter->GetXaxis()->SetBinLabel(1, "all"); + hEMCollisionCounter->GetXaxis()->SetBinLabel(2, "No TF border"); + hEMCollisionCounter->GetXaxis()->SetBinLabel(3, "No ITS ROF border"); + hEMCollisionCounter->GetXaxis()->SetBinLabel(4, "No Same Bunch Pileup"); + hEMCollisionCounter->GetXaxis()->SetBinLabel(5, "Is Vertex ITSTPC"); + hEMCollisionCounter->GetXaxis()->SetBinLabel(6, "Is Good Zvtx FT0vsPV"); + hEMCollisionCounter->GetXaxis()->SetBinLabel(7, "FT0AND"); + hEMCollisionCounter->GetXaxis()->SetBinLabel(8, "sel8"); + hEMCollisionCounter->GetXaxis()->SetBinLabel(9, "|Z_{vtx}| < 10 cm"); + hEMCollisionCounter->GetXaxis()->SetBinLabel(10, "EMC MB Readout"); + hEMCollisionCounter->GetXaxis()->SetBinLabel(11, "EMC L0 Triggered"); + hEMCollisionCounter->GetXaxis()->SetBinLabel(12, "EMC Cell Content"); + hEMCollisionCounter->GetXaxis()->SetBinLabel(13, "accepted"); + + o2::emcal::Geometry::GetInstanceFromRunNumber(300000); + } + + PresliceUnsorted perFoundBC = aod::evsel::foundBCId; + Preslice MCCollperBC = aod::mccollision::bcId; + Preslice perMcCollision = aod::mcparticle::mcCollisionId; + + void process(MyBCs const& bcs, MyMCCollisions const& collisions, aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + + for (const auto& bc : bcs) { + + auto collisionsInFoundBC = collisions.sliceBy(perFoundBC, bc.globalIndex()); + auto MCCollisionsBC = mcCollisions.sliceBy(MCCollperBC, bc.globalIndex()); + + mHistManager.fill(HIST("NCollisionsMCCollisions"), collisionsInFoundBC.size(), MCCollisionsBC.size()); + mHistManager.fill(HIST("hBCCounter"), 1); + + if (!mRequireTVX || bc.selection_bit(aod::evsel::kIsTriggerTVX)) { // Count BCs with TVX trigger with and without a collision, as well as the generated particles within + + mHistManager.fill(HIST("NTVXCollisionsMCCollisions"), collisionsInFoundBC.size(), mcCollisions.size()); + + mHistManager.fill(HIST("hBCCounter"), 2); + + bool bcHasCollision = collisionsInFoundBC.size() > 0; + + if (bcHasCollision) + mHistManager.fill(HIST("hBCCounter"), 3); + + for (auto& mcCollision : MCCollisionsBC) { + + auto mcParticles_inColl = mcParticles.sliceBy(perMcCollision, mcCollision.globalIndex()); + + for (auto& mcParticle : mcParticles_inColl) { + if (mSelectedParticleCode != 0 && mcParticle.pdgCode() != mSelectedParticleCode) + continue; + else if (mSelectOnlyChargedParticles && TDatabasePDG::Instance()->GetParticle(mcParticle.pdgCode())->Charge()) + continue; + if (fabs(mcParticle.y()) > mRapidityCut) + continue; + if (!mcParticle.isPhysicalPrimary() && !mcParticle.producedByGenerator()) + continue; + if (mRequireGammaGammaDecay && !isGammaGammaDecay(mcParticle, mcParticles)) + continue; + + mHistManager.fill(HIST("Yield_BC_T"), mcParticle.pt()); + + if (bcHasCollision) + mHistManager.fill(HIST("Yield_BC_TC"), mcParticle.pt()); + } + } + } + } + + for (auto& collision : collisions) { + fillEventHistogram(&mHistManager, collision); + + auto mcCollision = collision.mcCollision(); + auto mcParticles_inColl = mcParticles.sliceBy(perMcCollision, mcCollision.globalIndex()); + + for (auto& mcParticle : mcParticles_inColl) { + if (mSelectedParticleCode != 0 && mcParticle.pdgCode() != mSelectedParticleCode) + continue; + else if (mSelectOnlyChargedParticles && TDatabasePDG::Instance()->GetParticle(mcParticle.pdgCode())->Charge()) + continue; + if (fabs(mcParticle.y()) > mRapidityCut) + continue; + if (!mcParticle.isPhysicalPrimary() && !mcParticle.producedByGenerator()) + continue; + if (mRequireGammaGammaDecay && !isGammaGammaDecay(mcParticle, mcParticles)) + continue; + + mHistManager.fill(HIST("Yield"), mcParticle.pt()); + if (isAccepted(mcParticle, mcParticles)) + mHistManager.fill(HIST("Yield_Accepted"), mcParticle.pt()); + if (!mRequireTVX || collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + mHistManager.fill(HIST("Yield_T"), mcParticle.pt()); + if (abs(collision.posZ()) < mVertexCut) { + mHistManager.fill(HIST("Yield_TZ"), mcParticle.pt()); + if (!mRequireSel8 || collision.sel8()) { + mHistManager.fill(HIST("Yield_TZS"), mcParticle.pt()); + if (!mRequireGoodZvtxFT0vsPV || collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + mHistManager.fill(HIST("Yield_TZSG"), mcParticle.pt()); + if (!mRequireNoSameBunchPileup || collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + mHistManager.fill(HIST("Yield_TZSGU"), mcParticle.pt()); + if (!mRequireEMCReadoutInMB || (mRequireEMCCellContent ? collision.isemcreadout() : collision.alias_bit(kTVXinEMC))) { + mHistManager.fill(HIST("Yield_TZSGUE"), mcParticle.pt()); + if (isAccepted(mcParticle, mcParticles)) + mHistManager.fill(HIST("Yield_TZSGUE_Accepted"), mcParticle.pt()); + } + } + } + } + } + } + } + } + } + + template + bool isGammaGammaDecay(TMCParticle mcParticle, TMCParticles mcParticles) + { + auto daughtersIds = mcParticle.daughtersIds(); + if (daughtersIds.size() != 2) + return false; + for (auto& daughterId : daughtersIds) { + if (mcParticles.iteratorAt(daughterId).pdgCode() != 22) + return false; + } + return true; + } + + template + bool isAccepted(TMCParticle mcParticle, TMCParticles mcParticles) + { + auto daughtersIds = mcParticle.daughtersIds(); + if (daughtersIds.size() != 2) + return false; + for (auto& daughterId : daughtersIds) { + if (mcParticles.iteratorAt(daughterId).pdgCode() != 22) + return false; + int iCellID = -1; + try { + iCellID = emcal::Geometry::GetInstance()->GetAbsCellIdFromEtaPhi(mcParticles.iteratorAt(daughterId).eta(), mcParticles.iteratorAt(daughterId).phi()); + } catch (emcal::InvalidPositionException& e) { + iCellID = -1; + } + if (iCellID == -1) + return false; + } + return true; + } + + void fillEventHistogram(HistogramRegistry* fRegistry, MyMCCollisions::iterator const& collision) + { + fRegistry->fill(HIST("hEMCollisionCounter"), 1.0); + if (collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) + fRegistry->fill(HIST("hEMCollisionCounter"), 2.0); + if (collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) + fRegistry->fill(HIST("hEMCollisionCounter"), 3.0); + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + fRegistry->fill(HIST("hEMCollisionCounter"), 4.0); + if (collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) + fRegistry->fill(HIST("hEMCollisionCounter"), 5.0); + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + fRegistry->fill(HIST("hEMCollisionCounter"), 6.0); + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) + fRegistry->fill(HIST("hEMCollisionCounter"), 7.0); + if (collision.sel8()) + fRegistry->fill(HIST("hEMCollisionCounter"), 8.0); + if (abs(collision.posZ()) < 10.0) + fRegistry->fill(HIST("hEMCollisionCounter"), 9.0); + if (collision.alias_bit(kTVXinEMC)) + fRegistry->fill(HIST("hEMCollisionCounter"), 10.0); + if (collision.alias_bit(kEMC7) || collision.alias_bit(kDMC7)) + fRegistry->fill(HIST("hEMCollisionCounter"), 11.0); + if (collision.isemcreadout()) + fRegistry->fill(HIST("hEMCollisionCounter"), 12.0); + fRegistry->fill(HIST("hEMCollisionCounter"), 13.0); + + fRegistry->fill(HIST("hCollisionCounter"), 1); + if (!mRequireTVX || collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + fRegistry->fill(HIST("hCollisionCounter"), 2); + if (abs(collision.posZ()) < mVertexCut) { + fRegistry->fill(HIST("hCollisionCounter"), 3); + if (!mRequireSel8 || collision.sel8()) { + fRegistry->fill(HIST("hCollisionCounter"), 4); + if (!mRequireGoodZvtxFT0vsPV || collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + fRegistry->fill(HIST("hCollisionCounter"), 5); + if (!mRequireNoSameBunchPileup || collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + fRegistry->fill(HIST("hCollisionCounter"), 6); + if (!mRequireEMCReadoutInMB || (mRequireEMCCellContent ? collision.isemcreadout() : collision.alias_bit(kTVXinEMC))) + fRegistry->fill(HIST("hCollisionCounter"), 7); + } + } + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"mc-generator-studies"})}; +} diff --git a/PWGJE/Tasks/mcgeneratorstudies.cxx b/PWGJE/Tasks/mcgeneratorstudies.cxx deleted file mode 100644 index 4df20c893ce..00000000000 --- a/PWGJE/Tasks/mcgeneratorstudies.cxx +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2019-2024 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. - -// Task that produces the generated pT spectrum of a given particle for MC studies -// -/// \author Nicolas Strangmann , Goethe University Frankfurt / Oak Ridge National Laoratory - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/HistogramRegistry.h" - -#include "PWGJE/DataModel/EMCALMatchedCollisions.h" - -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -using MyMCCollisions = soa::Join; - -struct MCGeneratorStudies { - HistogramRegistry mHistManager{"MCGeneratorStudyHistograms"}; - - Configurable mVertexCut{"vertexCut", 10.f, "apply z-vertex cut with value in cm"}; - Configurable mRapidityCut{"rapidityCut", 0.9f, "Maximum absolute rapidity of counted generated particles"}; - Configurable mSelectedParticleCode{"particlePDGCode", 111, "PDG code of the particle to be investigated"}; - - Filter collisionFilter = (aod::collision::posZ > -mVertexCut) && (aod::collision::posZ < mVertexCut); - Filter mcParticleFilter = (aod::mcparticle::pdgCode == mSelectedParticleCode) && (aod::mcparticle::y > -mRapidityCut) && (aod::mcparticle::y < mRapidityCut); - - void init(InitContext const&) - { - AxisSpec pTAxis{250, 0., 25., "#it{p}_{T} (GeV/#it{c})"}; - - mHistManager.add("hCollisionCounter", "Number of collisions after event cuts", HistType::kTH1F, {{5, 0.5, 5.5}}); - mHistManager.add("hpT_all", "All collisions", HistType::kTH1F, {pTAxis}); - mHistManager.add("hpT_T0Triggered", "T0 triggered collisions", HistType::kTH1F, {pTAxis}); - mHistManager.add("hpT_T0Triggered_EMCReadout", "T0 triggered and EMC readout collisions", HistType::kTH1F, {pTAxis}); - mHistManager.add("hpT_T0Triggered_EMCReadout_Unique", "Unique T0 triggered and EMC readout collisions", HistType::kTH1F, {pTAxis}); - } - - PresliceUnsorted perMcCollision = aod::mcparticle::mcCollisionId; - - void process(soa::Filtered::iterator const& collision, soa::Filtered const& mcParticles) - { - bool isT0Triggered = collision.sel8(); - bool isEMCReadout = collision.isemcreadout(); - bool isUniqueCollision = !collision.ambiguous(); - - mHistManager.fill(HIST("hCollisionCounter"), 1); - if (isT0Triggered) { - mHistManager.fill(HIST("hCollisionCounter"), 2); - // mHistManager.fill(HIST("hpT_T0Triggered"), mcParticles, aod::evsel::sel8 == true); - if (isEMCReadout) { - mHistManager.fill(HIST("hCollisionCounter"), 3); - if (isUniqueCollision) { - mHistManager.fill(HIST("hCollisionCounter"), 4); - } - } - } - auto mcParticles_inColl = mcParticles.sliceBy(perMcCollision, collision.globalIndex()); - for (auto& mcParticle : mcParticles_inColl) { - mHistManager.fill(HIST("hpT_all"), mcParticle.pt()); - if (isT0Triggered) { - mHistManager.fill(HIST("hpT_T0Triggered"), mcParticle.pt()); - if (isEMCReadout) { - mHistManager.fill(HIST("hpT_T0Triggered_EMCReadout"), mcParticle.pt()); - if (isUniqueCollision) { - mHistManager.fill(HIST("hpT_T0Triggered_EMCReadout_Unique"), mcParticle.pt()); - } - } - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"mc-generator-studies"})}; -} diff --git a/PWGJE/Tasks/nSubjettiness.cxx b/PWGJE/Tasks/nsubjettiness.cxx similarity index 91% rename from PWGJE/Tasks/nSubjettiness.cxx rename to PWGJE/Tasks/nsubjettiness.cxx index b1a695bd9f7..1eabf7c6c50 100644 --- a/PWGJE/Tasks/nSubjettiness.cxx +++ b/PWGJE/Tasks/nsubjettiness.cxx @@ -227,7 +227,7 @@ struct NSubjettinessTask { table(jet.pt(), jet.eta(), jet.phi(), nSub_Kt_results[1], nSub_Kt_results[2], nSub_Kt_results[0], nSub_CA_results[1], nSub_CA_results[2], nSub_CA_results[0], nSub_CASD_results[1], nSub_CASD_results[2], nSub_CASD_results[0]); } - void processJetsData(soa::Filtered::iterator const&, soa::Filtered> const& jets, JetTracks const& tracks) + void processJetsData(soa::Filtered::iterator const&, soa::Filtered> const& jets, aod::JetTracks const& tracks) { for (auto& jet : jets) { processJet(jet, tracks); @@ -236,7 +236,7 @@ struct NSubjettinessTask { } PROCESS_SWITCH(NSubjettinessTask, processJetsData, "Process function for inclusive jets in data", true); - void processJetsDataEWS(soa::Filtered::iterator const&, soa::Filtered> const& jets, JetTracksSub const& tracks) + void processJetsDataEWS(soa::Filtered::iterator const&, soa::Filtered> const& jets, aod::JetTracksSub const& tracks) { for (auto& jet : jets) { processJet(jet, tracks); @@ -245,7 +245,7 @@ struct NSubjettinessTask { } PROCESS_SWITCH(NSubjettinessTask, processJetsDataEWS, "Process function for inclusive jets with eventwise subtraction in data", false); - void processJetsMCD(soa::Filtered::iterator const&, soa::Filtered> const& jets, JetTracks const& tracks) + void processJetsMCD(soa::Filtered::iterator const&, soa::Filtered> const& jets, aod::JetTracks const& tracks) { for (auto& jet : jets) { processJet(jet, tracks); @@ -254,7 +254,7 @@ struct NSubjettinessTask { } PROCESS_SWITCH(NSubjettinessTask, processJetsMCD, "Process function for inclusive jets in mcd", false); - void processJetsMCDWeighted(soa::Filtered::iterator const&, soa::Filtered> const& jets, JetTracks const& tracks) + void processJetsMCDWeighted(soa::Filtered::iterator const&, soa::Filtered> const& jets, aod::JetTracks const& tracks) { for (auto& jet : jets) { processJet(jet, tracks, jet.eventWeight()); @@ -263,7 +263,7 @@ struct NSubjettinessTask { } PROCESS_SWITCH(NSubjettinessTask, processJetsMCDWeighted, "Process function for inclusive jets in weighted mcd", false); - void processJetsMCP(JetMcCollision const&, soa::Filtered> const& jets, JetParticles const& particles) + void processJetsMCP(aod::JetMcCollision const&, soa::Filtered> const& jets, aod::JetParticles const& particles) { for (auto& jet : jets) { processJet(jet, particles); @@ -272,7 +272,7 @@ struct NSubjettinessTask { } PROCESS_SWITCH(NSubjettinessTask, processJetsMCP, "Process function for inclusive jets in mcp", false); - void processJetsMCPWeighted(JetMcCollision const&, soa::Filtered> const& jets, JetParticles const& particles) + void processJetsMCPWeighted(aod::JetMcCollision const&, soa::Filtered> const& jets, aod::JetParticles const& particles) { for (auto& jet : jets) { processJet(jet, particles, jet.eventWeight()); diff --git a/PWGJE/Tasks/nucleiInJets.cxx b/PWGJE/Tasks/nucleiInJets.cxx new file mode 100644 index 00000000000..150824d438b --- /dev/null +++ b/PWGJE/Tasks/nucleiInJets.cxx @@ -0,0 +1,1647 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// author: Arvind Khuntia (arvind.khuntia@cern.ch) INFN Bologna, Italy + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "CommonConstants/PhysicsConstants.h" + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" + +#include "ReconstructionDataFormats/Track.h" + +#include "PWGLF/DataModel/LFParticleIdentification.h" + +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedDataSelector.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +struct nucleiInJets { + + enum Particle { + kPion = 1, // π+ + kKaon = 2, // K+ + kProton = 3, // p + kDeuteron = 4, // d + kTriton = 5, // Tr + kHelium = 6 // He + }; + + int mapPDGToValue(int pdgCode) + { + switch (pdgCode) { + case 211: // π+ + return Particle::kPion; + case -211: // π- + return -Particle::kPion; + + case 321: // k+ + return Particle::kKaon; + case -321: // k- + return -Particle::kKaon; + + case 2212: // p + return Particle::kProton; + case -2212: // antip + return -Particle::kProton; + + case 1000010020: // Deuteron + return Particle::kDeuteron; + case -1000010020: // AntiDeuteron + return -Particle::kDeuteron; + + case 1000010030: // Triton + return Particle::kTriton; + case -1000010030: // AntiTriton + return -Particle::kTriton; + + case 1000020030: // Helium + return Particle::kHelium; + case -1000020030: // AntiHelium + return -Particle::kHelium; + default: + return 0; // Default case for unknown or unmapped PDG codes + } + } + + Configurable cfgtrackSelections{"cfgtrackSelections", "globalTracks", "set track selections"}; + Configurable isMC{"isMC", false, "flag for the MC"}; + Configurable isWithJetEvents{"isWithJetEvents", true, "Events with at least one jet"}; + Configurable isWithLeadingJet{"isWithLeadingJet", true, "Events with leading jet"}; + Configurable useLfTpcPid{"useLfTpcPid", true, "Events with custom TPC parameters"}; + + Configurable cfgtrkMinPt{"cfgtrkMinPt", 0.15, "set track min pT"}; + Configurable cfgtrkMaxEta{"cfgtrkMaxEta", 0.8, "set track max Eta"}; + Configurable cfgtrkMaxRap{"cfgtrkMaxRap", 0.5, "set track max y"}; + Configurable cfgMaxDCArToPVcut{"cfgMaxDCArToPVcut", 0.12, "Track DCAr cut to PV Maximum"}; + Configurable cfgMaxDCAzToPVcut{"cfgMaxDCAzToPVcut", 1.0, "Track DCAz cut to PV Maximum"}; + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; + Configurable cfgConnectedToPV{"cfgConnectedToPV", true, "PV contributor track selection"}; // PV Contriuibutor + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) + Configurable cfgnFindableTPCClusters{"cfgnFindableTPCClusters", 120, "nFindable TPC Clusters"}; + Configurable cfgnTPCCrossedRows{"cfgnTPCCrossedRows", 70, "nCrossed TPC Rows"}; + Configurable cfgnTPCChi2{"cfgnTPChi2", 4.0, "nTPC Chi2 per Cluster"}; + Configurable cfgnITSChi2{"cfgnITShi2", 36.0, "nITS Chi2 per Cluster"}; + + Configurable cfgjetPtMin{"cfgjetPtMin", 5.0, "minimum jet pT cut"}; + Configurable cfgjetR{"cfgjetR", 0.4, "jet resolution parameter"}; + Configurable cDebugLevel{"cDebugLevel", 0, "print debug msg"}; + Configurable cMaxPt{"cMaxPt", 10, "max pt for Hist"}; + + Configurable cfgnTPCPIDPr{"cfgnTPCPIDPr", 3, "nTPC PID Pr"}; + Configurable cfgnTPCPIDDe{"cfgnTPCPIDDe", 3, "nTPC PID De"}; + Configurable cfgnTPCPIDHe{"cfgnTPCPIDHe", 3, "nTPC PID He"}; + Configurable cfgnTPCPIDTr{"cfgnTPCPIDTr", 3, "nTPC PID Tr"}; + + Configurable cfgnTPCPIDPrTOF{"cfgnTPCPIDPrTOF", 3, "nTPC PID Pr"}; + Configurable cfgnTPCPIDDeTOF{"cfgnTPCPIDDeTOF", 3, "nTPC PID De"}; + Configurable cfgnTPCPIDHeTOF{"cfgnTPCPIDHeTOF", 3, "nTPC PID He"}; + Configurable cfgnTPCPIDTrTOF{"cfgnTPCPIDTrTOF", 3, "nTPC PID Tr"}; + + Configurable cEnableProtonQA{"cEnableProtonQA", true, "nTPC PID Pr"}; + Configurable cEnableDeuteronQA{"cEnableDeuteronQA", true, "nTPC PID De"}; + Configurable cEnableHeliumQA{"cEnableHeliumQA", true, "nTPC PID He"}; + Configurable cEnableTritonQA{"cEnableTritonQA", true, "nTPC PID Tr"}; + Configurable addTOFplots{"addTOFplots", true, "add TOF plots"}; + Configurable useTPCpreSel{"useTPCpreSel", 3, "add TPC nsgma preselection for TOF: (0) no selection (!0) selction on TPC"}; + Configurable useLeadingJetDetLevelValue{"useLeadingJetDetLevelValue", false, "true: use det level value for leading jet, false: use part level value"}; + Configurable useDcaxyPtDepCut{"useDcaxyPtDepCut", true, "true: use pt dependent DCAxy cut, false: use constant DCAxy cut"}; + Configurable useTOFNsigmaPreSel{"useTOFNsigmaPreSel", true, "true: use TOF nsgma preselection, false: no TOF nsgma preselection"}; + Configurable isRequireHitsInITSLayers{"isRequireHitsInITSLayers", true, "true: at least one hit in the its inner layes"}; + Configurable useMcC{"useMcC", true, "use mcC"}; + + Configurable addpik{"addpik", true, "add pion and kaon hist"}; + ConfigurableAxis binsDCA{"binsDCA", {400, -1.f, 1.f}, ""}; + ConfigurableAxis binsdEdx{"binsdEdx", {1000, 0.f, 1000.f}, ""}; + ConfigurableAxis binsBeta{"binsBeta", {120, 0.0, 1.2}, ""}; + + ConfigurableAxis binsMassPr{"binsMassPr", {100, -1., 1.f}, ""}; + ConfigurableAxis binsMassDe{"binsMassDe", {180, -1.8, 1.8f}, ""}; + ConfigurableAxis binsMassTr{"binsMassTr", {250, -2.5, 2.5f}, ""}; + ConfigurableAxis binsMassHe{"binsMassHe", {300, -3., 3.f}, ""}; + + ConfigurableAxis binsPtZHe{"binsPtZHe", {VARIABLE_WIDTH, 0.5, 0.625, 0.75, 0.875, 1.0, 1.125, 1.25, 1.375, 1.5, 1.625, 1.75, 1.875, 2.0, 2.25, 2.5, 3.0, 3.5, 4.0}, ""}; + + Configurable applySkim{"applySkim", false, "Apply skimming"}; + Configurable cfgSkim{"cfgSkim", "fHighFt0Mult", "Configurable for skimming"}; + + static constexpr float gMassProton = 0.93827208f; + static constexpr float gMassDeuteron = 1.87561f; + static constexpr float gMassTriton = 2.80892f; + static constexpr float gMassHelium = 2.80839f; + static constexpr int PDGProton = 2212; + static constexpr int PDGDeuteron = 1000010020; + static constexpr int PDGTriton = 1000010030; + static constexpr int PDGHelium = 1000020030; + + using EventCandidates = soa::Join; // , aod::CentFT0Ms, aod::CentFT0As, aod::CentFT0Cs + using TrackCandidates = soa::Join; + using TrackCandidatesLfPid = soa::Join; + using TrackCandidatesMC = soa::Join; + + Filter jetCuts = aod::jet::pt > cfgjetPtMin&& aod::jet::r == nround(cfgjetR.node() * 100.0f); + + using chargedJetstrack = soa::Filtered>; + using JetMCPartTable = soa::Filtered>; + using JetMCDetTable = soa::Filtered>; + + SliceCache cache; + HistogramRegistry jetHist{"jetHist", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + Service ccdb; + TRandom3 randUniform; + + void init(o2::framework::InitContext&) + { + + if (doprocessJetTracksData && doprocessJetTracksDataLfPid) { + LOGP(fatal, "only one process function should be enabled!!!"); + } + const AxisSpec PtAxis = {100, 0, 10.0}; + const AxisSpec PtJetAxis = {100, 0, 100.0}; + const AxisSpec MultAxis = {100, 0, 100}; + const AxisSpec dRAxis = {100, 0, 3.6}; + const AxisSpec dcaxyAxis{binsDCA, "DCAxy (cm)"}; + const AxisSpec dcazAxis{binsDCA, "DCAz (cm)"}; + const AxisSpec dedxAxis{binsdEdx, "d#it{E}/d#it{x} A.U."}; + + const AxisSpec betaAxis{binsBeta, "TOF #beta"}; + const AxisSpec ptZHeAxis{binsPtZHe, "#it{p}_{T}"}; + + const AxisSpec massPrAxis{binsMassPr, ""}; + const AxisSpec massDeAxis{binsMassDe, ""}; + const AxisSpec massTrAxis{binsMassTr, ""}; + const AxisSpec massHeAxis{binsMassHe, ""}; + + if (applySkim) { + jetHist.add("hNEvents", "hNEvents", {HistType::kTH1D, {{6, 0.f, 6.f}}}); + jetHist.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(1, "All"); + jetHist.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(2, "Skimmed"); + jetHist.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(3, "|Vz|<10"); + jetHist.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(4, "Sel8+|Vz|<10"); + jetHist.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(5, "nJets>0"); + } + + // jet property + jetHist.add("jet/h1JetPt", "jet_{p_{T}}", kTH1F, {PtJetAxis}); + jetHist.add("jet/h1JetEvents", "NumbeOfJetEvents", kTH1F, {{1, 0, 1}}); + jetHist.add("jet/h1JetEta", "jet_{#eta}", kTH1F, {{100, -1.0, 1.0}}); + jetHist.add("jet/h1JetPhi", "jet_{#phi}", kTH1F, {{80, -1.0, 7.}}); + jetHist.add("jet/nJetsPerEvent", "nJetsPerEvent", kTH1F, {{15, .0, 15.}}); + jetHist.add("mcpJet/nJetsPerEvent", "nJetsPerEvent", kTH1F, {{15, .0, 15.}}); + jetHist.add("mcdJet/nJetsPerEvent", "nJetsPerEvent", kTH1F, {{15, .0, 15.}}); + jetHist.add("jet/vertexZ", "vertexZ (Jet flag)", kTH1F, {{100, -15.0, 15.0}}); + jetHist.add("vertexZ", "vertexZ (all)", kTH1F, {{100, -15.0, 15.0}}); + jetHist.add("jetOut/vertexZ", "vertexZ (without z-flag)", kTH1F, {{100, -15.0, 15.0}}); + //////////////////////////// + // MC + //////////////////////////// + jetHist.add("mcpJet/eventStat", "vertexZ (All)", kTH1F, {{5, .0, 5.0}}); + auto h = jetHist.get(HIST("mcpJet/eventStat")); + h->GetXaxis()->SetBinLabel(1, "All"); + h->GetXaxis()->SetBinLabel(2, "Sel8-goodRecJet"); + h->GetXaxis()->SetBinLabel(3, "vz < 10"); + h->GetXaxis()->SetBinLabel(4, "ingt0"); + + jetHist.add("mcpJet/vertexZ", "vertexZ (All)", kTH1F, {{100, -15.0, 15.0}}); + jetHist.add("mcdJet/vertexZ", "vertexZ (All)", kTH1F, {{100, -15.0, 15.0}}); + jetHist.add("mcdJet/eventStat", "vertexZ (All)", kTH1F, {{5, .0, 5.0}}); + auto h1 = jetHist.get(HIST("mcdJet/eventStat")); + h1->GetXaxis()->SetBinLabel(1, "All"); + h1->GetXaxis()->SetBinLabel(2, "Sel8-goodRecJet"); + h1->GetXaxis()->SetBinLabel(3, "vz< 10"); + h1->GetXaxis()->SetBinLabel(4, "ingt0"); + + jetHist.add("recmatched/vertexZ", "vertexZ (All)", kTH1F, {{100, -15.0, 15.0}}); + jetHist.add("genmatched/vertexZ", "vertexZ (All)", kTH1F, {{100, -15.0, 15.0}}); + + ////////////////////////////////////////////// + // inside jet + ////////////////////////////////////////////// + if (addpik) { + jetHist.add("tracks/pion/h3PtVsPionNSigmaTPCVsPtJet_jet", "pT(p) vs NSigmaTPC (p) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/antiPion/h3PtVsPionNSigmaTPCVsPtJet_jet", "pT(p) vs NSigmaTPC (p) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/kaon/h3PtVsKaonNSigmaTPCVsPtJet_jet", "pT(p) vs NSigmaTPC (p) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/antiKaon/h3PtVsKaonNSigmaTPCVsPtJet_jet", "pT(p) vs NSigmaTPC (p) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + } + jetHist.add("tracks/proton/h3PtVsProtonNSigmaTPCVsPtJet_jet", "pT(p) vs NSigmaTPC (p) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJet_jet", "pT(#bar{p}) vs NSigmaTPC (#bar{p}) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJet_jet", "pT(d) vs NSigmaTPC (d) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJet_jet", "pT(#bar{d}) vs NSigmaTPC (#bar{d}) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/helium/h3PtVsHeliumNSigmaTPCVsPtJet_jet", "pT(He) vs NSigmaTPC (He) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJet_jet", "pT(#bar{He}) vs NSigmaTPC (#bar{He}) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/triton/h3PtVsTritonNSigmaTPCVsPtJet_jet", "pT(Tr) vs NSigmaTPC (Tr) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJet_jet", "pT(#bar{Tr}) vs NSigmaTPC (#bar{Tr}) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + + if (cEnableProtonQA) { + jetHist.add("tracks/proton/dca/after/hDCAxyVsPtProton_jet", "DCAxy vs Pt (p)", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/antiProton/dca/after/hDCAxyVsPtantiProton_jet", "DCAxy vs Pt (#bar{p})", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/proton/dca/after/hDCAzVsPtProton_jet", "DCAz vs Pt (p)", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + jetHist.add("tracks/antiProton/dca/after/hDCAzVsPtantiProton_jet", "DCAz vs Pt (#bar{p})", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + } + + if (cEnableDeuteronQA) { + jetHist.add("tracks/deuteron/dca/after/hDCAxyVsPtDeuteron_jet", "DCAxy vs Pt (d)", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/antiDeuteron/dca/after/hDCAxyVsPtantiDeuteron_jet", "DCAxy vs Pt (#bar{d})", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/deuteron/dca/after/hDCAzVsPtDeuteron_jet", "DCAz vs Pt (d)", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + jetHist.add("tracks/antiDeuteron/dca/after/hDCAzVsPtantiDeuteron_jet", "DCAz vs Pt (#bar{d})", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + } + + if (cEnableTritonQA) { + jetHist.add("tracks/triton/dca/after/hDCAxyVsPtTriton_jet", "DCAxy vs Pt (t)", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/antiTriton/dca/after/hDCAxyVsPtantiTriton_jet", "DCAxy vs Pt (#bar{t})", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/triton/dca/after/hDCAzVsPtTriton_jet", "DCAz vs Pt (t)", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + jetHist.add("tracks/antiTriton/dca/after/hDCAzVsPtantiTriton_jet", "DCAz vs Pt (#bar{t})", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + } + if (cEnableHeliumQA) { + jetHist.add("tracks/helium/dca/after/hDCAxyVsPtHelium_jet", "DCAxy vs Pt (He)", HistType::kTH2F, {{dcaxyAxis}, {450, 0.5f, 5.f}}); + jetHist.add("tracks/antiHelium/dca/after/hDCAxyVsPtantiHelium_jet", "DCAxy vs Pt (#bar{He})", HistType::kTH2F, {{dcaxyAxis}, {450, 0.5f, 5.f}}); + jetHist.add("tracks/helium/dca/after/hDCAzVsPtHelium_jet", "DCAz vs Pt (He)", HistType::kTH2F, {{dcazAxis}, {450, 0.5f, 5.f}}); + jetHist.add("tracks/antiHelium/dca/after/hDCAzVsPtantiHelium_jet", "DCAz vs Pt (#bar{He})", HistType::kTH2F, {{dcazAxis}, {450, 0.5f, 5.f}}); + } + + jetHist.add("tracks/h2TPCsignVsTPCmomentum", "TPC <-dE/dX> vs #it{p}/Z;#it{p}/Z (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{500, -5.f, 5.f}, {dedxAxis}}); + jetHist.add("tracks/h2TPCsignVsTPCmomentum_Jet", "TPC <-dE/dX> vs #it{p}/Z;#it{p}/Z (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{500, -5.f, 5.f}, {dedxAxis}}); + jetHist.add("tracks/h2TPCsignVsTPCmomentum_OutJet", "TPC <-dE/dX> vs #it{p}/Z;#it{p}/Z (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{500, -5.f, 5.f}, {dedxAxis}}); + jetHist.add("tracks/perpCone/h2TPCsignVsTPCmomentum", "TPC <-dE/dX> vs #it{p}/Z;#it{p}/Z (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{500, -5.f, 5.f}, {dedxAxis}}); + + jetHist.add("tracks/h2TOFbetaVsP_Jet", "TOF #beta vs #it{p}/Z; #it{p}/Z (GeV/#it{c}); TOF #beta", HistType::kTH2F, {{250, -5.f, 5.f}, {betaAxis}}); + jetHist.add("tracks/h2TOFbetaVsP_OutJet", "TOF #beta vs #it{p}/Z; #it{p}/Z (GeV/#it{c}); TOF #beta", HistType::kTH2F, {{250, -5.f, 5.f}, {betaAxis}}); + jetHist.add("tracks/h2TOFbetaVsP", "TOF #beta vs #it{p}/Z; #it{p}/Z (GeV/#it{c}); TOF #beta", HistType::kTH2F, {{250, -5.f, 5.f}, {betaAxis}}); + + // TOF hist + jetHist.add("tracks/proton/h2TOFmassProtonVsPt_jet", "h2TOFmassProtonVsPt_jet; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{80, 0.4, 4.}, {50, 0., 5.}}); + jetHist.add("tracks/antiProton/h2TOFmassantiProtonVsPt_jet", "h2TOFmassantiProtonVsPt_jet; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{80, 0.4, 4.}, {50, 0., 5.}}); + jetHist.add("tracks/proton/h2TOFmass2ProtonVsPt_jet", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV)", HistType::kTH2F, {{massPrAxis}, {250, 0., 5.}}); + jetHist.add("tracks/antiProton/h2TOFmass2antiProtonVsPt_jet", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV)", HistType::kTH2F, {{massPrAxis}, {250, 0., 5.}}); + + jetHist.add("tracks/deuteron/h2TOFmassDeuteronVsPt_jet", "h2TOFmassDeuteronVsPt_jet; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{80, 0.4, 4.}, {50, 0., 5.}}); + jetHist.add("tracks/antiDeuteron/h2TOFmassantiDeuteronVsPt_jet", "h2TOFmassantiDeuteronVsPt_jet; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{80, 0.4, 4.}, {50, 0., 5.}}); + jetHist.add("tracks/deuteron/h2TOFmass2DeuteronVsPt_jet", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV)", HistType::kTH2F, {{massDeAxis}, {250, 0., 5.}}); + jetHist.add("tracks/antiDeuteron/h2TOFmass2antiDeuteronVsPt_jet", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV)", HistType::kTH2F, {{massDeAxis}, {250, 0., 5.}}); + + jetHist.add("tracks/triton/h2TOFmassTritonVsPt_jet", "h2TOFmassTritonVsPt_jet; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{80, 0.4, 4.}, {50, 0., 5.}}); + jetHist.add("tracks/antiTriton/h2TOFmassantiTritonVsPt_jet", "h2TOFmassantiTritonVsPt_jet; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{80, 0.4, 4.}, {50, 0., 5.}}); + jetHist.add("tracks/triton/h2TOFmass2TritonVsPt_jet", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV)", HistType::kTH2F, {{massTrAxis}, {250, 0., 5.}}); + jetHist.add("tracks/antiTriton/h2TOFmass2antiTritonVsPt_jet", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV)", HistType::kTH2F, {{massTrAxis}, {250, 0., 5.}}); + + jetHist.add("tracks/helium/h2TOFmassHeliumVsPt_jet", "h2TOFmassHeliumVsPt_jet; TOFmass; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {ptZHeAxis}}); + jetHist.add("tracks/antiHelium/h2TOFmassantiHeliumVsPt_jet", "h2TOFmassantiHeliumVsPt_jet; TOFmass; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {ptZHeAxis}}); + jetHist.add("tracks/helium/h2TOFmass2HeliumVsPt_jet", "#Delta M^{2} (t) vs #it{p}_{T}t; TOFmass2; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{massHeAxis}, {ptZHeAxis}}); + jetHist.add("tracks/antiHelium/h2TOFmass2antiHeliumVsPt_jet", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{massHeAxis}, {ptZHeAxis}}); + + // TOF hist nSigma + if (addpik) { + jetHist.add("tracks/pion/h2TofNsigmaPionVsPt_jet", "h2TofNsigmaPionVsPt_jet; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/antiPion/h2TofNsigmaantiPionVsPt_jet", "h2TofNsigmaantiPionVsPt_jet; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/kaon/h2TofNsigmaKaonVsPt_jet", "h2TofNsigmaKaonVsPt_jet; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/antiKaon/h2TofNsigmaantiKaonVsPt_jet", "h2TofNsigmaantiKaonVsPt_jet; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + } + jetHist.add("tracks/proton/h2TofNsigmaProtonVsPt_jet", "h2TofNsigmaProtonVsPt_jet; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/antiProton/h2TofNsigmaantiProtonVsPt_jet", "h2TofNsigmaantiProtonVsPt_jet; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/deuteron/h2TofNsigmaDeuteronVsPt_jet", "h2TofNsigmaDeuteronVsPt_jet; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/antiDeuteron/h2TofNsigmaantiDeuteronVsPt_jet", "h2TofNsigmaantiDeuteronVsPt_jet; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/triton/h2TofNsigmaTritonVsPt_jet", "h2TofNsigmaTritonVsPt_jet; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/antiTriton/h2TofNsigmaantiTritonVsPt_jet", "h2TofNsigmaantiTritonVsPt_jet; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/helium/h2TofNsigmaHeliumVsPt_jet", "h2TofNsigmaHeliumVsPt_jet; TofNsigma; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/antiHelium/h2TofNsigmaantiHeliumVsPt_jet", "h2TofNsigmaantiHeliumVsPt_jet; TofNsigma; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + + jetHist.add("tracks/proton/h3TpcNsigmaTofNsigmaProtonVsPt_jet", "h3TpcNsigmaTofNsigmaProtonVsPt_jet; TpcNsigma; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH3F, {{100, -5., 5.}, {100, -5., 5.}, {50, 0., 5.}}); + jetHist.add("tracks/antiProton/h3TpcNsigmaTofNsigmaantiProtonVsPt_jet", "h3TpcNsigmaTofNsigmaantiProtonVsPt_jet; TpcNsigma; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH3F, {{100, -5., 5.}, {100, -5., 5.}, {50, 0., 5.}}); + jetHist.add("tracks/deuteron/h3TpcNsigmaTofNsigmaDeuteronVsPt_jet", "h3TpcNsigmaTofNsigmaDeuteronVsPt_jet; TpcNsigma; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH3F, {{100, -5., 5.}, {100, -5., 5.}, {50, 0., 5.}}); + jetHist.add("tracks/antiDeuteron/h3TpcNsigmaTofNsigmaantiDeuteronVsPt_jet", "h3TpcNsigmaTofNsigmaantiDeuteronVsPt_jet; TpcNsigma; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH3F, {{100, -5., 5.}, {100, -5., 5.}, {50, 0., 5.}}); + + ///////////// + // perp cone + ///////////// + jetHist.add("tracks/perpCone/proton/h2TofNsigmaProtonVsPt", "h2TofNsigmaProtonVsPt; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/perpCone/antiProton/h2TofNsigmaantiProtonVsPt", "h2TofNsigmaantiProtonVsPt; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/perpCone/deuteron/h2TofNsigmaDeuteronVsPt", "h2TofNsigmaDeuteronVsPt; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/perpCone/antiDeuteron/h2TofNsigmaantiDeuteronVsPt", "h2TofNsigmaantiDeuteronVsPt; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/perpCone/triton/h2TofNsigmaTritonVsPt", "h2TofNsigmaTritonVsPt; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/perpCone/antiTriton/h2TofNsigmaantiTritonVsPt", "h2TofNsigmaantiTritonVsPt; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/perpCone/helium/h2TofNsigmaHeliumVsPt", "h2TofNsigmaHeliumVsPt; TofNsigma; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/perpCone/antiHelium/h2TofNsigmaantiHeliumVsPt", "h2TofNsigmaantiHeliumVsPt; TofNsigma; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + ////////////////////////////////////////////// + // outside jet + ////////////////////////////////////////////// + jetHist.add("tracks/proton/h3PtVsProtonNSigmaTPC", "pT(p) vs NSigmaTPC (p); #it{p}_{T} (GeV/#it{c}; NSigmaTPC;", HistType::kTH2F, {{PtAxis}, {200, -10, 10}}); + jetHist.add("tracks/antiProton/h3PtVsantiProtonNSigmaTPC", "pT(#bar{p}) vs NSigmaTPC (#bar{p}); #it{p}_{T} (GeV/#it{c}; NSigmaTPC;", HistType::kTH2F, {{PtAxis}, {200, -10, 10}}); + jetHist.add("tracks/deuteron/h3PtVsDeuteronNSigmaTPC", "pT(d) vs NSigmaTPC (d); #it{p}_{T} (GeV/#it{c}; NSigmaTPC;", HistType::kTH2F, {{PtAxis}, {200, -10, 10}}); + jetHist.add("tracks/antiDeuteron/h3PtVsantiDeuteronNSigmaTPC", "pT(#bar{d}) vs NSigmaTPC (#bar{d}); #it{p}_{T} (GeV/#it{c}; NSigmaTPC;", HistType::kTH2F, {{PtAxis}, {200, -10, 10}}); + jetHist.add("tracks/helium/h3PtVsHeliumNSigmaTPC", "pT(He) vs NSigmaTPC (He); #it{p}_{T} (GeV/#it{c}; NSigmaTPC;", HistType::kTH2F, {{PtAxis}, {200, -10, 10}}); + jetHist.add("tracks/antiHelium/h3PtVsantiHeliumNSigmaTPC", "pT(#bar{He}) vs NSigmaTPC (#bar{He}); #it{p}_{T} (GeV/#it{c}; NSigmaTPC;", HistType::kTH2F, {{PtAxis}, {200, -10, 10}}); + jetHist.add("tracks/triton/h3PtVsTritonNSigmaTPC", "pT(Tr) vs NSigmaTPC(Tr); #it{p}_{T} (GeV/#it{c}; NSigmaTPC;", HistType::kTH2F, {{PtAxis}, {200, -10, 10}}); + jetHist.add("tracks/antiTriton/h3PtVsantiTritonNSigmaTPC", "pT(#barTr}) vs NSigmaTPC (#bar{Tr}); #it{p}_{T} (GeV/#it{c}; NSigmaTPC;", HistType::kTH2F, {{PtAxis}, {200, -10, 10}}); + + jetHist.add("tracks/perpCone/proton/h3PtVsProtonNSigmaTPCVsPtJet", "pT(p) vs NSigmaTPC (p) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJet", "pT(#bar{p}) vs NSigmaTPC (#bar{p}) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJet", "pT(d) vs NSigmaTPC (d) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJet", "pT(#bar{d}) vs NSigmaTPC (#bar{d}) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/helium/h3PtVsHeliumNSigmaTPCVsPtJet", "pT(He) vs NSigmaTPC (He) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJet", "pT(#bar{He}) vs NSigmaTPC (#bar{He}) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/triton/h3PtVsTritonNSigmaTPCVsPtJet", "pT(Tr) vs NSigmaTPC (Tr) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJet", "pT(#bar{Tr}) vs NSigmaTPC (#bar{Tr}) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + + if (cEnableProtonQA) { + jetHist.add("tracks/proton/dca/after/hDCAxyVsPtProton", "DCAxy vs Pt (p)", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/antiProton/dca/after/hDCAxyVsPtantiProton", "DCAxy vs Pt (#bar{p})", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/proton/dca/after/hDCAzVsPtProton", "DCAz vs Pt (p)", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + jetHist.add("tracks/antiProton/dca/after/hDCAzVsPtantiProton", "DCAz vs Pt (#bar{p})", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + } + if (cEnableDeuteronQA) { + jetHist.add("tracks/deuteron/dca/after/hDCAxyVsPtDeuteron", "DCAxy vs Pt (d)", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/antiDeuteron/dca/after/hDCAxyVsPtantiDeuteron", "DCAxy vs Pt (#bar{d})", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/deuteron/dca/after/hDCAzVsPtDeuteron", "DCAz vs Pt (d)", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + jetHist.add("tracks/antiDeuteron/dca/after/hDCAzVsPtantiDeuteron", "DCAz vs Pt (#bar{d})", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + } + if (cEnableTritonQA) { + jetHist.add("tracks/triton/dca/after/hDCAxyVsPtTriton", "DCAxy vs Pt (t)", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/antiTriton/dca/after/hDCAxyVsPtantiTriton", "DCAxy vs Pt (#bar{t})", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/triton/dca/after/hDCAzVsPtTriton", "DCAz vs Pt (t)", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + jetHist.add("tracks/antiTriton/dca/after/hDCAzVsPtantiTriton", "DCAz vs Pt (#bar{t})", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + } + if (cEnableHeliumQA) { + jetHist.add("tracks/helium/dca/after/hDCAxyVsPtHelium", "DCAxy vs Pt (He)", HistType::kTH2F, {{dcaxyAxis}, {450, 0.5f, 5.f}}); + jetHist.add("tracks/antiHelium/dca/after/hDCAxyVsPtantiHelium", "DCAxy vs Pt (#bar{He})", HistType::kTH2F, {{dcaxyAxis}, {450, 0.5f, 5.f}}); + jetHist.add("tracks/helium/dca/after/hDCAzVsPtHelium", "DCAz vs Pt (He)", HistType::kTH2F, {{dcazAxis}, {450, 0.5f, 5.f}}); + jetHist.add("tracks/antiHelium/dca/after/hDCAzVsPtantiHelium", "DCAz vs Pt (#bar{He})", HistType::kTH2F, {{dcazAxis}, {450, 0.5f, 5.f}}); + } + + // TOF hist #DeltaMass2 + jetHist.add("tracks/proton/h2TOFmassProtonVsPt", "h2TOFmassProtonVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{80, 0.4, 4.}, {50, 0., 5.}}); + jetHist.add("tracks/antiProton/h2TOFmassantiProtonVsPt", "h2TOFmassantiProtonVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{80, 0.4, 4.}, {50, 0., 5.}}); + jetHist.add("tracks/proton/h2TOFmass2ProtonVsPt", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV)", HistType::kTH2F, {{massPrAxis}, {250, 0., 5.}}); + jetHist.add("tracks/antiProton/h2TOFmass2antiProtonVsPt", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV)", HistType::kTH2F, {{massPrAxis}, {250, 0., 5.}}); + + jetHist.add("tracks/deuteron/h2TOFmassDeuteronVsPt", "h2TOFmassDeuteronVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{80, 0.4, 4.}, {50, 0., 5.}}); + jetHist.add("tracks/antiDeuteron/h2TOFmassantiDeuteronVsPt", "h2TOFmassantiDeuteronVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{80, 0.4, 4.}, {50, 0., 5.}}); + jetHist.add("tracks/deuteron/h2TOFmass2DeuteronVsPt", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV)", HistType::kTH2F, {{massDeAxis}, {250, 0., 5.}}); + jetHist.add("tracks/antiDeuteron/h2TOFmass2antiDeuteronVsPt", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV)", HistType::kTH2F, {{massDeAxis}, {250, 0., 5.}}); + + jetHist.add("tracks/triton/h2TOFmassTritonVsPt", "h2TOFmassTritonVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{80, 0.4, 4.}, {50, 0., 5.}}); + jetHist.add("tracks/antiTriton/h2TOFmassantiTritonVsPt", "h2TOFmassantiTritonVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{80, 0.4, 4.}, {50, 0., 5.}}); + jetHist.add("tracks/triton/h2TOFmass2TritonVsPt", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV)", HistType::kTH2F, {{massTrAxis}, {250, 0., 5.}}); + jetHist.add("tracks/antiTriton/h2TOFmass2antiTritonVsPt", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV)", HistType::kTH2F, {{massTrAxis}, {250, 0., 5.}}); + + jetHist.add("tracks/helium/h2TOFmassHeliumVsPt", "h2TOFmassHeliumVsPt; TOFmass; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {ptZHeAxis}}); + jetHist.add("tracks/antiHelium/h2TOFmassantiHeliumVsPt", "h2TOFmassantiHeliumVsPt; TOFmass; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {ptZHeAxis}}); + jetHist.add("tracks/helium/h2TOFmass2HeliumVsPt", "#Delta M^{2} (t) vs #it{p}_{T}t; TOFmass2; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{massHeAxis}, {ptZHeAxis}}); + jetHist.add("tracks/antiHelium/h2TOFmass2antiHeliumVsPt", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{massHeAxis}, {ptZHeAxis}}); + + // TOF hist nSigma + jetHist.add("tracks/proton/h2TofNsigmaProtonVsPt", "h2TofNsigmaProtonVsPt; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/antiProton/h2TofNsigmaantiProtonVsPt", "h2TofNsigmaantiProtonVsPt; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/deuteron/h2TofNsigmaDeuteronVsPt", "h2TofNsigmaDeuteronVsPt; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/antiDeuteron/h2TofNsigmaantiDeuteronVsPt", "h2TofNsigmaantiDeuteronVsPt; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/triton/h2TofNsigmaTritonVsPt", "h2TofNsigmaTritonVsPt; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/antiTriton/h2TofNsigmaantiTritonVsPt", "h2TofNsigmaantiTritonVsPt; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/helium/h2TofNsigmaHeliumVsPt", "h2TofNsigmaHeliumVsPt; TofNsigma; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + jetHist.add("tracks/antiHelium/h2TofNsigmaantiHeliumVsPt", "h2TofNsigmaantiHeliumVsPt; TofNsigma; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{100, -5, 5}, {50, 0., 5.}}); + + if (isMC) { + // inside jet + jetHist.add("tracks/mc/proton/h3PtVsProtonNSigmaTPCVsPtJet_jet", "pT(p) vs NSigmaTPC (p) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/mc/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJet_jet", "pT(#bar{p}) vs NSigmaTPC (#bar{p}) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/mc/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJet_jet", "pT(d) vs NSigmaTPC (d) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/mc/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJet_jet", "pT(#bar{d}) vs NSigmaTPC (#bar{d}) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/mc/helium/h3PtVsHeliumNSigmaTPCVsPtJet_jet", "pT(He) vs NSigmaTPC (He) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/mc/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJet_jet", "pT(#bar{He}) vs NSigmaTPC (#bar{He}) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/mc/triton/h3PtVsTritonNSigmaTPCVsPtJet_jet", "pT(Tr) vs NSigmaTPC (Tr) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/mc/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJet_jet", "pT(#bar{Tr}) vs NSigmaTPC (#bar{Tr}) vs jet pT; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T}", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + + if (cEnableProtonQA) { + jetHist.add("tracks/proton/dca/before/hDCAxyVsPtProton_jet", "DCAxy vs Pt (p)", HistType::kTH2F, {{PtAxis}, {dcaxyAxis}}); + jetHist.add("tracks/antiProton/dca/before/hDCAxyVsPtantiProton_jet", "DCAxy vs Pt (#bar{p})", HistType::kTH2F, {{PtAxis}, {dcaxyAxis}}); + jetHist.add("tracks/proton/dca/before/hDCAzVsPtProton_jet", "DCAz vs Pt (p)", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + jetHist.add("tracks/antiProton/dca/before/hDCAzVsPtantiProton_jet", "DCAz vs Pt (#bar{p})", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + } + + if (cEnableDeuteronQA) { + jetHist.add("tracks/deuteron/dca/before/hDCAxyVsPtDeuteron_jet", "DCAxy vs Pt (d)", HistType::kTH2F, {{PtAxis}, {dcaxyAxis}}); + jetHist.add("tracks/antiDeuteron/dca/before/hDCAxyVsPtantiDeuteron_jet", "DCAxy vs Pt (#bar{d})", HistType::kTH2F, {{PtAxis}, {dcaxyAxis}}); + jetHist.add("tracks/deuteron/dca/before/hDCAzVsPtDeuteron_jet", "DCAz vs Pt (d)", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + jetHist.add("tracks/antiDeuteron/dca/before/hDCAzVsPtantiDeuteron_jet", "DCAz vs Pt (#bar{d})", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + } + + if (cEnableTritonQA) { + jetHist.add("tracks/triton/dca/before/hDCAxyVsPtTriton_jet", "DCAxy vs Pt (t)", HistType::kTH2F, {{PtAxis}, {dcaxyAxis}}); + jetHist.add("tracks/antiTriton/dca/before/hDCAxyVsPtantiTriton_jet", "DCAxy vs Pt (#bar{t})", HistType::kTH2F, {{PtAxis}, {dcaxyAxis}}); + jetHist.add("tracks/triton/dca/before/hDCAzVsPtTriton_jet", "DCAz vs Pt (t)", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + jetHist.add("tracks/antiTriton/dca/before/hDCAzVsPtantiTriton_jet", "DCAz vs Pt (#bar{t})", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + } + + if (cEnableHeliumQA) { + jetHist.add("tracks/helium/dca/before/hDCAxyVsPtHelium_jet", "DCAxy vs Pt (He)", HistType::kTH2F, {{dcaxyAxis}, {450, 0.5f, 5.f}}); + jetHist.add("tracks/antiHelium/dca/before/hDCAxyVsPtantiHelium_jet", "DCAxy vs Pt (#bar{He})", HistType::kTH2F, {{dcaxyAxis}, {450, 0.5f, 5.f}}); + jetHist.add("tracks/helium/dca/before/hDCAzVsPtHelium_jet", "DCAz vs Pt (He)", HistType::kTH2F, {{dcazAxis}, {450, 0.5f, 5.f}}); + jetHist.add("tracks/antiHelium/dca/before/hDCAzVsPtantiHelium_jet", "DCAz vs Pt (#bar{He})", HistType::kTH2F, {{dcazAxis}, {450, 0.5f, 5.f}}); + } + + // outside jet + if (cEnableProtonQA) { + jetHist.add("tracks/proton/dca/before/hDCAxyVsPtProton", "DCAxy vs Pt (p)", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/antiProton/dca/before/hDCAxyVsPtantiProton", "DCAxy vs Pt (#bar{p})", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/proton/dca/before/hDCAzVsPtProton", "DCAz vs Pt (p)", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + jetHist.add("tracks/antiProton/dca/before/hDCAzVsPtantiProton", "DCAz vs Pt (#bar{p})", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + } + + if (cEnableDeuteronQA) { + jetHist.add("tracks/deuteron/dca/before/hDCAxyVsPtDeuteron", "DCAxy vs Pt (d)", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/antiDeuteron/dca/before/hDCAxyVsPtantiDeuteron", "DCAxy vs Pt (#bar{d})", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/deuteron/dca/before/hDCAzVsPtDeuteron", "DCAz vs Pt (d)", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + jetHist.add("tracks/antiDeuteron/dca/before/hDCAzVsPtantiDeuteron", "DCAz vs Pt (#bar{d})", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + } + + if (cEnableTritonQA) { + jetHist.add("tracks/triton/dca/before/hDCAxyVsPtTriton", "DCAxy vs Pt (t)", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/antiTriton/dca/before/hDCAxyVsPtantiTriton", "DCAxy vs Pt (#bar{t})", HistType::kTH2F, {{dcaxyAxis}, {PtAxis}}); + jetHist.add("tracks/triton/dca/before/hDCAzVsPtTriton", "DCAz vs Pt (t)", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + jetHist.add("tracks/antiTriton/dca/before/hDCAzVsPtantiTriton", "DCAz vs Pt (#bar{t})", HistType::kTH2F, {{dcazAxis}, {PtAxis}}); + } + + if (cEnableHeliumQA) { + jetHist.add("tracks/helium/dca/before/hDCAxyVsPtHelium", "DCAxy vs Pt (He)", HistType::kTH2F, {{450, 0.5f, 5.f}, {dcaxyAxis}}); + jetHist.add("tracks/antiHelium/dca/before/hDCAxyVsPtantiHelium", "DCAxy vs Pt (#bar{He})", HistType::kTH2F, {{450, 0.5f, 5.f}, {dcaxyAxis}}); + jetHist.add("tracks/helium/dca/before/hDCAzVsPtHelium", "DCAz vs Pt (He)", HistType::kTH2F, {{dcazAxis}, {450, 0.5f, 5.f}}); + jetHist.add("tracks/antiHelium/dca/before/hDCAzVsPtantiHelium", "DCAz vs Pt (#bar{He})", HistType::kTH2F, {{dcazAxis}, {450, 0.5f, 5.f}}); + } + + // PartilceJet-constituents + jetHist.add("mcpJet/pt/PtParticleType", "Pt (p) vs jetflag vs particletype", HistType::kTH3D, {{100, 0.f, 10.f}, {2, 0, 2}, {14, -7, 7}}); + // detectorJet-constituents + jetHist.add("mcdJet/pt/PtParticleType", "Pt (p) vs jetflag vs particletype", HistType::kTH3D, {{100, 0.f, 10.f}, {2, 0, 2}, {14, -7, 7}}); + jetHist.add("mcdJet/pt/perpCone/PtParticleType", "Pt (p) vs particletype", HistType::kTH2D, {{100, 0.f, 10.f}, {14, -7, 7}}); + + jetHist.add("mcpJet/hJetPt", "Pt (jet)", HistType::kTH1F, {{100, 0.f, 50.f}}); + jetHist.add("mcpJet/hJetEta", "Eta (jet)", HistType::kTH1F, {{100, 1.5, 1.5}}); + jetHist.add("mcpJet/hJetPhi", "Phi (jet)", HistType::kTH1F, {{70, 0.f, 7.f}}); + + jetHist.add("mcdJet/hJetPt", "Pt (jet)", HistType::kTH1F, {{100, 0.f, 50.f}}); + jetHist.add("mcdJet/hJetEta", "Eta (jet)", HistType::kTH1F, {{100, 1.5, 1.5}}); + jetHist.add("mcdJet/hJetPhi", "Phi (jet)", HistType::kTH1F, {{70, 0.f, 7.f}}); + + // rec matched + jetHist.add("recmatched/hRecMatchedJetPt", "matched jet pT (Rec level);#it{p}_{T,jet part} (GeV/#it{c}); #it{p}_{T,jet part} - #it{p}_{T,jet det}", HistType::kTH2F, {{100, 0., 100.}, {400, -20., 20.}}); + jetHist.add("recmatched/hRecMatchedVsGenJetPtVsEta", "matched jet pT vs #eta (Rec level); #it{p}_{T,jet det}; #eta_{jet}", HistType::kTH2F, {{100, 0., 100.}, {200, -1., 1.}}); + jetHist.add("recmatched/hRecMatchedJetPhi", "matched jet #varphi (Rec level);#varphi_{T,jet part}; #varphi_{jet part}-#varphi_{jet det}", HistType::kTH2F, {{700, 0., 7.}, {200, -5., 5.}}); + jetHist.add("recmatched/hRecMatchedJetEta", "matched jet #eta (Rec level);#eta_{T,jet part}; #eta_{jet part}-#eta_{jet det} ", HistType::kTH2F, {{200, -1., 1.}, {500, -2.5, 2.5}}); + + jetHist.add("recmatched/h2ResponseMatrix", "matched jet pT;#it{p}_{T} (mes.); #it{p}_{T} (true)", HistType::kTH2F, {{100, 0., 100.}, {100, 0., 100.}}); + jetHist.add("recmatched/h2ResponseMatrixLeadingJet", "matched jet rec pT vs true pt;#it{p}_{T} (mes.); #it{p}_{T} (true)", HistType::kTH2F, {{100, 0., 100.}, {100, 0., 100.}}); + jetHist.add("recmatched/mcC/h2ResponseMatrixLeadingJet", "matched jet rec pT vs true pt;#it{p}_{T} (mes.); #it{p}_{T} (true)", HistType::kTH2F, {{100, 0., 100.}, {100, 0., 100.}}); + + ///////// + jetHist.add("recmatched/hRecJetPt", "matched jet pT (Rec level);#it{p}_{T,jet part} (GeV/#it{c}); #it{p}_{T,jet part} - #it{p}_{T,jet det}", HistType::kTH1F, {{100, 0., 100.}}); + jetHist.add("recmatched/hGenJetPt", "matched jet pT (Rec level);#it{p}_{T,jet part} (GeV/#it{c}); #it{p}_{T,jet part} - #it{p}_{T,jet det}", HistType::kTH1F, {{100, 0., 100.}}); + jetHist.add("recmatched/pt/PtParticleType", "Pt (p) vs jetflag vs particletype", HistType::kTH3D, {{100, 0.f, 10.f}, {2, 0, 2}, {14, -7, 7}}); + + jetHist.add("eff/recmatched/pt/PtParticleType", "Pt (p) vs jetflag vs particletype", HistType::kTH3D, {{100, 0.f, 10.f}, {2, 0, 2}, {14, -7, 7}}); + jetHist.add("eff/recmatched/mcC/pt/PtParticleType", "Pt (pt, rec) vs Pt (pt, true) vs particletype", HistType::kTH3D, {{100, 0.f, 10.f}, {100, 0.f, 10.f}, {14, -7, 7}}); + jetHist.add("eff/recmatched/mcCSpectra/pt/PtParticleType", "Pt (pt) vs Pt (pt, true) vs particletype", HistType::kTH3D, {{100, 0.f, 10.f}, {100, 0.f, 10.f}, {14, -7, 7}}); + jetHist.add("eff/recmatched/pt/PtParticleTypeTPC", "Pt (p) vs jetflag vs particletype", HistType::kTH3D, {{100, 0.f, 10.f}, {2, 0, 2}, {14, -7, 7}}); + jetHist.add("eff/recmatched/pt/PtParticleTypeTOF", "Pt (p) vs jetflag vs particletype", HistType::kTH3D, {{100, 0.f, 10.f}, {2, 0, 2}, {14, -7, 7}}); + jetHist.add("eff/recmatched/pt/PtParticleTypeTPCTOF", "Pt (p) vs jetflag vs particletype", HistType::kTH3D, {{100, 0.f, 10.f}, {2, 0, 2}, {14, -7, 7}}); + jetHist.add("eff/recmatched/perpCone/pt/PtParticleType", "Pt (p) vs particletype", HistType::kTH2D, {{100, 0.f, 10.f}, {14, -7, 7}}); + jetHist.add("eff/recmatched/perpCone/mcC/pt/PtParticleType", "Pt (rec) vs Pt (true) vs particletype", HistType::kTH3D, {{100, 0.f, 10.f}, {100, 0.f, 10.f}, {14, -7, 7}}); + jetHist.add("eff/recmatched/perpCone/mcCSpectra/pt/PtParticleType", "Pt (rec) vs Pt (true) vs particletype", HistType::kTH3D, {{100, 0.f, 10.f}, {100, 0.f, 10.f}, {14, -7, 7}}); + jetHist.add("eff/recmatched/perpCone/pt/PtParticleTypeTPC", "Pt (p) vs particletype", HistType::kTH2D, {{100, 0.f, 10.f}, {14, -7, 7}}); + jetHist.add("eff/recmatched/perpCone/pt/PtParticleTypeTOF", "Pt (p) vs particletype", HistType::kTH2D, {{100, 0.f, 10.f}, {14, -7, 7}}); + jetHist.add("eff/recmatched/perpCone/pt/PtParticleTypeTPCTOF", "Pt (p) vs particletype", HistType::kTH2D, {{100, 0.f, 10.f}, {14, -7, 7}}); + + jetHist.add("eff/recmatched/gen/pt/PtParticleType", "Pt (p) vs jetflag vs particletype", HistType::kTH3D, {{100, 0.f, 10.f}, {2, 0, 2}, {14, -7, 7}}); + jetHist.add("eff/recmatched/gen/perpCone/pt/PtParticleType", "Pt (p) vs particletype", HistType::kTH2D, {{100, 0.f, 10.f}, {14, -7, 7}}); + // gen matched + jetHist.add("genmatched/hRecMatchedJetPt", "matched jet pT (Rec level);#it{p}_{T,jet part} (GeV/#it{c}); #it{p}_{T,jet part} - #it{p}_{T,jet det}", HistType::kTH2F, {{100, 0., 100.}, {400, -20., 20.}}); + jetHist.add("genmatched/hRecMatchedVsGenJetPt", "matched jet pT (Rec level);#it{p}_{T,jet det}; #it{p}_{T,jet part} (GeV/#it{c})", HistType::kTH2F, {{100, 0., 100.}, {100, 0., 100.}}); + jetHist.add("genmatched/mcC/hRecMatchedVsGenJetPt", "matched jet pT (Rec level); #it{p}_{T,jet det}; #it{p}_{T,jet part} (GeV/#it{c})", HistType::kTH2F, {{100, 0., 100.}, {100, 0., 100.}}); + jetHist.add("genmatched/hRecMatchedVsGenJetPtVsEta", "matched jet pT (Rec level) vs Eta (rec); #it{p}_{T,jet} ; #eta_{jet}", HistType::kTH2F, {{100, 0., 100.}, {200, -1., 1.}}); + + jetHist.add("genmatched/hRecMatchedJetPhi", "matched jet #varphi (Rec level);#varphi_{T,jet part}; #varphi_{jet part}-#varphi_{jet det}", HistType::kTH2F, {{700, 0., 7.}, {200, -5., 5.}}); + jetHist.add("genmatched/hRecMatchedJetEta", "matched jet #eta (Rec level);#eta_{T,jet part}; #eta_{jet part}-#eta_{jet det} ", HistType::kTH2F, {{200, -1., 1.}, {500, -2.5, 2.5}}); + jetHist.add("genmatched/hRecJetPt", "matched jet pT (Rec level);#it{p}_{T,jet part} (GeV/#it{c}); #it{p}_{T,jet part} - #it{p}_{T,jet det}", HistType::kTH1F, {{100, 0., 100.}}); + jetHist.add("genmatched/hGenJetPt", "matched jet pT (Rec level);#it{p}_{T,jet part} (GeV/#it{c}); #it{p}_{T,jet part} - #it{p}_{T,jet det}", HistType::kTH1F, {{100, 0., 100.}}); + jetHist.add("genmatched/leadingJet/hGenJetPt", "matched jet pT (Rec level);#it{p}_{T,jet part} (GeV/#it{c}); #it{p}_{T,jet part} - #it{p}_{T,jet det}", HistType::kTH1F, {{100, 0., 100.}}); + jetHist.add("genmatched/hRecJetWithGenPt", "matched jet pT (Rec level);#it{p}_{T,jet part} (GeV/#it{c}); #it{p}_{T,jet part} - #it{p}_{T,jet det}", HistType::kTH1F, {{100, 0., 100.}}); + jetHist.add("genmatched/hGenJetPtMatched", "matched jet pT (Rec level);#it{p}_{T,jet part} (GeV/#it{c}); #it{p}_{T,jet part} - #it{p}_{T,jet det}", HistType::kTH1F, {{100, 0., 100.}}); + jetHist.add("genmatched/leadingJet/hGenJetPtMatched", "matched jet pT (Rec level);#it{p}_{T,jet part} (GeV/#it{c}); #it{p}_{T,jet part} - #it{p}_{T,jet det}", HistType::kTH1F, {{100, 0., 100.}}); + jetHist.add("genmatched/pt/PtParticleType", "Pt (p) vs jetflag vs particletype", HistType::kTH3D, {{100, 0.f, 10.f}, {2, 0, 2}, {14, -7, 7}}); + } + } + + template + void initCCDB(const BCType& bc) + { + if (applySkim) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), cfgSkim.value); + zorro.populateHistRegistry(jetHist, bc.runNumber()); + } + } + std::array getPerpendicuarPhi(float jetPhi) + { + std::array PerpendicularConeAxisPhi = {-999.0f, -999.0f}; + // build 2 perp cones in phi around the leading jet (right and left of the jet) + PerpendicularConeAxisPhi[0] = RecoDecay::constrainAngle(jetPhi + (M_PI / 2.)); // This will contrain the angel between 0-2Pi + PerpendicularConeAxisPhi[1] = RecoDecay::constrainAngle(jetPhi - (M_PI / 2.)); // This will contrain the angel between 0-2Pi + return PerpendicularConeAxisPhi; + } + + float dcaXYPtDepCut(float trackPt) + { + return 0.0105f + 0.0350f / std::pow(trackPt, 1.1f); + } + + // Check hits on ITS Layers + bool hasHitOnITSLayer(uint8_t itsClsmap, int layer) + { + unsigned char test_bit = 1 << layer; + return (itsClsmap & test_bit); + } + + template + bool isTrackSelected(const TrackType track) + { + // standard track selection + if (track.pt() < cfgtrkMinPt) + return false; + if (isRequireHitsInITSLayers) { + if (!track.hasITS()) + return false; + if (!hasHitOnITSLayer(track.itsClusterMap(), 0) && + !hasHitOnITSLayer(track.itsClusterMap(), 1) && + !hasHitOnITSLayer(track.itsClusterMap(), 2)) + return false; + } + if (std::fabs(track.eta()) > cfgtrkMaxEta) + return false; + if (std::fabs(track.dcaXY()) > cfgMaxDCArToPVcut && !useDcaxyPtDepCut) + return false; + if (std::fabs(track.dcaXY()) > dcaXYPtDepCut(track.pt()) && useDcaxyPtDepCut) + return false; + if (std::fabs(track.dcaZ()) > cfgMaxDCAzToPVcut) + return false; + if (track.tpcNClsFindable() < cfgnFindableTPCClusters) + return false; + if (track.tpcNClsCrossedRows() < cfgnTPCCrossedRows) + return false; + if (track.tpcChi2NCl() > cfgnTPCChi2) + return false; + if (track.itsChi2NCl() > cfgnITSChi2) + return false; + if (cfgConnectedToPV && !track.isPVContributor()) + return false; + return true; + } + + int nEvents = 0; + template + void fillTrackInfo(const TracksType& trk, const JetType& jets, std::vector& leadingJetPtEtaPhi) + { + if (!isTrackSelected(trk)) + return; + if (trk.pt() > cMaxPt) + return; + jetHist.fill(HIST("tracks/h2TPCsignVsTPCmomentum"), trk.tpcInnerParam() / (1.f * trk.sign()), trk.tpcSignal()); + bool jetFlag = false; + bool jetFlagPerpCone = false; + float jetPt = -999.; + + if (isWithLeadingJet) { + double delPhi = TVector2::Phi_mpi_pi(leadingJetPtEtaPhi[2] - trk.phi()); + double delEta = leadingJetPtEtaPhi[1] - trk.eta(); + double R = TMath::Sqrt((delEta * delEta) + (delPhi * delPhi)); + if (R < cfgjetR) + jetFlag = true; + jetPt = leadingJetPtEtaPhi[0]; + // Get perpCone + std::array perpConePhiJet = getPerpendicuarPhi(leadingJetPtEtaPhi[2]); + double delPhiPerpCone1 = TVector2::Phi_mpi_pi(perpConePhiJet[0] - trk.phi()); + double delPhiPerpCone2 = TVector2::Phi_mpi_pi(perpConePhiJet[1] - trk.phi()); + double RPerpCone1 = TMath::Sqrt((delEta * delEta) + (delPhiPerpCone1 * delPhiPerpCone1)); + double RPerpCone2 = TMath::Sqrt((delEta * delEta) + (delPhiPerpCone2 * delPhiPerpCone2)); + if (RPerpCone1 < cfgjetR || RPerpCone2 < cfgjetR) + jetFlagPerpCone = true; + } else { + for (auto const& jet : jets) { + double delPhi = TVector2::Phi_mpi_pi(jet.phi() - trk.phi()); + double delEta = jet.eta() - trk.eta(); + double R = TMath::Sqrt((delEta * delEta) + (delPhi * delPhi)); + if (R < cfgjetR) + jetFlag = true; + jetPt = jet.pt(); + break; + } + } + // tof + float massTOF = -999; + if (trk.hasTOF()) { + massTOF = trk.p() * TMath::Sqrt(1.f / (trk.beta() * trk.beta()) - 1.f); + } + + if (addTOFplots && trk.hasTOF()) { + jetHist.fill(HIST("tracks/h2TOFbetaVsP"), trk.p() / (1.f * trk.sign()), trk.beta()); + } + if (jetFlag) { + jetHist.fill(HIST("tracks/h2TPCsignVsTPCmomentum_Jet"), trk.tpcInnerParam() / (1.f * trk.sign()), trk.tpcSignal()); + if (addTOFplots && trk.hasTOF()) { + jetHist.fill(HIST("tracks/h2TOFbetaVsP_Jet"), trk.p() / (1.f * trk.sign()), trk.beta()); + } + if (trk.sign() > 0) { // particle info + if (addpik) { + jetHist.fill(HIST("tracks/pion/h3PtVsPionNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaPi(), jetPt); + jetHist.fill(HIST("tracks/kaon/h3PtVsKaonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaKa(), jetPt); + } + + if (useTOFNsigmaPreSel && trk.hasTOF()) { + if (std::fabs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF) + jetHist.fill(HIST("tracks/proton/h3PtVsProtonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); + if (std::fabs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) + jetHist.fill(HIST("tracks/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); + if (std::fabs(trk.tofNSigmaHe()) < cfgnTPCPIDHeTOF) + jetHist.fill(HIST("tracks/helium/h3PtVsHeliumNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); + if (std::fabs(trk.tofNSigmaTr()) < cfgnTPCPIDTrTOF) + jetHist.fill(HIST("tracks/triton/h3PtVsTritonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); + } else if (!useTOFNsigmaPreSel) { + jetHist.fill(HIST("tracks/proton/h3PtVsProtonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); + jetHist.fill(HIST("tracks/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); + jetHist.fill(HIST("tracks/helium/h3PtVsHeliumNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); + jetHist.fill(HIST("tracks/triton/h3PtVsTritonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); + } + if (cEnableProtonQA && std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr) { + jetHist.fill(HIST("tracks/proton/dca/after/hDCAxyVsPtProton_jet"), trk.dcaXY(), trk.pt()); + jetHist.fill(HIST("tracks/proton/dca/after/hDCAzVsPtProton_jet"), trk.dcaZ(), trk.pt()); + } + if (cEnableDeuteronQA && std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe) { + jetHist.fill(HIST("tracks/deuteron/dca/after/hDCAxyVsPtDeuteron_jet"), trk.dcaXY(), trk.pt()); + jetHist.fill(HIST("tracks/deuteron/dca/after/hDCAzVsPtDeuteron_jet"), trk.dcaZ(), trk.pt()); + } + if (cEnableTritonQA && std::abs(trk.tpcNSigmaHe()) < cfgnTPCPIDTr) { + jetHist.fill(HIST("tracks/triton/dca/after/hDCAxyVsPtTriton_jet"), trk.dcaXY(), trk.pt()); + jetHist.fill(HIST("tracks/triton/dca/after/hDCAzVsPtTriton_jet"), trk.dcaZ(), trk.pt()); + } + if (cEnableHeliumQA && std::abs(trk.tpcNSigmaHe()) < cfgnTPCPIDHe) { + jetHist.fill(HIST("tracks/helium/dca/after/hDCAxyVsPtHelium_jet"), trk.dcaXY(), trk.pt()); + jetHist.fill(HIST("tracks/helium/dca/after/hDCAzVsPtHelium_jet"), trk.dcaZ(), trk.pt()); + } + + if (addTOFplots && trk.hasTOF()) { + if (!useTPCpreSel) { + jetHist.fill(HIST("tracks/proton/h2TOFmassProtonVsPt_jet"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/proton/h2TOFmass2ProtonVsPt_jet"), massTOF * massTOF - gMassProton * gMassProton, trk.pt()); + jetHist.fill(HIST("tracks/deuteron/h2TOFmassDeuteronVsPt_jet"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/deuteron/h2TOFmass2DeuteronVsPt_jet"), massTOF * massTOF - gMassDeuteron * gMassDeuteron, trk.pt()); + jetHist.fill(HIST("tracks/triton/h2TOFmassTritonVsPt_jet"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/triton/h2TOFmass2TritonVsPt_jet"), massTOF * massTOF - gMassTriton * gMassTriton, trk.pt()); + jetHist.fill(HIST("tracks/helium/h2TOFmassHeliumVsPt_jet"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/helium/h2TOFmass2HeliumVsPt_jet"), massTOF * massTOF - gMassHelium * gMassHelium, trk.pt()); + jetHist.fill(HIST("tracks/proton/h2TofNsigmaProtonVsPt_jet"), trk.tofNSigmaPr(), trk.pt()); + jetHist.fill(HIST("tracks/deuteron/h2TofNsigmaDeuteronVsPt_jet"), trk.tofNSigmaDe(), trk.pt()); + jetHist.fill(HIST("tracks/helium/h2TofNsigmaHeliumVsPt_jet"), trk.tofNSigmaHe(), trk.pt()); + jetHist.fill(HIST("tracks/triton/h2TofNsigmaTritonVsPt_jet"), trk.tofNSigmaTr(), trk.pt()); + jetHist.fill(HIST("tracks/proton/h3TpcNsigmaTofNsigmaProtonVsPt_jet"), trk.tpcNSigmaPr(), trk.tofNSigmaPr(), trk.pt()); + jetHist.fill(HIST("tracks/deuteron/h3TpcNsigmaTofNsigmaDeuteronVsPt_jet"), trk.tpcNSigmaDe(), trk.tofNSigmaDe(), trk.pt()); + } else { + if (trk.tpcNSigmaPr() < useTPCpreSel) { + jetHist.fill(HIST("tracks/proton/h2TOFmassProtonVsPt_jet"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/proton/h2TOFmass2ProtonVsPt_jet"), massTOF * massTOF - gMassProton * gMassProton, trk.pt()); + jetHist.fill(HIST("tracks/proton/h2TofNsigmaProtonVsPt_jet"), trk.tofNSigmaPr(), trk.pt()); + jetHist.fill(HIST("tracks/proton/h3TpcNsigmaTofNsigmaProtonVsPt_jet"), trk.tpcNSigmaPr(), trk.tofNSigmaPr(), trk.pt()); + } + if (trk.tpcNSigmaDe() < useTPCpreSel) { + jetHist.fill(HIST("tracks/deuteron/h2TOFmassDeuteronVsPt_jet"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/deuteron/h2TOFmass2DeuteronVsPt_jet"), massTOF * massTOF - gMassDeuteron * gMassDeuteron, trk.pt()); + jetHist.fill(HIST("tracks/deuteron/h2TofNsigmaDeuteronVsPt_jet"), trk.tofNSigmaDe(), trk.pt()); + jetHist.fill(HIST("tracks/deuteron/h3TpcNsigmaTofNsigmaDeuteronVsPt_jet"), trk.tpcNSigmaDe(), trk.tofNSigmaDe(), trk.pt()); + } + if (trk.tpcNSigmaTr() < useTPCpreSel) { + jetHist.fill(HIST("tracks/triton/h2TOFmassTritonVsPt_jet"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/triton/h2TOFmass2TritonVsPt_jet"), massTOF * massTOF - gMassTriton * gMassTriton, trk.pt()); + jetHist.fill(HIST("tracks/triton/h2TofNsigmaTritonVsPt_jet"), trk.tofNSigmaTr(), trk.pt()); + } + if (trk.tpcNSigmaHe() < useTPCpreSel) { + jetHist.fill(HIST("tracks/helium/h2TOFmassHeliumVsPt_jet"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/helium/h2TOFmass2HeliumVsPt_jet"), massTOF * massTOF - gMassHelium * gMassHelium, trk.pt()); + jetHist.fill(HIST("tracks/helium/h2TofNsigmaHeliumVsPt_jet"), trk.tofNSigmaHe(), trk.pt()); + } + } + // nSigma + if (addpik) { + jetHist.fill(HIST("tracks/pion/h2TofNsigmaPionVsPt_jet"), trk.tofNSigmaPi(), trk.pt()); + jetHist.fill(HIST("tracks/kaon/h2TofNsigmaKaonVsPt_jet"), trk.tofNSigmaKa(), trk.pt()); + } + + } // tof info + + } else { // anti-particle info + if (addpik) { + jetHist.fill(HIST("tracks/antiPion/h3PtVsPionNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaPi(), jetPt); + jetHist.fill(HIST("tracks/antiKaon/h3PtVsKaonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaKa(), jetPt); + } + + if (useTOFNsigmaPreSel && trk.hasTOF()) { + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF) + jetHist.fill(HIST("tracks/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) + jetHist.fill(HIST("tracks/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); + if (std::abs(trk.tofNSigmaHe()) < cfgnTPCPIDHeTOF) + jetHist.fill(HIST("tracks/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); + if (std::abs(trk.tofNSigmaTr()) < cfgnTPCPIDTrTOF) + jetHist.fill(HIST("tracks/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); + } else if (!useTOFNsigmaPreSel) { + jetHist.fill(HIST("tracks/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); + jetHist.fill(HIST("tracks/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); + jetHist.fill(HIST("tracks/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); + jetHist.fill(HIST("tracks/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); + } + + if (cEnableProtonQA && std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr) { + jetHist.fill(HIST("tracks/antiProton/dca/after/hDCAxyVsPtantiProton_jet"), trk.dcaXY(), trk.pt()); + jetHist.fill(HIST("tracks/antiProton/dca/after/hDCAzVsPtantiProton_jet"), trk.dcaZ(), trk.pt()); + } + if (cEnableDeuteronQA && std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe) { + jetHist.fill(HIST("tracks/antiDeuteron/dca/after/hDCAxyVsPtantiDeuteron_jet"), trk.dcaXY(), trk.pt()); + jetHist.fill(HIST("tracks/antiDeuteron/dca/after/hDCAzVsPtantiDeuteron_jet"), trk.dcaZ(), trk.pt()); + } + if (cEnableHeliumQA && std::abs(trk.tpcNSigmaHe()) < cfgnTPCPIDHe) { + jetHist.fill(HIST("tracks/antiTriton/dca/after/hDCAxyVsPtantiTriton_jet"), trk.dcaXY(), trk.pt()); + jetHist.fill(HIST("tracks/antiTriton/dca/after/hDCAzVsPtantiTriton_jet"), trk.dcaZ(), trk.pt()); + } + if (cEnableTritonQA && std::abs(trk.tpcNSigmaHe()) < cfgnTPCPIDHe) { + jetHist.fill(HIST("tracks/antiHelium/dca/after/hDCAxyVsPtantiHelium_jet"), trk.dcaXY(), trk.pt()); + jetHist.fill(HIST("tracks/antiHelium/dca/after/hDCAzVsPtantiHelium_jet"), trk.dcaZ(), trk.pt()); + } + + if (addTOFplots && trk.hasTOF()) { + if (!useTPCpreSel) { + jetHist.fill(HIST("tracks/antiProton/h2TOFmassantiProtonVsPt_jet"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiProton/h2TOFmass2antiProtonVsPt_jet"), massTOF * massTOF - gMassProton * gMassProton, trk.pt()); + jetHist.fill(HIST("tracks/antiProton/h2TofNsigmaantiProtonVsPt_jet"), trk.tofNSigmaPr(), trk.pt()); + jetHist.fill(HIST("tracks/antiProton/h3TpcNsigmaTofNsigmaantiProtonVsPt_jet"), trk.tpcNSigmaPr(), trk.tofNSigmaPr(), trk.pt()); + + jetHist.fill(HIST("tracks/antiDeuteron/h2TOFmassantiDeuteronVsPt_jet"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiDeuteron/h2TOFmass2antiDeuteronVsPt_jet"), massTOF * massTOF - gMassDeuteron * gMassDeuteron, trk.pt()); + jetHist.fill(HIST("tracks/antiDeuteron/h2TofNsigmaantiDeuteronVsPt_jet"), trk.tofNSigmaDe(), trk.pt()); + jetHist.fill(HIST("tracks/antiDeuteron/h3TpcNsigmaTofNsigmaantiDeuteronVsPt_jet"), trk.tpcNSigmaDe(), trk.tofNSigmaDe(), trk.pt()); + + jetHist.fill(HIST("tracks/antiTriton/h2TOFmassantiTritonVsPt_jet"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiTriton/h2TOFmass2antiTritonVsPt_jet"), massTOF * massTOF - gMassTriton * gMassTriton, trk.pt()); + jetHist.fill(HIST("tracks/antiTriton/h2TofNsigmaantiTritonVsPt_jet"), trk.tofNSigmaTr(), trk.pt()); + + jetHist.fill(HIST("tracks/antiHelium/h2TOFmassantiHeliumVsPt_jet"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiHelium/h2TOFmass2antiHeliumVsPt_jet"), massTOF * massTOF - gMassHelium * gMassHelium, trk.pt()); + jetHist.fill(HIST("tracks/antiHelium/h2TofNsigmaantiHeliumVsPt_jet"), trk.tofNSigmaHe(), trk.pt()); + } else { + if (trk.tpcNSigmaPr() < useTPCpreSel) { + jetHist.fill(HIST("tracks/antiProton/h2TOFmassantiProtonVsPt_jet"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiProton/h2TOFmass2antiProtonVsPt_jet"), massTOF * massTOF - gMassProton * gMassProton, trk.pt()); + jetHist.fill(HIST("tracks/antiProton/h2TofNsigmaantiProtonVsPt_jet"), trk.tofNSigmaPr(), trk.pt()); + jetHist.fill(HIST("tracks/antiProton/h3TpcNsigmaTofNsigmaantiProtonVsPt_jet"), trk.tpcNSigmaPr(), trk.tofNSigmaPr(), trk.pt()); + } + if (trk.tpcNSigmaDe() < useTPCpreSel) { + jetHist.fill(HIST("tracks/antiDeuteron/h2TOFmassantiDeuteronVsPt_jet"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiDeuteron/h2TOFmass2antiDeuteronVsPt_jet"), massTOF * massTOF - gMassDeuteron * gMassDeuteron, trk.pt()); + jetHist.fill(HIST("tracks/antiDeuteron/h2TofNsigmaantiDeuteronVsPt_jet"), trk.tofNSigmaDe(), trk.pt()); + jetHist.fill(HIST("tracks/antiDeuteron/h3TpcNsigmaTofNsigmaantiDeuteronVsPt_jet"), trk.tpcNSigmaDe(), trk.tofNSigmaDe(), trk.pt()); + } + if (trk.tpcNSigmaTr() < useTPCpreSel) { + jetHist.fill(HIST("tracks/antiTriton/h2TOFmassantiTritonVsPt_jet"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiTriton/h2TOFmass2antiTritonVsPt_jet"), massTOF * massTOF - gMassTriton * gMassTriton, trk.pt()); + jetHist.fill(HIST("tracks/antiTriton/h2TofNsigmaantiTritonVsPt_jet"), trk.tofNSigmaTr(), trk.pt()); + } + if (trk.tpcNSigmaHe() < useTPCpreSel) { + jetHist.fill(HIST("tracks/antiHelium/h2TOFmassantiHeliumVsPt_jet"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiHelium/h2TOFmass2antiHeliumVsPt_jet"), massTOF * massTOF - gMassHelium * gMassHelium, trk.pt()); + jetHist.fill(HIST("tracks/antiHelium/h2TofNsigmaantiHeliumVsPt_jet"), trk.tofNSigmaHe(), trk.pt()); + } + } + if (addpik) { + if (!useTPCpreSel) { + jetHist.fill(HIST("tracks/antiPion/h2TofNsigmaantiPionVsPt_jet"), trk.tofNSigmaPi(), trk.pt()); + jetHist.fill(HIST("tracks/antiKaon/h2TofNsigmaantiKaonVsPt_jet"), trk.tofNSigmaKa(), trk.pt()); + } else { + if (trk.tpcNSigmaPi() < useTPCpreSel) { + jetHist.fill(HIST("tracks/antiPion/h2TofNsigmaantiPionVsPt_jet"), trk.tofNSigmaPi(), trk.pt()); + } + if (trk.tpcNSigmaKa() < useTPCpreSel) { + jetHist.fill(HIST("tracks/antiKaon/h2TofNsigmaantiKaonVsPt_jet"), trk.tofNSigmaKa(), trk.pt()); + } + } + } // pikEnd + } + } // anti-particle + //////////////////////////////////////// + // within jet end + ////////////////////////////////////////// + } else { + jetHist.fill(HIST("tracks/h2TPCsignVsTPCmomentum_OutJet"), trk.tpcInnerParam() / (1.f * trk.sign()), trk.tpcSignal()); + if (jetFlagPerpCone && isWithLeadingJet) { + jetHist.fill(HIST("tracks/perpCone/h2TPCsignVsTPCmomentum"), trk.tpcInnerParam() / (1.f * trk.sign()), trk.tpcSignal()); + } + if (addTOFplots && trk.hasTOF()) { + jetHist.fill(HIST("tracks/h2TOFbetaVsP_OutJet"), trk.p() / (1.f * trk.sign()), trk.beta()); + } + if (trk.sign() > 0) { + jetHist.fill(HIST("tracks/proton/h3PtVsProtonNSigmaTPC"), trk.pt(), trk.tpcNSigmaPr()); // Pr + jetHist.fill(HIST("tracks/deuteron/h3PtVsDeuteronNSigmaTPC"), trk.pt(), trk.tpcNSigmaDe()); // De + jetHist.fill(HIST("tracks/helium/h3PtVsHeliumNSigmaTPC"), trk.pt(), trk.tpcNSigmaHe()); // He + jetHist.fill(HIST("tracks/triton/h3PtVsTritonNSigmaTPC"), trk.pt(), trk.tpcNSigmaTr()); // Tr + // perpCone + if (jetFlagPerpCone && isWithLeadingJet) { + if (useTOFNsigmaPreSel && trk.hasTOF()) { + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF) + jetHist.fill(HIST("tracks/perpCone/proton/h3PtVsProtonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); // Pr + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) + jetHist.fill(HIST("tracks/perpCone/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); // De + if (std::abs(trk.tofNSigmaHe()) < cfgnTPCPIDHeTOF) + jetHist.fill(HIST("tracks/perpCone/helium/h3PtVsHeliumNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); // He + if (std::abs(trk.tofNSigmaTr()) < cfgnTPCPIDTrTOF) + jetHist.fill(HIST("tracks/perpCone/triton/h3PtVsTritonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); // Tr + } else if (!useTOFNsigmaPreSel) { + jetHist.fill(HIST("tracks/perpCone/proton/h3PtVsProtonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); // Pr + jetHist.fill(HIST("tracks/perpCone/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); // De + jetHist.fill(HIST("tracks/perpCone/helium/h3PtVsHeliumNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); // He + jetHist.fill(HIST("tracks/perpCone/triton/h3PtVsTritonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); // Tr + } + } + + if (cEnableProtonQA && std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr) { + jetHist.fill(HIST("tracks/proton/dca/after/hDCAxyVsPtProton"), trk.dcaXY(), trk.pt()); + jetHist.fill(HIST("tracks/proton/dca/after/hDCAzVsPtProton"), trk.dcaZ(), trk.pt()); + } + if (cEnableDeuteronQA && std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe) { + jetHist.fill(HIST("tracks/deuteron/dca/after/hDCAxyVsPtDeuteron"), trk.dcaXY(), trk.pt()); + jetHist.fill(HIST("tracks/deuteron/dca/after/hDCAzVsPtDeuteron"), trk.dcaZ(), trk.pt()); + } + if (cEnableTritonQA && std::abs(trk.tpcNSigmaHe()) < cfgnTPCPIDTr) { + jetHist.fill(HIST("tracks/triton/dca/after/hDCAxyVsPtTriton"), trk.dcaXY(), trk.pt()); + jetHist.fill(HIST("tracks/triton/dca/after/hDCAzVsPtTriton"), trk.dcaZ(), trk.pt()); + } + if (cEnableHeliumQA && std::abs(trk.tpcNSigmaHe()) < cfgnTPCPIDHe) { + jetHist.fill(HIST("tracks/helium/dca/after/hDCAxyVsPtHelium"), trk.dcaXY(), trk.pt()); + jetHist.fill(HIST("tracks/helium/dca/after/hDCAzVsPtHelium"), trk.dcaZ(), trk.pt()); + } + if (addTOFplots && trk.hasTOF()) { + if (!useTPCpreSel) { + jetHist.fill(HIST("tracks/proton/h2TOFmassProtonVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - gMassProton * gMassProton, trk.pt()); + jetHist.fill(HIST("tracks/proton/h2TofNsigmaProtonVsPt"), trk.tofNSigmaPr(), trk.pt()); + + jetHist.fill(HIST("tracks/deuteron/h2TOFmassDeuteronVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - gMassDeuteron * gMassDeuteron, trk.pt()); + jetHist.fill(HIST("tracks/deuteron/h2TofNsigmaDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt()); + + jetHist.fill(HIST("tracks/triton/h2TOFmassTritonVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/triton/h2TOFmass2TritonVsPt"), massTOF * massTOF - gMassTriton * gMassTriton, trk.pt()); + jetHist.fill(HIST("tracks/helium/h2TofNsigmaHeliumVsPt"), trk.tofNSigmaHe(), trk.pt()); + + jetHist.fill(HIST("tracks/helium/h2TOFmassHeliumVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/helium/h2TOFmass2HeliumVsPt"), massTOF * massTOF - gMassHelium * gMassHelium, trk.pt()); + jetHist.fill(HIST("tracks/triton/h2TofNsigmaTritonVsPt"), trk.tofNSigmaTr(), trk.pt()); + } else { + if (trk.tpcNSigmaPr() < useTPCpreSel) { + jetHist.fill(HIST("tracks/proton/h2TOFmassProtonVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - gMassProton * gMassProton, trk.pt()); + jetHist.fill(HIST("tracks/proton/h2TofNsigmaProtonVsPt"), trk.tofNSigmaPr(), trk.pt()); + if (jetFlagPerpCone && isWithLeadingJet) + jetHist.fill(HIST("tracks/perpCone/proton/h2TofNsigmaProtonVsPt"), trk.tofNSigmaPr(), trk.pt()); + } + if (trk.tpcNSigmaDe() < useTPCpreSel) { + jetHist.fill(HIST("tracks/deuteron/h2TOFmassDeuteronVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - gMassDeuteron * gMassDeuteron, trk.pt()); + jetHist.fill(HIST("tracks/deuteron/h2TofNsigmaDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt()); + if (jetFlagPerpCone && isWithLeadingJet) + jetHist.fill(HIST("tracks/perpCone/deuteron/h2TofNsigmaDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt()); + } + if (trk.tpcNSigmaTr() < useTPCpreSel) { + jetHist.fill(HIST("tracks/triton/h2TOFmassTritonVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/triton/h2TOFmass2TritonVsPt"), massTOF * massTOF - gMassTriton * gMassTriton, trk.pt()); + jetHist.fill(HIST("tracks/triton/h2TofNsigmaTritonVsPt"), trk.tofNSigmaTr(), trk.pt()); + if (jetFlagPerpCone && isWithLeadingJet) + jetHist.fill(HIST("tracks/perpCone/triton/h2TofNsigmaTritonVsPt"), trk.tofNSigmaTr(), trk.pt()); + } + if (trk.tpcNSigmaHe() < useTPCpreSel) { + jetHist.fill(HIST("tracks/helium/h2TOFmassHeliumVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/helium/h2TOFmass2HeliumVsPt"), massTOF * massTOF - gMassHelium * gMassHelium, trk.pt()); + jetHist.fill(HIST("tracks/helium/h2TofNsigmaHeliumVsPt"), trk.tofNSigmaHe(), trk.pt()); + if (jetFlagPerpCone && isWithLeadingJet) + jetHist.fill(HIST("tracks/perpCone/helium/h2TofNsigmaHeliumVsPt"), trk.tofNSigmaHe(), trk.pt()); + } + } + } // tof info + } else { + jetHist.fill(HIST("tracks/antiProton/h3PtVsantiProtonNSigmaTPC"), trk.pt(), trk.tpcNSigmaPr()); // Pr + jetHist.fill(HIST("tracks/antiDeuteron/h3PtVsantiDeuteronNSigmaTPC"), trk.pt(), trk.tpcNSigmaDe()); // De + jetHist.fill(HIST("tracks/antiHelium/h3PtVsantiHeliumNSigmaTPC"), trk.pt(), trk.tpcNSigmaHe()); // He + jetHist.fill(HIST("tracks/antiTriton/h3PtVsantiTritonNSigmaTPC"), trk.pt(), trk.tpcNSigmaTr()); // Tr + + // perpCone + if (jetFlagPerpCone && isWithLeadingJet) { + // antiparticle info + if (useTOFNsigmaPreSel && trk.hasTOF()) { + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF) + jetHist.fill(HIST("tracks/perpCone/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); // Pr + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) + jetHist.fill(HIST("tracks/perpCone/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); // De + if (std::abs(trk.tofNSigmaHe()) < cfgnTPCPIDHeTOF) + jetHist.fill(HIST("tracks/perpCone/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); // He + if (std::abs(trk.tofNSigmaTr()) < cfgnTPCPIDTrTOF) + jetHist.fill(HIST("tracks/perpCone/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); // Tr + } else if (!useTOFNsigmaPreSel) { + jetHist.fill(HIST("tracks/perpCone/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); // Pr + jetHist.fill(HIST("tracks/perpCone/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); // De + jetHist.fill(HIST("tracks/perpCone/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); // He + jetHist.fill(HIST("tracks/perpCone/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); // Tr + } + } + + if (cEnableProtonQA && std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr) { + jetHist.fill(HIST("tracks/antiProton/dca/after/hDCAxyVsPtantiProton"), trk.dcaXY(), trk.pt()); + jetHist.fill(HIST("tracks/antiProton/dca/after/hDCAzVsPtantiProton"), trk.dcaZ(), trk.pt()); + } + if (cEnableDeuteronQA && std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe) { + jetHist.fill(HIST("tracks/antiDeuteron/dca/after/hDCAxyVsPtantiDeuteron"), trk.dcaXY(), trk.pt()); + jetHist.fill(HIST("tracks/antiDeuteron/dca/after/hDCAzVsPtantiDeuteron"), trk.dcaZ(), trk.pt()); + } + if (cEnableHeliumQA && std::abs(trk.tpcNSigmaHe()) < cfgnTPCPIDHe) { + jetHist.fill(HIST("tracks/antiTriton/dca/after/hDCAxyVsPtantiTriton"), trk.dcaXY(), trk.pt()); + jetHist.fill(HIST("tracks/antiTriton/dca/after/hDCAzVsPtantiTriton"), trk.dcaZ(), trk.pt()); + } + if (cEnableTritonQA && std::abs(trk.tpcNSigmaHe()) < cfgnTPCPIDHe) { + jetHist.fill(HIST("tracks/antiHelium/dca/after/hDCAxyVsPtantiHelium"), trk.dcaXY(), trk.pt()); + jetHist.fill(HIST("tracks/antiHelium/dca/after/hDCAzVsPtantiHelium"), trk.dcaZ(), trk.pt()); + } + if (addTOFplots && trk.hasTOF()) { + if (!useTPCpreSel) { + jetHist.fill(HIST("tracks/antiProton/h2TOFmassantiProtonVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiProton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - gMassProton * gMassProton, trk.pt()); + jetHist.fill(HIST("tracks/antiProton/h2TofNsigmaantiProtonVsPt"), trk.tofNSigmaPr(), trk.pt()); + + jetHist.fill(HIST("tracks/antiDeuteron/h2TOFmassantiDeuteronVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiDeuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - gMassDeuteron * gMassDeuteron, trk.pt()); + jetHist.fill(HIST("tracks/antiDeuteron/h2TofNsigmaantiDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt()); + + jetHist.fill(HIST("tracks/antiTriton/h2TOFmassantiTritonVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiTriton/h2TOFmass2antiTritonVsPt"), massTOF * massTOF - gMassTriton * gMassTriton, trk.pt()); + jetHist.fill(HIST("tracks/antiHelium/h2TofNsigmaantiHeliumVsPt"), trk.tofNSigmaHe(), trk.pt()); + + jetHist.fill(HIST("tracks/antiHelium/h2TOFmassantiHeliumVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiHelium/h2TOFmass2antiHeliumVsPt"), massTOF * massTOF - gMassHelium * gMassHelium, trk.pt()); + jetHist.fill(HIST("tracks/antiTriton/h2TofNsigmaantiTritonVsPt"), trk.tofNSigmaTr(), trk.pt()); + } else { + if (trk.tpcNSigmaPr() < useTPCpreSel) { + jetHist.fill(HIST("tracks/antiProton/h2TOFmassantiProtonVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiProton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - gMassProton * gMassProton, trk.pt()); + jetHist.fill(HIST("tracks/antiProton/h2TofNsigmaantiProtonVsPt"), trk.tofNSigmaPr(), trk.pt()); + if (jetFlagPerpCone && isWithLeadingJet) + jetHist.fill(HIST("tracks/perpCone/antiProton/h2TofNsigmaantiProtonVsPt"), trk.tofNSigmaPr(), trk.pt()); + } + if (trk.tpcNSigmaDe() < useTPCpreSel) { + jetHist.fill(HIST("tracks/antiDeuteron/h2TOFmassantiDeuteronVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiDeuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - gMassDeuteron * gMassDeuteron, trk.pt()); + jetHist.fill(HIST("tracks/antiDeuteron/h2TofNsigmaantiDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt()); + if (jetFlagPerpCone && isWithLeadingJet) + jetHist.fill(HIST("tracks/perpCone/antiDeuteron/h2TofNsigmaantiDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt()); + } + if (trk.tpcNSigmaTr() < useTPCpreSel) { + jetHist.fill(HIST("tracks/antiTriton/h2TOFmassantiTritonVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiTriton/h2TOFmass2antiTritonVsPt"), massTOF * massTOF - gMassTriton * gMassTriton, trk.pt()); + jetHist.fill(HIST("tracks/antiTriton/h2TofNsigmaantiTritonVsPt"), trk.tofNSigmaTr(), trk.pt()); + if (jetFlagPerpCone && isWithLeadingJet) + jetHist.fill(HIST("tracks/perpCone/antiTriton/h2TofNsigmaantiTritonVsPt"), trk.tofNSigmaTr(), trk.pt()); + } + if (trk.tpcNSigmaHe() < useTPCpreSel) { + jetHist.fill(HIST("tracks/antiHelium/h2TOFmassantiHeliumVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiHelium/h2TOFmass2antiHeliumVsPt"), massTOF * massTOF - gMassHelium * gMassHelium, trk.pt()); + jetHist.fill(HIST("tracks/antiHelium/h2TofNsigmaantiHeliumVsPt"), trk.tofNSigmaHe(), trk.pt()); + if (jetFlagPerpCone && isWithLeadingJet) + jetHist.fill(HIST("tracks/perpCone/antiHelium/h2TofNsigmaantiHeliumVsPt"), trk.tofNSigmaHe(), trk.pt()); + } + } + } + } + } //////////////////////////////////////// + // outside jet end + //////////////////////////////////////// + } + + void processJetTracksData(soa::Join::iterator const& collision, + chargedJetstrack const& chargedjets, soa::Join const& tracks, TrackCandidates const&, aod::JBCs const&) + { + auto bc = collision.bc_as(); + initCCDB(bc); + if (applySkim) { + jetHist.fill(HIST("hNEvents"), 0.5); + bool zorroSelected = zorro.isSelected(bc.globalBC()); + if (!zorroSelected) { + return; + } + jetHist.fill(HIST("hNEvents"), 1.5); + } + if (fabs(collision.posZ()) > 10) + return; + jetHist.fill(HIST("hNEvents"), 2.5); + if (!jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("sel8"))) + return; + jetHist.fill(HIST("hNEvents"), 3.5); + int nJets = 0; + std::vector leadingJetWithPtEtaPhi(3); + float leadingJetPt = -1.0f; + for (const auto& chargedjet : chargedjets) { + jetHist.fill(HIST("jet/h1JetPt"), chargedjet.pt()); + jetHist.fill(HIST("jet/h1JetEta"), chargedjet.eta()); + jetHist.fill(HIST("jet/h1JetPhi"), chargedjet.phi()); + + if (chargedjet.pt() > leadingJetPt) { + leadingJetWithPtEtaPhi[0] = chargedjet.pt(); + leadingJetWithPtEtaPhi[1] = chargedjet.eta(); + leadingJetWithPtEtaPhi[2] = chargedjet.phi(); + } + nJets++; + } + jetHist.fill(HIST("jet/nJetsPerEvent"), nJets); + jetHist.fill(HIST("vertexZ"), collision.posZ()); + if (nJets > 0) { + jetHist.fill(HIST("jet/vertexZ"), collision.posZ()); + jetHist.fill(HIST("hNEvents"), 4.5); + } else { + jetHist.fill(HIST("jetOut/vertexZ"), collision.posZ()); + } + if (isWithJetEvents && nJets == 0) + return; + jetHist.fill(HIST("jet/h1JetEvents"), 0.5); + for (auto& track : tracks) { + auto trk = track.track_as(); + fillTrackInfo(trk, chargedjets, leadingJetWithPtEtaPhi); + } + } + + void processJetTracksDataLfPid(soa::Join::iterator const& collision, + chargedJetstrack const& chargedjets, soa::Join const& tracks, TrackCandidatesLfPid const&, aod::JBCs const&) + { + auto bc = collision.bc_as(); + initCCDB(bc); + if (applySkim) { + jetHist.fill(HIST("hNEvents"), 0.5); + bool zorroSelected = zorro.isSelected(bc.globalBC()); + if (!zorroSelected) { + return; + } + jetHist.fill(HIST("hNEvents"), 1.5); + } + if (fabs(collision.posZ()) > 10) + return; + jetHist.fill(HIST("hNEvents"), 2.5); + if (!jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("sel8"))) + return; + jetHist.fill(HIST("hNEvents"), 3.5); + int nJets = 0; + std::vector leadingJetWithPtEtaPhi(3); + float leadingJetPt = -1.0f; + for (const auto& chargedjet : chargedjets) { + jetHist.fill(HIST("jet/h1JetPt"), chargedjet.pt()); + jetHist.fill(HIST("jet/h1JetEta"), chargedjet.eta()); + jetHist.fill(HIST("jet/h1JetPhi"), chargedjet.phi()); + if (chargedjet.pt() > leadingJetPt) { + leadingJetWithPtEtaPhi[0] = chargedjet.pt(); + leadingJetWithPtEtaPhi[1] = chargedjet.eta(); + leadingJetWithPtEtaPhi[2] = chargedjet.phi(); + } + nJets++; + } + jetHist.fill(HIST("jet/nJetsPerEvent"), nJets); + jetHist.fill(HIST("vertexZ"), collision.posZ()); + if (nJets > 0) { + jetHist.fill(HIST("jet/vertexZ"), collision.posZ()); + jetHist.fill(HIST("hNEvents"), 4.5); + } else { + jetHist.fill(HIST("jetOut/vertexZ"), collision.posZ()); + } + if (isWithJetEvents && nJets == 0) + return; + jetHist.fill(HIST("jet/h1JetEvents"), 0.5); + for (auto& track : tracks) { + auto trk = track.track_as(); + fillTrackInfo(trk, chargedjets, leadingJetWithPtEtaPhi); + } + } + + void processMCGen(o2::aod::JetMcCollision const& collision, /*soa::SmallGroups> const& recoColls,*/ aod::JetParticles const& mcParticles, soa::Filtered const& mcpjets) + { + jetHist.fill(HIST("mcpJet/eventStat"), 0.5); + jetHist.fill(HIST("mcpJet/eventStat"), 1.5); + + if (fabs(collision.posZ()) > 10) // bad vertex + return; + + jetHist.fill(HIST("mcpJet/eventStat"), 2.5); + + jetHist.fill(HIST("mcpJet/vertexZ"), collision.posZ()); + + bool INELgt0 = false; + for (const auto& mcParticle : mcParticles) { + if (fabs(mcParticle.eta()) < cfgtrkMaxEta) { + INELgt0 = true; + break; + } + } + if (!INELgt0) // not true INEL + return; + jetHist.fill(HIST("mcpJet/eventStat"), 3.5); + + int nJets = 0; + for (auto& mcpjet : mcpjets) { + jetHist.fill(HIST("mcpJet/hJetPt"), mcpjet.pt()); + jetHist.fill(HIST("mcpJet/hJetEta"), mcpjet.eta()); + jetHist.fill(HIST("mcpJet/hJetPhi"), mcpjet.phi()); + nJets++; + } + jetHist.fill(HIST("mcpJet/nJetsPerEvent"), nJets); + + for (const auto& mcParticle : mcParticles) { + if (!mcParticle.isPhysicalPrimary()) + continue; + if (fabs(mcParticle.eta()) > cfgtrkMaxEta) + continue; + if (fabs(mcParticle.y()) > cfgtrkMaxRap) + continue; + + bool jetFlag = false; + // float jetPt = -999.; + for (auto& mcpjet : mcpjets) { + double delPhi = TVector2::Phi_mpi_pi(mcpjet.phi() - mcParticle.phi()); + double delEta = mcpjet.eta() - mcParticle.eta(); + double R = TMath::Sqrt((delEta * delEta) + (delPhi * delPhi)); + if (R < cfgjetR) + jetFlag = true; + // jetPt = mcpjet.pt(); + break; + } // jet + if (mapPDGToValue(mcParticle.pdgCode()) != 0) { + jetHist.fill(HIST("mcpJet/pt/PtParticleType"), mcParticle.pt(), jetFlag, mapPDGToValue(mcParticle.pdgCode())); + } + } // track + } // process mc + + void processMCRec(o2::aod::JetCollision const& collisionJet, soa::Join const& tracks, + soa::Filtered const& mcdjets, TrackCandidatesMC const&, aod::JetParticles const&) + { + jetHist.fill(HIST("mcdJet/eventStat"), 0.5); + if (!jetderiveddatautilities::selectCollision(collisionJet, jetderiveddatautilities::initialiseEventSelectionBits("sel8"))) + return; + // bool jetFlag = kFALSE; + jetHist.fill(HIST("mcdJet/eventStat"), 1.5); + + if (fabs(collisionJet.posZ()) > 10) + return; + + jetHist.fill(HIST("mcdJet/eventStat"), 2.5); + bool INELgt0 = false; + for (const auto& track : tracks) { + if (fabs(track.eta()) < cfgtrkMaxEta) { + INELgt0 = true; + break; + } + } + if (!INELgt0) + return; + jetHist.fill(HIST("mcdJet/eventStat"), 3.5); + int nJets = 0; + std::vector leadingJetWithPtEtaPhi(3); + float leadingJetPt = -1.0f; + for (auto& mcdjet : mcdjets) { + jetHist.fill(HIST("mcdJet/hJetPt"), mcdjet.pt()); + jetHist.fill(HIST("mcdJet/hJetEta"), mcdjet.eta()); + jetHist.fill(HIST("mcdJet/hJetPhi"), mcdjet.phi()); + if (mcdjet.pt() > leadingJetPt) { + leadingJetWithPtEtaPhi[0] = mcdjet.pt(); + leadingJetWithPtEtaPhi[1] = mcdjet.eta(); + leadingJetWithPtEtaPhi[2] = mcdjet.phi(); + } + nJets++; + } + jetHist.fill(HIST("mcdJet/vertexZ"), collisionJet.posZ()); + jetHist.fill(HIST("mcdJet/nJetsPerEvent"), nJets); + if (isWithJetEvents && nJets == 0) + return; + for (auto& track : tracks) { + auto fullTrack = track.track_as(); + if (!isTrackSelected(fullTrack)) + continue; + if (!track.has_mcParticle()) + continue; + auto mcTrack = track.mcParticle_as(); + if (fabs(mcTrack.eta()) > cfgtrkMaxEta) + continue; + if (!mcTrack.isPhysicalPrimary()) + continue; + bool jetFlag = false; + bool jetFlagPerpCone = false; + // float jetPt = -999.; + if (isWithLeadingJet) { + double delPhi = TVector2::Phi_mpi_pi(leadingJetWithPtEtaPhi[2] - track.phi()); + double delEta = leadingJetWithPtEtaPhi[1] - track.eta(); + double R = TMath::Sqrt((delEta * delEta) + (delPhi * delPhi)); + if (R < cfgjetR) + jetFlag = true; + std::array perpConePhiJet = getPerpendicuarPhi(leadingJetWithPtEtaPhi[2]); + double delPhiPerpCone1 = TVector2::Phi_mpi_pi(perpConePhiJet[0] - track.phi()); + double delPhiPerpCone2 = TVector2::Phi_mpi_pi(perpConePhiJet[1] - track.phi()); + double RPerpCone1 = TMath::Sqrt((delEta * delEta) + (delPhiPerpCone1 * delPhiPerpCone1)); + double RPerpCone2 = TMath::Sqrt((delEta * delEta) + (delPhiPerpCone2 * delPhiPerpCone2)); + if (RPerpCone1 < cfgjetR || RPerpCone2 < cfgjetR) + jetFlagPerpCone = true; + } else { + for (auto& mcdjet : mcdjets) { + double delPhi = TVector2::Phi_mpi_pi(mcdjet.phi() - track.phi()); + double delEta = mcdjet.eta() - track.eta(); + double R = TMath::Sqrt((delEta * delEta) + (delPhi * delPhi)); + if (R < cfgjetR) + jetFlag = true; + // jetPt = mcdjet.pt(); + break; + } // jet + } + if (mapPDGToValue(mcTrack.pdgCode()) != 0) { + jetHist.fill(HIST("mcdJet/pt/PtParticleType"), mcTrack.pt(), jetFlag, mapPDGToValue(mcTrack.pdgCode())); + if (jetFlagPerpCone) + jetHist.fill(HIST("mcdJet/pt/perpCone/PtParticleType"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode())); + } + } // tracks + } + + Preslice> perMCCol = aod::jmcparticle::mcCollisionId; + void processRecMatched(aod::JetCollisionMCD const& collision, JetMCDetTable const& mcdjets, + soa::Join const& tracks, + JetMCPartTable const&, TrackCandidatesMC const&, aod::JetParticles const& particleTracks, aod::JMcCollisions const&) + { + if (fabs(collision.posZ()) > 10) + return; + if (!jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("sel8"))) + return; + + jetHist.fill(HIST("recmatched/vertexZ"), collision.posZ()); + bool INELgt0 = false; + for (const auto& track : tracks) { + if (fabs(track.eta()) < cfgtrkMaxEta) { + INELgt0 = true; + break; + } + } + if (!INELgt0) + return; + + std::vector mcdJetPt{}; + std::vector mcdJetPhi{}; + std::vector mcdJetEta{}; + std::vector mcpJetPt{}; + std::vector mcpJetPhi{}; + std::vector mcpJetEta{}; + + if (mcdjets.size() == 0) + return; + // LOG(info) <<" size(mcd) "< leadingJetWithPtEtaPhi(3); + for (auto& mcdjet : mcdjets) { + if (!mcdjet.has_matchedJetGeo()) + continue; + for (auto& mcpjet : mcdjet.template matchedJetGeo_as()) { + if (!mcpjet.has_matchedJetGeo()) + continue; + + mcdJetPt.push_back(mcdjet.pt()); + mcdJetPhi.push_back(mcdjet.phi()); + mcdJetEta.push_back(mcdjet.eta()); + mcpJetPt.push_back(mcpjet.pt()); + mcpJetPhi.push_back(mcpjet.phi()); + mcpJetEta.push_back(mcpjet.eta()); + + jetHist.fill(HIST("recmatched/hRecMatchedJetPt"), mcpjet.pt(), mcpjet.pt() - mcdjet.pt()); + jetHist.fill(HIST("recmatched/hRecMatchedJetPhi"), mcpjet.phi(), mcpjet.phi() - mcdjet.phi()); + jetHist.fill(HIST("recmatched/hRecMatchedJetEta"), mcpjet.eta(), mcpjet.eta() - mcdjet.eta()); + + jetHist.fill(HIST("recmatched/hRecMatchedVsGenJetPtVsEta"), mcdjet.pt(), mcdjet.eta()); + jetHist.fill(HIST("recmatched/hRecJetPt"), mcdjet.pt()); + jetHist.fill(HIST("recmatched/hGenJetPt"), mcpjet.pt()); + jetHist.fill(HIST("recmatched/h2ResponseMatrix"), mcdjet.pt(), mcpjet.pt()); + } // mcpJet + } // mcdJet + + if (mcdJetPt.size() == 0) + return; // no matched jet + auto itLeadPtJet = std::max_element(mcdJetPt.begin(), mcdJetPt.end()); + size_t indexJet = 0; // safe to be initialised with 0 + if (itLeadPtJet != mcdJetPt.end()) { + indexJet = std::distance(mcdJetPt.begin(), itLeadPtJet); + } else { + LOGP(fatal, "Error: Index {} is out of range for vectors!", indexJet); + } + if (useMcC) { + if (randUniform.Uniform(0, 1) < 0.5) + jetHist.fill(HIST("recmatched/h2ResponseMatrixLeadingJet"), mcdJetPt.at(indexJet), mcpJetPt.at(indexJet)); + else + jetHist.fill(HIST("recmatched/mcC/h2ResponseMatrixLeadingJet"), mcdJetPt.at(indexJet), mcpJetPt.at(indexJet)); + } else { + jetHist.fill(HIST("recmatched/h2ResponseMatrixLeadingJet"), mcdJetPt.at(indexJet), mcpJetPt.at(indexJet)); + } + if (useLeadingJetDetLevelValue) { + leadingJetWithPtEtaPhi[0] = mcdJetPt.at(indexJet); + leadingJetWithPtEtaPhi[1] = mcdJetEta.at(indexJet); + leadingJetWithPtEtaPhi[2] = mcdJetPhi.at(indexJet); + } else { + leadingJetWithPtEtaPhi[0] = mcpJetPt.at(indexJet); + leadingJetWithPtEtaPhi[1] = mcpJetEta.at(indexJet); + leadingJetWithPtEtaPhi[2] = mcpJetPhi.at(indexJet); + } + + for (const auto& track : tracks) { + auto completeTrack = track.track_as(); + if (fabs(completeTrack.eta()) > cfgtrkMaxEta) + continue; + if (!isTrackSelected(completeTrack)) + continue; + if (!track.has_mcParticle()) + continue; + auto mcTrack = track.mcParticle_as(); + if (!mcTrack.isPhysicalPrimary()) + continue; + if (fabs(mcTrack.y()) > cfgtrkMaxRap) + continue; + + bool isTpcPassed(true); + bool isTof(completeTrack.hasTOF()); + bool isTOFAndTPCPreSel(completeTrack.hasTOF() && + (completeTrack.tpcNSigmaPr() < cfgnTPCPIDPrTOF || completeTrack.tpcNSigmaDe() < cfgnTPCPIDDeTOF || + completeTrack.tpcNSigmaHe() < cfgnTPCPIDHeTOF || completeTrack.tpcNSigmaTr() < cfgnTPCPIDTrTOF)); + + bool jetFlag = false; + bool jetFlagPerpCone = false; + if (isWithLeadingJet) { + double delPhi = TVector2::Phi_mpi_pi(leadingJetWithPtEtaPhi[2] - track.phi()); + double delEta = leadingJetWithPtEtaPhi[1] - track.eta(); + double R = TMath::Sqrt((delEta * delEta) + (delPhi * delPhi)); + if (R < cfgjetR) + jetFlag = true; + std::array perpConePhiJet = getPerpendicuarPhi(leadingJetWithPtEtaPhi[2]); + double delPhiPerpCone1 = TVector2::Phi_mpi_pi(perpConePhiJet[0] - track.phi()); + double delPhiPerpCone2 = TVector2::Phi_mpi_pi(perpConePhiJet[1] - track.phi()); + double RPerpCone1 = TMath::Sqrt((delEta * delEta) + (delPhiPerpCone1 * delPhiPerpCone1)); + double RPerpCone2 = TMath::Sqrt((delEta * delEta) + (delPhiPerpCone2 * delPhiPerpCone2)); + if (RPerpCone1 < cfgjetR || RPerpCone2 < cfgjetR) + jetFlagPerpCone = true; + } else { + + for (std::size_t iDJet = 0; iDJet < mcdJetPt.size(); iDJet++) { + double delPhi = TVector2::Phi_mpi_pi(mcdJetPhi[iDJet] - track.phi()); + double delEta = mcdJetEta[iDJet] - track.eta(); + double R = TMath::Sqrt((delEta * delEta) + (delPhi * delPhi)); + + if (R < cfgjetR) { + jetFlag = true; + break; + } + } + } // jet + + if (mapPDGToValue(mcTrack.pdgCode()) != 0) { + jetHist.fill(HIST("eff/recmatched/pt/PtParticleType"), mcTrack.pt(), jetFlag, mapPDGToValue(mcTrack.pdgCode())); + if (useMcC) { + if (randUniform.Uniform(0, 1) < 0.5) + jetHist.fill(HIST("eff/recmatched/mcC/pt/PtParticleType"), track.pt(), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode())); + else + jetHist.fill(HIST("eff/recmatched/mcCSpectra/pt/PtParticleType"), track.pt(), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode())); + } + if (isTpcPassed) + jetHist.fill(HIST("eff/recmatched/pt/PtParticleTypeTPC"), mcTrack.pt(), jetFlag, mapPDGToValue(mcTrack.pdgCode())); + if (isTof) + jetHist.fill(HIST("eff/recmatched/pt/PtParticleTypeTOF"), mcTrack.pt(), jetFlag, mapPDGToValue(mcTrack.pdgCode())); + if (isTOFAndTPCPreSel) + jetHist.fill(HIST("eff/recmatched/pt/PtParticleTypeTPCTOF"), mcTrack.pt(), jetFlag, mapPDGToValue(mcTrack.pdgCode())); + + if (jetFlagPerpCone) { + jetHist.fill(HIST("eff/recmatched/perpCone/pt/PtParticleType"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode())); + if (useMcC) { + if (randUniform.Uniform(0, 1) < 0.5) + jetHist.fill(HIST("eff/recmatched/perpCone/mcC/pt/PtParticleType"), track.pt(), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode())); + else + jetHist.fill(HIST("eff/recmatched/perpCone/mcCSpectra/pt/PtParticleType"), track.pt(), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode())); + } + if (isTpcPassed) + jetHist.fill(HIST("eff/recmatched/perpCone/pt/PtParticleTypeTPC"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode())); + if (isTof) + jetHist.fill(HIST("eff/recmatched/perpCone/pt/PtParticleTypeTOF"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode())); + if (isTOFAndTPCPreSel) + jetHist.fill(HIST("eff/recmatched/perpCone/pt/PtParticleTypeTPCTOF"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode())); + } + } + } // tracks + + auto mcParticles_per_coll = particleTracks.sliceBy(perMCCol, collision.mcCollision().globalIndex()); + for (const auto& mcParticle : mcParticles_per_coll) { + if (!mcParticle.isPhysicalPrimary()) + continue; + if (fabs(mcParticle.eta()) > cfgtrkMaxEta) + continue; + if (fabs(mcParticle.y()) > cfgtrkMaxRap) + continue; + bool jetFlagMC = false; + bool jetFlagPerpConeMC = false; + if (isWithLeadingJet) { + double delPhi = TVector2::Phi_mpi_pi(leadingJetWithPtEtaPhi[2] - mcParticle.phi()); + double delEta = leadingJetWithPtEtaPhi[1] - mcParticle.eta(); + double R = TMath::Sqrt((delEta * delEta) + (delPhi * delPhi)); + if (R < cfgjetR) + jetFlagMC = true; + std::array perpConePhiJet = getPerpendicuarPhi(leadingJetWithPtEtaPhi[2]); + double delPhiPerpCone1 = TVector2::Phi_mpi_pi(perpConePhiJet[0] - mcParticle.phi()); + double delPhiPerpCone2 = TVector2::Phi_mpi_pi(perpConePhiJet[1] - mcParticle.phi()); + double RPerpCone1 = TMath::Sqrt((delEta * delEta) + (delPhiPerpCone1 * delPhiPerpCone1)); + double RPerpCone2 = TMath::Sqrt((delEta * delEta) + (delPhiPerpCone2 * delPhiPerpCone2)); + if (RPerpCone1 < cfgjetR || RPerpCone2 < cfgjetR) + jetFlagPerpConeMC = true; + } else { + + for (std::size_t iDJet = 0; iDJet < mcdJetPt.size(); iDJet++) { + double delPhi = TVector2::Phi_mpi_pi(mcdJetPhi[iDJet] - mcParticle.phi()); + double delEta = mcdJetEta[iDJet] - mcParticle.eta(); + double R = TMath::Sqrt((delEta * delEta) + (delPhi * delPhi)); + if (R < cfgjetR) { + jetFlagMC = true; + break; + } + } + } // jet + + if (mapPDGToValue(mcParticle.pdgCode()) != 0) { + jetHist.fill(HIST("eff/recmatched/gen/pt/PtParticleType"), mcParticle.pt(), jetFlagMC, mapPDGToValue(mcParticle.pdgCode())); + if (jetFlagPerpConeMC) { + jetHist.fill(HIST("eff/recmatched/gen/perpCone/pt/PtParticleType"), mcParticle.pt(), mapPDGToValue(mcParticle.pdgCode())); + } + } + + } // mcParticle + } // process + + int nprocessSimJEEvents = 0; + void processGenMatched(aod::JetMcCollision const& collision, + soa::SmallGroups> const& recocolls, + JetMCDetTable const&, JetMCPartTable const& mcpjets, aod::JetParticles const& mcParticles) + { + if (cDebugLevel > 0) { + nprocessSimJEEvents++; + if ((nprocessSimJEEvents + 1) % 100000 == 0) + LOG(debug) << "Jet Events: " << nprocessSimJEEvents; + } + if (recocolls.size() <= 0) // not reconstructed + return; + + for (const auto& recocoll : recocolls) { // return if not reconstructed event based on our selection + if (!jetderiveddatautilities::selectCollision(recocoll, jetderiveddatautilities::initialiseEventSelectionBits("sel8"))) + return; + } + if (fabs(collision.posZ()) > 10) + return; + jetHist.fill(HIST("genmatched/vertexZ"), collision.posZ()); + std::vector mcdJetPt{}; + std::vector mcdJetPhi{}; + std::vector mcdJetEta{}; + std::vector mcpJetPt{}; + std::vector mcpJetPhi{}; + std::vector mcpJetEta{}; + + // Find the mcpjet with the highest pt + auto itLeadPtJet = mcpjets.begin(); + float maxPt = -1.0f; + + for (auto it = mcpjets.begin(); it != mcpjets.end(); ++it) { + if (it.pt() > maxPt) { + maxPt = it.pt(); + itLeadPtJet = it; + LOG(debug) << " mcp jet pT " << it.pt() << " " << __LINE__; + } + } + // Process all MCP jets for general histograms + for (const auto& mcpjet : mcpjets) { + jetHist.fill(HIST("genmatched/hGenJetPt"), mcpjet.pt()); + if (!mcpjet.has_matchedJetGeo()) + continue; + jetHist.fill(HIST("genmatched/hGenJetPtMatched"), mcpjet.pt()); + } + + // Process ONLY the leading jet's matched detector jets (if valid) + if (itLeadPtJet != mcpjets.end()) { + const auto& leadingMCPJet = *itLeadPtJet; + jetHist.fill(HIST("genmatched/leadingJet/hGenJetPt"), leadingMCPJet.pt()); + if (leadingMCPJet.has_matchedJetGeo()) { + jetHist.fill(HIST("genmatched/leadingJet/hGenJetPtMatched"), leadingMCPJet.pt()); + for (auto& mcdjet : leadingMCPJet.template matchedJetGeo_as()) { + // Assuming matchedJetGeo_as returns valid MCD jets; no redundant has check needed + // Store jet properties + mcdJetPt.push_back(mcdjet.pt()); + mcdJetPhi.push_back(mcdjet.phi()); + mcdJetEta.push_back(mcdjet.eta()); + mcpJetPt.push_back(leadingMCPJet.pt()); + mcpJetPhi.push_back(leadingMCPJet.phi()); + mcpJetEta.push_back(leadingMCPJet.eta()); + // Fill histograms with MCD (reco) and MCP (gen) properties + jetHist.fill(HIST("genmatched/hRecJetPt"), mcdjet.pt()); + jetHist.fill(HIST("genmatched/hRecJetWithGenPt"), leadingMCPJet.pt()); + // Resolution plots: Gen - Reco + jetHist.fill(HIST("genmatched/hRecMatchedJetPt"), leadingMCPJet.pt(), leadingMCPJet.pt() - mcdjet.pt()); + jetHist.fill(HIST("genmatched/hRecMatchedJetPhi"), leadingMCPJet.phi(), leadingMCPJet.phi() - mcdjet.phi()); + jetHist.fill(HIST("genmatched/hRecMatchedJetEta"), leadingMCPJet.eta(), leadingMCPJet.eta() - mcdjet.eta()); + + if (useMcC) { + if (randUniform.Uniform(0, 1) < 0.5) { + jetHist.fill(HIST("genmatched/hRecMatchedVsGenJetPt"), mcdjet.pt(), leadingMCPJet.pt()); + } else { + jetHist.fill(HIST("genmatched/mcC/hRecMatchedVsGenJetPt"), mcdjet.pt(), leadingMCPJet.pt()); + } + } + jetHist.fill(HIST("genmatched/hRecMatchedVsGenJetPtVsEta"), mcdjet.pt(), mcdjet.eta()); + + } // End loop over mcdjet + } + } // leading jet only + + for (const auto& mcParticle : mcParticles) { + if (fabs(mcParticle.eta()) > cfgtrkMaxEta) + continue; + // add pid later + + bool jetFlag = false; + for (std::size_t iDJet = 0; iDJet < mcpJetPt.size(); iDJet++) { + double delPhi = TVector2::Phi_mpi_pi(mcpJetPhi[iDJet] - mcParticle.phi()); + double delEta = mcpJetEta[iDJet] - mcParticle.eta(); + double R = TMath::Sqrt((delEta * delEta) + (delPhi * delPhi)); + + if (R < cfgjetR) { + jetFlag = true; + break; + } + } // DetJet + if (mapPDGToValue(mcParticle.pdgCode()) != 0) { + jetHist.fill(HIST("genmatched/pt/PtParticleType"), mcParticle.pt(), jetFlag, mapPDGToValue(mcParticle.pdgCode())); + } + } // jet constituents + } // process + + PROCESS_SWITCH(nucleiInJets, processJetTracksData, "nuclei in Jets data", true); + PROCESS_SWITCH(nucleiInJets, processJetTracksDataLfPid, "nuclei in Jets data", false); + PROCESS_SWITCH(nucleiInJets, processMCRec, "nuclei in Jets for detectorlevel Jets", false); + PROCESS_SWITCH(nucleiInJets, processMCGen, "nuclei in Jets MC particlelevel Jets", false); + PROCESS_SWITCH(nucleiInJets, processRecMatched, "nuclei in Jets rec matched", false); + PROCESS_SWITCH(nucleiInJets, processGenMatched, "nuclei in Jets gen matched", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"nuclei-in-jets"})}; +}; diff --git a/PWGJE/Tasks/phiInJets.cxx b/PWGJE/Tasks/phiInJets.cxx index f13033fe533..be99a57a576 100644 --- a/PWGJE/Tasks/phiInJets.cxx +++ b/PWGJE/Tasks/phiInJets.cxx @@ -15,9 +15,14 @@ /// /// \author Adrian Fereydon Nassirpour +#include +#include #include #include +#include +#include +#include "TRandom.h" #include "Framework/ASoA.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" @@ -49,24 +54,11 @@ struct phiInJets { SliceCache cache; HistogramRegistry JEhistos{"JEhistos", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registry{"registry", - {{"h_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, - {"h_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, - {"h_jet_phi", "jet #phi;#phi_{jet};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}, - {"h_matched_REC_jet_pt", "matched_REC level jet pT;#it{p}_{T,jet part} (GeV/#it{c});Delta", {HistType::kTH2F, {{200, 0., 200.}, {400, -20., 20.}}}}, - {"h_matched_REC_jet_eta", "matched_REC level jet #eta;#eta_{jet part};Delta", {HistType::kTH2F, {{100, -1.0, 1.0}, {400, -20., 20.}}}}, - {"h_matched_REC_jet_phi", "matched_REC level jet #phi;#phi_{jet part};Delta", {HistType::kTH2F, {{80, -1.0, 7.}, {400, -20., 20.}}}}, - {"h_matched_GEN_jet_pt", "matched_GEN level jet pT;#it{p}_{T,jet part} (GeV/#it{c});Delta", {HistType::kTH2F, {{200, 0., 200.}, {400, -20., 20.}}}}, - {"h_matched_GEN_jet_eta", "matched_GEN level jet #eta;#eta_{jet part};Delta", {HistType::kTH2F, {{100, -1.0, 1.0}, {400, -20., 20.}}}}, - {"h_matched_GEN_jet_phi", "matched_GEN level jet #phi;#phi_{jet part};Delta", {HistType::kTH2F, {{80, -1.0, 7.}, {400, -20., 20.}}}}, - {"h_part_jet_pt", "particle level jet pT;#it{p}_{T,jet part} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, - {"h_part_jet_eta", "particle level jet #eta;#eta_{jet part};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, - {"h_part_jet_phi", "particle level jet #phi;#phi_{jet part};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}}}; - Configurable cfgeventSelections{"cfgeventSelections", "sel8", "choose event selection"}; Configurable cfgtrackSelections{"cfgtrackSelections", "globalTracks", "set track selections"}; Configurable cfgtrkMinPt{"cfgtrkMinPt", 0.15, "set track min pT"}; + Configurable cfgtrkMaxEta{"cfgtrkMaxEta", 0.9, "set track max Eta"}; Configurable cfgMaxDCArToPVcut{"cfgMaxDCArToPVcut", 0.5, "Track DCAr cut to PV Maximum"}; Configurable cfgMaxDCAzToPVcut{"cfgMaxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz @@ -81,11 +73,29 @@ struct phiInJets { Configurable cfgnTOFPID{"cfgnTOFPID", 4, "nTOF PID"}; Configurable cfgjetPtMin{"cfgjetPtMin", 5.0, "minimum jet pT cut"}; Configurable cfgjetR{"cfgjetR", 0.4, "jet resolution parameter"}; + Configurable cfgVtxCut{"cfgVtxCut", 10.0, "V_z cut selection"}; Configurable cDebugLevel{"cDebugLevel", 0, "Resolution of Debug"}; + Configurable cfgBR{"cfgBR", false, "Forces Gen. Charged BR Only"}; + Configurable cfgSimPID{"cfgSimPID", false, "Enforces PID on the Gen. Rec level"}; + Configurable cfgSingleJet{"cfgSingleJet", false, "Enforces strict phi-jet correspondance"}; + Configurable cfgIsKstar{"cfgIsKstar", false, "Swaps Phi for Kstar analysis"}; + Configurable cfgDataHists{"cfgDataHists", false, "Enables DataHists"}; + Configurable cfgMCRecHists{"cfgMCRecHists", false, "Enables MCRecHists"}; + Configurable cfgMCRecMBHists{"cfgMCRecMBHists", false, "Enables MCRec MB Hists"}; + Configurable cfgMCRecInsideHists{"cfgMCRecInsideHists", false, "Enables MCRec Inside Hists"}; + Configurable cfgMCRecRotationalHists{"cfgMCRecRotationalHists", false, "Enables MCRotational Hists"}; + Configurable cfgMCGenHists{"cfgMCGenHists", false, "Enables MCGenHists"}; + Configurable cfgMCGenMATCHEDHists{"cfgMCGenMATCHEDHists", false, "Enables MCGenMATCHEDHists"}; + Configurable cfgMCRecMATCHEDHists{"cfgMCRecMATCHEDHists", false, "Enables MCRecMATCHEDHists"}; + + Configurable cfgMinvNBins{"cfgMinvNBins", 500, "Number of bins for Minv axis"}; + Configurable cfgMinvMin{"cfgMinvMin", 0.75, "Minimum Minv value"}; + Configurable cfgMinvMax{"cfgMinvMax", 1.25, "Maximum Minv value"}; + // CONFIG DONE ///////////////////////////////////////// //INIT - int eventSelection = -1; + std::vector eventSelectionBits; void init(o2::framework::InitContext&) { @@ -93,101 +103,177 @@ struct phiInJets { const AxisSpec axisEta{30, -1.5, +1.5, "#eta"}; const AxisSpec axisPhi{200, -1, +7, "#phi"}; const AxisSpec axisPt{200, 0, +200, "#pt"}; - const AxisSpec MinvAxis = {400, 0.95, 1.35}; + const AxisSpec MinvAxis = {cfgMinvNBins, cfgMinvMin, cfgMinvMax}; const AxisSpec PtAxis = {200, 0, 20.0}; const AxisSpec MultAxis = {100, 0, 100}; - const AxisSpec dRAxis = {100, 0, 3.6}; - - JEhistos.add("ptJEHistogramPion", "ptJEHistogramPion", kTH1F, {PtAxis}); - JEhistos.add("ptJEHistogramKaon", "ptJEHistogramKaon", kTH1F, {PtAxis}); - JEhistos.add("ptJEHistogramProton", "ptJEHistogramProton", kTH1F, {PtAxis}); - JEhistos.add("ptJEHistogramPhi", "ptJEHistogramPhi", kTH1F, {PtAxis}); - JEhistos.add("minvJEHistogramPhi", "minvJEHistogramPhi", kTH1F, {MinvAxis}); - - JEhistos.add("ptGeneratedPion", "ptGeneratedPion", kTH1F, {PtAxis}); - JEhistos.add("ptGeneratedKaon", "ptGeneratedKaon", kTH1F, {PtAxis}); - JEhistos.add("ptGeneratedProton", "ptGeneratedProton", kTH1F, {PtAxis}); - JEhistos.add("ptGeneratedPhi", "ptGeneratedPhi", kTH1F, {PtAxis}); - JEhistos.add("mGeneratedPhi", "mGeneratedPhi", kTH1F, {MinvAxis}); - - JEhistos.add("etaHistogram", "etaHistogram", kTH1F, {axisEta}); - JEhistos.add("phiHistogram", "phiHistogram", kTH1F, {axisPhi}); - JEhistos.add("FJetaHistogram", "FJetaHistogram", kTH1F, {axisEta}); - JEhistos.add("FJphiHistogram", "FJphiHistogram", kTH1F, {axisPhi}); - JEhistos.add("FJptHistogram", "FJptHistogram", kTH1F, {axisPt}); - JEhistos.add("FJetaHistogram_MCRec", "FJetaHistogram_MCRec", kTH1F, {axisEta}); - JEhistos.add("FJphiHistogram_MCRec", "FJphiHistogram_MCRec", kTH1F, {axisPhi}); - JEhistos.add("FJptHistogram_MCRec", "FJptHistogram_MCRec", kTH1F, {axisPt}); - JEhistos.add("FJetaHistogram_MCTrue", "FJetaHistogram_MCTrue", kTH1F, {axisEta}); - JEhistos.add("FJphiHistogram_MCTrue", "FJphiHistogram_MCTrue", kTH1F, {axisPhi}); - JEhistos.add("FJptHistogram_MCTrue", "FJptHistogram_MCTrue", kTH1F, {axisPt}); - - JEhistos.add("FJnchHistogram", "FJnchHistogram", kTH1F, {MultAxis}); - JEhistos.add("nEvents", "nEvents", kTH1F, {{4, 0.0, 4.0}}); - JEhistos.add("nEvents_MCRec", "nEvents_MCRec", kTH1F, {{4, 0.0, 4.0}}); - JEhistos.add("nEvents_MCGen", "nEvents_MCGen", kTH1F, {{4, 0.0, 4.0}}); - - JEhistos.add("nJetsPerEvent", "nJetsPerEvent", kTH1F, {{10, 0.0, 10.0}}); - - JEhistos.add("hDCArToPv", "DCArToPv", kTH1F, {{300, 0.0, 3.0}}); - JEhistos.add("hDCAzToPv", "DCAzToPv", kTH1F, {{300, 0.0, 3.0}}); - JEhistos.add("rawpT", "rawpT", kTH1F, {{1000, 0.0, 10.0}}); - JEhistos.add("rawDpT", "rawDpT", kTH2F, {{1000, 0.0, 10.0}, {300, -1.5, 1.5}}); - JEhistos.add("hIsPrim", "hIsPrim", kTH1F, {{2, -0.5, +1.5}}); - JEhistos.add("hIsGood", "hIsGood", kTH1F, {{2, -0.5, +1.5}}); - JEhistos.add("hIsPrimCont", "hIsPrimCont", kTH1F, {{2, -0.5, +1.5}}); - JEhistos.add("hFindableTPCClusters", "hFindableTPCClusters", kTH1F, {{200, 0, 200}}); - JEhistos.add("hFindableTPCRows", "hFindableTPCRows", kTH1F, {{200, 0, 200}}); - JEhistos.add("hClustersVsRows", "hClustersVsRows", kTH1F, {{200, 0, 2}}); - JEhistos.add("hTPCChi2", "hTPCChi2", kTH1F, {{200, 0, 100}}); - JEhistos.add("hITSChi2", "hITSChi2", kTH1F, {{200, 0, 100}}); - - JEhistos.add("hUSS", "hUSS", kTH3F, {dRAxis, PtAxis, MinvAxis}); - JEhistos.add("hUSS_1D", "hUSS_1D", kTH1F, {MinvAxis}); - JEhistos.add("hUSS_1D_2_3", "hUSS_1D_2_3", kTH1F, {MinvAxis}); - JEhistos.add("hLSS", "hLSS", kTH3F, {dRAxis, PtAxis, MinvAxis}); - JEhistos.add("hLSS_1D", "hLSS_1D", kTH1F, {MinvAxis}); - JEhistos.add("hLSS_1D_2_3", "hLSS_1D_2_3", kTH1F, {MinvAxis}); - JEhistos.add("hUSS_INSIDE", "hUSS_INSIDE", kTH3F, {dRAxis, PtAxis, MinvAxis}); - JEhistos.add("hUSS_INSIDE_1D", "hUSS_INSIDE_1D", kTH1F, {MinvAxis}); - JEhistos.add("hUSS_INSIDE_1D_2_3", "hUSS_INSIDE_1D_2_3", kTH1F, {MinvAxis}); - JEhistos.add("hLSS_INSIDE", "hLSS_INSIDE", kTH3F, {dRAxis, PtAxis, MinvAxis}); - JEhistos.add("hLSS_INSIDE_1D", "hLSS_INSIDE_1D", kTH1F, {MinvAxis}); - JEhistos.add("hLSS_INSIDE_1D_2_3", "hLSS_INSIDE_1D_2_3", kTH1F, {MinvAxis}); - JEhistos.add("hUSS_OUTSIDE", "hUSS_OUTSIDE", kTH3F, {dRAxis, PtAxis, MinvAxis}); - JEhistos.add("hUSS_OUTSIDE_1D", "hUSS_OUTSIDE_1D", kTH1F, {MinvAxis}); - JEhistos.add("hUSS_OUTSIDE_1D_2_3", "hUSS_OUTSIDE_1D_2_3", kTH1F, {MinvAxis}); - JEhistos.add("hLSS_OUTSIDE", "hLSS_OUTSIDE", kTH3F, {dRAxis, PtAxis, MinvAxis}); - JEhistos.add("hLSS_OUTSIDE_1D", "hLSS_OUTSIDE_1D", kTH1F, {MinvAxis}); - JEhistos.add("hLSS_OUTSIDE_1D_2_3", "hLSS_OUTSIDE_1D_2_3", kTH1F, {MinvAxis}); - - JEhistos.add("hMCTrue_hUSS_INSIDE", "hMCTrue_hUSS_INSIDE", kTH3F, {dRAxis, PtAxis, MinvAxis}); - JEhistos.add("hMCTrue_hUSS_INSIDE_1D", "hMCTrue_hUSS_INSIDE_1D", kTH1F, {MinvAxis}); - JEhistos.add("hMCTrue_hUSS_INSIDE_1D_2_3", "hMCTrue_hUSS_INSIDE_1D_2_3", kTH1F, {MinvAxis}); - JEhistos.add("hMCTrue_hUSS_OUTSIDE", "hMCTrue_hUSS_OUTSIDE", kTH3F, {dRAxis, PtAxis, MinvAxis}); - JEhistos.add("hMCTrue_hUSS_OUTSIDE_1D", "hMCTrue_hUSS_OUTSIDE_1D", kTH1F, {MinvAxis}); - JEhistos.add("hMCTrue_hUSS_OUTSIDE_1D_2_3", "hMCTrue_hUSS_OUTSIDE_1D_2_3", kTH1F, {MinvAxis}); - - JEhistos.add("hMCRec_hUSS", "hMCRec_hUSS", kTH3F, {dRAxis, PtAxis, MinvAxis}); - JEhistos.add("hMCRec_hUSS_1D", "hMCRec_hUSS_1D", kTH1F, {MinvAxis}); - JEhistos.add("hMCRec_hUSS_1D_2_3", "hMCRec_hUSS_1D_2_3", kTH1F, {MinvAxis}); - JEhistos.add("hMCRec_hUSS_INSIDE", "hMCRec_hUSS_INSIDE", kTH3F, {dRAxis, PtAxis, MinvAxis}); - JEhistos.add("hMCRec_hUSS_INSIDE_1D", "hMCRec_hUSS_INSIDE_1D", kTH1F, {MinvAxis}); - JEhistos.add("hMCRec_hUSS_INSIDE_1D_2_3", "hMCRec_hUSS_INSIDE_1D_2_3", kTH1F, {MinvAxis}); - JEhistos.add("hMCRec_hUSS_OUTSIDE", "hMCRec_hUSS_OUTSIDE", kTH3F, {dRAxis, PtAxis, MinvAxis}); - JEhistos.add("hMCRec_hUSS_OUTSIDE_1D", "hMCRec_hUSS_OUTSIDE_1D", kTH1F, {MinvAxis}); - JEhistos.add("hMCRec_hUSS_OUTSIDE_1D_2_3", "hMCRec_hUSS_OUTSIDE_1D_2_3", kTH1F, {MinvAxis}); + const AxisSpec dRAxis = {100, 0, 100}; + + // Now we define histograms. Due to saving space, we only reserve histogram memory for histograms we will be filling. + + if (cfgDataHists) { + JEhistos.add("nEvents", "nEvents", kTH1F, {{4, 0.0, 4.0}}); + JEhistos.add("hDCArToPv", "DCArToPv", kTH1F, {{300, 0.0, 3.0}}); + JEhistos.add("hDCAzToPv", "DCAzToPv", kTH1F, {{300, 0.0, 3.0}}); + JEhistos.add("rawpT", "rawpT", kTH1F, {{1000, 0.0, 10.0}}); + JEhistos.add("rawDpT", "rawDpT", kTH2F, {{1000, 0.0, 10.0}, {300, -1.5, 1.5}}); + JEhistos.add("hIsPrim", "hIsPrim", kTH1F, {{2, -0.5, +1.5}}); + JEhistos.add("hIsGood", "hIsGood", kTH1F, {{2, -0.5, +1.5}}); + JEhistos.add("hIsPrimCont", "hIsPrimCont", kTH1F, {{2, -0.5, +1.5}}); + JEhistos.add("hFindableTPCClusters", "hFindableTPCClusters", kTH1F, {{200, 0, 200}}); + JEhistos.add("hFindableTPCRows", "hFindableTPCRows", kTH1F, {{200, 0, 200}}); + JEhistos.add("hClustersVsRows", "hClustersVsRows", kTH1F, {{200, 0, 2}}); + JEhistos.add("hTPCChi2", "hTPCChi2", kTH1F, {{200, 0, 100}}); + JEhistos.add("hITSChi2", "hITSChi2", kTH1F, {{200, 0, 100}}); + JEhistos.add("etaHistogram", "etaHistogram", kTH1F, {axisEta}); + JEhistos.add("phiHistogram", "phiHistogram", kTH1F, {axisPhi}); + + JEhistos.add("hNResoPerEvent", "hNResoPerEvent", kTH1F, {{10, 0, 10}}); + JEhistos.add("hNResoPerEventWJet", "hNResoPerEventWJet", kTH1F, {{10, 0, 10}}); + JEhistos.add("hNResoPerEventInJet", "hNResoPerEventInJet", kTH1F, {{10, 0, 10}}); + + JEhistos.add("FJetaHistogram", "FJetaHistogram", kTH1F, {axisEta}); + JEhistos.add("FJphiHistogram", "FJphiHistogram", kTH1F, {axisPhi}); + JEhistos.add("FJptHistogram", "FJptHistogram", kTH1F, {axisPt}); + JEhistos.add("nJetsPerEvent", "nJetsPerEvent", kTH1F, {{10, 0.0, 10.0}}); + + JEhistos.add("hUSS", "hUSS", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("hUSS_1D", "hUSS_1D", kTH1F, {MinvAxis}); + JEhistos.add("hUSS_1D_2_3", "hUSS_1D_2_3", kTH1F, {MinvAxis}); + JEhistos.add("hLSS", "hLSS", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("hLSS_1D", "hLSS_1D", kTH1F, {MinvAxis}); + JEhistos.add("hLSS_1D_2_3", "hLSS_1D_2_3", kTH1F, {MinvAxis}); + JEhistos.add("hUSS_INSIDE", "hUSS_INSIDE", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("hUSS_INSIDE_1D", "hUSS_INSIDE_1D", kTH1F, {MinvAxis}); + JEhistos.add("hUSS_INSIDE_1D_2_3", "hUSS_INSIDE_1D_2_3", kTH1F, {MinvAxis}); + JEhistos.add("hLSS_INSIDE", "hLSS_INSIDE", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("hLSS_INSIDE_1D", "hLSS_INSIDE_1D", kTH1F, {MinvAxis}); + JEhistos.add("hLSS_INSIDE_1D_2_3", "hLSS_INSIDE_1D_2_3", kTH1F, {MinvAxis}); + } + + if (cfgMCRecHists) { + JEhistos.add("nEvents_MCRec", "nEvents_MCRec", kTH1F, {{4, 0.0, 4.0}}); + + JEhistos.add("h_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{4000, 0., 200.}}}); + JEhistos.add("h_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + JEhistos.add("h_jet_phi", "jet #phi;#phi_{jet};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}); + + JEhistos.add("ptJEHistogramPion", "ptJEHistogramPion", kTH1F, {PtAxis}); + JEhistos.add("ptJEHistogramKaon", "ptJEHistogramKaon", kTH1F, {PtAxis}); + JEhistos.add("ptJEHistogramProton", "ptJEHistogramProton", kTH1F, {PtAxis}); + JEhistos.add("ptJEHistogramPhi", "ptJEHistogramPhi", kTH1F, {PtAxis}); + JEhistos.add("ptJEHistogramPhi_JetTrigger", "ptJEHistogramPhi_JetTrigger", kTH1F, {PtAxis}); + JEhistos.add("minvJEHistogramPhi", "minvJEHistogramPhi", kTH1F, {MinvAxis}); + JEhistos.add("hNRealPhiVPhiCand", "hNRealPhiVPhiCand", kTH2F, {{10, 0, 10}, {10, 0, 10}}); + JEhistos.add("hNRealPhiWithJetVPhiCand", "hNRealPhiWithJetVPhiCand", kTH2F, {{10, 0, 10}, {10, 0, 10}}); + JEhistos.add("hNRealPhiInJetVPhiCand", "hNRealPhiInJetVPhiCand", kTH2F, {{10, 0, 10}, {10, 0, 10}}); + + JEhistos.add("hMCRec_nonmatch_hUSS_KtoKangle_v_pt", "hMCRec_nonmatch_hUSS_KtoKangle_v_pt", kTH2F, {axisEta, PtAxis}); + JEhistos.add("hMCRec_nonmatch_hUSS_Kangle_v_pt", "hMCRec_nonmatch_hUSS_Kangle_v_pt", kTH2F, {axisEta, PtAxis}); + JEhistos.add("hMCRec_nonmatch_hUSS_INSIDE_pt_v_eta", "hMCRec_nonmatch_hUSS_INSIDE_pt_v_eta", kTH2F, {PtAxis, axisEta}); + JEhistos.add("JetVsPhi_REC", "JetVsPhi_REC", kTH2F, {{4000, 0., 200.}, {200, 0, 20.0}}); + + // used for Minv closure tests + // MB + if (cfgMCRecMBHists) { + JEhistos.add("hMCRec_hUSS", "hMCRec_hUSS", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("hMCRec_hLSS", "hMCRec_hLSS", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("hMCRecTrue_hUSS", "hMCRecTrue_hUSS", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("hMCRecTrue_hLSS", "hMCRecTrue_hLSS", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("hMCRec_R_distribution", "hMCRec_R_distribution", kTH1F, {{100, 0.0, 2 * TMath::Pi()}}); + JEhistos.add("hMCRec_dPhi_distribution", "hMCRec_dPhi_distribution", kTH1F, {{80, -5.0, 7.0}}); + JEhistos.add("hMCRec_dEta_distribution", "hMCRec_dEta_distribution", kTH1F, {{100, -2.0, 2.0}}); + } + if (cfgMCRecRotationalHists) { + JEhistos.add("hMCRec_hUSS_Rotational", "hMCRec_hUSS_Rotational", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("hMCRec_R_Rotation_distribution", "hMCRec_R_Rotation_distribution", HistType::kTH1F, {{100, 0.0, 2 * TMath::Pi()}}); + JEhistos.add("hMCRec_dPhi_rot_distribution", "hMCRec_dPhi_rot_distribution", kTH1F, {{80, -5.0, 7.0}}); + JEhistos.add("hMCRec_dEta_rot_distribution", "hMCRec_dEta_rot_distribution", kTH1F, {{100, -2.0, 2.0}}); + JEhistos.add("hMCRec_dEta_qa_rot_distribution", "hMCRec_dEta_qa_rot_distribution", kTH1F, {{100, -4.0, 2.0}}); + } + } + // INSIDE + if (cfgMCRecInsideHists) { + JEhistos.add("hMCRec_hUSS_INSIDE", "hMCRec_hUSS_INSIDE", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("hMCRec_hLSS_INSIDE", "hMCRec_hLSS_INSIDE", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("hMCRecTrue_hUSS_INSIDE", "hMCRecTrue_hUSS_INSIDE", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("hMCRecTrue_hLSS_INSIDE", "hMCRecTrue_hLSS_INSIDE", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("hMCRec_nonmatch_hUSS_INSIDE", "hMCRec_nonmatch_hUSS_INSIDE", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("hMCRec_nonmatch_hUSS_INSIDE_1D", "hMCRec_nonmatch_hUSS_INSIDE_1D", kTH1F, {MinvAxis}); + JEhistos.add("hMCRec_nonmatch_hUSS_INSIDE_1D_2_3", "hMCRec_nonmatch_hUSS_INSIDE_1D_2_3", kTH1F, {MinvAxis}); + } + + if (cfgMCGenHists) { + JEhistos.add("nEvents_MCGen", "nEvents_MCGen", kTH1F, {{4, 0.0, 4.0}}); + + JEhistos.add("h_part_jet_pt", "particle level jet pT;#it{p}_{T,jet part} (GeV/#it{c});entries", {HistType::kTH1F, {{4000, 0., 200.}}}); + JEhistos.add("h_part_jet_eta", "particle level jet #eta;#eta_{jet part};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + JEhistos.add("h_part_jet_phi", "particle level jet #phi;#phi_{jet part};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}); + + JEhistos.add("ptGeneratedPion", "ptGeneratedPion", kTH1F, {PtAxis}); + JEhistos.add("ptGeneratedKaon", "ptGeneratedKaon", kTH1F, {PtAxis}); + JEhistos.add("ptGeneratedProton", "ptGeneratedProton", kTH1F, {PtAxis}); + JEhistos.add("ptGeneratedPhi", "ptGeneratedPhi", kTH1F, {PtAxis}); + JEhistos.add("ptGeneratedPhi_ALLBR", "ptGeneratedPhi_ALLBR", kTH1F, {PtAxis}); + + JEhistos.add("ptGeneratedPhi_JetTrigger", "ptGeneratedPhi_JetTrigger", kTH1F, {PtAxis}); + JEhistos.add("mGeneratedPhi", "mGeneratedPhi", kTH1F, {MinvAxis}); + + JEhistos.add("hMCTrue_nonmatch_hUSS_Kangle_v_pt", "hMCTrue_nonmatch_hUSS_Kangle_v_pt", kTH2F, {axisEta, PtAxis}); + JEhistos.add("hMCTrue_nonmatch_hUSS_INSIDE_pt_v_eta", "hMCTrue_nonmatch_hUSS_INSIDE_pt_v_eta", kTH2F, {PtAxis, axisEta}); + JEhistos.add("JetVsPhi_GEN", "JetVsPhi_GEN", kTH2F, {{4000, 0., 200.}, {200, 0, 20.0}}); + + JEhistos.add("hMCTrue_nonmatch_hUSS_INSIDE", "hMCTrue_nonmatch_hUSS_INSIDE", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("hMCTrue_nonmatch_hUSS_INSIDE_1D", "hMCTrue_nonmatch_hUSS_INSIDE_1D", kTH1F, {MinvAxis}); + JEhistos.add("hMCTrue_nonmatch_hUSS_INSIDE_1D_2_3", "hMCTrue_nonmatch_hUSS_INSIDE_1D_2_3", kTH1F, {MinvAxis}); + } + + if (cfgMCGenMATCHEDHists) { + JEhistos.add("nEvents_MCGen_MATCHED", "nEvents_MCGen_MATCHED", kTH1F, {{4, 0.0, 4.0}}); + + JEhistos.add("h_matched_GEN_jet_pt", "matched_GEN level jet pT;#it{p}_{T,jet part} (GeV/#it{c});Delta", {HistType::kTH2F, {{200, 0., 200.}, {400, -20., 20.}}}); + JEhistos.add("h_matched_GEN_jet_eta", "matched_GEN level jet #eta;#eta_{jet part};Delta", {HistType::kTH2F, {{100, -1.0, 1.0}, {400, -20., 20.}}}); + JEhistos.add("h_matched_GEN_jet_phi", "matched_GEN level jet #phi;#phi_{jet part};Delta", {HistType::kTH2F, {{80, -1.0, 7.}, {400, -20., 20.}}}); + JEhistos.add("2DGenToRec", "2DGenToRec", kTH2F, {PtAxis, axisPt}); + JEhistos.add("2DGenToRec_constrained", "2DGenToRec_constrained", kTH2F, {PtAxis, axisPt}); + JEhistos.add("RespGen_Matrix_MATCHED", "RespGen_Matrix_MATCHED", HistType::kTHnSparseD, {PtAxis, axisPt, PtAxis, axisPt}); // REC(Phi,Jet), GEN(Phi,Jet) + JEhistos.add("RespGen_Matrix_MATCHED_rand0", "RespGen_Matrix_MATCHED_rand0", HistType::kTHnSparseD, {PtAxis, axisPt, PtAxis, axisPt}); // REC(Phi,Jet), GEN(Phi,Jet) + JEhistos.add("RespGen_Matrix_MATCHED_rand1", "RespGen_Matrix_MATCHED_rand1", HistType::kTHnSparseD, {PtAxis, axisPt, PtAxis, axisPt}); // REC(Phi,Jet), GEN(Phi,Jet) + + JEhistos.add("hMCTrue_hUSS_INSIDE", "hMCTrue_hUSS_INSIDE", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("hMCTrue_hUSS_INSIDE_1D", "hMCTrue_hUSS_INSIDE_1D", kTH1F, {MinvAxis}); + JEhistos.add("hMCTrue_hUSS_INSIDE_1D_2_3", "hMCTrue_hUSS_INSIDE_1D_2_3", kTH1F, {MinvAxis}); + } + + if (cfgMCRecMATCHEDHists) { + JEhistos.add("nEvents_MCRec_MATCHED", "nEvents_MCRec_MATCHED", kTH1F, {{4, 0.0, 4.0}}); + + JEhistos.add("h_matched_REC_jet_pt", "matched_REC level jet pT;#it{p}_{T,jet part} (GeV/#it{c});Delta", {HistType::kTH2F, {{200, 0., 200.}, {400, -20., 20.}}}); + JEhistos.add("h_matched_REC_jet_eta", "matched_REC level jet #eta;#eta_{jet part};Delta", {HistType::kTH2F, {{100, -1.0, 1.0}, {400, -20., 20.}}}); + JEhistos.add("h_matched_REC_jet_phi", "matched_REC level jet #phi;#phi_{jet part};Delta", {HistType::kTH2F, {{80, -1.0, 7.}, {400, -20., 20.}}}); + + JEhistos.add("Resp_Matrix_MATCHED", "Resp_Matrix_MATCHED", HistType::kTHnSparseD, {PtAxis, axisPt, PtAxis, axisPt}); // REC(Phi,Jet), GEN(Phi,Jet) + JEhistos.add("Resp_Matrix_MATCHED_rand0", "Resp_Matrix_MATCHED_rand0", HistType::kTHnSparseD, {PtAxis, axisPt, PtAxis, axisPt}); // REC(Phi,Jet), GEN(Phi,Jet) + JEhistos.add("Resp_Matrix_MATCHED_rand1", "Resp_Matrix_MATCHED_rand1", HistType::kTHnSparseD, {PtAxis, axisPt, PtAxis, axisPt}); // REC(Phi,Jet), GEN(Phi,Jet) + + JEhistos.add("2DRecToGen", "2DRecToGen", kTH2F, {PtAxis, axisPt}); + JEhistos.add("2DRecToGen_constrained", "2DRecToGen_constrained", kTH2F, {PtAxis, axisPt}); + + JEhistos.add("hMCRec_hUSS_INSIDE", "hMCRec_hUSS_INSIDE", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("hMCRec_hUSS_INSIDE_1D", "hMCRec_hUSS_INSIDE_1D", kTH1F, {MinvAxis}); + JEhistos.add("hMCRec_hUSS_INSIDE_1D_2_3", "hMCRec_hUSS_INSIDE_1D_2_3", kTH1F, {MinvAxis}); + } // EVENT SELECTION - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(cfgeventSelections)); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(cfgeventSelections)); } // end of init double massKa = o2::constants::physics::MassKPlus; + double massPi = o2::constants::physics::MassPiMinus; using EventCandidates = soa::Join; // , aod::CentFT0Ms, aod::CentFT0As, aod::CentFT0Cs using TrackCandidates = soa::Join; + aod::pidTPCKa, aod::pidTOFKa, aod::pidTPCPi, aod::pidTOFPi>; Filter jetCuts = aod::jet::pt > cfgjetPtMin&& aod::jet::r == nround(cfgjetR.node() * 100.0f); // Function for track quality cuts @@ -197,7 +283,10 @@ struct phiInJets { bool trackSelection(const TrackType track) { // basic track cuts - if (std::abs(track.pt()) < cfgtrkMinPt) + if (track.pt() < cfgtrkMinPt) + return false; + + if (std::abs(track.eta()) > cfgtrkMaxEta) return false; if (std::abs(track.dcaXY()) > cfgMaxDCArToPVcut) @@ -212,27 +301,45 @@ struct phiInJets { if (track.tpcNClsFindable() < cfgnFindableTPCClusters) return false; - if (std::abs(track.tpcNClsCrossedRows()) < cfgnTPCCrossedRows) + if (track.tpcNClsCrossedRows() < cfgnTPCCrossedRows) return false; - if (std::abs(track.tpcCrossedRowsOverFindableCls()) > cfgnRowsOverFindable) + if (track.tpcCrossedRowsOverFindableCls() > cfgnRowsOverFindable) return false; - if (std::abs(track.tpcChi2NCl()) > cfgnTPCChi2) + if (track.tpcChi2NCl() > cfgnTPCChi2) return false; - if (std::abs(track.itsChi2NCl()) > cfgnITSChi2) + if (track.itsChi2NCl() > cfgnITSChi2) return false; if (cfgConnectedToPV && !track.isPVContributor()) return false; + return true; }; ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// template - bool trackPID(const T& candidate) + bool trackPID(const T& candidate, bool FT) + { + bool pid = false; + + if (!cfgIsKstar) { + pid = trackPIDKaon(candidate); + + } else { + if (!FT) + pid = trackPIDPion(candidate); + else + pid = trackPIDKaon(candidate); + } + return pid; + } + + template + bool trackPIDKaon(const T& candidate) { bool tpcPIDPassed{false}, tofPIDPassed{false}; if (std::abs(candidate.tpcNSigmaKa()) < cfgnTPCPID) @@ -250,46 +357,119 @@ struct phiInJets { } return false; } + + template + bool trackPIDPion(const T& candidate) + { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + if (std::abs(candidate.tpcNSigmaPi()) < cfgnTPCPID) + tpcPIDPassed = true; + + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaPi()) < cfgnTOFPID) { + tofPIDPassed = true; + } + } else { + tofPIDPassed = true; + } + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + return false; + } + ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// + template + double DistinguishJets(const JetType& jets, const TLorentzVector lResonance) + { + if (cDebugLevel > 0) + std::cout << "oof, multiple jets fit to the same phi. Time to find the best phi-jet link" << std::endl; + + double best_R = 0; + double best_jetpt = 0; + for (auto const& jet : jets) { + double phidiff = TVector2::Phi_mpi_pi(jet.phi() - lResonance.Phi()); + double etadiff = jet.eta() - lResonance.Eta(); + double R = TMath::Sqrt((etadiff * etadiff) + (phidiff * phidiff)); + if (R < cfgjetR && best_R == 0) { + best_R = R; + best_jetpt = jet.pt(); + } else if (R < best_R) { + best_R = R; + best_jetpt = jet.pt(); + } + } // jetloop + return best_jetpt; + } + + template + double DistinguishJetsMC(const Jet_pt& jet_pt, const Jet_phi& jet_phi, const Jet_eta& jet_eta, const TLorentzVector lResonance) + { + if (cDebugLevel > 0) + std::cout << "oof, multiple jets fit to the same phi. Time to find the best phi-jet link" << std::endl; + + double best_R = 0; + double best_jetpt = 0; + for (std::vector::size_type i = 0; i < jet_pt.size(); i++) { + double phidiff = TVector2::Phi_mpi_pi(jet_phi[i] - lResonance.Phi()); + double etadiff = jet_eta[i] - lResonance.Eta(); + double R = TMath::Sqrt((etadiff * etadiff) + (phidiff * phidiff)); + if (R < cfgjetR && best_R == 0) { + best_R = R; + best_jetpt = jet_pt[i]; + } else if (R < best_R) { + best_R = R; + best_jetpt = jet_pt[i]; + } + } // jetloop + return best_jetpt; + } + + ///////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////// template - void minvReconstruction(double mult, const TracksType& trk1, const TracksType& trk2, const JetType& jets) + int minvReconstruction(double mult, const TracksType& trk1, const TracksType& trk2, const JetType& jets) { + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; + //==================================================== if (!trackSelection(trk1) || !trackSelection(trk2)) - return; + return -1; - if (!trackPID(trk1) || !trackPID(trk2)) - return; + if (!trackPID(trk1, true) || !trackPID(trk2, false)) + return -1; - if (trk1.index() >= trk2.index()) - return; // We need to run (0,1), (1,0) pairs as well. but same id pairs are not needed. + if (!cfgIsKstar) { + if (trk1.globalIndex() >= trk2.globalIndex()) + return -1; // For Phi, we only need to iterate each pair once + } else { + if (trk1.globalIndex() == trk2.globalIndex()) + return -1; // For Kstar, we need to run (0,1), (1,0) pairs as well. but same id pairs are not needed. + } lDecayDaughter1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massKa); - lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massKa); + if (!cfgIsKstar) + lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massKa); + else + lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massPi); + lResonance = lDecayDaughter1 + lDecayDaughter2; - if (std::abs(lResonance.Rapidity()) > 0.5) - return; + //================================================== + + if (std::abs(lResonance.Eta()) > cfgtrkMaxEta) + return -1; ///////////////////////////////////////////////////////////////////////////// // Fill Global Event Minv if (trk1.sign() * trk2.sign() < 0) { - if (!IsMC) { - JEhistos.fill(HIST("hUSS_1D"), lResonance.M()); - if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) - JEhistos.fill(HIST("hUSS_1D_2_3"), lResonance.M()); - JEhistos.fill(HIST("hUSS"), mult, lResonance.Pt(), lResonance.M()); - } - - if (IsMC) { - JEhistos.fill(HIST("hMCRec_hUSS_1D"), lResonance.M()); - if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) - JEhistos.fill(HIST("hMCRec_hUSS_1D_2_3"), lResonance.M()); - JEhistos.fill(HIST("hMCRec_hUSS"), mult, lResonance.Pt(), lResonance.M()); - } + JEhistos.fill(HIST("hUSS_1D"), lResonance.M()); + if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) + JEhistos.fill(HIST("hUSS_1D_2_3"), lResonance.M()); + JEhistos.fill(HIST("hUSS"), mult, lResonance.Pt(), lResonance.M()); } else if (trk1.sign() * trk2.sign() > 0) { @@ -301,113 +481,122 @@ struct phiInJets { ///////////////////////////////////////////////////////////////////////////// bool jetFlag = false; + int goodjets = 0; + double jetpt = 0; for (auto const& jet : jets) { - double phidiff = TVector2::Phi_mpi_pi(jet.phi() - lResonance.Phi()); double etadiff = jet.eta() - lResonance.Eta(); double R = TMath::Sqrt((etadiff * etadiff) + (phidiff * phidiff)); - if (R < cfgjetR) + if (R < cfgjetR) { jetFlag = true; + jetpt = jet.pt(); + goodjets++; + } } + if (cfgSingleJet) { + if (goodjets > 1) { + jetpt = DistinguishJets(jets, lResonance); + } + } ///////////////////////////////////////////////////////////////////////////// // Fill inside Jet if (jetFlag) { if (trk1.sign() * trk2.sign() < 0) { - if (!IsMC) { - JEhistos.fill(HIST("hUSS_INSIDE_1D"), lResonance.M()); - if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) - JEhistos.fill(HIST("hUSS_INSIDE_1D_2_3"), lResonance.M()); - JEhistos.fill(HIST("hUSS_INSIDE"), mult, lResonance.Pt(), lResonance.M()); - } - - if (IsMC) { - JEhistos.fill(HIST("hMCRec_hUSS_INSIDE_1D"), lResonance.M()); - if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) - JEhistos.fill(HIST("hMCRec_hUSS_INSIDE_1D_2_3"), lResonance.M()); - JEhistos.fill(HIST("hMCRec_hUSS_INSIDE"), mult, lResonance.Pt(), lResonance.M()); - } + JEhistos.fill(HIST("hUSS_INSIDE_1D"), lResonance.M()); + if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) + JEhistos.fill(HIST("hUSS_INSIDE_1D_2_3"), lResonance.M()); + JEhistos.fill(HIST("hUSS_INSIDE"), jetpt, lResonance.Pt(), lResonance.M()); } else if (trk1.sign() * trk2.sign() > 0) { JEhistos.fill(HIST("hLSS_INSIDE_1D"), lResonance.M()); if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) JEhistos.fill(HIST("hLSS_INSIDE_1D_2_3"), lResonance.M()); - JEhistos.fill(HIST("hLSS_INSIDE"), mult, lResonance.Pt(), lResonance.M()); + JEhistos.fill(HIST("hLSS_INSIDE"), jetpt, lResonance.Pt(), lResonance.M()); } } // jetflag ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - // Fill outside Jet - if (!jetFlag) { - if (trk1.sign() * trk2.sign() < 0) { - if (!IsMC) { - JEhistos.fill(HIST("hUSS_OUTSIDE_1D"), lResonance.M()); - if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) - JEhistos.fill(HIST("hUSS_OUTSIDE_1D_2_3"), lResonance.M()); - JEhistos.fill(HIST("hUSS_OUTSIDE"), mult, lResonance.Pt(), lResonance.M()); - } - - if (IsMC) { - JEhistos.fill(HIST("hMCRec_hUSS_OUTSIDE_1D"), lResonance.M()); - if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) - JEhistos.fill(HIST("hMCRec_hUSS_OUTSIDE_1D_2_3"), lResonance.M()); - JEhistos.fill(HIST("hMCRec_hUSS_OUTSIDE"), mult, lResonance.Pt(), lResonance.M()); - } - - } else if (trk1.sign() * trk2.sign() > 0) { - - JEhistos.fill(HIST("hLSS_OUTSIDE_1D"), lResonance.M()); - if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) - JEhistos.fill(HIST("hLSS_OUTSIDE_1D_2_3"), lResonance.M()); - JEhistos.fill(HIST("hLSS_OUTSIDE"), mult, lResonance.Pt(), lResonance.M()); + if (!cfgIsKstar) { + if (lResonance.M() > 1.005 && lResonance.M() < 1.035) { + if (jetFlag) + return 3; + if (goodjets > 0) + return 2; + return 1; + } else { + return -1; } - } //! jetflag - ///////////////////////////////////////////////////////////////////////////// + } else { + if (lResonance.M() > 0.85 && lResonance.M() < 0.95) { + if (jetFlag) + return 3; + if (goodjets > 0) + return 2; + return 1; + } else { + return -1; + } + } } // MinvReconstruction ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// - int nEvents = 0; - void processJetTracks(aod::JCollision const& collision, soa::Filtered> const& chargedjets, soa::Join const& tracks, TrackCandidates const&) + void processJetTracks(aod::JetCollision const& collision, soa::Filtered> const& chargedjets, soa::Join const& tracks, TrackCandidates const&) { if (cDebugLevel > 0) { nEvents++; - if ((nEvents + 1) % 10000 == 0) - std::cout << nEvents << std::endl; + if ((nEvents + 1) % 10000 == 0) { + std::cout << "Processed Data Events: " << nEvents << std::endl; + } } JEhistos.fill(HIST("nEvents"), 0.5); - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) + if (fabs(collision.posZ()) > cfgVtxCut) return; - if (fabs(collision.posZ()) > 10) + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) return; + int nReso = 0; + int nResoWTrig = 0; + int nResoInTrig = 0; for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(tracks, tracks))) { - auto trk1 = track1.track_as>(); - auto trk2 = track2.track_as>(); - minvReconstruction(1.0, trk1, trk2, chargedjets); + auto trk1 = track1.track_as>(); + auto trk2 = track2.track_as>(); + int Reso = minvReconstruction(1.0, trk1, trk2, chargedjets); + if (Reso > 0) + nReso++; + if (Reso > 1) + nResoWTrig++; + if (Reso > 2) + nResoInTrig++; } + // Here we have to fill the number of reso candidates per event + JEhistos.fill(HIST("hNResoPerEvent"), nReso); + JEhistos.fill(HIST("hNResoPerEventWJet"), nResoWTrig); + JEhistos.fill(HIST("hNResoPerEventInJet"), nResoInTrig); + int nJets = 0; for (auto chargedjet : chargedjets) { JEhistos.fill(HIST("FJetaHistogram"), chargedjet.eta()); JEhistos.fill(HIST("FJphiHistogram"), chargedjet.phi()); JEhistos.fill(HIST("FJptHistogram"), chargedjet.pt()); - JEhistos.fill(HIST("FJnchHistogram"), chargedjet.tracks().size()); nJets++; } + JEhistos.fill(HIST("nJetsPerEvent"), nJets); JEhistos.fill(HIST("nEvents"), 1.5); + // return; - for (auto const& track : tracks) { - auto originalTrack = track.track_as>(); + for (auto& trackC : tracks) { + auto originalTrack = trackC.track_as>(); JEhistos.fill(HIST("hDCArToPv"), originalTrack.dcaXY()); JEhistos.fill(HIST("hDCAzToPv"), originalTrack.dcaZ()); JEhistos.fill(HIST("rawpT"), originalTrack.pt()); - JEhistos.fill(HIST("rawDpT"), track.pt(), track.pt() - originalTrack.pt()); + JEhistos.fill(HIST("rawDpT"), trackC.pt(), trackC.pt() - originalTrack.pt()); JEhistos.fill(HIST("hIsPrim"), originalTrack.isPrimaryTrack()); JEhistos.fill(HIST("hIsGood"), originalTrack.isGlobalTrackWoDCA()); JEhistos.fill(HIST("hIsPrimCont"), originalTrack.isPVContributor()); @@ -420,8 +609,8 @@ struct phiInJets { if (!trackSelection(originalTrack)) continue; - JEhistos.fill(HIST("etaHistogram"), track.eta()); - JEhistos.fill(HIST("phiHistogram"), track.phi()); + JEhistos.fill(HIST("etaHistogram"), trackC.eta()); + JEhistos.fill(HIST("phiHistogram"), trackC.phi()); } // JTrack Loop }; // Process Switch @@ -433,32 +622,76 @@ struct phiInJets { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - using myCompleteTracks = soa::Join; - using myCompleteJetTracks = soa::Join; + using myCompleteTracks = soa::Join; + using myCompleteJetTracks = soa::Join; int nJEEvents = 0; - void processRec(o2::aod::JCollision const& collision, myCompleteJetTracks const& tracks, soa::Filtered const& mcdjets, aod::McParticles const&, myCompleteTracks const&) + int nprocessRecEvents = 0; + void processRec(o2::aod::JetCollision const& collision, myCompleteJetTracks const& tracks, soa::Filtered const& mcdjets, aod::McParticles const&, myCompleteTracks const& /*originalTracks*/) { if (cDebugLevel > 0) { - nJEEvents++; - if ((nJEEvents + 1) % 10000 == 0) - std::cout << "JEvents: " << nJEEvents << std::endl; + nprocessRecEvents++; + if ((nprocessRecEvents + 1) % 10000 == 0) { + double histmem = JEhistos.getSize(); + std::cout << histmem << std::endl; + std::cout << "processRec: " << nprocessRecEvents << std::endl; + } } - + //================= + // # of Events + //================= JEhistos.fill(HIST("nEvents_MCRec"), 0.5); - if (fabs(collision.posZ()) > 10) + if (fabs(collision.posZ()) > cfgVtxCut) + return; + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) return; - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) + + bool INELgt0 = false; + for (const auto& track : tracks) { + if (fabs(track.eta()) < cfgtrkMaxEta) { + INELgt0 = true; + break; + } + } + if (!INELgt0) return; + JEhistos.fill(HIST("nEvents_MCRec"), 1.5); - // Track Eff + std::vector mcd_pt{}; + std::vector mcd_phi{}; + std::vector mcd_eta{}; + + bool hasJets = kFALSE; + for (auto& mcdjet : mcdjets) { + hasJets = kTRUE; + mcd_pt.push_back(mcdjet.pt()); + mcd_eta.push_back(mcdjet.eta()); + mcd_phi.push_back(mcdjet.phi()); + JEhistos.fill(HIST("h_jet_pt"), mcdjet.pt()); + JEhistos.fill(HIST("h_jet_eta"), mcdjet.eta()); + JEhistos.fill(HIST("h_jet_phi"), mcdjet.phi()); + } + if (hasJets) + JEhistos.fill(HIST("nEvents_MCRec"), 2.5); + + double PhiCand = 0; + double RealPhiCand = 0; + double RealPhiCandWithJet = 0; + double RealPhiCandInJet = 0; + //============ + // Track Effl for (const auto& track : tracks) { auto originalTrack = track.track_as(); if (!trackSelection(originalTrack)) continue; + if (cfgSimPID) + if (!trackPID(originalTrack, true)) + continue; + if (track.has_mcParticle()) { auto mcParticle = track.mcParticle(); - if (mcParticle.isPhysicalPrimary() && fabs(mcParticle.y()) <= 0.5) { // do this in the context of the track ! (context matters!!!) + + if (mcParticle.isPhysicalPrimary() && fabs(mcParticle.eta()) <= cfgtrkMaxEta) { if (abs(mcParticle.pdgCode()) == 211) JEhistos.fill(HIST("ptJEHistogramPion"), mcParticle.pt()); if (abs(mcParticle.pdgCode()) == 321) @@ -467,96 +700,320 @@ struct phiInJets { JEhistos.fill(HIST("ptJEHistogramProton"), mcParticle.pt()); } } - } - - // Jet Eff - for (auto& mcdjet : mcdjets) { - registry.fill(HIST("h_jet_pt"), mcdjet.pt()); - registry.fill(HIST("h_jet_eta"), mcdjet.eta()); - registry.fill(HIST("h_jet_phi"), mcdjet.phi()); - } - // Phi Eff - - for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(tracks, tracks))) { - auto trk1 = track1.track_as(); - auto trk2 = track2.track_as(); - if (trk1.index() >= trk2.index()) - continue; - if (fabs(trk1.eta()) > 0.8 || fabs(trk2.eta()) > 0.8) - continue; + for (const auto& track2 : tracks) { + auto originalTrack2 = track2.track_as(); + if (!trackSelection(originalTrack2)) + continue; + if (cfgSimPID) + if (!trackPID(originalTrack2, false)) + continue; + if (!cfgIsKstar) { + if (originalTrack.globalIndex() >= originalTrack2.globalIndex()) + continue; + } else { + if (originalTrack.globalIndex() == originalTrack2.globalIndex()) + continue; + } + if (fabs(originalTrack.eta()) > cfgtrkMaxEta || fabs(originalTrack2.eta()) > cfgtrkMaxEta) + continue; - if (!trackSelection(trk1)) - continue; - if (!trackSelection(trk2)) - continue; - if ((trk1.sign() * trk2.sign()) > 0) - continue; // Not K+K- - if (!track1.has_mcParticle()) - continue; - if (!track2.has_mcParticle()) - continue; + double dPhi = TVector2::Phi_mpi_pi(originalTrack.phi() - originalTrack2.phi()); + double dEta = originalTrack.eta() - originalTrack2.eta(); + JEhistos.fill(HIST("hMCRec_dPhi_distribution"), dPhi); + JEhistos.fill(HIST("hMCRec_dEta_distribution"), dEta); + + double dR = TMath::Sqrt(dPhi * dPhi + dEta * dEta); + double dR_rot = 0; + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance, lRotationalTrack, lRotationalResonance; + lDecayDaughter1.SetXYZM(originalTrack.px(), originalTrack.py(), originalTrack.pz(), massKa); + //----------------------------------------------------------------------- + + TRandom* trand = new TRandom(); + double shift = trand->Uniform(TMath::Pi() - TMath::Pi() / 10.0, TMath::Pi() + TMath::Pi() / 10.0); + // double shift = TMath::Pi(); + + if (!cfgIsKstar) { + lDecayDaughter2.SetXYZM(originalTrack2.px(), originalTrack2.py(), originalTrack2.pz(), massKa); + } else { + lDecayDaughter2.SetXYZM(originalTrack2.px(), originalTrack2.py(), originalTrack2.pz(), massPi); + + // double pTog = TMath::Sqrt(originalTrack2.px() * originalTrack2.px() + originalTrack2.py() * originalTrack2.py()); + // double Pxrot = pTog*TMath::Cos(originalTrack2.phi() + shift); + // double Pyrot = pTog*TMath::Sin(originalTrack2.phi() + shift); + + // if(gDebug){ + // double Ptrot = TMath::Sqrt(Pxrot*Pxrot + Pyrot*Pyrot); + // if(TMath::Abs(Ptrot-pTog)>0.1) { + // std::cout<<"We are jottettta"< cfgtrkMaxEta) + continue; - auto part1 = track1.mcParticle(); - auto part2 = track2.mcParticle(); - if (fabs(part1.pdgCode()) != 321) - continue; // Not Kaon - if (fabs(part2.pdgCode()) != 321) - continue; // Not Kaon - if (!part1.has_mothers()) - continue; // Not decaying Kaon - if (!part2.has_mothers()) - continue; // Not decaying Kaon - - std::vector mothers1{}; - std::vector mothers1PDG{}; - for (auto& part1_mom : part1.mothers_as()) { - mothers1.push_back(part1_mom.globalIndex()); - mothers1PDG.push_back(part1_mom.pdgCode()); - } - if (mothers1.size() > 1) - continue; // Strange multi-mother decay - - std::vector mothers2{}; - std::vector mothers2PDG{}; - for (auto& part2_mom : part2.mothers_as()) { - mothers2.push_back(part2_mom.globalIndex()); - mothers2PDG.push_back(part2_mom.pdgCode()); - } + if (lResonance.M() > 1.005 && lResonance.M() < 1.035) + PhiCand++; + + //================== + // 1.MB REC Closure + //================== + if (cfgMCRecMBHists) { + if (originalTrack.sign() * originalTrack2.sign() < 0) { + JEhistos.fill(HIST("hMCRec_hUSS"), 1.0, lResonance.Pt(), lResonance.M()); + // normal R + JEhistos.fill(HIST("hMCRec_R_distribution"), dR); + + // switch because of memory + if (cfgMCRecRotationalHists && cfgIsKstar) { + JEhistos.fill(HIST("hMCRec_hUSS_Rotational"), 1.0, lRotationalResonance.Pt(), lResonance.M()); + // Rotational R + JEhistos.fill(HIST("hMCRec_R_Rotation_distribution"), dR_rot); + } + } else if (originalTrack.sign() * originalTrack2.sign() > 0) { + JEhistos.fill(HIST("hMCRec_hLSS"), 1.0, lResonance.Pt(), lResonance.M()); + } + } + //============================================ + // 2.Check if particle is inside a jet or not + //============================================ + bool jetFlag = false; + int goodjets = 0; + double jetpt = 0; + + for (std::size_t i = 0; i < mcd_pt.size(); i++) { + if (i == 0) { + if (lResonance.M() > 1.005 && lResonance.M() < 1.035) { + RealPhiCandWithJet++; + } + } + double phidiff = TVector2::Phi_mpi_pi(mcd_phi[i] - lResonance.Phi()); + double etadiff = mcd_eta[i] - lResonance.Eta(); + double R = TMath::Sqrt((etadiff * etadiff) + (phidiff * phidiff)); - if (mothers2.size() > 1) - continue; // Strange multi-mother decay - if (mothers1PDG[0] != 333) - continue; // mother not phi - if (mothers2PDG[0] != 333) - continue; // mother not phi - if (mothers1[0] != mothers2[0]) - continue; // Kaons not from the same phi - TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; - lDecayDaughter1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massKa); - lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massKa); - lResonance = lDecayDaughter1 + lDecayDaughter2; - if (lResonance.Rapidity() > 0.5) - continue; - JEhistos.fill(HIST("ptJEHistogramPhi"), lResonance.Pt()); - JEhistos.fill(HIST("minvJEHistogramPhi"), lResonance.M()); + double phidiff_K1 = TVector2::Phi_mpi_pi(mcd_phi[i] - lDecayDaughter1.Phi()); + double etadiff_K1 = mcd_eta[i] - lDecayDaughter1.Eta(); + double R_K1 = TMath::Sqrt((etadiff_K1 * etadiff_K1) + (phidiff_K1 * phidiff_K1)); + + double phidiff_K2 = TVector2::Phi_mpi_pi(mcd_phi[i] - lDecayDaughter2.Phi()); + double etadiff_K2 = mcd_eta[i] - lDecayDaughter2.Eta(); + double R_K2 = TMath::Sqrt((etadiff_K2 * etadiff_K2) + (phidiff_K2 * phidiff_K2)); + if (R < cfgjetR) { + JEhistos.fill(HIST("hMCRec_nonmatch_hUSS_Kangle_v_pt"), R_K1, lResonance.Pt()); + JEhistos.fill(HIST("hMCRec_nonmatch_hUSS_Kangle_v_pt"), R_K2, lResonance.Pt()); + } + if (R < cfgjetR) { + jetFlag = true; + jetpt = mcd_pt[i]; + goodjets++; + } + } // R check for jets + + //====================== + // 3.INSIDE REC Closure + //====================== + if (cfgMCRecInsideHists) { + if (jetFlag) { + if (originalTrack.sign() * originalTrack2.sign() < 0) { + JEhistos.fill(HIST("hMCRec_hUSS_INSIDE"), 1.0, lResonance.Pt(), lResonance.M()); + } else if (originalTrack.sign() * originalTrack2.sign() > 0) { + JEhistos.fill(HIST("hMCRec_hLSS_INSIDE"), 1.0, lResonance.Pt(), lResonance.M()); + } + } + } + // check PID + if (track.has_mcParticle() && track2.has_mcParticle()) { + auto part1 = track.mcParticle(); + auto part2 = track2.mcParticle(); + if (fabs(part1.pdgCode()) != 321) + continue; // Not Kaon + if (!cfgIsKstar) { + if (fabs(part2.pdgCode()) != 321) + continue; // Not Kaon + } else { + if (fabs(part2.pdgCode()) != 211) + continue; // Not Kaon + } + + if (!part1.has_mothers()) + continue; // Not decaying Kaon + if (!part2.has_mothers()) + continue; // Not decaying Kaon + + std::vector mothers1{}; + std::vector mothers1PDG{}; + for (auto& part1_mom : part1.mothers_as()) { + mothers1.push_back(part1_mom.globalIndex()); + mothers1PDG.push_back(part1_mom.pdgCode()); + } + + std::vector mothers2{}; + std::vector mothers2PDG{}; + for (auto& part2_mom : part2.mothers_as()) { + mothers2.push_back(part2_mom.globalIndex()); + mothers2PDG.push_back(part2_mom.pdgCode()); + } + + if (!cfgIsKstar) { + if (mothers1PDG[0] != 333) + continue; // mother not phi + if (mothers2PDG[0] != 333) + continue; // mother not phi + } else { + if (mothers1PDG[0] != 313) + continue; // mother not phi + if (mothers2PDG[0] != 313) + continue; // mother not phi + } + if (mothers1[0] != mothers2[0]) + continue; // Kaons not from the same phi + + double phidiff_Kaons = TVector2::Phi_mpi_pi(lDecayDaughter2.Phi() - lDecayDaughter1.Phi()); + double etadiff_Kaons = lDecayDaughter2.Eta() - lDecayDaughter1.Eta(); + double R_Kaons = TMath::Sqrt((etadiff_Kaons * etadiff_Kaons) + (phidiff_Kaons * phidiff_Kaons)); + JEhistos.fill(HIST("hMCRec_nonmatch_hUSS_KtoKangle_v_pt"), R_Kaons, lResonance.Pt()); + JEhistos.fill(HIST("ptJEHistogramPhi"), lResonance.Pt()); + + //===================== + // 4.MB True Closure + //===================== + if (cfgMCRecMBHists) { + if (originalTrack.sign() * originalTrack2.sign() < 0) { + JEhistos.fill(HIST("hMCRecTrue_hUSS"), 1.0, lResonance.Pt(), lResonance.M()); + } else if (originalTrack.sign() * originalTrack2.sign() > 0) { + JEhistos.fill(HIST("hMCRecTrue_hLSS"), 1.0, lResonance.Pt(), lResonance.M()); + } + } + //=========================== + // 5.INSIDE REC True Closure + //=========================== + if (cfgMCRecInsideHists) { + if (jetFlag) { + if (originalTrack.sign() * originalTrack2.sign() < 0) { + JEhistos.fill(HIST("hMCRecTrue_hUSS_INSIDE"), 1.0, lResonance.Pt(), lResonance.M()); + } else if (originalTrack.sign() * originalTrack2.sign() > 0) { + JEhistos.fill(HIST("hMCRecTrue_hLSS_INSIDE"), 1.0, lResonance.Pt(), lResonance.M()); + } + } + } + if (lResonance.M() > 1.005 && lResonance.M() < 1.035) + RealPhiCand++; + + // Now we do jets + if (cfgMCRecInsideHists) { + if (cfgSingleJet) + if (goodjets > 1) + jetpt = DistinguishJetsMC(mcd_pt, mcd_phi, mcd_eta, lResonance); + + if (jetFlag) { + if (lResonance.M() > 1.005 && lResonance.M() < 1.035) + RealPhiCandInJet++; + JEhistos.fill(HIST("hMCRec_nonmatch_hUSS_INSIDE_pt_v_eta"), lResonance.Pt(), lResonance.Eta()); + JEhistos.fill(HIST("hMCRec_nonmatch_hUSS_INSIDE_1D"), lResonance.M()); + if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) + JEhistos.fill(HIST("hMCRec_nonmatch_hUSS_INSIDE_1D_2_3"), lResonance.M()); + JEhistos.fill(HIST("hMCRec_nonmatch_hUSS_INSIDE"), jetpt, lResonance.Pt(), lResonance.M()); + } + + if (hasJets) { + JEhistos.fill(HIST("ptJEHistogramPhi_JetTrigger"), lResonance.Pt()); + auto triggerjet = std::min_element(mcd_pt.begin(), mcd_pt.end()); + double triggerjet_pt = *triggerjet; + JEhistos.fill(HIST("JetVsPhi_REC"), triggerjet_pt, lResonance.Pt()); + } + JEhistos.fill(HIST("minvJEHistogramPhi"), lResonance.M()); + } + } // mcpart check + } // tracks2 + } // tracks1 + JEhistos.fill(HIST("hNRealPhiVPhiCand"), PhiCand, RealPhiCand); + JEhistos.fill(HIST("hNRealPhiWithJetVPhiCand"), PhiCand, RealPhiCandWithJet); + JEhistos.fill(HIST("hNRealPhiInJetVPhiCand"), PhiCand, RealPhiCandInJet); - } // end of phi check + // Jet Eff } PROCESS_SWITCH(phiInJets, processRec, "pikp detector level MC JE", true); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void processSim(o2::aod::JMcCollision const& collision, aod::JMcParticles const& mcParticles, soa::Filtered const& mcpjets) + int nprocessSimEvents = 0; + // Preslice slice = o2::aod::JCollision::collisionId; + void processSim(o2::aod::JetMcCollision const& collision, soa::SmallGroups> const& recocolls, aod::JetParticles const& mcParticles, soa::Filtered const& mcpjets) { + if (cDebugLevel > 0) { + nprocessSimEvents++; + if ((nprocessSimEvents + 1) % 10000 == 0) { + double histmem = JEhistos.getSize(); + std::cout << histmem << std::endl; + std::cout << "processSim: " << nprocessSimEvents << std::endl; + } + } + JEhistos.fill(HIST("nEvents_MCGen"), 0.5); - if (fabs(collision.posZ()) > 10) + if (recocolls.size() <= 0) // not reconstructed return; + + for (auto& recocoll : recocolls) { // poorly reconstructed + if (!jetderiveddatautilities::selectCollision(recocoll, eventSelectionBits)) + return; + } + + if (fabs(collision.posZ()) > cfgVtxCut) // bad vertex + return; + bool INELgt0 = false; + for (const auto& mcParticle : mcParticles) { + if (fabs(mcParticle.eta()) < cfgtrkMaxEta) { + INELgt0 = true; + break; + } + } + + if (!INELgt0) // not INEL + return; + std::vector mcp_pt{}; + std::vector mcp_phi{}; + std::vector mcp_eta{}; JEhistos.fill(HIST("nEvents_MCGen"), 1.5); + bool hasJets = kFALSE; + // Check jets + for (auto& mcpjet : mcpjets) { + hasJets = kTRUE; + mcp_pt.push_back(mcpjet.pt()); + mcp_eta.push_back(mcpjet.eta()); + mcp_phi.push_back(mcpjet.phi()); + + JEhistos.fill(HIST("h_part_jet_pt"), mcpjet.pt()); + JEhistos.fill(HIST("h_part_jet_eta"), mcpjet.eta()); + JEhistos.fill(HIST("h_part_jet_phi"), mcpjet.phi()); + } + if (hasJets) + JEhistos.fill(HIST("nEvents_MCGen"), 2.5); + // Check pikp and phi for (const auto& mcParticle : mcParticles) { - if (mcParticle.isPhysicalPrimary() && fabs(mcParticle.y()) <= 0.5) { // watch out for context!!! + if (mcParticle.isPhysicalPrimary() && fabs(mcParticle.eta()) <= cfgtrkMaxEta) { // watch out for context!!! if (abs(mcParticle.pdgCode()) == 211) JEhistos.fill(HIST("ptGeneratedPion"), mcParticle.pt()); if (abs(mcParticle.pdgCode()) == 321) @@ -564,22 +1021,90 @@ struct phiInJets { if (abs(mcParticle.pdgCode()) == 2212) JEhistos.fill(HIST("ptGeneratedProton"), mcParticle.pt()); } - if (fabs(mcParticle.y()) <= 0.5) { // watch out for context!!! + if (fabs(mcParticle.eta()) <= cfgtrkMaxEta) { // watch out for context!!! TLorentzVector lResonance; lResonance.SetPxPyPzE(mcParticle.px(), mcParticle.py(), mcParticle.pz(), mcParticle.e()); - if (abs(mcParticle.pdgCode()) == 333) + + int GenPID = 0; + if (!cfgIsKstar) + GenPID = 333; + else + GenPID = 313; + + if (abs(mcParticle.pdgCode()) == GenPID) { + JEhistos.fill(HIST("ptGeneratedPhi_ALLBR"), mcParticle.pt()); + + bool skip = false; + + // First we check for Forced BR + // if we check for Phi + if (!cfgIsKstar) { + if (mcParticle.has_daughters()) + for (auto& dgth : mcParticle.daughters_as()) + if (fabs(dgth.pdgCode()) != 321) + skip = true; + } else { + if (mcParticle.has_daughters()) + for (auto& dgth : mcParticle.daughters_as()) + if (fabs(dgth.pdgCode()) != 321 || fabs(dgth.pdgCode()) != 211) + skip = true; + } + + if (skip && cfgBR) + continue; JEhistos.fill(HIST("ptGeneratedPhi"), mcParticle.pt()); - if (abs(mcParticle.pdgCode()) == 333) JEhistos.fill(HIST("mGeneratedPhi"), lResonance.M()); - } - } - // Check jets - for (auto& mcpjet : mcpjets) { - registry.fill(HIST("h_part_jet_pt"), mcpjet.pt()); - registry.fill(HIST("h_part_jet_eta"), mcpjet.eta()); - registry.fill(HIST("h_part_jet_phi"), mcpjet.phi()); - } - } + + ////////////////////////////Implementation of phi finding + + int goodjets = 0; + double jetpt = 0; + TLorentzVector lResonance; + lResonance.SetPxPyPzE(mcParticle.px(), mcParticle.py(), mcParticle.pz(), mcParticle.e()); + bool jetFlag = false; + for (std::vector::size_type i = 0; i < mcp_pt.size(); i++) { + double phidiff = TVector2::Phi_mpi_pi(mcp_phi[i] - lResonance.Phi()); + double etadiff = mcp_eta[i] - lResonance.Eta(); + double R = TMath::Sqrt((etadiff * etadiff) + (phidiff * phidiff)); + if (mcParticle.has_daughters()) { + for (auto& dgth : mcParticle.daughters_as()) { + double phidiff_K = TVector2::Phi_mpi_pi(mcp_phi[i] - dgth.phi()); + double etadiff_K = mcp_eta[i] - dgth.eta(); + double R_K = TMath::Sqrt((etadiff_K * etadiff_K) + (phidiff_K * phidiff_K)); + if (R < cfgjetR) + JEhistos.fill(HIST("hMCTrue_nonmatch_hUSS_Kangle_v_pt"), R_K, lResonance.Pt()); + } + } + if (R < cfgjetR) { + jetFlag = true; + jetpt = mcp_pt[i]; + goodjets++; + } + } + if (cfgSingleJet) + if (goodjets > 1) + jetpt = DistinguishJetsMC(mcp_pt, mcp_phi, mcp_eta, lResonance); + + if (jetFlag) { + JEhistos.fill(HIST("hMCTrue_nonmatch_hUSS_INSIDE_pt_v_eta"), lResonance.Pt(), lResonance.Eta()); + JEhistos.fill(HIST("hMCTrue_nonmatch_hUSS_INSIDE_1D"), lResonance.M()); + if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) + JEhistos.fill(HIST("hMCTrue_nonmatch_hUSS_INSIDE_1D_2_3"), lResonance.M()); + JEhistos.fill(HIST("hMCTrue_nonmatch_hUSS_INSIDE"), jetpt, lResonance.Pt(), lResonance.M()); + } + + ////////////////////////////Phi found + if (hasJets) { + JEhistos.fill(HIST("ptGeneratedPhi_JetTrigger"), mcParticle.pt()); + auto triggerjet = std::min_element(mcp_pt.begin(), mcp_pt.end()); + double triggerjet_pt = *triggerjet; + JEhistos.fill(HIST("JetVsPhi_GEN"), triggerjet_pt, mcParticle.pt()); + } // check for jets + + } // check for phi + } // check for rapidity + } // loop over particles + } // process switch PROCESS_SWITCH(phiInJets, processSim, "pikp particle level MC", true); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -588,15 +1113,49 @@ struct phiInJets { using JetMCPTable = soa::Filtered>; using JetMCDTable = soa::Filtered>; - // void processMatchedGen(o2::aod::JMcCollision const& collision, aod::JMcParticles const& mcParticles, soa::Filtered const& mcpjets) - void processMatchedGen(aod::JMcCollision const&, - JetMCDTable const&, + int nprocessSimJEEvents = 0; + void processMatchedGen(aod::JetMcCollision const& collision, + soa::SmallGroups> const& recocolls, + JetMCDTable const& /*mcdjets*/, JetMCPTable const& mcpjets, - aod::JMcParticles const& mcParticles) + myCompleteJetTracks const& tracks, + myCompleteTracks const&, + aod::JetParticles const& mcParticles, + aod::McParticles const&) { - // if(fabs(collision.posZ())>10) - // return; + if (cDebugLevel > 0) { + nprocessSimJEEvents++; + if ((nprocessSimJEEvents + 1) % 10000 == 0) { + double histmem = JEhistos.getSize(); + std::cout << histmem << std::endl; + std::cout << "processMatchedGen Events: " << nprocessSimJEEvents << std::endl; + } + } + + JEhistos.fill(HIST("nEvents_MCGen_MATCHED"), 0.5); + + if (fabs(collision.posZ()) > cfgVtxCut) + return; + + if (recocolls.size() <= 0) // not reconstructed + return; + for (auto& recocoll : recocolls) { // poorly reconstructed + if (!jetderiveddatautilities::selectCollision(recocoll, eventSelectionBits)) + return; + } + + bool INELgt0 = false; + for (const auto& mcParticle : mcParticles) { + if (TMath::Abs(mcParticle.eta()) < cfgtrkMaxEta) { + INELgt0 = true; + break; + } + } + if (!INELgt0) + return; + + JEhistos.fill(HIST("nEvents_MCGen_MATCHED"), 1.5); std::vector mcd_pt{}; std::vector mcd_phi{}; @@ -605,6 +1164,8 @@ struct phiInJets { std::vector mcp_phi{}; std::vector mcp_eta{}; + bool hasJets = kFALSE; + for (auto& mcpjet : mcpjets) { if (!mcpjet.has_matchedJetGeo()) continue; @@ -612,10 +1173,10 @@ struct phiInJets { for (auto& mcdjet : mcpjet.template matchedJetGeo_as()) { if (!mcdjet.has_matchedJetGeo()) continue; - - registry.fill(HIST("h_matched_GEN_jet_pt"), mcpjet.pt(), mcdjet.pt() - mcpjet.pt()); - registry.fill(HIST("h_matched_GEN_jet_phi"), mcpjet.phi(), mcdjet.phi() - mcpjet.phi()); - registry.fill(HIST("h_matched_GEN_jet_eta"), mcpjet.eta(), mcdjet.eta() - mcpjet.eta()); + hasJets = kTRUE; + JEhistos.fill(HIST("h_matched_GEN_jet_pt"), mcpjet.pt(), mcdjet.pt() - mcpjet.pt()); + JEhistos.fill(HIST("h_matched_GEN_jet_phi"), mcpjet.phi(), mcdjet.phi() - mcpjet.phi()); + JEhistos.fill(HIST("h_matched_GEN_jet_eta"), mcpjet.eta(), mcdjet.eta() - mcpjet.eta()); mcd_pt.push_back(mcdjet.pt()); mcd_eta.push_back(mcdjet.eta()); @@ -624,64 +1185,191 @@ struct phiInJets { mcp_eta.push_back(mcpjet.eta()); mcp_phi.push_back(mcpjet.phi()); } // mcpjets - } // mcdjets + } // mcdjets + + if (hasJets) + JEhistos.fill(HIST("nEvents_MCGen_MATCHED"), 2.5); // First we do GEN part for (const auto& mcParticle : mcParticles) { - if (fabs(mcParticle.y()) > 0.5) - continue; - if (fabs(mcParticle.eta() > 0.8)) + if (fabs(mcParticle.eta()) > cfgtrkMaxEta) continue; - if (abs(mcParticle.pdgCode()) == 333) { + int GenPID = 0; + + if (!cfgIsKstar) + GenPID = 333; + else + GenPID = 313; + + if (fabs(mcParticle.pdgCode()) == GenPID) { + bool skip = false; + double phi_dgth_px[2] = {0}; + double phi_dgth_py[2] = {0}; + double phi_dgth_pz[2] = {0}; + double TEMP_phi_dgth_px[2] = {0}; + double TEMP_phi_dgth_py[2] = {0}; + double TEMP_phi_dgth_pz[2] = {0}; + + bool good_daughter[2] = {false}; + int dgth_index = 0; + // First we check for Forced BR + // if we check for Phi + if (!cfgIsKstar) { + if (mcParticle.has_daughters()) { + for (auto& dgth : mcParticle.daughters_as()) { + if (fabs(dgth.pdgCode()) != 321) { + skip = true; + break; + } + for (const auto& track : tracks) { + auto trk = track.track_as(); + if (!trackSelection(trk)) + continue; + if (fabs(trk.eta()) > cfgtrkMaxEta) + continue; + if (cfgSimPID) { + if (!trackPID(trk, true)) + continue; + } + if (!trk.has_mcParticle()) + continue; + auto part = trk.mcParticle(); + if (part.globalIndex() == dgth.globalIndex()) { + TEMP_phi_dgth_px[dgth_index] = track.px(); + TEMP_phi_dgth_py[dgth_index] = track.py(); + TEMP_phi_dgth_pz[dgth_index] = track.pz(); + good_daughter[dgth_index] = true; + dgth_index++; + if (dgth_index == 2) { + phi_dgth_px[0] = TEMP_phi_dgth_px[0]; + phi_dgth_py[0] = TEMP_phi_dgth_py[0]; + phi_dgth_pz[0] = TEMP_phi_dgth_pz[0]; + phi_dgth_px[1] = TEMP_phi_dgth_px[1]; + phi_dgth_py[1] = TEMP_phi_dgth_py[1]; + phi_dgth_pz[1] = TEMP_phi_dgth_pz[1]; + break; + } + } // index check + } // track loop + } // mc daughter loop + } // check if particle has daughters + } else { // check for kstar + if (mcParticle.has_daughters()) + for (auto& dgth : mcParticle.daughters_as()) + if (fabs(dgth.pdgCode()) != 321 || fabs(dgth.pdgCode()) != 211) + skip = true; + } + + if (skip && cfgBR) + continue; + + int goodjets = 0; + double jetpt_mcd = 0; + double jetpt_mcp = 0; TLorentzVector lResonance; + TLorentzVector lResonance_REC; + TLorentzVector lDecayDaughter1_REC; + TLorentzVector lDecayDaughter2_REC; lResonance.SetPxPyPzE(mcParticle.px(), mcParticle.py(), mcParticle.pz(), mcParticle.e()); + lDecayDaughter1_REC.SetXYZM(phi_dgth_px[0], phi_dgth_py[0], phi_dgth_pz[0], massKa); + lDecayDaughter2_REC.SetXYZM(phi_dgth_px[1], phi_dgth_py[1], phi_dgth_pz[1], massKa); + lResonance_REC = lDecayDaughter1_REC + lDecayDaughter2_REC; + bool jetFlag = false; - for (int i = 0; i < mcp_pt.size(); i++) { - double phidiff = TVector2::Phi_mpi_pi(mcp_pt[i] - lResonance.Phi()); + for (std::vector::size_type i = 0; i < mcp_pt.size(); i++) { + double phidiff = TVector2::Phi_mpi_pi(mcp_phi[i] - lResonance.Phi()); double etadiff = mcp_eta[i] - lResonance.Eta(); double R = TMath::Sqrt((etadiff * etadiff) + (phidiff * phidiff)); - if (R < cfgjetR) + if (R < cfgjetR) { jetFlag = true; + jetpt_mcp = mcp_pt[i]; + jetpt_mcd = mcd_pt[i]; + goodjets++; + } + } + if (cfgSingleJet) { + if (goodjets > 1) { + jetpt_mcp = DistinguishJetsMC(mcp_pt, mcp_phi, mcp_eta, lResonance); + jetpt_mcd = DistinguishJetsMC(mcd_pt, mcd_phi, mcd_eta, lResonance_REC); + } } if (jetFlag) { + if (cDebugLevel > 0) { + std::cout << "******************************************" << std::endl; + std::cout << "GEN TO REC LEVEL: " << std::endl; + std::cout << "Rec. Phi Pt: " << lResonance_REC.Pt() << std::endl; + std::cout << "Rec. Phi Eta: " << lResonance_REC.Eta() << std::endl; + std::cout << "Rec. Jet Pt: " << jetpt_mcd << std::endl; + std::cout << "Gen. Phi Pt: " << lResonance.Pt() << std::endl; + std::cout << "Gen. Phi Eta: " << lResonance.Eta() << std::endl; + std::cout << "Gen. Jet Pt: " << jetpt_mcp << std::endl; + std::cout << "******************************************" << std::endl; + } + + JEhistos.fill(HIST("RespGen_Matrix_MATCHED"), lResonance_REC.Pt(), jetpt_mcd, lResonance.Pt(), jetpt_mcp); + unsigned int seed = static_cast(std::chrono::system_clock::now().time_since_epoch().count()); + int dice = rand_r(&seed) % 2; + if (dice > 0) + JEhistos.fill(HIST("RespGen_Matrix_MATCHED_rand0"), lResonance_REC.Pt(), jetpt_mcd, lResonance.Pt(), jetpt_mcp); + else + JEhistos.fill(HIST("RespGen_Matrix_MATCHED_rand1"), lResonance_REC.Pt(), jetpt_mcd, lResonance.Pt(), jetpt_mcp); + + JEhistos.fill(HIST("2DGenToRec"), lResonance.Pt(), jetpt_mcp); + // //check constrained eff + if (good_daughter[0] && good_daughter[1] && lResonance_REC.Pt() > 0 && lResonance_REC.Pt() < 20.0 && jetpt_mcd > 8 && jetpt_mcd < 200) + JEhistos.fill(HIST("2DGenToRec_constrained"), lResonance.Pt(), jetpt_mcp); + JEhistos.fill(HIST("hMCTrue_hUSS_INSIDE_1D"), lResonance.M()); if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) JEhistos.fill(HIST("hMCTrue_hUSS_INSIDE_1D_2_3"), lResonance.M()); - JEhistos.fill(HIST("hMCTrue_hUSS_INSIDE"), 1.0, lResonance.Pt(), lResonance.M()); - - } // jetflag - if (!jetFlag) { - JEhistos.fill(HIST("hMCTrue_hUSS_OUTSIDE_1D"), lResonance.M()); - - if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) - JEhistos.fill(HIST("hMCTrue_hUSS_OUTSIDE_1D_2_3"), lResonance.M()); - - JEhistos.fill(HIST("hMCTrue_hUSS_OUTSIDE"), 1.0, lResonance.Pt(), lResonance.M()); - - } //! jetflag - } // chech for phi - } // MC Particles - } // main fcn + JEhistos.fill(HIST("hMCTrue_hUSS_INSIDE"), jetpt_mcp, lResonance.Pt(), lResonance.M()); + } + } // chech for phi + } // MC Particles + } // main fcn PROCESS_SWITCH(phiInJets, processMatchedGen, "phi matched level MC", true); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - + int nprocessRecJEEvents = 0; // void processMatchedRec(o2::aod::JCollision const& collision, myCompleteJetTracks const& tracks, soa::Filtered const& mcdjets, aod::McParticles const&, myCompleteTracks const& originalTracks) - void processMatchedRec(aod::JCollision const& collision, + void processMatchedRec(aod::JetCollision const& collision, JetMCDTable const& mcdjets, JetMCPTable const&, myCompleteJetTracks const& tracks, myCompleteTracks const&, aod::McParticles const&) { - if (fabs(collision.posZ()) > 10) + + if (cDebugLevel > 0) { + nprocessRecJEEvents++; + if ((nprocessRecJEEvents + 1) % 10000 == 0) { + double histmem = JEhistos.getSize(); + std::cout << histmem << std::endl; + std::cout << "processMatched Rec Events: " << nprocessRecJEEvents << std::endl; + } + } + JEhistos.fill(HIST("nEvents_MCRec_MATCHED"), 0.5); + + if (fabs(collision.posZ()) > cfgVtxCut) return; - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) return; + bool INELgt0 = false; + for (const auto& track : tracks) { + if (fabs(track.eta()) < cfgtrkMaxEta) { + INELgt0 = true; + break; + } + } + if (!INELgt0) + return; + + JEhistos.fill(HIST("nEvents_MCRec_MATCHED"), 1.5); + std::vector mcd_pt{}; std::vector mcd_phi{}; std::vector mcd_eta{}; @@ -689,19 +1377,17 @@ struct phiInJets { std::vector mcp_phi{}; std::vector mcp_eta{}; - // std::vector mcp_ID{}; - // std::vector mcp_ID{}; - + bool hasJets = kFALSE; for (auto& mcdjet : mcdjets) { if (!mcdjet.has_matchedJetGeo()) continue; for (auto& mcpjet : mcdjet.template matchedJetGeo_as()) { if (!mcpjet.has_matchedJetGeo()) continue; - - registry.fill(HIST("h_matched_REC_jet_pt"), mcpjet.pt(), mcdjet.pt() - mcpjet.pt()); - registry.fill(HIST("h_matched_REC_jet_phi"), mcpjet.phi(), mcdjet.phi() - mcpjet.phi()); - registry.fill(HIST("h_matched_REC_jet_eta"), mcpjet.eta(), mcdjet.eta() - mcpjet.eta()); + hasJets = kTRUE; + JEhistos.fill(HIST("h_matched_REC_jet_pt"), mcpjet.pt(), mcdjet.pt() - mcpjet.pt()); + JEhistos.fill(HIST("h_matched_REC_jet_phi"), mcpjet.phi(), mcdjet.phi() - mcpjet.phi()); + JEhistos.fill(HIST("h_matched_REC_jet_eta"), mcpjet.eta(), mcdjet.eta() - mcpjet.eta()); mcd_pt.push_back(mcdjet.pt()); mcd_eta.push_back(mcdjet.eta()); @@ -710,96 +1396,170 @@ struct phiInJets { mcp_eta.push_back(mcpjet.eta()); mcp_phi.push_back(mcpjet.phi()); } // mcpjets - } // mcdjets - + } // mcdjets // Now we do REC part - for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(tracks, tracks))) { - auto trk1 = track1.track_as(); - auto trk2 = track2.track_as(); - if (trk1.index() >= trk2.index()) - continue; - if (fabs(trk1.eta()) > 0.8 || fabs(trk2.eta()) > 0.8) - continue; - if (!trackSelection(trk1)) - continue; - if (!trackSelection(trk2)) - continue; - if ((trk1.sign() * trk2.sign()) > 0) - continue; // Not K+K- - if (!track1.has_mcParticle()) - continue; - if (!track2.has_mcParticle()) - continue; + if (hasJets) + JEhistos.fill(HIST("nEvents_MCRec_MATCHED"), 2.5); - auto part1 = track1.mcParticle(); - auto part2 = track2.mcParticle(); - if (fabs(part1.pdgCode()) != 321) - continue; // Not Kaon - if (fabs(part2.pdgCode()) != 321) - continue; // Not Kaon - if (!part1.has_mothers()) - continue; // Not decaying Kaon - if (!part2.has_mothers()) - continue; // Not decaying Kaon - - std::vector mothers1{}; - std::vector mothers1PDG{}; - for (auto& part1_mom : part1.mothers_as()) { - mothers1.push_back(part1_mom.globalIndex()); - mothers1PDG.push_back(part1_mom.pdgCode()); - } - if (mothers1.size() > 1) - continue; // Strange multi-mother decay - - std::vector mothers2{}; - std::vector mothers2PDG{}; - for (auto& part2_mom : part2.mothers_as()) { - mothers2.push_back(part2_mom.globalIndex()); - mothers2PDG.push_back(part2_mom.pdgCode()); - } - if (mothers2.size() > 1) - continue; // Strange multi-mother decay - if (mothers1PDG[0] != 333) - continue; // mother not phi - if (mothers2PDG[0] != 333) - continue; // mother not phi - if (mothers1[0] != mothers2[0]) - continue; // Kaons not from the same phi - - TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; - lDecayDaughter1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massKa); - lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massKa); - lResonance = lDecayDaughter1 + lDecayDaughter2; - if (lResonance.Rapidity() > 0.5) - continue; - - bool jetFlag = false; - for (int i = 0; i < mcd_pt.size(); i++) { - double phidiff = TVector2::Phi_mpi_pi(mcd_pt[i] - lResonance.Phi()); - double etadiff = mcd_eta[i] - lResonance.Eta(); - double R = TMath::Sqrt((etadiff * etadiff) + (phidiff * phidiff)); - if (R < cfgjetR) - jetFlag = true; - } - - if (jetFlag) { - JEhistos.fill(HIST("hMCRec_hUSS_INSIDE_1D"), lResonance.M()); - if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) - JEhistos.fill(HIST("hMCRec_hUSS_INSIDE_1D_2_3"), lResonance.M()); - JEhistos.fill(HIST("hMCRec_hUSS_INSIDE"), 1.0, lResonance.Pt(), lResonance.M()); - - } // jetflag - if (!jetFlag) { - JEhistos.fill(HIST("hMCRec_hUSS_OUTSIDE_1D"), lResonance.M()); - - if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) - JEhistos.fill(HIST("hMCRec_hUSS_OUTSIDE_1D_2_3"), lResonance.M()); - - JEhistos.fill(HIST("hMCRec_hUSS_OUTSIDE"), 1.0, lResonance.Pt(), lResonance.M()); - - } //! jetflag - } // tracks - } // main fcn + for (const auto& track1 : tracks) { + auto trk1 = track1.track_as(); + for (const auto& track2 : tracks) { + auto trk2 = track2.track_as(); + if (!cfgIsKstar) { + if (trk1.globalIndex() >= trk2.globalIndex()) + continue; + } else { + if (trk1.globalIndex() == trk2.globalIndex()) + continue; + } + if (fabs(trk1.eta()) > cfgtrkMaxEta || fabs(trk2.eta()) > cfgtrkMaxEta) + continue; + if ((trk1.sign() * trk2.sign()) > 0) + continue; // Not K+K- + if (trackSelection(trk1) && trackSelection(trk2)) { + if (cfgSimPID) { + if (!trackPID(trk1, true)) + continue; + if (!trackPID(trk2, false)) + continue; + } + if (track1.has_mcParticle() && track2.has_mcParticle()) { + auto part1 = track1.mcParticle(); + auto part2 = track2.mcParticle(); + if (fabs(part1.pdgCode()) != 321) + continue; // Not Kaon + if (!cfgIsKstar) { + if (fabs(part2.pdgCode()) != 321) + continue; // Not Kaon + } else { + if (fabs(part2.pdgCode()) != 211) + continue; // Not Kaon + } + if (!part1.has_mothers()) + continue; // Not decaying Kaon + if (!part2.has_mothers()) + continue; // Not decaying Kaon + + std::vector mothers1{}; + std::vector mothers1PDG{}; + std::vector mothers1Pt{}; + for (auto& part1_mom : part1.mothers_as()) { + mothers1.push_back(part1_mom.globalIndex()); + mothers1PDG.push_back(part1_mom.pdgCode()); + mothers1Pt.push_back(part1_mom.pt()); + } + + std::vector mothers2{}; + std::vector mothers2PDG{}; + std::vector mothers2Pt{}; + for (auto& part2_mom : part2.mothers_as()) { + mothers2.push_back(part2_mom.globalIndex()); + mothers2PDG.push_back(part2_mom.pdgCode()); + mothers2Pt.push_back(part2_mom.pt()); + } + if (!cfgIsKstar) { + if (mothers1PDG[0] != 333) + continue; // mother not phi + if (mothers2PDG[0] != 333) + continue; // mother not phi + } else { + if (mothers1PDG[0] != 313) + continue; // mother not phi + if (mothers2PDG[0] != 313) + continue; // mother not phi + } + if (mothers1[0] != mothers2[0]) + continue; // Kaons not from the same phi + + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; + lDecayDaughter1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massKa); + if (!cfgIsKstar) + lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massKa); + else + lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massPi); + + lResonance = lDecayDaughter1 + lDecayDaughter2; + if (fabs(lResonance.Eta()) > cfgtrkMaxEta) + continue; + + bool jetFlag = false; + int goodjets = 0; + double jetpt_mcp = 0; + double jetpt_mcd = 0; + for (std::vector::size_type i = 0; i < mcd_pt.size(); i++) { + double phidiff = TVector2::Phi_mpi_pi(mcd_phi[i] - lResonance.Phi()); + double etadiff = mcd_eta[i] - lResonance.Eta(); + double R = TMath::Sqrt((etadiff * etadiff) + (phidiff * phidiff)); + if (R < cfgjetR) { + jetpt_mcd = mcd_pt[i]; + jetpt_mcp = mcp_pt[i]; + goodjets++; + jetFlag = true; + } + } + + if (cfgSingleJet) { + if (goodjets > 1) { + jetpt_mcd = DistinguishJetsMC(mcd_pt, mcd_phi, mcd_eta, lResonance); + jetpt_mcp = DistinguishJetsMC(mcp_pt, mcp_phi, mcp_eta, lResonance); + } + } + if (jetFlag) { // Fill Resp. Matrix + if (cDebugLevel > 0) { + std::cout << "******************************************" << std::endl; + std::cout << "REC TO GEN LEVEL: " << std::endl; + std::cout << "Rec. Phi Pt: " << lResonance.Pt() << std::endl; + std::cout << "Rec. Jet Pt: " << jetpt_mcd << std::endl; + std::cout << "Gen. Phi Pt: " << mothers1Pt[0] << std::endl; + std::cout << "Gen. Jet Pt: " << jetpt_mcp << std::endl; + std::cout << "******************************************" << std::endl; + } + JEhistos.fill(HIST("Resp_Matrix_MATCHED"), lResonance.Pt(), jetpt_mcd, mothers1Pt[0], jetpt_mcp); + unsigned int seed = static_cast(std::chrono::system_clock::now().time_since_epoch().count()); + int dice = rand_r(&seed) % 2; + if (dice > 0) + JEhistos.fill(HIST("Resp_Matrix_MATCHED_rand0"), lResonance.Pt(), jetpt_mcd, mothers1Pt[0], jetpt_mcp); + else + JEhistos.fill(HIST("Resp_Matrix_MATCHED_rand1"), lResonance.Pt(), jetpt_mcd, mothers1Pt[0], jetpt_mcp); + + JEhistos.fill(HIST("2DRecToGen"), lResonance.Pt(), jetpt_mcd); + // check constrained eff + if (mothers1Pt[0] > 0 && mothers1Pt[0] < 20.0 && jetpt_mcp > 8 && jetpt_mcp < 200) + JEhistos.fill(HIST("2DRecToGen_constrained"), lResonance.Pt(), jetpt_mcd); + } + + // Fill 3D Invariant mass distributions + if (jetFlag) { + JEhistos.fill(HIST("hMCRec_hUSS_INSIDE_1D"), lResonance.M()); + if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) + JEhistos.fill(HIST("hMCRec_hUSS_INSIDE_1D_2_3"), lResonance.M()); + JEhistos.fill(HIST("hMCRec_hUSS_INSIDE"), jetpt_mcd, lResonance.Pt(), lResonance.M()); + } + // else if (!jetFlag && mcd_pt.size() > 0) { + // JEhistos.fill(HIST("hMCRec_hUSS_OUTSIDE_TRIG_1D"), lResonance.M()); + + // if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) + // JEhistos.fill(HIST("hMCRec_hUSS_OUTSIDE_TRIG_1D_2_3"), lResonance.M()); + + // JEhistos.fill(HIST("hMCRec_hUSS_OUTSIDE_TRIG"), jetpt_mcd, lResonance.Pt(), lResonance.M()); + + // } else if (!jetFlag) { + // JEhistos.fill(HIST("hMCRec_hUSS_OUTSIDE_1D"), lResonance.M()); + + // if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) + // JEhistos.fill(HIST("hMCRec_hUSS_OUTSIDE_1D_2_3"), lResonance.M()); + + // JEhistos.fill(HIST("hMCRec_hUSS_OUTSIDE"), jetpt_mcd, lResonance.Pt(), lResonance.M()); + + // } //! jetflag + + } // pass track cut + } // has mc particle + + } // tracks 2 + } // tracks 1 + // } // tracks + } // main fcn PROCESS_SWITCH(phiInJets, processMatchedRec, "phi matched Rec level MC", true); }; // end of main struct diff --git a/PWGJE/Tasks/photonIsolationQA.cxx b/PWGJE/Tasks/photonIsolationQA.cxx new file mode 100644 index 00000000000..7bac1ce3d5b --- /dev/null +++ b/PWGJE/Tasks/photonIsolationQA.cxx @@ -0,0 +1,512 @@ +// 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. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "EMCALBase/Geometry.h" +#include "EMCALCalib/BadChannelMap.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" + +#include "DataFormatsEMCAL/Cell.h" +#include "DataFormatsEMCAL/Constants.h" +#include "DataFormatsEMCAL/AnalysisCluster.h" +#include "CommonDataFormat/InteractionRecord.h" + +// \struct PhotonIsolationQA +/// \brief Task to select emcal clusters originating from promt photons +/// \author Berend van Beuzekom +/// \since 30-05-2024 +/// +/// This task is designed to select EMCal clusters originating from prompt photons. +/// Cluster selection is performed using Pt_Iso (density of particles around the cluster minus UE density) and cluster shape. +/// The task can also be run over Monte Carlo data to obtain a correction factor for the purity measurement using the ABCD method. + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using myGlobTracks = o2::soa::Join; +using collisionEvSelIt = o2::soa::Join; +using collisionEvSelItMC = o2::aod::McCollisions; +using MCClusters = o2::soa::Join; + +struct PhotonIsolationQA { + HistogramRegistry Data_Info{"Data_Info", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry MC_Info{"MC_Info", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + using o2HistType = HistType; + using o2Axis = AxisSpec; + + o2::emcal::Geometry* mGeometry = nullptr; + + Configurable maxPosZ{"maxPosZ", 10.0f, "maximum z position of collision in cm"}; + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + Configurable mClusterDefinition{"clusterDefinition", 0, "cluster definition to be selected, e.g. 10=kV3Default, 0 = kV1Default"}; + Configurable minTime{"minTime", -30., "Minimum cluster time for time cut"}; + Configurable maxTime{"maxTime", +35., "Maximum cluster time for time cut"}; + Configurable minClusterEnergy{"minClusterEnergy", 0.7f, "Minimal cluster energy"}; + Configurable minNCells{"minNCelss", 2, "Minimal amount of cells per cluster"}; + Configurable maxNLM{"maxNLM", 2, "Maximal amount of local maxima per cluster"}; + Configurable ExoticContribution{"ExoticContribution", false, "Exotic cluster in the data"}; + Configurable minDPhi{"minDPhi", 0.01, "Minimum dPhi between track and cluster"}; + Configurable Track_matching_Radius{"Track_matching_Radius", 0.05, "Radius for which a high energetic track is matched to a cluster"}; + Configurable isMC{"isMC", true, "should be set to true if the data set is monte carlo"}; + + Filter PosZFilter = nabs(aod::collision::posZ) < maxPosZ; + Filter PosZFilterMC = nabs(aod::mccollision::posZ) < maxPosZ; + Filter clusterDefinitionSelection = (o2::aod::emcalcluster::definition == mClusterDefinition) && (o2::aod::emcalcluster::time >= minTime) && (o2::aod::emcalcluster::time <= maxTime) && (o2::aod::emcalcluster::energy > minClusterEnergy) && (o2::aod::emcalcluster::nCells >= minNCells) && (o2::aod::emcalcluster::nlm <= maxNLM) && (o2::aod::emcalcluster::isExotic == ExoticContribution); + Filter emccellfilter = aod::calo::caloType == 1; + + using selectedCollisions = soa::Filtered; + using selectedMcCollisions = soa::Filtered; + using selectedClusters = soa::Filtered; + using selectedMCClusters = soa::Filtered; + + // Preslices + Preslice collisionsPerBC = aod::collision::bcId; + Preslice McCollisionsPerBC = aod::mccollision::bcId; + Preslice TracksPercollision = aod::track::collisionId; + Preslice perClusterMatchedTracks = o2::aod::emcalclustercell::emcalclusterId; + Preslice ClustersPerCol = aod::emcalcluster::collisionId; + Preslice CellsPerCluster = aod::emcalclustercell::emcalclusterId; + + std::vector eventSelectionBits; + int trackSelection = -1; + void init(o2::framework::InitContext&) + { + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + + mGeometry = o2::emcal::Geometry::GetInstanceFromRunNumber(300000); + auto nCells = mGeometry->GetNCells(); + + const o2Axis PosZ_Axis{100, -15, 15, "Z Positions (cm)"}; + const o2Axis Num_Cluster_Axis{10, 0, 10, "N Clusters"}; + const o2Axis Shower_Shape_Long_Axis{100, 0, 4, "#sigma^{2}_{long}"}; + const o2Axis Shower_Shape_Short_Axis{100, 0, 4, "#sigma^{2}_{short}"}; + const o2Axis Phi_Axis{100, 1, 6, "#phi"}; + const o2Axis Eta_Axis{100, -0.9, 0.9, "#eta"}; + const o2Axis Energy_Axis{100, 0, 100, "E (GeV/c)"}; + const o2Axis NCells_Axis{50, 0, 50, "N Cells"}; + const o2Axis Num_Track_Axis{20, -0.5, 19.5, "N Tracks"}; + const o2Axis PtIso_Axis{100, -10, 15, "P_{T, Iso} (GeV/c)"}; + const o2Axis Rho_Axis{200, 0, 200, "#rho (#frac{GeV/c}{A})"}; + const o2Axis ABCD_Axis{5, 0, 5, "ABCD"}; + const o2Axis NLM_Axis{50, -0.5, 49.5, "NLM"}; + const o2Axis PDG_Axis{20000, -10000.5, 9999.5, "PDG Code"}; + const o2Axis Status_Code_Axis{400, -200.5, 199.5, "Status Code"}; + const o2Axis BC_Axis{100, -0.5, 99.5, "Col per BC"}; + const o2Axis CellNumber_Axis{nCells, -0.5, nCells - 0.5, "Cell Number"}; + const o2Axis SM_Flag_Axis{2, -0.5, 1.5}; + + Data_Info.add("hPosZ", "Z Position of collision", o2HistType::kTH1F, {PosZ_Axis}); + Data_Info.add("hNumClusters", "Number of cluster per collision", o2HistType::kTH1F, {Num_Cluster_Axis}); + Data_Info.add("hClusterLocation", "Location of shower in eta phi plane", o2HistType::kTH2F, {{Eta_Axis}, {Phi_Axis}}); + Data_Info.add("hEnergy_ShowerShapeLong", "Energy vs Shower shape long axis", o2HistType::kTH2F, {{Energy_Axis}, {Shower_Shape_Long_Axis}}); + Data_Info.add("hEnergy_ShowerShapeShort", "Energy vs Shower shape short axis", o2HistType::kTH2F, {{Energy_Axis}, {Shower_Shape_Short_Axis}}); + Data_Info.add("hEnergy_m02_m20", "Energy cluster Vs m02 vs m20", o2HistType::kTH3F, {{Energy_Axis}, {Shower_Shape_Long_Axis}, {Shower_Shape_Short_Axis}}); + Data_Info.add("hEnergy_NCells", "Energy vs Number of cells in cluster", o2HistType::kTH2F, {{Energy_Axis}, {NCells_Axis}}); + Data_Info.add("hEvsNumTracks", "Energy of cluster vs matched tracks", o2HistType::kTH2F, {{Energy_Axis}, {Num_Track_Axis}}); + + Data_Info.add("hEvsPtIso", "Pt_Iso", o2HistType::kTH2F, {{Energy_Axis}, {PtIso_Axis}}); + Data_Info.add("hRho_Perpen_Cone", "Energy vs Density of perpendicular cone", o2HistType::kTH2F, {{Energy_Axis}, {Rho_Axis}}); + Data_Info.add("hShowerShape", "Shower shape", o2HistType::kTH2F, {{Shower_Shape_Long_Axis}, {Shower_Shape_Short_Axis}}); + Data_Info.add("hSigmaLongvsPtIso", "Long shower shape vs Pt_Iso", o2HistType::kTH3F, {{Shower_Shape_Long_Axis}, {PtIso_Axis}, {Energy_Axis}}); + Data_Info.add("hABCDControlRegion", "Yield Control Regions", o2HistType::kTH2F, {{ABCD_Axis}, {Energy_Axis}}); + Data_Info.add("hCollperBC", "collisions per BC", o2HistType::kTH1F, {BC_Axis}); + Data_Info.add("hEnergy_NLM_Flag", "Energy vs NLM", o2HistType::kTH3F, {{Energy_Axis}, {NLM_Axis}, {SM_Flag_Axis}}); + Data_Info.add("hNCells_NLM_Flag", "Energy vs NLM", o2HistType::kTH3F, {{NCells_Axis}, {NLM_Axis}, {SM_Flag_Axis}}); + + MC_Info.add("hPosZ", "Z Position of collision", o2HistType::kTH1F, {PosZ_Axis}); + MC_Info.get(HIST("hPosZ"))->Sumw2(); + MC_Info.add("hNumClusters", "Number of cluster per collision", o2HistType::kTH1F, {Num_Cluster_Axis}); + MC_Info.get(HIST("hNumClusters"))->Sumw2(); + MC_Info.add("hClusterLocation", "Location of shower in eta phi plane", o2HistType::kTH2F, {{Eta_Axis}, {Phi_Axis}}); + MC_Info.add("hEnergy_ShowerShapeLong", "Energy vs Shower shape long axis", o2HistType::kTH2F, {{Energy_Axis}, {Shower_Shape_Long_Axis}}); + MC_Info.get(HIST("hEnergy_ShowerShapeLong"))->Sumw2(); + MC_Info.add("hEnergy_ShowerShapeShort", "Energy vs Shower shape short axis", o2HistType::kTH2F, {{Energy_Axis}, {Shower_Shape_Short_Axis}}); + MC_Info.get(HIST("hEnergy_ShowerShapeShort"))->Sumw2(); + MC_Info.add("hEnergy_m02_m20", "Energy cluster Vs m02 vs m20", o2HistType::kTH3F, {{Energy_Axis}, {Shower_Shape_Long_Axis}, {Shower_Shape_Short_Axis}}); + MC_Info.get(HIST("hEnergy_m02_m20"))->Sumw2(); + MC_Info.add("hEnergy_NCells", "Energy vs Number of cells in cluster", o2HistType::kTH2F, {{Energy_Axis}, {NCells_Axis}}); + MC_Info.get(HIST("hEnergy_NCells"))->Sumw2(); + + MC_Info.add("hEvsNumTracks", "Energy of cluster vs matched tracks", o2HistType::kTH2F, {{Energy_Axis}, {Num_Track_Axis}}); + MC_Info.get(HIST("hEvsNumTracks"))->Sumw2(); + MC_Info.add("hEvsPtIso", "Pt_Iso", o2HistType::kTH2F, {{Energy_Axis}, {PtIso_Axis}}); + MC_Info.get(HIST("hEvsPtIso"))->Sumw2(); + MC_Info.add("hRho_Perpen_Cone", "Energy vs Density of perpendicular cone", o2HistType::kTH2F, {{Energy_Axis}, {Rho_Axis}}); + MC_Info.get(HIST("hRho_Perpen_Cone"))->Sumw2(); + MC_Info.add("hShowerShape", "Shower shape", o2HistType::kTH2F, {{Shower_Shape_Long_Axis}, {Shower_Shape_Short_Axis}}); + MC_Info.get(HIST("hShowerShape"))->Sumw2(); + MC_Info.add("hSigmaLongvsPtIso", "Long shower shape vs Pt_Iso", o2HistType::kTH3F, {{Shower_Shape_Long_Axis}, {PtIso_Axis}, {Energy_Axis}}); + MC_Info.get(HIST("hSigmaLongvsPtIso"))->Sumw2(); + MC_Info.add("hABCDControlRegion", "Yield Control Regions", o2HistType::kTH2F, {{ABCD_Axis}, {Energy_Axis}}); + MC_Info.get(HIST("hABCDControlRegion"))->Sumw2(); + MC_Info.add("hClusterEnergy_MCParticleEnergy", "Energy cluster vs energy particle of cluster", o2HistType::kTH2F, {{Energy_Axis}, {Energy_Axis}}); + MC_Info.get(HIST("hClusterEnergy_MCParticleEnergy"))->Sumw2(); + MC_Info.add("hMotherPDG", "PDG code of candidate photons mother", o2HistType::kTH1F, {{2000, -1000.5, 999.5}}); + MC_Info.add("hMotherStatusCode", "Statuscode of candidate photons mother", o2HistType::kTH1F, {{400, -200.5, 199.5}}); + MC_Info.add("hMotherStatusCodeVsPDG", "Statuscode of candidate photons mother", o2HistType::kTH2F, {{Status_Code_Axis}, {PDG_Axis}}); + MC_Info.add("hCollperBC", "collisions per BC", o2HistType::kTH1F, {BC_Axis}); + MC_Info.add("hEnergy_NLM_Flag", "Energy vs NLM", o2HistType::kTH3F, {{Energy_Axis}, {NLM_Axis}, {SM_Flag_Axis}}); + MC_Info.get(HIST("hEnergy_NLM_Flag"))->Sumw2(); + MC_Info.add("hNCells_NLM_Flag", "Energy vs NLM", o2HistType::kTH3F, {{NCells_Axis}, {NLM_Axis}, {SM_Flag_Axis}}); + MC_Info.get(HIST("hNCells_NLM_Flag"))->Sumw2(); + MC_Info.add("hPromtPhoton", "Energy vs m02 vs NCells, PtIso", o2HistType::kTHnSparseF, {{Energy_Axis}, {Shower_Shape_Long_Axis}, {NCells_Axis}, {PtIso_Axis}}); + + std::vector bin_names = {"A", "B", "C", "D", "True Bckgr A"}; + for (size_t i = 0; i < bin_names.size(); i++) { + MC_Info.get(HIST("hABCDControlRegion"))->GetXaxis()->SetBinLabel(i + 1, bin_names[i].c_str()); + Data_Info.get(HIST("hABCDControlRegion"))->GetXaxis()->SetBinLabel(i + 1, bin_names[i].c_str()); + } + } + + // boolian returns true if a track is matched to the cluster with E_Cluster/P_track < 1.75. Otherwise returns false + bool track_matching(const auto& cluster, o2::aod::EMCALMatchedTracks const& matched_tracks) + { + for (const auto& match : matched_tracks) { + double dphi = cluster.phi() - match.track_as().phi(); + if (abs(dphi) > M_PI) { + dphi = 2. * M_PI - abs(dphi); + } + double distance = sqrt(pow((cluster.eta() - match.track_as().eta()), 2) + pow(dphi, 2)); + if (distance < Track_matching_Radius) { + double abs_pt = abs(match.track_as().pt()); + if ((cluster.energy() / abs_pt) < 1.75) { + return true; + } + } + } + return false; + } + + // sums the pt of all tracks around the cluster within a radius of R = 0.4 + double sum_Pt_tracks_in_cone(const auto& cluster, myGlobTracks const& tracks, double Cone_Radius = 0.4) + { + double sum_Pt = 0.; + for (const auto& track : tracks) { + double dphi = cluster.phi() - track.phi(); + if (abs(dphi) > M_PI) { + dphi = 2. * M_PI - abs(dphi); + } + double distance = sqrt(pow((cluster.eta() - track.eta()), 2) + pow(dphi, 2)); + if (distance < Cone_Radius) { + sum_Pt += track.pt(); + } + } + return sum_Pt; + } + + // Calculates the Pt density of tracks of the UE with the perpendicular cone method + double Rho_Perpendicular_Cone(const auto& cluster, myGlobTracks const& tracks, double Perpendicular_Cone_Radius = 0.4) + { + double sum_Pt = 0.; + double Perpendicular_Phi1 = cluster.phi() + (1. / 2.) * M_PI; + double Perpendicular_Phi2 = cluster.phi() - (1. / 2.) * M_PI; + if (Perpendicular_Phi1 > 2. * M_PI) { + Perpendicular_Phi1 = Perpendicular_Phi1 - 2. * M_PI; + } + if (Perpendicular_Phi2 < 0.) { + Perpendicular_Phi2 = 2. * M_PI + Perpendicular_Phi2; + } + for (const auto& track : tracks) { + double dphi1 = Perpendicular_Phi1 - track.phi(); + double dphi2 = Perpendicular_Phi2 - track.phi(); + if (abs(dphi1) > M_PI) { + dphi1 = 2. * M_PI - abs(dphi1); + } + if (abs(dphi2) > M_PI) { + dphi2 = 2. * M_PI - abs(dphi2); + } + double distance1 = sqrt(pow((cluster.eta() - track.eta()), 2) + pow(dphi1, 2)); + double distance2 = sqrt(pow((cluster.eta() - track.eta()), 2) + pow(dphi2, 2)); + if (distance1 < Perpendicular_Cone_Radius) { + sum_Pt += track.pt(); + } + if (distance2 < Perpendicular_Cone_Radius) { + sum_Pt += track.pt(); + } + } + double Rho = sum_Pt / (2. * M_PI * pow(Perpendicular_Cone_Radius, 2)); + return Rho; + } + + // Calculates the Pt_Isolation. (Check if the photon candidate is isolated) + double Pt_Iso(double sum_Pt_tracks_in_cone, double rho, double Cone_Radius = 0.4) + { + double Pt_Iso = sum_Pt_tracks_in_cone - rho * M_PI * pow(Cone_Radius, 2); + return Pt_Iso; + } + + void fillclusterhistos(const auto cluster, HistogramRegistry registry, double weight = 1.0) + { + registry.fill(HIST("hClusterLocation"), cluster.eta(), cluster.phi()); + if (isMC == true) { + registry.fill(HIST("hEnergy_ShowerShapeLong"), cluster.energy(), cluster.m02(), weight); + registry.fill(HIST("hEnergy_ShowerShapeShort"), cluster.energy(), cluster.m20(), weight); + registry.fill(HIST("hEnergy_NCells"), cluster.energy(), cluster.nCells(), weight); + registry.fill(HIST("hEnergy_m02_m20"), cluster.energy(), cluster.m02(), cluster.m20(), weight); + registry.fill(HIST("hShowerShape"), cluster.m02(), cluster.m20(), weight); + } else { + registry.fill(HIST("hEnergy_ShowerShapeLong"), cluster.energy(), cluster.m02()); + registry.fill(HIST("hEnergy_ShowerShapeShort"), cluster.energy(), cluster.m20()); + registry.fill(HIST("hEnergy_NCells"), cluster.energy(), cluster.nCells()); + registry.fill(HIST("hEnergy_m02_m20"), cluster.energy(), cluster.m02(), cluster.m20()); + registry.fill(HIST("hShowerShape"), cluster.m02(), cluster.m20()); + } + } + + void fillABCDHisto(HistogramRegistry registry, const auto& cluster, double Pt_iso, double weight = 1.0) + { + if (isMC == true) { + if ((Pt_iso < 1.5) && (cluster.m02() < 0.3) && (cluster.m02() > 0.1)) { + registry.fill(HIST("hABCDControlRegion"), 0.5, cluster.energy(), weight); + } + if ((Pt_iso > 4.0) && (cluster.m02() < 0.3) && (cluster.m02() > 0.1)) { + registry.fill(HIST("hABCDControlRegion"), 1.5, cluster.energy(), weight); + } + if ((Pt_iso < 1.5) && (cluster.m02() < 2.0) && (cluster.m02() > 0.4)) { + registry.fill(HIST("hABCDControlRegion"), 2.5, cluster.energy(), weight); + } + if ((Pt_iso > 4.0) && (cluster.m02() < 2.0) && (cluster.m02() > 0.4)) { + registry.fill(HIST("hABCDControlRegion"), 3.5, cluster.energy(), weight); + } + } else { + if ((Pt_iso < 1.5) && (cluster.m02() < 0.3) && (cluster.m02() > 0.1)) { + registry.fill(HIST("hABCDControlRegion"), 0.5, cluster.energy()); + } + if ((Pt_iso > 4.0) && (cluster.m02() < 0.3) && (cluster.m02() > 0.1)) { + registry.fill(HIST("hABCDControlRegion"), 1.5, cluster.energy()); + } + if ((Pt_iso < 1.5) && (cluster.m02() < 2.0) && (cluster.m02() > 0.4)) { + registry.fill(HIST("hABCDControlRegion"), 2.5, cluster.energy()); + } + if ((Pt_iso > 4.0) && (cluster.m02() < 2.0) && (cluster.m02() > 0.4)) { + registry.fill(HIST("hABCDControlRegion"), 3.5, cluster.energy()); + } + } + } + + // iterates over all mothers to check if photon originated from hard scattering (statuscode = abs(23)) + template + int getOriginalMotherIndex(const typename T::iterator& particle) + { + if (abs(particle.getGenStatusCode()) == 23) { + return particle.getGenStatusCode(); + } + auto mother = particle; + + while (mother.has_mothers()) { + mother = mother.template mothers_first_as(); + + MC_Info.fill(HIST("hMotherPDG"), mother.pdgCode()); + MC_Info.fill(HIST("hMotherStatusCode"), mother.getGenStatusCode()); + MC_Info.fill(HIST("hMotherStatusCodeVsPDG"), mother.getGenStatusCode(), mother.pdgCode()); + + int motherStatusCode = mother.getGenStatusCode(); + int motherPDGCode = mother.pdgCode(); + + if (abs(motherStatusCode) == 23 && motherPDGCode == 22) { + return motherStatusCode; + } + } + return -1.0; + } + + // Calculates the number of local maxima within a cluster + std::pair CalculateNLM(const auto& ClusterCells) + { + std::vector> Cell_Info(ClusterCells.size(), std::vector(3)); + std::vector supermodules; + + int idx = 0; + for (auto& Cell : ClusterCells) { + auto [supermodule, module, phiInModule, etaInModule] = mGeometry->GetCellIndex(Cell.calo().cellNumber()); + auto [row, col] = mGeometry->GetCellPhiEtaIndexInSModule(supermodule, module, phiInModule, etaInModule); + supermodules.push_back(supermodule); + Cell_Info[idx++] = {static_cast(row), static_cast(col), Cell.calo().amplitude()}; + } + + std::vector> local_max_vector(ClusterCells.size(), std::vector(3)); + for (size_t i = 0; i < Cell_Info.size(); ++i) { + float row = Cell_Info[i][0]; + float col = Cell_Info[i][1]; + float amp = Cell_Info[i][2]; + + bool updated; + do { + updated = false; + for (const auto& cell : Cell_Info) { + float dr = cell[0] - row; + float dc = cell[1] - col; + if (std::abs(dr) <= 1 && std::abs(dc) <= 1 && cell[2] > amp) { + row += dr; + col += dc; + amp = cell[2]; + updated = true; + } + } + } while (updated); + + local_max_vector[i] = {row, col, amp}; + } + + std::set uniqueRows; + for (const auto& localMax : local_max_vector) { + uniqueRows.insert(localMax[0]); + } + + int NLM = uniqueRows.size(); + + // flag = 0 if cluster falls in 1 supermodule. flag = 1 if cluster falls in multiple supermodules and will have automatically more local maxima + int flag = (std::unordered_set(supermodules.begin(), supermodules.end()).size() > 1) ? 1 : 0; + return std::make_pair(NLM, flag); + } + + // process monte carlo data + void processMC(aod::BCs const& bcs, selectedMcCollisions const& Collisions, selectedMCClusters const& mcclusters, aod::McParticles const&, myGlobTracks const& tracks, o2::aod::EMCALMatchedTracks const& matchedtracks, aod::Calos const&, aod::EMCALClusterCells const& ClusterCells) + { + for (auto bc : bcs) { + auto collisionsInBC = Collisions.sliceBy(McCollisionsPerBC, bc.globalIndex()); + MC_Info.fill(HIST("hCollperBC"), collisionsInBC.size()); + if (collisionsInBC.size() == 1) { + for (const auto& Collision : collisionsInBC) { + MC_Info.fill(HIST("hPosZ"), Collision.posZ(), Collision.weight()); + auto ClustersInCol = mcclusters.sliceBy(ClustersPerCol, Collision.globalIndex()); + auto tracksInCol = tracks.sliceBy(TracksPercollision, Collision.globalIndex()); + + if (ClustersInCol.size() > 0) { + MC_Info.fill(HIST("hNumClusters"), ClustersInCol.size(), Collision.weight()); + } + + for (auto& mccluster : ClustersInCol) { + auto tracksofcluster = matchedtracks.sliceBy(perClusterMatchedTracks, mccluster.globalIndex()); + fillclusterhistos(mccluster, MC_Info, Collision.weight()); + MC_Info.fill(HIST("hEvsNumTracks"), mccluster.energy(), tracksofcluster.size(), Collision.weight()); + + auto CellsInCluster = ClusterCells.sliceBy(CellsPerCluster, mccluster.globalIndex()); + auto [NLM, flag] = CalculateNLM(CellsInCluster); + MC_Info.fill(HIST("hEnergy_NLM_Flag"), mccluster.energy(), NLM, flag, Collision.weight()); + MC_Info.fill(HIST("hNCells_NLM_Flag"), mccluster.nCells(), NLM, flag, Collision.weight()); + + if (!track_matching(mccluster, tracksofcluster)) { // no track with significant momentum is matched to cluster + if (NLM <= maxNLM) { + double Pt_Cone = sum_Pt_tracks_in_cone(mccluster, tracksInCol); + double Rho_Perpen_Cone = Rho_Perpendicular_Cone(mccluster, tracksInCol); + double Pt_iso = Pt_Iso(Pt_Cone, Rho_Perpen_Cone); + + MC_Info.fill(HIST("hEvsPtIso"), mccluster.energy(), Pt_iso, Collision.weight()); + MC_Info.fill(HIST("hRho_Perpen_Cone"), mccluster.energy(), Rho_Perpen_Cone, Collision.weight()); + MC_Info.fill(HIST("hSigmaLongvsPtIso"), mccluster.m02(), Pt_iso, mccluster.energy(), Collision.weight()); + fillABCDHisto(MC_Info, mccluster, Pt_iso, Collision.weight()); + + // acces mc true info + auto ClusterParticles = mccluster.mcParticle_as(); + bool background = true; + for (auto& clusterparticle : ClusterParticles) { + if (clusterparticle.pdgCode() == 22) { + MC_Info.fill(HIST("hClusterEnergy_MCParticleEnergy"), mccluster.energy(), clusterparticle.e(), Collision.weight()); + int first_mother_status_code = getOriginalMotherIndex(clusterparticle); + if (abs(first_mother_status_code) == 23) { + background = false; + MC_Info.fill(HIST("hPromtPhoton"), mccluster.energy(), mccluster.m02(), mccluster.nCells(), Pt_iso); + } + } + } + if (background) { + if ((Pt_iso < 1.5) && (mccluster.m02() < 0.3) && (mccluster.m02() > 0.1)) { + MC_Info.fill(HIST("hABCDControlRegion"), 4.5, mccluster.energy(), Collision.weight()); + } + } + } + } + } + } + } + } + } + + PROCESS_SWITCH(PhotonIsolationQA, processMC, "proces MC data", true); + + void processData(aod::BCs const& bcs, selectedCollisions const& Collisions, selectedClusters const& clusters, o2::aod::EMCALMatchedTracks const& matchedtracks, myGlobTracks const& tracks, aod::Calos const&, aod::EMCALClusterCells const& ClusterCells) + { + for (auto bc : bcs) { + auto collisionsInBC = Collisions.sliceBy(collisionsPerBC, bc.globalIndex()); + Data_Info.fill(HIST("hCollperBC"), collisionsInBC.size()); + if (collisionsInBC.size() == 1) { + for (const auto& Collision : collisionsInBC) { + Data_Info.fill(HIST("hPosZ"), Collision.posZ()); + auto ClustersInCol = clusters.sliceBy(ClustersPerCol, Collision.globalIndex()); + auto tracksInCol = tracks.sliceBy(TracksPercollision, Collision.globalIndex()); + + if (ClustersInCol.size() > 0) { + Data_Info.fill(HIST("hNumClusters"), ClustersInCol.size()); + } + + for (auto& cluster : ClustersInCol) { + auto tracksofcluster = matchedtracks.sliceBy(perClusterMatchedTracks, cluster.globalIndex()); + fillclusterhistos(cluster, Data_Info); + Data_Info.fill(HIST("hEvsNumTracks"), cluster.energy(), tracksofcluster.size()); + + auto CellsInCluster = ClusterCells.sliceBy(CellsPerCluster, cluster.globalIndex()); + auto [NLM, flag] = CalculateNLM(CellsInCluster); + Data_Info.fill(HIST("hEnergy_NLM_Flag"), cluster.energy(), NLM, flag); + Data_Info.fill(HIST("hNCells_NLM_Flag"), cluster.nCells(), NLM, flag); + + if (!track_matching(cluster, tracksofcluster)) { // no track with significant momentum is matched to cluster + if (NLM < maxNLM) { + double Pt_Cone = sum_Pt_tracks_in_cone(cluster, tracksInCol); + double Rho_Perpen_Cone = Rho_Perpendicular_Cone(cluster, tracksInCol); + double Pt_iso = Pt_Iso(Pt_Cone, Rho_Perpen_Cone); + + Data_Info.fill(HIST("hEvsPtIso"), cluster.energy(), Pt_iso); + Data_Info.fill(HIST("hRho_Perpen_Cone"), cluster.energy(), Rho_Perpen_Cone); + Data_Info.fill(HIST("hSigmaLongvsPtIso"), cluster.m02(), Pt_iso, cluster.energy()); + fillABCDHisto(Data_Info, cluster, Pt_iso); + } + } + } + } + } + } + } + + PROCESS_SWITCH(PhotonIsolationQA, processData, "proces data", true); +}; + +WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"photon-isolation-qa"})}; +} diff --git a/PWGJE/Tasks/recoilJets.cxx b/PWGJE/Tasks/recoilJets.cxx new file mode 100644 index 00000000000..ba3dde1e8f2 --- /dev/null +++ b/PWGJE/Tasks/recoilJets.cxx @@ -0,0 +1,638 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author Kotliarov Artem +/// \file recoilJets.cxx +/// \brief hadron-jet correlation analysis + +#include +#include +#include + +#include "TRandom3.h" +#include "TVector2.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "CommonConstants/MathConstants.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" + +#include "PWGJE/Core/JetDerivedDataUtilities.h" + +#include "EventFiltering/filterTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// Shorthand notations +using FilteredColl = soa::Filtered>::iterator; +using FilteredCollPartLevel = soa::Filtered>::iterator; +using FilteredCollDetLevelGetWeight = soa::Filtered>::iterator; + +using FilteredJets = soa::Filtered>; +using FilteredJetsDetLevel = soa::Filtered>; +using FilteredJetsPartLevel = soa::Filtered>; + +using FilteredMatchedJetsDetLevel = soa::Filtered>; +using FilteredMatchedJetsPartLevel = soa::Filtered>; + +using FilteredTracks = soa::Filtered; + +struct RecoilJets { + + // List of configurable parameters + Configurable evSel{"evSel", "sel8", "Choose event selection"}; + Configurable trkSel{"trkSel", "globalTracks", "Set track selection"}; + Configurable vertexZCut{"vertexZCut", 10., "Accepted z-vertex range"}; + Configurable fracSig{"fracSig", 0.9, "Fraction of events to use for signal TT"}; + Configurable bGetMissJets{"bGetMissJets", false, "Flag to get miss histo for particle level jets"}; + + Configurable trkPtMin{"trkPtMin", 0.15, "Minimum pT of acceptanced tracks"}; + Configurable trkPtMax{"trkPtMax", 100., "Maximum pT of acceptanced tracks"}; + + Configurable trkEtaCut{"trkEtaCut", 0.9, "Eta acceptance of TPC"}; + Configurable jetR{"jetR", 0.4, "Jet cone radius"}; + + Configurable triggerMasks{"triggerMasks", "", "Relevant trigger masks: fTrackLowPt,fTrackHighPt"}; + Configurable skipMBGapEvents{"skipMBGapEvents", false, "flag to choose to reject min. bias gap events; jet-level rejection applied at the jet finder level, here rejection is applied for collision and track process functions"}; + + // List of configurable parameters for MC + Configurable pTHatExponent{"pTHatExponent", 4.0, "Exponent of the event weight for the calculation of pTHat"}; + Configurable pTHatMax{"pTHatMax", 999.0, "Maximum fraction of hard scattering for jet acceptance in MC"}; + Configurable pTHatMaxTrack{"pTHatMaxTrack", 999.0, "Maximum fraction of hard scattering for track acceptance in MC"}; + + // Parameters for recoil jet selection + Configurable ptTTrefMin{"ptTTrefMin", 5., "Minimum pT of reference TT"}; + Configurable ptTTrefMax{"ptTTrefMax", 7., "Maximum pT of reference TT"}; + Configurable ptTTsigMin{"ptTTsigMin", 20., "Minimum pT of signal TT"}; + Configurable ptTTsigMax{"ptTTsigMax", 50., "Maximum pT of signal TT"}; + Configurable recoilRegion{"recoilRegion", 0.6, "Width of recoil acceptance"}; + + // List of configurable parameters for histograms + Configurable histJetPt{"histJetPt", 100, "Maximum value of jet pT shown in histograms"}; + + // Axes specification + AxisSpec pT{histJetPt, 0.0, histJetPt * 1.0, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec jetPTcorr{histJetPt + 20, -20., histJetPt * 1.0, "#it{p}_{T, jet}^{ch, corr} (GeV/#it{c})"}; + AxisSpec phiAngle{40, 0.0, constants::math::TwoPI, "#it{#varphi} (rad)"}; + AxisSpec deltaPhiAngle{52, 0.0, constants::math::PI, "#Delta#it{#varphi} (rad)"}; + AxisSpec pseudorap{40, -1., 1., "#it{#eta}"}; + AxisSpec pseudorapJets{20, -0.5, 0.5, "#it{#eta}_{jet}"}; + AxisSpec jetArea{50, 0.0, 5., "Area_{jet}"}; + AxisSpec rhoArea{60, 0.0, 60., "#it{#rho} #times Area_{jet}"}; + AxisSpec rho{50, 0.0, 50., "#it{#rho}"}; + + Preslice partJetsPerCollision = aod::jet::mcCollisionId; + + TRandom3* rand = new TRandom3(0); + + // Declare filter on collision Z vertex + Filter collisionFilter = nabs(aod::jcollision::posZ) < vertexZCut; + Filter collisionFilterMC = nabs(aod::jmccollision::posZ) < vertexZCut; + + // Declare filters on accepted tracks and MC particles (settings for jet reco are provided in the jet finder wagon) + Filter trackFilter = aod::jtrack::pt > trkPtMin&& aod::jtrack::pt < trkPtMax&& nabs(aod::jtrack::eta) < trkEtaCut; + Filter partFilter = nabs(aod::jmcparticle::eta) < trkEtaCut; + + // Declare filter on jets + Filter jetRadiusFilter = aod::jet::r == nround(jetR.node() * 100.); + + HistogramRegistry spectra; + + std::vector eventSelectionBits; + int trackSelection = -1; + std::vector triggerMaskBits; + + Service pdg; + + void init(InitContext const&) + { + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(evSel)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trkSel)); + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(triggerMasks); + + // List of raw and MC det. distributions + if (doprocessData || doprocessMCDetLevel || doprocessMCDetLevelWeighted) { + spectra.add("vertexZ", "Z vertex of collisions", kTH1F, {{60, -12., 12.}}); + spectra.add("hHasAssocMcCollision", "Has det. level coll. associat. MC coll.", kTH1F, {{2, 0.0, 2.}}); + spectra.get(HIST("hHasAssocMcCollision"))->GetXaxis()->SetBinLabel(1, "Yes"); + spectra.get(HIST("hHasAssocMcCollision"))->GetXaxis()->SetBinLabel(2, "No"); + + spectra.add("hTrackPtEtaPhi", "Charact. of tracks", kTH3F, {pT, pseudorap, phiAngle}); + + spectra.add("hTTSig_pT", "pT spectrum of all found TT_{Sig} cand.", kTH1F, {{40, 10., 50.}}); // needed to distinguish merged data from diff. wagons + + spectra.add("hNtrig", "Total number of selected triggers per class", kTH1F, {{2, 0.0, 2.}}); + spectra.get(HIST("hNtrig"))->GetXaxis()->SetBinLabel(1, "TT_{ref}"); + spectra.get(HIST("hNtrig"))->GetXaxis()->SetBinLabel(2, "TT_{sig}"); + + spectra.add("hTTRef_per_event", "Number of TT_{Ref} per event", kTH1F, {{15, 0.5, 15.5}}); + spectra.add("hTTSig_per_event", "Number of TT_{Sig} per event", kTH1F, {{10, 0.5, 10.5}}); + + spectra.add("hJetPtEtaPhiRhoArea", "Charact. of inclusive jets", kTHnSparseF, {pT, pseudorapJets, phiAngle, rho, jetArea}); + + spectra.add("hDPhi_JetPt_Corr_TTRef", "Events w. TT_{Ref}: #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH2F, {deltaPhiAngle, jetPTcorr}); + spectra.add("hDPhi_JetPt_Corr_TTSig", "Events w. TT_{Sig}: #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH2F, {deltaPhiAngle, jetPTcorr}); + spectra.add("hDPhi_JetPt_TTRef", "Events w. TT_{Ref}: #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH2F, {deltaPhiAngle, pT}); + spectra.add("hDPhi_JetPt_TTSig", "Events w. TT_{Sig}: #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH2F, {deltaPhiAngle, pT}); + + spectra.add("hRecoil_JetPt_Corr_TTRef", "Events w. TT_{Ref}: #it{p}_{T} of recoil jets", kTH1F, {jetPTcorr}); + spectra.add("hRecoil_JetPt_Corr_TTSig", "Events w. TT_{Sig}: #it{p}_{T} of recoil jets", kTH1F, {jetPTcorr}); + spectra.add("hRecoil_JetPt_TTRef", "Events w. TT_{Ref}: #it{p}_{T} of recoil jets", kTH1F, {pT}); + spectra.add("hRecoil_JetPt_TTSig", "Events w. TT_{Sig}: #it{p}_{T} of recoil jets", kTH1F, {pT}); + + spectra.add("hJetArea_JetPt_Rho_TTRef", "Events w. TT_{Ref}: A_{jet} & jet pT & #rho", kTH3F, {jetArea, pT, rho}); + spectra.add("hJetArea_JetPt_Rho_TTSig", "Events w. TT_{Sig}: A_{jet} & jet pT & #rho", kTH3F, {jetArea, pT, rho}); + } + + // List of MC particle level distributions + if (doprocessMCPartLevel || doprocessMCPartLevelWeighted) { + spectra.add("vertexZMC", "Z vertex of jmccollision", kTH1F, {{60, -12., 12.}}); + spectra.add("ptHat", "Distribution of pT hat", kTH1F, {{500, 0.0, 100.}}); + + spectra.add("hPartPtEtaPhi", "Charact. of particles", kTH3F, {pT, pseudorap, phiAngle}); + spectra.add("hNtrig_Part", "Total number of selected triggers per class", kTH1F, {{2, 0.0, 2.}}); + spectra.get(HIST("hNtrig_Part"))->GetXaxis()->SetBinLabel(1, "TT_{ref}"); + spectra.get(HIST("hNtrig_Part"))->GetXaxis()->SetBinLabel(2, "TT_{sig}"); + + spectra.add("hTTRef_per_event_Part", "Number of TT_{Ref} per event", kTH1F, {{15, 0.5, 15.5}}); + spectra.add("hTTSig_per_event_Part", "Number of TT_{Sig} per event", kTH1F, {{10, 0.5, 10.5}}); + + spectra.add("hJetPtEtaPhiRhoArea_Part", "Charact. of inclusive part. level jets", kTHnSparseF, {pT, pseudorapJets, phiAngle, rho, jetArea}); + + spectra.add("hDPhi_JetPt_Corr_TTRef_Part", "Events w. TT_{Ref}: #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH2F, {deltaPhiAngle, jetPTcorr}); + spectra.add("hDPhi_JetPt_Corr_TTSig_Part", "Events w. TT_{Sig}: #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH2F, {deltaPhiAngle, jetPTcorr}); + spectra.add("hDPhi_JetPt_TTRef_Part", "Events w. TT_{Ref}: #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH2F, {deltaPhiAngle, pT}); + spectra.add("hDPhi_JetPt_TTSig_Part", "Events w. TT_{Sig}: #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH2F, {deltaPhiAngle, pT}); + + spectra.add("hRecoil_JetPt_Corr_TTRef_Part", "Events w. TT_{Ref}: #it{p}_{T} of recoil jets", kTH1F, {jetPTcorr}); + spectra.add("hRecoil_JetPt_Corr_TTSig_Part", "Events w. TT_{Sig}: #it{p}_{T} of recoil jets", kTH1F, {jetPTcorr}); + spectra.add("hRecoil_JetPt_TTRef_Part", "Events w. TT_{Ref}: #it{p}_{T} of recoil jets", kTH1F, {pT}); + spectra.add("hRecoil_JetPt_TTSig_Part", "Events w. TT_{Sig}: #it{p}_{T} of recoil jets", kTH1F, {pT}); + + spectra.add("hJetArea_JetPt_Rho_TTRef_Part", "Events w. TT_{Ref}: A_{jet} & jet pT & #rho", kTH3F, {jetArea, pT, rho}); + spectra.add("hJetArea_JetPt_Rho_TTSig_Part", "Events w. TT_{Sig}: A_{jet} & jet pT & #rho", kTH3F, {jetArea, pT, rho}); + } + + // Jet matching: part. vs. det. + if (doprocessJetsMatched || doprocessJetsMatchedWeighted) { + spectra.add("hJetPt_DetLevel_vs_PartLevel", "Correlation jet pT at det. vs. part. levels", kTH2F, {{200, 0.0, 200.}, {200, 0.0, 200.}}); + // spectra.add("hJetPt_Corr_PartLevel_vs_DetLevel", "Correlation jet pT at part. vs. det. levels", kTH2F, {jetPTcorr, jetPTcorr}); + spectra.add("hJetPt_DetLevel_vs_PartLevel_RecoilJets", "Correlation recoil jet pT at part. vs. det. levels", kTH2F, {{200, 0.0, 200.}, {200, 0.0, 200.}}); + // spectra.add("hJetPt_Corr_PartLevel_vs_DetLevel_RecoilJets", "Correlation recoil jet pT at part. vs. det. levels", kTH2F, {jetPTcorr, jetPTcorr}); + + if (bGetMissJets) { + spectra.add("hMissedJets_pT", "Part. level jets w/o matched pair", kTH1F, {{200, 0.0, 200.}}); + // spectra.add("hMissedJets_Corr_pT", "Part. level jets w/o matched pair", kTH1F, {jetPTcorr}); + spectra.add("hMissedJets_pT_RecoilJets", "Part. level jets w/o matched pair", kTH1F, {{200, 0.0, 200.}}); + // spectra.add("hMissedJets_Corr_pT_RecoilJets", "Part. level jets w/o matched pair", kTH1F, {jetPTcorr}); + } else { + spectra.add("hFakeJets_pT", "Det. level jets w/o matched pair", kTH1F, {{200, 0.0, 200.}}); + // spectra.add("hFakeJets_Corr_pT", "Det. level jets w/o matched pair", kTH1F, {jetPTcorr}); + spectra.add("hFakeJets_pT_RecoilJets", "Det. level jets w/o matched pair", kTH1F, {{200, 0.0, 200.}}); + // spectra.add("hFakeJets_Corr_pT_RecoilJets", "Det. level jets w/o matched pair", kTH1F, {jetPTcorr}); + } + + spectra.add("hJetPt_resolution", "Jet p_{T} relative resolution as a func. of jet #it{p}_{T, part}", kTH2F, {{100, -5., 5.}, pT}); + spectra.add("hJetPt_resolution_RecoilJets", "Jet p_{T} relative resolution as a func. of jet #it{p}_{T, part}", kTH2F, {{100, -5., 5.}, pT}); + + spectra.add("hJetPhi_resolution", "#varphi resolution as a func. of jet #it{p}_{T, part}", kTH2F, {{40, -1., 1.}, pT}); + spectra.add("hJetPhi_resolution_RecoilJets", "#varphi resolution as a func. of jet #it{p}_{T, part}", kTH2F, {{40, -1., 1.}, pT}); + + spectra.add("hNumberMatchedJetsPerOneBaseJet", "# of taged jets per 1 base jet vs. jet pT", kTH2F, {{10, 0.5, 10.5}, {100, 0.0, 100.}}); + } + } + + // Fill histograms with raw or MC det. level data + template + void fillHistograms(Collision const& collision, Jets const& jets, Tracks const& tracks, bool bIsMC = false, float weight = 1.) + { + + bool bSigEv = false; + std::vector vPhiOfTT; + double phiTT = 0.; + int nTT = 0; + float pTHat = 0.; + if (bIsMC) + pTHat = getPtHat(weight); + + auto dice = rand->Rndm(); + if (dice < fracSig) + bSigEv = true; + + for (const auto& track : tracks) { + if (skipTrack(track)) + continue; + + if (bIsMC && (track.pt() > pTHatMaxTrack * pTHat)) + continue; + + spectra.fill(HIST("hTrackPtEtaPhi"), track.pt(), track.eta(), track.phi(), weight); + + // Search for TT candidate + if (bSigEv && (track.pt() > ptTTsigMin && track.pt() < ptTTsigMax)) { + vPhiOfTT.push_back(track.phi()); + spectra.fill(HIST("hTTSig_pT"), track.pt(), weight); + ++nTT; + } + + if (!bSigEv && (track.pt() > ptTTrefMin && track.pt() < ptTTrefMax)) { + vPhiOfTT.push_back(track.phi()); + ++nTT; + } + } + + if (nTT > 0) { // at least 1 TT + + phiTT = getPhiTT(vPhiOfTT); + + if (bSigEv) { + spectra.fill(HIST("hNtrig"), 1.5, weight); + spectra.fill(HIST("hTTSig_per_event"), nTT, weight); + } else { + spectra.fill(HIST("hNtrig"), 0.5, weight); + spectra.fill(HIST("hTTRef_per_event"), nTT, weight); + } + } + + for (const auto& jet : jets) { + + if (bIsMC && (jet.pt() > pTHatMax * pTHat)) + continue; + + spectra.fill(HIST("hJetPtEtaPhiRhoArea"), jet.pt(), jet.eta(), jet.phi(), collision.rho(), jet.area(), weight); + + if (nTT > 0) { + auto [dphi, bRecoilJet] = isRecoilJet(jet, phiTT); + + if (bSigEv) { + + spectra.fill(HIST("hDPhi_JetPt_Corr_TTSig"), dphi, jet.pt() - collision.rho() * jet.area(), weight); + spectra.fill(HIST("hDPhi_JetPt_TTSig"), dphi, jet.pt(), weight); + spectra.fill(HIST("hJetArea_JetPt_Rho_TTSig"), jet.area(), jet.pt(), collision.rho(), weight); + + if (bRecoilJet) { + spectra.fill(HIST("hRecoil_JetPt_Corr_TTSig"), jet.pt() - collision.rho() * jet.area(), weight); + spectra.fill(HIST("hRecoil_JetPt_TTSig"), jet.pt(), weight); + } + + } else { + spectra.fill(HIST("hDPhi_JetPt_Corr_TTRef"), dphi, jet.pt() - collision.rho() * jet.area(), weight); + spectra.fill(HIST("hDPhi_JetPt_TTRef"), dphi, jet.pt(), weight); + spectra.fill(HIST("hJetArea_JetPt_Rho_TTRef"), jet.area(), jet.pt(), collision.rho(), weight); + + if (bRecoilJet) { + spectra.fill(HIST("hRecoil_JetPt_Corr_TTRef"), jet.pt() - collision.rho() * jet.area(), weight); + spectra.fill(HIST("hRecoil_JetPt_TTRef"), jet.pt(), weight); + } + } + } + } + } + + template + void fillMCPHistograms(Collision const& collision, Jets const& jets, Particles const& particles, float weight = 1.) + { + bool bSigEv = false; + std::vector vPhiOfTT; + double phiTT = 0.; + int nTT = 0; + float pTHat = getPtHat(weight); + spectra.fill(HIST("ptHat"), pTHat, weight); + + auto dice = rand->Rndm(); + if (dice < fracSig) + bSigEv = true; + + for (const auto& particle : particles) { + auto pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (!pdgParticle) + continue; + + // Need charge and physical primary particles + bool bParticleNeutral = (static_cast(pdgParticle->Charge()) == 0); + if (bParticleNeutral || !particle.isPhysicalPrimary()) + continue; + + if (particle.pt() > pTHatMaxTrack * pTHat) + continue; + + spectra.fill(HIST("hPartPtEtaPhi"), particle.pt(), particle.eta(), particle.phi(), weight); + + if (bSigEv && (particle.pt() > ptTTsigMin && particle.pt() < ptTTsigMax)) { + vPhiOfTT.push_back(particle.phi()); + ++nTT; + } + + if (!bSigEv && (particle.pt() > ptTTrefMin && particle.pt() < ptTTrefMax)) { + vPhiOfTT.push_back(particle.phi()); + ++nTT; + } + } + + if (nTT > 0) { + + phiTT = getPhiTT(vPhiOfTT); + + if (bSigEv) { + spectra.fill(HIST("hNtrig_Part"), 1.5, weight); + spectra.fill(HIST("hTTSig_per_event_Part"), nTT, weight); + } else { + spectra.fill(HIST("hNtrig_Part"), 0.5, weight); + spectra.fill(HIST("hTTRef_per_event_Part"), nTT, weight); + } + } + + for (const auto& jet : jets) { + + if (jet.pt() > pTHatMax * pTHat) + continue; + + spectra.fill(HIST("hJetPtEtaPhiRhoArea_Part"), jet.pt(), jet.eta(), jet.phi(), collision.rho(), jet.area(), weight); + + if (nTT > 0) { + + auto [dphi, bRecoilJet] = isRecoilJet(jet, phiTT); + + if (bSigEv) { + + spectra.fill(HIST("hDPhi_JetPt_Corr_TTSig_Part"), dphi, jet.pt() - collision.rho() * jet.area(), weight); + spectra.fill(HIST("hDPhi_JetPt_TTSig_Part"), dphi, jet.pt(), weight); + spectra.fill(HIST("hJetArea_JetPt_Rho_TTSig_Part"), jet.area(), jet.pt(), collision.rho(), weight); + + if (bRecoilJet) { + spectra.fill(HIST("hRecoil_JetPt_Corr_TTSig_Part"), jet.pt() - collision.rho() * jet.area(), weight); + spectra.fill(HIST("hRecoil_JetPt_TTSig_Part"), jet.pt(), weight); + } + + } else { + + spectra.fill(HIST("hDPhi_JetPt_Corr_TTRef_Part"), dphi, jet.pt() - collision.rho() * jet.area(), weight); + spectra.fill(HIST("hDPhi_JetPt_TTRef_Part"), dphi, jet.pt(), weight); + spectra.fill(HIST("hJetArea_JetPt_Rho_TTRef_Part"), jet.area(), jet.pt(), collision.rho(), weight); + + if (bRecoilJet) { + spectra.fill(HIST("hRecoil_JetPt_Corr_TTRef_Part"), jet.pt() - collision.rho() * jet.area(), weight); + spectra.fill(HIST("hRecoil_JetPt_TTRef_Part"), jet.pt(), weight); + } + } + } + } + } + + template + void fillMatchedHistograms(TracksTable const& tracks, JetsBase const& jetsBase, JetsTag const& jetsTag, float weight = 1.) + { + std::vector vPhiOfTT; + double phiTTSig = 0.; + float pTHat = getPtHat(weight); + + for (const auto& track : tracks) { + if (skipTrack(track)) + continue; + + if (track.pt() > pTHatMaxTrack * pTHat) + continue; + + if (track.pt() > ptTTsigMin && track.pt() < ptTTsigMax) { + vPhiOfTT.push_back(track.phi()); + } + } + + bool bIsThereTTSig = vPhiOfTT.size() > 0; + + if (bIsThereTTSig) + phiTTSig = getPhiTT(vPhiOfTT); + + for (const auto& jetBase : jetsBase) { + if (jetBase.pt() > pTHatMax * pTHat) + continue; + + bool bIsBaseJetRecoil = get<1>(isRecoilJet(jetBase, phiTTSig)) && bIsThereTTSig; + dataForUnfolding(jetBase, jetsTag, bIsBaseJetRecoil, weight); + } + } + + void processData(FilteredColl const& collision, + FilteredTracks const& tracks, + FilteredJets const& jets) + { + if (skipEvent(collision)) + return; + + spectra.fill(HIST("vertexZ"), collision.posZ()); + fillHistograms(collision, jets, tracks); + } + PROCESS_SWITCH(RecoilJets, processData, "process data", true); + + void processMCDetLevel(FilteredColl const& collision, + FilteredTracks const& tracks, + FilteredJetsDetLevel const& jets) + { + if (skipEvent(collision) || skipMBGapEvent(collision)) + return; + + spectra.fill(HIST("vertexZ"), collision.posZ()); + fillHistograms(collision, jets, tracks, true); + } + PROCESS_SWITCH(RecoilJets, processMCDetLevel, "process MC detector level", false); + + void processMCDetLevelWeighted(FilteredCollDetLevelGetWeight const& collision, + aod::JetMcCollisions const&, + FilteredTracks const& tracks, + FilteredJetsDetLevel const& jets) + { + if (skipEvent(collision) || skipMBGapEvent(collision)) + return; + + auto weight = collision.mcCollision().weight(); + spectra.fill(HIST("vertexZ"), collision.posZ(), weight); + + if (collision.has_mcCollision()) { + spectra.fill(HIST("hHasAssocMcCollision"), 0.5, weight); + } else { + spectra.fill(HIST("hHasAssocMcCollision"), 1.5, weight); + } + + fillHistograms(collision, jets, tracks, true, weight); + } + PROCESS_SWITCH(RecoilJets, processMCDetLevelWeighted, "process MC detector level with event weight", false); + + void processMCPartLevel(FilteredCollPartLevel const& collision, + aod::JetParticles const& particles, + FilteredJetsPartLevel const& jets) + { + if (skipMBGapEvent(collision)) + return; + + spectra.fill(HIST("vertexZMC"), collision.posZ()); + fillMCPHistograms(collision, jets, particles); + } + PROCESS_SWITCH(RecoilJets, processMCPartLevel, "process MC particle level", false); + + void processMCPartLevelWeighted(FilteredCollPartLevel const& collision, + aod::JetParticles const& particles, + FilteredJetsPartLevel const& jets) + { + if (skipMBGapEvent(collision)) + return; + + auto weight = collision.weight(); + spectra.fill(HIST("vertexZMC"), collision.posZ(), weight); + fillMCPHistograms(collision, jets, particles, weight); + } + PROCESS_SWITCH(RecoilJets, processMCPartLevelWeighted, "process MC particle level with event weight", false); + + void processJetsMatched(FilteredCollDetLevelGetWeight const& collision, + aod::JetMcCollisions const&, + FilteredTracks const& tracks, + FilteredMatchedJetsDetLevel const& mcdjets, + FilteredMatchedJetsPartLevel const& mcpjets) + { + if (skipEvent(collision) || skipMBGapEvent(collision)) + return; + + auto mcpjetsPerMCCollision = mcpjets.sliceBy(partJetsPerCollision, collision.mcCollisionId()); + + if (bGetMissJets) { + fillMatchedHistograms(tracks, mcpjetsPerMCCollision, mcdjets); + } else { + fillMatchedHistograms(tracks, mcdjets, mcpjetsPerMCCollision); + } + } + PROCESS_SWITCH(RecoilJets, processJetsMatched, "process matching of MC jets (no weight)", false); + + void processJetsMatchedWeighted(FilteredCollDetLevelGetWeight const& collision, + aod::JetMcCollisions const&, + FilteredTracks const& tracks, + FilteredMatchedJetsDetLevel const& mcdjets, + FilteredMatchedJetsPartLevel const& mcpjets) + { + if (skipEvent(collision) || skipMBGapEvent(collision)) + return; + + auto mcpjetsPerMCCollision = mcpjets.sliceBy(partJetsPerCollision, collision.mcCollisionId()); + auto weight = collision.mcCollision().weight(); + + if (bGetMissJets) { + fillMatchedHistograms(tracks, mcpjetsPerMCCollision, mcdjets, weight); + } else { + fillMatchedHistograms(tracks, mcdjets, mcpjetsPerMCCollision, weight); + } + } + PROCESS_SWITCH(RecoilJets, processJetsMatchedWeighted, "process matching of MC jets (weighted)", false); + + //------------------------------------------------------------------------------ + // Auxiliary functions + template + bool skipEvent(const Collision& coll) + { + /// \brief: trigger cut is needed for pp data + return !jetderiveddatautilities::selectCollision(coll, eventSelectionBits) || !jetderiveddatautilities::selectTrigger(coll, triggerMaskBits); + } + + template + bool skipMBGapEvent(const Collision& coll) + { + return (skipMBGapEvents && coll.subGeneratorId()) == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap; + } + + template + bool skipTrack(const Track& track) + { + return !jetderiveddatautilities::selectTrack(track, trackSelection); + } + + template + std::tuple isRecoilJet(const Jet& jet, + double phiTT) + { + double dphi = std::fabs(RecoDecay::constrainAngle(jet.phi() - phiTT, -constants::math::PI)); + return {dphi, (constants::math::PI - recoilRegion) < dphi}; + } + + double getPhiTT(const std::vector& vPhiOfTT) + { + auto iTrig = rand->Integer(vPhiOfTT.size()); + return vPhiOfTT[iTrig]; + } + + float getPtHat(float weight) + { + return 10. / (std::pow(weight, 1.0 / pTHatExponent)); + } + + template + void dataForUnfolding(JetBase const& jetBase, JetsTag const&, bool bIsBaseJetRecoil, float weight = 1.0) + { + + bool bIsThereMatchedJet = jetBase.has_matchedJetGeo(); + if (bIsThereMatchedJet) { + const auto& jetsMatched = jetBase.template matchedJetGeo_as>(); + + for (const auto& jetMatched : jetsMatched) { + spectra.fill(HIST("hNumberMatchedJetsPerOneBaseJet"), jetsMatched.size(), jetMatched.pt(), weight); + + if (bGetMissJets) { + // Mean that base jet is particle level jet + spectra.fill(HIST("hJetPt_DetLevel_vs_PartLevel"), jetMatched.pt(), jetBase.pt(), weight); + spectra.fill(HIST("hJetPt_resolution"), (jetBase.pt() - jetMatched.pt()) / jetBase.pt(), jetBase.pt(), weight); + spectra.fill(HIST("hJetPhi_resolution"), jetBase.phi() - jetMatched.phi(), jetBase.pt(), weight); + + if (bIsBaseJetRecoil) { + spectra.fill(HIST("hJetPt_DetLevel_vs_PartLevel_RecoilJets"), jetMatched.pt(), jetBase.pt(), weight); + spectra.fill(HIST("hJetPt_resolution_RecoilJets"), (jetBase.pt() - jetMatched.pt()) / jetBase.pt(), jetBase.pt(), weight); + spectra.fill(HIST("hJetPhi_resolution_RecoilJets"), jetBase.phi() - jetMatched.phi(), jetBase.pt(), weight); + } + } else { + // Mean that base jet is detector level jet + spectra.fill(HIST("hJetPt_DetLevel_vs_PartLevel"), jetBase.pt(), jetMatched.pt(), weight); + spectra.fill(HIST("hJetPt_resolution"), (jetMatched.pt() - jetBase.pt()) / jetMatched.pt(), jetMatched.pt(), weight); + spectra.fill(HIST("hJetPhi_resolution"), jetMatched.phi() - jetBase.phi(), jetMatched.phi(), weight); + + if (bIsBaseJetRecoil) { + spectra.fill(HIST("hJetPt_DetLevel_vs_PartLevel_RecoilJets"), jetBase.pt(), jetMatched.pt(), weight); + spectra.fill(HIST("hJetPt_resolution_RecoilJets"), (jetMatched.pt() - jetBase.pt()) / jetMatched.pt(), jetMatched.pt(), weight); + spectra.fill(HIST("hJetPhi_resolution_RecoilJets"), jetMatched.phi() - jetBase.phi(), jetMatched.phi(), weight); + } + } + } + } else { + // No closest jet + if (bGetMissJets) { + spectra.fill(HIST("hMissedJets_pT"), jetBase.pt(), weight); + if (bIsBaseJetRecoil) + spectra.fill(HIST("hMissedJets_pT_RecoilJets"), jetBase.pt(), weight); + } else { + spectra.fill(HIST("hFakeJets_pT"), jetBase.pt(), weight); + if (bIsBaseJetRecoil) + spectra.fill(HIST("hFakeJets_pT_RecoilJets"), jetBase.pt(), weight); + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGJE/Tasks/statPromptPhoton.cxx b/PWGJE/Tasks/statPromptPhoton.cxx new file mode 100644 index 00000000000..62d9bf72b97 --- /dev/null +++ b/PWGJE/Tasks/statPromptPhoton.cxx @@ -0,0 +1,1404 @@ +// 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 statPromptPhoton.cxx +/// \brief Reconstruction of Phi yield through track-track Minv correlations for resonance hadrochemistry analysis. +/// +/// +/// \author Adrian Fereydon Nassirpour +#include + +#include +#include +#include +#include + +#include +#include + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "CommonConstants/PhysicsConstants.h" + +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "EMCALBase/Geometry.h" +#include "EMCALCalib/BadChannelMap.h" + +#include "DataFormatsEMCAL/Cell.h" +#include "DataFormatsEMCAL/Constants.h" +#include "DataFormatsEMCAL/AnalysisCluster.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" + +#include "DetectorsBase/Propagator.h" + +#include "CommonDataFormat/InteractionRecord.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct statPromptPhoton { + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Configurable cfgMaxDCArToPVcut{"cfgMaxDCArToPVcut", 0.5, "Track DCAr cut to PV Maximum"}; + Configurable cfgMaxDCAzToPVcut{"cfgMaxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; + Configurable cfgConnectedToPV{"cfgConnectedToPV", true, "PV contributor track selection"}; + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; + Configurable cfgnFindableTPCClusters{"cfgnFindableTPCClusters", 50, "nFindable TPC Clusters"}; + Configurable cfgnTPCCrossedRows{"cfgnTPCCrossedRows", 70, "nCrossed TPC Rows"}; + Configurable cfgnRowsOverFindable{"cfgnRowsOverFindable", 1.2, "nRowsOverFindable TPC CLusters"}; + Configurable cfgnTPCChi2{"cfgnTPChi2", 4.0, "nTPC Chi2 per Cluster"}; + Configurable cfgnITSChi2{"cfgnITShi2", 36.0, "nITS Chi2 per Cluster"}; + Configurable cfgClusterDefinition{"clusterDefinition", 10, "cluster definition to be selected, e.g. 10=kV3Default, 0 = kV1Default"}; + Configurable cfgMinTime{"MinTime", -30., "Minimum cluster time for time cut"}; + Configurable cfgMaxTime{"MaxTime", +35., "Maximum cluster time for time cut"}; + Configurable cfgMinClusterEnergy{"MinClusterEnergy", 0.7f, "Minimal cluster energy"}; + Configurable cfgMinNCells{"MinNCelss", 2, "Minimal amount of cells per cluster"}; + Configurable cfgMaxNLM{"MaxNLM", 2, "Maximal amount of local Maxima per cluster"}; + Configurable cfgExoticContribution{"ExoticContribution", false, "Exotic cluster in the data"}; + Configurable cfgtrkMinPt{"cfgtrkMinPt", 0.15, "set track min pT"}; + Configurable cfgtrkMaxEta{"cfgtrkMaxEta", 0.6, "set track max Eta"}; + Configurable cfgMinR{"MinR", 0.1, "Min. Radii of Delta R cone around photon trigger"}; + Configurable cfgMaxR{"MaxR", 0.4, "Max. Radii of Delta R cone around photon trigger"}; + Configurable cfgMinTrig{"MinTrig", 1, "Min. Trigger energy/momentum"}; + Configurable cfgMaxTrig{"MaxTrig", 5, "Max. Trigger energy/momentum"}; + Configurable cfgVtxCut{"cfgVtxCut", 10.0, "V_z cut selection"}; + Configurable cfgLowM02{"cfgLowM02", 0.1, "Lower-bound M02 cut"}; + Configurable cfgHighM02{"cfgHighM02", 0.3, "Higher-bound M02 cut"}; + Configurable cfgLowClusterE{"cfgLowClusterE", 0.5, "Higher-bound Cluster E cut"}; + Configurable cfgHighClusterE{"cfgHighClusterE", 500, "Lower-bound Cluster E cut"}; + Configurable cfgEmcTrigger{"cfgEmcTrigger", true, "Require EMC readout for event"}; + Configurable cfgGeoCut{"cfgGeoCut", true, "Performs Geometric TPC cut"}; + Configurable cfgPtClusterCut{"cfgPtClusterCut", true, "Performs Pt-dependent cluster-track matching"}; + Configurable cfgTrackFilter{"cfgTrackFilter", "globalTracks", "set track selections"}; + Configurable cfgJETracks{"cfgJETracks", false, "Enables running on derived JE data"}; + Configurable cfgGenHistograms{"cfgGenHistograms", false, "Enables Generated histograms"}; + Configurable cfgRecHistograms{"cfgRecHistograms", false, "Enables Reconstructed histograms"}; + Configurable cfgDataHistograms{"cfgDataHistograms", false, "Enables Data histograms"}; + Configurable cfgDebug{"cfgDebug", false, "Enables debug information for local running"}; + int trackFilter = -1; + + // INIT + void init(InitContext const&) + { + std::vector ptBinning = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0, 8.0, 12.0, 16.0, 20.0, 25.0, 30.0, 40.0, 50.0, 75.0, 100.0, 150.0, 200.0, 300.0, 500.0}; + AxisSpec pthadAxis = {ptBinning, "#it{p}_{T}^{had sum} [GeV/c]"}; + + if (cfgJETracks) { + trackFilter = jetderiveddatautilities::initialiseTrackSelection(static_cast(cfgTrackFilter)); + } + + if (cfgRecHistograms) { + histos.add("REC_nEvents", "REC_nEvents", kTH1F, {{4, 0.0, 4.0}}); + histos.add("REC_Cluster_QA", "REC_Cluster_QA", kTH1F, {{10, -0.5, 9.5}}); + histos.add("REC_PtHadSum_Photon", "REC_PtHadSum_Photon", kTH1F, {pthadAxis}); + histos.add("REC_TrackPhi_photontrigger", "REC_TrackPhi_photontrigger", kTH1F, {{64, 0, 2 * TMath::Pi()}}); + histos.add("REC_TrackEta_photontrigger", "REC_TrackEta_photontrigger", kTH1F, {{100, -1, 1}}); + histos.add("REC_ClusterPhi", "REC_ClusterPhi", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("REC_ClusterEta", "REC_ClusterEta", kTH1F, {{100, -1, 1}}); + histos.add("REC_Track_Pt", "REC_Track_Pt", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_Track_Phi", "REC_Track_Phi", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("REC_Track_PhiPrime_Pt", "REC_Track_PhiPrime_Pt", kTH2F, {{640, 0, 2 * TMath::Pi()}, {82, -1.0, 40.0}}); + histos.add("REC_Cluster_PhiPrime_Pt", "REC_Cluster_PhiPrime_Pt", kTH2F, {{640, 0, 2 * TMath::Pi()}, {82, -1.0, 40.0}}); + histos.add("REC_Cluster_PhiPrime_Pt_AC", "REC_Cluster_PhiPrime_Pt_AC", kTH2F, {{640, 0, 2 * TMath::Pi()}, {82, -1.0, 40.0}}); + histos.add("REC_Cluster_PhiPrime_Pt_C", "REC_Cluster_PhiPrime_Pt_C", kTH2F, {{640, 0, 2 * TMath::Pi()}, {82, -1.0, 40.0}}); + histos.add("REC_Cluster_Particle_Pt", "REC_Cluster_Particle_Pt", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_Cluster_ParticleWITHtrack_Pt", "REC_Cluster_ParticleWITHtrack_Pt", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_Cluster_ParticleWITHtrack_Phi", "REC_Cluster_ParticleWITHtrack_Phi", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Cluster_ParticleWITHtrack_Eta", "REC_Cluster_ParticleWITHtrack_Eta", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Cluster_ParticleWITHtrack_TrackPt", "REC_Cluster_ParticleWITHtrack_TrackPt", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_Cluster_ParticleWITHtrack_Pt_Phi", "REC_Cluster_ParticleWITHtrack_Pt_Phi", kTH2F, {{82, -1.0, 40.0}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Cluster_ParticleWITHtrack_Pt_PhiPrime", "REC_Cluster_ParticleWITHtrack_Pt_PhiPrime", kTH2F, {{82, -1.0, 40.0}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Impurity_ParticleWITHtrack_Pt_PhiPrime", "REC_Impurity_ParticleWITHtrack_Pt_PhiPrime", kTH2F, {{82, -1.0, 40.0}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Cluster_ParticleWITHtrack_Pt_Eta", "REC_Cluster_ParticleWITHtrack_Pt_Eta", kTH2F, {{82, -1.0, 40.0}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Cluster_ParticleWITHOUTtrack_Pt", "REC_Cluster_ParticleWITHOUTtrack_Pt", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_Cluster_ParticleWITHOUTtrack_Phi", "REC_Cluster_ParticleWITHOUTtrack_Phi", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Cluster_ParticleWITHOUTtrack_Eta", "REC_Cluster_ParticleWITHOUTtrack_Eta", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Cluster_ParticleWITHOUTtrack_Pt_Phi", "REC_Cluster_ParticleWITHOUTtrack_Pt_Phi", kTH2F, {{82, -1.0, 40.0}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Cluster_ParticleWITHOUTtrack_Pt_PhiPrime", "REC_Cluster_ParticleWITHOUTtrack_Pt_PhiPrime", kTH2F, {{82, -1.0, 40.0}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Cluster_ParticleWITHOUTtrack_Pt_Eta", "REC_Cluster_ParticleWITHOUTtrack_Pt_Eta", kTH2F, {{82, -1.0, 40.0}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Impurity_ParticleWITHOUTtrack_Pt_PhiPrime", "REC_Impurity_ParticleWITHOUTtrack_Pt_PhiPrime", kTH2F, {{82, -1.0, 40.0}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_TrackPt_ClusterE", "REC_TrackPt_ClusterE", kTH2F, {{82, -1.0, 40.0}, {82, -1.0, 40.0}}); + histos.add("REC_ParticlePt_ClusterE", "REC_ParticlePt_ClusterE", kTH2F, {{82, -1.0, 40.0}, {82, -1.0, 40.0}}); + histos.add("REC_TrackPt_Phi_Eta", "REC_TrackPt_Phi_Eta", kTH2F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_ParticlePt_Phi_Eta", "REC_ParticlePt_Phi_Eta", kTH2F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_True_v_Cluster_Phi", "REC_True_v_Cluster_Phi", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_True_v_Cluster_Eta", "REC_True_v_Cluster_Eta", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_TrueImpurity_v_Cluster_Phi", "REC_TrueImpurity_v_Cluster_Phi", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_TrueImpurity_v_Cluster_Eta", "REC_TrueImpurity_v_Cluster_Eta", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_TrueImpurity_v_Cluster_PhiAbs", "REC_TrueImpurity_v_Cluster_PhiAbs", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_TrueImpurity_v_Cluster_EtaAbs", "REC_TrueImpurity_v_Cluster_EtaAbs", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_TrueImpurity_v_Cluster_Phi_Eta", "REC_TrueImpurity_v_Cluster_Phi_Eta", kTH2F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Track_v_Cluster_Phi", "REC_Track_v_Cluster_Phi", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Track_v_Cluster_Eta", "REC_Track_v_Cluster_Eta", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Track_v_Cluster_Phi_Pt", "REC_Track_v_Cluster_Phi_Pt", kTH2F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}, {82, -1.0, 40.0}}); + histos.add("REC_Track_v_Cluster_Eta_Pt", "REC_Track_v_Cluster_Eta_Pt", kTH2F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}, {82, -1.0, 40.0}}); + histos.add("REC_Track_v_Cluster_Phi_Eta", "REC_Track_v_Cluster_Phi_Eta", kTH2F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Track_v_Cluster_Phi_AC", "REC_Track_v_Cluster_Phi_AC", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Track_v_Cluster_Eta_AC", "REC_Track_v_Cluster_Eta_AC", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Track_v_Cluster_Phi_Eta_AC", "REC_Track_v_Cluster_Phi_Eta_AC", kTH2F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Track_v_Cluster_Phi_C", "REC_Track_v_Cluster_Phi_C", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Track_v_Cluster_Eta_C", "REC_Track_v_Cluster_Eta_C", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Track_v_Cluster_Phi_Eta_C", "REC_Track_v_Cluster_Phi_Eta_C", kTH2F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_SumPt_BC", "REC_SumPt_BC", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_SumPt_AC", "REC_SumPt_AC", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_M02_BC", "REC_M02_BC", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_M02_AC", "REC_M02_AC", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Trigger_Purity", "REC_Trigger_Purity", kTH1F, {{4, 0.0, 4.0}}); + histos.add("REC_Trigger_Energy", "REC_Trigger_Energy", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_Trigger_Purity_v_Energy", "REC_Trigger_Purity_v_Energy", kTH2F, {{4, 0.0, 4.0}, {82, -1.0, 40.0}}); + histos.add("REC_Trigger_Energy_GOOD", "REC_Trigger_Energy_GOOD", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_Trigger_Energy_MISS", "REC_Trigger_Energy_MISS", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_Trigger_Energy_FAKE", "REC_Trigger_Energy_FAKE", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_All_Energy", "REC_All_Energy", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_Impurity_Energy", "REC_Impurity_Energy", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_Impurity_Energy_v_Cluster_Phi", "REC_Impurity_Energy_v_Cluster_Phi", kTH2F, {{82, -1.0, 40.0}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Impurity_Energy_v_ClusterE_Phi", "REC_Impurity_Energy_v_ClusterE_Phi", kTH2F, {{82, -1.0, 40.0}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Impurity_Energy_v_ClusterEoP_Phi", "REC_Impurity_Energy_v_ClusterEoP_Phi", kTH2F, {{82, -1.0, 40.0}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("REC_Impurity_Energy_v_Cluster_Energy", "REC_Impurity_Energy_v_Cluster_Energy", kTH2F, {{82, -1.0, 40.0}, {82, -1.0, 40.0}}); + histos.add("REC_True_Trigger_Energy", "REC_True_Trigger_Energy", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_True_Prompt_Trigger_Energy", "REC_True_Prompt_Trigger_Energy", kTH1F, {{82, -1.0, 40.0}}); + histos.add("REC_Trigger_V_PtHadSum_Stern", "REC_Trigger_V_PtHadSum_Stern", kTH2F, {{100, 0, 100}, pthadAxis}); + histos.add("REC_Trigger_V_PtHadSum_Nch", "REC_Trigger_V_PtHadSum_Nch", kTH2F, {{100, 0, 100}, pthadAxis}); + histos.add("REC_Trigger_V_PtHadSum_Photon", "REC_Trigger_V_PtHadSum_Photon", kTH2F, {{100, 0, 100}, pthadAxis}); + histos.add("REC_TrueTrigger_V_PtHadSum_Photon", "REC_Trigger_V_PtHadSum_Photon", kTH2F, {{100, 0, 100}, pthadAxis}); + histos.add("REC_dR_Photon", "REC_dR_Photon", kTH1F, {{628, 0.0, 2 * TMath::Pi()}}); + histos.add("REC_dR_Stern", "REC_dR_Stern", kTH1F, {{628, 0.0, 2 * TMath::Pi()}}); + } + if (cfgGenHistograms) { + histos.add("GEN_nEvents", "GEN_nEvents", kTH1F, {{4, 0.0, 4.0}}); + histos.add("GEN_True_Trigger_Energy", "GEN_True_Trigger_Energy", kTH1F, {{82, -1.0, 40.0}}); + histos.add("GEN_Particle_Pt", "GEN_Particle_Pt", kTH1F, {{82, -1.0, 40.0}}); + histos.add("GEN_True_Photon_Energy", "GEN_True_Photon_Energy", kTH1F, {{8200, -1.0, 40.0}}); + histos.add("GEN_True_Prompt_Photon_Energy", "GEN_True_Prompt_Photon_Energy", kTH1F, {{8200, -1.0, 40.0}}); + histos.add("GEN_Trigger_V_PtHadSum_Stern", "GEN_Trigger_V_PtHadSum_Stern", kTH2F, {{100, 0, 100}, pthadAxis}); + histos.add("GEN_Trigger_V_PtHadSum_Photon", "GEN_Trigger_V_PtHadSum_Photon", kTH2F, {{100, 0, 100}, pthadAxis}); + histos.add("GEN_TrueTrigger_V_PtHadSum_Photon", "GEN_Trigger_V_PtHadSum_Photon", kTH2F, {{100, 0, 100}, pthadAxis}); + histos.add("GEN_dR_Photon", "GEN_dR_Photon", kTH1F, {{628, 0.0, 2 * TMath::Pi()}}); + histos.add("GEN_dR_Stern", "GEN_dR_Stern", kTH1F, {{628, 0.0, 2 * TMath::Pi()}}); + } + if (cfgDataHistograms) { + histos.add("DATA_nEvents", "DATA_nEvents", kTH1F, {{4, 0.0, 4.0}}); + histos.add("DATA_M02_BC", "DATA_M02_BC", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("DATA_M02_AC", "DATA_M02_AC", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("DATA_Cluster_QA", "DATA_Cluster_QA", kTH1F, {{10, -0.5, 9.5}}); + histos.add("DATA_ClusterPhi", "DATA_ClusterPhi", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("DATA_ClusterEta", "DATA_ClusterEta", kTH1F, {{100, -1, 1}}); + histos.add("DATA_All_Energy", "DATA_All_Energy", kTH1F, {{82, -1.0, 40.0}}); + histos.add("DATA_Cluster_PhiPrime_Pt", "DATA_Cluster_PhiPrime_Pt", kTH2F, {{640, 0, 2 * TMath::Pi()}, {82, -1.0, 40.0}}); + histos.add("DATA_Cluster_PhiPrime_Pt_AC", "DATA_Cluster_PhiPrime_Pt_AC", kTH2F, {{640, 0, 2 * TMath::Pi()}, {82, -1.0, 40.0}}); + histos.add("DATA_Cluster_PhiPrime_Pt_C", "DATA_Cluster_PhiPrime_Pt_C", kTH2F, {{640, 0, 2 * TMath::Pi()}, {82, -1.0, 40.0}}); + histos.add("DATA_Track_v_Cluster_Phi", "DATA_Track_v_Cluster_Phi", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("DATA_Track_v_Cluster_Eta", "DATA_Track_v_Cluster_Eta", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("DATA_Track_v_Cluster_Phi_Pt", "DATA_Track_v_Cluster_Phi_Pt", kTH2F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}, {82, -1.0, 40.0}}); + histos.add("DATA_Track_v_Cluster_Phi_Eta", "DATA_Track_v_Cluster_Phi_Eta", kTH2F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}, {628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("DATA_SumPt_BC", "DATA_SumPt_BC", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("DATA_SumPt_AC", "DATA_SumPt_AC", kTH1F, {{628, -2 * TMath::Pi(), 2 * TMath::Pi()}}); + histos.add("DATA_Trigger_V_PtHadSum_Photon", "DATA_Trigger_V_PtHadSum_Photon", kTH2F, {{100, 0, 100}, pthadAxis}); + histos.add("DATA_PtHadSum_Photon", "DATA_PtHadSum_Photon", kTH1F, {pthadAxis}); + histos.add("DATA_Trigger_Energy", "DATA_Trigger_Energy", kTH1F, {{82, -1.0, 40.0}}); + histos.add("DATA_Track_PhiPrime_Pt", "DATA_Track_PhiPrime_Pt", kTH2F, {{640, 0, 2 * TMath::Pi()}, {82, -1.0, 40.0}}); + histos.add("DATA_Track_Pt", "DATA_Track_Pt", kTH1F, {{82, -1.0, 40.0}}); + histos.add("DATA_Track_Phi", "DATA_Track_Phi", kTH1F, {{640 * 2, 0, 2 * TMath::Pi()}}); + histos.add("DATA_TrackPhi_photontrigger", "DATA_TrackPhi_photontrigger", kTH1F, {{64, 0, 2 * TMath::Pi()}}); + histos.add("DATA_TrackEta_photontrigger", "DATA_TrackEta_photontrigger", kTH1F, {{100, -1, 1}}); + histos.add("DATA_Trigger_V_PtHadSum_Stern", "DATA_Trigger_V_PtHadSum_Stern", kTH2F, {{100, 0, 100}, pthadAxis}); + histos.add("DATA_Trigger_V_PtHadSum_Nch", "DATA_Trigger_V_PtHadSum_Nch", kTH2F, {{100, 0, 100}, pthadAxis}); + histos.add("DATA_dR_Photon", "DATA_dR_Photon", kTH1F, {{628, 0.0, 2 * TMath::Pi()}}); + histos.add("DATA_dR_Stern", "DATA_dR_Stern", kTH1F, {{628, 0.0, 2 * TMath::Pi()}}); + } + } // end of init + + Filter PosZFilter_JE = nabs(aod::jcollision::posZ) < cfgVtxCut; + Filter mcPosZFilter = nabs(aod::jmccollision::posZ) < cfgVtxCut; + Filter clusterDefinitionSelection_JE = (o2::aod::jcluster::definition == cfgClusterDefinition) && (o2::aod::jcluster::time >= cfgMinTime) && (o2::aod::jcluster::time <= cfgMaxTime) && (o2::aod::jcluster::energy > cfgMinClusterEnergy) && (o2::aod::jcluster::nCells >= cfgMinNCells) && (o2::aod::jcluster::nlm <= cfgMaxNLM) && (o2::aod::jcluster::isExotic == cfgExoticContribution); + + using selectedMCCollisions = aod::JMcCollisions; + using filteredMCCollisions = soa::Filtered; + using TrackCandidates = soa::Join; + using BcCandidates = soa::Join; + + using jTrackCandidates = soa::Join; + using jEMCtracks = aod::JEMCTracks; + + using jDataTrackCandidates = soa::Join; + + using jMCClusters = o2::soa::Join; + using jClusters = o2::soa::Join; + using jselectedCollisions = soa::Join; + using jfilteredCollisions = soa::Filtered; + using jfilteredMCClusters = soa::Filtered; + using jfilteredClusters = soa::Filtered; + + Preslice perClusterMatchedTracks = o2::aod::emcalclustercell::emcalclusterId; + + // Helper functions + ///////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////// + template + + double GetPtHadSum(const Tracks& tracks, const Trigger& trigger, double MinR, double MaxR, bool IsStern, bool IsParticle, bool DodR) + { + double eta_trigger, phi_trigger; + if constexpr (requires { trigger.eta(); }) { + eta_trigger = trigger.eta(); + phi_trigger = trigger.phi(); + } else if constexpr (requires { trigger.Eta(); }) { + eta_trigger = trigger.Eta(); + phi_trigger = trigger.Phi(); + } + double pthadsum = 0; + + for (auto& track : tracks) { + double phi_track = track.phi(); + double eta_track = track.eta(); + double pt_track = track.pt(); + + if (!IsParticle) { + if constexpr (requires { track.trackId(); }) { + if (cfgJETracks) { + if (!jetderiveddatautilities::selectTrack(track, trackFilter)) { + continue; + } + } else { + auto originaltrack = track.template track_as>(); + if (!trackSelection(originaltrack)) { + continue; + } + } // reject track + } else if constexpr (requires { track.sign(); }) { // checking for JTrack + if (cfgJETracks) { + if (!jetderiveddatautilities::selectTrack(track, trackFilter)) { + continue; + } + } else { + if (!trackSelection(track)) { + continue; + } + } // reject track + } // done checking for JTrack + } else { + if constexpr (requires { track.isPhysicalPrimary(); }) { + if (track.pt() < 0.15) { + continue; + } + if (std::abs(track.eta()) > cfgtrkMaxEta) { + continue; + } + if (track.getGenStatusCode() < 20) { + continue; + } + if (!track.isPhysicalPrimary()) { + continue; + } + int pdg = std::abs(track.pdgCode()); + if (pdg != 211 && pdg != 321 && pdg != 2212) { + continue; + } + } + } + if (IsStern || IsParticle) { + if constexpr (requires { trigger.globalIndex(); }) { + if (trigger.globalIndex() == track.globalIndex()) + continue; + } + } + double phidiff = TVector2::Phi_mpi_pi(phi_track - phi_trigger); + double etadiff = std::abs(eta_track - eta_trigger); + double dR = TMath::Sqrt((etadiff * etadiff) + (phidiff * phidiff)); + + if (DodR) { + if (dR > MinR && dR < MaxR) { + if (!IsParticle) { + if (cfgRecHistograms) { + if (IsStern) { + histos.fill(HIST("REC_dR_Stern"), dR); + } + if (!IsStern) { + histos.fill(HIST("REC_dR_Photon"), dR); + } + } else if (cfgDataHistograms) { + if (IsStern) { + histos.fill(HIST("DATA_dR_Stern"), dR); + } + if (!IsStern) { + histos.fill(HIST("DATA_dR_Photon"), dR); + } + } + } else { + if (IsStern) { + histos.fill(HIST("GEN_dR_Stern"), dR); + } + if (!IsStern) { + histos.fill(HIST("GEN_dR_Photon"), dR); + } + } + } + } + if (dR > MinR && dR < MaxR) { + pthadsum += pt_track; + } + + } // end of track loop + return pthadsum; + } // end of GetPtHadSum + ///////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////// + template + bool trackSelection(const TrackType track) + { + // basic track cuts + if (track.pt() < cfgtrkMinPt) + return false; + + if (std::abs(track.eta()) > cfgtrkMaxEta) + return false; + + if (std::abs(track.dcaXY()) > cfgMaxDCArToPVcut) + return false; + + if (std::abs(track.dcaZ()) > cfgMaxDCAzToPVcut) + return false; + + if (cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + + if (track.tpcNClsFindable() < cfgnFindableTPCClusters) + return false; + + if (track.tpcNClsCrossedRows() < cfgnTPCCrossedRows) + return false; + + if (track.tpcCrossedRowsOverFindableCls() > cfgnRowsOverFindable) + return false; + + if (track.tpcChi2NCl() > cfgnTPCChi2) + return false; + + if (track.itsChi2NCl() > cfgnITSChi2) + return false; + + if (cfgConnectedToPV && !track.isPVContributor()) + return false; + + return true; + }; // end of track selection + ///////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////// + // PROCESS + ///////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////// + int nEventsGenMC = 0; + + // void processMCGen(filteredMCCollisions::iterator const& collision, soa::SmallGroups> const& recocolls, aod::McParticles const& mcParticles, filteredMCClusters const&) + void processMCGen(filteredMCCollisions::iterator const& collision, soa::SmallGroups> const& recocolls, aod::JMcParticles const& mcParticles, jfilteredMCClusters const&) + { + nEventsGenMC++; + if (cfgDebug) { + if ((nEventsGenMC + 1) % 10000 == 0) { + std::cout << "Processed Gen MC Events: " << nEventsGenMC << std::endl; + } + } + histos.fill(HIST("GEN_nEvents"), 0.5); + if (fabs(collision.posZ()) > cfgVtxCut) + return; + + if (recocolls.size() <= 0) // not reconstructed + return; + for (auto& recocoll : recocolls) { // poorly reconstructed + if (!recocoll.sel8()) + return; + if (fabs(recocoll.posZ()) > cfgVtxCut) + + return; + histos.fill(HIST("GEN_nEvents"), 1.5); + + if (cfgEmcTrigger) { + if (!recocoll.isEmcalReadout()) + return; + } + histos.fill(HIST("GEN_nEvents"), 2.5); + } + + for (auto& mcPhoton : mcParticles) { + bool photontrigger = false; + if (mcPhoton.pt() < 0.15) + continue; + if (std::abs(mcPhoton.eta()) > cfgtrkMaxEta) + continue; + double pdgcode = fabs(mcPhoton.pdgCode()); + if (mcPhoton.isPhysicalPrimary()) { + if (pdgcode == 211 || pdgcode == 321 || pdgcode == 2212 || pdgcode == 11) { + histos.fill(HIST("GEN_Particle_Pt"), mcPhoton.pt()); + } + } + if (mcPhoton.getGenStatusCode() < 20) + continue; + + // first we check for pthadsums for all charged particles a la sternheimer + if (mcPhoton.isPhysicalPrimary()) { + int pdg = std::abs(mcPhoton.pdgCode()); + if (pdg == 211 || pdg == 321 || pdg == 2212) { + bool sterntrigger = false; + double sternPt = 0.0; + if (mcPhoton.pt() > cfgMinTrig && mcPhoton.pt() < cfgMaxTrig) { + if (fabs(mcPhoton.eta()) <= cfgtrkMaxEta) { + sterntrigger = true; + sternPt = mcPhoton.pt(); + } + } + // stern trigger + if (sterntrigger) { + bool doStern = true; + double sterncount = 1.0; + while (doStern) { + TLorentzVector lParticleTrigger; + lParticleTrigger.SetPxPyPzE(mcPhoton.px(), mcPhoton.py(), mcPhoton.pz(), mcPhoton.e()); + double pthadsum = GetPtHadSum(mcParticles, lParticleTrigger, cfgMinR, cfgMaxR, true, true, true); + histos.fill(HIST("GEN_Trigger_V_PtHadSum_Stern"), sterncount, pthadsum, 2.0 / sternPt); + if (sterncount < sternPt) { + sterncount++; + } else { + doStern = false; + } + } // While sternin' + } // stern trigger loop + } // check if charged pikp + } // check for primary particles + + // now we do all photons + if (mcPhoton.pdgCode() == 22) { + histos.fill(HIST("GEN_True_Photon_Energy"), mcPhoton.e()); + if (mcPhoton.pt() > cfgMinTrig && mcPhoton.pt() < cfgMaxTrig) { + if (fabs(mcPhoton.eta()) <= cfgtrkMaxEta) { + photontrigger = true; + } + } // check for photon trigger + if (photontrigger) { + TLorentzVector lRealPhoton; + lRealPhoton.SetPxPyPzE(mcPhoton.px(), mcPhoton.py(), mcPhoton.pz(), mcPhoton.e()); + double truepthadsum = GetPtHadSum(mcParticles, lRealPhoton, cfgMinR, cfgMaxR, false, true, false); + histos.fill(HIST("GEN_Trigger_V_PtHadSum_Photon"), mcPhoton.e(), truepthadsum); + } + + // now we do all PROMPT photons + histos.fill(HIST("GEN_True_Trigger_Energy"), mcPhoton.e()); + + int mompdg1 = 0; + int momindex1 = 0; + int momstatus1 = 0; + for (auto& photon_mom : mcPhoton.mothers_as()) { + if (mompdg1 == 0) { + mompdg1 = photon_mom.pdgCode(); + momindex1 = photon_mom.globalIndex(); + momstatus1 = photon_mom.getGenStatusCode(); + } + } // first photon loop + + if (std::fabs(mompdg1) < 40 && std::fabs(mompdg1) > 0) { + int mompdg2 = 0; + int momindex2 = 0; + int momstatus2 = 0; + int mompdg3 = 0; + int momindex3 = 0; + int momstatus3 = 0; + for (auto& mcPhoton_mom : mcParticles) { + if (mcPhoton_mom.globalIndex() == momindex1) { + for (auto& photon_momom : mcPhoton_mom.mothers_as()) { + if (mompdg2 == 0) { + mompdg2 = photon_momom.pdgCode(); + momindex2 = photon_momom.globalIndex(); + momstatus2 = photon_momom.getGenStatusCode(); + } + } + break; + } + } // 2nd photon loop + if (std::fabs(mompdg2) < 40 && std::fabs(mompdg2) > 0) { + for (auto& mcPhoton_mom : mcParticles) { + if (mcPhoton_mom.globalIndex() == momindex2) { + for (auto& photon_momom : mcPhoton_mom.mothers_as()) { + if (mompdg3 == 0) { + mompdg3 = photon_momom.pdgCode(); + momindex3 = photon_momom.globalIndex(); + momstatus3 = photon_momom.getGenStatusCode(); + } + } + break; + } + } // 3rd photon loop + } // 2nd photon check + + if (cfgDebug) { + std::cout << "We have a GEN prompt photon" << std::endl; + std::cout << "Photon gen status code chain: " << std::endl; + std::cout << "Photon stat: " << mcPhoton.getGenStatusCode() << std::endl; + std::cout << "Photon index: " << mcPhoton.globalIndex() << std::endl; + std::cout << "Photon mompdg 1: " << mompdg1 << std::endl; + std::cout << "Photon momstatus 1: " << momstatus1 << std::endl; + std::cout << "Photon momindex 1: " << momindex1 << std::endl; + std::cout << "Photon mompdg 2: " << mompdg2 << std::endl; + std::cout << "Photon momstatus 2: " << momstatus2 << std::endl; + std::cout << "Photon momindex 2: " << momindex2 << std::endl; + std::cout << "Photon mompdg 3: " << mompdg3 << std::endl; + std::cout << "Photon momstatus 3: " << momstatus3 << std::endl; + std::cout << "Photon momindex 3: " << momindex3 << std::endl; + } + } else { + continue; + } + + if (std::abs(mcPhoton.getGenStatusCode()) > 19 && std::abs(mcPhoton.getGenStatusCode()) < 90) { + if (mcPhoton.isPhysicalPrimary()) { + histos.fill(HIST("GEN_True_Prompt_Photon_Energy"), mcPhoton.e()); + if (photontrigger) { + TLorentzVector lRealPromptPhoton; + lRealPromptPhoton.SetPxPyPzE(mcPhoton.px(), mcPhoton.py(), mcPhoton.pz(), mcPhoton.e()); + double truepthadsum = GetPtHadSum(mcParticles, lRealPromptPhoton, cfgMinR, cfgMaxR, false, true, true); + histos.fill(HIST("GEN_TrueTrigger_V_PtHadSum_Photon"), mcPhoton.e(), truepthadsum); + } // photontrigger + } // check for primary photons + } // prompt photon check + + } // photon check + + } // loop over mc particles + + } // end of process + + PROCESS_SWITCH(statPromptPhoton, processMCGen, "process MC Gen", true); + + PresliceUnsorted EMCTrackPerTrack = aod::jemctrack::trackId; + int nEventsRecMC_JE = 0; + void processMCRec_JE(jfilteredCollisions::iterator const& collision, jfilteredMCClusters const& mcclusters, jTrackCandidates const& tracks, soa::Join const&, TrackCandidates const&, aod::JMcParticles const&, BcCandidates const&, jEMCtracks const& emctracks) + { + + nEventsRecMC_JE++; + if (cfgDebug) { + if ((nEventsRecMC_JE + 1) % 10000 == 0) { + std::cout << "Processed JE Rec MC Events: " << nEventsRecMC_JE << std::endl; + } + } + histos.fill(HIST("REC_nEvents"), 0.5); + + // required cuts + if (fabs(collision.posZ()) > cfgVtxCut) + return; + if (!collision.sel8()) + return; + + histos.fill(HIST("REC_nEvents"), 1.5); + + if (cfgEmcTrigger) { + if (!collision.isEmcalReadout()) + return; + } + histos.fill(HIST("REC_nEvents"), 2.5); + + bool noTrk = true; + for (auto& track : tracks) { + if (cfgJETracks) { + if (!jetderiveddatautilities::selectTrack(track, trackFilter)) { + continue; + } + } else { + auto ogtrack = track.track_as(); + if (!trackSelection(ogtrack)) { + continue; + } + if (!ogtrack.isGlobalTrack()) { + continue; + } + } + noTrk = false; + break; + } + + if (noTrk) + return; + + // now we do clusters + bool clustertrigger = false; + for (auto& mccluster : mcclusters) { + histos.fill(HIST("REC_M02_BC"), mccluster.m02()); + if (mccluster.m02() < cfgLowM02) + continue; + if (mccluster.m02() > cfgHighM02) + continue; + if (mccluster.energy() < cfgLowClusterE) + continue; + if (mccluster.energy() > cfgHighClusterE) + continue; + if (fabs(mccluster.eta()) > cfgtrkMaxEta) + continue; + + histos.fill(HIST("REC_Cluster_QA"), 0.5); + histos.fill(HIST("REC_M02_AC"), mccluster.m02()); + histos.fill(HIST("REC_All_Energy"), mccluster.energy()); + histos.fill(HIST("REC_ClusterPhi"), mccluster.phi()); + histos.fill(HIST("REC_ClusterEta"), mccluster.eta()); + + bool photontrigger = false; // is a neutral cluster + bool chargetrigger = false; // is definitely not a neutral cluster + // double photonPt = 0.0; + double truephotonPt = 0.0; + auto tracksofcluster = mccluster.matchedTracks_as>(); + /////////////// + /////////////// + /////////////// + + double phiPrimeC = mccluster.phi(); + phiPrimeC = phiPrimeC + TMath::Pi() / 18.; + phiPrimeC = fmod(phiPrimeC, 2 * TMath::Pi() / 18.); + double ptC = mccluster.energy(); + bool geocut = false; + histos.fill(HIST("REC_Cluster_PhiPrime_Pt"), phiPrimeC, mccluster.energy()); + if (phiPrimeC > (0.12 / ptC + TMath::Pi() / 18. + 0.035) || + phiPrimeC < (0.1 / ptC / ptC + TMath::Pi() / 18. - 0.025)) { + geocut = false; + } else { + geocut = true; + } + + if (cfgGeoCut) { + if (geocut) { + histos.fill(HIST("REC_Cluster_PhiPrime_Pt_C"), phiPrimeC, mccluster.energy()); + continue; + } + } + + histos.fill(HIST("REC_Cluster_PhiPrime_Pt_AC"), phiPrimeC, mccluster.energy()); + + // first, we check if veto is required + double sumptT = 0; + bool clusterqa = false; + for (auto& ctrack : tracksofcluster) { + double etaT, phiT; + + if (cfgJETracks) { + if (!jetderiveddatautilities::selectTrack(ctrack, trackFilter)) { + continue; + } + auto emctracksPerTrack = emctracks.sliceBy(EMCTrackPerTrack, ctrack.globalIndex()); + auto emctrack = emctracksPerTrack.iteratorAt(0); + etaT = emctrack.etaEmcal(); + phiT = emctrack.phiEmcal(); + } else { + auto ogtrack = ctrack.track_as(); + if (!trackSelection(ogtrack)) { + continue; + } + if (!ogtrack.isGlobalTrack()) { + continue; + } + etaT = ogtrack.trackEtaEmcal(); + phiT = ogtrack.trackPhiEmcal(); + } + + double etaC = mccluster.eta(); + double phiC = mccluster.phi(); + double ptT = ctrack.pt(); + bool etatrigger = false; + bool phitrigger = false; + double phidiff = TVector2::Phi_mpi_pi(mccluster.phi() - ctrack.phi()); + double etadiff = mccluster.eta() - ctrack.eta(); + + if (cfgPtClusterCut) { + if (fabs(etaT - etaC) < (0.010 + pow(ptT + 4.07, -2.5))) { + etatrigger = true; + } + + if (fabs(TVector2::Phi_mpi_pi(phiT - phiC)) < (0.015 + pow(ptT + 3.65, -2.0))) { + phitrigger = true; + } + } else { + if (fabs(etadiff) < 0.05) { + etatrigger = true; + } + + if (fabs(phidiff) < 0.05) { + phitrigger = true; + } + } + + if (etatrigger && phitrigger) { + chargetrigger = true; + sumptT += ptT; + } + if (chargetrigger) { + if (!clusterqa) { + histos.fill(HIST("REC_Cluster_QA"), 1.5); + clusterqa = true; + } + } + histos.fill(HIST("REC_Track_v_Cluster_Phi"), phidiff); + histos.fill(HIST("REC_Track_v_Cluster_Eta"), etadiff); + + histos.fill(HIST("REC_Track_v_Cluster_Phi_Eta"), phidiff, etadiff); + + } // track of cluster loop + + if (chargetrigger && sumptT > 0) { + double mccluster_over_sumptT = mccluster.energy() / sumptT; + histos.fill(HIST("REC_SumPt_BC"), mccluster_over_sumptT); + if (mccluster_over_sumptT < 1.7) { + histos.fill(HIST("REC_Cluster_QA"), 2.5); // veto fails, cluster is charged + } else { + histos.fill(HIST("REC_Cluster_QA"), 3.5); // veto is good, cluster is converted to neutral cluster + // chargetrigger = false; + histos.fill(HIST("REC_SumPt_AC"), mccluster_over_sumptT); + } + } // sumptT check + + if (!chargetrigger) { + photontrigger = true; + } + + /////////////// + /////////////// + /////////////// + + // check if cluster is good + for (auto& ctrack : tracksofcluster) { + if (cfgJETracks) { + if (!jetderiveddatautilities::selectTrack(ctrack, trackFilter)) { + continue; + } + } else { + auto ogtrack = ctrack.track_as(); + if (!trackSelection(ogtrack)) { + continue; + } + if (!ogtrack.isGlobalTrack()) { + continue; + } + } + bool etatrigger = false; + bool phitrigger = false; + // double ptT = ctrack.pt(); + double phidiff = TVector2::Phi_mpi_pi(mccluster.phi() - ctrack.phi()); + double etadiff = mccluster.eta() - ctrack.eta(); + if (fabs(etadiff) < 0.05) { + etatrigger = true; + } + + if (fabs(phidiff) < 0.05) { + phitrigger = true; + } + + if (chargetrigger) { + histos.fill(HIST("REC_Track_v_Cluster_Phi_C"), phidiff); + histos.fill(HIST("REC_Track_v_Cluster_Eta_C"), etadiff); + histos.fill(HIST("REC_Track_v_Cluster_Phi_Eta_C"), phidiff, etadiff); + } else { + if ((etatrigger || phitrigger) && chargetrigger) { + if (cfgDebug) { + std::cout << "????????????????????" << std::endl; + } + } + histos.fill(HIST("REC_Track_v_Cluster_Phi_AC"), phidiff); + histos.fill(HIST("REC_Track_v_Cluster_Eta_AC"), etadiff); + histos.fill(HIST("REC_Track_v_Cluster_Phi_Eta_AC"), phidiff, etadiff); + } + } // tracks + + /////////////// + /////////////// + /////////////// + + if (photontrigger) { // if no charge trigger, cluster is good! + histos.fill(HIST("REC_Cluster_QA"), 4.5); + clustertrigger = true; + double pthadsum = GetPtHadSum(tracks, mccluster, cfgMinR, cfgMaxR, false, false, true); + histos.fill(HIST("REC_Trigger_V_PtHadSum_Photon"), mccluster.energy(), pthadsum); + histos.fill(HIST("REC_PtHadSum_Photon"), pthadsum); + histos.fill(HIST("REC_Trigger_Energy"), mccluster.energy()); + } + + auto ClusterParticles = mccluster.mcParticles_as(); + + // now we check the realness of our prompt photons + bool goodgentrigger = true; + double chPe = 0; + for (auto& clusterparticle : ClusterParticles) { + // double etaP = clusterparticle.eta(); + // double etaC = mccluster.eta(); + // double phiP = clusterparticle.phi(); + // double phiC = mccluster.phi(); + // double ptP = clusterparticle.pt(); + int cindex = clusterparticle.globalIndex(); + double pdgcode = fabs(clusterparticle.pdgCode()); + if (!clusterparticle.isPhysicalPrimary()) { + continue; + } + if (pdgcode == 211 || pdgcode == 321 || pdgcode == 2212 || pdgcode == 11) { + bool notrack = true; + histos.fill(HIST("REC_Cluster_Particle_Pt"), clusterparticle.pt()); + + double phiPrimeP = clusterparticle.phi(); + if (clusterparticle.pdgCode() < 0) { + phiPrimeP = 2 * TMath::Pi() - phiPrimeP; + } + phiPrimeP = phiPrimeP + TMath::Pi() / 18.; + phiPrimeP = fmod(phiPrimeP, 2 * TMath::Pi() / 18.); + double ptP = clusterparticle.pt(); + for (auto& track : tracks) { + if (!track.has_mcParticle()) + continue; + + if (cfgJETracks) { + if (!jetderiveddatautilities::selectTrack(track, trackFilter)) { + continue; + } + } else { + auto ogtrack = track.track_as(); + if (!trackSelection(ogtrack)) { + continue; + } + if (!ogtrack.isGlobalTrack()) { + continue; + } + } + + int tindex = track.mcParticleId(); + if (tindex == cindex) { + histos.fill(HIST("REC_Cluster_ParticleWITHtrack_Pt"), clusterparticle.pt()); + histos.fill(HIST("REC_Cluster_ParticleWITHtrack_Phi"), clusterparticle.phi()); + histos.fill(HIST("REC_Cluster_ParticleWITHtrack_Eta"), clusterparticle.eta()); + histos.fill(HIST("REC_Cluster_ParticleWITHtrack_Pt_Phi"), clusterparticle.pt(), clusterparticle.phi()); + // if (phiPrimeP > (0.12/ptP + TMath::Pi()/18. + 0.035) || + // phiPrimeP < (0.1/ptP/ptP + TMath::Pi()/18. - 0.025) ) { + histos.fill(HIST("REC_Cluster_ParticleWITHtrack_Pt_PhiPrime"), ptP, phiPrimeP); + if (photontrigger) { + histos.fill(HIST("REC_Impurity_ParticleWITHtrack_Pt_PhiPrime"), ptP, phiPrimeP); + } + // }//geo cut + histos.fill(HIST("REC_Cluster_ParticleWITHtrack_Pt_Eta"), clusterparticle.pt(), clusterparticle.eta()); + + histos.fill(HIST("REC_Cluster_ParticleWITHtrack_TrackPt"), track.pt()); + notrack = false; + break; + } + } // track loop + + if (notrack) { + histos.fill(HIST("REC_Cluster_ParticleWITHOUTtrack_Pt"), clusterparticle.pt()); + histos.fill(HIST("REC_Cluster_ParticleWITHOUTtrack_Phi"), clusterparticle.phi()); + histos.fill(HIST("REC_Cluster_ParticleWITHOUTtrack_Eta"), clusterparticle.eta()); + histos.fill(HIST("REC_Cluster_ParticleWITHOUTtrack_Pt_Phi"), clusterparticle.pt(), clusterparticle.phi()); + // if (phiPrimeP > (0.12/ptP + TMath::Pi()/18. + 0.035) || + // phiPrimeP < (0.1/ptP/ptP + TMath::Pi()/18. - 0.025) ) { + histos.fill(HIST("REC_Cluster_ParticleWITHOUTtrack_Pt_PhiPrime"), ptP, phiPrimeP); + if (photontrigger) { + histos.fill(HIST("REC_Impurity_ParticleWITHOUTtrack_Pt_PhiPrime"), ptP, phiPrimeP); + } + // }//geo cut + histos.fill(HIST("REC_Cluster_ParticleWITHOUTtrack_Pt_Eta"), clusterparticle.pt(), clusterparticle.eta()); + } + } // pdg code check + + double phidiff = TVector2::Phi_mpi_pi(mccluster.phi() - clusterparticle.phi()); + double etadiff = mccluster.eta() - clusterparticle.eta(); + + if (pdgcode == 211 || pdgcode == 321 || pdgcode == 2212 || pdgcode == 11) { + if (clusterparticle.e() > 0.01) { + chPe += clusterparticle.e(); + goodgentrigger = false; + if (photontrigger) { + histos.fill(HIST("REC_Impurity_Energy_v_Cluster_Phi"), clusterparticle.e(), phidiff); + histos.fill(HIST("REC_Impurity_Energy_v_ClusterE_Phi"), mccluster.energy(), phidiff); + histos.fill(HIST("REC_Impurity_Energy_v_ClusterEoP_Phi"), mccluster.energy() / clusterparticle.e(), phidiff); + histos.fill(HIST("REC_Impurity_Energy_v_Cluster_Energy"), mccluster.energy(), clusterparticle.e()); + + histos.fill(HIST("REC_TrueImpurity_v_Cluster_Phi"), phidiff); + histos.fill(HIST("REC_TrueImpurity_v_Cluster_PhiAbs"), clusterparticle.phi()); + histos.fill(HIST("REC_TrueImpurity_v_Cluster_Eta"), etadiff); + histos.fill(HIST("REC_TrueImpurity_v_Cluster_EtaAbs"), clusterparticle.eta()); + histos.fill(HIST("REC_TrueImpurity_v_Cluster_Phi_Eta"), phidiff, etadiff); + } + } + } + histos.fill(HIST("REC_True_v_Cluster_Phi"), phidiff); + histos.fill(HIST("REC_True_v_Cluster_Eta"), etadiff); + + if (!photontrigger) { + continue; + } + if (clusterparticle.pdgCode() == 22) { + histos.fill(HIST("REC_True_Trigger_Energy"), clusterparticle.e()); + int mom1 = 0; + int mom2 = 0; + for (auto& photon_mom : clusterparticle.mothers_as()) { + if (mom1 == 0) { + mom1 = photon_mom.pdgCode(); + } + if (mom1 != 0) { + mom2 = photon_mom.pdgCode(); + } + } + if (std::fabs(mom1) > 40 && std::fabs(mom1) > 0) + continue; + + if (cfgDebug) { + std::cout << "We have a REC prompt photon" << std::endl; + std::cout << "Photon gen status code: " << clusterparticle.getGenStatusCode() << std::endl; + std::cout << "Photon mom 1: " << mom1 << std::endl; + std::cout << "Photon mom 2: " << mom2 << std::endl; + } + if (std::abs(clusterparticle.getGenStatusCode()) > 19 && std::abs(clusterparticle.getGenStatusCode()) < 90) { + histos.fill(HIST("REC_True_Prompt_Trigger_Energy"), clusterparticle.e()); + TLorentzVector lRealPhoton; + lRealPhoton.SetPxPyPzE(clusterparticle.px(), clusterparticle.py(), clusterparticle.pz(), clusterparticle.e()); + double truepthadsum = GetPtHadSum(tracks, lRealPhoton, cfgMinR, cfgMaxR, false, false, false); + truephotonPt = clusterparticle.e(); + histos.fill(HIST("REC_TrueTrigger_V_PtHadSum_Photon"), truephotonPt, truepthadsum); + } + } // photon check + } // clusterparticle loop + + if (cfgDebug) { + if (chPe > 0) { + if (photontrigger) { + if (chPe / mccluster.energy() < 0.50) { + goodgentrigger = true; + } + } + } + } + if (goodgentrigger && photontrigger) { + histos.fill(HIST("REC_Trigger_Purity"), 0.5); + histos.fill(HIST("REC_Trigger_Energy_GOOD"), mccluster.energy()); + histos.fill(HIST("REC_Trigger_Purity_v_Energy"), 0.5, mccluster.energy()); + } + if (goodgentrigger && !photontrigger) { + histos.fill(HIST("REC_Trigger_Purity"), 1.5); + histos.fill(HIST("REC_Trigger_Energy_MISS"), mccluster.energy()); + histos.fill(HIST("REC_Trigger_Purity_v_Energy"), 1.5, mccluster.energy()); + } + if (!goodgentrigger && photontrigger) { + histos.fill(HIST("REC_Trigger_Purity"), 2.5); + histos.fill(HIST("REC_Trigger_Energy_FAKE"), mccluster.energy()); + histos.fill(HIST("REC_Trigger_Purity_v_Energy"), 2.5, mccluster.energy()); + } + } // cluster loop + + // auto bc = collision.bc_as(); + // int rnr = bc.runNumber(); + + // std::string rnrstring = std::to_string(rnr); + // if (runs.find(rnrstring) == std::string::npos) { + // std::cout<<"++++++++++++++++++++++++++++++++"<getForTimeStamp(ccdbpath, bc.timestamp()); + // if(grpmag) { + // bfield = std::lround(5.f * grpmag->getL3Current() / 30000.f); + // std::cout<<"++++++++++++++++++++++++++++++++"<getForTimeStamp(ccdbpath, bc.timestamp()); + // if(!grpo) { + // std::cout<<"WE CAN NEITHER FETCH GRPMAG OR GRPO!!! SHIT IS SCREWED"<getNominalL3Field(); + // } + // bfield = 5; + // runs += rnrstring; + // std::cout << "++++++++++++++++++++++++++++++++" << std::endl; + // std::cout << "Run is now appended to string: " << runs << std::endl; + // std::cout << "++++++++++++++++++++++++++++++++" << std::endl; + + // } // check mag field for current run number: done! + + // clusters done, now we do the sternheimer tracks + for (auto& track : tracks) { + bool sterntrigger = false; + double sternPt = 0.0; + if (cfgJETracks) { + if (!jetderiveddatautilities::selectTrack(track, trackFilter)) { + continue; + } + } else { + auto ogtrack = track.track_as(); + if (!trackSelection(ogtrack)) { + continue; + } + if (!ogtrack.isGlobalTrack()) { + continue; + } + } + + // Do stuff with geometric cuts + double phiPrime = track.phi(); + if (track.sign() < 0) { + phiPrime = 2 * TMath::Pi() - phiPrime; + } + + // if (bfield < 0) { + // phiPrime = 2 * TMath::Pi() - phiPrime; + // } + + phiPrime = phiPrime + TMath::Pi() / 18.; + phiPrime = fmod(phiPrime, 2 * TMath::Pi() / 18.); + // double pt = track.pt(); + // if (phiPrime > (0.12/pt + TMath::Pi()/18. + 0.035) || + // phiPrime < (0.1/pt/pt + TMath::Pi()/18. - 0.025) ) { + histos.fill(HIST("REC_Track_PhiPrime_Pt"), phiPrime, track.pt()); + // }//geo cut + // Done with geometric cuts + + histos.fill(HIST("REC_Track_Pt"), track.pt()); + histos.fill(HIST("REC_Track_Phi"), track.phi()); + if (clustertrigger) { + histos.fill(HIST("REC_TrackPhi_photontrigger"), track.phi()); + histos.fill(HIST("REC_TrackEta_photontrigger"), track.eta()); + } + if (track.pt() > cfgMinTrig && track.pt() < cfgMaxTrig) { + if (fabs(track.eta()) <= cfgtrkMaxEta) { + sterntrigger = true; + sternPt = track.pt(); + } + } + double pthadsum = GetPtHadSum(tracks, track, cfgMinR, cfgMaxR, true, false, true); + histos.fill(HIST("REC_Trigger_V_PtHadSum_Nch"), sternPt, pthadsum); + if (sterntrigger) { + bool doStern = true; + double sterncount = 1.0; + while (doStern) { + histos.fill(HIST("REC_Trigger_V_PtHadSum_Stern"), sterncount, pthadsum, 2.0 / sternPt); + if (sterncount < sternPt) { + sterncount++; + } else { + doStern = false; + } + } // While sternin' + } // stern trigger loop + } // track loop + + } // end of process + + PROCESS_SWITCH(statPromptPhoton, processMCRec_JE, "processJE MC data", false); + + int nEventsData = 0; + void processData(jfilteredCollisions::iterator const& collision, jfilteredClusters const& clusters, jDataTrackCandidates const& tracks, soa::Join const&, TrackCandidates const&, BcCandidates const&, jEMCtracks const& emctracks) + { + + nEventsData++; + if (cfgDebug) { + if (nEventsData == 1) { + std::cout << "Starting Data Processing: " << nEventsData << std::endl; + } + if ((nEventsData + 1) % 10000 == 0) { + std::cout << "Processed Data Events: " << nEventsData << std::endl; + } + } + histos.fill(HIST("DATA_nEvents"), 0.5); + + // required cuts + if (fabs(collision.posZ()) > cfgVtxCut) + return; + if (!collision.sel8()) + return; + + histos.fill(HIST("DATA_nEvents"), 1.5); + + if (cfgEmcTrigger) { + if (!collision.isEmcalReadout()) + return; + } + histos.fill(HIST("DATA_nEvents"), 2.5); + + bool noTrk = true; + for (auto& track : tracks) { + + if (cfgJETracks) { + if (!jetderiveddatautilities::selectTrack(track, trackFilter)) { + continue; + } + } else { + auto ogtrack = track.track_as(); + if (!trackSelection(ogtrack)) { + continue; + } + if (!ogtrack.isGlobalTrack()) { + continue; + } + } + noTrk = false; + break; + } + if (noTrk) + return; + + // now we do clusters + bool clustertrigger = false; + for (auto& cluster : clusters) { + histos.fill(HIST("DATA_M02_BC"), cluster.m02()); + if (cluster.m02() < cfgLowM02) + continue; + if (cluster.m02() > cfgHighM02) + continue; + if (cluster.energy() < cfgLowClusterE) + continue; + if (cluster.energy() > cfgHighClusterE) + continue; + if (fabs(cluster.eta()) > cfgtrkMaxEta) + continue; + + histos.fill(HIST("DATA_Cluster_QA"), 0.5); + histos.fill(HIST("DATA_M02_AC"), cluster.m02()); + histos.fill(HIST("DATA_All_Energy"), cluster.energy()); + histos.fill(HIST("DATA_ClusterPhi"), cluster.phi()); + histos.fill(HIST("DATA_ClusterEta"), cluster.eta()); + + bool photontrigger = false; // is a neutral cluster + bool chargetrigger = false; // is definitely not a neutral cluster + auto tracksofcluster = cluster.matchedTracks_as>(); + + ///*GEOMETRICAL CUT*/// + + double phiPrimeC = cluster.phi(); + phiPrimeC = phiPrimeC + TMath::Pi() / 18.; + phiPrimeC = fmod(phiPrimeC, 2 * TMath::Pi() / 18.); + double ptC = cluster.energy(); + bool geocut = false; + histos.fill(HIST("DATA_Cluster_PhiPrime_Pt"), phiPrimeC, cluster.energy()); + if (phiPrimeC > (0.12 / ptC + TMath::Pi() / 18. + 0.035) || + phiPrimeC < (0.1 / ptC / ptC + TMath::Pi() / 18. - 0.025)) { + geocut = false; + } else { + geocut = true; + } + + if (cfgGeoCut) { + if (geocut) { + histos.fill(HIST("DATA_Cluster_PhiPrime_Pt_C"), phiPrimeC, cluster.energy()); + continue; + } + } + + histos.fill(HIST("DATA_Cluster_PhiPrime_Pt_AC"), phiPrimeC, cluster.energy()); + + ///*GEOMETRICAL CUT*/// + + ///*CHECK FOR PHOTON CANDIDATE*/// + + // first, we check if veto is required + double sumptT = 0; + bool clusterqa = false; + for (auto& ctrack : tracksofcluster) { + double etaT, phiT; + if (cfgJETracks) { + if (!jetderiveddatautilities::selectTrack(ctrack, trackFilter)) { + continue; + } + auto emctracksPerTrack = emctracks.sliceBy(EMCTrackPerTrack, ctrack.globalIndex()); + auto emctrack = emctracksPerTrack.iteratorAt(0); + etaT = emctrack.etaEmcal(); + phiT = emctrack.phiEmcal(); + } else { + auto ogtrack = ctrack.track_as(); + if (!trackSelection(ogtrack)) { + continue; + } + if (!ogtrack.isGlobalTrack()) { + continue; + } + etaT = ogtrack.trackEtaEmcal(); + phiT = ogtrack.trackPhiEmcal(); + } + + double etaC = cluster.eta(); + double phiC = cluster.phi(); + double ptT = ctrack.pt(); + bool etatrigger = false; + bool phitrigger = false; + double phidiff = TVector2::Phi_mpi_pi(cluster.phi() - ctrack.phi()); + double etadiff = cluster.eta() - ctrack.eta(); + + if (cfgPtClusterCut) { + if (fabs(etaT - etaC) < (0.010 + pow(ptT + 4.07, -2.5))) { + etatrigger = true; + } + + if (fabs(TVector2::Phi_mpi_pi(phiT - phiC)) < (0.015 + pow(ptT + 3.65, -2.0))) { + phitrigger = true; + } + } else { + if (fabs(etadiff) < 0.05) { + etatrigger = true; + } + + if (fabs(phidiff) < 0.05) { + phitrigger = true; + } + } + + if (etatrigger && phitrigger) { + chargetrigger = true; + sumptT += ptT; + } + if (chargetrigger) { + if (!clusterqa) { + histos.fill(HIST("DATA_Cluster_QA"), 1.5); + clusterqa = true; + } + } + histos.fill(HIST("DATA_Track_v_Cluster_Phi"), phidiff); + histos.fill(HIST("DATA_Track_v_Cluster_Eta"), etadiff); + histos.fill(HIST("DATA_Track_v_Cluster_Phi_Eta"), phidiff, etadiff); + + } // track of cluster loop + + if (chargetrigger && sumptT > 0) { + double cluster_over_sumptT = cluster.energy() / sumptT; + histos.fill(HIST("DATA_SumPt_BC"), cluster_over_sumptT); + if (cluster_over_sumptT < 1.7) { + histos.fill(HIST("DATA_Cluster_QA"), 2.5); // veto fails, cluster is charged + } else { + histos.fill(HIST("DATA_Cluster_QA"), 3.5); // veto is good, cluster is converted to neutral cluster + chargetrigger = false; + histos.fill(HIST("DATA_SumPt_AC"), cluster_over_sumptT); + } + } // sumptT check + + if (!chargetrigger) { + photontrigger = true; + } + + ///*CHECK FOR PHOTON CANDIDATE*/// + + ///*CALCULATE PTHAD SUM*/// + + if (photontrigger) { // if no charge trigger, cluster is good! + histos.fill(HIST("DATA_Cluster_QA"), 4.5); + clustertrigger = true; + double pthadsum = GetPtHadSum(tracks, cluster, cfgMinR, cfgMaxR, false, false, true); + histos.fill(HIST("DATA_Trigger_V_PtHadSum_Photon"), cluster.energy(), pthadsum); + histos.fill(HIST("DATA_PtHadSum_Photon"), pthadsum); + histos.fill(HIST("DATA_Trigger_Energy"), cluster.energy()); + } + + ///*CALCULATE PTHAD SUM*/// + + } // cluster loop + + ///*CALCULATE STERNHEIMER*/// + + for (auto& track : tracks) { + bool sterntrigger = false; + double sternPt = 0.0; + if (cfgJETracks) { + if (!jetderiveddatautilities::selectTrack(track, trackFilter)) { + continue; + } + } else { + auto ogtrack = track.track_as(); + if (!trackSelection(ogtrack)) { + continue; + } + if (!ogtrack.isGlobalTrack()) { + continue; + } + } + + // Do stuff with geometric cuts + double phiPrime = track.phi(); + if (track.sign() < 0) { + phiPrime = 2 * TMath::Pi() - phiPrime; + } + + // if (bfield < 0) { + // phiPrime = 2 * TMath::Pi() - phiPrime; + // } + + phiPrime = phiPrime + TMath::Pi() / 18.; + phiPrime = fmod(phiPrime, 2 * TMath::Pi() / 18.); + double pt = track.pt(); + if (phiPrime > (0.12 / pt + TMath::Pi() / 18. + 0.035) || + phiPrime < (0.1 / pt / pt + TMath::Pi() / 18. - 0.025)) { + histos.fill(HIST("DATA_Track_PhiPrime_Pt"), phiPrime, track.pt()); + } // geo cut + // Done with geometric cuts + + histos.fill(HIST("DATA_Track_Pt"), track.pt()); + histos.fill(HIST("DATA_Track_Phi"), track.phi()); + if (clustertrigger) { + histos.fill(HIST("DATA_TrackPhi_photontrigger"), track.phi()); + histos.fill(HIST("DATA_TrackEta_photontrigger"), track.eta()); + } + if (track.pt() > cfgMinTrig && track.pt() < cfgMaxTrig) { + if (fabs(track.eta()) <= cfgtrkMaxEta) { + sterntrigger = true; + sternPt = track.pt(); + } + } + + if (sterntrigger) { + bool doStern = true; + double sterncount = 1.0; + double pthadsum = GetPtHadSum(tracks, track, cfgMinR, cfgMaxR, true, false, true); + histos.fill(HIST("DATA_Trigger_V_PtHadSum_Nch"), sternPt, pthadsum); + while (doStern) { + double pthadsum = GetPtHadSum(tracks, track, cfgMinR, cfgMaxR, true, false, true); + histos.fill(HIST("DATA_Trigger_V_PtHadSum_Stern"), sterncount, pthadsum, 2.0 / sternPt); + if (sterncount < sternPt) { + sterncount++; + } else { + doStern = false; + } + } // While sternin' + } // stern trigger loop + } // track loop + + ///*CALCULATE STERNHEIMER*/// + + } // end of process + + PROCESS_SWITCH(statPromptPhoton, processData, "processJE data", false); + +}; // end of main struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +}; diff --git a/PWGJE/Tasks/trackEfficiency.cxx b/PWGJE/Tasks/trackEfficiency.cxx new file mode 100644 index 00000000000..b9fde50abde --- /dev/null +++ b/PWGJE/Tasks/trackEfficiency.cxx @@ -0,0 +1,549 @@ +// 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. + +// track efficiency task (global tracks) +// +/// \author Aimeric Landou + +#include +#include +#include +#include +#include + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" + +#include "PWGJE/Core/JetDerivedDataUtilities.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct TrackEfficiencyJets { + Service pdg; + + using JetParticlesWithOriginal = soa::Join; + + HistogramRegistry registry; + + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections; other option: uniformTracks"}; + Configurable skipMBGapEvents{"skipMBGapEvents", false, "flag to choose to reject min. bias gap events"}; + + // Tracking efficiency process function configurables: + Configurable checkPrimaryPart{"checkPrimaryPart", true, "0: doesn't check mcparticle.isPhysicalPrimary() - 1: checks particle.isPhysicalPrimary()"}; + Configurable checkCentrality{"checkCentrality", false, ""}; + Configurable acceptSplitCollisions{"acceptSplitCollisions", 0, "0: only look at mcCollisions that are not split; 1: accept split mcCollisions, 2: accept split mcCollisions but only look at the first reco collision associated with it"}; + Configurable trackEtaAcceptanceCountQA{"trackEtaAcceptanceCountQA", 0.9, "eta acceptance"}; // removed from actual cuts for now because all the histograms have an eta axis + Configurable centralityMin{"centralityMin", -999, ""}; + Configurable centralityMax{"centralityMax", 999, ""}; + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + Configurable trackDcaZmax{"trackDcaZmax", 99, "additional cut on dcaZ to PV for tracks; uniformTracks in particular don't cut on this at all"}; + Configurable nBinsLowPt{"nBinsLowPt", 200, "number of pt bins for low pt (below 10GeV) efficiency histograms"}; + + // Track QA process function configurables: + Configurable trackQAEtaMin{"trackQAEtaMin", -0.9, "minimum eta acceptance for tracks in the processTracks QA"}; + Configurable trackQAEtaMax{"trackQAEtaMax", 0.9, "maximum eta acceptance for tracks in the processTracks QA"}; + Configurable trackQAPtMin{"trackQAPtMin", 0.15, "minimum pT acceptance for tracks in the processTracks QA"}; + Configurable trackQAPtMax{"trackQAPtMax", 100.0, "maximum pT acceptance for tracks in the processTracks QA"}; + Configurable trackOccupancyInTimeRangeMax{"trackOccupancyInTimeRangeMax", 999999, "maximum occupancy of tracks in neighbouring collisions in a given time range; only applied for reconstructed tracks, not mc particles"}; + Configurable trackOccupancyInTimeRangeMin{"trackOccupancyInTimeRangeMin", -999999, "minimum occupancy of tracks in neighbouring collisions in a given time range; only applied for reconstructed tracks, not mc particles"}; + + Configurable> centralityBinning{"centralityBinning", {0., 10., 50., 70.}, "binning of centrality histograms"}; + Configurable intRateNBins{"intRateNBins", 50, "number of bins for interaction rate axis"}; + Configurable intRateMax{"intRateMax", 50000.0, "maximum value of interaction rate axis"}; + + std::vector eventSelectionBits; + int trackSelection = -1; + + bool isChargedParticle(int code) + { + auto p = pdg->GetParticle(code); + auto charge = 0.; + if (p != nullptr) { + charge = p->Charge(); + } + return std::abs(charge) >= 3.; + } + + template + void fillTrackHistograms(T const& collision, U const& tracks, float weight = 1.0) + { + for (auto const& track : tracks) { + if (!(jetderiveddatautilities::selectTrack(track, trackSelection) && jetderiveddatautilities::selectTrackDcaZ(track, trackDcaZmax))) { + continue; + } + registry.fill(HIST("h2_centrality_track_pt"), collision.centrality(), track.pt(), weight); + registry.fill(HIST("h2_centrality_track_eta"), collision.centrality(), track.eta(), weight); + registry.fill(HIST("h2_centrality_track_phi"), collision.centrality(), track.phi(), weight); + registry.fill(HIST("h2_centrality_track_energy"), collision.centrality(), track.energy(), weight); + registry.fill(HIST("h2_track_pt_track_sigma1overpt"), track.pt(), track.sigma1Pt(), weight); + registry.fill(HIST("h2_track_pt_track_sigmapt"), track.pt(), track.sigma1Pt() * track.pt(), weight); + registry.fill(HIST("h2_track_pt_high_track_sigma1overpt"), track.pt(), track.sigma1Pt(), weight); + registry.fill(HIST("h2_track_pt_high_track_sigmapt"), track.pt(), track.sigma1Pt() * track.pt(), weight); + registry.fill(HIST("h3_intrate_centrality_track_pt"), collision.hadronicRate(), collision.centrality(), track.pt(), weight); + } + } + + template + void fillParticlesHistograms(T const& collision, U const& mcparticles, float weight = 1.0) + { + for (auto const& mcparticle : mcparticles) { + registry.fill(HIST("h2_centrality_particle_pt"), collision.centrality(), mcparticle.pt(), weight); + registry.fill(HIST("h2_centrality_particle_eta"), collision.centrality(), mcparticle.eta(), weight); + registry.fill(HIST("h2_centrality_particle_phi"), collision.centrality(), mcparticle.phi(), weight); + registry.fill(HIST("h2_centrality_particle_energy"), collision.centrality(), mcparticle.energy(), weight); + registry.fill(HIST("h3_intrate_centrality_particle_pt"), collision.hadronicRate(), collision.centrality(), mcparticle.pt(), weight); + } + } + + void init(o2::framework::InitContext&) + { + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + + if (doprocessEFficiencyPurity) { + + registry.add("hMcCollCutsCounts", "McColl cuts count checks", {HistType::kTH1F, {{10, 0., 10.}}}); + registry.get(HIST("hMcCollCutsCounts"))->GetXaxis()->SetBinLabel(1, "allMcColl"); + registry.get(HIST("hMcCollCutsCounts"))->GetXaxis()->SetBinLabel(2, "vertexZ"); + registry.get(HIST("hMcCollCutsCounts"))->GetXaxis()->SetBinLabel(3, "noRecoColl"); + registry.get(HIST("hMcCollCutsCounts"))->GetXaxis()->SetBinLabel(4, "splitColl"); + registry.get(HIST("hMcCollCutsCounts"))->GetXaxis()->SetBinLabel(5, "recoCollEvtSel"); + registry.get(HIST("hMcCollCutsCounts"))->GetXaxis()->SetBinLabel(6, "centralityCut"); + + registry.add("hMcPartCutsCounts", "McPart cuts count checks", {HistType::kTH1F, {{10, 0., 10.}}}); + registry.get(HIST("hMcPartCutsCounts"))->GetXaxis()->SetBinLabel(1, "allPartsInSelMcColl"); + registry.get(HIST("hMcPartCutsCounts"))->GetXaxis()->SetBinLabel(2, "isCharged"); + registry.get(HIST("hMcPartCutsCounts"))->GetXaxis()->SetBinLabel(3, "isPrimary"); + registry.get(HIST("hMcPartCutsCounts"))->GetXaxis()->SetBinLabel(4, "etaAccept"); // not actually applied here but it will give an idea of what will be done in the post processing + + registry.add("hTrackCutsCounts", "Track cuts count checks", {HistType::kTH1F, {{10, 0., 10.}}}); + registry.get(HIST("hTrackCutsCounts"))->GetXaxis()->SetBinLabel(1, "allTracksInSelColl"); + registry.get(HIST("hTrackCutsCounts"))->GetXaxis()->SetBinLabel(2, "trackSel"); + registry.get(HIST("hTrackCutsCounts"))->GetXaxis()->SetBinLabel(3, "hasMcParticle"); + registry.get(HIST("hTrackCutsCounts"))->GetXaxis()->SetBinLabel(4, "mcPartIsPrimary"); + registry.get(HIST("hTrackCutsCounts"))->GetXaxis()->SetBinLabel(5, "etaAcc"); // not actually applied here but it will give an idea of what will be done in the post processing + + AxisSpec ptAxis_eff = {nBinsLowPt, 0., 10., "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptAxisHigh_eff = {18, 10., 100., "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec etaAxis_eff = {100, -1.0, 1.0, "#eta"}; + AxisSpec phiAxis_eff = {200, -1.0, 7., "#phi"}; + + // ptAxisLow + registry.add("h3_particle_pt_particle_eta_particle_phi_mcpartofinterest", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxis_eff, etaAxis_eff, phiAxis_eff}}); + registry.add("h3_particle_pt_particle_eta_particle_phi_mcpart_nonprimary", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxis_eff, etaAxis_eff, phiAxis_eff}}); + + registry.add("h3_track_pt_track_eta_track_phi_nonassociatedtrack", "#it{p}_{T, track} (GeV/#it{c}); #eta_{track}; #phi_{track}", {HistType::kTH3F, {ptAxis_eff, etaAxis_eff, phiAxis_eff}}); + registry.add("h3_track_pt_track_eta_track_phi_associatedtrack_primary", "#it{p}_{T, track} (GeV/#it{c}); #eta_{track}; #phi_{track}", {HistType::kTH3F, {ptAxis_eff, etaAxis_eff, phiAxis_eff}}); + registry.add("h3_track_pt_track_eta_track_phi_associatedtrack_nonprimary", "#it{p}_{T, track} (GeV/#it{c}); #eta_{track}; #phi_{track}", {HistType::kTH3F, {ptAxis_eff, etaAxis_eff, phiAxis_eff}}); + registry.add("h3_track_pt_track_eta_track_phi_associatedtrack_split_primary", "#it{p}_{T, track} (GeV/#it{c}); #eta_{track}; #phi_{track}", {HistType::kTH3F, {ptAxis_eff, etaAxis_eff, phiAxis_eff}}); + registry.add("h3_track_pt_track_eta_track_phi_associatedtrack_split_nonprimary", "#it{p}_{T, track} (GeV/#it{c}); #eta_{track}; #phi_{track}", {HistType::kTH3F, {ptAxis_eff, etaAxis_eff, phiAxis_eff}}); + + registry.add("h3_particle_pt_particle_eta_particle_phi_associatedtrack_primary", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxis_eff, etaAxis_eff, phiAxis_eff}}); + registry.add("h3_particle_pt_particle_eta_particle_phi_associatedtrack_nonprimary", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxis_eff, etaAxis_eff, phiAxis_eff}}); + registry.add("h3_particle_pt_particle_eta_particle_phi_associatedtrack_split_primary", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxis_eff, etaAxis_eff, phiAxis_eff}}); + registry.add("h3_particle_pt_particle_eta_particle_phi_associatedtrack_split_nonprimary", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxis_eff, etaAxis_eff, phiAxis_eff}}); + + registry.add("h2_particle_pt_track_pt_residual_associatedtrack_primary", "(#it{p}_{T, mcpart} - #it{p}_{T, track}) / #it{p}_{T, mcpart}; #it{p}_{T, mcpart} (GeV/#it{c})", {HistType::kTH2F, {ptAxis_eff, {200, -1., 1.}}}); + + // ptAxisHigh + registry.add("h3_particle_pt_high_particle_eta_particle_phi_mcpartofinterest", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxisHigh_eff, etaAxis_eff, phiAxis_eff}}); + + registry.add("h3_track_pt_high_track_eta_track_phi_nonassociatedtrack", "#it{p}_{T, track} (GeV/#it{c}); #eta_{track}; #phi_{track}", {HistType::kTH3F, {ptAxisHigh_eff, etaAxis_eff, phiAxis_eff}}); + registry.add("h3_track_pt_high_track_eta_track_phi_associatedtrack_primary", "#it{p}_{T, track} (GeV/#it{c}); #eta_{track}; #phi_{track}", {HistType::kTH3F, {ptAxisHigh_eff, etaAxis_eff, phiAxis_eff}}); + registry.add("h3_track_pt_high_track_eta_track_phi_associatedtrack_nonprimary", "#it{p}_{T, track} (GeV/#it{c}); #eta_{track}; #phi_{track}", {HistType::kTH3F, {ptAxisHigh_eff, etaAxis_eff, phiAxis_eff}}); + registry.add("h3_track_pt_high_track_eta_track_phi_associatedtrack_split_primary", "#it{p}_{T, track} (GeV/#it{c}); #eta_{track}; #phi_{track}", {HistType::kTH3F, {ptAxisHigh_eff, etaAxis_eff, phiAxis_eff}}); + registry.add("h3_track_pt_high_track_eta_track_phi_associatedtrack_split_nonprimary", "#it{p}_{T, track} (GeV/#it{c}); #eta_{track}; #phi_{track}", {HistType::kTH3F, {ptAxisHigh_eff, etaAxis_eff, phiAxis_eff}}); + + registry.add("h3_particle_pt_high_particle_eta_particle_phi_associatedtrack_primary", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxisHigh_eff, etaAxis_eff, phiAxis_eff}}); + registry.add("h3_particle_pt_high_particle_eta_particle_phi_associatedtrack_nonprimary", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxisHigh_eff, etaAxis_eff, phiAxis_eff}}); + registry.add("h3_particle_pt_high_particle_eta_particle_phi_associatedtrack_split_primary", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxisHigh_eff, etaAxis_eff, phiAxis_eff}}); + registry.add("h3_particle_pt_high_particle_eta_particle_phi_associatedtrack_split_nonprimary", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxisHigh_eff, etaAxis_eff, phiAxis_eff}}); + + registry.add("h2_particle_pt_high_track_pt_high_residual_associatedtrack_primary", "(#it{p}_{T, mcpart} - #it{p}_{T, track}) / #it{p}_{T, mcpart}; #it{p}_{T, mcpart} (GeV/#it{c})", {HistType::kTH2F, {ptAxisHigh_eff, {200, -1., 1.}}}); + } + + if (doprocessTracks || doprocessTracksWeighted) { + AxisSpec centAxis = {centralityBinning, "centrality (%)"}; + AxisSpec intRateAxis = {intRateNBins, 0., intRateMax, "int. rate (kHz)"}; + registry.add("h2_centrality_track_pt", "centrality vs track pT; centrality; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {centAxis, {200, 0., 200.}}}); + registry.add("h2_centrality_track_eta", "centrality vs track #eta; centrality; #eta_{track}", {HistType::kTH2F, {centAxis, {100, -1.0, 1.0}}}); + registry.add("h2_centrality_track_phi", "centrality vs track #varphi; centrality; #varphi_{track}", {HistType::kTH2F, {centAxis, {160, -1.0, 7.}}}); + registry.add("h2_centrality_track_energy", "centrality vs track energy; centrality; Energy GeV", {HistType::kTH2F, {centAxis, {100, 0.0, 100.0}}}); + registry.add("h2_track_pt_track_sigmapt", "#sigma(#it{p}_{T})/#it{p}_{T}; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{100, 0., 10.}, {100000, 0.0, 100.0}}}); + registry.add("h2_track_pt_high_track_sigmapt", "#sigma(#it{p}_{T})/#it{p}_{T}; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{90, 10., 100.}, {100000, 0.0, 100.0}}}); + registry.add("h2_track_pt_track_sigma1overpt", "#sigma(1/#it{p}_{T}); #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{100, 0., 10.}, {1000, 0.0, 10.0}}}); + registry.add("h2_track_pt_high_track_sigma1overpt", "#sigma(1/#it{p}_{T}); #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{90, 10., 100.}, {1000, 0.0, 10.0}}}); + registry.add("h3_intrate_centrality_track_pt", "interaction rate vs centrality vs track pT; int. rate; centrality; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH3F, {intRateAxis, centAxis, {200, 0., 200.}}}); + } + + if (doprocessParticles || doprocessParticlesWeighted) { + AxisSpec centAxis = {centralityBinning, "centrality (%)"}; + AxisSpec intRateAxis = {intRateNBins, 0., intRateMax, "int. rate (kHz)"}; + registry.add("h2_centrality_particle_pt", "centrality vs particle pT; centrality; #it{p}_{T,part} (GeV/#it{c})", {HistType::kTH2F, {centAxis, {200, 0., 200.}}}); + registry.add("h2_centrality_particle_eta", "centrality vs particle #eta; centrality; #eta_{part}", {HistType::kTH2F, {centAxis, {100, -1.0, 1.0}}}); + registry.add("h2_centrality_particle_phi", "centrality vs particle #varphi; centrality; #varphi_{part}", {HistType::kTH2F, {centAxis, {160, -1.0, 7.}}}); + registry.add("h2_centrality_particle_energy", "centrality vs particle energy; centrality; Energy GeV", {HistType::kTH2F, {centAxis, {100, 0.0, 100.0}}}); + registry.add("h3_intrate_centrality_particle_pt", "interaction rate vs centrality vs particle pT; int. rate; centrality; #it{p}_{T,part} (GeV/#it{c})", {HistType::kTH3F, {intRateAxis, centAxis, {200, 0., 200.}}}); + } + + if (doprocessTracks || doprocessTracksWeighted) { + AxisSpec centAxis = {centralityBinning, "centrality (%)"}; + registry.add("h_collisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + registry.add("h_fakecollisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + registry.add("h2_centrality_collisions", "centrality vs collisions; centrality; collisions", {HistType::kTH2F, {centAxis, {4, 0.0, 4.0}}}); + } + if (doprocessParticles || doprocessParticlesWeighted) { + AxisSpec centAxis = {centralityBinning, "centrality (%)"}; + registry.add("h_mccollisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + registry.add("h2_centrality_mccollisions", "centrality vs mccollisions; centrality; collisions", {HistType::kTH2F, {centAxis, {4, 0.0, 4.0}}}); + } + if (doprocessTracksWeighted) { + registry.add("h_collisions_weighted", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + } + if (doprocessParticlesWeighted) { + registry.add("h_mccollisions_weighted", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + } + } + + Preslice tracksPerJCollision = o2::aod::jtrack::collisionId; + + // filters for processTracks QA functions only: + Filter trackCuts = (aod::jtrack::pt >= trackQAPtMin && aod::jtrack::pt < trackQAPtMax && aod::jtrack::eta > trackQAEtaMin && aod::jtrack::eta < trackQAEtaMax); + Filter particleCuts = (aod::jmcparticle::pt >= trackQAPtMin && aod::jmcparticle::pt < trackQAPtMax && aod::jmcparticle::eta > trackQAEtaMin && aod::jmcparticle::eta < trackQAEtaMax); + Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax); + + void processEFficiencyPurity(aod::JetMcCollision const& mcCollision, + soa::SmallGroups const& collisions, // smallgroups gives only the collisions associated to the current mccollision, thanks to the mccollisionlabel pre-integrated in jetcollisionsmcd + soa::Join const& jetTracks, + JetParticlesWithOriginal const& jMcParticles) + { + // missing: + // * constexpr auto hasCentrality = CollisionMCRecTableCentFT0C::template contains(); + // if constexpr (hasCentrality) { + // * dividing in centrality bins + // I should maybe introduce the sel8 cuts on the collisoins (reco, but what about mccoll? maybe not htat way included in efficiency) + + registry.fill(HIST("hMcCollCutsCounts"), 0.5); // all mcCollisions + + if (!(abs(mcCollision.posZ()) < vertexZCut)) { + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 1.5); // mcCollision.posZ() condition + + if (collisions.size() < 1) { + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 2.5); // mcCollisions with at least one reconstructed collision + + if (acceptSplitCollisions == 0 && collisions.size() > 1) { + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 3.5); // split mcCollisions condition + + bool hasSel8Coll = false; + bool centralityCheck = false; + if (acceptSplitCollisions == 2) { // check only that the first reconstructed collision passes the check + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split + hasSel8Coll = true; + } + if (!checkCentrality || ((centralityMin < collisions.begin().centrality()) && (collisions.begin().centrality() < centralityMax))) { // effect unclear if mcColl is split + centralityCheck = true; + } + } else { // check that at least one of the reconstructed collisions passes the checks + for (auto& collision : collisions) { + if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split + hasSel8Coll = true; + } + if (!checkCentrality || ((centralityMin < collision.centrality()) && (collision.centrality() < centralityMax))) { // effect unclear if mcColl is split + centralityCheck = true; + } + } + } + if (!hasSel8Coll) { + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 4.5); // at least one of the reconstructed collisions associated with this mcCollision is selected + + if (!centralityCheck) { + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 5.5); // at least one of the reconstructed collisions associated with this mcCollision is selected with regard to centrality + + for (auto& jMcParticle : jMcParticles) { + registry.fill(HIST("hMcPartCutsCounts"), 0.5); // allPartsInSelMcColl + + if (!isChargedParticle(jMcParticle.pdgCode())) { + continue; + } + registry.fill(HIST("hMcPartCutsCounts"), 1.5); // isCharged + + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_mcpart_nonprimary"), jMcParticle.pt(), jMcParticle.eta(), jMcParticle.phi()); + + if (checkPrimaryPart && !jMcParticle.isPhysicalPrimary()) { // global tracks should be mostly primaries + continue; + } + registry.fill(HIST("hMcPartCutsCounts"), 2.5); // isPrimary + + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_mcpartofinterest"), jMcParticle.pt(), jMcParticle.eta(), jMcParticle.phi()); + + registry.fill(HIST("h3_particle_pt_high_particle_eta_particle_phi_mcpartofinterest"), jMcParticle.pt(), jMcParticle.eta(), jMcParticle.phi()); + + if ((abs(jMcParticle.eta()) < trackEtaAcceptanceCountQA)) { // removed from actual cuts for now because all the histograms have an eta axis + registry.fill(HIST("hMcPartCutsCounts"), 3.5); // etaAccept // not actually applied here but it will give an idea of what will be done in the post processing + } + } + + std::vector seenMcParticlesVector; // is reset every mc collision + + int splitCollCounter = 0; + for (auto& collision : collisions) { + splitCollCounter++; + if (acceptSplitCollisions == 2 && splitCollCounter > 1) { + return; + } + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents) || !(abs(collision.posZ()) < vertexZCut)) { + continue; + } + + auto collTracks = jetTracks.sliceBy(tracksPerJCollision, collision.globalIndex()); + for (auto& track : collTracks) { + registry.fill(HIST("hTrackCutsCounts"), 0.5); + + if (!(jetderiveddatautilities::selectTrack(track, trackSelection) && jetderiveddatautilities::selectTrackDcaZ(track, trackDcaZmax))) { // if track selection is uniformTrack, dcaZ cuts need to be added as they aren't in the selection so that they can be studied here + continue; + } + registry.fill(HIST("hTrackCutsCounts"), 1.5); + + if (!track.has_mcParticle()) { + registry.fill(HIST("h3_track_pt_track_eta_track_phi_nonassociatedtrack"), track.pt(), track.eta(), track.phi()); + + registry.fill(HIST("h3_track_pt_high_track_eta_track_phi_nonassociatedtrack"), track.pt(), track.eta(), track.phi()); + continue; + } + registry.fill(HIST("hTrackCutsCounts"), 2.5); + + auto jMcParticleFromTrack = track.mcParticle_as(); + if (!jMcParticleFromTrack.isPhysicalPrimary()) { + registry.fill(HIST("h3_track_pt_track_eta_track_phi_associatedtrack_nonprimary"), track.pt(), track.eta(), track.phi()); + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_associatedtrack_nonprimary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi()); + + registry.fill(HIST("h3_track_pt_high_track_eta_track_phi_associatedtrack_nonprimary"), track.pt(), track.eta(), track.phi()); + registry.fill(HIST("h3_particle_pt_high_particle_eta_particle_phi_associatedtrack_nonprimary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi()); + + if (std::find(seenMcParticlesVector.begin(), seenMcParticlesVector.end(), jMcParticleFromTrack.globalIndex()) != seenMcParticlesVector.end()) { + registry.fill(HIST("h3_track_pt_track_eta_track_phi_associatedtrack_split_nonprimary"), track.pt(), track.eta(), track.phi()); + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_associatedtrack_split_nonprimary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi()); + + registry.fill(HIST("h3_track_pt_high_track_eta_track_phi_associatedtrack_split_nonprimary"), track.pt(), track.eta(), track.phi()); + registry.fill(HIST("h3_particle_pt_high_particle_eta_particle_phi_associatedtrack_split_nonprimary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi()); + } else { + seenMcParticlesVector.push_back(jMcParticleFromTrack.globalIndex()); + } + + continue; + } + + registry.fill(HIST("hTrackCutsCounts"), 3.5); + + registry.fill(HIST("h3_track_pt_track_eta_track_phi_associatedtrack_primary"), track.pt(), track.eta(), track.phi()); + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_associatedtrack_primary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi()); + registry.fill(HIST("h2_particle_pt_track_pt_residual_associatedtrack_primary"), jMcParticleFromTrack.pt(), (jMcParticleFromTrack.pt() - track.pt()) / jMcParticleFromTrack.pt()); + + registry.fill(HIST("h3_track_pt_high_track_eta_track_phi_associatedtrack_primary"), track.pt(), track.eta(), track.phi()); + registry.fill(HIST("h3_particle_pt_high_particle_eta_particle_phi_associatedtrack_primary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi()); + registry.fill(HIST("h2_particle_pt_high_track_pt_high_residual_associatedtrack_primary"), jMcParticleFromTrack.pt(), (jMcParticleFromTrack.pt() - track.pt()) / jMcParticleFromTrack.pt()); + + if (std::find(seenMcParticlesVector.begin(), seenMcParticlesVector.end(), jMcParticleFromTrack.globalIndex()) != seenMcParticlesVector.end()) { + registry.fill(HIST("h3_track_pt_track_eta_track_phi_associatedtrack_split_primary"), track.pt(), track.eta(), track.phi()); + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_associatedtrack_split_primary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi()); + + registry.fill(HIST("h3_track_pt_high_track_eta_track_phi_associatedtrack_split_primary"), track.pt(), track.eta(), track.phi()); + registry.fill(HIST("h3_particle_pt_high_particle_eta_particle_phi_associatedtrack_split_primary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi()); + } else { + seenMcParticlesVector.push_back(jMcParticleFromTrack.globalIndex()); + } + + if (abs(jMcParticleFromTrack.eta()) < trackEtaAcceptanceCountQA) { // not actually applied here but it will give an idea of what will be done in the post processing + registry.fill(HIST("hTrackCutsCounts"), 4.5); + } + } + } + } + PROCESS_SWITCH(TrackEfficiencyJets, processEFficiencyPurity, "Histograms for efficiency and purity quantities", true); + + void processTracks(soa::Filtered::iterator const& collision, + soa::Filtered> const& tracks) + { + registry.fill(HIST("h_collisions"), 0.5); + registry.fill(HIST("h2_centrality_collisions"), collision.centrality(), 0.5); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + registry.fill(HIST("h_collisions"), 1.5); + registry.fill(HIST("h2_centrality_collisions"), collision.centrality(), 1.5); + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + registry.fill(HIST("h_collisions"), 2.5); + registry.fill(HIST("h2_centrality_collisions"), collision.centrality(), 2.5); + fillTrackHistograms(collision, tracks); + } + PROCESS_SWITCH(TrackEfficiencyJets, processTracks, "QA for charged tracks", false); + + void processTracksWeighted(soa::Join::iterator const& collision, + aod::JetMcCollisions const&, + soa::Filtered> const& tracks) + { + if (!collision.has_mcCollision()) { // the collision is fake and has no associated mc coll; skip as .mccollision() cannot be called + registry.fill(HIST("h_fakecollisions"), 0.5); + return; + } + float eventWeight = collision.mcCollision().weight(); + registry.fill(HIST("h_collisions"), 0.5); + registry.fill(HIST("h_collisions_weighted"), 0.5, eventWeight); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + registry.fill(HIST("h_collisions"), 1.5); + registry.fill(HIST("h_collisions_weighted"), 1.5, eventWeight); + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + registry.fill(HIST("h_collisions"), 2.5); + registry.fill(HIST("h_collisions_weighted"), 2.5, eventWeight); + fillTrackHistograms(collision, tracks, eventWeight); + } + PROCESS_SWITCH(TrackEfficiencyJets, processTracksWeighted, "QA for charged tracks weighted", false); + + void processParticles(aod::JetMcCollision const& mcCollision, + soa::SmallGroups const& collisions, + soa::Filtered const& mcparticles) + { + registry.fill(HIST("h_mccollisions"), 0.5); + registry.fill(HIST("h2_centrality_mccollisions"), collisions.begin().centrality(), 0.5); + + if (!(abs(mcCollision.posZ()) < vertexZCut)) { + return; + } + if (collisions.size() < 1) { + return; + } + if (acceptSplitCollisions == 0 && collisions.size() > 1) { + return; + } + + bool hasSel8Coll = false; + bool centralityCheck = false; + if (acceptSplitCollisions == 2) { // check only that the first reconstructed collision passes the check + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split + hasSel8Coll = true; + } + if (!checkCentrality || ((centralityMin < collisions.begin().centrality()) && (collisions.begin().centrality() < centralityMax))) { // effect unclear if mcColl is split + centralityCheck = true; + } + } else { // check that at least one of the reconstructed collisions passes the checks + for (auto& collision : collisions) { + if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split + hasSel8Coll = true; + } + if (!checkCentrality || ((centralityMin < collision.centrality()) && (collision.centrality() < centralityMax))) { // effect unclear if mcColl is split + centralityCheck = true; + } + } + } + if (!hasSel8Coll) { + return; + } + if (!centralityCheck) { + return; + } + + registry.fill(HIST("h_mccollisions"), 1.5); + registry.fill(HIST("h2_centrality_mccollisions"), collisions.begin().centrality(), 1.5); + fillParticlesHistograms(collisions.begin(), mcparticles); + } + PROCESS_SWITCH(TrackEfficiencyJets, processParticles, "QA for charged particles", false); + + void processParticlesWeighted(aod::JetMcCollision const& mcCollision, + soa::SmallGroups const& collisions, + soa::Filtered const& mcparticles) + { + if (skipMBGapEvents && mcCollision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + + float eventWeight = mcCollision.weight(); + registry.fill(HIST("h_mccollisions"), 0.5); + registry.fill(HIST("h_mccollisions_weighted"), 0.5, eventWeight); + + if (!(abs(mcCollision.posZ()) < vertexZCut)) { + return; + } + if (collisions.size() < 1) { + return; + } + if (acceptSplitCollisions == 0 && collisions.size() > 1) { + return; + } + + bool hasSel8Coll = false; + bool centralityCheck = false; + if (acceptSplitCollisions == 2) { // check only that the first reconstructed collision passes the check + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split + hasSel8Coll = true; + } + if (!checkCentrality || ((centralityMin < collisions.begin().centrality()) && (collisions.begin().centrality() < centralityMax))) { // effect unclear if mcColl is split + centralityCheck = true; + } + } else { // check that at least one of the reconstructed collisions passes the checks + for (auto& collision : collisions) { + if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split + hasSel8Coll = true; + } + if (!checkCentrality || ((centralityMin < collision.centrality()) && (collision.centrality() < centralityMax))) { // effect unclear if mcColl is split + centralityCheck = true; + } + } + } + if (!hasSel8Coll) { + return; + } + if (!centralityCheck) { + return; + } + + registry.fill(HIST("h_mccollisions"), 1.5); + registry.fill(HIST("h_mccollisions_weighted"), 1.5, eventWeight); + fillParticlesHistograms(collisions.begin(), mcparticles, eventWeight); + } + PROCESS_SWITCH(TrackEfficiencyJets, processParticlesWeighted, "QA for charged particles weighted", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"track-efficiency"})}; } diff --git a/PWGJE/Tasks/trackJetqa.cxx b/PWGJE/Tasks/trackJetQA.cxx similarity index 86% rename from PWGJE/Tasks/trackJetqa.cxx rename to PWGJE/Tasks/trackJetQA.cxx index 9477f88d66e..a66bc0e8c0d 100644 --- a/PWGJE/Tasks/trackJetqa.cxx +++ b/PWGJE/Tasks/trackJetQA.cxx @@ -82,6 +82,9 @@ struct TrackJetQa { ConfigurableAxis binsDcaZ{"binsDcaZ", {100, -5, 5}, "Binning for the dcaXY axis"}; ConfigurableAxis binsLength{"binsLength", {200, 0, 1000}, "Binning for the track length axis"}; + Filter ptFilter = (aod::track::pt >= minPt) && (aod::track::pt <= maxPt); + Filter etaFilter = (aod::track::eta <= ValCutEta) && (aod::track::eta >= -ValCutEta); + void init(o2::framework::InitContext&) { if (customTrack) { @@ -171,7 +174,7 @@ struct TrackJetQa { histos.add("TrackPar/xyz", "track #it{x}, #it{y}, #it{z} position at dca in local coordinate system", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisTrackX, axisTrackY, axisTrackZ, axisPercentileFT0A, axisPercentileFT0C}); histos.add("TrackPar/alpha", "rotation angle of local wrt. global coordinate system", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisRotation, axisPercentileFT0A, axisPercentileFT0C}); histos.add("TrackPar/signed1Pt", "track signed 1/#it{p}_{T}", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisSignedPt, axisPercentileFT0A, axisPercentileFT0C}); - histos.add("TrackPar/snp", "sinus of track momentum azimuthal angle (snp)", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, {11, -0.05, 0.5, "snp"}, axisPercentileFT0A, axisPercentileFT0C}); + histos.add("TrackPar/snp", "sinus of track momentum azimuthal angle (snp)", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, {50, -0.5, 0.5, "snp"}, axisPercentileFT0A, axisPercentileFT0C}); histos.add("TrackPar/tgl", "tangent of the track momentum dip angle (tgl)", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, {200, -1., 1., "tgl"}, axisPercentileFT0A, axisPercentileFT0C}); histos.add("TrackPar/flags", "track flag;#it{p}_{T} [GeV/c];flag bit", {HistType::kTH2F, {{200, 0, 200}, {64, -0.5, 63.5}}}); histos.add("TrackPar/dcaXY", "distance of closest approach in #it{xy} plane", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisDcaXY, axisPercentileFT0A, axisPercentileFT0C}); @@ -180,16 +183,21 @@ struct TrackJetQa { histos.add("TrackPar/Sigma1Pt", "uncertainty over #it{p}_{T}", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); histos.add("TrackPar/Sigma1Pt_hasTRD", "uncertainty over #it{p}_{T} for tracks with TRD", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); histos.add("TrackPar/Sigma1Pt_hasNoTRD", "uncertainty over #it{p}_{T} for tracks without TRD", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); - histos.add("TrackPar/Sigma1Pt_Layer1", "uncertainty over #it{p}_{T} with only 1st ITS layer active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); - histos.add("TrackPar/Sigma1Pt_Layer2", "uncertainty over #it{p}_{T} with only 2nd ITS layer active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); - histos.add("TrackPar/Sigma1Pt_Layers12", "uncertainty over #it{p}_{T} with only 1st and 2nd ITS layers active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); - histos.add("TrackPar/Sigma1Pt_Layer4", "uncertainty over #it{p}_{T} with only 4th ITS layer active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); - histos.add("TrackPar/Sigma1Pt_Layer5", "uncertainty over #it{p}_{T} with only 5th ITS layer active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); - histos.add("TrackPar/Sigma1Pt_Layer6", "uncertainty over #it{p}_{T} with only 6th ITS layer active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); - histos.add("TrackPar/Sigma1Pt_Layers45", "uncertainty over #it{p}_{T} with only 4th and 5th ITS layers active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); - histos.add("TrackPar/Sigma1Pt_Layers56", "uncertainty over #it{p}_{T} with only 5th and 6th ITS layers active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); - histos.add("TrackPar/Sigma1Pt_Layers46", "uncertainty over #it{p}_{T} with only 4th and 6th ITS layers active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); - histos.add("TrackPar/Sigma1Pt_Layers456", "uncertainty over #it{p}_{T} with only 4th, 5th and 6th ITS layers active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); + histos.add("TrackPar/Sigma1Pt_Layer1", "uncertainty over #it{p}_{T} with 1st ITS layer active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); + histos.add("TrackPar/Sigma1Pt_Layer2", "uncertainty over #it{p}_{T} with 2nd ITS layer active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); + histos.add("TrackPar/Sigma1Pt_Layer3", "uncertainty over #it{p}_{T} with 3rd ITS layer active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); + histos.add("TrackPar/Sigma1Pt_Layer4", "uncertainty over #it{p}_{T} with 4th ITS layer active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); + histos.add("TrackPar/Sigma1Pt_Layer5", "uncertainty over #it{p}_{T} with 5th ITS layer active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); + histos.add("TrackPar/Sigma1Pt_Layer6", "uncertainty over #it{p}_{T} with 6th ITS layer active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); + histos.add("TrackPar/Sigma1Pt_Layer7", "uncertainty over #it{p}_{T} with 7th ITS layer active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); + histos.add("TrackPar/Sigma1Pt_Layers12", "uncertainty over #it{p}_{T} with 1st and 2nd ITS layers active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); + histos.add("TrackPar/Sigma1Pt_Layers34", "uncertainty over #it{p}_{T} with 3rd and 4th ITS layers active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); + histos.add("TrackPar/Sigma1Pt_Layers45", "uncertainty over #it{p}_{T} with 4th and 5th ITS layers active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); + histos.add("TrackPar/Sigma1Pt_Layers56", "uncertainty over #it{p}_{T} with 5th and 6th ITS layers active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); + histos.add("TrackPar/Sigma1Pt_Layers67", "uncertainty over #it{p}_{T} with 6th and 7th ITS layers active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); + histos.add("TrackPar/Sigma1Pt_Layers1or2and7", "uncertainty over #it{p}_{T} with 1st or 2nd and 7th ITS layers active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); + histos.add("TrackPar/Sigma1Pt_Layers1or2and6or7", "uncertainty over #it{p}_{T} with 1st or 2nd and 6th or 7th ITS layers active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); + histos.add("TrackPar/Sigma1Pt_Layers456", "uncertainty over #it{p}_{T} with 4th, 5th and 6th ITS layers active", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, axisPercentileFT0A, axisPercentileFT0C}); // ITS histograms histos.add("ITS/itsNCls", "number of found ITS clusters", HistType::kTHnSparseD, {axisPt, axisSigma1OverPt, {8, -0.5, 7.5, "# clusters ITS"}, axisPercentileFT0A, axisPercentileFT0C}); @@ -276,17 +284,20 @@ struct TrackJetQa { //// check the uncertainty over pT activating several ITS layers bool firstLayerActive = track.itsClusterMap() & (1 << 0); bool secondLayerActive = track.itsClusterMap() & (1 << 1); + bool thirdLayerActive = track.itsClusterMap() & (1 << 2); bool fourthLayerActive = track.itsClusterMap() & (1 << 3); bool fifthLayerActive = track.itsClusterMap() & (1 << 4); bool sixthLayerActive = track.itsClusterMap() & (1 << 5); + bool seventhLayerActive = track.itsClusterMap() & (1 << 6); + if (firstLayerActive) { histos.fill(HIST("TrackPar/Sigma1Pt_Layer1"), track.pt(), track.sigma1Pt() * track.pt(), collision.centFT0A(), collision.centFT0C()); } if (secondLayerActive) { histos.fill(HIST("TrackPar/Sigma1Pt_Layer2"), track.pt(), track.sigma1Pt() * track.pt(), collision.centFT0A(), collision.centFT0C()); } - if (firstLayerActive && secondLayerActive) { - histos.fill(HIST("TrackPar/Sigma1Pt_Layers12"), track.pt(), track.sigma1Pt() * track.pt(), collision.centFT0A(), collision.centFT0C()); + if (thirdLayerActive) { + histos.fill(HIST("TrackPar/Sigma1Pt_Layer3"), track.pt(), track.sigma1Pt() * track.pt(), collision.centFT0A(), collision.centFT0C()); } if (fourthLayerActive) { histos.fill(HIST("TrackPar/Sigma1Pt_Layer4"), track.pt(), track.sigma1Pt() * track.pt(), collision.centFT0A(), collision.centFT0C()); @@ -297,14 +308,29 @@ struct TrackJetQa { if (sixthLayerActive) { histos.fill(HIST("TrackPar/Sigma1Pt_Layer6"), track.pt(), track.sigma1Pt() * track.pt(), collision.centFT0A(), collision.centFT0C()); } + if (seventhLayerActive) { + histos.fill(HIST("TrackPar/Sigma1Pt_Layer7"), track.pt(), track.sigma1Pt() * track.pt(), collision.centFT0A(), collision.centFT0C()); + } + if (firstLayerActive && secondLayerActive) { + histos.fill(HIST("TrackPar/Sigma1Pt_Layers12"), track.pt(), track.sigma1Pt() * track.pt(), collision.centFT0A(), collision.centFT0C()); + } + if (thirdLayerActive && fourthLayerActive) { + histos.fill(HIST("TrackPar/Sigma1Pt_Layers34"), track.pt(), track.sigma1Pt() * track.pt(), collision.centFT0A(), collision.centFT0C()); + } if (fourthLayerActive && fifthLayerActive) { histos.fill(HIST("TrackPar/Sigma1Pt_Layers45"), track.pt(), track.sigma1Pt() * track.pt(), collision.centFT0A(), collision.centFT0C()); } if (fifthLayerActive && sixthLayerActive) { histos.fill(HIST("TrackPar/Sigma1Pt_Layers56"), track.pt(), track.sigma1Pt() * track.pt(), collision.centFT0A(), collision.centFT0C()); } - if (fourthLayerActive && sixthLayerActive) { - histos.fill(HIST("TrackPar/Sigma1Pt_Layers46"), track.pt(), track.sigma1Pt() * track.pt(), collision.centFT0A(), collision.centFT0C()); + if (sixthLayerActive && seventhLayerActive) { + histos.fill(HIST("TrackPar/Sigma1Pt_Layers67"), track.pt(), track.sigma1Pt() * track.pt(), collision.centFT0A(), collision.centFT0C()); + } + if ((firstLayerActive || secondLayerActive) && seventhLayerActive) { + histos.fill(HIST("TrackPar/Sigma1Pt_Layers1or2and7"), track.pt(), track.sigma1Pt() * track.pt(), collision.centFT0A(), collision.centFT0C()); + } + if ((firstLayerActive || secondLayerActive) && (sixthLayerActive || seventhLayerActive)) { + histos.fill(HIST("TrackPar/Sigma1Pt_Layers1or2and6or7"), track.pt(), track.sigma1Pt() * track.pt(), collision.centFT0A(), collision.centFT0C()); } if (fourthLayerActive && fifthLayerActive && sixthLayerActive) { histos.fill(HIST("TrackPar/Sigma1Pt_Layers456"), track.pt(), track.sigma1Pt() * track.pt(), collision.centFT0A(), collision.centFT0C()); @@ -332,7 +358,7 @@ struct TrackJetQa { using TrackCandidates = soa::Join; void processFull(CollisionCandidate const& collisions, - TrackCandidates const& tracks) + soa::Filtered const& tracks) { for (const auto& collision : collisions) { auto tracksInCollision = tracks.sliceBy(trackPerColl, collision.globalIndex()); diff --git a/PWGJE/Tasks/triggerCorrelations.cxx b/PWGJE/Tasks/triggerCorrelations.cxx index e215bae706e..bb2d43e1f95 100644 --- a/PWGJE/Tasks/triggerCorrelations.cxx +++ b/PWGJE/Tasks/triggerCorrelations.cxx @@ -44,79 +44,31 @@ struct TriggerCorrelationsTask { HistogramRegistry registry; - int nChTrigs; - int nFullTrigs; - int nChHFTrigs; - int nAllTrigs; - - int chTrigOffset; - int fullTrigOffset; - int chHFTrigOffset; - + std::vector triggerMaskBits; void init(o2::framework::InitContext&) { - std::vector trigSelChLabels = {"chargedLow", "chargedHigh", "trackLowPt", "trackHighPt"}; - std::vector trigSelFullLabels = {"fullHigh", "fullLow", "neutralHigh", "neutralLow", "gammaVeryHighEMCAL", "gammaHighEMCAL", "gammaLowEMCAL", "gammaVeryLowEMCAL", "gammaVeryHighDCAL", "gammaHighDCAL", "gammaLowDCAL", "gammaVeryLowDCAL"}; - std::vector trigSelChHFLabels = {"chargedD0Low", "chargedD0High", "chargedLcLow", "chargedLcHigh"}; - nChTrigs = trigSelChLabels.size(); - nFullTrigs = trigSelFullLabels.size(); - nChHFTrigs = trigSelChHFLabels.size(); - nAllTrigs = nChTrigs + nFullTrigs + nChHFTrigs; - chTrigOffset = 0; - fullTrigOffset = chTrigOffset + nChTrigs; - chHFTrigOffset = fullTrigOffset + nFullTrigs; - registry.add("triggerCorrelations", "Correlation between jet triggers", HistType::kTH2D, {{nAllTrigs, -0.5, static_cast(nAllTrigs) - 0.5, "primary trigger"}, {nAllTrigs, -0.5, static_cast(nAllTrigs) - 0.5, "secondary trigger"}}); + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(jetderiveddatautilities::JTriggerMasks); + + std::vector trigSelLabels = {"JetChLowPt", "JetChHighPt", "TrackLowPt", "TrackHighPt", "JetD0ChLowPt", "JetD0ChHighPt", "JetLcChLowPt", "JetLcChHighPt", "EMCALReadout", "JetFullHighPt", "JetFullLowPt", "JetNeutralHighPt", "JetNeutralLowPt", "GammaVeryHighPtEMCAL", "GammaVeryHighPtDCAL", "GammaHighPtEMCAL", "GammaHighPtDCAL", "GammaLowPtEMCAL", "GammaLowPtDCAL", "GammaVeryLowPtEMCAL", "GammaVeryLowPtDCAL"}; + registry.add("triggerCorrelations", "Correlation between jet triggers", HistType::kTH2D, {{static_cast(trigSelLabels.size()), -0.5, static_cast(trigSelLabels.size()) - 0.5, "primary trigger"}, {static_cast(trigSelLabels.size()), -0.5, static_cast(trigSelLabels.size()) - 0.5, "secondary trigger"}}); auto triggerCorrelation = registry.get(HIST("triggerCorrelations")); - for (auto iChTrigs = 0; iChTrigs < nChTrigs; iChTrigs++) { - triggerCorrelation->GetXaxis()->SetBinLabel(iChTrigs + chTrigOffset + 1, trigSelChLabels[iChTrigs].data()); - triggerCorrelation->GetYaxis()->SetBinLabel(iChTrigs + chTrigOffset + 1, trigSelChLabels[iChTrigs].data()); - } - for (auto iFullTrigs = 0; iFullTrigs < nFullTrigs; iFullTrigs++) { - triggerCorrelation->GetXaxis()->SetBinLabel(iFullTrigs + fullTrigOffset + 1, trigSelFullLabels[iFullTrigs].data()); - triggerCorrelation->GetYaxis()->SetBinLabel(iFullTrigs + fullTrigOffset + 1, trigSelFullLabels[iFullTrigs].data()); - } - for (auto iChHFTrigs = 0; iChHFTrigs < nChHFTrigs; iChHFTrigs++) { - triggerCorrelation->GetXaxis()->SetBinLabel(iChHFTrigs + chHFTrigOffset + 1, trigSelChHFLabels[iChHFTrigs].data()); - triggerCorrelation->GetYaxis()->SetBinLabel(iChHFTrigs + chHFTrigOffset + 1, trigSelChHFLabels[iChHFTrigs].data()); + for (std::vector::size_type iTrigs = 0; iTrigs < trigSelLabels.size(); iTrigs++) { + triggerCorrelation->GetXaxis()->SetBinLabel(iTrigs + 1, trigSelLabels[iTrigs].data()); + triggerCorrelation->GetYaxis()->SetBinLabel(iTrigs + 1, trigSelLabels[iTrigs].data()); } } template - void fillCorrelationsHistogram(T const& collision, bool fill = false, int iTrig = -1) + void fillCorrelationsHistogram(T const& collision, bool fill = false, int iCurrentTrig = -1) { - - for (auto iChTrigs = 0; iChTrigs < nChTrigs; iChTrigs++) { - if (fill) { - if (jetderiveddatautilities::selectChargedTrigger(collision, iChTrigs + 1)) { - registry.fill(HIST("triggerCorrelations"), iTrig, iChTrigs + chTrigOffset); - } - } else { - if (jetderiveddatautilities::selectChargedTrigger(collision, iChTrigs + 1)) { - fillCorrelationsHistogram(collision, true, iChTrigs + chTrigOffset); - } - } - } - - for (auto iFullTrigs = 0; iFullTrigs < nFullTrigs; iFullTrigs++) { - if (fill) { - if (jetderiveddatautilities::selectFullTrigger(collision, iFullTrigs + 1)) { - registry.fill(HIST("triggerCorrelations"), iTrig, iFullTrigs + fullTrigOffset); - } - } else { - if (jetderiveddatautilities::selectFullTrigger(collision, iFullTrigs + 1)) { - fillCorrelationsHistogram(collision, true, iFullTrigs + fullTrigOffset); - } - } - } - - for (auto iChHFTrigs = 0; iChHFTrigs < nFullTrigs; iChHFTrigs++) { + for (std::vector::size_type iTrig = 0; iTrig < triggerMaskBits.size(); iTrig++) { if (fill) { - if (jetderiveddatautilities::selectChargedHFTrigger(collision, iChHFTrigs + 1)) { - registry.fill(HIST("triggerCorrelations"), iTrig, iChHFTrigs + chHFTrigOffset); + if (jetderiveddatautilities::selectTrigger(collision, triggerMaskBits[iTrig])) { + registry.fill(HIST("triggerCorrelations"), iCurrentTrig, iTrig); } } else { - if (jetderiveddatautilities::selectChargedHFTrigger(collision, iChHFTrigs + 1)) { - fillCorrelationsHistogram(collision, true, iChHFTrigs + chHFTrigOffset); + if (jetderiveddatautilities::selectTrigger(collision, triggerMaskBits[iTrig])) { + fillCorrelationsHistogram(collision, true, iTrig); } } } diff --git a/PWGJE/Tasks/v0JetSpectra.cxx b/PWGJE/Tasks/v0JetSpectra.cxx new file mode 100644 index 00000000000..700f0b33b54 --- /dev/null +++ b/PWGJE/Tasks/v0JetSpectra.cxx @@ -0,0 +1,152 @@ +// 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 Jet spectra for ch+V0 jets +/// +/// \author Gijs van Weelden +// + +#include +#include + +#include "TH1F.h" +#include "TTree.h" + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/RunningWorkflowInfo.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" + +#include "CommonConstants/PhysicsConstants.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using MCDJets = aod::ChargedMCDetectorLevelJets; +using MCDJetsWithConstituents = soa::Join; +using MatchedMCDJets = soa::Join; +using MatchedMCDJetsWithConstituents = soa::Join; + +using MCPJets = aod::ChargedMCParticleLevelJets; +using MatchedMCPJets = soa::Join; +using MCPJetsWithConstituents = soa::Join; +using MatchedMCPJetsWithConstituents = soa::Join; + +// V0 jets +using MCDV0Jets = aod::V0ChargedMCDetectorLevelJets; +using MCDV0JetsWithConstituents = soa::Join; +using MatchedMCDV0Jets = soa::Join; +using MatchedMCDV0JetsWithConstituents = soa::Join; + +using MCPV0Jets = aod::V0ChargedMCParticleLevelJets; +using MCPV0JetsWithConstituents = soa::Join; +using MatchedMCPV0Jets = soa::Join; +using MatchedMCPV0JetsWithConstituents = soa::Join; + +struct V0JetSpectra { + HistogramRegistry registry{"registry"}; + + Configurable evSel{"evSel", "sel8WithoutTimeFrameBorderCut", "choose event selection"}; + Configurable vertexZCut{"vertexZCut", 10.f, "vertex z cut"}; + std::vector eventSelectionBits; + + Filter jetCollisionFilter = nabs(aod::jcollision::posZ) < vertexZCut; + + void init(InitContext&) + { + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(evSel)); + registry.add("jetPtEtaPhi", "Jets; #it{p}_{T}; #eta; #phi", HistType::kTH3D, {{200, 0., 200.}, {20, -1.f, 1.f}, {18 * 8, 0.f, 2. * TMath::Pi()}}); + registry.add("mcpJetPtEtaPhi", "Jets; #it{p}_{T}; #eta; #phi", HistType::kTH3D, {{200, 0., 200.}, {20, -1.f, 1.f}, {18 * 8, 0.f, 2. * TMath::Pi()}}); + } + + template + void fillHistograms(T const& jets, double weight = 1.) + { + for (const auto& jet : jets) { + registry.fill(HIST("jetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi(), weight); + } + } + template + void fillMCPHistograms(T const& jets, double weight = 1.) + { + for (const auto& jet : jets) { + registry.fill(HIST("mcpJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi(), weight); + } + } + + void processData(soa::Filtered::iterator const& jcoll, aod::ChargedJets const& chjets, aod::V0ChargedJets const& v0jets) + { + if (!jetderiveddatautilities::selectCollision(jcoll, eventSelectionBits)) { + return; + } + if (v0jets.size() == 0) { + fillHistograms(chjets); + } + } + PROCESS_SWITCH(V0JetSpectra, processData, "Jet spectra for V0 jets or Ch jets if no V0s in data", false); + + void processMCD(soa::Filtered::iterator const& jcoll, aod::JetMcCollisions const&, MCDJets const& chjets, MCDV0Jets const& v0jets) + { + if (!jcoll.has_mcCollision()) { + return; + } + if (!jetderiveddatautilities::selectCollision(jcoll, eventSelectionBits)) { + return; + } + double weight = jcoll.mcCollision().weight(); + if (v0jets.size() == 0) { + fillHistograms(chjets, weight); + } + } + PROCESS_SWITCH(V0JetSpectra, processMCD, "Jet spectra for V0 jets or Ch jets if no V0s", false); + + void processMCP(aod::JetMcCollision const& jcoll, MCPJets const& chjets, MCPV0Jets const& v0jets) + { + double weight = jcoll.weight(); + if (v0jets.size() == 0) { + fillMCPHistograms(chjets, weight); + } + } + PROCESS_SWITCH(V0JetSpectra, processMCP, "Jet spectra for V0 jets or Ch jets if no V0s", false); + + void processMcMatched(soa::Filtered::iterator const& jcoll, aod::JetMcCollisions const&, MatchedMCDJets const& chjetsMCD, MatchedMCPJets const& chjetsMCP, MatchedMCDV0Jets const& v0jetsMCD, MatchedMCPV0Jets const& v0jetsMCP) + { + if (!jetderiveddatautilities::selectCollision(jcoll, eventSelectionBits)) { + return; + } + // TODO: Need to add checker to only count matched jets (?) + double weight = jcoll.mcCollision().weight(); + if (v0jetsMCP.size() == 0) { + fillMCPHistograms(chjetsMCP, weight); + } // Particle level loop + + if (v0jetsMCD.size() == 0) { + fillHistograms(chjetsMCD, weight); + } // Detector level loop + } + PROCESS_SWITCH(V0JetSpectra, processMcMatched, "Jet spectra for matched ch jets if no V0s", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"jet-v0-spectra"})}; +} diff --git a/PWGJE/Tasks/v0QA.cxx b/PWGJE/Tasks/v0QA.cxx new file mode 100644 index 00000000000..6966c3b0101 --- /dev/null +++ b/PWGJE/Tasks/v0QA.cxx @@ -0,0 +1,1243 @@ +// 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 v0QA.cxx +/// \brief QA task for V0s in the jets framework, based on the LF v0cascadesqa task +/// +/// \author Gijs van Weelden + +#include +#include + +#include "TH1F.h" +#include "TTree.h" + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/RunningWorkflowInfo.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" + +#include "CommonConstants/PhysicsConstants.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGLF/DataModel/V0SelectorTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// V0 jets +using MCDV0Jets = aod::V0ChargedMCDetectorLevelJets; +using MCDV0JetsWithConstituents = soa::Join; +using MatchedMCDV0Jets = soa::Join; +using MatchedMCDV0JetsWithConstituents = soa::Join; + +using CandidatesV0MCDWithFlags = soa::Join; + +using MCPV0Jets = aod::V0ChargedMCParticleLevelJets; +using MCPV0JetsWithConstituents = soa::Join; +using MatchedMCPV0Jets = soa::Join; +using MatchedMCPV0JetsWithConstituents = soa::Join; + +struct V0QA { + HistogramRegistry registry{"registry"}; + + Configurable evSel{"evSel", "sel8WithoutTimeFrameBorderCut", "choose event selection"}; + Configurable v0cospaMin{"v0cospaMin", 0.995, "Minimum V0 cosine of pointing angle"}; + Configurable v0radiusMin{"v0radiusMin", 0.5, "Minimum V0 radius (cm)"}; + Configurable dcav0dauMax{"dcav0dauMax", 1.0, "Maximum DCA between V0 daughters (cm)"}; + Configurable dcapiMin{"dcapiMin", 0.1, "Minimum DCA of pion daughter to PV (cm)"}; + Configurable dcaprMin{"dcaprMin", 0.1, "Minimum DCA of proton daughter to PV (cm)"}; + Configurable yK0SMax{"yK0SMax", 0.5, "Maximum rapidity of K0S"}; + Configurable yLambdaMax{"yLambdaMax", 0.5, "Maximum rapidity of Lambda(bar)"}; + Configurable lifetimeK0SMax{"lifetimeK0SMax", 20.0, "Maximum lifetime of K0S (cm)"}; + Configurable lifetimeLambdaMax{"lifetimeLambdaMax", 30.0, "Maximum lifetime of Lambda (cm)"}; + Configurable yPartMax{"yPartMax", 0.5, "Maximum rapidity of particles"}; + Configurable vertexZCut{"vertexZCut", 10.0, "Vertex Z cut"}; + + Filter jetCollisionFilter = nabs(aod::jcollision::posZ) < vertexZCut; + + ConfigurableAxis binPtJet{"ptJet", {100., 0.0f, 50.0f}, ""}; + ConfigurableAxis binPtV0{"ptV0", {100., 0.0f, 50.0f}, ""}; + ConfigurableAxis binEta{"binEta", {100, -1.0f, 1.0f}, ""}; + ConfigurableAxis binPhi{"binPhi", {constants::math::PI * 10 / 2, 0.0f, constants::math::TwoPI}, ""}; + + ConfigurableAxis binInvMassK0S{"binInvMassK0S", {200, 0.4f, 0.6f}, ""}; + ConfigurableAxis binInvMassLambda{"binInvMassLambda", {200, 1.07f, 1.17f}, ""}; + ConfigurableAxis binV0Radius{"R", {100., 0.0f, 50.0f}, ""}; + ConfigurableAxis binV0CosPA{"cosPA", {50., 0.95f, 1.0f}, ""}; + + ConfigurableAxis binsDcaXY{"binsDcaXY", {100, -0.5f, 0.5f}, ""}; + ConfigurableAxis binsDcaZ{"binsDcaZ", {100, -5.f, 5.f}, ""}; + ConfigurableAxis binPtDiff{"ptdiff", {200., -49.5f, 50.5f}, ""}; + ConfigurableAxis binPtRelDiff{"ptreldiff", {100., -1.0f, 1.0f}, ""}; + ConfigurableAxis binITSNCl{"ITSNCl", {8, -0.5, 7.5}, ""}; + ConfigurableAxis binITSChi2NCl{"ITSChi2NCl", {100, 0, 40}, ""}; + + ConfigurableAxis binTPCNCl{"TPCNCl", {165, -0.5, 164.5}, ""}; + ConfigurableAxis binTPCChi2NCl{"TPCChi2NCl", {100, 0, 10}, ""}; + ConfigurableAxis binTPCNClSharedFraction{"sharedFraction", {100, 0., 1.}, ""}; + ConfigurableAxis binTPCCrossedRowsOverFindableCl{"crossedOverFindable", {120, 0.0, 1.2}, ""}; + + std::vector eventSelectionBits; + + void init(InitContext&) + { + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(evSel)); + + const AxisSpec axisJetPt{binPtJet, "Jet Pt (GeV/c)"}; + const AxisSpec axisV0Pt{binPtV0, "V0 Pt (GeV/c)"}; + const AxisSpec axisEta{binEta, "Eta"}; + const AxisSpec axisPhi{binPhi, "Phi"}; + const AxisSpec axisV0Radius{binV0Radius, "V0 Radius (cm)"}; + const AxisSpec axisV0CosPA{binV0CosPA, "V0 CosPA"}; + const AxisSpec axisK0SM{binInvMassK0S, "M(#pi^{+} #pi^{-}) (GeV/c^{2})"}; + const AxisSpec axisLambdaM{binInvMassLambda, "M(p #pi^{-}) (GeV/c^{2})"}; + const AxisSpec axisAntiLambdaM{binInvMassLambda, "M(#bar{p} #pi^{+}) (GeV/c^{2})"}; + + const AxisSpec axisPtDiff{binPtDiff, "Pt difference (GeV/c)"}; + const AxisSpec axisPtRelDiff{binPtRelDiff, "Pt relative difference"}; + const AxisSpec axisDcaXY{binsDcaXY, "DCA_{xy} (cm)"}; + const AxisSpec axisDcaZ{binsDcaZ, "DCA_{z} (cm)"}; + const AxisSpec axisITSNCl{binITSNCl, "# clusters ITS"}; + const AxisSpec axisITSChi2NCl{binITSChi2NCl, "Chi2 / cluster ITS"}; + + const AxisSpec axisNClFindable{binTPCNCl, "# findable clusters TPC"}; + const AxisSpec axisNClFound{binTPCNCl, "# found clusters TPC"}; + const AxisSpec axisNClShared{binTPCNCl, "# shared clusters TPC"}; + const AxisSpec axisNClCrossedRows{binTPCNCl, "# crossed rows TPC"}; + const AxisSpec axisTPCChi2NCl{binTPCChi2NCl, "Chi2 / cluster TPC"}; + const AxisSpec axisSharedFraction{binTPCNClSharedFraction, "Fraction shared clusters TPC"}; + const AxisSpec axisCrossedRowsOverFindable{binTPCCrossedRowsOverFindableCl, "Crossed rows / findable clusters TPC"}; + + if (doprocessFlags) { + registry.add("inclusive/V0Flags", "V0Flags", HistType::kTH2D, {{5, -0.5, 4.5}, {5, -0.5, 4.5}}); + } + if (doprocessMcD) { + registry.add("inclusive/hEvents", "Events", {HistType::kTH1D, {{2, 0.0f, 2.0f}}}); + registry.add("inclusive/K0SPtEtaMass", "K0S Pt, Eta, Mass", HistType::kTH3D, {axisV0Pt, axisEta, axisK0SM}); + registry.add("inclusive/InvMassK0STrue", "Invariant mass of K0S", HistType::kTH3D, {axisV0Pt, axisV0Radius, axisK0SM}); + registry.add("inclusive/InvMassLambdaTrue", "Invariant mass of Lambda", HistType::kTH3D, {axisV0Pt, axisV0Radius, axisLambdaM}); + registry.add("inclusive/LambdaPtEtaMass", "Lambda Pt, Eta, Mass", HistType::kTH3D, {axisV0Pt, axisEta, axisLambdaM}); + registry.add("inclusive/InvMassAntiLambdaTrue", "Invariant mass of AntiLambda", HistType::kTH3D, {axisV0Pt, axisV0Radius, axisAntiLambdaM}); + registry.add("inclusive/AntiLambdaPtEtaMass", "AntiLambda Pt, Eta, Mass", HistType::kTH3D, {axisV0Pt, axisEta, axisAntiLambdaM}); + } + if (doprocessMcP) { + registry.add("inclusive/hMcEvents", "MC Events", {HistType::kTH1D, {{2, 0.0f, 2.0f}}}); + registry.add("inclusive/GeneratedK0S", "Generated K0S", HistType::kTH3D, {axisV0Pt, axisEta, axisV0Radius}); + registry.add("inclusive/GeneratedLambda", "Generated Lambda", HistType::kTH3D, {axisV0Pt, axisEta, axisV0Radius}); + registry.add("inclusive/GeneratedAntiLambda", "Generated AntiLambda", HistType::kTH3D, {axisV0Pt, axisEta, axisV0Radius}); + } + if (doprocessMcDJets) { + registry.add("jets/hJetEvents", "Jet Events", {HistType::kTH1D, {{2, 0.0f, 2.0f}}}); + registry.add("jets/JetPtEtaK0SPt", "Jet Pt, Eta, K0S Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("jets/InvMassJetK0STrue", "Invariant mass of K0S in jets", HistType::kTH3D, {axisJetPt, axisV0Pt, axisK0SM}); + registry.add("jets/JetPtEtaLambdaPt", "Jet Pt, Eta, Lambda Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("jets/InvMassJetLambdaTrue", "Invariant mass of Lambda in jets", HistType::kTH3D, {axisJetPt, axisV0Pt, axisLambdaM}); + registry.add("jets/JetPtEtaAntiLambdaPt", "Jet Pt, Eta, AntiLambda Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("jets/InvMassJetAntiLambdaTrue", "Invariant mass of AntiLambda in jets", HistType::kTH3D, {axisJetPt, axisV0Pt, axisAntiLambdaM}); + } + if (doprocessMcDMatchedJets) { + registry.add("jets/hMatchedJetEvents", "Matched Jet Events", {HistType::kTH1D, {{2, 0.0f, 2.0f}}}); + registry.add("jets/JetsPtEtaK0SPt", "Matched Jet Pt, Eta, K0S Pt", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt}); + registry.add("jets/InvMassJetsK0STrue", "Invariant mass of K0S in matched jets", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisV0Pt, axisK0SM}); + registry.add("jets/JetsPtEtaLambdaPt", "Matched Jet Pt, Eta, Lambda Pt", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt}); + registry.add("jets/InvMassJetsLambdaTrue", "Invariant mass of Lambda in matched jets", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisV0Pt, axisLambdaM}); + registry.add("jets/JetsPtEtaAntiLambdaPt", "Matched Jet Pt, Eta, AntiLambda Pt", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt}); + registry.add("jets/InvMassJetsAntiLambdaTrue", "Invariant mass of AntiLambda in matched jets", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisV0Pt, axisAntiLambdaM}); + } + if (doprocessMcPJets) { + registry.add("jets/hMcJetEvents", "MC Jet Events", {HistType::kTH1D, {{2, 0.0f, 2.0f}}}); + registry.add("jets/GeneratedJetK0S", "Generated Jet K0S", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("jets/GeneratedJetLambda", "Generated Jet Lambda", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("jets/GeneratedJetAntiLambda", "Generated Jet AntiLambda", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + } + if (doprocessCollisionAssociation) { + registry.add("collisions/V0PtEta", "V0 Pt, Eta", HistType::kTH2D, {axisV0Pt, axisEta}); + registry.add("collisions/V0PtEtaWrongColl", "V0 Pt, Eta, wrong collision", HistType::kTH2D, {axisV0Pt, axisEta}); + registry.add("collisions/K0SPtEtaMass", "K0S Pt, Eta, Mass", HistType::kTH3D, {axisV0Pt, axisEta, axisK0SM}); + registry.add("collisions/K0SPtEtaMassWrongColl", "K0S Pt, Eta, Mass, wrong collision", HistType::kTH3D, {axisV0Pt, axisEta, axisK0SM}); + registry.add("collisions/LambdaPtEtaMass", "Lambda Pt, Eta, Mass", HistType::kTH3D, {axisV0Pt, axisEta, axisLambdaM}); + registry.add("collisions/LambdaPtEtaMassWrongColl", "Lambda Pt, Eta, Mass, wrong collision", HistType::kTH3D, {axisV0Pt, axisEta, axisLambdaM}); + registry.add("collisions/AntiLambdaPtEtaMass", "AntiLambda Pt, Eta, Mass", HistType::kTH3D, {axisV0Pt, axisEta, axisAntiLambdaM}); + registry.add("collisions/AntiLambdaPtEtaMassWrongColl", "AntiLambda Pt, Eta, Mass, wrong collision", HistType::kTH3D, {axisV0Pt, axisEta, axisAntiLambdaM}); + + registry.add("collisions/XiMinusPtYLambdaPt", "#Xi^{-} Pt, Y, #Lambda Pt", HistType::kTH3D, {axisV0Pt, axisEta, axisV0Pt}); + registry.add("collisions/XiMinusPtYLambdaPtWrongColl", "#Xi^{-} Pt, Y, #Lambda Pt, wrong collision", HistType::kTH3D, {axisV0Pt, axisEta, axisV0Pt}); + registry.add("collisions/XiPlusPtYAntiLambdaPt", "#Xi^{+} Pt, Y, #bar{#Lambda} Pt", HistType::kTH3D, {axisV0Pt, axisEta, axisV0Pt}); + registry.add("collisions/XiPlusPtYAntiLambdaPtWrongColl", "#Xi^{+} Pt, Y, #bar{#Lambda} Pt, wrong collision", HistType::kTH3D, {axisV0Pt, axisEta, axisV0Pt}); + } + if (doprocessCollisionAssociationJets) { + registry.add("collisions/JetPtEtaV0Pt", "Jet Pt, Eta, V0 Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("collisions/JetPtEtaV0PtWrongColl", "Jet Pt, Eta, V0 Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("collisions/JetPtEtaK0SPtMass", "Jet Pt, Eta, K0S Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisK0SM}); + registry.add("collisions/JetPtEtaK0SPtMassWrongColl", "Jet Pt, Eta, K0S Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisK0SM}); + registry.add("collisions/JetPtEtaLambdaPtMass", "Jet Pt, Eta, Lambda Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisLambdaM}); + registry.add("collisions/JetPtEtaLambdaPtMassWrongColl", "Jet Pt, Eta, Lambda Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisLambdaM}); + registry.add("collisions/JetPtEtaAntiLambdaPtMass", "Jet Pt, Eta, AntiLambda Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisAntiLambdaM}); + registry.add("collisions/JetPtEtaAntiLambdaPtMassWrongColl", "Jet Pt, Eta, AntiLambda Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisAntiLambdaM}); + + registry.add("collisions/JetPtEtaXiMinusPtLambdaPt", "Jet Pt, #Xi^{-} Pt, #Lambda Pt", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + registry.add("collisions/JetPtEtaXiMinusPtLambdaPtWrongColl", "Jet Pt, #Xi^{-} Pt, #Lambda Pt", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + registry.add("collisions/JetPtEtaXiPlusPtAntiLambdaPt", "Jet Pt, #Xi^{+} Pt, #bar{#Lambda} Pt", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + registry.add("collisions/JetPtEtaXiPlusPtAntiLambdaPtWrongColl", "Jet Pt, #Xi^{+} Pt, #bar{#Lambda} Pt", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + } + if (doprocessCollisionAssociationMatchedJets) { + registry.add("collisions/JetsPtEtaV0Pt", "Jets Pt, Eta, V0 Pt", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt}); + registry.add("collisions/JetsPtEtaV0PtWrongColl", "Jets Pt, Eta, V0 Pt", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt}); + registry.add("collisions/JetsPtEtaK0SPtMass", "Jets Pt, Eta, K0S Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt, axisK0SM}); + registry.add("collisions/JetsPtEtaK0SPtMassWrongColl", "Jets Pt, Eta, K0S Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt, axisK0SM}); + registry.add("collisions/JetsPtEtaLambdaPtMass", "Jets Pt, Eta, Lambda Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt, axisLambdaM}); + registry.add("collisions/JetsPtEtaLambdaPtMassWrongColl", "Jets Pt, Eta, Lambda Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt, axisLambdaM}); + registry.add("collisions/JetsPtEtaAntiLambdaPtMass", "Jets Pt, Eta, AntiLambda Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt, axisAntiLambdaM}); + registry.add("collisions/JetsPtEtaAntiLambdaPtMassWrongColl", "Jets Pt, Eta, AntiLambda Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt, axisAntiLambdaM}); + + registry.add("collisions/JetsPtEtaXiMinusPtLambdaPt", "Jets Pt, Eta, #Xi^{-} Pt, #Lambda Pt", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + registry.add("collisions/JetsPtEtaXiMinusPtLambdaPtWrongColl", "Jets Pt, Eta, #Xi^{-} Pt, #Lambda Pt", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + registry.add("collisions/JetsPtEtaXiPlusPtAntiLambdaPt", "Jets Pt, Eta, #Xi^{+} Pt, #bar{#Lambda} Pt", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + registry.add("collisions/JetsPtEtaXiPlusPtAntiLambdaPtWrongColl", "Jets Pt, Eta, #Xi^{+} Pt, #bar{#Lambda} Pt", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + } + if (doprocessFeeddown) { + registry.add("feeddown/XiMinusPtYLambdaPt", "#Xi^{-} Pt, Y, #Lambda Pt", HistType::kTH3D, {axisV0Pt, axisEta, axisV0Pt}); + registry.add("feeddown/XiPlusPtYAntiLambdaPt", "#Xi^{-} Pt, Y, #Lambda Pt", HistType::kTH3D, {axisV0Pt, axisEta, axisV0Pt}); + } + if (doprocessFeeddownJets) { + registry.add("feeddown/JetPtXiMinusPtLambdaPt", "Jets Pt, #Xi^{-} Pt, #Lambda Pt", HistType::kTH3D, {axisJetPt, axisJetPt, axisV0Pt}); + registry.add("feeddown/JetPtXiPlusPtAntiLambdaPt", "Jets Pt, #Xi^{+} Pt, #Lambda Pt", HistType::kTH3D, {axisJetPt, axisJetPt, axisV0Pt}); + } + if (doprocessFeeddownMatchedJets) { + registry.add("feeddown/JetsPtXiMinusPtLambdaPt", "Jets Pt, #Xi^{-} Pt, #Lambda Pt", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisV0Pt, axisV0Pt}); + registry.add("feeddown/JetsPtXiPlusPtAntiLambdaPt", "Jets Pt, #Xi^{+} Pt, #bar{#Lambda} Pt", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisV0Pt, axisV0Pt}); + } + if (doprocessV0TrackQA) { + registry.add("tracks/Pos", "pos", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisEta, axisPhi}); + registry.add("tracks/Neg", "neg", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisEta, axisPhi}); + registry.add("tracks/Pt", "pt", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff, axisPtRelDiff}); + registry.add("tracks/PtMass", "pt mass", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM, axisLambdaM, axisAntiLambdaM}); + registry.add("tracks/PtDiffMass", "ptdiff mass", HistType::kTHnSparseD, {axisV0Pt, axisPtDiff, axisK0SM, axisLambdaM, axisAntiLambdaM}); + + registry.add("tracks/DCAxy", "dcaxy", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisDcaXY, axisDcaXY, axisPtDiff}); + registry.add("tracks/DCAxyMassK0S", "dcaxy mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisDcaXY, axisDcaXY, axisK0SM}); + registry.add("tracks/DCAxyMassLambda0", "dcaxy mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisDcaXY, axisDcaXY, axisLambdaM}); + registry.add("tracks/DCAxyMassAntiLambda0", "dcaxy mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisDcaXY, axisDcaXY, axisAntiLambdaM}); + + registry.add("tracks/DCAz", "dcaz", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisDcaZ, axisDcaZ, axisPtDiff}); + registry.add("tracks/DCAzMassK0S", "dcaz mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisDcaZ, axisDcaZ, axisK0SM}); + registry.add("tracks/DCAzMassLambda0", "dcaz mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisDcaZ, axisDcaZ, axisLambdaM}); + registry.add("tracks/DCAzMassAntiLambda0", "dcaz mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisDcaZ, axisDcaZ, axisAntiLambdaM}); + + registry.add("tracks/V0Radius", "v0 radius", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisV0Radius, axisPtDiff}); + registry.add("tracks/V0RadiusMassK0S", "v0 radius mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisV0Radius, axisK0SM}); + registry.add("tracks/V0RadiusMassLambda0", "v0 radius mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisV0Radius, axisLambdaM}); + registry.add("tracks/V0RadiusMassAntiLambda0", "v0 radius mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisV0Radius, axisAntiLambdaM}); + + registry.add("tracks/V0CosPa", "v0 cos pa", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisV0CosPA, axisPtDiff}); + registry.add("tracks/V0CosPaMassK0S", "v0 cos pa mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisV0CosPA, axisK0SM}); + registry.add("tracks/V0CosPaMassLambda0", "v0 cos pa mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisV0CosPA, axisLambdaM}); + registry.add("tracks/V0CosPaMassAntiLambda0", "v0 cos pa mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisV0CosPA, axisAntiLambdaM}); + + // TRD + registry.add("tracks/posTRDPt", "pos trd pt", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/posTRDPtMass", "pos trd pt mass", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM, axisLambdaM, axisAntiLambdaM}); + registry.add("tracks/posNoTRDPt", "pos no trd pt", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/posNoTRDPtMass", "pos no trd pt mass", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM, axisLambdaM, axisAntiLambdaM}); + + registry.add("tracks/negTRDPt", "neg trd pt", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/negTRDPtMass", "neg trd pt mass", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM, axisLambdaM, axisAntiLambdaM}); + registry.add("tracks/negNoTRDPt", "neg no trd pt", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/negNoTRDPtMass", "neg no trd pt mass", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM, axisLambdaM, axisAntiLambdaM}); + + // ITS: positive track + registry.add("tracks/ITS/posLayer1", "pos layer 1", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/posLayer1MassK0S", "pos layer 1 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/posLayer1MassLambda0", "pos layer 1 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/posLayer1MassAntiLambda0", "pos layer 1 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/posLayer2", "pos layer 2", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/posLayer2MassK0S", "pos layer 2 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/posLayer2MassLambda0", "pos layer 2 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/posLayer2MassAntiLambda0", "pos layer 2 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/posLayer3", "pos layer 3", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/posLayer3MassK0S", "pos layer 3 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/posLayer3MassLambda0", "pos layer 3 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/posLayer3MassAntiLambda0", "pos layer 3 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/posLayer4", "pos layer 4", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/posLayer4MassK0S", "pos layer 4 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/posLayer4MassLambda0", "pos layer 4 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/posLayer4MassAntiLambda0", "pos layer 4 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/posLayer5", "pos layer 5", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/posLayer5MassK0S", "pos layer 5 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/posLayer5MassLambda0", "pos layer 5 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/posLayer5MassAntiLambda0", "pos layer 5 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/posLayer6", "pos layer 6", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/posLayer6MassK0S", "pos layer 6 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/posLayer6MassLambda0", "pos layer 6 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/posLayer6MassAntiLambda0", "pos layer 6 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/posLayer7", "pos layer 7", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/posLayer7MassK0S", "pos layer 7 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/posLayer7MassLambda0", "pos layer 7 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/posLayer7MassAntiLambda0", "pos layer 7 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/posLayer56", "pos layer 56", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/posLayer56MassK0S", "pos layer 56 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/posLayer56MassLambda0", "pos layer 56 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/posLayer56MassAntiLambda0", "pos layer 56 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/posLayer67", "pos layer 67", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/posLayer67MassK0S", "pos layer 67 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/posLayer67MassLambda0", "pos layer 67 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/posLayer67MassAntiLambda0", "pos layer 67 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/posLayer57", "pos layer 57", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/posLayer57MassK0S", "pos layer 57 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/posLayer57MassLambda0", "pos layer 57 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/posLayer57MassAntiLambda0", "pos layer 57 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/posLayer567", "pos layer 567", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/posLayer567MassK0S", "pos layer 567 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/posLayer567MassLambda0", "pos layer 567 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/posLayer567MassAntiLambda0", "pos layer 567 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/posNCl", "pos ncl", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisITSNCl}); + registry.add("tracks/ITS/posChi2NCl", "pos chi2ncl", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisITSChi2NCl}); + + // ITS: Negative track + registry.add("tracks/ITS/negLayer1", "neg layer 1", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/negLayer1MassK0S", "neg layer 1 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/negLayer1MassLambda0", "neg layer 1 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/negLayer1MassAntiLambda0", "neg layer 1 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/negLayer2", "neg layer 2", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/negLayer2MassK0S", "neg layer 2 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/negLayer2MassLambda0", "neg layer 2 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/negLayer2MassAntiLambda0", "neg layer 2 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/negLayer3", "neg layer 3", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/negLayer3MassK0S", "neg layer 3 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/negLayer3MassLambda0", "neg layer 3 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/negLayer3MassAntiLambda0", "neg layer 3 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/negLayer4", "neg layer 4", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/negLayer4MassK0S", "neg layer 4 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/negLayer4MassLambda0", "neg layer 4 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/negLayer4MassAntiLambda0", "neg layer 4 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/negLayer5", "neg layer 5", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/negLayer5MassK0S", "neg layer 5 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/negLayer5MassLambda0", "neg layer 5 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/negLayer5MassAntiLambda0", "neg layer 5 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/negLayer6", "neg layer 6", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/negLayer6MassK0S", "neg layer 6 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/negLayer6MassLambda0", "neg layer 6 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/negLayer6MassAntiLambda0", "neg layer 6 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/negLayer7", "neg layer 7", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/negLayer7MassK0S", "neg layer 7 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/negLayer7MassLambda0", "neg layer 7 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/negLayer7MassAntiLambda0", "neg layer 7 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/negLayer56", "neg layer 56", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/negLayer56MassK0S", "neg layer 56 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/negLayer56MassLambda0", "neg layer 56 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/negLayer56MassAntiLambda0", "neg layer 56 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/negLayer67", "neg layer 67", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/negLayer67MassK0S", "neg layer 67 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/negLayer67MassLambda0", "neg layer 67 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/negLayer67MassAntiLambda0", "neg layer 67 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/negLayer57", "neg layer 57", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/negLayer57MassK0S", "neg layer 57 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/negLayer57MassLambda0", "neg layer 57 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/negLayer57MassAntiLambda0", "neg layer 57 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/negLayer567", "neg layer 567", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisPtDiff}); + registry.add("tracks/ITS/negLayer567MassK0S", "neg layer 567 mass K0S", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisK0SM}); + registry.add("tracks/ITS/negLayer567MassLambda0", "neg layer 567 mass Lambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisLambdaM}); + registry.add("tracks/ITS/negLayer567MassAntiLambda0", "neg layer 567 mass AntiLambda0", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisAntiLambdaM}); + + registry.add("tracks/ITS/negNCl", "neg ncl", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisITSNCl}); + registry.add("tracks/ITS/negChi2NCl", "neg chi2ncl", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisITSChi2NCl}); + + // TPC information + registry.add("tracks/TPC/posNClFindable", "pos ncl findable", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisNClFindable}); + registry.add("tracks/TPC/posNClsFound", "pos ncl found", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisNClFound}); + registry.add("tracks/TPC/posNClsShared", "pos ncl shared", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisNClShared}); + registry.add("tracks/TPC/posNClsCrossedRows", "pos ncl crossed rows", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisNClCrossedRows}); + registry.add("tracks/TPC/posNClsCrossedRowsOverFindableCls", "pos ncl crossed rows over findable cls", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisCrossedRowsOverFindable}); + registry.add("tracks/TPC/posFractionSharedCls", "pos fraction shared cls", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisSharedFraction}); + registry.add("tracks/TPC/posChi2NCl", "pos chi2ncl", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisTPCChi2NCl}); + + registry.add("tracks/TPC/negNClFindable", "neg ncl findable", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisNClFindable}); + registry.add("tracks/TPC/negNClsFound", "neg ncl found", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisNClFound}); + registry.add("tracks/TPC/negNClsShared", "neg ncl shared", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisNClShared}); + registry.add("tracks/TPC/negNClsCrossedRows", "neg ncl crossed rows", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisNClCrossedRows}); + registry.add("tracks/TPC/negNClsCrossedRowsOverFindableCls", "neg ncl crossed rows over findable cls", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisCrossedRowsOverFindable}); + registry.add("tracks/TPC/negFractionSharedCls", "neg fraction shared cls", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisSharedFraction}); + registry.add("tracks/TPC/negChi2NCl", "neg chi2ncl", HistType::kTHnSparseD, {axisV0Pt, axisV0Pt, axisV0Pt, axisTPCChi2NCl}); + } // doprocessV0TrackQA + } // init + + template + bool isCollisionReconstructed(T const& collision, U const& eventSelectionBits) + { + if (!collision.has_mcCollision()) { + return false; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return false; + } + return true; + } + template + bool v0sAreMatched(T const& v0, U const& particle, V const& /*tracks*/) + { + // This is necessary, because the V0Labels table points to aod::McParticles, not to aod::CandidatesV0MCP + auto negId = v0.template negTrack_as().mcParticleId(); + auto posId = v0.template posTrack_as().mcParticleId(); + auto daughters = particle.daughtersIds(); + return ((negId == daughters[0] && posId == daughters[1]) || (posId == daughters[0] && negId == daughters[1])); + } + + template + bool hasITSHit(T const& track, int layer) + { + int ibit = layer - 1; + return (track.itsClusterMap() & (1 << ibit)); + } + + template + void fillTrackQa(V const& v0) + { + auto posTrack = v0.template posTrack_as().template track_as(); + auto negTrack = v0.template negTrack_as().template track_as(); + + double mK = v0.mK0Short(); + double mL = v0.mLambda(); + double mAL = v0.mAntiLambda(); + + double vPt = v0.pt(); + double pPt = posTrack.pt(); + double nPt = negTrack.pt(); + double dPt = posTrack.pt() - negTrack.pt(); + + registry.fill(HIST("tracks/Pos"), vPt, pPt, posTrack.eta(), posTrack.phi()); + registry.fill(HIST("tracks/Neg"), vPt, nPt, negTrack.eta(), negTrack.phi()); + registry.fill(HIST("tracks/Pt"), vPt, pPt, nPt, dPt, dPt / vPt); + registry.fill(HIST("tracks/PtMass"), vPt, pPt, nPt, mK, mL, mAL); + registry.fill(HIST("tracks/PtDiffMass"), vPt, dPt, mK, mL, mAL); + + registry.fill(HIST("tracks/DCAxy"), vPt, pPt, nPt, posTrack.dcaXY(), negTrack.dcaXY(), dPt); + registry.fill(HIST("tracks/DCAxyMassK0S"), vPt, pPt, nPt, posTrack.dcaXY(), negTrack.dcaXY(), mK); + registry.fill(HIST("tracks/DCAxyMassLambda0"), vPt, pPt, nPt, posTrack.dcaXY(), negTrack.dcaXY(), mL); + registry.fill(HIST("tracks/DCAxyMassAntiLambda0"), vPt, pPt, nPt, posTrack.dcaXY(), negTrack.dcaXY(), mAL); + + registry.fill(HIST("tracks/DCAz"), vPt, pPt, nPt, posTrack.dcaZ(), negTrack.dcaZ(), dPt); + registry.fill(HIST("tracks/DCAzMassK0S"), vPt, pPt, nPt, posTrack.dcaZ(), negTrack.dcaZ(), mK); + registry.fill(HIST("tracks/DCAzMassLambda0"), vPt, pPt, nPt, posTrack.dcaZ(), negTrack.dcaZ(), mL); + registry.fill(HIST("tracks/DCAzMassAntiLambda0"), vPt, pPt, nPt, posTrack.dcaZ(), negTrack.dcaZ(), mAL); + + registry.fill(HIST("tracks/V0Radius"), vPt, pPt, nPt, v0.v0radius(), dPt); + registry.fill(HIST("tracks/V0RadiusMassK0S"), vPt, pPt, nPt, v0.v0radius(), mK); + registry.fill(HIST("tracks/V0RadiusMassLambda0"), vPt, pPt, nPt, v0.v0radius(), mL); + registry.fill(HIST("tracks/V0RadiusMassAntiLambda0"), vPt, pPt, nPt, v0.v0radius(), mAL); + + registry.fill(HIST("tracks/V0CosPa"), vPt, pPt, nPt, v0.v0cosPA(), dPt); + registry.fill(HIST("tracks/V0CosPaMassK0S"), vPt, pPt, nPt, v0.v0cosPA(), mK); + registry.fill(HIST("tracks/V0CosPaMassLambda0"), vPt, pPt, nPt, v0.v0cosPA(), mL); + registry.fill(HIST("tracks/V0CosPaMassAntiLambda0"), vPt, pPt, nPt, v0.v0cosPA(), mAL); + + // Has TRD or not + if (posTrack.hasTRD()) { + registry.fill(HIST("tracks/posTRDPt"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/posTRDPtMass"), vPt, pPt, nPt, mK, mL, mAL); + } else { + registry.fill(HIST("tracks/posNoTRDPt"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/posNoTRDPtMass"), vPt, pPt, nPt, mK, mL, mAL); + } + if (negTrack.hasTRD()) { + registry.fill(HIST("tracks/negTRDPt"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/negTRDPtMass"), vPt, pPt, nPt, mK, mL, mAL); + } else { + registry.fill(HIST("tracks/negNoTRDPt"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/negNoTRDPtMass"), vPt, pPt, nPt, mK, mL, mAL); + } + + // ITS information + if (hasITSHit(posTrack, 1)) { + registry.fill(HIST("tracks/ITS/posLayer1"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/posLayer1MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/posLayer1MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/posLayer1MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(posTrack, 2)) { + registry.fill(HIST("tracks/ITS/posLayer2"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/posLayer2MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/posLayer2MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/posLayer2MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(posTrack, 3)) { + registry.fill(HIST("tracks/ITS/posLayer3"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/posLayer3MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/posLayer3MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/posLayer3MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(posTrack, 4)) { + registry.fill(HIST("tracks/ITS/posLayer4"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/posLayer4MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/posLayer4MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/posLayer4MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(posTrack, 5)) { + registry.fill(HIST("tracks/ITS/posLayer5"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/posLayer5MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/posLayer5MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/posLayer5MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(posTrack, 6)) { + registry.fill(HIST("tracks/ITS/posLayer6"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/posLayer6MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/posLayer6MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/posLayer6MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(posTrack, 7)) { + registry.fill(HIST("tracks/ITS/posLayer7"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/posLayer7MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/posLayer7MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/posLayer7MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(posTrack, 5) && hasITSHit(posTrack, 6)) { + registry.fill(HIST("tracks/ITS/posLayer56"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/posLayer56MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/posLayer56MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/posLayer56MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(posTrack, 6) && hasITSHit(posTrack, 7)) { + registry.fill(HIST("tracks/ITS/posLayer67"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/posLayer67MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/posLayer67MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/posLayer67MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(posTrack, 5) && hasITSHit(posTrack, 7)) { + registry.fill(HIST("tracks/ITS/posLayer57"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/posLayer57MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/posLayer57MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/posLayer57MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(posTrack, 5) && hasITSHit(posTrack, 6) && hasITSHit(posTrack, 7)) { + registry.fill(HIST("tracks/ITS/posLayer567"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/posLayer567MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/posLayer567MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/posLayer567MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + registry.fill(HIST("tracks/ITS/posNCl"), vPt, pPt, nPt, posTrack.itsNCls()); + registry.fill(HIST("tracks/ITS/posChi2NCl"), vPt, pPt, nPt, posTrack.itsChi2NCl()); + + if (hasITSHit(negTrack, 1)) { + registry.fill(HIST("tracks/ITS/negLayer1"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/negLayer1MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/negLayer1MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/negLayer1MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(negTrack, 2)) { + registry.fill(HIST("tracks/ITS/negLayer2"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/negLayer2MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/negLayer2MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/negLayer2MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(negTrack, 3)) { + registry.fill(HIST("tracks/ITS/negLayer3"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/negLayer3MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/negLayer3MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/negLayer3MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(negTrack, 4)) { + registry.fill(HIST("tracks/ITS/negLayer4"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/negLayer4MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/negLayer4MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/negLayer4MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(negTrack, 5)) { + registry.fill(HIST("tracks/ITS/negLayer5"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/negLayer5MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/negLayer5MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/negLayer5MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(negTrack, 6)) { + registry.fill(HIST("tracks/ITS/negLayer6"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/negLayer6MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/negLayer6MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/negLayer6MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(negTrack, 7)) { + registry.fill(HIST("tracks/ITS/negLayer7"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/negLayer7MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/negLayer7MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/negLayer7MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(negTrack, 5) && hasITSHit(negTrack, 6)) { + registry.fill(HIST("tracks/ITS/negLayer56"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/negLayer56MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/negLayer56MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/negLayer56MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(negTrack, 6) && hasITSHit(negTrack, 7)) { + registry.fill(HIST("tracks/ITS/negLayer67"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/negLayer67MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/negLayer67MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/negLayer67MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(negTrack, 5) && hasITSHit(negTrack, 7)) { + registry.fill(HIST("tracks/ITS/negLayer57"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/negLayer57MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/negLayer57MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/negLayer57MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + if (hasITSHit(negTrack, 5) && hasITSHit(negTrack, 6) && hasITSHit(negTrack, 7)) { + registry.fill(HIST("tracks/ITS/negLayer567"), vPt, pPt, nPt, dPt); + registry.fill(HIST("tracks/ITS/negLayer567MassK0S"), vPt, pPt, nPt, mK); + registry.fill(HIST("tracks/ITS/negLayer567MassLambda0"), vPt, pPt, nPt, mL); + registry.fill(HIST("tracks/ITS/negLayer567MassAntiLambda0"), vPt, pPt, nPt, mAL); + } + registry.fill(HIST("tracks/ITS/negNCl"), vPt, pPt, nPt, negTrack.itsNCls()); + registry.fill(HIST("tracks/ITS/negChi2NCl"), vPt, pPt, nPt, negTrack.itsChi2NCl()); + + // TPC information + registry.fill(HIST("tracks/TPC/posNClFindable"), vPt, pPt, nPt, posTrack.tpcNClsFindable()); + registry.fill(HIST("tracks/TPC/posNClsFound"), vPt, pPt, nPt, posTrack.tpcNClsFound()); + registry.fill(HIST("tracks/TPC/posChi2NCl"), vPt, pPt, nPt, posTrack.tpcChi2NCl()); + registry.fill(HIST("tracks/TPC/posNClsShared"), vPt, pPt, nPt, posTrack.tpcNClsShared()); + registry.fill(HIST("tracks/TPC/posFractionSharedCls"), vPt, pPt, nPt, posTrack.tpcFractionSharedCls()); + registry.fill(HIST("tracks/TPC/posNClsCrossedRows"), vPt, pPt, nPt, posTrack.tpcNClsCrossedRows()); + registry.fill(HIST("tracks/TPC/posNClsCrossedRowsOverFindableCls"), vPt, pPt, nPt, posTrack.tpcCrossedRowsOverFindableCls()); + + registry.fill(HIST("tracks/TPC/negNClFindable"), vPt, pPt, nPt, negTrack.tpcNClsFindable()); + registry.fill(HIST("tracks/TPC/negNClsFound"), vPt, pPt, nPt, negTrack.tpcNClsFound()); + registry.fill(HIST("tracks/TPC/negChi2NCl"), vPt, pPt, nPt, negTrack.tpcChi2NCl()); + registry.fill(HIST("tracks/TPC/negNClsShared"), vPt, pPt, nPt, negTrack.tpcNClsShared()); + registry.fill(HIST("tracks/TPC/negFractionSharedCls"), vPt, pPt, nPt, negTrack.tpcFractionSharedCls()); + registry.fill(HIST("tracks/TPC/negNClsCrossedRows"), vPt, pPt, nPt, negTrack.tpcNClsCrossedRows()); + registry.fill(HIST("tracks/TPC/negNClsCrossedRowsOverFindableCls"), vPt, pPt, nPt, negTrack.tpcCrossedRowsOverFindableCls()); + } + + void processDummy(aod::CandidatesV0MCD const&) {} + PROCESS_SWITCH(V0QA, processDummy, "Dummy process function turned on by default", true); + + void processFlags(soa::Join::iterator const& v0) + { + int isK0S = static_cast(v0.isK0SCandidate()); + int isLambda = static_cast((v0.isLambdaCandidate())); + int isAntiLambda = static_cast(v0.isAntiLambdaCandidate()); + int isRejected = static_cast(v0.isRejectedCandidate()); + + registry.fill(HIST("inclusive/V0Flags"), 0, 0, isRejected); + registry.fill(HIST("inclusive/V0Flags"), 1, 1, isK0S); + registry.fill(HIST("inclusive/V0Flags"), 2, 2, isLambda); + registry.fill(HIST("inclusive/V0Flags"), 3, 3, isAntiLambda); + + registry.fill(HIST("inclusive/V0Flags"), 0, 1, isRejected * isK0S); + registry.fill(HIST("inclusive/V0Flags"), 1, 0, isRejected * isK0S); + registry.fill(HIST("inclusive/V0Flags"), 0, 2, isRejected * isLambda); + registry.fill(HIST("inclusive/V0Flags"), 2, 0, isRejected * isLambda); + registry.fill(HIST("inclusive/V0Flags"), 0, 3, isRejected * isAntiLambda); + registry.fill(HIST("inclusive/V0Flags"), 3, 0, isRejected * isAntiLambda); + + registry.fill(HIST("inclusive/V0Flags"), 1, 2, isK0S * isLambda); + registry.fill(HIST("inclusive/V0Flags"), 2, 1, isK0S * isLambda); + registry.fill(HIST("inclusive/V0Flags"), 1, 3, isK0S * isAntiLambda); + registry.fill(HIST("inclusive/V0Flags"), 3, 1, isK0S * isAntiLambda); + + registry.fill(HIST("inclusive/V0Flags"), 2, 3, isLambda * isAntiLambda); + registry.fill(HIST("inclusive/V0Flags"), 3, 2, isLambda * isAntiLambda); + + // V0 satisfies 3+ classes + registry.fill(HIST("inclusive/V0Flags"), 0, 4, isRejected * isK0S * isLambda); + registry.fill(HIST("inclusive/V0Flags"), 4, 0, isRejected * isK0S * isLambda); + registry.fill(HIST("inclusive/V0Flags"), 1, 4, isRejected * isK0S * isAntiLambda); + registry.fill(HIST("inclusive/V0Flags"), 4, 1, isRejected * isK0S * isAntiLambda); + registry.fill(HIST("inclusive/V0Flags"), 2, 4, isRejected * isLambda * isAntiLambda); + registry.fill(HIST("inclusive/V0Flags"), 4, 2, isRejected * isLambda * isAntiLambda); + registry.fill(HIST("inclusive/V0Flags"), 3, 4, isRejected * isK0S * isLambda * isAntiLambda); + registry.fill(HIST("inclusive/V0Flags"), 4, 3, isRejected * isK0S * isLambda * isAntiLambda); + registry.fill(HIST("inclusive/V0Flags"), 4, 4, isK0S * isLambda * isAntiLambda); + } + PROCESS_SWITCH(V0QA, processFlags, "V0 flags", false); + + void processMcD(soa::Filtered::iterator const& jcoll, aod::JetMcCollisions const&, CandidatesV0MCDWithFlags const& v0s, aod::McParticles const&) + { + registry.fill(HIST("inclusive/hEvents"), 0.5); + if (!isCollisionReconstructed(jcoll, eventSelectionBits)) { + return; + } + registry.fill(HIST("inclusive/hEvents"), 1.5); + double weight = jcoll.mcCollision().weight(); + + for (const auto& v0 : v0s) { + if (!v0.has_mcParticle()) + continue; + + if (v0.isRejectedCandidate()) + continue; + + int pdg = v0.mcParticle().pdgCode(); + // K0S + if (std::abs(pdg) == 310) { + registry.fill(HIST("inclusive/K0SPtEtaMass"), v0.pt(), v0.eta(), v0.mK0Short(), weight); + registry.fill(HIST("inclusive/InvMassK0STrue"), v0.pt(), v0.v0radius(), v0.mK0Short(), weight); + } + // Lambda + if (pdg == 3122) { + registry.fill(HIST("inclusive/LambdaPtEtaMass"), v0.pt(), v0.eta(), v0.mLambda(), weight); + registry.fill(HIST("inclusive/InvMassLambdaTrue"), v0.pt(), v0.v0radius(), v0.mLambda(), weight); + } + if (pdg == -3122) { + registry.fill(HIST("inclusive/AntiLambdaPtEtaMass"), v0.pt(), v0.eta(), v0.mAntiLambda(), weight); + registry.fill(HIST("inclusive/InvMassAntiLambdaTrue"), v0.pt(), v0.v0radius(), v0.mAntiLambda(), weight); + } + } + } + PROCESS_SWITCH(V0QA, processMcD, "Reconstructed true V0s", false); + + void processMcP(aod::JetMcCollision const& mccoll, aod::CandidatesV0MCP const& pv0s, soa::SmallGroups const& collisions) + { + registry.fill(HIST("inclusive/hMcEvents"), 0.5); + bool isReconstructed = false; + + for (const auto& collision : collisions) { + if (!isCollisionReconstructed(collision, eventSelectionBits)) + continue; + + if (collision.mcCollision().globalIndex() != mccoll.globalIndex()) + continue; + + isReconstructed = true; + break; + } + if (!isReconstructed) + return; + + registry.fill(HIST("inclusive/hMcEvents"), 1.5); + double weight = mccoll.weight(); + + for (const auto& pv0 : pv0s) { + if (!pv0.has_daughters()) + continue; + if (!pv0.isPhysicalPrimary()) + continue; + if (std::abs(pv0.y()) > yPartMax) + continue; + + // Can calculate this from aod::CandidatesV0MCD (contains decay vertex) + double r_Decay = 1.0; + + if (pv0.pdgCode() == 310) { + registry.fill(HIST("inclusive/GeneratedK0S"), pv0.pt(), pv0.eta(), r_Decay, weight); + } + if (pv0.pdgCode() == 3122) { + registry.fill(HIST("inclusive/GeneratedLambda"), pv0.pt(), pv0.eta(), r_Decay, weight); + } + if (pv0.pdgCode() == -3122) { + registry.fill(HIST("inclusive/GeneratedAntiLambda"), pv0.pt(), pv0.eta(), r_Decay, weight); + } + } + } + PROCESS_SWITCH(V0QA, processMcP, "Particle level V0s", false); + + void processMcDJets(soa::Filtered::iterator const& jcoll, aod::JetMcCollisions const&, MCDV0JetsWithConstituents const& mcdjets, CandidatesV0MCDWithFlags const&, aod::McParticles const&) + { + registry.fill(HIST("jets/hJetEvents"), 0.5); + if (!isCollisionReconstructed(jcoll, eventSelectionBits)) + return; + + registry.fill(HIST("jets/hJetEvents"), 1.5); + double weight = jcoll.mcCollision().weight(); + + for (const auto& mcdjet : mcdjets) { + // if (!jetfindingutilities::isInEtaAcceptance(jet, -99., -99., v0EtaMin, v0EtaMax)) + for (const auto& v0 : mcdjet.template candidates_as()) { + if (!v0.has_mcParticle()) + continue; + + int pdg = v0.mcParticle().pdgCode(); + + // Check V0 decay kinematics + if (v0.isRejectedCandidate()) + continue; + + // K0S + if (std::abs(pdg) == 310) { + registry.fill(HIST("jets/JetPtEtaK0SPt"), mcdjet.pt(), mcdjet.eta(), v0.pt(), weight); + registry.fill(HIST("jets/InvMassJetK0STrue"), mcdjet.pt(), v0.pt(), v0.mK0Short(), weight); + } + // Lambda + if (pdg == 3122) { + registry.fill(HIST("jets/JetPtEtaLambdaPt"), mcdjet.pt(), mcdjet.eta(), v0.pt(), weight); + registry.fill(HIST("jets/InvMassJetLambdaTrue"), mcdjet.pt(), v0.pt(), v0.mLambda(), weight); + } + if (pdg == -3122) { + registry.fill(HIST("jets/JetPtEtaAntiLambdaPt"), mcdjet.pt(), mcdjet.eta(), v0.pt(), weight); + registry.fill(HIST("jets/InvMassJetAntiLambdaTrue"), mcdjet.pt(), v0.pt(), v0.mAntiLambda(), weight); + } + } + } + } + PROCESS_SWITCH(V0QA, processMcDJets, "Reconstructed true V0s in jets", false); + + void processMcDMatchedJets(soa::Filtered::iterator const& jcoll, aod::JetMcCollisions const&, MatchedMCDV0JetsWithConstituents const& mcdjets, MatchedMCPV0JetsWithConstituents const&, CandidatesV0MCDWithFlags const&, aod::CandidatesV0MCP const&, aod::JetTracksMCD const& jTracks, aod::McParticles const&) + { + registry.fill(HIST("jets/hMatchedJetEvents"), 0.5); + if (!isCollisionReconstructed(jcoll, eventSelectionBits)) + return; + + registry.fill(HIST("jets/hMatchedJetEvents"), 1.5); + double weight = jcoll.mcCollision().weight(); + + for (const auto& mcdjet : mcdjets) { + // if (!jetfindingutilities::isInEtaAcceptance(mcdjet, -99., -99., v0EtaMin, v0EtaMax)) + for (const auto& mcpjet : mcdjet.template matchedJetGeo_as()) { + for (const auto& v0 : mcdjet.template candidates_as()) { + if (!v0.has_mcParticle()) + continue; + + for (const auto& pv0 : mcpjet.template candidates_as()) { + if (!v0sAreMatched(v0, pv0, jTracks)) + continue; + int pdg = pv0.pdgCode(); + + // Check V0 decay kinematics + if (v0.isRejectedCandidate()) + continue; + + // K0S + if (std::abs(pdg) == 310) { + registry.fill(HIST("jets/JetsPtEtaK0SPt"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), v0.pt(), weight); + registry.fill(HIST("jets/InvMassJetsK0STrue"), mcpjet.pt(), mcdjet.pt(), v0.pt(), v0.mK0Short(), weight); + } + // Lambda + if (pdg == 3122) { + registry.fill(HIST("jets/JetsPtEtaLambdaPt"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), v0.pt(), weight); + registry.fill(HIST("jets/InvMassJetsLambdaTrue"), mcpjet.pt(), mcdjet.pt(), v0.pt(), v0.mLambda(), weight); + } + if (pdg == -3122) { + registry.fill(HIST("jets/JetsPtEtaAntiLambdaPt"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), v0.pt(), weight); + registry.fill(HIST("jets/InvMassJetsAntiLambdaTrue"), mcpjet.pt(), mcdjet.pt(), v0.pt(), v0.mAntiLambda(), weight); + } + } + } + } + } + } + PROCESS_SWITCH(V0QA, processMcDMatchedJets, "Reconstructed true V0s in jets", false); + + void processMcPJets(aod::JetMcCollision const& mccoll, soa::SmallGroups const& collisions, MCPV0JetsWithConstituents const& jets, aod::CandidatesV0MCP const&) + { + registry.fill(HIST("jets/hMcJetEvents"), 0.5); + bool isReconstructed = false; + + for (const auto& collision : collisions) { + if (!isCollisionReconstructed(collision, eventSelectionBits)) + continue; + + if (collision.mcCollision().globalIndex() != mccoll.globalIndex()) + continue; + + isReconstructed = true; + break; + } + if (!isReconstructed) + return; + + registry.fill(HIST("jets/hMcJetEvents"), 1.5); + double weight = mccoll.weight(); + + for (const auto& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, -99., -99., -1. * yPartMax, yPartMax)) + continue; + + for (const auto& pv0 : jet.template candidates_as()) { + if (!pv0.has_daughters()) + continue; + if (!pv0.isPhysicalPrimary()) + continue; + + if (pv0.pdgCode() == 310) { + registry.fill(HIST("jets/GeneratedJetK0S"), jet.pt(), jet.eta(), pv0.pt(), weight); + } + if (pv0.pdgCode() == 3122) { + registry.fill(HIST("jets/GeneratedJetLambda"), jet.pt(), jet.eta(), pv0.pt(), weight); + } + if (pv0.pdgCode() == -3122) { + registry.fill(HIST("jets/GeneratedJetAntiLambda"), jet.pt(), jet.eta(), pv0.pt(), weight); + } + } + } + } + PROCESS_SWITCH(V0QA, processMcPJets, "Particle level V0s in jets", false); + + void processCollisionAssociation(soa::Filtered::iterator const& jcoll, CandidatesV0MCDWithFlags const& v0s, soa::Join const&, aod::McCollisions const&, aod::McParticles const&) + { + // Based on PWGLF/Tasks/Strangeness/derivedlambdakzeroanalysis.cxx + if (!jcoll.has_mcCollision()) + return; + + auto mcColl = jcoll.template mcCollision_as>(); + double weight = mcColl.weight(); + + for (const auto& v0 : v0s) { + if (!v0.has_mcParticle()) + continue; + + auto pv0 = v0.mcParticle(); + bool correctCollision = (mcColl.mcCollisionId() == v0.mcParticle().mcCollisionId()); + int pdg = v0.mcParticle().pdgCode(); + + // Check V0 decay kinematics + if (v0.isRejectedCandidate()) + continue; + + registry.fill(HIST("collisions/V0PtEta"), pv0.pt(), pv0.eta(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/V0PtEtaWrongColl"), pv0.pt(), pv0.eta(), weight); + } + if (std::abs(pdg) == 310) { + registry.fill(HIST("collisions/K0SPtEtaMass"), pv0.pt(), pv0.eta(), v0.mK0Short(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/K0SPtEtaMassWrongColl"), pv0.pt(), pv0.eta(), v0.mK0Short(), weight); + } + } + if (pdg == 3122) { + registry.fill(HIST("collisions/LambdaPtEtaMass"), pv0.pt(), pv0.eta(), v0.mLambda(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/LambdaPtEtaMassWrongColl"), pv0.pt(), pv0.eta(), v0.mLambda(), weight); + } + } + if (pdg == -3122) { + registry.fill(HIST("collisions/AntiLambdaPtEtaMass"), pv0.pt(), pv0.eta(), v0.mAntiLambda(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/AntiLambdaPtEtaMassWrongColl"), pv0.pt(), pv0.eta(), v0.mAntiLambda(), weight); + } + } + // Feed-down from Xi + if (!v0.has_mcMotherParticle()) + continue; + + auto mother = v0.mcMotherParticle(); + pdg = mother.pdgCode(); + correctCollision = (mcColl.mcCollisionId() == mother.mcCollisionId()); + + if (pdg == 3312) { // Xi- + registry.fill(HIST("collisions/XiMinusPtYLambdaPt"), mother.pt(), mother.y(), pv0.pt(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/XiMinusPtYLambdaPtWrongColl"), mother.pt(), mother.y(), pv0.pt(), weight); + } + } + if (pdg == -3312) { // Xi+ + registry.fill(HIST("collisions/XiPlusPtYAntiLambdaPt"), mother.pt(), mother.y(), pv0.pt(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/XiPlusPtYAntiLambdaPtWrongColl"), mother.pt(), mother.y(), pv0.pt(), weight); + } + } + } + } + PROCESS_SWITCH(V0QA, processCollisionAssociation, "V0 collision association", false); + + void processCollisionAssociationJets(soa::Filtered::iterator const& jcoll, MCDV0JetsWithConstituents const& mcdjets, CandidatesV0MCDWithFlags const&, soa::Join const&, aod::McCollisions const&, aod::McParticles const&) + { + if (!jcoll.has_mcCollision()) + return; + + auto mcColl = jcoll.template mcCollision_as>(); + double weight = mcColl.weight(); + + for (const auto& mcdjet : mcdjets) { + // Eta cut? + for (const auto& v0 : mcdjet.template candidates_as()) { + if (!v0.has_mcParticle()) + continue; + + auto pv0 = v0.mcParticle(); + bool correctCollision = (mcColl.mcCollisionId() == pv0.mcCollisionId()); + int pdg = pv0.pdgCode(); + + // Check V0 decay kinematics + if (v0.isRejectedCandidate()) + continue; + + registry.fill(HIST("collisions/JetPtEtaV0Pt"), mcdjet.pt(), mcdjet.eta(), pv0.pt(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetPtEtaV0PtWrongColl"), mcdjet.pt(), mcdjet.eta(), pv0.pt(), weight); + } + if (std::abs(pdg) == 310) { + registry.fill(HIST("collisions/JetPtEtaK0SPtMass"), mcdjet.pt(), mcdjet.eta(), pv0.pt(), v0.mK0Short(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetPtEtaK0SPtMassWrongColl"), mcdjet.pt(), mcdjet.eta(), pv0.pt(), v0.mK0Short(), weight); + } + } + if (pdg == 3122) { + registry.fill(HIST("collisions/JetPtEtaLambdaPtMass"), mcdjet.pt(), mcdjet.eta(), pv0.pt(), v0.mLambda(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetPtEtaLambdaPtMassWrongColl"), mcdjet.pt(), mcdjet.eta(), pv0.pt(), v0.mLambda(), weight); + } + } + if (pdg == -3122) { + registry.fill(HIST("collisions/JetPtEtaAntiLambdaPtMass"), mcdjet.pt(), mcdjet.eta(), pv0.pt(), v0.mAntiLambda(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetPtEtaAntiLambdaPtMassWrongColl"), mcdjet.pt(), mcdjet.eta(), pv0.pt(), v0.mAntiLambda(), weight); + } + } + + if (!v0.has_mcMotherParticle()) + continue; + + auto mother = v0.mcMotherParticle(); + pdg = mother.pdgCode(); + correctCollision = (mcColl.mcCollisionId() == mother.mcCollisionId()); + if (pdg == 3312) { // Xi- + registry.fill(HIST("collisions/JetPtEtaXiMinusPtLambdaPt"), mcdjet.pt(), mcdjet.eta(), mother.pt(), pv0.pt(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetPtEtaXiMinusPtLambdaPtWrongColl"), mcdjet.pt(), mcdjet.eta(), mother.pt(), pv0.pt(), weight); + } + } + if (pdg == -3312) { // Xi+ + registry.fill(HIST("collisions/JetPtEtaXiPlusPtAntiLambdaPt"), mcdjet.pt(), mcdjet.eta(), mother.pt(), pv0.pt(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetPtEtaXiPlusPtAntiLambdaPtWrongColl"), mcdjet.pt(), mcdjet.eta(), mother.pt(), pv0.pt(), weight); + } + } + } // for v0s + } // for mcdjets + } + PROCESS_SWITCH(V0QA, processCollisionAssociationJets, "V0 in jets collision association", false); + + void processCollisionAssociationMatchedJets(soa::Filtered::iterator const& jcoll, MatchedMCDV0JetsWithConstituents const& mcdjets, MatchedMCPV0JetsWithConstituents const&, CandidatesV0MCDWithFlags const&, aod::CandidatesV0MCP const&, soa::Join const&, aod::McCollisions const&, aod::McParticles const&, aod::JetTracksMCD const& jTracks) + { + if (!jcoll.has_mcCollision()) + return; + + auto mcColl = jcoll.template mcCollision_as>(); + double weight = mcColl.weight(); + + for (const auto& mcdjet : mcdjets) { + for (const auto& mcpjet : mcdjet.template matchedJetGeo_as()) { + for (const auto& v0 : mcdjet.template candidates_as()) { + if (!v0.has_mcParticle()) + continue; + + for (const auto& pv0 : mcpjet.template candidates_as()) { + if (!v0sAreMatched(v0, pv0, jTracks)) + continue; + + int pdg = pv0.pdgCode(); + bool correctCollision = (mcColl.mcCollisionId() == pv0.mcCollisionId()); + + // Check V0 decay kinematics + if (v0.isRejectedCandidate()) + continue; + + registry.fill(HIST("collisions/JetsPtEtaV0Pt"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), pv0.pt(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetsPtEtaV0PtWrongColl"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), pv0.pt(), weight); + } + if (std::abs(pdg) == 310) { + registry.fill(HIST("collisions/JetsPtEtaK0SPtMass"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), pv0.pt(), v0.mK0Short(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetsPtEtaK0SPtMassWrongColl"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), pv0.pt(), v0.mK0Short(), weight); + } + } + if (pdg == 3122) { + registry.fill(HIST("collisions/JetsPtEtaLambdaPtMass"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), pv0.pt(), v0.mLambda(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetsPtEtaLambdaPtMassWrongColl"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), pv0.pt(), v0.mLambda(), weight); + } + } + if (pdg == -3122) { + registry.fill(HIST("collisions/JetsPtEtaAntiLambdaPtMass"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), pv0.pt(), v0.mAntiLambda(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetsPtEtaAntiLambdaPtMassWrongColl"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), pv0.pt(), v0.mAntiLambda(), weight); + } + } + + if (!v0.has_mcMotherParticle()) + continue; + + auto mother = v0.mcMotherParticle(); + pdg = mother.pdgCode(); + correctCollision = (mcColl.mcCollisionId() == mother.mcCollisionId()); + if (pdg == 3312) { // Xi- + registry.fill(HIST("collisions/JetsPtEtaXiMinusPtLambdaPt"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), mother.pt(), pv0.pt(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetsPtEtaXiMinusPtLambdaPtWrongColl"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), mother.pt(), pv0.pt(), weight); + } + } + if (pdg == -3312) { // Xi+ + registry.fill(HIST("collisions/JetsPtEtaXiPlusPtAntiLambdaPt"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), mother.pt(), pv0.pt(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetsPtEtaXiPlusPtAntiLambdaPtWrongColl"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), mother.pt(), pv0.pt(), weight); + } + } + } // for pv0 + } // for v0 + } // for mcpjet + } // for mcdjet + } + PROCESS_SWITCH(V0QA, processCollisionAssociationMatchedJets, "V0 in matched jets collision association", false); + + void processFeeddown(soa::Filtered::iterator const& jcoll, CandidatesV0MCDWithFlags const& v0s, aod::CandidatesV0MCP const&, soa::Join const&, aod::McCollisions const&, aod::McParticles const&) + { + // Based on PWGLF/Tasks/Strangeness/derivedlambdakzeroanalysis.cxx + if (!jcoll.has_mcCollision()) + return; + + auto mcColl = jcoll.template mcCollision_as>(); + double weight = mcColl.weight(); + + for (const auto& v0 : v0s) { + if (!v0.has_mcParticle()) + continue; + + int pdg = v0.mcParticle().pdgCode(); + + // Check V0 decay kinematics + if (v0.isRejectedCandidate()) + continue; + // Feed-down from Xi + if (!v0.has_mcMotherParticle()) + continue; + + auto pv0 = v0.mcParticle(); + auto mother = v0.mcMotherParticle(); + pdg = mother.pdgCode(); + + if (pdg == 3312) { // Xi- + registry.fill(HIST("feeddown/XiMinusPtYLambdaPt"), mother.pt(), mother.y(), pv0.pt(), weight); + } + if (pdg == -3312) { // Xi+ + registry.fill(HIST("feeddown/XiPlusPtYAntiLambdaPt"), mother.pt(), mother.y(), pv0.pt(), weight); + } + } + } + PROCESS_SWITCH(V0QA, processFeeddown, "Inclusive feeddown", false); + + void processFeeddownJets(soa::Filtered::iterator const& jcoll, MCDV0JetsWithConstituents const& mcdjets, CandidatesV0MCDWithFlags const&, aod::CandidatesV0MCP const&, soa::Join const&, aod::McCollisions const&, aod::McParticles const&) + { + // Based on PWGLF/Tasks/Strangeness/derivedlambdakzeroanalysis.cxx + if (!jcoll.has_mcCollision()) + return; + + auto mcColl = jcoll.template mcCollision_as>(); + double weight = mcColl.weight(); + + for (const auto& mcdjet : mcdjets) { + for (const auto& v0 : mcdjet.template candidates_as()) { + if (!v0.has_mcParticle()) + continue; + + int pdg = v0.mcParticle().pdgCode(); + + // Check V0 decay kinematics + if (v0.isRejectedCandidate()) + continue; + // Feed-down from Xi + if (!v0.has_mcMotherParticle()) + continue; + + auto pv0 = v0.mcParticle(); + auto mother = v0.mcMotherParticle(); + pdg = mother.pdgCode(); + + if (pdg == 3312) { // Xi- + registry.fill(HIST("feeddown/JetPtXiMinusPtLambdaPt"), mcdjet.pt(), mother.pt(), pv0.pt(), weight); + } + if (pdg == -3312) { // Xi+ + registry.fill(HIST("feeddown/JetPtXiPlusPtAntiLambdaPt"), mcdjet.pt(), mother.pt(), pv0.pt(), weight); + } + } + } + } + PROCESS_SWITCH(V0QA, processFeeddownJets, "Jets feeddown", false); + + void processFeeddownMatchedJets(soa::Filtered::iterator const& jcoll, MatchedMCDV0JetsWithConstituents const& mcdjets, aod::JetTracksMCD const& jTracks, MatchedMCPV0JetsWithConstituents const&, CandidatesV0MCDWithFlags const&, aod::CandidatesV0MCP const&, soa::Join const&, aod::McCollisions const&, aod::McParticles const&) + { + // Based on PWGLF/Tasks/Strangeness/derivedlambdakzeroanalysis.cxx + if (!jcoll.has_mcCollision()) + return; + + auto mcColl = jcoll.template mcCollision_as>(); + double weight = mcColl.weight(); + + for (const auto& mcdjet : mcdjets) { + for (const auto& mcpjet : mcdjet.template matchedJetGeo_as()) { + for (const auto& v0 : mcdjet.template candidates_as()) { + if (!v0.has_mcParticle()) + continue; + if (!v0.has_mcMotherParticle()) + continue; + + for (const auto& pv0 : mcpjet.template candidates_as()) { + if (!v0sAreMatched(v0, pv0, jTracks)) + continue; + + int pdg = v0.mcParticle().pdgCode(); + + // Check V0 decay kinematics + if (v0.isRejectedCandidate()) + continue; + + auto mother = v0.mcMotherParticle(); + pdg = mother.pdgCode(); + if (pdg == 3312) { // Xi- + registry.fill(HIST("feeddown/JetsPtXiMinusPtLambdaPt"), mcpjet.pt(), mcdjet.pt(), mother.pt(), pv0.pt(), weight); + } + if (pdg == -3312) { // Xi+ + registry.fill(HIST("feeddown/JetsPtXiPlusPtAntiLambdaPt"), mcpjet.pt(), mcdjet.pt(), mother.pt(), pv0.pt(), weight); + } + } + } + } + } + } + PROCESS_SWITCH(V0QA, processFeeddownMatchedJets, "Jets feeddown", false); + + using DaughterJTracks = soa::Join; + using DaughterTracks = soa::Join; + void processV0TrackQA(aod::JetCollision const& /*jcoll*/, soa::Join const& v0s, DaughterJTracks const&, DaughterTracks const&) + { + // if (!jetderiveddatautilities::selectCollision(jcoll, eventSelectionBits)) { + // return; + // } + for (const auto& v0 : v0s) { + if (v0.isRejectedCandidate()) + continue; + + fillTrackQa(v0); + } + } + PROCESS_SWITCH(V0QA, processV0TrackQA, "V0 track QA", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"jet-v0qa"})}; +} diff --git a/PWGLF/CMakeLists.txt b/PWGLF/CMakeLists.txt index 9d96b0b8d33..797ac01500f 100644 --- a/PWGLF/CMakeLists.txt +++ b/PWGLF/CMakeLists.txt @@ -13,4 +13,4 @@ # add_subdirectory(DataModel) add_subdirectory(Tasks) add_subdirectory(TableProducer) - +add_subdirectory(Utils) diff --git a/PWGLF/DataModel/LFClusterStudiesTable.h b/PWGLF/DataModel/LFClusterStudiesTable.h new file mode 100644 index 00000000000..88ca35a85d3 --- /dev/null +++ b/PWGLF/DataModel/LFClusterStudiesTable.h @@ -0,0 +1,122 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +// Author: Giorgio Alberto Lucia + +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#ifndef PWGLF_DATAMODEL_LFCLUSTERSTUDIESTABLE_H_ +#define PWGLF_DATAMODEL_LFCLUSTERSTUDIESTABLE_H_ + +namespace o2::aod +{ + +namespace LFClusterStudiesTables +{ +DECLARE_SOA_COLUMN(PMother, pMother, float); +DECLARE_SOA_COLUMN(PtMother, ptMother, float); +DECLARE_SOA_COLUMN(EtaMother, etaMother, float); +DECLARE_SOA_COLUMN(PhiMother, phiMother, float); +DECLARE_SOA_COLUMN(MassMother, massMother, float); +DECLARE_SOA_COLUMN(PdgCodeMother, pdgCodeMother, int); +DECLARE_SOA_COLUMN(RadiusMother, radiusMother, float); +DECLARE_SOA_COLUMN(DcaMotherPV, dcaMotherPV, float); +DECLARE_SOA_COLUMN(CosPAMother, cosPAMother, float); +DECLARE_SOA_COLUMN(AlphaAPMother, alphaAPMother, float); +DECLARE_SOA_COLUMN(QtAPMother, qtAPMother, float); +DECLARE_SOA_COLUMN(McPdgCodeMother, mcPdgCodeMother, int); + +/** + * PartID: + * 0: e + * 1: #pi + * 2: K + * 3: p + * 4: d + * 5: ^{3}He + */ +DECLARE_SOA_COLUMN(PartID, partID, uint8_t); +DECLARE_SOA_COLUMN(PartIDMc, partIDMc, int); +DECLARE_SOA_COLUMN(IsPositive, isPositive, bool); + +DECLARE_SOA_COLUMN(P, p, float); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(PTPC, pTPC, float); +DECLARE_SOA_COLUMN(PIDinTrk, pidInTrk, uint32_t); +DECLARE_SOA_COLUMN(PDGCode, pdgCode, int); +DECLARE_SOA_COLUMN(DcaToPV, dcaToPV, float); +DECLARE_SOA_COLUMN(ItsClusterSize, itsClusterSize, uint32_t); +DECLARE_SOA_COLUMN(TpcSignal, tpcSignal, float); +DECLARE_SOA_COLUMN(TpcNcls, tpcNcls, uint8_t); +DECLARE_SOA_COLUMN(TpcNSigma, tpcNSigma, float); +DECLARE_SOA_COLUMN(TofNSigma, tofNSigma, float); +DECLARE_SOA_COLUMN(TofMass, tofMass, float); +DECLARE_SOA_COLUMN(Chi2its, chi2its, float); +DECLARE_SOA_COLUMN(Chi2tpc, chi2tpc, float); +DECLARE_SOA_COLUMN(HasTPC, hasTPC, bool); +DECLARE_SOA_COLUMN(McPdgCode, mcPdgCode, int); + +} // namespace LFClusterStudiesTables + +DECLARE_SOA_TABLE( + ClStTable, "AOD", "CLSTTABLE", + LFClusterStudiesTables::P, + LFClusterStudiesTables::Eta, + LFClusterStudiesTables::Phi, + LFClusterStudiesTables::ItsClusterSize, + LFClusterStudiesTables::PartID); + +DECLARE_SOA_TABLE( + ClStTableMc, "AOD", "CLSTTABLEMC", + LFClusterStudiesTables::P, + LFClusterStudiesTables::Eta, + LFClusterStudiesTables::Phi, + LFClusterStudiesTables::ItsClusterSize, + LFClusterStudiesTables::PartID, + LFClusterStudiesTables::PartIDMc); + +DECLARE_SOA_TABLE( + ClStTableExtra, "AOD", "CLSTTABLEEXTRA", + LFClusterStudiesTables::P, + LFClusterStudiesTables::Eta, + LFClusterStudiesTables::Phi, + LFClusterStudiesTables::ItsClusterSize, + LFClusterStudiesTables::PartID, + LFClusterStudiesTables::PTPC, + LFClusterStudiesTables::PIDinTrk, + LFClusterStudiesTables::TpcNSigma, + LFClusterStudiesTables::TofNSigma, + LFClusterStudiesTables::TofMass, + LFClusterStudiesTables::CosPAMother, + LFClusterStudiesTables::MassMother); + +DECLARE_SOA_TABLE( + ClStTableMcExt, "AOD", "CLSTTABLEMCEXT", + LFClusterStudiesTables::P, + LFClusterStudiesTables::Eta, + LFClusterStudiesTables::Phi, + LFClusterStudiesTables::ItsClusterSize, + LFClusterStudiesTables::PartID, + LFClusterStudiesTables::PartIDMc, + LFClusterStudiesTables::PTPC, + LFClusterStudiesTables::PIDinTrk, + LFClusterStudiesTables::TpcNSigma, + LFClusterStudiesTables::TofNSigma, + LFClusterStudiesTables::TofMass, + LFClusterStudiesTables::CosPAMother, + LFClusterStudiesTables::MassMother); + +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_LFCLUSTERSTUDIESTABLE_H_ diff --git a/PWGLF/DataModel/LFDoubleCascTables.h b/PWGLF/DataModel/LFDoubleCascTables.h new file mode 100644 index 00000000000..49e3b6604de --- /dev/null +++ b/PWGLF/DataModel/LFDoubleCascTables.h @@ -0,0 +1,73 @@ +// 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. + +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#ifndef PWGLF_DATAMODEL_LFDOUBLECASCTABLES_H_ +#define PWGLF_DATAMODEL_LFDOUBLECASCTABLES_H_ + +namespace o2::aod +{ + +namespace DoubleCascTables +{ +DECLARE_SOA_COLUMN(PtCasc1, ptCasc1, float); // signed pt of the cascade +DECLARE_SOA_COLUMN(EtaCasc1, etaCasc1, float); +DECLARE_SOA_COLUMN(PhiCasc1, phiCasc1, float); +DECLARE_SOA_COLUMN(CascDecLength1, cascDecLength1, float); +DECLARE_SOA_COLUMN(OmegaMassCasc1, omegaMassCasc1, float); +DECLARE_SOA_COLUMN(XiMassCasc1, xiMassCasc1, float); +DECLARE_SOA_COLUMN(CosPACasc1, cosPACasc1, float); +DECLARE_SOA_COLUMN(DcaBachPVCasc1, dcaBachPVCasc1, float); +DECLARE_SOA_COLUMN(DcaV0BachCasc1, dcaV0BachCasc1, float); +DECLARE_SOA_COLUMN(NSigmaKBach1, nSigmaKBach1, float); + +DECLARE_SOA_COLUMN(PtCasc2, ptCasc2, float); +DECLARE_SOA_COLUMN(EtaCasc2, etaCasc2, float); +DECLARE_SOA_COLUMN(PhiCasc2, phiCasc2, float); +DECLARE_SOA_COLUMN(CascDecLength2, cascDecLength2, float); +DECLARE_SOA_COLUMN(OmegaMassCasc2, omegaMassCasc2, float); +DECLARE_SOA_COLUMN(XiMassCasc2, xiMassCasc2, float); +DECLARE_SOA_COLUMN(CosPACasc2, cosPACasc2, float); +DECLARE_SOA_COLUMN(DcaBachPVCasc2, dcaBachPVCasc2, float); +DECLARE_SOA_COLUMN(DcaV0BachCasc2, dcaV0BachCasc2, float); +DECLARE_SOA_COLUMN(NSigmaKBach2, nSigmaKBach2, float); + +DECLARE_SOA_COLUMN(DoubleOmegaMass, doubleOmegaMass, float); +} // namespace DoubleCascTables + +DECLARE_SOA_TABLE(DoubleCascTable, "AOD", "DOUBLECASCTABLE", + DoubleCascTables::PtCasc1, + DoubleCascTables::EtaCasc1, + DoubleCascTables::PhiCasc1, + DoubleCascTables::CascDecLength1, + DoubleCascTables::OmegaMassCasc1, + DoubleCascTables::XiMassCasc1, + DoubleCascTables::CosPACasc1, + DoubleCascTables::DcaBachPVCasc1, + DoubleCascTables::DcaV0BachCasc1, + DoubleCascTables::NSigmaKBach1, + DoubleCascTables::PtCasc2, + DoubleCascTables::EtaCasc2, + DoubleCascTables::PhiCasc2, + DoubleCascTables::CascDecLength2, + DoubleCascTables::OmegaMassCasc2, + DoubleCascTables::XiMassCasc2, + DoubleCascTables::CosPACasc2, + DoubleCascTables::DcaBachPVCasc2, + DoubleCascTables::DcaV0BachCasc2, + DoubleCascTables::NSigmaKBach2, + DoubleCascTables::DoubleOmegaMass); + +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_LFDOUBLECASCTABLES_H_ diff --git a/PWGLF/DataModel/LFEbyeTables.h b/PWGLF/DataModel/LFEbyeTables.h new file mode 100644 index 00000000000..d7ff437ece4 --- /dev/null +++ b/PWGLF/DataModel/LFEbyeTables.h @@ -0,0 +1,163 @@ +// 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. + +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#ifndef PWGLF_DATAMODEL_LFEBYETABLES_H_ +#define PWGLF_DATAMODEL_LFEBYETABLES_H_ + +namespace o2::aod +{ + +namespace LFEbyeCollTable +{ +DECLARE_SOA_COLUMN(Centrality, centrality, uint8_t); +DECLARE_SOA_COLUMN(Zvtx, zvtx, float); +DECLARE_SOA_COLUMN(ZvtxMask, zvtxMask, int8_t); +DECLARE_SOA_COLUMN(TriggerMask, triggerMask, uint8_t); +DECLARE_SOA_COLUMN(Ntracklets, ntracklets, uint8_t); +DECLARE_SOA_COLUMN(V0Multiplicity, v0Multiplicity, uint8_t); +} // namespace LFEbyeCollTable + +DECLARE_SOA_TABLE(CollEbyeTables, "AOD", "COLLEBYETABLE", + o2::soa::Index<>, + LFEbyeCollTable::Centrality, + LFEbyeCollTable::Zvtx); +using CollEbyeTable = CollEbyeTables::iterator; + +DECLARE_SOA_TABLE(MiniCollTables, "AOD", "MINICOLLTABLE", + o2::soa::Index<>, + LFEbyeCollTable::ZvtxMask, + LFEbyeCollTable::TriggerMask, + LFEbyeCollTable::Ntracklets, + LFEbyeCollTable::V0Multiplicity); +using MiniCollTable = MiniCollTables::iterator; + +namespace LFEbyeTable +{ +DECLARE_SOA_INDEX_COLUMN(CollEbyeTable, collEbyeTable); +DECLARE_SOA_INDEX_COLUMN(MiniCollTable, miniCollTable); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Mass, mass, float); +DECLARE_SOA_COLUMN(DcaPV, dcaPV, float); +DECLARE_SOA_COLUMN(TpcNcls, tpcNcls, uint8_t); +DECLARE_SOA_COLUMN(TpcNsigma, tpcNsigma, float); +DECLARE_SOA_COLUMN(TofMass, tofMass, float); +DECLARE_SOA_COLUMN(DcaV0PV, dcaV0Pv, float); +DECLARE_SOA_COLUMN(DcaNegPV, dcaNegPv, float); +DECLARE_SOA_COLUMN(DcaPosPV, dcaPosPv, float); +DECLARE_SOA_COLUMN(DcaV0Tracks, dcaV0tracks, float); +DECLARE_SOA_COLUMN(CosPA, cosPa, double); +DECLARE_SOA_COLUMN(TpcNsigmaNeg, tpcNsigmaNeg, float); +DECLARE_SOA_COLUMN(TpcNsigmaPos, tpcNsigmaPos, float); +DECLARE_SOA_COLUMN(IdNeg, idNeg, int64_t); +DECLARE_SOA_COLUMN(IdPos, idPos, int64_t); +DECLARE_SOA_COLUMN(GenPt, genPt, float); +DECLARE_SOA_COLUMN(GenEta, genEta, float); +DECLARE_SOA_COLUMN(PdgCode, pdgCode, int); +DECLARE_SOA_COLUMN(IsReco, isReco, bool); +DECLARE_SOA_COLUMN(EtaMask, etaMask, int8_t); +DECLARE_SOA_COLUMN(SelMask, selMask, int); +DECLARE_SOA_COLUMN(OuterPID, outerPID, float); +DECLARE_SOA_COLUMN(GenEtaMask, genEtaMask, int8_t); +} // namespace LFEbyeTable + +DECLARE_SOA_TABLE(NucleiEbyeTables, "AOD", "NUCLEBYETABLE", + o2::soa::Index<>, + LFEbyeTable::CollEbyeTableId, + LFEbyeTable::Pt, + LFEbyeTable::Eta, + LFEbyeTable::Mass, + LFEbyeTable::DcaPV, + LFEbyeTable::TpcNcls, + LFEbyeTable::TpcNsigma, + LFEbyeTable::TofMass); +using NucleiEbyeTable = NucleiEbyeTables::iterator; + +DECLARE_SOA_TABLE(McNucleiEbyeTables, "AOD", "MCNUCLEBYETABLE", + o2::soa::Index<>, + LFEbyeTable::CollEbyeTableId, + LFEbyeTable::Pt, + LFEbyeTable::Eta, + LFEbyeTable::Mass, + LFEbyeTable::DcaPV, + LFEbyeTable::TpcNcls, + LFEbyeTable::TpcNsigma, + LFEbyeTable::TofMass, + LFEbyeTable::GenPt, + LFEbyeTable::GenEta, + LFEbyeTable::PdgCode, + LFEbyeTable::IsReco); +using McNucleiEbyeTable = McNucleiEbyeTables::iterator; + +DECLARE_SOA_TABLE(LambdaEbyeTables, "AOD", "LAMBEBYETABLE", + o2::soa::Index<>, + LFEbyeTable::CollEbyeTableId, + LFEbyeTable::Pt, + LFEbyeTable::Eta, + LFEbyeTable::Mass, + LFEbyeTable::DcaV0PV, + // LFEbyeTable::DcaNegPV, + // LFEbyeTable::DcaPosPV, + LFEbyeTable::DcaV0Tracks, + LFEbyeTable::CosPA, + // LFEbyeTable::TpcNsigmaNeg, + // LFEbyeTable::TpcNsigmaPos, + LFEbyeTable::IdNeg, + LFEbyeTable::IdPos); +using LambdaEbyeTable = LambdaEbyeTables::iterator; + +DECLARE_SOA_TABLE(McLambdaEbyeTables, "AOD", "MCLAMBEBYETABLE", + o2::soa::Index<>, + LFEbyeTable::CollEbyeTableId, + LFEbyeTable::Pt, + LFEbyeTable::Eta, + LFEbyeTable::Mass, + LFEbyeTable::DcaV0PV, + // LFEbyeTable::DcaNegPV, + // LFEbyeTable::DcaPosPV, + LFEbyeTable::DcaV0Tracks, + LFEbyeTable::CosPA, + // LFEbyeTable::TpcNsigmaNeg, + // LFEbyeTable::TpcNsigmaPos, + LFEbyeTable::IdNeg, + LFEbyeTable::IdPos, + LFEbyeTable::GenPt, + LFEbyeTable::GenEta, + LFEbyeTable::PdgCode, + LFEbyeTable::IsReco); +using McLambdaEbyeTable = McLambdaEbyeTables::iterator; + +DECLARE_SOA_TABLE(MiniTrkTables, "AOD", "MINITRKTABLE", + o2::soa::Index<>, + LFEbyeTable::MiniCollTableId, + LFEbyeTable::Pt, + LFEbyeTable::EtaMask, + LFEbyeTable::SelMask, + LFEbyeTable::OuterPID); +using MiniTrkTable = MiniTrkTables::iterator; + +DECLARE_SOA_TABLE(McMiniTrkTables, "AOD", "MCMINITRKTABLE", + o2::soa::Index<>, + LFEbyeTable::MiniCollTableId, + LFEbyeTable::Pt, + LFEbyeTable::EtaMask, + LFEbyeTable::SelMask, + LFEbyeTable::OuterPID, + LFEbyeTable::GenPt, + LFEbyeTable::GenEtaMask, + LFEbyeTable::IsReco); +using McMiniTrkTable = McMiniTrkTables::iterator; +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_LFEBYETABLES_H_ diff --git a/PWGLF/DataModel/LFHStrangeCorrelationTables.h b/PWGLF/DataModel/LFHStrangeCorrelationTables.h index 53cf20bc7eb..62b50667263 100644 --- a/PWGLF/DataModel/LFHStrangeCorrelationTables.h +++ b/PWGLF/DataModel/LFHStrangeCorrelationTables.h @@ -22,10 +22,13 @@ #ifndef PWGLF_DATAMODEL_LFHSTRANGECORRELATIONTABLES_H_ #define PWGLF_DATAMODEL_LFHSTRANGECORRELATIONTABLES_H_ +#include #include "Framework/AnalysisDataModel.h" #include "Common/Core/RecoDecay.h" #include "CommonConstants/PhysicsConstants.h" -#include + +// Simple checker +#define bitcheck(var, nbit) ((var) & (1 << (nbit))) namespace o2::aod { @@ -34,61 +37,79 @@ namespace o2::aod namespace triggerTracks { DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! +DECLARE_SOA_COLUMN(MCPhysicalPrimary, mcPhysicalPrimary, bool); // true physical primary flag DECLARE_SOA_INDEX_COLUMN_FULL(Track, track, int, Tracks, "_Trigger"); //! +DECLARE_SOA_COLUMN(MCOriginalPt, mcOriginalPt, float); // true generated pt } // namespace triggerTracks -DECLARE_SOA_TABLE(TriggerTracks, "AOD", "TRIGGERTRACKS", o2::soa::Index<>, triggerTracks::CollisionId, triggerTracks::TrackId); +DECLARE_SOA_TABLE(TriggerTracks, "AOD", "TRIGGERTRACKS", o2::soa::Index<>, triggerTracks::CollisionId, triggerTracks::MCPhysicalPrimary, triggerTracks::TrackId, triggerTracks::MCOriginalPt); +namespace triggerTrackExtras +{ +DECLARE_SOA_COLUMN(Extra, extra, int); // true physical primary flag +} // namespace triggerTrackExtras +DECLARE_SOA_TABLE(TriggerTrackExtras, "AOD", "TRIGGERTRACKEXTRAs", triggerTrackExtras::Extra); /// _________________________________________ /// Table for storing assoc track indices -namespace assocPions +namespace assocHadrons { DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! +DECLARE_SOA_COLUMN(MCPhysicalPrimary, mcPhysicalPrimary, bool); // true physical primary flag DECLARE_SOA_INDEX_COLUMN_FULL(Track, track, int, Tracks, "_Assoc"); //! -} // namespace assocPions -DECLARE_SOA_TABLE(AssocPions, "AOD", "ASSOCPIONS", o2::soa::Index<>, assocPions::CollisionId, assocPions::TrackId); +DECLARE_SOA_COLUMN(MCOriginalPt, mcOriginalPt, float); // true generated pt +} // namespace assocHadrons +DECLARE_SOA_TABLE(AssocHadrons, "AOD", "ASSOCHADRONS", o2::soa::Index<>, assocHadrons::CollisionId, assocHadrons::MCPhysicalPrimary, assocHadrons::TrackId, assocHadrons::MCOriginalPt); +/// _________________________________________ +/// Table for storing assoc track PID +namespace assocPID +{ +DECLARE_SOA_COLUMN(NSigmaTPCPi, nSigmaTPCPi, float); +DECLARE_SOA_COLUMN(NSigmaTPCKa, nSigmaTPCKa, float); +DECLARE_SOA_COLUMN(NSigmaTPCPr, nSigmaTPCPr, float); +DECLARE_SOA_COLUMN(NSigmaTPCEl, nSigmaTPCEl, float); +DECLARE_SOA_COLUMN(NSigmaTOFPi, nSigmaTOFPi, float); +DECLARE_SOA_COLUMN(NSigmaTOFKa, nSigmaTOFKa, float); +DECLARE_SOA_COLUMN(NSigmaTOFPr, nSigmaTOFPr, float); +DECLARE_SOA_COLUMN(NSigmaTOFEl, nSigmaTOFEl, float); +} // namespace assocPID +DECLARE_SOA_TABLE(AssocPID, "AOD", "ASSOCPID", assocPID::NSigmaTPCPi, assocPID::NSigmaTPCKa, assocPID::NSigmaTPCPr, assocPID::NSigmaTPCEl, assocPID::NSigmaTOFPi, assocPID::NSigmaTOFKa, assocPID::NSigmaTOFPr, assocPID::NSigmaTOFEl); + /// _________________________________________ /// Table for storing associated V0 indices namespace assocV0s { -DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! -DECLARE_SOA_INDEX_COLUMN(V0Core, v0Core); //! -DECLARE_SOA_COLUMN(CompatibleK0Short, compatibleK0Short, bool); // compatible with K0Short -DECLARE_SOA_COLUMN(CompatibleLambda, compatibleLambda, bool); // compatible with Lambda -DECLARE_SOA_COLUMN(CompatibleAntiLambda, compatibleAntiLambda, bool); // compatible with AntiLambda -DECLARE_SOA_COLUMN(MCTrueK0Short, mcTrueK0Short, bool); // true K0Short in MC -DECLARE_SOA_COLUMN(MCTrueLambda, mcTrueLambda, bool); // true Lambda in MC -DECLARE_SOA_COLUMN(MCTrueAntiLambda, mcTrueAntiLambda, bool); // true AntiLambda in MC -DECLARE_SOA_COLUMN(MassRegionK0Short, massRegionK0Short, int); // -DECLARE_SOA_COLUMN(MassRegionLambda, massRegionLambda, int); // -DECLARE_SOA_COLUMN(MassRegionAntiLambda, massRegionAntiLambda, int); // -DECLARE_SOA_DYNAMIC_COLUMN(Compatible, compatible, //! check compatibility with a hypothesis of a certain number (0 - K0, 1 - L, 2 - Lbar) - [](bool cK0Short, bool cLambda, bool cAntiLambda, int value) -> bool { - if (value == 0 && cK0Short) - return true; - if (value == 1 && cLambda) - return true; - if (value == 2 && cAntiLambda) - return true; - return false; - }); -DECLARE_SOA_DYNAMIC_COLUMN(InvMassRegionCheck, invMassRegionCheck, - [](int rK0Short, int rLambda, int rAntiLambda, int value, int region) -> bool { - if (value == 0 && rK0Short == region) +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! +DECLARE_SOA_INDEX_COLUMN(V0Core, v0Core); //! + +// dEdx compatibility is done via encoded integer: 0: passes loose; 1: passes normal, 2: passes tight; definition of loose/normal/tight is in hStrangeCorrelationFilter +DECLARE_SOA_COLUMN(CompatibleK0Short, compatibleK0Short, int); // compatible with K0Short dEdx, encoded syst checks +DECLARE_SOA_COLUMN(CompatibleLambda, compatibleLambda, int); // compatible with Lambda dEdx, encoded syst checks +DECLARE_SOA_COLUMN(CompatibleAntiLambda, compatibleAntiLambda, int); // compatible with AntiLambda dEdx, encoded syst checks + +DECLARE_SOA_COLUMN(MCTrueK0Short, mcTrueK0Short, bool); // true K0Short in MC +DECLARE_SOA_COLUMN(MCTrueLambda, mcTrueLambda, bool); // true Lambda in MC +DECLARE_SOA_COLUMN(MCTrueAntiLambda, mcTrueAntiLambda, bool); // true AntiLambda in MC +DECLARE_SOA_COLUMN(MCPhysicalPrimary, mcPhysicalPrimary, bool); // true physical primary flag +DECLARE_SOA_COLUMN(NSigmaMassK0Short, nSigmaMassK0Short, float); // +DECLARE_SOA_COLUMN(NSigmaMassLambda, nSigmaMassLambda, float); // +DECLARE_SOA_COLUMN(NSigmaMassAntiLambda, nSigmaMassAntiLambda, float); // +DECLARE_SOA_DYNAMIC_COLUMN(Compatible, compatible, //! check compatibility with a hypothesis of a certain number (0 - K0, 1 - L, 2 - Lbar) + [](int cK0Short, int cLambda, int cAntiLambda, int value, int compatibilityLevel) -> bool { + if (value == 0 && bitcheck(cK0Short, compatibilityLevel)) return true; - if (value == 1 && rLambda == region) + if (value == 1 && bitcheck(cLambda, compatibilityLevel)) return true; - if (value == 2 && rAntiLambda == region) + if (value == 2 && bitcheck(cAntiLambda, compatibilityLevel)) return true; return false; }); -DECLARE_SOA_DYNAMIC_COLUMN(InvMassRegion, invMassRegion, - [](int rK0Short, int rLambda, int rAntiLambda, int value) -> int { +DECLARE_SOA_DYNAMIC_COLUMN(InvMassNSigma, invMassNSigma, + [](float rK0Short, float rLambda, float rAntiLambda, int value) -> float { if (value == 0) return rK0Short; if (value == 1) return rLambda; if (value == 2) return rAntiLambda; - return -1; + return 1000.0f; }); DECLARE_SOA_DYNAMIC_COLUMN(MCTrue, mcTrue, [](int mcTrueK0Short, int mcTrueLambda, int mcTrueAntiLambda, int value) -> bool { @@ -109,60 +130,52 @@ DECLARE_SOA_TABLE(AssocV0s, "AOD", "ASSOCV0S", o2::soa::Index<>, assocV0s::MCTrueK0Short, assocV0s::MCTrueLambda, assocV0s::MCTrueAntiLambda, - assocV0s::MassRegionK0Short, - assocV0s::MassRegionLambda, - assocV0s::MassRegionAntiLambda, + assocV0s::MCPhysicalPrimary, + assocV0s::NSigmaMassK0Short, + assocV0s::NSigmaMassLambda, + assocV0s::NSigmaMassAntiLambda, + assocV0s::InvMassNSigma, assocV0s::Compatible, - assocV0s::InvMassRegionCheck, - assocV0s::InvMassRegion, assocV0s::MCTrue); /// _________________________________________ /// Table for storing associated casc indices namespace assocCascades { -DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! -DECLARE_SOA_INDEX_COLUMN(CascData, cascData); //! -DECLARE_SOA_COLUMN(CompatibleXiMinus, compatibleXiMinus, bool); // compatible with XiMinus -DECLARE_SOA_COLUMN(CompatibleXiPlus, compatibleXiPlus, bool); // compatible with XiPlus -DECLARE_SOA_COLUMN(CompatibleOmegaMinus, compatibleOmegaMinus, bool); // compatible with OmegaMinus -DECLARE_SOA_COLUMN(CompatibleOmegaPlus, compatibleOmegaPlus, bool); // compatible with OmegaPlus -DECLARE_SOA_COLUMN(MCTrueXiMinus, mcTrueXiMinus, bool); // true XiMinus in mc -DECLARE_SOA_COLUMN(MCTrueXiPlus, mcTrueXiPlus, bool); // true XiPlus in mc -DECLARE_SOA_COLUMN(MCTrueOmegaMinus, mcTrueOmegaMinus, bool); // true OmegaMinus in mc -DECLARE_SOA_COLUMN(MCTrueOmegaPlus, mcTrueOmegaPlus, bool); // true OmegaPlus in mc -DECLARE_SOA_COLUMN(MassRegionXi, massRegionXi, int); // -DECLARE_SOA_COLUMN(MassRegionOmega, massRegionOmega, int); // -DECLARE_SOA_DYNAMIC_COLUMN(Compatible, compatible, //! check compatibility with a hypothesis of a certain number (0 - K0, 1 - L, 2 - Lbar) - [](bool cXiMinus, bool cXiPlus, bool cOmegaMinus, bool cOmegaPlus, int value) -> bool { - if (value == 0 && cXiMinus) - return true; - if (value == 1 && cXiPlus) - return true; - if (value == 2 && cOmegaMinus) - return true; - if (value == 3 && cOmegaPlus) - return true; - return false; - }); -DECLARE_SOA_DYNAMIC_COLUMN(InvMassRegionCheck, invMassRegionCheck, - [](int rXi, int rOmega, int value, int region) -> bool { - if (value == 0 && rXi == region) +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! +DECLARE_SOA_INDEX_COLUMN(CascData, cascData); //! + +// dEdx compatibility is done via encoded integer: 0: passes loose; 1: passes normal, 2: passes tight; definition of loose/normal/tight is in hStrangeCorrelationFilter +DECLARE_SOA_COLUMN(CompatibleXiMinus, compatibleXiMinus, int); // compatible with XiMinus +DECLARE_SOA_COLUMN(CompatibleXiPlus, compatibleXiPlus, int); // compatible with XiPlus +DECLARE_SOA_COLUMN(CompatibleOmegaMinus, compatibleOmegaMinus, int); // compatible with OmegaMinus +DECLARE_SOA_COLUMN(CompatibleOmegaPlus, compatibleOmegaPlus, int); // compatible with OmegaPlus + +DECLARE_SOA_COLUMN(MCTrueXiMinus, mcTrueXiMinus, bool); // true XiMinus in mc +DECLARE_SOA_COLUMN(MCTrueXiPlus, mcTrueXiPlus, bool); // true XiPlus in mc +DECLARE_SOA_COLUMN(MCTrueOmegaMinus, mcTrueOmegaMinus, bool); // true OmegaMinus in mc +DECLARE_SOA_COLUMN(MCTrueOmegaPlus, mcTrueOmegaPlus, bool); // true OmegaPlus in mc +DECLARE_SOA_COLUMN(MCPhysicalPrimary, mcPhysicalPrimary, bool); // physical primary in MC +DECLARE_SOA_COLUMN(NSigmaMassXi, nSigmaMassXi, float); // +DECLARE_SOA_COLUMN(NSigmaMassOmega, nSigmaMassOmega, float); // +DECLARE_SOA_DYNAMIC_COLUMN(Compatible, compatible, //! check compatibility with a hypothesis of a certain number (0 - K0, 1 - L, 2 - Lbar) + [](int cXiMinus, int cXiPlus, int cOmegaMinus, int cOmegaPlus, int value, int compatibilityLevel) -> bool { + if (value == 0 && bitcheck(cXiMinus, compatibilityLevel)) return true; - if (value == 1 && rXi == region) + if (value == 1 && bitcheck(cXiPlus, compatibilityLevel)) return true; - if (value == 2 && rOmega == region) + if (value == 2 && bitcheck(cOmegaMinus, compatibilityLevel)) return true; - if (value == 3 && rOmega == region) + if (value == 3 && bitcheck(cOmegaPlus, compatibilityLevel)) return true; return false; }); -DECLARE_SOA_DYNAMIC_COLUMN(InvMassRegion, invMassRegion, - [](int rXi, int rOmega, int value) -> int { +DECLARE_SOA_DYNAMIC_COLUMN(InvMassNSigma, invMassNSigma, + [](float rXi, float rOmega, int value) -> float { if (value == 0 || value == 1) return rXi; if (value == 2 || value == 3) return rOmega; - return -1; + return 1000.0f; }); DECLARE_SOA_DYNAMIC_COLUMN(MCTrue, mcTrue, [](int mcTrueXiMinus, int mcTrueXiPlus, int mcTrueOmegaMinus, int mcTrueOmegaPlus, int value) -> bool { @@ -186,11 +199,11 @@ DECLARE_SOA_TABLE(AssocCascades, "AOD", "ASSOCCASCADES", o2::soa::Index<>, assoc assocCascades::MCTrueXiPlus, assocCascades::MCTrueOmegaMinus, assocCascades::MCTrueOmegaPlus, - assocCascades::MassRegionXi, - assocCascades::MassRegionOmega, + assocCascades::MCPhysicalPrimary, + assocCascades::NSigmaMassXi, + assocCascades::NSigmaMassOmega, + assocCascades::InvMassNSigma, assocCascades::Compatible, - assocCascades::InvMassRegionCheck, - assocCascades::InvMassRegion, assocCascades::MCTrue); } // namespace o2::aod diff --git a/PWGLF/DataModel/LFHypernucleiKfTables.h b/PWGLF/DataModel/LFHypernucleiKfTables.h new file mode 100644 index 00000000000..98f8076b2f6 --- /dev/null +++ b/PWGLF/DataModel/LFHypernucleiKfTables.h @@ -0,0 +1,236 @@ +// 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 LFHypernucleiKfTables.h +/// \brief Slim hypernuclei kf tables +/// \author Janik Ditzel and Michael Hartung + +#ifndef PWGLF_DATAMODEL_LFHYPERNUCLEIKFTABLES_H_ +#define PWGLF_DATAMODEL_LFHYPERNUCLEIKFTABLES_H_ + +#include +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/Centrality.h" +#include "Common/Core/RecoDecay.h" + +namespace o2::aod +{ +namespace hykfmccoll +{ +DECLARE_SOA_COLUMN(PassedEvSel, passedEvSel, bool); //! +} +DECLARE_SOA_TABLE(HypKfMcColls, "AOD", "HYPKFMCCOLL", + o2::soa::Index<>, + hykfmccoll::PassedEvSel, + mccollision::PosX, + mccollision::PosY, + mccollision::PosZ); +using HypKfMcColl = HypKfMcColls::iterator; + +namespace hykfmc +{ +DECLARE_SOA_INDEX_COLUMN(HypKfMcColl, hypKfMcColl); +DECLARE_SOA_COLUMN(Species, species, int8_t); //! +DECLARE_SOA_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, bool); //! +DECLARE_SOA_COLUMN(Svx, svx, float); //! +DECLARE_SOA_COLUMN(Svy, svy, float); //! +DECLARE_SOA_COLUMN(Svz, svz, float); //! +DECLARE_SOA_COLUMN(Occupancy, occupancy, int); //! +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float px, float py) { return RecoDecay::pt(std::array{px, py}); }); +DECLARE_SOA_DYNAMIC_COLUMN(Y, y, [](float E, float pz) { return 0.5 * std::log((E + pz) / (E - pz)); }); +DECLARE_SOA_DYNAMIC_COLUMN(Mass, mass, [](float E, float px, float py, float pz) { return std::sqrt(E * E - px * px - py * py - pz * pz); }); +DECLARE_SOA_DYNAMIC_COLUMN(IsMatter, isMatter, [](int pdgCode) { return pdgCode > 0; }); +} // namespace hykfmc + +DECLARE_SOA_TABLE(HypKfMcParts, "AOD", "HYPKFMCPART", + o2::soa::Index<>, + hykfmc::HypKfMcCollId, + hykfmc::Species, + mcparticle::PdgCode, + hykfmc::IsPhysicalPrimary, + mcparticle::Px, + mcparticle::Py, + mcparticle::Pz, + mcparticle::E, + hykfmc::Svx, + hykfmc::Svy, + hykfmc::Svz, + hykfmc::Pt, + hykfmc::Y, + hykfmc::Mass, + hykfmc::IsMatter); +using HypKfMcPart = HypKfMcParts::iterator; + +DECLARE_SOA_TABLE(HypKfColls, "AOD", "HYPKFCOLL", + o2::soa::Index<>, + hykfmccoll::PassedEvSel, + hykfmc::HypKfMcCollId, + collision::PosX, + collision::PosY, + collision::PosZ, + cent::CentFT0A, + cent::CentFT0C, + cent::CentFT0M, + hykfmc::Occupancy); +using HypKfColl = HypKfColls::iterator; + +namespace hykftrk +{ +DECLARE_SOA_INDEX_COLUMN(HypKfColl, hypKfColl); +DECLARE_SOA_COLUMN(Rigidity, rigidity, float); //! +DECLARE_SOA_COLUMN(TpcNcluster, tpcNcluster, float); //! +DECLARE_SOA_COLUMN(TpcNsigma, tpcNsigma, float); //! +DECLARE_SOA_COLUMN(TpcNsigmaNhp, tpcNsigmaNhp, float); //! +DECLARE_SOA_COLUMN(TpcNsigmaNlp, tpcNsigmaNlp, float); //! +DECLARE_SOA_COLUMN(TofMass, tofMass, float); //! +DECLARE_SOA_COLUMN(IsPVContributor, isPVContributor, bool); //! +DECLARE_SOA_COLUMN(SubMass, subMass, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) { return (double)pt * std::cos(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float pt, float phi) { return (double)pt * std::sin(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float pt, float eta) { return (double)pt * std::sinh(eta); }); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float pt, float eta) { return pt * std::cosh(eta); }); // +DECLARE_SOA_DYNAMIC_COLUMN(Y, y, [](float pt, float eta, float mass) { return std::log((RecoDecay::sqrtSumOfSquares(mass, pt * std::cosh(eta)) + pt * std::sinh(eta)) / RecoDecay::sqrtSumOfSquares(mass, pt)); }); +DECLARE_SOA_DYNAMIC_COLUMN(Lambda, lambda, [](float eta) { return 1. / std::cosh(eta); }); +DECLARE_SOA_DYNAMIC_COLUMN(ItsNcluster, itsNcluster, [](uint32_t itsClusterSizes) { + uint8_t n = 0; + for (uint8_t i = 0; i < 7; i++) { + if (itsClusterSizes >> (4 * i) & 15) + n++; + } + return n; +}); +DECLARE_SOA_DYNAMIC_COLUMN(ItsFirstLayer, itsFirstLayer, [](uint32_t itsClusterSizes) { + for (int i = 0; i < 8; i++) { + if (itsClusterSizes >> (4 * i) & 15) + return i; + } + return -999; +}); +DECLARE_SOA_DYNAMIC_COLUMN(ItsMeanClsSize, itsMeanClsSize, [](uint32_t itsClusterSizes) { + int sum = 0, n = 0; + for (int i = 0; i < 8; i++) { + sum += (itsClusterSizes >> (4 * i) & 15); + if (itsClusterSizes >> (4 * i) & 15) + n++; + } + return n > 0 ? static_cast(sum) / n : 0.f; +}); +} // namespace hykftrk + +DECLARE_SOA_TABLE(HypKfTracks, "AOD", "HYPKFTRACK", + o2::soa::Index<>, + hykfmc::Species, + track::Pt, + track::Eta, + track::Phi, + track::DcaXY, + track::DcaZ, + hykftrk::TpcNcluster, + track::TPCChi2NCl, + track::ITSClusterSizes, + track::ITSChi2NCl, + hykftrk::Rigidity, + track::TPCSignal, + hykftrk::TpcNsigma, + hykftrk::TpcNsigmaNhp, + hykftrk::TpcNsigmaNlp, + hykftrk::TofMass, + hykftrk::IsPVContributor, + hykftrk::Px, + hykftrk::Py, + hykftrk::Pz, + hykftrk::P, + hykftrk::Lambda, + hykftrk::ItsNcluster, + hykftrk::ItsFirstLayer, + hykftrk::ItsMeanClsSize); +using HypKfTrack = HypKfTracks::iterator; + +DECLARE_SOA_TABLE(HypKfSubDs, "AOD", "HYPKFSUBD", + o2::soa::Index<>, + hykftrk::SubMass); +using HypKfSubD = HypKfSubDs::iterator; + +DECLARE_SOA_TABLE(HypKfDaughtAdds, "AOD", "HYPKFDAUGHTADD", + o2::soa::Index<>, + track::X, + track::Y, + track::Z, + mcparticle::Px, + mcparticle::Py, + mcparticle::Pz); +using HypKfDaughtAdd = HypKfDaughtAdds::iterator; + +namespace hykfhyp +{ +DECLARE_SOA_INDEX_COLUMN(HypKfColl, hypKfColl); +DECLARE_SOA_INDEX_COLUMN(HypKfMcPart, hypKfMcPart); +DECLARE_SOA_ARRAY_INDEX_COLUMN(HypKfDaughtAdd, hypKfDaughtAdd); +DECLARE_SOA_ARRAY_INDEX_COLUMN(HypKfTrack, hypKfTrack); +DECLARE_SOA_SELF_INDEX_COLUMN_FULL(HypDaughter, hypDaughter, int, "HypKfHypNucs"); +DECLARE_SOA_ARRAY_INDEX_COLUMN(HypKfSubD, hypKfSubD); +DECLARE_SOA_COLUMN(Primary, primary, bool); //! +DECLARE_SOA_COLUMN(Mass, mass, float); //! +DECLARE_SOA_COLUMN(Px, px, float); //! +DECLARE_SOA_COLUMN(Py, py, float); //! +DECLARE_SOA_COLUMN(Pz, pz, float); //! +DECLARE_SOA_COLUMN(DcaToPvXY, dcaToPvXY, float); //! +DECLARE_SOA_COLUMN(DcaToPvZ, dcaToPvZ, float); //! +DECLARE_SOA_COLUMN(DcaToVtxXY, dcaToVtxXY, float); //! +DECLARE_SOA_COLUMN(DcaToVtxZ, dcaToVtxZ, float); //! +DECLARE_SOA_COLUMN(Chi2, chi2, float); //! +DECLARE_SOA_COLUMN(DevToPvXY, devToPvXY, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float px, float py) { return RecoDecay::pt(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, [](float px, float py, float pz) { return RecoDecay::eta(std::array{px, py, pz}); }); +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, [](float px, float py) { return RecoDecay::phi(std::array{px, py}); }); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float px, float py, float pz) { return RecoDecay::p(px, py, pz); }); // +DECLARE_SOA_DYNAMIC_COLUMN(Y, y, [](float px, float py, float pz, float mass) { return RecoDecay::y(std::array{px, py, pz}, mass); }); +DECLARE_SOA_DYNAMIC_COLUMN(McTrue, mcTrue, [](int hypKfMcPartId) { return hypKfMcPartId > 0; }); +DECLARE_SOA_DYNAMIC_COLUMN(IsMatter, isMatter, [](int8_t species) { return species > 0; }); +DECLARE_SOA_DYNAMIC_COLUMN(Cascade, cascade, [](int hypDaughter) { return hypDaughter > 0; }); +} // namespace hykfhyp + +DECLARE_SOA_TABLE(HypKfHypNucs, "AOD", "HYPKFHYPNUC", + o2::soa::Index<>, + hykfhyp::HypKfMcPartId, + hykfhyp::HypKfCollId, + hykfhyp::HypKfTrackIds, + hykfhyp::HypKfDaughtAddIds, + hykfhyp::HypDaughterId, + hykfhyp::HypKfSubDIds, + hykfmc::Species, + hykfhyp::Primary, + hykfhyp::Mass, + hykfhyp::Px, + hykfhyp::Py, + hykfhyp::Pz, + hykfhyp::DcaToPvXY, + hykfhyp::DcaToPvZ, + hykfhyp::DevToPvXY, + hykfhyp::DcaToVtxXY, + hykfhyp::DcaToVtxZ, + hykfhyp::Chi2, + hykfmc::Svx, + hykfmc::Svy, + hykfmc::Svz, + hykfhyp::Y, + hykfhyp::Pt, + hykfhyp::Eta, + hykfhyp::Phi, + hykfhyp::P, + hykfhyp::McTrue, + hykfhyp::IsMatter, + hykfhyp::Cascade); +using HypKfHypNuc = HypKfHypNucs::iterator; +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_LFHYPERNUCLEIKFTABLES_H_ diff --git a/PWGLF/DataModel/LFHypernucleiTables.h b/PWGLF/DataModel/LFHypernucleiTables.h index ba87038753a..eeccdcdf26f 100644 --- a/PWGLF/DataModel/LFHypernucleiTables.h +++ b/PWGLF/DataModel/LFHypernucleiTables.h @@ -30,51 +30,55 @@ DECLARE_SOA_COLUMN(CentralityFT0M, centralityFT0M, float); // centrality with FT DECLARE_SOA_COLUMN(PsiFT0A, psiFT0A, float); // Psi with FT0A estimator DECLARE_SOA_COLUMN(MultFT0A, multFT0A, float); // Multiplicity with FT0A estimator DECLARE_SOA_COLUMN(PsiFT0C, psiFT0C, float); // Psi with FT0C estimator +DECLARE_SOA_COLUMN(QFT0C, qFT0C, float); // Amplitude with FT0C estimator DECLARE_SOA_COLUMN(MultFT0C, multFT0C, float); // Multiplicity with FT0C estimator DECLARE_SOA_COLUMN(PsiTPC, psiTPC, float); // Psi with TPC estimator DECLARE_SOA_COLUMN(MultTPC, multTPC, float); // Multiplicity with TPC estimator -DECLARE_SOA_COLUMN(IsMatter, isMatter, bool); // bool: true for matter -DECLARE_SOA_COLUMN(PtHe3, ptHe3, float); // Pt of the He daughter -DECLARE_SOA_COLUMN(PhiHe3, phiHe3, float); // Phi of the He daughter -DECLARE_SOA_COLUMN(EtaHe3, etaHe3, float); // Eta of the He daughter -DECLARE_SOA_COLUMN(PtPi, ptPi, float); // Pt of the Pi daughter -DECLARE_SOA_COLUMN(PhiPi, phiPi, float); // Phi of the Pi daughter -DECLARE_SOA_COLUMN(EtaPi, etaPi, float); // Eta of the Pi daughter -DECLARE_SOA_COLUMN(XPrimVtx, xPrimVtx, float); // Decay vertex of the candidate (x direction) -DECLARE_SOA_COLUMN(YPrimVtx, yPrimVtx, float); // Decay vertex of the candidate (y direction) -DECLARE_SOA_COLUMN(ZPrimVtx, zPrimVtx, float); // Decay vertex of the candidate (z direction) -DECLARE_SOA_COLUMN(XDecVtx, xDecVtx, float); // Decay vertex of the candidate (x direction) -DECLARE_SOA_COLUMN(YDecVtx, yDecVtx, float); // Decay vertex of the candidate (y direction) -DECLARE_SOA_COLUMN(ZDecVtx, zDecVtx, float); // Decay vertex of the candidate (z direction) -DECLARE_SOA_COLUMN(MassH3L, massH3L, float); // Squared mass w/ hypertriton mass hypo -DECLARE_SOA_COLUMN(MassH4L, massH4L, float); // Squared mass w/ H4L mass hypo -DECLARE_SOA_COLUMN(DcaV0Daug, dcaV0Daug, float); // DCA between daughters -DECLARE_SOA_COLUMN(CosPA, cosPA, double); // Cosine of the pointing angle -DECLARE_SOA_COLUMN(NSigmaHe, nSigmaHe, float); // Number of sigmas of the He daughter -DECLARE_SOA_COLUMN(NTPCclusHe, nTPCclusHe, uint8_t); // Number of TPC clusters of the He daughter -DECLARE_SOA_COLUMN(NTPCclusPi, nTPCclusPi, uint8_t); // Number of TPC clusters of the Pi daughter -DECLARE_SOA_COLUMN(TPCsignalHe, tpcSignalHe, uint16_t); // TPC signal of the He daughter -DECLARE_SOA_COLUMN(TPCsignalPi, tpcSignalPi, uint16_t); // TPC signal of the Pi daughter -DECLARE_SOA_COLUMN(Tracked, tracked, bool); // bool: true for tracked candidates -DECLARE_SOA_COLUMN(Flags, flags, uint8_t); // Flags for PID in tracking (bits [0, 3] for negative daughter, [4,7] for positive daughter) -DECLARE_SOA_COLUMN(TPCmomHe, tpcMomHe, float); // TPC momentum of the He daughter -DECLARE_SOA_COLUMN(TPCmomPi, tpcMomPi, float); // TPC momentum of the Pi daughter -DECLARE_SOA_COLUMN(ITSclusterSizesHe, itsClusterSizesHe, uint32_t); // ITS cluster size of the He daughter -DECLARE_SOA_COLUMN(ITSclusterSizesPi, itsClusterSizesPi, uint32_t); // ITS cluster size of the Pi daughter -DECLARE_SOA_COLUMN(DcaHe, dcaHe, float); // DCA between He daughter and V0 -DECLARE_SOA_COLUMN(DcaPi, dcaPi, float); // DCA between pi daughter and V0 -DECLARE_SOA_COLUMN(GenPt, genPt, float); // Pt of the hypertriton -DECLARE_SOA_COLUMN(GenPhi, genPhi, float); // Phi of the hypertriton -DECLARE_SOA_COLUMN(GenEta, genEta, float); // Eta of the hypertriton -DECLARE_SOA_COLUMN(GenPtHe3, genPtHe3, float); // Pt of the He daughter (to be used for the recalibration) -DECLARE_SOA_COLUMN(GenXDecVtx, genXDecVtx, float); // Decay vertex of the candidate (x direction) -DECLARE_SOA_COLUMN(GenYDecVtx, genYDecVtx, float); // Decay vertex of the candidate (y direction) -DECLARE_SOA_COLUMN(GenZDecVtx, genZDecVtx, float); // Decay vertex of the candidate (z direction) -DECLARE_SOA_COLUMN(IsReco, isReco, bool); // bool: true for reco -DECLARE_SOA_COLUMN(IsSignal, isSignal, bool); // bool: true for signal -DECLARE_SOA_COLUMN(IsRecoMCCollision, isRecoMCCollision, bool); // bool: true for reco MC collision -DECLARE_SOA_COLUMN(IsSurvEvSel, isSurvEvSel, bool); // bool: true for survived event selection +DECLARE_SOA_COLUMN(IsMatter, isMatter, bool); // bool: true for matter +DECLARE_SOA_COLUMN(PtHe3, ptHe3, float); // Pt of the He daughter +DECLARE_SOA_COLUMN(PhiHe3, phiHe3, float); // Phi of the He daughter +DECLARE_SOA_COLUMN(EtaHe3, etaHe3, float); // Eta of the He daughter +DECLARE_SOA_COLUMN(PtPi, ptPi, float); // Pt of the Pi daughter +DECLARE_SOA_COLUMN(PhiPi, phiPi, float); // Phi of the Pi daughter +DECLARE_SOA_COLUMN(EtaPi, etaPi, float); // Eta of the Pi daughter +DECLARE_SOA_COLUMN(XPrimVtx, xPrimVtx, float); // Decay vertex of the candidate (x direction) +DECLARE_SOA_COLUMN(YPrimVtx, yPrimVtx, float); // Decay vertex of the candidate (y direction) +DECLARE_SOA_COLUMN(ZPrimVtx, zPrimVtx, float); // Decay vertex of the candidate (z direction) +DECLARE_SOA_COLUMN(XDecVtx, xDecVtx, float); // Decay vertex of the candidate (x direction) +DECLARE_SOA_COLUMN(YDecVtx, yDecVtx, float); // Decay vertex of the candidate (y direction) +DECLARE_SOA_COLUMN(ZDecVtx, zDecVtx, float); // Decay vertex of the candidate (z direction) +DECLARE_SOA_COLUMN(MassH3L, massH3L, float); // Squared mass w/ hypertriton mass hypo +DECLARE_SOA_COLUMN(MassH4L, massH4L, float); // Squared mass w/ H4L mass hypo +DECLARE_SOA_COLUMN(DcaV0Daug, dcaV0Daug, float); // DCA between daughters +DECLARE_SOA_COLUMN(CosPA, cosPA, double); // Cosine of the pointing angle +DECLARE_SOA_COLUMN(NSigmaHe, nSigmaHe, float); // Number of sigmas of the He daughter +DECLARE_SOA_COLUMN(NTPCclusHe, nTPCclusHe, uint8_t); // Number of TPC clusters of the He daughter +DECLARE_SOA_COLUMN(NTPCclusPi, nTPCclusPi, uint8_t); // Number of TPC clusters of the Pi daughter +DECLARE_SOA_COLUMN(TPCsignalHe, tpcSignalHe, uint16_t); // TPC signal of the He daughter +DECLARE_SOA_COLUMN(TPCsignalPi, tpcSignalPi, uint16_t); // TPC signal of the Pi daughter +DECLARE_SOA_COLUMN(TPCChi2He, tpcChi2He, float); // TPC chi2 of the He daughter +DECLARE_SOA_COLUMN(TrackedClSize, trackedClSize, int); // int: zero for non-tracked candidates +DECLARE_SOA_COLUMN(Flags, flags, uint8_t); // Flags for PID in tracking (bits [0, 3] for negative daughter, [4,7] for positive daughter) +DECLARE_SOA_COLUMN(TPCmomHe, tpcMomHe, float); // TPC momentum of the He daughter +DECLARE_SOA_COLUMN(TPCmomPi, tpcMomPi, float); // TPC momentum of the Pi daughter +DECLARE_SOA_COLUMN(TOFMass, tofMass, float); // TOF mass of the candidate +DECLARE_SOA_COLUMN(ITSclusterSizesHe, itsClusterSizesHe, uint32_t); // ITS cluster size of the He daughter +DECLARE_SOA_COLUMN(ITSclusterSizesPi, itsClusterSizesPi, uint32_t); // ITS cluster size of the Pi daughter +DECLARE_SOA_COLUMN(ITSclusterSizesHyp, itsClusterSizesHyp, uint32_t); // ITS cluster size of the Pi daughter +DECLARE_SOA_COLUMN(DcaHe, dcaHe, float); // DCA between He daughter and V0 +DECLARE_SOA_COLUMN(DcaPi, dcaPi, float); // DCA between pi daughter and V0 +DECLARE_SOA_COLUMN(GenPt, genPt, float); // Pt of the hypertriton +DECLARE_SOA_COLUMN(GenPhi, genPhi, float); // Phi of the hypertriton +DECLARE_SOA_COLUMN(GenEta, genEta, float); // Eta of the hypertriton +DECLARE_SOA_COLUMN(GenPtHe3, genPtHe3, float); // Pt of the He daughter (to be used for the recalibration) +DECLARE_SOA_COLUMN(GenXDecVtx, genXDecVtx, float); // Decay vertex of the candidate (x direction) +DECLARE_SOA_COLUMN(GenYDecVtx, genYDecVtx, float); // Decay vertex of the candidate (y direction) +DECLARE_SOA_COLUMN(GenZDecVtx, genZDecVtx, float); // Decay vertex of the candidate (z direction) +DECLARE_SOA_COLUMN(IsReco, isReco, bool); // bool: true for reco +DECLARE_SOA_COLUMN(IsSignal, isSignal, bool); // bool: true for signal +DECLARE_SOA_COLUMN(IsRecoMCCollision, isRecoMCCollision, bool); // bool: true for reco MC collision +DECLARE_SOA_COLUMN(IsSurvEvSel, isSurvEvSel, bool); // bool: true for survived event selection } // namespace hyperrec DECLARE_SOA_TABLE(DataHypCands, "AOD", "HYPCANDS", @@ -88,15 +92,16 @@ DECLARE_SOA_TABLE(DataHypCands, "AOD", "HYPCANDS", hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::DcaV0Daug, hyperrec::DcaHe, hyperrec::DcaPi, hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, - hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, + hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, + hyperrec::TOFMass, hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, - hyperrec::Flags, hyperrec::Tracked); + hyperrec::Flags, hyperrec::TrackedClSize); DECLARE_SOA_TABLE(DataHypCandsFlow, "AOD", "HYPCANDSFLOW", o2::soa::Index<>, hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, hyperrec::PsiFT0A, hyperrec::MultFT0A, - hyperrec::PsiFT0C, hyperrec::MultFT0C, + hyperrec::PsiFT0C, hyperrec::MultFT0C, hyperrec::QFT0C, hyperrec::PsiTPC, hyperrec::MultTPC, hyperrec::XPrimVtx, hyperrec::YPrimVtx, hyperrec::ZPrimVtx, @@ -106,9 +111,10 @@ DECLARE_SOA_TABLE(DataHypCandsFlow, "AOD", "HYPCANDSFLOW", hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::DcaV0Daug, hyperrec::DcaHe, hyperrec::DcaPi, hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, - hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, + hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, + hyperrec::TOFMass, hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, - hyperrec::Flags, hyperrec::Tracked); + hyperrec::Flags, hyperrec::TrackedClSize); DECLARE_SOA_TABLE(MCHypCands, "AOD", "MCHYPCANDS", o2::soa::Index<>, @@ -121,9 +127,10 @@ DECLARE_SOA_TABLE(MCHypCands, "AOD", "MCHYPCANDS", hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::DcaV0Daug, hyperrec::DcaHe, hyperrec::DcaPi, hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, - hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, + hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, + hyperrec::TOFMass, hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, - hyperrec::Flags, hyperrec::Tracked, + hyperrec::Flags, hyperrec::TrackedClSize, hyperrec::GenPt, hyperrec::GenPhi, hyperrec::GenEta, @@ -188,7 +195,8 @@ DECLARE_SOA_TABLE(MCHypKinkCands, "AOD", "MCHYPKINKCANDS", hyperkink::TPCmomTrit, hyperkink::TPCsignalTrit, hyperkink::NSigmaTPCTrit, hyperkink::NSigmaTOFTrit, hyperrec::GenXDecVtx, hyperrec::GenYDecVtx, hyperrec::GenZDecVtx, hyperrec::GenPt, hyperkink::GenPtTrit, - hyperrec::IsReco, hyperrec::IsSignal, hyperkink::MCMask, hyperkink::HyperPtITS); + hyperrec::IsReco, hyperrec::IsSignal, hyperkink::MCMask, hyperkink::HyperPtITS, + hyperrec::IsRecoMCCollision, hyperrec::IsSurvEvSel); } // namespace o2::aod diff --git a/PWGLF/DataModel/LFKinkDecayTables.h b/PWGLF/DataModel/LFKinkDecayTables.h new file mode 100644 index 00000000000..5f8798856d5 --- /dev/null +++ b/PWGLF/DataModel/LFKinkDecayTables.h @@ -0,0 +1,100 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file LFKinkDecayTables.h +/// \brief Slim tables for kinks +/// \author Francesco Mazzaschi +/// + +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Common/Core/RecoDecay.h" + +#ifndef PWGLF_DATAMODEL_LFKINKDECAYTABLES_H_ +#define PWGLF_DATAMODEL_LFKINKDECAYTABLES_H_ + +namespace o2::aod +{ + +namespace kinkcand +{ + +DECLARE_SOA_INDEX_COLUMN_FULL(TrackMoth, trackMoth, int, TracksIU, "_Moth"); //! +DECLARE_SOA_INDEX_COLUMN_FULL(TrackDaug, trackDaug, int, TracksIU, "_Daug"); //! +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! + +DECLARE_SOA_COLUMN(XDecVtx, xDecVtx, float); //! Decay vertex of the candidate (x direction) +DECLARE_SOA_COLUMN(YDecVtx, yDecVtx, float); //! Decay vertex of the candidate (y direction) +DECLARE_SOA_COLUMN(ZDecVtx, zDecVtx, float); //! Decay vertex of the candidate (z direction) +DECLARE_SOA_COLUMN(PxMoth, pxMoth, float); //! Px of the mother kink +DECLARE_SOA_COLUMN(PyMoth, pyMoth, float); //! Py of the mother kink +DECLARE_SOA_COLUMN(PzMoth, pzMoth, float); //! Pz of the mother kink +DECLARE_SOA_COLUMN(PxDaug, pxDaug, float); //! Px of the daughter kink +DECLARE_SOA_COLUMN(PyDaug, pyDaug, float); //! Py of the daughter kink +DECLARE_SOA_COLUMN(PzDaug, pzDaug, float); //! Pz of the daughter kink +DECLARE_SOA_COLUMN(MothSign, mothSign, int); //! Sign of the mother kink +DECLARE_SOA_COLUMN(DcaMothPv, dcaMothPv, float); //! DCA of the mother to the primary vertex +DECLARE_SOA_COLUMN(DcaDaugPv, dcaDaugPv, float); //! DCA of the daughter kink to the primary vertex +DECLARE_SOA_COLUMN(DcaKinkTopo, dcaKinkTopo, float); //! DCA of the kink topology + +// DYNAMIC COLUMNS + +DECLARE_SOA_DYNAMIC_COLUMN(PxDaugNeut, pxDaugNeut, //! Px of the daughter neutral particle + [](float pxmoth, float pxdau) -> float { return pxmoth - pxdau; }); + +DECLARE_SOA_DYNAMIC_COLUMN(PyDaugNeut, pyDaugNeut, //! Py of the daughter neutral particle + [](float pymoth, float pydau) -> float { return pymoth - pydau; }); + +DECLARE_SOA_DYNAMIC_COLUMN(PzDaugNeut, pzDaugNeut, //! Pz of the daughter neutral particle + [](float pzmoth, float pzdau) -> float { return pzmoth - pzdau; }); + +DECLARE_SOA_DYNAMIC_COLUMN(PtMoth, ptMoth, //! pT of the mother kink + [](float pxmoth, float pymoth) -> float { return std::hypot(pxmoth, pymoth); }); + +DECLARE_SOA_DYNAMIC_COLUMN(PtDaug, ptDaug, //! + [](float pxdaug, float pydaug) -> float { return std::hypot(pxdaug, pydaug); }); + +DECLARE_SOA_DYNAMIC_COLUMN(MSigmaMinus, mSigmaMinus, //! mass under sigma minus hypothesis + [](float pxmoth, float pymoth, float pzmoth, float pxch, float pych, float pzch) -> float { + float pxneut = pxmoth - pxch; + float pyneut = pymoth - pych; + float pzneut = pzmoth - pzch; + return RecoDecay::m(std::array{std::array{pxch, pych, pzch}, std::array{pxneut, pyneut, pzneut}}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassNeutron}); }); + +DECLARE_SOA_DYNAMIC_COLUMN(MSigmaPlus, mSigmaPlus, //! mass under sigma plus hypothesis + [](float pxmoth, float pymoth, float pzmoth, float pxch, float pych, float pzch) -> float { + float pxneut = pxmoth - pxch; + float pyneut = pymoth - pych; + float pzneut = pzmoth - pzch; + return RecoDecay::m(std::array{std::array{pxch, pych, pzch}, std::array{pxneut, pyneut, pzneut}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionNeutral}); }); + +} // namespace kinkcand + +DECLARE_SOA_TABLE(KinkCands, "AOD", "KINKCANDS", + o2::soa::Index<>, kinkcand::CollisionId, kinkcand::TrackMothId, kinkcand::TrackDaugId, + kinkcand::XDecVtx, kinkcand::YDecVtx, kinkcand::ZDecVtx, + kinkcand::MothSign, kinkcand::PxMoth, kinkcand::PyMoth, kinkcand::PzMoth, + kinkcand::PxDaug, kinkcand::PyDaug, kinkcand::PzDaug, + kinkcand::DcaMothPv, kinkcand::DcaDaugPv, kinkcand::DcaKinkTopo, + + // dynamic columns + kinkcand::PxDaugNeut, + kinkcand::PyDaugNeut, + kinkcand::PzDaugNeut, + kinkcand::PtMoth, + kinkcand::PtDaug, + kinkcand::MSigmaMinus, + kinkcand::MSigmaPlus); + +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_LFKINKDECAYTABLES_H_ diff --git a/PWGLF/DataModel/LFLithium4Tables.h b/PWGLF/DataModel/LFLithium4Tables.h index 50c5acb5cca..486e44575ee 100644 --- a/PWGLF/DataModel/LFLithium4Tables.h +++ b/PWGLF/DataModel/LFLithium4Tables.h @@ -44,6 +44,8 @@ DECLARE_SOA_COLUMN(InnerParamTPCPr, innerParamTPCPr, float); DECLARE_SOA_COLUMN(NClsTPCHe3, nClsTPCHe3, uint8_t); DECLARE_SOA_COLUMN(NSigmaTPCHe3, nSigmaTPCHe3, float); DECLARE_SOA_COLUMN(NSigmaTPCPr, nSigmaTOFPr, float); +DECLARE_SOA_COLUMN(Chi2TPCHe3, chi2TPCHe3, float); +DECLARE_SOA_COLUMN(Chi2TPCPr, chi2TPCPr, float); DECLARE_SOA_COLUMN(MassTOFHe3, massTOFHe3, float); DECLARE_SOA_COLUMN(MassTOFPr, massTOFPr, float); DECLARE_SOA_COLUMN(PIDtrkHe3, pidTrkHe3, uint32_t); @@ -59,10 +61,18 @@ DECLARE_SOA_COLUMN(IsBkgLS, isBkgLS, bool); DECLARE_SOA_COLUMN(IsBkgEM, isBkgEM, bool); DECLARE_SOA_COLUMN(PtMCHe3, ptMCHe3, float); +DECLARE_SOA_COLUMN(EtaMCHe3, etaMCHe3, float); +DECLARE_SOA_COLUMN(PhiMCHe3, phiMCHe3, float); DECLARE_SOA_COLUMN(PtMCPr, ptMCPr, float); +DECLARE_SOA_COLUMN(EtaMCPr, etaMCPr, float); +DECLARE_SOA_COLUMN(PhiMCPr, phiMCPr, float); DECLARE_SOA_COLUMN(SignedPtMC, signedPtMC, float); DECLARE_SOA_COLUMN(MassMC, massMC, float); +DECLARE_SOA_COLUMN(Multiplicity, multiplicity, uint16_t); +DECLARE_SOA_COLUMN(CentralityFT0C, centFT0C, float); +DECLARE_SOA_COLUMN(MultiplicityFT0C, multiplicityFT0C, float); + } // namespace Lithium4TablesNS DECLARE_SOA_TABLE(Lithium4Table, "AOD", "LITHIUM4TABLE", @@ -83,6 +93,8 @@ DECLARE_SOA_TABLE(Lithium4Table, "AOD", "LITHIUM4TABLE", Lithium4TablesNS::NClsTPCHe3, Lithium4TablesNS::NSigmaTPCHe3, Lithium4TablesNS::NSigmaTPCPr, + Lithium4TablesNS::Chi2TPCHe3, + Lithium4TablesNS::Chi2TPCPr, Lithium4TablesNS::MassTOFHe3, Lithium4TablesNS::MassTOFPr, Lithium4TablesNS::PIDtrkHe3, @@ -94,37 +106,18 @@ DECLARE_SOA_TABLE(Lithium4Table, "AOD", "LITHIUM4TABLE", Lithium4TablesNS::IsBkgLS, Lithium4TablesNS::IsBkgEM) DECLARE_SOA_TABLE(Lithium4TableMC, "AOD", "LITHIUM4TABLEMC", - Lithium4TablesNS::PtHe3, - Lithium4TablesNS::EtaHe3, - Lithium4TablesNS::PhiHe3, - Lithium4TablesNS::PtPr, - Lithium4TablesNS::EtaPr, - Lithium4TablesNS::PhiPr, - Lithium4TablesNS::DCAxyHe3, - Lithium4TablesNS::DCAzHe3, - Lithium4TablesNS::DCAxyPr, - Lithium4TablesNS::DCAzPr, - Lithium4TablesNS::SignalTPCHe3, - Lithium4TablesNS::InnerParamTPCHe3, - Lithium4TablesNS::SignalTPCPr, - Lithium4TablesNS::InnerParamTPCPr, - Lithium4TablesNS::NClsTPCHe3, - Lithium4TablesNS::NSigmaTPCHe3, - Lithium4TablesNS::NSigmaTPCPr, - Lithium4TablesNS::MassTOFHe3, - Lithium4TablesNS::MassTOFPr, - Lithium4TablesNS::PIDtrkHe3, - Lithium4TablesNS::PIDtrkPr, - Lithium4TablesNS::ItsClusterSizeHe3, - Lithium4TablesNS::ItsClusterSizePr, - Lithium4TablesNS::SharedClustersHe3, - Lithium4TablesNS::SharedClustersPr, - Lithium4TablesNS::IsBkgLS, - Lithium4TablesNS::IsBkgEM, Lithium4TablesNS::PtMCHe3, + Lithium4TablesNS::EtaMCHe3, + Lithium4TablesNS::PhiMCHe3, Lithium4TablesNS::PtMCPr, + Lithium4TablesNS::EtaMCPr, + Lithium4TablesNS::PhiMCPr, Lithium4TablesNS::SignedPtMC, Lithium4TablesNS::MassMC) +DECLARE_SOA_TABLE(Lithium4Mult, "AOD", "LITHIUM4MULT", + Lithium4TablesNS::Multiplicity, + Lithium4TablesNS::CentralityFT0C, + Lithium4TablesNS::MultiplicityFT0C) } // namespace o2::aod diff --git a/PWGLF/DataModel/LFLnnTables.h b/PWGLF/DataModel/LFLnnTables.h index 2ee0fa22839..f9ab7fe3989 100644 --- a/PWGLF/DataModel/LFLnnTables.h +++ b/PWGLF/DataModel/LFLnnTables.h @@ -58,6 +58,8 @@ DECLARE_SOA_COLUMN(TPCsignalPi, tpcSignalPi, uint16_t); // TPC DECLARE_SOA_COLUMN(Flags, flags, uint8_t); // Flags for PID in tracking (bits [0, 3] for negative daughter, [4,7] for positive daughter) DECLARE_SOA_COLUMN(TPCmom3H, tpcMom3H, float); // TPC momentum of the 3H daughter DECLARE_SOA_COLUMN(TPCmomPi, tpcMomPi, float); // TPC momentum of the Pi daughter +DECLARE_SOA_COLUMN(MassTrTOF, mass2TrTOF, float); // TOF 3H mass +DECLARE_SOA_COLUMN(TPCchi3H, tpcChi3H, float); // tpcChi3H DECLARE_SOA_COLUMN(ITSclusterSizes3H, itsClusterSizes3H, uint32_t); // ITS cluster size of the 3H daughter DECLARE_SOA_COLUMN(ITSclusterSizesPi, itsClusterSizesPi, uint32_t); // ITS cluster size of the Pi daughter DECLARE_SOA_COLUMN(Dca3H, dca3H, float); // DCA between 3H daughter and V0 @@ -87,6 +89,7 @@ DECLARE_SOA_TABLE(DataLnnCands, "AOD", "LNNCANDS", lnnrec::DcaV0Daug, lnnrec::Dca3H, lnnrec::DcaPi, lnnrec::NSigma3H, lnnrec::NTPCclus3H, lnnrec::NTPCclusPi, lnnrec::TPCmom3H, lnnrec::TPCmomPi, lnnrec::TPCsignal3H, lnnrec::TPCsignalPi, + lnnrec::MassTrTOF, lnnrec::TPCchi3H, lnnrec::ITSclusterSizes3H, lnnrec::ITSclusterSizesPi, lnnrec::Flags); @@ -102,6 +105,7 @@ DECLARE_SOA_TABLE(MCLnnCands, "AOD", "MCLNNCANDS", lnnrec::DcaV0Daug, lnnrec::Dca3H, lnnrec::DcaPi, lnnrec::NSigma3H, lnnrec::NTPCclus3H, lnnrec::NTPCclusPi, lnnrec::TPCmom3H, lnnrec::TPCmomPi, lnnrec::TPCsignal3H, lnnrec::TPCsignalPi, + lnnrec::MassTrTOF, lnnrec::TPCchi3H, lnnrec::ITSclusterSizes3H, lnnrec::ITSclusterSizesPi, lnnrec::Flags, lnnrec::GenPt, @@ -119,4 +123,4 @@ using DataLnnCand = DataLnnCands::iterator; using MCLnnCand = MCLnnCands::iterator; } // namespace o2::aod -#endif // PWGLF_DATAMODEL_LFLNNTABLES_H_ \ No newline at end of file +#endif // PWGLF_DATAMODEL_LFLNNTABLES_H_ diff --git a/PWGLF/DataModel/LFNonPromptCascadeTables.h b/PWGLF/DataModel/LFNonPromptCascadeTables.h index 7b8d32c76f6..bcdc5d6f08d 100644 --- a/PWGLF/DataModel/LFNonPromptCascadeTables.h +++ b/PWGLF/DataModel/LFNonPromptCascadeTables.h @@ -24,10 +24,33 @@ namespace o2::aod { namespace NPCascadeTable { +DECLARE_SOA_COLUMN(MatchingChi2, matchingChi2, float); +DECLARE_SOA_COLUMN(DeltaPtITSCascade, deltaPtITSCascade, float); +DECLARE_SOA_COLUMN(ITSClusSize, itsClusSize, float); +DECLARE_SOA_COLUMN(HasReassociatedCluster, hasReassociatedCluster, bool); +DECLARE_SOA_COLUMN(IsGoodMatch, isGoodMatch, bool); +DECLARE_SOA_COLUMN(IsGoodCascade, isGoodCascade, bool); +DECLARE_SOA_COLUMN(PdgCodeMom, pdgCodeMom, int); +DECLARE_SOA_COLUMN(PdgCodeITStrack, pdgCodeITStrack, int); +DECLARE_SOA_COLUMN(IsFromBeauty, isFromBeauty, bool); +DECLARE_SOA_COLUMN(IsFromCharm, isFromCharm, bool); + +DECLARE_SOA_COLUMN(PvX, pvX, float); +DECLARE_SOA_COLUMN(PvY, pvY, float); +DECLARE_SOA_COLUMN(PvZ, pvZ, float); +DECLARE_SOA_COLUMN(CascPVContribs, cascPVContribs, uint8_t); + DECLARE_SOA_COLUMN(CascPt, cascPt, float); DECLARE_SOA_COLUMN(CascEta, cascEta, float); DECLARE_SOA_COLUMN(CascPhi, cascPhi, float); +DECLARE_SOA_COLUMN(ProtonPt, protonPt, float); +DECLARE_SOA_COLUMN(ProtonEta, protonEta, float); +DECLARE_SOA_COLUMN(PionPt, pionPt, float); +DECLARE_SOA_COLUMN(PionEta, pionEta, float); +DECLARE_SOA_COLUMN(BachPt, bachPt, float); +DECLARE_SOA_COLUMN(BachEta, bachEta, float); + DECLARE_SOA_COLUMN(CascDCAxy, cascDCAxy, float); DECLARE_SOA_COLUMN(CascDCAz, cascDCAz, float); DECLARE_SOA_COLUMN(ProtonDCAxy, protonDCAxy, float); @@ -50,16 +73,14 @@ DECLARE_SOA_COLUMN(V0Radius, v0Radius, float); DECLARE_SOA_COLUMN(CascLenght, cascLenght, float); DECLARE_SOA_COLUMN(V0Lenght, v0Lenght, float); -DECLARE_SOA_COLUMN(CascNClusITS, cascNClusITS, int); -DECLARE_SOA_COLUMN(ProtonNClusITS, protonNClusITS, int); -DECLARE_SOA_COLUMN(PionNClusITS, pionNClusITS, int); -DECLARE_SOA_COLUMN(BachKaonNClusITS, bachKaonNClusITS, int); -DECLARE_SOA_COLUMN(BachPionNClusITS, bachPionNClusITS, int); +DECLARE_SOA_COLUMN(CascNClusITS, cascNClusITS, int16_t); +DECLARE_SOA_COLUMN(ProtonNClusITS, protonNClusITS, int16_t); +DECLARE_SOA_COLUMN(PionNClusITS, pionNClusITS, int16_t); +DECLARE_SOA_COLUMN(BachNClusITS, bachNClusITS, int16_t); -DECLARE_SOA_COLUMN(ProtonNClusTPC, protonNClusTPC, int); -DECLARE_SOA_COLUMN(PionNClusTPC, pionNClusTPC, int); -DECLARE_SOA_COLUMN(BachKaonNClusTPC, bachKaonNClusTPC, int); -DECLARE_SOA_COLUMN(BachPionNClusTPC, bachPionNClusTPC, int); +DECLARE_SOA_COLUMN(ProtonNClusTPC, protonNClusTPC, int16_t); +DECLARE_SOA_COLUMN(PionNClusTPC, pionNClusTPC, int16_t); +DECLARE_SOA_COLUMN(BachNClusTPC, bachNClusTPC, int16_t); DECLARE_SOA_COLUMN(ProtonTPCNSigma, protonTPCNSigma, float); DECLARE_SOA_COLUMN(PionTPCNSigma, pionTPCNSigma, float); @@ -68,8 +89,7 @@ DECLARE_SOA_COLUMN(BachPionTPCNSigma, bachPionTPCNSigma, float); DECLARE_SOA_COLUMN(ProtonHasTOF, protonHasTOF, bool); DECLARE_SOA_COLUMN(PionHasTOF, pionHasTOF, bool); -DECLARE_SOA_COLUMN(BachKaonHasTOF, bachKaonHasTOF, bool); -DECLARE_SOA_COLUMN(BachPionHasTOF, bachPionHasTOF, bool); +DECLARE_SOA_COLUMN(BachHasTOF, bachHasTOF, bool); DECLARE_SOA_COLUMN(ProtonTOFNSigma, protonTOFNSigma, float); DECLARE_SOA_COLUMN(PionTOFNSigma, pionTOFNSigma, float); @@ -80,12 +100,95 @@ DECLARE_SOA_COLUMN(gPt, genPt, float); DECLARE_SOA_COLUMN(gEta, genEta, float); DECLARE_SOA_COLUMN(gPhi, genPhi, float); DECLARE_SOA_COLUMN(PDGcode, pdgCode, int); +DECLARE_SOA_COLUMN(DCAxMC, dcaXmc, float); +DECLARE_SOA_COLUMN(DCAyMC, dcaYmc, float); +DECLARE_SOA_COLUMN(DCAzMC, dcaZmc, float); +DECLARE_SOA_COLUMN(MCcollisionMatch, mcCollisionMatch, bool); + +DECLARE_SOA_COLUMN(Sel8, sel8, bool); +DECLARE_SOA_COLUMN(MultFT0C, multFT0C, float); +DECLARE_SOA_COLUMN(MultFT0A, multFT0A, float); } // namespace NPCascadeTable DECLARE_SOA_TABLE(NPCascTable, "AOD", "NPCASCTABLE", + NPCascadeTable::MatchingChi2, + NPCascadeTable::DeltaPtITSCascade, + NPCascadeTable::ITSClusSize, + NPCascadeTable::HasReassociatedCluster, + aod::collision::NumContrib, + NPCascadeTable::CascPVContribs, + aod::collision::CollisionTimeRes, + NPCascadeTable::PvX, + NPCascadeTable::PvY, + NPCascadeTable::PvZ, + NPCascadeTable::CascPt, + NPCascadeTable::CascEta, + NPCascadeTable::CascPhi, + NPCascadeTable::ProtonPt, + NPCascadeTable::ProtonEta, + NPCascadeTable::PionPt, + NPCascadeTable::PionEta, + NPCascadeTable::BachPt, + NPCascadeTable::BachEta, + NPCascadeTable::CascDCAxy, + NPCascadeTable::CascDCAz, + NPCascadeTable::ProtonDCAxy, + NPCascadeTable::ProtonDCAz, + NPCascadeTable::PionDCAxy, + NPCascadeTable::PionDCAz, + NPCascadeTable::BachDCAxy, + NPCascadeTable::BachDCAz, + NPCascadeTable::CascCosPA, + NPCascadeTable::V0CosPA, + NPCascadeTable::MassXi, + NPCascadeTable::MassOmega, + NPCascadeTable::MassV0, + NPCascadeTable::CascRadius, + NPCascadeTable::V0Radius, + NPCascadeTable::CascLenght, + NPCascadeTable::V0Lenght, + NPCascadeTable::CascNClusITS, + NPCascadeTable::ProtonNClusITS, + NPCascadeTable::PionNClusITS, + NPCascadeTable::BachNClusITS, + NPCascadeTable::ProtonNClusTPC, + NPCascadeTable::PionNClusTPC, + NPCascadeTable::BachNClusTPC, + NPCascadeTable::ProtonTPCNSigma, + NPCascadeTable::PionTPCNSigma, + NPCascadeTable::BachKaonTPCNSigma, + NPCascadeTable::BachPionTPCNSigma, + NPCascadeTable::ProtonHasTOF, + NPCascadeTable::PionHasTOF, + NPCascadeTable::BachHasTOF, + NPCascadeTable::ProtonTOFNSigma, + NPCascadeTable::PionTOFNSigma, + NPCascadeTable::BachKaonTOFNSigma, + NPCascadeTable::BachPionTOFNSigma, + NPCascadeTable::Sel8, + NPCascadeTable::MultFT0C, + NPCascadeTable::MultFT0A) + +DECLARE_SOA_TABLE(NPCascTableNT, "AOD", "NPCASCTABLENT", + NPCascadeTable::MatchingChi2, + NPCascadeTable::DeltaPtITSCascade, + NPCascadeTable::ITSClusSize, + NPCascadeTable::HasReassociatedCluster, + aod::collision::NumContrib, + NPCascadeTable::CascPVContribs, + aod::collision::CollisionTimeRes, + NPCascadeTable::PvX, + NPCascadeTable::PvY, + NPCascadeTable::PvZ, NPCascadeTable::CascPt, NPCascadeTable::CascEta, NPCascadeTable::CascPhi, + NPCascadeTable::ProtonPt, + NPCascadeTable::ProtonEta, + NPCascadeTable::PionPt, + NPCascadeTable::PionEta, + NPCascadeTable::BachPt, + NPCascadeTable::BachEta, NPCascadeTable::CascDCAxy, NPCascadeTable::CascDCAz, NPCascadeTable::ProtonDCAxy, @@ -106,29 +209,124 @@ DECLARE_SOA_TABLE(NPCascTable, "AOD", "NPCASCTABLE", NPCascadeTable::CascNClusITS, NPCascadeTable::ProtonNClusITS, NPCascadeTable::PionNClusITS, - NPCascadeTable::BachKaonNClusITS, - NPCascadeTable::BachPionNClusITS, + NPCascadeTable::BachNClusITS, NPCascadeTable::ProtonNClusTPC, NPCascadeTable::PionNClusTPC, - NPCascadeTable::BachKaonNClusTPC, - NPCascadeTable::BachPionNClusTPC, + NPCascadeTable::BachNClusTPC, NPCascadeTable::ProtonTPCNSigma, NPCascadeTable::PionTPCNSigma, NPCascadeTable::BachKaonTPCNSigma, NPCascadeTable::BachPionTPCNSigma, NPCascadeTable::ProtonHasTOF, NPCascadeTable::PionHasTOF, - NPCascadeTable::BachKaonHasTOF, - NPCascadeTable::BachPionHasTOF, + NPCascadeTable::BachHasTOF, NPCascadeTable::ProtonTOFNSigma, NPCascadeTable::PionTOFNSigma, NPCascadeTable::BachKaonTOFNSigma, - NPCascadeTable::BachPionTOFNSigma) + NPCascadeTable::BachPionTOFNSigma, + NPCascadeTable::Sel8, + NPCascadeTable::MultFT0C, + NPCascadeTable::MultFT0A) DECLARE_SOA_TABLE(NPCascTableMC, "AOD", "NPCASCTABLEMC", + NPCascadeTable::MatchingChi2, + NPCascadeTable::DeltaPtITSCascade, + NPCascadeTable::ITSClusSize, + NPCascadeTable::HasReassociatedCluster, + NPCascadeTable::IsGoodMatch, + NPCascadeTable::IsGoodCascade, + NPCascadeTable::PdgCodeMom, + NPCascadeTable::PdgCodeITStrack, + NPCascadeTable::IsFromBeauty, + NPCascadeTable::IsFromCharm, + aod::collision::NumContrib, + NPCascadeTable::CascPVContribs, + aod::collision::CollisionTimeRes, + NPCascadeTable::PvX, + NPCascadeTable::PvY, + NPCascadeTable::PvZ, + NPCascadeTable::CascPt, + NPCascadeTable::CascEta, + NPCascadeTable::CascPhi, + NPCascadeTable::ProtonPt, + NPCascadeTable::ProtonEta, + NPCascadeTable::PionPt, + NPCascadeTable::PionEta, + NPCascadeTable::BachPt, + NPCascadeTable::BachEta, + NPCascadeTable::CascDCAxy, + NPCascadeTable::CascDCAz, + NPCascadeTable::ProtonDCAxy, + NPCascadeTable::ProtonDCAz, + NPCascadeTable::PionDCAxy, + NPCascadeTable::PionDCAz, + NPCascadeTable::BachDCAxy, + NPCascadeTable::BachDCAz, + NPCascadeTable::CascCosPA, + NPCascadeTable::V0CosPA, + NPCascadeTable::MassXi, + NPCascadeTable::MassOmega, + NPCascadeTable::MassV0, + NPCascadeTable::CascRadius, + NPCascadeTable::V0Radius, + NPCascadeTable::CascLenght, + NPCascadeTable::V0Lenght, + NPCascadeTable::CascNClusITS, + NPCascadeTable::ProtonNClusITS, + NPCascadeTable::PionNClusITS, + NPCascadeTable::BachNClusITS, + NPCascadeTable::ProtonNClusTPC, + NPCascadeTable::PionNClusTPC, + NPCascadeTable::BachNClusTPC, + NPCascadeTable::ProtonTPCNSigma, + NPCascadeTable::PionTPCNSigma, + NPCascadeTable::BachKaonTPCNSigma, + NPCascadeTable::BachPionTPCNSigma, + NPCascadeTable::ProtonHasTOF, + NPCascadeTable::PionHasTOF, + NPCascadeTable::BachHasTOF, + NPCascadeTable::ProtonTOFNSigma, + NPCascadeTable::PionTOFNSigma, + NPCascadeTable::BachKaonTOFNSigma, + NPCascadeTable::BachPionTOFNSigma, + NPCascadeTable::gPt, + NPCascadeTable::gEta, + NPCascadeTable::gPhi, + NPCascadeTable::PDGcode, + NPCascadeTable::DCAxMC, + NPCascadeTable::DCAyMC, + NPCascadeTable::DCAzMC, + NPCascadeTable::MCcollisionMatch, + NPCascadeTable::Sel8, + NPCascadeTable::MultFT0C, + NPCascadeTable::MultFT0A) + +DECLARE_SOA_TABLE(NPCascTableMCNT, "AOD", "NPCASCTABLEMCNT", + NPCascadeTable::MatchingChi2, + NPCascadeTable::DeltaPtITSCascade, + NPCascadeTable::ITSClusSize, + NPCascadeTable::HasReassociatedCluster, + NPCascadeTable::IsGoodMatch, + NPCascadeTable::IsGoodCascade, + NPCascadeTable::PdgCodeMom, + NPCascadeTable::PdgCodeITStrack, + NPCascadeTable::IsFromBeauty, + NPCascadeTable::IsFromCharm, + aod::collision::NumContrib, + NPCascadeTable::CascPVContribs, + aod::collision::CollisionTimeRes, + NPCascadeTable::PvX, + NPCascadeTable::PvY, + NPCascadeTable::PvZ, NPCascadeTable::CascPt, NPCascadeTable::CascEta, NPCascadeTable::CascPhi, + NPCascadeTable::ProtonPt, + NPCascadeTable::ProtonEta, + NPCascadeTable::PionPt, + NPCascadeTable::PionEta, + NPCascadeTable::BachPt, + NPCascadeTable::BachEta, NPCascadeTable::CascDCAxy, NPCascadeTable::CascDCAz, NPCascadeTable::ProtonDCAxy, @@ -149,20 +347,17 @@ DECLARE_SOA_TABLE(NPCascTableMC, "AOD", "NPCASCTABLEMC", NPCascadeTable::CascNClusITS, NPCascadeTable::ProtonNClusITS, NPCascadeTable::PionNClusITS, - NPCascadeTable::BachKaonNClusITS, - NPCascadeTable::BachPionNClusITS, + NPCascadeTable::BachNClusITS, NPCascadeTable::ProtonNClusTPC, NPCascadeTable::PionNClusTPC, - NPCascadeTable::BachKaonNClusTPC, - NPCascadeTable::BachPionNClusTPC, + NPCascadeTable::BachNClusTPC, NPCascadeTable::ProtonTPCNSigma, NPCascadeTable::PionTPCNSigma, NPCascadeTable::BachKaonTPCNSigma, NPCascadeTable::BachPionTPCNSigma, NPCascadeTable::ProtonHasTOF, NPCascadeTable::PionHasTOF, - NPCascadeTable::BachKaonHasTOF, - NPCascadeTable::BachPionHasTOF, + NPCascadeTable::BachHasTOF, NPCascadeTable::ProtonTOFNSigma, NPCascadeTable::PionTOFNSigma, NPCascadeTable::BachKaonTOFNSigma, @@ -170,7 +365,26 @@ DECLARE_SOA_TABLE(NPCascTableMC, "AOD", "NPCASCTABLEMC", NPCascadeTable::gPt, NPCascadeTable::gEta, NPCascadeTable::gPhi, - NPCascadeTable::PDGcode) + NPCascadeTable::PDGcode, + NPCascadeTable::DCAxMC, + NPCascadeTable::DCAyMC, + NPCascadeTable::DCAzMC, + NPCascadeTable::MCcollisionMatch, + NPCascadeTable::Sel8, + NPCascadeTable::MultFT0C, + NPCascadeTable::MultFT0A) + +DECLARE_SOA_TABLE(NPCascTableGen, "AOD", "NPCASCTABLEGen", + NPCascadeTable::gPt, + NPCascadeTable::gEta, + NPCascadeTable::gPhi, + NPCascadeTable::PDGcode, + NPCascadeTable::PdgCodeMom, + NPCascadeTable::DCAxMC, + NPCascadeTable::DCAyMC, + NPCascadeTable::DCAzMC, + NPCascadeTable::IsFromBeauty, + NPCascadeTable::IsFromCharm) } // namespace o2::aod diff --git a/PWGLF/DataModel/LFNucleiTables.h b/PWGLF/DataModel/LFNucleiTables.h index fe8459a18a6..2fcd940d070 100644 --- a/PWGLF/DataModel/LFNucleiTables.h +++ b/PWGLF/DataModel/LFNucleiTables.h @@ -22,8 +22,6 @@ #ifndef PWGLF_DATAMODEL_LFNUCLEITABLES_H_ #define PWGLF_DATAMODEL_LFNUCLEITABLES_H_ -using namespace o2; - namespace o2::aod { namespace fullEvent @@ -187,44 +185,44 @@ DECLARE_SOA_TABLE(LfCandNucleus, "AOD", "LFNUCL", track::TPCNClsCrossedRows, track::TPCCrossedRowsOverFindableCls, track::TPCFoundOverFindableCls); -DECLARE_SOA_TABLE_FULL(LfCandNucleusDummy, "LfCandNucleus", "AOD", "LFNUCL", - o2::soa::Index<>, - full::LfNuclEventId, - full::DcaXY, full::DcaZ, - full::TPCNSigmaDe, full::TPCNSigmaHe, - full::TOFNSigmaDe, full::TOFNSigmaHe, - full::IsEvTimeTOF, - full::IsEvTimeT0AC, - full::HasTOF, - full::HasTRD, - full::TPCInnerParam, - full::Beta, - full::TPCSignal, - full::Pt, - full::Eta, - full::Phi, - full::Sign, - full::ITSNCls, - track::TPCNClsFindable, - track::TPCNClsFindableMinusFound, - track::TPCNClsFindableMinusCrossedRows, - full::TPCChi2Ncl, - full::ITSChi2NCl, - track::ITSClusterMap, - full::IsPVContributor, - full::P, - dummy::TPCNSigmaPi, dummy::TPCNSigmaKa, dummy::TPCNSigmaPr, - dummy::TPCNSigmaTr, dummy::TPCNSigmaAl, - dummy::TOFNSigmaPi, dummy::TOFNSigmaKa, dummy::TOFNSigmaPr, - dummy::TOFNSigmaTr, dummy::TOFNSigmaAl, - dummy::TPCExpSignalDiffPr, dummy::TPCExpSignalDiffDe, dummy::TPCExpSignalDiffHe, - dummy::TOFExpSignalDiffPr, dummy::TOFExpSignalDiffDe, dummy::TOFExpSignalDiffHe, - dummy::TOFExpMom, - full::Rapidity, - track::TPCNClsFound, - track::TPCNClsCrossedRows, - track::TPCCrossedRowsOverFindableCls, - track::TPCFoundOverFindableCls); +DECLARE_SOA_TABLE_VERSIONED(LfCandNucleusDummy, "AOD", "LFNUCL", 1, + o2::soa::Index<>, + full::LfNuclEventId, + full::DcaXY, full::DcaZ, + full::TPCNSigmaDe, full::TPCNSigmaHe, + full::TOFNSigmaDe, full::TOFNSigmaHe, + full::IsEvTimeTOF, + full::IsEvTimeT0AC, + full::HasTOF, + full::HasTRD, + full::TPCInnerParam, + full::Beta, + full::TPCSignal, + full::Pt, + full::Eta, + full::Phi, + full::Sign, + full::ITSNCls, + track::TPCNClsFindable, + track::TPCNClsFindableMinusFound, + track::TPCNClsFindableMinusCrossedRows, + full::TPCChi2Ncl, + full::ITSChi2NCl, + track::ITSClusterMap, + full::IsPVContributor, + full::P, + dummy::TPCNSigmaPi, dummy::TPCNSigmaKa, dummy::TPCNSigmaPr, + dummy::TPCNSigmaTr, dummy::TPCNSigmaAl, + dummy::TOFNSigmaPi, dummy::TOFNSigmaKa, dummy::TOFNSigmaPr, + dummy::TOFNSigmaTr, dummy::TOFNSigmaAl, + dummy::TPCExpSignalDiffPr, dummy::TPCExpSignalDiffDe, dummy::TPCExpSignalDiffHe, + dummy::TOFExpSignalDiffPr, dummy::TOFExpSignalDiffDe, dummy::TOFExpSignalDiffHe, + dummy::TOFExpMom, + full::Rapidity, + track::TPCNClsFound, + track::TPCNClsCrossedRows, + track::TPCCrossedRowsOverFindableCls, + track::TPCFoundOverFindableCls); DECLARE_SOA_TABLE(LfCandNucleusExtra, "AOD", "LFNUCLEXTRA", full::TPCNSigmaPi, full::TPCNSigmaKa, full::TPCNSigmaPr, diff --git a/PWGLF/DataModel/LFResonanceTables.h b/PWGLF/DataModel/LFResonanceTables.h index b62661e448f..6d0b909a695 100644 --- a/PWGLF/DataModel/LFResonanceTables.h +++ b/PWGLF/DataModel/LFResonanceTables.h @@ -15,11 +15,15 @@ /// Inspired by StrangenessTables.h, FemtoDerived.h /// /// \author Bong-Hwi Lim +/// \author Nasir Mehdi Malik +/// \author Minjae Kim +/// #ifndef PWGLF_DATAMODEL_LFRESONANCETABLES_H_ #define PWGLF_DATAMODEL_LFRESONANCETABLES_H_ #include +#include #include "Common/DataModel/PIDResponse.h" #include "Common/Core/RecoDecay.h" @@ -33,15 +37,82 @@ namespace o2::aod /// Resonance Collisions namespace resocollision { -DECLARE_SOA_COLUMN(Cent, cent, float); //! Centrality (Multiplicity) percentile (Default: FT0M) -DECLARE_SOA_COLUMN(Spherocity, spherocity, float); //! Spherocity of the event -DECLARE_SOA_COLUMN(EvtPl, evtPl, float); //! Second harmonic event plane -DECLARE_SOA_COLUMN(EvtPlResAB, evtPlResAB, float); //! Second harmonic event plane resolution of A-B sub events -DECLARE_SOA_COLUMN(EvtPlResAC, evtPlResAC, float); //! Second harmonic event plane resolution of A-C sub events -DECLARE_SOA_COLUMN(EvtPlResBC, evtPlResBC, float); //! Second harmonic event plane resolution of B-C sub events -DECLARE_SOA_COLUMN(BMagField, bMagField, float); //! Magnetic field +enum { + kECbegin = 0, + kINEL = 1, + kINEL10, + kINELg0, + kINELg010, + kTrig, + kTrig10, + kTrigINELg0, + kTrigINELg010, + kSel8, + kSel810, + kSel8INELg0, + kSel8INELg010, + kAllCuts, + kAllCuts10, + kAllCutsINELg0, + kAllCutsINELg010, + kECend, +}; +DECLARE_SOA_INDEX_COLUMN_FULL(Collision, collision, int, Collisions, "_Col"); //! +DECLARE_SOA_COLUMN(Cent, cent, float); //! Centrality (Multiplicity) percentile (Default: FT0M) +DECLARE_SOA_COLUMN(Spherocity, spherocity, float); //! Spherocity of the event +DECLARE_SOA_COLUMN(EvtPl, evtPl, float); //! Second harmonic event plane +DECLARE_SOA_COLUMN(EvtPlResAB, evtPlResAB, float); //! Second harmonic event plane resolution of A-B sub events +DECLARE_SOA_COLUMN(EvtPlResAC, evtPlResAC, float); //! Second harmonic event plane resolution of A-C sub events +DECLARE_SOA_COLUMN(EvtPlResBC, evtPlResBC, float); //! Second harmonic event plane resolution of B-C sub events +DECLARE_SOA_COLUMN(BMagField, bMagField, float); //! Magnetic field +// MC +DECLARE_SOA_COLUMN(IsVtxIn10, isVtxIn10, bool); //! Vtx10 +DECLARE_SOA_COLUMN(IsINELgt0, isINELgt0, bool); //! INEL>0 +DECLARE_SOA_COLUMN(IsTriggerTVX, isTriggerTVX, bool); //! TriggerTVX +DECLARE_SOA_COLUMN(IsInSel8, isInSel8, bool); //! InSel8 +DECLARE_SOA_COLUMN(IsInAfterAllCuts, isInAfterAllCuts, bool); //! InAfterAllCuts +DECLARE_SOA_COLUMN(ImpactParameter, impactParameter, float); //! ImpactParameter + } // namespace resocollision -DECLARE_SOA_TABLE(ResoCollisions, "AOD", "RESOCOL", +DECLARE_SOA_TABLE(ResoCollisions, "AOD", "RESOCOLLISION", + o2::soa::Index<>, + o2::aod::mult::MultNTracksPV, + collision::PosX, + collision::PosY, + collision::PosZ, + resocollision::Cent, + resocollision::BMagField); +using ResoCollision = ResoCollisions::iterator; + +DECLARE_SOA_TABLE(ResoCollisionColls, "AOD", "RESOCOLLISIONCOL", + resocollision::CollisionId); +using ResoCollisionColl = ResoCollisionColls::iterator; + +DECLARE_SOA_TABLE(ResoMCCollisions, "AOD", "RESOMCCOLLISION", + o2::soa::Index<>, + resocollision::IsVtxIn10, + resocollision::IsINELgt0, + resocollision::IsTriggerTVX, + resocollision::IsInSel8, + resocollision::IsInAfterAllCuts, + resocollision::ImpactParameter); +using ResoMCCollision = ResoMCCollisions::iterator; + +DECLARE_SOA_TABLE(ResoSpheroCollisions, "AOD", "RESOSPHEROCOLLISION", + o2::soa::Index<>, + resocollision::Spherocity); +using ResoSpheroCollision = ResoSpheroCollisions::iterator; + +DECLARE_SOA_TABLE(ResoEvtPlCollisions, "AOD", "RESOEVTPLCOLLISION", + o2::soa::Index<>, + resocollision::EvtPl, + resocollision::EvtPlResAB, + resocollision::EvtPlResAC, + resocollision::EvtPlResBC); +using ResoEvtPlCollision = ResoEvtPlCollisions::iterator; + +// For DF mixing study +DECLARE_SOA_TABLE(ResoCollisionDFs, "AOD", "RESOCOLLISIONDF", o2::soa::Index<>, o2::aod::mult::MultNTracksPV, collision::PosX, @@ -54,108 +125,492 @@ DECLARE_SOA_TABLE(ResoCollisions, "AOD", "RESOCOL", resocollision::EvtPlResAC, resocollision::EvtPlResBC, resocollision::BMagField, - timestamp::Timestamp); -using ResoCollision = ResoCollisions::iterator; + timestamp::Timestamp, + evsel::NumTracksInTimeRange); +using ResoCollisionDF = ResoCollisionDFs::iterator; // Resonance Daughters // inspired from PWGCF/DataModel/FemtoDerived.h namespace resodaughter { +struct ResoTrackFlags { + public: + typedef uint8_t flagtype; + static constexpr flagtype kPassedITSRefit = 1 << 0; + static constexpr flagtype kPassedTPCRefit = 1 << 1; + static constexpr flagtype kIsGlobalTrackWoDCA = 1 << 2; + static constexpr flagtype kIsGlobalTrack = 1 << 3; + static constexpr flagtype kIsPrimaryTrack = 1 << 4; + static constexpr flagtype kIsPVContributor = 1 << 5; + static constexpr flagtype kHasTOF = 1 << 6; + static constexpr flagtype kSign = 1 << 7; + /// @brief check if the flag is set + static bool checkFlag(const flagtype flags, const flagtype mask) + { + return (flags & mask) == mask; + } +}; +#define requireTrackFlag(mask) ((o2::aod::resodaughter::trackFlags & o2::aod::resodaughter::mask) == o2::aod::resodaughter::mask) + +#define requirePassedITSRefit() requireTrackFlag(ResoTrackFlags::kPassedITSRefit) +#define requirePassedTPCRefit() requireTrackFlag(ResoTrackFlags::kPassedTPCRefit) +#define requireGlobalTrack() requireTrackFlag(ResoTrackFlags::kIsGlobalTrack) +#define requireGlobalTrackWoDCA() requireTrackFlag(ResoTrackFlags::kIsGlobalTrackWoDCA) +#define requirePrimaryTrack() requireTrackFlag(ResoTrackFlags::kIsPrimaryTrack) +#define requirePVContributor() requireTrackFlag(ResoTrackFlags::kIsPVContributor) +#define requireHasTOF() requireTrackFlag(ResoTrackFlags::kHasTOF) +#define requireSign() requireTrackFlag(ResoTrackFlags::kSign) + +#define DECLARE_DYN_TRKSEL_COLUMN(name, getter, mask) \ + DECLARE_SOA_DYNAMIC_COLUMN(name, getter, [](ResoTrackFlags::flagtype flags) -> bool { return ResoTrackFlags::checkFlag(flags, mask); }); DECLARE_SOA_INDEX_COLUMN(ResoCollision, resoCollision); -DECLARE_SOA_COLUMN(Pt, pt, float); //! p_T (GeV/c) -DECLARE_SOA_COLUMN(Px, px, float); //! p_x (GeV/c) -DECLARE_SOA_COLUMN(Py, py, float); //! p_y (GeV/c) -DECLARE_SOA_COLUMN(Pz, pz, float); //! p_z (GeV/c) -DECLARE_SOA_COLUMN(Eta, eta, float); //! Eta -DECLARE_SOA_COLUMN(Phi, phi, float); //! Phi -DECLARE_SOA_COLUMN(PartType, partType, uint8_t); //! Type of the particle, according to resodaughter::ParticleType -DECLARE_SOA_COLUMN(TempFitVar, tempFitVar, float); //! Observable for the template fitting (Track: DCA_xy, V0: CPA) -DECLARE_SOA_COLUMN(Indices, indices, int[2]); //! Field for the track indices to remove auto-correlations -DECLARE_SOA_COLUMN(CascadeIndices, cascIndices, int[3]); //! Field for the track indices to remove auto-correlations (ordered: positive, negative, bachelor) -DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! Sign of the track charge -DECLARE_SOA_COLUMN(TPCNClsCrossedRows, tpcNClsCrossedRows, uint8_t); //! Number of TPC crossed rows -DECLARE_SOA_COLUMN(TPCNClsFound, tpcNClsFound, uint8_t); //! Number of TPC clusters found -DECLARE_SOA_COLUMN(ITSNCls, itsNCls, uint8_t); //! Number of ITS clusters found -DECLARE_SOA_COLUMN(IsGlobalTrackWoDCA, isGlobalTrackWoDCA, bool); //! Is global track without DCA -DECLARE_SOA_COLUMN(IsGlobalTrack, isGlobalTrack, bool); //! Is global track -DECLARE_SOA_COLUMN(IsPrimaryTrack, isPrimaryTrack, bool); //! Is primary track -DECLARE_SOA_COLUMN(IsPVContributor, isPVContributor, bool); //! Is primary vertex contributor -DECLARE_SOA_COLUMN(HasTOF, hasTOF, bool); //! Has TOF -DECLARE_SOA_COLUMN(TPCCrossedRowsOverFindableCls, tpcCrossedRowsOverFindableCls, float); -DECLARE_SOA_COLUMN(DaughDCA, daughDCA, float); //! DCA between daughters -DECLARE_SOA_COLUMN(CascDaughDCA, cascdaughDCA, float); //! DCA between daughters from cascade -DECLARE_SOA_COLUMN(V0CosPA, v0CosPA, float); //! V0 Cosine of Pointing Angle -DECLARE_SOA_COLUMN(CascCosPA, cascCosPA, float); //! Cascade Cosine of Pointing Angle -DECLARE_SOA_COLUMN(MLambda, mLambda, float); //! The invariant mass of V0 candidate, assuming lambda -DECLARE_SOA_COLUMN(MAntiLambda, mAntiLambda, float); //! The invariant mass of V0 candidate, assuming antilambda -DECLARE_SOA_COLUMN(MK0Short, mK0Short, float); //! The invariant mass of V0 candidate, assuming k0s -DECLARE_SOA_COLUMN(MXi, mXi, float); //! The invariant mass of Xi candidate -DECLARE_SOA_COLUMN(TransRadius, transRadius, float); //! Transverse radius of the decay vertex -DECLARE_SOA_COLUMN(CascTransRadius, casctransRadius, float); //! Transverse radius of the decay vertex from cascade -DECLARE_SOA_COLUMN(DecayVtxX, decayVtxX, float); //! X position of the decay vertex -DECLARE_SOA_COLUMN(DecayVtxY, decayVtxY, float); //! Y position of the decay vertex -DECLARE_SOA_COLUMN(DecayVtxZ, decayVtxZ, float); //! Z position of the decay vertex +DECLARE_SOA_INDEX_COLUMN(ResoCollisionDF, resoCollisionDF); +DECLARE_SOA_INDEX_COLUMN_FULL(Track, track, int, Tracks, "_Trk"); //! +DECLARE_SOA_INDEX_COLUMN_FULL(V0, v0, int, V0s, "_V0"); //! +DECLARE_SOA_INDEX_COLUMN_FULL(Cascade, cascade, int, Cascades, "_Cas"); //! +DECLARE_SOA_COLUMN(Pt, pt, float); //! p_t (GeV/c) +DECLARE_SOA_COLUMN(Px, px, float); //! p_x (GeV/c) +DECLARE_SOA_COLUMN(Py, py, float); //! p_y (GeV/c) +DECLARE_SOA_COLUMN(Pz, pz, float); //! p_z (GeV/c) +DECLARE_SOA_COLUMN(PartType, partType, uint8_t); //! Type of the particle, according to resodaughter::ParticleType +DECLARE_SOA_COLUMN(TempFitVar, tempFitVar, float); //! Observable for the template fitting (Track: DCA_xy, V0: CPA) +DECLARE_SOA_COLUMN(Indices, indices, int[2]); //! Field for the track indices to remove auto-correlations +DECLARE_SOA_COLUMN(CascadeIndices, cascadeIndices, int[3]); //! Field for the track indices to remove auto-correlations (ordered: positive, negative, bachelor) +DECLARE_SOA_COLUMN(TpcNClsCrossedRows, tpcNClsCrossedRows, uint8_t); //! Number of TPC crossed rows +DECLARE_SOA_COLUMN(TpcNClsFound, tpcNClsFound, uint8_t); //! Number of TPC clusters found +DECLARE_SOA_COLUMN(DcaXY10000, dcaXY10000, int16_t); //! DCA_xy x10,000 in int16_t, resolution 10 um +DECLARE_SOA_COLUMN(DcaZ10000, dcaZ10000, int16_t); //! DCA_z x10,000 in int16_t, resolution 10 um +DECLARE_SOA_COLUMN(TrackFlags, trackFlags, uint8_t); //! Track flags +DECLARE_SOA_COLUMN(TpcNSigmaPi10, tpcNSigmaPi10, int8_t); //! TPC PID x10 of the track as Pion +DECLARE_SOA_COLUMN(TpcNSigmaKa10, tpcNSigmaKa10, int8_t); //! TPC PID x10 of the track as Kaon +DECLARE_SOA_COLUMN(TpcNSigmaPr10, tpcNSigmaPr10, int8_t); //! TPC PID x10 of the track as Proton +DECLARE_SOA_COLUMN(TofNSigmaPi10, tofNSigmaPi10, int8_t); //! TOF PID x10 of the track as Pion +DECLARE_SOA_COLUMN(TofNSigmaKa10, tofNSigmaKa10, int8_t); //! TOF PID x10 of the track as Kaon +DECLARE_SOA_COLUMN(TofNSigmaPr10, tofNSigmaPr10, int8_t); //! TOF PID x10 of the track as Proton +DECLARE_SOA_COLUMN(DaughDCA, daughDCA, float); //! DCA between daughters +DECLARE_SOA_COLUMN(CascDaughDCA, cascDaughDCA, float); //! DCA between daughters from cascade +DECLARE_SOA_COLUMN(V0CosPA, v0CosPA, float); //! V0 Cosine of Pointing Angle +DECLARE_SOA_COLUMN(CascCosPA, cascCosPA, float); //! Cascade Cosine of Pointing Angle +DECLARE_SOA_COLUMN(MLambda, mLambda, float); //! The invariant mass of V0 candidate, assuming lambda +DECLARE_SOA_COLUMN(MAntiLambda, mAntiLambda, float); //! The invariant mass of V0 candidate, assuming antilambda +DECLARE_SOA_COLUMN(MK0Short, mK0Short, float); //! The invariant mass of V0 candidate, assuming k0s +DECLARE_SOA_COLUMN(MXi, mXi, float); //! The invariant mass of Xi candidate +DECLARE_SOA_COLUMN(TransRadius, transRadius, float); //! Transverse radius of the decay vertex +DECLARE_SOA_COLUMN(CascTransRadius, cascTransRadius, float); //! Transverse radius of the decay vertex from cascade +DECLARE_SOA_COLUMN(DecayVtxX, decayVtxX, float); //! X position of the decay vertex +DECLARE_SOA_COLUMN(DecayVtxY, decayVtxY, float); //! Y position of the decay vertex +DECLARE_SOA_COLUMN(DecayVtxZ, decayVtxZ, float); //! Z position of the decay vertex +DECLARE_SOA_COLUMN(TpcSignal10, tpcSignal10, int8_t); //! TPC signal of the track x10 +DECLARE_SOA_COLUMN(DaughterTPCNSigmaPosPi10, daughterTPCNSigmaPosPi10, int8_t); //! TPC PID x10 of the positive daughter as Pion +DECLARE_SOA_COLUMN(DaughterTPCNSigmaPosKa10, daughterTPCNSigmaPosKa10, int8_t); //! TPC PID x10 of the positive daughter as Kaon +DECLARE_SOA_COLUMN(DaughterTPCNSigmaPosPr10, daughterTPCNSigmaPosPr10, int8_t); //! TPC PID x10 of the positive daughter as Proton +DECLARE_SOA_COLUMN(DaughterTPCNSigmaNegPi10, daughterTPCNSigmaNegPi10, int8_t); //! TPC PID x10 of the negative daughter as Pion +DECLARE_SOA_COLUMN(DaughterTPCNSigmaNegKa10, daughterTPCNSigmaNegKa10, int8_t); //! TPC PID x10 of the negative daughter as Kaon +DECLARE_SOA_COLUMN(DaughterTPCNSigmaNegPr10, daughterTPCNSigmaNegPr10, int8_t); //! TPC PID x10 of the negative daughter as Proton +DECLARE_SOA_COLUMN(DaughterTPCNSigmaBachPi10, daughterTPCNSigmaBachPi10, int8_t); //! TPC PID x10 of the bachelor daughter as Pion +DECLARE_SOA_COLUMN(DaughterTPCNSigmaBachKa10, daughterTPCNSigmaBachKa10, int8_t); //! TPC PID x10 of the bachelor daughter as Kaon +DECLARE_SOA_COLUMN(DaughterTPCNSigmaBachPr10, daughterTPCNSigmaBachPr10, int8_t); //! TPC PID x10 of the bachelor daughter as Proton +DECLARE_SOA_COLUMN(DaughterTOFNSigmaPosPi10, daughterTOFNSigmaPosPi10, int8_t); //! TOF PID x10 of the positive daughter as Pion +DECLARE_SOA_COLUMN(DaughterTOFNSigmaPosKa10, daughterTOFNSigmaPosKa10, int8_t); //! TOF PID x10 of the positive daughter as Kaon +DECLARE_SOA_COLUMN(DaughterTOFNSigmaPosPr10, daughterTOFNSigmaPosPr10, int8_t); //! TOF PID x10 of the positive daughter as Proton +DECLARE_SOA_COLUMN(DaughterTOFNSigmaNegPi10, daughterTOFNSigmaNegPi10, int8_t); //! TOF PID x10 of the negative daughter as Pion +DECLARE_SOA_COLUMN(DaughterTOFNSigmaNegKa10, daughterTOFNSigmaNegKa10, int8_t); //! TOF PID x10 of the negative daughter as Kaon +DECLARE_SOA_COLUMN(DaughterTOFNSigmaNegPr10, daughterTOFNSigmaNegPr10, int8_t); //! TOF PID x10 of the negative daughter as Proton +DECLARE_SOA_COLUMN(DaughterTOFNSigmaBachPi10, daughterTOFNSigmaBachPi10, int8_t); //! TOF PID x10 of the bachelor daughter as Pion +DECLARE_SOA_COLUMN(DaughterTOFNSigmaBachKa10, daughterTOFNSigmaBachKa10, int8_t); //! TOF PID x10 of the bachelor daughter as Kaon +DECLARE_SOA_COLUMN(DaughterTOFNSigmaBachPr10, daughterTOFNSigmaBachPr10, int8_t); //! TOF PID x10 of the bachelor daughter as Proton // For MC DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! Index of the corresponding MC particle DECLARE_SOA_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, bool); DECLARE_SOA_COLUMN(ProducedByGenerator, producedByGenerator, bool); -DECLARE_SOA_COLUMN(MothersId, motherId, int); //! Id of the mother particle +DECLARE_SOA_COLUMN(MotherId, motherId, int); //! Id of the mother particle DECLARE_SOA_COLUMN(MotherPDG, motherPDG, int); //! PDG code of the mother particle DECLARE_SOA_COLUMN(DaughterPDG1, daughterPDG1, int); //! PDG code of the first Daughter particle DECLARE_SOA_COLUMN(DaughterPDG2, daughterPDG2, int); //! PDG code of the second Daughter particle -DECLARE_SOA_COLUMN(DaughterID1, daughterId1, int); //! Id of the first Daughter particle -DECLARE_SOA_COLUMN(DaughterID2, daughterId2, int); //! Id of the second Daughter particle +DECLARE_SOA_COLUMN(DaughterID1, daughterID1, int); //! Id of the first Daughter particle +DECLARE_SOA_COLUMN(DaughterID2, daughterID2, int); //! Id of the second Daughter particle DECLARE_SOA_COLUMN(SiblingIds, siblingIds, int[2]); //! Index of the particles with the same mother -DECLARE_SOA_COLUMN(BachTrkID, bachtrkID, int); //! Id of the bach track from cascade +DECLARE_SOA_COLUMN(BachTrkID, bachTrkID, int); //! Id of the bach track from cascade DECLARE_SOA_COLUMN(V0ID, v0ID, int); //! Id of the V0 from cascade +// Dynamic columns +// DCA_xy x10,000 +DECLARE_SOA_DYNAMIC_COLUMN(DcaXY, dcaXY, + [](int16_t dcaXY10000) { return (float)dcaXY10000 / 10000.f; }); +// DCA_z x10,000 +DECLARE_SOA_DYNAMIC_COLUMN(DcaZ, dcaZ, + [](int16_t dcaZ10000) { return (float)dcaZ10000 / 10000.f; }); +// TPC PID return value/10 +DECLARE_SOA_DYNAMIC_COLUMN(TpcNSigmaPi, tpcNSigmaPi, + [](int8_t tpcNSigmaPi10) { return (float)tpcNSigmaPi10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcNSigmaKa, tpcNSigmaKa, + [](int8_t tpcNSigmaKa10) { return (float)tpcNSigmaKa10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcNSigmaPr, tpcNSigmaPr, + [](int8_t tpcNSigmaPr10) { return (float)tpcNSigmaPr10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(TofNSigmaPi, tofNSigmaPi, + [](int8_t tofNSigmaPi10) { return (float)tofNSigmaPi10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(TofNSigmaKa, tofNSigmaKa, + [](int8_t tofNSigmaKa10) { return (float)tofNSigmaKa10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(TofNSigmaPr, tofNSigmaPr, + [](int8_t tofNSigmaPr10) { return (float)tofNSigmaPr10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTPCNSigmaPosPi, daughterTPCNSigmaPosPi, + [](int8_t daughterTPCNSigmaPosPi10) { return (float)daughterTPCNSigmaPosPi10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTPCNSigmaPosKa, daughterTPCNSigmaPosKa, + [](int8_t daughterTPCNSigmaPosKa10) { return (float)daughterTPCNSigmaPosKa10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTPCNSigmaPosPr, daughterTPCNSigmaPosPr, + [](int8_t daughterTPCNSigmaPosPr10) { return (float)daughterTPCNSigmaPosPr10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTPCNSigmaNegPi, daughterTPCNSigmaNegPi, + [](int8_t daughterTPCNSigmaNegPi10) { return (float)daughterTPCNSigmaNegPi10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTPCNSigmaNegKa, daughterTPCNSigmaNegKa, + [](int8_t daughterTPCNSigmaNegKa10) { return (float)daughterTPCNSigmaNegKa10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTPCNSigmaNegPr, daughterTPCNSigmaNegPr, + [](int8_t daughterTPCNSigmaNegPr10) { return (float)daughterTPCNSigmaNegPr10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTPCNSigmaBachPi, daughterTPCNSigmaBachPi, + [](int8_t daughterTPCNSigmaBachPi10) { return (float)daughterTPCNSigmaBachPi10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTPCNSigmaBachKa, daughterTPCNSigmaBachKa, + [](int8_t daughterTPCNSigmaBachKa10) { return (float)daughterTPCNSigmaBachKa10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTPCNSigmaBachPr, daughterTPCNSigmaBachPr, + [](int8_t daughterTPCNSigmaBachPr10) { return (float)daughterTPCNSigmaBachPr10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTOFNSigmaPosPi, daughterTOFNSigmaPosPi, + [](int8_t daughterTOFNSigmaPosPi10) { return (float)daughterTOFNSigmaPosPi10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTOFNSigmaPosKa, daughterTOFNSigmaPosKa, + [](int8_t daughterTOFNSigmaPosKa10) { return (float)daughterTOFNSigmaPosKa10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTOFNSigmaPosPr, daughterTOFNSigmaPosPr, + [](int8_t daughterTOFNSigmaPosPr10) { return (float)daughterTOFNSigmaPosPr10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTOFNSigmaNegPi, daughterTOFNSigmaNegPi, + [](int8_t daughterTOFNSigmaNegPi10) { return (float)daughterTOFNSigmaNegPi10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTOFNSigmaNegKa, daughterTOFNSigmaNegKa, + [](int8_t daughterTOFNSigmaNegKa10) { return (float)daughterTOFNSigmaNegKa10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTOFNSigmaNegPr, daughterTOFNSigmaNegPr, + [](int8_t daughterTOFNSigmaNegPr10) { return (float)daughterTOFNSigmaNegPr10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTOFNSigmaBachPi, daughterTOFNSigmaBachPi, + [](int8_t daughterTOFNSigmaBachPi10) { return (float)daughterTOFNSigmaBachPi10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTOFNSigmaBachKa, daughterTOFNSigmaBachKa, + [](int8_t daughterTOFNSigmaBachKa10) { return (float)daughterTOFNSigmaBachKa10 / 10.f; }); +DECLARE_SOA_DYNAMIC_COLUMN(DaughterTOFNSigmaBachPr, daughterTOFNSigmaBachPr, + [](int8_t daughterTOFNSigmaBachPr10) { return (float)daughterTOFNSigmaBachPr10 / 10.f; }); +// TPC signal x10 +DECLARE_SOA_DYNAMIC_COLUMN(TpcSignal, tpcSignal, + [](int8_t tpcSignal10) { return (float)tpcSignal10 / 10.f; }); +// pT, Eta, Phi +// DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float px, float py) -> float { return RecoDecay::sqrtSumOfSquares(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, [](float px, float py, float pz) -> float { return RecoDecay::eta(std::array{px, py, pz}); }); +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, [](float px, float py) -> float { return RecoDecay::phi(px, py); }); +// Track flags +DECLARE_SOA_DYNAMIC_COLUMN(PassedITSRefit, passedITSRefit, + [](ResoTrackFlags::flagtype trackFlags) -> bool { + return ResoTrackFlags::checkFlag(trackFlags, ResoTrackFlags::kPassedITSRefit); + }); +DECLARE_SOA_DYNAMIC_COLUMN(PassedTPCRefit, passedTPCRefit, + [](ResoTrackFlags::flagtype trackFlags) -> bool { + return ResoTrackFlags::checkFlag(trackFlags, ResoTrackFlags::kPassedTPCRefit); + }); +DECLARE_SOA_DYNAMIC_COLUMN(IsGlobalTrackWoDCA, isGlobalTrackWoDCA, + [](ResoTrackFlags::flagtype trackFlags) -> bool { + return ResoTrackFlags::checkFlag(trackFlags, ResoTrackFlags::kIsGlobalTrackWoDCA); + }); +DECLARE_SOA_DYNAMIC_COLUMN(IsGlobalTrack, isGlobalTrack, + [](ResoTrackFlags::flagtype trackFlags) -> bool { + return ResoTrackFlags::checkFlag(trackFlags, ResoTrackFlags::kIsGlobalTrack); + }); +DECLARE_SOA_DYNAMIC_COLUMN(IsPrimaryTrack, isPrimaryTrack, + [](ResoTrackFlags::flagtype trackFlags) -> bool { + return ResoTrackFlags::checkFlag(trackFlags, ResoTrackFlags::kIsPrimaryTrack); + }); +DECLARE_SOA_DYNAMIC_COLUMN(IsPVContributor, isPVContributor, + [](ResoTrackFlags::flagtype trackFlags) -> bool { + return ResoTrackFlags::checkFlag(trackFlags, ResoTrackFlags::kIsPVContributor); + }); +DECLARE_SOA_DYNAMIC_COLUMN(HasTOF, hasTOF, + [](ResoTrackFlags::flagtype trackFlags) -> bool { + return ResoTrackFlags::checkFlag(trackFlags, ResoTrackFlags::kHasTOF); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Sign, sign, + [](ResoTrackFlags::flagtype trackFlags) -> int8_t { + return (trackFlags & ResoTrackFlags::kSign) ? 1 : -1; + }); + } // namespace resodaughter -DECLARE_SOA_TABLE(ResoTracks, "AOD", "RESOTRACKS", + +namespace resodmciroaughter +{ +// micro track for primary pion + +/// @brief Save TPC & TOF nSigma info with 8-bit variable +struct PidNSigma { + uint8_t flag; + + /// @brief Constructor: Convert TPC & TOF values and save + PidNSigma(float TPCnSigma, float TOFnSigma, bool hasTOF) + { + uint8_t TPCencoded = encodeNSigma(TPCnSigma); + uint8_t TOFencoded = hasTOF ? encodeNSigma(TOFnSigma) : 0x0F; // If TOF is not available, set all 4 bits to 1 + flag = (TPCencoded << 4) | TOFencoded; // Upper 4 bits = TPC, Lower 4 bits = TOF + } + + /// @brief Encode 0.2 sigma interval to 0~10 range + static uint8_t encodeNSigma(float nSigma) + { + float encoded = std::abs((nSigma - 1.5) / 0.2); // Convert to 0~10 range + encoded = std::min(std::max(encoded, 0.f), 10.f); // Clamp to 0~10 range + return (uint8_t)round(encoded); + } + + /// @brief Decode 0~10 value to original 1.5~3.5 sigma range + static float decodeNSigma(uint8_t encoded) + { + encoded = std::min(encoded, (uint8_t)10); // Safety check, should not be needed if encode is used properly + return (encoded * 0.2) + 1.5; + } + + /// @brief Check if TOF info is available + bool hasTOF() const + { + return (flag & 0x0F) != 0x0F; // Check if lower 4 bits are not all 1 + } + + /// @brief Restore TPC nSigma value + static float getTPCnSigma(uint8_t encoded) + { + return decodeNSigma((encoded >> 4) & 0x0F); // Extract upper 4 bits + } + + /// @brief Restore TOF nSigma value (if not available, return NAN) + static float getTOFnSigma(uint8_t encoded) + { + uint8_t TOFencoded = encoded & 0x0F; // Extract lower 4 bits + return (TOFencoded == 0x0F) ? NAN : decodeNSigma(TOFencoded); + } + + /// @brief Operator to convert to uint8_t (automatic conversion support) + operator uint8_t() const + { + return flag; + } +}; + +DECLARE_SOA_COLUMN(PidNSigmaPiFlag, pidNSigmaPiFlag, uint8_t); //! Pid flag for the track as Pion +DECLARE_SOA_COLUMN(PidNSigmaKaFlag, pidNSigmaKaFlag, uint8_t); //! Pid flag for the track as Kaon +DECLARE_SOA_COLUMN(PidNSigmaPrFlag, pidNSigmaPrFlag, uint8_t); //! Pid flag for the track as Proton +DECLARE_SOA_COLUMN(TrackSelectionFlags, trackSelectionFlags, int8_t); //! Track selection flags +DECLARE_SOA_DYNAMIC_COLUMN(HasTOF, hasTOF, + [](uint8_t pidNSigmaFlags) -> bool { + return (pidNSigmaFlags & 0x0F) != 0x0F; + }); + +/// @brief DCAxy & DCAz selection flag +struct ResoMicroTrackSelFlag { + uint8_t flag; // Flag for DCAxy & DCAz selection (8-bit variable) + + /// @brief Default constructor + ResoMicroTrackSelFlag() + { + flag = 0x00; + } + + /// @brief Constructor: Convert DCAxy/DCAz and save (default 1~15 values) + ResoMicroTrackSelFlag(float DCAxy, float DCAz) + { + uint8_t DCAxyEncoded = encodeDCA(DCAxy); + uint8_t DCAzEncoded = encodeDCA(DCAz); + flag = (DCAxyEncoded << 4) | DCAzEncoded; // Upper 4 bits = DCAxy, Lower 4 bits = DCAz + } + + /// @brief Convert DCA to 1~15 steps (0 value is not used) + static uint8_t encodeDCA(float DCA) + { + for (uint8_t i = 1; i < 15; i++) { + if (DCA < i * 0.1f) + return i; + } + return 15; + } + + /// @brief Operator to convert to `uint8_t` (for SOA storage) + operator uint8_t() const + { + return flag; + } + + /// @brief Get DCAxy value + uint8_t getDCAxyFlag() const + { + return (flag >> 4) & 0x0F; // Extract upper 4 bits + } + + /// @brief Get DCAz value + uint8_t getDCAzFlag() const + { + return flag & 0x0F; // Extract lower 4 bits + } + + /// @brief Apply DCAxy tight cut (0 value) + void setDCAxy0() + { + flag &= 0x0F; // Set DCAxy to 0 (delete upper 4 bits) + } + + /// @brief Apply DCAz tight cut (0 value) + void setDCAz0() + { + flag &= 0xF0; // Set DCAz to 0 (delete lower 4 bits) + } + /// @brief Decode DCAxy + static float decodeDCAxy(uint8_t flag_saved) + { + uint8_t DCAxyFlag = (flag_saved >> 4) & 0x0F; // Extract upper 4 bits + return (DCAxyFlag == 0) ? 0.0f : DCAxyFlag * 0.1f; // Tight cut(0) is 0.0, otherwise flag * 0.1 cm + } + + /// @brief Decode DCAz + static float decodeDCAz(uint8_t flag_saved) + { + uint8_t DCAzFlag = flag_saved & 0x0F; // Extract lower 4 bits + return (DCAzFlag == 0) ? 0.0f : DCAzFlag * 0.1f; // Tight cut(0) is 0.0, otherwise flag * 0.1 cm + } +}; + +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float px, float py) -> float { return RecoDecay::sqrtSumOfSquares(px, py); }); +} // namespace resodmciroaughter + +DECLARE_SOA_TABLE(ResoTracks, "AOD", "RESOTRACK", o2::soa::Index<>, resodaughter::ResoCollisionId, resodaughter::Pt, resodaughter::Px, resodaughter::Py, resodaughter::Pz, - resodaughter::Eta, - resodaughter::Phi, - resodaughter::Sign, - resodaughter::TPCNClsCrossedRows, - resodaughter::TPCNClsFound, - resodaughter::ITSNCls, - o2::aod::track::DcaXY, - o2::aod::track::DcaZ, - o2::aod::track::X, - o2::aod::track::Alpha, - resodaughter::HasTOF, - o2::aod::pidtpc::TPCNSigmaPi, - o2::aod::pidtpc::TPCNSigmaKa, - o2::aod::pidtpc::TPCNSigmaPr, - o2::aod::pidtof::TOFNSigmaPi, - o2::aod::pidtof::TOFNSigmaKa, - o2::aod::pidtof::TOFNSigmaPr, - o2::aod::track::TPCSignal, - o2::aod::track::PassedITSRefit, - o2::aod::track::PassedTPCRefit, - resodaughter::IsGlobalTrackWoDCA, - resodaughter::IsGlobalTrack, - resodaughter::IsPrimaryTrack, - resodaughter::IsPVContributor, - resodaughter::TPCCrossedRowsOverFindableCls, - o2::aod::track::ITSChi2NCl, - o2::aod::track::TPCChi2NCl); + resodaughter::TpcNClsCrossedRows, + resodaughter::TpcNClsFound, + resodaughter::DcaXY10000, + resodaughter::DcaZ10000, + resodaughter::TpcNSigmaPi10, + resodaughter::TpcNSigmaKa10, + resodaughter::TpcNSigmaPr10, + resodaughter::TofNSigmaPi10, + resodaughter::TofNSigmaKa10, + resodaughter::TofNSigmaPr10, + resodaughter::TpcSignal10, + resodaughter::TrackFlags, + // Dynamic columns + resodaughter::TpcNSigmaPi, + resodaughter::TpcNSigmaKa, + resodaughter::TpcNSigmaPr, + resodaughter::TofNSigmaPi, + resodaughter::TofNSigmaKa, + resodaughter::TofNSigmaPr, + resodaughter::TpcSignal, + // resodaughter::Pt, + resodaughter::DcaXY, + resodaughter::DcaZ, + resodaughter::Eta, + resodaughter::Phi, + resodaughter::PassedITSRefit, + resodaughter::PassedTPCRefit, + resodaughter::IsGlobalTrackWoDCA, + resodaughter::IsGlobalTrack, + resodaughter::IsPrimaryTrack, + resodaughter::IsPVContributor, + resodaughter::HasTOF, + resodaughter::Sign); using ResoTrack = ResoTracks::iterator; -DECLARE_SOA_TABLE(ResoV0s, "AOD", "RESOV0S", +DECLARE_SOA_TABLE(ResoTrackTracks, "AOD", "RESOTRACKTRACK", + resodaughter::TrackId); +using ResoTrackTrack = ResoTrackTracks::iterator; + +DECLARE_SOA_TABLE(ResoMicroTracks, "AOD", "RESOMICROTRACK", + o2::soa::Index<>, + resodaughter::ResoCollisionId, + resodaughter::Px, + resodaughter::Py, + resodaughter::Pz, + resodmciroaughter::PidNSigmaPiFlag, + resodmciroaughter::PidNSigmaKaFlag, + resodmciroaughter::PidNSigmaPrFlag, + resodmciroaughter::TrackSelectionFlags, + resodaughter::TrackFlags, + // Dynamic columns + resodmciroaughter::Pt, + resodaughter::Eta, + resodaughter::Phi, + resodaughter::PassedITSRefit, + resodaughter::PassedTPCRefit, + resodaughter::IsGlobalTrackWoDCA, + resodaughter::IsGlobalTrack, + resodaughter::IsPrimaryTrack, + resodaughter::IsPVContributor, + resodmciroaughter::HasTOF, + resodaughter::Sign); +using ResoMicroTrack = ResoMicroTracks::iterator; + +DECLARE_SOA_TABLE(ResoMicroTrackTracks, "AOD", "RESOMICROTRACKTRACK", + resodaughter::TrackId); +using ResoMicroTrackTrack = ResoMicroTrackTracks::iterator; + +// For DF mixing study +DECLARE_SOA_TABLE(ResoTrackDFs, "AOD", "RESOTRACKDF", + o2::soa::Index<>, + resodaughter::ResoCollisionDFId, + resodaughter::Pt, + resodaughter::Px, + resodaughter::Py, + resodaughter::Pz, + resodaughter::TpcNClsCrossedRows, + resodaughter::TpcNClsFound, + resodaughter::DcaXY10000, + resodaughter::DcaZ10000, + resodaughter::TpcNSigmaPi10, + resodaughter::TpcNSigmaKa10, + resodaughter::TpcNSigmaPr10, + resodaughter::TofNSigmaPi10, + resodaughter::TofNSigmaKa10, + resodaughter::TofNSigmaPr10, + resodaughter::TpcSignal10, + resodaughter::TrackFlags, + // Dynamic columns + resodaughter::TpcNSigmaPi, + resodaughter::TpcNSigmaKa, + resodaughter::TpcNSigmaPr, + resodaughter::TofNSigmaPi, + resodaughter::TofNSigmaKa, + resodaughter::TofNSigmaPr, + resodaughter::TpcSignal, + // resodaughter::Pt, + resodaughter::DcaXY, + resodaughter::DcaZ, + resodaughter::Eta, + resodaughter::Phi, + resodaughter::PassedITSRefit, + resodaughter::PassedTPCRefit, + resodaughter::IsGlobalTrackWoDCA, + resodaughter::IsGlobalTrack, + resodaughter::IsPrimaryTrack, + resodaughter::IsPVContributor, + resodaughter::HasTOF, + resodaughter::Sign); +using ResoTrackDF = ResoTrackDFs::iterator; + +DECLARE_SOA_TABLE(ResoV0s, "AOD", "RESOV0", o2::soa::Index<>, resodaughter::ResoCollisionId, resodaughter::Pt, resodaughter::Px, resodaughter::Py, resodaughter::Pz, - resodaughter::Eta, - resodaughter::Phi, resodaughter::Indices, + resodaughter::DaughterTPCNSigmaPosPi10, + resodaughter::DaughterTPCNSigmaPosKa10, + resodaughter::DaughterTPCNSigmaPosPr10, + resodaughter::DaughterTPCNSigmaNegPi10, + resodaughter::DaughterTPCNSigmaNegKa10, + resodaughter::DaughterTPCNSigmaNegPr10, + resodaughter::DaughterTOFNSigmaPosPi10, + resodaughter::DaughterTOFNSigmaPosKa10, + resodaughter::DaughterTOFNSigmaPosPr10, + resodaughter::DaughterTOFNSigmaNegPi10, + resodaughter::DaughterTOFNSigmaNegKa10, + resodaughter::DaughterTOFNSigmaNegPr10, resodaughter::V0CosPA, resodaughter::DaughDCA, v0data::DCAPosToPV, @@ -167,19 +622,54 @@ DECLARE_SOA_TABLE(ResoV0s, "AOD", "RESOV0S", resodaughter::TransRadius, resodaughter::DecayVtxX, resodaughter::DecayVtxY, - resodaughter::DecayVtxZ); + resodaughter::DecayVtxZ, + // resodaughter::Pt, + resodaughter::Eta, + resodaughter::Phi, + resodaughter::DaughterTPCNSigmaPosPi, + resodaughter::DaughterTPCNSigmaPosKa, + resodaughter::DaughterTPCNSigmaPosPr, + resodaughter::DaughterTPCNSigmaNegPi, + resodaughter::DaughterTPCNSigmaNegKa, + resodaughter::DaughterTPCNSigmaNegPr, + resodaughter::DaughterTOFNSigmaPosPi, + resodaughter::DaughterTOFNSigmaPosKa, + resodaughter::DaughterTOFNSigmaPosPr, + resodaughter::DaughterTOFNSigmaNegPi, + resodaughter::DaughterTOFNSigmaNegKa, + resodaughter::DaughterTOFNSigmaNegPr); using ResoV0 = ResoV0s::iterator; -DECLARE_SOA_TABLE(ResoCascades, "AOD", "RESOCASCADES", +DECLARE_SOA_TABLE(ResoV0V0s, "AOD", "RESOV0V0", + resodaughter::V0Id); +using ResoV0V0 = ResoV0V0s::iterator; + +DECLARE_SOA_TABLE(ResoCascades, "AOD", "RESOCASCADE", o2::soa::Index<>, resodaughter::ResoCollisionId, resodaughter::Pt, resodaughter::Px, resodaughter::Py, resodaughter::Pz, - resodaughter::Eta, - resodaughter::Phi, resodaughter::CascadeIndices, + resodaughter::DaughterTPCNSigmaPosPi10, + resodaughter::DaughterTPCNSigmaPosKa10, + resodaughter::DaughterTPCNSigmaPosPr10, + resodaughter::DaughterTPCNSigmaNegPi10, + resodaughter::DaughterTPCNSigmaNegKa10, + resodaughter::DaughterTPCNSigmaNegPr10, + resodaughter::DaughterTPCNSigmaBachPi10, + resodaughter::DaughterTPCNSigmaBachKa10, + resodaughter::DaughterTPCNSigmaBachPr10, + resodaughter::DaughterTOFNSigmaPosPi10, + resodaughter::DaughterTOFNSigmaPosKa10, + resodaughter::DaughterTOFNSigmaPosPr10, + resodaughter::DaughterTOFNSigmaNegPi10, + resodaughter::DaughterTOFNSigmaNegKa10, + resodaughter::DaughterTOFNSigmaNegPr10, + resodaughter::DaughterTOFNSigmaBachPi10, + resodaughter::DaughterTOFNSigmaBachKa10, + resodaughter::DaughterTOFNSigmaBachPr10, resodaughter::V0CosPA, resodaughter::CascCosPA, resodaughter::DaughDCA, @@ -191,26 +681,119 @@ DECLARE_SOA_TABLE(ResoCascades, "AOD", "RESOCASCADES", cascdata::DCAXYCascToPV, cascdata::DCAZCascToPV, cascdata::Sign, + resodaughter::MLambda, resodaughter::MXi, resodaughter::TransRadius, resodaughter::CascTransRadius, resodaughter::DecayVtxX, resodaughter::DecayVtxY, - resodaughter::DecayVtxZ); + resodaughter::DecayVtxZ, + // resodaughter::Pt, + resodaughter::Eta, + resodaughter::Phi, + resodaughter::DaughterTPCNSigmaPosPi, + resodaughter::DaughterTPCNSigmaPosKa, + resodaughter::DaughterTPCNSigmaPosPr, + resodaughter::DaughterTPCNSigmaNegPi, + resodaughter::DaughterTPCNSigmaNegKa, + resodaughter::DaughterTPCNSigmaNegPr, + resodaughter::DaughterTPCNSigmaBachPi, + resodaughter::DaughterTPCNSigmaBachKa, + resodaughter::DaughterTPCNSigmaBachPr, + resodaughter::DaughterTOFNSigmaPosPi, + resodaughter::DaughterTOFNSigmaPosKa, + resodaughter::DaughterTOFNSigmaPosPr, + resodaughter::DaughterTOFNSigmaNegPi, + resodaughter::DaughterTOFNSigmaNegKa, + resodaughter::DaughterTOFNSigmaNegPr, + resodaughter::DaughterTOFNSigmaBachPi, + resodaughter::DaughterTOFNSigmaBachKa, + resodaughter::DaughterTOFNSigmaBachPr); using ResoCascade = ResoCascades::iterator; -DECLARE_SOA_TABLE(ResoMCTracks, "AOD", "RESOMCTRACKS", +DECLARE_SOA_TABLE(ResoCascadeCascades, "AOD", "RESOCASCADECASCADE", + resodaughter::CascadeId); +using ResoCascadeCascade = ResoCascadeCascades::iterator; + +DECLARE_SOA_TABLE(ResoCascadeDFs, "AOD", "RESOCASCADEDF", + o2::soa::Index<>, + resodaughter::ResoCollisionDFId, + resodaughter::Pt, + resodaughter::Px, + resodaughter::Py, + resodaughter::Pz, + resodaughter::CascadeIndices, + resodaughter::DaughterTPCNSigmaPosPi10, + resodaughter::DaughterTPCNSigmaPosKa10, + resodaughter::DaughterTPCNSigmaPosPr10, + resodaughter::DaughterTPCNSigmaNegPi10, + resodaughter::DaughterTPCNSigmaNegKa10, + resodaughter::DaughterTPCNSigmaNegPr10, + resodaughter::DaughterTPCNSigmaBachPi10, + resodaughter::DaughterTPCNSigmaBachKa10, + resodaughter::DaughterTPCNSigmaBachPr10, + resodaughter::DaughterTOFNSigmaPosPi10, + resodaughter::DaughterTOFNSigmaPosKa10, + resodaughter::DaughterTOFNSigmaPosPr10, + resodaughter::DaughterTOFNSigmaNegPi10, + resodaughter::DaughterTOFNSigmaNegKa10, + resodaughter::DaughterTOFNSigmaNegPr10, + resodaughter::DaughterTOFNSigmaBachPi10, + resodaughter::DaughterTOFNSigmaBachKa10, + resodaughter::DaughterTOFNSigmaBachPr10, + resodaughter::V0CosPA, + resodaughter::CascCosPA, + resodaughter::DaughDCA, + resodaughter::CascDaughDCA, + cascdata::DCAPosToPV, + cascdata::DCANegToPV, + cascdata::DCABachToPV, + v0data::DCAV0ToPV, + cascdata::DCAXYCascToPV, + cascdata::DCAZCascToPV, + cascdata::Sign, + resodaughter::MLambda, + resodaughter::MXi, + resodaughter::TransRadius, + resodaughter::CascTransRadius, + resodaughter::DecayVtxX, + resodaughter::DecayVtxY, + resodaughter::DecayVtxZ, + // resodaughter::Pt, + resodaughter::Eta, + resodaughter::Phi, + resodaughter::DaughterTPCNSigmaPosPi, + resodaughter::DaughterTPCNSigmaPosKa, + resodaughter::DaughterTPCNSigmaPosPr, + resodaughter::DaughterTPCNSigmaNegPi, + resodaughter::DaughterTPCNSigmaNegKa, + resodaughter::DaughterTPCNSigmaNegPr, + resodaughter::DaughterTPCNSigmaBachPi, + resodaughter::DaughterTPCNSigmaBachKa, + resodaughter::DaughterTPCNSigmaBachPr, + resodaughter::DaughterTOFNSigmaPosPi, + resodaughter::DaughterTOFNSigmaPosKa, + resodaughter::DaughterTOFNSigmaPosPr, + resodaughter::DaughterTOFNSigmaNegPi, + resodaughter::DaughterTOFNSigmaNegKa, + resodaughter::DaughterTOFNSigmaNegPr, + resodaughter::DaughterTOFNSigmaBachPi, + resodaughter::DaughterTOFNSigmaBachKa, + resodaughter::DaughterTOFNSigmaBachPr); +using ResoCascadeDF = ResoCascadeDFs::iterator; + +DECLARE_SOA_TABLE(ResoMCTracks, "AOD", "RESOMCTRACK", mcparticle::PdgCode, - resodaughter::MothersId, + resodaughter::MotherId, resodaughter::MotherPDG, resodaughter::SiblingIds, resodaughter::IsPhysicalPrimary, resodaughter::ProducedByGenerator); using ResoMCTrack = ResoMCTracks::iterator; -DECLARE_SOA_TABLE(ResoMCV0s, "AOD", "RESOMCV0S", +DECLARE_SOA_TABLE(ResoMCV0s, "AOD", "RESOMCV0", mcparticle::PdgCode, - resodaughter::MothersId, + resodaughter::MotherId, resodaughter::MotherPDG, resodaughter::DaughterID1, resodaughter::DaughterID2, @@ -220,9 +803,9 @@ DECLARE_SOA_TABLE(ResoMCV0s, "AOD", "RESOMCV0S", resodaughter::ProducedByGenerator); using ResoMCV0 = ResoMCV0s::iterator; -DECLARE_SOA_TABLE(ResoMCCascades, "AOD", "RESOMCCASCADES", +DECLARE_SOA_TABLE(ResoMCCascades, "AOD", "RESOMCCASCADE", mcparticle::PdgCode, - resodaughter::MothersId, + resodaughter::MotherId, resodaughter::MotherPDG, resodaughter::BachTrkID, resodaughter::V0ID, @@ -232,7 +815,7 @@ DECLARE_SOA_TABLE(ResoMCCascades, "AOD", "RESOMCCASCADES", resodaughter::ProducedByGenerator); using ResoMCCascade = ResoMCCascades::iterator; -DECLARE_SOA_TABLE(ResoMCParents, "AOD", "RESOMCPARENTS", +DECLARE_SOA_TABLE(ResoMCParents, "AOD", "RESOMCPARENT", o2::soa::Index<>, resodaughter::ResoCollisionId, resodaughter::McParticleId, @@ -245,9 +828,12 @@ DECLARE_SOA_TABLE(ResoMCParents, "AOD", "RESOMCPARENTS", resodaughter::Px, resodaughter::Py, resodaughter::Pz, - resodaughter::Eta, - resodaughter::Phi, - mcparticle::Y); + mcparticle::Y, + mcparticle::E, + mcparticle::StatusCode, + // resodaughter::Pt, + resodaughter::Eta, + resodaughter::Phi); using ResoMCParent = ResoMCParents::iterator; using Reso2TracksExt = soa::Join; // without Extra @@ -255,5 +841,17 @@ using Reso2TracksMC = soa::Join; using Reso2TracksPID = soa::Join; using Reso2TracksPIDExt = soa::Join; // Without Extra +using ResoCollisionCandidates = soa::Join; +using ResoRun2CollisionCandidates = soa::Join; +using ResoCollisionCandidatesMC = soa::Join; +using ResoRun2CollisionCandidatesMC = soa::Join; +using ResoTrackCandidates = aod::Reso2TracksPIDExt; +using ResoTrackCandidatesMC = soa::Join; +using ResoV0Candidates = aod::V0Datas; +using ResoV0CandidatesMC = soa::Join; +using ResoCascadesCandidates = aod::CascDatas; +using ResoCascadesCandidatesMC = soa::Join; +using BCsWithRun2Info = soa::Join; + } // namespace o2::aod #endif // PWGLF_DATAMODEL_LFRESONANCETABLES_H_ diff --git a/PWGLF/DataModel/LFResonanceTablesMergeDF.h b/PWGLF/DataModel/LFResonanceTablesMergeDF.h deleted file mode 100644 index fbb4bfacfaf..00000000000 --- a/PWGLF/DataModel/LFResonanceTablesMergeDF.h +++ /dev/null @@ -1,143 +0,0 @@ -// 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 LFResonanceTables.h -/// \brief Definitions of tables of resonance decay candidates -/// -/// Inspired by StrangenessTables.h, FemtoDerived.h -/// -/// \author Bong-Hwi Lim -/// Nasir Mehdi Malik - -#ifndef PWGLF_DATAMODEL_LFRESONANCETABLESMERGEDF_H_ -#define PWGLF_DATAMODEL_LFRESONANCETABLESMERGEDF_H_ - -#include - -#include "Common/DataModel/PIDResponse.h" -#include "Common/Core/RecoDecay.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Framework/AnalysisDataModel.h" - -namespace o2::aod -{ -/// Resonance Collisions -namespace resocollisiondf -{ -DECLARE_SOA_COLUMN(Cent, cent, float); //! Centrality (Multiplicity) percentile (Default: FT0M) -DECLARE_SOA_COLUMN(Spherocity, spherocity, float); //! Spherocity of the event -DECLARE_SOA_COLUMN(EvtPl, evtPl, float); //! Second harmonic event plane -DECLARE_SOA_COLUMN(EvtPlResAB, evtPlResAB, float); //! Second harmonic event plane resolution of A-B sub events -DECLARE_SOA_COLUMN(EvtPlResAC, evtPlResAC, float); //! Second harmonic event plane resolution of A-C sub events -DECLARE_SOA_COLUMN(EvtPlResBC, evtPlResBC, float); //! Second harmonic event plane resolution of B-C sub events -DECLARE_SOA_COLUMN(BMagField, bMagField, float); //! Magnetic field -} // namespace resocollisiondf -DECLARE_SOA_TABLE(ResoCollisionDFs, "AOD", "RESOCOLDF", - o2::soa::Index<>, - collision::PosX, - collision::PosY, - collision::PosZ, - resocollisiondf::Cent, - resocollisiondf::Spherocity, - resocollisiondf::EvtPl, - resocollisiondf::EvtPlResAB, - resocollisiondf::EvtPlResAC, - resocollisiondf::EvtPlResBC, - resocollisiondf::BMagField, - timestamp::Timestamp); -using ResoCollisionDF = ResoCollisionDFs::iterator; - -// Resonance Daughters -// inspired from PWGCF/DataModel/FemtoDerived.h -namespace resodaughterdf -{ - -DECLARE_SOA_INDEX_COLUMN(ResoCollisionDF, resoCollisiondf); -DECLARE_SOA_COLUMN(Pt, pt, float); //! p_T (GeV/c) -DECLARE_SOA_COLUMN(Px, px, float); //! p_x (GeV/c) -DECLARE_SOA_COLUMN(Py, py, float); //! p_y (GeV/c) -DECLARE_SOA_COLUMN(Pz, pz, float); //! p_z (GeV/c) -DECLARE_SOA_COLUMN(Eta, eta, float); //! Eta -DECLARE_SOA_COLUMN(Phi, phi, float); //! Phi -DECLARE_SOA_COLUMN(PartType, partType, uint8_t); //! Type of the particle, according to resodaughter::ParticleType -DECLARE_SOA_COLUMN(TempFitVar, tempFitVar, float); //! Observable for the template fitting (Track: DCA_xy, V0: CPA) -DECLARE_SOA_COLUMN(Indices, indices, int[2]); //! Field for the track indices to remove auto-correlations -DECLARE_SOA_COLUMN(CascadeIndices, cascIndices, int[3]); //! Field for the track indices to remove auto-correlations (ordered: positive, negative, bachelor) -DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! Sign of the track charge -DECLARE_SOA_COLUMN(TPCNClsCrossedRows, tpcNClsCrossedRows, uint8_t); //! Number of TPC crossed rows -DECLARE_SOA_COLUMN(IsGlobalTrackWoDCA, isGlobalTrackWoDCA, bool); //! Is global track without DCA -DECLARE_SOA_COLUMN(IsPrimaryTrack, isPrimaryTrack, bool); //! Is primary track -DECLARE_SOA_COLUMN(IsPVContributor, isPVContributor, bool); //! Is primary vertex contributor -DECLARE_SOA_COLUMN(HasTOF, hasTOF, bool); //! Has TOF -DECLARE_SOA_COLUMN(TPCCrossedRowsOverFindableCls, tpcCrossedRowsOverFindableCls, float); -DECLARE_SOA_COLUMN(DaughDCA, daughDCA, float); //! DCA between daughters -DECLARE_SOA_COLUMN(CascDaughDCA, cascdaughDCA, float); //! DCA between daughters from cascade -DECLARE_SOA_COLUMN(V0CosPA, v0CosPA, float); //! V0 Cosine of Pointing Angle -DECLARE_SOA_COLUMN(CascCosPA, cascCosPA, float); //! Cascade Cosine of Pointing Angle -DECLARE_SOA_COLUMN(MLambda, mLambda, float); //! The invariant mass of V0 candidate, assuming lambda -DECLARE_SOA_COLUMN(MAntiLambda, mAntiLambda, float); //! The invariant mass of V0 candidate, assuming antilambda -DECLARE_SOA_COLUMN(MK0Short, mK0Short, float); //! The invariant mass of V0 candidate, assuming k0s -DECLARE_SOA_COLUMN(MXi, mXi, float); //! The invariant mass of Xi candidate -DECLARE_SOA_COLUMN(TransRadius, transRadius, float); //! Transverse radius of the decay vertex -DECLARE_SOA_COLUMN(CascTransRadius, casctransRadius, float); //! Transverse radius of the decay vertex from cascade -DECLARE_SOA_COLUMN(DecayVtxX, decayVtxX, float); //! X position of the decay vertex -DECLARE_SOA_COLUMN(DecayVtxY, decayVtxY, float); //! Y position of the decay vertex -DECLARE_SOA_COLUMN(DecayVtxZ, decayVtxZ, float); //! Z position of the decay vertex -// For MC -DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! Index of the corresponding MC particle -DECLARE_SOA_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, bool); -DECLARE_SOA_COLUMN(ProducedByGenerator, producedByGenerator, bool); -DECLARE_SOA_COLUMN(MothersId, motherId, int); //! Id of the mother particle -DECLARE_SOA_COLUMN(MotherPDG, motherPDG, int); //! PDG code of the mother particle -DECLARE_SOA_COLUMN(DaughterPDG1, daughterPDG1, int); //! PDG code of the first Daughter particle -DECLARE_SOA_COLUMN(DaughterPDG2, daughterPDG2, int); //! PDG code of the second Daughter particle -DECLARE_SOA_COLUMN(DaughterID1, daughterId1, int); //! Id of the first Daughter particle -DECLARE_SOA_COLUMN(DaughterID2, daughterId2, int); //! Id of the second Daughter particle -DECLARE_SOA_COLUMN(SiblingIds, siblingIds, int[2]); //! Index of the particles with the same mother -DECLARE_SOA_COLUMN(BachTrkID, bachtrkID, int); //! Id of the bach track from cascade -DECLARE_SOA_COLUMN(V0ID, v0ID, int); //! Id of the V0 from cascade -} // namespace resodaughterdf -DECLARE_SOA_TABLE(ResoTrackDFs, "AOD", "RESOTRACKDFs", - o2::soa::Index<>, - resodaughterdf::ResoCollisionDFId, - resodaughterdf::Pt, - resodaughterdf::Px, - resodaughterdf::Py, - resodaughterdf::Pz, - resodaughterdf::Eta, - resodaughterdf::Phi, - resodaughterdf::Sign, - resodaughterdf::TPCNClsCrossedRows, - o2::aod::track::DcaXY, - o2::aod::track::DcaZ, - o2::aod::track::X, - o2::aod::track::Alpha, - resodaughterdf::HasTOF, - o2::aod::pidtpc::TPCNSigmaPi, - o2::aod::pidtpc::TPCNSigmaKa, - o2::aod::pidtpc::TPCNSigmaPr, - o2::aod::pidtof::TOFNSigmaPi, - o2::aod::pidtof::TOFNSigmaKa, - o2::aod::pidtof::TOFNSigmaPr, - o2::aod::track::TPCSignal, - o2::aod::track::PassedITSRefit, - o2::aod::track::PassedTPCRefit, - resodaughterdf::IsGlobalTrackWoDCA, - resodaughterdf::IsPrimaryTrack, - resodaughterdf::IsPVContributor, - resodaughterdf::TPCCrossedRowsOverFindableCls, - o2::aod::track::ITSChi2NCl, - o2::aod::track::TPCChi2NCl); -using ResoTrackDF = ResoTrackDFs::iterator; - -} // namespace o2::aod -#endif // PWGLF_DATAMODEL_LFRESONANCETABLESMERGEDF_H_ diff --git a/PWGLF/DataModel/LFSigmaTables.h b/PWGLF/DataModel/LFSigmaTables.h index e2df7da8bbe..08b511bf1ca 100644 --- a/PWGLF/DataModel/LFSigmaTables.h +++ b/PWGLF/DataModel/LFSigmaTables.h @@ -10,29 +10,47 @@ // or submit itself to any jurisdiction. #include +#include #include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" #include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Qvectors.h" #include "CommonConstants/PhysicsConstants.h" #ifndef PWGLF_DATAMODEL_LFSIGMATABLES_H_ #define PWGLF_DATAMODEL_LFSIGMATABLES_H_ -using namespace o2; -using namespace o2::framework; - // Creating output TTree for sigma analysis namespace o2::aod { // for real data -namespace v0SigmaCandidate +namespace sigma0Core { DECLARE_SOA_COLUMN(SigmapT, sigmapT, float); DECLARE_SOA_COLUMN(SigmaMass, sigmaMass, float); -// DECLARE_SOA_COLUMN(SigmaDCAz, sigmaDCAz, float); -// DECLARE_SOA_COLUMN(SigmaDCAxy, sigmaDCAxy, float); -// DECLARE_SOA_COLUMN(SigmaDCADau, sigmaDCADau, float); +DECLARE_SOA_COLUMN(SigmaRapidity, sigmaRapidity, float); +DECLARE_SOA_COLUMN(SigmaOPAngle, sigmaOPAngle, float); +DECLARE_SOA_COLUMN(SigmaCentrality, sigmaCentrality, float); +DECLARE_SOA_COLUMN(SigmaRunNumber, sigmaRunNumber, int); +DECLARE_SOA_COLUMN(SigmaTimestamp, sigmaTimestamp, uint64_t); + +} // namespace sigma0Core + +DECLARE_SOA_TABLE(Sigma0Cores, "AOD", "SIGMA0CORES", + sigma0Core::SigmapT, + sigma0Core::SigmaMass, + sigma0Core::SigmaRapidity, + sigma0Core::SigmaOPAngle, + sigma0Core::SigmaCentrality, + sigma0Core::SigmaRunNumber, + sigma0Core::SigmaTimestamp); + +// For Photon extra info +namespace sigmaPhotonExtra +{ DECLARE_SOA_COLUMN(PhotonPt, photonPt, float); DECLARE_SOA_COLUMN(PhotonMass, photonMass, float); DECLARE_SOA_COLUMN(PhotonQt, photonQt, float); @@ -43,57 +61,180 @@ DECLARE_SOA_COLUMN(PhotonDCADau, photonDCADau, float); DECLARE_SOA_COLUMN(PhotonDCANegPV, photonDCANegPV, float); DECLARE_SOA_COLUMN(PhotonDCAPosPV, photonDCAPosPV, float); DECLARE_SOA_COLUMN(PhotonZconv, photonZconv, float); +DECLARE_SOA_COLUMN(PhotonEta, photonEta, float); +DECLARE_SOA_COLUMN(PhotonY, photonY, float); +DECLARE_SOA_COLUMN(PhotonPhi, photonPhi, float); +DECLARE_SOA_COLUMN(PhotonPosTPCNSigmaEl, photonPosTPCNSigmaEl, float); +DECLARE_SOA_COLUMN(PhotonNegTPCNSigmaEl, photonNegTPCNSigmaEl, float); +DECLARE_SOA_COLUMN(PhotonPosTPCNSigmaPi, photonPosTPCNSigmaPi, float); +DECLARE_SOA_COLUMN(PhotonNegTPCNSigmaPi, photonNegTPCNSigmaPi, float); +DECLARE_SOA_COLUMN(PhotonPosTPCCrossedRows, photonPosTPCCrossedRows, uint8_t); +DECLARE_SOA_COLUMN(PhotonNegTPCCrossedRows, photonNegTPCCrossedRows, uint8_t); +DECLARE_SOA_COLUMN(PhotonPosPt, photonPosPt, float); +DECLARE_SOA_COLUMN(PhotonNegPt, photonNegPt, float); +DECLARE_SOA_COLUMN(PhotonPosEta, photonPosEta, float); +DECLARE_SOA_COLUMN(PhotonNegEta, photonNegEta, float); +DECLARE_SOA_COLUMN(PhotonPosY, photonPosY, float); +DECLARE_SOA_COLUMN(PhotonNegY, photonNegY, float); +DECLARE_SOA_COLUMN(PhotonPsiPair, photonPsiPair, float); +DECLARE_SOA_COLUMN(PhotonPosITSCls, photonPosITSCls, int); +DECLARE_SOA_COLUMN(PhotonNegITSCls, photonNegITSCls, int); +DECLARE_SOA_COLUMN(PhotonPosITSChi2PerNcl, photonPosITSChi2PerNcl, float); +DECLARE_SOA_COLUMN(PhotonNegITSChi2PerNcl, photonNegITSChi2PerNcl, float); +DECLARE_SOA_COLUMN(PhotonV0Type, photonV0Type, uint8_t); +DECLARE_SOA_COLUMN(GammaBDTScore, gammaBDTScore, float); + +} // namespace sigmaPhotonExtra + +DECLARE_SOA_TABLE(SigmaPhotonExtras, "AOD", "SIGMA0PHOTON", + sigmaPhotonExtra::PhotonPt, + sigmaPhotonExtra::PhotonMass, + sigmaPhotonExtra::PhotonQt, + sigmaPhotonExtra::PhotonAlpha, + sigmaPhotonExtra::PhotonRadius, + sigmaPhotonExtra::PhotonCosPA, + sigmaPhotonExtra::PhotonDCADau, + sigmaPhotonExtra::PhotonDCANegPV, + sigmaPhotonExtra::PhotonDCAPosPV, + sigmaPhotonExtra::PhotonZconv, + sigmaPhotonExtra::PhotonEta, + sigmaPhotonExtra::PhotonY, + sigmaPhotonExtra::PhotonPhi, + sigmaPhotonExtra::PhotonPosTPCNSigmaEl, + sigmaPhotonExtra::PhotonNegTPCNSigmaEl, + sigmaPhotonExtra::PhotonPosTPCNSigmaPi, + sigmaPhotonExtra::PhotonNegTPCNSigmaPi, + sigmaPhotonExtra::PhotonPosTPCCrossedRows, + sigmaPhotonExtra::PhotonNegTPCCrossedRows, + sigmaPhotonExtra::PhotonPosPt, + sigmaPhotonExtra::PhotonNegPt, + sigmaPhotonExtra::PhotonPosEta, + sigmaPhotonExtra::PhotonNegEta, + sigmaPhotonExtra::PhotonPosY, + sigmaPhotonExtra::PhotonNegY, + sigmaPhotonExtra::PhotonPsiPair, + sigmaPhotonExtra::PhotonPosITSCls, + sigmaPhotonExtra::PhotonNegITSCls, + sigmaPhotonExtra::PhotonPosITSChi2PerNcl, + sigmaPhotonExtra::PhotonNegITSChi2PerNcl, + sigmaPhotonExtra::PhotonV0Type, + sigmaPhotonExtra::GammaBDTScore); + +// For Lambda extra info +namespace sigmaLambdaExtra +{ DECLARE_SOA_COLUMN(LambdaPt, lambdaPt, float); DECLARE_SOA_COLUMN(LambdaMass, lambdaMass, float); +DECLARE_SOA_COLUMN(AntiLambdaMass, antilambdaMass, float); DECLARE_SOA_COLUMN(LambdaQt, lambdaQt, float); DECLARE_SOA_COLUMN(LambdaAlpha, lambdaAlpha, float); +DECLARE_SOA_COLUMN(LambdaLifeTime, lambdaLifeTime, float); DECLARE_SOA_COLUMN(LambdaRadius, lambdaRadius, float); DECLARE_SOA_COLUMN(LambdaCosPA, lambdaCosPA, float); DECLARE_SOA_COLUMN(LambdaDCADau, lambdaDCADau, float); DECLARE_SOA_COLUMN(LambdaDCANegPV, lambdaDCANegPV, float); DECLARE_SOA_COLUMN(LambdaDCAPosPV, lambdaDCAPosPV, float); -DECLARE_SOA_COLUMN(GammaProbability, gammaProbability, float); -DECLARE_SOA_COLUMN(LambdaProbability, lambdaProbability, float); - -} // namespace v0SigmaCandidate - -DECLARE_SOA_TABLE(V0SigmaCandidates, "AOD", "V0SIGMAS", - v0SigmaCandidate::SigmapT, - v0SigmaCandidate::SigmaMass, - // v0SigmaCandidate::SigmaDCAz, - // v0SigmaCandidate::SigmaDCAxy, - // v0SigmaCandidate::SigmaDCADau, - v0SigmaCandidate::PhotonPt, - v0SigmaCandidate::PhotonMass, - v0SigmaCandidate::PhotonQt, - v0SigmaCandidate::PhotonAlpha, - v0SigmaCandidate::PhotonRadius, - v0SigmaCandidate::PhotonCosPA, - v0SigmaCandidate::PhotonDCADau, - v0SigmaCandidate::PhotonDCANegPV, - v0SigmaCandidate::PhotonDCAPosPV, - v0SigmaCandidate::PhotonZconv, - v0SigmaCandidate::LambdaPt, - v0SigmaCandidate::LambdaMass, - v0SigmaCandidate::LambdaQt, - v0SigmaCandidate::LambdaAlpha, - v0SigmaCandidate::LambdaRadius, - v0SigmaCandidate::LambdaCosPA, - v0SigmaCandidate::LambdaDCADau, - v0SigmaCandidate::LambdaDCANegPV, - v0SigmaCandidate::LambdaDCAPosPV, - v0SigmaCandidate::GammaProbability, - v0SigmaCandidate::LambdaProbability); +DECLARE_SOA_COLUMN(LambdaEta, lambdaEta, float); +DECLARE_SOA_COLUMN(LambdaY, lambdaY, float); +DECLARE_SOA_COLUMN(LambdaPhi, lambdaPhi, float); +DECLARE_SOA_COLUMN(LambdaPosPrTPCNSigma, lambdaPosPrTPCNSigma, float); +DECLARE_SOA_COLUMN(LambdaPosPiTPCNSigma, lambdaPosPiTPCNSigma, float); +DECLARE_SOA_COLUMN(LambdaNegPrTPCNSigma, lambdaNegPrTPCNSigma, float); +DECLARE_SOA_COLUMN(LambdaNegPiTPCNSigma, lambdaNegPiTPCNSigma, float); +DECLARE_SOA_COLUMN(LambdaPrTOFNSigma, lambdaPrTOFNSigma, float); +DECLARE_SOA_COLUMN(LambdaPiTOFNSigma, lambdaPiTOFNSigma, float); +DECLARE_SOA_COLUMN(ALambdaPrTOFNSigma, aLambdaPrTOFNSigma, float); +DECLARE_SOA_COLUMN(ALambdaPiTOFNSigma, aLambdaPiTOFNSigma, float); +DECLARE_SOA_COLUMN(LambdaPosTPCCrossedRows, lambdaPosTPCCrossedRows, uint8_t); +DECLARE_SOA_COLUMN(LambdaNegTPCCrossedRows, lambdaNegTPCCrossedRows, uint8_t); +DECLARE_SOA_COLUMN(LambdaPosPt, lambdaPosPt, float); +DECLARE_SOA_COLUMN(LambdaNegPt, lambdaNegPt, float); +DECLARE_SOA_COLUMN(LambdaPosEta, lambdaPosEta, float); +DECLARE_SOA_COLUMN(LambdaNegEta, lambdaNegEta, float); +DECLARE_SOA_COLUMN(LambdaPosPrY, lambdaPosPrY, float); +DECLARE_SOA_COLUMN(LambdaPosPiY, lambdaPosPiY, float); +DECLARE_SOA_COLUMN(LambdaNegPrY, lambdaNegPrY, float); +DECLARE_SOA_COLUMN(LambdaNegPiY, lambdaNegPiY, float); +DECLARE_SOA_COLUMN(LambdaPosITSCls, lambdaPosITSCls, int); +DECLARE_SOA_COLUMN(LambdaNegITSCls, lambdaNegITSCls, int); +DECLARE_SOA_COLUMN(LambdaPosITSChi2PerNcl, lambdaPosChi2PerNcl, float); +DECLARE_SOA_COLUMN(LambdaNegITSChi2PerNcl, lambdaNegChi2PerNcl, float); +DECLARE_SOA_COLUMN(LambdaV0Type, lambdaV0Type, uint8_t); +DECLARE_SOA_COLUMN(LambdaBDTScore, lambdaBDTScore, float); +DECLARE_SOA_COLUMN(AntiLambdaBDTScore, antilambdaBDTScore, float); + +} // namespace sigmaLambdaExtra + +DECLARE_SOA_TABLE(SigmaLambdaExtras, "AOD", "SIGMA0LAMBDA", + sigmaLambdaExtra::LambdaPt, + sigmaLambdaExtra::LambdaMass, + sigmaLambdaExtra::AntiLambdaMass, + sigmaLambdaExtra::LambdaQt, + sigmaLambdaExtra::LambdaAlpha, + sigmaLambdaExtra::LambdaLifeTime, + sigmaLambdaExtra::LambdaRadius, + sigmaLambdaExtra::LambdaCosPA, + sigmaLambdaExtra::LambdaDCADau, + sigmaLambdaExtra::LambdaDCANegPV, + sigmaLambdaExtra::LambdaDCAPosPV, + sigmaLambdaExtra::LambdaEta, + sigmaLambdaExtra::LambdaY, + sigmaLambdaExtra::LambdaPhi, + sigmaLambdaExtra::LambdaPosPrTPCNSigma, + sigmaLambdaExtra::LambdaPosPiTPCNSigma, + sigmaLambdaExtra::LambdaNegPrTPCNSigma, + sigmaLambdaExtra::LambdaNegPiTPCNSigma, + sigmaLambdaExtra::LambdaPrTOFNSigma, + sigmaLambdaExtra::LambdaPiTOFNSigma, + sigmaLambdaExtra::ALambdaPrTOFNSigma, + sigmaLambdaExtra::ALambdaPiTOFNSigma, + sigmaLambdaExtra::LambdaPosTPCCrossedRows, + sigmaLambdaExtra::LambdaNegTPCCrossedRows, + sigmaLambdaExtra::LambdaPosPt, + sigmaLambdaExtra::LambdaNegPt, + sigmaLambdaExtra::LambdaPosEta, + sigmaLambdaExtra::LambdaNegEta, + sigmaLambdaExtra::LambdaPosPrY, + sigmaLambdaExtra::LambdaPosPiY, + sigmaLambdaExtra::LambdaNegPrY, + sigmaLambdaExtra::LambdaNegPiY, + sigmaLambdaExtra::LambdaPosITSCls, + sigmaLambdaExtra::LambdaNegITSCls, + sigmaLambdaExtra::LambdaPosITSChi2PerNcl, + sigmaLambdaExtra::LambdaNegITSChi2PerNcl, + sigmaLambdaExtra::LambdaV0Type, + sigmaLambdaExtra::LambdaBDTScore, + sigmaLambdaExtra::AntiLambdaBDTScore); // for MC data -namespace v0SigmaMCCandidate +namespace sigmaMCCore { -DECLARE_SOA_COLUMN(IsSigma, isSigma, bool); +DECLARE_SOA_COLUMN(IsSigma, isSigma, bool); // TODO: include PDG + IsPhysicalPrimary +DECLARE_SOA_COLUMN(IsAntiSigma, isAntiSigma, bool); +DECLARE_SOA_COLUMN(SigmaMCPt, sigmaMCPt, float); +DECLARE_SOA_COLUMN(PhotonCandPDGCode, photonCandPDGCode, int); +DECLARE_SOA_COLUMN(PhotonCandPDGCodeMother, photonCandPDGCodeMother, int); +DECLARE_SOA_COLUMN(IsPhotonCandPrimary, isPhotonCandPrimary, bool); +DECLARE_SOA_COLUMN(PhotonMCPt, photonMCPt, float); +DECLARE_SOA_COLUMN(LambdaCandPDGCode, lambdaCandPDGCode, int); +DECLARE_SOA_COLUMN(LambdaCandPDGCodeMother, lambdaCandPDGCodeMother, int); +DECLARE_SOA_COLUMN(IsLambdaCandPrimary, isLambdaCandPrimary, bool); +DECLARE_SOA_COLUMN(LambdaMCPt, lambdaMCPt, float); -} // namespace v0SigmaMCCandidate +} // namespace sigmaMCCore -DECLARE_SOA_TABLE(V0SigmaMCCandidates, "AOD", "V0MCSIGMAS", - v0SigmaMCCandidate::IsSigma); +DECLARE_SOA_TABLE(SigmaMCCores, "AOD", "SIGMA0MCCORES", + sigmaMCCore::IsSigma, + sigmaMCCore::IsAntiSigma, + sigmaMCCore::SigmaMCPt, + sigmaMCCore::PhotonCandPDGCode, + sigmaMCCore::PhotonCandPDGCodeMother, + sigmaMCCore::IsPhotonCandPrimary, + sigmaMCCore::PhotonMCPt, + sigmaMCCore::LambdaCandPDGCode, + sigmaMCCore::LambdaCandPDGCodeMother, + sigmaMCCore::IsLambdaCandPrimary, + sigmaMCCore::LambdaMCPt); } // namespace o2::aod #endif // PWGLF_DATAMODEL_LFSIGMATABLES_H_ diff --git a/PWGLF/DataModel/LFSlimNucleiTables.h b/PWGLF/DataModel/LFSlimNucleiTables.h index c61c1b25a7b..28067a9521b 100644 --- a/PWGLF/DataModel/LFSlimNucleiTables.h +++ b/PWGLF/DataModel/LFSlimNucleiTables.h @@ -36,16 +36,19 @@ DECLARE_SOA_COLUMN(DCAz, dcaz, float); DECLARE_SOA_COLUMN(TPCsignal, tpcSignal, float); DECLARE_SOA_COLUMN(ITSchi2, itsChi2, float); DECLARE_SOA_COLUMN(TPCchi2, tpcChi2, float); +DECLARE_SOA_COLUMN(TOFchi2, tofChi2, float); DECLARE_SOA_COLUMN(Flags, flags, uint16_t); DECLARE_SOA_COLUMN(TPCfindableCls, tpcFindableCls, uint8_t); DECLARE_SOA_COLUMN(TPCcrossedRows, tpcCrossedRows, uint8_t); DECLARE_SOA_COLUMN(ITSclsMap, itsClsMap, uint8_t); DECLARE_SOA_COLUMN(TPCnCls, tpcNCls, uint8_t); +DECLARE_SOA_COLUMN(TPCnClsShared, tpcNClsShared, uint8_t); DECLARE_SOA_COLUMN(ITSclusterSizes, itsClusterSizes, uint32_t); DECLARE_SOA_COLUMN(gPt, genPt, float); DECLARE_SOA_COLUMN(gEta, genEta, float); DECLARE_SOA_COLUMN(gPhi, genPhi, float); DECLARE_SOA_COLUMN(PDGcode, pdgCode, int); +DECLARE_SOA_COLUMN(MotherPDGcode, MotherpdgCode, int); DECLARE_SOA_COLUMN(SurvivedEventSelection, survivedEventSelection, bool); DECLARE_SOA_COLUMN(AbsoDecL, absoDecL, float); @@ -57,13 +60,15 @@ DECLARE_SOA_COLUMN(CentFT0A, centFT0A, float); // centrality with FT0A estimator DECLARE_SOA_COLUMN(CentFT0C, centFT0C, float); // centrality with FT0C estimator DECLARE_SOA_COLUMN(CentFT0M, centFT0M, float); // centrality with FT0M estimator DECLARE_SOA_COLUMN(PsiFT0A, psiFT0A, float); // Psi with FT0A estimator -DECLARE_SOA_COLUMN(MultFT0A, multFT0A, float); // Multiplicity with FT0A estimator DECLARE_SOA_COLUMN(PsiFT0C, psiFT0C, float); // Psi with FT0C estimator -DECLARE_SOA_COLUMN(MultFT0C, multFT0C, float); // Multiplicity with FT0C estimator DECLARE_SOA_COLUMN(PsiTPC, psiTPC, float); // Psi with TPC estimator DECLARE_SOA_COLUMN(PsiTPCl, psiTPCl, float); // Psi with TPC estimator (left) DECLARE_SOA_COLUMN(PsiTPCr, psiTPCr, float); // Psi with TPC estimator (right) -DECLARE_SOA_COLUMN(MultTPC, multTPC, int); // Multiplicity with TPC estimator +DECLARE_SOA_COLUMN(QFT0A, qFT0A, float); // Amplitude with FT0A estimator +DECLARE_SOA_COLUMN(QFT0C, qFT0C, float); // Amplitude with FT0C estimator +DECLARE_SOA_COLUMN(QTPC, qTPC, float); // Amplitude with TPC estimator +DECLARE_SOA_COLUMN(QTPCl, qTPCl, float); // Amplitude with TPC estimator (left) +DECLARE_SOA_COLUMN(QTPCr, qTPCr, float); // Amplitude with TPC estimator (right) } // namespace NucleiFlowTableNS DECLARE_SOA_TABLE(NucleiTable, "AOD", "NUCLEITABLE", @@ -78,11 +83,13 @@ DECLARE_SOA_TABLE(NucleiTable, "AOD", "NUCLEITABLE", NucleiTableNS::TPCsignal, NucleiTableNS::ITSchi2, NucleiTableNS::TPCchi2, + NucleiTableNS::TOFchi2, NucleiTableNS::Flags, NucleiTableNS::TPCfindableCls, NucleiTableNS::TPCcrossedRows, NucleiTableNS::ITSclsMap, NucleiTableNS::TPCnCls, + NucleiTableNS::TPCnClsShared, NucleiTableNS::ITSclusterSizes); DECLARE_SOA_TABLE(NucleiTableFlow, "AOD", "NUCLEITABLEFLOW", @@ -91,13 +98,15 @@ DECLARE_SOA_TABLE(NucleiTableFlow, "AOD", "NUCLEITABLEFLOW", NucleiFlowTableNS::CentFT0A, NucleiFlowTableNS::CentFT0C, NucleiFlowTableNS::PsiFT0A, - NucleiFlowTableNS::MultFT0A, NucleiFlowTableNS::PsiFT0C, - NucleiFlowTableNS::MultFT0C, NucleiFlowTableNS::PsiTPC, NucleiFlowTableNS::PsiTPCl, NucleiFlowTableNS::PsiTPCr, - NucleiFlowTableNS::MultTPC); + NucleiFlowTableNS::QFT0A, + NucleiFlowTableNS::QFT0C, + NucleiFlowTableNS::QTPC, + NucleiFlowTableNS::QTPCl, + NucleiFlowTableNS::QTPCr); DECLARE_SOA_TABLE(NucleiTableMC, "AOD", "NUCLEITABLEMC", NucleiTableNS::Pt, @@ -111,16 +120,19 @@ DECLARE_SOA_TABLE(NucleiTableMC, "AOD", "NUCLEITABLEMC", NucleiTableNS::TPCsignal, NucleiTableNS::ITSchi2, NucleiTableNS::TPCchi2, + NucleiTableNS::TOFchi2, NucleiTableNS::Flags, NucleiTableNS::TPCfindableCls, NucleiTableNS::TPCcrossedRows, NucleiTableNS::ITSclsMap, NucleiTableNS::TPCnCls, + NucleiTableNS::TPCnClsShared, NucleiTableNS::ITSclusterSizes, NucleiTableNS::gPt, NucleiTableNS::gEta, NucleiTableNS::gPhi, NucleiTableNS::PDGcode, + NucleiTableNS::MotherPDGcode, NucleiTableNS::SurvivedEventSelection, NucleiTableNS::AbsoDecL); diff --git a/PWGLF/DataModel/LFSlimStrangeTables.h b/PWGLF/DataModel/LFSlimStrangeTables.h index 8a68e17fda4..423a412bb6d 100644 --- a/PWGLF/DataModel/LFSlimStrangeTables.h +++ b/PWGLF/DataModel/LFSlimStrangeTables.h @@ -22,59 +22,129 @@ namespace SlimLambdaTables { DECLARE_SOA_COLUMN(Pt, pt, float); DECLARE_SOA_COLUMN(Eta, eta, float); -DECLARE_SOA_COLUMN(CentFT0C, centFT0C, float); -DECLARE_SOA_COLUMN(IsMatter, isMatter, bool); DECLARE_SOA_COLUMN(Mass, mass, float); DECLARE_SOA_COLUMN(Ct, ct, float); +DECLARE_SOA_COLUMN(Len, len, float); DECLARE_SOA_COLUMN(Radius, radius, float); DECLARE_SOA_COLUMN(DcaV0PV, dcaV0Pv, float); -DECLARE_SOA_COLUMN(DcaPiPV, dcaPiPv, float); -DECLARE_SOA_COLUMN(DcaPrPV, dcaPrPv, float); +DECLARE_SOA_COLUMN(DcaPosPV, dcaPosPv, float); +DECLARE_SOA_COLUMN(DcaNegPV, dcaNegPv, float); DECLARE_SOA_COLUMN(DcaV0Tracks, dcaV0tracks, float); DECLARE_SOA_COLUMN(CosPA, cosPa, double); -DECLARE_SOA_COLUMN(TpcNsigmaPi, tpcNsigmaPi, float); -DECLARE_SOA_COLUMN(TpcNsigmaPr, tpcNsigmaPr, float); +DECLARE_SOA_COLUMN(AlphaAP, alphaAP, double); +DECLARE_SOA_COLUMN(QtAP, qtAP, double); +DECLARE_SOA_COLUMN(TpcNsigmaPos, tpcNsigmaPos, float); +DECLARE_SOA_COLUMN(TpcNsigmaNeg, tpcNsigmaNeg, float); +DECLARE_SOA_COLUMN(PxPos, pxPos, float); +DECLARE_SOA_COLUMN(PyPos, pyPos, float); +DECLARE_SOA_COLUMN(PzPos, pzPos, float); +DECLARE_SOA_COLUMN(PxNeg, pxNeg, float); +DECLARE_SOA_COLUMN(PyNeg, pyNeg, float); +DECLARE_SOA_COLUMN(PzNeg, pzNeg, float); +DECLARE_SOA_COLUMN(PxPosMC, pxPosMC, float); +DECLARE_SOA_COLUMN(PyPosMC, pyPosMC, float); +DECLARE_SOA_COLUMN(PzPosMC, pzPosMC, float); +DECLARE_SOA_COLUMN(PxNegMC, pxNegMC, float); +DECLARE_SOA_COLUMN(PyNegMC, pyNegMC, float); +DECLARE_SOA_COLUMN(PzNegMC, pzNegMC, float); DECLARE_SOA_COLUMN(GenPt, gentPt, float); DECLARE_SOA_COLUMN(GenEta, genEta, float); DECLARE_SOA_COLUMN(GenCt, genCt, float); +DECLARE_SOA_COLUMN(GenLen, genLen, float); +DECLARE_SOA_COLUMN(PDGCodeDauPos, pdgCodeDauPos, int); +DECLARE_SOA_COLUMN(PDGCodeMotherDauPos, pdgCodeMotherDauPos, int); +DECLARE_SOA_COLUMN(PDGCodeDauNeg, pdgCodeDauNeg, int); +DECLARE_SOA_COLUMN(PDGCodeMotherDauNeg, pdgCodeMotherDauNeg, int); DECLARE_SOA_COLUMN(PDGCode, pdgCode, int); +DECLARE_SOA_COLUMN(PDGCodeMother, pdgCodeMother, int); DECLARE_SOA_COLUMN(IsReco, isReco, bool); +DECLARE_SOA_COLUMN(IsFD, isFD, uint8_t); +DECLARE_SOA_COLUMN(PDGMatchMotherSecondMother, pdgMatchMotherSecondMother, int); } // namespace SlimLambdaTables DECLARE_SOA_TABLE(LambdaTableML, "AOD", "LAMBDATABLEML", SlimLambdaTables::Pt, SlimLambdaTables::Eta, - SlimLambdaTables::CentFT0C, - SlimLambdaTables::IsMatter, SlimLambdaTables::Mass, SlimLambdaTables::Ct, SlimLambdaTables::Radius, SlimLambdaTables::DcaV0PV, - SlimLambdaTables::DcaPiPV, - SlimLambdaTables::DcaPrPV, + SlimLambdaTables::DcaPosPV, + SlimLambdaTables::DcaNegPV, SlimLambdaTables::DcaV0Tracks, SlimLambdaTables::CosPA, - SlimLambdaTables::TpcNsigmaPi, - SlimLambdaTables::TpcNsigmaPr); + SlimLambdaTables::AlphaAP, + SlimLambdaTables::QtAP, + SlimLambdaTables::TpcNsigmaPos, + SlimLambdaTables::TpcNsigmaNeg, + SlimLambdaTables::IsFD); DECLARE_SOA_TABLE(McLambdaTableML, "AOD", "MCLAMBDATABLEML", SlimLambdaTables::Pt, SlimLambdaTables::Eta, - SlimLambdaTables::CentFT0C, - SlimLambdaTables::IsMatter, SlimLambdaTables::Mass, SlimLambdaTables::Ct, SlimLambdaTables::Radius, SlimLambdaTables::DcaV0PV, - SlimLambdaTables::DcaPiPV, - SlimLambdaTables::DcaPrPV, + SlimLambdaTables::DcaPosPV, + SlimLambdaTables::DcaNegPV, SlimLambdaTables::DcaV0Tracks, SlimLambdaTables::CosPA, - SlimLambdaTables::TpcNsigmaPi, - SlimLambdaTables::TpcNsigmaPr, + SlimLambdaTables::AlphaAP, + SlimLambdaTables::QtAP, + SlimLambdaTables::TpcNsigmaPos, + SlimLambdaTables::TpcNsigmaNeg, SlimLambdaTables::GenPt, SlimLambdaTables::GenEta, SlimLambdaTables::GenCt, + SlimLambdaTables::PDGCodeDauPos, + SlimLambdaTables::PDGCodeMotherDauPos, + SlimLambdaTables::PDGCodeDauNeg, + SlimLambdaTables::PDGCodeMotherDauNeg, + SlimLambdaTables::PDGCode, + SlimLambdaTables::PDGCodeMother, + SlimLambdaTables::IsReco, + SlimLambdaTables::PDGMatchMotherSecondMother); + +DECLARE_SOA_TABLE(V0TableAP, "AOD", "V0TABLEAP", + SlimLambdaTables::Eta, + SlimLambdaTables::Len, + SlimLambdaTables::PxPos, + SlimLambdaTables::PyPos, + SlimLambdaTables::PzPos, + SlimLambdaTables::PxNeg, + SlimLambdaTables::PyNeg, + SlimLambdaTables::PzNeg, + SlimLambdaTables::Radius, + SlimLambdaTables::DcaV0PV, + SlimLambdaTables::DcaPosPV, + SlimLambdaTables::DcaNegPV, + SlimLambdaTables::DcaV0Tracks, + SlimLambdaTables::CosPA); + +DECLARE_SOA_TABLE(McV0TableAP, "AOD", "MCV0TABLEAP", + SlimLambdaTables::Eta, + SlimLambdaTables::Len, + SlimLambdaTables::PxPos, + SlimLambdaTables::PyPos, + SlimLambdaTables::PzPos, + SlimLambdaTables::PxNeg, + SlimLambdaTables::PyNeg, + SlimLambdaTables::PzNeg, + SlimLambdaTables::PxPosMC, + SlimLambdaTables::PyPosMC, + SlimLambdaTables::PzPosMC, + SlimLambdaTables::PxNegMC, + SlimLambdaTables::PyNegMC, + SlimLambdaTables::PzNegMC, + SlimLambdaTables::Radius, + SlimLambdaTables::DcaV0PV, + SlimLambdaTables::DcaPosPV, + SlimLambdaTables::DcaNegPV, + SlimLambdaTables::DcaV0Tracks, + SlimLambdaTables::CosPA, + SlimLambdaTables::GenEta, + SlimLambdaTables::GenLen, SlimLambdaTables::PDGCode, SlimLambdaTables::IsReco); diff --git a/PWGLF/DataModel/LFStrangenessMLTables.h b/PWGLF/DataModel/LFStrangenessMLTables.h index c052ab70fdf..abae8814856 100644 --- a/PWGLF/DataModel/LFStrangenessMLTables.h +++ b/PWGLF/DataModel/LFStrangenessMLTables.h @@ -18,9 +18,6 @@ #ifndef PWGLF_DATAMODEL_LFSTRANGENESSMLTABLES_H_ #define PWGLF_DATAMODEL_LFSTRANGENESSMLTABLES_H_ -using namespace o2; -using namespace o2::framework; - // Creating output TTree for ML analysis namespace o2::aod { @@ -30,8 +27,8 @@ DECLARE_SOA_COLUMN(PosITSCls, posITSCls, int); DECLARE_SOA_COLUMN(NegITSCls, negITSCls, int); DECLARE_SOA_COLUMN(PosITSClSize, posITSClSize, uint32_t); DECLARE_SOA_COLUMN(NegITSClSize, negITSClSize, uint32_t); -DECLARE_SOA_COLUMN(PosTPCRows, posTPCRows, float); -DECLARE_SOA_COLUMN(NegTPCRows, negTPCRows, float); +DECLARE_SOA_COLUMN(PosTPCRows, posTPCRows, uint8_t); +DECLARE_SOA_COLUMN(NegTPCRows, negTPCRows, uint8_t); DECLARE_SOA_COLUMN(PosTPCSigmaPi, posTPCSigmaPi, float); DECLARE_SOA_COLUMN(NegTPCSigmaPi, negTPCSigmaPi, float); DECLARE_SOA_COLUMN(PosTPCSigmaPr, posTPCSigmaPr, float); @@ -69,6 +66,7 @@ DECLARE_SOA_COLUMN(IsLambda, isLambda, bool); DECLARE_SOA_COLUMN(IsAntiLambda, isAntiLambda, bool); DECLARE_SOA_COLUMN(IsGamma, isGamma, bool); DECLARE_SOA_COLUMN(IsKZeroShort, isKZeroShort, bool); +DECLARE_SOA_COLUMN(PDGCodeMother, pdgCodeMother, int); } // namespace v0mlcandidates DECLARE_SOA_TABLE(V0MLCandidates, "AOD", "V0MLCANDIDATES", @@ -114,7 +112,8 @@ DECLARE_SOA_TABLE(V0MLCandidates, "AOD", "V0MLCANDIDATES", v0mlcandidates::IsLambda, v0mlcandidates::IsAntiLambda, v0mlcandidates::IsGamma, - v0mlcandidates::IsKZeroShort); + v0mlcandidates::IsKZeroShort, + v0mlcandidates::PDGCodeMother); namespace V0MLSelection { @@ -236,6 +235,18 @@ DECLARE_SOA_TABLE(CascMLCandidates, "AOD", "CAMLCANDIDATES", cascmlcandidates::IsXiPlus, cascmlcandidates::IsOmegaMinus, cascmlcandidates::IsOmegaPlus); + +namespace CascMLSelection +{ +DECLARE_SOA_COLUMN(XiBDTScore, xiBDTScore, float); +DECLARE_SOA_COLUMN(OmegaBDTScore, omegaBDTScore, float); +} // namespace CascMLSelection + +DECLARE_SOA_TABLE(CascXiMLScores, "AOD", "CASCXIMLSCORES", + CascMLSelection::XiBDTScore); +DECLARE_SOA_TABLE(CascOmMLScores, "AOD", "CASCOMMLSCORES", + CascMLSelection::OmegaBDTScore); + } // namespace o2::aod #endif // PWGLF_DATAMODEL_LFSTRANGENESSMLTABLES_H_ diff --git a/PWGLF/DataModel/LFStrangenessPIDTables.h b/PWGLF/DataModel/LFStrangenessPIDTables.h index 36a345b87ad..e689dc28141 100644 --- a/PWGLF/DataModel/LFStrangenessPIDTables.h +++ b/PWGLF/DataModel/LFStrangenessPIDTables.h @@ -137,15 +137,15 @@ DECLARE_SOA_COLUMN(BachTOFEventTime, bachTOFEventTime, float); //! bachelor tr // delta-times DECLARE_SOA_COLUMN(PosTOFDeltaTXiPi, posTOFDeltaTXiPi, float); //! positive track TOFDeltaT from pion <- lambda <- xi expectation -DECLARE_SOA_COLUMN(PosTOFDeltaTXiPr, posTOFDeltaTXiPr, float); //! positive track TOFDeltaT from pion <- lambda <- xi expectation +DECLARE_SOA_COLUMN(PosTOFDeltaTXiPr, posTOFDeltaTXiPr, float); //! positive track TOFDeltaT from proton <- lambda <- xi expectation DECLARE_SOA_COLUMN(NegTOFDeltaTXiPi, negTOFDeltaTXiPi, float); //! negative track TOFDeltaT from pion <- lambda <- xi expectation -DECLARE_SOA_COLUMN(NegTOFDeltaTXiPr, negTOFDeltaTXiPr, float); //! negative track TOFDeltaT from pion <- lambda <- xi expectation +DECLARE_SOA_COLUMN(NegTOFDeltaTXiPr, negTOFDeltaTXiPr, float); //! negative track TOFDeltaT from proton <- lambda <- xi expectation DECLARE_SOA_COLUMN(BachTOFDeltaTXiPi, bachTOFDeltaTXiPi, float); //! bachelor track TOFDeltaT from pion <- xi expectation DECLARE_SOA_COLUMN(PosTOFDeltaTOmPi, posTOFDeltaTOmPi, float); //! positive track TOFDeltaT from pion <- lambda <- omega expectation -DECLARE_SOA_COLUMN(PosTOFDeltaTOmPr, posTOFDeltaTOmPr, float); //! positive track TOFDeltaT from pion <- lambda <- omega expectation +DECLARE_SOA_COLUMN(PosTOFDeltaTOmPr, posTOFDeltaTOmPr, float); //! positive track TOFDeltaT from proton <- lambda <- omega expectation DECLARE_SOA_COLUMN(NegTOFDeltaTOmPi, negTOFDeltaTOmPi, float); //! negative track TOFDeltaT from pion <- lambda <- omega expectation -DECLARE_SOA_COLUMN(NegTOFDeltaTOmPr, negTOFDeltaTOmPr, float); //! negative track TOFDeltaT from pion <- lambda <- omega expectation -DECLARE_SOA_COLUMN(BachTOFDeltaTOmPi, bachTOFDeltaTOmPi, float); //! bachelor track TOFDeltaT from pion <- omega expectation +DECLARE_SOA_COLUMN(NegTOFDeltaTOmPr, negTOFDeltaTOmPr, float); //! negative track TOFDeltaT from proton <- lambda <- omega expectation +DECLARE_SOA_COLUMN(BachTOFDeltaTOmKa, bachTOFDeltaTOmKa, float); //! bachelor track TOFDeltaT from kaon <- omega expectation // n-sigmas DECLARE_SOA_COLUMN(TOFNSigmaXiLaPi, tofNSigmaXiLaPi, float); //! meson track NSigma from pion <- lambda <- xi expectation @@ -170,7 +170,7 @@ DECLARE_SOA_TABLE(CascTOFPIDs, "AOD", "CASCTOFPID", // processed information for cascdata::BachTOFDeltaTXiPi, cascdata::PosTOFDeltaTOmPi, cascdata::PosTOFDeltaTOmPr, cascdata::NegTOFDeltaTOmPi, cascdata::NegTOFDeltaTOmPr, - cascdata::BachTOFDeltaTOmPi); + cascdata::BachTOFDeltaTOmKa); DECLARE_SOA_TABLE(CascTOFNSigmas, "AOD", "CascTOFNSigmas", // Nsigmas for cascades cascdata::TOFNSigmaXiLaPi, cascdata::TOFNSigmaXiLaPr, cascdata::TOFNSigmaXiPi, cascdata::TOFNSigmaOmLaPi, cascdata::TOFNSigmaOmLaPr, cascdata::TOFNSigmaOmKa); diff --git a/PWGLF/DataModel/LFStrangenessTables.h b/PWGLF/DataModel/LFStrangenessTables.h old mode 100755 new mode 100644 index f1fde733c72..bfe3a4f055d --- a/PWGLF/DataModel/LFStrangenessTables.h +++ b/PWGLF/DataModel/LFStrangenessTables.h @@ -20,26 +20,72 @@ #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/SPCalibrationTables.h" +#include "PWGUD/DataModel/UDTables.h" namespace o2::aod { +// for DF name follow-up and debug +namespace straorigin +{ +DECLARE_SOA_COLUMN(DataframeID, dataframeID, uint64_t); //! Data frame ID (what is usually found in directory name in the AO2D.root, i.e. +} // namespace straorigin + +DECLARE_SOA_TABLE(StraOrigins, "AOD", "STRAORIGIN", //! Table which contains the IDs of all dataframes merged into this dataframe + o2::soa::Index<>, straorigin::DataframeID); + +namespace stracollision +{ +DECLARE_SOA_DYNAMIC_COLUMN(IsUPC, isUPC, //! check whether this is a UPC or hadronic collision + [](int value) -> bool { return value <= 2 ? true : false; }); +DECLARE_SOA_DYNAMIC_COLUMN(TotalFV0AmplitudeA, totalFV0AmplitudeA, //! get the total sum of the FV0 A amplitudes + [](float value) -> float { return value; }); +DECLARE_SOA_DYNAMIC_COLUMN(TotalFT0AmplitudeA, totalFT0AmplitudeA, //! get the total sum of the FT0 A amplitudes + [](float value) -> float { return value; }); +DECLARE_SOA_DYNAMIC_COLUMN(TotalFT0AmplitudeC, totalFT0AmplitudeC, //! get the total sum of the FT0 C amplitudes + [](float value) -> float { return value; }); +DECLARE_SOA_DYNAMIC_COLUMN(TotalFDDAmplitudeA, totalFDDAmplitudeA, //! get the total sum of the FDD A amplitudes + [](float value) -> float { return value; }); +DECLARE_SOA_DYNAMIC_COLUMN(TotalFDDAmplitudeC, totalFDDAmplitudeC, //! get the total sum of the FDD C amplitudes + [](float value) -> float { return value; }); +DECLARE_SOA_DYNAMIC_COLUMN(EnergyCommonZNA, energyCommonZNA, //! get the total sum of the ZN A amplitudes + [](float value) -> float { return value; }); +DECLARE_SOA_DYNAMIC_COLUMN(EnergyCommonZNC, energyCommonZNC, //! get the total sum of the ZN A amplitudes + [](float value) -> float { return value; }); +} // namespace stracollision + //______________________________________________________ // Collision declarations for derived data analysis // this is optional but will ensure full flexibility // if required (for 2pc, etc) DECLARE_SOA_TABLE(StraCollisions, "AOD", "STRACOLLISION", //! basic collision properties: position o2::soa::Index<>, collision::PosX, collision::PosY, collision::PosZ); -DECLARE_SOA_TABLE(StraCents, "AOD", "STRACENTS", //! centrality percentiles +DECLARE_SOA_TABLE(StraCents_000, "AOD", "STRACENTS", //! centrality percentiles cent::CentFT0M, cent::CentFT0A, cent::CentFT0C, cent::CentFV0A); +DECLARE_SOA_TABLE_VERSIONED(StraCents_001, "AOD", "STRACENTS", 1, //! centrality percentiles in Run 3 + cent::CentFT0M, cent::CentFT0A, + cent::CentFT0C, cent::CentFV0A, + cent::CentFT0CVariant1, cent::CentMFT, + cent::CentNGlobal); + +DECLARE_SOA_TABLE(StraCentsRun2, "AOD", "STRACENTSRUN2", //! centrality percentiles in Run 2 + cent::CentRun2V0M, cent::CentRun2V0A, + cent::CentRun2SPDTracklets, cent::CentRun2SPDClusters); + +// !!! DEPRECATED TABLE: StraRawCents_000 !!! All info in StraEvSels_001, in order to group all event characteristics in a unique table. Please use StraEvSels_001 DECLARE_SOA_TABLE(StraRawCents_000, "AOD", "STRARAWCENTS", //! debug information mult::MultFT0A, mult::MultFT0C, mult::MultFV0A, mult::MultNTracksPVeta1); +// !!! DEPRECATED TABLE: StraRawCents_001 !!! All info in StraEvSels_001, in order to group all event characteristics in a unique table. Please use StraEvSels_001 DECLARE_SOA_TABLE_VERSIONED(StraRawCents_001, "AOD", "STRARAWCENTS", 1, //! debug information mult::MultFT0A, mult::MultFT0C, mult::MultFV0A, // FIT detectors mult::MultNTracksPVeta1, // track multiplicities mult::MultZNA, mult::MultZNC, mult::MultZEM1, // ZDC signals mult::MultZEM2, mult::MultZPA, mult::MultZPC); +// !!! DEPRECATED TABLE: StraRawCents_002 !!! All info in StraEvSels_001, in order to group all event characteristics in a unique table. Please use StraEvSels_001 DECLARE_SOA_TABLE_VERSIONED(StraRawCents_002, "AOD", "STRARAWCENTS", 2, //! debug information mult::MultFT0A, mult::MultFT0C, mult::MultFV0A, // FIT detectors mult::MultNTracksPVeta1, // track multiplicities with eta cut for INEL>0 @@ -47,6 +93,7 @@ DECLARE_SOA_TABLE_VERSIONED(StraRawCents_002, "AOD", "STRARAWCENTS", 2, mult::MultAllTracksTPCOnly, mult::MultAllTracksITSTPC, // track multiplicities, all, no eta cut mult::MultZNA, mult::MultZNC, mult::MultZEM1, // ZDC signals mult::MultZEM2, mult::MultZPA, mult::MultZPC); +// !!! DEPRECATED TABLE: StraRawCents_003 !!! All info in StraEvSels_001, in order to group all event characteristics in a unique table. Please use StraEvSels_001 DECLARE_SOA_TABLE_VERSIONED(StraRawCents_003, "AOD", "STRARAWCENTS", 3, //! debug information mult::MultFT0A, mult::MultFT0C, mult::MultFV0A, // FIT detectors mult::MultNTracksPVeta1, // track multiplicities with eta cut for INEL>0 @@ -57,8 +104,182 @@ DECLARE_SOA_TABLE_VERSIONED(StraRawCents_003, "AOD", "STRARAWCENTS", 3, //! mult::MultAllTracksITSTPC, // ITSTPC track multiplicities, all, no eta cut mult::MultZNA, mult::MultZNC, mult::MultZEM1, // ZDC signals mult::MultZEM2, mult::MultZPA, mult::MultZPC); -DECLARE_SOA_TABLE(StraEvSels, "AOD", "STRAEVSELS", //! event selection: sel8 +// !!! DEPRECATED TABLE: StraRawCents_004 !!! All info in StraEvSels_001, in order to group all event characteristics in a unique table. Please use StraEvSels_001 +DECLARE_SOA_TABLE_VERSIONED(StraRawCents_004, "AOD", "STRARAWCENTS", 4, //! debug information + mult::MultFT0A, mult::MultFT0C, mult::MultFV0A, // FIT detectors + mult::MultNTracksPVeta1, // track multiplicities with eta cut for INEL>0 + mult::MultPVTotalContributors, // number of PV contribs total + mult::MultNTracksGlobal, // global track multiplicities + mult::MultNTracksITSTPC, // track multiplicities, PV contribs, no eta cut + mult::MultAllTracksTPCOnly, // TPConly track multiplicities, all, no eta cut + mult::MultAllTracksITSTPC, // ITSTPC track multiplicities, all, no eta cut + mult::MultZNA, mult::MultZNC, mult::MultZEM1, // ZDC signals + mult::MultZEM2, mult::MultZPA, mult::MultZPC, + evsel::NumTracksInTimeRange); // add occupancy as extra +DECLARE_SOA_TABLE(StraEvSels_000, "AOD", "STRAEVSELS", //! event selection: sel8 evsel::Sel8, evsel::Selection); +DECLARE_SOA_TABLE_VERSIONED(StraEvSels_001, "AOD", "STRAEVSELS", 1, //! debug information + evsel::Sel8, evsel::Selection, //! event selection: sel8 + mult::MultFT0A, mult::MultFT0C, mult::MultFV0A, // FIT detectors + mult::MultFDDA, mult::MultFDDC, + mult::MultNTracksPVeta1, // track multiplicities with eta cut for INEL>0 + mult::MultPVTotalContributors, // number of PV contribs total + mult::MultNTracksGlobal, // global track multiplicities + mult::MultNTracksITSTPC, // track multiplicities, PV contribs, no eta cut + mult::MultAllTracksTPCOnly, // TPConly track multiplicities, all, no eta cut + mult::MultAllTracksITSTPC, // ITSTPC track multiplicities, all, no eta cut + mult::MultZNA, mult::MultZNC, mult::MultZEM1, // ZDC signals + mult::MultZEM2, mult::MultZPA, mult::MultZPC, + evsel::NumTracksInTimeRange, // add occupancy as extra + udcollision::GapSide, // UPC info: 0 for side A, 1 for side C, 2 for both sides, 3 neither A or C, 4 not enough or too many pv contributors + udcollision::TotalFT0AmplitudeA, // UPC info: re-assigned FT0-A amplitude, in case of SG event, from the most active bc + udcollision::TotalFT0AmplitudeC, // UPC info: re-assigned FT0-C amplitude, in case of SG event, from the most active bc + udcollision::TotalFV0AmplitudeA, // UPC info: re-assigned FV0-A amplitude, in case of SG event, from the most active bc + udcollision::TotalFDDAmplitudeA, // UPC info: re-assigned FDD-A amplitude, in case of SG event, from the most active bc + udcollision::TotalFDDAmplitudeC, // UPC info: re-assigned FDD-C amplitude, in case of SG event, from the most active bc + udzdc::EnergyCommonZNA, // UPC info: re-assigned ZN-A amplitude, in case of SG event, from the most active bc + udzdc::EnergyCommonZNC, // UPC info: re-assigned ZN-C amplitude, in case of SG event, from the most active bc + stracollision::IsUPC); + +DECLARE_SOA_TABLE_VERSIONED(StraEvSels_002, "AOD", "STRAEVSELS", 2, //! debug information + evsel::Sel8, evsel::Selection, //! event selection: sel8 + mult::MultFT0A, mult::MultFT0C, mult::MultFV0A, // FIT detectors + mult::MultFDDA, mult::MultFDDC, + mult::MultNTracksPVeta1, // track multiplicities with eta cut for INEL>0 + mult::MultPVTotalContributors, // number of PV contribs total + mult::MultNTracksGlobal, // global track multiplicities + mult::MultNTracksITSTPC, // track multiplicities, PV contribs, no eta cut + mult::MultAllTracksTPCOnly, // TPConly track multiplicities, all, no eta cut + mult::MultAllTracksITSTPC, // ITSTPC track multiplicities, all, no eta cut + mult::MultZNA, mult::MultZNC, mult::MultZEM1, // ZDC signals + mult::MultZEM2, mult::MultZPA, mult::MultZPC, + evsel::NumTracksInTimeRange, // add occupancy in specified time interval by a number of tracks from nearby collisions + udcollision::GapSide, // UPC info: 0 for side A, 1 for side C, 2 for both sides, 3 neither A or C, 4 not enough or too many pv contributors + udcollision::TotalFT0AmplitudeA, // UPC info: re-assigned FT0-A amplitude, in case of SG event, from the most active bc + udcollision::TotalFT0AmplitudeC, // UPC info: re-assigned FT0-C amplitude, in case of SG event, from the most active bc + udcollision::TotalFV0AmplitudeA, // UPC info: re-assigned FV0-A amplitude, in case of SG event, from the most active bc + udcollision::TotalFDDAmplitudeA, // UPC info: re-assigned FDD-A amplitude, in case of SG event, from the most active bc + udcollision::TotalFDDAmplitudeC, // UPC info: re-assigned FDD-C amplitude, in case of SG event, from the most active bc + udzdc::EnergyCommonZNA, // UPC info: re-assigned ZN-A amplitude, in case of SG event, from the most active bc + udzdc::EnergyCommonZNC, // UPC info: re-assigned ZN-C amplitude, in case of SG event, from the most active bc + collision::Flags, // Contains Vertex::Flags, with most notably the UPCMode to know whether the vertex has been found using UPC settings + stracollision::IsUPC); + +DECLARE_SOA_TABLE_VERSIONED(StraEvSels_003, "AOD", "STRAEVSELS", 3, //! debug information + evsel::Sel8, evsel::Selection, //! event selection: sel8 + mult::MultFT0A, mult::MultFT0C, mult::MultFV0A, // FIT detectors + mult::MultFDDA, mult::MultFDDC, + mult::MultNTracksPVeta1, // track multiplicities with eta cut for INEL>0 + mult::MultPVTotalContributors, // number of PV contribs total + mult::MultNTracksGlobal, // global track multiplicities + mult::MultNTracksITSTPC, // track multiplicities, PV contribs, no eta cut + mult::MultAllTracksTPCOnly, // TPConly track multiplicities, all, no eta cut + mult::MultAllTracksITSTPC, // ITSTPC track multiplicities, all, no eta cut + mult::MultZNA, mult::MultZNC, mult::MultZEM1, // ZDC signals + mult::MultZEM2, mult::MultZPA, mult::MultZPC, + evsel::NumTracksInTimeRange, // add occupancy in specified time interval by a number of tracks from nearby collisions + evsel::SumAmpFT0CInTimeRange, // add occupancy in specified time interval by a sum of FT0C amplitudes from nearby collisions + udcollision::GapSide, // UPC info: 0 for side A, 1 for side C, 2 for both sides, 3 neither A or C, 4 not enough or too many pv contributors + udcollision::TotalFT0AmplitudeA, // UPC info: re-assigned FT0-A amplitude, in case of SG event, from the most active bc + udcollision::TotalFT0AmplitudeC, // UPC info: re-assigned FT0-C amplitude, in case of SG event, from the most active bc + udcollision::TotalFV0AmplitudeA, // UPC info: re-assigned FV0-A amplitude, in case of SG event, from the most active bc + udcollision::TotalFDDAmplitudeA, // UPC info: re-assigned FDD-A amplitude, in case of SG event, from the most active bc + udcollision::TotalFDDAmplitudeC, // UPC info: re-assigned FDD-C amplitude, in case of SG event, from the most active bc + udzdc::EnergyCommonZNA, // UPC info: re-assigned ZN-A amplitude, in case of SG event, from the most active bc + udzdc::EnergyCommonZNC, // UPC info: re-assigned ZN-C amplitude, in case of SG event, from the most active bc + collision::Flags, // Contains Vertex::Flags, with most notably the UPCMode to know whether the vertex has been found using UPC settings + stracollision::IsUPC); + +DECLARE_SOA_TABLE_VERSIONED(StraEvSels_004, "AOD", "STRAEVSELS", 4, //! debug information + evsel::Sel8, evsel::Selection, //! event selection: sel8 + mult::MultFT0A, mult::MultFT0C, mult::MultFV0A, // FIT detectors + mult::MultFDDA, mult::MultFDDC, + mult::MultNTracksPVeta1, // track multiplicities with eta cut for INEL>0 + mult::MultPVTotalContributors, // number of PV contribs total + mult::MultNTracksGlobal, // global track multiplicities + mult::MultNTracksITSTPC, // track multiplicities, PV contribs, no eta cut + mult::MultAllTracksTPCOnly, // TPConly track multiplicities, all, no eta cut + mult::MultAllTracksITSTPC, // ITSTPC track multiplicities, all, no eta cut + mult::MultZNA, mult::MultZNC, mult::MultZEM1, // ZDC signals + mult::MultZEM2, mult::MultZPA, mult::MultZPC, + evsel::NumTracksInTimeRange, // add occupancy in specified time interval by a number of tracks from nearby collisions + evsel::SumAmpFT0CInTimeRange, // add occupancy in specified time interval by a sum of FT0C amplitudes from nearby collisions + udcollision::GapSide, // UPC info: 0 for side A, 1 for side C, 2 for both sides, 3 neither A or C, 4 not enough or too many pv contributors + udcollision::TotalFT0AmplitudeA, // UPC info: re-assigned FT0-A amplitude, in case of SG event, from the most active bc + udcollision::TotalFT0AmplitudeC, // UPC info: re-assigned FT0-C amplitude, in case of SG event, from the most active bc + udcollision::TotalFV0AmplitudeA, // UPC info: re-assigned FV0-A amplitude, in case of SG event, from the most active bc + udcollision::TotalFDDAmplitudeA, // UPC info: re-assigned FDD-A amplitude, in case of SG event, from the most active bc + udcollision::TotalFDDAmplitudeC, // UPC info: re-assigned FDD-C amplitude, in case of SG event, from the most active bc + udzdc::EnergyCommonZNA, // UPC info: re-assigned ZN-A amplitude, in case of SG event, from the most active bc + udzdc::EnergyCommonZNC, // UPC info: re-assigned ZN-C amplitude, in case of SG event, from the most active bc + + collision::Flags, // Contains Vertex::Flags, with most notably the UPCMode to know whether the vertex has been found using UPC settings + evsel::Alias, // trigger aliases (e.g. kTVXinTRD for v2) + + // Dynamic columns for manipulating information + // stracollision::TotalFV0AmplitudeA, + // stracollision::TotalFT0AmplitudeA, + // stracollision::TotalFT0AmplitudeC, + // stracollision::TotalFDDAmplitudeA, + // stracollision::TotalFDDAmplitudeC, + // stracollision::EnergyCommonZNA, + // stracollision::EnergyCommonZNC, + stracollision::IsUPC); + +DECLARE_SOA_TABLE_VERSIONED(StraEvSels_005, "AOD", "STRAEVSELS", 5, //! debug information + evsel::Sel8, evsel::Selection, //! event selection: sel8 + mult::MultFT0A, mult::MultFT0C, mult::MultFV0A, // FIT detectors + mult::MultFDDA, mult::MultFDDC, + mult::MultNTracksPVeta1, // track multiplicities with eta cut for INEL>0 + mult::MultPVTotalContributors, // number of PV contribs total + mult::MultNTracksGlobal, // global track multiplicities + mult::MultNTracksITSTPC, // track multiplicities, PV contribs, no eta cut + mult::MultAllTracksTPCOnly, // TPConly track multiplicities, all, no eta cut + mult::MultAllTracksITSTPC, // ITSTPC track multiplicities, all, no eta cut + mult::MultZNA, mult::MultZNC, mult::MultZEM1, // ZDC signals + mult::MultZEM2, mult::MultZPA, mult::MultZPC, + evsel::NumTracksInTimeRange, // add occupancy in specified time interval by a number of tracks from nearby collisions + evsel::SumAmpFT0CInTimeRange, // add occupancy in specified time interval by a sum of FT0C amplitudes from nearby collisions + udcollision::GapSide, // UPC info: 0 for side A, 1 for side C, 2 for both sides, 3 neither A or C, 4 not enough or too many pv contributors + udcollision::TotalFT0AmplitudeA, // UPC info: re-assigned FT0-A amplitude, in case of SG event, from the most active bc + udcollision::TotalFT0AmplitudeC, // UPC info: re-assigned FT0-C amplitude, in case of SG event, from the most active bc + udcollision::TotalFV0AmplitudeA, // UPC info: re-assigned FV0-A amplitude, in case of SG event, from the most active bc + udcollision::TotalFDDAmplitudeA, // UPC info: re-assigned FDD-A amplitude, in case of SG event, from the most active bc + udcollision::TotalFDDAmplitudeC, // UPC info: re-assigned FDD-C amplitude, in case of SG event, from the most active bc + udzdc::EnergyCommonZNA, // UPC info: re-assigned ZN-A amplitude, in case of SG event, from the most active bc + udzdc::EnergyCommonZNC, // UPC info: re-assigned ZN-C amplitude, in case of SG event, from the most active bc + + collision::Flags, // Contains Vertex::Flags, with most notably the UPCMode to know whether the vertex has been found using UPC settings + evsel::Alias, // trigger aliases (e.g. kTVXinTRD for v2) + evsel::Rct, // Bitmask of RCT flags + + // Dynamic columns for manipulating information + // stracollision::TotalFV0AmplitudeA, + // stracollision::TotalFT0AmplitudeA, + // stracollision::TotalFT0AmplitudeC, + // stracollision::TotalFDDAmplitudeA, + // stracollision::TotalFDDAmplitudeC, + // stracollision::EnergyCommonZNA, + // stracollision::EnergyCommonZNC, + stracollision::IsUPC); + +DECLARE_SOA_TABLE(StraEvSelsRun2, "AOD", "STRAEVSELSRUN2", //! debug information + evsel::Sel8, evsel::Sel7, evsel::Selection, //! event selection: sel8 + mult::MultFT0A, mult::MultFT0C, // FIT detectors + mult::MultFV0A, mult::MultFV0C, + mult::MultFDDA, mult::MultFDDC, + run2::SPDClustersL0, run2::SPDClustersL1, // SPD detectors + mult::MultNTracksPVeta1, // track multiplicities with eta cut for INEL>0 + mult::MultTracklets, // multiplicity with tracklets (only Run2) + mult::MultPVTotalContributors, // number of PV contribs total + mult::MultNTracksGlobal, // global track multiplicities + mult::MultNTracksITSTPC, // track multiplicities, PV contribs, no eta cut + mult::MultAllTracksTPCOnly, // TPConly track multiplicities, all, no eta cut + mult::MultAllTracksITSTPC, // ITSTPC track multiplicities, all, no eta cut + mult::MultZNA, mult::MultZNC, mult::MultZEM1, // ZDC signals + mult::MultZEM2, mult::MultZPA, mult::MultZPC, + evsel::Alias); // trigger aliases (e.g. kTVXinTRD for v2) + DECLARE_SOA_TABLE(StraFT0AQVs, "AOD", "STRAFT0AQVS", //! t0a Qvec qvec::QvecFT0ARe, qvec::QvecFT0AIm, qvec::SumAmplFT0A); DECLARE_SOA_TABLE(StraFT0CQVs, "AOD", "STRAFT0CQVS", //! t0c Qvec @@ -67,33 +288,69 @@ DECLARE_SOA_TABLE(StraFT0MQVs, "AOD", "STRAFT0MQVS", //! t0m Qvec qvec::QvecFT0MRe, qvec::QvecFT0MIm, qvec::SumAmplFT0M); DECLARE_SOA_TABLE(StraFV0AQVs, "AOD", "STRAFV0AQVS", //! v0a Qvec qvec::QvecFV0ARe, qvec::QvecFV0AIm, qvec::SumAmplFV0A); -DECLARE_SOA_TABLE(StraStamps, "AOD", "STRASTAMPS", //! information for ID-ing mag field if needed +DECLARE_SOA_TABLE(StraTPCQVs, "AOD", "STRATPCQVS", //! tpc Qvec + qvec::QvecBNegRe, qvec::QvecBNegIm, epcalibrationtable::QTPCL, + qvec::QvecBPosRe, qvec::QvecBPosIm, epcalibrationtable::QTPCR); +DECLARE_SOA_TABLE(StraFT0CQVsEv, "AOD", "STRAFT0CQVSEv", //! events used to compute t0c Qvec + epcalibrationtable::TriggerEventEP); +DECLARE_SOA_TABLE(StraZDCSP, "AOD", "STRAZDCSP", //! ZDC SP information + spcalibrationtable::TriggerEventSP, + spcalibrationtable::PsiZDCA, spcalibrationtable::PsiZDCC, spcalibrationtable::QXZDCA, spcalibrationtable::QXZDCC, spcalibrationtable::QYZDCA, spcalibrationtable::QYZDCC); +DECLARE_SOA_TABLE(StraStamps_000, "AOD", "STRASTAMPS", //! information for ID-ing mag field if needed bc::RunNumber, timestamp::Timestamp); +DECLARE_SOA_TABLE_VERSIONED(StraStamps_001, "AOD", "STRASTAMPS", 1, //! information for ID-ing mag field if needed + bc::RunNumber, timestamp::Timestamp, bc::GlobalBC); -using StraRawCents = StraRawCents_003; +using StraRawCents = StraRawCents_004; +using StraCents = StraCents_001; +using StraEvSels = StraEvSels_005; +using StraStamps = StraStamps_001; using StraCollision = StraCollisions::iterator; -using StraCent = StraCents::iterator; +using StraCent = StraCents_001::iterator; + +namespace stramccollision +{ +DECLARE_SOA_COLUMN(TotalMultMCParticles, totalMultMCParticles, int); //! total number of MC particles in a generated collision +} // namespace stramccollision //______________________________________________________ // for correlating information with MC // also allows for collision association cross-checks -DECLARE_SOA_TABLE(StraMCCollisions, "AOD", "STRAMCCOLLISION", //! MC collision properties +DECLARE_SOA_TABLE(StraMCCollisions_000, "AOD", "STRAMCCOLLISION", //! MC collision properties o2::soa::Index<>, mccollision::PosX, mccollision::PosY, mccollision::PosZ, mccollision::ImpactParameter); -DECLARE_SOA_TABLE(StraMCCollMults, "AOD", "STRAMCCOLLMULTS", //! MC collision multiplicities +DECLARE_SOA_TABLE_VERSIONED(StraMCCollisions_001, "AOD", "STRAMCCOLLISION", 1, //! debug information + o2::soa::Index<>, mccollision::PosX, mccollision::PosY, mccollision::PosZ, + mccollision::ImpactParameter, mccollision::EventPlaneAngle); +DECLARE_SOA_TABLE_VERSIONED(StraMCCollisions_002, "AOD", "STRAMCCOLLISION", 2, //! debug information + o2::soa::Index<>, mccollision::PosX, mccollision::PosY, mccollision::PosZ, + mccollision::ImpactParameter, mccollision::EventPlaneAngle, mccollision::GeneratorsID); +using StraMCCollisions = StraMCCollisions_002; +using StraMCCollision = StraMCCollisions::iterator; + +DECLARE_SOA_TABLE(StraMCCollMults_000, "AOD", "STRAMCCOLLMULTS", //! MC collision multiplicities mult::MultMCFT0A, mult::MultMCFT0C, mult::MultMCNParticlesEta05, mult::MultMCNParticlesEta08, mult::MultMCNParticlesEta10, o2::soa::Marker<2>); +DECLARE_SOA_TABLE_VERSIONED(StraMCCollMults_001, "AOD", "STRAMCCOLLMULTS", 1, //! MC collision multiplicities + mult::MultMCFT0A, mult::MultMCFT0C, mult::MultMCNParticlesEta05, mult::MultMCNParticlesEta08, mult::MultMCNParticlesEta10, stramccollision::TotalMultMCParticles); -using StraMCCollision = StraMCCollisions::iterator; +using StraMCCollMults = StraMCCollMults_001; namespace dautrack { //______________________________________________________ // Daughter track declarations for derived data analysis +// These definitions are for the first version of the table +// The latest version will inherit most properties from TracksExtra +DECLARE_SOA_COLUMN(ITSChi2PerNcl, itsChi2PerNcl, float); //! ITS chi2 per N cluster DECLARE_SOA_COLUMN(DetectorMap, detectorMap, uint8_t); //! detector map for reference (see DetectorMapEnum) DECLARE_SOA_COLUMN(ITSClusterSizes, itsClusterSizes, uint32_t); //! ITS cluster sizes per layer DECLARE_SOA_COLUMN(TPCClusters, tpcClusters, uint8_t); //! N TPC clusters DECLARE_SOA_COLUMN(TPCCrossedRows, tpcCrossedRows, uint8_t); //! N TPC clusters +//______________________________________________________ +// Daughter track MC information +DECLARE_SOA_COLUMN(ParticleMCId, particleMCId, int); //! particle MC Id + //______________________________________________________ // for extras: replicated here to ensure ease of manipulating the ITS information // directly from the V0 extras table in simple ways for derived data as well @@ -124,9 +381,25 @@ DECLARE_SOA_DYNAMIC_COLUMN(HasTRD, hasTRD, //! Flag to check if track has a TRD [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TRD; }); DECLARE_SOA_DYNAMIC_COLUMN(HasTOF, hasTOF, //! Flag to check if track has a TOF measurement [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TOF; }); +DECLARE_SOA_DYNAMIC_COLUMN(HasITSTracker, hasITSTracker, //! Flag to check if track is from ITS tracker + [](uint8_t detectorMap, float itsChi2PerNcl) -> bool { return (detectorMap & o2::aod::track::ITS) ? (itsChi2PerNcl > -1e-3f) : false; }); +DECLARE_SOA_DYNAMIC_COLUMN(HasITSAfterburner, hasITSAfterburner, //! Flag to check if track is from ITS AB + [](uint8_t detectorMap, float itsChi2PerNcl) -> bool { return (detectorMap & o2::aod::track::ITS) ? (itsChi2PerNcl < -1e-3f) : false; }); + +// sub-namespace for compatibility purposes +namespace compatibility +{ // adds dynamics that ensure full backwards compatibility with previous getters +DECLARE_SOA_DYNAMIC_COLUMN(TPCClusters, tpcClusters, //! number of TPC clusters + [](uint8_t tpcNClsFindable, int8_t tpcNClsFindableMinusFound) -> int16_t { return (int16_t)tpcNClsFindable - tpcNClsFindableMinusFound; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCCrossedRows, tpcCrossedRows, //! Number of crossed TPC Rows + [](uint8_t tpcNClsFindable, int8_t TPCNClsFindableMinusCrossedRows) -> int16_t { return (int16_t)tpcNClsFindable - TPCNClsFindableMinusCrossedRows; }); +DECLARE_SOA_DYNAMIC_COLUMN(ITSChi2PerNcl, itsChi2PerNcl, //! simple equivalent return + [](float itsChi2NCl) -> float { return (float)itsChi2NCl; }); +} // namespace compatibility + } // namespace dautrack -DECLARE_SOA_TABLE(DauTrackExtras, "AOD", "DAUTRACKEXTRA", //! detector properties of decay daughters +DECLARE_SOA_TABLE(DauTrackExtras_000, "AOD", "DAUTRACKEXTRA", //! detector properties of decay daughters dautrack::DetectorMap, dautrack::ITSClusterSizes, dautrack::TPCClusters, dautrack::TPCCrossedRows, @@ -136,8 +409,96 @@ DECLARE_SOA_TABLE(DauTrackExtras, "AOD", "DAUTRACKEXTRA", //! detector propertie dautrack::HasITS, dautrack::HasTPC, dautrack::HasTRD, - dautrack::HasTOF); - + dautrack::HasTOF, + dautrack::HasITSTracker, + dautrack::HasITSAfterburner); + +DECLARE_SOA_TABLE_VERSIONED(DauTrackExtras_001, "AOD", "DAUTRACKEXTRA", 1, //! detector properties of decay daughters + dautrack::ITSChi2PerNcl, + dautrack::DetectorMap, dautrack::ITSClusterSizes, + dautrack::TPCClusters, dautrack::TPCCrossedRows, + + // Dynamic columns for manipulating information + dautrack::ITSClusterMap, + dautrack::ITSNCls, + dautrack::HasITS, + dautrack::HasTPC, + dautrack::HasTRD, + dautrack::HasTOF, + dautrack::HasITSTracker, + dautrack::HasITSAfterburner); + +DECLARE_SOA_TABLE_VERSIONED(DauTrackExtras_002, "AOD", "DAUTRACKEXTRA", 2, //! detector properties of decay daughters + track::ITSChi2NCl, + dautrack::DetectorMap, // here we don´t save everything so we simplify this + track::ITSClusterSizes, + track::TPCNClsFindable, + track::TPCNClsFindableMinusFound, + track::TPCNClsFindableMinusCrossedRows, + + // Dynamics for ITS matching TracksExtra + track::v001::ITSNClsInnerBarrel, + track::v001::ITSClsSizeInLayer, + track::v001::ITSClusterMap, + track::v001::ITSNCls, + track::v001::IsITSAfterburner, + /*compatibility*/ dautrack::HasITSTracker, + /*compatibility*/ dautrack::HasITSAfterburner, + + // dynamics for TPC tracking properties matching main data model + track::TPCCrossedRowsOverFindableCls, + track::TPCFoundOverFindableCls, + track::TPCNClsFound, + track::TPCNClsCrossedRows, + /*compatibility*/ dautrack::compatibility::TPCClusters, + /*compatibility*/ dautrack::compatibility::TPCCrossedRows, + /*compatibility*/ dautrack::compatibility::ITSChi2PerNcl, + + // dynamics to identify detectors + dautrack::HasITS, + dautrack::HasTPC, + dautrack::HasTRD, + dautrack::HasTOF); + +DECLARE_SOA_TABLE_VERSIONED(DauTrackExtras_003, "AOD", "DAUTRACKEXTRA", 3, //! detector properties of decay daughters + track::ITSChi2NCl, + track::TPCChi2NCl, + dautrack::DetectorMap, // here we don´t save everything so we simplify this + track::ITSClusterSizes, + track::TPCNClsFindable, + track::TPCNClsFindableMinusFound, + track::TPCNClsFindableMinusCrossedRows, + track::TPCNClsShared, + + // Dynamics for ITS matching TracksExtra + track::v001::ITSNClsInnerBarrel, + track::v001::ITSClsSizeInLayer, + track::v001::ITSClusterMap, + track::v001::ITSNCls, + track::v001::IsITSAfterburner, + /*compatibility*/ dautrack::HasITSTracker, + /*compatibility*/ dautrack::HasITSAfterburner, + + // dynamics for TPC tracking properties matching main data model + track::TPCCrossedRowsOverFindableCls, + track::TPCFoundOverFindableCls, + track::TPCNClsFound, + track::TPCNClsCrossedRows, + track::TPCFractionSharedCls, + /*compatibility*/ dautrack::compatibility::TPCClusters, + /*compatibility*/ dautrack::compatibility::TPCCrossedRows, + /*compatibility*/ dautrack::compatibility::ITSChi2PerNcl, + + // dynamics to identify detectors + dautrack::HasITS, + dautrack::HasTPC, + dautrack::HasTRD, + dautrack::HasTOF); + +DECLARE_SOA_TABLE(DauTrackMCIds, "AOD", "DAUTRACKMCID", // index table when using AO2Ds + dautrack::ParticleMCId); + +using DauTrackExtras = DauTrackExtras_003; using DauTrackExtra = DauTrackExtras::iterator; namespace motherParticle @@ -214,16 +575,16 @@ DECLARE_SOA_COLUMN(DCAV0Daughters, dcaV0daughters, float); //! DCA between V0 da DECLARE_SOA_COLUMN(DCAPosToPV, dcapostopv, float); //! DCA positive prong to PV DECLARE_SOA_COLUMN(DCANegToPV, dcanegtopv, float); //! DCA negative prong to PV DECLARE_SOA_COLUMN(V0CosPA, v0cosPA, float); //! V0 CosPA -DECLARE_SOA_COLUMN(DCAV0ToPV, dcav0topv, float); //! DCA V0 to PV +DECLARE_SOA_COLUMN(DCAV0ToPV, dcav0topv, float); //! DCA V0 to PV (3D) // Type of V0 from the svertexer (photon, regular, from cascade) DECLARE_SOA_COLUMN(V0Type, v0Type, uint8_t); //! type of V0. 0: built solely for cascades (does not pass standard V0 cuts), 1: standard 2, 3: photon-like with TPC-only use. Regular analysis should always use type 1. // Saved from finding: covariance matrix of parent track (on request) -DECLARE_SOA_COLUMN(PositionCovMat, positionCovMat, float[6]); //! covariance matrix elements -DECLARE_SOA_COLUMN(MomentumCovMat, momentumCovMat, float[6]); //! covariance matrix elements -DECLARE_SOA_COLUMN(CovMatPosDau, covMatPosDau, float[21]); //! covariance matrix elements positive daughter track -DECLARE_SOA_COLUMN(CovMatNegDau, covMatNegDau, float[21]); //! covariance matrix elements negative daughter track +DECLARE_SOA_COLUMN(PositionCovMat, positionCovMat, float[6]); //! covariance matrix elements +DECLARE_SOA_COLUMN(MomentumCovMat, momentumCovMat, float[6]); //! covariance matrix elements +DECLARE_SOA_COLUMN(CovMatPosDau, covMatPosDau, float[21]); //! covariance matrix elements positive daughter track +DECLARE_SOA_COLUMN(CovMatNegDau, covMatNegDau, float[21]); //! covariance matrix elements negative daughter track DECLARE_SOA_COLUMN(CovMatPosDauIU, covMatPosDauIU, float[21]); //! covariance matrix elements positive daughter track DECLARE_SOA_COLUMN(CovMatNegDauIU, covMatNegDauIU, float[21]); //! covariance matrix elements negative daughter track @@ -232,6 +593,7 @@ DECLARE_SOA_COLUMN(KFV0Chi2, kfV0Chi2, float); //! //______________________________________________________ // REGULAR COLUMNS FOR V0MCCORES +DECLARE_SOA_COLUMN(ParticleIdMC, particleIdMC, int); //! V0 Particle ID DECLARE_SOA_COLUMN(PDGCode, pdgCode, int); //! V0 PDG Code DECLARE_SOA_COLUMN(PDGCodeMother, pdgCodeMother, int); //! V0 mother PDG code (for feeddown) DECLARE_SOA_COLUMN(PDGCodePositive, pdgCodePositive, int); //! V0 positive prong PDG code @@ -246,6 +608,9 @@ DECLARE_SOA_COLUMN(PzPosMC, pzPosMC, float); //! V0 positive DECLARE_SOA_COLUMN(PxNegMC, pxNegMC, float); //! V0 positive daughter px (GeV/c) DECLARE_SOA_COLUMN(PyNegMC, pyNegMC, float); //! V0 positive daughter py (GeV/c) DECLARE_SOA_COLUMN(PzNegMC, pzNegMC, float); //! V0 positive daughter pz (GeV/c) +DECLARE_SOA_COLUMN(PxMC, pxMC, float); //! V0 px (GeV/c) +DECLARE_SOA_COLUMN(PyMC, pyMC, float); //! V0 py (GeV/c) +DECLARE_SOA_COLUMN(PzMC, pzMC, float); //! V0 pz (GeV/c) //______________________________________________________ // Binned content for generated particles: derived data @@ -416,6 +781,22 @@ DECLARE_SOA_DYNAMIC_COLUMN(IsPhotonTPConly, isPhotonTPConly, //! is tpc-only pho [](uint8_t V0Type) -> bool { return V0Type & (1 << 1); }); DECLARE_SOA_DYNAMIC_COLUMN(IsCollinear, isCollinear, //! is collinear V0 [](uint8_t V0Type) -> bool { return V0Type & (1 << 2); }); + +DECLARE_SOA_DYNAMIC_COLUMN(RapidityMC, rapidityMC, //! rapidity (0:K0, 1:L, 2:Lbar) + [](float PxMC, float PyMC, float PzMC, int value) -> float { + if (value == 0) + return RecoDecay::y(std::array{PxMC, PyMC, PzMC}, o2::constants::physics::MassKaonNeutral); + if (value == 1 || value == 2) + return RecoDecay::y(std::array{PxMC, PyMC, PzMC}, o2::constants::physics::MassLambda); + return 0.0f; + }); + +DECLARE_SOA_DYNAMIC_COLUMN(NegativePtMC, negativeptMC, //! negative daughter pT + [](float pxnegMC, float pynegMC) -> float { return RecoDecay::sqrtSumOfSquares(pxnegMC, pynegMC); }); +DECLARE_SOA_DYNAMIC_COLUMN(PositivePtMC, positiveptMC, //! positive daughter pT + [](float pxposMC, float pyposMC) -> float { return RecoDecay::sqrtSumOfSquares(pxposMC, pyposMC); }); +DECLARE_SOA_DYNAMIC_COLUMN(PtMC, ptMC, //! V0 pT + [](float pxMC, float pyMC) -> float { return RecoDecay::sqrtSumOfSquares(pxMC, pyMC); }); } // namespace v0data DECLARE_SOA_TABLE(V0Indices, "AOD", "V0INDEX", //! index table when using AO2Ds @@ -424,59 +805,63 @@ DECLARE_SOA_TABLE(V0Indices, "AOD", "V0INDEX", //! index table when using AO2Ds DECLARE_SOA_TABLE(V0CollRefs, "AOD", "V0COLLREF", //! optional table to refer back to a collision o2::soa::Index<>, v0data::StraCollisionId); -DECLARE_SOA_TABLE(V0Extras, "AOD", "V0EXTRA", //! optional table to refer to custom track extras - o2::soa::Index<>, v0data::PosTrackExtraId, v0data::NegTrackExtraId); +DECLARE_SOA_TABLE_STAGED(V0Extras, "V0EXTRA", //! optional table to refer to custom track extras + o2::soa::Index<>, v0data::PosTrackExtraId, v0data::NegTrackExtraId); DECLARE_SOA_TABLE(V0TrackXs, "AOD", "V0TRACKX", //! track X positions at minima when using AO2Ds v0data::PosX, v0data::NegX, o2::soa::Marker<1>); -DECLARE_SOA_TABLE_FULL(StoredV0Cores, "V0Cores", "AOD", "V0CORE", //! core information about decay, viable with AO2Ds or derived - v0data::X, v0data::Y, v0data::Z, - v0data::PxPos, v0data::PyPos, v0data::PzPos, - v0data::PxNeg, v0data::PyNeg, v0data::PzNeg, - v0data::DCAV0Daughters, v0data::DCAPosToPV, v0data::DCANegToPV, - v0data::V0CosPA, v0data::DCAV0ToPV, v0data::V0Type, - - // Dynamic columns - v0data::PtHypertriton, - v0data::PtAntiHypertriton, - v0data::V0Radius, - v0data::DistOverTotMom, - v0data::Alpha, - v0data::QtArm, - v0data::PsiPair, - v0data::PFracPos, - v0data::PFracNeg, // 24 - - // Invariant masses - v0data::MLambda, - v0data::MAntiLambda, - v0data::MK0Short, - v0data::MGamma, - v0data::MHypertriton, - v0data::MAntiHypertriton, - v0data::M, - - // Longitudinal - v0data::YK0Short, - v0data::YLambda, - v0data::YHypertriton, - v0data::YAntiHypertriton, - v0data::Rapidity, - v0data::NegativePt, - v0data::PositivePt, - v0data::NegativeEta, - v0data::NegativePhi, - v0data::PositiveEta, - v0data::PositivePhi, - v0data::IsStandardV0, - v0data::IsPhotonTPConly, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(V0CoresBase, "V0CORE", //! core information about decay, viable with AO2Ds or derived + o2::soa::Index<>, + v0data::X, v0data::Y, v0data::Z, + v0data::PxPos, v0data::PyPos, v0data::PzPos, + v0data::PxNeg, v0data::PyNeg, v0data::PzNeg, + v0data::DCAV0Daughters, v0data::DCAPosToPV, v0data::DCANegToPV, + v0data::V0CosPA, v0data::DCAV0ToPV, v0data::V0Type, + + // Dynamic columns + v0data::PtHypertriton, + v0data::PtAntiHypertriton, + v0data::V0Radius, + v0data::DistOverTotMom, + v0data::Alpha, + v0data::QtArm, + v0data::PsiPair, + v0data::PFracPos, + v0data::PFracNeg, // 24 + + // Invariant masses + v0data::MLambda, + v0data::MAntiLambda, + v0data::MK0Short, + v0data::MGamma, + v0data::MHypertriton, + v0data::MAntiHypertriton, + v0data::M, + + // Longitudinal + v0data::YK0Short, + v0data::YLambda, + v0data::YHypertriton, + v0data::YAntiHypertriton, + v0data::Rapidity, + v0data::NegativePt, + v0data::PositivePt, + v0data::NegativeEta, + v0data::NegativePhi, + v0data::PositiveEta, + v0data::PositivePhi, + v0data::IsStandardV0, + v0data::IsPhotonTPConly); // extended table with expression columns that can be used as arguments of dynamic columns -DECLARE_SOA_EXTENDED_TABLE_USER(V0Cores, StoredV0Cores, "V0COREEXT", //! +DECLARE_SOA_EXTENDED_TABLE_USER(V0Cores, V0CoresBase, "V0COREEXT", //! v0data::Px, v0data::Py, v0data::Pz, v0data::Pt, v0data::P, v0data::Phi, v0data::Eta); // the table name has here to be the one with EXT which is not nice and under study +// // extended table with expression columns that can be used as arguments of dynamic columns +// DECLARE_SOA_EXTENDED_TABLE_USER(StoredV0Cores, StoredV0CoresBase, "V0COREEXT", //! +// v0data::Px, v0data::Py, v0data::Pz, v0data::Pt, v0data::P, v0data::Phi, v0data::Eta, o2::soa::Marker<2>); // the table name has here to be the one with EXT which is not nice and under study + DECLARE_SOA_TABLE(V0TraPosAtDCAs, "AOD", "V0TRAPOSATDCAs", //! positions of tracks at their DCA for debug v0data::XPosAtDCA, v0data::YPosAtDCA, v0data::ZPosAtDCA, v0data::XNegAtDCA, v0data::YNegAtDCA, v0data::ZNegAtDCA); @@ -551,12 +936,60 @@ DECLARE_SOA_EXTENDED_TABLE_USER(V0fCCores, StoredV0fCCores, "V0FCCOREEXT", DECLARE_SOA_TABLE_FULL(V0fCCovs, "V0fCCovs", "AOD", "V0FCCOVS", //! V0 covariance matrices v0data::PositionCovMat, v0data::MomentumCovMat, o2::soa::Marker<2>); -DECLARE_SOA_TABLE(V0MCCores, "AOD", "V0MCCORE", //! MC properties of the V0 for posterior analysis - v0data::PDGCode, v0data::PDGCodeMother, - v0data::PDGCodePositive, v0data::PDGCodeNegative, - v0data::IsPhysicalPrimary, v0data::XMC, v0data::YMC, v0data::ZMC, - v0data::PxPosMC, v0data::PyPosMC, v0data::PzPosMC, - v0data::PxNegMC, v0data::PyNegMC, v0data::PzNegMC); +DECLARE_SOA_TABLE_STAGED(V0MCCores_000, "V0MCCORE", //! MC properties of the V0 for posterior analysis + v0data::PDGCode, v0data::PDGCodeMother, + v0data::PDGCodePositive, v0data::PDGCodeNegative, + v0data::IsPhysicalPrimary, v0data::XMC, v0data::YMC, v0data::ZMC, + v0data::PxPosMC, v0data::PyPosMC, v0data::PzPosMC, + v0data::PxNegMC, v0data::PyNegMC, v0data::PzNegMC); + +DECLARE_SOA_TABLE_STAGED_VERSIONED(V0MCCores_001, "V0MCCORE", 1, //! debug information + v0data::ParticleIdMC, //! MC properties of the V0 for posterior analysis + v0data::PDGCode, v0data::PDGCodeMother, + v0data::PDGCodePositive, v0data::PDGCodeNegative, + v0data::IsPhysicalPrimary, v0data::XMC, v0data::YMC, v0data::ZMC, + v0data::PxPosMC, v0data::PyPosMC, v0data::PzPosMC, + v0data::PxNegMC, v0data::PyNegMC, v0data::PzNegMC); + +DECLARE_SOA_TABLE_STAGED_VERSIONED(V0MCCores_002, "V0MCCORE", 2, //! debug information + v0data::ParticleIdMC, //! MC properties of the V0 for posterior analysis + v0data::PDGCode, v0data::PDGCodeMother, + v0data::PDGCodePositive, v0data::PDGCodeNegative, + v0data::IsPhysicalPrimary, v0data::XMC, v0data::YMC, v0data::ZMC, + v0data::PxPosMC, v0data::PyPosMC, v0data::PzPosMC, + v0data::PxNegMC, v0data::PyNegMC, v0data::PzNegMC, + v0data::PxMC, v0data::PyMC, v0data::PzMC, + v0data::RapidityMC, + v0data::NegativePtMC, + v0data::PositivePtMC, + v0data::PtMC); + +// DECLARE_SOA_TABLE(StoredV0MCCores_000, "AOD", "V0MCCORE", //! MC properties of the V0 for posterior analysis +// v0data::PDGCode, v0data::PDGCodeMother, +// v0data::PDGCodePositive, v0data::PDGCodeNegative, +// v0data::IsPhysicalPrimary, v0data::XMC, v0data::YMC, v0data::ZMC, +// v0data::PxPosMC, v0data::PyPosMC, v0data::PzPosMC, +// v0data::PxNegMC, v0data::PyNegMC, v0data::PzNegMC, +// o2::soa::Marker<1>); + +// DECLARE_SOA_TABLE_VERSIONED(StoredV0MCCores_001, "AOD", "V0MCCORE", 1, //! debug information +// v0data::ParticleIdMC, //! MC properties of the V0 for posterior analysis +// v0data::PDGCode, v0data::PDGCodeMother, +// v0data::PDGCodePositive, v0data::PDGCodeNegative, +// v0data::IsPhysicalPrimary, v0data::XMC, v0data::YMC, v0data::ZMC, +// v0data::PxPosMC, v0data::PyPosMC, v0data::PzPosMC, +// v0data::PxNegMC, v0data::PyNegMC, v0data::PzNegMC, +// o2::soa::Marker<1>); + +// DECLARE_SOA_TABLE_VERSIONED(StoredV0MCCores_002, "AOD", "V0MCCORE", 2, //! debug information +// v0data::ParticleIdMC, //! MC properties of the V0 for posterior analysis +// v0data::PDGCode, v0data::PDGCodeMother, +// v0data::PDGCodePositive, v0data::PDGCodeNegative, +// v0data::IsPhysicalPrimary, v0data::XMC, v0data::YMC, v0data::ZMC, +// v0data::PxPosMC, v0data::PyPosMC, v0data::PzPosMC, +// v0data::PxNegMC, v0data::PyNegMC, v0data::PzNegMC, +// v0data::PxMC, v0data::PyMC, v0data::PzMC, +// o2::soa::Marker<1>); DECLARE_SOA_TABLE(V0MCCollRefs, "AOD", "V0MCCOLLREF", //! refers MC candidate back to proper MC Collision o2::soa::Index<>, v0data::StraMCCollisionId, o2::soa::Marker<2>); @@ -565,8 +998,11 @@ DECLARE_SOA_TABLE(GeK0Short, "AOD", "GeK0Short", v0data::GeneratedK0Short); DECLARE_SOA_TABLE(GeLambda, "AOD", "GeLambda", v0data::GeneratedLambda); DECLARE_SOA_TABLE(GeAntiLambda, "AOD", "GeAntiLambda", v0data::GeneratedAntiLambda); -DECLARE_SOA_TABLE(V0MCMothers, "AOD", "V0MCMOTHER", //! optional table for MC mothers - o2::soa::Index<>, v0data::MotherMCPartId); +DECLARE_SOA_TABLE_STAGED(V0MCMothers, "V0MCMOTHER", //! optional table for MC mothers + o2::soa::Index<>, v0data::MotherMCPartId); + +using V0MCCores = V0MCCores_002; +using StoredV0MCCores = StoredV0MCCores_002; using V0Index = V0Indices::iterator; using V0Core = V0Cores::iterator; @@ -577,6 +1013,7 @@ using V0fCDatas = soa::Join; using V0fCData = V0fCDatas::iterator; using V0MCDatas = soa::Join; using V0MCData = V0MCDatas::iterator; +using V0MCCore = V0MCCores::iterator; // definitions of indices for interlink tables namespace v0data @@ -584,16 +1021,40 @@ namespace v0data DECLARE_SOA_INDEX_COLUMN(V0Data, v0Data); //! Index to V0Data entry DECLARE_SOA_INDEX_COLUMN(V0fCData, v0fCData); //! Index to V0Data entry DECLARE_SOA_INDEX_COLUMN_FULL(V0MC, v0MC, int, V0MCCores, "_MC"); //! +DECLARE_SOA_INDEX_COLUMN(V0MCCore, v0MCCore); } // namespace v0data DECLARE_SOA_TABLE(V0DataLink, "AOD", "V0DATALINK", //! Joinable table with V0s which links to V0Data which is not produced for all entries o2::soa::Index<>, v0data::V0DataId, v0data::V0fCDataId); DECLARE_SOA_TABLE(V0MCRefs, "AOD", "V0MCREF", //! index table when using AO2Ds o2::soa::Index<>, v0data::V0MCId); +DECLARE_SOA_TABLE(V0CoreMCLabels, "AOD", "V0COREMCLABEL", //! optional table to refer to V0MCCores if not joinable + o2::soa::Index<>, v0data::V0MCCoreId); using V0sLinked = soa::Join; using V0Linked = V0sLinked::iterator; +namespace v0data +{ +DECLARE_SOA_COLUMN(IsFound, isFound, bool); //! is this FindableV0 actually in the V0s table? +} + +// Major bypass for simultaneous found vs findable study +DECLARE_SOA_TABLE(FindableV0s, "AOD", "FindableV0", //! Will store findable + o2::soa::Index<>, v0::CollisionId, + v0::PosTrackId, v0::NegTrackId, + v0::V0Type, + v0::IsStandardV0, + v0::IsPhotonV0, + v0::IsCollinearV0, + o2::soa::Marker<1>); + +DECLARE_SOA_TABLE(V0FoundTags, "AOD", "V0FoundTag", //! found or not? + v0data::IsFound); + +using FindableV0sLinked = soa::Join; +using FindableV0Linked = FindableV0sLinked::iterator; + // helper for building namespace v0tag { @@ -607,6 +1068,7 @@ DECLARE_SOA_COLUMN(IsTrueLambda, isTrueLambda, bool); //! PDG DECLARE_SOA_COLUMN(IsTrueAntiLambda, isTrueAntiLambda, bool); //! PDG checked correctly in MC DECLARE_SOA_COLUMN(IsTrueHypertriton, isTrueHypertriton, bool); //! PDG checked correctly in MC DECLARE_SOA_COLUMN(IsTrueAntiHypertriton, isTrueAntiHypertriton, bool); //! PDG checked correctly in MC +DECLARE_SOA_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, bool); //! physical primary // dE/dx compatibility bools DECLARE_SOA_COLUMN(IsdEdxGamma, isdEdxGamma, bool); //! compatible with dE/dx hypotheses @@ -628,6 +1090,7 @@ DECLARE_SOA_TABLE(V0Tags, "AOD", "V0TAGS", v0tag::IsTrueAntiLambda, v0tag::IsTrueHypertriton, v0tag::IsTrueAntiHypertriton, + v0tag::IsPhysicalPrimary, v0tag::IsdEdxGamma, v0tag::IsdEdxK0Short, v0tag::IsdEdxLambda, @@ -705,13 +1168,22 @@ DECLARE_SOA_COLUMN(BachX, bachX, float); //! bachelor track X at min //______________________________________________________ // REGULAR COLUMNS FOR CASCCOVS // Saved from finding: covariance matrix of parent track (on request) -DECLARE_SOA_COLUMN(PositionCovMat, positionCovMat, float[6]); //! covariance matrix elements -DECLARE_SOA_COLUMN(MomentumCovMat, momentumCovMat, float[6]); //! covariance matrix elements +DECLARE_SOA_DYNAMIC_COLUMN(PositionCovMat, positionCovMat, //! for transparent handling + [](const float covMat[21]) -> std::vector { + std::vector posCovMat { covMat[0], covMat[1], covMat[2], covMat[3], covMat[4], covMat[5] }; + return posCovMat; }); +DECLARE_SOA_DYNAMIC_COLUMN(MomentumCovMat, momentumCovMat, //! for transparent handling + [](const float covMat[21]) -> std::vector { + std::vector momCovMat { covMat[9], covMat[13], covMat[14], covMat[18], covMat[19], covMat[20] }; + return momCovMat; }); DECLARE_SOA_COLUMN(KFTrackCovMat, kfTrackCovMat, float[21]); //! covariance matrix elements for KF method (Cascade) DECLARE_SOA_COLUMN(KFTrackCovMatV0, kfTrackCovMatV0, float[21]); //! covariance matrix elements for KF method (V0) DECLARE_SOA_COLUMN(KFTrackCovMatV0DauPos, kfTrackCovMatV0DauPos, float[21]); //! covariance matrix elements for KF method (V0 pos daughter) DECLARE_SOA_COLUMN(KFTrackCovMatV0DauNeg, kfTrackCovMatV0DauNeg, float[21]); //! covariance matrix elements for KF method (V0 neg daughter) +// for CascCovs / TraCascCovs, meant to provide consistent interface everywhere +DECLARE_SOA_COLUMN(CovMat, covMat, float[21]); //! covariance matrix elements + //______________________________________________________ // REGULAR COLUMNS FOR CASCBBS // General cascade properties: position, momentum @@ -792,8 +1264,10 @@ DECLARE_SOA_DYNAMIC_COLUMN(CascRadius, cascradius, //! // CosPAs DECLARE_SOA_DYNAMIC_COLUMN(V0CosPA, v0cosPA, //! [](float Xlambda, float Ylambda, float Zlambda, float PxLambda, float PyLambda, float PzLambda, float pvX, float pvY, float pvZ) -> float { return RecoDecay::cpa(std::array{pvX, pvY, pvZ}, std::array{Xlambda, Ylambda, Zlambda}, std::array{PxLambda, PyLambda, PzLambda}); }); +// DECLARE_SOA_DYNAMIC_COLUMN(CascCosPA, casccosPA, //! +// [](float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) -> float { return RecoDecay::cpa(std::array{pvX, pvY, pvZ}, std::array{X, Y, Z}, std::array{Px, Py, Pz}); }); DECLARE_SOA_DYNAMIC_COLUMN(CascCosPA, casccosPA, //! - [](float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) -> float { return RecoDecay::cpa(std::array{pvX, pvY, pvZ}, std::array{X, Y, Z}, std::array{Px, Py, Pz}); }); + [](float X, float Y, float Z, float PxBach, float PxPos, float PxNeg, float PyBach, float PyPos, float PyNeg, float PzBach, float PzPos, float PzNeg, float pvX, float pvY, float pvZ) -> float { return RecoDecay::cpa(std::array{pvX, pvY, pvZ}, std::array{X, Y, Z}, std::array{PxBach + PxPos + PxNeg, PyBach + PyPos + PyNeg, PzBach + PzPos + PzNeg}); }); DECLARE_SOA_DYNAMIC_COLUMN(DCAV0ToPV, dcav0topv, //! [](float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) -> float { return std::sqrt((std::pow((pvY - Y) * Pz - (pvZ - Z) * Py, 2) + std::pow((pvX - X) * Pz - (pvZ - Z) * Px, 2) + std::pow((pvX - X) * Py - (pvY - Y) * Px, 2)) / (Px * Px + Py * Py + Pz * Pz)); }); @@ -840,6 +1314,24 @@ DECLARE_SOA_DYNAMIC_COLUMN(BachelorEta, bacheloreta, //! bachelor daughter eta [](float PxPos, float PyPos, float PzPos) -> float { return RecoDecay::eta(std::array{PxPos, PyPos, PzPos}); }); DECLARE_SOA_DYNAMIC_COLUMN(BachelorPhi, bachelorphi, //! bachelor daughter phi [](float PxPos, float PyPos) -> float { return RecoDecay::phi(PxPos, PyPos); }); + +DECLARE_SOA_DYNAMIC_COLUMN(RapidityMC, rapidityMC, //! rapidity (0, 1: Xi; 2, 3: Omega) + [](float PxMC, float PyMC, float PzMC, int value) -> float { + if (value == 0 || value == 1) + return RecoDecay::y(std::array{PxMC, PyMC, PzMC}, o2::constants::physics::MassXiMinus); + if (value == 2 || value == 3) + return RecoDecay::y(std::array{PxMC, PyMC, PzMC}, o2::constants::physics::MassOmegaMinus); + return 0.0f; + }); + +DECLARE_SOA_DYNAMIC_COLUMN(NegativePtMC, negativeptMC, //! negative daughter pT + [](float pxNegMC, float pyNegMC) -> float { return RecoDecay::sqrtSumOfSquares(pxNegMC, pyNegMC); }); +DECLARE_SOA_DYNAMIC_COLUMN(PositivePtMC, positiveptMC, //! positive daughter pT + [](float pxPosMC, float pyPosMC) -> float { return RecoDecay::sqrtSumOfSquares(pxPosMC, pyPosMC); }); +DECLARE_SOA_DYNAMIC_COLUMN(BachelorPtMC, bachelorptMC, //! bachelor daughter pT + [](float pxBachMC, float pyBachMC) -> float { return RecoDecay::sqrtSumOfSquares(pxBachMC, pyBachMC); }); +DECLARE_SOA_DYNAMIC_COLUMN(PtMC, ptMC, //! cascade pT + [](float pxMC, float pyMC) -> float { return RecoDecay::sqrtSumOfSquares(pxMC, pyMC); }); } // namespace cascdata //______________________________________________________ @@ -924,7 +1416,7 @@ DECLARE_SOA_TABLE(StoredCascCores, "AOD", "CASCCORE", //! core information about cascdata::V0Radius, cascdata::CascRadius, cascdata::V0CosPA, - cascdata::CascCosPA, + cascdata::CascCosPA, cascdata::DCAV0ToPV, // Invariant masses @@ -967,7 +1459,7 @@ DECLARE_SOA_TABLE(StoredKFCascCores, "AOD", "KFCASCCORE", //! cascdata::V0Radius, cascdata::CascRadius, cascdata::V0CosPA, - cascdata::CascCosPA, + cascdata::CascCosPA, cascdata::DCAV0ToPV, // Invariant masses @@ -1005,7 +1497,7 @@ DECLARE_SOA_TABLE(StoredTraCascCores, "AOD", "TRACASCCORE", //! cascdata::V0Radius, cascdata::CascRadius, cascdata::V0CosPA, - cascdata::CascCosPA, + cascdata::CascCosPA, cascdata::DCAV0ToPV, // Invariant masses @@ -1033,8 +1525,20 @@ DECLARE_SOA_TABLE(CascMCCores, "AOD", "CASCMCCORE", //! bachelor-baryon correlat cascdata::PxPosMC, cascdata::PyPosMC, cascdata::PzPosMC, cascdata::PxNegMC, cascdata::PyNegMC, cascdata::PzNegMC, cascdata::PxBachMC, cascdata::PyBachMC, cascdata::PzBachMC, - cascdata::PxMC, cascdata::PyMC, cascdata::PzMC); + cascdata::PxMC, cascdata::PyMC, cascdata::PzMC, + cascdata::RapidityMC, + cascdata::NegativePtMC, + cascdata::PositivePtMC, + cascdata::BachelorPtMC, + cascdata::PtMC); +namespace cascdata +{ +DECLARE_SOA_INDEX_COLUMN(CascMCCore, cascMCCore); //! Index to CascMCCore entry +} + +DECLARE_SOA_TABLE(CascCoreMCLabels, "AOD", "CASCCOREMCLABEL", //! optional table to refer to CascMCCores if not joinable + o2::soa::Index<>, cascdata::CascMCCoreId); DECLARE_SOA_TABLE(CascMCCollRefs, "AOD", "CASCMCCOLLREF", //! refers MC candidate back to proper MC Collision o2::soa::Index<>, cascdata::StraMCCollisionId, o2::soa::Marker<3>); @@ -1049,11 +1553,20 @@ DECLARE_SOA_TABLE(CascMCMothers, "AOD", "CASCMCMOTHER", //! optional table for M DECLARE_SOA_TABLE(CascBBs, "AOD", "CASCBB", //! bachelor-baryon correlation variables cascdata::BachBaryonCosPA, cascdata::BachBaryonDCAxyToPV) -DECLARE_SOA_TABLE_FULL(CascCovs, "CascCovs", "AOD", "CASCCOVS", //! - cascdata::PositionCovMat, cascdata::MomentumCovMat); +DECLARE_SOA_TABLE(CascCovs, "AOD", "CASCCOVS", //! + cascdata::CovMat, + cascdata::PositionCovMat, + cascdata::MomentumCovMat, + o2::soa::Marker<1>); + +DECLARE_SOA_TABLE(KFCascCovs, "AOD", "KFCASCCOVS", //! + cascdata::KFTrackCovMat, cascdata::KFTrackCovMatV0, cascdata::KFTrackCovMatV0DauPos, cascdata::KFTrackCovMatV0DauNeg); -DECLARE_SOA_TABLE_FULL(KFCascCovs, "KFCascCovs", "AOD", "KFCASCCOVS", //! - cascdata::KFTrackCovMat, cascdata::KFTrackCovMatV0, cascdata::KFTrackCovMatV0DauPos, cascdata::KFTrackCovMatV0DauNeg); +DECLARE_SOA_TABLE(TraCascCovs, "AOD", "TRACASCCOVS", //! + cascdata::CovMat, + cascdata::PositionCovMat, + cascdata::MomentumCovMat, + o2::soa::Marker<2>); // extended table with expression columns that can be used as arguments of dynamic columns DECLARE_SOA_EXTENDED_TABLE_USER(CascCores, StoredCascCores, "CascDATAEXT", //! @@ -1129,16 +1642,34 @@ using CascadesLinked = soa::Join; using CascadeLinked = CascadesLinked::iterator; using KFCascadesLinked = soa::Join; using KFCascadeLinked = KFCascadesLinked::iterator; +using TraCascadesLinked = soa::Join; +using TraCascadeLinked = TraCascadesLinked::iterator; + +namespace cascdata +{ +DECLARE_SOA_INDEX_COLUMN(FindableV0, findableV0); //! V0 index +DECLARE_SOA_COLUMN(IsFound, isFound, bool); //! is this FindableCascade actually in the Cascades table? +} // namespace cascdata + +DECLARE_SOA_TABLE(FindableCascades, "AOD", "FINDABLECASCS", //! Run 3 cascade table + o2::soa::Index<>, cascade::CollisionId, cascdata::FindableV0Id, cascade::BachelorId, o2::soa::Marker<1>); + +DECLARE_SOA_TABLE(CascFoundTags, "AOD", "CascFoundTag", //! found or not? + cascdata::IsFound); + +using FindableCascadesLinked = soa::Join; +using FindableCascadeLinked = FindableCascadesLinked::iterator; namespace casctag { DECLARE_SOA_COLUMN(IsInteresting, isInteresting, bool); //! will this be built or not? // MC association bools -DECLARE_SOA_COLUMN(IsTrueXiMinus, isTrueXiMinus, bool); //! PDG checked correctly in MC -DECLARE_SOA_COLUMN(IsTrueXiPlus, isTrueXiPlus, bool); //! PDG checked correctly in MC -DECLARE_SOA_COLUMN(IsTrueOmegaMinus, isTrueOmegaMinus, bool); //! PDG checked correctly in MC -DECLARE_SOA_COLUMN(IsTrueOmegaPlus, isTrueOmegaPlus, bool); //! PDG checked correctly in MC +DECLARE_SOA_COLUMN(IsTrueXiMinus, isTrueXiMinus, bool); //! PDG checked correctly in MC +DECLARE_SOA_COLUMN(IsTrueXiPlus, isTrueXiPlus, bool); //! PDG checked correctly in MC +DECLARE_SOA_COLUMN(IsTrueOmegaMinus, isTrueOmegaMinus, bool); //! PDG checked correctly in MC +DECLARE_SOA_COLUMN(IsTrueOmegaPlus, isTrueOmegaPlus, bool); //! PDG checked correctly in MC +DECLARE_SOA_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, bool); //! physical primary // dE/dx compatibility bools DECLARE_SOA_COLUMN(IsdEdxXiMinus, isdEdxXiMinus, bool); //! compatible with dE/dx hypotheses @@ -1152,6 +1683,7 @@ DECLARE_SOA_TABLE(CascTags, "AOD", "CASCTAGS", casctag::IsTrueXiPlus, casctag::IsTrueOmegaMinus, casctag::IsTrueOmegaPlus, + casctag::IsPhysicalPrimary, casctag::IsdEdxXiMinus, casctag::IsdEdxXiPlus, casctag::IsdEdxOmegaMinus, @@ -1230,6 +1762,38 @@ DECLARE_SOA_TABLE(Tracked3BodyColls, "AOD", "TRA3BODYCOLL", //! Table joinable w using Tracked3BodyColl = Tracked3BodyColls::iterator; using AssignedTracked3Bodys = soa::Join; using AssignedTracked3Body = AssignedTracked3Bodys::iterator; + +namespace zdcneutrons +{ +// FOR DERIVED +DECLARE_SOA_INDEX_COLUMN(StraMCCollision, straMCCollision); //! +// DYNAMIC COLUMNS +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! neutron transverse momentum (GeV/c) + [](float px, float py) -> float { return RecoDecay::sqrtSumOfSquares(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! neutron total momentum (GeV/c) + [](float px, float py, float pz) -> float { return RecoDecay::sqrtSumOfSquares(px, py, pz); }); +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, //! neutron phi in the range [0, 2pi) + [](float px, float py) -> float { return RecoDecay::phi(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, //! neutron pseudorapidity + [](float px, float py, float pz) -> float { return RecoDecay::eta(std::array{px, py, pz}); }); +DECLARE_SOA_DYNAMIC_COLUMN(Y, y, //! neutron rapidity + [](float pz, float e) -> float { return std::atanh(pz / e); }); +} // namespace zdcneutrons + +DECLARE_SOA_TABLE(ZDCNeutrons, "AOD", "ZDCNEUTRON", //! MC properties of the neutrons within ZDC acceptance (for UPC analysis) + mcparticle::PdgCode, mcparticle::StatusCode, mcparticle::Flags, + mcparticle::Vx, mcparticle::Vy, mcparticle::Vz, mcparticle::Vt, + mcparticle::Px, mcparticle::Py, mcparticle::Pz, mcparticle::E, + // Dynamic columns for manipulating information + zdcneutrons::Pt, + zdcneutrons::P, + zdcneutrons::Phi, + zdcneutrons::Eta, + zdcneutrons::Y); + +DECLARE_SOA_TABLE(ZDCNMCCollRefs, "AOD", "ZDCNMCCOLLREF", //! refers MC candidate back to proper MC Collision + o2::soa::Index<>, zdcneutrons::StraMCCollisionId, o2::soa::Marker<4>); + } // namespace o2::aod //______________________________________________________ diff --git a/PWGLF/DataModel/LFhe3HadronTables.h b/PWGLF/DataModel/LFhe3HadronTables.h new file mode 100644 index 00000000000..9074fb8b20c --- /dev/null +++ b/PWGLF/DataModel/LFhe3HadronTables.h @@ -0,0 +1,128 @@ +// 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 LFhe3HadronTables.h +/// \brief Slim tables for he3Hadron +/// + +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#ifndef PWGLF_DATAMODEL_LFHE3HADRONTABLES_H_ +#define PWGLF_DATAMODEL_LFHE3HADRONTABLES_H_ + +namespace o2::aod +{ +namespace he3HadronTablesNS +{ + +DECLARE_SOA_COLUMN(PtHe3, ptHe3, float); +DECLARE_SOA_COLUMN(EtaHe3, etaHe3, float); +DECLARE_SOA_COLUMN(PhiHe3, phiHe3, float); +DECLARE_SOA_COLUMN(PtHad, ptHad, float); +DECLARE_SOA_COLUMN(EtaHad, etaHad, float); +DECLARE_SOA_COLUMN(PhiHad, phiHad, float); + +DECLARE_SOA_COLUMN(DCAxyHe3, dcaxyHe3, float); +DECLARE_SOA_COLUMN(DCAzHe3, dcazHe3, float); +DECLARE_SOA_COLUMN(DCAxyHad, dcaxyHad, float); +DECLARE_SOA_COLUMN(DCAzHad, dcazHad, float); + +DECLARE_SOA_COLUMN(SignalTPCHe3, signalTPCHe3, float); +DECLARE_SOA_COLUMN(InnerParamTPCHe3, innerParamTPCHe3, float); +DECLARE_SOA_COLUMN(SignalTPCHad, signalTPCHad, float); +DECLARE_SOA_COLUMN(InnerParamTPCHad, innerParamTPCHad, float); +DECLARE_SOA_COLUMN(NClsTPCHe3, nClsTPCHe3, uint8_t); +DECLARE_SOA_COLUMN(NSigmaTPCHe3, nSigmaTPCHe3, float); +DECLARE_SOA_COLUMN(NSigmaTPCHad, nSigmaTOFHad, float); +DECLARE_SOA_COLUMN(Chi2TPCHe3, chi2TPCHe3, float); +DECLARE_SOA_COLUMN(Chi2TPCHad, chi2TPCHad, float); +DECLARE_SOA_COLUMN(MassTOFHe3, massTOFHe3, float); +DECLARE_SOA_COLUMN(MassTOFHad, massTOFHad, float); +DECLARE_SOA_COLUMN(PIDtrkHe3, pidTrkHe3, uint32_t); +DECLARE_SOA_COLUMN(PIDtrkHad, pidTrkHad, uint32_t); + +DECLARE_SOA_COLUMN(ItsClusterSizeHe3, itsClusterSizeHe3, uint32_t); +DECLARE_SOA_COLUMN(ItsClusterSizeHad, itsClusterSizeHad, uint32_t); + +DECLARE_SOA_COLUMN(SharedClustersHe3, sharedClustersHe3, uint8_t); +DECLARE_SOA_COLUMN(SharedClustersHad, sharedClustersHad, uint8_t); + +DECLARE_SOA_COLUMN(IsBkgUS, isBkgUS, bool); +DECLARE_SOA_COLUMN(IsBkgEM, isBkgEM, bool); + +DECLARE_SOA_COLUMN(PtMCHe3, ptMCHe3, float); +DECLARE_SOA_COLUMN(EtaMCHe3, etaMCHe3, float); +DECLARE_SOA_COLUMN(PhiMCHe3, phiMCHe3, float); +DECLARE_SOA_COLUMN(PtMCHad, ptMCHad, float); +DECLARE_SOA_COLUMN(EtaMCHad, etaMCHad, float); +DECLARE_SOA_COLUMN(PhiMCHad, phiMCHad, float); +DECLARE_SOA_COLUMN(SignedPtMC, signedPtMC, float); +DECLARE_SOA_COLUMN(MassMC, massMC, float); + +DECLARE_SOA_COLUMN(CollisionId, collisionId, int64_t); +DECLARE_SOA_COLUMN(ZVertex, zVertex, float); +DECLARE_SOA_COLUMN(Multiplicity, multiplicity, uint16_t); +DECLARE_SOA_COLUMN(CentralityFT0C, centFT0C, float); +DECLARE_SOA_COLUMN(MultiplicityFT0C, multiplicityFT0C, float); + +} // namespace he3HadronTablesNS + +DECLARE_SOA_TABLE(he3HadronTable, "AOD", "HE3HADTABLE", + he3HadronTablesNS::PtHe3, + he3HadronTablesNS::EtaHe3, + he3HadronTablesNS::PhiHe3, + he3HadronTablesNS::PtHad, + he3HadronTablesNS::EtaHad, + he3HadronTablesNS::PhiHad, + he3HadronTablesNS::DCAxyHe3, + he3HadronTablesNS::DCAzHe3, + he3HadronTablesNS::DCAxyHad, + he3HadronTablesNS::DCAzHad, + he3HadronTablesNS::SignalTPCHe3, + he3HadronTablesNS::InnerParamTPCHe3, + he3HadronTablesNS::SignalTPCHad, + he3HadronTablesNS::InnerParamTPCHad, + he3HadronTablesNS::NClsTPCHe3, + he3HadronTablesNS::NSigmaTPCHe3, + he3HadronTablesNS::NSigmaTPCHad, + he3HadronTablesNS::Chi2TPCHe3, + he3HadronTablesNS::Chi2TPCHad, + he3HadronTablesNS::MassTOFHe3, + he3HadronTablesNS::MassTOFHad, + he3HadronTablesNS::PIDtrkHe3, + he3HadronTablesNS::PIDtrkHad, + he3HadronTablesNS::ItsClusterSizeHe3, + he3HadronTablesNS::ItsClusterSizeHad, + he3HadronTablesNS::SharedClustersHe3, + he3HadronTablesNS::SharedClustersHad, + he3HadronTablesNS::IsBkgUS, + he3HadronTablesNS::IsBkgEM) +DECLARE_SOA_TABLE(he3HadronTableMC, "AOD", "HE3HADTABLEMC", + he3HadronTablesNS::PtMCHe3, + he3HadronTablesNS::EtaMCHe3, + he3HadronTablesNS::PhiMCHe3, + he3HadronTablesNS::PtMCHad, + he3HadronTablesNS::EtaMCHad, + he3HadronTablesNS::PhiMCHad, + he3HadronTablesNS::SignedPtMC, + he3HadronTablesNS::MassMC) +DECLARE_SOA_TABLE(he3HadronMult, "AOD", "HE3HADMULT", + he3HadronTablesNS::CollisionId, + he3HadronTablesNS::ZVertex, + he3HadronTablesNS::Multiplicity, + he3HadronTablesNS::CentralityFT0C, + he3HadronTablesNS::MultiplicityFT0C) + +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_LFHE3HADRONTABLES_H_ diff --git a/PWGLF/DataModel/QC/strangenessTablesQC.h b/PWGLF/DataModel/QC/strangenessTablesQC.h index 042fbd3f2be..ccf1724dc4b 100644 --- a/PWGLF/DataModel/QC/strangenessTablesQC.h +++ b/PWGLF/DataModel/QC/strangenessTablesQC.h @@ -13,16 +13,12 @@ /// /// \author Roman Nepeivoda (roman.nepeivoda@cern.ch) -#ifndef PWGLF_DATAMODEL_STRANGENESSTABLESQC_H_ -#define PWGLF_DATAMODEL_STRANGENESSTABLESQC_H_ +#ifndef PWGLF_DATAMODEL_QC_STRANGENESSTABLESQC_H_ +#define PWGLF_DATAMODEL_QC_STRANGENESSTABLESQC_H_ #include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - namespace o2::aod { namespace cascadesQC @@ -116,4 +112,4 @@ DECLARE_SOA_TABLE(VZerosQC, "AOD", "VZEROSQC", o2::soa::Index<>, vZerosQC::PosPhi, vZerosQC::NegPhi); } // namespace o2::aod -#endif // PWGLF_DATAMODEL_STRANGENESSTABLESQC_H_ +#endif // PWGLF_DATAMODEL_QC_STRANGENESSTABLESQC_H_ diff --git a/PWGLF/DataModel/Reduced3BodyTables.h b/PWGLF/DataModel/Reduced3BodyTables.h new file mode 100644 index 00000000000..51fff63c81d --- /dev/null +++ b/PWGLF/DataModel/Reduced3BodyTables.h @@ -0,0 +1,149 @@ +// 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 Reduced3BodyTables.h +/// \brief Definitions of tables for reduced data of 3body decayed hypertriton analysis +/// \author Carolina Reetz +/// \author Yuanzhe Wang + +#ifndef PWGLF_DATAMODEL_REDUCED3BODYTABLES_H_ +#define PWGLF_DATAMODEL_REDUCED3BODYTABLES_H_ + +#include +#include "Framework/AnalysisDataModel.h" +#include "Common/Core/RecoDecay.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "PWGLF/DataModel/Vtx3BodyTables.h" + +namespace o2::aod +{ + +DECLARE_SOA_TABLE(RedCollisions, "AOD", "REDCOLLISION", //! reduced collision table (same structure as the original collision table) + o2::soa::Index<>, + collision::PosX, collision::PosY, collision::PosZ, + collision::CovXX, collision::CovXY, collision::CovYY, collision::CovXZ, collision::CovYZ, collision::CovZZ, + collision::Flags, collision::Chi2, collision::NumContrib, + collision::CollisionTime, collision::CollisionTimeRes, + bc::RunNumber); + +DECLARE_SOA_TABLE(RedPVMults, "AOD", "REDPVMULT", //! Multiplicity from the PV contributors, joinable with reducedCollisions + mult::MultNTracksPV); + +DECLARE_SOA_TABLE(RedCentFT0Cs, "AOD", "REDCENTFT0C", //! Reduced Run 3 FT0C centrality table, joinable with reducedCollisions + cent::CentFT0C); + +namespace reducedtracks3body +{ +// track parameter definition +DECLARE_SOA_INDEX_COLUMN_FULL(Collision, collision, int, RedCollisions, ""); //! Collision index + +// track PID definition +DECLARE_SOA_COLUMN(TPCNSigmaPr, tpcNSigmaPr, float); //! Nsigma separation with the TPC detector for proton +DECLARE_SOA_COLUMN(TPCNSigmaDe, tpcNSigmaDe, float); //! Nsigma separation with the TPC detector for deuteron +DECLARE_SOA_COLUMN(TPCNSigmaPi, tpcNSigmaPi, float); //! Nsigma separation with the TPC detector for pion +DECLARE_SOA_COLUMN(TOFNSigmaDe, tofNSigmaDe, float); //! Nsigma separation with the TOF detector for deuteron (recalculated) + +} // namespace reducedtracks3body + +DECLARE_SOA_TABLE_FULL(StoredRedIUTracks, "RedIUTracks", "AOD", "REDIUTRACK", //! On disk version of the track parameters at inner most update (e.g. ITS) as it comes from the tracking + o2::soa::Index<>, reducedtracks3body::CollisionId, + track::X, track::Alpha, + track::Y, track::Z, track::Snp, track::Tgl, + track::Signed1Pt, + // cov matrix + track::SigmaY, track::SigmaZ, track::SigmaSnp, track::SigmaTgl, track::Sigma1Pt, + track::RhoZY, track::RhoSnpY, track::RhoSnpZ, track::RhoTglY, track::RhoTglZ, + track::RhoTglSnp, track::Rho1PtY, track::Rho1PtZ, track::Rho1PtSnp, track::Rho1PtTgl, + // tracks extra + track::TPCInnerParam, track::Flags, track::ITSClusterSizes, + track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusCrossedRows, + track::TRDPattern, track::TPCChi2NCl, track::TOFChi2, + track::TPCSignal, track::TOFExpMom, + // TPC PID + reducedtracks3body::TPCNSigmaPr, reducedtracks3body::TPCNSigmaPi, reducedtracks3body::TPCNSigmaDe, + reducedtracks3body::TOFNSigmaDe, + + // ----------- dynmaic columns ------------ + // tracks IU + track::Px, + track::Py, + track::Pz, + track::Rapidity, + track::Sign, + // tracks extra + track::PIDForTracking, + track::IsPVContributor, + track::HasTPC, + track::HasTOF, + track::TPCNClsFound, + track::TPCNClsCrossedRows, + track::v001::ITSClsSizeInLayer, + track::TPCCrossedRowsOverFindableCls); + +DECLARE_SOA_EXTENDED_TABLE_USER(RedIUTracks, StoredRedIUTracks, "REDIUTRACKEXT", //! Track parameters at inner most update (e.g. ITS) as it comes from the tracking + track::Pt, + track::P, + track::Eta, + track::Phi, + // cov matrix + track::CYY, + track::CZY, + track::CZZ, + track::CSnpY, + track::CSnpZ, + track::CSnpSnp, + track::CTglY, + track::CTglZ, + track::CTglSnp, + track::CTglTgl, + track::C1PtY, + track::C1PtZ, + track::C1PtSnp, + track::C1PtTgl, + track::C1Pt21Pt2, + // tracks extra + track::v001::DetectorMap); + +namespace reduceddecay3body +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Track0, track0, int, RedIUTracks, "_0"); //! Track 0 index +DECLARE_SOA_INDEX_COLUMN_FULL(Track1, track1, int, RedIUTracks, "_1"); //! Track 1 index +DECLARE_SOA_INDEX_COLUMN_FULL(Track2, track2, int, RedIUTracks, "_2"); //! Track 2 index +DECLARE_SOA_INDEX_COLUMN_FULL(Collision, collision, int, RedCollisions, ""); //! Collision index +DECLARE_SOA_COLUMN(Phi, phi, float); //! decay3body radius +DECLARE_SOA_COLUMN(Radius, radius, float); //! decay3body phi +DECLARE_SOA_COLUMN(PosZ, posz, float); //! decay3body z position +} // namespace reduceddecay3body + +DECLARE_SOA_TABLE(RedDecay3Bodys, "AOD", "REDDECAY3BODY", //! reduced 3-body decay table + o2::soa::Index<>, reduceddecay3body::CollisionId, reduceddecay3body::Track0Id, reduceddecay3body::Track1Id, reduceddecay3body::Track2Id); + +using ReducedDecay3BodysLinked = soa::Join; +using ReducedDecay3BodyLinked = ReducedDecay3BodysLinked::iterator; + +DECLARE_SOA_TABLE(Red3BodyInfo, "AOD", "RED3BODYINFO", //! joinable with RedDecay3Bodys + reduceddecay3body::Radius, reduceddecay3body::Phi, reduceddecay3body::PosZ); + +namespace dcafittersvinfo +{ +DECLARE_SOA_COLUMN(SVRadius, svRadius, float); //! SV radius in x-y plane calculated by dcaFitter +DECLARE_SOA_COLUMN(MomPhi, momPhi, float); //! phi of momentum of mother particle calculated from dcaFitter +DECLARE_SOA_COLUMN(SVPosZ, svPosZ, float); //! z position of SV calculated by dcaFitter +} // namespace dcafittersvinfo + +DECLARE_SOA_TABLE_FULL(DCAFitterSVInfo, "FitSVInfo", "AOD", "FITSVINFO", //! joinable with RedDecay3Bodys + dcafittersvinfo::SVRadius, dcafittersvinfo::MomPhi, dcafittersvinfo::SVPosZ); + +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_REDUCED3BODYTABLES_H_ diff --git a/PWGLF/DataModel/ReducedDoublePhiTables.h b/PWGLF/DataModel/ReducedDoublePhiTables.h new file mode 100644 index 00000000000..76cc65312a7 --- /dev/null +++ b/PWGLF/DataModel/ReducedDoublePhiTables.h @@ -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. + +/// +/// \author Sourav Kundu + +#ifndef PWGLF_DATAMODEL_REDUCEDDOUBLEPHITABLES_H_ +#define PWGLF_DATAMODEL_REDUCEDDOUBLEPHITABLES_H_ + +#include + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" + +namespace o2::aod +{ +namespace redphievent +{ +DECLARE_SOA_COLUMN(NumPos, numPos, int); //! Number of positive Kaon +DECLARE_SOA_COLUMN(NumNeg, numNeg, int); //! Number of negative Kaon +} // namespace redphievent +DECLARE_SOA_TABLE(RedPhiEvents, "AOD", "REDPHIEVENT", + o2::soa::Index<>, + bc::GlobalBC, + bc::RunNumber, + timestamp::Timestamp, + collision::PosZ, + collision::NumContrib, + redphievent::NumPos, + redphievent::NumNeg); +using RedPhiEvent = RedPhiEvents::iterator; + +namespace phitrack +{ +DECLARE_SOA_INDEX_COLUMN(RedPhiEvent, redPhiEvent); +DECLARE_SOA_COLUMN(PhiPx, phiPx, float); //! Phi Px +DECLARE_SOA_COLUMN(PhiPy, phiPy, float); //! Phi Py +DECLARE_SOA_COLUMN(PhiPz, phiPz, float); //! Phi Pz +DECLARE_SOA_COLUMN(Phid1Px, phid1Px, float); //! Phi d1 Px +DECLARE_SOA_COLUMN(Phid1Py, phid1Py, float); //! Phi d1 Py +DECLARE_SOA_COLUMN(Phid1Pz, phid1Pz, float); //! Phi d1 Pz +DECLARE_SOA_COLUMN(Phid2Px, phid2Px, float); //! Phi d2 Px +DECLARE_SOA_COLUMN(Phid2Py, phid2Py, float); //! Phi d2 Py +DECLARE_SOA_COLUMN(Phid2Pz, phid2Pz, float); //! Phi d2 Pz +DECLARE_SOA_COLUMN(PhiMass, phiMass, float); //! Phi Mass +DECLARE_SOA_COLUMN(Phid1Index, phid1Index, int64_t); //! Phi d1 index +DECLARE_SOA_COLUMN(Phid2Index, phid2Index, int64_t); //! Phi d2 index +DECLARE_SOA_COLUMN(Phid1Charge, phid1Charge, float); //! Phi d1 charge +DECLARE_SOA_COLUMN(Phid2Charge, phid2Charge, float); //! Phi d1 charge +DECLARE_SOA_COLUMN(Phid1TPC, phid1TPC, float); //! TPC nsigma d1 +DECLARE_SOA_COLUMN(Phid2TPC, phid2TPC, float); //! TPC nsigma d2 +DECLARE_SOA_COLUMN(Phid1TOFHit, phid1TOFHit, int); //! TOF hit d1 +DECLARE_SOA_COLUMN(Phid2TOFHit, phid2TOFHit, int); //! TOF hit d2 +DECLARE_SOA_COLUMN(Phid1TOF, phid1TOF, float); //! TOF nsigma d1 +DECLARE_SOA_COLUMN(Phid2TOF, phid2TOF, float); //! TOF nsigma d2 +} // namespace phitrack +DECLARE_SOA_TABLE(PhiTracks, "AOD", "PHITRACK", + o2::soa::Index<>, + phitrack::RedPhiEventId, + phitrack::PhiPx, + phitrack::PhiPy, + phitrack::PhiPz, + phitrack::Phid1Px, + phitrack::Phid1Py, + phitrack::Phid1Pz, + phitrack::Phid2Px, + phitrack::Phid2Py, + phitrack::Phid2Pz, + phitrack::PhiMass, + phitrack::Phid1Index, + phitrack::Phid2Index, + phitrack::Phid1Charge, + phitrack::Phid2Charge, + phitrack::Phid1TPC, + phitrack::Phid2TPC, + phitrack::Phid1TOFHit, + phitrack::Phid2TOFHit, + phitrack::Phid1TOF, + phitrack::Phid2TOF); + +using PhiTrack = PhiTracks::iterator; +} // namespace o2::aod +#endif // PWGLF_DATAMODEL_REDUCEDDOUBLEPHITABLES_H_ diff --git a/PWGLF/DataModel/ReducedF1ProtonTables.h b/PWGLF/DataModel/ReducedF1ProtonTables.h index e7534204f54..2f806c4bd1b 100644 --- a/PWGLF/DataModel/ReducedF1ProtonTables.h +++ b/PWGLF/DataModel/ReducedF1ProtonTables.h @@ -60,6 +60,9 @@ DECLARE_SOA_COLUMN(F1d3Py, f1d3Py, float); //! F DECLARE_SOA_COLUMN(F1d3Pz, f1d3Pz, float); //! F1 d3 Pz DECLARE_SOA_COLUMN(F1d1TOFHit, f1d1TOFHit, int); //! TOF hit pion DECLARE_SOA_COLUMN(F1d2TOFHit, f1d2TOFHit, int); //! TOF hit pion +DECLARE_SOA_COLUMN(F1d1TPC, f1d1TPC, float); //! TPC nsigma pion +DECLARE_SOA_COLUMN(F1d2TPC, f1d2TPC, float); //! TPC nsigma kaon +DECLARE_SOA_COLUMN(F1d2TPCPionHypo, f1d2TPCPionHypo, float); //! TPC nsigma kaon DECLARE_SOA_COLUMN(F1Mass, f1Mass, float); //! F1 mass DECLARE_SOA_COLUMN(F1MassKaonKshort, f1MassKaonKshort, float); //! F1 mass kaon kshort DECLARE_SOA_COLUMN(F1PionIndex, f1PionIndex, int64_t); //! F1 pion index @@ -93,6 +96,9 @@ DECLARE_SOA_TABLE(F1Tracks, "AOD", "F1TRACK", f1protondaughter::F1d3Pz, f1protondaughter::F1d1TOFHit, f1protondaughter::F1d2TOFHit, + f1protondaughter::F1d1TPC, + f1protondaughter::F1d2TPC, + f1protondaughter::F1d2TPCPionHypo, f1protondaughter::F1Mass, f1protondaughter::F1MassKaonKshort, f1protondaughter::F1PionIndex, diff --git a/PWGLF/DataModel/ReducedHeptaQuarkTables.h b/PWGLF/DataModel/ReducedHeptaQuarkTables.h new file mode 100644 index 00000000000..a8dd487fe9c --- /dev/null +++ b/PWGLF/DataModel/ReducedHeptaQuarkTables.h @@ -0,0 +1,101 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \author Junlee Kim + +#ifndef PWGLF_DATAMODEL_REDUCEDHEPTAQUARKTABLES_H_ +#define PWGLF_DATAMODEL_REDUCEDHEPTAQUARKTABLES_H_ + +#include + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" + +namespace o2::aod +{ +namespace redhqevent +{ +DECLARE_SOA_COLUMN(NumPhi, numPhi, int); //! Number of negative K +DECLARE_SOA_COLUMN(NumLambda, numLambda, int); //! Number of lambda +DECLARE_SOA_COLUMN(Centrality, centrality, float); //! +} // namespace redhqevent +DECLARE_SOA_TABLE(RedHQEvents, "AOD", "REDHQEVENT", + o2::soa::Index<>, + bc::GlobalBC, + bc::RunNumber, + timestamp::Timestamp, + collision::PosZ, + collision::NumContrib, + redhqevent::Centrality, + redhqevent::NumPhi, + redhqevent::NumLambda); +using RedHQEvent = RedHQEvents::iterator; + +namespace hqtrack +{ +DECLARE_SOA_INDEX_COLUMN(RedHQEvent, redHQEvent); +DECLARE_SOA_COLUMN(HQId, hqId, int); //! HQ ID +DECLARE_SOA_COLUMN(HQPx, hqPx, float); //! HQ Px +DECLARE_SOA_COLUMN(HQPy, hqPy, float); //! HQ Py +DECLARE_SOA_COLUMN(HQPz, hqPz, float); //! HQ Pz +DECLARE_SOA_COLUMN(HQd1Px, hqd1Px, float); //! HQ d1 Px +DECLARE_SOA_COLUMN(HQd1Py, hqd1Py, float); //! HQ d1 Py +DECLARE_SOA_COLUMN(HQd1Pz, hqd1Pz, float); //! HQ d1 Pz +DECLARE_SOA_COLUMN(HQd2Px, hqd2Px, float); //! HQ d2 Px +DECLARE_SOA_COLUMN(HQd2Py, hqd2Py, float); //! HQ d2 Py +DECLARE_SOA_COLUMN(HQd2Pz, hqd2Pz, float); //! HQ d2 Pz +DECLARE_SOA_COLUMN(HQMass, hqMass, float); //! HQ Mass +DECLARE_SOA_COLUMN(HQd1Index, hqd1Index, int64_t); //! HQ d1 index +DECLARE_SOA_COLUMN(HQd2Index, hqd2Index, int64_t); //! HQ d2 index +DECLARE_SOA_COLUMN(HQd1Charge, hqd1Charge, float); //! HQ d1 charge +DECLARE_SOA_COLUMN(HQd2Charge, hqd2Charge, float); //! HQ d1 charge +DECLARE_SOA_COLUMN(HQd1TPC, hqd1TPC, float); //! TPC nsigma d1 +DECLARE_SOA_COLUMN(HQd2TPC, hqd2TPC, float); //! TPC nsigma d2 +DECLARE_SOA_COLUMN(HQd1TOFHit, hqd1TOFHit, int); //! TOF hit d1 +DECLARE_SOA_COLUMN(HQd2TOFHit, hqd2TOFHit, int); //! TOF hit d2 +DECLARE_SOA_COLUMN(HQd1TOF, hqd1TOF, float); //! TOF nsigma d1 +DECLARE_SOA_COLUMN(HQd2TOF, hqd2TOF, float); //! TOF nsigma d2 + +} // namespace hqtrack +DECLARE_SOA_TABLE(HQTracks, "AOD", "HQTRACK", + o2::soa::Index<>, + hqtrack::RedHQEventId, + hqtrack::HQId, + hqtrack::HQPx, + hqtrack::HQPy, + hqtrack::HQPz, + hqtrack::HQd1Px, + hqtrack::HQd1Py, + hqtrack::HQd1Pz, + hqtrack::HQd2Px, + hqtrack::HQd2Py, + hqtrack::HQd2Pz, + hqtrack::HQMass, + hqtrack::HQd1Index, + hqtrack::HQd2Index, + hqtrack::HQd1Charge, + hqtrack::HQd2Charge, + hqtrack::HQd1TPC, + hqtrack::HQd2TPC, + hqtrack::HQd1TOFHit, + hqtrack::HQd2TOFHit, + hqtrack::HQd1TOF, + hqtrack::HQd2TOF); + +using HQTrack = HQTracks::iterator; +} // namespace o2::aod +#endif // PWGLF_DATAMODEL_REDUCEDHEPTAQUARKTABLES_H_ diff --git a/PWGLF/DataModel/ReducedLambdaLambdaTables.h b/PWGLF/DataModel/ReducedLambdaLambdaTables.h new file mode 100644 index 00000000000..88ea8fb0530 --- /dev/null +++ b/PWGLF/DataModel/ReducedLambdaLambdaTables.h @@ -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. + +/// +/// \author Junlee Kim + +#ifndef PWGLF_DATAMODEL_REDUCEDLAMBDALAMBDATABLES_H_ +#define PWGLF_DATAMODEL_REDUCEDLAMBDALAMBDATABLES_H_ + +#include + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" + +namespace o2::aod +{ +namespace redllevent +{ +DECLARE_SOA_COLUMN(NumLambda, numLambda, int); //! Number of lambda +DECLARE_SOA_COLUMN(Centrality, centrality, float); //! +} // namespace redllevent +DECLARE_SOA_TABLE(RedLLEvents, "AOD", "REDLLEVENT", + o2::soa::Index<>, + bc::GlobalBC, + bc::RunNumber, + timestamp::Timestamp, + collision::PosZ, + collision::NumContrib, + redllevent::Centrality, + redllevent::NumLambda); +using RedLLEvent = RedLLEvents::iterator; + +namespace lltrack +{ +DECLARE_SOA_INDEX_COLUMN(RedLLEvent, redLLEvent); +DECLARE_SOA_COLUMN(LLdId, lldId, int); //! LL PID +DECLARE_SOA_COLUMN(LLdPx, lldPx, float); //! LL d Px +DECLARE_SOA_COLUMN(LLdPy, lldPy, float); //! LL d Py +DECLARE_SOA_COLUMN(LLdPz, lldPz, float); //! LL d Pz +DECLARE_SOA_COLUMN(LLdx, lldx, float); //! LL d x +DECLARE_SOA_COLUMN(LLdy, lldy, float); //! LL d y +DECLARE_SOA_COLUMN(LLdz, lldz, float); //! LL d z +DECLARE_SOA_COLUMN(LLdMass, lldMass, float); //! LL d Mass +DECLARE_SOA_COLUMN(LLdd1TPC, lldd1TPC, float); //! LL dd1 TPC nsigma +DECLARE_SOA_COLUMN(LLdd2TPC, lldd2TPC, float); //! LL dd2 TPC nsigma +DECLARE_SOA_COLUMN(LLdd1Index, lldd1Index, int64_t); //! LL dd1 global index +DECLARE_SOA_COLUMN(LLdd2Index, lldd2Index, int64_t); //! LL dd2 global index + +} // namespace lltrack +DECLARE_SOA_TABLE(LLTracks, "AOD", "LLTRACK", + o2::soa::Index<>, + lltrack::RedLLEventId, + lltrack::LLdId, + lltrack::LLdPx, + lltrack::LLdPy, + lltrack::LLdPz, + lltrack::LLdx, + lltrack::LLdy, + lltrack::LLdz, + lltrack::LLdMass, + lltrack::LLdd1TPC, + lltrack::LLdd2TPC, + lltrack::LLdd1Index, + lltrack::LLdd2Index); + +using LLTrack = LLTracks::iterator; +} // namespace o2::aod +#endif // PWGLF_DATAMODEL_REDUCEDLAMBDALAMBDATABLES_H_ diff --git a/PWGLF/DataModel/SPCalibrationTables.h b/PWGLF/DataModel/SPCalibrationTables.h new file mode 100644 index 00000000000..2b417ce8758 --- /dev/null +++ b/PWGLF/DataModel/SPCalibrationTables.h @@ -0,0 +1,79 @@ +// 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 SPCalibrationTables.h +/// +/// author: prottay das 07/09/2024 +/// email: prottay.das@cern.ch + +#ifndef PWGLF_DATAMODEL_SPCALIBRATIONTABLES_H_ +#define PWGLF_DATAMODEL_SPCALIBRATIONTABLES_H_ + +#include + +#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace spcalibrationtable +{ +DECLARE_SOA_COLUMN(TriggerEventSP, triggereventsp, bool); +DECLARE_SOA_COLUMN(TriggerEventRunNo, triggereventrunno, int); +DECLARE_SOA_COLUMN(Cent, cent, float); +DECLARE_SOA_COLUMN(Vx, vx, float); +DECLARE_SOA_COLUMN(Vy, vy, float); +DECLARE_SOA_COLUMN(Vz, vz, float); +DECLARE_SOA_COLUMN(ZNAC, znaC, float); +DECLARE_SOA_COLUMN(ZNCC, zncC, float); +DECLARE_SOA_COLUMN(ZNAE0, znaE0, float); +DECLARE_SOA_COLUMN(ZNAE1, znaE1, float); +DECLARE_SOA_COLUMN(ZNAE2, znaE2, float); +DECLARE_SOA_COLUMN(ZNAE3, znaE3, float); +DECLARE_SOA_COLUMN(ZNCE0, zncE0, float); +DECLARE_SOA_COLUMN(ZNCE1, zncE1, float); +DECLARE_SOA_COLUMN(ZNCE2, zncE2, float); +DECLARE_SOA_COLUMN(ZNCE3, zncE3, float); +DECLARE_SOA_COLUMN(QXZDCA, qxZDCA, float); +DECLARE_SOA_COLUMN(QXZDCC, qxZDCC, float); +DECLARE_SOA_COLUMN(QYZDCA, qyZDCA, float); +DECLARE_SOA_COLUMN(QYZDCC, qyZDCC, float); +DECLARE_SOA_COLUMN(PsiZDCC, psiZDCC, float); +DECLARE_SOA_COLUMN(PsiZDCA, psiZDCA, float); +} // namespace spcalibrationtable +DECLARE_SOA_TABLE(SPCalibrationTables, "AOD", "SPCALCOLS", + spcalibrationtable::TriggerEventSP, + spcalibrationtable::TriggerEventRunNo, + spcalibrationtable::Cent, + spcalibrationtable::Vx, + spcalibrationtable::Vy, + spcalibrationtable::Vz, + spcalibrationtable::ZNAC, + spcalibrationtable::ZNCC, + spcalibrationtable::ZNAE0, + spcalibrationtable::ZNAE1, + spcalibrationtable::ZNAE2, + spcalibrationtable::ZNAE3, + spcalibrationtable::ZNCE0, + spcalibrationtable::ZNCE1, + spcalibrationtable::ZNCE2, + spcalibrationtable::ZNCE3, + spcalibrationtable::QXZDCA, + spcalibrationtable::QXZDCC, + spcalibrationtable::QYZDCA, + spcalibrationtable::QYZDCC, + spcalibrationtable::PsiZDCC, + spcalibrationtable::PsiZDCA); +using SPCalibrationTable = SPCalibrationTables::iterator; +} // namespace o2::aod +#endif // PWGLF_DATAMODEL_SPCALIBRATIONTABLES_H_ diff --git a/PWGLF/DataModel/V0SelectorTables.h b/PWGLF/DataModel/V0SelectorTables.h new file mode 100644 index 00000000000..1283c754819 --- /dev/null +++ b/PWGLF/DataModel/V0SelectorTables.h @@ -0,0 +1,49 @@ +// 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. +#ifndef PWGLF_DATAMODEL_V0SELECTORTABLES_H_ +#define PWGLF_DATAMODEL_V0SELECTORTABLES_H_ + +#include +#include +namespace o2::aod +{ + +namespace v0flags +{ + +enum V0Flags : uint8_t { + FK0S = 0x1, // K0S candidate + FLAMBDA = 0x2, // Lambda candidate + FANTILAMBDA = 0x4, // AntiLambda candidate + FREJECTED = 0x8 // Does not satisfy any of the above, or is randomly rejected +}; + +DECLARE_SOA_COLUMN(SignalFlag, signalFlag, uint8_t); +DECLARE_SOA_DYNAMIC_COLUMN(IsK0SCandidate, isK0SCandidate, //! Flag to check if V0 is a K0S candidate + [](uint8_t flag) -> bool { return flag & o2::aod::v0flags::FK0S; }); +DECLARE_SOA_DYNAMIC_COLUMN(IsLambdaCandidate, isLambdaCandidate, //! Flag to check if V0 is a Lambda candidate + [](uint8_t flag) -> bool { return flag & o2::aod::v0flags::FLAMBDA; }); +DECLARE_SOA_DYNAMIC_COLUMN(IsAntiLambdaCandidate, isAntiLambdaCandidate, //! Flag to check if V0 is a AntiLambda candidate + [](uint8_t flag) -> bool { return flag & o2::aod::v0flags::FANTILAMBDA; }); +DECLARE_SOA_DYNAMIC_COLUMN(IsRejectedCandidate, isRejectedCandidate, //! Flag to check if V0 is rejected + [](uint8_t flag) -> bool { return flag & o2::aod::v0flags::FREJECTED; }); +} // namespace v0flags + +DECLARE_SOA_TABLE_STAGED(V0SignalFlags, "V0SIGNALFLAGS", + v0flags::SignalFlag, + v0flags::IsK0SCandidate, + v0flags::IsLambdaCandidate, + v0flags::IsAntiLambdaCandidate, + v0flags::IsRejectedCandidate); + +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_V0SELECTORTABLES_H_ diff --git a/PWGLF/DataModel/Vtx3BodyTables.h b/PWGLF/DataModel/Vtx3BodyTables.h index 14713156e1d..9ae43bb0255 100644 --- a/PWGLF/DataModel/Vtx3BodyTables.h +++ b/PWGLF/DataModel/Vtx3BodyTables.h @@ -9,6 +9,11 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file Vtx3BodyTables.h +/// \brief Definitions of reduced tables for 3body decayed hypertriton +/// \author Yuanzhe Wang +/// \author Carolina Reetz + #ifndef PWGLF_DATAMODEL_VTX3BODYTABLES_H_ #define PWGLF_DATAMODEL_VTX3BODYTABLES_H_ @@ -43,10 +48,16 @@ DECLARE_SOA_COLUMN(Z, z, float); //! decay position Z // Saved from finding: DCAs DECLARE_SOA_COLUMN(DCAVtxDaughters, dcaVtxdaughters, float); //! DCA among daughters +DECLARE_SOA_COLUMN(DCAXYTrack0ToPV, dcaXYtrack0topv, float); //! DCAXY of prong0 to PV +DECLARE_SOA_COLUMN(DCAXYTrack1ToPV, dcaXYtrack1topv, float); //! DCAXY of prong1 to PV +DECLARE_SOA_COLUMN(DCAXYTrack2ToPV, dcaXYtrack2topv, float); //! DCAXY of prong2 to PV DECLARE_SOA_COLUMN(DCATrack0ToPV, dcatrack0topv, float); //! DCA of prong0 to PV DECLARE_SOA_COLUMN(DCATrack1ToPV, dcatrack1topv, float); //! DCA of prong1 to PV DECLARE_SOA_COLUMN(DCATrack2ToPV, dcatrack2topv, float); //! DCA of prong2 to PV +// Recalculated TOF PID information of bachelor +DECLARE_SOA_COLUMN(TOFNSigmaBachDe, tofNSigmaBachDe, float); //! Recalculated Nsigma seperation with TOF for deuteron + // Derived expressions // Momenta DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! 3 body p @@ -129,7 +140,9 @@ DECLARE_SOA_TABLE_FULL(StoredVtx3BodyDatas, "Vtx3BodyDatas", "AOD", "Vtx3BodyDAT vtx3body::PxTrack1, vtx3body::PyTrack1, vtx3body::PzTrack1, vtx3body::PxTrack2, vtx3body::PyTrack2, vtx3body::PzTrack2, vtx3body::DCAVtxDaughters, + vtx3body::DCAXYTrack0ToPV, vtx3body::DCAXYTrack1ToPV, vtx3body::DCAXYTrack2ToPV, vtx3body::DCATrack0ToPV, vtx3body::DCATrack1ToPV, vtx3body::DCATrack2ToPV, + vtx3body::TOFNSigmaBachDe, // Dynamic columns vtx3body::P, @@ -201,34 +214,29 @@ namespace hyp3body { // collision DECLARE_SOA_COLUMN(Centrality, centrality, float); //! centrality -DECLARE_SOA_COLUMN(XPV, xpv, float); //! primary vertex X -DECLARE_SOA_COLUMN(YPV, ypv, float); //! primary vertex Y -DECLARE_SOA_COLUMN(ZPV, zpv, float); //! primary vertex Z // reconstruced candidate DECLARE_SOA_COLUMN(IsMatter, isMatter, bool); //! bool: true for matter DECLARE_SOA_COLUMN(M, m, float); //! invariant mass DECLARE_SOA_COLUMN(P, p, float); //! p DECLARE_SOA_COLUMN(Pt, pt, float); //! pT DECLARE_SOA_COLUMN(Ct, ct, float); //! ct -DECLARE_SOA_COLUMN(X, x, float); //! decay position X -DECLARE_SOA_COLUMN(Y, y, float); //! decay position Y -DECLARE_SOA_COLUMN(Z, z, float); //! decay position Z DECLARE_SOA_COLUMN(CosPA, cospa, float); DECLARE_SOA_COLUMN(DCADaughters, dcaDaughters, float); //! DCA among daughters DECLARE_SOA_COLUMN(DCACandToPV, dcaCandtopv, float); //! DCA of the reconstructed track to pv +DECLARE_SOA_COLUMN(VtxRadius, vtxRadius, float); //! Radius of SV // kinematic infomation of daughter tracks -DECLARE_SOA_COLUMN(PProton, pProton, float); //! p of the proton daughter -DECLARE_SOA_COLUMN(PtProton, ptProton, float); //! pT of the proton daughter -DECLARE_SOA_COLUMN(EtaProton, etaProton, float); //! eta of the proton daughter -DECLARE_SOA_COLUMN(PhiProton, phiProton, float); //! phi of the proton daughter -DECLARE_SOA_COLUMN(PPion, pPion, float); //! p of the pion daughter -DECLARE_SOA_COLUMN(PtPion, ptPion, float); //! pT of the pion daughter -DECLARE_SOA_COLUMN(EtaPion, etaPion, float); //! eta of the pion daughter -DECLARE_SOA_COLUMN(PhiPion, phiPion, float); //! phi of the pion daughter -DECLARE_SOA_COLUMN(PBachelor, pBachelor, float); //! p of the bachelor daughter -DECLARE_SOA_COLUMN(PtBachelor, ptBachelor, float); //! pT of the bachelor daughter -DECLARE_SOA_COLUMN(EtaBachelor, etaBachelor, float); //! eta of the bachelor daughter -DECLARE_SOA_COLUMN(PhiBachelor, phiBachelor, float); //! phi of the bachelor daughter +DECLARE_SOA_COLUMN(PtProton, ptProton, float); //! pT of the proton daughter +DECLARE_SOA_COLUMN(EtaProton, etaProton, float); //! eta of the proton daughter +DECLARE_SOA_COLUMN(PhiProton, phiProton, float); //! phi of the proton daughter +DECLARE_SOA_COLUMN(RadiusProton, radiusProton, float); //! radius of innermost hit of the proton daughter +DECLARE_SOA_COLUMN(PtPion, ptPion, float); //! pT of the pion daughter +DECLARE_SOA_COLUMN(EtaPion, etaPion, float); //! eta of the pion daughter +DECLARE_SOA_COLUMN(PhiPion, phiPion, float); //! phi of the pion daughter +DECLARE_SOA_COLUMN(RadiusPion, radiusPion, float); //! radius of innermost hit of the pion daughter +DECLARE_SOA_COLUMN(PtBachelor, ptBachelor, float); //! pT of the bachelor daughter +DECLARE_SOA_COLUMN(EtaBachelor, etaBachelor, float); //! eta of the bachelor daughter +DECLARE_SOA_COLUMN(PhiBachelor, phiBachelor, float); //! phi of the bachelor daughter +DECLARE_SOA_COLUMN(RadiusBachelor, radiusBachelor, float); //! radius of innermost hit of the bachelor daughter // track quality DECLARE_SOA_COLUMN(TPCNclusProton, tpcNclusProton, uint8_t); //! number of TPC clusters of the proton daughter DECLARE_SOA_COLUMN(TPCNclusPion, tpcNclusPion, uint8_t); //! number of TPC clusters of the pion daughter @@ -242,15 +250,20 @@ DECLARE_SOA_COLUMN(TPCNSigmaPion, tpcNSigmaPion, float); //! nsigma of T DECLARE_SOA_COLUMN(TPCNSigmaBachelor, tpcNSigmaBachelor, float); //! nsigma of TPC PID of the bachelor daughter DECLARE_SOA_COLUMN(TOFNSigmaBachelor, tofNSigmaBachelor, float); //! nsigma of TOF PID of the bachelor daughter // DCA to PV -DECLARE_SOA_COLUMN(DCAProtonToPV, dcaProtontoPV, float); //! DCA of the proton daughter to pv -DECLARE_SOA_COLUMN(DCAPionToPV, dcaPiontoPV, float); //! DCA of the pion daughter to pv -DECLARE_SOA_COLUMN(DCABachelorToPV, dcaBachelortoPV, float); //! DCA of the bachelor daughter to pv +DECLARE_SOA_COLUMN(DCAXYProtonToPV, dcaxyProtontoPV, float); //! DCAXY of the proton daughter to pv +DECLARE_SOA_COLUMN(DCAXYPionToPV, dcaxyPiontoPV, float); //! DCAXY of the pion daughter to pv +DECLARE_SOA_COLUMN(DCAXYBachelorToPV, dcaxyBachelortoPV, float); //! DCAXY of the bachelor daughter to pv +DECLARE_SOA_COLUMN(DCAProtonToPV, dcaProtontoPV, float); //! DCA of the proton daughter to pv +DECLARE_SOA_COLUMN(DCAPionToPV, dcaPiontoPV, float); //! DCA of the pion daughter to pv +DECLARE_SOA_COLUMN(DCABachelorToPV, dcaBachelortoPV, float); //! DCA of the bachelor daughter to pv +DECLARE_SOA_COLUMN(IsBachPrimary, isbachprimary, bool); //! flag for bachelor daughter primary // for MC DECLARE_SOA_COLUMN(GenP, genP, float); // P of the hypertriton DECLARE_SOA_COLUMN(GenPt, genPt, float); // pT of the hypertriton DECLARE_SOA_COLUMN(GenCt, genCt, float); // ct of the hypertriton DECLARE_SOA_COLUMN(GenPhi, genPhi, float); // Phi of the hypertriton DECLARE_SOA_COLUMN(GenEta, genEta, float); // Eta of the hypertriton +DECLARE_SOA_COLUMN(GenRapidity, genRapidity, float); // Rapidity of the hypertriton DECLARE_SOA_COLUMN(IsReco, isReco, bool); // bool: true for reco DECLARE_SOA_COLUMN(IsSignal, isSignal, bool); // bool: true for signal DECLARE_SOA_COLUMN(PdgCode, pdgCode, int); // pdgCode of the mcparticle, -1 for fake pair @@ -261,62 +274,347 @@ DECLARE_SOA_COLUMN(SurvivedEventSelection, survivedEventSelection, bool); // boo DECLARE_SOA_TABLE(Hyp3BodyCands, "AOD", "HYP3BODYCANDS", o2::soa::Index<>, hyp3body::Centrality, - hyp3body::XPV, hyp3body::YPV, hyp3body::ZPV, // secondary vertex and reconstruced candidate hyp3body::IsMatter, hyp3body::M, hyp3body::P, hyp3body::Pt, hyp3body::Ct, - hyp3body::X, hyp3body::Y, hyp3body::Z, hyp3body::CosPA, hyp3body::DCADaughters, hyp3body::DCACandToPV, + hyp3body::VtxRadius, // daughter tracks - hyp3body::PProton, hyp3body::PtProton, hyp3body::EtaProton, hyp3body::PhiProton, - hyp3body::PPion, hyp3body::PtPion, hyp3body::EtaPion, hyp3body::PhiPion, - hyp3body::PBachelor, hyp3body::PtBachelor, hyp3body::EtaBachelor, hyp3body::PhiBachelor, + hyp3body::PtProton, hyp3body::EtaProton, hyp3body::PhiProton, hyp3body::RadiusProton, + hyp3body::PtPion, hyp3body::EtaPion, hyp3body::PhiPion, hyp3body::RadiusPion, + hyp3body::PtBachelor, hyp3body::EtaBachelor, hyp3body::PhiBachelor, hyp3body::RadiusBachelor, hyp3body::TPCNclusProton, hyp3body::TPCNclusPion, hyp3body::TPCNclusBachelor, hyp3body::ITSNclusSizeProton, hyp3body::ITSNclusSizePion, hyp3body::ITSNclusSizeBachelor, hyp3body::TPCNSigmaProton, hyp3body::TPCNSigmaPion, hyp3body::TPCNSigmaBachelor, hyp3body::TOFNSigmaBachelor, + hyp3body::DCAXYProtonToPV, hyp3body::DCAXYPionToPV, hyp3body::DCAXYBachelorToPV, hyp3body::DCAProtonToPV, hyp3body::DCAPionToPV, hyp3body::DCABachelorToPV); // output table for MC DECLARE_SOA_TABLE(MCHyp3BodyCands, "AOD", "MCHYP3BODYCANDS", o2::soa::Index<>, hyp3body::Centrality, - hyp3body::XPV, hyp3body::YPV, hyp3body::ZPV, // secondary vertex and reconstruced candidate hyp3body::IsMatter, hyp3body::M, hyp3body::P, hyp3body::Pt, hyp3body::Ct, - hyp3body::X, hyp3body::Y, hyp3body::Z, hyp3body::CosPA, hyp3body::DCADaughters, hyp3body::DCACandToPV, + hyp3body::VtxRadius, // daughter tracks - hyp3body::PProton, hyp3body::PtProton, hyp3body::EtaProton, hyp3body::PhiProton, - hyp3body::PPion, hyp3body::PtPion, hyp3body::EtaPion, hyp3body::PhiPion, - hyp3body::PBachelor, hyp3body::PtBachelor, hyp3body::EtaBachelor, hyp3body::PhiBachelor, + hyp3body::PtProton, hyp3body::EtaProton, hyp3body::PhiProton, hyp3body::RadiusProton, + hyp3body::PtPion, hyp3body::EtaPion, hyp3body::PhiPion, hyp3body::RadiusPion, + hyp3body::PtBachelor, hyp3body::EtaBachelor, hyp3body::PhiBachelor, hyp3body::RadiusBachelor, hyp3body::TPCNclusProton, hyp3body::TPCNclusPion, hyp3body::TPCNclusBachelor, hyp3body::ITSNclusSizeProton, hyp3body::ITSNclusSizePion, hyp3body::ITSNclusSizeBachelor, hyp3body::TPCNSigmaProton, hyp3body::TPCNSigmaPion, hyp3body::TPCNSigmaBachelor, hyp3body::TOFNSigmaBachelor, + hyp3body::DCAXYProtonToPV, hyp3body::DCAXYPionToPV, hyp3body::DCAXYBachelorToPV, hyp3body::DCAProtonToPV, hyp3body::DCAPionToPV, hyp3body::DCABachelorToPV, + hyp3body::IsBachPrimary, // MC information hyp3body::GenP, hyp3body::GenPt, hyp3body::GenCt, hyp3body::GenPhi, hyp3body::GenEta, + hyp3body::GenRapidity, hyp3body::IsSignal, hyp3body::IsReco, hyp3body::PdgCode, hyp3body::SurvivedEventSelection); +//______________________________________________________ +// DATAMODEL FOR KFPARTICLE DECAY3BODYS + +namespace kfvtx3body +{ +// General 3 body Vtx properties: mass, momentum, charge +DECLARE_SOA_COLUMN(Mass, mass, float); //! candidate mass (PID hypothesis depending on bachelor charge) +DECLARE_SOA_COLUMN(XErr, xerr, float); //! candidate position x error at decay position +DECLARE_SOA_COLUMN(YErr, yerr, float); //! candidate position y error at decay position +DECLARE_SOA_COLUMN(ZErr, zerr, float); //! candidate position z error at decay position +DECLARE_SOA_COLUMN(Px, px, float); //! candidate px at decay position +DECLARE_SOA_COLUMN(Py, py, float); //! candidate py at decay position +DECLARE_SOA_COLUMN(Pz, pz, float); //! candidate pz at decay position +DECLARE_SOA_COLUMN(Pt, pt, float); //! candidate pt at decay position +DECLARE_SOA_COLUMN(PxErr, pxerr, float); //! candidate px error at decay position +DECLARE_SOA_COLUMN(PyErr, pyerr, float); //! candidate py error at decay position +DECLARE_SOA_COLUMN(PzErr, pzerr, float); //! candidate pz error at decay position +DECLARE_SOA_COLUMN(PtErr, pterr, float); //! candidate pt error at decay position +DECLARE_SOA_COLUMN(Sign, sign, float); //! candidate sign + +// topological properties +DECLARE_SOA_COLUMN(VtxCosPAKF, vtxcospakf, float); //! 3 body vtx CosPA from KFParticle (using kfpPV) +DECLARE_SOA_COLUMN(VtxCosXYPAKF, vtxcosxypakf, float); //! 3 body vtx CosPA from KFParticle (using kfpPV) +DECLARE_SOA_COLUMN(VtxCosPAKFtopo, vtxcospakftopo, float); //! 3 body vtx CosPA from KFParticle after topological constraint (using kfpPV) +DECLARE_SOA_COLUMN(VtxCosXYPAKFtopo, vtxcosxypakftopo, float); //! 3 body vtx CosPA from KFParticle after topological constraint (using kfpPV) +DECLARE_SOA_COLUMN(DCAVtxToPVKF, dcavtxtopvkf, float); //! 3 body vtx DCA to PV from KFParticle (using kfpPV) +DECLARE_SOA_COLUMN(DCAXYVtxToPVKF, dcaxyvtxtopvkf, float); //! 3 body vtx DCAxy to PV from KFParticle (using kfpPV) +DECLARE_SOA_COLUMN(DecayLKF, decaylkf, float); //! 3 body vtx decay length from KFParticle (using kfpPV after topological constraint) +DECLARE_SOA_COLUMN(DecayLXYKF, decaylxykf, float); //! 3 body vtx decay length XY from KFParticle (using kfpPV after topological constraint) +DECLARE_SOA_COLUMN(DecayLDeltaL, decayldeltal, float); //! 3 body vtx l/dl from KFParticle (using kfpPV after topological constraint) +DECLARE_SOA_COLUMN(Chi2geoNDF, chi2geondf, float); //! 3 body vtx chi2geo from geometrical KFParticle fit +DECLARE_SOA_COLUMN(Chi2topoNDF, chi2topondf, float); //! 3 body vtx chi2topo from KFParticle topological constraint to the PV (using kfpPV) +DECLARE_SOA_COLUMN(CTauKFtopo, ctaukftopo, float); //! 3 body vtx ctau from KFParticle after topological constraint + +// Strangeness tracking +DECLARE_SOA_COLUMN(TrackedClSize, trackedclsize, int); //! Cluster size of strangeness tracked 3body + +// daughters +DECLARE_SOA_COLUMN(DCATrack0ToPVKF, dcatrack0topvkf, float); //! DCA of proton prong to PV from KFParticle +DECLARE_SOA_COLUMN(DCATrack1ToPVKF, dcatrack1topvkf, float); //! DCA of pion prong to PV from KFParticle +DECLARE_SOA_COLUMN(DCATrack2ToPVKF, dcatrack2topvkf, float); //! DCA of deuteron prong to PV from KFParticle +DECLARE_SOA_COLUMN(DCAxyTrack0ToPVKF, dcaxytrack0topvkf, float); //! DCAxy of proton prong to PV from KFParticle +DECLARE_SOA_COLUMN(DCAxyTrack1ToPVKF, dcaxytrack1topvkf, float); //! DCAxy of pion prong to PV from KFParticle +DECLARE_SOA_COLUMN(DCAxyTrack2ToPVKF, dcaxytrack2topvkf, float); //! DCAxy of deuteron prong to PV from KFParticle +DECLARE_SOA_COLUMN(DCATrackPosToPV, dcatrackpostopv, float); //! DCA of positive track to PV (propagated before vtx fit) +DECLARE_SOA_COLUMN(DCATrackNegToPV, dcatracknegtopv, float); //! DCA of negative track to PV (propagated before vtx fit) +DECLARE_SOA_COLUMN(DCATrackBachToPV, dcatrackbachtopv, float); //! DCA of bachelor track to PV (propagated before vtx fit) +DECLARE_SOA_COLUMN(DCAxyTrackPosToPV, dcaxytrackpostopv, float); //! DCAxy of positive track to PV (propagated before vtx fit) +DECLARE_SOA_COLUMN(DCAxyTrackNegToPV, dcaxytracknegtopv, float); //! DCAxy of negative track to PV (propagated before vtx fit) +DECLARE_SOA_COLUMN(DCAxyTrackBachToPV, dcaxytrackbachtopv, float); //! DCAxy of bachelor track to PV (propagated before vtx fit) +DECLARE_SOA_COLUMN(DCAxyTrack0ToSVKF, dcaxytrack0tosvkf, float); //! DCAxy of proton prong to SV from KFParticle +DECLARE_SOA_COLUMN(DCAxyTrack1ToSVKF, dcaxytrack1tosvkf, float); //! DCAxy of pion prong to SV from KFParticle +DECLARE_SOA_COLUMN(DCAxyTrack2ToSVKF, dcaxytrack2tosvkf, float); //! DCAxy of deuteron prong to SV from KFParticle +DECLARE_SOA_COLUMN(DCATrack0ToTrack1KF, dcatrack0totrack1kf, float); //! DCAxy of proton prong to pion from KFParticle +DECLARE_SOA_COLUMN(DCATrack0ToTrack2KF, dcatrack0totrack2kf, float); //! DCAxy of proton prong to deuteron from KFParticle +DECLARE_SOA_COLUMN(DCATrack1ToTrack2KF, dcatrack1totrack2kf, float); //! DCAxy of pion prong to deuteron from KFParticle +DECLARE_SOA_COLUMN(DCAVtxDaughtersKF, dcavtxdaughterskf, float); //! sum of DCAs between daughters in 3D from KFParticle +DECLARE_SOA_COLUMN(Track0Sign, track0sign, float); //! sign of proton daughter track +DECLARE_SOA_COLUMN(Track1Sign, track1sign, float); //! sign of pion daughter track +DECLARE_SOA_COLUMN(Track2Sign, track2sign, float); //! sign of deuteron daughter track +DECLARE_SOA_COLUMN(TPCInnerParamTrack0, tpcinnerparamtrack0, float); //! momentum at inner wall of TPC of proton daughter +DECLARE_SOA_COLUMN(TPCInnerParamTrack1, tpcinnerparamtrack1, float); //! momentum at inner wall of TPC of pion daughter +DECLARE_SOA_COLUMN(TPCInnerParamTrack2, tpcinnerparamtrack2, float); //! momentum at inner wall of TPC of deuteron daughter +DECLARE_SOA_COLUMN(TPCNClTrack0, tpcncltrack0, int); //! Number of TPC clusters of proton daughter +DECLARE_SOA_COLUMN(TPCNClTrack1, tpcncltrack1, int); //! Number of TPC clusters of pion daughter +DECLARE_SOA_COLUMN(TPCNClTrack2, tpcncltrack2, int); //! Number of TPC clusters of deuteron daughter +DECLARE_SOA_COLUMN(TPCChi2NClDeuteron, tpcchi2ncldeuteron, float); //! TPC Chi2 / cluster of deuteron daughter +DECLARE_SOA_COLUMN(DeltaPhiDeuteron, deltaphideuteron, float); //! phi before track rotation - phi after track rotation for deuteron track +DECLARE_SOA_COLUMN(DeltaPhiProton, deltaphiproton, float); //! phi before track rotation - phi after track rotation for proton track +// PID +DECLARE_SOA_COLUMN(TPCNSigmaProton, tpcnsigmaproton, float); //! nsigma proton of TPC PID of the proton daughter +DECLARE_SOA_COLUMN(TPCNSigmaPion, tpcnsigmapion, float); //! nsigma pion of TPC PID of the pion daughter +DECLARE_SOA_COLUMN(TPCNSigmaDeuteron, tpcnsigmadeuteron, float); //! nsigma deuteron of TPC PID of the bachelor daughter +DECLARE_SOA_COLUMN(TPCNSigmaPionBach, tpcnsigmapionbach, float); //! nsigma pion of TPC PID of the bachelor daughter +DECLARE_SOA_COLUMN(TPCdEdxProton, tpcdedxproton, float); //! TPC dEdx of the proton daughter +DECLARE_SOA_COLUMN(TPCdEdxPion, tpcdedxpion, float); //! TPC dEdx of the pion daughter +DECLARE_SOA_COLUMN(TPCdEdxDeuteron, tpcdedxdeuteron, float); //! TPC dEdx of the bachelor daughter +DECLARE_SOA_COLUMN(TOFNSigmaDeuteron, tofnsigmadeuteron, float); //! nsigma of TOF PID of the bachelor daughter +DECLARE_SOA_COLUMN(ITSClusSizeDeuteron, itsclussizedeuteron, double); //! average ITS cluster size of bachelor daughter +DECLARE_SOA_COLUMN(PIDTrackingDeuteron, pidtrackingdeuteron, uint32_t); //! PID during tracking of bachelor daughter + +// Monte Carlo +DECLARE_SOA_COLUMN(GenP, genp, float); //! generated momentum +DECLARE_SOA_COLUMN(GenPt, genpt, float); //! generated transverse momentum +DECLARE_SOA_COLUMN(GenDecVtxX, gendecvtxx, double); //! generated decay vertex position x +DECLARE_SOA_COLUMN(GenDecVtxY, gendecvtxy, double); //! generated decay vertex position y +DECLARE_SOA_COLUMN(GenDecVtxZ, gendecvtxz, double); //! generated decay vertex position z +DECLARE_SOA_COLUMN(GenCtau, genctau, double); //! generated ctau +DECLARE_SOA_COLUMN(GenPhi, genphi, float); //! generated phi +DECLARE_SOA_COLUMN(GenEta, geneta, float); //! generated eta +DECLARE_SOA_COLUMN(GenRapidity, genrapidity, float); //! generated rapidity +DECLARE_SOA_COLUMN(GenPosP, genposp, float); //! generated momentum pos daughter particle +DECLARE_SOA_COLUMN(GenPosPt, genpospt, float); //! generated transverse momentum pos daughter particle +DECLARE_SOA_COLUMN(GenNegP, gennegp, float); //! generated momentum neg daughter particle +DECLARE_SOA_COLUMN(GenNegPt, gennegpt, float); //! generated transverse momentum neg daughter particle +DECLARE_SOA_COLUMN(GenBachP, genbachp, float); //! generated momentum bachelor daughter particle +DECLARE_SOA_COLUMN(GenBachPt, genbachpt, float); //! generated transverse momentum bachelor daughter particle +DECLARE_SOA_COLUMN(IsTrueH3L, istrueh3l, bool); //! flag for true hypertriton candidate +DECLARE_SOA_COLUMN(IsTrueAntiH3L, istrueantih3l, bool); //! flag for true anti-hypertriton candidate +DECLARE_SOA_COLUMN(PdgCodeDau0, pdgcodedau0, int); //! MC particle daughter 0 PDG code +DECLARE_SOA_COLUMN(PdgCodeDau1, pdgcodedau1, int); //! MC particle daughter 1 PDG code +DECLARE_SOA_COLUMN(PdgCodeDau2, pdgcodedau2, int); //! MC particle daughter 2 PDG code +DECLARE_SOA_COLUMN(IsBachPrimary, isbachprimary, bool); //! flag for bachelor daughter primary +DECLARE_SOA_COLUMN(SurvEvSel, survevsel, int); //! flag if reco collision survived event selection +DECLARE_SOA_COLUMN(IsReco, isreco, int); //! flag if candidate was reconstructed + +// V0 +DECLARE_SOA_COLUMN(MassV0, massv0, float); //! proton, pion vertex mass +DECLARE_SOA_COLUMN(Chi2MassV0, chi2massv0, float); //! chi2 of proton, pion mass constraint to Lambda mass +DECLARE_SOA_COLUMN(CosPAV0, cospav0, float); //! proton, pion vertex mass + +} // namespace kfvtx3body + +DECLARE_SOA_TABLE(KFVtx3BodyDatas, "AOD", "KFVTX3BODYDATA", + o2::soa::Index<>, vtx3body::CollisionId, vtx3body::Track0Id, vtx3body::Track1Id, vtx3body::Track2Id, vtx3body::Decay3BodyId, + + // hypertriton candidate + kfvtx3body::Mass, + vtx3body::X, vtx3body::Y, vtx3body::Z, + kfvtx3body::XErr, kfvtx3body::YErr, kfvtx3body::ZErr, + kfvtx3body::Px, kfvtx3body::Py, kfvtx3body::Pz, kfvtx3body::Pt, + kfvtx3body::PxErr, kfvtx3body::PyErr, kfvtx3body::PzErr, kfvtx3body::PtErr, + kfvtx3body::Sign, + kfvtx3body::DCAVtxToPVKF, kfvtx3body::DCAXYVtxToPVKF, + kfvtx3body::VtxCosPAKF, kfvtx3body::VtxCosXYPAKF, + kfvtx3body::VtxCosPAKFtopo, kfvtx3body::VtxCosXYPAKFtopo, + kfvtx3body::DecayLKF, kfvtx3body::DecayLXYKF, kfvtx3body::DecayLDeltaL, + kfvtx3body::Chi2geoNDF, kfvtx3body::Chi2topoNDF, + kfvtx3body::CTauKFtopo, kfvtx3body::TrackedClSize, + + // V0 + kfvtx3body::MassV0, kfvtx3body::Chi2MassV0, + kfvtx3body::CosPAV0, + + // daughters + vtx3body::PxTrack0, vtx3body::PyTrack0, vtx3body::PzTrack0, // proton + vtx3body::PxTrack1, vtx3body::PyTrack1, vtx3body::PzTrack1, // pion + vtx3body::PxTrack2, vtx3body::PyTrack2, vtx3body::PzTrack2, // deuteron + kfvtx3body::TPCInnerParamTrack0, kfvtx3body::TPCInnerParamTrack1, kfvtx3body::TPCInnerParamTrack2, // proton, pion, deuteron + kfvtx3body::TPCNClTrack0, kfvtx3body::TPCNClTrack1, kfvtx3body::TPCNClTrack2, // proton, pion, deuteron + kfvtx3body::TPCChi2NClDeuteron, + kfvtx3body::DeltaPhiDeuteron, kfvtx3body::DeltaPhiProton, + kfvtx3body::DCATrack0ToPVKF, kfvtx3body::DCATrack1ToPVKF, kfvtx3body::DCATrack2ToPVKF, kfvtx3body::DCAxyTrack0ToPVKF, kfvtx3body::DCAxyTrack1ToPVKF, kfvtx3body::DCAxyTrack2ToPVKF, + kfvtx3body::DCAxyTrack0ToSVKF, kfvtx3body::DCAxyTrack1ToSVKF, kfvtx3body::DCAxyTrack2ToSVKF, + kfvtx3body::DCATrack0ToTrack1KF, kfvtx3body::DCATrack0ToTrack2KF, kfvtx3body::DCATrack1ToTrack2KF, + kfvtx3body::DCAVtxDaughtersKF, + kfvtx3body::DCAxyTrackPosToPV, kfvtx3body::DCAxyTrackNegToPV, kfvtx3body::DCAxyTrackBachToPV, + kfvtx3body::DCATrackPosToPV, kfvtx3body::DCATrackNegToPV, kfvtx3body::DCATrackBachToPV, + kfvtx3body::Track0Sign, kfvtx3body::Track1Sign, kfvtx3body::Track2Sign, // track sing: proton, pion, deuteron + kfvtx3body::TPCNSigmaProton, kfvtx3body::TPCNSigmaPion, kfvtx3body::TPCNSigmaDeuteron, kfvtx3body::TPCNSigmaPionBach, + kfvtx3body::TPCdEdxProton, kfvtx3body::TPCdEdxPion, kfvtx3body::TPCdEdxDeuteron, + kfvtx3body::TOFNSigmaDeuteron, + kfvtx3body::ITSClusSizeDeuteron, + kfvtx3body::PIDTrackingDeuteron); + +using KFVtx3BodyData = KFVtx3BodyDatas::iterator; +namespace kfvtx3body +{ +DECLARE_SOA_INDEX_COLUMN(KFVtx3BodyData, kfvtx3BodyData); //! Index to KFVtx3BodyData entry +} + +DECLARE_SOA_TABLE(KFDecay3BodyDataLink, "AOD", "KF3BODYLINK", //! Joinable table with Decay3bodys which links to KFVtx3BodyData which is not produced for all entries + kfvtx3body::KFVtx3BodyDataId); + +using KFDecay3BodysLinked = soa::Join; +using KFDecay3BodyLinked = KFDecay3BodysLinked::iterator; + +// Lite data candidate table for analysis +DECLARE_SOA_TABLE(KFVtx3BodyDatasLite, "AOD", "KF3BODYLITE", + o2::soa::Index<>, + // hypertriton candidate + kfvtx3body::Mass, + vtx3body::X, vtx3body::Y, vtx3body::Z, + kfvtx3body::Px, kfvtx3body::Py, kfvtx3body::Pz, kfvtx3body::Pt, + kfvtx3body::Sign, + kfvtx3body::DCAVtxToPVKF, kfvtx3body::DCAXYVtxToPVKF, + kfvtx3body::VtxCosPAKF, kfvtx3body::VtxCosXYPAKF, + kfvtx3body::DecayLKF, kfvtx3body::DecayLXYKF, kfvtx3body::DecayLDeltaL, + kfvtx3body::Chi2geoNDF, kfvtx3body::Chi2topoNDF, + kfvtx3body::CTauKFtopo, kfvtx3body::TrackedClSize, + + // V0 + kfvtx3body::MassV0, + kfvtx3body::CosPAV0, + + // daughters + vtx3body::PxTrack0, vtx3body::PyTrack0, vtx3body::PzTrack0, // proton + vtx3body::PxTrack1, vtx3body::PyTrack1, vtx3body::PzTrack1, // pion + vtx3body::PxTrack2, vtx3body::PyTrack2, vtx3body::PzTrack2, // deuteron + kfvtx3body::TPCInnerParamTrack0, kfvtx3body::TPCInnerParamTrack1, kfvtx3body::TPCInnerParamTrack2, // proton, pion, deuteron + kfvtx3body::TPCNClTrack0, kfvtx3body::TPCNClTrack1, kfvtx3body::TPCNClTrack2, // proton, pion, deuteron + kfvtx3body::TPCChi2NClDeuteron, + kfvtx3body::DeltaPhiDeuteron, kfvtx3body::DeltaPhiProton, + kfvtx3body::DCATrack0ToPVKF, kfvtx3body::DCATrack1ToPVKF, kfvtx3body::DCATrack2ToPVKF, kfvtx3body::DCAxyTrack0ToPVKF, kfvtx3body::DCAxyTrack1ToPVKF, kfvtx3body::DCAxyTrack2ToPVKF, + kfvtx3body::DCAxyTrack0ToSVKF, kfvtx3body::DCAxyTrack1ToSVKF, kfvtx3body::DCAxyTrack2ToSVKF, + kfvtx3body::DCATrack0ToTrack1KF, kfvtx3body::DCATrack0ToTrack2KF, kfvtx3body::DCATrack1ToTrack2KF, + kfvtx3body::DCAVtxDaughtersKF, + kfvtx3body::Track0Sign, kfvtx3body::Track1Sign, kfvtx3body::Track2Sign, // track sing: proton, pion, deuteron + kfvtx3body::TPCNSigmaProton, kfvtx3body::TPCNSigmaPion, kfvtx3body::TPCNSigmaDeuteron, kfvtx3body::TPCNSigmaPionBach, + kfvtx3body::TOFNSigmaDeuteron, + kfvtx3body::ITSClusSizeDeuteron, + kfvtx3body::PIDTrackingDeuteron); + +using KFVtx3BodyDataLite = KFVtx3BodyDatasLite::iterator; + +// MC candidate table for analysis +DECLARE_SOA_TABLE(McKFVtx3BodyDatas, "AOD", "MCKF3BODYDATAS", + o2::soa::Index<>, + // hypertriton candidate + kfvtx3body::Mass, + vtx3body::X, vtx3body::Y, vtx3body::Z, + kfvtx3body::XErr, kfvtx3body::YErr, kfvtx3body::ZErr, + kfvtx3body::Px, kfvtx3body::Py, kfvtx3body::Pz, kfvtx3body::Pt, + kfvtx3body::PxErr, kfvtx3body::PyErr, kfvtx3body::PzErr, kfvtx3body::PtErr, + kfvtx3body::Sign, + kfvtx3body::DCAVtxToPVKF, kfvtx3body::DCAXYVtxToPVKF, + kfvtx3body::VtxCosPAKF, kfvtx3body::VtxCosXYPAKF, + kfvtx3body::VtxCosPAKFtopo, kfvtx3body::VtxCosXYPAKFtopo, + kfvtx3body::DecayLKF, kfvtx3body::DecayLXYKF, kfvtx3body::DecayLDeltaL, + kfvtx3body::Chi2geoNDF, kfvtx3body::Chi2topoNDF, + kfvtx3body::CTauKFtopo, kfvtx3body::TrackedClSize, + + // V0 + kfvtx3body::MassV0, kfvtx3body::Chi2MassV0, + kfvtx3body::CosPAV0, + + // daughters + vtx3body::PxTrack0, vtx3body::PyTrack0, vtx3body::PzTrack0, // proton + vtx3body::PxTrack1, vtx3body::PyTrack1, vtx3body::PzTrack1, // pion + vtx3body::PxTrack2, vtx3body::PyTrack2, vtx3body::PzTrack2, // deuteron + kfvtx3body::TPCInnerParamTrack0, kfvtx3body::TPCInnerParamTrack1, kfvtx3body::TPCInnerParamTrack2, // proton, pion, deuteron + kfvtx3body::TPCNClTrack0, kfvtx3body::TPCNClTrack1, kfvtx3body::TPCNClTrack2, // proton, pion, deuteron + kfvtx3body::TPCChi2NClDeuteron, + kfvtx3body::DeltaPhiDeuteron, kfvtx3body::DeltaPhiProton, + kfvtx3body::DCATrack0ToPVKF, kfvtx3body::DCATrack1ToPVKF, kfvtx3body::DCATrack2ToPVKF, kfvtx3body::DCAxyTrack0ToPVKF, kfvtx3body::DCAxyTrack1ToPVKF, kfvtx3body::DCAxyTrack2ToPVKF, + kfvtx3body::DCAxyTrack0ToSVKF, kfvtx3body::DCAxyTrack1ToSVKF, kfvtx3body::DCAxyTrack2ToSVKF, + kfvtx3body::DCATrack0ToTrack1KF, kfvtx3body::DCATrack0ToTrack2KF, kfvtx3body::DCATrack1ToTrack2KF, + kfvtx3body::DCAVtxDaughtersKF, + kfvtx3body::DCAxyTrackPosToPV, kfvtx3body::DCAxyTrackNegToPV, kfvtx3body::DCAxyTrackBachToPV, + kfvtx3body::DCATrackPosToPV, kfvtx3body::DCATrackNegToPV, kfvtx3body::DCATrackBachToPV, + kfvtx3body::Track0Sign, kfvtx3body::Track1Sign, kfvtx3body::Track2Sign, // track sing: proton, pion, deuteron + kfvtx3body::TPCNSigmaProton, kfvtx3body::TPCNSigmaPion, kfvtx3body::TPCNSigmaDeuteron, kfvtx3body::TPCNSigmaPionBach, + kfvtx3body::TPCdEdxProton, kfvtx3body::TPCdEdxPion, kfvtx3body::TPCdEdxDeuteron, + kfvtx3body::TOFNSigmaDeuteron, + kfvtx3body::ITSClusSizeDeuteron, + kfvtx3body::PIDTrackingDeuteron, + + // MC information + kfvtx3body::GenP, + kfvtx3body::GenPt, + kfvtx3body::GenDecVtxX, kfvtx3body::GenDecVtxY, kfvtx3body::GenDecVtxZ, + kfvtx3body::GenCtau, + kfvtx3body::GenPhi, + kfvtx3body::GenEta, + kfvtx3body::GenRapidity, + kfvtx3body::GenPosP, kfvtx3body::GenPosPt, + kfvtx3body::GenNegP, kfvtx3body::GenNegPt, + kfvtx3body::GenBachP, kfvtx3body::GenBachPt, + kfvtx3body::IsTrueH3L, kfvtx3body::IsTrueAntiH3L, + kfvtx3body::PdgCodeDau0, kfvtx3body::PdgCodeDau1, kfvtx3body::PdgCodeDau2, + kfvtx3body::IsBachPrimary, + kfvtx3body::IsReco, + kfvtx3body::SurvEvSel); + +// Definition of labels for KFVtx3BodyDatas +namespace mckfvtx3bodylabel +{ +DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! MC particle for KF Vtx3BodyDatas +} // namespace mckfvtx3bodylabel + +DECLARE_SOA_TABLE(McKFVtx3BodyLabels, "AOD", "MCKFVTXLABEL", //! Table joinable with KFVtx3BodyData containing the MC labels + mckfvtx3bodylabel::McParticleId); +using McKFVtx3BodyLabel = McKFVtx3BodyLabels::iterator; + +// Definition of labels for KFDecay3Bodys // Full table, joinable with KFDecay3Bodys (CAUTION: NOT WITH Vtx3BodyDATA) +namespace mcfullkfvtx3bodylabel +{ +DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! MC particle for Decay3Bodys +} // namespace mcfullkfvtx3bodylabel + +DECLARE_SOA_TABLE(McFullKFVtx3BodyLabels, "AOD", "MCFULLKFLABEL", //! Table joinable with Decay3Bodys (CAUTION: NOT WITH Vtx3BodyDATA) + mcfullkfvtx3bodylabel::McParticleId); +using McFullKFVtx3BodyLabel = McFullKFVtx3BodyLabels::iterator; } // namespace o2::aod #endif // PWGLF_DATAMODEL_VTX3BODYTABLES_H_ diff --git a/PWGLF/DataModel/cascqaanalysis.h b/PWGLF/DataModel/cascqaanalysis.h index 3eced8d6b77..efe98908517 100644 --- a/PWGLF/DataModel/cascqaanalysis.h +++ b/PWGLF/DataModel/cascqaanalysis.h @@ -25,10 +25,8 @@ #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Centrality.h" #include "TRandom.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; +#include "Math/Vector4D.h" +#include "Math/Boost.h" namespace o2::aod { @@ -43,6 +41,8 @@ enum EvFlags : uint8_t { }; DECLARE_SOA_COLUMN(CollisionZ, zcoll, float); +DECLARE_SOA_COLUMN(CentFT0M, centFT0M, float); +DECLARE_SOA_COLUMN(CentFV0A, centFV0A, float); DECLARE_SOA_COLUMN(MultFT0M, multFT0M, float); DECLARE_SOA_COLUMN(MultFV0A, multFV0A, float); DECLARE_SOA_COLUMN(Sign, sign, int); @@ -100,6 +100,8 @@ DECLARE_SOA_COLUMN(IsPrimary, isPrimary, int); //! -1 unkn DECLARE_SOA_COLUMN(BachBaryonCosPA, bachBaryonCosPA, float); //! avoid bach-baryon correlated inv mass structure in analysis DECLARE_SOA_COLUMN(BachBaryonDCAxyToPV, bachBaryonDCAxyToPV, float); //! avoid bach-baryon correlated inv mass structure in analysis DECLARE_SOA_COLUMN(EventSelFilterBitMask, eventSelFilterBitMask, uint8_t); +DECLARE_SOA_COLUMN(GenPt, genPt, float); +DECLARE_SOA_COLUMN(GenY, genY, float); DECLARE_SOA_DYNAMIC_COLUMN(IsINEL, isINEL, //! True if the Event belongs to the INEL event class [](uint8_t flags) -> bool { return (flags & EvFlags::EvINEL) == EvFlags::EvINEL; }); @@ -115,20 +117,35 @@ namespace cascadesflow DECLARE_SOA_COLUMN(CentFT0A, centFT0A, float); DECLARE_SOA_COLUMN(CentFT0C, centFT0C, float); DECLARE_SOA_COLUMN(CentFT0M, centFT0M, float); -DECLARE_SOA_COLUMN(Sign, sign, int); +DECLARE_SOA_COLUMN(IsNoCollInTimeRange, isNoCollInTimeRange, bool); +DECLARE_SOA_COLUMN(IsNoCollInRof, isNoCollInRof, bool); +DECLARE_SOA_COLUMN(HasEventPlane, hasEventPlane, bool); +DECLARE_SOA_COLUMN(HasSpectatorPlane, hasSpectatorPlane, bool); +DECLARE_SOA_COLUMN(Sign, sign, int16_t); DECLARE_SOA_COLUMN(Pt, pt, float); DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(MassLambda, masslambda, float); DECLARE_SOA_COLUMN(MassXi, massxi, float); DECLARE_SOA_COLUMN(MassOmega, massomega, float); -DECLARE_SOA_COLUMN(V2A, v2A, float); -DECLARE_SOA_COLUMN(V2C, v2C, float); +DECLARE_SOA_COLUMN(V2CEP, v2CEP, float); +DECLARE_SOA_COLUMN(V2CSP, v2CSP, float); +DECLARE_SOA_COLUMN(V1SPzdcA, v1SPzdcA, float); +DECLARE_SOA_COLUMN(V1SPzdcC, v1SPzdcC, float); +DECLARE_SOA_COLUMN(PsiT0C, psiT0C, float); DECLARE_SOA_COLUMN(BDTResponseXi, bdtResponseXi, float); DECLARE_SOA_COLUMN(BDTResponseOmega, bdtResponseOmega, float); +DECLARE_SOA_COLUMN(CosThetaStarLambdaFromOmega, cosThetaStarLambdaFromOmega, float); +DECLARE_SOA_COLUMN(CosThetaStarLambdaFromXi, cosThetaStarLambdaFromXi, float); +DECLARE_SOA_COLUMN(CosThetaStarProton, cosThetaStarProton, float); } // namespace cascadesflow DECLARE_SOA_TABLE(MyCascades, "AOD", "MYCASCADES", o2::soa::Index<>, - mycascades::CollisionZ, mycascades::MultFT0M, mycascades::MultFV0A, mycascades::Sign, mycascades::Pt, mycascades::RapXi, mycascades::RapOmega, mycascades::Eta, mycascades::MassXi, mycascades::MassOmega, mycascades::MassLambdaDau, mycascades::CascRadius, mycascades::V0Radius, + mycascades::CollisionZ, + mycascades::CentFT0M, mycascades::CentFV0A, + mycascades::MultFT0M, mycascades::MultFV0A, + mycascades::Sign, mycascades::Pt, mycascades::RapXi, mycascades::RapOmega, mycascades::Eta, mycascades::MassXi, mycascades::MassOmega, mycascades::MassLambdaDau, mycascades::CascRadius, mycascades::V0Radius, mycascades::CascCosPA, mycascades::V0CosPA, mycascades::DCAPosToPV, mycascades::DCANegToPV, mycascades::DCABachToPV, mycascades::DCACascDaughters, mycascades::DCAV0Daughters, mycascades::DCAV0ToPV, mycascades::PosEta, mycascades::NegEta, mycascades::BachEta, mycascades::PosITSHits, mycascades::NegITSHits, mycascades::BachITSHits, @@ -143,6 +160,8 @@ DECLARE_SOA_TABLE(MyCascades, "AOD", "MYCASCADES", o2::soa::Index<>, mycascades::McPdgCode, mycascades::IsPrimary, mycascades::BachBaryonCosPA, mycascades::BachBaryonDCAxyToPV, mycascades::EventSelFilterBitMask, + mycascades::GenPt, + mycascades::GenY, mycascades::IsINEL, mycascades::IsINELgt0, mycascades::IsINELgt1); @@ -152,7 +171,7 @@ DECLARE_SOA_TABLE(CascTraining, "AOD", "CascTraining", o2::soa::Index<>, mycascades::DCABachToPV, mycascades::DCACascDaughters, mycascades::DCAV0Daughters, mycascades::DCAV0ToPV, mycascades::BachBaryonCosPA, mycascades::BachBaryonDCAxyToPV, mycascades::McPdgCode); DECLARE_SOA_TABLE(CascAnalysis, "AOD", "CascAnalysis", o2::soa::Index<>, - cascadesflow::CentFT0C, cascadesflow::Sign, cascadesflow::Pt, cascadesflow::Eta, cascadesflow::MassXi, cascadesflow::MassOmega, cascadesflow::V2C, cascadesflow::BDTResponseXi, cascadesflow::BDTResponseOmega); + cascadesflow::CentFT0C, cascadesflow::IsNoCollInTimeRange, cascadesflow::IsNoCollInRof, cascadesflow::HasEventPlane, cascadesflow::HasSpectatorPlane, cascadesflow::Sign, cascadesflow::Pt, cascadesflow::Eta, cascadesflow::Phi, cascadesflow::MassLambda, cascadesflow::MassXi, cascadesflow::MassOmega, cascadesflow::V2CSP, cascadesflow::V2CEP, cascadesflow::V1SPzdcA, cascadesflow::V1SPzdcC, cascadesflow::PsiT0C, cascadesflow::BDTResponseXi, cascadesflow::BDTResponseOmega, cascadesflow::CosThetaStarLambdaFromOmega, cascadesflow::CosThetaStarLambdaFromXi, cascadesflow::CosThetaStarProton, mycascades::McPdgCode); namespace myMCcascades { @@ -173,6 +192,9 @@ DECLARE_SOA_COLUMN(Pt, pt, float); DECLARE_SOA_COLUMN(IsPrimary, isPrimary, bool); DECLARE_SOA_COLUMN(NAssocColl, nAssocColl, int); // Number of reconstructed collisions assoceated to the generated one of this cascade DECLARE_SOA_COLUMN(NChInFT0M, nChInFT0M, float); // Number of charged particles in FT0M acceptance +DECLARE_SOA_COLUMN(NChInFV0A, nChInFV0A, float); // Number of charged particles in FV0A acceptance +DECLARE_SOA_COLUMN(CentFT0M, centFT0M, float); // centr. (mult.) % FT0M +DECLARE_SOA_COLUMN(CentFV0A, centFV0A, float); // centr. (mult.) % FV0A DECLARE_SOA_COLUMN(AssCollisionTypeFilterBitMask, assCollisionTypeFilterBitMask, uint8_t); DECLARE_SOA_COLUMN(McCollisionTypeFilterBitMask, mcCollisionTypeFilterBitMask, uint8_t); @@ -194,7 +216,9 @@ DECLARE_SOA_DYNAMIC_COLUMN(IsINELgt1, isINELgt1, //! True if the Event belongs t DECLARE_SOA_TABLE(MyMCCascades, "AOD", "MYMCCASCADES", o2::soa::Index<>, myMCcascades::CollisionZ, myMCcascades::Sign, myMCcascades::PdgCode, myMCcascades::Y, myMCcascades::Eta, myMCcascades::Phi, myMCcascades::Pt, - myMCcascades::IsPrimary, myMCcascades::NAssocColl, myMCcascades::NChInFT0M, + myMCcascades::IsPrimary, myMCcascades::NAssocColl, + myMCcascades::NChInFT0M, myMCcascades::NChInFV0A, + myMCcascades::CentFT0M, myMCcascades::CentFV0A, myMCcascades::AssCollisionTypeFilterBitMask, myMCcascades::McCollisionTypeFilterBitMask, myMCcascades::IsINELassoc, diff --git a/PWGLF/DataModel/lambdaJetpolarization.h b/PWGLF/DataModel/lambdaJetpolarization.h new file mode 100644 index 00000000000..41bd7e26b15 --- /dev/null +++ b/PWGLF/DataModel/lambdaJetpolarization.h @@ -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 QA task for lambda polarization induced by jet analysis using derived data +/// +/// \author Youpeng Su (yousu@cern.ch) + +#ifndef PWGLF_DATAMODEL_LAMBDAJETPOLARIZATION_H_ +#define PWGLF_DATAMODEL_LAMBDAJETPOLARIZATION_H_ + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "TRandom.h" +#include "Math/Vector4D.h" +#include "Math/Boost.h" + +namespace o2::aod +{ +DECLARE_SOA_TABLE(MyCollisions, "AOD", "MYCOLLISION", //! vertex information of collision + o2::soa::Index<>, collision::PosZ); +using MyCollision = MyCollisions::iterator; + +DECLARE_SOA_TABLE(MyCollisionsV0, "AOD", "MYCOLLISIONV0", //! vertex information of collision + o2::soa::Index<>, collision::PosX); +using MyCollisionV0s = MyCollisionsV0::iterator; + +namespace myTable +{ +DECLARE_SOA_INDEX_COLUMN(MyCollision, mycollision); +DECLARE_SOA_COLUMN(MyCollisionV0, mycollisionv0, Int_t); +DECLARE_SOA_COLUMN(V0px, v0px, Float_t); +DECLARE_SOA_COLUMN(V0py, v0py, Float_t); +DECLARE_SOA_COLUMN(V0pz, v0pz, Float_t); +DECLARE_SOA_COLUMN(V0pT, v0pt, Float_t); +DECLARE_SOA_COLUMN(V0Lambdamass, v0Lambdamass, Float_t); +DECLARE_SOA_COLUMN(V0protonpx, v0protonpx, Float_t); +DECLARE_SOA_COLUMN(V0protonpy, v0protonpy, Float_t); +DECLARE_SOA_COLUMN(V0protonpz, v0protonpz, Float_t); +DECLARE_SOA_COLUMN(MyCollisionJet, mycollisionjet, Int_t); +DECLARE_SOA_COLUMN(Jetpx, jetpx, Float_t); +DECLARE_SOA_COLUMN(Jetpy, jetpy, Float_t); +DECLARE_SOA_COLUMN(Jetpz, jetpz, Float_t); +DECLARE_SOA_COLUMN(JetpT, jetpt, Float_t); +DECLARE_SOA_COLUMN(MyCollisionLeadingJet, mycollisionleadingjet, Int_t); +DECLARE_SOA_COLUMN(LeadingJetpx, leadingjetpx, Float_t); +DECLARE_SOA_COLUMN(LeadingJetpy, leadingjetpy, Float_t); +DECLARE_SOA_COLUMN(LeadingJetpz, leadingjetpz, Float_t); +DECLARE_SOA_COLUMN(LeadingJetpT, leadingjetpt, Float_t); + +} // namespace myTable + +DECLARE_SOA_TABLE(MyTable, "AOD", "MYTABLE", o2::soa::Index<>, + myTable::MyCollisionId, myTable::MyCollisionV0, myTable::V0px, myTable::V0py, myTable::V0pz, myTable::V0pT, myTable::V0Lambdamass, + myTable::V0protonpx, myTable::V0protonpy, myTable::V0protonpz); + +DECLARE_SOA_TABLE(MyTableAnti, "AOD", "MYTABLEAnti", o2::soa::Index<>, + myTable::MyCollisionId, myTable::MyCollisionV0, myTable::V0px, myTable::V0py, myTable::V0pz, myTable::V0pT, myTable::V0Lambdamass, + myTable::V0protonpx, myTable::V0protonpy, myTable::V0protonpz); + +DECLARE_SOA_TABLE(MyTableJet, "AOD", "MYTABLEJet", o2::soa::Index<>, + myTable::MyCollisionId, myTable::MyCollisionJet, myTable::Jetpx, myTable::Jetpy, myTable::Jetpz, myTable::JetpT); + +DECLARE_SOA_TABLE(MyTableLeadingJet, "AOD", "LeadingJet", o2::soa::Index<>, myTable::MyCollisionId, myTable::MyCollisionLeadingJet, myTable::LeadingJetpx, myTable::LeadingJetpy, myTable::LeadingJetpz, myTable::LeadingJetpT); + +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_LAMBDAJETPOLARIZATION_H_ diff --git a/PWGLF/DataModel/mcCentrality.h b/PWGLF/DataModel/mcCentrality.h new file mode 100644 index 00000000000..86e97eb8c33 --- /dev/null +++ b/PWGLF/DataModel/mcCentrality.h @@ -0,0 +1,47 @@ +// 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 mcCentrality.h +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \author Francesca Ercolessi francesca.ercolessi@cern.ch +/// \since 2024-06-05 +/// \brief Set of tables for the MC centrality +/// + +#ifndef PWGLF_DATAMODEL_MCCENTRALITY_H_ +#define PWGLF_DATAMODEL_MCCENTRALITY_H_ + +// O2 includes +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/Centrality.h" +#include "Framework/Logger.h" + +namespace o2::aod +{ +// DECLARE_SOA_TABLE(CentFV0As, "AOD", "CENTFV0A", cent::CentFV0A); //! Run3 FV0A estimated centrality table +// DECLARE_SOA_TABLE(CentFT0Ms, "AOD", "CENTFT0M", cent::CentFT0M); //! Run3 FT0M estimated centrality table +// DECLARE_SOA_TABLE(CentFT0As, "AOD", "CENTFT0A", cent::CentFT0A); //! Run3 FT0A estimated centrality table +// DECLARE_SOA_TABLE(CentFT0Cs, "AOD", "CENTFT0C", cent::CentFT0C); //! Run3 FT0C estimated centrality table +// DECLARE_SOA_TABLE(CentFDDMs, "AOD", "CENTFDDM", cent::CentFDDM); //! Run3 FDDM estimated centrality table +// DECLARE_SOA_TABLE(CentNTPVs, "AOD", "CENTNTPV", cent::CentNTPV); //! Run3 NTPV estimated centrality table + +DECLARE_SOA_TABLE(McCentFV0As, "AOD", "MCCENTFV0A", o2::soa::Marker<1>, cent::CentFV0A); +DECLARE_SOA_TABLE(McCentFT0Ms, "AOD", "MCCENTFT0M", o2::soa::Marker<2>, cent::CentFT0M); +DECLARE_SOA_TABLE(McCentFT0As, "AOD", "MCCENTFT0A", o2::soa::Marker<3>, cent::CentFT0A); +DECLARE_SOA_TABLE(McCentFT0Cs, "AOD", "MCCENTFT0C", o2::soa::Marker<4>, cent::CentFT0C); +DECLARE_SOA_TABLE(McCentFDDMs, "AOD", "MCCENTFDDM", o2::soa::Marker<5>, cent::CentFDDM); +DECLARE_SOA_TABLE(McCentNTPVs, "AOD", "MCCENTNTPV", o2::soa::Marker<6>, cent::CentNTPV); + +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_MCCENTRALITY_H_ diff --git a/PWGLF/DataModel/pidTOFGeneric.h b/PWGLF/DataModel/pidTOFGeneric.h new file mode 100644 index 00000000000..a0d287a7643 --- /dev/null +++ b/PWGLF/DataModel/pidTOFGeneric.h @@ -0,0 +1,220 @@ +// 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. + +#ifndef PWGLF_DATAMODEL_PIDTOFGENERIC_H_ +#define PWGLF_DATAMODEL_PIDTOFGENERIC_H_ +#include "CommonDataFormat/InteractionRecord.h" +#include "Common/Core/PID/PIDTOF.h" + +namespace o2::aod +{ +namespace evtime +{ + +DECLARE_SOA_COLUMN(EvTime, evTime, float); //! Event time. Can be obtained via a combination of detectors e.g. TOF, FT0A, FT0C +DECLARE_SOA_COLUMN(EvTimeErr, evTimeErr, float); //! Error of event time. Can be obtained via a combination of detectors e.g. TOF, FT0A, FT0C +DECLARE_SOA_COLUMN(EvTimeTOF, evTimeTOF, float); //! Event time computed with the TOF detector +DECLARE_SOA_COLUMN(EvTimeTOFErr, evTimeTOFErr, float); //! Error of the event time computed with the TOF detector +DECLARE_SOA_COLUMN(EvTimeFT0, evTimeFT0, float); //! Event time computed with the FT0 detector +DECLARE_SOA_COLUMN(EvTimeFT0Err, evTimeFT0Err, float); //! Error of the event time computed with the FT0 detector +} // namespace evtime + +DECLARE_SOA_TABLE(EvTimeTOFFT0, "AOD", "EvTimeTOFFT0", //! Table of the event time. One entry per collision. + evtime::EvTime, + evtime::EvTimeErr, + evtime::EvTimeTOF, + evtime::EvTimeTOFErr, + evtime::EvTimeFT0, + evtime::EvTimeFT0Err); + +namespace tracktime +{ + +DECLARE_SOA_COLUMN(EvTimeForTrack, evTimeForTrack, float); //! Event time. Removed the bias for the specific track +DECLARE_SOA_COLUMN(EvTimeErrForTrack, evTimeErrForTrack, float); //! Error of event time. Removed the bias for the specific track +} // namespace tracktime + +DECLARE_SOA_TABLE(EvTimeTOFFT0ForTrack, "AOD", "EvTimeForTrack", //! Table of the event time. One entry per track. + tracktime::EvTimeForTrack, + tracktime::EvTimeErrForTrack); + +namespace pidtofgeneric +{ + +static constexpr float kCSPEED = TMath::C() * 1.0e2f * 1.0e-12f; // c in cm/ps + +template +class TofPidNewCollision +{ + public: + TofPidNewCollision() = default; + ~TofPidNewCollision() = default; + + o2::pid::tof::TOFResoParamsV2 mRespParamsV2; + o2::track::PID::ID pidType; + + template + using ResponseImplementation = o2::pid::tof::ExpTimes; + static constexpr auto responseEl = ResponseImplementation(); + static constexpr auto responseMu = ResponseImplementation(); + static constexpr auto responsePi = ResponseImplementation(); + static constexpr auto responseKa = ResponseImplementation(); + static constexpr auto responsePr = ResponseImplementation(); + static constexpr auto responseDe = ResponseImplementation(); + static constexpr auto responseTr = ResponseImplementation(); + static constexpr auto responseHe = ResponseImplementation(); + static constexpr auto responseAl = ResponseImplementation(); + + void SetParams(o2::pid::tof::TOFResoParamsV2 const& para) + { + mRespParamsV2.setParameters(para); + } + + void SetPidType(o2::track::PID::ID pidId) + { + pidType = pidId; + } + + template + float GetTOFNSigma(o2::track::PID::ID pidId, TTrack const& track, TCollision const& originalcol, TCollision const& correctedcol, bool EnableBCAO2D = true); + + template + float GetTOFNSigma(TTrack const& track, TCollision const& originalcol, TCollision const& correctedcol, bool EnableBCAO2D = true); + + float GetTOFNSigma(TTrack const& track); + float GetTOFNSigma(o2::track::PID::ID pidId, TTrack const& track); + + float CalculateTOFNSigma(o2::track::PID::ID pidId, TTrack const& track, double tofsignal, double evTime, double evTimeErr) + { + + float expSigma, tofNsigma = -999; + + switch (pidId) { + case 0: + expSigma = responseEl.GetExpectedSigma(mRespParamsV2, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responseEl.GetCorrectedExpectedSignal(mRespParamsV2, track)) / expSigma; + break; + case 1: + expSigma = responseMu.GetExpectedSigma(mRespParamsV2, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responseMu.GetCorrectedExpectedSignal(mRespParamsV2, track)) / expSigma; + break; + case 2: + expSigma = responsePi.GetExpectedSigma(mRespParamsV2, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responsePi.GetCorrectedExpectedSignal(mRespParamsV2, track)) / expSigma; + break; + case 3: + expSigma = responseKa.GetExpectedSigma(mRespParamsV2, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responseKa.GetCorrectedExpectedSignal(mRespParamsV2, track)) / expSigma; + break; + case 4: + expSigma = responsePr.GetExpectedSigma(mRespParamsV2, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responsePr.GetCorrectedExpectedSignal(mRespParamsV2, track)) / expSigma; + break; + case 5: + expSigma = responseDe.GetExpectedSigma(mRespParamsV2, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responseDe.GetCorrectedExpectedSignal(mRespParamsV2, track)) / expSigma; + break; + case 6: + expSigma = responseTr.GetExpectedSigma(mRespParamsV2, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responseTr.GetCorrectedExpectedSignal(mRespParamsV2, track)) / expSigma; + break; + case 7: + expSigma = responseHe.GetExpectedSigma(mRespParamsV2, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responseHe.GetCorrectedExpectedSignal(mRespParamsV2, track)) / expSigma; + break; + case 8: + expSigma = responseAl.GetExpectedSigma(mRespParamsV2, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responseAl.GetCorrectedExpectedSignal(mRespParamsV2, track)) / expSigma; + break; + default: + LOG(fatal) << "Wrong particle ID in TofPidSecondary class"; + return -999; + } + + return tofNsigma; + } +}; + +template +template +float TofPidNewCollision::GetTOFNSigma(o2::track::PID::ID pidId, TTrack const& track, TCollision const& originalcol, TCollision const& correctedcol, bool EnableBCAO2D) +{ + + if (!track.has_collision() || !track.hasTOF()) { + return -999; + } + + float mMassHyp = o2::track::pid_constants::sMasses2Z[track.pidForTracking()]; + float expTime = track.length() * sqrt((mMassHyp * mMassHyp) + (track.tofExpMom() * track.tofExpMom())) / (kCSPEED * track.tofExpMom()); // L*E/(p*c) = L/v + + float evTime = correctedcol.evTime(); + float evTimeErr = correctedcol.evTimeErr(); + float tofsignal = track.trackTime() * 1000 + expTime; // in ps + + if (originalcol.globalIndex() == correctedcol.globalIndex()) { + evTime = track.evTimeForTrack(); + evTimeErr = track.evTimeErrForTrack(); + } else { + if (EnableBCAO2D) { + auto originalbc = originalcol.template bc_as(); + auto correctedbc = correctedcol.template bc_as(); + o2::InteractionRecord originalIR = o2::InteractionRecord::long2IR(originalbc.globalBC()); + o2::InteractionRecord correctedIR = o2::InteractionRecord::long2IR(correctedbc.globalBC()); + tofsignal += originalIR.differenceInBCNS(correctedIR) * 1000; + } else { + auto originalbc = originalcol.template foundBC_as(); + auto correctedbc = correctedcol.template foundBC_as(); + o2::InteractionRecord originalIR = o2::InteractionRecord::long2IR(originalbc.globalBC()); + o2::InteractionRecord correctedIR = o2::InteractionRecord::long2IR(correctedbc.globalBC()); + tofsignal += originalIR.differenceInBCNS(correctedIR) * 1000; + } + } + + float tofNsigma = CalculateTOFNSigma(pidId, track, tofsignal, evTime, evTimeErr); + return tofNsigma; +} + +template +template +float TofPidNewCollision::GetTOFNSigma(TTrack const& track, TCollision const& originalcol, TCollision const& correctedcol, bool EnableBCAO2D) +{ + return GetTOFNSigma(pidType, track, originalcol, correctedcol, EnableBCAO2D); +} + +template +float TofPidNewCollision::GetTOFNSigma(o2::track::PID::ID pidId, TTrack const& track) +{ + + if (!track.has_collision() || !track.hasTOF()) { + return -999; + } + + float mMassHyp = o2::track::pid_constants::sMasses2Z[track.pidForTracking()]; + float expTime = track.length() * sqrt((mMassHyp * mMassHyp) + (track.tofExpMom() * track.tofExpMom())) / (kCSPEED * track.tofExpMom()); // L*E/(p*c) = L/v + + float evTime = track.evTimeForTrack(); + float evTimeErr = track.evTimeErrForTrack(); + float tofsignal = track.trackTime() * 1000 + expTime; // in ps + + float tofNsigma = CalculateTOFNSigma(pidId, track, tofsignal, evTime, evTimeErr); + return tofNsigma; +} + +template +float TofPidNewCollision::GetTOFNSigma(TTrack const& track) +{ + return GetTOFNSigma(pidType, track); +} + +} // namespace pidtofgeneric +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_PIDTOFGENERIC_H_ diff --git a/PWGLF/DataModel/spectraTOF.h b/PWGLF/DataModel/spectraTOF.h index 18e229b20cd..9cf4b789295 100644 --- a/PWGLF/DataModel/spectraTOF.h +++ b/PWGLF/DataModel/spectraTOF.h @@ -19,6 +19,8 @@ #ifndef PWGLF_DATAMODEL_SPECTRATOF_H_ #define PWGLF_DATAMODEL_SPECTRATOF_H_ +#include + // O2 includes #include "ReconstructionDataFormats/Track.h" #include "Framework/runDataProcessing.h" @@ -38,19 +40,20 @@ #include "TPDGCode.h" -using namespace o2; -using namespace o2::track; -using namespace o2::framework; -using namespace o2::framework::expressions; - -static constexpr PID::ID Np = 9; -static constexpr PID::ID NpCharge = Np * 2; +static constexpr o2::track::PID::ID Np = 9; +static constexpr int NCharges = 2; +static constexpr o2::track::PID::ID NpCharge = Np * NCharges; static constexpr const char* pT[Np] = {"e", "#mu", "#pi", "K", "p", "d", "t", "{}^{3}He", "#alpha"}; +static constexpr const char* pN[Np] = {"el", "mu", "pi", "ka", "pr", "de", "tr", "he", "al"}; +static constexpr const char* cN[NCharges] = {"pos", "neg"}; static constexpr const char* pTCharge[NpCharge] = {"e^{-}", "#mu^{-}", "#pi^{+}", "K^{+}", "p", "d", "t", "{}^{3}He", "#alpha", "e^{+}", "#mu^{+}", "#pi^{-}", "K^{-}", "#bar{p}", "#bar{d}", "#bar{t}", "{}^{3}#bar{He}", "#bar{#alpha}"}; +static constexpr const char* pNCharge[NpCharge] = {"pos/el", "pos/mu", "pos/pi", "pos/ka", "pos/pr", "pos/de", "pos/tr", "pos/he", "pos/al", + "neg/el", "neg/mu", "neg/pi", "neg/ka", "neg/pr", "neg/de", "neg/tr", "neg/he", "neg/al"}; static constexpr int PDGs[NpCharge] = {kElectron, kMuonMinus, kPiPlus, kKPlus, kProton, 1000010020, 1000010030, 1000020030, 1000020040, -kElectron, -kMuonMinus, -kPiPlus, -kKPlus, -kProton, -1000010020, -1000010030, -1000020030, -1000020040}; +std::shared_ptr hMultiplicityvsPercentile; static constexpr std::string_view hnsigmatpctof[NpCharge] = {"nsigmatpctof/pos/el", "nsigmatpctof/pos/mu", "nsigmatpctof/pos/pi", "nsigmatpctof/pos/ka", "nsigmatpctof/pos/pr", "nsigmatpctof/pos/de", "nsigmatpctof/pos/tr", "nsigmatpctof/pos/he", "nsigmatpctof/pos/al", @@ -136,6 +139,12 @@ static constexpr std::string_view hpt_numtof_prm[NpCharge] = {"MC/el/pos/prm/pt/ "MC/el/neg/prm/pt/numtof", "MC/mu/neg/prm/pt/numtof", "MC/pi/neg/prm/pt/numtof", "MC/ka/neg/prm/pt/numtof", "MC/pr/neg/prm/pt/numtof", "MC/de/neg/prm/pt/numtof", "MC/tr/neg/prm/pt/numtof", "MC/he/neg/prm/pt/numtof", "MC/al/neg/prm/pt/numtof"}; +static constexpr std::string_view hpt_numtofgoodmatch_prm[NpCharge] = {"MC/el/pos/prm/pt/numtofgoodmatch", "MC/mu/pos/prm/pt/numtofgoodmatch", "MC/pi/pos/prm/pt/numtofgoodmatch", + "MC/ka/pos/prm/pt/numtofgoodmatch", "MC/pr/pos/prm/pt/numtofgoodmatch", "MC/de/pos/prm/pt/numtofgoodmatch", + "MC/tr/pos/prm/pt/numtofgoodmatch", "MC/he/pos/prm/pt/numtofgoodmatch", "MC/al/pos/prm/pt/numtofgoodmatch", + "MC/el/neg/prm/pt/numtofgoodmatch", "MC/mu/neg/prm/pt/numtofgoodmatch", "MC/pi/neg/prm/pt/numtofgoodmatch", + "MC/ka/neg/prm/pt/numtofgoodmatch", "MC/pr/neg/prm/pt/numtofgoodmatch", "MC/de/neg/prm/pt/numtofgoodmatch", + "MC/tr/neg/prm/pt/numtofgoodmatch", "MC/he/neg/prm/pt/numtofgoodmatch", "MC/al/neg/prm/pt/numtofgoodmatch"}; //********************************************RD********************************************************************************************** static constexpr std::string_view hpt_numtof_str[NpCharge] = {"MC/el/pos/str/pt/numtof", "MC/mu/pos/str/pt/numtof", "MC/pi/pos/str/pt/numtof", @@ -338,6 +347,10 @@ DECLARE_SOA_DYNAMIC_COLUMN(MultTPC, multTPC, //! Dummy [](bool /*v*/) -> float { return 0.f; }); DECLARE_SOA_DYNAMIC_COLUMN(SelectionBit, selection_bit, //! Dummy [](aod::evsel::EventSelectionFlags /*v*/) -> bool { return true; }); +DECLARE_SOA_DYNAMIC_COLUMN(IsInelGt0, isInelGt0, //! is INEL > 0 + [](int multPveta1) -> bool { return multPveta1 > 0; }); +DECLARE_SOA_DYNAMIC_COLUMN(IsInelGt1, isInelGt1, //! is INEL > 1 + [](int multPveta1) -> bool { return multPveta1 > 1; }); // Track info DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! Index to the collision @@ -387,11 +400,11 @@ DECLARE_SOA_DYNAMIC_COLUMN(TRDSignal, trdSignal, //! Dummy [](float /*v*/) -> float { return 0.f; }); DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float signedpt, float eta) -> float { return std::abs(signedpt) * cosh(eta); }); DECLARE_SOA_DYNAMIC_COLUMN(TrackType, trackType, [](float /*v*/) -> uint8_t { return o2::aod::track::TrackTypeEnum::Track; }); -DECLARE_SOA_COLUMN(IsGlobalTrack, isGlobalTrack, bool); // if a track passed the isGlobalTrack requirement -DECLARE_SOA_COLUMN(IsGlobalTrackWoDCA, isGlobalTrackWoDCA, bool); // if a track passed the isGlobalTrackWoDCA requirement -DECLARE_SOA_DYNAMIC_COLUMN(Flags, flags, [](float /*v*/) -> uint32_t { return 0; }); // Dummy +DECLARE_SOA_COLUMN(IsGlobalTrack, isGlobalTrack, bool); // if a track passed the isGlobalTrack requirement +DECLARE_SOA_COLUMN(IsGlobalTrackWoDCA, isGlobalTrackWoDCA, bool); // if a track passed the isGlobalTrackWoDCA requirement +DECLARE_SOA_DYNAMIC_COLUMN(Flags, flags, [](float /*v*/) -> uint32_t { return 0; }); // Dummy DECLARE_SOA_DYNAMIC_COLUMN(TRDPattern, trdPattern, [](float /*v*/) -> uint8_t { return 0; }); // Dummy -DECLARE_SOA_DYNAMIC_COLUMN(Rapidity, rapidity, //! Track rapidity, computed under the mass assumption given as input +DECLARE_SOA_DYNAMIC_COLUMN(Rapidity, rapidity, //! Track rapidity, computed under the mass assumption given as input [](float signedPt, float eta, float mass) -> float { const auto pt = std::abs(signedPt); const auto p = std::abs(signedPt) * cosh(eta); @@ -415,6 +428,8 @@ DECLARE_SOA_TABLE(SpColls, "AOD", "SPCOLLS", spectra::Sel8, spectra::MultNTracksPVeta1, spectra::RunNumber, + spectra::IsInelGt0, + spectra::IsInelGt1, spectra::CentFV0A, spectra::CentFT0A, spectra::CentFT0C, @@ -506,4 +521,4 @@ struct MultCodes { static constexpr int kNMults = 10; }; -#endif // PWGLF_DATAMODEL_SPECTRATOF_H_ \ No newline at end of file +#endif // PWGLF_DATAMODEL_SPECTRATOF_H_ diff --git a/PWGLF/DataModel/v0qaanalysis.h b/PWGLF/DataModel/v0qaanalysis.h index 3d1b51a5bea..c2b26d3054f 100644 --- a/PWGLF/DataModel/v0qaanalysis.h +++ b/PWGLF/DataModel/v0qaanalysis.h @@ -10,24 +10,20 @@ // or submit itself to any jurisdiction. /// /// \brief QA task for V0 analysis using derived data -/// /// \author Francesca Ercolessi (francesca.ercolessi@cern.ch) #ifndef PWGLF_DATAMODEL_V0QAANALYSIS_H_ #define PWGLF_DATAMODEL_V0QAANALYSIS_H_ -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - namespace o2::aod { namespace myv0candidates { -DECLARE_SOA_INDEX_COLUMN(Collision, collision); DECLARE_SOA_COLUMN(V0Pt, v0pt, float); +DECLARE_SOA_COLUMN(V0MotherPt, v0motherpt, float); +DECLARE_SOA_COLUMN(V0MCRap, v0mcrap, float); DECLARE_SOA_COLUMN(RapLambda, raplambda, float); DECLARE_SOA_COLUMN(RapK0Short, rapk0short, float); DECLARE_SOA_COLUMN(MassLambda, masslambda, float); @@ -40,8 +36,6 @@ DECLARE_SOA_COLUMN(V0DCANegToPV, v0dcanegtopv, float); DECLARE_SOA_COLUMN(V0DCAV0Daughters, v0dcav0daughters, float); DECLARE_SOA_COLUMN(V0PosEta, v0poseta, float); DECLARE_SOA_COLUMN(V0NegEta, v0negeta, float); -DECLARE_SOA_COLUMN(V0PosPhi, v0posphi, float); -DECLARE_SOA_COLUMN(V0NegPhi, v0negphi, float); DECLARE_SOA_COLUMN(V0PosITSHits, v0positshits, float); DECLARE_SOA_COLUMN(V0NegITSHits, v0negitshits, float); DECLARE_SOA_COLUMN(CtauLambda, ctaulambda, float); @@ -58,26 +52,44 @@ DECLARE_SOA_COLUMN(NTOFSigmaPosPi, ntofsigmapospi, float); DECLARE_SOA_COLUMN(PosHasTOF, poshastof, float); DECLARE_SOA_COLUMN(NegHasTOF, neghastof, float); DECLARE_SOA_COLUMN(PDGCode, pdgcode, int); +DECLARE_SOA_COLUMN(PDGCodeMother, pdgcodemother, int); +DECLARE_SOA_COLUMN(IsDauK0Short, isdauk0short, bool); +DECLARE_SOA_COLUMN(IsDauLambda, isdaulambda, bool); +DECLARE_SOA_COLUMN(IsDauAntiLambda, isdauantilambda, bool); DECLARE_SOA_COLUMN(IsPhysicalPrimary, isphysprimary, bool); DECLARE_SOA_COLUMN(MultFT0M, multft0m, float); -DECLARE_SOA_COLUMN(MultFV0A, multfv0a, float); +DECLARE_SOA_COLUMN(MultNGlobals, multnglobals, float); DECLARE_SOA_COLUMN(EvFlag, evflag, int); +DECLARE_SOA_COLUMN(Alpha, alpha, float); +DECLARE_SOA_COLUMN(QtArm, qtarm, float); +DECLARE_SOA_COLUMN(V0PosTPCCrossedRows, v0postpcCrossedRows, float); +DECLARE_SOA_COLUMN(V0PosTPCNClsShared, v0postpcNClsShared, float); +DECLARE_SOA_COLUMN(V0PosITSChi2NCl, v0positsChi2NCl, float); +DECLARE_SOA_COLUMN(V0PosTPCChi2NCl, v0postpcChi2NCl, float); +DECLARE_SOA_COLUMN(V0NegTPCCrossedRows, v0negtpcCrossedRows, float); +DECLARE_SOA_COLUMN(V0NegTPCNClsShared, v0negtpcNClsShared, float); +DECLARE_SOA_COLUMN(V0NegITSChi2NCl, v0negitsChi2NCl, float); +DECLARE_SOA_COLUMN(V0NegTPCChi2NCl, v0negtpcChi2NCl, float); } // namespace myv0candidates -DECLARE_SOA_TABLE(MyV0Candidates, "AOD", "MYV0CANDIDATES", o2::soa::Index<>, - myv0candidates::CollisionId, myv0candidates::V0Pt, myv0candidates::RapLambda, myv0candidates::RapK0Short, +DECLARE_SOA_TABLE(MyV0Candidates, "AOD", "MYV0CANDIDATES", + myv0candidates::V0Pt, myv0candidates::V0MotherPt, myv0candidates::V0MCRap, myv0candidates::RapLambda, myv0candidates::RapK0Short, myv0candidates::MassLambda, myv0candidates::MassAntiLambda, myv0candidates::MassK0Short, myv0candidates::V0Radius, myv0candidates::V0CosPA, myv0candidates::V0DCAPosToPV, myv0candidates::V0DCANegToPV, myv0candidates::V0DCAV0Daughters, - myv0candidates::V0PosEta, myv0candidates::V0NegEta, myv0candidates::V0PosPhi, myv0candidates::V0NegPhi, + myv0candidates::V0PosEta, myv0candidates::V0NegEta, myv0candidates::V0PosITSHits, myv0candidates::V0NegITSHits, myv0candidates::CtauLambda, myv0candidates::CtauAntiLambda, myv0candidates::CtauK0Short, myv0candidates::NTPCSigmaNegPr, myv0candidates::NTPCSigmaPosPr, myv0candidates::NTPCSigmaNegPi, myv0candidates::NTPCSigmaPosPi, myv0candidates::NTOFSigmaNegPr, myv0candidates::NTOFSigmaPosPr, myv0candidates::NTOFSigmaNegPi, myv0candidates::NTOFSigmaPosPi, myv0candidates::PosHasTOF, myv0candidates::NegHasTOF, - myv0candidates::PDGCode, myv0candidates::IsPhysicalPrimary, - myv0candidates::MultFT0M, myv0candidates::MultFV0A, - myv0candidates::EvFlag); + myv0candidates::PDGCode, myv0candidates::PDGCodeMother, myv0candidates::IsDauK0Short, myv0candidates::IsDauLambda, myv0candidates::IsDauAntiLambda, myv0candidates::IsPhysicalPrimary, + myv0candidates::MultFT0M, myv0candidates::MultNGlobals, + myv0candidates::EvFlag, myv0candidates::Alpha, myv0candidates::QtArm, + myv0candidates::V0PosTPCCrossedRows, myv0candidates::V0PosTPCNClsShared, + myv0candidates::V0PosITSChi2NCl, myv0candidates::V0PosTPCChi2NCl, + myv0candidates::V0NegTPCCrossedRows, myv0candidates::V0NegTPCNClsShared, + myv0candidates::V0NegITSChi2NCl, myv0candidates::V0NegTPCChi2NCl); } // namespace o2::aod diff --git a/PWGLF/TableProducer/CMakeLists.txt b/PWGLF/TableProducer/CMakeLists.txt index 723e5b74155..ec21b553563 100644 --- a/PWGLF/TableProducer/CMakeLists.txt +++ b/PWGLF/TableProducer/CMakeLists.txt @@ -10,24 +10,8 @@ # or submit itself to any jurisdiction. add_subdirectory(QC) -add_subdirectory(converters) +add_subdirectory(Common) add_subdirectory(Nuspex) add_subdirectory(Strangeness) add_subdirectory(Resonances) - -# General purpose -o2physics_add_dpl_workflow(epvector - SOURCES epvector.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsVertexing - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(tpcpid - SOURCES lfTPCPID.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(zdcsp - SOURCES zdcSP.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB - COMPONENT_NAME Analysis) diff --git a/PWGLF/TableProducer/Common/CMakeLists.txt b/PWGLF/TableProducer/Common/CMakeLists.txt new file mode 100644 index 00000000000..5f1df4b5202 --- /dev/null +++ b/PWGLF/TableProducer/Common/CMakeLists.txt @@ -0,0 +1,41 @@ +# 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. + +# General purpose +o2physics_add_dpl_workflow(epvector + SOURCES epvector.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsVertexing + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(spvector + SOURCES spvector.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsVertexing + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(tpcpid + SOURCES lfTPCPID.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(zdcsp + SOURCES zdcSP.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(mc-centrality + SOURCES mcCentrality.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(kink-builder + SOURCES kinkBuilder.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter + COMPONENT_NAME Analysis) diff --git a/PWGLF/TableProducer/epvector.cxx b/PWGLF/TableProducer/Common/epvector.cxx similarity index 69% rename from PWGLF/TableProducer/epvector.cxx rename to PWGLF/TableProducer/Common/epvector.cxx index 69c842be22f..8d57d3711fd 100644 --- a/PWGLF/TableProducer/epvector.cxx +++ b/PWGLF/TableProducer/Common/epvector.cxx @@ -25,6 +25,7 @@ #include #include #include +#include // o2Physics includes. #include "Framework/AnalysisDataModel.h" @@ -95,10 +96,15 @@ struct epvector { Configurable useGainCallib{"useGainCallib", true, "use gain calibration"}; Configurable useRecentere{"useRecentere", true, "use Recentering"}; Configurable useShift{"useShift", false, "use Shift"}; + Configurable useShift2{"useShift2", false, "use Shift for others"}; Configurable ConfGainPath{"ConfGainPath", "Users/s/skundu/My/Object/test100", "Path to gain calibration"}; Configurable ConfRecentere{"ConfRecentere", "Users/s/skundu/My/Object/Finaltest2/recenereall", "Path for recentere"}; Configurable ConfShift{"ConfShift", "Users/s/skundu/My/Object/Finaltest2/recenereall", "Path for Shift"}; - + Configurable ConfShiftFT0A{"ConfShiftFT0A", "Users/s/skundu/My/Object/Finaltest2/recenereall", "Path for Shift FT0A"}; + Configurable ConfShiftTPC{"ConfShiftTPC", "Users/s/skundu/My/Object/Finaltest2/recenereall", "Path for Shift TPC"}; + Configurable ConfShiftTPCL{"ConfShiftTPCL", "Users/s/skundu/My/Object/Finaltest2/recenereall", "Path for Shift TPCL"}; + Configurable ConfShiftTPCR{"ConfShiftTPCR", "Users/s/skundu/My/Object/Finaltest2/recenereall", "Path for Shift TPCR"}; + ConfigurableAxis configAxisCentrality{"configAxisCentrality", {80, 0.0, 80}, "centrality bining"}; // Event selection cuts - Alex TF1* fMultPVCutLow = nullptr; TF1* fMultPVCutHigh = nullptr; @@ -108,7 +114,10 @@ struct epvector { void init(o2::framework::InitContext&) { - AxisSpec centAxis = {8, 0, 80, "V0M (%)"}; + std::vector occupancyBinning = {-0.5, 500.0, 1000.0, 1500.0, 2000.0, 3000.0, 4000.0, 5000.0, 50000.0}; + + const AxisSpec centAxis{configAxisCentrality, "V0M (%)"}; + // AxisSpec centAxis = {8, 0, 80, "V0M (%)"}; AxisSpec multiplicity = {5000, -500, 500, "TPC Multiplicity"}; AxisSpec amplitudeFT0 = {5000, 0, 10000, "FT0 amplitude"}; AxisSpec channelFT0Axis = {220, 0.0, 220.0, "FT0 channel"}; @@ -116,9 +125,12 @@ struct epvector { AxisSpec qyFT0Axis = {80000, -10000.0, 10000.0, "Qy"}; AxisSpec phiAxis = {500, -6.28, 6.28, "phi"}; AxisSpec vzAxis = {400, -20, 20, "vz"}; - AxisSpec resAxis = {400, -2, 2, "vz"}; + AxisSpec resAxis = {200, -2, 2, "Resv2"}; + AxisSpec resAxisSP = {800, -80, 80, "ResSP"}; + AxisSpec qAxis = {100, 0, 10, "Q axis"}; AxisSpec shiftAxis = {10, 0, 10, "shift"}; AxisSpec basisAxis = {2, 0, 2, "basis"}; + AxisSpec occupancyAxis = {occupancyBinning, "occupancy"}; histos.add("hCentrality", "hCentrality", kTH1F, {{8, 0, 80.0}}); histos.add("Vz", "Vz", kTH1F, {{400, -20.0, 20.0}}); @@ -138,11 +150,32 @@ struct epvector { histos.add("QxTPCR", "QxTPCR", kTH2F, {centAxis, multiplicity}); histos.add("QyTPCR", "QyTPCR", kTH2F, {centAxis, multiplicity}); histos.add("PsiTPCR", "PsiTPCR", kTH2F, {centAxis, phiAxis}); - histos.add("ResFT0CTPC", "ResFT0CTPC", kTH2F, {centAxis, resAxis}); - histos.add("ResFT0CFT0A", "ResFT0CFT0A", kTH2F, {centAxis, resAxis}); - histos.add("ResFT0ATPC", "ResFT0ATPC", kTH2F, {centAxis, resAxis}); + + histos.add("ResFT0CFT0A", "ResFT0CFT0A", kTH3F, {centAxis, resAxis, occupancyAxis}); + histos.add("ResFT0CTPC", "ResFT0CTPC", kTH3F, {centAxis, resAxis, occupancyAxis}); + histos.add("ResFT0ATPC", "ResFT0ATPC", kTH3F, {centAxis, resAxis, occupancyAxis}); + histos.add("ResFT0CTPCL", "ResFT0CTPCL", kTH3F, {centAxis, resAxis, occupancyAxis}); + histos.add("ResFT0CTPCR", "ResFT0CTPCR", kTH3F, {centAxis, resAxis, occupancyAxis}); + histos.add("ResTPCRTPCL", "ResTPCRTPCL", kTH3F, {centAxis, resAxis, occupancyAxis}); + + histos.add("ResFT0CFT0ASP", "ResFT0CFT0ASP", kTH3F, {centAxis, resAxisSP, occupancyAxis}); + histos.add("ResFT0CTPCSP", "ResFT0CTPCSP", kTH3F, {centAxis, resAxisSP, occupancyAxis}); + histos.add("ResFT0ATPCSP", "ResFT0ATPCSP", kTH3F, {centAxis, resAxisSP, occupancyAxis}); + histos.add("ResFT0CTPCLSP", "ResFT0CTPCLSP", kTH3F, {centAxis, resAxisSP, occupancyAxis}); + histos.add("ResFT0CTPCRSP", "ResFT0CTPCRSP", kTH3F, {centAxis, resAxisSP, occupancyAxis}); + histos.add("ResTPCRTPCLSP", "ResTPCRTPCLSP", kTH3F, {centAxis, resAxisSP, occupancyAxis}); + + histos.add("QFT0C", "QFT0C", kTH3F, {centAxis, qAxis, occupancyAxis}); + histos.add("QFT0A", "QFT0A", kTH3F, {centAxis, qAxis, occupancyAxis}); + histos.add("QTPCL", "QTPCL", kTH3F, {centAxis, qAxis, occupancyAxis}); + histos.add("QTPCR", "QTPCR", kTH3F, {centAxis, qAxis, occupancyAxis}); + histos.add("QTPC", "QTPC", kTH3F, {centAxis, qAxis, occupancyAxis}); histos.add("ShiftFT0C", "ShiftFT0C", kTProfile3D, {centAxis, basisAxis, shiftAxis}); + histos.add("ShiftFT0A", "ShiftFT0A", kTProfile3D, {centAxis, basisAxis, shiftAxis}); + histos.add("ShiftTPC", "ShiftTPC", kTProfile3D, {centAxis, basisAxis, shiftAxis}); + histos.add("ShiftTPCL", "ShiftTPCL", kTProfile3D, {centAxis, basisAxis, shiftAxis}); + histos.add("ShiftTPCR", "ShiftTPCR", kTProfile3D, {centAxis, basisAxis, shiftAxis}); // Event selection cut additional - Alex // if (additionalEvsel) { @@ -231,6 +264,10 @@ struct epvector { TProfile* gainprofile; TH2D* hrecentere; TProfile3D* shiftprofile; + TProfile3D* shiftprofile2; + TProfile3D* shiftprofile3; + TProfile3D* shiftprofile4; + TProfile3D* shiftprofile5; Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPT); Filter DCAcutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); @@ -265,7 +302,7 @@ struct epvector { if (useGainCallib && (currentRunNumber != lastRunNumber)) { gainprofile = ccdb->getForTimeStamp(ConfGainPath.value, bc.timestamp()); } - + int occupancy = coll.trackOccupancyInTimeRange(); histos.fill(HIST("hCentrality"), centrality); histos.fill(HIST("Vz"), vz); @@ -301,7 +338,7 @@ struct epvector { } for (auto& trk : tracks) { - if (!selectionTrack(trk) || abs(trk.eta()) > 0.8 || trk.pt() > cfgCutPTMax || abs(trk.eta()) < cfgMinEta) { + if (!selectionTrack(trk) || TMath::Abs(trk.eta()) > 0.8 || trk.pt() > cfgCutPTMax || TMath::Abs(trk.eta()) < cfgMinEta) { continue; } qxTPC = qxTPC + trk.pt() * TMath::Cos(2.0 * trk.phi()); @@ -338,15 +375,46 @@ struct epvector { if (useShift && (currentRunNumber != lastRunNumber)) { shiftprofile = ccdb->getForTimeStamp(ConfShift.value, bc.timestamp()); + if (useShift2) { + shiftprofile2 = ccdb->getForTimeStamp(ConfShiftFT0A.value, bc.timestamp()); + shiftprofile3 = ccdb->getForTimeStamp(ConfShiftTPC.value, bc.timestamp()); + shiftprofile4 = ccdb->getForTimeStamp(ConfShiftTPCL.value, bc.timestamp()); + shiftprofile5 = ccdb->getForTimeStamp(ConfShiftTPCR.value, bc.timestamp()); + } } if (useShift) { auto deltapsiFT0C = 0.0; + auto deltapsiFT0A = 0.0; + auto deltapsiTPC = 0.0; + auto deltapsiTPCL = 0.0; + auto deltapsiTPCR = 0.0; for (int ishift = 1; ishift <= 10; ishift++) { auto coeffshiftxFT0C = shiftprofile->GetBinContent(shiftprofile->FindBin(centrality, 0.5, ishift - 0.5)); auto coeffshiftyFT0C = shiftprofile->GetBinContent(shiftprofile->FindBin(centrality, 1.5, ishift - 0.5)); deltapsiFT0C = deltapsiFT0C + ((1 / (1.0 * ishift)) * (-coeffshiftxFT0C * TMath::Cos(ishift * 2.0 * psiFT0C) + coeffshiftyFT0C * TMath::Sin(ishift * 2.0 * psiFT0C))); + if (useShift2) { + auto coeffshiftxFT0A = shiftprofile2->GetBinContent(shiftprofile2->FindBin(centrality, 0.5, ishift - 0.5)); + auto coeffshiftyFT0A = shiftprofile2->GetBinContent(shiftprofile2->FindBin(centrality, 1.5, ishift - 0.5)); + + auto coeffshiftxTPC = shiftprofile3->GetBinContent(shiftprofile3->FindBin(centrality, 0.5, ishift - 0.5)); + auto coeffshiftyTPC = shiftprofile3->GetBinContent(shiftprofile3->FindBin(centrality, 1.5, ishift - 0.5)); + + auto coeffshiftxTPCL = shiftprofile4->GetBinContent(shiftprofile4->FindBin(centrality, 0.5, ishift - 0.5)); + auto coeffshiftyTPCL = shiftprofile4->GetBinContent(shiftprofile4->FindBin(centrality, 1.5, ishift - 0.5)); + + auto coeffshiftxTPCR = shiftprofile5->GetBinContent(shiftprofile5->FindBin(centrality, 0.5, ishift - 0.5)); + auto coeffshiftyTPCR = shiftprofile5->GetBinContent(shiftprofile5->FindBin(centrality, 1.5, ishift - 0.5)); + deltapsiFT0A = deltapsiFT0A + ((1 / (1.0 * ishift)) * (-coeffshiftxFT0A * TMath::Cos(ishift * 2.0 * psiFT0A) + coeffshiftyFT0A * TMath::Sin(ishift * 2.0 * psiFT0A))); + deltapsiTPC = deltapsiTPC + ((1 / (1.0 * ishift)) * (-coeffshiftxTPC * TMath::Cos(ishift * 2.0 * psiTPC) + coeffshiftyTPC * TMath::Sin(ishift * 2.0 * psiTPC))); + deltapsiTPCL = deltapsiTPCL + ((1 / (1.0 * ishift)) * (-coeffshiftxTPCL * TMath::Cos(ishift * 2.0 * psiTPCL) + coeffshiftyTPCL * TMath::Sin(ishift * 2.0 * psiTPCL))); + deltapsiTPCR = deltapsiTPCR + ((1 / (1.0 * ishift)) * (-coeffshiftxTPCR * TMath::Cos(ishift * 2.0 * psiTPCR) + coeffshiftyTPCR * TMath::Sin(ishift * 2.0 * psiTPCR))); + } } psiFT0C = psiFT0C + deltapsiFT0C; + psiFT0A = psiFT0A + deltapsiFT0A; + psiTPC = psiTPC + deltapsiTPC; + psiTPCL = psiTPCL + deltapsiTPCL; + psiTPCR = psiTPCR + deltapsiTPCR; } histos.fill(HIST("QxFT0C"), centrality, qxFT0C); histos.fill(HIST("QyFT0C"), centrality, qyFT0C); @@ -364,13 +432,47 @@ struct epvector { histos.fill(HIST("QyTPCR"), centrality, qyTPCR); histos.fill(HIST("PsiTPCR"), centrality, psiTPCR); - histos.fill(HIST("ResFT0CTPC"), centrality, TMath::Cos(2.0 * (psiFT0C - psiTPC))); - histos.fill(HIST("ResFT0CFT0A"), centrality, TMath::Cos(2.0 * (psiFT0C - psiFT0A))); - histos.fill(HIST("ResFT0ATPC"), centrality, TMath::Cos(2.0 * (psiTPC - psiFT0A))); + histos.fill(HIST("ResFT0CFT0A"), centrality, TMath::Cos(2.0 * (psiFT0C - psiFT0A)), occupancy); + histos.fill(HIST("ResFT0CTPC"), centrality, TMath::Cos(2.0 * (psiFT0C - psiTPC)), occupancy); + histos.fill(HIST("ResFT0ATPC"), centrality, TMath::Cos(2.0 * (psiFT0A - psiTPC)), occupancy); + histos.fill(HIST("ResFT0CTPCL"), centrality, TMath::Cos(2.0 * (psiFT0C - psiTPCL)), occupancy); + histos.fill(HIST("ResFT0CTPCR"), centrality, TMath::Cos(2.0 * (psiFT0C - psiTPCR)), occupancy); + histos.fill(HIST("ResTPCRTPCL"), centrality, TMath::Cos(2.0 * (psiTPCR - psiTPCL)), occupancy); + + double qFT0Cmag = TMath::Sqrt(qxFT0C * qxFT0C + qyFT0C * qyFT0C); + double qFT0Amag = TMath::Sqrt(qxFT0A * qxFT0A + qyFT0A * qyFT0A); + double qTPCmag = TMath::Sqrt(qxTPC * qxTPC + qyTPC * qyTPC); + double qTPCLmag = TMath::Sqrt(qxTPCL * qxTPCL + qyTPCL * qyTPCL); + double qTPCRmag = TMath::Sqrt(qxTPCR * qxTPCR + qyTPCR * qyTPCR); + + histos.fill(HIST("QTPC"), centrality, qTPCmag, occupancy); + histos.fill(HIST("QTPCL"), centrality, qTPCLmag, occupancy); + histos.fill(HIST("QTPCR"), centrality, qTPCRmag, occupancy); + histos.fill(HIST("QFT0C"), centrality, qFT0Cmag, occupancy); + histos.fill(HIST("QFT0A"), centrality, qFT0Amag, occupancy); + + histos.fill(HIST("ResFT0CFT0ASP"), centrality, qFT0Cmag * qFT0Amag * TMath::Cos(2.0 * (psiFT0C - psiFT0A)), occupancy); + histos.fill(HIST("ResFT0CTPCSP"), centrality, qFT0Cmag * qTPCmag * TMath::Cos(2.0 * (psiFT0C - psiTPC)), occupancy); + histos.fill(HIST("ResFT0ATPCSP"), centrality, qFT0Amag * qTPCmag * TMath::Cos(2.0 * (psiFT0A - psiTPC)), occupancy); + histos.fill(HIST("ResFT0CTPCLSP"), centrality, qFT0Cmag * qTPCLmag * TMath::Cos(2.0 * (psiFT0C - psiTPCL)), occupancy); + histos.fill(HIST("ResFT0CTPCRSP"), centrality, qFT0Cmag * qTPCRmag * TMath::Cos(2.0 * (psiFT0C - psiTPCR)), occupancy); + histos.fill(HIST("ResTPCRTPCLSP"), centrality, qTPCRmag * qTPCLmag * TMath::Cos(2.0 * (psiTPCR - psiTPCL)), occupancy); for (int ishift = 1; ishift <= 10; ishift++) { histos.fill(HIST("ShiftFT0C"), centrality, 0.5, ishift - 0.5, TMath::Sin(ishift * 2.0 * psiFT0C)); histos.fill(HIST("ShiftFT0C"), centrality, 1.5, ishift - 0.5, TMath::Cos(ishift * 2.0 * psiFT0C)); + + histos.fill(HIST("ShiftFT0A"), centrality, 0.5, ishift - 0.5, TMath::Sin(ishift * 2.0 * psiFT0A)); + histos.fill(HIST("ShiftFT0A"), centrality, 1.5, ishift - 0.5, TMath::Cos(ishift * 2.0 * psiFT0A)); + + histos.fill(HIST("ShiftTPC"), centrality, 0.5, ishift - 0.5, TMath::Sin(ishift * 2.0 * psiTPC)); + histos.fill(HIST("ShiftTPC"), centrality, 1.5, ishift - 0.5, TMath::Cos(ishift * 2.0 * psiTPC)); + + histos.fill(HIST("ShiftTPCL"), centrality, 0.5, ishift - 0.5, TMath::Sin(ishift * 2.0 * psiTPCL)); + histos.fill(HIST("ShiftTPCL"), centrality, 1.5, ishift - 0.5, TMath::Cos(ishift * 2.0 * psiTPCL)); + + histos.fill(HIST("ShiftTPCR"), centrality, 0.5, ishift - 0.5, TMath::Sin(ishift * 2.0 * psiTPCR)); + histos.fill(HIST("ShiftTPCR"), centrality, 1.5, ishift - 0.5, TMath::Cos(ishift * 2.0 * psiTPCR)); } lastRunNumber = currentRunNumber; } diff --git a/PWGLF/TableProducer/Common/kinkBuilder.cxx b/PWGLF/TableProducer/Common/kinkBuilder.cxx new file mode 100644 index 00000000000..fde62514a60 --- /dev/null +++ b/PWGLF/TableProducer/Common/kinkBuilder.cxx @@ -0,0 +1,441 @@ +// 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 kinkBuilder.cxx +/// \brief Builder task for kink decay topologies using ITS standalone tracks for the mother +/// \author Francesco Mazzaschi + +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "DCAFitter/DCAFitterN.h" + +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/Utils/svPoolCreator.h" +#include "PWGLF/DataModel/LFKinkDecayTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; +using VBracket = o2::math_utils::Bracket; +using TracksFull = soa::Join; + +namespace +{ +constexpr std::array LayerRadii{2.33959f, 3.14076f, 3.91924f, 19.6213f, 24.5597f, 34.388f, 39.3329f}; +constexpr double betheBlochDefault[1][6]{{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}}; +static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; +static const std::vector particleNames{"Daughter"}; + +std::shared_ptr h2ClsMapPtMoth; +std::shared_ptr h2ClsMapPtDaug; +std::shared_ptr h2DeDxDaugSel; +std::shared_ptr h2KinkAnglePt; +std::shared_ptr h2SigmaMinusMassPt; +} // namespace + +struct kinkCandidate { + + float recoPtMoth() const { return std::hypot(momMoth[0], momMoth[1]); } + float recoPhiMoth() const { return std::atan2(momMoth[1], momMoth[0]); } + float recoEtaMoth() const { return std::asinh(momMoth[2] / recoPtMoth()); } + + float recoPtDaug() const { return std::hypot(momDaug[0], momDaug[1]); } + float recoPhiDaug() const { return std::atan2(momDaug[1], momDaug[0]); } + float recoEtaDaug() const { return std::asinh(momDaug[2] / recoPtDaug()); } + + int mothTrackID; + int daugTrackID; + int collisionID; + + int mothSign; + std::array momMoth = {-999, -999, -999}; + std::array momDaug = {-999, -999, -999}; + std::array primVtx = {-999, -999, -999}; + std::array decVtx = {-999, -999, -999}; + + float dcaKinkTopo = -999; + float nSigmaTPCDaug = -999; + float nSigmaTOFDaug = -999; + float dcaXYdaug = -999; + float dcaXYmoth = -999; + float kinkAngle = -999; +}; + +struct kinkBuilder { + + Produces outputDataTable; + Service ccdb; + + // Selection criteria + Configurable maxDCAMothToPV{"maxDCAMothToPV", 0.1, "Max DCA of the mother to the PV"}; + Configurable minDCADaugToPV{"minDCADaugToPV", 0., "Min DCA of the daughter to the PV"}; + Configurable minPtMoth{"minPtMoth", 0.5, "Minimum pT of the hypercandidate"}; + Configurable maxZDiff{"maxZDiff", 20., "Max z difference between the kink daughter and the mother"}; + Configurable maxPhiDiff{"maxPhiDiff", 100, "Max phi difference between the kink daughter and the mother"}; + Configurable timeMarginNS{"timeMarginNS", 600, "Additional time res tolerance in ns"}; + Configurable etaMax{"etaMax", 1., "eta daughter"}; + Configurable nTPCClusMinDaug{"nTPCClusMinDaug", 80, "daug NTPC clusters cut"}; + Configurable askTOFforDaug{"askTOFforDaug", false, "If true, ask for TOF signal"}; + + o2::vertexing::DCAFitterN<2> fitter; + o2::base::MatLayerCylSet* lut = nullptr; + + // constants + float radToDeg = 180. / M_PI; + svPoolCreator svCreator; + + // bethe bloch parameters + Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {betheBlochDefault[0], 1, 6, particleNames, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for charged daughter"}; + Configurable cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Type of material correction"}; + Configurable customVertexerTimeMargin{"customVertexerTimeMargin", 800, "Time margin for custom vertexer (ns)"}; + Configurable skipAmbiTracks{"skipAmbiTracks", false, "Skip ambiguous tracks"}; + Configurable unlikeSignBkg{"unlikeSignBkg", false, "Use unlike sign background"}; + + // CCDB options + Configurable inputBz{"inputBz", -999, "bz field, -999 is automatic"}; + Configurable ccdbPath{"ccdbPath", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + + // PDG codes + + // histogram axes + ConfigurableAxis rigidityBins{"rigidityBins", {200, -10.f, 10.f}, "Binning for rigidity #it{p}^{TPC}/#it{z}"}; + ConfigurableAxis dedxBins{"dedxBins", {1000, 0.f, 1000.f}, "Binning for dE/dx"}; + ConfigurableAxis nSigmaBins{"nSigmaBins", {200, -5.f, 5.f}, "Binning for n sigma"}; + + // std vector of candidates + std::vector kinkCandidates; + + HistogramRegistry qaRegistry{"QA", {}, OutputObjHandlingPolicy::AnalysisObject}; + + int mRunNumber; + float mBz; + std::array mBBparamsDaug; + + void init(InitContext const&) + { + + // dummy values, 1 for mother, 0 for daughter + svCreator.setPDGs(1, 0); + + mRunNumber = 0; + mBz = 0; + + ccdb->setURL(ccdbPath); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + fitter.setPropagateToPCA(true); + fitter.setMaxR(200.); + fitter.setMinParamChange(1e-3); + fitter.setMinRelChi2Change(0.9); + fitter.setMaxDZIni(1e9); + fitter.setMaxChi2(1e9); + fitter.setUseAbsDCA(true); + + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); + int mat{static_cast(cfgMaterialCorrection)}; + fitter.setMatCorrType(static_cast(mat)); + + svCreator.setTimeMargin(customVertexerTimeMargin); + if (skipAmbiTracks) { + svCreator.setSkipAmbiTracks(); + } + + const AxisSpec itsClusterMapAxis(128, 0, 127, "ITS cluster map"); + const AxisSpec rigidityAxis{rigidityBins, "#it{p}^{TPC}/#it{z}"}; + const AxisSpec ptAxis{rigidityBins, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec sigmaMassAxis{100, 1.1, 1.4, "m (GeV/#it{c}^{2})"}; + const AxisSpec kinkAngleAxis{100, 0, 180, "#theta_{kink} (deg)"}; + const AxisSpec dedxAxis{dedxBins, "d#it{E}/d#it{x}"}; + + h2DeDxDaugSel = qaRegistry.add("h2DeDxDaugSel", ";p_{TPC}/z (GeV/#it{c}); dE/dx", HistType::kTH2F, {rigidityAxis, dedxAxis}); + h2KinkAnglePt = qaRegistry.add("h2KinkAnglePt", "; p_{T} (GeV/#it{c}); #theta_{kink} (deg)", HistType::kTH2F, {ptAxis, kinkAngleAxis}); + h2SigmaMinusMassPt = qaRegistry.add("h2SigmaMinusMassPt", "; p_{T} (GeV/#it{c}); m (GeV/#it{c}^{2})", HistType::kTH2F, {ptAxis, sigmaMassAxis}); + h2ClsMapPtMoth = qaRegistry.add("h2ClsMapPtMoth", "; p_{T} (GeV/#it{c}); ITS cluster map", HistType::kTH2F, {ptAxis, itsClusterMapAxis}); + h2ClsMapPtDaug = qaRegistry.add("h2ClsMapPtDaug", "; p_{T} (GeV/#it{c}); ITS cluster map", HistType::kTH2F, {ptAxis, itsClusterMapAxis}); + } + + template + bool selectMothTrack(const T& candidate) + { + if (candidate.has_collision() && candidate.hasITS() && !candidate.hasTPC() && !candidate.hasTOF() && candidate.itsNCls() < 6 && + candidate.itsNClsInnerBarrel() == 3 && candidate.itsChi2NCl() < 36 && candidate.pt() > minPtMoth) { + return true; + } + return false; + } + + template + bool selectDaugTrack(const T& candidate) + { + if (!candidate.hasTPC() || !candidate.hasITS()) { + return false; + } + + if (askTOFforDaug && !candidate.hasTOF()) { + return false; + } + + bool isGoodTPCCand = false; + if (candidate.itsNClsInnerBarrel() == 0 && candidate.itsNCls() < 4 && + candidate.tpcNClsCrossedRows() > 0.8 * candidate.tpcNClsFindable() && candidate.tpcNClsFound() > nTPCClusMinDaug) { + isGoodTPCCand = true; + } + + if (!isGoodTPCCand) { + return false; + } + + return true; + } + + template + void fillCandidateData(const Tcolls& collisions, const Ttracks& tracks, aod::AmbiguousTracks const& ambiguousTracks, aod::BCsWithTimestamps const& bcs) + { + svCreator.clearPools(); + svCreator.fillBC2Coll(collisions, bcs); + + for (auto& track : tracks) { + if (std::abs(track.eta()) > etaMax) + continue; + + bool isDaug = selectDaugTrack(track); + bool isMoth = selectMothTrack(track); + + if (!isDaug && !isMoth) + continue; + + int pdgHypo = isMoth ? 1 : 0; + svCreator.appendTrackCand(track, collisions, pdgHypo, ambiguousTracks, bcs); + } + auto& kinkPool = svCreator.getSVCandPool(collisions, !unlikeSignBkg); + + for (auto& svCand : kinkPool) { + kinkCandidate kinkCand; + + auto trackMoth = tracks.rawIteratorAt(svCand.tr0Idx); + auto trackDaug = tracks.rawIteratorAt(svCand.tr1Idx); + + auto const& collision = trackMoth.template collision_as(); + auto const& bc = collision.template bc_as(); + initCCDB(bc); + + o2::dataformats::VertexBase primaryVertex; + primaryVertex.setPos({collision.posX(), collision.posY(), collision.posZ()}); + primaryVertex.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + kinkCand.primVtx = {primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}; + + o2::track::TrackParCov trackParCovMoth = getTrackParCov(trackMoth); + o2::base::Propagator::Instance()->PropagateToXBxByBz(trackParCovMoth, LayerRadii[trackMoth.itsNCls() - 1]); + + o2::track::TrackParCov trackParCovMothPV = getTrackParCov(trackMoth); + gpu::gpustd::array dcaInfoMoth; + o2::base::Propagator::Instance()->propagateToDCABxByBz({primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, trackParCovMothPV, 2.f, static_cast(cfgMaterialCorrection.value), &dcaInfoMoth); + + if (std::abs(dcaInfoMoth[0]) > maxDCAMothToPV) { + continue; + } + + o2::track::TrackParCov trackParCovDaug = getTrackParCov(trackDaug); + + // check if the kink daughter is close to the mother + if (std::abs(trackParCovMoth.getZ() - trackParCovDaug.getZ()) > maxZDiff) { + continue; + } + + if ((std::abs(trackParCovMoth.getPhi() - trackParCovDaug.getPhi()) * radToDeg) > maxPhiDiff) { + continue; + } + + // propagate to PV + gpu::gpustd::array dcaInfoDaug; + o2::base::Propagator::Instance()->propagateToDCABxByBz({primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, trackParCovDaug, 2.f, static_cast(cfgMaterialCorrection.value), &dcaInfoDaug); + if (std::abs(dcaInfoDaug[0]) < minDCADaugToPV) { + continue; + } + + int nCand = 0; + try { + nCand = fitter.process(trackParCovMoth, trackParCovDaug); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call!"; + continue; + } + if (nCand == 0) { + continue; + } + + if (!fitter.propagateTracksToVertex()) { + continue; + } + + auto propMothTrack = fitter.getTrack(0); + auto propDaugTrack = fitter.getTrack(1); + kinkCand.decVtx = fitter.getPCACandidatePos(); + + // cut on decay radius to 17 cm + float decRad2 = kinkCand.decVtx[0] * kinkCand.decVtx[0] + kinkCand.decVtx[1] * kinkCand.decVtx[1]; + if (decRad2 < LayerRadii[3] * LayerRadii[3]) { + continue; + } + + // get last layer hitted by the mother and the first layer hitted by the daughter + int lastLayerMoth = 0, firstLayerDaug = 0; + for (int i = 0; i < 7; i++) { + if (trackMoth.itsClusterMap() & (1 << i)) { + lastLayerMoth = i; + } + } + + for (int i = 0; i < 7; i++) { + if (trackDaug.itsClusterMap() & (1 << i)) { + firstLayerDaug = i; + break; + } + } + + if (lastLayerMoth >= firstLayerDaug) { + continue; + } + + if (decRad2 < LayerRadii[lastLayerMoth] * LayerRadii[lastLayerMoth]) { + continue; + } + + for (int i = 0; i < 3; i++) { + kinkCand.decVtx[i] -= kinkCand.primVtx[i]; + } + + propMothTrack.getPxPyPzGlo(kinkCand.momMoth); + propDaugTrack.getPxPyPzGlo(kinkCand.momDaug); + float pMoth = propMothTrack.getP(); + float pDaug = propDaugTrack.getP(); + float spKink = kinkCand.momMoth[0] * kinkCand.momDaug[0] + kinkCand.momMoth[1] * kinkCand.momDaug[1] + kinkCand.momMoth[2] * kinkCand.momDaug[2]; + kinkCand.kinkAngle = std::acos(spKink / (pMoth * pDaug)); + + std::array neutDauMom{0.f, 0.f, 0.f}; + for (int i = 0; i < 3; i++) { + neutDauMom[i] = kinkCand.momMoth[i] - kinkCand.momDaug[i]; + } + + float piMinusE = std::sqrt(neutDauMom[0] * neutDauMom[0] + neutDauMom[1] * neutDauMom[1] + neutDauMom[2] * neutDauMom[2] + 0.13957 * 0.13957); + float neutronE = std::sqrt(pDaug * pDaug + 0.93957 * 0.93957); + float invMass = std::sqrt((piMinusE + neutronE) * (piMinusE + neutronE) - (pMoth * pMoth)); + + h2DeDxDaugSel->Fill(trackDaug.tpcInnerParam() * trackDaug.sign(), trackDaug.tpcSignal()); + h2KinkAnglePt->Fill(trackMoth.pt() * trackMoth.sign(), kinkCand.kinkAngle * radToDeg); + h2SigmaMinusMassPt->Fill(trackMoth.pt() * trackMoth.sign(), invMass); + h2ClsMapPtMoth->Fill(trackMoth.pt() * trackMoth.sign(), trackMoth.itsClusterMap()); + h2ClsMapPtDaug->Fill(trackDaug.pt() * trackDaug.sign(), trackDaug.itsClusterMap()); + + kinkCand.collisionID = collision.globalIndex(); + kinkCand.mothTrackID = trackMoth.globalIndex(); + kinkCand.daugTrackID = trackDaug.globalIndex(); + + kinkCand.dcaXYmoth = dcaInfoMoth[0]; + kinkCand.mothSign = trackMoth.sign(); + kinkCand.dcaXYdaug = dcaInfoDaug[0]; + kinkCand.dcaKinkTopo = std::sqrt(fitter.getChi2AtPCACandidate()); + kinkCandidates.push_back(kinkCand); + } + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + auto run3grp_timestamp = bc.timestamp(); + + o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + o2::parameters::GRPMagField* grpmag = 0x0; + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + if (inputBz < -990) { + // Fetch magnetic field from ccdb for current collision + mBz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << mBz << " kZG"; + } else { + mBz = inputBz; + } + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + if (inputBz < -990) { + // Fetch magnetic field from ccdb for current collision + mBz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << mBz << " kZG"; + } else { + mBz = inputBz; + } + } + + for (int i = 0; i < 5; i++) { + mBBparamsDaug[i] = cfgBetheBlochParams->get("Daughter", Form("p%i", i)); + } + mBBparamsDaug[5] = cfgBetheBlochParams->get("Daughter", "resolution"); + + fitter.setBz(mBz); + mRunNumber = bc.runNumber(); + o2::base::Propagator::Instance()->setMatLUT(lut); + LOG(info) << "Task initialized for run " << mRunNumber << " with magnetic field " << mBz << " kZG"; + } + + void process(aod::Collisions const& collisions, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs) + { + + kinkCandidates.clear(); + fillCandidateData(collisions, tracks, ambiTracks, bcs); + + // sort kinkCandidates by collisionID to allow joining with collision table + std::sort(kinkCandidates.begin(), kinkCandidates.end(), [](const kinkCandidate& a, const kinkCandidate& b) { return a.collisionID < b.collisionID; }); + + for (auto& kinkCand : kinkCandidates) { + outputDataTable(kinkCand.collisionID, kinkCand.mothTrackID, kinkCand.daugTrackID, + kinkCand.decVtx[0], kinkCand.decVtx[1], kinkCand.decVtx[2], + kinkCand.mothSign, kinkCand.momMoth[0], kinkCand.momMoth[1], kinkCand.momMoth[2], + kinkCand.momDaug[0], kinkCand.momDaug[1], kinkCand.momDaug[2], + kinkCand.dcaXYmoth, kinkCand.dcaXYdaug, kinkCand.dcaKinkTopo); + } + } +}; + +WorkflowSpec + defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/lfTPCPID.cxx b/PWGLF/TableProducer/Common/lfTPCPID.cxx similarity index 100% rename from PWGLF/TableProducer/lfTPCPID.cxx rename to PWGLF/TableProducer/Common/lfTPCPID.cxx diff --git a/PWGLF/TableProducer/Common/mcCentrality.cxx b/PWGLF/TableProducer/Common/mcCentrality.cxx new file mode 100644 index 00000000000..690d049af4d --- /dev/null +++ b/PWGLF/TableProducer/Common/mcCentrality.cxx @@ -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 mcCentrality.cxx +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \author Francesca Ercolessi francesca.ercolessi@cern.ch +/// \since 2024-06-05 +/// \brief Task to produce the table for the equalized multiplicity into centrality bins +/// + +// O2 includes +#include "CCDB/BasicCCDBManager.h" +#include "ReconstructionDataFormats/Track.h" +#include "CCDB/CcdbApi.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StaticFor.h" +#include "TableHelper.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Common/DataModel/Centrality.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::track; + +/// Task to produce the response table +struct mcCentrality { + + // Tables to produce + Produces centFV0A; + Produces centFT0M; + Produces centFT0A; + Produces centFT0C; + Produces centFDDM; + Produces centNTPV; + + // Input parameters + Service ccdb; + Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbTimestamp{"ccdb-timestamp", -1, "timestamp of the object used to query in CCDB the detector response. If 0 the object corresponding to the run number is used, if < 0 the latest object is used"}; + Configurable path{"path", "/tmp/InputCalibMC.root", "path to calib file or ccdb path if begins with ccdb://"}; + Configurable selectPrimaries{"selectPrimaries", true, "Select only primary particles"}; + Service pdgDB; + ConfigurableAxis binsPercentile{"binsPercentile", {VARIABLE_WIDTH, 0, 0.001, 0.01, 1.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0}, "Binning of the percentile axis"}; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + TH1F* h1dFT0M; + /*TH1F* h1dFT0A; + TH1F* h1dFT0C; + TH1F* h1dFDD; + TH1F* h1dNTP;*/ + + o2::pwglf::ParticleCounter mCounter; + + void init(o2::framework::InitContext& /*initContext*/) + { + // Set up the CCDB + ccdb->setURL(url.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + ccdb->setFatalWhenNull(false); + + mCounter.mPdgDatabase = pdgDB.service; + mCounter.mSelectPrimaries = selectPrimaries.value; + histos.add("FT0M/percentile", "FT0M percentile.", HistType::kTH1D, {{binsPercentile, "FT0M percentile"}}); + histos.add("FT0M/percentilevsMult", "FT0M percentile.", HistType::kTH2D, {{binsPercentile, "FT0M percentile"}, {1000, 0, 5000, "FT0M mult."}}); + + TList* lOfInput; + if (path.value.rfind("ccdb://", 0) == 0) { // Getting post calib. from CCDB + path.value.replace(0, 7, ""); + lOfInput = ccdb->get(path); + if (!lOfInput) { + LOG(fatal) << "Could not find the calibration TList from CCDB in path " << path; + return; + } + } else { // Getting post calib. from file + TFile* f = TFile::Open(path.value.c_str(), "READ"); + if (!f) { + LOG(fatal) << "The input file " << path << " is not valid"; + } + if (!f->IsOpen()) { + LOG(fatal) << "The input file " << f->GetName() << " is not open"; + } + lOfInput = static_cast(f->Get("ccdb_object")); + if (!lOfInput) { + f->ls(); + LOG(fatal) << "The input file " << path.value << " does not contain the TList ccdb_object"; + } + } + h1dFT0M = static_cast(lOfInput->FindObject("h1dFT0M")); + if (!h1dFT0M) { + lOfInput->ls(); + LOG(fatal) << "Could not open histogram h1dFT0M from TList"; + return; + } + } + + // Full tables (independent on central calibrations) + void process(aod::McCollision const& /*mcCollision*/, + aod::McParticles const& mcParticles) + { + const float nFT0M = mCounter.countFT0A(mcParticles) + mCounter.countFT0C(mcParticles); + /*const float nFT0A = mCounter.countFT0A(mcParticles); + const float nFT0C = mCounter.countFT0C(mcParticles); + const float nFV0A = mCounter.countFV0A(mcParticles);*/ + + const float valueCentFT0M = h1dFT0M->GetBinContent(h1dFT0M->FindBin(nFT0M)); + /*const float valueCentFT0A = h1dFT0M->GetBinContent(h1dFT0M->FindBin(nFT0A)); + const float valueCentFT0C = h1dFT0M->GetBinContent(h1dFT0M->FindBin(nFT0C)); + const float valueCentFV0A = h1dFT0M->GetBinContent(h1dFT0M->FindBin(nFV0A));*/ + + centFT0M(valueCentFT0M); + /*centFT0A(valueCentFT0A); + centFT0C(valueCentFT0C); + centFV0A(valueCentFV0A);*/ + histos.fill(HIST("FT0M/percentile"), valueCentFT0M); + histos.fill(HIST("FT0M/percentilevsMult"), valueCentFT0M, nFT0M); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/TableProducer/Common/spvector.cxx b/PWGLF/TableProducer/Common/spvector.cxx new file mode 100644 index 00000000000..20f5f738255 --- /dev/null +++ b/PWGLF/TableProducer/Common/spvector.cxx @@ -0,0 +1,708 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +// \author: prottay das 23/12/2024 +// \email: prottay.das@cern.ch + +// C++/ROOT includes. +#include +#include +#include +#include +#include +#include +#include +#include +#include "Math/Vector4D.h" +#include "TRandom3.h" +#include "TF1.h" + +// o2Physics includes. +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "FT0Base/Geometry.h" +#include "FV0Base/Geometry.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/PID/PIDTOF.h" +#include "Common/TableProducer/PID/pidTOFBase.h" +#include "Common/Core/EventPlaneHelper.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "PWGLF/DataModel/SPCalibrationTables.h" +// #include "SPCalibrationTableswrite.h" + +// o2 includes. +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" +#include "DetectorsCommonDataFormats/AlignParam.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +using BCsRun3 = soa::Join; + +struct spvector { + + Produces spcalibrationtable; + + // Configurables. + struct : ConfigurableGroup { + Configurable cfgURL{"cfgURL", "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; + Configurable nolaterthan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "Latest acceptable timestamp of creation for the object"}; + } cfgCcdbParam; + + // Enable access to the CCDB for the offset and correction constants and save them in dedicated variables. + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutCentralityMax{"cfgCutCentralityMax", 80.0f, "Centrality cut Max"}; + Configurable cfgCutCentralityMin{"cfgCutCentralityMin", 0.0f, "Centrality cut Min"}; + + Configurable QxyNbins{"QxyNbins", 100, "Number of bins in QxQy histograms"}; + Configurable PhiNbins{"PhiNbins", 100, "Number of bins in phi histogram"}; + Configurable lbinQxy{"lbinQxy", -5.0, "lower bin value in QxQy histograms"}; + Configurable hbinQxy{"hbinQxy", 5.0, "higher bin value in QxQy histograms"}; + Configurable VxNbins{"VxNbins", 25, "Number of bins in Vx histograms"}; + Configurable lbinVx{"lbinVx", -0.05, "lower bin value in Vx histograms"}; + Configurable hbinVx{"hbinVx", 0.0, "higher bin value in Vx histograms"}; + Configurable VyNbins{"VyNbins", 25, "Number of bins in Vy histograms"}; + Configurable lbinVy{"lbinVy", -0.02, "lower bin value in Vy histograms"}; + Configurable hbinVy{"hbinVy", 0.02, "higher bin value in Vy histograms"}; + Configurable VzNbins{"VzNbins", 20, "Number of bins in Vz histograms"}; + Configurable lbinVz{"lbinVz", -10.0, "lower bin value in Vz histograms"}; + Configurable hbinVz{"hbinVz", 10.0, "higher bin value in Vz histograms"}; + Configurable CentNbins{"CentNbins", 16, "Number of bins in cent histograms"}; + Configurable lbinCent{"lbinCent", 0.0, "lower bin value in cent histograms"}; + Configurable hbinCent{"hbinCent", 80.0, "higher bin value in cent histograms"}; + Configurable VxfineNbins{"VxfineNbins", 25, "Number of bins in Vx fine histograms"}; + Configurable lfinebinVx{"lfinebinVx", -0.05, "lower bin value in Vx fine histograms"}; + Configurable hfinebinVx{"hfinebinVx", 0.0, "higher bin value in Vx fine histograms"}; + Configurable VyfineNbins{"VyfineNbins", 25, "Number of bins in Vy fine histograms"}; + Configurable lfinebinVy{"lfinebinVy", -0.02, "lower bin value in Vy fine histograms"}; + Configurable hfinebinVy{"hfinebinVy", 0.02, "higher bin value in Vy fine histograms"}; + Configurable VzfineNbins{"VzfineNbins", 20, "Number of bins in Vz fine histograms"}; + Configurable lfinebinVz{"lfinebinVz", -10.0, "lower bin value in Vz fine histograms"}; + Configurable hfinebinVz{"hfinebinVz", 10.0, "higher bin value in Vz fine histograms"}; + Configurable CentfineNbins{"CentfineNbins", 16, "Number of bins in cent fine histograms"}; + Configurable lfinebinCent{"lfinebinCent", 0.0, "lower bin value in cent fine histograms"}; + Configurable hfinebinCent{"hfinebinCent", 80.0, "higher bin value in cent fine histograms"}; + Configurable useShift{"useShift", false, "shift histograms"}; + Configurable ispolarization{"ispolarization", false, "Flag to check polarization"}; + Configurable followpub{"followpub", true, "flag to use alphaZDC"}; + Configurable useGainCallib{"useGainCallib", false, "use gain calibration"}; + Configurable useCallibvertex{"useCallibvertex", false, "use calibration for vxy"}; + Configurable coarse1{"coarse1", false, "RE1"}; + Configurable fine1{"fine1", false, "REfine1"}; + Configurable coarse2{"coarse2", false, "RE2"}; + Configurable fine2{"fine2", false, "REfine2"}; + Configurable coarse3{"coarse3", false, "RE3"}; + Configurable fine3{"fine3", false, "REfine3"}; + Configurable coarse4{"coarse4", false, "RE4"}; + Configurable fine4{"fine4", false, "REfine4"}; + Configurable coarse5{"coarse5", false, "RE5"}; + Configurable fine5{"fine5", false, "REfine5"}; + Configurable coarse6{"coarse6", false, "RE6"}; + Configurable useRecentereSp{"useRecentereSp", false, "use Recentering with Sparse or THn"}; + Configurable useRecenterefineSp{"useRecenterefineSp", false, "use fine Recentering with THn"}; + Configurable ConfGainPath{"ConfGainPath", "Users/p/prottay/My/Object/NewPbPbpass4_10092024/gaincallib", "Path to gain calibration"}; + Configurable ConfGainPathvxy{"ConfGainPathvxy", "Users/p/prottay/My/Object/swapcoords/PbPbpass4_20112024/recentervert", "Path to gain calibration for vxy"}; + Configurable ConfRecentereSp{"ConfRecentereSp", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for recentere"}; + Configurable ConfRecentereSp2{"ConfRecentereSp2", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for recentere2"}; + Configurable ConfRecentereSp3{"ConfRecentereSp3", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for recentere3"}; + Configurable ConfRecentereSp4{"ConfRecentereSp4", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for recentere4"}; + Configurable ConfRecentereSp5{"ConfRecentereSp5", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for recentere5"}; + Configurable ConfRecentereSp6{"ConfRecentereSp6", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for recentere6"}; + Configurable ConfRecenterecentSp{"ConfRecenterecentSp", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for cent recentere"}; + Configurable ConfRecenterevxSp{"ConfRecenterevxSp", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vx recentere"}; + Configurable ConfRecenterevySp{"ConfRecenterevySp", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vy recentere"}; + Configurable ConfRecenterevzSp{"ConfRecenterevzSp", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vz recentere"}; + Configurable ConfRecenterecentSp2{"ConfRecenterecentSp2", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for cent recentere2"}; + Configurable ConfRecenterevxSp2{"ConfRecenterevxSp2", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vx recentere2"}; + Configurable ConfRecenterevySp2{"ConfRecenterevySp2", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vy recentere2"}; + Configurable ConfRecenterevzSp2{"ConfRecenterevzSp2", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vz recentere2"}; + Configurable ConfRecenterecentSp3{"ConfRecenterecentSp3", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for cent recentere3"}; + Configurable ConfRecenterevxSp3{"ConfRecenterevxSp3", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vx recentere3"}; + Configurable ConfRecenterevySp3{"ConfRecenterevySp3", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vy recentere3"}; + Configurable ConfRecenterevzSp3{"ConfRecenterevzSp3", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vz recentere3"}; + Configurable ConfRecenterecentSp4{"ConfRecenterecentSp4", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for cent recentere4"}; + Configurable ConfRecenterevxSp4{"ConfRecenterevxSp4", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vx recentere4"}; + Configurable ConfRecenterevySp4{"ConfRecenterevySp4", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vy recentere4"}; + Configurable ConfRecenterevzSp4{"ConfRecenterevzSp4", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vz recentere4"}; + Configurable ConfRecenterecentSp5{"ConfRecenterecentSp5", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for cent recentere5"}; + Configurable ConfRecenterevxSp5{"ConfRecenterevxSp5", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vx recentere5"}; + Configurable ConfRecenterevySp5{"ConfRecenterevySp5", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vy recentere5"}; + Configurable ConfRecenterevzSp5{"ConfRecenterevzSp5", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vz recentere5"}; + Configurable ConfShiftC{"ConfShiftC", "Users/p/prottay/My/Object/Testinglocaltree/shiftcallib2", "Path to shift C"}; + Configurable ConfShiftA{"ConfShiftA", "Users/p/prottay/My/Object/Testinglocaltree/shiftcallib2", "Path to shift A"}; + + // Event selection cuts - Alex + /* + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + TF1* fMultCutLow = nullptr; + TF1* fMultCutHigh = nullptr; + TF1* fMultMultPVCut = nullptr; + */ + /* + template + bool eventSelected(TCollision collision, const double& centrality) + { + auto multNTracksPV = collision.multNTracksPV(); + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) + return 0; + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) + return 0; + + return 1; + } + */ + void init(o2::framework::InitContext&) + { + + AxisSpec channelZDCAxis = {8, 0.0, 8.0, "ZDC tower"}; + AxisSpec qxZDCAxis = {QxyNbins, lbinQxy, hbinQxy, "Qx"}; + AxisSpec phiAxis = {PhiNbins, -6.28, 6.28, "phi"}; + AxisSpec vzAxis = {VzNbins, lbinVz, hbinVz, "vz"}; + AxisSpec vxAxis = {VxNbins, lbinVx, hbinVx, "vx"}; + AxisSpec vyAxis = {VyNbins, lbinVy, hbinVy, "vy"}; + AxisSpec centAxis = {CentNbins, lbinCent, hbinCent, "V0M (%)"}; + AxisSpec vzfineAxis = {VzfineNbins, lfinebinVz, hfinebinVz, "vzfine"}; + AxisSpec vxfineAxis = {VxfineNbins, lfinebinVx, hfinebinVx, "vxfine"}; + AxisSpec vyfineAxis = {VyfineNbins, lfinebinVy, hfinebinVy, "vyfine"}; + AxisSpec centfineAxis = {CentfineNbins, lfinebinCent, hfinebinCent, "V0M (%) fine"}; + AxisSpec shiftAxis = {10, 0, 10, "shift"}; + AxisSpec basisAxis = {2, 0, 2, "basis"}; + AxisSpec VxyAxis = {2, 0, 2, "Vxy"}; + + histos.add("hCentrality", "hCentrality", kTH1F, {{centfineAxis}}); + histos.add("Vz", "Vz", kTH1F, {vzfineAxis}); + histos.add("hpQxZDCAC", "hpQxZDCAC", kTProfile, {centfineAxis}); + histos.add("hpQyZDCAC", "hpQyZDCAC", kTProfile, {centfineAxis}); + histos.add("hpQxZDCAQyZDCC", "hpQxZDCAQyZDCC", kTProfile, {centfineAxis}); + histos.add("hpQxZDCCQyZDCA", "hpQxZDCCQyZDCA", kTProfile, {centfineAxis}); + + if (!ispolarization) { + histos.add("hnQxZDCA", "hnQxZDCA", kTHnF, {{centAxis}, {vxAxis}, {vyAxis}, {vzAxis}, {qxZDCAxis}}); + histos.add("hnQyZDCA", "hnQyZDCA", kTHnF, {{centAxis}, {vxAxis}, {vyAxis}, {vzAxis}, {qxZDCAxis}}); + histos.add("hnQxZDCC", "hnQxZDCC", kTHnF, {{centAxis}, {vxAxis}, {vyAxis}, {vzAxis}, {qxZDCAxis}}); + histos.add("hnQyZDCC", "hnQyZDCC", kTHnF, {{centAxis}, {vxAxis}, {vyAxis}, {vzAxis}, {qxZDCAxis}}); + + histos.add("hcentQxZDCA", "hcentQxZDCA", kTH2F, {{centfineAxis}, {qxZDCAxis}}); + histos.add("hcentQyZDCA", "hcentQyZDCA", kTH2F, {{centfineAxis}, {qxZDCAxis}}); + histos.add("hcentQxZDCC", "hcentQxZDCC", kTH2F, {{centfineAxis}, {qxZDCAxis}}); + histos.add("hcentQyZDCC", "hcentQyZDCC", kTH2F, {{centfineAxis}, {qxZDCAxis}}); + + histos.add("hvxQxZDCA", "hvxQxZDCA", kTH2F, {{vxfineAxis}, {qxZDCAxis}}); + histos.add("hvxQyZDCA", "hvxQyZDCA", kTH2F, {{vxfineAxis}, {qxZDCAxis}}); + histos.add("hvxQxZDCC", "hvxQxZDCC", kTH2F, {{vxfineAxis}, {qxZDCAxis}}); + histos.add("hvxQyZDCC", "hvxQyZDCC", kTH2F, {{vxfineAxis}, {qxZDCAxis}}); + + histos.add("hvyQxZDCA", "hvyQxZDCA", kTH2F, {{vyfineAxis}, {qxZDCAxis}}); + histos.add("hvyQyZDCA", "hvyQyZDCA", kTH2F, {{vyfineAxis}, {qxZDCAxis}}); + histos.add("hvyQxZDCC", "hvyQxZDCC", kTH2F, {{vyfineAxis}, {qxZDCAxis}}); + histos.add("hvyQyZDCC", "hvyQyZDCC", kTH2F, {{vyfineAxis}, {qxZDCAxis}}); + + histos.add("hvzQxZDCA", "hvzQxZDCA", kTH2F, {{vzfineAxis}, {qxZDCAxis}}); + histos.add("hvzQyZDCA", "hvzQyZDCA", kTH2F, {{vzfineAxis}, {qxZDCAxis}}); + histos.add("hvzQxZDCC", "hvzQxZDCC", kTH2F, {{vzfineAxis}, {qxZDCAxis}}); + histos.add("hvzQyZDCC", "hvzQyZDCC", kTH2F, {{vzfineAxis}, {qxZDCAxis}}); + } + + histos.add("PsiZDCC", "PsiZDCC", kTH2F, {centfineAxis, phiAxis}); + histos.add("PsiZDCA", "PsiZDCA", kTH2F, {centfineAxis, phiAxis}); + histos.add("ZDCAmp", "ZDCAmp", kTProfile2D, {channelZDCAxis, vzfineAxis}); + histos.add("ZDCAmpCommon", "ZDCAmpCommon", kTProfile2D, {{2, 0.0, 2.0}, vzfineAxis}); + histos.add("ShiftZDCC", "ShiftZDCC", kTProfile3D, {centfineAxis, basisAxis, shiftAxis}); + histos.add("ShiftZDCA", "ShiftZDCA", kTProfile3D, {centfineAxis, basisAxis, shiftAxis}); + histos.add("hpCosPsiAPsiC", "hpCosPsiAPsiC", kTProfile, {centfineAxis}); + histos.add("hpSinPsiAPsiC", "hpSinPsiAPsiC", kTProfile, {centfineAxis}); + histos.add("AvgVxy", "AvgVxy", kTProfile, {VxyAxis}); + + // Event selection cut additional - Alex + /* + fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultPVCutLow->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05); + fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultPVCutHigh->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05); + fMultCutLow = new TF1("fMultCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.5*([4]+[5]*x)", 0, 100); + fMultCutLow->SetParameters(1893.94, -53.86, 0.502913, -0.0015122, 109.625, -1.19253); + fMultCutHigh = new TF1("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 3.*([4]+[5]*x)", 0, 100); + fMultCutHigh->SetParameters(1893.94, -53.86, 0.502913, -0.0015122, 109.625, -1.19253); + fMultMultPVCut = new TF1("fMultMultPVCut", "[0]+[1]*x+[2]*x*x", 0, 5000); + fMultMultPVCut->SetParameters(-0.1, 0.785, -4.7e-05); + */ + ccdb->setURL(cfgCcdbParam.cfgURL); + ccdbApi.init("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + } + + int currentRunNumber = -999; + int lastRunNumber = -999; + TH2D* gainprofile; + TProfile* gainprofilevxy; + /*THnF* hrecentereSp; + TH2F* hrecenterecentSp; + TH2F* hrecenterevxSp; + TH2F* hrecenterevySp; + TH2F* hrecenterevzSp;*/ + std::array hrecentereSpA; // Array of 6 histograms + std::array hrecenterecentSpA; // Array of 5 histograms + std::array hrecenterevxSpA; // Array of 5 histograms + std::array hrecenterevySpA; // Array of 5 histograms + std::array hrecenterevzSpA; // Array of 5 histograms + TProfile3D* shiftprofileA; + TProfile3D* shiftprofileC; + + // Bool_t Correctcoarse(int64_t ts, Configurable& ConfRecentereSpp, bool useRecentereSp, int currentRunNumber, int lastRunNumber, auto centrality, auto vx, auto vy, auto vz, auto& qxZDCA, auto& qyZDCA, auto& qxZDCC, auto& qyZDCC) + //{ + Bool_t Correctcoarse(const THnF* hrecentereSp, auto centrality, auto vx, auto vy, auto vz, auto& qxZDCA, auto& qyZDCA, auto& qxZDCC, auto& qyZDCC) + { + + /* + if (useRecentereSp && (currentRunNumber != lastRunNumber)) { + hrecentereSp = ccdb->getForTimeStamp(ConfRecentereSpp.value, ts); + }*/ + + int binCoords[5]; + + // Get axes of the THnSparse + TAxis* centralityAxis = hrecentereSp->GetAxis(0); // Axis 0: centrality + TAxis* vxAxis = hrecentereSp->GetAxis(1); // Axis 1: vx + TAxis* vyAxis = hrecentereSp->GetAxis(2); // Axis 2: vy + TAxis* vzAxis = hrecentereSp->GetAxis(3); // Axis 3: vz + TAxis* channelAxis = hrecentereSp->GetAxis(4); // Axis 4: channel + + // Find bin indices for centrality, vx, vy, vz, and channel (for meanxA, 0.5) + binCoords[0] = centralityAxis->FindBin(centrality); // Centrality + binCoords[1] = vxAxis->FindBin(vx); // vx + binCoords[2] = vyAxis->FindBin(vy); // vy + binCoords[3] = vzAxis->FindBin(vz); // vz + binCoords[4] = channelAxis->FindBin(0.5); // Channel for meanxA + + // Get the global bin for meanxA + int globalBinMeanxA = hrecentereSp->GetBin(binCoords); + float meanxA = hrecentereSp->GetBinContent(globalBinMeanxA); + + // Repeat for other channels (meanyA, meanxC, meanyC) + binCoords[4] = channelAxis->FindBin(1.5); // Channel for meanyA + int globalBinMeanyA = hrecentereSp->GetBin(binCoords); + float meanyA = hrecentereSp->GetBinContent(globalBinMeanyA); + + binCoords[4] = channelAxis->FindBin(2.5); // Channel for meanxC + int globalBinMeanxC = hrecentereSp->GetBin(binCoords); + float meanxC = hrecentereSp->GetBinContent(globalBinMeanxC); + + binCoords[4] = channelAxis->FindBin(3.5); // Channel for meanyC + int globalBinMeanyC = hrecentereSp->GetBin(binCoords); + float meanyC = hrecentereSp->GetBinContent(globalBinMeanyC); + + qxZDCA = qxZDCA - meanxA; + qyZDCA = qyZDCA - meanyA; + qxZDCC = qxZDCC - meanxC; + qyZDCC = qyZDCC - meanyC; + + return kTRUE; + } + + // Bool_t Correctfine(int64_t ts, Configurable& ConfRecenterecentSpp, Configurable& ConfRecenterevxSpp, Configurable& ConfRecenterevySpp, Configurable& ConfRecenterevzSpp, bool useRecenterefineSp, int currentRunNumber, int lastRunNumber, auto centrality, auto vx, auto vy, auto vz, auto& qxZDCA, auto& qyZDCA, auto& qxZDCC, auto& qyZDCC) + //{ + Bool_t Correctfine(TH2F* hrecenterecentSp, TH2F* hrecenterevxSp, TH2F* hrecenterevySp, TH2F* hrecenterevzSp, auto centrality, auto vx, auto vy, auto vz, auto& qxZDCA, auto& qyZDCA, auto& qxZDCC, auto& qyZDCC) + { + + if (!hrecenterecentSp || !hrecenterevxSp || !hrecenterevySp || !hrecenterevzSp) { + std::cerr << "Error: One or more histograms are null." << std::endl; + return false; + } + /* + if (useRecenterefineSp && (currentRunNumber != lastRunNumber)) { + hrecenterecentSp = ccdb->getForTimeStamp(ConfRecenterecentSpp.value, ts); + hrecenterevxSp = ccdb->getForTimeStamp(ConfRecenterevxSpp.value, ts); + hrecenterevySp = ccdb->getForTimeStamp(ConfRecenterevySpp.value, ts); + hrecenterevzSp = ccdb->getForTimeStamp(ConfRecenterevzSpp.value, ts); + }*/ + + double meanxAcent = hrecenterecentSp->GetBinContent(hrecenterecentSp->FindBin(centrality, 0.5)); + double meanyAcent = hrecenterecentSp->GetBinContent(hrecenterecentSp->FindBin(centrality, 1.5)); + double meanxCcent = hrecenterecentSp->GetBinContent(hrecenterecentSp->FindBin(centrality, 2.5)); + double meanyCcent = hrecenterecentSp->GetBinContent(hrecenterecentSp->FindBin(centrality, 3.5)); + + double meanxAvx = hrecenterevxSp->GetBinContent(hrecenterevxSp->FindBin(vx, 0.5)); + double meanyAvx = hrecenterevxSp->GetBinContent(hrecenterevxSp->FindBin(vx, 1.5)); + double meanxCvx = hrecenterevxSp->GetBinContent(hrecenterevxSp->FindBin(vx, 2.5)); + double meanyCvx = hrecenterevxSp->GetBinContent(hrecenterevxSp->FindBin(vx, 3.5)); + + double meanxAvy = hrecenterevySp->GetBinContent(hrecenterevySp->FindBin(vy, 0.5)); + double meanyAvy = hrecenterevySp->GetBinContent(hrecenterevySp->FindBin(vy, 1.5)); + double meanxCvy = hrecenterevySp->GetBinContent(hrecenterevySp->FindBin(vy, 2.5)); + double meanyCvy = hrecenterevySp->GetBinContent(hrecenterevySp->FindBin(vy, 3.5)); + + double meanxAvz = hrecenterevzSp->GetBinContent(hrecenterevzSp->FindBin(vz, 0.5)); + double meanyAvz = hrecenterevzSp->GetBinContent(hrecenterevzSp->FindBin(vz, 1.5)); + double meanxCvz = hrecenterevzSp->GetBinContent(hrecenterevzSp->FindBin(vz, 2.5)); + double meanyCvz = hrecenterevzSp->GetBinContent(hrecenterevzSp->FindBin(vz, 3.5)); + + qxZDCA = qxZDCA - meanxAcent - meanxAvx - meanxAvy - meanxAvz; + qyZDCA = qyZDCA - meanyAcent - meanyAvx - meanyAvy - meanyAvz; + qxZDCC = qxZDCC - meanxCcent - meanxCvx - meanxCvy - meanxCvz; + qyZDCC = qyZDCC - meanyCcent - meanyCvx - meanyCvy - meanyCvz; + + return kTRUE; + } + + using MyCollisions = soa::Join; + Preslice zdcPerCollision = aod::collision::bcId; + + void process(MyCollisions::iterator const& collision, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0s*/, BCsRun3 const& bcs, aod::Zdcs const&) + { + + auto centrality = collision.centFT0C(); + bool triggerevent = false; + + if (bcs.size() != 0) { + gRandom->SetSeed(bcs.iteratorAt(0).globalBC()); + } + + currentRunNumber = collision.foundBC_as().runNumber(); + auto vz = collision.posZ(); + auto vx = collision.posX(); + auto vy = collision.posY(); + + double psiZDCC = -99; + double psiZDCA = -99; + auto qxZDCA = 0.0; + auto qxZDCC = 0.0; + auto qyZDCA = 0.0; + auto qyZDCC = 0.0; + auto sumA = 0.0; + auto sumC = 0.0; + + auto bc = collision.foundBC_as(); + + if (!bc.has_zdc()) { + triggerevent = false; + spcalibrationtable(triggerevent, currentRunNumber, centrality, vx, vy, vz, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, qxZDCA, qxZDCC, qyZDCA, qyZDCC, psiZDCC, psiZDCA); + return; + } + + auto zdc = bc.zdc(); + auto zncEnergy = zdc.energySectorZNC(); + auto znaEnergy = zdc.energySectorZNA(); + auto zncEnergycommon = zdc.energyCommonZNC(); + auto znaEnergycommon = zdc.energyCommonZNA(); + + if (znaEnergycommon <= 0.0 || zncEnergycommon <= 0.0) { + triggerevent = false; + spcalibrationtable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3], qxZDCA, qxZDCC, qyZDCA, qyZDCC, psiZDCC, psiZDCA); + return; + } + + if (znaEnergy[0] <= 0.0 || znaEnergy[1] <= 0.0 || znaEnergy[2] <= 0.0 || znaEnergy[3] <= 0.0) { + triggerevent = false; + spcalibrationtable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3], qxZDCA, qxZDCC, qyZDCA, qyZDCC, psiZDCC, psiZDCA); + return; + } + if (zncEnergy[0] <= 0.0 || zncEnergy[1] <= 0.0 || zncEnergy[2] <= 0.0 || zncEnergy[3] <= 0.0) { + triggerevent = false; + spcalibrationtable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3], qxZDCA, qxZDCC, qyZDCA, qyZDCC, psiZDCC, psiZDCA); + return; + } + + // if (collision.sel8() && centrality > cfgCutCentralityMin && centrality < cfgCutCentralityMax && TMath::Abs(vz) < cfgCutVertex && collision.has_foundFT0() && eventSelected(collision, centrality) && collision.selection_bit(aod::evsel::kNoTimeFrameBorder) && collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + if (collision.sel8() && centrality > cfgCutCentralityMin && centrality < cfgCutCentralityMax && TMath::Abs(vz) < cfgCutVertex && collision.has_foundFT0() && collision.selection_bit(aod::evsel::kNoTimeFrameBorder) && collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + triggerevent = true; + if (useGainCallib && (currentRunNumber != lastRunNumber)) { + gainprofile = ccdb->getForTimeStamp(ConfGainPath.value, bc.timestamp()); + } + + auto gainequal = 1.0; + auto alphaZDC = 0.395; + constexpr double x[4] = {-1.75, 1.75, -1.75, 1.75}; + constexpr double y[4] = {-1.75, -1.75, 1.75, 1.75}; + + histos.fill(HIST("ZDCAmpCommon"), 0.5, vz, znaEnergycommon); + histos.fill(HIST("ZDCAmpCommon"), 1.5, vz, zncEnergycommon); + + for (std::size_t iChA = 0; iChA < 8; iChA++) { + auto chanelid = iChA; + if (useGainCallib && gainprofile) { + gainequal = gainprofile->GetBinContent(gainprofile->FindBin(vz, chanelid + 0.5)); + } + + if (iChA < 4) { + + if (znaEnergy[iChA] <= 0.0) { + triggerevent = false; + spcalibrationtable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3], qxZDCA, qxZDCC, qyZDCA, qyZDCC, psiZDCC, psiZDCA); + return; + } else { + double ampl = gainequal * znaEnergy[iChA]; + if (followpub) { + ampl = TMath::Power(ampl, alphaZDC); + } + qxZDCA = qxZDCA - ampl * x[iChA]; + qyZDCA = qyZDCA + ampl * y[iChA]; + sumA = sumA + ampl; + histos.fill(HIST("ZDCAmp"), chanelid + 0.5, vz, ampl); + } + } else { + if (zncEnergy[iChA - 4] <= 0.0) { + triggerevent = false; + spcalibrationtable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3], qxZDCA, qxZDCC, qyZDCA, qyZDCC, psiZDCC, psiZDCA); + return; + } else { + double ampl = gainequal * zncEnergy[iChA - 4]; + if (followpub) { + ampl = TMath::Power(ampl, alphaZDC); + } + qxZDCC = qxZDCC + ampl * x[iChA - 4]; + qyZDCC = qyZDCC + ampl * y[iChA - 4]; + sumC = sumC + ampl; + histos.fill(HIST("ZDCAmp"), chanelid + 0.5, vz, ampl); + } + } + } + + if (sumA > 0) { + qxZDCA = qxZDCA / sumA; + qyZDCA = qyZDCA / sumA; + } + if (sumC > 0) { + qxZDCC = qxZDCC / sumC; + qyZDCC = qyZDCC / sumC; + } + + if (sumA <= 1e-4 || sumC <= 1e-4) { + qxZDCA = 0.0; + qxZDCC = 0.0; + qyZDCA = 0.0; + qyZDCC = 0.0; + triggerevent = false; + spcalibrationtable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3], qxZDCA, qxZDCC, qyZDCA, qyZDCC, psiZDCC, psiZDCA); + return; + } + + histos.fill(HIST("hCentrality"), centrality); + histos.fill(HIST("Vz"), vz); + + histos.fill(HIST("AvgVxy"), 0.5, vx); + histos.fill(HIST("AvgVxy"), 1.5, vy); + + if (useCallibvertex && (currentRunNumber != lastRunNumber)) { + gainprofilevxy = ccdb->getForTimeStamp(ConfGainPathvxy.value, bc.timestamp()); + } + + if (useCallibvertex) { + vx = vx - gainprofilevxy->GetBinContent(1); + vy = vy - gainprofilevxy->GetBinContent(2); + } + + Bool_t res = 0; + Bool_t resfine = 0; + + if (coarse1) { + if (useRecentereSp && (currentRunNumber != lastRunNumber)) { + hrecentereSpA[0] = ccdb->getForTimeStamp(ConfRecentereSp.value, bc.timestamp()); + } + res = Correctcoarse(hrecentereSpA[0], centrality, vx, vy, vz, qxZDCA, qyZDCA, qxZDCC, qyZDCC); + } + + if (fine1) { + + if (useRecenterefineSp && (currentRunNumber != lastRunNumber)) { + hrecenterecentSpA[0] = ccdb->getForTimeStamp(ConfRecenterecentSp.value, bc.timestamp()); + hrecenterevxSpA[0] = ccdb->getForTimeStamp(ConfRecenterevxSp.value, bc.timestamp()); + hrecenterevySpA[0] = ccdb->getForTimeStamp(ConfRecenterevySp.value, bc.timestamp()); + hrecenterevzSpA[0] = ccdb->getForTimeStamp(ConfRecenterevzSp.value, bc.timestamp()); + } + resfine = Correctfine(hrecenterecentSpA[0], hrecenterevxSpA[0], hrecenterevySpA[0], hrecenterevzSpA[0], centrality, vx, vy, vz, qxZDCA, qyZDCA, qxZDCC, qyZDCC); + } + + if (coarse2) { + if (useRecentereSp && (currentRunNumber != lastRunNumber)) { + hrecentereSpA[1] = ccdb->getForTimeStamp(ConfRecentereSp2.value, bc.timestamp()); + } + res = Correctcoarse(hrecentereSpA[1], centrality, vx, vy, vz, qxZDCA, qyZDCA, qxZDCC, qyZDCC); + } + + if (fine2) { + if (useRecenterefineSp && (currentRunNumber != lastRunNumber)) { + hrecenterecentSpA[1] = ccdb->getForTimeStamp(ConfRecenterecentSp2.value, bc.timestamp()); + hrecenterevxSpA[1] = ccdb->getForTimeStamp(ConfRecenterevxSp2.value, bc.timestamp()); + hrecenterevySpA[1] = ccdb->getForTimeStamp(ConfRecenterevySp2.value, bc.timestamp()); + hrecenterevzSpA[1] = ccdb->getForTimeStamp(ConfRecenterevzSp2.value, bc.timestamp()); + } + resfine = Correctfine(hrecenterecentSpA[1], hrecenterevxSpA[1], hrecenterevySpA[1], hrecenterevzSpA[1], centrality, vx, vy, vz, qxZDCA, qyZDCA, qxZDCC, qyZDCC); + } + + if (coarse3) { + if (useRecentereSp && (currentRunNumber != lastRunNumber)) { + hrecentereSpA[2] = ccdb->getForTimeStamp(ConfRecentereSp3.value, bc.timestamp()); + } + res = Correctcoarse(hrecentereSpA[2], centrality, vx, vy, vz, qxZDCA, qyZDCA, qxZDCC, qyZDCC); + } + + if (fine3) { + if (useRecenterefineSp && (currentRunNumber != lastRunNumber)) { + hrecenterecentSpA[2] = ccdb->getForTimeStamp(ConfRecenterecentSp3.value, bc.timestamp()); + hrecenterevxSpA[2] = ccdb->getForTimeStamp(ConfRecenterevxSp3.value, bc.timestamp()); + hrecenterevySpA[2] = ccdb->getForTimeStamp(ConfRecenterevySp3.value, bc.timestamp()); + hrecenterevzSpA[2] = ccdb->getForTimeStamp(ConfRecenterevzSp3.value, bc.timestamp()); + } + resfine = Correctfine(hrecenterecentSpA[2], hrecenterevxSpA[2], hrecenterevySpA[2], hrecenterevzSpA[2], centrality, vx, vy, vz, qxZDCA, qyZDCA, qxZDCC, qyZDCC); + } + + if (coarse4) { + if (useRecentereSp && (currentRunNumber != lastRunNumber)) { + hrecentereSpA[3] = ccdb->getForTimeStamp(ConfRecentereSp4.value, bc.timestamp()); + } + res = Correctcoarse(hrecentereSpA[3], centrality, vx, vy, vz, qxZDCA, qyZDCA, qxZDCC, qyZDCC); + } + + if (fine4) { + if (useRecenterefineSp && (currentRunNumber != lastRunNumber)) { + hrecenterecentSpA[3] = ccdb->getForTimeStamp(ConfRecenterecentSp4.value, bc.timestamp()); + hrecenterevxSpA[3] = ccdb->getForTimeStamp(ConfRecenterevxSp4.value, bc.timestamp()); + hrecenterevySpA[3] = ccdb->getForTimeStamp(ConfRecenterevySp4.value, bc.timestamp()); + hrecenterevzSpA[3] = ccdb->getForTimeStamp(ConfRecenterevzSp4.value, bc.timestamp()); + } + resfine = Correctfine(hrecenterecentSpA[3], hrecenterevxSpA[3], hrecenterevySpA[3], hrecenterevzSpA[3], centrality, vx, vy, vz, qxZDCA, qyZDCA, qxZDCC, qyZDCC); + } + + if (coarse5) { + if (useRecentereSp && (currentRunNumber != lastRunNumber)) { + hrecentereSpA[4] = ccdb->getForTimeStamp(ConfRecentereSp5.value, bc.timestamp()); + } + res = Correctcoarse(hrecentereSpA[4], centrality, vx, vy, vz, qxZDCA, qyZDCA, qxZDCC, qyZDCC); + } + + if (fine5) { + if (useRecenterefineSp && (currentRunNumber != lastRunNumber)) { + hrecenterecentSpA[4] = ccdb->getForTimeStamp(ConfRecenterecentSp5.value, bc.timestamp()); + hrecenterevxSpA[4] = ccdb->getForTimeStamp(ConfRecenterevxSp5.value, bc.timestamp()); + hrecenterevySpA[4] = ccdb->getForTimeStamp(ConfRecenterevySp5.value, bc.timestamp()); + hrecenterevzSpA[4] = ccdb->getForTimeStamp(ConfRecenterevzSp5.value, bc.timestamp()); + } + resfine = Correctfine(hrecenterecentSpA[4], hrecenterevxSpA[4], hrecenterevySpA[4], hrecenterevzSpA[4], centrality, vx, vy, vz, qxZDCA, qyZDCA, qxZDCC, qyZDCC); + } + + if (coarse6) { + if (useRecentereSp && (currentRunNumber != lastRunNumber)) { + hrecentereSpA[5] = ccdb->getForTimeStamp(ConfRecentereSp6.value, bc.timestamp()); + } + res = Correctcoarse(hrecentereSpA[5], centrality, vx, vy, vz, qxZDCA, qyZDCA, qxZDCC, qyZDCC); + } + + if (res == 0 || resfine == 0) { + } + psiZDCC = 1.0 * TMath::ATan2(qyZDCC, qxZDCC); + psiZDCA = 1.0 * TMath::ATan2(qyZDCA, qxZDCA); + + int nshift = 10; // no. of iterations + + if (useShift && (currentRunNumber != lastRunNumber)) { + shiftprofileC = ccdb->getForTimeStamp(ConfShiftC.value, bc.timestamp()); + shiftprofileA = ccdb->getForTimeStamp(ConfShiftA.value, bc.timestamp()); + } + + if (useShift) { + auto deltapsiZDCC = 0.0; + auto deltapsiZDCA = 0.0; + for (int ishift = 1; ishift <= nshift; ishift++) { + auto coeffshiftxZDCC = shiftprofileC->GetBinContent(shiftprofileC->FindBin(centrality, 0.5, ishift - 0.5)); + auto coeffshiftyZDCC = shiftprofileC->GetBinContent(shiftprofileC->FindBin(centrality, 1.5, ishift - 0.5)); + auto coeffshiftxZDCA = shiftprofileA->GetBinContent(shiftprofileA->FindBin(centrality, 0.5, ishift - 0.5)); + auto coeffshiftyZDCA = shiftprofileA->GetBinContent(shiftprofileA->FindBin(centrality, 1.5, ishift - 0.5)); + deltapsiZDCC = deltapsiZDCC + ((2 / (1.0 * ishift)) * (-coeffshiftxZDCC * TMath::Cos(ishift * 1.0 * psiZDCC) + coeffshiftyZDCC * TMath::Sin(ishift * 1.0 * psiZDCC))); + deltapsiZDCA = deltapsiZDCA + ((2 / (1.0 * ishift)) * (-coeffshiftxZDCA * TMath::Cos(ishift * 1.0 * psiZDCA) + coeffshiftyZDCA * TMath::Sin(ishift * 1.0 * psiZDCA))); + } + psiZDCC = psiZDCC + deltapsiZDCC; + psiZDCA = psiZDCA + deltapsiZDCA; + } + + for (int ishift = 1; ishift <= nshift; ishift++) { + histos.fill(HIST("ShiftZDCC"), centrality, 0.5, ishift - 0.5, TMath::Sin(ishift * 1.0 * psiZDCC)); + histos.fill(HIST("ShiftZDCC"), centrality, 1.5, ishift - 0.5, TMath::Cos(ishift * 1.0 * psiZDCC)); + histos.fill(HIST("ShiftZDCA"), centrality, 0.5, ishift - 0.5, TMath::Sin(ishift * 1.0 * psiZDCA)); + histos.fill(HIST("ShiftZDCA"), centrality, 1.5, ishift - 0.5, TMath::Cos(ishift * 1.0 * psiZDCA)); + } + + histos.fill(HIST("hpQxZDCAC"), centrality, (qxZDCA * qxZDCC)); + histos.fill(HIST("hpQyZDCAC"), centrality, (qyZDCA * qyZDCC)); + histos.fill(HIST("hpQxZDCAQyZDCC"), centrality, (qxZDCA * qyZDCC)); + histos.fill(HIST("hpQxZDCCQyZDCA"), centrality, (qxZDCC * qyZDCA)); + + if (!ispolarization) { + histos.fill(HIST("hnQxZDCA"), centrality, vx, vy, vz, qxZDCA); + histos.fill(HIST("hnQyZDCA"), centrality, vx, vy, vz, qyZDCA); + histos.fill(HIST("hnQxZDCC"), centrality, vx, vy, vz, qxZDCC); + histos.fill(HIST("hnQyZDCC"), centrality, vx, vy, vz, qyZDCC); + + histos.fill(HIST("hcentQxZDCA"), centrality, qxZDCA); + histos.fill(HIST("hcentQyZDCA"), centrality, qyZDCA); + histos.fill(HIST("hcentQxZDCC"), centrality, qxZDCC); + histos.fill(HIST("hcentQyZDCC"), centrality, qyZDCC); + + histos.fill(HIST("hvxQxZDCA"), vx, qxZDCA); + histos.fill(HIST("hvxQyZDCA"), vx, qyZDCA); + histos.fill(HIST("hvxQxZDCC"), vx, qxZDCC); + histos.fill(HIST("hvxQyZDCC"), vx, qyZDCC); + + histos.fill(HIST("hvyQxZDCA"), vy, qxZDCA); + histos.fill(HIST("hvyQyZDCA"), vy, qyZDCA); + histos.fill(HIST("hvyQxZDCC"), vy, qxZDCC); + histos.fill(HIST("hvyQyZDCC"), vy, qyZDCC); + + histos.fill(HIST("hvzQxZDCA"), vz, qxZDCA); + histos.fill(HIST("hvzQyZDCA"), vz, qyZDCA); + histos.fill(HIST("hvzQxZDCC"), vz, qxZDCC); + histos.fill(HIST("hvzQyZDCC"), vz, qyZDCC); + } + + histos.fill(HIST("hpCosPsiAPsiC"), centrality, (TMath::Cos(psiZDCA - psiZDCC))); + histos.fill(HIST("hpSinPsiAPsiC"), centrality, (TMath::Sin(psiZDCA - psiZDCC))); + histos.fill(HIST("PsiZDCA"), centrality, psiZDCA); + histos.fill(HIST("PsiZDCC"), centrality, psiZDCC); + + lastRunNumber = currentRunNumber; + } + spcalibrationtable(triggerevent, currentRunNumber, centrality, vx, vy, vz, znaEnergycommon, zncEnergycommon, znaEnergy[0], znaEnergy[1], znaEnergy[2], znaEnergy[3], zncEnergy[0], zncEnergy[1], zncEnergy[2], zncEnergy[3], qxZDCA, qxZDCC, qyZDCA, qyZDCC, psiZDCC, psiZDCA); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/zdcSP.cxx b/PWGLF/TableProducer/Common/zdcSP.cxx similarity index 100% rename from PWGLF/TableProducer/zdcSP.cxx rename to PWGLF/TableProducer/Common/zdcSP.cxx diff --git a/PWGLF/TableProducer/Nuspex/CMakeLists.txt b/PWGLF/TableProducer/Nuspex/CMakeLists.txt index 3150e9b7555..e8ec0868378 100644 --- a/PWGLF/TableProducer/Nuspex/CMakeLists.txt +++ b/PWGLF/TableProducer/Nuspex/CMakeLists.txt @@ -11,7 +11,7 @@ o2physics_add_dpl_workflow(decay3bodybuilder SOURCES decay3bodybuilder.cxx - PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2::DCAFitter KFParticle::KFParticle O2Physics::AnalysisCore O2::TOFBase O2Physics::EventFilteringUtils O2::DetectorsVertexing COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(hyhefour-builder @@ -19,14 +19,9 @@ o2physics_add_dpl_workflow(hyhefour-builder PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(hyper-kink-reco-task - SOURCES hyperKinkRecoTask.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(hypertriton-reco-task SOURCES hyperRecoTask.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(lnn-reco-task @@ -43,14 +38,15 @@ o2physics_add_dpl_workflow(nucleustreecreator SOURCES LFTreeCreatorNuclei.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(lithium4analysis - SOURCES lithium4analysis.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + +o2physics_add_dpl_workflow(he3hadronfemto + SOURCES he3HadronFemto.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(nuclei-spectra SOURCES nucleiSpectra.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(spectra-derived @@ -65,5 +61,50 @@ o2physics_add_dpl_workflow(threebodymcfinder o2physics_add_dpl_workflow(threebody-reco-task SOURCES threebodyRecoTask.cxx + PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(ebye-maker + SOURCES ebyeMaker.cxx PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(cluster-studies-tree-creator + SOURCES LFTreeCreatorClusterStudies.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pidtof-generic + SOURCES pidTOFGeneric.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::TOFBase + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(threebody-kf-task + SOURCES threebodyKFTask.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(hypernuclei-kf-reco-task + SOURCES hypKfRecoTask.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore KFParticle::KFParticle + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(hypernuclei-kf-tree-creator + SOURCES hypKfTreeCreator.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(tr-he-analysis + SOURCES trHeAnalysis.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(reduced3body-creator + SOURCES reduced3bodyCreator.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore KFParticle::KFParticle O2Physics::EventFilteringUtils O2::TOFBase + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(nuclei-flow-trees + SOURCES nucleiFlowTree.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) diff --git a/PWGLF/TableProducer/Nuspex/LFTreeCreatorClusterStudies.cxx b/PWGLF/TableProducer/Nuspex/LFTreeCreatorClusterStudies.cxx new file mode 100644 index 00000000000..237b4538a2d --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/LFTreeCreatorClusterStudies.cxx @@ -0,0 +1,1330 @@ +// 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. +// +// TableProducer to generate Trees for pure protons ans pions (from Lambda), Kaons (from Omegas), deuterons (identified with TOF) and He3 (identified with TPC). +// The output trees contain the ITS cluster size information. +// +// Author: Giorgio Alberto Lucia + +#include +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + +#include "Common/Core/PID/PIDTOF.h" +#include "Common/TableProducer/PID/pidTOFBase.h" +#include "Common/Core/PID/TPCPIDResponse.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "DCAFitter/DCAFitterN.h" + +#include "PWGLF/DataModel/LFClusterStudiesTable.h" + +#include "TDatabasePDG.h" +#include "TPDGCode.h" + +using namespace ::o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using Track = o2::track::TrackParCov; +using TracksFullIU = soa::Join; +using TracksFullIUMc = soa::Join; +using CollisionsCustom = soa::Join; + +namespace BetheBloch +{ + +constexpr double defaultParams[1][6]{{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}}; +static const std::vector parNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; + +} // namespace BetheBloch + +enum V0Type : uint8_t { + K0s = 0, + Lambda, + AntiLambda, + Photon, + V0TypeAll +}; + +enum CascadeType : uint8_t { + XiMinus = 0, + OmegaMinus +}; + +enum Selections { + kNoCut = 0, + kSel8, + kVtxZ, + kAll +}; + +enum V0Selections { + kV0NoCut = 0, + kV0DaughterQuality, + kV0DaughterDCA, + // kV0DCA, + kV0Radius, + kV0CosPA, + kV0PID, + kV0DaughterDCAtoPV, + kV0All +}; + +enum CascSelections { + kCascNoCut = 0, + kCascDCA, + kCascCosPA, + kAcceptedOmega, + kRejectedXi, + kNSigmaTPC, + kCascAll +}; + +enum DeSelections { + kDeNoCut = 0, + kDeNClsIts, + kDePIDtpc, + kDePIDtof, + kDeAll +}; + +enum He3Selections { + kHe3NoCut = 0, + kHe3NClsIts, + kHe3PIDtpc, + kHe3PIDtof, + kHe3All +}; + +enum PartID { + none = 0, + el, + pi, + ka, + pr, + de, + he +}; + +struct LfTreeCreatorClusterStudies { + + Service m_ccdb; + int m_runNumber; + int m_collisionCounter = 0; + float m_d_bz; + uint32_t m_randomSeed = 0.; + + Configurable setting_fillV0{"fillV0", true, "Fill the V0 tree"}; + Configurable setting_fillK{"fillK", true, "Fill the K tree"}; + Configurable setting_fillDe{"fillDe", true, "Fill the De tree"}; + Configurable setting_fillHe3{"fillHe3", true, "Fill the He3 tree"}; + Configurable setting_fillPKPi{"fillPKPPi", true, "Fill the p, K, pi tree"}; + Configurable setting_smallTable{"smallTable", true, "Use a small table for testing"}; + + Configurable setting_materialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Type of material correction"}; + + Configurable setting_zVtxMax{"zVtxMax", 10.f, "Maximum z vertex position"}; + + Configurable setting_downscaleFactor{"downscaleFactor", 1.f, "Downscale factor for the V0 candidates"}; + Configurable setting_applyAdditionalEvSel{"applyAdditionalEvSel", false, "Apply additional event selection"}; + + Configurable track_nClsItsMin{"track_NclsItsMin", 0.f, "Minimum number of ITS clusters for the V0 daughters"}; + Configurable track_nClsTpcMin{"track_NclsTpcMin", 100.f, "Minimum number of TPC clusters for the V0 daughters"}; + Configurable track_nClsTpcMaxShared{"track_NclsTpcMaxShared", 5.f, "Maximum number of shared TPC clusters for the V0 daughters"}; + + // Configurable v0setting_etaMaxV0{"etaMaxV0", 0.8f, "Maximum eta for the V0 daughters"}; + Configurable v0setting_etaMaxV0dau{"etaMaxV0dau", 0.8f, "Maximum eta for the V0 daughters"}; + Configurable v0setting_dcaV0daughters{"v0setting_dcaV0daughters", 0.5f, "DCA between the V0 daughters"}; + Configurable v0setting_dcaV0toPV{"v0setting_dcaV0fromPV", 1.f, "DCA of the V0 to the primary vertex"}; + Configurable v0setting_dcaDaughtersToPV{"v0setting_dcaDaughtersToPV", 1.f, "DCA of the daughters to the primary vertex"}; + Configurable v0setting_radiusMax{"v0setting_radiusMax", 100.f, "Maximum radius of the V0 accepted"}; + Configurable v0setting_radiusMin{"v0setting_radiusMin", 5.f, "Minimum radius of the V0 accepted"}; + Configurable v0setting_cosPA{"v0setting_cosPA", 0.99f, "Cosine of the pointing angle of the V0"}; + Configurable v0setting_nsigmatpc{"v0setting_nsigmaTPC", 4.f, "Number of sigmas for the TPC PID"}; + Configurable v0setting_massWindowLambda{"v0setting_massWindowLambda", 0.02f, "Mass window for the Lambda"}; + Configurable v0setting_massWindowK0s{"v0setting_massWindowK0s", 0.02f, "Mass window for the K0s"}; + Configurable v0setting_nsigmatpcEl{"v0setting_nsigmaTPCEl", 1.f, "Number of sigmas for the TPC PID for electrons"}; + Configurable v0setting_nsigmatpcPi{"v0setting_nsigmaTPCPi", 2.f, "Number of sigmas for the TPC PID for pions"}; + Configurable v0setting_nsigmatpcPr{"v0setting_nsigmaTPCPr", 2.f, "Number of sigmas for the TPC PID for protons"}; + Configurable lambdasetting_qtAPcut{"lambdasetting_qtAPcut", 0.02f, "Cut on the qt for the Armenteros-Podolanski plot for photon rejection"}; + Configurable lambdasetting_pmin{"lambdasetting_pmin", 0.0f, "Minimum momentum for the V0 daughters"}; + + Configurable cascsetting_dcaCascDaughters{"casc_setting_dcaV0daughters", 0.1f, "DCA between the V0 daughters"}; + Configurable cascsetting_cosPA{"casc_setting_cosPA", 0.99f, "Cosine of the pointing angle of the V0"}; + Configurable cascsetting_massWindowOmega{"casc_setting_massWindowOmega", 0.01f, "Mass window for the Omega"}; + Configurable cascsetting_massWindowXi{"casc_setting_massWindowXi", 0.01f, "Mass window for the Xi"}; + Configurable cascsetting_nsigmatpc{"casc_setting_nsigmaTPC", 3.f, "Number of sigmas for the TPC PID"}; + + Configurable desetting_nClsIts{"desetting_nClsIts", 6, "Minimum number of ITS clusters"}; + Configurable desetting_nsigmatpc{"desetting_nsigmaCutTPC", 2.f, "Number of sigmas for the TPC PID"}; + Configurable desetting_nsigmatof{"desetting_nsigmaCutTOF", 2.f, "Number of sigmas for the TOF PID"}; + Configurable he3setting_nClsIts{"he3setting_nClsIts", 6, "Minimum number of ITS clusters"}; + Configurable he3setting_compensatePIDinTracking{"he3setting_compensatePIDinTracking", true, "Compensate PID in tracking"}; + Configurable he3setting_nsigmatpc{"he3setting_nsigmaCutTPC", 2.f, "Number of sigmas for the TPC PID"}; + Configurable he3setting_tofmasslow{"he3setting_tofmasslow", 1.8f, "Lower limit for the TOF mass"}; + Configurable he3setting_tofmasshigh{"he3setting_tofmasshigh", 4.2f, "Upper limit for the TOF mass"}; + + // Bethe Bloch parameters + std::array m_BBparamsDe, m_BBparamsHe; + Configurable> setting_BetheBlochParams{"setting_BetheBlochParams", {BetheBloch::defaultParams[0], 2, 6, {"De", "He3"}, BetheBloch::parNames}, "TPC Bethe-Bloch parameterisation for nuclei"}; + + Preslice m_perCollisionV0 = o2::aod::v0::collisionId; + Preslice m_perCollisionCascade = o2::aod::cascade::collisionId; + Preslice m_perCol = aod::track::collisionId; + Preslice m_perColMC = aod::track::collisionId; + + HistogramRegistry m_hAnalysis{ + "LFTreeCreator", + {{"collision_selections", "Collision selection; selection; counts", {HistType::kTH1F, {{Selections::kAll, -0.5, static_cast(Selections::kAll) - 0.5}}}}, + {"v0_selections", "V0 selection; selection; counts", {HistType::kTH1F, {{V0Selections::kV0All, -0.5, static_cast(V0Selections::kV0All) - 0.5}}}}, + {"casc_selections", "Cascade selection; selection; counts", {HistType::kTH1F, {{CascSelections::kCascAll, -0.5, static_cast(CascSelections::kCascAll) - 0.5}}}}, + {"de_selections", "Deuteron track selection; selection; counts", {HistType::kTH1F, {{DeSelections::kDeAll, -0.5, static_cast(DeSelections::kDeAll) - 0.5}}}}, + {"he3_selections", "He3 track selection; selection; counts", {HistType::kTH1F, {{He3Selections::kHe3All, -0.5, static_cast(He3Selections::kHe3All) - 0.5}}}}, + {"v0_type", "Selected V0; particle; counts", {HistType::kTH1F, {{V0Type::V0TypeAll, -0.5, static_cast(V0Type::V0TypeAll) - 0.5}}}}, + {"radiusV0", "Decay radius (xy) V0; radius (cm); counts", {HistType::kTH1F, {{100, 0., 100.}}}}, + {"massLambda", "#Lambda invariant mass; signed #it{p} (GeV/#it{c}); m (GeV/#it{c}^{2})", {HistType::kTH2F, {{100, -5.f, 5.f}, {50, 1.08f, 1.18f}}}}, + {"Lambda_vs_K0s", "Mass #Lambda vs K^{0}_s; m_{K^{0}_{s}} (GeV/#it{c}^{2}); m_{#Lambda} (GeV/#it{c}^{2})", {HistType::kTH2F, {{50, 0.f, 1.f}, {70, 0.6f, 2.f}}}}, + {"armenteros_plot_before_selections", "Armenteros-Podolanski plot; #alpha; q_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -1.f, 1.f}, {100, 0.f, 0.3f}}}}, + {"armenteros_plot", "Armenteros-Podolanski plot; #alpha; q_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -1.f, 1.f}, {100, 0.f, 0.3f}}}}, + {"armenteros_plot_lambda", "Armenteros-Podolanski plot (#Lambda only); #alpha; q_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -1.f, 1.f}, {100, 0.f, 0.3f}}}}, + {"armenteros_plot_gamma", "Armenteros-Podolanski plot (#gamma only); #alpha; q_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -1.f, 1.f}, {100, 0.f, 0.3f}}}}, + {"photon_radiusV0", "Photon conversion radius (xy) V0; radius (cm); counts", {HistType::kTH1F, {{100, 0., 100.}}}}, + {"photon_conversion_position", "Photon conversion position; x (cm); y (cm)", {HistType::kTH2F, {{250, -5.f, 5.f}, {250, -5.f, 5.f}}}}, + {"photon_conversion_position_layer", "Photon conversion position (ITS layers); x (cm); y (cm)", {HistType::kTH2F, {{100, -5.f, 5.f}, {100, -5.f, 5.f}}}}, + {"Xi_vs_Omega", "Mass Xi vs Omega; mass Omega (GeV/#it{c}^{2}); mass Xi (GeV/#it{c}^{2})", {HistType::kTH2F, {{50, 1.f, 2.f}, {50, 1.f, 2.f}}}}, + {"massOmega", "Mass #Omega; signed #it{p}_{T} (GeV/#it{c}); mass (GeV/#it{c}^{2})", {HistType::kTH2F, {{100, -5.f, 5.f}, {100, 1.62f, 1.72f}}}}, + {"massOmegaWithBkg", "Mass Omega with Background; mass Omega (GeV/#it{c}^{2}); counts", {HistType::kTH1F, {{100, 1.62f, 1.72f}}}}, + {"nSigmaTPCEl", "nSigma TPC Electron; signed #it{p} (GeV/#it{c}); n#sigma_{TPC} e", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {60, -2.0f, 2.0f}}}}, + {"nSigmaTPCPi", "nSigma TPC Pion; signed #it{p} (GeV/#it{c}); n#sigma_{TPC} #pi", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {60, -3.0f, 3.0f}}}}, + {"nSigmaTPCKa", "nSigma TPC Kaon; signed #it{p} (GeV/#it{c}); n#sigma_{TPC} e", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {60, -4.0f, 4.0f}}}}, + {"nSigmaTPCPr", "nSigma TPC Proton; signed #it{p} (GeV/#it{c}); n#sigma_{TPC} p", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {60, -3.0f, 3.0f}}}}, + {"nSigmaTPCDe", "nSigma TPC Deuteron; signed #it{p} (GeV/#it{c}); n#sigma_{TPC} d", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {100, -3.0f, 3.0f}}}}, + {"nSigmaTPCHe", "nSigma TPC He3; signed #it{p} (GeV/#it{c}); n#sigma_{TPC} ^{3}He", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {100, -3.0f, 3.0f}}}}, + {"nSigmaTOFDe", "nSigma TOF Deuteron; signed #it{p} (GeV/#it{c}); n#sigma_{TOF} d", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {100, -3.0f, 3.0f}}}}, + {"TOFmassDe", "TOF mass De; signed #it{p}_{T} (GeV/#it{c}); mass_{TOF} ^{3}He (GeV/#it{c}^2)", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {100, 1.0f, 5.0f}}}}, + {"TOFmassHe", "TOF mass He3; signed #it{p}_{T} (GeV/#it{c}); mass_{TOF} ^{3}He (GeV/#it{c}^2)", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {100, 1.0f, 5.0f}}}}, + {"nSigmaITSEl", "nSigma ITS Electron; signed #it{p} (GeV/#it{c}); n#sigma_{ITS} e", {HistType::kTH2F, {{50, -5.0f, 5.0f}, {60, -2.0f, 2.0f}}}}, + {"nSigmaITSPi", "nSigma ITS Pion; signed #it{p} (GeV/#it{c}); n#sigma_{ITS} #pi", {HistType::kTH2F, {{50, -5.0f, 5.0f}, {60, -3.0f, 3.0f}}}}, + {"nSigmaITSKa", "nSigma ITS Kaon; signed #it{p} (GeV/#it{c}); n#sigma_{ITS} e", {HistType::kTH2F, {{50, -5.0f, 5.0f}, {60, -4.0f, 4.0f}}}}, + {"nSigmaITSPr", "nSigma ITS Proton; signed #it{p} (GeV/#it{c}); n#sigma_{ITS} p", {HistType::kTH2F, {{50, -5.0f, 5.0f}, {60, -3.0f, 3.0f}}}}, + {"nSigmaITSDe", "nSigma ITS Deuteron; signed #it{p} (GeV/#it{c}); n#sigma_{ITS} d", {HistType::kTH2F, {{50, -5.0f, 5.0f}, {100, -3.0f, 3.0f}}}}, + {"nSigmaITSHe", "nSigma ITS He3; signed #it{p} (GeV/#it{c}); n#sigma_{ITS} ^{3}He", {HistType::kTH2F, {{50, -5.0f, 5.0f}, {100, -3.0f, 3.0f}}}}, + {"pmatchingEl", "#it{p} matching e; signed #it{p}_{TPC} (GeV/#it{c}); #frac{#it{p}_{TPC} - #it{p}}{#it{p}_{TPC}}", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {100, -0.5f, 0.5f}}}}, + {"pmatchingPi", "#it{p} matching #pi; signed #it{p}_{TPC} (GeV/#it{c}); #frac{#it{p}_{TPC} - #it{p}}{#it{p}_{TPC}}", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {100, -0.5f, 0.5f}}}}, + {"pmatchingKa", "#it{p} matching K; signed #it{p}_{TPC} (GeV/#it{c}); #frac{#it{p}_{TPC} - #it{p}}{#it{p}_{TPC}}", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {100, -0.5f, 0.5f}}}}, + {"pmatchingPr", "#it{p} matching p; signed #it{p}_{TPC} (GeV/#it{c}); #frac{#it{p}_{TPC} - #it{p}}{#it{p}_{TPC}}", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {100, -0.5f, 0.5f}}}}, + {"pmatchingDe", "#it{p} matching d; signed #it{p}_{TPC} (GeV/#it{c}); #frac{#it{p}_{TPC} - #it{p}}{#it{p}_{TPC}}", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {100, -0.5f, 0.5f}}}}, + {"pmatchingHe", "#it{p} matching ^{3}He; signed #it{p}_{TPC} (GeV/#it{c}); #frac{#it{p}_{TPC} - #it{p}}{#it{p}_{TPC}}", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {100, -0.5f, 0.5f}}}}, + {"zVtx", "Binning for the vertex z in cm", {HistType::kTH1F, {{100, -20.f, 20.f}}}}, + {"isPositive", "is the candidate positive?; isPositive; counts", {HistType::kTH1F, {{2, -0.5f, 1.5f}}}}}, + OutputObjHandlingPolicy::AnalysisObject, + false, + true}; // check histograms + + Produces m_ClusterStudiesTable; + Produces m_ClusterStudiesTableExtra; + Produces m_ClusterStudiesTableMc; + Produces m_ClusterStudiesTableMcExtra; + + struct V0TrackParCov { + int64_t globalIndex; + Track trackParCov; + }; + std::vector m_v0TrackParCovs; + + o2::vertexing::DCAFitterN<2> m_fitter; + o2::aod::ITSResponse m_responseITS; + + template + bool initializeFitter(const T& trackParCovA, const T& trackParCovB) + { + int nCand = 0; + try { + nCand = m_fitter.process(trackParCovA, trackParCovB); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call!"; + return false; + } + if (nCand == 0) { + return false; + } + + return true; + } + + /** + * Compute the momentum of the track using the fitter + * @param itrack Index of the track in the fitter + * @param mom Array to store the momentum + */ + void computeTrackMomentum(const int itrack, std::array& mom) + { + auto fittedTrack = m_fitter.getTrack(itrack); + fittedTrack.getPxPyPzGlo(mom); + } + + void computeMotherMomentum(const std::array& momA, const std::array& momB, std::array& momMother) + { + momMother[0] = momA[0] + momB[0]; + momMother[1] = momA[1] + momB[1]; + momMother[2] = momA[2] + momB[2]; + } + + /** + * Compute the alpha for the Armenteros-Podolanski plot + */ + float computeAlphaAP(const std::array& momMother, const std::array& momP, const std::array& momN) + { + float lQlP = std::inner_product(momMother.begin(), momMother.end(), momP.begin(), 0.f); + float lQlN = std::inner_product(momMother.begin(), momMother.end(), momN.begin(), 0.f); + return (lQlP - lQlN) / (lQlP + lQlN); + } + + /** + * Compute the qt for the Armenteros-Podolanski plot + */ + float computeQtAP(const std::array& momMother, const std::array& momP) + { + float dp = std::inner_product(momMother.begin(), momMother.end(), momP.begin(), 0.f); + float p2V0 = std::inner_product(momMother.begin(), momMother.end(), momMother.begin(), 0.f); + float p2A = std::inner_product(momP.begin(), momP.end(), momP.begin(), 0.f); + return std::sqrt(p2A - dp * dp / p2V0); + } + + float dcaMotherToPV(const std::array& decayVtx, const std::array& PV, std::array momMother) const + { + std::array relPos = {decayVtx[0] - PV[0], decayVtx[1] - PV[1], decayVtx[2] - PV[2]}; + float lmomMotherl = std::hypot(momMother[0], momMother[1], momMother[2]); + return std::sqrt((std::pow(relPos[1] * momMother[2] - relPos[2] * momMother[1], 2) + std::pow(relPos[2] * momMother[0] - relPos[0] * momMother[2], 2) + std::pow(relPos[0] * momMother[1] - relPos[1] * momMother[0], 2))) / lmomMotherl; + } + + template + float dcaToPV(const std::array& PV, T& trackParCov, gpu::gpustd::array& dcaInfo) + { + o2::base::Propagator::Instance()->propagateToDCABxByBz({PV[0], PV[1], PV[2]}, trackParCov, 2.f, m_fitter.getMatCorrType(), &dcaInfo); + return std::hypot(dcaInfo[0], dcaInfo[1]); + } + + float computeMassMother(const float massA, const float massB, const std::array& momA, const std::array& momB, const std::array& momMother) const + { + float eA = std::hypot(massA, std::hypot(momA[0], momA[1], momA[2])); + float eB = std::hypot(massB, std::hypot(momB[0], momB[1], momB[2])); + float lmomMotherl = std::hypot(momMother[0], momMother[1], momMother[2]); + float eMother = eA + eB; + return std::sqrt(eMother * eMother - lmomMotherl * lmomMotherl); + } + + bool collisionSelection(const CollisionsCustom::iterator& collision) + { + m_hAnalysis.fill(HIST("collision_selections"), Selections::kNoCut); + if (!collision.sel8()) { + return false; + } + m_hAnalysis.fill(HIST("collision_selections"), Selections::kSel8); + // if (!collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + // return false; + // } + if (std::abs(collision.posZ()) > setting_zVtxMax) { + return false; + } + m_hAnalysis.fill(HIST("collision_selections"), Selections::kVtxZ); + return true; + } + + // ========================================================================================================= + + /** + * Select the V0 daughters based on the quality cuts + */ + template + bool qualityTrackSelection(const T& track) + { + if (std::abs(track.eta()) > v0setting_etaMaxV0dau) { + return false; + } + if (track.itsNCls() < track_nClsItsMin || + track.tpcNClsFound() < track_nClsTpcMin || + track.tpcNClsCrossedRows() < track_nClsTpcMin || + track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || + track.tpcNClsShared() > track_nClsTpcMaxShared) { + return false; + } + return true; + } + + bool qualitySelectionV0(const double /*dcaV0toPV*/, const double dcaV0daughters, const double radiusV0, const double cosPA) + { + if (std::abs(dcaV0daughters) > v0setting_dcaV0daughters) { + return false; + } + m_hAnalysis.fill(HIST("v0_selections"), V0Selections::kV0DaughterDCA); + if (radiusV0 > v0setting_radiusMax || radiusV0 < v0setting_radiusMin) { + return false; + } + m_hAnalysis.fill(HIST("v0_selections"), V0Selections::kV0Radius); + if (std::abs(cosPA) < v0setting_cosPA) { + return false; + } + m_hAnalysis.fill(HIST("v0_selections"), V0Selections::kV0CosPA); + return true; + } + + bool qualitySelectionCascade(const double dcaCascDaughters, const double cosPA) + { + if (std::abs(dcaCascDaughters) > cascsetting_dcaCascDaughters) { + return false; + } + m_hAnalysis.fill(HIST("casc_selections"), CascSelections::kCascDCA); + if (std::abs(cosPA) < cascsetting_cosPA) { + return false; + } + m_hAnalysis.fill(HIST("casc_selections"), CascSelections::kCascCosPA); + return true; + } + + // ========================================================================================================= + + template + bool nucleiTrackSelection(const T& track) + { + if (track.tpcNClsFound() < 90) { + return false; + } + return true; + } + + // ========================================================================================================= + + template + float computeNSigmaDe(const T& candidate) + { + float expTPCSignal = o2::tpc::BetheBlochAleph(static_cast(candidate.tpcInnerParam() / constants::physics::MassDeuteron), m_BBparamsDe[0], m_BBparamsDe[1], m_BBparamsDe[2], m_BBparamsDe[3], m_BBparamsDe[4]); + double resoTPC{expTPCSignal * m_BBparamsDe[5]}; + return static_cast((candidate.tpcSignal() - expTPCSignal) / resoTPC); + } + + template + bool selectionPIDtpcDe(const T& candidate) + { + auto nSigmaDe = computeNSigmaDe(candidate); + if (std::abs(nSigmaDe) < desetting_nsigmatpc) { + return true; + } + return false; + } + + template + float computeTOFmassDe(const T& candidate) + { + float beta = o2::pid::tof::Beta::GetBeta(candidate); + beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked + return candidate.tpcInnerParam() * 2.f * std::sqrt(1.f / (beta * beta) - 1.f); + } + + // ========================================================================================================= + + template + float computeNSigmaHe3(const T& candidate) + { + bool heliumPID = candidate.pidForTracking() == o2::track::PID::Helium3 || candidate.pidForTracking() == o2::track::PID::Alpha; + float correctedTPCinnerParam = (heliumPID && he3setting_compensatePIDinTracking) ? candidate.tpcInnerParam() / 2.f : candidate.tpcInnerParam(); + float expTPCSignal = o2::tpc::BetheBlochAleph(static_cast(correctedTPCinnerParam * 2.f / constants::physics::MassHelium3), m_BBparamsHe[0], m_BBparamsHe[1], m_BBparamsHe[2], m_BBparamsHe[3], m_BBparamsHe[4]); + double resoTPC{expTPCSignal * m_BBparamsHe[5]}; + return static_cast((candidate.tpcSignal() - expTPCSignal) / resoTPC); + } + + template + bool selectionPIDtpcHe3(const T& candidate) + { + auto nSigmaHe3 = computeNSigmaHe3(candidate); + if (std::abs(nSigmaHe3) < he3setting_nsigmatpc) { + return true; + } + return false; + } + + template + float computeTOFmassHe3(const T& candidate) + { + float beta = o2::pid::tof::Beta::GetBeta(candidate); + beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked + bool heliumPID = candidate.pidForTracking() == o2::track::PID::Helium3 || candidate.pidForTracking() == o2::track::PID::Alpha; + float correctedTPCinnerParamHe3 = (heliumPID && he3setting_compensatePIDinTracking) ? candidate.tpcInnerParam() / 2.f : candidate.tpcInnerParam(); + return correctedTPCinnerParamHe3 * 2.f * std::sqrt(1.f / (beta * beta) - 1.f); + } + + // ========================================================================================================= + + template + void initCCDB(Bc const& bc) + { + if (m_runNumber == bc.runNumber()) { + return; + } + + auto timestamp = bc.timestamp(); + o2::parameters::GRPMagField* grpmag = 0x0; + + auto grpmagPath{"GLO/Config/GRPMagField"}; + grpmag = m_ccdb->getForTimeStamp("GLO/Config/GRPMagField", timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField for timestamp " << timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + + // Fetch magnetic field from ccdb for current collision + m_d_bz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "Retrieved GRP for timestamp " << timestamp << " with magnetic field of " << m_d_bz << " kG"; + m_runNumber = bc.runNumber(); + m_fitter.setBz(m_d_bz); + + // o2::base::Propagator::Instance()->setMatLUT(lut); + } + + void init(o2::framework::InitContext&) + { + m_runNumber = 0; + m_d_bz = 0; + + m_ccdb->setURL("http://alice-ccdb.cern.ch"); + m_ccdb->setCaching(true); + m_ccdb->setLocalObjectValidityChecking(); + m_ccdb->setFatalWhenNull(false); + // lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get("GLO/Param/MatLUT")); + + m_fitter.setPropagateToPCA(true); + m_fitter.setMaxR(200.); + m_fitter.setMinParamChange(1e-3); + m_fitter.setMinRelChi2Change(0.9); + m_fitter.setMaxDZIni(4); + m_fitter.setMaxDXYIni(4); + m_fitter.setMaxChi2(1e9); + m_fitter.setUseAbsDCA(true); + m_fitter.setWeightedFinalPCA(false); + int mat{static_cast(setting_materialCorrection)}; + m_fitter.setMatCorrType(static_cast(mat)); + + LOG(info) << "Bethe-Bloch parameters for He3:"; + for (int i = 0; i < 5; i++) { + m_BBparamsHe[i] = setting_BetheBlochParams->get("He3", Form("p%i", i)); + LOG(info) << "p" << i << ": " << m_BBparamsHe[i]; + } + m_BBparamsHe[5] = setting_BetheBlochParams->get("He3", "resolution"); + LOG(info) << "resolution: " << m_BBparamsHe[5]; + + LOG(info) << "Bethe-Bloch parameters for De:"; + for (int i = 0; i < 5; i++) { + m_BBparamsDe[i] = setting_BetheBlochParams->get("De", Form("p%i", i)); + LOG(info) << "p" << i << ": " << m_BBparamsDe[i]; + } + m_BBparamsDe[5] = setting_BetheBlochParams->get("De", "resolution"); + LOG(info) << "resolution: " << m_BBparamsDe[5]; + + std::vector collision_selection_labels = {"All", "sel8", "z_{VTX} < 10 cm"}; + for (int i = 0; i < Selections::kAll; i++) + m_hAnalysis.get(HIST("collision_selections"))->GetXaxis()->SetBinLabel(i + 1, collision_selection_labels[i].c_str()); + + std::vector V0_selection_labels = {"All", "daughter track quality", "V0 daughters dca", "V0 radius", "V0 cosPA", "V0 mass selection", "V0 daughter DCA to PV"}; + for (int i = 0; i < V0Selections::kV0All; i++) + m_hAnalysis.get(HIST("v0_selections"))->GetXaxis()->SetBinLabel(i + 1, V0_selection_labels[i].c_str()); + + std::vector Casc_selection_labels = {"All", "Casc DCA", "Casc CosPA", "Accepted Omega", "Veto Xi", "n#sigma_{TPC} K"}; + for (int i = 0; i < CascSelections::kCascAll; i++) + m_hAnalysis.get(HIST("casc_selections"))->GetXaxis()->SetBinLabel(i + 1, Casc_selection_labels[i].c_str()); + + std::vector De_selection_labels = {"All", "n clusters ITS", "n#sigma_{TPC} d", "n#sigma_{TOF} d"}; + for (int i = 0; i < DeSelections::kDeAll; i++) + m_hAnalysis.get(HIST("de_selections"))->GetXaxis()->SetBinLabel(i + 1, De_selection_labels[i].c_str()); + + std::vector He3_selection_labels = {"All", "n clusters ITS", "n#sigma_{TPC} ^{3}He", "TOF mass ^{3}He"}; + for (int i = 0; i < He3Selections::kHe3All; i++) + m_hAnalysis.get(HIST("he3_selections"))->GetXaxis()->SetBinLabel(i + 1, He3_selection_labels[i].c_str()); + + std::vector V0Type_labels = {"K0s", "#Lambda", "#bar{#Lambda}", "Photon"}; + for (int i = 0; i < V0Type::V0TypeAll; i++) + m_hAnalysis.get(HIST("v0_type"))->GetXaxis()->SetBinLabel(i + 1, V0Type_labels[i].c_str()); + } + + template + void fillV0Cand(const std::array& PV, const aod::V0s::iterator& v0, const Track&) + { + m_hAnalysis.fill(HIST("v0_selections"), V0Selections::kV0NoCut); + + auto posTrack = v0.posTrack_as(); + auto negTrack = v0.negTrack_as(); + if (!qualityTrackSelection(posTrack) || !qualityTrackSelection(negTrack)) { + return; + } + m_hAnalysis.fill(HIST("v0_selections"), V0Selections::kV0DaughterQuality); + + auto daughterTrackCovarianceA = getTrackParCov(posTrack); + auto daughterTrackCovarianceB = getTrackParCov(negTrack); + if (!initializeFitter(daughterTrackCovarianceA, daughterTrackCovarianceB)) { + return; + } + + std::array momPos, momNeg, momMother; + computeTrackMomentum(0, momPos); + computeTrackMomentum(1, momNeg); + computeMotherMomentum(momPos, momNeg, momMother); + ROOT::Math::SVector vec_decayVtx = m_fitter.getPCACandidate(); + std::array decayVtx = {static_cast(vec_decayVtx[0]), static_cast(vec_decayVtx[1]), static_cast(vec_decayVtx[2])}; + float alphaAP = computeAlphaAP(momMother, momPos, momNeg); + float qtAP = computeQtAP(momMother, momPos); + m_hAnalysis.fill(HIST("armenteros_plot_before_selections"), alphaAP, qtAP); + + gpu::gpustd::array dcaInfo; + V0TrackParCov v0TrackParCov{v0.globalIndex(), m_fitter.createParentTrackParCov()}; + float dcaV0daughters = std::sqrt(std::abs(m_fitter.getChi2AtPCACandidate())); + float radiusV0 = std::hypot(decayVtx[0], decayVtx[1]); + float dcaV0toPV = dcaToPV(PV, v0TrackParCov.trackParCov, dcaInfo); + float cosPA = RecoDecay::cpa(PV, decayVtx, momMother); + if (!qualitySelectionV0(dcaV0toPV, dcaV0daughters, radiusV0, cosPA)) { + return; + } + + // mass hypothesis + float massLambdaV0 = computeMassMother(o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, momPos, momNeg, momMother); + float massAntiLambdaV0 = computeMassMother(o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, momPos, momNeg, momMother); + float massK0sV0 = computeMassMother(o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged, momPos, momNeg, momMother); + m_hAnalysis.fill(HIST("Lambda_vs_K0s"), massK0sV0, massLambdaV0); + // float massPhotonV0 = computeMassMother(o2::constants::physics::MassElectron, o2::constants::physics::MassElectron, momPos, momNeg, momMother); + + uint8_t v0Bitmask(0); + if (v0.isPhotonV0()) { + SETBIT(v0Bitmask, Photon); + } + if (std::abs(massK0sV0 - o2::constants::physics::MassK0Short) < v0setting_massWindowK0s) { + SETBIT(v0Bitmask, K0s); + } + if ((std::abs(massLambdaV0 - o2::constants::physics::MassLambda0) < v0setting_massWindowLambda) && (alphaAP > 0)) { + SETBIT(v0Bitmask, Lambda); + } + if ((std::abs(massAntiLambdaV0 - o2::constants::physics::MassLambda0) < v0setting_massWindowLambda) && (alphaAP < 0)) { + SETBIT(v0Bitmask, AntiLambda); + } + if (v0Bitmask == 0 || (v0Bitmask & (v0Bitmask - 1)) != 0) { + return; + } + m_hAnalysis.fill(HIST("v0_selections"), V0Selections::kV0PID); + + uint8_t partID_pos{0}, partID_neg{0}; + if (TESTBIT(v0Bitmask, Lambda)) { + if (qtAP < lambdasetting_qtAPcut) + return; + if (std::abs(posTrack.tpcNSigmaPr()) > v0setting_nsigmatpcPr || std::abs(negTrack.tpcNSigmaPi()) > v0setting_nsigmatpcPi) + return; + if (std::hypot(momMother[0], momMother[1], momMother[2]) < lambdasetting_pmin) + return; + partID_pos = PartID::pr; + partID_neg = PartID::pi; + m_hAnalysis.fill(HIST("v0_type"), V0Type::Lambda); + } else if (TESTBIT(v0Bitmask, AntiLambda)) { + if (qtAP < lambdasetting_qtAPcut) + return; + if (std::abs(posTrack.tpcNSigmaPi()) > v0setting_nsigmatpcPr || std::abs(negTrack.tpcNSigmaPr()) > v0setting_nsigmatpcPi) + return; + if (std::hypot(momMother[0], momMother[1], momMother[2]) < lambdasetting_pmin) + return; + partID_pos = PartID::pi; + partID_neg = PartID::pr; + m_hAnalysis.fill(HIST("v0_type"), V0Type::AntiLambda); + } else if (TESTBIT(v0Bitmask, K0s)) { + m_hAnalysis.fill(HIST("v0_type"), V0Type::K0s); + return; // K0s not implemented + } else if (TESTBIT(v0Bitmask, Photon)) { + // require photon conversion to happen in one of the Inner Tracker layers (± 0.5 cm resolution) + m_hAnalysis.fill(HIST("photon_conversion_position"), decayVtx[0], decayVtx[1]); + m_hAnalysis.fill(HIST("photon_radiusV0"), radiusV0); + if (!(radiusV0 > 1.76 && radiusV0 < 4.71)) + return; + if (std::abs(posTrack.tpcNSigmaEl()) > v0setting_nsigmatpcEl || std::abs(negTrack.tpcNSigmaEl()) > v0setting_nsigmatpcEl) + return; + m_hAnalysis.fill(HIST("photon_conversion_position_layer"), decayVtx[0], decayVtx[1]); + partID_pos = PartID::el; + partID_neg = PartID::el; + m_hAnalysis.fill(HIST("v0_type"), V0Type::Photon); + } else { + return; + } + + float dcaToPVpos = dcaToPV(PV, daughterTrackCovarianceA, dcaInfo); + if (std::abs(dcaToPVpos) < v0setting_dcaDaughtersToPV /*&& std::abs(dcaInfo[0]) < v0setting_dcaDaughtersToPV*/) { + return; + } + float dcaToPVneg = dcaToPV(PV, daughterTrackCovarianceB, dcaInfo); + if (std::abs(dcaToPVneg) < v0setting_dcaDaughtersToPV /*&& std::abs(dcaInfo[0]) < v0setting_dcaDaughtersToPV*/) { + return; + } + + float massV0{0.f}; + m_hAnalysis.fill(HIST("v0_selections"), V0Selections::kV0DaughterDCAtoPV); + if (TESTBIT(v0Bitmask, Lambda)) { + massV0 = massLambdaV0; + m_hAnalysis.fill(HIST("massLambda"), std::hypot(momMother[0], momMother[1], momMother[2]), massLambdaV0); + m_hAnalysis.fill(HIST("armenteros_plot_lambda"), alphaAP, qtAP); + m_hAnalysis.fill(HIST("nSigmaTPCPr"), std::hypot(momPos[0], momPos[1], momPos[2]), posTrack.tpcNSigmaPr()); + m_hAnalysis.fill(HIST("nSigmaITSPr"), std::hypot(momPos[0], momPos[1], momPos[2]), m_responseITS.nSigmaITS(posTrack.itsClusterSizes(), posTrack.p(), posTrack.eta())); + m_hAnalysis.fill(HIST("nSigmaTPCPi"), std::hypot(momNeg[0], momNeg[1], momNeg[2]) * -1.f, negTrack.tpcNSigmaPi()); + m_hAnalysis.fill(HIST("nSigmaITSPi"), std::hypot(momNeg[0], momNeg[1], momNeg[2]) * -1.f, m_responseITS.nSigmaITS(negTrack.itsClusterSizes(), negTrack.p(), negTrack.eta())); + m_hAnalysis.fill(HIST("pmatchingPr"), posTrack.tpcInnerParam(), (posTrack.tpcInnerParam() - posTrack.p()) / posTrack.tpcInnerParam()); + m_hAnalysis.fill(HIST("pmatchingPi"), -negTrack.tpcInnerParam(), (negTrack.tpcInnerParam() - negTrack.p()) / negTrack.tpcInnerParam()); + + } else if (TESTBIT(v0Bitmask, AntiLambda)) { + massV0 = massAntiLambdaV0; + m_hAnalysis.fill(HIST("massLambda"), std::hypot(momMother[0], momMother[1], momMother[2]) * -1.f, massAntiLambdaV0); + // "signed" pt for antimatter + m_hAnalysis.fill(HIST("armenteros_plot_lambda"), alphaAP, qtAP); + m_hAnalysis.fill(HIST("nSigmaTPCPi"), std::hypot(momPos[0], momPos[1], momPos[2]), posTrack.tpcNSigmaPi()); + m_hAnalysis.fill(HIST("nSigmaITSPi"), std::hypot(momPos[0], momPos[1], momPos[2]), m_responseITS.nSigmaITS(posTrack.itsClusterSizes(), posTrack.p(), posTrack.eta())); + m_hAnalysis.fill(HIST("nSigmaTPCPr"), std::hypot(momNeg[0], momNeg[1], momNeg[2]) * -1.f, negTrack.tpcNSigmaPr()); + m_hAnalysis.fill(HIST("nSigmaITSPr"), std::hypot(momNeg[0], momNeg[1], momNeg[2]) * -1.f, m_responseITS.nSigmaITS(negTrack.itsClusterSizes(), negTrack.p(), negTrack.eta())); + m_hAnalysis.fill(HIST("pmatchingPi"), posTrack.tpcInnerParam(), (posTrack.tpcInnerParam() - posTrack.p()) / posTrack.tpcInnerParam()); + m_hAnalysis.fill(HIST("pmatchingPr"), -negTrack.tpcInnerParam(), (negTrack.tpcInnerParam() - negTrack.p()) / negTrack.tpcInnerParam()); + + } else if (TESTBIT(v0Bitmask, Photon)) { + massV0 = 0.f; + m_hAnalysis.fill(HIST("nSigmaTPCEl"), std::hypot(momPos[0], momPos[1], momPos[2]), posTrack.tpcNSigmaEl()); + m_hAnalysis.fill(HIST("nSigmaTPCEl"), std::hypot(momNeg[0], momNeg[1], momNeg[2]) * -1.f, negTrack.tpcNSigmaEl()); + m_hAnalysis.fill(HIST("nSigmaITSEl"), std::hypot(momPos[0], momPos[1], momPos[2]), m_responseITS.nSigmaITS(posTrack.itsClusterSizes(), posTrack.p(), posTrack.eta())); + m_hAnalysis.fill(HIST("nSigmaITSEl"), std::hypot(momNeg[0], momNeg[1], momNeg[2]) * -1.f, m_responseITS.nSigmaITS(negTrack.itsClusterSizes(), negTrack.p(), negTrack.eta())); + m_hAnalysis.fill(HIST("armenteros_plot_gamma"), alphaAP, qtAP); + m_hAnalysis.fill(HIST("pmatchingEl"), posTrack.tpcInnerParam(), (posTrack.tpcInnerParam() - posTrack.p()) / posTrack.tpcInnerParam()); + m_hAnalysis.fill(HIST("pmatchingEl"), -negTrack.tpcInnerParam(), (negTrack.tpcInnerParam() - negTrack.p()) / negTrack.tpcInnerParam()); + } + m_hAnalysis.fill(HIST("radiusV0"), radiusV0); + m_hAnalysis.fill(HIST("armenteros_plot"), alphaAP, qtAP); + m_v0TrackParCovs.push_back(v0TrackParCov); + + if (!setting_fillV0) { + return; + } + + if constexpr (isMC) { // MC + if (!posTrack.has_mcParticle() || !negTrack.has_mcParticle()) { + return; + } + + auto posMcParticle = posTrack.mcParticle(); + auto negMcParticle = negTrack.mcParticle(); + + if (setting_smallTable) { + m_ClusterStudiesTableMc( + std::hypot(momPos[0], momPos[1], momPos[2]) * posTrack.sign(), // p_pos + RecoDecay::eta(momPos), // eta_pos + RecoDecay::phi(momPos), // phi_pos + posTrack.itsClusterSizes(), // itsClsize_pos + partID_pos, // partID_pos + posMcParticle.pdgCode()); // pdgCode_pos + m_ClusterStudiesTableMc( + std::hypot(momNeg[0], momNeg[1], momNeg[2]) * negTrack.sign(), // p_neg + RecoDecay::eta(momNeg), // eta_neg + RecoDecay::phi(momNeg), // phi_neg + negTrack.itsClusterSizes(), // itsClsize_neg + partID_neg, // partID_neg + negMcParticle.pdgCode()); // pdgCode_neg + } else { + m_ClusterStudiesTableMcExtra( + std::hypot(momPos[0], momPos[1], momPos[2]) * posTrack.sign(), // p_pos + RecoDecay::eta(momPos), // eta_pos + RecoDecay::phi(momPos), // phi_pos + posTrack.itsClusterSizes(), // itsClsize_pos + partID_pos, // partID_pos + posMcParticle.pdgCode(), // pdgCode_pos + posTrack.tpcInnerParam() * posTrack.sign(), // pTPC_pos + posTrack.pidForTracking(), // pidInTrk_pos + -999.f, // TpcNSigma_pos + -999.f, // TofNSigma_pos + -999.f, // TofMass_pos + cosPA, // cosPA + massV0); // massV0 + m_ClusterStudiesTableMcExtra( + std::hypot(momNeg[0], momNeg[1], momNeg[2]) * negTrack.sign(), // p_neg + RecoDecay::eta(momNeg), // eta_neg + RecoDecay::phi(momNeg), // phi_neg + negTrack.itsClusterSizes(), // itsClsize_neg + partID_neg, // partID_neg + negMcParticle.pdgCode(), // pdgCode_pos + negTrack.tpcInnerParam() * negTrack.sign(), // pTPC_neg + negTrack.pidForTracking(), // pidInTrk_neg + -999.f, // TpcNSigma_neg + -999.f, // TofNSigma_neg + -999.f, // TofMass_neg + cosPA, // cosPA + massV0); // massV0 + } + } else { // data + if (setting_smallTable) { + m_ClusterStudiesTable( + std::hypot(momPos[0], momPos[1], momPos[2]) * posTrack.sign(), // p_pos + RecoDecay::eta(momPos), // eta_pos + RecoDecay::phi(momPos), // phi_pos + posTrack.itsClusterSizes(), // itsClsize_pos + partID_pos); // partID_pos + m_ClusterStudiesTable( + std::hypot(momNeg[0], momNeg[1], momNeg[2]) * negTrack.sign(), // p_neg + RecoDecay::eta(momNeg), // eta_neg + RecoDecay::phi(momNeg), // phi_neg + negTrack.itsClusterSizes(), // itsClsize_neg + partID_neg); // partID_neg + } else { + m_ClusterStudiesTableExtra( + std::hypot(momPos[0], momPos[1], momPos[2]) * posTrack.sign(), // p_pos + RecoDecay::eta(momPos), // eta_pos + RecoDecay::phi(momPos), // phi_pos + posTrack.itsClusterSizes(), // itsClsize_pos + partID_pos, // partID_pos + posTrack.tpcInnerParam() * posTrack.sign(), // pTPC_pos + posTrack.pidForTracking(), // pidInTrk_pos + -999.f, // TpcNSigma_pos + -999.f, // TofNSigma_pos + -999.f, // TofMass_pos + cosPA, // cosPA + massV0); // massV0 + m_ClusterStudiesTableExtra( + std::hypot(momNeg[0], momNeg[1], momNeg[2]) * negTrack.sign(), // p_neg + RecoDecay::eta(momNeg), // eta_neg + RecoDecay::phi(momNeg), // phi_neg + negTrack.itsClusterSizes(), // itsClsize_neg + partID_neg, // partID_neg + negTrack.tpcInnerParam() * negTrack.sign(), // pTPC_neg + negTrack.pidForTracking(), // pidInTrk_neg + -999.f, // TpcNSigma_neg + -999.f, // TofNSigma_neg + -999.f, // TofMass_neg + cosPA, // cosPA + massV0); // massV0 + } + } + + m_hAnalysis.fill(HIST("isPositive"), true); + m_hAnalysis.fill(HIST("isPositive"), false); + } + + template + void fillKCand(const std::array& PV, const aod::Cascades::iterator& cascade, const Track&) + { + m_hAnalysis.fill(HIST("casc_selections"), CascSelections::kCascNoCut); + + auto v0Track = cascade.template v0_as(); + auto bachelorTrack = cascade.template bachelor_as(); + + auto itv0 = std::find_if(m_v0TrackParCovs.begin(), m_v0TrackParCovs.end(), [&](const V0TrackParCov& v0) { return v0.globalIndex == v0Track.globalIndex(); }); + if (itv0 == m_v0TrackParCovs.end()) { + return; + } + + auto v0TrackCovariance = itv0->trackParCov; + auto bachelorTrackCovariance = getTrackParCov(bachelorTrack); + if (!initializeFitter(v0TrackCovariance, bachelorTrackCovariance)) { + return; + } + + std::array momV0, momBachelor, momMother; + computeTrackMomentum(0, momV0); + computeTrackMomentum(1, momBachelor); + computeMotherMomentum(momV0, momBachelor, momMother); + + ROOT::Math::SVector vec_decayVtx = m_fitter.getPCACandidate(); + std::array decayVtx = {static_cast(vec_decayVtx[0]), static_cast(vec_decayVtx[1]), static_cast(vec_decayVtx[2])}; + + float dcaV0daughters = std::sqrt(std::abs(m_fitter.getChi2AtPCACandidate())); + float cosPA = RecoDecay::cpa(PV, decayVtx, momMother); + + if (!qualitySelectionCascade(dcaV0daughters, cosPA)) { + return; + } + // gpu::gpustd::array dcaInfo; + // float dcaToPVbachelor = dcaToPV(PV, bachelorTrackCovariance, dcaInfo); + + float massXi = computeMassMother(o2::constants::physics::MassLambda0, o2::constants::physics::MassPionCharged, momV0, momBachelor, momMother); + float massOmega = computeMassMother(o2::constants::physics::MassLambda0, o2::constants::physics::MassKaonCharged, momV0, momBachelor, momMother); + m_hAnalysis.fill(HIST("Xi_vs_Omega"), massOmega, massXi); + if (std::abs(massOmega - o2::constants::physics::MassOmegaMinus) > cascsetting_massWindowOmega) { + return; + } + m_hAnalysis.fill(HIST("massOmegaWithBkg"), massOmega); + m_hAnalysis.fill(HIST("casc_selections"), CascSelections::kAcceptedOmega); + if (std::abs(massXi - o2::constants::physics::MassXiMinus) < cascsetting_massWindowXi) { + return; + } // enhance purity by rejecting Xi background + m_hAnalysis.fill(HIST("casc_selections"), CascSelections::kRejectedXi); + if (std::abs(bachelorTrack.tpcNSigmaKa()) > cascsetting_nsigmatpc) { + return; + } + m_hAnalysis.fill(HIST("casc_selections"), CascSelections::kNSigmaTPC); + m_hAnalysis.fill(HIST("massOmega"), std::hypot(momMother[0], momMother[1]) * bachelorTrack.sign(), massOmega); + m_hAnalysis.fill(HIST("pmatchingKa"), bachelorTrack.sign() * bachelorTrack.tpcInnerParam(), (bachelorTrack.tpcInnerParam() - bachelorTrack.p()) / bachelorTrack.tpcInnerParam()); + m_hAnalysis.fill(HIST("nSigmaTPCKa"), bachelorTrack.sign() * std::hypot(momBachelor[0], momBachelor[1], momBachelor[2]), bachelorTrack.tpcNSigmaKa()); + + uint8_t partID_bachelor = PartID::ka; + + if constexpr (isMC) { + if (!bachelorTrack.has_mcParticle()) { + return; + } + auto mcParticle = bachelorTrack.mcParticle(); + + if (setting_smallTable) { + m_ClusterStudiesTableMc( + std::hypot(momBachelor[0], momBachelor[1], momBachelor[2]) * bachelorTrack.sign(), // p_K + RecoDecay::eta(momBachelor), // eta_K + RecoDecay::phi(momBachelor), // phi_K + bachelorTrack.itsClusterSizes(), // itsClSize_K + partID_bachelor, // partID_K + mcParticle.pdgCode()); // pdgCode_K + } else { + m_ClusterStudiesTableMcExtra( + std::hypot(momBachelor[0], momBachelor[1], momBachelor[2]) * bachelorTrack.sign(), // p_K + RecoDecay::eta(momBachelor), // eta_K + RecoDecay::phi(momBachelor), // phi_K + bachelorTrack.itsClusterSizes(), // itsClSize_K + partID_bachelor, // partID_K + mcParticle.pdgCode(), // pdgCode_K + bachelorTrack.tpcInnerParam() * bachelorTrack.sign(), // pTPC_K + bachelorTrack.pidForTracking(), // PIDinTrk_K + -999.f, // TpcNSigma_K + -999.f, // TofNSigma_K + -999.f, // TofMass_K + cosPA, // cosPA + massOmega); // massMother + } + } else { + if (setting_smallTable) { + m_ClusterStudiesTable( + std::hypot(momBachelor[0], momBachelor[1], momBachelor[2]) * bachelorTrack.sign(), // p_K + RecoDecay::eta(momBachelor), // eta_K + RecoDecay::phi(momBachelor), // phi_K + bachelorTrack.itsClusterSizes(), // itsClSize_K + partID_bachelor); // partID_K + } else { + m_ClusterStudiesTableExtra( + std::hypot(momBachelor[0], momBachelor[1], momBachelor[2]) * bachelorTrack.sign(), // p_K + RecoDecay::eta(momBachelor), // eta_K + RecoDecay::phi(momBachelor), // phi_K + bachelorTrack.itsClusterSizes(), // itsClSize_K + partID_bachelor, // partID_K + bachelorTrack.tpcInnerParam() * bachelorTrack.sign(), // pTPC_K + bachelorTrack.pidForTracking(), // PIDinTrk_K + -999.f, // TpcNSigma_K + -999.f, // TofNSigma_K + -999.f, // TofMass_K + cosPA, // cosPA + massOmega); + } + } + + m_hAnalysis.fill(HIST("isPositive"), bachelorTrack.p() > 0); + } + + template + void fillDeTable(const Track& track) + { + if (track.sign() > 0) { + return; + } + m_hAnalysis.fill(HIST("de_selections"), DeSelections::kDeNoCut); + if (track.itsNCls() < desetting_nClsIts) { + return; + } + m_hAnalysis.fill(HIST("de_selections"), DeSelections::kDeNClsIts); + if (!selectionPIDtpcDe(track)) { + return; + } + m_hAnalysis.fill(HIST("de_selections"), DeSelections::kDePIDtpc); + if (!track.hasTOF() || std::abs(track.tofNSigmaDe()) > desetting_nsigmatof) { + return; + } + m_hAnalysis.fill(HIST("de_selections"), DeSelections::kDePIDtof); + m_hAnalysis.fill(HIST("nSigmaTPCDe"), track.p() * track.sign(), computeNSigmaDe(track)); + m_hAnalysis.fill(HIST("nSigmaITSDe"), track.p() * track.sign(), m_responseITS.nSigmaITS(track.itsClusterSizes(), track.p(), track.eta())); + m_hAnalysis.fill(HIST("nSigmaTOFDe"), track.p() * track.sign(), track.tofNSigmaDe()); + m_hAnalysis.fill(HIST("TOFmassDe"), track.p() * track.sign(), computeTOFmassDe(track)); + m_hAnalysis.fill(HIST("pmatchingDe"), track.sign() * track.tpcInnerParam(), (track.tpcInnerParam() - track.p()) / track.tpcInnerParam()); + + uint8_t partID = PartID::de; + + if constexpr (isMC) { + if (!track.has_mcParticle() || track.sign() > 0) { + return; + } + + auto mcParticle = track.mcParticle(); + + if (setting_smallTable) { + m_ClusterStudiesTableMc( + track.p() * track.sign(), // p_De, + track.eta(), // eta_De, + track.phi(), // phi_De, + track.itsClusterSizes(), // itsClSize_De, + partID, // pdgCode_De, + mcParticle.pdgCode()); // pdgCodeMc_De + } else { + m_ClusterStudiesTableMcExtra( + track.p() * track.sign(), // p_De, + track.eta(), // eta_De, + track.phi(), // phi_De, + track.itsClusterSizes(), // itsClSize_De, + partID, // pdgCode_De, + mcParticle.pdgCode(), // pdgCodeMc_De + track.tpcInnerParam() * track.sign(), // pTPC_De, + track.pidForTracking(), // PIDinTrk_De, + computeNSigmaDe(track), // TpcNSigma_De, + track.tofNSigmaDe(), // TofNSigma_De, + computeTOFmassDe(track), // TofMass_De, + -999.f, // cosPA, + -999.f); // massMother + } + } else { + if (setting_smallTable) { + m_ClusterStudiesTable( + track.p() * track.sign(), // p_De, + track.eta(), // eta_De, + track.phi(), // phi_De, + track.itsClusterSizes(), // itsClSize_De, + partID); // pdgCode_De + } else { + m_ClusterStudiesTableExtra( + track.p() * track.sign(), // p_De, + track.eta(), // eta_De, + track.phi(), // phi_De, + track.itsClusterSizes(), // itsClSize_De, + partID, // pdgCode_De, + track.tpcInnerParam() * track.sign(), // pTPC_De, + track.pidForTracking(), // PIDinTrk_De, + computeNSigmaDe(track), // TpcNSigma_De, + track.tofNSigmaDe(), // TofNSigma_De, + computeTOFmassDe(track), // TofMass_De, + -999.f, // cosPA, + -999.f); // massMother + } + } + + m_hAnalysis.fill(HIST("isPositive"), track.sign() > 0); + } + + template + void fillHe3Table(const Track& track) + { + m_hAnalysis.fill(HIST("he3_selections"), He3Selections::kHe3NoCut); + + if (track.itsNCls() < he3setting_nClsIts) { + return; + } + m_hAnalysis.fill(HIST("he3_selections"), He3Selections::kHe3NClsIts); + if (!selectionPIDtpcHe3(track)) { + return; + } + m_hAnalysis.fill(HIST("he3_selections"), He3Selections::kHe3PIDtpc); + float tofMass = track.hasTOF() ? computeTOFmassHe3(track) : -999.f; + if (track.hasTOF() && (tofMass < he3setting_tofmasslow || tofMass > he3setting_tofmasshigh)) { + return; + } + uint8_t partID = PartID::he; + bool heliumPID = track.pidForTracking() == o2::track::PID::Helium3 || track.pidForTracking() == o2::track::PID::Alpha; + float correctedTPCinnerParam = (heliumPID && he3setting_compensatePIDinTracking) ? track.tpcInnerParam() / 2.f : track.tpcInnerParam(); + + m_hAnalysis.fill(HIST("he3_selections"), He3Selections::kHe3PIDtof); + m_hAnalysis.fill(HIST("nSigmaTPCHe"), track.p() * track.sign(), computeNSigmaHe3(track)); + m_hAnalysis.fill(HIST("nSigmaITSHe"), track.p() * track.sign(), m_responseITS.nSigmaITS(track.itsClusterSizes(), track.p(), track.eta())); + m_hAnalysis.fill(HIST("TOFmassHe"), track.p() * track.sign(), tofMass); + m_hAnalysis.fill(HIST("pmatchingHe"), track.sign() * correctedTPCinnerParam, (correctedTPCinnerParam - track.p()) / correctedTPCinnerParam); + + if constexpr (isMC) { + if (!track.has_mcParticle()) { + return; + } + auto mcParticle = track.mcParticle(); + + if (setting_smallTable) { + m_ClusterStudiesTableMc( + track.p() * track.sign(), // p_He3, + track.eta(), // eta_He3, + track.phi(), // phi_He3, + track.itsClusterSizes(), // itsClSize_He3, + partID, // pdgCode_He3, + mcParticle.pdgCode()); // pdgCodeMc_He3 + } else { + m_ClusterStudiesTableMcExtra( + track.p() * track.sign(), // p_He3 + track.eta(), // eta_He3 + track.phi(), // phi_He3 + track.itsClusterSizes(), // itsClSize_He3 + partID, // pdgCode_He3 + mcParticle.pdgCode(), // pdgCodeMc_He3 + correctedTPCinnerParam * track.sign(), // pTPC_He3 + track.pidForTracking(), // PIDinTrk_He3 + computeNSigmaHe3(track), // TpcNSigma_He3 + -999.f, // TofNSigma_He3 + tofMass, // TofMass_He3 + -999.f, // cosPA_He3 + -999.f); // massMother_He3 + } + + } else { + if (setting_smallTable) { + m_ClusterStudiesTable( + track.p() * track.sign(), // p_He3, + track.eta(), // eta_He3, + track.phi(), // phi_He3, + track.itsClusterSizes(), // itsClSize_He3, + partID); // pdgCode_He3 + } else { + m_ClusterStudiesTableExtra( + track.p() * track.sign(), // p_He3, + track.eta(), // eta_He3, + track.phi(), // phi_He3, + track.itsClusterSizes(), // itsClSize_He3, + partID, // pdgCode_He3, + correctedTPCinnerParam * track.sign(), // pTPC_He3, + track.pidForTracking(), // PIDinTrk_He3, + computeNSigmaHe3(track), // TpcNSigma_He3, + -999.f, // TofNSigma_He3, + tofMass, // TofMass_He3, + -999.f, // cosPA, + -999.f); // massMother + } + } + + m_hAnalysis.fill(HIST("isPositive"), track.sign() > 0); + } + + void fillPKPiTable(const TracksFullIU::iterator& track) + { + uint8_t partID = 0; + float tpcNSigma = 0.f; + if (std::abs(track.tpcNSigmaPi()) < v0setting_nsigmatpcPi && std::abs(track.tpcNSigmaKa()) > 3) { + partID = PartID::pi; + tpcNSigma = track.tpcNSigmaPi(); + m_hAnalysis.fill(HIST("nSigmaTPCPi"), track.p() * track.sign(), tpcNSigma); + } else if (std::abs(track.tpcNSigmaKa()) < cascsetting_nsigmatpc && (std::abs(track.tpcNSigmaPi()) > 3 /*&& std::abs(track.tpcNSigmaPr()) > 3*/)) { + partID = PartID::ka; + tpcNSigma = track.tpcNSigmaKa(); + m_hAnalysis.fill(HIST("nSigmaTPCKa"), track.p() * track.sign(), tpcNSigma); + } else if (std::abs(track.tpcNSigmaPr()) < v0setting_nsigmatpcPr && std::abs(track.tpcNSigmaKa()) > 3) { + partID = PartID::pr; + tpcNSigma = track.tpcNSigmaPr(); + m_hAnalysis.fill(HIST("nSigmaTPCPr"), track.p() * track.sign(), tpcNSigma); + } else { + return; + } + + if (setting_smallTable) { + m_ClusterStudiesTable( + track.p() * track.sign(), + track.eta(), + track.phi(), + track.itsClusterSizes(), + partID); + } else { + m_ClusterStudiesTableExtra( + track.p() * track.sign(), // p, + track.eta(), // eta, + track.phi(), // phi, + track.itsClusterSizes(), // itsClSize, + partID, // pdgCode, + track.tpcInnerParam() * track.sign(), // pTPC, + track.pidForTracking(), // PIDinTrk, + tpcNSigma, // TpcNSigma, + -999.f, // TofNSigma, + -999.f, // TofMass, + -999.f, // cosPA, + -999.f); // massMother + } + } + + // ========================================================================================================= + + void processDataV0Casc(CollisionsCustom const& collisions, TracksFullIU const& tracks, aod::V0s const& v0s, aod::Cascades const& cascades, aod::BCsWithTimestamps const&) + { + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + + if (!collisionSelection(collision)) { + continue; + } + + m_hAnalysis.fill(HIST("zVtx"), collision.posZ()); + std::array PV = {collision.posX(), collision.posY(), collision.posZ()}; + + const uint64_t collIdx = collision.globalIndex(); + auto v0Table_thisCollision = v0s.sliceBy(m_perCollisionV0, collIdx); + auto cascTable_thisCollision = cascades.sliceBy(m_perCollisionCascade, collIdx); + v0Table_thisCollision.bindExternalIndices(&tracks); + cascTable_thisCollision.bindExternalIndices(&tracks); + cascTable_thisCollision.bindExternalIndices(&v0s); + + if (setting_fillV0 || setting_fillK) { + m_v0TrackParCovs.clear(); + for (auto& v0 : v0Table_thisCollision) { + fillV0Cand(PV, v0, tracks); + } + } + if (setting_fillK) { // the v0 loops are needed for the Ks + for (auto& cascade : cascTable_thisCollision) { + fillKCand(PV, cascade, tracks); + } + } + } + } + PROCESS_SWITCH(LfTreeCreatorClusterStudies, processDataV0Casc, "process Data V0 and cascade", false); + + void processDataNuclei(CollisionsCustom const& collisions, TracksFullIU const& tracks) + { + for (const auto& collision : collisions) { + if (!collisionSelection(collision)) { + continue; + } + + m_hAnalysis.fill(HIST("zVtx"), collision.posZ()); + + const uint64_t collIdx = collision.globalIndex(); + auto TrackTable_thisCollision = tracks.sliceBy(m_perCol, collIdx); + TrackTable_thisCollision.bindExternalIndices(&tracks); + + for (auto track : TrackTable_thisCollision) { + if (!nucleiTrackSelection(track)) { + continue; + } + + if (setting_fillDe) + fillDeTable(track); + if (setting_fillHe3) + fillHe3Table(track); + } + } + } + PROCESS_SWITCH(LfTreeCreatorClusterStudies, processDataNuclei, "process Data Nuclei", false); + + /** + * @brief Produce a dataset with high purity p, K, #pi + */ + void processDataPKPi(CollisionsCustom const& collisions, TracksFullIU const& tracks) + { + for (const auto& collision : collisions) { + if (!collisionSelection(collision)) { + continue; + } + + m_hAnalysis.fill(HIST("zVtx"), collision.posZ()); + + const uint64_t collIdx = collision.globalIndex(); + auto TrackTable_thisCollision = tracks.sliceBy(m_perCol, collIdx); + TrackTable_thisCollision.bindExternalIndices(&tracks); + + for (auto track : TrackTable_thisCollision) { + if (!qualityTrackSelection(track)) { + continue; + } + + if (setting_fillPKPi) + fillPKPiTable(track); + } + } + } + PROCESS_SWITCH(LfTreeCreatorClusterStudies, processDataPKPi, "process Data p, K, pi", false); + + void processMcV0Casc(CollisionsCustom const& collisions, TracksFullIUMc const& tracks, aod::V0s const& v0s, aod::Cascades const& cascades, aod::BCsWithTimestamps const&, aod::McParticles const&) + { + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + + if (!collisionSelection(collision)) { + continue; + } + + m_hAnalysis.fill(HIST("zVtx"), collision.posZ()); + std::array PV = {collision.posX(), collision.posY(), collision.posZ()}; + + const uint64_t collIdx = collision.globalIndex(); + auto v0Table_thisCollision = v0s.sliceBy(m_perCollisionV0, collIdx); + auto cascTable_thisCollision = cascades.sliceBy(m_perCollisionCascade, collIdx); + v0Table_thisCollision.bindExternalIndices(&tracks); + cascTable_thisCollision.bindExternalIndices(&tracks); + cascTable_thisCollision.bindExternalIndices(&v0s); + + m_v0TrackParCovs.clear(); + if (setting_fillV0 || setting_fillK) { + for (auto& v0 : v0Table_thisCollision) { + fillV0Cand(PV, v0, tracks); + } + } + + if (setting_fillK) { // the v0 loops are needed for the Ks + for (auto& cascade : cascTable_thisCollision) { + fillKCand(PV, cascade, tracks); + } + } + } + } + PROCESS_SWITCH(LfTreeCreatorClusterStudies, processMcV0Casc, "process Mc V0 and cascade", false); + + void processMcNuclei(CollisionsCustom const& collisions, TracksFullIUMc const& tracks, aod::BCs const&, aod::McParticles const&) + { + for (const auto& collision : collisions) { + if (!collisionSelection(collision)) { + continue; + } + + m_hAnalysis.fill(HIST("zVtx"), collision.posZ()); + + const uint64_t collIdx = collision.globalIndex(); + auto TrackTable_thisCollision = tracks.sliceBy(m_perColMC, collIdx); + TrackTable_thisCollision.bindExternalIndices(&tracks); + + for (auto track : TrackTable_thisCollision) { + if (!nucleiTrackSelection(track)) { + continue; + } + + if (setting_fillDe) { + fillDeTable(track); + } + if (setting_fillHe3) { + fillHe3Table(track); + } + } + } + } + PROCESS_SWITCH(LfTreeCreatorClusterStudies, processMcNuclei, "process Mc Nuclei", false); + +}; // LfTreeCreatorClusterStudies + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx index 7b6b8fa24f9..e4d05bbacd5 100644 --- a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx +++ b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx @@ -9,12 +9,22 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -// Builder task for 3-body decay reconstruction (p + pion + bachelor) -// author: yuanzhe.wang@cern.ch +/// \file decay3bodybuilder.cxx +/// \brief Builder task for 3-body decay reconstruction (p + pion + bachelor) +/// \author Yuanzhe Wang +/// \author Carolina Reetz (KFParticle specific part) #include #include #include +#include +#include +#include +#include +#include + +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -22,14 +32,21 @@ #include "Framework/ASoAHelpers.h" #include "DCAFitter/DCAFitterN.h" #include "ReconstructionDataFormats/Track.h" +#include "DetectorsVertexing/SVertexHypothesis.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" #include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/Reduced3BodyTables.h" #include "PWGLF/DataModel/Vtx3BodyTables.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGLF/DataModel/pidTOFGeneric.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/PIDResponse.h" +#include "Common/Core/PID/PIDTOF.h" +#include "TableHelper.h" +#include "Tools/KFparticle/KFUtilities.h" + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" #include "DetectorsBase/Propagator.h" #include "DetectorsBase/GeometryManager.h" @@ -37,6 +54,18 @@ #include "DataFormatsParameters/GRPMagField.h" #include "CCDB/BasicCCDBManager.h" #include "DataFormatsTPC/BetheBlochAleph.h" +#include "DataFormatsCalibration/MeanVertexObject.h" + +#ifndef HomogeneousField +#define HomogeneousField +#endif + +// includes KFParticle +#include "KFParticle.h" +#include "KFPTrack.h" +#include "KFPVertex.h" +#include "KFParticleBase.h" +#include "KFVertex.h" using namespace o2; using namespace o2::framework; @@ -44,40 +73,170 @@ using namespace o2::framework::expressions; using std::array; using FullTracksExtIU = soa::Join; +using FullTracksExtPIDIU = soa::Join; + +using ColwithEvTimes = o2::soa::Join; +using ColwithEvTimesMults = o2::soa::Join; +using TrackExtIUwithEvTimes = soa::Join; +using TrackExtPIDIUwithEvTimes = soa::Join; + using MCLabeledTracksIU = soa::Join; +using ReducedCollisionsMults = soa::Join; +using ReducedCollisionsMultsCents = soa::Join; + +namespace +{ +const float pidCutsLambda[o2::vertexing::SVertexHypothesis::NPIDParams] = {0., 20, 0., 5.0, 0.0, 1.09004e-03, 2.62291e-04, 8.93179e-03, 2.83121}; // Lambda +} // namespace + +struct VtxCandidate { + int track0Id; + int track1Id; + int track2Id; + int collisionId; + int decay3bodyId; + float vtxPos[3]; + float track0P[3]; + float track1P[3]; + float track2P[3]; + float dcadaughters; + float daudcaxytopv[3]; // 0 - proton, 1 - pion, 2 - bachelor + float daudcatopv[3]; // 0 - proton, 1 - pion, 2 - bachelor + float bachelortofNsigma; +}; + +struct kfCandidate { + // hypertriton + int collisionID; + int trackPosID; + int trackNegID; + int trackBachID; + int decay3bodyID; + float mass; + float pos[3]; + float posErr[3]; + float mom[4]; + float momErr[4]; + float charge; + float dcaToPV[2]; // 3D, xy + float cpaToPV[2]; // 3D, xy + float cpaToPVtopo[2]; // 3D, xy + float decLen[2]; // 3D, xy + float ldl; + float chi2geoNDF; + float chi2topoNDF; + float ctau; + float trackedClSize; + float DeltaPhiRotDeuteron; + float DeltaPhiRotProton; + // V0 + float massV0; + float chi2massV0; + float cpaV0ToPV; + // daughter momenta + float protonMom[3]; + float pionMom[3]; + float deuteronMom[3]; + float tpcInnerParam[3]; // proton, pion, deuteron + // daughter track quality + int tpcNClDaughters[3]; // proton, pion, deuteron + float tpcChi2NClDeuteron; + // daughter DCAs KF + float DCAdaughterToPV[3]; // proton, pion, deuteron + float DCAdaughterToPVxy[3]; // proton, pion, deuteron + float DCAdaughterToSVxy[3]; // proton, pion, deuteron + float DCAprotonToPion; + float DCAprotonToDeuteron; + float DCApionToDeuteron; + float DCAvtxDaughters3D; + // daughter DCAs to PV propagated with material + float trackDCAxy[3]; // pos, neg, bach + float trackDCA[3]; // pos, neg, bach + // daughter signs + float daughterCharge[3]; // proton, pion, deuteron + // daughter PID + float tpcNsigma[4]; // proton, pion, deuteron, bach with pion hyp + float tpcdEdx[3]; // proton, pion, deuteron + float tofNsigmaDeuteron; + float averageClusterSizeDeuteron; + float pidForTrackingDeuteron; +}; + struct decay3bodyBuilder { Produces vtx3bodydata; + Produces kfvtx3bodydata; + Produces kfvtx3bodydatalite; Service ccdb; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + std::vector VtxCandidates; + + std::unordered_map ccdbCache; // Maps runNumber -> d_bz + std::unordered_map> grpMagCache; // Maps runNumber -> grpmap + + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + std::vector fTrackedClSizeVector; // Configurables Configurable d_UseAbsDCA{"d_UseAbsDCA", true, "Use Abs DCAs"}; - enum vtxstep { kVtxAll = 0, + enum Hyp3Body { kH3L = 0, + kH4L, + kHe4L, + kHe5L, + kNHyp3body }; + + enum VtxStep { kVtxAll = 0, kVtxTPCNcls, + kVtxPIDCut, kVtxhasSV, kVtxDcaDau, kVtxCosPA, kNVtxSteps }; - // Helper struct to pass V0 information + enum kfvtxstep { kKfVtxAll = 0, + kKfVtxCharge, + kKfVtxEta, + kKfVtxTPCNcls, + kKfVtxTPCRows, + kKfVtxTPCPID, + kKfVtxDCAxyPV, + kKfVtxDCAzPV, + kKfVtxV0MassConst, + kKfVtxhasSV, + kKfVtxDcaDau, + kKfVtxDcaDauVtx, + kKfVtxDauPt, + kKfVtxRap, + kKfVtxPt, + kKfVtxMass, + kKfVtxCosPA, + kKfVtxCosPAXY, + kKfVtxChi2geo, + kKfVtxTopoConstr, + kKfVtxChi2topo, + kKfNVtxSteps }; - HistogramRegistry registry{ - "registry", - { - {"hEventCounter", "hEventCounter", {HistType::kTH1F, {{1, 0.0f, 1.0f}}}}, - {"hVtx3BodyCounter", "hVtx3BodyCounter", {HistType::kTH1F, {{5, 0.0f, 5.0f}}}}, - }, - }; + HistogramRegistry registry{"registry", {}}; // hypothesis - Configurable bachelorcharge{"bachelorcharge", 1, "charge of the bachelor track"}; + Configurable motherhyp{"motherhyp", 0, "hypothesis of the 3body decayed particle"}; // corresponds to Hyp3Body + int bachelorcharge = 1; // to be updated in Init base on the hypothesis + o2::aod::pidtofgeneric::TofPidNewCollision bachelorTOFPID; // to be updated in Init base on the hypothesis + // Selection criteria Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; Configurable mintpcNCls{"mintpcNCls", 70, "min tpc Nclusters"}; Configurable minCosPA3body{"minCosPA3body", 0.9, "minCosPA3body"}; Configurable dcavtxdau{"dcavtxdau", 1.0, "DCA Vtx Daughters"}; + Configurable enablePidCut{"enablePidCut", 0, "enable function checkPIDH3L"}; + Configurable TofPidNsigmaMin{"TofPidNsigmaMin", -5, "TofPidNsigmaMin"}; + Configurable TofPidNsigmaMax{"TofPidNsigmaMax", 5, "TofPidNsigmaMax"}; + Configurable TpcPidNsigmaCut{"TpcPidNsigmaCut", 5, "TpcPidNsigmaCut"}; + Configurable minBachPUseTOF{"minBachPUseTOF", 1, "minBachP Enable TOF PID"}; Configurable useMatCorrType{"useMatCorrType", 0, "0: none, 1: TGeo, 2: LUT"}; // CCDB options @@ -86,20 +245,174 @@ struct decay3bodyBuilder { Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + // CCDB TOF PID paras + Configurable timestamp{"ccdb-timestamp", -1, "timestamp of the object"}; + Configurable paramFileName{"paramFileName", "", "Path to the parametrization object. If empty the parametrization is not taken from file"}; + Configurable parametrizationPath{"parametrizationPath", "TOF/Calib/Params", "Path of the TOF parametrization on the CCDB or in the file, if the paramFileName is not empty"}; + Configurable passName{"passName", "", "Name of the pass inside of the CCDB parameter collection. If empty, the automatically deceted from metadata (to be implemented!!!)"}; + Configurable timeShiftCCDBPath{"timeShiftCCDBPath", "", "Path of the TOF time shift vs eta. If empty none is taken"}; + Configurable loadResponseFromCCDB{"loadResponseFromCCDB", false, "Flag to load the response from the CCDB"}; + Configurable fatalOnPassNotAvailable{"fatalOnPassNotAvailable", true, "Flag to throw a fatal if the pass is not available in the retrieved CCDB object"}; + // for KFParticle reconstruction + struct : ConfigurableGroup { + Configurable cfgSkimmedProcessing{"kfparticleConfigurations.cfgSkimmedProcessing", false, "Flag for skimmed dataset processing"}; + Configurable triggerList{"kfparticleConfigurations.triggerList", "fH3L3Body", "List of triggers used to select events"}; + Configurable cfgOnlyKeepInterestedTrigger{"kfparticleConfigurations.cfgOnlyKeepInterestedTrigger", false, "Flag to keep only interested trigger"}; + Configurable fillCandidateFullTable{"kfparticleConfigurations.fillCandidateFullTable", false, "Switch to fill full table with candidate properties"}; + Configurable doSel8selection{"kfparticleConfigurations.doSel8selection", true, "flag for sel8 event selection"}; + Configurable doPosZselection{"kfparticleConfigurations.doPosZselection", true, "flag for posZ event selection"}; + Configurable doDCAFitterPreMinimum{"kfparticleConfigurations.doDCAFitterPreMinimum", false, "do DCAFitter pre-optimization before KF fit to include material corrections for decay3body vertex"}; + Configurable doTrackQA{"kfparticleConfigurations.doTrackQA", false, "Flag to fill QA histograms for daughter tracks."}; + Configurable doVertexQA{"kfparticleConfigurations.doVertexQA", false, "Flag to fill QA histograms for KFParticle PV."}; + Configurable useLambdaMassConstraint{"kfparticleConfigurations.useLambdaMassConstraint", false, "Apply Lambda mass constraint on proton-pion vertex"}; + Configurable doDCAPreSel{"kfparticleConfigurations.doDCAPreSel", false, "Apply selection on DCA of daughter tracks to PV"}; + Configurable maxEta{"kfparticleConfigurations.maxEta", 1.0, "Maximum eta for proton and pion daughter tracks"}; + Configurable maxEtaDeuteron{"kfparticleConfigurations.maxEtaDeuteron", 0.9, "Maximum eta for deuteron daughter track"}; + Configurable useTPCforPion{"kfparticleConfigurations.useTPCforPion", true, "Flag to ask for TPC info for pion track (PID, nClusters), false: pion track can be ITS only"}; + Configurable mintpcNClsProton{"kfparticleConfigurations.mintpcNClsProton", 70, "Minimum number of TPC clusters for proton track"}; + Configurable mintpcNClsPion{"kfparticleConfigurations.mintpcNClsPion", 70, "Minimum number of TPC clusters for pion track"}; + Configurable mintpcNClsBach{"kfparticleConfigurations.mintpcNClsBach", 70, "Minimum number of TPC clusters for bachelor track"}; + Configurable mintpcCrossedRows{"kfparticleConfigurations.mintpcCrossedRows", 70, "Minimum number of TPC crossed rows for proton and deuteron track"}; + Configurable mintpcCrossedRowsPion{"kfparticleConfigurations.mintpcCrossedRowsPion", 70, "Minimum number of TPC crossed rows for pion track"}; + Configurable minPtProton{"kfparticleConfigurations.minPtProton", 0.1, "Minimum pT of proton track"}; + Configurable maxPtProton{"kfparticleConfigurations.maxPtProton", 10, "Maximum pT of proton track"}; + Configurable minPtPion{"kfparticleConfigurations.minPtPion", 0.1, "Minimum pT of pion track"}; + Configurable maxPtPion{"kfparticleConfigurations.maxPtPion", 10, "Maximum pT of pion track"}; + Configurable minPtDeuteron{"kfparticleConfigurations.minPtDeuteron", 0.1, "Minimum pT of deuteron track"}; + Configurable maxPtDeuteron{"kfparticleConfigurations.maxPtDeuteron", 10, "Maximum pT of deuteron track"}; + Configurable mindcaXYPionPV{"kfparticleConfigurations.mindcaXYPionPV", 0.1, "Minimum DCA XY of the pion daughter track to the PV"}; + Configurable mindcaXYProtonPV{"kfparticleConfigurations.mindcaXYProtonPV", 0.1, "Minimum DCA XY of the proton daughter track to the PV"}; + Configurable mindcaZPionPV{"kfparticleConfigurations.mindcaZPionPV", 0.1, "Minimum DCA Z of the pion daughter track to the PV"}; + Configurable mindcaZProtonPV{"kfparticleConfigurations.mindcaZProtonPV", 0.1, "Minimum DCA Z of the proton daughter track to the PV"}; + Configurable maxtpcnSigma{"kfparticleConfigurations.maxtpcnSigma", 5., "Maximum nSigma TPC for daughter tracks"}; + Configurable maxDcaProDeu{"kfparticleConfigurations.maxDcaProDeu", 1000., "Maximum geometrical distance between proton and deuteron at the SV in 3D with KFParticle"}; + Configurable maxDcaProPi{"kfparticleConfigurations.maxDcaProPi", 1000., "Maximum geometrical distance between proton and pion at the SV in 3D with KFParticle"}; + Configurable maxDcaPiDe{"kfparticleConfigurations.maxDcaPiDe", 1000., "Maximum geometrical distance between pion and deuteron at the SV in 3D with KFParticle"}; + Configurable maxDcaXYSVDau{"kfparticleConfigurations.maxDcaXYSVDau", 1.0, "Maximum geometrical distance of daughter tracks from the SV in XY with KFParticle"}; + Configurable maxRapidityHt{"kfparticleConfigurations.maxRapidityHt", 1., "Maximum rapidity for Hypertriton candidates with KFParticle"}; + Configurable minPtHt{"kfparticleConfigurations.minPtHt", 0.01, "Minimum momentum for Hypertriton candidates with KFParticle (0.01 applied in SVertexer)"}; + Configurable maxPtHt{"kfparticleConfigurations.maxPtHt", 36., "Maximum momentum for Hypertriton candidates with KFParticle"}; + Configurable minMassHt{"kfparticleConfigurations.minMassHt", 2.96, "Minimum candidate mass with KFParticle"}; + Configurable maxMassHt{"kfparticleConfigurations.maxMassHt", 3.05, "Maximum candidate mass with KFParticle"}; + Configurable maxctauHt{"kfparticleConfigurations.maxctauHt", 40., "Maximum candidate ctau with KFParticle before topological constraint"}; + Configurable maxChi2geo{"kfparticleConfigurations.maxChi2geo", 1000., "Maximum chi2 geometrical with KFParticle"}; + Configurable minCosPA{"kfparticleConfigurations.minCosPA", 0.8, "Minimum cosine pointing angle with KFParticle (0.8 applied in SVertexer)"}; + Configurable minCosPAxy{"kfparticleConfigurations.minCosPAxy", 0.8, "Minimum cosine pointing angle in xy with KFParticle"}; + Configurable applyTopoSel{"kfparticleConfigurations.applyTopoSel", false, "Apply selection constraining the mother to the PV with KFParticle"}; + Configurable maxChi2topo{"kfparticleConfigurations.maxChi2topo", 1000., "Maximum chi2 topological with KFParticle"}; + Configurable nEvtMixing{"kfparticleConfigurations.nEvtMixing", 5, "Number of events to mix"}; + ConfigurableAxis binsVtxZ{"kfparticleConfigurations.binsVtxZ", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis binsMultiplicity{"kfparticleConfigurations.binsMultiplicity", {VARIABLE_WIDTH, 0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Mixing bins - multiplicity"}; + // 3body mixing + Configurable mixingType{"kfparticleConfigurations.mixingType", 0, "0: mix V0 from one event with bachelor from another, 1: mix pion and bachelor from one event with proton from another "}; + Configurable applySVertexerV0Cuts{"kfparticleConfigurations.applySVertexerV0Cuts", false, "Apply virtual V0 cuts applied in SVertexer in case of proton mixing"}; + ConfigurableAxis bins3BodyRadius{"kfparticleConfigurations.bins3BodyRadius", {VARIABLE_WIDTH, 0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 3.0f, 4.0f, 6.0f, 8.0f, 10.0f, 12.0f, 14.0f, 16.0f, 18.0f, 20.0f, 30.0f, 1000.0}, "Mixing bins - 3body radius"}; + // ConfigurableAxis bins3BodyPhi{"kfparticleConfigurations.bins3BodyPhi", {VARIABLE_WIDTH, -180.0f*TMath::Pi()/180, -170.0f*TMath::Pi()/180, -160.0f*TMath::Pi()/180, -150.0f*TMath::Pi()/180, -140.0f*TMath::Pi()/180, -130.0f*TMath::Pi()/180, -120.0f*TMath::Pi()/180, -110.0f*TMath::Pi()/180, -100.0f*TMath::Pi()/180, -90.0f*TMath::Pi()/180, -80.0f*TMath::Pi()/180, -70.0f*TMath::Pi()/180, -60.0f*TMath::Pi()/180, -50.0f*TMath::Pi()/180, -40.0f*TMath::Pi()/180, -30.0f*TMath::Pi()/180, -20.0f*TMath::Pi()/180, -10.0f*TMath::Pi()/180, 0.0f, 10.0f*TMath::Pi()/180, 20.0f*TMath::Pi()/180, 30.0f*TMath::Pi()/180, 40.0f*TMath::Pi()/180, 50.0f*TMath::Pi()/180, 60.0f*TMath::Pi()/180, 70.0f*TMath::Pi()/180, 80.0f*TMath::Pi()/180, 90.0f*TMath::Pi()/180, 100.0f*TMath::Pi()/180, 110.0f*TMath::Pi()/180, 120.0f*TMath::Pi()/180, 130.0f*TMath::Pi()/180, 140.0f*TMath::Pi()/180, 150.0f*TMath::Pi()/180, 160.0f*TMath::Pi()/180, 170.0f*TMath::Pi()/180, 180.0f*TMath::Pi()/180}, "Mixing bins - 3body phi"}; + ConfigurableAxis bins3BodyPhi{"kfparticleConfigurations.bins3BodyPhi", {VARIABLE_WIDTH, -180.0f * TMath::Pi() / 180, -160.0f * TMath::Pi() / 180, -140.0f * TMath::Pi() / 180, -120.0f * TMath::Pi() / 180, -100.0f * TMath::Pi() / 180, -80.0f * TMath::Pi() / 180, -60.0f * TMath::Pi() / 180, -40.0f * TMath::Pi() / 180, -20.0f * TMath::Pi() / 180, 0.0f, 20.0f * TMath::Pi() / 180, 40.0f * TMath::Pi() / 180, 60.0f * TMath::Pi() / 180, 80.0f * TMath::Pi() / 180, 100.0f * TMath::Pi() / 180, 120.0f * TMath::Pi() / 180, 140.0f * TMath::Pi() / 180, 160.0f * TMath::Pi() / 180, 180.0f * TMath::Pi() / 180}, "Mixing bins - 3body phi"}; + ConfigurableAxis bins3BodyPosZ{"kfparticleConfigurations.bins3BodyPosZ", {VARIABLE_WIDTH, -300.0f, -42.0f, -13.0f, -6.0f, -4.0f, -2.0f, 0.0f, 2.0f, 4.0f, 6.0f, 13.0f, 42.0f, 300.0f}, "Mixing bins - 3body z position"}; + Configurable selectVtxZ3bodyMixing{"kfparticleConfigurations.selectVtxZ3bodyMixing", true, "Select same VtxZ events in case of 3body mixing"}; + Configurable VtxZBin3bodyMixing{"kfparticleConfigurations.VtxZBin3bodyMixing", 1., "Bin width for event vtx z position in case of 3body mixing"}; + } kfparticleConfigurations; + + //------------------------------------------------------------------ + // Sets for DCAFitter event mixing + struct : ConfigurableGroup { + Configurable nUseMixed{"dcaFitterEMSel.nUseMixed", 5, "nUseMixed"}; + Configurable mMinPt2V0{"dcaFitterEMSel.mMinPt2V0", 0.5, "mMinPt2V0"}; // minimum pT^2 of V0 + Configurable mMaxTgl2V0{"dcaFitterEMSel.mMaxTgl2V0", 4, "mMaxTgl2V0"}; // maximum tgLambda^2 of V0 + Configurable mMaxDCAXY2ToMeanVertex3bodyV0{"dcaFitterEMSel.mMaxDCAXY2ToMeanVertex3bodyV0", 4, "mMaxDCAXY2ToMeanVertex3bodyV0"}; // max DCA^2 of 2 body decay to mean vertex of 3 body decay in XY + Configurable minCosPAXYMeanVertex3bodyV0{"dcaFitterEMSel.minCosPAXYMeanVertex3bodyV0", 0.9, "minCosPAXYMeanVertex3bodyV0"}; // min CosPA of 2 body decay to mean vertex of 3 body decay in XY + Configurable minCosPA3bodyV0{"dcaFitterEMSel.minCosPA3bodyV0", 0.8, "minCosPA3bodyV0"}; // min CosPA of 3 body decay to PV + Configurable maxRDiffV03body{"dcaFitterEMSel.maxRDiffV03body", 3, "maxRDiffV03body"}; // Maximum difference between virtual V0 and 3body radius + Configurable minPt3Body = {"dcaFitterEMSel.minPt3Body", 0.01, ""}; // minimum pT of 3body Vertex + Configurable maxTgl3Body = {"dcaFitterEMSel.maxTgl3Body", 2, ""}; // maximum tgLambda of 3body Vertex + Configurable maxDCAXY3Body{"dcaFitterEMSel.maxDCAXY3Body", 0.5, "DCAXY H3L to PV"}; // max DCA of 3 body decay to PV in XY + Configurable maxDCAZ3Body{"dcaFitterEMSel.maxDCAZ3Body", 1.0, "DCAZ H3L to PV"}; // max DCA of 3 body decay to PV in Z + // Binning for mixing events + ConfigurableAxis binsVtxZ{"dcaFitterEMSel.binsVtxZ", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis binsMultiplicity{"dcaFitterEMSel.binsMultiplicity", {VARIABLE_WIDTH, 0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Mixing bins - multiplicity"}; + Configurable maxDeltaRadiusColMixing{"dcaFitterEMSel.maxDeltaRadiusColMixing", 2., "max difference between pv z position in case of collision mixing"}; + Configurable maxDeltaPhiColMixing{"dcaFitterEMSel.maxDeltaPhiColMixing", 30., "max difference between Phi of monther particle in case of collision mixing (degree)"}; + // Configurations for mixing decay3bodys + // Configurable cfgUseDCAFitterInfo{"dcaFitterEMSel.cfgUseDCAFitterInfo", true, ""}; // if use information from dcatFitter while mixing reduced 3bodys + Configurable cfgMix3BodyMethod{"dcaFitterEMSel.cfgMix3BodyMethod", 0, ""}; // 0: bachelor, 1: pion, 2: proton + Configurable cfgApplyV0Cut{"dcaFitterEMSel.cfgApplyV0Cut", true, "if apply V0 cut while performing event-mixing"}; + ConfigurableAxis bins3BodyRadius{"dcaFitterEMSel.bins3BodyRadius", {VARIABLE_WIDTH, 0.0f, 2.0f, 4.0f, 7.0f, 10.0f, 14.0f, 18.0f, 22.0f, 30.0f, 40.0f}, "Mixing bins - 3body radius"}; + ConfigurableAxis bins3BodyPhi{"dcaFitterEMSel.bins3BodyPhi", {VARIABLE_WIDTH, -3.15, -2.15, -1, 0, 1, 2.15, 3.15}, "Mixing bins - 3body phi"}; + ConfigurableAxis bins3BodyPhiDegree{"dcaFitterEMSel.bins3BodyPhiDegree", {VARIABLE_WIDTH, -180, -120, -60, 0, 60, 120, 180}, "Mixing bins - 3body phi"}; + ConfigurableAxis bins3BodyPosZ{"dcaFitterEMSel.bins3BodyPosZ", {VARIABLE_WIDTH, -500.0f, -200.0f, -100.0f, -70.0f, -60.0f, -50.0f, -40.0f, -35.0f, -30.0f, -25.0f, -20.0f, -15.0f, -13.0f, -10.0f, -8.0f, -6.0f, -4.0f, -2.0f, 0.0f, 2.0f, 4.0f, 6.0f, 8.0f, 10.0f, 13.0f, 15.0f, 20.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f, 60.0f, 70.0f, 100.0f, 200.0f, 500.0f}, "3body SV z position"}; + Configurable selectPVPosZ3bodyMixing{"dcaFitterEMSel.selectPVPosZ3bodyMixing", true, "Select same pvPosZ events in case of 3body mixing"}; + Configurable maxDeltaPVPosZ3bodyMixing{"dcaFitterEMSel.maxDeltaPVPosZ3bodyMixing", 1., "max difference between pv z position in case of 3body mixing"}; + } dcaFitterEMSel; + + SliceCache cache; + using BinningTypeColEM = ColumnBinningPolicy; + using Binning3BodyDCAFitter = ColumnBinningPolicy; + using Binning3BodyKFInfo = ColumnBinningPolicy; + + // KF event mixing + using BinningTypeKF = ColumnBinningPolicy; + + // 3body mixing + // using Binning3Body = ColumnBinningPolicy; + using Binning3Body = ColumnBinningPolicy; + + // Filters and slices + Preslice perCollision = o2::aod::decay3body::collisionId; + Preslice perReducedCollision = o2::aod::reduceddecay3body::collisionId; int mRunNumber; float d_bz; float maxSnp; // max sine phi for propagation float maxStep; // max step size (cm) for propagation o2::base::MatLayerCylSet* lut = nullptr; + o2::vertexing::DCAFitterN<2> fitterV0; o2::vertexing::DCAFitterN<3> fitter3body; + o2::pid::tof::TOFResoParamsV2 mRespParamsV2; + std::array mV0Hyps; // 0 - Lambda, 1 - AntiLambda + bool doUpdateGRPMagField = false; // if initialize magnetic field for each bc + o2::dataformats::VertexBase mMeanVertex{{0., 0., 0.}, {0.1 * 0.1, 0., 0.1 * 0.1, 0., 0., 6. * 6.}}; void init(InitContext&) { + zorroSummary.setObject(zorro.getZorroSummary()); + mRunNumber = 0; d_bz = 0; maxSnp = 0.85f; // could be changed later maxStep = 2.00f; // could be changed later + + // set hypothesis corresponds to Hyp3Body, tpcpid to be implemented + switch (motherhyp) { + case Hyp3Body::kH3L: + bachelorcharge = 1; + bachelorTOFPID.SetPidType(o2::track::PID::Deuteron); + break; + case Hyp3Body::kH4L: + bachelorcharge = 1; + bachelorTOFPID.SetPidType(o2::track::PID::Triton); + break; + case Hyp3Body::kHe4L: + bachelorcharge = 2; + bachelorTOFPID.SetPidType(o2::track::PID::Helium3); + break; + case Hyp3Body::kHe5L: + bachelorcharge = 2; + bachelorTOFPID.SetPidType(o2::track::PID::Alpha); + break; + default: + LOG(fatal) << "Wrong hypothesis for decay3body"; + return; + } + + fitterV0.setPropagateToPCA(true); + fitterV0.setMaxR(200.); + fitterV0.setMinParamChange(1e-3); + fitterV0.setMinRelChi2Change(0.9); + fitterV0.setMaxDZIni(1e9); + fitterV0.setMaxChi2(1e9); + fitterV0.setUseAbsDCA(d_UseAbsDCA); + fitter3body.setPropagateToPCA(true); fitter3body.setMaxR(200.); //->maxRIni3body fitter3body.setMinParamChange(1e-3); @@ -109,7 +422,6 @@ struct decay3bodyBuilder { fitter3body.setUseAbsDCA(d_UseAbsDCA); // Material correction in the DCA fitter - ccdb->setURL(ccdburl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); @@ -126,20 +438,165 @@ struct decay3bodyBuilder { lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); } - registry.get(HIST("hVtx3BodyCounter"))->GetXaxis()->SetBinLabel(1, "Total"); - registry.get(HIST("hVtx3BodyCounter"))->GetXaxis()->SetBinLabel(2, "TPCNcls"); - registry.get(HIST("hVtx3BodyCounter"))->GetXaxis()->SetBinLabel(3, "HasSV"); - registry.get(HIST("hVtx3BodyCounter"))->GetXaxis()->SetBinLabel(4, "DcaDau"); - registry.get(HIST("hVtx3BodyCounter"))->GetXaxis()->SetBinLabel(5, "CosPA"); - // Material correction in the DCA fitter - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; if (useMatCorrType == 1) matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; if (useMatCorrType == 2) matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + fitterV0.setMatCorrType(matCorr); fitter3body.setMatCorrType(matCorr); + + // Add histograms separately for different process functions + if (doprocessRun3 == true || doprocessRun3Reduced) { + registry.add("hEventCounter", "hEventCounter", HistType::kTH1F, {{1, 0.0f, 1.0f}}); + } + + if (doprocessRun3 == true || doprocessRun3Reduced || doprocessRun3ReducedEM == true || doprocessRun3Reduced3bodyMixing == true || doprocessRun3Reduced3bodyMixingKFInfo == true) { + auto hVtx3BodyCounter = registry.add("hVtx3BodyCounter", "hVtx3BodyCounter", HistType::kTH1D, {{6, 0.0f, 6.0f}}); + hVtx3BodyCounter->GetXaxis()->SetBinLabel(1, "Total"); + hVtx3BodyCounter->GetXaxis()->SetBinLabel(2, "TPCNcls"); + hVtx3BodyCounter->GetXaxis()->SetBinLabel(3, "PIDCut"); + hVtx3BodyCounter->GetXaxis()->SetBinLabel(4, "HasSV"); + hVtx3BodyCounter->GetXaxis()->SetBinLabel(5, "DcaDau"); + hVtx3BodyCounter->GetXaxis()->SetBinLabel(6, "CosPA"); + registry.add("hBachelorTOFNSigmaDe", "", HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}); + } + + if (doprocessRun3ReducedEM == true) { + registry.add("hEventCount", "hEventCount", HistType::kTH2F, {dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}); + registry.add("hEventPairs", "hEventPairs", HistType::kTH2F, {dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}); + registry.add("hDecay3BodyPairsBeforeCut", "hDecay3BodyPairsBeforeCut", HistType::kTH2F, {dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}); + registry.add("hDecay3BodyPairsAfterCut", "hDecay3BodyPairsAfterCut", HistType::kTH2F, {dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}); + registry.add("hRadius0", "hRadius0", HistType::kTH1F, {{200, 0.0f, 20.0f, "Radius (cm)"}}); + registry.add("hRadius1", "hRadius1", HistType::kTH1F, {{200, 0.0f, 20.0f, "Radius (cm)"}}); + registry.add("hDeltaRadius", "hDeltaRadius", HistType::kTH1F, {{400, -20.0f, 20.0f, "#Delta Radius (cm)"}}); + registry.add("hPhi0", "hPhi0", HistType::kTH1F, {{360, -180.0f, 180.0f, "#phi (degree)"}}); + registry.add("hPhi1", "hPhi1", HistType::kTH1F, {{360, -180.0f, 180.0f, "#phi (degree)"}}); + registry.add("hDeltaPhi", "hDeltaPhi", HistType::kTH1F, {{360, -180.0f, 180.0f, "#Delta #phi (degree)"}}); + } + + if (doprocessRun3Reduced3bodyMixing == true || doprocessRun3Reduced3bodyMixingKFInfo == true) { + registry.add("hDecay3BodyRadiusPhi", "hDecay3BodyRadiusPhi", HistType::kTH2F, {dcaFitterEMSel.bins3BodyRadius, dcaFitterEMSel.bins3BodyPhi}); + registry.add("hDecay3BodyPosZ", "hDecay3BodyPosZ", HistType::kTH1F, {dcaFitterEMSel.bins3BodyPosZ}); + auto h3bodyCombinationCounter = registry.add("h3bodyCombinationCounter", "h3bodyCombinationCounter", HistType::kTH1D, {{4, 0.0f, 4.0f}}); + h3bodyCombinationCounter->GetXaxis()->SetBinLabel(1, "total"); + h3bodyCombinationCounter->GetXaxis()->SetBinLabel(2, "bach sign/ID"); + h3bodyCombinationCounter->GetXaxis()->SetBinLabel(3, "not same collision"); + h3bodyCombinationCounter->GetXaxis()->SetBinLabel(4, "collision VtxZ"); + } + + if (doprocessRun3ReducedEM == true || doprocessRun3Reduced3bodyMixing == true || doprocessRun3Reduced3bodyMixingKFInfo == true) { + doUpdateGRPMagField = true; + registry.add("h3bodyEMCutCounter", "h3bodyEMCutCounter", HistType::kTH1D, {{14, 0.0f, 14.0f}}); + } + + if (doprocessRun3withKFParticle == true || doprocessRun3withKFParticleStrangenessTracking == true || doprocessRun3withKFParticleReduced == true || doprocessRun3withKFParticleReducedEM == true || doprocessRun3withKFParticleReduced3bodyMixing == true) { + auto hEventCounterZorro = registry.add("Counters/hEventCounterZorro", "hEventCounterZorro", HistType::kTH1D, {{2, -0.5, 1.5}}); + hEventCounterZorro->GetXaxis()->SetBinLabel(1, "Zorro before evsel"); + hEventCounterZorro->GetXaxis()->SetBinLabel(2, "Zorro after evsel"); + auto hEventCounterKFParticle = registry.add("Counters/hEventCounterKFParticle", "hEventCounterKFParticle", HistType::kTH1D, {{4, 0.0f, 4.0f}}); + hEventCounterKFParticle->GetXaxis()->SetBinLabel(1, "total"); + hEventCounterKFParticle->GetXaxis()->SetBinLabel(2, "sel8"); + hEventCounterKFParticle->GetXaxis()->SetBinLabel(3, "vertexZ"); + hEventCounterKFParticle->GetXaxis()->SetBinLabel(4, "has candidate"); + hEventCounterKFParticle->LabelsOption("v"); + auto hVtx3BodyCounterKFParticle = registry.add("Counters/hVtx3BodyCounterKFParticle", "hVtx3BodyCounterKFParticle", HistType::kTH1D, {{21, 0.0f, 21.0f}}); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(1, "Total"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(2, "Charge"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(3, "Eta"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(4, "TPCNcls"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(5, "TPCRows"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(6, "TPCpid"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(7, "DCAxyPV"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(8, "DCAzPV"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(9, "V0MassConst"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(10, "HasSV"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(11, "DcaDau"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(12, "DCADauVtx"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(13, "DauPt"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(14, "Rapidity"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(15, "Pt"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(16, "Mass"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(17, "CosPA"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(18, "CosPAXY"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(19, "Chi2geo"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(20, "TopoConstr"); + hVtx3BodyCounterKFParticle->GetXaxis()->SetBinLabel(21, "Chi2topo"); + hVtx3BodyCounterKFParticle->LabelsOption("v"); + + registry.add("QA/Tracks/hTrackPosTPCNcls", "hTrackPosTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); + registry.add("QA/Tracks/hTrackNegTPCNcls", "hTrackNegTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); + registry.add("QA/Tracks/hTrackBachTPCNcls", "hTrackBachTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); + registry.add("QA/Tracks/hTrackPosHasTPC", "hTrackPosHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); + registry.add("QA/Tracks/hTrackNegHasTPC", "hTrackNegHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); + registry.add("QA/Tracks/hTrackBachHasTPC", "hTrackBachHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); + registry.add("QA/Tracks/hTrackBachITSClusSizes", "hTrackBachITSClusSizes", HistType::kTH1F, {{10, 0., 10., "ITS cluster sizes"}}); + registry.add("QA/Tracks/hTrackProtonTPCPID", "hTrackProtonTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); + registry.add("QA/Tracks/hTrackPionTPCPID", "hTrackPionTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); + registry.add("QA/Tracks/hTrackBachTPCPID", "hTrackBachTPCPID", HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}); + registry.add("QA/Tracks/hTrackProtonPt", "hTrackProtonPt", HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}); + registry.add("QA/Tracks/hTrackPionPt", "hTrackPionPt", HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}); + registry.add("QA/Tracks/hTrackBachPt", "hTrackBachPt", HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}); + registry.add("QA/Event/hAllSelEventsVtxZ", "hAllSelEventsVtxZ", HistType::kTH1F, {{500, -15.0f, 15.0f, "PV Z (cm)"}}); + registry.add("QA/Event/hVtxXKF", "hVtxXKF", HistType::kTH1F, {{500, -0.1f, 0.1f, "PV X (cm)"}}); + registry.add("QA/Event/hVtxYKF", "hVtxYKF", HistType::kTH1F, {{500, -0.1f, 0.1f, "PV Y (cm)"}}); + registry.add("QA/Event/hVtxZKF", "hVtxZKF", HistType::kTH1F, {{500, -15.0f, 15.0f, "PV Z (cm)"}}); + registry.add("QA/Event/hVtxCovXXKF", "hVtxCovXXKF", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XX) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovYYKF", "hVtxCovYYKF", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(YY) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovZZKF", "hVtxCovZZKF", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(ZZ) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovXYKF", "hVtxCovXYKF", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XY) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovXZKF", "hVtxCovXZKF", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XZ) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovYZKF", "hVtxCovYZKF", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(YZ) (cm^{2})"}}); + registry.add("QA/Event/hVtxX", "hVtxX", HistType::kTH1F, {{500, -0.1f, 0.1f, "PV X (cm)"}}); + registry.add("QA/Event/hVtxY", "hVtxY", HistType::kTH1F, {{500, -0.1f, 0.1f, "PV Y (cm)"}}); + registry.add("QA/Event/hVtxZ", "hVtxZ", HistType::kTH1F, {{500, -15.0f, 15.0f, "PV Z (cm)"}}); + registry.add("QA/Event/hVtxCovXX", "hVtxCovXX", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XX) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovYY", "hVtxCovYY", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(YY) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovZZ", "hVtxCovZZ", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(ZZ) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovXY", "hVtxCovXY", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XY) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovXZ", "hVtxCovXZ", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(XZ) (cm^{2})"}}); + registry.add("QA/Event/hVtxCovYZ", "hVtxCovYZ", HistType::kTH1F, {{200, -0.0001f, 0.0001f, "PV cov(YZ) (cm^{2})"}}); + } + + if (doprocessRun3withKFParticleReducedEM == true) { + registry.add("QA/EM/hPairCounterMixing", "hPairCounterMixing", HistType::kTH1D, {{1, 0.0f, 1.0f}}); + auto hCombinationCounterMixing = registry.add("QA/EM/hCombinationCounterMixing", "hCombinationCounterMixing", HistType::kTH1D, {{3, 0.0f, 3.0f}}); + hCombinationCounterMixing->GetXaxis()->SetBinLabel(1, "total"); + hCombinationCounterMixing->GetXaxis()->SetBinLabel(2, "bach sign/ID"); + hCombinationCounterMixing->GetXaxis()->SetBinLabel(3, "radius, phi"); + hCombinationCounterMixing->LabelsOption("v"); + + registry.add("QA/EM/hEventBinCounts", "hEventBinCounts", HistType::kTH2D, {{10, 0, 10, "bins VtxZ"}, {13, 0, 13, "bins mult"}}); + registry.add("QA/EM/h3bodyBinCounts", "h3bodyBinCounts", HistType::kTH2D, {{10, 0, 10, "bins VtxZ"}, {13, 0, 13, "bins mult"}}); + registry.add("QA/EM/hPairBinCounts", "hPairBinCounts", HistType::kTH2D, {{10, 0, 10, "bins VtxZ"}, {13, 0, 13, "bins mult"}}); + + registry.add("QA/EM/hRadius1", "hRadius1", HistType::kTH1F, {{200, 0.0f, 20.0f, "Radius (cm)"}}); + registry.add("QA/EM/hRadius2", "hRadius2", HistType::kTH1F, {{200, 0.0f, 20.0f, "Radius (cm)"}}); + registry.add("QA/EM/hPhi1", "hPhi1", HistType::kTH1F, {{360, 0.0f, 360.0f, "#phi (degree)"}}); + registry.add("QA/EM/hPhi2", "hPhi2", HistType::kTH1F, {{360, 0.0f, 360.0f, "#phi (degree)"}}); + registry.add("QA/EM/hDeltaRadius", "hDeltaRadius", HistType::kTH1F, {{200, 0.0f, 10.0f, "#Delta Radius (cm)"}}); + registry.add("QA/EM/hDeltaPhi", "hDeltaPhi", HistType::kTH1F, {{360, 0.0f, 360.0f, "#Delta #phi (degree)"}}); + } + + if (doprocessRun3withKFParticleReduced3bodyMixing == true) { + auto h3bodyCombinationCounter = registry.add("QA/EM/h3bodyCombinationCounter", "h3bodyCombinationCounter", HistType::kTH1D, {{4, 0.0f, 4.0f}}); + h3bodyCombinationCounter->GetXaxis()->SetBinLabel(1, "total"); + h3bodyCombinationCounter->GetXaxis()->SetBinLabel(2, "not same collision"); + h3bodyCombinationCounter->GetXaxis()->SetBinLabel(3, "collision VtxZ"); + h3bodyCombinationCounter->GetXaxis()->SetBinLabel(4, "bach sign/ID"); + h3bodyCombinationCounter->LabelsOption("v"); + // registry.add("QA/EM/h3bodyBinCounts", "h3bodyBinCounts", HistType::kTH3D, {{16, 0, 16, "bins radius"}, {36, 0, 36, "bins phi"}, {12, 0, 12, "bins pos Z"}}); + registry.add("QA/EM/h3bodyBinCounts", "h3bodyBinCounts", HistType::kTH2D, {{16, 0, 16, "bins radius"}, {18, 0, 18, "bins phi"}}); + + AxisSpec radiusAxis = {kfparticleConfigurations.bins3BodyRadius, "Radius (cm)"}; + AxisSpec phiAxis = {kfparticleConfigurations.bins3BodyPhi, "#phi (degree)"}; + AxisSpec posZAxis = {kfparticleConfigurations.bins3BodyPosZ, "position in z (cm)"}; + + registry.add("QA/EM/hRadius", "hRadius", HistType::kTH1F, {radiusAxis}); + registry.add("QA/EM/hPhi", "hPhi", HistType::kTH1F, {phiAxis}); + registry.add("QA/EM/hPosZ", "hPosZ", HistType::kTH1F, {posZAxis}); + } } void initCCDB(aod::BCsWithTimestamps::iterator const& bc) @@ -147,13 +604,21 @@ struct decay3bodyBuilder { if (mRunNumber == bc.runNumber()) { return; } + if (kfparticleConfigurations.cfgSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), kfparticleConfigurations.triggerList); + zorro.populateHistRegistry(registry, bc.runNumber()); + } // In case override, don't proceed, please - no CCDB access required if (d_bz_input > -990) { d_bz = d_bz_input; + fitterV0.setBz(d_bz); fitter3body.setBz(d_bz); +#ifdef HomogeneousField + KFParticle::SetField(d_bz); +#endif o2::parameters::GRPMagField grpmag; - if (fabs(d_bz) > 1e-5) { + if (std::fabs(d_bz) > 1e-5) { grpmag.setL3Current(30000.f / (d_bz / 5.0f)); } o2::base::Propagator::initFieldFromGRP(&grpmag); @@ -176,130 +641,1736 @@ struct decay3bodyBuilder { } o2::base::Propagator::initFieldFromGRP(grpmag); // Fetch magnetic field from ccdb for current collision - d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + // d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + d_bz = o2::base::Propagator::Instance()->getNominalBz(); LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; } mRunNumber = bc.runNumber(); // Set magnetic field value once known + fitterV0.setBz(d_bz); fitter3body.setBz(d_bz); +// Set magnetic field for KF vertexing +#ifdef HomogeneousField + KFParticle::SetField(d_bz); +#endif if (useMatCorrType == 2) { // setMatLUT only after magfield has been initalized // (setMatLUT has implicit and problematic init field call if not) o2::base::Propagator::Instance()->setMatLUT(lut); } + + // Initial TOF PID Paras, copied from PIDTOF.h + timestamp.value = bc.timestamp(); + ccdb->setTimestamp(timestamp.value); + // Not later than now objects + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + // TODO: implement the automatic pass name detection from metadata + if (passName.value == "") { + passName.value = "unanchored"; // temporary default + LOG(warning) << "Passed autodetect mode for pass, not implemented yet, waiting for metadata. Taking '" << passName.value << "'"; + } + LOG(info) << "Using parameter collection, starting from pass '" << passName.value << "'"; + + const std::string fname = paramFileName.value; + if (!fname.empty()) { // Loading the parametrization from file + LOG(info) << "Loading exp. sigma parametrization from file " << fname << ", using param: " << parametrizationPath.value; + if (1) { + o2::tof::ParameterCollection paramCollection; + paramCollection.loadParamFromFile(fname, parametrizationPath.value); + LOG(info) << "+++ Loaded parameter collection from file +++"; + if (!paramCollection.retrieveParameters(mRespParamsV2, passName.value)) { + if (fatalOnPassNotAvailable) { + LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + } else { + LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + } + } else { + mRespParamsV2.setShiftParameters(paramCollection.getPars(passName.value)); + mRespParamsV2.printShiftParameters(); + } + } else { + mRespParamsV2.loadParamFromFile(fname.data(), parametrizationPath.value); + } + } else if (loadResponseFromCCDB) { // Loading it from CCDB + LOG(info) << "Loading exp. sigma parametrization from CCDB, using path: " << parametrizationPath.value << " for timestamp " << timestamp.value; + o2::tof::ParameterCollection* paramCollection = ccdb->getForTimeStamp(parametrizationPath.value, timestamp.value); + paramCollection->print(); + if (!paramCollection->retrieveParameters(mRespParamsV2, passName.value)) { // Attempt at loading the parameters with the pass defined + if (fatalOnPassNotAvailable) { + LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + } else { + LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + } + } else { // Pass is available, load non standard parameters + mRespParamsV2.setShiftParameters(paramCollection->getPars(passName.value)); + mRespParamsV2.printShiftParameters(); + } + } + mRespParamsV2.print(); + if (timeShiftCCDBPath.value != "") { + if (timeShiftCCDBPath.value.find(".root") != std::string::npos) { + mRespParamsV2.setTimeShiftParameters(timeShiftCCDBPath.value, "gmean_Pos", true); + mRespParamsV2.setTimeShiftParameters(timeShiftCCDBPath.value, "gmean_Neg", false); + } else { + mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/pos", timeShiftCCDBPath.value.c_str()), timestamp.value), true); + mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/neg", timeShiftCCDBPath.value.c_str()), timestamp.value), false); + } + } + + bachelorTOFPID.SetParams(mRespParamsV2); + } + + void initCCDBfromRunNumber(int runNumber) + { + // set magnetic field only when run number changes + if (mRunNumber == runNumber) { + LOG(debug) << "CCDB initialized for run " << mRunNumber; + return; + } + mRunNumber = runNumber; // Update the last run number + + // Check if the CCDB data for this run is already cached + if (ccdbCache.find(runNumber) != ccdbCache.end()) { + LOG(debug) << "CCDB data already cached for run " << runNumber; + d_bz = ccdbCache[runNumber]; + if (doUpdateGRPMagField == true) { + o2::base::Propagator::initFieldFromGRP(grpMagCache[runNumber].get()); + } + } else { + std::shared_ptr grpmag = std::make_shared(*ccdb->getForRun(grpmagPath, runNumber)); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for run number " << runNumber; + } + o2::base::Propagator::initFieldFromGRP(grpmag.get()); + // Fetch magnetic field from ccdb for current collision + d_bz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "Retrieved GRP for run number " << runNumber << " with magnetic field of " << d_bz << " kZG"; + + ccdbCache[runNumber] = d_bz; + grpMagCache[runNumber] = grpmag; + } + + // Set magnetic field for KF vertexing +#ifdef HomogeneousField + KFParticle::SetField(d_bz); +#endif + // Set field for DCAfitter + fitterV0.setBz(d_bz); + fitter3body.setBz(d_bz); + + mV0Hyps[0].set(o2::track::PID::Lambda, o2::track::PID::Proton, o2::track::PID::Pion, pidCutsLambda, d_bz); + mV0Hyps[1].set(o2::track::PID::Lambda, o2::track::PID::Pion, o2::track::PID::Proton, pidCutsLambda, d_bz); + + if (useMatCorrType == 2) { + // setMatLUT only after magfield has been initalized + o2::base::Propagator::Instance()->setMatLUT(lut); + } + + // cache magnetic field info + ccdbCache[runNumber] = d_bz; + } + + //------------------------------------------------------------------ + //-------------------- DCA fitter reconstruction ------------------- + //------------------------------------------------------------------ + // Select decay3body candidate based on daughter track PID + template + bool checkPID(TTrack const& trackProton, TTrack const& trackPion, TTrack const& trackBachelor, const double& tofNSigmaBach) + { + if ((tofNSigmaBach < TofPidNsigmaMin || tofNSigmaBach > TofPidNsigmaMax) && trackBachelor.p() > minBachPUseTOF) { + return false; + } + if (std::abs(trackProton.tpcNSigmaPr()) > TpcPidNsigmaCut) { + return false; + } + if (std::abs(trackPion.tpcNSigmaPi()) > TpcPidNsigmaCut) { + return false; + } + return true; + } + // PID check for H3L + template + bool checkPIDH3L(TTrack const& trackProton, TTrack const& trackPion, TTrack const& trackBachelor, const double& tofNSigmaBach) + { + if ((std::abs(trackBachelor.tpcNSigmaDe()) > TpcPidNsigmaCut) || !checkPID(trackProton, trackPion, trackBachelor, tofNSigmaBach)) { + return false; + } + return true; } //------------------------------------------------------------------ // 3body candidate builder - template - void buildVtx3BodyDataTable(TCollisionTable const& collision, TTrackTable const& /*tracks*/, aod::Decay3Bodys const& decay3bodys, int bachelorcharge = 1) + template + void fillVtxCand(TCollisionTable const& collision, TTrackTable const& t0, TTrackTable const& t1, TTrackTable const& t2, int64_t decay3bodyId, int bachelorcharge = 1, double tofNSigmaBach = -999, bool saveInTable = true) { + registry.fill(HIST("hVtx3BodyCounter"), kVtxAll); - for (auto& vtx3body : decay3bodys) { + if (t0.tpcNClsFound() < mintpcNCls || t1.tpcNClsFound() < mintpcNCls || t2.tpcNClsFound() < mintpcNCls) { + return; + } + registry.fill(HIST("hVtx3BodyCounter"), kVtxTPCNcls); - registry.fill(HIST("hVtx3BodyCounter"), kVtxAll); + if (enablePidCut) { + if (t2.sign() > 0) { + if (!checkPIDH3L(t0, t1, t2, tofNSigmaBach)) + return; + } else { + if (!checkPIDH3L(t1, t0, t2, tofNSigmaBach)) + return; + } + } - auto t0 = vtx3body.template track0_as(); - auto t1 = vtx3body.template track1_as(); - auto t2 = vtx3body.template track2_as(); + registry.fill(HIST("hVtx3BodyCounter"), kVtxPIDCut); - if (t0.tpcNClsFound() < mintpcNCls && t1.tpcNClsFound() < mintpcNCls && t2.tpcNClsFound() < mintpcNCls) { - continue; - } - registry.fill(HIST("hVtx3BodyCounter"), kVtxTPCNcls); + // Calculate DCA with respect to the collision associated to the V0, not individual tracks + gpu::gpustd::array dcaInfo; + + auto Track0Par = getTrackPar(t0); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, Track0Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); + auto Track0dcaXY = dcaInfo[0]; + auto Track0dca = std::sqrt(Track0dcaXY * Track0dcaXY + dcaInfo[1] * dcaInfo[1]); - // Calculate DCA with respect to the collision associated to the V0, not individual tracks - gpu::gpustd::array dcaInfo; + auto Track1Par = getTrackPar(t1); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, Track1Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); + auto Track1dcaXY = dcaInfo[0]; + auto Track1dca = std::sqrt(Track1dcaXY * Track1dcaXY + dcaInfo[1] * dcaInfo[1]); - auto Track0Par = getTrackPar(t0); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, Track0Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); - auto Track0dcaXY = dcaInfo[0]; + auto Track2Par = getTrackPar(t2); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, Track2Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); + auto Track2dcaXY = dcaInfo[0]; + auto Track2dca = std::sqrt(Track2dcaXY * Track2dcaXY + dcaInfo[1] * dcaInfo[1]); - auto Track1Par = getTrackPar(t1); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, Track1Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); - auto Track1dcaXY = dcaInfo[0]; + auto Track0 = getTrackParCov(t0); + auto Track1 = getTrackParCov(t1); + auto Track2 = getTrackParCov(t2); + int n3bodyVtx = fitter3body.process(Track0, Track1, Track2); + if (n3bodyVtx == 0) { // discard this pair + return; + } + registry.fill(HIST("hVtx3BodyCounter"), kVtxhasSV); - auto Track2Par = getTrackPar(t2); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, Track2Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); - auto Track2dcaXY = dcaInfo[0]; + std::array pos = {0.}; + const auto& vtxXYZ = fitter3body.getPCACandidate(); + for (int i = 0; i < 3; i++) { + pos[i] = vtxXYZ[i]; + } - auto Track0 = getTrackParCov(t0); - auto Track1 = getTrackParCov(t1); - auto Track2 = getTrackParCov(t2); - int n3bodyVtx = fitter3body.process(Track0, Track1, Track2); - if (n3bodyVtx == 0) { // discard this pair - continue; + std::array p0 = {0.}, p1 = {0.}, p2{0.}; + const auto& propagatedTrack0 = fitter3body.getTrack(0); + const auto& propagatedTrack1 = fitter3body.getTrack(1); + const auto& propagatedTrack2 = fitter3body.getTrack(2); + propagatedTrack0.getPxPyPzGlo(p0); + propagatedTrack1.getPxPyPzGlo(p1); + propagatedTrack2.getPxPyPzGlo(p2); + for (int i = 0; i < 3; i++) { + p2[i] *= bachelorcharge; + } + std::array p3B = {p0[0] + p1[0] + p2[0], p0[1] + p1[1] + p2[1], p0[2] + p1[2] + p2[2]}; + + if (fitter3body.getChi2AtPCACandidate() > dcavtxdau) { + return; + } + registry.fill(HIST("hVtx3BodyCounter"), kVtxDcaDau); + + float VtxcosPA = RecoDecay::cpa(std::array{collision.posX(), collision.posY(), collision.posZ()}, std::array{pos[0], pos[1], pos[2]}, std::array{p3B[0], p3B[1], p3B[2]}); + if (VtxcosPA < minCosPA3body) { + return; + } + registry.fill(HIST("hVtx3BodyCounter"), kVtxCosPA); + registry.fill(HIST("hBachelorTOFNSigmaDe"), t2.sign() * t2.p(), tofNSigmaBach); + + // additional cut for EM + if (decay3bodyId == -1) { + registry.fill(HIST("h3bodyEMCutCounter"), 0.5); + auto v0Track0 = getTrackParCov(t0); + auto v0Track1 = getTrackParCov(t1); + int nV0 = fitterV0.process(v0Track0, v0Track1); + if (nV0 == 0) { + return; } - registry.fill(HIST("hVtx3BodyCounter"), kVtxhasSV); + registry.fill(HIST("h3bodyEMCutCounter"), 1.5); - std::array pos = {0.}; - const auto& vtxXYZ = fitter3body.getPCACandidate(); + std::array v0pos = {0.}; + const auto& v0vtxXYZ = fitterV0.getPCACandidate(); for (int i = 0; i < 3; i++) { - pos[i] = vtxXYZ[i]; + v0pos[i] = v0vtxXYZ[i]; } + const int cand = 0; + if (!fitterV0.isPropagateTracksToVertexDone(cand) && !fitterV0.propagateTracksToVertex(cand)) { + return; + } + registry.fill(HIST("h3bodyEMCutCounter"), 2.5); - std::array p0 = {0.}, p1 = {0.}, p2{0.}; - const auto& propagatedTrack0 = fitter3body.getTrack(0); - const auto& propagatedTrack1 = fitter3body.getTrack(1); - const auto& propagatedTrack2 = fitter3body.getTrack(2); - propagatedTrack0.getPxPyPzGlo(p0); - propagatedTrack1.getPxPyPzGlo(p1); - propagatedTrack2.getPxPyPzGlo(p2); - for (int i = 0; i < 3; i++) { - p2[i] *= bachelorcharge; + const auto& trPProp = fitterV0.getTrack(0, cand); + const auto& trNProp = fitterV0.getTrack(1, cand); + std::array pP{}, pN{}; + trPProp.getPxPyPzGlo(pP); + trNProp.getPxPyPzGlo(pN); + std::array pV0 = {pP[0] + pN[0], pP[1] + pN[1], pP[2] + pN[2]}; + // Cut for Virtual V0 + float dxv0 = v0pos[0] - mMeanVertex.getX(), dyv0 = v0pos[1] - mMeanVertex.getY(), r2v0 = dxv0 * dxv0 + dyv0 * dyv0; + float rv0 = std::sqrt(r2v0); + float pt2V0 = pV0[0] * pV0[0] + pV0[1] * pV0[1], prodXYv0 = dxv0 * pV0[0] + dyv0 * pV0[1], tDCAXY = prodXYv0 / pt2V0; + if (dcaFitterEMSel.cfgApplyV0Cut && pt2V0 <= dcaFitterEMSel.mMinPt2V0) { + return; + } + registry.fill(HIST("h3bodyEMCutCounter"), 3.5); + if (dcaFitterEMSel.cfgApplyV0Cut && pV0[2] * pV0[2] / pt2V0 > dcaFitterEMSel.mMaxTgl2V0) { // tgLambda cut + return; } - std::array p3B = {p0[0] + p1[0] + p2[0], p0[1] + p1[1] + p2[1], p0[2] + p1[2] + p2[2]}; + registry.fill(HIST("h3bodyEMCutCounter"), 4.5); - if (fitter3body.getChi2AtPCACandidate() > dcavtxdau) { + float p2V0 = pt2V0 + pV0[2] * pV0[2], ptV0 = std::sqrt(pt2V0); + // apply mass selections + float p2Pos = pP[0] * pP[0] + pP[1] * pP[1] + pP[2] * pP[2], p2Neg = pN[0] * pN[0] + pN[1] * pN[1] + pN[2] * pN[2]; + bool good3bodyV0Hyp = false; + for (int ipid = 0; ipid < 2; ipid++) { + float massForLambdaHyp = mV0Hyps[ipid].calcMass(p2Pos, p2Neg, p2V0); + if (massForLambdaHyp - mV0Hyps[ipid].getMassV0Hyp() < mV0Hyps[ipid].getMargin(ptV0)) { + good3bodyV0Hyp = true; + break; + } + } + if (dcaFitterEMSel.cfgApplyV0Cut && !good3bodyV0Hyp) { + return; + } + registry.fill(HIST("h3bodyEMCutCounter"), 5.5); + + float dcaX = dxv0 - pV0[0] * tDCAXY, dcaY = dyv0 - pV0[1] * tDCAXY, dca2 = dcaX * dcaX + dcaY * dcaY; + float cosPAXY = prodXYv0 / rv0 * ptV0; + if (dcaFitterEMSel.cfgApplyV0Cut && dca2 > dcaFitterEMSel.mMaxDCAXY2ToMeanVertex3bodyV0) { + return; + } + registry.fill(HIST("h3bodyEMCutCounter"), 6.5); + // FIXME: V0 cosPA cut to be investigated + if (dcaFitterEMSel.cfgApplyV0Cut && cosPAXY < dcaFitterEMSel.minCosPAXYMeanVertex3bodyV0) { + return; + } + registry.fill(HIST("h3bodyEMCutCounter"), 7.5); + // Check: CosPA Cut of Virtual V0 may not be used since the V0 may be based on another PV + float dx = v0pos[0] - collision.posX(), dy = v0pos[1] - collision.posY(), dz = v0pos[2] - collision.posZ(), prodXYZv0 = dx * pV0[0] + dy * pV0[1] + dz * pV0[2]; + float v0CosPA = prodXYZv0 / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0); + if (dcaFitterEMSel.cfgApplyV0Cut && v0CosPA < dcaFitterEMSel.minCosPA3bodyV0) { + return; + } + registry.fill(HIST("h3bodyEMCutCounter"), 8.5); + + float r3body = std::hypot(pos[0], pos[1]); + if (r3body < 0.5) { + return; + } + registry.fill(HIST("h3bodyEMCutCounter"), 9.5); + + // Cut for the compatibility of V0 and 3body vertex + float deltaR = std::abs(rv0 - r3body); + if (deltaR > dcaFitterEMSel.maxRDiffV03body) { + return; + } + registry.fill(HIST("h3bodyEMCutCounter"), 10.5); + + float pt3B = std::hypot(p3B[0], p3B[1]); + if (pt3B < dcaFitterEMSel.minPt3Body) { // pt cut + return; + } + registry.fill(HIST("h3bodyEMCutCounter"), 11.5); + if (p3B[2] / pt3B > dcaFitterEMSel.maxTgl3Body) { // tgLambda cut + return; + } + registry.fill(HIST("h3bodyEMCutCounter"), 12.5); + + // H3L DCA Check + const auto& vertexXYZ = fitter3body.getPCACandidatePos(); + auto track3B = o2::track::TrackParCov(vertexXYZ, p3B, t2.sign()); + o2::dataformats::DCA dca; + if (!track3B.propagateToDCA({{collision.posX(), collision.posY(), collision.posZ()}, {collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}}, fitter3body.getBz(), &dca, 5.) || + std::abs(dca.getY()) > dcaFitterEMSel.maxDCAXY3Body || std::abs(dca.getZ()) > dcaFitterEMSel.maxDCAZ3Body) { + return; + } + registry.fill(HIST("h3bodyEMCutCounter"), 13.5); + } + + VtxCandidate candVtx; + candVtx.track0Id = t0.globalIndex(); + candVtx.track1Id = t1.globalIndex(); + candVtx.track2Id = t2.globalIndex(); + candVtx.collisionId = collision.globalIndex(); + candVtx.decay3bodyId = decay3bodyId; + candVtx.vtxPos[0] = pos[0]; + candVtx.vtxPos[1] = pos[1]; + candVtx.vtxPos[2] = pos[2]; + candVtx.track0P[0] = p0[0]; + candVtx.track0P[1] = p0[1]; + candVtx.track0P[2] = p0[2]; + candVtx.track1P[0] = p1[0]; + candVtx.track1P[1] = p1[1]; + candVtx.track1P[2] = p1[2]; + candVtx.track2P[0] = p2[0]; + candVtx.track2P[1] = p2[1]; + candVtx.track2P[2] = p2[2]; + candVtx.dcadaughters = fitter3body.getChi2AtPCACandidate(); + candVtx.daudcaxytopv[0] = Track0dcaXY; + candVtx.daudcaxytopv[1] = Track1dcaXY; + candVtx.daudcaxytopv[2] = Track2dcaXY; + candVtx.daudcatopv[0] = Track0dca; + candVtx.daudcatopv[1] = Track1dca; + candVtx.daudcatopv[2] = Track2dca; + candVtx.bachelortofNsigma = tofNSigmaBach; + if (saveInTable) { + fillVtx3BodyTable(candVtx); + } else { + VtxCandidates.push_back(candVtx); + } + } + //------------------------------------------------------------------ + // event mixing + template + void doMixed3Body(TMixed3bodys decay3bodys, TBinningType binningType) + { + // Strictly upper index policy for decay3body objects binned by radius, phi + for (const auto& [decay3body0, decay3body1] : selfCombinations(binningType, dcaFitterEMSel.nUseMixed, -1, decay3bodys, decay3bodys)) { + auto tpos0 = decay3body0.template track0_as(); + auto tneg0 = decay3body0.template track1_as(); + auto tbach0 = decay3body0.template track2_as(); + auto tpos1 = decay3body1.template track0_as(); + auto tneg1 = decay3body1.template track1_as(); + auto tbach1 = decay3body1.template track2_as(); + + registry.fill(HIST("h3bodyCombinationCounter"), 0.5); + + // ---------- selections ---------- + if ((tbach0.sign() > 0 && !(tbach1.sign() > 0)) || (tbach0.sign() < 0 && !(tbach1.sign() < 0)) || tbach0.globalIndex() == tbach1.globalIndex()) { // only combine if tbach1 has correct sign and is not same as tbach0 continue; } - registry.fill(HIST("hVtx3BodyCounter"), kVtxDcaDau); + registry.fill(HIST("h3bodyCombinationCounter"), 1.5); - float VtxcosPA = RecoDecay::cpa(array{collision.posX(), collision.posY(), collision.posZ()}, array{pos[0], pos[1], pos[2]}, array{p3B[0], p3B[1], p3B[2]}); - if (VtxcosPA < minCosPA3body) { + if (decay3body0.collisionId() == decay3body1.collisionId()) { // only combine if from different event continue; } - registry.fill(HIST("hVtx3BodyCounter"), kVtxCosPA); + registry.fill(HIST("h3bodyCombinationCounter"), 2.5); + + auto c0 = decay3body0.template collision_as(); + auto c1 = decay3body1.template collision_as(); - vtx3bodydata( - t0.globalIndex(), t1.globalIndex(), t2.globalIndex(), collision.globalIndex(), vtx3body.globalIndex(), - pos[0], pos[1], pos[2], - p0[0], p0[1], p0[2], p1[0], p1[1], p1[2], p2[0], p2[1], p2[2], - fitter3body.getChi2AtPCACandidate(), - Track0dcaXY, Track1dcaXY, Track2dcaXY); + if (dcaFitterEMSel.selectPVPosZ3bodyMixing && std::abs(c0.posZ() - c1.posZ()) > dcaFitterEMSel.maxDeltaPVPosZ3bodyMixing) { // only combine if collision similar in PV posZ + continue; + } + registry.fill(HIST("h3bodyCombinationCounter"), 3.5); + + initCCDBfromRunNumber(c0.runNumber()); + + if (dcaFitterEMSel.cfgMix3BodyMethod == 0) { // mix bachelor (deuteron) + fillVtxCand(c0, tpos0, tneg0, tbach1, -1, bachelorcharge, tbach1.tofNSigmaDe()); + fillVtxCand(c1, tpos1, tneg1, tbach0, -1, bachelorcharge, tbach0.tofNSigmaDe()); + } else if ((dcaFitterEMSel.cfgMix3BodyMethod == 1 && tbach0.sign() > 0) || (dcaFitterEMSel.cfgMix3BodyMethod == 2 && tbach0.sign() < 0)) { // mix piMinus or proton + fillVtxCand(c0, tpos0, tneg1, tbach0, -1, bachelorcharge, tbach0.tofNSigmaDe()); + fillVtxCand(c1, tpos1, tneg0, tbach1, -1, bachelorcharge, tbach1.tofNSigmaDe()); + } else if ((dcaFitterEMSel.cfgMix3BodyMethod == 1 && tbach0.sign() < 0) || (dcaFitterEMSel.cfgMix3BodyMethod == 2 && tbach0.sign() > 0)) { // mix piPlus or anti-proton + fillVtxCand(c0, tpos1, tneg0, tbach0, -1, bachelorcharge, tbach0.tofNSigmaDe()); + fillVtxCand(c1, tpos0, tneg1, tbach1, -1, bachelorcharge, tbach1.tofNSigmaDe()); + } + + VtxCandidates.clear(); + } // end decay3body combinations loop + } + //------------------------------------------------------------------ + // fill the StoredVtx3BodyDatas table + void fillVtx3BodyTable(VtxCandidate const& candVtx) + { + vtx3bodydata( + candVtx.track0Id, candVtx.track1Id, candVtx.track2Id, candVtx.collisionId, candVtx.decay3bodyId, + candVtx.vtxPos[0], candVtx.vtxPos[1], candVtx.vtxPos[2], + candVtx.track0P[0], candVtx.track0P[1], candVtx.track0P[2], candVtx.track1P[0], candVtx.track1P[1], candVtx.track1P[2], candVtx.track2P[0], candVtx.track2P[1], candVtx.track2P[2], + candVtx.dcadaughters, + candVtx.daudcaxytopv[0], candVtx.daudcaxytopv[1], candVtx.daudcaxytopv[2], + candVtx.daudcatopv[0], candVtx.daudcatopv[1], candVtx.daudcatopv[2], + candVtx.bachelortofNsigma); + } + + //------------------------------------------------------------------ + //-------------------- KFParticle reconstruction ------------------- + //------------------------------------------------------------------ + // function to select daughter track PID + template + bool selectTPCPID(TTrack const& trackProton, TTrack const& trackPion, TTrack const& trackDeuteron) + { + if (std::abs(trackProton.tpcNSigmaPr()) > kfparticleConfigurations.maxtpcnSigma) { + return false; + } + if (std::abs(trackDeuteron.tpcNSigmaDe()) > kfparticleConfigurations.maxtpcnSigma) { + return false; + } + if (kfparticleConfigurations.useTPCforPion && std::abs(trackPion.tpcNSigmaPi()) > kfparticleConfigurations.maxtpcnSigma) { + return false; + } + return true; + } + + template + double getTOFnSigma(TCollision const& collision, TTrack const& track, bool isEventMixing) + { + // TOF PID of deuteron (set motherhyp correctly) + double tofNSigmaDeuteron = -999; + if (track.has_collision() && track.hasTOF()) { + if (isEventMixing) { + tofNSigmaDeuteron = bachelorTOFPID.GetTOFNSigma(track, collision, collision); + } else { + auto originalcol = track.template collision_as(); + tofNSigmaDeuteron = bachelorTOFPID.GetTOFNSigma(track, originalcol, collision); + } } + return tofNSigmaDeuteron; } //------------------------------------------------------------------ - void process(aod::Collision const& collision, FullTracksExtIU const& tracks, aod::Decay3Bodys const& decay3bodys, aod::BCsWithTimestamps const&) + // function to fill candidate table + template + void fillCandidateTable(TCandidate const& candidate) { - auto bc = collision.bc_as(); - initCCDB(bc); - registry.fill(HIST("hEventCounter"), 0.5); + kfvtx3bodydatalite( + // hypertriton + candidate.mass, + candidate.pos[0], candidate.pos[1], candidate.pos[2], + candidate.mom[0], candidate.mom[1], candidate.mom[2], candidate.mom[3], + candidate.charge, + candidate.dcaToPV[0], candidate.dcaToPV[1], // 3D, xy + candidate.cpaToPV[0], candidate.cpaToPV[1], // 3D, xy + candidate.decLen[0], candidate.decLen[1], // 3D, xy + candidate.ldl, + candidate.chi2geoNDF, candidate.chi2topoNDF, + candidate.ctau, + candidate.trackedClSize, + // V0 + candidate.massV0, + candidate.cpaV0ToPV, + // daughter momenta at vertex + candidate.protonMom[0], candidate.protonMom[1], candidate.protonMom[2], + candidate.pionMom[0], candidate.pionMom[1], candidate.pionMom[2], + candidate.deuteronMom[0], candidate.deuteronMom[1], candidate.deuteronMom[2], + candidate.tpcInnerParam[0], candidate.tpcInnerParam[1], candidate.tpcInnerParam[2], // proton, pion, deuteron + // daughter track quality + candidate.tpcNClDaughters[0], candidate.tpcNClDaughters[1], candidate.tpcNClDaughters[2], // proton, pion, deuteron + candidate.tpcChi2NClDeuteron, + candidate.DeltaPhiRotDeuteron, candidate.DeltaPhiRotProton, + // daughter DCAs KF + candidate.DCAdaughterToPV[0], candidate.DCAdaughterToPV[1], candidate.DCAdaughterToPV[2], // proton, pion, deuteron + candidate.DCAdaughterToPVxy[0], candidate.DCAdaughterToPVxy[1], candidate.DCAdaughterToPVxy[2], // proton, pion, deuteron + candidate.DCAdaughterToSVxy[0], candidate.DCAdaughterToSVxy[1], candidate.DCAdaughterToSVxy[2], // proton, pion, deuteron + candidate.DCAprotonToPion, candidate.DCAprotonToDeuteron, candidate.DCApionToDeuteron, + candidate.DCAvtxDaughters3D, + // daughter signs + candidate.daughterCharge[0], candidate.daughterCharge[1], candidate.daughterCharge[2], // proton, pion, deuteron + // daughter PID + candidate.tpcNsigma[0], candidate.tpcNsigma[1], candidate.tpcNsigma[2], candidate.tpcNsigma[3], // proton, pion, deuteron, bach with pion hyp + candidate.tofNsigmaDeuteron, + candidate.averageClusterSizeDeuteron, + candidate.pidForTrackingDeuteron); + + if (kfparticleConfigurations.fillCandidateFullTable) { + kfvtx3bodydata( + candidate.collisionID, candidate.trackPosID, candidate.trackNegID, candidate.trackBachID, candidate.decay3bodyID, + // hypertriton + candidate.mass, + candidate.pos[0], candidate.pos[1], candidate.pos[2], + candidate.posErr[0], candidate.posErr[1], candidate.posErr[2], + candidate.mom[0], candidate.mom[1], candidate.mom[2], candidate.mom[3], + candidate.momErr[0], candidate.momErr[1], candidate.momErr[2], candidate.momErr[3], + candidate.charge, + candidate.dcaToPV[0], candidate.dcaToPV[1], // 3D, xy + candidate.cpaToPV[0], candidate.cpaToPV[1], // 3D, xy + candidate.cpaToPVtopo[0], candidate.cpaToPVtopo[1], // 3D, xy + candidate.decLen[0], candidate.decLen[1], // 3D, xy + candidate.ldl, + candidate.chi2geoNDF, candidate.chi2topoNDF, + candidate.ctau, + candidate.trackedClSize, + // V0 + candidate.massV0, candidate.chi2massV0, + candidate.cpaV0ToPV, + // daughter momenta (at vertex and TPC) + candidate.protonMom[0], candidate.protonMom[1], candidate.protonMom[2], + candidate.pionMom[0], candidate.pionMom[1], candidate.pionMom[2], + candidate.deuteronMom[0], candidate.deuteronMom[1], candidate.deuteronMom[2], + candidate.tpcInnerParam[0], candidate.tpcInnerParam[1], candidate.tpcInnerParam[2], // proton, pion, deuteron + // daughter track quality + candidate.tpcNClDaughters[0], candidate.tpcNClDaughters[1], candidate.tpcNClDaughters[2], // proton, pion, deuteron + candidate.tpcChi2NClDeuteron, + candidate.DeltaPhiRotDeuteron, candidate.DeltaPhiRotProton, + // daughter DCAs KF + candidate.DCAdaughterToPV[0], candidate.DCAdaughterToPV[1], candidate.DCAdaughterToPV[2], // proton, pion, deuteron + candidate.DCAdaughterToPVxy[0], candidate.DCAdaughterToPVxy[1], candidate.DCAdaughterToPVxy[2], // proton, pion, deuteron + candidate.DCAdaughterToSVxy[0], candidate.DCAdaughterToSVxy[1], candidate.DCAdaughterToSVxy[2], // proton, pion, deuteron + candidate.DCAprotonToPion, candidate.DCAprotonToDeuteron, candidate.DCApionToDeuteron, + candidate.DCAvtxDaughters3D, + // daughter DCAs to PV propagated with material + candidate.trackDCAxy[0], candidate.trackDCAxy[1], candidate.trackDCAxy[2], // pos, neg, bach + candidate.trackDCA[0], candidate.trackDCA[1], candidate.trackDCA[2], // pos, neg, bach + // daughter signs + candidate.daughterCharge[0], candidate.daughterCharge[1], candidate.daughterCharge[2], // proton, pion, deuteron + // daughter PID + candidate.tpcNsigma[0], candidate.tpcNsigma[1], candidate.tpcNsigma[2], candidate.tpcNsigma[3], // proton, pion, deuteron, bach with pion hyp + candidate.tpcdEdx[0], candidate.tpcdEdx[1], candidate.tpcdEdx[2], // proton, pion, deuteron + candidate.tofNsigmaDeuteron, + candidate.averageClusterSizeDeuteron, + candidate.pidForTrackingDeuteron); + } + LOG(debug) << "Table filled."; + } - buildVtx3BodyDataTable(collision, tracks, decay3bodys, bachelorcharge); + //------------------------------------------------------------------ + // function to fit KFParticle 3body vertex + template + void fit3bodyVertex(TKFParticle& kfpProton, TKFParticle& kfpPion, TKFParticle& kfpDeuteron, TKFParticle& KFHt) + { + // Construct 3body vertex + int nDaughters3body = 3; + const KFParticle* Daughters3body[3] = {&kfpProton, &kfpPion, &kfpDeuteron}; + KFHt.SetConstructMethod(2); + try { + KFHt.Construct(Daughters3body, nDaughters3body); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to create Hyper triton 3-body vertex." << e.what(); + return; + } + // transport all daughter tracks to hypertriton vertex + float HtVtx[3] = {0.}; + HtVtx[0] = KFHt.GetX(); + HtVtx[1] = KFHt.GetY(); + HtVtx[2] = KFHt.GetZ(); + kfpProton.TransportToPoint(HtVtx); + kfpPion.TransportToPoint(HtVtx); + kfpDeuteron.TransportToPoint(HtVtx); + LOG(debug) << "Hypertriton vertex constructed."; } + + //------------------------------------------------------------------ + // 3body candidate builder with KFParticle + template + void buildVtx3BodyDataTableKFParticle(TCollision const& collision, TTrack const& trackPos, TTrack const& trackNeg, TTrack const& trackBach, int64_t decay3bodyID, int bachelorcharge, double tofNSigmaDeuteron) + { + gROOT->SetBatch(true); + gRandom->SetSeed(42); + + // initialise KF primary vertex + KFPVertex kfpVertex = createKFPVertexFromCollision(collision); + KFParticle kfpv(kfpVertex); + LOG(debug) << "Created KF PV."; + + // fill event QA histograms --> only for events with a decay3body! + if (kfparticleConfigurations.doVertexQA) { + registry.fill(HIST("QA/Event/hVtxXKF"), kfpv.GetX()); + registry.fill(HIST("QA/Event/hVtxYKF"), kfpv.GetY()); + registry.fill(HIST("QA/Event/hVtxZKF"), kfpv.GetZ()); + registry.fill(HIST("QA/Event/hVtxCovXXKF"), kfpv.GetCovariance(0)); + registry.fill(HIST("QA/Event/hVtxCovYYKF"), kfpv.GetCovariance(2)); + registry.fill(HIST("QA/Event/hVtxCovZZKF"), kfpv.GetCovariance(5)); + registry.fill(HIST("QA/Event/hVtxCovXYKF"), kfpv.GetCovariance(1)); + registry.fill(HIST("QA/Event/hVtxCovXZKF"), kfpv.GetCovariance(3)); + registry.fill(HIST("QA/Event/hVtxCovYZKF"), kfpv.GetCovariance(4)); + registry.fill(HIST("QA/Event/hVtxX"), collision.posX()); + registry.fill(HIST("QA/Event/hVtxY"), collision.posY()); + registry.fill(HIST("QA/Event/hVtxZ"), collision.posZ()); + registry.fill(HIST("QA/Event/hVtxCovXX"), collision.covXX()); + registry.fill(HIST("QA/Event/hVtxCovYY"), collision.covYY()); + registry.fill(HIST("QA/Event/hVtxCovZZ"), collision.covZZ()); + registry.fill(HIST("QA/Event/hVtxCovXY"), collision.covXY()); + registry.fill(HIST("QA/Event/hVtxCovXZ"), collision.covXZ()); + registry.fill(HIST("QA/Event/hVtxCovYZ"), collision.covYZ()); + } + + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxAll); + + auto trackParCovPos = getTrackParCov(trackPos); + auto trackParCovNeg = getTrackParCov(trackNeg); + auto trackParCovBach = getTrackParCov(trackBach); + LOG(debug) << "Got all daughter tracks."; + + bool isMatter = trackBach.sign() > 0 ? true : false; + + // ---------- fill track QA histograms ---------- + if (kfparticleConfigurations.doTrackQA) { + registry.fill(HIST("QA/Tracks/hTrackPosTPCNcls"), trackPos.tpcNClsFound()); + registry.fill(HIST("QA/Tracks/hTrackNegTPCNcls"), trackNeg.tpcNClsFound()); + registry.fill(HIST("QA/Tracks/hTrackBachTPCNcls"), trackBach.tpcNClsFound()); + registry.fill(HIST("QA/Tracks/hTrackPosHasTPC"), trackPos.hasTPC()); + registry.fill(HIST("QA/Tracks/hTrackNegHasTPC"), trackNeg.hasTPC()); + registry.fill(HIST("QA/Tracks/hTrackBachHasTPC"), trackBach.hasTPC()); + registry.fill(HIST("QA/Tracks/hTrackBachITSClusSizes"), trackBach.itsClusterSizes()); + if (isMatter) { + registry.fill(HIST("QA/Tracks/hTrackProtonTPCPID"), trackPos.sign() * trackPos.tpcInnerParam(), trackPos.tpcNSigmaPr()); + registry.fill(HIST("QA/Tracks/hTrackPionTPCPID"), trackNeg.sign() * trackNeg.tpcInnerParam(), trackNeg.tpcNSigmaPi()); + registry.fill(HIST("QA/Tracks/hTrackProtonPt"), trackPos.pt()); + registry.fill(HIST("QA/Tracks/hTrackPionPt"), trackNeg.pt()); + } else { + registry.fill(HIST("QA/Tracks/hTrackProtonTPCPID"), trackNeg.sign() * trackNeg.tpcInnerParam(), trackNeg.tpcNSigmaPr()); + registry.fill(HIST("QA/Tracks/hTrackPionTPCPID"), trackPos.sign() * trackPos.tpcInnerParam(), trackPos.tpcNSigmaPi()); + registry.fill(HIST("QA/Tracks/hTrackProtonPt"), trackNeg.pt()); + registry.fill(HIST("QA/Tracks/hTrackPionPt"), trackPos.pt()); + } + registry.fill(HIST("QA/Tracks/hTrackBachTPCPID"), trackBach.sign() * trackBach.tpcInnerParam(), trackBach.tpcNSigmaDe()); + registry.fill(HIST("QA/Tracks/hTrackBachPt"), trackBach.pt()); + } + + // -------- STEP 1: track selection -------- + // collision ID --> not correct? tracks can have different collisions, but belong to one 3prong vertex! + // if (trackPos.collisionId() != trackNeg.collisionId() || trackPos.collisionId() != trackBach.collisionId() || trackNeg.collisionId() != trackBach.collisionId()) { + // continue; + // } + // track IDs --> already checked in SVertexer! + + // track signs (pos, neg, bach) --> sanity check, should already be in SVertexer + if (trackPos.sign() != +1 || trackNeg.sign() != -1) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxCharge); + + // track eta + if (std::abs(trackPos.eta()) > kfparticleConfigurations.maxEta || std::abs(trackNeg.eta()) > kfparticleConfigurations.maxEta || std::abs(trackBach.eta()) > kfparticleConfigurations.maxEtaDeuteron) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxEta); + + // number of TPC clusters + if (trackBach.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsBach) { + return; + } + if (isMatter && ((kfparticleConfigurations.useTPCforPion && trackNeg.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsPion) || trackPos.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsProton)) { + return; + } else if (!isMatter && ((kfparticleConfigurations.useTPCforPion && trackPos.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsPion) || trackNeg.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsProton)) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxTPCNcls); + + // number of TPC crossed rows + if (trackBach.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRows) { + return; + } + if (isMatter && ((kfparticleConfigurations.useTPCforPion && trackNeg.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRowsPion) || trackPos.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRows)) { + return; + } else if (!isMatter && ((kfparticleConfigurations.useTPCforPion && trackPos.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRowsPion) || trackNeg.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRows)) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxTPCRows); + + // TPC PID + float tpcNsigmaProton; + float tpcNsigmaPion; + float dEdxProton; + float dEdxPion; + float tpcNsigmaDeuteron = trackBach.tpcNSigmaDe(); + float tpcNsigmaPionBach = trackBach.tpcNSigmaPi(); + float dEdxDeuteron = trackBach.tpcSignal(); + if (isMatter) { // hypertriton (proton, pi-, deuteron) + tpcNsigmaProton = trackPos.tpcNSigmaPr(); + tpcNsigmaPion = trackNeg.tpcNSigmaPi(); + dEdxProton = trackPos.tpcSignal(); + dEdxPion = trackNeg.tpcSignal(); + if (!selectTPCPID(trackPos, trackNeg, trackBach)) { + return; + } + } else if (!isMatter) { // anti-hypertriton (anti-proton, pi+, deuteron) + tpcNsigmaProton = trackNeg.tpcNSigmaPr(); + tpcNsigmaPion = trackPos.tpcNSigmaPi(); + dEdxProton = trackNeg.tpcSignal(); + dEdxPion = trackPos.tpcSignal(); + if (!selectTPCPID(trackNeg, trackPos, trackBach)) { + return; + } + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxTPCPID); + LOG(debug) << "Basic track selections done."; + + // Average ITS cluster size of deuteron track + double averageClusterSizeDeuteron(0); + int nCls(0); + for (int i = 0; i < 7; i++) { + int clusterSize = trackBach.itsClsSizeInLayer(i); + averageClusterSizeDeuteron += static_cast(clusterSize); + if (clusterSize > 0) + nCls++; + } + averageClusterSizeDeuteron = averageClusterSizeDeuteron / static_cast(nCls); + + // track DCAxy and DCAz to PV associated with decay3body + o2::dataformats::VertexBase mPV; + o2::dataformats::DCA mDcaInfoCovPos; + o2::dataformats::DCA mDcaInfoCovNeg; + o2::dataformats::DCA mDcaInfoCovBach; + auto trackParCovPVPos = trackParCovPos; + auto trackParCovPVNeg = trackParCovNeg; + auto trackParCovPVBach = trackParCovBach; + mPV.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mPV.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPVPos, 2.f, matCorr, &mDcaInfoCovPos); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPVNeg, 2.f, matCorr, &mDcaInfoCovNeg); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPVBach, 2.f, matCorr, &mDcaInfoCovBach); + auto TrackPosDcaXY = mDcaInfoCovPos.getY(); + auto TrackNegDcaXY = mDcaInfoCovNeg.getY(); + auto TrackBachDcaXY = mDcaInfoCovBach.getY(); + auto TrackPosDcaZ = mDcaInfoCovPos.getZ(); + auto TrackNegDcaZ = mDcaInfoCovNeg.getZ(); + auto TrackBachDcaZ = mDcaInfoCovBach.getZ(); + // calculate 3D track DCA + auto TrackPosDca = std::sqrt(TrackPosDcaXY * TrackPosDcaXY + TrackPosDcaZ * TrackPosDcaZ); + auto TrackNegDca = std::sqrt(TrackNegDcaXY * TrackNegDcaXY + TrackNegDcaZ * TrackNegDcaZ); + auto TrackBachDca = std::sqrt(TrackBachDcaXY * TrackBachDcaXY + TrackBachDcaZ * TrackBachDcaZ); + // selection + if (kfparticleConfigurations.doDCAPreSel && isMatter && (std::fabs(TrackNegDcaXY) <= kfparticleConfigurations.mindcaXYPionPV || std::fabs(TrackPosDcaXY) <= kfparticleConfigurations.mindcaXYProtonPV)) { + return; + } else if (kfparticleConfigurations.doDCAPreSel && !isMatter && (std::fabs(TrackPosDcaXY) <= kfparticleConfigurations.mindcaXYPionPV || std::fabs(TrackNegDcaXY) <= kfparticleConfigurations.mindcaXYProtonPV)) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDCAxyPV); + if (kfparticleConfigurations.doDCAPreSel && isMatter && (std::fabs(TrackNegDcaZ) <= kfparticleConfigurations.mindcaZPionPV || std::fabs(TrackPosDcaZ) <= kfparticleConfigurations.mindcaZProtonPV)) { + return; + } else if (kfparticleConfigurations.doDCAPreSel && !isMatter && (std::fabs(TrackPosDcaZ) <= kfparticleConfigurations.mindcaZPionPV || std::fabs(TrackNegDcaZ) <= kfparticleConfigurations.mindcaZProtonPV)) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDCAzPV); + + // daughter track momentum at inner wall of TPC + float tpcInnerParamProton; + float tpcInnerParamPion; + float tpcInnerParamDeuteron = trackBach.tpcInnerParam(); + if (isMatter) { // hypertriton (proton, pi-, deuteron) + tpcInnerParamProton = trackPos.tpcInnerParam(); + tpcInnerParamPion = trackNeg.tpcInnerParam(); + } else if (!isMatter) { // anti-hypertriton (anti-proton, pi+, deuteron) + tpcInnerParamProton = trackNeg.tpcInnerParam(); + tpcInnerParamPion = trackPos.tpcInnerParam(); + } + + // -------- STEP 2: fit vertex with proton and pion -------- + // Fit vertex with DCA fitter to find minimization point --> uses material corrections implicitly + if (kfparticleConfigurations.doDCAFitterPreMinimum) { + try { + fitter3body.process(trackParCovPos, trackParCovNeg, trackParCovBach); + } catch (std::runtime_error& e) { + LOG(error) << "Exception caught in DCA fitter process call: Not able to fit decay3body vertex!"; + return; + } + // re-acquire tracks at vertex position from DCA fitter + trackParCovPos = fitter3body.getTrack(0); + trackParCovNeg = fitter3body.getTrack(1); + trackParCovBach = fitter3body.getTrack(2); + + LOG(debug) << "Minimum found with DCA fitter for decay3body."; + } + + // create KFParticle objects from tracks + KFParticle kfpProton, kfpPion; + if (isMatter) { + kfpProton = createKFParticleFromTrackParCov(trackParCovPos, trackPos.sign(), constants::physics::MassProton); + kfpPion = createKFParticleFromTrackParCov(trackParCovNeg, trackNeg.sign(), constants::physics::MassPionCharged); + } else if (!isMatter) { + kfpProton = createKFParticleFromTrackParCov(trackParCovNeg, trackNeg.sign(), constants::physics::MassProton); + kfpPion = createKFParticleFromTrackParCov(trackParCovPos, trackPos.sign(), constants::physics::MassPionCharged); + } + LOG(debug) << "KFParticle objects created from daughter tracks."; + + // Construct V0 as intermediate step + KFParticle KFV0; + int nDaughtersV0 = 2; + const KFParticle* DaughtersV0[2] = {&kfpProton, &kfpPion}; + KFV0.SetConstructMethod(2); + try { + KFV0.Construct(DaughtersV0, nDaughtersV0); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to create V0 vertex from daughter tracks." << e.what(); + return; + } + KFV0.TransportToDecayVertex(); + LOG(debug) << "V0 constructed."; + + // check V0 mass and set mass constraint + float massV0, sigmaMassV0; + KFV0.GetMass(massV0, sigmaMassV0); + KFParticle KFV0Mass = KFV0; + KFV0Mass.SetNonlinearMassConstraint(o2::constants::physics::MassLambda); + float chi2massV0 = KFV0Mass.GetChi2() / KFV0Mass.GetNDF(); + if (kfparticleConfigurations.useLambdaMassConstraint) { + LOG(debug) << "V0 mass constraint applied."; + KFV0 = KFV0Mass; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxV0MassConst); + + // apply virtual V0 cuts used in SVertexer in case of 3body mixing with proton track + if (kfparticleConfigurations.mixingType == 1 && kfparticleConfigurations.applySVertexerV0Cuts) { + // V0 radius + if (std::sqrt(KFV0.GetX() * KFV0.GetX() + KFV0.GetY() * KFV0.GetY()) <= 0.5) { + return; + } + // pT + if (KFV0.GetPt() <= 0.01) { + return; + } + // pz/pT + if (KFV0.GetPz() / KFV0.GetPt() >= 2) { + return; + } + // cos(PA) + if (cpaXYFromKF(KFV0, kfpv) <= 0.9 || cpaFromKF(KFV0, kfpv) <= 0.8) { + return; + } + } + + // -------- STEP 3: fit three body vertex -------- + // Create KFParticle object from deuteron track + KFParticle kfpDeuteron; + kfpDeuteron = createKFParticleFromTrackParCov(trackParCovBach, trackBach.sign() * bachelorcharge, constants::physics::MassDeuteron); + LOG(debug) << "KFParticle created from deuteron track."; + + // Construct vertex + KFParticle KFHt; + fit3bodyVertex(kfpProton, kfpPion, kfpDeuteron, KFHt); + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxhasSV); + + // -------- STEP 4: daughter selections after geometrical vertex fit -------- + // daughter DCAs with KF + if ((kfpProton.GetDistanceFromParticle(kfpPion) >= kfparticleConfigurations.maxDcaProPi) || (kfpProton.GetDistanceFromParticle(kfpDeuteron) >= kfparticleConfigurations.maxDcaProDeu) || (kfpPion.GetDistanceFromParticle(kfpDeuteron) >= kfparticleConfigurations.maxDcaPiDe)) { + return; + } + float DCAvtxDaughters3D = kfpProton.GetDistanceFromParticle(kfpPion) + kfpProton.GetDistanceFromParticle(kfpDeuteron) + kfpPion.GetDistanceFromParticle(kfpDeuteron); + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDcaDau); + LOG(debug) << "DCA selection after vertex fit applied."; + + // daughter DCAs to vertex + if (kfpProton.GetDistanceFromVertexXY(KFHt) >= kfparticleConfigurations.maxDcaXYSVDau || kfpPion.GetDistanceFromVertexXY(KFHt) >= kfparticleConfigurations.maxDcaXYSVDau || kfpDeuteron.GetDistanceFromVertexXY(KFHt) >= kfparticleConfigurations.maxDcaXYSVDau) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDcaDauVtx); + LOG(debug) << "DCA to vertex selection after vertex fit applied."; + + // daughter pT + if (kfpProton.GetPt() < kfparticleConfigurations.minPtProton || kfpProton.GetPt() > kfparticleConfigurations.maxPtProton || kfpPion.GetPt() < kfparticleConfigurations.minPtPion || kfpPion.GetPt() > kfparticleConfigurations.maxPtPion || kfpDeuteron.GetPt() < kfparticleConfigurations.minPtDeuteron || kfpDeuteron.GetPt() > kfparticleConfigurations.maxPtDeuteron) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxDauPt); + LOG(debug) << "Daughter pT selection applied."; + + // -------- STEP 5: candidate selection and constraint after geometrical vertex fit -------- + // Rapidity + float rapHt = RecoDecay::y(std::array{KFHt.GetPx(), KFHt.GetPy(), KFHt.GetPz()}, o2::constants::physics::MassHyperTriton); + if (std::abs(rapHt) > kfparticleConfigurations.maxRapidityHt) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxRap); + + // Pt selection + if (KFHt.GetPt() <= kfparticleConfigurations.minPtHt || KFHt.GetPt() >= kfparticleConfigurations.maxPtHt) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxPt); + + // Mass window + float massHt, sigmaMassHt; + KFHt.GetMass(massHt, sigmaMassHt); + if (massHt <= kfparticleConfigurations.minMassHt || massHt >= kfparticleConfigurations.maxMassHt) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxMass); + + // cos(PA) to PV + if (std::abs(cpaFromKF(KFHt, kfpv)) <= kfparticleConfigurations.minCosPA) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxCosPA); + + // cos(PA) xy to PV + if (std::abs(cpaXYFromKF(KFHt, kfpv)) <= kfparticleConfigurations.minCosPAxy) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxCosPAXY); + + // chi2 geometrical + float chi2geoNDF = KFHt.GetChi2() / KFHt.GetNDF(); + if (kfparticleConfigurations.applyTopoSel && chi2geoNDF >= kfparticleConfigurations.maxChi2geo) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxChi2geo); + LOG(debug) << "Basic selections after vertex fit done."; + + // ctau before topo constraint + if (KFHt.GetLifeTime() > kfparticleConfigurations.maxctauHt) { + return; + } + + // Set vertex constraint and topological selection + KFParticle KFHtPV = KFHt; + try { + KFHtPV.SetProductionVertex(kfpv); + } catch (std::runtime_error& e) { + LOG(error) << "Exception caught KFParticle process call: Topological constraint failed"; + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxTopoConstr); // to check if topo constraint fails + // get topological chi2 + float chi2topoNDF = KFHtPV.GetChi2() / KFHtPV.GetNDF(); + KFHtPV.TransportToDecayVertex(); + if (kfparticleConfigurations.applyTopoSel && chi2topoNDF >= kfparticleConfigurations.maxChi2topo) { + return; + } + registry.fill(HIST("Counters/hVtx3BodyCounterKFParticle"), kKfVtxChi2topo); + + // -------- STEP 6: collect and fill candidate info -------- + // get cluster size of strangeness tracked 3bodies + float trackedClSize; + if (decay3bodyID == -1) { + trackedClSize = 0; + } else { + trackedClSize = !fTrackedClSizeVector.empty() ? fTrackedClSizeVector[decay3bodyID] : 0; + } + + // candidate filling + kfCandidate candidate; + candidate.collisionID = collision.globalIndex(); + candidate.trackPosID = trackPos.globalIndex(); + candidate.trackNegID = trackNeg.globalIndex(); + candidate.trackBachID = trackBach.globalIndex(); + candidate.decay3bodyID = decay3bodyID; + // hypertriton + candidate.mass = massHt; + candidate.pos[0] = KFHt.GetX(); + candidate.pos[1] = KFHt.GetY(); + candidate.pos[2] = KFHt.GetZ(); + candidate.posErr[0] = KFHt.GetErrX(); + candidate.posErr[1] = KFHt.GetErrY(); + candidate.posErr[2] = KFHt.GetErrZ(); + candidate.mom[0] = KFHt.GetPx(); + candidate.mom[1] = KFHt.GetPy(); + candidate.mom[2] = KFHt.GetPz(); + candidate.mom[3] = KFHt.GetPt(); + candidate.momErr[0] = KFHt.GetErrPx(); + candidate.momErr[1] = KFHt.GetErrPy(); + candidate.momErr[2] = KFHt.GetErrPz(); + candidate.momErr[3] = KFHt.GetErrPt(); + candidate.charge = KFHt.GetQ(); + candidate.dcaToPV[0] = KFHt.GetDistanceFromVertex(kfpv); + candidate.dcaToPV[1] = KFHt.GetDistanceFromVertexXY(kfpv); + candidate.cpaToPV[0] = cpaFromKF(KFHt, kfpv); + candidate.cpaToPV[1] = cpaXYFromKF(KFHt, kfpv); + candidate.cpaToPVtopo[0] = cpaFromKF(KFHtPV, kfpv); + candidate.cpaToPVtopo[1] = cpaXYFromKF(KFHtPV, kfpv); + candidate.decLen[0] = KFHtPV.GetDecayLength(); + candidate.decLen[1] = KFHtPV.GetDecayLengthXY(); + candidate.ldl = KFHtPV.GetDecayLength() / KFHtPV.GetErrDecayLength(); + candidate.chi2geoNDF = chi2geoNDF; + candidate.chi2topoNDF = chi2topoNDF; + candidate.ctau = KFHtPV.GetLifeTime(); + candidate.trackedClSize = trackedClSize; + // V0 + candidate.massV0 = massV0; + candidate.chi2massV0 = chi2massV0; + candidate.cpaV0ToPV = cpaFromKF(KFV0, kfpv); + // daughter momenta + candidate.protonMom[0] = kfpProton.GetPx(); + candidate.protonMom[1] = kfpProton.GetPy(); + candidate.protonMom[2] = kfpProton.GetPz(); + candidate.pionMom[0] = kfpPion.GetPx(); + candidate.pionMom[1] = kfpPion.GetPy(); + candidate.pionMom[2] = kfpPion.GetPz(); + candidate.deuteronMom[0] = kfpDeuteron.GetPx(); + candidate.deuteronMom[1] = kfpDeuteron.GetPy(); + candidate.deuteronMom[2] = kfpDeuteron.GetPz(); + candidate.tpcInnerParam[0] = tpcInnerParamProton; + candidate.tpcInnerParam[1] = tpcInnerParamPion; + candidate.tpcInnerParam[2] = tpcInnerParamDeuteron; + // daughter DCAs with KF + candidate.DCAdaughterToPV[0] = kfpProton.GetDistanceFromVertex(kfpv); + candidate.DCAdaughterToPV[1] = kfpPion.GetDistanceFromVertex(kfpv); + candidate.DCAdaughterToPV[2] = kfpDeuteron.GetDistanceFromVertex(kfpv); + candidate.DCAdaughterToPVxy[0] = kfpProton.GetDistanceFromVertexXY(kfpv); + candidate.DCAdaughterToPVxy[1] = kfpPion.GetDistanceFromVertexXY(kfpv); + candidate.DCAdaughterToPVxy[2] = kfpDeuteron.GetDistanceFromVertexXY(kfpv); + candidate.DCAdaughterToSVxy[0] = kfpProton.GetDistanceFromVertexXY(KFHt); + candidate.DCAdaughterToSVxy[1] = kfpPion.GetDistanceFromVertexXY(KFHt); + candidate.DCAdaughterToSVxy[2] = kfpDeuteron.GetDistanceFromVertexXY(KFHt); + candidate.DCAprotonToPion = kfpProton.GetDistanceFromParticle(kfpPion); + candidate.DCAprotonToDeuteron = kfpProton.GetDistanceFromParticle(kfpDeuteron); + candidate.DCApionToDeuteron = kfpPion.GetDistanceFromParticle(kfpDeuteron); + candidate.DCAvtxDaughters3D = DCAvtxDaughters3D; + // daughter DCAs with material corrections + candidate.trackDCAxy[0] = TrackPosDcaXY; + candidate.trackDCAxy[1] = TrackNegDcaXY; + candidate.trackDCAxy[2] = TrackBachDcaXY; + candidate.trackDCA[0] = TrackPosDca; + candidate.trackDCA[1] = TrackNegDca; + candidate.trackDCA[2] = TrackBachDca; + // daughter signs + candidate.daughterCharge[0] = kfpProton.GetQ(); + candidate.daughterCharge[1] = kfpPion.GetQ(); + candidate.daughterCharge[2] = trackBach.sign(); + // daughter PID + candidate.tpcNsigma[0] = tpcNsigmaProton; + candidate.tpcNsigma[1] = tpcNsigmaPion; + candidate.tpcNsigma[2] = tpcNsigmaDeuteron; + candidate.tpcNsigma[3] = tpcNsigmaPionBach; + candidate.tpcdEdx[0] = dEdxProton; + candidate.tpcdEdx[1] = dEdxPion; + candidate.tpcdEdx[2] = dEdxDeuteron; + candidate.tofNsigmaDeuteron = tofNSigmaDeuteron; + candidate.averageClusterSizeDeuteron = averageClusterSizeDeuteron; + candidate.pidForTrackingDeuteron = trackBach.pidForTracking(); + + //------------------------------------------------------------------ + // table filling + fillCandidateTable(candidate); + LOG(debug) << "Table filled."; + + // fill event counter hist (has selected candidate) --> only filled once per vertex + registry.fill(HIST("Counters/hEventCounterKFParticle"), 3.5); + } // end buildVtx3BodyDataTableKFParticle + + //------------------------------------------------------------------ + void processRun3(ColwithEvTimes const& collisions, aod::Decay3Bodys const& decay3bodys, TrackExtPIDIUwithEvTimes const&, aod::BCsWithTimestamps const&) + { + VtxCandidates.clear(); + + registry.fill(HIST("hEventCounter"), 0.5, collisions.size()); + + for (const auto& d3body : decay3bodys) { + auto t0 = d3body.track0_as(); + auto t1 = d3body.track1_as(); + auto t2 = d3body.track2_as(); + auto collision = d3body.collision_as(); + auto bc = collision.bc_as(); + initCCDB(bc); + + // Recalculate the TOF PID + double tofNSigmaBach = -999; + if (t2.has_collision() && t2.hasTOF()) { + auto originalcol = t2.template collision_as(); + tofNSigmaBach = bachelorTOFPID.GetTOFNSigma(t2, originalcol, collision); + } + + fillVtxCand(collision, t0, t1, t2, d3body.globalIndex(), bachelorcharge, tofNSigmaBach); + } + } + PROCESS_SWITCH(decay3bodyBuilder, processRun3, "Produce DCA fitter decay3body tables", true); + + //------------------------------------------------------------------ + void processRun3Reduced(aod::RedCollisions const& collisions, aod::RedDecay3Bodys const& decay3bodys, aod::RedIUTracks const&) + { + VtxCandidates.clear(); + + registry.fill(HIST("hEventCounter"), 0.5, collisions.size()); + + for (const auto& d3body : decay3bodys) { + auto t0 = d3body.track0_as(); + auto t1 = d3body.track1_as(); + auto t2 = d3body.track2_as(); + auto collision = d3body.collision_as(); + + initCCDBfromRunNumber(collision.runNumber()); + fillVtxCand(collision, t0, t1, t2, d3body.globalIndex(), bachelorcharge, t2.tofNSigmaDe()); + } + } + PROCESS_SWITCH(decay3bodyBuilder, processRun3Reduced, "Produce DCA fitter decay3body tables with reduced data", false); + + //------------------------------------------------------------------ + // Event-mixing background + void processRun3ReducedEM(ReducedCollisionsMultsCents const& collisions, aod::RedDecay3Bodys const& decay3bodys, aod::RedIUTracks const&) + { + auto xAxis = registry.get(HIST("hEventPairs"))->GetXaxis(); + auto yAxis = registry.get(HIST("hEventPairs"))->GetYaxis(); + + // fill collisions counter + for (const auto& collision : collisions) { + int bin_PosZ = xAxis->FindBin(collision.posZ()); + int bin_Mult = yAxis->FindBin(collision.multNTracksPV()); + registry.fill(HIST("hEventCount"), xAxis->GetBinCenter(bin_PosZ), yAxis->GetBinCenter(bin_Mult)); + } + VtxCandidates.clear(); + + auto tuple = std::make_tuple(decay3bodys); + BinningTypeColEM binningEvent{{dcaFitterEMSel.binsVtxZ, dcaFitterEMSel.binsMultiplicity}, true}; + SameKindPair pair{binningEvent, dcaFitterEMSel.nUseMixed, -1, collisions, tuple, &cache}; + + for (const auto& [c0, decay3bodys0, c1, decay3bodys1] : pair) { + // LOG(info) << "Processing event mixing with collisions " << c0.globalIndex() << " and " << c1.globalIndex(); + initCCDBfromRunNumber(c0.runNumber()); + + int bin_PosZ = xAxis->FindBin(c0.posZ()); + int bin_Mult = yAxis->FindBin(c0.multNTracksPV()); + registry.fill(HIST("hEventPairs"), xAxis->GetBinCenter(bin_PosZ), yAxis->GetBinCenter(bin_Mult)); + + for (const auto& [d3body0, d3body1] : combinations(soa::CombinationsFullIndexPolicy(decay3bodys0, decay3bodys1))) { + + registry.fill(HIST("hDecay3BodyPairsBeforeCut"), xAxis->GetBinCenter(bin_PosZ), yAxis->GetBinCenter(bin_Mult)); + + auto tpos0 = d3body0.track0_as(); + auto tneg0 = d3body0.track1_as(); + auto tbach0 = d3body0.track2_as(); + auto tpos1 = d3body1.track0_as(); + auto tneg1 = d3body1.track1_as(); + auto tbach1 = d3body1.track2_as(); + + // try to fit the vertex for decay3body0 + auto Trackpos0 = getTrackParCov(tpos0); + auto Trackneg0 = getTrackParCov(tneg0); + auto Trackbach0 = getTrackParCov(tbach0); + int nVtx0 = fitter3body.process(Trackpos0, Trackneg0, Trackbach0); + if (nVtx0 == 0) { + continue; + ; + } + + if ((tbach0.sign() > 0 && !(tbach1.sign() > 0)) || (tbach0.sign() < 0 && !(tbach1.sign() < 0)) || tbach0.globalIndex() == tbach1.globalIndex()) { // only combine if tbach1 has correct sign and is not same as tbach0 + continue; + } + + const auto& vtx0XYZ = fitter3body.getPCACandidate(); + float rVtx0 = std::hypot(vtx0XYZ[0], vtx0XYZ[1]); + registry.fill(HIST("hRadius0"), rVtx0); + + std::array ppos0 = {0.}, pneg0 = {0.}, pbach0{0.}; + const auto& propagatedtpos0 = fitter3body.getTrack(0); + const auto& propagatedtneg0 = fitter3body.getTrack(1); + const auto& propagatedtbach0 = fitter3body.getTrack(2); + propagatedtpos0.getPxPyPzGlo(ppos0); + propagatedtneg0.getPxPyPzGlo(pneg0); + propagatedtbach0.getPxPyPzGlo(pbach0); + for (int i = 0; i < 3; i++) { + pbach0[i] *= bachelorcharge; + } + std::array p3B0 = {ppos0[0] + pneg0[0] + pbach0[0], ppos0[1] + pneg0[1] + pbach0[1], ppos0[2] + pneg0[2] + pbach0[2]}; + float phiVtx0 = std::atan2(p3B0[1], p3B0[0]); + + // try to fit the vertex for decay3body1 + auto Trackpos1 = getTrackParCov(tpos1); + auto Trackneg1 = getTrackParCov(tneg1); + auto Trackbach1 = getTrackParCov(tbach1); + int nVtx1 = fitter3body.process(Trackpos1, Trackneg1, Trackbach1); + if (nVtx1 == 0) { + continue; + } + + const auto& vtx1XYZ = fitter3body.getPCACandidate(); + float rVtx1 = std::hypot(vtx1XYZ[0], vtx1XYZ[1]); + registry.fill(HIST("hRadius1"), rVtx1); + + std::array ppos1 = {0.}, pneg1 = {0.}, pbach1{0.}; + const auto& propagatedtpos1 = fitter3body.getTrack(0); + const auto& propagatedtneg1 = fitter3body.getTrack(1); + const auto& propagatedtbach1 = fitter3body.getTrack(2); + propagatedtpos1.getPxPyPzGlo(ppos1); + propagatedtneg1.getPxPyPzGlo(pneg1); + propagatedtbach1.getPxPyPzGlo(pbach1); + for (int i = 0; i < 3; i++) { + pbach1[i] *= bachelorcharge; + } + std::array p3B1 = {ppos1[0] + pneg1[0] + pbach1[0], ppos1[1] + pneg1[1] + pbach1[1], ppos1[2] + pneg1[2] + pbach1[2]}; + float phiVtx1 = std::atan2(p3B1[1], p3B1[0]); + registry.fill(HIST("hPhi0"), phiVtx0 * o2::constants::math::Rad2Deg); + registry.fill(HIST("hPhi1"), phiVtx1 * o2::constants::math::Rad2Deg); + // convert deltaPhi to range [-pi, pi] + float deltaPhi = RecoDecay::constrainAngle(phiVtx1 - phiVtx0, -o2::constants::math::PI); + // check if radius and phi of the two vertices are compatible + registry.fill(HIST("hDeltaRadius"), rVtx1 - rVtx0); + registry.fill(HIST("hDeltaPhi"), deltaPhi * o2::constants::math::Rad2Deg); + if (std::abs(deltaPhi) * o2::constants::math::Rad2Deg > dcaFitterEMSel.maxDeltaPhiColMixing || std::abs(rVtx1 - rVtx0) > dcaFitterEMSel.maxDeltaRadiusColMixing) { + continue; + } + registry.fill(HIST("hDecay3BodyPairsAfterCut"), xAxis->GetBinCenter(bin_PosZ), yAxis->GetBinCenter(bin_Mult)); + + fillVtxCand(c0, tpos0, tneg0, tbach1, -1, bachelorcharge, tbach1.tofNSigmaDe()); + // initCCDBfromRunNumber(c1.runNumber()); + fillVtxCand(c1, tpos1, tneg1, tbach0, -1, bachelorcharge, tbach0.tofNSigmaDe()); + } + } + + // Aviod break of preslice in following workflow + /*std::sort(VtxCandidates.begin(), VtxCandidates.end(), [](const VtxCandidate a, const VtxCandidate b) { + return a.collisionId < b.collisionId; + });*/ + } + PROCESS_SWITCH(decay3bodyBuilder, processRun3ReducedEM, "Produce event-mixing background", false); + + void processRun3Reduced3bodyMixing(ReducedCollisionsMults const&, aod::RedIUTracks const&, soa::Join const& decay3bodys) + { + VtxCandidates.clear(); + + auto xAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetXaxis(); + auto yAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetYaxis(); + + for (const auto& decay3body : decay3bodys) { + int bin_Radius = xAxis->FindBin(decay3body.svRadius()); + int bin_Phi = yAxis->FindBin(decay3body.momPhi()); + registry.fill(HIST("hDecay3BodyRadiusPhi"), xAxis->GetBinCenter(bin_Radius), yAxis->GetBinCenter(bin_Phi)); + registry.fill(HIST("hDecay3BodyPosZ"), decay3body.svPosZ()); + } + + Binning3BodyDCAFitter binningOnRadiusPhi{{dcaFitterEMSel.bins3BodyRadius, dcaFitterEMSel.bins3BodyPhiDegree}, true}; + doMixed3Body(decay3bodys, binningOnRadiusPhi); + } + PROCESS_SWITCH(decay3bodyBuilder, processRun3Reduced3bodyMixing, "Produce mixing background directly from mixed decay3bodys based on DCAFitter Info", false); + + void processRun3Reduced3bodyMixingKFInfo(ReducedCollisionsMults const&, aod::RedIUTracks const&, soa::Join const& decay3bodys) + { + VtxCandidates.clear(); + + auto xAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetXaxis(); + auto yAxis = registry.get(HIST("hDecay3BodyRadiusPhi"))->GetYaxis(); + + for (const auto& decay3body : decay3bodys) { + int bin_Radius = xAxis->FindBin(decay3body.radius()); + int bin_Phi = yAxis->FindBin(decay3body.phi()); + registry.fill(HIST("hDecay3BodyRadiusPhi"), xAxis->GetBinCenter(bin_Radius), yAxis->GetBinCenter(bin_Phi)); + registry.fill(HIST("hDecay3BodyPosZ"), decay3body.posz()); + } + + Binning3BodyKFInfo binningOnRadiusPhi{{dcaFitterEMSel.bins3BodyRadius, dcaFitterEMSel.bins3BodyPhi}, true}; + doMixed3Body(decay3bodys, binningOnRadiusPhi); + } + PROCESS_SWITCH(decay3bodyBuilder, processRun3Reduced3bodyMixingKFInfo, "Produce mixing background directly from mixed decay3bodys based on KF Info", false); + + //------------------------------------------------------------------ + void processRun3withKFParticle(ColwithEvTimes const& collisions, TrackExtPIDIUwithEvTimes const&, aod::Decay3Bodys const& decay3bodys, aod::BCsWithTimestamps const&) + { + for (const auto& collision : collisions) { + + auto bc = collision.bc_as(); + initCCDB(bc); + LOG(debug) << "CCDB initialised."; + + // Zorro event counting + bool isZorroSelected = false; + if (kfparticleConfigurations.cfgSkimmedProcessing) { + isZorroSelected = zorro.isSelected(collision.template bc_as().globalBC()); + if (isZorroSelected) { + registry.fill(HIST("Counters/hEventCounterZorro"), 0.); + } else { + if (kfparticleConfigurations.cfgOnlyKeepInterestedTrigger) { + continue; + } + } + } + + // event selection + registry.fill(HIST("Counters/hEventCounterKFParticle"), 0.5); + if (kfparticleConfigurations.doSel8selection && !collision.sel8()) { + continue; + } + registry.fill(HIST("Counters/hEventCounterKFParticle"), 1.5); + if (kfparticleConfigurations.doPosZselection && (collision.posZ() >= 10.0f || collision.posZ() <= -10.0f)) { + continue; + } + registry.fill(HIST("Counters/hEventCounterKFParticle"), 2.5); + registry.fill(HIST("QA/Event/hAllSelEventsVtxZ"), collision.posZ()); + + if (isZorroSelected) { + registry.fill(HIST("Counters/hEventCounterZorro"), 1.); + } + + // slice Decay3Body table by collision + const uint64_t collIdx = collision.globalIndex(); + auto Decay3BodyTable_thisCollision = decay3bodys.sliceBy(perCollision, collIdx); + for (auto& vtx3body : Decay3BodyTable_thisCollision) { + auto trackPos = vtx3body.template track0_as(); + auto trackNeg = vtx3body.template track1_as(); + auto trackBach = vtx3body.template track2_as(); + buildVtx3BodyDataTableKFParticle(collision, trackPos, trackNeg, trackBach, vtx3body.globalIndex(), bachelorcharge, getTOFnSigma(collision, trackBach, false /*isEventMixing*/)); + LOG(debug) << "End of processKFParticle."; + } + } + } + PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticle, "Produce KFParticle decay3body tables", false); + + void processRun3withKFParticleStrangenessTracking(ColwithEvTimes const& collisions, TrackExtPIDIUwithEvTimes const& tracks, aod::Decay3Bodys const& decay3bodys, aod::Tracked3Bodys const& tracked3bodys, aod::BCsWithTimestamps const& bcs) + { + fTrackedClSizeVector.clear(); + fTrackedClSizeVector.resize(decay3bodys.size(), 0); + for (const auto& tvtx3body : tracked3bodys) { + fTrackedClSizeVector[tvtx3body.decay3BodyId()] = tvtx3body.itsClsSize(); + } + processRun3withKFParticle(collisions, tracks, decay3bodys, bcs); + } + PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticleStrangenessTracking, "Produce KFParticle strangeness tracked decay3body tables", false); + + void processRun3withKFParticleReduced(aod::RedCollisions const& collisions, aod::RedIUTracks const&, aod::RedDecay3Bodys const& decay3bodys) + { + int lastRunNumber = -1; + + for (const auto& collision : collisions) { + // set magnetic field only when run number changes + if (collision.runNumber() != lastRunNumber) { + initCCDBfromRunNumber(collision.runNumber()); + lastRunNumber = collision.runNumber(); // Update the last run number + LOG(debug) << "CCDB initialized for run " << lastRunNumber; + } + + // event selection + registry.fill(HIST("Counters/hEventCounterKFParticle"), 2.5); + registry.fill(HIST("QA/Event/hAllSelEventsVtxZ"), collision.posZ()); + + // slice Decay3Body table by collision + const uint64_t collIdx = collision.globalIndex(); + auto Decay3BodyTable_thisCollision = decay3bodys.sliceBy(perReducedCollision, collIdx); + for (auto& vtx3body : Decay3BodyTable_thisCollision) { + auto trackPos = vtx3body.template track0_as(); + auto trackNeg = vtx3body.template track1_as(); + auto trackBach = vtx3body.template track2_as(); + buildVtx3BodyDataTableKFParticle(collision, trackPos, trackNeg, trackBach, vtx3body.globalIndex(), bachelorcharge, trackBach.tofNSigmaDe()); + } + LOG(debug) << "End of processKFParticleDerived."; + } + } + PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticleReduced, "Produce KFParticle decay3body tables from derived decay3body data", false); + + void processRun3withKFParticleReducedEM(ReducedCollisionsMults const& collisions, aod::RedIUTracks const&, aod::RedDecay3Bodys const& decay3bodys) + { + // ------------- Check number of events in bins -------------- + // Define a 2D array to count events and pairs per bin + std::vector> binEventCounts(10, std::vector(13, 0)); // 10 vtxZ bins, 13 multiplicity bins + std::vector> binPairCounts(10, std::vector(13, 0)); + + // Function to find bin index (returns -1 if out of range) + auto findBin = [](float value, const std::vector& binEdges) -> int { + for (size_t i = 0; i < binEdges.size() - 1; ++i) { + if (value > binEdges[i] && value <= binEdges[i + 1]) { + return i; + } + } + return -1; // Shouldn't happen if events are within range + }; + // Loop over all collisions to count them in bins + for (auto& collision : collisions) { + float vtxZ = collision.posZ(); + float mult = collision.multNTracksPV(); + + // Determine bin indices + int vtxZBin = findBin(vtxZ, {-10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}); + int multBin = findBin(mult, {0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}); + + if (vtxZBin >= 0 && multBin >= 0) { + binEventCounts[vtxZBin][multBin]++; + } + } + // Print out the number of events per bin + LOG(info) << "Event count per bin (vtxZ, mult):"; + for (size_t i = 0; i < binEventCounts.size(); ++i) { + for (size_t j = 0; j < binEventCounts[i].size(); ++j) { + LOG(info) << "Bin (" << i << ", " << j << "): " << binEventCounts[i][j] << " events"; + } + } + // Fill histogram with numbers per bin + for (size_t i = 0; i < binEventCounts.size(); ++i) { + for (size_t j = 0; j < binEventCounts[i].size(); ++j) { + registry.fill(HIST("QA/EM/hEventBinCounts"), i, j, binEventCounts[i][j]); + } + } + LOG(info) << "Integral of hEventBinCounts:" << registry.get(HIST("QA/EM/hEventBinCounts"))->Integral(); + + // ------------- Check number of decay3bodys in bins ------------- + // Define a 2D array to count events and pairs per bin + std::vector> binDecay3BodyCounts(10, std::vector(13, 0)); // 10 vtxZ bins, 13 multiplicity bins + // Loop over all decay3bodys to count them in bins + for (auto& decay3body : decay3bodys) { + auto collision = decay3body.template collision_as(); + float vtx3bodyZ = collision.posZ(); + float mult3body = collision.multNTracksPV(); + + // Determine bin indices + int vtx3bodyZBin = findBin(vtx3bodyZ, {-10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}); + int mult3bodyBin = findBin(mult3body, {0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}); + + if (vtx3bodyZBin >= 0 && mult3bodyBin >= 0) { + binDecay3BodyCounts[vtx3bodyZBin][mult3bodyBin]++; + } + } + // Print out the number of events per bin + LOG(debug) << "Event count per bin (vtxZ, mult):"; + for (size_t i = 0; i < binDecay3BodyCounts.size(); ++i) { + for (size_t j = 0; j < binDecay3BodyCounts[i].size(); ++j) { + LOG(debug) << "Bin (" << i << ", " << j << "): " << binDecay3BodyCounts[i][j] << " events"; + } + } + // Fill histogram with numbers per bin + for (size_t i = 0; i < binDecay3BodyCounts.size(); ++i) { + for (size_t j = 0; j < binDecay3BodyCounts[i].size(); ++j) { + registry.fill(HIST("QA/EM/h3bodyBinCounts"), i, j, binDecay3BodyCounts[i][j]); + } + } + LOG(info) << "Integral of h3bodyBinCounts:" << registry.get(HIST("QA/EM/h3bodyBinCounts"))->Integral(); + + // ------------- Do event mixing -------------- + auto tuple = std::make_tuple(decay3bodys); + BinningTypeKF binningOnPosAndMult{{kfparticleConfigurations.binsVtxZ, kfparticleConfigurations.binsMultiplicity}, true}; // ignore over-/underflow + SameKindPair pair{binningOnPosAndMult, kfparticleConfigurations.nEvtMixing, -1, collisions, tuple, &cache}; // indicates that under/overflow (-1) to be ignored + + int lastRunNumber = -1; + + for (auto& [c1, decays3body1, c2, decays3body2] : pair) { + registry.fill(HIST("QA/EM/hPairCounterMixing"), 0.5); + + // event selection already applied in reducer task + + // set magnetic field only when run number changes + if (c1.runNumber() != lastRunNumber) { + initCCDBfromRunNumber(c1.runNumber()); + lastRunNumber = c1.runNumber(); // Update the last run number + LOG(debug) << "CCDB initialized for run " << lastRunNumber; + } + + // Get vtxZ and multiplicity from collision + float vtxZpair = c1.posZ(); + float multpair = c1.multNTracksPV(); + // Find the bin index + int vtxZpairBin = findBin(vtxZpair, {-10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}); + int multpairBin = findBin(multpair, {0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}); + if (vtxZpairBin >= 0 && multpairBin >= 0) { + binPairCounts[vtxZpairBin][multpairBin]++; // Count the pair + } + + for (auto& [decay3body1, decay3body2] : soa::combinations(soa::CombinationsFullIndexPolicy(decays3body1, decays3body2))) { + auto trackPos1 = decay3body1.template track0_as(); + auto trackNeg1 = decay3body1.template track1_as(); + auto trackBach1 = decay3body1.template track2_as(); + auto trackPos2 = decay3body2.template track0_as(); + auto trackNeg2 = decay3body2.template track1_as(); + auto trackBach2 = decay3body2.template track2_as(); + + registry.fill(HIST("QA/EM/hCombinationCounterMixing"), 0.5); + + // ---------- selections bachelor track ---------- + if ((trackBach1.sign() > 0 && !(trackBach2.sign() > 0)) || (trackBach1.sign() < 0 && !(trackBach2.sign() < 0)) || trackBach1.globalIndex() == trackBach2.globalIndex()) { // only combine if trackBach2 has correct sign and is not same as trackBach1 + continue; + } + registry.fill(HIST("QA/EM/hCombinationCounterMixing"), 1.5); + + // ---------- check radius and phi of decay3bodys ---------- + auto trackParCovPos1 = getTrackParCov(trackPos1); + auto trackParCovNeg1 = getTrackParCov(trackNeg1); + auto trackParCovBach1 = getTrackParCov(trackBach1); + auto trackParCovPos2 = getTrackParCov(trackPos2); + auto trackParCovNeg2 = getTrackParCov(trackNeg2); + auto trackParCovBach2 = getTrackParCov(trackBach2); + // create KFParticle objects from tracks + KFParticle kfpProton1, kfpPion1, kfpDeuteron1; + if (trackBach1.sign() > 0) { + kfpProton1 = createKFParticleFromTrackParCov(trackParCovPos1, trackPos1.sign(), constants::physics::MassProton); + kfpPion1 = createKFParticleFromTrackParCov(trackParCovNeg1, trackNeg1.sign(), constants::physics::MassPionCharged); + } else if (!(trackBach1.sign() > 0)) { + kfpProton1 = createKFParticleFromTrackParCov(trackParCovNeg1, trackNeg1.sign(), constants::physics::MassProton); + kfpPion1 = createKFParticleFromTrackParCov(trackParCovPos1, trackPos1.sign(), constants::physics::MassPionCharged); + } + kfpDeuteron1 = createKFParticleFromTrackParCov(trackParCovBach1, trackBach1.sign() * bachelorcharge, constants::physics::MassDeuteron); + KFParticle kfpProton2, kfpPion2, kfpDeuteron2; + if (trackBach2.sign() > 0) { + kfpProton2 = createKFParticleFromTrackParCov(trackParCovPos2, trackPos2.sign(), constants::physics::MassProton); + kfpPion2 = createKFParticleFromTrackParCov(trackParCovNeg2, trackNeg2.sign(), constants::physics::MassPionCharged); + } else if (!(trackBach2.sign() > 0)) { + kfpProton2 = createKFParticleFromTrackParCov(trackParCovNeg2, trackNeg2.sign(), constants::physics::MassProton); + kfpPion2 = createKFParticleFromTrackParCov(trackParCovPos2, trackPos2.sign(), constants::physics::MassPionCharged); + } + kfpDeuteron2 = createKFParticleFromTrackParCov(trackParCovBach2, trackBach2.sign() * bachelorcharge, constants::physics::MassDeuteron); + // fit vertices + KFParticle KFHt1, KFHt2; + fit3bodyVertex(kfpProton1, kfpPion1, kfpDeuteron1, KFHt1); + fit3bodyVertex(kfpProton2, kfpPion2, kfpDeuteron2, KFHt2); + + // ---------- select common radius and phi region ---------- + auto radius1 = std::sqrt(KFHt1.GetX() * KFHt1.GetX() + KFHt1.GetY() * KFHt1.GetY()); + auto radius2 = std::sqrt(KFHt2.GetX() * KFHt2.GetX() + KFHt2.GetY() * KFHt2.GetY()); + registry.fill(HIST("QA/EM/hRadius1"), radius1); + registry.fill(HIST("QA/EM/hRadius2"), radius2); + registry.fill(HIST("QA/EM/hPhi1"), KFHt1.GetPhi() * (180.0 / TMath::Pi())); + registry.fill(HIST("QA/EM/hPhi2"), KFHt2.GetPhi() * (180.0 / TMath::Pi())); + registry.fill(HIST("QA/EM/hDeltaRadius"), std::abs(radius1 - radius2)); + registry.fill(HIST("QA/EM/hDeltaPhi"), std::abs(KFHt1.GetPhi() - KFHt2.GetPhi()) * (180.0 / TMath::Pi())); + if (std::abs(KFHt1.GetPhi() - KFHt2.GetPhi()) * (180.0 / TMath::Pi()) > 10 || std::abs(radius1 - radius2) > 2) { + continue; + } + registry.fill(HIST("QA/EM/hCombinationCounterMixing"), 2.5); + + // fill 2D pair counter per bin + registry.fill(HIST("QA/EM/hPairBinCounts"), vtxZpairBin, multpairBin, 1); + + // ---------- do candidate analysis ---------- + buildVtx3BodyDataTableKFParticle(c1, trackPos1, trackNeg1, trackBach2, -1 /*vtx3bodyID*/, bachelorcharge, trackBach2.tofNSigmaDe()); + } // end decay3body combinations loop + } // end pairing loop + } // end process + PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticleReducedEM, "Produce KFParticle event mixing decay3body tables from derived decay3body data", false); + + void processRun3withKFParticleReduced3bodyMixing(ReducedCollisionsMults const&, aod::RedIUTracks const&, soa::Join const& decay3bodys) + { + // Define a 2D array to count 3bodies per bin (radius, phi, posZ) + std::vector> bin3bodyCounts(16, std::vector(36, 0)); + + // Function to find bin index (returns -1 if out of range) + auto findBin = [](float value, const std::vector& binEdges) -> int { + for (size_t i = 0; i < binEdges.size() - 1; ++i) { + if (value > binEdges[i] && value <= binEdges[i + 1]) { + return i; + } + } + return -1; // Out of range + }; + + int counter = 0; + // Loop over all collisions to count them in bins + for (auto& decay3body : decay3bodys) { + counter++; + float radius = decay3body.radius(); + float phi = decay3body.phi(); + float posZ = decay3body.posz(); + + registry.fill(HIST("QA/EM/hRadius"), radius); + registry.fill(HIST("QA/EM/hPhi"), phi); + registry.fill(HIST("QA/EM/hPosZ"), posZ); + + // float degToRad = TMath::Pi()/180; + + // Determine bin indices + int radiusBin = findBin(radius, {0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 3.0f, 4.0f, 6.0f, 8.0f, 10.0f, 12.0f, 14.0f, 16.0f, 18.0f, 20.0f, 30.0f, 1000.0}); + int phiBin = findBin(phi, {-180.0f * TMath::Pi() / 180, -160.0f * TMath::Pi() / 180, -140.0f * TMath::Pi() / 180, -120.0f * TMath::Pi() / 180, -100.0f * TMath::Pi() / 180, -80.0f * TMath::Pi() / 180, -60.0f * TMath::Pi() / 180, -40.0f * TMath::Pi() / 180, -20.0f * TMath::Pi() / 180, 0.0f, 20.0f * TMath::Pi() / 180, 40.0f * TMath::Pi() / 180, 60.0f * TMath::Pi() / 180, 80.0f * TMath::Pi() / 180, 100.0f * TMath::Pi() / 180, 120.0f * TMath::Pi() / 180, 140.0f * TMath::Pi() / 180, 160.0f * TMath::Pi() / 180, 180.0f * TMath::Pi() / 180}); + if (radiusBin >= 0 && phiBin >= 0) { // && posZBin >= 0) { + bin3bodyCounts[radiusBin][phiBin]++; //[posZBin]++; + } + } + LOG(info) << "3body counter: " << counter; + + // Print out the number of 3-body decays per bin + LOG(info) << "3body count per bin (radius, phi, posZ):"; + for (size_t i = 0; i < bin3bodyCounts.size(); ++i) { + for (size_t j = 0; j < bin3bodyCounts[i].size(); ++j) { + LOG(info) << "Bin (" << i << ", " << j << "): " << bin3bodyCounts[i][j] << " 3bodies"; + } + } + // Fill 3D histogram with numbers per bin + for (size_t i = 0; i < bin3bodyCounts.size(); ++i) { + for (size_t j = 0; j < bin3bodyCounts[i].size(); ++j) { + registry.fill(HIST("QA/EM/h3bodyBinCounts"), i, j, bin3bodyCounts[i][j]); + } + } + LOG(info) << "Integral of h3bodyBinCounts: " << registry.get(HIST("QA/EM/h3bodyBinCounts"))->Integral(); + + Binning3Body binningOnRadPhi{{kfparticleConfigurations.bins3BodyRadius, kfparticleConfigurations.bins3BodyPhi}, true}; + + // Strictly upper index policy for decay3body objects binned by radius, phi and z position + for (auto& [decay3body1, decay3body2] : selfPairCombinations(binningOnRadPhi, kfparticleConfigurations.nEvtMixing, -1, decay3bodys)) { + auto trackPos1 = decay3body1.template track0_as(); + auto trackNeg1 = decay3body1.template track1_as(); + auto trackBach1 = decay3body1.template track2_as(); + auto trackPos2 = decay3body2.template track0_as(); + auto trackNeg2 = decay3body2.template track1_as(); + auto trackBach2 = decay3body2.template track2_as(); + + registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 0.5); + + // collision vertex selections + auto collision1 = decay3body1.template collision_as(); + auto collision2 = decay3body2.template collision_as(); + initCCDBfromRunNumber(collision2.runNumber()); + initCCDBfromRunNumber(collision1.runNumber()); + + if (decay3body1.collisionId() == decay3body2.collisionId()) { // only combine if from different event + continue; + } + registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 1.5); + if (kfparticleConfigurations.selectVtxZ3bodyMixing && std::abs(collision1.posZ() - collision2.posZ()) > kfparticleConfigurations.VtxZBin3bodyMixing) { // only combine if collision similar in VtxZ + continue; + } + registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 2.5); + + // ---------- selections ---------- + if ((trackBach1.sign() > 0 && !(trackBach2.sign() > 0)) || (trackBach1.sign() < 0 && !(trackBach2.sign() < 0)) || trackBach1.globalIndex() == trackBach2.globalIndex()) { // only combine if trackBach2 has correct sign and is not same as trackBach1 + continue; + } + registry.fill(HIST("QA/EM/h3bodyCombinationCounter"), 3.5); + + // ---------- do candidate analysis ---------- + bool isMatter1 = false; + if (trackBach1.sign() > 0) { + isMatter1 = true; + } + if (kfparticleConfigurations.mixingType == 0) { // mix deuteron + buildVtx3BodyDataTableKFParticle(collision1, trackPos1, trackNeg1, trackBach2, -1 /*vtx3bodyID*/, bachelorcharge, trackBach2.tofNSigmaDe()); + buildVtx3BodyDataTableKFParticle(collision2, trackPos2, trackNeg2, trackBach1, -1 /*vtx3bodyID*/, bachelorcharge, trackBach1.tofNSigmaDe()); + } else if (kfparticleConfigurations.mixingType == 1) { // mix proton + if (isMatter1 == true) { + buildVtx3BodyDataTableKFParticle(collision1, trackPos2, trackNeg1, trackBach1, -1 /*vtx3bodyID*/, bachelorcharge, trackBach1.tofNSigmaDe()); + buildVtx3BodyDataTableKFParticle(collision2, trackPos1, trackNeg2, trackBach2, -1 /*vtx3bodyID*/, bachelorcharge, trackBach2.tofNSigmaDe()); + } else if (isMatter1 == false) { + buildVtx3BodyDataTableKFParticle(collision1, trackPos1, trackNeg2, trackBach1, -1 /*vtx3bodyID*/, bachelorcharge, trackBach1.tofNSigmaDe()); + buildVtx3BodyDataTableKFParticle(collision2, trackPos2, trackNeg1, trackBach2, -1 /*vtx3bodyID*/, bachelorcharge, trackBach2.tofNSigmaDe()); + } + } + } // end decay3body combinations loop + } + PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticleReduced3bodyMixing, "Produce KFParticle mixed decay3body tables from derived decay3body data", false); }; +// build link from decay3body -> vtx3body struct decay3bodyDataLinkBuilder { - Produces vtxdataLink; + Produces VtxDataLink; + + void init(InitContext const&) {} + + template + void buildDecay3BodyLabel(TDecay3Bodys const& decay3bodytable, TVtx3BodyDatas const& vtxdatatable) + { + std::vector lIndices; + lIndices.reserve(decay3bodytable.size()); + for (int ii = 0; ii < decay3bodytable.size(); ii++) + lIndices[ii] = -1; + for (const auto& vtxdata : vtxdatatable) { + if (vtxdata.decay3bodyId() != -1) { + lIndices[vtxdata.decay3bodyId()] = vtxdata.globalIndex(); + } + } + for (int ii = 0; ii < decay3bodytable.size(); ii++) { + VtxDataLink(lIndices[ii]); + } + } + + void processStandard(aod::Decay3Bodys const& decay3bodytable, aod::Vtx3BodyDatas const& vtxdatatable) + { + buildDecay3BodyLabel(decay3bodytable, vtxdatatable); + } + PROCESS_SWITCH(decay3bodyDataLinkBuilder, processStandard, "Produce label from decay3body to vtx3body", true); + + void processReduced(aod::RedDecay3Bodys const& decay3bodytable, aod::Vtx3BodyDatas const& vtxdatatable) + { + buildDecay3BodyLabel(decay3bodytable, vtxdatatable); + } + PROCESS_SWITCH(decay3bodyDataLinkBuilder, processReduced, "Produce label from reducedDecay3body to vtx3body", false); +}; + +struct kfdecay3bodyDataLinkBuilder { + Produces kfvtxdataLink; void init(InitContext const&) {} - void process(aod::Decay3Bodys const& decay3bodytable, aod::Vtx3BodyDatas const& vtxdatatable) + template + void buildDataLink(TDecay3Bodys const& decay3bodytable, TVtx3BodyDatas const& vtxdatatable) { std::vector lIndices; lIndices.reserve(decay3bodytable.size()); for (int ii = 0; ii < decay3bodytable.size(); ii++) lIndices[ii] = -1; for (auto& vtxdata : vtxdatatable) { - lIndices[vtxdata.decay3bodyId()] = vtxdata.globalIndex(); + if (vtxdata.decay3bodyId() != -1) { + lIndices[vtxdata.decay3bodyId()] = vtxdata.globalIndex(); + } } for (int ii = 0; ii < decay3bodytable.size(); ii++) { - vtxdataLink(lIndices[ii]); + kfvtxdataLink(lIndices[ii]); } } + + void processStandard(aod::Decay3Bodys const& decay3bodytable, aod::KFVtx3BodyDatas const& vtxdatatable) + { + buildDataLink(decay3bodytable, vtxdatatable); // build Decay3Body -> KFDecay3BodyData link table + } + PROCESS_SWITCH(kfdecay3bodyDataLinkBuilder, processStandard, "Build data link table.", true); + + void processReduced(aod::RedDecay3Bodys const& decay3bodytable, aod::KFVtx3BodyDatas const& vtxdatatable) + { + buildDataLink(decay3bodytable, vtxdatatable); // build ReducedDecay3Body -> KFDecay3BodyData link table + } + PROCESS_SWITCH(kfdecay3bodyDataLinkBuilder, processReduced, "Build data link table for reduced data.", false); }; struct decay3bodyLabelBuilder { @@ -307,33 +2378,31 @@ struct decay3bodyLabelBuilder { Produces vtxlabels; Produces vtxfulllabels; - // for bookkeeping purposes: how many V0s come from same mother etc - HistogramRegistry registry{ - "registry", - { - {"hLabelCounter", "hLabelCounter", {HistType::kTH1F, {{3, 0.0f, 3.0f}}}}, - {"hHypertritonMCPt", "hHypertritonMCPt", {HistType::kTH1F, {{100, 0.0f, 10.0f}}}}, - {"hAntiHypertritonMCPt", "hAntiHypertritonMCPt", {HistType::kTH1F, {{100, 0.0f, 10.0f}}}}, - {"hHypertritonMCMass", "hHypertritonMCMass", {HistType::kTH1F, {{40, 2.95f, 3.05f, "Inv. Mass (GeV/c^{2})"}}}}, - {"hAntiHypertritonMCMass", "hAntiHypertritonMCMass", {HistType::kTH1F, {{40, 2.95f, 3.05f, "Inv. Mass (GeV/c^{2})"}}}}, - {"hHypertritonMCLifetime", "hHypertritonMCLifetime", {HistType::kTH1F, {{50, 0.0f, 50.0f, "ct(cm)"}}}}, - {"hAntiHypertritonMCLifetime", "hAntiHypertritonMCLifetime", {HistType::kTH1F, {{50, 0.0f, 50.0f, "ct(cm)"}}}}, - }, - }; + HistogramRegistry registry{"registry", {}}; void init(InitContext const&) { - registry.get(HIST("hLabelCounter"))->GetXaxis()->SetBinLabel(1, "Total"); - registry.get(HIST("hLabelCounter"))->GetXaxis()->SetBinLabel(2, "Have Same MotherTrack"); - registry.get(HIST("hLabelCounter"))->GetXaxis()->SetBinLabel(3, "True H3L"); + if (doprocessDoNotBuildLabels == false) { + auto hLabelCounter = registry.add("hLabelCounter", "hLabelCounter", HistType::kTH1D, {{3, 0.0f, 3.0f}}); + hLabelCounter->GetXaxis()->SetBinLabel(1, "Total"); + hLabelCounter->GetXaxis()->SetBinLabel(2, "Have Same MotherTrack"); + hLabelCounter->GetXaxis()->SetBinLabel(3, "True H3L"); + + registry.add("hHypertritonMCPt", "hHypertritonMCPt", HistType::kTH1F, {{100, 0.0f, 10.0f}}); + registry.add("hAntiHypertritonMCPt", "hAntiHypertritonMCPt", HistType::kTH1F, {{100, 0.0f, 10.0f}}); + registry.add("hHypertritonMCMass", "hHypertritonMCMass", HistType::kTH1F, {{40, 2.95f, 3.05f, "Inv. Mass (GeV/c^{2})"}}); + registry.add("hAntiHypertritonMCMass", "hAntiHypertritonMCMass", HistType::kTH1F, {{40, 2.95f, 3.05f, "Inv. Mass (GeV/c^{2})"}}); + registry.add("hHypertritonMCLifetime", "hHypertritonMCLifetime", HistType::kTH1F, {{50, 0.0f, 50.0f, "ct(cm)"}}); + registry.add("hAntiHypertritonMCLifetime", "hAntiHypertritonMCLifetime", HistType::kTH1F, {{50, 0.0f, 50.0f, "ct(cm)"}}); + } } Configurable TpcPidNsigmaCut{"TpcPidNsigmaCut", 5, "TpcPidNsigmaCut"}; - void processDoNotBuildLabels(aod::Collisions::iterator const&) + void processDoNotBuildLabels(aod::Decay3BodyDataLink const&) // is it possible to have none parameter? { // dummy process function - should not be required in the future - } + }; PROCESS_SWITCH(decay3bodyLabelBuilder, processDoNotBuildLabels, "Do not produce MC label tables", true); void processBuildLabels(aod::Decay3BodysLinked const& decay3bodys, aod::Vtx3BodyDatas const& vtx3bodydatas, MCLabeledTracksIU const&, aod::McParticles const&) @@ -344,7 +2413,7 @@ struct decay3bodyLabelBuilder { lIndices[ii] = -1; } - for (auto& decay3body : decay3bodys) { + for (const auto& decay3body : decay3bodys) { int lLabel = -1; int lPDG = -1; @@ -372,9 +2441,9 @@ struct decay3bodyLabelBuilder { continue; } - for (auto& lMother0 : lMCTrack0.mothers_as()) { - for (auto& lMother1 : lMCTrack1.mothers_as()) { - for (auto& lMother2 : lMCTrack2.mothers_as()) { + for (const auto& lMother0 : lMCTrack0.mothers_as()) { + for (const auto& lMother1 : lMCTrack1.mothers_as()) { + for (const auto& lMother2 : lMCTrack2.mothers_as()) { if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { lGlobalIndex = lMother1.globalIndex(); lPt = lMother1.pt(); @@ -394,7 +2463,7 @@ struct decay3bodyLabelBuilder { // Intended for hypertriton cross-checks only if (lPDG == 1010010030 && lMCTrack0.pdgCode() == 2212 && lMCTrack1.pdgCode() == -211 && lMCTrack2.pdgCode() == 1000010020) { lLabel = lGlobalIndex; - double hypertritonMCMass = RecoDecay::m(array{array{lMCTrack0.px(), lMCTrack0.py(), lMCTrack0.pz()}, array{lMCTrack1.px(), lMCTrack1.py(), lMCTrack1.pz()}, array{lMCTrack2.px(), lMCTrack2.py(), lMCTrack2.pz()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); + double hypertritonMCMass = RecoDecay::m(std::array{std::array{lMCTrack0.px(), lMCTrack0.py(), lMCTrack0.pz()}, std::array{lMCTrack1.px(), lMCTrack1.py(), lMCTrack1.pz()}, std::array{lMCTrack2.px(), lMCTrack2.py(), lMCTrack2.pz()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); registry.fill(HIST("hLabelCounter"), 2.5); registry.fill(HIST("hHypertritonMCPt"), lPt); registry.fill(HIST("hHypertritonMCLifetime"), MClifetime); @@ -402,7 +2471,7 @@ struct decay3bodyLabelBuilder { } if (lPDG == -1010010030 && lMCTrack0.pdgCode() == 211 && lMCTrack1.pdgCode() == -2212 && lMCTrack2.pdgCode() == -1000010020) { lLabel = lGlobalIndex; - double antiHypertritonMCMass = RecoDecay::m(array{array{lMCTrack0.px(), lMCTrack0.py(), lMCTrack0.pz()}, array{lMCTrack1.px(), lMCTrack1.py(), lMCTrack1.pz()}, array{lMCTrack2.px(), lMCTrack2.py(), lMCTrack2.pz()}}, array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}); + double antiHypertritonMCMass = RecoDecay::m(std::array{std::array{lMCTrack0.px(), lMCTrack0.py(), lMCTrack0.pz()}, std::array{lMCTrack1.px(), lMCTrack1.py(), lMCTrack1.pz()}, std::array{lMCTrack2.px(), lMCTrack2.py(), lMCTrack2.pz()}}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}); registry.fill(HIST("hLabelCounter"), 2.5); registry.fill(HIST("hAntiHypertritonMCPt"), lPt); registry.fill(HIST("hAntiHypertritonMCLifetime"), MClifetime); @@ -434,7 +2503,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) return WorkflowSpec{ adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), }; } diff --git a/PWGLF/TableProducer/Nuspex/ebyeMaker.cxx b/PWGLF/TableProducer/Nuspex/ebyeMaker.cxx new file mode 100644 index 00000000000..99d2be3dc3c --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/ebyeMaker.cxx @@ -0,0 +1,1469 @@ +// 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. + +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "Common/Core/PID/PIDTOF.h" +#include "Common/TableProducer/PID/pidTOFBase.h" +#include "CCDB/CcdbApi.h" + +#include "Common/Core/PID/TPCPIDResponse.h" +#include "Common/DataModel/PIDResponse.h" +#include "DCAFitter/DCAFitterN.h" + +#include "PWGLF/DataModel/LFEbyeTables.h" + +#include "TDatabasePDG.h" +#include "TFormula.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using TracksFull = soa::Join; +using TracksFullPID = soa::Join; +using TracksFullIU = soa::Join; +using BCsWithRun2Info = soa::Join; + +namespace +{ +constexpr int kNpart = 2; +constexpr float trackSels[12]{/* 60, */ 80, 100, 2, 3, /* 4, */ 0.05, 0.1, /* 0.15, */ 0.5, 1, /* 1.5, */ 2, 3 /* , 4 */, 2, 3, /*, 4 */}; +constexpr float dcaSels[3]{10., 10., 10.}; +constexpr double betheBlochDefault[kNpart][6]{{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}, {-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}}; +constexpr double betheBlochDefaultITS[6]{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}; +constexpr double estimatorsCorrelationCoef[2]{-0.669108, 1.04489}; +constexpr double estimatorsSigmaPars[4]{0.933321, 0.0416976, -0.000936344, 8.92179e-06}; +constexpr double deltaEstimatorNsigma[2]{5.5, 5.}; +constexpr double partMass[kNpart]{o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}; +constexpr double partPdg[kNpart]{2212, o2::constants::physics::kDeuteron}; +static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; +static const std::vector particleNamesPar{"p", "d"}; +static const std::vector trackSelsNames{"tpcClsMid", "tpcClsTight", "chi2TpcTight", "chi2TpcMid", "dcaxyTight", "dcaxyMid", "dcazTight", "dcazMid", "tpcNsigmaTight", "tpcNsigmaMid", "itsNsigmaTight", "itsNsigmaMid"}; +static const std::vector dcaSelsNames{"dcaxy", "dcaz", "dca"}; +static const std::vector particleName{"p"}; +std::array, kNpart> tofMass; +void momTotXYZ(std::array& momA, std::array const& momB, std::array const& momC) +{ + for (int i = 0; i < 3; ++i) { + momA[i] = momB[i] + momC[i]; + } +} +float invMass2Body(std::array const& momA, std::array const& momB, std::array const& momC, float const& massB, float const& massC) +{ + float p2B = momB[0] * momB[0] + momB[1] * momB[1] + momB[2] * momB[2]; + float p2C = momC[0] * momC[0] + momC[1] * momC[1] + momC[2] * momC[2]; + float eB = std::sqrt(p2B + massB * massB); + float eC = std::sqrt(p2C + massC * massC); + float eA = eB + eC; + float massA = std::sqrt(eA * eA - momA[0] * momA[0] - momA[1] * momA[1] - momA[2] * momA[2]); + return massA; +} +float alphaAP(std::array const& momA, std::array const& momB, std::array const& momC) +{ + float momTot = std::sqrt(std::pow(momA[0], 2.) + std::pow(momA[1], 2.) + std::pow(momA[2], 2.)); + float lQlPos = (momB[0] * momA[0] + momB[1] * momA[1] + momB[2] * momA[2]) / momTot; + float lQlNeg = (momC[0] * momA[0] + momC[1] * momA[1] + momC[2] * momA[2]) / momTot; + return (lQlPos - lQlNeg) / (lQlPos + lQlNeg); +} +float etaFromMom(std::array const& momA, std::array const& momB) +{ + if (std::sqrt((1.f * momA[0] + 1.f * momB[0]) * (1.f * momA[0] + 1.f * momB[0]) + + (1.f * momA[1] + 1.f * momB[1]) * (1.f * momA[1] + 1.f * momB[1]) + + (1.f * momA[2] + 1.f * momB[2]) * (1.f * momA[2] + 1.f * momB[2])) - + (1.f * momA[2] + 1.f * momB[2]) < + static_cast(1e-7)) { + if ((1.f * momA[2] + 1.f * momB[2]) < 0.f) + return -100.f; + return 100.f; + } + return 0.5f * std::log((std::sqrt((1.f * momA[0] + 1.f * momB[0]) * (1.f * momA[0] + 1.f * momB[0]) + + (1.f * momA[1] + 1.f * momB[1]) * (1.f * momA[1] + 1.f * momB[1]) + + (1.f * momA[2] + 1.f * momB[2]) * (1.f * momA[2] + 1.f * momB[2])) + + (1.f * momA[2] + 1.f * momB[2])) / + (std::sqrt((1.f * momA[0] + 1.f * momB[0]) * (1.f * momA[0] + 1.f * momB[0]) + + (1.f * momA[1] + 1.f * momB[1]) * (1.f * momA[1] + 1.f * momB[1]) + + (1.f * momA[2] + 1.f * momB[2]) * (1.f * momA[2] + 1.f * momB[2])) - + (1.f * momA[2] + 1.f * momB[2]))); +} +float CalculateDCAStraightToPV(float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) +{ + return std::sqrt((std::pow((pvY - Y) * Pz - (pvZ - Z) * Py, 2) + std::pow((pvX - X) * Pz - (pvZ - Z) * Px, 2) + std::pow((pvX - X) * Py - (pvY - Y) * Px, 2)) / (Px * Px + Py * Py + Pz * Pz)); +} +} // namespace + +struct CandidateV0 { + float pt = -999.f; + float eta = -999.f; + float mass = -999.f; + float cpa = -999.f; + float dcav0daugh = -999.f; + float dcanegpv = -999.f; + float dcapospv = -999.f; + float dcav0pv = -999.f; + float tpcnsigmaneg = -999.f; + float tpcnsigmapos = -999.f; + float genpt = -999.f; + float geneta = -999.f; + int pdgcode = -999; + bool isreco = 0; + int64_t mcIndex = -999; + int64_t globalIndexPos = -999; + int64_t globalIndexNeg = -999; +}; + +struct CandidateTrack { + float pt = -999.f; + float eta = -999.f; + uint8_t mass = 100; + float dcapv = 0; + float dcaxypv = 0; + float dcazpv = 0; + uint8_t tpcncls = 0; + float tpcchi2 = 0; + float tpcnsigma = -999.f; + float itsnsigma = -999.f; + float tofmass = -999.f; + float outerPID = -999.f; + float genpt = -999.f; + float geneta = -999.f; + int pdgcode = -999; + int pdgcodemoth = -999; + bool isreco = 0; + int64_t mcIndex = -999; + int64_t globalIndex = -999; +}; + +enum selBits { + kTPCclsTight = BIT(0), + kTPCclsMid = BIT(1), + kChi2TPCTight = BIT(2), + kChi2TPCMid = BIT(3), + kDCAxyTight = BIT(4), + kDCAxyMid = BIT(5), + kDCAzTight = BIT(6), + kDCAzMid = BIT(7), + kITSPIDTight = BIT(8), + kITSPIDMid = BIT(9), + kTPCPIDTight = BIT(10), + kTPCPIDMid = BIT(11) +}; + +enum PartTypes { + kLa = BIT(20), + kSig = BIT(21), + kPhysPrim = BIT(22) +}; + +struct tagRun2V0MCalibration { + bool mCalibrationStored = false; + TH1* mhVtxAmpCorrV0A = nullptr; + TH1* mhVtxAmpCorrV0C = nullptr; + TH1* mhMultSelCalib = nullptr; + float mMCScalePars[6] = {0.0}; + TFormula* mMCScale = nullptr; +} Run2V0MInfo; + +struct tagRun2CL0Calibration { + bool mCalibrationStored = false; + TH1* mhVtxAmpCorr = nullptr; + TH1* mhMultSelCalib = nullptr; +} Run2CL0Info; + +struct ebyeMaker { + Produces collisionEbyeTable; + Produces miniCollTable; + Produces nucleiEbyeTable; + Produces lambdaEbyeTable; + Produces miniTrkTable; + Produces mcNucleiEbyeTable; + Produces mcLambdaEbyeTable; + Produces mcMiniTrkTable; + std::mt19937 gen32; + std::vector candidateV0s; + std::array, 2> candidateTracks; + Service ccdb; + o2::vertexing::DCAFitterN<2> fitter; + std::vector classIds; + + int mRunNumber; + float d_bz; + uint8_t nTrackletsColl; + // o2::base::MatLayerCylSet* lut = nullptr; + + Configurable cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Type of material correction"}; + Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {betheBlochDefault[0], 2, 6, particleNamesPar, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for deuteron"}; + Configurable> cfgBetheBlochParamsITS{"cfgBetheBlochParamsITS", {betheBlochDefaultITS, 1, 6, particleName, betheBlochParNames}, "ITS Bethe-Bloch parameterisation for deuteron"}; + + ConfigurableAxis centAxis{"centAxis", {106, 0, 106}, "binning for the centrality"}; + ConfigurableAxis zVtxAxis{"zVtxBins", {100, -20.f, 20.f}, "Binning for the vertex z in cm"}; + ConfigurableAxis multAxis{"multAxis", {100, 0, 10000}, "Binning for the multiplicity axis"}; + ConfigurableAxis multFt0Axis{"multFt0Axis", {100, 0, 100000}, "Binning for the ft0 multiplicity axis"}; + + // binning of (anti)lambda mass QA histograms + ConfigurableAxis massLambdaAxis{"massLambdaAxis", {400, o2::constants::physics::MassLambda0 - 0.03f, o2::constants::physics::MassLambda0 + 0.03f}, "binning for the lambda invariant-mass"}; + + // binning of PID QA histograms + ConfigurableAxis momAxis{"momAxisFine", {5.e2, 0.f, 5.f}, "momentum axis binning"}; + ConfigurableAxis tpcAxis{"tpcAxis", {4.e2, 0.f, 4.e3f}, "tpc signal axis binning"}; + ConfigurableAxis tofMassAxis{"tofMassAxis", {1000, 0., 3.f}, "tof mass axis"}; + + Configurable zVtxMax{"zVtxMax", 10.0f, "maximum z position of the primary vertex"}; + Configurable etaMax{"etaMax", 0.8f, "maximum eta"}; + Configurable etaMaxV0dau{"etaMaxV0dau", 0.8f, "maximum eta V0 daughters"}; + Configurable outerPIDMin{"outerPIDMin", -4.f, "minimum outer PID"}; + + Configurable fillOnlySignal{"fillOnlySignal", false, "fill histograms only for true signal candidates (MC)"}; + Configurable genName{"genname", "", "Genearator name: HIJING, PYTHIA8, ... Default: \"\""}; + + Configurable triggerCut{"triggerCut", 0x0, "trigger cut to select"}; + Configurable kINT7Intervals{"kINT7Intervals", false, "toggle kINT7 trigger selection in the 10-30% and 50-90% centrality intervals (2018 Pb-Pb)"}; + Configurable kUsePileUpCut{"kUsePileUpCut", false, "toggle strong correlation cuts (Run 2)"}; + Configurable kUseEstimatorsCorrelationCut{"kUseEstimatorsCorrelationCut", false, "toggle cut on the correlation between centrality estimators (2018 Pb-Pb)"}; + + Configurable antidPtMin{"antidPtMin", 0.6f, "minimum antideuteron pT (GeV/c)"}; + Configurable antidPtTof{"antidPtTof", 1.0f, "antideuteron pT to switch to TOF pid (GeV/c) "}; + Configurable antidPtMax{"antidPtMax", 1.8f, "maximum antideuteron pT (GeV/c)"}; + + Configurable antipPtMin{"antipPtMin", 0.4f, "minimum antiproton pT (GeV/c)"}; + Configurable antipPtTof{"antipPtTof", 0.6f, "antiproton pT to switch to TOF pid (GeV/c) "}; + Configurable antipPtMax{"antipPtMax", 0.9f, "maximum antiproton pT (GeV/c)"}; + + Configurable lambdaPtMin{"lambdaPtMin", 1.f, "minimum (anti)lambda pT (GeV/c)"}; + Configurable lambdaPtMax{"lambdaPtMax", 4.f, "maximum (anti)lambda pT (GeV/c)"}; + + Configurable trackNcrossedRows{"trackNcrossedRows", 70, "Minimum number of crossed TPC rows"}; + Configurable trackNclusItsCut{"trackNclusITScut", 2, "Minimum number of ITS clusters"}; + Configurable trackNclusTpcCut{"trackNclusTPCcut", 60, "Minimum number of TPC clusters"}; + Configurable trackChi2Cut{"trackChi2Cut", 4.f, "Maximum chi2/ncls in TPC"}; + Configurable> cfgDcaSels{"cfgDcaSels", {dcaSels, 1, 3, particleName, dcaSelsNames}, "DCA selections"}; + + Configurable v0trackNcrossedRows{"v0trackNcrossedRows", 100, "Minimum number of crossed TPC rows for V0 daughter"}; + Configurable v0trackNclusItsCut{"v0trackNclusITScut", 0, "Minimum number of ITS clusters for V0 daughter"}; + Configurable v0trackNclusTpcCut{"v0trackNclusTPCcut", 100, "Minimum number of TPC clusters for V0 daughter"}; + Configurable v0trackNsharedClusTpc{"v0trackNsharedClusTpc", 5, "Maximum number of shared TPC clusters for V0 daughter"}; + Configurable v0requireITSrefit{"v0requireITSrefit", false, "require ITS refit for V0 daughter"}; + Configurable vetoMassK0Short{"vetoMassK0Short", 0.01f, "veto for V0 compatible with K0s mass"}; + Configurable v0radiusMax{"v0radiusMax", 100.f, "maximum V0 radius eccepted"}; + + Configurable antidNsigmaTpcCutLow{"antidNsigmaTpcCutLow", -4.f, "TPC PID cut low"}; + Configurable antidNsigmaTpcCutUp{"antidNsigmaTpcCutUp", 4.f, "TPC PID cut up"}; + Configurable antidTpcInnerParamMax{"tpcInnerParamMax", 0.f, "(temporary) tpc inner param cut"}; + Configurable antidTofMassMax{"tofMassMax", 0.3f, "(temporary) tof mass cut"}; + + Configurable antipNsigmaTpcCutLow{"antipNsigmaTpcCutLow", -4.f, "TPC PID cut low"}; + Configurable antipNsigmaTpcCutUp{"antipNsigmaTpcCutUp", 4.f, "TPC PID cut up"}; + Configurable antipTpcInnerParamMax{"antipTpcInnerParamMax", 0.f, "(temporary) tpc inner param cut"}; + Configurable antipTofMassMax{"antipTofMassMax", 0.3f, "(temporary) tof mass cut"}; + Configurable tofMassMaxQA{"tofMassMaxQA", 0.6f, "(temporary) tof mass cut (for QA histograms)"}; + + Configurable v0setting_dcav0dau{"v0setting_dcav0dau", 0.5f, "DCA V0 Daughters"}; + Configurable v0setting_dcav0pv{"v0setting_dcav0pv", 1.f, "DCA V0 to Pv"}; + Configurable v0setting_dcadaughtopv{"v0setting_dcadaughtopv", 0.1f, "DCA Pos To PV"}; + Configurable v0setting_cospa{"v0setting_cospa", 0.99f, "V0 CosPA"}; + Configurable v0setting_radius{"v0setting_radius", 5.f, "v0radius"}; + Configurable v0setting_lifetime{"v0setting_lifetime", 40.f, "v0 lifetime cut"}; + Configurable v0setting_nsigmatpc{"v0setting_nsigmatpc", 4.f, "nsigmatpc"}; + Configurable lambdaMassCut{"lambdaMassCut", 0.02f, "maximum deviation from PDG mass (for QA histograms)"}; + + Configurable constDCASel{"constDCASel", true, "use DCA selections independent of pt"}; + + Configurable antidItsClsSizeCut{"antidItsClsSizeCut", 1.e-10f, "cluster size cut for antideuterons"}; + Configurable antidPtItsClsSizeCut{"antidPtItsClsSizeCut", 10.f, "pt for cluster size cut for antideuterons"}; + + Configurable> cfgTrackSels{"cfgTrackSels", {trackSels, 1, 12, particleName, trackSelsNames}, "Track selections"}; + + std::array ptMin; + std::array ptTof; + std::array ptMax; + std::array nSigmaTpcCutLow; + std::array nSigmaTpcCutUp; + std::array tpcInnerParamMax; + std::array tofMassMax; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Preslice perCollisionTracksFull = o2::aod::track::collisionId; + Preslice perCollisionTracksFullPID = o2::aod::track::collisionId; + Preslice perCollisionTracksFullIU = o2::aod::track::collisionId; + Preslice perCollisionV0 = o2::aod::v0::collisionId; + Preslice perCollisionMcParts = o2::aod::mcparticle::mcCollisionId; + + template + int getPartTypeMother(P const& mcPart) + { + for (auto& mother : mcPart.template mothers_as()) { + if (!mother.isPhysicalPrimary()) + return -1; + int pdgCode = mother.pdgCode(); + switch (std::abs(pdgCode)) { + case 3122: { + int foundPi = 0; + for (auto& mcDaught : mother.template daughters_as()) { + if (std::abs(mcDaught.pdgCode()) == 211) { + foundPi = mcDaught.pdgCode(); + break; + } + } + if (foundPi * mcPart.pdgCode() < -0.5) + return PartTypes::kLa; + return -1; + } + // case 3222: + // return PartTypes::kSig; + // case 3112: + // return PartTypes::kSig; + default: + return -1; + } + } + return -1; + } + + template + bool selectV0Daughter(T const& track) + { + if (std::abs(track.eta()) > etaMaxV0dau) { + return false; + } + if (track.itsNCls() < v0trackNclusItsCut || + track.tpcNClsFound() < v0trackNclusTpcCut || + track.tpcNClsCrossedRows() < v0trackNclusTpcCut || + track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || + track.tpcNClsShared() > v0trackNsharedClusTpc) { + return false; + } + if (doprocessRun2 || doprocessMiniRun2 || doprocessMcRun2 || doprocessMiniMcRun2) { + if (!(track.trackType() & o2::aod::track::Run2Track) || + !(track.flags() & o2::aod::track::TPCrefit)) { + return false; + } + if (v0requireITSrefit && !(track.flags() & o2::aod::track::ITSrefit)) { + return false; + } + } + return true; + } + + template + bool selectTrack(T const& track) + { + if (std::abs(track.eta()) > etaMax) { + return false; + } + if (!(track.itsClusterMap() & 0x01) && !(track.itsClusterMap() & 0x02)) { + return false; + } + if (track.itsNCls() < trackNclusItsCut || + track.tpcNClsFound() < trackNclusTpcCut || + track.tpcNClsCrossedRows() < trackNcrossedRows || + track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || + track.tpcChi2NCl() > trackChi2Cut || + track.itsChi2NCl() > 36.f) { + return false; + } + if (doprocessRun2 || doprocessMiniRun2 || doprocessMcRun2 || doprocessMiniMcRun2) { + if (!(track.trackType() & o2::aod::track::Run2Track) || + !(track.flags() & o2::aod::track::TPCrefit) || + !(track.flags() & o2::aod::track::ITSrefit)) { + return false; + } + } + return true; + } + + template + float getITSClSize(T const& track) + { + float sum{0.f}; + for (int iL{0}; iL < 6; ++iL) { + sum += (track.itsClusterSizes() >> (iL * 4)) & 0xf; + } + return sum / track.itsNCls(); + } + + float dcaSigma(float const& pt) + { + return 0.0105 + 0.0350 / std::pow(std::abs(pt), 1.1); + } + + template + void initCCDB(Bc const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + classIds.clear(); + auto timestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (doprocessRun2 || doprocessMcRun2 || doprocessMiniRun2 || doprocessMiniMcRun2) { + auto grpPath{"GLO/GRP/GRP"}; + grpo = ccdb->getForTimeStamp("GLO/GRP/GRP", timestamp); + if (!grpo) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpPath << " of object GRPObject for timestamp " << timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpo); + TList* callst = ccdb->getForTimeStamp("Centrality/Estimators", bc.timestamp()); + if (callst != nullptr) { + auto getccdb = [callst](const char* ccdbhname) { + TH1* h = reinterpret_cast(callst->FindObject(ccdbhname)); + return h; + }; + auto getformulaccdb = [callst](const char* ccdbhname) { + TFormula* f = reinterpret_cast(callst->FindObject(ccdbhname)); + return f; + }; + Run2V0MInfo.mhVtxAmpCorrV0A = getccdb("hVtx_fAmplitude_V0A_Normalized"); + Run2V0MInfo.mhVtxAmpCorrV0C = getccdb("hVtx_fAmplitude_V0C_Normalized"); + Run2V0MInfo.mhMultSelCalib = getccdb("hMultSelCalib_V0M"); + Run2V0MInfo.mMCScale = getformulaccdb(TString::Format("%s-V0M", genName->c_str()).Data()); + if ((Run2V0MInfo.mhVtxAmpCorrV0A != nullptr) && (Run2V0MInfo.mhVtxAmpCorrV0C != nullptr) && (Run2V0MInfo.mhMultSelCalib != nullptr)) { + if (genName->length() != 0) { + if (Run2V0MInfo.mMCScale != nullptr) { + for (int ixpar = 0; ixpar < 6; ++ixpar) { + Run2V0MInfo.mMCScalePars[ixpar] = Run2V0MInfo.mMCScale->GetParameter(ixpar); + } + } else { + LOGF(fatal, "MC Scale information from V0M for run %d not available", bc.runNumber()); + } + } + Run2V0MInfo.mCalibrationStored = true; + } else { + LOGF(fatal, "Calibration information from V0M for run %d corrupted", bc.runNumber()); + } + if (doprocessRun2) { + Run2CL0Info.mhVtxAmpCorr = getccdb("hVtx_fnSPDClusters0_Normalized"); + Run2CL0Info.mhMultSelCalib = getccdb("hMultSelCalib_CL0"); + if ((Run2CL0Info.mhVtxAmpCorr != nullptr) && (Run2CL0Info.mhMultSelCalib != nullptr)) { + Run2CL0Info.mCalibrationStored = true; + } else { + LOGF(fatal, "Calibration information from CL0 multiplicity for run %d corrupted", bc.runNumber()); + } + } + } + } else { + auto grpmagPath{"GLO/Config/GRPMagField"}; + grpmag = ccdb->getForTimeStamp("GLO/Config/GRPMagField", timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField for timestamp " << timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + } + // Fetch magnetic field from ccdb for current collision + d_bz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "Retrieved GRP for timestamp " << timestamp << " with magnetic field of " << d_bz << " kG"; + mRunNumber = bc.runNumber(); + if (doprocessMiniRun2) { + o2::ccdb::CcdbApi ccdbApi; + ccdbApi.init("http://alice-ccdb.cern.ch"); + std::map metadata; + std::map* classNameToIndexMap = ccdbApi.retrieveFromTFileAny>("CTP/ClassNameToIndexMap", metadata, mRunNumber); + for (const auto& classToIndexPair : *classNameToIndexMap) { + bool hasClassName = classToIndexPair.first.find("HMV0M") < classToIndexPair.first.length(); + int classId = hasClassName ? classToIndexPair.second - 1 : -1; + if (classId < 0) { + continue; + } + classIds.push_back(classId); + } + } + fitter.setBz(d_bz); + + // o2::base::Propagator::Instance()->setMatLUT(lut); + } + + template + std::pair getITSSignal(T const& track, aod::Run2TrackExtras const& trackExtraRun2) + { + if ((doprocessMiniRun2 || doprocessMiniMcRun2) && track.hasITS()) { + auto extra = trackExtraRun2.rawIteratorAt(track.globalIndex()); + double expBethe{tpc::BetheBlochAleph(static_cast(track.p() / partMass[0]), cfgBetheBlochParamsITS->get("p0"), cfgBetheBlochParamsITS->get("p1"), cfgBetheBlochParamsITS->get("p2"), cfgBetheBlochParamsITS->get("p3"), cfgBetheBlochParamsITS->get("p4"))}; + double expSigma{expBethe * cfgBetheBlochParamsITS->get("resolution")}; + auto nSigmaITS = static_cast((extra.itsSignal() - expBethe) / expSigma); + return std::make_pair(extra.itsSignal(), nSigmaITS); + } + return std::make_pair(-999.f, -999.f); + } + + template + float getOuterPID(T const& track) + { + if ((doprocessMiniRun2 || doprocessMiniMcRun2) && track.hasTOF() && track.pt() > antipPtTof) + return track.tofNSigmaPr(); + return -999.f; + } + + float getV0M(int64_t const id, float const zvtx, aod::FV0As const& fv0as, aod::FV0Cs const& fv0cs) + { + auto fv0a = fv0as.rawIteratorAt(id); + auto fv0c = fv0cs.rawIteratorAt(id); + float multFV0A = 0; + float multFV0C = 0; + for (float amplitude : fv0a.amplitude()) { + multFV0A += amplitude; + } + + for (float amplitude : fv0c.amplitude()) { + multFV0C += amplitude; + } + + float v0m = -1; + auto scaleMC = [](float x, float pars[6]) { + return pow(((pars[0] + pars[1] * pow(x, pars[2])) - pars[3]) / pars[4], 1.0f / pars[5]); + }; + + if (Run2V0MInfo.mMCScale != nullptr) { + float multFV0M = multFV0A + multFV0C; + v0m = scaleMC(multFV0M, Run2V0MInfo.mMCScalePars); + LOGF(debug, "Unscaled v0m: %f, scaled v0m: %f", multFV0M, v0m); + } else if (Run2V0MInfo.mCalibrationStored) { + v0m = multFV0A * Run2V0MInfo.mhVtxAmpCorrV0A->GetBinContent(Run2V0MInfo.mhVtxAmpCorrV0A->FindFixBin(zvtx)) + + multFV0C * Run2V0MInfo.mhVtxAmpCorrV0C->GetBinContent(Run2V0MInfo.mhVtxAmpCorrV0C->FindFixBin(zvtx)); + } + return v0m; + } + + template + int getTrackSelMask(T const& track) + { + int mask = 0x0; + if (track.tpcncls > cfgTrackSels->get("tpcClsTight")) + mask |= kTPCclsTight; + else if (track.tpcncls > cfgTrackSels->get("tpcClsMid")) + mask |= kTPCclsMid; + if (track.tpcchi2 < cfgTrackSels->get("chi2TpcTight")) + mask |= kChi2TPCTight; + else if (track.tpcchi2 < cfgTrackSels->get("chi2TpcMid")) + mask |= kChi2TPCMid; + if (std::abs(track.dcaxypv) < cfgTrackSels->get("dcaxyTight") * (constDCASel ? 1. : dcaSigma(track.pt))) + mask |= kDCAxyTight; + else if (std::abs(track.dcaxypv) < cfgTrackSels->get("dcaxyMid") * (constDCASel ? 1. : dcaSigma(track.pt))) + mask |= kDCAxyMid; + if (std::abs(track.dcazpv) < cfgTrackSels->get("dcazTight")) + mask |= kDCAzTight; + else if (std::abs(track.dcazpv) < cfgTrackSels->get("dcazMid")) + mask |= kDCAzMid; + if (std::abs(track.tpcnsigma) < cfgTrackSels->get("tpcNsigmaTight")) + mask |= kTPCPIDTight; + else if (std::abs(track.tpcnsigma) < cfgTrackSels->get("tpcNsigmaMid")) + mask |= kTPCPIDMid; + if (std::abs(track.itsnsigma) < cfgTrackSels->get("itsNsigmaTight")) + mask |= kITSPIDTight; + else if (std::abs(track.itsnsigma) < cfgTrackSels->get("itsNsigmaMid")) + mask |= kITSPIDMid; + return mask; + } + + void init(o2::framework::InitContext&) + { + + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + // lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get("GLO/Param/MatLUT")); + + fitter.setPropagateToPCA(true); + fitter.setMaxR(200.); + fitter.setMinParamChange(1e-3); + fitter.setMinRelChi2Change(0.9); + fitter.setMaxDZIni(4); + fitter.setMaxDXYIni(1); + fitter.setMaxChi2(1e9); + fitter.setUseAbsDCA(true); + fitter.setWeightedFinalPCA(false); + int mat{static_cast(cfgMaterialCorrection)}; + fitter.setMatCorrType(static_cast(mat)); + + // event QA + histos.add("QA/zVtx", ";#it{z}_{vtx} (cm);Entries", HistType::kTH1F, {zVtxAxis}); + if (doprocessRun3) { + histos.add("QA/PvMultVsCent", ";Centrality T0C (%);#it{N}_{PV contributors};", HistType::kTH2F, {centAxis, multAxis}); + histos.add("QA/MultVsCent", ";Centrality T0C (%);Multiplicity T0C;", HistType::kTH2F, {centAxis, multFt0Axis}); + } else if (doprocessRun2 || doprocessMiniRun2 || doprocessMcRun2 || doprocessMiniMcRun2) { + histos.add("QA/V0MvsCL0", ";Centrality CL0 (%);Centrality V0M (%)", HistType::kTH2F, {centAxis, centAxis}); + histos.add("QA/trackletsVsV0M", ";Centrality CL0 (%);Centrality V0M (%)", HistType::kTH2F, {centAxis, multAxis}); + histos.add("QA/nTrklCorrelation", ";Tracklets |#eta| < 0.6; Tracklets |#eta| > 0.7", HistType::kTH2D, {{201, -0.5, 200.5}, {201, -0.5, 200.5}}); + histos.add("QA/TrklEta", ";Tracklets #eta; Entries", HistType::kTH1D, {{100, -3., 3.}}); + } + + // v0 QA + histos.add("QA/massLambda", ";Centrality (%);#it{p}_{T} (GeV/#it{c});#it{M}(p + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH3F, {centAxis, momAxis, massLambdaAxis}); + + // antid and antip QA + histos.add("QA/tpcSignal", ";#it{p}_{TPC} (GeV/#it{c});d#it{E}/d#it{x}_{TPC} (a.u.)", HistType::kTH2F, {momAxis, tpcAxis}); + histos.add("QA/tpcSignalPr", ";#it{p}_{TPC} (GeV/#it{c});d#it{E}/d#it{x}_{TPC} (a.u.)", HistType::kTH2F, {momAxis, tpcAxis}); + histos.add("QA/itsSignal", ";#it{p}_{glo} (GeV/#it{c});d#it{E}/d#it{x}_{ITS} (a.u.)", HistType::kTH2F, {momAxis, tpcAxis}); + tofMass[0] = histos.add("QA/tofMass_p", ";Centrality (%);#it{p}_{T} (GeV/#it{c});Mass (GeV/#it{c}^{2});Entries", HistType::kTH3F, {centAxis, momAxis, tofMassAxis}); + tofMass[1] = histos.add("QA/tofMass_d", ";Centrality (%);#it{p}_{T} (GeV/#it{c});Mass (GeV/#it{c}^{2});Entries", HistType::kTH3F, {centAxis, momAxis, tofMassAxis}); + + ptMin = std::array{antipPtMin, antidPtMin}; + ptMax = std::array{antipPtMax, antidPtMax}; + ptTof = std::array{antipPtTof, antidPtTof}; + + nSigmaTpcCutLow = std::array{antipNsigmaTpcCutLow, antidNsigmaTpcCutLow}; + nSigmaTpcCutUp = std::array{antipNsigmaTpcCutUp, antidNsigmaTpcCutUp}; + tpcInnerParamMax = std::array{antipTpcInnerParamMax, antidTpcInnerParamMax}; + tofMassMax = std::array{antipTofMassMax, antidTofMassMax}; + } + + template + auto tracksSlice(T const& tracksAll, uint64_t const& collId) + { + if (doprocessRun3 || doprocessMcRun3) + return tracksAll.sliceBy(perCollisionTracksFullIU, collId); + else if (doprocessRun2 || doprocessMcRun2) + return tracksAll.sliceBy(perCollisionTracksFull, collId); + else + return tracksAll.sliceBy(perCollisionTracksFullPID, collId); + } + + template + void fillRecoEvent(C const& collision, T const& tracksAll, aod::V0s const& V0s, float const& centrality) + { + auto tracks = tracksSlice(tracksAll, collision.globalIndex()); + candidateTracks[0].clear(); + candidateTracks[1].clear(); + candidateV0s.clear(); + + gpu::gpustd::array dcaInfo; + uint8_t nTracklets[2]{0, 0}; + for (const auto& track : tracks) { + + if (track.trackType() == 255 && std::abs(track.eta()) < 1.2) { // tracklet + if (std::abs(track.eta()) < 0.6) + nTracklets[0]++; + else if (std::abs(track.eta()) > 0.7) + nTracklets[1]++; + } + + if (!selectTrack(track)) { + continue; + } + + auto trackParCov = getTrackParCov(track); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParCov, 2.f, fitter.getMatCorrType(), &dcaInfo); + auto dca = std::hypot(dcaInfo[0], dcaInfo[1]); + auto trackPt = trackParCov.getPt(); + auto trackEta = trackParCov.getEta(); + if (dca > cfgDcaSels->get("dca")) { // dca + continue; + } + if (std::abs(dcaInfo[1]) > cfgDcaSels->get("dcaz")) { // dcaz + continue; + } + if (std::abs(dcaInfo[0]) > cfgDcaSels->get("dcaxy") * (constDCASel ? 1. : dcaSigma(track.pt()))) { // dcaxy + continue; + } + histos.fill(HIST("QA/tpcSignal"), track.tpcInnerParam(), track.tpcSignal()); + + for (int iP{0}; iP < kNpart; ++iP) { + if (trackPt < ptMin[iP] || trackPt > ptMax[iP]) { + continue; + } + + if (doprocessRun3 || doprocessMcRun3) { + float cosL = 1 / std::sqrt(1.f + track.tgl() * track.tgl()); + if (iP && getITSClSize(track) * cosL < antidItsClsSizeCut && trackPt < antidPtItsClsSizeCut) { + continue; + } + } + + double expBethe{tpc::BetheBlochAleph(static_cast(track.tpcInnerParam() / partMass[iP]), cfgBetheBlochParams->get(iP, "p0"), cfgBetheBlochParams->get(iP, "p1"), cfgBetheBlochParams->get(iP, "p2"), cfgBetheBlochParams->get(iP, "p3"), cfgBetheBlochParams->get(iP, "p4"))}; + double expSigma{expBethe * cfgBetheBlochParams->get(iP, "resolution")}; + auto nSigmaTPC = static_cast((track.tpcSignal() - expBethe) / expSigma); + + float beta{track.hasTOF() ? track.length() / (track.tofSignal() - track.tofEvTime()) * o2::constants::physics::invLightSpeedCm2PS : -999.f}; + beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); + float mass{track.tpcInnerParam() * std::sqrt(1.f / (beta * beta) - 1.f)}; + bool hasTof = track.hasTOF() && track.tofChi2() < 3; + + if (trackPt <= ptTof[iP] || (trackPt > ptTof[iP] && hasTof && std::abs(mass - partMass[iP]) < tofMassMaxQA)) { // for QA histograms + if (nSigmaTPC > nSigmaTpcCutLow[iP] && nSigmaTPC < nSigmaTpcCutUp[iP]) { + tofMass[iP]->Fill(centrality, trackPt, mass); + } + } + + if (nSigmaTPC < nSigmaTpcCutLow[iP] || nSigmaTPC > nSigmaTpcCutUp[iP]) { + continue; + } + + // temporary cut to reject fake matches (run 3) + if (track.tpcInnerParam() < tpcInnerParamMax[iP]) { + continue; + } + if (trackPt > ptTof[iP] && !hasTof) { + continue; + } + + if (trackPt <= ptTof[iP] || (trackPt > ptTof[iP] && hasTof && std::abs(mass - partMass[iP]) < tofMassMax[iP])) { + CandidateTrack candTrack; + candTrack.pt = track.sign() > 0. ? trackPt : -trackPt; + candTrack.eta = trackEta; + candTrack.mass = iP; + candTrack.dcapv = dca; + candTrack.dcaxypv = dcaInfo[0]; + candTrack.dcazpv = dcaInfo[1]; + candTrack.tpcchi2 = track.tpcChi2NCl(); + candTrack.tpcncls = track.tpcNClsFound(); + candTrack.tpcnsigma = nSigmaTPC; + candTrack.tofmass = hasTof ? mass : -999.f; + candTrack.globalIndex = track.globalIndex(); + candTrack.outerPID = nSigmaTPC; + candidateTracks[iP].push_back(candTrack); + } + } + } + if (doprocessRun2 || doprocessMcRun2 || doprocessMiniRun2 || doprocessMiniMcRun2) { + histos.fill(HIST("QA/nTrklCorrelation"), nTracklets[0], nTracklets[1]); + nTrackletsColl = nTracklets[1]; + } + + if (lambdaPtMax > lambdaPtMin) { + std::vector trkId; + for (const auto& v0 : V0s) { + auto posTrack = v0.posTrack_as(); + auto negTrack = v0.negTrack_as(); + + bool posSelect = selectV0Daughter(posTrack); + bool negSelect = selectV0Daughter(negTrack); + if (!posSelect || !negSelect) + continue; + + if (doprocessRun2 || doprocessMiniRun2 || doprocessMcRun2 || doprocessMiniMcRun2) { + bool checkPosPileUp = posTrack.hasTOF() || (posTrack.flags() & o2::aod::track::ITSrefit); + bool checkNegPileUp = negTrack.hasTOF() || (negTrack.flags() & o2::aod::track::ITSrefit); + if (!checkPosPileUp && !checkNegPileUp) { + continue; + } + } + + auto posTrackCov = getTrackParCov(posTrack); + auto negTrackCov = getTrackParCov(negTrack); + + int nCand = 0; + try { + nCand = fitter.process(posTrackCov, negTrackCov); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call!"; + continue; + } + if (nCand == 0) { + continue; + } + + auto& posPropTrack = fitter.getTrack(0); + auto& negPropTrack = fitter.getTrack(1); + + std::array momPos; + std::array momNeg; + std::array momV0; + posPropTrack.getPxPyPzGlo(momPos); + negPropTrack.getPxPyPzGlo(momNeg); + momTotXYZ(momV0, momPos, momNeg); + + auto ptV0 = std::hypot(momV0[0], momV0[1]); + if (ptV0 < lambdaPtMin || ptV0 > lambdaPtMax) { + continue; + } + + auto etaV0 = etaFromMom(momPos, momNeg); + if (std::abs(etaV0) > etaMax) { + continue; + } + + auto alpha = alphaAP(momV0, momPos, momNeg); + bool matter = alpha > 0; + auto massPos = matter ? o2::constants::physics::MassProton : o2::constants::physics::MassPionCharged; + auto massNeg = matter ? o2::constants::physics::MassPionCharged : o2::constants::physics::MassProton; + auto mLambda = invMass2Body(momV0, momPos, momNeg, massPos, massNeg); + auto mK0Short = invMass2Body(momV0, momPos, momNeg, o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged); + + // pid selections + double expBethePos{tpc::BetheBlochAleph(static_cast(posTrack.tpcInnerParam() / massPos), cfgBetheBlochParams->get("p0"), cfgBetheBlochParams->get("p1"), cfgBetheBlochParams->get("p2"), cfgBetheBlochParams->get("p3"), cfgBetheBlochParams->get("p4"))}; + double expSigmaPos{expBethePos * cfgBetheBlochParams->get("resolution")}; + auto nSigmaTPCPos = static_cast((posTrack.tpcSignal() - expBethePos) / expSigmaPos); + double expBetheNeg{tpc::BetheBlochAleph(static_cast(negTrack.tpcInnerParam() / massNeg), cfgBetheBlochParams->get("p0"), cfgBetheBlochParams->get("p1"), cfgBetheBlochParams->get("p2"), cfgBetheBlochParams->get("p3"), cfgBetheBlochParams->get("p4"))}; + double expSigmaNeg{expBetheNeg * cfgBetheBlochParams->get("resolution")}; + auto nSigmaTPCNeg = static_cast((negTrack.tpcSignal() - expBetheNeg) / expSigmaNeg); + float tpcSigPr = matter ? posTrack.tpcSignal() : negTrack.tpcSignal(); + + if (std::abs(nSigmaTPCPos) > v0setting_nsigmatpc || std::abs(nSigmaTPCNeg) > v0setting_nsigmatpc) { + continue; + } + + // veto on K0s mass + if (std::abs(mK0Short - o2::constants::physics::MassK0Short) < vetoMassK0Short) { + continue; + } + + float dcaV0dau = std::sqrt(fitter.getChi2AtPCACandidate()); + if (dcaV0dau > v0setting_dcav0dau) { + continue; + } + + std::array primVtx = {collision.posX(), collision.posY(), collision.posZ()}; + const auto& vtx = fitter.getPCACandidate(); + + float radiusV0 = std::hypot(vtx[0], vtx[1]); + if (radiusV0 < v0setting_radius || radiusV0 > v0radiusMax) { + continue; + } + + float dcaV0Pv = CalculateDCAStraightToPV( + vtx[0], vtx[1], vtx[2], + momPos[0] + momNeg[0], + momPos[1] + momNeg[1], + momPos[2] + momNeg[2], + collision.posX(), collision.posY(), collision.posZ()); + if (std::abs(dcaV0Pv) > v0setting_dcav0pv) { + continue; + } + + double cosPA = RecoDecay::cpa(primVtx, vtx, momV0); + if (cosPA < v0setting_cospa) { + continue; + } + + auto ptotal = RecoDecay::sqrtSumOfSquares(momV0[0], momV0[1], momV0[2]); + auto lengthTraveled = RecoDecay::sqrtSumOfSquares(vtx[0] - primVtx[0], vtx[1] - primVtx[1], vtx[2] - primVtx[2]); + float ML2P_Lambda = o2::constants::physics::MassLambda * lengthTraveled / ptotal; + if (ML2P_Lambda > v0setting_lifetime) { + continue; + } + + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, posTrackCov, 2.f, fitter.getMatCorrType(), &dcaInfo); + auto posDcaToPv = std::hypot(dcaInfo[0], dcaInfo[1]); + if (posDcaToPv < v0setting_dcadaughtopv && std::abs(dcaInfo[0]) < v0setting_dcadaughtopv) { + continue; + } + + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, negTrackCov, 2.f, fitter.getMatCorrType(), &dcaInfo); + auto negDcaToPv = std::hypot(dcaInfo[0], dcaInfo[1]); + if (negDcaToPv < v0setting_dcadaughtopv && std::abs(dcaInfo[0]) < v0setting_dcadaughtopv) { + continue; + } + + if (std::abs(mLambda - o2::constants::physics::MassLambda0) > lambdaMassCut) { // for QA histograms + continue; + } + histos.fill(HIST("QA/massLambda"), centrality, ptV0, mLambda); + + histos.fill(HIST("QA/tpcSignalPr"), matter > 0. ? posTrack.tpcInnerParam() : negTrack.tpcInnerParam(), tpcSigPr); + + CandidateV0 candV0; + candV0.pt = matter > 0. ? ptV0 : -ptV0; + candV0.eta = etaV0; + candV0.mass = mLambda; + candV0.cpa = cosPA; + candV0.dcav0daugh = dcaV0dau; + candV0.dcav0pv = dcaV0Pv; + candV0.dcanegpv = negDcaToPv; + candV0.dcapospv = posDcaToPv; + candV0.tpcnsigmaneg = nSigmaTPCNeg; + candV0.tpcnsigmapos = nSigmaTPCPos; + candV0.globalIndexPos = posTrack.globalIndex(); + candV0.globalIndexNeg = negTrack.globalIndex(); + candidateV0s.push_back(candV0); + } + } + } + + template + void fillMcEvent(C const& collision, T const& tracks, aod::V0s const& V0s, float const& centrality, aod::McParticles const& particlesMC, aod::McTrackLabels const& mcLabels) + { + fillRecoEvent(collision, tracks, V0s, centrality); + + for (int iP{0}; iP < kNpart; ++iP) { + for (auto& candidateTrack : candidateTracks[iP]) { + candidateTrack.isreco = true; + + auto mcLab = mcLabels.rawIteratorAt(candidateTrack.globalIndex); + + if (mcLab.mcParticleId() < -1 || mcLab.mcParticleId() >= particlesMC.size()) { + continue; + } + if (mcLab.has_mcParticle()) { + auto mcTrack = mcLab.template mcParticle_as(); + if (std::abs(mcTrack.pdgCode()) != partPdg[iP]) + continue; + if (((mcTrack.flags() & 0x8) && (doprocessMcRun2 || doprocessMiniMcRun2)) || (mcTrack.flags() & 0x2) || ((mcTrack.flags() & 0x1) && !doprocessMiniMcRun2)) + continue; + + if (!mcTrack.isPhysicalPrimary() && !doprocessMiniMcRun2) + continue; + if (mcTrack.isPhysicalPrimary()) + candidateTrack.pdgcodemoth = PartTypes::kPhysPrim; + else if (mcTrack.has_mothers() && iP == 0) + candidateTrack.pdgcodemoth = getPartTypeMother(mcTrack); + + auto genPt = std::hypot(mcTrack.px(), mcTrack.py()); + candidateTrack.pdgcode = mcTrack.pdgCode(); + candidateTrack.genpt = genPt; + candidateTrack.geneta = mcTrack.eta(); + candidateTrack.mcIndex = mcTrack.globalIndex(); + } + } + } + for (auto& candidateV0 : candidateV0s) { + candidateV0.isreco = true; + auto mcLabPos = mcLabels.rawIteratorAt(candidateV0.globalIndexPos); + auto mcLabNeg = mcLabels.rawIteratorAt(candidateV0.globalIndexNeg); + + if (mcLabPos.has_mcParticle() && mcLabNeg.has_mcParticle()) { + auto mcTrackPos = mcLabPos.template mcParticle_as(); + auto mcTrackNeg = mcLabNeg.template mcParticle_as(); + if (mcTrackPos.has_mothers() && mcTrackNeg.has_mothers()) { + for (auto& negMother : mcTrackNeg.template mothers_as()) { + for (auto& posMother : mcTrackPos.template mothers_as()) { + if (posMother.globalIndex() != negMother.globalIndex()) + continue; + if (!((mcTrackPos.pdgCode() == 2212 && mcTrackNeg.pdgCode() == -211) || (mcTrackPos.pdgCode() == 211 && mcTrackNeg.pdgCode() == -2212))) + continue; + if (std::abs(posMother.pdgCode()) != 3122) { + continue; + } + if (!posMother.isPhysicalPrimary() && !posMother.has_mothers()) + continue; + if (((posMother.flags() & 0x8) && (doprocessMcRun2 || doprocessMiniMcRun2)) || (posMother.flags() & 0x2) || (posMother.flags() & 0x1)) + continue; + + auto genPt = std::hypot(posMother.px(), posMother.py()); + candidateV0.pdgcode = posMother.pdgCode(); + candidateV0.genpt = genPt; + candidateV0.geneta = posMother.eta(); + candidateV0.mcIndex = posMother.globalIndex(); + } + } + } + } + } + } + + void fillMcGen(aod::McParticles const& mcParticles, aod::McTrackLabels const& /*mcLab*/, uint64_t const& collisionId) + { + auto mcParticles_thisCollision = mcParticles.sliceBy(perCollisionMcParts, collisionId); + for (auto& mcPart : mcParticles_thisCollision) { + auto genEta = mcPart.eta(); + if (std::abs(genEta) > etaMax) { + continue; + } + if (((mcPart.flags() & 0x8) && (doprocessMcRun2 || doprocessMiniMcRun2)) || (mcPart.flags() & 0x2) || ((mcPart.flags() & 0x1) && !doprocessMiniMcRun2)) + continue; + auto pdgCode = mcPart.pdgCode(); + if (std::abs(pdgCode) == 3122) { + if (!mcPart.isPhysicalPrimary() && !mcPart.has_mothers()) + continue; + bool foundPr = false; + for (auto& mcDaught : mcPart.daughters_as()) { + if (std::abs(mcDaught.pdgCode()) == 2212) { + foundPr = true; + break; + } + } + if (!foundPr) { + continue; + } + auto genPt = std::hypot(mcPart.px(), mcPart.py()); + CandidateV0 candV0; + candV0.genpt = genPt; + candV0.geneta = mcPart.eta(); + candV0.pdgcode = pdgCode; + auto it = find_if(candidateV0s.begin(), candidateV0s.end(), [&](CandidateV0 v0) { return v0.mcIndex == mcPart.globalIndex(); }); + if (it != candidateV0s.end()) { + continue; + } else { + LOGF(debug, "not found!"); + candidateV0s.emplace_back(candV0); + } + } else if (std::abs(pdgCode) == partPdg[0] || std::abs(pdgCode) == partPdg[1]) { + int iP = 1; + if (std::abs(pdgCode) == partPdg[0]) { + iP = 0; + } + if ((!mcPart.isPhysicalPrimary() && !doprocessMiniMcRun2)) + continue; + auto genPt = std::hypot(mcPart.px(), mcPart.py()); + CandidateTrack candTrack; + candTrack.genpt = genPt; + candTrack.geneta = mcPart.eta(); + candTrack.pdgcode = pdgCode; + if (mcPart.isPhysicalPrimary()) + candTrack.pdgcodemoth = PartTypes::kPhysPrim; + else if (mcPart.has_mothers() && iP == 0) + candTrack.pdgcodemoth = getPartTypeMother(mcPart); + + auto it = find_if(candidateTracks[iP].begin(), candidateTracks[iP].end(), [&](CandidateTrack trk) { return trk.mcIndex == mcPart.globalIndex(); }); + if (it != candidateTracks[iP].end()) { + continue; + } else { + candidateTracks[iP].emplace_back(candTrack); + } + } + } + } + + void processRun3(soa::Join const& collisions, TracksFullIU const& tracks, aod::V0s const& V0s, aod::BCsWithTimestamps const&) + { + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + + if (!collision.sel8()) + continue; + + if (std::abs(collision.posZ()) > zVtxMax) + continue; + + if (!collision.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + continue; + + histos.fill(HIST("QA/zVtx"), collision.posZ()); + + const uint64_t collIdx = collision.globalIndex(); + auto V0Table_thisCollision = V0s.sliceBy(perCollisionV0, collIdx); + V0Table_thisCollision.bindExternalIndices(&tracks); + + auto multiplicity = collision.multFT0C(); + auto centrality = collision.centFT0C(); + fillRecoEvent(collision, tracks, V0Table_thisCollision, centrality); + + histos.fill(HIST("QA/PvMultVsCent"), centrality, collision.numContrib()); + histos.fill(HIST("QA/MultVsCent"), centrality, multiplicity); + + collisionEbyeTable(centrality, collision.posZ()); + + for (auto& candidateV0 : candidateV0s) { + lambdaEbyeTable( + collisionEbyeTable.lastIndex(), + candidateV0.pt, + candidateV0.eta, + candidateV0.mass, + candidateV0.dcav0pv, + // candidateV0.dcanegpv, + // candidateV0.dcapospv, + candidateV0.dcav0daugh, + candidateV0.cpa, + // candidateV0.tpcnsigmaneg, + // candidateV0.tpcnsigmapos, + candidateV0.globalIndexNeg, + candidateV0.globalIndexPos); + } + + for (int iP{0}; iP < kNpart; ++iP) { + for (auto& candidateTrack : candidateTracks[iP]) { // deuterons + protons + nucleiEbyeTable( + collisionEbyeTable.lastIndex(), + candidateTrack.pt, + candidateTrack.eta, + candidateTrack.mass, + candidateTrack.dcapv, + candidateTrack.tpcncls, + candidateTrack.tpcnsigma, + candidateTrack.tofmass); + } + } + } + } + PROCESS_SWITCH(ebyeMaker, processRun3, "process (Run 3)", false); + + void processRun2(soa::Join const& collisions, TracksFull const& tracks, aod::V0s const& V0s, aod::FV0As const& fv0as, aod::FV0Cs const& fv0cs, BCsWithRun2Info const&) + { + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + + if (std::abs(collision.posZ()) > zVtxMax) + continue; + + if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kAliEventCutsAccepted))) + continue; + + if (kUsePileUpCut && !(bc.eventCuts() & BIT(aod::Run2EventCuts::kTPCPileUp))) + continue; + + float v0m = getV0M(bc.globalIndex(), collision.posZ(), fv0as, fv0cs); + float cV0M = 105.f; + if (Run2V0MInfo.mCalibrationStored) { + cV0M = Run2V0MInfo.mhMultSelCalib->GetBinContent(Run2V0MInfo.mhMultSelCalib->FindFixBin(v0m)); + if (!(collision.sel7() && collision.alias_bit(kINT7)) && (!kINT7Intervals || (kINT7Intervals && ((cV0M >= 10 && cV0M < 30) || cV0M > 50)))) + continue; + } + + auto centralityCl0 = 105.0f; + if (Run2CL0Info.mCalibrationStored) { + float cl0m = bc.spdClustersL0() * Run2CL0Info.mhVtxAmpCorr->GetBinContent(Run2CL0Info.mhVtxAmpCorr->FindFixBin(collision.posZ())); + centralityCl0 = Run2CL0Info.mhMultSelCalib->GetBinContent(Run2CL0Info.mhMultSelCalib->FindFixBin(cl0m)); + } + if (kUseEstimatorsCorrelationCut) { + const auto& x = centralityCl0; + const double center = estimatorsCorrelationCoef[0] + estimatorsCorrelationCoef[1] * x; + const double sigma = estimatorsSigmaPars[0] + estimatorsSigmaPars[1] * x + estimatorsSigmaPars[2] * std::pow(x, 2) + estimatorsSigmaPars[3] * std::pow(x, 3); + if (cV0M < center - deltaEstimatorNsigma[0] * sigma || cV0M > center + deltaEstimatorNsigma[1] * sigma) { + continue; + } + } + + histos.fill(HIST("QA/zVtx"), collision.posZ()); + + const uint64_t collIdx = collision.globalIndex(); + auto V0Table_thisCollision = V0s.sliceBy(perCollisionV0, collIdx); + V0Table_thisCollision.bindExternalIndices(&tracks); + + auto multTracklets = collision.multTracklets(); + fillRecoEvent(collision, tracks, V0Table_thisCollision, cV0M); + + histos.fill(HIST("QA/V0MvsCL0"), centralityCl0, cV0M); + histos.fill(HIST("QA/trackletsVsV0M"), cV0M, multTracklets); + + collisionEbyeTable(cV0M, collision.posZ()); + + for (auto& candidateV0 : candidateV0s) { + lambdaEbyeTable( + collisionEbyeTable.lastIndex(), + candidateV0.pt, + candidateV0.eta, + candidateV0.mass, + candidateV0.dcav0pv, + // candidateV0.dcanegpv, + // candidateV0.dcapospv, + candidateV0.dcav0daugh, + candidateV0.cpa, + // candidateV0.tpcnsigmaneg, + // candidateV0.tpcnsigmapos, + candidateV0.globalIndexNeg, + candidateV0.globalIndexPos); + } + + for (int iP{0}; iP < kNpart; ++iP) { + for (auto& candidateTrack : candidateTracks[iP]) { // deuterons + protons + nucleiEbyeTable( + collisionEbyeTable.lastIndex(), + candidateTrack.pt, + candidateTrack.eta, + candidateTrack.mass, + candidateTrack.dcapv, + candidateTrack.tpcncls, + candidateTrack.tpcnsigma, + candidateTrack.tofmass); + } + } + } + } + PROCESS_SWITCH(ebyeMaker, processRun2, "process (Run 2)", false); + + void processMiniRun2(soa::Join const& collisions, TracksFullPID const& tracks, aod::Run2TrackExtras const& trackExtraRun2, aod::FV0As const& fv0as, aod::FV0Cs const& fv0cs, aod::V0s const& V0s, BCsWithRun2Info const&) + { + + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + + if (std::abs(collision.posZ()) > zVtxMax) + continue; + + if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kINELgtZERO))) + continue; + + if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kAliEventCutsAccepted))) + continue; + + if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kPileUpMV) || bc.eventCuts() & BIT(aod::Run2EventCuts::kTPCPileUp)) && kUsePileUpCut) + continue; + + float v0m = getV0M(bc.globalIndex(), collision.posZ(), fv0as, fv0cs); + float cV0M = 105.f; + if (Run2V0MInfo.mCalibrationStored) { + cV0M = Run2V0MInfo.mhMultSelCalib->GetBinContent(Run2V0MInfo.mhMultSelCalib->FindFixBin(v0m)); + } + + histos.fill(HIST("QA/zVtx"), collision.posZ()); + + const uint64_t collIdx = collision.globalIndex(); + auto V0Table_thisCollision = V0s.sliceBy(perCollisionV0, collIdx); + V0Table_thisCollision.bindExternalIndices(&tracks); + + fillRecoEvent(collision, tracks, V0Table_thisCollision, cV0M); + + uint8_t trigger = collision.alias_bit(kINT7) ? 0x1 : 0x0; + for (auto& classId : classIds) { + if (bc.triggerMask() & BIT(classId)) { + trigger |= 0x2; + cV0M = cV0M < 104.f ? cV0M * 100. : cV0M; + break; + } + } + if (trigger == 0x0) { + continue; + } + if (triggerCut != 0x0 && (trigger & triggerCut) != triggerCut) { + continue; + } + miniCollTable(static_cast(collision.posZ() * 10), trigger, nTrackletsColl, cV0M); + + for (auto& candidateTrack : candidateTracks[0]) { // protons + auto tk = tracks.rawIteratorAt(candidateTrack.globalIndex); + float outerPID = getOuterPID(tk); + auto [itsSignal, nSigmaITS] = getITSSignal(tk, trackExtraRun2); + histos.fill(HIST("QA/itsSignal"), tk.p(), itsSignal); + candidateTrack.itsnsigma = nSigmaITS; + candidateTrack.outerPID = tk.pt() < antipPtTof ? candidateTrack.outerPID : outerPID; + int selMask = getTrackSelMask(candidateTrack); + if (candidateTrack.outerPID < outerPIDMin) + continue; + miniTrkTable( + miniCollTable.lastIndex(), + candidateTrack.pt, + static_cast(candidateTrack.eta * 100), + selMask, + candidateTrack.outerPID); + } + } + } + PROCESS_SWITCH(ebyeMaker, processMiniRun2, "process mini tables(Run 2)", false); + + void processMcRun3(soa::Join const& collisions, aod::McCollisions const& /*mcCollisions*/, TracksFullIU const& tracks, aod::V0s const& V0s, aod::McParticles const& mcParticles, aod::McTrackLabels const& mcLab, aod::BCsWithTimestamps const&) + { + for (auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + + if (!collision.sel8()) + continue; + + if (!collision.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + continue; + + if (std::abs(collision.posZ()) > zVtxMax) + continue; + + auto centrality = collision.centFT0C(); + + histos.fill(HIST("QA/zVtx"), collision.posZ()); + + const uint64_t collIdx = collision.globalIndex(); + auto V0Table_thisCollision = V0s.sliceBy(perCollisionV0, collIdx); + V0Table_thisCollision.bindExternalIndices(&tracks); + + fillMcEvent(collision, tracks, V0Table_thisCollision, centrality, mcParticles, mcLab); + fillMcGen(mcParticles, mcLab, collision.mcCollisionId()); + + collisionEbyeTable(centrality, collision.posZ()); + + for (auto& candidateV0 : candidateV0s) { + mcLambdaEbyeTable( + collisionEbyeTable.lastIndex(), + candidateV0.pt, + candidateV0.eta, + candidateV0.mass, + candidateV0.dcav0pv, + // candidateV0.dcanegpv, + // candidateV0.dcapospv, + candidateV0.dcav0daugh, + candidateV0.cpa, + // candidateV0.tpcnsigmaneg, + // candidateV0.tpcnsigmapos, + candidateV0.globalIndexNeg, + candidateV0.globalIndexPos, + candidateV0.genpt, + candidateV0.geneta, + candidateV0.pdgcode, + candidateV0.isreco); + } + + for (int iP{0}; iP < kNpart; ++iP) { + for (auto& candidateTrack : candidateTracks[iP]) { // deuterons + protons + mcNucleiEbyeTable( + collisionEbyeTable.lastIndex(), + candidateTrack.pt, + candidateTrack.eta, + candidateTrack.mass, + candidateTrack.dcapv, + candidateTrack.tpcncls, + candidateTrack.tpcnsigma, + candidateTrack.tofmass, + candidateTrack.genpt, + candidateTrack.geneta, + candidateTrack.pdgcode, + candidateTrack.isreco); + } + } + } + } + PROCESS_SWITCH(ebyeMaker, processMcRun3, "process MC (Run 3)", false); + + void processMcRun2(soa::Join const& collisions, aod::McCollisions const& /*mcCollisions*/, TracksFull const& tracks, aod::V0s const& V0s, aod::FV0As const& fv0as, aod::FV0Cs const& fv0cs, aod::McParticles const& mcParticles, aod::McTrackLabels const& mcLab, BCsWithRun2Info const&) + { + for (auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + + if (std::abs(collision.posZ()) > zVtxMax) + continue; + + if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kAliEventCutsAccepted))) + continue; + + float v0m = getV0M(bc.globalIndex(), collision.posZ(), fv0as, fv0cs); + float cV0M = 105.f; + if (Run2V0MInfo.mCalibrationStored) { + cV0M = Run2V0MInfo.mhMultSelCalib->GetBinContent(Run2V0MInfo.mhMultSelCalib->FindFixBin(v0m)); + } + + histos.fill(HIST("QA/zVtx"), collision.posZ()); + + const uint64_t collIdx = collision.globalIndex(); + auto V0Table_thisCollision = V0s.sliceBy(perCollisionV0, collIdx); + V0Table_thisCollision.bindExternalIndices(&tracks); + + fillMcEvent(collision, tracks, V0Table_thisCollision, cV0M, mcParticles, mcLab); + fillMcGen(mcParticles, mcLab, collision.mcCollisionId()); + + collisionEbyeTable(cV0M, collision.posZ()); + + for (auto& candidateV0 : candidateV0s) { + mcLambdaEbyeTable( + collisionEbyeTable.lastIndex(), + candidateV0.pt, + candidateV0.eta, + candidateV0.mass, + candidateV0.dcav0pv, + // candidateV0.dcanegpv, + // candidateV0.dcapospv, + candidateV0.dcav0daugh, + candidateV0.cpa, + // candidateV0.tpcnsigmaneg, + // candidateV0.tpcnsigmapos, + candidateV0.globalIndexNeg, + candidateV0.globalIndexPos, + candidateV0.genpt, + candidateV0.geneta, + candidateV0.pdgcode, + candidateV0.isreco); + } + + for (int iP{0}; iP < kNpart; ++iP) { + for (auto& candidateTrack : candidateTracks[iP]) { // deuterons + protons + mcNucleiEbyeTable( + collisionEbyeTable.lastIndex(), + candidateTrack.pt, + candidateTrack.eta, + candidateTrack.mass, + candidateTrack.dcapv, + candidateTrack.tpcncls, + candidateTrack.tpcnsigma, + candidateTrack.tofmass, + candidateTrack.genpt, + candidateTrack.geneta, + candidateTrack.pdgcode, + candidateTrack.isreco); + } + } + } + } + PROCESS_SWITCH(ebyeMaker, processMcRun2, "process MC (Run 2)", false); + + void processMiniMcRun2(soa::Join const& collisions, aod::McCollisions const& /*mcCollisions*/, TracksFullPID const& tracks, aod::Run2TrackExtras const& trackExtraRun2, aod::FV0As const& fv0as, aod::FV0Cs const& fv0cs, aod::V0s const& V0s, aod::McParticles const& mcParticles, aod::McTrackLabels const& mcLab, BCsWithRun2Info const&) + { + + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + + if (std::abs(collision.posZ()) > zVtxMax) + continue; + + if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kAliEventCutsAccepted))) + continue; + + float v0m = getV0M(bc.globalIndex(), collision.posZ(), fv0as, fv0cs); + float cV0M = 105.f; + if (Run2V0MInfo.mCalibrationStored) { + cV0M = Run2V0MInfo.mhMultSelCalib->GetBinContent(Run2V0MInfo.mhMultSelCalib->FindFixBin(v0m)); + } + + histos.fill(HIST("QA/zVtx"), collision.posZ()); + + const uint64_t collIdx = collision.globalIndex(); + auto V0Table_thisCollision = V0s.sliceBy(perCollisionV0, collIdx); + V0Table_thisCollision.bindExternalIndices(&tracks); + + fillMcEvent(collision, tracks, V0Table_thisCollision, cV0M, mcParticles, mcLab); + fillMcGen(mcParticles, mcLab, collision.mcCollisionId()); + + miniCollTable(static_cast(collision.posZ() * 10), 0x0, nTrackletsColl, cV0M); + + for (auto& candidateTrack : candidateTracks[0]) { // protons + int selMask = -1; + if (candidateTrack.isreco) { + auto tk = tracks.rawIteratorAt(candidateTrack.globalIndex); + float outerPID = getOuterPID(tk); + auto [itsSignal, nSigmaITS] = getITSSignal(tk, trackExtraRun2); + histos.fill(HIST("QA/itsSignal"), tk.p(), itsSignal); + candidateTrack.itsnsigma = nSigmaITS; + candidateTrack.outerPID = tk.pt() < antipPtTof ? candidateTrack.outerPID : outerPID; + selMask = getTrackSelMask(candidateTrack); + // if (candidateTrack.outerPID < -4) + // continue; + if (candidateTrack.pdgcodemoth > 0) + selMask |= candidateTrack.pdgcodemoth; + } else if (candidateTrack.pdgcodemoth > 0) { + selMask = candidateTrack.pdgcodemoth; + } + if (selMask < 0) + continue; + mcMiniTrkTable( + miniCollTable.lastIndex(), + candidateTrack.pt, + static_cast(candidateTrack.eta * 100), + selMask, + candidateTrack.outerPID, + candidateTrack.pdgcode > 0 ? candidateTrack.genpt : -candidateTrack.genpt, + static_cast(candidateTrack.geneta * 100), + candidateTrack.isreco); + } + } + } + PROCESS_SWITCH(ebyeMaker, processMiniMcRun2, "process mini tables for mc(Run 2)", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx b/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx new file mode 100644 index 00000000000..f8aa89a0d35 --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx @@ -0,0 +1,1090 @@ +// 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. +// Analysis task for he3-hadron femto analysis + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include // std::prev + +#include "Framework/ASoAHelpers.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" + +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/PID/TPCPIDResponse.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTOFBase.h" + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "ReconstructionDataFormats/Track.h" + +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/LFhe3HadronTables.h" +#include "PWGLF/Utils/svPoolCreator.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; +using CollBracket = o2::math_utils::Bracket; + +using McIter = aod::McParticles::iterator; +using CollBracket = o2::math_utils::Bracket; +using CollisionsFull = soa::Join; +using CollisionsFullMC = soa::Join; +using TrackCandidates = soa::Join; +using TrackCandidatesMC = soa::Join; + +namespace +{ +constexpr double betheBlochDefault[1][6]{{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}}; +static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; + +// constexpr float he3Mass = o2::constants::physics::MassHelium3; +// constexpr float protonMass = o2::constants::physics::MassProton; +// constexpr float pionchargedMass = o2::constants::physics::MassPiPlus; +constexpr int li4PDG = 1000030040; +constexpr int prPDG = 2212; +constexpr int hePDG = 1000020030; +// constexpr int pichargedPDG = 211; + +enum Selections { + kNoCuts = 0, + kTrackCuts, + kPID, + kAll +}; + +} // namespace + +struct he3HadCandidate { + + float recoPtHe3() const { return signHe3 * std::hypot(momHe3[0], momHe3[1]); } + float recoPhiHe3() const { return std::atan2(momHe3[1], momHe3[0]); } + float recoEtaHe3() const { return std::asinh(momHe3[2] / std::abs(recoPtHe3())); } + float recoPtHad() const { return signHad * std::hypot(momHad[0], momHad[1]); } + float recoPhiHad() const { return std::atan2(momHad[1], momHad[0]); } + float recoEtaHad() const { return std::asinh(momHad[2] / std::abs(recoPtHad())); } + + std::array momHe3 = {99.f, 99.f, 99.f}; + std::array momHad = {99.f, 99.f, 99.f}; + + float signHe3 = 1.f; + float signHad = 1.f; + float invMass = -10.f; + float DCAxyHe3 = -10.f; + float DCAzHe3 = -10.f; + float DCAxyHad = -10.f; + float DCAzHad = -10.f; + + uint16_t tpcSignalHe3 = 0u; + uint16_t tpcSignalHad = 0u; + float momHe3TPC = -99.f; + float momHadTPC = -99.f; + uint8_t nTPCClustersHe3 = 0u; + uint8_t sharedClustersHe3 = 0u; + uint8_t sharedClustersHad = 0u; + float chi2TPCHe3 = -10.f; + float chi2TPCHad = -10.f; + float nSigmaHe3 = -10.f; + float nSigmaHad = -10.f; + uint32_t PIDtrkHe3 = 0xFFFFF; // PID in tracking + uint32_t PIDtrkHad = 0xFFFFF; + float massTOFHe3 = -10; + float massTOFHad = -10; + uint32_t itsClSizeHe3 = 0u; + uint32_t itsClSizeHad = 0u; + + uint8_t NClsITSHe3 = 0u; + uint8_t NClsITSHad = 0u; + float Chi2NClITSHe3 = -10.f; + float Chi2NClITSHad = -10.f; + + bool isBkgUS = false; // unlike sign + bool isBkgEM = false; // event mixing + + int trackIDHe3 = -1; + int trackIDHad = -1; + + float l4MassMC = -10.f; + float l4PtMC = -99.f; + float momHe3MC = -99.f; + float etaHe3MC = -99.f; + float phiHe3MC = -99.f; + float momHadMC = -99.f; + float etaHadMC = -99.f; + float phiHadMC = -99.f; + + // collision information + int32_t collisionID = 0; +}; + +struct he3hadronfemto { + + Produces m_outputDataTable; + Produces m_outputMCTable; + Produces m_outputMultiplicityTable; + + // Selections + Configurable setting_HadPDGCode{"setting_HadPDGCode", 211, "Hadron - PDG code"}; + Configurable setting_cutVertex{"setting_cutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable setting_cutRigidityMinHe3{"setting_cutRigidityMinHe3", 0.8f, "Minimum rigidity for He3"}; + Configurable setting_cutEta{"setting_cutEta", 0.9f, "Eta cut on daughter track"}; + Configurable setting_cutDCAxy{"setting_cutDCAxy", 2.0f, "DCAxy range for tracks"}; + Configurable setting_cutDCAz{"setting_cutDCAz", 2.0f, "DCAz range for tracks"}; + Configurable setting_cutChi2tpcLow{"setting_cutChi2tpcLow", 0.5f, "Low cut on TPC chi2"}; + Configurable setting_cutInvMass{"setting_cutInvMass", 0.0f, "Invariant mass upper limit"}; + Configurable setting_cutPtMinhe3Had{"setting_cutPtMinhe3Had", 0.0f, "Minimum PT cut on he3Had4"}; + Configurable setting_cutClSizeItsHe3{"setting_cutClSizeItsHe3", 4.0f, "Minimum ITS cluster size for He3"}; + Configurable setting_cutNCls{"setting_cutNCls", 5.0f, "Minimum ITS Ncluster for tracks"}; + Configurable setting_cutChi2NClITS{"setting_cutChi2NClITS", 36.f, "Maximum ITS Chi2 for tracks"}; + Configurable setting_cutNsigmaTPC{"setting_cutNsigmaTPC", 3.0f, "Value of the TPC Nsigma cut"}; + Configurable setting_cutNsigmaITS{"setting_cutNsigmaITS", -1.5f, "Value of the TPC Nsigma cut"}; + Configurable setting_cutPtMinTOFHad{"setting_cutPtMinTOFHad", 0.4f, "Minimum pT to apply the TOF cut on hadrons"}; + Configurable setting_cutNsigmaTOF{"setting_cutNsigmaTOF", 3.0f, "Value of the TOF Nsigma cut"}; + Configurable setting_noMixedEvents{"setting_noMixedEvents", 5, "Number of mixed events per event"}; + Configurable setting_enableBkgUS{"setting_enableBkgUS", false, "Enable US background"}; + Configurable setting_enableDCAfitter{"setting_enableDCAfitter", false, "Enable DCA fitter"}; + Configurable setting_saveUSandLS{"setting_saveUSandLS", true, "Save All Pairs"}; + Configurable setting_isMC{"setting_isMC", false, "Run MC"}; + Configurable setting_fillMultiplicity{"setting_fillMultiplicity", false, "Fill multiplicity table"}; + + // Zorro + Configurable setting_skimmedProcessing{"setting_skimmedProcessing", false, "Skimmed dataset processing"}; + + // svPool + Configurable setting_skipAmbiTracks{"setting_skipAmbiTracks", false, "Skip ambiguous tracks"}; + Configurable setting_customVertexerTimeMargin{"setting_customVertexerTimeMargin", 800, "Time margin for custom vertexer (ns)"}; + + // CCDB options + Configurable setting_d_bz_input{"setting_d_bz", -999, "bz field, -999 is automatic"}; + Configurable setting_ccdburl{"setting_ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable setting_grpPath{"setting_grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable setting_grpmagPath{"setting_grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable setting_lutPath{"setting_lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable setting_geoPath{"setting_geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable setting_pidPath{"setting_pidPath", "", "Path to the PID response object"}; + + Configurable> setting_BetheBlochParams{"setting_BetheBlochParams", {betheBlochDefault[0], 1, 6, {"He3"}, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for He3"}; + Configurable setting_compensatePIDinTracking{"setting_compensatePIDinTracking", false, "If true, divide tpcInnerParam by the electric charge"}; + Configurable setting_materialCorrection{"setting_materialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Material correction type"}; + + Preslice m_perCol = aod::track::collisionId; + Preslice m_perColMC = aod::track::collisionId; + + // binning for EM background + ConfigurableAxis axisVertex{"axisVertex", {30, -10, 10}, "Binning for multiplicity"}; + ConfigurableAxis axisCentrality{"axisCentrality", {40, 0, 100}, "Binning for centrality"}; + using BinningType = ColumnBinningPolicy; + BinningType binningPolicy{{axisVertex, axisCentrality}, true}; + SliceCache cache; + SameKindPair m_pair{binningPolicy, setting_noMixedEvents, -1, &cache}; + + std::array m_BBparamsHe; + + std::vector m_recoCollisionIDs; + std::vector m_goodCollisions; + std::vector m_trackPairs; + o2::vertexing::DCAFitterN<2> m_fitter; + svPoolCreator m_svPoolCreator{hePDG, prPDG}; + + int m_runNumber; + float m_d_bz; + Service m_ccdb; + Zorro m_zorro; + OutputObj m_zorroSummary{"zorroSummary"}; + + HistogramRegistry m_qaRegistry{ + "QA", + { + {"hVtxZ", "Vertex distribution in Z;Z (cm)", {HistType::kTH1F, {{400, -20.0, 20.0}}}}, + {"hNcontributor", "Number of primary vertex contributor", {HistType::kTH1F, {{2000, 0.0f, 2000.0f}}}}, + {"hTrackSel", "Accepted tracks", {HistType::kTH1F, {{Selections::kAll, -0.5, static_cast(Selections::kAll) - 0.5}}}}, + {"hEvents", "; Events;", {HistType::kTH1F, {{3, -0.5, 2.5}}}}, + {"hEmptyPool", "svPoolCreator did not find track pairs false/true", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, + {"hDCAxyHe3", ";DCA_{xy} (cm)", {HistType::kTH1F, {{200, -5.0f, 5.0f}}}}, + {"hDCAzHe3", ";DCA_{z} (cm)", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}}, + {"hNClsHe3ITS", ";N_{ITS} Cluster", {HistType::kTH1F, {{20, -10.0f, 10.0f}}}}, + {"hNClsHadITS", ";N_{ITS} Cluster", {HistType::kTH1F, {{20, -10.0f, 10.0f}}}}, + {"hChi2NClHe3ITS", ";Chi2_{ITS} Ncluster", {HistType::kTH1F, {{100, 0, 100.0f}}}}, + {"hChi2NClHadITS", ";Chi2_{ITS} Ncluster", {HistType::kTH1F, {{100, 0, 100.0f}}}}, + {"hhe3HadtInvMass", "; M(^{3}He + p) (GeV/#it{c}^{2})", {HistType::kTH1F, {{300, 3.74f, 4.34f}}}}, + {"hHe3Pt", "#it{p}_{T} distribution; #it{p}_{T} (GeV/#it{c})", {HistType::kTH1F, {{240, -6.0f, 6.0f}}}}, + {"hHadronPt", "Pt distribution; #it{p}_{T} (GeV/#it{c})", {HistType::kTH1F, {{120, -3.0f, 3.0f}}}}, + {"h2dEdxHe3candidates", "dEdx distribution; #it{p} (GeV/#it{c}); dE/dx (a.u.)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {100, 0.0f, 2000.0f}}}}, + {"h2NsigmaHe3TPC", "NsigmaHe3 TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(^{3}He)", {HistType::kTH2F, {{20, -5.0f, 5.0f}, {200, -5.0f, 5.0f}}}}, + {"h2NsigmaHe3TPC_preselection", "NsigmaHe3 TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(^{3}He)", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {400, -10.0f, 10.0f}}}}, + {"h2NSigmaHe3ITS_preselection", "NsigmaHe3 ITS distribution; signed #it{p}_{T} (GeV/#it{c}); n#sigma_{ITS} ^{3}He", {HistType::kTH2F, {{50, -5.0f, 5.0f}, {120, -3.0f, 3.0f}}}}, + {"h2NSigmaHe3ITS", "NsigmaHe3 ITS distribution; signed #it{p}_{T} (GeV/#it{c}); n#sigma_{ITS} ^{3}He", {HistType::kTH2F, {{50, -5.0f, 5.0f}, {120, -3.0f, 3.0f}}}}, + {"h2NsigmaHadronTPC", "NsigmaHadron TPC distribution; #it{p}_{T}(GeV/#it{c}); n#sigma_{TPC}(p)", {HistType::kTH2F, {{20, -5.0f, 5.0f}, {200, -5.0f, 5.0f}}}}, + {"h2NsigmaHadronTPC_preselection", "NsigmaHe3 TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(^{3}He)", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {400, -10.0f, 10.0f}}}}, + {"h2NsigmaHadronTOF", "NsigmaHadron TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(p)", {HistType::kTH2F, {{20, -5.0f, 5.0f}, {200, -5.0f, 5.0f}}}}, + {"h2NsigmaHadronTOF_preselection", "NsigmaHadron TOF distribution; #iit{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(p)", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {400, -10.0f, 10.0f}}}}, + }, + OutputObjHandlingPolicy::AnalysisObject, + false, + true}; + + void init(o2::framework::InitContext&) + { + m_zorroSummary.setObject(m_zorro.getZorroSummary()); + m_runNumber = 0; + + m_ccdb->setURL(setting_ccdburl); + m_ccdb->setCaching(true); + m_ccdb->setLocalObjectValidityChecking(); + m_ccdb->setFatalWhenNull(false); + + m_fitter.setPropagateToPCA(true); + m_fitter.setMaxR(200.); + m_fitter.setMinParamChange(1e-3); + m_fitter.setMinRelChi2Change(0.9); + m_fitter.setMaxDZIni(1e9); + m_fitter.setMaxChi2(1e9); + m_fitter.setUseAbsDCA(true); + int mat{static_cast(setting_materialCorrection)}; + m_fitter.setMatCorrType(static_cast(mat)); + + m_svPoolCreator.setTimeMargin(setting_customVertexerTimeMargin); + if (setting_skipAmbiTracks) { + m_svPoolCreator.setSkipAmbiTracks(); + } + + for (int i = 0; i < 5; i++) { + m_BBparamsHe[i] = setting_BetheBlochParams->get("He3", Form("p%i", i)); + } + m_BBparamsHe[5] = setting_BetheBlochParams->get("He3", "resolution"); + + std::vector selection_labels = {"All", "Track selection", "PID"}; + for (int i = 0; i < Selections::kAll; i++) { + m_qaRegistry.get(HIST("hTrackSel"))->GetXaxis()->SetBinLabel(i + 1, selection_labels[i].c_str()); + } + + std::vector events_labels = {"All", "Selected", "Zorro He events"}; + for (int i = 0; i < Selections::kAll; i++) { + m_qaRegistry.get(HIST("hEvents"))->GetXaxis()->SetBinLabel(i + 1, events_labels[i].c_str()); + } + + m_qaRegistry.get(HIST("hEmptyPool"))->GetXaxis()->SetBinLabel(1, "False"); + m_qaRegistry.get(HIST("hEmptyPool"))->GetXaxis()->SetBinLabel(2, "True"); + } + + void initCCDB(const aod::BCsWithTimestamps::iterator& bc) + { + if (m_runNumber == bc.runNumber()) { + return; + } + if (setting_skimmedProcessing) { + m_zorro.initCCDB(m_ccdb.service, bc.runNumber(), bc.timestamp(), "fHe"); + m_zorro.populateHistRegistry(m_qaRegistry, bc.runNumber()); + } + m_runNumber = bc.runNumber(); + + auto run3grp_timestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = m_ccdb->getForTimeStamp(setting_grpPath, run3grp_timestamp); + o2::parameters::GRPMagField* grpmag = 0x0; + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + if (setting_d_bz_input < -990) { + // Fetch magnetic field from ccdb for current collision + m_d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << m_d_bz << " kZG"; + } else { + m_d_bz = setting_d_bz_input; + } + } else { + grpmag = m_ccdb->getForTimeStamp(setting_grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << setting_grpmagPath << " of object GRPMagField and " << setting_grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + if (setting_d_bz_input < -990) { + // Fetch magnetic field from ccdb for current collision + m_d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << m_d_bz << " kZG"; + } else { + m_d_bz = setting_d_bz_input; + } + } + } + + // ================================================================================================================== + + template + bool selectCollision(const Tcollision& collision, const aod::BCsWithTimestamps&) + { + m_qaRegistry.fill(HIST("hEvents"), 0); + + if constexpr (isMC) { + if (/*!collision.sel8() ||*/ std::abs(collision.posZ()) > setting_cutVertex) { + return false; + } + } else { + auto bc = collision.template bc_as(); + initCCDB(bc); + + if (!collision.sel8() || std::abs(collision.posZ()) > setting_cutVertex) { + return false; + } + if (setting_skimmedProcessing) { + bool zorroSelected = m_zorro.isSelected(collision.template bc_as().globalBC()); + if (zorroSelected) { + m_qaRegistry.fill(HIST("hEvents"), 2); + } + } + } + + m_qaRegistry.fill(HIST("hEvents"), 1); + m_qaRegistry.fill(HIST("hNcontributor"), collision.numContrib()); + m_qaRegistry.fill(HIST("hVtxZ"), collision.posZ()); + return true; + } + + template + bool selectTrack(const Ttrack& candidate) + { + if (std::abs(candidate.eta()) > setting_cutEta) { + return false; + } + if (candidate.itsNCls() < setting_cutNCls || + candidate.tpcNClsFound() < 90 || + candidate.tpcNClsCrossedRows() < 70 || + candidate.tpcNClsCrossedRows() < 0.8 * candidate.tpcNClsFindable() || + candidate.tpcChi2NCl() > 4.f || + candidate.tpcChi2NCl() < setting_cutChi2tpcLow || + candidate.itsChi2NCl() > setting_cutChi2NClITS) { + return false; + } + + return true; + } + + template + float computeTPCNSigmaHadron(const Ttrack& candidate) + { + float tpcNSigmaHad = 0; + if (setting_HadPDGCode == 211) { + tpcNSigmaHad = candidate.tpcNSigmaPi(); + } else if (setting_HadPDGCode == 2212) { + tpcNSigmaHad = candidate.tpcNSigmaPr(); + } else { + LOG(info) << "invalid PDG code for TPC"; + } + return tpcNSigmaHad; + } + + template + float computeTOFNSigmaHadron(const Ttrack& candidate) + { + float tofNSigmaHad = 0; + if (setting_HadPDGCode == 211) { + tofNSigmaHad = candidate.tofNSigmaPi(); + } else if (setting_HadPDGCode == 2212) { + tofNSigmaHad = candidate.tofNSigmaPr(); + } else { + LOG(info) << "invalid PDG code for TOF"; + } + return tofNSigmaHad; + } + + template + bool selectionPIDHadron(const Ttrack& candidate) + { + auto tpcNSigmaHad = computeTPCNSigmaHadron(candidate); + m_qaRegistry.fill(HIST("h2NsigmaHadronTPC_preselection"), candidate.tpcInnerParam(), tpcNSigmaHad); + if (candidate.hasTOF() && candidate.pt() > setting_cutPtMinTOFHad) { + auto tofNSigmaHad = computeTOFNSigmaHadron(candidate); + + if (std::abs(tpcNSigmaHad) > setting_cutNsigmaTPC) { + return false; + } + m_qaRegistry.fill(HIST("h2NsigmaHadronTOF_preselection"), candidate.pt(), tofNSigmaHad); + if (std::abs(tofNSigmaHad) > setting_cutNsigmaTOF) { + return false; + } + m_qaRegistry.fill(HIST("h2NsigmaHadronTPC"), candidate.pt(), tpcNSigmaHad); + m_qaRegistry.fill(HIST("h2NsigmaHadronTOF"), candidate.pt(), tofNSigmaHad); + return true; + } else if (std::abs(tpcNSigmaHad) < setting_cutNsigmaTPC) { + m_qaRegistry.fill(HIST("h2NsigmaHadronTPC"), candidate.pt(), tpcNSigmaHad); + return true; + } + return false; + } + + template + float computeNSigmaHe3(const Ttrack& candidate) + { + bool heliumPID = candidate.pidForTracking() == o2::track::PID::Helium3 || candidate.pidForTracking() == o2::track::PID::Alpha; + float correctedTPCinnerParam = (heliumPID && setting_compensatePIDinTracking) ? candidate.tpcInnerParam() / 2.f : candidate.tpcInnerParam(); + float expTPCSignal = o2::tpc::BetheBlochAleph(static_cast(correctedTPCinnerParam * 2.f / constants::physics::MassHelium3), m_BBparamsHe[0], m_BBparamsHe[1], m_BBparamsHe[2], m_BBparamsHe[3], m_BBparamsHe[4]); + + double resoTPC{expTPCSignal * m_BBparamsHe[5]}; + return static_cast((candidate.tpcSignal() - expTPCSignal) / resoTPC); + } + + template + bool selectionPIDHe3(const Ttrack& candidate) + { + bool heliumPID = candidate.pidForTracking() == o2::track::PID::Helium3 || candidate.pidForTracking() == o2::track::PID::Alpha; + float correctedTPCinnerParam = (heliumPID && setting_compensatePIDinTracking) ? candidate.tpcInnerParam() / 2.f : candidate.tpcInnerParam(); + + if (correctedTPCinnerParam < setting_cutRigidityMinHe3) { + return false; + } + + auto nSigmaHe3 = computeNSigmaHe3(candidate); + m_qaRegistry.fill(HIST("h2NsigmaHe3TPC_preselection"), candidate.sign() * 2 * candidate.pt(), nSigmaHe3); + if (std::abs(nSigmaHe3) > setting_cutNsigmaTPC) { + return false; + } + // + o2::aod::ITSResponse m_responseITS; + auto ITSnSigmaHe3 = m_responseITS.nSigmaITS(candidate.itsClusterSizes(), 2 * candidate.p(), candidate.eta()); + // + m_qaRegistry.fill(HIST("h2NSigmaHe3ITS_preselection"), candidate.sign() * 2 * candidate.pt(), ITSnSigmaHe3); + if (ITSnSigmaHe3 < setting_cutNsigmaITS) { + return false; + } + + m_qaRegistry.fill(HIST("h2dEdxHe3candidates"), candidate.sign() * correctedTPCinnerParam, candidate.tpcSignal()); + m_qaRegistry.fill(HIST("h2NsigmaHe3TPC"), candidate.sign() * 2 * candidate.pt(), nSigmaHe3); + m_qaRegistry.fill(HIST("h2NSigmaHe3ITS"), candidate.sign() * 2 * candidate.pt(), ITSnSigmaHe3); + return true; + } + + // ================================================================================================================== + + template + bool fillCandidateInfo(const Ttrack& trackHe3, const Ttrack& trackHad, const CollBracket& collBracket, const Tcollisions& collisions, he3HadCandidate& he3Hadcand, const Ttracks& /*trackTable*/, bool isMixedEvent) + { + if (!isMixedEvent) { + auto trackCovHe3 = getTrackParCov(trackHe3); + auto trackCovHad = getTrackParCov(trackHad); + int nCand = 0; + try { + nCand = m_fitter.process(trackCovHe3, trackCovHad); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call!"; + return false; + } + if (nCand == 0) { + return false; + } + + // associate collision id as the one that minimises the distance between the vertex and the PCAs of the daughters + double distanceMin = -1; + unsigned int collIdxMin = 0; + + for (int collIdx = collBracket.getMin(); collIdx <= collBracket.getMax(); collIdx++) { + auto collision = collisions.rawIteratorAt(collIdx); + std::array collVtx = {collision.posX(), collision.posY(), collision.posZ()}; + const auto& PCA = m_fitter.getPCACandidate(); + float distance = 0; + for (int i = 0; i < 3; i++) { + distance += (PCA[i] - collVtx[i]) * (PCA[i] - collVtx[i]); + } + if (distanceMin < 0 || distance < distanceMin) { + distanceMin = distance; + collIdxMin = collIdx; + } + } + + if (!m_goodCollisions[collIdxMin]) { + return false; + } + he3Hadcand.collisionID = collIdxMin; + + } else { + he3Hadcand.collisionID = collBracket.getMin(); + } + + he3Hadcand.momHe3 = std::array{trackHe3.px(), trackHe3.py(), trackHe3.pz()}; + for (int i = 0; i < 3; i++) + he3Hadcand.momHe3[i] = he3Hadcand.momHe3[i] * 2; + he3Hadcand.momHad = std::array{trackHad.px(), trackHad.py(), trackHad.pz()}; + float invMass = 0; + if (setting_HadPDGCode == 211) { + invMass = RecoDecay::m(std::array{he3Hadcand.momHe3, he3Hadcand.momHad}, std::array{o2::constants::physics::MassHelium3, o2::constants::physics::MassPiPlus}); + } else if (setting_HadPDGCode == 2212) { + invMass = RecoDecay::m(std::array{he3Hadcand.momHe3, he3Hadcand.momHad}, std::array{o2::constants::physics::MassHelium3, o2::constants::physics::MassProton}); + } else { + LOG(info) << "invalid PDG code for invMass"; + } + // float invMass = RecoDecay::m(std::array{he3Hadcand.momHe3, he3Hadcand.momHad}, std::array{o2::constants::physics::MassHelium3, o2::constants::physics::MassPiPlus}); + if (setting_cutInvMass > 0 && invMass > setting_cutInvMass) { + return false; + } + float pthe3Had = std::hypot(he3Hadcand.momHe3[0] + he3Hadcand.momHad[0], he3Hadcand.momHe3[1] + he3Hadcand.momHad[1]); + if (pthe3Had < setting_cutPtMinhe3Had) { + return false; + } + + he3Hadcand.signHe3 = trackHe3.sign(); + he3Hadcand.signHad = trackHad.sign(); + + gpu::gpustd::array dcaInfo; + if (setting_enableDCAfitter) { + auto trackCovHe3 = getTrackParCov(trackHe3); + auto trackCovHad = getTrackParCov(trackHad); + auto collision = collisions.rawIteratorAt(he3Hadcand.collisionID); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackCovHe3, 2.f, m_fitter.getMatCorrType(), &dcaInfo); + he3Hadcand.DCAxyHe3 = dcaInfo[0]; + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackCovHad, 2.f, m_fitter.getMatCorrType(), &dcaInfo); + he3Hadcand.DCAxyHad = dcaInfo[0]; + } else { + he3Hadcand.DCAxyHe3 = trackHe3.dcaXY(); + he3Hadcand.DCAxyHad = trackHad.dcaXY(); + } + he3Hadcand.DCAzHe3 = trackHe3.dcaZ(); + he3Hadcand.DCAzHad = trackHad.dcaZ(); + he3Hadcand.tpcSignalHe3 = trackHe3.tpcSignal(); + bool heliumPID = trackHe3.pidForTracking() == o2::track::PID::Helium3 || trackHe3.pidForTracking() == o2::track::PID::Alpha; + float correctedTPCinnerParamHe3 = (heliumPID && setting_compensatePIDinTracking) ? trackHe3.tpcInnerParam() / 2.f : trackHe3.tpcInnerParam(); + he3Hadcand.momHe3TPC = correctedTPCinnerParamHe3; + he3Hadcand.tpcSignalHad = trackHad.tpcSignal(); + he3Hadcand.momHadTPC = trackHad.tpcInnerParam(); + + he3Hadcand.nTPCClustersHe3 = trackHe3.tpcNClsFound(); + he3Hadcand.nSigmaHe3 = computeNSigmaHe3(trackHe3); + he3Hadcand.nSigmaHad = computeTPCNSigmaHadron(trackHad); + + he3Hadcand.chi2TPCHe3 = trackHe3.tpcChi2NCl(); + he3Hadcand.chi2TPCHad = trackHad.tpcChi2NCl(); + + he3Hadcand.PIDtrkHe3 = trackHe3.pidForTracking(); + he3Hadcand.PIDtrkHad = trackHad.pidForTracking(); + + he3Hadcand.itsClSizeHe3 = trackHe3.itsClusterSizes(); + he3Hadcand.itsClSizeHad = trackHad.itsClusterSizes(); + + he3Hadcand.NClsITSHe3 = trackHe3.itsNCls(); + he3Hadcand.NClsITSHad = trackHad.itsNCls(); + he3Hadcand.Chi2NClITSHe3 = trackHe3.itsChi2NCl(); + he3Hadcand.Chi2NClITSHad = trackHad.itsChi2NCl(); + + he3Hadcand.sharedClustersHe3 = trackHe3.tpcNClsShared(); + he3Hadcand.sharedClustersHad = trackHad.tpcNClsShared(); + + he3Hadcand.isBkgUS = trackHe3.sign() * trackHad.sign() < 0; + he3Hadcand.isBkgEM = isMixedEvent; + + he3Hadcand.invMass = invMass; + + he3Hadcand.trackIDHe3 = trackHe3.globalIndex(); + he3Hadcand.trackIDHad = trackHad.globalIndex(); + + if (trackHe3.hasTOF()) { + float beta = o2::pid::tof::Beta::GetBeta(trackHe3); + beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked + bool heliumPID = trackHe3.pidForTracking() == o2::track::PID::Helium3 || trackHe3.pidForTracking() == o2::track::PID::Alpha; + float correctedTPCinnerParamHe3 = (heliumPID && setting_compensatePIDinTracking) ? trackHe3.tpcInnerParam() / 2.f : trackHe3.tpcInnerParam(); + he3Hadcand.massTOFHe3 = correctedTPCinnerParamHe3 * 2.f * std::sqrt(1.f / (beta * beta) - 1.f); + } + if (trackHad.hasTOF()) { + float beta = o2::pid::tof::Beta::GetBeta(trackHad); + beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked + he3Hadcand.massTOFHad = trackHad.tpcInnerParam() * std::sqrt(1.f / (beta * beta) - 1.f); + } + + return true; + } + + template + void fillCandidateInfoMC(const Mc& mctrackHe3, const Mc& mctrackHad, const Mc& mctrackMother, he3HadCandidate& he3Hadcand) + { + he3Hadcand.momHe3MC = mctrackHe3.pt() * (mctrackHe3.pdgCode() > 0 ? 1 : -1); + he3Hadcand.etaHe3MC = mctrackHe3.eta(); + he3Hadcand.phiHe3MC = mctrackHe3.phi(); + he3Hadcand.momHadMC = mctrackHad.pt() * (mctrackHad.pdgCode() > 0 ? 1 : -1); + he3Hadcand.etaHadMC = mctrackHad.eta(); + he3Hadcand.phiHadMC = mctrackHad.phi(); + he3Hadcand.l4PtMC = mctrackMother.pt() * (mctrackMother.pdgCode() > 0 ? 1 : -1); + const double eLit = mctrackHe3.e() + mctrackHad.e(); + he3Hadcand.l4MassMC = std::sqrt(eLit * eLit - mctrackMother.p() * mctrackMother.p()); + } + + template + void pairTracksSameEvent(const Ttrack& tracks) + { + for (auto track0 : tracks) { + + m_qaRegistry.fill(HIST("hTrackSel"), Selections::kNoCuts); + + if (!selectTrack(track0)) { + continue; + } + m_qaRegistry.fill(HIST("hTrackSel"), Selections::kTrackCuts); + + if (!selectionPIDHe3(track0)) { + continue; + } + m_qaRegistry.fill(HIST("hTrackSel"), Selections::kPID); + + for (auto track1 : tracks) { + + if (track0 == track1) { + continue; + } + + if (!setting_saveUSandLS) { + if (!setting_enableBkgUS && (track0.sign() * track1.sign() < 0)) { + continue; + } + if (setting_enableBkgUS && (track0.sign() * track1.sign() > 0)) { + continue; + } + } + + if (!selectTrack(track1) || !selectionPIDHadron(track1)) { + continue; + } + + SVCand trackPair; + trackPair.tr0Idx = track0.globalIndex(); + trackPair.tr1Idx = track1.globalIndex(); + const int collIdx = track0.collisionId(); + CollBracket collBracket{collIdx, collIdx}; + trackPair.collBracket = collBracket; + m_trackPairs.push_back(trackPair); + } + } + } + + template + void pairTracksEventMixing(T& he3Cands, T& hadronCands) + { + for (auto& he3Cand : he3Cands) { + if (!selectTrack(he3Cand) || !selectionPIDHe3(he3Cand)) { + continue; + } + for (auto& hadronCand : hadronCands) { + if (!selectTrack(hadronCand) || !selectionPIDHadron(hadronCand)) { + continue; + } + + SVCand trackPair; + trackPair.tr0Idx = he3Cand.globalIndex(); + trackPair.tr1Idx = hadronCand.globalIndex(); + const int collIdx = he3Cand.collisionId(); + CollBracket collBracket{collIdx, collIdx}; + trackPair.collBracket = collBracket; + m_trackPairs.push_back(trackPair); + } + } + } + + template + void fillTable(const he3HadCandidate& he3Hadcand, const Tcoll& collision, bool isMC = false) + { + m_outputDataTable( + he3Hadcand.recoPtHe3(), + he3Hadcand.recoEtaHe3(), + he3Hadcand.recoPhiHe3(), + he3Hadcand.recoPtHad(), + he3Hadcand.recoEtaHad(), + he3Hadcand.recoPhiHad(), + he3Hadcand.DCAxyHe3, + he3Hadcand.DCAzHe3, + he3Hadcand.DCAxyHad, + he3Hadcand.DCAzHad, + he3Hadcand.tpcSignalHe3, + he3Hadcand.momHe3TPC, + he3Hadcand.tpcSignalHad, + he3Hadcand.momHadTPC, + he3Hadcand.nTPCClustersHe3, + he3Hadcand.nSigmaHe3, + he3Hadcand.nSigmaHad, + he3Hadcand.chi2TPCHe3, + he3Hadcand.chi2TPCHad, + he3Hadcand.massTOFHe3, + he3Hadcand.massTOFHad, + he3Hadcand.PIDtrkHe3, + he3Hadcand.PIDtrkHad, + he3Hadcand.itsClSizeHe3, + he3Hadcand.itsClSizeHad, + he3Hadcand.sharedClustersHe3, + he3Hadcand.sharedClustersHad, + he3Hadcand.isBkgUS, + he3Hadcand.isBkgEM); + if (isMC) { + m_outputMCTable( + he3Hadcand.momHe3MC, + he3Hadcand.etaHe3MC, + he3Hadcand.phiHe3MC, + he3Hadcand.momHadMC, + he3Hadcand.etaHadMC, + he3Hadcand.phiHadMC, + he3Hadcand.l4PtMC, + he3Hadcand.l4MassMC); + } + if (setting_fillMultiplicity) { + m_outputMultiplicityTable( + collision.globalIndex(), + collision.posZ(), + collision.numContrib(), + collision.centFT0C(), + collision.multFT0C()); + } + } + + void fillHistograms(const he3HadCandidate& he3Hadcand) + { + m_qaRegistry.fill(HIST("hHe3Pt"), he3Hadcand.recoPtHe3()); + m_qaRegistry.fill(HIST("hHadronPt"), he3Hadcand.recoPtHad()); + m_qaRegistry.fill(HIST("hhe3HadtInvMass"), he3Hadcand.invMass); + m_qaRegistry.fill(HIST("hDCAxyHe3"), he3Hadcand.DCAxyHe3); + m_qaRegistry.fill(HIST("hDCAzHe3"), he3Hadcand.DCAzHe3); + m_qaRegistry.fill(HIST("hNClsHe3ITS"), he3Hadcand.NClsITSHe3); + m_qaRegistry.fill(HIST("hNClsHadITS"), he3Hadcand.NClsITSHad); + m_qaRegistry.fill(HIST("hChi2NClHe3ITS"), he3Hadcand.Chi2NClITSHe3); + m_qaRegistry.fill(HIST("hChi2NClHadITS"), he3Hadcand.Chi2NClITSHad); + } + + // ================================================================================================================== + + template + void fillPairs(const Tcollisions& collisions, const Ttracks& tracks, const bool isMixedEvent) + { + for (auto& trackPair : m_trackPairs) { + + auto heTrack = tracks.rawIteratorAt(trackPair.tr0Idx); + auto hadTrack = tracks.rawIteratorAt(trackPair.tr1Idx); + auto collBracket = trackPair.collBracket; + + he3HadCandidate he3Hadcand; + if (!fillCandidateInfo(heTrack, hadTrack, collBracket, collisions, he3Hadcand, tracks, isMixedEvent)) { + continue; + } + fillHistograms(he3Hadcand); + auto collision = collisions.rawIteratorAt(he3Hadcand.collisionID); + fillTable(he3Hadcand, collision, /*isMC*/ false); + } + } + + template + void fillMcParticles(const Tcollisions& collisions, const TmcParticles& mcParticles, std::vector& filledMothers) + { + for (auto& mcParticle : mcParticles) { + + if (std::abs(mcParticle.pdgCode()) != li4PDG || std::abs(mcParticle.y()) > 1 || mcParticle.isPhysicalPrimary() == false) { + continue; + } + + if (std::find(filledMothers.begin(), filledMothers.end(), mcParticle.globalIndex()) != filledMothers.end()) { + continue; + } + + auto kDaughters = mcParticle.template daughters_as(); + bool daughtHe3(false), daughtHad(false); + McIter mcHe3, mcHad; + for (auto kCurrentDaughter : kDaughters) { + if (std::abs(kCurrentDaughter.pdgCode()) == hePDG) { + daughtHe3 = true; + mcHe3 = kCurrentDaughter; + } else if (std::abs(kCurrentDaughter.pdgCode()) == prPDG) { + daughtHad = true; + mcHad = kCurrentDaughter; + } + } + if (daughtHe3 && daughtHad) { + he3HadCandidate he3Hadcand; + fillCandidateInfoMC(mcHe3, mcHad, mcParticle, he3Hadcand); + auto collision = collisions.rawIteratorAt(he3Hadcand.collisionID); + fillTable(he3Hadcand, collision, /*isMC*/ true); + } + } + } + + // ================================================================================================================== + + void processSameEvent(const CollisionsFull& collisions, const TrackCandidates& tracks, const aod::BCsWithTimestamps& bcs) + { + m_goodCollisions.clear(); + m_goodCollisions.resize(collisions.size(), false); + + for (auto& collision : collisions) { + + m_trackPairs.clear(); + + if (!selectCollision(collision, bcs)) { + continue; + } + + m_goodCollisions[collision.globalIndex()] = true; + const uint64_t collIdx = collision.globalIndex(); + auto TrackTable_thisCollision = tracks.sliceBy(m_perCol, collIdx); + TrackTable_thisCollision.bindExternalIndices(&tracks); + + pairTracksSameEvent(TrackTable_thisCollision); + + if (m_trackPairs.size() == 0) { + continue; + } + + fillPairs(collisions, tracks, /*isMixedEvent*/ false); + } + } + PROCESS_SWITCH(he3hadronfemto, processSameEvent, "Process Same event", false); + + void processMixedEvent(const CollisionsFull& collisions, const TrackCandidates& tracks) + { + LOG(debug) << "Processing mixed event"; + m_trackPairs.clear(); + + for (auto& [c1, tracks1, c2, tracks2] : m_pair) { + if (!c1.sel8() || !c2.sel8()) { + continue; + } + + m_qaRegistry.fill(HIST("hNcontributor"), c1.numContrib()); + m_qaRegistry.fill(HIST("hVtxZ"), c1.posZ()); + + pairTracksEventMixing(tracks1, tracks2); + pairTracksEventMixing(tracks2, tracks1); + } + + fillPairs(collisions, tracks, /*isMixedEvent*/ true); + } + PROCESS_SWITCH(he3hadronfemto, processMixedEvent, "Process Mixed event", false); + + void processMC(const CollisionsFullMC& collisions, const aod::BCsWithTimestamps& bcs, const TrackCandidatesMC& tracks, const aod::McParticles& mcParticles) + { + std::vector filledMothers; + + m_goodCollisions.clear(); + m_goodCollisions.resize(collisions.size(), false); + + for (auto& collision : collisions) { + + m_trackPairs.clear(); + + if (!selectCollision(collision, bcs)) { + continue; + } + + const uint64_t collIdx = collision.globalIndex(); + m_goodCollisions[collIdx] = true; + auto TrackTable_thisCollision = tracks.sliceBy(m_perColMC, collIdx); + TrackTable_thisCollision.bindExternalIndices(&tracks); + + pairTracksSameEvent(TrackTable_thisCollision); + + for (auto& trackPair : m_trackPairs) { + + auto heTrack = tracks.rawIteratorAt(trackPair.tr0Idx); + auto prTrack = tracks.rawIteratorAt(trackPair.tr1Idx); + auto collBracket = trackPair.collBracket; + + if (!heTrack.has_mcParticle() || !prTrack.has_mcParticle()) { + continue; + } + + auto mctrackHe3 = heTrack.mcParticle(); + auto mctrackHad = prTrack.mcParticle(); + + if (std::abs(mctrackHe3.pdgCode()) != hePDG || std::abs(mctrackHad.pdgCode()) != prPDG) { + continue; + } + + for (auto& mothertrack : mctrackHe3.mothers_as()) { + for (auto& mothertrackHad : mctrackHad.mothers_as()) { + + if (mothertrack != mothertrackHad || std::abs(mothertrack.pdgCode()) != li4PDG || std::abs(mothertrack.y()) > 1) { + continue; + } + + he3HadCandidate he3Hadcand; + if (!fillCandidateInfo(heTrack, prTrack, collBracket, collisions, he3Hadcand, tracks, /*mix*/ false)) { + continue; + } + fillCandidateInfoMC(mctrackHe3, mctrackHad, mothertrack, he3Hadcand); + fillHistograms(he3Hadcand); + auto collision = collisions.rawIteratorAt(he3Hadcand.collisionID); + fillTable(he3Hadcand, collision, /*isMC*/ true); + filledMothers.push_back(mothertrack.globalIndex()); + } + } + } + } + + fillMcParticles(collisions, mcParticles, filledMothers); + } + PROCESS_SWITCH(he3hadronfemto, processMC, "Process MC", false); + + void processSameEventPools(const CollisionsFull& collisions, const TrackCandidates& tracks, const aod::AmbiguousTracks& ambiguousTracks, const aod::BCsWithTimestamps& bcs) + { + m_goodCollisions.clear(); + m_goodCollisions.resize(collisions.size(), false); + + for (auto& collision : collisions) { + if (selectCollision(collision, bcs)) { + m_goodCollisions[collision.globalIndex()] = true; + } + } + + m_svPoolCreator.clearPools(); + m_svPoolCreator.fillBC2Coll(collisions, bcs); + + for (auto& track : tracks) { + + m_qaRegistry.fill(HIST("hTrackSel"), Selections::kNoCuts); + if (!selectTrack(track)) + continue; + m_qaRegistry.fill(HIST("hTrackSel"), Selections::kTrackCuts); + + bool selHad = selectionPIDHadron(track); + bool selHe = selectionPIDHe3(track); + if ((!selHad && !selHe) || (selHad && selHe)) { + continue; + } + m_qaRegistry.fill(HIST("hTrackSel"), Selections::kPID); + + int pdgHypo = selHe ? hePDG : prPDG; + + m_svPoolCreator.appendTrackCand(track, collisions, pdgHypo, ambiguousTracks, bcs); + } + + m_trackPairs = m_svPoolCreator.getSVCandPool(collisions, true); + if (m_trackPairs.size() == 0) { + m_qaRegistry.fill(HIST("hEmptyPool"), 1); + return; + } + m_qaRegistry.fill(HIST("hEmptyPool"), 0); + + fillPairs(collisions, tracks, /*isMixedEvent*/ false); + } + PROCESS_SWITCH(he3hadronfemto, processSameEventPools, "Process Same event pools", false); + + void processMcPools(const CollisionsFullMC& collisions, const TrackCandidatesMC& tracks, const aod::AmbiguousTracks& ambiguousTracks, const aod::BCsWithTimestamps& bcs, const aod::McParticles& mcParticles, const aod::McTrackLabels& mcTrackLabels) + { + std::vector filledMothers; + + m_goodCollisions.clear(); + m_goodCollisions.resize(collisions.size(), false); + + for (auto& collision : collisions) { + if (selectCollision(collision, bcs)) { + m_goodCollisions[collision.globalIndex()] = true; + } + } + + m_svPoolCreator.clearPools(); + m_svPoolCreator.fillBC2Coll(collisions, bcs); + + for (auto& track : tracks) { + + m_qaRegistry.fill(HIST("hTrackSel"), Selections::kNoCuts); + if (!selectTrack(track)) + continue; + m_qaRegistry.fill(HIST("hTrackSel"), Selections::kTrackCuts); + + bool selHad = selectionPIDHadron(track); + bool selHe = selectionPIDHe3(track); + if ((!selHad && !selHe) || (selHad && selHe)) + continue; + m_qaRegistry.fill(HIST("hTrackSel"), Selections::kPID); + + int pdgHypo = selHe ? hePDG : prPDG; + + m_svPoolCreator.appendTrackCand(track, collisions, pdgHypo, ambiguousTracks, bcs); + } + + auto& svPool = m_svPoolCreator.getSVCandPool(collisions, true); + if (svPool.size() == 0) { + m_qaRegistry.fill(HIST("hEmptyPool"), 1); + return; + } + m_qaRegistry.fill(HIST("hEmptyPool"), 0); + + for (auto& svCand : svPool) { + auto heTrack = tracks.rawIteratorAt(svCand.tr0Idx); + auto prTrack = tracks.rawIteratorAt(svCand.tr1Idx); + auto heTrackLabel = mcTrackLabels.rawIteratorAt(svCand.tr0Idx); + auto prTrackLabel = mcTrackLabels.rawIteratorAt(svCand.tr1Idx); + auto collBracket = svCand.collBracket; + + if (!heTrackLabel.has_mcParticle() || !prTrackLabel.has_mcParticle()) { + continue; + } + + auto mctrackHe3 = heTrackLabel.mcParticle_as(); + auto mctrackHad = prTrackLabel.mcParticle_as(); + + if (std::abs(mctrackHe3.pdgCode()) != hePDG || std::abs(mctrackHad.pdgCode()) != prPDG || !mctrackHe3.has_mothers() || !mctrackHad.has_mothers()) { + continue; + } + + for (auto& mothertrackHe : mctrackHe3.mothers_as()) { + for (auto& mothertrackHad : mctrackHad.mothers_as()) { + + if (mothertrackHe.globalIndex() != mothertrackHad.globalIndex() || std::abs(mothertrackHe.pdgCode()) != li4PDG || std::abs(mothertrackHe.y()) > 1) { + continue; + } + + he3HadCandidate he3Hadcand; + if (!fillCandidateInfo(heTrack, prTrack, collBracket, collisions, he3Hadcand, tracks, /*mix*/ false)) { + continue; + } + fillCandidateInfoMC(mctrackHe3, mctrackHad, mothertrackHe, he3Hadcand); + fillHistograms(he3Hadcand); + auto collision = collisions.rawIteratorAt(he3Hadcand.collisionID); + fillTable(he3Hadcand, collision, /*isMC*/ true); + filledMothers.push_back(mothertrackHe.globalIndex()); + } + } + } + + fillMcParticles(collisions, mcParticles, filledMothers); + } + PROCESS_SWITCH(he3hadronfemto, processMcPools, "Process MC pools", false); +}; + +WorkflowSpec defineDataProcessing(const ConfigContext& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"he3hadronfemto"})}; +} diff --git a/PWGLF/TableProducer/Nuspex/hypKfRecoTask.cxx b/PWGLF/TableProducer/Nuspex/hypKfRecoTask.cxx new file mode 100644 index 00000000000..68e334f5766 --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/hypKfRecoTask.cxx @@ -0,0 +1,1263 @@ +// 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 hypKfRecoTask.cxx +/// \brief Hypernuclei rconstruction using KFParticle package +/// \author Janik Ditzel and Michael Hartung + +#include +#include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/PID/TPCPIDResponse.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "DCAFitter/DCAFitterN.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGLF/DataModel/LFHypernucleiKfTables.h" +#include "TRandom3.h" +#include "Common/DataModel/CollisionAssociationTables.h" + +// KFParticle +#ifndef HomogeneousField +#define HomogeneousField // o2-linter: disable=[name/macro] +#endif +#include "KFParticle.h" +#include "KFPTrack.h" +#include "KFPVertex.h" +#include "KFParticleBase.h" +#include "KFVertex.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using CollisionsFull = soa::Join; +using CollisionsFullMC = soa::Join; +using TracksFull = soa::Join; + +//---------------------------------------------------------------------------------------------------------------- + +namespace +{ +static const int nDaughterParticles = 6; +enum DAUGHTERS { kPion, + kProton, + kDeuteron, + kTriton, + kHe3, + kAlpha }; + +static const std::vector particleNames{"pion", "proton", "deuteron", "triton", "helion", "alpha"}; +static const std::vector particlePdgCodes{211, 2212, o2::constants::physics::kDeuteron, o2::constants::physics::kTriton, o2::constants::physics::kHelium3, o2::constants::physics::kAlpha}; +static const std::vector particleMasses{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron, o2::constants::physics::MassTriton, o2::constants::physics::MassHelium3, o2::constants::physics::MassAlpha}; +static const std::vector particleCharge{1, 1, 1, 1, 2, 2}; + +const int nBetheParams = 6; +static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; +constexpr double betheBlochDefault[nDaughterParticles][nBetheParams]{ + {13.611469, 3.598765, -0.021138, 2.039562, 0.651040, 0.09}, // pion + {5.393020, 7.859534, 0.004048, 2.323197, 1.609307, 0.09}, // proton + {5.393020, 7.859534, 0.004048, 2.323197, 1.609307, 0.09}, // deuteron + {5.393020, 7.859534, 0.004048, 2.323197, 1.609307, 0.09}, // triton + {-126.557359, -0.858569, 1.111643, 1.210323, 2.656374, 0.09}, // helion + {-126.557359, -0.858569, 1.111643, 1.210323, 2.656374, 0.09}}; // alpha + +const int nTrkSettings = 15; +static const std::vector trackPIDsettingsNames{"useBBparams", "minITSnCls", "minTPCnCls", "maxTPCchi2", "maxITSchi2", "minRigidity", "maxRigidity", "maxTPCnSigma", "TOFrequiredabove", "minTOFmass", "maxTOFmass", "minDcaToPvXY", "minDcaToPvZ", "minITSclsSize", "maxITSclsSize"}; +constexpr double trackPIDsettings[nDaughterParticles][nTrkSettings]{ + {0, 0, 60, 3.0, 5000, 0.15, 1.2, 2.5, -1, 0, 100, 0., 0., 0., 1000}, + {1, 0, 70, 2.5, 5000, 0.20, 4.0, 3.0, -1, 0, 100, 0., 0., 0., 1000}, + {1, 0, 70, 5.0, 5000, 0.50, 5.0, 3.0, -1, 0, 100, 0., 0., 0., 1000}, + {1, 0, 70, 5.0, 5000, 0.50, 5.0, 3.0, -1, 0, 100, 0., 0., 0., 1000}, + {1, 0, 75, 1.5, 5000, 0.50, 5.0, 3.0, -1, 0, 100, 0., 0., 0., 1000}, + {1, 0, 70, 1.5, 5000, 0.50, 5.0, 3.0, -1, 0, 100, 0., 0., 0., 1000}}; + +static const int nHyperNuclei = 10; +static const std::vector hyperNucNames{"L->p+pi", "3LH->3He+pi", "3LH->d+p+pi", "4LH->4He+pi", "4LH->t+p+pi", "4LHe->3He+p+pi", "5LHe->4He+p+pi", "5LHe->3He+d+pi", "custom1", "custom2"}; +static const std::vector hyperNucEnabledLb{"enabled"}; +static const std::vector reduceLb{"reduce factor"}; +constexpr int hyperNucEnabled[nHyperNuclei][1]{{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}}; +constexpr float reduceFactor[nHyperNuclei][1]{{1.}, {1.}, {1.}, {1.}, {1.}, {1.}, {1.}, {1.}, {1.}, {1.}}; +static const std::vector hyperNucPdgLb{"PDG code"}; +static constexpr int hyperNucPdgCodes[nHyperNuclei][1]{ + {3122}, + {o2::constants::physics::kHyperTriton}, + {o2::constants::physics::kHyperTriton}, + {o2::constants::physics::kHyperHydrogen4}, + {o2::constants::physics::kHyperHydrogen4}, + {o2::constants::physics::kHyperHelium4}, + {o2::constants::physics::kHyperHelium5}, + {o2::constants::physics::kHyperHelium5}, + {0}, + {0}}; +static const std::vector hyperNucDaughtersLb{"daughter1", "daughter2", "daughter3", "daughter4"}; +static const std::string hyperNucDaughters[nHyperNuclei][4]{{"proton", "pion", "none", "none"}, {"helion", "pion", "none", "none"}, {"deuteron", "proton", "pion", "none"}, {"alpha", "pion", "none", "none"}, {"triton", "proton", "pion", "none"}, {"helion", "proton", "pion", "none"}, {"alpha", "proton", "pion", "none"}, {"helion", "deuteron", "pion", "none"}, {"none", "none", "none", "none"}, {"none", "none", "none", "none"}}; // NOLINT: runtime/string +static const std::string hyperNucSigns[nHyperNuclei][4]{{"+", "-", "", ""}, {"+", "-", "", ""}, {"+", "+", "-", ""}, {"+", "-", "", ""}, {"+", "+", "-", ""}, {"+", "+", "-", ""}, {"+", "+", "-", ""}, {"+", "+", "-", ""}, {"", "", "", ""}, {"", "", "", ""}}; // NOLINT: runtime/string +const int nSelPrim = 8; +static const std::vector preSelectionPrimNames{"minMass", "maxMass", "minCt", "maxCt", "minCosPa", "maxDcaTracks", "maxDcaMotherToPvXY", "maxDcaMotherToPvZ"}; +constexpr double preSelectionsPrimaries[nHyperNuclei][nSelPrim]{ + {1.00, 1.30, 0, 50, 0.90, 100., 2.0, 5.0}, + {2.96, 3.04, 0, 30, 0.99, 100., 1.5, 4.0}, + {2.96, 3.04, 0, 30, 0.99, 100., 1.5, 4.0}, + {3.87, 3.97, 0, 30, 0.95, 100., 2.0, 5.0}, + {3.87, 3.97, 0, 30, 0.95, 100., 2.0, 5.0}, + {3.85, 3.99, 0, 30, 0.98, 100., 1.5, 4.0}, + {4.60, 5.20, 0, 100, -1., 100., 10., 10.}, + {4.60, 5.20, 0, 100, -1., 100., 10., 10.}, + {0.00, 9.90, 0, 100, -1., 100., 10., 10.}, + {0.00, 9.90, 0, 100, -1., 100., 10., 10.}}; +const int nSelSec = 8; +static const std::vector preSelectionSecNames{"minMass", "maxMass", "minCt", "maxCt", "minCosPaSv", "maxDcaTracks", "maxDcaMotherToSvXY", "maxDcaMotherToSvZ"}; +constexpr double preSelectionsSecondaries[nHyperNuclei][nSelSec]{ + {1.00, 1.30, 0, 50, 0.90, 100., 2.0, 5.0}, + {2.96, 3.04, 0, 30, 0.99, 100., 1.5, 4.0}, + {2.96, 3.04, 0, 30, 0.99, 100., 1.5, 4.0}, + {3.87, 3.97, 0, 30, 0.95, 100., 2.0, 5.0}, + {3.87, 3.97, 0, 30, 0.95, 100., 2.0, 5.0}, + {3.85, 3.99, 0, 30, 0.98, 100., 1.5, 4.0}, + {4.60, 5.20, 0, 100, -1., 100., 10., 10.}, + {4.60, 5.20, 0, 100, -1., 100., 10., 10.}, + {0.00, 9.90, 0, 100, -1., 100., 10., 10.}, + {0.00, 9.90, 0, 100, -1., 100., 10., 10.}}; + +static const int nCascades = 6; +static const std::vector cascadeNames{"4LLH->4LHe+pi", "4XHe->4LHe+pi", "custom1", "custom2", "custom3", "custom4"}; +constexpr int cascadeEnabled[nCascades][1]{{0}, {0}, {0}, {0}, {0}, {0}}; +constexpr int cascadePdgCodes[nCascades][1]{ + {1020010040}, + {1120010040}, + {0}, + {0}, + {0}, + {0}}; +static const std::vector cascadeHypDaughterLb{"hypernucleus"}; +static const std::string cascadeHypDaughter[nCascades][1]{{"4LHe->3He+p+pi"}, {"4LHe->3He+p+pi"}, {"none"}, {"none"}, {"none"}, {"none"}}; // NOLINT: runtime/string +static const std::vector cascadeDaughtersLb{"daughter2", "daughter3", "daughter4"}; +static const std::string cascadeDaughters[nCascades][3]{{"pion", "none", "none"}, {"pion", "none", "none"}, {"none", "none", "none"}, {"none", "none", "none"}, {"none", "none", "none"}, {"none", "none", "none"}}; // NOLINT: runtime/string +static const std::string cascadeSigns[nCascades][4]{{"+", "-", "", ""}, {"+", "-", "", ""}, {"", "", "", ""}, {"", "", "", ""}, {"", "", "", ""}, {"", "", "", ""}}; // NOLINT: runtime/string +const int nSelCas = 8; +static const std::vector preSelectionCascadeNames{"minMass", "maxMass", "minCt", "maxCt", "minCosPa", "maxDcaTracks", "maxDcaMotherToPvXY", "maxDcaMotherToPvZ"}; +constexpr double preSelectionsCascades[nCascades][nSelCas]{ + {4.00, 4.20, 0, 30, 0.95, 100., 2.0, 5.}, + {4.00, 4.20, 0, 30, 0.95, 100., 2.0, 5.}, + {0.00, 9.90, 0, 100, -1., 100., 10., 10.}, + {0.00, 9.90, 0, 100, -1., 100., 10., 10.}, + {0.00, 9.90, 0, 100, -1., 100., 10., 10.}, + {0.00, 9.90, 0, 100, -1., 100., 10., 10.}}; + +//---------------------------------------------------------------------------------------------------------------- +struct DaughterParticle { + TString name; + int pdgCode, charge; + double mass, resolution; + std::vector betheParams; + bool active; + DaughterParticle(std::string name_, int pdgCode_, double mass_, int charge_, LabeledArray bethe) : name(name_), pdgCode(pdgCode_), charge(charge_), mass(mass_), active(false) + { + resolution = bethe.get(name, "resolution"); + betheParams.clear(); + for (unsigned int i = 0; i < 5; i++) + betheParams.push_back(bethe.get(name, i)); + } +}; // struct DaughterParticle + +struct HyperNucleus { + TString name; + int pdgCode; + bool active; + std::vector daughters, daughterTrackSigns; + HyperNucleus(std::string name_, int pdgCode_, bool active_, std::vector daughters_, std::vector daughterTrackSigns_) : pdgCode(pdgCode_), active(active_) + { + init(name_, daughters_, daughterTrackSigns_); + } + HyperNucleus(std::string name_, int pdgCode_, bool active_, int hypDaughter, std::vector daughters_, std::vector daughterTrackSigns_) : pdgCode(pdgCode_), active(active_) + { + daughters.push_back(hypDaughter); + init(name_, daughters_, daughterTrackSigns_); + } + void init(std::string name_, std::vector daughters_, std::vector daughterTrackSigns_) + { + name = TString(name_); + for (const int& d : daughters_) + daughters.push_back(d); + for (const int& dc : daughterTrackSigns_) + daughterTrackSigns.push_back(dc); + } + int getNdaughters() { return static_cast(daughters.size()); } + const char* motherName() { return name.Contains("->") ? ((TString)name(0, name.First("-"))).Data() : name.Data(); } + const char* daughterNames() { return name.Contains("->") ? ((TString)name(name.First("-") + 2, name.Length())).Data() : ""; } +}; // struct HyperNucleus + +struct DaughterKf { + int64_t daughterTrackId; + int hypNucId; + KFParticle daughterKfp; + float dcaToPv, dcaToPvXY, dcaToPvZ; + DaughterKf(int64_t daughterTrackId_, KFParticle daughterKfp_, std::vector vtx) : daughterTrackId(daughterTrackId_), hypNucId(-1), daughterKfp(daughterKfp_) + { + dcaToPvXY = daughterKfp.GetDistanceFromVertexXY(&vtx[0]); + dcaToPv = daughterKfp.GetDistanceFromVertex(&vtx[0]); + dcaToPvZ = std::sqrt(dcaToPv * dcaToPv - dcaToPvXY * dcaToPvXY); + } + DaughterKf(KFParticle daughterKfp_, int hypNucId_) : daughterTrackId(-999), hypNucId(hypNucId_), daughterKfp(daughterKfp_), dcaToPv(-999), dcaToPvXY(-999), dcaToPvZ(-999) {} +}; // struct DaughterKf + +struct HyperNucCandidate { + int species; + KFParticle kfp; + HyperNucCandidate* hypNucDaughter; + std::vector daughters; + std::vector recoSV; + std::vector> daughterPosMoms; + float mass, px, py, pz; + float devToPvXY, dcaToPvXY, dcaToPvZ, dcaToVtxXY, dcaToVtxZ, chi2; + bool mcTrue, isPhysPrimary, isPrimaryCandidate, isSecondaryCandidate, isUsedSecondary; + int64_t mcParticleId; + int tableId; + HyperNucCandidate(int species_, HyperNucCandidate* hypNucDaughter_, std::vector daughters_) : species(species_), hypNucDaughter(hypNucDaughter_), devToPvXY(999), dcaToPvXY(999), dcaToPvZ(999), dcaToVtxXY(999), dcaToVtxZ(999), chi2(999), mcTrue(false), isPhysPrimary(false), isPrimaryCandidate(false), isSecondaryCandidate(false), isUsedSecondary(false), mcParticleId(-1), tableId(-1) + { + for (const auto& d : daughters_) + daughters.push_back(d); + kfp.SetConstructMethod(2); + for (size_t i = 0; i < daughters.size(); i++) + kfp.AddDaughter(daughters.at(i)->daughterKfp); + kfp.TransportToDecayVertex(); + chi2 = kfp.GetChi2() / kfp.GetNDF(); + recoSV.clear(); + recoSV.push_back(kfp.GetX()); + recoSV.push_back(kfp.GetY()); + recoSV.push_back(kfp.GetZ()); + mass = kfp.GetMass(); + px = kfp.GetPx(); + py = kfp.GetPy(); + pz = kfp.GetPz(); + } + std::vector daughterTrackIds() + { + std::vector trackIds; + for (const auto& daughter : daughters) { + const auto& id = daughter->daughterTrackId; + if (id >= 0) + trackIds.push_back(id); + } + return trackIds; + } + bool checkKfp() { return mass != 0 && !std::isnan(mass); } + int getDaughterTableId() { return hypNucDaughter ? hypNucDaughter->tableId : -1; } + bool isCascade() { return hypNucDaughter != 0; } + int getSign() + { + if (kfp.GetQ() == 0) + return daughters.front()->daughterKfp.GetQ() / std::abs(daughters.front()->daughterKfp.GetQ()); + return kfp.GetQ() / std::abs(kfp.GetQ()); + } + int getNdaughters() { return static_cast(daughters.size()); } + float getDcaTracks() + { + if (!daughterPosMoms.size()) + setDaughterPosMoms(); + float maxDca = std::numeric_limits::lowest(); + for (size_t i = 0; i < daughters.size(); i++) { + float dx = daughterPosMoms.at(i).at(0) - recoSV[0]; + float dy = daughterPosMoms.at(i).at(1) - recoSV[1]; + const float dca = std::sqrt(dx * dx + dy * dy); + if (dca > maxDca) + maxDca = dca; + } + return maxDca; + } + float getDcaMotherToVertex(std::vector vtx) { return kfp.GetDistanceFromVertex(&vtx[0]); } + double getCpa(std::vector vtx) + { + return RecoDecay::cpa(std::array{vtx[0], vtx[1], vtx[2]}, std::array{recoSV[0], recoSV[1], recoSV[2]}, std::array{px, py, pz}); + } + float getCt(std::vector vtx) + { + float dl = 0; + for (size_t i = 0; i < vtx.size(); i++) { + float tmp = recoSV.at(i) - vtx.at(i); + dl += (tmp * tmp); + } + return std::sqrt(dl) * mass / std::sqrt(px * px + py * py + pz * pz); + } + void setDaughterPosMoms() + { + for (size_t i = 0; i < daughters.size(); i++) { + daughterPosMoms.push_back(getDaughterPosMom(i)); + } + } + std::vector getDaughterPosMom(int daughter) + { + std::vector posMom; + auto kfpDaughter = daughters.at(daughter)->daughterKfp; + kfpDaughter.TransportToPoint(&recoSV[0]); + posMom.assign({kfpDaughter.GetX(), kfpDaughter.GetY(), kfpDaughter.GetZ(), kfpDaughter.GetPx(), kfpDaughter.GetPy(), kfpDaughter.GetPz()}); + return posMom; + } + float getDcaMotherToVtxXY(std::vector vtx) { return kfp.GetDistanceFromVertexXY(&vtx[0]); } + float getDcaMotherToVtxZ(std::vector vtx) + { + kfp.TransportToPoint(&vtx[0]); + return kfp.GetZ() - vtx[2]; + } + void calcDcaToVtx(KFPVertex& vtx) + { + if (devToPvXY != 999) + return; + devToPvXY = kfp.GetDeviationFromVertexXY(vtx); + dcaToPvXY = kfp.GetDistanceFromVertexXY(vtx); + kfp.TransportToVertex(vtx); + dcaToPvZ = kfp.GetZ() - vtx.GetZ(); + } + void calcDcaToVtx(HyperNucCandidate& cand) + { + dcaToVtxXY = getDcaMotherToVtxXY(cand.recoSV); + dcaToVtxZ = getDcaMotherToVtxZ(cand.recoSV); + } + float getSubDaughterMass(int d1, int d2) + { + KFParticle subDaughter; + subDaughter.SetConstructMethod(2); + subDaughter.AddDaughter(daughters.at(d1)->daughterKfp); + subDaughter.AddDaughter(daughters.at(d2)->daughterKfp); + subDaughter.TransportToDecayVertex(); + return subDaughter.GetMass(); + } +}; // struct HyperNucCandidate + +struct IndexPairs { + std::vector> pairs; + + void add(int64_t a, int b) { pairs.push_back({a, b}); } + void clear() { pairs.clear(); } + bool getIndex(int64_t a, int& b) + { + for (const auto& pair : pairs) { + if (pair.first == a) { + b = pair.second; + return true; + } + } + return false; + } +}; // struct IndexPairs + +struct McCollInfo { + bool hasRecoColl; + bool passedEvSel; + bool hasRecoParticle; + int tableIndex; + McCollInfo() : hasRecoColl(false), passedEvSel(false), hasRecoParticle(false), tableIndex(-1) {} +}; // struct McCollInfo + +//---------------------------------------------------------------------------------------------------------------- +std::vector> hDeDx; +std::vector> hInvMass; +} // namespace + +//---------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------- +struct HypKfRecoTask { + + Produces outputMcCollisionTable; + Produces outputMcParticleTable; + Produces outputCollisionTable; + Produces outputTrackTable; + Produces outputDaughterAddonTable; + Produces outputSubDaughterTable; + Produces outputHypNucTable; + + Preslice perCollision = aod::track_association::collisionId; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable cfgSaveOnlyMcTrue{"cfgSaveOnlyMcTrue", true, "save only MCtrue candidates"}; + Configurable cfgDebug{"cfgDebug", 1, "debug level"}; + + Configurable cfgRigidityCorrection{"cfgRigidityCorrection", false, "apply rigidity correction"}; + Configurable cfgCutEta{"cfgCutEta", 0.9f, "Eta range for tracks"}; + Configurable cfgUsePVcontributors{"cfgUsePVcontributors", true, "use tracks that are PV contibutors"}; + + Configurable> cfgHyperNucsActive{"cfgHyperNucsActive", {hyperNucEnabled[0], nHyperNuclei, 1, hyperNucNames, hyperNucEnabledLb}, "enable or disable reconstruction"}; + Configurable> cfgReduce{"cfgReduce", {reduceFactor[0], nHyperNuclei, 1, hyperNucNames, reduceLb}, "reconstruct only a percentage of all possible hypernuclei"}; + Configurable> cfgHyperNucPdg{"cfgHyperNucPdg", {hyperNucPdgCodes[0], nHyperNuclei, 1, hyperNucNames, hyperNucPdgLb}, "PDG codes"}; + Configurable> cfgHyperNucDaughters{"cfgHyperNucDaughters", {hyperNucDaughters[0], nHyperNuclei, 4, hyperNucNames, hyperNucDaughtersLb}, "Daughter particles"}; + Configurable> cfgHyperNucSigns{"cfgHyperNucSigns", {hyperNucSigns[0], nHyperNuclei, 4, hyperNucNames, hyperNucDaughtersLb}, "Daughter signs"}; + + Configurable> cfgCascadesActive{"cfgCascadesActive", {cascadeEnabled[0], nCascades, 1, cascadeNames, hyperNucEnabledLb}, "enable or disable reconstruction"}; + Configurable> cfgCascadesPdg{"cfgCascadesPdg", {cascadePdgCodes[0], nCascades, 1, cascadeNames, hyperNucPdgLb}, "PDG codes"}; + Configurable> cfgCascadeHypDaughter{"cfgCascadeHypDaughter", {cascadeHypDaughter[0], nCascades, 1, cascadeNames, cascadeHypDaughterLb}, "Hyernuclei daugther"}; + Configurable> cfgCascadeDaughters{"cfgCascadeDaughters", {cascadeDaughters[0], nCascades, 3, cascadeNames, cascadeDaughtersLb}, "Daughter particles"}; + Configurable> cfgCascadeSigns{"cfgCascadeSigns", {cascadeSigns[0], nCascades, 4, cascadeNames, hyperNucDaughtersLb}, "Daughter signs"}; + + Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {betheBlochDefault[0], nDaughterParticles, nBetheParams, particleNames, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for light nuclei"}; + Configurable> cfgTrackPIDsettings{"cfgTrackPIDsettings", {trackPIDsettings[0], nDaughterParticles, nTrkSettings, particleNames, trackPIDsettingsNames}, "track selection and PID criteria"}; + Configurable> cfgPreSelectionsPrimaries{"cfgPreSelectionsPrimaries", {preSelectionsPrimaries[0], nHyperNuclei, nSelPrim, hyperNucNames, preSelectionPrimNames}, "selection criteria for primary hypernuclei"}; + Configurable> cfgPreSelectionsSecondaries{"cfgPreSelectionsSecondaries", {preSelectionsSecondaries[0], nHyperNuclei, nSelSec, hyperNucNames, preSelectionSecNames}, "selection criteria for secondary hypernuclei"}; + Configurable> cfgPreSelectionsCascades{"cfgPreSelectionsCascades", {preSelectionsCascades[0], nCascades, nSelCas, cascadeNames, preSelectionCascadeNames}, "selection criteria for cascade hypernuclei"}; + + // CCDB + Service ccdb; + Configurable bField{"bField", -999, "bz field, -999 is automatic"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable pidPath{"pidPath", "", "Path to the PID response object"}; + + std::vector daughterParticles; + std::vector> foundDaughters; + std::vector> foundDaughterKfs, hypNucDaughterKfs; + std::vector> singleHyperNucCandidates, cascadeHyperNucCandidates; + std::vector singleHyperNuclei, cascadeHyperNuclei; + std::vector primVtx, cents; + std::vector mcCollInfos; + IndexPairs trackIndices, mcPartIndices; + KFPVertex kfPrimVtx; + bool collHasCandidate, collHasMcTrueCandidate, collPassedEvSel, activeCascade; + int64_t mcCollTableIndex; + int mRunNumber, occupancy; + float dBz; + TRandom3 rand; + //---------------------------------------------------------------------------------------------------------------- + + void init(InitContext const&) + { + mRunNumber = 0; + dBz = 0; + rand.SetSeed(0); + + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + for (int i = 0; i < nDaughterParticles; i++) { // create daughterparticles + daughterParticles.push_back(DaughterParticle(particleNames.at(i), particlePdgCodes.at(i), particleMasses.at(i), particleCharge.at(i), cfgBetheBlochParams)); + } + for (unsigned int i = 0; i < nHyperNuclei; i++) { // create hypernuclei + singleHyperNuclei.push_back(HyperNucleus(hyperNucNames.at(i), cfgHyperNucPdg->get(i, 0u), cfgHyperNucsActive->get(i, 0u), getDaughterVec(i, cfgHyperNucDaughters), getDaughterSignVec(i, cfgHyperNucSigns))); + } + activeCascade = false; + for (unsigned int i = 0; i < nCascades; i++) { // create cascades + cascadeHyperNuclei.push_back(HyperNucleus(cascadeNames.at(i), cfgCascadesPdg->get(i, 0u), cfgCascadesActive->get(i, 0u), getHypDaughterVec(i, cfgCascadeHypDaughter), getDaughterVec(i, cfgCascadeDaughters), getDaughterSignVec(i, cfgCascadeSigns))); + if (cfgCascadesActive->get(i, 0u)) + activeCascade = true; + } + // define histogram axes + const AxisSpec axisMagField{10, -10., 10., "magnetic field"}; + const AxisSpec axisNev{3, 0., 3., "Number of events"}; + const AxisSpec axisRigidity{4000, -10., 10., "#it{p}^{TPC}/#it{z}"}; + const AxisSpec axisdEdx{2000, 0, 2000, "d#it{E}/d#it{x}"}; + const AxisSpec axisInvMass{1000, 1, 6, "inv mass"}; + const AxisSpec axisCent{100, 0, 100, "centrality"}; + const AxisSpec axisOccupancy{5000, 0, 50000, "occupancy"}; + const AxisSpec axisVtxZ{100, -10, 10, "z"}; + // create histograms + histos.add("histMagField", "histMagField", kTH1F, {axisMagField}); + histos.add("histNev", "histNev", kTH1F, {axisNev}); + histos.add("histVtxZ", "histVtxZ", kTH1F, {axisVtxZ}); + histos.add("histCentFT0A", "histCentFT0A", kTH1F, {axisCent}); + histos.add("histCentFT0C", "histCentFT0C", kTH1F, {axisCent}); + histos.add("histCentFT0M", "histCentFT0M", kTH1F, {axisCent}); + histos.add("histEvents", "histEvents", kTH2F, {axisCent, axisOccupancy}); + hDeDx.resize(2 * nDaughterParticles + 2); + for (int i = 0; i < nDaughterParticles + 1; i++) { + TString histName = i < nDaughterParticles ? daughterParticles[i].name : "all"; + hDeDx[2 * i] = histos.add(Form("histdEdx_%s", histName.Data()), ";p_{TPC}/z (GeV/#it{c}); d#it{E}/d#it{x}", HistType::kTH2F, {axisRigidity, axisdEdx}); + hDeDx[2 * i + 1] = histos.add(Form("histdEdx_%s_Cuts", histName.Data()), ";p_{TPC}/z (GeV/#it{c}); d#it{E}/d#it{x}", HistType::kTH2F, {axisRigidity, axisdEdx}); + } + // create invariant mass histograms + hInvMass.resize(nHyperNuclei + nCascades); + int histCount = 0; + std::vector> hypNucVectors = {singleHyperNuclei, cascadeHyperNuclei}; + for (size_t i = 0; i < hypNucVectors.size(); i++) { + for (size_t j = 0; j < hypNucVectors.at(i).size(); j++) { + if (hypNucVectors.at(i).at(j).active) { + hInvMass[histCount] = histos.add(Form("h%d_%s", histCount, hypNucVectors.at(i).at(j).motherName()), ";;Counts", HistType::kTH1F, {axisInvMass}); + } + histCount++; + } + } + } + //---------------------------------------------------------------------------------------------------------------- + + void findDaughterParticles(aod::TrackAssoc const& tracksByColl, TracksFull const& tracks) + { + // track loop, store daughter candidates in std::vector + for (const auto& trackId : tracksByColl) { + const auto& track = tracks.rawIteratorAt(trackId.trackId()); + filldedx(track, nDaughterParticles); + if (std::abs(track.eta()) > cfgCutEta) + continue; + if (!cfgUsePVcontributors && track.isPVContributor()) + continue; + for (size_t i = 0; i < daughterParticles.size(); i++) { + if (track.tpcNClsFound() < cfgTrackPIDsettings->get(i, "minTPCnCls")) + continue; + if (track.tpcChi2NCl() > cfgTrackPIDsettings->get(i, "maxTPCchi2")) + continue; + if (track.itsNCls() < cfgTrackPIDsettings->get(i, "minITSnCls")) + continue; + if (track.itsChi2NCl() > cfgTrackPIDsettings->get(i, "maxITSchi2")) + continue; + if (std::abs(getTPCnSigma(track, daughterParticles.at(i))) > cfgTrackPIDsettings->get(i, "maxTPCnSigma")) + continue; + filldedx(track, i); + if (getMeanItsClsSize(track) < cfgTrackPIDsettings->get(i, "minITSclsSize")) + continue; + if (getMeanItsClsSize(track) > cfgTrackPIDsettings->get(i, "maxITSclsSize")) + continue; + if (getRigidity(track) < cfgTrackPIDsettings->get(i, "minRigidity") || getRigidity(track) > cfgTrackPIDsettings->get(i, "maxRigidity")) + continue; + if (cfgTrackPIDsettings->get(i, "TOFrequiredabove") >= 0 && getRigidity(track) > cfgTrackPIDsettings->get(i, "TOFrequiredabove") && (track.mass() < cfgTrackPIDsettings->get(i, "minTOFmass") || track.mass() > cfgTrackPIDsettings->get(i, "maxTOFmass"))) + continue; + foundDaughters.at(i).push_back(track.globalIndex()); + } + } // track loop + } + + //---------------------------------------------------------------------------------------------------------------- + void checkMCTrueTracks(aod::McTrackLabels const& trackLabels, aod::McParticles const&) + { + std::vector activePdgs; + std::vector*> hypNucVectors = {&singleHyperNuclei, &cascadeHyperNuclei}; + for (int vec = 0; vec < 2; vec++) { + for (size_t hyperNucIter = 0; hyperNucIter < hypNucVectors.at(vec)->size(); hyperNucIter++) { + HyperNucleus* hyperNuc = &(hypNucVectors.at(vec)->at(hyperNucIter)); + if (!hyperNuc->active) + continue; + activePdgs.push_back(std::abs(hyperNuc->pdgCode)); + } + } + for (int i = 0; i < nDaughterParticles; i++) { + auto& daughterVec = foundDaughters.at(i); + if (!daughterVec.size()) + continue; + for (auto it = daughterVec.end() - 1; it >= daughterVec.begin(); it--) { + const auto& mcLab = trackLabels.rawIteratorAt(*it); + if (!mcLab.has_mcParticle()) { + daughterVec.erase(it); + continue; + } + const auto& mcPart = mcLab.mcParticle_as(); + if (std::abs(mcPart.pdgCode()) != daughterParticles.at(i).pdgCode) { + daughterVec.erase(it); + continue; + } + if (!mcPart.has_mothers()) { + daughterVec.erase(it); + continue; + } + bool isDaughter = false; + for (const auto& mother : mcPart.mothers_as()) { + if (std::find(activePdgs.begin(), activePdgs.end(), std::abs(mother.pdgCode())) != activePdgs.end()) { + isDaughter = true; + } + } + if (!isDaughter) { + daughterVec.erase(it); + continue; + } + } + } + } + //---------------------------------------------------------------------------------------------------------------- + void createKFDaughters(TracksFull const& tracks) + { + std::vector*> hypNucVectors = {&singleHyperNuclei, &cascadeHyperNuclei}; + for (size_t vec = 0; vec < 2; vec++) { + for (const auto& hyperNuc : *(hypNucVectors.at(vec))) { + if (!hyperNuc.active) + continue; + for (size_t i = vec; i < hyperNuc.daughters.size(); i++) { + if (foundDaughters.at(hyperNuc.daughters.at(i)).size() > 0) + daughterParticles.at(hyperNuc.daughters.at(i)).active = true; + else + break; + } + } + } + for (size_t daughterCount = 0; daughterCount < daughterParticles.size(); daughterCount++) { + const auto& daughterParticle = daughterParticles.at(daughterCount); + if (!daughterParticle.active) + continue; + const auto& daughterMass = daughterParticle.mass; + const auto& daughterCharge = daughterParticle.charge; + for (const auto& daughterId : foundDaughters.at(daughterCount)) { + const auto& daughterTrack = tracks.rawIteratorAt(daughterId); + DaughterKf daughter(daughterId, createKFParticle(daughterTrack, daughterMass, daughterCharge), primVtx); + if (std::abs(daughter.dcaToPvXY) < cfgTrackPIDsettings->get(daughterCount, "minDcaToPvXY")) + continue; + if (std::abs(daughter.dcaToPvZ) < cfgTrackPIDsettings->get(daughterCount, "minDcaToPvZ")) + continue; + foundDaughterKfs.at(daughterCount).push_back(daughter); + } + } + } + //---------------------------------------------------------------------------------------------------------------- + + void createKFHypernuclei(TracksFull const& tracks) + { + // loop over all hypernuclei that are to be reconstructed + for (size_t hyperNucIter = 0; hyperNucIter < singleHyperNuclei.size(); hyperNucIter++) { + HyperNucleus* hyperNuc = &(singleHyperNuclei.at(hyperNucIter)); + if (!hyperNuc->active) + continue; + int nDaughters = hyperNuc->getNdaughters(); + std::vector::iterator> it; + int nCombinations = 1; + for (int i = 0; i < nDaughters; i++) { + nCombinations *= foundDaughterKfs.at(hyperNuc->daughters.at(i)).size(); + it.push_back(foundDaughterKfs.at(hyperNuc->daughters.at(i)).begin()); + } + if (!nCombinations) + continue; + const float reduceFactor = cfgReduce->get(hyperNucIter, 0u); + const float minMassPrim = cfgPreSelectionsPrimaries->get(hyperNucIter, "minMass"); + const float maxMassPrim = cfgPreSelectionsPrimaries->get(hyperNucIter, "maxMass"); + const float minCtPrim = cfgPreSelectionsPrimaries->get(hyperNucIter, "minCt"); + const float maxCtPrim = cfgPreSelectionsPrimaries->get(hyperNucIter, "maxCt"); + const float minCosPaPrim = cfgPreSelectionsPrimaries->get(hyperNucIter, "minCosPa"); + const float maxDcaTracksPrim = cfgPreSelectionsPrimaries->get(hyperNucIter, "maxDcaTracks"); + const float maxDcaMotherToPvXYPrim = cfgPreSelectionsPrimaries->get(hyperNucIter, "maxDcaMotherToPvXY"); + const float maxDcaMotherToPvZPrim = cfgPreSelectionsPrimaries->get(hyperNucIter, "maxDcaMotherToPvZ"); + const float minMassSec = cfgPreSelectionsSecondaries->get(hyperNucIter, "minMass"); + const float maxMassSec = cfgPreSelectionsSecondaries->get(hyperNucIter, "maxMass"); + const float minCtSec = cfgPreSelectionsSecondaries->get(hyperNucIter, "minCt"); + const float maxCtSec = cfgPreSelectionsSecondaries->get(hyperNucIter, "maxCt"); + const float maxDcaTracksSec = cfgPreSelectionsSecondaries->get(hyperNucIter, "maxDcaTracks"); + while (it[0] != foundDaughterKfs.at(hyperNuc->daughters.at(0)).end()) { + // check for correct signs, avoid double usage of tracks + bool passedChecks = true; + int checkSign = 0; + std::vector vec; + for (int i = 0; i < nDaughters; i++) { + const auto& daughterTrack = tracks.rawIteratorAt(it[i]->daughterTrackId); + if (!i) + checkSign = daughterTrack.sign(); + if (daughterTrack.sign() != checkSign * hyperNuc->daughterTrackSigns.at(i) || std::find(vec.begin(), vec.end(), it[i]->daughterTrackId) != vec.end()) { + passedChecks = false; + break; + } + vec.push_back(it[i]->daughterTrackId); + } + if (passedChecks && rand.Rndm() <= reduceFactor) { + std::vector daughters; + for (int i = 0; i < nDaughters; i++) { + daughters.push_back(&(*it[i])); + } + HyperNucCandidate candidate(hyperNucIter, static_cast(0), daughters); + // check preselections + if (candidate.checkKfp()) { + if (candidate.mass <= maxMassPrim && candidate.mass >= minMassPrim && candidate.getDcaTracks() <= maxDcaTracksPrim && candidate.getCt(primVtx) <= maxCtPrim && candidate.getCt(primVtx) >= minCtPrim && candidate.getCpa(primVtx) >= minCosPaPrim) { + candidate.calcDcaToVtx(kfPrimVtx); + if (std::abs(candidate.dcaToPvXY) <= maxDcaMotherToPvXYPrim && std::abs(candidate.dcaToPvZ) <= maxDcaMotherToPvZPrim) { + candidate.isPrimaryCandidate = true; + collHasCandidate = true; + } + } + if (activeCascade && candidate.mass <= maxMassSec && candidate.mass >= minMassSec && candidate.getDcaTracks() <= maxDcaTracksSec && candidate.getCt(primVtx) <= maxCtSec && candidate.getCt(primVtx) >= minCtSec) { + candidate.calcDcaToVtx(kfPrimVtx); + candidate.isSecondaryCandidate = true; + } + if (candidate.isPrimaryCandidate || candidate.isSecondaryCandidate) + singleHyperNucCandidates.at(hyperNucIter).push_back(candidate); + } + } + it[nDaughters - 1]++; + for (int i = nDaughters - 1; i && it[i] == foundDaughterKfs.at(hyperNuc->daughters.at(i)).end(); i--) { + it[i] = foundDaughterKfs.at(hyperNuc->daughters.at(i)).begin(); + it[i - 1]++; + } + } + } + } + //---------------------------------------------------------------------------------------------------------------- + void createKFCascades(TracksFull const& tracks) + { + // loop over all cascade hypernuclei that are to be reconstructed + for (size_t hyperNucIter = 0; hyperNucIter < cascadeHyperNuclei.size(); hyperNucIter++) { + HyperNucleus* hyperNuc = &(cascadeHyperNuclei.at(hyperNucIter)); + if (!hyperNuc->active) + continue; + int nDaughters = hyperNuc->getNdaughters(); + + int nHypNucDaughters = singleHyperNucCandidates.at(hyperNuc->daughters.at(0)).size(); + for (int64_t i = 0; i < static_cast(nHypNucDaughters); i++) { + if (singleHyperNucCandidates.at(hyperNuc->daughters.at(0)).at(i).isSecondaryCandidate) { + auto hypNucDaughter = &(singleHyperNucCandidates.at(hyperNuc->daughters.at(0)).at(i)); + hypNucDaughterKfs.at(hyperNucIter).push_back(DaughterKf(hypNucDaughter->kfp, i)); + } + } + int nCombinations = hypNucDaughterKfs.at(hyperNucIter).size(); + std::vector::iterator> it; + it.push_back(hypNucDaughterKfs.at(hyperNucIter).begin()); + for (int i = 1; i < nDaughters; i++) { + nCombinations *= foundDaughterKfs.at(hyperNuc->daughters.at(i)).size(); + it.push_back(foundDaughterKfs.at(hyperNuc->daughters.at(i)).begin()); + } + if (!nCombinations) + continue; + const float minMassCas = cfgPreSelectionsCascades->get(hyperNucIter, "minMass"); + const float maxMassCas = cfgPreSelectionsCascades->get(hyperNucIter, "maxMass"); + const float minCtCas = cfgPreSelectionsCascades->get(hyperNucIter, "minCt"); + const float maxCtCas = cfgPreSelectionsCascades->get(hyperNucIter, "maxCt"); + const float minCosPaCas = cfgPreSelectionsCascades->get(hyperNucIter, "minCosPa"); + const float maxDcaTracksCas = cfgPreSelectionsCascades->get(hyperNucIter, "maxDcaTracks"); + const float maxDcaMotherToPvXYCas = cfgPreSelectionsCascades->get(hyperNucIter, "maxDcaMotherToPvXY"); + const float maxDcaMotherToPvZCas = cfgPreSelectionsCascades->get(hyperNucIter, "maxDcaMotherToPvZ"); + const float minCtSec = cfgPreSelectionsSecondaries->get(hyperNuc->daughters.at(0), "minCt"); + const float maxCtSec = cfgPreSelectionsSecondaries->get(hyperNuc->daughters.at(0), "maxCt"); + const float minCosPaSvSec = cfgPreSelectionsSecondaries->get(hyperNuc->daughters.at(0), "minCosPaSv"); + const float maxDcaMotherToSvXYSec = cfgPreSelectionsSecondaries->get(hyperNuc->daughters.at(0), "maxDcaMotherToSvXY"); + const float maxDcaMotherToSvZSec = cfgPreSelectionsSecondaries->get(hyperNuc->daughters.at(0), "maxDcaMotherToSvZ"); + + while (it[0] != hypNucDaughterKfs.at(hyperNucIter).end()) { + // select hypernuclei daughter KFParticle + auto hypNucDaughter = &(singleHyperNucCandidates.at(hyperNuc->daughters.at(0)).at(it[0]->hypNucId)); + // check for correct signs + int checkSign = hypNucDaughter->getSign(); + bool passedChecks = true; + std::vector vec = hypNucDaughter->daughterTrackIds(); + for (int i = 1; i < nDaughters; i++) { + const auto& daughterTrack = tracks.rawIteratorAt(it[i]->daughterTrackId); + if (daughterTrack.sign() != checkSign * hyperNuc->daughterTrackSigns.at(i) || std::find(vec.begin(), vec.end(), it[i]->daughterTrackId) != vec.end()) { + passedChecks = false; + break; + } + vec.push_back(it[i]->daughterTrackId); + } + if (passedChecks) { + std::vector daughters; + daughters.push_back(&(*it[0])); + for (int i = 1; i < nDaughters; i++) { + daughters.push_back(&(*it[i])); + } + HyperNucCandidate candidate(hyperNucIter, hypNucDaughter, daughters); + if (candidate.checkKfp()) { + // preselections for cascade and hypernucleus daughter + if (candidate.mass <= maxMassCas && candidate.mass >= minMassCas && candidate.getDcaTracks() <= maxDcaTracksCas && candidate.getCt(primVtx) >= minCtCas && candidate.getCt(primVtx) <= maxCtCas && hypNucDaughter->getCt(candidate.recoSV) >= minCtSec && hypNucDaughter->getCt(candidate.recoSV) <= maxCtSec && candidate.getCpa(primVtx) >= minCosPaCas && hypNucDaughter->getCpa(candidate.recoSV) >= minCosPaSvSec) { + candidate.calcDcaToVtx(kfPrimVtx); + if (std::abs(candidate.dcaToPvXY) <= maxDcaMotherToPvXYCas && std::abs(candidate.dcaToPvZ) <= maxDcaMotherToPvZCas) { + hypNucDaughter->calcDcaToVtx(candidate); + if (hypNucDaughter->dcaToVtxXY <= maxDcaMotherToSvXYSec && hypNucDaughter->dcaToVtxZ <= maxDcaMotherToSvZSec) { + collHasCandidate = true; + hypNucDaughter->isUsedSecondary = true; + cascadeHyperNucCandidates.at(hyperNucIter).push_back(candidate); + } + } + } + } + } + it[nDaughters - 1]++; + for (int i = nDaughters - 1; i && it[i] == foundDaughterKfs.at(hyperNuc->daughters.at(i)).end(); i--) { + it[i] = foundDaughterKfs.at(hyperNuc->daughters.at(i)).begin(); + it[i - 1]++; + } + } + } + } + //---------------------------------------------------------------------------------------------------------------- + void createMCinfo(aod::McTrackLabels const& trackLabels, aod::McCollisionLabels const&, aod::McParticles const& particlesMC, aod::McCollisions const&, bool cascadesOnly = false) + { + // check for mcTrue: single (primary & cascade daughter) and cascade hypernuclei + std::vector*> hypNucVectors = {&singleHyperNuclei, &cascadeHyperNuclei}; + std::vector>*> candidateVectors = {&singleHyperNucCandidates, &cascadeHyperNucCandidates}; + const int nVecs = candidateVectors.size(); + const int startVec = cascadesOnly ? 1 : 0; + for (int vec = startVec; vec < nVecs; vec++) { + auto candidateVector = candidateVectors.at(vec); + for (size_t hyperNucIter = 0; hyperNucIter < hypNucVectors.at(vec)->size(); hyperNucIter++) { + HyperNucleus* hyperNuc = &(hypNucVectors.at(vec)->at(hyperNucIter)); + if (!hyperNuc->active) + continue; + for (auto& hypCand : candidateVector->at(hyperNucIter)) { // o2-linter: disable=[const-ref-in-for-loop] + std::vector motherIds; + int daughterCount = 0; + if (hypCand.isCascade()) { + if (!hypCand.hypNucDaughter->mcTrue) + continue; + const auto& mcPart = particlesMC.rawIteratorAt(hypCand.hypNucDaughter->mcParticleId); + if (!mcPart.has_mothers()) + continue; + for (const auto& mother : mcPart.mothers_as()) { + if (mother.pdgCode() == hyperNuc->pdgCode * hypCand.getSign()) { + motherIds.push_back(mother.globalIndex()); + break; + } + } + daughterCount++; + } + for (const auto& daughter : hypCand.daughters) { + if (daughter->daughterTrackId < 0) + continue; + const auto& mcLab = trackLabels.rawIteratorAt(daughter->daughterTrackId); + if (!mcLab.has_mcParticle()) + continue; + const auto& mcPart = mcLab.mcParticle_as(); + if (std::abs(mcPart.pdgCode()) != daughterParticles.at(hyperNuc->daughters.at(daughterCount++)).pdgCode) + continue; + if (!mcPart.has_mothers()) + continue; + for (const auto& mother : mcPart.mothers_as()) { + if (mother.pdgCode() == hyperNuc->pdgCode * hypCand.getSign()) { + motherIds.push_back(mother.globalIndex()); + break; + } + } + } + if (motherIds.size() != hyperNuc->daughters.size()) { + if (cfgSaveOnlyMcTrue) + hypCand.isSecondaryCandidate = false; + continue; + } + hypCand.mcTrue = true; + for (auto iter = motherIds.begin(); iter != motherIds.end() - 1; iter++) + if (*iter != *(iter + 1)) + hypCand.mcTrue = false; + if (hypCand.mcTrue) { + hypCand.mcParticleId = motherIds.front(); + collHasMcTrueCandidate = true; + } + if (!hypCand.mcTrue && cfgSaveOnlyMcTrue) + hypCand.isSecondaryCandidate = false; + } + } + } + } + //---------------------------------------------------------------------------------------------------------------- + + void fillTree(TracksFull const& tracks, bool saveOnlyMcTrue = false) + { + + outputCollisionTable( + collPassedEvSel, mcCollTableIndex, + primVtx.at(0), primVtx.at(1), primVtx.at(2), + cents.at(0), cents.at(1), cents.at(2), occupancy); + + std::vector*> hypNucVectors = {&singleHyperNuclei, &cascadeHyperNuclei}; + std::vector>*> candidateVectors = {&singleHyperNucCandidates, &cascadeHyperNucCandidates}; + + for (int vec = 0; vec < 2; vec++) { + auto candidateVector = candidateVectors.at(vec); + for (size_t hyperNucIter = 0; hyperNucIter < hypNucVectors.at(vec)->size(); hyperNucIter++) { + HyperNucleus* hyperNuc = &(hypNucVectors.at(vec)->at(hyperNucIter)); + if (!hyperNuc->active) + continue; + for (auto& hypCand : candidateVector->at(hyperNucIter)) { // o2-linter: disable=[const-ref-in-for-loop] + if (!hypCand.isPrimaryCandidate && !hypCand.isUsedSecondary && !hypCand.isCascade()) + continue; + if (saveOnlyMcTrue && !hypCand.mcTrue && !hypCand.isCascade()) + continue; + hInvMass[vec * nHyperNuclei + hyperNucIter]->Fill(hypCand.mass); + std::vector vecDaugtherTracks, vecAddons, vecSubDaughters; + int daughterCount = 0; + for (const auto& daughter : hypCand.daughters) { + const auto& daughterTrackId = daughter->daughterTrackId; + if (daughterTrackId < 0) + continue; + int trackTableId; + if (!trackIndices.getIndex(daughterTrackId, trackTableId)) { + auto daught = hyperNuc->daughters.at(daughterCount); + const auto& track = tracks.rawIteratorAt(daughterTrackId); + outputTrackTable( + hyperNuc->daughters.at(daughterCount) * track.sign(), + track.pt(), track.eta(), track.phi(), + daughter->dcaToPvXY, daughter->dcaToPvZ, + track.tpcNClsFound(), track.tpcChi2NCl(), + track.itsClusterSizes(), track.itsChi2NCl(), + getRigidity(track), track.tpcSignal(), getTPCnSigma(track, daughterParticles.at(daught)), + daught == kAlpha ? -999 : getTPCnSigma(track, daughterParticles.at(daught + 1)), + daught == kPion ? 999 : getTPCnSigma(track, daughterParticles.at(daught - 1)), + track.mass(), + track.isPVContributor()); + trackTableId = outputTrackTable.lastIndex(); + trackIndices.add(daughterTrackId, trackTableId); + } + vecDaugtherTracks.push_back(trackTableId); + daughterCount++; + } + for (int i = 0; i < hypCand.getNdaughters(); i++) { + std::vector& posMom = hypCand.daughterPosMoms.at(i); + outputDaughterAddonTable( + posMom.at(0), posMom.at(1), posMom.at(2), posMom.at(3), posMom.at(4), posMom.at(5)); + vecAddons.push_back(outputDaughterAddonTable.lastIndex()); + } + if (hypCand.getNdaughters() > 2) { + for (int i = 0; i < hypCand.getNdaughters(); i++) { + for (int j = i + 1; j < hypCand.getNdaughters(); j++) { + outputSubDaughterTable(hypCand.getSubDaughterMass(i, j)); + vecSubDaughters.push_back(outputSubDaughterTable.lastIndex()); + } + } + } + + hypCand.kfp.TransportToDecayVertex(); + int mcPartTableId; + outputHypNucTable( + mcPartIndices.getIndex(hypCand.mcParticleId, mcPartTableId) ? mcPartTableId : -1, + outputCollisionTable.lastIndex(), vecDaugtherTracks, vecAddons, hypCand.getDaughterTableId(), vecSubDaughters, + (vec * nHyperNuclei + hyperNucIter + 1) * hypCand.getSign(), + hypCand.isPrimaryCandidate, hypCand.mass, + hypCand.px, hypCand.py, hypCand.pz, + hypCand.dcaToPvXY, hypCand.dcaToPvZ, hypCand.devToPvXY, + hypCand.dcaToVtxXY, hypCand.dcaToVtxZ, hypCand.chi2, + hypCand.recoSV.at(0), hypCand.recoSV.at(1), hypCand.recoSV.at(2)); + hypCand.tableId = outputHypNucTable.lastIndex(); + } + } + } + } + //---------------------------------------------------------------------------------------------------------------- + + void processMC(CollisionsFullMC const& collisions, aod::McCollisions const& mcColls, TracksFull const& tracks, aod::BCsWithTimestamps const&, aod::McParticles const& particlesMC, aod::McTrackLabels const& trackLabelsMC, aod::McCollisionLabels const& collLabels, aod::TrackAssoc const& tracksColl) + { + + mcCollInfos.clear(); + mcCollInfos.resize(mcColls.size()); + mcPartIndices.clear(); + for (const auto& collision : collisions) { + if (!collision.has_mcCollision()) + continue; + if (collision.sel8() && std::abs(collision.posZ()) < 10) + mcCollInfos.at(collision.mcCollisionId()).passedEvSel = true; + } + std::vector*> hypNucVectors = {&singleHyperNuclei, &cascadeHyperNuclei}; + for (const auto& mcPart : particlesMC) { + for (int vec = 0; vec < 2; vec++) { + for (size_t hyperNucIter = 0; hyperNucIter < hypNucVectors.at(vec)->size(); hyperNucIter++) { + HyperNucleus* hyperNuc = &(hypNucVectors.at(vec)->at(hyperNucIter)); + if (!hyperNuc->active) + continue; + if (std::abs(mcPart.pdgCode()) != hyperNuc->pdgCode) + continue; + bool isDecayMode = false; + float svx, svy, svz; + int daughterPdg; + if (vec == 0) + daughterPdg = daughterParticles.at(hyperNuc->daughters.at(0)).pdgCode; + else + daughterPdg = singleHyperNuclei.at(hyperNuc->daughters.at(0)).pdgCode; + for (const auto& mcDaught : mcPart.daughters_as()) { + if (std::abs(mcDaught.pdgCode()) == daughterPdg) { + isDecayMode = true; + svx = mcDaught.vx(); + svy = mcDaught.vy(); + svz = mcDaught.vz(); + break; + } + } + if (!isDecayMode) + continue; + + if (mcCollInfos.at(mcPart.mcCollisionId()).tableIndex < 0) { + outputMcCollisionTable( + mcCollInfos.at(mcPart.mcCollisionId()).passedEvSel, + mcPart.mcCollision().posX(), mcPart.mcCollision().posY(), mcPart.mcCollision().posZ()); + } + mcCollInfos.at(mcPart.mcCollisionId()).tableIndex = outputMcCollisionTable.lastIndex(); + + outputMcParticleTable( + mcCollInfos.at(mcPart.mcCollisionId()).tableIndex, + (vec * nHyperNuclei + hyperNucIter + 1) * (mcPart.pdgCode() > 0 ? +1 : -1), + mcPart.pdgCode(), + mcPart.isPhysicalPrimary(), + mcPart.px(), mcPart.py(), mcPart.pz(), + mcPart.e(), + svx, svy, svz); + mcPartIndices.add(mcPart.globalIndex(), outputMcParticleTable.lastIndex()); + } + } + } + + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + initCollision(collision); + const uint64_t collIdx = collision.globalIndex(); + auto tracksByColl = tracksColl.sliceBy(perCollision, collIdx); + findDaughterParticles(tracksByColl, tracks); + if (cfgSaveOnlyMcTrue) + checkMCTrueTracks(trackLabelsMC, particlesMC); + createKFDaughters(tracks); + createKFHypernuclei(tracks); + createMCinfo(trackLabelsMC, collLabels, particlesMC, mcColls); + createKFCascades(tracks); + createMCinfo(trackLabelsMC, collLabels, particlesMC, mcColls, true); + + if (!collHasCandidate) + continue; + if (cfgSaveOnlyMcTrue && !collHasMcTrueCandidate) + continue; + + mcCollTableIndex = -1; + if (collision.has_mcCollision()) { + mcCollTableIndex = mcCollInfos.at(collision.mcCollisionId()).tableIndex; + if (mcCollTableIndex < 0) { + outputMcCollisionTable( + mcCollInfos.at(collision.mcCollisionId()).passedEvSel, + collision.mcCollision().posX(), collision.mcCollision().posY(), collision.mcCollision().posZ()); + mcCollTableIndex = outputMcCollisionTable.lastIndex(); + mcCollInfos.at(collision.mcCollisionId()).tableIndex = mcCollTableIndex; + } + } + fillTree(tracks, cfgSaveOnlyMcTrue); + } + } + PROCESS_SWITCH(HypKfRecoTask, processMC, "MC analysis", false); + //---------------------------------------------------------------------------------------------------------------- + void processData(CollisionsFull const& collisions, TracksFull const& tracks, aod::BCsWithTimestamps const&, aod::TrackAssoc const& tracksColl) + { + + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + initCollision(collision); + if (!collPassedEvSel) + continue; + const uint64_t collIdx = collision.globalIndex(); + auto tracksByColl = tracksColl.sliceBy(perCollision, collIdx); + findDaughterParticles(tracksByColl, tracks); + createKFDaughters(tracks); + createKFHypernuclei(tracks); + createKFCascades(tracks); + if (!collHasCandidate) + continue; + mcCollTableIndex = -1; + fillTree(tracks); + } + } + PROCESS_SWITCH(HypKfRecoTask, processData, "data analysis", true); + //---------------------------------------------------------------------------------------------------------------- + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + auto run3grpTimestamp = bc.timestamp(); + dBz = 0; + o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grpTimestamp); + o2::parameters::GRPMagField* grpmag = 0x0; + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + if (bField < -990) { + // Fetch magnetic field from ccdb for current collision + dBz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grpTimestamp << " with magnetic field of " << dBz << " kZG"; + } else { + dBz = bField; + } + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grpTimestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grpTimestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + if (bField < -990) { + // Fetch magnetic field from ccdb for current collision + dBz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grpTimestamp << " with magnetic field of " << dBz << " kZG"; + } else { + dBz = bField; + } + } + mRunNumber = bc.runNumber(); + KFParticle::SetField(dBz); + } + //---------------------------------------------------------------------------------------------------------------- + template + void initCollision(const T& collision) + { + foundDaughters.clear(); + foundDaughters.resize(nDaughterParticles); + foundDaughterKfs.clear(); + foundDaughterKfs.resize(nDaughterParticles); + hypNucDaughterKfs.clear(); + hypNucDaughterKfs.resize(nCascades); + singleHyperNucCandidates.clear(); + singleHyperNucCandidates.resize(nHyperNuclei); + cascadeHyperNucCandidates.clear(); + cascadeHyperNucCandidates.resize(nCascades); + trackIndices.clear(); + collHasCandidate = false; + collHasMcTrueCandidate = false; + histos.fill(HIST("histMagField"), dBz); + histos.fill(HIST("histNev"), 0.5); + collPassedEvSel = collision.sel8() && std::abs(collision.posZ()) < 10; + occupancy = collision.trackOccupancyInTimeRange(); + if (collPassedEvSel) { + histos.fill(HIST("histNev"), 1.5); + histos.fill(HIST("histVtxZ"), collision.posZ()); + histos.fill(HIST("histCentFT0A"), collision.centFT0A()); + histos.fill(HIST("histCentFT0C"), collision.centFT0C()); + histos.fill(HIST("histCentFT0M"), collision.centFT0M()); + histos.fill(HIST("histEvents"), collision.centFT0C(), occupancy); + } + kfPrimVtx = createKFPVertexFromCollision(collision); + primVtx.assign({collision.posX(), collision.posY(), collision.posZ()}); + cents.assign({collision.centFT0A(), collision.centFT0C(), collision.centFT0M()}); + } + + //---------------------------------------------------------------------------------------------------------------- + template + void filldedx(T const& track, int species) + { + const float rigidity = getRigidity(track); + hDeDx[2 * species]->Fill(track.sign() * rigidity, track.tpcSignal()); + if (track.tpcNClsFound() < 100 || track.itsNCls() < 2) + return; + hDeDx[2 * species + 1]->Fill(track.sign() * rigidity, track.tpcSignal()); + } + //---------------------------------------------------------------------------------------------------------------- + + template + float getTPCnSigma(T const& track, DaughterParticle const& particle) + { + const float rigidity = getRigidity(track); + if (!track.hasTPC()) + return -999; + + if (particle.name == "pion" && cfgTrackPIDsettings->get("pion", "useBBparams") < 1) + return cfgTrackPIDsettings->get("pion", "useBBparams") == 0 ? track.tpcNSigmaPi() : 0; + if (particle.name == "proton" && cfgTrackPIDsettings->get("proton", "useBBparams") < 1) + return cfgTrackPIDsettings->get("proton", "useBBparams") == 0 ? track.tpcNSigmaPr() : 0; + if (particle.name == "deuteron" && cfgTrackPIDsettings->get("deuteron", "useBBparams") < 1) + return cfgTrackPIDsettings->get("deuteron", "useBBparams") == 0 ? track.tpcNSigmaDe() : 0; + if (particle.name == "triton" && cfgTrackPIDsettings->get("triton", "useBBparams") < 1) + return cfgTrackPIDsettings->get("triton", "useBBparams") == 0 ? track.tpcNSigmaTr() : 0; + if (particle.name == "helion" && cfgTrackPIDsettings->get("helion", "useBBparams") < 1) + return cfgTrackPIDsettings->get("helion", "useBBparams") == 0 ? track.tpcNSigmaHe() : 0; + if (particle.name == "alpha" && cfgTrackPIDsettings->get("alpha", "useBBparams") < 1) + return cfgTrackPIDsettings->get("alpha", "useBBparams") == 0 ? track.tpcNSigmaAl() : 0; + + double expBethe{tpc::BetheBlochAleph(static_cast(particle.charge * rigidity / particle.mass), particle.betheParams[0], particle.betheParams[1], particle.betheParams[2], particle.betheParams[3], particle.betheParams[4])}; + double expSigma{expBethe * particle.resolution}; + float sigmaTPC = static_cast((track.tpcSignal() - expBethe) / expSigma); + return sigmaTPC; + } + //---------------------------------------------------------------------------------------------------------------- + template + float getMeanItsClsSize(T const& track) + { + int sum = 0, n = 0; + for (int i = 0; i < 8; i++) { + sum += (track.itsClusterSizes() >> (4 * i) & 15); + if (track.itsClusterSizes() >> (4 * i) & 15) + n++; + } + return n > 0 ? static_cast(sum) / n : 0.f; + } + //---------------------------------------------------------------------------------------------------------------- + template + float getRigidity(T const& track) + { + if (!cfgRigidityCorrection) + return track.tpcInnerParam(); + bool hePID = track.pidForTracking() == o2::track::PID::Helium3 || track.pidForTracking() == o2::track::PID::Alpha; + return hePID ? track.tpcInnerParam() / 2 : track.tpcInnerParam(); + } + //---------------------------------------------------------------------------------------------------------------- + + template + KFParticle createKFParticle(const T& track, float mass, int charge) + { + auto trackparCov = getTrackParCov(track); + std::array fP; + std::array fM; + trackparCov.getXYZGlo(fP); + trackparCov.getPxPyPzGlo(fM); + float fPM[6]; + for (int i = 0; i < 3; i++) { + fPM[i] = fP[i]; + fPM[i + 3] = fM[i] * std::abs(charge); + } + std::array fC; + trackparCov.getCovXYZPxPyPzGlo(fC); + KFParticle part; + part.Create(fPM, fC.data(), std::abs(charge) * track.sign(), mass); + return part; + } + //---------------------------------------------------------------------------------------------------------------- + + template + KFPVertex createKFPVertexFromCollision(const T& collision) + { + KFPVertex kfpVertex; + kfpVertex.SetXYZ(collision.posX(), collision.posY(), collision.posZ()); + kfpVertex.SetCovarianceMatrix(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + kfpVertex.SetChi2(collision.chi2()); + kfpVertex.SetNDF(2 * collision.numContrib() - 3); + kfpVertex.SetNContributors(collision.numContrib()); + return kfpVertex; + } + //---------------------------------------------------------------------------------------------------------------- + + int getHypDaughterVec(unsigned int cascade, LabeledArray cfg) + { + std::string daughter = cfg.get(cascade, 0u); + if (std::find(hyperNucNames.begin(), hyperNucNames.end(), daughter) == hyperNucNames.end()) + return -1; + return std::find(hyperNucNames.begin(), hyperNucNames.end(), daughter) - hyperNucNames.begin(); + } + //---------------------------------------------------------------------------------------------------------------- + std::vector getDaughterVec(unsigned int hypNuc, LabeledArray cfg) + { + std::vector vec; + for (unsigned int i = 0; i < 4; i++) { + std::string daughter = cfg.get(hypNuc, i); + if (std::find(particleNames.begin(), particleNames.end(), daughter) == particleNames.end()) + break; + vec.push_back(std::find(particleNames.begin(), particleNames.end(), daughter) - particleNames.begin()); + } + return vec; + } + //---------------------------------------------------------------------------------------------------------------- + + std::vector getDaughterSignVec(unsigned int hypNuc, LabeledArray cfg) + { + std::vector vec; + for (unsigned int i = 0; i < 4; i++) { + std::string sign = cfg.get(hypNuc, i); + if (sign != "+" && sign != "-") + break; + vec.push_back(sign == "+" ? +1 : -1); + } + return vec; + } + //---------------------------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------------------------- +}; +//---------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------- +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} +//---------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------- diff --git a/PWGLF/TableProducer/Nuspex/hypKfTreeCreator.cxx b/PWGLF/TableProducer/Nuspex/hypKfTreeCreator.cxx new file mode 100644 index 00000000000..da8316e3c8d --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/hypKfTreeCreator.cxx @@ -0,0 +1,788 @@ +// 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 hypKfTreeCreator.cxx +/// \brief Creates flat tree for ML analysis +/// \author Janik Ditzel and Michael Hartung + +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/PID/TPCPIDResponse.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "DCAFitter/DCAFitterN.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGLF/DataModel/LFHypernucleiKfTables.h" + +using namespace o2; +using namespace o2::framework; +typedef std::array arr3; + +namespace +{ +std::vector> hPt; + +struct TrackProperties { + TrackProperties() : x(0), y(0), z(0), px(0), py(0), pz(0), tpcNcls(0), itsNcls(0), tpcChi2(0), itsChi2(0), itsMeanClsSize(0), itsMeanClsSizeL(0), rigidity(0), tpcSignal(0), tpcNsigma(0), tpcNsigmaNhp(0), tpcNsigmaNlp(0), tofMass(0), dcaXY(0), dcaZ(0), isPvContributor(0), subMass(0) {} + float x, y, z, px, py, pz; + uint8_t tpcNcls, itsNcls; + float tpcChi2, itsChi2, itsMeanClsSize, itsMeanClsSizeL; + float rigidity, tpcSignal, tpcNsigma, tpcNsigmaNhp, tpcNsigmaNlp; + float tofMass, dcaXY, dcaZ; + bool isPvContributor; + float subMass; +}; + +struct HyperNucleus { + HyperNucleus() : pdgCode(0), isReconstructed(0), globalIndex(0), species(0), isPrimaryCandidate(0), isMatter(0), passedEvSel(0), isMatterMC(0), passedEvSelMC(0), isPhysicalPrimary(0), collisionMcTrue(0), mass(0), y(0), pt(0), ct(0), yGen(0), ptGen(0), ctGen(0), cpaPvGen(0), cpaPv(0), cpaSv(0), maxDcaTracks(0), maxDcaTracksSv(0), dcaToPvXY(0), dcaToPvZ(0), dcaToVtxXY(0), dcaToVtxZ(0), devToPvXY(0), chi2(0), pvx(0), pvy(0), pvz(0), svx(0), svy(0), svz(0), px(0), py(0), pz(0), pvxGen(0), pvyGen(0), pvzGen(0), svxGen(0), svyGen(0), svzGen(0), pxGen(0), pyGen(0), pzGen(0), nSingleDaughters(0), nCascadeDaughters(0), mcTrue(0), mcTrueVtx(0), mcPhysicalPrimary(0), hypNucDaughter(0) {} + int pdgCode, isReconstructed, globalIndex; + uint8_t species; + bool isPrimaryCandidate, isMatter, passedEvSel, isMatterMC, passedEvSelMC, isPhysicalPrimary, collisionMcTrue; + float mass, y, pt, ct, yGen, ptGen, ctGen, cpaPvGen, cpaPv, cpaSv, maxDcaTracks, maxDcaTracksSv; + float dcaToPvXY, dcaToPvZ, dcaToVtxXY, dcaToVtxZ, devToPvXY, chi2; + float pvx, pvy, pvz, svx, svy, svz, px, py, pz; + float pvxGen, pvyGen, pvzGen, svxGen, svyGen, svzGen, pxGen, pyGen, pzGen; + int nSingleDaughters, nCascadeDaughters, cent, occu; + bool mcTrue, mcTrueVtx, mcPhysicalPrimary; + std::vector daughterTracks; + std::vector subDaughterMassVec; + HyperNucleus* hypNucDaughter; + ~HyperNucleus() + { + if (hypNucDaughter) + delete hypNucDaughter; + } +}; +} // namespace +namespace o2::aod +{ +namespace hypkftree +{ +DECLARE_SOA_COLUMN(Y, y, float); +DECLARE_SOA_COLUMN(Ct, ct, float); +DECLARE_SOA_COLUMN(YGen, yGen, float); +DECLARE_SOA_COLUMN(PtGen, ptGen, float); +DECLARE_SOA_COLUMN(CtGen, ctGen, float); +DECLARE_SOA_COLUMN(CpaPvGen, cpaPvGen, float); +DECLARE_SOA_COLUMN(DcaTracks, dcaTracks, float); +DECLARE_SOA_COLUMN(DcaTrackSv, dcaTrackSv, float); +DECLARE_SOA_COLUMN(CosPa, cosPa, double); +DECLARE_SOA_COLUMN(McTrue, mcTrue, bool); +DECLARE_SOA_COLUMN(Pvx, pvx, float); +DECLARE_SOA_COLUMN(Pvy, pvy, float); +DECLARE_SOA_COLUMN(Pvz, pvz, float); +DECLARE_SOA_COLUMN(Tvx, tvx, float); +DECLARE_SOA_COLUMN(Tvy, tvy, float); +DECLARE_SOA_COLUMN(Tvz, tvz, float); +DECLARE_SOA_COLUMN(PxGen, pxGen, float); +DECLARE_SOA_COLUMN(PyGen, pyGen, float); +DECLARE_SOA_COLUMN(PzGen, pzGen, float); +DECLARE_SOA_COLUMN(PvxGen, pvxGen, float); +DECLARE_SOA_COLUMN(PvyGen, pvyGen, float); +DECLARE_SOA_COLUMN(PvzGen, pvzGen, float); +DECLARE_SOA_COLUMN(SvxGen, svxGen, float); +DECLARE_SOA_COLUMN(SvyGen, svyGen, float); +DECLARE_SOA_COLUMN(SvzGen, svzGen, float); +DECLARE_SOA_COLUMN(TvxGen, tvxGen, float); +DECLARE_SOA_COLUMN(TvyGen, tvyGen, float); +DECLARE_SOA_COLUMN(TvzGen, tvzGen, float); +DECLARE_SOA_COLUMN(Centrality, centrality, int); +DECLARE_SOA_COLUMN(Occupancy, occupancy, int); +DECLARE_SOA_COLUMN(PassedEvSelMC, passedEvSelMC, bool); +DECLARE_SOA_COLUMN(IsMatter, isMatter, bool); +DECLARE_SOA_COLUMN(IsMatterGen, isMatterGen, bool); +DECLARE_SOA_COLUMN(IsReconstructed, isReconstructed, bool); +DECLARE_SOA_COLUMN(CollMcTrue, collMcTrue, bool); +DECLARE_SOA_COLUMN(D1X, d1X, float); +DECLARE_SOA_COLUMN(D1Y, d1Y, float); +DECLARE_SOA_COLUMN(D1Z, d1Z, float); +DECLARE_SOA_COLUMN(D1Px, d1Px, float); +DECLARE_SOA_COLUMN(D1Py, d1Py, float); +DECLARE_SOA_COLUMN(D1Pz, d1Pz, float); +DECLARE_SOA_COLUMN(D1TPCnCls, d1TPCnCls, uint8_t); +DECLARE_SOA_COLUMN(D1TPCchi2, d1TPCchi2, float); +DECLARE_SOA_COLUMN(D1ITSnCls, d1ITSnCls, uint8_t); +DECLARE_SOA_COLUMN(D1ITSchi2, d1ITSchi2, float); +DECLARE_SOA_COLUMN(D1ITSmeanClsSize, d1ITSmeanClsSize, float); +DECLARE_SOA_COLUMN(D1ITSmeanClsSizeL, d1ITSmeanClsSizeL, float); +DECLARE_SOA_COLUMN(D1Rigidity, d1Rigidity, float); +DECLARE_SOA_COLUMN(D1TPCsignal, d1TPCsignal, float); +DECLARE_SOA_COLUMN(D1TPCnSigma, d1TPCnSigma, float); +DECLARE_SOA_COLUMN(D1TPCnSigmaNhp, d1TPCnSigmaNhp, float); +DECLARE_SOA_COLUMN(D1TPCnSigmaNlp, d1TPCnSigmaNlp, float); +DECLARE_SOA_COLUMN(D1TOFmass, d1TOFmass, float); +DECLARE_SOA_COLUMN(D1DcaXY, d1DcaXY, float); +DECLARE_SOA_COLUMN(D1DcaZ, d1DcaZ, float); +DECLARE_SOA_COLUMN(D1IsPvContributor, d1IsPvContributor, bool); +DECLARE_SOA_COLUMN(D2X, d2X, float); +DECLARE_SOA_COLUMN(D2Y, d2Y, float); +DECLARE_SOA_COLUMN(D2Z, d2Z, float); +DECLARE_SOA_COLUMN(D2Px, d2Px, float); +DECLARE_SOA_COLUMN(D2Py, d2Py, float); +DECLARE_SOA_COLUMN(D2Pz, d2Pz, float); +DECLARE_SOA_COLUMN(D2TPCnCls, d2TPCnCls, uint8_t); +DECLARE_SOA_COLUMN(D2TPCchi2, d2TPCchi2, float); +DECLARE_SOA_COLUMN(D2ITSnCls, d2ITSnCls, uint8_t); +DECLARE_SOA_COLUMN(D2ITSchi2, d2ITSchi2, float); +DECLARE_SOA_COLUMN(D2ITSmeanClsSize, d2ITSmeanClsSize, float); +DECLARE_SOA_COLUMN(D2ITSmeanClsSizeL, d2ITSmeanClsSizeL, float); +DECLARE_SOA_COLUMN(D2Rigidity, d2Rigidity, float); +DECLARE_SOA_COLUMN(D2TPCsignal, d2TPCsignal, float); +DECLARE_SOA_COLUMN(D2TPCnSigma, d2TPCnSigma, float); +DECLARE_SOA_COLUMN(D2TPCnSigmaNhp, d2TPCnSigmaNhp, float); +DECLARE_SOA_COLUMN(D2TPCnSigmaNlp, d2TPCnSigmaNlp, float); +DECLARE_SOA_COLUMN(D2TOFmass, d2TOFmass, float); +DECLARE_SOA_COLUMN(D2DcaXY, d2DcaXY, float); +DECLARE_SOA_COLUMN(D2DcaZ, d2DcaZ, float); +DECLARE_SOA_COLUMN(D2IsPvContributor, d2IsPvContributor, bool); +DECLARE_SOA_COLUMN(D3X, d3X, float); +DECLARE_SOA_COLUMN(D3Y, d3Y, float); +DECLARE_SOA_COLUMN(D3Z, d3Z, float); +DECLARE_SOA_COLUMN(D3Px, d3Px, float); +DECLARE_SOA_COLUMN(D3Py, d3Py, float); +DECLARE_SOA_COLUMN(D3Pz, d3Pz, float); +DECLARE_SOA_COLUMN(D3TPCnCls, d3TPCnCls, uint8_t); +DECLARE_SOA_COLUMN(D3TPCchi2, d3TPCchi2, float); +DECLARE_SOA_COLUMN(D3ITSnCls, d3ITSnCls, uint8_t); +DECLARE_SOA_COLUMN(D3ITSchi2, d3ITSchi2, float); +DECLARE_SOA_COLUMN(D3ITSmeanClsSize, d3ITSmeanClsSize, float); +DECLARE_SOA_COLUMN(D3ITSmeanClsSizeL, d3ITSmeanClsSizeL, float); +DECLARE_SOA_COLUMN(D3Rigidity, d3Rigidity, float); +DECLARE_SOA_COLUMN(D3TPCsignal, d3TPCsignal, float); +DECLARE_SOA_COLUMN(D3TPCnSigma, d3TPCnSigma, float); +DECLARE_SOA_COLUMN(D3TPCnSigmaNhp, d3TPCnSigmaNhp, float); +DECLARE_SOA_COLUMN(D3TPCnSigmaNlp, d3TPCnSigmaNlp, float); +DECLARE_SOA_COLUMN(D3TOFmass, d3TOFmass, float); +DECLARE_SOA_COLUMN(D3DcaXY, d3DcaXY, float); +DECLARE_SOA_COLUMN(D3DcaZ, d3DcaZ, float); +DECLARE_SOA_COLUMN(D1d2Mass, d1d2Mass, float); +DECLARE_SOA_COLUMN(D1d3Mass, d1d3Mass, float); +DECLARE_SOA_COLUMN(D2d3Mass, d2d3Mass, float); +DECLARE_SOA_COLUMN(D3IsPvContributor, d3IsPvContributor, bool); +DECLARE_SOA_COLUMN(D0X, d0X, float); +DECLARE_SOA_COLUMN(D0Y, d0Y, float); +DECLARE_SOA_COLUMN(D0Z, d0Z, float); +DECLARE_SOA_COLUMN(D0Px, d0Px, float); +DECLARE_SOA_COLUMN(D0Py, d0Py, float); +DECLARE_SOA_COLUMN(D0Pz, d0Pz, float); +DECLARE_SOA_COLUMN(D0Mass, d0Mass, float); +DECLARE_SOA_COLUMN(D0ct, d0ct, float); +DECLARE_SOA_COLUMN(D0cosPa, d0cosPa, float); +DECLARE_SOA_COLUMN(D0dcaTracks, d0dcaTracks, float); +DECLARE_SOA_COLUMN(D0dcaTracksTv, d0dcaTracksTv, float); +DECLARE_SOA_COLUMN(D0dcaToPvXY, d0dcaToPvXY, float); +DECLARE_SOA_COLUMN(D0dcaToPvZ, d0dcaToPvZ, float); +DECLARE_SOA_COLUMN(D0dcaToSvXY, d0dcaToSvXY, float); +DECLARE_SOA_COLUMN(D0dcaToSvZ, d0dcaToSvZ, float); +DECLARE_SOA_COLUMN(D0chi2, d0chi2, float); +DECLARE_SOA_COLUMN(Sd1X, sd1X, float); +DECLARE_SOA_COLUMN(Sd1Y, sd1Y, float); +DECLARE_SOA_COLUMN(Sd1Z, sd1Z, float); +DECLARE_SOA_COLUMN(Sd1Px, sd1Px, float); +DECLARE_SOA_COLUMN(Sd1Py, sd1Py, float); +DECLARE_SOA_COLUMN(Sd1Pz, sd1Pz, float); +DECLARE_SOA_COLUMN(Sd1TPCnCls, sd1TPCnCls, uint8_t); +DECLARE_SOA_COLUMN(Sd1TPCchi2, sd1TPCchi2, float); +DECLARE_SOA_COLUMN(Sd1ITSnCls, sd1ITSnCls, uint8_t); +DECLARE_SOA_COLUMN(Sd1ITSchi2, sd1ITSchi2, float); +DECLARE_SOA_COLUMN(Sd1ITSmeanClsSize, sd1ITSmeanClsSize, float); +DECLARE_SOA_COLUMN(Sd1ITSmeanClsSizeL, sd1ITSmeanClsSizeL, float); +DECLARE_SOA_COLUMN(Sd1Rigidity, sd1Rigidity, float); +DECLARE_SOA_COLUMN(Sd1TPCsignal, sd1TPCsignal, float); +DECLARE_SOA_COLUMN(Sd1TPCnSigma, sd1TPCnSigma, float); +DECLARE_SOA_COLUMN(Sd1TPCnSigmaNhp, sd1TPCnSigmaNhp, float); +DECLARE_SOA_COLUMN(Sd1TPCnSigmaNlp, sd1TPCnSigmaNlp, float); +DECLARE_SOA_COLUMN(Sd1TOFmass, sd1TOFmass, float); +DECLARE_SOA_COLUMN(Sd1DcaXY, sd1DcaXY, float); +DECLARE_SOA_COLUMN(Sd1DcaZ, sd1DcaZ, float); +DECLARE_SOA_COLUMN(Sd1IsPvContributor, sd1IsPvContributor, bool); +DECLARE_SOA_COLUMN(Sd2X, sd2X, float); +DECLARE_SOA_COLUMN(Sd2Y, sd2Y, float); +DECLARE_SOA_COLUMN(Sd2Z, sd2Z, float); +DECLARE_SOA_COLUMN(Sd2Px, sd2Px, float); +DECLARE_SOA_COLUMN(Sd2Py, sd2Py, float); +DECLARE_SOA_COLUMN(Sd2Pz, sd2Pz, float); +DECLARE_SOA_COLUMN(Sd2TPCnCls, sd2TPCnCls, uint8_t); +DECLARE_SOA_COLUMN(Sd2TPCchi2, sd2TPCchi2, float); +DECLARE_SOA_COLUMN(Sd2ITSnCls, sd2ITSnCls, uint8_t); +DECLARE_SOA_COLUMN(Sd2ITSchi2, sd2ITSchi2, float); +DECLARE_SOA_COLUMN(Sd2ITSmeanClsSize, sd2ITSmeanClsSize, float); +DECLARE_SOA_COLUMN(Sd2ITSmeanClsSizeL, sd2ITSmeanClsSizeL, float); +DECLARE_SOA_COLUMN(Sd2Rigidity, sd2Rigidity, float); +DECLARE_SOA_COLUMN(Sd2TPCsignal, sd2TPCsignal, float); +DECLARE_SOA_COLUMN(Sd2TPCnSigma, sd2TPCnSigma, float); +DECLARE_SOA_COLUMN(Sd2TPCnSigmaNhp, sd2TPCnSigmaNhp, float); +DECLARE_SOA_COLUMN(Sd2TPCnSigmaNlp, sd2TPCnSigmaNlp, float); +DECLARE_SOA_COLUMN(Sd2TOFmass, sd2TOFmass, float); +DECLARE_SOA_COLUMN(Sd2DcaXY, sd2DcaXY, float); +DECLARE_SOA_COLUMN(Sd2DcaZ, sd2DcaZ, float); +DECLARE_SOA_COLUMN(Sd2IsPvContributor, sd2IsPvContributor, bool); +DECLARE_SOA_COLUMN(Sd3X, sd3X, float); +DECLARE_SOA_COLUMN(Sd3Y, sd3Y, float); +DECLARE_SOA_COLUMN(Sd3Z, sd3Z, float); +DECLARE_SOA_COLUMN(Sd3Px, sd3Px, float); +DECLARE_SOA_COLUMN(Sd3Py, sd3Py, float); +DECLARE_SOA_COLUMN(Sd3Pz, sd3Pz, float); +DECLARE_SOA_COLUMN(Sd3TPCnCls, sd3TPCnCls, uint8_t); +DECLARE_SOA_COLUMN(Sd3TPCchi2, sd3TPCchi2, float); +DECLARE_SOA_COLUMN(Sd3ITSnCls, sd3ITSnCls, uint8_t); +DECLARE_SOA_COLUMN(Sd3ITSchi2, sd3ITSchi2, float); +DECLARE_SOA_COLUMN(Sd3ITSmeanClsSize, sd3ITSmeanClsSize, float); +DECLARE_SOA_COLUMN(Sd3ITSmeanClsSizeL, sd3ITSmeanClsSizeL, float); +DECLARE_SOA_COLUMN(Sd3Rigidity, sd3Rigidity, float); +DECLARE_SOA_COLUMN(Sd3TPCsignal, sd3TPCsignal, float); +DECLARE_SOA_COLUMN(Sd3TPCnSigma, sd3TPCnSigma, float); +DECLARE_SOA_COLUMN(Sd3TPCnSigmaNhp, sd3TPCnSigmaNhp, float); +DECLARE_SOA_COLUMN(Sd3TPCnSigmaNlp, sd3TPCnSigmaNlp, float); +DECLARE_SOA_COLUMN(Sd3TOFmass, sd3TOFmass, float); +DECLARE_SOA_COLUMN(Sd3DcaXY, sd3DcaXY, float); +DECLARE_SOA_COLUMN(Sd3DcaZ, sd3DcaZ, float); +DECLARE_SOA_COLUMN(Sd3IsPvContributor, sd3IsPvContributor, bool); +DECLARE_SOA_COLUMN(Sd1sd2Mass, sd1sd2Mass, float); +DECLARE_SOA_COLUMN(Sd1sd3Mass, sd1sd3Mass, float); +DECLARE_SOA_COLUMN(Sd2sd3Mass, sd2sd3Mass, float); +} // namespace hypkftree + +#define HYPKFGENBASE mcparticle::PdgCode, hypkftree::IsMatterGen, hypkftree::IsReconstructed, hykfmc::IsPhysicalPrimary, hypkftree::PassedEvSelMC, hypkftree::YGen, hypkftree::PtGen, hypkftree::CtGen + +#define HYPKFGENEXT hypkftree::CpaPvGen, hypkftree::PxGen, hypkftree::PyGen, hypkftree::PzGen, hypkftree::PvxGen, hypkftree::PvyGen, hypkftree::PvzGen, hypkftree::SvxGen, hypkftree::SvyGen, hypkftree::SvzGen + +#define HYPKFGENCAS hypkftree::TvxGen, hypkftree::TvyGen, hypkftree::TvzGen + +#define HYPKFHYPNUC hykfmc::Species, hypkftree::IsMatter, hypkftree::Centrality, hypkftree::Occupancy, hykfmccoll::PassedEvSel, hykfhyp::Mass, hypkftree::Y, track::Pt, hypkftree::Ct, hypkftree::CosPa, hypkftree::DcaTracks, hypkftree::DcaTrackSv, hykfhyp::DcaToPvXY, hykfhyp::DcaToPvZ, hykfhyp::DevToPvXY, hykfhyp::Chi2, hypkftree::Pvx, hypkftree::Pvy, hypkftree::Pvz, hykfmc::Svx, hykfmc::Svy, hykfmc::Svz, hykfhyp::Px, hykfhyp::Py, hykfhyp::Pz, hypkftree::CollMcTrue + +#define HYPKFHYPNUCMC hypkftree::McTrue, hykfmc::IsPhysicalPrimary + +#define HYPKFD0 hypkftree::Tvx, hypkftree::Tvy, hypkftree::Tvz, hypkftree::D0X, hypkftree::D0Y, hypkftree::D0Z, hypkftree::D0Px, hypkftree::D0Py, hypkftree::D0Pz, hypkftree::D0Mass, hypkftree::D0ct, hypkftree::D0cosPa, hypkftree::D0dcaTracks, hypkftree::D0dcaToPvXY, hypkftree::D0dcaToPvZ, hypkftree::D0dcaToSvXY, hypkftree::D0dcaToSvZ, hypkftree::D0chi2 + +#define HYPKFD1 hypkftree::D1X, hypkftree::D1Y, hypkftree::D1Z, hypkftree::D1Px, hypkftree::D1Py, hypkftree::D1Pz, hypkftree::D1TPCnCls, hypkftree::D1TPCchi2, hypkftree::D1ITSnCls, hypkftree::D1ITSchi2, hypkftree::D1ITSmeanClsSizeL, hypkftree::D1Rigidity, hypkftree::D1TPCsignal, hypkftree::D1TPCnSigma, hypkftree::D1TPCnSigmaNhp, hypkftree::D1TPCnSigmaNlp, hypkftree::D1TOFmass, hypkftree::D1DcaXY, hypkftree::D1DcaZ, hypkftree::D1IsPvContributor + +#define HYPKFD2 hypkftree::D2X, hypkftree::D2Y, hypkftree::D2Z, hypkftree::D2Px, hypkftree::D2Py, hypkftree::D2Pz, hypkftree::D2TPCnCls, hypkftree::D2TPCchi2, hypkftree::D2ITSnCls, hypkftree::D2ITSchi2, hypkftree::D2ITSmeanClsSizeL, hypkftree::D2Rigidity, hypkftree::D2TPCsignal, hypkftree::D2TPCnSigma, hypkftree::D2TPCnSigmaNhp, hypkftree::D2TPCnSigmaNlp, hypkftree::D2TOFmass, hypkftree::D2DcaXY, hypkftree::D2DcaZ, hypkftree::D2IsPvContributor + +#define HYPKFD3 hypkftree::D3X, hypkftree::D3Y, hypkftree::D3Z, hypkftree::D3Px, hypkftree::D3Py, hypkftree::D3Pz, hypkftree::D3TPCnCls, hypkftree::D3TPCchi2, hypkftree::D3ITSnCls, hypkftree::D3ITSchi2, hypkftree::D3ITSmeanClsSizeL, hypkftree::D3Rigidity, hypkftree::D3TPCsignal, hypkftree::D3TPCnSigma, hypkftree::D3TPCnSigmaNhp, hypkftree::D3TPCnSigmaNlp, hypkftree::D3TOFmass, hypkftree::D3DcaXY, hypkftree::D3DcaZ, hypkftree::D3IsPvContributor + +#define HYPKFSD1 hypkftree::Sd1X, hypkftree::Sd1Y, hypkftree::Sd1Z, hypkftree::Sd1Px, hypkftree::Sd1Py, hypkftree::Sd1Pz, hypkftree::Sd1TPCnCls, hypkftree::Sd1TPCchi2, hypkftree::Sd1ITSnCls, hypkftree::Sd1ITSchi2, hypkftree::Sd1ITSmeanClsSizeL, hypkftree::Sd1Rigidity, hypkftree::Sd1TPCsignal, hypkftree::Sd1TPCnSigma, hypkftree::Sd1TPCnSigmaNhp, hypkftree::Sd1TPCnSigmaNlp, hypkftree::Sd1TOFmass, hypkftree::Sd1DcaXY, hypkftree::Sd1DcaZ, hypkftree::Sd1IsPvContributor + +#define HYPKFSD2 hypkftree::Sd2X, hypkftree::Sd2Y, hypkftree::Sd2Z, hypkftree::Sd2Px, hypkftree::Sd2Py, hypkftree::Sd2Pz, hypkftree::Sd2TPCnCls, hypkftree::Sd2TPCchi2, hypkftree::Sd2ITSnCls, hypkftree::Sd2ITSchi2, hypkftree::Sd2ITSmeanClsSizeL, hypkftree::Sd2Rigidity, hypkftree::Sd2TPCsignal, hypkftree::Sd2TPCnSigma, hypkftree::Sd2TPCnSigmaNhp, hypkftree::Sd2TPCnSigmaNlp, hypkftree::Sd2TOFmass, hypkftree::Sd2DcaXY, hypkftree::Sd2DcaZ, hypkftree::Sd2IsPvContributor + +#define HYPKFSD3 hypkftree::Sd3X, hypkftree::Sd3Y, hypkftree::Sd3Z, hypkftree::Sd3Px, hypkftree::Sd3Py, hypkftree::Sd3Pz, hypkftree::Sd3TPCnCls, hypkftree::Sd3TPCchi2, hypkftree::Sd3ITSnCls, hypkftree::Sd3ITSchi2, hypkftree::Sd3ITSmeanClsSizeL, hypkftree::Sd3Rigidity, hypkftree::Sd3TPCsignal, hypkftree::Sd3TPCnSigma, hypkftree::Sd3TPCnSigmaNhp, hypkftree::Sd3TPCnSigmaNlp, hypkftree::Sd3TOFmass, hypkftree::Sd3DcaXY, hypkftree::Sd3DcaZ, hypkftree::Sd3IsPvContributor + +#define HYPKFSDMASS hypkftree::D1d2Mass, hypkftree::D1d3Mass, hypkftree::D2d3Mass +#define HYPKFSSDMASS hypkftree::Sd1sd2Mass, hypkftree::Sd1sd3Mass, hypkftree::Sd2sd3Mass + +DECLARE_SOA_TABLE(HypKfGens, "AOD", "HYPKFGEN", HYPKFGENBASE); +using HypKfGen = HypKfGens::iterator; + +DECLARE_SOA_TABLE(HypKfSingleTwoBodyCandidates, "AOD", "HYPKFCAND2", HYPKFHYPNUC, HYPKFHYPNUCMC, HYPKFD1, HYPKFD2); +using HypKfSingleTwoBodyCandidate = HypKfSingleTwoBodyCandidates::iterator; + +DECLARE_SOA_TABLE(HypKfMcSingleTwoBodyCandidates, "AOD", "HYPKFMCCAND2", HYPKFGENBASE, HYPKFGENEXT, HYPKFHYPNUC, HYPKFD1, HYPKFD2); +using HypKfMcSingleTwoBodyCandidate = HypKfMcSingleTwoBodyCandidates::iterator; + +DECLARE_SOA_TABLE(HypKfSingleThreeBodyCandidates, "AOD", "HYPKFCAND3", HYPKFHYPNUC, HYPKFHYPNUCMC, HYPKFD1, HYPKFD2, HYPKFD3, HYPKFSDMASS); +using HypKfSingleThreeBodyCandidate = HypKfSingleThreeBodyCandidates::iterator; + +DECLARE_SOA_TABLE(HypKfMcSingleThreeBodyCandidates, "AOD", "HYPKFMCCAND3", HYPKFGENBASE, HYPKFGENEXT, HYPKFHYPNUC, HYPKFD1, HYPKFD2, HYPKFD3, HYPKFSDMASS); +using HypKfMcSingleThreeBodyCandidate = HypKfMcSingleThreeBodyCandidates::iterator; + +DECLARE_SOA_TABLE(HypKfCascadeTwoThreeCandidates, "AOD", "HYPKFCAND23", HYPKFHYPNUC, HYPKFHYPNUCMC, HYPKFD0, HYPKFD1, HYPKFSD1, HYPKFSD2, HYPKFSD3, HYPKFSSDMASS); +using HypKfCascadeTwoThreeCandidate = HypKfCascadeTwoThreeCandidates::iterator; + +DECLARE_SOA_TABLE(HypKfMcCascadeTwoThreeCandidates, "AOD", "HYPKFMCCAND23", HYPKFGENBASE, HYPKFGENEXT, HYPKFHYPNUC, HYPKFD0, HYPKFD1, HYPKFSD1, HYPKFSD2, HYPKFSD3, HYPKFSSDMASS); +using HypKfMcCascadeTwoThreeCandidate = HypKfMcCascadeTwoThreeCandidates::iterator; + +DECLARE_SOA_TABLE(HypKfCascadeThreeTwoCandidates, "AOD", "HYPKFCAND32", HYPKFHYPNUC, HYPKFHYPNUCMC, HYPKFD0, HYPKFD1, HYPKFD2, HYPKFSDMASS, HYPKFSD1, HYPKFSD2); +using HypKfCascadeThreeTwoCandidate = HypKfCascadeThreeTwoCandidates::iterator; + +DECLARE_SOA_TABLE(HypKfMcCascadeThreeTwoCandidates, "AOD", "HYPKFMCCAND32", HYPKFGENBASE, HYPKFGENEXT, HYPKFHYPNUC, HYPKFD0, HYPKFD1, HYPKFD2, HYPKFSDMASS, HYPKFSD1, HYPKFSD2); +using HypKfMcCascadeThreeTwoCandidate = HypKfMcCascadeThreeTwoCandidates::iterator; +} // namespace o2::aod + +struct HypKfTreeCreator { + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Produces outputMcGenTable; + Produces outputTableTwo; + Produces outputTableMcTwo; + Produces outputTableThree; + Produces outputTableMcThree; + Produces outputTableTwoThree; + Produces outputTableMcTwoThree; + Produces outputTableThreeTwo; + Produces outputTableMcThreeTwo; + PresliceUnsorted perMcParticle = aod::hykfhyp::hypKfMcPartId; + + Configurable cfgSpecies{"cfgSpecies", 0, "Select species"}; + Configurable cfgNprimDaughters{"cfgNprimDaughters", 0, "Number of primary daughters"}; + Configurable cfgNsecDaughters{"cfgNsecDaughters", 0, "Number of secondary daughters (cascades only)"}; + Configurable cfgMCGenerated{"cfgMCGenerated", false, "create MC generated tree"}; + Configurable cfgMCReconstructed{"cfgMCReconstructed", false, "create MC reconstructed tree"}; + Configurable cfgMCCombined{"cfgMCCombined", false, "create MC tree containig generated and reconstructed"}; + + bool isMC; + //___________________________________________________________________________________________________________________________________________________________ + + void init(InitContext const&) + { + const AxisSpec axisPt{10, 0., 10., "#it{p}_{T} (GeV/#it{c})"}; + hPt.resize(3); + hPt[0] = histos.add("hGen", "", HistType::kTH1F, {axisPt}); + hPt[0]->Sumw2(); + hPt[1] = histos.add("hRec", "", HistType::kTH1F, {axisPt}); + hPt[1]->Sumw2(); + hPt[2] = histos.add("hEff", "", HistType::kTH1F, {axisPt}); + isMC = false; + } + //___________________________________________________________________________________________________________________________________________________________ + + void processData(aod::HypKfHypNucs const& hypNucs, aod::HypKfColls const& hypKfColls, aod::HypKfTracks const& hypKfTrks, aod::HypKfDaughtAdds const& hypKfDAdd, aod::HypKfSubDs const& hypKfDSub) + { + for (const auto& hypNuc : hypNucs) { + if (cfgSpecies && std::abs(hypNuc.species()) != cfgSpecies) + continue; + HyperNucleus candidate, hypNucDaughter; + fillCandidatePrim(candidate, hypNuc, hypNucs, hypKfColls, hypKfTrks, hypKfDAdd, hypKfDSub); + if (hypNuc.hypDaughterId() >= 0) { + fillCandidateSec(hypNucDaughter, hypNucs.rawIteratorAt(hypNuc.hypDaughterId()), hypNuc, hypNucs, hypKfColls, hypKfTrks, hypKfDAdd, hypKfDSub); + } + fillTable(candidate, hypNucDaughter); + } + } + PROCESS_SWITCH(HypKfTreeCreator, processData, "single tree", false); + //___________________________________________________________________________________________________________________________________________________________ + void fillTable(HyperNucleus& cand, HyperNucleus& hypDaughter) + { + if (isMC && cfgMCGenerated) + outputMcGenTable( + cand.pdgCode, cand.isMatterMC, cand.isReconstructed, cand.isPhysicalPrimary, cand.passedEvSelMC, cand.yGen, cand.ptGen, cand.ctGen); + + if (!cand.isReconstructed) { + cand.daughterTracks.resize(4); + cand.subDaughterMassVec.resize(4); + hypDaughter.daughterTracks.resize(4); + hypDaughter.subDaughterMassVec.resize(4); + } + + if (cfgNprimDaughters == 2 && cfgNsecDaughters == 0) { + const auto& d1 = cand.daughterTracks.at(0); + const auto& d2 = cand.daughterTracks.at(1); + if (!isMC || (isMC && cfgMCReconstructed && cand.isReconstructed)) + outputTableTwo( + cand.species, cand.isMatter, cand.cent, cand.occu, cand.passedEvSel, cand.mass, cand.y, cand.pt, cand.ct, cand.cpaPv, cand.maxDcaTracks, cand.maxDcaTracksSv, cand.dcaToPvXY, + cand.dcaToPvZ, cand.devToPvXY, cand.chi2, cand.pvx, cand.pvy, cand.pvz, cand.svx, cand.svy, cand.svz, cand.px, cand.py, cand.pz, cand.collisionMcTrue, + cand.mcTrue, cand.mcPhysicalPrimary, + d1.x, d1.y, d1.z, d1.px, d1.py, d1.pz, d1.tpcNcls, d1.tpcChi2, d1.itsNcls, d1.itsChi2, d1.itsMeanClsSizeL, + d1.rigidity, d1.tpcSignal, d1.tpcNsigma, d1.tpcNsigmaNhp, d1.tpcNsigmaNlp, d1.tofMass, d1.dcaXY, d1.dcaZ, d1.isPvContributor, + d2.x, d2.y, d2.z, d2.px, d2.py, d2.pz, d2.tpcNcls, d2.tpcChi2, d2.itsNcls, d2.itsChi2, d2.itsMeanClsSizeL, + d2.rigidity, d2.tpcSignal, d2.tpcNsigma, d2.tpcNsigmaNhp, d2.tpcNsigmaNlp, d2.tofMass, d2.dcaXY, d2.dcaZ, d2.isPvContributor); + if (isMC && cfgMCCombined) + outputTableMcTwo( + cand.pdgCode, cand.isMatterMC, cand.isReconstructed, cand.isPhysicalPrimary, cand.passedEvSelMC, cand.yGen, cand.ptGen, cand.ctGen, + cand.cpaPvGen, cand.pxGen, cand.pyGen, cand.pzGen, cand.pvxGen, cand.pvyGen, cand.pvzGen, cand.svxGen, cand.svyGen, cand.svzGen, + cand.species, cand.isMatter, cand.cent, cand.occu, cand.passedEvSel, cand.mass, cand.y, cand.pt, cand.ct, cand.cpaPv, cand.maxDcaTracks, cand.maxDcaTracksSv, + cand.dcaToPvXY, cand.dcaToPvZ, cand.devToPvXY, + cand.chi2, cand.pvx, cand.pvy, cand.pvz, cand.svx, cand.svy, cand.svz, cand.px, cand.py, cand.pz, cand.collisionMcTrue, + d1.x, d1.y, d1.z, d1.px, d1.py, d1.pz, d1.tpcNcls, d1.tpcChi2, d1.itsNcls, d1.itsChi2, d1.itsMeanClsSizeL, + d1.rigidity, d1.tpcSignal, d1.tpcNsigma, d1.tpcNsigmaNhp, d1.tpcNsigmaNlp, d1.tofMass, d1.dcaXY, d1.dcaZ, d1.isPvContributor, + d2.x, d2.y, d2.z, d2.px, d2.py, d2.pz, d2.tpcNcls, d2.tpcChi2, d2.itsNcls, d2.itsChi2, d2.itsMeanClsSizeL, + d2.rigidity, d2.tpcSignal, d2.tpcNsigma, d2.tpcNsigmaNhp, d2.tpcNsigmaNlp, d2.tofMass, d2.dcaXY, d2.dcaZ, d2.isPvContributor); + } + if (cand.isPrimaryCandidate && ((cfgNprimDaughters == 3 && cfgNsecDaughters == 0) || (cfgNsecDaughters == 3 && cfgSpecies == 0))) { + const auto& d1 = cand.daughterTracks.at(0); + const auto& d2 = cand.daughterTracks.at(1); + const auto& d3 = cand.daughterTracks.at(2); + if (!isMC || (isMC && cfgMCReconstructed && cand.isReconstructed)) + outputTableThree( + cand.species, cand.isMatter, cand.cent, cand.occu, cand.passedEvSel, cand.mass, cand.y, cand.pt, cand.ct, cand.cpaPv, cand.maxDcaTracks, cand.maxDcaTracksSv, cand.dcaToPvXY, + cand.dcaToPvZ, cand.devToPvXY, cand.chi2, cand.pvx, cand.pvy, cand.pvz, cand.svx, cand.svy, cand.svz, cand.px, cand.py, cand.pz, cand.collisionMcTrue, + cand.mcTrue, cand.mcPhysicalPrimary, + d1.x, d1.y, d1.z, d1.px, d1.py, d1.pz, d1.tpcNcls, d1.tpcChi2, d1.itsNcls, d1.itsChi2, d1.itsMeanClsSizeL, + d1.rigidity, d1.tpcSignal, d1.tpcNsigma, d1.tpcNsigmaNhp, d1.tpcNsigmaNlp, d1.tofMass, d1.dcaXY, d1.dcaZ, d1.isPvContributor, + d2.x, d2.y, d2.z, d2.px, d2.py, d2.pz, d2.tpcNcls, d2.tpcChi2, d2.itsNcls, d2.itsChi2, d2.itsMeanClsSizeL, + d2.rigidity, d2.tpcSignal, d2.tpcNsigma, d2.tpcNsigmaNhp, d2.tpcNsigmaNlp, d2.tofMass, d2.dcaXY, d2.dcaZ, d2.isPvContributor, + d3.x, d3.y, d3.z, d3.px, d3.py, d3.pz, d3.tpcNcls, d3.tpcChi2, d3.itsNcls, d3.itsChi2, d3.itsMeanClsSizeL, + d3.rigidity, d3.tpcSignal, d3.tpcNsigma, d3.tpcNsigmaNhp, d3.tpcNsigmaNlp, d3.tofMass, d3.dcaXY, d3.dcaZ, d3.isPvContributor, + d1.subMass, d2.subMass, d3.subMass); + if (isMC && cfgMCCombined) + outputTableMcThree( + cand.pdgCode, cand.isMatterMC, cand.isReconstructed, cand.isPhysicalPrimary, cand.passedEvSelMC, cand.yGen, cand.ptGen, cand.ctGen, + cand.cpaPvGen, cand.pxGen, cand.pyGen, cand.pzGen, cand.pvxGen, cand.pvyGen, cand.pvzGen, cand.svxGen, cand.svyGen, cand.svzGen, + cand.species, cand.isMatter, cand.cent, cand.occu, cand.passedEvSel, cand.mass, cand.y, cand.pt, cand.ct, cand.cpaPv, cand.maxDcaTracks, cand.maxDcaTracksSv, + cand.dcaToPvXY, cand.dcaToPvZ, cand.devToPvXY, cand.chi2, cand.pvx, cand.pvy, cand.pvz, cand.svx, cand.svy, cand.svz, cand.px, cand.py, + cand.pz, cand.collisionMcTrue, + d1.x, d1.y, d1.z, d1.px, d1.py, d1.pz, d1.tpcNcls, d1.tpcChi2, d1.itsNcls, d1.itsChi2, d1.itsMeanClsSizeL, + d1.rigidity, d1.tpcSignal, d1.tpcNsigma, d1.tpcNsigmaNhp, d1.tpcNsigmaNlp, d1.tofMass, d1.dcaXY, d1.dcaZ, d1.isPvContributor, + d2.x, d2.y, d2.z, d2.px, d2.py, d2.pz, d2.tpcNcls, d2.tpcChi2, d2.itsNcls, d2.itsChi2, d2.itsMeanClsSizeL, + d2.rigidity, d2.tpcSignal, d2.tpcNsigma, d2.tpcNsigmaNhp, d2.tpcNsigmaNlp, d2.tofMass, d2.dcaXY, d2.dcaZ, d2.isPvContributor, + d3.x, d3.y, d3.z, d3.px, d3.py, d3.pz, d3.tpcNcls, d3.tpcChi2, d3.itsNcls, d3.itsChi2, d3.itsMeanClsSizeL, + d3.rigidity, d3.tpcSignal, d3.tpcNsigma, d3.tpcNsigmaNhp, d3.tpcNsigmaNlp, d3.tofMass, d3.dcaXY, d3.dcaZ, d3.isPvContributor, + d1.subMass, d2.subMass, d3.subMass); + } + if (cfgNprimDaughters == 2 && cfgNsecDaughters == 3) { + const auto& d0 = cand.daughterTracks.at(0); + const auto& d1 = cand.daughterTracks.at(1); + const auto& sd1 = hypDaughter.daughterTracks.at(0); + const auto& sd2 = hypDaughter.daughterTracks.at(1); + const auto& sd3 = hypDaughter.daughterTracks.at(2); + if (!isMC || (isMC && cfgMCReconstructed && cand.isReconstructed)) + outputTableTwoThree( + cand.species, cand.isMatter, cand.cent, cand.occu, cand.passedEvSel, cand.mass, cand.y, cand.pt, cand.ct, cand.cpaPv, cand.maxDcaTracks, cand.maxDcaTracksSv, cand.dcaToPvXY, + cand.dcaToPvZ, cand.devToPvXY, cand.chi2, cand.pvx, cand.pvy, cand.pvz, cand.svx, cand.svy, cand.svz, cand.px, cand.py, cand.pz, cand.collisionMcTrue, + cand.mcTrue, cand.mcPhysicalPrimary, + hypDaughter.svx, hypDaughter.svy, hypDaughter.svz, d0.x, d0.y, d0.z, d0.px, d0.py, d0.pz, hypDaughter.mass, hypDaughter.ct, hypDaughter.cpaPv, + hypDaughter.maxDcaTracks, hypDaughter.dcaToPvXY, hypDaughter.dcaToPvZ, hypDaughter.dcaToVtxXY, hypDaughter.dcaToVtxZ, hypDaughter.chi2, + d1.x, d1.y, d1.z, d1.px, d1.py, d1.pz, d1.tpcNcls, d1.tpcChi2, d1.itsNcls, d1.itsChi2, d1.itsMeanClsSizeL, + d1.rigidity, d1.tpcSignal, d1.tpcNsigma, d1.tpcNsigmaNhp, d1.tpcNsigmaNlp, d1.tofMass, d1.dcaXY, d1.dcaZ, d1.isPvContributor, + sd1.x, sd1.y, sd1.z, sd1.px, sd1.py, sd1.pz, sd1.tpcNcls, sd1.tpcChi2, sd1.itsNcls, sd1.itsChi2, sd1.itsMeanClsSizeL, + sd1.rigidity, sd1.tpcSignal, sd1.tpcNsigma, sd1.tpcNsigmaNhp, sd1.tpcNsigmaNlp, sd1.tofMass, sd1.dcaXY, sd1.dcaZ, sd1.isPvContributor, + sd2.x, sd2.y, sd2.z, sd2.px, sd2.py, sd2.pz, sd2.tpcNcls, sd2.tpcChi2, sd2.itsNcls, sd2.itsChi2, sd2.itsMeanClsSizeL, + sd2.rigidity, sd2.tpcSignal, sd2.tpcNsigma, sd2.tpcNsigmaNhp, sd2.tpcNsigmaNlp, sd2.tofMass, sd2.dcaXY, sd2.dcaZ, sd2.isPvContributor, + sd3.x, sd3.y, sd3.z, sd3.px, sd3.py, sd3.pz, sd3.tpcNcls, sd3.tpcChi2, sd3.itsNcls, sd3.itsChi2, sd3.itsMeanClsSizeL, + sd3.rigidity, sd3.tpcSignal, sd3.tpcNsigma, sd3.tpcNsigmaNhp, sd3.tpcNsigmaNlp, sd3.tofMass, sd3.dcaXY, sd3.dcaZ, sd3.isPvContributor, + sd1.subMass, sd2.subMass, sd3.subMass); + if (isMC && cfgMCCombined) + outputTableMcTwoThree( + cand.pdgCode, cand.isMatterMC, cand.isReconstructed, cand.isPhysicalPrimary, cand.passedEvSelMC, cand.yGen, cand.ptGen, cand.ctGen, + cand.cpaPvGen, cand.pxGen, cand.pyGen, cand.pzGen, cand.pvxGen, cand.pvyGen, cand.pvzGen, cand.svxGen, cand.svyGen, cand.svzGen, + cand.species, cand.isMatter, cand.cent, cand.occu, cand.passedEvSel, cand.mass, cand.y, cand.pt, cand.ct, cand.cpaPv, cand.maxDcaTracks, cand.maxDcaTracksSv, cand.dcaToPvXY, + cand.dcaToPvZ, cand.devToPvXY, + cand.chi2, cand.pvx, cand.pvy, cand.pvz, cand.svx, cand.svy, cand.svz, cand.px, cand.py, cand.pz, cand.collisionMcTrue, + hypDaughter.svx, hypDaughter.svy, hypDaughter.svz, d0.x, d0.y, d0.z, d0.px, d0.py, d0.pz, hypDaughter.mass, hypDaughter.ct, hypDaughter.cpaPv, + hypDaughter.maxDcaTracks, hypDaughter.dcaToPvXY, hypDaughter.dcaToPvZ, hypDaughter.dcaToVtxXY, hypDaughter.dcaToVtxZ, hypDaughter.chi2, + d1.x, d1.y, d1.z, d1.px, d1.py, d1.pz, d1.tpcNcls, d1.tpcChi2, d1.itsNcls, d1.itsChi2, d1.itsMeanClsSizeL, + d1.rigidity, d1.tpcSignal, d1.tpcNsigma, d1.tpcNsigmaNhp, d1.tpcNsigmaNlp, d1.tofMass, d1.dcaXY, d1.dcaZ, d1.isPvContributor, + sd1.x, sd1.y, sd1.z, sd1.px, sd1.py, sd1.pz, sd1.tpcNcls, sd1.tpcChi2, sd1.itsNcls, sd1.itsChi2, sd1.itsMeanClsSizeL, + sd1.rigidity, sd1.tpcSignal, sd1.tpcNsigma, sd1.tpcNsigmaNhp, sd1.tpcNsigmaNlp, sd1.tofMass, sd1.dcaXY, sd1.dcaZ, sd1.isPvContributor, + sd2.x, sd2.y, sd2.z, sd2.px, sd2.py, sd2.pz, sd2.tpcNcls, sd2.tpcChi2, sd2.itsNcls, sd2.itsChi2, sd2.itsMeanClsSizeL, + sd2.rigidity, sd2.tpcSignal, sd2.tpcNsigma, sd2.tpcNsigmaNhp, sd2.tpcNsigmaNlp, sd2.tofMass, sd2.dcaXY, sd2.dcaZ, sd2.isPvContributor, + sd3.x, sd3.y, sd3.z, sd3.px, sd3.py, sd3.pz, sd3.tpcNcls, sd3.tpcChi2, sd3.itsNcls, sd3.itsChi2, sd3.itsMeanClsSizeL, + sd3.rigidity, sd3.tpcSignal, sd3.tpcNsigma, sd3.tpcNsigmaNhp, sd3.tpcNsigmaNlp, sd3.tofMass, sd3.dcaXY, sd3.dcaZ, sd3.isPvContributor, + sd1.subMass, sd2.subMass, sd3.subMass); + } + if (cfgNprimDaughters == 3 && cfgNsecDaughters == 1) { + const auto& d0 = cand.daughterTracks.at(0); + const auto& d1 = cand.daughterTracks.at(1); + const auto& d2 = cand.daughterTracks.at(2); + const auto& sd1 = hypDaughter.daughterTracks.at(0); + const auto& sd2 = hypDaughter.daughterTracks.at(1); + if (!isMC || (isMC && cfgMCReconstructed && cand.isReconstructed)) + outputTableThreeTwo( + cand.species, cand.isMatter, cand.cent, cand.occu, cand.passedEvSel, cand.mass, cand.y, cand.pt, cand.ct, cand.cpaPv, cand.maxDcaTracks, cand.maxDcaTracksSv, cand.dcaToPvXY, + cand.dcaToPvZ, cand.devToPvXY, cand.chi2, cand.pvx, cand.pvy, cand.pvz, cand.svx, cand.svy, cand.svz, cand.px, cand.py, cand.pz, cand.collisionMcTrue, + cand.mcTrue, cand.mcPhysicalPrimary, hypDaughter.svx, hypDaughter.svy, hypDaughter.svz, d0.x, d0.y, d0.z, d0.px, d0.py, d0.pz, hypDaughter.mass, hypDaughter.ct, + hypDaughter.cpaPv, hypDaughter.maxDcaTracks, hypDaughter.dcaToPvXY, hypDaughter.dcaToPvZ, hypDaughter.dcaToVtxXY, hypDaughter.dcaToVtxZ, hypDaughter.chi2, + d1.x, d1.y, d1.z, d1.px, d1.py, d1.pz, d1.tpcNcls, d1.tpcChi2, d1.itsNcls, d1.itsChi2, d1.itsMeanClsSizeL, + d1.rigidity, d1.tpcSignal, d1.tpcNsigma, d1.tpcNsigmaNhp, d1.tpcNsigmaNlp, d1.tofMass, d1.dcaXY, d1.dcaZ, d1.isPvContributor, + d2.x, d2.y, d2.z, d2.px, d2.py, d2.pz, d2.tpcNcls, d2.tpcChi2, d2.itsNcls, d2.itsChi2, d2.itsMeanClsSizeL, + d2.rigidity, d2.tpcSignal, d2.tpcNsigma, d2.tpcNsigmaNhp, d2.tpcNsigmaNlp, d2.tofMass, d2.dcaXY, d2.dcaZ, d2.isPvContributor, + d0.subMass, d1.subMass, d2.subMass, + sd1.x, sd1.y, sd1.z, sd1.px, sd1.py, sd1.pz, sd1.tpcNcls, sd1.tpcChi2, sd1.itsNcls, sd1.itsChi2, sd1.itsMeanClsSizeL, + sd1.rigidity, sd1.tpcSignal, sd1.tpcNsigma, sd1.tpcNsigmaNhp, sd1.tpcNsigmaNlp, sd1.tofMass, sd1.dcaXY, sd1.dcaZ, sd1.isPvContributor, + sd2.x, sd2.y, sd2.z, sd2.px, sd2.py, sd2.pz, sd2.tpcNcls, sd2.tpcChi2, sd2.itsNcls, sd2.itsChi2, sd2.itsMeanClsSizeL, + sd2.rigidity, sd2.tpcSignal, sd2.tpcNsigma, sd2.tpcNsigmaNhp, sd2.tpcNsigmaNlp, sd2.tofMass, sd2.dcaXY, sd2.dcaZ, sd2.isPvContributor); + if (isMC && cfgMCCombined) + outputTableMcThreeTwo( + cand.pdgCode, cand.isMatterMC, cand.isReconstructed, cand.isPhysicalPrimary, cand.passedEvSelMC, cand.yGen, cand.ptGen, cand.ctGen, + cand.cpaPvGen, cand.pxGen, cand.pyGen, cand.pzGen, cand.pvxGen, cand.pvyGen, cand.pvzGen, cand.svxGen, cand.svyGen, cand.svzGen, + cand.species, cand.isMatter, cand.cent, cand.occu, cand.passedEvSel, cand.mass, cand.y, cand.pt, cand.ct, cand.cpaPv, cand.maxDcaTracks, cand.maxDcaTracksSv, cand.dcaToPvXY, + cand.dcaToPvZ, cand.devToPvXY, cand.chi2, cand.pvx, cand.pvy, cand.pvz, cand.svx, cand.svy, cand.svz, cand.px, cand.py, cand.pz, cand.collisionMcTrue, + hypDaughter.svx, hypDaughter.svy, hypDaughter.svz, d0.x, d0.y, d0.z, d0.px, d0.py, d0.pz, hypDaughter.mass, hypDaughter.ct, hypDaughter.cpaPv, + hypDaughter.maxDcaTracks, hypDaughter.dcaToPvXY, hypDaughter.dcaToPvZ, hypDaughter.dcaToVtxXY, hypDaughter.dcaToVtxZ, hypDaughter.chi2, + d1.x, d1.y, d1.z, d1.px, d1.py, d1.pz, d1.tpcNcls, d1.tpcChi2, d1.itsNcls, d1.itsChi2, d1.itsMeanClsSizeL, + d1.rigidity, d1.tpcSignal, d1.tpcNsigma, d1.tpcNsigmaNhp, d1.tpcNsigmaNlp, d1.tofMass, d1.dcaXY, d1.dcaZ, d1.isPvContributor, + d2.x, d2.y, d2.z, d2.px, d2.py, d2.pz, d2.tpcNcls, d2.tpcChi2, d2.itsNcls, d2.itsChi2, d2.itsMeanClsSizeL, + d2.rigidity, d2.tpcSignal, d2.tpcNsigma, d2.tpcNsigmaNhp, d2.tpcNsigmaNlp, d2.tofMass, d2.dcaXY, d2.dcaZ, d2.isPvContributor, + d0.subMass, d1.subMass, d2.subMass, + sd1.x, sd1.y, sd1.z, sd1.px, sd1.py, sd1.pz, sd1.tpcNcls, sd1.tpcChi2, sd1.itsNcls, sd1.itsChi2, sd1.itsMeanClsSizeL, + sd1.rigidity, sd1.tpcSignal, sd1.tpcNsigma, sd1.tpcNsigmaNhp, sd1.tpcNsigmaNlp, sd1.tofMass, sd1.dcaXY, sd1.dcaZ, sd1.isPvContributor, + sd2.x, sd2.y, sd2.z, sd2.px, sd2.py, sd2.pz, sd2.tpcNcls, sd2.tpcChi2, sd2.itsNcls, sd2.itsChi2, sd2.itsMeanClsSizeL, + sd2.rigidity, sd2.tpcSignal, sd2.tpcNsigma, sd2.tpcNsigmaNhp, sd2.tpcNsigmaNlp, sd2.tofMass, sd2.dcaXY, sd2.dcaZ, sd2.isPvContributor); + } + } + //___________________________________________________________________________________________________________________________________________________________ + void fillCandidatePrim(HyperNucleus& cand, aod::HypKfHypNuc const& hypNuc, aod::HypKfHypNucs const& hypNucs, aod::HypKfColls const& colls, aod::HypKfTracks const& tracks, aod::HypKfDaughtAdds const& daughterAdds, aod::HypKfSubDs const& subDs) + { + auto coll = hypNuc.hypKfColl(); + cand.ct = ct(coll, hypNuc); + cand.cpaPv = cpa(coll, hypNuc); + fillCandidate(cand, hypNuc, hypNucs, colls, tracks, daughterAdds, subDs); + } + //___________________________________________________________________________________________________________________________________________________________ + void fillCandidateSec(HyperNucleus& cand, aod::HypKfHypNuc const& hypNuc, aod::HypKfHypNuc const& mother, aod::HypKfHypNucs const& hypNucs, aod::HypKfColls const& colls, aod::HypKfTracks const& tracks, aod::HypKfDaughtAdds const& daughterAdds, aod::HypKfSubDs const& subDs) + { + cand.ct = ct(mother, hypNuc); + cand.cpaPv = cpa(mother, hypNuc); + fillCandidate(cand, hypNuc, hypNucs, colls, tracks, daughterAdds, subDs); + } + //___________________________________________________________________________________________________________________________________________________________ + void fillCandidate(HyperNucleus& cand, aod::HypKfHypNuc const& hypNuc, aod::HypKfHypNucs const&, aod::HypKfColls const&, aod::HypKfTracks const&, aod::HypKfDaughtAdds const&, aod::HypKfSubDs const&) + { + cand.daughterTracks.clear(); + cand.subDaughterMassVec.clear(); + auto coll = hypNuc.hypKfColl(); + auto addOns = hypNuc.hypKfDaughtAdd_as(); + auto posVec = posVector(addOns); + cand.species = std::abs(hypNuc.species()); + cand.isPrimaryCandidate = hypNuc.primary(); + cand.isMatter = hypNuc.isMatter(); + cand.cent = coll.centFT0C(); + cand.occu = coll.occupancy(); + cand.passedEvSel = coll.passedEvSel(); + cand.mass = hypNuc.mass(); + cand.y = hypNuc.y(); + cand.pt = hypNuc.pt(); + cand.maxDcaTracks = maxValue(dcaTracksAll(posVec, "XY")); + cand.maxDcaTracksSv = maxValue(dcaTrackSvAll(posVec, hypNuc, "XY")); + cand.dcaToPvXY = hypNuc.dcaToPvXY(); + cand.dcaToPvZ = hypNuc.dcaToPvZ(); + cand.dcaToVtxXY = hypNuc.dcaToVtxXY(); + cand.dcaToVtxZ = hypNuc.dcaToVtxZ(); + cand.devToPvXY = hypNuc.devToPvXY(); + cand.chi2 = hypNuc.chi2(); + cand.pvx = coll.posX(); + cand.pvy = coll.posY(); + cand.pvz = coll.posZ(); + cand.svx = hypNuc.svx(); + cand.svy = hypNuc.svy(); + cand.svz = hypNuc.svz(); + cand.px = hypNuc.px(); + cand.py = hypNuc.py(); + cand.pz = hypNuc.pz(); + if (hypNuc.hypDaughterId() >= 0) { + TrackProperties hypDaughter; + cand.daughterTracks.push_back(hypDaughter); + } + auto daughterTracks = hypNuc.hypKfTrack_as(); + for (const auto& track : daughterTracks) { + TrackProperties daughter; + daughter.tpcNcls = track.tpcNcluster(); + daughter.itsNcls = track.itsNcluster(); + daughter.tpcChi2 = track.tpcChi2NCl(); + daughter.itsChi2 = track.itsChi2NCl(); + daughter.itsMeanClsSize = track.itsMeanClsSize(); + daughter.itsMeanClsSizeL = track.itsMeanClsSize() * track.lambda(); + daughter.rigidity = track.rigidity(); + daughter.tpcSignal = track.tpcSignal(); + daughter.tpcNsigma = track.tpcNsigma(); + daughter.tpcNsigmaNhp = track.tpcNsigmaNhp(); + daughter.tpcNsigmaNlp = track.tpcNsigmaNlp(); + daughter.tofMass = track.tofMass(); + daughter.dcaXY = track.dcaXY(); + daughter.dcaZ = track.dcaZ(); + daughter.isPvContributor = track.isPVContributor(); + cand.daughterTracks.push_back(daughter); + } + int trackCount = 0; + for (const auto& addOn : addOns) { + cand.daughterTracks.at(trackCount).x = addOn.x(); + cand.daughterTracks.at(trackCount).y = addOn.y(); + cand.daughterTracks.at(trackCount).z = addOn.z(); + cand.daughterTracks.at(trackCount).px = addOn.px(); + cand.daughterTracks.at(trackCount).py = addOn.py(); + cand.daughterTracks.at(trackCount).pz = addOn.py(); + trackCount++; + } + cand.nSingleDaughters = trackCount; + if (cand.nSingleDaughters < 3) + return; + + trackCount = 0; + auto subDaughters = hypNuc.hypKfSubD_as(); + for (const auto& subDaughter : subDaughters) { + cand.daughterTracks.at(trackCount++).subMass = subDaughter.subMass(); + } + } + //___________________________________________________________________________________________________________________________________________________________ + + void processMC(aod::HypKfMcParts const& mcHypNucs, aod::HypKfHypNucs const& hypNucs, aod::HypKfMcColls const&, aod::HypKfColls const& hypKfColls, aod::HypKfTracks const& hypKfTrks, aod::HypKfDaughtAdds const& hypKfDAdd, aod::HypKfSubDs const& hypKfDSub) + { + isMC = true; + for (const auto& mcHypNuc : mcHypNucs) { + if (cfgSpecies && std::abs(mcHypNuc.species()) != cfgSpecies) + continue; + auto mcColl = mcHypNuc.hypKfMcColl(); + const auto mcParticleIdx = mcHypNuc.globalIndex(); + auto hypNucsByMc = hypNucs.sliceBy(perMcParticle, mcParticleIdx); + HyperNucleus candidate, hypNucDaughter; + candidate.pdgCode = mcHypNuc.pdgCode(); + candidate.isMatterMC = mcHypNuc.isMatter(); + candidate.isPhysicalPrimary = mcHypNuc.isPhysicalPrimary(); + candidate.passedEvSelMC = mcColl.passedEvSel(); + candidate.yGen = mcHypNuc.y(); + candidate.ptGen = mcHypNuc.pt(); + candidate.ctGen = ct(mcColl, mcHypNuc); + candidate.isReconstructed = 0; + candidate.cpaPvGen = cpa(mcColl, mcHypNuc); + candidate.pxGen = mcHypNuc.px(); + candidate.pyGen = mcHypNuc.py(); + candidate.pzGen = mcHypNuc.pz(); + candidate.pvxGen = mcColl.posX(); + candidate.pvyGen = mcColl.posY(); + candidate.pvzGen = mcColl.posZ(); + candidate.svxGen = mcHypNuc.svx(); + candidate.svyGen = mcHypNuc.svy(); + candidate.svzGen = mcHypNuc.svz(); + for (const auto& hypNuc : hypNucsByMc) { + auto coll = hypNuc.hypKfColl(); + if (coll.hypKfMcCollId() == mcHypNuc.hypKfMcCollId()) { + candidate.collisionMcTrue = true; + } + candidate.isReconstructed++; + fillCandidatePrim(candidate, hypNucs.rawIteratorAt(hypNuc.globalIndex()), hypNucs, hypKfColls, hypKfTrks, hypKfDAdd, hypKfDSub); + if (hypNuc.hypDaughterId() >= 0) { + fillCandidateSec(hypNucDaughter, hypNucs.rawIteratorAt(hypNuc.hypDaughterId()), hypNucs.rawIteratorAt(hypNuc.globalIndex()), hypNucs, hypKfColls, hypKfTrks, hypKfDAdd, hypKfDSub); + } + } + fillTable(candidate, hypNucDaughter); + hPt[0]->Fill(mcHypNuc.pt()); + if (candidate.isReconstructed) + hPt[1]->Fill(candidate.pt); + } + hPt[2]->Divide(hPt[1].get(), hPt[0].get()); + } + PROCESS_SWITCH(HypKfTreeCreator, processMC, "MC Gen tree", false); + + //___________________________________________________________________________________________________________________________________________________________ + std::vector dcaTracksAll(std::vector& posVec, TString opt = "") + { + std::vector vec; + int n = posVec.size(); + for (int i = 0; i < (n - 1); i++) { + for (int j = (i + 1); j < n; j++) { + vec.push_back(dcaTracks(posVec, i, j, opt)); + } + } + return vec; + } + template + std::vector dcaTrackSvAll(std::vector& posVec, T const& hypNuc, TString opt = "") + { + std::vector vec; + for (size_t i = 0; i < posVec.size(); i++) { + vec.push_back(dcaTrackSv(posVec, i, hypNuc, opt)); + } + return vec; + } + + float maxValue(std::vector vec) + { + return *max_element(vec.begin(), vec.end()); + } + float meanValue(std::vector vec) + { + float sum = 0; + for (const auto& value : vec) + sum += value; + return sum / vec.size(); + } + float mean2Value(std::vector vec) + { + float sum = 0; + for (const auto& value : vec) + sum += (value * value); + return std::sqrt(sum / vec.size()); + } + + float dcaTracks(std::vector v, int track1, int track2, TString opt = "XY") + { + if (opt == "XY") + return RecoDecay::distanceXY(v.at(track1), v.at(track2)); + else if (opt == "Z") + return std::abs(v.at(track1).at(2) - v.at(track2).at(2)); + else + return RecoDecay::distance(v.at(track1), v.at(track2)); + } + template + float dcaTrackSv(std::vector& v, int track, T const& hypNuc, TString opt = "") + { + if (opt == "XY") + return RecoDecay::distanceXY(v.at(track), decayVtx(hypNuc)); + else if (opt == "Z") + return std::abs(v.at(track).at(2) - decayVtx(hypNuc).at(2)); + else + return RecoDecay::distance(v.at(track), decayVtx(hypNuc)); + } + template + std::vector posVector(T const& addons) + { + std::vector v; + for (const auto& pos : addons) { + v.push_back(std::array{pos.x(), pos.y(), pos.z()}); + } + return v; + } + template + arr3 primVtx(T const& coll) + { + return std::array{coll.posX(), coll.posY(), coll.posZ()}; + } + template + arr3 decayVtx(T const& hypNuc) + { + return std::array{hypNuc.svx(), hypNuc.svy(), hypNuc.svz()}; + } + template + arr3 momenta(T const& hypNuc) + { + return std::array{hypNuc.px(), hypNuc.py(), hypNuc.pz()}; + } + template + float decayLength(TColl const& coll, TPart const& hypNuc) + { + return RecoDecay::distance(primVtx(coll), decayVtx(hypNuc)); + } + template + float ct(TColl const& coll, TPart const& hypNuc) + { + return RecoDecay::ct(momenta(hypNuc), decayLength(coll, hypNuc), hypNuc.mass()); + } + template + double cpa(TColl const& coll, TPart const& hypNuc) + { + return RecoDecay::cpa(primVtx(coll), decayVtx(hypNuc), momenta(hypNuc)); + } + // only for Cascades + template + float decayLength(TPart const& mother, TPart const& daughter) + { + return RecoDecay::distance(decayVtx(mother), decayVtx(daughter)); + } + template + float ct(TPart const& mother, TPart const& daughter) + { + return RecoDecay::ct(momenta(daughter), decayLength(mother, daughter), daughter.mass()); + } + template + double cpa(TPart const& mother, TPart const& daughter) + { + return RecoDecay::cpa(decayVtx(mother), decayVtx(daughter), momenta(daughter)); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Nuspex/hyperKinkRecoTask.cxx b/PWGLF/TableProducer/Nuspex/hyperKinkRecoTask.cxx deleted file mode 100644 index 56248bb1e16..00000000000 --- a/PWGLF/TableProducer/Nuspex/hyperKinkRecoTask.cxx +++ /dev/null @@ -1,796 +0,0 @@ -// 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. -// -// Search for hypernuclei kink decay topology -// ============================================================================== - -#include - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/trackUtilities.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" - -#include "Common/Core/PID/TPCPIDResponse.h" -#include "DataFormatsTPC/BetheBlochAleph.h" -#include "DCAFitter/DCAFitterN.h" - -#include "PWGLF/DataModel/LFParticleIdentification.h" -#include "PWGLF/DataModel/LFHypernucleiTables.h" - -static constexpr int POS = 0, NEG = 1; - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; -using VBracket = o2::math_utils::Bracket; -using TracksFull = soa::Join; -using CollisionsFull = soa::Join; - -namespace -{ -constexpr std::array LayerRadii{2.33959f, 3.14076f, 3.91924f, 19.6213f, 24.5597f, 34.388f, 39.3329f}; -constexpr double betheBlochDefault[1][6]{{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}}; -static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; -static const std::vector particleNames{"Triton"}; -std::shared_ptr hEvents; -std::shared_ptr hZvtx; -std::shared_ptr hCentFT0A; -std::shared_ptr hCentFT0C; -std::shared_ptr hCentFT0M; -std::shared_ptr hCentFV0A; -std::shared_ptr hNsigmaTritSel; -std::shared_ptr hDeDxTritSel; -std::shared_ptr hDeDxTot; -std::shared_ptr hIsMatterGen; -} // namespace - -struct kinkCandidate { - - float recoPtHyp() const { return std::hypot(momHyp[0], momHyp[1]); } - float recoPhiHyp() const { return std::atan2(momHyp[1], momHyp[0]); } - float recoEtaHyp() const { return std::asinh(momHyp[2] / recoPtHyp()); } - - float recoPtTrit() const { return std::hypot(momTrit[0], momTrit[1]); } - float recoPhiTrit() const { return std::atan2(momTrit[1], momTrit[0]); } - float recoEtaTrit() const { return std::asinh(momTrit[2] / recoPtTrit()); } - - float genPt() const { return std::hypot(gMomHyp[0], gMomHyp[1]); } - float genPtTrit() const { return std::hypot(gMomTrit[0], gMomTrit[1]); } - float genPhi() const { return std::atan2(gMomHyp[1], gMomHyp[0]); } - float genEta() const { return std::asinh(gMomHyp[2] / genPt()); } - - int hyperTrackID; - int tritTrackID; - bool isMatter = false; - - std::array momHyp = {-999, -999, -999}; - std::array momTrit = {-999, -999, -999}; - std::array primVtx = {-999, -999, -999}; - std::array decVtx = {-999, -999, -999}; - - float dcaKinkTopo = -999; - float nSigmaTPCTrit = -999; - float nSigmaTOFTrit = -999; - float tritDCAXY = -999; - float hypDCAXY = -999; - float kinkAngle = -999; - - float momTritTPC = -999.f; - uint16_t tpcSignalTrit = 0u; - uint8_t nTPCClustersTrit = 0u; - uint8_t trackingPIDTriton = 0u; // flags for triton PID in tracking - - uint32_t clusterSizeITSHyp = 0u; - uint32_t clusterSizeITSTrit = 0u; - - std::array gMomHyp; - std::array gMomTrit; - std::array gDecVtx; - - bool isSignal = false; // true MC signal - bool isReco = false; // true if the candidate is actually reconstructed - float itsPt = -999.f; // pt of the ITS hypertrack even when the topology is not reconstructed, tagged with the MC truth - uint16_t mcMask = false; // to study fake its tracks - bool survEvSelection = false; // true if the corresponding event passed the event selection - int pdgCode = 0; // pdg code of the mother particle -}; - -struct TrackCand { - int Idxtr; - int mcParticleIdx = -1; - VBracket vBracket{}; -}; - -struct hyperKinkRecoTask { - - Produces outputDataTable; - Produces outputMCTable; - Service ccdb; - - // Selection criteria - Configurable invMassLow{"invMassLow", 2.9, "Lower limit for the invariant mass"}; - Configurable invMassHigh{"invMassHigh", 15., "Upper limit for the invariant mass"}; - Configurable maxDCAHypToPV{"maxDCAHypToPV", 0.1, "Max DCA of the hypertriton to the PV"}; - Configurable minDCATritToPV{"minDCATritToPV", 0., "Min DCA of the triton to the PV"}; - Configurable minPtHyp{"minPtHyp", 0.5, "Minimum pT of the hypercandidate"}; - Configurable maxZDiff{"maxZDiff", 20., "Max z difference between the kink daughter and the hypertriton"}; - Configurable maxPhiDiff{"maxPhiDiff", 100, "Max phi difference between the kink daughter and the hypertriton"}; - Configurable timeMarginNS{"timeMarginNS", 600, "Additional time res tolerance in ns"}; - Configurable etaMax{"eta", 1., "eta daughter"}; - Configurable nSigmaTPCCutTrit{"nSigmaTPCTrit", 5, "triton dEdx cut (n sigma)"}; - Configurable nSigmaTOFCutTrit{"nSigmaTOFTrit", 5, "triton TOF cut (n sigma)"}; - Configurable nTPCClusMinTrit{"nTPCClusMinTrit", 80, "triton NTPC clusters cut"}; - Configurable alwaysAskTOF{"alwaysAskTOF", false, "If true, ask for TOF signal"}; - Configurable mcSignalOnly{"mcSignalOnly", true, "If true, save only signal in MC"}; - - // Define o2 fitter, 2-prong, active memory (no need to redefine per event) - o2::vertexing::DCAFitterN<2> fitter; - o2::base::MatLayerCylSet* lut = nullptr; - - // constants - float tritonMass = o2::constants::physics::MassTriton; - float pi0Mass = o2::constants::physics::MassPi0; - float radToDeg = 180. / M_PI; - Configurable hyperPdg{"hyperPDG", 1010010030, "PDG code of the hyper-mother"}; - Configurable tritDauPdg{"kinkDauPDG", 1000010030, "PDG code of the kink daughter"}; - - // bethe bloch parameters - Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {betheBlochDefault[0], 1, 6, particleNames, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for Triton"}; - Configurable cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Type of material correction"}; - - // CCDB options - Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - Configurable pidPath{"pidPath", "", "Path to the PID response object"}; - - // PDG codes - - // histogram axes - ConfigurableAxis rigidityBins{"rigidityBins", {200, -10.f, 10.f}, "Binning for rigidity #it{p}^{TPC}/#it{z}"}; - ConfigurableAxis dedxBins{"dedxBins", {1000, 0.f, 1000.f}, "Binning for dE/dx"}; - ConfigurableAxis nSigmaBins{"nSigmaBins", {200, -5.f, 5.f}, "Binning for n sigma"}; - ConfigurableAxis zVtxBins{"zVtxBins", {100, -20.f, 20.f}, "Binning for n sigma"}; - ConfigurableAxis centBins{"centBins", {100, 0.f, 100.f}, "Binning for centrality"}; - - // std vector of candidates - std::vector mKinkCandidates; - // vector to keep track of MC mothers already filled - std::vector filledMothers; - // vector to keep track of the collisions passing the event selection in the MC - std::vector isGoodCollision; - HistogramRegistry qaRegistry{"QA", {}, OutputObjHandlingPolicy::AnalysisObject}; - - int mRunNumber; - float d_bz; - std::array mBBparamsTrit; - - void init(InitContext const&) - { - - mRunNumber = 0; - d_bz = 0; - - ccdb->setURL(ccdburl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - fitter.setPropagateToPCA(true); - fitter.setMaxR(200.); - fitter.setMinParamChange(1e-3); - fitter.setMinRelChi2Change(0.9); - fitter.setMaxDZIni(1e9); - fitter.setMaxChi2(1e9); - fitter.setUseAbsDCA(true); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); - int mat{static_cast(cfgMaterialCorrection)}; - fitter.setMatCorrType(static_cast(mat)); - - const AxisSpec rigidityAxis{rigidityBins, "#it{p}^{TPC}/#it{z}"}; - const AxisSpec dedxAxis{dedxBins, "d#it{E}/d#it{x}"}; - const AxisSpec nSigma3HeAxis{nSigmaBins, "n_{#sigma}({}^{3}He)"}; - const AxisSpec zVtxAxis{zVtxBins, "z_{vtx} (cm)"}; - const AxisSpec centAxis{centBins, "Centrality"}; - - hNsigmaTritSel = qaRegistry.add("hNsigmaTritSel", "; p_{TPC}/z (GeV/#it{c}); n_{#sigma} ({}^{3}H)", HistType::kTH2F, {rigidityAxis, nSigma3HeAxis}); - hDeDxTritSel = qaRegistry.add("hDeDxTritSel", ";p_{TPC}/z (GeV/#it{c}); dE/dx", HistType::kTH2F, {rigidityAxis, dedxAxis}); - hDeDxTot = qaRegistry.add("hDeDxTot", ";p_{TPC}/z (GeV/#it{c}); dE/dx", HistType::kTH2F, {rigidityAxis, dedxAxis}); - hEvents = qaRegistry.add("hEvents", ";Events; ", HistType::kTH1D, {{3, -0.5, 2.5}}); - hEvents->GetXaxis()->SetBinLabel(1, "All"); - hEvents->GetXaxis()->SetBinLabel(2, "sel8"); - hEvents->GetXaxis()->SetBinLabel(3, "z vtx"); - - if (doprocessMC) { - hIsMatterGen = qaRegistry.add("hIsMatterGen", ";; ", HistType::kTH1D, {{2, -0.5, 1.5}}); - hIsMatterGen->GetXaxis()->SetBinLabel(1, "Matter"); - hIsMatterGen->GetXaxis()->SetBinLabel(2, "Antimatter"); - } - hZvtx = qaRegistry.add("hZvtx", ";z_{vtx} (cm); ", HistType::kTH1D, {{100, -20, 20}}); - hCentFT0M = qaRegistry.add("hCentFT0M", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); - } - - float angleCutFunction(float x) - { - float par1 = 2.99131; // hypertriton mass - float par2 = 0.07; // optimized by mdiotti - float par3 = TMath::Pi(); - return par1 * (par2 / (sqrt((x * x) * (1 - (par2 * par2)) - ((par1 * par1) * (par2 * par2))))) * (180. / par3) + 1; - } - - template - float computeNSigmaTrit(const T& candidate) - { - float nSigmaTrit = -100.f; - if (mBBparamsTrit[5] > 0) { - float expTPCSignal = o2::tpc::BetheBlochAleph(static_cast(candidate.tpcInnerParam() * 2 / constants::physics::MassHelium3), mBBparamsTrit[0], mBBparamsTrit[1], mBBparamsTrit[2], mBBparamsTrit[3], mBBparamsTrit[4]); - double resoTPC{expTPCSignal * mBBparamsTrit[5]}; - nSigmaTrit = static_cast((candidate.tpcSignal() - expTPCSignal) / resoTPC); - } else { - nSigmaTrit = candidate.tpcNSigmaTr(); - } - return nSigmaTrit; - } - - template - bool selectHyperTrack(const T& candidate) - { - if (candidate.hasITS() && !candidate.hasTPC() && !candidate.hasTOF() && candidate.itsNCls() < 6 && - candidate.itsNClsInnerBarrel() == 3 && candidate.itsChi2NCl() < 36 && candidate.pt() > minPtHyp) { - return true; - } - return false; - } - - template - bool selectTritTrack(const T& candidate) - { - if (!candidate.hasTPC() || !candidate.hasITS()) { - return false; - } - - if (alwaysAskTOF && !candidate.hasTOF()) { - return false; - } - - float nSigmaTrit = computeNSigmaTrit(candidate); - float nSigmaTOFTrit = candidate.tofNSigmaTr(); - - bool isGoodTPCCand = false; - if (candidate.itsNClsInnerBarrel() == 0 && candidate.itsNCls() < 4 && - candidate.tpcNClsCrossedRows() >= 70 && candidate.tpcChi2NCl() < 4.f && - candidate.tpcNClsCrossedRows() > 0.8 * candidate.tpcNClsFindable() && candidate.tpcNClsFound() > 80 && abs(nSigmaTrit) < nSigmaTPCCutTrit) { - isGoodTPCCand = true; - } - - if (!isGoodTPCCand) { - return false; - } - - if (candidate.hasTOF() && abs(nSigmaTOFTrit) > nSigmaTOFCutTrit) { - return false; - } - - hNsigmaTritSel->Fill(candidate.pt(), nSigmaTrit); - hDeDxTritSel->Fill(candidate.tpcInnerParam(), candidate.tpcSignal()); - - return true; - } - - std::array, 4> makeTracksPool(CollisionsFull const& collisions, TracksFull const& tracks, o2::aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const&) - { - std::unordered_map> tmap; - TrackCand trForpool; - - std::array, 4> pools; // pools of positive and negative seeds sorted in min VtxID - std::vector selected(tracks.size(), 0u); - std::vector globalBCvector; - - int index{0}; - for (const auto& track : tracks) { - if (track.has_collision()) { - if (track.collision_as().has_bc()) { - globalBCvector.push_back(track.collision_as().bc_as().globalBC()); - } - } else { - for (const auto& ambTrack : ambiTracks) { - if (ambTrack.trackId() == track.globalIndex()) { - if (!ambTrack.has_bc() || ambTrack.bc_as().size() == 0) { - globalBCvector.push_back(-1); - break; - } - globalBCvector.push_back(ambTrack.bc_as().begin().globalBC()); - break; - } - } - } - - if (std::abs(track.eta()) < 0.8) { - if (selectHyperTrack(track)) { - selected[index] = 1; - } else if (selectTritTrack(track)) { - selected[index] = 2; - } - } - - index++; - } - constexpr auto bOffsetMax = 241; // 6 mus (ITS) - - for (const auto& collision : collisions) { - - hEvents->Fill(0); - if (!collision.sel8()) - continue; - hEvents->Fill(1); - if (std::abs(collision.posZ()) > 10.) - continue; - hEvents->Fill(2); - hZvtx->Fill(collision.posZ()); - hCentFT0M->Fill(collision.centFT0M()); - - const float collTime = collision.collisionTime(); - const float collTimeRes2 = collision.collisionTimeRes() * collision.collisionTimeRes(); - uint64_t collBC = collision.bc_as().globalBC(); - const auto collIdx = collision.globalIndex(); - - index = -1; - for (const auto& track : tracks) { - index++; - if (!selected[index] || !track.has_collision()) - continue; - const int64_t bcOffset = (int64_t)globalBCvector[track.globalIndex()] - (int64_t)collBC; - if (std::abs(bcOffset) > bOffsetMax) { - continue; - } - - float trackTime{0.}; - float trackTimeRes{0.}; - if (track.isPVContributor()) { - trackTime = track.collision_as().collisionTime(); // if PV contributor, we assume the time to be the one of the collision - trackTimeRes = constants::lhc::LHCBunchSpacingNS; // 1 BC - } else { - trackTime = track.trackTime(); - trackTimeRes = track.trackTimeRes(); - } - - const float deltaTime = trackTime - collTime + bcOffset * constants::lhc::LHCBunchSpacingNS; - float sigmaTimeRes2 = collTimeRes2 + trackTimeRes * trackTimeRes; - - float thresholdTime = 0.; - if (track.isPVContributor()) { - thresholdTime = trackTimeRes; - } else if (TESTBIT(track.flags(), o2::aod::track::TrackTimeResIsRange)) { - thresholdTime = std::sqrt(sigmaTimeRes2); // + timeMargin; - thresholdTime += timeMarginNS; - - } else { - // thresholdTime = nSigmaForTimeCompat * std::sqrt(sigmaTimeRes2); // + timeMargin; - thresholdTime = 4. * std::sqrt(sigmaTimeRes2); // + timeMargin; - thresholdTime += timeMarginNS; - } - - if (std::abs(deltaTime) > thresholdTime) { - continue; - } - - const auto& tref = tmap.find(track.globalIndex()); - if (tref != tmap.end()) { - LOG(debug) << "Track: " << track.globalIndex() << " already processed with other vertex"; - pools[tref->second.second][tref->second.first].vBracket.setMax(static_cast(collIdx)); // this track was already processed with other vertex, account the latter - continue; - } - - int poolIndex = (selected[index] - 1) * 2 + (track.sign() < 0); /// first the two mothers then the two daughters (mom pos 0, mom neg 1, dau pos 2, dau neg 3) - trForpool.Idxtr = track.globalIndex(); - trForpool.vBracket = {static_cast(collIdx), static_cast(collIdx)}; - pools[poolIndex].emplace_back(trForpool); - tmap[track.globalIndex()] = {pools[poolIndex].size() - 1, poolIndex}; - - } // track Mother loop - } // collision loop - - return pools; - } - - void fillCandidateData(CollisionsFull const& collisions, TracksFull const& tracks, o2::aod::AmbiguousTracks const&, aod::BCsWithTimestamps const&, std::array, 4> trackPool) - { - gsl::span> hyperPool{trackPool.data(), 2}; - gsl::span> tritPool{trackPool.data() + 2, 2}; - - std::array, 2> mVtxTritTrack{}; // 1st pos. and neg. track of the kink pool for each vertex - for (int i = 0; i < 2; i++) { - mVtxTritTrack[i].clear(); - mVtxTritTrack[i].resize(collisions.size(), -1); - } - - for (int pn = 0; pn < 2; pn++) { - auto& vtxFirstT = mVtxTritTrack[pn]; - const auto& signedTritPool = tritPool[pn]; - for (unsigned i = 0; i < signedTritPool.size(); i++) { - const auto& t = signedTritPool[i]; - const auto& track = tracks.iteratorAt(t.Idxtr); - LOG(debug) << "Track with index: " << track.globalIndex() << " min bracket: " << t.vBracket.getMin() << " max bracket: " << t.vBracket.getMax() << " and sign: " << track.sign(); - for (int j{t.vBracket.getMin()}; j <= t.vBracket.getMax(); ++j) { - if (vtxFirstT[j] == -1) { - vtxFirstT[j] = i; - } - } - } - - auto& signedHyperPool = hyperPool[pn]; - for (unsigned itp = 0; itp < signedHyperPool.size(); itp++) { - auto& seedHyper = signedHyperPool[itp]; - LOG(debug) << "Processing hyperseed with global index " << seedHyper.Idxtr << ", bracket: " << seedHyper.vBracket.getMin() << " - " << seedHyper.vBracket.getMax() << " and sign: " << tracks.iteratorAt(seedHyper.Idxtr).sign(); - int firstKinkID = -1; - for (int j{seedHyper.vBracket.getMin()}; j <= seedHyper.vBracket.getMax(); ++j) { - LOG(debug) << "Checking vtxFirstT at position " << j << " with value " << vtxFirstT[j]; - if (vtxFirstT[j] != -1) { - firstKinkID = vtxFirstT[j]; - break; - } - } - - if (firstKinkID < 0) { - continue; - } - const auto& trackHyper = tracks.iteratorAt(seedHyper.Idxtr); - if (!trackHyper.has_collision()) - continue; - - auto const& collision = trackHyper.collision_as(); - o2::dataformats::VertexBase primaryVertex; - primaryVertex.setPos({collision.posX(), collision.posY(), collision.posZ()}); - primaryVertex.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); - - o2::track::TrackParCov trackParCovHyper = getTrackParCov(trackHyper); - o2::base::Propagator::Instance()->PropagateToXBxByBz(trackParCovHyper, LayerRadii[trackHyper.itsNCls() - 1]); - - o2::track::TrackParCov trackParCovHyperPV = getTrackParCov(trackHyper); - gpu::gpustd::array dcaInfoHyp; - o2::base::Propagator::Instance()->propagateToDCABxByBz({primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, trackParCovHyperPV, 2.f, static_cast(cfgMaterialCorrection.value), &dcaInfoHyp); - - if (abs(dcaInfoHyp[0]) > maxDCAHypToPV) { - continue; - } - - kinkCandidate kinkCand; - kinkCand.primVtx = {primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}; - // now we search for the kink daughter - - for (unsigned itn = firstKinkID; itn < signedTritPool.size(); itn++) { - auto& seedTrit = signedTritPool[itn]; - - if (seedTrit.vBracket.getMin() > seedHyper.vBracket.getMax()) { - break; - } - - if (seedTrit.vBracket.isOutside(seedHyper.vBracket)) { - LOG(debug) << "Brackets do not match"; - continue; - } - - const auto& trackTrit = tracks.iteratorAt(seedTrit.Idxtr); - LOG(debug) << "Trying to pair a triton track with global index " << seedTrit.Idxtr; - o2::track::TrackParCov trackParCovTrit = getTrackParCov(trackTrit); - - // check if the kink daughter is close to the hypertriton - if (std::abs(trackParCovHyper.getZ() - trackParCovTrit.getZ()) > maxZDiff) { - continue; - } - if ((std::abs(trackParCovHyper.getPhi() - trackParCovTrit.getPhi()) * radToDeg) > maxPhiDiff) { - continue; - } - - // propagate to PV - gpu::gpustd::array dcaInfoTrit; - o2::base::Propagator::Instance()->propagateToDCABxByBz({primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, trackParCovTrit, 2.f, static_cast(cfgMaterialCorrection.value), &dcaInfoTrit); - if (abs(dcaInfoTrit[0]) < minDCATritToPV) { - continue; - } - - int nCand = 0; - try { - nCand = fitter.process(trackParCovHyper, trackParCovTrit); - } catch (...) { - LOG(error) << "Exception caught in DCA fitter process call!"; - continue; - } - if (nCand == 0) { - continue; - } - - if (!fitter.propagateTracksToVertex()) { - continue; - } - - auto propHyperTrack = fitter.getTrack(0); - auto propTritTrack = fitter.getTrack(1); - - kinkCand.decVtx = fitter.getPCACandidatePos(); - - // cut on decay radius to 17 cm - if (kinkCand.decVtx[0] * kinkCand.decVtx[0] + kinkCand.decVtx[1] * kinkCand.decVtx[1] < 17 * 17) { - continue; - } - - propHyperTrack.getPxPyPzGlo(kinkCand.momHyp); - propTritTrack.getPxPyPzGlo(kinkCand.momTrit); - float pHyp = propHyperTrack.getP(); - float pTrit = propTritTrack.getP(); - float spKink = kinkCand.momHyp[0] * kinkCand.momTrit[0] + kinkCand.momHyp[1] * kinkCand.momTrit[1] + kinkCand.momHyp[2] * kinkCand.momTrit[2]; - kinkCand.kinkAngle = std::acos(spKink / (pHyp * pTrit)); - float angleCut = angleCutFunction(pHyp); - if (kinkCand.kinkAngle * radToDeg > angleCut) { - continue; - } - - std::array pi0mom{0.f, 0.f, 0.f}; - for (int i = 0; i < 3; i++) { - pi0mom[i] = kinkCand.momHyp[i] - kinkCand.momTrit[i]; - } - float pi0E = std::sqrt(pi0mom[0] * pi0mom[0] + pi0mom[1] * pi0mom[1] + pi0mom[2] * pi0mom[2] + pi0Mass * pi0Mass); - float tritE = std::sqrt(pTrit * pTrit + tritonMass * tritonMass); - float invMass = std::sqrt((pi0E + tritE) * (pi0E + tritE) - pHyp * pHyp); - - if (invMass < invMassLow || invMass > invMassHigh) { - continue; - } - - kinkCand.hyperTrackID = seedHyper.Idxtr; - kinkCand.hypDCAXY = dcaInfoHyp[0]; - kinkCand.clusterSizeITSHyp = trackHyper.itsClusterSizes(); - kinkCand.isMatter = trackHyper.sign() > 0; - kinkCand.tritTrackID = seedTrit.Idxtr; - kinkCand.tritDCAXY = dcaInfoTrit[0]; - kinkCand.clusterSizeITSTrit = trackTrit.itsClusterSizes(); - kinkCand.nSigmaTPCTrit = computeNSigmaTrit(trackTrit); - kinkCand.nTPCClustersTrit = trackTrit.tpcNClsFound(); - kinkCand.tpcSignalTrit = trackTrit.tpcSignal(); - kinkCand.momTritTPC = trackTrit.tpcInnerParam(); - kinkCand.dcaKinkTopo = std::sqrt(fitter.getChi2AtPCACandidate()); - kinkCand.trackingPIDTriton = trackTrit.pidForTracking(); - kinkCand.isReco = true; - mKinkCandidates.push_back(kinkCand); - } - } - } - } - - void fillMCinfo(aod::McTrackLabels const& trackLabels, aod::McParticles const&) - { - - for (auto& kinkCand : mKinkCandidates) { - auto mcLabHyper = trackLabels.rawIteratorAt(kinkCand.hyperTrackID); - auto mcLabTrit = trackLabels.rawIteratorAt(kinkCand.tritTrackID); - if (mcLabHyper.has_mcParticle() && mcLabTrit.has_mcParticle()) { - auto mcTrackHyper = mcLabHyper.mcParticle_as(); - auto mcTrackTrit = mcLabTrit.mcParticle_as(); - - if (abs(mcTrackHyper.pdgCode()) != hyperPdg || abs(mcTrackTrit.pdgCode()) != tritDauPdg) { - continue; - } - auto tritIdx = mcTrackTrit.globalIndex(); - kinkCand.isSignal = false; - for (auto& dauMCTracks : mcTrackHyper.daughters_as()) { - if (abs(dauMCTracks.pdgCode()) == tritDauPdg) { - if (dauMCTracks.globalIndex() == tritIdx) { - kinkCand.isSignal = true; - break; - } - } - } - auto primVtx = array{mcTrackHyper.vx(), mcTrackHyper.vy(), mcTrackHyper.vz()}; - auto secVtx = array{mcTrackTrit.vx(), mcTrackTrit.vy(), mcTrackTrit.vz()}; - for (int i = 0; i < 3; i++) { - kinkCand.gDecVtx[i] = secVtx[i] - primVtx[i]; - } - kinkCand.pdgCode = mcTrackHyper.pdgCode(); - kinkCand.mcMask = mcLabHyper.mcMask(); - filledMothers.push_back(mcTrackHyper.globalIndex()); - } - } - } - - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - auto run3grp_timestamp = bc.timestamp(); - - o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); - o2::parameters::GRPMagField* grpmag = 0x0; - if (grpo) { - o2::base::Propagator::initFieldFromGRP(grpo); - if (d_bz_input < -990) { - // Fetch magnetic field from ccdb for current collision - d_bz = grpo->getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; - } else { - d_bz = d_bz_input; - } - } else { - grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); - if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; - } - o2::base::Propagator::initFieldFromGRP(grpmag); - if (d_bz_input < -990) { - // Fetch magnetic field from ccdb for current collision - d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; - } else { - d_bz = d_bz_input; - } - } - if (!pidPath.value.empty()) { - auto tritpid = ccdb->getForTimeStamp>(pidPath.value + "_Trit", run3grp_timestamp); - std::copy(tritpid->begin(), tritpid->end(), mBBparamsTrit.begin()); - } else { - for (int i = 0; i < 5; i++) { - mBBparamsTrit[i] = cfgBetheBlochParams->get("Triton", Form("p%i", i)); - } - mBBparamsTrit[5] = cfgBetheBlochParams->get("Triton", "resolution"); - } - fitter.setBz(d_bz); - mRunNumber = bc.runNumber(); - - o2::base::Propagator::Instance()->setMatLUT(lut); - } - - void processData(CollisionsFull const& collisions, TracksFull const& tracks, o2::aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcWtmp) - { - - if (mBBparamsTrit[5] < 0) { - LOG(info) << "Bethe-Bloch parameters for Triton not set, using default nSigma"; - } - - mKinkCandidates.clear(); - - auto firstcollision = collisions.begin(); - auto bc1 = firstcollision.bc_as(); - initCCDB(bc1); - LOG(info) << "Processing " << collisions.size() << " collisions"; - auto pools = makeTracksPool(collisions, tracks, ambiTracks, bcWtmp); - LOG(info) << "Mother track pool created: " << pools[POS].size() << " positive and " << pools[NEG].size() << " negative seeds"; - LOG(info) << "Kink daughter track pool created: " << pools[2 + POS].size() << " positive and " << pools[2 + NEG].size() << " negative seeds"; - - fillCandidateData(collisions, tracks, ambiTracks, bcWtmp, pools); - LOG(info) << "Filled " << mKinkCandidates.size() << " kink candidates"; - for (auto& kinkCand : mKinkCandidates) { - outputDataTable(kinkCand.primVtx[0], kinkCand.primVtx[1], kinkCand.primVtx[2], - kinkCand.decVtx[0], kinkCand.decVtx[1], kinkCand.decVtx[2], - kinkCand.isMatter, kinkCand.recoPtHyp(), kinkCand.recoPhiHyp(), kinkCand.recoEtaHyp(), - kinkCand.recoPtTrit(), kinkCand.recoPhiTrit(), kinkCand.recoEtaTrit(), - kinkCand.hypDCAXY, kinkCand.tritDCAXY, kinkCand.dcaKinkTopo, - kinkCand.clusterSizeITSHyp, kinkCand.clusterSizeITSTrit, kinkCand.trackingPIDTriton, - kinkCand.momTritTPC, kinkCand.tpcSignalTrit, kinkCand.nSigmaTPCTrit, kinkCand.nSigmaTOFTrit); - } - } - PROCESS_SWITCH(hyperKinkRecoTask, processData, "Data analysis", true); - - void processMC(CollisionsFull const& collisions, TracksFull const& tracks, o2::aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcWtmp, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC) - { - filledMothers.clear(); - mKinkCandidates.clear(); - if (mBBparamsTrit[5] < 0) { - LOG(info) << "Bethe-Bloch parameters for Triton not set, using default nSigma"; - } - - auto firstcollision = collisions.begin(); - auto bc1 = firstcollision.bc_as(); - initCCDB(bc1); - LOG(info) << "Processing " << collisions.size() << " collisions"; - auto pools = makeTracksPool(collisions, tracks, ambiTracks, bcWtmp); - LOG(info) << "Mother track pool created: " << pools[POS].size() << " positive and " << pools[NEG].size() << " negative seeds"; - LOG(info) << "Kink daughter track pool created: " << pools[2 + POS].size() << " positive and " << pools[2 + NEG].size() << " negative seeds"; - - fillCandidateData(collisions, tracks, ambiTracks, bcWtmp, pools); - fillMCinfo(trackLabelsMC, particlesMC); - - // now we fill only the signal candidates that were not reconstructed - std::vector mcToKinkCandidates; - mcToKinkCandidates.resize(particlesMC.size(), -1); - - for (auto& mcPart : particlesMC) { - - if (std::abs(mcPart.pdgCode()) != hyperPdg) - continue; - std::array secVtx; - std::array primVtx = {mcPart.vx(), mcPart.vy(), mcPart.vz()}; - std::array momMother = {mcPart.px(), mcPart.py(), mcPart.pz()}; - std::array momTrit; - bool isTritFound = false; - int hyperMCIndex = mcPart.globalIndex(); - for (auto& mcDaught : mcPart.daughters_as()) { - if (std::abs(mcDaught.pdgCode()) == tritDauPdg) { - secVtx = {mcDaught.vx(), mcDaught.vy(), mcDaught.vz()}; - momTrit = {mcDaught.px(), mcDaught.py(), mcDaught.pz()}; - isTritFound = true; - break; - } - } - if (!isTritFound) { - continue; - } - - if (std::find(filledMothers.begin(), filledMothers.end(), mcPart.globalIndex()) != std::end(filledMothers)) { - continue; - } - kinkCandidate kinkCand; - kinkCand.pdgCode = mcPart.pdgCode(); - for (int i = 0; i < 3; i++) { - kinkCand.gDecVtx[i] = secVtx[i] - primVtx[i]; - kinkCand.gMomHyp[i] = momMother[i]; - kinkCand.gMomTrit[i] = momTrit[i]; - } - kinkCand.hyperTrackID = -1; - kinkCand.tritTrackID = -1; - kinkCand.isSignal = true; - mKinkCandidates.push_back(kinkCand); - mcToKinkCandidates[hyperMCIndex] = mKinkCandidates.size() - 1; - } - - // look for hypertriton or triton tracks - for (auto& track : tracks) { - auto mcLabel = trackLabelsMC.rawIteratorAt(track.globalIndex()); - if (mcLabel.has_mcParticle()) { - auto mcTrack = mcLabel.mcParticle_as(); - if (mcToKinkCandidates[mcTrack.globalIndex()] < 0 || !track.hasITS()) { - continue; - } - auto& kinkCand = mKinkCandidates[mcToKinkCandidates[mcTrack.globalIndex()]]; - kinkCand.mcMask = mcLabel.mcMask(); - kinkCand.itsPt = track.pt(); - } - } - - for (auto& kinkCand : mKinkCandidates) { - if (!kinkCand.isSignal && mcSignalOnly) { - continue; - } - int chargeFactor = -1 + 2 * (kinkCand.pdgCode > 0); - outputMCTable(kinkCand.primVtx[0], kinkCand.primVtx[1], kinkCand.primVtx[2], - kinkCand.decVtx[0], kinkCand.decVtx[1], kinkCand.decVtx[2], - kinkCand.isMatter, kinkCand.recoPtHyp(), kinkCand.recoPhiHyp(), kinkCand.recoEtaHyp(), - kinkCand.recoPtTrit(), kinkCand.recoPhiTrit(), kinkCand.recoEtaTrit(), - kinkCand.hypDCAXY, kinkCand.tritDCAXY, kinkCand.dcaKinkTopo, - kinkCand.clusterSizeITSHyp, kinkCand.clusterSizeITSTrit, kinkCand.trackingPIDTriton, - kinkCand.momTritTPC, kinkCand.tpcSignalTrit, kinkCand.nSigmaTPCTrit, kinkCand.nSigmaTOFTrit, - kinkCand.gDecVtx[0], kinkCand.gDecVtx[1], kinkCand.gDecVtx[2], - kinkCand.genPt() * chargeFactor, kinkCand.genPtTrit(), - kinkCand.isReco, kinkCand.isSignal, kinkCand.mcMask, kinkCand.itsPt); - } - } - PROCESS_SWITCH(hyperKinkRecoTask, processMC, "MC analysis", false); -}; - -WorkflowSpec - defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx b/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx index d092d3f6009..d5141f1b3e2 100644 --- a/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx @@ -11,7 +11,11 @@ // // Build hypertriton candidates from V0s and tracks +#include +#include #include +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -30,33 +34,39 @@ #include "DataFormatsParameters/GRPMagField.h" #include "CCDB/BasicCCDBManager.h" +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" + #include "Common/Core/PID/TPCPIDResponse.h" +#include "Common/Core/PID/PIDTOF.h" +#include "Common/TableProducer/PID/pidTOFBase.h" #include "DataFormatsTPC/BetheBlochAleph.h" #include "DCAFitter/DCAFitterN.h" - +#include "PWGLF/Utils/svPoolCreator.h" #include "PWGLF/DataModel/LFHypernucleiTables.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using std::array; -using TracksFull = soa::Join; -using CollisionsFull = soa::Join; -using CollisionsFullMC = soa::Join; +using CollBracket = o2::math_utils::Bracket; +using TracksFull = soa::Join; +using CollisionsFull = soa::Join; +using CollisionsFullMC = soa::Join; -using CollisionsFullWithFlow = soa::Join; +using CollisionsFullWithFlow = soa::Join; namespace { constexpr double betheBlochDefault[1][6]{{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}}; static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; -static const std::vector particleNames{"He3"}; +static const std::vector particleName{"He3"}; std::shared_ptr hEvents; +std::shared_ptr hEventsZorro; std::shared_ptr hZvtx; std::shared_ptr hCentFT0A; std::shared_ptr hCentFT0C; std::shared_ptr hCentFT0M; -std::shared_ptr hCentFV0A; std::shared_ptr hNsigma3HeSel; std::shared_ptr hDeDx3HeSel; std::shared_ptr hDeDxTot; @@ -82,8 +92,8 @@ struct hyperCandidate { float genEta() const { return std::asinh(gMom[2] / genPt()); } int v0ID; - int posTrackID; - int negTrackID; + int heTrackID; + int piTrackID; float dcaV0dau = -10; float cosPA = -10; float nSigmaHe3 = -10; @@ -99,10 +109,16 @@ struct hyperCandidate { std::array gDecVtx; uint16_t tpcSignalHe3 = 0u; uint16_t tpcSignalPi = 0u; + float tpcChi2He3 = 0.f; + float massTOFHe3 = 0.f; uint8_t nTPCClustersHe3 = 0u; uint8_t nTPCClustersPi = 0u; uint32_t clusterSizeITSHe3 = 0u; uint32_t clusterSizeITSPi = 0u; + + // collision information + unsigned int collisionID = 0; + bool isMatter = false; bool isSignal = false; // true MC signal bool isReco = false; // true if the candidate is actually reconstructed @@ -118,28 +134,43 @@ struct hyperRecoTask { Produces outputDataTableWithFlow; Produces outputMCTable; Service ccdb; + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + // PDG codes + Configurable hyperPdg{"hyperPDG", 1010010030, "PDG code of the hyper-mother (could be 3LamH or 4LamH)"}; + Configurable heDauPdg{"heDauPDG", 1000020030, "PDG code of the helium (could be 3He or 4He)"}; // Selection criteria - Configurable v0cospa{"hypcospa", 0.95, "V0 CosPA"}; + Configurable v0cospacut{"hypcospa", 0.95, "V0 CosPA"}; Configurable masswidth{"hypmasswidth", 0.06, "Mass width (GeV/c^2)"}; + Configurable dcaToPvPion{"dcapvPi", 0., "DCA to PV pion"}; + Configurable dcaToPvHe{"dcapvHe", 0., "DCA to PV helium"}; Configurable dcav0dau{"hypdcaDau", 1.0, "DCA V0 Daughters"}; Configurable ptMin{"ptMin", 0.5, "Minimum pT of the hypercandidate"}; Configurable TPCRigidityMinHe{"TPCRigidityMinHe", 0.2, "Minimum rigidity of the helium candidate"}; Configurable etaMax{"eta", 1., "eta daughter"}; Configurable nSigmaMaxHe{"nSigmaMaxHe", 5, "helium dEdx cut (n sigma)"}; - Configurable nTPCClusMinHe{"nTPCClusMinHe", 80, "helium NTPC clusters cut"}; + Configurable nTPCClusMinHe{"nTPCClusMinHe", 70, "helium NTPC clusters cut"}; + Configurable nTPCClusMinPi{"nTPCClusMinPi", -1., "pion NTPC clusters cut"}; Configurable mcSignalOnly{"mcSignalOnly", true, "If true, save only signal in MC"}; + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; + Configurable isEventUsedForEPCalibration{"isEventUsedForEPCalibration", 1, "Event is used for EP calibration"}; // Define o2 fitter, 2-prong, active memory (no need to redefine per event) o2::vertexing::DCAFitterN<2> fitter; + svPoolCreator svCreator{heDauPdg, 211}; // daughter masses float he3Mass = o2::constants::physics::MassHelium3; float he4Mass = o2::constants::physics::MassAlpha; float piMass = o2::constants::physics::MassPionCharged; - // bethe bloch parameters - Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {betheBlochDefault[0], 1, 6, particleNames, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for He3"}; + Configurable useCustomVertexer{"useCustomVertexer", false, "Use custom vertexer"}; + Configurable skipAmbiTracks{"skipAmbiTracks", false, "Skip ambiguous tracks"}; + Configurable customVertexerTimeMargin{"customVertexerTimeMargin", 800, "Time margin for custom vertexer (ns)"}; + Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {betheBlochDefault[0], 1, 6, particleName, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for He3"}; + Configurable cfgCompensatePIDinTracking{"cfgCompensatePIDinTracking", true, "If true, divide tpcInnerParam by the electric charge"}; Configurable cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Type of material correction"}; // CCDB options @@ -151,10 +182,6 @@ struct hyperRecoTask { Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; Configurable pidPath{"pidPath", "", "Path to the PID response object"}; - // PDG codes - Configurable hyperPdg{"hyperPDG", 1010010030, "PDG code of the hyper-mother (could be 3LamH or 4LamH)"}; - Configurable heDauPdg{"heDauPDG", 1000020030, "PDG code of the helium (could be 3He or 4He)"}; - // histogram axes ConfigurableAxis rigidityBins{"rigidityBins", {200, -10.f, 10.f}, "Binning for rigidity #it{p}^{TPC}/#it{z}"}; ConfigurableAxis dedxBins{"dedxBins", {1000, 0.f, 1000.f}, "Binning for dE/dx"}; @@ -167,9 +194,10 @@ struct hyperRecoTask { // vector to keep track of MC mothers already filled std::vector filledMothers; // vector to keep track of the collisions passing the event selection in the MC - std::vector isRecoCollision; + std::vector recoCollisionIds; std::vector isSurvEvSelCollision; - std::vector isTracked; + std::vector goodCollision; + std::vector trackedClSize; Preslice perCollision = o2::aod::v0::collisionId; @@ -182,6 +210,8 @@ struct hyperRecoTask { void init(InitContext const&) { + zorroSummary.setObject(zorro.getZorroSummary()); + mRunNumber = 0; d_bz = 0; @@ -200,6 +230,11 @@ struct hyperRecoTask { int mat{static_cast(cfgMaterialCorrection)}; fitter.setMatCorrType(static_cast(mat)); + svCreator.setTimeMargin(customVertexerTimeMargin); + if (skipAmbiTracks) { + svCreator.setSkipAmbiTracks(); + } + const AxisSpec rigidityAxis{rigidityBins, "#it{p}^{TPC}/#it{z}"}; const AxisSpec dedxAxis{dedxBins, "d#it{E}/d#it{x}"}; const AxisSpec nSigma3HeAxis{nSigmaBins, "n_{#sigma}({}^{3}He)"}; @@ -217,7 +252,12 @@ struct hyperRecoTask { hEvents = qaRegistry.add("hEvents", ";Events; ", HistType::kTH1D, {{2, -0.5, 1.5}}); hEvents->GetXaxis()->SetBinLabel(1, "All"); hEvents->GetXaxis()->SetBinLabel(2, "Selected"); - if (doprocessMC) { + + hEventsZorro = qaRegistry.add("hEventsZorro", ";Events; ", HistType::kTH1D, {{2, -0.5, 1.5}}); + hEventsZorro->GetXaxis()->SetBinLabel(1, "Zorro before evsel"); + hEventsZorro->GetXaxis()->SetBinLabel(2, "Zorro after evsel"); + + if (doprocessMC || doprocessMCTracked) { hDecayChannel = qaRegistry.add("hDecayChannel", ";Decay channel; ", HistType::kTH1D, {{2, -0.5, 1.5}}); hDecayChannel->GetXaxis()->SetBinLabel(1, "2-body"); hDecayChannel->GetXaxis()->SetBinLabel(2, "3-body"); @@ -232,7 +272,6 @@ struct hyperRecoTask { hCentFT0A = qaRegistry.add("hCentFT0A", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); hCentFT0C = qaRegistry.add("hCentFT0C", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); hCentFT0M = qaRegistry.add("hCentFT0M", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); - hCentFV0A = qaRegistry.add("hCentFV0A", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); } void initCCDB(aod::BCsWithTimestamps::iterator const& bc) @@ -240,6 +279,10 @@ struct hyperRecoTask { if (mRunNumber == bc.runNumber()) { return; } + if (cfgSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), "fHe"); + zorro.populateHistRegistry(qaRegistry, bc.runNumber()); + } auto run3grp_timestamp = bc.timestamp(); o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); @@ -280,192 +323,326 @@ struct hyperRecoTask { mRunNumber = bc.runNumber(); } - template - void fillCandidateData(Tcoll const& collision, aod::V0s const& V0s) + template + float computeNSigmaHe3(const T& candidate) { - if (mBBparamsHe[5] < 0) { - LOG(fatal) << "Bethe-Bloch parameters for He3 not set, please check your CCDB and configuration"; - } - for (auto& v0 : V0s) { + bool heliumPID = candidate.pidForTracking() == o2::track::PID::Helium3 || candidate.pidForTracking() == o2::track::PID::Alpha; + float correctedTPCinnerParam = (heliumPID && cfgCompensatePIDinTracking) ? candidate.tpcInnerParam() / 2.f : candidate.tpcInnerParam(); + float expTPCSignal = o2::tpc::BetheBlochAleph(static_cast(correctedTPCinnerParam * 2.f / constants::physics::MassHelium3), mBBparamsHe[0], mBBparamsHe[1], mBBparamsHe[2], mBBparamsHe[3], mBBparamsHe[4]); + double resoTPC{expTPCSignal * mBBparamsHe[5]}; + return static_cast((candidate.tpcSignal() - expTPCSignal) / resoTPC); + } - auto posTrack = v0.posTrack_as(); - auto negTrack = v0.negTrack_as(); + template + void selectGoodCollisions(const Tcoll& collisions) + { + for (const auto& collision : collisions) { + auto bc = collision.template bc_as(); + initCCDB(bc); + hEvents->Fill(0.); - if (std::abs(posTrack.eta()) > etaMax || std::abs(negTrack.eta()) > etaMax) + if (!collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { continue; + } - // temporary fix: tpcInnerParam() returns the momentum in all the software tags before: https://github.com/AliceO2Group/AliceO2/pull/12521 - bool posHeliumPID = posTrack.pidForTracking() == o2::track::PID::Helium3 || posTrack.pidForTracking() == o2::track::PID::Alpha; - bool negHeliumPID = negTrack.pidForTracking() == o2::track::PID::Helium3 || negTrack.pidForTracking() == o2::track::PID::Alpha; - float posRigidity = posHeliumPID ? posTrack.tpcInnerParam() / 2 : posTrack.tpcInnerParam(); - float negRigidity = negHeliumPID ? negTrack.tpcInnerParam() / 2 : negTrack.tpcInnerParam(); - - hDeDxTot->Fill(posRigidity, posTrack.tpcSignal()); - hDeDxTot->Fill(-negRigidity, negTrack.tpcSignal()); - - double expBethePos{tpc::BetheBlochAleph(static_cast(posRigidity * 2 / constants::physics::MassHelium3), mBBparamsHe[0], mBBparamsHe[1], mBBparamsHe[2], mBBparamsHe[3], mBBparamsHe[4])}; - double expBetheNeg{tpc::BetheBlochAleph(static_cast(negRigidity * 2 / constants::physics::MassHelium3), mBBparamsHe[0], mBBparamsHe[1], mBBparamsHe[2], mBBparamsHe[3], mBBparamsHe[4])}; - double expSigmaPos{expBethePos * mBBparamsHe[5]}; - double expSigmaNeg{expBetheNeg * mBBparamsHe[5]}; - auto nSigmaTPCpos = static_cast((posTrack.tpcSignal() - expBethePos) / expSigmaPos); - auto nSigmaTPCneg = static_cast((negTrack.tpcSignal() - expBetheNeg) / expSigmaNeg); - - // ITS only tracks do not have TPC information. TPCnSigma: only lower cut to allow for both hypertriton and hyperhydrogen4 reconstruction - bool isHe = posTrack.hasTPC() && nSigmaTPCpos > -1 * nSigmaMaxHe; - bool isAntiHe = negTrack.hasTPC() && nSigmaTPCneg > -1 * nSigmaMaxHe; + bool zorroSelected = false; + if (cfgSkimmedProcessing) { + // accounting done after ITS border cut, to properly correct with the MC + zorroSelected = zorro.isSelected(collision.template bc_as().globalBC()); + if (zorroSelected) { + hEventsZorro->Fill(0.); + } + } - if (!isHe && !isAntiHe) + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || std::abs(collision.posZ()) > 10) { continue; + } - hyperCandidate hypCand; - hypCand.v0ID = v0.globalIndex(); - hypCand.isMatter = isHe && isAntiHe ? std::abs(nSigmaTPCpos) < std::abs(nSigmaTPCneg) : isHe; - auto& he3track = hypCand.isMatter ? posTrack : negTrack; - auto& he3Rigidity = hypCand.isMatter ? posRigidity : negRigidity; - if (he3track.tpcNClsFound() < nTPCClusMinHe || he3Rigidity < TPCRigidityMinHe) - continue; + if (zorroSelected) { + hEventsZorro->Fill(1.); + } - hypCand.nSigmaHe3 = hypCand.isMatter ? nSigmaTPCpos : nSigmaTPCneg; - hypCand.nTPCClustersHe3 = hypCand.isMatter ? posTrack.tpcNClsFound() : negTrack.tpcNClsFound(); - hypCand.tpcSignalHe3 = hypCand.isMatter ? posTrack.tpcSignal() : negTrack.tpcSignal(); - hypCand.clusterSizeITSHe3 = hypCand.isMatter ? posTrack.itsClusterSizes() : negTrack.itsClusterSizes(); - hypCand.nTPCClustersPi = !hypCand.isMatter ? posTrack.tpcNClsFound() : negTrack.tpcNClsFound(); - hypCand.tpcSignalPi = !hypCand.isMatter ? posTrack.tpcSignal() : negTrack.tpcSignal(); - hypCand.clusterSizeITSPi = !hypCand.isMatter ? posTrack.itsClusterSizes() : negTrack.itsClusterSizes(); - hypCand.momHe3TPC = hypCand.isMatter ? posRigidity : negRigidity; - hypCand.momPiTPC = !hypCand.isMatter ? posRigidity : negRigidity; - - hypCand.flags |= hypCand.isMatter ? static_cast((posTrack.pidForTracking() & 0xF) << 4) : static_cast((negTrack.pidForTracking() & 0xF) << 4); - hypCand.flags |= hypCand.isMatter ? static_cast(negTrack.pidForTracking() & 0xF) : static_cast(posTrack.pidForTracking() & 0xF); - - auto posTrackCov = getTrackParCov(posTrack); - auto negTrackCov = getTrackParCov(negTrack); - - int nCand = 0; - try { - nCand = fitter.process(posTrackCov, negTrackCov); - } catch (...) { - LOG(error) << "Exception caught in DCA fitter process call!"; - continue; + goodCollision[collision.globalIndex()] = true; + hEvents->Fill(1.); + hZvtx->Fill(collision.posZ()); + hCentFT0A->Fill(collision.centFT0A()); + hCentFT0C->Fill(collision.centFT0C()); + hCentFT0M->Fill(collision.centFT0M()); + } + } + + template + void selectGoodCollisionsMC(const Tcoll& collisions) + { + for (const auto& collision : collisions) { + auto bc = collision.template bc_as(); + initCCDB(bc); + hEvents->Fill(0.); + if (collision.has_mcCollision()) { + recoCollisionIds[collision.mcCollisionId()] = collision.globalIndex(); } - if (nCand == 0) { + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || std::abs(collision.posZ()) > 10) continue; + + if (collision.has_mcCollision()) { + isSurvEvSelCollision[collision.mcCollisionId()] = true; } + goodCollision[collision.globalIndex()] = true; + hEvents->Fill(1.); + hZvtx->Fill(collision.posZ()); + hCentFT0A->Fill(collision.centFT0A()); + hCentFT0C->Fill(collision.centFT0C()); + hCentFT0M->Fill(collision.centFT0M()); + } + } - auto& hePropTrack = hypCand.isMatter ? fitter.getTrack(0) : fitter.getTrack(1); - auto& piPropTrack = hypCand.isMatter ? fitter.getTrack(1) : fitter.getTrack(0); - hePropTrack.getPxPyPzGlo(hypCand.momHe3); - piPropTrack.getPxPyPzGlo(hypCand.momPi); + template + void fillHyperCand(Ttrack& heTrack, Ttrack& piTrack, CollBracket collBracket, const Tcolls& collisions, hyperCandidate& hypCand) + { - // the momentum has to be multiplied by 2 (charge) - for (int i = 0; i < 3; i++) { - hypCand.momHe3[i] *= 2; - } + hypCand.isMatter = heTrack.sign() > 0; + hypCand.nSigmaHe3 = computeNSigmaHe3(heTrack); + hypCand.nTPCClustersHe3 = heTrack.tpcNClsFound(); + hypCand.tpcSignalHe3 = heTrack.tpcSignal(); + hypCand.clusterSizeITSHe3 = heTrack.itsClusterSizes(); + hypCand.nTPCClustersPi = piTrack.tpcNClsFound(); + hypCand.tpcSignalPi = piTrack.tpcSignal(); + hypCand.tpcChi2He3 = heTrack.tpcChi2NCl(); + hypCand.clusterSizeITSPi = piTrack.itsClusterSizes(); + bool heliumPID = heTrack.pidForTracking() == o2::track::PID::Helium3 || heTrack.pidForTracking() == o2::track::PID::Alpha; + hypCand.momHe3TPC = (heliumPID && cfgCompensatePIDinTracking) ? heTrack.tpcInnerParam() / 2 : heTrack.tpcInnerParam(); + if (hypCand.momHe3TPC < TPCRigidityMinHe) + return; + hypCand.momPiTPC = piTrack.tpcInnerParam(); + hDeDxTot->Fill(hypCand.momHe3TPC * heTrack.sign(), heTrack.tpcSignal()); + hDeDxTot->Fill(hypCand.momPiTPC * piTrack.sign(), piTrack.tpcSignal()); + hypCand.flags |= static_cast((heTrack.pidForTracking() & 0xF) << 4); + hypCand.flags |= static_cast(piTrack.pidForTracking() & 0xF); + auto heTrackCov = getTrackParCov(heTrack); + auto piTrackCov = getTrackParCov(piTrack); + + int nCand = 0; + try { + nCand = fitter.process(heTrackCov, piTrackCov); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call!"; + return; + } + if (nCand == 0) { + return; + } - float heP2 = hypCand.momHe3[0] * hypCand.momHe3[0] + hypCand.momHe3[1] * hypCand.momHe3[1] + hypCand.momHe3[2] * hypCand.momHe3[2]; - float piP2 = hypCand.momPi[0] * hypCand.momPi[0] + hypCand.momPi[1] * hypCand.momPi[1] + hypCand.momPi[2] * hypCand.momPi[2]; - float he3E = std::sqrt(heP2 + he3Mass * he3Mass); - float he4E = std::sqrt(heP2 + he4Mass * he4Mass); - float piE = std::sqrt(piP2 + piMass * piMass); - float h3lE = he3E + piE; - float h4lE = he4E + piE; + auto& hePropTrack = fitter.getTrack(0); + auto& piPropTrack = fitter.getTrack(1); + hePropTrack.getPxPyPzGlo(hypCand.momHe3); + piPropTrack.getPxPyPzGlo(hypCand.momPi); + // the momentum has to be multiplied by 2 (charge) + for (int i = 0; i < 3; i++) { + hypCand.momHe3[i] *= 2; + } + float heP2 = hypCand.momHe3[0] * hypCand.momHe3[0] + hypCand.momHe3[1] * hypCand.momHe3[1] + hypCand.momHe3[2] * hypCand.momHe3[2]; + float piP2 = hypCand.momPi[0] * hypCand.momPi[0] + hypCand.momPi[1] * hypCand.momPi[1] + hypCand.momPi[2] * hypCand.momPi[2]; + float he3E = std::sqrt(heP2 + he3Mass * he3Mass); + float he4E = std::sqrt(heP2 + he4Mass * he4Mass); + float piE = std::sqrt(piP2 + piMass * piMass); + float h3lE = he3E + piE; + float h4lE = he4E + piE; + std::array hypMom; + const auto& vtx = fitter.getPCACandidate(); + for (int i = 0; i < 3; i++) { + hypCand.decVtx[i] = vtx[i]; + hypMom[i] = hypCand.momHe3[i] + hypCand.momPi[i]; + } + float hypPt = std::hypot(hypMom[0], hypMom[1]); + if (hypPt < ptMin) + return; + float massH3L = std::sqrt(h3lE * h3lE - hypMom[0] * hypMom[0] - hypMom[1] * hypMom[1] - hypMom[2] * hypMom[2]); + float massH4L = std::sqrt(h4lE * h4lE - hypMom[0] * hypMom[0] - hypMom[1] * hypMom[1] - hypMom[2] * hypMom[2]); + bool isHypMass = false; + if (massH3L > o2::constants::physics::MassHyperTriton - masswidth && massH3L < o2::constants::physics::MassHyperTriton + masswidth) + isHypMass = true; + if (massH4L > o2::constants::physics::MassHyperhydrog4 - masswidth && massH4L < o2::constants::physics::MassHyperhydrog4 + masswidth) + isHypMass = true; + if (!isHypMass) + return; - std::array hypMom; - const auto& vtx = fitter.getPCACandidate(); - for (int i = 0; i < 3; i++) { - hypCand.decVtx[i] = vtx[i]; - hypMom[i] = hypCand.momHe3[i] + hypCand.momPi[i]; + hH3LMassBefSel->Fill(massH3L); + hH4LMassBefSel->Fill(massH4L); + if (!trackedClSize.empty() && trackedClSize[hypCand.v0ID] > 0) { + hH3LMassTracked->Fill(massH3L); + hH4LMassTracked->Fill(massH4L); + } + + hypCand.dcaV0dau = std::sqrt(fitter.getChi2AtPCACandidate()); + if (hypCand.dcaV0dau > dcav0dau) { + return; + } + + // select the collision that maximizes the cosine of the pointing angle + double cosPAmax = -2; + unsigned int collIDmax = 0; + + for (int collID = collBracket.getMin(); collID <= collBracket.getMax(); collID++) { + auto collision = collisions.rawIteratorAt(collID); + std::array collVtx = {collision.posX(), collision.posY(), collision.posZ()}; + double cosPA = RecoDecay::cpa(collVtx, hypCand.decVtx, hypMom); + if (cosPA > cosPAmax) { + cosPAmax = cosPA; + collIDmax = collID; } + } - float hypPt = std::hypot(hypMom[0], hypMom[1]); - if (hypPt < ptMin) - continue; + if (!goodCollision[collIDmax]) { + return; + } + + if (cosPAmax < v0cospacut) { + return; + } + + auto collision = collisions.rawIteratorAt(collIDmax); + std::array primVtx = {collision.posX(), collision.posY(), collision.posZ()}; + for (int i = 0; i < 3; i++) { + hypCand.decVtx[i] = hypCand.decVtx[i] - primVtx[i]; + } + + // if survived all selections, propagate decay daughters to PV + gpu::gpustd::array dcaInfo; + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, heTrackCov, 2.f, fitter.getMatCorrType(), &dcaInfo); + hypCand.he3DCAXY = dcaInfo[0]; + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, piTrackCov, 2.f, fitter.getMatCorrType(), &dcaInfo); + hypCand.piDCAXY = dcaInfo[0]; + + if (std::abs(hypCand.piDCAXY) < dcaToPvPion || std::abs(hypCand.he3DCAXY) < dcaToPvHe) { + return; + } - float massH3L = std::sqrt(h3lE * h3lE - hypMom[0] * hypMom[0] - hypMom[1] * hypMom[1] - hypMom[2] * hypMom[2]); - float massH4L = std::sqrt(h4lE * h4lE - hypMom[0] * hypMom[0] - hypMom[1] * hypMom[1] - hypMom[2] * hypMom[2]); - bool isHypMass = false; - if (massH3L > o2::constants::physics::MassHyperTriton - masswidth && massH3L < o2::constants::physics::MassHyperTriton + masswidth) - isHypMass = true; - if (massH4L > o2::constants::physics::MassHyperhydrog4 - masswidth && massH4L < o2::constants::physics::MassHyperhydrog4 + masswidth) - isHypMass = true; - if (!isHypMass) + // finally, fill collision info and push back the candidate + hypCand.isReco = true; + hypCand.heTrackID = heTrack.globalIndex(); + hypCand.piTrackID = piTrack.globalIndex(); + hypCand.collisionID = collision.globalIndex(); + + if (heTrack.hasTOF()) { + float beta = o2::pid::tof::Beta::GetBeta(heTrack); + beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked + hypCand.massTOFHe3 = hypCand.momHe3TPC * 2.f * std::sqrt(1.f / (beta * beta) - 1.f); + } + + hDeDx3HeSel->Fill(heTrack.sign() * hypCand.momHe3TPC, heTrack.tpcSignal()); + hNsigma3HeSel->Fill(heTrack.sign() * hypCand.momHe3TPC, hypCand.nSigmaHe3); + hyperCandidates.push_back(hypCand); + } + + template + void fillV0s(const Tcolls& collisions, const Ttracks& tracks, aod::V0s const& V0s) + { + if (mBBparamsHe[5] < 0) { + LOG(fatal) << "Bethe-Bloch parameters for He3 not set, please check your CCDB and configuration"; + } + for (auto& v0 : V0s) { + // if(v0.isStandardV0()) + // continue; + auto posTrack = tracks.rawIteratorAt(v0.posTrackId()); + auto negTrack = tracks.rawIteratorAt(v0.negTrackId()); + + if (std::abs(posTrack.eta()) > etaMax || std::abs(negTrack.eta()) > etaMax) continue; - hH3LMassBefSel->Fill(massH3L); - hH4LMassBefSel->Fill(massH4L); - if (!isTracked.empty() && isTracked[hypCand.v0ID]) { - hH3LMassTracked->Fill(massH3L); - hH4LMassTracked->Fill(massH4L); + // temporary fix: tpcInnerParam() returns the momentum in all the software tags before: https://github.com/AliceO2Group/AliceO2/pull/12521 + auto nSigmaTPCpos = computeNSigmaHe3(posTrack); + auto nSigmaTPCneg = computeNSigmaHe3(negTrack); + // ITS only tracks do not have TPC information. TPCnSigma: only lower cut to allow for both hypertriton and hyperhydrogen4 reconstruction + bool isHe = posTrack.hasTPC() && nSigmaTPCpos > -1 * nSigmaMaxHe; + bool isAntiHe = negTrack.hasTPC() && nSigmaTPCneg > -1 * nSigmaMaxHe; + if (!isHe && !isAntiHe) { + continue; } - - hypCand.dcaV0dau = std::sqrt(fitter.getChi2AtPCACandidate()); - if (hypCand.dcaV0dau > dcav0dau) { + auto& heTrack = isHe ? posTrack : negTrack; + auto& piTrack = isHe ? negTrack : posTrack; + if (heTrack.tpcNClsFound() < nTPCClusMinHe || piTrack.tpcNClsFound() < nTPCClusMinPi) { continue; } - std::array primVtx = {collision.posX(), collision.posY(), collision.posZ()}; + hyperCandidate hypCand; + hypCand.v0ID = v0.globalIndex(); - double cosPA = RecoDecay::cpa(primVtx, hypCand.decVtx, hypMom); - if (cosPA < v0cospa) { - continue; - } + int collIdx = v0.collision_as().globalIndex(); + CollBracket collBracket{collIdx, collIdx}; - for (int i = 0; i < 3; i++) { - hypCand.decVtx[i] = hypCand.decVtx[i] - primVtx[i]; - } + fillHyperCand(heTrack, piTrack, collBracket, collisions, hypCand); + } + } - // if survived all selections, propagate decay daughters to PV - gpu::gpustd::array dcaInfo; + template + void fillCustomV0s(const Tcolls& collisions, const Ttracks& tracks, aod::AmbiguousTracks const& ambiguousTracks, aod::BCsWithTimestamps const& bcs) + { - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, posTrackCov, 2.f, fitter.getMatCorrType(), &dcaInfo); - hypCand.isMatter ? hypCand.he3DCAXY = dcaInfo[0] : hypCand.piDCAXY = dcaInfo[0]; + svCreator.clearPools(); + svCreator.fillBC2Coll(collisions, bcs); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, negTrackCov, 2.f, fitter.getMatCorrType(), &dcaInfo); - hypCand.isMatter ? hypCand.piDCAXY = dcaInfo[0] : hypCand.he3DCAXY = dcaInfo[0]; + for (auto& track : tracks) { - // finally, push back the candidate - hypCand.isReco = true; - hypCand.posTrackID = posTrack.globalIndex(); - hypCand.negTrackID = negTrack.globalIndex(); + if (std::abs(track.eta()) > etaMax) + continue; - int chargeFactor = -1 + 2 * hypCand.isMatter; - hDeDx3HeSel->Fill(chargeFactor * hypCand.momHe3TPC, he3track.tpcSignal()); - hNsigma3HeSel->Fill(chargeFactor * hypCand.momHe3TPC, hypCand.nSigmaHe3); - hyperCandidates.push_back(hypCand); + if (!track.hasITS()) + continue; + + auto nSigmaHe = computeNSigmaHe3(track); + bool isHe = nSigmaHe > -1 * nSigmaMaxHe; + int pdgHypo = isHe ? heDauPdg : 211; + // LOG(info) << "ncls found: " << track.tpcNClsFound(); + if (isHe && track.tpcNClsFound() < nTPCClusMinHe) + continue; + if (!isHe && track.tpcNClsFound() < nTPCClusMinPi) + continue; + + svCreator.appendTrackCand(track, collisions, pdgHypo, ambiguousTracks, bcs); } - } + auto& svPool = svCreator.getSVCandPool(collisions); + LOG(debug) << "SV pool size: " << svPool.size(); + for (auto& svCand : svPool) { + auto heTrack = tracks.rawIteratorAt(svCand.tr0Idx); + auto piTrack = tracks.rawIteratorAt(svCand.tr1Idx); + auto collIdxs = svCand.collBracket; + hyperCandidate hypCand; + hypCand.v0ID = -1; + fillHyperCand(heTrack, piTrack, collIdxs, collisions, hypCand); + } + } void fillMCinfo(aod::McTrackLabels const& trackLabels, aod::McParticles const&) { for (auto& hypCand : hyperCandidates) { - auto mcLabPos = trackLabels.rawIteratorAt(hypCand.posTrackID); - auto mcLabNeg = trackLabels.rawIteratorAt(hypCand.negTrackID); - - if (mcLabPos.has_mcParticle() && mcLabNeg.has_mcParticle()) { - auto mcTrackPos = mcLabPos.mcParticle_as(); - auto mcTrackNeg = mcLabNeg.mcParticle_as(); - if (mcTrackPos.has_mothers() && mcTrackNeg.has_mothers()) { - for (auto& negMother : mcTrackNeg.mothers_as()) { - for (auto& posMother : mcTrackPos.mothers_as()) { - if (posMother.globalIndex() != negMother.globalIndex()) + auto mcLabHe = trackLabels.rawIteratorAt(hypCand.heTrackID); + auto mcLabPi = trackLabels.rawIteratorAt(hypCand.piTrackID); + + if (mcLabHe.has_mcParticle() && mcLabPi.has_mcParticle()) { + auto mcTrackHe = mcLabHe.mcParticle_as(); + auto mcTrackPi = mcLabPi.mcParticle_as(); + if (mcTrackHe.has_mothers() && mcTrackPi.has_mothers()) { + for (auto& heMother : mcTrackHe.mothers_as()) { + for (auto& piMother : mcTrackPi.mothers_as()) { + if (heMother.globalIndex() != piMother.globalIndex()) continue; - if (!((mcTrackPos.pdgCode() == heDauPdg && mcTrackNeg.pdgCode() == -211) || (mcTrackPos.pdgCode() == 211 && mcTrackNeg.pdgCode() == -1 * heDauPdg))) // TODO: check warning for constant comparison + if (std::abs(mcTrackHe.pdgCode()) != heDauPdg || std::abs(mcTrackPi.pdgCode()) != 211) continue; - if (std::abs(posMother.pdgCode()) != hyperPdg) + if (std::abs(heMother.pdgCode()) != hyperPdg) continue; - auto posPrimVtx = array{posMother.vx(), posMother.vy(), posMother.vz()}; - auto secVtx = array{mcTrackPos.vx(), mcTrackPos.vy(), mcTrackPos.vz()}; - hypCand.gMom = array{posMother.px(), posMother.py(), posMother.pz()}; - hypCand.gMomHe3 = mcTrackPos.pdgCode() == heDauPdg ? array{mcTrackPos.px(), mcTrackPos.py(), mcTrackPos.pz()} : array{mcTrackNeg.px(), mcTrackNeg.py(), mcTrackNeg.pz()}; + auto primVtx = array{heMother.vx(), heMother.vy(), heMother.vz()}; + auto secVtx = array{mcTrackHe.vx(), mcTrackHe.vy(), mcTrackHe.vz()}; + hypCand.gMom = array{heMother.px(), heMother.py(), heMother.pz()}; + hypCand.gMomHe3 = array{mcTrackHe.px(), mcTrackHe.py(), mcTrackHe.pz()}; for (int i = 0; i < 3; i++) { - hypCand.gDecVtx[i] = secVtx[i] - posPrimVtx[i]; + hypCand.gDecVtx[i] = secVtx[i] - primVtx[i]; } hypCand.isSignal = true; - hypCand.pdgCode = posMother.pdgCode(); - hypCand.isRecoMCCollision = isRecoCollision[posMother.mcCollisionId()]; - hypCand.isSurvEvSelection = isSurvEvSelCollision[posMother.mcCollisionId()]; - filledMothers.push_back(posMother.globalIndex()); + hypCand.pdgCode = heMother.pdgCode(); + hypCand.isRecoMCCollision = recoCollisionIds[heMother.mcCollisionId()] > 0; + hypCand.isSurvEvSelection = isSurvEvSelCollision[heMother.mcCollisionId()]; + filledMothers.push_back(heMother.globalIndex()); } } } @@ -473,157 +650,112 @@ struct hyperRecoTask { } } - void processDataTracked(CollisionsFull const& collisions, aod::V0s const& V0s, aod::TrackedV0s const& tV0s, TracksFull const& tracks, aod::BCsWithTimestamps const& bcs) + void processDataTracked(CollisionsFull const& collisions, aod::V0s const& V0s, aod::TrackedV0s const& tV0s, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs) { - isTracked.clear(); - isTracked.resize(V0s.size(), false); + trackedClSize.clear(); + trackedClSize.resize(V0s.size(), 0); for (const auto& tV0 : tV0s) { - isTracked[tV0.v0Id()] = true; + trackedClSize[tV0.v0Id()] = tV0.itsClsSize(); } - processData(collisions, V0s, tracks, bcs); + processData(collisions, V0s, tracks, ambiTracks, bcs); } PROCESS_SWITCH(hyperRecoTask, processDataTracked, "Data analysis wit tracked V0s information", false); - void processData(CollisionsFull const& collisions, aod::V0s const& V0s, TracksFull const& tracks, aod::BCsWithTimestamps const&) + void processData(CollisionsFull const& collisions, aod::V0s const& V0s, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs) { - for (const auto& collision : collisions) { - hyperCandidates.clear(); + goodCollision.clear(); + goodCollision.resize(collisions.size(), false); + hyperCandidates.clear(); - auto bc = collision.bc_as(); - initCCDB(bc); + selectGoodCollisions(collisions); + useCustomVertexer ? fillCustomV0s(collisions, tracks, ambiTracks, bcs) : fillV0s(collisions, tracks, V0s); - hEvents->Fill(0.); - if (!collision.sel8() || std::abs(collision.posZ()) > 10) - continue; - hEvents->Fill(1.); - hZvtx->Fill(collision.posZ()); - hCentFT0A->Fill(collision.centFT0A()); - hCentFT0C->Fill(collision.centFT0C()); - hCentFT0M->Fill(collision.centFT0M()); - hCentFV0A->Fill(collision.centFV0A()); - - const uint64_t collIdx = collision.globalIndex(); - auto V0Table_thisCollision = V0s.sliceBy(perCollision, collIdx); - V0Table_thisCollision.bindExternalIndices(&tracks); - - fillCandidateData(collision, V0Table_thisCollision); - - for (auto& hypCand : hyperCandidates) { - outputDataTable(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), - collision.posX(), collision.posY(), collision.posZ(), - hypCand.isMatter, - hypCand.recoPtHe3(), hypCand.recoPhiHe3(), hypCand.recoEtaHe3(), - hypCand.recoPtPi(), hypCand.recoPhiPi(), hypCand.recoEtaPi(), - hypCand.decVtx[0], hypCand.decVtx[1], hypCand.decVtx[2], - hypCand.dcaV0dau, hypCand.he3DCAXY, hypCand.piDCAXY, - hypCand.nSigmaHe3, hypCand.nTPCClustersHe3, hypCand.nTPCClustersPi, - hypCand.momHe3TPC, hypCand.momPiTPC, hypCand.tpcSignalHe3, hypCand.tpcSignalPi, - hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, !isTracked.empty() && isTracked[hypCand.v0ID]); - } + for (auto& hypCand : hyperCandidates) { + auto collision = collisions.rawIteratorAt(hypCand.collisionID); + float trackedHypClSize = !trackedClSize.empty() ? trackedClSize[hypCand.v0ID] : 0; + outputDataTable(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + collision.posX(), collision.posY(), collision.posZ(), + hypCand.isMatter, + hypCand.recoPtHe3(), hypCand.recoPhiHe3(), hypCand.recoEtaHe3(), + hypCand.recoPtPi(), hypCand.recoPhiPi(), hypCand.recoEtaPi(), + hypCand.decVtx[0], hypCand.decVtx[1], hypCand.decVtx[2], + hypCand.dcaV0dau, hypCand.he3DCAXY, hypCand.piDCAXY, + hypCand.nSigmaHe3, hypCand.nTPCClustersHe3, hypCand.nTPCClustersPi, + hypCand.momHe3TPC, hypCand.momPiTPC, hypCand.tpcSignalHe3, hypCand.tpcSignalPi, hypCand.tpcChi2He3, + hypCand.massTOFHe3, + hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, trackedHypClSize); } } PROCESS_SWITCH(hyperRecoTask, processData, "Data analysis", true); - void processDataWithFlow(CollisionsFullWithFlow const& collisions, aod::V0s const& V0s, TracksFull const& tracks, aod::BCsWithTimestamps const&) + void processDataWithFlow(CollisionsFullWithFlow const& collisions, aod::V0s const& V0s, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs) { - for (const auto& collision : collisions) { - hyperCandidates.clear(); + goodCollision.clear(); + goodCollision.resize(collisions.size(), false); + hyperCandidates.clear(); - auto bc = collision.bc_as(); - initCCDB(bc); + selectGoodCollisions(collisions); + useCustomVertexer ? fillCustomV0s(collisions, tracks, ambiTracks, bcs) : fillV0s(collisions, tracks, V0s); - hEvents->Fill(0.); - if (!collision.sel8() || std::abs(collision.posZ()) > 10) - continue; - hEvents->Fill(1.); - hZvtx->Fill(collision.posZ()); - hCentFT0A->Fill(collision.centFT0A()); - hCentFT0C->Fill(collision.centFT0C()); - hCentFT0M->Fill(collision.centFT0M()); - hCentFV0A->Fill(collision.centFV0A()); - - const uint64_t collIdx = collision.globalIndex(); - auto V0Table_thisCollision = V0s.sliceBy(perCollision, collIdx); - V0Table_thisCollision.bindExternalIndices(&tracks); - - fillCandidateData(collision, V0Table_thisCollision); - - for (auto& hypCand : hyperCandidates) { - outputDataTableWithFlow(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), - collision.psiFT0A(), collision.multFT0A(), - collision.psiFT0C(), collision.multFT0C(), - collision.psiTPC(), collision.multTPC(), - collision.posX(), collision.posY(), collision.posZ(), - hypCand.isMatter, - hypCand.recoPtHe3(), hypCand.recoPhiHe3(), hypCand.recoEtaHe3(), - hypCand.recoPtPi(), hypCand.recoPhiPi(), hypCand.recoEtaPi(), - hypCand.decVtx[0], hypCand.decVtx[1], hypCand.decVtx[2], - hypCand.dcaV0dau, hypCand.he3DCAXY, hypCand.piDCAXY, - hypCand.nSigmaHe3, hypCand.nTPCClustersHe3, hypCand.nTPCClustersPi, - hypCand.momHe3TPC, hypCand.momPiTPC, hypCand.tpcSignalHe3, hypCand.tpcSignalPi, - hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, !isTracked.empty() && isTracked[hypCand.v0ID]); + for (auto& hypCand : hyperCandidates) { + auto collision = collisions.rawIteratorAt(hypCand.collisionID); + if (isEventUsedForEPCalibration && !collision.triggereventep()) { + return; } + float trackedHypClSize = !trackedClSize.empty() ? trackedClSize[hypCand.v0ID] : 0; + outputDataTableWithFlow(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + collision.psiFT0A(), collision.multFT0A(), + collision.psiFT0C(), collision.multFT0C(), collision.qFT0C(), + collision.psiTPC(), collision.multTPC(), + collision.posX(), collision.posY(), collision.posZ(), + hypCand.isMatter, + hypCand.recoPtHe3(), hypCand.recoPhiHe3(), hypCand.recoEtaHe3(), + hypCand.recoPtPi(), hypCand.recoPhiPi(), hypCand.recoEtaPi(), + hypCand.decVtx[0], hypCand.decVtx[1], hypCand.decVtx[2], + hypCand.dcaV0dau, hypCand.he3DCAXY, hypCand.piDCAXY, + hypCand.nSigmaHe3, hypCand.nTPCClustersHe3, hypCand.nTPCClustersPi, + hypCand.momHe3TPC, hypCand.momPiTPC, hypCand.tpcSignalHe3, hypCand.tpcSignalPi, hypCand.tpcChi2He3, + hypCand.massTOFHe3, + hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, trackedHypClSize); } } PROCESS_SWITCH(hyperRecoTask, processDataWithFlow, "Data analysis with flow", false); - void processMC(CollisionsFullMC const& collisions, aod::McCollisions const& mcCollisions, aod::V0s const& V0s, TracksFull const& tracks, aod::BCsWithTimestamps const&, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC) + void processMC(CollisionsFullMC const& collisions, aod::McCollisions const& mcCollisions, aod::V0s const& V0s, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC) { filledMothers.clear(); - isRecoCollision.clear(); + recoCollisionIds.clear(); + recoCollisionIds.resize(mcCollisions.size(), -1); isSurvEvSelCollision.clear(); - isRecoCollision.resize(mcCollisions.size(), false); isSurvEvSelCollision.resize(mcCollisions.size(), false); + goodCollision.clear(); + goodCollision.resize(collisions.size(), false); + hyperCandidates.clear(); - for (const auto& collision : collisions) { - hyperCandidates.clear(); - auto bc = collision.bc_as(); - initCCDB(bc); - hEvents->Fill(0.); - - if (collision.has_mcCollision()) { - isRecoCollision[collision.mcCollisionId()] = true; - } - - if (!collision.sel8() || std::abs(collision.posZ()) > 10) + selectGoodCollisionsMC(collisions); + useCustomVertexer ? fillCustomV0s(collisions, tracks, ambiTracks, bcs) : fillV0s(collisions, tracks, V0s); + fillMCinfo(trackLabelsMC, particlesMC); + for (auto& hypCand : hyperCandidates) { + auto collision = collisions.rawIteratorAt(hypCand.collisionID); + if (!hypCand.isSignal && mcSignalOnly) continue; - hEvents->Fill(1.); - hZvtx->Fill(collision.posZ()); - hCentFT0A->Fill(collision.centFT0A()); - hCentFT0C->Fill(collision.centFT0C()); - hCentFT0M->Fill(collision.centFT0M()); - hCentFV0A->Fill(collision.centFV0A()); - - if (collision.has_mcCollision()) { - isSurvEvSelCollision[collision.mcCollisionId()] = true; - } - - const uint64_t collIdx = collision.globalIndex(); - auto V0Table_thisCollision = V0s.sliceBy(perCollision, collIdx); - V0Table_thisCollision.bindExternalIndices(&tracks); - - fillCandidateData(collision, V0Table_thisCollision); - fillMCinfo(trackLabelsMC, particlesMC); - - for (auto& hypCand : hyperCandidates) { - if (!hypCand.isSignal && mcSignalOnly) - continue; - int chargeFactor = -1 + 2 * (hypCand.pdgCode > 0); - outputMCTable(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), - collision.posX(), collision.posY(), collision.posZ(), - hypCand.isMatter, - hypCand.recoPtHe3(), hypCand.recoPhiHe3(), hypCand.recoEtaHe3(), - hypCand.recoPtPi(), hypCand.recoPhiPi(), hypCand.recoEtaPi(), - hypCand.decVtx[0], hypCand.decVtx[1], hypCand.decVtx[2], - hypCand.dcaV0dau, hypCand.he3DCAXY, hypCand.piDCAXY, - hypCand.nSigmaHe3, hypCand.nTPCClustersHe3, hypCand.nTPCClustersPi, - hypCand.momHe3TPC, hypCand.momPiTPC, hypCand.tpcSignalHe3, hypCand.tpcSignalPi, - hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, !isTracked.empty() && isTracked[hypCand.v0ID], - chargeFactor * hypCand.genPt(), hypCand.genPhi(), hypCand.genEta(), hypCand.genPtHe3(), - hypCand.gDecVtx[0], hypCand.gDecVtx[1], hypCand.gDecVtx[2], - hypCand.isReco, hypCand.isSignal, hypCand.isRecoMCCollision, hypCand.isSurvEvSelection); - } + int chargeFactor = -1 + 2 * (hypCand.pdgCode > 0); + float trackedHypClSize = !trackedClSize.empty() ? trackedClSize[hypCand.v0ID] : 0; + outputMCTable(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + collision.posX(), collision.posY(), collision.posZ(), + hypCand.isMatter, + hypCand.recoPtHe3(), hypCand.recoPhiHe3(), hypCand.recoEtaHe3(), + hypCand.recoPtPi(), hypCand.recoPhiPi(), hypCand.recoEtaPi(), + hypCand.decVtx[0], hypCand.decVtx[1], hypCand.decVtx[2], + hypCand.dcaV0dau, hypCand.he3DCAXY, hypCand.piDCAXY, + hypCand.nSigmaHe3, hypCand.nTPCClustersHe3, hypCand.nTPCClustersPi, + hypCand.momHe3TPC, hypCand.momPiTPC, hypCand.tpcSignalHe3, hypCand.tpcSignalPi, hypCand.tpcChi2He3, + hypCand.massTOFHe3, + hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, trackedHypClSize, + chargeFactor * hypCand.genPt(), hypCand.genPhi(), hypCand.genEta(), hypCand.genPtHe3(), + hypCand.gDecVtx[0], hypCand.gDecVtx[1], hypCand.gDecVtx[2], + hypCand.isReco, hypCand.isSignal, hypCand.isRecoMCCollision, hypCand.isSurvEvSelection); } // now we fill only the signal candidates that were not reconstructed @@ -664,7 +796,7 @@ struct hyperRecoTask { } hyperCandidate hypCand; hypCand.pdgCode = mcPart.pdgCode(); - hypCand.isRecoMCCollision = isRecoCollision[mcPart.mcCollisionId()]; + hypCand.isRecoMCCollision = recoCollisionIds[mcPart.mcCollisionId()] > 0; hypCand.isSurvEvSelection = isSurvEvSelCollision[mcPart.mcCollisionId()]; int chargeFactor = -1 + 2 * (hypCand.pdgCode > 0); for (int i = 0; i < 3; i++) { @@ -672,10 +804,19 @@ struct hyperRecoTask { hypCand.gMom[i] = momMother[i]; hypCand.gMomHe3[i] = momHe3[i]; } - hypCand.posTrackID = -1; - hypCand.negTrackID = -1; + hypCand.heTrackID = -1; + hypCand.piTrackID = -1; hypCand.isSignal = true; - outputMCTable(-1, -1, -1, + + float centFT0A = -1, centFT0C = -1, centFT0M = -1; + if (hypCand.isRecoMCCollision) { + auto recoCollision = collisions.rawIteratorAt(recoCollisionIds[mcPart.mcCollisionId()]); + centFT0A = recoCollision.centFT0A(); + centFT0C = recoCollision.centFT0C(); + centFT0M = recoCollision.centFT0M(); + } + + outputMCTable(centFT0A, centFT0C, centFT0M, -1, -1, -1, 0, -1, -1, -1, @@ -683,7 +824,7 @@ struct hyperRecoTask { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, false, chargeFactor * hypCand.genPt(), hypCand.genPhi(), hypCand.genEta(), hypCand.genPtHe3(), hypCand.gDecVtx[0], hypCand.gDecVtx[1], hypCand.gDecVtx[2], @@ -692,14 +833,14 @@ struct hyperRecoTask { } PROCESS_SWITCH(hyperRecoTask, processMC, "MC analysis", false); - void processMCTracked(CollisionsFullMC const& collisions, aod::McCollisions const& mcCollisions, aod::V0s const& V0s, aod::TrackedV0s const& tV0s, TracksFull const& tracks, aod::BCsWithTimestamps const& bcs, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC) + void processMCTracked(CollisionsFullMC const& collisions, aod::McCollisions const& mcCollisions, aod::V0s const& V0s, aod::TrackedV0s const& tV0s, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC) { - isTracked.clear(); - isTracked.resize(V0s.size(), false); + trackedClSize.clear(); + trackedClSize.resize(V0s.size(), 0); for (const auto& tV0 : tV0s) { - isTracked[tV0.v0Id()] = true; + trackedClSize[tV0.v0Id()] = tV0.itsClsSize(); } - processMC(collisions, mcCollisions, V0s, tracks, bcs, trackLabelsMC, particlesMC); + processMC(collisions, mcCollisions, V0s, tracks, ambiTracks, bcs, trackLabelsMC, particlesMC); } PROCESS_SWITCH(hyperRecoTask, processMCTracked, "MC analysis with tracked V0s", false); }; diff --git a/PWGLF/TableProducer/Nuspex/hypertriton3bodyfinder.cxx b/PWGLF/TableProducer/Nuspex/hypertriton3bodyfinder.cxx index 2b1f065750e..40019d82533 100644 --- a/PWGLF/TableProducer/Nuspex/hypertriton3bodyfinder.cxx +++ b/PWGLF/TableProducer/Nuspex/hypertriton3bodyfinder.cxx @@ -687,14 +687,17 @@ struct hypertriton3bodyFinder { auto Track0Par = getTrackPar(dPtrack); o2::base::Propagator::Instance()->propagateToDCABxByBz({dCollision.posX(), dCollision.posY(), dCollision.posZ()}, Track0Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); auto Track0dcaXY = dcaInfo[0]; + auto Track0dca = std::sqrt(Track0dcaXY * Track0dcaXY + dcaInfo[1] * dcaInfo[1]); auto Track1Par = getTrackPar(dNtrack); o2::base::Propagator::Instance()->propagateToDCABxByBz({dCollision.posX(), dCollision.posY(), dCollision.posZ()}, Track1Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); auto Track1dcaXY = dcaInfo[0]; + auto Track1dca = std::sqrt(Track1dcaXY * Track1dcaXY + dcaInfo[1] * dcaInfo[1]); auto Track2Par = getTrackPar(dBachtrack); o2::base::Propagator::Instance()->propagateToDCABxByBz({dCollision.posX(), dCollision.posY(), dCollision.posZ()}, Track2Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); auto Track2dcaXY = dcaInfo[0]; + auto Track2dca = std::sqrt(Track2dcaXY * Track2dcaXY + dcaInfo[1] * dcaInfo[1]); // H3L DCA Check // auto track3B = o2::track::TrackParCov(vertexXYZ, p3B, fitter3body.calcPCACovMatrixFlat(), t2.sign()); @@ -711,7 +714,9 @@ struct hypertriton3bodyFinder { vertexXYZ[0], vertexXYZ[1], vertexXYZ[2], p0[0], p0[1], p0[2], p1[0], p1[1], p1[2], p2[0], p2[1], p2[2], fitter3body.getChi2AtPCACandidate(), - Track0dcaXY, Track1dcaXY, Track2dcaXY); + Track0dcaXY, Track1dcaXY, Track2dcaXY, + Track0dca, Track1dca, Track2dca, + 0); // To be fixed } //------------------------------------------------------------------ // 3body decay finder for a collsion @@ -860,7 +865,7 @@ struct hypertriton3bodyFinder { auto ntracks = Ntracks.sliceBy(perCollisionGoodNegTracks, collision.globalIndex()); auto goodtracks = Goodtracks.sliceBy(perCollisionGoodTracks, collision.globalIndex()); - if (!cffilter.hasLD() && UseCFFilter) { + if (!cffilter.hasLD_LooseKstar() && UseCFFilter) { continue; } registry.fill(HIST("hEventCounter"), 1.5); @@ -897,7 +902,7 @@ struct hypertriton3bodyFinder { VirtualLambdaCheck(collision, v0s, 0); VirtualLambdaCheck(collision, fullv0s, 3); - if (!cffilter.hasLD() && UseCFFilter) { + if (!cffilter.hasLD_LooseKstar() && UseCFFilter) { continue; } registry.fill(HIST("hEventCounter"), 1.5); diff --git a/PWGLF/TableProducer/Nuspex/lithium4analysis.cxx b/PWGLF/TableProducer/Nuspex/lithium4analysis.cxx deleted file mode 100644 index 7e36ce21f62..00000000000 --- a/PWGLF/TableProducer/Nuspex/lithium4analysis.cxx +++ /dev/null @@ -1,655 +0,0 @@ -// 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. -// Analysis task for anti-lithium4 analysis - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "Common/Core/PID/PIDTOF.h" -#include "Common/TableProducer/PID/pidTOFBase.h" - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/StepTHn.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/Core/trackUtilities.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/TrackSelection.h" -#include "Framework/ASoAHelpers.h" -#include "DataFormatsTPC/BetheBlochAleph.h" -#include "CCDB/BasicCCDBManager.h" - -#include "PWGLF/DataModel/LFLithium4Tables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; - -namespace -{ -constexpr double betheBlochDefault[1][6]{{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}}; -static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; - -constexpr float he3Mass = o2::constants::physics::MassHelium3; -constexpr float protonMass = o2::constants::physics::MassProton; -constexpr int lithium4PDG = 1000030040; -constexpr int protonPDG = 2212; -constexpr int he3PDG = 1000020030; - -enum Selections { - kNoCuts = 0, - kGlobalTrack, - kTrackCuts, - kPID, - kAll -}; - -} // namespace - -struct lithium4Candidate { - - float recoPtHe3() const { return std::hypot(momHe3[0], momHe3[1]); } - float recoPhiHe3() const { return std::atan2(momHe3[1], momHe3[0]); } - float recoEtaHe3() const { return std::asinh(momHe3[2] / recoPtHe3()); } - float recoPtPr() const { return std::hypot(momPr[0], momPr[1]); } - float recoPhiPr() const { return std::atan2(momPr[1], momPr[0]); } - float recoEtaPr() const { return std::asinh(momPr[2] / recoPtPr()); } - - std::array momHe3 = {99.f, 99.f, 99.f}; - std::array momPr = {99.f, 99.f, 99.f}; - - bool isMatter = false; - - uint32_t PIDtrkHe3 = 0xFFFFF; // PID in tracking - uint32_t PIDtrkPr = 0xFFFFF; - - float nSigmaHe3 = -10; - float nSigmaPr = -10; - float massTOFHe3 = -10; - float massTOFPr = -10; - - float DCAxyHe3 = -10; - float DCAzHe3 = -10; - float DCAxyPr = -10; - float DCAzPr = -10; - uint16_t tpcSignalHe3 = 0u; - float momHe3TPC = -99.f; - uint16_t tpcSignalPr = 0u; - float momPrTPC = -99.f; - float invMass = -10.f; - - uint32_t itsClSizeHe3 = 0u; - uint32_t itsClSizePr = 0u; - uint8_t nTPCClustersHe3 = 0u; - - float momHe3MC = -99.f; - float momPrMC = -99.f; - - uint8_t sharedClustersHe3 = 0u; - uint8_t sharedClustersPr = 0u; - - bool isBkgUS = false; - bool isBkgEM = false; - - float l4PtMC = -99.f; - float l4MassMC = -10.f; -}; - -struct lithium4analysis { - - Produces outputDataTable; - Produces outputMCTable; - - std::vector l4Candidates; - - SliceCache cache; - HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - // events - Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; - // track - Configurable cfgCutPT{"cfgCutPT", 0.2, "PT cut on daughter track"}; - Configurable cfgCutMaxPrPT{"cfgCutMaxPrPT", 1.8, "Max PT cut on proton"}; - Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; - Configurable cfgCutDCAxy{"cfgCutDCAxy", 2.0f, "DCAxy range for tracks"}; - Configurable cfgCutDCAz{"cfgCutDCAz", 2.0f, "DCAz range for tracks"}; - Configurable nsigmaCutTPC{"nsigmacutTPC", 3.0, "Value of the TPC Nsigma cut"}; - Configurable nsigmaCutTOF{"nsigmaCutTOF", 3.0, "Value of the TOF Nsigma cut"}; - Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 5, "Number of mixed events per event"}; - Configurable cfgEnableBkgUS{"cfgEnableBkgUS", false, "Enable US background"}; - - // bethe bloch parameters - std::array mBBparamsHe; - Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {betheBlochDefault[0], 1, 6, {"He3"}, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for He3"}; - // MC - Configurable isMC{"isMC", false, "Run MC"}; - void init(o2::framework::InitContext&) - { - - histos.add("hCentrality", "Centrality distribution", kTH1F, {{2001, -0.5, 2000.5}}); - histos.add("hVtxZ", "Vertex distribution in Z;Z (cm)", kTH1F, {{400, -20.0, 20.0}}); - histos.add("hNcontributor", "Number of primary vertex contributor", kTH1F, {{2000, 0.0f, 2000.0f}}); - histos.add("hDCAxyHe3", ";DCA_{xy} (cm)", kTH1F, {{200, -1.0f, 1.0f}}); - histos.add("hDCAzHe3", ";DCA_{z} (cm)", kTH1F, {{200, -1.0f, 1.0f}}); - histos.add("hLitInvMass", "; M(^{3}He + p) (GeV/#it{c}^{2})", kTH1F, {{50, 3.74f, 3.85f}}); - histos.add("hHe3Pt", "#it{p}_{T} distribution; #it{p}_{T} (GeV/#it{c})", kTH1F, {{200, 0.0f, 6.0f}}); - histos.add("hProtonPt", "Pt distribution; #it{p}_{T} (GeV/#it{c})", kTH1F, {{200, 0.0f, 3.0f}}); - histos.add("h2NsigmaHe3TPC", "NsigmaHe3 TPC distribution; Signed #it{p}/#it{z} (GeV/#it{c}); n#sigma_{TPC}({}^{3}He)", kTH2F, {{20, -5.0f, 5.0f}, {200, -5.0f, 5.0f}}); - histos.add("h2NsigmaProtonTPC", "NsigmaProton TPC distribution; Signed #it{p}/#it{z} (GeV/#it{c}); n#sigma_{TPC}(p)", kTH2F, {{20, -5.0f, 5.0f}, {200, -5.0f, 5.0f}}); - histos.add("h2NsigmaProtonTOF", "NsigmaProton TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(p)", kTH2F, {{20, -5.0f, 5.0f}, {200, -5.0f, 5.0f}}); - histos.add("hTrackSel", "Accepted tracks", kTH1F, {{Selections::kAll, -0.5, static_cast(Selections::kAll) - 0.5}}); - - for (int i = 0; i < 5; i++) { - mBBparamsHe[i] = cfgBetheBlochParams->get("He3", Form("p%i", i)); - } - mBBparamsHe[5] = cfgBetheBlochParams->get("He3", "resolution"); - - std::vector labels = {"All", "Global track", "Track selection", "PID {}^{3}He"}; - for (int i = 0; i < Selections::kAll; i++) { - histos.get(HIST("hTrackSel"))->GetXaxis()->SetBinLabel(i + 1, labels[i].c_str()); - } - } - - template - bool selectionTrack(const T& candidate) - { - - if (candidate.itsNCls() < 5 || - candidate.tpcNClsFound() < 100 || // candidate.tpcNClsFound() < 70 || - candidate.tpcNClsCrossedRows() < 70 || - candidate.tpcNClsCrossedRows() < 0.8 * candidate.tpcNClsFindable() || - candidate.tpcChi2NCl() > 4.f || - candidate.itsChi2NCl() > 36.f) { - return false; - } - - return true; - } - - template - bool selectionPIDProton(const T& candidate) - { - if (candidate.hasTOF()) { - if (std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOF && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { - histos.fill(HIST("h2NsigmaProtonTPC"), candidate.tpcInnerParam(), candidate.tpcNSigmaPr()); - histos.fill(HIST("h2NsigmaProtonTOF"), candidate.p(), candidate.tofNSigmaPr()); - return true; - } - } else if (std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { - histos.fill(HIST("h2NsigmaProtonTPC"), candidate.tpcInnerParam(), candidate.tpcNSigmaPr()); - return true; - } - return false; - } - - template - float computeNSigmaHe3(const T& candidate) - { - float expTPCSignal = o2::tpc::BetheBlochAleph(static_cast(candidate.tpcInnerParam() * 2 / constants::physics::MassHelium3), mBBparamsHe[0], mBBparamsHe[1], mBBparamsHe[2], mBBparamsHe[3], mBBparamsHe[4]); - double resoTPC{expTPCSignal * mBBparamsHe[5]}; - return static_cast((candidate.tpcSignal() - expTPCSignal) / resoTPC); - } - - template - bool selectionPIDHe3(const T& candidate) - { - auto nSigmaHe3 = computeNSigmaHe3(candidate); - if (std::abs(nSigmaHe3) < nsigmaCutTPC) { - return true; - } - return false; - } - - template - bool FillCandidateInfo(const T1& candidateHe3, const T2& candidatePr, bool mix, bool /*isMC*/ = false) - { - lithium4Candidate l4Cand; - - l4Cand.momHe3 = array{2 * candidateHe3.px(), 2 * candidateHe3.py(), 2 * candidateHe3.pz()}; - l4Cand.momPr = array{candidatePr.px(), candidatePr.py(), candidatePr.pz()}; - - float invMass = RecoDecay::m(array{l4Cand.momHe3, l4Cand.momPr}, array{he3Mass, protonMass}); - - if (invMass < 3.74 || invMass > 3.85 || candidatePr.pt() > cfgCutMaxPrPT) { - return false; - } - - l4Cand.PIDtrkHe3 = candidateHe3.pidForTracking(); - l4Cand.PIDtrkPr = candidatePr.pidForTracking(); - - l4Cand.isBkgUS = candidateHe3.sign() * candidatePr.sign() < 0; - l4Cand.isBkgEM = mix; - l4Cand.isMatter = candidateHe3.sign() > 0; - l4Cand.DCAxyHe3 = candidateHe3.dcaXY(); - l4Cand.DCAzHe3 = candidateHe3.dcaZ(); - l4Cand.DCAxyPr = candidatePr.dcaXY(); - l4Cand.DCAzPr = candidatePr.dcaZ(); - - l4Cand.tpcSignalHe3 = candidateHe3.tpcSignal(); - l4Cand.momHe3TPC = candidateHe3.tpcInnerParam(); - l4Cand.tpcSignalPr = candidatePr.tpcSignal(); - l4Cand.momPrTPC = candidatePr.tpcInnerParam(); - l4Cand.invMass = invMass; - - l4Cand.itsClSizeHe3 = candidateHe3.itsClusterSizes(); - l4Cand.itsClSizePr = candidatePr.itsClusterSizes(); - - l4Cand.nTPCClustersHe3 = candidateHe3.tpcNClsFound(); - - l4Cand.nSigmaHe3 = computeNSigmaHe3(candidateHe3); - l4Cand.nSigmaPr = candidatePr.tpcNSigmaPr(); - - l4Cand.sharedClustersHe3 = candidateHe3.tpcNClsShared(); - l4Cand.sharedClustersPr = candidatePr.tpcNClsShared(); - - l4Candidates.push_back(l4Cand); - return true; - } - - template - void fillHistograms(const T& l4cand) - { - int candSign = l4cand.isMatter ? 1 : -1; - histos.fill(HIST("hHe3Pt"), l4cand.recoPtHe3()); - histos.fill(HIST("hProtonPt"), l4cand.recoPtPr()); - histos.fill(HIST("hLitInvMass"), l4cand.invMass); - histos.fill(HIST("hDCAxyHe3"), l4cand.DCAxyHe3); - histos.fill(HIST("hDCAzHe3"), l4cand.DCAzHe3); - histos.fill(HIST("h2NsigmaHe3TPC"), candSign * l4cand.momHe3TPC, l4cand.nSigmaHe3); - histos.fill(HIST("h2NsigmaProtonTPC"), candSign * l4cand.momPrTPC, l4cand.nSigmaPr); - histos.fill(HIST("h2NsigmaProtonTOF"), l4cand.recoPtPr(), l4cand.nSigmaPr); - } - - Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; - Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPT); - Filter DCAcutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); - - using EventCandidates = soa::Filtered>; - using TrackCandidates = soa::Filtered>; - using TrackCandidatesMC = soa::Filtered>; - o2::pid::tof::Beta responseBeta; - o2::pid::tof::Beta responseBetaMC; - - Preslice perCol = aod::track::collisionId; - Preslice perColMC = aod::track::collisionId; - - // binning for EM background - ConfigurableAxis axisVertex{"axisVertex", {30, -10, 10}, "vertex axis for bin"}; - using BinningType = ColumnBinningPolicy; - BinningType binningOnPositions{{axisVertex}, true}; - SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, &cache}; - - void processSameEvent(soa::Join const& collisions, TrackCandidates const& tracks, aod::BCs const&) - { - l4Candidates.clear(); - - for (auto& collision : collisions) { - if (!collision.sel8() || std::abs(collision.posZ()) > cfgCutVertex) { - continue; - } - histos.fill(HIST("hNcontributor"), collision.numContrib()); - histos.fill(HIST("hVtxZ"), collision.posZ()); - - const uint64_t collIdx = collision.globalIndex(); - auto TrackTable_thisCollision = tracks.sliceBy(perCol, collIdx); - TrackTable_thisCollision.bindExternalIndices(&tracks); - - for (auto track1 : TrackTable_thisCollision) { - - histos.fill(HIST("hTrackSel"), Selections::kNoCuts); - - if (!track1.isGlobalTrackWoDCA()) { - continue; - } - histos.fill(HIST("hTrackSel"), Selections::kGlobalTrack); - - if (!selectionTrack(track1)) { - continue; - } - histos.fill(HIST("hTrackSel"), Selections::kTrackCuts); - - if (!selectionPIDHe3(track1)) { - continue; - } - histos.fill(HIST("hTrackSel"), Selections::kPID); - - for (auto track2 : TrackTable_thisCollision) { - - if (track1 == track2) { - continue; - } - - if (!cfgEnableBkgUS) { - if (track1.sign() * track2.sign() < 0) { - continue; - } - } - - if (!track2.isGlobalTrackWoDCA()) { - continue; - } - - if (!selectionTrack(track2)) { - continue; - } - - if (!selectionPIDProton(track2)) { - continue; - } - - if (!FillCandidateInfo(track1, track2, false)) { - continue; - } - // fill TOF info outside to avoide responseBeta crash - auto& cand = l4Candidates.back(); - if (track1.hasTOF()) { - float beta = responseBeta.GetBeta(track1); - beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked - cand.massTOFHe3 = track1.tpcInnerParam() * 2 * std::sqrt(1.f / (beta * beta) - 1.f); - } - if (track2.hasTOF()) { - float beta = responseBeta.GetBeta(track2); - beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked - cand.massTOFPr = track2.tpcInnerParam() * std::sqrt(1.f / (beta * beta) - 1.f); - } - fillHistograms(cand); - } - } - } - - for (auto& l4Cand : l4Candidates) { - outputDataTable(l4Cand.recoPtHe3(), l4Cand.recoEtaHe3(), l4Cand.recoPhiHe3(), - l4Cand.recoPtPr(), l4Cand.recoEtaPr(), l4Cand.recoPhiPr(), - l4Cand.DCAxyHe3, l4Cand.DCAzHe3, l4Cand.DCAxyPr, l4Cand.DCAzPr, - l4Cand.tpcSignalHe3, l4Cand.momHe3TPC, l4Cand.tpcSignalPr, l4Cand.momPrTPC, - l4Cand.nTPCClustersHe3, - l4Cand.nSigmaHe3, l4Cand.nSigmaPr, l4Cand.massTOFHe3, l4Cand.massTOFPr, - l4Cand.PIDtrkHe3, l4Cand.PIDtrkPr, l4Cand.itsClSizeHe3, l4Cand.itsClSizePr, - l4Cand.sharedClustersHe3, l4Cand.sharedClustersPr, - l4Cand.isBkgUS, l4Cand.isBkgEM); - } - } - PROCESS_SWITCH(lithium4analysis, processSameEvent, "Process Same event", false); - - void processMixedEvent(EventCandidates& /*collisions*/, TrackCandidates const& /*tracks*/) - { - l4Candidates.clear(); - for (auto& [c1, tracks1, c2, tracks2] : pair) { - if (!c1.sel8()) { - continue; - } - if (!c2.sel8()) { - continue; - } - histos.fill(HIST("hNcontributor"), c1.numContrib()); - histos.fill(HIST("hVtxZ"), c1.posZ()); - - for (auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - - if (!t1.isGlobalTrackWoDCA()) { - continue; - } - - if (!selectionTrack(t1)) { - continue; - } - - if (!t2.isGlobalTrackWoDCA()) { - continue; - } - - if (!selectionTrack(t2)) { - continue; - } - - TrackCandidates::iterator he3Cand, protonCand; - bool passPID = false; - if (selectionPIDHe3(t1) && selectionPIDProton(t2)) { - he3Cand = t1, protonCand = t2; - passPID = true; - } - if (selectionPIDHe3(t2) && selectionPIDProton(t1)) { - he3Cand = t2, protonCand = t1; - passPID = true; - } - if (!passPID) { - continue; - } - - if (!FillCandidateInfo(he3Cand, protonCand, true)) { - continue; - } - // fill TOF info outside to avoide responseBeta crash - auto& cand = l4Candidates.back(); - if (he3Cand.hasTOF()) { - float beta = responseBeta.GetBeta(he3Cand); - beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked - cand.massTOFHe3 = he3Cand.tpcInnerParam() * 2 * std::sqrt(1.f / (beta * beta) - 1.f); - } - if (protonCand.hasTOF()) { - float beta = responseBeta.GetBeta(protonCand); - beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked - cand.massTOFPr = protonCand.tpcInnerParam() * std::sqrt(1.f / (beta * beta) - 1.f); - } - fillHistograms(cand); - } - } - - for (auto& l4Cand : l4Candidates) { - outputDataTable(l4Cand.recoPtHe3(), l4Cand.recoEtaHe3(), l4Cand.recoPhiHe3(), - l4Cand.recoPtPr(), l4Cand.recoEtaPr(), l4Cand.recoPhiPr(), - l4Cand.DCAxyHe3, l4Cand.DCAzHe3, l4Cand.DCAxyPr, l4Cand.DCAzPr, - l4Cand.tpcSignalHe3, l4Cand.momHe3TPC, l4Cand.tpcSignalPr, l4Cand.momPrTPC, - l4Cand.nTPCClustersHe3, - l4Cand.nSigmaHe3, l4Cand.nSigmaPr, l4Cand.massTOFHe3, l4Cand.massTOFPr, - l4Cand.PIDtrkHe3, l4Cand.PIDtrkPr, l4Cand.itsClSizeHe3, l4Cand.itsClSizePr, - l4Cand.sharedClustersHe3, l4Cand.sharedClustersPr, - l4Cand.isBkgUS, l4Cand.isBkgEM); - } - } - PROCESS_SWITCH(lithium4analysis, processMixedEvent, "Process Mixed event", false); - - void processMC(soa::Join const& collisions, aod::BCs const&, TrackCandidatesMC const& tracks, aod::McParticles const& mcParticles) - { - std::vector filledMothers; - l4Candidates.clear(); - - for (auto& collision : collisions) { - - if (!collision.sel8() || std::abs(collision.posZ()) > cfgCutVertex) { - continue; - } - - histos.fill(HIST("hNcontributor"), collision.numContrib()); - histos.fill(HIST("hVtxZ"), collision.posZ()); - - const uint64_t collIdx = collision.globalIndex(); - auto TrackTable_thisCollision = tracks.sliceBy(perColMC, collIdx); - TrackTable_thisCollision.bindExternalIndices(&tracks); - - for (auto track1 : TrackTable_thisCollision) { - - if (!track1.has_mcParticle()) { - continue; - } - - histos.fill(HIST("hTrackSel"), Selections::kNoCuts); - - if (!track1.isGlobalTrackWoDCA()) { - continue; - } - histos.fill(HIST("hTrackSel"), Selections::kGlobalTrack); - - if (!selectionTrack(track1)) { - continue; - } - histos.fill(HIST("hTrackSel"), Selections::kTrackCuts); - - if (!selectionPIDHe3(track1)) { - continue; - } - histos.fill(HIST("hTrackSel"), Selections::kPID); - - for (auto track2 : TrackTable_thisCollision) { - if (!track2.has_mcParticle()) { - continue; - } - - if (!track2.isGlobalTrackWoDCA()) { - continue; - } - - if (!selectionTrack(track2)) { - continue; - } - - if (!selectionPIDProton(track2)) { - continue; - } - - if (track1.sign() * track2.sign() < 0) { - continue; - } - - const auto mctrackHe3 = track1.mcParticle(); - const auto mctrackPr = track2.mcParticle(); - - if (std::abs(mctrackHe3.pdgCode()) != he3PDG || std::abs(mctrackPr.pdgCode()) != protonPDG) { - continue; - } - - for (auto& mothertrack : mctrackHe3.mothers_as()) { - for (auto& mothertrackPr : mctrackPr.mothers_as()) { - - if (mothertrack != mothertrackPr || std::abs(mothertrack.pdgCode()) != lithium4PDG) { - continue; - } - - if (std::abs(mothertrack.y()) > 1) { - continue; - } - - if (!FillCandidateInfo(track1, track2, false, true)) { - continue; - } - - // fill TOF info outside to avoide responseBeta crash - auto& cand = l4Candidates.back(); - if (track1.hasTOF()) { - float beta = responseBetaMC.GetBeta(track1); - beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked - cand.massTOFHe3 = track1.tpcInnerParam() * 2 * std::sqrt(1.f / (beta * beta) - 1.f); - } - if (track2.hasTOF()) { - float beta = responseBetaMC.GetBeta(track2); - beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked - cand.massTOFPr = track2.tpcInnerParam() * std::sqrt(1.f / (beta * beta) - 1.f); - } - - cand.momHe3MC = mctrackHe3.pt() * (mctrackHe3.pdgCode() > 0 ? 1 : -1); - cand.momPrMC = mctrackPr.pt() * (mctrackPr.pdgCode() > 0 ? 1 : -1); - cand.l4PtMC = mothertrack.pt() * (mothertrack.pdgCode() > 0 ? 1 : -1); - double eLit = mctrackHe3.e() + mctrackPr.e(); - cand.l4MassMC = std::sqrt(eLit * eLit - mothertrack.p() * mothertrack.p()); - filledMothers.push_back(mothertrack.globalIndex()); - fillHistograms(cand); - } - } - } - } - } - - for (auto& mcParticle : mcParticles) { - - if (std::abs(mcParticle.pdgCode()) != lithium4PDG) { - continue; - } - - if (std::abs(mcParticle.y()) > 1 || mcParticle.isPhysicalPrimary() == false) { - continue; - } - - if (std::find(filledMothers.begin(), filledMothers.end(), mcParticle.globalIndex()) != filledMothers.end()) { - continue; - } - - auto kDaughters = mcParticle.daughters_as(); - auto daughtHe3 = false; - auto daughtPr = false; - double eLit = 0; - int signHe3 = 0, signPr = 0; - double ptHe3 = 0, ptPr = 0; - for (auto kCurrentDaughter : kDaughters) { - if (std::abs(kCurrentDaughter.pdgCode()) == he3PDG) { - daughtHe3 = true; - signHe3 = kCurrentDaughter.pdgCode() > 0 ? 1 : -1; - ptHe3 = kCurrentDaughter.pt(); - eLit += kCurrentDaughter.e(); - } else if (std::abs(kCurrentDaughter.pdgCode()) == protonPDG) { - daughtPr = true; - signPr = kCurrentDaughter.pdgCode() > 0 ? 1 : -1; - ptPr = kCurrentDaughter.pt(); - eLit += kCurrentDaughter.e(); - } - } - if (daughtHe3 && daughtPr) { - lithium4Candidate l4Candidate; - int signLi = mcParticle.pdgCode() > 0 ? 1 : -1; - l4Candidate.l4PtMC = mcParticle.pt() * signLi; - l4Candidate.momHe3MC = ptHe3 * signHe3; - l4Candidate.momPrMC = ptPr * signPr; - l4Candidate.l4MassMC = std::sqrt(eLit * eLit - mcParticle.p() * mcParticle.p()); - l4Candidates.push_back(l4Candidate); - } - } - - for (auto& l4Cand : l4Candidates) { - outputMCTable(l4Cand.recoPtHe3(), l4Cand.recoEtaHe3(), l4Cand.recoPhiHe3(), - l4Cand.recoPtPr(), l4Cand.recoEtaPr(), l4Cand.recoPhiPr(), - l4Cand.DCAxyHe3, l4Cand.DCAzHe3, l4Cand.DCAxyPr, l4Cand.DCAzPr, - l4Cand.tpcSignalHe3, l4Cand.momHe3TPC, l4Cand.tpcSignalPr, l4Cand.momPrTPC, - l4Cand.nTPCClustersHe3, - l4Cand.nSigmaHe3, l4Cand.nSigmaPr, l4Cand.massTOFHe3, l4Cand.massTOFPr, - l4Cand.PIDtrkHe3, l4Cand.PIDtrkPr, l4Cand.itsClSizeHe3, l4Cand.itsClSizePr, - l4Cand.sharedClustersHe3, l4Cand.sharedClustersPr, - l4Cand.isBkgUS, l4Cand.isBkgEM, - l4Cand.momHe3MC, l4Cand.momPrMC, - l4Cand.l4PtMC, l4Cand.l4MassMC); - } - } - PROCESS_SWITCH(lithium4analysis, processMC, "Process MC", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"lithium4analysis"})}; -} diff --git a/PWGLF/TableProducer/Nuspex/lnnRecoTask.cxx b/PWGLF/TableProducer/Nuspex/lnnRecoTask.cxx index 5bc0606f9a5..c84a4c95dcb 100644 --- a/PWGLF/TableProducer/Nuspex/lnnRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/lnnRecoTask.cxx @@ -12,6 +12,12 @@ // Build \Lambda-n-n candidates from V0s and tracks // ============================================================================== #include +#include +#include +#include +#include + +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -30,31 +36,33 @@ #include "DataFormatsParameters/GRPMagField.h" #include "CCDB/BasicCCDBManager.h" +#include "Common/DataModel/PIDResponse.h" + #include "Common/Core/PID/TPCPIDResponse.h" #include "DataFormatsTPC/BetheBlochAleph.h" #include "DCAFitter/DCAFitterN.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Common/Core/PID/PIDTOF.h" +#include "Common/TableProducer/PID/pidTOFBase.h" + #include "PWGLF/DataModel/LFLnnTables.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using std::array; -using TracksFull = soa::Join; +using TracksFull = soa::Join; +using TracksFullMC = soa::Join; using CollisionsFull = soa::Join; using CollisionsFullMC = soa::Join; -// using CollisionsFullWithFlow = soa::Join; - namespace { constexpr double betheBlochDefault[1][6]{{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}}; static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; -static const std::vector particleNames{"3H"}; - -constexpr int h3DauPdg{1000010030}; -constexpr int lnnPdg{1010000030}; - +static const std::vector NucleiName{"3H"}; std::shared_ptr hEvents; std::shared_ptr hZvtx; std::shared_ptr hCentFT0A; @@ -62,11 +70,28 @@ std::shared_ptr hCentFT0C; std::shared_ptr hCentFT0M; std::shared_ptr hCentFV0A; std::shared_ptr hNsigma3HSel; +std::shared_ptr hNsigma3HSelTOF; std::shared_ptr hdEdx3HSel; +std::shared_ptr hdEdx3HPosTrack; std::shared_ptr hdEdxTot; +std::shared_ptr h3HMassPtTOF; +std::shared_ptr h3HSignalPtTOF; std::shared_ptr hDecayChannel; std::shared_ptr hIsMatterGen; std::shared_ptr hIsMatterGenTwoBody; +std::shared_ptr hDCAxy3H; +std::shared_ptr hLnnCandLoss; +std::shared_ptr hNSigma3HTPC_preselection; + +float alphaAP(std::array const& momB, std::array const& momC) +{ + std::array momA = {momB[0] + momC[0], momB[1] + momC[1], momB[2] + momC[2]}; + float momTot = std::sqrt(momA[0] * momA[0] + momA[1] * momA[1] + momA[2] * momA[2]); + float lQlPos = (momB[0] * momA[0] + momB[1] * momA[1] + momB[2] * momA[2]) / momTot; + float lQlNeg = (momC[0] * momA[0] + momC[1] * momA[1] + momC[2] * momA[2]) / momTot; + return (lQlPos - lQlNeg) / (lQlPos + lQlNeg); +} + } // namespace struct lnnCandidate { @@ -90,6 +115,11 @@ struct lnnCandidate { float piDCAXY = -10; float mom3HTPC = -10.f; float momPiTPC = -10.f; + float mass2TrTOF = -10.f; + float DCAPvto3H = -10.f; + float DCAPvtoPi = -10.f; + float beta = -10.f; + float tpcChi3H = -10.f; std::array mom3H; std::array momPi; std::array decVtx; @@ -118,13 +148,21 @@ struct lnnRecoTask { // Selection criteria Configurable v0cospa{"lnncospa", 0.95, "V0 CosPA"}; - Configurable masswidth{"lnnmasswidth", 0.06, "Mass width (GeV/c^2)"}; - Configurable dcav0dau{"lnndcaDau", 1.0, "DCA V0 Daughters"}; + Configurable masswidth{"lnnmasswidth", 0.1, "Mass width (GeV/c^2)"}; + Configurable dcav0dau{"lnndcaDau", 0.6, "DCA V0 Daughters"}; + Configurable Chi2nClusTPCMax{"Chi2NClusTPCMax", 4, "Chi2 / nClusTPC for triton track max"}; + Configurable Chi2nClusTPCMin{"Chi2NClusTPC", 0.5, "Chi2 / nClusTPC for triton track min"}; + Configurable Chi2nClusITS{"Chi2NClusITS", 36., "Chi2 / nClusITS for triton track"}; Configurable ptMin{"ptMin", 0.5, "Minimum pT of the lnncandidate"}; - Configurable TPCRigidityMin3H{"TPCRigidityMin3H", 0.5, "Minimum rigidity of the triton candidate"}; - Configurable etaMax{"eta", 1., "eta daughter"}; - Configurable nSigmaMax3H{"nSigmaMax3H", 5, "triton dEdx cut (n sigma)"}; + Configurable etaMax{"eta", 0.8, "eta daughter"}; + Configurable TPCRigidityMin3H{"TPCRigidityMin3H", 0.2, "Minimum rigidity of the triton candidate"}; + Configurable nSigmaCutMinTPC{"nSigmaCutMinTPC", -5, "triton dEdx cut (n sigma)"}; + Configurable nSigmaCutMaxTPC{"nSigmaCutMaxTPC", 5, "triton dEdx cut (n sigma)"}; Configurable nTPCClusMin3H{"nTPCClusMin3H", 80, "triton NTPC clusters cut"}; + Configurable nTPCClusMinPi{"nTPCClusMinPi", 60, "pion NTPC clusters cut"}; + Configurable ptMinTOF{"ptMinTOF", 0.8, "minimum pt for TOF cut"}; + Configurable TrTOFMass2Cut{"TrTOFMass2Cut", 5.5, "minimum Triton mass square to TOF"}; + Configurable BetaTrTOF{"BetaTrTOF", 0.4, "minimum beta TOF cut"}; Configurable mcSignalOnly{"mcSignalOnly", true, "If true, save only signal in MC"}; // Define o2 fitter, 2-prong, active memory (no need to redefine per event) @@ -135,7 +173,7 @@ struct lnnRecoTask { float piMass = o2::constants::physics::MassPionCharged; // bethe bloch parameters - Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {betheBlochDefault[0], 1, 6, particleNames, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for 3H"}; + Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {betheBlochDefault[0], 1, 6, NucleiName, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for 3H"}; Configurable cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Type of material correction"}; // CCDB options @@ -147,12 +185,22 @@ struct lnnRecoTask { Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; Configurable pidPath{"pidPath", "", "Path to the PID response object"}; + // PDG codes + Configurable h3DauPdg{"h3DauPdg", 1000010030, "PDG Triton"}; // PDG Triton + Configurable lnnPdg{"lnnPdg", 1010000030, "PDG Lnn"}; // PDG Lnn + // histogram axes ConfigurableAxis rigidityBins{"rigidityBins", {200, -10.f, 10.f}, "Binning for rigidity #it{p}^{TPC}/#it{z}"}; - ConfigurableAxis dEdxBins{"dEdxBins", {1000, 0.f, 1000.f}, "Binning for dE/dx"}; + ConfigurableAxis dEdxBins{"dEdxBins", {5000, 0.f, 1000.f}, "Binning for dE/dx"}; ConfigurableAxis nSigmaBins{"nSigmaBins", {200, -5.f, 5.f}, "Binning for n sigma"}; ConfigurableAxis zVtxBins{"zVtxBins", {100, -20.f, 20.f}, "Binning for n sigma"}; ConfigurableAxis centBins{"centBins", {100, 0.f, 100.f}, "Binning for centrality"}; + ConfigurableAxis TritMomBins{"TritMomBins", {100, -5.f, 5.f}, "Binning for Triton momentum"}; + ConfigurableAxis MassTOFBins{"MassTOFBins", {400, 2.0f, 12.f}, "Binning for Triton Mass TOF"}; + ConfigurableAxis PtTritonBins{"PtTritonBins", {200, -5.f, 5.f}, "Binning for Triton p values"}; + ConfigurableAxis PtPosTritonBins{"PtPosTritonBins", {200, 0.f, 5.f}, "Binning for Triton pt positive values"}; + ConfigurableAxis BetaBins{"BetaBins", {550, 0.f, 1.1f}, "Binning for Beta"}; + ConfigurableAxis DCAxyBins{"DCAxyBins", {550, -5.f, 5.f}, "Binning for DCAxy"}; // std vector of candidates std::vector lnnCandidates; @@ -160,6 +208,8 @@ struct lnnRecoTask { std::vector filledMothers; // vector to keep track of the collisions passing the event selection in the MC std::vector isGoodCollision; + std::vector collisionFT0Ccent; + // vector to armazenade h3Track Preslice perCollision = o2::aod::v0::collisionId; @@ -195,18 +245,39 @@ struct lnnRecoTask { const AxisSpec nSigma3HAxis{nSigmaBins, "n_{#sigma}({}^{3}H)"}; const AxisSpec zVtxAxis{zVtxBins, "z_{vtx} (cm)"}; const AxisSpec centAxis{centBins, "Centrality"}; - - hNsigma3HSel = qaRegistry.add("hNsigma3HSel", "; p_{TPC}/z (GeV/#it{c}); n_{#sigma} ({}^{3}H)", HistType::kTH2F, {rigidityAxis, nSigma3HAxis}); - hdEdx3HSel = qaRegistry.add("hdEdx3HSel", ";p_{TPC}/z (GeV/#it{c}); dE/dx", HistType::kTH2F, {rigidityAxis, dEdxAxis}); + const AxisSpec TritMomAxis{TritMomBins, "#it{p}({}^{3}H)"}; + const AxisSpec PtTrAxis{PtTritonBins, "#it{p_T}({}^{3}H)"}; + const AxisSpec PtPosTrAxis{PtPosTritonBins, "#it{p_T}({}^{3}H)"}; + const AxisSpec MassTOFAxis{MassTOFBins, "{m}^{2}/{z}^{2}"}; + const AxisSpec BetaAxis{BetaBins, "#beta (TOF)"}; + const AxisSpec DCAxyAxis(DCAxyBins, "DCAxy ({}^{3}H) (cm)"); + + hNsigma3HSel = qaRegistry.add("hNsigma3HSel", "; #it{p}_{TPC}/z (GeV/#it{c}); n_{#sigma} ({}^{3}H)", HistType::kTH2F, {rigidityAxis, nSigma3HAxis}); + hNsigma3HSelTOF = qaRegistry.add("hNsigma3HSelTOF", "; Signed p_{T} ({}^{3}H) (GeV/#it{c^2}); n#sigma_{TOF} ({}^{3}H)", HistType::kTH2F, {PtTrAxis, nSigma3HAxis}); + hdEdx3HSel = qaRegistry.add("hdEdx3HSel", ";#it{p}_{TPC}/z (GeV/#it{c}); dE/dx", HistType::kTH2F, {rigidityAxis, dEdxAxis}); + hdEdx3HPosTrack = qaRegistry.add("hdEdx3HPosTrack", "; #it{p}^{TPC}({}^{3}H); dE/dx", HistType::kTH2F, {TritMomAxis, dEdxAxis}); hdEdxTot = qaRegistry.add("hdEdxTot", ";p_{TPC}/z (GeV/#it{c}); dE/dx", HistType::kTH2F, {rigidityAxis, dEdxAxis}); - hEvents = qaRegistry.add("hEvents", ";Events; ", HistType::kTH1D, {{3, -0.5, 2.5}}); + h3HMassPtTOF = qaRegistry.add("hTrMassPtTOF", "; #it{p}_{T}({}^{3}H) (#it{GeV}^2/#it{c}^4); m^{2}/z", HistType::kTH2F, {PtTrAxis, MassTOFAxis}); + h3HSignalPtTOF = qaRegistry.add("h3HSignalPtTOF", "; #it{p}_{T}({}^{3}H) (GeV/#it{c}); #beta (TOF)", HistType::kTH2F, {PtTrAxis, BetaAxis}); + hDCAxy3H = qaRegistry.add("hDCAxy3H", "; #it{p}_{T}({}^{3}H) (GeV/#it{c}); #it{DCA}_{xy} 3H", HistType::kTH2F, {PtPosTrAxis, DCAxyAxis}); + hEvents = qaRegistry.add("hEvents", ";Events; ", HistType::kTH1D, {{2, -0.5, 1.5}}); + hLnnCandLoss = qaRegistry.add("hLnnCandLoss", ";CandLoss; ", HistType::kTH1D, {{7, -0.5, 6.5}}); + hNSigma3HTPC_preselection = qaRegistry.add("hNSigma3HTPC_preselection", "#it{p}/z (GeV/#it{c}); n#sigma_{TPC}(^{3}H)", HistType::kTH2F, {rigidityAxis, nSigma3HAxis}); + hEvents->GetXaxis()->SetBinLabel(1, "All"); hEvents->GetXaxis()->SetBinLabel(2, "sel8"); - hEvents->GetXaxis()->SetBinLabel(3, "z vtx"); + hLnnCandLoss->GetYaxis()->SetTitle("#it{N}_{candidates}"); + hLnnCandLoss->GetXaxis()->SetTitle("Cuts"); + hLnnCandLoss->GetXaxis()->SetBinLabel(1, "Initial LnnCandidates"); + hLnnCandLoss->GetXaxis()->SetBinLabel(2, "not 3H"); + hLnnCandLoss->GetXaxis()->SetBinLabel(3, "not anti3H"); + hLnnCandLoss->GetXaxis()->SetBinLabel(4, "#it{p}_{Tmin}"); + hLnnCandLoss->GetXaxis()->SetBinLabel(5, "!isLnnMass"); + hLnnCandLoss->GetXaxis()->SetBinLabel(6, "DCA #it{V}_{0} daughter"); + hLnnCandLoss->GetXaxis()->SetBinLabel(7, "cosPA"); if (doprocessMC) { hDecayChannel = qaRegistry.add("hDecayChannel", ";Decay channel; ", HistType::kTH1D, {{2, -0.5, 1.5}}); hDecayChannel->GetXaxis()->SetBinLabel(1, "2-body"); - hDecayChannel->GetXaxis()->SetBinLabel(2, "3-body"); hIsMatterGen = qaRegistry.add("hIsMatterGen", ";; ", HistType::kTH1D, {{2, -0.5, 1.5}}); hIsMatterGen->GetXaxis()->SetBinLabel(1, "Matter"); hIsMatterGen->GetXaxis()->SetBinLabel(2, "Antimatter"); @@ -266,6 +337,7 @@ struct lnnRecoTask { fitter.setBz(d_bz); mRunNumber = bc.runNumber(); } + // Template template void fillCandidateData(Tcoll const& collision, aod::V0s const& V0s) @@ -273,55 +345,75 @@ struct lnnRecoTask { if (mBBparams3H[5] < 0) { LOG(fatal) << "Bethe-Bloch parameters for 3H not set, please check your CCDB and configuration"; } + for (auto& v0 : V0s) { auto posTrack = v0.posTrack_as(); auto negTrack = v0.negTrack_as(); - if (std::abs(posTrack.eta()) > etaMax || std::abs(negTrack.eta()) > etaMax) + /// remove tracks wo TPC information, too much bkg for Lnn analysis + if (std::abs(posTrack.eta()) > etaMax || std::abs(negTrack.eta()) > etaMax || !posTrack.hasTPC() || !negTrack.hasTPC()) { continue; + } - // temporary fix: tpcInnerParam() returns the momentum in all the software tags before: https://github.com/AliceO2Group/AliceO2/pull/12521 - bool posTritonPID = posTrack.pidForTracking() == o2::track::PID::Triton; - bool negTritonPID = negTrack.pidForTracking() == o2::track::PID::Triton; - float posRigidity = posTritonPID ? posTrack.tpcInnerParam() / 2 : posTrack.tpcInnerParam(); - float negRigidity = negTritonPID ? negTrack.tpcInnerParam() / 2 : negTrack.tpcInnerParam(); - - hdEdxTot->Fill(posRigidity, posTrack.tpcSignal()); - hdEdxTot->Fill(-negRigidity, negTrack.tpcSignal()); - - // Bethe-Bloch calcution for 3H - double expBethePos{tpc::BetheBlochAleph(static_cast(posRigidity * 2 / constants::physics::MassTriton), mBBparams3H[0], mBBparams3H[1], mBBparams3H[2], mBBparams3H[3], mBBparams3H[4])}; - double expBetheNeg{tpc::BetheBlochAleph(static_cast(negRigidity * 2 / constants::physics::MassTriton), mBBparams3H[0], mBBparams3H[1], mBBparams3H[2], mBBparams3H[3], mBBparams3H[4])}; + float posRigidity = posTrack.tpcInnerParam(); + float negRigidity = negTrack.tpcInnerParam(); - // nSigma calculation + // Bethe-Bloch calcution for 3H & nSigma calculation + double expBethePos{tpc::BetheBlochAleph(static_cast(posRigidity / constants::physics::MassTriton), mBBparams3H[0], mBBparams3H[1], mBBparams3H[2], mBBparams3H[3], mBBparams3H[4])}; + double expBetheNeg{tpc::BetheBlochAleph(static_cast(negRigidity / constants::physics::MassTriton), mBBparams3H[0], mBBparams3H[1], mBBparams3H[2], mBBparams3H[3], mBBparams3H[4])}; double expSigmaPos{expBethePos * mBBparams3H[5]}; double expSigmaNeg{expBetheNeg * mBBparams3H[5]}; auto nSigmaTPCpos = static_cast((posTrack.tpcSignal() - expBethePos) / expSigmaPos); auto nSigmaTPCneg = static_cast((negTrack.tpcSignal() - expBetheNeg) / expSigmaNeg); + hdEdxTot->Fill(posRigidity, posTrack.tpcSignal()); + hdEdxTot->Fill(-negRigidity, negTrack.tpcSignal()); + // ITS only tracks do not have TPC information. TPCnSigma: only lower cut to allow for triton reconstruction - bool is3H = posTrack.hasTPC() && nSigmaTPCpos > -1 * nSigmaMax3H; - bool isAnti3H = negTrack.hasTPC() && nSigmaTPCneg > -1 * nSigmaMax3H; + bool is3H = nSigmaTPCpos > nSigmaCutMinTPC && nSigmaTPCpos < nSigmaCutMaxTPC; + bool isAnti3H = nSigmaTPCneg > nSigmaCutMinTPC && nSigmaTPCneg < nSigmaCutMaxTPC; - if (!is3H && !isAnti3H) + if (!is3H && !isAnti3H) // discard if both tracks are not 3H candidates continue; - // Describing lnn as matter candidate + // if alphaAP is > 0 the candidate is 3H, if < 0 it is anti-3H + std::array momPos = std::array{posTrack.px(), posTrack.py(), posTrack.pz()}; + std::array momNeg = std::array{negTrack.px(), negTrack.py(), negTrack.pz()}; + float alpha = alphaAP(momPos, momNeg); lnnCandidate lnnCand; - lnnCand.isMatter = is3H && isAnti3H ? std::abs(nSigmaTPCpos) < std::abs(nSigmaTPCneg) : is3H; + lnnCand.isMatter = alpha > 0; + hLnnCandLoss->Fill(0.); + if ((lnnCand.isMatter && !is3H) || (!lnnCand.isMatter && !isAnti3H)) { + if (lnnCand.isMatter && !is3H) { + hLnnCandLoss->Fill(1.); + } + if (!lnnCand.isMatter && !isAnti3H) { + hLnnCandLoss->Fill(2.); + } + continue; + } auto& h3track = lnnCand.isMatter ? posTrack : negTrack; + auto& pitrack = lnnCand.isMatter ? negTrack : posTrack; auto& h3Rigidity = lnnCand.isMatter ? posRigidity : negRigidity; - if (h3track.tpcNClsFound() < nTPCClusMin3H || h3Rigidity < TPCRigidityMin3H) + + if (h3Rigidity < TPCRigidityMin3H || + h3track.tpcNClsFound() < nTPCClusMin3H || + h3track.tpcChi2NCl() < Chi2nClusTPCMin || + h3track.tpcChi2NCl() > Chi2nClusTPCMax || + h3track.itsChi2NCl() > Chi2nClusITS || + pitrack.tpcNClsFound() < nTPCClusMinPi) { continue; + } + lnnCand.tpcChi3H = lnnCand.isMatter ? h3track.tpcChi2NCl() : negTrack.tpcChi2NCl(); lnnCand.nSigma3H = lnnCand.isMatter ? nSigmaTPCpos : nSigmaTPCneg; - lnnCand.nTPCClusters3H = lnnCand.isMatter ? posTrack.tpcNClsFound() : negTrack.tpcNClsFound(); - lnnCand.tpcSignal3H = lnnCand.isMatter ? posTrack.tpcSignal() : negTrack.tpcSignal(); - lnnCand.clusterSizeITS3H = lnnCand.isMatter ? posTrack.itsClusterSizes() : negTrack.itsClusterSizes(); - lnnCand.nTPCClustersPi = !lnnCand.isMatter ? posTrack.tpcNClsFound() : negTrack.tpcNClsFound(); - lnnCand.tpcSignalPi = !lnnCand.isMatter ? posTrack.tpcSignal() : negTrack.tpcSignal(); - lnnCand.clusterSizeITSPi = !lnnCand.isMatter ? posTrack.itsClusterSizes() : negTrack.itsClusterSizes(); + lnnCand.nTPCClusters3H = lnnCand.isMatter ? h3track.tpcNClsFound() : negTrack.tpcNClsFound(); + lnnCand.tpcSignal3H = lnnCand.isMatter ? h3track.tpcSignal() : negTrack.tpcSignal(); + lnnCand.clusterSizeITS3H = lnnCand.isMatter ? h3track.itsClusterSizes() : negTrack.itsClusterSizes(); + lnnCand.nTPCClustersPi = !lnnCand.isMatter ? h3track.tpcNClsFound() : negTrack.tpcNClsFound(); + lnnCand.tpcSignalPi = !lnnCand.isMatter ? h3track.tpcSignal() : negTrack.tpcSignal(); + lnnCand.clusterSizeITSPi = !lnnCand.isMatter ? h3track.itsClusterSizes() : negTrack.itsClusterSizes(); lnnCand.mom3HTPC = lnnCand.isMatter ? posRigidity : negRigidity; lnnCand.momPiTPC = !lnnCand.isMatter ? posRigidity : negRigidity; @@ -330,6 +422,21 @@ struct lnnRecoTask { auto posTrackCov = getTrackParCov(posTrack); auto negTrackCov = getTrackParCov(negTrack); + int chargeFactor = -1 + 2 * lnnCand.isMatter; + + float beta = -1.f; + if (h3track.pt() >= ptMinTOF) { + hNSigma3HTPC_preselection->Fill(h3track.tpcInnerParam(), lnnCand.nSigma3H); + if (!h3track.hasTOF()) { + continue; + } + + beta = h3track.beta(); + lnnCand.mass2TrTOF = h3track.mass() * h3track.mass(); + if (lnnCand.mass2TrTOF < TrTOFMass2Cut || beta < BetaTrTOF) { + continue; + } + } int nCand = 0; try { @@ -347,11 +454,6 @@ struct lnnRecoTask { h3PropTrack.getPxPyPzGlo(lnnCand.mom3H); piPropTrack.getPxPyPzGlo(lnnCand.momPi); - // the momentum has to be multiplied by 2 (charge) - for (int i = 0; i < 3; i++) { - lnnCand.mom3H[i] *= 2; - } - // Definition of relativistic momentum and energy to triton and pion and total energy float h3P2 = lnnCand.mom3H[0] * lnnCand.mom3H[0] + lnnCand.mom3H[1] * lnnCand.mom3H[1] + lnnCand.mom3H[2] * lnnCand.mom3H[2]; float piP2 = lnnCand.momPi[0] * lnnCand.momPi[0] + lnnCand.momPi[1] * lnnCand.momPi[1] + lnnCand.momPi[2] * lnnCand.momPi[2]; @@ -361,6 +463,7 @@ struct lnnRecoTask { // Building the mother particle: lnn std::array lnnMom; + const auto& vtx = fitter.getPCACandidate(); for (int i = 0; i < 3; i++) { lnnCand.decVtx[i] = vtx[i]; @@ -368,20 +471,27 @@ struct lnnRecoTask { } float lnnPt = std::hypot(lnnMom[0], lnnMom[1]); - if (lnnPt < ptMin) + if (lnnPt < ptMin) { + hLnnCandLoss->Fill(3.); continue; + } // Definition of lnn mass + float mLNN_HypHI = 3.00; // , but 2993.7 MeV/c**2 float massLNNL = std::sqrt(h3lE * h3lE - lnnMom[0] * lnnMom[0] - lnnMom[1] * lnnMom[1] - lnnMom[2] * lnnMom[2]); bool isLNNMass = false; - if (massLNNL > o2::constants::physics::MassTriton - masswidth && massLNNL < o2::constants::physics::MassTriton + masswidth) + if (massLNNL > mLNN_HypHI - masswidth && massLNNL < mLNN_HypHI + masswidth) { isLNNMass = true; - if (!isLNNMass) + } + if (!isLNNMass) { + hLnnCandLoss->Fill(4.); continue; + } // V0, primary vertex and poiting angle lnnCand.dcaV0dau = std::sqrt(fitter.getChi2AtPCACandidate()); if (lnnCand.dcaV0dau > dcav0dau) { + hLnnCandLoss->Fill(5.); continue; } @@ -389,6 +499,7 @@ struct lnnRecoTask { double cosPA = RecoDecay::cpa(primVtx, lnnCand.decVtx, lnnMom); if (cosPA < v0cospa) { + hLnnCandLoss->Fill(6.); continue; } @@ -398,28 +509,33 @@ struct lnnRecoTask { // if survived all selections, propagate decay daughters to PV gpu::gpustd::array dcaInfo; + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, h3PropTrack, 2.f, fitter.getMatCorrType(), &dcaInfo); + lnnCand.h3DCAXY = dcaInfo[0]; - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, posTrackCov, 2.f, fitter.getMatCorrType(), &dcaInfo); - lnnCand.isMatter ? lnnCand.h3DCAXY = dcaInfo[0] : lnnCand.piDCAXY = dcaInfo[0]; - - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, negTrackCov, 2.f, fitter.getMatCorrType(), &dcaInfo); - lnnCand.isMatter ? lnnCand.piDCAXY = dcaInfo[0] : lnnCand.h3DCAXY = dcaInfo[0]; + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, piPropTrack, 2.f, fitter.getMatCorrType(), &dcaInfo); + lnnCand.piDCAXY = dcaInfo[0]; // finally, push back the candidate lnnCand.isReco = true; lnnCand.posTrackID = posTrack.globalIndex(); lnnCand.negTrackID = negTrack.globalIndex(); - int chargeFactor = -1 + 2 * lnnCand.isMatter; + lnnCandidates.push_back(lnnCand); + + // Fill QA histograms hdEdx3HSel->Fill(chargeFactor * lnnCand.mom3HTPC, h3track.tpcSignal()); hNsigma3HSel->Fill(chargeFactor * lnnCand.mom3HTPC, lnnCand.nSigma3H); - - lnnCandidates.push_back(lnnCand); + hDCAxy3H->Fill(h3track.pt(), h3track.dcaXY()); + if (h3track.hasTOF()) { + h3HSignalPtTOF->Fill(chargeFactor * h3track.pt(), beta); + hNsigma3HSelTOF->Fill(chargeFactor * h3track.p(), h3track.tofNSigmaTr()); + h3HMassPtTOF->Fill(chargeFactor * h3track.pt(), lnnCand.mass2TrTOF); + } } } // Monte Carlo information - void fillMCinfo(aod::McTrackLabels const& trackLabels, aod::McParticles const& particlesMC) + void fillMCinfo(aod::McTrackLabels const& trackLabels, aod::McParticles const&) { for (auto& lnnCand : lnnCandidates) { auto mcLabPos = trackLabels.rawIteratorAt(lnnCand.posTrackID); @@ -429,21 +545,26 @@ struct lnnRecoTask { if (mcLabPos.has_mcParticle() && mcLabNeg.has_mcParticle()) { auto mcTrackPos = mcLabPos.mcParticle_as(); auto mcTrackNeg = mcLabNeg.mcParticle_as(); + if (mcTrackPos.has_mothers() && mcTrackNeg.has_mothers()) { for (auto& negMother : mcTrackNeg.mothers_as()) { for (auto& posMother : mcTrackPos.mothers_as()) { if (posMother.globalIndex() != negMother.globalIndex()) continue; - if (!((mcTrackPos.pdgCode() == h3DauPdg && mcTrackNeg.pdgCode() == -211) || (mcTrackPos.pdgCode() == 211 && mcTrackNeg.pdgCode() == -1 * h3DauPdg))) // TODO: check warning for constant comparison + if (!((mcTrackPos.pdgCode() == h3DauPdg && mcTrackNeg.pdgCode() == -211) || (mcTrackPos.pdgCode() == 211 && mcTrackNeg.pdgCode() == -1 * h3DauPdg))) continue; if (std::abs(posMother.pdgCode()) != lnnPdg) continue; // Checking primary and second vertex with MC simulations - auto posPrimVtx = array{posMother.vx(), posMother.vy(), posMother.vz()}; - auto secVtx = array{mcTrackPos.vx(), mcTrackPos.vy(), mcTrackPos.vz()}; - lnnCand.gMom = array{posMother.px(), posMother.py(), posMother.pz()}; - lnnCand.gMom3H = mcTrackPos.pdgCode() == h3DauPdg ? array{mcTrackPos.px(), mcTrackPos.py(), mcTrackPos.pz()} : array{mcTrackNeg.px(), mcTrackNeg.py(), mcTrackNeg.pz()}; + std::array posPrimVtx = {posMother.vx(), posMother.vy(), posMother.vz()}; + + std::array secVtx = {mcTrackPos.vx(), mcTrackPos.vy(), mcTrackPos.vz()}; + + lnnCand.gMom = posMother.pVector(); + + lnnCand.gMom3H = mcTrackPos.pdgCode() == h3DauPdg ? mcTrackPos.pVector() : mcTrackNeg.pVector(); + for (int i = 0; i < 3; i++) { lnnCand.gDecVtx[i] = secVtx[i] - posPrimVtx[i]; } @@ -460,7 +581,6 @@ struct lnnRecoTask { void processData(CollisionsFull const& collisions, aod::V0s const& V0s, TracksFull const& tracks, aod::BCsWithTimestamps const&) { - for (const auto& collision : collisions) { lnnCandidates.clear(); @@ -468,8 +588,9 @@ struct lnnRecoTask { initCCDB(bc); hEvents->Fill(0.); - if (!collision.sel8() || std::abs(collision.posZ()) > 10) + if ((!collision.sel8()) || std::abs(collision.posZ()) > 10) { continue; + } hEvents->Fill(1.); hZvtx->Fill(collision.posZ()); hCentFT0A->Fill(collision.centFT0A()); @@ -493,19 +614,22 @@ struct lnnRecoTask { lnnCand.dcaV0dau, lnnCand.h3DCAXY, lnnCand.piDCAXY, lnnCand.nSigma3H, lnnCand.nTPCClusters3H, lnnCand.nTPCClustersPi, lnnCand.mom3HTPC, lnnCand.momPiTPC, lnnCand.tpcSignal3H, lnnCand.tpcSignalPi, + lnnCand.mass2TrTOF, lnnCand.tpcChi3H, lnnCand.clusterSizeITS3H, lnnCand.clusterSizeITSPi, lnnCand.flags); } } } - - // Data process PROCESS_SWITCH(lnnRecoTask, processData, "Data analysis", true); // MC process - void processMC(CollisionsFullMC const& collisions, aod::McCollisions const& mcCollisions, aod::V0s const& V0s, TracksFull const& tracks, aod::BCsWithTimestamps const&, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC) + void processMC(CollisionsFullMC const& collisions, aod::McCollisions const& mcCollisions, aod::V0s const& V0s, aod::BCsWithTimestamps const&, TracksFull const& tracks, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC) { filledMothers.clear(); + + isGoodCollision.clear(); isGoodCollision.resize(mcCollisions.size(), false); + collisionFT0Ccent.clear(); + collisionFT0Ccent.resize(mcCollisions.size(), -1.f); for (const auto& collision : collisions) { lnnCandidates.clear(); @@ -513,8 +637,10 @@ struct lnnRecoTask { initCCDB(bc); hEvents->Fill(0.); - if (!collision.sel8() || std::abs(collision.posZ()) > 10) + + if (std::abs(collision.posZ()) > 10) { continue; + } hEvents->Fill(1.); hZvtx->Fill(collision.posZ()); hCentFT0A->Fill(collision.centFT0A()); @@ -522,7 +648,10 @@ struct lnnRecoTask { hCentFT0M->Fill(collision.centFT0M()); hCentFV0A->Fill(collision.centFV0A()); - isGoodCollision[collision.mcCollisionId()] = true; + if (collision.has_mcCollision()) { + isGoodCollision[collision.mcCollisionId()] = true; + collisionFT0Ccent[collision.mcCollisionId()] = collision.centFT0C(); + } const uint64_t collIdx = collision.globalIndex(); auto V0Table_thisCollision = V0s.sliceBy(perCollision, collIdx); @@ -532,8 +661,9 @@ struct lnnRecoTask { fillMCinfo(trackLabelsMC, particlesMC); for (auto& lnnCand : lnnCandidates) { - if (!lnnCand.isSignal && mcSignalOnly) + if (!lnnCand.isSignal && mcSignalOnly) { continue; + } int chargeFactor = -1 + 2 * (lnnCand.pdgCode > 0); outputMCTable(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), collision.posX(), collision.posY(), collision.posZ(), @@ -544,6 +674,7 @@ struct lnnRecoTask { lnnCand.dcaV0dau, lnnCand.h3DCAXY, lnnCand.piDCAXY, lnnCand.nSigma3H, lnnCand.nTPCClusters3H, lnnCand.nTPCClustersPi, lnnCand.mom3HTPC, lnnCand.momPiTPC, lnnCand.tpcSignal3H, lnnCand.tpcSignalPi, + lnnCand.mass2TrTOF, lnnCand.tpcChi3H, lnnCand.clusterSizeITS3H, lnnCand.clusterSizeITSPi, lnnCand.flags, chargeFactor * lnnCand.genPt(), lnnCand.genPhi(), lnnCand.genEta(), lnnCand.genPt3H(), lnnCand.gDecVtx[0], lnnCand.gDecVtx[1], lnnCand.gDecVtx[2], lnnCand.isReco, lnnCand.isSignal, lnnCand.survEvSelection); @@ -553,17 +684,22 @@ struct lnnRecoTask { // now we fill only the signal candidates that were not reconstructed for (auto& mcPart : particlesMC) { - if (std::abs(mcPart.pdgCode()) != lnnPdg) + if (std::abs(mcPart.pdgCode()) != lnnPdg) { continue; + } std::array secVtx; std::array primVtx = {mcPart.vx(), mcPart.vy(), mcPart.vz()}; - std::array momMother = {mcPart.px(), mcPart.py(), mcPart.pz()}; + + std::array momMother = mcPart.pVector(); + std::array mom3H; bool is3HFound = false; for (auto& mcDaught : mcPart.daughters_as()) { if (std::abs(mcDaught.pdgCode()) == h3DauPdg) { secVtx = {mcDaught.vx(), mcDaught.vy(), mcDaught.vz()}; - mom3H = {mcDaught.px(), mcDaught.py(), mcDaught.pz()}; + + mom3H = mcDaught.pVector(); + is3HFound = true; break; } @@ -586,6 +722,7 @@ struct lnnRecoTask { if (std::find(filledMothers.begin(), filledMothers.end(), mcPart.globalIndex()) != std::end(filledMothers)) { continue; } + lnnCandidate lnnCand; lnnCand.pdgCode = mcPart.pdgCode(); lnnCand.survEvSelection = isGoodCollision[mcPart.mcCollisionId()]; @@ -598,15 +735,16 @@ struct lnnRecoTask { lnnCand.posTrackID = -1; lnnCand.negTrackID = -1; lnnCand.isSignal = true; - outputMCTable(-1, -1, -1, - 0, + outputMCTable(-1, collisionFT0Ccent[mcPart.mcCollisionId()], -1, -1, -1, -1, + 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, chargeFactor * lnnCand.genPt(), lnnCand.genPhi(), lnnCand.genEta(), lnnCand.genPt3H(), lnnCand.gDecVtx[0], lnnCand.gDecVtx[1], lnnCand.gDecVtx[2], lnnCand.isReco, lnnCand.isSignal, lnnCand.survEvSelection); diff --git a/PWGLF/TableProducer/Nuspex/nucleiFlowTree.cxx b/PWGLF/TableProducer/Nuspex/nucleiFlowTree.cxx new file mode 100644 index 00000000000..85dea6f7ac0 --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/nucleiFlowTree.cxx @@ -0,0 +1,489 @@ +// 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. +// +// Nuclei spectra analysis task +// ======================== +// +// Executable + dependencies: +// +// Data (run3): +// o2-analysis-lf-nuclei-spectra, o2-analysis-timestamp +// o2-analysis-pid-tof-base, o2-analysis-multiplicity-table, o2-analysis-event-selection +// (to add flow: o2-analysis-qvector-table, o2-analysis-centrality-table) + +#include +#include +#include +#include +#include + +#include "Math/Vector4D.h" + +#include "CCDB/BasicCCDBManager.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/PID/PIDTOF.h" +#include "Common/TableProducer/PID/pidTOFBase.h" +#include "Common/Core/EventPlaneHelper.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/Tools/TrackTuner.h" +#include "Common/Core/RecoDecay.h" + +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "ReconstructionDataFormats/Track.h" + +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/LFSlimNucleiTables.h" + +#include "TRandom3.h" + +#include "nucleiUtils.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +struct nucleiFlowTree { + enum { + kProton = BIT(0), + kDeuteron = BIT(1), + kTriton = BIT(2), + kHe3 = BIT(3), + kHe4 = BIT(4), + kHasTOF = BIT(5), + kHasTRD = BIT(6), + kIsAmbiguous = BIT(7), /// just a placeholder now + kITSrof = BIT(8), + kIsPhysicalPrimary = BIT(9), /// MC flags starting from the second half of the short + kIsSecondaryFromMaterial = BIT(10), + kIsSecondaryFromWeakDecay = BIT(11) /// the last 4 bits are reserved for the PID in tracking + }; + + Produces nucleiTable; + Produces nucleiTableMC; + Produces nucleiTableFlow; + Service ccdb; + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + Configurable cfgCompensatePIDinTracking{"cfgCompensatePIDinTracking", false, "If true, divide tpcInnerParam by the electric charge"}; + + Configurable cfgCentralityEstimator{"cfgCentralityEstimator", 0, "Centrality estimator (FV0A: 0, FT0M: 1, FT0A: 2, FT0C: 3)"}; + Configurable cfgCMrapidity{"cfgCMrapidity", 0.f, "Rapidity of the center of mass (only for p-Pb)"}; + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutEta{"cfgCutEta", 0.8f, "Eta range for tracks"}; + Configurable cfgCutTpcMom{"cfgCutTpcMom", 0.2f, "Minimum TPC momentum for tracks"}; + Configurable cfgCutRapidityMin{"cfgCutRapidityMin", -0.5, "Minimum rapidity for tracks"}; + Configurable cfgCutRapidityMax{"cfgCutRapidityMax", 0.5, "Maximum rapidity for tracks"}; + Configurable cfgCutOnReconstructedRapidity{"cfgCutOnReconstructedRapidity", false, "Cut on reconstructed rapidity"}; + Configurable cfgCutNclusITS{"cfgCutNclusITS", 5, "Minimum number of ITS clusters"}; + Configurable cfgCutNclusTPC{"cfgCutNclusTPC", 70, "Minimum number of TPC clusters"}; + Configurable cfgCutPtMinTree{"cfgCutPtMinTree", 0.2f, "Minimum track transverse momentum for tree saving"}; + Configurable cfgCutPtMaxTree{"cfgCutPtMaxTree", 15.0f, "Maximum track transverse momentum for tree saving"}; + + Configurable> cfgEventSelections{"cfgEventSelections", {nuclei::EvSelDefault[0], 8, 1, nuclei::eventSelectionLabels, nuclei::eventSelectionTitle}, "Event selections"}; + + Configurable> cfgMomentumScalingBetheBloch{"cfgMomentumScalingBetheBloch", {nuclei::bbMomScalingDefault[0], 5, 2, nuclei::names, nuclei::chargeLabelNames}, "TPC Bethe-Bloch momentum scaling for light nuclei"}; + Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {nuclei::betheBlochDefault[0], 5, 6, nuclei::names, nuclei::betheBlochParNames}, "TPC Bethe-Bloch parameterisation for light nuclei"}; + Configurable> cfgNsigmaTPC{"cfgNsigmaTPC", {nuclei::nSigmaTPCdefault[0], 5, 2, nuclei::names, nuclei::nSigmaConfigName}, "TPC nsigma selection for light nuclei"}; + Configurable> cfgDCAcut{"cfgDCAcut", {nuclei::DCAcutDefault[0], 5, 2, nuclei::names, nuclei::nDCAConfigName}, "Max DCAxy and DCAz for light nuclei"}; + Configurable> cfgDownscaling{"cfgDownscaling", {nuclei::DownscalingDefault[0], 5, 1, nuclei::names, nuclei::DownscalingConfigName}, "Fraction of kept candidates for light nuclei"}; + Configurable> cfgTreeConfig{"cfgTreeConfig", {nuclei::TreeConfigDefault[0], 5, 2, nuclei::names, nuclei::treeConfigNames}, "Filtered trees configuration"}; + + ConfigurableAxis cfgNITSClusBins{"cfgNITSClusBins", {3, 4.5, 7.5}, "N ITS clusters binning"}; + ConfigurableAxis cfgNTPCClusBins{"cfgNTPCClusBins", {3, 89.5, 159.5}, "N TPC clusters binning"}; + + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; + + o2::track::TrackParametrizationWithError mTrackParCov; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + + // CCDB options + Configurable cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrLUT), "Type of material correction"}; + Configurable cfgCCDBurl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable cfgZorroCCDBpath{"cfgZorroCCDBpath", "/Users/m/mpuccio/EventFiltering/OTS/", "path to the zorro ccdb objects"}; + int mRunNumber = 0; + float mBz = 0.f; + + using TrackCandidates = soa::Join; + + // Configurable Harmonics index + Configurable cfgHarmonics{"cfgHarmonics", 2, "Harmonics index for flow analysis"}; + + // Collisions with chentrality + using CollWithCent = soa::Join::iterator; + + // Flow analysis + using CollWithEP = soa::Join::iterator; + + using CollWithQvec = soa::Join::iterator; + + HistogramRegistry spectra{"spectra", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + float computeEventPlane(float y, float x) + { + return 0.5 * std::atan2(y, x); + } + + template + bool eventSelectionWithHisto(Tcoll& collision) + { + spectra.fill(HIST("hEventSelections"), 0); + + if (cfgEventSelections->get(nuclei::evSel::kTVX) && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + spectra.fill(HIST("hEventSelections"), nuclei::evSel::kTVX + 1); + + if (cfgEventSelections->get(nuclei::evSel::kZvtx) && std::abs(collision.posZ()) > cfgCutVertex) { + return false; + } + spectra.fill(HIST("hEventSelections"), nuclei::evSel::kZvtx + 1); + + if (cfgEventSelections->get(nuclei::evSel::kTFborder) && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } + spectra.fill(HIST("hEventSelections"), nuclei::evSel::kTFborder + 1); + + if (cfgEventSelections->get(nuclei::evSel::kITSROFborder) && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return false; + } + spectra.fill(HIST("hEventSelections"), nuclei::evSel::kITSROFborder + 1); + + if (cfgEventSelections->get(nuclei::evSel::kNoSameBunchPileup) && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + spectra.fill(HIST("hEventSelections"), nuclei::evSel::kNoSameBunchPileup + 1); + + if (cfgEventSelections->get(nuclei::evSel::kIsGoodZvtxFT0vsPV) && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + spectra.fill(HIST("hEventSelections"), nuclei::evSel::kIsGoodZvtxFT0vsPV + 1); + + if (cfgEventSelections->get(nuclei::evSel::kIsGoodITSLayersAll) && !collision.selection_bit(aod::evsel::kIsGoodITSLayersAll)) { + return false; + } + spectra.fill(HIST("hEventSelections"), nuclei::evSel::kIsGoodITSLayersAll + 1); + + if constexpr ( + requires { + collision.triggereventep(); + }) { + if (cfgEventSelections->get(nuclei::evSel::kIsEPtriggered) && !collision.triggereventep()) { + return false; + } + spectra.fill(HIST("hEventSelections"), nuclei::evSel::kIsEPtriggered + 1); + } + + float centrality = getCentrality(collision); + spectra.fill(HIST("hCentrality"), centrality); + + return true; + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + if (cfgSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), "fHe"); + zorro.populateHistRegistry(spectra, bc.runNumber()); + } + auto timestamp = bc.timestamp(); + mRunNumber = bc.runNumber(); + + o2::parameters::GRPMagField* grpmag = ccdb->getForTimeStamp("GLO/Config/GRPMagField", timestamp); + o2::base::Propagator::initFieldFromGRP(grpmag); + o2::base::Propagator::Instance()->setMatLUT(nuclei::lut); + mBz = static_cast(grpmag->getNominalL3Field()); + LOGF(info, "Retrieved GRP for timestamp %ull (%i) with magnetic field of %1.2f kZG", timestamp, mRunNumber, mBz); + } + + void init(o2::framework::InitContext&) + { + zorroSummary.setObject(zorro.getZorroSummary()); + zorro.setBaseCCDBPath(cfgZorroCCDBpath.value); + ccdb->setURL(cfgCCDBurl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + spectra.add("hEventSelections", "hEventSelections", {HistType::kTH1D, {{nuclei::evSel::kNevSels + 1, -0.5f, static_cast(nuclei::evSel::kNevSels) + 0.5f}}}); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(1, "all"); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(nuclei::evSel::kTVX + 2, "TVX"); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(nuclei::evSel::kZvtx + 2, "Zvtx"); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(nuclei::evSel::kTFborder + 2, "TFborder"); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(nuclei::evSel::kITSROFborder + 2, "ITSROFborder"); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(nuclei::evSel::kNoSameBunchPileup + 2, "kNoSameBunchPileup"); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(nuclei::evSel::kIsGoodZvtxFT0vsPV + 2, "isGoodZvtxFT0vsPV"); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(nuclei::evSel::kIsGoodITSLayersAll + 2, "IsGoodITSLayersAll"); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(nuclei::evSel::kIsEPtriggered + 2, "IsEPtriggered"); + + spectra.add("hCentrality", "hCentrality", HistType::kTH1D, {{100, 0., 100., "Centrality (%)"}}); + + spectra.add("hRecVtxZData", "collision z position", HistType::kTH1F, {{200, -20., 20., "z position (cm)"}}); + spectra.add("hTpcSignalData", "Specific energy loss", HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {1400, 0, 1400, "d#it{E} / d#it{X} (a. u.)"}}); + spectra.add("hTpcSignalDataSelected", "Specific energy loss for selected particles", HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {1400, 0, 1400, "d#it{E} / d#it{X} (a. u.)"}}); + spectra.add("hTofSignalData", "TOF beta", HistType::kTH2F, {{500, 0., 5., "#it{p} (GeV/#it{c})"}, {750, 0, 1.5, "TOF #beta"}}); + + for (int iS{0}; iS < nuclei::species; ++iS) { + for (int iMax{0}; iMax < 2; ++iMax) { + nuclei::pidCutTPC[iS][iMax] = cfgNsigmaTPC->get(iS, iMax); // changed pidCut to pidCutTPC so that it compiles TODO: check if it is correct + } + } + + nuclei::lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get("GLO/Param/MatLUT")); + } + + template + float getCentrality(Tcoll const& collision) + { + float centrality = 1.; + if constexpr (o2::aod::HasCentrality) { + if (cfgCentralityEstimator == nuclei::centDetectors::kFV0A) { + centrality = collision.centFV0A(); + } else if (cfgCentralityEstimator == nuclei::centDetectors::kFT0M) { + centrality = collision.centFT0M(); + } else if (cfgCentralityEstimator == nuclei::centDetectors::kFT0A) { + centrality = collision.centFT0A(); + } else if (cfgCentralityEstimator == nuclei::centDetectors::kFT0C) { + centrality = collision.centFT0C(); + } else { + LOG(warning) << "Centrality estimator not valid. Possible values: (FV0A: 0, FT0M: 1, FT0A: 2, FT0C: 3). Centrality set to 1."; + } + } + return centrality; + } + + template + void fillDataInfo(Tcoll const& collision, Ttrks const& tracks) + { + auto bc = collision.template bc_as(); + initCCDB(bc); + if (cfgSkimmedProcessing) { + zorro.isSelected(bc.globalBC()); /// Just let Zorro do the accounting + } + gRandom->SetSeed(bc.timestamp()); + + spectra.fill(HIST("hRecVtxZData"), collision.posZ()); + + const o2::math_utils::Point3D collVtx{collision.posX(), collision.posY(), collision.posZ()}; + + const double bgScalings[5][2]{ + {nuclei::charges[0] * cfgMomentumScalingBetheBloch->get(0u, 0u) / nuclei::masses[0], nuclei::charges[0] * cfgMomentumScalingBetheBloch->get(0u, 1u) / nuclei::masses[0]}, + {nuclei::charges[1] * cfgMomentumScalingBetheBloch->get(1u, 0u) / nuclei::masses[1], nuclei::charges[1] * cfgMomentumScalingBetheBloch->get(1u, 1u) / nuclei::masses[1]}, + {nuclei::charges[2] * cfgMomentumScalingBetheBloch->get(2u, 0u) / nuclei::masses[2], nuclei::charges[2] * cfgMomentumScalingBetheBloch->get(2u, 1u) / nuclei::masses[2]}, + {nuclei::charges[3] * cfgMomentumScalingBetheBloch->get(3u, 0u) / nuclei::masses[3], nuclei::charges[3] * cfgMomentumScalingBetheBloch->get(3u, 1u) / nuclei::masses[3]}, + {nuclei::charges[4] * cfgMomentumScalingBetheBloch->get(3u, 0u) / nuclei::masses[4], nuclei::charges[4] * cfgMomentumScalingBetheBloch->get(3u, 1u) / nuclei::masses[4]}}; + + for (auto& track : tracks) { // start loop over tracks + if (std::abs(track.eta()) > cfgCutEta || + track.tpcInnerParam() < cfgCutTpcMom || + track.itsNCls() < cfgCutNclusITS || + track.tpcNClsFound() < cfgCutNclusTPC || + track.tpcNClsCrossedRows() < 70 || + track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || + track.tpcChi2NCl() > 4.f || + track.itsChi2NCl() > 36.f) { + continue; + } + // temporary fix: tpcInnerParam() returns the momentum in all the software tags before + bool heliumPID = track.pidForTracking() == o2::track::PID::Helium3 || track.pidForTracking() == o2::track::PID::Alpha; + float correctedTpcInnerParam = (heliumPID && cfgCompensatePIDinTracking) ? track.tpcInnerParam() / 2 : track.tpcInnerParam(); + + spectra.fill(HIST("hTpcSignalData"), correctedTpcInnerParam * track.sign(), track.tpcSignal()); + const int iC{track.sign() < 0}; + + bool selectedTPC[5]{false}, goodToAnalyse{false}; + std::array nSigmaTPC; + + for (int iS{0}; iS < nuclei::species; ++iS) { + + double expBethe{tpc::BetheBlochAleph(static_cast(correctedTpcInnerParam * bgScalings[iS][iC]), cfgBetheBlochParams->get(iS, 0u), cfgBetheBlochParams->get(iS, 1u), cfgBetheBlochParams->get(iS, 2u), cfgBetheBlochParams->get(iS, 3u), cfgBetheBlochParams->get(iS, 4u))}; + + double expSigma{expBethe * cfgBetheBlochParams->get(iS, 5u)}; + + nSigmaTPC[iS] = static_cast((track.tpcSignal() - expBethe) / expSigma); + + selectedTPC[iS] = (nSigmaTPC[iS] > nuclei::pidCutTPC[iS][0] && nSigmaTPC[iS] < nuclei::pidCutTPC[iS][1]); + + goodToAnalyse = goodToAnalyse || selectedTPC[iS]; + } + if (!goodToAnalyse) { + continue; + } + + setTrackParCov(track, mTrackParCov); + mTrackParCov.setPID(track.pidForTracking()); + + gpu::gpustd::array dcaInfo; + o2::base::Propagator::Instance()->propagateToDCA(collVtx, mTrackParCov, mBz, 2.f, static_cast(cfgMaterialCorrection.value), &dcaInfo); + + float beta{o2::pid::tof::Beta::GetBeta(track)}; + spectra.fill(HIST("hTpcSignalDataSelected"), correctedTpcInnerParam * track.sign(), track.tpcSignal()); + spectra.fill(HIST("hTofSignalData"), correctedTpcInnerParam, beta); + beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked + uint16_t flag = static_cast((track.pidForTracking() & 0xF) << 12); + std::array tofMasses{-3.f, -3.f, -3.f, -3.f, -3.f}; + bool fillTree{true}; // set to true and never used again + bool fillDCAHist{false}; + bool correctPV{false}; + bool isSecondary{false}; + bool fromWeakDecay{false}; + + if (track.hasTOF()) { + flag |= kHasTOF; + } + if (track.hasTRD()) { + flag |= kHasTRD; + } + if (!collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + flag |= kITSrof; + } + for (int iS{0}; iS < nuclei::species; ++iS) { + bool selectedTOF{false}; + if (std::abs(dcaInfo[1]) > cfgDCAcut->get(iS, 1)) { + continue; + } + ROOT::Math::LorentzVector> fvector{mTrackParCov.getPt() * nuclei::charges[iS], mTrackParCov.getEta(), mTrackParCov.getPhi(), nuclei::masses[iS]}; + if (selectedTPC[iS]) { + if (track.hasTOF()) { + selectedTOF = true; /// temporarly skipped + float charge{1.f + static_cast(iS == 3 || iS == 4)}; + tofMasses[iS] = correctedTpcInnerParam * charge * std::sqrt(1.f / (beta * beta) - 1.f) - nuclei::masses[iS]; + } + if (cfgTreeConfig->get(iS, 1u) && !selectedTOF) { + continue; + } + bool setPartFlag = cfgTreeConfig->get(iS, 0u); + if (setPartFlag) { + if (cfgDownscaling->get(iS) < 1. && gRandom->Rndm() > cfgDownscaling->get(iS)) { + continue; + } + flag |= BIT(iS); + } + } + } + if (flag & (kProton | kDeuteron | kTriton | kHe3 | kHe4) /*|| doprocessMC*/) { /// ignore PID pre-selections for the MC + if constexpr (requires { + collision.psiFT0A(); + }) { + nuclei::candidates_flow.emplace_back(NucleusCandidateFlow{ + collision.centFV0A(), + collision.centFT0M(), + collision.centFT0A(), + collision.centFT0C(), + collision.psiFT0A(), + collision.psiFT0C(), + collision.psiTPC(), + collision.psiTPCL(), + collision.psiTPCR(), + collision.qFT0A(), + collision.qFT0C(), + collision.qTPC(), + collision.qTPCL(), + collision.qTPCR(), + }); + } else if constexpr (requires { + collision.qvecFT0AImVec()[cfgHarmonics - 2]; + }) { + nuclei::candidates_flow.emplace_back(NucleusCandidateFlow{ + collision.centFV0A(), + collision.centFT0M(), + collision.centFT0A(), + collision.centFT0C(), + computeEventPlane(collision.qvecFT0AImVec()[cfgHarmonics - 2], collision.qvecFT0AReVec()[cfgHarmonics - 2]), + computeEventPlane(collision.qvecFT0CImVec()[cfgHarmonics - 2], collision.qvecFT0CReVec()[cfgHarmonics - 2]), + computeEventPlane(collision.qvecTPCallImVec()[cfgHarmonics - 2], collision.qvecTPCallReVec()[cfgHarmonics - 2]), + computeEventPlane(collision.qvecTPCnegImVec()[cfgHarmonics - 2], collision.qvecTPCnegReVec()[cfgHarmonics - 2]), + computeEventPlane(collision.qvecTPCposImVec()[cfgHarmonics - 2], collision.qvecTPCposReVec()[cfgHarmonics - 2]), + collision.sumAmplFT0A(), + collision.sumAmplFT0C(), + static_cast(collision.nTrkTPCall()), + static_cast(collision.nTrkTPCneg()), + static_cast(collision.nTrkTPCpos())}); + } + if (flag & kTriton) { + if (track.pt() < cfgCutPtMinTree || track.pt() > cfgCutPtMaxTree || track.sign() > 0) + continue; + } + nuclei::candidates.emplace_back(NucleusCandidate{ + static_cast(track.globalIndex()), static_cast(track.collisionId()), (1 - 2 * iC) * mTrackParCov.getPt(), mTrackParCov.getEta(), mTrackParCov.getPhi(), + correctedTpcInnerParam, beta, collision.posZ(), dcaInfo[0], dcaInfo[1], track.tpcSignal(), track.itsChi2NCl(), track.tpcChi2NCl(), track.tofChi2(), + nSigmaTPC, tofMasses, fillTree, fillDCAHist, correctPV, isSecondary, fromWeakDecay, flag, track.tpcNClsFindable(), static_cast(track.tpcNClsCrossedRows()), track.itsClusterMap(), + static_cast(track.tpcNClsFound()), static_cast(track.tpcNClsShared()), static_cast(track.itsNCls()), static_cast(track.itsClusterSizes())}); + } + } // end loop over tracks + } + + void processDataFlow(CollWithEP const& collision, TrackCandidates const& tracks, aod::BCsWithTimestamps const&) + { + nuclei::candidates.clear(); + nuclei::candidates_flow.clear(); + if (!eventSelectionWithHisto(collision)) { + return; + } + fillDataInfo(collision, tracks); + for (auto& c : nuclei::candidates) { + nucleiTable(c.pt, c.eta, c.phi, c.tpcInnerParam, c.beta, c.zVertex, c.DCAxy, c.DCAz, c.TPCsignal, c.ITSchi2, c.TPCchi2, c.TOFchi2, c.flags, c.TPCfindableCls, c.TPCcrossedRows, c.ITSclsMap, c.TPCnCls, c.TPCnClsShared, c.clusterSizesITS); + } + for (auto& c : nuclei::candidates_flow) { + nucleiTableFlow(c.centFV0A, c.centFT0M, c.centFT0A, c.centFT0C, c.psiFT0A, c.psiFT0C, c.psiTPC, c.psiTPCl, c.psiTPCr, c.qFT0A, c.qFT0C, c.qTPC, c.qTPCl, c.qTPCr); + } + } + PROCESS_SWITCH(nucleiFlowTree, processDataFlow, "Data analysis with flow", true); + + void processDataFlowAlternative(CollWithQvec const& collision, TrackCandidates const& tracks, aod::BCsWithTimestamps const&) + { + nuclei::candidates.clear(); + nuclei::candidates_flow.clear(); + if (!eventSelectionWithHisto(collision)) { + return; + } + fillDataInfo(collision, tracks); + for (auto& c : nuclei::candidates) { + nucleiTable(c.pt, c.eta, c.phi, c.tpcInnerParam, c.beta, c.zVertex, c.DCAxy, c.DCAz, c.TPCsignal, c.ITSchi2, c.TPCchi2, c.TOFchi2, c.flags, c.TPCfindableCls, c.TPCcrossedRows, c.ITSclsMap, c.TPCnCls, c.TPCnClsShared, c.clusterSizesITS); + } + for (auto& c : nuclei::candidates_flow) { + nucleiTableFlow(c.centFV0A, c.centFT0M, c.centFT0A, c.centFT0C, c.psiFT0A, c.psiFT0C, c.psiTPC, c.psiTPCl, c.psiTPCr, c.qFT0A, c.qFT0C, c.qTPC, c.qTPCl, c.qTPCr); + } + } + PROCESS_SWITCH(nucleiFlowTree, processDataFlowAlternative, "Data analysis with flow - alternative framework", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"nuclei-flow-trees"})}; +} diff --git a/PWGLF/TableProducer/Nuspex/nucleiSpectra.cxx b/PWGLF/TableProducer/Nuspex/nucleiSpectra.cxx index 57d20a7052a..134a1a150cf 100644 --- a/PWGLF/TableProducer/Nuspex/nucleiSpectra.cxx +++ b/PWGLF/TableProducer/Nuspex/nucleiSpectra.cxx @@ -19,7 +19,11 @@ // o2-analysis-pid-tof-base, o2-analysis-multiplicity-table, o2-analysis-event-selection // (to add flow: o2-analysis-qvector-table, o2-analysis-centrality-table) +#include #include +#include +#include +#include #include "Math/Vector4D.h" @@ -31,11 +35,14 @@ #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" #include "Common/DataModel/TrackSelectionTables.h" #include "Common/Core/PID/PIDTOF.h" #include "Common/TableProducer/PID/pidTOFBase.h" #include "Common/Core/EventPlaneHelper.h" -#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/Tools/TrackTuner.h" +#include "Common/Core/RecoDecay.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" @@ -43,6 +50,9 @@ #include "DetectorsBase/GeometryManager.h" #include "DetectorsBase/Propagator.h" +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" + #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/ASoAHelpers.h" @@ -51,6 +61,7 @@ #include "ReconstructionDataFormats/Track.h" +#include "PWGLF/DataModel/EPCalibrationTables.h" #include "PWGLF/DataModel/LFSlimNucleiTables.h" #include "TRandom3.h" @@ -62,6 +73,7 @@ using namespace o2::constants::physics; struct NucleusCandidate { int globalIndex; + int collTrackIndex; float pt; float eta; float phi; @@ -73,11 +85,21 @@ struct NucleusCandidate { float TPCsignal; float ITSchi2; float TPCchi2; + float TOFchi2; + std::array nSigmaTPC; + std::array tofMasses; + bool fillTree; + bool fillDCAHist; + bool correctPV; + bool isSecondary; + bool fromWeakDecay; uint16_t flags; uint8_t TPCfindableCls; uint8_t TPCcrossedRows; uint8_t ITSclsMap; uint8_t TPCnCls; + uint8_t TPCnClsShared; + uint8_t ITSnCls; uint32_t clusterSizesITS; }; @@ -87,13 +109,15 @@ struct NucleusCandidateFlow { float centFT0A; float centFT0C; float psiFT0A; - float multFT0A; float psiFT0C; - float multFT0C; float psiTPC; float psiTPCl; float psiTPCr; - int multTPC; + float qFT0A; + float qFT0C; + float qTPC; + float qTPCl; + float qTPCr; }; namespace nuclei @@ -140,6 +164,12 @@ constexpr int FlowHistDefault[5][1]{ {0}, {0}, {0}}; +constexpr int DCAHistDefault[5][2]{ + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}}; constexpr double DownscalingDefault[5][1]{ {1.}, {1.}, @@ -156,6 +186,7 @@ static const std::vector pidName{"TPC", "TOF"}; static const std::vector names{"proton", "deuteron", "triton", "He3", "alpha"}; static const std::vector treeConfigNames{"Filter trees", "Use TOF selection"}; static const std::vector flowConfigNames{"Save flow hists"}; +static const std::vector DCAConfigNames{"Save DCA hist", "Matter/Antimatter"}; static const std::vector nSigmaConfigName{"nsigma_min", "nsigma_max"}; static const std::vector nDCAConfigName{"max DCAxy", "max DCAz"}; static const std::vector DownscalingConfigName{"Fraction of kept candidates"}; @@ -175,6 +206,9 @@ std::shared_ptr hDCAz[2][5][2]; std::shared_ptr hGloTOFtracks[2]; std::shared_ptr hDeltaP[2][5]; std::shared_ptr hFlowHists[2][5]; +std::shared_ptr hDCAHists[2][5]; +std::shared_ptr hMatchingStudy[2]; +std::shared_ptr hMatchingStudyHadrons[2]; o2::base::MatLayerCylSet* lut = nullptr; std::vector candidates; @@ -188,6 +222,31 @@ enum centDetectors { }; static const std::vector centDetectorNames{"FV0A", "FT0M", "FT0A", "FT0C"}; + +enum evSel { + kTVX = 0, + kZvtx, + kTFborder, + kITSROFborder, + kNoSameBunchPileup, + kIsGoodZvtxFT0vsPV, + kIsGoodITSLayersAll, + kIsEPtriggered, + kNevSels +}; + +static const std::vector eventSelectionTitle{"Event selections"}; +static const std::vector eventSelectionLabels{"TVX", "Z vtx", "TF border", "ITS ROF border", "No same-bunch pile-up", "kIsGoodZvtxFT0vsPV", "isGoodITSLayersAll", "isEPtriggered"}; + +constexpr int EvSelDefault[8][1]{ + {1}, + {1}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}}; } // namespace nuclei struct nucleiSpectra { @@ -210,6 +269,9 @@ struct nucleiSpectra { Produces nucleiTableMC; Produces nucleiTableFlow; Service ccdb; + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + TrackTuner trackTunerObj; Configurable cfgCompensatePIDinTracking{"cfgCompensatePIDinTracking", false, "If true, divide tpcInnerParam by the electric charge"}; @@ -223,6 +285,10 @@ struct nucleiSpectra { Configurable cfgCutOnReconstructedRapidity{"cfgCutOnReconstructedRapidity", false, "Cut on reconstructed rapidity"}; Configurable cfgCutNclusITS{"cfgCutNclusITS", 5, "Minimum number of ITS clusters"}; Configurable cfgCutNclusTPC{"cfgCutNclusTPC", 70, "Minimum number of TPC clusters"}; + Configurable cfgCutPtMinTree{"cfgCutPtMinTree", 0.2f, "Minimum track transverse momentum for tree saving"}; + Configurable cfgCutPtMaxTree{"cfgCutPtMaxTree", 15.0f, "Maximum track transverse momentum for tree saving"}; + + Configurable> cfgEventSelections{"cfgEventSelections", {nuclei::EvSelDefault[0], 8, 1, nuclei::eventSelectionLabels, nuclei::eventSelectionTitle}, "Event selections"}; Configurable> cfgMomentumScalingBetheBloch{"cfgMomentumScalingBetheBloch", {nuclei::bbMomScalingDefault[0], 5, 2, nuclei::names, nuclei::chargeLabelNames}, "TPC Bethe-Bloch momentum scaling for light nuclei"}; Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {nuclei::betheBlochDefault[0], 5, 6, nuclei::names, nuclei::betheBlochParNames}, "TPC Bethe-Bloch parameterisation for light nuclei"}; @@ -230,8 +296,11 @@ struct nucleiSpectra { Configurable> cfgDCAcut{"cfgDCAcut", {nuclei::DCAcutDefault[0], 5, 2, nuclei::names, nuclei::nDCAConfigName}, "Max DCAxy and DCAz for light nuclei"}; Configurable> cfgDownscaling{"cfgDownscaling", {nuclei::DownscalingDefault[0], 5, 1, nuclei::names, nuclei::DownscalingConfigName}, "Fraction of kept candidates for light nuclei"}; Configurable> cfgTreeConfig{"cfgTreeConfig", {nuclei::TreeConfigDefault[0], 5, 2, nuclei::names, nuclei::treeConfigNames}, "Filtered trees configuration"}; + Configurable> cfgDCAHists{"cfgDCAHists", {nuclei::DCAHistDefault[0], 5, 2, nuclei::names, nuclei::DCAConfigNames}, "DCA hist configuration"}; Configurable> cfgFlowHist{"cfgFlowHist", {nuclei::FlowHistDefault[0], 5, 1, nuclei::names, nuclei::flowConfigNames}, "Flow hist configuration"}; + Configurable cfgNsigmaTPCcutDCAhists{"cfgNsigmaTPCcutDCAhists", 3., "TPC nsigma cut for DCA hists"}; + Configurable cfgDeltaTOFmassCutDCAhists{"cfgDeltaTOFmassCutDCAhists", 0.2, "Delta TOF mass cut for DCA hists"}; ConfigurableAxis cfgDCAxyBinsProtons{"cfgDCAxyBinsProtons", {1500, -1.5f, 1.5f}, "DCAxy binning for Protons"}; ConfigurableAxis cfgDCAxyBinsDeuterons{"cfgDCAxyBinsDeuterons", {1500, -1.5f, 1.5f}, "DCAxy binning for Deuterons"}; ConfigurableAxis cfgDCAxyBinsTritons{"cfgDCAxyBinsTritons", {1500, -1.5f, 1.5f}, "DCAxy binning for Tritons"}; @@ -253,15 +322,24 @@ struct nucleiSpectra { ConfigurableAxis cfgNITSClusBins{"cfgNITSClusBins", {3, 4.5, 7.5}, "N ITS clusters binning"}; ConfigurableAxis cfgNTPCClusBins{"cfgNTPCClusBins", {3, 89.5, 159.5}, "N TPC clusters binning"}; + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; + + // configurables for track tuner + Configurable cfgUseTrackTuner{"cfgUseTrackTuner", false, "Apply track tuner corrections to MC tracks"}; + Configurable cfgTrackTunerParams{"cfgTrackTunerParams", "debugInfo=0|updateTrackDCAs=1|updateTrackCovMat=1|updateCurvature=0|updateCurvatureIU=0|updatePulls=1|isInputFileFromCCDB=1|pathInputFile=Users/m/mfaggin/test/inputsTrackTuner/pp2023/smoothHighPtMC|nameInputFile=trackTuner_DataLHC23fPass1_McLHC23k4b_run535085.root|pathFileQoverPt=Users/h/hsharma/qOverPtGraphs|nameFileQoverPt=D0sigma_Data_removal_itstps_MC_LHC22b1b.root|usePvRefitCorrections=0|qOverPtMC=-1.|qOverPtData=-1.", "TrackTuner parameter initialization (format: =|=)"}; + // running variables for track tuner + o2::dataformats::DCA mDcaInfoCov; + o2::track::TrackParametrizationWithError mTrackParCov; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + // CCDB options Configurable cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrLUT), "Type of material correction"}; Configurable cfgCCDBurl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable cfgZorroCCDBpath{"cfgZorroCCDBpath", "/Users/m/mpuccio/EventFiltering/OTS/", "path to the zorro ccdb objects"}; int mRunNumber = 0; float mBz = 0.f; - Filter trackFilter = nabs(aod::track::eta) < cfgCutEta && aod::track::tpcInnerParam > cfgCutTpcMom; - - using TrackCandidates = soa::Filtered>; + using TrackCandidates = soa::Join; // Collisions with chentrality using CollWithCent = soa::Join::iterator; @@ -269,20 +347,9 @@ struct nucleiSpectra { // Flow analysis using CollWithEP = soa::Join::iterator; - HistogramRegistry spectra{"spectra", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - o2::pid::tof::Beta responseBeta; + using CollWithQvec = soa::Join::iterator; - double getPhiInRange(double phi) - { - double result = phi; - while (result < 0) { - result = result + 2. * TMath::Pi() / 2; - } - while (result > 2. * TMath::Pi() / 2) { - result = result - 2. * TMath::Pi() / 2; - } - return result; - } + HistogramRegistry spectra{"spectra", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; double computeAbsoDecL(aod::McParticles::iterator particle) { @@ -303,10 +370,68 @@ struct nucleiSpectra { return std::hypot(mothVtx[0] - dauVtx[0], mothVtx[1] - dauVtx[1], mothVtx[2] - dauVtx[2]); } + float computeEventPlane(float y, float x) + { + return 0.5 * std::atan2(y, x); + } + template bool eventSelection(collision_t& collision) { - return collision.sel8() && collision.posZ() > -cfgCutVertex && collision.posZ() < cfgCutVertex && collision.selection_bit(aod::evsel::kNoTimeFrameBorder); + return collision.selection_bit(aod::evsel::kIsTriggerTVX) && collision.posZ() > -cfgCutVertex && collision.posZ() < cfgCutVertex && collision.selection_bit(aod::evsel::kNoTimeFrameBorder); + } + + template + bool eventSelectionWithHisto(Tcoll& collision) + { + spectra.fill(HIST("hEventSelections"), 0); + + if (cfgEventSelections->get(nuclei::evSel::kTVX) && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + spectra.fill(HIST("hEventSelections"), nuclei::evSel::kTVX + 1); + + if (cfgEventSelections->get(nuclei::evSel::kZvtx) && std::abs(collision.posZ()) > cfgCutVertex) { + return false; + } + spectra.fill(HIST("hEventSelections"), nuclei::evSel::kZvtx + 1); + + if (cfgEventSelections->get(nuclei::evSel::kTFborder) && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } + spectra.fill(HIST("hEventSelections"), nuclei::evSel::kTFborder + 1); + + if (cfgEventSelections->get(nuclei::evSel::kITSROFborder) && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return false; + } + spectra.fill(HIST("hEventSelections"), nuclei::evSel::kITSROFborder + 1); + + if (cfgEventSelections->get(nuclei::evSel::kNoSameBunchPileup) && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + spectra.fill(HIST("hEventSelections"), nuclei::evSel::kNoSameBunchPileup + 1); + + if (cfgEventSelections->get(nuclei::evSel::kIsGoodZvtxFT0vsPV) && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + spectra.fill(HIST("hEventSelections"), nuclei::evSel::kIsGoodZvtxFT0vsPV + 1); + + if (cfgEventSelections->get(nuclei::evSel::kIsGoodITSLayersAll) && !collision.selection_bit(aod::evsel::kIsGoodITSLayersAll)) { + return false; + } + spectra.fill(HIST("hEventSelections"), nuclei::evSel::kIsGoodITSLayersAll + 1); + + if constexpr ( + requires { + collision.triggereventep(); + }) { + if (cfgEventSelections->get(nuclei::evSel::kIsEPtriggered) && !collision.triggereventep()) { + return false; + } + spectra.fill(HIST("hEventSelections"), nuclei::evSel::kIsEPtriggered + 1); + } + + return true; } void initCCDB(aod::BCsWithTimestamps::iterator const& bc) @@ -314,17 +439,24 @@ struct nucleiSpectra { if (mRunNumber == bc.runNumber()) { return; } + if (cfgSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), "fHe"); + zorro.populateHistRegistry(spectra, bc.runNumber()); + } auto timestamp = bc.timestamp(); mRunNumber = bc.runNumber(); o2::parameters::GRPMagField* grpmag = ccdb->getForTimeStamp("GLO/Config/GRPMagField", timestamp); o2::base::Propagator::initFieldFromGRP(grpmag); + o2::base::Propagator::Instance()->setMatLUT(nuclei::lut); mBz = static_cast(grpmag->getNominalL3Field()); LOGF(info, "Retrieved GRP for timestamp %ull (%i) with magnetic field of %1.2f kZG", timestamp, mRunNumber, mBz); } void init(o2::framework::InitContext&) { + zorroSummary.setObject(zorro.getZorroSummary()); + zorro.setBaseCCDBPath(cfgZorroCCDBpath.value); ccdb->setURL(cfgCCDBurl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); @@ -338,6 +470,9 @@ struct nucleiSpectra { const AxisSpec nITSClusAxis{cfgNITSClusBins, "N ITS clusters"}; const AxisSpec nTPCClusAxis{cfgNTPCClusBins, "N TPC clusters"}; const AxisSpec hasTRDAxis{2, -0.5, 1.5, "Has TRD"}; + const AxisSpec correctPVAxis{2, -0.5, 1.5, "Correct PV"}; + const AxisSpec isSecondaryAxis{2, -0.5, 1.5, "Is secondary"}; + const AxisSpec fromWeakDecayAxis{2, -0.5, 1.5, "From weak decay"}; const AxisSpec ptAxes[5]{ {cfgPtBinsProtons, "#it{p}_{T} (GeV/#it{c})"}, @@ -359,7 +494,21 @@ struct nucleiSpectra { {cfgDCAxyBinsAlpha, "DCA_{z} (cm)"}}; const AxisSpec etaAxis{40, -1., 1., "#eta"}; + spectra.add("hEventSelections", "hEventSelections", {HistType::kTH1D, {{nuclei::evSel::kNevSels + 1, -0.5f, static_cast(nuclei::evSel::kNevSels) + 0.5f}}}); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(1, "all"); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(nuclei::evSel::kTVX + 2, "TVX"); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(nuclei::evSel::kZvtx + 2, "Zvtx"); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(nuclei::evSel::kTFborder + 2, "TFborder"); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(nuclei::evSel::kITSROFborder + 2, "ITSROFborder"); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(nuclei::evSel::kNoSameBunchPileup + 2, "kNoSameBunchPileup"); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(nuclei::evSel::kIsGoodZvtxFT0vsPV + 2, "isGoodZvtxFT0vsPV"); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(nuclei::evSel::kIsGoodITSLayersAll + 2, "IsGoodITSLayersAll"); + spectra.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(nuclei::evSel::kIsEPtriggered + 2, "IsEPtriggered"); + spectra.add("hRecVtxZData", "collision z position", HistType::kTH1F, {{200, -20., +20., "z position (cm)"}}); + if (doprocessMC) { + spectra.add("hGenVtxZ", " generated collision z position", HistType::kTH1F, {{200, -20., +20., "z position (cm)"}}); + } spectra.add("hRecVtxZDataITSrof", "collision z position", HistType::kTH1F, {{200, -20., +20., "z position (cm)"}}); spectra.add("hTpcSignalData", "Specific energy loss", HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {1400, 0, 1400, "d#it{E} / d#it{X} (a. u.)"}}); spectra.add("hTpcSignalDataSelected", "Specific energy loss for selected particles", HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {1400, 0, 1400, "d#it{E} / d#it{X} (a. u.)"}}); @@ -381,11 +530,14 @@ struct nucleiSpectra { if (doprocessMC) { nuclei::hMomRes[iS][iC] = spectra.add(fmt::format("h{}MomRes{}", nuclei::matter[iC], nuclei::names[iS]).data(), fmt::format("Momentum resolution {}", nuclei::names[iS]).data(), HistType::kTH3D, {centAxis, ptAxes[iS], ptResAxis}); nuclei::hGenNuclei[iS][iC] = spectra.add(fmt::format("h{}Gen{}", nuclei::matter[iC], nuclei::names[iS]).data(), fmt::format("Generated {}", nuclei::names[iS]).data(), HistType::kTH2D, {centAxis, ptAxes[iS]}); - } - if (doprocessDataFlow) { - if (cfgFlowHist->get(iS)) { - nuclei::hFlowHists[iC][iS] = spectra.add(fmt::format("hFlowHists{}_{}", nuclei::matter[iC], nuclei::names[iS]).data(), fmt::format("Flow histograms {} {}", nuclei::matter[iC], nuclei::names[iS]).data(), HistType::kTHnSparseF, {centAxis, ptAxes[iS], nSigmaAxes[0], tofMassAxis, v2Axis, nITSClusAxis, nTPCClusAxis, hasTRDAxis}); + nuclei::hDCAHists[iC][iS] = spectra.add(fmt::format("hDCAHists{}_{}", nuclei::matter[iC], nuclei::names[iS]).data(), fmt::format("DCA histograms {} {}", nuclei::matter[iC], nuclei::names[iS]).data(), HistType::kTHnSparseF, {ptAxes[iS], dcaxyAxes[iS], dcazAxes[iS], nSigmaAxes[0], tofMassAxis, nITSClusAxis, nTPCClusAxis, correctPVAxis, isSecondaryAxis, fromWeakDecayAxis}); + } else { + if (doprocessDataFlow) { + if (cfgFlowHist->get(iS)) { + nuclei::hFlowHists[iC][iS] = spectra.add(fmt::format("hFlowHists{}_{}", nuclei::matter[iC], nuclei::names[iS]).data(), fmt::format("Flow histograms {} {}", nuclei::matter[iC], nuclei::names[iS]).data(), HistType::kTHnSparseF, {centAxis, ptAxes[iS], nSigmaAxes[0], tofMassAxis, v2Axis, nITSClusAxis, nTPCClusAxis}); + } } + nuclei::hDCAHists[iC][iS] = spectra.add(fmt::format("hDCAHists{}_{}", nuclei::matter[iC], nuclei::names[iS]).data(), fmt::format("DCA histograms {} {}", nuclei::matter[iC], nuclei::names[iS]).data(), HistType::kTHnSparseF, {ptAxes[iS], dcaxyAxes[iS], dcazAxes[iS], nSigmaAxes[0], tofMassAxis, nITSClusAxis, nTPCClusAxis}); } } } @@ -396,15 +548,29 @@ struct nucleiSpectra { } } + if (doprocessMatching) { + std::vector occBins{-0.5, 499.5, 999.5, 1999.5, 2999.5, 3999.5, 4999.5, 10000., 50000.}; + AxisSpec occAxis{occBins, "Occupancy"}; + for (int iC{0}; iC < 2; ++iC) { + nuclei::hMatchingStudy[iC] = spectra.add(fmt::format("hMatchingStudy{}", nuclei::matter[iC]).data(), ";#it{p}_{T};#phi;#eta;n#sigma_{ITS};n#sigma{TPC};n#sigma_{TOF};Centrality", HistType::kTHnSparseF, {{20, 1., 9.}, {10, 0., o2::constants::math::TwoPI}, {10, -1., 1.}, {50, -5., 5.}, {50, -5., 5.}, {50, 0., 1.}, {8, 0., 80.}}); + nuclei::hMatchingStudyHadrons[iC] = spectra.add(fmt::format("hMatchingStudyHadrons{}", nuclei::matter[iC]).data(), ";#it{p}_{T};#phi;#eta;Centrality;Track type; Occupancy", HistType::kTHnF, {{23, 0.4, 5.}, {20, 0., o2::constants::math::TwoPI}, {10, -1., 1.}, {8, 0., 80.}, {2, -0.5, 1.5}, occAxis}); + } + } + nuclei::lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get("GLO/Param/MatLUT")); - o2::base::Propagator::Instance(true)->setMatLUT(nuclei::lut); + // TrackTuner initialization + if (cfgUseTrackTuner) { + std::string outputStringParams = trackTunerObj.configParams(cfgTrackTunerParams); + spectra.add("hTrackTunedTracks", outputStringParams.c_str(), HistType::kTH1F, {{1, 0.5, 1.5, ""}}); + trackTunerObj.getDcaGraphs(); + } } template float getCentrality(Tcoll const& collision) { float centrality = 1.; - if constexpr (std::is_same::value || std::is_same::value) { + if constexpr (o2::aod::HasCentrality) { if (cfgCentralityEstimator == nuclei::centDetectors::kFV0A) { centrality = collision.centFV0A(); } else if (cfgCentralityEstimator == nuclei::centDetectors::kFT0M) { @@ -425,6 +591,9 @@ struct nucleiSpectra { { auto bc = collision.template bc_as(); initCCDB(bc); + if (cfgSkimmedProcessing) { + zorro.isSelected(bc.globalBC()); /// Just let Zorro do the accounting + } gRandom->SetSeed(bc.timestamp()); spectra.fill(HIST("hRecVtxZData"), collision.posZ()); @@ -446,7 +615,9 @@ struct nucleiSpectra { int nGloTracks[2]{0, 0}, nTOFTracks[2]{0, 0}; for (auto& track : tracks) { // start loop over tracks - if (track.itsNCls() < cfgCutNclusITS || + if (std::abs(track.eta()) > cfgCutEta || + track.tpcInnerParam() < cfgCutTpcMom || + track.itsNCls() < cfgCutNclusITS || track.tpcNClsFound() < cfgCutNclusTPC || track.tpcNClsCrossedRows() < 70 || track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || @@ -454,7 +625,6 @@ struct nucleiSpectra { track.itsChi2NCl() > 36.f) { continue; } - // temporary fix: tpcInnerParam() returns the momentum in all the software tags before bool heliumPID = track.pidForTracking() == o2::track::PID::Helium3 || track.pidForTracking() == o2::track::PID::Alpha; float correctedTpcInnerParam = (heliumPID && cfgCompensatePIDinTracking) ? track.tpcInnerParam() / 2 : track.tpcInnerParam(); @@ -472,10 +642,12 @@ struct nucleiSpectra { } bool selectedTPC[5]{false}, goodToAnalyse{false}; + std::array nSigmaTPC; for (int iS{0}; iS < nuclei::species; ++iS) { double expBethe{tpc::BetheBlochAleph(static_cast(correctedTpcInnerParam * bgScalings[iS][iC]), cfgBetheBlochParams->get(iS, 0u), cfgBetheBlochParams->get(iS, 1u), cfgBetheBlochParams->get(iS, 2u), cfgBetheBlochParams->get(iS, 3u), cfgBetheBlochParams->get(iS, 4u))}; double expSigma{expBethe * cfgBetheBlochParams->get(iS, 5u)}; nSigma[0][iS] = static_cast((track.tpcSignal() - expBethe) / expSigma); + nSigmaTPC[iS] = nSigma[0][iS]; selectedTPC[iS] = (nSigma[0][iS] > nuclei::pidCuts[0][iS][0] && nSigma[0][iS] < nuclei::pidCuts[0][iS][1]); goodToAnalyse = goodToAnalyse || selectedTPC[iS]; if (selectedTPC[iS] && track.p() > 0.2) { @@ -486,15 +658,38 @@ struct nucleiSpectra { continue; } - auto trackParCov = getTrackParCov(track); // should we set the charge according to the nucleus? + mDcaInfoCov.set(999, 999, 999, 999, 999); + setTrackParCov(track, mTrackParCov); + mTrackParCov.setPID(track.pidForTracking()); + if constexpr ( + requires { + track.has_mcParticle(); + }) { + if (cfgUseTrackTuner) { + bool hasMcParticle = track.has_mcParticle(); + if (hasMcParticle) { + spectra.get(HIST("hTrackTunedTracks"))->Fill(1); // all tracks + auto mcParticle = track.mcParticle(); + trackTunerObj.tuneTrackParams(mcParticle, mTrackParCov, matCorr, &mDcaInfoCov, spectra.get(HIST("hTrackTunedTracks"))); + } + } + } + gpu::gpustd::array dcaInfo; - o2::base::Propagator::Instance()->propagateToDCA(collVtx, trackParCov, mBz, 2.f, static_cast(cfgMaterialCorrection.value), &dcaInfo); + o2::base::Propagator::Instance()->propagateToDCA(collVtx, mTrackParCov, mBz, 2.f, static_cast(cfgMaterialCorrection.value), &dcaInfo); - float beta{responseBeta.GetBeta(track)}; + float beta{o2::pid::tof::Beta::GetBeta(track)}; spectra.fill(HIST("hTpcSignalDataSelected"), correctedTpcInnerParam * track.sign(), track.tpcSignal()); spectra.fill(HIST("hTofSignalData"), correctedTpcInnerParam, beta); beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked uint16_t flag = static_cast((track.pidForTracking() & 0xF) << 12); + std::array tofMasses{-3.f, -3.f, -3.f, -3.f, -3.f}; + bool fillTree{false}; + bool fillDCAHist{false}; + bool correctPV{false}; + bool isSecondary{false}; + bool fromWeakDecay{false}; + if (track.hasTOF()) { flag |= kHasTOF; } @@ -509,71 +704,119 @@ struct nucleiSpectra { if (std::abs(dcaInfo[1]) > cfgDCAcut->get(iS, 1)) { continue; } - ROOT::Math::LorentzVector> fvector{trackParCov.getPt() * nuclei::charges[iS], trackParCov.getEta(), trackParCov.getPhi(), nuclei::masses[iS]}; + ROOT::Math::LorentzVector> fvector{mTrackParCov.getPt() * nuclei::charges[iS], mTrackParCov.getEta(), mTrackParCov.getPhi(), nuclei::masses[iS]}; float y{fvector.Rapidity() + cfgCMrapidity}; - - for (int iPID{0}; iPID < 2; ++iPID) { + for (int iPID{0}; iPID < 2; ++iPID) { /// 0 TPC, 1 TOF if (selectedTPC[iS]) { if (iPID && !track.hasTOF()) { continue; } else if (iPID) { - selectedTOF = true; + selectedTOF = true; /// temporarly skipped + float charge{1.f + static_cast(iS == 3 || iS == 4)}; + tofMasses[iS] = correctedTpcInnerParam * charge * std::sqrt(1.f / (beta * beta) - 1.f) - nuclei::masses[iS]; } if (!cfgCutOnReconstructedRapidity || (y > cfgCutRapidityMin && y < cfgCutRapidityMax)) { - nuclei::hDCAxy[iPID][iS][iC]->Fill(centrality, fvector.pt(), dcaInfo[0]); - nuclei::hDCAz[iPID][iS][iC]->Fill(centrality, fvector.pt(), dcaInfo[1]); + if (std::abs(nSigmaTPC[iS]) < cfgNsigmaTPCcutDCAhists && (!iPID || std::abs(tofMasses[iS]) < cfgDeltaTOFmassCutDCAhists)) { + nuclei::hDCAxy[iPID][iS][iC]->Fill(centrality, fvector.pt(), dcaInfo[0]); + nuclei::hDCAz[iPID][iS][iC]->Fill(centrality, fvector.pt(), dcaInfo[1]); + } if (std::abs(dcaInfo[0]) < cfgDCAcut->get(iS, 0u)) { - float tofMass = -10.f; if (!iPID) { /// temporary exclusion of the TOF nsigma PID for the He3 and Alpha nuclei::hNsigma[iPID][iS][iC]->Fill(centrality, fvector.pt(), nSigma[iPID][iS]); nuclei::hNsigmaEta[iPID][iS][iC]->Fill(fvector.eta(), fvector.pt(), nSigma[iPID][iS]); } if (iPID) { - tofMass = correctedTpcInnerParam * std::sqrt(1.f / (beta * beta) - 1.f) - nuclei::masses[iS]; - nuclei::hTOFmass[iS][iC]->Fill(centrality, fvector.pt(), tofMass); - nuclei::hTOFmassEta[iS][iC]->Fill(fvector.eta(), fvector.pt(), tofMass); + nuclei::hTOFmass[iS][iC]->Fill(centrality, fvector.pt(), tofMasses[iS]); + nuclei::hTOFmassEta[iS][iC]->Fill(fvector.eta(), fvector.pt(), tofMasses[iS]); } if (cfgFlowHist->get(iS) && doprocessDataFlow) { - if constexpr (std::is_same::value) { - auto deltaPhiInRange = getPhiInRange(fvector.phi() - collision.psiFT0C()); - auto v2 = TMath::Cos(2.0 * deltaPhiInRange); - nuclei::hFlowHists[iC][iS]->Fill(collision.centFT0C(), fvector.pt(), nSigma[0][iS], tofMass, v2, track.itsNCls(), track.tpcNClsFound(), track.hasTRD()); + if constexpr (requires { + collision.psiFT0C(); + }) { + auto deltaPhiInRange = RecoDecay::constrainAngle(fvector.phi() - collision.psiFT0C(), 0.f, 2); + auto v2 = std::cos(2.0 * deltaPhiInRange); + nuclei::hFlowHists[iC][iS]->Fill(collision.centFT0C(), fvector.pt(), nSigma[0][iS], tofMasses[iS], v2, track.itsNCls(), track.tpcNClsFound()); + } + } else if (cfgFlowHist->get(iS) && doprocessDataFlowAlternative) { + if constexpr (requires { + collision.qvecFT0CIm(); + collision.qvecFT0CRe(); + }) { + auto deltaPhiInRange = RecoDecay::constrainAngle(fvector.phi() - computeEventPlane(collision.qvecFT0CIm(), collision.qvecFT0CRe()), 0.f, 2); + auto v2 = std::cos(2.0 * deltaPhiInRange); + nuclei::hFlowHists[iC][iS]->Fill(collision.centFT0C(), fvector.pt(), nSigma[0][iS], tofMasses[iS], v2, track.itsNCls(), track.tpcNClsFound()); } } } } } } - - if (cfgTreeConfig->get(iS, 0u) && selectedTPC[iS]) { + if (selectedTPC[iS]) { if (cfgTreeConfig->get(iS, 1u) && !selectedTOF) { continue; } - if (cfgDownscaling->get(iS) < 1. && gRandom->Rndm() > cfgDownscaling->get(iS)) { - continue; + !fillTree && cfgTreeConfig->get(iS, 0u) ? fillTree = true : fillTree; + !fillDCAHist && cfgDCAHists->get(iS, iC) ? fillDCAHist = true : fillDCAHist; + bool setPartFlag = cfgTreeConfig->get(iS, 0u) || cfgDCAHists->get(iS, iC); + if (setPartFlag) { + if (cfgDownscaling->get(iS) < 1. && gRandom->Rndm() > cfgDownscaling->get(iS)) { + continue; + } + flag |= BIT(iS); } - flag |= BIT(iS); } } if (flag & (kProton | kDeuteron | kTriton | kHe3 | kHe4) || doprocessMC) { /// ignore PID pre-selections for the MC - if constexpr (std::is_same::value) { + if constexpr (requires { + collision.psiFT0A(); + }) { nuclei::candidates_flow.emplace_back(NucleusCandidateFlow{ collision.centFV0A(), collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.psiFT0A(), - collision.multFT0A(), collision.psiFT0C(), - collision.multFT0C(), collision.psiTPC(), collision.psiTPCL(), collision.psiTPCR(), - collision.multTPC(), + collision.qFT0A(), + collision.qFT0C(), + collision.qTPC(), + collision.qTPCL(), + collision.qTPCR(), }); + } else if constexpr (requires { + collision.qvecFT0AIm(); + }) { + nuclei::candidates_flow.emplace_back(NucleusCandidateFlow{ + collision.centFV0A(), + collision.centFT0M(), + collision.centFT0A(), + collision.centFT0C(), + computeEventPlane(collision.qvecFT0AIm(), collision.qvecFT0ARe()), + computeEventPlane(collision.qvecFT0CIm(), collision.qvecFT0CRe()), + computeEventPlane(collision.qvecBTotIm(), collision.qvecBTotRe()), + computeEventPlane(collision.qvecBNegIm(), collision.qvecBNegRe()), + computeEventPlane(collision.qvecBPosIm(), collision.qvecBPosRe()), + std::hypot(collision.qvecFT0AIm(), collision.qvecFT0ARe()), + std::hypot(collision.qvecFT0CIm(), collision.qvecFT0CRe()), + std::hypot(collision.qvecBTotIm(), collision.qvecBTotRe()), + std::hypot(collision.qvecBNegIm(), collision.qvecBNegRe()), + std::hypot(collision.qvecBPosIm(), collision.qvecBPosRe())}); + } + if (fillTree) { + if (flag & kTriton) { + if (track.pt() < cfgCutPtMinTree || track.pt() > cfgCutPtMaxTree || track.sign() > 0) + continue; + } } - nuclei::candidates.emplace_back(NucleusCandidate{static_cast(track.globalIndex()), (1 - 2 * iC) * trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), correctedTpcInnerParam, beta, collision.posZ(), dcaInfo[0], dcaInfo[1], track.tpcSignal(), track.itsChi2NCl(), track.tpcChi2NCl(), flag, track.tpcNClsFindable(), static_cast(track.tpcNClsCrossedRows()), track.itsClusterMap(), static_cast(track.tpcNClsFound()), static_cast(track.itsClusterSizes())}); + nuclei::candidates.emplace_back(NucleusCandidate{ + static_cast(track.globalIndex()), static_cast(track.collisionId()), (1 - 2 * iC) * mTrackParCov.getPt(), mTrackParCov.getEta(), mTrackParCov.getPhi(), + correctedTpcInnerParam, beta, collision.posZ(), dcaInfo[0], dcaInfo[1], track.tpcSignal(), track.itsChi2NCl(), track.tpcChi2NCl(), track.tofChi2(), + nSigmaTPC, tofMasses, fillTree, fillDCAHist, correctPV, isSecondary, fromWeakDecay, flag, track.tpcNClsFindable(), static_cast(track.tpcNClsCrossedRows()), track.itsClusterMap(), + static_cast(track.tpcNClsFound()), static_cast(track.tpcNClsShared()), static_cast(track.itsNCls()), static_cast(track.itsClusterSizes())}); } } // end loop over tracks @@ -587,9 +830,19 @@ struct nucleiSpectra { if (!eventSelection(collision)) { return; } + fillDataInfo(collision, tracks); for (auto& c : nuclei::candidates) { - nucleiTable(c.pt, c.eta, c.phi, c.tpcInnerParam, c.beta, c.zVertex, c.DCAxy, c.DCAz, c.TPCsignal, c.ITSchi2, c.TPCchi2, c.flags, c.TPCfindableCls, c.TPCcrossedRows, c.ITSclsMap, c.TPCnCls, c.clusterSizesITS); + if (c.fillTree) { + nucleiTable(c.pt, c.eta, c.phi, c.tpcInnerParam, c.beta, c.zVertex, c.DCAxy, c.DCAz, c.TPCsignal, c.ITSchi2, c.TPCchi2, c.TOFchi2, c.flags, c.TPCfindableCls, c.TPCcrossedRows, c.ITSclsMap, c.TPCnCls, c.TPCnClsShared, c.clusterSizesITS); + } + if (c.fillDCAHist) { + for (int iS{0}; iS < nuclei::species; ++iS) { + if (c.flags & BIT(iS)) { + nuclei::hDCAHists[c.pt < 0][iS]->Fill(std::abs(c.pt), c.DCAxy, c.DCAz, c.nSigmaTPC[iS], c.tofMasses[iS], c.ITSnCls, c.TPCnCls); + } + } + } } } PROCESS_SWITCH(nucleiSpectra, processData, "Data analysis", true); @@ -598,23 +851,67 @@ struct nucleiSpectra { { nuclei::candidates.clear(); nuclei::candidates_flow.clear(); - if (!eventSelection(collision)) { + if (!eventSelectionWithHisto(collision)) { + return; + } + if (!collision.triggereventep() || !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { return; } fillDataInfo(collision, tracks); for (auto& c : nuclei::candidates) { - nucleiTable(c.pt, c.eta, c.phi, c.tpcInnerParam, c.beta, c.zVertex, c.DCAxy, c.DCAz, c.TPCsignal, c.ITSchi2, c.TPCchi2, c.flags, c.TPCfindableCls, c.TPCcrossedRows, c.ITSclsMap, c.TPCnCls, c.clusterSizesITS); + if (c.fillTree) { + nucleiTable(c.pt, c.eta, c.phi, c.tpcInnerParam, c.beta, c.zVertex, c.DCAxy, c.DCAz, c.TPCsignal, c.ITSchi2, c.TPCchi2, c.TOFchi2, c.flags, c.TPCfindableCls, c.TPCcrossedRows, c.ITSclsMap, c.TPCnCls, c.TPCnClsShared, c.clusterSizesITS); + } + if (c.fillDCAHist) { + for (int iS{0}; iS < nuclei::species; ++iS) { + if (c.flags & BIT(iS)) { + nuclei::hDCAHists[c.pt < 0][iS]->Fill(std::abs(c.pt), c.DCAxy, c.DCAz, c.nSigmaTPC[iS], c.tofMasses[iS], c.ITSnCls, c.TPCnCls); + } + } + } } for (auto& c : nuclei::candidates_flow) { - nucleiTableFlow(c.centFV0A, c.centFT0M, c.centFT0A, c.centFT0C, c.psiFT0A, c.multFT0A, c.psiFT0C, c.multFT0C, c.psiTPC, c.psiTPCl, c.psiTPCr, c.multTPC); + nucleiTableFlow(c.centFV0A, c.centFT0M, c.centFT0A, c.centFT0C, c.psiFT0A, c.psiFT0C, c.psiTPC, c.psiTPCl, c.psiTPCr, c.qFT0A, c.qFT0C, c.qTPC, c.qTPCl, c.qTPCr); } } PROCESS_SWITCH(nucleiSpectra, processDataFlow, "Data analysis with flow", false); + void processDataFlowAlternative(CollWithQvec const& collision, TrackCandidates const& tracks, aod::BCsWithTimestamps const&) + { + nuclei::candidates.clear(); + nuclei::candidates_flow.clear(); + if (!eventSelectionWithHisto(collision)) { + return; + } + if (!collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return; + } + fillDataInfo(collision, tracks); + for (auto& c : nuclei::candidates) { + if (c.fillTree) { + nucleiTable(c.pt, c.eta, c.phi, c.tpcInnerParam, c.beta, c.zVertex, c.DCAxy, c.DCAz, c.TPCsignal, c.ITSchi2, c.TPCchi2, c.TOFchi2, c.flags, c.TPCfindableCls, c.TPCcrossedRows, c.ITSclsMap, c.TPCnCls, c.TPCnClsShared, c.clusterSizesITS); + } + if (c.fillDCAHist) { + for (int iS{0}; iS < nuclei::species; ++iS) { + if (c.flags & BIT(iS)) { + nuclei::hDCAHists[c.pt < 0][iS]->Fill(std::abs(c.pt), c.DCAxy, c.DCAz, c.nSigmaTPC[iS], c.tofMasses[iS], c.ITSnCls, c.TPCnCls); + } + } + } + } + for (auto& c : nuclei::candidates_flow) { + nucleiTableFlow(c.centFV0A, c.centFT0M, c.centFT0A, c.centFT0C, c.psiFT0A, c.psiFT0C, c.psiTPC, c.psiTPCl, c.psiTPCr, c.qFT0A, c.qFT0C, c.qTPC, c.qTPCl, c.qTPCr); + } + } + PROCESS_SWITCH(nucleiSpectra, processDataFlowAlternative, "Data analysis with flow - alternative framework", false); + Preslice tracksPerCollisions = aod::track::collisionId; - void processMC(soa::Join const& collisions, aod::McCollisions const& mcCollisions, TrackCandidates const& tracks, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC, aod::BCsWithTimestamps const&) + void processMC(soa::Join const& collisions, aod::McCollisions const& mcCollisions, soa::Join const& tracks, aod::McParticles const& particlesMC, aod::BCsWithTimestamps const&) { nuclei::candidates.clear(); + for (auto& c : mcCollisions) { + spectra.fill(HIST("hGenVtxZ"), c.posZ()); + } std::vector goodCollisions(mcCollisions.size(), false); for (auto& collision : collisions) { if (!eventSelection(collision)) { @@ -626,7 +923,7 @@ struct nucleiSpectra { } std::vector isReconstructed(particlesMC.size(), false); for (auto& c : nuclei::candidates) { - auto label = trackLabelsMC.iteratorAt(c.globalIndex); + auto label = tracks.iteratorAt(c.globalIndex); if (label.mcParticleId() < -1 || label.mcParticleId() >= particlesMC.size()) { continue; } @@ -634,24 +931,47 @@ struct nucleiSpectra { bool storeIt{false}; for (int iS{0}; iS < nuclei::species; ++iS) { if (std::abs(particle.pdgCode()) == nuclei::codes[iS]) { - nuclei::hMomRes[iS][particle.pdgCode() < 0]->Fill(1., std::abs(c.pt * nuclei::charges[iS]), 1. - std::abs(c.pt * nuclei::charges[iS]) / particle.pt()); - storeIt = cfgTreeConfig->get(iS, 0u) || cfgTreeConfig->get(iS, 1u); /// store only the particles of interest - break; + if (c.fillTree && !storeIt) { + nuclei::hMomRes[iS][particle.pdgCode() < 0]->Fill(1., std::abs(c.pt * nuclei::charges[iS]), 1. - std::abs(c.pt * nuclei::charges[iS]) / particle.pt()); + storeIt = cfgTreeConfig->get(iS, 0u) || cfgTreeConfig->get(iS, 1u); /// store only the particles of interest + } + auto coll = collisions.iteratorAt(c.collTrackIndex); + int collMCGlobId = coll.mcCollisionId(); + if (particle.mcCollisionId() == collMCGlobId) { + c.correctPV = true; + } + if (!c.correctPV) { + c.flags |= kIsAmbiguous; + } + if (!particle.isPhysicalPrimary()) { + c.isSecondary = true; + if (particle.getProcess() == 4) { + c.fromWeakDecay = true; + } + } + + if (c.fillDCAHist && cfgDCAHists->get(iS, c.pt < 0)) { + nuclei::hDCAHists[c.pt < 0][iS]->Fill(std::abs(c.pt), c.DCAxy, c.DCAz, c.nSigmaTPC[iS], c.tofMasses[iS], c.ITSnCls, c.TPCnCls, c.correctPV, c.isSecondary, c.fromWeakDecay); + } } } if (!storeIt) { continue; } + int MotherpdgCode = 0; isReconstructed[particle.globalIndex()] = true; if (particle.isPhysicalPrimary()) { c.flags |= kIsPhysicalPrimary; } else if (particle.has_mothers()) { c.flags |= kIsSecondaryFromWeakDecay; + for (auto& motherparticle : particle.mothers_as()) { + MotherpdgCode = motherparticle.pdgCode(); + } } else { c.flags |= kIsSecondaryFromMaterial; } float absoDecL = computeAbsoDecL(particle); - nucleiTableMC(c.pt, c.eta, c.phi, c.tpcInnerParam, c.beta, c.zVertex, c.DCAxy, c.DCAz, c.TPCsignal, c.ITSchi2, c.TPCchi2, c.flags, c.TPCfindableCls, c.TPCcrossedRows, c.ITSclsMap, c.TPCnCls, c.clusterSizesITS, particle.pt(), particle.eta(), particle.phi(), particle.pdgCode(), goodCollisions[particle.mcCollisionId()], absoDecL); + nucleiTableMC(c.pt, c.eta, c.phi, c.tpcInnerParam, c.beta, c.zVertex, c.DCAxy, c.DCAz, c.TPCsignal, c.ITSchi2, c.TPCchi2, c.TOFchi2, c.flags, c.TPCfindableCls, c.TPCcrossedRows, c.ITSclsMap, c.TPCnCls, c.TPCnClsShared, c.clusterSizesITS, particle.pt(), particle.eta(), particle.phi(), particle.pdgCode(), MotherpdgCode, goodCollisions[particle.mcCollisionId()], absoDecL); } int index{0}; @@ -672,7 +992,7 @@ struct nucleiSpectra { if (!isReconstructed[index] && (cfgTreeConfig->get(iS, 0u) || cfgTreeConfig->get(iS, 1u))) { float absDecL = computeAbsoDecL(particle); - nucleiTableMC(999., 999., 999., 0., 0., 999., 999., 999., -1, -1, -1, flags, 0, 0, 0, 0, 0, particle.pt(), particle.eta(), particle.phi(), particle.pdgCode(), goodCollisions[particle.mcCollisionId()], absDecL); + nucleiTableMC(999., 999., 999., 0., 0., 999., 999., 999., -1, -1, -1, -1, flags, 0, 0, 0, 0, 0, 0, particle.pt(), particle.eta(), particle.phi(), particle.pdgCode(), 0, goodCollisions[particle.mcCollisionId()], absDecL); } break; } @@ -680,6 +1000,34 @@ struct nucleiSpectra { } } PROCESS_SWITCH(nucleiSpectra, processMC, "MC analysis", false); + + void processMatching(soa::Join::iterator const& collision, TrackCandidates const& tracks, aod::BCsWithTimestamps const&) + { + if (!eventSelection(collision) || !collision.triggereventep()) { + return; + } + const float centrality = collision.centFT0C(); + o2::aod::ITSResponse itsResponse; + for (const auto& track : tracks) { + if (std::abs(track.eta()) > cfgCutEta || + track.itsNCls() < 7 || + track.itsChi2NCl() > 36.f) { + continue; + } + double expBethe{tpc::BetheBlochAleph(static_cast(track.tpcInnerParam() * 2. / o2::constants::physics::MassHelium3), cfgBetheBlochParams->get(4, 0u), cfgBetheBlochParams->get(4, 1u), cfgBetheBlochParams->get(4, 2u), cfgBetheBlochParams->get(4, 3u), cfgBetheBlochParams->get(4, 4u))}; + double expSigma{expBethe * cfgBetheBlochParams->get(4, 5u)}; + double nSigmaTPC{(track.tpcSignal() - expBethe) / expSigma}; + int iC = track.signed1Pt() > 0; + const float pt = track.pt(); + const float phi = 2.f * RecoDecay::constrainAngle(track.phi() - collision.psiFT0C(), 0.f, 2); + nuclei::hMatchingStudyHadrons[iC]->Fill(pt, phi, track.eta(), centrality, track.hasTPC(), collision.trackOccupancyInTimeRange()); + if (itsResponse.nSigmaITS(track) > -1.) { + nuclei::hMatchingStudy[iC]->Fill(pt * 2, phi, track.eta(), itsResponse.nSigmaITS(track), nSigmaTPC, o2::pid::tof::Beta::GetBeta(track), centrality); + } + } + } + + PROCESS_SWITCH(nucleiSpectra, processMatching, "Matching analysis", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/TableProducer/Nuspex/nucleiUtils.h b/PWGLF/TableProducer/Nuspex/nucleiUtils.h new file mode 100644 index 00000000000..2a9a64bc4b2 --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/nucleiUtils.h @@ -0,0 +1,186 @@ +// 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. + +#ifndef PWGLF_TABLEPRODUCER_NUSPEX_NUCLEIUTILS_H_ +#define PWGLF_TABLEPRODUCER_NUSPEX_NUCLEIUTILS_H_ + +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +struct NucleusCandidate { + int globalIndex; + int collTrackIndex; + float pt; + float eta; + float phi; + float tpcInnerParam; + float beta; + float zVertex; + float DCAxy; + float DCAz; + float TPCsignal; + float ITSchi2; + float TPCchi2; + float TOFchi2; + std::array nSigmaTPC; + std::array tofMasses; + bool fillTree; + bool fillDCAHist; + bool correctPV; + bool isSecondary; + bool fromWeakDecay; + uint16_t flags; + uint8_t TPCfindableCls; + uint8_t TPCcrossedRows; + uint8_t ITSclsMap; + uint8_t TPCnCls; + uint8_t TPCnClsShared; + uint8_t ITSnCls; + uint32_t clusterSizesITS; +}; + +struct NucleusCandidateFlow { + float centFV0A; + float centFT0M; + float centFT0A; + float centFT0C; + float psiFT0A; + float psiFT0C; + float psiTPC; + float psiTPCl; + float psiTPCr; + float qFT0A; + float qFT0C; + float qTPC; + float qTPCl; + float qTPCr; +}; + +namespace nuclei +{ +constexpr double bbMomScalingDefault[5][2]{ + {1., 1.}, + {1., 1.}, + {1., 1.}, + {1., 1.}, + {1., 1.}}; +constexpr double betheBlochDefault[5][6]{ + {-136.71, 0.441, 0.2269, 1.347, 0.8035, 0.09}, + {-136.71, 0.441, 0.2269, 1.347, 0.8035, 0.09}, + {-239.99, 1.155, 1.099, 1.137, 1.006, 0.09}, + {-321.34, 0.6539, 1.591, 0.8225, 2.363, 0.09}, + {-586.66, 1.859, 4.435, 0.282, 3.201, 0.09}}; +constexpr double nSigmaTPCdefault[5][2]{ + {-5., 5.}, + {-5., 5.}, + {-5., 5.}, + {-5., 5.}, + {-5., 5.}}; +// constexpr double nSigmaTOFdefault[5][2]{ +// {-5., 5.}, +// {-5., 5.}, +// {-5., 5.}, +// {-5., 5.}, +// {-5., 5.}}; +constexpr double DCAcutDefault[5][2]{ + {1., 1.}, + {1., 1.}, + {1., 1.}, + {1., 1.}, + {1., 1.}}; +constexpr int TreeConfigDefault[5][2]{ + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}}; +constexpr int FlowHistDefault[5][1]{ + {0}, + {0}, + {0}, + {0}, + {0}}; +constexpr int DCAHistDefault[5][2]{ + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}}; +constexpr double DownscalingDefault[5][1]{ + {1.}, + {1.}, + {1.}, + {1.}, + {1.}}; +// constexpr bool storeTreesDefault[5]{false, false, false, false, false}; +constexpr int species{5}; +constexpr float charges[5]{1.f, 1.f, 1.f, 2.f, 2.f}; +constexpr float masses[5]{MassProton, MassDeuteron, MassTriton, MassHelium3, MassAlpha}; +static const std::vector matter{"M", "A"}; +static const std::vector pidName{"TPC", "TOF"}; +static const std::vector names{"proton", "deuteron", "triton", "He3", "alpha"}; +static const std::vector treeConfigNames{"Filter trees", "Use TOF selection"}; +static const std::vector flowConfigNames{"Save flow hists"}; +static const std::vector DCAConfigNames{"Save DCA hist", "Matter/Antimatter"}; +static const std::vector nSigmaConfigName{"nsigma_min", "nsigma_max"}; +static const std::vector nDCAConfigName{"max DCAxy", "max DCAz"}; +static const std::vector DownscalingConfigName{"Fraction of kept candidates"}; +static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; +static const std::vector chargeLabelNames{"Positive", "Negative"}; + +float pidCutTPC[5][2]; //[species][lower/upper limit] + +o2::base::MatLayerCylSet* lut = nullptr; + +std::vector candidates; +std::vector candidates_flow; + +enum centDetectors { + kFV0A = 0, + kFT0M = 1, + kFT0A = 2, + kFT0C = 3 +}; + +static const std::vector centDetectorNames{"FV0A", "FT0M", "FT0A", "FT0C"}; + +enum evSel { + kTVX = 0, + kZvtx, + kTFborder, + kITSROFborder, + kNoSameBunchPileup, + kIsGoodZvtxFT0vsPV, + kIsGoodITSLayersAll, + kIsEPtriggered, + kNevSels +}; + +static const std::vector eventSelectionTitle{"Event selections"}; +static const std::vector eventSelectionLabels{"TVX", "Z vtx", "TF border", "ITS ROF border", "No same-bunch pile-up", "kIsGoodZvtxFT0vsPV", "isGoodITSLayersAll", "isEPtriggered"}; + +constexpr int EvSelDefault[8][1]{ + {1}, + {1}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}}; +} // namespace nuclei + +#endif // PWGLF_TABLEPRODUCER_NUSPEX_NUCLEIUTILS_H_ diff --git a/PWGLF/TableProducer/Nuspex/pidTOFGeneric.cxx b/PWGLF/TableProducer/Nuspex/pidTOFGeneric.cxx new file mode 100644 index 00000000000..9997d4d27c8 --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/pidTOFGeneric.cxx @@ -0,0 +1,410 @@ +// 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 pidTOFGeneric.cxx +/// \origin Based on pidTOFBase.cxx +/// \brief Task to produce event Time obtained from TOF and FT0. +/// In order to redo TOF PID for tracks which are linked to wrong collisions +/// + +#include +#include +#include + +// O2 includes +#include "CCDB/BasicCCDBManager.h" +#include "TOFBase/EventTimeMaker.h" +#include "Framework/AnalysisTask.h" +#include "ReconstructionDataFormats/Track.h" + +// O2Physics includes +#include "Common/Core/TableHelper.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "PID/ParamBase.h" +#include "PID/PIDTOF.h" +#include "PWGLF/DataModel/pidTOFGeneric.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::pid; +using namespace o2::framework::expressions; +using namespace o2::track; + +/// Selection criteria for tracks used for TOF event time +float trackSampleMinMomentum = 0.5f; +float trackSampleMaxMomentum = 2.f; +template +bool filterForTOFEventTime(const trackType& tr) +{ + return (tr.hasTOF() && tr.p() > trackSampleMinMomentum && tr.p() < trackSampleMaxMomentum && (tr.trackType() == o2::aod::track::TrackTypeEnum::Track || tr.trackType() == o2::aod::track::TrackTypeEnum::TrackIU)); +} // accept all + +/// Specialization of TOF event time maker +template typename response, + typename trackTypeContainer, + typename responseParametersType> +o2::tof::eventTimeContainer evTimeMakerForTracks(const trackTypeContainer& tracks, + const responseParametersType& responseParameters, + const float& diamond = 6.0, + bool isFast = false) +{ + return o2::tof::evTimeMakerFromParam(tracks, responseParameters, diamond, isFast); +} + +/// Task to produce the event time tables for generic TOF PID +struct pidTOFGeneric { + // Tables to produce + Produces tableEvTime; // Table for global event time + Produces tableEvTimeForTrack; // Table for event time after removing bias from the track + static constexpr float diamond = 6.0; // Collision diamond used in the estimation of the TOF event time + static constexpr float errDiamond = diamond * 33.356409f; + static constexpr float weightDiamond = 1.f / (errDiamond * errDiamond); + + bool enableTable = false; + // Detector response and input parameters + o2::pid::tof::TOFResoParamsV2 mRespParamsV2; + Service ccdb; + Configurable inheritFromBaseTask{"inheritFromBaseTask", true, "Flag to iherit all common configurables from the TOF base task"}; + Configurable fastTOFPID{"fastTOFPID", false, "Flag to enable computeEvTimeFast for evTimeMaker"}; + // CCDB configuration (inherited from TOF signal task) + Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable timestamp{"ccdb-timestamp", -1, "timestamp of the object"}; + // Event time configurations + Configurable minMomentum{"minMomentum", 0.5f, "Minimum momentum to select track sample for TOF event time"}; + Configurable maxMomentum{"maxMomentum", 2.0f, "Maximum momentum to select track sample for TOF event time"}; + Configurable maxEvTimeTOF{"maxEvTimeTOF", 100000.0f, "Maximum value of the TOF event time"}; + Configurable sel8TOFEvTime{"sel8TOFEvTime", false, "Flag to compute the ev. time only for events that pass the sel8 ev. selection"}; + Configurable maxNtracksInSet{"maxNtracksInSet", 10, "Size of the set to consider for the TOF ev. time computation"}; + // TOF Calib configuration + Configurable paramFileName{"paramFileName", "", "Path to the parametrization object. If empty the parametrization is not taken from file"}; + Configurable parametrizationPath{"parametrizationPath", "TOF/Calib/Params", "Path of the TOF parametrization on the CCDB or in the file, if the paramFileName is not empty"}; + Configurable passName{"passName", "", "Name of the pass inside of the CCDB parameter collection. If empty, the automatically deceted from metadata (to be implemented!!!)"}; + Configurable loadResponseFromCCDB{"loadResponseFromCCDB", false, "Flag to load the response from the CCDB"}; + Configurable enableTimeDependentResponse{"enableTimeDependentResponse", false, "Flag to use the collision timestamp to fetch the PID Response"}; + Configurable fatalOnPassNotAvailable{"fatalOnPassNotAvailable", true, "Flag to throw a fatal if the pass is not available in the retrieved CCDB object"}; + + void init(o2::framework::InitContext& initContext) + { + if (inheritFromBaseTask.value) { + if (!getTaskOptionValue(initContext, "tof-signal", "ccdb-url", url.value, true)) { + LOG(fatal) << "Could not get ccdb-url from tof-signal task"; + } + if (!getTaskOptionValue(initContext, "tof-signal", "ccdb-timestamp", timestamp.value, true)) { + LOG(fatal) << "Could not get ccdb-timestamp from tof-signal task"; + } + } + + trackSampleMinMomentum = minMomentum; + trackSampleMaxMomentum = maxMomentum; + LOG(info) << "Configuring track sample for TOF ev. time: " << trackSampleMinMomentum << " < p < " << trackSampleMaxMomentum; + // Check that both processes are not enabled + int nEnabled = 0; + if (doprocessNoFT0 == true) { + LOGF(info, "Enabling process function: processNoFT0"); + nEnabled++; + } + if (doprocessFT0 == true) { + LOGF(info, "Enabling process function: processFT0"); + nEnabled++; + } + if (doprocessOnlyFT0 == true) { + LOGF(info, "Enabling process function: processOnlyFT0"); + nEnabled++; + } + if (nEnabled > 1) { + LOGF(fatal, "Cannot enable more process functions at the same time. Please choose one."); + } + // Checking that the table is requested in the workflow and enabling it + enableTable = isTableRequiredInWorkflow(initContext, "EvTimeTOFFT0") || isTableRequiredInWorkflow(initContext, "EvTimeTOFFT0ForTrack"); + if (!enableTable) { + LOG(info) << "Table for global Event time is not required, disabling it"; + return; + } + LOG(info) << "Table EvTimeTOFFT0 enabled!"; + + if (sel8TOFEvTime.value == true) { + LOG(info) << "TOF event time will be computed for collisions that pass the event selection only!"; + } + // Getting the parametrization parameters + ccdb->setURL(url.value); + ccdb->setTimestamp(timestamp.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + // Not later than now objects + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + // + + // TODO: implement the automatic pass name detection from metadata + if (passName.value == "") { + passName.value = "unanchored"; // temporary default + LOG(warning) << "Passed autodetect mode for pass, not implemented yet, waiting for metadata. Taking '" << passName.value << "'"; + } + LOG(info) << "Using parameter collection, starting from pass '" << passName.value << "'"; + + const std::string fname = paramFileName.value; + if (!fname.empty()) { // Loading the parametrization from file + LOG(info) << "Loading exp. sigma parametrization from file " << fname << ", using param: " << parametrizationPath.value; + if (1) { + o2::tof::ParameterCollection paramCollection; + paramCollection.loadParamFromFile(fname, parametrizationPath.value); + LOG(info) << "+++ Loaded parameter collection from file +++"; + if (!paramCollection.retrieveParameters(mRespParamsV2, passName.value)) { + if (fatalOnPassNotAvailable) { + LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + } else { + LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + } + } else { + mRespParamsV2.setShiftParameters(paramCollection.getPars(passName.value)); + mRespParamsV2.printShiftParameters(); + } + } else { + mRespParamsV2.loadParamFromFile(fname.data(), parametrizationPath.value); + } + } else if (loadResponseFromCCDB) { // Loading it from CCDB + LOG(info) << "Loading exp. sigma parametrization from CCDB, using path: " << parametrizationPath.value << " for timestamp " << timestamp.value; + + o2::tof::ParameterCollection* paramCollection = ccdb->getForTimeStamp(parametrizationPath.value, timestamp.value); + paramCollection->print(); + if (!paramCollection->retrieveParameters(mRespParamsV2, passName.value)) { + if (fatalOnPassNotAvailable) { + LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + } else { + LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + } + } else { + mRespParamsV2.setShiftParameters(paramCollection->getPars(passName.value)); + mRespParamsV2.printShiftParameters(); + } + } + mRespParamsV2.print(); + o2::tof::eventTimeContainer::setMaxNtracksInSet(maxNtracksInSet.value); + o2::tof::eventTimeContainer::printConfig(); + } + + /// + /// Process function to prepare the event time on Run 3 data without the FT0 + using TrksEvTime = soa::Join; + // Define slice per collision + Preslice perCollision = aod::track::collisionId; + template + using ResponseImplementationEvTime = o2::pid::tof::ExpTimes; + using EvTimeCollisions = soa::Join; + void processNoFT0(TrksEvTime& tracks, + EvTimeCollisions const& collisions) + { + if (!enableTable) { + return; + } + tableEvTime.reserve(collisions.size()); + tableEvTimeForTrack.reserve(tracks.size()); + + // for tracks not assigned to a collision + for (auto track : tracks) { + if (!track.has_collision()) { + tableEvTimeForTrack(0.f, 999.f); + } + } + + for (auto const& collision : collisions) { // Loop on collisions + const auto& tracksInCollision = tracks.sliceBy(perCollision, collision.globalIndex()); + if ((sel8TOFEvTime.value == true) && !collision.sel8()) { + tableEvTime(0.f, 999.f, 0.f, 999.f, 0.f, 999.f); + for (int i = 0; i < tracksInCollision.size(); i++) { + tableEvTimeForTrack(0.f, 999.f); + } + continue; + } + + // First make table for event time + const auto evTimeTOF = evTimeMakerForTracks(tracksInCollision, mRespParamsV2, diamond, fastTOFPID); + int nGoodTracksForTOF = 0; // count for ntrackIndex for removeBias() + float et = evTimeTOF.mEventTime; + float erret = evTimeTOF.mEventTimeError; + + if (erret < errDiamond && (maxEvTimeTOF <= 0.f || abs(et) < maxEvTimeTOF)) { + } else { + et = 0.f; + erret = errDiamond; + } + tableEvTime(et, erret, et, erret, 0.f, 999.f); + for (auto const& track : tracksInCollision) { + evTimeTOF.removeBias(track, nGoodTracksForTOF, et, erret, 2); + if (erret < errDiamond && (maxEvTimeTOF <= 0.f || abs(et) < maxEvTimeTOF)) { + } else { + et = 0.f; + erret = errDiamond; + } + tableEvTimeForTrack(et, erret); + } + } + } + PROCESS_SWITCH(pidTOFGeneric, processNoFT0, "Process without FT0", false); + + /// + /// Process function to prepare the event for each track on Run 3 data with the FT0 + using EvTimeCollisionsFT0 = soa::Join; + void processFT0(TrksEvTime& tracks, + aod::FT0s const&, + EvTimeCollisionsFT0 const& collisions) + { + if (!enableTable) { + return; + } + tableEvTime.reserve(collisions.size()); + tableEvTimeForTrack.reserve(tracks.size()); + std::vector tEvTimeForTrack; + std::vector tEvTimeErrForTrack; + tEvTimeForTrack.resize(tracks.size()); + tEvTimeErrForTrack.resize(tracks.size()); + + // for tracks not assigned to a collision + for (auto track : tracks) { + if (!track.has_collision()) { + tEvTimeForTrack[track.globalIndex()] = 0.f; + tEvTimeErrForTrack[track.globalIndex()] = 999.f; + } + } + + for (auto const& collision : collisions) { // Loop on collisions + const auto& tracksInCollision = tracks.sliceBy(perCollision, collision.globalIndex()); + if ((sel8TOFEvTime.value == true) && !collision.sel8()) { + tableEvTime(0.f, 999.f, 0.f, 999.f, 0.f, 999.f); + for (auto track : tracksInCollision) { + tEvTimeForTrack[track.globalIndex()] = 0.f; + tEvTimeErrForTrack[track.globalIndex()] = 999.f; + } + continue; + } + + // Compute the TOF event time + const auto evTimeTOF = evTimeMakerForTracks(tracksInCollision, mRespParamsV2, diamond, fastTOFPID); + + float t0TOF[2] = {static_cast(evTimeTOF.mEventTime), static_cast(evTimeTOF.mEventTimeError)}; // Value and error of TOF + float t0AC[2] = {.0f, 999.f}; // Value and error of T0A or T0C or T0AC + + float eventTime = 0.f; + float sumOfWeights = 0.f; + float weight = 0.f; + + if (t0TOF[1] < errDiamond && (maxEvTimeTOF <= 0 || abs(t0TOF[0]) < maxEvTimeTOF)) { + weight = 1.f / (t0TOF[1] * t0TOF[1]); + eventTime += t0TOF[0] * weight; + sumOfWeights += weight; + } + + if (collision.has_foundFT0()) { // T0 measurement is available + // const auto& ft0 = collision.foundFT0(); + if (collision.t0ACValid()) { + t0AC[0] = collision.t0AC() * 1000.f; + t0AC[1] = collision.t0resolution() * 1000.f; + } + + weight = 1.f / (t0AC[1] * t0AC[1]); + eventTime += t0AC[0] * weight; + sumOfWeights += weight; + } + + if (sumOfWeights < weightDiamond) { // avoiding sumOfWeights = 0 or worse that diamond + eventTime = 0; + sumOfWeights = weightDiamond; + } + tableEvTime(eventTime / sumOfWeights, sqrt(1. / sumOfWeights), t0TOF[0], t0TOF[1], t0AC[0], t0AC[1]); + + int nGoodTracksForTOF = 0; // count for ntrackIndex for removeBias() + for (auto const& track : tracksInCollision) { + // Reset the event time + eventTime = 0.f; + sumOfWeights = 0.f; + weight = 0.f; + // Remove the bias on TOF ev. time + evTimeTOF.removeBias(track, nGoodTracksForTOF, t0TOF[0], t0TOF[1], 2); + if (t0TOF[1] < errDiamond && (maxEvTimeTOF <= 0 || abs(t0TOF[0]) < maxEvTimeTOF)) { + weight = 1.f / (t0TOF[1] * t0TOF[1]); + eventTime += t0TOF[0] * weight; + sumOfWeights += weight; + } + + // Add the contribution from FT0 if it is available, t0AC is already calculated + if (collision.has_foundFT0()) { + weight = 1.f / (t0AC[1] * t0AC[1]); + eventTime += t0AC[0] * weight; + sumOfWeights += weight; + } + + if (sumOfWeights < weightDiamond) { // avoiding sumOfWeights = 0 or worse that diamond + eventTime = 0; + sumOfWeights = weightDiamond; + } + tEvTimeForTrack[track.globalIndex()] = eventTime / sumOfWeights; + tEvTimeErrForTrack[track.globalIndex()] = sqrt(1. / sumOfWeights); + } + } + for (int i = 0; i < tracks.size(); i++) { + tableEvTimeForTrack(tEvTimeForTrack[i], tEvTimeErrForTrack[i]); + } + } + PROCESS_SWITCH(pidTOFGeneric, processFT0, "Process with FT0", true); + + /// + /// Process function to prepare the event time on Run 3 data with only the FT0 + void processOnlyFT0(EvTimeCollisionsFT0 const& collisions, + TrksEvTime& tracks, + aod::FT0s const&) + { + if (!enableTable) { + return; + } + tableEvTime.reserve(collisions.size()); + tableEvTimeForTrack.reserve(tracks.size()); + + // for tracks not assigned to a collision + for (auto track : tracks) { + if (!track.has_collision()) { + tableEvTimeForTrack(0.f, 999.f); + } + } + + for (auto const& collision : collisions) { + const auto& tracksInCollision = tracks.sliceBy(perCollision, collision.globalIndex()); + if (collision.has_foundFT0()) { // T0 measurement is available + // const auto& ft0 = collision.foundFT0(); + if (collision.t0ACValid()) { + tableEvTime(collision.t0AC() * 1000.f, collision.t0resolution() * 1000.f, 0.f, 999.f, collision.t0AC() * 1000.f, collision.t0resolution() * 1000.f); + for (int i = 0; i < tracks.size(); i++) { + tableEvTimeForTrack(collision.t0AC() * 1000.f, collision.t0resolution() * 1000.f); + } + return; + } + } + tableEvTime(0.f, 999.f, 0.f, 999.f, 0.f, 999.f); + for (int i = 0; i < tracksInCollision.size(); i++) { + tableEvTimeForTrack(0.f, 999.f); + } + } + } + PROCESS_SWITCH(pidTOFGeneric, processOnlyFT0, "Process only with FT0", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Nuspex/reduced3bodyCreator.cxx b/PWGLF/TableProducer/Nuspex/reduced3bodyCreator.cxx new file mode 100644 index 00000000000..f8d3d04856a --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/reduced3bodyCreator.cxx @@ -0,0 +1,465 @@ +// 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 reduced3bodyCreator.cxx +/// \brief Task to produce reduced AO2Ds for use in the hypertriton 3body reconstruction with the decay3bodybuilder.cxx +/// \author Yuanzhe Wang +/// \author Carolina Reetz + +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "DCAFitter/DCAFitterN.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "PWGLF/DataModel/pidTOFGeneric.h" +#include "PWGLF/DataModel/Reduced3BodyTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/PID/PIDTOF.h" +#include "TableHelper.h" +#include "Tools/KFparticle/KFUtilities.h" + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" + +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + +#ifndef HomogeneousField +#define HomogeneousField +#endif + +// includes KFParticle +#include "KFParticle.h" +#include "KFPTrack.h" +#include "KFPVertex.h" +#include "KFParticleBase.h" +#include "KFVertex.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using FullTracksExtIU = soa::Join; +using FullTracksExtPIDIU = soa::Join; + +using ColwithEvTimes = o2::soa::Join; +using ColwithEvTimesMultsCents = o2::soa::Join; +using TrackExtIUwithEvTimes = soa::Join; +using TrackExtPIDIUwithEvTimes = soa::Join; + +struct reduced3bodyCreator { + + Produces reducedCollisions; + Produces reducedPVMults; + Produces reducedCentFT0Cs; + Produces reducedDecay3Bodys; + Produces reduced3BodyInfo; + Produces reducedFullTracksPIDIU; + Produces dcaFitterSVInfo; + + Service ccdb; + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + o2::vertexing::DCAFitterN<3> fitter3body; + o2::aod::pidtofgeneric::TofPidNewCollision bachelorTOFPID; + + Configurable event_sel8_selection{"event_sel8_selection", true, "event selection count post sel8 cut"}; + Configurable mc_event_selection{"mc_event_selection", true, "mc event selection count post kIsTriggerTVX and kNoTimeFrameBorder"}; + Configurable event_posZ_selection{"event_posZ_selection", true, "event selection count post poZ cut"}; + // CCDB options + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + // CCDB TOF PID paras + Configurable timestamp{"ccdb-timestamp", -1, "timestamp of the object"}; + Configurable paramFileName{"paramFileName", "", "Path to the parametrization object. If empty the parametrization is not taken from file"}; + Configurable parametrizationPath{"parametrizationPath", "TOF/Calib/Params", "Path of the TOF parametrization on the CCDB or in the file, if the paramFileName is not empty"}; + Configurable passName{"passName", "", "Name of the pass inside of the CCDB parameter collection. If empty, the automatically deceted from metadata (to be implemented!!!)"}; + Configurable timeShiftCCDBPath{"timeShiftCCDBPath", "", "Path of the TOF time shift vs eta. If empty none is taken"}; + Configurable loadResponseFromCCDB{"loadResponseFromCCDB", false, "Flag to load the response from the CCDB"}; + Configurable fatalOnPassNotAvailable{"fatalOnPassNotAvailable", true, "Flag to throw a fatal if the pass is not available in the retrieved CCDB object"}; + // Zorro counting + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; + // Flag for trigger + Configurable cfgOnlyKeepInterestedTrigger{"cfgOnlyKeepInterestedTrigger", false, "Flag to keep only interested trigger"}; + Configurable triggerList{"triggerList", "fH3L3Body", "List of triggers used to select events"}; + + Configurable cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Type of material correction for DCAFitter"}; + + int mRunNumber; + float d_bz; + o2::pid::tof::TOFResoParamsV2 mRespParamsV2; + + HistogramRegistry registry{"registry", {}}; + + void init(InitContext&) + { + mRunNumber = 0; + zorroSummary.setObject(zorro.getZorroSummary()); + bachelorTOFPID.SetPidType(o2::track::PID::Deuteron); + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + fitter3body.setPropagateToPCA(true); + fitter3body.setMaxR(200.); //->maxRIni3body + fitter3body.setMinParamChange(1e-3); + fitter3body.setMinRelChi2Change(0.9); + fitter3body.setMaxDZIni(1e9); + fitter3body.setMaxChi2(1e9); + fitter3body.setUseAbsDCA(true); + int mat{static_cast(cfgMaterialCorrection)}; + fitter3body.setMatCorrType(static_cast(mat)); + + registry.add("hAllSelEventsVtxZ", "hAllSelEventsVtxZ", HistType::kTH1F, {{500, -15.0f, 15.0f, "PV Z (cm)"}}); + + auto hEventCounter = registry.add("hEventCounter", "hEventCounter", HistType::kTH1D, {{4, 0.0f, 4.0f}}); + hEventCounter->GetXaxis()->SetBinLabel(1, "total"); + hEventCounter->GetXaxis()->SetBinLabel(2, "sel8"); + hEventCounter->GetXaxis()->SetBinLabel(3, "vertexZ"); + hEventCounter->GetXaxis()->SetBinLabel(4, "reduced"); + hEventCounter->LabelsOption("v"); + + auto hEventCounterZorro = registry.add("hEventCounterZorro", "hEventCounterZorro", HistType::kTH1D, {{2, 0, 2}}); + hEventCounterZorro->GetXaxis()->SetBinLabel(1, "Zorro before evsel"); + hEventCounterZorro->GetXaxis()->SetBinLabel(2, "Zorro after evsel"); + } + + void initZorroBC(aod::BCsWithTimestamps::iterator const& bc) + { + if (cfgSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), triggerList); + zorro.populateHistRegistry(registry, bc.runNumber()); + } + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + // In case override, don't proceed, please - no CCDB access required + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + + // In case override, don't proceed, please - no CCDB access required + auto run3grp_timestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + o2::parameters::GRPMagField* grpmag = 0x0; + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + // Fetch magnetic field from ccdb for current collision + // d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + d_bz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } +// Set magnetic field for KF vertexing +#ifdef HomogeneousField + KFParticle::SetField(d_bz); +#endif + + // Initial TOF PID Paras, copied from PIDTOF.h + timestamp.value = bc.timestamp(); + ccdb->setTimestamp(timestamp.value); + // Not later than now objects + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + // TODO: implement the automatic pass name detection from metadata + if (passName.value == "") { + passName.value = "unanchored"; // temporary default + LOG(warning) << "Passed autodetect mode for pass, not implemented yet, waiting for metadata. Taking '" << passName.value << "'"; + } + LOG(info) << "Using parameter collection, starting from pass '" << passName.value << "'"; + + const std::string fname = paramFileName.value; + if (!fname.empty()) { // Loading the parametrization from file + LOG(info) << "Loading exp. sigma parametrization from file " << fname << ", using param: " << parametrizationPath.value; + if (1) { + o2::tof::ParameterCollection paramCollection; + paramCollection.loadParamFromFile(fname, parametrizationPath.value); + LOG(info) << "+++ Loaded parameter collection from file +++"; + if (!paramCollection.retrieveParameters(mRespParamsV2, passName.value)) { + if (fatalOnPassNotAvailable) { + LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + } else { + LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + } + } else { + mRespParamsV2.setShiftParameters(paramCollection.getPars(passName.value)); + mRespParamsV2.printShiftParameters(); + } + } else { + mRespParamsV2.loadParamFromFile(fname.data(), parametrizationPath.value); + } + } else if (loadResponseFromCCDB) { // Loading it from CCDB + LOG(info) << "Loading exp. sigma parametrization from CCDB, using path: " << parametrizationPath.value << " for timestamp " << timestamp.value; + o2::tof::ParameterCollection* paramCollection = ccdb->getForTimeStamp(parametrizationPath.value, timestamp.value); + paramCollection->print(); + if (!paramCollection->retrieveParameters(mRespParamsV2, passName.value)) { // Attempt at loading the parameters with the pass defined + if (fatalOnPassNotAvailable) { + LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + } else { + LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + } + } else { // Pass is available, load non standard parameters + mRespParamsV2.setShiftParameters(paramCollection->getPars(passName.value)); + mRespParamsV2.printShiftParameters(); + } + } + mRespParamsV2.print(); + if (timeShiftCCDBPath.value != "") { + if (timeShiftCCDBPath.value.find(".root") != std::string::npos) { + mRespParamsV2.setTimeShiftParameters(timeShiftCCDBPath.value, "gmean_Pos", true); + mRespParamsV2.setTimeShiftParameters(timeShiftCCDBPath.value, "gmean_Neg", false); + } else { + mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/pos", timeShiftCCDBPath.value.c_str()), timestamp.value), true); + mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/neg", timeShiftCCDBPath.value.c_str()), timestamp.value), false); + } + } + + fitter3body.setBz(d_bz); + bachelorTOFPID.SetParams(mRespParamsV2); + } + + //------------------------------------------------------------------ + // function to fill reduced track table + template + void fillTrackTable(TTrack const& daughter, double tofNSigmaTrack, auto collisionIndex) + { + reducedFullTracksPIDIU( + // TrackIU + collisionIndex, + daughter.x(), daughter.alpha(), + daughter.y(), daughter.z(), daughter.snp(), daughter.tgl(), + daughter.signed1Pt(), + // TracksCovIU + daughter.sigmaY(), daughter.sigmaZ(), daughter.sigmaSnp(), daughter.sigmaTgl(), daughter.sigma1Pt(), + daughter.rhoZY(), daughter.rhoSnpY(), daughter.rhoSnpZ(), daughter.rhoTglY(), daughter.rhoTglZ(), + daughter.rhoTglSnp(), daughter.rho1PtY(), daughter.rho1PtZ(), daughter.rho1PtSnp(), daughter.rho1PtTgl(), + // TracksExtra + daughter.tpcInnerParam(), daughter.flags(), daughter.itsClusterSizes(), + daughter.tpcNClsFindable(), daughter.tpcNClsFindableMinusFound(), daughter.tpcNClsFindableMinusCrossedRows(), + daughter.trdPattern(), daughter.tpcChi2NCl(), daughter.tofChi2(), + daughter.tpcSignal(), daughter.tofExpMom(), + // PID + daughter.tpcNSigmaPr(), daughter.tpcNSigmaPi(), daughter.tpcNSigmaDe(), + tofNSigmaTrack); + } + + //------------------------------------------------------------------ + // function to fit KFParticle 3body vertex + template + void fit3bodyVertex(TKFParticle& kfpProton, TKFParticle& kfpPion, TKFParticle& kfpDeuteron, TKFParticle& KFHt) + { + // Construct 3body vertex + int nDaughters3body = 3; + const KFParticle* Daughters3body[3] = {&kfpProton, &kfpPion, &kfpDeuteron}; + KFHt.SetConstructMethod(2); + try { + KFHt.Construct(Daughters3body, nDaughters3body); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to create Hyper triton 3-body vertex." << e.what(); + return; + } + LOG(debug) << "Hypertriton vertex constructed."; + } + + void process(ColwithEvTimesMultsCents const& collisions, TrackExtPIDIUwithEvTimes const&, aod::Decay3Bodys const& decay3bodys, aod::BCsWithTimestamps const&) + { + std::vector triggeredCollisions(collisions.size(), false); + + int lastRunNumber = -1; // RunNumber of last collision, used for zorro counting + // Event counting + for (const auto& collision : collisions) { + + auto bc = collision.bc_as(); + if (bc.runNumber() != lastRunNumber) { + initZorroBC(bc); + lastRunNumber = bc.runNumber(); // Update the last run number + } + + // Zorro event counting + bool isZorroSelected = false; + if (cfgSkimmedProcessing) { + isZorroSelected = zorro.isSelected(bc.globalBC()); + if (isZorroSelected) { + registry.fill(HIST("hEventCounterZorro"), 0.5); + triggeredCollisions[collision.globalIndex()] = true; + } + } + + // Event selection + registry.fill(HIST("hEventCounter"), 0.5); + if (event_sel8_selection && !collision.sel8()) { + continue; + } + registry.fill(HIST("hEventCounter"), 1.5); + if (event_posZ_selection && (collision.posZ() >= 10.0f || collision.posZ() <= -10.0f)) { // 10cm + continue; + } + registry.fill(HIST("hEventCounter"), 2.5); + registry.fill(HIST("hAllSelEventsVtxZ"), collision.posZ()); + + if (cfgSkimmedProcessing && isZorroSelected) { + registry.fill(HIST("hEventCounterZorro"), 1.5); + } + } + + int lastCollisionID = -1; // collisionId of last analysed decay3body. Table is sorted. + + // Creat reduced table + for (const auto& d3body : decay3bodys) { + + auto collision = d3body.template collision_as(); + + if (event_sel8_selection && !collision.sel8()) { + continue; + } + if (event_posZ_selection && (collision.posZ() >= 10.0f || collision.posZ() <= -10.0f)) { // 10cm + continue; + } + + auto bc = collision.bc_as(); + initCCDB(bc); + if (cfgSkimmedProcessing && cfgOnlyKeepInterestedTrigger) { + if (triggeredCollisions[collision.globalIndex()] == false) { + continue; + } + } + + // Save the collision + if (collision.globalIndex() != lastCollisionID) { + int runNumber = bc.runNumber(); + reducedCollisions( + collision.posX(), collision.posY(), collision.posZ(), + collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ(), + collision.flags(), collision.chi2(), collision.numContrib(), + collision.collisionTime(), collision.collisionTimeRes(), + runNumber); + reducedPVMults(collision.multNTracksPV()); + reducedCentFT0Cs(collision.centFT0C()); + + lastCollisionID = collision.globalIndex(); + } + + // Precompute collision index + const auto collisionIndex = reducedCollisions.lastIndex(); + + // Save daughter tracks + const auto daughter0 = d3body.template track0_as(); + const auto daughter1 = d3body.template track1_as(); + const auto daughter2 = d3body.template track2_as(); + + // TOF PID of bachelor must be calcualted here + // ---------------------------------------------- + auto originalcol = daughter2.template collision_as(); + double tofNSigmaBach = bachelorTOFPID.GetTOFNSigma(daughter2, originalcol, collision); + // ---------------------------------------------- + + // -------- save reduced track table with decay3body daughters ---------- + fillTrackTable(daughter0, -999, collisionIndex); + fillTrackTable(daughter1, -999, collisionIndex); + fillTrackTable(daughter2, tofNSigmaBach, collisionIndex); + + // -------- save reduced decay3body table -------- + const auto trackStartIndex = reducedFullTracksPIDIU.lastIndex(); + reducedDecay3Bodys(collisionIndex, trackStartIndex - 2, trackStartIndex - 1, trackStartIndex); + + // -------- save reduced decay3body info table -------- + // get trackParCov daughters + auto trackParCovPos = getTrackParCov(daughter0); + auto trackParCovNeg = getTrackParCov(daughter1); + auto trackParCovBach = getTrackParCov(daughter2); + // create KFParticle daughters + KFParticle kfpProton, kfpPion, kfpDeuteron; + if (daughter2.sign() > 0) { + kfpProton = createKFParticleFromTrackParCov(trackParCovPos, daughter0.sign(), constants::physics::MassProton); + kfpPion = createKFParticleFromTrackParCov(trackParCovNeg, daughter1.sign(), constants::physics::MassPionCharged); + } else if (!(daughter2.sign() > 0)) { + kfpProton = createKFParticleFromTrackParCov(trackParCovNeg, daughter1.sign(), constants::physics::MassProton); + kfpPion = createKFParticleFromTrackParCov(trackParCovPos, daughter0.sign(), constants::physics::MassPionCharged); + } + kfpDeuteron = createKFParticleFromTrackParCov(trackParCovBach, daughter2.sign(), constants::physics::MassDeuteron); + // fit 3body vertex + KFParticle KFHt; + fit3bodyVertex(kfpProton, kfpPion, kfpDeuteron, KFHt); + // calculate radius and phi + auto radius = std::sqrt(KFHt.GetX() * KFHt.GetX() + KFHt.GetY() * KFHt.GetY()); + float phi, sigma; + KFHt.GetPhi(phi, sigma); + // fill 3body info table + reduced3BodyInfo(radius, phi, KFHt.GetZ()); + + // -------- save dcaFitter secondary vertex info table -------- + auto Track0 = getTrackParCov(daughter0); + auto Track1 = getTrackParCov(daughter1); + auto Track2 = getTrackParCov(daughter2); + int n3bodyVtx = fitter3body.process(Track0, Track1, Track2); + if (n3bodyVtx == 0) { // discard this pair + dcaFitterSVInfo(-999, -999, -999); + } else { + const auto& vtxXYZ = fitter3body.getPCACandidate(); + + std::array p0 = {0.}, p1 = {0.}, p2{0.}; + const auto& propagatedTrack0 = fitter3body.getTrack(0); + const auto& propagatedTrack1 = fitter3body.getTrack(1); + const auto& propagatedTrack2 = fitter3body.getTrack(2); + propagatedTrack0.getPxPyPzGlo(p0); + propagatedTrack1.getPxPyPzGlo(p1); + propagatedTrack2.getPxPyPzGlo(p2); + std::array p3B = {p0[0] + p1[0] + p2[0], p0[1] + p1[1] + p2[1], p0[2] + p1[2] + p2[2]}; + float phiVtx = std::atan2(p3B[1], p3B[0]); + float rVtx = std::hypot(vtxXYZ[0], vtxXYZ[1]); + dcaFitterSVInfo(rVtx, phiVtx, vtxXYZ[2]); + } + } // end decay3body loop + + registry.fill(HIST("hEventCounter"), 3.5, reducedCollisions.lastIndex() + 1); + } +}; + +struct reduced3bodyInitializer { + Spawns reducedTracksIU; + void init(InitContext const&) {} +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGLF/TableProducer/Nuspex/spectraDerivedMaker.cxx b/PWGLF/TableProducer/Nuspex/spectraDerivedMaker.cxx index c96b8b1fbb6..bce0c9153d1 100644 --- a/PWGLF/TableProducer/Nuspex/spectraDerivedMaker.cxx +++ b/PWGLF/TableProducer/Nuspex/spectraDerivedMaker.cxx @@ -178,7 +178,7 @@ struct spectraDerivedMaker { histos.fill(HIST("evsel"), 6.f); } } - if (abs(collision.posZ()) > cfgCutVertex) { + if (std::abs(collision.posZ()) > cfgCutVertex) { return false; } if constexpr (fillHistograms) { @@ -235,7 +235,7 @@ struct spectraDerivedMaker { if constexpr (fillHistograms) { histos.fill(HIST("tracksel"), 1); } - if (abs(track.eta()) > cfgCutEta) { + if (std::abs(track.eta()) > cfgCutEta) { return false; } if constexpr (fillHistograms) { @@ -388,4 +388,4 @@ struct spectraDerivedMaker { PROCESS_SWITCH(spectraDerivedMaker, processMC, "Process MC for derived dataset production", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } \ No newline at end of file +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/TableProducer/Nuspex/threebodyKFTask.cxx b/PWGLF/TableProducer/Nuspex/threebodyKFTask.cxx new file mode 100644 index 00000000000..1fed55805c2 --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/threebodyKFTask.cxx @@ -0,0 +1,488 @@ +// 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 Analysis task for KFVtx3BodyDatas (3body candidates reconstructed with KF) +/// \author Carolina Reetz --> partly copied from threebodyRecoTask.cxx +// ======================== + +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/Vtx3BodyTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "CommonConstants/PhysicsConstants.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +using MCLabeledTracksIU = soa::Join; + +struct threebodyKFTask { + + Produces outputMCTable; + std::vector filledMothers; + std::vector isGoodCollision; + + // Configurables + Configurable bachelorPdgCode{"bachelorPdgCode", 1000010020, "pdgCode of bachelor daughter"}; + Configurable motherPdgCode{"motherPdgCode", 1010010030, "pdgCode of mother"}; + + ConfigurableAxis m2PrPiBins{"m2PrPiBins", {60, 1., 3.3}, "Binning for m2(p,pi) axis"}; + ConfigurableAxis m2PiDeBins{"m2PiDeBins", {120, 4.0, 8.0}, "Binning for m2(pi,d) axis"}; + + // collision filter and preslice + Filter collisionFilter = (aod::evsel::sel8 == true && nabs(aod::collision::posZ) < 10.f); + Preslice perCollisionVtx3BodyDatas = o2::aod::vtx3body::collisionId; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext const&) + { + const AxisSpec axisM2PrPi{m2PrPiBins, "#it{m}^{2}(p,#pi^{-}) ((GeV/#it{c}^{2})^{2})"}; + const AxisSpec axisM2PiDe{m2PiDeBins, "#it{m}^{2}(#pi^{+},#bar{d}) ((GeV/#it{c}^{2})^{2})"}; + + registry.add("hCentFT0C", "hCentFT0C", HistType::kTH1F, {{100, 0.0f, 100.0f, "FT0C Centrality"}}); + + // mass spectrum of reco candidates + registry.add("hMassHypertriton", "Mass hypertriton", HistType::kTH1F, {{80, 2.96f, 3.04f, "#it{m}(p,#pi^{-},d) (GeV/#it{c}^{2})"}}); + registry.add("hMassAntiHypertriton", "Mass anti-hypertriton", HistType::kTH1F, {{80, 2.96f, 3.04f, "#it{m}(#bar{p},#pi^{+},#bar{d}) (GeV/#it{c}^{2})"}}); + // Dalitz diagrams of reco candidates + registry.add("hDalitzHypertriton", "Dalitz diagram", HistType::kTH2F, {axisM2PrPi, axisM2PiDe})->GetYaxis()->SetTitle("#it{m}^{2}(#pi^{-},d) ((GeV/#it{c}^{2})^{2})"); + registry.add("hDalitzAntiHypertriton", "Dalitz diagram", HistType::kTH2F, {axisM2PrPi, axisM2PiDe})->GetXaxis()->SetTitle("#it{m}^{2}(#bar{p},#pi^{+}) ((GeV/#it{c}^{2})^{2})"); + + // bachelor histgrams + registry.add("hAverageITSClusterSizeBachelor", "Average ITS cluster size bachelor track", HistType::kTH1F, {{15, 0.5, 15.5, "#langle ITS cluster size #rangle"}}); + registry.add("hdEdxBachelor", "TPC dE/dx bachelor track", HistType::kTH1F, {{200, 0.0f, 200.0f, "Average ITS cluster size"}}); + registry.add("hPIDTrackingBachelor", "Tracking PID bachelor track", HistType::kTH1F, {{20, 0.5, 20.5, "Tracking PID identifier"}}); + + // for gen information of reco candidates + auto LabelHist = registry.add("hLabelCounter", "Reco MC candidate counter", HistType::kTH1F, {{3, 0.0f, 3.0f}}); + LabelHist->GetXaxis()->SetBinLabel(1, "Total"); + LabelHist->GetXaxis()->SetBinLabel(2, "Have Same MotherTrack"); + LabelHist->GetXaxis()->SetBinLabel(3, "True H3L/Anti-H3L"); + registry.add("hTrueHypertritonMCPt", "pT gen. of reco. H3L", HistType::kTH1F, {{100, -10.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}}); + registry.add("hTrueHypertritonMCMass", "mass gen. of reco. H3L", HistType::kTH1F, {{40, 2.96f, 3.04f, "#it{m}(p,#pi^{-},d) (GeV/#it{c}^{2})"}}); + registry.add("hTrueHypMassWithMuReco", "mass gen. of reco. H3L", HistType::kTH1F, {{40, 2.96f, 3.04f, "#it{m}(p,#pi^{-},d) (GeV/#it{c}^{2})"}}); + registry.add("hTrueHypertritonMCCTau", "#it{c}#tau gen. of reco. H3L", HistType::kTH1F, {{50, 0.0f, 50.0f, "#it{c}#tau(cm)"}}); + registry.add("hTrueHypertritonMCMassPrPi", "inv. mass gen. of reco. V0 pair (H3L)", HistType::kTH1F, {{100, 0.0f, 6.0f, "#it{m}(p,#pi^{-}) (GeV/#it{c}^{2})"}}); + + // for gen information of non reco candidates + registry.add("hTrueHypertritonMCMassPrPi_nonReco", "inv. mass gen. of non-reco. V0 pair (H3L)", HistType::kTH1F, {{100, 0.0f, 6.0f, "#it{m}(p,#pi^{-}) (GeV/#it{c}^{2})"}}); + registry.add("hTrueHypertritonMCPtPion_nonReco", "Pion #it{p}_{T} gen. of non-reco. H3L", HistType::kTH1F, {{100, 0.0f, 6.0f, "#it{p}_{T}(#pi) (GeV/#it{c})"}}); + registry.add("hTrueHypertritonMCPtProton_nonReco", "Proton #it{p}_{T} gen. of non-reco. H3L", HistType::kTH1F, {{100, 0.0f, 6.0f, "#it{p}_{T}(p) (GeV/#it{c})"}}); + } + + // helper function to check if a mother track is a true H3L/Anti-H3L + template + int checkH3LTruth(MCTrack3B const& mcParticlePr, MCTrack3B const& mcParticlePi, MCTrack3B const& mcParticleDe, bool& isMuonReco) + { + if (abs(mcParticlePr.pdgCode()) != 2212 || abs(mcParticleDe.pdgCode()) != 1000010020) { + return -1; + } + // check proton and deuteron mother + int prDeMomID = -1; + for (const auto& motherPr : mcParticlePr.template mothers_as()) { + for (const auto& motherDe : mcParticleDe.template mothers_as()) { + if (motherPr.globalIndex() == motherDe.globalIndex() && std::abs(motherPr.pdgCode()) == 1010010030) { + prDeMomID = motherPr.globalIndex(); + break; + } + } + } + if (prDeMomID == -1) { + return -1; + } + if (std::abs(mcParticlePi.pdgCode()) != 211 && std::abs(mcParticlePi.pdgCode()) != 13) { + return -1; + } + // check if the pion track is a muon coming from a pi -> mu + vu decay, if yes, take the mother pi + auto mcParticlePiTmp = mcParticlePi; + if (std::abs(mcParticlePiTmp.pdgCode()) == 13) { + for (const auto& motherPi : mcParticlePiTmp.template mothers_as()) { + if (std::abs(motherPi.pdgCode()) == 211) { + mcParticlePiTmp = motherPi; + isMuonReco = true; + break; + } + } + } + // now loop over the pion mother + for (const auto& motherPi : mcParticlePiTmp.template mothers_as()) { + if (motherPi.globalIndex() == prDeMomID) { + return motherPi.globalIndex(); + } + } + return -1; + } + + template + void fillQAPlots(TCand const& vtx3body) + { + // Mass plot + if (vtx3body.track2sign() > 0) { // hypertriton + registry.fill(HIST("hMassHypertriton"), vtx3body.mass()); + } else if (vtx3body.track2sign() < 0) { // anti-hypertriton + registry.fill(HIST("hMassAntiHypertriton"), vtx3body.mass()); + } + + // Dalitz plot + auto m2prpi = RecoDecay::m2(array{array{vtx3body.pxtrack0(), vtx3body.pytrack0(), vtx3body.pztrack0()}, array{vtx3body.pxtrack1(), vtx3body.pytrack1(), vtx3body.pztrack1()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); + auto m2pide = RecoDecay::m2(array{array{vtx3body.pxtrack1(), vtx3body.pytrack1(), vtx3body.pztrack1()}, array{vtx3body.pxtrack2(), vtx3body.pytrack2(), vtx3body.pztrack2()}}, array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); + if (std::abs(vtx3body.mass() - o2::constants::physics::MassHyperTriton) <= 0.005) { + if (vtx3body.track2sign() > 0) { // hypertriton + registry.fill(HIST("hDalitzHypertriton"), m2prpi, m2pide); + } else if (vtx3body.track2sign() < 0) { // anti-hypertriton + registry.fill(HIST("hDalitzAntiHypertriton"), m2prpi, m2pide); + } + } + + // ITS cluster sizes + registry.fill(HIST("hAverageITSClusterSizeBachelor"), vtx3body.itsclussizedeuteron()); + registry.fill(HIST("hdEdxBachelor"), vtx3body.tpcdedxdeuteron()); + registry.fill(HIST("hPIDTrackingBachelor"), vtx3body.pidtrackingdeuteron()); + } + + //------------------------------------------------------------------ + // process real data analysis + void processData(soa::Filtered>::iterator const& collision, + aod::KFVtx3BodyDatas const& vtx3bodydatas) + { + registry.fill(HIST("hCentFT0C"), collision.centFT0C()); + + for (auto& vtx3bodydata : vtx3bodydatas) { + // QA histograms + fillQAPlots(vtx3bodydata); + } + } + PROCESS_SWITCH(threebodyKFTask, processData, "Data analysis", true); + + //------------------------------------------------------------------ + // process mc analysis + void processMC(soa::Join const& collisions, + aod::KFVtx3BodyDatas const& vtx3bodydatas, + aod::McParticles const& particlesMC, + MCLabeledTracksIU const&, + aod::McCollisions const& mcCollisions) + { + filledMothers.clear(); + isGoodCollision.resize(mcCollisions.size(), false); + + // loop over collisions + for (const auto& collision : collisions) { + // event selection + if (!collision.sel8() || std::abs(collision.posZ()) > 10.f) { + continue; + } + // reco collision survived event selection filter --> fill value for MC collision if collision is "true" MC collision + if (collision.mcCollisionId() >= 0) { + isGoodCollision[collision.mcCollisionId()] = true; + } + + // fill MC table with reco MC candidate information and gen information if matched to MC particle + auto Decay3BodyTable_thisCollision = vtx3bodydatas.sliceBy(perCollisionVtx3BodyDatas, collision.globalIndex()); + for (auto& vtx3bodydata : Decay3BodyTable_thisCollision) { + registry.fill(HIST("hLabelCounter"), 0.5); + + // fill QA histograms for all reco candidates + fillQAPlots(vtx3bodydata); + + auto track0 = vtx3bodydata.track0_as(); + auto track1 = vtx3bodydata.track1_as(); + auto track2 = vtx3bodydata.track2_as(); + + if (!track0.has_mcParticle() || !track1.has_mcParticle() || !track2.has_mcParticle()) { + continue; + } + + auto mcTrack0 = track0.mcParticle_as(); + auto mcTrack1 = track1.mcParticle_as(); + auto mcTrack2 = track2.mcParticle_as(); + + float genPosPt = mcTrack0.pt(); + float genPosP = mcTrack0.p(); + int daughter0PDGcode = mcTrack0.pdgCode(); + float genNegPt = mcTrack1.pt(); + float genNegP = mcTrack1.p(); + int daughter1PDGcode = mcTrack1.pdgCode(); + float genBachPt = mcTrack2.pt(); + float genBachP = mcTrack2.p(); + int daughter2PDGcode = mcTrack2.pdgCode(); + bool isBachPrimary = mcTrack2.isPhysicalPrimary(); + + double MClifetime = -1.; + bool isTrueH3L = false; + bool isTrueAntiH3L = false; + float genPhi = -1.; + float genEta = -1.; + float genRap = -1.; + float genP = -1.; + float genPt = -1.; + std::array genDecVtx{-1.f}; + bool isMuonReco = false; + auto& mcTrackPr = vtx3bodydata.sign() > 0 ? mcTrack0 : mcTrack1; + auto& mcTrackPi = vtx3bodydata.sign() > 0 ? mcTrack1 : mcTrack0; + auto& mcTrackDe = mcTrack2; + int motherID = checkH3LTruth(mcTrackPr, mcTrackPi, mcTrackDe, isMuonReco); + if (motherID > 0) { + auto mcTrackHyp = particlesMC.rawIteratorAt(motherID); + genPhi = mcTrackHyp.phi(); + genEta = mcTrackHyp.eta(); + genPt = mcTrackHyp.pt(); + int chargeFactor = mcTrackHyp.pdgCode() > 0 ? 1 : -1; + isTrueH3L = chargeFactor > 0; + isTrueAntiH3L = chargeFactor < 0; + MClifetime = RecoDecay::sqrtSumOfSquares(mcTrackPr.vx() - mcTrackHyp.vx(), mcTrackPr.vy() - mcTrackHyp.vy(), mcTrackPr.vz() - mcTrackHyp.vz()) * o2::constants::physics::MassHyperTriton / mcTrackHyp.p(); + double MCMass = RecoDecay::m(array{array{mcTrackPr.px(), mcTrackPr.py(), mcTrackPr.pz()}, array{mcTrackPi.px(), mcTrackPi.py(), mcTrackPi.pz()}, array{mcTrackDe.px(), mcTrackDe.py(), mcTrackDe.pz()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); + float MCmassPrPi = RecoDecay::m(array{array{mcTrackPr.px(), mcTrackPr.py(), mcTrackPr.pz()}, array{mcTrackPi.px(), mcTrackPi.py(), mcTrackPi.pz()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); + registry.fill(HIST("hLabelCounter"), 2.5); + registry.fill(HIST("hTrueHypertritonMCPt"), mcTrackHyp.pt() * chargeFactor); + registry.fill(HIST("hTrueHypertritonMCCTau"), MClifetime); + registry.fill(HIST("hTrueHypertritonMCMass"), MCMass); + registry.fill(HIST("hTrueHypertritonMCMassPrPi"), MCmassPrPi); + if (isMuonReco) { + registry.fill(HIST("hTrueHypMassWithMuReco"), MCMass); + } + filledMothers.push_back(mcTrackHyp.globalIndex()); + } + outputMCTable( // filled for each reconstructed candidate (in KFVtx3BodyDatas) + vtx3bodydata.mass(), + vtx3bodydata.x(), vtx3bodydata.y(), vtx3bodydata.z(), + vtx3bodydata.xerr(), vtx3bodydata.yerr(), vtx3bodydata.zerr(), + vtx3bodydata.px(), vtx3bodydata.py(), vtx3bodydata.pz(), vtx3bodydata.pt(), + vtx3bodydata.pxerr(), vtx3bodydata.pyerr(), vtx3bodydata.pzerr(), vtx3bodydata.pterr(), + vtx3bodydata.sign(), + vtx3bodydata.dcavtxtopvkf(), vtx3bodydata.dcaxyvtxtopvkf(), + vtx3bodydata.vtxcospakf(), vtx3bodydata.vtxcosxypakf(), + vtx3bodydata.vtxcospakftopo(), vtx3bodydata.vtxcosxypakftopo(), + vtx3bodydata.decaylkf(), vtx3bodydata.decaylxykf(), vtx3bodydata.decayldeltal(), + vtx3bodydata.chi2geondf(), vtx3bodydata.chi2topondf(), + vtx3bodydata.ctaukftopo(), + vtx3bodydata.trackedclsize(), + vtx3bodydata.massv0(), vtx3bodydata.chi2massv0(), + vtx3bodydata.cospav0(), + vtx3bodydata.pxtrack0(), vtx3bodydata.pytrack0(), vtx3bodydata.pztrack0(), // proton + vtx3bodydata.pxtrack1(), vtx3bodydata.pytrack1(), vtx3bodydata.pztrack1(), // pion + vtx3bodydata.pxtrack2(), vtx3bodydata.pytrack2(), vtx3bodydata.pztrack2(), // deuteron + vtx3bodydata.tpcinnerparamtrack0(), vtx3bodydata.tpcinnerparamtrack1(), vtx3bodydata.tpcinnerparamtrack2(), // proton, pion, deuteron + vtx3bodydata.tpcncltrack0(), vtx3bodydata.tpcncltrack1(), vtx3bodydata.tpcncltrack1(), // proton, pion, deuteron + vtx3bodydata.tpcchi2ncldeuteron(), + vtx3bodydata.deltaphideuteron(), vtx3bodydata.deltaphiproton(), + vtx3bodydata.dcatrack0topvkf(), vtx3bodydata.dcatrack1topvkf(), vtx3bodydata.dcatrack2topvkf(), // proton, pion, deuteron + vtx3bodydata.dcaxytrack0topvkf(), vtx3bodydata.dcaxytrack1topvkf(), vtx3bodydata.dcaxytrack2topvkf(), // proton, pion, deuteron + vtx3bodydata.dcaxytrack0tosvkf(), vtx3bodydata.dcaxytrack1tosvkf(), vtx3bodydata.dcaxytrack2tosvkf(), // proton, pion, deuteron + vtx3bodydata.dcatrack0totrack1kf(), vtx3bodydata.dcatrack0totrack2kf(), vtx3bodydata.dcatrack1totrack2kf(), + vtx3bodydata.dcavtxdaughterskf(), + vtx3bodydata.dcaxytrackpostopv(), vtx3bodydata.dcaxytracknegtopv(), vtx3bodydata.dcaxytrackbachtopv(), + vtx3bodydata.dcatrackpostopv(), vtx3bodydata.dcatracknegtopv(), vtx3bodydata.dcatrackbachtopv(), + vtx3bodydata.track0sign(), vtx3bodydata.track1sign(), vtx3bodydata.track2sign(), // proton, pion, deuteron + vtx3bodydata.tpcnsigmaproton(), vtx3bodydata.tpcnsigmapion(), vtx3bodydata.tpcnsigmadeuteron(), vtx3bodydata.tpcnsigmapionbach(), + vtx3bodydata.tpcdedxproton(), vtx3bodydata.tpcdedxpion(), vtx3bodydata.tpcdedxdeuteron(), + vtx3bodydata.tofnsigmadeuteron(), + vtx3bodydata.itsclussizedeuteron(), + vtx3bodydata.pidtrackingdeuteron(), + // MC info (-1 if not matched to MC particle) + genP, + genPt, + genDecVtx[0], genDecVtx[1], genDecVtx[2], + MClifetime, + genPhi, + genEta, + genRap, + genPosP, genPosPt, genNegP, genNegPt, genBachP, genBachPt, + isTrueH3L, isTrueAntiH3L, + daughter0PDGcode, daughter1PDGcode, daughter2PDGcode, isBachPrimary, + true, // is reconstructed + true); // reco event passed event selection + } // end vtx3bodydatas loop + } // end collision loop + + // generated MC particle analysis + // fill MC table with gen information for all generated but not reconstructed particles + for (auto& mcparticle : particlesMC) { + + double genMCmassPrPi = -1.; + bool isTrueGenH3L = false; + bool isTrueGenAntiH3L = false; + float genPBach = -1.; + float genPtBach = -1.; + float genPPos = -1.; + float genPtPos = -1.; + float genPNeg = -1.; + float genPtNeg = -1.; + int posDauPdgCode = -1; + int negDauPdgCode = -1; + int bachDauPdgCode = -1; + + // check if mcparticle was reconstructed and already filled in the table + if (std::find(filledMothers.begin(), filledMothers.end(), mcparticle.globalIndex()) != std::end(filledMothers)) { + continue; + } + + // set flag if corresponding reco collision survived event selection + bool survEvSel = isGoodCollision[mcparticle.mcCollisionId()]; + + // check if MC particle is hypertriton with 3-body decay + if (std::abs(mcparticle.pdgCode()) != motherPdgCode) { + continue; + } + bool haveProton = false, havePion = false, haveBachelor = false; + bool haveAntiProton = false, haveAntiPion = false, haveAntiBachelor = false; + for (auto& mcparticleDaughter : mcparticle.template daughters_as()) { + if (mcparticleDaughter.pdgCode() == 2212) + haveProton = true; + if (mcparticleDaughter.pdgCode() == -2212) + haveAntiProton = true; + if (mcparticleDaughter.pdgCode() == 211) + havePion = true; + if (mcparticleDaughter.pdgCode() == -211) + haveAntiPion = true; + if (mcparticleDaughter.pdgCode() == bachelorPdgCode) + haveBachelor = true; + if (mcparticleDaughter.pdgCode() == -bachelorPdgCode) + haveAntiBachelor = true; + } + + // check if particle or anti-particle + if (haveProton && haveAntiPion && haveBachelor && mcparticle.pdgCode() > 0) { + isTrueGenH3L = true; + // get proton and pion daughter + std::array protonMom{0.f}; + std::array piMinusMom{0.f}; + for (auto& mcparticleDaughter : mcparticle.template daughters_as()) { + if (mcparticleDaughter.pdgCode() == 2212) { + protonMom = {mcparticleDaughter.px(), mcparticleDaughter.py(), mcparticleDaughter.pz()}; + genPPos = mcparticleDaughter.p(); + genPtPos = mcparticleDaughter.pt(); + posDauPdgCode = mcparticleDaughter.pdgCode(); + } else if (mcparticleDaughter.pdgCode() == -211) { + piMinusMom = {mcparticleDaughter.px(), mcparticleDaughter.py(), mcparticleDaughter.pz()}; + genPNeg = mcparticleDaughter.p(); + genPtNeg = mcparticleDaughter.pt(); + negDauPdgCode = mcparticleDaughter.pdgCode(); + } + } + genMCmassPrPi = RecoDecay::m(array{protonMom, piMinusMom}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); + registry.fill(HIST("hTrueHypertritonMCMassPrPi_nonReco"), genMCmassPrPi); + registry.fill(HIST("hTrueHypertritonMCPtProton_nonReco"), RecoDecay::sqrtSumOfSquares(protonMom[0], protonMom[1])); + registry.fill(HIST("hTrueHypertritonMCPtPion_nonReco"), RecoDecay::sqrtSumOfSquares(piMinusMom[0], piMinusMom[1])); + } else if (haveAntiProton && havePion && haveAntiBachelor && mcparticle.pdgCode() < 0) { + isTrueGenAntiH3L = true; + // get anti-proton and pion daughter + std::array antiProtonMom{0.f}; + std::array piPlusMom{0.f}; + for (auto& mcparticleDaughter : mcparticle.template daughters_as()) { + if (mcparticleDaughter.pdgCode() == -2212) { + antiProtonMom = {mcparticleDaughter.px(), mcparticleDaughter.py(), mcparticleDaughter.pz()}; + genPNeg = mcparticleDaughter.p(); + genPtNeg = mcparticleDaughter.pt(); + negDauPdgCode = mcparticleDaughter.pdgCode(); + } else if (mcparticleDaughter.pdgCode() == 211) { + piPlusMom = {mcparticleDaughter.px(), mcparticleDaughter.py(), mcparticleDaughter.pz()}; + genPPos = mcparticleDaughter.p(); + genPtPos = mcparticleDaughter.pt(); + posDauPdgCode = mcparticleDaughter.pdgCode(); + } + } + genMCmassPrPi = RecoDecay::m(array{antiProtonMom, piPlusMom}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); + registry.fill(HIST("hTrueHypertritonMCMassPrPi_nonReco"), genMCmassPrPi); + registry.fill(HIST("hTrueHypertritonMCPtProton_nonReco"), RecoDecay::sqrtSumOfSquares(antiProtonMom[0], antiProtonMom[1])); + registry.fill(HIST("hTrueHypertritonMCPtPion_nonReco"), RecoDecay::sqrtSumOfSquares(piPlusMom[0], piPlusMom[1])); + } else { + continue; // stop if particle is no true H3L or Anti-H3L + } + + // get gen decay vertex and calculate ctau + std::array genDecayVtx{0.f}; + for (auto& mcDaughter : mcparticle.daughters_as()) { + if (std::abs(mcDaughter.pdgCode()) == bachelorPdgCode) { + genDecayVtx = {mcDaughter.vx(), mcDaughter.vy(), mcDaughter.vz()}; + genPBach = mcDaughter.p(); + genPtBach = mcDaughter.pt(); + bachDauPdgCode = mcDaughter.pdgCode(); + } + } + double genMClifetime = RecoDecay::sqrtSumOfSquares(genDecayVtx[0] - mcparticle.vx(), genDecayVtx[1] - mcparticle.vy(), genDecayVtx[2] - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); + outputMCTable( // reco information (-1) + -1, + -1, -1, -1, + -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, + -1, -1, + -1, -1, + -1, -1, + -1, -1, -1, + -1, -1, + -1, + -1, + -1, -1, + -1, + -1, -1, -1, + -1, -1, -1, + -1, -1, -1, + -1, -1, -1, + -1, -1, -1, + -1, + -1, -1, + -1, -1, -1, + -1, -1, -1, + -1, -1, -1, + -1, -1, -1, + -1, + -1, -1, -1, + -1, -1, -1, + -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, + -1, + -1, + -1, + // gen information + mcparticle.p(), + mcparticle.pt(), + genDecayVtx[0], genDecayVtx[1], genDecayVtx[2], + genMClifetime, + mcparticle.phi(), + mcparticle.eta(), + mcparticle.y(), + genPPos, genPtPos, genPNeg, genPtNeg, genPBach, genPtBach, + isTrueGenH3L, isTrueGenAntiH3L, + posDauPdgCode, negDauPdgCode, bachDauPdgCode, + false, // isBachPrimary + false, // is reconstructed + survEvSel); + } // end mcparticles loop + } + PROCESS_SWITCH(threebodyKFTask, processMC, "MC analysis", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGLF/TableProducer/Nuspex/threebodyRecoTask.cxx b/PWGLF/TableProducer/Nuspex/threebodyRecoTask.cxx index 1daea1d3f77..36af287f95e 100644 --- a/PWGLF/TableProducer/Nuspex/threebodyRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/threebodyRecoTask.cxx @@ -9,12 +9,16 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // -// StoredVtx3BodyDatas analysis task -// ======================== +/// \file threebodyRecoTask.cxx +/// \brief Analysis task for 3-body decay process (now mainly for hypertriton) +/// \author Yuanzhe Wang #include #include #include +#include +#include +#include #include #include "Framework/runDataProcessing.h" @@ -24,72 +28,116 @@ #include "ReconstructionDataFormats/Track.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGLF/DataModel/Vtx3BodyTables.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGLF/DataModel/Reduced3BodyTables.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/PIDResponse.h" #include "CommonConstants/PhysicsConstants.h" +#include "CCDB/BasicCCDBManager.h" + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -using std::array; -using FullTracksExtIU = soa::Join; +using ReducedCols = soa::Join; +using FullTracksExtIU = soa::Join; using MCLabeledTracksIU = soa::Join; +std::vector triggerLabels = { + "fTriggerEventF1Proton", "fTrackedOmega", "fTrackedXi", "fOmegaLargeRadius", + "fDoubleOmega", "fOmegaHighMult", "fSingleXiYN", "fQuadrupleXi", "fDoubleXi", + "fhadronOmega", "fOmegaXi", "fTripleXi", "fOmega", "fGammaVeryLowPtEMCAL", + "fGammaVeryLowPtDCAL", "fGammaHighPtEMCAL", "fGammaLowPtEMCAL", "fGammaVeryHighPtDCAL", + "fGammaVeryHighPtEMCAL", "fGammaLowPtDCAL", "fJetNeutralLowPt", "fJetNeutralHighPt", + "fGammaHighPtDCAL", "fJetFullLowPt", "fJetFullHighPt", "fEMCALReadout", "fPCMandEE", + "fPHOSnbar", "fPCMHighPtPhoton", "fPHOSPhoton", "fLD", "fPPPHI", "fPD", "fLLL", "fPLL", + "fPPL", "fPPP", "fLeadingPtTrack", "fHighFt0cFv0Flat", "fHighFt0cFv0Mult", "fHighFt0Flat", + "fHighFt0Mult", "fHighMultFv0", "fHighTrackMult", "fHfSingleNonPromptCharm3P", + "fHfSingleNonPromptCharm2P", "fHfSingleCharm3P", "fHfPhotonCharm3P", "fHfHighPt2P", + "fHfSigmaC0K0", "fHfDoubleCharm2P", "fHfBeauty3P", "fHfFemto3P", "fHfFemto2P", + "fHfHighPt3P", "fHfSigmaCPPK", "fHfDoubleCharm3P", "fHfDoubleCharmMix", + "fHfPhotonCharm2P", "fHfV0Charm2P", "fHfBeauty4P", "fHfV0Charm3P", "fHfSingleCharm2P", + "fHfCharmBarToXiBach", "fSingleMuHigh", "fSingleMuLow", "fLMeeHMR", "fDiMuon", + "fDiElectron", "fLMeeIMR", "fSingleE", "fTrackHighPt", "fTrackLowPt", "fJetChHighPt", + "fJetChLowPt", "fUDdiffLarge", "fUDdiffSmall", "fITSextremeIonisation", + "fITSmildIonisation", "fH3L3Body", "fHe", "fH2"}; + struct Candidate3body { + // Index int mcmotherId; int track0Id; int track1Id; int track2Id; - std::array posSV; - TLorentzVector lcand; - TLorentzVector lproton; - TLorentzVector lpion; - TLorentzVector lbachelor; - // 0 - proton, 1 - pion, 2 - bachelor - uint8_t dautpcNclusters[3]; - uint8_t dauitsclussize[3]; - uint8_t daudcatopv[3]; - float dautpcNsigma[3]; + // Collision + float colCentFT0C; + // sv and candidate bool isMatter; float invmass; float ct; float cosPA; float dcadaughters; float dcacandtopv; + float vtxradius; + // daughter tracks + TLorentzVector lcand; + TLorentzVector lproton; + TLorentzVector lpion; + TLorentzVector lbachelor; + uint8_t dautpcNclusters[3]; // 0 - proton, 1 - pion, 2 - bachelor + uint32_t dauitsclussize[3]; // 0 - proton, 1 - pion, 2 - bachelor + float daudcaxytopv[3]; // 0 - proton, 1 - pion, 2 - bachelor + float daudcatopv[3]; // 0 - proton, 1 - pion, 2 - bachelor + float dautpcNsigma[3]; // 0 - proton, 1 - pion, 2 - bachelor + float dauinnermostR[3]; // 0 - proton, 1 - pion, 2 - bachelor !!! TracksIU required !!! float bachelortofNsigma; + bool isBachPrimary = false; + // MC infomartion TLorentzVector lgencand = {0, 0, 0, 0}; float genct = -1; + float genrapidity = -999; bool isSignal = false; bool isReco = false; int pdgCode = -1; - bool SurvivedEventSelection = false; + bool survivedEventSelection = false; }; -struct threebodyRecoTask { +struct ThreebodyRecoTask { Produces outputDataTable; Produces outputMCTable; - std::vector Candidates3body; + std::vector candidates3body; std::vector filledMothers; std::vector isGoodCollision; + Service ccdb; + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + //------------------------------------------------------------------ + PresliceUnsorted perCollisionVtx3BodyDatas = o2::aod::vtx3body::collisionId; + + // Configurable for trigger selection + Configurable triggerList{"triggerList", "fTriggerEventF1Proton, fTrackedOmega, fTrackedXi, fOmegaLargeRadius, fDoubleOmega, fOmegaHighMult, fSingleXiYN, fQuadrupleXi, fDoubleXi, fhadronOmega, fOmegaXi, fTripleXi, fOmega, fGammaVeryLowPtEMCAL, fGammaVeryLowPtDCAL, fGammaHighPtEMCAL, fGammaLowPtEMCAL, fGammaVeryHighPtDCAL, fGammaVeryHighPtEMCAL, fGammaLowPtDCAL, fJetNeutralLowPt, fJetNeutralHighPt, fGammaHighPtDCAL, fJetFullLowPt, fJetFullHighPt, fEMCALReadout, fPCMandEE, fPHOSnbar, fPCMHighPtPhoton, fPHOSPhoton, fLD, fPPPHI, fPD, fLLL, fPLL, fPPL, fPPP, fLeadingPtTrack, fHighFt0cFv0Flat, fHighFt0cFv0Mult, fHighFt0Flat, fHighFt0Mult, fHighMultFv0, fHighTrackMult, fHfSingleNonPromptCharm3P, fHfSingleNonPromptCharm2P, fHfSingleCharm3P, fHfPhotonCharm3P, fHfHighPt2P, fHfSigmaC0K0, fHfDoubleCharm2P, fHfBeauty3P, fHfFemto3P, fHfFemto2P, fHfHighPt3P, fHfSigmaCPPK, fHfDoubleCharm3P, fHfDoubleCharmMix, fHfPhotonCharm2P, fHfV0Charm2P, fHfBeauty4P, fHfV0Charm3P, fHfSingleCharm2P, fHfCharmBarToXiBach, fSingleMuHigh, fSingleMuLow, fLMeeHMR, fDiMuon, fDiElectron, fLMeeIMR, fSingleE, fTrackHighPt, fTrackLowPt, fJetChHighPt, fJetChLowPt, fUDdiffLarge, fUDdiffSmall, fITSextremeIonisation, fITSmildIonisation, fH3L3Body, fHe, fH2", "List of triggers used to select events"}; + Configurable cfgOnlyKeepInterestedTrigger{"cfgOnlyKeepInterestedTrigger", false, "Flag to keep only interested trigger"}; + Configurable bcTolerance{"bcTolerance", 100, "Tolerance for BC in Zorro"}; + // Configuration to enable like-sign analysis + Configurable cfgLikeSignAnalysis{"cfgLikeSignAnalysis", false, "Enable like-sign analysis"}; // Selection criteria Configurable vtxcospa{"vtxcospa", 0.99, "Vtx CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0) Configurable dcavtxdau{"dcavtxdau", 1.0, "DCA Vtx Daughters"}; // loose cut Configurable dcapiontopv{"dcapiontopv", .05, "DCA Pion To PV"}; Configurable etacut{"etacut", 0.9, "etacut"}; Configurable rapiditycut{"rapiditycut", 1, "rapiditycut"}; - Configurable TofPidNsigmaMin{"TofPidNsigmaMin", -5, "TofPidNsigmaMin"}; - Configurable TofPidNsigmaMax{"TofPidNsigmaMax", 5, "TofPidNsigmaMax"}; - Configurable TpcPidNsigmaCut{"TpcPidNsigmaCut", 5, "TpcPidNsigmaCut"}; - Configurable event_sel8_selection{"event_sel8_selection", true, "event selection count post sel8 cut"}; - Configurable event_posZ_selection{"event_posZ_selection", true, "event selection count post poZ cut"}; + Configurable tofPIDNSigmaMin{"tofPIDNSigmaMin", -5, "tofPIDNSigmaMin"}; + Configurable tofPIDNSigmaMax{"tofPIDNSigmaMax", 5, "tofPIDNSigmaMax"}; + Configurable tpcPIDNSigmaCut{"tpcPIDNSigmaCut", 5, "tpcPIDNSigmaCut"}; + Configurable eventSel8Cut{"eventSel8Cut", true, "flag to enable event sel8 selection"}; + Configurable mcEventCut{"mcEventCut", true, "flag to enable mc event selection: kIsTriggerTVX and kNoTimeFrameBorder"}; + Configurable eventPosZCut{"eventPosZCut", true, "flag to enable event posZ selection"}; Configurable lifetimecut{"lifetimecut", 40., "lifetimecut"}; // ct Configurable minProtonPt{"minProtonPt", 0.3, "minProtonPt"}; Configurable maxProtonPt{"maxProtonPt", 5, "maxProtonPt"}; @@ -108,32 +156,31 @@ struct threebodyRecoTask { Configurable bachelorPdgCode{"bachelorPdgCode", 1000010020, "pdgCode of bachelor daughter"}; Configurable motherPdgCode{"motherPdgCode", 1010010030, "pdgCode of mother track"}; + // 3sigma region for Dalitz plot + float lowersignallimit = o2::constants::physics::MassHyperTriton - 3 * mcsigma; + float uppersignallimit = o2::constants::physics::MassHyperTriton + 3 * mcsigma; + + // CCDB options + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable pidPath{"pidPath", "", "Path to the PID response object"}; + + // Zorro counting + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; + HistogramRegistry registry{ "registry", { - {"hEventCounter", "hEventCounter", {HistType::kTH1F, {{4, 0.0f, 4.0f}}}}, + {"hEventCounter", "hEventCounter", {HistType::kTH1F, {{5, 0.0f, 5.0f}}}}, + {"hCentFT0C", "hCentFT0C", {HistType::kTH1F, {{100, 0.0f, 100.0f, "FT0C Centrality"}}}}, {"hCandidatesCounter", "hCandidatesCounter", {HistType::kTH1F, {{12, 0.0f, 12.0f}}}}, {"hMassHypertriton", "hMassHypertriton", {HistType::kTH1F, {{80, 2.96f, 3.04f}}}}, {"hMassAntiHypertriton", "hMassAntiHypertriton", {HistType::kTH1F, {{80, 2.96f, 3.04f}}}}, {"hMassHypertritonTotal", "hMassHypertritonTotal", {HistType::kTH1F, {{300, 2.9f, 3.2f}}}}, - {"hPtProton", "hPtProton", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPtPionMinus", "hPtPionMinus", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPtDeuteron", "hPtDeuteron", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPtAntiProton", "hPtAntiProton", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPtPionPlus", "hPtPionPlus", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPtAntiDeuteron", "hPtAntiDeuteron", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDCAProtonToPV", "hDCAProtonToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, - {"hDCAPionToPV", "hDCAPionToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, - {"hDCADeuteronToPV", "hDCADeuteronToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, - {"hProtonTPCNcls", "hProtonTPCNcls", {HistType::kTH1F, {{180, 0, 180, "TPC cluster"}}}}, - {"hPionTPCNcls", "hPionTPCNcls", {HistType::kTH1F, {{180, 0, 180, "TPC cluster"}}}}, - {"hDeuteronTPCNcls", "hDeuteronTPCNcls", {HistType::kTH1F, {{180, 0, 180, "TPC cluster"}}}}, - {"hVtxCosPA", "hVtxCosPA", {HistType::kTH1F, {{1000, 0.9f, 1.0f}}}}, - {"hDCAVtxDau", "hDCAVtxDau", {HistType::kTH1F, {{1000, 0.0f, 10.0f, "cm^{2}"}}}}, {"hTOFPIDDeuteron", "hTOFPIDDeuteron", {HistType::kTH1F, {{2000, -100.0f, 100.0f}}}}, - {"hTPCPIDProton", "hTPCPIDProton", {HistType::kTH1F, {{240, -6.0f, 6.0f}}}}, - {"hTPCPIDPion", "hTPCPIDPion", {HistType::kTH1F, {{240, -6.0f, 6.0f}}}}, - {"hTPCPIDDeuteron", "hTPCPIDDeuteron", {HistType::kTH1F, {{240, -6.0f, 6.0f}}}}, {"hProtonTPCBB", "hProtonTPCBB", {HistType::kTH2F, {{160, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, {"hPionTPCBB", "hPionTPCBB", {HistType::kTH2F, {{160, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, {"hDeuteronTPCBB", "hDeuteronTPCBB", {HistType::kTH2F, {{160, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, @@ -144,41 +191,22 @@ struct threebodyRecoTask { {"hDeuteronTOFVsPAtferTOFCut", "hDeuteronTOFVsPAtferTOFCut", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, {"hDalitz", "hDalitz", {HistType::kTH2F, {{120, 7.85, 8.45, "M^{2}(dp) (GeV^{2}/c^{4})"}, {60, 1.1, 1.4, "M^{2}(p#pi) (GeV^{2}/c^{4})"}}}}, - {"h3dMassHypertriton", "h3dMassHypertriton", {HistType::kTH3F, {{20, 0.0f, 100.0f, "Cent (%)"}, {200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}, {80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"}}}}, - {"h3dMassAntiHypertriton", "h3dMassAntiHypertriton", {HistType::kTH3F, {{20, 0.0f, 100.0f, "Cent (%)"}, {200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}, {80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"}}}}, - {"h3dTotalHypertriton", "h3dTotalHypertriton", {HistType::kTH3F, {{50, 0, 50, "ct(cm)"}, {200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}, {80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"}}}}, - - {"hTrueHypertritonCounter", "hTrueHypertritonCounter", {HistType::kTH1F, {{12, 0.0f, 12.0f}}}}, - {"hDeuteronTOFVsPBeforeTOFCutSig", "hDeuteronTOFVsPBeforeTOFCutSig", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, - {"hDeuteronTOFVsPAtferTOFCutSig", "hDeuteronTOFVsPAtferTOFCutSig", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, - {"h3dTotalTrueHypertriton", "h3dTotalTrueHypertriton", {HistType::kTH3F, {{50, 0, 50, "ct(cm)"}, {200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}, {80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"}}}}, - - // for mcparticles information - {"hGeneratedHypertritonCounter", "hGeneratedHypertritonCounter", {HistType::kTH1F, {{2, 0.0f, 2.0f}}}}, - {"hPtGeneratedHypertriton", "hPtGeneratedHypertriton", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hctGeneratedHypertriton", "hctGeneratedHypertriton", {HistType::kTH1F, {{50, 0, 50, "ct(cm)"}}}}, - {"hEtaGeneratedHypertriton", "hEtaGeneratedHypertriton", {HistType::kTH1F, {{40, -2.0f, 2.0f}}}}, - {"hRapidityGeneratedHypertriton", "hRapidityGeneratedHypertriton", {HistType::kTH1F, {{40, -2.0f, 2.0f}}}}, - {"hPtGeneratedAntiHypertriton", "hPtGeneratedAntiHypertriton", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hctGeneratedAntiHypertriton", "hctGeneratedAntiHypertriton", {HistType::kTH1F, {{50, 0, 50, "ct(cm)"}}}}, - {"hEtaGeneratedAntiHypertriton", "hEtaGeneratedAntiHypertriton", {HistType::kTH1F, {{40, -2.0f, 2.0f}}}}, - {"hRapidityGeneratedAntiHypertriton", "hRapidityGeneratedAntiHypertriton", {HistType::kTH1F, {{40, -2.0f, 2.0f}}}}, }, }; //------------------------------------------------------------------ // Fill stats histograms - enum vtxstep { kCandAll = 0, - kCandCosPA, + enum Vtxstep { kCandAll = 0, kCandDauEta, + kCandDauPt, + kCandTPCNcls, + kCandTPCPID, + kCandTOFPID, + kCandDcaToPV, kCandRapidity, kCandct, + kCandCosPA, kCandDcaDau, - kCandTOFPID, - kCandTPCPID, - kCandTPCNcls, - kCandDauPt, - kCandDcaToPV, kCandInvMass, kNCandSteps }; @@ -189,12 +217,12 @@ struct threebodyRecoTask { void resetHistos() { - for (Int_t ii = 0; ii < kNCandSteps; ii++) { + for (int ii = 0; ii < kNCandSteps; ii++) { statisticsRegistry.candstats[ii] = 0; statisticsRegistry.truecandstats[ii] = 0; } } - void FillCandCounter(int kn, bool istrue = false) + void fillCandCounter(int kn, bool istrue = false) { statisticsRegistry.candstats[kn]++; if (istrue) { @@ -203,39 +231,91 @@ struct threebodyRecoTask { } void fillHistos() { - for (Int_t ii = 0; ii < kNCandSteps; ii++) { + for (int ii = 0; ii < kNCandSteps; ii++) { registry.fill(HIST("hCandidatesCounter"), ii, statisticsRegistry.candstats[ii]); - registry.fill(HIST("hTrueHypertritonCounter"), ii, statisticsRegistry.truecandstats[ii]); + if (doprocessMC == true) { + registry.fill(HIST("hTrueHypertritonCounter"), ii, statisticsRegistry.truecandstats[ii]); + } } } - ConfigurableAxis dcaBinning{"dca-binning", {200, 0.0f, 1.0f}, ""}; - ConfigurableAxis ptBinning{"pt-binning", {200, 0.0f, 10.0f}, ""}; + int mRunNumber; void init(InitContext const&) { - AxisSpec dcaAxis = {dcaBinning, "DCA (cm)"}; - AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/c)"}; - AxisSpec massAxisHypertriton = {80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"}; + zorroSummary.setObject(zorro.getZorroSummary()); + + mRunNumber = 0; + + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(1, "total"); registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(2, "sel8"); registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(3, "vertexZ"); - registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(4, "has Candidate"); + registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(4, "Zorro H3L 3body event"); + registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(5, "has Candidate"); + + // Check for selection criteria !!! TracksIU required !!! + registry.add("hDiffRVtxProton", "hDiffRVtxProton", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of proton + registry.add("hDiffRVtxPion", "hDiffRVtxPion", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of pion + registry.add("hDiffRVtxDeuteron", "hDiffRVtxDeuteron", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of deuteron + registry.add("hDiffDaughterR", "hDiffDaughterR", HistType::kTH1F, {{10000, -100, 100}}); // difference between minR of pion&proton and R of deuteron(bachelor) + + // Check triggers + auto hEventTriggerCount = registry.add("hEventTriggerCount", "hEventTriggerCount", HistType::kTH1F, {{static_cast(triggerLabels.size() + 1), 0, static_cast(triggerLabels.size() + 1)}}); + for (size_t i = 0; i < triggerLabels.size(); i++) { + hEventTriggerCount->GetXaxis()->SetBinLabel(i + 1, triggerLabels[i].c_str()); + } + hEventTriggerCount->GetXaxis()->SetBinLabel(triggerLabels.size() + 1, "NoTrigger"); + + if (cfgLikeSignAnalysis) { + registry.add("hInvMassCorrectSign", "hInvMassCorrectSign", HistType::kTH1F, {{80, 2.96f, 3.04f}}); // check if there are contamination of possible signals which are caused by unexpected PID + } + + if (doprocessMC == true) { + registry.add("hTrueHypertritonCounter", "hTrueHypertritonCounter", HistType::kTH1F, {{12, 0.0f, 12.0f}}); + auto hGeneratedHypertritonCounter = registry.add("hGeneratedHypertritonCounter", "hGeneratedHypertritonCounter", HistType::kTH1F, {{2, 0.0f, 2.0f}}); + hGeneratedHypertritonCounter->GetXaxis()->SetBinLabel(1, "Total"); + hGeneratedHypertritonCounter->GetXaxis()->SetBinLabel(2, "3-body decay"); + registry.add("hPtGeneratedHypertriton", "hPtGeneratedHypertriton", HistType::kTH1F, {{200, 0.0f, 10.0f}}); + registry.add("hctGeneratedHypertriton", "hctGeneratedHypertriton", HistType::kTH1F, {{50, 0, 50, "ct(cm)"}}); + registry.add("hEtaGeneratedHypertriton", "hEtaGeneratedHypertriton", HistType::kTH1F, {{40, -2.0f, 2.0f}}); + registry.add("hRapidityGeneratedHypertriton", "hRapidityGeneratedHypertriton", HistType::kTH1F, {{40, -2.0f, 2.0f}}); + registry.add("hPtGeneratedAntiHypertriton", "hPtGeneratedAntiHypertriton", HistType::kTH1F, {{200, 0.0f, 10.0f}}); + registry.add("hctGeneratedAntiHypertriton", "hctGeneratedAntiHypertriton", HistType::kTH1F, {{50, 0, 50, "ct(cm)"}}); + registry.add("hEtaGeneratedAntiHypertriton", "hEtaGeneratedAntiHypertriton", HistType::kTH1F, {{40, -2.0f, 2.0f}}); + registry.add("hRapidityGeneratedAntiHypertriton", "hRapidityGeneratedAntiHypertriton", HistType::kTH1F, {{40, -2.0f, 2.0f}}); + } - TString CandCounterbinLabel[12] = {"Total", "VtxCosPA", "TrackEta", "MomRapidity", "Lifetime", "VtxDcaDau", "d TOFPID", "TPCPID", "TPCNcls", "DauPt", "PionDcatoPV", "InvMass"}; + TString candCounterbinLabel[kNCandSteps] = {"Total", "TrackEta", "DauPt", "TPCNcls", "TPCPID", "d TOFPID", "PionDcatoPV", "MomRapidity", "Lifetime", "VtxCosPA", "VtxDcaDau", "InvMass"}; for (int i{0}; i < kNCandSteps; i++) { - registry.get(HIST("hCandidatesCounter"))->GetXaxis()->SetBinLabel(i + 1, CandCounterbinLabel[i]); - registry.get(HIST("hTrueHypertritonCounter"))->GetXaxis()->SetBinLabel(i + 1, CandCounterbinLabel[i]); + registry.get(HIST("hCandidatesCounter"))->GetXaxis()->SetBinLabel(i + 1, candCounterbinLabel[i]); + if (doprocessMC == true) { + registry.get(HIST("hTrueHypertritonCounter"))->GetXaxis()->SetBinLabel(i + 1, candCounterbinLabel[i]); + } + } + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + if (cfgSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), triggerList); + zorro.populateHistRegistry(registry, bc.runNumber()); } - registry.get(HIST("hGeneratedHypertritonCounter"))->GetXaxis()->SetBinLabel(1, "Total"); - registry.get(HIST("hGeneratedHypertritonCounter"))->GetXaxis()->SetBinLabel(2, "3-body decay"); + LOGF(info, "Initializing CCDB for run %d", bc.runNumber()); + mRunNumber = bc.runNumber(); } //------------------------------------------------------------------ - Preslice perCollisionVtx3BodyDatas = o2::aod::vtx3body::collisionId; - //------------------------------------------------------------------ + // Check if the mcparticle is hypertriton which decays into 3 daughters template bool is3bodyDecayed(TMCParticle const& particle) { @@ -244,14 +324,14 @@ struct threebodyRecoTask { } bool haveProton = false, havePion = false, haveBachelor = false; bool haveAntiProton = false, haveAntiPion = false, haveAntiBachelor = false; - for (auto& mcparticleDaughter : particle.template daughters_as()) { - if (mcparticleDaughter.pdgCode() == 2212) + for (const auto& mcparticleDaughter : particle.template daughters_as()) { + if (mcparticleDaughter.pdgCode() == PDG_t::kProton) haveProton = true; - if (mcparticleDaughter.pdgCode() == -2212) + if (mcparticleDaughter.pdgCode() == PDG_t::kProtonBar) haveAntiProton = true; - if (mcparticleDaughter.pdgCode() == 211) + if (mcparticleDaughter.pdgCode() == PDG_t::kPiPlus) havePion = true; - if (mcparticleDaughter.pdgCode() == -211) + if (mcparticleDaughter.pdgCode() == PDG_t::kPiMinus) haveAntiPion = true; if (mcparticleDaughter.pdgCode() == bachelorPdgCode) haveBachelor = true; @@ -267,233 +347,357 @@ struct threebodyRecoTask { } //------------------------------------------------------------------ - // Analysis process for a single candidate - template - void CandidateAnalysis(TCollisionTable const& dCollision, TCandTable const& candData, bool& if_hasvtx, bool isTrueCand = false, int lLabel = -1, TLorentzVector lmother = {0, 0, 0, 0}, double MClifetime = -1) + // Event Selection + template + bool eventSelection(TCollision const& collision) { + auto bc = collision.template bc_as(); + initCCDB(bc); + registry.fill(HIST("hEventCounter"), 0.5); - FillCandCounter(kCandAll, isTrueCand); - - auto track0 = candData.template track0_as(); - auto track1 = candData.template track1_as(); - auto track2 = candData.template track2_as(); - - auto& trackProton = (track2.sign() > 0) ? track0 : track1; - auto& trackPion = (track2.sign() > 0) ? track1 : track0; - auto& trackDeuteron = track2; - - float cospa = candData.vtxcosPA(dCollision.posX(), dCollision.posY(), dCollision.posZ()); - if (cospa < vtxcospa) { - return; - } - FillCandCounter(kCandCosPA, isTrueCand); - if (TMath::Abs(trackProton.eta()) > etacut || TMath::Abs(trackPion.eta()) > etacut || TMath::Abs(trackDeuteron.eta()) > etacut) { - return; - } - FillCandCounter(kCandDauEta, isTrueCand); - if (TMath::Abs(candData.yHypertriton()) > rapiditycut) { - return; - } - FillCandCounter(kCandRapidity, isTrueCand); - double ct = candData.distovertotmom(dCollision.posX(), dCollision.posY(), dCollision.posZ()) * o2::constants::physics::MassHyperTriton; - if (ct > lifetimecut) { - return; - } - FillCandCounter(kCandct, isTrueCand); - if (candData.dcaVtxdaughters() > dcavtxdau) { - return; - } - FillCandCounter(kCandDcaDau, isTrueCand); - - registry.fill(HIST("hDeuteronTOFVsPBeforeTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tofNSigmaDe()); - if (isTrueCand) { - registry.fill(HIST("hDeuteronTOFVsPBeforeTOFCutSig"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tofNSigmaDe()); - } - if ((trackDeuteron.tofNSigmaDe() < TofPidNsigmaMin || trackDeuteron.tofNSigmaDe() > TofPidNsigmaMax) && trackDeuteron.p() > minDeuteronPUseTOF) { - return; - } - FillCandCounter(kCandTOFPID, isTrueCand); - registry.fill(HIST("hDeuteronTOFVsPAtferTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tofNSigmaDe()); - if (isTrueCand) { - registry.fill(HIST("hDeuteronTOFVsPAtferTOFCutSig"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tofNSigmaDe()); - } - - if (TMath::Abs(trackProton.tpcNSigmaPr()) > TpcPidNsigmaCut || TMath::Abs(trackPion.tpcNSigmaPi()) > TpcPidNsigmaCut || TMath::Abs(trackDeuteron.tpcNSigmaDe()) > TpcPidNsigmaCut) { - return; + if (eventSel8Cut && !collision.sel8()) { + return false; } - FillCandCounter(kCandTPCPID, isTrueCand); - - if (trackProton.tpcNClsFound() < mintpcNClsproton || trackPion.tpcNClsFound() < mintpcNClspion || trackDeuteron.tpcNClsFound() < mintpcNClsdeuteron) { - return; + registry.fill(HIST("hEventCounter"), 1.5); + if (eventPosZCut && std::abs(collision.posZ()) > 10.f) { // 10cm + return false; } - FillCandCounter(kCandTPCNcls, isTrueCand); + registry.fill(HIST("hEventCounter"), 2.5); + registry.fill(HIST("hCentFT0C"), collision.centFT0C()); - if (trackProton.pt() < minProtonPt || trackProton.pt() > maxProtonPt || trackPion.pt() < minPionPt || trackPion.pt() > maxPionPt || trackDeuteron.pt() < minDeuteronPt || trackDeuteron.pt() > maxDeuteronPt) { - return; + if (cfgSkimmedProcessing) { + bool zorroSelected = zorro.isSelected(bc.globalBC()); /// Just let Zorro do the accounting + if (zorroSelected) { + registry.fill(HIST("hEventCounter"), 3.5); + } else { + if (cfgOnlyKeepInterestedTrigger) { + return false; + } + } } - FillCandCounter(kCandDauPt, isTrueCand); - double dcapion = (track2.sign() > 0) ? candData.dcatrack1topv() : candData.dcatrack0topv(); - if (TMath::Abs(dcapion) < dcapiontopv) { - return; - } - FillCandCounter(kCandDcaToPV, isTrueCand); + return true; + } - // 3sigma region for Dalitz plot - double lowersignallimit = o2::constants::physics::MassHyperTriton - 3 * mcsigma; - double uppersignallimit = o2::constants::physics::MassHyperTriton + 3 * mcsigma; + //------------------------------------------------------------------ + // Fill candidate table + template + void fillCand(TCollisionTable const& collision, TCandTable const& candData, TTrackTable const& trackProton, TTrackTable const& trackPion, TTrackTable const& trackDeuteron, bool isMatter, bool isTrueCand = false, int lLabel = -1, TLorentzVector lmother = {0, 0, 0, 0}, double mcLifetime = -1, bool isBachPrimary = false) + { + double cospa = candData.vtxcosPA(collision.posX(), collision.posY(), collision.posZ()); + double ct = candData.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassHyperTriton; Candidate3body cand3body; - // Hypertriton - if ((track2.sign() > 0 && candData.mHypertriton() > h3LMassLowerlimit && candData.mHypertriton() < h3LMassUpperlimit)) { - FillCandCounter(kCandInvMass, isTrueCand); - - registry.fill(HIST("hPtProton"), trackProton.pt()); - registry.fill(HIST("hPtPionMinus"), trackPion.pt()); - registry.fill(HIST("hPtDeuteron"), trackDeuteron.pt()); - registry.fill(HIST("hDCAProtonToPV"), candData.dcatrack0topv()); - registry.fill(HIST("hDCAPionToPV"), candData.dcatrack1topv()); - - registry.fill(HIST("hMassHypertriton"), candData.mHypertriton()); - registry.fill(HIST("hMassHypertritonTotal"), candData.mHypertriton()); - registry.fill(HIST("h3dMassHypertriton"), 0., candData.pt(), candData.mHypertriton()); // dCollision.centV0M() instead of 0. once available - registry.fill(HIST("h3dTotalHypertriton"), ct, candData.pt(), candData.mHypertriton()); - - cand3body.isMatter = true; + cand3body.isMatter = isMatter; + if (isMatter == true) { cand3body.lproton.SetXYZM(candData.pxtrack0(), candData.pytrack0(), candData.pztrack0(), o2::constants::physics::MassProton); cand3body.lpion.SetXYZM(candData.pxtrack1(), candData.pytrack1(), candData.pztrack1(), o2::constants::physics::MassPionCharged); - - if (candData.mHypertriton() > lowersignallimit && candData.mHypertriton() < uppersignallimit) { - registry.fill(HIST("hDalitz"), RecoDecay::m2(array{array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}, array{candData.pxtrack2(), candData.pytrack2(), candData.pztrack2()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}), RecoDecay::m2(array{array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}, array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged})); - } - if (isTrueCand) { - registry.fill(HIST("h3dTotalTrueHypertriton"), MClifetime, lmother.Pt(), candData.mHypertriton()); - } - } else if ((track2.sign() < 0 && candData.mAntiHypertriton() > h3LMassLowerlimit && candData.mAntiHypertriton() < h3LMassUpperlimit)) { - // AntiHypertriton - FillCandCounter(kCandInvMass, isTrueCand); - cand3body.isMatter = false; + } else { cand3body.lproton.SetXYZM(candData.pxtrack1(), candData.pytrack1(), candData.pztrack1(), o2::constants::physics::MassPionCharged); cand3body.lpion.SetXYZM(candData.pxtrack0(), candData.pytrack0(), candData.pztrack0(), o2::constants::physics::MassProton); - - registry.fill(HIST("hPtAntiProton"), trackProton.pt()); - registry.fill(HIST("hPtPionPlus"), trackPion.pt()); - registry.fill(HIST("hPtAntiDeuteron"), trackDeuteron.pt()); - registry.fill(HIST("hDCAProtonToPV"), candData.dcatrack1topv()); - registry.fill(HIST("hDCAPionToPV"), candData.dcatrack0topv()); - - registry.fill(HIST("hMassAntiHypertriton"), candData.mAntiHypertriton()); - registry.fill(HIST("hMassHypertritonTotal"), candData.mAntiHypertriton()); - registry.fill(HIST("h3dMassAntiHypertriton"), 0., candData.pt(), candData.mAntiHypertriton()); // dCollision.centV0M() instead of 0. once available - registry.fill(HIST("h3dTotalHypertriton"), ct, candData.pt(), candData.mAntiHypertriton()); - if (candData.mAntiHypertriton() > lowersignallimit && candData.mAntiHypertriton() < uppersignallimit) { - registry.fill(HIST("hDalitz"), RecoDecay::m2(array{array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}, array{candData.pxtrack2(), candData.pytrack2(), candData.pztrack2()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}), RecoDecay::m2(array{array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}, array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged})); - } - if (isTrueCand) { - registry.fill(HIST("h3dTotalTrueHypertriton"), MClifetime, lmother.Pt(), candData.mHypertriton()); - } - } else { - return; } - if_hasvtx = true; cand3body.mcmotherId = lLabel; cand3body.track0Id = candData.track0Id(); cand3body.track1Id = candData.track1Id(); cand3body.track2Id = candData.track2Id(); + cand3body.colCentFT0C = collision.centFT0C(); cand3body.invmass = cand3body.isMatter ? candData.mHypertriton() : candData.mAntiHypertriton(); - cand3body.posSV[0] = candData.x(); - cand3body.posSV[1] = candData.y(); - cand3body.posSV[2] = candData.z(); + cand3body.lcand.SetXYZM(candData.px(), candData.py(), candData.pz(), o2::constants::physics::MassHyperTriton); + cand3body.ct = ct; + cand3body.cosPA = cospa; + cand3body.dcadaughters = candData.dcaVtxdaughters(); + cand3body.dcacandtopv = candData.dcavtxtopv(collision.posX(), collision.posY(), collision.posZ()); + cand3body.vtxradius = candData.vtxradius(); cand3body.lbachelor.SetXYZM(candData.pxtrack2(), candData.pytrack2(), candData.pztrack2(), o2::constants::physics::MassDeuteron); cand3body.dautpcNclusters[0] = trackProton.tpcNClsFound(); cand3body.dautpcNclusters[1] = trackPion.tpcNClsFound(); cand3body.dautpcNclusters[2] = trackDeuteron.tpcNClsFound(); - cand3body.dauitsclussize[0] = trackPion.itsClusterSizes(); + cand3body.dauitsclussize[0] = trackProton.itsClusterSizes(); + cand3body.dauitsclussize[1] = trackPion.itsClusterSizes(); + cand3body.dauitsclussize[2] = trackDeuteron.itsClusterSizes(); cand3body.dautpcNsigma[0] = trackProton.tpcNSigmaPr(); cand3body.dautpcNsigma[1] = trackPion.tpcNSigmaPi(); cand3body.dautpcNsigma[2] = trackDeuteron.tpcNSigmaDe(); + cand3body.daudcaxytopv[0] = cand3body.isMatter ? candData.dcaXYtrack0topv() : candData.dcaXYtrack1topv(); + cand3body.daudcaxytopv[1] = cand3body.isMatter ? candData.dcaXYtrack1topv() : candData.dcaXYtrack0topv(); + cand3body.daudcaxytopv[2] = candData.dcaXYtrack2topv(); cand3body.daudcatopv[0] = cand3body.isMatter ? candData.dcatrack0topv() : candData.dcatrack1topv(); cand3body.daudcatopv[1] = cand3body.isMatter ? candData.dcatrack1topv() : candData.dcatrack0topv(); cand3body.daudcatopv[2] = candData.dcatrack2topv(); - cand3body.lcand.SetXYZM(candData.px(), candData.py(), candData.pz(), o2::constants::physics::MassHyperTriton); - cand3body.ct = ct; - cand3body.cosPA = cospa; - cand3body.dcadaughters = candData.dcaVtxdaughters(); - cand3body.dcacandtopv = candData.dcavtxtopv(dCollision.posX(), dCollision.posY(), dCollision.posZ()); - cand3body.bachelortofNsigma = trackDeuteron.tofNSigmaDe(); + cand3body.dauinnermostR[0] = trackProton.x(); + cand3body.dauinnermostR[1] = trackPion.x(); + cand3body.dauinnermostR[2] = trackDeuteron.x(); + + cand3body.bachelortofNsigma = candData.tofNSigmaBachDe(); + cand3body.isBachPrimary = isBachPrimary; if (isTrueCand) { cand3body.mcmotherId = lLabel; cand3body.lgencand = lmother; - cand3body.genct = MClifetime; + cand3body.genct = mcLifetime; + cand3body.genrapidity = lmother.Rapidity(); cand3body.isSignal = true; cand3body.isReco = true; cand3body.pdgCode = cand3body.isMatter ? motherPdgCode : -motherPdgCode; - cand3body.SurvivedEventSelection = true; + cand3body.survivedEventSelection = true; filledMothers.push_back(lLabel); } - Candidates3body.push_back(cand3body); + candidates3body.push_back(cand3body); - registry.fill(HIST("hDCADeuteronToPV"), candData.dcatrack2topv()); - registry.fill(HIST("hVtxCosPA"), candData.vtxcosPA(dCollision.posX(), dCollision.posY(), dCollision.posZ())); - registry.fill(HIST("hDCAVtxDau"), candData.dcaVtxdaughters()); - registry.fill(HIST("hProtonTPCNcls"), trackProton.tpcNClsFound()); - registry.fill(HIST("hPionTPCNcls"), trackPion.tpcNClsFound()); - registry.fill(HIST("hDeuteronTPCNcls"), trackDeuteron.tpcNClsFound()); - registry.fill(HIST("hTPCPIDProton"), trackProton.tpcNSigmaPr()); - registry.fill(HIST("hTPCPIDPion"), trackPion.tpcNSigmaPi()); - registry.fill(HIST("hTPCPIDDeuteron"), trackDeuteron.tpcNSigmaDe()); registry.fill(HIST("hProtonTPCBB"), trackProton.sign() * trackProton.p(), trackProton.tpcSignal()); registry.fill(HIST("hPionTPCBB"), trackPion.sign() * trackPion.p(), trackPion.tpcSignal()); registry.fill(HIST("hDeuteronTPCBB"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tpcSignal()); registry.fill(HIST("hProtonTPCVsPt"), trackProton.pt(), trackProton.tpcNSigmaPr()); registry.fill(HIST("hPionTPCVsPt"), trackProton.pt(), trackPion.tpcNSigmaPi()); registry.fill(HIST("hDeuteronTPCVsPt"), trackDeuteron.pt(), trackDeuteron.tpcNSigmaDe()); - registry.fill(HIST("hTOFPIDDeuteron"), trackDeuteron.tofNSigmaDe()); + registry.fill(HIST("hTOFPIDDeuteron"), candData.tofNSigmaBachDe()); + registry.fill(HIST("hDiffRVtxProton"), trackProton.x() - candData.vtxradius()); + registry.fill(HIST("hDiffRVtxPion"), trackPion.x() - candData.vtxradius()); + registry.fill(HIST("hDiffRVtxDeuteron"), trackDeuteron.x() - candData.vtxradius()); + float diffTrackR = trackDeuteron.x() - std::min(trackProton.x(), trackPion.x()); + registry.fill(HIST("hDiffDaughterR"), diffTrackR); + } + + //------------------------------------------------------------------ + // Selections for candidates + template + bool selectCand(TCollisionTable const& collision, TCandTable const& candData, TTrackTable const& trackProton, TTrackTable const& trackPion, TTrackTable const& trackDeuteron, bool isMatter, bool isTrueCand = false) + { + fillCandCounter(kCandAll, isTrueCand); + + // Selection on daughters + if (std::abs(trackProton.eta()) > etacut || std::abs(trackPion.eta()) > etacut || std::abs(trackDeuteron.eta()) > etacut) { + return false; + } + fillCandCounter(kCandDauEta, isTrueCand); + + if (trackProton.pt() < minProtonPt || trackProton.pt() > maxProtonPt || trackPion.pt() < minPionPt || trackPion.pt() > maxPionPt || trackDeuteron.pt() < minDeuteronPt || trackDeuteron.pt() > maxDeuteronPt) { + return false; + } + fillCandCounter(kCandDauPt, isTrueCand); + + if (trackProton.tpcNClsFound() < mintpcNClsproton || trackPion.tpcNClsFound() < mintpcNClspion || trackDeuteron.tpcNClsFound() < mintpcNClsdeuteron) { + return false; + } + fillCandCounter(kCandTPCNcls, isTrueCand); + + if (std::abs(trackProton.tpcNSigmaPr()) > tpcPIDNSigmaCut || std::abs(trackPion.tpcNSigmaPi()) > tpcPIDNSigmaCut || std::abs(trackDeuteron.tpcNSigmaDe()) > tpcPIDNSigmaCut) { + return false; + } + fillCandCounter(kCandTPCPID, isTrueCand); + + registry.fill(HIST("hDeuteronTOFVsPBeforeTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); + if ((candData.tofNSigmaBachDe() < tofPIDNSigmaMin || candData.tofNSigmaBachDe() > tofPIDNSigmaMax) && trackDeuteron.p() > minDeuteronPUseTOF) { + return false; + } + fillCandCounter(kCandTOFPID, isTrueCand); + registry.fill(HIST("hDeuteronTOFVsPAtferTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); + + double dcapion = isMatter ? candData.dcatrack1topv() : candData.dcatrack0topv(); + if (std::abs(dcapion) < dcapiontopv) { + return false; + } + fillCandCounter(kCandDcaToPV, isTrueCand); + + // Selection on candidate hypertriton + if (std::abs(candData.yHypertriton()) > rapiditycut) { + return false; + } + fillCandCounter(kCandRapidity, isTrueCand); + + double ct = candData.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassHyperTriton; + if (ct > lifetimecut) { + return false; + } + fillCandCounter(kCandct, isTrueCand); + + double cospa = candData.vtxcosPA(collision.posX(), collision.posY(), collision.posZ()); + if (cospa < vtxcospa) { + return false; + } + fillCandCounter(kCandCosPA, isTrueCand); + + if (candData.dcaVtxdaughters() > dcavtxdau) { + return false; + } + fillCandCounter(kCandDcaDau, isTrueCand); + + if ((isMatter && candData.mHypertriton() > h3LMassLowerlimit && candData.mHypertriton() < h3LMassUpperlimit)) { + // Hypertriton + registry.fill(HIST("hMassHypertriton"), candData.mHypertriton()); + registry.fill(HIST("hMassHypertritonTotal"), candData.mHypertriton()); + if (candData.mHypertriton() > lowersignallimit && candData.mHypertriton() < uppersignallimit) { + registry.fill(HIST("hDalitz"), RecoDecay::m2(std::array{std::array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}, std::array{candData.pxtrack2(), candData.pytrack2(), candData.pztrack2()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}), RecoDecay::m2(std::array{std::array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}, std::array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged})); + } + } else if ((!isMatter && candData.mAntiHypertriton() > h3LMassLowerlimit && candData.mAntiHypertriton() < h3LMassUpperlimit)) { + // AntiHypertriton + registry.fill(HIST("hMassAntiHypertriton"), candData.mAntiHypertriton()); + registry.fill(HIST("hMassHypertritonTotal"), candData.mAntiHypertriton()); + if (candData.mAntiHypertriton() > lowersignallimit && candData.mAntiHypertriton() < uppersignallimit) { + registry.fill(HIST("hDalitz"), RecoDecay::m2(std::array{std::array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}, std::array{candData.pxtrack2(), candData.pytrack2(), candData.pztrack2()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}), RecoDecay::m2(std::array{std::array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}, std::array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged})); + } + } else { + return false; + } + fillCandCounter(kCandInvMass, isTrueCand); + + return true; + } + + //------------------------------------------------------------------ + // Analysis process for a single candidate + template + void candidateAnalysis(TCollisionTable const& collision, TCandTable const& candData, bool& ifHasCandidate, bool isTrueCand = false, int lLabel = -1, TLorentzVector lmother = {0, 0, 0, 0}, double mcLifetime = -1, double isBachPrimary = false) + { + auto track0 = candData.template track0_as(); + auto track1 = candData.template track1_as(); + auto track2 = candData.template track2_as(); + + bool isMatter = track2.sign() > 0; // true if the candidate is hypertriton (p pi- d) + + auto& trackProton = isMatter ? track0 : track1; + auto& trackPion = isMatter ? track1 : track0; + auto& trackDeuteron = track2; + + if (selectCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand)) { + ifHasCandidate = true; + fillCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand, lLabel, lmother, mcLifetime, isBachPrimary); + } + } + + //------------------------------------------------------------------ + // Analysis process for like-sign candidates : (p pi- anti-d) or (anti-p pi+ d) + template + void likeSignAnalysis(TCollisionTable const& collision, TCandTable const& candData, bool& ifHasCandidate, bool isTrueCand = false, int lLabel = -1, TLorentzVector lmother = {0, 0, 0, 0}, double mcLifetime = -1, double isBachPrimary = false) + { + auto track0 = candData.template track0_as(); + auto track1 = candData.template track1_as(); + auto track2 = candData.template track2_as(); + + bool isMatter = track2.sign() < 0; // true if seach for background consists of (p pi- anti-d) + + // Assume proton has an oppisite charge with deuteron + auto& trackProton = isMatter ? track0 : track1; + auto& trackPion = isMatter ? track1 : track0; + auto& trackDeuteron = track2; + + if (selectCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand)) { + ifHasCandidate = true; + fillCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand, lLabel, lmother, mcLifetime, isBachPrimary); + // QA for if signals have the possibility to be reconginzed as a like-sign background + if (isMatter) { + registry.fill(HIST("hInvMassCorrectSign"), candData.mHypertriton()); + } else { + registry.fill(HIST("hInvMassCorrectSign"), candData.mAntiHypertriton()); + } + } + } + + //------------------------------------------------------------------ + // Analysis process for reduced data + template + void reducedAnalysis(TCollisionTable const& collision, TCandTable const& candData, TTracks tracks, bool isTrueCand = false, int lLabel = -1, TLorentzVector lmother = {0, 0, 0, 0}, double mcLifetime = -1, double isBachPrimary = false) + { + auto track0 = tracks.rawIteratorAt(candData.track0Id()); + auto track1 = tracks.rawIteratorAt(candData.track1Id()); + auto track2 = tracks.rawIteratorAt(candData.track2Id()); + + bool isMatter = track2.sign() > 0; // true if the candidate is hypertriton (p pi- d) + + auto& trackProton = isMatter ? track0 : track1; + auto& trackPion = isMatter ? track1 : track0; + auto& trackDeuteron = track2; + + if (selectCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand)) { + fillCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand, lLabel, lmother, mcLifetime, isBachPrimary); + } + } + + //------------------------------------------------------------------ + // Analysis process for reduced data with like-sign candidates + template + void reducedLikeSignAnalysis(TCollisionTable const& collision, TCandTable const& candData, TTracks tracks, bool isTrueCand = false, int lLabel = -1, TLorentzVector lmother = {0, 0, 0, 0}, double mcLifetime = -1, bool isBachPrimary = false) + { + auto track0 = tracks.rawIteratorAt(candData.track0Id()); + auto track1 = tracks.rawIteratorAt(candData.track1Id()); + auto track2 = tracks.rawIteratorAt(candData.track2Id()); + + bool isMatter = track2.sign() < 0; // true if seach for background consists of (p pi- anti-d) + + // Assume proton has an oppisite charge with deuteron + auto& trackProton = isMatter ? track0 : track1; + auto& trackPion = isMatter ? track1 : track0; + auto& trackDeuteron = track2; + + if (selectCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand)) { + fillCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand, lLabel, lmother, mcLifetime, isBachPrimary); + // QA for if signals have the possibility to be reconginzed as a like-sign background + if (isMatter) { + registry.fill(HIST("hInvMassCorrectSign"), candData.mHypertriton()); + } else { + registry.fill(HIST("hInvMassCorrectSign"), candData.mAntiHypertriton()); + } + } + } + + //------------------------------------------------------------------ + void fillOutputDataTable(Candidate3body const& cand3body) + { + outputDataTable(cand3body.colCentFT0C, + cand3body.isMatter, cand3body.invmass, cand3body.lcand.P(), cand3body.lcand.Pt(), cand3body.ct, + cand3body.cosPA, cand3body.dcadaughters, cand3body.dcacandtopv, cand3body.vtxradius, + cand3body.lproton.Pt(), cand3body.lproton.Eta(), cand3body.lproton.Phi(), cand3body.dauinnermostR[0], + cand3body.lpion.Pt(), cand3body.lpion.Eta(), cand3body.lpion.Phi(), cand3body.dauinnermostR[1], + cand3body.lbachelor.Pt(), cand3body.lbachelor.Eta(), cand3body.lbachelor.Phi(), cand3body.dauinnermostR[2], + cand3body.dautpcNclusters[0], cand3body.dautpcNclusters[1], cand3body.dautpcNclusters[2], + cand3body.dauitsclussize[0], cand3body.dauitsclussize[1], cand3body.dauitsclussize[2], + cand3body.dautpcNsigma[0], cand3body.dautpcNsigma[1], cand3body.dautpcNsigma[2], cand3body.bachelortofNsigma, + cand3body.daudcaxytopv[0], cand3body.daudcaxytopv[1], cand3body.daudcaxytopv[2], + cand3body.daudcatopv[0], cand3body.daudcatopv[1], cand3body.daudcatopv[2]); } //------------------------------------------------------------------ // collect information for generated hypertriton (should be called after event selection) - void GetGeneratedH3LInfo(aod::McParticles const& particlesMC) + void getGeneratedH3LInfo(aod::McParticles const& particlesMC) { - for (auto& mcparticle : particlesMC) { - if (mcparticle.pdgCode() != motherPdgCode && mcparticle.pdgCode() != -motherPdgCode) { + for (const auto& mcparticle : particlesMC) { + if (std::abs(mcparticle.pdgCode()) != motherPdgCode) { continue; } registry.fill(HIST("hGeneratedHypertritonCounter"), 0.5); bool haveProton = false, havePionPlus = false, haveDeuteron = false; bool haveAntiProton = false, havePionMinus = false, haveAntiDeuteron = false; - double MClifetime = -1; - for (auto& mcparticleDaughter : mcparticle.template daughters_as()) { - if (mcparticleDaughter.pdgCode() == 2212) + double mcLifetime = -1; + for (const auto& mcparticleDaughter : mcparticle.template daughters_as()) { + if (mcparticleDaughter.pdgCode() == PDG_t::kProton) haveProton = true; - if (mcparticleDaughter.pdgCode() == -2212) + if (mcparticleDaughter.pdgCode() == PDG_t::kProtonBar) haveAntiProton = true; - if (mcparticleDaughter.pdgCode() == 211) + if (mcparticleDaughter.pdgCode() == PDG_t::kPiPlus) havePionPlus = true; - if (mcparticleDaughter.pdgCode() == -211) + if (mcparticleDaughter.pdgCode() == -PDG_t::kPiPlus) havePionMinus = true; if (mcparticleDaughter.pdgCode() == bachelorPdgCode) { haveDeuteron = true; - MClifetime = RecoDecay::sqrtSumOfSquares(mcparticleDaughter.vx() - mcparticle.vx(), mcparticleDaughter.vy() - mcparticle.vy(), mcparticleDaughter.vz() - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); + mcLifetime = RecoDecay::sqrtSumOfSquares(mcparticleDaughter.vx() - mcparticle.vx(), mcparticleDaughter.vy() - mcparticle.vy(), mcparticleDaughter.vz() - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); } if (mcparticleDaughter.pdgCode() == -bachelorPdgCode) { haveAntiDeuteron = true; - MClifetime = RecoDecay::sqrtSumOfSquares(mcparticleDaughter.vx() - mcparticle.vx(), mcparticleDaughter.vy() - mcparticle.vy(), mcparticleDaughter.vz() - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); + mcLifetime = RecoDecay::sqrtSumOfSquares(mcparticleDaughter.vx() - mcparticle.vx(), mcparticleDaughter.vy() - mcparticle.vy(), mcparticleDaughter.vz() - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); } } if (haveProton && havePionMinus && haveDeuteron && mcparticle.pdgCode() == motherPdgCode) { registry.fill(HIST("hGeneratedHypertritonCounter"), 1.5); registry.fill(HIST("hPtGeneratedHypertriton"), mcparticle.pt()); - registry.fill(HIST("hctGeneratedHypertriton"), MClifetime); + registry.fill(HIST("hctGeneratedHypertriton"), mcLifetime); registry.fill(HIST("hEtaGeneratedHypertriton"), mcparticle.eta()); registry.fill(HIST("hRapidityGeneratedHypertriton"), mcparticle.y()); } else if (haveAntiProton && havePionPlus && haveAntiDeuteron && mcparticle.pdgCode() == -motherPdgCode) { registry.fill(HIST("hGeneratedHypertritonCounter"), 1.5); registry.fill(HIST("hPtGeneratedAntiHypertriton"), mcparticle.pt()); - registry.fill(HIST("hctGeneratedAntiHypertriton"), MClifetime); + registry.fill(HIST("hctGeneratedAntiHypertriton"), mcLifetime); registry.fill(HIST("hEtaGeneratedAntiHypertriton"), mcparticle.eta()); registry.fill(HIST("hRapidityGeneratedAntiHypertriton"), mcparticle.y()); } @@ -502,76 +706,106 @@ struct threebodyRecoTask { //------------------------------------------------------------------ // process real data analysis - void processData(soa::Join::iterator const& collision, aod::Vtx3BodyDatas const& vtx3bodydatas, FullTracksExtIU const& /*tracks*/) + void processData(soa::Join const& collisions, aod::Vtx3BodyDatas const& vtx3bodydatas, FullTracksExtIU const&, aod::BCsWithTimestamps const&) { - Candidates3body.clear(); - registry.fill(HIST("hEventCounter"), 0.5); - if (event_sel8_selection && !collision.sel8()) { - return; - } - registry.fill(HIST("hEventCounter"), 1.5); - if (event_posZ_selection && abs(collision.posZ()) > 10.f) { // 10cm - return; - } - registry.fill(HIST("hEventCounter"), 2.5); + for (const auto& collision : collisions) { + candidates3body.clear(); - bool if_hasvtx = false; + if (!eventSelection(collision)) { + continue; + } - for (auto& vtx : vtx3bodydatas) { - CandidateAnalysis(collision, vtx, if_hasvtx); + bool ifHasCandidate = false; + auto d3BodyCands = vtx3bodydatas.sliceBy(perCollisionVtx3BodyDatas, collision.globalIndex()); + for (const auto& vtx : d3BodyCands) { + if (cfgLikeSignAnalysis) { + likeSignAnalysis(collision, vtx, ifHasCandidate); + } else { + candidateAnalysis(collision, vtx, ifHasCandidate); + } + } + + if (ifHasCandidate) { + auto bc = collision.bc_as(); + auto triggerSelection = zorro.getTriggerOfInterestResults(bc.globalBC(), bcTolerance); + for (size_t i = 0; i < triggerSelection.size(); i++) { + if (triggerSelection[i]) { + registry.fill(HIST("hEventTriggerCount"), i + 0.5); + } + } + if (zorro.isNotSelectedByAny(bc.globalBC(), bcTolerance)) { + registry.fill(HIST("hEventTriggerCount"), triggerLabels.size() + 0.5); + } + registry.fill(HIST("hEventCounter"), 4.5); + } + fillHistos(); + resetHistos(); + + for (const auto& cand3body : candidates3body) { + fillOutputDataTable(cand3body); + } } + } + PROCESS_SWITCH(ThreebodyRecoTask, processData, "Real data reconstruction", true); - if (if_hasvtx) - registry.fill(HIST("hEventCounter"), 3.5); - fillHistos(); - resetHistos(); + //------------------------------------------------------------------ + // process reduced data analysis + void processReducedData(ReducedCols const& collisions, aod::Vtx3BodyDatas const& vtx3bodydatas, aod::RedIUTracks const& tracks) + { + candidates3body.clear(); - for (auto& cand3body : Candidates3body) { - outputDataTable(collision.centFT0C(), collision.posX(), collision.posY(), collision.posZ(), - cand3body.isMatter, cand3body.invmass, cand3body.lcand.P(), cand3body.lcand.Pt(), cand3body.ct, - cand3body.posSV[0], cand3body.posSV[1], cand3body.posSV[2], - cand3body.cosPA, cand3body.dcadaughters, cand3body.dcacandtopv, - cand3body.lproton.P(), cand3body.lproton.Pt(), cand3body.lproton.Eta(), cand3body.lproton.Phi(), - cand3body.lpion.P(), cand3body.lpion.Pt(), cand3body.lpion.Eta(), cand3body.lpion.Phi(), - cand3body.lbachelor.P(), cand3body.lbachelor.Pt(), cand3body.lbachelor.Eta(), cand3body.lbachelor.Phi(), - cand3body.dautpcNclusters[0], cand3body.dautpcNclusters[1], cand3body.dautpcNclusters[2], - cand3body.dauitsclussize[0], cand3body.dauitsclussize[1], cand3body.dauitsclussize[2], - cand3body.dautpcNsigma[0], cand3body.dautpcNsigma[1], cand3body.dautpcNsigma[2], cand3body.bachelortofNsigma, - cand3body.daudcatopv[0], cand3body.daudcatopv[1], cand3body.daudcatopv[2]); + registry.fill(HIST("hEventCounter"), 0.5, collisions.size()); + + for (const auto& vtx : vtx3bodydatas) { + const auto& collision = collisions.iteratorAt(vtx.collisionId()); + if (cfgLikeSignAnalysis) { + reducedLikeSignAnalysis(collision, vtx, tracks); + } else { + reducedAnalysis(collision, vtx, tracks); + } + for (const auto& cand3body : candidates3body) { + fillOutputDataTable(cand3body); + } + candidates3body.clear(); } + fillHistos(); + resetHistos(); } - PROCESS_SWITCH(threebodyRecoTask, processData, "Real data reconstruction", true); + PROCESS_SWITCH(ThreebodyRecoTask, processReducedData, "Reduced data reconstruction", false); //------------------------------------------------------------------ // process mc analysis void processMC(soa::Join const& collisions, aod::Vtx3BodyDatas const& vtx3bodydatas, aod::McParticles const& particlesMC, MCLabeledTracksIU const& /*tracks*/, aod::McCollisions const& mcCollisions) { - Candidates3body.clear(); filledMothers.clear(); - GetGeneratedH3LInfo(particlesMC); + getGeneratedH3LInfo(particlesMC); isGoodCollision.resize(mcCollisions.size(), false); for (const auto& collision : collisions) { + candidates3body.clear(); registry.fill(HIST("hEventCounter"), 0.5); - if (event_sel8_selection && !collision.sel8()) { + if (mcEventCut && (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder))) { continue; } registry.fill(HIST("hEventCounter"), 1.5); - if (event_posZ_selection && abs(collision.posZ()) > 10.f) { // 10cm + if (eventPosZCut && std::abs(collision.posZ()) > 10.f) { // 10cm continue; } registry.fill(HIST("hEventCounter"), 2.5); + registry.fill(HIST("hCentFT0C"), collision.centFT0C()); + if (collision.mcCollisionId() >= 0) { isGoodCollision[collision.mcCollisionId()] = true; } - bool if_hasvtx = false; - auto vtxsthiscol = vtx3bodydatas.sliceBy(perCollisionVtx3BodyDatas, collision.globalIndex()); + bool ifHasCandidate = false; + auto vtxsThisCol = vtx3bodydatas.sliceBy(perCollisionVtx3BodyDatas, collision.globalIndex()); - for (auto& vtx : vtxsthiscol) { + for (const auto& vtx : vtxsThisCol) { + bool isBachPrimary = false; int lLabel = -1; int lPDG = -1; - double MClifetime = -1; + double mcLifetime = -1; TLorentzVector lmother; bool isTrueCand = false; auto track0 = vtx.track0_as(); @@ -581,17 +815,22 @@ struct threebodyRecoTask { auto lMCTrack0 = track0.mcParticle_as(); auto lMCTrack1 = track1.mcParticle_as(); auto lMCTrack2 = track2.mcParticle_as(); + + if (lMCTrack2.isPhysicalPrimary()) { + isBachPrimary = true; + } + if (lMCTrack0.has_mothers() && lMCTrack1.has_mothers() && lMCTrack2.has_mothers()) { - for (auto& lMother0 : lMCTrack0.mothers_as()) { - for (auto& lMother1 : lMCTrack1.mothers_as()) { - for (auto& lMother2 : lMCTrack2.mothers_as()) { + for (const auto& lMother0 : lMCTrack0.mothers_as()) { + for (const auto& lMother1 : lMCTrack1.mothers_as()) { + for (const auto& lMother2 : lMCTrack2.mothers_as()) { if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { lLabel = lMother0.globalIndex(); - lPDG = lMother1.pdgCode(); - if ((lPDG == motherPdgCode && lMCTrack0.pdgCode() == 2212 && lMCTrack1.pdgCode() == -211 && lMCTrack2.pdgCode() == bachelorPdgCode) || - (lPDG == -motherPdgCode && lMCTrack0.pdgCode() == 211 && lMCTrack1.pdgCode() == -2212 && lMCTrack2.pdgCode() == -bachelorPdgCode)) { + lPDG = lMother0.pdgCode(); + if ((lPDG == motherPdgCode && lMCTrack0.pdgCode() == PDG_t::kProton && lMCTrack1.pdgCode() == PDG_t::kPiMinus && lMCTrack2.pdgCode() == bachelorPdgCode) || + (lPDG == -motherPdgCode && lMCTrack0.pdgCode() == PDG_t::kPiPlus && lMCTrack1.pdgCode() == PDG_t::kProtonBar && lMCTrack2.pdgCode() == -bachelorPdgCode)) { isTrueCand = true; - MClifetime = RecoDecay::sqrtSumOfSquares(lMCTrack2.vx() - lMother2.vx(), lMCTrack2.vy() - lMother2.vy(), lMCTrack2.vz() - lMother2.vz()) * o2::constants::physics::MassHyperTriton / lMother2.p(); + mcLifetime = RecoDecay::sqrtSumOfSquares(lMCTrack2.vx() - lMother2.vx(), lMCTrack2.vy() - lMother2.vy(), lMCTrack2.vz() - lMother2.vz()) * o2::constants::physics::MassHyperTriton / lMother2.p(); lmother.SetXYZM(lMother0.px(), lMother0.py(), lMother0.pz(), o2::constants::physics::MassHyperTriton); } } @@ -601,33 +840,34 @@ struct threebodyRecoTask { } } - CandidateAnalysis(collision, vtx, if_hasvtx, isTrueCand, lLabel, lmother, MClifetime); + candidateAnalysis(collision, vtx, ifHasCandidate, isTrueCand, lLabel, lmother, mcLifetime, isBachPrimary); } - if (if_hasvtx) - registry.fill(HIST("hEventCounter"), 3.5); + if (ifHasCandidate) + registry.fill(HIST("hEventCounter"), 4.5); fillHistos(); resetHistos(); - for (auto& cand3body : Candidates3body) { - outputMCTable(collision.centFT0C(), collision.posX(), collision.posY(), collision.posZ(), // centV0M() instead of 0. once available + for (const auto& cand3body : candidates3body) { + outputMCTable(cand3body.colCentFT0C, cand3body.isMatter, cand3body.invmass, cand3body.lcand.P(), cand3body.lcand.Pt(), cand3body.ct, - cand3body.posSV[0], cand3body.posSV[1], cand3body.posSV[2], - cand3body.cosPA, cand3body.dcadaughters, cand3body.dcacandtopv, - cand3body.lproton.P(), cand3body.lproton.Pt(), cand3body.lproton.Eta(), cand3body.lproton.Phi(), - cand3body.lpion.P(), cand3body.lpion.Pt(), cand3body.lpion.Eta(), cand3body.lpion.Phi(), - cand3body.lbachelor.P(), cand3body.lbachelor.Pt(), cand3body.lbachelor.Eta(), cand3body.lbachelor.Phi(), + cand3body.cosPA, cand3body.dcadaughters, cand3body.dcacandtopv, cand3body.vtxradius, + cand3body.lproton.Pt(), cand3body.lproton.Eta(), cand3body.lproton.Phi(), cand3body.dauinnermostR[0], + cand3body.lpion.Pt(), cand3body.lpion.Eta(), cand3body.lpion.Phi(), cand3body.dauinnermostR[1], + cand3body.lbachelor.Pt(), cand3body.lbachelor.Eta(), cand3body.lbachelor.Phi(), cand3body.dauinnermostR[2], cand3body.dautpcNclusters[0], cand3body.dautpcNclusters[1], cand3body.dautpcNclusters[2], cand3body.dauitsclussize[0], cand3body.dauitsclussize[1], cand3body.dauitsclussize[2], cand3body.dautpcNsigma[0], cand3body.dautpcNsigma[1], cand3body.dautpcNsigma[2], cand3body.bachelortofNsigma, + cand3body.daudcaxytopv[0], cand3body.daudcaxytopv[1], cand3body.daudcaxytopv[2], cand3body.daudcatopv[0], cand3body.daudcatopv[1], cand3body.daudcatopv[2], - cand3body.lgencand.P(), cand3body.lgencand.Pt(), cand3body.genct, cand3body.lgencand.Phi(), cand3body.lgencand.Eta(), - cand3body.isSignal, cand3body.isReco, cand3body.pdgCode, cand3body.SurvivedEventSelection); + cand3body.isBachPrimary, + cand3body.lgencand.P(), cand3body.lgencand.Pt(), cand3body.genct, cand3body.lgencand.Phi(), cand3body.lgencand.Eta(), cand3body.lgencand.Rapidity(), + cand3body.isSignal, cand3body.isReco, cand3body.pdgCode, cand3body.survivedEventSelection); } } // now we fill only the signal candidates that were not reconstructed - for (auto& mcparticle : particlesMC) { + for (const auto& mcparticle : particlesMC) { if (!is3bodyDecayed(mcparticle)) { continue; } @@ -636,16 +876,15 @@ struct threebodyRecoTask { } bool isSurEvSelection = isGoodCollision[mcparticle.mcCollisionId()]; std::array posSV{0.f}; - for (auto& mcDaughter : mcparticle.daughters_as()) { + for (const auto& mcDaughter : mcparticle.daughters_as()) { if (std::abs(mcDaughter.pdgCode()) == bachelorPdgCode) { posSV = {mcDaughter.vx(), mcDaughter.vy(), mcDaughter.vz()}; } } - double MClifetime = RecoDecay::sqrtSumOfSquares(posSV[0] - mcparticle.vx(), posSV[1] - mcparticle.vy(), posSV[2] - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); - outputMCTable(-1, -1, -1, -1, + double mcLifetime = RecoDecay::sqrtSumOfSquares(posSV[0] - mcparticle.vx(), posSV[1] - mcparticle.vy(), posSV[2] - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); + outputMCTable(-1, -1, -1, -1, -1, -1, - -1, -1, -1, - -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -653,16 +892,18 @@ struct threebodyRecoTask { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - mcparticle.p(), mcparticle.pt(), MClifetime, mcparticle.phi(), mcparticle.eta(), + -1, -1, -1, + false, + mcparticle.p(), mcparticle.pt(), mcLifetime, mcparticle.phi(), mcparticle.eta(), mcparticle.y(), true, false, mcparticle.pdgCode(), isSurEvSelection); } } - PROCESS_SWITCH(threebodyRecoTask, processMC, "MC reconstruction", false); + PROCESS_SWITCH(ThreebodyRecoTask, processMC, "MC reconstruction", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), }; } diff --git a/PWGLF/TableProducer/Nuspex/trHeAnalysis.cxx b/PWGLF/TableProducer/Nuspex/trHeAnalysis.cxx new file mode 100644 index 00000000000..bc402c3579b --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/trHeAnalysis.cxx @@ -0,0 +1,660 @@ +// 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 trHeAnalysis.cxx +/// +/// \brief Triton and Helion Analysis on pp Data +/// +/// \author Matthias Herzer , Goethe University Frankfurt +/// +#include +#include +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/PID/TPCPIDResponse.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFNucleiTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include + +namespace o2::aod +{ +namespace h3_data +{ +DECLARE_SOA_COLUMN(TPt, tPt, float); +DECLARE_SOA_COLUMN(TEta, tEta, float); +DECLARE_SOA_COLUMN(TPhi, tPhi, float); +DECLARE_SOA_COLUMN(TCharge, tCharge, int8_t); +DECLARE_SOA_COLUMN(TP, tP, float); +DECLARE_SOA_COLUMN(TH3DeDx, tH3DeDx, float); +DECLARE_SOA_COLUMN(TnSigmaTpc, tnSigmaTpc, float); +DECLARE_SOA_COLUMN(TTofSignalH3, tTofSignalH3, float); +DECLARE_SOA_COLUMN(TDcaXY, tDcaXY, float); +DECLARE_SOA_COLUMN(TDcaZ, tDcaZ, float); +DECLARE_SOA_COLUMN(TSigmaYX, tSigmaYX, float); +DECLARE_SOA_COLUMN(TSigmaXYZ, tSigmaXYZ, float); +DECLARE_SOA_COLUMN(TSigmaZ, tSigmaZ, float); +DECLARE_SOA_COLUMN(TnTpcCluster, tnTpcCluster, int); +DECLARE_SOA_COLUMN(TnItsCluster, tnItsCluster, int); +DECLARE_SOA_COLUMN(TTpcChi2NCl, tTpcChi2NCl, float); +DECLARE_SOA_COLUMN(TItsChi2NCl, tItsChi2NCl, float); +DECLARE_SOA_COLUMN(TRigidity, tRigidity, float); +DECLARE_SOA_COLUMN(TItsClusterSize, tItsClusterSize, float); +} // namespace h3_data +DECLARE_SOA_TABLE(H3Data, "AOD", "h3_data", h3_data::TPt, h3_data::TEta, + h3_data::TPhi, h3_data::TCharge, h3_data::TH3DeDx, + h3_data::TnSigmaTpc, h3_data::TTofSignalH3, h3_data::TDcaXY, + h3_data::TDcaZ, h3_data::TSigmaYX, h3_data::TSigmaXYZ, + h3_data::TSigmaZ, h3_data::TnTpcCluster, + h3_data::TnItsCluster, h3_data::TTpcChi2NCl, + h3_data::TItsChi2NCl, h3_data::TRigidity, + h3_data::TItsClusterSize); +namespace he_data +{ +DECLARE_SOA_COLUMN(TPt, tPt, float); +DECLARE_SOA_COLUMN(TEta, tEta, float); +DECLARE_SOA_COLUMN(TPhi, tPhi, float); +DECLARE_SOA_COLUMN(TCharge, tCharge, int8_t); +DECLARE_SOA_COLUMN(TP, tP, float); +DECLARE_SOA_COLUMN(THeDeDx, tHeDeDx, float); +DECLARE_SOA_COLUMN(TnSigmaTpc, tnSigmaTpc, float); +DECLARE_SOA_COLUMN(TTofSignalHe, tTofSignalHe, float); +DECLARE_SOA_COLUMN(TDcaXY, tDcaXY, float); +DECLARE_SOA_COLUMN(TDcaZ, tDcaZ, float); +DECLARE_SOA_COLUMN(TSigmaYX, tSigmaYX, float); +DECLARE_SOA_COLUMN(TSigmaXYZ, tSigmaXYZ, float); +DECLARE_SOA_COLUMN(TSigmaZ, tSigmaZ, float); +DECLARE_SOA_COLUMN(TnTpcCluster, tnTpcCluster, int); +DECLARE_SOA_COLUMN(TnItsCluster, tnItsCluster, int); +DECLARE_SOA_COLUMN(TTpcChi2NCl, tTpcChi2NCl, float); +DECLARE_SOA_COLUMN(TItsChi2NCl, tItsChi2NCl, float); +DECLARE_SOA_COLUMN(TRigidity, tRigidity, float); +DECLARE_SOA_COLUMN(TItsClusterSize, tItsClusterSize, float); +} // namespace he_data +DECLARE_SOA_TABLE(HeData, "AOD", "he_data", he_data::TPt, he_data::TEta, + he_data::TPhi, he_data::TCharge, he_data::THeDeDx, + he_data::TnSigmaTpc, he_data::TTofSignalHe, he_data::TDcaXY, + he_data::TDcaZ, he_data::TSigmaYX, he_data::TSigmaXYZ, + he_data::TSigmaZ, he_data::TnTpcCluster, + he_data::TnItsCluster, he_data::TTpcChi2NCl, + he_data::TItsChi2NCl, he_data::TRigidity, + he_data::TItsClusterSize); +} // namespace o2::aod +namespace +{ +const int nBetheParams = 6; +const int nParticles = 2; +static const std::vector particleNames{"triton", "helion"}; +static const std::vector particlePdgCodes{ + o2::constants::physics::kTriton, o2::constants::physics::kHelium3}; +static const std::vector particleMasses{ + o2::constants::physics::MassTriton, o2::constants::physics::MassHelium3}; +static const std::vector particleCharge{1, 2}; +static const std::vector betheBlochParNames{ + "p0", "p1", "p2", "p3", "p4", "resolution"}; +constexpr float betheBlochDefault[nParticles][nBetheParams]{ + {0.313129, 181.664226, 2779397163087.684082, 2.130773, 29.609643, + 0.09}, // triton + {70.584685, 3.196364, 0.133878, 2.731736, 1.675617, 0.09}}; // Helion + +} // namespace +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using TracksFull = + soa::Join; + +class Particle +{ + public: + TString name; + int pdgCode; + float mass; + int charge; + float resolution; + std::vector betheParams; + + Particle(const std::string name_, int pdgCode_, float mass_, int charge_, + LabeledArray bethe) + { + name = TString(name_); + pdgCode = pdgCode_; + mass = mass_; + charge = charge_; + + resolution = + bethe.get(name, "resolution"); // Access the "resolution" parameter + + betheParams.clear(); + for (int i = 0; i < 5; ++i) { + betheParams.push_back(bethe.get(name, i)); + } + } +}; + +struct TrHeAnalysis { + Produces h3Data; + Produces heData; + HistogramRegistry histos{ + "Histos", + {}, + OutputObjHandlingPolicy::AnalysisObject}; + std::vector particles; + Configurable enableTr{"enableTr", true, "Flag to enable triton analysis."}; + Configurable enableHe{"enableHe", true, "Flag to enable helium-3 analysis."}; + ConfigurableAxis binsDeDx{"binsDeDx", {600, 0.f, 3000.f}, ""}; + ConfigurableAxis binsBeta{"binsBeta", {120, 0.0, 1.2}, ""}; + ConfigurableAxis binsDca{"binsDca", {400, -1.f, 1.f}, ""}; + ConfigurableAxis binsSigmaTpc{"binsSigmaTpc", {1000, -100, 100}, ""}; + ConfigurableAxis binsSigmaTof{"binsSigmaTof", {1000, -100, 100}, ""}; + ConfigurableAxis binsMassTr{"binsMassTr", {250, -2.5, 2.5f}, ""}; + ConfigurableAxis binsMassHe{"binsMassHe", {300, -3., 3.f}, ""}; + // Set the event selection cuts + struct : ConfigurableGroup { + Configurable useSel8{"useSel8", true, "Use Sel8 for run3 Event Selection"}; + Configurable tvxTrigger{"tvxTrigger", false, "Use TVX for Event Selection (default w/ Sel8)"}; + Configurable removeTfBorder{"removeTfBorder", false, "Remove TimeFrame border (default w/ Sel8)"}; + Configurable removeItsRofBorder{"removeItsRofBorder", false, "Remove ITS Read-Out Frame border (default w/ Sel8)"}; + } evselOptions; + + Configurable cfgTPCPidMethod{"cfgTPCPidMethod", false, "Using own or built in bethe parametrization"}; // false for built in + + // Set the multiplity event limits + Configurable cfgLowMultCut{"cfgLowMultCut", 0.0f, "Accepted multiplicity percentage lower limit"}; + Configurable cfgHighMultCut{"cfgHighMultCut", 100.0f, "Accepted multiplicity percentage higher limit"}; + + // Set the z-vertex event cut limits + Configurable cfgHighCutVertex{"cfgHighCutVertex", 10.0f, "Accepted z-vertex upper limit"}; + Configurable cfgLowCutVertex{"cfgLowCutVertex", -10.0f, "Accepted z-vertex lower limit"}; + + // Set the quality cuts for tracks + Configurable rejectFakeTracks{"rejectFakeTracks", false, "Flag to reject ITS-TPC fake tracks (for MC)"}; + Configurable cfgCutItsClusters{"cfgCutItsClusters", -1.f, "Minimum number of ITS clusters"}; + Configurable cfgCutTpcXRows{"cfgCutTpcXRows", -1.f, "Minimum number of crossed TPC rows"}; + Configurable cfgCutTpcClusters{"cfgCutTpcClusters", 40.f, "Minimum number of found TPC clusters"}; + Configurable nItsLayer{"nItsLayer", 0, "ITS Layer (0-6)"}; + Configurable cfgCutTpcCrRowToFindableCl{"cfgCutTpcCrRowToFindableCl", 0.8f, "Minimum ratio of crossed rows to findable cluster in TPC"}; + Configurable cfgCutMaxChi2TpcH3{"cfgCutMaxChi2TpcH3", 4.f, "Maximum chi2 per cluster for TPC"}; + Configurable cfgCutMaxChi2ItsH3{"cfgCutMaxChi2ItsH3", 36.f, "Maximum chi2 per cluster for ITS"}; + Configurable cfgCutMaxChi2TpcHe{"cfgCutMaxChi2TpcHe", 4.f, "Maximum chi2 per cluster for TPC"}; + Configurable cfgCutMaxChi2ItsHe{"cfgCutMaxChi2ItsHe", 36.f, "Maximum chi2 per cluster for ITS"}; + Configurable cfgCutTpcRefit{"cfgCutTpcRefit", 1, "TPC refit "}; + Configurable cfgCutItsRefit{"cfgCutItsRefit", 1, "ITS refit"}; + Configurable cfgCutMaxItsClusterSizeHe{"cfgCutMaxItsClusterSizeHe", 4.f, "Maximum ITS Cluster Size for He "}; + Configurable cfgCutMinItsClusterSizeHe{"cfgCutMinItsClusterSizeHe", 1.f, "Minimum ITS Cluster Size for He"}; + Configurable cfgCutMaxItsClusterSizeH3{"cfgCutMaxItsClusterSizeH3", 4.f, "Maximum ITS Cluster Size for Tr"}; + Configurable cfgCutMinItsClusterSizeH3{"cfgCutMinItsClusterSizeH3", 1.f, "Minimum ITS Cluster Size for Tr"}; + Configurable cfgCutMinTofMassH3{"cfgCutMinTofMassH3", 2.24f, "Minimum Tof mass H3"}; + Configurable cfgCutMaxTofMassH3{"cfgCutMaxTofMassH3", 3.32f, "Maximum TOF mass H3"}; + // Set the kinematic and PID cuts for tracks + struct : ConfigurableGroup { + Configurable pCut{"pCut", 0.3f, "Value of the p selection for spectra (default 0.3)"}; + Configurable etaCut{"etaCut", 0.8f, "Value of the eta selection for spectra (default 0.8)"}; + Configurable yLowCut{"yLowCut", -1.0f, "Value of the low rapidity selection for spectra (default -1.0)"}; + Configurable yHighCut{"yHighCut", 1.0f, "Value of the high rapidity selection for spectra (default 1.0)"}; + } kinemOptions; + + struct : ConfigurableGroup { + Configurable nsigmaTPCTr{"nsigmaTPCTr", 5.f, "Value of the Nsigma TPC cut for tritons"}; + Configurable nsigmaTPCHe{"nsigmaTPCHe", 5.f, "Value of the Nsigma TPC cut for helium-3"}; + } nsigmaTPCvar; + Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {betheBlochDefault[0], nParticles, nBetheParams, particleNames, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for light nuclei"}; + + void init(o2::framework::InitContext&) + { + const AxisSpec dedxAxis{binsDeDx, "d#it{E}/d#it{x} A.U."}; + const AxisSpec betaAxis{binsBeta, "TOF #beta"}; + const AxisSpec dcaxyAxis{binsDca, "DCAxy (cm)"}; + const AxisSpec dcazAxis{binsDca, "DCAz (cm)"}; + const AxisSpec massTrAxis{binsMassTr, ""}; + const AxisSpec massHeAxis{binsMassHe, ""}; + const AxisSpec sigmaTPCAxis{binsSigmaTpc, ""}; + const AxisSpec sigmaTOFAxis{binsSigmaTof, ""}; + + histos.add("histogram/pT", + "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", + HistType::kTH1F, {{500, 0., 10.}}); + histos.add("histogram/p", "Track momentum; p (GeV/#it{c}); counts", + HistType::kTH1F, {{500, 0., 10.}}); + histos.add("histogram/TPCsignVsTPCmomentum", + "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC " + "<-dE/dx> (a.u.)", + HistType::kTH2F, {{400, -8.f, 8.f}, {dedxAxis}}); + histos.add( + "histogram/TOFbetaVsP", + "TOF #beta vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TOF #beta", + HistType::kTH2F, {{250, -5.f, 5.f}, {betaAxis}}); + histos.add("histogram/H3/H3-TPCsignVsTPCmomentum", + "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC " + "<-dE/dx> (a.u.)", + HistType::kTH2F, {{400, -8.f, 8.f}, {dedxAxis}}); + histos.add( + "histogram/H3/H3-TOFbetaVsP", + "TOF #beta vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TOF #beta", + HistType::kTH2F, {{250, -5.f, 5.f}, {betaAxis}}); + histos.add("histogram/He/He-TPCsignVsTPCmomentum", + "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC " + "<-dE/dx> (a.u.)", + HistType::kTH2F, {{400, -8.f, 8.f}, {dedxAxis}}); + histos.add( + "histogram/He/He-TOFbetaVsP", + "TOF #beta vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TOF #beta", + HistType::kTH2F, {{250, -5.f, 5.f}, {betaAxis}}); + histos.add("event/eventSelection", "eventSelection", HistType::kTH1D, + {{7, -0.5, 6.5}}); + auto h = histos.get(HIST("event/eventSelection")); + h->GetXaxis()->SetBinLabel(1, "Total"); + h->GetXaxis()->SetBinLabel(2, "TVX trigger cut"); + h->GetXaxis()->SetBinLabel(3, "TF border cut"); + h->GetXaxis()->SetBinLabel(4, "ITS ROF cut"); + h->GetXaxis()->SetBinLabel(5, "TVX + TF + ITS ROF"); + h->GetXaxis()->SetBinLabel(6, "Sel8 cut"); + h->GetXaxis()->SetBinLabel(7, "Z-vert Cut"); + histos.add("histogram/cuts", "cuts", HistType::kTH1D, + {{13, -0.5, 12.5}}); + auto hCuts = histos.get(HIST("histogram/cuts")); + hCuts->GetXaxis()->SetBinLabel(1, "total"); + hCuts->GetXaxis()->SetBinLabel(2, "p cut"); + hCuts->GetXaxis()->SetBinLabel(3, "eta cut"); + hCuts->GetXaxis()->SetBinLabel(4, "TPC cluster"); + hCuts->GetXaxis()->SetBinLabel(5, "ITS clsuter"); + hCuts->GetXaxis()->SetBinLabel(6, "TPC crossed rows"); + hCuts->GetXaxis()->SetBinLabel(7, "max chi2 ITS"); + hCuts->GetXaxis()->SetBinLabel(8, "max chi2 TPC"); + hCuts->GetXaxis()->SetBinLabel(9, "crossed rows over findable cluster"); + hCuts->GetXaxis()->SetBinLabel(10, "TPC refit"); + hCuts->GetXaxis()->SetBinLabel(11, "ITS refit"); + hCuts->GetXaxis()->SetBinLabel(12, "ITS cluster size"); + hCuts->GetXaxis()->SetBinLabel(13, "TOF mass cut"); + for (int i = 0; i < nParticles; i++) { + particles.push_back(Particle(particleNames.at(i), particlePdgCodes.at(i), + particleMasses.at(i), particleCharge.at(i), + cfgBetheBlochParams)); + } + } + void process(soa::Join::iterator const& event, + TracksFull const& tracks) + { + bool trRapCut = kFALSE; + bool heRapCut = kFALSE; + histos.fill(HIST("event/eventSelection"), 0); + if ((event.selection_bit(aod::evsel::kNoITSROFrameBorder)) && + (event.selection_bit(aod::evsel::kNoTimeFrameBorder)) && + (event.selection_bit(aod::evsel::kIsTriggerTVX))) { + histos.fill(HIST("event/eventSelection"), 4); + } + if (evselOptions.useSel8 && !event.sel8()) + return; + histos.fill(HIST("event/eventSelection"), 5); + if (event.posZ() < cfgLowCutVertex || event.posZ() > cfgHighCutVertex) + return; + histos.fill(HIST("event/eventSelection"), 6); + if (cfgTPCPidMethod) { + for (const auto& track : tracks) { + trRapCut = + track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Triton)) > + kinemOptions.yLowCut && + track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Triton)) < + kinemOptions.yHighCut; + heRapCut = + track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Helium3)) > + kinemOptions.yLowCut && + track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Helium3)) < + kinemOptions.yHighCut; + histos.fill(HIST("histogram/cuts"), 0); + if (std::abs(track.tpcInnerParam()) < kinemOptions.pCut) { + histos.fill(HIST("histogram/cuts"), 1); + continue; + } + if (std::abs(track.eta()) > kinemOptions.etaCut) { + histos.fill(HIST("histogram/cuts"), 2); + continue; + } + if (track.tpcNClsFound() < cfgCutTpcClusters) { + histos.fill(HIST("histogram/cuts"), 3); + continue; + } + if (track.itsNCls() < cfgCutItsClusters) { + histos.fill(HIST("histogram/cuts"), 4); + continue; + } + if (track.tpcNClsCrossedRows() < cfgCutTpcXRows) { + histos.fill(HIST("histogram/cuts"), 5); + continue; + } + if (track.tpcCrossedRowsOverFindableCls() <= cfgCutTpcCrRowToFindableCl) { + histos.fill(HIST("histogram/cuts"), 8); + continue; + } + if (cfgCutTpcRefit) { + if (!track.passedTPCRefit()) { + histos.fill(HIST("histogram/cuts"), 9); + continue; + } + } + if (cfgCutItsRefit) { + if (!track.passedITSRefit()) { + histos.fill(HIST("histogram/cuts"), 10); + continue; + } + } + histos.fill(HIST("histogram/pT"), track.pt()); + histos.fill(HIST("histogram/p"), track.p()); + histos.fill(HIST("histogram/TPCsignVsTPCmomentum"), + track.tpcInnerParam() / (1.f * track.sign()), + track.tpcSignal()); + histos.fill(HIST("histogram/TOFbetaVsP"), + track.p() / (1.f * track.sign()), track.beta()); + if (enableTr && trRapCut) { + if (std::abs(getTPCnSigma(track, particles.at(0))) < + nsigmaTPCvar.nsigmaTPCTr) { + if (track.itsChi2NCl() > cfgCutMaxChi2ItsH3) { + histos.fill(HIST("histogram/cuts"), 6); + continue; + } + if (track.tpcChi2NCl() > cfgCutMaxChi2TpcH3) { + histos.fill(HIST("histogram/cuts"), 7); + continue; + } + if (getMeanItsClsSize(track) / std::cosh(track.eta()) <= cfgCutMinItsClusterSizeH3 || + getMeanItsClsSize(track) / std::cosh(track.eta()) >= cfgCutMaxItsClusterSizeH3) { + histos.fill(HIST("histogram/cuts"), 12); + continue; + } + if (track.mass() < cfgCutMinTofMassH3 || track.mass() > cfgCutMaxTofMassH3) { + histos.fill(HIST("histogram/cuts"), 13); + continue; + } + histos.fill(HIST("histogram/H3/H3-TPCsignVsTPCmomentum"), + track.tpcInnerParam() / (1.f * track.sign()), + track.tpcSignal()); + histos.fill(HIST("histogram/H3/H3-TOFbetaVsP"), + track.p() / (1.f * track.sign()), track.beta()); + float tPt = track.pt(); + float tEta = track.eta(); + float tPhi = track.phi(); + int8_t tCharge = track.sign(); + float tH3DeDx = track.tpcSignal(); + float tnSigmaTpc = track.tpcNSigmaTr(); + float tTofSignalH3 = track.mass(); + float tDcaXY = track.dcaXY(); + float tDcaZ = track.dcaZ(); + float tSigmaYX = track.sigmaY(); + float tSigmaXYZ = track.sigmaSnp(); + float tSigmaZ = track.sigmaZ(); + int tnTpcCluster = track.tpcNClsFound(); + int tnItsCluster = track.itsNCls(); + float tTpcChi2NCl = track.tpcChi2NCl(); + float tItsChi2NCl = track.itsChi2NCl(); + float tRigidity = track.tpcInnerParam(); + float tItsClusterSize = + getMeanItsClsSize(track) / std::cosh(track.eta()); + h3Data(tPt, tEta, tPhi, tCharge, tH3DeDx, tnSigmaTpc, tTofSignalH3, + tDcaXY, tDcaZ, tSigmaYX, tSigmaXYZ, tSigmaZ, tnTpcCluster, + tnItsCluster, tTpcChi2NCl, tItsChi2NCl, tRigidity, + tItsClusterSize); + } + } + if (enableHe && heRapCut) { + if (std::abs(getTPCnSigma(track, particles.at(1))) < + nsigmaTPCvar.nsigmaTPCHe) { + if (track.itsChi2NCl() > cfgCutMaxChi2ItsHe) { + histos.fill(HIST("histogram/cuts"), 6); + continue; + } + if (track.tpcChi2NCl() > cfgCutMaxChi2TpcHe) { + histos.fill(HIST("histogram/cuts"), 7); + continue; + } + if (getMeanItsClsSize(track) / std::cosh(track.eta()) <= cfgCutMinItsClusterSizeHe || + getMeanItsClsSize(track) / std::cosh(track.eta()) >= cfgCutMaxItsClusterSizeHe) { + histos.fill(HIST("histogram/cuts"), 12); + continue; + } + histos.fill(HIST("histogram/He/He-TPCsignVsTPCmomentum"), + track.tpcInnerParam() / (2.f * track.sign()), + track.tpcSignal()); + histos.fill(HIST("histogram/He/He-TOFbetaVsP"), + track.p() / (2.f * track.sign()), track.beta()); + float tPt = track.pt(); + float tEta = track.eta(); + float tPhi = track.phi(); + int8_t tCharge = 2.f * track.sign(); + float tHeDeDx = track.tpcSignal(); + float tnSigmaTpc = track.tpcNSigmaHe(); + float tTofSignalHe = track.mass(); + float tDcaXY = track.dcaXY(); + float tDcaZ = track.dcaZ(); + float tSigmaYX = track.sigmaY(); + float tSigmaXYZ = track.sigmaSnp(); + float tSigmaZ = track.sigmaZ(); + int tnTpcCluster = track.tpcNClsFound(); + int tnItsCluster = track.itsNCls(); + float tTpcChi2NCl = track.tpcChi2NCl(); + float tItsChi2NCl = track.itsChi2NCl(); + float tRigidity = track.tpcInnerParam(); + float tItsClusterSize = + getMeanItsClsSize(track) / std::cosh(track.eta()); + heData(tPt, tEta, tPhi, tCharge, tHeDeDx, tnSigmaTpc, tTofSignalHe, + tDcaXY, tDcaZ, tSigmaYX, tSigmaXYZ, tSigmaZ, tnTpcCluster, + tnItsCluster, tTpcChi2NCl, tItsChi2NCl, tRigidity, + tItsClusterSize); + } + } + } + } + if (!cfgTPCPidMethod) { + for (const auto& track : tracks) { + trRapCut = + track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Triton)) > + kinemOptions.yLowCut && + track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Triton)) < + kinemOptions.yHighCut; + heRapCut = + track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Helium3)) > + kinemOptions.yLowCut && + track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Helium3)) < + kinemOptions.yHighCut; + histos.fill(HIST("histogram/cuts"), 0); + if (std::abs(track.tpcInnerParam()) < kinemOptions.pCut) { + histos.fill(HIST("histogram/cuts"), 1); + continue; + } + if (std::abs(track.eta()) > kinemOptions.etaCut) { + histos.fill(HIST("histogram/cuts"), 2); + continue; + } + if (track.tpcNClsFound() < cfgCutTpcClusters) { + histos.fill(HIST("histogram/cuts"), 3); + continue; + } + if (track.itsNCls() < cfgCutItsClusters) { + histos.fill(HIST("histogram/cuts"), 4); + continue; + } + if (track.tpcNClsCrossedRows() < cfgCutTpcXRows) { + histos.fill(HIST("histogram/cuts"), 5); + continue; + } + if (track.tpcCrossedRowsOverFindableCls() <= cfgCutTpcCrRowToFindableCl) { + histos.fill(HIST("histogram/cuts"), 8); + continue; + } + if (cfgCutTpcRefit) { + if (!track.passedTPCRefit()) { + histos.fill(HIST("histogram/cuts"), 9); + continue; + } + } + if (cfgCutItsRefit) { + if (!track.passedITSRefit()) { + histos.fill(HIST("histogram/cuts"), 10); + continue; + } + } + histos.fill(HIST("histogram/pT"), track.pt()); + histos.fill(HIST("histogram/p"), track.p()); + histos.fill(HIST("histogram/TPCsignVsTPCmomentum"), + track.tpcInnerParam() / (1.f * track.sign()), + track.tpcSignal()); + histos.fill(HIST("histogram/TOFbetaVsP"), + track.p() / (1.f * track.sign()), track.beta()); + if (enableTr && trRapCut) { + if (std::abs(track.tpcNSigmaTr()) < nsigmaTPCvar.nsigmaTPCTr) { + if (track.itsChi2NCl() > cfgCutMaxChi2ItsH3) { + histos.fill(HIST("histogram/cuts"), 6); + continue; + } + if (track.tpcChi2NCl() > cfgCutMaxChi2TpcH3) { + histos.fill(HIST("histogram/cuts"), 7); + continue; + } + if (getMeanItsClsSize(track) / std::cosh(track.eta()) <= cfgCutMinItsClusterSizeH3 || + getMeanItsClsSize(track) / std::cosh(track.eta()) >= cfgCutMaxItsClusterSizeH3) { + histos.fill(HIST("histogram/cuts"), 12); + continue; + } + if (track.mass() < cfgCutMinTofMassH3 || track.mass() > cfgCutMaxTofMassH3) { + histos.fill(HIST("histogram/cuts"), 13); + continue; + } + histos.fill(HIST("histogram/H3/H3-TPCsignVsTPCmomentum"), + track.tpcInnerParam() / (1.f * track.sign()), + track.tpcSignal()); + histos.fill(HIST("histogram/H3/H3-TOFbetaVsP"), + track.p() / (1.f * track.sign()), track.beta()); + float tPt = track.pt(); + float tEta = track.eta(); + float tPhi = track.phi(); + int8_t tCharge = track.sign(); + float tH3DeDx = track.tpcSignal(); + float tnSigmaTpc = track.tpcNSigmaTr(); + float tTofSignalH3 = track.mass(); + float tDcaXY = track.dcaXY(); + float tDcaZ = track.dcaZ(); + float tSigmaYX = track.sigmaY(); + float tSigmaXYZ = track.sigmaSnp(); + float tSigmaZ = track.sigmaZ(); + int tnTpcCluster = track.tpcNClsFound(); + int tnItsCluster = track.itsNCls(); + float tTpcChi2NCl = track.tpcChi2NCl(); + float tItsChi2NCl = track.itsChi2NCl(); + float tRigidity = track.tpcInnerParam(); + float tItsClusterSize = + getMeanItsClsSize(track) / std::cosh(track.eta()); + h3Data(tPt, tEta, tPhi, tCharge, tH3DeDx, tnSigmaTpc, tTofSignalH3, + tDcaXY, tDcaZ, tSigmaYX, tSigmaXYZ, tSigmaZ, tnTpcCluster, + tnItsCluster, tTpcChi2NCl, tItsChi2NCl, tRigidity, + tItsClusterSize); + } + } + if (enableHe && heRapCut) { + if (std::abs(track.tpcNSigmaHe()) < nsigmaTPCvar.nsigmaTPCHe) { + if (track.itsChi2NCl() > cfgCutMaxChi2ItsHe) { + histos.fill(HIST("histogram/cuts"), 6); + continue; + } + if (track.tpcChi2NCl() > cfgCutMaxChi2TpcHe) { + histos.fill(HIST("histogram/cuts"), 7); + continue; + } + if (getMeanItsClsSize(track) / std::cosh(track.eta()) <= cfgCutMinItsClusterSizeHe || + getMeanItsClsSize(track) / std::cosh(track.eta()) >= cfgCutMaxItsClusterSizeHe) { + histos.fill(HIST("histogram/cuts"), 12); + continue; + } + histos.fill(HIST("histogram/He/He-TPCsignVsTPCmomentum"), + track.tpcInnerParam() / (2.f * track.sign()), + track.tpcSignal()); + histos.fill(HIST("histogram/He/He-TOFbetaVsP"), + track.p() / (2.f * track.sign()), track.beta()); + float tPt = track.pt(); + float tEta = track.eta(); + float tPhi = track.phi(); + int8_t tCharge = 2.f * track.sign(); + float tHeDeDx = track.tpcSignal(); + float tnSigmaTpc = track.tpcNSigmaHe(); + float tTofSignalHe = track.mass(); + float tDcaXY = track.dcaXY(); + float tDcaZ = track.dcaZ(); + float tSigmaYX = track.sigmaY(); + float tSigmaXYZ = track.sigmaSnp(); + float tSigmaZ = track.sigmaZ(); + int tnTpcCluster = track.tpcNClsFound(); + int tnItsCluster = track.itsNCls(); + float tTpcChi2NCl = track.tpcChi2NCl(); + float tItsChi2NCl = track.itsChi2NCl(); + float tRigidity = track.tpcInnerParam(); + float tItsClusterSize = + getMeanItsClsSize(track) / std::cosh(track.eta()); + heData(tPt, tEta, tPhi, tCharge, tHeDeDx, tnSigmaTpc, tTofSignalHe, + tDcaXY, tDcaZ, tSigmaYX, tSigmaXYZ, tSigmaZ, tnTpcCluster, + tnItsCluster, tTpcChi2NCl, tItsChi2NCl, tRigidity, + tItsClusterSize); + } + } + } + } + } + + template + float getTPCnSigma(T const& track, Particle const& particle) + { + const float rigidity = track.tpcInnerParam(); + if (!track.hasTPC()) + return -999; + + float expBethe{tpc::BetheBlochAleph( + static_cast(particle.charge * rigidity / particle.mass), + particle.betheParams[0], particle.betheParams[1], + particle.betheParams[2], particle.betheParams[3], + particle.betheParams[4])}; + float expSigma{expBethe * particle.resolution}; + float sigmaTPC = + static_cast((track.tpcSignal() - expBethe) / expSigma); + return sigmaTPC; + } + + template + float getMeanItsClsSize(T const& track) + { + int sum = 0, n = 0; + for (int i = 0; i < 8; i++) { + sum += (track.itsClusterSizes() >> (4 * i) & 15); + if (track.itsClusterSizes() >> (4 * i) & 15) + n++; + } + return n > 0 ? static_cast(sum) / n : 0.f; + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGLF/TableProducer/QC/CMakeLists.txt b/PWGLF/TableProducer/QC/CMakeLists.txt index b53c54f4804..db3fdb4876b 100644 --- a/PWGLF/TableProducer/QC/CMakeLists.txt +++ b/PWGLF/TableProducer/QC/CMakeLists.txt @@ -10,11 +10,11 @@ # or submit itself to any jurisdiction. o2physics_add_dpl_workflow(strangenessqc - SOURCES strangenessQC.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) + SOURCES strangenessQC.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(flow-qc - SOURCES flowQC.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) + SOURCES flowQC.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGLF/TableProducer/QC/flowQC.cxx b/PWGLF/TableProducer/QC/flowQC.cxx index ce4747a7534..f5dfa06f9d7 100644 --- a/PWGLF/TableProducer/QC/flowQC.cxx +++ b/PWGLF/TableProducer/QC/flowQC.cxx @@ -31,6 +31,7 @@ #include "Common/DataModel/EventSelection.h" #include "Common/Core/EventPlaneHelper.h" #include "PWGLF/DataModel/EPCalibrationTables.h" +#include "Common/DataModel/Qvectors.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" @@ -66,16 +67,27 @@ enum qVecDetectors { kFT0A, kTPCl, kTPCr, + kTPC, kNqVecDetectors }; -static const std::vector qVecDetectorNames{"FT0C", "FT0A", "TPCl", "TPCr"}; - -std::shared_ptr hQxQy[kNqVecDetectors]; -std::shared_ptr hNormQxQy[kNqVecDetectors]; -std::shared_ptr hPsi[kNqVecDetectors]; -std::shared_ptr hDeltaPsi[kNqVecDetectors][kNqVecDetectors]; -std::shared_ptr hScalarProduct[kNqVecDetectors][kNqVecDetectors]; -std::shared_ptr hNormalisedScalarProduct[kNqVecDetectors][kNqVecDetectors]; +static const std::vector qVecDetectorNames{"FT0C", "FT0A", "TPCl", "TPCr", "TPC"}; + +enum methods { + kEP = 0, + kQvec, + kNmethods +}; +static const std::vector suffixes = {"EP", "Qvec"}; + +std::shared_ptr hQxQy[kNmethods][kNqVecDetectors]; +std::shared_ptr hNormQxQy[kNmethods][kNqVecDetectors]; +std::shared_ptr hPsi[kNmethods][kNqVecDetectors]; +std::shared_ptr hDeltaPsi[kNmethods][kNqVecDetectors][kNqVecDetectors]; +std::shared_ptr hScalarProduct[kNmethods][kNqVecDetectors][kNqVecDetectors]; +std::shared_ptr hNormalisedScalarProduct[kNmethods][kNqVecDetectors][kNqVecDetectors]; + +std::shared_ptr hPsiComp[kNqVecDetectors]; +std::shared_ptr hCosPsiComp[kNqVecDetectors]; } // namespace struct flowQC { @@ -89,6 +101,7 @@ struct flowQC { ConfigurableAxis cfgQvecBins{"cfgQvecBins", {100, -2.f, 2.f}, "Binning for scalar product"}; ConfigurableAxis cfgPhiBins{"cfgPhiBins", {140, -3.5f, 3.5f}, "Binning for azimuthal angle"}; ConfigurableAxis cfgDeltaPhiBins{"cfgDeltaPhiBins", {280, -7.f, 7.f}, "Binning for azimuthal-angle differences"}; + ConfigurableAxis cfgCosPhiBins{"cfgCosPhiBins", {220, -1.1f, 1.1f}, "Binning for consinus of azimuthal angle"}; // CCDB options Configurable cfgBz{"cfgBz", -999, "bz field, -999 is automatic"}; @@ -99,15 +112,23 @@ struct flowQC { float mBz = 0.f; // Flow analysis - using CollWithEP = soa::Join::iterator; + using CollWithEPandQvec = soa::Join::iterator; - HistogramRegistry flow{"flow", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry general{"general", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry flow_ep{"flow_ep", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry flow_qvec{"flow_qvec", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry flow_comp{"flow_comp", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; template bool eventSelection(collision_t& collision) { - return collision.sel8() && collision.posZ() > -cfgCutVertex && collision.posZ() < cfgCutVertex; + return collision.sel8() && collision.posZ() > -cfgCutVertex && collision.posZ() < cfgCutVertex && collision.selection_bit(aod::evsel::kNoTimeFrameBorder) && collision.triggereventep() && collision.selection_bit(aod::evsel::kNoSameBunchPileup); + } + + float computeEventPlane(float y, float x) + { + return 0.5 * TMath::ATan2(y, x); } void initCCDB(aod::BCsWithTimestamps::iterator const& bc) @@ -156,37 +177,47 @@ struct flowQC { const AxisSpec NormQxAxis{cfgQvecBins, "#frac{Q_{2,x}}{||#vec{Q_{2}}||}"}; const AxisSpec NormQyAxis{cfgQvecBins, "#frac{Q_{2,y}}{||#vec{Q_{2}}||}"}; - const AxisSpec psiAxis{cfgPhiBins, "#psi"}; + const AxisSpec psiAxis{cfgPhiBins, "#psi_{2}"}; + const AxisSpec psiCompAxis{cfgPhiBins, "#psi_{2}^{EP} - #psi_{2}^{Qvec}"}; + const AxisSpec cosPsiCompAxis{cfgCosPhiBins, "cos[2(#psi_{2}^{EP} - #psi_{2}^{Qvec})]"}; // z vertex histogram - flow.add("hRecVtxZData", "collision z position", HistType::kTH1F, {{200, -20., +20., "z position (cm)"}}); + general.add("hRecVtxZData", "collision z position", HistType::kTH1F, {{200, -20., +20., "z position (cm)"}}); // Centrality histograms - flow.add("hCentFT0C", "", HistType::kTH1F, {centFT0cAxis}); - flow.add("hCentFT0A", "", HistType::kTH1F, {centFT0aAxis}); - flow.add("hCentFT0M", "", HistType::kTH1F, {centFT0mAxis}); - flow.add("hCentFV0A", "", HistType::kTH1F, {centFV0aAxis}); + general.add("hCentFT0C", "", HistType::kTH1F, {centFT0cAxis}); + general.add("hCentFT0A", "", HistType::kTH1F, {centFT0aAxis}); + general.add("hCentFT0M", "", HistType::kTH1F, {centFT0mAxis}); + general.add("hCentFV0A", "", HistType::kTH1F, {centFV0aAxis}); - for (int iQvecDet = 0; iQvecDet < qVecDetectors::kNqVecDetectors; iQvecDet++) { - hQxQy[iQvecDet] = flow.add(Form("hQxQy_%s", qVecDetectorNames[iQvecDet].c_str()), "", HistType::kTH3F, {centAxis, QxAxis, QyAxis}); - hNormQxQy[iQvecDet] = flow.add(Form("hNormQxQy_%s", qVecDetectorNames[iQvecDet].c_str()), "", HistType::kTH3F, {centAxis, NormQxAxis, NormQyAxis}); - hPsi[iQvecDet] = flow.add(Form("hPsi_%s", qVecDetectorNames[iQvecDet].c_str()), "", HistType::kTH2F, {centAxis, psiAxis}); - for (int jQvecDet = iQvecDet + 1; jQvecDet < qVecDetectors::kNqVecDetectors; jQvecDet++) { + for (int iMethod = 0; iMethod < methods::kNmethods; iMethod++) { + HistogramRegistry* registry = (iMethod == methods::kEP) ? &flow_ep : &flow_qvec; + + for (int iQvecDet = 0; iQvecDet < qVecDetectors::kNqVecDetectors; iQvecDet++) { + hQxQy[iMethod][iQvecDet] = registry->add(Form("hQxQy_%s_%s", qVecDetectorNames[iQvecDet].c_str(), suffixes[iMethod].c_str()), "", HistType::kTH3F, {centAxis, QxAxis, QyAxis}); + hNormQxQy[iMethod][iQvecDet] = registry->add(Form("hNormQxQy_%s_%s", qVecDetectorNames[iQvecDet].c_str(), suffixes[iMethod].c_str()), "", HistType::kTH3F, {centAxis, NormQxAxis, NormQyAxis}); + hPsi[iMethod][iQvecDet] = registry->add(Form("hPsi_%s_%s", qVecDetectorNames[iQvecDet].c_str(), suffixes[iMethod].c_str()), "", HistType::kTH2F, {centAxis, psiAxis}); + for (int jQvecDet = iQvecDet + 1; jQvecDet < qVecDetectors::kNqVecDetectors; jQvecDet++) { - // Q-vector azimuthal-angle differences - hDeltaPsi[iQvecDet][jQvecDet] = flow.add(Form("hDeltaPsi_%s_%s", qVecDetectorNames[iQvecDet].c_str(), qVecDetectorNames[jQvecDet].c_str()), "", HistType::kTH2F, {centAxis, {cfgDeltaPhiBins, Form("#psi_{%s} - #psi_{%s}", qVecDetectorNames[iQvecDet].c_str(), qVecDetectorNames[jQvecDet].c_str())}}); + // Q-vector azimuthal-angle differences + hDeltaPsi[iMethod][iQvecDet][jQvecDet] = registry->add(Form("hDeltaPsi_%s_%s_%s", qVecDetectorNames[iQvecDet].c_str(), qVecDetectorNames[jQvecDet].c_str(), suffixes[iMethod].c_str()), "", HistType::kTH2F, {centAxis, {cfgDeltaPhiBins, Form("#psi_{%s} - #psi_{%s}", qVecDetectorNames[iQvecDet].c_str(), qVecDetectorNames[jQvecDet].c_str())}}); - // Scalar-product histograms - auto spLabel = Form("#vec{Q}_{2}^{%s} #upoint #vec{Q}_{2}^{%s}", qVecDetectorNames[iQvecDet].c_str(), qVecDetectorNames[jQvecDet].c_str()); + // Scalar-product histograms + auto spLabel = Form("#vec{Q}_{2}^{%s} #upoint #vec{Q}_{2}^{%s}", qVecDetectorNames[iQvecDet].c_str(), qVecDetectorNames[jQvecDet].c_str()); - hScalarProduct[iQvecDet][jQvecDet] = flow.add(Form("hScalarProduct_%s_%s", qVecDetectorNames[iQvecDet].c_str(), qVecDetectorNames[jQvecDet].c_str()), "", HistType::kTH2F, {centAxis, {cfgQvecBins, spLabel}}); + hScalarProduct[iMethod][iQvecDet][jQvecDet] = registry->add(Form("hScalarProduct_%s_%s_%s", qVecDetectorNames[iQvecDet].c_str(), qVecDetectorNames[jQvecDet].c_str(), suffixes[iMethod].c_str()), "", HistType::kTH2F, {centAxis, {cfgQvecBins, spLabel}}); - // Normalised scalar-product histograms - auto normSpLabel = Form("#frac{#vec{Q}_{2}^{%s} #upoint #vec{Q}_{2}^{%s}}{||#vec{Q}_{2}^{%s}|| ||#vec{Q}_{2}^{%s}||}", qVecDetectorNames[iQvecDet].c_str(), qVecDetectorNames[jQvecDet].c_str(), qVecDetectorNames[iQvecDet].c_str(), qVecDetectorNames[jQvecDet].c_str()); + // Normalised scalar-product histograms + auto normSpLabel = Form("#frac{#vec{Q}_{2}^{%s} #upoint #vec{Q}_{2}^{%s}}{||#vec{Q}_{2}^{%s}|| ||#vec{Q}_{2}^{%s}||}", qVecDetectorNames[iQvecDet].c_str(), qVecDetectorNames[jQvecDet].c_str(), qVecDetectorNames[iQvecDet].c_str(), qVecDetectorNames[jQvecDet].c_str()); - hNormalisedScalarProduct[iQvecDet][jQvecDet] = flow.add(Form("hNormalisedScalarProduct_%s_%s", qVecDetectorNames[iQvecDet].c_str(), qVecDetectorNames[jQvecDet].c_str()), "", HistType::kTH2F, {centAxis, {cfgQvecBins, normSpLabel}}); + hNormalisedScalarProduct[iMethod][iQvecDet][jQvecDet] = registry->add(Form("hNormalisedScalarProduct_%s_%s_%s", qVecDetectorNames[iQvecDet].c_str(), qVecDetectorNames[jQvecDet].c_str(), suffixes[iMethod].c_str()), "", HistType::kTH2F, {centAxis, {cfgQvecBins, normSpLabel}}); + } } } + for (int iQvecDet = 0; iQvecDet < qVecDetectors::kNqVecDetectors; iQvecDet++) { + hPsiComp[iQvecDet] = flow_comp.add(Form("hPsiComp_%s", qVecDetectorNames[iQvecDet].c_str()), "", HistType::kTH2F, {centAxis, psiCompAxis}); + hCosPsiComp[iQvecDet] = flow_comp.add(Form("hCosPsiComp_%s", qVecDetectorNames[iQvecDet].c_str()), "", HistType::kTH2F, {centAxis, cosPsiCompAxis}); + } } template @@ -206,7 +237,7 @@ struct flowQC { } } - void process(CollWithEP const& collision, aod::BCsWithTimestamps const&) + void process(CollWithEPandQvec const& collision, aod::BCsWithTimestamps const&) { auto bc = collision.template bc_as(); initCCDB(bc); @@ -216,61 +247,99 @@ struct flowQC { return; } - flow.fill(HIST("hRecVtxZData"), collision.posZ()); + general.fill(HIST("hRecVtxZData"), collision.posZ()); const o2::math_utils::Point3D collVtx{collision.posX(), collision.posY(), collision.posZ()}; - flow.fill(HIST("hCentFT0C"), collision.centFT0C()); - flow.fill(HIST("hCentFT0A"), collision.centFT0A()); - flow.fill(HIST("hCentFT0M"), collision.centFT0M()); - flow.fill(HIST("hCentFV0A"), collision.centFV0A()); + general.fill(HIST("hCentFT0C"), collision.centFT0C()); + general.fill(HIST("hCentFT0A"), collision.centFT0A()); + general.fill(HIST("hCentFT0M"), collision.centFT0M()); + general.fill(HIST("hCentFV0A"), collision.centFV0A()); float centrality = getCentrality(collision); - float psiFT0A = collision.psiFT0A(); - float QxFT0A = std::cos(2 * psiFT0A); - float QyFT0A = std::sin(2 * psiFT0A); - float QmodFT0A = std::hypot(QxFT0A, QyFT0A); - - float psiFT0C = collision.psiFT0C(); - float QxFT0C = std::cos(2 * psiFT0C); - float QyFT0C = std::sin(2 * psiFT0C); - float QmodFT0C = std::hypot(QxFT0C, QyFT0C); - - float psiTPCl = collision.psiTPCL(); - float QxTPCl = std::cos(2 * psiTPCl); - float QyTPCl = std::sin(2 * psiTPCl); - float QmodTPCl = std::hypot(QxTPCl, QyTPCl); - - float psiTPCr = collision.psiTPCR(); - float QxTPCr = std::cos(2 * psiTPCr); - float QyTPCr = std::sin(2 * psiTPCr); - float QmodTPCr = std::hypot(QxTPCr, QyTPCr); - - std::array vec_Qx = {QxFT0C, QxFT0A, QxTPCl, QxTPCr}; - std::array vec_Qy = {QyFT0C, QyFT0A, QyTPCl, QyTPCr}; - std::array vec_Qmod = {QmodFT0C, QmodFT0A, QmodTPCl, QmodTPCr}; - std::array vec_Qpsi = {psiFT0C, psiFT0A, psiTPCl, psiTPCr}; - - for (int iQvecDet = 0; iQvecDet < qVecDetectors::kNqVecDetectors; iQvecDet++) { - hQxQy[iQvecDet]->Fill(centrality, vec_Qx[iQvecDet], vec_Qy[iQvecDet]); - hNormQxQy[iQvecDet]->Fill(centrality, vec_Qx[iQvecDet] / vec_Qmod[iQvecDet], vec_Qy[iQvecDet] / vec_Qmod[iQvecDet]); - hPsi[iQvecDet]->Fill(centrality, vec_Qpsi[iQvecDet]); - for (int jQvecDet = iQvecDet + 1; jQvecDet < qVecDetectors::kNqVecDetectors; jQvecDet++) { - // Q-vector azimuthal-angle differences - hDeltaPsi[iQvecDet][jQvecDet]->Fill(centrality, vec_Qpsi[iQvecDet] - vec_Qpsi[jQvecDet]); - // Scalar-product histograms - auto getSP = [&](int iDet1, int iDet2) { - return vec_Qx[iDet1] * vec_Qx[iDet2] + vec_Qy[iDet1] * vec_Qy[iDet2]; - }; - hScalarProduct[iQvecDet][jQvecDet]->Fill(centrality, getSP(iQvecDet, jQvecDet)); - // Normalised scalar-product histograms - auto getNormSP = [&](int iDet1, int iDet2) { - return getSP(iDet1, iDet2) / (vec_Qmod[iDet1] * vec_Qmod[iDet2]); - }; - hNormalisedScalarProduct[iQvecDet][jQvecDet]->Fill(centrality, getNormSP(iQvecDet, jQvecDet)); + // EP method + float QmodFT0A_EP = collision.qFT0A(); + float psiFT0A_EP = collision.psiFT0A(); + float QxFT0A_EP = QmodFT0A_EP * std::cos(2 * psiFT0A_EP); + float QyFT0A_EP = QmodFT0A_EP * std::sin(2 * psiFT0A_EP); + + float QmodFT0C_EP = collision.qFT0C(); + float psiFT0C_EP = collision.psiFT0C(); + float QxFT0C_EP = QmodFT0C_EP * std::cos(2 * psiFT0C_EP); + float QyFT0C_EP = QmodFT0C_EP * std::sin(2 * psiFT0C_EP); + + float QmodTPCl_EP = collision.qTPCL(); + float psiTPCl_EP = collision.psiTPCL(); + float QxTPCl_EP = QmodTPCl_EP * std::cos(2 * psiTPCl_EP); + float QyTPCl_EP = QmodTPCl_EP * std::sin(2 * psiTPCl_EP); + + float QmodTPCr_EP = collision.qTPCR(); + float psiTPCr_EP = collision.psiTPCR(); + float QxTPCr_EP = QmodTPCr_EP * std::cos(2 * psiTPCr_EP); + float QyTPCr_EP = QmodTPCr_EP * std::sin(2 * psiTPCr_EP); + + float QmodTPC_EP = collision.qTPC(); + float psiTPC_EP = collision.psiTPC(); + float QxTPC_EP = QmodTPC_EP * std::cos(2 * psiTPC_EP); + float QyTPC_EP = QmodTPC_EP * std::sin(2 * psiTPC_EP); + + // Qvec method + float QxFT0A_Qvec = collision.qvecFT0ARe(); + float QyFT0A_Qvec = collision.qvecFT0AIm(); + float QmodFT0A_Qvec = std::hypot(QxFT0A_Qvec, QyFT0A_Qvec); + float psiFT0A_Qvec = computeEventPlane(QyFT0A_Qvec, QxFT0A_Qvec); + + float QxFT0C_Qvec = collision.qvecFT0CRe(); + float QyFT0C_Qvec = collision.qvecFT0CIm(); + float QmodFT0C_Qvec = std::hypot(QxFT0C_Qvec, QyFT0C_Qvec); + float psiFT0C_Qvec = computeEventPlane(QyFT0C_Qvec, QxFT0C_Qvec); + + float QxTPCl_Qvec = collision.qvecBNegRe(); + float QyTPCl_Qvec = collision.qvecBNegIm(); + float QmodTPCl_Qvec = std::hypot(QxTPCl_Qvec, QyTPCl_Qvec); + float psiTPCl_Qvec = computeEventPlane(QyTPCl_Qvec, QxTPCl_Qvec); + + float QxTPCr_Qvec = collision.qvecBPosRe(); + float QyTPCr_Qvec = collision.qvecBPosIm(); + float QmodTPCr_Qvec = std::hypot(QxTPCr_Qvec, QyTPCr_Qvec); + float psiTPCr_Qvec = computeEventPlane(QyTPCr_Qvec, QxTPCr_Qvec); + + float QxTPC_Qvec = collision.qvecBTotRe(); + float QyTPC_Qvec = collision.qvecBTotIm(); + float QmodTPC_Qvec = std::hypot(QxTPC_Qvec, QyTPC_Qvec); + float psiTPC_Qvec = computeEventPlane(QyTPC_Qvec, QxTPC_Qvec); + + std::array vec_Qx[2] = {{QxFT0C_EP, QxFT0A_EP, QxTPCl_EP, QxTPCr_EP, QxTPC_EP}, {QxFT0C_Qvec, QxFT0A_Qvec, QxTPCl_Qvec, QxTPCr_Qvec, QxTPC_Qvec}}; + std::array vec_Qy[2] = {{QyFT0C_EP, QyFT0A_EP, QyTPCl_EP, QyTPCr_EP, QyTPC_EP}, {QyFT0C_Qvec, QyFT0A_Qvec, QyTPCl_Qvec, QyTPCr_Qvec, QyTPC_Qvec}}; + std::array vec_Qmod[2] = {{QmodFT0C_EP, QmodFT0A_EP, QmodTPCl_EP, QmodTPCr_EP, QmodTPC_EP}, {QmodFT0C_Qvec, QmodFT0A_Qvec, QmodTPCl_Qvec, QmodTPCr_Qvec, QmodTPC_Qvec}}; + std::array vec_Qpsi[2] = {{psiFT0C_EP, psiFT0A_EP, psiTPCl_EP, psiTPCr_EP, psiTPC_EP}, {psiFT0C_Qvec, psiFT0A_Qvec, psiTPCl_Qvec, psiTPCr_Qvec, psiTPC_Qvec}}; + + for (int iMethod = 0; iMethod < methods::kNmethods; iMethod++) { + for (int iQvecDet = 0; iQvecDet < qVecDetectors::kNqVecDetectors; iQvecDet++) { + hQxQy[iMethod][iQvecDet]->Fill(centrality, vec_Qx[iMethod][iQvecDet], vec_Qy[iMethod][iQvecDet]); + hNormQxQy[iMethod][iQvecDet]->Fill(centrality, vec_Qx[iMethod][iQvecDet] / vec_Qmod[iMethod][iQvecDet], vec_Qy[iMethod][iQvecDet] / vec_Qmod[iMethod][iQvecDet]); + hPsi[iMethod][iQvecDet]->Fill(centrality, vec_Qpsi[iMethod][iQvecDet]); + for (int jQvecDet = iQvecDet + 1; jQvecDet < qVecDetectors::kNqVecDetectors; jQvecDet++) { + // Q-vector azimuthal-angle differences + hDeltaPsi[iMethod][iQvecDet][jQvecDet]->Fill(centrality, vec_Qpsi[iMethod][iQvecDet] - vec_Qpsi[iMethod][jQvecDet]); + // Scalar-product histograms + auto getSP = [&](int iDet1, int iDet2) { + return vec_Qx[iMethod][iDet1] * vec_Qx[iMethod][iDet2] + vec_Qy[iMethod][iDet1] * vec_Qy[iMethod][iDet2]; + }; + hScalarProduct[iMethod][iQvecDet][jQvecDet]->Fill(centrality, getSP(iQvecDet, jQvecDet)); + // Normalised scalar-product histograms + auto getNormSP = [&](int iDet1, int iDet2) { + return getSP(iDet1, iDet2) / (vec_Qmod[iMethod][iDet1] * vec_Qmod[iMethod][iDet2]); + }; + hNormalisedScalarProduct[iMethod][iQvecDet][jQvecDet]->Fill(centrality, getNormSP(iQvecDet, jQvecDet)); + } } } + for (int iQvecDet = 0; iQvecDet < qVecDetectors::kNqVecDetectors; iQvecDet++) { + hPsiComp[iQvecDet]->Fill(centrality, vec_Qpsi[methods::kEP][iQvecDet] - vec_Qpsi[methods::kQvec][iQvecDet]); + hCosPsiComp[iQvecDet]->Fill(centrality, std::cos(2 * (vec_Qpsi[methods::kEP][iQvecDet] - vec_Qpsi[methods::kQvec][iQvecDet]))); + } } }; diff --git a/PWGLF/TableProducer/Resonances/CMakeLists.txt b/PWGLF/TableProducer/Resonances/CMakeLists.txt index baa9b98325a..79b69b5b071 100644 --- a/PWGLF/TableProducer/Resonances/CMakeLists.txt +++ b/PWGLF/TableProducer/Resonances/CMakeLists.txt @@ -17,6 +17,11 @@ o2physics_add_dpl_workflow(f1protoninitializer o2physics_add_dpl_workflow(f1protonreducedtable SOURCES f1protonreducedtable.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsVertexing O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(doublephitable + SOURCES doublephitable.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsVertexing COMPONENT_NAME Analysis) @@ -25,12 +30,22 @@ o2physics_add_dpl_workflow(filterf1proton PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsVertexing COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(reso2initializer - SOURCES LFResonanceInitializer.cxx +o2physics_add_dpl_workflow(resonance-initializer + SOURCES resonanceInitializer.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(resonance-module-initializer + SOURCES resonanceModuleInitializer.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(reso2mergedf - SOURCES LFResonanceMergeDF.cxx +o2physics_add_dpl_workflow(resonance-merge-df + SOURCES resonanceMergeDF.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(heptaquarktable + SOURCES HeptaQuarktable.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsVertexing + COMPONENT_NAME Analysis) diff --git a/PWGLF/TableProducer/Resonances/HeptaQuarktable.cxx b/PWGLF/TableProducer/Resonances/HeptaQuarktable.cxx new file mode 100644 index 00000000000..ccb0c61465f --- /dev/null +++ b/PWGLF/TableProducer/Resonances/HeptaQuarktable.cxx @@ -0,0 +1,455 @@ +// 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 heptaquarktable.cxx +/// \brief Selection of events with triplets and pairs for femtoscopic studies +/// +/// \author Junlee Kim, (junlee.kim@cern.ch) + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "CommonConstants/MathConstants.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" + +#include "PWGLF/DataModel/ReducedHeptaQuarkTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct heptaquarktable { + + // Produce derived tables + Produces redHQEvents; + Produces hqTrack; + + // events + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + + Configurable cfgUseGlobalTrack{"cfgUseGlobalTrack", true, "use Global track"}; + Configurable cfgCutCharge{"cfgCutCharge", 0.0, "cut on Charge"}; + Configurable cfgCutPt{"cfgCutPt", 0.2, "PT cut on daughter track"}; + Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; + Configurable cfgCutDCAxy{"cfgCutDCAxy", 2.0f, "DCAxy range for tracks"}; + Configurable cfgCutDCAz{"cfgCutDCAz", 2.0f, "DCAz range for tracks"}; + Configurable cfgNsigmaTPCKa{"cfgNsigmaTPCKa", 3.0, "Value of the TPC Nsigma cut for kaon"}; + Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; + + Configurable cfgMinPhiMass{"cfgMinPhiMass", 1.01, "Minimum phi mass"}; + Configurable cfgMaxPhiMass{"cfgMaxPhiMass", 1.03, "Maximum phi mass"}; + Configurable cfgDeepAngleFlag{"cfgDeepAngleFlag", true, "Deep Angle cut"}; + Configurable cfgDeepAngle{"cfgDeepAngle", 0.04, "Deep Angle cut value"}; + + Configurable cfgv0radiusMin{"cfgv0radiusMin", 1.2, "minimum decay radius"}; + Configurable cfgDCAPosToPVMin{"cfgDCAPosToPVMin", 0.05, "minimum DCA to PV for positive track"}; + Configurable cfgDCANegToPVMin{"cfgDCANegToPVMin", 0.2, "minimum DCA to PV for negative track"}; + Configurable cfgv0CosPA{"cfgv0CosPA", 0.995, "minimum v0 cosine"}; + Configurable cfgDCAV0Dau{"cfgDCAV0Dau", 1.0, "maximum DCA between daughters"}; + + Configurable cfgV0PtMin{"cfgV0PtMin", 0, "minimum pT for lambda"}; + Configurable cfgV0EtaMin{"cfgV0EtaMin", -0.5, "maximum rapidity"}; + Configurable cfgV0EtaMax{"cfgV0EtaMax", 0.5, "maximum rapidity"}; + Configurable cfgV0LifeTime{"cfgV0LifeTime", 30., "maximum lambda lifetime"}; + + Configurable cfgDaughTPCnclsMin{"cfgDaughTPCnclsMin", 70, "minimum fired crossed rows"}; + Configurable cfgDaughPIDCutsTPCPr{"cfgDaughPIDCutsTPCPr", 3, "proton nsigma for TPC"}; + Configurable cfgDaughPIDCutsTPCPi{"cfgDaughPIDCutsTPCPi", 3, "pion nsigma for TPC"}; + Configurable cfgDaughEtaMin{"cfgDaughEtaMin", -0.8, "minimum daughter eta"}; + Configurable cfgDaughEtaMax{"cfgDaughEtaMax", 0.8, "maximum daughter eta"}; + Configurable cfgDaughPrPt{"cfgDaughPrPt", 0.5, "minimum daughter proton pt"}; + Configurable cfgDaughPiPt{"cfgDaughPiPt", 0.5, "minimum daughter pion pt"}; + + Configurable cfgMinLambdaMass{"cfgMinLambdaMass", 1.105, "Minimum lambda mass"}; + Configurable cfgMaxLambdaMass{"cfgMaxLambdaMass", 1.125, "Maximum lambda mass"}; + + ConfigurableAxis massAxis{"massAxis", {200, 3.0, 3.4}, "Invariant mass axis"}; + ConfigurableAxis ptAxis{"ptAxis", {VARIABLE_WIDTH, 0.2, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.5, 8.0, 10.0, 100.0}, "Transverse momentum bins"}; + ConfigurableAxis centAxis{"centAxis", {VARIABLE_WIDTH, 0, 20, 50, 100}, "Centrality interval"}; + ConfigurableAxis vertexAxis{"vertexAxis", {10, -10, 10}, "vertex axis for mixing"}; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPt); + Filter DCAcutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); + + using EventCandidates = soa::Filtered>; + using TrackCandidates = soa::Filtered>; + + HistogramRegistry histos{ + "histos", + {}, + OutputObjHandlingPolicy::AnalysisObject}; + + SliceCache cache; + Partition posTracks = aod::track::signed1Pt > cfgCutCharge; + Partition negTracks = aod::track::signed1Pt < cfgCutCharge; + + double massLambda = o2::constants::physics::MassLambda; + double massPr = o2::constants::physics::MassProton; + double massPi = o2::constants::physics::MassPionCharged; + double massKa = o2::constants::physics::MassKPlus; + + float centrality; + + void init(o2::framework::InitContext&) + { + histos.add("hEventstat", "", {HistType::kTH1F, {{3, 0, 3}}}); + } + + template + bool selectionTrack(const T& candidate) + { + if (cfgUseGlobalTrack && !(candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsFound() > cfgTPCcluster)) { + return false; + } + return true; + } + + template + bool selectionPID(const T& candidate, int pid) + { + if (pid == 0) { + if (std::abs(candidate.tpcNSigmaPi()) > cfgDaughPIDCutsTPCPi) { + return false; + } + } else if (pid == 1) { + if (std::abs(candidate.tpcNSigmaKa()) > cfgNsigmaTPCKa) { + return false; + } + } else if (pid == 2) { + if (std::abs(candidate.tpcNSigmaPr()) > cfgDaughPIDCutsTPCPr) { + return false; + } + } + return true; + } + + template + bool selectionPair(const T1& candidate1, const T2& candidate2) + { + double pt1, pt2, pz1, pz2, p1, p2, angle; + pt1 = candidate1.pt(); + pt2 = candidate2.pt(); + pz1 = candidate1.pz(); + pz2 = candidate2.pz(); + p1 = candidate1.p(); + p2 = candidate2.p(); + angle = TMath::ACos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); + if (cfgDeepAngleFlag && angle < cfgDeepAngle) { + return false; + } + return true; + } + + template + bool selectionV0(TCollision const& collision, V0 const& candidate) + { + if (candidate.v0radius() < cfgv0radiusMin) + return false; + if (std::abs(candidate.dcapostopv()) < cfgDCAPosToPVMin) + return false; + if (std::abs(candidate.dcanegtopv()) < cfgDCANegToPVMin) + return false; + if (candidate.v0cosPA() < cfgv0CosPA) + return false; + if (std::abs(candidate.dcaV0daughters()) > cfgDCAV0Dau) + return false; + if (candidate.pt() < cfgV0PtMin) + return false; + if (candidate.yLambda() < cfgV0EtaMin) + return false; + if (candidate.yLambda() > cfgV0EtaMax) + return false; + if (candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massLambda > cfgV0LifeTime) + return false; + + return true; + } + + template + bool selectionV0Daughter(T const& track, int pid) // pid 0: proton, pid 1: pion + { + if (track.tpcNClsFound() < cfgDaughTPCnclsMin) + return false; + if (pid == 0 && std::abs(track.tpcNSigmaPr()) > cfgDaughPIDCutsTPCPr) + return false; + if (pid == 1 && std::abs(track.tpcNSigmaPi()) > cfgDaughPIDCutsTPCPi) + return false; + if (track.eta() > cfgDaughEtaMax) + return false; + if (track.eta() < cfgDaughEtaMin) + return false; + if (pid == 0 && track.pt() < cfgDaughPrPt) + return false; + if (pid == 1 && track.pt() < cfgDaughPiPt) + return false; + + return true; + } + + ROOT::Math::PxPyPzMVector DauVec1, DauVec2, HQMesonMother, HQVectorDummy, HQd1dummy, HQd2dummy; + + void processHQReducedTable(EventCandidates::iterator const& collision, TrackCandidates const& /*tracks*/, aod::V0Datas const& V0s, aod::BCsWithTimestamps const&) + { + o2::aod::ITSResponse itsResponse; + bool keepEventDoubleHQ = false; + int numberPhi = 0; + int numberLambda = 0; + auto currentRunNumber = collision.bc_as().runNumber(); + auto bc = collision.bc_as(); + centrality = collision.centFT0M(); + + std::vector HQId = {}; + + std::vector HQd1Index = {}; + std::vector HQd2Index = {}; + + std::vector HQd1Charge = {}; + std::vector HQd2Charge = {}; + + std::vector HQd1TPC = {}; + std::vector HQd2TPC = {}; + + std::vector HQd1TOFHit = {}; + std::vector HQd2TOFHit = {}; + + std::vector HQd1TOF = {}; + std::vector HQd2TOF = {}; + + std::vector hqresonance, hqresonanced1, hqresonanced2; + + histos.fill(HIST("hEventstat"), 0.5); + if (!(collision.sel8() && collision.selection_bit(aod::evsel::kNoTimeFrameBorder) && collision.selection_bit(aod::evsel::kNoITSROFrameBorder) && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) + return; + histos.fill(HIST("hEventstat"), 1.5); + + auto posThisColl = posTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negThisColl = negTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + for (auto track1 : posThisColl) { + if (!selectionTrack(track1)) + continue; + + if (!selectionPID(track1, 1)) + continue; + + if (!(itsResponse.nSigmaITS(track1) > -3.0 && itsResponse.nSigmaITS(track1) < 3.0)) + continue; + + /* + qaRegistry.fill(HIST("hNsigmaPtkaonTPC"), track1.tpcNSigmaKa(), track1.pt()); + if (track1.hasTOF()) { + qaRegistry.fill(HIST("hNsigmaPtkaonTOF"), track1.tofNSigmaKa(), track1.pt()); + } + */ + auto track1ID = track1.globalIndex(); + for (auto track2 : negThisColl) { + if (!selectionTrack(track2)) + continue; + + if (!selectionPID(track2, 1)) + continue; + + if (!(itsResponse.nSigmaITS(track2) > -3.0 && itsResponse.nSigmaITS(track2) < 3.0)) + continue; + + auto track2ID = track2.globalIndex(); + if (track2ID == track1ID) + continue; + + if (!selectionPair(track1, track2)) + continue; + + DauVec1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + DauVec2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + HQMesonMother = DauVec1 + DauVec2; + if (!(HQMesonMother.M() > cfgMinPhiMass && HQMesonMother.M() < cfgMaxPhiMass)) + continue; + + numberPhi++; + ROOT::Math::PtEtaPhiMVector temp1(track1.pt(), track1.eta(), track1.phi(), massKa); + ROOT::Math::PtEtaPhiMVector temp2(track2.pt(), track2.eta(), track2.phi(), massKa); + ROOT::Math::PtEtaPhiMVector temp3(HQMesonMother.pt(), HQMesonMother.eta(), HQMesonMother.phi(), HQMesonMother.M()); + + hqresonanced1.push_back(temp1); + hqresonanced2.push_back(temp2); + hqresonance.push_back(temp3); + + HQId.push_back(333); + + HQd1Index.push_back(track1.globalIndex()); + HQd2Index.push_back(track2.globalIndex()); + + HQd1Charge.push_back(track1.sign()); + HQd2Charge.push_back(track2.sign()); + + HQd1TPC.push_back(track1.tpcNSigmaKa()); + HQd2TPC.push_back(track2.tpcNSigmaKa()); + + auto d1TOFHit = -1; + auto d2TOFHit = -1; + auto d1TOF = -999.0; + auto d2TOF = -999.0; + + if (track1.hasTOF()) { + d1TOFHit = 1; + d1TOF = track1.tofNSigmaKa(); + } + if (track2.hasTOF()) { + d2TOFHit = 1; + d2TOF = track2.tofNSigmaKa(); + } + + HQd1TOFHit.push_back(d1TOFHit); + HQd2TOFHit.push_back(d2TOFHit); + + HQd1TOF.push_back(d1TOF); + HQd2TOF.push_back(d2TOF); + } + } + for (auto& v0 : V0s) { + auto postrack_v0 = v0.template posTrack_as(); + auto negtrack_v0 = v0.template negTrack_as(); + + int LambdaTag = 0; + int aLambdaTag = 0; + + if (selectionV0Daughter(postrack_v0, 0) && selectionV0Daughter(negtrack_v0, 1)) + LambdaTag = 1; + + if (selectionV0Daughter(negtrack_v0, 0) && selectionV0Daughter(postrack_v0, 1)) + aLambdaTag = 1; + + if (LambdaTag == aLambdaTag) + continue; + + if (!selectionV0(collision, v0)) + continue; + + if (LambdaTag) { + if (v0.mLambda() < cfgMinLambdaMass || v0.mLambda() > cfgMaxLambdaMass) { + continue; + } + DauVec1 = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), massPr); + DauVec2 = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), massPi); + + HQId.push_back(3122); + } else if (aLambdaTag) { + if (v0.mAntiLambda() < cfgMinLambdaMass || v0.mAntiLambda() > cfgMaxLambdaMass) { + continue; + } + DauVec1 = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), massPi); + DauVec2 = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), massPr); + HQId.push_back(-3122); + } + numberLambda++; + + HQMesonMother = DauVec1 + DauVec2; + + ROOT::Math::PtEtaPhiMVector temp1(DauVec1.Pt(), DauVec1.Eta(), DauVec1.Phi(), DauVec1.M()); + ROOT::Math::PtEtaPhiMVector temp2(DauVec2.Pt(), DauVec2.Eta(), DauVec2.Phi(), DauVec2.M()); + ROOT::Math::PtEtaPhiMVector temp3(HQMesonMother.Pt(), HQMesonMother.Eta(), HQMesonMother.Phi(), HQMesonMother.M()); + + hqresonanced1.push_back(temp1); + hqresonanced2.push_back(temp2); + hqresonance.push_back(temp3); + + HQd1Index.push_back(postrack_v0.globalIndex()); + HQd2Index.push_back(negtrack_v0.globalIndex()); + + HQd1Charge.push_back(postrack_v0.sign()); + HQd2Charge.push_back(negtrack_v0.sign()); + + if (LambdaTag) { + HQd1TPC.push_back(postrack_v0.tpcNSigmaPr()); + HQd2TPC.push_back(negtrack_v0.tpcNSigmaPi()); + } else if (aLambdaTag) { + HQd1TPC.push_back(postrack_v0.tpcNSigmaPi()); + HQd2TPC.push_back(negtrack_v0.tpcNSigmaPr()); + } + + auto d1TOFHit = -1; + auto d2TOFHit = -1; + auto d1TOF = -999.0; + auto d2TOF = -999.0; + + if (postrack_v0.hasTOF()) { + d1TOFHit = 1; + d1TOF = postrack_v0.tofNSigmaPr(); + } + if (negtrack_v0.hasTOF()) { + d2TOFHit = 1; + d2TOF = negtrack_v0.tofNSigmaPr(); + } ////// TOF with PV assumption to be corrected + HQd1TOFHit.push_back(d1TOFHit); + HQd2TOFHit.push_back(d2TOFHit); + + HQd1TOF.push_back(d1TOF); + HQd2TOF.push_back(d2TOF); + } // select collision + if (numberPhi < 2 || numberLambda < 1) + return; + + keepEventDoubleHQ = true; + + if (keepEventDoubleHQ && numberPhi > 1 && numberLambda > 0 && (hqresonance.size() == hqresonanced1.size()) && (hqresonance.size() == hqresonanced2.size())) { + histos.fill(HIST("hEventstat"), 2.5); + /////////// Fill collision table/////////////// + redHQEvents(bc.globalBC(), currentRunNumber, bc.timestamp(), collision.posZ(), collision.numContrib(), centrality, numberPhi, numberLambda); + auto indexEvent = redHQEvents.lastIndex(); + //// Fill track table for HQ////////////////// + for (auto if1 = hqresonance.begin(); if1 != hqresonance.end(); ++if1) { + auto i5 = std::distance(hqresonance.begin(), if1); + HQVectorDummy = hqresonance.at(i5); + HQd1dummy = hqresonanced1.at(i5); + HQd2dummy = hqresonanced2.at(i5); + hqTrack(indexEvent, HQId.at(i5), HQVectorDummy.Px(), HQVectorDummy.Py(), HQVectorDummy.Pz(), + HQd1dummy.Px(), HQd1dummy.Py(), HQd1dummy.Pz(), HQd2dummy.Px(), HQd2dummy.Py(), HQd2dummy.Pz(), + HQVectorDummy.M(), + HQd1Index.at(i5), HQd2Index.at(i5), + HQd1Charge.at(i5), HQd2Charge.at(i5), HQd1TPC.at(i5), HQd2TPC.at(i5), + HQd1TOFHit.at(i5), HQd2TOFHit.at(i5), HQd1TOF.at(i5), HQd2TOF.at(i5)); + } + } + } // process + PROCESS_SWITCH(heptaquarktable, processHQReducedTable, "Process table creation for double hq", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfg) +{ + return WorkflowSpec{adaptAnalysisTask(cfg)}; +} diff --git a/PWGLF/TableProducer/Resonances/LFResonanceInitializer.cxx b/PWGLF/TableProducer/Resonances/LFResonanceInitializer.cxx deleted file mode 100644 index c7c0c15a008..00000000000 --- a/PWGLF/TableProducer/Resonances/LFResonanceInitializer.cxx +++ /dev/null @@ -1,1330 +0,0 @@ -// 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 LFResonanceInitializer.cxx -/// \brief Initializes variables for the resonance candidate producers -/// -/// -/// \author Bong-Hwi Lim - -#include "Common/DataModel/PIDResponse.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/Centrality.h" -// #include "Common/DataModel/Multiplicity.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/Qvectors.h" -#include "Common/Core/EventPlaneHelper.h" -#include "Framework/ASoAHelpers.h" -#include "DetectorsBase/Propagator.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "PWGLF/DataModel/LFResonanceTables.h" -#include "PWGLF/Utils/collisionCuts.h" -#include "ReconstructionDataFormats/Track.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::soa; - -/// Initializer for the resonance candidate producers -struct reso2initializer { - enum { - kECbegin = 0, - kINEL = 1, - kINEL10, - kINELg0, - kINELg010, - kTrig, - kINELg0Trig, - kINELg010Trig, - kECend, - }; - SliceCache cache; - float cXiMass; - int mRunNumber; - int multEstimator; - float d_bz; - Service ccdb; - Service pdg; - - Produces resoCollisions; - Produces reso2trks; - Produces reso2v0s; - Produces reso2cascades; - Produces reso2mctracks; - Produces reso2mcparents; - Produces reso2mcv0s; - Produces reso2mccascades; - - // CCDB options - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - - Configurable cfgFatalWhenNull{"cfgFatalWhenNull", true, "Fatal when null on ccdb access"}; - - // Configurables - Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; - Configurable ConfFillQA{"ConfFillQA", false, "Fill QA histograms"}; - Configurable ConfBypassCCDB{"ConfBypassCCDB", true, "Bypass loading CCDB part to save CPU time and memory"}; // will be affected to b_z value. - - // Track filter from tpcSkimsTableCreator - Configurable trackSelection{"trackSelection", 0, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; - Configurable trackSphDef{"trackSphDef", 0, "Spherocity Definition: |pT| = 1 -> 0, otherwise -> 1"}; - Configurable trackSphMin{"trackSphMin", 10, "Number of tracks for Spherocity Calculation"}; - - // EventCorrection for MC - ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 0.01, 0.1, 1.0, 5.0, 10., 15., 20., 30., 40., 50., 70., 100.0, 105.}, "Binning of the centrality axis"}; - ConfigurableAxis CfgVtxBins{"CfgVtxBins", {VARIABLE_WIDTH, -20, -15, -10, -7, -5, -3, -2, -1, 0, 1, 2, 3, 5, 7, 10, 15, 20}, "Mixing bins - z-vertex"}; - - /// Event cuts - o2::analysis::CollisonCuts colCuts; - Configurable ConfEvtZvtx{"ConfEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; - Configurable ConfEvtTriggerCheck{"ConfEvtTriggerCheck", false, "Evt sel: check for trigger"}; - Configurable ConfEvtTriggerSel{"ConfEvtTriggerSel", 8, "Evt sel: trigger"}; - Configurable ConfEvtOfflineCheck{"ConfEvtOfflineCheck", true, "Evt sel: check for offline selection"}; - Configurable ConfEvtTFBorderCut{"ConfEvtTFBorderCut", false, "Evt sel: apply TF border cut"}; - Configurable ConfEvtITSTPCmatching{"ConfEvtITSTPCmatching", false, "Evt sel: apply ITS-TPC matching"}; - Configurable ConfEvtZvertexTimedifference{"ConfEvtZvertexTimedifference", false, "Evt sel: apply Z-vertex time difference"}; - Configurable ConfEvtPileupRejection{"ConfEvtPileupRejection", false, "Evt sel: apply pileup rejection"}; - Configurable ConfEvtNoITSROBorderCut{"ConfEvtNoITSROBorderCut", false, "Evt sel: apply NoITSRO border cut"}; - - Configurable cfgMultName{"cfgMultName", "FT0M", "The name of multiplicity estimator"}; - - // Qvector configuration - Configurable ConfBypassQvec{"ConfBypassQvec", true, "Bypass for qvector task"}; - Configurable cfgEvtPl{"cfgEvtPl", 40500, "Configuration of three subsystems for the event plane and its resolution, 10000*RefA + 100*RefB + S, where FT0C:0, FT0A:1, FT0M:2, FV0A:3, BPos:5, BNeg:6"}; - - // Pre-selection cuts - Configurable cfgCutEta{"cfgCutEta", 0.8f, "Eta range for tracks"}; - Configurable pidnSigmaPreSelectionCut{"pidnSigmaPreSelectionCut", 5.0f, "TPC and TOF PID cut (loose, improve performance)"}; - Configurable mincrossedrows{"mincrossedrows", 70, "min crossed rows"}; - - /// DCA Selections for V0 - // DCAr to PV - Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 2.0, "Track DCAr cut to PV Maximum"}; - Configurable cMinV0PosDCArToPVcut{"cMinV0PosDCArToPVcut", 0.05f, "V0 Positive Track DCAr cut to PV Minimum"}; // Pre-selection - Configurable cMinV0NegDCArToPVcut{"cMinV0NegDCArToPVcut", 0.05f, "V0 Negative Track DCAr cut to PV Minimum"}; // Pre-selection - // DCAz to PV - Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; - Configurable cMinDCAzToPVcut{"cMinDCAzToPVcut", 0.0, "Track DCAz cut to PV Minimum"}; - - Configurable cMinV0Radius{"cMinV0Radius", 0.0, "Minimum V0 radius from PV"}; - Configurable cMaxV0Radius{"cMaxV0Radius", 200.0, "Maximum V0 radius from PV"}; - Configurable cMinV0CosPA{"cMinV0CosPA", 0.995, "Minimum V0 CosPA to PV"}; - - /// DCA Selections for Cascades - Configurable mincrossedrows_cascbach{"mincrossedrows_cascbach", 70, "min crossed rows for bachelor track from cascade"}; - Configurable cMinCascBachDCArToPVcut{"cMinCascBachDCArToPVcut", 0.05f, "Cascade Bachelor Track DCAr cut to PV Minimum"}; // Pre-selection - Configurable cMaxCascBachDCArToPVcut{"cMaxCascBachDCArToPVcut", 999.0f, "Cascade Bachelor Track DCAr cut to PV Maximum"}; // Pre-selection - Configurable cMaxCascDCAV0Daughters{"cMaxCascDCAV0Daughters", 1.6, "Cascade DCA between V0 daughters Maximum"}; - Configurable cMaxCascDCACascDaughters{"cMaxCascDCACascDaughters", 1.6, "Cascade DCA between Casc daughters Maximum"}; - Configurable cMinCascCosPA{"cMinCascCosPA", 0.97, "Minimum Cascade CosPA to PV"}; - Configurable cMinCascV0CosPA{"cMinCascV0CosPA", 0.97, "Minimum Cascade V0 CosPA to PV"}; - Configurable cMaxCascV0Radius{"cMaxCascV0Radius", 200.0, "Maximum Cascade V0 radius from PV"}; - Configurable cMinCascV0Radius{"cMinCascV0Radius", 0.0, "Minimum Cascade V0 radius from PV"}; - Configurable cMaxCascRadius{"cMaxCascRadius", 200.0, "Maximum Cascade radius from PV"}; - Configurable cMinCascRadius{"cMinCascRadius", 0.0, "Minimum Cascade radius from PV"}; - Configurable cCascMassResol{"cCascMassResol", 999, "Cascade mass resolution"}; - - HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - // Pre-filters for efficient process - // Filter tofPIDFilter = aod::track::tofExpMom < 0.f || ((aod::track::tofExpMom > 0.f) && ((nabs(aod::pidtof::tofNSigmaPi) < pidnSigmaPreSelectionCut) || (nabs(aod::pidtof::tofNSigmaKa) < pidnSigmaPreSelectionCut) || (nabs(aod::pidtof::tofNSigmaPr) < pidnSigmaPreSelectionCut))); // TOF - Filter trackFilter = (trackSelection.node() == 0) || // from tpcSkimsTableCreator - ((trackSelection.node() == 1) && requireGlobalTrackInFilter()) || - ((trackSelection.node() == 2) && requireGlobalTrackWoPtEtaInFilter()) || - ((trackSelection.node() == 3) && requireGlobalTrackWoDCAInFilter()) || - ((trackSelection.node() == 4) && requireQualityTracksInFilter()) || - ((trackSelection.node() == 5) && requireTrackCutInFilter(TrackSelectionFlags::kInAcceptanceTracks)); - Filter tpcPIDFilter = nabs(aod::pidtpc::tpcNSigmaPi) < pidnSigmaPreSelectionCut || nabs(aod::pidtpc::tpcNSigmaKa) < pidnSigmaPreSelectionCut || nabs(aod::pidtpc::tpcNSigmaPr) < pidnSigmaPreSelectionCut; // TPC - Filter trackEtaFilter = nabs(aod::track::eta) < cfgCutEta; // Eta cut - Filter collisionFilter = nabs(aod::collision::posZ) < ConfEvtZvtx; - - EventPlaneHelper helperEP; - - int EvtPlRefAId = static_cast(cfgEvtPl / 10000); - int EvtPlRefBId = static_cast((cfgEvtPl - EvtPlRefAId * 10000) / 100); - int EvtPlDetId = cfgEvtPl - EvtPlRefAId * 10000 - EvtPlRefBId * 100; - - // MC Resonance parent filter - Partition selectedMCParticles = (nabs(aod::mcparticle::pdgCode) == 313) // K* - || (nabs(aod::mcparticle::pdgCode) == 323) // K*pm - || (nabs(aod::mcparticle::pdgCode) == 333) // phi - || (nabs(aod::mcparticle::pdgCode) == 9010221) // f_0(980) - || (nabs(aod::mcparticle::pdgCode) == 10221) // f_0(1370) - || (nabs(aod::mcparticle::pdgCode) == 9030221) // f_0(1500) - || (nabs(aod::mcparticle::pdgCode) == 10331) // f_0(1710) - || (nabs(aod::mcparticle::pdgCode) == 20223) // f_1(1285) - || (nabs(aod::mcparticle::pdgCode) == 20333) // f_1(1420) - || (nabs(aod::mcparticle::pdgCode) == 335) // f_1(1525) - || (nabs(aod::mcparticle::pdgCode) == 113) // rho(770) - || (nabs(aod::mcparticle::pdgCode) == 213) // rho(770)pm - || (nabs(aod::mcparticle::pdgCode) == 3224) // Sigma(1385)+ - || (nabs(aod::mcparticle::pdgCode) == 102134) // Lambda(1520) - || (nabs(aod::mcparticle::pdgCode) == 3324) // Xi(1530)0 - || (nabs(aod::mcparticle::pdgCode) == 10323) // K1(1270)+ - || (nabs(aod::mcparticle::pdgCode) == 123314) // Xi(1820)0 - || (nabs(aod::mcparticle::pdgCode) == 123324); // Xi(1820)-0 - - using ResoEvents = soa::Join; - using ResoRun2Events = soa::Join; - using ResoEventsMC = soa::Join; - using ResoRun2EventsMC = soa::Join; - using ResoTracks = aod::Reso2TracksPIDExt; - using ResoTracksMC = soa::Join; - using ResoV0s = aod::V0Datas; - using ResoV0sMC = soa::Join; - using ResoCascades = aod::CascDatas; - using ResoCascadesMC = soa::Join; - - template - bool IsTrackSelected(CollisionType const&, TrackType const& track) - { - // Track selection - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodTrackIndices"), 0.5); - // MC case can be handled here - if constexpr (isMC) { - // MC check - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodMCTrackIndices"), 0.5); - } - // DCAxy cut - if (fabs(track.dcaXY()) > cMaxDCArToPVcut) - return false; - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodTrackIndices"), 1.5); - // DCAz cut - if (fabs(track.dcaZ()) > cMaxDCAzToPVcut || fabs(track.dcaZ()) < cMinDCAzToPVcut) - return false; - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodTrackIndices"), 2.5); - - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodTrackIndices"), 7.5); - return true; - } - - template - bool IsV0Selected(CollisionType const&, V0Type const& v0, TrackType const&) - { - // V0 selection - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodV0Indices"), 0.5); - - auto postrack = v0.template posTrack_as(); - auto negtrack = v0.template negTrack_as(); - - if (postrack.tpcNClsCrossedRows() < mincrossedrows) - return false; - if (negtrack.tpcNClsCrossedRows() < mincrossedrows) - return false; - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodV0Indices"), 1.5); - - if (fabs(postrack.dcaXY()) < cMinV0PosDCArToPVcut) - return false; - if (fabs(negtrack.dcaXY()) < cMinV0NegDCArToPVcut) - return false; - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodV0Indices"), 2.5); - - if ((v0.v0radius() > cMaxV0Radius) || (v0.v0radius() < cMinV0Radius)) - return false; - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodV0Indices"), 3.5); - if (v0.v0cosPA() < cMinV0CosPA) - return false; - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodV0Indices"), 4.5); - - // MC case can be handled here - if constexpr (isMC) { - // MC check - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodMCV0Indices"), 0.5); - } - return true; - } - - template - bool IsCascSelected(CollisionType const& collision, CascType const& casc, TrackType const&) - { - // V0 selection - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodCascIndices"), 0.5); - - auto trackBach = casc.template bachelor_as(); - // auto trackPos = casc.template posTrack_as(); - // auto trackNeg = casc.template negTrack_as(); - - // track cuts - if (trackBach.tpcNClsCrossedRows() < mincrossedrows_cascbach) - return false; - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodCascIndices"), 1.5); - - if (fabs(trackBach.dcaXY()) < cMinCascBachDCArToPVcut) - return false; - if (fabs(trackBach.dcaXY()) > cMaxCascBachDCArToPVcut) - return false; - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodCascIndices"), 2.5); - - // DCA daugthers - if (casc.dcaV0daughters() > cMaxCascDCAV0Daughters) - return false; - if (casc.dcacascdaughters() > cMaxCascDCACascDaughters) - return false; - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodCascIndices"), 3.5); - - // CPA cuts - if (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cMinCascCosPA) - return false; - if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cMinCascV0CosPA) - return false; - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodCascIndices"), 4.5); - - // V0 radius - auto v0radius = casc.v0radius(); - if ((v0radius > cMaxCascV0Radius) || (v0radius < cMinCascV0Radius)) - return false; - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodCascIndices"), 5.5); - - // Casc radius - auto cascradius = casc.cascradius(); - if ((cascradius > cMaxCascRadius) || (cascradius < cMinCascRadius)) - return false; - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodCascIndices"), 6.5); - - // Casc mass - auto cascMass = casc.mXi(); - if (abs(cascMass - cXiMass) > cCascMassResol) - return false; - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodCascIndices"), 7.5); - - // MC case can be handled here - if constexpr (isMC) { - // MC check - if (ConfFillQA) - qaRegistry.fill(HIST("hGoodMCCascIndices"), 0.5); - } - return true; - } - - // Centralicity estimator selection - template - float CentEst(ResoColl ResoEvents) - { - float returnValue = -999.0; - switch (multEstimator) { - case 0: - returnValue = ResoEvents.centFT0M(); - break; - case 1: - returnValue = ResoEvents.centFT0C(); - break; - case 2: - returnValue = ResoEvents.centFT0A(); - break; - case 99: - returnValue = ResoEvents.centFV0A(); - break; - default: - returnValue = ResoEvents.centFT0M(); - break; - } - return returnValue; - } - - /// Compute the spherocity of an event - /// Important here is that the filter on tracks does not interfere here! - /// In Run 2 we used here global tracks within |eta| < 0.8 - /// \tparam T type of the tracks - /// \param tracks All tracks - /// \return value of the spherocity of the event - template - float ComputeSpherocity(T const& tracks, int nTracksMin, int spdef) - { - // if number of tracks is not enough for spherocity estimation. - int ntrks = tracks.size(); - if (ntrks < nTracksMin) - return -99.; - - // start computing spherocity - - float ptSum = 0.; - for (auto const& track : tracks) { - if (ConfFillQA) { - qaRegistry.fill(HIST("Phi"), track.phi()); - } - if (spdef == 0) { - ptSum += 1.; - } else { - ptSum += track.pt(); - } - } - - float tempSph = 1.; - for (int i = 0; i < 360 / 0.1; ++i) { - float sum = 0., pt = 0.; - float phiparm = (TMath::Pi() * i * 0.1) / 180.; - float nx = TMath::Cos(phiparm); - float ny = TMath::Sin(phiparm); - for (auto const& trk : tracks) { - pt = trk.pt(); - if (spdef == 0) { - pt = 1.; - } - float phi = trk.phi(); - float px = pt * TMath::Cos(phi); - float py = pt * TMath::Sin(phi); - // sum += pt * abs(sin(phiparm - phi)); - sum += TMath::Abs(px * ny - py * nx); - } - float sph = TMath::Power((sum / ptSum), 2); - if (sph < tempSph) - tempSph = sph; - } - - return TMath::Power(TMath::Pi() / 2., 2) * tempSph; - } - - template - float GetEvtPl(ResoColl ResoEvents) - { - float returnValue = -999.0; - if (ResoEvents.qvecAmp()[EvtPlDetId] > 1e-8) - returnValue = helperEP.GetEventPlane(ResoEvents.qvecRe()[EvtPlDetId * 4 + 3], ResoEvents.qvecIm()[EvtPlDetId * 4 + 3], 2); - return returnValue; - } - - template - float GetEvtPlRes(ResoColl ResoEvents, int a, int b) - { - float returnValue = -999.0; - if (ResoEvents.qvecAmp()[a] < 1e-8 || ResoEvents.qvecAmp()[b] < 1e-8) - return returnValue; - returnValue = helperEP.GetResolution(helperEP.GetEventPlane(ResoEvents.qvecRe()[a * 4 + 3], ResoEvents.qvecIm()[a * 4 + 3], 2), helperEP.GetEventPlane(ResoEvents.qvecRe()[b * 4 + 3], ResoEvents.qvecIm()[b * 4 + 3], 2), 2); - return returnValue; - } - - // Filter for all tracks - template - void fillTracks(CollisionType const& collision, TrackType const& tracks) - { - // Loop over tracks - for (auto& track : tracks) { - if (!IsTrackSelected(collision, track)) - continue; - reso2trks(resoCollisions.lastIndex(), - track.pt(), - track.px(), - track.py(), - track.pz(), - track.eta(), - track.phi(), - track.sign(), - (uint8_t)track.tpcNClsCrossedRows(), - (uint8_t)track.tpcNClsFound(), - (uint8_t)track.itsNCls(), - track.dcaXY(), - track.dcaZ(), - track.x(), - track.alpha(), - track.hasTOF(), - track.tpcNSigmaPi(), - track.tpcNSigmaKa(), - track.tpcNSigmaPr(), - track.tofNSigmaPi(), - track.tofNSigmaKa(), - track.tofNSigmaPr(), - track.tpcSignal(), - track.passedITSRefit(), - track.passedTPCRefit(), - track.isGlobalTrackWoDCA(), - track.isGlobalTrack(), - track.isPrimaryTrack(), - track.isPVContributor(), - track.tpcCrossedRowsOverFindableCls(), - track.itsChi2NCl(), - track.tpcChi2NCl()); - if constexpr (isMC) { - fillMCTrack(track); - } - } - } - - // Filter for all V0s - template - void fillV0s(CollisionType const& collision, V0Type const& v0s, TrackType const& tracks) - { - int childIDs[2] = {0, 0}; // these IDs are necessary to keep track of the children - for (auto& v0 : v0s) { - if (!IsV0Selected(collision, v0, tracks)) - continue; - childIDs[0] = v0.posTrackId(); - childIDs[1] = v0.negTrackId(); - reso2v0s(resoCollisions.lastIndex(), - v0.pt(), - v0.px(), - v0.py(), - v0.pz(), - v0.eta(), - v0.phi(), - childIDs, - v0.v0cosPA(), - v0.dcaV0daughters(), - v0.dcapostopv(), - v0.dcanegtopv(), - v0.dcav0topv(), - v0.mLambda(), - v0.mAntiLambda(), - v0.mK0Short(), - v0.v0radius(), v0.x(), v0.y(), v0.z()); - if constexpr (isMC) { - fillMCV0(v0); - } - } - } - - // Filter for all Cascades - template - void fillCascades(CollisionType const& collision, CascType const& cascades, TrackType const& tracks) - { - int childIDs[3] = {0, 0, 0}; // these IDs are necessary to keep track of the children - for (auto& casc : cascades) { - if (!IsCascSelected(collision, casc, tracks)) - continue; - childIDs[0] = casc.posTrackId(); - childIDs[1] = casc.negTrackId(); - childIDs[2] = casc.bachelorId(); - reso2cascades(resoCollisions.lastIndex(), - casc.pt(), - casc.px(), - casc.py(), - casc.pz(), - casc.eta(), - casc.phi(), - childIDs, - casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()), - casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()), - casc.dcaV0daughters(), - casc.dcacascdaughters(), - casc.dcapostopv(), - casc.dcanegtopv(), - casc.dcabachtopv(), - casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()), - casc.dcaXYCascToPV(), - casc.dcaZCascToPV(), - casc.sign(), - casc.mXi(), - casc.v0radius(), casc.cascradius(), casc.x(), casc.y(), casc.z()); - if constexpr (isMC) { - fillMCCascade(casc); - } - } - } - - template - void fillMCTrack(TrackType const& track) - { - // ------ Temporal lambda function to prevent error in build - auto getMothersIndeces = [&](auto const& theMcParticle) { - std::vector lMothersIndeces{}; - for (auto& lMother : theMcParticle.template mothers_as()) { - LOGF(debug, " mother index lMother: %d", lMother.globalIndex()); - lMothersIndeces.push_back(lMother.globalIndex()); - } - return lMothersIndeces; - }; - auto getMothersPDGCodes = [&](auto const& theMcParticle) { - std::vector lMothersPDGs{}; - for (auto& lMother : theMcParticle.template mothers_as()) { - LOGF(debug, " mother pdgcode lMother: %d", lMother.pdgCode()); - lMothersPDGs.push_back(lMother.pdgCode()); - } - return lMothersPDGs; - }; - auto getSiblingsIndeces = [&](auto const& theMcParticle) { - std::vector lSiblingsIndeces{}; - for (auto& lMother : theMcParticle.template mothers_as()) { - LOGF(debug, " mother index lMother: %d", lMother.globalIndex()); - for (auto& lDaughter : lMother.template daughters_as()) { - LOGF(debug, " daughter index lDaughter: %d", lDaughter.globalIndex()); - if (lDaughter.globalIndex() != 0 && lDaughter.globalIndex() != theMcParticle.globalIndex()) { - lSiblingsIndeces.push_back(lDaughter.globalIndex()); - } - } - } - return lSiblingsIndeces; - }; - // ------ - std::vector mothers = {-1, -1}; - std::vector motherPDGs = {-1, -1}; - int siblings[2] = {0, 0}; - std::vector siblings_temp = {-1, -1}; - if (track.has_mcParticle()) { - // - // Get the MC particle - const auto& particle = track.mcParticle(); - if (particle.has_mothers()) { - mothers = getMothersIndeces(particle); - motherPDGs = getMothersPDGCodes(particle); - siblings_temp = getSiblingsIndeces(particle); - } - while (mothers.size() > 2) { - mothers.pop_back(); - motherPDGs.pop_back(); - } - if (siblings_temp.size() > 0) - siblings[0] = siblings_temp[0]; - if (siblings_temp.size() > 1) - siblings[1] = siblings_temp[1]; - reso2mctracks(particle.pdgCode(), - mothers[0], - motherPDGs[0], - siblings, - particle.isPhysicalPrimary(), - particle.producedByGenerator()); - } else { - // No MC particle associated - reso2mctracks(0, - mothers[0], - motherPDGs[0], - siblings, - 0, - 0); - } - } - // Additonoal information for MC V0s - template - void fillMCV0(V0Type const& v0) - { - // ------ Temporal lambda function to prevent error in build - auto getMothersIndeces = [&](auto const& theMcParticle) { - std::vector lMothersIndeces{}; - for (auto& lMother : theMcParticle.template mothers_as()) { - LOGF(debug, " mother index lMother: %d", lMother.globalIndex()); - lMothersIndeces.push_back(lMother.globalIndex()); - } - return lMothersIndeces; - }; - auto getMothersPDGCodes = [&](auto const& theMcParticle) { - std::vector lMothersPDGs{}; - for (auto& lMother : theMcParticle.template mothers_as()) { - LOGF(debug, " mother pdgcode lMother: %d", lMother.pdgCode()); - lMothersPDGs.push_back(lMother.pdgCode()); - } - return lMothersPDGs; - }; - auto getDaughtersIndeces = [&](auto const& theMcParticle) { - std::vector lDaughtersIndeces{}; - for (auto& lDaughter : theMcParticle.template daughters_as()) { - LOGF(debug, " daughter index lDaughter: %d", lDaughter.globalIndex()); - if (lDaughter.globalIndex() != 0) { - lDaughtersIndeces.push_back(lDaughter.globalIndex()); - } - } - return lDaughtersIndeces; - }; - auto getDaughtersPDGCodes = [&](auto const& theMcParticle) { - std::vector lDaughtersPDGs{}; - for (auto& lDaughter : theMcParticle.template daughters_as()) { - LOGF(debug, " daughter pdgcode lDaughter: %d", lDaughter.pdgCode()); - if (lDaughter.globalIndex() != 0) { - lDaughtersPDGs.push_back(lDaughter.pdgCode()); - } - } - return lDaughtersPDGs; - }; - // ------ - std::vector mothers = {-1, -1}; - std::vector motherPDGs = {-1, -1}; - std::vector daughters = {-1, -1}; - std::vector daughterPDGs = {-1, -1}; - if (v0.has_mcParticle()) { - auto v0mc = v0.mcParticle(); - if (v0mc.has_mothers()) { - mothers = getMothersIndeces(v0mc); - motherPDGs = getMothersPDGCodes(v0mc); - } - while (mothers.size() > 2) { - mothers.pop_back(); - motherPDGs.pop_back(); - } - if (v0mc.has_daughters()) { - daughters = getDaughtersIndeces(v0mc); - daughterPDGs = getDaughtersPDGCodes(v0mc); - } - while (daughters.size() > 2) { - LOGF(info, "daughters.size() is larger than 2"); - daughters.pop_back(); - daughterPDGs.pop_back(); - } - reso2mcv0s(v0mc.pdgCode(), - mothers[0], - motherPDGs[0], - daughters[0], - daughters[1], - daughterPDGs[0], - daughterPDGs[1], - v0mc.isPhysicalPrimary(), - v0mc.producedByGenerator()); - } else { - reso2mcv0s(0, - mothers[0], - motherPDGs[0], - daughters[0], - daughters[1], - daughterPDGs[0], - daughterPDGs[1], - 0, - 0); - } - } - // Additonoal information for MC Cascades - template - void fillMCCascade(CascType const& casc) - { - // ------ Temporal lambda function to prevent error in build - auto getMothersIndeces = [&](auto const& theMcParticle) { - std::vector lMothersIndeces{}; - for (auto& lMother : theMcParticle.template mothers_as()) { - LOGF(debug, " mother index lMother: %d", lMother.globalIndex()); - lMothersIndeces.push_back(lMother.globalIndex()); - } - return lMothersIndeces; - }; - auto getMothersPDGCodes = [&](auto const& theMcParticle) { - std::vector lMothersPDGs{}; - for (auto& lMother : theMcParticle.template mothers_as()) { - LOGF(debug, " mother pdgcode lMother: %d", lMother.pdgCode()); - lMothersPDGs.push_back(lMother.pdgCode()); - } - return lMothersPDGs; - }; - auto getDaughtersIndeces = [&](auto const& theMcParticle) { - std::vector lDaughtersIndeces{}; - for (auto& lDaughter : theMcParticle.template daughters_as()) { - LOGF(debug, " daughter index lDaughter: %d", lDaughter.globalIndex()); - if (lDaughter.globalIndex() != 0) { - lDaughtersIndeces.push_back(lDaughter.globalIndex()); - } - } - return lDaughtersIndeces; - }; - auto getDaughtersPDGCodes = [&](auto const& theMcParticle) { - std::vector lDaughtersPDGs{}; - for (auto& lDaughter : theMcParticle.template daughters_as()) { - LOGF(debug, " daughter pdgcode lDaughter: %d", lDaughter.pdgCode()); - if (lDaughter.globalIndex() != 0) { - lDaughtersPDGs.push_back(lDaughter.pdgCode()); - } - } - return lDaughtersPDGs; - }; - // ------ - std::vector mothers = {-1, -1}; - std::vector motherPDGs = {-1, -1}; - std::vector daughters = {-1, -1}; - std::vector daughterPDGs = {-1, -1}; - if (casc.has_mcParticle()) { - auto cascmc = casc.mcParticle(); - if (cascmc.has_mothers()) { - mothers = getMothersIndeces(cascmc); - motherPDGs = getMothersPDGCodes(cascmc); - } - while (mothers.size() > 2) { - mothers.pop_back(); - motherPDGs.pop_back(); - } - if (cascmc.has_daughters()) { - daughters = getDaughtersIndeces(cascmc); - daughterPDGs = getDaughtersPDGCodes(cascmc); - } - while (daughters.size() > 2) { - LOGF(info, "daughters.size() is larger than 2"); - daughters.pop_back(); - daughterPDGs.pop_back(); - } - reso2mccascades(cascmc.pdgCode(), - mothers[0], - motherPDGs[0], - daughters[0], - daughters[1], - daughterPDGs[0], - daughterPDGs[1], - cascmc.isPhysicalPrimary(), - cascmc.producedByGenerator()); - } else { - reso2mccascades(0, - mothers[0], - motherPDGs[0], - daughters[0], - daughters[1], - daughterPDGs[0], - daughterPDGs[1], - 0, - 0); - } - } - // Additonoal information for MC Cascades - template - void fillMCParticles(SelectedMCPartType const& mcParts, TotalMCParts const& mcParticles) - { - for (auto& mcPart : mcParts) { - std::vector daughterPDGs; - if (mcPart.has_daughters()) { - auto daughter01 = mcParticles.rawIteratorAt(mcPart.daughtersIds()[0] - mcParticles.offset()); - auto daughter02 = mcParticles.rawIteratorAt(mcPart.daughtersIds()[1] - mcParticles.offset()); - daughterPDGs = {daughter01.pdgCode(), daughter02.pdgCode()}; - } else { - daughterPDGs = {-1, -1}; - } - reso2mcparents(resoCollisions.lastIndex(), - mcPart.globalIndex(), - mcPart.pdgCode(), - daughterPDGs[0], daughterPDGs[1], - mcPart.isPhysicalPrimary(), - mcPart.producedByGenerator(), - mcPart.pt(), - mcPart.px(), - mcPart.py(), - mcPart.pz(), - mcPart.eta(), - mcPart.phi(), - mcPart.y()); - daughterPDGs.clear(); - } - } - - void init(InitContext&) - { - cXiMass = pdg->GetParticle(3312)->Mass(); - mRunNumber = 0; - d_bz = 0; - // Multiplicity estimator selection (0: FT0M, 1: FT0C, 2: FT0A, 99: FV0A) - if (cfgMultName.value == "FT0M") { - multEstimator = 0; - } else if (cfgMultName.value == "FT0C") { - multEstimator = 1; - } else if (cfgMultName.value == "FT0A") { - multEstimator = 2; - } else if (cfgMultName.value == "FV0A") { - multEstimator = 99; - } else { - multEstimator = 0; - } - - // Check if we are running multiple processes at the same time - int nProcesses = doprocessTrackDataRun2 + doprocessTrackV0DataRun2 + doprocessTrackV0CascDataRun2 + - doprocessMCGenCountRun2 + doprocessTrackMCRun2 + doprocessTrackV0MCRun2 + - doprocessTrackV0CascMCRun2; - - if (nProcesses > 1) { - LOG(fatal) << "Multiple processes are not supported at the same time"; - } - - // Case selector based on the process. - if (doprocessTrackDataRun2 || doprocessTrackV0DataRun2 || doprocessTrackV0CascDataRun2 || doprocessMCGenCountRun2 || doprocessTrackMCRun2 || doprocessTrackV0MCRun2 || doprocessTrackV0CascMCRun2) { - colCuts.setCuts(ConfEvtZvtx, ConfEvtTriggerCheck, ConfEvtTriggerSel, ConfEvtOfflineCheck, false); - } else if (doprocessTrackData || doprocessTrackV0Data || doprocessTrackV0CascData || doprocessMCGenCount || doprocessTrackMC || doprocessTrackV0MC || doprocessTrackV0CascMC || doprocessTrackEPData) { - colCuts.setCuts(ConfEvtZvtx, ConfEvtTriggerCheck, ConfEvtTriggerSel, ConfEvtOfflineCheck, true); - } - colCuts.init(&qaRegistry); - colCuts.setApplyTFBorderCut(ConfEvtTFBorderCut); - colCuts.setApplyITSTPCmatching(ConfEvtITSTPCmatching); - colCuts.setApplyZvertexTimedifference(ConfEvtZvertexTimedifference); - colCuts.setApplyPileupRejection(ConfEvtPileupRejection); - colCuts.setApplyNoITSROBorderCut(ConfEvtNoITSROBorderCut); - if (!ConfBypassCCDB) { - ccdb->setURL(ccdburl.value); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(cfgFatalWhenNull); - uint64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - ccdb->setCreatedNotAfter(now); // TODO must become global parameter from the train creation time - } - - // QA histograms - AxisSpec idxAxis = {8, 0, 8, "Index"}; - if (ConfFillQA) { - qaRegistry.add("hGoodTrackIndices", "hGoodTrackIndices", kTH1F, {idxAxis}); - qaRegistry.add("hGoodMCTrackIndices", "hGoodMCTrackIndices", kTH1F, {idxAxis}); - qaRegistry.add("hGoodV0Indices", "hGoodV0Indices", kTH1F, {idxAxis}); - qaRegistry.add("hGoodMCV0Indices", "hGoodMCV0Indices", kTH1F, {idxAxis}); - qaRegistry.add("hGoodCascIndices", "hGoodCascIndices", kTH1F, {idxAxis}); - qaRegistry.add("hGoodMCCascIndices", "hGoodMCCascIndices", kTH1F, {idxAxis}); - qaRegistry.add("Phi", "#phi distribution", kTH1F, {{65, -0.1, 6.4}}); - } - // MC histograms - if (doprocessMCGenCount) { - AxisSpec EvtClassAxis = {kECend - 1, +kECbegin + 0.5, +kECend - 0.5, "", "event class"}; - AxisSpec ZAxis = {CfgVtxBins, "zaxis"}; - AxisSpec CentAxis = {binsCent, "centrality"}; - qaRegistry.add("Event/totalEventGenMC", "totalEventGenMC", {HistType::kTHnSparseF, {EvtClassAxis}}); - qaRegistry.add("Event/hgenzvtx", "evntclass; zvtex", {HistType::kTHnSparseF, {EvtClassAxis, ZAxis, CentAxis}}); - } - } - - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) // Simple copy from LambdaKzeroFinder.cxx - { - if (ConfBypassCCDB) - return; - if (mRunNumber == bc.runNumber()) { - return; - } - - // In case override, don't proceed, please - no CCDB access required - if (d_bz_input > -990) { - d_bz = d_bz_input; - ; - o2::parameters::GRPMagField grpmag; - if (fabs(d_bz) > 1e-5) { - grpmag.setL3Current(30000.f / (d_bz / 5.0f)); - } - o2::base::Propagator::initFieldFromGRP(&grpmag); - mRunNumber = bc.runNumber(); - return; - } - - auto run3grp_timestamp = bc.timestamp(); - o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); - o2::parameters::GRPMagField* grpmag = 0x0; - if (grpo) { - o2::base::Propagator::initFieldFromGRP(grpo); - // Fetch magnetic field from ccdb for current collision - d_bz = grpo->getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; - } else { - grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); - if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; - } - o2::base::Propagator::initFieldFromGRP(grpmag); - // Fetch magnetic field from ccdb for current collision - d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; - } - mRunNumber = bc.runNumber(); - // Set magnetic field value once known - LOGF(info, "Bz set to %f for run: ", d_bz, mRunNumber); - } - - void processTrackData(soa::Filtered::iterator const& collision, - soa::Filtered const& tracks, - aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); - // Default event selection - if (!colCuts.isSelected(collision)) - return; - colCuts.fillQA(collision); - - resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), CentEst(collision), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); - - fillTracks(collision, tracks); - } - PROCESS_SWITCH(reso2initializer, processTrackData, "Process for data", true); - - void processTrackDataRun2(soa::Filtered::iterator const& collision, - soa::Filtered const& tracks, - aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); - // Default event selection - if (!colCuts.isSelected(collision)) - return; - colCuts.fillQARun2(collision); - - resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), collision.centRun2V0M(), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); - - fillTracks(collision, tracks); - } - PROCESS_SWITCH(reso2initializer, processTrackDataRun2, "Process for data", false); - - void processTrackEPData(soa::Filtered>::iterator const& collision, - soa::Filtered const& tracks, - aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); - // Default event selection - if (!colCuts.isSelected(collision)) - return; - colCuts.fillQA(collision); - - resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), CentEst(collision), ComputeSpherocity(tracks, trackSphMin, trackSphDef), GetEvtPl(collision), GetEvtPlRes(collision, EvtPlDetId, EvtPlRefAId), GetEvtPlRes(collision, EvtPlDetId, EvtPlRefBId), GetEvtPlRes(collision, EvtPlRefAId, EvtPlRefBId), d_bz, bc.timestamp()); - - fillTracks(collision, tracks); - } - PROCESS_SWITCH(reso2initializer, processTrackEPData, "Process for data and ep ana", false); - - PresliceUnsorted perMcCol = aod::mccollisionlabel::mcCollisionId; - void processMCGenCount(aod::McCollisions const& mccollisions, aod::McParticles const& mcParticles, ResoEventsMC const& mcCols) - { - // Mainly referenced from dndeta_hi task in PWG-MM PAG-Multiplicity (Beomkyu Kim) - for (auto& mcCollision : mccollisions) { // Gen MC Event loop - auto particles = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); - std::vector bevtc(kECend, false); - bevtc[kINEL] = true; - auto posZ = mcCollision.posZ(); - if (std::abs(posZ) < 10) - bevtc[kINEL10] = true; - for (auto& particle : particles) { - if (!particle.isPhysicalPrimary()) - continue; - auto kp = pdg->GetParticle(particle.pdgCode()); - if (kp != nullptr) { - if (std::abs(kp->Charge()) >= 3) { // 3 quarks - if (std::abs(particle.eta()) < 1) { // INEL>0 definition - bevtc[kINELg0] = true; - break; - } - } - } - } - if (bevtc[kINELg0] && bevtc[kINEL10]) - bevtc[kINELg010] = true; - - for (auto ievtc = 1u; ievtc < kECend; ievtc++) { - if (bevtc[ievtc]) - qaRegistry.fill(HIST("Event/totalEventGenMC"), Double_t(ievtc)); - } - - auto collisionsample = mcCols.sliceBy(perMcCol, mcCollision.globalIndex()); - float cent = -1.0; - if (collisionsample.size() != 1) { // Prevent no reconstructed collision case - cent = -1; - } else { - for (auto& collision : collisionsample) { - cent = CentEst(collision); - if (collision.sel8()) - bevtc[kTrig] = true; - } - } - if (bevtc[kTrig] && bevtc[kINELg0]) - bevtc[kINELg0Trig] = true; - if (bevtc[kINELg0Trig] && bevtc[kINEL10]) - bevtc[kINELg010Trig] = true; - for (auto ievtc = 1u; ievtc < kECend; ievtc++) { - if (bevtc[ievtc]) - qaRegistry.fill(HIST("Event/hgenzvtx"), Double_t(ievtc), posZ, cent); - } - } - } - PROCESS_SWITCH(reso2initializer, processMCGenCount, "Process for MC", false); - - PresliceUnsorted perMcColRun2 = aod::mccollisionlabel::mcCollisionId; - void processMCGenCountRun2(aod::McCollisions const& mccollisions, aod::McParticles const& mcParticles, ResoRun2EventsMC const& mcCols) - { - // Mainly referenced from dndeta_hi task in PWG-MM PAG-Multiplicity (Beomkyu Kim) - for (auto& mcCollision : mccollisions) { // Gen MC Event loop - auto particles = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); - std::vector bevtc(kECend, false); - bevtc[kINEL] = true; - auto posZ = mcCollision.posZ(); - if (std::abs(posZ) < 10) - bevtc[kINEL10] = true; - for (auto& particle : particles) { - if (!particle.isPhysicalPrimary()) - continue; - auto kp = pdg->GetParticle(particle.pdgCode()); - if (kp != nullptr) { - if (std::abs(kp->Charge()) >= 3) { // 3 quarks - if (std::abs(particle.eta()) < 1) { // INEL>0 definition - bevtc[kINELg0] = true; - break; - } - } - } - } - if (bevtc[kINELg0] && bevtc[kINEL10]) - bevtc[kINELg010] = true; - - for (auto ievtc = 1u; ievtc < kECend; ievtc++) { - if (bevtc[ievtc]) - qaRegistry.fill(HIST("Event/totalEventGenMC"), Double_t(ievtc)); - } - - auto collisionsample = mcCols.sliceBy(perMcColRun2, mcCollision.globalIndex()); - float cent = -1.0; - if (collisionsample.size() != 1) { // Prevent no reconstructed collision case - cent = -1; - } else { - for (auto& collision : collisionsample) { - cent = CentEst(collision); - if (collision.sel7()) - bevtc[kTrig] = true; - } - } - if (bevtc[kTrig] && bevtc[kINELg0]) - bevtc[kINELg0Trig] = true; - if (bevtc[kINELg0Trig] && bevtc[kINEL10]) - bevtc[kINELg010Trig] = true; - for (auto ievtc = 1u; ievtc < kECend; ievtc++) { - if (bevtc[ievtc]) - qaRegistry.fill(HIST("Event/hgenzvtx"), Double_t(ievtc), posZ, cent); - } - } - } - PROCESS_SWITCH(reso2initializer, processMCGenCountRun2, "Process for MC", false); - - void processTrackV0Data(soa::Filtered::iterator const& collision, - soa::Filtered const& tracks, - ResoV0s const& V0s, - aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); - // Default event selection - if (!colCuts.isSelected(collision)) - return; - colCuts.fillQA(collision); - - resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), CentEst(collision), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); - - fillTracks(collision, tracks); - fillV0s(collision, V0s, tracks); - } - PROCESS_SWITCH(reso2initializer, processTrackV0Data, "Process for data", false); - - void processTrackV0DataRun2(soa::Filtered::iterator const& collision, - soa::Filtered const& tracks, - ResoV0s const& V0s, - aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); - // Default event selection - if (!colCuts.isSelected(collision)) - return; - colCuts.fillQARun2(collision); - - resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), collision.centRun2V0M(), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); - - fillTracks(collision, tracks); - fillV0s(collision, V0s, tracks); - } - PROCESS_SWITCH(reso2initializer, processTrackV0DataRun2, "Process for data", false); - - void processTrackV0CascData(soa::Filtered::iterator const& collision, - soa::Filtered const& tracks, - ResoV0s const& V0s, - ResoCascades const& Cascades, - aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); - // Default event selection - if (!colCuts.isSelected(collision)) - return; - colCuts.fillQA(collision); - - resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), CentEst(collision), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); - - fillTracks(collision, tracks); - fillV0s(collision, V0s, tracks); - fillCascades(collision, Cascades, tracks); - } - PROCESS_SWITCH(reso2initializer, processTrackV0CascData, "Process for data", false); - - void processTrackV0CascDataRun2(soa::Filtered::iterator const& collision, - soa::Filtered const& tracks, - ResoV0s const& V0s, - ResoCascades const& Cascades, - aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); - // Default event selection - if (!colCuts.isSelected(collision)) - return; - colCuts.fillQARun2(collision); - - resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), collision.centRun2V0M(), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); - - fillTracks(collision, tracks); - fillV0s(collision, V0s, tracks); - fillCascades(collision, Cascades, tracks); - } - PROCESS_SWITCH(reso2initializer, processTrackV0CascDataRun2, "Process for data", false); - - Preslice perMcCollision = aod::mcparticle::mcCollisionId; - void processTrackMC(soa::Filtered>::iterator const& collision, - aod::McCollisions const&, soa::Filtered const& tracks, - aod::McParticles const& mcParticles, aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); - if (!colCuts.isSelected(collision)) - return; - colCuts.fillQA(collision); - - resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), CentEst(collision), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); - - // Loop over tracks - fillTracks(collision, tracks); - - // Loop over all MC particles - auto mcParts = selectedMCParticles->sliceBy(perMcCollision, collision.mcCollision().globalIndex()); - fillMCParticles(mcParts, mcParticles); - } - PROCESS_SWITCH(reso2initializer, processTrackMC, "Process for MC", false); - - Preslice perMcCollisionRun2 = aod::mcparticle::mcCollisionId; - void processTrackMCRun2(soa::Filtered>::iterator const& collision, - aod::McCollisions const&, soa::Filtered const& tracks, - aod::McParticles const& mcParticles, aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); - if (!colCuts.isSelected(collision)) - return; - colCuts.fillQARun2(collision); - - resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), collision.centRun2V0M(), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); - - // Loop over tracks - fillTracks(collision, tracks); - - // Loop over all MC particles - auto mcParts = selectedMCParticles->sliceBy(perMcCollisionRun2, collision.mcCollision().globalIndex()); - fillMCParticles(mcParts, mcParticles); - } - PROCESS_SWITCH(reso2initializer, processTrackMCRun2, "Process for MC", false); - - void processTrackV0MC(soa::Filtered>::iterator const& collision, - aod::McCollisions const&, soa::Filtered const& tracks, - ResoV0sMC const& V0s, - aod::McParticles const& mcParticles, aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); - if (!colCuts.isSelected(collision)) - return; - colCuts.fillQA(collision); - - resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), CentEst(collision), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); - - // Loop over tracks - fillTracks(collision, tracks); - fillV0s(collision, V0s, tracks); - - // Loop over all MC particles - auto mcParts = selectedMCParticles->sliceBy(perMcCollision, collision.mcCollision().globalIndex()); - fillMCParticles(mcParts, mcParticles); - } - PROCESS_SWITCH(reso2initializer, processTrackV0MC, "Process for MC", false); - - void processTrackV0MCRun2(soa::Filtered>::iterator const& collision, - aod::McCollisions const&, soa::Filtered const& tracks, - ResoV0sMC const& V0s, - aod::McParticles const& mcParticles, aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); - if (!colCuts.isSelected(collision)) - return; - colCuts.fillQARun2(collision); - - resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), collision.centRun2V0M(), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); - - // Loop over tracks - fillTracks(collision, tracks); - fillV0s(collision, V0s, tracks); - - // Loop over all MC particles - auto mcParts = selectedMCParticles->sliceBy(perMcCollision, collision.mcCollision().globalIndex()); - fillMCParticles(mcParts, mcParticles); - } - PROCESS_SWITCH(reso2initializer, processTrackV0MCRun2, "Process for MC", false); - - void processTrackV0CascMC(soa::Filtered>::iterator const& collision, - aod::McCollisions const&, soa::Filtered const& tracks, - ResoV0sMC const& V0s, - ResoCascadesMC const& Cascades, - aod::McParticles const& mcParticles, aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); - if (!colCuts.isSelected(collision)) - return; - colCuts.fillQA(collision); - - resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), CentEst(collision), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); - - // Loop over tracks - fillTracks(collision, tracks); - fillV0s(collision, V0s, tracks); - fillV0s(collision, V0s, tracks); - fillCascades(collision, Cascades, tracks); - - // Loop over all MC particles - auto mcParts = selectedMCParticles->sliceBy(perMcCollision, collision.mcCollision().globalIndex()); - fillMCParticles(mcParts, mcParticles); - } - PROCESS_SWITCH(reso2initializer, processTrackV0CascMC, "Process for MC", false); - - void processTrackV0CascMCRun2(soa::Filtered>::iterator const& collision, - aod::McCollisions const&, soa::Filtered const& tracks, - ResoV0sMC const& V0s, - ResoCascadesMC const& Cascades, - aod::McParticles const& mcParticles, aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); - if (!colCuts.isSelected(collision)) - return; - colCuts.fillQARun2(collision); - - resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), collision.centRun2V0M(), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); - - // Loop over tracks - fillTracks(collision, tracks); - fillV0s(collision, V0s, tracks); - fillV0s(collision, V0s, tracks); - fillCascades(collision, Cascades, tracks); - - // Loop over all MC particles - auto mcParts = selectedMCParticles->sliceBy(perMcCollision, collision.mcCollision().globalIndex()); - fillMCParticles(mcParts, mcParticles); - } - PROCESS_SWITCH(reso2initializer, processTrackV0CascMCRun2, "Process for MC", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"lf-reso2initializer"}), - }; -} diff --git a/PWGLF/TableProducer/Resonances/LFResonanceMergeDF.cxx b/PWGLF/TableProducer/Resonances/LFResonanceMergeDF.cxx deleted file mode 100644 index 73d76e08275..00000000000 --- a/PWGLF/TableProducer/Resonances/LFResonanceMergeDF.cxx +++ /dev/null @@ -1,192 +0,0 @@ -// 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 LFResonanceInitializer.cxx -/// \brief Initializes variables for the resonance candidate producers -/// -/// -/// In typical dataframes (DF), we usually observe a range of 200 to 300 collisions. -/// This limited number of collisions often results in most events having very few currentwindowneighbors() for event mixing. -/// However, for resonances analysis, a minimum of 10 currentwindowneighbors() is required. -/// To address this limitation, this script is designed to aggregate information from multiple dataframes into a single dataframe, -/// thereby increasing the number of available current window neighbors for analysis. Here, nDF refers to the number of events or collisions. -/// For instance, if the total number of collisions across all dataframes is, say, 10,836, setting nDF to 10,836 will result in the creation of a single table. -/// Conversely, if nDF is set to 2,709, it will generate four tables, each containing approximately 2,709 collisions. -/// If nDF is set to 1, it will generate tables equal to the number of parent tables. -/// -/// /// -/// \author Bong-Hwi Lim -/// Nasir Mehdi Malik - -#include "Common/DataModel/PIDResponse.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/Qvectors.h" -#include "Common/Core/EventPlaneHelper.h" -#include "Framework/ASoAHelpers.h" -#include "DetectorsBase/Propagator.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "PWGLF/DataModel/LFResonanceTablesMergeDF.h" -#include "PWGLF/DataModel/LFResonanceTables.h" -#include "PWGLF/Utils/collisionCuts.h" -#include "ReconstructionDataFormats/Track.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::soa; - -/// Initializer for the resonance candidate producers - -struct reso2dfmerged { - // SliceCache cache; - - Configurable nDF{"nDF", 1, "no of combination of collision"}; - HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - using resoCols = aod::ResoCollisions; - using resoTracks = aod::ResoTracks; - - void init(InitContext const&) - { - - const AxisSpec axisCent(110, 0, 110, "FT0 (%)"); - histos.add("Event/h1d_ft0_mult_percentile", "FT0 (%)", kTH1F, {axisCent}); - } - Produces resoCollisionsdf; - Produces reso2trksdf; - int df = 0; - - std::vector> vecOfTuples; - std::vector>> - vecOfVecOfTuples; - void processTrackDataDF(resoCols::iterator const& collision, resoTracks const& tracks) - { - - int nCollisions = nDF; - vecOfTuples.push_back(std::make_tuple(collision.posX(), collision.posY(), collision.posZ(), collision.cent(), collision.spherocity(), collision.evtPl())); - std::vector> - innerVector; - for (auto& track : tracks) { - innerVector.push_back(std::make_tuple( - track.pt(), - track.px(), - track.py(), - track.pz(), - track.eta(), - track.phi(), - track.sign(), - (uint8_t)track.tpcNClsCrossedRows(), - track.dcaXY(), - track.dcaZ(), - track.x(), - track.alpha(), - track.hasTOF(), - track.tpcNSigmaPi(), - track.tpcNSigmaKa(), - track.tpcNSigmaPr(), - track.tofNSigmaPi(), - track.tofNSigmaKa(), - track.tofNSigmaPr(), - track.tpcSignal(), - track.passedITSRefit(), - track.passedTPCRefit(), - track.isGlobalTrackWoDCA(), - track.isPrimaryTrack(), - track.isPVContributor(), - track.tpcCrossedRowsOverFindableCls(), - track.itsChi2NCl(), - track.tpcChi2NCl())); - } - - vecOfVecOfTuples.push_back(innerVector); - innerVector.clear(); - df++; - if (df < nCollisions) - return; - df = 0; - - for (size_t i = 0; i < vecOfTuples.size(); ++i) { - const auto& tuple = vecOfTuples[i]; - const auto& innerVector = vecOfVecOfTuples[i]; - - histos.fill(HIST("Event/h1d_ft0_mult_percentile"), std::get<3>(tuple)); - resoCollisionsdf(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple), std::get<3>(tuple), std::get<4>(tuple), std::get<5>(tuple), 0., 0., 0., 0, 0); - // LOGF(info, "collisions: Index = %d ) %f - %f - %f %f %d -- %d", std::get<0>(tuple).globalIndex(),std::get<1>(tuple),std::get<2>(tuple), std::get<3>(tuple), std::get<4>(tuple), std::get<5>(tuple).size(),resoCollisionsdf.lastIndex()); - - for (const auto& tuple : innerVector) { - reso2trksdf(resoCollisionsdf.lastIndex(), - std::get<0>(tuple), - std::get<1>(tuple), - std::get<2>(tuple), - std::get<3>(tuple), - std::get<4>(tuple), - std::get<5>(tuple), - std::get<6>(tuple), - std::get<7>(tuple), - std::get<8>(tuple), - std::get<9>(tuple), - std::get<10>(tuple), - std::get<11>(tuple), - std::get<12>(tuple), - std::get<13>(tuple), - std::get<14>(tuple), - std::get<15>(tuple), - std::get<16>(tuple), - std::get<17>(tuple), - std::get<18>(tuple), - std::get<19>(tuple), - std::get<20>(tuple), - std::get<21>(tuple), - std::get<22>(tuple), - std::get<23>(tuple), - std::get<24>(tuple), - std::get<25>(tuple), - std::get<26>(tuple), - std::get<27>(tuple)); - } - } - - vecOfTuples.clear(); - vecOfVecOfTuples.clear(); // - } - - PROCESS_SWITCH(reso2dfmerged, processTrackDataDF, "Process for data merged DF", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} diff --git a/PWGLF/TableProducer/Resonances/doublephitable.cxx b/PWGLF/TableProducer/Resonances/doublephitable.cxx new file mode 100644 index 00000000000..d02ab3d3734 --- /dev/null +++ b/PWGLF/TableProducer/Resonances/doublephitable.cxx @@ -0,0 +1,286 @@ +// 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 doublephitable.cxx +/// \brief Selection of events with triplets and pairs for femtoscopic studies +/// +/// \author Sourav Kundu, sourav.kundu@cern.ch + +#include +#include +#include +#include +#include +#include // FIXME +#include // FIXME + +#include +#include +#include +#include + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" + +#include "PWGLF/DataModel/ReducedDoublePhiTables.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "CommonConstants/MathConstants.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "Common/DataModel/PIDResponseITS.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct doublephitable { + + // Produce derived tables + Produces redPhiEvents; + Produces phiTrack; + + // events + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + // Configurable cfgCutCentralityMax{"cfgCutCentralityMax", 0.0f, "Accepted maximum Centrality"}; + // Configurable cfgCutCentralityMin{"cfgCutCentralityMin", 100.0f, "Accepted minimum Centrality"}; + // track + Configurable useGlobalTrack{"useGlobalTrack", true, "use Global track"}; + Configurable cfgCutTOFBeta{"cfgCutTOFBeta", 0.0, "cut TOF beta"}; + Configurable cfgCutCharge{"cfgCutCharge", 0.0, "cut on Charge"}; + Configurable cfgCutPT{"cfgCutPT", 0.2, "PT cut on daughter track"}; + Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; + Configurable cfgCutDCAxy{"cfgCutDCAxy", 2.0f, "DCAxy range for tracks"}; + Configurable cfgCutDCAz{"cfgCutDCAz", 2.0f, "DCAz range for tracks"}; + Configurable nsigmaCutTPC{"nsigmacutTPC", 3.0, "Value of the TPC Nsigma cut"}; + Configurable nsigmaCutTOF{"nsigmaCutTOF", 3.0, "Value of the TOF Nsigma cut"}; + Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; + Configurable isDeepAngle{"isDeepAngle", true, "Deep Angle cut"}; + Configurable cfgDeepAngle{"cfgDeepAngle", 0.04, "Deep Angle cut value"}; + ConfigurableAxis configThnAxisInvMass{"configThnAxisInvMass", {120, 0.98, 1.1}, "#it{M} (GeV/#it{c}^{2})"}; + ConfigurableAxis configThnAxisPt{"configThnAxisPt", {100, 0.0, 10.}, "#it{p}_{T} (GeV/#it{c})"}; + Configurable minPhiMass{"minPhiMass", 1.01, "Minimum phi mass"}; + Configurable maxPhiMass{"maxPhiMass", 1.03, "Maximum phi mass"}; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + // Filter centralityFilter = (nabs(aod::cent::centFT0C) < cfgCutCentralityMax && nabs(aod::cent::centFT0C) > cfgCutCentralityMin); + Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPT); + Filter DCAcutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); + Filter PIDcutFilter = nabs(aod::pidtpc::tpcNSigmaKa) < nsigmaCutTPC; + + using EventCandidates = soa::Filtered>; + using TrackCandidates = soa::Filtered>; + + SliceCache cache; + Partition posTracks = aod::track::signed1Pt > cfgCutCharge; + Partition negTracks = aod::track::signed1Pt < cfgCutCharge; + + // Histogram + HistogramRegistry qaRegistry{"QAHistos", { + {"hEventstat", "hEventstat", {HistType::kTH1F, {{2, 0.0f, 2.0f}}}}, + {"hInvMassPhi", "hInvMassPhi", {HistType::kTH2F, {{40, 1.0f, 1.04f}, {100, 0.0f, 10.0f}}}}, + {"hNsigmaPtkaonTPC", "hNsigmaPtkaonTPC", {HistType::kTH2F, {{200, -10.0f, 10.0f}, {100, 0.0f, 10.0f}}}}, + {"hNsigmaPtkaonTOF", "hNsigmaPtkaonTOF", {HistType::kTH2F, {{200, -10.0f, 10.0f}, {100, 0.0f, 10.0f}}}}, + }, + OutputObjHandlingPolicy::AnalysisObject}; + + double massKa = o2::constants::physics::MassKPlus; + + template + bool selectionTrack(const T& candidate) + { + if (useGlobalTrack && !(candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsFound() > cfgTPCcluster)) { + return false; + } + return true; + } + template + bool selectionPID(const T& candidate) + { + if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return true; + } + if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF) { + return true; + } + return false; + } + // deep angle cut on pair to remove photon conversion + template + bool selectionPair(const T1& candidate1, const T2& candidate2) + { + double pt1, pt2, pz1, pz2, p1, p2, angle; + pt1 = candidate1.pt(); + pt2 = candidate2.pt(); + pz1 = candidate1.pz(); + pz2 = candidate2.pz(); + p1 = candidate1.p(); + p2 = candidate2.p(); + angle = TMath::ACos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); + if (isDeepAngle && angle < cfgDeepAngle) { + return false; + } + return true; + } + + ROOT::Math::PxPyPzMVector KaonPlus, KaonMinus, PhiMesonMother, PhiVectorDummy, Phid1dummy, Phid2dummy; + void processPhiReducedTable(EventCandidates::iterator const& collision, TrackCandidates const&, aod::BCsWithTimestamps const&) + { + o2::aod::ITSResponse itsResponse; + bool keepEventDoublePhi = false; + int numberPhi = 0; + auto currentRunNumber = collision.bc_as().runNumber(); + auto bc = collision.bc_as(); + std::vector Phid1Index = {}; + std::vector Phid2Index = {}; + + std::vector Phid1Charge = {}; + std::vector Phid2Charge = {}; + + std::vector Phid1TPC = {}; + std::vector Phid2TPC = {}; + + std::vector Phid1TOF = {}; + std::vector Phid2TOF = {}; + + std::vector Phid1TOFHit = {}; + std::vector Phid2TOFHit = {}; + + std::vector phiresonance, phiresonanced1, phiresonanced2; + + int Npostrack = 0; + int Nnegtrack = 0; + + if (collision.sel8() && collision.selection_bit(aod::evsel::kNoTimeFrameBorder) && collision.selection_bit(aod::evsel::kNoITSROFrameBorder) && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + auto posThisColl = posTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negThisColl = negTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + for (auto track1 : posThisColl) { + // track selection + if (!selectionTrack(track1)) { + continue; + } + // PID check + if (!selectionPID(track1)) { + continue; + } + if (!(itsResponse.nSigmaITS(track1) > -3.0 && itsResponse.nSigmaITS(track1) < 3.0)) { + continue; + } + Npostrack = Npostrack + 1; + qaRegistry.fill(HIST("hNsigmaPtkaonTPC"), track1.tpcNSigmaKa(), track1.pt()); + if (track1.hasTOF()) { + qaRegistry.fill(HIST("hNsigmaPtkaonTOF"), track1.tofNSigmaKa(), track1.pt()); + } + auto track1ID = track1.globalIndex(); + for (auto track2 : negThisColl) { + // track selection + if (!selectionTrack(track2)) { + continue; + } + // PID check + if (!selectionPID(track2)) { + continue; + } + if (Npostrack == 1) { + Nnegtrack = Nnegtrack + 1; + } + auto track2ID = track2.globalIndex(); + if (track2ID == track1ID) { + continue; + } + if (!(itsResponse.nSigmaITS(track2) > -3.0 && itsResponse.nSigmaITS(track2) < 3.0)) { + continue; + } + if (!selectionPair(track1, track2)) { + continue; + } + KaonPlus = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + KaonMinus = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + PhiMesonMother = KaonPlus + KaonMinus; + if (PhiMesonMother.M() > minPhiMass && PhiMesonMother.M() < maxPhiMass) { + numberPhi = numberPhi + 1; + ROOT::Math::PtEtaPhiMVector temp1(track1.pt(), track1.eta(), track1.phi(), massKa); + ROOT::Math::PtEtaPhiMVector temp2(track2.pt(), track2.eta(), track2.phi(), massKa); + ROOT::Math::PtEtaPhiMVector temp3(PhiMesonMother.pt(), PhiMesonMother.eta(), PhiMesonMother.phi(), PhiMesonMother.M()); + + phiresonanced1.push_back(temp1); + phiresonanced2.push_back(temp2); + phiresonance.push_back(temp3); + + Phid1Index.push_back(track1.globalIndex()); + Phid2Index.push_back(track2.globalIndex()); + + Phid1Charge.push_back(track1.sign()); + Phid2Charge.push_back(track2.sign()); + + Phid1TPC.push_back(track1.tpcNSigmaKa()); + Phid2TPC.push_back(track2.tpcNSigmaKa()); + auto d1TOFHit = -1; + auto d2TOFHit = -1; + auto d1TOF = -999.0; + auto d2TOF = -999.0; + if (track1.hasTOF()) { + d1TOFHit = 1; + d1TOF = track1.tofNSigmaKa(); + } + if (track2.hasTOF()) { + d2TOFHit = 1; + d2TOF = track2.tofNSigmaKa(); + } + Phid1TOF.push_back(d1TOF); + Phid2TOF.push_back(d2TOF); + Phid1TOFHit.push_back(d1TOFHit); + Phid2TOFHit.push_back(d2TOFHit); + qaRegistry.fill(HIST("hInvMassPhi"), PhiMesonMother.M(), PhiMesonMother.Pt()); + } + } + } + } // select collision + if (numberPhi > 1 && Npostrack > 1 && Nnegtrack > 1) { + keepEventDoublePhi = true; + } + qaRegistry.fill(HIST("hEventstat"), 0.5); + if (keepEventDoublePhi && numberPhi > 1 && Npostrack > 1 && Nnegtrack > 1 && (phiresonance.size() == phiresonanced1.size()) && (phiresonance.size() == phiresonanced2.size())) { + qaRegistry.fill(HIST("hEventstat"), 1.5); + /////////// Fill collision table/////////////// + redPhiEvents(bc.globalBC(), currentRunNumber, bc.timestamp(), collision.posZ(), collision.numContrib(), Npostrack, Nnegtrack); + auto indexEvent = redPhiEvents.lastIndex(); + //// Fill track table for Phi////////////////// + for (auto if1 = phiresonance.begin(); if1 != phiresonance.end(); ++if1) { + auto i5 = std::distance(phiresonance.begin(), if1); + PhiVectorDummy = phiresonance.at(i5); + Phid1dummy = phiresonanced1.at(i5); + Phid2dummy = phiresonanced2.at(i5); + phiTrack(indexEvent, PhiVectorDummy.Px(), PhiVectorDummy.Py(), PhiVectorDummy.Pz(), Phid1dummy.Px(), Phid1dummy.Py(), Phid1dummy.Pz(), Phid2dummy.Px(), Phid2dummy.Py(), Phid2dummy.Pz(), + PhiVectorDummy.M(), + Phid1Index.at(i5), Phid2Index.at(i5), + Phid1Charge.at(i5), Phid2Charge.at(i5), + Phid1TPC.at(i5), Phid2TPC.at(i5), Phid1TOFHit.at(i5), Phid2TOFHit.at(i5), Phid1TOF.at(i5), Phid2TOF.at(i5)); + } + } + } // process + PROCESS_SWITCH(doublephitable, processPhiReducedTable, "Process table creation for double phi", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfg) +{ + return WorkflowSpec{adaptAnalysisTask(cfg)}; +} diff --git a/PWGLF/TableProducer/Resonances/f1protonreducedtable.cxx b/PWGLF/TableProducer/Resonances/f1protonreducedtable.cxx index 30082692386..ce0cdcf3af5 100644 --- a/PWGLF/TableProducer/Resonances/f1protonreducedtable.cxx +++ b/PWGLF/TableProducer/Resonances/f1protonreducedtable.cxx @@ -25,6 +25,10 @@ #include #include #include +#include + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" #include "PWGLF/DataModel/ReducedF1ProtonTables.h" #include "Framework/ASoAHelpers.h" @@ -42,6 +46,7 @@ #include "DataFormatsTPC/BetheBlochAleph.h" #include "CCDB/BasicCCDBManager.h" #include "CCDB/CcdbApi.h" +#include "Common/DataModel/PIDResponseITS.h" using namespace o2; using namespace o2::framework; @@ -57,6 +62,9 @@ struct f1protonreducedtable { Service ccdb; o2::ccdb::CcdbApi ccdbApi; + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + // Configs for events Configurable ConfEvtSelectZvtx{"ConfEvtSelectZvtx", true, "Event selection includes max. z-Vertex"}; Configurable ConfEvtZvtx{"ConfEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; @@ -66,6 +74,7 @@ struct f1protonreducedtable { Configurable trackSphMin{"trackSphMin", 10, "Number of tracks for Spherocity Calculation"}; // Configs for track PID + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", true, "Analysed skimmed events"}; Configurable ConfUseManualPIDproton{"ConfUseManualPIDproton", true, "True: use home-made PID solution for proton "}; Configurable ConfUseManualPIDkaon{"ConfUseManualPIDkaon", true, "True: use home-made PID solution for kaon "}; Configurable ConfUseManualPIDpion{"ConfUseManualPIDpion", true, "True: use home-made PID solution for pion "}; @@ -135,6 +144,7 @@ struct f1protonreducedtable { Configurable cMaxRelMom{"cMaxRelMom", 0.5, "Relative momentum cut"}; // Histogram + OutputObj hProcessedEvents{TH1D("hProcessedEvents", ";; Number of events", 2, 0.0f, 2.0f)}; HistogramRegistry qaRegistry{"QAHistos", { {"hEventstat", "hEventstat", {HistType::kTH1F, {{3, 0.0f, 3.0f}}}}, {"hInvMassf1", "hInvMassf1", {HistType::kTH2F, {{400, 1.1f, 1.9f}, {100, 0.0f, 10.0f}}}}, @@ -148,7 +158,7 @@ struct f1protonreducedtable { {"hEta", "hEta", {HistType::kTH1F, {{20, -1.0f, 1.0f}}}}, {"hNsigmaPtpionTPC", "hNsigmaPtpionTPC", {HistType::kTH2F, {{200, -10.0f, 10.0f}, {100, 0.0f, 10.0f}}}}, {"hNsigmaPtpionTOF", "hNsigmaPtpionTOF", {HistType::kTH2F, {{200, -10.0f, 10.0f}, {100, 0.0f, 10.0f}}}}, - {"hNsigmaPtkaonTPC", "hNsigmaPtkaonTPC", {HistType::kTH2F, {{200, -10.0f, 10.0f}, {100, 0.0f, 10.0f}}}}, + {"hNsigmaPtkaonTPC", "hNsigmaPtkaonTPC", {HistType::kTH3F, {{200, -10.0f, 10.0f}, {200, -20.0f, 20.0f}, {100, 0.0f, 10.0f}}}}, {"hNsigmaPtkaonTOF", "hNsigmaPtkaonTOF", {HistType::kTH2F, {{200, -10.0f, 10.0f}, {100, 0.0f, 10.0f}}}}, {"hNsigmaPtprotonTPC", "hNsigmaPtprotonTPC", {HistType::kTH2F, {{200, -10.0f, 10.0f}, {100, 0.0f, 10.0f}}}}, {"hNsigmaPtprotonTOF", "hNsigmaPtprotonTOF", {HistType::kTH2F, {{200, -10.0f, 10.0f}, {100, 0.0f, 10.0f}}}}, @@ -163,6 +173,9 @@ struct f1protonreducedtable { ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + zorroSummary.setObject(zorro.getZorroSummary()); + hProcessedEvents->GetXaxis()->SetBinLabel(1, "All Trigger events"); + hProcessedEvents->GetXaxis()->SetBinLabel(2, "Events with F1 Trigger"); } template @@ -236,6 +249,15 @@ struct f1protonreducedtable { return true; } + template + bool selectionGlobalTrack(const T& candidate) + { + if (!(candidate.isGlobalTrack() && candidate.isPVContributor())) { + return false; + } + return true; + } + template double updatePID(T const& track, double bgScaling, std::vector BB) { @@ -481,6 +503,7 @@ struct f1protonreducedtable { void processF1ProtonReducedTable(EventCandidates::iterator const& collision, aod::BCsWithTimestamps const&, PrimaryTrackCandidates const& tracks, ResoV0s const& V0s) { + o2::aod::ITSResponse itsResponse; bool keepEventF1Proton = false; int numberF1 = 0; // keep track of indices @@ -501,27 +524,33 @@ struct f1protonreducedtable { std::vector PionCharge = {}; std::vector KaonCharge = {}; std::vector ProtonCharge = {}; - std::vector ProtonChargeFinal = {}; + // std::vector ProtonChargeFinal = {}; // keep TPC PID of proton std::vector ProtonTPCNsigma = {}; - std::vector ProtonTPCNsigmaFinal = {}; + // std::vector ProtonTPCNsigmaFinal = {}; // keep TOF PID of proton std::vector ProtonTOFNsigma = {}; - std::vector ProtonTOFNsigmaFinal = {}; + // std::vector ProtonTOFNsigmaFinal = {}; // keep TOF Hit of proton std::vector ProtonTOFHit = {}; - std::vector ProtonTOFHitFinal = {}; + // std::vector ProtonTOFHitFinal = {}; // keep TOF Hit of pion std::vector PionTOFHit = {}; std::vector PionTOFHitFinal = {}; + std::vector PionTPC = {}; + std::vector PionTPCFinal = {}; // keep TOF Hit of kaon std::vector KaonTOFHit = {}; std::vector KaonTOFHitFinal = {}; + std::vector KaonTPC = {}; + std::vector KaonTPCFinal = {}; + std::vector KaonTPCPionHypo = {}; + std::vector KaonTPCPionHypoFinal = {}; // keep kaon-kshort mass of f1resonance std::vector f1kaonkshortmass = {}; @@ -530,15 +559,21 @@ struct f1protonreducedtable { std::vector f1signal = {}; // Prepare vectors for different species - std::vector protons, kaons, pions, kshorts, f1resonance, f1resonanced1, f1resonanced2, f1resonanced3, protonsfinal; + std::vector protons, kaons, pions, kshorts, f1resonance, f1resonanced1, f1resonanced2, f1resonanced3; + // , protonsfinal; float kstar = 999.f; currentRunNumber = collision.bc_as().runNumber(); auto bc = collision.bc_as(); - + hProcessedEvents->Fill(0.5); + bool zorroSelected = false; if (isSelectedEvent(collision)) { - if (ConfUseManualPIDproton || ConfUseManualPIDkaon || ConfUseManualPIDpion) { - if (currentRunNumber != lastRunNumber) { + if (currentRunNumber != lastRunNumber) { + if (cfgSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), "fTriggerEventF1Proton"); + zorro.populateHistRegistry(qaRegistry, bc.runNumber()); + } + if (ConfUseManualPIDproton || ConfUseManualPIDkaon || ConfUseManualPIDpion) { if (ConfUseManualPIDproton) { BBProton = setValuesBB(ccdbApi, bc, ConfPIDBBProton); BBAntiproton = setValuesBB(ccdbApi, bc, ConfPIDBBAntiProton); @@ -551,202 +586,225 @@ struct f1protonreducedtable { BBKaon = setValuesBB(ccdbApi, bc, ConfPIDBBKaon); BBAntikaon = setValuesBB(ccdbApi, bc, ConfPIDBBAntiKaon); } - lastRunNumber = currentRunNumber; } + lastRunNumber = currentRunNumber; } - - for (auto& track : tracks) { - - if (!isSelectedTrack(track)) - continue; - qaRegistry.fill(HIST("hDCAxy"), track.dcaXY()); - qaRegistry.fill(HIST("hDCAz"), track.dcaZ()); - qaRegistry.fill(HIST("hEta"), track.eta()); - qaRegistry.fill(HIST("hPhi"), track.phi()); - double nTPCSigmaP[3]{track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; - double nTPCSigmaN[3]{track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; - if (ConfUseManualPIDproton) { - auto bgScalingProton = 1 / massPr; // momentum scaling? - if (BBProton.size() == 6) - nTPCSigmaP[2] = updatePID(track, bgScalingProton, BBProton); - if (BBAntiproton.size() == 6) - nTPCSigmaN[2] = updatePID(track, bgScalingProton, BBAntiproton); - } - if (ConfUseManualPIDkaon) { - auto bgScalingKaon = 1 / massKa; // momentum scaling? - if (BBKaon.size() == 6) - nTPCSigmaP[1] = updatePID(track, bgScalingKaon, BBKaon); - if (BBAntikaon.size() == 6) - nTPCSigmaN[1] = updatePID(track, bgScalingKaon, BBAntikaon); - } - if (ConfUseManualPIDpion) { - auto bgScalingPion = 1 / massPi; // momentum scaling? - if (BBPion.size() == 6) - nTPCSigmaP[0] = updatePID(track, bgScalingPion, BBPion); - if (BBAntipion.size() == 6) - nTPCSigmaN[0] = updatePID(track, bgScalingPion, BBAntipion); - } - - if ((track.sign() > 0 && SelectionPID(track, strategyPIDPion, 0, nTPCSigmaP[0])) || (track.sign() < 0 && SelectionPID(track, strategyPIDPion, 0, nTPCSigmaN[0]))) { - ROOT::Math::PtEtaPhiMVector temp(track.pt(), track.eta(), track.phi(), massPi); - pions.push_back(temp); - PionIndex.push_back(track.globalIndex()); - PionCharge.push_back(track.sign()); - auto PionTOF = 0; - if (track.sign() > 0) { - qaRegistry.fill(HIST("hNsigmaPtpionTPC"), nTPCSigmaP[0], track.pt()); + if (cfgSkimmedProcessing) { + zorroSelected = zorro.isSelected(collision.template bc_as().globalBC()); + } else { + zorroSelected = true; + } + if (zorroSelected) { + hProcessedEvents->Fill(1.5); + for (auto& track : tracks) { + if (!isSelectedTrack(track)) { + continue; } - if (track.sign() < 0) { - qaRegistry.fill(HIST("hNsigmaPtpionTPC"), nTPCSigmaN[0], track.pt()); + if (!selectionGlobalTrack(track)) { + continue; } - if (track.hasTOF()) { - qaRegistry.fill(HIST("hNsigmaPtpionTOF"), track.tofNSigmaPi(), track.pt()); - PionTOF = 1; + qaRegistry.fill(HIST("hDCAxy"), track.dcaXY()); + qaRegistry.fill(HIST("hDCAz"), track.dcaZ()); + qaRegistry.fill(HIST("hEta"), track.eta()); + qaRegistry.fill(HIST("hPhi"), track.phi()); + double nTPCSigmaP[3]{track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + double nTPCSigmaN[3]{track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + if (ConfUseManualPIDproton) { + auto bgScalingProton = 1 / massPr; // momentum scaling? + if (BBProton.size() == 6) + nTPCSigmaP[2] = updatePID(track, bgScalingProton, BBProton); + if (BBAntiproton.size() == 6) + nTPCSigmaN[2] = updatePID(track, bgScalingProton, BBAntiproton); + } + if (ConfUseManualPIDkaon) { + auto bgScalingKaon = 1 / massKa; // momentum scaling? + if (BBKaon.size() == 6) + nTPCSigmaP[1] = updatePID(track, bgScalingKaon, BBKaon); + if (BBAntikaon.size() == 6) + nTPCSigmaN[1] = updatePID(track, bgScalingKaon, BBAntikaon); + } + if (ConfUseManualPIDpion) { + auto bgScalingPion = 1 / massPi; // momentum scaling? + if (BBPion.size() == 6) + nTPCSigmaP[0] = updatePID(track, bgScalingPion, BBPion); + if (BBAntipion.size() == 6) + nTPCSigmaN[0] = updatePID(track, bgScalingPion, BBAntipion); } - PionTOFHit.push_back(PionTOF); - } - if ((track.pt() > cMinKaonPt && track.sign() > 0 && SelectionPID(track, strategyPIDKaon, 1, nTPCSigmaP[1])) || (track.pt() > cMinKaonPt && track.sign() < 0 && SelectionPID(track, strategyPIDKaon, 1, nTPCSigmaN[1]))) { - ROOT::Math::PtEtaPhiMVector temp(track.pt(), track.eta(), track.phi(), massKa); - kaons.push_back(temp); - KaonIndex.push_back(track.globalIndex()); - KaonCharge.push_back(track.sign()); - auto KaonTOF = 0; - if (track.sign() > 0) { - qaRegistry.fill(HIST("hNsigmaPtkaonTPC"), nTPCSigmaP[1], track.pt()); + if ((track.sign() > 0 && SelectionPID(track, strategyPIDPion, 0, nTPCSigmaP[0]) && (itsResponse.nSigmaITS(track) > -3.0 && itsResponse.nSigmaITS(track) < 3.0)) || (track.sign() < 0 && SelectionPID(track, strategyPIDPion, 0, nTPCSigmaN[0]) && (itsResponse.nSigmaITS(track) > -3.0 && itsResponse.nSigmaITS(track) < 3.0))) { + ROOT::Math::PtEtaPhiMVector temp(track.pt(), track.eta(), track.phi(), massPi); + pions.push_back(temp); + PionIndex.push_back(track.globalIndex()); + PionCharge.push_back(track.sign()); + auto PionTOF = 0; + if (track.sign() > 0) { + qaRegistry.fill(HIST("hNsigmaPtpionTPC"), nTPCSigmaP[0], track.pt()); + PionTPC.push_back(nTPCSigmaP[0]); + } + if (track.sign() < 0) { + qaRegistry.fill(HIST("hNsigmaPtpionTPC"), nTPCSigmaN[0], track.pt()); + PionTPC.push_back(nTPCSigmaN[0]); + } + if (track.hasTOF()) { + qaRegistry.fill(HIST("hNsigmaPtpionTOF"), track.tofNSigmaPi(), track.pt()); + PionTOF = 1; + } + PionTOFHit.push_back(PionTOF); } - if (track.sign() < 0) { - qaRegistry.fill(HIST("hNsigmaPtkaonTPC"), nTPCSigmaN[1], track.pt()); + + if ((track.pt() > cMinKaonPt && track.sign() > 0 && SelectionPID(track, strategyPIDKaon, 1, nTPCSigmaP[1]) && (itsResponse.nSigmaITS(track) > -3.0 && itsResponse.nSigmaITS(track) < 3.0)) || (track.pt() > cMinKaonPt && track.sign() < 0 && SelectionPID(track, strategyPIDKaon, 1, nTPCSigmaN[1]) && (itsResponse.nSigmaITS(track) > -3.0 && itsResponse.nSigmaITS(track) < 3.0))) { + ROOT::Math::PtEtaPhiMVector temp(track.pt(), track.eta(), track.phi(), massKa); + kaons.push_back(temp); + KaonIndex.push_back(track.globalIndex()); + KaonCharge.push_back(track.sign()); + auto KaonTOF = 0; + if (track.sign() > 0) { + qaRegistry.fill(HIST("hNsigmaPtkaonTPC"), nTPCSigmaP[1], nTPCSigmaP[0], track.pt()); + KaonTPC.push_back(nTPCSigmaP[1]); + KaonTPCPionHypo.push_back(nTPCSigmaP[0]); + } + if (track.sign() < 0) { + qaRegistry.fill(HIST("hNsigmaPtkaonTPC"), nTPCSigmaN[1], nTPCSigmaN[0], track.pt()); + KaonTPC.push_back(nTPCSigmaN[1]); + KaonTPCPionHypo.push_back(nTPCSigmaN[0]); + } + if (track.hasTOF()) { + qaRegistry.fill(HIST("hNsigmaPtkaonTOF"), track.tofNSigmaKa(), track.pt()); + KaonTOF = 1; + } + KaonTOFHit.push_back(KaonTOF); } - if (track.hasTOF()) { - qaRegistry.fill(HIST("hNsigmaPtkaonTOF"), track.tofNSigmaKa(), track.pt()); - KaonTOF = 1; + + if ((track.pt() < cMaxProtonPt && track.sign() > 0 && SelectionPID(track, strategyPIDProton, 2, nTPCSigmaP[2]) && (itsResponse.nSigmaITS(track) > -3.0 && itsResponse.nSigmaITS(track) < 3.0)) || (track.pt() < cMaxProtonPt && track.sign() < 0 && SelectionPID(track, strategyPIDProton, 2, nTPCSigmaN[2]) && (itsResponse.nSigmaITS(track) > -3.0 && itsResponse.nSigmaITS(track) < 3.0))) { + ROOT::Math::PtEtaPhiMVector temp(track.pt(), track.eta(), track.phi(), massPr); + protons.push_back(temp); + ProtonIndex.push_back(track.globalIndex()); + ProtonCharge.push_back(track.sign()); + if (track.sign() > 0) { + qaRegistry.fill(HIST("hNsigmaPtprotonTPC"), nTPCSigmaP[2], track.pt()); + ProtonTPCNsigma.push_back(nTPCSigmaP[2]); + } + if (track.sign() < 0) { + qaRegistry.fill(HIST("hNsigmaPtprotonTPC"), nTPCSigmaN[2], track.pt()); + ProtonTPCNsigma.push_back(nTPCSigmaN[2]); + } + if (track.hasTOF()) { + qaRegistry.fill(HIST("hNsigmaPtprotonTOF"), track.tofNSigmaPr(), track.pt()); + ProtonTOFNsigma.push_back(track.tofNSigmaPr()); + ProtonTOFHit.push_back(1); + } + if (!track.hasTOF()) { + ProtonTOFNsigma.push_back(999.0); + ProtonTOFHit.push_back(0); + } } - KaonTOFHit.push_back(KaonTOF); - } + } // track loop end + for (auto& v0 : V0s) { - if ((track.pt() < cMaxProtonPt && track.sign() > 0 && SelectionPID(track, strategyPIDProton, 2, nTPCSigmaP[2])) || (track.pt() < cMaxProtonPt && track.sign() < 0 && SelectionPID(track, strategyPIDProton, 2, nTPCSigmaN[2]))) { - ROOT::Math::PtEtaPhiMVector temp(track.pt(), track.eta(), track.phi(), massPr); - protons.push_back(temp); - ProtonIndex.push_back(track.globalIndex()); - ProtonCharge.push_back(track.sign()); - if (track.sign() > 0) { - qaRegistry.fill(HIST("hNsigmaPtprotonTPC"), nTPCSigmaP[2], track.pt()); - ProtonTPCNsigma.push_back(nTPCSigmaP[2]); + if (!SelectionV0(collision, v0)) { + continue; } - if (track.sign() < 0) { - qaRegistry.fill(HIST("hNsigmaPtprotonTPC"), nTPCSigmaN[2], track.pt()); - ProtonTPCNsigma.push_back(nTPCSigmaN[2]); + auto postrack = v0.template posTrack_as(); + auto negtrack = v0.template negTrack_as(); + double nTPCSigmaPos[1]{postrack.tpcNSigmaPi()}; + double nTPCSigmaNeg[1]{negtrack.tpcNSigmaPi()}; + if (ConfUseManualPIDdaughterPion) { + auto bgScalingPion = 1 / massPi; // momentum scaling? + if (BBPion.size() == 6) + nTPCSigmaPos[0] = updatePID(postrack, bgScalingPion, BBPion); + if (BBAntipion.size() == 6) + nTPCSigmaNeg[0] = updatePID(negtrack, bgScalingPion, BBAntipion); } - if (track.hasTOF()) { - qaRegistry.fill(HIST("hNsigmaPtprotonTOF"), track.tofNSigmaPr(), track.pt()); - ProtonTOFNsigma.push_back(track.tofNSigmaPr()); - ProtonTOFHit.push_back(1); + if (!isSelectedV0Daughter(postrack, 1, nTPCSigmaPos[0])) { + continue; } - if (!track.hasTOF()) { - ProtonTOFNsigma.push_back(999.0); - ProtonTOFHit.push_back(0); + if (!isSelectedV0Daughter(negtrack, -1, nTPCSigmaNeg[0])) { + continue; } + qaRegistry.fill(HIST("hInvMassk0"), v0.mK0Short(), v0.pt()); + ROOT::Math::PtEtaPhiMVector temp(v0.pt(), v0.eta(), v0.phi(), massK0s); + kshorts.push_back(temp); + KshortPosDaughIndex.push_back(postrack.globalIndex()); + KshortNegDaughIndex.push_back(negtrack.globalIndex()); } - } // track loop end - for (auto& v0 : V0s) { - if (!SelectionV0(collision, v0)) { - continue; - } - auto postrack = v0.template posTrack_as(); - auto negtrack = v0.template negTrack_as(); - double nTPCSigmaPos[1]{postrack.tpcNSigmaPi()}; - double nTPCSigmaNeg[1]{negtrack.tpcNSigmaPi()}; - if (ConfUseManualPIDdaughterPion) { - auto bgScalingPion = 1 / massPi; // momentum scaling? - if (BBPion.size() == 6) - nTPCSigmaPos[0] = updatePID(postrack, bgScalingPion, BBPion); - if (BBAntipion.size() == 6) - nTPCSigmaNeg[0] = updatePID(negtrack, bgScalingPion, BBAntipion); - } - if (!isSelectedV0Daughter(postrack, 1, nTPCSigmaPos[0])) { - continue; - } - if (!isSelectedV0Daughter(negtrack, -1, nTPCSigmaNeg[0])) { - continue; - } - qaRegistry.fill(HIST("hInvMassk0"), v0.mK0Short(), v0.pt()); - ROOT::Math::PtEtaPhiMVector temp(v0.pt(), v0.eta(), v0.phi(), massK0s); - kshorts.push_back(temp); - KshortPosDaughIndex.push_back(postrack.globalIndex()); - KshortNegDaughIndex.push_back(negtrack.globalIndex()); - } - - if (pions.size() != 0 && kaons.size() != 0 && kshorts.size() != 0) { - for (auto ipion = pions.begin(); ipion != pions.end(); ++ipion) { - for (auto ikaon = kaons.begin(); ikaon != kaons.end(); ++ikaon) { - auto i1 = std::distance(pions.begin(), ipion); - auto i2 = std::distance(kaons.begin(), ikaon); - if (PionIndex.at(i1) == KaonIndex.at(i2)) - continue; - for (auto ikshort = kshorts.begin(); ikshort != kshorts.end(); ++ikshort) { - auto i3 = std::distance(kshorts.begin(), ikshort); - if (PionIndex.at(i1) == KshortPosDaughIndex.at(i3)) - continue; - if (PionIndex.at(i1) == KshortNegDaughIndex.at(i3)) - continue; - KKs0Vector = kaons.at(i2) + kshorts.at(i3); - if (KKs0Vector.M() > cMaxMassKKs0) + if (pions.size() != 0 && kaons.size() != 0 && kshorts.size() != 0) { + for (auto ipion = pions.begin(); ipion != pions.end(); ++ipion) { + for (auto ikaon = kaons.begin(); ikaon != kaons.end(); ++ikaon) { + auto i1 = std::distance(pions.begin(), ipion); + auto i2 = std::distance(kaons.begin(), ikaon); + if (PionIndex.at(i1) == KaonIndex.at(i2)) continue; - F1Vector = KKs0Vector + pions.at(i1); - if (F1Vector.M() > cMaxMassF1) - continue; - if (F1Vector.Pt() < cMinF1Pt) - continue; - - // check if the pair is unlike or wrongsign - auto pairsign = 1; - if (PionCharge.at(i1) * KaonCharge.at(i2) > 0) { - qaRegistry.fill(HIST("hInvMassf1Like"), F1Vector.M(), F1Vector.Pt()); - pairsign = -1; - } - ROOT::Math::PtEtaPhiMVector temp(F1Vector.Pt(), F1Vector.Eta(), F1Vector.Phi(), F1Vector.M()); - f1resonance.push_back(temp); - f1resonanced1.push_back(pions.at(i1)); - f1resonanced2.push_back(kaons.at(i2)); - f1resonanced3.push_back(kshorts.at(i3)); - f1signal.push_back(pairsign); - f1kaonkshortmass.push_back(KKs0Vector.M()); - F1PionIndex.push_back(PionIndex.at(i1)); - F1KaonIndex.push_back(KaonIndex.at(i2)); - F1KshortDaughterPositiveIndex.push_back(KshortPosDaughIndex.at(i3)); - F1KshortDaughterNegativeIndex.push_back(KshortNegDaughIndex.at(i3)); - PionTOFHitFinal.push_back(PionTOFHit.at(i1)); // Pion TOF Hit - KaonTOFHitFinal.push_back(KaonTOFHit.at(i2)); // Kaon TOF Hit - if (pairsign == 1) { - qaRegistry.fill(HIST("hInvMassf1"), F1Vector.M(), F1Vector.Pt()); - numberF1 = numberF1 + 1; - for (auto iproton = protons.begin(); iproton != protons.end(); ++iproton) { - auto i4 = std::distance(protons.begin(), iproton); - ProtonVectorDummy = protons.at(i4); - if (numberF1 == 1) { - //////////// Fill final proton information after pairing////////// - ROOT::Math::PtEtaPhiMVector temp(ProtonVectorDummy.Pt(), ProtonVectorDummy.Eta(), ProtonVectorDummy.Phi(), massPr); - protonsfinal.push_back(temp); // 4 vector - ProtonChargeFinal.push_back(ProtonCharge.at(i4)); // Charge - ProtonTOFHitFinal.push_back(ProtonTOFHit.at(i4)); // TOF Hit - ProtonTOFNsigmaFinal.push_back(ProtonTOFNsigma.at(i4)); // Nsigma TOF - ProtonTPCNsigmaFinal.push_back(ProtonTPCNsigma.at(i4)); // Nsigma TPC - F1ProtonIndex.push_back(ProtonIndex.at(i4)); // proton index for share track - } - - if ((ProtonIndex.at(i4) == PionIndex.at(i1)) || (ProtonIndex.at(i4) == KaonIndex.at(i2)) || (ProtonIndex.at(i4) == KshortPosDaughIndex.at(i3)) || (ProtonIndex.at(i4) == KshortNegDaughIndex.at(i3))) { - continue; - } - - kstar = getkstar(F1Vector, *iproton); - qaRegistry.fill(HIST("hkstarDist"), kstar); - if (kstar > cMaxRelMom) - continue; - qaRegistry.fill(HIST("hInvMassf1kstar"), F1Vector.M(), F1Vector.Pt(), kstar); - keepEventF1Proton = true; + for (auto ikshort = kshorts.begin(); ikshort != kshorts.end(); ++ikshort) { + auto i3 = std::distance(kshorts.begin(), ikshort); + if (PionIndex.at(i1) == KshortPosDaughIndex.at(i3)) + continue; + if (PionIndex.at(i1) == KshortNegDaughIndex.at(i3)) + continue; + KKs0Vector = kaons.at(i2) + kshorts.at(i3); + if (KKs0Vector.M() > cMaxMassKKs0) + continue; + F1Vector = KKs0Vector + pions.at(i1); + if (F1Vector.M() > cMaxMassF1) + continue; + if (F1Vector.Pt() < cMinF1Pt) + continue; + + // check if the pair is unlike or wrongsign + auto pairsign = 1; + if (PionCharge.at(i1) * KaonCharge.at(i2) > 0) { + qaRegistry.fill(HIST("hInvMassf1Like"), F1Vector.M(), F1Vector.Pt()); + pairsign = -1; } + ROOT::Math::PtEtaPhiMVector temp(F1Vector.Pt(), F1Vector.Eta(), F1Vector.Phi(), F1Vector.M()); + f1resonance.push_back(temp); + f1resonanced1.push_back(pions.at(i1)); + f1resonanced2.push_back(kaons.at(i2)); + f1resonanced3.push_back(kshorts.at(i3)); + f1signal.push_back(pairsign); + f1kaonkshortmass.push_back(KKs0Vector.M()); + F1PionIndex.push_back(PionIndex.at(i1)); + F1KaonIndex.push_back(KaonIndex.at(i2)); + F1KshortDaughterPositiveIndex.push_back(KshortPosDaughIndex.at(i3)); + F1KshortDaughterNegativeIndex.push_back(KshortNegDaughIndex.at(i3)); + PionTOFHitFinal.push_back(PionTOFHit.at(i1)); // Pion TOF Hit + KaonTOFHitFinal.push_back(KaonTOFHit.at(i2)); // Kaon TOF Hit + PionTPCFinal.push_back(PionTPC.at(i1)); // Pion TPC + KaonTPCFinal.push_back(KaonTPC.at(i2)); // Kaon TPC + KaonTPCPionHypoFinal.push_back(KaonTPCPionHypo.at(i2)); // Kaon TPC + if (pairsign == 1) { + qaRegistry.fill(HIST("hInvMassf1"), F1Vector.M(), F1Vector.Pt()); + numberF1 = numberF1 + 1; + for (auto iproton = protons.begin(); iproton != protons.end(); ++iproton) { + auto i4 = std::distance(protons.begin(), iproton); + if (ProtonIndex.at(i4) == PionIndex.at(i1)) + continue; + if (ProtonIndex.at(i4) == KaonIndex.at(i2)) + continue; + if (ProtonIndex.at(i4) == KshortPosDaughIndex.at(i3)) + continue; + if (ProtonIndex.at(i4) == KshortNegDaughIndex.at(i3)) + continue; + kstar = getkstar(F1Vector, *iproton); + qaRegistry.fill(HIST("hkstarDist"), kstar); + if (kstar > cMaxRelMom) { + continue; + } + qaRegistry.fill(HIST("hInvMassf1kstar"), F1Vector.M(), F1Vector.Pt(), kstar); + keepEventF1Proton = true; + /*ProtonVectorDummy = protons.at(i4); + if (numberF1 == 1 && keepEventF1Proton) { + //////////// Fill final proton information after pairing////////// + ROOT::Math::PtEtaPhiMVector temp(ProtonVectorDummy.Pt(), ProtonVectorDummy.Eta(), ProtonVectorDummy.Phi(), massPr); + protonsfinal.push_back(temp); // 4 vector + ProtonChargeFinal.push_back(ProtonCharge.at(i4)); // Charge + ProtonTOFHitFinal.push_back(ProtonTOFHit.at(i4)); // TOF Hit + ProtonTOFNsigmaFinal.push_back(ProtonTOFNsigma.at(i4)); // Nsigma TOF + ProtonTPCNsigmaFinal.push_back(ProtonTPCNsigma.at(i4)); // Nsigma TPC + F1ProtonIndex.push_back(ProtonIndex.at(i4)); // proton index for share track + }*/ + } + } // pair sign } } } @@ -758,7 +816,8 @@ struct f1protonreducedtable { qaRegistry.fill(HIST("hEventstat"), 1.5); if (keepEventF1Proton) { qaRegistry.fill(HIST("hEventstat"), 2.5); - auto eventspherocity = ComputeSpherocity(tracks, trackSphMin, trackSphDef); + auto eventspherocity = 0.0; + // ComputeSpherocity(tracks, trackSphMin, trackSphDef); /////////// Fill collision table/////////////// redf1pevents(bc.globalBC(), currentRunNumber, bc.timestamp(), collision.posZ(), collision.numContrib(), eventspherocity); auto indexEvent = redf1pevents.lastIndex(); @@ -769,13 +828,13 @@ struct f1protonreducedtable { F1d1dummy = f1resonanced1.at(i5); F1d2dummy = f1resonanced2.at(i5); F1d3dummy = f1resonanced3.at(i5); - f1track(indexEvent, f1signal.at(i5), F1VectorDummy.Px(), F1VectorDummy.Py(), F1VectorDummy.Pz(), F1d1dummy.Px(), F1d1dummy.Py(), F1d1dummy.Pz(), F1d2dummy.Px(), F1d2dummy.Py(), F1d2dummy.Pz(), F1d3dummy.Px(), F1d3dummy.Py(), F1d3dummy.Pz(), PionTOFHitFinal.at(i5), KaonTOFHitFinal.at(i5), F1VectorDummy.M(), f1kaonkshortmass.at(i5), F1PionIndex.at(i5), F1KaonIndex.at(i5), F1KshortDaughterPositiveIndex.at(i5), F1KshortDaughterNegativeIndex.at(i5)); + f1track(indexEvent, f1signal.at(i5), F1VectorDummy.Px(), F1VectorDummy.Py(), F1VectorDummy.Pz(), F1d1dummy.Px(), F1d1dummy.Py(), F1d1dummy.Pz(), F1d2dummy.Px(), F1d2dummy.Py(), F1d2dummy.Pz(), F1d3dummy.Px(), F1d3dummy.Py(), F1d3dummy.Pz(), PionTOFHitFinal.at(i5), KaonTOFHitFinal.at(i5), PionTPCFinal.at(i5), KaonTPCFinal.at(i5), KaonTPCPionHypoFinal.at(i5), F1VectorDummy.M(), f1kaonkshortmass.at(i5), F1PionIndex.at(i5), F1KaonIndex.at(i5), F1KshortDaughterPositiveIndex.at(i5), F1KshortDaughterNegativeIndex.at(i5)); } //// Fill track table for proton////////////////// - for (auto iproton = protonsfinal.begin(); iproton != protonsfinal.end(); ++iproton) { - auto i6 = std::distance(protonsfinal.begin(), iproton); - ProtonVectorDummy2 = protonsfinal.at(i6); - protontrack(indexEvent, ProtonChargeFinal.at(i6), ProtonVectorDummy2.Px(), ProtonVectorDummy2.Py(), ProtonVectorDummy2.Pz(), ProtonTPCNsigmaFinal.at(i6), ProtonTOFHitFinal.at(i6), ProtonTOFNsigmaFinal.at(i6), F1ProtonIndex.at(i6)); + for (auto iproton = protons.begin(); iproton != protons.end(); ++iproton) { + auto i6 = std::distance(protons.begin(), iproton); + ProtonVectorDummy2 = protons.at(i6); + protontrack(indexEvent, ProtonCharge.at(i6), ProtonVectorDummy2.Px(), ProtonVectorDummy2.Py(), ProtonVectorDummy2.Pz(), ProtonTPCNsigma.at(i6), ProtonTOFHit.at(i6), ProtonTOFNsigma.at(i6), ProtonIndex.at(i6)); } } } diff --git a/PWGLF/TableProducer/Resonances/resonanceInitializer.cxx b/PWGLF/TableProducer/Resonances/resonanceInitializer.cxx new file mode 100644 index 00000000000..da010f6ea59 --- /dev/null +++ b/PWGLF/TableProducer/Resonances/resonanceInitializer.cxx @@ -0,0 +1,1704 @@ +// 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 resonanceInitializer.cxx +/// \brief Initializes variables for the resonance candidate producers +/// \author Bong-Hwi Lim +/// + +#include +#include +#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/Core/EventPlaneHelper.h" +#include "Framework/ASoAHelpers.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFResonanceTables.h" +#include "PWGLF/Utils/collisionCuts.h" +#include "ReconstructionDataFormats/Track.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "CommonConstants/MathConstants.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; +using namespace o2::constants::math; +using namespace o2::aod::rctsel; + +/// Initializer for the resonance candidate producers +struct ResonanceInitializer { + SliceCache cache; + int mRunNumber; + int multEstimator; + float dBz; + Service ccdb; + Service pdg; + + Produces resoCollisions; + Produces resoCollisionColls; + Produces resoMCCollisions; + Produces resoSpheroCollisions; + Produces resoEvtPlCollisions; + Produces reso2trks; + Produces resoTrackTracks; + Produces reso2microtrks; + Produces resoMicroTrackTracks; + Produces reso2v0s; + Produces resoV0V0s; + Produces reso2cascades; + Produces resoCascadeCascades; + Produces reso2mctracks; + Produces reso2mcparents; + Produces reso2mcv0s; + Produces reso2mccascades; + + // CCDB options + Configurable ccdbURL{"ccdbURL", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + + Configurable cfgFatalWhenNull{"cfgFatalWhenNull", true, "Fatal when null on ccdb access"}; + Configurable cfgFillMicroTracks{"cfgFillMicroTracks", false, "Fill micro tracks"}; + Configurable cfgBypassTrackFill{"cfgBypassTrackFill", false, "Bypass track fill"}; + Configurable cfgBypassCollIndexFill{"cfgBypassCollIndexFill", false, "Bypass collision index fill"}; + Configurable cfgBypassTrackIndexFill{"cfgBypassTrackIndexFill", false, "Bypass track index fill"}; + + // Configurables + Configurable dBzInput{"dBzInput", -999, "bz field, -999 is automatic"}; + Configurable cfgFillQA{"cfgFillQA", false, "Fill QA histograms"}; + Configurable cfgBypassCCDB{"cfgBypassCCDB", true, "Bypass loading CCDB part to save CPU time and memory"}; // will be affected to b_z value. + + // Track filter from tpcSkimsTableCreator + Configurable trackSelection{"trackSelection", 0, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; + Configurable trackSphDef{"trackSphDef", 0, "Spherocity Definition: |pT| = 1 -> 0, otherwise -> 1"}; + Configurable trackSphMin{"trackSphMin", 10, "Number of tracks for Spherocity Calculation"}; + + // EventCorrection for MC + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 0.01, 0.1, 1.0, 5.0, 10., 15., 20., 30., 40., 50., 60., 70., 80., 90., 100.0, 105.}, "Binning of the centrality axis"}; + + /// Event cuts + o2::analysis::CollisonCuts colCuts; + + struct : ConfigurableGroup { + Configurable cfgEvtZvtx{"cfgEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; + Configurable cfgEvtOccupancyInTimeRangeMax{"cfgEvtOccupancyInTimeRangeMax", -1, "Evt sel: maximum track occupancy"}; + Configurable cfgEvtOccupancyInTimeRangeMin{"cfgEvtOccupancyInTimeRangeMin", -1, "Evt sel: minimum track occupancy"}; + Configurable cfgEvtTriggerCheck{"cfgEvtTriggerCheck", false, "Evt sel: check for trigger"}; + Configurable cfgEvtOfflineCheck{"cfgEvtOfflineCheck", true, "Evt sel: check for offline selection"}; + Configurable cfgEvtTriggerTVXSel{"cfgEvtTriggerTVXSel", false, "Evt sel: triggerTVX selection (MB)"}; + Configurable cfgEvtTFBorderCut{"cfgEvtTFBorderCut", false, "Evt sel: apply TF border cut"}; + Configurable cfgEvtUseITSTPCvertex{"cfgEvtUseITSTPCvertex", false, "Evt sel: use at lease on ITS-TPC track for vertexing"}; + Configurable cfgEvtZvertexTimedifference{"cfgEvtZvertexTimedifference", false, "Evt sel: apply Z-vertex time difference"}; + Configurable cfgEvtPileupRejection{"cfgEvtPileupRejection", false, "Evt sel: apply pileup rejection"}; + Configurable cfgEvtNoITSROBorderCut{"cfgEvtNoITSROBorderCut", false, "Evt sel: apply NoITSRO border cut"}; + Configurable cfgEvtCollInTimeRangeStandard{"cfgEvtCollInTimeRangeStandard", false, "Evt sel: apply NoCollInTimeRangeStandard"}; + Configurable cfgEvtRun2AliEventCuts{"cfgEvtRun2AliEventCuts", true, "Evt sel: apply Run2 AliEventCuts"}; + Configurable cfgEvtRun2INELgtZERO{"cfgEvtRun2INELgtZERO", false, "Evt sel: apply Run2 INELgtZERO"}; + Configurable cfgEvtUseRCTFlagChecker{"cfgEvtUseRCTFlagChecker", false, "Evt sel: use RCT flag checker"}; + Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; + Configurable cfgEvtRCTFlagCheckerZDCCheck{"cfgEvtRCTFlagCheckerZDCCheck", false, "Evt sel: RCT flag checker ZDC check"}; + Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", false, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } EventCuts; + RCTFlagsChecker rctChecker; + + Configurable cfgMultName{"cfgMultName", "FT0M", "The name of multiplicity estimator"}; + + // Qvector configuration + Configurable cfgBypassQvec{"cfgBypassQvec", true, "Bypass for qvector task"}; + Configurable cfgEvtPl{"cfgEvtPl", 40500, "Configuration of three subsystems for the event plane and its resolution, 10000*RefA + 100*RefB + S, where FT0C:0, FT0A:1, FT0M:2, FV0A:3, BPos:5, BNeg:6"}; + + // Pre-selection cuts + Configurable cfgCutEta{"cfgCutEta", 0.8f, "Eta range for tracks"}; + Configurable pidnSigmaPreSelectionCut{"pidnSigmaPreSelectionCut", 5.0f, "TPC and TOF PID cut (loose, improve performance)"}; + Configurable mincrossedrows{"mincrossedrows", 70, "min crossed rows"}; + + /// DCA Selections for V0 + // DCAr to PV + Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 2.0, "Track DCAr cut to PV Maximum"}; + Configurable cMinV0PosDCArToPVcut{"cMinV0PosDCArToPVcut", 0.05f, "V0 Positive Track DCAr cut to PV Minimum"}; // Pre-selection + Configurable cMinV0NegDCArToPVcut{"cMinV0NegDCArToPVcut", 0.05f, "V0 Negative Track DCAr cut to PV Minimum"}; // Pre-selection + // DCAz to PV + Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; + Configurable cMinDCAzToPVcut{"cMinDCAzToPVcut", 0.0, "Track DCAz cut to PV Minimum"}; + + Configurable cMinV0Radius{"cMinV0Radius", 0.0, "Minimum V0 radius from PV"}; + Configurable cMaxV0Radius{"cMaxV0Radius", 200.0, "Maximum V0 radius from PV"}; + Configurable cMinV0CosPA{"cMinV0CosPA", 0.995, "Minimum V0 CosPA to PV"}; + + /// DCA Selections for Cascades + Configurable cfgMinCrossedRowsCascBach{"cfgMinCrossedRowsCascBach", 70, "min crossed rows for bachelor track from cascade"}; + Configurable cMinCascBachDCArToPVcut{"cMinCascBachDCArToPVcut", 0.05f, "Cascade Bachelor Track DCAr cut to PV Minimum"}; // Pre-selection + Configurable cMaxCascBachDCArToPVcut{"cMaxCascBachDCArToPVcut", 999.0f, "Cascade Bachelor Track DCAr cut to PV Maximum"}; // Pre-selection + Configurable cMaxCascDCAV0Daughters{"cMaxCascDCAV0Daughters", 1.6, "Cascade DCA between V0 daughters Maximum"}; + Configurable cMaxCascDCACascDaughters{"cMaxCascDCACascDaughters", 1.6, "Cascade DCA between Casc daughters Maximum"}; + Configurable cMinCascCosPA{"cMinCascCosPA", 0.97, "Minimum Cascade CosPA to PV"}; + Configurable cMinCascV0CosPA{"cMinCascV0CosPA", 0.97, "Minimum Cascade V0 CosPA to PV"}; + Configurable cMaxCascV0Radius{"cMaxCascV0Radius", 200.0, "Maximum Cascade V0 radius from PV"}; + Configurable cMinCascV0Radius{"cMinCascV0Radius", 0.0, "Minimum Cascade V0 radius from PV"}; + Configurable cMaxCascRadius{"cMaxCascRadius", 200.0, "Maximum Cascade radius from PV"}; + Configurable cMinCascRadius{"cMinCascRadius", 0.0, "Minimum Cascade radius from PV"}; + Configurable cCascMassResol{"cCascMassResol", 999, "Cascade mass resolution"}; + + // Derived dataset selections + struct : ConfigurableGroup { + Configurable cfgFillPionTracks{"cfgFillPionTracks", false, "Fill pion tracks"}; + Configurable cfgFillKaonTracks{"cfgFillKaonTracks", false, "Fill kaon tracks"}; + Configurable cfgFillProtonTracks{"cfgFillProtonTracks", false, "Fill proton tracks"}; + Configurable cfgFillPionMicroTracks{"cfgFillPionMicroTracks", false, "Fill pion micro tracks"}; + Configurable cfgFillKaonMicroTracks{"cfgFillKaonMicroTracks", false, "Fill kaon micro tracks"}; + Configurable cfgFillProtonMicroTracks{"cfgFillProtonMicroTracks", false, "Fill proton micro tracks"}; + Configurable cfgFillK0s{"cfgFillK0s", false, "Fill K0s"}; + Configurable cfgFillLambda0{"cfgFillLambda0", false, "Fill Lambda0"}; + Configurable cfgFillXi0{"cfgFillXi0", false, "Fill Xi0"}; + Configurable cfgFillOmega0{"cfgFillOmega0", false, "Fill Omega0"}; + } FilterForDerivedTables; + + // Secondary cuts + // Secondary Selection for K0s + struct : ConfigurableGroup { + Configurable cfgSecondaryRequire{"cfgSecondaryRequire", true, "Secondary cuts on/off"}; + Configurable cfgSecondaryArmenterosCut{"cfgSecondaryArmenterosCut", true, "cut on Armenteros-Podolanski graph"}; + Configurable cfgSecondaryCrossMassHypothesisCut{"cfgSecondaryCrossMassHypothesisCut", false, "Apply cut based on the lambda mass hypothesis"}; + + Configurable cfgByPassDauPIDSelection{"cfgByPassDauPIDSelection", true, "Bypass Daughters PID selection"}; + Configurable cfgSecondaryDauDCAMax{"cfgSecondaryDauDCAMax", 0.2, "Maximum DCA Secondary daughters to PV"}; + Configurable cfgSecondaryDauPosDCAtoPVMin{"cfgSecondaryDauPosDCAtoPVMin", 0.0, "Minimum DCA Secondary positive daughters to PV"}; + Configurable cfgSecondaryDauNegDCAtoPVMin{"cfgSecondaryDauNegDCAtoPVMin", 0.0, "Minimum DCA Secondary negative daughters to PV"}; + + Configurable cfgSecondaryPtMin{"cfgSecondaryPtMin", 0.f, "Minimum transverse momentum of Secondary"}; + Configurable cfgSecondaryRapidityMax{"cfgSecondaryRapidityMax", 0.5, "Maximum rapidity of Secondary"}; + Configurable cfgSecondaryRadiusMin{"cfgSecondaryRadiusMin", 0.0, "Minimum transverse radius of Secondary"}; + Configurable cfgSecondaryRadiusMax{"cfgSecondaryRadiusMax", 999.9, "Maximum transverse radius of Secondary"}; + Configurable cfgSecondaryCosPAMin{"cfgSecondaryCosPAMin", 0.998, "Mininum cosine pointing angle of Secondary"}; + Configurable cfgSecondaryDCAtoPVMax{"cfgSecondaryDCAtoPVMax", 0.4, "Maximum DCA Secondary to PV"}; + Configurable cfgSecondaryProperLifetimeMax{"cfgSecondaryProperLifetimeMax", 20., "Maximum Secondary Lifetime"}; + Configurable cfgSecondaryparamArmenterosCut{"cfgSecondaryparamArmenterosCut", 0.2, "parameter for Armenteros Cut"}; + Configurable cfgSecondaryMassWindow{"cfgSecondaryMassWindow", 0.03, "Secondary inv mass selection window"}; + Configurable cfgSecondaryCrossMassCutWindow{"cfgSecondaryCrossMassCutWindow", 0.05, "Secondary inv mass selection window with (anti)lambda hypothesis"}; + } SecondaryCuts; + + HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Pre-filters for efficient process + // Filter tofPIDFilter = aod::track::tofExpMom < 0.f || ((aod::track::tofExpMom > 0.f) && ((nabs(aod::pidtof::tofNSigmaPi) < pidnSigmaPreSelectionCut) || (nabs(aod::pidtof::tofNSigmaKa) < pidnSigmaPreSelectionCut) || (nabs(aod::pidtof::tofNSigmaPr) < pidnSigmaPreSelectionCut))); // TOF + // Filter tpcPIDFilter = nabs(aod::pidtpc::tpcNSigmaPi) < pidnSigmaPreSelectionCut || nabs(aod::pidtpc::tpcNSigmaKa) < pidnSigmaPreSelectionCut || nabs(aod::pidtpc::tpcNSigmaPr) < pidnSigmaPreSelectionCut; // TPC + Filter trackFilter = (trackSelection.node() == 0) || // from tpcSkimsTableCreator + ((trackSelection.node() == 1) && requireGlobalTrackInFilter()) || + ((trackSelection.node() == 2) && requireGlobalTrackWoPtEtaInFilter()) || + ((trackSelection.node() == 3) && requireGlobalTrackWoDCAInFilter()) || + ((trackSelection.node() == 4) && requireQualityTracksInFilter()) || + ((trackSelection.node() == 5) && requireTrackCutInFilter(TrackSelectionFlags::kInAcceptanceTracks)); + Filter trackEtaFilter = nabs(aod::track::eta) < cfgCutEta; // Eta cut + + EventPlaneHelper helperEP; + + int evtPlRefAId = static_cast(cfgEvtPl / 10000); + int evtPlRefBId = static_cast((cfgEvtPl - evtPlRefAId * 10000) / 100); + int evtPlDetId = cfgEvtPl - evtPlRefAId * 10000 - evtPlRefBId * 100; + + // MC Resonance parent filter + Partition selectedMCParticles = (nabs(aod::mcparticle::pdgCode) == 313) // K* + || (nabs(aod::mcparticle::pdgCode) == 323) // K*pm + || (nabs(aod::mcparticle::pdgCode) == 333) // phi + || (nabs(aod::mcparticle::pdgCode) == 9010221) // f_0(980) + || (nabs(aod::mcparticle::pdgCode) == 10221) // f_0(1370) + || (nabs(aod::mcparticle::pdgCode) == 9030221) // f_0(1500) + || (nabs(aod::mcparticle::pdgCode) == 10331) // f_0(1710) + || (nabs(aod::mcparticle::pdgCode) == 20223) // f_1(1285) + || (nabs(aod::mcparticle::pdgCode) == 20333) // f_1(1420) + || (nabs(aod::mcparticle::pdgCode) == 335) // f_1(1525) + || (nabs(aod::mcparticle::pdgCode) == 113) // rho(770) + || (nabs(aod::mcparticle::pdgCode) == 213) // rho(770)pm + || (nabs(aod::mcparticle::pdgCode) == 3224) // Sigma(1385)+ + || (nabs(aod::mcparticle::pdgCode) == 102134) // Lambda(1520) + || (nabs(aod::mcparticle::pdgCode) == 3324) // Xi(1530)0 + || (nabs(aod::mcparticle::pdgCode) == 10323) // K1(1270)+ + || (nabs(aod::mcparticle::pdgCode) == 123314) // Xi(1820)0 + || (nabs(aod::mcparticle::pdgCode) == 123324); // Xi(1820)-0 + + using ResoEvents = soa::Join; + using ResoRun2Events = soa::Join; + using ResoEventsMC = soa::Join; + using ResoRun2EventsMC = soa::Join; + using ResoTracks = aod::Reso2TracksPIDExt; + using ResoTracksMC = soa::Join; + using ResoV0s = aod::V0Datas; + using ResoV0sMC = soa::Join; + using ResoCascades = aod::CascDatas; + using ResoCascadesMC = soa::Join; + using BCsWithRun2Info = soa::Join; + + template + bool filterMicroTrack(T const& track) + { + // if no selection is requested, return true + if (!FilterForDerivedTables.cfgFillPionMicroTracks && !FilterForDerivedTables.cfgFillKaonMicroTracks && !FilterForDerivedTables.cfgFillProtonMicroTracks) + return true; + if (FilterForDerivedTables.cfgFillPionMicroTracks) { + if (std::abs(track.tpcNSigmaPi()) < pidnSigmaPreSelectionCut) + return true; + } + if (FilterForDerivedTables.cfgFillKaonMicroTracks) { + if (std::abs(track.tpcNSigmaKa()) < pidnSigmaPreSelectionCut) + return true; + } + if (FilterForDerivedTables.cfgFillProtonMicroTracks) { + if (std::abs(track.tpcNSigmaPr()) < pidnSigmaPreSelectionCut) + return true; + } + return false; + } + + template + bool filterTrack(T const& track) + { + // if no selection is requested, return true + if (!FilterForDerivedTables.cfgFillPionTracks && !FilterForDerivedTables.cfgFillKaonTracks && !FilterForDerivedTables.cfgFillProtonTracks) + return true; + if (FilterForDerivedTables.cfgFillPionTracks) { + if (std::abs(track.tpcNSigmaPi()) < pidnSigmaPreSelectionCut) + return true; + } + if (FilterForDerivedTables.cfgFillKaonTracks) { + if (std::abs(track.tpcNSigmaKa()) < pidnSigmaPreSelectionCut) + return true; + } + if (FilterForDerivedTables.cfgFillProtonTracks) { + if (std::abs(track.tpcNSigmaPr()) < pidnSigmaPreSelectionCut) + return true; + } + return false; + } + + template + bool filterV0(CollisionType const& collision, V0Type const& v0) + { + // if no selection is requested, return true + if (!FilterForDerivedTables.cfgFillK0s && !FilterForDerivedTables.cfgFillLambda0) + return true; + if (FilterForDerivedTables.cfgFillK0s) { + if (!SecondaryCuts.cfgSecondaryRequire) + return true; + if (v0.dcaV0daughters() > SecondaryCuts.cfgSecondaryDauDCAMax) + return false; + if (std::abs(v0.dcapostopv()) < SecondaryCuts.cfgSecondaryDauPosDCAtoPVMin) + return false; + if (std::abs(v0.dcanegtopv()) < SecondaryCuts.cfgSecondaryDauNegDCAtoPVMin) + return false; + if (v0.pt() < SecondaryCuts.cfgSecondaryPtMin) + return false; + if (std::fabs(v0.yK0Short()) > SecondaryCuts.cfgSecondaryRapidityMax) + return false; + if (v0.v0radius() < SecondaryCuts.cfgSecondaryRadiusMin || v0.v0radius() > SecondaryCuts.cfgSecondaryRadiusMax) + return false; + if (v0.dcav0topv() > SecondaryCuts.cfgSecondaryDCAtoPVMax) + return false; + if (v0.v0cosPA() < SecondaryCuts.cfgSecondaryCosPAMin) + return false; + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassK0Short > SecondaryCuts.cfgSecondaryProperLifetimeMax) + return false; + if (v0.qtarm() < SecondaryCuts.cfgSecondaryparamArmenterosCut * std::abs(v0.alpha())) + return false; + if (std::fabs(v0.mK0Short() - MassK0Short) > SecondaryCuts.cfgSecondaryMassWindow) + return false; + if (SecondaryCuts.cfgSecondaryCrossMassHypothesisCut && + ((std::fabs(v0.mLambda() - MassLambda0) < SecondaryCuts.cfgSecondaryCrossMassCutWindow) || (std::fabs(v0.mAntiLambda() - MassLambda0Bar) < SecondaryCuts.cfgSecondaryCrossMassCutWindow))) + return false; + return true; + } + if (FilterForDerivedTables.cfgFillLambda0) { + if (!SecondaryCuts.cfgSecondaryRequire) + return true; + if (v0.dcaV0daughters() > SecondaryCuts.cfgSecondaryDauDCAMax) + return false; + if (std::abs(v0.dcapostopv()) < SecondaryCuts.cfgSecondaryDauPosDCAtoPVMin) + return false; + if (std::abs(v0.dcanegtopv()) < SecondaryCuts.cfgSecondaryDauNegDCAtoPVMin) + return false; + if (v0.pt() < SecondaryCuts.cfgSecondaryPtMin) + return false; + if (std::fabs(v0.yLambda()) > SecondaryCuts.cfgSecondaryRapidityMax) + return false; + if (v0.v0radius() < SecondaryCuts.cfgSecondaryRadiusMin || v0.v0radius() > SecondaryCuts.cfgSecondaryRadiusMax) + return false; + if (v0.dcav0topv() > SecondaryCuts.cfgSecondaryDCAtoPVMax) + return false; + if (v0.v0cosPA() < SecondaryCuts.cfgSecondaryCosPAMin) + return false; + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassLambda0 > SecondaryCuts.cfgSecondaryProperLifetimeMax) + return false; + if (v0.qtarm() < SecondaryCuts.cfgSecondaryparamArmenterosCut * std::abs(v0.alpha())) + return false; + if (std::fabs(v0.mLambda() - MassLambda0) < SecondaryCuts.cfgSecondaryMassWindow) + return false; + if (SecondaryCuts.cfgSecondaryCrossMassHypothesisCut && (std::fabs(v0.mK0Short() - MassK0Short) < SecondaryCuts.cfgSecondaryCrossMassCutWindow)) + return false; + return true; + } + return false; + } + + template + bool filterCasc(T const& /*casc*/) + { + // if no selection is requested, return true + if (!FilterForDerivedTables.cfgFillXi0 && !FilterForDerivedTables.cfgFillOmega0) + return true; + if (FilterForDerivedTables.cfgFillXi0) { + // TODO: Implement, but cascades are very rare, do we need this? + return true; + } + if (FilterForDerivedTables.cfgFillOmega0) { + // TODO: Implement, but cascades are very rare, do we need this? + return true; + } + return false; + } + template + bool isMicroTrackSelected(CollisionType const&, TrackType const& track) + { + // Micro track selection + // DCAxy cut + if (std::fabs(track.dcaXY()) > cMaxDCArToPVcut) + return false; + // DCAz cut + if (std::fabs(track.dcaZ()) > cMaxDCAzToPVcut || std::fabs(track.dcaZ()) < cMinDCAzToPVcut) + return false; + return true; + } + + template + bool isTrackSelected(CollisionType const&, TrackType const& track) + { + // Track selection + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodTrackIndices"), 0.5); + // MC case can be handled here + if constexpr (isMC) { + // MC check + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodMCTrackIndices"), 0.5); + } + // DCAxy cut + if (std::fabs(track.dcaXY()) > cMaxDCArToPVcut) + return false; + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodTrackIndices"), 1.5); + // DCAz cut + if (std::fabs(track.dcaZ()) > cMaxDCAzToPVcut || std::fabs(track.dcaZ()) < cMinDCAzToPVcut) + return false; + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodTrackIndices"), 2.5); + + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodTrackIndices"), 7.5); + return true; + } + + template + bool isV0Selected(CollisionType const&, V0Type const& v0, TrackType const&) + { + // V0 selection + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodV0Indices"), 0.5); + + auto postrack = v0.template posTrack_as(); + auto negtrack = v0.template negTrack_as(); + + if (postrack.tpcNClsCrossedRows() < mincrossedrows) + return false; + if (negtrack.tpcNClsCrossedRows() < mincrossedrows) + return false; + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodV0Indices"), 1.5); + + if (std::fabs(postrack.dcaXY()) < cMinV0PosDCArToPVcut) + return false; + if (std::fabs(negtrack.dcaXY()) < cMinV0NegDCArToPVcut) + return false; + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodV0Indices"), 2.5); + + if ((v0.v0radius() > cMaxV0Radius) || (v0.v0radius() < cMinV0Radius)) + return false; + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodV0Indices"), 3.5); + if (v0.v0cosPA() < cMinV0CosPA) + return false; + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodV0Indices"), 4.5); + + // MC case can be handled here + if constexpr (isMC) { + // MC check + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodMCV0Indices"), 0.5); + } + return true; + } + + template + bool isCascSelected(CollisionType const& collision, CascType const& casc, TrackType const&) + { + // V0 selection + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodCascIndices"), 0.5); + + auto trackBach = casc.template bachelor_as(); + // auto trackPos = casc.template posTrack_as(); + // auto trackNeg = casc.template negTrack_as(); + + // track cuts + if (trackBach.tpcNClsCrossedRows() < cfgMinCrossedRowsCascBach) + return false; + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodCascIndices"), 1.5); + + if (std::fabs(trackBach.dcaXY()) < cMinCascBachDCArToPVcut) + return false; + if (std::fabs(trackBach.dcaXY()) > cMaxCascBachDCArToPVcut) + return false; + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodCascIndices"), 2.5); + + // DCA daugthers + if (casc.dcaV0daughters() > cMaxCascDCAV0Daughters) + return false; + if (casc.dcacascdaughters() > cMaxCascDCACascDaughters) + return false; + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodCascIndices"), 3.5); + + // CPA cuts + if (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cMinCascCosPA) + return false; + if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cMinCascV0CosPA) + return false; + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodCascIndices"), 4.5); + + // V0 radius + auto v0radius = casc.v0radius(); + if ((v0radius > cMaxCascV0Radius) || (v0radius < cMinCascV0Radius)) + return false; + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodCascIndices"), 5.5); + + // Casc radius + auto cascradius = casc.cascradius(); + if ((cascradius > cMaxCascRadius) || (cascradius < cMinCascRadius)) + return false; + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodCascIndices"), 6.5); + + // Casc mass + auto cascMass = casc.mXi(); + if (std::abs(cascMass - MassXiMinus) > cCascMassResol) + return false; + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodCascIndices"), 7.5); + + // MC case can be handled here + if constexpr (isMC) { + // MC check + if (cfgFillQA) + qaRegistry.fill(HIST("hGoodMCCascIndices"), 0.5); + } + return true; + } + + // Check if the collision is INEL>0 + template + bool isTrueINEL0(MCColl const& /*mccoll*/, MCPart const& mcparts) + { + for (auto const& mcparticle : mcparts) { + if (!mcparticle.isPhysicalPrimary()) + continue; + auto p = pdg->GetParticle(mcparticle.pdgCode()); + if (p != nullptr) { + if (std::abs(p->Charge()) >= 3) { + if (std::abs(mcparticle.eta()) < 1) + return true; + } + } + } + return false; + } + + // Centralicity estimator selection + template + float centEst(ResoColl ResoEvents) + { + float returnValue = -999.0; + switch (multEstimator) { + case 0: + returnValue = ResoEvents.centFT0M(); + break; + case 1: + returnValue = ResoEvents.centFT0C(); + break; + case 2: + returnValue = ResoEvents.centFT0A(); + break; + default: + returnValue = ResoEvents.centFT0M(); + break; + } + return returnValue; + } + + /// Compute the spherocity of an event + /// Important here is that the filter on tracks does not interfere here! + /// In Run 2 we used here global tracks within |eta| < 0.8 + /// \tparam T type of the tracks + /// \param tracks All tracks + /// \return value of the spherocity of the event + template + float computeSpherocity(T const& tracks, int nTracksMin, int spdef) + { + // if number of tracks is not enough for spherocity estimation. + int ntrks = tracks.size(); + if (ntrks < nTracksMin) + return -99.; + + // start computing spherocity + + float ptSum = 0.; + for (auto const& track : tracks) { + if (cfgFillQA) { + qaRegistry.fill(HIST("Phi"), track.phi()); + } + if (spdef == 0) { + ptSum += 1.; + } else { + ptSum += track.pt(); + } + } + + float tempSph = 1.; + for (int i = 0; i < 360 / 0.1; ++i) { + float sum = 0., pt = 0.; + float phiparm = (PI * i * 0.1) / 180.; + float nx = std::cos(phiparm); + float ny = std::sin(phiparm); + for (auto const& trk : tracks) { + pt = trk.pt(); + if (spdef == 0) { + pt = 1.; + } + float phi = trk.phi(); + float px = pt * std::cos(phi); + float py = pt * std::sin(phi); + // sum += pt * abs(sin(phiparm - phi)); + sum += std::abs(px * ny - py * nx); + } + float sph = std::pow((sum / ptSum), 2); + if (sph < tempSph) + tempSph = sph; + } + + return std::pow(PIHalf, 2) * tempSph; + } + + template + float getEvtPl(ResoColl ResoEvents) + { + float returnValue = -999.0; + if (ResoEvents.qvecAmp()[evtPlDetId] > 1e-8) + returnValue = helperEP.GetEventPlane(ResoEvents.qvecRe()[evtPlDetId * 4 + 3], ResoEvents.qvecIm()[evtPlDetId * 4 + 3], 2); + return returnValue; + } + + template + float getEvtPlRes(ResoColl ResoEvents, int a, int b) + { + float returnValue = -999.0; + if (ResoEvents.qvecAmp()[a] < 1e-8 || ResoEvents.qvecAmp()[b] < 1e-8) + return returnValue; + returnValue = helperEP.GetResolution(helperEP.GetEventPlane(ResoEvents.qvecRe()[a * 4 + 3], ResoEvents.qvecIm()[a * 4 + 3], 2), helperEP.GetEventPlane(ResoEvents.qvecRe()[b * 4 + 3], ResoEvents.qvecIm()[b * 4 + 3], 2), 2); + return returnValue; + } + // Filter for micro tracks + template + void fillMicroTracks(CollisionType const& collision, TrackType const& tracks) + { + // Loop over tracks + for (auto const& track : tracks) { + if (!isMicroTrackSelected(collision, track)) + continue; + if (!filterMicroTrack(track)) + continue; + o2::aod::resodmciroaughter::ResoMicroTrackSelFlag trackSelFlag(track.dcaXY(), track.dcaZ()); + if (std::abs(track.dcaXY()) < (0.004 + (0.013 / track.pt()))) { + trackSelFlag.setDCAxy0(); + } + if (std::abs(track.dcaZ()) < (0.004 + (0.013 / track.pt()))) { // TODO: check this + trackSelFlag.setDCAz0(); + } + uint8_t trackFlags = (track.passedITSRefit() << 0) | + (track.passedTPCRefit() << 1) | + (track.isGlobalTrackWoDCA() << 2) | + (track.isGlobalTrack() << 3) | + (track.isPrimaryTrack() << 4) | + (track.isPVContributor() << 5) | + (track.hasTOF() << 6) | + ((track.sign() > 0) << 7); // sign +1: 1, -1: 0 + reso2microtrks(resoCollisions.lastIndex(), + track.px(), + track.py(), + track.pz(), + static_cast(o2::aod::resodmciroaughter::PidNSigma(std::abs(track.tpcNSigmaPi()), std::abs(track.tofNSigmaPi()), track.hasTOF())), + static_cast(o2::aod::resodmciroaughter::PidNSigma(std::abs(track.tpcNSigmaKa()), std::abs(track.tofNSigmaKa()), track.hasTOF())), + static_cast(o2::aod::resodmciroaughter::PidNSigma(std::abs(track.tpcNSigmaPr()), std::abs(track.tofNSigmaPr()), track.hasTOF())), + static_cast(trackSelFlag), + trackFlags); + if (!cfgBypassTrackIndexFill) { + resoMicroTrackTracks(track.globalIndex()); + } + } + } + // Filter for all tracks + template + void fillTracks(CollisionType const& collision, TrackType const& tracks) + { + if (cfgBypassTrackFill) + return; + // Loop over tracks + for (auto const& track : tracks) { + if (!isTrackSelected(collision, track)) + continue; + if (!filterTrack(track)) + continue; + uint8_t trackFlags = (track.passedITSRefit() << 0) | + (track.passedTPCRefit() << 1) | + (track.isGlobalTrackWoDCA() << 2) | + (track.isGlobalTrack() << 3) | + (track.isPrimaryTrack() << 4) | + (track.isPVContributor() << 5) | + (track.hasTOF() << 6) | + ((track.sign() > 0) << 7); // sign +1: 1, -1: 0 + reso2trks(resoCollisions.lastIndex(), + track.pt(), + track.px(), + track.py(), + track.pz(), + static_cast(track.tpcNClsCrossedRows()), + static_cast(track.tpcNClsFound()), + static_cast(std::round(track.dcaXY() * 10000)), + static_cast(std::round(track.dcaZ() * 10000)), + static_cast(std::round(track.tpcNSigmaPi() * 10)), + static_cast(std::round(track.tpcNSigmaKa() * 10)), + static_cast(std::round(track.tpcNSigmaPr() * 10)), + static_cast(std::round(track.tofNSigmaPi() * 10)), + static_cast(std::round(track.tofNSigmaKa() * 10)), + static_cast(std::round(track.tofNSigmaPr() * 10)), + static_cast(std::round(track.tpcSignal() * 10)), + trackFlags); + if (!cfgBypassTrackIndexFill) { + resoTrackTracks(track.globalIndex()); + } + if constexpr (isMC) { + fillMCTrack(track); + } + } + } + + // Filter for all V0s + template + void fillV0s(CollisionType const& collision, V0Type const& v0s, TrackType const& tracks) + { + int childIDs[2] = {0, 0}; // these IDs are necessary to keep track of the children + for (auto const& v0 : v0s) { + if (!isV0Selected(collision, v0, tracks)) + continue; + childIDs[0] = v0.posTrackId(); + childIDs[1] = v0.negTrackId(); + if (!filterV0(collision, v0)) + continue; + reso2v0s(resoCollisions.lastIndex(), + v0.pt(), + v0.px(), + v0.py(), + v0.pz(), + childIDs, + (int8_t)(v0.template posTrack_as().tpcNSigmaPi() * 10), + (int8_t)(v0.template posTrack_as().tpcNSigmaKa() * 10), + (int8_t)(v0.template posTrack_as().tpcNSigmaPr() * 10), + (int8_t)(v0.template negTrack_as().tpcNSigmaPi() * 10), + (int8_t)(v0.template negTrack_as().tpcNSigmaKa() * 10), + (int8_t)(v0.template negTrack_as().tpcNSigmaPr() * 10), + (int8_t)(v0.template negTrack_as().tofNSigmaPi() * 10), + (int8_t)(v0.template negTrack_as().tofNSigmaKa() * 10), + (int8_t)(v0.template negTrack_as().tofNSigmaPr() * 10), + (int8_t)(v0.template posTrack_as().tofNSigmaPi() * 10), + (int8_t)(v0.template posTrack_as().tofNSigmaKa() * 10), + (int8_t)(v0.template posTrack_as().tofNSigmaPr() * 10), + v0.v0cosPA(), + v0.dcaV0daughters(), + v0.dcapostopv(), + v0.dcanegtopv(), + v0.dcav0topv(), + v0.mLambda(), + v0.mAntiLambda(), + v0.mK0Short(), + v0.v0radius(), v0.x(), v0.y(), v0.z()); + if (!cfgBypassTrackIndexFill) { + resoV0V0s(v0.globalIndex()); + } + if constexpr (isMC) { + fillMCV0(v0); + } + } + } + + // Filter for all Cascades + template + void fillCascades(CollisionType const& collision, CascType const& cascades, TrackType const& tracks) + { + int childIDs[3] = {0, 0, 0}; // these IDs are necessary to keep track of the children + for (auto const& casc : cascades) { + if (!isCascSelected(collision, casc, tracks)) + continue; + childIDs[0] = casc.posTrackId(); + childIDs[1] = casc.negTrackId(); + childIDs[2] = casc.bachelorId(); + if (!filterCasc(casc)) + continue; + reso2cascades(resoCollisions.lastIndex(), + casc.pt(), + casc.px(), + casc.py(), + casc.pz(), + childIDs, + (int8_t)(casc.template posTrack_as().tpcNSigmaPi() * 10), + (int8_t)(casc.template posTrack_as().tpcNSigmaKa() * 10), + (int8_t)(casc.template posTrack_as().tpcNSigmaPr() * 10), + (int8_t)(casc.template negTrack_as().tpcNSigmaPi() * 10), + (int8_t)(casc.template negTrack_as().tpcNSigmaKa() * 10), + (int8_t)(casc.template negTrack_as().tpcNSigmaPr() * 10), + (int8_t)(casc.template bachelor_as().tpcNSigmaPi() * 10), + (int8_t)(casc.template bachelor_as().tpcNSigmaKa() * 10), + (int8_t)(casc.template bachelor_as().tpcNSigmaPr() * 10), + (int8_t)(casc.template posTrack_as().tofNSigmaPi() * 10), + (int8_t)(casc.template posTrack_as().tofNSigmaKa() * 10), + (int8_t)(casc.template posTrack_as().tofNSigmaPr() * 10), + (int8_t)(casc.template negTrack_as().tofNSigmaPi() * 10), + (int8_t)(casc.template negTrack_as().tofNSigmaKa() * 10), + (int8_t)(casc.template negTrack_as().tofNSigmaPr() * 10), + (int8_t)(casc.template bachelor_as().tofNSigmaPi() * 10), + (int8_t)(casc.template bachelor_as().tofNSigmaKa() * 10), + (int8_t)(casc.template bachelor_as().tofNSigmaPr() * 10), + casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()), + casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()), + casc.dcaV0daughters(), + casc.dcacascdaughters(), + casc.dcapostopv(), + casc.dcanegtopv(), + casc.dcabachtopv(), + casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()), + casc.dcaXYCascToPV(), + casc.dcaZCascToPV(), + casc.sign(), + casc.mLambda(), + casc.mXi(), + casc.v0radius(), casc.cascradius(), casc.x(), casc.y(), casc.z()); + if (!cfgBypassTrackIndexFill) { + resoCascadeCascades(casc.globalIndex()); + } + if constexpr (isMC) { + fillMCCascade(casc); + } + } + } + + template + void fillMCTrack(TrackType const& track) + { + // ------ Temporal lambda function to prevent error in build + auto getMothersIndeces = [&](auto const& theMcParticle) { + std::vector lMothersIndeces{}; + for (auto const& lMother : theMcParticle.template mothers_as()) { + LOGF(debug, " mother index lMother: %d", lMother.globalIndex()); + lMothersIndeces.push_back(lMother.globalIndex()); + } + return lMothersIndeces; + }; + auto getMothersPDGCodes = [&](auto const& theMcParticle) { + std::vector lMothersPDGs{}; + for (auto const& lMother : theMcParticle.template mothers_as()) { + LOGF(debug, " mother pdgcode lMother: %d", lMother.pdgCode()); + lMothersPDGs.push_back(lMother.pdgCode()); + } + return lMothersPDGs; + }; + auto getSiblingsIndeces = [&](auto const& theMcParticle) { + std::vector lSiblingsIndeces{}; + for (auto const& lMother : theMcParticle.template mothers_as()) { + LOGF(debug, " mother index lMother: %d", lMother.globalIndex()); + for (auto const& lDaughter : lMother.template daughters_as()) { + LOGF(debug, " daughter index lDaughter: %d", lDaughter.globalIndex()); + if (lDaughter.globalIndex() != 0 && lDaughter.globalIndex() != theMcParticle.globalIndex()) { + lSiblingsIndeces.push_back(lDaughter.globalIndex()); + } + } + } + return lSiblingsIndeces; + }; + // ------ + std::vector mothers = {-1, -1}; + std::vector motherPDGs = {-1, -1}; + int siblings[2] = {0, 0}; + std::vector siblingsTemp = {-1, -1}; + if (track.has_mcParticle()) { + // + // Get the MC particle + const auto& particle = track.mcParticle(); + if (particle.has_mothers()) { + mothers = getMothersIndeces(particle); + motherPDGs = getMothersPDGCodes(particle); + siblingsTemp = getSiblingsIndeces(particle); + } + while (mothers.size() > 2) { + mothers.pop_back(); + motherPDGs.pop_back(); + } + if (siblingsTemp.size() > 0) + siblings[0] = siblingsTemp[0]; + if (siblingsTemp.size() > 1) + siblings[1] = siblingsTemp[1]; + reso2mctracks(particle.pdgCode(), + mothers[0], + motherPDGs[0], + siblings, + particle.isPhysicalPrimary(), + particle.producedByGenerator()); + } else { + // No MC particle associated + reso2mctracks(0, + mothers[0], + motherPDGs[0], + siblings, + 0, + 0); + } + } + // Additonoal information for MC V0s + template + void fillMCV0(V0Type const& v0) + { + // ------ Temporal lambda function to prevent error in build + auto getMothersIndeces = [&](auto const& theMcParticle) { + std::vector lMothersIndeces{}; + for (auto const& lMother : theMcParticle.template mothers_as()) { + LOGF(debug, " mother index lMother: %d", lMother.globalIndex()); + lMothersIndeces.push_back(lMother.globalIndex()); + } + return lMothersIndeces; + }; + auto getMothersPDGCodes = [&](auto const& theMcParticle) { + std::vector lMothersPDGs{}; + for (auto const& lMother : theMcParticle.template mothers_as()) { + LOGF(debug, " mother pdgcode lMother: %d", lMother.pdgCode()); + lMothersPDGs.push_back(lMother.pdgCode()); + } + return lMothersPDGs; + }; + auto getDaughtersIndeces = [&](auto const& theMcParticle) { + std::vector lDaughtersIndeces{}; + for (auto const& lDaughter : theMcParticle.template daughters_as()) { + LOGF(debug, " daughter index lDaughter: %d", lDaughter.globalIndex()); + if (lDaughter.globalIndex() != 0) { + lDaughtersIndeces.push_back(lDaughter.globalIndex()); + } + } + return lDaughtersIndeces; + }; + auto getDaughtersPDGCodes = [&](auto const& theMcParticle) { + std::vector lDaughtersPDGs{}; + for (auto const& lDaughter : theMcParticle.template daughters_as()) { + LOGF(debug, " daughter pdgcode lDaughter: %d", lDaughter.pdgCode()); + if (lDaughter.globalIndex() != 0) { + lDaughtersPDGs.push_back(lDaughter.pdgCode()); + } + } + return lDaughtersPDGs; + }; + // ------ + std::vector mothers = {-1, -1}; + std::vector motherPDGs = {-1, -1}; + std::vector daughters = {-1, -1}; + std::vector daughterPDGs = {-1, -1}; + if (v0.has_mcParticle()) { + auto v0mc = v0.mcParticle(); + if (v0mc.has_mothers()) { + mothers = getMothersIndeces(v0mc); + motherPDGs = getMothersPDGCodes(v0mc); + } + while (mothers.size() > 2) { + mothers.pop_back(); + motherPDGs.pop_back(); + } + if (v0mc.has_daughters()) { + daughters = getDaughtersIndeces(v0mc); + daughterPDGs = getDaughtersPDGCodes(v0mc); + } + while (daughters.size() > 2) { + LOGF(info, "daughters.size() is larger than 2"); + daughters.pop_back(); + daughterPDGs.pop_back(); + } + reso2mcv0s(v0mc.pdgCode(), + mothers[0], + motherPDGs[0], + daughters[0], + daughters[1], + daughterPDGs[0], + daughterPDGs[1], + v0mc.isPhysicalPrimary(), + v0mc.producedByGenerator()); + } else { + reso2mcv0s(0, + mothers[0], + motherPDGs[0], + daughters[0], + daughters[1], + daughterPDGs[0], + daughterPDGs[1], + 0, + 0); + } + } + // Additonoal information for MC Cascades + template + void fillMCCascade(CascType const& casc) + { + // ------ Temporal lambda function to prevent error in build + auto getMothersIndeces = [&](auto const& theMcParticle) { + std::vector lMothersIndeces{}; + for (auto const& lMother : theMcParticle.template mothers_as()) { + LOGF(debug, " mother index lMother: %d", lMother.globalIndex()); + lMothersIndeces.push_back(lMother.globalIndex()); + } + return lMothersIndeces; + }; + auto getMothersPDGCodes = [&](auto const& theMcParticle) { + std::vector lMothersPDGs{}; + for (auto const& lMother : theMcParticle.template mothers_as()) { + LOGF(debug, " mother pdgcode lMother: %d", lMother.pdgCode()); + lMothersPDGs.push_back(lMother.pdgCode()); + } + return lMothersPDGs; + }; + auto getDaughtersIndeces = [&](auto const& theMcParticle) { + std::vector lDaughtersIndeces{}; + for (auto const& lDaughter : theMcParticle.template daughters_as()) { + LOGF(debug, " daughter index lDaughter: %d", lDaughter.globalIndex()); + if (lDaughter.globalIndex() != 0) { + lDaughtersIndeces.push_back(lDaughter.globalIndex()); + } + } + return lDaughtersIndeces; + }; + auto getDaughtersPDGCodes = [&](auto const& theMcParticle) { + std::vector lDaughtersPDGs{}; + for (auto const& lDaughter : theMcParticle.template daughters_as()) { + LOGF(debug, " daughter pdgcode lDaughter: %d", lDaughter.pdgCode()); + if (lDaughter.globalIndex() != 0) { + lDaughtersPDGs.push_back(lDaughter.pdgCode()); + } + } + return lDaughtersPDGs; + }; + // ------ + std::vector mothers = {-1, -1}; + std::vector motherPDGs = {-1, -1}; + std::vector daughters = {-1, -1}; + std::vector daughterPDGs = {-1, -1}; + if (casc.has_mcParticle()) { + auto cascmc = casc.mcParticle(); + if (cascmc.has_mothers()) { + mothers = getMothersIndeces(cascmc); + motherPDGs = getMothersPDGCodes(cascmc); + } + while (mothers.size() > 2) { + mothers.pop_back(); + motherPDGs.pop_back(); + } + if (cascmc.has_daughters()) { + daughters = getDaughtersIndeces(cascmc); + daughterPDGs = getDaughtersPDGCodes(cascmc); + } + while (daughters.size() > 2) { + LOGF(info, "daughters.size() is larger than 2"); + daughters.pop_back(); + daughterPDGs.pop_back(); + } + reso2mccascades(cascmc.pdgCode(), + mothers[0], + motherPDGs[0], + daughters[0], + daughters[1], + daughterPDGs[0], + daughterPDGs[1], + cascmc.isPhysicalPrimary(), + cascmc.producedByGenerator()); + } else { + reso2mccascades(0, + mothers[0], + motherPDGs[0], + daughters[0], + daughters[1], + daughterPDGs[0], + daughterPDGs[1], + 0, + 0); + } + } + // Additonoal information for MC Cascades + template + void fillMCParticles(SelectedMCPartType const& mcParts, TotalMCParts const& mcParticles) + { + for (auto const& mcPart : mcParts) { + std::vector daughterPDGs; + if (mcPart.has_daughters()) { + auto daughter01 = mcParticles.rawIteratorAt(mcPart.daughtersIds()[0] - mcParticles.offset()); + auto daughter02 = mcParticles.rawIteratorAt(mcPart.daughtersIds()[1] - mcParticles.offset()); + daughterPDGs = {daughter01.pdgCode(), daughter02.pdgCode()}; + } else { + daughterPDGs = {-1, -1}; + } + reso2mcparents(resoCollisions.lastIndex(), + mcPart.globalIndex(), + mcPart.pdgCode(), + daughterPDGs[0], daughterPDGs[1], + mcPart.isPhysicalPrimary(), + mcPart.producedByGenerator(), + mcPart.pt(), + mcPart.px(), + mcPart.py(), + mcPart.pz(), + mcPart.y(), + mcPart.e(), + mcPart.statusCode()); + daughterPDGs.clear(); + } + } + + template + void fillMCCollision(MCCol const& mccol, MCPart const& mcparts, float impactpar = -999.0) + { + auto centrality = 0.0; + if constexpr (!isRun2) + centrality = centEst(mccol); + else + centrality = mccol.centRun2V0M(); + bool inVtx10 = (std::abs(mccol.mcCollision().posZ()) > 10.) ? false : true; + bool isTrueINELgt0 = isTrueINEL0(mccol, mcparts); + bool isTriggerTVX = mccol.selection_bit(aod::evsel::kIsTriggerTVX); + bool isSel8 = mccol.sel8(); + bool isSelected = colCuts.isSelected(mccol); + resoMCCollisions(inVtx10, isTrueINELgt0, isTriggerTVX, isSel8, isSelected, impactpar); + + // QA for Trigger efficiency + qaRegistry.fill(HIST("Event/hMCEventIndices"), centrality, aod::resocollision::kINEL); + if (inVtx10) + qaRegistry.fill(HIST("Event/hMCEventIndices"), centrality, aod::resocollision::kINEL10); + if (isTrueINELgt0) + qaRegistry.fill(HIST("Event/hMCEventIndices"), centrality, aod::resocollision::kINELg0); + if (inVtx10 && isTrueINELgt0) + qaRegistry.fill(HIST("Event/hMCEventIndices"), centrality, aod::resocollision::kINELg010); + + // TVX MB trigger + if (isTriggerTVX) + qaRegistry.fill(HIST("Event/hMCEventIndices"), centrality, aod::resocollision::kTrig); + if (isTriggerTVX && inVtx10) + qaRegistry.fill(HIST("Event/hMCEventIndices"), centrality, aod::resocollision::kTrig10); + if (isTriggerTVX && isTrueINELgt0) + qaRegistry.fill(HIST("Event/hMCEventIndices"), centrality, aod::resocollision::kTrigINELg0); + if (isTriggerTVX && isTrueINELgt0 && inVtx10) + qaRegistry.fill(HIST("Event/hMCEventIndices"), centrality, aod::resocollision::kTrigINELg010); + + // Sel8 event selection + if (isSel8) + qaRegistry.fill(HIST("Event/hMCEventIndices"), centrality, aod::resocollision::kSel8); + if (isSel8 && inVtx10) + qaRegistry.fill(HIST("Event/hMCEventIndices"), centrality, aod::resocollision::kSel810); + if (isSel8 && isTrueINELgt0) + qaRegistry.fill(HIST("Event/hMCEventIndices"), centrality, aod::resocollision::kSel8INELg0); + if (isSel8 && isTrueINELgt0 && inVtx10) + qaRegistry.fill(HIST("Event/hMCEventIndices"), centrality, aod::resocollision::kSel8INELg010); + + // CollisionCuts selection + if (isSelected) + qaRegistry.fill(HIST("Event/hMCEventIndices"), centrality, aod::resocollision::kAllCuts); + if (isSelected && inVtx10) + qaRegistry.fill(HIST("Event/hMCEventIndices"), centrality, aod::resocollision::kAllCuts10); + if (isSelected && isTrueINELgt0) + qaRegistry.fill(HIST("Event/hMCEventIndices"), centrality, aod::resocollision::kAllCutsINELg0); + if (isSelected && isTrueINELgt0 && inVtx10) + qaRegistry.fill(HIST("Event/hMCEventIndices"), centrality, aod::resocollision::kAllCutsINELg010); + } + + void init(InitContext&) + { + mRunNumber = 0; + dBz = 0; + // Multiplicity estimator selection (0: FT0M, 1: FT0C, 2: FT0A, 99: FV0A) + if (cfgMultName.value == "FT0M") { + multEstimator = 0; + } else if (cfgMultName.value == "FT0C") { + multEstimator = 1; + } else if (cfgMultName.value == "FT0A") { + multEstimator = 2; + } else if (cfgMultName.value == "FV0A") { + multEstimator = 99; + } else { + multEstimator = 0; + } + + // Check if we are running multiple processes at the same time + int nProcesses = doprocessTrackData + doprocessTrackV0Data + doprocessTrackV0CascData + + doprocessTrackMC + doprocessTrackV0MC + doprocessTrackV0CascMC + doprocessTrackEPData + + doprocessTrackDataRun2 + doprocessTrackV0DataRun2 + doprocessTrackV0CascDataRun2 + + doprocessTrackMCRun2 + doprocessTrackV0MCRun2 + doprocessTrackV0CascMCRun2; + + if (nProcesses > 1) { + LOG(fatal) << "Multiple processes are not supported at the same time"; + } + + // Case selector based on the process. + if (doprocessTrackDataRun2 || doprocessTrackV0DataRun2 || doprocessTrackV0CascDataRun2 || doprocessTrackMCRun2 || doprocessTrackV0MCRun2 || doprocessTrackV0CascMCRun2) { + colCuts.setCuts(EventCuts.cfgEvtZvtx, EventCuts.cfgEvtTriggerCheck, EventCuts.cfgEvtOfflineCheck, false); + } else if (doprocessTrackData || doprocessTrackV0Data || doprocessTrackV0CascData || doprocessTrackMC || doprocessTrackV0MC || doprocessTrackV0CascMC || doprocessTrackEPData) { + colCuts.setCuts(EventCuts.cfgEvtZvtx, EventCuts.cfgEvtTriggerCheck, EventCuts.cfgEvtOfflineCheck, /*checkRun3*/ true, /*triggerTVXsel*/ false, EventCuts.cfgEvtOccupancyInTimeRangeMax, EventCuts.cfgEvtOccupancyInTimeRangeMin); + } + colCuts.init(&qaRegistry); + colCuts.setTriggerTVX(EventCuts.cfgEvtTriggerTVXSel); + colCuts.setApplyTFBorderCut(EventCuts.cfgEvtTFBorderCut); + colCuts.setApplyITSTPCvertex(EventCuts.cfgEvtUseITSTPCvertex); + colCuts.setApplyZvertexTimedifference(EventCuts.cfgEvtZvertexTimedifference); + colCuts.setApplyPileupRejection(EventCuts.cfgEvtPileupRejection); + colCuts.setApplyNoITSROBorderCut(EventCuts.cfgEvtNoITSROBorderCut); + colCuts.setApplyCollInTimeRangeStandard(EventCuts.cfgEvtCollInTimeRangeStandard); + colCuts.setApplyRun2AliEventCuts(EventCuts.cfgEvtRun2AliEventCuts); + colCuts.setApplyRun2INELgtZERO(EventCuts.cfgEvtRun2INELgtZERO); + colCuts.printCuts(); + + rctChecker.init(EventCuts.cfgEvtRCTFlagCheckerLabel, EventCuts.cfgEvtRCTFlagCheckerZDCCheck, EventCuts.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + + if (!cfgBypassCCDB) { + ccdb->setURL(ccdbURL.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(cfgFatalWhenNull); + uint64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); // TODO must become global parameter from the train creation time + } + + // QA histograms + if (doprocessTrackMCRun2 || doprocessTrackV0MCRun2 || doprocessTrackV0CascMCRun2 || doprocessTrackMC || doprocessTrackV0MC || doprocessTrackV0CascMC) { + AxisSpec centAxis = {binsCent, "Centrality (%)"}; + AxisSpec idxMCAxis = {26, -0.5, 25.5, "Index"}; + qaRegistry.add("Event/hMCEventIndices", "hMCEventIndices", kTH2D, {centAxis, idxMCAxis}); + } + AxisSpec idxAxis = {8, 0, 8, "Index"}; + if (cfgFillQA) { + qaRegistry.add("hGoodTrackIndices", "hGoodTrackIndices", kTH1F, {idxAxis}); + qaRegistry.add("hGoodMCTrackIndices", "hGoodMCTrackIndices", kTH1F, {idxAxis}); + qaRegistry.add("hGoodV0Indices", "hGoodV0Indices", kTH1F, {idxAxis}); + qaRegistry.add("hGoodMCV0Indices", "hGoodMCV0Indices", kTH1F, {idxAxis}); + qaRegistry.add("hGoodCascIndices", "hGoodCascIndices", kTH1F, {idxAxis}); + qaRegistry.add("hGoodMCCascIndices", "hGoodMCCascIndices", kTH1F, {idxAxis}); + qaRegistry.add("Phi", "#phi distribution", kTH1F, {{65, -0.1, 6.4}}); + } + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) // Simple copy from LambdaKzeroFinder.cxx + { + if (cfgBypassCCDB) + return; + if (mRunNumber == bc.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (dBzInput > -990) { + dBz = dBzInput; + ; + o2::parameters::GRPMagField grpmag; + if (std::fabs(dBz) > 1e-5) { + grpmag.setL3Current(30000.f / (dBz / 5.0f)); + } + o2::base::Propagator::initFieldFromGRP(&grpmag); + mRunNumber = bc.runNumber(); + return; + } + + auto run3GRPTimestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3GRPTimestamp); + o2::parameters::GRPMagField* grpmag = 0x0; + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + // Fetch magnetic field from ccdb for current collision + dBz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3GRPTimestamp << " with magnetic field of " << dBz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3GRPTimestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3GRPTimestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + // Fetch magnetic field from ccdb for current collision + dBz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3GRPTimestamp << " with magnetic field of " << dBz << " kZG"; + } + mRunNumber = bc.runNumber(); + // Set magnetic field value once known + LOGF(info, "Bz set to %f for run: ", dBz, mRunNumber); + } + + void processDummy(aod::Collisions const& /*collisions*/) + { + } + PROCESS_SWITCH(ResonanceInitializer, processDummy, "Process for dummy", true); + + void processTrackData(ResoEvents::iterator const& collision, + soa::Filtered const& tracks, + aod::BCsWithTimestamps const&) + { + auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later + initCCDB(bc); + // Default event selection + if (!colCuts.isSelected(collision)) + return; + if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) + return; + colCuts.fillQA(collision); + + resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), centEst(collision), dBz); + if (!cfgBypassCollIndexFill) { + resoCollisionColls(collision.globalIndex()); + } + resoSpheroCollisions(computeSpherocity(tracks, trackSphMin, trackSphDef)); + resoEvtPlCollisions(0, 0, 0, 0); + + fillTracks(collision, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } + } + PROCESS_SWITCH(ResonanceInitializer, processTrackData, "Process for data", false); + + void processTrackDataRun2(ResoRun2Events::iterator const& collision, + soa::Filtered const& tracks, + BCsWithRun2Info const&) + { + // auto bc = collision.bc_as(); + // Default event selection + if (!colCuts.isSelected(collision)) + return; + if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) + return; + colCuts.fillQARun2(collision); + + resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), collision.centRun2V0M(), dBz); + if (!cfgBypassCollIndexFill) { + resoCollisionColls(collision.globalIndex()); + } + resoSpheroCollisions(computeSpherocity(tracks, trackSphMin, trackSphDef)); + resoEvtPlCollisions(0, 0, 0, 0); + + fillTracks(collision, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } + } + PROCESS_SWITCH(ResonanceInitializer, processTrackDataRun2, "Process for data", false); + + void processTrackEPData(soa::Join::iterator const& collision, + soa::Filtered const& tracks, + aod::BCsWithTimestamps const&) + { + auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later + initCCDB(bc); + // Default event selection + if (!colCuts.isSelected(collision)) + return; + if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) + return; + colCuts.fillQA(collision); + + resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), centEst(collision), dBz); + if (!cfgBypassCollIndexFill) { + resoCollisionColls(collision.globalIndex()); + } + resoSpheroCollisions(computeSpherocity(tracks, trackSphMin, trackSphDef)); + resoEvtPlCollisions(getEvtPl(collision), getEvtPlRes(collision, evtPlDetId, evtPlRefAId), getEvtPlRes(collision, evtPlDetId, evtPlRefBId), getEvtPlRes(collision, evtPlRefAId, evtPlRefBId)); + fillTracks(collision, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } + } + PROCESS_SWITCH(ResonanceInitializer, processTrackEPData, "Process for data and ep ana", false); + + void processTrackV0Data(ResoEvents::iterator const& collision, + soa::Filtered const& tracks, + ResoV0s const& V0s, + aod::BCsWithTimestamps const&) + { + auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later + initCCDB(bc); + // Default event selection + if (!colCuts.isSelected(collision)) + return; + if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) + return; + colCuts.fillQA(collision); + + resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), centEst(collision), dBz); + if (!cfgBypassCollIndexFill) { + resoCollisionColls(collision.globalIndex()); + } + resoSpheroCollisions(computeSpherocity(tracks, trackSphMin, trackSphDef)); + resoEvtPlCollisions(0, 0, 0, 0); + + fillTracks(collision, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } + fillV0s(collision, V0s, tracks); + } + PROCESS_SWITCH(ResonanceInitializer, processTrackV0Data, "Process for data", false); + + void processTrackV0DataRun2(ResoRun2Events::iterator const& collision, + soa::Filtered const& tracks, + ResoV0s const& V0s, + BCsWithRun2Info const&) + { + // auto bc = collision.bc_as(); + // Default event selection + if (!colCuts.isSelected(collision)) + return; + colCuts.fillQARun2(collision); + + resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), collision.centRun2V0M(), dBz); + if (!cfgBypassCollIndexFill) { + resoCollisionColls(collision.globalIndex()); + } + resoSpheroCollisions(computeSpherocity(tracks, trackSphMin, trackSphDef)); + resoEvtPlCollisions(0, 0, 0, 0); + + fillTracks(collision, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } + fillV0s(collision, V0s, tracks); + } + PROCESS_SWITCH(ResonanceInitializer, processTrackV0DataRun2, "Process for data", false); + + void processTrackV0CascData(ResoEvents::iterator const& collision, + soa::Filtered const& tracks, + ResoV0s const& V0s, + ResoCascades const& Cascades, + aod::BCsWithTimestamps const&) + { + auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later + initCCDB(bc); + // Default event selection + if (!colCuts.isSelected(collision)) + return; + if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) + return; + colCuts.fillQA(collision); + + resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), centEst(collision), dBz); + if (!cfgBypassCollIndexFill) { + resoCollisionColls(collision.globalIndex()); + } + resoSpheroCollisions(computeSpherocity(tracks, trackSphMin, trackSphDef)); + resoEvtPlCollisions(0, 0, 0, 0); + fillTracks(collision, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } + fillV0s(collision, V0s, tracks); + fillCascades(collision, Cascades, tracks); + } + PROCESS_SWITCH(ResonanceInitializer, processTrackV0CascData, "Process for data", false); + + void processTrackV0CascDataRun2(ResoRun2Events::iterator const& collision, + soa::Filtered const& tracks, + ResoV0s const& V0s, + ResoCascades const& Cascades, + BCsWithRun2Info const&) + { + // auto bc = collision.bc_as(); + // Default event selection + if (!colCuts.isSelected(collision)) + return; + colCuts.fillQARun2(collision); + + resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), collision.centRun2V0M(), dBz); + if (!cfgBypassCollIndexFill) { + resoCollisionColls(collision.globalIndex()); + } + resoSpheroCollisions(computeSpherocity(tracks, trackSphMin, trackSphDef)); + resoEvtPlCollisions(0, 0, 0, 0); + + fillTracks(collision, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } + fillV0s(collision, V0s, tracks); + fillCascades(collision, Cascades, tracks); + } + PROCESS_SWITCH(ResonanceInitializer, processTrackV0CascDataRun2, "Process for data", false); + + Preslice perMcCollision = aod::mcparticle::mcCollisionId; + void processTrackMC(soa::Join::iterator const& collision, + aod::McCollisions const&, soa::Filtered const& tracks, + aod::McParticles const& mcParticles, aod::BCsWithTimestamps const&) + { + auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later + initCCDB(bc); + if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) + return; + colCuts.fillQA(collision); + + resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), centEst(collision), dBz); + if (!cfgBypassCollIndexFill) { + resoCollisionColls(collision.globalIndex()); + } + resoSpheroCollisions(computeSpherocity(tracks, trackSphMin, trackSphDef)); + resoEvtPlCollisions(0, 0, 0, 0); + auto mccollision = collision.mcCollision_as(); + float impactpar = mccollision.impactParameter(); + fillMCCollision(collision, mcParticles, impactpar); + + // Loop over tracks + fillTracks(collision, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } + + // Loop over all MC particles + auto mcParts = selectedMCParticles->sliceBy(perMcCollision, collision.mcCollision().globalIndex()); + fillMCParticles(mcParts, mcParticles); + } + PROCESS_SWITCH(ResonanceInitializer, processTrackMC, "Process for MC", false); + + void processTrackEPMC(soa::Join::iterator const& collision, + aod::McCollisions const&, soa::Filtered const& tracks, + aod::McParticles const& mcParticles, aod::BCsWithTimestamps const&) + { + auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later + initCCDB(bc); + if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) + return; + colCuts.fillQA(collision); + + resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), centEst(collision), dBz); + if (!cfgBypassCollIndexFill) { + resoCollisionColls(collision.globalIndex()); + } + resoSpheroCollisions(computeSpherocity(tracks, trackSphMin, trackSphDef)); + resoEvtPlCollisions(getEvtPl(collision), getEvtPlRes(collision, evtPlDetId, evtPlRefAId), getEvtPlRes(collision, evtPlDetId, evtPlRefBId), getEvtPlRes(collision, evtPlRefAId, evtPlRefBId)); + fillMCCollision(collision, mcParticles); + + // Loop over tracks + fillTracks(collision, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } + // Loop over all MC particles + auto mcParts = selectedMCParticles->sliceBy(perMcCollision, collision.mcCollision().globalIndex()); + fillMCParticles(mcParts, mcParticles); + } + PROCESS_SWITCH(ResonanceInitializer, processTrackEPMC, "Process for MC and ep ana", false); + + Preslice perMcCollisionRun2 = aod::mcparticle::mcCollisionId; + void processTrackMCRun2(soa::Join::iterator const& collision, + aod::McCollisions const&, soa::Filtered const& tracks, + aod::McParticles const& mcParticles, BCsWithRun2Info const&) + { + // auto bc = collision.bc_as(); + colCuts.fillQARun2(collision); + + resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), collision.centRun2V0M(), dBz); + if (!cfgBypassCollIndexFill) { + resoCollisionColls(collision.globalIndex()); + } + resoSpheroCollisions(computeSpherocity(tracks, trackSphMin, trackSphDef)); + resoEvtPlCollisions(0, 0, 0, 0); + fillMCCollision(collision, mcParticles); + + // Loop over tracks + fillTracks(collision, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } + // Loop over all MC particles + auto mcParts = selectedMCParticles->sliceBy(perMcCollisionRun2, collision.mcCollision().globalIndex()); + fillMCParticles(mcParts, mcParticles); + } + PROCESS_SWITCH(ResonanceInitializer, processTrackMCRun2, "Process for MC", false); + + void processTrackV0MC(soa::Join::iterator const& collision, + aod::McCollisions const&, soa::Filtered const& tracks, + ResoV0sMC const& V0s, + aod::McParticles const& mcParticles, aod::BCsWithTimestamps const&) + { + auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later + initCCDB(bc); + if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) + return; + colCuts.fillQA(collision); + + resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), centEst(collision), dBz); + if (!cfgBypassCollIndexFill) { + resoCollisionColls(collision.globalIndex()); + } + resoSpheroCollisions(computeSpherocity(tracks, trackSphMin, trackSphDef)); + resoEvtPlCollisions(0, 0, 0, 0); + fillMCCollision(collision, mcParticles); + + // Loop over tracks + fillTracks(collision, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } + fillV0s(collision, V0s, tracks); + + // Loop over all MC particles + auto mcParts = selectedMCParticles->sliceBy(perMcCollision, collision.mcCollision().globalIndex()); + fillMCParticles(mcParts, mcParticles); + } + PROCESS_SWITCH(ResonanceInitializer, processTrackV0MC, "Process for MC", false); + + void processTrackV0MCRun2(soa::Join::iterator const& collision, + aod::McCollisions const&, soa::Filtered const& tracks, + ResoV0sMC const& V0s, + aod::McParticles const& mcParticles, BCsWithRun2Info const&) + { + // auto bc = collision.bc_as(); + colCuts.fillQARun2(collision); + + resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), collision.centRun2V0M(), dBz); + if (!cfgBypassCollIndexFill) { + resoCollisionColls(collision.globalIndex()); + } + resoSpheroCollisions(computeSpherocity(tracks, trackSphMin, trackSphDef)); + resoEvtPlCollisions(0, 0, 0, 0); + fillMCCollision(collision, mcParticles); + + // Loop over tracks + fillTracks(collision, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } + fillV0s(collision, V0s, tracks); + + // Loop over all MC particles + auto mcParts = selectedMCParticles->sliceBy(perMcCollision, collision.mcCollision().globalIndex()); + fillMCParticles(mcParts, mcParticles); + } + PROCESS_SWITCH(ResonanceInitializer, processTrackV0MCRun2, "Process for MC", false); + + void processTrackV0CascMC(soa::Join::iterator const& collision, + aod::McCollisions const&, soa::Filtered const& tracks, + ResoV0sMC const& V0s, + ResoCascadesMC const& Cascades, + aod::McParticles const& mcParticles, aod::BCsWithTimestamps const&) + { + auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later + initCCDB(bc); + if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) + return; + colCuts.fillQA(collision); + + resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), centEst(collision), dBz); + if (!cfgBypassCollIndexFill) { + resoCollisionColls(collision.globalIndex()); + } + resoSpheroCollisions(computeSpherocity(tracks, trackSphMin, trackSphDef)); + resoEvtPlCollisions(0, 0, 0, 0); + fillMCCollision(collision, mcParticles); + + // Loop over tracks + fillTracks(collision, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } + fillV0s(collision, V0s, tracks); + fillCascades(collision, Cascades, tracks); + + // Loop over all MC particles + auto mcParts = selectedMCParticles->sliceBy(perMcCollision, collision.mcCollision().globalIndex()); + fillMCParticles(mcParts, mcParticles); + } + PROCESS_SWITCH(ResonanceInitializer, processTrackV0CascMC, "Process for MC", false); + + void processTrackV0CascMCRun2(soa::Join::iterator const& collision, + aod::McCollisions const&, soa::Filtered const& tracks, + ResoV0sMC const& V0s, + ResoCascadesMC const& Cascades, + aod::McParticles const& mcParticles, BCsWithRun2Info const&) + { + // auto bc = collision.bc_as(); + colCuts.fillQARun2(collision); + + resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), collision.centRun2V0M(), dBz); + if (!cfgBypassCollIndexFill) { + resoCollisionColls(collision.globalIndex()); + } + resoSpheroCollisions(computeSpherocity(tracks, trackSphMin, trackSphDef)); + resoEvtPlCollisions(0, 0, 0, 0); + fillMCCollision(collision, mcParticles); + + // Loop over tracks + fillTracks(collision, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } + fillV0s(collision, V0s, tracks); + fillCascades(collision, Cascades, tracks); + + // Loop over all MC particles + auto mcParts = selectedMCParticles->sliceBy(perMcCollision, collision.mcCollision().globalIndex()); + fillMCParticles(mcParts, mcParticles); + } + PROCESS_SWITCH(ResonanceInitializer, processTrackV0CascMCRun2, "Process for MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGLF/TableProducer/Resonances/resonanceMergeDF.cxx b/PWGLF/TableProducer/Resonances/resonanceMergeDF.cxx new file mode 100644 index 00000000000..e7c31d1010e --- /dev/null +++ b/PWGLF/TableProducer/Resonances/resonanceMergeDF.cxx @@ -0,0 +1,369 @@ +// 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 resonanceMergeDF.cxx +/// \brief Merges multiple dataframes into a single dataframe +/// +/// +/// In typical dataframes (DF), we usually observe a range of 200 to 300 collisions. +/// This limited number of collisions often results in most events having very few currentwindowneighbors() for event mixing. +/// However, for resonances analysis, a minimum of 10 currentwindowneighbors() is required. +/// To address this limitation, this script is designed to aggregate information from multiple dataframes into a single dataframe, +/// thereby increasing the number of available current window neighbors for analysis. Here, nDF refers to the number of events or collisions. +/// For instance, if the total number of collisions across all dataframes is, say, 10,836, setting nDF to 10,836 will result in the creation of a single table. +/// Conversely, if nDF is set to 2,709, it will generate four tables, each containing approximately 2,709 collisions. +/// If nDF is set to 1, it will generate tables equal to the number of parent tables. +/// +/// /// +/// \author Bong-Hwi Lim +/// Nasir Mehdi Malik +/// Min-jae Kim +#include + +#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/Core/EventPlaneHelper.h" +#include "Framework/ASoAHelpers.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFResonanceTables.h" +#include "PWGLF/Utils/collisionCuts.h" +#include "ReconstructionDataFormats/Track.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +/// Initializer for the resonance candidate producers + +struct ResonanceMergeDF { + // SliceCache cache; + Configurable nDF{"nDF", 1, "no of combination of collision"}; + Configurable cpidCut{"cpidCut", 0, "pid cut"}; + Configurable crejtpc{"crejtpc", 0, "reject electron pion"}; + Configurable crejtof{"crejtof", 0, "reject electron pion tof"}; + Configurable isPrimary{"isPrimary", 0, "is Primary only"}; + Configurable isGlobal{"isGlobal", 0, "Global tracks only"}; + Configurable cDCAXY{"cDCAXY", 1., "value of dcaxy"}; + Configurable cDCAZ{"cDCAZ", 1., "value of dcaz"}; + Configurable nsigmaPr{"nsigmaPr", 6., "nsigma value for proton"}; + Configurable nsigmaKa{"nsigmaKa", 6., "nsigma value for kaon"}; + Configurable nsigmatofPr{"nsigmatofPr", 6., "nsigma value for tof prot"}; + Configurable nsigmatofKa{"nsigmatofKa", 6., "nsigma value for tof kaon"}; + + // Xi1530 candidate cuts + Configurable trackSelection{"trackSelection", 0, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoDCA"}; + Configurable requireTOF{"requireTOF", false, "Require TOF"}; + Configurable applyTOFveto{"applyTOFveto", 999, "Apply TOF veto with value, 999 for passing all"}; + Configurable nsigmaPi{"nsigmaPi", 5., "nsigma value for pion"}; + Configurable minCent{"minCent", 0., "Minimum centrality"}; + Configurable maxCent{"maxCent", 100., "Maximum centrality"}; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext const&) + { + + const AxisSpec axisCent(110, 0, 110, "FT0 (%)"); + histos.add("Event/h1d_ft0_mult_percentile", "FT0 (%)", kTH1F, {axisCent}); + histos.add("Event/h1d_ft0_mult_percentile_CASC", "FT0 (%)", kTH1F, {axisCent}); + } + Produces resoCollisionsdf; + Produces reso2trksdf; + Produces reso2cascadesdf; + int df = 0; + + std::vector> vecOfTuples; + std::vector>> + vecOfVecOfTuples; + void processTrackDataDF(aod::ResoCollisions::iterator const& collision, aod::ResoTracks const& tracks) + { + + int nCollisions = nDF; + vecOfTuples.push_back(std::make_tuple(collision.posX(), collision.posY(), collision.posZ(), collision.cent(), 0, 0, 0)); + std::vector> + innerVector; + for (const auto& track : tracks) { + if (cpidCut) { + if (!track.hasTOF()) { + if (std::abs(track.tpcNSigmaPr()) > nsigmaPr && std::abs(track.tpcNSigmaKa()) > nsigmaKa) + continue; + + if (crejtpc && (std::abs(track.tpcNSigmaPr()) > std::abs(track.tpcNSigmaPi()) && std::abs(track.tpcNSigmaKa()) > std::abs(track.tpcNSigmaPi()))) + continue; + + } else { + if (std::abs(track.tofNSigmaPr()) > nsigmatofPr && std::abs(track.tofNSigmaKa()) > nsigmatofKa) + continue; + + if (crejtof && (std::abs(track.tofNSigmaPr()) > std::abs(track.tofNSigmaPi()) && std::abs(track.tofNSigmaKa()) > std::abs(track.tofNSigmaPi()))) + continue; + } + + if (std::abs(track.dcaXY()) > cDCAXY) + continue; + if (std::abs(track.dcaZ()) > cDCAZ) + continue; + } + + innerVector.push_back(std::make_tuple( + // track.trackId(), + track.pt(), + track.px(), + track.py(), + track.pz(), + track.sign(), + (uint8_t)track.tpcNClsCrossedRows(), + (uint8_t)track.tpcNClsFound(), + static_cast(track.dcaXY() * 10000), + static_cast(track.dcaZ() * 10000), + (int8_t)(track.tpcNSigmaPi() * 10), + (int8_t)(track.tpcNSigmaKa() * 10), + (int8_t)(track.tpcNSigmaPr() * 10), + (int8_t)(track.tofNSigmaPi() * 10), + (int8_t)(track.tofNSigmaKa() * 10), + (int8_t)(track.tofNSigmaPr() * 10), + (int8_t)(track.tpcSignal() * 10), + track.trackFlags())); + } + + vecOfVecOfTuples.push_back(innerVector); + innerVector.clear(); + df++; + LOGF(info, "collisions: df = %i", df); + if (df < nCollisions) + return; + df = 0; + + for (size_t i = 0; i < vecOfTuples.size(); ++i) { + const auto& tuple = vecOfTuples[i]; + const auto& innerVector = vecOfVecOfTuples[i]; + + histos.fill(HIST("Event/h1d_ft0_mult_percentile"), std::get<3>(tuple)); + resoCollisionsdf(0, std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple), std::get<3>(tuple), std::get<4>(tuple), std::get<5>(tuple), 0., 0., 0., 0., 0, std::get<6>(tuple)); + // LOGF(info, "collisions: Index = %d ) %f - %f - %f %f %d -- %d", std::get<0>(tuple).globalIndex(),std::get<1>(tuple),std::get<2>(tuple), std::get<3>(tuple), std::get<4>(tuple), std::get<5>(tuple).size(),resoCollisionsdf.lastIndex()); + + for (const auto& tuple : innerVector) { + reso2trksdf(resoCollisionsdf.lastIndex(), + std::get<0>(tuple), + std::get<1>(tuple), + std::get<2>(tuple), + std::get<3>(tuple), + std::get<4>(tuple), + std::get<5>(tuple), + std::get<6>(tuple), + std::get<7>(tuple), + std::get<8>(tuple), + std::get<9>(tuple), + std::get<10>(tuple), + std::get<11>(tuple), + std::get<12>(tuple), + std::get<13>(tuple), + std::get<14>(tuple), + std::get<15>(tuple)); + } + } + + vecOfTuples.clear(); + vecOfVecOfTuples.clear(); // + } + + PROCESS_SWITCH(ResonanceMergeDF, processTrackDataDF, "Process for data merged DF", true); + + void processLambdaStarCandidate(aod::ResoCollisions::iterator const& collision, aod::ResoTracks const& tracks) + { + + if (doprocessTrackDataDF) + LOG(fatal) << "Disable processTrackDataDF first!"; + + histos.fill(HIST("Event/h1d_ft0_mult_percentile"), collision.cent()); + + resoCollisionsdf(0, collision.posX(), collision.posY(), collision.posZ(), collision.cent(), 0, 0, 0., 0., 0., 0., 0, 0); + + for (const auto& track : tracks) { + if (isPrimary && !track.isPrimaryTrack()) + continue; + if (isGlobal && !track.isGlobalTrack()) + continue; + if (!track.hasTOF()) { + if (std::abs(track.tpcNSigmaPr()) > nsigmaPr && std::abs(track.tpcNSigmaKa()) > nsigmaKa) + continue; + + if (crejtpc && (std::abs(track.tpcNSigmaPr()) > std::abs(track.tpcNSigmaPi()) && std::abs(track.tpcNSigmaKa()) > std::abs(track.tpcNSigmaPi()))) + continue; + + } else { + if (std::abs(track.tofNSigmaPr()) > nsigmatofPr && std::abs(track.tofNSigmaKa()) > nsigmatofKa) + continue; + + if (crejtof && (std::abs(track.tofNSigmaPr()) > std::abs(track.tofNSigmaPi()) && std::abs(track.tofNSigmaKa()) > std::abs(track.tofNSigmaPi()))) + continue; + } + if (std::abs(track.dcaXY()) > cDCAXY) + continue; + if (std::abs(track.dcaZ()) > cDCAZ) + continue; + reso2trksdf(resoCollisionsdf.lastIndex(), + // track.trackId(), + track.pt(), + track.px(), + track.py(), + track.pz(), + (uint8_t)track.tpcNClsCrossedRows(), + (uint8_t)track.tpcNClsFound(), + static_cast(track.dcaXY() * 10000), + static_cast(track.dcaZ() * 10000), + (int8_t)(track.tpcNSigmaPi() * 10), + (int8_t)(track.tpcNSigmaKa() * 10), + (int8_t)(track.tpcNSigmaPr() * 10), + (int8_t)(track.tofNSigmaPi() * 10), + (int8_t)(track.tofNSigmaKa() * 10), + (int8_t)(track.tofNSigmaPr() * 10), + (int8_t)(track.tpcSignal() * 10), + track.trackFlags()); + } + } + PROCESS_SWITCH(ResonanceMergeDF, processLambdaStarCandidate, "Process for lambda star candidate", false); + + void processXi1530Candidate(aod::ResoCollisions::iterator const& collision, aod::ResoTracks const& tracks, aod::ResoCascades const& resocasctracks) + { + if (doprocessTrackDataDF) + LOG(fatal) << "Disable processTrackDataDF first!"; + if (doprocessLambdaStarCandidate) + LOG(fatal) << "Disable processLambdaStarCandidate first!"; + + if (collision.cent() < minCent || collision.cent() > maxCent) + return; + + resoCollisionsdf(0, collision.posX(), collision.posY(), collision.posZ(), collision.cent(), 0, 0, 0., 0., 0., 0., 0, 0); + histos.fill(HIST("Event/h1d_ft0_mult_percentile"), collision.cent()); + + for (const auto& track : tracks) { + if (trackSelection == 1) { + if (!track.isGlobalTrack()) + continue; + } else if (trackSelection == 2) { + if (!track.isGlobalTrackWoDCA()) + continue; + } + if (!track.hasTOF()) { + if (requireTOF) { + continue; + } + // TPC selection + if (std::abs(track.tpcNSigmaPi()) > nsigmaPi) + continue; + } else { + if (applyTOFveto > 998 && std::abs(track.tofNSigmaPi()) > applyTOFveto) + continue; + // TPC selection + if (std::abs(track.tpcNSigmaPi()) > nsigmaPi) + continue; + } + + if (std::abs(track.dcaXY()) > cDCAXY) + continue; + if (std::abs(track.dcaZ()) > cDCAZ) + continue; + + reso2trksdf(resoCollisionsdf.lastIndex(), + // track.trackId(), + track.pt(), + track.px(), + track.py(), + track.pz(), + (uint8_t)track.tpcNClsCrossedRows(), + (uint8_t)track.tpcNClsFound(), + static_cast(track.dcaXY() * 10000), + static_cast(track.dcaZ() * 10000), + (int8_t)(track.tpcNSigmaPi() * 10), + (int8_t)(track.tpcNSigmaKa() * 10), + (int8_t)(track.tpcNSigmaPr() * 10), + (int8_t)(track.tofNSigmaPi() * 10), + (int8_t)(track.tofNSigmaKa() * 10), + (int8_t)(track.tofNSigmaPr() * 10), + (int8_t)(track.tpcSignal() * 10), + track.trackFlags()); + } + // Cascade candidate + for (const auto& track : resocasctracks) { + // TODO: add cascade cuts + reso2cascadesdf(resoCollisionsdf.lastIndex(), + // casc.globalIndex(), + track.pt(), + track.px(), + track.py(), + track.pz(), + const_cast(track.cascadeIndices()), + (int8_t)(track.daughterTPCNSigmaPosPi() * 10), + (int8_t)(track.daughterTPCNSigmaPosKa() * 10), + (int8_t)(track.daughterTPCNSigmaPosPr() * 10), + (int8_t)(track.daughterTPCNSigmaNegPi() * 10), + (int8_t)(track.daughterTPCNSigmaNegKa() * 10), + (int8_t)(track.daughterTPCNSigmaNegPr() * 10), + (int8_t)(track.daughterTPCNSigmaBachPi() * 10), + (int8_t)(track.daughterTPCNSigmaBachKa() * 10), + (int8_t)(track.daughterTPCNSigmaBachPr() * 10), + (int8_t)(track.daughterTOFNSigmaPosPi() * 10), + (int8_t)(track.daughterTOFNSigmaPosKa() * 10), + (int8_t)(track.daughterTOFNSigmaPosPr() * 10), + (int8_t)(track.daughterTOFNSigmaNegPi() * 10), + (int8_t)(track.daughterTOFNSigmaNegKa() * 10), + (int8_t)(track.daughterTOFNSigmaNegPr() * 10), + (int8_t)(track.daughterTOFNSigmaBachPi() * 10), + (int8_t)(track.daughterTOFNSigmaBachKa() * 10), + (int8_t)(track.daughterTOFNSigmaBachPr() * 10), + track.v0CosPA(), + track.cascCosPA(), + track.daughDCA(), + track.cascDaughDCA(), + track.dcapostopv(), + track.dcanegtopv(), + track.dcabachtopv(), + track.dcav0topv(), + track.dcaXYCascToPV(), + track.dcaZCascToPV(), + track.sign(), + track.mLambda(), + track.mXi(), + track.transRadius(), track.cascTransRadius(), track.decayVtxX(), track.decayVtxY(), track.decayVtxZ()); + } + } + PROCESS_SWITCH(ResonanceMergeDF, processXi1530Candidate, "Process for Xi(1530) candidate", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Resonances/resonanceModuleInitializer.cxx b/PWGLF/TableProducer/Resonances/resonanceModuleInitializer.cxx new file mode 100644 index 00000000000..5dc53b28509 --- /dev/null +++ b/PWGLF/TableProducer/Resonances/resonanceModuleInitializer.cxx @@ -0,0 +1,1411 @@ +// 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 resonanceModuleInitializer.cxx +/// \brief Initializes variables for the resonance candidate producers +/// +/// \author Bong-Hwi Lim + +#include +#include +#include "CCDB/BasicCCDBManager.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/Core/EventPlaneHelper.h" +#include "CommonConstants/PhysicsConstants.h" +#include "CommonConstants/MathConstants.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFResonanceTables.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/collisionCuts.h" +#include "ReconstructionDataFormats/Track.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; +using namespace o2::constants::math; +using namespace o2::aod::rctsel; + +/** + * @brief Initializer for the event pool for resonance study + * + * This struct is responsible for initializing and processing collision data + * for resonance studies. It handles event selection, centrality estimation, + * and QA histogram filling. + */ +struct ResonanceModuleInitializer { + int mRunNumber; ///< Run number for the current data + int multEstimator; ///< Multiplicity estimator type + float dBz; ///< Magnetic field value + float centrality; ///< Centrality value for the event + Service ccdb; ///< CCDB manager service + Service pdg; ///< PDG database service + EventPlaneHelper helperEP; ///< Helper for event plane calculations + + Produces resoCollisions; ///< Output table for resonance collisions + Produces resoCollisionColls; ///< Output table for collision references + Produces resoMCCollisions; ///< Output table for MC resonance collisions + Produces resoSpheroCollisions; ///< Output table for spherocity + Produces resoEvtPlCollisions; ///< Output table for event plane + + // CCDB options + Configurable ccdbURL{"ccdbURL", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + + Configurable cfgFatalWhenNull{"cfgFatalWhenNull", true, "Fatal when null on ccdb access"}; + Configurable cfgBypassCollIndexFill{"cfgBypassCollIndexFill", false, "Bypass collision index fill"}; + + // Configurables + Configurable dBzInput{"dBzInput", -999, "bz field, -999 is automatic"}; + Configurable cfgFillQA{"cfgFillQA", false, "Fill QA histograms"}; + Configurable cfgBypassCCDB{"cfgBypassCCDB", true, "Bypass loading CCDB part to save CPU time and memory"}; // will be affected to b_z value. + Configurable cfgMultName{"cfgMultName", "FT0M", "The name of multiplicity estimator"}; + Configurable cfgCentralityMC{"cfgCentralityMC", 0, "Centrality estimator for MC (0: Reco, 1: MC, 2: impact parameter)"}; + + // EventCorrection for MC + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 0.01, 0.1, 1.0, 5.0, 10., 15., 20., 30., 40., 50., 70., 100.0, 105.}, "Binning of the centrality axis"}; + ConfigurableAxis cfgVtxBins{"cfgVtxBins", {VARIABLE_WIDTH, -20, -15, -10, -7, -5, -3, -2, -1, 0, 1, 2, 3, 5, 7, 10, 15, 20}, "Mixing bins - z-vertex"}; + + /// Event cuts + o2::analysis::CollisonCuts colCuts; + Configurable cfgEvtZvtx{"cfgEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; + Configurable cfgEvtOccupancyInTimeRange{"cfgEvtOccupancyInTimeRange", -1, "Evt sel: maximum track occupancy"}; + Configurable cfgEvtTriggerCheck{"cfgEvtTriggerCheck", false, "Evt sel: check for trigger"}; + Configurable cfgEvtOfflineCheck{"cfgEvtOfflineCheck", true, "Evt sel: check for offline selection"}; + Configurable cfgEvtTriggerTVXSel{"cfgEvtTriggerTVXSel", false, "Evt sel: triggerTVX selection (MB)"}; + Configurable cfgEvtTFBorderCut{"cfgEvtTFBorderCut", false, "Evt sel: apply TF border cut"}; + Configurable cfgEvtUseITSTPCvertex{"cfgEvtUseITSTPCvertex", false, "Evt sel: use at lease on ITS-TPC track for vertexing"}; + Configurable cfgEvtCollInTimeRangeNarrow{"cfgEvtCollInTimeRangeNarrow", false, "Evt sel: apply NoCollInTimeRangeNarrow"}; + Configurable cfgEvtZvertexTimedifference{"cfgEvtZvertexTimedifference", false, "Evt sel: apply Z-vertex time difference"}; + Configurable cfgEvtPileupRejection{"cfgEvtPileupRejection", false, "Evt sel: apply pileup rejection"}; + Configurable cfgEvtNoITSROBorderCut{"cfgEvtNoITSROBorderCut", false, "Evt sel: apply NoITSRO border cut"}; + Configurable cfgEvtRun2AliEventCuts{"cfgEvtRun2AliEventCuts", true, "Evt sel: apply Run2 AliEventCuts"}; + Configurable cfgEvtRun2INELgtZERO{"cfgEvtRun2INELgtZERO", false, "Evt sel: apply Run2 INELgtZERO"}; + Configurable cfgEvtUseRCTFlagChecker{"cfgEvtUseRCTFlagChecker", false, "Evt sel: use RCT flag checker"}; + Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; + Configurable cfgEvtRCTFlagCheckerZDCCheck{"cfgEvtRCTFlagCheckerZDCCheck", false, "Evt sel: RCT flag checker ZDC check"}; + Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", false, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + RCTFlagsChecker rctChecker; + + // Spherocity configuration + Configurable cfgTrackSphMin{"cfgTrackSphMin", 10, "Number of tracks for Spherocity Calculation"}; + Configurable cfgTrackSphDef{"cfgTrackSphDef", 0, "Spherocity Definition: |pT| = 1 -> 0, otherwise -> 1"}; + + // Qvector configuration + Configurable cfgEvtPl{"cfgEvtPl", 40500, "Configuration of three subsystems for the event plane and its resolution, 10000*RefA + 100*RefB + S, where FT0C:0, FT0A:1, FT0M:2, FV0A:3, BPos:5, BNeg:6"}; + + int evtPlRefAId = static_cast(cfgEvtPl / 10000); + int evtPlRefBId = static_cast((cfgEvtPl - evtPlRefAId * 10000) / 100); + int evtPlDetId = cfgEvtPl - evtPlRefAId * 10000 - evtPlRefBId * 100; + + HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgEvtZvtx; + + /** + * @brief Initializes the task + * + * @param context Initialization context + */ + void init(InitContext&) + { + mRunNumber = 0; + dBz = 0; + centrality = 0; + // Determine the multiplicity estimator based on the configuration + multEstimator = 0; + if (cfgMultName.value == "FT0M") { + multEstimator = 0; + } else if (cfgMultName.value == "FT0C") { + multEstimator = 1; + } else if (cfgMultName.value == "FT0A") { + multEstimator = 2; + } + LOGF(info, "Mult estimator: %d, %s", multEstimator, cfgMultName.value.c_str()); + + // Ensure that only one process type is active at a time + if (doprocessRun3 && doprocessRun2) { + LOG(fatal) << "You cannot run both Run2 and Run3 processes at the same time"; + } + if (doprocessRun2MC && doprocessRun3MC) { + LOG(fatal) << "You cannot run both Run2 and Run3 MC processes at the same time"; + } + + // Initialize event selection cuts based on the process type + if (doprocessRun2) { + colCuts.setCuts(cfgEvtZvtx, cfgEvtTriggerCheck, cfgEvtOfflineCheck, false); + } else if (doprocessRun3) { + colCuts.setCuts(cfgEvtZvtx, cfgEvtTriggerCheck, cfgEvtOfflineCheck, true, false, cfgEvtOccupancyInTimeRange); + } + colCuts.init(&qaRegistry); + colCuts.setTriggerTVX(cfgEvtTriggerTVXSel); + colCuts.setApplyTFBorderCut(cfgEvtTFBorderCut); + colCuts.setApplyITSTPCvertex(cfgEvtUseITSTPCvertex); + colCuts.setApplyCollInTimeRangeNarrow(cfgEvtCollInTimeRangeNarrow); + colCuts.setApplyZvertexTimedifference(cfgEvtZvertexTimedifference); + colCuts.setApplyPileupRejection(cfgEvtPileupRejection); + colCuts.setApplyNoITSROBorderCut(cfgEvtNoITSROBorderCut); + colCuts.setApplyRun2AliEventCuts(cfgEvtRun2AliEventCuts); + colCuts.setApplyRun2INELgtZERO(cfgEvtRun2INELgtZERO); + + rctChecker.init(cfgEvtRCTFlagCheckerLabel, cfgEvtRCTFlagCheckerZDCCheck, cfgEvtRCTFlagCheckerLimitAcceptAsBad); + + // Configure CCDB access if not bypassed + if (!cfgBypassCCDB) { + ccdb->setURL(ccdbURL.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(cfgFatalWhenNull); + uint64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); // TODO must become global parameter from the train creation time + } + + // Initialize QA histograms if required + if (doprocessRun3MC || doprocessRun2MC) { + AxisSpec centAxis = {binsCent, "Centrality (%)"}; + AxisSpec idxMCAxis = {26, -0.5, 25.5, "Index"}; + qaRegistry.add("Event/hMCEventIndices", "hMCEventIndices", kTH2D, {centAxis, idxMCAxis}); + } + } + + /** + * @brief Initializes CCDB for a given BC + * + * @param bc BC iterator + */ + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) // Simple copy from LambdaKzeroFinder.cxx + { + if (cfgBypassCCDB) + return; + if (mRunNumber == bc.runNumber()) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (dBzInput > -990) { + dBz = dBzInput; + ; + o2::parameters::GRPMagField grpmag; + if (std::fabs(dBz) > 1e-5) { + grpmag.setL3Current(30000.f / (dBz / 5.0f)); + } + o2::base::Propagator::initFieldFromGRP(&grpmag); + mRunNumber = bc.runNumber(); + return; + } + + auto run3grpTimestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grpTimestamp); + o2::parameters::GRPMagField* grpmag = 0x0; + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + // Fetch magnetic field from ccdb for current collision + dBz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grpTimestamp << " with magnetic field of " << dBz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grpTimestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grpTimestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + // Fetch magnetic field from ccdb for current collision + dBz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grpTimestamp << " with magnetic field of " << dBz << " kZG"; + } + mRunNumber = bc.runNumber(); + // Set magnetic field value once known + LOGF(info, "Bz set to %f for run: ", dBz, mRunNumber); + } + + /** + * @brief Checks if the collision is INEL>0 + * + * @tparam MCPart Type of MC particles + * @param mcparts MC particles + * @return true if INEL>0, false otherwise + */ + template + bool isTrueINEL0(MCPart const& mcparts) + { + for (auto const& mcparticle : mcparts) { + if (!mcparticle.isPhysicalPrimary()) + continue; + auto p = pdg->GetParticle(mcparticle.pdgCode()); + if (p != nullptr) { + if (std::abs(p->Charge()) >= 3) { + if (std::abs(mcparticle.eta()) < 1) + return true; + } + } + } + return false; + } + + /** + * @brief Centrality estimator selection + * + * @tparam ResoColl Type of resonance collision + * @tparam isMC Boolean indicating if it's MC + * @param ResoEvents Resonance events + * @return Centrality value + */ + template + float centEst(ResoColl ResoEvents) + { + float returnValue = -999.0; + switch (multEstimator) { + case 0: + returnValue = ResoEvents.centFT0M(); + break; + case 1: + if constexpr (isMC) { + LOG(fatal) << "CentFT0C is not available for MC"; + return returnValue; + } else { + returnValue = ResoEvents.centFT0C(); + break; + } + case 2: + if constexpr (isMC) { + LOG(fatal) << "CentFT0A is not available for MC"; + return returnValue; + } else { + returnValue = ResoEvents.centFT0A(); + break; + } + default: + returnValue = ResoEvents.centFT0M(); + break; + } + return returnValue; + } + using GenMCCollisions = soa::Join; + float centEstMC(const GenMCCollisions::iterator& collision) { return centEst(collision); } + + /** + * @brief Computes the spherocity of an event + * + * @tparam T Type of the tracks + * @param tracks All tracks + * @param nTracksMin Minimum number of tracks + * @param spdef Spherocity definition + * @return Spherocity value + */ + template + float computeSpherocity(T const& tracks, int nTracksMin, int spdef) + { + // if number of tracks is not enough for spherocity estimation. + int ntrks = tracks.size(); + if (ntrks < nTracksMin) + return -99.; + + // start computing spherocity + + float ptSum = 0.; + for (auto const& track : tracks) { + if (cfgFillQA) { + qaRegistry.fill(HIST("Phi"), track.phi()); + } + if (spdef == 0) { + ptSum += 1.; + } else { + ptSum += track.pt(); + } + } + + float tempSph = 1.; + for (int i = 0; i < 360 / 0.1; ++i) { + float sum = 0., pt = 0.; + float phiparm = (PI * i * 0.1) / 180.; + float nx = std::cos(phiparm); + float ny = std::sin(phiparm); + for (auto const& trk : tracks) { + pt = trk.pt(); + if (spdef == 0) { + pt = 1.; + } + float phi = trk.phi(); + float px = pt * std::cos(phi); + float py = pt * std::sin(phi); + // sum += pt * abs(sin(phiparm - phi)); + sum += std::abs(px * ny - py * nx); + } + float sph = std::pow((sum / ptSum), 2); + if (sph < tempSph) + tempSph = sph; + } + + return std::pow(PIHalf, 2) * tempSph; + } + + /** + * @brief Gets the event plane + * + * @tparam ResoColl Type of resonance collision + * @param ResoEvents Resonance events + * @return Event plane value + */ + template + float getEvtPl(ResoColl ResoEvents) + { + float returnValue = -999.0; + if (ResoEvents.qvecAmp()[evtPlDetId] > 1e-8) + returnValue = helperEP.GetEventPlane(ResoEvents.qvecRe()[evtPlDetId * 4 + 3], ResoEvents.qvecIm()[evtPlDetId * 4 + 3], 2); + return returnValue; + } + + /** + * @brief Gets the event plane resolution + * + * @tparam ResoColl Type of resonance collision + * @param ResoEvents Resonance events + * @param a First index + * @param b Second index + * @return Event plane resolution + */ + template + float getEvtPlRes(ResoColl ResoEvents, int a, int b) + { + float returnValue = -999.0; + if (ResoEvents.qvecAmp()[a] < 1e-8 || ResoEvents.qvecAmp()[b] < 1e-8) + return returnValue; + returnValue = helperEP.GetResolution(helperEP.GetEventPlane(ResoEvents.qvecRe()[a * 4 + 3], ResoEvents.qvecIm()[a * 4 + 3], 2), helperEP.GetEventPlane(ResoEvents.qvecRe()[b * 4 + 3], ResoEvents.qvecIm()[b * 4 + 3], 2), 2); + return returnValue; + } + + /** + * @brief Fills MC particles + * + * @tparam CollisionType Type of collision + * @tparam SelectedMCPartType Type of selected MC particles + * @tparam TotalMCParts Type of total MC particles + * @param collision Collision data + * @param mcParts Selected MC particles + * @param mcParticles Total MC particles + */ + template + void fillMCParticles(CollisionType collision, SelectedMCPartType const& mcParts, TotalMCParts const& mcParticles) + { + for (auto const& mcPart : mcParts) { + std::vector daughterPDGs; + if (mcPart.has_daughters()) { + auto daughter01 = mcParticles.rawIteratorAt(mcPart.daughtersIds()[0] - mcParticles.offset()); + auto daughter02 = mcParticles.rawIteratorAt(mcPart.daughtersIds()[1] - mcParticles.offset()); + daughterPDGs = {daughter01.pdgCode(), daughter02.pdgCode()}; + } else { + daughterPDGs = {-1, -1}; + } + reso2mcparents(collision.globalIndex(), + mcPart.globalIndex(), + mcPart.pdgCode(), + daughterPDGs[0], daughterPDGs[1], + mcPart.isPhysicalPrimary(), + mcPart.producedByGenerator(), + mcPart.pt(), + mcPart.px(), + mcPart.py(), + mcPart.pz(), + mcPart.eta(), + mcPart.phi(), + mcPart.y()); + daughterPDGs.clear(); + } + } + + /** + * @brief Fills MC collision data + * + * @tparam isRun2 Boolean indicating if it's Run2 + * @tparam MCCol Type of MC collision + * @tparam MCPart Type of MC particles + * @param mccol MC collision data + * @param mcparts MC particles + */ + template + void fillMCCollision(MCCol const& mccol, MCPart const& mcparts) + { + const auto& mcColg = mccol.template mcCollision_as(); + float mcCent = 999.0; + if constexpr (isRun2) { + if (cfgCentralityMC == 0) { + mcCent = mccol.centRun2V0M(); + } else { + mcCent = mcColg.impactParameter(); + } + } else { + if (cfgCentralityMC == 0) { + mcCent = centEst(mccol); + } else if (cfgCentralityMC == 1) { + mcCent = centEstMC(mcColg); + } else if (cfgCentralityMC == 2) { + mcCent = mcColg.impactParameter(); + } + } + bool inVtx10 = (std::abs(mcColg.posZ()) > 10.) ? false : true; + bool isTrueINELgt0 = isTrueINEL0(mcparts); + bool isTriggerTVX = mccol.selection_bit(aod::evsel::kIsTriggerTVX); + bool isSel8 = mccol.sel8(); + bool isSelected = colCuts.isSelected(mccol); + resoMCCollisions(inVtx10, isTrueINELgt0, isTriggerTVX, isSel8, isSelected, mcCent); + + // QA for Trigger efficiency + qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kINEL); + if (inVtx10) + qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kINEL10); + if (isTrueINELgt0) + qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kINELg0); + if (inVtx10 && isTrueINELgt0) + qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kINELg010); + + // TVX MB trigger + if (isTriggerTVX) + qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kTrig); + if (isTriggerTVX && inVtx10) + qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kTrig10); + if (isTriggerTVX && isTrueINELgt0) + qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kTrigINELg0); + if (isTriggerTVX && isTrueINELgt0 && inVtx10) + qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kTrigINELg010); + + // Sel8 event selection + if (isSel8) + qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kSel8); + if (isSel8 && inVtx10) + qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kSel810); + if (isSel8 && isTrueINELgt0) + qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kSel8INELg0); + if (isSel8 && isTrueINELgt0 && inVtx10) + qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kSel8INELg010); + + // CollisionCuts selection + if (isSelected) + qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kAllCuts); + if (isSelected && inVtx10) + qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kAllCuts10); + if (isSelected && isTrueINELgt0) + qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kAllCutsINELg0); + if (isSelected && isTrueINELgt0 && inVtx10) + qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kAllCutsINELg010); + } + + /** + * @brief Processes Dummy + * + * @param collision Collision data + */ + void processDummy(aod::Collisions const&) + { + } + PROCESS_SWITCH(ResonanceModuleInitializer, processDummy, "process Dummy", true); + + /** + * @brief Processes Run3 data + * + * @param collision Collision data + * @param bc BC data + */ + void processRun3(soa::Filtered::iterator const& collision, + aod::BCsWithTimestamps const&) + { + auto bc = collision.bc_as(); + initCCDB(bc); + // Default event selection + if (!colCuts.isSelected(collision)) + return; + if (cfgEvtUseRCTFlagChecker && !rctChecker(collision)) + return; + colCuts.fillQA(collision); + centrality = centEst(collision); + + resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), centrality, dBz); + if (!cfgBypassCollIndexFill) { + resoCollisionColls(collision.globalIndex()); + } + } + PROCESS_SWITCH(ResonanceModuleInitializer, processRun3, "Default process for RUN3", false); + + /** + * @brief Processes Run2 data + * + * @param collision Collision data + * @param bc BC data + */ + void processRun2(soa::Filtered::iterator const& collision, + aod::BCsWithRun2Info const&) + { + // auto bc = collision.bc_as(); + // Default event selection + if (!colCuts.isSelected(collision)) + return; + colCuts.fillQARun2(collision); + centrality = collision.centRun2V0M(); + + resoCollisions(0, collision.posX(), collision.posY(), collision.posZ(), centrality, dBz); + if (!cfgBypassCollIndexFill) { + resoCollisionColls(collision.globalIndex()); + } + } + PROCESS_SWITCH(ResonanceModuleInitializer, processRun2, "process for RUN2", false); + + /** + * @brief Processes Run3 MC data + * + * @param collision Collision data + * @param mcParticles MC particles + * @param mcCollisions MC collisions + */ + void processRun3MC(soa::Filtered::iterator const& collision, + aod::McParticles const& mcParticles, GenMCCollisions const&) + { + if (cfgEvtUseRCTFlagChecker && !rctChecker(collision)) + return; + fillMCCollision(collision, mcParticles); + } + PROCESS_SWITCH(ResonanceModuleInitializer, processRun3MC, "process MC for RUN3", false); + + /** + * @brief Processes Run2 MC data + * + * @param collision Collision data + * @param mcParticles MC particles + */ + void processRun2MC(soa::Filtered::iterator const& collision, + aod::McParticles const& mcParticles) + { + fillMCCollision(collision, mcParticles); + } + PROCESS_SWITCH(ResonanceModuleInitializer, processRun2MC, "process MC for RUN2", false); + + /** + * @brief Processes Spherocity + * + * @param collision Collision data + * @param tracks Track data + */ + void processSpherocity(soa::Filtered::iterator const& /*collision*/, aod::ResoTrackCandidates const& tracks) + { + float spherocity = computeSpherocity(tracks, cfgTrackSphMin, cfgTrackSphDef); + resoSpheroCollisions(spherocity); + } + PROCESS_SWITCH(ResonanceModuleInitializer, processSpherocity, "process Spherocity", false); + + /** + * @brief Processes Event Plane + * + * @param collision Collision data with Qvectors + * @param tracks Track data + */ + void processEventPlane(soa::Filtered>::iterator const& collision) + { + resoEvtPlCollisions(getEvtPl(collision), getEvtPlRes(collision, evtPlDetId, evtPlRefAId), getEvtPlRes(collision, evtPlDetId, evtPlRefBId), getEvtPlRes(collision, evtPlRefAId, evtPlRefBId)); + } + PROCESS_SWITCH(ResonanceModuleInitializer, processEventPlane, "process Event Plane", false); +}; + +/** + * @brief Initializer for the resonance daughters producer + * + * This struct initializes and processes daughters for resonance studies. + * It applies daughter selection criteria and fills QA histograms for daughter properties. + */ +struct ResonanceDaughterInitializer { + SliceCache cache; + Produces reso2trks; ///< Output table for resonance tracks + Produces resoTrackTracks; ///< Output table for resonance track tracks + Produces reso2microtrks; ///< Output table for resonance microtracks + Produces resoMicroTrackTracks; ///< Output table for resonance microtrack tracks + Produces reso2mctracks; ///< Output table for MC resonance tracks + Produces reso2v0s; ///< Output table for resonance V0s + Produces resoV0V0s; ///< Output table for resonance V0-V0s + Produces reso2mcv0s; ///< Output table for MC resonance V0s + Produces reso2cascades; ///< Output table for resonance cascades + Produces resoCascadeCascades; ///< Output table for resonance cascade-cascades + Produces reso2mccascades; ///< Output table for MC resonance cascades + + // Configurables + Configurable cfgFillQA{"cfgFillQA", false, "Fill QA histograms"}; + Configurable cfgFillMicroTracks{"cfgFillMicroTracks", false, "Fill micro tracks"}; + Configurable cfgBypassTrackFill{"cfgBypassTrackFill", true, "Bypass track fill"}; + Configurable cfgBypassTrackIndexFill{"cfgBypassTrackIndexFill", false, "Bypass track index fill"}; + + // Configurables for tracks + Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 2.0, "Track DCAr cut to PV Maximum"}; + Configurable cMinDCArToPVcut{"cMinDCArToPVcut", 0.0, "Track DCAr cut to PV Minimum"}; + Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; + Configurable cMinDCAzToPVcut{"cMinDCAzToPVcut", 0.0, "Track DCAz cut to PV Minimum"}; + Configurable pidnSigmaPreSelectionCut{"pidnSigmaPreSelectionCut", 5.0f, "TPC and TOF PID cut (loose, improve performance)"}; + Configurable trackSelection{"trackSelection", 1, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; + + // Configurables for V0s + Configurable cMinV0Radius{"cMinV0Radius", 0.0, "Minimum V0 radius from PV"}; + Configurable cMaxV0Radius{"cMaxV0Radius", 200.0, "Maximum V0 radius from PV"}; + Configurable cMinV0CosPA{"cMinV0CosPA", 0.995, "Minimum V0 CosPA to PV"}; + + // Configurables for cascades + Configurable cMinCascRadius{"cMinCascRadius", 0.0, "Minimum Cascade radius from PV"}; + Configurable cMaxCascRadius{"cMaxCascRadius", 200.0, "Maximum Cascade radius from PV"}; + Configurable cMinCascCosPA{"cMinCascCosPA", 0.97, "Minimum Cascade CosPA to PV"}; + + // Derived dataset selections + struct : ConfigurableGroup { + Configurable cfgFillPionTracks{"cfgFillPionTracks", false, "Fill pion tracks"}; + Configurable cfgFillKaonTracks{"cfgFillKaonTracks", false, "Fill kaon tracks"}; + Configurable cfgFillProtonTracks{"cfgFillProtonTracks", false, "Fill proton tracks"}; + Configurable cfgFillPionMicroTracks{"cfgFillPionMicroTracks", false, "Fill pion micro tracks"}; + Configurable cfgFillKaonMicroTracks{"cfgFillKaonMicroTracks", false, "Fill kaon micro tracks"}; + Configurable cfgFillProtonMicroTracks{"cfgFillProtonMicroTracks", false, "Fill proton micro tracks"}; + } FilterForDerivedTables; + + // Filters + Filter dcaXYFilter = nabs(aod::track::dcaXY) < cMaxDCArToPVcut && nabs(aod::track::dcaXY) > cMinDCArToPVcut; + Filter dcaZFilter = nabs(aod::track::dcaZ) < cMaxDCAzToPVcut && nabs(aod::track::dcaZ) > cMinDCAzToPVcut; + Preslice perMcCollision = aod::mcparticle::mcCollisionId; + + // Track selection filter based on configuration + Filter trackFilter = (trackSelection.node() == 0) || + ((trackSelection.node() == 1) && requireGlobalTrackInFilter()) || // kGlobalTrack = kQualityTracks | kPrimaryTracks | kInAcceptanceTracks + ((trackSelection.node() == 2) && requireGlobalTrackWoPtEtaInFilter()) || // kGlobalTrackWoPtEta = kQualityTracks | kPrimaryTracks + ((trackSelection.node() == 3) && requireGlobalTrackWoDCAInFilter()) || // kGlobalTrackWoDCA = kQualityTracks | kInAcceptanceTracks + ((trackSelection.node() == 4) && requireQualityTracksInFilter()) || // kQualityTracks = kQualityTracksITS | kQualityTracksTPC + ((trackSelection.node() == 5) && requireTrackCutInFilter(TrackSelectionFlags::kInAcceptanceTracks)); // kInAcceptanceTracks = kPtRange | kEtaRange + HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + /** + * @brief Initializes the task + * + * @param context Initialization context + */ + void init(InitContext&) + { + if (cfgFillQA) { + AxisSpec idxAxis = {8, -0.5, 7.5, "Index"}; + AxisSpec ptAxis = {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec etaAxis = {100, -1.0f, 1.0f, "#eta"}; + AxisSpec phiAxis = {100, 0.0f, TwoPI, "#phi"}; + + qaRegistry.add("QA/hGoodTrackIndices", "hGoodTrackIndices", kTH1D, {idxAxis}); + if (doprocessMC) { + qaRegistry.add("QA/hGoodMCTrackIndices", "hGoodMCTrackIndices", kTH1D, {idxAxis}); + } + qaRegistry.add("QA/hTrackPt", "Track pT", kTH1F, {ptAxis}); + qaRegistry.add("QA/hTrackEta", "Track eta", kTH1F, {etaAxis}); + qaRegistry.add("QA/hTrackPhi", "Track phi", kTH1F, {phiAxis}); + + if (doprocessV0Data || doprocessV0MC) { + qaRegistry.add("QA/hGoodV0Indices", "hGoodV0Indices", kTH1D, {idxAxis}); + if (doprocessMC) { + qaRegistry.add("QA/hGoodMCV0Indices", "hGoodMCV0Indices", kTH1D, {idxAxis}); + } + AxisSpec radiusAxis = {100, 0.0, 200.0, "V0 Radius"}; + AxisSpec cosPAAxis = {100, 0.995, 1.0, "V0 CosPA"}; + qaRegistry.add("QA/hV0Radius", "V0 Radius", kTH1F, {radiusAxis}); + qaRegistry.add("QA/hV0CosPA", "V0 CosPA", kTH1F, {cosPAAxis}); + } + + if (doprocessCascData || doprocessCascMC) { + AxisSpec radiusAxis = {100, 0.0, 200.0, "Cascade Radius"}; + AxisSpec cosPAAxis = {100, 0.97, 1.0, "Cascade CosPA"}; + qaRegistry.add("QA/hGoodCascIndices", "hGoodCascIndices", kTH1D, {idxAxis}); + if (doprocessMC) { + qaRegistry.add("QA/hGoodMCCascIndices", "hGoodMCCascIndices", kTH1D, {idxAxis}); + } + qaRegistry.add("QA/hCascRadius", "Cascade Radius", kTH1F, {radiusAxis}); + qaRegistry.add("QA/hCascCosPA", "Cascade CosPA", kTH1F, {cosPAAxis}); + } + } + if (doprocessData || doprocessMC) { + LOGF(info, "ResonanceDaughterInitializer initialized with tracks"); + } + if (doprocessV0Data || doprocessV0MC) { + LOGF(info, "ResonanceDaughterInitializer initialized with V0s"); + } + if (doprocessCascData || doprocessCascMC) { + LOGF(info, "ResonanceDaughterInitializer initialized with cascades"); + } + + // Check if the module is initialized with both data and MC + if ((doprocessData && doprocessMC) || (doprocessV0Data && doprocessV0MC) || (doprocessCascData && doprocessCascMC)) { + LOGF(fatal, "ResonanceDaughterInitializer initialized with both data and MC"); + } + // Check if none of the processes are enabled + if (!doprocessDummy && !doprocessData && !doprocessMC && !doprocessV0Data && !doprocessV0MC && !doprocessCascData && !doprocessCascMC) { + LOGF(fatal, "ResonanceDaughterInitializer not initialized, enable at least one process"); + } + } + template + bool filterMicroTrack(T const& track) + { + // if no selection is requested, return true + if (!FilterForDerivedTables.cfgFillPionMicroTracks && !FilterForDerivedTables.cfgFillKaonMicroTracks && !FilterForDerivedTables.cfgFillProtonMicroTracks) + return true; + if (FilterForDerivedTables.cfgFillPionMicroTracks) { + if (std::abs(track.tpcNSigmaPi()) < pidnSigmaPreSelectionCut) + return true; + } + if (FilterForDerivedTables.cfgFillKaonMicroTracks) { + if (std::abs(track.tpcNSigmaKa()) < pidnSigmaPreSelectionCut) + return true; + } + if (FilterForDerivedTables.cfgFillProtonMicroTracks) { + if (std::abs(track.tpcNSigmaPr()) < pidnSigmaPreSelectionCut) + return true; + } + return false; + } + + template + bool filterTrack(T const& track) + { + // if no selection is requested, return true + if (!FilterForDerivedTables.cfgFillPionTracks && !FilterForDerivedTables.cfgFillKaonTracks && !FilterForDerivedTables.cfgFillProtonTracks) + return true; + if (FilterForDerivedTables.cfgFillPionTracks) { + if (std::abs(track.tpcNSigmaPi()) < pidnSigmaPreSelectionCut) + return true; + } + if (FilterForDerivedTables.cfgFillKaonTracks) { + if (std::abs(track.tpcNSigmaKa()) < pidnSigmaPreSelectionCut) + return true; + } + if (FilterForDerivedTables.cfgFillProtonTracks) { + if (std::abs(track.tpcNSigmaPr()) < pidnSigmaPreSelectionCut) + return true; + } + return false; + } + + /** + * @brief Fills track data + * + * @tparam isMC Boolean indicating if it's MC + * @tparam TrackType Type of track + * @tparam CollisionType Type of collision + * @param collision Collision data + * @param tracks Track data + */ + template + void fillMicroTracks(CollisionType const& collision, TrackType const& tracks) + { + // Loop over tracks + for (auto const& track : tracks) { + if (!filterMicroTrack(track)) + continue; + o2::aod::resodmciroaughter::ResoMicroTrackSelFlag trackSelFlag(track.dcaXY(), track.dcaZ()); + if (std::abs(track.dcaXY()) < (0.004 + (0.013 / track.pt()))) { + trackSelFlag.setDCAxy0(); + } + if (std::abs(track.dcaZ()) < (0.004 + (0.013 / track.pt()))) { // TODO: check this + trackSelFlag.setDCAz0(); + } + uint8_t trackFlags = (track.passedITSRefit() << 0) | + (track.passedTPCRefit() << 1) | + (track.isGlobalTrackWoDCA() << 2) | + (track.isGlobalTrack() << 3) | + (track.isPrimaryTrack() << 4) | + (track.isPVContributor() << 5) | + (track.hasTOF() << 6) | + ((track.sign() > 0) << 7); // sign +1: 1, -1: 0 + reso2microtrks(collision.globalIndex(), + track.px(), + track.py(), + track.pz(), + static_cast(o2::aod::resodmciroaughter::PidNSigma(std::abs(track.tpcNSigmaPi()), std::abs(track.tofNSigmaPi()), track.hasTOF())), + static_cast(o2::aod::resodmciroaughter::PidNSigma(std::abs(track.tpcNSigmaKa()), std::abs(track.tofNSigmaKa()), track.hasTOF())), + static_cast(o2::aod::resodmciroaughter::PidNSigma(std::abs(track.tpcNSigmaPr()), std::abs(track.tofNSigmaPr()), track.hasTOF())), + static_cast(trackSelFlag), + trackFlags); + if (!cfgBypassTrackIndexFill) { + resoMicroTrackTracks(track.globalIndex()); + } + } + } + + /** + * @brief Fills track data + * + * @tparam isMC Boolean indicating if it's MC + * @tparam TrackType Type of track + * @tparam CollisionType Type of collision + * @param collision Collision data + * @param tracks Track data + */ + template + void fillTracks(CollisionType const& collision, TrackType const& tracks) + { + if (cfgBypassTrackFill) { + return; + } + // Loop over tracks + for (auto const& track : tracks) { + if (!filterTrack(track)) + continue; + if (cfgFillQA) { + qaRegistry.fill(HIST("QA/hGoodTrackIndices"), 0); + qaRegistry.fill(HIST("QA/hTrackPt"), track.pt()); + qaRegistry.fill(HIST("QA/hTrackEta"), track.eta()); + qaRegistry.fill(HIST("QA/hTrackPhi"), track.phi()); + } + uint8_t trackFlags = (track.passedITSRefit() << 0) | + (track.passedTPCRefit() << 1) | + (track.isGlobalTrackWoDCA() << 2) | + (track.isGlobalTrack() << 3) | + (track.isPrimaryTrack() << 4) | + (track.isPVContributor() << 5) | + (track.hasTOF() << 6) | + ((track.sign() > 0) << 7); // sign +1: 1, -1: 0 + reso2trks(collision.globalIndex(), + track.pt(), + track.px(), + track.py(), + track.pz(), + (uint8_t)track.tpcNClsCrossedRows(), + (uint8_t)track.tpcNClsFound(), + static_cast(track.dcaXY() * 10000), + static_cast(track.dcaZ() * 10000), + (int8_t)(track.tpcNSigmaPi() * 10), + (int8_t)(track.tpcNSigmaKa() * 10), + (int8_t)(track.tpcNSigmaPr() * 10), + (int8_t)(track.tofNSigmaPi() * 10), + (int8_t)(track.tofNSigmaKa() * 10), + (int8_t)(track.tofNSigmaPr() * 10), + (int8_t)(track.tpcSignal() * 10), + trackFlags); + if (!cfgBypassTrackIndexFill) { + resoTrackTracks(track.globalIndex()); + } + if constexpr (isMC) { + fillMCTrack(track); + } + } + } + + /** + * @brief Fills MC track data + * + * @tparam TrackType Type of track + * @param track Track data + */ + template + void fillMCTrack(TrackType const& track) + { + // ------ Temporal lambda function to prevent error in build + auto getMothersIndeces = [&](auto const& theMcParticle) { + std::vector lMothersIndeces{}; + for (auto const& lMother : theMcParticle.template mothers_as()) { + LOGF(debug, " mother index lMother: %d", lMother.globalIndex()); + lMothersIndeces.push_back(lMother.globalIndex()); + } + return lMothersIndeces; + }; + auto getMothersPDGCodes = [&](auto const& theMcParticle) { + std::vector lMothersPDGs{}; + for (auto const& lMother : theMcParticle.template mothers_as()) { + LOGF(debug, " mother pdgcode lMother: %d", lMother.pdgCode()); + lMothersPDGs.push_back(lMother.pdgCode()); + } + return lMothersPDGs; + }; + auto getSiblingsIndeces = [&](auto const& theMcParticle) { + std::vector lSiblingsIndeces{}; + for (auto const& lMother : theMcParticle.template mothers_as()) { + LOGF(debug, " mother index lMother: %d", lMother.globalIndex()); + for (auto const& lDaughter : lMother.template daughters_as()) { + LOGF(debug, " daughter index lDaughter: %d", lDaughter.globalIndex()); + if (lDaughter.globalIndex() != 0 && lDaughter.globalIndex() != theMcParticle.globalIndex()) { + lSiblingsIndeces.push_back(lDaughter.globalIndex()); + } + } + } + return lSiblingsIndeces; + }; + // ------ + std::vector mothers = {-1, -1}; + std::vector motherPDGs = {-1, -1}; + int siblings[2] = {0, 0}; + std::vector siblingsTemp = {-1, -1}; + if (track.has_mcParticle()) { + if (cfgFillQA) { + qaRegistry.fill(HIST("QA/hGoodMCTrackIndices"), 0); + } + // Get the MC particle + const auto& particle = track.mcParticle(); + if (particle.has_mothers()) { + mothers = getMothersIndeces(particle); + motherPDGs = getMothersPDGCodes(particle); + siblingsTemp = getSiblingsIndeces(particle); + } + while (mothers.size() > 2) { + mothers.pop_back(); + motherPDGs.pop_back(); + } + if (siblingsTemp.size() > 0) + siblings[0] = siblingsTemp[0]; + if (siblingsTemp.size() > 1) + siblings[1] = siblingsTemp[1]; + reso2mctracks(particle.pdgCode(), + mothers[0], + motherPDGs[0], + siblings, + particle.isPhysicalPrimary(), + particle.producedByGenerator()); + } else { + // No MC particle associated + reso2mctracks(0, + mothers[0], + motherPDGs[0], + siblings, + 0, + 0); + } + } + + /** + * @brief Fills V0 data + * + * @tparam isMC Boolean indicating if it's MC + * @tparam CollisionType Type of collision + * @tparam V0Type Type of V0 + * @tparam TrackType Type of track + * @param collision Collision data + * @param v0s V0 data + * @param tracks Track data + */ + template + void fillV0s(CollisionType const& collision, V0Type const& v0s, TrackType const&) + { + int childIDs[2] = {0, 0}; // these IDs are necessary to keep track of the children + for (auto const& v0 : v0s) { + if (cfgFillQA) { + qaRegistry.fill(HIST("QA/hGoodV0Indices"), 0); + qaRegistry.fill(HIST("QA/hV0Radius"), v0.v0radius()); + qaRegistry.fill(HIST("QA/hV0CosPA"), v0.v0cosPA()); + } + childIDs[0] = v0.posTrackId(); + childIDs[1] = v0.negTrackId(); + reso2v0s(collision.globalIndex(), + v0.pt(), + v0.px(), + v0.py(), + v0.pz(), + childIDs, + (int8_t)(v0.template posTrack_as().tpcNSigmaPi() * 10), + (int8_t)(v0.template posTrack_as().tpcNSigmaKa() * 10), + (int8_t)(v0.template posTrack_as().tpcNSigmaPr() * 10), + (int8_t)(v0.template negTrack_as().tpcNSigmaPi() * 10), + (int8_t)(v0.template negTrack_as().tpcNSigmaKa() * 10), + (int8_t)(v0.template negTrack_as().tpcNSigmaPr() * 10), + (int8_t)(v0.template negTrack_as().tofNSigmaPi() * 10), + (int8_t)(v0.template negTrack_as().tofNSigmaKa() * 10), + (int8_t)(v0.template negTrack_as().tofNSigmaPr() * 10), + (int8_t)(v0.template posTrack_as().tofNSigmaPi() * 10), + (int8_t)(v0.template posTrack_as().tofNSigmaKa() * 10), + (int8_t)(v0.template posTrack_as().tofNSigmaPr() * 10), + v0.v0cosPA(), + v0.dcaV0daughters(), + v0.dcapostopv(), + v0.dcanegtopv(), + v0.dcav0topv(), + v0.mLambda(), + v0.mAntiLambda(), + v0.mK0Short(), + v0.v0radius(), v0.x(), v0.y(), v0.z()); + if (!cfgBypassTrackIndexFill) { + resoV0V0s(v0.globalIndex()); + } + if constexpr (isMC) { + fillMCV0(v0); + } + } + } + + /** + * @brief Fills MC V0 data + * + * @tparam V0Type Type of V0 + * @param v0 V0 data + */ + template + void fillMCV0(V0Type const& v0) + { + // ------ Temporal lambda function to prevent error in build + auto getMothersIndeces = [&](auto const& theMcParticle) { + std::vector lMothersIndeces{}; + for (auto const& lMother : theMcParticle.template mothers_as()) { + LOGF(debug, " mother index lMother: %d", lMother.globalIndex()); + lMothersIndeces.push_back(lMother.globalIndex()); + } + return lMothersIndeces; + }; + auto getMothersPDGCodes = [&](auto const& theMcParticle) { + std::vector lMothersPDGs{}; + for (auto const& lMother : theMcParticle.template mothers_as()) { + LOGF(debug, " mother pdgcode lMother: %d", lMother.pdgCode()); + lMothersPDGs.push_back(lMother.pdgCode()); + } + return lMothersPDGs; + }; + auto getDaughtersIndeces = [&](auto const& theMcParticle) { + std::vector lDaughtersIndeces{}; + for (auto const& lDaughter : theMcParticle.template daughters_as()) { + LOGF(debug, " daughter index lDaughter: %d", lDaughter.globalIndex()); + if (lDaughter.globalIndex() != 0) { + lDaughtersIndeces.push_back(lDaughter.globalIndex()); + } + } + return lDaughtersIndeces; + }; + auto getDaughtersPDGCodes = [&](auto const& theMcParticle) { + std::vector lDaughtersPDGs{}; + for (auto const& lDaughter : theMcParticle.template daughters_as()) { + LOGF(debug, " daughter pdgcode lDaughter: %d", lDaughter.pdgCode()); + if (lDaughter.globalIndex() != 0) { + lDaughtersPDGs.push_back(lDaughter.pdgCode()); + } + } + return lDaughtersPDGs; + }; + // ------ + std::vector mothers = {-1, -1}; + std::vector motherPDGs = {-1, -1}; + std::vector daughters = {-1, -1}; + std::vector daughterPDGs = {-1, -1}; + if (v0.has_mcParticle()) { + if (cfgFillQA) { + qaRegistry.fill(HIST("QA/hGoodMCV0Indices"), 0); + } + auto v0mc = v0.mcParticle(); + if (v0mc.has_mothers()) { + mothers = getMothersIndeces(v0mc); + motherPDGs = getMothersPDGCodes(v0mc); + } + while (mothers.size() > 2) { + mothers.pop_back(); + motherPDGs.pop_back(); + } + if (v0mc.has_daughters()) { + daughters = getDaughtersIndeces(v0mc); + daughterPDGs = getDaughtersPDGCodes(v0mc); + } + while (daughters.size() > 2) { + LOGF(info, "daughters.size() is larger than 2"); + daughters.pop_back(); + daughterPDGs.pop_back(); + } + reso2mcv0s(v0mc.pdgCode(), + mothers[0], + motherPDGs[0], + daughters[0], + daughters[1], + daughterPDGs[0], + daughterPDGs[1], + v0mc.isPhysicalPrimary(), + v0mc.producedByGenerator()); + } else { + reso2mcv0s(0, + mothers[0], + motherPDGs[0], + daughters[0], + daughters[1], + daughterPDGs[0], + daughterPDGs[1], + 0, + 0); + } + } + + /** + * @brief Fills cascade data + * + * @tparam isMC Boolean indicating if it's MC + * @tparam CollisionType Type of collision + * @tparam CascType Type of cascade + * @tparam TrackType Type of track + * @param collision Collision data + * @param cascades Cascade data + * @param tracks Track data + */ + template + void fillCascades(CollisionType const& collision, CascType const& cascades, TrackType const&) + { + int childIDs[3] = {0, 0, 0}; // these IDs are necessary to keep track of the children + for (auto const& casc : cascades) { + if (cfgFillQA) { + qaRegistry.fill(HIST("QA/hGoodCascIndices"), 0); + qaRegistry.fill(HIST("QA/hCascRadius"), casc.cascradius()); + qaRegistry.fill(HIST("QA/hCascCosPA"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + } + childIDs[0] = casc.posTrackId(); + childIDs[1] = casc.negTrackId(); + childIDs[2] = casc.bachelorId(); + reso2cascades(collision.globalIndex(), + casc.pt(), + casc.px(), + casc.py(), + casc.pz(), + childIDs, + (int8_t)(casc.template posTrack_as().tpcNSigmaPi() * 10), + (int8_t)(casc.template posTrack_as().tpcNSigmaKa() * 10), + (int8_t)(casc.template posTrack_as().tpcNSigmaPr() * 10), + (int8_t)(casc.template negTrack_as().tpcNSigmaPi() * 10), + (int8_t)(casc.template negTrack_as().tpcNSigmaKa() * 10), + (int8_t)(casc.template negTrack_as().tpcNSigmaPr() * 10), + (int8_t)(casc.template bachelor_as().tpcNSigmaPi() * 10), + (int8_t)(casc.template bachelor_as().tpcNSigmaKa() * 10), + (int8_t)(casc.template bachelor_as().tpcNSigmaPr() * 10), + (int8_t)(casc.template posTrack_as().tofNSigmaPi() * 10), + (int8_t)(casc.template posTrack_as().tofNSigmaKa() * 10), + (int8_t)(casc.template posTrack_as().tofNSigmaPr() * 10), + (int8_t)(casc.template negTrack_as().tofNSigmaPi() * 10), + (int8_t)(casc.template negTrack_as().tofNSigmaKa() * 10), + (int8_t)(casc.template negTrack_as().tofNSigmaPr() * 10), + (int8_t)(casc.template bachelor_as().tofNSigmaPi() * 10), + (int8_t)(casc.template bachelor_as().tofNSigmaKa() * 10), + (int8_t)(casc.template bachelor_as().tofNSigmaPr() * 10), + casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()), + casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()), + casc.dcaV0daughters(), + casc.dcacascdaughters(), + casc.dcapostopv(), + casc.dcanegtopv(), + casc.dcabachtopv(), + casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()), + casc.dcaXYCascToPV(), + casc.dcaZCascToPV(), + casc.sign(), + casc.mLambda(), + casc.mXi(), + casc.v0radius(), casc.cascradius(), casc.x(), casc.y(), casc.z()); + if (!cfgBypassTrackIndexFill) { + resoCascadeCascades(casc.globalIndex()); + } + if constexpr (isMC) { + fillMCCascade(casc); + } + } + } + + /** + * @brief Fills MC cascade data + * + * @tparam CascType Type of cascade + * @param casc Cascade data + */ + template + void fillMCCascade(CascType const& casc) + { + // ------ Temporal lambda function to prevent error in build + auto getMothersIndeces = [&](auto const& theMcParticle) { + std::vector lMothersIndeces{}; + for (auto const& lMother : theMcParticle.template mothers_as()) { + LOGF(debug, " mother index lMother: %d", lMother.globalIndex()); + lMothersIndeces.push_back(lMother.globalIndex()); + } + return lMothersIndeces; + }; + auto getMothersPDGCodes = [&](auto const& theMcParticle) { + std::vector lMothersPDGs{}; + for (auto const& lMother : theMcParticle.template mothers_as()) { + LOGF(debug, " mother pdgcode lMother: %d", lMother.pdgCode()); + lMothersPDGs.push_back(lMother.pdgCode()); + } + return lMothersPDGs; + }; + auto getDaughtersIndeces = [&](auto const& theMcParticle) { + std::vector lDaughtersIndeces{}; + for (auto const& lDaughter : theMcParticle.template daughters_as()) { + LOGF(debug, " daughter index lDaughter: %d", lDaughter.globalIndex()); + if (lDaughter.globalIndex() != 0) { + lDaughtersIndeces.push_back(lDaughter.globalIndex()); + } + } + return lDaughtersIndeces; + }; + auto getDaughtersPDGCodes = [&](auto const& theMcParticle) { + std::vector lDaughtersPDGs{}; + for (auto const& lDaughter : theMcParticle.template daughters_as()) { + LOGF(debug, " daughter pdgcode lDaughter: %d", lDaughter.pdgCode()); + if (lDaughter.globalIndex() != 0) { + lDaughtersPDGs.push_back(lDaughter.pdgCode()); + } + } + return lDaughtersPDGs; + }; + // ------ + std::vector mothers = {-1, -1}; + std::vector motherPDGs = {-1, -1}; + std::vector daughters = {-1, -1}; + std::vector daughterPDGs = {-1, -1}; + if (casc.has_mcParticle()) { + if (cfgFillQA) { + qaRegistry.fill(HIST("QA/hGoodMCCascIndices"), 0); + } + auto cascmc = casc.mcParticle(); + if (cascmc.has_mothers()) { + mothers = getMothersIndeces(cascmc); + motherPDGs = getMothersPDGCodes(cascmc); + } + while (mothers.size() > 2) { + mothers.pop_back(); + motherPDGs.pop_back(); + } + if (cascmc.has_daughters()) { + daughters = getDaughtersIndeces(cascmc); + daughterPDGs = getDaughtersPDGCodes(cascmc); + } + while (daughters.size() > 2) { + LOGF(info, "daughters.size() is larger than 2"); + daughters.pop_back(); + daughterPDGs.pop_back(); + } + reso2mccascades(cascmc.pdgCode(), + mothers[0], + motherPDGs[0], + daughters[0], + daughters[1], + daughterPDGs[0], + daughterPDGs[1], + cascmc.isPhysicalPrimary(), + cascmc.producedByGenerator()); + } else { + reso2mccascades(0, + mothers[0], + motherPDGs[0], + daughters[0], + daughters[1], + daughterPDGs[0], + daughterPDGs[1], + 0, + 0); + } + } + + /** + * @brief Processes dummy + * + * @param collision Collision data + */ + void processDummy(aod::ResoCollision const&) + { + } + PROCESS_SWITCH(ResonanceDaughterInitializer, processDummy, "Process dummy", true); + + /** + * @brief Processes data tracks + * + * @param collision Collision data + * @param tracks Track data + */ + void processData(aod::ResoCollision const& collision, + soa::Filtered const& tracks) + { + fillTracks(collision, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } + } + PROCESS_SWITCH(ResonanceDaughterInitializer, processData, "Process tracks for data", false); + + /** + * @brief Processes MC tracks + * + * @param collision Collision data + * @param tracks Track data + * @param mcParticles MC particles + */ + void processMC(aod::ResoCollision const& collision, + soa::Filtered const& tracks, + aod::McParticles const&) + { + fillTracks(collision, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } + } + PROCESS_SWITCH(ResonanceDaughterInitializer, processMC, "Process tracks for MC", false); + + /** + * @brief Processes V0 data + * + * @param collision Collision data + * @param v0s V0 data + * @param tracks Track data + */ + void processV0Data(aod::ResoCollision const& collision, aod::ResoV0Candidates const& v0s, aod::ResoTrackCandidates const& tracks) + { + fillV0s(collision, v0s, tracks); + } + PROCESS_SWITCH(ResonanceDaughterInitializer, processV0Data, "Process V0s for data", false); + + /** + * @brief Processes MC V0 data + * + * @param collision Collision data + * @param v0s V0 data + * @param tracks Track data + */ + void processV0MC(aod::ResoCollision const& collision, aod::ResoV0CandidatesMC const& v0s, aod::ResoTrackCandidatesMC const& tracks) + { + fillV0s(collision, v0s, tracks); + } + PROCESS_SWITCH(ResonanceDaughterInitializer, processV0MC, "Process V0s for MC", false); + + /** + * @brief Processes cascade data + * + * @param collision Collision data + * @param cascades Cascade data + * @param tracks Track data + */ + void processCascData(aod::ResoCollision const& collision, aod::ResoCascadesCandidates const& cascades, aod::ResoTrackCandidates const& tracks) + { + fillCascades(collision, cascades, tracks); + } + PROCESS_SWITCH(ResonanceDaughterInitializer, processCascData, "Process Cascades for data", false); + + /** + * @brief Processes MC cascade data + * + * @param collision Collision data + * @param cascades Cascade data + * @param tracks Track data + */ + void processCascMC(aod::ResoCollision const& collision, aod::ResoCascadesCandidatesMC const& cascades, aod::ResoTrackCandidatesMC const& tracks) + { + fillCascades(collision, cascades, tracks); + } + PROCESS_SWITCH(ResonanceDaughterInitializer, processCascMC, "Process Cascades for MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/CMakeLists.txt b/PWGLF/TableProducer/Strangeness/CMakeLists.txt index 3f3ddddaa31..84f22d54d1d 100644 --- a/PWGLF/TableProducer/Strangeness/CMakeLists.txt +++ b/PWGLF/TableProducer/Strangeness/CMakeLists.txt @@ -9,6 +9,8 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +add_subdirectory(Converters) + o2physics_add_dpl_workflow(cascadebuilder SOURCES cascadebuilder.cxx PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore KFParticle::KFParticle O2Physics::MLCore @@ -51,7 +53,12 @@ o2physics_add_dpl_workflow(cascqaanalysis o2physics_add_dpl_workflow(hstrangecorrelationfilter SOURCES hStrangeCorrelationFilter.cxx - PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(double-casc-tree-creator + SOURCES doubleCascTreeCreator.cxx + PUBLIC_LINK_LIBRARIES O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(lambdakzerobuilder @@ -99,11 +106,26 @@ o2physics_add_dpl_workflow(strangederivedbuilder PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(strangenessbuilder + SOURCES strangenessbuilder.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle O2Physics::TPCDriftManager + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(v0-selector + SOURCES v0selector.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(v0qaanalysis SOURCES v0qaanalysis.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(lambdalambdatable + SOURCES LambdaLambdatable.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsVertexing + COMPONENT_NAME Analysis) + # ML selection o2physics_add_dpl_workflow(lambdakzeromlselectiontreecreator SOURCES lambdakzeroMLSelectionTreeCreator.cxx @@ -120,7 +142,22 @@ o2physics_add_dpl_workflow(lambdakzeromlselection PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(cascademlselection + SOURCES cascademlselection.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(sigma0builder SOURCES sigma0builder.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(lambdajetpolarizationbuilder + SOURCES lambdaJetpolarizationbuilder.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(stracents + SOURCES stracents.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) \ No newline at end of file diff --git a/PWGLF/TableProducer/Strangeness/Converters/CMakeLists.txt b/PWGLF/TableProducer/Strangeness/Converters/CMakeLists.txt new file mode 100644 index 00000000000..3ba4fdb55b7 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/CMakeLists.txt @@ -0,0 +1,115 @@ +# 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(stradautrackstofpidconverter + SOURCES stradautrackstofpidconverter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(stradautracksextraconverter2 + SOURCES stradautracksextraconverter2.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(stradautracksextraconverter3 + SOURCES stradautracksextraconverter3.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(strarawcentsconverter + SOURCES strarawcentsconverter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(strarawcentsconverter2v4 + SOURCES strarawcentsconverter2v4.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(straevselsconverter + SOURCES straevselsconverter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(straevselsconverter2 + SOURCES straevselsconverter2.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::ITStracking + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(straevselsconverter3 + SOURCES straevselsconverter3.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::ITStracking + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(straevselsconverter4 + SOURCES straevselsconverter4.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::ITStracking + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(straevselsconverter5 + SOURCES straevselsconverter5.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::ITStracking + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(straevselsconverter2rawcents + SOURCES straevselsconverter2rawcents.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(straevselsconverter2rawcents2 + SOURCES straevselsconverter2rawcents2.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(straevselsconverter2rawcents3 + SOURCES straevselsconverter2rawcents3.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(v0coresconverter + SOURCES v0coresconverter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(v0coresconverter2 + SOURCES v0coresconverter2.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(v0mlscoresconverter + SOURCES v0mlscoresconverter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(stramccollisionconverter + SOURCES stramccollisionconverter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(strastampsconverter + SOURCES strastampsconverter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(stracentconverter + SOURCES stracentconverter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(stramccollmultconverter + SOURCES stramccollmultconverter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(stramccollisionconverter2 + SOURCES stramccollisionconverter2.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGLF/TableProducer/Strangeness/Converters/stracentconverter.cxx b/PWGLF/TableProducer/Strangeness/Converters/stracentconverter.cxx new file mode 100644 index 00000000000..74a786101e9 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/stracentconverter.cxx @@ -0,0 +1,41 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts Stra Cents from 000 to 001 +struct stracentconverter { + Produces straCents_001; + + void process(aod::StraCents_000 const& straCents_000) + { + for (auto& values : straCents_000) { + straCents_001(values.centFT0M(), + values.centFT0A(), + values.centFT0C(), + values.centFV0A(), + -999., /*dummy FT0Cvariant1 value*/ + -999., /*dummy MFT value*/ + -999. /*dummy NGlobal value*/); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/converters/stradautracksconverter.cxx b/PWGLF/TableProducer/Strangeness/Converters/stradautracksconverter.cxx similarity index 100% rename from PWGLF/TableProducer/converters/stradautracksconverter.cxx rename to PWGLF/TableProducer/Strangeness/Converters/stradautracksconverter.cxx diff --git a/PWGLF/TableProducer/Strangeness/Converters/stradautracksextraconverter.cxx b/PWGLF/TableProducer/Strangeness/Converters/stradautracksextraconverter.cxx new file mode 100644 index 00000000000..ad436f4dfee --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/stradautracksextraconverter.cxx @@ -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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts V0 version 001 to 002 +struct stradautracksextraconverter { + Produces dauTrackExtras_001; + + void process(aod::DauTrackExtras_000 const& dauTrackExtras_000) + { + for (auto& values : dauTrackExtras_000) { + dauTrackExtras_001(0, + values.detectorMap(), + values.itsClusterSizes(), + values.tpcClusters(), + values.tpcCrossedRows()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} \ No newline at end of file diff --git a/PWGLF/TableProducer/Strangeness/Converters/stradautracksextraconverter2.cxx b/PWGLF/TableProducer/Strangeness/Converters/stradautracksextraconverter2.cxx new file mode 100644 index 00000000000..22c9fc7eea4 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/stradautracksextraconverter2.cxx @@ -0,0 +1,44 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts daughter TracksExtra from 1 to 2 +struct stradautracksextraconverter2 { + Produces dauTrackExtras_002; + + void process(aod::DauTrackExtras_001 const& dauTrackExtras_001) + { + for (auto& values : dauTrackExtras_001) { + const int maxFindable = 130; // synthetic findable to ensure range is ok + int findableMinusFound = maxFindable - values.tpcClusters(); + int findableMinusCrossedRows = maxFindable - values.tpcCrossedRows(); + dauTrackExtras_002(values.itsChi2PerNcl(), + values.detectorMap(), + values.itsClusterSizes(), + static_cast(maxFindable), // findable (unknown in old format) + static_cast(findableMinusFound), // findable minus found: we know found + static_cast(findableMinusCrossedRows)); // findable minus crossed rows: we know crossed rows + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/Converters/stradautracksextraconverter3.cxx b/PWGLF/TableProducer/Strangeness/Converters/stradautracksextraconverter3.cxx new file mode 100644 index 00000000000..a4144c1ee9a --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/stradautracksextraconverter3.cxx @@ -0,0 +1,43 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts daughter TracksExtra from 2 to 3 +struct stradautracksextraconverter3 { + Produces dauTrackExtras_003; + + void process(aod::DauTrackExtras_002 const& dauTrackExtras_002) + { + for (auto& values : dauTrackExtras_002) { + dauTrackExtras_003(values.itsChi2PerNcl(), + -1 /* dummy tpcChi2PerNcl value */, + values.detectorMap(), + values.itsClusterSizes(), + values.tpcNClsFindable(), + values.tpcNClsFindableMinusFound(), + values.tpcNClsFindableMinusCrossedRows(), + -1 /* dummy tpcNClsShared value */); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/Converters/stradautrackstofpidconverter.cxx b/PWGLF/TableProducer/Strangeness/Converters/stradautrackstofpidconverter.cxx new file mode 100644 index 00000000000..8731939ca53 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/stradautrackstofpidconverter.cxx @@ -0,0 +1,65 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts V0 version 001 to 002 +struct stradautrackstofpidconverter { + Produces dautracktofpids; + + void process(soa::Join const& v0s, soa::Join const& cascs, aod::DauTrackExtras const& dauTracks) + { + // prepare arrays with the relevant information + std::vector lLengths, lTOFSignals, lTOFEvTimes; + lLengths.reserve(dauTracks.size()); + lTOFSignals.reserve(dauTracks.size()); + lTOFEvTimes.reserve(dauTracks.size()); + for (int ii = 0; ii < dauTracks.size(); ii++) { + lLengths[ii] = 1e+6; + lTOFSignals[ii] = -1e+3f; + lTOFEvTimes[ii] = -1e+3f; + } + for (auto& v0 : v0s) { + lLengths[v0.posTrackExtraId()] = v0.posTOFLengthToPV(); + lTOFSignals[v0.posTrackExtraId()] = v0.posTOFSignal(); + lTOFEvTimes[v0.posTrackExtraId()] = v0.posTOFEventTime(); + lLengths[v0.negTrackExtraId()] = v0.negTOFLengthToPV(); + lTOFSignals[v0.negTrackExtraId()] = v0.negTOFSignal(); + lTOFEvTimes[v0.negTrackExtraId()] = v0.negTOFEventTime(); + } + for (auto& casc : cascs) { + lLengths[casc.posTrackExtraId()] = casc.posTOFLengthToPV(); + lTOFSignals[casc.posTrackExtraId()] = casc.posTOFSignal(); + lTOFEvTimes[casc.posTrackExtraId()] = casc.posTOFEventTime(); + lLengths[casc.negTrackExtraId()] = casc.negTOFLengthToPV(); + lTOFSignals[casc.negTrackExtraId()] = casc.negTOFSignal(); + lTOFEvTimes[casc.negTrackExtraId()] = casc.negTOFEventTime(); + lLengths[casc.bachTrackExtraId()] = casc.bachTOFLengthToPV(); + lTOFSignals[casc.bachTrackExtraId()] = casc.bachTOFSignal(); + lTOFEvTimes[casc.bachTrackExtraId()] = casc.bachTOFEventTime(); + } + for (int ii = 0; ii < dauTracks.size(); ii++) { + dautracktofpids(lTOFSignals[ii], lTOFEvTimes[ii], lLengths[ii]); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} \ No newline at end of file diff --git a/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter.cxx b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter.cxx new file mode 100644 index 00000000000..9806e15abfc --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter.cxx @@ -0,0 +1,62 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts Stra Event selections from 000 to 001 +struct straevselsconverter { + Produces straEvSels_001; + + void process(soa::Join const& straEvSels_000_RawCents_004) + { + for (auto& values : straEvSels_000_RawCents_004) { + straEvSels_001(values.sel8(), + values.selection_raw(), + values.multFT0A(), + values.multFT0C(), + values.multFT0A(), + 0 /*dummy FDDA value*/, + 0 /*dummy FDDC value*/, + values.multNTracksPVeta1(), + values.multPVTotalContributors(), + values.multNTracksGlobal(), + values.multNTracksITSTPC(), + values.multAllTracksTPCOnly(), + values.multAllTracksITSTPC(), + values.multZNA(), + values.multZNC(), + values.multZEM1(), + values.multZEM2(), + values.multZPA(), + values.multZPC(), + values.trackOccupancyInTimeRange(), + -1 /*dummy gap side value*/, + -999. /*dummy FT0-A value*/, + -999. /*dummy FT0-C value*/, + -999. /*dummy FV0-A value*/, + -999. /*dummy FDD-A value*/, + -999. /*dummy FDD-C value*/, + -999. /*dummy ZN-A value*/, + -999. /*dummy ZN-C value*/); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter2.cxx b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter2.cxx new file mode 100644 index 00000000000..401b04bbc83 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter2.cxx @@ -0,0 +1,64 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "ITStracking/Vertexer.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts Stra Event selections from 000 to 001 +struct straevselsconverter2 { + Produces straEvSels_002; + + void process(aod::StraEvSels_001 const& straEvSels_001) + { + for (auto& values : straEvSels_001) { + straEvSels_002(values.sel8(), + values.selection_raw(), + values.multFT0A(), + values.multFT0C(), + values.multFT0A(), + 0 /*dummy FDDA value*/, + 0 /*dummy FDDC value*/, + values.multNTracksPVeta1(), + values.multPVTotalContributors(), + values.multNTracksGlobal(), + values.multNTracksITSTPC(), + values.multAllTracksTPCOnly(), + values.multAllTracksITSTPC(), + values.multZNA(), + values.multZNC(), + values.multZEM1(), + values.multZEM2(), + values.multZPA(), + values.multZPC(), + values.trackOccupancyInTimeRange(), + values.gapSide(), + values.totalFT0AmplitudeA(), + values.totalFT0AmplitudeC(), + values.totalFV0AmplitudeA(), + values.totalFDDAmplitudeA(), + values.totalFDDAmplitudeC(), + values.energyCommonZNA(), + values.energyCommonZNC(), + o2::its::Vertex::FlagsMask /*dummy flag value*/); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter2rawcents.cxx b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter2rawcents.cxx new file mode 100644 index 00000000000..deeafa8eeca --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter2rawcents.cxx @@ -0,0 +1,50 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts V0 version 001 to 002 +struct straevselsconverter2rawcents { + Produces straRawCents_004; + + void process(aod::StraEvSels_001 const& straEvSels_001) + { + for (auto& values : straEvSels_001) { + straRawCents_004(values.multFT0A(), + values.multFT0C(), + values.multFT0A(), + values.multNTracksPVeta1(), + values.multPVTotalContributors(), + values.multNTracksGlobal(), + values.multNTracksITSTPC(), + values.multAllTracksTPCOnly(), + values.multAllTracksITSTPC(), + values.multZNA(), + values.multZNC(), + values.multZEM1(), + values.multZEM2(), + values.multZPA(), + values.multZPC(), + values.trackOccupancyInTimeRange()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter2rawcents2.cxx b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter2rawcents2.cxx new file mode 100644 index 00000000000..ffed58e9072 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter2rawcents2.cxx @@ -0,0 +1,50 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts V0 version 001 to 002 +struct straevselsconverter2rawcents2 { + Produces straRawCents_004; + + void process(aod::StraEvSels_002 const& straEvSels_002) + { + for (auto& values : straEvSels_002) { + straRawCents_004(values.multFT0A(), + values.multFT0C(), + values.multFT0A(), + values.multNTracksPVeta1(), + values.multPVTotalContributors(), + values.multNTracksGlobal(), + values.multNTracksITSTPC(), + values.multAllTracksTPCOnly(), + values.multAllTracksITSTPC(), + values.multZNA(), + values.multZNC(), + values.multZEM1(), + values.multZEM2(), + values.multZPA(), + values.multZPC(), + values.trackOccupancyInTimeRange()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter2rawcents3.cxx b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter2rawcents3.cxx new file mode 100644 index 00000000000..8d92146d6f7 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter2rawcents3.cxx @@ -0,0 +1,50 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts V0 version 001 to 002 +struct straevselsconverter2rawcents3 { + Produces straRawCents_004; + + void process(aod::StraEvSels_003 const& straEvSels_003) + { + for (auto& values : straEvSels_003) { + straRawCents_004(values.multFT0A(), + values.multFT0C(), + values.multFT0A(), + values.multNTracksPVeta1(), + values.multPVTotalContributors(), + values.multNTracksGlobal(), + values.multNTracksITSTPC(), + values.multAllTracksTPCOnly(), + values.multAllTracksITSTPC(), + values.multZNA(), + values.multZNC(), + values.multZEM1(), + values.multZEM2(), + values.multZPA(), + values.multZPC(), + values.trackOccupancyInTimeRange()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter3.cxx b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter3.cxx new file mode 100644 index 00000000000..ecbd738f5fa --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter3.cxx @@ -0,0 +1,65 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "ITStracking/Vertexer.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts Stra Event selections from 000 to 001 +struct straevselsconverter3 { + Produces straEvSels_003; + + void process(aod::StraEvSels_002 const& straEvSels_002) + { + for (auto& values : straEvSels_002) { + straEvSels_003(values.sel8(), + values.selection_raw(), + values.multFT0A(), + values.multFT0C(), + values.multFT0A(), + 0 /*dummy FDDA value*/, + 0 /*dummy FDDC value*/, + values.multNTracksPVeta1(), + values.multPVTotalContributors(), + values.multNTracksGlobal(), + values.multNTracksITSTPC(), + values.multAllTracksTPCOnly(), + values.multAllTracksITSTPC(), + values.multZNA(), + values.multZNC(), + values.multZEM1(), + values.multZEM2(), + values.multZPA(), + values.multZPC(), + values.trackOccupancyInTimeRange(), + 0 /*dummy occupancy value*/, + values.gapSide(), + values.totalFT0AmplitudeA(), + values.totalFT0AmplitudeC(), + values.totalFV0AmplitudeA(), + values.totalFDDAmplitudeA(), + values.totalFDDAmplitudeC(), + values.energyCommonZNA(), + values.energyCommonZNC(), + o2::its::Vertex::FlagsMask /*dummy flag value*/); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter4.cxx b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter4.cxx new file mode 100644 index 00000000000..ad988fd93aa --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter4.cxx @@ -0,0 +1,66 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "ITStracking/Vertexer.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts Stra Event selections from 000 to 001 +struct straevselsconverter4 { + Produces straEvSels_004; + + void process(aod::StraEvSels_003 const& straEvSels_003) + { + for (auto& values : straEvSels_003) { + straEvSels_004(values.sel8(), + values.selection_raw(), + values.multFT0A(), + values.multFT0C(), + values.multFT0A(), + 0 /*dummy FDDA value*/, + 0 /*dummy FDDC value*/, + values.multNTracksPVeta1(), + values.multPVTotalContributors(), + values.multNTracksGlobal(), + values.multNTracksITSTPC(), + values.multAllTracksTPCOnly(), + values.multAllTracksITSTPC(), + values.multZNA(), + values.multZNC(), + values.multZEM1(), + values.multZEM2(), + values.multZPA(), + values.multZPC(), + values.trackOccupancyInTimeRange(), + 0 /*dummy occupancy value*/, + values.gapSide(), + values.totalFT0AmplitudeA(), + values.totalFT0AmplitudeC(), + values.totalFV0AmplitudeA(), + values.totalFDDAmplitudeA(), + values.totalFDDAmplitudeC(), + values.energyCommonZNA(), + values.energyCommonZNC(), + values.flags(), + 0 /*dummy Alias value*/); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter5.cxx b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter5.cxx new file mode 100644 index 00000000000..ab2962e36be --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter5.cxx @@ -0,0 +1,67 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "ITStracking/Vertexer.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts Stra Event selections from 004 to 005 +struct straevselsconverter5 { + Produces straEvSels_005; + + void process(aod::StraEvSels_004 const& straEvSels_004) + { + for (auto& values : straEvSels_004) { + straEvSels_005(values.sel8(), + values.selection_raw(), + values.multFT0A(), + values.multFT0C(), + values.multFT0A(), + 0 /*dummy FDDA value*/, + 0 /*dummy FDDC value*/, + values.multNTracksPVeta1(), + values.multPVTotalContributors(), + values.multNTracksGlobal(), + values.multNTracksITSTPC(), + values.multAllTracksTPCOnly(), + values.multAllTracksITSTPC(), + values.multZNA(), + values.multZNC(), + values.multZEM1(), + values.multZEM2(), + values.multZPA(), + values.multZPC(), + values.trackOccupancyInTimeRange(), + 0 /*dummy occupancy value*/, + values.gapSide(), + values.totalFT0AmplitudeA(), + values.totalFT0AmplitudeC(), + values.totalFV0AmplitudeA(), + values.totalFDDAmplitudeA(), + values.totalFDDAmplitudeC(), + values.energyCommonZNA(), + values.energyCommonZNC(), + values.flags(), + 0 /*dummy Alias value*/, + 0 /*dummy Rct value*/); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/Converters/stramccollisionconverter.cxx b/PWGLF/TableProducer/Strangeness/Converters/stramccollisionconverter.cxx new file mode 100644 index 00000000000..8c7950dc4fd --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/stramccollisionconverter.cxx @@ -0,0 +1,36 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts V0 version 001 to 002 +struct stramccollisionconverter { + Produces straMCCollisions_001; + + void process(aod::StraMCCollisions_000 const& straMCcoll) + { + for (auto& mccollision : straMCcoll) { + straMCCollisions_001(mccollision.posX(), mccollision.posY(), mccollision.posZ(), + mccollision.impactParameter(), 0.0f); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/Converters/stramccollisionconverter2.cxx b/PWGLF/TableProducer/Strangeness/Converters/stramccollisionconverter2.cxx new file mode 100644 index 00000000000..c821c6fb5fe --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/stramccollisionconverter2.cxx @@ -0,0 +1,44 @@ +// 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 stramccollisionconverter2.cxx +/// \brief Converter task to convert StraMCCollisions_001 --> StraMCCollisions_002 +/// +/// \author Romain Schotter , Austrian Academy of Sciences & SMI +// + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts V0 version 001 to 002 +struct stramccollisionconverter2 { + Produces straMCCollisions_002; + + void process(aod::StraMCCollisions_001 const& straMCcoll) + { + for (auto& mccollision : straMCcoll) { + straMCCollisions_002(mccollision.posX(), mccollision.posY(), mccollision.posZ(), + mccollision.impactParameter(), mccollision.eventPlaneAngle(), 0); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/Converters/stramccollmultconverter.cxx b/PWGLF/TableProducer/Strangeness/Converters/stramccollmultconverter.cxx new file mode 100644 index 00000000000..411e3c15da5 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/stramccollmultconverter.cxx @@ -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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts V0 version 001 to 002 +struct stramccollmultconverter { + Produces straMCCollMults_001; + + void process(aod::StraMCCollMults_000 const& straMCcolls) + { + for (auto& straMCcoll : straMCcolls) { + straMCCollMults_001(straMCcoll.multMCFT0A(), + straMCcoll.multMCFT0C(), + straMCcoll.multMCNParticlesEta05(), + straMCcoll.multMCNParticlesEta08(), + straMCcoll.multMCNParticlesEta10(), + -1 /* dummy value for totalMultMCParticles */); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/converters/strarawcentsconverter.cxx b/PWGLF/TableProducer/Strangeness/Converters/strarawcentsconverter.cxx similarity index 83% rename from PWGLF/TableProducer/converters/strarawcentsconverter.cxx rename to PWGLF/TableProducer/Strangeness/Converters/strarawcentsconverter.cxx index 1527ee9ed81..e912c724870 100644 --- a/PWGLF/TableProducer/converters/strarawcentsconverter.cxx +++ b/PWGLF/TableProducer/Strangeness/Converters/strarawcentsconverter.cxx @@ -16,17 +16,18 @@ using namespace o2; using namespace o2::framework; +// Converts V0 version 001 to 002 struct strarawcentsconverter { Produces straRawCents_001; Produces straRawCents_003; - void processStraRawCents000to001(aod::StraRawCents_000 const& straRawCents_000) + void process000to001(aod::StraRawCents_000 const& straRawCents_000) { for (auto& values : straRawCents_000) { straRawCents_001(values.multFT0A(), values.multFT0C(), values.multFV0A(), values.multNTracksPVeta1(), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); } } - void processStraRawCents002to003(aod::StraRawCents_002 const& straRawCents_002) + void process002to003(aod::StraRawCents_002 const& straRawCents_002) { for (auto& values : straRawCents_002) { straRawCents_003(values.multFT0A(), @@ -46,8 +47,8 @@ struct strarawcentsconverter { } } - PROCESS_SWITCH(strarawcentsconverter, processStraRawCents000to001, "from StraRawCents 000 to 001", false); - PROCESS_SWITCH(strarawcentsconverter, processStraRawCents002to003, "from StraRawCents 002 to 003", false); + PROCESS_SWITCH(strarawcentsconverter, process000to001, "from raw 000 to 001", false); + PROCESS_SWITCH(strarawcentsconverter, process002to003, "from raw 002 to 003", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/TableProducer/Strangeness/Converters/strarawcentsconverter2v4.cxx b/PWGLF/TableProducer/Strangeness/Converters/strarawcentsconverter2v4.cxx new file mode 100644 index 00000000000..c94227e31cd --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/strarawcentsconverter2v4.cxx @@ -0,0 +1,50 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts V0 version 001 to 002 +struct strarawcentsconverter2v4 { + Produces straRawCents_004; + + void process(aod::StraRawCents_003 const& straRawCents_003) + { + for (auto& values : straRawCents_003) { + straRawCents_004(values.multFT0A(), + values.multFT0C(), + values.multFT0A(), + values.multNTracksPVeta1(), + values.multPVTotalContributors(), + values.multNTracksGlobal(), + values.multNTracksITSTPC(), + values.multAllTracksTPCOnly(), + values.multAllTracksITSTPC(), + values.multZNA(), + values.multZNC(), + values.multZEM1(), + values.multZEM2(), + values.multZPA(), + values.multZPC(), + 0 /*dummy occupancy value*/); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/Converters/strastampsconverter.cxx b/PWGLF/TableProducer/Strangeness/Converters/strastampsconverter.cxx new file mode 100644 index 00000000000..7f5f129d623 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/strastampsconverter.cxx @@ -0,0 +1,37 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts Stra Stamps from 000 to 001 +struct strastampsconverter { + Produces straStamps_001; + + void process(aod::StraStamps_000 const& straStamps_000) + { + for (auto& values : straStamps_000) { + straStamps_001(values.runNumber(), + values.timestamp(), + 0 /*dummy globalBC value*/); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/Converters/v0coresconverter.cxx b/PWGLF/TableProducer/Strangeness/Converters/v0coresconverter.cxx new file mode 100644 index 00000000000..06fafc1cc1a --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/v0coresconverter.cxx @@ -0,0 +1,49 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts V0 version 001 to 002 +struct v0coresconverter { + Produces v0MCCores_001; + + void process(aod::V0MCCores_000 const& v0MCCores_000) + { + for (auto& values : v0MCCores_000) { + v0MCCores_001(0, + values.pdgCode(), + values.pdgCodeMother(), + values.pdgCodePositive(), + values.pdgCodeNegative(), + values.isPhysicalPrimary(), + values.xMC(), + values.yMC(), + values.zMC(), + values.pxPosMC(), + values.pyPosMC(), + values.pzPosMC(), + values.pxNegMC(), + values.pyNegMC(), + values.pzNegMC()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/Converters/v0coresconverter2.cxx b/PWGLF/TableProducer/Strangeness/Converters/v0coresconverter2.cxx new file mode 100644 index 00000000000..c918f227525 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/v0coresconverter2.cxx @@ -0,0 +1,52 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts V0 version 001 to 002 +struct v0coresconverter2 { + Produces v0MCCores_002; + + void process(aod::V0MCCores_001 const& v0MCCores_001) + { + for (auto& values : v0MCCores_001) { + v0MCCores_002(0, + values.pdgCode(), + values.pdgCodeMother(), + values.pdgCodePositive(), + values.pdgCodeNegative(), + values.isPhysicalPrimary(), + values.xMC(), + values.yMC(), + values.zMC(), + values.pxPosMC(), + values.pyPosMC(), + values.pzPosMC(), + values.pxNegMC(), + values.pyNegMC(), + values.pzNegMC(), + values.pxPosMC() + values.pxNegMC(), + values.pyPosMC() + values.pyNegMC(), + values.pzPosMC() + values.pzNegMC()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/Converters/v0mlscoresconverter.cxx b/PWGLF/TableProducer/Strangeness/Converters/v0mlscoresconverter.cxx new file mode 100644 index 00000000000..9f2020bf20d --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/v0mlscoresconverter.cxx @@ -0,0 +1,42 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessMLTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts V0 version 001 to 002 +struct v0mlscoresconverter { + Produces gammaMLSelections; // gamma scores + Produces lambdaMLSelections; // lambda scores + Produces antiLambdaMLSelections; // AntiLambda scores + Produces k0ShortMLSelections; // K0Short scores + + void process(aod::V0Cores const& v0cores) + { + for (int64_t i = 0; i < v0cores.size(); ++i) { + gammaMLSelections(-1); + lambdaMLSelections(-1); + antiLambdaMLSelections(-1); + k0ShortMLSelections(-1); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/LFStrangeTreeCreator.cxx b/PWGLF/TableProducer/Strangeness/LFStrangeTreeCreator.cxx index 74ec37f125d..fd5f225ea99 100644 --- a/PWGLF/TableProducer/Strangeness/LFStrangeTreeCreator.cxx +++ b/PWGLF/TableProducer/Strangeness/LFStrangeTreeCreator.cxx @@ -10,14 +10,17 @@ // or submit itself to any jurisdiction. #include +#include #include -#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" #include "ReconstructionDataFormats/Track.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" #include "Common/DataModel/EventSelection.h" @@ -26,480 +29,850 @@ #include "DetectorsBase/GeometryManager.h" #include "DataFormatsParameters/GRPObject.h" #include "DataFormatsParameters/GRPMagField.h" -#include "CommonConstants/PhysicsConstants.h" +#include "CCDB/BasicCCDBManager.h" #include "Common/Core/PID/TPCPIDResponse.h" #include "Common/DataModel/PIDResponse.h" +#include "DCAFitter/DCAFitterN.h" #include "PWGLF/DataModel/LFSlimStrangeTables.h" +#include "TDatabasePDG.h" + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -using TracksFull = soa::Join; -using TracksFullMC = soa::Join; -using BCsWithRun2Info = soa::Join; +using TracksFullIU = soa::Join; + +namespace +{ +void momTotXYZ(std::array& momA, std::array const& momB, std::array const& momC) +{ + for (int i = 0; i < 3; ++i) { + momA[i] = momB[i] + momC[i]; + } +} +float invMass2Body(std::array const& momA, std::array const& momB, std::array const& momC, float const& massB, float const& massC) +{ + float p2B = momB[0] * momB[0] + momB[1] * momB[1] + momB[2] * momB[2]; + float p2C = momC[0] * momC[0] + momC[1] * momC[1] + momC[2] * momC[2]; + float eB = std::sqrt(p2B + massB * massB); + float eC = std::sqrt(p2C + massC * massC); + float eA = eB + eC; + float massA = std::sqrt(eA * eA - momA[0] * momA[0] - momA[1] * momA[1] - momA[2] * momA[2]); + return massA; +} +float alphaAP(std::array const& momA, std::array const& momB, std::array const& momC) +{ + float momTot = std::sqrt(std::pow(momA[0], 2.) + std::pow(momA[1], 2.) + std::pow(momA[2], 2.)); + float lQlPos = (momB[0] * momA[0] + momB[1] * momA[1] + momB[2] * momA[2]) / momTot; + float lQlNeg = (momC[0] * momA[0] + momC[1] * momA[1] + momC[2] * momA[2]) / momTot; + return (lQlPos - lQlNeg) / (lQlPos + lQlNeg); +} + +float qtAP(std::array const& momA, std::array const& momB) +{ + float dp = momA[0] * momB[0] + momA[1] * momB[1] + momA[2] * momB[2]; + float p2A = momA[0] * momA[0] + momA[1] * momA[1] + momA[2] * momA[2]; + float p2B = momB[0] * momB[0] + momB[1] * momB[1] + momB[2] * momB[2]; + return std::sqrt(p2B - dp * dp / p2A); +} + +float etaFromMom(std::array const& momA, std::array const& momB) +{ + if (std::sqrt((1.f * momA[0] + 1.f * momB[0]) * (1.f * momA[0] + 1.f * momB[0]) + + (1.f * momA[1] + 1.f * momB[1]) * (1.f * momA[1] + 1.f * momB[1]) + + (1.f * momA[2] + 1.f * momB[2]) * (1.f * momA[2] + 1.f * momB[2])) - + (1.f * momA[2] + 1.f * momB[2]) < + static_cast(1e-7)) { + if ((1.f * momA[2] + 1.f * momB[2]) < 0.f) + return -100.f; + return 100.f; + } + return 0.5f * std::log((std::sqrt((1.f * momA[0] + 1.f * momB[0]) * (1.f * momA[0] + 1.f * momB[0]) + + (1.f * momA[1] + 1.f * momB[1]) * (1.f * momA[1] + 1.f * momB[1]) + + (1.f * momA[2] + 1.f * momB[2]) * (1.f * momA[2] + 1.f * momB[2])) + + (1.f * momA[2] + 1.f * momB[2])) / + (std::sqrt((1.f * momA[0] + 1.f * momB[0]) * (1.f * momA[0] + 1.f * momB[0]) + + (1.f * momA[1] + 1.f * momB[1]) * (1.f * momA[1] + 1.f * momB[1]) + + (1.f * momA[2] + 1.f * momB[2]) * (1.f * momA[2] + 1.f * momB[2])) - + (1.f * momA[2] + 1.f * momB[2]))); +} +float CalculateDCAStraightToPV(float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) +{ + return std::sqrt((std::pow((pvY - Y) * Pz - (pvZ - Z) * Py, 2) + std::pow((pvX - X) * Pz - (pvZ - Z) * Px, 2) + std::pow((pvX - X) * Py - (pvY - Y) * Px, 2)) / (Px * Px + Py * Py + Pz * Pz)); +} +} // namespace struct CandidateV0 { - float pt; - float eta; - bool isMatter; - float mass; - float ct; - float radius; - float dcaV0PV; - float dcaPiPV; - float dcaPrPV; - float dcaV0Tracks; - float cosPA; - float tpcNsigmaPi; - float tpcNsigmaPr; - float genPt; - float genEta; - float genCt; - int pdgCode; - bool isReco; + float pt = -999.f; + float eta = -999.f; + float ct = -999.f; + float len = -999.f; + float mass = -999.f; + float radius = -999.f; + float cpa = -999.f; + float alphaAP = -999.f; + float qtAP = -999.f; + uint8_t isFD = 0u; + o2::track::TrackParCov trackv0; + std::array mompos; + std::array momneg; + std::array momposMC; + std::array momnegMC; + float dcav0daugh = -999.f; + float dcanegpv = -999.f; + float dcapospv = -999.f; + float dcav0pv = -999.f; + float tpcnsigmaneg = -999.f; + float tpcnsigmapos = -999.f; + float genpt = -999.f; + float geneta = -999.f; + float genct = -999.f; + float genlen = -999.f; + int pdgcode = -999; + int pdgcodemother = -999; + int pdgposdau = -999; + int pdgcodemotherdaupos = -999; + int pdgnegdau = -999; + int pdgcodemotherdauneg = -999; + bool isreco = 0; + int64_t pdgmatchmothersecondmother = -999; + int64_t mcIndex = -999; + int64_t globalIndex = -999; int64_t globalIndexPos = -999; int64_t globalIndexNeg = -999; }; struct LFStrangeTreeCreator { - + Produces lambdaTableML; + Produces v0TableAP; + Produces mcLambdaTableML; + Produces mcV0TableAP; std::mt19937 gen32; - - Produces lambdaTableML; - Produces mcLambdaTableML; std::vector candidateV0s; - std::vector checkedV0s; + Service ccdb; + o2::vertexing::DCAFitterN<2> fitter; - Configurable downscaleFactor{"downscaleFactor", 1.f, "downscaling factor"}; - Configurable fillOnlySignal{"fillOnlySignal", true, "toggle table filling of signal-only candidates (for mc)"}; - Configurable fillNonRecSignal{"fillNonRecSignal", true, "toggle table filling of non-reco signal candidates (for mc)"}; - - Configurable kINT7Intervals{"kINT7Intervals", false, "toggle kINT7 trigger selection in the 10-30% and 50-90% centrality intervals (2018 Pb-Pb)"}; - Configurable kUseTPCPileUpCut{"kUseTPCPileUpCut", false, "toggle strong correlation cuts (Run 2)"}; - Configurable kUseEstimatorsCorrelationCut{"kUseEstimatorsCorrelationCut", false, "toggle cut on the correlation between centrality estimators (2018 Pb-Pb)"}; + int mRunNumber; + float d_bz; + // o2::base::MatLayerCylSet* lut = nullptr; + Configurable cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Type of material correction"}; - ConfigurableAxis zVtxAxis{"zVtxBins", {100, -20.f, 20.f}, "Binning for the vertex z in cm"}; - ConfigurableAxis massLambdaAxis{"massLambdaAxis", {400, o2::constants::physics::MassLambda0 - 0.05f, o2::constants::physics::MassLambda0 + 0.05f}, "binning for the lambda invariant-mass"}; ConfigurableAxis centAxis{"centAxis", {106, 0, 106}, "binning for the centrality"}; + ConfigurableAxis zVtxAxis{"zVtxBins", {100, -20.f, 20.f}, "Binning for the vertex z in cm"}; - ConfigurableAxis cosPaAxis{"cosPaAxis", {1e3, 0.95f, 1.00f}, "binning for the cosPa axis"}; - ConfigurableAxis radiusAxis{"radiusAxis", {1e3, 0.f, 100.f}, "binning for the radius axis"}; - ConfigurableAxis dcaV0daughAxis{"dcaV0daughAxis", {2e2, 0.f, 2.f}, "binning for the dca of V0 daughters"}; - ConfigurableAxis dcaDaughPvAxis{"dcaDaughPvAxis", {1e3, 0.f, 10.f}, "binning for the dca of positive daughter to PV"}; + // binning of (anti)lambda mass QA histograms + ConfigurableAxis massLambdaAxis{"massLambdaAxis", {400, o2::constants::physics::MassLambda0 - 0.03f, o2::constants::physics::MassLambda0 + 0.03f}, "binning for the lambda invariant-mass"}; + ConfigurableAxis massXiAxis{"massXiAxis", {400, o2::constants::physics::MassXiMinus - 0.05f, o2::constants::physics::MassXiMinus + 0.05f}, "binning for the Xi invariant-mass"}; Configurable zVtxMax{"zVtxMax", 10.0f, "maximum z position of the primary vertex"}; Configurable etaMax{"etaMax", 0.8f, "maximum eta"}; + Configurable etaMaxV0dau{"etaMaxV0dau", 0.8f, "maximum eta V0 daughters"}; + ConfigurableAxis momAxis{"momAxisFine", {5.e2, 0.f, 5.f}, "momentum axis binning"}; - Configurable lambdaPtMin{"lambdaPtMin", 0.5f, "minimum (anti)lambda pT (GeV/c)"}; - Configurable lambdaPtMax{"lambdaPtMax", 3.0f, "maximum (anti)lambda pT (GeV/c)"}; + Configurable downscaleFactor{"downscaleFactor", 1.f, "downscaling factor"}; + Configurable applyAdditionalEvSel{"applyAdditionalEvSel", false, "apply additional event selections"}; + + Configurable lambdaPtMin{"lambdaPtMin", 1.f, "minimum (anti)lambda pT (GeV/c)"}; + Configurable lambdaPtMax{"lambdaPtMax", 4.f, "maximum (anti)lambda pT (GeV/c)"}; + + Configurable v0trackNcrossedRows{"v0trackNcrossedRows", 100, "Minimum number of crossed TPC rows for V0 daughter"}; + Configurable v0trackNclusItsCut{"v0trackNclusITScut", 0, "Minimum number of ITS clusters for V0 daughter"}; + Configurable v0trackNclusTpcCut{"v0trackNclusTPCcut", 100, "Minimum number of TPC clusters for V0 daughter"}; + Configurable v0trackNsharedClusTpc{"v0trackNsharedClusTpc", 5, "Maximum number of shared TPC clusters for V0 daughter"}; + Configurable vetoMassK0Short{"vetoMassK0Short", 0.01f, "veto for V0 compatible with K0s mass"}; + Configurable v0radiusMax{"v0radiusMax", 100.f, "maximum V0 radius eccepted"}; + + Configurable v0setting_dcav0dau{"v0setting_dcav0dau", 0.5f, "DCA V0 Daughters"}; + Configurable v0setting_dcav0pv{"v0setting_dcav0pv", 1.f, "DCA V0 to Pv"}; + Configurable v0setting_dcadaughtopv{"v0setting_dcadaughtopv", 0.1f, "DCA Pos To PV"}; + Configurable v0setting_cospa{"v0setting_cospa", 0.99f, "V0 CosPA"}; + Configurable v0setting_radius{"v0setting_radius", 5.f, "v0radius"}; + Configurable v0setting_lifetime{"v0setting_lifetime", 40.f, "v0 lifetime cut"}; + Configurable v0setting_nsigmatpc{"v0setting_nsigmatpc", 4.f, "nsigmatpc"}; + Configurable cascsetting_dcabachpv{"cascsetting_dcabachpv", 0.1f, "cascdcabachpv"}; + Configurable cascsetting_cospa{"cascsetting_cospa", 0.99f, "casc cospa cut"}; + Configurable cascsetting_dcav0bach{"cascsetting_dcav0bach", 1.0f, "dcav0bach"}; + Configurable cascsetting_vetoOm{"cascsetting_vetoOm", 0.01f, "vetoOm"}; + Configurable cascsetting_mXi{"cascsetting_mXi", 0.02f, "mXi"}; + Configurable lambdaMassCut{"lambdaMassCut", 0.02f, "maximum deviation from PDG mass (for QA histograms)"}; + Configurable k0short{"k0short", false, "process for k0short (true) or lambda (false)"}; - Configurable v0setting_dcav0dau{"v0setting_dcav0dau", 1, "DCA V0 Daughters"}; - Configurable v0setting_dcapostopv{"v0setting_dcapostopv", 0.1f, "DCA Pos To PV"}; - Configurable v0setting_dcanegtopv{"v0setting_dcanegtopv", 0.1f, "DCA Neg To PV"}; - Configurable v0setting_cospa{"v0setting_cospa", 0.98, "V0 CosPA"}; - Configurable v0setting_radius{"v0setting_radius", 0.5f, "v0radius"}; - Configurable lambdaMassCut{"lambdaMassCut", 0.05f, "maximum deviation from PDG mass"}; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; uint32_t randomSeed = 0.; - HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Preslice perCollisionTracksFullIU = o2::aod::track::collisionId; + Preslice perCollisionV0 = o2::aod::v0::collisionId; + Preslice perCollisionCasc = o2::aod::cascade::collisionId; + Preslice perCollisionMcParts = o2::aod::mcparticle::mcCollisionId; - Preslice> perCollision = aod::v0data::collisionId; - std::vector filledMothers; + template + bool selectV0Daughter(T const& track) + { + if (std::abs(track.eta()) > etaMaxV0dau) { + return false; + } + if (track.itsNCls() < v0trackNclusItsCut || + track.tpcNClsFound() < v0trackNclusTpcCut || + track.tpcNClsCrossedRows() < v0trackNclusTpcCut || + track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || + track.tpcNClsShared() > v0trackNsharedClusTpc) { + return false; + } + return true; + } - template - void fillRecoLambda(Collision const& collision, RecV0s const& v0s, T const& /*tracks*/) + template + void initCCDB(Bc const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + auto timestamp = bc.timestamp(); + o2::parameters::GRPMagField* grpmag = 0x0; + + auto grpmagPath{"GLO/Config/GRPMagField"}; + grpmag = ccdb->getForTimeStamp("GLO/Config/GRPMagField", timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField for timestamp " << timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + + // Fetch magnetic field from ccdb for current collision + d_bz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "Retrieved GRP for timestamp " << timestamp << " with magnetic field of " << d_bz << " kG"; + mRunNumber = bc.runNumber(); + fitter.setBz(d_bz); + + // o2::base::Propagator::Instance()->setMatLUT(lut); + } + + void init(o2::framework::InitContext&) + { + + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + // lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get("GLO/Param/MatLUT")); + + fitter.setPropagateToPCA(true); + fitter.setMaxR(200.); + fitter.setMinParamChange(1e-3); + fitter.setMinRelChi2Change(0.9); + fitter.setMaxDZIni(4); + fitter.setMaxDXYIni(4); + fitter.setMaxChi2(1e9); + fitter.setUseAbsDCA(true); + fitter.setWeightedFinalPCA(false); + int mat{static_cast(cfgMaterialCorrection)}; + fitter.setMatCorrType(static_cast(mat)); + + // event QA + histos.add("QA/zVtx", ";#it{z}_{vtx} (cm);Entries", HistType::kTH1F, {zVtxAxis}); + + // v0 QA + histos.add("QA/massLambda", ";Centrality (%);#it{p}_{T} (GeV/#it{c});#it{M}(p + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH3F, {centAxis, momAxis, massLambdaAxis}); + histos.add("QA/massXi", ";Centrality (%);#it{p}_{T} (GeV/#it{c});#it{M}(#Lambda + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH3F, {centAxis, momAxis, massXiAxis}); + } + + template + void fillRecoEvent(C const& collision, T const& /* tracks */, aod::V0s const& V0s, aod::V0s const& /* V0s_all */, aod::Cascades const& cascades, float const& centrality) { candidateV0s.clear(); - CandidateV0 candV0; - for (const auto& v0 : v0s) { - if (v0.pt() < lambdaPtMin || v0.pt() > lambdaPtMax) { + gpu::gpustd::array dcaInfo; + + for (const auto& v0 : V0s) { + auto posTrack = v0.posTrack_as(); + auto negTrack = v0.negTrack_as(); + + bool posSelect = selectV0Daughter(posTrack); + bool negSelect = selectV0Daughter(negTrack); + if (!posSelect || !negSelect) + continue; + + auto posTrackCov = getTrackParCov(posTrack); + auto negTrackCov = getTrackParCov(negTrack); + + int nCand = 0; + try { + nCand = fitter.process(posTrackCov, negTrackCov); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call!"; + continue; + } + if (nCand == 0) { + continue; + } + + auto& posPropTrack = fitter.getTrack(0); + auto& negPropTrack = fitter.getTrack(1); + + std::array momPos = std::array{static_cast(-999.), static_cast(-999.), static_cast(-999.)}; + std::array momNeg = std::array{static_cast(-999.), static_cast(-999.), static_cast(-999.)}; + std::array momV0 = std::array{static_cast(-999.), static_cast(-999.), static_cast(-999.)}; + posPropTrack.getPxPyPzGlo(momPos); + negPropTrack.getPxPyPzGlo(momNeg); + momTotXYZ(momV0, momPos, momNeg); + + auto ptV0 = std::hypot(momV0[0], momV0[1]); + if (ptV0 < lambdaPtMin || ptV0 > lambdaPtMax) { continue; } - if (std::abs(v0.dcapostopv()) < v0setting_dcapostopv && - std::abs(v0.dcanegtopv()) < v0setting_dcanegtopv && - std::abs(v0.dcaV0daughters()) > v0setting_dcav0dau) { + auto etaV0 = etaFromMom(momPos, momNeg); + if (std::abs(etaV0) > etaMax) { continue; } - if (std::abs(v0.eta()) > etaMax || - v0.v0cosPA() < v0setting_cospa || - v0.v0radius() < v0setting_radius) { - return; + auto alpha = alphaAP(momV0, momPos, momNeg); + bool matter = alpha > 0; + auto massPos = matter ? o2::constants::physics::MassProton : o2::constants::physics::MassPionCharged; + auto massNeg = matter ? o2::constants::physics::MassPionCharged : o2::constants::physics::MassProton; + auto mLambda = invMass2Body(momV0, momPos, momNeg, massPos, massNeg); + auto mK0Short = invMass2Body(momV0, momPos, momNeg, o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged); + + // pid selections + auto nSigmaTPCPos = matter ? posTrack.tpcNSigmaPr() : posTrack.tpcNSigmaPi(); + auto nSigmaTPCNeg = matter ? negTrack.tpcNSigmaPi() : negTrack.tpcNSigmaPr(); + // change for k0 + if (k0short) { + nSigmaTPCPos = posTrack.tpcNSigmaPi(); + nSigmaTPCNeg = negTrack.tpcNSigmaPi(); } - auto mLambda = v0.alpha() > 0 ? v0.mLambda() : v0.mAntiLambda(); - if (std::abs(mLambda - o2::constants::physics::MassLambda0) > lambdaMassCut) { - return; + + if (std::abs(nSigmaTPCPos) > v0setting_nsigmatpc || std::abs(nSigmaTPCNeg) > v0setting_nsigmatpc) { + continue; } - auto pos = v0.template posTrack_as(); - auto neg = v0.template negTrack_as(); - if (std::abs(pos.eta()) > etaMax || std::abs(pos.eta()) > etaMax) { - return; + // veto on K0s mass (only for lambda) + if (!k0short && (std::abs(mK0Short - o2::constants::physics::MassK0Short) < vetoMassK0Short)) { + continue; + } + + float dcaV0dau = std::sqrt(fitter.getChi2AtPCACandidate()); + if (dcaV0dau > v0setting_dcav0dau) { + continue; + } + + std::array primVtx = {collision.posX(), collision.posY(), collision.posZ()}; + const auto& vtx = fitter.getPCACandidate(); + + float radiusV0 = std::hypot(vtx[0], vtx[1]); + if (radiusV0 < v0setting_radius || radiusV0 > v0radiusMax) { + continue; + } + + float dcaV0Pv = CalculateDCAStraightToPV( + vtx[0], vtx[1], vtx[2], + momPos[0] + momNeg[0], + momPos[1] + momNeg[1], + momPos[2] + momNeg[2], + collision.posX(), collision.posY(), collision.posZ()); + if (std::abs(dcaV0Pv) > v0setting_dcav0pv) { + continue; + } + + double cosPA = RecoDecay::cpa(primVtx, vtx, momV0); + if (cosPA < v0setting_cospa) { + continue; } - bool matter = v0.alpha() > 0; - histos.fill(HIST("massLambda"), matter ? v0.mLambda() : v0.mAntiLambda()); - histos.fill(HIST("cosPa"), v0.v0cosPA()); - histos.fill(HIST("radius"), v0.v0radius()); - histos.fill(HIST("dcaV0daugh"), v0.dcaV0daughters()); - histos.fill(HIST("dcaPosPv"), v0.dcapostopv()); - histos.fill(HIST("dcaNegPv"), v0.dcanegtopv()); - - float ct = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; - float tpcNsigmaPi = matter ? neg.tpcNSigmaPi() : pos.tpcNSigmaPi(); - float tpcNsigmaPr = matter ? pos.tpcNSigmaPr() : neg.tpcNSigmaPr(); - - candV0.pt = v0.pt(); - candV0.eta = v0.eta(); - candV0.isMatter = matter; - candV0.mass = matter ? v0.mLambda() : v0.mAntiLambda(); - candV0.ct = ct; - candV0.radius = v0.v0radius(); - candV0.dcaV0PV = v0.dcav0topv(); - candV0.dcaPiPV = matter ? v0.dcanegtopv() : v0.dcapostopv(); - candV0.dcaPrPV = matter ? v0.dcapostopv() : v0.dcanegtopv(); - candV0.dcaV0Tracks = v0.dcaV0daughters(); - candV0.cosPA = v0.v0cosPA(); - candV0.tpcNsigmaPi = tpcNsigmaPi; - candV0.tpcNsigmaPr = tpcNsigmaPr; - candV0.globalIndexPos = pos.globalIndex(); - candV0.globalIndexNeg = neg.globalIndex(); - - candidateV0s.emplace_back(candV0); - // LOGF(info, "v0.pt = %f", candV0.pt); + auto ptotal = RecoDecay::sqrtSumOfSquares(momV0[0], momV0[1], momV0[2]); + auto lengthTraveled = RecoDecay::sqrtSumOfSquares(vtx[0] - primVtx[0], vtx[1] - primVtx[1], vtx[2] - primVtx[2]); + // change calculation of ML2P for k0 and lambda + float particlemass; + if (k0short) { + particlemass = o2::constants::physics::MassK0; + } else { + particlemass = o2::constants::physics::MassLambda; + } + float ML2P = particlemass * lengthTraveled / ptotal; + if (ML2P > v0setting_lifetime) { + continue; + } + + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, posTrackCov, 2.f, fitter.getMatCorrType(), &dcaInfo); + auto posDcaToPv = std::hypot(dcaInfo[0], dcaInfo[1]); + if (posDcaToPv < v0setting_dcadaughtopv && std::abs(dcaInfo[0]) < v0setting_dcadaughtopv) { + continue; + } + + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, negTrackCov, 2.f, fitter.getMatCorrType(), &dcaInfo); + auto negDcaToPv = std::hypot(dcaInfo[0], dcaInfo[1]); + if (negDcaToPv < v0setting_dcadaughtopv && std::abs(dcaInfo[0]) < v0setting_dcadaughtopv) { + continue; + } + + if (std::abs(mLambda - o2::constants::physics::MassLambda0) > lambdaMassCut) { // for QA histograms + continue; + } + histos.fill(HIST("QA/massLambda"), centrality, ptV0, mLambda); + + CandidateV0 candV0; + candV0.pt = matter > 0. ? ptV0 : -ptV0; + candV0.eta = etaV0; + candV0.ct = ML2P; + candV0.len = lengthTraveled; + candV0.mass = mLambda; + candV0.radius = radiusV0; + candV0.cpa = cosPA; + candV0.alphaAP = alpha; + candV0.qtAP = qtAP(momV0, momPos); + candV0.trackv0 = fitter.createParentTrackParCov(); + candV0.mompos = std::array{momPos[0], momPos[1], momPos[2]}; + candV0.momneg = std::array{momNeg[0], momNeg[1], momNeg[2]}; + candV0.dcav0daugh = dcaV0dau; + candV0.dcav0pv = dcaV0Pv; + candV0.dcanegpv = negDcaToPv; + candV0.dcapospv = posDcaToPv; + candV0.tpcnsigmaneg = nSigmaTPCNeg; + candV0.tpcnsigmapos = nSigmaTPCPos; + candV0.globalIndex = v0.globalIndex(); + candV0.globalIndexPos = posTrack.globalIndex(); + candV0.globalIndexNeg = negTrack.globalIndex(); + candidateV0s.push_back(candV0); + } + + for (auto& casc : cascades) { + auto v0 = casc.template v0_as(); + auto itv0 = find_if(candidateV0s.begin(), candidateV0s.end(), [&](CandidateV0 v0cand) { return v0cand.globalIndex == v0.globalIndex(); }); + if (itv0 == candidateV0s.end()) { + continue; + } + auto bachTrack = casc.template bachelor_as(); + auto bachTrackPar = getTrackPar(bachTrack); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, bachTrackPar, 2.f, fitter.getMatCorrType(), &dcaInfo); + + if (TMath::Abs(dcaInfo[0]) < cascsetting_dcabachpv) + continue; + + auto bachelorTrack = getTrackParCov(bachTrack); + int nCand = 0; + try { + nCand = fitter.process(itv0->trackv0, bachelorTrack); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call!"; + continue; + } + if (nCand == 0) + continue; + + auto v0Track = fitter.getTrack(0); + bachelorTrack = fitter.getTrack(1); + + std::array momV0; + std::array momBach; + std::array momCasc; + v0Track.getPxPyPzGlo(momV0); + bachelorTrack.getPxPyPzGlo(momBach); + momTotXYZ(momCasc, momV0, momBach); + + auto dcacascv0bach = TMath::Sqrt(fitter.getChi2AtPCACandidate()); + if (dcacascv0bach > cascsetting_dcav0bach) + continue; + + std::array primVtx = {collision.posX(), collision.posY(), collision.posZ()}; + const auto& vtx = fitter.getPCACandidate(); + double cosPA = RecoDecay::cpa(primVtx, vtx, momCasc); + if (cosPA < cascsetting_cospa) + continue; + + float mXi = invMass2Body(momCasc, momV0, momBach, o2::constants::physics::MassLambda0, o2::constants::physics::MassPionCharged); + float mOm = invMass2Body(momCasc, momV0, momBach, o2::constants::physics::MassLambda0, o2::constants::physics::MassKaonCharged); + + if (std::abs(mOm - o2::constants::physics::MassOmegaMinus) < cascsetting_vetoOm) + continue; + + if (std::abs(mXi - o2::constants::physics::MassXiMinus) > cascsetting_mXi) + continue; + + histos.fill(HIST("QA/massXi"), centrality, std::hypot(momCasc[0], momCasc[1]), mXi); + itv0->isFD = 1u; // Xi } } - template - void fillMcLambda(Collision const& collision, RecV0s const& v0s, T const& tracks, aod::McParticles const&, aod::McTrackLabels const& mcLabels) + template + void fillMcEvent(C const& collision, T const& tracks, aod::V0s const& V0s, aod::V0s const& V0s_all, aod::Cascades const& cascades, float const& centrality, aod::McParticles const&, aod::McTrackLabels const& mcLabels) { - fillRecoLambda(collision, v0s, tracks); + fillRecoEvent(collision, tracks, V0s, V0s_all, cascades, centrality); + for (auto& candidateV0 : candidateV0s) { - candidateV0.isReco = true; + candidateV0.isreco = true; auto mcLabPos = mcLabels.rawIteratorAt(candidateV0.globalIndexPos); auto mcLabNeg = mcLabels.rawIteratorAt(candidateV0.globalIndexNeg); if (mcLabPos.has_mcParticle() && mcLabNeg.has_mcParticle()) { auto mcTrackPos = mcLabPos.template mcParticle_as(); auto mcTrackNeg = mcLabNeg.template mcParticle_as(); + candidateV0.pdgposdau = mcTrackPos.pdgCode(); + candidateV0.pdgnegdau = mcTrackNeg.pdgCode(); + auto pdgCodeMotherDauPos = -999; + auto pdgCodeMotherDauNeg = -999; + auto pdgMatchMotherSecondMother = -999; if (mcTrackPos.has_mothers() && mcTrackNeg.has_mothers()) { for (auto& negMother : mcTrackNeg.template mothers_as()) { for (auto& posMother : mcTrackPos.template mothers_as()) { - if (posMother.globalIndex() != negMother.globalIndex()) - continue; - if (!((mcTrackPos.pdgCode() == 2212 && mcTrackNeg.pdgCode() == -211) || (mcTrackPos.pdgCode() == 211 && mcTrackNeg.pdgCode() == -1 * 2212))) // TODO: check warning for constant comparison - continue; - if (std::abs(posMother.pdgCode()) != 3122) - continue; - - auto posPrimVtx = std::array{posMother.vx(), posMother.vy(), posMother.vz()}; - auto secVtx = std::array{mcTrackPos.vx(), mcTrackPos.vy(), mcTrackPos.vz()}; - candidateV0.genPt = std::hypot(posMother.px(), posMother.py()); - auto mom = std::sqrt(std::pow(posMother.px(), 2) + std::pow(posMother.py(), 2) + std::pow(posMother.pz(), 2)); - auto len = std::sqrt(std::pow(secVtx[0] - posPrimVtx[0], 2) + std::pow(secVtx[1] - posPrimVtx[1], 2) + std::pow(secVtx[2] - posPrimVtx[2], 2)); - candidateV0.pdgCode = posMother.pdgCode(); - candidateV0.genEta = posMother.eta(); - candidateV0.genCt = len / (mom + 1e-10) * o2::constants::physics::MassLambda0; - checkedV0s.push_back(posMother.globalIndex()); + if (posMother.globalIndex() != negMother.globalIndex()) { + pdgCodeMotherDauPos = posMother.pdgCode(); + pdgCodeMotherDauNeg = negMother.pdgCode(); + if (negMother.pdgCode() == -211) { + if (negMother.has_mothers()) { + for (auto& negSecondMother : negMother.template mothers_as()) { + if (negSecondMother.globalIndex() == posMother.globalIndex()) { + pdgMatchMotherSecondMother = negSecondMother.pdgCode(); + } + } + } + } + if (posMother.pdgCode() == 211) { + if (posMother.has_mothers()) { + for (auto& posSecondMother : posMother.template mothers_as()) { + if (posSecondMother.globalIndex() == negMother.globalIndex()) { + pdgMatchMotherSecondMother = posSecondMother.pdgCode(); + } + } + } + } + } else { + candidateV0.pdgcode = posMother.pdgCode(); + pdgCodeMotherDauPos = posMother.pdgCode(); + pdgCodeMotherDauNeg = negMother.pdgCode(); + // build conditions for mother/daughter for k0short or lambda + bool mother; + bool daughter; + if (k0short) { + // mother is k0short (310) and daughters are pions (211/-211) + mother = posMother.pdgCode() == 310; + daughter = (mcTrackPos.pdgCode() == 211 && mcTrackNeg.pdgCode() == -211); + } else { + // mother is lambda (3122) and daughters are proton (2212) and pion(211) + mother = posMother.pdgCode() == 3122; + daughter = ((mcTrackPos.pdgCode() == 2212 && mcTrackNeg.pdgCode() == -211) || (mcTrackPos.pdgCode() == 211 && mcTrackNeg.pdgCode() == -2212)); + } + // check conditions + if (!mother || !daughter) { + continue; + } + + if (!posMother.isPhysicalPrimary() && !posMother.has_mothers()) + continue; + + auto pdgCodeMother = -999; + if (posMother.isPhysicalPrimary()) { + pdgCodeMother = 0; + } else if (posMother.has_mothers()) { + for (auto& mcMother : posMother.mothers_as()) { + // feed-down: xi and omega decaying to lambda, ignore for k0 + if (!k0short && (std::abs(mcMother.pdgCode()) == 3322 || std::abs(mcMother.pdgCode()) == 3312 || std::abs(mcMother.pdgCode()) == 3334)) { + pdgCodeMother = mcMother.pdgCode(); + break; + } + } + } + auto genPt = std::hypot(posMother.px(), posMother.py()); + auto posPrimVtx = std::array{posMother.vx(), posMother.vy(), posMother.vz()}; + auto secVtx = std::array{mcTrackPos.vx(), mcTrackPos.vy(), mcTrackPos.vz()}; + auto mom = std::sqrt(std::pow(posMother.px(), 2) + std::pow(posMother.py(), 2) + std::pow(posMother.pz(), 2)); + auto len = std::sqrt(std::pow(secVtx[0] - posPrimVtx[0], 2) + std::pow(secVtx[1] - posPrimVtx[1], 2) + std::pow(secVtx[2] - posPrimVtx[2], 2)); + candidateV0.genpt = genPt; + candidateV0.genlen = len; + candidateV0.genct = len / (mom + 1e-10) * o2::constants::physics::MassLambda0; + candidateV0.pdgcodemother = pdgCodeMother; + candidateV0.geneta = posMother.eta(); + candidateV0.mcIndex = posMother.globalIndex(); + } } } } + if ((!mcTrackPos.has_mothers()) && mcTrackNeg.has_mothers()) { + pdgCodeMotherDauPos = -999; + for (auto& negMother : mcTrackNeg.template mothers_as()) { + pdgCodeMotherDauNeg = negMother.pdgCode(); + } + } + if ((!mcTrackNeg.has_mothers()) && mcTrackPos.has_mothers()) { + pdgCodeMotherDauNeg = -999; + for (auto& posMother : mcTrackPos.template mothers_as()) { + pdgCodeMotherDauPos = posMother.pdgCode(); + } + } + if ((!mcTrackNeg.has_mothers()) && (!mcTrackPos.has_mothers())) { + pdgCodeMotherDauNeg = -999; + pdgCodeMotherDauPos = -999; + } + candidateV0.pdgcodemotherdauneg = pdgCodeMotherDauNeg; + candidateV0.pdgcodemotherdaupos = pdgCodeMotherDauPos; + candidateV0.pdgmatchmothersecondmother = pdgMatchMotherSecondMother; + // momentum of daughters + std::array momPosMC = std::array{static_cast(-999.), static_cast(-999.), static_cast(-999.)}; + std::array momNegMC = std::array{static_cast(-999.), static_cast(-999.), static_cast(-999.)}; + momPosMC[0] = mcTrackPos.px(); + momPosMC[1] = mcTrackPos.py(); + momPosMC[2] = mcTrackPos.pz(); + momNegMC[0] = mcTrackNeg.px(); + momNegMC[1] = mcTrackNeg.py(); + momNegMC[2] = mcTrackNeg.pz(); + candidateV0.momposMC = std::array{momPosMC[0], momPosMC[1], momPosMC[2]}; + candidateV0.momnegMC = std::array{momNegMC[0], momNegMC[1], momNegMC[2]}; } } } - void init(o2::framework::InitContext&) - { - randomSeed = static_cast(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); - - histos.add("zVtx", ";#it{z}_{vtx} (cm);Entries", HistType::kTH1F, {zVtxAxis}); - - // v0 QA - histos.add("massLambda", ";#it{M}(p + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH1F, {massLambdaAxis}); - histos.add("cosPa", ";cosPa;Entries", HistType::kTH1F, {cosPaAxis}); - histos.add("radius", ";radius;Entries", HistType::kTH1F, {radiusAxis}); - histos.add("dcaV0daugh", ";dcaV0daugh;Entries", HistType::kTH1F, {dcaV0daughAxis}); - histos.add("dcaPosPv", ";dcaPosPv;Entries", HistType::kTH1F, {dcaDaughPvAxis}); - histos.add("dcaNegPv", ";dcaNegPv;Entries", HistType::kTH1F, {dcaDaughPvAxis}); - } - - void processData(soa::Join::iterator const& collision, TracksFull const& tracks, aod::V0Datas const& V0s, aod::BCsWithTimestamps const&) + void fillMcGen(aod::McParticles const& mcParticles, aod::McTrackLabels const& /*mcLab*/, uint64_t const& collisionId) { - if (!collision.sel8()) - return; - - if (std::abs(collision.posZ()) > zVtxMax) - return; + auto mcParticles_thisCollision = mcParticles.sliceBy(perCollisionMcParts, collisionId); + for (auto& mcPart : mcParticles_thisCollision) { + auto genEta = mcPart.eta(); + if (std::abs(genEta) > etaMax) { + continue; + } - histos.fill(HIST("zVtx"), collision.posZ()); + auto pdgCode = mcPart.pdgCode(); + std::array secVtx; + std::array momPosMC = std::array{static_cast(-999.), static_cast(-999.), static_cast(-999.)}; + std::array momNegMC = std::array{static_cast(-999.), static_cast(-999.), static_cast(-999.)}; - if (downscaleFactor < 1.f && (static_cast(rand_r(&randomSeed)) / static_cast(RAND_MAX)) > downscaleFactor) { - return; - } + // look for lambda (3122) or k0short (310) + int pdg_test = 3122; + if (k0short) + pdg_test = 310; - auto centrality = collision.centFT0C(); - fillRecoLambda(collision, V0s, tracks); - for (auto& candidateV0 : candidateV0s) { - // LOG(info) << candidateV0.pt; - lambdaTableML( - candidateV0.pt, - candidateV0.eta, - centrality, - candidateV0.isMatter, - candidateV0.mass, - candidateV0.ct, - candidateV0.radius, - candidateV0.dcaV0PV, - candidateV0.dcaPiPV, - candidateV0.dcaPrPV, - candidateV0.dcaV0Tracks, - candidateV0.cosPA, - candidateV0.tpcNsigmaPi, - candidateV0.tpcNsigmaPr); + if (std::abs(pdgCode) == pdg_test) { + if (!mcPart.isPhysicalPrimary() && !mcPart.has_mothers()) + continue; + // check if its the right decay containing proton (2122) for lambda and charged pion (211) for k0short + int pdg_particle; + if (k0short) { + pdg_particle = 211; + } else { + pdg_particle = 2212; + } + bool foundParticle = false; + for (auto& mcDaught : mcPart.daughters_as()) { + if (std::abs(mcDaught.pdgCode()) == pdg_particle) { + foundParticle = true; + secVtx = std::array{mcDaught.vx(), mcDaught.vy(), mcDaught.vz()}; + break; + } + } + // momentum of daughters + for (auto& mcDaught : mcPart.daughters_as()) { + if (mcDaught.pdgCode() < 0) { + momNegMC[0] = mcDaught.px(); + momNegMC[1] = mcDaught.py(); + momNegMC[2] = mcDaught.pz(); + } else { + momPosMC[0] = mcDaught.px(); + momPosMC[1] = mcDaught.py(); + momPosMC[2] = mcDaught.pz(); + } + } + if (!foundParticle) { + continue; + } + auto pdgCodeMother = -999; + if (mcPart.isPhysicalPrimary()) { + pdgCodeMother = 0; + } else if (mcPart.has_mothers()) { + for (auto& mcMother : mcPart.mothers_as()) { + // feed-down: xi and omega decaying to lambda, ignore for k0 + if (!k0short && (std::abs(mcMother.pdgCode()) == 3322 || std::abs(mcMother.pdgCode()) == 3312 || std::abs(mcMother.pdgCode()) == 3334)) { + pdgCodeMother = mcMother.pdgCode(); + break; + } + } + } + auto genPt = std::hypot(mcPart.px(), mcPart.py()); + auto posPrimVtx = std::array{mcPart.vx(), mcPart.vy(), mcPart.vz()}; + auto mom = std::sqrt(std::pow(mcPart.px(), 2) + std::pow(mcPart.py(), 2) + std::pow(mcPart.pz(), 2)); + auto len = std::sqrt(std::pow(secVtx[0] - posPrimVtx[0], 2) + std::pow(secVtx[1] - posPrimVtx[1], 2) + std::pow(secVtx[2] - posPrimVtx[2], 2)); + + CandidateV0 candV0; + candV0.genpt = genPt; + candV0.genlen = len; + candV0.genct = len / (mom + 1e-10) * o2::constants::physics::MassLambda0; + candV0.geneta = mcPart.eta(); + candV0.pdgcode = pdgCode; + candV0.pdgcodemother = pdgCodeMother; + candV0.momposMC = std::array{momPosMC[0], momPosMC[1], momPosMC[2]}; + candV0.momnegMC = std::array{momNegMC[0], momNegMC[1], momNegMC[2]}; + auto it = find_if(candidateV0s.begin(), candidateV0s.end(), [&](CandidateV0 v0) { return v0.mcIndex == mcPart.globalIndex(); }); + if (it == candidateV0s.end()) { + candidateV0s.emplace_back(candV0); + } else { + continue; + } + } } } - PROCESS_SWITCH(LFStrangeTreeCreator, processData, "process data", false); - void processDataRun2(soa::Join::iterator const& collision, TracksFull const& tracks, aod::V0Datas const& V0s, BCsWithRun2Info const&) + void processRun3(soa::Join const& collisions, TracksFullIU const& tracks, aod::V0s const& V0s, aod::Cascades const& cascades, aod::BCsWithTimestamps const&) { - if (std::abs(collision.posZ()) > zVtxMax) - return; - - auto bc = collision.bc_as(); - if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kAliEventCutsAccepted))) - return; + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); - if (kUseTPCPileUpCut && !(bc.eventCuts() & BIT(aod::Run2EventCuts::kTPCPileUp))) - return; - - auto centrality = collision.centRun2V0M(); - if (!collision.alias_bit(kINT7) && (!kINT7Intervals || (kINT7Intervals && ((centrality >= 10 && centrality < 30) || centrality > 50)))) - return; - - histos.fill(HIST("zVtx"), collision.posZ()); - - if (downscaleFactor < 1.f && (static_cast(rand_r(&randomSeed)) / static_cast(RAND_MAX)) > downscaleFactor) { - return; - } - - fillRecoLambda(collision, V0s, tracks); - for (auto& candidateV0 : candidateV0s) { - // LOG(info) << candidateV0.pt; - lambdaTableML( - candidateV0.pt, - candidateV0.eta, - centrality, - candidateV0.isMatter, - candidateV0.mass, - candidateV0.ct, - candidateV0.radius, - candidateV0.dcaV0PV, - candidateV0.dcaPiPV, - candidateV0.dcaPrPV, - candidateV0.dcaV0Tracks, - candidateV0.cosPA, - candidateV0.tpcNsigmaPi, - candidateV0.tpcNsigmaPr); - } - } - PROCESS_SWITCH(LFStrangeTreeCreator, processDataRun2, "process data run 2", false); - - void processMc(soa::Join const& collisions, TracksFull const& tracks, aod::V0Datas const& V0s, aod::McParticles const& mcParticles, aod::McTrackLabels const& mcLabels) - { - for (auto& collision : collisions) { if (!collision.sel8()) continue; if (std::abs(collision.posZ()) > zVtxMax) continue; - const uint64_t collIdx = collision.globalIndex(); - auto V0Table_thisCollision = V0s.sliceBy(perCollision, collIdx); - V0Table_thisCollision.bindExternalIndices(&tracks); + if (!collision.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + continue; - histos.fill(HIST("zVtx"), collision.posZ()); + if ((!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) && applyAdditionalEvSel) + continue; if (downscaleFactor < 1.f && (static_cast(rand_r(&randomSeed)) / static_cast(RAND_MAX)) > downscaleFactor) { - continue; + return; } - fillMcLambda(collision, V0Table_thisCollision, tracks, mcParticles, mcLabels); + histos.fill(HIST("QA/zVtx"), collision.posZ()); - auto centrality = collision.centFT0C(); - for (auto& candidateV0 : candidateV0s) { - if ((fillOnlySignal && std::abs(candidateV0.pdgCode) == 3122) || !fillOnlySignal) { - mcLambdaTableML( - candidateV0.pt, - candidateV0.eta, - centrality, - candidateV0.isMatter, - candidateV0.mass, - candidateV0.ct, - candidateV0.radius, - candidateV0.dcaV0PV, - candidateV0.dcaPiPV, - candidateV0.dcaPrPV, - candidateV0.dcaV0Tracks, - candidateV0.cosPA, - candidateV0.tpcNsigmaPi, - candidateV0.tpcNsigmaPr, - candidateV0.genPt, - candidateV0.genEta, - candidateV0.genCt, - candidateV0.pdgCode, - candidateV0.isReco); - } - } - } + const uint64_t collIdx = collision.globalIndex(); + auto V0Table_thisCollision = V0s.sliceBy(perCollisionV0, collIdx); + auto CascTable_thisCollision = cascades.sliceBy(perCollisionCasc, collIdx); + V0Table_thisCollision.bindExternalIndices(&tracks); + CascTable_thisCollision.bindExternalIndices(&tracks); + CascTable_thisCollision.bindExternalIndices(&V0s); - if (fillNonRecSignal) { - for (auto& mcPart : mcParticles) { + auto centrality = collision.centFT0C(); + fillRecoEvent(collision, tracks, V0Table_thisCollision, V0s, CascTable_thisCollision, centrality); - if (std::abs(mcPart.pdgCode()) != 3122) - continue; - std::array secVtx{0.f}; - std::array primVtx = {mcPart.vx(), mcPart.vy(), mcPart.vz()}; - std::array momMother = {mcPart.px(), mcPart.py(), mcPart.pz()}; - for (auto& mcDaught : mcPart.daughters_as()) { - if (std::abs(mcDaught.pdgCode()) == 2212) { - secVtx = {mcDaught.vx(), mcDaught.vy(), mcDaught.vz()}; - break; - } - } - if (std::find(checkedV0s.begin(), checkedV0s.end(), mcPart.globalIndex()) != std::end(checkedV0s)) { - continue; - } - CandidateV0 candidateV0; - auto momV0 = std::sqrt(std::pow(momMother[0], 2) + std::pow(momMother[1], 2) + std::pow(momMother[2], 2)); - candidateV0.genCt = std::sqrt(std::pow(secVtx[0] - primVtx[0], 2) + std::pow(secVtx[1] - primVtx[1], 2) + std::pow(secVtx[2] - primVtx[2], 2)) / (momV0 + 1e-10) * o2::constants::physics::MassLambda0; - candidateV0.isReco = false; - candidateV0.genPt = std::sqrt(std::pow(momMother[0], 2) + std::pow(momMother[1], 2)); - candidateV0.genEta = mcPart.eta(); - candidateV0.pdgCode = mcPart.pdgCode(); - mcLambdaTableML( - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - candidateV0.genPt, - candidateV0.genEta, - candidateV0.genCt, - candidateV0.pdgCode, - candidateV0.isReco); + for (auto& candidateV0 : candidateV0s) { + lambdaTableML( + candidateV0.pt, + candidateV0.eta, + candidateV0.mass, + candidateV0.ct, + candidateV0.radius, + candidateV0.dcav0pv, + candidateV0.dcapospv, + candidateV0.dcanegpv, + candidateV0.dcav0daugh, + candidateV0.cpa, + candidateV0.alphaAP, + candidateV0.qtAP, + candidateV0.tpcnsigmapos, + candidateV0.tpcnsigmaneg, + candidateV0.isFD); + + v0TableAP( + candidateV0.eta, + candidateV0.len, + candidateV0.mompos[0], + candidateV0.mompos[1], + candidateV0.mompos[2], + candidateV0.momneg[0], + candidateV0.momneg[1], + candidateV0.momneg[2], + candidateV0.radius, + candidateV0.dcav0pv, + candidateV0.dcapospv, + candidateV0.dcanegpv, + candidateV0.dcav0daugh, + candidateV0.cpa); } } } - PROCESS_SWITCH(LFStrangeTreeCreator, processMc, "process mc", false); + PROCESS_SWITCH(LFStrangeTreeCreator, processRun3, "process (Run 3)", false); - void processMcRun2(soa::Join const& collisions, TracksFull const& tracks, aod::V0Datas const& V0s, aod::McParticles const& mcParticles, aod::McTrackLabels const& mcLabels) + void processMcRun3(soa::Join const& collisions, aod::McCollisions const& /*mcCollisions*/, TracksFullIU const& tracks, aod::V0s const& V0s, aod::Cascades const& cascades, aod::McParticles const& mcParticles, aod::McTrackLabels const& mcLab, aod::BCsWithTimestamps const&) { for (auto& collision : collisions) { - if (std::abs(collision.posZ()) > zVtxMax) - continue; + auto bc = collision.bc_as(); + initCCDB(bc); - const uint64_t collIdx = collision.globalIndex(); - auto V0Table_thisCollision = V0s.sliceBy(perCollision, collIdx); - V0Table_thisCollision.bindExternalIndices(&tracks); + if (!collision.sel8()) + continue; - histos.fill(HIST("zVtx"), collision.posZ()); + if ((!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) && applyAdditionalEvSel) + continue; - if (downscaleFactor < 1.f && (static_cast(rand_r(&randomSeed)) / static_cast(RAND_MAX)) > downscaleFactor) { + if (std::abs(collision.posZ()) > zVtxMax) continue; - } - fillMcLambda(collision, V0Table_thisCollision, tracks, mcParticles, mcLabels); + auto centrality = collision.centFT0C(); - auto centrality = collision.centRun2V0M(); - for (auto& candidateV0 : candidateV0s) { - if ((fillOnlySignal && std::abs(candidateV0.pdgCode) == 3122) || !fillOnlySignal) { - mcLambdaTableML( - candidateV0.pt, - candidateV0.eta, - centrality, - candidateV0.isMatter, - candidateV0.mass, - candidateV0.ct, - candidateV0.radius, - candidateV0.dcaV0PV, - candidateV0.dcaPiPV, - candidateV0.dcaPrPV, - candidateV0.dcaV0Tracks, - candidateV0.cosPA, - candidateV0.tpcNsigmaPi, - candidateV0.tpcNsigmaPr, - candidateV0.genPt, - candidateV0.genEta, - candidateV0.genCt, - candidateV0.pdgCode, - candidateV0.isReco); - } - } - } + histos.fill(HIST("QA/zVtx"), collision.posZ()); - if (fillNonRecSignal) { - for (auto& mcPart : mcParticles) { + const uint64_t collIdx = collision.globalIndex(); + auto V0Table_thisCollision = V0s.sliceBy(perCollisionV0, collIdx); + auto CascTable_thisCollision = cascades.sliceBy(perCollisionCasc, collIdx); + V0Table_thisCollision.bindExternalIndices(&tracks); + CascTable_thisCollision.bindExternalIndices(&tracks); + CascTable_thisCollision.bindExternalIndices(&V0s); - if (std::abs(mcPart.pdgCode()) != 3122) - continue; - std::array secVtx{0.f}; - std::array primVtx = {mcPart.vx(), mcPart.vy(), mcPart.vz()}; - std::array momMother = {mcPart.px(), mcPart.py(), mcPart.pz()}; - for (auto& mcDaught : mcPart.daughters_as()) { - if (std::abs(mcDaught.pdgCode()) == 2212) { - secVtx = {mcDaught.vx(), mcDaught.vy(), mcDaught.vz()}; - break; - } - } - if (std::find(checkedV0s.begin(), checkedV0s.end(), mcPart.globalIndex()) != std::end(checkedV0s)) { - continue; - } - CandidateV0 candidateV0; - auto momV0 = std::sqrt(std::pow(momMother[0], 2) + std::pow(momMother[1], 2) + std::pow(momMother[2], 2)); - candidateV0.genCt = std::sqrt(std::pow(secVtx[0] - primVtx[0], 2) + std::pow(secVtx[1] - primVtx[1], 2) + std::pow(secVtx[2] - primVtx[2], 2)) / (momV0 + 1e-10) * o2::constants::physics::MassLambda0; - candidateV0.isReco = false; - candidateV0.genPt = std::sqrt(std::pow(momMother[0], 2) + std::pow(momMother[1], 2)); - candidateV0.genEta = mcPart.eta(); - candidateV0.pdgCode = mcPart.pdgCode(); + fillMcEvent(collision, tracks, V0Table_thisCollision, V0s, CascTable_thisCollision, centrality, mcParticles, mcLab); + fillMcGen(mcParticles, mcLab, collision.mcCollisionId()); + + for (auto& candidateV0 : candidateV0s) { mcLambdaTableML( - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - candidateV0.genPt, - candidateV0.genEta, - candidateV0.genCt, - candidateV0.pdgCode, - candidateV0.isReco); + candidateV0.pt, + candidateV0.eta, + candidateV0.mass, + candidateV0.ct, + candidateV0.radius, + candidateV0.dcav0pv, + candidateV0.dcapospv, + candidateV0.dcanegpv, + candidateV0.dcav0daugh, + candidateV0.cpa, + candidateV0.alphaAP, + candidateV0.qtAP, + candidateV0.tpcnsigmapos, + candidateV0.tpcnsigmaneg, + candidateV0.genpt, + candidateV0.geneta, + candidateV0.genct, + candidateV0.pdgposdau, + candidateV0.pdgcodemotherdaupos, + candidateV0.pdgnegdau, + candidateV0.pdgcodemotherdauneg, + candidateV0.pdgcode, + candidateV0.pdgcodemother, + candidateV0.isreco, + candidateV0.pdgmatchmothersecondmother); + + mcV0TableAP( + candidateV0.eta, + candidateV0.len, + candidateV0.mompos[0], + candidateV0.mompos[1], + candidateV0.mompos[2], + candidateV0.momneg[0], + candidateV0.momneg[1], + candidateV0.momneg[2], + candidateV0.momposMC[0], + candidateV0.momposMC[1], + candidateV0.momposMC[2], + candidateV0.momnegMC[0], + candidateV0.momnegMC[1], + candidateV0.momnegMC[2], + candidateV0.radius, + candidateV0.dcav0pv, + candidateV0.dcapospv, + candidateV0.dcanegpv, + candidateV0.dcav0daugh, + candidateV0.cpa, + candidateV0.geneta, + candidateV0.genlen, + candidateV0.pdgcode, + candidateV0.isreco); } } } - PROCESS_SWITCH(LFStrangeTreeCreator, processMcRun2, "process mc run 2", false); + PROCESS_SWITCH(LFStrangeTreeCreator, processMcRun3, "process MC (Run 3)", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/TableProducer/Strangeness/LambdaLambdatable.cxx b/PWGLF/TableProducer/Strangeness/LambdaLambdatable.cxx new file mode 100644 index 00000000000..778f39ed442 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/LambdaLambdatable.cxx @@ -0,0 +1,299 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \author Junlee Kim, (junlee.kim@cern.ch) + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "CommonConstants/MathConstants.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" + +#include "PWGLF/DataModel/ReducedLambdaLambdaTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct lambdalambdatable { + + // Produce derived tables + Produces redLLEvents; + Produces llTrack; + + // events + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + + Configurable cfgUseGlobalTrack{"cfgUseGlobalTrack", true, "use Global track"}; + Configurable cfgCutPt{"cfgCutPt", 0.2, "PT cut on daughter track"}; + Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; + Configurable cfgCutDCAxy{"cfgCutDCAxy", 0.2f, "DCAxy range for tracks"}; + Configurable cfgCutDCAz{"cfgCutDCAz", 0.2f, "DCAz range for tracks"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 50, "Number of TPC cluster"}; + + Configurable cfgv0radiusMin{"cfgv0radiusMin", 1.2, "minimum decay radius"}; + Configurable cfgDCAPosToPVMin{"cfgDCAPosToPVMin", 0.05, "minimum DCA to PV for positive track"}; + Configurable cfgDCANegToPVMin{"cfgDCANegToPVMin", 0.2, "minimum DCA to PV for negative track"}; + Configurable cfgv0CosPA{"cfgv0CosPA", 0.995, "minimum v0 cosine"}; + Configurable cfgDCAV0Dau{"cfgDCAV0Dau", 1.0, "maximum DCA between daughters"}; + + Configurable cfgV0PtMin{"cfgV0PtMin", 0, "minimum pT for lambda"}; + Configurable cfgV0EtaMin{"cfgV0EtaMin", -0.5, "maximum rapidity"}; + Configurable cfgV0EtaMax{"cfgV0EtaMax", 0.5, "maximum rapidity"}; + Configurable cfgV0LifeTime{"cfgV0LifeTime", 30., "maximum lambda lifetime"}; + + Configurable cfgDaughTPCnclsMin{"cfgDaughTPCnclsMin", 50, "minimum fired crossed rows"}; + Configurable cfgDaughPIDCutsTPCPr{"cfgDaughPIDCutsTPCPr", 5, "proton nsigma for TPC"}; + Configurable cfgDaughPIDCutsTPCPi{"cfgDaughPIDCutsTPCPi", 5, "pion nsigma for TPC"}; + Configurable cfgDaughEtaMin{"cfgDaughEtaMin", -0.8, "minimum daughter eta"}; + Configurable cfgDaughEtaMax{"cfgDaughEtaMax", 0.8, "maximum daughter eta"}; + Configurable cfgDaughPrPt{"cfgDaughPrPt", 0.5, "minimum daughter proton pt"}; + Configurable cfgDaughPiPt{"cfgDaughPiPt", 0.2, "minimum daughter pion pt"}; + + Configurable cfgMinLambdaMass{"cfgMinLambdaMass", 1.105, "Minimum lambda mass"}; + Configurable cfgMaxLambdaMass{"cfgMaxLambdaMass", 1.125, "Maximum lambda mass"}; + + ConfigurableAxis massAxis{"massAxis", {200, 2.1, 2.3}, "Invariant mass axis"}; + ConfigurableAxis ptAxis{"ptAxis", {VARIABLE_WIDTH, 0.0, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.5, 8.0, 10.0, 100.0}, "Transverse momentum bins"}; + ConfigurableAxis centAxis{"centAxis", {VARIABLE_WIDTH, 0, 20, 50, 100}, "Centrality interval"}; + ConfigurableAxis vertexAxis{"vertexAxis", {10, -10, 10}, "vertex axis for mixing"}; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPt); + Filter DCAcutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); + + using EventCandidates = soa::Filtered>; + using TrackCandidates = soa::Filtered>; + + HistogramRegistry histos{ + "histos", + {}, + OutputObjHandlingPolicy::AnalysisObject}; + + SliceCache cache; + + double massLambda = o2::constants::physics::MassLambda; + double massPr = o2::constants::physics::MassProton; + double massPi = o2::constants::physics::MassPionCharged; + + float centrality; + + void init(o2::framework::InitContext&) + { + histos.add("hEventstat", "", {HistType::kTH1F, {{3, 0, 3}}}); + } + + template + bool selectionTrack(const T& candidate) + { + if (cfgUseGlobalTrack && !(candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.tpcNClsFound() > cfgTPCcluster)) { + return false; + } + return true; + } + + template + bool selectionPID(const T& candidate, int pid) + { + if (pid == 0) { + if (std::abs(candidate.tpcNSigmaPi()) > cfgDaughPIDCutsTPCPi) { + return false; + } + } else if (pid == 2) { + if (std::abs(candidate.tpcNSigmaPr()) > cfgDaughPIDCutsTPCPr) { + return false; + } + } + return true; + } + + template + bool selectionV0(TCollision const& collision, V0 const& candidate) + { + if (candidate.v0radius() < cfgv0radiusMin) + return false; + if (std::abs(candidate.dcapostopv()) < cfgDCAPosToPVMin) + return false; + if (std::abs(candidate.dcanegtopv()) < cfgDCANegToPVMin) + return false; + if (candidate.v0cosPA() < cfgv0CosPA) + return false; + if (std::abs(candidate.dcaV0daughters()) > cfgDCAV0Dau) + return false; + if (candidate.pt() < cfgV0PtMin) + return false; + if (candidate.yLambda() < cfgV0EtaMin) + return false; + if (candidate.yLambda() > cfgV0EtaMax) + return false; + if (candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massLambda > cfgV0LifeTime) + return false; + + return true; + } + + template + bool selectionV0Daughter(T const& track, int pid) // pid 0: proton, pid 1: pion + { + if (track.tpcNClsFound() < cfgDaughTPCnclsMin) + return false; + if (pid == 0 && std::abs(track.tpcNSigmaPr()) > cfgDaughPIDCutsTPCPr) + return false; + if (pid == 1 && std::abs(track.tpcNSigmaPi()) > cfgDaughPIDCutsTPCPi) + return false; + if (track.eta() > cfgDaughEtaMax) + return false; + if (track.eta() < cfgDaughEtaMin) + return false; + if (pid == 0 && track.pt() < cfgDaughPrPt) + return false; + if (pid == 1 && track.pt() < cfgDaughPiPt) + return false; + + return true; + } + + ROOT::Math::PxPyPzMVector DauVec1, DauVec2, LLMesonMother, LLVectorDummy, LLd1dummy, LLd2dummy; + + void processLLReducedTable(EventCandidates::iterator const& collision, TrackCandidates const& /*tracks*/, aod::V0Datas const& V0s, aod::BCsWithTimestamps const&) + { + bool keepEventLL = false; + int numberLambda = 0; + auto currentRunNumber = collision.bc_as().runNumber(); + auto bc = collision.bc_as(); + centrality = collision.centFT0M(); + + std::vector LLdId = {}; + + std::vector LLdd1Index = {}; + std::vector LLdd2Index = {}; + + std::vector LLdd1TPC = {}; + std::vector LLdd2TPC = {}; + + std::vector LLdx = {}; + std::vector LLdy = {}; + std::vector LLdz = {}; + + std::vector llresonance; + + histos.fill(HIST("hEventstat"), 0.5); + if (!(collision.sel8() && collision.selection_bit(aod::evsel::kNoTimeFrameBorder) && collision.selection_bit(aod::evsel::kNoITSROFrameBorder) && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) + return; + histos.fill(HIST("hEventstat"), 1.5); + + for (auto& v0 : V0s) { + auto postrack_v0 = v0.template posTrack_as(); + auto negtrack_v0 = v0.template negTrack_as(); + + int LambdaTag = 0; + int aLambdaTag = 0; + + if (selectionV0Daughter(postrack_v0, 0) && selectionV0Daughter(negtrack_v0, 1)) + LambdaTag = 1; + + if (selectionV0Daughter(negtrack_v0, 0) && selectionV0Daughter(postrack_v0, 1)) + aLambdaTag = 1; + + if (LambdaTag == aLambdaTag) + continue; + + if (!selectionV0(collision, v0)) + continue; + + if (LambdaTag) { + if (v0.mLambda() < cfgMinLambdaMass || v0.mLambda() > cfgMaxLambdaMass) { + continue; + } + DauVec1 = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), massPr); + DauVec2 = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), massPi); + LLdId.push_back(3122); + } else if (aLambdaTag) { + if (v0.mAntiLambda() < cfgMinLambdaMass || v0.mAntiLambda() > cfgMaxLambdaMass) { + continue; + } + DauVec1 = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), massPi); + DauVec2 = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), massPr); + LLdId.push_back(-3122); + } + numberLambda++; + + LLdx.push_back(v0.x()); + LLdy.push_back(v0.y()); + LLdz.push_back(v0.z()); + + LLMesonMother = DauVec1 + DauVec2; + + ROOT::Math::PtEtaPhiMVector temp3(LLMesonMother.Pt(), LLMesonMother.Eta(), LLMesonMother.Phi(), LLMesonMother.M()); + llresonance.push_back(temp3); + + if (LambdaTag) { + LLdd1TPC.push_back(postrack_v0.tpcNSigmaPr()); + LLdd2TPC.push_back(negtrack_v0.tpcNSigmaPi()); + } else if (aLambdaTag) { + LLdd1TPC.push_back(postrack_v0.tpcNSigmaPi()); + LLdd2TPC.push_back(negtrack_v0.tpcNSigmaPr()); + } + + LLdd1Index.push_back(postrack_v0.globalIndex()); + LLdd2Index.push_back(negtrack_v0.globalIndex()); + } // select collision + + if (numberLambda < 2) + return; + + keepEventLL = true; + + if (keepEventLL) { + histos.fill(HIST("hEventstat"), 2.5); + /////////// Fill collision table/////////////// + redLLEvents(bc.globalBC(), currentRunNumber, bc.timestamp(), collision.posZ(), collision.numContrib(), centrality, numberLambda); + auto indexEvent = redLLEvents.lastIndex(); + //// Fill track table for LL////////////////// + for (auto if1 = llresonance.begin(); if1 != llresonance.end(); ++if1) { + auto i5 = std::distance(llresonance.begin(), if1); + LLVectorDummy = llresonance.at(i5); + llTrack(indexEvent, LLdId.at(i5), LLVectorDummy.Px(), LLVectorDummy.Py(), LLVectorDummy.Pz(), LLdx.at(i5), LLdy.at(i5), LLdz.at(i5), LLVectorDummy.M(), LLdd1TPC.at(i5), LLdd2TPC.at(i5), LLdd1Index.at(i5), LLdd2Index.at(i5)); + } + } + } // process + PROCESS_SWITCH(lambdalambdatable, processLLReducedTable, "Process table creation for double ll", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfg) +{ + return WorkflowSpec{adaptAnalysisTask(cfg)}; +} diff --git a/PWGLF/TableProducer/Strangeness/cascadebuilder.cxx b/PWGLF/TableProducer/Strangeness/cascadebuilder.cxx index f85d3e2d34f..8aeb741bff7 100644 --- a/PWGLF/TableProducer/Strangeness/cascadebuilder.cxx +++ b/PWGLF/TableProducer/Strangeness/cascadebuilder.cxx @@ -36,12 +36,16 @@ // david.dobrigkeit.chinellato@cern.ch // +#include +#include #include #include #include #include #include #include +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/RunningWorkflowInfo.h" @@ -53,6 +57,7 @@ #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" #include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessMLTables.h" #include "PWGLF/DataModel/LFParticleIdentification.h" #include "Common/Core/TrackSelection.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -99,6 +104,7 @@ using TracksExtraWithPIDandLabels = soa::Join; using V0fCfull = soa::Join; using TaggedCascades = soa::Join; +using TaggedFindableCascades = soa::Join; // For MC association in pre-selection using LabeledTracksExtra = soa::Join; @@ -122,15 +128,20 @@ struct cascadeBuilder { Produces cascTrackXs; // if desired for replaying of position information Produces cascbb; // if enabled Produces casccovs; // if requested by someone + Produces tracasccovs; // if requested by someone Produces kfcasccovs; // if requested by someone + // produces calls for machine-learning selections + Produces xiMLSelections; // Xi scores + Produces omegaMLSelections; // Omega scores + o2::ccdb::CcdbApi ccdbApi; Service ccdb; Configurable d_UseAutodetectMode{"d_UseAutodetectMode", false, "Autodetect requested topo sels"}; // Configurables related to table creation - Configurable createCascCovMats{"createCascCovMats", -1, {"Produces V0 cov matrices. -1: auto, 0: don't, 1: yes. Default: auto (-1)"}}; + Configurable createCascCovMats{"createCascCovMats", -1, {"Produces casc cov matrices. -1: auto, 0: don't, 1: yes. Default: auto (-1)"}}; Configurable createCascTrackXs{"createCascTrackXs", -1, {"Produces track X at minima table. -1: auto, 0: don't, 1: yes. Default: auto (-1)"}}; // Topological selection criteria @@ -193,6 +204,8 @@ struct cascadeBuilder { Configurable kfDoDCAFitterPreMinimV0{"kfDoDCAFitterPreMinimV0", true, "KF: do DCAFitter pre-optimization before KF fit to include material corrections for V0"}; Configurable kfDoDCAFitterPreMinimCasc{"kfDoDCAFitterPreMinimCasc", true, "KF: do DCAFitter pre-optimization before KF fit to include material corrections for Xi"}; + // for using cascade momentum at prim. vtx + Configurable useCascadeMomentumAtPrimVtx{"useCascadeMomentumAtPrimVtx", false, "if enabled, store cascade momentum at prim. vtx instead of decay point (= default)"}; // for topo var QA struct : ConfigurableGroup { ConfigurableAxis axisTopoVarPointingAngle{"axisConfigurations.axisTopoVarPointingAngle", {50, 0.0, 1.0}, "pointing angle"}; @@ -251,6 +264,7 @@ struct cascadeBuilder { // For manual sliceBy Preslice perCollision = o2::aod::cascade::collisionId; + Preslice perCollisionFindable = o2::aod::cascade::collisionId; Preslice perCascade = o2::aod::strangenesstracking::cascadeId; // Define o2 fitter, 2-prong, active memory (no need to redefine per event) @@ -529,12 +543,11 @@ struct cascadeBuilder { } } if (useMatCorrType == 2) { - LOGF(info, "LUT correction requested, loading LUT"); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbConfigurations.lutPath)); + LOGF(info, "LUT correction requested, will load LUT when initializing with timestamp..."); } - if (doprocessRun2 == false && doprocessRun3 == false && doprocessRun3withStrangenessTracking == false && doprocessRun3withKFParticle == false) { - LOGF(fatal, "Neither processRun2 nor processRun3 nor processRun3withstrangenesstracking enabled. Please choose one!"); + if (doprocessRun2 == false && doprocessRun3 == false && doprocessRun3withStrangenessTracking == false && doprocessRun3withKFParticle == false && doprocessFindableRun3 == false) { + LOGF(fatal, "Neither processRun2 nor processRun3 nor processRun3withstrangenesstracking nor processFindableRun3 enabled. Please choose one!"); } if (doprocessRun2 == true && doprocessRun3 == true) { LOGF(fatal, "Cannot enable processRun2 and processRun3 at the same time. Please choose one."); @@ -742,9 +755,11 @@ struct cascadeBuilder { /// Set magnetic field for KF vertexing KFParticle::SetField(d_bz); - if (useMatCorrType == 2) { + if (useMatCorrType == 2 && !lut) { // setMatLUT only after magfield has been initalized // (setMatLUT has implicit and problematic init field call if not) + LOG(info) << "Loading material look-up table for timestamp: " << timestamp; + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->getForTimeStamp(ccdbConfigurations.lutPath, timestamp)); o2::base::Propagator::Instance()->setMatLUT(lut); } } @@ -1116,6 +1131,14 @@ struct cascadeBuilder { cascadecandidate.v0dcapostopv = v0.dcapostopv(); cascadecandidate.v0dcanegtopv = v0.dcanegtopv(); + if (useCascadeMomentumAtPrimVtx) { + lCascadeTrack.getPxPyPzGlo(cascadecandidate.cascademom); + } else { + cascadecandidate.cascademom[0] = cascadecandidate.bachP[0] + cascadecandidate.v0mompos[0] + cascadecandidate.v0momneg[0]; + cascadecandidate.cascademom[1] = cascadecandidate.bachP[1] + cascadecandidate.v0mompos[1] + cascadecandidate.v0momneg[1]; + cascadecandidate.cascademom[2] = cascadecandidate.bachP[2] + cascadecandidate.v0mompos[2] + cascadecandidate.v0momneg[2]; + } + if (d_doTrackQA) { if (posTrack.itsNCls() < 10) statisticsRegistry.posITSclu[posTrack.itsNCls()]++; @@ -1217,8 +1240,8 @@ struct cascadeBuilder { return true; } - template - bool buildCascadeCandidateWithKF(TCascObject const& cascade) + template + bool buildCascadeCandidateWithKF(TCascObject const& cascade, TV0Object const& v0) { registry.fill(HIST("hKFParticleStatistics"), 0.0f); //*>~<*>~<*>~<*>~<*>~<*>~<*>~<*>~<*>~<* @@ -1226,11 +1249,10 @@ struct cascadeBuilder { // dispenses prior V0 generation, uses constrained (re-)fit based on bachelor charge //*>~<*>~<*>~<*>~<*>~<*>~<*>~<*>~<*>~<* - // Track casting - auto bachTrack = cascade.template bachelor_as(); - auto v0 = cascade.v0(); + // Track casting for those not provided auto posTrack = v0.template posTrack_as(); auto negTrack = v0.template negTrack_as(); + auto bachTrack = cascade.template bachelor_as(); auto const& collision = cascade.collision(); if (calculateBachBaryonVars) { @@ -1392,12 +1414,8 @@ struct cascadeBuilder { KFXi.TransportToDecayVertex(); KFOmega.TransportToDecayVertex(); - // get DCA of updated daughters at vertex - KFParticle kfpBachPionUpd = kfpBachPion; - KFParticle kfpV0Upd = kfpV0; - kfpBachPionUpd.SetProductionVertex(KFXi); - kfpV0Upd.SetProductionVertex(KFXi); - cascadecandidate.dcacascdau = kfpBachPionUpd.GetDistanceFromParticle(kfpV0Upd); + // get DCA of daughters at vertex + cascadecandidate.dcacascdau = kfpBachPion.GetDistanceFromParticle(kfpV0); if (cascadecandidate.dcacascdau > dcacascdau) return false; @@ -1522,78 +1540,99 @@ struct cascadeBuilder { return true; } - template - void buildStrangenessTables(TCascTable const& cascades) + template + void processCascadeCandidate(TV0Index const& v0index, TCascade const& cascade) { - statisticsRegistry.eventCounter++; + bool validCascadeCandidate = false; + if (v0index.has_v0Data()) { + // this V0 passed both standard V0 and cascade V0 selections + auto v0row = v0index.template v0Data_as(); + validCascadeCandidate = buildCascadeCandidate(cascade, v0row); + } else if (v0index.has_v0fCData()) { + // this V0 passes only V0-for-cascade selections, use that instead + auto v0row = v0index.template v0fCData_as(); + validCascadeCandidate = buildCascadeCandidate(cascade, v0row); + } else { + return; // this was inadequately linked, should not happen + } + if (!validCascadeCandidate) + return; // doesn't pass cascade selections + + // round the DCA variables to a certain precision if asked + if (roundDCAVariables) + roundCascadeCandidateVariables(); + + cascidx(/*cascadecandidate.v0Id, */ cascade.globalIndex(), + cascadecandidate.positiveId, cascadecandidate.negativeId, + cascadecandidate.bachelorId, cascade.collisionId()); + cascdata(cascadecandidate.charge, cascadecandidate.mXi, cascadecandidate.mOmega, + cascadecandidate.pos[0], cascadecandidate.pos[1], cascadecandidate.pos[2], + cascadecandidate.v0pos[0], cascadecandidate.v0pos[1], cascadecandidate.v0pos[2], + cascadecandidate.v0mompos[0], cascadecandidate.v0mompos[1], cascadecandidate.v0mompos[2], + cascadecandidate.v0momneg[0], cascadecandidate.v0momneg[1], cascadecandidate.v0momneg[2], + cascadecandidate.bachP[0], cascadecandidate.bachP[1], cascadecandidate.bachP[2], + cascadecandidate.cascademom[0], cascadecandidate.cascademom[1], cascadecandidate.cascademom[2], + cascadecandidate.v0dcadau, cascadecandidate.dcacascdau, + cascadecandidate.v0dcapostopv, cascadecandidate.v0dcanegtopv, + cascadecandidate.bachDCAxy, cascadecandidate.cascDCAxy, cascadecandidate.cascDCAz); // <--- no corresponding stratrack information available + if (createCascTrackXs) { + cascTrackXs(cascadecandidate.positiveX, cascadecandidate.negativeX, cascadecandidate.bachelorX); + } + cascbb(cascadecandidate.bachBaryonCosPA, cascadecandidate.bachBaryonDCAxyToPV); + if (cascadecandidate.charge < 0) { + xiMLSelections(cascadecandidate.mlXiMinusScore); + omegaMLSelections(cascadecandidate.mlOmegaMinusScore); + } else { + xiMLSelections(cascadecandidate.mlXiPlusScore); + omegaMLSelections(cascadecandidate.mlOmegaPlusScore); + } + + // populate cascade covariance matrices if required by any other task + if (createCascCovMats) { + // Calculate position covariance matrix + auto covVtxV = fitter.calcPCACovMatrix(0); + // std::array positionCovariance; + float positionCovariance[6]; + positionCovariance[0] = covVtxV(0, 0); + positionCovariance[1] = covVtxV(1, 0); + positionCovariance[2] = covVtxV(1, 1); + positionCovariance[3] = covVtxV(2, 0); + positionCovariance[4] = covVtxV(2, 1); + positionCovariance[5] = covVtxV(2, 2); + // store momentum covariance matrix + std::array covTv0 = {0.}; + std::array covTbachelor = {0.}; + float covCascade[21]; + // std::array momentumCovariance; + lV0Track.getCovXYZPxPyPzGlo(covTv0); + lBachelorTrack.getCovXYZPxPyPzGlo(covTbachelor); + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 21; i++) { + covCascade[i] = 0.0f; + } + for (int i = 0; i < 6; i++) { + covCascade[i] = positionCovariance[i]; + covCascade[MomInd[i]] = covTv0[MomInd[i]] + covTbachelor[MomInd[i]]; + } + casccovs(covCascade); + } + } + template + void buildStrangenessTables(auto const& cascades) + { + statisticsRegistry.eventCounter++; for (auto& cascade : cascades) { // de-reference from V0 pool, either specific for cascades or general // use templatizing to avoid code duplication - bool validCascadeCandidate = false; - auto v0index = cascade.template v0_as(); - if (v0index.has_v0Data()) { - // this V0 passed both standard V0 and cascade V0 selections - auto v0row = v0index.template v0Data_as(); - validCascadeCandidate = buildCascadeCandidate(cascade, v0row); - } else if (v0index.has_v0fCData()) { - // this V0 passes only V0-for-cascade selections, use that instead - auto v0row = v0index.template v0fCData_as(); - validCascadeCandidate = buildCascadeCandidate(cascade, v0row); - } else { - continue; // this was inadequately linked, should not happen - } - if (!validCascadeCandidate) - continue; // doesn't pass cascade selections - // round the DCA variables to a certain precision if asked - if (roundDCAVariables) - roundCascadeCandidateVariables(); - - cascidx(/*cascadecandidate.v0Id, */ cascade.globalIndex(), - cascadecandidate.positiveId, cascadecandidate.negativeId, - cascadecandidate.bachelorId, cascade.collisionId()); - cascdata(cascadecandidate.charge, cascadecandidate.mXi, cascadecandidate.mOmega, - cascadecandidate.pos[0], cascadecandidate.pos[1], cascadecandidate.pos[2], - cascadecandidate.v0pos[0], cascadecandidate.v0pos[1], cascadecandidate.v0pos[2], - cascadecandidate.v0mompos[0], cascadecandidate.v0mompos[1], cascadecandidate.v0mompos[2], - cascadecandidate.v0momneg[0], cascadecandidate.v0momneg[1], cascadecandidate.v0momneg[2], - cascadecandidate.bachP[0], cascadecandidate.bachP[1], cascadecandidate.bachP[2], - cascadecandidate.bachP[0] + cascadecandidate.v0mompos[0] + cascadecandidate.v0momneg[0], // <--- redundant but ok - cascadecandidate.bachP[1] + cascadecandidate.v0mompos[1] + cascadecandidate.v0momneg[1], // <--- redundant but ok - cascadecandidate.bachP[2] + cascadecandidate.v0mompos[2] + cascadecandidate.v0momneg[2], // <--- redundant but ok - cascadecandidate.v0dcadau, cascadecandidate.dcacascdau, - cascadecandidate.v0dcapostopv, cascadecandidate.v0dcanegtopv, - cascadecandidate.bachDCAxy, cascadecandidate.cascDCAxy, cascadecandidate.cascDCAz); // <--- no corresponding stratrack information available - if (createCascTrackXs) { - cascTrackXs(cascadecandidate.positiveX, cascadecandidate.negativeX, cascadecandidate.bachelorX); + if constexpr (requires { cascade.v0(); }) { + auto v0index = cascade.template v0_as(); + processCascadeCandidate(v0index, cascade); } - cascbb(cascadecandidate.bachBaryonCosPA, cascadecandidate.bachBaryonDCAxyToPV); - - // populate cascade covariance matrices if required by any other task - if (createCascCovMats) { - // Calculate position covariance matrix - auto covVtxV = fitter.calcPCACovMatrix(0); - // std::array positionCovariance; - float positionCovariance[6]; - positionCovariance[0] = covVtxV(0, 0); - positionCovariance[1] = covVtxV(1, 0); - positionCovariance[2] = covVtxV(1, 1); - positionCovariance[3] = covVtxV(2, 0); - positionCovariance[4] = covVtxV(2, 1); - positionCovariance[5] = covVtxV(2, 2); - // store momentum covariance matrix - std::array covTv0 = {0.}; - std::array covTbachelor = {0.}; - // std::array momentumCovariance; - float momentumCovariance[6]; - lV0Track.getCovXYZPxPyPzGlo(covTv0); - lBachelorTrack.getCovXYZPxPyPzGlo(covTbachelor); - constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component - for (int i = 0; i < 6; i++) { - momentumCovariance[i] = covTv0[MomInd[i]] + covTbachelor[MomInd[i]]; - } - casccovs(positionCovariance, momentumCovariance); + if constexpr (requires { cascade.findableV0(); }) { + auto v0index = cascade.template findableV0_as(); + processCascadeCandidate(v0index, cascade); } } // En masse filling at end of process call @@ -1601,11 +1640,20 @@ struct cascadeBuilder { resetHistos(); } - template - void buildKFStrangenessTables(TCascTable const& cascades) + template + void buildKFStrangenessTables(auto const& cascades) { + statisticsRegistry.eventCounter++; for (auto& cascade : cascades) { - bool validCascadeCandidateKF = buildCascadeCandidateWithKF(cascade); + bool validCascadeCandidateKF = false; + if constexpr (requires { cascade.v0(); }) { + auto v0 = cascade.template v0_as(); + validCascadeCandidateKF = buildCascadeCandidateWithKF(cascade, v0); + } + if constexpr (requires { cascade.findableV0(); }) { + auto v0 = cascade.template findableV0_as(); + validCascadeCandidateKF = buildCascadeCandidateWithKF(cascade, v0); + } if (!validCascadeCandidateKF) continue; // doesn't pass cascade selections @@ -1648,6 +1696,9 @@ struct cascadeBuilder { kfcasccovs(trackCovariance, trackCovarianceV0, trackCovariancePos, trackCovarianceNeg); } } + // En masse filling at end of process call + fillHistos(); + resetHistos(); } template @@ -1707,6 +1758,13 @@ struct cascadeBuilder { cascTrackXs(cascadecandidate.positiveX, cascadecandidate.negativeX, cascadecandidate.bachelorX); } cascbb(cascadecandidate.bachBaryonCosPA, cascadecandidate.bachBaryonDCAxyToPV); + if (cascadecandidate.charge < 0) { + xiMLSelections(cascadecandidate.mlXiMinusScore); + omegaMLSelections(cascadecandidate.mlOmegaMinusScore); + } else { + xiMLSelections(cascadecandidate.mlXiPlusScore); + omegaMLSelections(cascadecandidate.mlOmegaPlusScore); + } // populate cascade covariance matrices if required by any other task if (createCascCovMats) { @@ -1723,15 +1781,19 @@ struct cascadeBuilder { // store momentum covariance matrix std::array covTv0 = {0.}; std::array covTbachelor = {0.}; + float covCascade[21]; // std::array momentumCovariance; - float momentumCovariance[6]; lV0Track.getCovXYZPxPyPzGlo(covTv0); lBachelorTrack.getCovXYZPxPyPzGlo(covTbachelor); constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 21; i++) { + covCascade[i] = 0.0f; + } for (int i = 0; i < 6; i++) { - momentumCovariance[i] = covTv0[MomInd[i]] + covTbachelor[MomInd[i]]; + covCascade[i] = positionCovariance[i]; + covCascade[MomInd[i]] = covTv0[MomInd[i]] + covTbachelor[MomInd[i]]; } - casccovs(positionCovariance, momentumCovariance); + casccovs(covCascade); } float lPt = 0.0f; @@ -1775,7 +1837,7 @@ struct cascadeBuilder { continue; // safety (should be fine but depends on future stratrack dev) // Track casting to auto cascadeTrack = trackedCascade.template track_as(); - auto cascadeTrackPar = getTrackPar(cascadeTrack); + auto cascadeTrackPar = getTrackParCov(cascadeTrack); auto const& collision = cascade.collision(); gpu::gpustd::array dcaInfo; lCascadeTrack.setPID(o2::track::PID::XiMinus); // FIXME: not OK for omegas @@ -1855,6 +1917,19 @@ struct cascadeBuilder { cascadecandidate.v0dcapostopv, cascadecandidate.v0dcanegtopv, cascadecandidate.bachDCAxy, cascadecandidate.cascDCAxy, cascadecandidate.cascDCAz, // <--- stratrack (cascDCAxy/z) trackedCascade.matchingChi2(), trackedCascade.topologyChi2(), trackedCascade.itsClsSize()); // <--- stratrack fit info + + if (createCascCovMats) { + // create tracked cascade covariance in exactly the same way as non-tracked + // ensures getter consistency and full compatibility in template functions + // (easy switching between tracked and non-tracked) + std::array traCovMat = {0.}; + cascadeTrackPar.getCovXYZPxPyPzGlo(traCovMat); + float traCovMatArray[21]; + for (int ii = 0; ii < 21; ii++) { + traCovMatArray[ii] = traCovMat[ii]; + } + tracasccovs(traCovMatArray); + } } } // En masse filling at end of process call @@ -1890,7 +1965,21 @@ struct cascadeBuilder { } PROCESS_SWITCH(cascadeBuilder, processRun3, "Produce Run 3 cascade tables", true); - void processRun3withKFParticle(aod::Collisions const& collisions, soa::Filtered const& cascades, FullTracksExtIU const&, aod::BCsWithTimestamps const&, aod::V0s const&) + void processFindableRun3(aod::Collisions const& collisions, aod::FindableV0sLinked const&, V0full const&, soa::Filtered const& cascades, FullTracksExtIU const&, aod::BCsWithTimestamps const&) + { + for (const auto& collision : collisions) { + // Fire up CCDB + auto bc = collision.bc_as(); + initCCDB(bc); + // Do analysis with collision-grouped V0s, retain full collision information + const uint64_t collIdx = collision.globalIndex(); + auto CascadeTable_thisCollision = cascades.sliceBy(perCollisionFindable, collIdx); + buildStrangenessTables(CascadeTable_thisCollision); + } + } + PROCESS_SWITCH(cascadeBuilder, processFindableRun3, "Produce Run 3 findable cascade tables", false); + + void processRun3withKFParticle(aod::Collisions const& collisions, soa::Filtered const& cascades, FullTracksExtIU const&, aod::BCsWithTimestamps const&, aod::V0sLinked const&) { for (const auto& collision : collisions) { // Fire up CCDB @@ -1904,6 +1993,20 @@ struct cascadeBuilder { } PROCESS_SWITCH(cascadeBuilder, processRun3withKFParticle, "Produce Run 3 KF cascade tables", false); + void processFindableRun3withKFParticle(aod::Collisions const& collisions, aod::FindableV0sLinked const&, V0full const&, soa::Filtered const& cascades, FullTracksExtIU const&, aod::BCsWithTimestamps const&) + { + for (const auto& collision : collisions) { + // Fire up CCDB + auto bc = collision.bc_as(); + initCCDB(bc); + // Do analysis with collision-grouped V0s, retain full collision information + const uint64_t collIdx = collision.globalIndex(); + auto CascadeTable_thisCollision = cascades.sliceBy(perCollisionFindable, collIdx); + buildKFStrangenessTables(CascadeTable_thisCollision); + } + } + PROCESS_SWITCH(cascadeBuilder, processFindableRun3withKFParticle, "Produce Run 3 findable cascade tables with KF processing path", false); + void processRun3withStrangenessTracking(aod::Collisions const& collisions, aod::V0sLinked const&, V0full const&, V0fCfull const&, soa::Filtered const& cascades, FullTracksExtIU const&, aod::BCsWithTimestamps const&, aod::TrackedCascades const& trackedCascades) { for (const auto& collision : collisions) { @@ -1957,6 +2060,7 @@ struct cascadePreselector { bitTrueXiMinus, bitTrueXiPlus, bitTrueOmegaMinus, + bitPhysicalPrimary, bitTrueOmegaPlus, bitdEdxXiMinus, bitdEdxXiPlus, @@ -1970,6 +2074,11 @@ struct cascadePreselector { void init(InitContext const&) { + // check settings and stop if not viable + if (doprocessBuildAll == false && doprocessBuildMCAssociated == false && doprocessBuildValiddEdx == false && doprocessBuildValiddEdxMCAssociated == false && doprocessBuildFindable == false) { + LOGF(fatal, "No processBuild function enabled. Please choose one."); + } + auto h = histos.add("hPreselectorStatistics", "hPreselectorStatistics", kTH1D, {{5, -0.5f, 4.5f}}); h->GetXaxis()->SetBinLabel(1, "All"); h->GetXaxis()->SetBinLabel(2, "Tracks OK"); @@ -2015,11 +2124,9 @@ struct cascadePreselector { //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* /// function to check track quality - template - void checkTrackQuality(TCascadeObject const& lCascadeCandidate, uint16_t& maskElement, bool passdEdx = false) + template + void checkTrackQuality(TCascadeObject const& lCascadeCandidate, TV0Type const& v0, uint16_t& maskElement, bool passdEdx = false) { - auto v0 = lCascadeCandidate.template v0_as(); - // Acquire all three daughter tracks, please auto lBachTrack = lCascadeCandidate.template bachelor_as(); auto lNegTrack = v0.template negTrack_as(); @@ -2053,6 +2160,7 @@ struct cascadePreselector { void checkPDG(TCascadeObject const& lCascadeCandidate, uint16_t& maskElement) { int lPDG = -1; + bool physicalPrimary = false; // Acquire all three daughter tracks, please auto lBachTrack = lCascadeCandidate.template bachelor_as(); @@ -2078,6 +2186,7 @@ struct cascadePreselector { for (auto& lBachMother : lMCBachTrack.template mothers_as()) { if (lV0Mother == lBachMother) { lPDG = lV0Mother.pdgCode(); + physicalPrimary = lV0Mother.isPhysicalPrimary(); // additionally check PDG of the mother particle if requested if (dIfMCselectV0MotherPDG != 0) { @@ -2107,6 +2216,8 @@ struct cascadePreselector { bitset(maskElement, bitTrueOmegaMinus); if (lPDG == -3334) bitset(maskElement, bitTrueOmegaPlus); + if (physicalPrimary) + bitset(maskElement, bitPhysicalPrimary); } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* /// function to check early dE/dx selection @@ -2157,7 +2268,7 @@ struct cascadePreselector { void checkAndFinalize() { // parse + publish tag table now - for (int ii = 0; ii < selectionMask.size(); ii++) { + for (std::size_t ii = 0; ii < selectionMask.size(); ii++) { histos.fill(HIST("hPreselectorStatistics"), 0.0f); // All cascades bool validCascade = bitcheck(selectionMask[ii], bitTrackQuality); if (validCascade) { @@ -2187,6 +2298,7 @@ struct cascadePreselector { casctags(validCascade, bitcheck(selectionMask[ii], bitTrueXiMinus), bitcheck(selectionMask[ii], bitTrueXiPlus), bitcheck(selectionMask[ii], bitTrueOmegaMinus), bitcheck(selectionMask[ii], bitTrueOmegaPlus), + bitcheck(selectionMask[ii], bitPhysicalPrimary), bitcheck(selectionMask[ii], bitdEdxXiMinus), bitcheck(selectionMask[ii], bitdEdxXiPlus), bitcheck(selectionMask[ii], bitdEdxOmegaMinus), bitcheck(selectionMask[ii], bitdEdxOmegaPlus)); } @@ -2194,50 +2306,66 @@ struct cascadePreselector { } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* /// This process function ensures that all cascades are built. It will simply tag everything as true. - void processBuildAll(aod::Cascades const& cascades, aod::V0s const&, aod::V0Datas const&, aod::TracksExtra const&) + void processBuildAll(aod::Cascades const& cascades, aod::V0s const&, aod::TracksExtra const&) { initializeMasks(cascades.size()); for (auto& casc : cascades) { - checkTrackQuality(casc, selectionMask[casc.globalIndex()], true); + auto v0 = casc.v0(); + checkTrackQuality(casc, v0, selectionMask[casc.globalIndex()], true); } if (!doprocessSkipCascadesNotUsedInTrackedCascades) checkAndFinalize(); } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - void processBuildMCAssociated(aod::Collisions const& /*collisions*/, aod::Cascades const& cascades, aod::V0s const&, aod::V0Datas const& /*v0table*/, LabeledTracksExtra const&, aod::McParticles const&) + void processBuildMCAssociated(aod::Collisions const& /*collisions*/, aod::Cascades const& cascades, aod::V0s const&, LabeledTracksExtra const&, aod::McParticles const&) { initializeMasks(cascades.size()); for (auto& casc : cascades) { checkPDG(casc, selectionMask[casc.globalIndex()]); - checkTrackQuality(casc, selectionMask[casc.globalIndex()], true); + auto v0 = casc.v0(); + checkTrackQuality(casc, v0, selectionMask[casc.globalIndex()], true); } // end cascades loop if (!doprocessSkipCascadesNotUsedInTrackedCascades) checkAndFinalize(); } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - void processBuildValiddEdx(aod::Collisions const& /*collisions*/, aod::Cascades const& cascades, aod::V0s const&, aod::V0Datas const&, TracksExtraWithPID const&) + void processBuildValiddEdx(aod::Collisions const& /*collisions*/, aod::Cascades const& cascades, aod::V0s const&, TracksExtraWithPID const&) { initializeMasks(cascades.size()); for (auto& casc : cascades) { checkdEdx(casc, selectionMask[casc.globalIndex()]); - checkTrackQuality(casc, selectionMask[casc.globalIndex()]); + auto v0 = casc.v0(); + checkTrackQuality(casc, v0, selectionMask[casc.globalIndex()]); } if (!doprocessSkipCascadesNotUsedInTrackedCascades) checkAndFinalize(); } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - void processBuildValiddEdxMCAssociated(aod::Collisions const& /*collisions*/, aod::Cascades const& cascades, aod::V0s const&, aod::V0Datas const&, TracksExtraWithPIDandLabels const&, aod::McParticles const&) + void processBuildValiddEdxMCAssociated(aod::Collisions const& /*collisions*/, aod::Cascades const& cascades, aod::V0s const&, TracksExtraWithPIDandLabels const&, aod::McParticles const&) { initializeMasks(cascades.size()); for (auto& casc : cascades) { checkPDG(casc, selectionMask[casc.globalIndex()]); checkdEdx(casc, selectionMask[casc.globalIndex()]); - checkTrackQuality(casc, selectionMask[casc.globalIndex()]); + auto v0 = casc.v0(); + checkTrackQuality(casc, v0, selectionMask[casc.globalIndex()]); } if (!doprocessSkipCascadesNotUsedInTrackedCascades) checkAndFinalize(); } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + /// This process function ensures that all findable cascades are built. + /// Not to be used with processSkip. + void processBuildFindable(aod::FindableCascades const& cascades, aod::FindableV0s const&, aod::TracksExtra const&) + { + initializeMasks(cascades.size()); + for (auto& casc : cascades) { + auto v0 = casc.findableV0(); + checkTrackQuality(casc, v0, selectionMask[casc.globalIndex()], true); + } + checkAndFinalize(); + } + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* /// This process function checks for the use of Cascades in strangeness tracked cascades /// They are then marked appropriately; the user could then operate /// the cascadebuilder to construct only those Cascades. @@ -2254,6 +2382,7 @@ struct cascadePreselector { PROCESS_SWITCH(cascadePreselector, processBuildMCAssociated, "Switch to build MC-associated cascades", false); PROCESS_SWITCH(cascadePreselector, processBuildValiddEdx, "Switch to build cascades with dE/dx preselection", false); PROCESS_SWITCH(cascadePreselector, processBuildValiddEdxMCAssociated, "Switch to build MC-associated cascades with dE/dx preselection", false); + PROCESS_SWITCH(cascadePreselector, processBuildFindable, "Switch to build all findable cascades", false); /// skipper option (choose in addition to a processBuild if you like) PROCESS_SWITCH(cascadePreselector, processSkipCascadesNotUsedInTrackedCascades, "Switch to skip cascades not used in cascade tracking", false); //*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<* @@ -2261,9 +2390,9 @@ struct cascadePreselector { /// Extends the cascdata table with expression columns struct cascadeInitializer { - Spawns cascdataext; - Spawns kfcascdataext; - Spawns tracascdataext; + Spawns cascdataext; + Spawns kfcascdataext; + Spawns tracascdataext; void init(InitContext const&) {} }; @@ -2273,7 +2402,7 @@ struct cascadeLinkBuilder { void init(InitContext const&) {} // build Cascade -> CascData link table - void process(aod::Cascades const& casctable, aod::CascDatas const& cascdatatable) + void processFound(aod::Cascades const& casctable, aod::CascDatas const& cascdatatable) { std::vector lIndices; lIndices.reserve(casctable.size()); @@ -2286,6 +2415,24 @@ struct cascadeLinkBuilder { cascdataLink(lIndices[ii]); } } + + // build Cascade -> CascData link table + void processFindable(aod::FindableCascades const& casctable, aod::CascDatas const& cascdatatable) + { + std::vector lIndices; + lIndices.reserve(casctable.size()); + for (int ii = 0; ii < casctable.size(); ii++) + lIndices[ii] = -1; + for (auto& cascdata : cascdatatable) { + lIndices[cascdata.cascadeId()] = cascdata.globalIndex(); + } + for (int ii = 0; ii < casctable.size(); ii++) { + cascdataLink(lIndices[ii]); + } + } + + PROCESS_SWITCH(cascadeLinkBuilder, processFound, "process found Cascades (default)", true); + PROCESS_SWITCH(cascadeLinkBuilder, processFindable, "process findable Cascades", false); }; struct kfcascadeLinkBuilder { diff --git a/PWGLF/TableProducer/Strangeness/cascadefinder.cxx b/PWGLF/TableProducer/Strangeness/cascadefinder.cxx index ae4cc41802a..a56b02666a1 100644 --- a/PWGLF/TableProducer/Strangeness/cascadefinder.cxx +++ b/PWGLF/TableProducer/Strangeness/cascadefinder.cxx @@ -432,7 +432,7 @@ struct cascadefinderQA { /// Extends the cascdata table with expression columns struct cascadeinitializer { - Spawns cascdataext; + Spawns cascdataext; void init(InitContext const&) {} }; diff --git a/PWGLF/TableProducer/Strangeness/cascadeflow.cxx b/PWGLF/TableProducer/Strangeness/cascadeflow.cxx index 77330c858c7..c66a1db16fd 100644 --- a/PWGLF/TableProducer/Strangeness/cascadeflow.cxx +++ b/PWGLF/TableProducer/Strangeness/cascadeflow.cxx @@ -12,6 +12,9 @@ /// \brief Task to create derived data for cascade flow analyses /// \authors: Chiara De Martin (chiara.de.martin@cern.ch), Maximiliano Puccio (maximiliano.puccio@cern.ch) +#include +#include +#include #include "Math/Vector3D.h" #include "TRandom3.h" #include "Common/DataModel/Centrality.h" @@ -27,6 +30,7 @@ #include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGLF/DataModel/LFStrangenessPIDTables.h" #include "Tools/ML/MlResponse.h" +#include "CCDB/BasicCCDBManager.h" using namespace o2; using namespace o2::framework; @@ -35,7 +39,12 @@ using namespace o2::framework::expressions; using std::array; using DauTracks = soa::Join; -using CollEventPlane = soa::Join::iterator; +using CollEventPlane = soa::Join::iterator; +using CollEventAndSpecPlane = soa::Join::iterator; +using CollEventPlaneCentralFW = soa::Join::iterator; +using MCCollisionsStra = soa::Join; +using CascCandidates = soa::Join; +using CascMCCandidates = soa::Join; namespace cascadev2 { @@ -48,6 +57,9 @@ constexpr double massSigmaParameters[4][2]{ {1.03468e-1, 0.1898}}; static const std::vector massSigmaParameterNames{"p0", "p1", "p2", "p3"}; static const std::vector speciesNames{"Xi", "Omega"}; +const double AlphaXi[2] = {-0.390, 0.371}; // decay parameter of XiMinus and XiPlus +const double AlphaOmega[2] = {0.0154, -0.018}; // decay parameter of OmegaMinus and OmegaPlus +const double AlphaLambda[2] = {0.747, -0.757}; // decay parameter of Lambda and AntiLambda std::shared_ptr hMassBeforeSelVsPt[2]; std::shared_ptr hMassAfterSelVsPt[2]; @@ -55,7 +67,7 @@ std::shared_ptr hSignalScoreBeforeSel[2]; std::shared_ptr hBkgScoreBeforeSel[2]; std::shared_ptr hSignalScoreAfterSel[2]; std::shared_ptr hBkgScoreAfterSel[2]; -std::shared_ptr hSparseV2C[2]; +std::shared_ptr hSparseV2C[2]; } // namespace cascadev2 namespace cascade_flow_cuts_ml @@ -117,8 +129,78 @@ static const std::vector labelsCutScore = {"Background score", "Sig struct cascadeFlow { - Configurable MinPt{"MinPt", 0.6, "Min pt of cascade"}; - Configurable MaxPt{"MaxPt", 10, "Max pt of cascade"}; + // Output filling criteria + struct : ConfigurableGroup { + Configurable isFillTree{"isFillTree", 1, ""}; + Configurable isFillTHNXi{"isFillTHNXi", 1, ""}; + Configurable isFillTHNXi_PzVsPsi{"isFillTHNXi_PzVsPsi", 1, ""}; + Configurable isFillTHNOmega{"isFillTHNOmega", 1, ""}; + Configurable isFillTHNOmega_PzVsPsi{"isFillTHNOmega_PzVsPsi", 1, ""}; + Configurable isFillTHN_V2{"isFillTHN_V2", 1, ""}; + Configurable isFillTHN_Pz{"isFillTHN_Pz", 1, ""}; + Configurable isFillTHN_PzFromLambda{"isFillTHN_PzFromLambda", 1, ""}; + Configurable isFillTHN_Acc{"isFillTHN_Acc", 1, ""}; + Configurable isFillTHN_AccFromLambdaVsCasc{"isFillTHN_AccFromLambdaVsCasc", 1, ""}; + Configurable isFillTHN_AccFromLambdaVsLambda{"isFillTHN_AccFromLambdaVsLambda", 1, ""}; + } fillingConfigs; + + // axes + ConfigurableAxis axisQVs{"axisQVs", {500, -10.f, 10.f}, "axisQVs"}; + ConfigurableAxis axisQVsNorm{"axisQVsNorm", {200, -1.f, 1.f}, "axisQVsNorm"}; + + // THN axes + ConfigurableAxis thnConfigAxisFT0C{"thnConfigAxisFT0C", {8, 0, 80}, "FT0C centrality (%)"}; + ConfigurableAxis thnConfigAxisEta{"thnConfigAxisEta", {8, -0.8, 0.8}, "pseudorapidity"}; + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {VARIABLE_WIDTH, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2, 2.25, 2.5, 2.75, 3, 3.5, 4, 5, 6, 8, 10}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis thnConfigAxisPtLambda{"thnConfigAxisPtLambda", {VARIABLE_WIDTH, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2, 2.25, 2.5, 2.75, 3, 3.5, 4, 5, 6, 8, 10, 20}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis thnConfigAxisCharge{"thnConfigAxisCharge", {2, 0, 2}, ""}; + ConfigurableAxis thnConfigAxisPsiDiff{"thnConfigAxisPsiDiff", {100, 0, 2 * TMath::Pi()}, ""}; + ConfigurableAxis thnConfigAxisMassXi{"thnConfigAxisMassXi", {45, 1.300, 1.345}, ""}; + ConfigurableAxis thnConfigAxisMassOmega{"thnConfigAxisMassOmega", {45, 1.655, 1.690}, ""}; + ConfigurableAxis thnConfigAxisMassLambda{"thnConfigAxisMassLambda", {60, 1.1, 1.13}, ""}; + ConfigurableAxis thnConfigAxisBDTScore{"thnConfigAxisBDTScore", {15, 0.4, 1}, ""}; + ConfigurableAxis thnConfigAxisV2{"thnConfigAxiV2", {100, -1., 1.}, ""}; + ConfigurableAxis thnConfigAxisPzs2Xi{"thnConfigAxiPzs2Xi", {200, -2.8, 2.8}, ""}; + ConfigurableAxis thnConfigAxisPzs2Omega{"thnConfigAxiPzs2Omega", {200, -70, 70}, ""}; + ConfigurableAxis thnConfigAxisPzs2Lambda{"thnConfigAxiPzs2Lambda", {200, -2, 2}, ""}; + ConfigurableAxis thnConfigAxisCos2Theta{"thnConfigAxiCos2Theta", {100, 0, 1}, ""}; + ConfigurableAxis thnConfigAxisCos2ThetaL{"thnConfigAxiCos2ThetaL", {100, 0, 1}, ""}; + ConfigurableAxis thnConfigAxisCosThetaXiAlpha{"thnConfigAxisCosThetaXiAlpha", {200, -2.8, 2.8}, ""}; + ConfigurableAxis thnConfigAxisCosThetaOmegaAlpha{"thnConfigAxisCosThetaOmegaAlpha", {200, -70, 70}, ""}; + ConfigurableAxis thnConfigAxisCosThetaProtonAlpha{"thnConfigAxisCosThetaProtonAlpha", {200, -2, 2}, ""}; + + // Event selection criteria + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable sel8{"sel8", 1, "Apply sel8 event selection"}; + Configurable isNoSameBunchPileupCut{"isNoSameBunchPileupCut", 1, "Same found-by-T0 bunch crossing rejection"}; + Configurable isGoodZvtxFT0vsPVCut{"isGoodZvtxFT0vsPVCut", 1, "z of PV by tracks and z of PV from FT0 A-C time difference cut"}; + Configurable isGoodEventEP{"isGoodEventEP", 1, "Event is used to calibrate event plane"}; + Configurable isTrackOccupancySel{"isTrackOccupancySel", 0, "isTrackOccupancySel"}; + Configurable MinOccupancy{"MinOccupancy", 0, "MinOccupancy"}; + Configurable MaxOccupancy{"MaxOccupancy", 500, "MaxOccupancy"}; + Configurable isFT0OccupancySel{"isFT0OccupancySel", 0, "isFT0OccupancySel"}; + Configurable MinOccupancyFT0{"MinOccupancyFT0", 0, "MinOccupancyFT0"}; + Configurable MaxOccupancyFT0{"MaxOccupancyFT0", 5000, "MaxOccupancyFT0"}; + Configurable isNoCollInStandardTimeRange{"isNoCollInStandardTimeRange", 1, "To remove collisions in +-10 micros time range"}; + Configurable isNoCollInNarrowTimeRange{"isNoCollInNarrowTimeRange", 0, "To remove collisions in +-2 micros time range"}; + Configurable isNoCollInRofStandard{"isNoCollInRofStandard", 0, "To remove collisions in the same ITS ROF and with a multiplicity above a certain threshold"}; + Configurable isNoTVXinTRD{"isNoTVXinTRD", 0, "To remove collisions with trigger in TRD"}; + + struct : ConfigurableGroup { + Configurable MinPt{"MinPt", 0.6, "Min pt of cascade"}; + Configurable MaxPt{"MaxPt", 10, "Max pt of cascade"}; + Configurable MinPtLambda{"MinPtLambda", 0.4, "Min pt of daughter lambda"}; + Configurable MaxPtLambda{"MaxPtLambda", 10, "Max pt of daughter lambda"}; + Configurable etaCasc{"etaCasc", 0.8, "etaCasc"}; + Configurable etaLambdaMax{"etaLambdaMax", 0.8, "etaLambdaMax"}; + Configurable MinLambdaMass{"MinLambdaMass", 1.1, ""}; + Configurable MaxLambdaMass{"MaxLambdaMass", 1.13, ""}; + Configurable MinXiMass{"MinXiMass", 1.300, ""}; + Configurable MaxXiMass{"MaxXiMass", 1.345, ""}; + Configurable MinOmegaMass{"MinOmegaMass", 1.655, ""}; + Configurable MaxOmegaMass{"MaxOmegaMass", 1.690, ""}; + } CandidateConfigs; + Configurable sideBandStart{"sideBandStart", 5, "Start of the sideband region in number of sigmas"}; Configurable sideBandEnd{"sideBandEnd", 7, "End of the sideband region in number of sigmas"}; Configurable downsample{"downsample", 1., "Downsample training output tree"}; @@ -127,6 +209,10 @@ struct cascadeFlow { Configurable nsigmatpcPi{"nsigmatpcPi", 5, "nsigmatpcPi"}; Configurable mintpccrrows{"mintpccrrows", 70, "mintpccrrows"}; + Configurable isStoreTrueCascOnly{"isStoreTrueCascOnly", 1, ""}; + Configurable etaCascMCGen{"etaCascMCGen", 0.8, "etaCascMCGen"}; + Configurable yCascMCGen{"yCascMCGen", 0.5, "yCascMCGen"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable> modelPathsCCDBXi{"modelPathsCCDBXi", std::vector{"Users/c/chdemart/CascadesFlow"}, "Paths of models on CCDB"}; Configurable> modelPathsCCDBOmega{"modelPathsCCDBOmega", std::vector{"Users/c/chdemart/CascadesFlow"}, "Paths of models on CCDB"}; @@ -134,20 +220,117 @@ struct cascadeFlow { Configurable> onnxFileNamesOmega{"onnxFileNamesOmega", std::vector{"model_onnx.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; Configurable loadModelsFromCCDB{"loadModelsFromCCDB", true, "Flag to enable or disable the loading of models from CCDB"}; + Configurable acceptancePathsCCDBXi{"acceptancePathsCCDBXi", "Users/c/chdemart/AcceptanceXi", "Paths of Xi acceptance on CCDB"}; + Configurable acceptancePathsCCDBOmega{"acceptancePathsCCDBOmega", "Users/c/chdemart/AcceptanceOmega", "Paths of Omega acceptance on CCDB"}; + Configurable acceptancePathsCCDBLambda{"acceptancePathsCCDBLambda", "Users/c/chdemart/AcceptanceLambda", "Paths of Lambda acceptance on CCDB"}; + Configurable acceptanceHistoNameCasc{"acceptanceHistoNameCasc", "histoCos2ThetaNoFit2D", "Histo name of acceptance on CCDB"}; + Configurable acceptanceHistoNameLambda{"acceptanceHistoNameLambda", "histoCos2ThetaLambdaFromCNoFit2D", "Histo name of acceptance on CCDB"}; // ML inference Configurable isApplyML{"isApplyML", 1, "Flag to apply ML selections"}; Configurable> binsPtMl{"binsPtMl", std::vector{cascade_flow_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; Configurable> cutDirMl{"cutDirMl", std::vector{cascade_flow_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; Configurable> cutsMl{"cutsMl", {cascade_flow_cuts_ml::cuts[0], cascade_flow_cuts_ml::nBinsPt, cascade_flow_cuts_ml::nCutScores, cascade_flow_cuts_ml::labelsPt, cascade_flow_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; - Configurable nClassesMl{"nClassesMl", (int8_t)cascade_flow_cuts_ml::nCutScores, "Number of classes in ML model"}; + Configurable nClassesMl{"nClassesMl", static_cast(cascade_flow_cuts_ml::nCutScores), "Number of classes in ML model"}; + + // acceptance crrection + Configurable applyAcceptanceCorrection{"applyAcceptanceCorrection", false, "apply acceptance correction"}; o2::ccdb::CcdbApi ccdbApi; + Service ccdb; // Add objects needed for ML inference o2::analysis::MlResponse mlResponseXi; o2::analysis::MlResponse mlResponseOmega; + template + bool AcceptEvent(TCollision const& collision, bool isFillHisto) + { + if (isFillHisto) { + histos.fill(HIST("hNEvents"), 0.5); + histos.fill(HIST("hEventNchCorrelationBefCuts"), collision.multNTracksPVeta1(), collision.multNTracksGlobal()); + histos.fill(HIST("hEventPVcontributorsVsCentralityBefCuts"), collision.centFT0C(), collision.multNTracksPVeta1()); + histos.fill(HIST("hEventGlobalTracksVsCentralityBefCuts"), collision.centFT0C(), collision.multNTracksGlobal()); + } + + // Event selection if required + if (sel8 && !collision.sel8()) { + return false; + } + if (isFillHisto) + histos.fill(HIST("hNEvents"), 1.5); + + // Z vertex selection + if (TMath::Abs(collision.posZ()) > cutzvertex) { + return false; + } + if (isFillHisto) + histos.fill(HIST("hNEvents"), 2.5); + + // kNoSameBunchPileup selection + if (isNoSameBunchPileupCut && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (isFillHisto) + histos.fill(HIST("hNEvents"), 3.5); + + // kIsGoodZvtxFT0vsPV selection + if (isGoodZvtxFT0vsPVCut && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (isFillHisto) + histos.fill(HIST("hNEvents"), 4.5); + + // occupancy cut + int occupancy = collision.trackOccupancyInTimeRange(); + if (isTrackOccupancySel && (occupancy < MinOccupancy || occupancy > MaxOccupancy)) { + return false; + } + // occupancy cut based on FT0C + int occupancyFT0 = collision.ft0cOccupancyInTimeRange(); + if (isFT0OccupancySel && (occupancyFT0 < MinOccupancyFT0 || occupancyFT0 > MaxOccupancyFT0)) { + return false; + } + + if (isFillHisto) + histos.fill(HIST("hNEvents"), 5.5); + + // time-based event selection + if (isNoCollInStandardTimeRange && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if (isNoCollInNarrowTimeRange && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + + if (isFillHisto) + histos.fill(HIST("hNEvents"), 6.5); + + // In-ROF event selection + if (isNoCollInRofStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + + if (isFillHisto) + histos.fill(HIST("hNEvents"), 7.5); + + // TVX in TRD + // if (isNoTVXinTRD && collision.alias_bit(kTVXinTRD)){ + // return false; + // } + + if (isFillHisto) + histos.fill(HIST("hNEvents"), 8.5); + + if (isFillHisto) { + histos.fill(HIST("hEventNchCorrelation"), collision.multNTracksPVeta1(), collision.multNTracksGlobal()); + histos.fill(HIST("hEventPVcontributorsVsCentrality"), collision.centFT0C(), collision.multNTracksPVeta1()); + histos.fill(HIST("hEventGlobalTracksVsCentrality"), collision.centFT0C(), collision.multNTracksGlobal()); + } + + return true; + } + template bool IsCascAccepted(TCascade casc, TDaughter negExtra, TDaughter posExtra, TDaughter bachExtra, int& counter) // loose cuts on topological selections of cascades { @@ -181,7 +364,14 @@ struct cascadeFlow { return phi; } - HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + // objects to use for acceptance correction + TH2F* hAcceptanceXi; + TH2F* hAcceptanceOmega; + TH2F* hAcceptanceLambda; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry histosMCGen{"histosMCGen", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry resolution{"resolution", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; // Tables to produce Produces trainingSample; @@ -224,18 +414,93 @@ struct cascadeFlow { } template - // void fillAnalisedTable(collision_t coll, cascade_t casc, float BDTresponse) - void fillAnalysedTable(collision_t coll, cascade_t casc, float v2C, float BDTresponseXi, float BDTresponseOmega) + void fillAnalysedTable(collision_t coll, bool hasEventPlane, bool hasSpectatorPlane, cascade_t casc, float v2CSP, float v2CEP, float v1SP_ZDCA, float v1SP_ZDCC, float PsiT0C, float BDTresponseXi, float BDTresponseOmega, int pdgCode) { + double masses[2]{o2::constants::physics::MassXiMinus, o2::constants::physics::MassOmegaMinus}; + ROOT::Math::PxPyPzMVector cascadeVector[2], lambdaVector, protonVector; + float cosThetaStarLambda[2], cosThetaStarProton; + lambdaVector.SetCoordinates(casc.pxlambda(), casc.pylambda(), casc.pzlambda(), o2::constants::physics::MassLambda); + ROOT::Math::Boost lambdaBoost{lambdaVector.BoostToCM()}; + if (casc.sign() > 0) { + protonVector.SetCoordinates(casc.pxneg(), casc.pyneg(), casc.pzneg(), o2::constants::physics::MassProton); + } else { + protonVector.SetCoordinates(casc.pxpos(), casc.pypos(), casc.pzpos(), o2::constants::physics::MassProton); + } + auto boostedProton{lambdaBoost(protonVector)}; + cosThetaStarProton = boostedProton.Pz() / boostedProton.P(); + for (int i{0}; i < 2; ++i) { + cascadeVector[i].SetCoordinates(casc.px(), casc.py(), casc.pz(), masses[i]); + ROOT::Math::Boost cascadeBoost{cascadeVector[i].BoostToCM()}; + auto boostedLambda{cascadeBoost(lambdaVector)}; + cosThetaStarLambda[i] = boostedLambda.Pz() / boostedLambda.P(); + } + + // time-based event selection + bool isNoCollInTimeRangeStd = 0; + if (coll.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) + isNoCollInTimeRangeStd = 1; + + // IN-ROF pile-up rejection + bool isNoCollInRofStd = 0; + if (coll.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) + isNoCollInRofStd = 1; + + // TVX in TRD + // bool isTVXinTRD = 0; + // if (coll.alias_bit(kTVXinTRD)) isTVXinTRD = 1; + analysisSample(coll.centFT0C(), + isNoCollInTimeRangeStd, + isNoCollInRofStd, + hasEventPlane, + hasSpectatorPlane, casc.sign(), casc.pt(), casc.eta(), + casc.phi(), + casc.mLambda(), casc.mXi(), casc.mOmega(), - v2C, + v2CSP, + v2CEP, + v1SP_ZDCA, + v1SP_ZDCC, + PsiT0C, BDTresponseXi, - BDTresponseOmega); + BDTresponseOmega, + cosThetaStarLambda[0], + cosThetaStarLambda[1], + cosThetaStarProton, + pdgCode); + } + void initAcceptanceFromCCDB() + { + LOG(info) << "Loading acceptance from CCDB "; + TList* listAcceptanceXi = ccdb->get(acceptancePathsCCDBXi); + if (!listAcceptanceXi) + LOG(fatal) << "Problem getting TList object with acceptance for Xi!"; + TList* listAcceptanceOmega = ccdb->get(acceptancePathsCCDBOmega); + if (!listAcceptanceOmega) + LOG(fatal) << "Problem getting TList object with acceptance for Omega!"; + TList* listAcceptanceLambda = ccdb->get(acceptancePathsCCDBLambda); + if (!listAcceptanceLambda) + LOG(fatal) << "Problem getting TList object with acceptance for Lambda!"; + hAcceptanceXi = static_cast(listAcceptanceXi->FindObject(Form("%s", acceptanceHistoNameCasc->data()))); + if (!hAcceptanceXi) { + LOG(fatal) << "The histogram for Xi is not there!"; + } + hAcceptanceXi->SetName("hAcceptanceXi"); + hAcceptanceOmega = static_cast(listAcceptanceOmega->FindObject(Form("%s", acceptanceHistoNameCasc->data()))); + if (!hAcceptanceOmega) { + LOG(fatal) << "The histogram for omega is not there!"; + } + hAcceptanceOmega->SetName("hAcceptanceOmega"); + hAcceptanceLambda = static_cast(listAcceptanceLambda->FindObject(Form("%s", acceptanceHistoNameLambda->data()))); + if (!hAcceptanceLambda) { + LOG(fatal) << "The histogram for Lambda is not there!"; + } + hAcceptanceLambda->SetName("hAcceptanceLambda"); + LOG(info) << "Acceptance now loaded"; } void init(InitContext const&) @@ -245,18 +510,149 @@ struct cascadeFlow { float maxMass[2]{1.36, 1.73}; const AxisSpec massCascAxis[2]{{static_cast((maxMass[0] - minMass[0]) / 0.001f), minMass[0], maxMass[0], "#Xi candidate mass (GeV/c^{2})"}, {static_cast((maxMass[1] - minMass[1]) / 0.001f), minMass[1], maxMass[1], "#Omega candidate mass (GeV/c^{2})"}}; - const AxisSpec ptAxis{static_cast((MaxPt - MinPt) / 0.2), MinPt, MaxPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec ptAxis{static_cast((CandidateConfigs.MaxPt - CandidateConfigs.MinPt) / 0.2), CandidateConfigs.MinPt, CandidateConfigs.MaxPt, "#it{p}_{T} (GeV/#it{c})"}; const AxisSpec v2Axis{200, -1., 1., "#it{v}_{2}"}; const AxisSpec CentAxis{18, 0., 90., "FT0C centrality percentile"}; + TString hNEventsLabels[10] = {"All", "sel8", "z vrtx", "kNoSameBunchPileup", "kIsGoodZvtxFT0vsPV", "trackOccupancyInTimeRange", "kNoCollInTimeRange", "kNoCollInROF", "kTVXinTRD", "kIsGoodEventEP"}; + TString hNEventsLabelsMC[6] = {"All", "z vtx", ">=1RecoColl", "1Reco", "2Reco", "EvSelected"}; + TString hNCascLabelsMC[8] = {"All Xi", "all Omega", "Xi: has MC coll", "Om: has MC coll", "Xi: isPrimary", "Om: is Primary", "Xi: |eta|<0.8", "Om: |eta| < 0.8"}; + + resolution.add("QVectorsT0CTPCA", "QVectorsT0CTPCA", HistType::kTH2F, {axisQVs, CentAxis}); + resolution.add("QVectorsT0CTPCC", "QVectorsT0CTPCC", HistType::kTH2F, {axisQVs, CentAxis}); + resolution.add("QVectorsTPCAC", "QVectorsTPCAC", HistType::kTH2F, {axisQVs, CentAxis}); + resolution.add("QVectorsNormT0CTPCA", "QVectorsNormT0CTPCA", HistType::kTH2F, {axisQVsNorm, CentAxis}); + resolution.add("QVectorsNormT0CTPCC", "QVectorsNormT0CTPCC", HistType::kTH2F, {axisQVsNorm, CentAxis}); + resolution.add("QVectorsNormTPCAC", "QVectorsNormTPCCB", HistType::kTH2F, {axisQVsNorm, CentAxis}); + resolution.add("QVectorsSpecPlane", "QVectorsSpecPlane", HistType::kTH2F, {axisQVsNorm, CentAxis}); + + histos.add("hNEvents", "hNEvents", {HistType::kTH1F, {{10, 0.f, 10.f}}}); + for (Int_t n = 1; n <= histos.get(HIST("hNEvents"))->GetNbinsX(); n++) { + histos.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(n, hNEventsLabels[n - 1]); + } histos.add("hEventVertexZ", "hEventVertexZ", kTH1F, {{120, -12., 12.}}); histos.add("hEventCentrality", "hEventCentrality", kTH1F, {{101, 0, 101}}); - histos.add("hPsiT0C", "hPsiT0C", HistType::kTH1D, {{100, 0, 2 * TMath::Pi()}}); + histos.add("hPsiT0C", "hPsiT0C", HistType::kTH1D, {{100, -TMath::Pi(), TMath::Pi()}}); + histos.add("hPsiT0CvsCentFT0C", "hPsiT0CvsCentFT0C", HistType::kTH2D, {CentAxis, {100, -TMath::Pi(), TMath::Pi()}}); + histos.add("hPsiZDCA_vs_ZDCC", "hPsiZDCA_vs_ZDCC", HistType::kTH2D, {{100, -TMath::Pi(), TMath::Pi()}, {100, -TMath::Pi(), TMath::Pi()}}); + histos.add("hEventNchCorrelation", "hEventNchCorrelation", kTH2F, {{5000, 0, 5000}, {5000, 0, 2500}}); + histos.add("hEventPVcontributorsVsCentrality", "hEventPVcontributorsVsCentrality", kTH2F, {{100, 0, 100}, {5000, 0, 5000}}); + histos.add("hEventGlobalTracksVsCentrality", "hEventGlobalTracksVsCentrality", kTH2F, {{100, 0, 100}, {2500, 0, 2500}}); + histos.add("hEventNchCorrelationBefCuts", "hEventNchCorrelationBefCuts", kTH2F, {{5000, 0, 5000}, {2500, 0, 2500}}); + histos.add("hEventPVcontributorsVsCentralityBefCuts", "hEventPVcontributorsVsCentralityBefCuts", kTH2F, {{100, 0, 100}, {5000, 0, 5000}}); + histos.add("hEventGlobalTracksVsCentralityBefCuts", "hEventGlobalTracksVsCentralityBefCuts", kTH2F, {{100, 0, 100}, {2500, 0, 2500}}); + histos.add("hEventNchCorrelationAfterEP", "hEventNchCorrelationAfterEP", kTH2F, {{5000, 0, 5000}, {2500, 0, 2500}}); + histos.add("hEventPVcontributorsVsCentralityAfterEP", "hEventPVcontributorsVsCentralityAfterEP", kTH2F, {{100, 0, 100}, {5000, 0, 5000}}); + histos.add("hEventGlobalTracksVsCentralityAfterEP", "hEventGlobalTracksVsCentralityAfterEP", kTH2F, {{100, 0, 100}, {2500, 0, 2500}}); + histos.add("hMultNTracksITSTPCVsCentrality", "hMultNTracksITSTPCVsCentrality", kTH2F, {{100, 0, 100}, {1000, 0, 5000}}); histos.add("hCandidate", "hCandidate", HistType::kTH1F, {{22, -0.5, 21.5}}); histos.add("hCascadeSignal", "hCascadeSignal", HistType::kTH1F, {{6, -0.5, 5.5}}); histos.add("hCascade", "hCascade", HistType::kTH1F, {{6, -0.5, 5.5}}); + histos.add("hXiPtvsCent", "hXiPtvsCent", HistType::kTH2F, {{100, 0, 100}, {400, 0, 20}}); + histos.add("hXiPtvsCentEta08", "hXiPtvsCentEta08", HistType::kTH2F, {{100, 0, 100}, {400, 0, 20}}); + histos.add("hXiPtvsCentY05", "hXiPtvsCentY05", HistType::kTH2F, {{100, 0, 100}, {400, 0, 20}}); + histos.add("hOmegaPtvsCent", "hOmegaPtvsCent", HistType::kTH2F, {{100, 0, 100}, {400, 0, 20}}); + histos.add("hOmegaPtvsCentEta08", "hOmegaPtvsCentEta08", HistType::kTH2F, {{100, 0, 100}, {400, 0, 20}}); + histos.add("hOmegaPtvsCentY05", "hOmegaPtvsCentY05", HistType::kTH2F, {{100, 0, 100}, {400, 0, 20}}); histos.add("hCascadePhi", "hCascadePhi", HistType::kTH1F, {{100, 0, 2 * TMath::Pi()}}); - histos.add("hcascminuspsiT0C", "hcascminuspsiT0C", HistType::kTH1F, {{100, 0, 2 * TMath::Pi()}}); + histos.add("hcascminuspsiT0C", "hcascminuspsiT0C", HistType::kTH1F, {{100, 0, TMath::Pi()}}); + histos.add("hv2CEPvsFT0C", "hv2CEPvsFT0C", HistType::kTH2F, {CentAxis, {100, -1, 1}}); + histos.add("hv2CEPvsv2CSP", "hv2CEPvsV2CSP", HistType::kTH2F, {{100, -1, 1}, {100, -1, 1}}); + histos.add("hv1EPvsv1SP", "hV1EPvsV1SP", HistType::kTH2F, {{100, -1, 1}, {100, -1, 1}}); + histos.add("hv1SP_ZDCA_vs_ZDCC", "hv1SP_ZDCA_vs_ZDCC", HistType::kTH2F, {{100, -1, 1}, {100, -1, 1}}); + + const AxisSpec thnAxisFT0C{thnConfigAxisFT0C, "FT0C (%)"}; + const AxisSpec thnAxisEta{thnConfigAxisEta, "#eta"}; + const AxisSpec thnAxisPt{thnConfigAxisPt, "p_{T}"}; + const AxisSpec thnAxisPtLambda{thnConfigAxisPtLambda, "p_{T, #Lambda}"}; + const AxisSpec thnAxisCharge{thnConfigAxisCharge, "Charge"}; + const AxisSpec thnAxisPsiDiff{thnConfigAxisPsiDiff, "2(phi-Psi)"}; + const AxisSpec thnAxisMassXi{thnConfigAxisMassXi, "inv. mass (#Lambda #pi) (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisMassOmega{thnConfigAxisMassOmega, "inv. mass (#Lambda K) (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisMassLambda{thnConfigAxisMassLambda, "inv. mass (p #pi) (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisBDTScore{thnConfigAxisBDTScore, "BDT score"}; + const AxisSpec thnAxisV2{thnConfigAxisV2, "v_{2}"}; + const AxisSpec thnAxisPzs2Xi{thnConfigAxisPzs2Xi, "Pzs2Xi"}; + const AxisSpec thnAxisPzs2Omega{thnConfigAxisPzs2Omega, "Pzs2Omega"}; + const AxisSpec thnAxisPzs2Lambda{thnConfigAxisPzs2Lambda, "Pzs2Lambda"}; + const AxisSpec thnAxisCos2Theta{thnConfigAxisCos2Theta, "Cos2Theta"}; + const AxisSpec thnAxisCos2ThetaL{thnConfigAxisCos2ThetaL, "Cos2ThetaL"}; + const AxisSpec thnAxisCosThetaXiAlpha{thnConfigAxisCosThetaXiAlpha, "CosThetaXiWithAlpha"}; + const AxisSpec thnAxisCosThetaOmegaAlpha{thnConfigAxisCosThetaOmegaAlpha, "CosThetaOmegaWithAlpha"}; + const AxisSpec thnAxisCosThetaProtonAlpha{thnConfigAxisCosThetaProtonAlpha, "CosThetaProtonWithAlpha"}; + + histos.add("massXi_ProtonAcc", "massXi", HistType::kTH1F, {thnAxisMassXi}); + histos.add("massOmega_ProtonAcc", "massOmega", HistType::kTH1F, {thnAxisMassOmega}); + + if (fillingConfigs.isFillTHNXi) { + if (fillingConfigs.isFillTHN_V2) + histos.add("hXiV2", "THn for v2 of Xi", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisPt, thnAxisMassXi, thnAxisBDTScore, thnAxisV2}); + if (fillingConfigs.isFillTHN_Pz) + histos.add("hXiPzs2", "THn for Pzs2 of Xi", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisPt, thnAxisMassXi, thnAxisBDTScore, thnAxisPzs2Xi}); + if (fillingConfigs.isFillTHN_PzFromLambda) + histos.add("hXiPzs2FromLambda", "THn for Pzs2 of Xi", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisPt, thnAxisMassXi, thnAxisBDTScore, thnAxisPzs2Lambda}); + if (fillingConfigs.isFillTHN_Acc) + histos.add("hXiCos2Theta", "THn for Cos2Theta of Xi", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisEta, thnAxisPt, thnAxisMassXi, thnAxisBDTScore, thnAxisCos2Theta}); + if (fillingConfigs.isFillTHN_AccFromLambdaVsCasc) + histos.add("hXiCos2ThetaFromLambda", "THn for Cos2Theta of Lambda vs Xi mass and pt", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisEta, thnAxisPt, thnAxisMassXi, thnAxisBDTScore, thnAxisCos2Theta}); + if (fillingConfigs.isFillTHN_AccFromLambdaVsLambda) + histos.add("hXiCos2ThetaFromLambdaL", "THn for Cos2Theta of Lambda vs Lambda mass and pt", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisEta, thnAxisPtLambda, thnAxisMassLambda, thnAxisBDTScore, thnAxisCos2ThetaL}); + } + if (fillingConfigs.isFillTHNXi_PzVsPsi) { + if (fillingConfigs.isFillTHN_Pz) + histos.add("hXiPzVsPsi", "THn for cosTheta of Xi", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisPt, thnAxisMassXi, thnAxisBDTScore, thnAxisCosThetaXiAlpha, thnAxisPsiDiff}); + if (fillingConfigs.isFillTHN_PzFromLambda) + histos.add("hXiPzVsPsiFromLambda", "THn for cosTheta of Xi", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisPt, thnAxisMassXi, thnAxisBDTScore, thnAxisCosThetaProtonAlpha, thnAxisPsiDiff}); + if (fillingConfigs.isFillTHN_Acc) + histos.add("hXiCos2ThetaVsPsi", "THn for cos2Theta of Xi", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisEta, thnAxisPt, thnAxisMassXi, thnAxisBDTScore, thnAxisCos2Theta, thnAxisPsiDiff}); + if (fillingConfigs.isFillTHN_AccFromLambdaVsCasc) + histos.add("hXiCos2ThetaVsPsiFromLambda", "THn for cos2Theta of Lambda vs Xi mass and pt", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisEta, thnAxisPt, thnAxisMassXi, thnAxisBDTScore, thnAxisCos2Theta, thnAxisPsiDiff}); + if (fillingConfigs.isFillTHN_AccFromLambdaVsLambda) + histos.add("hXiCos2ThetaVsPsiFromLambdaL", "THn for cos2Theta of Lambda vs Lambda mass and pt", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisEta, thnAxisPtLambda, thnAxisMassLambda, thnAxisBDTScore, thnAxisCos2ThetaL, thnAxisPsiDiff}); + } + if (fillingConfigs.isFillTHNOmega) { + if (fillingConfigs.isFillTHN_V2) + histos.add("hOmegaV2", "THn for v2 of Omega", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisPt, thnAxisMassOmega, thnAxisBDTScore, thnAxisV2}); + if (fillingConfigs.isFillTHN_Pz) + histos.add("hOmegaPzs2", "THn for Pzs2 of Omega", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisPt, thnAxisMassOmega, thnAxisBDTScore, thnAxisPzs2Omega}); + if (fillingConfigs.isFillTHN_PzFromLambda) + histos.add("hOmegaPzs2FromLambda", "THn for Pzs2 of Omega", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisPt, thnAxisMassOmega, thnAxisBDTScore, thnAxisPzs2Lambda}); + if (fillingConfigs.isFillTHN_Acc) + histos.add("hOmegaCos2Theta", "THn for Cos2Theta of Omega", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisEta, thnAxisPt, thnAxisMassOmega, thnAxisBDTScore, thnAxisCos2Theta}); + if (fillingConfigs.isFillTHN_AccFromLambdaVsCasc) + histos.add("hOmegaCos2ThetaFromLambda", "THn for Cos2Theta of Lambda vs Omega mass and pt", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisEta, thnAxisPt, thnAxisMassOmega, thnAxisBDTScore, thnAxisCos2Theta}); + if (fillingConfigs.isFillTHN_AccFromLambdaVsLambda) + histos.add("hOmegaCos2ThetaFromLambdaL", "THn for Cos2Theta of Lambda vs Lambda mass and pt", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisEta, thnAxisPtLambda, thnAxisMassLambda, thnAxisBDTScore, thnAxisCos2ThetaL}); + } + if (fillingConfigs.isFillTHNOmega_PzVsPsi) { + if (fillingConfigs.isFillTHN_Pz) + histos.add("hOmegaPzVsPsi", "THn for cosTheta of Omega", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisPt, thnAxisMassOmega, thnAxisBDTScore, thnAxisCosThetaOmegaAlpha, thnAxisPsiDiff}); + if (fillingConfigs.isFillTHN_PzFromLambda) + histos.add("hOmegaPzVsPsiFromLambda", "THn for cosTheta of Omega", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisPt, thnAxisMassOmega, thnAxisBDTScore, thnAxisCosThetaProtonAlpha, thnAxisPsiDiff}); + if (fillingConfigs.isFillTHN_Acc) + histos.add("hOmegaCos2ThetaVsPsi", "THn for cos2Theta of Omega", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisEta, thnAxisPt, thnAxisMassOmega, thnAxisBDTScore, thnAxisCos2Theta, thnAxisPsiDiff}); + if (fillingConfigs.isFillTHN_AccFromLambdaVsCasc) + histos.add("hOmegaCos2ThetaVsPsiFromLambda", "THn for cos2Theta of Lambda vs Omega mass and pt", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisEta, thnAxisPt, thnAxisMassOmega, thnAxisBDTScore, thnAxisCos2Theta, thnAxisPsiDiff}); + if (fillingConfigs.isFillTHN_AccFromLambdaVsLambda) + histos.add("hOmegaCos2ThetaVsPsiFromLambdaL", "THn for cos2Theta of Lambda vs Lambda mass and pt", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisEta, thnAxisPtLambda, thnAxisMassLambda, thnAxisBDTScore, thnAxisCos2ThetaL, thnAxisPsiDiff}); + } + + histosMCGen.add("h2DGenXiEta08", "h2DGenXiEta08", HistType::kTH2F, {{100, 0, 100}, {400, 0, 20}}); + histosMCGen.add("h2DGenOmegaEta08", "h2DGenOmegaEta08", HistType::kTH2F, {{100, 0, 100}, {400, 0, 20}}); + histosMCGen.add("h2DGenXiY05", "h2DGenXiY05", HistType::kTH2F, {{100, 0, 100}, {400, 0, 20}}); + histosMCGen.add("h2DGenOmegaY05", "h2DGenOmegaY05", HistType::kTH2F, {{100, 0, 100}, {400, 0, 20}}); + histosMCGen.add("hGenXiY", "hGenXiY", HistType::kTH1F, {{100, -1, 1}}); + histosMCGen.add("hGenOmegaY", "hGenOmegaY", HistType::kTH1F, {{100, -1, 1}}); + histosMCGen.add("hZvertexGen", "hZvertexGen", HistType::kTH1F, {{100, -20, 20}}); + histosMCGen.add("hNEventsMC", "hNEventsMC", {HistType::kTH1F, {{6, 0.f, 6.f}}}); + for (Int_t n = 1; n <= histosMCGen.get(HIST("hNEventsMC"))->GetNbinsX(); n++) { + histosMCGen.get(HIST("hNEventsMC"))->GetXaxis()->SetBinLabel(n, hNEventsLabelsMC[n - 1]); + } + histosMCGen.add("hNCascGen", "hNCascGen", {HistType::kTH1F, {{8, 0.f, 8.f}}}); + for (Int_t n = 1; n <= histosMCGen.get(HIST("hNCascGen"))->GetNbinsX(); n++) { + histosMCGen.get(HIST("hNCascGen"))->GetXaxis()->SetBinLabel(n, hNCascLabelsMC[n - 1]); + } + for (int iS{0}; iS < 2; ++iS) { cascadev2::hMassBeforeSelVsPt[iS] = histos.add(Form("hMassBeforeSelVsPt%s", cascadev2::speciesNames[iS].data()), "hMassBeforeSelVsPt", HistType::kTH2F, {massCascAxis[iS], ptAxis}); cascadev2::hMassAfterSelVsPt[iS] = histos.add(Form("hMassAfterSelVsPt%s", cascadev2::speciesNames[iS].data()), "hMassAfterSelVsPt", HistType::kTH2F, {massCascAxis[iS], ptAxis}); @@ -264,7 +660,7 @@ struct cascadeFlow { cascadev2::hBkgScoreBeforeSel[iS] = histos.add(Form("hBkgScoreBeforeSel%s", cascadev2::speciesNames[iS].data()), "Bkg score before selection;BDT first score;entries", HistType::kTH1F, {{100, 0., 1.}}); cascadev2::hSignalScoreAfterSel[iS] = histos.add(Form("hSignalScoreAfterSel%s", cascadev2::speciesNames[iS].data()), "Signal score after selection;BDT first score;entries", HistType::kTH1F, {{100, 0., 1.}}); cascadev2::hBkgScoreAfterSel[iS] = histos.add(Form("hBkgScoreAfterSel%s", cascadev2::speciesNames[iS].data()), "Bkg score after selection;BDT first score;entries", HistType::kTH1F, {{100, 0., 1.}}); - cascadev2::hSparseV2C[iS] = histos.add(Form("hSparseV2C%s", cascadev2::speciesNames[iS].data()), "hSparseV2C", HistType::kTHnSparseF, {massCascAxis[iS], ptAxis, v2Axis, CentAxis}); + cascadev2::hSparseV2C[iS] = histos.add(Form("hSparseV2C%s", cascadev2::speciesNames[iS].data()), "hSparseV2C", HistType::kTHnF, {massCascAxis[iS], ptAxis, v2Axis, CentAxis}); } if (isApplyML) { // Configure and initialise the ML class @@ -282,6 +678,13 @@ struct cascadeFlow { mlResponseXi.init(); mlResponseOmega.init(); } + if (applyAcceptanceCorrection) { + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + initAcceptanceFromCCDB(); + } } void processTrainingBackground(soa::Join::iterator const& coll, soa::Join const& Cascades, DauTracks const&) @@ -289,9 +692,10 @@ struct cascadeFlow { int counter = 0; - if (!coll.sel8() || std::abs(coll.posZ()) > 10.) { + if (!AcceptEvent(coll, 1)) { return; } + histos.fill(HIST("hEventCentrality"), coll.centFT0C()); histos.fill(HIST("hEventVertexZ"), coll.posZ()); @@ -336,19 +740,23 @@ struct cascadeFlow { } } - void processTrainingSignal(soa::Join::iterator const& coll, soa::Join const& Cascades, DauTracks const&) + void processTrainingSignal(soa::Join::iterator const& coll, CascMCCandidates const& Cascades, DauTracks const&, soa::Join const&) { - if (!coll.sel8() || std::abs(coll.posZ()) > 10.) { + if (!AcceptEvent(coll, 1)) { return; } histos.fill(HIST("hEventCentrality"), coll.centFT0C()); histos.fill(HIST("hEventVertexZ"), coll.posZ()); for (auto& casc : Cascades) { - int pdgCode{casc.pdgCode()}; - if (!(std::abs(pdgCode) == 3312 && std::abs(casc.pdgCodeV0()) == 3122 && std::abs(casc.pdgCodeBachelor()) == 211) // Xi - && !(std::abs(pdgCode) == 3334 && std::abs(casc.pdgCodeV0()) == 3122 && std::abs(casc.pdgCodeBachelor()) == 321)) // Omega + if (!casc.has_cascMCCore()) + continue; + + auto cascMC = casc.cascMCCore_as>(); + int pdgCode{cascMC.pdgCode()}; + if (!(std::abs(pdgCode) == 3312 && std::abs(cascMC.pdgCodeV0()) == 3122 && std::abs(cascMC.pdgCodeBachelor()) == 211) // Xi + && !(std::abs(pdgCode) == 3334 && std::abs(cascMC.pdgCodeV0()) == 3122 && std::abs(cascMC.pdgCodeBachelor()) == 321)) // Omega continue; auto negExtra = casc.negTrackExtra_as(); @@ -364,20 +772,54 @@ struct cascadeFlow { } } - void processAnalyseData(CollEventPlane const& coll, soa::Join const& Cascades, DauTracks const&) + void processAnalyseData(CollEventAndSpecPlane const& coll, CascCandidates const& Cascades, DauTracks const&) { - if (!coll.sel8() || std::abs(coll.posZ()) > 10.) { + if (!AcceptEvent(coll, 1)) { return; } + // select only events used for the calibration of the event plane + if (isGoodEventEP && !coll.triggereventep()) { + return; + } + + // event has event plane + bool hasEventPlane = 0; + if (coll.triggereventep()) + hasEventPlane = 1; + + // event has spectator plane + bool hasSpectatorPlane = 0; + if (coll.triggereventsp()) + hasSpectatorPlane = 1; + + histos.fill(HIST("hNEvents"), 9.5); + histos.fill(HIST("hEventNchCorrelationAfterEP"), coll.multNTracksPVeta1(), coll.multNTracksGlobal()); + histos.fill(HIST("hEventPVcontributorsVsCentralityAfterEP"), coll.centFT0C(), coll.multNTracksPVeta1()); + histos.fill(HIST("hEventGlobalTracksVsCentralityAfterEP"), coll.centFT0C(), coll.multNTracksGlobal()); + histos.fill(HIST("hEventCentrality"), coll.centFT0C()); histos.fill(HIST("hEventVertexZ"), coll.posZ()); ROOT::Math::XYZVector eventplaneVecT0C{coll.qvecFT0CRe(), coll.qvecFT0CIm(), 0}; + ROOT::Math::XYZVector eventplaneVecTPCA{coll.qvecBPosRe(), coll.qvecBPosIm(), 0}; + ROOT::Math::XYZVector eventplaneVecTPCC{coll.qvecBNegRe(), coll.qvecBNegIm(), 0}; + ROOT::Math::XYZVector spectatorplaneVecZDCA{std::cos(coll.psiZDCA()), std::sin(coll.psiZDCA()), 0}; // eta positive = projectile + ROOT::Math::XYZVector spectatorplaneVecZDCC{std::cos(coll.psiZDCC()), std::sin(coll.psiZDCC()), 0}; // eta negative = target const float PsiT0C = std::atan2(coll.qvecFT0CIm(), coll.qvecFT0CRe()) * 0.5f; histos.fill(HIST("hPsiT0C"), PsiT0C); + histos.fill(HIST("hPsiZDCA_vs_ZDCC"), coll.psiZDCC(), coll.psiZDCA()); + histos.fill(HIST("hPsiT0CvsCentFT0C"), coll.centFT0C(), PsiT0C); + + resolution.fill(HIST("QVectorsT0CTPCA"), eventplaneVecT0C.Dot(eventplaneVecTPCA), coll.centFT0C()); + resolution.fill(HIST("QVectorsT0CTPCC"), eventplaneVecT0C.Dot(eventplaneVecTPCC), coll.centFT0C()); + resolution.fill(HIST("QVectorsTPCAC"), eventplaneVecTPCA.Dot(eventplaneVecTPCC), coll.centFT0C()); + resolution.fill(HIST("QVectorsNormT0CTPCA"), eventplaneVecT0C.Dot(eventplaneVecTPCA) / (coll.qTPCR() * coll.sumAmplFT0C()), coll.centFT0C()); + resolution.fill(HIST("QVectorsNormT0CTPCC"), eventplaneVecT0C.Dot(eventplaneVecTPCC) / (coll.qTPCL() * coll.sumAmplFT0C()), coll.centFT0C()); + resolution.fill(HIST("QVectorsNormTPCAC"), eventplaneVecTPCA.Dot(eventplaneVecTPCC) / (coll.qTPCR() * coll.qTPCL()), coll.centFT0C()); + resolution.fill(HIST("QVectorsSpecPlane"), spectatorplaneVecZDCC.Dot(spectatorplaneVecZDCA), coll.centFT0C()); std::vector bdtScore[2]; for (auto& casc : Cascades) { @@ -409,8 +851,8 @@ struct cascadeFlow { float massCasc[2]{casc.mXi(), casc.mOmega()}; - // inv mass loose cut - if (casc.pt() < MinPt || casc.pt() > MaxPt) { + // pt cut + if (casc.pt() < CandidateConfigs.MinPt || casc.pt() > CandidateConfigs.MaxPt) { continue; } @@ -440,12 +882,311 @@ struct cascadeFlow { } ROOT::Math::XYZVector cascQvec{std::cos(2 * casc.phi()), std::sin(2 * casc.phi()), 0}; - auto v2C = cascQvec.Dot(eventplaneVecT0C) / std::sqrt(eventplaneVecT0C.mag2()); + auto v2CSP = cascQvec.Dot(eventplaneVecT0C); // not normalised by amplitude auto cascminuspsiT0C = GetPhiInRange(casc.phi() - PsiT0C); + auto v2CEP = TMath::Cos(2.0 * cascminuspsiT0C); + ROOT::Math::XYZVector cascUvec{std::cos(casc.phi()), std::sin(casc.phi()), 0}; + auto v1SP_ZDCA = cascUvec.Dot(spectatorplaneVecZDCA); + auto v1SP_ZDCC = cascUvec.Dot(spectatorplaneVecZDCC); + auto v1EP_ZDCA = TMath::Cos(casc.phi() - coll.psiZDCA()); + auto v1EP_ZDCC = TMath::Cos(casc.phi() - coll.psiZDCC()); + float v1SP = 0.5 * (v1SP_ZDCA - v1SP_ZDCC); + float v1EP = 0.5 * (v1EP_ZDCA - v1EP_ZDCC); // same as v1SP + + // polarization variables + double masses[2]{o2::constants::physics::MassXiMinus, o2::constants::physics::MassOmegaMinus}; + ROOT::Math::PxPyPzMVector cascadeVector[2], lambdaVector, protonVector; + float cosThetaStarLambda[2], cosThetaStarProton; + lambdaVector.SetCoordinates(casc.pxlambda(), casc.pylambda(), casc.pzlambda(), o2::constants::physics::MassLambda); + ROOT::Math::Boost lambdaBoost{lambdaVector.BoostToCM()}; + if (casc.sign() > 0) { + protonVector.SetCoordinates(casc.pxneg(), casc.pyneg(), casc.pzneg(), o2::constants::physics::MassProton); + } else { + protonVector.SetCoordinates(casc.pxpos(), casc.pypos(), casc.pzpos(), o2::constants::physics::MassProton); + } + auto boostedProton{lambdaBoost(protonVector)}; + cosThetaStarProton = boostedProton.Pz() / boostedProton.P(); + for (int i{0}; i < 2; ++i) { + cascadeVector[i].SetCoordinates(casc.px(), casc.py(), casc.pz(), masses[i]); + ROOT::Math::Boost cascadeBoost{cascadeVector[i].BoostToCM()}; + auto boostedLambda{cascadeBoost(lambdaVector)}; + cosThetaStarLambda[i] = boostedLambda.Pz() / boostedLambda.P(); + } + + double ptLambda = sqrt(pow(casc.pxlambda(), 2) + pow(casc.pylambda(), 2)); + auto etaLambda = RecoDecay::eta(std::array{casc.pxlambda(), casc.pylambda(), casc.pzlambda()}); + + // acceptance values if requested + double MeanCos2ThetaLambdaFromXi = 1; + double MeanCos2ThetaLambdaFromOmega = 1; + double MeanCos2ThetaProtonFromLambda = 1; + if (applyAcceptanceCorrection) { + if (ptLambda < CandidateConfigs.MinPtLambda || ptLambda > CandidateConfigs.MaxPtLambda) { + continue; + } + if (std::abs(casc.eta()) > CandidateConfigs.etaCasc) + continue; + if (std::abs(etaLambda) > CandidateConfigs.etaLambdaMax) + continue; + int bin2DXi = hAcceptanceXi->FindBin(casc.pt(), casc.eta()); + int bin2DOmega = hAcceptanceOmega->FindBin(casc.pt(), casc.eta()); + int bin2DLambda = hAcceptanceLambda->FindBin(ptLambda, etaLambda); + MeanCos2ThetaLambdaFromXi = hAcceptanceXi->GetBinContent(bin2DXi); + MeanCos2ThetaLambdaFromOmega = hAcceptanceOmega->GetBinContent(bin2DOmega); + MeanCos2ThetaProtonFromLambda = hAcceptanceLambda->GetBinContent(bin2DLambda); + } + + int ChargeIndex = 0; + if (casc.sign() > 0) + ChargeIndex = 1; + double Pzs2Xi = cosThetaStarLambda[0] * std::sin(2 * (casc.phi() - PsiT0C)) / cascadev2::AlphaXi[ChargeIndex] / MeanCos2ThetaLambdaFromXi; + double Pzs2Omega = cosThetaStarLambda[1] * std::sin(2 * (casc.phi() - PsiT0C)) / cascadev2::AlphaOmega[ChargeIndex] / MeanCos2ThetaLambdaFromOmega; + double Cos2ThetaXi = cosThetaStarLambda[0] * cosThetaStarLambda[0]; + double Cos2ThetaOmega = cosThetaStarLambda[1] * cosThetaStarLambda[1]; + double Pzs2LambdaFromCasc = cosThetaStarProton * std::sin(2 * (casc.phi() - PsiT0C)) / cascadev2::AlphaLambda[ChargeIndex] / MeanCos2ThetaProtonFromLambda; + double Cos2ThetaLambda = cosThetaStarProton * cosThetaStarProton; + + double CosThetaXiWithAlpha = cosThetaStarLambda[0] / cascadev2::AlphaXi[ChargeIndex]; + double CosThetaOmegaWithAlpha = cosThetaStarLambda[1] / cascadev2::AlphaOmega[ChargeIndex]; + double CosThetaProtonWithAlpha = cosThetaStarProton / cascadev2::AlphaLambda[ChargeIndex]; + + histos.fill(HIST("hv2CEPvsFT0C"), coll.centFT0C(), v2CEP); + histos.fill(HIST("hv2CEPvsv2CSP"), v2CSP, v2CEP); + histos.fill(HIST("hv1EPvsv1SP"), v1SP, v1EP); + histos.fill(HIST("hv1SP_ZDCA_vs_ZDCC"), v1SP_ZDCC, v1SP_ZDCA); + histos.fill(HIST("hCascadePhi"), casc.phi()); + histos.fill(HIST("hcascminuspsiT0C"), cascminuspsiT0C); + + double values[4]{casc.mXi(), casc.pt(), v2CSP, coll.centFT0C()}; + if (isSelectedCasc[0]) { + cascadev2::hSparseV2C[0]->Fill(values); + } + if (isSelectedCasc[1]) { + values[0] = casc.mOmega(); + cascadev2::hSparseV2C[0]->Fill(values); + } + + float BDTresponse[2]{0.f, 0.f}; + if (isApplyML) { + BDTresponse[0] = bdtScore[0][1]; + BDTresponse[1] = bdtScore[1][1]; + } + + if (std::abs(casc.eta()) < CandidateConfigs.etaCasc) { + if (fillingConfigs.isFillTHNXi) { + if (fillingConfigs.isFillTHN_V2) + histos.get(HIST("hXiV2"))->Fill(coll.centFT0C(), ChargeIndex, casc.pt(), casc.mXi(), BDTresponse[0], v2CEP); + if (fillingConfigs.isFillTHN_Pz) + histos.get(HIST("hXiPzs2"))->Fill(coll.centFT0C(), ChargeIndex, casc.pt(), casc.mXi(), BDTresponse[0], Pzs2Xi); + if (casc.mLambda() > CandidateConfigs.MinLambdaMass && casc.mLambda() < CandidateConfigs.MaxLambdaMass) { + if (fillingConfigs.isFillTHN_PzFromLambda) + histos.get(HIST("hXiPzs2FromLambda"))->Fill(coll.centFT0C(), ChargeIndex, casc.pt(), casc.mXi(), BDTresponse[0], Pzs2LambdaFromCasc); + } + if (fillingConfigs.isFillTHN_Acc) + histos.get(HIST("hXiCos2Theta"))->Fill(coll.centFT0C(), ChargeIndex, casc.eta(), casc.pt(), casc.mXi(), BDTresponse[0], Cos2ThetaXi); + if (fillingConfigs.isFillTHN_AccFromLambdaVsCasc) + histos.get(HIST("hXiCos2ThetaFromLambda"))->Fill(coll.centFT0C(), ChargeIndex, casc.eta(), casc.pt(), casc.mXi(), BDTresponse[0], Cos2ThetaLambda); + if (casc.mXi() > CandidateConfigs.MinXiMass && casc.mXi() < CandidateConfigs.MaxXiMass) { + if (fillingConfigs.isFillTHN_AccFromLambdaVsLambda) + histos.get(HIST("hXiCos2ThetaFromLambdaL"))->Fill(coll.centFT0C(), ChargeIndex, etaLambda, ptLambda, casc.mLambda(), BDTresponse[0], Cos2ThetaLambda); + histos.get(HIST("massXi_ProtonAcc"))->Fill(casc.mXi()); + } + } + if (fillingConfigs.isFillTHNXi_PzVsPsi) { + if (fillingConfigs.isFillTHN_Pz) + histos.get(HIST("hXiPzVsPsi"))->Fill(coll.centFT0C(), ChargeIndex, casc.pt(), casc.mXi(), BDTresponse[0], CosThetaXiWithAlpha, 2 * cascminuspsiT0C); + if (fillingConfigs.isFillTHN_PzFromLambda) + histos.get(HIST("hXiPzVsPsiFromLambda"))->Fill(coll.centFT0C(), ChargeIndex, casc.pt(), casc.mXi(), BDTresponse[0], CosThetaProtonWithAlpha, 2 * cascminuspsiT0C); + if (casc.mLambda() > CandidateConfigs.MinLambdaMass && casc.mLambda() < CandidateConfigs.MaxLambdaMass) { + if (fillingConfigs.isFillTHN_Acc) + histos.get(HIST("hXiCos2ThetaVsPsi"))->Fill(coll.centFT0C(), ChargeIndex, casc.eta(), casc.pt(), casc.mXi(), BDTresponse[0], Cos2ThetaXi, 2 * cascminuspsiT0C); + } + if (fillingConfigs.isFillTHN_AccFromLambdaVsCasc) + histos.get(HIST("hXiCos2ThetaVsPsiFromLambda"))->Fill(coll.centFT0C(), ChargeIndex, casc.eta(), casc.pt(), casc.mXi(), BDTresponse[0], Cos2ThetaLambda, 2 * cascminuspsiT0C); + if (casc.mXi() > CandidateConfigs.MinXiMass && casc.mXi() < CandidateConfigs.MaxXiMass) { + if (fillingConfigs.isFillTHN_AccFromLambdaVsLambda) + histos.get(HIST("hXiCos2ThetaVsPsiFromLambdaL"))->Fill(coll.centFT0C(), ChargeIndex, etaLambda, ptLambda, casc.mLambda(), BDTresponse[0], Cos2ThetaLambda, 2 * cascminuspsiT0C); + histos.get(HIST("massXi_ProtonAcc"))->Fill(casc.mXi()); + } + } + if (fillingConfigs.isFillTHNOmega) { + if (fillingConfigs.isFillTHN_V2) + histos.get(HIST("hOmegaV2"))->Fill(coll.centFT0C(), ChargeIndex, casc.pt(), casc.mOmega(), BDTresponse[1], v2CEP); + if (fillingConfigs.isFillTHN_Pz) + histos.get(HIST("hOmegaPzs2"))->Fill(coll.centFT0C(), ChargeIndex, casc.pt(), casc.mOmega(), BDTresponse[1], Pzs2Omega); + if (casc.mLambda() > CandidateConfigs.MinLambdaMass && casc.mLambda() < CandidateConfigs.MaxLambdaMass) { + if (fillingConfigs.isFillTHN_PzFromLambda) + histos.get(HIST("hOmegaPzs2FromLambda"))->Fill(coll.centFT0C(), ChargeIndex, casc.pt(), casc.mOmega(), BDTresponse[1], Pzs2LambdaFromCasc); + } + if (fillingConfigs.isFillTHN_Acc) + histos.get(HIST("hOmegaCos2Theta"))->Fill(coll.centFT0C(), ChargeIndex, casc.eta(), casc.pt(), casc.mOmega(), BDTresponse[1], Cos2ThetaOmega); + if (fillingConfigs.isFillTHN_AccFromLambdaVsCasc) + histos.get(HIST("hOmegaCos2ThetaFromLambda"))->Fill(coll.centFT0C(), ChargeIndex, casc.eta(), casc.pt(), casc.mOmega(), BDTresponse[1], Cos2ThetaLambda); + if (casc.mOmega() > CandidateConfigs.MinOmegaMass && casc.mOmega() < CandidateConfigs.MaxOmegaMass) { + if (fillingConfigs.isFillTHN_AccFromLambdaVsLambda) + histos.get(HIST("hOmegaCos2ThetaFromLambdaL"))->Fill(coll.centFT0C(), ChargeIndex, etaLambda, ptLambda, casc.mLambda(), BDTresponse[1], Cos2ThetaLambda); + histos.get(HIST("massOmega_ProtonAcc"))->Fill(casc.mOmega()); + } + } + if (fillingConfigs.isFillTHNOmega_PzVsPsi) { + if (fillingConfigs.isFillTHN_Pz) + histos.get(HIST("hOmegaPzVsPsi"))->Fill(coll.centFT0C(), ChargeIndex, casc.pt(), casc.mOmega(), BDTresponse[1], CosThetaOmegaWithAlpha, 2 * cascminuspsiT0C); + if (fillingConfigs.isFillTHN_PzFromLambda) + histos.get(HIST("hOmegaPzVsPsiFromLambda"))->Fill(coll.centFT0C(), ChargeIndex, casc.pt(), casc.mOmega(), BDTresponse[1], CosThetaProtonWithAlpha, 2 * cascminuspsiT0C); + if (casc.mLambda() > CandidateConfigs.MinLambdaMass && casc.mLambda() < CandidateConfigs.MaxLambdaMass) { + if (fillingConfigs.isFillTHN_Acc) + histos.get(HIST("hOmegaCos2ThetaVsPsi"))->Fill(coll.centFT0C(), ChargeIndex, casc.eta(), casc.pt(), casc.mOmega(), BDTresponse[1], Cos2ThetaOmega, 2 * cascminuspsiT0C); + } + if (fillingConfigs.isFillTHN_AccFromLambdaVsCasc) + histos.get(HIST("hOmegaCos2ThetaVsPsiFromLambda"))->Fill(coll.centFT0C(), ChargeIndex, casc.eta(), casc.pt(), casc.mOmega(), BDTresponse[1], Cos2ThetaLambda, 2 * cascminuspsiT0C); + if (casc.mOmega() > CandidateConfigs.MinOmegaMass && casc.mOmega() < CandidateConfigs.MaxOmegaMass) { + if (fillingConfigs.isFillTHN_AccFromLambdaVsLambda) + histos.get(HIST("hOmegaCos2ThetaVsPsiFromLambdaL"))->Fill(coll.centFT0C(), ChargeIndex, etaLambda, ptLambda, casc.mLambda(), BDTresponse[1], Cos2ThetaLambda, 2 * cascminuspsiT0C); + histos.get(HIST("massOmega_ProtonAcc"))->Fill(casc.mOmega()); + } + } + } + + if (isSelectedCasc[0] || isSelectedCasc[1]) { + if (fillingConfigs.isFillTree) + fillAnalysedTable(coll, hasEventPlane, hasSpectatorPlane, casc, v2CSP, v2CEP, v1SP_ZDCA, v1SP_ZDCC, PsiT0C, BDTresponse[0], BDTresponse[1], 0); + } + } + } + + void processAnalyseDataEPCentralFW(CollEventPlaneCentralFW const& coll, CascCandidates const& Cascades, DauTracks const&) + { + + if (!AcceptEvent(coll, 1)) { + return; + } + + // select only events used for the calibration of the event plane + if (isGoodEventEP) { + if (abs(coll.qvecFT0CRe()) > 990 || abs(coll.qvecFT0CIm()) > 990 || abs(coll.qvecBNegRe()) > 990 || abs(coll.qvecBNegIm()) > 990 || abs(coll.qvecBPosRe()) > 990 || abs(coll.qvecBPosIm()) > 990) { + return; + } + } + + // event has event plane + bool hasEventPlane = 0; + if (abs(coll.qvecFT0CRe()) > 990 || abs(coll.qvecFT0CIm()) > 990 || abs(coll.qvecBNegRe()) > 990 || abs(coll.qvecBNegIm()) > 990 || abs(coll.qvecBPosRe()) > 990 || abs(coll.qvecBPosIm()) > 990) + hasEventPlane = 1; + + // event has spectator plane + bool hasSpectatorPlane = 0; + if (coll.triggereventsp()) + hasSpectatorPlane = 1; + + histos.fill(HIST("hNEvents"), 9.5); + histos.fill(HIST("hEventNchCorrelationAfterEP"), coll.multNTracksPVeta1(), coll.multNTracksGlobal()); + histos.fill(HIST("hEventPVcontributorsVsCentralityAfterEP"), coll.centFT0C(), coll.multNTracksPVeta1()); + histos.fill(HIST("hEventGlobalTracksVsCentralityAfterEP"), coll.centFT0C(), coll.multNTracksGlobal()); + + histos.fill(HIST("hEventCentrality"), coll.centFT0C()); + histos.fill(HIST("hEventVertexZ"), coll.posZ()); + + ROOT::Math::XYZVector eventplaneVecT0C{coll.qvecFT0CRe(), coll.qvecFT0CIm(), 0}; + ROOT::Math::XYZVector eventplaneVecTPCA{coll.qvecBPosRe(), coll.qvecBPosIm(), 0}; + ROOT::Math::XYZVector eventplaneVecTPCC{coll.qvecBNegRe(), coll.qvecBNegIm(), 0}; + ROOT::Math::XYZVector spectatorplaneVecZDCA{std::cos(coll.psiZDCA()), std::sin(coll.psiZDCA()), 0}; // eta positive = projectile + ROOT::Math::XYZVector spectatorplaneVecZDCC{std::cos(coll.psiZDCC()), std::sin(coll.psiZDCC()), 0}; // eta negative = target + + float NormQvT0C = sqrt(eventplaneVecT0C.Dot(eventplaneVecT0C)); + float NormQvTPCA = sqrt(eventplaneVecTPCA.Dot(eventplaneVecTPCA)); + float NormQvTPCC = sqrt(eventplaneVecTPCC.Dot(eventplaneVecTPCC)); + + const float PsiT0C = std::atan2(coll.qvecFT0CIm(), coll.qvecFT0CRe()) * 0.5f; + histos.fill(HIST("hPsiT0C"), PsiT0C); + histos.fill(HIST("hPsiT0CvsCentFT0C"), coll.centFT0C(), PsiT0C); + + resolution.fill(HIST("QVectorsT0CTPCA"), eventplaneVecT0C.Dot(eventplaneVecTPCA), coll.centFT0C()); + resolution.fill(HIST("QVectorsT0CTPCC"), eventplaneVecT0C.Dot(eventplaneVecTPCC), coll.centFT0C()); + resolution.fill(HIST("QVectorsTPCAC"), eventplaneVecTPCA.Dot(eventplaneVecTPCC), coll.centFT0C()); + resolution.fill(HIST("QVectorsNormT0CTPCA"), eventplaneVecT0C.Dot(eventplaneVecTPCA) / (NormQvT0C * NormQvTPCA), coll.centFT0C()); + resolution.fill(HIST("QVectorsNormT0CTPCC"), eventplaneVecT0C.Dot(eventplaneVecTPCC) / (NormQvT0C * NormQvTPCC), coll.centFT0C()); + resolution.fill(HIST("QVectorsNormTPCAC"), eventplaneVecTPCA.Dot(eventplaneVecTPCC) / (NormQvTPCA * NormQvTPCC), coll.centFT0C()); + resolution.fill(HIST("QVectorsSpecPlane"), spectatorplaneVecZDCC.Dot(spectatorplaneVecZDCA), coll.centFT0C()); + + std::vector bdtScore[2]; + for (auto& casc : Cascades) { + + /// Add some minimal cuts for single track variables (min number of TPC clusters) + auto negExtra = casc.negTrackExtra_as(); + auto posExtra = casc.posTrackExtra_as(); + auto bachExtra = casc.bachTrackExtra_as(); + + int counter = 0; + IsCascAccepted(casc, negExtra, posExtra, bachExtra, counter); + histos.fill(HIST("hCascade"), counter); + + // ML selections + bool isSelectedCasc[2]{false, false}; + + std::vector inputFeaturesCasc{casc.cascradius(), + casc.v0radius(), + casc.casccosPA(coll.posX(), coll.posY(), coll.posZ()), + casc.v0cosPA(coll.posX(), coll.posY(), coll.posZ()), + casc.dcapostopv(), + casc.dcanegtopv(), + casc.dcabachtopv(), + casc.dcacascdaughters(), + casc.dcaV0daughters(), + casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ()), + casc.bachBaryonCosPA(), + casc.bachBaryonDCAxyToPV()}; + + float massCasc[2]{casc.mXi(), casc.mOmega()}; + + // inv mass loose cut + if (casc.pt() < CandidateConfigs.MinPt || casc.pt() > CandidateConfigs.MaxPt) { + continue; + } + + cascadev2::hMassBeforeSelVsPt[0]->Fill(massCasc[0], casc.pt()); + cascadev2::hMassBeforeSelVsPt[1]->Fill(massCasc[1], casc.pt()); + + if (isApplyML) { + // Retrieve model output and selection outcome + isSelectedCasc[0] = mlResponseXi.isSelectedMl(inputFeaturesCasc, casc.pt(), bdtScore[0]); + isSelectedCasc[1] = mlResponseOmega.isSelectedMl(inputFeaturesCasc, casc.pt(), bdtScore[1]); + + for (int iS{0}; iS < 2; ++iS) { + // Fill BDT score histograms before selection + cascadev2::hSignalScoreBeforeSel[iS]->Fill(bdtScore[0][1]); + cascadev2::hBkgScoreBeforeSel[iS]->Fill(bdtScore[1][0]); + // Fill histograms for selected candidates + if (isSelectedCasc[iS]) { + cascadev2::hSignalScoreAfterSel[iS]->Fill(bdtScore[0][1]); + cascadev2::hBkgScoreAfterSel[iS]->Fill(bdtScore[1][0]); + cascadev2::hMassAfterSelVsPt[iS]->Fill(massCasc[iS], casc.pt()); + } + } + } else { + isSelectedCasc[0] = true; + isSelectedCasc[1] = true; + } + + ROOT::Math::XYZVector cascQvec{std::cos(2 * casc.phi()), std::sin(2 * casc.phi()), 0}; + auto v2CSP = cascQvec.Dot(eventplaneVecT0C); + auto cascminuspsiT0C = GetPhiInRange(casc.phi() - PsiT0C); + auto v2CEP = TMath::Cos(2.0 * cascminuspsiT0C); + ROOT::Math::XYZVector cascUvec{std::cos(casc.phi()), std::sin(casc.phi()), 0}; + auto v1SP_ZDCA = cascUvec.Dot(spectatorplaneVecZDCA); + auto v1SP_ZDCC = cascUvec.Dot(spectatorplaneVecZDCC); + auto v1EP_ZDCA = TMath::Cos(casc.phi() - coll.psiZDCA()); + auto v1EP_ZDCC = TMath::Cos(casc.phi() - coll.psiZDCC()); + float v1SP = 0.5 * (v1SP_ZDCA - v1SP_ZDCC); + float v1EP = 0.5 * (v1EP_ZDCA - v1EP_ZDCC); // same as v1SP + + histos.fill(HIST("hv2CEPvsFT0C"), coll.centFT0C(), v2CEP); + histos.fill(HIST("hv2CEPvsv2CSP"), v2CSP, v2CEP); + histos.fill(HIST("hv1EPvsv1SP"), v1SP, v1EP); + histos.fill(HIST("hv1SP_ZDCA_vs_ZDCC"), v1SP_ZDCC, v1SP_ZDCA); histos.fill(HIST("hCascadePhi"), casc.phi()); histos.fill(HIST("hcascminuspsiT0C"), cascminuspsiT0C); - double values[4]{casc.mXi(), casc.pt(), v2C, coll.centFT0C()}; + double values[4]{casc.mXi(), casc.pt(), v2CSP, coll.centFT0C()}; if (isSelectedCasc[0]) { cascadev2::hSparseV2C[0]->Fill(values); } @@ -460,13 +1201,240 @@ struct cascadeFlow { BDTresponse[1] = bdtScore[1][1]; } if (isSelectedCasc[0] || isSelectedCasc[1]) - fillAnalysedTable(coll, casc, v2C, BDTresponse[0], BDTresponse[1]); + if (fillingConfigs.isFillTree) + fillAnalysedTable(coll, hasEventPlane, hasSpectatorPlane, casc, v2CSP, v2CEP, v1SP_ZDCA, v1SP_ZDCC, PsiT0C, BDTresponse[0], BDTresponse[1], 0); + } + } + + void processAnalyseMC(soa::Join::iterator const& coll, CascMCCandidates const& Cascades, DauTracks const&, soa::Join const&) + { + + if (!AcceptEvent(coll, 1)) { + return; + } + + bool hasEventPlane = 0; // no info at the moment + bool hasSpectatorPlane = 0; // no infor at the moment + + histos.fill(HIST("hNEvents"), 9.5); + histos.fill(HIST("hEventNchCorrelationAfterEP"), coll.multNTracksPVeta1(), coll.multNTracksGlobal()); + histos.fill(HIST("hEventPVcontributorsVsCentralityAfterEP"), coll.centFT0C(), coll.multNTracksPVeta1()); + histos.fill(HIST("hEventGlobalTracksVsCentralityAfterEP"), coll.centFT0C(), coll.multNTracksGlobal()); + histos.fill(HIST("hEventCentrality"), coll.centFT0C()); + histos.fill(HIST("hEventVertexZ"), coll.posZ()); + histos.fill(HIST("hMultNTracksITSTPCVsCentrality"), coll.centFT0C(), coll.multNTracksITSTPC()); + + std::vector bdtScore[2]; + for (auto& casc : Cascades) { + + if (!casc.has_cascMCCore()) + continue; + + auto cascMC = casc.cascMCCore_as>(); + + int pdgCode{cascMC.pdgCode()}; + if (!(std::abs(pdgCode) == 3312 && std::abs(cascMC.pdgCodeV0()) == 3122 && std::abs(cascMC.pdgCodeBachelor()) == 211) // Xi + && !(std::abs(pdgCode) == 3334 && std::abs(cascMC.pdgCodeV0()) == 3122 && std::abs(cascMC.pdgCodeBachelor()) == 321)) // Omega + { + pdgCode = 0; + } + + // rapidity definition + float XiY = RecoDecay::y(std::array{casc.px(), casc.py(), casc.pz()}, constants::physics::MassXiMinus); + float OmegaY = RecoDecay::y(std::array{casc.px(), casc.py(), casc.pz()}, constants::physics::MassOmegaMinus); + // true reco cascades before applying any selection + if (std::abs(pdgCode) == 3312 && std::abs(cascMC.pdgCodeV0()) == 3122 && std::abs(cascMC.pdgCodeBachelor()) == 211) { + histos.fill(HIST("hXiPtvsCent"), coll.centFT0C(), casc.pt()); + if (std::abs(casc.eta()) < 0.8) + histos.fill(HIST("hXiPtvsCentEta08"), coll.centFT0C(), casc.pt()); + if (std::abs(XiY) < 0.5) + histos.fill(HIST("hXiPtvsCentY05"), coll.centFT0C(), casc.pt()); + } else if (std::abs(pdgCode) == 3334 && std::abs(cascMC.pdgCodeV0()) == 3122 && std::abs(cascMC.pdgCodeBachelor()) == 321) { + histos.fill(HIST("hOmegaPtvsCent"), coll.centFT0C(), casc.pt()); + if (std::abs(casc.eta()) < 0.8) + histos.fill(HIST("hOmegaPtvsCentEta08"), coll.centFT0C(), casc.pt()); + if (std::abs(OmegaY) < 0.5) + histos.fill(HIST("hOmegaPtvsCentY05"), coll.centFT0C(), casc.pt()); + } + + /// Add some minimal cuts for single track variables (min number of TPC clusters) + auto negExtra = casc.negTrackExtra_as(); + auto posExtra = casc.posTrackExtra_as(); + auto bachExtra = casc.bachTrackExtra_as(); + + int counter = 0; + IsCascAccepted(casc, negExtra, posExtra, bachExtra, counter); + histos.fill(HIST("hCascade"), counter); + + // ML selections + bool isSelectedCasc[2]{false, false}; + + std::vector inputFeaturesCasc{casc.cascradius(), + casc.v0radius(), + casc.casccosPA(coll.posX(), coll.posY(), coll.posZ()), + casc.v0cosPA(coll.posX(), coll.posY(), coll.posZ()), + casc.dcapostopv(), + casc.dcanegtopv(), + casc.dcabachtopv(), + casc.dcacascdaughters(), + casc.dcaV0daughters(), + casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ()), + casc.bachBaryonCosPA(), + casc.bachBaryonDCAxyToPV()}; + + float massCasc[2]{casc.mXi(), casc.mOmega()}; + + if (casc.pt() < CandidateConfigs.MinPt || casc.pt() > CandidateConfigs.MaxPt) { + continue; + } + + cascadev2::hMassBeforeSelVsPt[0]->Fill(massCasc[0], casc.pt()); + cascadev2::hMassBeforeSelVsPt[1]->Fill(massCasc[1], casc.pt()); + + if (isApplyML) { + // Retrieve model output and selection outcome + isSelectedCasc[0] = mlResponseXi.isSelectedMl(inputFeaturesCasc, casc.pt(), bdtScore[0]); + isSelectedCasc[1] = mlResponseOmega.isSelectedMl(inputFeaturesCasc, casc.pt(), bdtScore[1]); + + for (int iS{0}; iS < 2; ++iS) { + // Fill BDT score histograms before selection + cascadev2::hSignalScoreBeforeSel[iS]->Fill(bdtScore[0][1]); + cascadev2::hBkgScoreBeforeSel[iS]->Fill(bdtScore[1][0]); + + // Fill histograms for selected candidates + if (isSelectedCasc[iS]) { + cascadev2::hSignalScoreAfterSel[iS]->Fill(bdtScore[0][1]); + cascadev2::hBkgScoreAfterSel[iS]->Fill(bdtScore[1][0]); + cascadev2::hMassAfterSelVsPt[iS]->Fill(massCasc[iS], casc.pt()); + } + } + } else { + isSelectedCasc[0] = true; + isSelectedCasc[1] = true; + } + + histos.fill(HIST("hCascadePhi"), casc.phi()); + + float BDTresponse[2]{0.f, 0.f}; + const float PsiT0C = 0; // not defined in MC for now + auto v2CSP = 0; // not defined in MC for now + auto v2CEP = 0; // not defined in MC for now + auto v1SP_ZDCA = 0; // not defined in MC for now + auto v1SP_ZDCC = 0; // not defined in MC for now + + if (isApplyML) { + BDTresponse[0] = bdtScore[0][1]; + BDTresponse[1] = bdtScore[1][1]; + } + if (isStoreTrueCascOnly) { + if (pdgCode == 0) + continue; + } + if (isSelectedCasc[0] || isSelectedCasc[1]) + fillAnalysedTable(coll, hasEventPlane, hasSpectatorPlane, casc, v2CSP, v2CEP, v1SP_ZDCA, v1SP_ZDCC, PsiT0C, BDTresponse[0], BDTresponse[1], pdgCode); + } + } + + void processMCGen(MCCollisionsStra::iterator const& mcCollision, const soa::SmallGroups>& collisions, const soa::SmallGroups>& cascMC) + { + + histosMCGen.fill(HIST("hZvertexGen"), mcCollision.posZ()); + histosMCGen.fill(HIST("hNEventsMC"), 0.5); + // Generated with accepted z vertex + if (TMath::Abs(mcCollision.posZ()) > cutzvertex) { + return; + } + histosMCGen.fill(HIST("hNEventsMC"), 1.5); + // Check if there is at least one of the reconstructed collisions associated to this MC collision + if (collisions.size() < 1) + return; + histosMCGen.fill(HIST("hNEventsMC"), 2.5); + if (collisions.size() == 1) + histosMCGen.fill(HIST("hNEventsMC"), 3.5); + else if (collisions.size() == 2) + histosMCGen.fill(HIST("hNEventsMC"), 4.5); + + int biggestNContribs = -1; + float centrality = 100.5f; + int nCollisions = 0; + for (auto const& coll : collisions) { + if (!AcceptEvent(coll, 0)) { + continue; + } + if (biggestNContribs < coll.multPVTotalContributors()) { + biggestNContribs = coll.multPVTotalContributors(); + centrality = coll.centFT0C(); + } + nCollisions++; + } + if (nCollisions < 1) { + return; + } + + histosMCGen.fill(HIST("hNEventsMC"), 5.5); + + for (auto const& cascmc : cascMC) { + if (TMath::Abs(cascmc.pdgCode()) == 3312) + histosMCGen.fill(HIST("hNCascGen"), 0.5); + else if (TMath::Abs(cascmc.pdgCode()) == 3334) + histosMCGen.fill(HIST("hNCascGen"), 1.5); + if (!cascmc.has_straMCCollision()) + continue; + if (TMath::Abs(cascmc.pdgCode()) == 3312) + histosMCGen.fill(HIST("hNCascGen"), 2.5); + else if (TMath::Abs(cascmc.pdgCode()) == 3334) + histosMCGen.fill(HIST("hNCascGen"), 3.5); + if (!cascmc.isPhysicalPrimary()) + continue; + if (TMath::Abs(cascmc.pdgCode()) == 3312) + histosMCGen.fill(HIST("hNCascGen"), 4.5); + else if (TMath::Abs(cascmc.pdgCode()) == 3334) + histosMCGen.fill(HIST("hNCascGen"), 5.5); + + float ptmc = RecoDecay::sqrtSumOfSquares(cascmc.pxMC(), cascmc.pyMC()); + + float theta = std::atan(ptmc / cascmc.pzMC()); //-pi/2 < theta < pi/2 + + float theta1 = 0; + + // if pz is positive (i.e. positive rapidity): 0 < theta < pi/2 + if (theta > 0) + theta1 = theta; // 0 < theta1/2 < pi/4 --> 0 < tan (theta1/2) < 1 --> positive eta + // if pz is negative (i.e. negative rapidity): -pi/2 < theta < 0 --> we need 0 < theta1/2 < pi/2 for the ln to be defined + else + theta1 = TMath::Pi() + theta; // pi/2 < theta1 < pi --> pi/4 < theta1/2 < pi/2 --> 1 < tan (theta1/2) --> negative eta + + float cascMCeta = -log(std::tan(theta1 / 2)); + float cascMCy = 0; + + if (TMath::Abs(cascmc.pdgCode()) == 3312) { + cascMCy = RecoDecay::y(std::array{cascmc.pxMC(), cascmc.pyMC(), cascmc.pzMC()}, constants::physics::MassXiMinus); + if (TMath::Abs(cascMCeta) < etaCascMCGen) { + histosMCGen.fill(HIST("h2DGenXiEta08"), centrality, ptmc); + histosMCGen.fill(HIST("hNCascGen"), 6.5); + } + if (TMath::Abs(cascMCy) < yCascMCGen) + histosMCGen.fill(HIST("h2DGenXiY05"), centrality, ptmc); + histosMCGen.fill(HIST("hGenXiY"), cascMCy); + } else if (TMath::Abs(cascmc.pdgCode() == 3334)) { + cascMCy = RecoDecay::y(std::array{cascmc.pxMC(), cascmc.pyMC(), cascmc.pzMC()}, constants::physics::MassOmegaMinus); + if (TMath::Abs(cascMCeta) < etaCascMCGen) { + histosMCGen.fill(HIST("h2DGenOmegaEta08"), centrality, ptmc); + histosMCGen.fill(HIST("hNCascGen"), 7.5); + } + if (TMath::Abs(cascMCy) < yCascMCGen) + histosMCGen.fill(HIST("h2DGenOmegaY05"), centrality, ptmc); + histosMCGen.fill(HIST("hGenOmegaY"), cascMCy); + } } } PROCESS_SWITCH(cascadeFlow, processTrainingBackground, "Process to create the training dataset for the background", true); PROCESS_SWITCH(cascadeFlow, processTrainingSignal, "Process to create the training dataset for the signal", false); PROCESS_SWITCH(cascadeFlow, processAnalyseData, "Process to apply ML model to the data", false); + PROCESS_SWITCH(cascadeFlow, processAnalyseDataEPCentralFW, "Process to apply ML model to the data - event plane calibration from central framework", false); + PROCESS_SWITCH(cascadeFlow, processAnalyseMC, "Process to apply ML model to the MC", false); + PROCESS_SWITCH(cascadeFlow, processMCGen, "Process to store MC generated particles", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/TableProducer/Strangeness/cascademcbuilder.cxx b/PWGLF/TableProducer/Strangeness/cascademcbuilder.cxx index c19436a0193..3d4a5642004 100644 --- a/PWGLF/TableProducer/Strangeness/cascademcbuilder.cxx +++ b/PWGLF/TableProducer/Strangeness/cascademcbuilder.cxx @@ -50,105 +50,343 @@ struct cascademcbuilder { Produces tracasclabels; // MC labels for tracked cascades Produces bbtags; // bb tags (inv structure tagging) Produces cascmccores; // optionally aggregate information from MC side for posterior analysis (derived data) + Produces cascCoreMClabels; // optionally aggregate information from MC side for posterior analysis (derived data) + Produces cascmccollrefs; // references MC collisions from MC cascades - Configurable populateCascMCCores{"populateCascMCCores", false, "populate CascMCCores table for derived data analysis"}; + Configurable populateCascMCCoresSymmetric{"populateCascMCCoresSymmetric", false, "populate CascMCCores table for derived data analysis, keep CascMCCores joinable with CascCores"}; + Configurable populateCascMCCoresAsymmetric{"populateCascMCCoresAsymmetric", false, "populate CascMCCores table for derived data analysis, create CascCores -> CascMCCores interlink. Saves only labeled Cascades."}; - void init(InitContext const&) {} + Configurable addGeneratedXiMinus{"addGeneratedXiMinus", false, "add CascMCCore entry for generated, not-recoed XiMinus"}; + Configurable addGeneratedXiPlus{"addGeneratedXiPlus", false, "add CascMCCore entry for generated, not-recoed XiPlus"}; + Configurable addGeneratedOmegaMinus{"addGeneratedOmegaMinus", false, "add CascMCCore entry for generated, not-recoed OmegaMinus"}; + Configurable addGeneratedOmegaPlus{"addGeneratedOmegaPlus", false, "add CascMCCore entry for generated, not-recoed OmegaPlus"}; + + Configurable treatPiToMuDecays{"treatPiToMuDecays", true, "if true, will correctly capture pi -> mu and V0 label will still point to originating V0 decay in those cases. Nota bene: prong info will still be for the muon!"}; + + Configurable rapidityWindow{"rapidityWindow", 0.5, "rapidity window to save non-recoed candidates"}; //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - // build cascade labels - void processCascades(aod::CascDatas const& casctable, aod::V0sLinked const&, aod::V0Datas const& /*v0table*/, aod::McTrackLabels const&, aod::McParticles const&) + // Helper struct to contain CascMCCore information prior to filling + struct mcCascinfo { + int label; + int motherLabel; + int mcCollision; + int pdgCode; + int pdgCodeMother; + int pdgCodeV0; + int pdgCodePositive; + int pdgCodeNegative; + int pdgCodeBachelor; + bool isPhysicalPrimary; + int processPositive = -1; + int processNegative = -1; + int processBachelor = -1; + std::array xyz; + std::array lxyz; + std::array posP; + std::array negP; + std::array bachP; + std::array momentum; + int mcParticlePositive; + int mcParticleNegative; + int mcParticleBachelor; + }; + mcCascinfo thisInfo; + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + + // kink handling + template + int getOriginatingParticle(mcpart const& part, int& indexForPositionOfDecay) { - for (auto& casc : casctable) { - int pdgCode = -1, pdgCodeMother = -1; - int pdgCodePositive = -1, pdgCodeNegative = -1, pdgCodeBachelor = -1, pdgCodeV0 = -1; - bool isPhysicalPrimary = false; - float xmc = -999.0f, ymc = -999.0f, zmc = -999.0f; - float xlmc = -999.0f, ylmc = -999.0f, zlmc = -999.0f; - float pxposmc = -999.0f, pyposmc = -999.0f, pzposmc = -999.0f; - float pxnegmc = -999.0f, pynegmc = -999.0f, pznegmc = -999.0f; - float pxbachmc = -999.0f, pybachmc = -999.0f, pzbachmc = -999.0f; - float px = -999.0f, py = -999.0f, pz = -999.0f; - int lLabel = -1, lMotherLabel = -1; + int returnValue = -1; + if (part.has_mothers()) { + auto const& motherList = part.template mothers_as(); + if (motherList.size() == 1) { + for (const auto& mother : motherList) { + if (std::abs(part.pdgCode()) == 13 && treatPiToMuDecays) { + // muon decay, de-ref mother twice + if (mother.has_mothers()) { + auto grandMotherList = mother.template mothers_as(); + if (grandMotherList.size() == 1) { + for (const auto& grandMother : grandMotherList) { + returnValue = grandMother.globalIndex(); + indexForPositionOfDecay = mother.globalIndex(); // for V0 decay position: grab muon + } + } + } + } else { + returnValue = mother.globalIndex(); + indexForPositionOfDecay = part.globalIndex(); + } + } + } + } + return returnValue; + } + + template + void generateCascadeMCinfo(TCascadeTable cascTable, TMCParticleTable mcParticles) + { + + // to be used if using the asymmetric mode, kept empty otherwise + std::vector mcCascinfos; // V0MCCore information + std::vector mcParticleIsReco(mcParticles.size(), false); // mc Particle not recoed by V0s + + for (auto& casc : cascTable) { + thisInfo.pdgCode = -1, thisInfo.pdgCodeMother = -1; + thisInfo.pdgCodePositive = -1, thisInfo.pdgCodeNegative = -1; + thisInfo.pdgCodeBachelor = -1, thisInfo.pdgCodeV0 = -1; + thisInfo.isPhysicalPrimary = false; + thisInfo.xyz[0] = -999.0f, thisInfo.xyz[1] = -999.0f, thisInfo.xyz[2] = -999.0f; + thisInfo.lxyz[0] = -999.0f, thisInfo.lxyz[1] = -999.0f, thisInfo.lxyz[2] = -999.0f; + thisInfo.posP[0] = -999.0f, thisInfo.posP[1] = -999.0f, thisInfo.posP[2] = -999.0f; + thisInfo.negP[0] = -999.0f, thisInfo.negP[1] = -999.0f, thisInfo.negP[2] = -999.0f; + thisInfo.bachP[0] = -999.0f, thisInfo.bachP[1] = -999.0f, thisInfo.bachP[2] = -999.0f; + thisInfo.momentum[0] = -999.0f, thisInfo.momentum[1] = -999.0f, thisInfo.momentum[2] = -999.0f; + thisInfo.label = -1, thisInfo.motherLabel = -1; + thisInfo.mcParticlePositive = -1; + thisInfo.mcParticleNegative = -1; + thisInfo.mcParticleBachelor = -1; // Acquire all three daughter tracks, please - auto lBachTrack = casc.bachelor_as(); - auto lNegTrack = casc.negTrack_as(); - auto lPosTrack = casc.posTrack_as(); + auto lBachTrack = casc.template bachelor_as(); + auto lNegTrack = casc.template negTrack_as(); + auto lPosTrack = casc.template posTrack_as(); // Association check // There might be smarter ways of doing this in the future if (lNegTrack.has_mcParticle() && lPosTrack.has_mcParticle() && lBachTrack.has_mcParticle()) { - auto lMCBachTrack = lBachTrack.mcParticle_as(); - auto lMCNegTrack = lNegTrack.mcParticle_as(); - auto lMCPosTrack = lPosTrack.mcParticle_as(); + auto lMCBachTrack = lBachTrack.template mcParticle_as(); + auto lMCNegTrack = lNegTrack.template mcParticle_as(); + auto lMCPosTrack = lPosTrack.template mcParticle_as(); - pdgCodePositive = lMCPosTrack.pdgCode(); - pdgCodeNegative = lMCNegTrack.pdgCode(); - pdgCodeBachelor = lMCBachTrack.pdgCode(); - pxposmc = lMCPosTrack.px(); - pyposmc = lMCPosTrack.py(); - pzposmc = lMCPosTrack.pz(); - pxnegmc = lMCNegTrack.px(); - pynegmc = lMCNegTrack.py(); - pznegmc = lMCNegTrack.pz(); - pxbachmc = lMCBachTrack.px(); - pybachmc = lMCBachTrack.py(); - pzbachmc = lMCBachTrack.pz(); + thisInfo.mcParticlePositive = lMCPosTrack.globalIndex(); + thisInfo.mcParticleNegative = lMCNegTrack.globalIndex(); + thisInfo.mcParticleBachelor = lMCBachTrack.globalIndex(); + thisInfo.pdgCodePositive = lMCPosTrack.pdgCode(); + thisInfo.pdgCodeNegative = lMCNegTrack.pdgCode(); + thisInfo.pdgCodeBachelor = lMCBachTrack.pdgCode(); + thisInfo.posP[0] = lMCPosTrack.px(); + thisInfo.posP[1] = lMCPosTrack.py(); + thisInfo.posP[2] = lMCPosTrack.pz(); + thisInfo.negP[0] = lMCNegTrack.px(); + thisInfo.negP[1] = lMCNegTrack.py(); + thisInfo.negP[2] = lMCNegTrack.pz(); + thisInfo.bachP[0] = lMCBachTrack.px(); + thisInfo.bachP[1] = lMCBachTrack.py(); + thisInfo.bachP[2] = lMCBachTrack.pz(); + thisInfo.processPositive = lMCPosTrack.getProcess(); + thisInfo.processNegative = lMCNegTrack.getProcess(); + thisInfo.processBachelor = lMCBachTrack.getProcess(); - // Step 1: check if the mother is the same, go up a level - if (lMCNegTrack.has_mothers() && lMCPosTrack.has_mothers()) { - for (auto& lNegMother : lMCNegTrack.mothers_as()) { - for (auto& lPosMother : lMCPosTrack.mothers_as()) { - if (lNegMother == lPosMother) { - // acquire information - xlmc = lMCPosTrack.vx(); - ylmc = lMCPosTrack.vy(); - zlmc = lMCPosTrack.vz(); - pdgCodeV0 = lNegMother.pdgCode(); + // Step 0: treat pi -> mu + antineutrino + // if present, de-reference original V0 correctly and provide label to original object + // NOTA BENE: the prong info will still correspond to a muon, treat carefully! + int negOriginating = -1, posOriginating = -1, bachOriginating = -1; + int particleForLambdaDecayPositionIdx = -1, particleForCascadeDecayPositionIdx = -1; + negOriginating = getOriginatingParticle(lMCNegTrack, particleForLambdaDecayPositionIdx); + posOriginating = getOriginatingParticle(lMCPosTrack, particleForLambdaDecayPositionIdx); + bachOriginating = getOriginatingParticle(lMCBachTrack, particleForCascadeDecayPositionIdx); - // if we got to this level, it means the mother particle exists and is the same - // now we have to go one level up and compare to the bachelor mother too - for (auto& lV0Mother : lNegMother.mothers_as()) { - for (auto& lBachMother : lMCBachTrack.mothers_as()) { - if (lV0Mother == lBachMother) { - lLabel = lV0Mother.globalIndex(); - pdgCode = lV0Mother.pdgCode(); - isPhysicalPrimary = lV0Mother.isPhysicalPrimary(); - xmc = lMCBachTrack.vx(); - ymc = lMCBachTrack.vy(); - zmc = lMCBachTrack.vz(); - px = lV0Mother.px(); - py = lV0Mother.py(); - pz = lV0Mother.pz(); - if (lV0Mother.has_mothers()) { - for (auto& lV0GrandMother : lV0Mother.mothers_as()) { - pdgCodeMother = lV0GrandMother.pdgCode(); - lMotherLabel = lV0GrandMother.globalIndex(); - } - } - } + if (negOriginating > -1 && negOriginating == posOriginating) { + auto originatingV0 = mcParticles.rawIteratorAt(negOriginating); + auto particleForLambdaDecayPosition = mcParticles.rawIteratorAt(particleForLambdaDecayPositionIdx); + + thisInfo.label = originatingV0.globalIndex(); + thisInfo.lxyz[0] = particleForLambdaDecayPosition.vx(); + thisInfo.lxyz[1] = particleForLambdaDecayPosition.vy(); + thisInfo.lxyz[2] = particleForLambdaDecayPosition.vz(); + thisInfo.pdgCodeV0 = originatingV0.pdgCode(); + + if (originatingV0.has_mothers()) { + for (auto& lV0Mother : originatingV0.template mothers_as()) { + if (lV0Mother.globalIndex() == bachOriginating) { // found mother particle + thisInfo.label = lV0Mother.globalIndex(); + + if (lV0Mother.has_mcCollision()) { + thisInfo.mcCollision = lV0Mother.mcCollisionId(); // save this reference, please + } + + thisInfo.pdgCode = lV0Mother.pdgCode(); + thisInfo.isPhysicalPrimary = lV0Mother.isPhysicalPrimary(); + thisInfo.xyz[0] = originatingV0.vx(); + thisInfo.xyz[1] = originatingV0.vy(); + thisInfo.xyz[2] = originatingV0.vz(); + thisInfo.momentum[0] = lV0Mother.px(); + thisInfo.momentum[1] = lV0Mother.py(); + thisInfo.momentum[2] = lV0Mother.pz(); + if (lV0Mother.has_mothers()) { + for (auto& lV0GrandMother : lV0Mother.template mothers_as()) { + thisInfo.pdgCodeMother = lV0GrandMother.pdgCode(); + thisInfo.motherLabel = lV0GrandMother.globalIndex(); } - } // end conditional V0-bach pair - } // end neg = pos mother conditional - } - } // end loop neg/pos mothers - } // end conditional of mothers existing + } + } + } // end v0 mother loop + } // end has_mothers check for V0 + } // end conditional of pos/neg originating being the same } // end association check // Construct label table (note: this will be joinable with CascDatas) casclabels( - lLabel, lMotherLabel); - if (populateCascMCCores) { + thisInfo.label, thisInfo.motherLabel); + + // Mark mcParticle as recoed (no searching necessary afterwards) + if (thisInfo.label > -1) { + mcParticleIsReco[thisInfo.label] = true; + } + + if (populateCascMCCoresSymmetric) { cascmccores( - pdgCode, pdgCodeMother, pdgCodeV0, isPhysicalPrimary, - pdgCodePositive, pdgCodeNegative, pdgCodeBachelor, - xmc, ymc, zmc, xlmc, ylmc, zlmc, - pxposmc, pyposmc, pzposmc, - pxnegmc, pynegmc, pznegmc, - pxbachmc, pybachmc, pzbachmc, - px, py, pz); + thisInfo.pdgCode, thisInfo.pdgCodeMother, thisInfo.pdgCodeV0, thisInfo.isPhysicalPrimary, + thisInfo.pdgCodePositive, thisInfo.pdgCodeNegative, thisInfo.pdgCodeBachelor, + thisInfo.xyz[0], thisInfo.xyz[1], thisInfo.xyz[2], + thisInfo.lxyz[0], thisInfo.lxyz[1], thisInfo.lxyz[2], + thisInfo.posP[0], thisInfo.posP[1], thisInfo.posP[2], + thisInfo.negP[0], thisInfo.negP[1], thisInfo.negP[2], + thisInfo.bachP[0], thisInfo.bachP[1], thisInfo.bachP[2], + thisInfo.momentum[0], thisInfo.momentum[1], thisInfo.momentum[2]); + cascmccollrefs(thisInfo.mcCollision); + } + + if (populateCascMCCoresAsymmetric) { + int thisCascMCCoreIndex = -1; + // step 1: check if this element is already provided in the table + // using the packedIndices variable calculated above + for (uint32_t ii = 0; ii < mcCascinfos.size(); ii++) { + if (thisInfo.label == mcCascinfos[ii].label && mcCascinfos[ii].label > -1) { + thisCascMCCoreIndex = ii; + break; // this exists already in list + } + } + if (thisCascMCCoreIndex < 0) { + // this CascMCCore does not exist yet. Create it and reference it + thisCascMCCoreIndex = mcCascinfos.size(); + mcCascinfos.push_back(thisInfo); + } + cascCoreMClabels(thisCascMCCoreIndex); // interlink: reconstructed -> MC index } } // end casctable loop + + // now populate V0MCCores if in asymmetric mode + if (populateCascMCCoresAsymmetric) { + // first step: add any un-recoed v0mmcores that were requested + for (auto& mcParticle : mcParticles) { + thisInfo.pdgCode = -1, thisInfo.pdgCodeMother = -1; + thisInfo.pdgCodePositive = -1, thisInfo.pdgCodeNegative = -1; + thisInfo.pdgCodeBachelor = -1, thisInfo.pdgCodeV0 = -1; + thisInfo.isPhysicalPrimary = false; + thisInfo.xyz[0] = 0.0f, thisInfo.xyz[1] = 0.0f, thisInfo.xyz[2] = 0.0f; + thisInfo.lxyz[0] = 0.0f, thisInfo.lxyz[1] = 0.0f, thisInfo.lxyz[2] = 0.0f; + thisInfo.posP[0] = 0.0f, thisInfo.posP[1] = 0.0f, thisInfo.posP[2] = 0.0f; + thisInfo.negP[0] = 0.0f, thisInfo.negP[1] = 0.0f, thisInfo.negP[2] = 0.0f; + thisInfo.bachP[0] = 0.0f, thisInfo.bachP[1] = 0.0f, thisInfo.bachP[2] = 0.0f; + thisInfo.momentum[0] = 0.0f, thisInfo.momentum[1] = 0.0f, thisInfo.momentum[2] = 0.0f; + thisInfo.label = -1, thisInfo.motherLabel = -1; + thisInfo.mcParticlePositive = -1; + thisInfo.mcParticleNegative = -1; + thisInfo.mcParticleBachelor = -1; + + if (mcParticleIsReco[mcParticle.globalIndex()] == true) + continue; // skip if already created in list + + if (TMath::Abs(mcParticle.y()) > rapidityWindow) + continue; // skip outside midrapidity + + if ( + (addGeneratedXiMinus && mcParticle.pdgCode() == 3312) || + (addGeneratedXiPlus && mcParticle.pdgCode() == -3312) || + (addGeneratedOmegaMinus && mcParticle.pdgCode() == 3334) || + (addGeneratedOmegaPlus && mcParticle.pdgCode() == -3334)) { + thisInfo.pdgCode = mcParticle.pdgCode(); + thisInfo.isPhysicalPrimary = mcParticle.isPhysicalPrimary(); + + if (mcParticle.has_mcCollision()) { + thisInfo.mcCollision = mcParticle.mcCollisionId(); // save this reference, please + } + thisInfo.momentum[0] = mcParticle.px(); + thisInfo.momentum[1] = mcParticle.py(); + thisInfo.momentum[2] = mcParticle.pz(); + thisInfo.label = mcParticle.globalIndex(); + + if (mcParticle.has_daughters()) { + auto const& daughters = mcParticle.template daughters_as(); + for (auto& dau : daughters) { + if (dau.getProcess() != 4) // check whether the daughter comes from a decay + continue; + + if (TMath::Abs(dau.pdgCode()) == 211 || TMath::Abs(dau.pdgCode()) == 321) { + thisInfo.pdgCodeBachelor = dau.pdgCode(); + thisInfo.bachP[0] = dau.px(); + thisInfo.bachP[1] = dau.py(); + thisInfo.bachP[2] = dau.pz(); + thisInfo.xyz[0] = dau.vx(); + thisInfo.xyz[1] = dau.vy(); + thisInfo.xyz[2] = dau.vz(); + thisInfo.mcParticleBachelor = dau.globalIndex(); + } + if (TMath::Abs(dau.pdgCode()) == 2212) { + thisInfo.pdgCodeV0 = dau.pdgCode(); + + for (auto& v0Dau : dau.template daughters_as()) { + if (v0Dau.getProcess() != 4) + continue; + + if (v0Dau.pdgCode() > 0) { + thisInfo.pdgCodePositive = v0Dau.pdgCode(); + thisInfo.processPositive = v0Dau.getProcess(); + thisInfo.posP[0] = v0Dau.px(); + thisInfo.posP[1] = v0Dau.py(); + thisInfo.posP[2] = v0Dau.pz(); + thisInfo.lxyz[0] = v0Dau.vx(); + thisInfo.lxyz[1] = v0Dau.vy(); + thisInfo.lxyz[2] = v0Dau.vz(); + thisInfo.mcParticlePositive = v0Dau.globalIndex(); + } + if (v0Dau.pdgCode() < 0) { + thisInfo.pdgCodeNegative = v0Dau.pdgCode(); + thisInfo.processNegative = v0Dau.getProcess(); + thisInfo.negP[0] = v0Dau.px(); + thisInfo.negP[1] = v0Dau.py(); + thisInfo.negP[2] = v0Dau.pz(); + thisInfo.mcParticleNegative = v0Dau.globalIndex(); + } + } + } + } + } + + // if I got here, it means this MC particle was not recoed and is of interest. Add it please + mcCascinfos.push_back(thisInfo); + } + } + + for (auto thisInfo : mcCascinfos) { + cascmccores( // a lot of the info below will be compressed in case of not-recoed MC (good!) + thisInfo.pdgCode, thisInfo.pdgCodeMother, thisInfo.pdgCodeV0, thisInfo.isPhysicalPrimary, + thisInfo.pdgCodePositive, thisInfo.pdgCodeNegative, thisInfo.pdgCodeBachelor, + thisInfo.xyz[0], thisInfo.xyz[1], thisInfo.xyz[2], + thisInfo.lxyz[0], thisInfo.lxyz[1], thisInfo.lxyz[2], + thisInfo.posP[0], thisInfo.posP[1], thisInfo.posP[2], + thisInfo.negP[0], thisInfo.negP[1], thisInfo.negP[2], + thisInfo.bachP[0], thisInfo.bachP[1], thisInfo.bachP[2], + thisInfo.momentum[0], thisInfo.momentum[1], thisInfo.momentum[2]); + cascmccollrefs(thisInfo.mcCollision); + } + } + } + + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + // build cascade labels + void processCascades(aod::CascDatas const& casctable, aod::V0sLinked const&, aod::V0Datas const& /*v0table*/, aod::McTrackLabels const&, aod::McParticles const& mcParticles) + { + generateCascadeMCinfo(casctable, mcParticles); + } + + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + // build findable cascade labels + void processFindableCascades(aod::CascDatas const& casctable, aod::FindableV0sLinked const&, aod::V0Datas const& /*v0table*/, aod::McTrackLabels const&, aod::McParticles const& mcParticles) + { + generateCascadeMCinfo(casctable, mcParticles); } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* @@ -159,25 +397,25 @@ struct cascademcbuilder { int lLabel = -1; // Acquire all three daughter tracks, please - auto lBachTrack = casc.bachelor_as(); - auto lNegTrack = casc.negTrack_as(); - auto lPosTrack = casc.posTrack_as(); + auto lBachTrack = casc.template bachelor_as(); + auto lNegTrack = casc.template negTrack_as(); + auto lPosTrack = casc.template posTrack_as(); // Association check // There might be smarter ways of doing this in the future if (lNegTrack.has_mcParticle() && lPosTrack.has_mcParticle() && lBachTrack.has_mcParticle()) { - auto lMCBachTrack = lBachTrack.mcParticle_as(); - auto lMCNegTrack = lNegTrack.mcParticle_as(); - auto lMCPosTrack = lPosTrack.mcParticle_as(); + auto lMCBachTrack = lBachTrack.template mcParticle_as(); + auto lMCNegTrack = lNegTrack.template mcParticle_as(); + auto lMCPosTrack = lPosTrack.template mcParticle_as(); // Step 1: check if the mother is the same, go up a level if (lMCNegTrack.has_mothers() && lMCPosTrack.has_mothers()) { - for (auto& lNegMother : lMCNegTrack.mothers_as()) { - for (auto& lPosMother : lMCPosTrack.mothers_as()) { + for (auto& lNegMother : lMCNegTrack.template mothers_as()) { + for (auto& lPosMother : lMCPosTrack.template mothers_as()) { if (lNegMother == lPosMother) { // if we got to this level, it means the mother particle exists and is the same // now we have to go one level up and compare to the bachelor mother too - for (auto& lV0Mother : lNegMother.mothers_as()) { - for (auto& lBachMother : lMCBachTrack.mothers_as()) { + for (auto& lV0Mother : lNegMother.template mothers_as()) { + for (auto& lBachMother : lMCBachTrack.template mothers_as()) { if (lV0Mother == lBachMother) { lLabel = lV0Mother.globalIndex(); } @@ -289,6 +527,7 @@ struct cascademcbuilder { } PROCESS_SWITCH(cascademcbuilder, processCascades, "Produce regular cascade label tables", true); + PROCESS_SWITCH(cascademcbuilder, processFindableCascades, "Produce findable cascade label tables", false); PROCESS_SWITCH(cascademcbuilder, processKFCascades, "Produce KF cascade label tables", false); PROCESS_SWITCH(cascademcbuilder, processTrackedCascades, "Produce tracked cascade label tables", false); PROCESS_SWITCH(cascademcbuilder, processBBTags, "Produce cascade bach-baryon correlation tags", true); diff --git a/PWGLF/TableProducer/Strangeness/cascademcfinder.cxx b/PWGLF/TableProducer/Strangeness/cascademcfinder.cxx index 46c4933cdab..8d26f0ea33c 100644 --- a/PWGLF/TableProducer/Strangeness/cascademcfinder.cxx +++ b/PWGLF/TableProducer/Strangeness/cascademcfinder.cxx @@ -24,6 +24,11 @@ // david.dobrigkeit.chinellato@cern.ch // +#include +#include +#include +#include + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -40,7 +45,6 @@ #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Centrality.h" #include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPObject.h" #include "DataFormatsParameters/GRPMagField.h" #include "CCDB/BasicCCDBManager.h" @@ -49,12 +53,8 @@ #include #include #include -#include #include #include -#include -#include -#include using namespace o2; using namespace o2::framework; @@ -62,11 +62,12 @@ using namespace o2::framework::expressions; using std::array; using namespace ROOT::Math; +// WARNING: the cascade findable uses findable V0s as well using LabeledTracks = soa::Join; -using LabeledFullV0s = soa::Join; +using LabeledFullV0s = soa::Join; struct cascademcfinder { - Produces cascades; + Produces cascades; HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -89,8 +90,8 @@ struct cascademcfinder { void init(InitContext&) { // initialize histograms - const AxisSpec axisNTimesCollRecoed{(int)10, -0.5f, +9.5f, ""}; - const AxisSpec axisPt{(int)100, +0.0f, +10.0f, "p_{T} (GeV/c)"}; + const AxisSpec axisNTimesCollRecoed{static_cast(10), -0.5f, +9.5f, ""}; + const AxisSpec axisPt{static_cast(100), +0.0f, +10.0f, "p_{T} (GeV/c)"}; histos.add("hNTimesCollRecoed", "hNTimesCollRecoed", kTH1F, {axisNTimesCollRecoed}); diff --git a/PWGLF/TableProducer/Strangeness/cascademlselection.cxx b/PWGLF/TableProducer/Strangeness/cascademlselection.cxx new file mode 100644 index 00000000000..6da4bc669e4 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/cascademlselection.cxx @@ -0,0 +1,298 @@ +// 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. +// +// *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* +// Lambdakzero ML selection task +// *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* +// +// Comments, questions, complaints, suggestions? +// Please write to: +// gianni.shigeru.setoue.liveraro@cern.ch +// romain.schotter@cern.ch +// david.dobrigkeit.chinellato@cern.ch +// + +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/ASoA.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessMLTables.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "CCDB/BasicCCDBManager.h" +#include +#include +#include +#include +#include +#include +#include "Tools/ML/MlResponse.h" +#include "Tools/ML/model.h" + +using namespace o2; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::ml; +using std::array; +using std::cout; +using std::endl; + +// For original data loops +using CascOriginalDatas = soa::Join; + +// For derived data analysis +using CascDerivedDatas = soa::Join; + +struct cascademlselection { + o2::ml::OnnxModel mlModelXiMinus; + o2::ml::OnnxModel mlModelXiPlus; + o2::ml::OnnxModel mlModelOmegaMinus; + o2::ml::OnnxModel mlModelOmegaPlus; + + std::map metadata; + + Produces xiMLSelections; // optionally aggregate information from ML output for posterior analysis (derived data) + Produces omegaMLSelections; // optionally aggregate information from ML output for posterior analysis (derived data) + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // CCDB configuration + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + int mRunNumber; + + // CCDB options + struct : ConfigurableGroup { + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + } ccdbConfigurations; + + // Machine learning evaluation for pre-selection and corresponding information generation + struct : ConfigurableGroup { + // ML classifiers: master flags to populate ML Selection tables + Configurable calculateXiMinusScores{"mlConfigurations.calculateXiMinusScores", true, "calculate XiMinus ML scores"}; + Configurable calculateXiPlusScores{"mlConfigurations.calculateXiPlusScores", true, "calculate XiPlus ML scores"}; + Configurable calculateOmegaMinusScores{"mlConfigurations.calculateOmegaMinusScores", true, "calculate OmegaMinus ML scores"}; + Configurable calculateOmegaPlusScores{"mlConfigurations.calculateOmegaPlusScores", true, "calculate OmegaPlus ML scores"}; + + // ML input for ML calculation + Configurable modelPathCCDB{"mlConfigurations.modelPathCCDB", "", "ML Model path in CCDB"}; + Configurable timestampCCDB{"mlConfigurations.timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; + Configurable loadModelsFromCCDB{"mlConfigurations.loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + Configurable enableOptimizations{"mlConfigurations.enableOptimizations", false, "Enables the ONNX extended model-optimization: sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED)"}; + + // Local paths for test purposes + Configurable localModelPathXiMinus{"mlConfigurations.localModelPathXiMinus", "XiMinus_BDTModel.onnx", "(std::string) Path to the local .onnx file."}; + Configurable localModelPathXiPlus{"mlConfigurations.localModelPathXiPlus", "XiPlus_BDTModel.onnx", "(std::string) Path to the local .onnx file."}; + Configurable localModelPathOmegaMinus{"mlConfigurations.localModelPathOmegaMinus", "OmegaMinus_BDTModel.onnx", "(std::string) Path to the local .onnx file."}; + Configurable localModelPathOmegaPlus{"mlConfigurations.localModelPathOmegaPlus", "OmegaPlus_BDTModel.onnx", "(std::string) Path to the local .onnx file."}; + + // Thresholds for choosing to populate V0Cores tables with pre-selections + Configurable thresholdXiMinus{"mlConfigurations.thresholdXiMinus", -1.0f, "Threshold to keep XiMinus candidates"}; + Configurable thresholdXiPlus{"mlConfigurations.thresholdXiPlus", -1.0f, "Threshold to keep XiPlus candidates"}; + Configurable thresholdOmegaMinus{"mlConfigurations.thresholdOmegaMinus", -1.0f, "Threshold to keep OmegaMinus candidates"}; + Configurable thresholdOmegaPlus{"mlConfigurations.thresholdOmegaPlus", -1.0f, "Threshold to keep OmegaPlus candidates"}; + } mlConfigurations; + + // Axis + // base properties + ConfigurableAxis vertexZ{"vertexZ", {30, -15.0f, 15.0f}, ""}; + + int nCandidates = 0; + + template + void initCCDB(TCollision const& collision) + { + int64_t timeStampML = 0; + if constexpr (requires { collision.timestamp(); }) { // we are in derived data + if (mRunNumber == collision.runNumber()) { + return; + } + mRunNumber = collision.runNumber(); + timeStampML = collision.timestamp(); + } + if constexpr (requires { collision.template bc_as(); }) { // we are in original data + auto bc = collision.template bc_as(); + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + timeStampML = bc.timestamp(); + } + + // machine learning initialization if requested + if (mlConfigurations.calculateXiMinusScores || + mlConfigurations.calculateXiPlusScores || + mlConfigurations.calculateOmegaMinusScores || + mlConfigurations.calculateOmegaPlusScores) { + if (mlConfigurations.timestampCCDB.value != -1) + timeStampML = mlConfigurations.timestampCCDB.value; + LoadMachines(timeStampML); + } + } + + // function to load models for ML-based classifiers + void LoadMachines(int64_t timeStampML) + { + if (mlConfigurations.loadModelsFromCCDB) { + ccdbApi.init(ccdbConfigurations.ccdburl); + LOG(info) << "Fetching cascade models for timestamp: " << timeStampML; + + if (mlConfigurations.calculateXiMinusScores) { + bool retrieveSuccess = ccdbApi.retrieveBlob(mlConfigurations.modelPathCCDB, ".", metadata, timeStampML, false, mlConfigurations.localModelPathXiMinus.value); + if (retrieveSuccess) { + mlModelXiMinus.initModel(mlConfigurations.localModelPathXiMinus.value, mlConfigurations.enableOptimizations.value); + } else { + LOG(fatal) << "Error encountered while fetching/loading the XiMinus model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; + } + } + + if (mlConfigurations.calculateXiPlusScores) { + bool retrieveSuccess = ccdbApi.retrieveBlob(mlConfigurations.modelPathCCDB, ".", metadata, timeStampML, false, mlConfigurations.localModelPathXiPlus.value); + if (retrieveSuccess) { + mlModelXiPlus.initModel(mlConfigurations.localModelPathXiPlus.value, mlConfigurations.enableOptimizations.value); + } else { + LOG(fatal) << "Error encountered while fetching/loading the XiPlus model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; + } + } + + if (mlConfigurations.calculateOmegaMinusScores) { + bool retrieveSuccess = ccdbApi.retrieveBlob(mlConfigurations.modelPathCCDB, ".", metadata, timeStampML, false, mlConfigurations.localModelPathOmegaMinus.value); + if (retrieveSuccess) { + mlModelOmegaMinus.initModel(mlConfigurations.localModelPathOmegaMinus.value, mlConfigurations.enableOptimizations.value); + } else { + LOG(fatal) << "Error encountered while fetching/loading the OmegaMinus model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; + } + } + + if (mlConfigurations.calculateOmegaPlusScores) { + bool retrieveSuccess = ccdbApi.retrieveBlob(mlConfigurations.modelPathCCDB, ".", metadata, timeStampML, false, mlConfigurations.localModelPathOmegaPlus.value); + if (retrieveSuccess) { + mlModelOmegaPlus.initModel(mlConfigurations.localModelPathOmegaPlus.value, mlConfigurations.enableOptimizations.value); + } else { + LOG(fatal) << "Error encountered while fetching/loading the OmegaPlus model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; + } + } + } else { + if (mlConfigurations.calculateXiMinusScores) + mlModelXiMinus.initModel(mlConfigurations.localModelPathXiMinus.value, mlConfigurations.enableOptimizations.value); + if (mlConfigurations.calculateXiPlusScores) + mlModelXiPlus.initModel(mlConfigurations.localModelPathXiPlus.value, mlConfigurations.enableOptimizations.value); + if (mlConfigurations.calculateOmegaMinusScores) + mlModelOmegaMinus.initModel(mlConfigurations.localModelPathOmegaMinus.value, mlConfigurations.enableOptimizations.value); + if (mlConfigurations.calculateOmegaPlusScores) + mlModelOmegaPlus.initModel(mlConfigurations.localModelPathOmegaPlus.value, mlConfigurations.enableOptimizations.value); + } + LOG(info) << "Cascade ML Models loaded."; + } + + void init(InitContext const&) + { + // Histograms + histos.add("hEventVertexZ", "hEventVertexZ", kTH1F, {vertexZ}); + + ccdb->setURL(ccdbConfigurations.ccdburl); + } + + // Process candidate and store properties in object + template + void processCandidate(TCascObject const& cand) + { + // Select features + // FIXME THIS NEEDS ADJUSTING + std::vector inputFeatures{0.0f, 0.0f, + 0.0f, 0.0f}; + + // calculate scores + if (cand.sign() < 0) { + if (mlConfigurations.calculateXiMinusScores) { + float* xiMinusProbability = mlModelXiMinus.evalModel(inputFeatures); + xiMLSelections(xiMinusProbability[1]); + } else { + xiMLSelections(-1); + } + if (mlConfigurations.calculateOmegaMinusScores) { + float* omegaMinusProbability = mlModelOmegaMinus.evalModel(inputFeatures); + omegaMLSelections(omegaMinusProbability[1]); + } else { + omegaMLSelections(-1); + } + } + if (cand.sign() > 0) { + if (mlConfigurations.calculateXiPlusScores) { + float* xiPlusProbability = mlModelXiPlus.evalModel(inputFeatures); + xiMLSelections(xiPlusProbability[1]); + } else { + xiMLSelections(-1); + } + if (mlConfigurations.calculateOmegaPlusScores) { + float* omegaPlusProbability = mlModelOmegaPlus.evalModel(inputFeatures); + omegaMLSelections(omegaPlusProbability[1]); + } else { + omegaMLSelections(-1); + } + } + } + + void processDerivedData(soa::Join::iterator const& collision, CascDerivedDatas const& cascades) + { + initCCDB(collision); + + histos.fill(HIST("hEventVertexZ"), collision.posZ()); + for (auto& casc : cascades) { + nCandidates++; + if (nCandidates % 50000 == 0) { + LOG(info) << "Candidates processed: " << nCandidates; + } + processCandidate(casc); + } + } + void processStandardData(aod::Collision const& collision, CascOriginalDatas const& cascades) + { + initCCDB(collision); + + histos.fill(HIST("hEventVertexZ"), collision.posZ()); + for (auto& casc : cascades) { + nCandidates++; + if (nCandidates % 50000 == 0) { + LOG(info) << "Candidates processed: " << nCandidates; + } + processCandidate(casc); + } + } + + PROCESS_SWITCH(cascademlselection, processStandardData, "Process standard data", false); + PROCESS_SWITCH(cascademlselection, processDerivedData, "Process derived data", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/cascadepid.cxx b/PWGLF/TableProducer/Strangeness/cascadepid.cxx index c9faa24a4ed..3c7c82dacdd 100644 --- a/PWGLF/TableProducer/Strangeness/cascadepid.cxx +++ b/PWGLF/TableProducer/Strangeness/cascadepid.cxx @@ -101,6 +101,10 @@ struct cascadepid { Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; Configurable nSigmaPath{"nSigmaPath", "Users/d/ddobrigk/stratof", "Path of information for n-sigma calculation"}; + // manual + Configurable useCustomRunNumber{"useCustomRunNumber", false, "Use custom timestamp"}; + Configurable manualRunNumber{"manualRunNumber", 544122, "manual run number if no collisions saved"}; + ConfigurableAxis axisEta{"axisEta", {20, -1.0f, +1.0f}, "#eta"}; ConfigurableAxis axisDeltaTime{"axisDeltaTime", {2000, -1000.0f, +1000.0f}, "delta-time (ps)"}; ConfigurableAxis axisNSigma{"axisNSigma", {200, -10.0f, +10.0f}, "N(#sigma)"}; @@ -296,10 +300,9 @@ struct cascadepid { } } - template - void initCCDB(TInformationClass const& infoObject) + void initCCDB(int runNumber) { - if (mRunNumber == infoObject.runNumber()) { + if (mRunNumber == runNumber) { return; } @@ -311,32 +314,31 @@ struct cascadepid { grpmag.setL3Current(30000.f / (d_bz / 5.0f)); } o2::base::Propagator::initFieldFromGRP(&grpmag); - mRunNumber = infoObject.runNumber(); + mRunNumber = runNumber; return; } - auto run3grp_timestamp = infoObject.timestamp(); - o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + o2::parameters::GRPObject* grpo = ccdb->getForRun(grpPath, runNumber); o2::parameters::GRPMagField* grpmag = 0x0; if (grpo) { o2::base::Propagator::initFieldFromGRP(grpo); // Fetch magnetic field from ccdb for current collision d_bz = grpo->getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + LOG(info) << "Retrieved GRP for run " << runNumber << " with magnetic field of " << d_bz << " kZG"; } else { - grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + grpmag = ccdb->getForRun(grpmagPath, runNumber); if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for run " << runNumber; } o2::base::Propagator::initFieldFromGRP(grpmag); // Fetch magnetic field from ccdb for current collision d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + LOG(info) << "Retrieved GRP for run " << runNumber << " with magnetic field of " << d_bz << " kZG"; } // if TOF Nsigma desired if (doNSigmas) { - nSigmaCalibObjects = ccdb->getForTimeStamp(nSigmaPath, infoObject.timestamp()); + nSigmaCalibObjects = ccdb->getForRun(nSigmaPath, runNumber); if (nSigmaCalibObjects) { LOGF(info, "loaded TList with this many objects: %i", nSigmaCalibObjects->GetEntries()); @@ -372,7 +374,7 @@ struct cascadepid { LOG(info) << "Problems finding omega sigma histograms!"; } } - mRunNumber = infoObject.runNumber(); + mRunNumber = runNumber; } float velocity(float lMomentum, float lMass) @@ -568,10 +570,15 @@ struct cascadepid { void processStandardData(aod::Collisions const& collisions, CascOriginalDatas const& Cascades, TracksWithAllExtras const&, aod::BCsWithTimestamps const& /*bcs*/) { - auto collision = collisions.begin(); - auto bc = collision.bc_as(); - // Fire up CCDB - based on standard collisions - initCCDB(bc); + // Fire up CCDB with first collision in record. If no collisions, bypass + if (useCustomRunNumber || collisions.size() < 1) { + initCCDB(manualRunNumber); + } else { + auto collision = collisions.begin(); + auto bc = collision.bc_as(); + initCCDB(bc.runNumber()); + } + for (const auto& collision : collisions) { // Do analysis with collision-grouped V0s, retain full collision information const uint64_t collIdx = collision.globalIndex(); @@ -590,9 +597,15 @@ struct cascadepid { void processDerivedData(soa::Join const& collisions, CascDerivedDatas const& Cascades, dauTracks const&) { + // Fire up CCDB with first collision in record. If no collisions, bypass + if (useCustomRunNumber || collisions.size() < 1) { + initCCDB(manualRunNumber); + } else { + auto collision = collisions.begin(); + initCCDB(collision.runNumber()); + } + for (const auto& collision : collisions) { - // Fire up CCDB - based on StraCollisions for derived analysis - initCCDB(collision); // Do analysis with collision-grouped V0s, retain full collision information const uint64_t collIdx = collision.globalIndex(); auto CascTable_thisCollision = Cascades.sliceBy(perCollisionDerived, collIdx); diff --git a/PWGLF/TableProducer/Strangeness/cascadespawner.cxx b/PWGLF/TableProducer/Strangeness/cascadespawner.cxx index 4e2d0c68a44..dc004b91e78 100644 --- a/PWGLF/TableProducer/Strangeness/cascadespawner.cxx +++ b/PWGLF/TableProducer/Strangeness/cascadespawner.cxx @@ -35,7 +35,7 @@ using namespace o2::framework::expressions; /// Extends the cascdata table with expression columns struct cascadespawner { - Spawns cascdataext; + Spawns cascdataext; void init(InitContext const&) {} }; diff --git a/PWGLF/TableProducer/Strangeness/cascqaanalysis.cxx b/PWGLF/TableProducer/Strangeness/cascqaanalysis.cxx index c639f176cab..a46f977c93a 100644 --- a/PWGLF/TableProducer/Strangeness/cascqaanalysis.cxx +++ b/PWGLF/TableProducer/Strangeness/cascqaanalysis.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// Copyright 2019-2025 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. // @@ -8,13 +8,14 @@ // 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 QA task for Cascade analysis using derived data -/// -/// \author Chiara De Martin (chiara.de.martin@cern.ch) -/// \author Francesca Ercolessi (francesca.ercolessi@cern.ch) -/// \modified by Roman Nepeivoda (roman.nepeivoda@cern.ch) -/// \since June 1, 2023 +// +/// \file cascqaanalysis.cxx +/// \brief Analysis of cascades in pp collisions +/// \author Roman Nepeivoda (roman.nepeivoda@cern.ch) + +#include +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -27,6 +28,8 @@ #include "PWGLF/DataModel/cascqaanalysis.h" #include "TRandom2.h" #include "Framework/O2DatabasePDGPlugin.h" +#include "PWGLF/Utils/inelGt.h" +#include "PWGLF/DataModel/mcCentrality.h" using namespace o2; using namespace o2::framework; @@ -37,7 +40,7 @@ using TrkPidInfo = soa::Join; using LabeledCascades = soa::Join; -struct cascqaanalysis { +struct Cascqaanalysis { // Tables to produce Produces mycascades; @@ -46,11 +49,16 @@ struct cascqaanalysis { HistogramRegistry registry{"registry"}; // Event selection criteria - Configurable cutzvertex{"cutzvertex", 20.0f, "Accepted z-vertex range (cm)"}; - Configurable sel8{"sel8", 1, "Apply sel8 event selection"}; - Configurable isVertexITSTPCCut{"isVertexITSTPCCut", 1, "Select collisions with at least one ITS-TPC track"}; - Configurable isNoSameBunchPileupCut{"isNoSameBunchPileupCut", 1, "Same found-by-T0 bunch crossing rejection"}; - Configurable isGoodZvtxFT0vsPVCut{"isGoodZvtxFT0vsPVCut", 1, "z of PV by tracks and z of PV from FT0 A-C time difference cut"}; + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable isVertexITSTPC{"isVertexITSTPC", 0, "Select collisions with at least one ITS-TPC track"}; + Configurable isNoSameBunchPileup{"isNoSameBunchPileup", 0, "Same found-by-T0 bunch crossing rejection"}; + Configurable isGoodZvtxFT0vsPV{"isGoodZvtxFT0vsPV", 0, "z of PV by tracks and z of PV from FT0 A-C time difference cut"}; + Configurable isVertexTOFmatched{"isVertexTOFmatched", 0, "Is Vertex TOF matched"}; + + Configurable isTriggerTVX{"isTriggerTVX", 1, "TVX trigger"}; + Configurable isNoTimeFrameBorder{"isNoTimeFrameBorder", 1, "TF border cut"}; + Configurable isNoITSROFrameBorder{"isNoITSROFrameBorder", 1, "ITS ROF border cut"}; + Configurable isNoCollInTimeRangeNarrow{"isNoCollInTimeRangeNarrow", 1, "No collisions in +-2us window"}; // Cascade selection criteria Configurable scalefactor{"scalefactor", 1.0, "Scaling factor"}; @@ -71,6 +79,9 @@ struct cascqaanalysis { // QA histograms for the multiplicity estimation Configurable multQA{"multQA", 0, "0 - not to do QA, 1 - do the QA"}; + // QA histograms for cascade rec. + Configurable candidateQA{"candidateQA", 1, "0 - not to do QA, 1 - do the QA"}; + // Necessary for particle charges Service pdgDB; @@ -85,20 +96,14 @@ struct cascqaanalysis { uint8_t typeFlag; } CollisionIndexAndType; - // Struct for counting charged particles in |eta| region - typedef struct EtaCharge { - double eta; - int charge; - } EtaCharge; - void init(InitContext const&) { AxisSpec ptAxis = {200, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; AxisSpec rapidityAxis = {200, -2.0f, 2.0f, "y"}; - ConfigurableAxis centFT0MAxis{"FT0M", + ConfigurableAxis centFT0MAxis{"centFT0MAxis", {VARIABLE_WIDTH, 0., 0.01, 0.05, 0.1, 0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 105.5}, "FT0M (%)"}; - ConfigurableAxis centFV0AAxis{"FV0A", + ConfigurableAxis centFV0AAxis{"centFV0AAxis", {VARIABLE_WIDTH, 0., 0.01, 0.05, 0.1, 0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 105.5}, "FV0A (%)"}; AxisSpec eventTypeAxis = {3, -0.5f, 2.5f, "Event Type"}; @@ -108,28 +113,31 @@ struct cascqaanalysis { AxisSpec multNTracksAxis = {500, 0, 500, "N_{tracks}"}; AxisSpec signalFT0MAxis = {10000, 0, 40000, "FT0M amplitude"}; AxisSpec signalFV0AAxis = {10000, 0, 40000, "FV0A amplitude"}; + AxisSpec nCandidates = {30, -0.5, 29.5, "N_{cand.}"}; - TString hCandidateCounterLabels[5] = {"All candidates", "v0data exists", "passed topo cuts", "has associated MC particle", "associated with Xi(Omega)"}; + TString hCandidateCounterLabels[4] = {"All candidates", "passed topo cuts", "has associated MC particle", "associated with Xi(Omega)"}; TString hNEventsMCLabels[6] = {"All", "z vrtx", "INEL", "INEL>0", "INEL>1", "Associated with rec. collision"}; - TString hNEventsLabels[9] = {"All", "sel8", "kIsVertexITSTPC", "kNoSameBunchPileup", "kIsGoodZvtxFT0vsPV", "z vrtx", "INEL", "INEL>0", "INEL>1"}; + TString hNEventsLabels[13] = {"All", "kIsTriggerTVX", "kNoTimeFrameBorder", "kNoITSROFrameBorder", "kIsVertexITSTPC", "kNoSameBunchPileup", "kIsGoodZvtxFT0vsPV", "isVertexTOFmatched", "kNoCollInTimeRangeNarrow", "z vrtx", "INEL", "INEL>0", "INEL>1"}; - registry.add("hNEvents", "hNEvents", {HistType::kTH1F, {{9, 0.f, 9.f}}}); - for (Int_t n = 1; n <= registry.get(HIST("hNEvents"))->GetNbinsX(); n++) { + registry.add("hNEvents", "hNEvents", {HistType::kTH1F, {{13, 0.f, 13.f}}}); + + for (int n = 1; n <= registry.get(HIST("hNEvents"))->GetNbinsX(); n++) { registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(n, hNEventsLabels[n - 1]); } registry.add("hZCollision", "hZCollision", {HistType::kTH1F, {{200, -20.f, 20.f}}}); - registry.add("hCandidateCounter", "hCandidateCounter", {HistType::kTH1F, {{5, 0.0f, 5.0f}}}); - for (Int_t n = 1; n <= registry.get(HIST("hCandidateCounter"))->GetNbinsX(); n++) { + registry.add("hCandidateCounter", "hCandidateCounter", {HistType::kTH1F, {{4, 0.0f, 4.0f}}}); + for (int n = 1; n <= registry.get(HIST("hCandidateCounter"))->GetNbinsX(); n++) { registry.get(HIST("hCandidateCounter"))->GetXaxis()->SetBinLabel(n, hCandidateCounterLabels[n - 1]); } if (isMC) { // Rec. lvl + registry.add("fakeEvents", "fakeEvents", {HistType::kTH1F, {{1, -0.5f, 0.5f}}}); registry.add("hNchFT0MPVContr", "hNchFT0MPVContr", {HistType::kTH3F, {nChargedFT0MGenAxis, multNTracksAxis, eventTypeAxis}}); registry.add("hNchFV0APVContr", "hNchFV0APVContr", {HistType::kTH3F, {nChargedFV0AGenAxis, multNTracksAxis, eventTypeAxis}}); // Gen. lvl registry.add("hNEventsMC", "hNEventsMC", {HistType::kTH1F, {{6, 0.0f, 6.0f}}}); - for (Int_t n = 1; n <= registry.get(HIST("hNEventsMC"))->GetNbinsX(); n++) { + for (int n = 1; n <= registry.get(HIST("hNEventsMC"))->GetNbinsX(); n++) { registry.get(HIST("hNEventsMC"))->GetXaxis()->SetBinLabel(n, hNEventsMCLabels[n - 1]); } registry.add("hZCollisionGen", "hZCollisionGen", {HistType::kTH1F, {{200, -20.f, 20.f}}}); @@ -138,20 +146,26 @@ struct cascqaanalysis { registry.add("hNContributorsCorrelation", "hNContributorsCorrelation", {HistType::kTH2F, {{250, -0.5f, 249.5f, "Secondary Contributor"}, {250, -0.5f, 249.5f, "Main Contributor"}}}); registry.add("hNchFT0MGenEvType", "hNchFT0MGenEvType", {HistType::kTH2F, {nChargedFT0MGenAxis, eventTypeAxis}}); registry.add("hNchFV0AGenEvType", "hNchFV0AGenEvType", {HistType::kTH2F, {nChargedFV0AGenAxis, eventTypeAxis}}); - } else { - registry.add("hFT0MpvContr", "hFT0MpvContr", {HistType::kTH3F, {centFT0MAxis, multNTracksAxis, eventTypeAxis}}); - registry.add("hFV0ApvContr", "hFV0ApvContr", {HistType::kTH3F, {centFV0AAxis, multNTracksAxis, eventTypeAxis}}); + registry.add("hCentFT0M_genMC", "hCentFT0M_genMC", {HistType::kTH2F, {centFT0MAxis, eventTypeAxis}}); + } + + registry.add("hCentFT0M_rec", "hCentFT0M_rec", {HistType::kTH2F, {centFT0MAxis, eventTypeAxis}}); + + if (candidateQA) { + registry.add("hNcandidates", "hNcandidates", {HistType::kTH3F, {nCandidates, centFT0MAxis, {2, -0.5f, 1.5f}}}); } if (multQA) { if (isMC) { // Rec. lvl registry.add("hNchFT0Mglobal", "hNchFT0Mglobal", {HistType::kTH3F, {nChargedFT0MGenAxis, multNTracksAxis, eventTypeAxis}}); - } else { - registry.add("hFT0Mglobal", "hFT0Mglobal", {HistType::kTH3F, {centFT0MAxis, multNTracksAxis, eventTypeAxis}}); - registry.add("hFV0AFT0M", "hFV0AFT0M", {HistType::kTH3F, {centFV0AAxis, centFT0MAxis, eventTypeAxis}}); } + registry.add("hFT0MpvContr", "hFT0MpvContr", {HistType::kTH3F, {centFT0MAxis, multNTracksAxis, eventTypeAxis}}); + registry.add("hFV0ApvContr", "hFV0ApvContr", {HistType::kTH3F, {centFV0AAxis, multNTracksAxis, eventTypeAxis}}); + registry.add("hFT0Mglobal", "hFT0Mglobal", {HistType::kTH3F, {centFT0MAxis, multNTracksAxis, eventTypeAxis}}); + registry.add("hFV0AFT0M", "hFV0AFT0M", {HistType::kTH3F, {centFV0AAxis, centFT0MAxis, eventTypeAxis}}); registry.add("hFT0MFV0Asignal", "hFT0MFV0Asignal", {HistType::kTH2F, {signalFT0MAxis, signalFV0AAxis}}); + registry.add("hFT0MsignalPVContr", "hFT0MsignalPVContr", {HistType::kTH3F, {signalFT0MAxis, multNTracksAxis, eventTypeAxis}}); } } @@ -162,11 +176,11 @@ struct cascqaanalysis { aod::cascdata::dcaV0daughters < dcav0dau && aod::cascdata::dcacascdaughters < dcacascdau); - Partition pvContribTracksIUEta1 = (nabs(aod::track::eta) < 1.0f) && ((aod::track::flags & (uint32_t)o2::aod::track::PVContributor) == (uint32_t)o2::aod::track::PVContributor); + Partition pvContribTracksIUEta1 = (nabs(aod::track::eta) < 1.0f) && ((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)); Partition globalTracksIUEta05 = (nabs(aod::track::eta) < 0.5f) && (requireGlobalTrackInFilter()); template - bool AcceptCascCandidate(TCascade const& cascCand, float const& pvx, float const& pvy, float const& pvz) + bool acceptCascCandidate(TCascade const& cascCand, float const& pvx, float const& pvy, float const& pvz) { // Access daughter tracks auto posdau = cascCand.template posTrack_as(); @@ -178,9 +192,9 @@ struct cascqaanalysis { cascCand.v0radius() > v0radius && cascCand.casccosPA(pvx, pvy, pvz) > casccospa && cascCand.v0cosPA(pvx, pvy, pvz) > v0cospa && - TMath::Abs(posdau.eta()) < etadau && - TMath::Abs(negdau.eta()) < etadau && - TMath::Abs(bachelor.eta()) < etadau) { + std::fabs(posdau.eta()) < etadau && + std::fabs(negdau.eta()) < etadau && + std::fabs(bachelor.eta()) < etadau) { return true; } else { return false; @@ -188,11 +202,11 @@ struct cascqaanalysis { } template - uint16_t GetGenNchInFT0Mregion(TMcParticles particles) + uint16_t getGenNchInFT0Mregion(TMcParticles particles) { // Particle counting in FITFT0: -3.3<η<-2.1; 3.5<η<4.9 uint16_t nchFT0 = 0; - for (auto& mcParticle : particles) { + for (const auto& mcParticle : particles) { if (!mcParticle.isPhysicalPrimary()) { continue; } @@ -212,11 +226,11 @@ struct cascqaanalysis { } template - uint16_t GetGenNchInFV0Aregion(TMcParticles particles) + uint16_t getGenNchInFV0Aregion(TMcParticles particles) { // Particle counting in FV0A: 2.2<η<5.1 uint16_t nchFV0A = 0; - for (auto& mcParticle : particles) { + for (const auto& mcParticle : particles) { if (!mcParticle.isPhysicalPrimary()) { continue; } @@ -236,110 +250,102 @@ struct cascqaanalysis { } template - int GetEventTypeFlag(TCollision const& collision) + int getEventTypeFlag(TCollision const& collision) { - // 0 - INEL, 1 - INEL > 0, 2 - INEL>1 + // 0 - INEL, 1 - INEL>0, 2 - INEL>1 int evFlag = 0; - registry.fill(HIST("hNEvents"), 6.5); // INEL - if (collision.multNTracksPVeta1() > 0) { + registry.fill(HIST("hNEvents"), 10.5); // INEL + if (collision.isInelGt0()) { evFlag += 1; - registry.fill(HIST("hNEvents"), 7.5); // INEL>0 + registry.fill(HIST("hNEvents"), 11.5); // INEL>0 } - if (collision.multNTracksPVeta1() > 1) { + if (collision.isInelGt1()) { evFlag += 1; - registry.fill(HIST("hNEvents"), 8.5); // INEL>1 + registry.fill(HIST("hNEvents"), 12.5); // INEL>1 } return evFlag; } template - bool AcceptEvent(TCollision const& collision, bool isFillEventSelectionQA) + bool acceptEvent(TCollision const& collision, bool isFillEventSelectionQA) { if (isFillEventSelectionQA) { registry.fill(HIST("hNEvents"), 0.5); } - // Event selection if required - if (sel8 && !collision.sel8()) { + + // kIsTriggerTVX selection + if (isTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { return false; } + if (isFillEventSelectionQA) { registry.fill(HIST("hNEvents"), 1.5); } - // kIsVertexITSTPC selection - if (isVertexITSTPCCut && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) { + // kNoTimeFrameBorder selection + if (isNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { return false; } + if (isFillEventSelectionQA) { registry.fill(HIST("hNEvents"), 2.5); } - // kNoSameBunchPileup selection - if (isNoSameBunchPileupCut && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + + // kNoITSROFrameBorder selection + if (isNoITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { return false; } + if (isFillEventSelectionQA) { registry.fill(HIST("hNEvents"), 3.5); } - // kIsGoodZvtxFT0vsPV selection - if (isGoodZvtxFT0vsPVCut && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + + // kIsVertexITSTPC selection + if (isVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) { return false; } if (isFillEventSelectionQA) { registry.fill(HIST("hNEvents"), 4.5); } - - // Z vertex selection - if (TMath::Abs(collision.posZ()) > cutzvertex) { + // kNoSameBunchPileup selection + if (isNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { return false; } if (isFillEventSelectionQA) { registry.fill(HIST("hNEvents"), 5.5); - registry.fill(HIST("hZCollision"), collision.posZ()); } - - return true; - } - - template - bool isINELgtNmc(TMcParticles particles, int nChToSatisfySelection) - { - // INEL > N (at least N+1 charged particles in |eta| < 1.0) - EtaCharge etaCharge; - std::vector ParticlesEtaAndCharge(particles.size()); - unsigned int nParticles = 0; - for (const auto& particle : particles) { - if (particle.isPhysicalPrimary() == 0) - continue; // consider only primaries - etaCharge = {999, 0}; // refresh init. for safety - TParticlePDG* p = pdgDB->GetParticle(particle.pdgCode()); - if (!p) { - switch (std::to_string(particle.pdgCode()).length()) { - case 10: // nuclei - { - etaCharge = {particle.eta(), static_cast(particle.pdgCode() / 10000 % 1000)}; - ParticlesEtaAndCharge[nParticles++] = etaCharge; - break; - } - default: - break; - } - } else { - etaCharge = {particle.eta(), static_cast(p->Charge())}; - ParticlesEtaAndCharge[nParticles++] = etaCharge; - } + // kIsGoodZvtxFT0vsPV selection + if (isGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (isFillEventSelectionQA) { + registry.fill(HIST("hNEvents"), 6.5); + } + // isVertexTOFmatched selection + if (isVertexTOFmatched && !collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (isFillEventSelectionQA) { + registry.fill(HIST("hNEvents"), 7.5); + } + // kNoCollInTimeRangeNarrow selection + if (isNoCollInTimeRangeNarrow && !collision.selection_bit(aod::evsel::kNoCollInTimeRangeNarrow)) { + return false; + } + if (isFillEventSelectionQA) { + registry.fill(HIST("hNEvents"), 8.5); } - ParticlesEtaAndCharge.resize(nParticles); - - auto etaChargeConditionFunc = [](EtaCharge elem) { - return ((TMath::Abs(elem.eta) < 1.0) && (TMath::Abs(elem.charge) > 0.001)); - }; - - if (std::count_if(ParticlesEtaAndCharge.begin(), ParticlesEtaAndCharge.end(), etaChargeConditionFunc) > nChToSatisfySelection) { - return true; - } else { + // Z vertex selection + if (std::fabs(collision.posZ()) > cutzvertex) { return false; } + if (isFillEventSelectionQA) { + registry.fill(HIST("hNEvents"), 9.5); + registry.fill(HIST("hZCollision"), collision.posZ()); + } + + return true; } void processData(soa::JoinsliceByCached(aod::track::collisionId, collision.globalIndex(), cache); int nTracksPVcontr = tracksGroupedPVcontr.size(); @@ -361,23 +367,27 @@ struct cascqaanalysis { auto tracksGroupedGlobal = globalTracksIUEta05->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); int nTracksGlobal = tracksGroupedGlobal.size(); - registry.fill(HIST("hFT0MpvContr"), collision.centFT0M(), nTracksPVcontr, evType); - registry.fill(HIST("hFV0ApvContr"), collision.centFV0A(), nTracksPVcontr, evType); + registry.fill(HIST("hCentFT0M_rec"), collision.centFT0M(), evType); if (multQA) { + registry.fill(HIST("hFT0MpvContr"), collision.centFT0M(), nTracksPVcontr, evType); + registry.fill(HIST("hFV0ApvContr"), collision.centFV0A(), nTracksPVcontr, evType); registry.fill(HIST("hFT0Mglobal"), collision.centFT0M(), nTracksGlobal, evType); registry.fill(HIST("hFV0AFT0M"), collision.centFV0A(), collision.centFT0M(), evType); registry.fill(HIST("hFT0MFV0Asignal"), collision.multFT0A() + collision.multFT0C(), collision.multFV0A()); + registry.fill(HIST("hFT0MsignalPVContr"), collision.multFT0A() + collision.multFT0C(), nTracksPVcontr, evType); } float lEventScale = scalefactor; + int nCandSel = 0; + int nCandAll = 0; for (const auto& casc : Cascades) { // loop over Cascades registry.fill(HIST("hCandidateCounter"), 0.5); // all candidates - registry.fill(HIST("hCandidateCounter"), 1.5); // v0data exists, deprecated - - if (AcceptCascCandidate(casc, collision.posX(), collision.posY(), collision.posZ())) { - registry.fill(HIST("hCandidateCounter"), 2.5); // passed topo cuts + nCandAll++; + if (acceptCascCandidate(casc, collision.posX(), collision.posY(), collision.posZ())) { + registry.fill(HIST("hCandidateCounter"), 1.5); // passed topo cuts + nCandSel++; // Fill table if (fRand->Rndm() < lEventScale) { auto posdau = casc.posTrack_as(); @@ -410,10 +420,13 @@ struct cascqaanalysis { // c x tau float cascpos = std::hypot(casc.x() - collision.posX(), casc.y() - collision.posY(), casc.z() - collision.posZ()); float cascptotmom = std::hypot(casc.px(), casc.py(), casc.pz()); - float ctauXi = pdgDB->Mass(3312) * cascpos / (cascptotmom + 1e-13); - float ctauOmega = pdgDB->Mass(3334) * cascpos / (cascptotmom + 1e-13); + float ctauXi = o2::constants::physics::MassXiMinus * cascpos / (cascptotmom + 1e-13); + float ctauOmega = o2::constants::physics::MassOmegaMinus * cascpos / (cascptotmom + 1e-13); - mycascades(collision.posZ(), collision.centFT0M(), collision.centFV0A(), casc.sign(), casc.pt(), casc.yXi(), casc.yOmega(), casc.eta(), + mycascades(collision.posZ(), + collision.centFT0M(), collision.centFV0A(), + collision.multFT0M(), collision.multFV0A(), + casc.sign(), casc.pt(), casc.yXi(), casc.yOmega(), casc.eta(), casc.mXi(), casc.mOmega(), casc.mLambda(), casc.cascradius(), casc.v0radius(), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()), casc.dcapostopv(), casc.dcanegtopv(), casc.dcabachtopv(), casc.dcacascdaughters(), casc.dcaV0daughters(), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()), @@ -423,10 +436,15 @@ struct cascqaanalysis { posdau.tpcNClsFound(), negdau.tpcNClsFound(), bachelor.tpcNClsFound(), posdau.tpcNClsCrossedRows(), negdau.tpcNClsCrossedRows(), bachelor.tpcNClsCrossedRows(), posdau.hasTOF(), negdau.hasTOF(), bachelor.hasTOF(), - posdau.pt(), negdau.pt(), bachelor.pt(), -1, -1, casc.bachBaryonCosPA(), casc.bachBaryonDCAxyToPV(), evFlag); + posdau.pt(), negdau.pt(), bachelor.pt(), -1, -1, casc.bachBaryonCosPA(), casc.bachBaryonDCAxyToPV(), evFlag, 1e3, 1e3); } } } + + if (candidateQA) { + registry.fill(HIST("hNcandidates"), nCandAll, collision.centFT0M(), 0); + registry.fill(HIST("hNcandidates"), nCandSel, collision.centFT0M(), 1); + } } Preslice perMcCollision = aod::mcparticle::mcCollisionId; @@ -437,14 +455,19 @@ struct cascqaanalysis { aod::V0Datas const&, soa::Filtered const& Cascades, DauTracks const&, - aod::McCollisions const&, + soa::Join const&, // aod::McCentFV0As to be added aod::McParticles const& mcParticles) { - if (!AcceptEvent(collision, 1)) { + if (!acceptEvent(collision, 1)) { return; } - int evType = GetEventTypeFlag(collision); + if (!collision.has_mcCollision()) { + registry.fill(HIST("fakeEvents"), 0); // no assoc. MC collisions + return; + } + + const auto& mcCollision = collision.mcCollision_as>(); // aod::McCentFV0As to be added auto tracksGroupedPVcontr = pvContribTracksIUEta1->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); int nTracksPVcontr = tracksGroupedPVcontr.size(); @@ -453,36 +476,61 @@ struct cascqaanalysis { int nTracksGlobal = tracksGroupedGlobal.size(); // N charged in FT0M region in corresponding gen. MC collision - auto mcPartSlice = mcParticles.sliceBy(perMcCollision, collision.mcCollision_as().globalIndex()); - uint16_t nchFT0 = GetGenNchInFT0Mregion(mcPartSlice); - uint16_t nchFV0 = GetGenNchInFV0Aregion(mcPartSlice); + auto mcPartSlice = mcParticles.sliceBy(perMcCollision, collision.mcCollision_as>().globalIndex()); // mcCollision.centFV0A() to be added + uint16_t nchFT0 = getGenNchInFT0Mregion(mcPartSlice); + uint16_t nchFV0 = getGenNchInFV0Aregion(mcPartSlice); - registry.fill(HIST("hNchFT0MPVContr"), nchFT0, nTracksPVcontr, evType); - registry.fill(HIST("hNchFV0APVContr"), nchFV0, nTracksPVcontr, evType); + int evType = 0; + registry.fill(HIST("hNEvents"), 10.5); // INEL + // Rec. collision associated with INEL>0 gen. one + if (pwglf::isINELgtNmc(mcPartSlice, 0, pdgDB)) { + registry.fill(HIST("hNEvents"), 11.5); // INEL + evType++; + } + // Rec. collision associated with INEL>1 gen. one + if (pwglf::isINELgtNmc(mcPartSlice, 1, pdgDB)) { + registry.fill(HIST("hNEvents"), 12.5); // INEL + evType++; + } + + registry.fill(HIST("hCentFT0M_rec"), mcCollision.centFT0M(), evType); if (multQA) { + registry.fill(HIST("hNchFT0MPVContr"), nchFT0, nTracksPVcontr, evType); + registry.fill(HIST("hNchFV0APVContr"), nchFV0, nTracksPVcontr, evType); + registry.fill(HIST("hFT0MpvContr"), mcCollision.centFT0M(), nTracksPVcontr, evType); + registry.fill(HIST("hFV0ApvContr"), 0, nTracksPVcontr, evType); // mcCollision.centFV0A() to be added + registry.fill(HIST("hFT0Mglobal"), mcCollision.centFT0M(), nTracksGlobal, evType); + registry.fill(HIST("hFV0AFT0M"), 0, mcCollision.centFT0M(), evType); // mcCollision.centFV0A() to be added registry.fill(HIST("hNchFT0Mglobal"), nchFT0, nTracksGlobal, evType); registry.fill(HIST("hFT0MFV0Asignal"), collision.multFT0A() + collision.multFT0C(), collision.multFV0A()); + registry.fill(HIST("hFT0MsignalPVContr"), collision.multFT0A() + collision.multFT0C(), nTracksPVcontr, evType); } float lEventScale = scalefactor; + int nCandSel = 0; + int nCandAll = 0; for (const auto& casc : Cascades) { // loop over Cascades registry.fill(HIST("hCandidateCounter"), 0.5); // all candidates - registry.fill(HIST("hCandidateCounter"), 1.5); // v0data exists - deprecated - - if (AcceptCascCandidate(casc, collision.posX(), collision.posY(), collision.posZ())) { - registry.fill(HIST("hCandidateCounter"), 2.5); // passed topo cuts + nCandAll++; + if (acceptCascCandidate(casc, collision.posX(), collision.posY(), collision.posZ())) { + registry.fill(HIST("hCandidateCounter"), 1.5); // passed topo cuts + nCandSel++; // Check mc association - float lPDG = -1; + float lPDG = 1e3; + float genPt = 1e3; + float genY = 1e3; float isPrimary = -1; if (casc.has_mcParticle()) { - registry.fill(HIST("hCandidateCounter"), 3.5); // has associated MC particle + registry.fill(HIST("hCandidateCounter"), 2.5); // has associated MC particle auto cascmc = casc.mcParticle(); - if (TMath::Abs(cascmc.pdgCode()) == 3312 || TMath::Abs(cascmc.pdgCode()) == 3334) { - registry.fill(HIST("hCandidateCounter"), 4.5); // associated with Xi or Omega + if (std::abs(cascmc.pdgCode()) == PDG_t::kXiMinus || std::abs(cascmc.pdgCode()) == PDG_t::kOmegaMinus) { + registry.fill(HIST("hCandidateCounter"), 3.5); // associated with Xi or Omega lPDG = cascmc.pdgCode(); isPrimary = cascmc.isPhysicalPrimary() ? 1 : 0; + genPt = cascmc.pt(); + genY = cascmc.y(); } } if (fRand->Rndm() < lEventScale) { @@ -518,10 +566,13 @@ struct cascqaanalysis { // c x tau float cascpos = std::hypot(casc.x() - collision.posX(), casc.y() - collision.posY(), casc.z() - collision.posZ()); float cascptotmom = std::hypot(casc.px(), casc.py(), casc.pz()); - float ctauXi = pdgDB->Mass(3312) * cascpos / (cascptotmom + 1e-13); - float ctauOmega = pdgDB->Mass(3334) * cascpos / (cascptotmom + 1e-13); + float ctauXi = o2::constants::physics::MassXiMinus * cascpos / (cascptotmom + 1e-13); + float ctauOmega = o2::constants::physics::MassOmegaMinus * cascpos / (cascptotmom + 1e-13); - mycascades(collision.posZ(), nchFT0, collision.multFV0A(), casc.sign(), casc.pt(), casc.yXi(), casc.yOmega(), casc.eta(), + mycascades(collision.posZ(), + mcCollision.centFT0M(), 0, // mcCollision.centFV0A() to be added + collision.multFT0M(), collision.multFV0A(), + casc.sign(), casc.pt(), casc.yXi(), casc.yOmega(), casc.eta(), casc.mXi(), casc.mOmega(), casc.mLambda(), casc.cascradius(), casc.v0radius(), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()), casc.dcapostopv(), casc.dcanegtopv(), casc.dcabachtopv(), casc.dcacascdaughters(), casc.dcaV0daughters(), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()), @@ -531,13 +582,18 @@ struct cascqaanalysis { posdau.tpcNClsFound(), negdau.tpcNClsFound(), bachelor.tpcNClsFound(), posdau.tpcNClsCrossedRows(), negdau.tpcNClsCrossedRows(), bachelor.tpcNClsCrossedRows(), posdau.hasTOF(), negdau.hasTOF(), bachelor.hasTOF(), - posdau.pt(), negdau.pt(), bachelor.pt(), lPDG, isPrimary, casc.bachBaryonCosPA(), casc.bachBaryonDCAxyToPV(), evFlag); + posdau.pt(), negdau.pt(), bachelor.pt(), lPDG, isPrimary, casc.bachBaryonCosPA(), casc.bachBaryonDCAxyToPV(), evFlag, genPt, genY); } } } + + if (candidateQA) { + registry.fill(HIST("hNcandidates"), nCandAll, mcCollision.centFT0M(), 0); + registry.fill(HIST("hNcandidates"), nCandSel, mcCollision.centFT0M(), 1); + } } - void processMCgen(aod::McCollision const& mcCollision, + void processMCgen(soa::Join::iterator const& mcCollision, // mcCollision.centFV0A() to be added aod::McParticles const& mcParticles, const soa::SmallGroups>& collisions, DauTracks const&) @@ -546,7 +602,7 @@ struct cascqaanalysis { registry.fill(HIST("hNEventsMC"), 0.5); // Generated with accepted z vertex - if (TMath::Abs(mcCollision.posZ()) > cutzvertex) { + if (std::fabs(mcCollision.posZ()) > cutzvertex) { return; } registry.fill(HIST("hZCollisionGen"), mcCollision.posZ()); @@ -558,66 +614,68 @@ struct cascqaanalysis { flagsGen |= o2::aod::myMCcascades::EvFlags::EvINEL; registry.fill(HIST("hNEventsMC"), 2.5); // Generated collision is INEL>0 - if (isINELgtNmc(mcParticles, 0)) { + if (pwglf::isINELgtNmc(mcParticles, 0, pdgDB)) { flagsGen |= o2::aod::myMCcascades::EvFlags::EvINELgt0; evType++; registry.fill(HIST("hNEventsMC"), 3.5); } // Generated collision is INEL>1 - if (isINELgtNmc(mcParticles, 1)) { + if (pwglf::isINELgtNmc(mcParticles, 1, pdgDB)) { flagsGen |= o2::aod::myMCcascades::EvFlags::EvINELgt1; evType++; registry.fill(HIST("hNEventsMC"), 4.5); } - uint16_t nchFT0 = GetGenNchInFT0Mregion(mcParticles); - uint16_t nchFV0 = GetGenNchInFV0Aregion(mcParticles); + registry.fill(HIST("hCentFT0M_genMC"), mcCollision.centFT0M(), evType); + + uint16_t nchFT0 = getGenNchInFT0Mregion(mcParticles); + uint16_t nchFV0 = getGenNchInFV0Aregion(mcParticles); registry.fill(HIST("hNchFT0MGenEvType"), nchFT0, evType); registry.fill(HIST("hNchFV0AGenEvType"), nchFV0, evType); - std::vector SelectedEvents(collisions.size()); - std::vector NumberOfContributors; + std::vector selectedEvents(collisions.size()); + std::vector numberOfContributors; int nevts = 0; int nAssocColl = 0; for (const auto& collision : collisions) { CollisionIndexAndType collWithType = {0, 0x0}; - if (!AcceptEvent(collision, 0)) { + if (!acceptEvent(collision, 0)) { continue; } - collWithType.index = collision.mcCollision_as().globalIndex(); + collWithType.index = collision.mcCollision_as>().globalIndex(); // mcCollision.centFV0A() to be added collWithType.typeFlag |= o2::aod::myMCcascades::EvFlags::EvINEL; - if (collision.multNTracksPVeta1() > 0) { + if (collision.isInelGt0()) { collWithType.typeFlag |= o2::aod::myMCcascades::EvFlags::EvINELgt0; } - if (collision.multNTracksPVeta1() > 1) { + if (collision.isInelGt1()) { collWithType.typeFlag |= o2::aod::myMCcascades::EvFlags::EvINELgt1; } - SelectedEvents[nevts++] = collWithType; - if (collision.mcCollision_as().globalIndex() == mcCollision.globalIndex()) { + selectedEvents[nevts++] = collWithType; + if (collision.mcCollision_as>().globalIndex() == mcCollision.globalIndex()) { // mcCollision.centFV0A() to be added nAssocColl++; - NumberOfContributors.push_back(collision.numContrib()); + numberOfContributors.push_back(collision.numContrib()); } } - SelectedEvents.resize(nevts); + selectedEvents.resize(nevts); registry.fill(HIST("hNchFT0MNAssocMCCollisions"), nchFT0, nAssocColl, evType); - if (NumberOfContributors.size() == 2) { - std::sort(NumberOfContributors.begin(), NumberOfContributors.end()); - registry.fill(HIST("hNContributorsCorrelation"), NumberOfContributors[0], NumberOfContributors[1]); + if (numberOfContributors.size() == 2) { + std::sort(numberOfContributors.begin(), numberOfContributors.end()); + registry.fill(HIST("hNContributorsCorrelation"), numberOfContributors[0], numberOfContributors[1]); } auto isAssocToINEL = [&mcCollision](CollisionIndexAndType i) { return (i.index == mcCollision.globalIndex()) && ((i.typeFlag & o2::aod::myMCcascades::EvFlags::EvINEL) == o2::aod::myMCcascades::EvFlags::EvINEL); }; auto isAssocToINELgt0 = [&mcCollision](CollisionIndexAndType i) { return (i.index == mcCollision.globalIndex()) && ((i.typeFlag & o2::aod::myMCcascades::EvFlags::EvINELgt0) == o2::aod::myMCcascades::EvFlags::EvINELgt0); }; auto isAssocToINELgt1 = [&mcCollision](CollisionIndexAndType i) { return (i.index == mcCollision.globalIndex()) && ((i.typeFlag & o2::aod::myMCcascades::EvFlags::EvINELgt1) == o2::aod::myMCcascades::EvFlags::EvINELgt1); }; // number of reconstructed INEL events that have the same global index as mcCollision - const auto evtReconstructedAndINEL = std::count_if(SelectedEvents.begin(), SelectedEvents.end(), isAssocToINEL); + const auto evtReconstructedAndINEL = std::count_if(selectedEvents.begin(), selectedEvents.end(), isAssocToINEL); // number of reconstructed INEL > 0 events that have the same global index as mcCollision - const auto evtReconstructedAndINELgt0 = std::count_if(SelectedEvents.begin(), SelectedEvents.end(), isAssocToINELgt0); + const auto evtReconstructedAndINELgt0 = std::count_if(selectedEvents.begin(), selectedEvents.end(), isAssocToINELgt0); // number of reconstructed INEL > 1 events that have the same global index as mcCollision - const auto evtReconstructedAndINELgt1 = std::count_if(SelectedEvents.begin(), SelectedEvents.end(), isAssocToINELgt1); + const auto evtReconstructedAndINELgt1 = std::count_if(selectedEvents.begin(), selectedEvents.end(), isAssocToINELgt1); switch (evType) { case 0: { @@ -651,27 +709,29 @@ struct cascqaanalysis { for (const auto& mcParticle : mcParticles) { float sign = 0; - if (mcParticle.pdgCode() == -3312 || mcParticle.pdgCode() == -3334) { + if (mcParticle.pdgCode() == PDG_t::kXiPlusBar || mcParticle.pdgCode() == PDG_t::kOmegaPlusBar) { sign = 1; - } else if (mcParticle.pdgCode() == 3312 || mcParticle.pdgCode() == 3334) { + } else if (mcParticle.pdgCode() == PDG_t::kXiMinus || mcParticle.pdgCode() == PDG_t::kOmegaMinus) { sign = -1; } else { continue; } myMCcascades(mcCollision.posZ(), sign, mcParticle.pdgCode(), mcParticle.y(), mcParticle.eta(), mcParticle.phi(), mcParticle.pt(), - mcParticle.isPhysicalPrimary(), nAssocColl, nchFT0, + mcParticle.isPhysicalPrimary(), nAssocColl, + nchFT0, nchFV0, + mcCollision.centFT0M(), 0, // mcCollision.centFV0A() to be added flagsAssoc, flagsGen); } } - PROCESS_SWITCH(cascqaanalysis, processData, "Process Run 3 data", true); - PROCESS_SWITCH(cascqaanalysis, processMCrec, "Process Run 3 mc, reconstructed", false); - PROCESS_SWITCH(cascqaanalysis, processMCgen, "Process Run 3 mc, genereated", false); + PROCESS_SWITCH(Cascqaanalysis, processData, "Process Run 3 data", true); + PROCESS_SWITCH(Cascqaanalysis, processMCrec, "Process Run 3 mc, reconstructed", false); + PROCESS_SWITCH(Cascqaanalysis, processMCgen, "Process Run 3 mc, genereated", false); }; -struct myCascades { +struct MyCascades { HistogramRegistry registry{"registry"}; @@ -680,7 +740,7 @@ struct myCascades { void init(InitContext const&) { - TString PGDlabels[3] = {"Unknown", "3312", "3334"}; + TString pdglabels[3] = {"Unknown", "3312", "3334"}; registry.add("hPt", "hPt", {HistType::kTH1F, {{100, 0.0f, 10.0f}}}); registry.add("hMassXi", "hMassXi", {HistType::kTH1F, {{1000, 1.0f, 2.0f}}}); registry.add("hMassOmega", "hMassOmega", {HistType::kTH1F, {{1000, 1.0f, 2.0f}}}); @@ -711,8 +771,8 @@ struct myCascades { registry.add("hBachITSHits", "hBachITSHits", {HistType::kTH1F, {{8, -0.5f, 7.5f}}}); registry.add("hIsPrimary", "hIsPrimary", {HistType::kTH1F, {{3, -1.5f, 1.5f}}}); registry.add("hPDGcode", "hPDGcode", {HistType::kTH1F, {{3, -1.5f, 1.5f}}}); - for (Int_t n = 1; n <= registry.get(HIST("hPDGcode"))->GetNbinsX(); n++) { - registry.get(HIST("hPDGcode"))->GetXaxis()->SetBinLabel(n, PGDlabels[n - 1]); + for (int n = 1; n <= registry.get(HIST("hPDGcode"))->GetNbinsX(); n++) { + registry.get(HIST("hPDGcode"))->GetXaxis()->SetBinLabel(n, pdglabels[n - 1]); } registry.add("hBachBaryonCosPA", "hBachBaryonCosPA", {HistType::kTH1F, {{100, 0.0f, 1.0f}}}); registry.add("hBachBaryonDCAxyToPV", "hBachBaryonDCAxyToPV", {HistType::kTH1F, {{300, -3.0f, 3.0f}}}); @@ -721,7 +781,7 @@ struct myCascades { void process(aod::MyCascades const& mycascades) { - for (auto& candidate : mycascades) { + for (const auto& candidate : mycascades) { registry.fill(HIST("hMassXi"), candidate.massxi()); registry.fill(HIST("hMassOmega"), candidate.massomega()); @@ -755,8 +815,8 @@ struct myCascades { registry.fill(HIST("hBachBaryonCosPA"), candidate.bachBaryonCosPA()); registry.fill(HIST("hBachBaryonDCAxyToPV"), candidate.bachBaryonDCAxyToPV()); - if (TMath::Abs(candidate.mcPdgCode()) == 3312 || TMath::Abs(candidate.mcPdgCode()) == 3334) { - registry.fill(HIST("hPDGcode"), TMath::Abs(candidate.mcPdgCode()) == 3312 ? 0 : 1); // 0 if Xi, 1 if Omega + if (std::abs(candidate.mcPdgCode()) == PDG_t::kXiMinus || std::abs(candidate.mcPdgCode()) == PDG_t::kOmegaMinus) { + registry.fill(HIST("hPDGcode"), std::abs(candidate.mcPdgCode()) == PDG_t::kXiMinus ? 0 : 1); // 0 if Xi, 1 if Omega } else { registry.fill(HIST("hPDGcode"), -1); // -1 if unknown } @@ -768,6 +828,6 @@ struct myCascades { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"lf-cascqaanalysis"}), - adaptAnalysisTask(cfgc, TaskName{"lf-mycascades"})}; + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/TableProducer/Strangeness/doubleCascTreeCreator.cxx b/PWGLF/TableProducer/Strangeness/doubleCascTreeCreator.cxx new file mode 100644 index 00000000000..5ecffca742f --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/doubleCascTreeCreator.cxx @@ -0,0 +1,334 @@ +// 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. + +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" + +#include "Common/Core/PID/TPCPIDResponse.h" +#include "Common/DataModel/PIDResponse.h" +#include "DCAFitter/DCAFitterN.h" + +#include "PWGLF/DataModel/LFDoubleCascTables.h" +#include "TDatabasePDG.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using Collisions = soa::Join::iterator; +using FullCascades = aod::CascDataExt; +using TracksFull = soa::Join; + +struct doubleCascCand { + float ptCasc1 = -999.f; // signed pt of the cascade + float etaCasc1 = -999.f; + float phiCasc1 = -999.f; + float cascDecLength1 = -999.f; + float omegaMassCasc1 = -999.f; + float xiMassCasc1 = -999.f; + float cosPACasc1 = -999.f; + float dcaBachPVCasc1 = -999.f; + float dcaV0BachCasc1 = -999.f; + float nSigmaKBach1 = -999.f; + + float ptCasc2 = -999.f; + float etaCasc2 = -999.f; + float phiCasc2 = -999.f; + float cascDecLength2 = -999.f; + float omegaMassCasc2 = -999.f; + float xiMassCasc2 = -999.f; + float cosPACasc2 = -999.f; + float dcaBachPVCasc2 = -999.f; + float dcaV0BachCasc2 = -999.f; + float nSigmaKBach2 = -999.f; + float doubleOmegaMass = -999.f; +}; + +struct doubleCascTreeCreator { + Produces doubleCascTable; + std::vector doubleCascCands; + Service ccdb; + o2::vertexing::DCAFitterN<2> fitter; + + int mRunNumber; + + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + ConfigurableAxis centAxis{"centAxis", {106, 0, 106}, "binning for the centrality"}; + ConfigurableAxis zVtxAxis{"zVtxBins", {100, -20.f, 20.f}, "Binning for the vertex z in cm"}; + + // binning of (anti)lambda mass QA histograms + ConfigurableAxis massOmegaAxis{"massLambdaAxis", {400, o2::constants::physics::MassOmegaMinus - 0.05f, o2::constants::physics::MassOmegaMinus + 0.035}, "binning for the Omega invariant-mass"}; + ConfigurableAxis massXiAxis{"massXiAxis", {400, o2::constants::physics::MassXiMinus - 0.05f, o2::constants::physics::MassXiMinus + 0.05f}, "binning for the Xi invariant-mass"}; + + Configurable zVtxMax{"zVtxMax", 10.0f, "maximum z position of the primary vertex"}; + Configurable etaMax{"etaMax", 0.9f, "maximum eta"}; + ConfigurableAxis momAxis{"momAxisFine", {5.e2, 0.f, 5.f}, "momentum axis binning"}; + + Configurable cascPtMin{"cascPtMin", 1.f, "minimum (anti)casc pT (GeV/c)"}; + Configurable cascPtMax{"cascPtMax", 4.f, "maximum (anti)casc pT (GeV/c)"}; + + Configurable minNCrossedRows{"minNCrossedRows", 100, "Minimum number of crossed TPC rows"}; + Configurable minNITSClus{"minNITSClus", 0., "Minimum number of ITS clusters"}; + Configurable minNTPCClus{"minNTPCClus", 100, "Minimum number of TPC clusters"}; + Configurable maxNSharedTPCClus{"maxNSharedTPCClus", 5, "Maximum number of shared TPC clusters"}; + + Configurable minCascCosPA{"minCascCosPA", 0.99f, "Minimum cosine of the pointing angle of the cascade"}; + Configurable nSigmaTPCCut{"nSigmaTPCCut", 3.f, "Number of sigmas for the TPC PID"}; + Configurable dcaBachToPV{"dcaBachToPV", 0.05f, "DCA of the bachelor to the primary vertex"}; + Configurable dcaV0Bach{"dcaV0Bach", 1.f, "DCA between the V0 daughters"}; + Configurable mXiWindow{"mXiWindow", 0.02f, "mXiWindow"}; + Configurable mOmegaWindow{"mOmegaWindow", 0.01f, "mOmegaWindow"}; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + template + bool selectTrack(T const& track) + { + if (std::abs(track.eta()) > etaMax) { + return false; + } + if (track.itsNCls() < minNITSClus || + track.tpcNClsFound() < minNTPCClus || + track.tpcNClsCrossedRows() < minNCrossedRows || + track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || + track.tpcNClsShared() > maxNSharedTPCClus) { + return false; + } + return true; + } + + template + void initCCDB(Bc const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + auto timestamp = bc.timestamp(); + LOG(info) << "Retrieved GRP for timestamp " << timestamp; + mRunNumber = bc.runNumber(); + if (cfgSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), "fDoubleOmega,fOmegaXi"); + zorro.populateHistRegistry(histos, bc.runNumber()); + } + } + + void init(o2::framework::InitContext&) + { + mRunNumber = 0; + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + zorroSummary.setObject(zorro.getZorroSummary()); + + // event QA + histos.add("QA/zVtx", ";#it{z}_{vtx} (cm);Entries", HistType::kTH1F, {zVtxAxis}); + histos.add("QA/massXi", ";#it{p}_{T} (GeV/#it{c});#it{M}(#Lambda + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH2F, {momAxis, massXiAxis}); + histos.add("QA/massOmega", ";#it{p}_{T} (GeV/#it{c});#it{M}(#Omega + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH2F, {momAxis, massOmegaAxis}); + } + + template + bool isSelectedCasc(C const& collision, T const&, FullCascades::iterator const& casc) + { + + auto bachelor = casc.bachelor_as(); + auto posDau = casc.posTrack_as(); + auto negDau = casc.negTrack_as(); + + if (!selectTrack(bachelor) || !selectTrack(posDau) || !selectTrack(negDau)) { + return false; + } + if (casc.sign() > 0) { + if (TMath::Abs(posDau.tpcNSigmaPi()) > nSigmaTPCCut || TMath::Abs(negDau.tpcNSigmaPr()) > nSigmaTPCCut) { + return false; + } + } else if (casc.sign() < 0) { + if (TMath::Abs(negDau.tpcNSigmaPi()) > nSigmaTPCCut || TMath::Abs(posDau.tpcNSigmaPr()) > nSigmaTPCCut) { + return false; + } + } + if (TMath::Abs(casc.dcabachtopv()) < dcaBachToPV) { + return false; + } + if (TMath::Abs(casc.dcacascdaughters()) > dcaV0Bach) { + return false; + } + if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < minCascCosPA) { + return false; + } + if (TMath::Abs(casc.eta()) > etaMax) { + return false; + } + // mass cuts + bool massInWindow = false; + if (casc.mOmega() > o2::constants::physics::MassOmegaMinus - mOmegaWindow && casc.mOmega() < o2::constants::physics::MassOmegaMinus + mOmegaWindow) { + massInWindow = true; + } + if (casc.mXi() > o2::constants::physics::MassXiMinus - mXiWindow && casc.mXi() < o2::constants::physics::MassXiMinus + mXiWindow) { + massInWindow = true; + } + if (!massInWindow) { + return false; + } + return true; + }; + + template + bool doubleOmegaMass(T const&, FullCascades::iterator const& casc1, FullCascades::iterator const& casc2) + { + // the fake omega decay is the one with the smaller radius + auto& fakeOmega = casc1.cascradius() < casc2.cascradius() ? casc1 : casc2; + auto& realOmega = casc1.cascradius() < casc2.cascradius() ? casc2 : casc1; + auto kaon = fakeOmega.bachelor_as(); + float momKaon[3] = {kaon.px(), kaon.py(), kaon.pz()}; + float momLambda[3] = {fakeOmega.pxlambda(), fakeOmega.pylambda(), fakeOmega.pzlambda()}; + // now compute real Omega-lambda-kaon mass + float momTot[3] = {momKaon[0] + momLambda[0] + realOmega.px(), momKaon[1] + momLambda[1] + realOmega.py(), momKaon[2] + momLambda[2] + realOmega.pz()}; + float eK = std::sqrt(o2::constants::physics::MassKaonCharged * o2::constants::physics::MassKaonCharged + momKaon[0] * momKaon[0] + momKaon[1] * momKaon[1] + momKaon[2] * momKaon[2]); + float eL = std::sqrt(o2::constants::physics::MassLambda0 * o2::constants::physics::MassLambda0 + momLambda[0] * momLambda[0] + momLambda[1] * momLambda[1] + momLambda[2] * momLambda[2]); + float eO = std::sqrt(o2::constants::physics::MassOmegaMinus * o2::constants::physics::MassOmegaMinus + momTot[0] * momTot[0] + momTot[1] * momTot[1] + momTot[2] * momTot[2]); + float eTot = eK + eL + eO; + float mass = std::sqrt(eTot * eTot - momTot[0] * momTot[0] - momTot[1] * momTot[1] - momTot[2] * momTot[2]); + return mass; + } + + template + void fillDoubleCasc(C const& collision, T const& tracks, FullCascades const& cascades) + { + doubleCascCands.clear(); + + for (auto& casc1 : cascades) { + if (!isSelectedCasc(collision, tracks, casc1)) { + continue; + } + for (auto& casc2 : cascades) { + if (!isSelectedCasc(collision, tracks, casc2)) { + continue; + } + + if (casc1.posTrackId() == casc2.posTrackId() || casc1.posTrackId() == casc2.negTrackId() || casc1.bachelorId() == casc2.bachelorId()) { + continue; + } + + auto bach1 = casc1.bachelor_as(); + auto bach2 = casc2.bachelor_as(); + + doubleCascCand cand; + cand.ptCasc1 = casc1.pt(); + cand.etaCasc1 = casc1.eta(); + cand.phiCasc1 = casc1.phi(); + cand.cascDecLength1 = std::hypot(casc1.x() - collision.posX(), casc1.y() - collision.posY(), casc1.z() - collision.posZ()); + cand.omegaMassCasc1 = casc1.mOmega(); + cand.xiMassCasc1 = casc1.mXi(); + cand.cosPACasc1 = casc1.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); + cand.dcaBachPVCasc1 = casc1.dcabachtopv(); + cand.dcaV0BachCasc1 = casc1.dcacascdaughters(); + cand.nSigmaKBach1 = bach1.tpcNSigmaKa(); + + cand.ptCasc2 = casc2.pt(); + cand.etaCasc2 = casc2.eta(); + cand.phiCasc2 = casc2.phi(); + cand.cascDecLength2 = std::hypot(casc2.x() - collision.posX(), casc2.y() - collision.posY(), casc2.z() - collision.posZ()); + cand.omegaMassCasc2 = casc2.mOmega(); + cand.xiMassCasc2 = casc2.mXi(); + cand.cosPACasc2 = casc2.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); + cand.dcaBachPVCasc2 = casc2.dcabachtopv(); + cand.dcaV0BachCasc2 = casc2.dcacascdaughters(); + cand.nSigmaKBach2 = bach2.tpcNSigmaKa(); + + cand.doubleOmegaMass = doubleOmegaMass(tracks, casc1, casc2); + + doubleCascCands.push_back(cand); + } + } + }; + + void processData(Collisions const& collision, TracksFull const& tracks, FullCascades const& cascades, aod::BCsWithTimestamps const&) + { + auto bc = collision.bc_as(); + initCCDB(bc); + + if (!collision.sel8()) + return; + + if (std::abs(collision.posZ()) > zVtxMax) + return; + + if (!collision.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + return; + + if (cfgSkimmedProcessing) { + zorro.isSelected(collision.bc_as().globalBC()); /// Just let Zorro do the accounting + } + histos.fill(HIST("QA/zVtx"), collision.posZ()); + fillDoubleCasc(collision, tracks, cascades); + + for (auto& cand : doubleCascCands) { + doubleCascTable( + cand.ptCasc1, + cand.etaCasc1, + cand.phiCasc1, + cand.cascDecLength1, + cand.omegaMassCasc1, + cand.xiMassCasc1, + cand.cosPACasc1, + cand.dcaBachPVCasc1, + cand.dcaV0BachCasc1, + cand.nSigmaKBach1, + cand.ptCasc2, + cand.etaCasc2, + cand.phiCasc2, + cand.cascDecLength2, + cand.omegaMassCasc2, + cand.xiMassCasc2, + cand.cosPACasc2, + cand.dcaBachPVCasc2, + cand.dcaV0BachCasc2, + cand.nSigmaKBach2, + cand.doubleOmegaMass); + } + } + PROCESS_SWITCH(doubleCascTreeCreator, processData, "process (Run 3)", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx b/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx index 4c84b1d3279..082d04f6bb5 100644 --- a/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx +++ b/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx @@ -12,6 +12,7 @@ /// \brief This task pre-filters tracks, V0s and cascades to do h-strangeness /// correlations with an analysis task. /// +/// \file hStrangeCorrelationFilter.cxx /// \author Kai Cui (kaicui@mails.ccnu.edu.cn) /// \author Lucia Anna Tarasovicova (lucia.anna.husova@cern.ch) /// \author David Dobrigkeit Chinellato (david.dobrigkeit.chinellato@cern.ch) @@ -27,36 +28,51 @@ #include "Framework/ASoAHelpers.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Centrality.h" +#include "CCDB/BasicCCDBManager.h" #include "TF1.h" +#include "string" + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" using namespace o2; +using namespace o2::constants::math; using namespace o2::framework; using namespace o2::framework::expressions; -#define bitcheck(var, nbit) ((var) & (1 << (nbit))) +#define BIT_SET(var, nbit) ((var) |= (1 << (nbit))) +#define BIT_CHECK(var, nbit) ((var) & (1 << (nbit))) + +struct HStrangeCorrelationFilter { + Service ccdb; -struct hstrangecorrelationfilter { HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; // Operational Configurable fillTableOnlyWithCompatible{"fillTableOnlyWithCompatible", true, "pre-apply dE/dx, broad mass window in table filling"}; - Configurable strangedEdxNSigma{"strangedEdxNSigma", 5, "Nsigmas for strange decay daughters"}; + Configurable strangedEdxNSigmaLoose{"strangedEdxNSigmaLoose", 5, "Nsigmas for strange decay daughters"}; + Configurable strangedEdxNSigma{"strangedEdxNSigma", 4, "Nsigmas for strange decay daughters"}; + Configurable strangedEdxNSigmaTight{"strangedEdxNSigmaTight", 3, "Nsigmas for strange decay daughters"}; + + // event filtering + Configurable zorroMask{"zorroMask", "", "zorro trigger class to select on (empty: none)"}; // Trigger particle selections in phase space - Configurable triggerEtaMin{"triggerEtaCutMin", -0.8, "triggeretamin"}; - Configurable triggerEtaMax{"triggerEtaCutMax", 0.8, "triggeretamax"}; + Configurable triggerEtaMin{"triggerEtaMin", -0.8, "triggeretamin"}; + Configurable triggerEtaMax{"triggerEtaMax", 0.8, "triggeretamax"}; Configurable triggerPtCutMin{"triggerPtCutMin", 3, "triggerptmin"}; Configurable triggerPtCutMax{"triggerPtCutMax", 20, "triggerptmax"}; // Track quality Configurable minTPCNCrossedRows{"minTPCNCrossedRows", 70, "Minimum TPC crossed rows"}; Configurable triggerRequireITS{"triggerRequireITS", true, "require ITS signal in trigger tracks"}; + Configurable assocRequireITS{"assocRequireITS", true, "require ITS signal in assoc tracks"}; Configurable triggerMaxTPCSharedClusters{"triggerMaxTPCSharedClusters", 200, "maximum number of shared TPC clusters (inclusive)"}; Configurable triggerRequireL0{"triggerRequireL0", false, "require ITS L0 cluster for trigger"}; // Associated particle selections in phase space - Configurable assocEtaMin{"assocEtaCutMin", -0.8, "triggeretamin"}; - Configurable assocEtaMax{"assocEtaCutMax", 0.8, "triggeretamax"}; + Configurable assocEtaMin{"assocEtaMin", -0.8, "triggeretamin"}; + Configurable assocEtaMax{"assocEtaMax", 0.8, "triggeretamax"}; Configurable assocPtCutMin{"assocPtCutMin", 0.2, "assocptmin"}; Configurable assocPtCutMax{"assocPtCutMax", 10, "assocptmax"}; @@ -66,12 +82,12 @@ struct hstrangecorrelationfilter { Configurable rejectSigma{"rejectSigma", 1, "n sigma for rejecting pion candidates"}; // V0 selections - Configurable v0Cospa{"v0cospa", 0.97, "V0 CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0) - Configurable dcaV0dau{"dcav0dau", 1.0, "DCA V0 Daughters"}; - Configurable dcaNegtopv{"dcanegtopv", 0.06, "DCA Neg To PV"}; - Configurable dcaPostopv{"dcapostopv", 0.06, "DCA Pos To PV"}; - Configurable v0RadiusMin{"v0radiusmin", 0.5, "v0radius"}; - Configurable v0RadiusMax{"v0radiusmax", 200, "v0radius"}; + Configurable v0Cospa{"v0Cospa", 0.97, "V0 CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0) + Configurable dcaV0dau{"dcaV0dau", 1.0, "DCA V0 Daughters"}; + Configurable dcaNegtopv{"dcaNegtopv", 0.06, "DCA Neg To PV"}; + Configurable dcaPostopv{"dcaPostopv", 0.06, "DCA Pos To PV"}; + Configurable v0RadiusMin{"v0RadiusMin", 0.5, "v0radius"}; + Configurable v0RadiusMax{"v0RadiusMax", 200, "v0radius"}; // specific selections Configurable lambdaCospa{"lambdaCospa", 0.995, "CosPA for lambda"}; // allows for tighter selection for Lambda @@ -82,29 +98,28 @@ struct hstrangecorrelationfilter { Configurable dcaXYpTdep{"dcaXYpTdep", 0.013, "[1] in |DCAxy| < [0]+[1]/pT"}; // cascade selections - Configurable cascadesetting_cospa{"cascadesetting_cospa", 0.95, "cascadesetting_cospa"}; - Configurable cascadesetting_dcacascdau{"cascadesetting_dcacascdau", 1.0, "cascadesetting_dcacascdau"}; - Configurable cascadesetting_dcabachtopv{"cascadesetting_dcabachtopv", 0.1, "cascadesetting_dcabachtopv"}; - Configurable cascadesetting_cascradius{"cascadesetting_cascradius", 0.5, "cascadesetting_cascradius"}; - Configurable cascadesetting_v0masswindow{"cascadesetting_v0masswindow", 0.01, "cascadesetting_v0masswindow"}; - Configurable cascadesetting_mindcav0topv{"cascadesetting_mindcav0topv", 0.01, "cascadesetting_mindcav0topv"}; + Configurable cascadeSettingCospa{"cascadeSettingCospa", 0.95, "cascadeSettingCospa"}; + Configurable cascadeSettingDcacascdau{"cascadeSettingDcacascdau", 1.0, "cascadeSettingDcacascdau"}; + Configurable cascadeSettingDcabachtopv{"cascadeSettingDcabachtopv", 0.1, "cascadeSettingDcabachtopv"}; + Configurable cascadeSettingCascradius{"cascadeSettingCascradius", 0.5, "cascadeSettingCascradius"}; + Configurable cascadeSettingV0masswindow{"cascadeSettingV0masswindow", 0.01, "cascadeSettingV0masswindow"}; + Configurable cascadeSettingMindcav0topv{"cascadeSettingMindcav0topv", 0.01, "cascadeSettingMindcav0topv"}; // invariant mass parametrizations - Configurable> massParsK0Mean{"massParsK0Mean", {0.495, 0.000250, 0.0, 0.0}, "pars in [0]+[1]*x+[2]*TMath::Exp(-[3]*x)"}; - Configurable> massParsK0Width{"massParsK0Width", {0.00354, 0.000609, 0.0, 0.0}, "pars in [0]+[1]*x+[2]*TMath::Exp(-[3]*x)"}; + Configurable> massParsK0Mean{"massParsK0Mean", {0.495, 0.000250, 0.0, 0.0}, "pars in [0]+[1]*x+[2]*std::exp(-[3]*x)"}; + Configurable> massParsK0Width{"massParsK0Width", {0.00354, 0.000609, 0.0, 0.0}, "pars in [0]+[1]*x+[2]*std::exp(-[3]*x)"}; - Configurable> massParsLambdaMean{"massParsLambdaMean", {1.114, 0.000314, 0.140, 11.9}, "pars in [0]+[1]*x+[2]*TMath::Exp(-[3]*x)"}; - Configurable> massParsLambdaWidth{"massParsLambdaWidth", {0.00127, 0.000172, 0.00261, 2.02}, "pars in [0]+[1]*x+[2]*TMath::Exp(-[3]*x)"}; + Configurable> massParsLambdaMean{"massParsLambdaMean", {1.114, 0.000314, 0.140, 11.9}, "pars in [0]+[1]*x+[2]*std::exp(-[3]*x)"}; + Configurable> massParsLambdaWidth{"massParsLambdaWidth", {0.00127, 0.000172, 0.00261, 2.02}, "pars in [0]+[1]*x+[2]*std::exp(-[3]*x)"}; - Configurable> massParsCascadeMean{"massParsCascadeMean", {1.32, 0.000278, 0.0, 0.0}, "pars in [0]+[1]*x+[2]*TMath::Exp(-[3]*x)"}; - Configurable> massParsCascadeWidth{"massParsCascadeWidth", {0.00189, 0.000227, 0.00370, 1.635}, "pars in [0]+[1]*x+[2]*TMath::Exp(-[3]*x)"}; + Configurable> massParsCascadeMean{"massParsCascadeMean", {1.32, 0.000278, 0.0, 0.0}, "pars in [0]+[1]*x+[2]*std::exp(-[3]*x)"}; + Configurable> massParsCascadeWidth{"massParsCascadeWidth", {0.00189, 0.000227, 0.00370, 1.635}, "pars in [0]+[1]*x+[2]*std::exp(-[3]*x)"}; - Configurable> massParsOmegaMean{"massParsOmegaMean", {1.67, 0.000298, 0.0, 0.0}, "pars in [0]+[1]*x+[2]*TMath::Exp(-[3]*x)"}; - Configurable> massParsOmegaWidth{"massParsOmegaWidth", {0.00189, 0.000325, 0.00606, 1.77}, "pars in [0]+[1]*x+[2]*TMath::Exp(-[3]*x)"}; + Configurable> massParsOmegaMean{"massParsOmegaMean", {1.67, 0.000298, 0.0, 0.0}, "pars in [0]+[1]*x+[2]*std::exp(-[3]*x)"}; + Configurable> massParsOmegaWidth{"massParsOmegaWidth", {0.00189, 0.000325, 0.00606, 1.77}, "pars in [0]+[1]*x+[2]*std::exp(-[3]*x)"}; - // definitions of peak and background - Configurable peakNsigma{"peakNsigma", 3.0f, "peak region is +/- this many sigmas away"}; - Configurable backgroundNsigma{"backgroundNsigma", 6.0f, "bg region is +/- this many sigmas away (minus peak)"}; + // must include windows for background and peak + Configurable maxMassNSigma{"maxMassNSigma", 12.0f, "max mass region to be considered for further analysis"}; // For extracting strangeness mass QA plots ConfigurableAxis axisPtQA{"axisPtQA", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for QA histograms"}; @@ -114,40 +129,53 @@ struct hstrangecorrelationfilter { ConfigurableAxis axisOmegaMass{"axisOmegaMass", {200, 1.57f, 1.77f}, "Inv. Mass (GeV/c^{2})"}; ConfigurableAxis axisMult{"axisMult", {VARIABLE_WIDTH, 0.0f, 0.01f, 1.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 70.0f, 100.0f}, "Centrality percentile bins"}; + // QA + Configurable doTrueSelectionInMass{"doTrueSelectionInMass", false, "Fill mass histograms only with true primary Particles for MC"}; // Do declarative selections for DCAs, if possible Filter preFilterTracks = nabs(aod::track::dcaXY) < dcaXYconstant + dcaXYpTdep * nabs(aod::track::signed1Pt); Filter preFilterV0 = nabs(aod::v0data::dcapostopv) > dcaPostopv&& nabs(aod::v0data::dcanegtopv) > dcaNegtopv&& aod::v0data::dcaV0daughters < dcaV0dau; Filter preFilterCascade = - nabs(aod::cascdata::dcapostopv) > dcaPostopv&& nabs(aod::cascdata::dcanegtopv) > dcaNegtopv&& nabs(aod::cascdata::dcabachtopv) > cascadesetting_dcabachtopv&& aod::cascdata::dcaV0daughters < dcaV0dau&& aod::cascdata::dcacascdaughters < cascadesetting_dcacascdau; - - // histogram defined with HistogramRegistry - HistogramRegistry registry{ - "registry", - {}}; - using V0LinkedTagged = soa::Join; - using CascadesLinkedTagged = soa::Join; + nabs(aod::cascdata::dcapostopv) > dcaPostopv&& nabs(aod::cascdata::dcanegtopv) > dcaNegtopv&& nabs(aod::cascdata::dcabachtopv) > cascadeSettingDcabachtopv&& aod::cascdata::dcaV0daughters < dcaV0dau&& aod::cascdata::dcacascdaughters < cascadeSettingDcacascdau; + + // using V0LinkedTagged = soa::Join; + // using CascadesLinkedTagged = soa::Join; + using FullTracks = soa::Join; + using FullTracksMC = soa::Join; using DauTracks = soa::Join; + using DauTracksMC = soa::Join; // using IDTracks= soa::Join; // prepared for Bayesian PID - using IDTracks = soa::Join; + using IDTracks = soa::Join; + using IDTracksMC = soa::Join; using V0DatasWithoutTrackX = soa::Join; + using V0DatasWithoutTrackXMC = soa::Join; + using CascDatasMC = soa::Join; Produces triggerTrack; - Produces assocPion; + Produces triggerTrackExtra; Produces assocV0; Produces assocCascades; - - TF1* fK0Mean = new TF1("fK0Mean", "[0]+[1]*x+[2]*TMath::Exp(-[3]*x)"); - TF1* fK0Width = new TF1("fK0Width", "[0]+[1]*x+[2]*TMath::Exp(-[3]*x)"); - TF1* fLambdaMean = new TF1("fLambdaMean", "[0]+[1]*x+[2]*TMath::Exp(-[3]*x)"); - TF1* fLambdaWidth = new TF1("fLambdaWidth", "[0]+[1]*x+[2]*TMath::Exp(-[3]*x)"); - TF1* fXiMean = new TF1("fXiMean", "[0]+[1]*x+[2]*TMath::Exp(-[3]*x)"); - TF1* fXiWidth = new TF1("fXiWidth", "[0]+[1]*x+[2]*TMath::Exp(-[3]*x)"); - TF1* fOmegaMean = new TF1("fomegaMean", "[0]+[1]*x+[2]*TMath::Exp(-[3]*x)"); - TF1* fOmegaWidth = new TF1("fomegaWidth", "[0]+[1]*x+[2]*TMath::Exp(-[3]*x)"); + Produces assocHadrons; + Produces assocPID; + + TF1* fK0Mean = new TF1("fK0Mean", "[0]+[1]*x+[2]*std::exp(-[3]*x)"); + TF1* fK0Width = new TF1("fK0Width", "[0]+[1]*x+[2]*std::exp(-[3]*x)"); + TF1* fLambdaMean = new TF1("fLambdaMean", "[0]+[1]*x+[2]*std::exp(-[3]*x)"); + TF1* fLambdaWidth = new TF1("fLambdaWidth", "[0]+[1]*x+[2]*std::exp(-[3]*x)"); + TF1* fXiMean = new TF1("fXiMean", "[0]+[1]*x+[2]*std::exp(-[3]*x)"); + TF1* fXiWidth = new TF1("fXiWidth", "[0]+[1]*x+[2]*std::exp(-[3]*x)"); + TF1* fOmegaMean = new TF1("fomegaMean", "[0]+[1]*x+[2]*std::exp(-[3]*x)"); + TF1* fOmegaWidth = new TF1("fomegaWidth", "[0]+[1]*x+[2]*std::exp(-[3]*x)"); + + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + int mRunNumber; void init(InitContext const&) { + zorroSummary.setObject(zorro.getZorroSummary()); + mRunNumber = -1; + fK0Mean->SetParameters(massParsK0Mean->at(0), massParsK0Mean->at(1), massParsK0Mean->at(2), massParsK0Mean->at(3)); fK0Width->SetParameters(massParsK0Width->at(0), massParsK0Width->at(1), massParsK0Width->at(2), massParsK0Width->at(3)); fLambdaMean->SetParameters(massParsLambdaMean->at(0), massParsLambdaMean->at(1), massParsLambdaMean->at(2), massParsLambdaMean->at(3)); @@ -166,242 +194,528 @@ struct hstrangecorrelationfilter { histos.add("h3dMassOmegaPlus", "h3dMassOmegaPlus", kTH3F, {axisPtQA, axisOmegaMass, axisMult}); } - void processTriggers(soa::Join::iterator const& collision, soa::Filtered const& tracks) + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), zorroMask.value); + zorro.populateHistRegistry(histos, bc.runNumber()); + + mRunNumber = bc.runNumber(); + } + + // reco-level trigger quality checks (N.B.: DCA is filtered, not selected) + template + bool isValidTrigger(TTrack track) + { + if (track.eta() > triggerEtaMax || track.eta() < triggerEtaMin) { + return false; + } + // if (track.sign()= 1 ) {continue;} + if (track.pt() > triggerPtCutMax || track.pt() < triggerPtCutMin) { + return false; + } + if (track.tpcNClsCrossedRows() < minTPCNCrossedRows) { + return false; // crossed rows + } + if (!track.hasITS() && triggerRequireITS) { + return false; // skip, doesn't have ITS signal (skips lots of TPC-only!) + } + if (track.tpcNClsShared() > triggerMaxTPCSharedClusters) { + return false; // skip, has shared clusters + } + if (!(BIT_CHECK(track.itsClusterMap(), 0)) && triggerRequireL0) { + return false; // skip, doesn't have cluster in ITS L0 + } + return true; + } + template + bool isValidAssocTrack(TTrack assoc) + { + if (assoc.eta() > assocEtaMax || assoc.eta() < assocEtaMin) { + return false; + } + if (assoc.pt() > assocPtCutMax || assoc.pt() < assocPtCutMin) { + return false; + } + if (assoc.tpcNClsCrossedRows() < minTPCNCrossedRows) { + return false; // crossed rows + } + if (!assoc.hasITS() && assocRequireITS) { + return false; // skip, doesn't have ITS signal (skips lots of TPC-only!) + } + + // do this only if information is available + float nSigmaTPCTOF[8] = {-10, -10, -10, -10, -10, -10, -10, -10}; + if constexpr (requires { assoc.tofSignal(); }) { + if (assoc.tofSignal() > 0) { + if (std::sqrt(assoc.tofNSigmaPi() * assoc.tofNSigmaPi() + assoc.tpcNSigmaPi() * assoc.tpcNSigmaPi()) > assocPionNSigmaTPCFOF) + return false; + if (assoc.tofNSigmaPr() < rejectSigma) + return false; + if (assoc.tpcNSigmaPr() < rejectSigma) + return false; + if (assoc.tofNSigmaKa() < rejectSigma) + return false; + if (assoc.tpcNSigmaKa() < rejectSigma) + return false; + nSigmaTPCTOF[4] = assoc.tofNSigmaPi(); + nSigmaTPCTOF[5] = assoc.tofNSigmaKa(); + nSigmaTPCTOF[6] = assoc.tofNSigmaPr(); + nSigmaTPCTOF[7] = assoc.tofNSigmaEl(); + } else { + if (assoc.tpcNSigmaPi() > assocPionNSigmaTPCFOF) + return false; + if (assoc.tpcNSigmaPr() < rejectSigma) + return false; + if (assoc.tpcNSigmaKa() < rejectSigma) + return false; + } + nSigmaTPCTOF[0] = assoc.tpcNSigmaPi(); + nSigmaTPCTOF[1] = assoc.tpcNSigmaKa(); + nSigmaTPCTOF[2] = assoc.tpcNSigmaPr(); + nSigmaTPCTOF[3] = assoc.tpcNSigmaEl(); + } + + bool physicalPrimary = false; + float origPt = -1; + if constexpr (requires { assoc.mcParticle(); }) { + if (assoc.has_mcParticle()) { + auto mcParticle = assoc.mcParticle(); + physicalPrimary = mcParticle.isPhysicalPrimary(); + origPt = mcParticle.pt(); + } + } + + assocHadrons( + assoc.collisionId(), + physicalPrimary, + assoc.globalIndex(), + origPt); + assocPID( + nSigmaTPCTOF[0], + nSigmaTPCTOF[1], + nSigmaTPCTOF[2], + nSigmaTPCTOF[3], + nSigmaTPCTOF[4], + nSigmaTPCTOF[5], + nSigmaTPCTOF[6], + nSigmaTPCTOF[7]); + return true; + } + + // for real data processing + void processTriggers(soa::Join::iterator const& collision, soa::Filtered const& tracks, aod::BCsWithTimestamps const&) { // Perform basic event selection if (!collision.sel8()) { return; } // No need to correlate stuff that's in far collisions - if (TMath::Abs(collision.posZ()) > 10.0) { + if (std::abs(collision.posZ()) > 10.0) { return; } + if (zorroMask.value != "") { + auto bc = collision.bc_as(); + initCCDB(bc); + bool zorroSelected = zorro.isSelected(collision.bc_as().globalBC()); /// Just let Zorro do the accounting + if (!zorroSelected) { + return; + } + } /// _________________________________________________ /// Step 1: Populate table with trigger tracks for (auto const& track : tracks) { - if (track.eta() > triggerEtaMax || track.eta() < triggerEtaMin) { + if (!isValidTrigger(track)) continue; + triggerTrack( + track.collisionId(), + false, // if you decide to check real data for primaries, you'll have a hard time + track.globalIndex(), + 0); + triggerTrackExtra(1); + } + } + + // for MC processing + void processTriggersMC(soa::Join::iterator const& collision, soa::Filtered const& tracks, aod::McParticles const&, aod::BCsWithTimestamps const&) + { + // Perform basic event selection + if (!collision.sel8()) { + return; + } + // No need to correlate stuff that's in far collisions + if (std::abs(collision.posZ()) > 10.0) { + return; + } + if (zorroMask.value != "") { + auto bc = collision.bc_as(); + initCCDB(bc); + bool zorroSelected = zorro.isSelected(collision.bc_as().globalBC()); /// Just let Zorro do the accounting + if (!zorroSelected) { + return; } - // if (track.sign()= 1 ) {continue;} - if (track.pt() > triggerPtCutMax || track.pt() < triggerPtCutMin) { + } + + /// _________________________________________________ + /// Step 1: Populate table with trigger tracks + for (auto const& track : tracks) { + if (!isValidTrigger(track)) continue; - } - if (track.tpcNClsCrossedRows() < minTPCNCrossedRows) { - continue; // crossed rows - } - if (!track.hasITS() && triggerRequireITS) { - continue; // skip, doesn't have ITS signal (skips lots of TPC-only!) - } - if (track.tpcNClsShared() > triggerMaxTPCSharedClusters) { - continue; // skip, has shared clusters - } - if (!(bitcheck(track.itsClusterMap(), 0)) && triggerRequireL0) { - continue; // skip, doesn't have cluster in ITS L0 + bool physicalPrimary = false; + float origPt = -1; + if (track.has_mcParticle()) { + auto mcParticle = track.mcParticle(); + physicalPrimary = mcParticle.isPhysicalPrimary(); + origPt = mcParticle.pt(); } triggerTrack( track.collisionId(), - track.globalIndex()); + physicalPrimary, + track.globalIndex(), + origPt); + triggerTrackExtra(1); } } - void processAssocPions(soa::Join::iterator const& collision, soa::Filtered const& tracks) + + void processAssocPions(soa::Join::iterator const& collision, soa::Filtered const& tracks, aod::BCsWithTimestamps const&) { // Perform basic event selection if (!collision.sel8()) { return; } // No need to correlate stuff that's in far collisions - if (TMath::Abs(collision.posZ()) > 10.0) { + if (std::abs(collision.posZ()) > 10.0) { return; } + if (zorroMask.value != "") { + auto bc = collision.bc_as(); + initCCDB(bc); + bool zorroSelected = zorro.isSelected(collision.bc_as().globalBC()); /// Just let Zorro do the accounting + if (!zorroSelected) { + return; + } + } /// _________________________________________________ /// Step 1: Populate table with trigger tracks for (auto const& track : tracks) { - if (track.eta() > assocEtaMax || track.eta() < assocEtaMin) { + if (!isValidAssocTrack(track)) continue; + } + } + + void processAssocPionsMC(soa::Join::iterator const& collision, soa::Filtered const& tracks, aod::BCsWithTimestamps const&) + { + // Perform basic event selection + if (!collision.sel8()) { + return; + } + // No need to correlate stuff that's in far collisions + if (std::abs(collision.posZ()) > 10.0) { + return; + } + if (zorroMask.value != "") { + auto bc = collision.bc_as(); + initCCDB(bc); + bool zorroSelected = zorro.isSelected(collision.bc_as().globalBC()); /// Just let Zorro do the accounting + if (!zorroSelected) { + return; } - // if (track.sign()= 1 ) {continue;} - if (track.pt() > assocPtCutMax || track.pt() < assocPtCutMin) { + } + + /// _________________________________________________ + /// Step 1: Populate table with trigger tracks + for (auto const& track : tracks) { + if (!isValidAssocTrack(track)) continue; + } + } + + void processAssocHadrons(soa::Join::iterator const& collision, soa::Filtered const& tracks, aod::BCsWithTimestamps const&) + { + // Perform basic event selection + if (!collision.sel8()) { + return; + } + // No need to correlate stuff that's in far collisions + if (std::abs(collision.posZ()) > 10.0) { + return; + } + if (zorroMask.value != "") { + auto bc = collision.bc_as(); + initCCDB(bc); + bool zorroSelected = zorro.isSelected(collision.bc_as().globalBC()); /// Just let Zorro do the accounting + if (!zorroSelected) { + return; } - if (track.tpcNClsCrossedRows() < minTPCNCrossedRows) { - continue; // crossed rows - } - if (!track.hasITS() && triggerRequireITS) { - continue; // skip, doesn't have ITS signal (skips lots of TPC-only!) - } - // prepared for Bayesian PID - // if (!track.bayesPi() > pionMinBayesProb) { - // continue; - // } - // if (track.bayesPi() < track.bayesPr() || track.bayesPi() < track.bayesKa()){ - // continue; - // } - // if (track.tpcNSigmaPi() < assocPionNSigmaTPCFOF){ - // continue; - // } - // if (track.tofSignal() > 0 && track.tofNSigmaPi() < assocPionNSigmaTPCFOF){ - // continue; - // } - if (track.tofSignal() > 0) { - if (std::sqrt(track.tofNSigmaPi() * track.tofNSigmaPi() + track.tpcNSigmaPi() * track.tpcNSigmaPi()) > assocPionNSigmaTPCFOF) - continue; - if (track.tofNSigmaPr() < rejectSigma) - continue; - if (track.tpcNSigmaPr() < rejectSigma) - continue; - if (track.tofNSigmaKa() < rejectSigma) - continue; - if (track.tpcNSigmaKa() < rejectSigma) - continue; - } else { - if (track.tpcNSigmaPi() > assocPionNSigmaTPCFOF) - continue; - if (track.tpcNSigmaPr() < rejectSigma) - continue; - if (track.tpcNSigmaKa() < rejectSigma) - continue; + } + + /// _________________________________________________ + /// Step 1: Populate table with trigger tracks + for (auto const& track : tracks) { + if (!isValidAssocTrack(track)) + continue; + } + } + void processAssocHadronsMC(soa::Join::iterator const& collision, soa::Filtered const& tracks, aod::BCsWithTimestamps const&) + { + // Perform basic event selection + if (!collision.sel8()) { + return; + } + // No need to correlate stuff that's in far collisions + if (std::abs(collision.posZ()) > 10.0) { + return; + } + if (zorroMask.value != "") { + auto bc = collision.bc_as(); + initCCDB(bc); + bool zorroSelected = zorro.isSelected(collision.bc_as().globalBC()); /// Just let Zorro do the accounting + if (!zorroSelected) { + return; } + } - assocPion( - track.collisionId(), - track.globalIndex()); + /// _________________________________________________ + /// Step 1: Populate table with trigger tracks + for (auto const& track : tracks) { + if (!isValidAssocTrack(track)) + continue; } } - void processV0s(soa::Join::iterator const& collision, DauTracks const&, soa::Filtered const& V0s, V0LinkedTagged const&) + void processV0s(soa::Join::iterator const& collision, DauTracks const&, soa::Filtered const& V0s, aod::BCsWithTimestamps const&) { // Perform basic event selection if (!collision.sel8()) { return; } // No need to correlate stuff that's in far collisions - if (TMath::Abs(collision.posZ()) > 10.0) { + if (std::abs(collision.posZ()) > 10.0) { return; } + if (zorroMask.value != "") { + auto bc = collision.bc_as(); + initCCDB(bc); + bool zorroSelected = zorro.isSelected(collision.bc_as().globalBC()); /// Just let Zorro do the accounting + if (!zorroSelected) { + return; + } + } + /// _________________________________________________ /// Populate table with associated V0s for (auto const& v0 : V0s) { if (v0.v0radius() < v0RadiusMin || v0.v0radius() > v0RadiusMax || v0.eta() > assocEtaMax || v0.eta() < assocEtaMin || v0.v0cosPA() < v0Cospa) { continue; } + if (v0.pt() > assocPtCutMax || v0.pt() < assocPtCutMin) { + continue; + } // check dE/dx compatibility - bool compatibleK0Short = false; - bool compatibleLambda = false; - bool compatibleAntiLambda = false; + int compatibleK0Short = 0; + int compatibleLambda = 0; + int compatibleAntiLambda = 0; auto posdau = v0.posTrack_as(); auto negdau = v0.negTrack_as(); - auto origV0entry = v0.v0_as(); // retrieve tags if (negdau.tpcNClsCrossedRows() < minTPCNCrossedRows) continue; if (posdau.tpcNClsCrossedRows() < minTPCNCrossedRows) continue; - if (TMath::Abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && TMath::Abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { - compatibleK0Short = true; - } - if (TMath::Abs(posdau.tpcNSigmaPr()) < strangedEdxNSigma && TMath::Abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { - if (v0.v0cosPA() > lambdaCospa) { - compatibleLambda = true; - } - } - if (TMath::Abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && TMath::Abs(negdau.tpcNSigmaPr()) < strangedEdxNSigma) { - if (v0.v0cosPA() > lambdaCospa) { - compatibleAntiLambda = true; - } - } - // check whether V0s are in the regin - int massRegK0Short = -1; - if (TMath::Abs(v0.mK0Short() - fK0Mean->Eval(v0.pt()) < peakNsigma * fK0Width->Eval(v0.pt()))) { - massRegK0Short = 2; - } - if (v0.mK0Short() > fK0Mean->Eval(v0.pt()) + peakNsigma * fK0Width->Eval(v0.pt()) && v0.mK0Short() < fK0Mean->Eval(v0.pt()) + backgroundNsigma * fK0Width->Eval(v0.pt())) { - massRegK0Short = 3; - } - if (v0.mK0Short() < fK0Mean->Eval(v0.pt()) - peakNsigma * fK0Width->Eval(v0.pt()) && v0.mK0Short() > fK0Mean->Eval(v0.pt()) - backgroundNsigma * fK0Width->Eval(v0.pt())) { - massRegK0Short = 1; - } - if (v0.mK0Short() > fK0Mean->Eval(v0.pt()) + backgroundNsigma * fK0Width->Eval(v0.pt())) { - massRegK0Short = 4; - } - if (v0.mK0Short() < fK0Mean->Eval(v0.pt()) - backgroundNsigma * fK0Width->Eval(v0.pt())) { - massRegK0Short = 0; - } + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) + BIT_SET(compatibleK0Short, 0); + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) + BIT_SET(compatibleK0Short, 1); + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) + BIT_SET(compatibleK0Short, 2); + + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) + if (v0.v0cosPA() > lambdaCospa) + BIT_SET(compatibleLambda, 0); + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) + if (v0.v0cosPA() > lambdaCospa) + BIT_SET(compatibleLambda, 1); + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) + if (v0.v0cosPA() > lambdaCospa) + BIT_SET(compatibleLambda, 2); + + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose) + if (v0.v0cosPA() > lambdaCospa) + BIT_SET(compatibleAntiLambda, 0); + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigma) + if (v0.v0cosPA() > lambdaCospa) + BIT_SET(compatibleAntiLambda, 1); + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaTight) + if (v0.v0cosPA() > lambdaCospa) + BIT_SET(compatibleAntiLambda, 2); + + // simplified handling: calculate NSigma in mass here + float massNSigmaK0Short = (v0.mK0Short() - fK0Mean->Eval(v0.pt())) / (fK0Width->Eval(v0.pt()) + 1e-6); + float massNSigmaLambda = (v0.mLambda() - fLambdaMean->Eval(v0.pt())) / (fLambdaWidth->Eval(v0.pt()) + 1e-6); + float massNSigmaAntiLambda = (v0.mAntiLambda() - fLambdaMean->Eval(v0.pt())) / (fLambdaWidth->Eval(v0.pt()) + 1e-6); - int massRegLambda = -1; - if (TMath::Abs(v0.mLambda() - fLambdaMean->Eval(v0.pt()) < peakNsigma * fLambdaWidth->Eval(v0.pt()))) { - massRegLambda = 2; - } - if (v0.mLambda() > fLambdaMean->Eval(v0.pt()) + peakNsigma * fLambdaWidth->Eval(v0.pt()) && v0.mLambda() < fLambdaMean->Eval(v0.pt()) + backgroundNsigma * fLambdaWidth->Eval(v0.pt())) { - massRegLambda = 3; - } - if (v0.mLambda() < fLambdaMean->Eval(v0.pt()) - peakNsigma * fLambdaWidth->Eval(v0.pt()) && v0.mLambda() > fLambdaMean->Eval(v0.pt()) - backgroundNsigma * fLambdaWidth->Eval(v0.pt())) { - massRegLambda = 1; - } - if (v0.mLambda() > fLambdaMean->Eval(v0.pt()) + backgroundNsigma * fLambdaWidth->Eval(v0.pt())) { - massRegLambda = 4; - } - if (v0.mLambda() < fLambdaMean->Eval(v0.pt()) - backgroundNsigma * fLambdaWidth->Eval(v0.pt())) { - massRegLambda = 0; - } + if (compatibleK0Short) + histos.fill(HIST("h3dMassK0Short"), v0.pt(), v0.mK0Short(), collision.centFT0M()); + if (compatibleLambda) + histos.fill(HIST("h3dMassLambda"), v0.pt(), v0.mLambda(), collision.centFT0M()); + if (compatibleAntiLambda) + histos.fill(HIST("h3dMassAntiLambda"), v0.pt(), v0.mAntiLambda(), collision.centFT0M()); - int massRegAntiLambda = -1; - if (TMath::Abs(v0.mAntiLambda() - fLambdaMean->Eval(v0.pt()) < peakNsigma * fLambdaWidth->Eval(v0.pt()))) { - massRegAntiLambda = 2; - } - if (v0.mAntiLambda() > fLambdaMean->Eval(v0.pt()) + peakNsigma * fLambdaWidth->Eval(v0.pt()) && v0.mAntiLambda() < fLambdaMean->Eval(v0.pt()) + backgroundNsigma * fLambdaWidth->Eval(v0.pt())) { - massRegAntiLambda = 3; + if (!fillTableOnlyWithCompatible || + ( // start major condition check + (compatibleK0Short > 0 && std::abs(massNSigmaK0Short) < maxMassNSigma) || + (compatibleLambda > 0 && std::abs(massNSigmaLambda) < maxMassNSigma) || + (compatibleAntiLambda > 0 && std::abs(massNSigmaAntiLambda) < maxMassNSigma)) // end major condition check + ) { + assocV0(v0.collisionId(), v0.globalIndex(), + compatibleK0Short, compatibleLambda, compatibleAntiLambda, + false, false, false, false, + massNSigmaK0Short, massNSigmaLambda, massNSigmaAntiLambda); } - if (v0.mAntiLambda() < fLambdaMean->Eval(v0.pt()) - peakNsigma * fLambdaWidth->Eval(v0.pt()) && v0.mAntiLambda() > fLambdaMean->Eval(v0.pt()) - backgroundNsigma * fLambdaWidth->Eval(v0.pt())) { - massRegAntiLambda = 1; + } + } + + void processV0sMC(soa::Join::iterator const& collision, DauTracksMC const&, soa::Filtered const& V0s, aod::McParticles const&, aod::BCsWithTimestamps const&) + { + // Perform basic event selection + if (!collision.sel8()) { + return; + } + // No need to correlate stuff that's in far collisions + if (std::abs(collision.posZ()) > 10.0) { + return; + } + if (zorroMask.value != "") { + auto bc = collision.bc_as(); + initCCDB(bc); + bool zorroSelected = zorro.isSelected(collision.bc_as().globalBC()); /// Just let Zorro do the accounting + if (!zorroSelected) { + return; } - if (v0.mAntiLambda() > fLambdaMean->Eval(v0.pt()) + backgroundNsigma * fLambdaWidth->Eval(v0.pt())) { - massRegAntiLambda = 4; + } + + /// _________________________________________________ + /// Populate table with associated V0s + for (auto const& v0 : V0s) { + if (v0.v0radius() < v0RadiusMin || v0.v0radius() > v0RadiusMax || v0.eta() > assocEtaMax || v0.eta() < assocEtaMin || v0.v0cosPA() < v0Cospa) { + continue; } - if (v0.mAntiLambda() < fLambdaMean->Eval(v0.pt()) - backgroundNsigma * fLambdaWidth->Eval(v0.pt())) { - massRegAntiLambda = 0; + if (v0.pt() > assocPtCutMax || v0.pt() < assocPtCutMin) { + continue; } + // check dE/dx compatibility + int compatibleK0Short = 0; + int compatibleLambda = 0; + int compatibleAntiLambda = 0; - if (compatibleK0Short) + auto posdau = v0.posTrack_as(); + auto negdau = v0.negTrack_as(); + + if (negdau.tpcNClsCrossedRows() < minTPCNCrossedRows) + continue; + if (posdau.tpcNClsCrossedRows() < minTPCNCrossedRows) + continue; + + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) + BIT_SET(compatibleK0Short, 0); + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) + BIT_SET(compatibleK0Short, 1); + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) + BIT_SET(compatibleK0Short, 2); + + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) + if (v0.v0cosPA() > lambdaCospa) + BIT_SET(compatibleLambda, 0); + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) + if (v0.v0cosPA() > lambdaCospa) + BIT_SET(compatibleLambda, 1); + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) + if (v0.v0cosPA() > lambdaCospa) + BIT_SET(compatibleLambda, 2); + + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose) + if (v0.v0cosPA() > lambdaCospa) + BIT_SET(compatibleAntiLambda, 0); + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigma) + if (v0.v0cosPA() > lambdaCospa) + BIT_SET(compatibleAntiLambda, 1); + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaTight) + if (v0.v0cosPA() > lambdaCospa) + BIT_SET(compatibleAntiLambda, 2); + + // simplified handling: calculate NSigma in mass here + float massNSigmaK0Short = (v0.mK0Short() - fK0Mean->Eval(v0.pt())) / (fK0Width->Eval(v0.pt()) + 1e-6); + float massNSigmaLambda = (v0.mLambda() - fLambdaMean->Eval(v0.pt())) / (fLambdaWidth->Eval(v0.pt()) + 1e-6); + float massNSigmaAntiLambda = (v0.mAntiLambda() - fLambdaMean->Eval(v0.pt())) / (fLambdaWidth->Eval(v0.pt()) + 1e-6); + bool v0PhysicalPrimary = false; + bool trueK0Short = false; + bool trueLambda = false; + bool trueAntiLambda = false; + v0PhysicalPrimary = v0.isPhysicalPrimary(); + if (v0.pdgCode() == 310) + trueK0Short = true; + if (v0.pdgCode() == 3122) + trueLambda = true; + if (v0.pdgCode() == -3122) + trueAntiLambda = true; + if (compatibleK0Short && (!doTrueSelectionInMass || (trueK0Short && v0PhysicalPrimary))) histos.fill(HIST("h3dMassK0Short"), v0.pt(), v0.mK0Short(), collision.centFT0M()); - if (compatibleLambda) + if (compatibleLambda && (!doTrueSelectionInMass || (trueLambda && v0PhysicalPrimary))) histos.fill(HIST("h3dMassLambda"), v0.pt(), v0.mLambda(), collision.centFT0M()); - if (compatibleAntiLambda) + if (compatibleAntiLambda && (!doTrueSelectionInMass || (trueAntiLambda && v0PhysicalPrimary))) histos.fill(HIST("h3dMassAntiLambda"), v0.pt(), v0.mAntiLambda(), collision.centFT0M()); if (!fillTableOnlyWithCompatible || ( // start major condition check - (compatibleK0Short && massRegK0Short > 0 && massRegK0Short < 4) || - (compatibleLambda && massRegLambda > 0 && massRegLambda < 4) || - (compatibleAntiLambda && massRegAntiLambda > 0 && massRegAntiLambda < 4)) // end major condition check + (compatibleK0Short > 0 && std::abs(massNSigmaK0Short) < maxMassNSigma) || + (compatibleLambda > 0 && std::abs(massNSigmaLambda) < maxMassNSigma) || + (compatibleAntiLambda > 0 && std::abs(massNSigmaAntiLambda) < maxMassNSigma)) // end major condition check ) { assocV0(v0.collisionId(), v0.globalIndex(), compatibleK0Short, compatibleLambda, compatibleAntiLambda, - origV0entry.isTrueK0Short(), origV0entry.isTrueLambda(), origV0entry.isTrueAntiLambda(), - massRegK0Short, massRegLambda, massRegAntiLambda); + trueK0Short, trueLambda, trueAntiLambda, v0PhysicalPrimary, + massNSigmaK0Short, massNSigmaLambda, massNSigmaAntiLambda); } } } - void processCascades(soa::Join::iterator const& collision, DauTracks const&, soa::Filtered const& /*V0s*/, soa::Filtered const& Cascades, aod::V0sLinked const&, CascadesLinkedTagged const&) + + void processCascades(soa::Join::iterator const& collision, DauTracks const&, soa::Filtered const& /*V0s*/, soa::Filtered const& Cascades, aod::BCsWithTimestamps const&) { // Perform basic event selection if (!collision.sel8()) { return; } // No need to correlate stuff that's in far collisions - if (TMath::Abs(collision.posZ()) > 10.0) { + if (std::abs(collision.posZ()) > 10.0) { return; } + if (zorroMask.value != "") { + auto bc = collision.bc_as(); + initCCDB(bc); + bool zorroSelected = zorro.isSelected(collision.bc_as().globalBC()); /// Just let Zorro do the accounting + if (!zorroSelected) { + return; + } + } /// _________________________________________________ /// Step 3: Populate table with associated Cascades for (auto const& casc : Cascades) { + if (casc.eta() > assocEtaMax || casc.eta() < assocEtaMin) { + continue; + } + if (casc.pt() > assocPtCutMax || casc.pt() < assocPtCutMin) { + continue; + } auto bachTrackCast = casc.bachelor_as(); auto posTrackCast = casc.posTrack_as(); auto negTrackCast = casc.negTrack_as(); - auto origCascadeEntry = casc.cascade_as(); // minimum TPC crossed rows if (bachTrackCast.tpcNClsCrossedRows() < minTPCNCrossedRows) @@ -412,89 +726,190 @@ struct hstrangecorrelationfilter { continue; // check dE/dx compatibility - bool compatibleXiMinus = false; - bool compatibleXiPlus = false; - bool compatibleOmegaMinus = false; - bool compatibleOmegaPlus = false; + int compatibleXiMinus = 0; + int compatibleXiPlus = 0; + int compatibleOmegaMinus = 0; + int compatibleOmegaPlus = 0; + + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() < 0) + BIT_SET(compatibleXiMinus, 0); + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() < 0) + BIT_SET(compatibleXiMinus, 1); + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() < 0) + BIT_SET(compatibleXiMinus, 2); + + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() > 0) + BIT_SET(compatibleXiPlus, 0); + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() > 0) + BIT_SET(compatibleXiPlus, 1); + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() > 0) + BIT_SET(compatibleXiPlus, 2); + + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() < 0) + BIT_SET(compatibleOmegaMinus, 0); + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() < 0) + BIT_SET(compatibleOmegaMinus, 1); + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() < 0) + BIT_SET(compatibleOmegaMinus, 2); + + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() > 0) + BIT_SET(compatibleOmegaPlus, 0); + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() > 0) + BIT_SET(compatibleOmegaPlus, 1); + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() > 0) + BIT_SET(compatibleOmegaPlus, 2); + + float massNSigmaXi = (casc.mXi() - fXiMean->Eval(casc.pt())) / (fXiWidth->Eval(casc.pt()) + 1e-6); + float massNSigmaOmega = (casc.mOmega() - fOmegaMean->Eval(casc.pt())) / (fOmegaWidth->Eval(casc.pt()) + 1e-6); - if (TMath::Abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && TMath::Abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && TMath::Abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() < 0) { - compatibleXiMinus = true; - } - if (TMath::Abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && TMath::Abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && TMath::Abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() > 0) { - compatibleXiPlus = true; - } - if (TMath::Abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && TMath::Abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && TMath::Abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() < 0) { - compatibleOmegaMinus = true; - } - if (TMath::Abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && TMath::Abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && TMath::Abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() > 0) { - compatibleOmegaPlus = true; - } + if (compatibleXiMinus) + histos.fill(HIST("h3dMassXiMinus"), casc.pt(), casc.mXi(), collision.centFT0M()); + if (compatibleXiPlus) + histos.fill(HIST("h3dMassXiPlus"), casc.pt(), casc.mXi(), collision.centFT0M()); + if (compatibleOmegaMinus) + histos.fill(HIST("h3dMassOmegaMinus"), casc.pt(), casc.mOmega(), collision.centFT0M()); + if (compatibleOmegaPlus) + histos.fill(HIST("h3dMassOmegaPlus"), casc.pt(), casc.mOmega(), collision.centFT0M()); - int massRegXi = -1; - if (TMath::Abs(casc.mXi() - fXiMean->Eval(casc.pt()) < peakNsigma * fXiWidth->Eval(casc.pt()))) { - massRegXi = 2; - } - if (casc.mXi() > fXiMean->Eval(casc.pt()) + peakNsigma * fXiWidth->Eval(casc.pt()) && casc.mXi() < fXiMean->Eval(casc.pt()) + backgroundNsigma * fXiWidth->Eval(casc.pt())) { - massRegXi = 3; - } - if (casc.mXi() < fXiMean->Eval(casc.pt()) - peakNsigma * fXiWidth->Eval(casc.pt()) && casc.mXi() > fXiMean->Eval(casc.pt()) - backgroundNsigma * fXiWidth->Eval(casc.pt())) { - massRegXi = 1; - } - if (casc.mXi() > fXiMean->Eval(casc.pt()) + backgroundNsigma * fXiWidth->Eval(casc.pt())) { - massRegXi = 4; - } - if (casc.mXi() < fXiMean->Eval(casc.pt()) - backgroundNsigma * fXiWidth->Eval(casc.pt())) { - massRegXi = 0; + if (!fillTableOnlyWithCompatible || + ( // start major condition check + ((compatibleXiMinus > 0 || compatibleXiPlus > 0) && std::abs(massNSigmaXi) < maxMassNSigma) || + ((compatibleOmegaMinus > 0 || compatibleOmegaPlus > 0) && std::abs(massNSigmaOmega) < maxMassNSigma)) // end major condition check + ) { + assocCascades(casc.collisionId(), casc.globalIndex(), + compatibleXiMinus, compatibleXiPlus, compatibleOmegaMinus, compatibleOmegaPlus, + false, false, false, false, false, + massNSigmaXi, massNSigmaOmega); } + } + } - int massRegOmega = -1; - if (TMath::Abs(casc.mOmega() - fOmegaMean->Eval(casc.pt()) < peakNsigma * fOmegaWidth->Eval(casc.pt()))) { - massRegOmega = 2; - } - if (casc.mOmega() > fOmegaMean->Eval(casc.pt()) + peakNsigma * fOmegaWidth->Eval(casc.pt()) && casc.mOmega() < fOmegaMean->Eval(casc.pt()) + backgroundNsigma * fOmegaWidth->Eval(casc.pt())) { - massRegOmega = 3; - } - if (casc.mOmega() < fOmegaMean->Eval(casc.pt()) - peakNsigma * fOmegaWidth->Eval(casc.pt()) && casc.mOmega() > fOmegaMean->Eval(casc.pt()) - backgroundNsigma * fOmegaWidth->Eval(casc.pt())) { - massRegOmega = 1; + void processCascadesMC(soa::Join::iterator const& collision, DauTracks const&, soa::Filtered const& /*V0s*/, soa::Filtered const& Cascades, aod::McParticles const&, aod::BCsWithTimestamps const&) + { + // Perform basic event selection + if (!collision.sel8()) { + return; + } + // No need to correlate stuff that's in far collisions + if (std::abs(collision.posZ()) > 10.0) { + return; + } + if (zorroMask.value != "") { + auto bc = collision.bc_as(); + initCCDB(bc); + bool zorroSelected = zorro.isSelected(collision.bc_as().globalBC()); /// Just let Zorro do the accounting + if (!zorroSelected) { + return; } - if (casc.mOmega() > fOmegaMean->Eval(casc.pt()) + backgroundNsigma * fOmegaWidth->Eval(casc.pt())) { - massRegOmega = 4; + } + /// _________________________________________________ + /// Step 3: Populate table with associated Cascades + for (auto const& casc : Cascades) { + if (casc.eta() > assocEtaMax || casc.eta() < assocEtaMin) { + continue; } - if (casc.mOmega() < fOmegaMean->Eval(casc.pt()) - backgroundNsigma * fOmegaWidth->Eval(casc.pt())) { - massRegOmega = 0; + if (casc.pt() > assocPtCutMax || casc.pt() < assocPtCutMin) { + continue; } + auto bachTrackCast = casc.bachelor_as(); + auto posTrackCast = casc.posTrack_as(); + auto negTrackCast = casc.negTrack_as(); - if (compatibleXiMinus) + // minimum TPC crossed rows + if (bachTrackCast.tpcNClsCrossedRows() < minTPCNCrossedRows) + continue; + if (posTrackCast.tpcNClsCrossedRows() < minTPCNCrossedRows) + continue; + if (negTrackCast.tpcNClsCrossedRows() < minTPCNCrossedRows) + continue; + + // check dE/dx compatibility + int compatibleXiMinus = 0; + int compatibleXiPlus = 0; + int compatibleOmegaMinus = 0; + int compatibleOmegaPlus = 0; + + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() < 0) + BIT_SET(compatibleXiMinus, 0); + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() < 0) + BIT_SET(compatibleXiMinus, 1); + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() < 0) + BIT_SET(compatibleXiMinus, 2); + + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() > 0) + BIT_SET(compatibleXiPlus, 0); + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() > 0) + BIT_SET(compatibleXiPlus, 1); + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() > 0) + BIT_SET(compatibleXiPlus, 2); + + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() < 0) + BIT_SET(compatibleOmegaMinus, 0); + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() < 0) + BIT_SET(compatibleOmegaMinus, 1); + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() < 0) + BIT_SET(compatibleOmegaMinus, 2); + + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() > 0) + BIT_SET(compatibleOmegaPlus, 0); + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() > 0) + BIT_SET(compatibleOmegaPlus, 1); + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() > 0) + BIT_SET(compatibleOmegaPlus, 2); + + float massNSigmaXi = (casc.mXi() - fXiMean->Eval(casc.pt())) / (fXiWidth->Eval(casc.pt()) + 1e-6); + float massNSigmaOmega = (casc.mOmega() - fOmegaMean->Eval(casc.pt())) / (fOmegaWidth->Eval(casc.pt()) + 1e-6); + bool cascPhysicalPrimary = false; + bool trueXiMinus = false; + bool trueXiPlus = false; + bool trueOmegaMinus = false; + bool trueOmegaPlus = false; + cascPhysicalPrimary = casc.isPhysicalPrimary(); + if (casc.pdgCode() == 3312) + trueXiMinus = true; + if (casc.pdgCode() == -3312) + trueXiPlus = true; + if (casc.pdgCode() == 3334) + trueOmegaMinus = true; + if (casc.pdgCode() == -3334) + trueOmegaPlus = true; + if (compatibleXiMinus && (!doTrueSelectionInMass || (trueXiMinus && cascPhysicalPrimary))) histos.fill(HIST("h3dMassXiMinus"), casc.pt(), casc.mXi(), collision.centFT0M()); - if (compatibleXiPlus) + if (compatibleXiPlus && (!doTrueSelectionInMass || (trueXiPlus && cascPhysicalPrimary))) histos.fill(HIST("h3dMassXiPlus"), casc.pt(), casc.mXi(), collision.centFT0M()); - if (compatibleOmegaMinus) + if (compatibleOmegaMinus && (!doTrueSelectionInMass || (trueOmegaMinus && cascPhysicalPrimary))) histos.fill(HIST("h3dMassOmegaMinus"), casc.pt(), casc.mOmega(), collision.centFT0M()); - if (compatibleOmegaPlus) + if (compatibleOmegaPlus && (!doTrueSelectionInMass || (trueOmegaPlus && cascPhysicalPrimary))) histos.fill(HIST("h3dMassOmegaPlus"), casc.pt(), casc.mOmega(), collision.centFT0M()); if (!fillTableOnlyWithCompatible || ( // start major condition check - ((compatibleXiMinus || compatibleXiPlus) && massRegXi > 0 && massRegXi < 4) || - ((compatibleOmegaMinus || compatibleOmegaPlus) && massRegOmega > 0 && massRegOmega < 4)) // end major condition check + ((compatibleXiMinus > 0 || compatibleXiPlus > 0) && std::abs(massNSigmaXi) < maxMassNSigma) || + ((compatibleOmegaMinus > 0 || compatibleOmegaPlus > 0) && std::abs(massNSigmaOmega) < maxMassNSigma)) // end major condition check ) { assocCascades(casc.collisionId(), casc.globalIndex(), compatibleXiMinus, compatibleXiPlus, compatibleOmegaMinus, compatibleOmegaPlus, - origCascadeEntry.isTrueXiMinus(), origCascadeEntry.isTrueXiPlus(), - origCascadeEntry.isTrueOmegaMinus(), origCascadeEntry.isTrueOmegaPlus(), - massRegXi, massRegOmega); + trueXiMinus, trueXiPlus, + trueOmegaMinus, trueOmegaPlus, + cascPhysicalPrimary, + massNSigmaXi, massNSigmaOmega); } } } - - PROCESS_SWITCH(hstrangecorrelationfilter, processTriggers, "Produce trigger tables", true); - PROCESS_SWITCH(hstrangecorrelationfilter, processV0s, "Produce associated V0 tables", true); - PROCESS_SWITCH(hstrangecorrelationfilter, processAssocPions, "Produce associated Pion tables", true); - PROCESS_SWITCH(hstrangecorrelationfilter, processCascades, "Produce associated cascade tables", true); + PROCESS_SWITCH(HStrangeCorrelationFilter, processTriggers, "Produce trigger tables", true); + PROCESS_SWITCH(HStrangeCorrelationFilter, processTriggersMC, "Produce trigger tables for MC", false); + PROCESS_SWITCH(HStrangeCorrelationFilter, processV0s, "Produce associated V0 tables", true); + PROCESS_SWITCH(HStrangeCorrelationFilter, processV0sMC, "Produce associated V0 tables for MC", false); + PROCESS_SWITCH(HStrangeCorrelationFilter, processAssocPions, "Produce associated Pion tables", false); + PROCESS_SWITCH(HStrangeCorrelationFilter, processAssocPionsMC, "Produce associated Pion tables for MC", false); + PROCESS_SWITCH(HStrangeCorrelationFilter, processCascades, "Produce associated cascade tables", true); + PROCESS_SWITCH(HStrangeCorrelationFilter, processCascadesMC, "Produce associated cascade tables for MC", false); + PROCESS_SWITCH(HStrangeCorrelationFilter, processAssocHadrons, "Produce associated Hadron tables", true); + PROCESS_SWITCH(HStrangeCorrelationFilter, processAssocHadronsMC, "Produce associated Hadron tables for MC", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/TableProducer/Strangeness/lambdaJetpolarizationbuilder.cxx b/PWGLF/TableProducer/Strangeness/lambdaJetpolarizationbuilder.cxx new file mode 100644 index 00000000000..6c8138f65a4 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/lambdaJetpolarizationbuilder.cxx @@ -0,0 +1,687 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// + +/// \author Youpeng Su (yousu@cern.ch) + +#include +#include +#include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Common/DataModel/EventSelection.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Common/DataModel/PIDResponse.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include +#include +#include +#include "PWGLF/DataModel/lambdaJetpolarization.h" + +using std::cout; +using std::endl; +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct myAnalysis { + Produces myTable; + Produces myTableanti; + Produces myTableJet; + Produces outputCollisions; + Produces outputCollisionsV0; + Produces myTableLeadingJet; + + HistogramRegistry registry{"registry"}; + Configurable v0cospa{"v0cospa", 0.995, "V0 CosPA"}; + Configurable dcanegtopv{"dcanegtopv", 0.05, "DCA Neg To PV"}; + Configurable dcapostopv{"dcapostopv", 0.05, "DCA Pos To PV"}; + SliceCache cache; + HistogramRegistry JEhistos{"JEhistos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable cfgeventSelections{"cfgeventSelections", "sel8", "choose event selection"}; + Configurable cfgtrackSelections{"cfgtrackSelections", "globalTracks", "set track selections"}; + Configurable cfgDataHists{"cfgDataHists", true, "Enables DataHists"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + // Others configure + Configurable cfgVtxCut{"cfgVtxCut", 10.0, "V_z cut selection"}; + Configurable cfgjetPtMin{"cfgjetPtMin", 0.0, "minimum jet pT cut"}; + Configurable cfgjetR{"cfgjetR", 0.4, "jet resolution parameter"}; + Configurable cfgtrkMinPt{"cfgtrkMinPt", 0.15, "set track min pT"}; + Configurable cfgtrkMaxEta{"cfgtrkMaxEta", 0.8, "set track max Eta"}; + Configurable cfgMaxDCArToPVcut{"cfgMaxDCArToPVcut", 0.5, "Track DCAr cut to PV Maximum"}; + Configurable cfgMaxDCAzToPVcut{"cfgMaxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; + Configurable cfgnFindableTPCClusters{"cfgnFindableTPCClusters", 50, "nFindable TPC Clusters"}; + Configurable cfgnTPCCrossedRows{"cfgnTPCCrossedRows", 70, "nCrossed TPC Rows"}; + Configurable cfgnRowsOverFindable{"cfgnRowsOverFindable", 1.2, "nRowsOverFindable TPC CLusters"}; + Configurable cfgnTPCChi2{"cfgnTPChi2", 4.0, "nTPC Chi2 per Cluster"}; + Configurable cfgnITSChi2{"cfgnITShi2", 36.0, "nITS Chi2 per Cluster"}; + Configurable cfgConnectedToPV{"cfgConnectedToPV", true, "PV contributor track selection"}; + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; + Configurable cfgnTPCPID{"cfgnTPCPID", 4, "nTPC PID"}; + Configurable cfgnTOFPID{"cfgnTOFPID", 4, "nTOF PID"}; + // V0 track selection//////////////////////////////////////////////////////////////// + Configurable requireITS{"requireITS", false, "require ITS hit"}; + Configurable requireTOF{"requireTOF", false, "require TOF hit"}; + Configurable requireTPC{"requireTPC", true, "require TPC hit"}; + Configurable requirepassedSingleTrackSelection{"requirepassedSingleTrackSelection", false, "requirepassedSingleTrackSelection"}; + Configurable minITSnCls{"minITSnCls", 4.0f, "min number of ITS clusters"}; + Configurable minTPCnClsFound{"minTPCnClsFound", 80.0f, "min number of found TPC clusters"}; + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 80.0f, "min number of TPC crossed rows"}; + Configurable maxChi2TPC{"maxChi2TPC", 4.0f, "max chi2 per cluster TPC"}; + Configurable maxChi2ITS{"maxChi2ITS", 36.0f, "max chi2 per cluster ITS"}; + Configurable minTpcNcrossedRowsOverFindable{"minTpcNcrossedRowsOverFindable", 0.8, "crossed rows/findable"}; + Configurable etaMin{"etaMin", -0.8f, "eta min track"}; + Configurable etaMax{"etaMax", +0.8f, "eta max track"}; + Configurable minimumV0Radius{"minimumV0Radius", 0.2f, "Minimum V0 Radius"}; + Configurable nsigmaTPCmin{"nsigmaTPCmin", -5.0f, "Minimum nsigma TPC"}; + Configurable nsigmaTPCmax{"nsigmaTPCmax", +5.0f, "Maximum nsigma TPC"}; + Configurable nsigmaTOFmin{"nsigmaTOFmin", -5.0f, "Minimum nsigma TOF"}; + Configurable nsigmaTOFmax{"nsigmaTOFmax", +5.0f, "Maximum nsigma TOF"}; + Configurable yMin{"yMin", -0.5f, "minimum y"}; + Configurable yMax{"yMax", +0.5f, "maximum y"}; + Configurable v0rejLambda{"v0rejLambda", 0.01, "V0 rej K0s"}; + Configurable CtauLambda{"ctauLambda", 30, "C tau Lambda (cm)"}; + Configurable ifpasslambda{"passedLambdaSelection", 1, "passedLambdaSelection"}; + Configurable ifpassantilambda{"passedAntiLambdaSelection", 1, "passedAntiLambdaSelection"}; + Configurable ifinitpasslambda{"ifinitpasslambda", 0, "ifinitpasslambda"}; + // Event Selection///////////////////////////////// + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable sel8{"sel8", 0, "Apply sel8 event selection"}; + Configurable isTriggerTVX{"isTriggerTVX", 1, "TVX trigger"}; + Configurable iscutzvertex{"iscutzvertex", 1, "Accepted z-vertex range (cm)"}; + Configurable isNoTimeFrameBorder{"isNoTimeFrameBorder", 1, "TF border cut"}; + Configurable isNoITSROFrameBorder{"isNoITSROFrameBorder", 1, "ITS ROF border cut"}; + Configurable isVertexTOFmatched{"isVertexTOFmatched", 1, "Is Vertex TOF matched"}; + Configurable isGoodZvtxFT0vsPV{"isGoodZvtxFT0vsPV", 0, "isGoodZvtxFT0vsPV"}; + /////////////////////////V0 QA analysis/////////////////////////////// + Configurable dcav0dau{"dcav0dau", 1.0, "DCA V0 Daughters"}; + Configurable doArmenterosCut{"doArmenterosCut", 1, "do Armenteros Cut"}; + Configurable paramArmenterosCut{"paramArmenterosCut", 0.2, "parameter Armenteros Cut"}; + Configurable doDrawPicture{"doDrawPicture", 0, "do Draw Picture"}; + // CONFIG DONE + ///////////////////////////////////////// //INIT//////////////////////////////////////////////////////////////////// + // int eventSelection = -1; + int trackSelection = -1; + std::vector eventSelectionBits; + void init(o2::framework::InitContext&) + { + // HISTOGRAMS + const AxisSpec axisEta{30, -1.5, +1.5, "#eta"}; + const AxisSpec axisPhi{200, -1, +7, "#phi"}; + const AxisSpec axisPt{200, 0, +200, "#pt"}; + const AxisSpec MinvAxis = {500, 0.1, 1.25}; + const AxisSpec PtAxis = {200, 0, 20.0}; + const AxisSpec MultAxis = {100, 0, 100}; + const AxisSpec dRAxis = {100, 0, 100}; + + const AxisSpec axisPx{200, -10, 10, "#px"}; + const AxisSpec axisPy{200, -10, 10, "#py"}; + const AxisSpec axisPz{200, -10, 10, "#pz"}; + const AxisSpec massAxis{200, 0.9f, 1.2f, "mass"}; + const AxisSpec eventAxis{1000000, 0.5f, 1000000.5f, "event"}; + + if (cfgDataHists) { + + JEhistos.add("h_track_pt", "track pT;#it{p}_{T,track} (GeV/#it{c});entries", kTH1F, {{200, 0., 200.}}); + JEhistos.add("h_track_eta", "track #eta;#eta_{track};entries", kTH1F, {{100, -1.f, 1.f}}); + JEhistos.add("h_track_phi", "track #varphi;#varphi_{track};entries", kTH1F, {{80, -1.f, 7.f}}); + JEhistos.add("nJetsPerEvent", "nJetsPerEvent", kTH1F, {{10, 0.0, 10.0}}); + JEhistos.add("FJetaHistogram", "FJetaHistogram", kTH1F, {axisEta}); + JEhistos.add("FJphiHistogram", "FJphiHistogram", kTH1F, {axisPhi}); + JEhistos.add("FJptHistogram", "FJptHistogram", kTH1F, {axisPt}); + JEhistos.add("hDCArToPv", "DCArToPv", kTH1F, {{300, 0.0, 3.0}}); + JEhistos.add("hDCAzToPv", "DCAzToPv", kTH1F, {{300, 0.0, 3.0}}); + JEhistos.add("rawpT", "rawpT", kTH1F, {{1000, 0.0, 10.0}}); + JEhistos.add("rawDpT", "rawDpT", kTH2F, {{1000, 0.0, 10.0}, {300, -1.5, 1.5}}); + JEhistos.add("hIsPrim", "hIsPrim", kTH1F, {{2, -0.5, +1.5}}); + JEhistos.add("hIsGood", "hIsGood", kTH1F, {{2, -0.5, +1.5}}); + JEhistos.add("hIsPrimCont", "hIsPrimCont", kTH1F, {{2, -0.5, +1.5}}); + JEhistos.add("hFindableTPCClusters", "hFindableTPCClusters", kTH1F, {{200, 0, 200}}); + JEhistos.add("hFindableTPCRows", "hFindableTPCRows", kTH1F, {{200, 0, 200}}); + JEhistos.add("hClustersVsRows", "hClustersVsRows", kTH1F, {{200, 0, 2}}); + JEhistos.add("hTPCChi2", "hTPCChi2", kTH1F, {{200, 0, 100}}); + JEhistos.add("hITSChi2", "hITSChi2", kTH1F, {{200, 0, 100}}); + JEhistos.add("etaHistogram", "etaHistogram", kTH1F, {axisEta}); + JEhistos.add("phiHistogram", "phiHistogram", kTH1F, {axisPhi}); + JEhistos.add("ptHistogram", "ptHistogram", kTH1F, {axisPt}); + JEhistos.add("V0Counts", "V0Counts", kTH1F, {{10, 0, 10}}); + JEhistos.add("hUSS_1D", "hUSS_1D", kTH1F, {MinvAxis}); + JEhistos.add("hPt", "hPt", {HistType::kTH1F, {{100, 0.0f, 10.0f}}}); + JEhistos.add("hMassVsPtLambda", "hMassVsPtLambda", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {200, 1.016f, 1.216f}}}); + JEhistos.add("hMassVsPtAntiLambda", "hMassVsPtAntiLambda", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {200, 1.016f, 1.216f}}}); + JEhistos.add("hMassLambda", "hMassLambda", {HistType::kTH1F, {{200, 0.9f, 1.2f}}}); + JEhistos.add("hMassAntiLambda", "hMassAntiLambda", {HistType::kTH1F, {{200, 0.9f, 1.2f}}}); + JEhistos.add("V0Radius", "V0Radius", {HistType::kTH1D, {{100, 0.0f, 20.0f}}}); + JEhistos.add("CosPA", "CosPA", {HistType::kTH1F, {{100, 0.9f, 1.0f}}}); + JEhistos.add("V0DCANegToPV", "V0DCANegToPV", {HistType::kTH1F, {{100, -1.0f, 1.0f}}}); + JEhistos.add("V0DCAPosToPV", "V0DCAPosToPV", {HistType::kTH1F, {{100, -1.0f, 1.0f}}}); + JEhistos.add("V0DCAV0Daughters", "V0DCAV0Daughters", {HistType::kTH1F, {{55, 0.0f, 2.20f}}}); + JEhistos.add("TPCNSigmaPosPi", "TPCNSigmaPosPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); + JEhistos.add("TPCNSigmaNegPi", "TPCNSigmaNegPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); + JEhistos.add("TPCNSigmaPosPr", "TPCNSigmaPosPr", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); + JEhistos.add("TPCNSigmaNegPr", "TPCNSigmaNegPr", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); + JEhistos.add("hNEvents", "hNEvents", {HistType::kTH1I, {{10, 0.f, 10.f}}}); + JEhistos.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(1, "all"); + JEhistos.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(2, "sel8"); + JEhistos.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(3, "TVX"); + JEhistos.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(4, "zvertex"); + JEhistos.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(5, "TFBorder"); + JEhistos.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(6, "ITSROFBorder"); + JEhistos.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(7, "isTOFVertexMatched"); + JEhistos.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(8, "isGoodZvtxFT0vsPV"); + JEhistos.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(9, "Applied selected"); + registry.add("hNEventsJet", "hNEventsJet", {HistType::kTH1I, {{4, 0.f, 4.f}}}); + registry.get(HIST("hNEventsJet"))->GetXaxis()->SetBinLabel(1, "all"); + registry.get(HIST("hNEventsJet"))->GetXaxis()->SetBinLabel(2, "zvertex"); + registry.get(HIST("hNEventsJet"))->GetXaxis()->SetBinLabel(3, "JCollisionSel::sel8"); + JEhistos.add("v0Lambdapx", "v0Lambdapx", kTH1F, {axisPx}); + JEhistos.add("v0Lambdapy", "v0Lambdapy", kTH1F, {axisPy}); + JEhistos.add("v0Lambdapz", "v0Lambdapz", kTH1F, {axisPz}); + JEhistos.add("v0AntiLambdapx", "v0AntiLambdapx", kTH1F, {axisPx}); + JEhistos.add("v0AntiLambdapy", "v0AntiLambdapy", kTH1F, {axisPy}); + JEhistos.add("v0AntiLambdapz", "v0AntiLambdapz", kTH1F, {axisPz}); + JEhistos.add("jetpx", "jetpx", kTH1F, {axisPx}); + JEhistos.add("jetpy", "jetpy", kTH1F, {axisPy}); + JEhistos.add("jetpz", "jetpz", kTH1F, {axisPz}); + JEhistos.add("EventIndexselection", "EventIndexselection", {HistType::kTH1F, {{1000000, 0.5f, 1000000.5f}}}); + } + JEhistos.add("hKaonplusCounts", "hKaonplusCounts", {HistType::kTH1F, {{1, -0.5, 0.5f}}}); + JEhistos.add("hKaonminusCounts", "hKaonminusCounts", {HistType::kTH1F, {{1, -0.5, 0.5f}}}); + + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(cfgeventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + } // end of init + + double massPi = o2::constants::physics::MassPiMinus; + double massPr = o2::constants::physics::MassProton; + using DauTracks = soa::Join; + using EventCandidates = soa::Join; // , aod::CentFT0Ms, aod::CentFT0As, aod::CentFT0Cs + using TrackCandidates = soa::Join; + using JCollisions = soa::Join; + using V0Collisions = soa::Join; + + Filter jetCuts = aod::jet::pt > cfgjetPtMin&& aod::jet::r == nround(cfgjetR.node() * 100.0f); + template + bool TrackSelection(const TrackType track) + { + // basic track cuts + if (track.pt() < cfgtrkMinPt) + return false; + + if (std::abs(track.eta()) > cfgtrkMaxEta) + return false; + + if (std::abs(track.dcaXY()) > cfgMaxDCArToPVcut) + return false; + + if (std::abs(track.dcaZ()) > cfgMaxDCAzToPVcut) + return false; + + if (cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + + if (track.tpcNClsFindable() < cfgnFindableTPCClusters) + return false; + + if (track.tpcNClsCrossedRows() < cfgnTPCCrossedRows) + return false; + + if (track.tpcCrossedRowsOverFindableCls() > cfgnRowsOverFindable) + return false; + + if (track.tpcChi2NCl() > cfgnTPCChi2) + return false; + + if (track.itsChi2NCl() > cfgnITSChi2) + return false; + + if (cfgConnectedToPV && !track.isPVContributor()) + return false; + + return true; + }; + + template + bool trackPIDPion(const T& candidate) + { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + if (std::abs(candidate.tpcNSigmaPi()) < cfgnTPCPID) + tpcPIDPassed = true; + + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaPi()) < cfgnTOFPID) { + tofPIDPassed = true; + } + } else { + tofPIDPassed = true; + } + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + return false; + } + + template + bool trackPIDProton(const T& candidate) + { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + if (std::abs(candidate.tpcNSigmaPr()) < cfgnTPCPID) + tpcPIDPassed = true; + + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaPr()) < cfgnTOFPID) { + tofPIDPassed = true; + } + } else { + tofPIDPassed = true; + } + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + return false; + } + + // Single-Track Selection + template + bool passedSingleTrackSelection(const Track& track) + { + if (requireITS && (!track.hasITS())) + return false; + if (requireITS && track.itsNCls() < minITSnCls) + return false; + if (!track.hasTPC()) + return false; + if (track.tpcNClsFound() < minTPCnClsFound) + return false; + if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < minTpcNcrossedRowsOverFindable) + return false; + if (track.tpcChi2NCl() > maxChi2TPC) + return false; + if (track.itsChi2NCl() > maxChi2ITS) + return false; + if (track.eta() < etaMin || track.eta() > etaMax) + return false; + if (requireTOF && (!track.hasTOF())) + return false; + return true; + } + + // init Selection + template + bool passedInitLambdaSelection(const Lambda& v0, const TrackPos& ptrack, const TrackNeg& ntrack) + { + if (v0.v0radius() < minimumV0Radius || v0.v0cosPA() < v0cospa || + TMath::Abs(ptrack.eta()) > etaMax || + TMath::Abs(ntrack.eta()) > etaMax) { + return false; + } + if (v0.dcaV0daughters() > dcav0dau) { + return false; + } + + if (TMath::Abs(v0.dcanegtopv()) < dcanegtopv) { + return false; + } + + if (TMath::Abs(v0.dcapostopv()) < dcapostopv) { + return false; + } + return true; + } + + // Lambda Selections + template + bool passedLambdaSelection(const Lambda& v0, const TrackPos& ptrack, const TrackNeg& ntrack) + { + + if (ptrack.tpcNSigmaKa() > nsigmaTPCmin && ptrack.tpcNSigmaKa() < nsigmaTPCmax) { + JEhistos.fill(HIST("hKaonplusCounts"), 1); + } + + if (ntrack.tpcNSigmaKa() > nsigmaTPCmin && ntrack.tpcNSigmaKa() < nsigmaTPCmax) { + JEhistos.fill(HIST("hKaonminusCounts"), 1); + } + + // Single-Track Selections + if (requirepassedSingleTrackSelection && !passedSingleTrackSelection(ptrack)) + return false; + if (requirepassedSingleTrackSelection && !passedSingleTrackSelection(ntrack)) + return false; + + if (v0.v0radius() < minimumV0Radius || v0.v0cosPA() < v0cospa || + TMath::Abs(ptrack.eta()) > etaMax || + TMath::Abs(ntrack.eta()) > etaMax) { + return false; + } + if (TMath::Abs(v0.dcanegtopv()) < dcanegtopv) + return false; + if (TMath::Abs(v0.dcapostopv()) < dcapostopv) + return false; + if (v0.dcaV0daughters() > dcav0dau) + return false; + + // PID Selections (TPC) + if (requireTPC) { + if (ptrack.tpcNSigmaPr() < nsigmaTPCmin || ptrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + if (ntrack.tpcNSigmaPi() < nsigmaTPCmin || ntrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + } + + if (requireTOF) { + if (ptrack.tofNSigmaPr() < nsigmaTOFmin || ptrack.tofNSigmaPr() > nsigmaTOFmax) + return false; + if (ntrack.tofNSigmaPi() < nsigmaTOFmin || ntrack.tofNSigmaPi() > nsigmaTOFmax) + return false; + } + + TLorentzVector lorentzVect; + lorentzVect.SetXYZM(v0.px(), v0.py(), v0.pz(), 1.115683); + + if (lorentzVect.Rapidity() < yMin || lorentzVect.Rapidity() > yMax) { + return false; + } + + if (TMath::Abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0rejLambda) { + return false; + } + if (TMath::Abs(v0.mLambda() - o2::constants::physics::MassLambda0) > 0.075) { + return false; + } + + return true; + } + // AntiLambda Selections + template + bool passedAntiLambdaSelection(const AntiLambda& v0, const TrackPos& ptrack, const TrackNeg& ntrack) + { + // Single-Track Selections + if (requirepassedSingleTrackSelection && !passedSingleTrackSelection(ptrack)) + return false; + if (requirepassedSingleTrackSelection && !passedSingleTrackSelection(ntrack)) + return false; + + if (v0.v0radius() < minimumV0Radius || v0.v0cosPA() < v0cospa || + TMath::Abs(ptrack.eta()) > etaMax || + TMath::Abs(ntrack.eta()) > etaMax) { + return false; + } + + if (TMath::Abs(v0.dcanegtopv()) < dcanegtopv) // + return false; + if (TMath::Abs(v0.dcapostopv()) < dcapostopv) // + return false; + if (v0.dcaV0daughters() > dcav0dau) // + return false; + // PID Selections (TOF) + if (requireTOF) { + if (ptrack.tofNSigmaPi() < nsigmaTOFmin || ptrack.tofNSigmaPi() > nsigmaTOFmax) + return false; + if (ntrack.tofNSigmaPr() < nsigmaTOFmin || ntrack.tofNSigmaPr() > nsigmaTOFmax) + return false; + } + if (requireTPC) { + if (ptrack.tpcNSigmaPi() < nsigmaTPCmin || ptrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + if (ntrack.tpcNSigmaPr() < nsigmaTPCmin || ntrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + } + + TLorentzVector lorentzVect; + lorentzVect.SetXYZM(v0.px(), v0.py(), v0.pz(), 1.115683); + if (lorentzVect.Rapidity() < yMin || lorentzVect.Rapidity() > yMax) { + return false; + } + + if (TMath::Abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0rejLambda) { + return false; + } + if (TMath::Abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) > 0.075) { + return false; + } + return true; + } + ///////Event selection + template + bool AcceptEvent(TCollision const& collision) + { + if (sel8 && !collision.sel8()) { + return false; + } + JEhistos.fill(HIST("hNEvents"), 1.5); + + if (isTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + JEhistos.fill(HIST("hNEvents"), 2.5); + + if (iscutzvertex && TMath::Abs(collision.posZ()) > cutzvertex) { + return false; + } + JEhistos.fill(HIST("hNEvents"), 3.5); + + if (isNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } + + JEhistos.fill(HIST("hNEvents"), 4.5); + + if (isNoITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return false; + } + JEhistos.fill(HIST("hNEvents"), 5.5); + if (isVertexTOFmatched && !collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { + return false; + } + JEhistos.fill(HIST("hNEvents"), 6.5); + if (isGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + JEhistos.fill(HIST("hNEvents"), 7.5); + + return true; + } + // Filter preFilterV0 = nabs(aod::v0data::dcapostopv) > dcapostopv&&nabs(aod::v0data::dcanegtopv) > dcanegtopv&& aod::v0data::dcaV0daughters < dcaV0DaughtersMax; + + int nEventsJet = 0; + void processJetTracks(aod::JetCollision const& collision, soa::Filtered> const& chargedjets, soa::Join const& tracks, TrackCandidates const&) + { + + registry.fill(HIST("hNEventsJet"), 0.5); + if (fabs(collision.posZ()) > cfgVtxCut) { + + return; + } + registry.fill(HIST("hNEventsJet"), 1.5); + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + registry.fill(HIST("hNEventsJet"), 2.5); + outputCollisions(collision.posZ()); + + for (auto const& track : tracks) { + + auto originalTrack = track.track_as>(); + if (doDrawPicture) { + JEhistos.fill(HIST("hDCArToPv"), originalTrack.dcaXY()); + JEhistos.fill(HIST("hDCAzToPv"), originalTrack.dcaZ()); + JEhistos.fill(HIST("rawpT"), originalTrack.pt()); + JEhistos.fill(HIST("rawDpT"), track.pt(), track.pt() - originalTrack.pt()); + JEhistos.fill(HIST("hIsPrim"), originalTrack.isPrimaryTrack()); + JEhistos.fill(HIST("hIsGood"), originalTrack.isGlobalTrackWoDCA()); + JEhistos.fill(HIST("hIsPrimCont"), originalTrack.isPVContributor()); + JEhistos.fill(HIST("hFindableTPCClusters"), originalTrack.tpcNClsFindable()); + JEhistos.fill(HIST("hFindableTPCRows"), originalTrack.tpcNClsCrossedRows()); + JEhistos.fill(HIST("hClustersVsRows"), originalTrack.tpcCrossedRowsOverFindableCls()); + JEhistos.fill(HIST("hTPCChi2"), originalTrack.tpcChi2NCl()); + JEhistos.fill(HIST("hITSChi2"), originalTrack.itsChi2NCl()); + JEhistos.fill(HIST("h_track_pt"), track.pt()); + JEhistos.fill(HIST("h_track_eta"), track.eta()); + JEhistos.fill(HIST("h_track_phi"), track.phi()); + } + if (track.pt() < cfgtrkMinPt && std::abs(track.eta()) > cfgtrkMaxEta) { + continue; + } + if (doDrawPicture) { + JEhistos.fill(HIST("ptHistogram"), track.pt()); + JEhistos.fill(HIST("etaHistogram"), track.eta()); + JEhistos.fill(HIST("phiHistogram"), track.phi()); + } + } + int nJets = 0; + int lastindex = 0; + int collisionId = 0; + float maxJetpx = 0; + float maxJetpy = 0; + float maxJetpz = 0; + float maxJetpT = 0; + float maxJetPt = -999; + nEventsJet++; + for (const auto& chargedjet : chargedjets) { + JEhistos.fill(HIST("FJetaHistogram"), chargedjet.eta()); + JEhistos.fill(HIST("FJphiHistogram"), chargedjet.phi()); + JEhistos.fill(HIST("FJptHistogram"), chargedjet.pt()); + + JEhistos.fill(HIST("jetpx"), chargedjet.px()); + JEhistos.fill(HIST("jetpy"), chargedjet.py()); + JEhistos.fill(HIST("jetpz"), chargedjet.pz()); + + myTableJet(outputCollisions.lastIndex(), chargedjet.collisionId(), chargedjet.px(), chargedjet.py(), chargedjet.pz(), chargedjet.pt()); + + nJets++; + if (chargedjet.pt() > maxJetPt) { + maxJetpx = chargedjet.px(); + maxJetpy = chargedjet.py(); + maxJetpz = chargedjet.pz(); + maxJetpT = chargedjet.pt(); + collisionId = chargedjet.collisionId(); + lastindex = outputCollisions.lastIndex(); + } + } + if (maxJetpT > 0) { + myTableLeadingJet(lastindex, collisionId, maxJetpx, maxJetpy, maxJetpz, maxJetpT); + } + JEhistos.fill(HIST("nJetsPerEvent"), nJets); + } + PROCESS_SWITCH(myAnalysis, processJetTracks, "process JE Framework", true); + int nEventsV0 = 0; + + void processV0(V0Collisions::iterator const& collision, aod::V0Datas const& V0s, TrackCandidates const&) + { + nEventsV0++; + JEhistos.fill(HIST("hNEvents"), 0.5); + if (!AcceptEvent(collision)) { + return; + } + JEhistos.fill(HIST("hNEvents"), 8.5); + int V0NumbersPerEvent = 0; + int V0LambdaNumbers = 0; + outputCollisionsV0(collision.posX()); + for (auto& v0 : V0s) { + float ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; + float ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0Bar; + + const auto& pos = v0.posTrack_as(); + const auto& neg = v0.negTrack_as(); + V0NumbersPerEvent = V0NumbersPerEvent + 1; + if (passedLambdaSelection(v0, pos, neg) && ctauLambda < CtauLambda && ifpasslambda) { + if (doDrawPicture) { + JEhistos.fill(HIST("hPt"), v0.pt()); + JEhistos.fill(HIST("V0Radius"), v0.v0radius()); + JEhistos.fill(HIST("CosPA"), v0.v0cosPA()); + JEhistos.fill(HIST("V0DCANegToPV"), v0.dcanegtopv()); + JEhistos.fill(HIST("V0DCAPosToPV"), v0.dcapostopv()); + JEhistos.fill(HIST("V0DCAV0Daughters"), v0.dcaV0daughters()); + } + } else if (passedInitLambdaSelection(v0, pos, neg) && ifinitpasslambda) { + if (doDrawPicture) { + JEhistos.fill(HIST("hPt"), v0.pt()); + JEhistos.fill(HIST("V0Radius"), v0.v0radius()); + JEhistos.fill(HIST("CosPA"), v0.v0cosPA()); + JEhistos.fill(HIST("V0DCANegToPV"), v0.dcanegtopv()); + JEhistos.fill(HIST("V0DCAPosToPV"), v0.dcapostopv()); + JEhistos.fill(HIST("V0DCAV0Daughters"), v0.dcaV0daughters()); + } + } + if (passedLambdaSelection(v0, pos, neg) && ctauAntiLambda < CtauLambda && ifpasslambda) { + + V0LambdaNumbers = V0LambdaNumbers + 1; + JEhistos.fill(HIST("hMassVsPtLambda"), v0.pt(), v0.mLambda()); + JEhistos.fill(HIST("hMassLambda"), v0.mLambda()); + + if (doDrawPicture) { + JEhistos.fill(HIST("TPCNSigmaPosPr"), pos.tpcNSigmaPr()); + JEhistos.fill(HIST("TPCNSigmaNegPi"), neg.tpcNSigmaPi()); + JEhistos.fill(HIST("v0Lambdapx"), v0.px()); + JEhistos.fill(HIST("v0Lambdapy"), v0.py()); + JEhistos.fill(HIST("v0Lambdapz"), v0.pz()); + } + myTable(outputCollisionsV0.lastIndex(), v0.collisionId(), v0.px(), v0.py(), v0.pz(), v0.pt(), v0.mLambda(), pos.px(), pos.py(), pos.pz()); + } else if (passedInitLambdaSelection(v0, pos, neg) && ifinitpasslambda) { + V0LambdaNumbers = V0LambdaNumbers + 1; + JEhistos.fill(HIST("hMassVsPtLambda"), v0.pt(), v0.mLambda()); + JEhistos.fill(HIST("hMassLambda"), v0.mLambda()); + if (doDrawPicture) { + JEhistos.fill(HIST("TPCNSigmaPosPr"), pos.tpcNSigmaPr()); + JEhistos.fill(HIST("TPCNSigmaNegPi"), neg.tpcNSigmaPi()); + JEhistos.fill(HIST("v0Lambdapx"), v0.px()); + JEhistos.fill(HIST("v0Lambdapy"), v0.py()); + JEhistos.fill(HIST("v0Lambdapz"), v0.pz()); + } + myTable(outputCollisionsV0.lastIndex(), v0.collisionId(), v0.px(), v0.py(), v0.pz(), v0.pt(), v0.mLambda(), pos.px(), pos.py(), pos.pz()); + } + if (passedAntiLambdaSelection(v0, pos, neg) && ifpassantilambda) { + JEhistos.fill(HIST("hMassVsPtAntiLambda"), v0.pt(), v0.mAntiLambda()); + JEhistos.fill(HIST("hMassAntiLambda"), v0.mAntiLambda()); + + if (doDrawPicture) { + JEhistos.fill(HIST("TPCNSigmaPosPi"), pos.tpcNSigmaPi()); + JEhistos.fill(HIST("TPCNSigmaNegPr"), neg.tpcNSigmaPr()); + JEhistos.fill(HIST("v0AntiLambdapx"), v0.px()); + JEhistos.fill(HIST("v0AntiLambdapy"), v0.py()); + JEhistos.fill(HIST("v0AntiLambdapz"), v0.pz()); + } + myTableanti(outputCollisionsV0.lastIndex(), v0.collisionId(), v0.px(), v0.py(), v0.pz(), v0.pt(), v0.mAntiLambda(), neg.px(), neg.py(), neg.pz()); + } else if (passedInitLambdaSelection(v0, pos, neg) && ifinitpasslambda) { + JEhistos.fill(HIST("hMassVsPtAntiLambda"), v0.pt(), v0.mAntiLambda()); + JEhistos.fill(HIST("hMassAntiLambda"), v0.mAntiLambda()); + + if (doDrawPicture) { + JEhistos.fill(HIST("TPCNSigmaPosPi"), pos.tpcNSigmaPi()); + JEhistos.fill(HIST("TPCNSigmaNegPr"), neg.tpcNSigmaPr()); + JEhistos.fill(HIST("v0AntiLambdapx"), v0.px()); + JEhistos.fill(HIST("v0AntiLambdapy"), v0.py()); + JEhistos.fill(HIST("v0AntiLambdapz"), v0.pz()); + } + myTableanti(outputCollisionsV0.lastIndex(), v0.collisionId(), v0.px(), v0.py(), v0.pz(), v0.pt(), v0.mAntiLambda(), neg.px(), neg.py(), neg.pz()); + } + } + JEhistos.fill(HIST("V0Counts"), V0NumbersPerEvent); + } + PROCESS_SWITCH(myAnalysis, processV0, "processV0", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGLF/TableProducer/Strangeness/lambdakzeroMLSelectionTreeCreator.cxx b/PWGLF/TableProducer/Strangeness/lambdakzeroMLSelectionTreeCreator.cxx index 3bbffccc632..d70552c4c71 100644 --- a/PWGLF/TableProducer/Strangeness/lambdakzeroMLSelectionTreeCreator.cxx +++ b/PWGLF/TableProducer/Strangeness/lambdakzeroMLSelectionTreeCreator.cxx @@ -105,6 +105,12 @@ struct lambdakzeroMLSelectionTreeCreator { Configurable K0Shortv0radius{"K0Shortv0radius", 1.5, "minimum V0 radius (cm)"}; Configurable K0ShortWindow{"K0ShortWindow", 0.01, "Mass window around expected (in GeV/c2)"}; + Configurable RejectHypothesis{"RejectHypothesis", -1, "SelHypothesis to reject"}; + Configurable SelMCCand{"SelMCCand", true, "Select candidate based on PDG Code"}; + Configurable SelMCCandMother{"SelMCCandMother", false, "Select candidate based on PDGCodeMother"}; + Configurable SelPDGCode{"SelPDGCode", 22, "PDGCode to select candidate"}; + Configurable SelPDGCodeMother{"SelPDGCodeMother", 3212, "PDGCodeMother to select candidate"}; + // Axis: ConfigurableAxis centralityAxis{"centralityAxis", {100, 0.0f, 100.0f}, ""}; ConfigurableAxis candSelectionAxis{"candSelectionAxis", {16, 0.0f, 16.0f}, ""}; @@ -121,8 +127,8 @@ struct lambdakzeroMLSelectionTreeCreator { int negITSCls; uint32_t posITSClSize; uint32_t negITSClSize; - float posTPCRows; - float negTPCRows; + uint8_t posTPCRows; + uint8_t negTPCRows; float posTPCSigmaPi; float negTPCSigmaPi; float posTPCSigmaPr; @@ -160,6 +166,7 @@ struct lambdakzeroMLSelectionTreeCreator { bool isAntiLambda; bool isGamma; bool isKZeroShort; + int PDGCodeMother; } Candidate; // Process candidate and store properties in object @@ -229,7 +236,7 @@ struct lambdakzeroMLSelectionTreeCreator { lConsistentWithLambda = false; if ((std::abs(cand.mAntiLambda() - 1.115683) > AntiLambdaWindow) || (cand.v0radius() < AntiLambdav0radius) || (cand.v0cosPA() < AntiLambdav0cospa) || (TMath::Abs(cand.dcapostopv()) < AntiLambdadcapostopv) || (TMath::Abs(cand.dcanegtopv()) < AntiLambdadcanegtopv) || (cand.dcaV0daughters() > AntiLambdadcav0dau)) lConsistentWithAntiLambda = false; - if ((std::abs(cand.mGamma()) > PhotonWindow) || (cand.mGamma() > PhotonMaxMass) || (cand.v0radius() < PhotonMinRadius) || (cand.v0radius() > PhotonMaxRadius) || (cand.pt() < PhotonMinPt) || (cand.qtarm() > PhotonMaxqt) || (TMath::Abs(cand.alpha()) > PhotonMaxalpha)) + if ((std::abs(cand.mGamma()) > PhotonWindow) || (cand.v0radius() < PhotonMinRadius) || (cand.v0radius() > PhotonMaxRadius) || (cand.pt() < PhotonMinPt) || (cand.qtarm() > PhotonMaxqt) || (TMath::Abs(cand.alpha()) > PhotonMaxalpha)) lConsistentWithGamma = false; if ((std::abs(cand.mK0Short() - 0.497) > K0ShortWindow) || (cand.v0radius() < K0Shortv0radius) || (cand.v0cosPA() < K0Shortv0cospa) || (TMath::Abs(cand.dcapostopv()) < K0Shortdcapostopv) || (TMath::Abs(cand.dcanegtopv()) < K0Shortdcanegtopv) || (cand.dcaV0daughters() > K0Shortdcav0dau)) lConsistentWithK0Short = false; @@ -246,7 +253,7 @@ struct lambdakzeroMLSelectionTreeCreator { histos.fill(HIST("hCandSelection"), Candidate.SelHypothesis); - if (Candidate.SelHypothesis == 0) + if (Candidate.SelHypothesis == RejectHypothesis) return; // MC flags @@ -254,14 +261,25 @@ struct lambdakzeroMLSelectionTreeCreator { Candidate.isAntiLambda = false; Candidate.isGamma = false; Candidate.isKZeroShort = false; + Candidate.PDGCodeMother = -1; if constexpr (requires { cand.pdgCode(); }) { + if (SelMCCand && (cand.pdgCode() != SelPDGCode)) + return; + Candidate.isLambda = (cand.pdgCode() == 3122); Candidate.isAntiLambda = (cand.pdgCode() == -3122); Candidate.isGamma = (cand.pdgCode() == 22); Candidate.isKZeroShort = (cand.pdgCode() == 310); } + if constexpr (requires { cand.pdgCodeMother(); }) { + if (SelMCCandMother && (cand.pdgCodeMother() != SelPDGCodeMother)) + return; + + Candidate.PDGCodeMother = cand.pdgCodeMother(); + } + // Filling TTree for ML analysis v0MLCandidates(Candidate.posITSCls, Candidate.negITSCls, Candidate.posITSClSize, Candidate.negITSClSize, Candidate.posTPCRows, Candidate.negTPCRows, Candidate.posTPCSigmaPi, Candidate.negTPCSigmaPi, Candidate.posTPCSigmaPr, Candidate.negTPCSigmaPr, @@ -270,7 +288,7 @@ struct lambdakzeroMLSelectionTreeCreator { Candidate.LambdaMass, Candidate.AntiLambdaMass, Candidate.GammaMass, Candidate.KZeroShortMass, Candidate.pT, Candidate.qt, Candidate.alpha, Candidate.posEta, Candidate.negEta, Candidate.v0Eta, Candidate.Z, Candidate.v0radius, Candidate.PA, Candidate.dcapostopv, Candidate.dcanegtopv, Candidate.dcaV0daughters, Candidate.dcav0topv, Candidate.PsiPair, - Candidate.v0type, Candidate.centrality, Candidate.SelHypothesis, Candidate.isLambda, Candidate.isAntiLambda, Candidate.isGamma, Candidate.isKZeroShort); + Candidate.v0type, Candidate.centrality, Candidate.SelHypothesis, Candidate.isLambda, Candidate.isAntiLambda, Candidate.isGamma, Candidate.isKZeroShort, Candidate.PDGCodeMother); } void processRealData(soa::Join::iterator const& coll, soa::Join const& v0s, dauTracks const&) diff --git a/PWGLF/TableProducer/Strangeness/lambdakzerobuilder.cxx b/PWGLF/TableProducer/Strangeness/lambdakzerobuilder.cxx index 85c2def6163..c1de2354aa4 100644 --- a/PWGLF/TableProducer/Strangeness/lambdakzerobuilder.cxx +++ b/PWGLF/TableProducer/Strangeness/lambdakzerobuilder.cxx @@ -36,6 +36,8 @@ // david.dobrigkeit.chinellato@cern.ch // +#include +#include #include #include #include @@ -90,6 +92,7 @@ using TracksExtraWithPIDandLabels = soa::Join; +using TaggedFindableV0s = soa::Join; // For MC association in pre-selection using LabeledTracksExtra = soa::Join; @@ -103,7 +106,7 @@ struct lambdakzeroBuilder { std::map metadata; Produces v0indices; - Produces v0cores; + Produces v0cores; Produces v0trackXs; Produces v0covs; // covariances Produces v0daucovs; // covariances of daughter tracks @@ -262,6 +265,7 @@ struct lambdakzeroBuilder { static constexpr float defaultLambdaWindowParameters[1][4] = {{1.17518e-03, 1.24099e-04, 5.47937e-03, 3.08009e-01}}; Configurable> massCutK0{"massCutK0", {defaultK0MassWindowParameters[0], 4, {"constant", "linear", "expoConstant", "expoRelax"}}, "mass parameters for K0"}; Configurable> massCutLambda{"massCutLambda", {defaultLambdaWindowParameters[0], 4, {"constant", "linear", "expoConstant", "expoRelax"}}, "mass parameters for Lambda"}; + Configurable massCutPhoton{"massCutPhoton", 0.2, "Photon max mass"}; Configurable massWindownumberOfSigmas{"massWindownumberOfSigmas", 5e+6, "number of sigmas around mass peaks to keep"}; Configurable massWindowWithTPCPID{"massWindowWithTPCPID", false, "when checking mass windows, correlate with TPC dE/dx"}; Configurable massWindowSafetyMargin{"massWindowSafetyMargin", 0.001, "Extra mass window safety margin"}; @@ -336,6 +340,7 @@ struct lambdakzeroBuilder { // Helper struct to do bookkeeping of building parameters struct { std::array v0stats; + std::array v0statsUnassociated; std::array posITSclu; std::array negITSclu; int32_t exceptions; @@ -407,8 +412,10 @@ struct lambdakzeroBuilder { { statisticsRegistry.exceptions = 0; statisticsRegistry.eventCounter = 0; - for (Int_t ii = 0; ii < kNV0Steps; ii++) + for (Int_t ii = 0; ii < kNV0Steps; ii++) { statisticsRegistry.v0stats[ii] = 0; + statisticsRegistry.v0statsUnassociated[ii] = 0; + } for (Int_t ii = 0; ii < 10; ii++) { statisticsRegistry.posITSclu[ii] = 0; statisticsRegistry.negITSclu[ii] = 0; @@ -419,8 +426,10 @@ struct lambdakzeroBuilder { { registry.fill(HIST("hEventCounter"), 0.0, statisticsRegistry.eventCounter); registry.fill(HIST("hCaughtExceptions"), 0.0, statisticsRegistry.exceptions); - for (Int_t ii = 0; ii < kNV0Steps; ii++) + for (Int_t ii = 0; ii < kNV0Steps; ii++) { registry.fill(HIST("hV0Criteria"), ii, statisticsRegistry.v0stats[ii]); + registry.fill(HIST("hV0CriteriaUnassociated"), ii, statisticsRegistry.v0statsUnassociated[ii]); + } if (qaConfigurations.d_doTrackQA) { for (Int_t ii = 0; ii < 10; ii++) { registry.fill(HIST("hPositiveITSClusters"), ii, statisticsRegistry.posITSclu[ii]); @@ -449,6 +458,17 @@ struct lambdakzeroBuilder { h->GetXaxis()->SetBinLabel(8, "Count: Standard V0"); h->GetXaxis()->SetBinLabel(9, "Count: V0 exc. for casc"); + auto h2 = registry.add("hV0CriteriaUnassociated", "hV0CriteriaUnassociated", kTH1D, {{10, -0.5f, 9.5f}}); + h2->GetXaxis()->SetBinLabel(1, "All sel"); + h2->GetXaxis()->SetBinLabel(2, "TPC requirement"); + h2->GetXaxis()->SetBinLabel(3, "DCAxy Dau to PV"); + h2->GetXaxis()->SetBinLabel(4, "DCA V0 Dau"); + h2->GetXaxis()->SetBinLabel(5, "CosPA"); + h2->GetXaxis()->SetBinLabel(6, "Radius"); + h2->GetXaxis()->SetBinLabel(7, "Within momentum range"); + h2->GetXaxis()->SetBinLabel(8, "Count: Standard V0"); + h2->GetXaxis()->SetBinLabel(9, "Count: V0 exc. for casc"); + randomSeed = static_cast(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); // Optionally, add extra QA histograms to processing chain @@ -523,17 +543,21 @@ struct lambdakzeroBuilder { } } if (dcaFitterConfigurations.useMatCorrType == 2) { - LOGF(info, "LUT correction requested, loading LUT"); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbConfigurations.lutPath)); - LOGF(info, "LUT load done!"); + LOGF(info, "LUT correction requested, will load LUT when initializing with timestamp..."); } - if (doprocessRun2 == false && doprocessRun3 == false) { - LOGF(fatal, "Neither processRun2 nor processRun3 enabled. Please choose one."); + if (doprocessRun2 == false && doprocessRun3 == false && doprocessFindableRun3 == false) { + LOGF(fatal, "Neither processRun2 nor processRun3 nor processFindableRun3 enabled. Please choose one."); } if (doprocessRun2 == true && doprocessRun3 == true) { LOGF(fatal, "Cannot enable processRun2 and processRun3 at the same time. Please choose one."); } + if (doprocessRun2 == true && doprocessFindableRun3 == true) { + LOGF(fatal, "Cannot enable processRun2 and processFindableRun3 at the same time. Please choose one."); + } + if (doprocessRun3 == true && doprocessFindableRun3 == true) { + LOGF(fatal, "Cannot enable processRun3 and processFindableRun3 at the same time. Please choose one."); + } if (d_UseAutodetectMode) { double loosest_v0cospa = 100; @@ -713,9 +737,11 @@ struct lambdakzeroBuilder { // Set magnetic field value once known fitter.setBz(d_bz); - if (dcaFitterConfigurations.useMatCorrType == 2) { + if (dcaFitterConfigurations.useMatCorrType == 2 && !lut) { // setMatLUT only after magfield has been initalized // (setMatLUT has implicit and problematic init field call if not) + LOG(info) << "Loading material look-up table for timestamp: " << timestamp; + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->getForTimeStamp(ccdbConfigurations.lutPath, timestamp)); o2::base::Propagator::Instance()->setMatLUT(lut); } } @@ -794,6 +820,9 @@ struct lambdakzeroBuilder { // value 0.5: any considered V0 statisticsRegistry.v0stats[kV0All]++; + if (!V0.has_collision()) + statisticsRegistry.v0statsUnassociated[kV0All]++; + if (tpcrefit) { if (!(posTrack.trackType() & o2::aod::track::TPCrefit)) { return false; @@ -805,6 +834,8 @@ struct lambdakzeroBuilder { // Passes TPC refit statisticsRegistry.v0stats[kV0TPCrefit]++; + if (!V0.has_collision()) + statisticsRegistry.v0statsUnassociated[kV0TPCrefit]++; // Calculate DCA with respect to the collision associated to the V0, not individual tracks gpu::gpustd::array dcaInfo; @@ -827,6 +858,8 @@ struct lambdakzeroBuilder { // passes DCAxy statisticsRegistry.v0stats[kV0DCAxy]++; + if (!V0.has_collision()) + statisticsRegistry.v0statsUnassociated[kV0DCAxy]++; // Change strangenessBuilder tracks lPositiveTrack = getTrackParCov(posTrack); @@ -874,6 +907,8 @@ struct lambdakzeroBuilder { // Passes DCA between daughters check statisticsRegistry.v0stats[kV0DCADau]++; + if (!V0.has_collision()) + statisticsRegistry.v0statsUnassociated[kV0DCADau]++; v0candidate.cosPA = RecoDecay::cpa(array{primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, array{v0candidate.pos[0], v0candidate.pos[1], v0candidate.pos[2]}, array{v0candidate.posP[0] + v0candidate.negP[0], v0candidate.posP[1] + v0candidate.negP[1], v0candidate.posP[2] + v0candidate.negP[2]}); if (v0candidate.cosPA < v0cospa) { @@ -889,6 +924,8 @@ struct lambdakzeroBuilder { // Passes CosPA check statisticsRegistry.v0stats[kV0CosPA]++; + if (!V0.has_collision()) + statisticsRegistry.v0statsUnassociated[kV0CosPA]++; v0candidate.V0radius = RecoDecay::sqrtSumOfSquares(v0candidate.pos[0], v0candidate.pos[1]); if (v0candidate.V0radius < v0radius) { @@ -897,6 +934,8 @@ struct lambdakzeroBuilder { // Passes radius check statisticsRegistry.v0stats[kV0Radius]++; + if (!V0.has_collision()) + statisticsRegistry.v0statsUnassociated[kV0Radius]++; // Return OK: passed all v0 candidate selecton criteria auto px = v0candidate.posP[0] + v0candidate.negP[0]; @@ -924,6 +963,8 @@ struct lambdakzeroBuilder { // Passes momentum window check statisticsRegistry.v0stats[kWithinMomentumRange]++; + if (!V0.has_collision()) + statisticsRegistry.v0statsUnassociated[kWithinMomentumRange]++; // Calculate masses auto lGammaMass = RecoDecay::m(array{array{v0candidate.posP[0], v0candidate.posP[1], v0candidate.posP[2]}, array{v0candidate.negP[0], v0candidate.negP[1], v0candidate.negP[2]}}, array{o2::constants::physics::MassElectron, o2::constants::physics::MassElectron}); @@ -939,15 +980,18 @@ struct lambdakzeroBuilder { bool desiredMassK0Short = false; bool desiredMassLambda = false; bool desiredMassAntiLambda = false; + bool desiredMassGamma = false; if (massWindownumberOfSigmas > 1e+3) { desiredMassK0Short = true; // safety fallback desiredMassLambda = true; // safety fallback desiredMassAntiLambda = true; // safety fallback + desiredMassGamma = true; // safety fallback } else { desiredMassK0Short = TMath::Abs(v0candidate.k0ShortMass - o2::constants::physics::MassKaonNeutral) < massWindownumberOfSigmas * getMassSigmaK0Short(lPt) + massWindowSafetyMargin; desiredMassLambda = TMath::Abs(v0candidate.lambdaMass - o2::constants::physics::MassLambda) < massWindownumberOfSigmas * getMassSigmaLambda(lPt) + massWindowSafetyMargin; desiredMassAntiLambda = TMath::Abs(v0candidate.antiLambdaMass - o2::constants::physics::MassLambda) < massWindownumberOfSigmas * getMassSigmaLambda(lPt) + massWindowSafetyMargin; + desiredMassGamma = TMath::Abs(lGammaMass) < massCutPhoton; } // check if user requested to correlate mass requirement with TPC PID @@ -955,6 +999,7 @@ struct lambdakzeroBuilder { bool dEdxK0Short = V0.isdEdxK0Short() || !massWindowWithTPCPID; bool dEdxLambda = V0.isdEdxLambda() || !massWindowWithTPCPID; bool dEdxAntiLambda = V0.isdEdxAntiLambda() || !massWindowWithTPCPID; + bool dEdxGamma = V0.isdEdxGamma() || !massWindowWithTPCPID; // check proper lifetime if asked for bool passML2P_K0Short = lML2P_K0Short < lifetimecut->get("lifetimecutK0S") || lifetimecut->get("lifetimecutK0S") > 1000; @@ -966,6 +1011,8 @@ struct lambdakzeroBuilder { keepCandidate = true; if (passML2P_Lambda && dEdxAntiLambda && desiredMassAntiLambda) keepCandidate = true; + if (dEdxGamma && desiredMassGamma) + keepCandidate = true; if (!keepCandidate) return false; @@ -1144,19 +1191,17 @@ struct lambdakzeroBuilder { if (V0.v0Type() > 1 && !storePhotonCandidates) continue; - if (mlConfigurations.calculateK0ShortScores || - mlConfigurations.calculateLambdaScores || - mlConfigurations.calculateAntiLambdaScores || - mlConfigurations.calculateGammaScores) { - // at this stage, the candidate is interesting -> populate table - gammaMLSelections(gammaScore); - lambdaMLSelections(lambdaScore); - antiLambdaMLSelections(antiLambdaScore); - k0ShortMLSelections(k0ShortScore); - } + // at this stage, the candidate is interesting -> populate table + gammaMLSelections(gammaScore); + lambdaMLSelections(lambdaScore); + antiLambdaMLSelections(antiLambdaScore); + k0ShortMLSelections(k0ShortScore); // populates the various tables for analysis statisticsRegistry.v0stats[kCountStandardV0]++; + if (!V0.has_collision()) + statisticsRegistry.v0statsUnassociated[kCountStandardV0]++; + v0indices(V0.posTrackId(), V0.negTrackId(), V0.collisionId(), V0.globalIndex()); v0trackXs(v0candidate.posTrackX, v0candidate.negTrackX); @@ -1172,7 +1217,7 @@ struct lambdakzeroBuilder { if (createV0PosAtDCAs) v0dauPositions(v0candidate.posPosition[0], v0candidate.posPosition[1], v0candidate.posPosition[2], v0candidate.negPosition[0], v0candidate.negPosition[1], v0candidate.negPosition[2]); - if (createV0PosAtDCAs) { + if (createV0PosAtIUs) { std::array posPositionIU; std::array negPositionIU; lPositiveTrackIU.getXYZGlo(posPositionIU); @@ -1283,6 +1328,20 @@ struct lambdakzeroBuilder { buildStrangenessTables(V0s); } PROCESS_SWITCH(lambdakzeroBuilder, processRun3, "Produce Run 3 V0 tables", true); + + void processFindableRun3(aod::Collisions const& collisions, soa::Filtered const& V0s, FullTracksExtIU const&, aod::BCsWithTimestamps const& bcs) + { + statisticsRegistry.eventCounter += collisions.size(); + // Fire up CCDB + auto bc = collisions.size() ? collisions.begin().bc_as() : bcs.begin(); + if (!bcs.size()) { + LOGF(warn, "No BC found, skipping this DF."); + return; + } + initCCDB(bc); + buildStrangenessTables(V0s); + } + PROCESS_SWITCH(lambdakzeroBuilder, processFindableRun3, "Produce Run 3 V0 tables with all findable candidates", false); }; //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* @@ -1321,8 +1380,11 @@ struct lambdakzeroPreselector { Configurable forceITSOnlyMesons{"forceITSOnlyMesons", false, "force meson-like daughters to be ITS-only to pass Lambda/AntiLambda selections (yes/no)"}; Configurable minITSCluITSOnly{"minITSCluITSOnly", 0, "minimum number of ITS clusters to ask for if daughter track does not have TPC"}; + // qa coll assoc directly from AO2D (MC mode exclusive) + Configurable qaCollisionAssociation{"qaCollisionAssociation", false, "QA collision association"}; + // for bit-packed maps - std::vector selectionMask; + std::vector selectionMask; enum v0bit { bitInteresting = 0, bitTrackQuality, bitTrueGamma, @@ -1331,6 +1393,7 @@ struct lambdakzeroPreselector { bitTrueAntiLambda, bitTrueHypertriton, bitTrueAntiHypertriton, + bitPhysicalPrimary, bitdEdxGamma, bitdEdxK0Short, bitdEdxLambda, @@ -1342,6 +1405,16 @@ struct lambdakzeroPreselector { void init(InitContext const&) { + // check settings and stop if not viable + if (doprocessBuildAll == false && doprocessBuildMCAssociated == false && doprocessBuildValiddEdx == false && doprocessBuildValiddEdxMCAssociated == false && doprocessBuildFindable == false) { + LOGF(fatal, "No processBuild function enabled. Please choose one."); + } + LOGF(info, "Process function processBuildAll status: %i", static_cast(doprocessBuildAll)); + LOGF(info, "Process function doprocessBuildMCAssociated status: %i", static_cast(doprocessBuildMCAssociated)); + LOGF(info, "Process function doprocessBuildValiddEdx status: %i", static_cast(doprocessBuildValiddEdx)); + LOGF(info, "Process function doprocessBuildValiddEdxMCAssociated status: %i", static_cast(doprocessBuildValiddEdxMCAssociated)); + LOGF(info, "Process function doprocessBuildFindable status: %i", static_cast(doprocessBuildFindable)); + auto h = histos.add("hPreselectorStatistics", "hPreselectorStatistics", kTH1D, {{6, -0.5f, 5.5f}}); h->GetXaxis()->SetBinLabel(1, "All"); h->GetXaxis()->SetBinLabel(2, "Tracks OK"); @@ -1349,12 +1422,36 @@ struct lambdakzeroPreselector { h->GetXaxis()->SetBinLabel(4, "dEdx OK"); h->GetXaxis()->SetBinLabel(5, "Used in Casc"); h->GetXaxis()->SetBinLabel(6, "Used in Tra-Casc"); + + if (qaCollisionAssociation) { + auto hCollAssocQA = histos.add("hCollAssocQA", "hCollAssocQA", kTH2D, {{6, -0.5f, 5.5f}, {2, -0.5f, 1.5f}}); + hCollAssocQA->GetXaxis()->SetBinLabel(1, "K0"); + hCollAssocQA->GetXaxis()->SetBinLabel(2, "Lambda"); + hCollAssocQA->GetXaxis()->SetBinLabel(3, "AntiLambda"); + hCollAssocQA->GetXaxis()->SetBinLabel(4, "Gamma"); + hCollAssocQA->GetYaxis()->SetBinLabel(1, "Wrong collision"); + hCollAssocQA->GetYaxis()->SetBinLabel(2, "Correct collision"); + + auto h2dPtVsCollAssocK0Short = histos.add("h2dPtVsCollAssocK0Short", "h2dPtVsCollAssocK0Short", kTH2D, {{100, 0.0f, 10.0f}, {2, -0.5f, 1.5f}}); + auto h2dPtVsCollAssocLambda = histos.add("h2dPtVsCollAssocLambda", "h2dPtVsCollAssocLambda", kTH2D, {{100, 0.0f, 10.0f}, {2, -0.5f, 1.5f}}); + auto h2dPtVsCollAssocAntiLambda = histos.add("h2dPtVsCollAssocAntiLambda", "h2dPtVsCollAssocAntiLambda", kTH2D, {{100, 0.0f, 10.0f}, {2, -0.5f, 1.5f}}); + auto h2dPtVsCollAssocGamma = histos.add("h2dPtVsCollAssocGamma", "h2dPtVsCollAssocGamma", kTH2D, {{100, 0.0f, 10.0f}, {2, -0.5f, 1.5f}}); + + h2dPtVsCollAssocK0Short->GetYaxis()->SetBinLabel(1, "Wrong collision"); + h2dPtVsCollAssocK0Short->GetYaxis()->SetBinLabel(2, "Correct collision"); + h2dPtVsCollAssocLambda->GetYaxis()->SetBinLabel(1, "Wrong collision"); + h2dPtVsCollAssocLambda->GetYaxis()->SetBinLabel(2, "Correct collision"); + h2dPtVsCollAssocAntiLambda->GetYaxis()->SetBinLabel(1, "Wrong collision"); + h2dPtVsCollAssocAntiLambda->GetYaxis()->SetBinLabel(2, "Correct collision"); + h2dPtVsCollAssocGamma->GetYaxis()->SetBinLabel(1, "Wrong collision"); + h2dPtVsCollAssocGamma->GetYaxis()->SetBinLabel(2, "Correct collision"); + } } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* /// function to check track quality template - void checkTrackQuality(TV0Object const& lV0Candidate, uint16_t& maskElement, bool passdEdx = false) + void checkTrackQuality(TV0Object const& lV0Candidate, uint32_t& maskElement, bool passdEdx = false) { auto lNegTrack = lV0Candidate.template negTrack_as(); auto lPosTrack = lV0Candidate.template posTrack_as(); @@ -1397,9 +1494,12 @@ struct lambdakzeroPreselector { //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* /// function to check PDG association template - void checkPDG(TV0Object const& lV0Candidate, uint16_t& maskElement) + void checkPDG(TV0Object const& lV0Candidate, uint32_t& maskElement, int mcCollisionId) { int lPDG = -1; + int correctMcCollisionIndex = -1; + float mcpt = -1.0; + bool physicalPrimary = false; auto lNegTrack = lV0Candidate.template negTrack_as(); auto lPosTrack = lV0Candidate.template posTrack_as(); @@ -1413,6 +1513,9 @@ struct lambdakzeroPreselector { for (auto& lPosMother : lMCPosTrack.template mothers_as()) { if (lNegMother.globalIndex() == lPosMother.globalIndex() && (!dIfMCselectPhysicalPrimary || lNegMother.isPhysicalPrimary())) { lPDG = lNegMother.pdgCode(); + correctMcCollisionIndex = lNegMother.mcCollisionId(); + physicalPrimary = lNegMother.isPhysicalPrimary(); + mcpt = lNegMother.pt(); // additionally check PDG of the mother particle if requested if (dIfMCselectV0MotherPDG != 0) { @@ -1430,22 +1533,50 @@ struct lambdakzeroPreselector { } } } // end association check - if (lPDG == 310) + + bool collisionAssociationOK = false; + if (correctMcCollisionIndex > -1 && correctMcCollisionIndex == mcCollisionId) { + collisionAssociationOK = true; + } + + if (lPDG == 310) { bitset(maskElement, bitTrueK0Short); - if (lPDG == 3122) + if (qaCollisionAssociation) { + histos.fill(HIST("hCollAssocQA"), 0.0f, collisionAssociationOK); + histos.fill(HIST("h2dPtVsCollAssocK0Short"), mcpt, collisionAssociationOK); + } + } + if (lPDG == 3122) { bitset(maskElement, bitTrueLambda); - if (lPDG == -3122) + if (qaCollisionAssociation) { + histos.fill(HIST("hCollAssocQA"), 1.0f, collisionAssociationOK); + histos.fill(HIST("h2dPtVsCollAssocLambda"), mcpt, collisionAssociationOK); + } + } + if (lPDG == -3122) { bitset(maskElement, bitTrueAntiLambda); - if (lPDG == 22) + if (qaCollisionAssociation) { + histos.fill(HIST("hCollAssocQA"), 2.0f, collisionAssociationOK); + histos.fill(HIST("h2dPtVsCollAssocAntiLambda"), mcpt, collisionAssociationOK); + } + } + if (lPDG == 22) { bitset(maskElement, bitTrueGamma); + if (qaCollisionAssociation) { + histos.fill(HIST("hCollAssocQA"), 3.0f, collisionAssociationOK); + histos.fill(HIST("h2dPtVsCollAssocGamma"), mcpt, collisionAssociationOK); + } + } if (lPDG == 1010010030) bitset(maskElement, bitTrueHypertriton); if (lPDG == -1010010030) bitset(maskElement, bitTrueAntiHypertriton); + if (physicalPrimary) + bitset(maskElement, bitPhysicalPrimary); } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* template - void checkdEdx(TV0Object const& lV0Candidate, uint16_t& maskElement) + void checkdEdx(TV0Object const& lV0Candidate, uint32_t& maskElement) { auto lNegTrack = lV0Candidate.template negTrack_as(); auto lPosTrack = lV0Candidate.template posTrack_as(); @@ -1490,7 +1621,7 @@ struct lambdakzeroPreselector { void checkAndFinalize() { // parse + publish tag table now - for (int ii = 0; ii < selectionMask.size(); ii++) { + for (std::size_t ii = 0; ii < selectionMask.size(); ii++) { histos.fill(HIST("hPreselectorStatistics"), 0.0f); // all V0s bool validV0 = bitcheck(selectionMask[ii], bitTrackQuality); if (validV0) { @@ -1528,7 +1659,8 @@ struct lambdakzeroPreselector { } v0tags(validV0, bitcheck(selectionMask[ii], bitTrueGamma), bitcheck(selectionMask[ii], bitTrueK0Short), bitcheck(selectionMask[ii], bitTrueLambda), - bitcheck(selectionMask[ii], bitTrueAntiLambda), bitcheck(selectionMask[ii], bitTrueHypertriton), bitcheck(selectionMask[ii], bitTrueAntiHypertriton), + bitcheck(selectionMask[ii], bitTrueAntiLambda), + bitcheck(selectionMask[ii], bitTrueHypertriton), bitcheck(selectionMask[ii], bitTrueAntiHypertriton), bitcheck(selectionMask[ii], bitPhysicalPrimary), bitcheck(selectionMask[ii], bitdEdxGamma), bitcheck(selectionMask[ii], bitdEdxK0Short), bitcheck(selectionMask[ii], bitdEdxLambda), bitcheck(selectionMask[ii], bitdEdxAntiLambda), bitcheck(selectionMask[ii], bitdEdxHypertriton), bitcheck(selectionMask[ii], bitdEdxAntiHypertriton), bitcheck(selectionMask[ii], bitUsedInCascade), bitcheck(selectionMask[ii], bitUsedInTrackedCascade)); @@ -1547,11 +1679,12 @@ struct lambdakzeroPreselector { checkAndFinalize(); } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - void processBuildMCAssociated(aod::Collisions const& /*collisions*/, aod::V0s const& v0table, LabeledTracksExtra const&, aod::McParticles const& /*particlesMC*/) + void processBuildMCAssociated(soa::Join const& /*collisions*/, aod::V0s const& v0table, LabeledTracksExtra const&, aod::McParticles const& /*particlesMC*/) { initializeMasks(v0table.size()); for (auto const& v0 : v0table) { - checkPDG(v0, selectionMask[v0.globalIndex()]); + auto collision = v0.collision_as>(); + checkPDG(v0, selectionMask[v0.globalIndex()], collision.mcCollisionId()); checkTrackQuality(v0, selectionMask[v0.globalIndex()], true); } if (!doprocessSkipV0sNotUsedInCascades && !doprocessSkipV0sNotUsedInTrackedCascades) @@ -1569,11 +1702,12 @@ struct lambdakzeroPreselector { checkAndFinalize(); } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - void processBuildValiddEdxMCAssociated(aod::Collisions const& /*collisions*/, aod::V0s const& v0table, TracksExtraWithPIDandLabels const&, aod::McParticles const&) + void processBuildValiddEdxMCAssociated(soa::Join const& /*collisions*/, aod::V0s const& v0table, TracksExtraWithPIDandLabels const&, aod::McParticles const&) { initializeMasks(v0table.size()); for (auto const& v0 : v0table) { - checkPDG(v0, selectionMask[v0.globalIndex()]); + auto collision = v0.collision_as>(); + checkPDG(v0, selectionMask[v0.globalIndex()], collision.mcCollisionId()); checkdEdx(v0, selectionMask[v0.globalIndex()]); checkTrackQuality(v0, selectionMask[v0.globalIndex()]); } @@ -1581,6 +1715,16 @@ struct lambdakzeroPreselector { checkAndFinalize(); } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + /// This process function ensures that all findable V0s are built. + void processBuildFindable(aod::FindableV0s const& v0table, aod::TracksExtra const&) + { + initializeMasks(v0table.size()); + for (auto const& v0 : v0table) { + checkTrackQuality(v0, selectionMask[v0.globalIndex()], true); + } + checkAndFinalize(); + } + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* /// This process function checks for the use of V0s in cascades /// They are then marked appropriately; the user could then operate /// the lambdakzerobuilder to construct only those V0s. @@ -1609,6 +1753,7 @@ struct lambdakzeroPreselector { PROCESS_SWITCH(lambdakzeroPreselector, processBuildMCAssociated, "Switch to build MC-associated V0s", false); PROCESS_SWITCH(lambdakzeroPreselector, processBuildValiddEdx, "Switch to build V0s with dE/dx preselection", false); PROCESS_SWITCH(lambdakzeroPreselector, processBuildValiddEdxMCAssociated, "Switch to build MC-associated V0s with dE/dx preselection", false); + PROCESS_SWITCH(lambdakzeroPreselector, processBuildFindable, "Switch to build findable V0s. Requires lambdakzeromcfinder", false); /// skippers options (choose one in addition to a processBuild if you like) PROCESS_SWITCH(lambdakzeroPreselector, processSkipV0sNotUsedInCascades, "skip all V0s not used in cascades", false); PROCESS_SWITCH(lambdakzeroPreselector, processSkipV0sNotUsedInTrackedCascades, "skip all V0s not used in tracked cascades", false); @@ -1623,7 +1768,7 @@ struct lambdakzeroV0DataLinkBuilder { //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* // build V0 -> V0Data link table - void process(aod::V0s const& v0table, aod::V0Datas const& v0datatable, aod::V0fCDatas const& v0fcdatatable) + void processFound(aod::V0s const& v0table, aod::V0Datas const& v0datatable, aod::V0fCDatas const& v0fcdatatable) { std::vector lIndices, lfCIndices; lIndices.reserve(v0table.size()); @@ -1643,6 +1788,24 @@ struct lambdakzeroV0DataLinkBuilder { } } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + // build V0Findable -> V0Data link table + void processFindable(aod::FindableV0s const& v0table, aod::V0Datas const& v0datatable) + { + std::vector lIndices; + lIndices.reserve(v0table.size()); + for (int ii = 0; ii < v0table.size(); ii++) { + lIndices[ii] = -1; + } + for (auto& v0data : v0datatable) { + lIndices[v0data.v0Id()] = v0data.globalIndex(); + } + for (int ii = 0; ii < v0table.size(); ii++) { + v0dataLink(lIndices[ii], -1); + } + } + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + PROCESS_SWITCH(lambdakzeroV0DataLinkBuilder, processFound, "process found V0s (default)", true); + PROCESS_SWITCH(lambdakzeroV0DataLinkBuilder, processFindable, "process findable V0s", false); }; // Extends the v0data table with expression columns diff --git a/PWGLF/TableProducer/Strangeness/lambdakzerofinder.cxx b/PWGLF/TableProducer/Strangeness/lambdakzerofinder.cxx index 95f7a396700..60d331ea61d 100644 --- a/PWGLF/TableProducer/Strangeness/lambdakzerofinder.cxx +++ b/PWGLF/TableProducer/Strangeness/lambdakzerofinder.cxx @@ -28,6 +28,19 @@ // david.dobrigkeit.chinellato@cern.ch // +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -44,22 +57,9 @@ #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Centrality.h" #include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPObject.h" #include "DataFormatsParameters/GRPMagField.h" #include "CCDB/BasicCCDBManager.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -123,7 +123,7 @@ struct lambdakzeroprefilter { struct lambdakzerofinder { Produces v0indices; - Produces v0cores; + Produces v0cores; Produces v0trackXs; Produces v0; Produces v0datalink; @@ -270,11 +270,11 @@ struct lambdakzerofinder { int collisionIndex = -1; // float getDCAtoPV(float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ){ for (auto const& collision : collisions) { - float thisDCA = TMath::Abs(getDCAtoPV(vtx[0], vtx[1], vtx[2], pvec0[0] + pvec1[0], pvec0[1] + pvec1[1], pvec0[2] + pvec1[2], collision.posX(), collision.posY(), collision.posY())); + float thisDCA = TMath::Abs(getDCAtoPV(vtx[0], vtx[1], vtx[2], pvec0[0] + pvec1[0], pvec0[1] + pvec1[1], pvec0[2] + pvec1[2], collision.posX(), collision.posY(), collision.posZ())); if (thisDCA < smallestDCA) { collisionIndex = collision.globalIndex(); smallestDCA = thisDCA; - cosPA = RecoDecay::cpa(std::array{collision.posX(), collision.posY(), collision.posY()}, array{vtx[0], vtx[1], vtx[2]}, array{pvec0[0] + pvec1[0], pvec0[1] + pvec1[1], pvec0[2] + pvec1[2]}); + cosPA = RecoDecay::cpa(std::array{collision.posX(), collision.posY(), collision.posZ()}, array{vtx[0], vtx[1], vtx[2]}, array{pvec0[0] + pvec1[0], pvec0[1] + pvec1[1], pvec0[2] + pvec1[2]}); } } if (smallestDCA > maxV0DCAtoPV) diff --git a/PWGLF/TableProducer/Strangeness/lambdakzeromcbuilder.cxx b/PWGLF/TableProducer/Strangeness/lambdakzeromcbuilder.cxx index d646920547f..1d7b1c29490 100644 --- a/PWGLF/TableProducer/Strangeness/lambdakzeromcbuilder.cxx +++ b/PWGLF/TableProducer/Strangeness/lambdakzeromcbuilder.cxx @@ -44,23 +44,129 @@ using std::array; struct lambdakzeromcbuilder { Produces v0labels; // MC labels for V0s Produces v0mccores; // optionally aggregate information from MC side for posterior analysis (derived data) + Produces v0CoreMCLabels; // interlink V0Cores -> V0MCCores in asymmetric mode + Produces v0mccollref; // references collisions from V0MCCores - Configurable populateV0MCCores{"populateV0MCCores", false, "populate V0MCCores table for derived data analysis"}; + Configurable populateV0MCCoresSymmetric{"populateV0MCCoresSymmetric", false, "populate V0MCCores table for derived data analysis, keep V0MCCores joinable with V0Cores"}; + Configurable populateV0MCCoresAsymmetric{"populateV0MCCoresAsymmetric", false, "populate V0MCCores table for derived data analysis, create V0Cores -> V0MCCores interlink. Saves only labeled V0s."}; - void init(InitContext const&) {} + Configurable addGeneratedK0Short{"addGeneratedK0Short", false, "add V0MCCore entry for generated, not-recoed K0Short"}; + Configurable addGeneratedLambda{"addGeneratedLambda", false, "add V0MCCore entry for generated, not-recoed Lambda"}; + Configurable addGeneratedAntiLambda{"addGeneratedAntiLambda", false, "add V0MCCore entry for generated, not-recoed AntiLambda"}; + Configurable addGeneratedGamma{"addGeneratedGamma", false, "add V0MCCore entry for generated, not-recoed Gamma"}; + + Configurable treatPiToMuDecays{"treatPiToMuDecays", true, "if true, will correctly capture pi -> mu and V0 label will still point to originating V0 decay in those cases. Nota bene: prong info will still be for the muon!"}; + + Configurable rapidityWindow{"rapidityWindow", 0.5, "rapidity window to save non-recoed candidates"}; + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext const&) + { + if (populateV0MCCoresAsymmetric) { + LOGF(info, "Asymmetric V0MCCores filling enabled!"); + } + if (populateV0MCCoresSymmetric) { + LOGF(info, "Symmetric V0MCCores filling enabled!"); + } + if (populateV0MCCoresAsymmetric && populateV0MCCoresSymmetric) { + LOGF(fatal, "Error in configuration: please select only one out of populateV0MCCoresAsymmetric and populateV0MCCoresSymmetric! Crashing!"); + } + + // for storing basic statistics + auto h = histos.add("hBuildingStatistics", "hBuildingStatistics", kTH1F, {{4, -0.5, 3.5f}}); + h->GetXaxis()->SetBinLabel(1, "V0Cores population"); + h->GetXaxis()->SetBinLabel(2, "V0MCCores population"); + h->GetXaxis()->SetBinLabel(3, "x check: duplicates"); + h->GetXaxis()->SetBinLabel(4, "x check: unique"); + + auto hK0s = histos.add("hStatisticsK0s", "hBuildingStatisticsK0s", kTH1F, {{3, -0.5, 2.5f}}); + hK0s->GetXaxis()->SetBinLabel(1, "MC associated to reco."); + hK0s->GetXaxis()->SetBinLabel(2, "Not originating from decay"); + hK0s->GetXaxis()->SetBinLabel(3, "MC with un-recoed V0"); + + auto hLambda = histos.add("hStatisticsLambda", "hBuildingStatisticsLambda", kTH1F, {{3, -0.5, 2.5f}}); + hLambda->GetXaxis()->SetBinLabel(1, "MC associated to reco."); + hLambda->GetXaxis()->SetBinLabel(2, "Not originating from decay"); + hLambda->GetXaxis()->SetBinLabel(3, "MC with un-recoed V0"); + + auto hAlambda = histos.add("hStatisticsAlambda", "hBuildingStatisticsAlambda", kTH1F, {{3, -0.5, 2.5f}}); + hAlambda->GetXaxis()->SetBinLabel(1, "MC associated to reco."); + hAlambda->GetXaxis()->SetBinLabel(2, "Not originating from decay"); + hAlambda->GetXaxis()->SetBinLabel(3, "MC with un-recoed V0"); + } + + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + // Helper struct to contain V0MCCore information prior to filling + struct mcV0info { + int label = -1; + int motherLabel = -1; + int pdgCode = 0; + int pdgCodeMother = 0; + int pdgCodePositive = 0; + int pdgCodeNegative = 0; + int mcCollision = -1; + bool isPhysicalPrimary = false; + int processPositive = -1; + int processNegative = -1; + std::array xyz; + std::array posP; + std::array negP; + std::array momentum; + }; + mcV0info thisInfo; + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + + // kink handling + template + int getOriginatingParticle(mcpart const& part, int& indexForPositionOfDecay) + { + int returnValue = -1; + if (part.has_mothers()) { + auto const& motherList = part.template mothers_as(); + if (motherList.size() == 1) { + for (const auto& mother : motherList) { + if (std::abs(part.pdgCode()) == 13 && treatPiToMuDecays) { + // muon decay, de-ref mother twice + if (mother.has_mothers()) { + auto grandMotherList = mother.template mothers_as(); + if (grandMotherList.size() == 1) { + for (const auto& grandMother : grandMotherList) { + returnValue = grandMother.globalIndex(); + indexForPositionOfDecay = mother.globalIndex(); // for V0 decay position: grab muon + } + } + } + } else { + returnValue = mother.globalIndex(); + indexForPositionOfDecay = part.globalIndex(); + } + } + } + } + return returnValue; + } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* // build V0 labels - void process(aod::V0Datas const& v0table, aod::McTrackLabels const&, aod::McParticles const& /*particlesMC*/) + void process(aod::V0Datas const& v0table, aod::McTrackLabels const&, aod::McParticles const& mcParticles) { - for (auto& v0 : v0table) { - int lLabel = -1, lMotherLabel = -1; - int pdgCode = -1, pdgCodeMother = -1, pdgCodePositive = -1, pdgCodeNegative = -1; - bool isPhysicalPrimary = false; - float xmc = -999.0f, ymc = -999.0f, zmc = -999.0f; - float pxposmc = -999.0f, pyposmc = -999.0f, pzposmc = -999.0f; - float pxnegmc = -999.0f, pynegmc = -999.0f, pznegmc = -999.0f; + // to be used if using the populateV0MCCoresAsymmetric mode, kept empty otherwise + std::vector mcV0infos; // V0MCCore information + std::vector mcParticleIsReco(mcParticles.size(), false); // mc Particle not recoed by V0s + for (auto& v0 : v0table) { + thisInfo.label = -1; + thisInfo.motherLabel = -1; + thisInfo.pdgCode = 0; + thisInfo.pdgCodeMother = 0; + thisInfo.pdgCodePositive = 0; + thisInfo.pdgCodeNegative = 0; + thisInfo.mcCollision = -1; + thisInfo.xyz[0] = thisInfo.xyz[1] = thisInfo.xyz[2] = 0.0f; + thisInfo.posP[0] = thisInfo.posP[1] = thisInfo.posP[2] = 0.0f; + thisInfo.negP[0] = thisInfo.negP[1] = thisInfo.negP[2] = 0.0f; + thisInfo.momentum[0] = thisInfo.momentum[1] = thisInfo.momentum[2] = 0.0f; auto lNegTrack = v0.negTrack_as(); auto lPosTrack = v0.posTrack_as(); @@ -69,47 +175,273 @@ struct lambdakzeromcbuilder { if (lNegTrack.has_mcParticle() && lPosTrack.has_mcParticle()) { auto lMCNegTrack = lNegTrack.mcParticle_as(); auto lMCPosTrack = lPosTrack.mcParticle_as(); - pdgCodePositive = lMCPosTrack.pdgCode(); - pdgCodeNegative = lMCNegTrack.pdgCode(); - pxposmc = lMCPosTrack.px(); - pyposmc = lMCPosTrack.py(); - pzposmc = lMCPosTrack.pz(); - pxnegmc = lMCNegTrack.px(); - pynegmc = lMCNegTrack.py(); - pznegmc = lMCNegTrack.pz(); - if (lMCNegTrack.has_mothers() && lMCPosTrack.has_mothers()) { - for (auto& lNegMother : lMCNegTrack.mothers_as()) { - for (auto& lPosMother : lMCPosTrack.mothers_as()) { - if (lNegMother.globalIndex() == lPosMother.globalIndex()) { - lLabel = lNegMother.globalIndex(); - // acquire information - xmc = lMCPosTrack.vx(); - ymc = lMCPosTrack.vy(); - zmc = lMCPosTrack.vz(); - pdgCode = lNegMother.pdgCode(); - isPhysicalPrimary = lNegMother.isPhysicalPrimary(); - if (lNegMother.has_mothers()) { - for (auto& lNegGrandMother : lNegMother.mothers_as()) { - pdgCodeMother = lNegGrandMother.pdgCode(); - lMotherLabel = lNegGrandMother.globalIndex(); - } - } - } + + thisInfo.pdgCodePositive = lMCPosTrack.pdgCode(); + thisInfo.pdgCodeNegative = lMCNegTrack.pdgCode(); + thisInfo.processPositive = lMCPosTrack.getProcess(); + thisInfo.processNegative = lMCNegTrack.getProcess(); + thisInfo.posP[0] = lMCPosTrack.px(); + thisInfo.posP[1] = lMCPosTrack.py(); + thisInfo.posP[2] = lMCPosTrack.pz(); + thisInfo.negP[0] = lMCNegTrack.px(); + thisInfo.negP[1] = lMCNegTrack.py(); + thisInfo.negP[2] = lMCNegTrack.pz(); + + // check for pi -> mu + antineutrino decay + // if present, de-reference original V0 correctly and provide label to original object + // NOTA BENE: the prong info will still correspond to a muon, treat carefully! + int negOriginating = -1, posOriginating = -1, particleForDecayPositionIdx = -1; + negOriginating = getOriginatingParticle(lMCNegTrack, particleForDecayPositionIdx); + posOriginating = getOriginatingParticle(lMCPosTrack, particleForDecayPositionIdx); + + if (negOriginating > -1 && negOriginating == posOriginating) { + auto originatingV0 = mcParticles.rawIteratorAt(negOriginating); + auto particleForDecayPosition = mcParticles.rawIteratorAt(particleForDecayPositionIdx); + + thisInfo.label = originatingV0.globalIndex(); + thisInfo.xyz[0] = particleForDecayPosition.vx(); + thisInfo.xyz[1] = particleForDecayPosition.vy(); + thisInfo.xyz[2] = particleForDecayPosition.vz(); + + // MC pos. and neg. daughters are the same! Looking for replacement... + // if (lMCPosTrack.globalIndex() == lMCNegTrack.globalIndex()) { + // auto const& daughters = lNegMother.daughters_as(); + // for (auto& ldau : daughters) { + // // check if the candidate originates from a decay + // // if not, this is not a suitable candidate for one of the decay daughters + // if (ldau.getProcess() != 4) // see TMCProcess.h + // continue; + + // if (lMCPosTrack.pdgCode() < 0 && ldau.pdgCode() > 0) { // the positive track needs to be changed + // thisInfo.pdgCodePositive = ldau.pdgCode(); + // thisInfo.processPositive = ldau.getProcess(); + // thisInfo.posP[0] = ldau.px(); + // thisInfo.posP[1] = ldau.py(); + // thisInfo.posP[2] = ldau.pz(); + // thisInfo.xyz[0] = ldau.vx(); + // thisInfo.xyz[1] = ldau.vy(); + // thisInfo.xyz[2] = ldau.vz(); + // } + // if (lMCNegTrack.pdgCode() > 0 && ldau.pdgCode() < 0) { // the negative track needs to be changed + // thisInfo.pdgCodeNegative = ldau.pdgCode(); + // thisInfo.processNegative = ldau.getProcess(); + // thisInfo.negP[0] = ldau.px(); + // thisInfo.negP[1] = ldau.py(); + // thisInfo.negP[2] = ldau.pz(); + // } + // } + // } + + if (originatingV0.has_mcCollision()) { + thisInfo.mcCollision = originatingV0.mcCollisionId(); // save this reference, please + } + + // acquire information + thisInfo.pdgCode = originatingV0.pdgCode(); + thisInfo.isPhysicalPrimary = originatingV0.isPhysicalPrimary(); + thisInfo.momentum[0] = originatingV0.px(); + thisInfo.momentum[1] = originatingV0.py(); + thisInfo.momentum[2] = originatingV0.pz(); + + if (originatingV0.has_mothers()) { + for (auto& lV0Mother : originatingV0.mothers_as()) { + thisInfo.pdgCodeMother = lV0Mother.pdgCode(); + thisInfo.motherLabel = lV0Mother.globalIndex(); } } } + } // end association check // Construct label table (note: this will be joinable with V0Datas!) v0labels( - lLabel, lMotherLabel); - if (populateV0MCCores) { + thisInfo.label, thisInfo.motherLabel); + + // Mark mcParticle as recoed (no searching necessary afterwards) + if (thisInfo.label > -1) { + mcParticleIsReco[thisInfo.label] = true; + } + + // ---] Symmetric populate [--- + // in this approach, V0Cores will be joinable with V0MCCores. + // this is the most pedagogical approach, but it is also more limited + // and it might use more disk space unnecessarily. + if (populateV0MCCoresSymmetric) { v0mccores( - pdgCode, pdgCodeMother, pdgCodePositive, pdgCodeNegative, - isPhysicalPrimary, xmc, ymc, zmc, - pxposmc, pyposmc, pzposmc, - pxnegmc, pynegmc, pznegmc); + thisInfo.label, thisInfo.pdgCode, + thisInfo.pdgCodeMother, thisInfo.pdgCodePositive, thisInfo.pdgCodeNegative, + thisInfo.isPhysicalPrimary, thisInfo.xyz[0], thisInfo.xyz[1], thisInfo.xyz[2], + thisInfo.posP[0], thisInfo.posP[1], thisInfo.posP[2], + thisInfo.negP[0], thisInfo.negP[1], thisInfo.negP[2], + thisInfo.momentum[0], thisInfo.momentum[1], thisInfo.momentum[2]); + v0mccollref(thisInfo.mcCollision); + + // n.b. placing the interlink index here allows for the writing of + // code that is agnostic with respect to the joinability of + // V0Cores and V0MCCores (always dereference -> safe) + v0CoreMCLabels(v0.globalIndex()); // interlink index + } + // ---] Asymmetric populate [--- + // in this approach, V0Cores will NOT be joinable with V0MCCores. + // an additional reference to V0MCCore that IS joinable with V0Cores + // will be provided to the user. + if (populateV0MCCoresAsymmetric) { + int thisV0MCCoreIndex = -1; + // step 1: check if this element is already provided in the table + // using the packedIndices variable calculated above + for (uint32_t ii = 0; ii < mcV0infos.size(); ii++) { + if (thisInfo.label == mcV0infos[ii].label && mcV0infos[ii].label > -1) { + thisV0MCCoreIndex = ii; + histos.fill(HIST("hBuildingStatistics"), 2.0f); // found + break; // this exists already in list + } + } + if (thisV0MCCoreIndex < 0 && thisInfo.label > -1) { + // this V0MCCore does not exist yet. Create it and reference it + histos.fill(HIST("hBuildingStatistics"), 3.0f); // new + thisV0MCCoreIndex = mcV0infos.size(); + mcV0infos.push_back(thisInfo); + + // For bookkeeping + if (thisInfo.label > -1 && thisInfo.isPhysicalPrimary) { + float ymc = 1e3; + if (thisInfo.pdgCode == 310) + ymc = RecoDecay::y(std::array{thisInfo.posP[0] + thisInfo.negP[0], thisInfo.posP[1] + thisInfo.negP[1], thisInfo.posP[2] + thisInfo.negP[2]}, o2::constants::physics::MassKaonNeutral); + else if (TMath::Abs(thisInfo.pdgCode) == 3122) + ymc = RecoDecay::y(std::array{thisInfo.posP[0] + thisInfo.negP[0], thisInfo.posP[1] + thisInfo.negP[1], thisInfo.posP[2] + thisInfo.negP[2]}, o2::constants::physics::MassLambda); + + if (thisInfo.pdgCode == 310 && TMath::Abs(ymc) < rapidityWindow) { + histos.fill(HIST("hStatisticsK0s"), 0.0f); // found + if (thisInfo.processPositive != 4 || thisInfo.processNegative != 4) { + histos.fill(HIST("hStatisticsK0s"), 1.0f); // Not originating from decay + } + } + if (thisInfo.pdgCode == 3122 && TMath::Abs(ymc) < rapidityWindow) { + histos.fill(HIST("hStatisticsLambda"), 0.0f); // found + if (thisInfo.processPositive != 4 || thisInfo.processNegative != 4) { + histos.fill(HIST("hStatisticsLambda"), 1.0f); // Not originating from decay + } + } + if (thisInfo.pdgCode == -3122 && TMath::Abs(ymc) < rapidityWindow) { + histos.fill(HIST("hStatisticsAlambda"), 0.0f); // found + if (thisInfo.processPositive != 4 || thisInfo.processNegative != 4) { + histos.fill(HIST("hStatisticsAlambda"), 1.0f); // Not originating from decay + } + } + } + } + v0CoreMCLabels(thisV0MCCoreIndex); // interlink index } } + + // now populate V0MCCores if in asymmetric mode + if (populateV0MCCoresAsymmetric) { + // first step: add any un-recoed v0mmcores that were requested + for (auto& mcParticle : mcParticles) { + thisInfo.label = -1; + thisInfo.motherLabel = -1; + thisInfo.pdgCode = 0; + thisInfo.pdgCodeMother = -1; + thisInfo.pdgCodePositive = -1; + thisInfo.pdgCodeNegative = -1; + thisInfo.mcCollision = -1; + thisInfo.xyz[0] = thisInfo.xyz[1] = thisInfo.xyz[2] = 0.0f; + thisInfo.posP[0] = thisInfo.posP[1] = thisInfo.posP[2] = 0.0f; + thisInfo.negP[0] = thisInfo.negP[1] = thisInfo.negP[2] = 0.0f; + thisInfo.momentum[0] = thisInfo.momentum[1] = thisInfo.momentum[2] = 0.0f; + + if (mcParticleIsReco[mcParticle.globalIndex()] == true) + continue; // skip if already created in list + + if (TMath::Abs(mcParticle.y()) > rapidityWindow) + continue; // skip outside midrapidity + + if ( + (addGeneratedK0Short && mcParticle.pdgCode() == 310) || + (addGeneratedLambda && mcParticle.pdgCode() == 3122) || + (addGeneratedAntiLambda && mcParticle.pdgCode() == -3122) || + (addGeneratedGamma && mcParticle.pdgCode() == 22)) { + thisInfo.pdgCode = mcParticle.pdgCode(); + thisInfo.isPhysicalPrimary = mcParticle.isPhysicalPrimary(); + thisInfo.label = mcParticle.globalIndex(); + + if (mcParticle.has_mcCollision()) { + thisInfo.mcCollision = mcParticle.mcCollisionId(); // save this reference, please + } + + // + thisInfo.momentum[0] = mcParticle.px(); + thisInfo.momentum[1] = mcParticle.py(); + thisInfo.momentum[2] = mcParticle.pz(); + + if (mcParticle.has_mothers()) { + auto const& mother = mcParticle.mothers_first_as(); + thisInfo.pdgCodeMother = mother.pdgCode(); + thisInfo.motherLabel = mother.globalIndex(); + } + if (mcParticle.has_daughters()) { + auto const& daughters = mcParticle.daughters_as(); + + for (auto& dau : daughters) { + if (dau.getProcess() != 4) + continue; + + if (dau.pdgCode() > 0) { + thisInfo.pdgCodePositive = dau.pdgCode(); + thisInfo.processPositive = dau.getProcess(); + thisInfo.posP[0] = dau.px(); + thisInfo.posP[1] = dau.py(); + thisInfo.posP[2] = dau.pz(); + thisInfo.xyz[0] = dau.vx(); + thisInfo.xyz[1] = dau.vy(); + thisInfo.xyz[2] = dau.vz(); + } + if (dau.pdgCode() < 0) { + thisInfo.pdgCodeNegative = dau.pdgCode(); + thisInfo.processNegative = dau.getProcess(); + thisInfo.negP[0] = dau.px(); + thisInfo.negP[1] = dau.py(); + thisInfo.negP[2] = dau.pz(); + } + } + } + + // For bookkeeping + float ymc = 1e3; + if (mcParticle.pdgCode() == 310) + ymc = RecoDecay::y(std::array{thisInfo.posP[0] + thisInfo.negP[0], thisInfo.posP[1] + thisInfo.negP[0], thisInfo.posP[2] + thisInfo.negP[2]}, o2::constants::physics::MassKaonNeutral); + else if (TMath::Abs(mcParticle.pdgCode()) == 3122) + ymc = RecoDecay::y(std::array{thisInfo.posP[0] + thisInfo.negP[0], thisInfo.posP[1] + thisInfo.negP[0], thisInfo.posP[2] + thisInfo.negP[2]}, o2::constants::physics::MassLambda); + + if (mcParticle.pdgCode() == 310 && mcParticle.isPhysicalPrimary() && TMath::Abs(ymc) < rapidityWindow) { + histos.fill(HIST("hStatisticsK0s"), 2.0f); // found + } + if (mcParticle.pdgCode() == 3122 && mcParticle.isPhysicalPrimary() && TMath::Abs(ymc) < rapidityWindow) { + histos.fill(HIST("hStatisticsLambda"), 2.0f); // found + } + if (mcParticle.pdgCode() == -3122 && mcParticle.isPhysicalPrimary() && TMath::Abs(ymc) < rapidityWindow) { + histos.fill(HIST("hStatisticsAlambda"), 2.0f); // found + } + + // if I got here, it means this MC particle was not recoed and is of interest. Add it please + mcV0infos.push_back(thisInfo); + } + } + + for (auto info : mcV0infos) { + v0mccores( + info.label, info.pdgCode, + info.pdgCodeMother, info.pdgCodePositive, info.pdgCodeNegative, + info.isPhysicalPrimary, info.xyz[0], info.xyz[1], info.xyz[2], + info.posP[0], info.posP[1], info.posP[2], + info.negP[0], info.negP[1], info.negP[2], + info.momentum[0], info.momentum[1], info.momentum[2]); + v0mccollref(info.mcCollision); + } + } + + // collect operating parameters + histos.fill(HIST("hBuildingStatistics"), 0.0f, v0table.size()); + histos.fill(HIST("hBuildingStatistics"), 1.0f, mcV0infos.size()); } }; diff --git a/PWGLF/TableProducer/Strangeness/lambdakzeromcfinder.cxx b/PWGLF/TableProducer/Strangeness/lambdakzeromcfinder.cxx index a7d898bc0f2..0a0db73ea6d 100644 --- a/PWGLF/TableProducer/Strangeness/lambdakzeromcfinder.cxx +++ b/PWGLF/TableProducer/Strangeness/lambdakzeromcfinder.cxx @@ -24,10 +24,18 @@ // david.dobrigkeit.chinellato@cern.ch // -#include #include #include #include +#include + +#include "Math/Vector4D.h" +#include +#include +#include +#include +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -50,14 +58,6 @@ #include "CommonConstants/PhysicsConstants.h" #include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table -#include -#include -#include -#include -#include -#include -#include - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -68,7 +68,7 @@ using LabeledTracks = soa::Join; struct lambdakzeromcfinder { - Produces v0; + Produces v0; Produces fullv0labels; HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -83,7 +83,8 @@ struct lambdakzeromcfinder { Configurable requireTPC{"requireTPC", true, "require TPC"}; Configurable skipTPConly{"skipTPConly", false, "skip tracks that are TPC-only"}; Configurable storeSingleTPCOnlyProng{"storeSingleTPCOnlyProng", false, "in case a TPC-only track is found, do not allow another TPC-only for the same mcParticle. Works only in MC particle path."}; - Configurable doUnassociatedV0s{"doUnassociatedV0s", true, "generate also unassociated V0s (for cascades!)"}; + Configurable doAssociatedV0s{"doAssociatedV0s", true, "generate collision-associated V0s (for cascades!)"}; + Configurable doUnassociatedV0s{"doUnassociatedV0s", true, "generate also unassociated V0s (for cascades, UPC)"}; Configurable doSameCollisionOnly{"doSameCollisionOnly", false, "stick to decays in which tracks are assoc to same collision"}; Configurable qaNbins{"qaNbins", 200, "qa plots: binning"}; Configurable yPreFilter{"yPreFilter", 2.5, "broad y pre-filter for speed"}; @@ -109,6 +110,9 @@ struct lambdakzeromcfinder { histos.add("hNTimesCollRecoed", "hNTimesCollRecoed", kTH1F, {axisNTimesRecoed}); + // store number of recoed V0s and number of recoed V0s with no collision association + histos.add("hNCollisionAssociation", "hNCollisionAssociation", kTH1F, {axisNTimesRecoed}); + // warning: this stores (composite) number of copies of tracks histos.add("hNTimesRecoedGamma", "hNTimesRecoedGamma", kTH2F, {axisNTimesRecoed, axisPtQA}); histos.add("hNTimesRecoedK0Short", "hNTimesRecoedK0Short", kTH2F, {axisNTimesRecoed, axisPtQA}); @@ -178,15 +182,16 @@ struct lambdakzeromcfinder { { int nPosReco = 0; int nNegReco = 0; - const int maxReco = 20; - int trackIndexPositive[maxReco]; - int trackIndexNegative[maxReco]; + std::vector trackIndexPositive; + std::vector trackIndexNegative; int positivePdg = 211; int negativePdg = -211; + int relevantProcess = 4; // normal search: decay if (mcParticle.pdgCode() == 22) { positivePdg = -11; negativePdg = +11; + relevantProcess = 5; // look for pair production if photon } if (mcParticle.pdgCode() == 3122) { positivePdg = 2212; @@ -205,7 +210,7 @@ struct lambdakzeromcfinder { auto const& daughters = mcParticle.template daughters_as(); if (daughters.size() >= 2) { for (auto const& daughter : daughters) { // might be better ways of doing this but ok - if (daughter.getProcess() != 4) + if (daughter.getProcess() != relevantProcess) continue; // skip deltarays (if ever), stick to decay products only if (daughter.pdgCode() == positivePdg) { auto const& thisDaughterTracks = daughter.template tracks_as(); @@ -219,7 +224,7 @@ struct lambdakzeromcfinder { tpcOnlyFound = true; } if (track.sign() > 0 && (track.hasTPC() || !requireTPC)) { - trackIndexPositive[nPosReco] = track.globalIndex(); // assign only if TPC present + trackIndexPositive.push_back(track.globalIndex()); // assign only if TPC present nPosReco++; } } // end track list loop @@ -236,7 +241,7 @@ struct lambdakzeromcfinder { tpcOnlyFound = true; } if (track.sign() < 0 && (track.hasTPC() || !requireTPC)) { - trackIndexNegative[nNegReco] = track.globalIndex(); // assign only if TPC present + trackIndexNegative.push_back(track.globalIndex()); // assign only if TPC present nNegReco++; } } // end track list loop @@ -301,7 +306,15 @@ struct lambdakzeromcfinder { // V0 list established, populate for (auto ic : sortedIndices) { - if (v0collisionId[ic] >= 0 || doUnassociatedV0s) { + histos.fill(HIST("hNCollisionAssociation"), 0.0f); // any correctly recoed + if (v0collisionId[ic] >= 0) + histos.fill(HIST("hNCollisionAssociation"), 1.0f); // reconstructed with a collision associated to it + + if (v0collisionId[ic] < 0 && doUnassociatedV0s) { + v0(v0collisionId[ic], v0positiveIndex[ic], v0negativeIndex[ic], 1); + fullv0labels(v0mcLabel[ic]); + } + if (v0collisionId[ic] >= 0 && doAssociatedV0s) { v0(v0collisionId[ic], v0positiveIndex[ic], v0negativeIndex[ic], 1); fullv0labels(v0mcLabel[ic]); } @@ -338,7 +351,7 @@ struct lambdakzeromcfinder { continue; // skip particles without decay mothers for (auto& posMotherParticle : posParticle.mothers_as()) { // determine if mother particle satisfies any condition curently being searched for - for (int ipdg = 0; ipdg < searchedV0PDG.size(); ipdg++) + for (std::size_t ipdg = 0; ipdg < searchedV0PDG.size(); ipdg++) if (searchedV0PDG[ipdg] == posMotherParticle.pdgCode() && fabs(posMotherParticle.y()) < yPreFilter) { v0pdgIndex = ipdg; // index mapping to desired V0 species motherIndex = posMotherParticle.globalIndex(); diff --git a/PWGLF/TableProducer/Strangeness/lambdakzeromlselection.cxx b/PWGLF/TableProducer/Strangeness/lambdakzeromlselection.cxx index 97e48328e3d..412161ebe52 100644 --- a/PWGLF/TableProducer/Strangeness/lambdakzeromlselection.cxx +++ b/PWGLF/TableProducer/Strangeness/lambdakzeromlselection.cxx @@ -77,6 +77,9 @@ struct lambdakzeromlselection { Produces gammaMLSelections; // optionally aggregate information from ML output for posterior analysis (derived data) Produces lambdaMLSelections; // optionally aggregate information from ML output for posterior analysis (derived data) + Produces antiLambdaMLSelections; // optionally aggregate information from ML output for posterior analysis (derived data) + Produces kzeroShortMLSelections; // optionally aggregate information from ML output for posterior analysis (derived data) + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; // ML inference @@ -86,6 +89,17 @@ struct lambdakzeromlselection { Configurable PredictKZeroShort{"PredictKZeroShort", false, "Flag to enable or disable the loading of model"}; Configurable fIsMC{"fIsMC", false, "If true, save additional MC info for analysis"}; + // Feature selection masks: + + //// Order: LambdaMass, AntiLambdaMass, GammaMass, KZeroShortMass, PT, Qt, Alpha, PosEta, NegEta, V0Eta + Configurable> Kine_SelMap{"Kine_SelMap", std::vector{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, "Mask to select basic kinematic features for ML Inference"}; + + //// Order: Z, V0radius, PA, DCApostopv, DCAnegtopv, DCAV0daughters, DCAv0topv, PsiPair + Configurable> Topo_SelMap{"Topo_SelMap", std::vector{0, 1, 1, 1, 1, 1, 1, 0}, "Mask to select basic topological features for ML Inference"}; + + //// Casting + std::vector CastKine_SelMap, CastTopo_SelMap, Feature_SelMask; + // CCDB configuration o2::ccdb::CcdbApi ccdbApi; Service ccdb; @@ -163,44 +177,90 @@ struct lambdakzeromlselection { if (PredictKZeroShort) kzeroshort_bdt.initModel(BDTLocalPathKZeroShort.value, enableOptimizations.value); } + + /// Here the Configurables are passed to std::vectors + CastKine_SelMap = (std::vector)Kine_SelMap; + CastTopo_SelMap = (std::vector)Topo_SelMap; + + // Concatenate the selection masks + Feature_SelMask.reserve(CastKine_SelMap.size() + CastTopo_SelMap.size()); // Reserve space to avoid reallocations + Feature_SelMask.insert(Feature_SelMask.end(), CastKine_SelMap.begin(), CastKine_SelMap.end()); + Feature_SelMask.insert(Feature_SelMask.end(), CastTopo_SelMap.begin(), CastTopo_SelMap.end()); + LOG(info) << "Feature_SelMask size: " << Feature_SelMask.size(); + } + + template + std::vector extractSelectedElements(const std::vector& base_features, const std::vector& Sel_mask) + { + std::vector selected_elements; + for (size_t i = 0; i < Sel_mask.size(); ++i) { + if (Sel_mask[i] >= 1) { // If the mask value is true, select the corresponding element + selected_elements.push_back(base_features[i]); + } + } + return selected_elements; } // Process candidate and store properties in object - template - void processCandidate(TV0Object const& cand) + template + void processCandidate(TV0Object const& cand, const std::vector& Feature_SelMask) { - std::vector inputFeatures{cand.pt(), static_cast(cand.qtarm()), - cand.alpha(), cand.v0radius(), - cand.v0cosPA(), cand.dcaV0daughters(), - cand.dcapostopv(), cand.dcanegtopv()}; - - // calculate classifier - float* LambdaProbability = lambda_bdt.evalModel(inputFeatures); - float* GammaProbability = gamma_bdt.evalModel(inputFeatures); - // float* AntiLambdaProbability = antilambda_bdt.evalModel(inputFeatures); // WIP - // float* KZeroShortProbability = kzeroshort_bdt.evalModel(inputFeatures); // WIP - - gammaMLSelections(GammaProbability[1]); - lambdaMLSelections(LambdaProbability[1]); + // Select features + std::vector base_features{cand.mLambda(), cand.mAntiLambda(), + cand.mGamma(), cand.mK0Short(), + cand.pt(), static_cast(cand.qtarm()), cand.alpha(), + cand.positiveeta(), cand.negativeeta(), cand.eta(), + cand.z(), cand.v0radius(), static_cast(TMath::ACos(cand.v0cosPA())), + cand.dcapostopv(), cand.dcanegtopv(), cand.dcaV0daughters(), + cand.dcav0topv(), cand.psipair()}; + + // Apply mask to select features + std::vector inputFeatures = extractSelectedElements(base_features, Feature_SelMask); + + // calculate classifier output + if (PredictLambda) { + float* LambdaProbability = lambda_bdt.evalModel(inputFeatures); + lambdaMLSelections(LambdaProbability[1]); + } + if (PredictGamma) { + float* GammaProbability = gamma_bdt.evalModel(inputFeatures); + gammaMLSelections(GammaProbability[1]); + } + if (PredictAntiLambda) { + float* AntiLambdaProbability = antilambda_bdt.evalModel(inputFeatures); + antiLambdaMLSelections(AntiLambdaProbability[1]); + } + if (PredictKZeroShort) { + float* KZeroShortProbability = kzeroshort_bdt.evalModel(inputFeatures); + kzeroShortMLSelections(KZeroShortProbability[1]); + } } void processDerivedData(aod::StraCollision const& coll, V0DerivedDatas const& v0s) { histos.fill(HIST("hEventVertexZ"), coll.posZ()); for (auto& v0 : v0s) { - processCandidate(v0); + nCandidates++; + if (nCandidates % 50000 == 0) { + LOG(info) << "Candidates processed: " << nCandidates; + } + processCandidate(v0, Feature_SelMask); } } void processStandardData(aod::Collision const& coll, V0OriginalDatas const& v0s) { histos.fill(HIST("hEventVertexZ"), coll.posZ()); for (auto& v0 : v0s) { - processCandidate(v0); + nCandidates++; + if (nCandidates % 50000 == 0) { + LOG(info) << "Candidates processed: " << nCandidates; + } + processCandidate(v0, Feature_SelMask); } } - PROCESS_SWITCH(lambdakzeromlselection, processStandardData, "Process standard data", true); - PROCESS_SWITCH(lambdakzeromlselection, processDerivedData, "Process derived data", false); + PROCESS_SWITCH(lambdakzeromlselection, processStandardData, "Process standard data", false); + PROCESS_SWITCH(lambdakzeromlselection, processDerivedData, "Process derived data", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/TableProducer/Strangeness/lambdakzeropid.cxx b/PWGLF/TableProducer/Strangeness/lambdakzeropid.cxx index 1624a8094d2..c6041aa0e02 100644 --- a/PWGLF/TableProducer/Strangeness/lambdakzeropid.cxx +++ b/PWGLF/TableProducer/Strangeness/lambdakzeropid.cxx @@ -49,6 +49,7 @@ #include "DataFormatsParameters/GRPObject.h" #include "DataFormatsParameters/GRPMagField.h" #include "CCDB/BasicCCDBManager.h" +#include "DataFormatsCalibration/MeanVertexObject.h" #include "CommonConstants/PhysicsConstants.h" #include "Common/TableProducer/PID/pidTOFBase.h" #include "Common/DataModel/PIDResponse.h" @@ -75,6 +76,9 @@ struct lambdakzeropid { Service ccdb; + // mean vertex position to be used if no collision associated + o2::dataformats::MeanVertexObject* mVtx = nullptr; + // For manual sliceBy Preslice perCollisionOriginal = o2::aod::v0data::collisionId; ; @@ -100,6 +104,11 @@ struct lambdakzeropid { Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; Configurable nSigmaPath{"nSigmaPath", "Users/d/ddobrigk/stratof", "Path of information for n-sigma calculation"}; + Configurable mVtxPath{"mVtxPath", "GLO/Calib/MeanVertex", "Path of the mean vertex file"}; + + // manual + Configurable useCustomRunNumber{"useCustomRunNumber", false, "Use custom timestamp"}; + Configurable manualRunNumber{"manualRunNumber", 544122, "manual run number if no collisions saved"}; ConfigurableAxis axisEta{"axisEta", {20, -1.0f, +1.0f}, "#eta"}; ConfigurableAxis axisDeltaTime{"axisDeltaTime", {2000, -1000.0f, +1000.0f}, "delta-time (ps)"}; @@ -318,10 +327,9 @@ struct lambdakzeropid { } } - template - void initCCDB(TInformationClass const& infoObject) + void initCCDB(int runNumber) { - if (mRunNumber == infoObject.runNumber()) { + if (mRunNumber == runNumber) { return; } @@ -333,32 +341,33 @@ struct lambdakzeropid { grpmag.setL3Current(30000.f / (d_bz / 5.0f)); } o2::base::Propagator::initFieldFromGRP(&grpmag); - mRunNumber = infoObject.runNumber(); + mVtx = ccdb->getForRun(mVtxPath, runNumber); + mRunNumber = runNumber; return; } - auto run3grp_timestamp = infoObject.timestamp(); - o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + o2::parameters::GRPObject* grpo = ccdb->getForRun(grpPath, runNumber); o2::parameters::GRPMagField* grpmag = 0x0; if (grpo) { o2::base::Propagator::initFieldFromGRP(grpo); // Fetch magnetic field from ccdb for current collision d_bz = grpo->getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + LOG(info) << "Retrieved GRP for run " << runNumber << " with magnetic field of " << d_bz << " kZG"; } else { - grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + grpmag = ccdb->getForRun(grpmagPath, runNumber); if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for run " << runNumber; } o2::base::Propagator::initFieldFromGRP(grpmag); // Fetch magnetic field from ccdb for current collision d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + mVtx = ccdb->getForRun(mVtxPath, runNumber); + LOG(info) << "Retrieved GRP for run " << runNumber << " with magnetic field of " << d_bz << " kZG"; } // if TOF Nsigma desired if (doNSigmas) { - nSigmaCalibObjects = ccdb->getForTimeStamp(nSigmaPath, infoObject.timestamp()); + nSigmaCalibObjects = ccdb->getForRun(nSigmaPath, runNumber); if (nSigmaCalibObjects) { LOGF(info, "loaded TList with this many objects: %i", nSigmaCalibObjects->GetEntries()); @@ -393,7 +402,7 @@ struct lambdakzeropid { } } } - mRunNumber = infoObject.runNumber(); + mRunNumber = runNumber; } float velocity(float lMomentum, float lMass) @@ -409,7 +418,7 @@ struct lambdakzeropid { void processV0Candidate(TCollision const& collision, TV0 const& v0, TTrack const& pTra, TTrack const& nTra) { // time of V0 segment - float lengthV0 = std::hypot(v0.x() - collision.posX(), v0.y() - collision.posY(), v0.z() - collision.posZ()); + float lengthV0 = std::hypot(v0.x() - collision.getX(), v0.y() - collision.getY(), v0.z() - collision.getZ()); float velocityK0Short = velocity(v0.p(), o2::constants::physics::MassKaonNeutral); float velocityLambda = velocity(v0.p(), o2::constants::physics::MassLambda); float timeK0Short = lengthV0 / velocityK0Short; // in picoseconds @@ -460,14 +469,14 @@ struct lambdakzeropid { // calculate and pack properties for QA purposes int posProperties = 0; if (lengthPositive > 0) - posProperties = posProperties | (int(1) << kLength); + posProperties = posProperties | (static_cast(1) << kLength); if (pTra.hasTOF()) - posProperties = posProperties | (int(1) << kHasTOF); + posProperties = posProperties | (static_cast(1) << kHasTOF); int negProperties = 0; if (lengthNegative > 0) - negProperties = negProperties | (int(1) << kLength); + negProperties = negProperties | (static_cast(1) << kLength); if (nTra.hasTOF()) - negProperties = negProperties | (int(1) << kHasTOF); + negProperties = negProperties | (static_cast(1) << kHasTOF); histos.fill(HIST("h2dPositiveTOFProperties"), v0.pt(), posProperties); histos.fill(HIST("h2dNegativeTOFProperties"), v0.pt(), negProperties); @@ -582,43 +591,57 @@ struct lambdakzeropid { void processStandardData(aod::Collisions const& collisions, V0OriginalDatas const& V0s, TracksWithAllExtras const&, aod::BCsWithTimestamps const& /*bcs*/) { - auto collision = collisions.begin(); - auto bc = collision.bc_as(); - // Fire up CCDB - based on standard collisions - initCCDB(bc); - for (const auto& collision : collisions) { - // Do analysis with collision-grouped V0s, retain full collision information - const uint64_t collIdx = collision.globalIndex(); - auto V0Table_thisCollision = V0s.sliceBy(perCollisionOriginal, collIdx); - histos.fill(HIST("hCandidateCounter"), V0Table_thisCollision.size()); - // V0 table sliced - for (auto const& v0 : V0Table_thisCollision) { - // de-reference interlinks by hand for derived data - auto pTra = v0.posTrack_as(); - auto nTra = v0.negTrack_as(); - - processV0Candidate(collision, v0, pTra, nTra); + // Fire up CCDB with first collision in record. If no collisions, bypass + if (useCustomRunNumber || collisions.size() < 1) { + initCCDB(manualRunNumber); + } else { + auto collision = collisions.begin(); + auto bc = collision.bc_as(); + initCCDB(bc.runNumber()); + } + + for (const auto& V0 : V0s) { + // for storing whatever is the relevant quantity for the PV + o2::dataformats::VertexBase primaryVertex; + if (V0.has_collision()) { + auto const& collision = V0.collision(); + primaryVertex.setPos({collision.posX(), collision.posY(), collision.posZ()}); + primaryVertex.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + } else { + primaryVertex.setPos({mVtx->getX(), mVtx->getY(), mVtx->getZ()}); } + + auto pTra = V0.posTrack_as(); + auto nTra = V0.negTrack_as(); + processV0Candidate(primaryVertex, V0, pTra, nTra); } } void processDerivedData(soa::Join const& collisions, V0DerivedDatas const& V0s, dauTracks const&) { - for (const auto& collision : collisions) { - // Fire up CCDB - based on StraCollisions for derived analysis - initCCDB(collision); - // Do analysis with collision-grouped V0s, retain full collision information - const uint64_t collIdx = collision.globalIndex(); - auto V0Table_thisCollision = V0s.sliceBy(perCollisionDerived, collIdx); - histos.fill(HIST("hCandidateCounter"), V0Table_thisCollision.size()); - // V0 table sliced - for (auto const& v0 : V0Table_thisCollision) { - // de-reference interlinks by hand for derived data - auto pTra = v0.posTrackExtra_as(); - auto nTra = v0.negTrackExtra_as(); - - processV0Candidate(collision, v0, pTra, nTra); + // Fire up CCDB with first collision in record. If no collisions, bypass + if (useCustomRunNumber || collisions.size() < 1) { + initCCDB(manualRunNumber); + } else { + auto collision = collisions.begin(); + initCCDB(collision.runNumber()); + } + + for (const auto& V0 : V0s) { + // for storing whatever is the relevant quantity for the PV + o2::dataformats::VertexBase primaryVertex; + if (V0.has_straCollision()) { + auto const& collision = V0.straCollision_as>(); + primaryVertex.setPos({collision.posX(), collision.posY(), collision.posZ()}); + // cov: won't be used anyways, all fine + primaryVertex.setCov(1e-6, 1e-6, 1e-6, 1e-6, 1e-6, 1e-6); + } else { + primaryVertex.setPos({mVtx->getX(), mVtx->getY(), mVtx->getZ()}); } + + auto pTra = V0.posTrackExtra_as(); + auto nTra = V0.negTrackExtra_as(); + processV0Candidate(primaryVertex, V0, pTra, nTra); } } diff --git a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx index 6d860c9b616..8dfb0cfed27 100644 --- a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx +++ b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx @@ -11,6 +11,14 @@ // // This is a task that employs the standard V0 tables and attempts to combine // two V0s into a Sigma0 -> Lambda + gamma candidate. +// *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* +// Sigma0 builder task +// *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* +// +// Comments, questions, complaints, suggestions? +// Please write to: +// gianni.shigeru.setoue.liveraro@cern.ch +// #include #include @@ -25,15 +33,15 @@ #include "ReconstructionDataFormats/Track.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "PWGLF/DataModel/LFStrangenessPIDTables.h" -#include "PWGLF/DataModel/LFStrangenessMLTables.h" -#include "PWGLF/DataModel/LFSigmaTables.h" #include "Common/Core/TrackSelection.h" #include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/PIDResponse.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessMLTables.h" +#include "PWGLF/DataModel/LFSigmaTables.h" #include "CCDB/BasicCCDBManager.h" #include #include @@ -46,127 +54,893 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using std::array; -using std::cout; -using std::endl; +using dauTracks = soa::Join; +// using V0DerivedMCDatas = soa::Join; +using V0DerivedMCDatas = soa::Join; +using V0StandardDerivedDatas = soa::Join; struct sigma0builder { - Produces v0Sigmas; // save sigma0 candidates for analysis - Produces v0MCSigmas; // save sigma0 candidates for analysis + SliceCache cache; + Produces sigma0cores; // save sigma0 candidates for analysis + Produces sigmaPhotonExtras; // save sigma0 candidates for analysis + Produces sigmaLambdaExtras; // save sigma0 candidates for analysis + Produces sigma0mccores; + + // For manual sliceBy + Preslice perCollisionMCDerived = o2::aod::v0data::straCollisionId; + Preslice perCollisionSTDDerived = o2::aod::v0data::straCollisionId; + + // Histogram registry HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - Configurable Gamma_MLThreshold{"Gamma_MLThreshold", 0.1, "Decision Threshold value to select gammas of sigma0 candidates"}; - Configurable Lambda_MLThreshold{"Lambda_MLThreshold", 0.1, "Decision Threshold value to select lambdas of sigma0 candidates"}; + // Event selection + Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; + + struct : ConfigurableGroup { + Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; + Configurable requireTriggerTVX{"requireTriggerTVX", true, "require FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level"}; + Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border"}; + Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", true, "require events with at least one ITS-TPC track"}; + Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "require events with PV position along z consistent (within 1 cm) between PV reconstructed using tracks and PV using FT0 A-C time difference"}; + Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", false, "require events with at least one of vertex contributors matched to TOF"}; + Configurable requireIsVertexTRDmatched{"requireIsVertexTRDmatched", false, "require events with at least one of vertex contributors matched to TRD"}; + Configurable rejectSameBunchPileup{"rejectSameBunchPileup", false, "reject collisions in case of pileup with another collision in the same foundBC"}; + Configurable requireNoCollInTimeRangeStd{"requireNoCollInTimeRangeStd", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds"}; + Configurable requireNoCollInTimeRangeStrict{"requireNoCollInTimeRangeStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds"}; + Configurable requireNoCollInTimeRangeNarrow{"requireNoCollInTimeRangeNarrow", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds"}; + Configurable requireNoCollInTimeRangeVzDep{"requireNoCollInTimeRangeVzDep", false, "reject collisions corrupted by the cannibalism, with other collisions with pvZ of drifting TPC tracks from past/future collisions within 2.5 cm the current pvZ"}; + Configurable requireNoCollInROFStd{"requireNoCollInROFStd", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF with mult. above a certain threshold"}; + Configurable requireNoCollInROFStrict{"requireNoCollInROFStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF"}; + Configurable requireINEL0{"requireINEL0", false, "require INEL>0 event selection"}; + Configurable requireINEL1{"requireINEL1", false, "require INEL>1 event selection"}; + Configurable maxZVtxPosition{"maxZVtxPosition", 10., "max Z vtx position"}; + Configurable useFT0CbasedOccupancy{"useFT0CbasedOccupancy", false, "Use sum of FT0-C amplitudes for estimating occupancy? (if not, use track-based definition)"}; + // fast check on occupancy + Configurable minOccupancy{"minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; + Configurable maxOccupancy{"maxOccupancy", -1, "maximum occupancy from neighbouring collisions"}; + } eventSelections; + + // For ML Selection + Configurable useMLScores{"useMLScores", false, "use ML scores to select candidates"}; + Configurable Gamma_MLThreshold{"Gamma_MLThreshold", 0.1, "Decision Threshold value to select gammas"}; + Configurable Lambda_MLThreshold{"Lambda_MLThreshold", 0.1, "Decision Threshold value to select lambdas"}; + Configurable AntiLambda_MLThreshold{"AntiLambda_MLThreshold", 0.1, "Decision Threshold value to select antilambdas"}; + + // For standard approach: + //// Lambda criteria: + Configurable LambdaDauPseudoRap{"LambdaDauPseudoRap", 1.5, "Max pseudorapidity of daughter tracks"}; + Configurable LambdaMinDCANegToPv{"LambdaMinDCANegToPv", 0.0, "min DCA Neg To PV (cm)"}; + Configurable LambdaMinDCAPosToPv{"LambdaMinDCAPosToPv", 0.0, "min DCA Pos To PV (cm)"}; + Configurable LambdaMaxDCAV0Dau{"LambdaMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; + Configurable LambdaMinv0radius{"LambdaMinv0radius", 0.0, "Min V0 radius (cm)"}; + Configurable LambdaMaxv0radius{"LambdaMaxv0radius", 60, "Max V0 radius (cm)"}; + Configurable LambdaWindow{"LambdaWindow", 0.05, "Mass window around expected (in GeV/c2)"}; + + //// Photon criteria: + Configurable PhotonMaxDauPseudoRap{"PhotonMaxDauPseudoRap", 1.5, "Max pseudorapidity of daughter tracks"}; + Configurable PhotonMinDCAToPv{"PhotonMinDCAToPv", 0.0, "Min DCA daughter To PV (cm)"}; + Configurable PhotonMaxDCAV0Dau{"PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; + Configurable PhotonMinRadius{"PhotonMinRadius", 0.0, "Min photon conversion radius (cm)"}; + Configurable PhotonMaxRadius{"PhotonMaxRadius", 240, "Max photon conversion radius (cm)"}; + Configurable PhotonMaxMass{"PhotonMaxMass", 0.3, "Max photon mass (GeV/c^{2})"}; + + //// Sigma0 criteria: + Configurable Sigma0Window{"Sigma0Window", 0.1, "Mass window around expected (in GeV/c2)"}; + Configurable SigmaMaxRap{"SigmaMaxRap", 0.8, "Max sigma0 rapidity"}; + + //// Extras: + Configurable doPi0QA{"doPi0QA", true, "Flag to fill QA histos for pi0 rejection study."}; + Configurable Pi0PhotonMinDCADauToPv{"Pi0PhotonMinDCADauToPv", 0.0, "Min DCA daughter To PV (cm)"}; + Configurable Pi0PhotonMaxDCAV0Dau{"Pi0PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; + Configurable Pi0PhotonMinTPCCrossedRows{"Pi0PhotonMinTPCCrossedRows", 0, "Min daughter TPC Crossed Rows"}; + Configurable Pi0PhotonMaxTPCNSigmas{"Pi0PhotonMaxTPCNSigmas", 7, "Max TPC NSigmas for daughters"}; + Configurable Pi0PhotonMaxEta{"Pi0PhotonMaxEta", 0.8, "Max photon rapidity"}; + Configurable Pi0PhotonMinRadius{"Pi0PhotonMinRadius", 3.0, "Min photon conversion radius (cm)"}; + Configurable Pi0PhotonMaxRadius{"Pi0PhotonMaxRadius", 115, "Max photon conversion radius (cm)"}; + Configurable Pi0PhotonMaxQt{"Pi0PhotonMaxQt", 0.05, "Max photon qt value (AP plot) (GeV/c)"}; + Configurable Pi0PhotonMaxAlpha{"Pi0PhotonMaxAlpha", 0.95, "Max photon alpha absolute value (AP plot)"}; + Configurable Pi0PhotonMinV0cospa{"Pi0PhotonMinV0cospa", 0.80, "Min V0 CosPA"}; + Configurable Pi0PhotonMaxMass{"Pi0PhotonMaxMass", 0.10, "Max photon mass (GeV/c^{2})"}; + // Axis // base properties - ConfigurableAxis vertexZ{"vertexZ", {30, -15.0f, 15.0f}, ""}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for analysis"}; + ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Centrality"}; + ConfigurableAxis axisInvPt{"axisInvPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 2.0, 5.0, 10.0, 20.0, 50.0}, ""}; + ConfigurableAxis axisDeltaPt{"axisDeltaPt", {200, -500.0, 500.0}, ""}; + // Invariant Mass - ConfigurableAxis axisSigmaMass{"axisSigmaMass", {200, 1.16f, 1.23f}, "M_{#Sigma^{0}} (GeV/c^{2})"}; + ConfigurableAxis axisSigmaMass{"axisSigmaMass", {1000, 1.10f, 1.30f}, "M_{#Sigma^{0}} (GeV/c^{2})"}; + ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.05f, 1.151f}, "M_{#Lambda} (GeV/c^{2})"}; + ConfigurableAxis axisPhotonMass{"axisPhotonMass", {600, -0.1f, 0.5f}, "M_{#Gamma}"}; + // AP plot axes + ConfigurableAxis axisAPAlpha{"axisAPAlpha", {220, -1.1f, 1.1f}, "V0 AP alpha"}; + ConfigurableAxis axisAPQt{"axisAPQt", {220, 0.0f, 0.5f}, "V0 AP alpha"}; + + // Track quality axes + ConfigurableAxis axisTPCrows{"axisTPCrows", {160, 0.0f, 160.0f}, "N TPC rows"}; + + // topological variable QA axes + ConfigurableAxis axisDCAtoPV{"axisDCAtoPV", {500, 0.0f, 50.0f}, "DCA (cm)"}; + ConfigurableAxis axisDCAdau{"axisDCAdau", {50, 0.0f, 5.0f}, "DCA (cm)"}; + ConfigurableAxis axisRadius{"axisRadius", {240, 0.0f, 120.0f}, "V0 radius (cm)"}; + ConfigurableAxis axisRapidity{"axisRapidity", {100, -2.0f, 2.0f}, "Rapidity"}; + ConfigurableAxis axisCandSel{"axisCandSel", {13, 0.5f, +13.5f}, "Candidate Selection"}; + + int nSigmaCandidates = 0; void init(InitContext const&) { - // Event counter - histos.add("hEventVertexZ", "hEventVertexZ", kTH1F, {vertexZ}); - histos.add("hEventVertexZMC", "hEventVertexZMC", kTH1F, {vertexZ}); + // Event Counters + histos.add("hEventSelection", "hEventSelection", kTH1F, {{20, -0.5f, +18.5f}}); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(3, "kIsTriggerTVX"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(6, "posZ cut"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(7, "kIsVertexITSTPC"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(8, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(9, "kIsVertexTOFmatched"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(10, "kIsVertexTRDmatched"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(11, "kNoSameBunchPileup"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(12, "kNoCollInTimeRangeStd"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(13, "kNoCollInTimeRangeStrict"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(14, "kNoCollInTimeRangeNarrow"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(15, "kNoCollInRofStd"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(16, "kNoCollInRofStrict"); + if (doPPAnalysis) { + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "INEL>0"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "INEL>1"); + } else { + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "Below min occup."); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "Above max occup."); + } + + histos.add("hEventCentrality", "hEventCentrality", kTH1F, {axisCentrality}); + histos.add("hCandidateBuilderSelection", "hCandidateBuilderSelection", kTH1F, {axisCandSel}); + histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(1, "No Sel"); + histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(2, "Photon Mass Cut"); + histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(3, "Photon DauEta Cut"); + histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(4, "Photon DCAToPV Cut"); + histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(5, "Photon DCADau Cut"); + histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(6, "Photon Radius Cut"); + histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(7, "Lambda Mass Cut"); + histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(8, "Lambda DauEta Cut"); + histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(9, "Lambda DCAToPV Cut"); + histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(10, "Lambda Radius Cut"); + histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(11, "Lambda DCADau Cut"); + histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(12, "Sigma Mass Window"); + histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(13, "Sigma Y Window"); + + // For QA: + histos.add("Selection/hPhotonMass", "hPhotonMass", kTH1F, {axisPhotonMass}); + histos.add("Selection/hPhotonNegEta", "hPhotonNegEta", kTH1F, {axisRapidity}); + histos.add("Selection/hPhotonPosEta", "hPhotonPosEta", kTH1F, {axisRapidity}); + histos.add("Selection/hPhotonDCANegToPV", "hPhotonDCANegToPV", kTH1F, {axisDCAtoPV}); + histos.add("Selection/hPhotonDCAPosToPV", "hPhotonDCAPosToPV", kTH1F, {axisDCAtoPV}); + histos.add("Selection/hPhotonDCADau", "hPhotonDCADau", kTH1F, {axisDCAdau}); + histos.add("Selection/hPhotonRadius", "hPhotonRadius", kTH1F, {axisRadius}); + histos.add("Selection/hLambdaMass", "hLambdaMass", kTH1F, {axisLambdaMass}); + histos.add("Selection/hAntiLambdaMass", "hAntiLambdaMass", kTH1F, {axisLambdaMass}); + histos.add("Selection/hLambdaNegEta", "hLambdaNegEta", kTH1F, {axisRapidity}); + histos.add("Selection/hLambdaPosEta", "hLambdaPosEta", kTH1F, {axisRapidity}); + histos.add("Selection/hLambdaDCANegToPV", "hLambdaDCANegToPV", kTH1F, {axisDCAtoPV}); + histos.add("Selection/hLambdaDCAPosToPV", "hLambdaDCAPosToPV", kTH1F, {axisDCAtoPV}); + histos.add("Selection/hLambdaDCADau", "hLambdaDCADau", kTH1F, {axisDCAdau}); + histos.add("Selection/hLambdaRadius", "hLambdaRadius", kTH1F, {axisRadius}); + histos.add("Selection/hSigmaMass", "hSigmaMass", kTH1F, {axisSigmaMass}); + histos.add("Selection/hSigmaMassWindow", "hSigmaMassWindow", kTH1F, {{1000, -0.09f, 0.11f}}); + histos.add("Selection/hSigmaY", "hSigmaY", kTH1F, {axisRapidity}); + + histos.add("GeneralQA/h2dMassGammaVsK0S", "h2dMassGammaVsK0S", kTH2D, {axisPhotonMass, {200, 0.4f, 0.6f}}); + histos.add("GeneralQA/h2dMassLambdaVsK0S", "h2dMassLambdaVsK0S", kTH2D, {axisLambdaMass, {200, 0.4f, 0.6f}}); + histos.add("GeneralQA/h2dMassGammaVsLambda", "h2dMassGammaVsLambda", kTH2D, {axisPhotonMass, axisLambdaMass}); + histos.add("GeneralQA/h3dMassSigma0VsDaupTs", "h3dMassSigma0VsDaupTs", kTH3F, {axisPt, axisPt, axisSigmaMass}); + histos.add("GeneralQA/h2dMassGammaVsK0SAfterMassSel", "h2dMassGammaVsK0SAfterMassSel", kTH2D, {axisPhotonMass, {200, 0.4f, 0.6f}}); + histos.add("GeneralQA/h2dMassLambdaVsK0SAfterMassSel", "h2dMassLambdaVsK0SAfterMassSel", kTH2D, {axisLambdaMass, {200, 0.4f, 0.6f}}); + histos.add("GeneralQA/h2dMassGammaVsLambdaAfterMassSel", "h2dMassGammaVsLambdaAfterMassSel", kTH2D, {axisPhotonMass, axisLambdaMass}); + histos.add("GeneralQA/h2dPtVsMassPi0BeforeSel_Candidates", "h2dPtVsMassPi0BeforeSel_Candidates", kTH2D, {axisPt, {500, 0.08f, 0.18f}}); + histos.add("GeneralQA/h2dPtVsMassPi0AfterSel_Candidates", "h2dPtVsMassPi0AfterSel_Candidates", kTH2D, {axisPt, {500, 0.08f, 0.18f}}); + histos.add("GeneralQA/h3dV0XYZ", "h3dV0XYZ", kTH3F, {{400, -200, 200}, {400, -200, 200}, {240, -120.0f, 120.0f}}); + + // MC + histos.add("MC/h2dPtVsCentrality_GammaBeforeSel", "h2dPtVsCentrality_GammaBeforeSel", kTH2D, {axisCentrality, axisPt}); + histos.add("MC/h2dPtVsCentrality_LambdaBeforeSel", "h2dPtVsCentrality_LambdaBeforeSel", kTH2D, {axisCentrality, axisPt}); + histos.add("MC/h2dPtVsCentrality_AntiLambdaBeforeSel", "h2dPtVsCentrality_AntiLambdaBeforeSel", kTH2D, {axisCentrality, axisPt}); + histos.add("MC/h2dPtVsCentrality_GammaSigma0", "h2dPtVsCentrality_GammaSigma0", kTH2D, {axisCentrality, axisPt}); + histos.add("MC/h2dPtVsCentrality_LambdaSigma0", "h2dPtVsCentrality_LambdaSigma0", kTH2D, {axisCentrality, axisPt}); + histos.add("MC/h2dPtVsCentrality_Sigma0BeforeSel", "h2dPtVsCentrality_Sigma0BeforeSel", kTH2D, {axisCentrality, axisPt}); + histos.add("MC/h2dPtVsCentrality_Sigma0AfterSel", "h2dPtVsCentrality_Sigma0AfterSel", kTH2D, {axisCentrality, axisPt}); + histos.add("MC/h2dPtVsCentrality_AntiSigma0BeforeSel", "h2dPtVsCentrality_AntiSigma0BeforeSel", kTH2D, {axisCentrality, axisPt}); + histos.add("MC/h2dPtVsCentrality_GammaAntiSigma0", "h2dPtVsCentrality_GammaAntiSigma0", kTH2D, {axisCentrality, axisPt}); + histos.add("MC/h2dPtVsCentrality_LambdaAntiSigma0", "h2dPtVsCentrality_LambdaAntiSigma0", kTH2D, {axisCentrality, axisPt}); + histos.add("MC/h2dPtVsCentrality_AntiSigma0AfterSel", "h2dPtVsCentrality_AntiSigma0AfterSel", kTH2D, {axisCentrality, axisPt}); + histos.add("MC/h3dGammasXYZ", "h3dGammasXYZ", kTH3F, {{400, -200, 200}, {400, -200, 200}, {240, -120.0f, 120.0f}}); + + // Sigma vs Daughters pT + histos.add("MC/h2dSigmaPtVsLambdaPt", "h2dSigmaPtVsLambdaPt", kTH2D, {axisPt, axisPt}); + histos.add("MC/h2dSigmaPtVsGammaPt", "h2dSigmaPtVsGammaPt", kTH2D, {axisPt, axisPt}); + + // pT Resolution: + histos.add("MC/h2dLambdaPtResolution", "h2dLambdaPtResolution", kTH2D, {axisInvPt, axisDeltaPt}); + histos.add("MC/h2dGammaPtResolution", "h2dGammaPtResolution", kTH2D, {axisInvPt, axisDeltaPt}); + + // For background decomposition + histos.add("MC/h2dPtVsMassSigma_All", "h2dPtVsMassSigma_All", kTH2D, {axisPt, axisSigmaMass}); + histos.add("MC/h2dPtVsMassSigma_SignalOnly", "h2dPtVsMassSigma_SignalOnly", kTH2D, {axisPt, axisSigmaMass}); + histos.add("MC/h2dPtVsMassSigma_TrueDaughters", "h2dPtVsMassSigma_TrueDaughters", kTH2D, {axisPt, axisSigmaMass}); + histos.add("MC/h2dPtVsMassSigma_TrueGammaFakeLambda", "h2dPtVsMassSigma_TrueGammaFakeLambda", kTH2D, {axisPt, axisSigmaMass}); + histos.add("MC/h2dPtVsMassSigma_FakeGammaTrueLambda", "h2dPtVsMassSigma_FakeGammaTrueLambda", kTH2D, {axisPt, axisSigmaMass}); + histos.add("MC/h2dPtVsMassSigma_FakeDaughters", "h2dPtVsMassSigma_FakeDaughters", kTH2D, {axisPt, axisSigmaMass}); + histos.add("MC/h2dTrueDaughtersMatrix", "h2dTrueDaughtersMatrix", kTHnSparseD, {{10001, -5000.5f, +5000.5f}, {10001, -5000.5f, +5000.5f}}); + histos.add("MC/h2dTrueGammaFakeLambdaMatrix", "h2dTrueGammaFakeLambdaMatrix", kTHnSparseD, {{10001, -5000.5f, +5000.5f}, {10001, -5000.5f, +5000.5f}}); + histos.add("MC/h2dFakeGammaTrueLambdaMatrix", "h2dFakeGammaTrueLambdaMatrix", kTHnSparseD, {{10001, -5000.5f, +5000.5f}, {10001, -5000.5f, +5000.5f}}); + histos.add("MC/h2dFakeDaughtersMatrix", "h2dFakeDaughtersMatrix", kTHnSparseD, {{10001, -5000.5f, +5000.5f}, {10001, -5000.5f, +5000.5f}}); + + // For Pi0 QA + histos.add("MC/h2dPtVsMassPi0BeforeSel_SignalOnly", "h2dPtVsMassPi0BeforeSel_SignalOnly", kTH2D, {axisPt, {500, 0.08f, 0.18f}}); + histos.add("MC/h2dPtVsMassPi0AfterSel_SignalOnly", "h2dPtVsMassPi0AfterSel_SignalOnly", kTH2D, {axisPt, {500, 0.08f, 0.18f}}); + + histos.add("h3dMassSigmasBeforeSel", "h3dMassSigmasBeforeSel", kTH3F, {axisCentrality, axisPt, axisSigmaMass}); + histos.add("h3dMassSigmasAfterSel", "h3dMassSigmasAfterSel", kTH3F, {axisCentrality, axisPt, axisSigmaMass}); + } + + template + bool IsEventAccepted(TCollision collision, bool fillHists) + // check whether the collision passes our collision selections + { + if (fillHists) + histos.fill(HIST("hEventSelection"), 0. /* all collisions */); + if (eventSelections.requireSel8 && !collision.sel8()) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 1 /* sel8 collisions */); + if (eventSelections.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 2 /* FT0 vertex (acceptable FT0C-FT0A time difference) collisions */); + if (eventSelections.rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 3 /* Not at ITS ROF border */); + if (eventSelections.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 4 /* Not at TF border */); + if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 5 /* vertex-Z selected */); + if (eventSelections.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 6 /* Contains at least one ITS-TPC track */); + if (eventSelections.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 7 /* PV position consistency check */); + if (eventSelections.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 8 /* PV with at least one contributor matched with TOF */); + if (eventSelections.requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 9 /* PV with at least one contributor matched with TRD */); + if (eventSelections.rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 10 /* Not at same bunch pile-up */); + if (eventSelections.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 11 /* No other collision within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds*/); + if (eventSelections.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 12 /* No other collision within +/- 10 microseconds */); + if (eventSelections.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 13 /* No other collision within +/- 2 microseconds */); + if (eventSelections.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 14 /* No other collision within the same ITS ROF with mult. above a certain threshold */); + if (eventSelections.requireNoCollInROFStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 15 /* No other collision within the same ITS ROF */); + if (doPPAnalysis) { // we are in pp + if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 16 /* INEL > 0 */); + if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 17 /* INEL > 1 */); + } else { // we are in Pb-Pb + float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 16 /* Below min occupancy */); + if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 17 /* Above max occupancy */); + } + return true; } - // Helper struct to pass v0 information - struct { - float mass; - float pT; - } sigmaCandidate; + template + void runPi0QA(TV0Object const& gamma1, TV0Object const& gamma2) + { + + // Check if both V0s are made of the same tracks + if (gamma1.posTrackExtraId() == gamma2.posTrackExtraId() || + gamma1.negTrackExtraId() == gamma2.negTrackExtraId() || + gamma1.posTrackExtraId() == gamma2.negTrackExtraId() || + gamma1.negTrackExtraId() == gamma2.posTrackExtraId()) { + return; + } + + // Calculate pi0 properties + std::array pVecGamma1{gamma1.px(), gamma1.py(), gamma1.pz()}; + std::array pVecGamma2{gamma2.px(), gamma2.py(), gamma2.pz()}; + std::array arrpi0{pVecGamma1, pVecGamma2}; + float pi0Mass = RecoDecay::m(arrpi0, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassPhoton}); + float pi0Pt = RecoDecay::pt(std::array{gamma1.px() + gamma2.px(), gamma1.py() + gamma2.py()}); + float pi0Y = RecoDecay::y(std::array{gamma1.px() + gamma2.px(), gamma1.py() + gamma2.py(), gamma1.pz() + gamma2.pz()}, o2::constants::physics::MassPi0); + + // MC-specific variables + bool fIsPi0 = false, fIsMC = false; + + // Check if MC data and populate fIsMC, fIsPi0 + if constexpr (requires { gamma1.motherMCPartId(); gamma2.motherMCPartId(); }) { + if (gamma1.has_v0MCCore() && gamma2.has_v0MCCore()) { + fIsMC = true; + auto gamma1MC = gamma1.template v0MCCore_as>(); + auto gamma2MC = gamma2.template v0MCCore_as>(); + + if (gamma1MC.pdgCode() == 22 && gamma2MC.pdgCode() == 22 && + gamma1MC.pdgCodeMother() == 111 && gamma2MC.pdgCodeMother() == 111 && + gamma1.motherMCPartId() == gamma2.motherMCPartId()) { + fIsPi0 = true; + histos.fill(HIST("MC/h2dPtVsMassPi0BeforeSel_SignalOnly"), pi0Pt, pi0Mass); + } + } + } else { + histos.fill(HIST("GeneralQA/h2dPtVsMassPi0BeforeSel_Candidates"), pi0Pt, pi0Mass); + } + + // Photon-specific selections + auto posTrackGamma1 = gamma1.template posTrackExtra_as(); + auto negTrackGamma1 = gamma1.template negTrackExtra_as(); + auto posTrackGamma2 = gamma2.template posTrackExtra_as(); + auto negTrackGamma2 = gamma2.template negTrackExtra_as(); + + // Gamma1 Selection + bool passedTPCGamma1 = (posTrackGamma1.tpcNSigmaEl() == -999.f || TMath::Abs(posTrackGamma1.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas) && + (negTrackGamma1.tpcNSigmaEl() == -999.f || TMath::Abs(negTrackGamma1.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas); + + if (TMath::Abs(gamma1.mGamma()) > Pi0PhotonMaxMass || + gamma1.qtarm() >= Pi0PhotonMaxQt || + TMath::Abs(gamma1.alpha()) >= Pi0PhotonMaxAlpha || + TMath::Abs(gamma1.dcapostopv()) < Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma1.dcanegtopv()) < Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma1.dcaV0daughters()) > Pi0PhotonMaxDCAV0Dau || + TMath::Abs(gamma1.negativeeta()) >= Pi0PhotonMaxEta || + TMath::Abs(gamma1.positiveeta()) >= Pi0PhotonMaxEta || + gamma1.v0cosPA() <= Pi0PhotonMinV0cospa || + gamma1.v0radius() <= Pi0PhotonMinRadius || + gamma1.v0radius() >= Pi0PhotonMaxRadius || + posTrackGamma1.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || + negTrackGamma1.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || + !passedTPCGamma1) { + return; + } + + // Gamma2 Selection + bool passedTPCGamma2 = (posTrackGamma2.tpcNSigmaEl() == -999.f || TMath::Abs(posTrackGamma2.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas) && + (negTrackGamma2.tpcNSigmaEl() == -999.f || TMath::Abs(negTrackGamma2.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas); + + if (TMath::Abs(gamma2.mGamma()) > Pi0PhotonMaxMass || + gamma2.qtarm() >= Pi0PhotonMaxQt || + TMath::Abs(gamma2.alpha()) >= Pi0PhotonMaxAlpha || + TMath::Abs(gamma2.dcapostopv()) < Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma2.dcanegtopv()) < Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma2.dcaV0daughters()) > Pi0PhotonMaxDCAV0Dau || + TMath::Abs(gamma2.negativeeta()) >= Pi0PhotonMaxEta || + TMath::Abs(gamma2.positiveeta()) >= Pi0PhotonMaxEta || + gamma2.v0cosPA() <= Pi0PhotonMinV0cospa || + gamma2.v0radius() <= Pi0PhotonMinRadius || + gamma2.v0radius() >= Pi0PhotonMaxRadius || + posTrackGamma2.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || + negTrackGamma2.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || + !passedTPCGamma2) { + return; + } + + // Pi0-specific selections: + if (TMath::Abs(pi0Y) > 0.5) { + return; + } + + // Fill histograms + if (fIsMC) { + if (fIsPi0) + histos.fill(HIST("MC/h2dPtVsMassPi0AfterSel_SignalOnly"), pi0Pt, pi0Mass); + } else { + histos.fill(HIST("GeneralQA/h2dPtVsMassPi0AfterSel_Candidates"), pi0Pt, pi0Mass); + } + } // Process sigma candidate and store properties in object - template - bool processSigmaCandidate(TCollision const&, TV0Object const& lambda, TV0Object const& gamma) + template + bool processSigmaCandidate(TV0Object const& lambda, TV0Object const& gamma) { - // Gamma selection: - if (gamma.gammaBDTScore() <= Gamma_MLThreshold) + if ((lambda.v0Type() == 0) || (gamma.v0Type() == 0)) return false; - // Lambda selection: - if (lambda.lambdaBDTScore() <= Lambda_MLThreshold) + // Checking if both V0s are made of the very same tracks + if ((gamma.posTrackExtraId() == lambda.posTrackExtraId()) || (gamma.negTrackExtraId() == lambda.negTrackExtraId()) || (gamma.posTrackExtraId() == lambda.negTrackExtraId()) || (gamma.negTrackExtraId() == lambda.posTrackExtraId()) || (gamma.posTrackExtraId() == lambda.negTrackExtraId())) return false; + if (useMLScores) { + // Gamma selection: + if (gamma.gammaBDTScore() <= Gamma_MLThreshold) + return false; + + // Lambda and AntiLambda selection + if ((lambda.lambdaBDTScore() <= Lambda_MLThreshold) && (lambda.antiLambdaBDTScore() <= AntiLambda_MLThreshold)) + return false; + + } else { + // Standard selection + // Gamma basic selection criteria: + histos.fill(HIST("hCandidateBuilderSelection"), 1.); + histos.fill(HIST("Selection/hPhotonMass"), gamma.mGamma()); + if ((gamma.mGamma() < 0) || (gamma.mGamma() > PhotonMaxMass)) + return false; + histos.fill(HIST("Selection/hPhotonNegEta"), gamma.negativeeta()); + histos.fill(HIST("Selection/hPhotonPosEta"), gamma.positiveeta()); + histos.fill(HIST("hCandidateBuilderSelection"), 2.); + if ((TMath::Abs(gamma.negativeeta()) > PhotonMaxDauPseudoRap) || (TMath::Abs(gamma.positiveeta()) > PhotonMaxDauPseudoRap)) + return false; + histos.fill(HIST("Selection/hPhotonDCANegToPV"), TMath::Abs(gamma.dcanegtopv())); + histos.fill(HIST("Selection/hPhotonDCAPosToPV"), TMath::Abs(gamma.dcapostopv())); + histos.fill(HIST("hCandidateBuilderSelection"), 3.); + if ((TMath::Abs(gamma.dcapostopv()) < PhotonMinDCAToPv) || (TMath::Abs(gamma.dcanegtopv()) < PhotonMinDCAToPv)) + return false; + histos.fill(HIST("Selection/hPhotonDCADau"), TMath::Abs(gamma.dcaV0daughters())); + histos.fill(HIST("hCandidateBuilderSelection"), 4.); + if (TMath::Abs(gamma.dcaV0daughters()) > PhotonMaxDCAV0Dau) + return false; + histos.fill(HIST("Selection/hPhotonRadius"), gamma.v0radius()); + histos.fill(HIST("hCandidateBuilderSelection"), 5.); + if ((gamma.v0radius() < PhotonMinRadius) || (gamma.v0radius() > PhotonMaxRadius)) + return false; + + // Lambda basic selection criteria: + histos.fill(HIST("hCandidateBuilderSelection"), 6.); + histos.fill(HIST("Selection/hLambdaMass"), lambda.mLambda()); + histos.fill(HIST("Selection/hAntiLambdaMass"), lambda.mAntiLambda()); + if ((TMath::Abs(lambda.mLambda() - o2::constants::physics::MassLambda0) > LambdaWindow) && (TMath::Abs(lambda.mAntiLambda() - o2::constants::physics::MassLambda0) > LambdaWindow)) + return false; + histos.fill(HIST("Selection/hLambdaNegEta"), lambda.negativeeta()); + histos.fill(HIST("Selection/hLambdaPosEta"), lambda.positiveeta()); + histos.fill(HIST("hCandidateBuilderSelection"), 7.); + if ((TMath::Abs(lambda.negativeeta()) > LambdaDauPseudoRap) || (TMath::Abs(lambda.positiveeta()) > LambdaDauPseudoRap)) + return false; + histos.fill(HIST("Selection/hLambdaDCANegToPV"), lambda.dcanegtopv()); + histos.fill(HIST("Selection/hLambdaDCAPosToPV"), lambda.dcapostopv()); + histos.fill(HIST("hCandidateBuilderSelection"), 8.); + if ((TMath::Abs(lambda.dcapostopv()) < LambdaMinDCAPosToPv) || (TMath::Abs(lambda.dcanegtopv()) < LambdaMinDCANegToPv)) + return false; + histos.fill(HIST("Selection/hLambdaRadius"), lambda.v0radius()); + histos.fill(HIST("hCandidateBuilderSelection"), 9.); + if ((lambda.v0radius() < LambdaMinv0radius) || (lambda.v0radius() > LambdaMaxv0radius)) + return false; + histos.fill(HIST("Selection/hLambdaDCADau"), lambda.dcaV0daughters()); + histos.fill(HIST("hCandidateBuilderSelection"), 10.); + if (TMath::Abs(lambda.dcaV0daughters()) > LambdaMaxDCAV0Dau) + return false; + histos.fill(HIST("hCandidateBuilderSelection"), 11.); + } + // Sigma0 candidate properties std::array pVecPhotons{gamma.px(), gamma.py(), gamma.pz()}; std::array pVecLambda{lambda.px(), lambda.py(), lambda.pz()}; auto arrMom = std::array{pVecPhotons, pVecLambda}; - sigmaCandidate.mass = RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassLambda0}); - sigmaCandidate.pT = RecoDecay::pt(array{gamma.px() + lambda.px(), gamma.py() + lambda.py()}); + float sigmamass = RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassLambda0}); + float sigmarap = RecoDecay::y(std::array{gamma.px() + lambda.px(), gamma.py() + lambda.py(), gamma.pz() + lambda.pz()}, o2::constants::physics::MassSigma0); + float SigmapT = RecoDecay::pt(array{gamma.px() + lambda.px(), gamma.py() + lambda.py()}); + + histos.fill(HIST("Selection/hSigmaMass"), sigmamass); + histos.fill(HIST("Selection/hSigmaMassWindow"), sigmamass - 1.192642); + histos.fill(HIST("GeneralQA/h2dMassGammaVsK0S"), gamma.mGamma(), gamma.mK0Short()); + histos.fill(HIST("GeneralQA/h2dMassLambdaVsK0S"), lambda.mLambda(), lambda.mK0Short()); + histos.fill(HIST("GeneralQA/h2dMassGammaVsLambda"), gamma.mGamma(), lambda.mLambda()); + histos.fill(HIST("GeneralQA/h3dMassSigma0VsDaupTs"), gamma.pt(), lambda.pt(), sigmamass); + + if constexpr (requires { gamma.pdgCode(); } && requires { lambda.pdgCode(); }) { + + histos.fill(HIST("MC/h2dPtVsMassSigma_All"), SigmapT, sigmamass); + + // Real Gamma x Real Lambda - but not from the same sigma0/antisigma0! + if ((gamma.pdgCode() == 22) && ((lambda.pdgCode() == 3122) || (lambda.pdgCode() == -3122)) && (gamma.motherMCPartId() != lambda.motherMCPartId())) { + histos.fill(HIST("MC/h2dPtVsMassSigma_TrueDaughters"), SigmapT, sigmamass); + histos.fill(HIST("MC/h2dTrueDaughtersMatrix"), lambda.pdgCodeMother(), gamma.pdgCodeMother()); + } + + // Real Gamma x fake Lambda + if ((gamma.pdgCode() == 22) && (lambda.pdgCode() != 3122) && (lambda.pdgCode() != -3122)) { + histos.fill(HIST("MC/h2dPtVsMassSigma_TrueGammaFakeLambda"), SigmapT, sigmamass); + histos.fill(HIST("MC/h2dTrueGammaFakeLambdaMatrix"), lambda.pdgCodeMother(), gamma.pdgCodeMother()); + } + + // Fake Gamma x Real Lambda + if ((gamma.pdgCode() != 22) && ((lambda.pdgCode() == 3122) || (lambda.pdgCode() == -3122))) { + histos.fill(HIST("MC/h2dPtVsMassSigma_FakeGammaTrueLambda"), SigmapT, sigmamass); + histos.fill(HIST("MC/h2dFakeGammaTrueLambdaMatrix"), lambda.pdgCodeMother(), gamma.pdgCodeMother()); + } + + // Fake Gamma x Fake Lambda + if ((gamma.pdgCode() != 22) && (lambda.pdgCode() != 3122) && (lambda.pdgCode() != -3122)) { + histos.fill(HIST("MC/h2dPtVsMassSigma_FakeDaughters"), SigmapT, sigmamass); + histos.fill(HIST("MC/h2dFakeDaughtersMatrix"), lambda.pdgCodeMother(), gamma.pdgCodeMother()); + } + } + + if (TMath::Abs(sigmamass - 1.192642) > Sigma0Window) + return false; + + histos.fill(HIST("GeneralQA/h2dMassGammaVsK0SAfterMassSel"), gamma.mGamma(), gamma.mK0Short()); + histos.fill(HIST("GeneralQA/h2dMassLambdaVsK0SAfterMassSel"), lambda.mLambda(), lambda.mK0Short()); + histos.fill(HIST("GeneralQA/h2dMassGammaVsLambdaAfterMassSel"), gamma.mGamma(), lambda.mLambda()); + histos.fill(HIST("Selection/hSigmaY"), sigmarap); + histos.fill(HIST("hCandidateBuilderSelection"), 12.); + + if (TMath::Abs(sigmarap) > SigmaMaxRap) + return false; + + histos.fill(HIST("hCandidateBuilderSelection"), 13.); + histos.fill(HIST("GeneralQA/h3dV0XYZ"), gamma.x(), gamma.y(), gamma.z()); return true; } - void processMonteCarlo(aod::StraCollision const& coll, soa::Join const& v0s) + // Fill tables with reconstructed sigma0 candidate + template + void fillTables(TV0Object const& lambda, TV0Object const& gamma, TCollision const& coll) { - histos.fill(HIST("hEventVertexZMC"), coll.posZ()); - for (auto& gamma : v0s) { // selecting photons from Sigma0 + float GammaBDTScore = gamma.gammaBDTScore(); + float LambdaBDTScore = lambda.lambdaBDTScore(); + float AntiLambdaBDTScore = lambda.antiLambdaBDTScore(); + + // Daughters related + /// Photon + auto posTrackGamma = gamma.template posTrackExtra_as(); + auto negTrackGamma = gamma.template negTrackExtra_as(); + + float fPhotonPt = gamma.pt(); + float fPhotonMass = gamma.mGamma(); + float fPhotonQt = gamma.qtarm(); + float fPhotonAlpha = gamma.alpha(); + float fPhotonRadius = gamma.v0radius(); + float fPhotonCosPA = gamma.v0cosPA(); + float fPhotonDCADau = gamma.dcaV0daughters(); + float fPhotonDCANegPV = gamma.dcanegtopv(); + float fPhotonDCAPosPV = gamma.dcapostopv(); + float fPhotonZconv = gamma.z(); + float fPhotonEta = gamma.eta(); + float fPhotonY = RecoDecay::y(std::array{gamma.px(), gamma.py(), gamma.pz()}, o2::constants::physics::MassGamma); + float fPhotonPhi = RecoDecay::phi(gamma.px(), gamma.py()); + float fPhotonPosTPCNSigmaEl = posTrackGamma.tpcNSigmaEl(); + float fPhotonNegTPCNSigmaEl = negTrackGamma.tpcNSigmaEl(); + float fPhotonPosTPCNSigmaPi = posTrackGamma.tpcNSigmaPi(); + float fPhotonNegTPCNSigmaPi = negTrackGamma.tpcNSigmaPi(); + uint8_t fPhotonPosTPCCrossedRows = posTrackGamma.tpcCrossedRows(); + uint8_t fPhotonNegTPCCrossedRows = negTrackGamma.tpcCrossedRows(); + float fPhotonPosPt = gamma.positivept(); + float fPhotonNegPt = gamma.negativept(); + float fPhotonPosEta = gamma.positiveeta(); + float fPhotonNegEta = gamma.negativeeta(); + float fPhotonPosY = RecoDecay::y(std::array{gamma.pxpos(), gamma.pypos(), gamma.pzpos()}, o2::constants::physics::MassElectron); + float fPhotonNegY = RecoDecay::y(std::array{gamma.pxneg(), gamma.pyneg(), gamma.pzneg()}, o2::constants::physics::MassElectron); + float fPhotonPsiPair = gamma.psipair(); + int fPhotonPosITSCls = posTrackGamma.itsNCls(); + int fPhotonNegITSCls = negTrackGamma.itsNCls(); + float fPhotonPosITSChi2PerNcl = posTrackGamma.itsChi2PerNcl(); + float fPhotonNegITSChi2PerNcl = negTrackGamma.itsChi2PerNcl(); + uint8_t fPhotonV0Type = gamma.v0Type(); + + // Lambda + auto posTrackLambda = lambda.template posTrackExtra_as(); + auto negTrackLambda = lambda.template negTrackExtra_as(); - if ((gamma.pdgCode() != 22) || (gamma.pdgCodeMother() != 3212)) + float fLambdaPt = lambda.pt(); + float fLambdaMass = lambda.mLambda(); + float fAntiLambdaMass = lambda.mAntiLambda(); + float fLambdaQt = lambda.qtarm(); + float fLambdaAlpha = lambda.alpha(); + float fLambdaLifeTime = lambda.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * o2::constants::physics::MassLambda0; + float fLambdaRadius = lambda.v0radius(); + float fLambdaCosPA = lambda.v0cosPA(); + float fLambdaDCADau = lambda.dcaV0daughters(); + float fLambdaDCANegPV = lambda.dcanegtopv(); + float fLambdaDCAPosPV = lambda.dcapostopv(); + float fLambdaEta = lambda.eta(); + float fLambdaY = lambda.yLambda(); + float fLambdaPhi = RecoDecay::phi(lambda.px(), lambda.py()); + float fLambdaPosPrTPCNSigma = posTrackLambda.tpcNSigmaPr(); + float fLambdaPosPiTPCNSigma = posTrackLambda.tpcNSigmaPi(); + float fLambdaNegPrTPCNSigma = negTrackLambda.tpcNSigmaPr(); + float fLambdaNegPiTPCNSigma = negTrackLambda.tpcNSigmaPi(); + + float fLambdaPrTOFNSigma = lambda.tofNSigmaLaPr(); + float fLambdaPiTOFNSigma = lambda.tofNSigmaLaPi(); + float fALambdaPrTOFNSigma = lambda.tofNSigmaALaPr(); + float fALambdaPiTOFNSigma = lambda.tofNSigmaALaPi(); + + uint8_t fLambdaPosTPCCrossedRows = posTrackLambda.tpcCrossedRows(); + uint8_t fLambdaNegTPCCrossedRows = negTrackLambda.tpcCrossedRows(); + float fLambdaPosPt = lambda.positivept(); + float fLambdaNegPt = lambda.negativept(); + float fLambdaPosEta = lambda.positiveeta(); + float fLambdaNegEta = lambda.negativeeta(); + float fLambdaPosPrY = RecoDecay::y(std::array{lambda.pxpos(), lambda.pypos(), lambda.pzpos()}, o2::constants::physics::MassProton); + float fLambdaPosPiY = RecoDecay::y(std::array{lambda.pxpos(), lambda.pypos(), lambda.pzpos()}, o2::constants::physics::MassPionCharged); + float fLambdaNegPrY = RecoDecay::y(std::array{lambda.pxneg(), lambda.pyneg(), lambda.pzneg()}, o2::constants::physics::MassProton); + float fLambdaNegPiY = RecoDecay::y(std::array{lambda.pxneg(), lambda.pyneg(), lambda.pzneg()}, o2::constants::physics::MassPionCharged); + int fLambdaPosITSCls = posTrackLambda.itsNCls(); + int fLambdaNegITSCls = negTrackLambda.itsNCls(); + float fLambdaPosITSChi2PerNcl = posTrackLambda.itsChi2PerNcl(); + float fLambdaNegITSChi2PerNcl = negTrackLambda.itsChi2PerNcl(); + uint8_t fLambdaV0Type = lambda.v0Type(); + + // Sigma0 candidate properties + std::array pVecPhotons{gamma.px(), gamma.py(), gamma.pz()}; + std::array pVecLambda{lambda.px(), lambda.py(), lambda.pz()}; + auto arrMom = std::array{pVecPhotons, pVecLambda}; + TVector3 v1(gamma.px(), gamma.py(), gamma.pz()); + TVector3 v2(lambda.px(), lambda.py(), lambda.pz()); + + // Sigma related + float fSigmapT = RecoDecay::pt(array{gamma.px() + lambda.px(), gamma.py() + lambda.py()}); + float fSigmaMass = RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassLambda0}); + float fSigmaRap = RecoDecay::y(std::array{gamma.px() + lambda.px(), gamma.py() + lambda.py(), gamma.pz() + lambda.pz()}, o2::constants::physics::MassSigma0); + float fSigmaOPAngle = v1.Angle(v2); + float fSigmaCentrality = coll.centFT0C(); + float fSigmaTimeStamp = coll.timestamp(); + float fSigmaRunNumber = coll.runNumber(); + + // Filling TTree for ML analysis + sigma0cores(fSigmapT, fSigmaMass, fSigmaRap, fSigmaOPAngle, fSigmaCentrality, fSigmaRunNumber, fSigmaTimeStamp); + + sigmaPhotonExtras(fPhotonPt, fPhotonMass, fPhotonQt, fPhotonAlpha, fPhotonRadius, + fPhotonCosPA, fPhotonDCADau, fPhotonDCANegPV, fPhotonDCAPosPV, fPhotonZconv, + fPhotonEta, fPhotonY, fPhotonPhi, fPhotonPosTPCNSigmaEl, fPhotonNegTPCNSigmaEl, fPhotonPosTPCNSigmaPi, fPhotonNegTPCNSigmaPi, fPhotonPosTPCCrossedRows, + fPhotonNegTPCCrossedRows, fPhotonPosPt, fPhotonNegPt, fPhotonPosEta, + fPhotonNegEta, fPhotonPosY, fPhotonNegY, fPhotonPsiPair, + fPhotonPosITSCls, fPhotonNegITSCls, fPhotonPosITSChi2PerNcl, fPhotonNegITSChi2PerNcl, + fPhotonV0Type, GammaBDTScore); + + sigmaLambdaExtras(fLambdaPt, fLambdaMass, fAntiLambdaMass, fLambdaQt, fLambdaAlpha, fLambdaLifeTime, + fLambdaRadius, fLambdaCosPA, fLambdaDCADau, fLambdaDCANegPV, + fLambdaDCAPosPV, fLambdaEta, fLambdaY, fLambdaPhi, fLambdaPosPrTPCNSigma, + fLambdaPosPiTPCNSigma, fLambdaNegPrTPCNSigma, fLambdaNegPiTPCNSigma, + fLambdaPrTOFNSigma, fLambdaPiTOFNSigma, fALambdaPrTOFNSigma, fALambdaPiTOFNSigma, + fLambdaPosTPCCrossedRows, fLambdaNegTPCCrossedRows, fLambdaPosPt, fLambdaNegPt, fLambdaPosEta, + fLambdaNegEta, fLambdaPosPrY, fLambdaPosPiY, fLambdaNegPrY, fLambdaNegPiY, + fLambdaPosITSCls, fLambdaNegITSCls, fLambdaPosITSChi2PerNcl, fLambdaNegITSChi2PerNcl, + fLambdaV0Type, LambdaBDTScore, AntiLambdaBDTScore); + } + + void processMonteCarlo(soa::Join const& collisions, V0DerivedMCDatas const& V0s, dauTracks const&, aod::MotherMCParts const&, soa::Join const&, soa::Join const&) + { + for (const auto& coll : collisions) { + if (!IsEventAccepted(coll, true)) { continue; - for (auto& lambda : v0s) { // selecting lambdas from Sigma0 - if ((lambda.pdgCode() != 3122) || (lambda.pdgCodeMother() != 3212)) - continue; + } + // Do analysis with collision-grouped V0s, retain full collision information + const uint64_t collIdx = coll.globalIndex(); + auto V0Table_thisCollision = V0s.sliceBy(perCollisionMCDerived, collIdx); - // if (gamma.motherMCPartId()!=lambda.motherMCPartId()) continue; - if (!processSigmaCandidate(coll, lambda, gamma)) + histos.fill(HIST("hEventCentrality"), coll.centFT0C()); + // V0 table sliced + for (auto& gamma : V0Table_thisCollision) { // selecting photons from Sigma0 + float centrality = coll.centFT0C(); + + if (!gamma.has_v0MCCore()) continue; - bool fIsSigma = (gamma.motherMCPartId() == lambda.motherMCPartId()); - // Filling TTree for ML analysis - v0MCSigmas(fIsSigma); + auto gammaMC = gamma.v0MCCore_as>(); + + // Auxiliary histograms: + if (gammaMC.pdgCode() == 22) { + histos.fill(HIST("MC/h3dGammasXYZ"), gamma.x(), gamma.y(), gamma.z()); + float GammaY = TMath::Abs(RecoDecay::y(std::array{gamma.px(), gamma.py(), gamma.pz()}, o2::constants::physics::MassGamma)); + float gammaMCpT = RecoDecay::pt(array{gammaMC.pxMC(), gammaMC.pyMC()}); + if (GammaY < 0.5) { // rapidity selection + histos.fill(HIST("MC/h2dPtVsCentrality_GammaBeforeSel"), centrality, gamma.pt()); // isgamma + if (gammaMCpT > 0) + histos.fill(HIST("MC/h2dGammaPtResolution"), 1.f / gammaMCpT, gamma.pt() - gammaMCpT); // pT resolution + + if (gammaMC.pdgCodeMother() == 3212) { + histos.fill(HIST("MC/h2dPtVsCentrality_GammaSigma0"), centrality, gamma.pt()); // isgamma from sigma + } + if (gammaMC.pdgCodeMother() == -3212) { + histos.fill(HIST("MC/h2dPtVsCentrality_GammaAntiSigma0"), centrality, gamma.pt()); // isgamma from sigma + } + } + } + if (gammaMC.pdgCode() == 3122) { // Is Lambda + float LambdaY = TMath::Abs(RecoDecay::y(std::array{gamma.px(), gamma.py(), gamma.pz()}, o2::constants::physics::MassLambda)); + float lambdaMCpT = RecoDecay::pt(array{gammaMC.pxMC(), gammaMC.pyMC()}); + if (LambdaY < 0.5) { // rapidity selection + histos.fill(HIST("MC/h2dPtVsCentrality_LambdaBeforeSel"), centrality, gamma.pt()); + if (lambdaMCpT > 0) + histos.fill(HIST("MC/h2dLambdaPtResolution"), 1.f / lambdaMCpT, gamma.pt() - lambdaMCpT); // pT resolution + if (gammaMC.pdgCodeMother() == 3212) { + histos.fill(HIST("MC/h2dPtVsCentrality_LambdaSigma0"), centrality, gamma.pt()); + } + } + } + if (gammaMC.pdgCode() == -3122) { // Is AntiLambda + float AntiLambdaY = TMath::Abs(RecoDecay::y(std::array{gamma.px(), gamma.py(), gamma.pz()}, o2::constants::physics::MassLambda)); + if (AntiLambdaY < 0.5) { // rapidity selection + histos.fill(HIST("MC/h2dPtVsCentrality_AntiLambdaBeforeSel"), centrality, gamma.pt()); + if (gammaMC.pdgCodeMother() == -3212) { + histos.fill(HIST("MC/h2dPtVsCentrality_LambdaAntiSigma0"), centrality, gamma.pt()); // isantilambda from antisigma + } + } + } + + for (auto& lambda : V0Table_thisCollision) { // selecting lambdas from Sigma0 + if (!lambda.has_v0MCCore()) + continue; + + if (lambda.v0Type() != 1) { // safeguard to avoid TPC-only photons + continue; + } + + auto lambdaMC = lambda.v0MCCore_as>(); + + if (doPi0QA) // Pi0 QA study + runPi0QA(gamma, lambda); + + // Sigma0 candidate properties + std::array pVecPhotons{gamma.px(), gamma.py(), gamma.pz()}; + std::array pVecLambda{lambda.px(), lambda.py(), lambda.pz()}; + auto arrMom = std::array{pVecPhotons, pVecLambda}; + float SigmaMass = RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassLambda0}); + float SigmapT = RecoDecay::pt(array{gamma.px() + lambda.px(), gamma.py() + lambda.py()}); + float SigmaY = TMath::Abs(RecoDecay::y(std::array{gamma.px() + lambda.px(), gamma.py() + lambda.py(), gamma.pz() + lambda.pz()}, o2::constants::physics::MassSigma0)); + + if ((gammaMC.pdgCode() == 22) && (gammaMC.pdgCodeMother() == 3212) && (lambdaMC.pdgCode() == 3122) && (lambdaMC.pdgCodeMother() == 3212) && (gamma.motherMCPartId() == lambda.motherMCPartId()) && (SigmaY < 0.5)) { + histos.fill(HIST("MC/h2dPtVsCentrality_Sigma0BeforeSel"), centrality, RecoDecay::pt(array{gamma.px() + lambda.px(), gamma.py() + lambda.py()})); + histos.fill(HIST("MC/h2dSigmaPtVsLambdaPt"), SigmapT, lambda.pt()); + histos.fill(HIST("MC/h2dSigmaPtVsGammaPt"), SigmapT, gamma.pt()); + } + if ((gammaMC.pdgCode() == 22) && (gammaMC.pdgCodeMother() == -3212) && (lambdaMC.pdgCode() == -3122) && (lambdaMC.pdgCodeMother() == -3212) && (gamma.motherMCPartId() == lambda.motherMCPartId()) && (SigmaY < 0.5)) + histos.fill(HIST("MC/h2dPtVsCentrality_AntiSigma0BeforeSel"), centrality, SigmapT); + + if (!processSigmaCandidate(lambda, gamma)) // basic selection + continue; + + bool fIsSigma = false; + bool fIsAntiSigma = false; + float SigmaMCpT = RecoDecay::pt(array{gammaMC.pxMC() + lambdaMC.pxMC(), gammaMC.pyMC() + lambdaMC.pyMC()}); + bool fIsPhotonPrimary = gammaMC.isPhysicalPrimary(); + int PhotonCandPDGCode = gammaMC.pdgCode(); + int PhotonCandPDGCodeMother = gammaMC.pdgCodeMother(); + float PhotonMCpT = RecoDecay::pt(array{gammaMC.pxMC(), gammaMC.pyMC()}); + bool fIsLambdaPrimary = lambdaMC.isPhysicalPrimary(); + int LambdaCandPDGCode = lambdaMC.pdgCode(); + int LambdaCandPDGCodeMother = lambdaMC.pdgCodeMother(); + float LambdaMCpT = RecoDecay::pt(array{lambdaMC.pxMC(), lambdaMC.pyMC()}); + + if ((gammaMC.pdgCode() == 22) && (gammaMC.pdgCodeMother() == 3212) && (lambdaMC.pdgCode() == 3122) && (lambdaMC.pdgCodeMother() == 3212) && (gamma.motherMCPartId() == lambda.motherMCPartId())) { + fIsSigma = true; + histos.fill(HIST("MC/h2dPtVsCentrality_Sigma0AfterSel"), centrality, RecoDecay::pt(array{gamma.px() + lambda.px(), gamma.py() + lambda.py()})); + } + if ((gammaMC.pdgCode() == 22) && (gammaMC.pdgCodeMother() == -3212) && (lambdaMC.pdgCode() == -3122) && (lambdaMC.pdgCodeMother() == -3212) && (gamma.motherMCPartId() == lambda.motherMCPartId())) { + fIsAntiSigma = true; + histos.fill(HIST("MC/h2dPtVsCentrality_AntiSigma0AfterSel"), centrality, RecoDecay::pt(array{gamma.px() + lambda.px(), gamma.py() + lambda.py()})); + // TH3D Mass histogram + } + sigma0mccores(fIsSigma, fIsAntiSigma, SigmaMCpT, + PhotonCandPDGCode, PhotonCandPDGCodeMother, fIsPhotonPrimary, PhotonMCpT, + LambdaCandPDGCode, LambdaCandPDGCodeMother, fIsLambdaPrimary, LambdaMCpT); + + fillTables(lambda, gamma, coll); // filling tables with accepted candidates + + nSigmaCandidates++; + if (nSigmaCandidates % 5000 == 0) { + LOG(info) << "Sigma0 Candidates built: " << nSigmaCandidates; + } + + // QA histograms + // Signal only (sigma0+antisigma0) + if (fIsSigma || fIsAntiSigma) + histos.fill(HIST("MC/h2dPtVsMassSigma_SignalOnly"), SigmapT, SigmaMass); + } } } } - void processRealData(aod::StraCollision const& coll, soa::Join const& v0s) + void processRealData(soa::Join const& collisions, V0StandardDerivedDatas const& V0s, dauTracks const&) { - histos.fill(HIST("hEventVertexZ"), coll.posZ()); + for (const auto& coll : collisions) { + if (!IsEventAccepted(coll, true)) { + continue; + } + // Do analysis with collision-grouped V0s, retain full collision information + const uint64_t collIdx = coll.globalIndex(); + auto V0Table_thisCollision = V0s.sliceBy(perCollisionSTDDerived, collIdx); - for (auto& gamma : v0s) { // selecting photons from Sigma0 - for (auto& lambda : v0s) { // selecting lambdas from Sigma0 - if (!processSigmaCandidate(coll, lambda, gamma)) - continue; + histos.fill(HIST("hEventCentrality"), coll.centFT0C()); + // V0 table sliced + for (auto& gamma : V0Table_thisCollision) { // selecting photons from Sigma0 + for (auto& lambda : V0Table_thisCollision) { // selecting lambdas from Sigma0 + if (doPi0QA) // Pi0 QA study + runPi0QA(gamma, lambda); + + if (lambda.v0Type() != 1) { // safeguard to avoid TPC-only photons + continue; + } + + // Sigma0 candidate properties + std::array pVecPhotons{gamma.px(), gamma.py(), gamma.pz()}; + std::array pVecLambda{lambda.px(), lambda.py(), lambda.pz()}; + auto arrMom = std::array{pVecPhotons, pVecLambda}; + float SigmaMass = RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassLambda0}); + float SigmapT = RecoDecay::pt(array{gamma.px() + lambda.px(), gamma.py() + lambda.py()}); + // float SigmaY = TMath::Abs(RecoDecay::y(std::array{gamma.px() + lambda.px(), gamma.py() + lambda.py(), gamma.pz() + lambda.pz()}, o2::constants::physics::MassSigma0)); + histos.fill(HIST("h3dMassSigmasBeforeSel"), coll.centFT0C(), SigmapT, SigmaMass); - // Sigma related - float fSigmapT = sigmaCandidate.pT; - float fSigmaMass = sigmaCandidate.mass; - - // Daughters related - /// Photon - float fPhotonPt = gamma.pt(); - float fPhotonMass = gamma.mGamma(); - float fPhotonQt = gamma.qtarm(); - float fPhotonAlpha = gamma.alpha(); - float fPhotonRadius = gamma.v0radius(); - float fPhotonCosPA = gamma.v0cosPA(); - float fPhotonDCADau = gamma.dcaV0daughters(); - float fPhotonDCANegPV = gamma.dcanegtopv(); - float fPhotonDCAPosPV = gamma.dcapostopv(); - float fPhotonZconv = gamma.z(); - - // Lambda - float fLambdaPt = lambda.pt(); - float fLambdaMass = lambda.mLambda(); - float fLambdaQt = lambda.qtarm(); - float fLambdaAlpha = lambda.alpha(); - float fLambdaRadius = lambda.v0radius(); - float fLambdaCosPA = lambda.v0cosPA(); - float fLambdaDCADau = lambda.dcaV0daughters(); - float fLambdaDCANegPV = lambda.dcanegtopv(); - float fLambdaDCAPosPV = lambda.dcapostopv(); - - // Filling TTree for ML analysis - v0Sigmas(fSigmapT, fSigmaMass, fPhotonPt, fPhotonMass, fPhotonQt, fPhotonAlpha, - fPhotonRadius, fPhotonCosPA, fPhotonDCADau, fPhotonDCANegPV, fPhotonDCAPosPV, - fPhotonZconv, fLambdaPt, fLambdaMass, fLambdaQt, fLambdaAlpha, fLambdaRadius, - fLambdaCosPA, fLambdaDCADau, fLambdaDCANegPV, fLambdaDCAPosPV, - gamma.gammaBDTScore(), lambda.lambdaBDTScore()); + if (!processSigmaCandidate(lambda, gamma)) // applying selection for reconstruction + continue; + + histos.fill(HIST("h3dMassSigmasAfterSel"), coll.centFT0C(), SigmapT, SigmaMass); + + fillTables(lambda, gamma, coll); // filling tables with accepted candidates + + nSigmaCandidates++; + if (nSigmaCandidates % 5000 == 0) { + LOG(info) << "Sigma0 Candidates built: " << nSigmaCandidates; + } + } } } } - PROCESS_SWITCH(sigma0builder, processMonteCarlo, "Do Monte-Carlo-based analysis", false); - PROCESS_SWITCH(sigma0builder, processRealData, "Do real data analysis", true); + + PROCESS_SWITCH(sigma0builder, processMonteCarlo, "process as if MC data", false); + PROCESS_SWITCH(sigma0builder, processRealData, "process as if real data", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/TableProducer/Strangeness/stCollIds.cxx b/PWGLF/TableProducer/Strangeness/stCollIds.cxx index 8dfe326a848..3cc94389197 100644 --- a/PWGLF/TableProducer/Strangeness/stCollIds.cxx +++ b/PWGLF/TableProducer/Strangeness/stCollIds.cxx @@ -31,24 +31,24 @@ struct StCollIds { void init(InitContext const&) {} - void processTrackedCascades(aod::TrackedCascades const& trackedCascades, aod::Tracks const& /*tracks*/) + void processTrackedCascades(aod::TrackedCascades const& trackedCascades, aod::TracksIU const& /*tracks*/) { for (const auto& trackedCascade : trackedCascades) - trackedCascadeColls(trackedCascade.track().collisionId()); + trackedCascadeColls(trackedCascade.track_as().collisionId()); } PROCESS_SWITCH(StCollIds, processTrackedCascades, "process cascades from strangeness tracking", true); - void processTrackedV0s(aod::TrackedV0s const& trackedV0s, aod::Tracks const& /*tracks*/) + void processTrackedV0s(aod::TrackedV0s const& trackedV0s, aod::TracksIU const& /*tracks*/) { for (const auto& trackedV0 : trackedV0s) - trackedV0Colls(trackedV0.track().collisionId()); + trackedV0Colls(trackedV0.track_as().collisionId()); } PROCESS_SWITCH(StCollIds, processTrackedV0s, "process V0s from strangeness tracking", true); - void processTracked3Bodys(aod::Tracked3Bodys const& tracked3Bodys, aod::Tracks const& /*tracks*/) + void processTracked3Bodys(aod::Tracked3Bodys const& tracked3Bodys, aod::TracksIU const& /*tracks*/) { for (const auto& tracked3Body : tracked3Bodys) - tracked3BodyColls(tracked3Body.track().collisionId()); + tracked3BodyColls(tracked3Body.track_as().collisionId()); } PROCESS_SWITCH(StCollIds, processTracked3Bodys, "process cascades from strangeness tracking", true); }; diff --git a/PWGLF/TableProducer/Strangeness/stracents.cxx b/PWGLF/TableProducer/Strangeness/stracents.cxx new file mode 100644 index 00000000000..e1b601fb4d8 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/stracents.cxx @@ -0,0 +1,587 @@ +// 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 straCents.cxx +/// \brief Task to re-produce the strangeness centrality tables, repeating what has been done the centralityTable.cxx and multiplicityTable.cxx tasks +/// +/// \author ALICE +// + +#include +#include +#include +#include + +#include +#include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/RunningWorkflowInfo.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Framework/HistogramRegistry.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "MetadataHelper.h" +#include "TableHelper.h" +#include "TList.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +MetadataHelper metadataInfo; // Metadata helper + +struct straCents { + Produces strangeCents; + Produces strangeCentsRun2; + + Service ccdb; + + Configurable doVertexZeq{"doVertexZeq", 1, "if 1: do vertex Z eq mult table"}; + struct : ConfigurableGroup { + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "The CCDB endpoint url address"}; + Configurable ccdbPath_Centrality{"ccdbPath_Centrality", "Centrality/Estimators", "The CCDB path for centrality/multiplicity information"}; + Configurable ccdbPath_Multiplicity{"ccdbPath_Multiplicity", "Centrality/Calibration", "The CCDB path for centrality/multiplicity information"}; + Configurable genName{"genName", "", "Genearator name: HIJING, PYTHIA8, ... Default: \"\""}; + Configurable doNotCrashOnNull{"doNotCrashOnNull", false, {"Option to not crash on null and instead fill required tables with dummy info"}}; + Configurable reconstructionPass{"reconstructionPass", "", {"Apass to use when fetching the calibration tables. Empty (default) does not check for any pass. Use `metadata` to fetch it from the AO2D metadata. Otherwise it will override the metadata."}}; + } ccdbConfig; + + Configurable embedINELgtZEROselection{"embedINELgtZEROselection", false, {"Option to do percentile 100.5 if not INELgtZERO"}}; + Configurable produceHistograms{"produceHistograms", false, {"Option to produce debug histograms"}}; + ConfigurableAxis binsPercentile{"binsPercentile", {VARIABLE_WIDTH, 0, 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, 0.01, 0.011, 0.012, 0.013, 0.014, 0.015, 0.016, 0.017, 0.018, 0.019, 0.02, 0.021, 0.022, 0.023, 0.024, 0.025, 0.026, 0.027, 0.028, 0.029, 0.03, 0.031, 0.032, 0.033, 0.034, 0.035, 0.036, 0.037, 0.038, 0.039, 0.04, 0.041, 0.042, 0.043, 0.044, 0.045, 0.046, 0.047, 0.048, 0.049, 0.05, 0.051, 0.052, 0.053, 0.054, 0.055, 0.056, 0.057, 0.058, 0.059, 0.06, 0.061, 0.062, 0.063, 0.064, 0.065, 0.066, 0.067, 0.068, 0.069, 0.07, 0.071, 0.072, 0.073, 0.074, 0.075, 0.076, 0.077, 0.078, 0.079, 0.08, 0.081, 0.082, 0.083, 0.084, 0.085, 0.086, 0.087, 0.088, 0.089, 0.09, 0.091, 0.092, 0.093, 0.094, 0.095, 0.096, 0.097, 0.098, 0.099, 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.7, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.8, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.9, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 33.0, 34.0, 35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0, 47.0, 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0, 56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 72.0, 73.0, 74.0, 75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, 88.0, 89.0, 90.0, 91.0, 92.0, 93.0, 94.0, 95.0, 96.0, 97.0, 98.0, 99.0, 100.0}, "Binning of the percentile axis"}; + + struct TagRun2V0MCalibration { + bool mCalibrationStored = false; + TFormula* mMCScale = nullptr; + float mMCScalePars[6] = {0.0}; + TH1* mhVtxAmpCorrV0A = nullptr; + TH1* mhVtxAmpCorrV0C = nullptr; + TH1* mhMultSelCalib = nullptr; + } Run2V0MInfo; + struct TagRun2V0ACalibration { + bool mCalibrationStored = false; + TH1* mhVtxAmpCorrV0A = nullptr; + TH1* mhMultSelCalib = nullptr; + } Run2V0AInfo; + struct TagRun2SPDTrackletsCalibration { + bool mCalibrationStored = false; + TH1* mhVtxAmpCorr = nullptr; + TH1* mhMultSelCalib = nullptr; + } Run2SPDTksInfo; + struct TagRun2SPDClustersCalibration { + bool mCalibrationStored = false; + TH1* mhVtxAmpCorrCL0 = nullptr; + TH1* mhVtxAmpCorrCL1 = nullptr; + TH1* mhMultSelCalib = nullptr; + } Run2SPDClsInfo; + struct TagRun2CL0Calibration { + bool mCalibrationStored = false; + TH1* mhVtxAmpCorr = nullptr; + TH1* mhMultSelCalib = nullptr; + } Run2CL0Info; + struct TagRun2CL1Calibration { + bool mCalibrationStored = false; + TH1* mhVtxAmpCorr = nullptr; + TH1* mhMultSelCalib = nullptr; + } Run2CL1Info; + struct CalibrationInfo { + std::string name = ""; + bool mCalibrationStored = false; + TH1* mhMultSelCalib = nullptr; + float mMCScalePars[6] = {0.0}; + TFormula* mMCScale = nullptr; + explicit CalibrationInfo(std::string name) + : name(name), + mCalibrationStored(false), + mhMultSelCalib(nullptr), + mMCScalePars{0.0}, + mMCScale(nullptr) + { + } + bool isSane(bool fatalize = false) + { + if (!mhMultSelCalib) { + return true; + } + for (int i = 1; i < mhMultSelCalib->GetNbinsX() + 1; i++) { + if (mhMultSelCalib->GetXaxis()->GetBinLowEdge(i) > mhMultSelCalib->GetXaxis()->GetBinUpEdge(i)) { + if (fatalize) { + LOG(fatal) << "Centrality calibration table " << name << " has bins with low edge > up edge"; + } + LOG(warning) << "Centrality calibration table " << name << " has bins with low edge > up edge"; + return false; + } + } + return true; + } + }; + CalibrationInfo fv0aInfo = CalibrationInfo("FV0"); + CalibrationInfo ft0mInfo = CalibrationInfo("FT0"); + CalibrationInfo ft0aInfo = CalibrationInfo("FT0A"); + CalibrationInfo ft0cInfo = CalibrationInfo("FT0C"); + CalibrationInfo ft0cVariant1Info = CalibrationInfo("FT0Cvar1"); + CalibrationInfo fddmInfo = CalibrationInfo("FDD"); + CalibrationInfo ntpvInfo = CalibrationInfo("NTracksPV"); + CalibrationInfo nGlobalInfo = CalibrationInfo("NGlobal"); + CalibrationInfo mftInfo = CalibrationInfo("MFT"); + + int mRunNumber; + bool lCalibLoaded; + TProfile* hVtxZFV0A; + TProfile* hVtxZFT0A; + TProfile* hVtxZFT0C; + TProfile* hVtxZFDDA; + + TProfile* hVtxZFDDC; + TProfile* hVtxZNTracks; + + // Debug output + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + OutputObj listCalib{"calib-list", OutputObjHandlingPolicy::QAObject}; + + void init(InitContext&) + { + LOG(info) << "Initializing centrality table producer"; + + if (metadataInfo.isFullyDefined() && !doprocessRun2 && !doprocessRun3) { // Check if the metadata is initialized (only if not forced from the workflow configuration) + if (metadataInfo.isRun3()) { + doprocessRun3.value = true; + } else { + doprocessRun2.value = false; + } + } + + if (doprocessRun2 == false && doprocessRun3 == false) { + LOGF(fatal, "Neither processRun2 nor processRun3 nor processRun3Complete enabled. Please choose one."); + } + if (doprocessRun2 == true && doprocessRun3 == true) { + LOGF(fatal, "Cannot enable processRun2 and processRun3 at the same time. Please choose one."); + } + + mRunNumber = 0; + lCalibLoaded = false; + + hVtxZFV0A = nullptr; + hVtxZFT0A = nullptr; + hVtxZFT0C = nullptr; + hVtxZFDDA = nullptr; + hVtxZFDDC = nullptr; + hVtxZNTracks = nullptr; + + ccdb->setURL(ccdbConfig.ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); // don't fatal, please - exception is caught explicitly (as it should) + + if (produceHistograms) { + histos.add("FT0M/Mult", "FT0M mult.", HistType::kTH1D, {{1000, 0, 5000, "FT0M mult."}}); + histos.add("FT0M/percentile", "FT0M percentile.", HistType::kTH1D, {{binsPercentile, "FT0M percentile"}}); + histos.add("FT0M/percentilevsPV", "percentile vs PV mult.", HistType::kTH2D, {{binsPercentile, "FT0M percentile"}, {100, 0, 100, "PV mult."}}); + histos.add("FT0M/MultvsPV", "FT0M mult. vs PV mult.", HistType::kTH2D, {{1000, 0, 5000, "FT0M mult."}, {100, 0, 100, "PV mult."}}); + + histos.add("FT0A/Mult", "FT0A mult", HistType::kTH1D, {{1000, 0, 1000, "FT0A multiplicity"}}); + histos.add("FT0A/percentile", "FT0A percentile.", HistType::kTH1D, {{binsPercentile, "FT0A percentile"}}); + histos.add("FT0A/percentilevsPV", "percentile vs PV mult.", HistType::kTH2D, {{binsPercentile, "FT0A percentile"}, {100, 0, 100, "PV mult."}}); + histos.add("FT0A/MultvsPV", "FT0A mult. vs PV mult.", HistType::kTH2D, {{1000, 0, 5000, "FT0A mult."}, {100, 0, 100, "PV mult."}}); + + histos.add("FT0C/Mult", "FT0C mult", HistType::kTH1D, {{1000, 0, 5000, "FT0C multiplicity"}}); + histos.add("FT0C/percentile", "FT0C percentile.", HistType::kTH1D, {{binsPercentile, "FT0C percentile"}}); + histos.add("FT0C/percentilevsPV", "percentile vs PV mult.", HistType::kTH2D, {{binsPercentile, "FT0C percentile"}, {100, 0, 100, "PV mult."}}); + histos.add("FT0C/MultvsPV", "FT0C mult. vs PV mult.", HistType::kTH2D, {{1000, 0, 5000, "FT0C mult."}, {100, 0, 100, "PV mult."}}); + + histos.addClone("FT0M/", "sel8FT0M/"); + histos.addClone("FT0C/", "sel8FT0C/"); + histos.addClone("FT0A/", "sel8FT0A/"); + + histos.print(); + } + listCalib.setObject(new TList); + } + + template + void initCCDB(TCollision collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + mRunNumber = collision.runNumber(); + LOGF(info, "timestamp=%llu, run number=%d", collision.timestamp(), collision.runNumber()); + + TList* lCalibObjects_Centrality = nullptr; + TList* lCalibObjects_Multiplicity = nullptr; + if (ccdbConfig.reconstructionPass.value == "") { + lCalibObjects_Centrality = ccdb->getForRun(ccdbConfig.ccdbPath_Centrality, mRunNumber); + lCalibObjects_Multiplicity = ccdb->getForRun(ccdbConfig.ccdbPath_Multiplicity, mRunNumber); + } else if (ccdbConfig.reconstructionPass.value == "metadata") { + std::map metadata; + metadata["RecoPassName"] = metadataInfo.get("RecoPassName"); + LOGF(info, "Loading CCDB for reconstruction pass (from metadata): %s", metadataInfo.get("RecoPassName")); + lCalibObjects_Centrality = ccdb->getSpecificForRun(ccdbConfig.ccdbPath_Centrality, mRunNumber, metadata); + lCalibObjects_Multiplicity = ccdb->getSpecificForRun(ccdbConfig.ccdbPath_Multiplicity, mRunNumber, metadata); + } else { + std::map metadata; + metadata["RecoPassName"] = ccdbConfig.reconstructionPass.value; + LOGF(info, "Loading CCDB for reconstruction pass (from provided argument): %s", ccdbConfig.reconstructionPass.value); + lCalibObjects_Centrality = ccdb->getSpecificForRun(ccdbConfig.ccdbPath_Centrality, mRunNumber, metadata); + lCalibObjects_Multiplicity = ccdb->getSpecificForRun(ccdbConfig.ccdbPath_Multiplicity, mRunNumber, metadata); + } + + fv0aInfo.mCalibrationStored = false; + ft0mInfo.mCalibrationStored = false; + ft0aInfo.mCalibrationStored = false; + ft0cInfo.mCalibrationStored = false; + ft0cVariant1Info.mCalibrationStored = false; + fddmInfo.mCalibrationStored = false; + ntpvInfo.mCalibrationStored = false; + nGlobalInfo.mCalibrationStored = false; + mftInfo.mCalibrationStored = false; + + Run2V0MInfo.mCalibrationStored = false; + Run2V0AInfo.mCalibrationStored = false; + Run2SPDTksInfo.mCalibrationStored = false; + Run2SPDClsInfo.mCalibrationStored = false; + Run2CL0Info.mCalibrationStored = false; + Run2CL1Info.mCalibrationStored = false; + + if (lCalibObjects_Centrality) { + if (produceHistograms) { + listCalib->Add(lCalibObjects_Centrality->Clone(Form("Centrality_%i", collision.runNumber()))); + } + + LOGF(info, "Getting new histograms with %d run number for %d run number", mRunNumber, collision.runNumber()); + + if constexpr (requires { collision.sel7(); }) { // check if we are in Run 2 + auto getccdb = [lCalibObjects_Centrality](const char* ccdbhname) { + TH1* h = reinterpret_cast(lCalibObjects_Centrality->FindObject(ccdbhname)); + return h; + }; + auto getformulaccdb = [lCalibObjects_Centrality](const char* ccdbhname) { + TFormula* f = reinterpret_cast(lCalibObjects_Centrality->FindObject(ccdbhname)); + return f; + }; + + // V0M + Run2V0MInfo.mhVtxAmpCorrV0A = getccdb("hVtx_fAmplitude_V0A_Normalized"); + Run2V0MInfo.mhVtxAmpCorrV0C = getccdb("hVtx_fAmplitude_V0C_Normalized"); + Run2V0MInfo.mhMultSelCalib = getccdb("hMultSelCalib_V0M"); + Run2V0MInfo.mMCScale = getformulaccdb(TString::Format("%s-V0M", ccdbConfig.genName->c_str()).Data()); + if ((Run2V0MInfo.mhVtxAmpCorrV0A != nullptr) && (Run2V0MInfo.mhVtxAmpCorrV0C != nullptr) && (Run2V0MInfo.mhMultSelCalib != nullptr)) { + if (ccdbConfig.genName->length() != 0) { + if (Run2V0MInfo.mMCScale != nullptr) { + for (int ixpar = 0; ixpar < 6; ++ixpar) { + Run2V0MInfo.mMCScalePars[ixpar] = Run2V0MInfo.mMCScale->GetParameter(ixpar); + } + } else { + if (!ccdbConfig.doNotCrashOnNull) { // default behaviour: crash + LOGF(fatal, "MC Scale information from V0M for run %d not available", collision.runNumber()); + } else { // only if asked: continue filling with non-valid values (105) + LOGF(warning, "MC Scale information from V0M for run %d not available", collision.runNumber()); + } + } + } + Run2V0MInfo.mCalibrationStored = true; + } else { + if (!ccdbConfig.doNotCrashOnNull) { // default behaviour: crash + LOGF(fatal, "Calibration information from V0M for run %d corrupted", collision.runNumber()); + } else { // only if asked: continue filling with non-valid values (105) + LOGF(warning, "Calibration information from V0M for run %d corrupted, will fill V0M tables with dummy values", collision.runNumber()); + } + } + + // V0A + Run2V0AInfo.mhVtxAmpCorrV0A = getccdb("hVtx_fAmplitude_V0A_Normalized"); + Run2V0AInfo.mhMultSelCalib = getccdb("hMultSelCalib_V0A"); + if ((Run2V0AInfo.mhVtxAmpCorrV0A != nullptr) && (Run2V0AInfo.mhMultSelCalib != nullptr)) { + Run2V0AInfo.mCalibrationStored = true; + } else { + if (!ccdbConfig.doNotCrashOnNull) { // default behaviour: crash + LOGF(fatal, "Calibration information from V0A for run %d corrupted", collision.runNumber()); + } else { // only if asked: continue filling with non-valid values (105) + LOGF(warning, "Calibration information from V0A for run %d corrupted, will fill V0A tables with dummy values", collision.runNumber()); + } + } + + // SPD tracklets + Run2SPDTksInfo.mhVtxAmpCorr = getccdb("hVtx_fnTracklets_Normalized"); + Run2SPDTksInfo.mhMultSelCalib = getccdb("hMultSelCalib_SPDTracklets"); + if ((Run2SPDTksInfo.mhVtxAmpCorr != nullptr) && (Run2SPDTksInfo.mhMultSelCalib != nullptr)) { + Run2SPDTksInfo.mCalibrationStored = true; + } else { + if (!ccdbConfig.doNotCrashOnNull) { // default behaviour: crash + LOGF(fatal, "Calibration information from SPD tracklets for run %d corrupted", collision.runNumber()); + } else { // only if asked: continue filling with non-valid values (105) + LOGF(warning, "Calibration information from SPD tracklets for run %d corrupted, will fill SPD tracklets tables with dummy values", collision.runNumber()); + } + } + + // SPD clusters + Run2SPDClsInfo.mhVtxAmpCorrCL0 = getccdb("hVtx_fnSPDClusters0_Normalized"); + Run2SPDClsInfo.mhVtxAmpCorrCL1 = getccdb("hVtx_fnSPDClusters1_Normalized"); + Run2SPDClsInfo.mhMultSelCalib = getccdb("hMultSelCalib_SPDClusters"); + if ((Run2SPDClsInfo.mhVtxAmpCorrCL0 != nullptr) && (Run2SPDClsInfo.mhVtxAmpCorrCL1 != nullptr) && (Run2SPDClsInfo.mhMultSelCalib != nullptr)) { + Run2SPDClsInfo.mCalibrationStored = true; + } else { + if (!ccdbConfig.doNotCrashOnNull) { // default behaviour: crash + LOGF(fatal, "Calibration information from SPD clusters for run %d corrupted", collision.runNumber()); + } else { // only if asked: continue filling with non-valid values (105) + LOGF(warning, "Calibration information from SPD clusters for run %d corrupted, will fill SPD clusters tables with dummy values", collision.runNumber()); + } + } + } else { + // we are in Run 3 + auto getccdb = [lCalibObjects_Centrality, collision](struct CalibrationInfo& estimator, const Configurable generatorName, const Configurable notCrashOnNull) { // TODO: to consider the name inside the estimator structure + estimator.mhMultSelCalib = reinterpret_cast(lCalibObjects_Centrality->FindObject(TString::Format("hCalibZeq%s", estimator.name.c_str()).Data())); + estimator.mMCScale = reinterpret_cast(lCalibObjects_Centrality->FindObject(TString::Format("%s-%s", generatorName->c_str(), estimator.name.c_str()).Data())); + if (estimator.mhMultSelCalib != nullptr) { + if (generatorName->length() != 0) { + LOGF(info, "Retrieving MC calibration for %d, generator name: %s", collision.runNumber(), generatorName->c_str()); + if (estimator.mMCScale != nullptr) { + for (int ixpar = 0; ixpar < 6; ++ixpar) { + estimator.mMCScalePars[ixpar] = estimator.mMCScale->GetParameter(ixpar); + LOGF(info, "Parameter index %i value %.5f", ixpar, estimator.mMCScalePars[ixpar]); + } + } else { + LOGF(warning, "MC Scale information from %s for run %d not available", estimator.name.c_str(), collision.runNumber()); + } + } + estimator.mCalibrationStored = true; + estimator.isSane(); + } else { + if (!notCrashOnNull.value) { // default behaviour: crash + LOGF(error, "Calibration information from %s for run %d not available", estimator.name.c_str(), collision.runNumber()); + } else { + LOGF(warning, "Calibration information from %s for run %d not available", estimator.name.c_str(), collision.runNumber()); + } + } + }; + getccdb(fv0aInfo, ccdbConfig.genName, ccdbConfig.doNotCrashOnNull); + getccdb(ft0mInfo, ccdbConfig.genName, ccdbConfig.doNotCrashOnNull); + getccdb(ft0aInfo, ccdbConfig.genName, ccdbConfig.doNotCrashOnNull); + getccdb(ft0cInfo, ccdbConfig.genName, ccdbConfig.doNotCrashOnNull); + getccdb(ft0cVariant1Info, ccdbConfig.genName, ccdbConfig.doNotCrashOnNull); + getccdb(fddmInfo, ccdbConfig.genName, ccdbConfig.doNotCrashOnNull); + getccdb(ntpvInfo, ccdbConfig.genName, ccdbConfig.doNotCrashOnNull); + getccdb(nGlobalInfo, ccdbConfig.genName, ccdbConfig.doNotCrashOnNull); + getccdb(mftInfo, ccdbConfig.genName, ccdbConfig.doNotCrashOnNull); + + if (lCalibObjects_Multiplicity) { + if (produceHistograms) { + listCalib->Add(lCalibObjects_Multiplicity->Clone(Form("Multiplicity_%i", collision.runNumber()))); + } + + hVtxZFV0A = static_cast(lCalibObjects_Multiplicity->FindObject("hVtxZFV0A")); + hVtxZFT0A = static_cast(lCalibObjects_Multiplicity->FindObject("hVtxZFT0A")); + hVtxZFT0C = static_cast(lCalibObjects_Multiplicity->FindObject("hVtxZFT0C")); + hVtxZFDDA = static_cast(lCalibObjects_Multiplicity->FindObject("hVtxZFDDA")); + hVtxZFDDC = static_cast(lCalibObjects_Multiplicity->FindObject("hVtxZFDDC")); + hVtxZNTracks = static_cast(lCalibObjects_Multiplicity->FindObject("hVtxZNTracksPV")); + lCalibLoaded = true; + // Capture error + if (!hVtxZFV0A || !hVtxZFT0A || !hVtxZFT0C || !hVtxZFDDA || !hVtxZFDDC || !hVtxZNTracks) { + LOGF(error, "Problem loading CCDB objects! Please check"); + lCalibLoaded = false; + } + } else { + if (!ccdbConfig.doNotCrashOnNull) { // default behaviour: crash + LOGF(fatal, "Multiplicity calibration is not available in CCDB for run=%d at timestamp=%llu", collision.runNumber(), collision.timestamp()); + } else { // only if asked: continue filling with non-valid values (105) + LOGF(warning, "Multiplicity calibration is not available in CCDB for run=%d at timestamp=%llu, will fill tables with dummy values", collision.runNumber(), collision.timestamp()); + } + lCalibLoaded = false; + } + } // end we are in Run 3 + } else { + if (!ccdbConfig.doNotCrashOnNull) { // default behaviour: crash + LOGF(fatal, "Centrality calibration is not available in CCDB for run=%d at timestamp=%llu", collision.runNumber(), collision.timestamp()); + } else { // only if asked: continue filling with non-valid values (105) + LOGF(warning, "Centrality calibration is not available in CCDB for run=%d at timestamp=%llu, will fill tables with dummy values", collision.runNumber(), collision.timestamp()); + } + lCalibLoaded = false; + } + } + + void processRun2(soa::Join const& collisions) + { + for (auto const& collision : collisions) { + if (doVertexZeq > 0) { + initCCDB(collision); + } + + float centRun2V0M = 105.0f; + float centRun2V0A = 105.0f; + float centRun2SPDTrks = 105.0f; + float centRun2SPDClss = 105.0f; + + auto scaleMC = [](float x, float pars[6]) { + return std::pow(((pars[0] + pars[1] * std::pow(x, pars[2])) - pars[3]) / pars[4], 1.0f / pars[5]); + }; + + // Run 2 V0M + if (Run2V0MInfo.mCalibrationStored) { + float v0m; + if (Run2V0MInfo.mMCScale != nullptr) { + v0m = scaleMC(collision.multFV0A() + collision.multFV0C(), Run2V0MInfo.mMCScalePars); + LOGF(debug, "Unscaled v0m: %f, scaled v0m: %f", collision.multFV0A() + collision.multFV0C(), v0m); + } else { + v0m = collision.multFV0A() * Run2V0MInfo.mhVtxAmpCorrV0A->GetBinContent(Run2V0MInfo.mhVtxAmpCorrV0A->FindFixBin(collision.posZ())) + + collision.multFV0C() * Run2V0MInfo.mhVtxAmpCorrV0C->GetBinContent(Run2V0MInfo.mhVtxAmpCorrV0C->FindFixBin(collision.posZ())); + } + centRun2V0M = Run2V0MInfo.mhMultSelCalib->GetBinContent(Run2V0MInfo.mhMultSelCalib->FindFixBin(v0m)); + } + LOGF(debug, "centRun2V0M=%.0f", centRun2V0M); + + // Run 2 V0A + if (Run2V0AInfo.mCalibrationStored) { + float v0a = collision.multFV0A() * Run2V0AInfo.mhVtxAmpCorrV0A->GetBinContent(Run2V0AInfo.mhVtxAmpCorrV0A->FindFixBin(collision.posZ())); + centRun2V0A = Run2V0AInfo.mhMultSelCalib->GetBinContent(Run2V0AInfo.mhMultSelCalib->FindFixBin(v0a)); + } + LOGF(debug, "centRun2V0A=%.0f", centRun2V0A); + + // Run 2 SPD tracklets + if (Run2SPDTksInfo.mCalibrationStored) { + float spdm = collision.multTracklets() * Run2SPDTksInfo.mhVtxAmpCorr->GetBinContent(Run2SPDTksInfo.mhVtxAmpCorr->FindFixBin(collision.posZ())); + centRun2SPDTrks = Run2SPDTksInfo.mhMultSelCalib->GetBinContent(Run2SPDTksInfo.mhMultSelCalib->FindFixBin(spdm)); + } + LOGF(debug, "centSPDTracklets=%.0f", centRun2SPDTrks); + + // Run 2 SPD Cls + if (Run2SPDClsInfo.mCalibrationStored) { + // spdClustersL0 and spdClustersL1 not available in strangeness data model + float spdm = collision.spdClustersL0() * Run2SPDClsInfo.mhVtxAmpCorrCL0->GetBinContent(Run2SPDClsInfo.mhVtxAmpCorrCL0->FindFixBin(collision.posZ())) + + collision.spdClustersL1() * Run2SPDClsInfo.mhVtxAmpCorrCL1->GetBinContent(Run2SPDClsInfo.mhVtxAmpCorrCL1->FindFixBin(collision.posZ())); + centRun2SPDClss = Run2SPDClsInfo.mhMultSelCalib->GetBinContent(Run2SPDClsInfo.mhMultSelCalib->FindFixBin(spdm)); + } + LOGF(debug, "centSPDClusters=%.0f", centRun2SPDClss); + + strangeCentsRun2(centRun2V0M, centRun2V0A, + centRun2SPDTrks, centRun2SPDClss); + } + } + + void processRun3(soa::Join const& collisions) + { + for (auto const& collision : collisions) { + if (doVertexZeq > 0) { + initCCDB(collision); + } + + float multZeqFV0A = 0.f; + float multZeqFT0A = 0.f; + float multZeqFT0C = 0.f; + // float multZeqFDDA = 0.f; + // float multZeqFDDC = 0.f; + + if (std::fabs(collision.posZ()) < 15.0f && hVtxZFV0A) { + multZeqFV0A = hVtxZFV0A->Interpolate(0.0) * collision.multFV0A() / hVtxZFV0A->Interpolate(collision.posZ()); + } + if (std::fabs(collision.posZ()) < 15.0f && hVtxZFT0A) { + multZeqFT0A = hVtxZFT0A->Interpolate(0.0) * collision.multFT0A() / hVtxZFT0A->Interpolate(collision.posZ()); + } + if (std::fabs(collision.posZ()) < 15.0f && hVtxZFT0C) { + multZeqFT0C = hVtxZFT0C->Interpolate(0.0) * collision.multFT0C() / hVtxZFT0C->Interpolate(collision.posZ()); + } + // if (std::fabs(collision.posZ()) < 15.0f && hVtxZFDDA) { + // multZeqFDDA = hVtxZFDDA->Interpolate(0.0) * collision.multFDDA() / hVtxZFDDA->Interpolate(collision.posZ()); + // } + // if (std::fabs(collision.posZ()) < 15.0f && hVtxZFDDC) { + // multZeqFDDC = hVtxZFDDC->Interpolate(0.0) * collision.multFDDC() / hVtxZFDDC->Interpolate(collision.posZ()); + // } + + /** + * @brief Get centrality value based on the given calibration information and multiplicity. + * Modified version of populateTable (https://github.com/AliceO2Group/O2Physics/blob/master/Common/TableProducer/centralityTable.cxx#L648) + * + * @param estimator The calibration information. + * @param multiplicity The multiplicity value. + */ + + auto getCentrality = [&](struct CalibrationInfo& estimator, float multiplicity) { + const bool assignOutOfRange = embedINELgtZEROselection && !(collision.multNTracksPVeta1() > 0); + auto scaleMC = [](float x, float pars[6]) { + return std::pow(((pars[0] + pars[1] * std::pow(x, pars[2])) - pars[3]) / pars[4], 1.0f / pars[5]); + }; + + float percentile = 105.0f; + float scaledMultiplicity = multiplicity; + if (estimator.mCalibrationStored) { + if (estimator.mMCScale != nullptr) { + scaledMultiplicity = scaleMC(multiplicity, estimator.mMCScalePars); + LOGF(debug, "Unscaled %s multiplicity: %f, scaled %s multiplicity: %f", estimator.name.c_str(), multiplicity, estimator.name.c_str(), scaledMultiplicity); + } + percentile = estimator.mhMultSelCalib->GetBinContent(estimator.mhMultSelCalib->FindFixBin(scaledMultiplicity)); + if (assignOutOfRange) + percentile = 100.5f; + } + LOGF(debug, "%s centrality/multiplicity percentile = %.0f for a zvtx eq %s value %.0f", estimator.name.c_str(), percentile, estimator.name.c_str(), scaledMultiplicity); + return percentile; + }; + + float centFT0M = getCentrality(ft0mInfo, multZeqFT0A + multZeqFT0C); + float centFT0A = getCentrality(ft0aInfo, multZeqFT0A); + float centFT0C = getCentrality(ft0cInfo, multZeqFT0C); + float centFV0A = getCentrality(fv0aInfo, multZeqFV0A); + float centFT0CVariant1 = getCentrality(ft0cVariant1Info, multZeqFT0C); + float centMFT = 100.5f; // missing mftNtracks in strangeness data model + float centNGlobal = getCentrality(nGlobalInfo, collision.multNTracksGlobal()); + + strangeCents(centFT0M, centFT0A, + centFT0C, centFV0A, centFT0CVariant1, + centMFT, centNGlobal); + + if (produceHistograms.value) { + histos.fill(HIST("FT0M/Mult"), multZeqFT0A + multZeqFT0C); + histos.fill(HIST("FT0M/percentile"), centFT0M); + histos.fill(HIST("FT0M/percentilevsPV"), centFT0M, collision.multNTracksPVeta1()); + histos.fill(HIST("FT0M/MultvsPV"), multZeqFT0A + multZeqFT0C, collision.multNTracksPVeta1()); + + histos.fill(HIST("FT0A/Mult"), multZeqFT0A); + histos.fill(HIST("FT0A/percentile"), centFT0A); + histos.fill(HIST("FT0A/percentilevsPV"), centFT0A, collision.multNTracksPVeta1()); + histos.fill(HIST("FT0A/MultvsPV"), multZeqFT0A, collision.multNTracksPVeta1()); + + histos.fill(HIST("FT0C/Mult"), multZeqFT0C); + histos.fill(HIST("FT0C/percentile"), centFT0C); + histos.fill(HIST("FT0C/percentilevsPV"), centFT0C, collision.multNTracksPVeta1()); + histos.fill(HIST("FT0C/MultvsPV"), multZeqFT0C, collision.multNTracksPVeta1()); + if (collision.sel8()) { + histos.fill(HIST("sel8FT0M/Mult"), multZeqFT0A + multZeqFT0C); + histos.fill(HIST("sel8FT0M/percentile"), centFT0M); + histos.fill(HIST("sel8FT0M/percentilevsPV"), centFT0M, collision.multNTracksPVeta1()); + histos.fill(HIST("sel8FT0M/MultvsPV"), multZeqFT0A + multZeqFT0C, collision.multNTracksPVeta1()); + + histos.fill(HIST("sel8FT0A/Mult"), multZeqFT0A); + histos.fill(HIST("sel8FT0A/percentile"), centFT0A); + histos.fill(HIST("sel8FT0A/percentilevsPV"), centFT0A, collision.multNTracksPVeta1()); + histos.fill(HIST("sel8FT0A/MultvsPV"), multZeqFT0A, collision.multNTracksPVeta1()); + + histos.fill(HIST("sel8FT0C/Mult"), multZeqFT0C); + histos.fill(HIST("sel8FT0C/percentile"), centFT0C); + histos.fill(HIST("sel8FT0C/percentilevsPV"), centFT0C, collision.multNTracksPVeta1()); + histos.fill(HIST("sel8FT0C/MultvsPV"), multZeqFT0C, collision.multNTracksPVeta1()); + } + } + } + } + + // Process switches + PROCESS_SWITCH(straCents, processRun2, "Provide Run2 calibrated centrality/multiplicity percentiles tables", false); + PROCESS_SWITCH(straCents, processRun3, "Provide Run3 calibrated centrality/multiplicity percentiles tables", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + metadataInfo.initMetadata(cfgc); + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx b/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx index 41a3cf46936..6a67077dff3 100644 --- a/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx +++ b/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/RunningWorkflowInfo.h" @@ -46,6 +48,7 @@ #include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/Qvectors.h" #include "Framework/StaticFor.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Common/DataModel/McCollisionExtra.h" #include "PWGLF/DataModel/EPCalibrationTables.h" @@ -54,12 +57,15 @@ using namespace o2::framework; using namespace o2::framework::expressions; using std::array; -using TracksWithExtra = soa::Join; +using TracksWithExtra = soa::Join; using TracksCompleteIUMC = soa::Join; using FullTracksExtIUTOF = soa::Join; using FullCollisions = soa::Join; +using UDCollisionsFull = soa::Join; -// simple checkers +using BCsWithTimestampsAndRun2Infos = soa::Join; + +// simple bit checkers #define bitset(var, nbit) ((var) |= (1 << (nbit))) #define bitcheck(var, nbit) ((var) & (1 << (nbit))) @@ -72,20 +78,20 @@ struct strangederivedbuilder { Produces strangeCollLabels; // characterises collisions Produces strangeMCColl; // characterises collisions / MC Produces strangeMCMults; // characterises collisions / MC mults - Produces strangeCents; // characterises collisions / centrality - Produces strangeRawCents; // characterises collisions / centrality - Produces strangeEvSels; // characterises collisions / sel8 selection + Produces strangeCents; // characterises collisions / centrality in Run 3 + Produces strangeCentsRun2; // characterises collisions / centrality in Run 2 + Produces strangeEvSels; // characterises collisions / centrality / sel8 selection in Run 3 + Produces strangeEvSelsRun2; // characterises collisions / centrality / sel8 selection in Run 2 Produces strangeStamps; // provides timestamps, run numbers Produces v0collref; // references collisions from V0s - Produces v0mccollref; // references collisions from V0s Produces casccollref; // references collisions from cascades - Produces cascmccollref; // references collisions from V0s Produces kfcasccollref; // references collisions from KF cascades Produces tracasccollref; // references collisions from tracked cascades //__________________________________________________ // track extra references Produces dauTrackExtras; // daughter track detector properties + Produces dauTrackMCIds; // daughter track MC Particle ID Produces dauTrackTPCPIDs; // daughter track TPC PID Produces dauTrackTOFPIDs; // daughter track TOF PID Produces v0Extras; // references DauTracks from V0s @@ -105,12 +111,20 @@ struct strangederivedbuilder { Produces cascmothers; // casc mother references Produces motherMCParts; // mc particles for mothers + //__________________________________________________ + // UPC specific information + Produces zdcNeutrons; // Primary neutrons within ZDC acceptance + Produces zdcNeutronsMCCollRefs; // references collisions from ZDCNeutrons + //__________________________________________________ // Q-vectors - Produces StraFT0AQVs; // FT0A Q-vector - Produces StraFT0CQVs; // FT0C Q-vector - Produces StraFT0MQVs; // FT0M Q-vector - Produces StraFV0AQVs; // FV0A Q-vector + Produces StraFT0AQVs; // FT0A Q-vector + Produces StraFT0CQVs; // FT0C Q-vector + Produces StraFT0MQVs; // FT0M Q-vector + Produces StraFV0AQVs; // FV0A Q-vector + Produces StraTPCQVs; // TPC Q-vector + Produces StraFT0CQVsEv; // events used to compute FT0C Q-vector (LF) + Produces StraZDCSP; // ZDC Sums and Products //__________________________________________________ // Generated binned data @@ -123,6 +137,10 @@ struct strangederivedbuilder { Produces geOmegaMinus; Produces geOmegaPlus; + //__________________________________________________ + // Debug + Produces straOrigin; + // histogram registry for bookkeeping HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -158,15 +176,32 @@ struct strangederivedbuilder { Configurable roundNSigmaVariables{"roundNSigmaVariables", false, "round NSigma variables"}; Configurable precisionNSigmas{"precisionNSigmas", 0.1f, "precision to keep NSigmas"}; - Configurable fillRawFT0A{"fillRawFT0A", false, "Fill raw FT0A information for debug"}; - Configurable fillRawFT0C{"fillRawFT0C", true, "Fill raw FT0C information for debug"}; - Configurable fillRawFV0A{"fillRawFV0A", false, "Fill raw FV0A information for debug"}; - Configurable fillRawZDC{"fillRawZDC", false, "Fill raw ZDC information for debug"}; - Configurable fillRawNTracksEta1{"fillRawNTracksEta1", true, "Fill raw NTracks |eta|<1 information for debug"}; - Configurable fillRawNTracksForCorrelation{"fillRawNTracksForCorrelation", true, "Fill raw NTracks for correlation cuts"}; - Configurable fillTOFInformation{"fillTOFInformation", true, "Fill Daughter Track TOF information"}; + struct : ConfigurableGroup { + Configurable fillRawFT0A{"fillRawFT0A", false, "Fill raw FT0A information for debug"}; + Configurable fillRawFT0C{"fillRawFT0C", true, "Fill raw FT0C information for debug"}; + Configurable fillRawFV0A{"fillRawFV0A", false, "Fill raw FV0A information for debug"}; + Configurable fillRawFV0C{"fillRawFV0C", false, "Fill raw FV0C information for debug (only Run 2)"}; + Configurable fillRawFDDA{"fillRawFDDA", false, "Fill raw FDDA information for debug"}; + Configurable fillRawFDDC{"fillRawFDDC", false, "Fill raw FDDC information for debug"}; + Configurable fillRawZDC{"fillRawZDC", false, "Fill raw ZDC information for debug"}; + Configurable fillRawNTracksEta1{"fillRawNTracksEta1", true, "Fill raw NTracks |eta|<1 information for debug"}; + Configurable fillRawTrackletsRun2{"fillRawTrackletsRun2", true, "Fill raw tracklets information for debug (only Run 2)"}; + Configurable fillRawSPDclsL0Run2{"fillRawSPDclsL0Run2", true, "Fill raw SPD clusters at layer 0 information for debug (only Run 2)"}; + Configurable fillRawSPDclsL1Run2{"fillRawSPDclsL1Run2", true, "Fill raw SPD clusters at layer 1 information for debug (only Run 2)"}; + Configurable fillRawNTracksForCorrelation{"fillRawNTracksForCorrelation", true, "Fill raw NTracks for correlation cuts"}; + Configurable fillTOFInformation{"fillTOFInformation", true, "Fill Daughter Track TOF information"}; + } fillTruncationOptions; Configurable qaCentrality{"qaCentrality", false, "qa centrality flag: check base raw values"}; + struct : ConfigurableGroup { + ConfigurableAxis axisFT0A{"FT0Aamplitude", {100, 0.0f, 2000.0f}, "FT0Aamplitude"}; + ConfigurableAxis axisFT0C{"FT0Camplitude", {100, 0.0f, 2000.0f}, "FT0Camplitude"}; + ConfigurableAxis axisFV0A{"FV0Aamplitude", {100, 0.0f, 2000.0f}, "FV0Aamplitude"}; + ConfigurableAxis axisFDDA{"FDDAamplitude", {100, 0.0f, 2000.0f}, "FDDAamplitude"}; + ConfigurableAxis axisFDDC{"FDDCamplitude", {100, 0.0f, 2000.0f}, "FDDCamplitude"}; + ConfigurableAxis axisZNA{"ZNAamplitude", {100, 0.0f, 250.0f}, "ZNAamplitude"}; + ConfigurableAxis axisZNC{"ZNCamplitude", {100, 0.0f, 250.0f}, "ZNCamplitude"}; + } axisDetectors; // For manual sliceBy Preslice V0perCollision = o2::aod::v0data::collisionId; @@ -174,6 +209,9 @@ struct strangederivedbuilder { Preslice KFCascperCollision = o2::aod::cascdata::collisionId; Preslice TraCascperCollision = o2::aod::cascdata::collisionId; Preslice mcParticlePerMcCollision = o2::aod::mcparticle::mcCollisionId; + Preslice udCollisionsPerCollision = o2::aod::udcollision::collisionId; + + Service pdg; std::vector genK0Short; std::vector genLambda; @@ -194,6 +232,140 @@ struct strangederivedbuilder { void init(InitContext&) { + LOGF(info, "Initializing now: cross-checking correctness..."); + if (doprocessCollisionsRun3 + + doprocessCollisionsRun3WithUD + + doprocessCollisionsRun3WithMC + + doprocessCollisionsRun3WithUDWithMC + + doprocessCollisionsRun2 + + doprocessCollisionsRun2WithMC > + 1) { + LOGF(fatal, "You have enabled more than one process function associated to collisions. Please check your configuration! Aborting now."); + } + if (doprocessTrackExtrasV0sOnly + + doprocessTrackExtras + + doprocessTrackExtrasNoPID + + doprocessTrackExtrasMC > + 1) { + LOGF(fatal, "You have enabled more than one process function associated to TracksExtra. Please check your configuration! Aborting now."); + } + + LOGF(info, "====] base information processing [==============================="); + if (doprocessDataframeIDs) { + LOGF(info, "Process data frame IDs............: yes"); + } else { + LOGF(info, "Process data frame IDs............: no"); + } + + // collision processing printout + if (doprocessCollisionsRun3) { + LOGF(info, "Collision processing type.........: Run 3, no UD, no MC"); + } + if (doprocessCollisionsRun3WithUD) { + LOGF(info, "Collision processing type.........: Run 3, with UD, no MC"); + } + if (doprocessCollisionsRun3WithMC) { + LOGF(info, "Collision processing type.........: Run 3, with MC, no UD"); + } + if (doprocessCollisionsRun3WithUDWithMC) { + LOGF(info, "Collision processing type.........: Run 3, with MC, with UD"); + } + if (doprocessCollisionsRun2) { + LOGF(info, "Collision processing type.........: Run 2, no UD, no MC"); + } + if (doprocessCollisionsRun2WithMC) { + LOGF(info, "Collision processing type.........: Run 2, with MC, no UD"); + } + + LOGF(info, "====] event characterization processing [========================="); + if (doprocessFT0AQVectors) { + LOGF(info, "Process FT0A Q-vectors............: yes"); + } else { + LOGF(info, "Process FT0A Q-vectors............: no"); + } + if (doprocessFT0CQVectors) { + LOGF(info, "Process FT0C Q-vectors............: yes"); + } else { + LOGF(info, "Process FT0C Q-vectors............: no"); + } + if (doprocessFT0CQVectorsLF) { + LOGF(info, "Process FT0C Q-vectors (LF).......: yes"); + } else { + LOGF(info, "Process FT0C Q-vectors (LF).......: no"); + } + if (doprocessFT0MQVectors) { + LOGF(info, "Process FT0M Q-vectors............: yes"); + } else { + LOGF(info, "Process FT0M Q-vectors............: no"); + } + if (doprocessFV0AQVectors) { + LOGF(info, "Process FV0A Q-vectors............: yes"); + } else { + LOGF(info, "Process FV0A Q-vectors............: no"); + } + if (doprocessTPCQVectors) { + LOGF(info, "Process TPC Q-vectors.............: yes"); + } else { + LOGF(info, "Process TPC Q-vectors.............: no"); + } + if (doprocessTPCQVectorsLF) { + LOGF(info, "Process TPC Q-vectors (LF)........: yes"); + } else { + LOGF(info, "Process TPC Q-vectors (LF)........: no"); + } + if (doprocessZDCSP) { + LOGF(info, "Process ZPC spectator plane.......: yes"); + } else { + LOGF(info, "Process ZPC spectator plane.......: no"); + } + + LOGF(info, "====] daughter track property processing [========================"); + if (doprocessTrackExtrasV0sOnly) { + LOGF(info, "TracksExtra processing type.......: V0s only"); + } + if (doprocessTrackExtras) { + LOGF(info, "TracksExtra processing type.......: V0s + cascades"); + } + if (doprocessTrackExtrasNoPID) { + LOGF(info, "TracksExtra processing type.......: V0s + cascades, no PID"); + } + if (doprocessTrackExtrasMC) { + LOGF(info, "TracksExtra processing type.......: V0s + cascades, Monte Carlo"); + } + LOGF(info, "====] cascade interlink processing [=============================="); + if (doprocessCascadeInterlinkTracked) { + LOGF(info, "Process cascade/tracked interlink.: yes"); + } else { + LOGF(info, "Process cascade/tracked interlink.: no"); + } + if (doprocessCascadeInterlinkKF) { + LOGF(info, "Process cascade/KF interlink......: yes"); + } else { + LOGF(info, "Process cascade/KF interlink......: no"); + } + LOGF(info, "====] simulated information processing [=========================="); + if (doprocessPureSimulation) { + LOGF(info, "Process pure simulation info......: yes"); + } else { + LOGF(info, "Process pure simulation info......: no"); + } + if (doprocessReconstructedSimulation) { + LOGF(info, "Process reco simulation info......: yes"); + } else { + LOGF(info, "Process reco simulation info......: no"); + } + if (doprocessBinnedGenerated) { + LOGF(info, "Process binned simulation info....: yes"); + } else { + LOGF(info, "Process binned simulation info....: no"); + } + if (doprocessStrangeMothers) { + LOGF(info, "Process strange mothers...........: yes"); + } else { + LOGF(info, "Process strange mothers...........: no"); + } + LOGF(info, "=================================================================="); + // setup map for fast checking if enabled static_for<0, nSpecies - 1>([&](auto i) { constexpr int index = i.value; @@ -205,8 +377,8 @@ struct strangederivedbuilder { // Creation of histograms: MC generated for (Int_t i = 0; i < nSpecies; i++) { - histos.add(Form("hGen%s", particleNames[i].data()), Form("hGen%s", particleNames[i].data()), kTH1D, {axisPt}); - histos.add(Form("h2dGen%s", particleNames[i].data()), Form("h2dGen%s", particleNames[i].data()), kTH2D, {axisCentrality, axisPt}); + histos.add(Form("hGenerated%s", particleNames[i].data()), Form("hGenerated%s", particleNames[i].data()), kTH1D, {axisPt}); + histos.add(Form("h2dGenerated%s", particleNames[i].data()), Form("h2dGenerated%s", particleNames[i].data()), kTH2D, {axisCentrality, axisPt}); } histos.add("h2dNVerticesVsCentrality", "h2dNVerticesVsCentrality", kTH2D, {axisCentrality, axisNVertices}); @@ -214,6 +386,14 @@ struct strangederivedbuilder { // for QA and test purposes auto hRawCentrality = histos.add("hRawCentrality", "hRawCentrality", kTH1F, {axisRawCentrality}); + auto hFT0AMultVsFT0AUD = histos.add("hFT0AMultVsFT0AUD", "hFT0AMultVsFT0AUD; FT0-A Mult; FT0-A UD", kTH2F, {axisDetectors.axisFT0A, axisDetectors.axisFT0A}); + auto hFT0CMultVsFT0CUD = histos.add("hFT0CMultVsFT0CUD", "hFT0CMultVsFT0CUD; FT0-C Mult; FT0-C UD", kTH2F, {axisDetectors.axisFT0C, axisDetectors.axisFT0C}); + auto hFV0AMultVsFV0AUD = histos.add("hFV0AMultVsFV0AUD", "hFV0AMultVsFV0AUD; FV0-A Mult; FV0-A UD", kTH2F, {axisDetectors.axisFV0A, axisDetectors.axisFV0A}); + auto hFDDAMultVsFDDAUD = histos.add("hFDDAMultVsFDDAUD", "hFDDAMultVsFDDAUD; FDD-A Mult; FDD-A UD", kTH2F, {axisDetectors.axisFDDA, axisDetectors.axisFDDA}); + auto hFDDCMultVsFDDCUD = histos.add("hFDDCMultVsFDDCUD", "hFDDCMultVsFDDCUD; FDD-C Mult; FDD-C UD", kTH2F, {axisDetectors.axisFDDC, axisDetectors.axisFDDC}); + auto hZNAMultVsZNAUD = histos.add("hZNAMultVsZNAUD", "hZNAMultVsZNAUD; ZNA Mult; ZNA UD", kTH2F, {axisDetectors.axisZNA, axisDetectors.axisZNA}); + auto hZNCMultVsZNCUD = histos.add("hZNCMultVsZNCUD", "hZNCMultVsZNCUD; ZNC Mult; ZNC UD", kTH2F, {axisDetectors.axisZNC, axisDetectors.axisZNC}); + for (int ii = 1; ii < 101; ii++) { float value = 100.5f - static_cast(ii); hRawCentrality->SetBinContent(ii, value); @@ -221,7 +401,7 @@ struct strangederivedbuilder { if (doprocessBinnedGenerated) { // reserve space for generated vectors if that process enabled - auto hBinFinder = histos.get(HIST("h2dGenK0Short")); + auto hBinFinder = histos.get(HIST("h2dGeneratedK0Short")); LOGF(info, "Binned generated processing enabled. Initialising with %i elements...", hBinFinder->GetNcells()); genK0Short.resize(hBinFinder->GetNcells(), 0); genLambda.resize(hBinFinder->GetNcells(), 0); @@ -234,55 +414,20 @@ struct strangederivedbuilder { } } - void processCollisionsV0sOnly(soa::Join const& collisions, aod::V0Datas const& V0s, aod::BCsWithTimestamps const&) + // master function to process a collision + template + void populateCollisionTables(coll const& collisions, udcoll const& udCollisions, v0d const& V0s, cad const& Cascades, kfcad const& KFCascades, tracad const& TraCascades, bcType const& /*bcs*/) { - for (const auto& collision : collisions) { - const uint64_t collIdx = collision.globalIndex(); - auto V0Table_thisColl = V0s.sliceBy(V0perCollision, collIdx); - bool strange = V0Table_thisColl.size() > 0; - // casc table sliced - if (strange || fillEmptyCollisions) { - strangeColl(collision.posX(), collision.posY(), collision.posZ()); - strangeCents(collision.centFT0M(), collision.centFT0A(), - collision.centFT0C(), collision.centFV0A()); - strangeEvSels(collision.sel8(), collision.selection_raw()); - auto bc = collision.bc_as(); - strangeStamps(bc.runNumber(), bc.timestamp()); - - if (fillRawFT0C || fillRawFT0C || fillRawFV0A || fillRawNTracksEta1 || fillRawZDC) { - strangeRawCents(collision.multFT0A() * static_cast(fillRawFT0A), - collision.multFT0C() * static_cast(fillRawFT0C), - collision.multFV0A() * static_cast(fillRawFV0A), - collision.multNTracksPVeta1() * static_cast(fillRawNTracksEta1), - collision.multPVTotalContributors() * static_cast(fillRawNTracksForCorrelation), - collision.multNTracksGlobal() * static_cast(fillRawNTracksForCorrelation), - collision.multNTracksITSTPC() * static_cast(fillRawNTracksForCorrelation), - collision.multAllTracksTPCOnly() * static_cast(fillRawNTracksForCorrelation), - collision.multAllTracksITSTPC() * static_cast(fillRawNTracksForCorrelation), - collision.multZNA() * static_cast(fillRawZDC), - collision.multZNC() * static_cast(fillRawZDC), - collision.multZEM1() * static_cast(fillRawZDC), - collision.multZEM2() * static_cast(fillRawZDC), - collision.multZPA() * static_cast(fillRawZDC), - collision.multZPC() * static_cast(fillRawZDC)); - } - } - for (int i = 0; i < V0Table_thisColl.size(); i++) - v0collref(strangeColl.lastIndex()); - } - } + // create collision indices beforehand + std::vector V0CollIndices(V0s.size(), -1); // index -1: no collision + std::vector CascadeCollIndices(Cascades.size(), -1); // index -1: no collision + std::vector KFCascadeCollIndices(KFCascades.size(), -1); // index -1: no collision + std::vector TraCascadeCollIndices(TraCascades.size(), -1); // index -1: no collision - void processCollisions(soa::Join const& collisions, aod::V0Datas const& V0s, aod::CascDatas const& Cascades, aod::KFCascDatas const& KFCascades, aod::TraCascDatas const& TraCascades, aod::BCsWithTimestamps const&) - { + // +-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+ for (const auto& collision : collisions) { const uint64_t collIdx = collision.globalIndex(); - float centrality = collision.centFT0C(); - if (qaCentrality) { - auto hRawCentrality = histos.get(HIST("hRawCentrality")); - centrality = hRawCentrality->GetBinContent(hRawCentrality->FindBin(collision.multFT0C())); - } - auto V0Table_thisColl = V0s.sliceBy(V0perCollision, collIdx); auto CascTable_thisColl = Cascades.sliceBy(CascperCollision, collIdx); auto KFCascTable_thisColl = KFCascades.sliceBy(KFCascperCollision, collIdx); @@ -291,129 +436,218 @@ struct strangederivedbuilder { CascTable_thisColl.size() > 0 || KFCascTable_thisColl.size() > 0 || TraCascTable_thisColl.size() > 0; - // casc table sliced + + auto bc = collision.template bc_as(); + + int gapSide = -1; + float totalFT0AmplitudeA = -999; + float totalFT0AmplitudeC = -999; + float totalFV0AmplitudeA = -999; + float totalFDDAmplitudeA = -999; + float totalFDDAmplitudeC = -999; + float energyCommonZNA = -999; + float energyCommonZNC = -999; + + // +-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+ + // set UD information in case present at this stage + auto udCollIterator = udCollisions.begin(); + if constexpr (requires { udCollIterator.gapSide(); }) { // check if this table is the expected one + auto udCollision = udCollisions.sliceBy(udCollisionsPerCollision, collIdx); + if (udCollision.size() == 1) { // check that the slicing provide a unique UD collision + for (auto& udColl : udCollision) { + gapSide = udColl.gapSide(); + totalFT0AmplitudeA = udColl.totalFT0AmplitudeA(); + totalFT0AmplitudeC = udColl.totalFT0AmplitudeC(); + totalFV0AmplitudeA = udColl.totalFV0AmplitudeA(); + totalFDDAmplitudeA = udColl.totalFDDAmplitudeA(); + totalFDDAmplitudeC = udColl.totalFDDAmplitudeC(); + energyCommonZNA = udColl.energyCommonZNA(); + energyCommonZNC = udColl.energyCommonZNC(); + + histos.fill(HIST("hFT0AMultVsFT0AUD"), collision.multFT0A(), udColl.totalFT0AmplitudeA()); + histos.fill(HIST("hFT0CMultVsFT0CUD"), collision.multFT0C(), udColl.totalFT0AmplitudeC()); + histos.fill(HIST("hFV0AMultVsFV0AUD"), collision.multFV0A(), udColl.totalFV0AmplitudeA()); + histos.fill(HIST("hFDDAMultVsFDDAUD"), collision.multFDDA(), udColl.totalFDDAmplitudeA()); + histos.fill(HIST("hFDDCMultVsFDDCUD"), collision.multFDDC(), udColl.totalFDDAmplitudeC()); + histos.fill(HIST("hZNAMultVsZNAUD"), collision.multZNA(), udColl.energyCommonZNA()); + histos.fill(HIST("hZNCMultVsZNCUD"), collision.multZNC(), udColl.energyCommonZNC()); + } + } + } + + // +-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+ + // fill collision tables if (strange || fillEmptyCollisions) { + strangeStamps(bc.runNumber(), bc.timestamp(), bc.globalBC()); strangeColl(collision.posX(), collision.posY(), collision.posZ()); - strangeCents(collision.centFT0M(), collision.centFT0A(), - centrality, collision.centFV0A()); - strangeEvSels(collision.sel8(), collision.selection_raw()); - auto bc = collision.bc_as(); - strangeStamps(bc.runNumber(), bc.timestamp()); - - if (fillRawFT0C || fillRawFT0C || fillRawFV0A || fillRawNTracksEta1 || fillRawZDC) { - strangeRawCents(collision.multFT0A() * static_cast(fillRawFT0A), - collision.multFT0C() * static_cast(fillRawFT0C), - collision.multFV0A() * static_cast(fillRawFV0A), - collision.multNTracksPVeta1() * static_cast(fillRawNTracksEta1), - collision.multPVTotalContributors() * static_cast(fillRawNTracksForCorrelation), - collision.multNTracksGlobal() * static_cast(fillRawNTracksForCorrelation), - collision.multNTracksITSTPC() * static_cast(fillRawNTracksForCorrelation), - collision.multAllTracksTPCOnly() * static_cast(fillRawNTracksForCorrelation), - collision.multAllTracksITSTPC() * static_cast(fillRawNTracksForCorrelation), - collision.multZNA() * static_cast(fillRawZDC), - collision.multZNC() * static_cast(fillRawZDC), - collision.multZEM1() * static_cast(fillRawZDC), - collision.multZEM2() * static_cast(fillRawZDC), - collision.multZPA() * static_cast(fillRawZDC), - collision.multZPC() * static_cast(fillRawZDC)); + if constexpr (requires { collision.mcCollisionId(); }) { // check if MC information is available and if so fill labels + strangeCollLabels(collision.mcCollisionId()); + } + + if constexpr (requires { collision.centFT0C(); }) { // check if we are in Run 3 + float centrality = collision.centFT0C(); + if (qaCentrality) { + auto hRawCentrality = histos.get(HIST("hRawCentrality")); + centrality = hRawCentrality->GetBinContent(hRawCentrality->FindBin(collision.multFT0C())); + } + + strangeCents(collision.centFT0M(), collision.centFT0A(), + centrality, collision.centFV0A(), collision.centFT0CVariant1(), + collision.centMFT(), collision.centNGlobal()); + strangeEvSels(collision.sel8(), collision.selection_raw(), + collision.multFT0A() * static_cast(fillTruncationOptions.fillRawFT0A), + collision.multFT0C() * static_cast(fillTruncationOptions.fillRawFT0C), + collision.multFV0A() * static_cast(fillTruncationOptions.fillRawFV0A), + collision.multFDDA() * static_cast(fillTruncationOptions.fillRawFDDA), + collision.multFDDC() * static_cast(fillTruncationOptions.fillRawFDDC), + collision.multNTracksPVeta1() * static_cast(fillTruncationOptions.fillRawNTracksEta1), + collision.multPVTotalContributors() * static_cast(fillTruncationOptions.fillRawNTracksForCorrelation), + collision.multNTracksGlobal() * static_cast(fillTruncationOptions.fillRawNTracksForCorrelation), + collision.multNTracksITSTPC() * static_cast(fillTruncationOptions.fillRawNTracksForCorrelation), + collision.multAllTracksTPCOnly() * static_cast(fillTruncationOptions.fillRawNTracksForCorrelation), + collision.multAllTracksITSTPC() * static_cast(fillTruncationOptions.fillRawNTracksForCorrelation), + collision.multZNA() * static_cast(fillTruncationOptions.fillRawZDC), + collision.multZNC() * static_cast(fillTruncationOptions.fillRawZDC), + collision.multZEM1() * static_cast(fillTruncationOptions.fillRawZDC), + collision.multZEM2() * static_cast(fillTruncationOptions.fillRawZDC), + collision.multZPA() * static_cast(fillTruncationOptions.fillRawZDC), + collision.multZPC() * static_cast(fillTruncationOptions.fillRawZDC), + collision.trackOccupancyInTimeRange(), + collision.ft0cOccupancyInTimeRange(), + // UPC info + gapSide, + totalFT0AmplitudeA, totalFT0AmplitudeC, totalFV0AmplitudeA, + totalFDDAmplitudeA, totalFDDAmplitudeC, + energyCommonZNA, energyCommonZNC, + // Collision flags + collision.flags(), + collision.alias_raw(), + collision.rct_raw()); + } else { // We are in Run 2 + strangeCentsRun2(collision.centRun2V0M(), collision.centRun2V0A(), + collision.centRun2SPDTracklets(), collision.centRun2SPDClusters()); + strangeEvSelsRun2(collision.sel8(), collision.sel7(), collision.selection_raw(), + collision.multFT0A() * static_cast(fillTruncationOptions.fillRawFT0A), + collision.multFT0C() * static_cast(fillTruncationOptions.fillRawFT0C), + collision.multFV0A() * static_cast(fillTruncationOptions.fillRawFV0A), + collision.multFV0C() * static_cast(fillTruncationOptions.fillRawFV0C), + collision.multFDDA() * static_cast(fillTruncationOptions.fillRawFDDA), + collision.multFDDC() * static_cast(fillTruncationOptions.fillRawFDDC), + bc.spdClustersL0() * static_cast(fillTruncationOptions.fillRawSPDclsL0Run2), + bc.spdClustersL1() * static_cast(fillTruncationOptions.fillRawSPDclsL1Run2), + collision.multNTracksPVeta1() * static_cast(fillTruncationOptions.fillRawNTracksEta1), + collision.multTracklets() * static_cast(fillTruncationOptions.fillRawTrackletsRun2), + -1, /* dummy number of PV contribs total while waiting for the multiplicity task to produce it */ + -1, /* dummy global track multiplicities while waiting for the multiplicity task to produce it */ + -1, /* dummy track multiplicities, PV contribs, no eta cut while waiting for the multiplicity task to produce it */ + -1, /* dummy TPConly track multiplicities, all, no eta cut while waiting for the multiplicity task to produce it */ + -1, /* dummy ITSTPC track multiplicities, all, no eta cut waiting for the multiplicity task to produce it */ + collision.multZNA() * static_cast(fillTruncationOptions.fillRawZDC), + collision.multZNC() * static_cast(fillTruncationOptions.fillRawZDC), + collision.multZEM1() * static_cast(fillTruncationOptions.fillRawZDC), + collision.multZEM2() * static_cast(fillTruncationOptions.fillRawZDC), + collision.multZPA() * static_cast(fillTruncationOptions.fillRawZDC), + collision.multZPC() * static_cast(fillTruncationOptions.fillRawZDC), + collision.alias_raw()); } } - for (int i = 0; i < V0Table_thisColl.size(); i++) - v0collref(strangeColl.lastIndex()); - for (int i = 0; i < CascTable_thisColl.size(); i++) - casccollref(strangeColl.lastIndex()); - for (int i = 0; i < KFCascTable_thisColl.size(); i++) - kfcasccollref(strangeColl.lastIndex()); - for (int i = 0; i < TraCascTable_thisColl.size(); i++) - tracasccollref(strangeColl.lastIndex()); + for (const auto& v0 : V0Table_thisColl) + V0CollIndices[v0.globalIndex()] = strangeColl.lastIndex(); + for (const auto& casc : CascTable_thisColl) + CascadeCollIndices[casc.globalIndex()] = strangeColl.lastIndex(); + for (const auto& casc : KFCascTable_thisColl) + KFCascadeCollIndices[casc.globalIndex()] = strangeColl.lastIndex(); + for (const auto& casc : TraCascTable_thisColl) + TraCascadeCollIndices[casc.globalIndex()] = strangeColl.lastIndex(); + } + + // +-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+ + // populate references, including those that might not be assigned + for (const auto& v0 : V0s) { + v0collref(V0CollIndices[v0.globalIndex()]); + } + for (const auto& casc : Cascades) { + casccollref(CascadeCollIndices[casc.globalIndex()]); + } + for (const auto& casc : KFCascades) { + kfcasccollref(KFCascadeCollIndices[casc.globalIndex()]); + } + for (const auto& casc : TraCascades) { + tracasccollref(TraCascadeCollIndices[casc.globalIndex()]); } } - void processCollisionsMC(soa::Join const& collisions, soa::Join const& V0s, soa::Join const& Cascades, aod::KFCascDatas const& KFCascades, aod::TraCascDatas const& TraCascades, aod::BCsWithTimestamps const&, soa::Join const& mcCollisions, aod::McParticles const&) + // master function to process a collision + template + void populateMCCollisionTable(mccoll const& mcCollisions, mcparts const& mcParticlesEntireTable) { // ______________________________________________ // fill all MC collisions, correlate via index later on for (const auto& mccollision : mcCollisions) { - strangeMCColl(mccollision.posX(), mccollision.posY(), mccollision.posZ(), mccollision.impactParameter()); + const uint64_t mcCollIndex = mccollision.globalIndex(); + auto mcParticles = mcParticlesEntireTable.sliceBy(mcParticlePerMcCollision, mcCollIndex); + + // count total MC multiplicity in generated collision + // reproduces what is done here: + // https://github.com/AliceO2Group/O2Physics/blob/master/Common/TableProducer/multiplicityTable.cxx#L654 + int totalMult = 0; + for (const auto& mcPart : mcParticles) { + if (!mcPart.isPhysicalPrimary()) { + continue; + } + + auto charge = 0.; + auto* p = pdg->GetParticle(mcPart.pdgCode()); + if (p != nullptr) { + charge = p->Charge(); + } + if (std::abs(charge) < 1e-3) { + continue; // reject neutral particles in counters + } + totalMult++; + } + + strangeMCColl(mccollision.posX(), mccollision.posY(), mccollision.posZ(), + mccollision.impactParameter(), mccollision.eventPlaneAngle(), mccollision.generatorsID()); strangeMCMults(mccollision.multMCFT0A(), mccollision.multMCFT0C(), mccollision.multMCNParticlesEta05(), mccollision.multMCNParticlesEta08(), - mccollision.multMCNParticlesEta10()); + mccollision.multMCNParticlesEta10(), + totalMult); } + } - // ______________________________________________ - for (const auto& collision : collisions) { - const uint64_t collIdx = collision.globalIndex(); + void processCollisionsRun3(soa::Join const& collisions, aod::V0Datas const& V0s, aod::CascDatas const& Cascades, aod::KFCascDatas const& KFCascades, aod::TraCascDatas const& TraCascades, aod::BCsWithTimestamps const& bcs) + { + populateCollisionTables(collisions, collisions, V0s, Cascades, KFCascades, TraCascades, bcs); + } - float centrality = collision.centFT0C(); - if (qaCentrality) { - auto hRawCentrality = histos.get(HIST("hRawCentrality")); - centrality = hRawCentrality->GetBinContent(hRawCentrality->FindBin(collision.multFT0C())); - } + void processCollisionsRun3WithUD(soa::Join const& collisions, aod::V0Datas const& V0s, aod::CascDatas const& Cascades, aod::KFCascDatas const& KFCascades, aod::TraCascDatas const& TraCascades, aod::BCsWithTimestamps const& bcs, UDCollisionsFull const& udCollisions) + { + populateCollisionTables(collisions, udCollisions, V0s, Cascades, KFCascades, TraCascades, bcs); + } - auto V0Table_thisColl = V0s.sliceBy(V0perCollision, collIdx); - auto CascTable_thisColl = Cascades.sliceBy(CascperCollision, collIdx); - auto KFCascTable_thisColl = KFCascades.sliceBy(KFCascperCollision, collIdx); - auto TraCascTable_thisColl = TraCascades.sliceBy(TraCascperCollision, collIdx); - bool strange = V0Table_thisColl.size() > 0 || - CascTable_thisColl.size() > 0 || - KFCascTable_thisColl.size() > 0 || - TraCascTable_thisColl.size() > 0; - // casc table sliced - if (strange || fillEmptyCollisions) { - strangeColl(collision.posX(), collision.posY(), collision.posZ()); - strangeCollLabels(collision.mcCollisionId()); - strangeCents(collision.centFT0M(), collision.centFT0A(), - centrality, collision.centFV0A()); - strangeEvSels(collision.sel8(), collision.selection_raw()); - auto bc = collision.bc_as(); - strangeStamps(bc.runNumber(), bc.timestamp()); - - if (fillRawFT0C || fillRawFT0C || fillRawFV0A || fillRawNTracksEta1 || fillRawZDC) { - strangeRawCents(collision.multFT0A() * static_cast(fillRawFT0A), - collision.multFT0C() * static_cast(fillRawFT0C), - collision.multFV0A() * static_cast(fillRawFV0A), - collision.multNTracksPVeta1() * static_cast(fillRawNTracksEta1), - collision.multPVTotalContributors() * static_cast(fillRawNTracksForCorrelation), - collision.multNTracksGlobal() * static_cast(fillRawNTracksForCorrelation), - collision.multNTracksITSTPC() * static_cast(fillRawNTracksForCorrelation), - collision.multAllTracksTPCOnly() * static_cast(fillRawNTracksForCorrelation), - collision.multAllTracksITSTPC() * static_cast(fillRawNTracksForCorrelation), - collision.multZNA() * static_cast(fillRawZDC), - collision.multZNC() * static_cast(fillRawZDC), - collision.multZEM1() * static_cast(fillRawZDC), - collision.multZEM2() * static_cast(fillRawZDC), - collision.multZPA() * static_cast(fillRawZDC), - collision.multZPC() * static_cast(fillRawZDC)); - } - } - for (int i = 0; i < V0Table_thisColl.size(); i++) - v0collref(strangeColl.lastIndex()); - for (int i = 0; i < CascTable_thisColl.size(); i++) - casccollref(strangeColl.lastIndex()); - for (int i = 0; i < KFCascTable_thisColl.size(); i++) - kfcasccollref(strangeColl.lastIndex()); - for (int i = 0; i < TraCascTable_thisColl.size(); i++) - tracasccollref(strangeColl.lastIndex()); - - // populate MC collision references - for (const auto& v0 : V0Table_thisColl) { - uint32_t indMCColl = -1; - if (v0.has_mcParticle()) { - auto mcParticle = v0.mcParticle(); - indMCColl = mcParticle.mcCollisionId(); - } - v0mccollref(indMCColl); - } - for (const auto& casc : CascTable_thisColl) { - uint32_t indMCColl = -1; - if (casc.has_mcParticle()) { - auto mcParticle = casc.mcParticle(); - indMCColl = mcParticle.mcCollisionId(); - } - cascmccollref(indMCColl); - } - } + void processCollisionsRun3WithMC(soa::Join const& collisions, soa::Join const& V0s, soa::Join const& /*V0MCCores*/, soa::Join const& Cascades, aod::KFCascDatas const& KFCascades, aod::TraCascDatas const& TraCascades, aod::BCsWithTimestamps const& bcs, soa::Join const& mcCollisions, aod::McParticles const& mcParticles) + { + populateMCCollisionTable(mcCollisions, mcParticles); + populateCollisionTables(collisions, collisions, V0s, Cascades, KFCascades, TraCascades, bcs); + } + + void processCollisionsRun3WithUDWithMC(soa::Join const& collisions, soa::Join const& V0s, soa::Join const& /*V0MCCores*/, soa::Join const& Cascades, aod::KFCascDatas const& KFCascades, aod::TraCascDatas const& TraCascades, aod::BCsWithTimestamps const& bcs, UDCollisionsFull const& udCollisions, soa::Join const& mcCollisions, aod::McParticles const& mcParticles) + { + populateMCCollisionTable(mcCollisions, mcParticles); + populateCollisionTables(collisions, udCollisions, V0s, Cascades, KFCascades, TraCascades, bcs); + } + + void processCollisionsRun2(soa::Join const& collisions, aod::V0Datas const& V0s, aod::CascDatas const& Cascades, aod::KFCascDatas const& KFCascades, aod::TraCascDatas const& TraCascades, BCsWithTimestampsAndRun2Infos const& bcs) + { + populateCollisionTables(collisions, collisions, V0s, Cascades, KFCascades, TraCascades, bcs); + } + + void processCollisionsRun2WithMC(soa::Join const& collisions, soa::Join const& V0s, soa::Join const& /*V0MCCores*/, soa::Join const& Cascades, aod::KFCascDatas const& KFCascades, aod::TraCascDatas const& TraCascades, BCsWithTimestampsAndRun2Infos const& bcs, soa::Join const& mcCollisions, aod::McParticles const& mcParticles) + { + populateMCCollisionTable(mcCollisions, mcParticles); + populateCollisionTables(collisions, collisions, V0s, Cascades, KFCascades, TraCascades, bcs); } void processTrackExtrasV0sOnly(aod::V0Datas const& V0s, TracksWithExtra const& tracksExtra) @@ -432,7 +666,7 @@ struct strangederivedbuilder { // Figure out the numbering of the new tracks table // assume filling per order int nTracks = 0; - for (int i = 0; i < trackMap.size(); i++) { + for (int i = 0; i < static_cast(trackMap.size()); i++) { if (trackMap[i] >= 0) { trackMap[i] = nTracks++; } @@ -449,22 +683,29 @@ struct strangederivedbuilder { // circle back and populate actual DauTrackExtra table for (auto const& tr : tracksExtra) { if (trackMap[tr.globalIndex()] >= 0) { - dauTrackExtras(tr.detectorMap(), tr.itsClusterSizes(), - tr.tpcNClsFound(), tr.tpcNClsCrossedRows()); + dauTrackExtras(tr.itsChi2NCl(), + tr.tpcChi2NCl(), + tr.detectorMap(), + tr.itsClusterSizes(), + tr.tpcNClsFindable(), + tr.tpcNClsFindableMinusFound(), + tr.tpcNClsFindableMinusCrossedRows(), + tr.tpcNClsShared()); } } // done! } - void processTrackExtras(aod::V0Datas const& V0s, aod::CascDatas const& Cascades, aod::KFCascDatas const& KFCascades, aod::TraCascDatas const& TraCascades, TracksWithExtra const& tracksExtra, aod::V0s const&) + template + void fillTrackExtras(V0Datas const& V0s, CascDatas const& Cascades, KFCascDatas const& KFCascades, TraCascDatas const& TraCascades, tracksWithExtra const& tracksExtra) { std::vector trackMap(tracksExtra.size(), -1); // index -1: not used //__________________________________________________ // mark tracks that belong to V0s for (auto const& v0 : V0s) { - auto const& posTrack = v0.posTrack_as(); - auto const& negTrack = v0.negTrack_as(); + auto const& posTrack = v0.template posTrack_as(); + auto const& negTrack = v0.template negTrack_as(); trackMap[posTrack.globalIndex()] = 0; trackMap[negTrack.globalIndex()] = 0; } @@ -472,9 +713,9 @@ struct strangederivedbuilder { //__________________________________________________ // index tracks that belong to CascDatas for (auto const& casc : Cascades) { - auto bachTrack = casc.bachelor_as(); - auto posTrack = casc.posTrack_as(); - auto negTrack = casc.negTrack_as(); + auto bachTrack = casc.template bachelor_as(); + auto posTrack = casc.template posTrack_as(); + auto negTrack = casc.template negTrack_as(); trackMap[posTrack.globalIndex()] = 0; trackMap[negTrack.globalIndex()] = 0; trackMap[bachTrack.globalIndex()] = 0; @@ -482,9 +723,9 @@ struct strangederivedbuilder { //__________________________________________________ // index tracks that belong to KFCascDatas for (auto const& casc : KFCascades) { - auto bachTrack = casc.bachelor_as(); - auto posTrack = casc.posTrack_as(); - auto negTrack = casc.negTrack_as(); + auto bachTrack = casc.template bachelor_as(); + auto posTrack = casc.template posTrack_as(); + auto negTrack = casc.template negTrack_as(); trackMap[posTrack.globalIndex()] = 0; trackMap[negTrack.globalIndex()] = 0; trackMap[bachTrack.globalIndex()] = 0; @@ -492,10 +733,10 @@ struct strangederivedbuilder { //__________________________________________________ // index tracks that belong to TraCascDatas for (auto const& casc : TraCascades) { - auto bachTrack = casc.bachelor_as(); - auto posTrack = casc.posTrack_as(); - auto negTrack = casc.negTrack_as(); - auto strangeTrack = casc.strangeTrack_as(); + auto bachTrack = casc.template bachelor_as(); + auto posTrack = casc.template posTrack_as(); + auto negTrack = casc.template negTrack_as(); + auto strangeTrack = casc.template strangeTrack_as(); trackMap[posTrack.globalIndex()] = 0; trackMap[negTrack.globalIndex()] = 0; trackMap[bachTrack.globalIndex()] = 0; @@ -505,7 +746,7 @@ struct strangederivedbuilder { // Figure out the numbering of the new tracks table // assume filling per order int nTracks = 0; - for (int i = 0; i < trackMap.size(); i++) { + for (int i = 0; i < static_cast(trackMap.size()); i++) { if (trackMap[i] >= 0) { trackMap[i] = nTracks++; } @@ -513,17 +754,17 @@ struct strangederivedbuilder { //__________________________________________________ // populate track references for (auto const& v0 : V0s) { - auto const& posTrack = v0.posTrack_as(); - auto const& negTrack = v0.negTrack_as(); + auto const& posTrack = v0.template posTrack_as(); + auto const& negTrack = v0.template negTrack_as(); v0Extras(trackMap[posTrack.globalIndex()], trackMap[negTrack.globalIndex()]); // joinable with V0Datas } //__________________________________________________ // populate track references for (auto const& casc : Cascades) { - auto bachTrack = casc.bachelor_as(); - auto posTrack = casc.posTrack_as(); - auto negTrack = casc.negTrack_as(); + auto bachTrack = casc.template bachelor_as(); + auto posTrack = casc.template posTrack_as(); + auto negTrack = casc.template negTrack_as(); cascExtras(trackMap[posTrack.globalIndex()], trackMap[negTrack.globalIndex()], trackMap[bachTrack.globalIndex()]); // joinable with CascDatas @@ -531,37 +772,70 @@ struct strangederivedbuilder { //__________________________________________________ // populate track references for (auto const& casc : TraCascades) { - auto strangeTrack = casc.strangeTrack_as(); + auto strangeTrack = casc.template strangeTrack_as(); straTrackExtras(trackMap[strangeTrack.globalIndex()]); // joinable with TraCascDatas } //__________________________________________________ // circle back and populate actual DauTrackExtra table for (auto const& tr : tracksExtra) { if (trackMap[tr.globalIndex()] >= 0) { - dauTrackExtras(tr.detectorMap(), tr.itsClusterSizes(), - tr.tpcNClsFound(), tr.tpcNClsCrossedRows()); - - // round if requested - if (roundNSigmaVariables) { - dauTrackTPCPIDs(tr.tpcSignal(), - roundToPrecision(tr.tpcNSigmaEl(), precisionNSigmas), - roundToPrecision(tr.tpcNSigmaPi(), precisionNSigmas), - roundToPrecision(tr.tpcNSigmaKa(), precisionNSigmas), - roundToPrecision(tr.tpcNSigmaPr(), precisionNSigmas), - roundToPrecision(tr.tpcNSigmaHe(), precisionNSigmas)); - } else { - dauTrackTPCPIDs(tr.tpcSignal(), tr.tpcNSigmaEl(), - tr.tpcNSigmaPi(), tr.tpcNSigmaKa(), - tr.tpcNSigmaPr(), tr.tpcNSigmaHe()); + dauTrackExtras(tr.itsChi2NCl(), + tr.tpcChi2NCl(), + tr.detectorMap(), + tr.itsClusterSizes(), + tr.tpcNClsFindable(), + tr.tpcNClsFindableMinusFound(), + tr.tpcNClsFindableMinusCrossedRows(), + tr.tpcNClsShared()); + + // _________________________________________ + // if the table has MC info + if constexpr (requires { tr.mcParticle(); }) { + // do your thing with the mcParticleIds only in case the table has the MC info + dauTrackMCIds(tr.mcParticleId()); // joinable with dauTrackExtras } - // populate daughter-level TOF information - dauTrackTOFPIDs(tr.tofSignal(), tr.tofEvTime(), tr.length()); + if constexpr (requires { tr.tpcNSigmaEl(); }) { + if (roundNSigmaVariables) { // round if requested + dauTrackTPCPIDs(tr.tpcSignal(), + roundToPrecision(tr.tpcNSigmaEl(), precisionNSigmas), + roundToPrecision(tr.tpcNSigmaPi(), precisionNSigmas), + roundToPrecision(tr.tpcNSigmaKa(), precisionNSigmas), + roundToPrecision(tr.tpcNSigmaPr(), precisionNSigmas), + roundToPrecision(tr.tpcNSigmaHe(), precisionNSigmas)); + } else { + dauTrackTPCPIDs(tr.tpcSignal(), tr.tpcNSigmaEl(), + tr.tpcNSigmaPi(), tr.tpcNSigmaKa(), + tr.tpcNSigmaPr(), tr.tpcNSigmaHe()); + } + // populate daughter-level TOF information + dauTrackTOFPIDs(tr.tofSignal(), tr.tofEvTime(), tr.length()); + } else { + // populate with empty fully-compatible Nsigmas if no corresponding table available + dauTrackTPCPIDs(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); + dauTrackTOFPIDs(0.0f, 0.0f, 0.0f); + } } } // done! } + void processTrackExtras(aod::V0Datas const& V0s, aod::CascDatas const& Cascades, aod::KFCascDatas const& KFCascades, aod::TraCascDatas const& TraCascades, soa::Join const& tracksExtra, aod::V0s const&) + { + fillTrackExtras(V0s, Cascades, KFCascades, TraCascades, tracksExtra); + } + + // no TPC services + void processTrackExtrasNoPID(aod::V0Datas const& V0s, aod::CascDatas const& Cascades, aod::KFCascDatas const& KFCascades, aod::TraCascDatas const& TraCascades, soa::Join const& tracksExtra, aod::V0s const&) + { + fillTrackExtras(V0s, Cascades, KFCascades, TraCascades, tracksExtra); + } + + void processTrackExtrasMC(aod::V0Datas const& V0s, aod::CascDatas const& Cascades, aod::KFCascDatas const& KFCascades, aod::TraCascDatas const& TraCascades, soa::Join const& tracksExtra, aod::V0s const&) + { + fillTrackExtras(V0s, Cascades, KFCascades, TraCascades, tracksExtra); + } + void processStrangeMothers(soa::Join const& V0s, soa::Join const& Cascades, aod::McParticles const& mcParticles) { std::vector motherReference(mcParticles.size(), -1); // index -1: not used / no reference @@ -578,7 +852,7 @@ struct strangederivedbuilder { // Figure out the numbering of the new mcMother table // assume filling per order int nParticles = 0; - for (int i = 0; i < motherReference.size(); i++) { + for (int i = 0; i < static_cast(motherReference.size()); i++) { if (motherReference[i] >= 0) { motherReference[i] = nParticles++; // count particles of interest } @@ -651,7 +925,7 @@ struct strangederivedbuilder { static_for<0, nSpecies - 1>([&](auto i) { constexpr int index = i.value; if (mcp.pdgCode() == particlePDGCodes[index] && bitcheck(enabledBits, index)) { - histos.fill(HIST("hGen") + HIST(particleNamesConstExpr[index]), mcp.pt()); + histos.fill(HIST("hGenerated") + HIST(particleNamesConstExpr[index]), mcp.pt()); } }); } @@ -681,7 +955,7 @@ struct strangederivedbuilder { static_for<0, nSpecies - 1>([&](auto i) { constexpr int index = i.value; if (mcp.pdgCode() == particlePDGCodes[index] && bitcheck(enabledBits, index)) { - histos.fill(HIST("h2dGen") + HIST(particleNamesConstExpr[index]), bestCentrality, mcp.pt()); + histos.fill(HIST("h2dGenerated") + HIST(particleNamesConstExpr[index]), bestCentrality, mcp.pt()); } }); } @@ -704,7 +978,7 @@ struct strangederivedbuilder { const uint64_t mcCollIndex = mcCollision.globalIndex(); // use one of the generated histograms as the bin finder - auto hBinFinder = histos.get(HIST("h2dGenK0Short")); + auto hBinFinder = histos.get(HIST("h2dGeneratedK0Short")); auto mcParticles = mcParticlesEntireTable.sliceBy(mcParticlePerMcCollision, mcCollIndex); for (auto& mcp : mcParticles) { @@ -748,7 +1022,13 @@ struct strangederivedbuilder { } void processFT0CQVectorsLF(soa::Join::iterator const& collision) { - StraFT0CQVs(std::cos(2 * collision.psiFT0C()), std::sin(2 * collision.psiFT0C()), 1.f); + StraFT0CQVs(collision.qFT0C() * std::cos(2 * collision.psiFT0C()), collision.qFT0C() * std::sin(2 * collision.psiFT0C()), collision.qFT0C()); + StraFT0CQVsEv(collision.triggereventep()); + } + void processZDCSP(soa::Join::iterator const& collision) + { + StraZDCSP(collision.triggereventsp(), + collision.psiZDCA(), collision.psiZDCC(), collision.qxZDCA(), collision.qxZDCC(), collision.qyZDCA(), collision.qyZDCC()); } void processFT0MQVectors(soa::Join::iterator const& collision) { @@ -758,23 +1038,81 @@ struct strangederivedbuilder { { StraFV0AQVs(collision.qvecFV0ARe(), collision.qvecFV0AIm(), collision.sumAmplFV0A()); } + void processTPCQVectors(soa::Join::iterator const& collision) + { + StraTPCQVs(collision.qvecBNegRe(), collision.qvecBNegIm(), collision.nTrkBNeg(), collision.qvecBPosRe(), collision.qvecBPosIm(), collision.nTrkBPos()); + } + void processTPCQVectorsLF(soa::Join::iterator const& collision) + { + StraTPCQVs(collision.qTPCL() * std::cos(2 * collision.psiTPCL()), collision.qTPCL() * std::sin(2 * collision.psiTPCL()), collision.qTPCL(), collision.qTPCR() * std::cos(2 * collision.psiTPCR()), collision.qTPCR() * std::sin(2 * collision.psiTPCR()), collision.qTPCR()); + } + + using uint128_t = __uint128_t; + uint128_t combineProngIndices128(uint32_t pos, uint32_t neg, uint32_t bach) + { + return ((static_cast(pos)) << 64) | ((static_cast(neg)) << 32) | (static_cast(bach)); + } + + void processDataframeIDs(aod::Origins const& origins) + { + auto origin = origins.begin(); + straOrigin(origin.dataframeID()); + } + + void processSimulatedZDCNeutrons(soa::Join const& mcCollisions, aod::McParticles const& mcParticlesEntireTable) + { + for (const auto& mccollision : mcCollisions) { + const uint64_t mcCollIndex = mccollision.globalIndex(); + auto mcParticles = mcParticlesEntireTable.sliceBy(mcParticlePerMcCollision, mcCollIndex); + + for (const auto& mcPart : mcParticles) { + if (std::abs(mcPart.pdgCode()) == kNeutron) { // check if it is a neutron or anti-neutron + if (std::abs(mcPart.eta()) > 8.7) { // check if it is within ZDC acceptance + zdcNeutrons(mcPart.pdgCode(), mcPart.statusCode(), mcPart.flags(), + mcPart.vx(), mcPart.vy(), mcPart.vz(), mcPart.vt(), + mcPart.px(), mcPart.py(), mcPart.pz(), mcPart.e()); - PROCESS_SWITCH(strangederivedbuilder, processCollisionsV0sOnly, "Produce collisions (V0s only)", true); - PROCESS_SWITCH(strangederivedbuilder, processCollisions, "Produce collisions (V0s + casc)", true); - PROCESS_SWITCH(strangederivedbuilder, processCollisionsMC, "Produce collisions (V0s + casc)", false); + zdcNeutronsMCCollRefs(mcPart.mcCollisionId()); + } + } + } + } + } + + // debug processing + PROCESS_SWITCH(strangederivedbuilder, processDataframeIDs, "Produce data frame ID tags", false); + + // Run 3: collision processing + PROCESS_SWITCH(strangederivedbuilder, processCollisionsRun3, "Produce collisions (Run 3)", true); + PROCESS_SWITCH(strangederivedbuilder, processCollisionsRun3WithUD, "Produce collisions (Run 3) with UD info", true); + PROCESS_SWITCH(strangederivedbuilder, processCollisionsRun3WithMC, "Produce collisions (Run 3) with MC info", true); + PROCESS_SWITCH(strangederivedbuilder, processCollisionsRun3WithUDWithMC, "Produce collisions (Run 3) with UD + MC info", true); + // Run 2: collision processing + PROCESS_SWITCH(strangederivedbuilder, processCollisionsRun2, "Produce collisions (Run2)", false); + PROCESS_SWITCH(strangederivedbuilder, processCollisionsRun2WithMC, "Produce collisions (Run 2) with MC info", false); + + // detailed information processing PROCESS_SWITCH(strangederivedbuilder, processTrackExtrasV0sOnly, "Produce track extra information (V0s only)", true); PROCESS_SWITCH(strangederivedbuilder, processTrackExtras, "Produce track extra information (V0s + casc)", true); + PROCESS_SWITCH(strangederivedbuilder, processTrackExtrasNoPID, "Produce track extra information (V0s + casc), no PID", false); + PROCESS_SWITCH(strangederivedbuilder, processTrackExtrasMC, "Produce track extra information (V0s + casc)", false); PROCESS_SWITCH(strangederivedbuilder, processStrangeMothers, "Produce tables with mother info for V0s + casc", true); PROCESS_SWITCH(strangederivedbuilder, processCascadeInterlinkTracked, "Produce tables interconnecting cascades", false); PROCESS_SWITCH(strangederivedbuilder, processCascadeInterlinkKF, "Produce tables interconnecting cascades", false); PROCESS_SWITCH(strangederivedbuilder, processPureSimulation, "Produce pure simulated information", true); PROCESS_SWITCH(strangederivedbuilder, processReconstructedSimulation, "Produce reco-ed simulated information", true); PROCESS_SWITCH(strangederivedbuilder, processBinnedGenerated, "Produce binned generated information", false); + PROCESS_SWITCH(strangederivedbuilder, processSimulatedZDCNeutrons, "Produce generated neutrons (within ZDC acceptance) table for UPC analysis", false); + + // event plane information PROCESS_SWITCH(strangederivedbuilder, processFT0AQVectors, "Produce FT0A Q-vectors table", false); PROCESS_SWITCH(strangederivedbuilder, processFT0CQVectors, "Produce FT0C Q-vectors table", false); PROCESS_SWITCH(strangederivedbuilder, processFT0CQVectorsLF, "Produce FT0C Q-vectors table using LF temporary calibration", false); PROCESS_SWITCH(strangederivedbuilder, processFT0MQVectors, "Produce FT0M Q-vectors table", false); PROCESS_SWITCH(strangederivedbuilder, processFV0AQVectors, "Produce FV0A Q-vectors table", false); + PROCESS_SWITCH(strangederivedbuilder, processTPCQVectors, "Produce TPC Q-vectors table", false); + PROCESS_SWITCH(strangederivedbuilder, processTPCQVectorsLF, "Produce TPC Q-vectors table using LF temporary calibration", false); + PROCESS_SWITCH(strangederivedbuilder, processZDCSP, "Produce ZDC SP table", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/TableProducer/Strangeness/strangenessbuilder.cxx b/PWGLF/TableProducer/Strangeness/strangenessbuilder.cxx new file mode 100644 index 00000000000..553a0f74e36 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/strangenessbuilder.cxx @@ -0,0 +1,2347 @@ +// 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 strangenessbuilder.cxx +/// \brief Strangeness builder task +/// \author David Dobrigkeit Chinellato (david.dobrigkeit.chinellato@cern.ch) +// ======================== +// +// This task produces all tables that may be necessary for +// strangeness analyses. A single device is provided to +// ensure better computing resource (memory) management. +// +// process functions: +// +// -- processRealData[Run2] .........: use this OR processMonteCarlo but NOT both +// -- processMonteCarlo[Run2] .......: use this OR processRealData but NOT both +// +// Most important configurables: +// -- enabledTables ......: key control bools to decide which tables to generate +// task will adapt algorithm to spare / spend CPU accordingly +// -- mc_findableMode ....: 0: only found (default), 1: add findable to found, 2: all findable +// When using findables, refer to FoundTag bools for checking if found +// -- v0builderopts ......: V0-specific building options (topological, etc) +// -- cascadebuilderopts .: cascade-specific building options (topological, etc) + +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/PIDResponse.h" +#include "TableHelper.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/Utils/strangenessBuilderHelper.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "Common/Core/TPCVDriftManager.h" + +using namespace o2; +using namespace o2::framework; + +static constexpr int nParameters = 1; +static const std::vector tableNames{ + "V0Indices", //.0 (standard analysis: V0Cores) + "V0CoresBase", //.1 (standard analyses: main table) + "V0Covs", //.2 (joinable with V0Cores) + "CascIndices", //.3 (standard analyses: CascData) + "KFCascIndices", //.4 (standard analyses: KFCascData) + "TraCascIndices", //.5 (standard analyses: TraCascData) + "StoredCascCores", //.6 (standard analyses: CascData, main table) + "StoredKFCascCores", //.7 (standard analyses: KFCascData, main table) + "StoredTraCascCores", //.8 (standard analyses: TraCascData, main table) + "CascCovs", //.9 (joinable with CascData) + "KFCascCovs", //.10 (joinable with KFCascData) + "TraCascCovs", //.11 (joinable with TraCascData) + "V0TrackXs", //.12 (joinable with V0Data) + "CascTrackXs", //.13 (joinable with CascData) + "CascBBs", //.14 (standard, bachelor-baryon vars) + "V0DauCovs", //.15 (requested: tracking studies) + "V0DauCovIUs", //.16 (requested: tracking studies) + "V0TraPosAtDCAs", //.17 (requested: tracking studies) + "V0TraPosAtIUs", //.18 (requested: tracking studies) + "V0Ivanovs", //.19 (requested: tracking studies) + "McV0Labels", //.20 (MC/standard analysis) + "V0MCCores", //.21 (MC, all generated desired V0s) + "V0CoreMCLabels", //.22 (MC, refs V0Cores to V0MCCores) + "V0MCCollRefs", //.23 (MC, refs V0MCCores to McCollisions) + "McCascLabels", //.24 (MC/standard analysis) + "McKFCascLabels", //.25 (MC, refs KFCascCores to CascMCCores) + "McTraCascLabels", //.26 (MC, refs TraCascCores to CascMCCores) + "McCascBBTags", //.27 (MC, joinable with CascCores, tags reco-ed) + "CascMCCores", //.28 (MC, all generated desired cascades) + "CascCoreMCLabels", //.29 (MC, refs CascCores to CascMCCores) + "CascMCCollRefs", // 30 (MC, refs CascMCCores to McCollisions) + "CascToTraRefs", //.31 (interlink CascCores -> TraCascCores) + "CascToKFRefs", //.32 (interlink CascCores -> KFCascCores) + "TraToCascRefs", //.33 (interlink TraCascCores -> CascCores) + "KFToCascRefs", //.34 (interlink KFCascCores -> CascCores) + "V0FoundTags", //.35 (tags found vs findable V0s in findable mode) + "CascFoundTags" //.36 (tags found vs findable Cascades in findable mode) +}; + +static constexpr int nTablesConst = 37; + +static const std::vector parameterNames{"enable"}; +static const int defaultParameters[nTablesConst][nParameters]{ + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, // index 9 + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, // index 19 + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, // index 29 + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}}; + +// use parameters + cov mat non-propagated, aux info + (extension propagated) +using FullTracksExt = soa::Join; +using FullTracksExtIU = soa::Join; +using FullTracksExtLabeled = soa::Join; +using FullTracksExtLabeledIU = soa::Join; +using TracksWithExtra = soa::Join; + +// For dE/dx association in pre-selection +using TracksExtraWithPID = soa::Join; + +struct StrangenessBuilder { + // helper object + o2::pwglf::strangenessBuilderHelper straHelper; + + // table index : match order above + enum tableIndex { kV0Indices = 0, + kV0CoresBase, + kV0Covs, + kCascIndices, + kKFCascIndices, + kTraCascIndices, + kStoredCascCores, + kStoredKFCascCores, + kStoredTraCascCores, + kCascCovs, + kKFCascCovs, + kTraCascCovs, + kV0TrackXs, + kCascTrackXs, + kCascBBs, + kV0DauCovs, + kV0DauCovIUs, + kV0TraPosAtDCAs, + kV0TraPosAtIUs, + kV0Ivanovs, + kMcV0Labels, + kV0MCCores, + kV0CoreMCLabels, + kV0MCCollRefs, + kMcCascLabels, + kMcKFCascLabels, + kMcTraCascLabels, + kMcCascBBTags, + kCascMCCores, + kCascCoreMCLabels, + kCascMCCollRefs, + kCascToTraRefs, + kCascToKFRefs, + kTraToCascRefs, + kKFToCascRefs, + kV0FoundTags, + kCascFoundTags, + nTables }; + + struct : ProducesGroup { + //__________________________________________________ + // V0 tables + Produces v0indices; // standard part of V0Datas + Produces v0cores; // standard part of V0Datas + Produces v0covs; // for decay chain reco + + //__________________________________________________ + // cascade tables + Produces cascidx; // standard part of CascDatas + Produces kfcascidx; // standard part of KFCascDatas + Produces tracascidx; // standard part of TraCascDatas + Produces cascdata; // standard part of CascDatas + Produces kfcascdata; // standard part of KFCascDatas + Produces tracascdata; // standard part of TraCascDatas + Produces casccovs; // for decay chain reco + Produces kfcasccovs; // for decay chain reco + Produces tracasccovs; // for decay chain reco + + //__________________________________________________ + // interlink tables + Produces v0dataLink; // de-refs V0s -> V0Data + Produces cascdataLink; // de-refs Cascades -> CascData + Produces kfcascdataLink; // de-refs Cascades -> KFCascData + Produces tracascdataLink; // de-refs Cascades -> TraCascData + + //__________________________________________________ + // secondary auxiliary tables + Produces v0trackXs; // for decay chain reco + Produces cascTrackXs; // for decay chain reco + + //__________________________________________________ + // further auxiliary / optional if desired + Produces cascbb; + Produces v0daucovs; // covariances of daughter tracks + Produces v0daucovIUs; // covariances of daughter tracks + Produces v0dauPositions; // auxiliary debug information + Produces v0dauPositionsIU; // auxiliary debug information + Produces v0ivanovs; // information for Marian's tests + + //__________________________________________________ + // MC information: V0 + Produces v0labels; // MC labels for V0s + Produces v0mccores; // mc info storage + Produces v0CoreMCLabels; // interlink V0Cores -> V0MCCores + Produces v0mccollref; // references collisions from V0MCCores + + // MC information: Cascades + Produces casclabels; // MC labels for cascades + Produces kfcasclabels; // MC labels for KF cascades + Produces tracasclabels; // MC labels for tracked cascades + Produces bbtags; // bb tags (inv structure tagging in mc) + Produces cascmccores; // mc info storage + Produces cascCoreMClabels; // interlink CascCores -> CascMCCores + Produces cascmccollrefs; // references MC collisions from MC cascades + + //__________________________________________________ + // cascade interlinks + // FIXME: commented out until strangederivedbuilder adjusted accordingly + // Produces cascToTraRefs; // cascades -> tracked + // Produces cascToKFRefs; // cascades -> KF + // Produces traToCascRefs; // tracked -> cascades + // Produces kfToCascRefs; // KF -> cascades + + //__________________________________________________ + // Findable tags + Produces v0FoundTag; + Produces cascFoundTag; + } products; + + Configurable> enabledTables{"enabledTables", + {defaultParameters[0], nTables, nParameters, tableNames, parameterNames}, + "Produce this table: -1 for autodetect; otherwise, 0/1 is false/true"}; + std::vector mEnabledTables; // Vector of enabled tables + + // CCDB options + struct : ConfigurableGroup { + std::string prefix = "ccdb"; + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + } ccdbConfigurations; + + // first order deduplication implementation + // more algorithms to be added as necessary + Configurable deduplicationAlgorithm{"deduplicationAlgorithm", 1, "0: disabled; 1: best pointing angle wins; 2: best DCA daughters wins; 3: best pointing and best DCA wins"}; + + // V0 buffer for V0s used in cascades: master switch + // exchanges CPU (generate V0s again) with memory (save pre-generated V0s) + Configurable useV0BufferForCascades{"useV0BufferForCascades", false, "store array of V0s for cascades or not. False (default): save RAM, use more CPU; true: save CPU, use more RAM"}; + + Configurable mc_findableMode{"mc_findableMode", 0, "0: disabled; 1: add findable-but-not-found to existing V0s from AO2D; 2: reset V0s and generate only findable-but-not-found"}; + + // V0 building options + struct : ConfigurableGroup { + std::string prefix = "v0BuilderOpts"; + Configurable generatePhotonCandidates{"generatePhotonCandidates", false, "generate gamma conversion candidates (V0s using TPC-only tracks)"}; + Configurable moveTPCOnlyTracks{"moveTPCOnlyTracks", true, "if dealing with TPC-only tracks, move them according to TPC drift / time info"}; + + // baseline conditionals of V0 building + Configurable minCrossedRows{"minCrossedRows", 50, "minimum TPC crossed rows for daughter tracks"}; + Configurable dcanegtopv{"dcanegtopv", .1, "DCA Neg To PV"}; + Configurable dcapostopv{"dcapostopv", .1, "DCA Pos To PV"}; + Configurable v0cospa{"v0cospa", 0.95, "V0 CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0) + Configurable dcav0dau{"dcav0dau", 1.0, "DCA V0 Daughters"}; + Configurable v0radius{"v0radius", 0.9, "v0radius"}; + Configurable maxDaughterEta{"maxDaughterEta", 5.0, "Maximum daughter eta (in abs value)"}; + + // MC builder options + Configurable mc_populateV0MCCoresSymmetric{"mc_populateV0MCCoresSymmetric", false, "populate V0MCCores table for derived data analysis, keep V0MCCores joinable with V0Cores"}; + Configurable mc_populateV0MCCoresAsymmetric{"mc_populateV0MCCoresAsymmetric", true, "populate V0MCCores table for derived data analysis, create V0Cores -> V0MCCores interlink. Saves only labeled V0s."}; + Configurable mc_treatPiToMuDecays{"mc_treatPiToMuDecays", true, "if true, will correctly capture pi -> mu and V0 label will still point to originating V0 decay in those cases. Nota bene: prong info will still be for the muon!"}; + Configurable mc_rapidityWindow{"mc_rapidityWindow", 0.5, "rapidity window to save non-recoed candidates"}; + Configurable mc_addGeneratedK0Short{"mc_addGeneratedK0Short", true, "add V0MCCore entry for generated, not-recoed K0Short"}; + Configurable mc_addGeneratedLambda{"mc_addGeneratedLambda", true, "add V0MCCore entry for generated, not-recoed Lambda"}; + Configurable mc_addGeneratedAntiLambda{"mc_addGeneratedAntiLambda", true, "add V0MCCore entry for generated, not-recoed AntiLambda"}; + Configurable mc_addGeneratedGamma{"mc_addGeneratedGamma", false, "add V0MCCore entry for generated, not-recoed Gamma"}; + Configurable mc_addGeneratedGammaMakeCollinear{"mc_addGeneratedGammaMakeCollinear", true, "when adding findable gammas, mark them as collinear"}; + Configurable mc_findableDetachedV0{"mc_findableDetachedV0", false, "if true, generate findable V0s that have collisionId -1. Caution advised."}; + } v0BuilderOpts; + + // cascade building options + struct : ConfigurableGroup { + std::string prefix = "cascadeBuilderOpts"; + Configurable useCascadeMomentumAtPrimVtx{"useCascadeMomentumAtPrimVtx", false, "use cascade momentum at PV"}; + + // conditionals + Configurable minCrossedRows{"minCrossedRows", 50, "minimum TPC crossed rows for daughter tracks"}; + Configurable dcabachtopv{"dcabachtopv", .05, "DCA Bach To PV"}; + Configurable cascradius{"cascradius", 0.9, "cascradius"}; + Configurable casccospa{"casccospa", 0.95, "casccospa"}; + Configurable dcacascdau{"dcacascdau", 1.0, "DCA cascade Daughters"}; + Configurable lambdaMassWindow{"lambdaMassWindow", .010, "Distance from Lambda mass (does not apply to KF path)"}; + Configurable maxDaughterEta{"maxDaughterEta", 5.0, "Maximum daughter eta (in abs value)"}; + + // KF building specific + Configurable kfTuneForOmega{"kfTuneForOmega", false, "if enabled, take main cascade properties from Omega fit instead of Xi fit (= default)"}; + Configurable kfConstructMethod{"kfConstructMethod", 2, "KF Construct Method"}; + Configurable kfUseV0MassConstraint{"kfUseV0MassConstraint", true, "KF: use Lambda mass constraint"}; + Configurable kfUseCascadeMassConstraint{"kfUseCascadeMassConstraint", false, "KF: use Cascade mass constraint - WARNING: not adequate for inv mass analysis of Xi"}; + Configurable kfDoDCAFitterPreMinimV0{"kfDoDCAFitterPreMinimV0", true, "KF: do DCAFitter pre-optimization before KF fit to include material corrections for V0"}; + Configurable kfDoDCAFitterPreMinimCasc{"kfDoDCAFitterPreMinimCasc", true, "KF: do DCAFitter pre-optimization before KF fit to include material corrections for Xi"}; + + // MC builder options + Configurable mc_populateCascMCCoresSymmetric{"mc_populateCascMCCoresSymmetric", false, "populate CascMCCores table for derived data analysis, keep CascMCCores joinable with CascCores"}; + Configurable mc_populateCascMCCoresAsymmetric{"mc_populateCascMCCoresAsymmetric", true, "populate CascMCCores table for derived data analysis, create CascCores -> CascMCCores interlink. Saves only labeled Cascades."}; + Configurable mc_addGeneratedXiMinus{"mc_addGeneratedXiMinus", true, "add CascMCCore entry for generated, not-recoed XiMinus"}; + Configurable mc_addGeneratedXiPlus{"mc_addGeneratedXiPlus", true, "add CascMCCore entry for generated, not-recoed XiPlus"}; + Configurable mc_addGeneratedOmegaMinus{"mc_addGeneratedOmegaMinus", true, "add CascMCCore entry for generated, not-recoed OmegaMinus"}; + Configurable mc_addGeneratedOmegaPlus{"mc_addGeneratedOmegaPlus", true, "add CascMCCore entry for generated, not-recoed OmegaPlus"}; + Configurable mc_treatPiToMuDecays{"mc_treatPiToMuDecays", true, "if true, will correctly capture pi -> mu and V0 label will still point to originating V0 decay in those cases. Nota bene: prong info will still be for the muon!"}; + Configurable mc_rapidityWindow{"mc_rapidityWindow", 0.5, "rapidity window to save non-recoed candidates"}; + Configurable mc_findableDetachedCascade{"mc_findableDetachedCascade", false, "if true, generate findable cascades that have collisionId -1. Caution advised."}; + } cascadeBuilderOpts; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + + int mRunNumber; + o2::base::MatLayerCylSet* lut = nullptr; + + // for handling TPC-only tracks (photons) + o2::aod::common::TPCVDriftManager mVDriftMgr; + + // for establishing CascData/KFData/TraCascData interlinks + struct { + std::vector cascCoreToCascades; + std::vector kfCascCoreToCascades; + std::vector traCascCoreToCascades; + std::vector cascadeToCascCores; + std::vector cascadeToKFCascCores; + std::vector cascadeToTraCascCores; + } interlinks; + + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + // struct to add abstraction layer between V0s, Cascades and build indices + // desirable for adding extra (findable, etc) V0s, Cascades to built list + struct trackEntry { + int globalId = -1; + int originId = -1; + int mcCollisionId = -1; + int pdgCode = -1; + }; + struct v0Entry { + int globalId = -1; + int collisionId = -1; + int posTrackId = -1; + int negTrackId = -1; + int v0Type = 0; + int pdgCode = 0; // undefined if not MC - useful for faster finding + int particleId = -1; // de-reference the V0 particle if necessary + bool isCollinearV0 = false; + bool found = false; + }; + struct cascadeEntry { + int globalId = -1; + int collisionId = -1; + int v0Id = -1; + int posTrackId = -1; + int negTrackId = -1; + int bachTrackId = -1; + bool found = false; + }; + + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + // Helper struct to contain V0MCCore information prior to filling + struct mcV0info { + int label = -1; + int motherLabel = -1; + int pdgCode = 0; + int pdgCodeMother = 0; + int pdgCodePositive = 0; + int pdgCodeNegative = 0; + int mcCollision = -1; + bool isPhysicalPrimary = false; + int processPositive = -1; + int processNegative = -1; + std::array xyz; + std::array posP; + std::array negP; + std::array momentum; + }; + mcV0info thisInfo; + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + // Helper struct to contain CascMCCore information prior to filling + struct mcCascinfo { + int label; + int motherLabel; + int mcCollision; + int pdgCode; + int pdgCodeMother; + int pdgCodeV0; + int pdgCodePositive; + int pdgCodeNegative; + int pdgCodeBachelor; + bool isPhysicalPrimary; + int processPositive = -1; + int processNegative = -1; + int processBachelor = -1; + std::array xyz; + std::array lxyz; + std::array posP; + std::array negP; + std::array bachP; + std::array momentum; + int mcParticlePositive; + int mcParticleNegative; + int mcParticleBachelor; + }; + mcCascinfo thisCascInfo; + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + std::vector v0List; + std::vector cascadeList; + std::vector sorted_v0; + std::vector sorted_cascade; + + // for tagging V0s used in cascades + std::vector v0sFromCascades; // Vector of v0 candidates used in cascades + std::vector ao2dV0toV0List; // index to relate v0s -> v0List + std::vector v0Map; // index to relate v0List -> v0sFromCascades + + void init(InitContext& context) + { + // setup bookkeeping histogram + auto h = histos.add("hTableBuildingStatistics", "hTableBuildingStatistics", kTH1D, {{nTablesConst, -0.5f, static_cast(nTablesConst)}}); + auto h2 = histos.add("hInputStatistics", "hInputStatistics", kTH1D, {{nTablesConst, -0.5f, static_cast(nTablesConst)}}); + h2->SetTitle("Input table sizes"); + + if (v0BuilderOpts.generatePhotonCandidates.value == true) { + auto hDeduplicationStatistics = histos.add("hDeduplicationStatistics", "hDeduplicationStatistics", kTH1D, {{2, -0.5f, 1.5f}}); + hDeduplicationStatistics->GetXaxis()->SetBinLabel(1, "AO2D V0s"); + hDeduplicationStatistics->GetXaxis()->SetBinLabel(2, "Deduplicated V0s"); + } + + if (mc_findableMode.value > 0) { + // save statistics of findable candidate processing + auto hFindable = histos.add("hFindableStatistics", "hFindableStatistics", kTH1D, {{6, -0.5f, 5.5f}}); + hFindable->SetTitle(Form("Findable mode: %i", static_cast(mc_findableMode.value))); + hFindable->GetXaxis()->SetBinLabel(1, "AO2D V0s"); + hFindable->GetXaxis()->SetBinLabel(2, "V0s to be built"); + hFindable->GetXaxis()->SetBinLabel(3, "V0s with collId -1"); + hFindable->GetXaxis()->SetBinLabel(4, "AO2D Cascades"); + hFindable->GetXaxis()->SetBinLabel(5, "Cascades to be built"); + hFindable->GetXaxis()->SetBinLabel(6, "Cascades with collId -1"); + } + + mRunNumber = 0; + + mEnabledTables.resize(nTables, 0); + + LOGF(info, "Configuring tables to generate"); + auto& workflows = context.services().get(); + + for (int i = 0; i < nTables; i++) { + // adjust bookkeeping histogram + h->GetXaxis()->SetBinLabel(i + 1, tableNames[i].c_str()); + h2->GetXaxis()->SetBinLabel(i + 1, tableNames[i].c_str()); + h->SetBinContent(i + 1, -1); // mark all as disabled to start + + int f = enabledTables->get(tableNames[i].c_str(), "enable"); + if (f == 1) { + mEnabledTables[i] = 1; + } + if (f == -1) { + // autodetect this table in other devices + for (DeviceSpec const& device : workflows.devices) { + // Step 1: check if this device subscribed to the V0data table + for (auto const& input : device.inputs) { + if (device.name.compare("strangenessbuilder-initializer") == 0) + continue; // don't listen to the initializer + if (input.matcher.binding == tableNames[i]) { + LOGF(info, "Device %s has subscribed to %s", device.name, tableNames[i]); + mEnabledTables[i] = 1; + } + } + } + } + } + + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + LOGF(info, " Strangeness builder: basic configuration listing"); + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + + if (doprocessRealData) { + LOGF(info, " ===> process function enabled: processRealData"); + } + if (doprocessRealDataRun2) { + LOGF(info, " ===> process function enabled: processRealDataRun2"); + } + if (doprocessMonteCarlo) { + LOGF(info, " ===> process function enabled: processMonteCarlo"); + } + if (doprocessMonteCarloRun2) { + LOGF(info, " ===> process function enabled: processMonteCarloRun2"); + } + if (mc_findableMode.value == 1) { + LOGF(info, " ===> findable mode 1 is enabled: complement reco-ed with non-found findable"); + } + if (mc_findableMode.value == 2) { + LOGF(info, " ===> findable mode 2 is enabled: re-generate all findable from scratch"); + } + + // list enabled tables + + for (int i = 0; i < nTables; i++) { + // printout to be improved in the future + if (mEnabledTables[i]) { + LOGF(info, " -~> Table enabled: %s", tableNames[i]); + h->SetBinContent(i + 1, 0); // mark enabled + } + } + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + // print base cuts + LOGF(info, "-~> V0 | min crossed rows ..............: %i", v0BuilderOpts.minCrossedRows.value); + LOGF(info, "-~> V0 | DCA pos track to PV ...........: %f", v0BuilderOpts.dcapostopv.value); + LOGF(info, "-~> V0 | DCA neg track to PV ...........: %f", v0BuilderOpts.dcanegtopv.value); + LOGF(info, "-~> V0 | V0 cosine of PA ...............: %f", v0BuilderOpts.v0cospa.value); + LOGF(info, "-~> V0 | DCA between V0 daughters ......: %f", v0BuilderOpts.dcav0dau.value); + LOGF(info, "-~> V0 | V0 2D decay radius ............: %f", v0BuilderOpts.v0radius.value); + LOGF(info, "-~> V0 | Maximum daughter eta ..........: %f", v0BuilderOpts.maxDaughterEta.value); + + LOGF(info, "-~> Cascade | min crossed rows .........: %i", cascadeBuilderOpts.minCrossedRows.value); + LOGF(info, "-~> Cascade | DCA bach track to PV .....: %f", cascadeBuilderOpts.dcabachtopv.value); + LOGF(info, "-~> Cascade | Cascade cosine of PA .....: %f", cascadeBuilderOpts.casccospa.value); + LOGF(info, "-~> Cascade | Cascade daughter DCA .....: %f", cascadeBuilderOpts.dcacascdau.value); + LOGF(info, "-~> Cascade | Cascade radius ...........: %f", cascadeBuilderOpts.cascradius.value); + LOGF(info, "-~> Cascade | Lambda mass window .......: %f", cascadeBuilderOpts.lambdaMassWindow.value); + LOGF(info, "-~> Cascade | Maximum daughter eta .....: %f", cascadeBuilderOpts.maxDaughterEta.value); + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + + ccdb->setURL(ccdbConfigurations.ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + // set V0 parameters in the helper + straHelper.v0selections.minCrossedRows = v0BuilderOpts.minCrossedRows; + straHelper.v0selections.dcanegtopv = v0BuilderOpts.dcanegtopv; + straHelper.v0selections.dcapostopv = v0BuilderOpts.dcapostopv; + straHelper.v0selections.v0cospa = v0BuilderOpts.v0cospa; + straHelper.v0selections.dcav0dau = v0BuilderOpts.dcav0dau; + straHelper.v0selections.v0radius = v0BuilderOpts.v0radius; + straHelper.v0selections.maxDaughterEta = v0BuilderOpts.maxDaughterEta; + + // set cascade parameters in the helper + straHelper.cascadeselections.minCrossedRows = cascadeBuilderOpts.minCrossedRows; + straHelper.cascadeselections.dcabachtopv = cascadeBuilderOpts.dcabachtopv; + straHelper.cascadeselections.cascradius = cascadeBuilderOpts.cascradius; + straHelper.cascadeselections.casccospa = cascadeBuilderOpts.casccospa; + straHelper.cascadeselections.dcacascdau = cascadeBuilderOpts.dcacascdau; + straHelper.cascadeselections.lambdaMassWindow = cascadeBuilderOpts.lambdaMassWindow; + straHelper.cascadeselections.maxDaughterEta = cascadeBuilderOpts.maxDaughterEta; + } + + // for sorting + template + std::vector sort_indices(const std::vector& v, bool doSorting = false) + { + std::vector idx(v.size()); + std::iota(idx.begin(), idx.end(), 0); + if (doSorting) { + // do sorting only if requested (not always necessary) + std::stable_sort(idx.begin(), idx.end(), + [&v](std::size_t i1, std::size_t i2) { return v[i1].collisionId < v[i2].collisionId; }); + } + return idx; + } + + template + bool initCCDB(aod::BCsWithTimestamps const& bcs, TCollisions const& collisions) + { + auto bc = collisions.size() ? collisions.begin().template bc_as() : bcs.begin(); + if (!bcs.size()) { + LOGF(warn, "No BC found, skipping this DF."); + return false; // signal to skip this DF + } + + if (mRunNumber == bc.runNumber()) { + return true; + } + + auto timestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (doprocessRealDataRun2) { + grpo = ccdb->getForTimeStamp(ccdbConfigurations.grpPath, timestamp); + if (!grpo) { + LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConfigurations.grpPath << " of object GRPObject for timestamp " << timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpo); + } else { + grpmag = ccdb->getForTimeStamp(ccdbConfigurations.grpmagPath, timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConfigurations.grpmagPath << " of object GRPMagField for timestamp " << timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + } + // Fetch magnetic field from ccdb for current collision + auto magneticField = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "Retrieved GRP for timestamp " << timestamp << " with magnetic field of " << magneticField << " kG"; + + // Set magnetic field value once known + straHelper.fitter.setBz(magneticField); + + // acquire LUT for this timestamp + LOG(info) << "Loading material look-up table for timestamp: " << timestamp; + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->getForTimeStamp(ccdbConfigurations.lutPath, timestamp)); + o2::base::Propagator::Instance()->setMatLUT(lut); + straHelper.lut = lut; + + LOG(info) << "Fully configured for run: " << bc.runNumber(); + // mmark this run as configured + mRunNumber = bc.runNumber(); + + if (v0BuilderOpts.generatePhotonCandidates.value && v0BuilderOpts.moveTPCOnlyTracks.value) { + // initialize only if needed, avoid unnecessary CCDB calls + mVDriftMgr.init(&ccdb->instance()); + mVDriftMgr.update(timestamp); + } + + return true; + } + + //__________________________________________________ + void resetInterlinks() + { + interlinks.cascCoreToCascades.clear(); + interlinks.kfCascCoreToCascades.clear(); + interlinks.traCascCoreToCascades.clear(); + interlinks.cascadeToCascCores.clear(); + interlinks.cascadeToKFCascCores.clear(); + interlinks.cascadeToTraCascCores.clear(); + } + + //__________________________________________________ + void populateCascadeInterlinks() + { + // if (mEnabledTables[kCascToKFRefs]) { + // for (const auto& cascCore : interlinks.cascCoreToCascades) { + // cascToKFRefs(interlinks.cascadeToKFCascCores[cascCore]); + // histos.fill(HIST("hTableBuildingStatistics"), kCascToKFRefs); + // } + // } + // if (mEnabledTables[kCascToTraRefs]) { + // for (const auto& cascCore : interlinks.cascCoreToCascades) { + // cascToTraRefs(interlinks.cascadeToTraCascCores[cascCore]); + // histos.fill(HIST("hTableBuildingStatistics"), kCascToTraRefs); + // } + // } + // if (mEnabledTables[kKFToCascRefs]) { + // for (const auto& kfCascCore : interlinks.kfCascCoreToCascades) { + // kfToCascRefs(interlinks.cascadeToCascCores[kfCascCore]); + // histos.fill(HIST("hTableBuildingStatistics"), kKFToCascRefs); + // } + // } + // if (mEnabledTables[kTraToCascRefs]) { + // for (const auto& traCascCore : interlinks.traCascCoreToCascades) { + // traToCascRefs(interlinks.cascadeToCascCores[traCascCore]); + // histos.fill(HIST("hTableBuildingStatistics"), kTraToCascRefs); + // } + // } + } + + //__________________________________________________ + template + void prepareBuildingLists(TCollisions const& collisions, TMCCollisions const& mcCollisions, TV0s const& v0s, TCascades const& cascades, TTracks const& tracks, TMCParticles const& mcParticles) + { + // this function prepares the v0List and cascadeList depending on + // how the task has been set up. Standard operation simply uses + // the existing V0s and Cascades from AO2D, while findable MC + // operation either complements with all findable-but-not-found + // or resets and fills with all findable. + // + // Whenever using findable candidates, they will be appropriately + // marked for posterior analysis using 'tag' variables. + // + // findable mode legend: + // 0: simple passthrough of V0s, Cascades in AO2Ds + // (in data, this is the only mode possible!) + // 1: add extra findable that haven't been found + // 2: generate only findable (no background) + + // redo lists from scratch + v0List.clear(); + cascadeList.clear(); + sorted_v0.clear(); + sorted_cascade.clear(); + ao2dV0toV0List.clear(); + + trackEntry currentTrackEntry; + v0Entry currentV0Entry; + cascadeEntry currentCascadeEntry; + + std::vector bestCollisionArray; // stores McCollision -> Collision map + std::vector bestCollisionNContribsArray; // stores Ncontribs for biggest coll assoc to mccoll + + int collisionLessV0s = 0; + int collisionLessCascades = 0; + + if (mc_findableMode.value > 0) { + if constexpr (soa::is_table) { + // if mcCollisions exist, assemble mcColl -> bestRecoColl map here + bestCollisionArray.clear(); + bestCollisionNContribsArray.clear(); + bestCollisionArray.resize(mcCollisions.size(), -1); // marks not reconstructed + bestCollisionNContribsArray.resize(mcCollisions.size(), -1); // marks not reconstructed + + // single loop over double loop at a small cost in memory for extra array + for (const auto& collision : collisions) { + if (collision.has_mcCollision()) { + if (collision.numContrib() > bestCollisionNContribsArray[collision.mcCollisionId()]) { + bestCollisionArray[collision.mcCollisionId()] = collision.globalIndex(); + bestCollisionNContribsArray[collision.mcCollisionId()] = collision.numContrib(); + } + } + } // end collision loop + } // end is_table + } // end findable mode check + + if (mc_findableMode.value < 2) { + // keep all unless de-duplication active + ao2dV0toV0List.resize(v0s.size(), -1); // -1 means keep, -2 means do not keep + + if (deduplicationAlgorithm > 0 && v0BuilderOpts.generatePhotonCandidates) { + // handle duplicates explicitly: group V0s according to (p,n) indices + // will provide a list of collisionIds (in V0group), allowing for + // easy de-duplication when passing to the v0List + std::vector v0tableGrouped = o2::pwglf::groupDuplicates(v0s); + histos.fill(HIST("hDeduplicationStatistics"), 0.0, v0s.size()); + histos.fill(HIST("hDeduplicationStatistics"), 1.0, v0tableGrouped.size()); + + // process grouped duplicates, remove 'bad' ones + for (size_t iV0 = 0; iV0 < v0tableGrouped.size(); iV0++) { + auto pTrack = tracks.rawIteratorAt(v0tableGrouped[iV0].posTrackId); + auto nTrack = tracks.rawIteratorAt(v0tableGrouped[iV0].negTrackId); + + bool isPosTPCOnly = (pTrack.hasTPC() && !pTrack.hasITS() && !pTrack.hasTRD() && !pTrack.hasTOF()); + bool isNegTPCOnly = (nTrack.hasTPC() && !nTrack.hasITS() && !nTrack.hasTRD() && !nTrack.hasTOF()); + + // skip single copy V0s + if (v0tableGrouped[iV0].collisionIds.size() == 1) { + continue; + } + + // don't try to de-duplicate if no track is TPC only + if (!isPosTPCOnly && !isNegTPCOnly) { + continue; + } + + // fitness criteria defined here + float bestPointingAngle = 10; // a nonsense angle, anything's better + size_t bestPointingAngleIndex = -1; + + float bestDCADaughters = 1e+3; // an excessively large DCA + size_t bestDCADaughtersIndex = -1; + + for (size_t ic = 0; ic < v0tableGrouped[iV0].collisionIds.size(); ic++) { + // get track parametrizations, collisions + auto posTrackPar = getTrackParCov(pTrack); + auto negTrackPar = getTrackParCov(nTrack); + auto const& collision = collisions.rawIteratorAt(v0tableGrouped[iV0].collisionIds[ic]); + + // handle TPC-only tracks properly (photon conversions) + if (v0BuilderOpts.moveTPCOnlyTracks) { + if (isPosTPCOnly) { + // Nota bene: positive is TPC-only -> this entire V0 merits treatment as photon candidate + posTrackPar.setPID(o2::track::PID::Electron); + negTrackPar.setPID(o2::track::PID::Electron); + if (!mVDriftMgr.moveTPCTrack(collision, pTrack, posTrackPar)) { + return; + } + } + if (isNegTPCOnly) { + // Nota bene: negative is TPC-only -> this entire V0 merits treatment as photon candidate + posTrackPar.setPID(o2::track::PID::Electron); + negTrackPar.setPID(o2::track::PID::Electron); + if (!mVDriftMgr.moveTPCTrack(collision, nTrack, negTrackPar)) { + return; + } + } + } // end TPC drift treatment + + // process candidate with helper, generate properties for consulting + // : do not apply selections: do as much as possible to preserve + // candidate at this level and do not select with topo selections + if (straHelper.buildV0Candidate(v0tableGrouped[iV0].collisionIds[ic], collision.posX(), collision.posY(), collision.posZ(), pTrack, nTrack, posTrackPar, negTrackPar, true, false, true)) { + // candidate built, check pointing angle + if (straHelper.v0.pointingAngle < bestPointingAngle) { + bestPointingAngle = straHelper.v0.pointingAngle; + bestPointingAngleIndex = ic; + } + if (straHelper.v0.daughterDCA < bestDCADaughters) { + bestDCADaughters = straHelper.v0.daughterDCA; + bestDCADaughtersIndex = ic; + } + } // end build V0 + } // end candidate loop + + // mark de-duplicated candidates + for (size_t ic = 0; ic < v0tableGrouped[iV0].collisionIds.size(); ic++) { + ao2dV0toV0List[v0tableGrouped[iV0].V0Ids[ic]] = -2; + // algorithm 1: best pointing angle + if (bestPointingAngleIndex == ic && deduplicationAlgorithm.value == 1) { + ao2dV0toV0List[v0tableGrouped[iV0].V0Ids[ic]] = -1; // keep best only + } + if (bestDCADaughtersIndex == ic && deduplicationAlgorithm.value == 2) { + ao2dV0toV0List[v0tableGrouped[iV0].V0Ids[ic]] = -1; // keep best only + } + if (bestDCADaughtersIndex == ic && bestPointingAngleIndex == ic && deduplicationAlgorithm.value == 3) { + ao2dV0toV0List[v0tableGrouped[iV0].V0Ids[ic]] = -1; // keep best only + } + } + } // end V0 loop + } // end de-duplication process + + for (const auto& v0 : v0s) { + if (ao2dV0toV0List[v0.globalIndex()] == -1) { // keep only de-duplicated + ao2dV0toV0List[v0.globalIndex()] = v0List.size(); // maps V0s to the corresponding v0List entry + currentV0Entry.globalId = v0.globalIndex(); + currentV0Entry.collisionId = v0.collisionId(); + currentV0Entry.posTrackId = v0.posTrackId(); + currentV0Entry.negTrackId = v0.negTrackId(); + currentV0Entry.v0Type = v0.v0Type(); + currentV0Entry.pdgCode = 0; + currentV0Entry.particleId = -1; + currentV0Entry.isCollinearV0 = v0.isCollinearV0(); + currentV0Entry.found = true; + v0List.push_back(currentV0Entry); + } + } + } + // any mode other than 0 will require mcParticles + if constexpr (soa::is_table) { + if (mc_findableMode.value > 0) { + // for search if existing or not + int v0ListReconstructedSize = v0List.size(); + + // find extra candidates, step 1: find subset of tracks that interest + std::vector positiveTrackArray; + std::vector negativeTrackArray; + // vector elements: track index, origin index [, mc collision id, pdg code] + int dummy = -1; // unnecessary in this path + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + continue; // skip this, it's trouble + } + auto particle = track.template mcParticle_as(); + int originParticleIndex = getOriginatingParticle(particle, dummy, v0BuilderOpts.mc_treatPiToMuDecays); + if (originParticleIndex < 0) { + continue; // skip this, it's trouble (2) + } + auto originParticle = mcParticles.rawIteratorAt(originParticleIndex); + + bool trackIsInteresting = false; + if ( + (originParticle.pdgCode() == 310 && v0BuilderOpts.mc_addGeneratedK0Short.value > 0) || + (originParticle.pdgCode() == 3122 && v0BuilderOpts.mc_addGeneratedLambda.value > 0) || + (originParticle.pdgCode() == -3122 && v0BuilderOpts.mc_addGeneratedAntiLambda.value > 0) || + (originParticle.pdgCode() == 22 && v0BuilderOpts.mc_addGeneratedGamma.value > 0)) { + trackIsInteresting = true; + } + if (!trackIsInteresting) { + continue; // skip this, it's uninteresting + } + + currentTrackEntry.globalId = static_cast(track.globalIndex()); + currentTrackEntry.originId = originParticleIndex; + currentTrackEntry.mcCollisionId = originParticle.mcCollisionId(); + currentTrackEntry.pdgCode = originParticle.pdgCode(); + + // now separate according to particle species + if (track.sign() < 0) { + negativeTrackArray.push_back(currentTrackEntry); + } else { + positiveTrackArray.push_back(currentTrackEntry); + } + } + + // Nested loop only with valuable tracks + for (const auto& positiveTrackIndex : positiveTrackArray) { + for (const auto& negativeTrackIndex : negativeTrackArray) { + if (positiveTrackIndex.originId != negativeTrackIndex.originId) { + continue; // not the same originating particle + } + // findable mode 1: add non-reconstructed as v0Type 8 + if (mc_findableMode.value == 1) { + bool detected = false; + for (int ii = 0; ii < v0ListReconstructedSize; ii++) { + // check if this particular combination already exists in v0List + if (v0List[ii].posTrackId == positiveTrackIndex.globalId && + v0List[ii].negTrackId == negativeTrackIndex.globalId) { + detected = true; + // override pdg code with something useful for cascade findable math + v0List[ii].pdgCode = positiveTrackIndex.pdgCode; + break; + } + } + if (detected == false) { + // collision index: from best-version-of-this-mcCollision + // nota bene: this could be negative, caution advised + currentV0Entry.globalId = -1; + currentV0Entry.collisionId = bestCollisionArray[positiveTrackIndex.mcCollisionId]; + currentV0Entry.posTrackId = positiveTrackIndex.globalId; + currentV0Entry.negTrackId = negativeTrackIndex.globalId; + currentV0Entry.v0Type = 1; + currentV0Entry.pdgCode = positiveTrackIndex.pdgCode; + currentV0Entry.particleId = positiveTrackIndex.originId; + currentV0Entry.isCollinearV0 = false; + if (v0BuilderOpts.mc_addGeneratedGammaMakeCollinear.value && currentV0Entry.pdgCode == 22) { + currentV0Entry.isCollinearV0 = true; + } + currentV0Entry.found = false; + if (bestCollisionArray[positiveTrackIndex.mcCollisionId] < 0) { + collisionLessV0s++; + } + if (v0BuilderOpts.mc_findableDetachedV0.value || currentV0Entry.collisionId >= 0) { + v0List.push_back(currentV0Entry); + } + } + } + // findable mode 2 + if (mc_findableMode.value == 2) { + currentV0Entry.globalId = -1; + currentV0Entry.collisionId = bestCollisionArray[positiveTrackIndex.mcCollisionId]; + currentV0Entry.posTrackId = positiveTrackIndex.globalId; + currentV0Entry.negTrackId = negativeTrackIndex.globalId; + currentV0Entry.v0Type = 1; + currentV0Entry.pdgCode = positiveTrackIndex.pdgCode; + currentV0Entry.particleId = positiveTrackIndex.originId; + currentV0Entry.isCollinearV0 = false; + if (v0BuilderOpts.mc_addGeneratedGammaMakeCollinear.value && currentV0Entry.pdgCode == 22) { + currentV0Entry.isCollinearV0 = true; + } + currentV0Entry.found = false; + for (const auto& v0 : v0s) { + if (v0.posTrackId() == positiveTrackIndex.globalId && + v0.negTrackId() == negativeTrackIndex.globalId) { + // this will override type, but not collision index + // N.B.: collision index checks still desirable! + currentV0Entry.globalId = v0.globalIndex(); + currentV0Entry.v0Type = v0.v0Type(); + currentV0Entry.isCollinearV0 = v0.isCollinearV0(); + currentV0Entry.found = true; + break; + } + } + if (v0BuilderOpts.mc_findableDetachedV0.value || currentV0Entry.collisionId >= 0) { + v0List.push_back(currentV0Entry); + } + } + } + } // end positive / negative track loops + + // fill findable statistics table + histos.fill(HIST("hFindableStatistics"), 0.0, v0s.size()); + histos.fill(HIST("hFindableStatistics"), 1.0, v0List.size()); + histos.fill(HIST("hFindableStatistics"), 2.0, collisionLessV0s); + + } // end findableMode > 0 check + } // end soa::is_table + + // determine properly collision-id-sorted index array for later use + // N.B.: necessary also before cascade part + sorted_v0.clear(); + sorted_v0 = sort_indices(v0List, (mc_findableMode.value > 0)); + + // Cascade part if cores are requested, skip otherwise + if (mEnabledTables[kStoredCascCores] || mEnabledTables[kStoredKFCascCores]) { + if (mc_findableMode.value < 2) { + // simple passthrough: copy existing cascades to build list + for (const auto& cascade : cascades) { + auto const& v0 = cascade.v0(); + if (v0.v0Type() > 1) { + continue; // skip any unexpected stuff (FIXME: follow-up) + } + currentCascadeEntry.globalId = cascade.globalIndex(); + currentCascadeEntry.collisionId = cascade.collisionId(); + currentCascadeEntry.v0Id = ao2dV0toV0List[v0.globalIndex()]; + currentCascadeEntry.posTrackId = v0.posTrackId(); + currentCascadeEntry.negTrackId = v0.negTrackId(); + currentCascadeEntry.bachTrackId = cascade.bachelorId(); + currentCascadeEntry.found = true; + cascadeList.push_back(currentCascadeEntry); + } + } + + // any mode other than 0 will require mcParticles + if constexpr (soa::is_table) { + if (mc_findableMode.value > 0) { + // for search if existing or not + size_t cascadeListReconstructedSize = cascadeList.size(); + + // determine which tracks are of interest + std::vector bachelorTrackArray; + // vector elements: track index, origin index, mc collision id, pdg code] + int dummy = -1; // unnecessary in this path + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + continue; // skip this, it's trouble + } + auto particle = track.template mcParticle_as(); + int originParticleIndex = getOriginatingParticle(particle, dummy, cascadeBuilderOpts.mc_treatPiToMuDecays); + if (originParticleIndex < 0) { + continue; // skip this, it's trouble (2) + } + auto originParticle = mcParticles.rawIteratorAt(originParticleIndex); + + bool trackIsInteresting = false; + if ( + (originParticle.pdgCode() == 3312 && cascadeBuilderOpts.mc_addGeneratedXiMinus.value > 0) || + (originParticle.pdgCode() == -3312 && cascadeBuilderOpts.mc_addGeneratedXiPlus.value > 0) || + (originParticle.pdgCode() == 3334 && cascadeBuilderOpts.mc_addGeneratedOmegaMinus.value > 0) || + (originParticle.pdgCode() == -3334 && cascadeBuilderOpts.mc_addGeneratedOmegaPlus.value > 0)) { + trackIsInteresting = true; + } + if (!trackIsInteresting) { + continue; // skip this, it's uninteresting + } + + currentTrackEntry.globalId = static_cast(track.globalIndex()); + currentTrackEntry.originId = originParticleIndex; + currentTrackEntry.mcCollisionId = originParticle.mcCollisionId(); + currentTrackEntry.pdgCode = originParticle.pdgCode(); + + // populate list of bachelor tracks to pair + bachelorTrackArray.push_back(currentTrackEntry); + } + + // determine which V0s are of interest to pair and do pairing + for (size_t v0i = 0; v0i < v0List.size(); v0i++) { + auto v0 = v0List[sorted_v0[v0i]]; + + if (std::abs(v0.pdgCode) != 3122) { + continue; // this V0 isn't a lambda, can't come from a cascade: skip + } + if (v0.particleId < 0) { + continue; // no de-referencing possible (e.g. background, ...) + } + auto v0Particle = mcParticles.rawIteratorAt(v0.particleId); + + int v0OriginParticleIndex = -1; + if (v0Particle.has_mothers()) { + auto const& motherList = v0Particle.template mothers_as(); + if (motherList.size() == 1) { + for (const auto& mother : motherList) { + v0OriginParticleIndex = mother.globalIndex(); + } + } + } + if (v0OriginParticleIndex < 0) { + continue; + } + auto v0OriginParticle = mcParticles.rawIteratorAt(v0OriginParticleIndex); + + if (std::abs(v0OriginParticle.pdgCode()) != 3312 && std::abs(v0OriginParticle.pdgCode()) != 3334) { + continue; // this V0 does not come from any particle of interest, don't try + } + for (const auto& bachelorTrackIndex : bachelorTrackArray) { + if (bachelorTrackIndex.originId != v0OriginParticle.globalIndex()) { + continue; + } + // if we are here: v0 origin is 3312 or 3334, bachelor origin matches V0 origin + // findable mode 1: add non-reconstructed as cascadeType 1 + if (mc_findableMode.value == 1) { + bool detected = false; + for (size_t ii = 0; ii < cascadeListReconstructedSize; ii++) { + // check if this particular combination already exists in cascadeList + // caution: use track indices (immutable) but not V0 indices (re-indexing) + if (cascadeList[ii].posTrackId == v0.posTrackId && + cascadeList[ii].negTrackId == v0.negTrackId && + cascadeList[ii].bachTrackId == bachelorTrackIndex.globalId) { + detected = true; + break; + } + } + if (detected == false) { + // collision index: from best-version-of-this-mcCollision + // nota bene: this could be negative, caution advised + currentCascadeEntry.globalId = -1; + currentCascadeEntry.collisionId = bestCollisionArray[bachelorTrackIndex.mcCollisionId]; + currentCascadeEntry.v0Id = v0i; // correct information here + currentCascadeEntry.posTrackId = v0.posTrackId; + currentCascadeEntry.negTrackId = v0.negTrackId; + currentCascadeEntry.bachTrackId = bachelorTrackIndex.globalId; + currentCascadeEntry.found = false; + cascadeList.push_back(currentCascadeEntry); + if (bestCollisionArray[bachelorTrackIndex.mcCollisionId] < 0) { + collisionLessCascades++; + } + if (cascadeBuilderOpts.mc_findableDetachedCascade.value || currentCascadeEntry.collisionId >= 0) { + cascadeList.push_back(currentCascadeEntry); + } + } + } + + // findable mode 2: determine type based on cascade table, + // with type 1 being reserved to findable-but-not-found + if (mc_findableMode.value == 2) { + currentCascadeEntry.globalId = -1; + currentCascadeEntry.collisionId = bestCollisionArray[bachelorTrackIndex.mcCollisionId]; + currentCascadeEntry.v0Id = v0i; // fill this in one go later + currentCascadeEntry.posTrackId = v0.posTrackId; + currentCascadeEntry.negTrackId = v0.negTrackId; + currentCascadeEntry.bachTrackId = bachelorTrackIndex.globalId; + currentCascadeEntry.found = false; + if (bestCollisionArray[bachelorTrackIndex.mcCollisionId] < 0) { + collisionLessCascades++; + } + for (const auto& cascade : cascades) { + auto const& v0fromAOD = cascade.v0(); + if (v0fromAOD.posTrackId() == v0.posTrackId && + v0fromAOD.negTrackId() == v0.negTrackId && + cascade.bachelorId() == bachelorTrackIndex.globalId) { + // this will override type, but not collision index + // N.B.: collision index checks still desirable! + currentCascadeEntry.found = true; + currentCascadeEntry.globalId = cascade.globalIndex(); + break; + } + } + if (cascadeBuilderOpts.mc_findableDetachedCascade.value || currentCascadeEntry.collisionId >= 0) { + cascadeList.push_back(currentCascadeEntry); + } + } + } // end bachelorTrackArray loop + } // end v0List loop + + // at this stage, cascadeList is alright, but the v0 indices are still not + // correct. We'll have to loop over all V0s and find the appropriate matches + // ---> but only in mode 1, and only for AO2D-native V0s + if (mc_findableMode.value == 1) { + for (size_t casci = 0; casci < cascadeListReconstructedSize; casci++) { + // loop over v0List to find corresponding v0 index, but do it in sorted way + for (size_t v0i = 0; v0i < v0List.size(); v0i++) { + auto v0 = v0List[sorted_v0[v0i]]; + if (cascadeList[casci].posTrackId == v0.posTrackId && + cascadeList[casci].negTrackId == v0.negTrackId) { + cascadeList[casci].v0Id = v0i; // fix, point to correct V0 index + break; + } + } + } + } + // we should now be done! collect statistics + histos.fill(HIST("hFindableStatistics"), 3.0, cascades.size()); + histos.fill(HIST("hFindableStatistics"), 4.0, cascadeList.size()); + histos.fill(HIST("hFindableStatistics"), 5.0, collisionLessCascades); + + } // end findable mode check + } // end soa::is_table + + // we need to allow for sorted use of cascadeList + sorted_cascade.clear(); + sorted_cascade = sort_indices(cascadeList, (mc_findableMode.value > 0)); + } + + LOGF(info, "AO2D input: %i V0s, %i cascades. Building list sizes: %i V0s, %i cascades", v0s.size(), cascades.size(), v0List.size(), cascadeList.size()); + } + + //__________________________________________________ + template + void markV0sUsedInCascades(TV0s const& v0s, TCascades const& cascades, TTrackedCascades const& trackedCascades) + { + int v0sUsedInCascades = 0; + v0sFromCascades.clear(); + v0Map.clear(); + v0Map.resize(v0List.size(), -2); // marks not used + if (mEnabledTables[kStoredCascCores]) { + for (const auto& cascade : cascadeList) { + if (v0Map[cascade.v0Id] == -2) { + v0sUsedInCascades++; + } + v0Map[cascade.v0Id] = -1; // marks used (but isn't the index of a properly built V0, which would be >= 0) + } + } + int trackedCascadeCount = 0; + if constexpr (soa::is_table) { + // tracked only created outside of findable mode + if (mEnabledTables[kStoredTraCascCores] && mc_findableMode.value == 0) { + trackedCascadeCount = trackedCascades.size(); + for (const auto& trackedCascade : trackedCascades) { + auto const& cascade = trackedCascade.cascade(); + LOGF(info, "trouble: cascade.v0Id() = %i but v0Map size %i", ao2dV0toV0List[cascade.v0Id()], v0Map.size()); + if (v0Map[ao2dV0toV0List[cascade.v0Id()]] == -2) { + v0sUsedInCascades++; + } + v0Map[ao2dV0toV0List[cascade.v0Id()]] = -1; // marks used (but isn't the index of a built V0, which would be >= 0) + } + } + } + LOGF(debug, "V0 total %i, Cascade total %i, Tracked cascade total %i, V0s flagged used in cascades: %i", v0s.size(), cascades.size(), trackedCascadeCount, v0sUsedInCascades); + } + + //__________________________________________________ + template + void buildV0s(TCollisions const& collisions, TV0s const& v0s, TTracks const& tracks, TMCParticles const& mcParticles) + { + // prepare MC containers (not necessarily used) + std::vector mcV0infos; // V0MCCore information + std::vector mcParticleIsReco; + + if constexpr (soa::is_table) { + // do this if provided with a mcParticle table as well + mcParticleIsReco.resize(mcParticles.size(), false); + } + + int nV0s = 0; + // Loops over all V0s in the time frame + histos.fill(HIST("hInputStatistics"), kV0CoresBase, v0s.size()); + for (size_t iv0 = 0; iv0 < v0List.size(); iv0++) { + const auto& v0 = v0List[sorted_v0[iv0]]; + + if (!mEnabledTables[kV0CoresBase] && v0Map[iv0] == -2) { + // this v0 hasn't been used by cascades and we're not generating V0s, so skip it + products.v0dataLink(-1, -1); + continue; + } + + // Get tracks and generate candidate + // if collisionId positive: get vertex, negative: origin + // could be replaced by mean vertex (but without much benefit...) + float pvX = 0.0f, pvY = 0.0f, pvZ = 0.0f; + if (v0.collisionId >= 0) { + auto const& collision = collisions.rawIteratorAt(v0.collisionId); + pvX = collision.posX(); + pvY = collision.posY(); + pvZ = collision.posZ(); + } + auto const& posTrack = tracks.rawIteratorAt(v0.posTrackId); + auto const& negTrack = tracks.rawIteratorAt(v0.negTrackId); + + auto posTrackPar = getTrackParCov(posTrack); + auto negTrackPar = getTrackParCov(negTrack); + + // handle TPC-only tracks properly (photon conversions) + if (v0BuilderOpts.moveTPCOnlyTracks) { + bool isPosTPCOnly = (posTrack.hasTPC() && !posTrack.hasITS() && !posTrack.hasTRD() && !posTrack.hasTOF()); + if (isPosTPCOnly) { + // Nota bene: positive is TPC-only -> this entire V0 merits treatment as photon candidate + posTrackPar.setPID(o2::track::PID::Electron); + negTrackPar.setPID(o2::track::PID::Electron); + + auto const& collision = collisions.rawIteratorAt(v0.collisionId); + if (!mVDriftMgr.moveTPCTrack(collision, posTrack, posTrackPar)) { + return; + } + } + + bool isNegTPCOnly = (negTrack.hasTPC() && !negTrack.hasITS() && !negTrack.hasTRD() && !negTrack.hasTOF()); + if (isNegTPCOnly) { + // Nota bene: negative is TPC-only -> this entire V0 merits treatment as photon candidate + posTrackPar.setPID(o2::track::PID::Electron); + negTrackPar.setPID(o2::track::PID::Electron); + + auto const& collision = collisions.rawIteratorAt(v0.collisionId); + if (!mVDriftMgr.moveTPCTrack(collision, negTrack, negTrackPar)) { + return; + } + } + } + + if (!straHelper.buildV0Candidate(v0.collisionId, pvX, pvY, pvZ, posTrack, negTrack, posTrackPar, negTrackPar, v0.isCollinearV0, mEnabledTables[kV0Covs], true)) { + products.v0dataLink(-1, -1); + continue; + } + if (v0Map[iv0] == -1 && useV0BufferForCascades) { + v0Map[iv0] = v0sFromCascades.size(); // provide actual valid index in buffer + v0sFromCascades.push_back(straHelper.v0); + } + // fill requested cursors only if type is not 0 + if (v0.v0Type == 1 || (v0.v0Type > 1 && v0BuilderOpts.generatePhotonCandidates)) { + nV0s++; + if (mEnabledTables[kV0Indices]) { + // for referencing (especially - but not only - when using derived data) + products.v0indices(v0.posTrackId, v0.negTrackId, + v0.collisionId, iv0); + histos.fill(HIST("hTableBuildingStatistics"), kV0Indices); + } + if (mEnabledTables[kV0TrackXs]) { + // further decay chains may need this + products.v0trackXs(straHelper.v0.positiveTrackX, straHelper.v0.negativeTrackX); + histos.fill(HIST("hTableBuildingStatistics"), kV0TrackXs); + } + if (mEnabledTables[kV0CoresBase]) { + // standard analysis + products.v0cores(straHelper.v0.position[0], straHelper.v0.position[1], straHelper.v0.position[2], + straHelper.v0.positiveMomentum[0], straHelper.v0.positiveMomentum[1], straHelper.v0.positiveMomentum[2], + straHelper.v0.negativeMomentum[0], straHelper.v0.negativeMomentum[1], straHelper.v0.negativeMomentum[2], + straHelper.v0.daughterDCA, + straHelper.v0.positiveDCAxy, + straHelper.v0.negativeDCAxy, + TMath::Cos(straHelper.v0.pointingAngle), + straHelper.v0.dcaToPV, + v0.v0Type); + products.v0dataLink(products.v0cores.lastIndex(), -1); + histos.fill(HIST("hTableBuildingStatistics"), kV0CoresBase); + } + if (mEnabledTables[kV0TraPosAtDCAs]) { + // for tracking studies + products.v0dauPositions(straHelper.v0.positivePosition[0], straHelper.v0.positivePosition[1], straHelper.v0.positivePosition[2], + straHelper.v0.negativePosition[0], straHelper.v0.negativePosition[1], straHelper.v0.negativePosition[2]); + histos.fill(HIST("hTableBuildingStatistics"), kV0TraPosAtDCAs); + } + if (mEnabledTables[kV0TraPosAtIUs]) { + // for tracking studies + std::array positivePositionIU; + std::array negativePositionIU; + o2::track::TrackPar positiveTrackParam = getTrackPar(posTrack); + o2::track::TrackPar negativeTrackParam = getTrackPar(negTrack); + positiveTrackParam.getXYZGlo(positivePositionIU); + negativeTrackParam.getXYZGlo(negativePositionIU); + products.v0dauPositionsIU(positivePositionIU[0], positivePositionIU[1], positivePositionIU[2], + negativePositionIU[0], negativePositionIU[1], negativePositionIU[2]); + histos.fill(HIST("hTableBuildingStatistics"), kV0TraPosAtIUs); + } + if (mEnabledTables[kV0Covs]) { + products.v0covs(straHelper.v0.positionCovariance, straHelper.v0.momentumCovariance); + histos.fill(HIST("hTableBuildingStatistics"), kV0Covs); + } + + //_________________________________________________________ + // MC handling part + if constexpr (soa::is_table) { + // only worry about this if someone else worried about this + if ((mEnabledTables[kV0MCCores] || mEnabledTables[kMcV0Labels] || mEnabledTables[kV0MCCollRefs])) { + thisInfo.label = -1; + thisInfo.motherLabel = -1; + thisInfo.pdgCode = 0; + thisInfo.pdgCodeMother = 0; + thisInfo.pdgCodePositive = 0; + thisInfo.pdgCodeNegative = 0; + thisInfo.mcCollision = -1; + thisInfo.xyz[0] = thisInfo.xyz[1] = thisInfo.xyz[2] = 0.0f; + thisInfo.posP[0] = thisInfo.posP[1] = thisInfo.posP[2] = 0.0f; + thisInfo.negP[0] = thisInfo.negP[1] = thisInfo.negP[2] = 0.0f; + thisInfo.momentum[0] = thisInfo.momentum[1] = thisInfo.momentum[2] = 0.0f; + + // Association check + // There might be smarter ways of doing this in the future + if (negTrack.has_mcParticle() && posTrack.has_mcParticle()) { + auto lMCNegTrack = negTrack.template mcParticle_as(); + auto lMCPosTrack = posTrack.template mcParticle_as(); + + thisInfo.pdgCodePositive = lMCPosTrack.pdgCode(); + thisInfo.pdgCodeNegative = lMCNegTrack.pdgCode(); + thisInfo.processPositive = lMCPosTrack.getProcess(); + thisInfo.processNegative = lMCNegTrack.getProcess(); + thisInfo.posP[0] = lMCPosTrack.px(); + thisInfo.posP[1] = lMCPosTrack.py(); + thisInfo.posP[2] = lMCPosTrack.pz(); + thisInfo.negP[0] = lMCNegTrack.px(); + thisInfo.negP[1] = lMCNegTrack.py(); + thisInfo.negP[2] = lMCNegTrack.pz(); + + // check for pi -> mu + antineutrino decay + // if present, de-reference original V0 correctly and provide label to original object + // NOTA BENE: the prong info will still correspond to a muon, treat carefully! + int negOriginating = -1, posOriginating = -1, particleForDecayPositionIdx = -1; + negOriginating = getOriginatingParticle(lMCNegTrack, particleForDecayPositionIdx, v0BuilderOpts.mc_treatPiToMuDecays); + posOriginating = getOriginatingParticle(lMCPosTrack, particleForDecayPositionIdx, v0BuilderOpts.mc_treatPiToMuDecays); + + if (negOriginating > -1 && negOriginating == posOriginating) { + auto originatingV0 = mcParticles.rawIteratorAt(negOriginating); + auto particleForDecayPosition = mcParticles.rawIteratorAt(particleForDecayPositionIdx); + + thisInfo.label = originatingV0.globalIndex(); + thisInfo.xyz[0] = particleForDecayPosition.vx(); + thisInfo.xyz[1] = particleForDecayPosition.vy(); + thisInfo.xyz[2] = particleForDecayPosition.vz(); + + if (originatingV0.has_mcCollision()) { + thisInfo.mcCollision = originatingV0.mcCollisionId(); // save this reference, please + } + + // acquire information + thisInfo.pdgCode = originatingV0.pdgCode(); + thisInfo.isPhysicalPrimary = originatingV0.isPhysicalPrimary(); + thisInfo.momentum[0] = originatingV0.px(); + thisInfo.momentum[1] = originatingV0.py(); + thisInfo.momentum[2] = originatingV0.pz(); + + if (originatingV0.has_mothers()) { + for (const auto& lV0Mother : originatingV0.template mothers_as()) { + thisInfo.pdgCodeMother = lV0Mother.pdgCode(); + thisInfo.motherLabel = lV0Mother.globalIndex(); + } + } + } + + } // end association check + // Construct label table (note: this will be joinable with V0Datas!) + if (mEnabledTables[kMcV0Labels]) { + products.v0labels(thisInfo.label, thisInfo.motherLabel); + histos.fill(HIST("hTableBuildingStatistics"), kMcV0Labels); + } + + // Construct found tag + if (mEnabledTables[kV0FoundTags]) { + products.v0FoundTag(v0.found); + histos.fill(HIST("hTableBuildingStatistics"), kV0FoundTags); + } + + // Mark mcParticle as recoed (no searching necessary afterwards) + if (thisInfo.label > -1) { + mcParticleIsReco[thisInfo.label] = true; + } + + // ---] Symmetric populate [--- + // in this approach, V0Cores will be joinable with V0MCCores. + // this is the most pedagogical approach, but it is also more limited + // and it might use more disk space unnecessarily. + if (v0BuilderOpts.mc_populateV0MCCoresSymmetric) { + if (mEnabledTables[kV0MCCores]) { + products.v0mccores( + thisInfo.label, thisInfo.pdgCode, + thisInfo.pdgCodeMother, thisInfo.pdgCodePositive, thisInfo.pdgCodeNegative, + thisInfo.isPhysicalPrimary, thisInfo.xyz[0], thisInfo.xyz[1], thisInfo.xyz[2], + thisInfo.posP[0], thisInfo.posP[1], thisInfo.posP[2], + thisInfo.negP[0], thisInfo.negP[1], thisInfo.negP[2], + thisInfo.momentum[0], thisInfo.momentum[1], thisInfo.momentum[2]); + histos.fill(HIST("hTableBuildingStatistics"), kV0MCCores); + } + if (mEnabledTables[kV0MCCollRefs]) { + products.v0mccollref(thisInfo.mcCollision); + histos.fill(HIST("hTableBuildingStatistics"), kV0MCCollRefs); + } + + // n.b. placing the interlink index here allows for the writing of + // code that is agnostic with respect to the joinability of + // V0Cores and V0MCCores (always dereference -> safe) + if (mEnabledTables[kV0CoreMCLabels]) { + products.v0CoreMCLabels(iv0); // interlink index + histos.fill(HIST("hTableBuildingStatistics"), kV0CoreMCLabels); + } + } + // ---] Asymmetric populate [--- + // in this approach, V0Cores will NOT be joinable with V0MCCores. + // an additional reference to V0MCCore that IS joinable with V0Cores + // will be provided to the user. + if (v0BuilderOpts.mc_populateV0MCCoresAsymmetric) { + int thisV0MCCoreIndex = -1; + // step 1: check if this element is already provided in the table + // using the packedIndices variable calculated above + for (uint32_t ii = 0; ii < mcV0infos.size(); ii++) { + if (thisInfo.label == mcV0infos[ii].label && mcV0infos[ii].label > -1) { + thisV0MCCoreIndex = ii; + break; // this exists already in list + } + } + if (thisV0MCCoreIndex < 0 && thisInfo.label > -1) { + // this V0MCCore does not exist yet. Create it and reference it + thisV0MCCoreIndex = mcV0infos.size(); + mcV0infos.push_back(thisInfo); + } + if (mEnabledTables[kV0CoreMCLabels]) { + products.v0CoreMCLabels(thisV0MCCoreIndex); // interlink index + histos.fill(HIST("hTableBuildingStatistics"), kV0CoreMCLabels); + } + } + } // enabled tables check + } // constexpr requires check + } + } + + // finish populating V0MCCores if in asymmetric mode + if constexpr (soa::is_table) { + if (v0BuilderOpts.mc_populateV0MCCoresAsymmetric && (mEnabledTables[kV0MCCores] || mEnabledTables[kV0MCCollRefs])) { + // first step: add any un-recoed v0mmcores that were requested + for (const auto& mcParticle : mcParticles) { + thisInfo.label = -1; + thisInfo.motherLabel = -1; + thisInfo.pdgCode = 0; + thisInfo.pdgCodeMother = -1; + thisInfo.pdgCodePositive = -1; + thisInfo.pdgCodeNegative = -1; + thisInfo.mcCollision = -1; + thisInfo.xyz[0] = thisInfo.xyz[1] = thisInfo.xyz[2] = 0.0f; + thisInfo.posP[0] = thisInfo.posP[1] = thisInfo.posP[2] = 0.0f; + thisInfo.negP[0] = thisInfo.negP[1] = thisInfo.negP[2] = 0.0f; + thisInfo.momentum[0] = thisInfo.momentum[1] = thisInfo.momentum[2] = 0.0f; + + if (mcParticleIsReco[mcParticle.globalIndex()] == true) + continue; // skip if already created in list + + if (std::fabs(mcParticle.y()) > v0BuilderOpts.mc_rapidityWindow) + continue; // skip outside midrapidity + + if ( + (v0BuilderOpts.mc_addGeneratedK0Short && mcParticle.pdgCode() == 310) || + (v0BuilderOpts.mc_addGeneratedLambda && mcParticle.pdgCode() == 3122) || + (v0BuilderOpts.mc_addGeneratedAntiLambda && mcParticle.pdgCode() == -3122) || + (v0BuilderOpts.mc_addGeneratedGamma && mcParticle.pdgCode() == 22)) { + thisInfo.pdgCode = mcParticle.pdgCode(); + thisInfo.isPhysicalPrimary = mcParticle.isPhysicalPrimary(); + thisInfo.label = mcParticle.globalIndex(); + + if (mcParticle.has_mcCollision()) { + thisInfo.mcCollision = mcParticle.mcCollisionId(); // save this reference, please + } + + // + thisInfo.momentum[0] = mcParticle.px(); + thisInfo.momentum[1] = mcParticle.py(); + thisInfo.momentum[2] = mcParticle.pz(); + + if (mcParticle.has_mothers()) { + auto const& mother = mcParticle.template mothers_first_as(); + thisInfo.pdgCodeMother = mother.pdgCode(); + thisInfo.motherLabel = mother.globalIndex(); + } + if (mcParticle.has_daughters()) { + auto const& daughters = mcParticle.template daughters_as(); + + for (const auto& dau : daughters) { + if (dau.getProcess() != 4) + continue; + + if (dau.pdgCode() > 0) { + thisInfo.pdgCodePositive = dau.pdgCode(); + thisInfo.processPositive = dau.getProcess(); + thisInfo.posP[0] = dau.px(); + thisInfo.posP[1] = dau.py(); + thisInfo.posP[2] = dau.pz(); + thisInfo.xyz[0] = dau.vx(); + thisInfo.xyz[1] = dau.vy(); + thisInfo.xyz[2] = dau.vz(); + } + if (dau.pdgCode() < 0) { + thisInfo.pdgCodeNegative = dau.pdgCode(); + thisInfo.processNegative = dau.getProcess(); + thisInfo.negP[0] = dau.px(); + thisInfo.negP[1] = dau.py(); + thisInfo.negP[2] = dau.pz(); + } + } + } + + // if I got here, it means this MC particle was not recoed and is of interest. Add it please + mcV0infos.push_back(thisInfo); + } + } + + for (const auto& info : mcV0infos) { + if (mEnabledTables[kV0MCCores]) { + products.v0mccores( + info.label, info.pdgCode, + info.pdgCodeMother, info.pdgCodePositive, info.pdgCodeNegative, + info.isPhysicalPrimary, info.xyz[0], info.xyz[1], info.xyz[2], + info.posP[0], info.posP[1], info.posP[2], + info.negP[0], info.negP[1], info.negP[2], + info.momentum[0], info.momentum[1], info.momentum[2]); + histos.fill(HIST("hTableBuildingStatistics"), kV0MCCores); + } + if (mEnabledTables[kV0MCCollRefs]) { + products.v0mccollref(info.mcCollision); + histos.fill(HIST("hTableBuildingStatistics"), kV0MCCollRefs); + } + } + } // end V0MCCores filling in case of MC + } // end constexpr requires mcParticles + + LOGF(debug, "V0s in DF: %i, V0s built: %i, V0s built and buffered for cascades: %i.", v0s.size(), nV0s, v0sFromCascades.size()); + } + + //__________________________________________________ + template + void extractMonteCarloProperties(TTrack const& posTrack, TTrack const& negTrack, TTrack const& bachTrack, TMCParticles const& mcParticles) + { + // encapsulates acquisition of MC properties from MC + thisCascInfo.pdgCode = -1, thisCascInfo.pdgCodeMother = -1; + thisCascInfo.pdgCodePositive = -1, thisCascInfo.pdgCodeNegative = -1; + thisCascInfo.pdgCodeBachelor = -1, thisCascInfo.pdgCodeV0 = -1; + thisCascInfo.isPhysicalPrimary = false; + thisCascInfo.xyz[0] = -999.0f, thisCascInfo.xyz[1] = -999.0f, thisCascInfo.xyz[2] = -999.0f; + thisCascInfo.lxyz[0] = -999.0f, thisCascInfo.lxyz[1] = -999.0f, thisCascInfo.lxyz[2] = -999.0f; + thisCascInfo.posP[0] = -999.0f, thisCascInfo.posP[1] = -999.0f, thisCascInfo.posP[2] = -999.0f; + thisCascInfo.negP[0] = -999.0f, thisCascInfo.negP[1] = -999.0f, thisCascInfo.negP[2] = -999.0f; + thisCascInfo.bachP[0] = -999.0f, thisCascInfo.bachP[1] = -999.0f, thisCascInfo.bachP[2] = -999.0f; + thisCascInfo.momentum[0] = -999.0f, thisCascInfo.momentum[1] = -999.0f, thisCascInfo.momentum[2] = -999.0f; + thisCascInfo.label = -1, thisCascInfo.motherLabel = -1; + thisCascInfo.mcParticlePositive = -1; + thisCascInfo.mcParticleNegative = -1; + thisCascInfo.mcParticleBachelor = -1; + + // Association check + // There might be smarter ways of doing this in the future + if (negTrack.has_mcParticle() && posTrack.has_mcParticle() && bachTrack.has_mcParticle()) { + auto lMCBachTrack = bachTrack.template mcParticle_as(); + auto lMCNegTrack = negTrack.template mcParticle_as(); + auto lMCPosTrack = posTrack.template mcParticle_as(); + + thisCascInfo.mcParticlePositive = lMCPosTrack.globalIndex(); + thisCascInfo.mcParticleNegative = lMCNegTrack.globalIndex(); + thisCascInfo.mcParticleBachelor = lMCBachTrack.globalIndex(); + thisCascInfo.pdgCodePositive = lMCPosTrack.pdgCode(); + thisCascInfo.pdgCodeNegative = lMCNegTrack.pdgCode(); + thisCascInfo.pdgCodeBachelor = lMCBachTrack.pdgCode(); + thisCascInfo.posP[0] = lMCPosTrack.px(); + thisCascInfo.posP[1] = lMCPosTrack.py(); + thisCascInfo.posP[2] = lMCPosTrack.pz(); + thisCascInfo.negP[0] = lMCNegTrack.px(); + thisCascInfo.negP[1] = lMCNegTrack.py(); + thisCascInfo.negP[2] = lMCNegTrack.pz(); + thisCascInfo.bachP[0] = lMCBachTrack.px(); + thisCascInfo.bachP[1] = lMCBachTrack.py(); + thisCascInfo.bachP[2] = lMCBachTrack.pz(); + thisCascInfo.processPositive = lMCPosTrack.getProcess(); + thisCascInfo.processNegative = lMCNegTrack.getProcess(); + thisCascInfo.processBachelor = lMCBachTrack.getProcess(); + + // Step 0: treat pi -> mu + antineutrino + // if present, de-reference original V0 correctly and provide label to original object + // NOTA BENE: the prong info will still correspond to a muon, treat carefully! + int negOriginating = -1, posOriginating = -1, bachOriginating = -1; + int particleForLambdaDecayPositionIdx = -1, particleForCascadeDecayPositionIdx = -1; + negOriginating = getOriginatingParticle(lMCNegTrack, particleForLambdaDecayPositionIdx, cascadeBuilderOpts.mc_treatPiToMuDecays); + posOriginating = getOriginatingParticle(lMCPosTrack, particleForLambdaDecayPositionIdx, cascadeBuilderOpts.mc_treatPiToMuDecays); + bachOriginating = getOriginatingParticle(lMCBachTrack, particleForCascadeDecayPositionIdx, cascadeBuilderOpts.mc_treatPiToMuDecays); + + if (negOriginating > -1 && negOriginating == posOriginating) { + auto originatingV0 = mcParticles.rawIteratorAt(negOriginating); + auto particleForLambdaDecayPosition = mcParticles.rawIteratorAt(particleForLambdaDecayPositionIdx); + + thisCascInfo.label = originatingV0.globalIndex(); + thisCascInfo.lxyz[0] = particleForLambdaDecayPosition.vx(); + thisCascInfo.lxyz[1] = particleForLambdaDecayPosition.vy(); + thisCascInfo.lxyz[2] = particleForLambdaDecayPosition.vz(); + thisCascInfo.pdgCodeV0 = originatingV0.pdgCode(); + + if (originatingV0.has_mothers()) { + for (const auto& lV0Mother : originatingV0.template mothers_as()) { + if (lV0Mother.globalIndex() == bachOriginating) { // found mother particle + thisCascInfo.label = lV0Mother.globalIndex(); + + if (lV0Mother.has_mcCollision()) { + thisCascInfo.mcCollision = lV0Mother.mcCollisionId(); // save this reference, please + } + + thisCascInfo.pdgCode = lV0Mother.pdgCode(); + thisCascInfo.isPhysicalPrimary = lV0Mother.isPhysicalPrimary(); + thisCascInfo.xyz[0] = originatingV0.vx(); + thisCascInfo.xyz[1] = originatingV0.vy(); + thisCascInfo.xyz[2] = originatingV0.vz(); + thisCascInfo.momentum[0] = lV0Mother.px(); + thisCascInfo.momentum[1] = lV0Mother.py(); + thisCascInfo.momentum[2] = lV0Mother.pz(); + if (lV0Mother.has_mothers()) { + for (const auto& lV0GrandMother : lV0Mother.template mothers_as()) { + thisCascInfo.pdgCodeMother = lV0GrandMother.pdgCode(); + thisCascInfo.motherLabel = lV0GrandMother.globalIndex(); + } + } + } + } // end v0 mother loop + } // end has_mothers check for V0 + } // end conditional of pos/neg originating being the same + } // end association check + } + + //__________________________________________________ + template + void buildCascades(TCollisions const& collisions, TCascades const& cascades, TTracks const& tracks, TMCParticles const& mcParticles) + { + // prepare MC containers (not necessarily used) + std::vector mcCascinfos; // V0MCCore information + std::vector mcParticleIsReco; + + if constexpr (soa::is_table) { + // do this if provided with a mcParticle table as well + mcParticleIsReco.resize(mcParticles.size(), false); + } + + if (!mEnabledTables[kStoredCascCores]) { + return; // don't do if no request for cascades in place + } + int nCascades = 0; + // Loops over all cascades in the time frame + histos.fill(HIST("hInputStatistics"), kStoredCascCores, cascades.size()); + for (size_t icascade = 0; icascade < cascades.size(); icascade++) { + // Get tracks and generate candidate + auto const& cascade = cascades[sorted_cascade[icascade]]; + // if collisionId positive: get vertex, negative: origin + // could be replaced by mean vertex (but without much benefit...) + float pvX = 0.0f, pvY = 0.0f, pvZ = 0.0f; + if (cascade.collisionId >= 0) { + auto const& collision = collisions.rawIteratorAt(cascade.collisionId); + pvX = collision.posX(); + pvY = collision.posY(); + pvZ = collision.posZ(); + } + auto const& posTrack = tracks.rawIteratorAt(cascade.posTrackId); + auto const& negTrack = tracks.rawIteratorAt(cascade.negTrackId); + auto const& bachTrack = tracks.rawIteratorAt(cascade.bachTrackId); + if (useV0BufferForCascades) { + // this processing path uses a buffer of V0s so that no + // additional minimization step is redone. It consumes less + // CPU at the cost of more memory. Since memory is a more + // limited commodity, this isn't the default option. + + // check if cached - if not, skip + if (v0Map[cascade.v0Id] < 0) { + // this V0 hasn't been stored / cached + products.cascdataLink(-1); + interlinks.cascadeToCascCores.push_back(-1); + continue; // didn't work out, skip + } + + if (!straHelper.buildCascadeCandidate(cascade.collisionId, pvX, pvY, pvZ, + v0sFromCascades[v0Map[cascade.v0Id]], + posTrack, + negTrack, + bachTrack, + mEnabledTables[kCascBBs], + cascadeBuilderOpts.useCascadeMomentumAtPrimVtx, + mEnabledTables[kCascCovs])) { + products.cascdataLink(-1); + interlinks.cascadeToCascCores.push_back(-1); + continue; // didn't work out, skip + } + } else { + // this processing path generates the entire cascade + // from tracks, without any need to have V0s generated. + if (!straHelper.buildCascadeCandidate(cascade.collisionId, pvX, pvY, pvZ, + posTrack, + negTrack, + bachTrack, + mEnabledTables[kCascBBs], + cascadeBuilderOpts.useCascadeMomentumAtPrimVtx, + mEnabledTables[kCascCovs])) { + products.cascdataLink(-1); + interlinks.cascadeToCascCores.push_back(-1); + continue; // didn't work out, skip + } + } + nCascades++; + + // generate analysis tables as required + if (mEnabledTables[kCascIndices]) { + products.cascidx(cascade.globalId, + straHelper.cascade.positiveTrack, straHelper.cascade.negativeTrack, + straHelper.cascade.bachelorTrack, straHelper.cascade.collisionId); + histos.fill(HIST("hTableBuildingStatistics"), kCascIndices); + } + if (mEnabledTables[kStoredCascCores]) { + products.cascdata(straHelper.cascade.charge, straHelper.cascade.massXi, straHelper.cascade.massOmega, + straHelper.cascade.cascadePosition[0], straHelper.cascade.cascadePosition[1], straHelper.cascade.cascadePosition[2], + straHelper.cascade.v0Position[0], straHelper.cascade.v0Position[1], straHelper.cascade.v0Position[2], + straHelper.cascade.positiveMomentum[0], straHelper.cascade.positiveMomentum[1], straHelper.cascade.positiveMomentum[2], + straHelper.cascade.negativeMomentum[0], straHelper.cascade.negativeMomentum[1], straHelper.cascade.negativeMomentum[2], + straHelper.cascade.bachelorMomentum[0], straHelper.cascade.bachelorMomentum[1], straHelper.cascade.bachelorMomentum[2], + straHelper.cascade.cascadeMomentum[0], straHelper.cascade.cascadeMomentum[1], straHelper.cascade.cascadeMomentum[2], + straHelper.cascade.v0DaughterDCA, straHelper.cascade.cascadeDaughterDCA, + straHelper.cascade.positiveDCAxy, straHelper.cascade.negativeDCAxy, + straHelper.cascade.bachelorDCAxy, straHelper.cascade.cascadeDCAxy, straHelper.cascade.cascadeDCAz); + histos.fill(HIST("hTableBuildingStatistics"), kStoredCascCores); + + // interlink always produced if cascades generated + products.cascdataLink(products.cascdata.lastIndex()); + interlinks.cascCoreToCascades.push_back(cascade.globalId); + interlinks.cascadeToCascCores.push_back(products.cascdata.lastIndex()); + } + + if (mEnabledTables[kCascTrackXs]) { + products.cascTrackXs(straHelper.cascade.positiveTrackX, straHelper.cascade.negativeTrackX, straHelper.cascade.bachelorTrackX); + histos.fill(HIST("hTableBuildingStatistics"), kCascTrackXs); + } + if (mEnabledTables[kCascBBs]) { + products.cascbb(straHelper.cascade.bachBaryonCosPA, straHelper.cascade.bachBaryonDCAxyToPV); + histos.fill(HIST("hTableBuildingStatistics"), kCascBBs); + } + if (mEnabledTables[kCascCovs]) { + products.casccovs(straHelper.cascade.covariance); + histos.fill(HIST("hTableBuildingStatistics"), kCascCovs); + } + + //_________________________________________________________ + // MC handling part + if constexpr (soa::is_table) { + // only worry about this if someone else worried about this + if ((mEnabledTables[kCascMCCores] || mEnabledTables[kMcCascLabels] || mEnabledTables[kCascMCCollRefs])) { + extractMonteCarloProperties(posTrack, negTrack, bachTrack, mcParticles); + + // Construct label table (note: this will be joinable with CascDatas) + if (mEnabledTables[kMcCascLabels]) { + products.casclabels( + thisCascInfo.label, thisCascInfo.motherLabel); + histos.fill(HIST("hTableBuildingStatistics"), kMcCascLabels); + } + + // Construct found tag + if (mEnabledTables[kCascFoundTags]) { + products.cascFoundTag(cascade.found); + histos.fill(HIST("hTableBuildingStatistics"), kCascFoundTags); + } + + // Mark mcParticle as recoed (no searching necessary afterwards) + if (thisCascInfo.label > -1) { + mcParticleIsReco[thisCascInfo.label] = true; + } + + if (cascadeBuilderOpts.mc_populateCascMCCoresSymmetric) { + if (mEnabledTables[kCascMCCores]) { + products.cascmccores( + thisCascInfo.pdgCode, thisCascInfo.pdgCodeMother, thisCascInfo.pdgCodeV0, thisCascInfo.isPhysicalPrimary, + thisCascInfo.pdgCodePositive, thisCascInfo.pdgCodeNegative, thisCascInfo.pdgCodeBachelor, + thisCascInfo.xyz[0], thisCascInfo.xyz[1], thisCascInfo.xyz[2], + thisCascInfo.lxyz[0], thisCascInfo.lxyz[1], thisCascInfo.lxyz[2], + thisCascInfo.posP[0], thisCascInfo.posP[1], thisCascInfo.posP[2], + thisCascInfo.negP[0], thisCascInfo.negP[1], thisCascInfo.negP[2], + thisCascInfo.bachP[0], thisCascInfo.bachP[1], thisCascInfo.bachP[2], + thisCascInfo.momentum[0], thisCascInfo.momentum[1], thisCascInfo.momentum[2]); + histos.fill(HIST("hTableBuildingStatistics"), kCascMCCores); + } + if (mEnabledTables[kCascMCCollRefs]) { + products.cascmccollrefs(thisCascInfo.mcCollision); + histos.fill(HIST("hTableBuildingStatistics"), kCascMCCollRefs); + } + } + + if (cascadeBuilderOpts.mc_populateCascMCCoresAsymmetric) { + int thisCascMCCoreIndex = -1; + // step 1: check if this element is already provided in the table + // using the packedIndices variable calculated above + for (uint32_t ii = 0; ii < mcCascinfos.size(); ii++) { + if (thisCascInfo.label == mcCascinfos[ii].label && mcCascinfos[ii].label > -1) { + thisCascMCCoreIndex = ii; + break; // this exists already in list + } + } + if (thisCascMCCoreIndex < 0) { + // this CascMCCore does not exist yet. Create it and reference it + thisCascMCCoreIndex = mcCascinfos.size(); + mcCascinfos.push_back(thisCascInfo); + } + if (mEnabledTables[kCascCoreMCLabels]) { + products.cascCoreMClabels(thisCascMCCoreIndex); // interlink: reconstructed -> MC index + histos.fill(HIST("hTableBuildingStatistics"), kCascCoreMCLabels); + } + } + + } // enabled tables check + + // if BB tags requested, generate them now + if (mEnabledTables[kMcCascBBTags]) { + bool bbTag = false; + if (bachTrack.has_mcParticle()) { + auto bachelorParticle = bachTrack.template mcParticle_as(); + if (bachelorParticle.pdgCode() == 211) { // pi+, look for antiproton in negative prong + if (negTrack.has_mcParticle()) { + auto baryonParticle = negTrack.template mcParticle_as(); + if (baryonParticle.has_mothers() && bachelorParticle.has_mothers() && baryonParticle.pdgCode() == -2212) { + for (const auto& baryonMother : baryonParticle.template mothers_as()) { + for (const auto& pionMother : bachelorParticle.template mothers_as()) { + if (baryonMother.globalIndex() == pionMother.globalIndex() && baryonMother.pdgCode() == -3122) { + bbTag = true; + } + } + } + } + } + } // end if-pion + if (bachelorParticle.pdgCode() == -211) { // pi-, look for proton in positive prong + if (posTrack.has_mcParticle()) { + auto baryonParticle = posTrack.template mcParticle_as(); + if (baryonParticle.has_mothers() && bachelorParticle.has_mothers() && baryonParticle.pdgCode() == 2212) { + for (const auto& baryonMother : baryonParticle.template mothers_as()) { + for (const auto& pionMother : bachelorParticle.template mothers_as()) { + if (baryonMother.globalIndex() == pionMother.globalIndex() && baryonMother.pdgCode() == 3122) { + bbTag = true; + } + } + } + } + } + } // end if-pion + } // end bachelor has mcparticle + // Construct label table (note: this will be joinable with CascDatas) + products.bbtags(bbTag); + histos.fill(HIST("hTableBuildingStatistics"), kMcCascBBTags); + } // end BB tag table enabled check + + } // constexpr requires mcParticles check + } // cascades loop + + //_________________________________________________________ + // MC handling part + if constexpr (soa::is_table) { + if ((mEnabledTables[kCascMCCores] || mEnabledTables[kMcCascLabels] || mEnabledTables[kCascMCCollRefs])) { + // now populate V0MCCores if in asymmetric mode + if (cascadeBuilderOpts.mc_populateCascMCCoresAsymmetric) { + // first step: add any un-recoed v0mmcores that were requested + for (const auto& mcParticle : mcParticles) { + thisCascInfo.pdgCode = -1, thisCascInfo.pdgCodeMother = -1; + thisCascInfo.pdgCodePositive = -1, thisCascInfo.pdgCodeNegative = -1; + thisCascInfo.pdgCodeBachelor = -1, thisCascInfo.pdgCodeV0 = -1; + thisCascInfo.isPhysicalPrimary = false; + thisCascInfo.xyz[0] = 0.0f, thisCascInfo.xyz[1] = 0.0f, thisCascInfo.xyz[2] = 0.0f; + thisCascInfo.lxyz[0] = 0.0f, thisCascInfo.lxyz[1] = 0.0f, thisCascInfo.lxyz[2] = 0.0f; + thisCascInfo.posP[0] = 0.0f, thisCascInfo.posP[1] = 0.0f, thisCascInfo.posP[2] = 0.0f; + thisCascInfo.negP[0] = 0.0f, thisCascInfo.negP[1] = 0.0f, thisCascInfo.negP[2] = 0.0f; + thisCascInfo.bachP[0] = 0.0f, thisCascInfo.bachP[1] = 0.0f, thisCascInfo.bachP[2] = 0.0f; + thisCascInfo.momentum[0] = 0.0f, thisCascInfo.momentum[1] = 0.0f, thisCascInfo.momentum[2] = 0.0f; + thisCascInfo.label = -1, thisCascInfo.motherLabel = -1; + thisCascInfo.mcParticlePositive = -1; + thisCascInfo.mcParticleNegative = -1; + thisCascInfo.mcParticleBachelor = -1; + + if (mcParticleIsReco[mcParticle.globalIndex()] == true) + continue; // skip if already created in list + + if (std::fabs(mcParticle.y()) > cascadeBuilderOpts.mc_rapidityWindow) + continue; // skip outside midrapidity + + if ( + (cascadeBuilderOpts.mc_addGeneratedXiMinus && mcParticle.pdgCode() == 3312) || + (cascadeBuilderOpts.mc_addGeneratedXiPlus && mcParticle.pdgCode() == -3312) || + (cascadeBuilderOpts.mc_addGeneratedOmegaMinus && mcParticle.pdgCode() == 3334) || + (cascadeBuilderOpts.mc_addGeneratedOmegaPlus && mcParticle.pdgCode() == -3334)) { + thisCascInfo.pdgCode = mcParticle.pdgCode(); + thisCascInfo.isPhysicalPrimary = mcParticle.isPhysicalPrimary(); + + if (mcParticle.has_mcCollision()) { + thisCascInfo.mcCollision = mcParticle.mcCollisionId(); // save this reference, please + } + thisCascInfo.momentum[0] = mcParticle.px(); + thisCascInfo.momentum[1] = mcParticle.py(); + thisCascInfo.momentum[2] = mcParticle.pz(); + thisCascInfo.label = mcParticle.globalIndex(); + + if (mcParticle.has_daughters()) { + auto const& daughters = mcParticle.template daughters_as(); + for (const auto& dau : daughters) { + if (dau.getProcess() != 4) // check whether the daughter comes from a decay + continue; + + if (std::abs(dau.pdgCode()) == 211 || std::abs(dau.pdgCode()) == 321) { + thisCascInfo.pdgCodeBachelor = dau.pdgCode(); + thisCascInfo.bachP[0] = dau.px(); + thisCascInfo.bachP[1] = dau.py(); + thisCascInfo.bachP[2] = dau.pz(); + thisCascInfo.xyz[0] = dau.vx(); + thisCascInfo.xyz[1] = dau.vy(); + thisCascInfo.xyz[2] = dau.vz(); + thisCascInfo.mcParticleBachelor = dau.globalIndex(); + } + if (std::abs(dau.pdgCode()) == 2212) { + thisCascInfo.pdgCodeV0 = dau.pdgCode(); + + for (const auto& v0Dau : dau.template daughters_as()) { + if (v0Dau.getProcess() != 4) + continue; + + if (v0Dau.pdgCode() > 0) { + thisCascInfo.pdgCodePositive = v0Dau.pdgCode(); + thisCascInfo.processPositive = v0Dau.getProcess(); + thisCascInfo.posP[0] = v0Dau.px(); + thisCascInfo.posP[1] = v0Dau.py(); + thisCascInfo.posP[2] = v0Dau.pz(); + thisCascInfo.lxyz[0] = v0Dau.vx(); + thisCascInfo.lxyz[1] = v0Dau.vy(); + thisCascInfo.lxyz[2] = v0Dau.vz(); + thisCascInfo.mcParticlePositive = v0Dau.globalIndex(); + } + if (v0Dau.pdgCode() < 0) { + thisCascInfo.pdgCodeNegative = v0Dau.pdgCode(); + thisCascInfo.processNegative = v0Dau.getProcess(); + thisCascInfo.negP[0] = v0Dau.px(); + thisCascInfo.negP[1] = v0Dau.py(); + thisCascInfo.negP[2] = v0Dau.pz(); + thisCascInfo.mcParticleNegative = v0Dau.globalIndex(); + } + } + } + } + } + + // if I got here, it means this MC particle was not recoed and is of interest. Add it please + mcCascinfos.push_back(thisCascInfo); + } + } + + for (const auto& thisInfoToFill : mcCascinfos) { + if (mEnabledTables[kCascMCCores]) { + products.cascmccores( // a lot of the info below will be compressed in case of not-recoed MC (good!) + thisInfoToFill.pdgCode, thisInfoToFill.pdgCodeMother, thisInfoToFill.pdgCodeV0, thisInfoToFill.isPhysicalPrimary, + thisInfoToFill.pdgCodePositive, thisInfoToFill.pdgCodeNegative, thisInfoToFill.pdgCodeBachelor, + thisInfoToFill.xyz[0], thisInfoToFill.xyz[1], thisInfoToFill.xyz[2], + thisInfoToFill.lxyz[0], thisInfoToFill.lxyz[1], thisInfoToFill.lxyz[2], + thisInfoToFill.posP[0], thisInfoToFill.posP[1], thisInfoToFill.posP[2], + thisInfoToFill.negP[0], thisInfoToFill.negP[1], thisInfoToFill.negP[2], + thisInfoToFill.bachP[0], thisInfoToFill.bachP[1], thisInfoToFill.bachP[2], + thisInfoToFill.momentum[0], thisInfoToFill.momentum[1], thisInfoToFill.momentum[2]); + histos.fill(HIST("hTableBuildingStatistics"), kCascMCCores); + } + if (mEnabledTables[kCascMCCollRefs]) { + products.cascmccollrefs(thisInfoToFill.mcCollision); + histos.fill(HIST("hTableBuildingStatistics"), kCascMCCollRefs); + } + } + } + } // enabled tables check + } // constexpr requires mcParticles check + + LOGF(debug, "Cascades in DF: %i, cascades built: %i", cascades.size(), nCascades); + } + + //__________________________________________________ + template + void buildKFCascades(TCollisions const& collisions, TCascades const& cascades, TTracks const& tracks, TMCParticles const& mcParticles) + { + if (!mEnabledTables[kStoredKFCascCores]) { + return; // don't do if no request for cascades in place + } + int nCascades = 0; + // Loops over all cascades in the time frame + histos.fill(HIST("hInputStatistics"), kStoredKFCascCores, cascades.size()); + for (size_t icascade = 0; icascade < cascades.size(); icascade++) { + // Get tracks and generate candidate + auto const& cascade = cascades[sorted_cascade[icascade]]; + // if collisionId positive: get vertex, negative: origin + // could be replaced by mean vertex (but without much benefit...) + float pvX = 0.0f, pvY = 0.0f, pvZ = 0.0f; + if (cascade.collisionId >= 0) { + auto const& collision = collisions.rawIteratorAt(cascade.collisionId); + pvX = collision.posX(); + pvY = collision.posY(); + pvZ = collision.posZ(); + } + auto const& posTrack = tracks.rawIteratorAt(cascade.posTrackId); + auto const& negTrack = tracks.rawIteratorAt(cascade.negTrackId); + auto const& bachTrack = tracks.rawIteratorAt(cascade.bachTrackId); + if (!straHelper.buildCascadeCandidateWithKF(cascade.collisionId, pvX, pvY, pvZ, + posTrack, + negTrack, + bachTrack, + mEnabledTables[kCascBBs], + cascadeBuilderOpts.kfConstructMethod, + cascadeBuilderOpts.kfTuneForOmega, + cascadeBuilderOpts.kfUseV0MassConstraint, + cascadeBuilderOpts.kfUseCascadeMassConstraint, + cascadeBuilderOpts.kfDoDCAFitterPreMinimV0, + cascadeBuilderOpts.kfDoDCAFitterPreMinimCasc)) { + products.kfcascdataLink(-1); + interlinks.cascadeToKFCascCores.push_back(-1); + continue; // didn't work out, skip + } + nCascades++; + + // generate analysis tables as required + if (mEnabledTables[kKFCascIndices]) { + products.kfcascidx(cascade.globalId, + straHelper.cascade.positiveTrack, straHelper.cascade.negativeTrack, + straHelper.cascade.bachelorTrack, straHelper.cascade.collisionId); + histos.fill(HIST("hTableBuildingStatistics"), kKFCascIndices); + } + if (mEnabledTables[kStoredKFCascCores]) { + products.kfcascdata(straHelper.cascade.charge, straHelper.cascade.massXi, straHelper.cascade.massOmega, + straHelper.cascade.cascadePosition[0], straHelper.cascade.cascadePosition[1], straHelper.cascade.cascadePosition[2], + straHelper.cascade.v0Position[0], straHelper.cascade.v0Position[1], straHelper.cascade.v0Position[2], + straHelper.cascade.positivePosition[0], straHelper.cascade.positivePosition[1], straHelper.cascade.positivePosition[2], + straHelper.cascade.negativePosition[0], straHelper.cascade.negativePosition[1], straHelper.cascade.negativePosition[2], + straHelper.cascade.positiveMomentum[0], straHelper.cascade.positiveMomentum[1], straHelper.cascade.positiveMomentum[2], + straHelper.cascade.negativeMomentum[0], straHelper.cascade.negativeMomentum[1], straHelper.cascade.negativeMomentum[2], + straHelper.cascade.bachelorMomentum[0], straHelper.cascade.bachelorMomentum[1], straHelper.cascade.bachelorMomentum[2], + straHelper.cascade.v0Momentum[0], straHelper.cascade.v0Momentum[1], straHelper.cascade.v0Momentum[2], + straHelper.cascade.cascadeMomentum[0], straHelper.cascade.cascadeMomentum[1], straHelper.cascade.cascadeMomentum[2], + straHelper.cascade.v0DaughterDCA, straHelper.cascade.cascadeDaughterDCA, + straHelper.cascade.positiveDCAxy, straHelper.cascade.negativeDCAxy, + straHelper.cascade.bachelorDCAxy, straHelper.cascade.cascadeDCAxy, straHelper.cascade.cascadeDCAz, + straHelper.cascade.kfMLambda, straHelper.cascade.kfV0Chi2, straHelper.cascade.kfCascadeChi2); + histos.fill(HIST("hTableBuildingStatistics"), kStoredKFCascCores); + + // interlink always produced if cascades generated + products.kfcascdataLink(products.kfcascdata.lastIndex()); + interlinks.kfCascCoreToCascades.push_back(cascade.globalId); + interlinks.cascadeToKFCascCores.push_back(products.kfcascdata.lastIndex()); + } + if (mEnabledTables[kKFCascCovs]) { + products.kfcasccovs(straHelper.cascade.covariance, straHelper.cascade.kfTrackCovarianceV0, straHelper.cascade.kfTrackCovariancePos, straHelper.cascade.kfTrackCovarianceNeg); + histos.fill(HIST("hTableBuildingStatistics"), kKFCascCovs); + } + + //_________________________________________________________ + // MC handling part (labels only) + if constexpr (soa::is_table) { + // only worry about this if someone else worried about this + if ((mEnabledTables[kMcKFCascLabels])) { + extractMonteCarloProperties(posTrack, negTrack, bachTrack, mcParticles); + + // Construct label table (note: this will be joinable with KFCascDatas) + products.kfcasclabels(thisCascInfo.label); + histos.fill(HIST("hTableBuildingStatistics"), kMcKFCascLabels); + } // enabled tables check + } // constexpr requires mcParticles check + } // end loop over cascades + + LOGF(debug, "KF Cascades in DF: %i, KF cascades built: %i", cascades.size(), nCascades); + } + + //__________________________________________________ + template + void buildTrackedCascades(TCollisions const& collisions, TStrangeTracks const& cascadeTracks, TMCParticles const& mcParticles) + { + if (!mEnabledTables[kStoredTraCascCores] || mc_findableMode.value != 0) { + return; // don't do if no request for cascades in place or findable mode used + } + int nCascades = 0; + // Loops over all V0s in the time frame + histos.fill(HIST("hInputStatistics"), kStoredTraCascCores, cascadeTracks.size()); + for (const auto& cascadeTrack : cascadeTracks) { + // Get tracks and generate candidate + if (!cascadeTrack.has_track()) + continue; // safety (should be fine but depends on future stratrack dev) + + auto const& strangeTrack = cascadeTrack.template track_as(); + + // if collisionId positive: get vertex, negative: origin + // could be replaced by mean vertex (but without much benefit...) + float pvX = 0.0f, pvY = 0.0f, pvZ = 0.0f; + if (strangeTrack.has_collision()) { + auto const& collision = collisions.rawIteratorAt(strangeTrack.collisionId()); + pvX = collision.posX(); + pvY = collision.posY(); + pvZ = collision.posZ(); + } + auto const& cascade = cascadeTrack.cascade(); + auto const& v0 = cascade.v0(); + auto const& posTrack = v0.template posTrack_as(); + auto const& negTrack = v0.template negTrack_as(); + auto const& bachTrack = cascade.template bachelor_as(); + if (!straHelper.buildCascadeCandidate(strangeTrack.collisionId(), pvX, pvY, pvZ, + posTrack, + negTrack, + bachTrack, + mEnabledTables[kCascBBs], + cascadeBuilderOpts.useCascadeMomentumAtPrimVtx, + mEnabledTables[kCascCovs])) { + products.tracascdataLink(-1); + interlinks.cascadeToTraCascCores.push_back(-1); + continue; // didn't work out, skip + } + + // recalculate DCAxy, DCAz with strange track + auto strangeTrackParCov = getTrackParCov(strangeTrack); + gpu::gpustd::array dcaInfo; + strangeTrackParCov.setPID(o2::track::PID::XiMinus); // FIXME: not OK for omegas + o2::base::Propagator::Instance()->propagateToDCABxByBz({pvX, pvY, pvZ}, strangeTrackParCov, 2.f, straHelper.fitter.getMatCorrType(), &dcaInfo); + straHelper.cascade.cascadeDCAxy = dcaInfo[0]; + straHelper.cascade.cascadeDCAz = dcaInfo[1]; + + // get momentum from strange track (should not be very different) + strangeTrackParCov.getPxPyPzGlo(straHelper.cascade.cascadeMomentum); + + // accounting + nCascades++; + + // generate analysis tables as required + if (mEnabledTables[kTraCascIndices]) { + products.tracascidx(cascade.globalIndex(), + straHelper.cascade.positiveTrack, straHelper.cascade.negativeTrack, + straHelper.cascade.bachelorTrack, cascadeTrack.trackId(), straHelper.cascade.collisionId); + histos.fill(HIST("hTableBuildingStatistics"), kTraCascIndices); + } + if (mEnabledTables[kStoredTraCascCores]) { + products.tracascdata(straHelper.cascade.charge, cascadeTrack.xiMass(), cascadeTrack.omegaMass(), + cascadeTrack.decayX(), cascadeTrack.decayY(), cascadeTrack.decayZ(), + straHelper.cascade.v0Position[0], straHelper.cascade.v0Position[1], straHelper.cascade.v0Position[2], + straHelper.cascade.positiveMomentum[0], straHelper.cascade.positiveMomentum[1], straHelper.cascade.positiveMomentum[2], + straHelper.cascade.negativeMomentum[0], straHelper.cascade.negativeMomentum[1], straHelper.cascade.negativeMomentum[2], + straHelper.cascade.bachelorMomentum[0], straHelper.cascade.bachelorMomentum[1], straHelper.cascade.bachelorMomentum[2], + straHelper.cascade.cascadeMomentum[0], straHelper.cascade.cascadeMomentum[1], straHelper.cascade.cascadeMomentum[2], + straHelper.cascade.v0DaughterDCA, straHelper.cascade.cascadeDaughterDCA, + straHelper.cascade.positiveDCAxy, straHelper.cascade.negativeDCAxy, + straHelper.cascade.bachelorDCAxy, straHelper.cascade.cascadeDCAxy, straHelper.cascade.cascadeDCAz, + cascadeTrack.matchingChi2(), cascadeTrack.topologyChi2(), cascadeTrack.itsClsSize()); + histos.fill(HIST("hTableBuildingStatistics"), kStoredTraCascCores); + + // interlink always produced if base core table generated + products.tracascdataLink(products.tracascdata.lastIndex()); + interlinks.traCascCoreToCascades.push_back(cascade.globalIndex()); + interlinks.cascadeToTraCascCores.push_back(products.tracascdata.lastIndex()); + } + if (mEnabledTables[kCascCovs]) { + std::array traCovMat = {0.}; + strangeTrackParCov.getCovXYZPxPyPzGlo(traCovMat); + float traCovMatArray[21]; + for (int ii = 0; ii < 21; ii++) { + traCovMatArray[ii] = traCovMat[ii]; + } + products.tracasccovs(traCovMatArray); + histos.fill(HIST("hTableBuildingStatistics"), kCascCovs); + } + + //_________________________________________________________ + // MC handling part (labels only) + if constexpr (soa::is_table) { + // only worry about this if someone else worried about this + if ((mEnabledTables[kMcTraCascLabels])) { + extractMonteCarloProperties(posTrack, negTrack, bachTrack, mcParticles); + + // Construct label table (note: this will be joinable with KFCascDatas) + products.tracasclabels(thisCascInfo.label); + histos.fill(HIST("hTableBuildingStatistics"), kMcTraCascLabels); + } // enabled tables check + } // constexpr requires mcParticles check + } // end loop over cascades + LOGF(debug, "Tracked cascades in DF: %i, tracked cascades built: %i", cascadeTracks.size(), nCascades); + } + + //__________________________________________________ + // MC kink handling + template + int getOriginatingParticle(mcpart const& part, int& indexForPositionOfDecay, bool treatPiToMuDecays) + { + int returnValue = -1; + if (part.has_mothers()) { + auto const& motherList = part.template mothers_as(); + if (motherList.size() == 1) { + for (const auto& mother : motherList) { + if (std::abs(part.pdgCode()) == 13 && treatPiToMuDecays) { + // muon decay, de-ref mother twice + if (mother.has_mothers()) { + auto grandMotherList = mother.template mothers_as(); + if (grandMotherList.size() == 1) { + for (const auto& grandMother : grandMotherList) { + returnValue = grandMother.globalIndex(); + indexForPositionOfDecay = mother.globalIndex(); // for V0 decay position: grab muon + } + } + } + } else { + returnValue = mother.globalIndex(); + indexForPositionOfDecay = part.globalIndex(); + } + } + } + } + return returnValue; + } + + //__________________________________________________ + template + void dataProcess(TCollisions const& collisions, TMCCollisions const& mccollisions, TV0s const& v0s, TCascades const& cascades, TTrackedCascades const& trackedCascades, TTracks const& tracks, TBCs const& bcs, TMCParticles const& mcParticles) + { + if (!initCCDB(bcs, collisions)) + return; + + // reset vectors for cascade interlinks + resetInterlinks(); + + // prepare v0List, cascadeList + prepareBuildingLists(collisions, mccollisions, v0s, cascades, tracks, mcParticles); + + // mark V0s that will be buffered for the cascade building + markV0sUsedInCascades(v0List, cascadeList, trackedCascades); + + // build V0s + buildV0s(collisions, v0List, tracks, mcParticles); + + // build cascades + buildCascades(collisions, cascadeList, tracks, mcParticles); + buildKFCascades(collisions, cascadeList, tracks, mcParticles); + + // build tracked cascades only if subscription is Run 3 like (doesn't exist in Run 2) + if constexpr (soa::is_table) { + buildTrackedCascades(collisions, trackedCascades, mcParticles); + } + + populateCascadeInterlinks(); + } + + void processRealData(soa::Join const& collisions, aod::V0s const& v0s, aod::Cascades const& cascades, aod::TrackedCascades const& trackedCascades, FullTracksExtIU const& tracks, aod::BCsWithTimestamps const& bcs) + { + dataProcess(collisions, static_cast(nullptr), v0s, cascades, trackedCascades, tracks, bcs, static_cast(nullptr)); + } + + void processRealDataRun2(soa::Join const& collisions, aod::V0s const& v0s, aod::Cascades const& cascades, FullTracksExt const& tracks, aod::BCsWithTimestamps const& bcs) + { + dataProcess(collisions, static_cast(nullptr), v0s, cascades, static_cast(nullptr), tracks, bcs, static_cast(nullptr)); + } + + void processMonteCarlo(soa::Join const& collisions, aod::McCollisions const& mccollisions, aod::V0s const& v0s, aod::Cascades const& cascades, aod::TrackedCascades const& trackedCascades, FullTracksExtLabeledIU const& tracks, aod::BCsWithTimestamps const& bcs, aod::McParticles const& mcParticles) + { + dataProcess(collisions, mccollisions, v0s, cascades, trackedCascades, tracks, bcs, mcParticles); + } + + void processMonteCarloRun2(soa::Join const& collisions, aod::McCollisions const& mccollisions, aod::V0s const& v0s, aod::Cascades const& cascades, FullTracksExtLabeled const& tracks, aod::BCsWithTimestamps const& bcs, aod::McParticles const& mcParticles) + { + dataProcess(collisions, mccollisions, v0s, cascades, static_cast(nullptr), tracks, bcs, mcParticles); + } + + PROCESS_SWITCH(StrangenessBuilder, processRealData, "process real data", true); + PROCESS_SWITCH(StrangenessBuilder, processRealDataRun2, "process real data (Run 2)", false); + PROCESS_SWITCH(StrangenessBuilder, processMonteCarlo, "process monte carlo", false); + PROCESS_SWITCH(StrangenessBuilder, processMonteCarloRun2, "process monte carlo (Run 2)", false); +}; + +// Extends the v0data table with expression columns +struct strangenessbuilderInitializer { + Spawns v0cores; + Spawns cascdataext; + Spawns kfcascdataext; + Spawns tracascdataext; + void init(InitContext const&) {} +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/v0qaanalysis.cxx b/PWGLF/TableProducer/Strangeness/v0qaanalysis.cxx index ad48399b5b6..bafe557c237 100644 --- a/PWGLF/TableProducer/Strangeness/v0qaanalysis.cxx +++ b/PWGLF/TableProducer/Strangeness/v0qaanalysis.cxx @@ -13,6 +13,9 @@ /// /// \author Francesca Ercolessi (francesca.ercolessi@cern.ch) +#include +#include + #include "Framework/AnalysisTask.h" #include "Common/DataModel/TrackSelectionTables.h" #include "PWGLF/DataModel/LFStrangenessTables.h" @@ -23,6 +26,8 @@ #include "Common/DataModel/Centrality.h" #include "CommonConstants/PhysicsConstants.h" #include "Framework/O2DatabasePDGPlugin.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.h" using namespace o2; using namespace o2::framework; @@ -38,7 +43,7 @@ void customize(std::vector& workflowOptions) using DauTracks = soa::Join; using DauTracksMC = soa::Join; -using V0Collisions = soa::Join; +using V0Collisions = soa::Join; struct LfV0qaanalysis { @@ -64,46 +69,88 @@ struct LfV0qaanalysis { } LOG(info) << "Number of process functions enabled: " << nProc; - registry.add("hNEvents", "hNEvents", {HistType::kTH1I, {{4, 0.f, 4.f}}}); + registry.add("hNEvents", "hNEvents", {HistType::kTH1D, {{10, 0.f, 10.f}}}); registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(1, "all"); registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(2, "sel8"); - registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(3, "zvertex"); - registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(4, "Selected"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(3, "TVX"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(4, "zvertex"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(5, "TFBorder"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(6, "ITSROFBorder"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(7, "isTOFVertexMatched"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(8, "isNoSameBunchPileup"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(9, "Applied selection"); registry.add("hCentFT0M", "hCentFT0M", {HistType::kTH1F, {{1000, 0.f, 100.f}}}); - registry.add("hCentFV0A", "hCentFV0A", {HistType::kTH1F, {{1000, 0.f, 100.f}}}); + registry.add("hCentNGlobals", "hCentNGlobals", {HistType::kTH1F, {{1000, 0.f, 100.f}}}); if (isMC) { - registry.add("hNEventsMCGen", "hNEventsMCGen", {HistType::kTH1I, {{4, 0.f, 4.f}}}); + registry.add("hCentFT0M_RecoColl_MC", "hCentFT0M_RecoColl_MC", {HistType::kTH1F, {{1000, 0.f, 100.f}}}); + registry.add("hCentFT0M_RecoColl_MC_INELgt0", "hCentFT0M_RecoColl_MC_INELgt0", {HistType::kTH1F, {{1000, 0.f, 100.f}}}); + registry.add("hCentFT0M_GenRecoColl_MC", "hCentFT0M_GenRecoColl_MC", {HistType::kTH1F, {{1000, 0.f, 100.f}}}); + registry.add("hCentFT0M_GenRecoColl_MC_INELgt0", "hCentFT0M_GenRecoColl_MC_INELgt0", {HistType::kTH1F, {{1000, 0.f, 100.f}}}); + registry.add("hCentFT0M_GenColl_MC", "hCentFT0M_GenColl_MC", {HistType::kTH1F, {{1000, 0.f, 100.f}}}); + registry.add("hCentFT0M_GenColl_MC_INELgt0", "hCentFT0M_GenColl_MC_INELgt0", {HistType::kTH1F, {{1000, 0.f, 100.f}}}); + registry.add("hNEventsMCGen", "hNEventsMCGen", {HistType::kTH1D, {{4, 0.f, 4.f}}}); registry.get(HIST("hNEventsMCGen"))->GetXaxis()->SetBinLabel(1, "all"); registry.get(HIST("hNEventsMCGen"))->GetXaxis()->SetBinLabel(2, "zvertex_true"); registry.get(HIST("hNEventsMCGen"))->GetXaxis()->SetBinLabel(3, "INELgt0_true"); - registry.get(HIST("hNEventsMCGen"))->GetXaxis()->SetBinLabel(4, "sel8_true"); - registry.add("hNEventsMC_AllColl", "hNEventsMC_AllColl", {HistType::kTH1I, {{2, 0.f, 2.f}}}); - registry.add("hNEventsMC_RecoColl", "hNEventsMC_RecoColl", {HistType::kTH1I, {{2, 0.f, 2.f}}}); - registry.add("Reconstructed_MCRecoColl_INEL_K0Short", "Reconstructed_MCRecoColl_INEL_K0Short", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); - registry.add("Reconstructed_MCRecoColl_INEL_Lambda", "Reconstructed_MCRecoColl_INEL_Lambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); - registry.add("Reconstructed_MCRecoColl_INEL_AntiLambda", "Reconstructed_MCRecoColl_INEL_AntiLambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); - registry.add("Reconstructed_MCRecoColl_INELgt0_K0Short", "Reconstructed_MCRecoColl_INELgt0_K0Short", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); - registry.add("Reconstructed_MCRecoColl_INELgt0_Lambda", "Reconstructed_MCRecoColl_INELgt0_Lambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); - registry.add("Reconstructed_MCRecoColl_INELgt0_AntiLambda", "Reconstructed_MCRecoColl_INELgt0_AntiLambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); - registry.add("Generated_MCRecoColl_INEL_K0Short", "Generated_MCRecoColl_INEL_K0Short", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); - registry.add("Generated_MCRecoColl_INEL_Lambda", "Generated_MCRecoColl_INEL_Lambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); - registry.add("Generated_MCRecoColl_INEL_AntiLambda", "Generated_MCRecoColl_INEL_AntiLambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); - registry.add("Generated_MCAllColl_INEL_K0Short", "Generated_MCAllColl_INEL_K0Short", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); - registry.add("Generated_MCAllColl_INEL_Lambda", "Generated_MCAllColl_INEL_Lambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); - registry.add("Generated_MCAllColl_INEL_AntiLambda", "Generated_MCAllColl_INEL_AntiLambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); - registry.add("Generated_MCRecoColl_INELgt0_K0Short", "Generated_MCRecoColl_INELgt0_K0Short", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); - registry.add("Generated_MCRecoColl_INELgt0_Lambda", "Generated_MCRecoColl_INELgt0_Lambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); - registry.add("Generated_MCRecoColl_INELgt0_AntiLambda", "Generated_MCRecoColl_INELgt0_AntiLambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); - registry.add("Generated_MCAllColl_INELgt0_K0Short", "Generated_MCAllColl_INELgt0_K0Short", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); - registry.add("Generated_MCAllColl_INELgt0_Lambda", "Generated_MCAllColl_INELgt0_Lambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); - registry.add("Generated_MCAllColl_INELgt0_AntiLambda", "Generated_MCAllColl_INELgt0_AntiLambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {100, -1.f, +1.f}}}); + registry.add("hNEventsMCGenReco", "hNEventsMCGenReco", {HistType::kTH1D, {{2, 0.f, 2.f}}}); + registry.get(HIST("hNEventsMCGenReco"))->GetXaxis()->SetBinLabel(1, "INEL"); + registry.get(HIST("hNEventsMCGenReco"))->GetXaxis()->SetBinLabel(2, "INELgt0"); + registry.add("hNEventsMCReco", "hNEventsMCReco", {HistType::kTH1D, {{4, 0.f, 4.f}}}); + registry.get(HIST("hNEventsMCReco"))->GetXaxis()->SetBinLabel(1, "all"); + registry.get(HIST("hNEventsMCReco"))->GetXaxis()->SetBinLabel(2, "pass ev sel"); + registry.get(HIST("hNEventsMCReco"))->GetXaxis()->SetBinLabel(3, "INELgt0"); + registry.get(HIST("hNEventsMCReco"))->GetXaxis()->SetBinLabel(4, "check"); + registry.add("Reconstructed_MCRecoColl_INEL_K0Short", "Reconstructed_MCRecoColl_INEL_K0Short", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Reconstructed_MCRecoColl_INEL_Lambda", "Reconstructed_MCRecoColl_INEL_Lambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Reconstructed_MCRecoColl_INEL_AntiLambda", "Reconstructed_MCRecoColl_INEL_AntiLambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Reconstructed_MCRecoColl_INELgt0_K0Short", "Reconstructed_MCRecoColl_INELgt0_K0Short", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Reconstructed_MCRecoColl_INELgt0_Lambda", "Reconstructed_MCRecoColl_INELgt0_Lambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Reconstructed_MCRecoColl_INELgt0_AntiLambda", "Reconstructed_MCRecoColl_INELgt0_AntiLambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCGenRecoColl_INEL_K0Short", "Generated_MCGenRecoColl_INEL_K0Short", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCGenRecoColl_INEL_Lambda", "Generated_MCGenRecoColl_INEL_Lambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCGenRecoColl_INEL_AntiLambda", "Generated_MCGenRecoColl_INEL_AntiLambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCGenRecoColl_INEL_XiMinus", "Generated_MCGenRecoColl_INEL_XiMinus", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCGenRecoColl_INEL_XiPlus", "Generated_MCGenRecoColl_INEL_XiPlus", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCRecoColl_INEL_K0Short", "Generated_MCRecoColl_INEL_K0Short", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCRecoColl_INEL_Lambda", "Generated_MCRecoColl_INEL_Lambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCRecoColl_INEL_AntiLambda", "Generated_MCRecoColl_INEL_AntiLambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCRecoCollCheck_INEL_K0Short", "Generated_MCRecoCollCheck_INEL_K0Short", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCRecoCollCheck_INEL_Lambda", "Generated_MCRecoCollCheck_INEL_Lambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCRecoCollCheck_INEL_AntiLambda", "Generated_MCRecoCollCheck_INEL_AntiLambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCGenColl_INEL_K0Short", "Generated_MCGenColl_INEL_K0Short", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCGenColl_INEL_Lambda", "Generated_MCGenColl_INEL_Lambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCGenColl_INEL_AntiLambda", "Generated_MCGenColl_INEL_AntiLambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCGenRecoColl_INELgt0_K0Short", "Generated_MCGenRecoColl_INELgt0_K0Short", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCGenRecoColl_INELgt0_Lambda", "Generated_MCGenRecoColl_INELgt0_Lambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCGenRecoColl_INELgt0_AntiLambda", "Generated_MCGenRecoColl_INELgt0_AntiLambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCGenRecoColl_INELgt0_XiMinus", "Generated_MCGenRecoColl_INELgt0_XiMinus", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCGenRecoColl_INELgt0_XiPlus", "Generated_MCGenRecoColl_INELgt0_XiPlus", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCRecoColl_INELgt0_K0Short", "Generated_MCRecoColl_INELgt0_K0Short", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCRecoColl_INELgt0_Lambda", "Generated_MCRecoColl_INELgt0_Lambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCRecoColl_INELgt0_AntiLambda", "Generated_MCRecoColl_INELgt0_AntiLambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCRecoCollCheck_INELgt0_K0Short", "Generated_MCRecoCollCheck_INELgt0_K0Short", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCRecoCollCheck_INELgt0_Lambda", "Generated_MCRecoCollCheck_INELgt0_Lambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCRecoCollCheck_INELgt0_AntiLambda", "Generated_MCRecoCollCheck_INELgt0_AntiLambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCGenColl_INELgt0_K0Short", "Generated_MCGenColl_INELgt0_K0Short", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCGenColl_INELgt0_Lambda", "Generated_MCGenColl_INELgt0_Lambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); + registry.add("Generated_MCGenColl_INELgt0_AntiLambda", "Generated_MCGenColl_INELgt0_AntiLambda", {HistType::kTH2F, {{250, 0.f, 25.f}, {1000, 0.f, 100.f}}}); } + registry.print(); } // Event selection criteria Configurable cutzvertex{"cutzvertex", 15.0f, "Accepted z-vertex range (cm)"}; - Configurable sel8{"sel8", 1, "Apply sel8 event selection"}; + Configurable MCcutzvertex{"MCcutzvertex", 100.0f, "Accepted true MC z-vertex range (cm)"}; + Configurable sel8{"sel8", 0, "Apply sel8 event selection"}; + Configurable isMC{"isMC", 0, "Is MC"}; + Configurable isTriggerTVX{"isTriggerTVX", 1, "Is Trigger TVX"}; + Configurable isNoTimeFrameBorder{"isNoTimeFrameBorder", 1, "Is No Time Frame Border"}; + Configurable isNoITSROFrameBorder{"isNoITSROFrameBorder", 1, "Is No ITS Readout Frame Border"}; + Configurable isVertexTOFmatched{"isVertexTOFmatched", 0, "Is Vertex TOF matched"}; + Configurable isNoSameBunchPileup{"isNoSameBunchPileup", 0, "isNoSameBunchPileup"}; + Configurable v0TypeSelection{"v0TypeSelection", 1, "select on a certain V0 type (leave negative if no selection desired)"}; + Configurable NotITSAfterburner{"NotITSAfterburner", 0, "NotITSAfterburner"}; // V0 selection criteria Configurable v0cospa{"v0cospa", 0.97, "V0 CosPA"}; @@ -112,51 +159,42 @@ struct LfV0qaanalysis { Configurable dcapostopv{"dcapostopv", 0.0, "DCA Pos To PV"}; Configurable v0radius{"v0radius", 0.0, "Radius"}; Configurable etadau{"etadau", 0.8, "Eta Daughters"}; - Configurable isMC{"isMC", 0, "Is MC"}; // Event selection template bool AcceptEvent(TCollision const& collision) { + registry.fill(HIST("hNEvents"), 0.5); if (sel8 && !collision.sel8()) { return false; } registry.fill(HIST("hNEvents"), 1.5); - - if (TMath::Abs(collision.posZ()) > cutzvertex) { + if (isTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { return false; } registry.fill(HIST("hNEvents"), 2.5); - - return true; - } - - // Event selection - template - bool isTrueINELgt0(TMcParticles particles) - { - int nPart = 0; - for (const auto& particle : particles) { - if (particle.isPhysicalPrimary() == 0) - continue; // consider only primaries - - const auto& pdgInfo = pdgDB->GetParticle(particle.pdgCode()); - if (!pdgInfo) { - continue; - } - if (TMath::Abs(pdgInfo->Charge()) < 0.001) { - continue; // consider only charged particles - } - - if (particle.eta() < -1.0 || particle.eta() > 1.0) - continue; // consider only particles in |eta| < 1 - - nPart++; + if (std::abs(collision.posZ()) > cutzvertex) { + return false; + } + registry.fill(HIST("hNEvents"), 3.5); + if (isNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } + registry.fill(HIST("hNEvents"), 4.5); + if (isNoITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return false; + } + registry.fill(HIST("hNEvents"), 5.5); + if (isVertexTOFmatched && !collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { + return false; } - if (nPart > 0) - return true; - else + registry.fill(HIST("hNEvents"), 6.5); + if (isNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { return false; + } + registry.fill(HIST("hNEvents"), 7.5); + + return true; } Filter preFilterV0 = nabs(aod::v0data::dcapostopv) > dcapostopv&& @@ -168,31 +206,26 @@ struct LfV0qaanalysis { { // Apply event selection - registry.fill(HIST("hNEvents"), 0.5); if (!AcceptEvent(collision)) { return; } - registry.fill(HIST("hNEvents"), 3.5); + registry.fill(HIST("hNEvents"), 8.5); registry.fill(HIST("hCentFT0M"), collision.centFT0M()); - registry.fill(HIST("hCentFV0A"), collision.centFV0A()); + registry.fill(HIST("hCentNGlobals"), collision.centNGlobal()); for (auto& v0 : V0s) { // loop over V0s + if (v0.v0Type() != v0TypeSelection) { + continue; + } // c tau float ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; float ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0Bar; float ctauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short; // ITS clusters - int posITSNhits = 0, negITSNhits = 0; - for (unsigned int i = 0; i < 7; i++) { - if (v0.posTrack_as().itsClusterMap() & (1 << i)) { - posITSNhits++; - } - if (v0.negTrack_as().itsClusterMap() & (1 << i)) { - negITSNhits++; - } - } + const int posITSNhits = v0.posTrack_as().itsNCls(); + const int negITSNhits = v0.negTrack_as().itsNCls(); // Event flags int evFlag = 0; @@ -201,27 +234,40 @@ struct LfV0qaanalysis { } int lPDG = 0; + float ptMotherMC = 0.; + float pdgMotherMC = 0.; + float yMC = 0.; bool isPhysicalPrimary = isMC; + bool isDauK0Short = false, isDauLambda = false, isDauAntiLambda = false; + + if (NotITSAfterburner && (v0.negTrack_as().isITSAfterburner() || v0.posTrack_as().isITSAfterburner())) { + continue; + } if (v0.v0radius() > v0radius && v0.v0cosPA() > v0cospa && - TMath::Abs(v0.posTrack_as().eta()) < etadau && - TMath::Abs(v0.negTrack_as().eta()) < etadau) { + std::abs(v0.posTrack_as().eta()) < etadau && + std::abs(v0.negTrack_as().eta()) < etadau) { // Fill table - myv0s(v0.globalIndex(), v0.pt(), v0.yLambda(), v0.yK0Short(), + myv0s(v0.pt(), ptMotherMC, yMC, v0.yLambda(), v0.yK0Short(), v0.mLambda(), v0.mAntiLambda(), v0.mK0Short(), v0.v0radius(), v0.v0cosPA(), v0.dcapostopv(), v0.dcanegtopv(), v0.dcaV0daughters(), v0.posTrack_as().eta(), v0.negTrack_as().eta(), - v0.posTrack_as().phi(), v0.negTrack_as().phi(), posITSNhits, negITSNhits, ctauLambda, ctauAntiLambda, ctauK0s, v0.negTrack_as().tpcNSigmaPr(), v0.posTrack_as().tpcNSigmaPr(), v0.negTrack_as().tpcNSigmaPi(), v0.posTrack_as().tpcNSigmaPi(), v0.negTrack_as().tofNSigmaPr(), v0.posTrack_as().tofNSigmaPr(), v0.negTrack_as().tofNSigmaPi(), v0.posTrack_as().tofNSigmaPi(), - v0.posTrack_as().hasTOF(), v0.negTrack_as().hasTOF(), lPDG, isPhysicalPrimary, - collision.centFT0M(), collision.centFV0A(), evFlag); + v0.posTrack_as().hasTOF(), v0.negTrack_as().hasTOF(), lPDG, pdgMotherMC, isDauK0Short, isDauLambda, isDauAntiLambda, isPhysicalPrimary, + collision.centFT0M(), collision.centNGlobal(), evFlag, v0.alpha(), v0.qtarm(), + v0.posTrack_as().tpcNClsCrossedRows(), + v0.posTrack_as().tpcNClsShared(), v0.posTrack_as().itsChi2NCl(), + v0.posTrack_as().tpcChi2NCl(), + v0.negTrack_as().tpcNClsCrossedRows(), + v0.negTrack_as().tpcNClsShared(), v0.negTrack_as().itsChi2NCl(), + v0.negTrack_as().tpcChi2NCl()); } } } @@ -231,18 +277,16 @@ struct LfV0qaanalysis { Preslice perMCCol = aod::mcparticle::mcCollisionId; SliceCache cache1; - SliceCache cache2; Service pdgDB; void processMCReco(soa::Join const& collisions, - aod::McCollisions const& /*mcCollisions*/, + soa::Join const& /*mcCollisions*/, soa::Join const& V0s, aod::McParticles const& mcParticles, DauTracksMC const& /*tracks*/) { for (const auto& collision : collisions) { // Apply event selection - registry.fill(HIST("hNEvents"), 0.5); if (!AcceptEvent(collision)) { continue; @@ -250,15 +294,15 @@ struct LfV0qaanalysis { if (!collision.has_mcCollision()) { continue; } - registry.fill(HIST("hNEvents"), 3.5); + const auto& mcCollision = collision.mcCollision_as>(); - registry.fill(HIST("hNEventsMC_RecoColl"), 0.5); + registry.fill(HIST("hNEventsMCReco"), 3.5); + const float cent = 0.f; // Event flags int evFlag = 0; if (collision.isInelGt0()) { evFlag = 1; - registry.fill(HIST("hNEventsMC_RecoColl"), 1.5); } auto v0sThisCollision = V0s.sliceBy(perCol, collision.globalIndex()); @@ -269,169 +313,324 @@ struct LfV0qaanalysis { } auto v0mcparticle = v0.mcParticle(); + if (std::abs(v0mcparticle.y()) > 0.5f) { + continue; + } + + if (v0.v0Type() != v0TypeSelection) { + continue; + } + + if (NotITSAfterburner && (v0.negTrack_as().isITSAfterburner() || v0.posTrack_as().isITSAfterburner())) { + continue; + } + // Highest numerator of efficiency if (v0mcparticle.isPhysicalPrimary()) { if (v0mcparticle.pdgCode() == 310) { - registry.fill(HIST("Reconstructed_MCRecoColl_INEL_K0Short"), v0mcparticle.pt(), v0mcparticle.y()); // K0s + registry.fill(HIST("Reconstructed_MCRecoColl_INEL_K0Short"), v0mcparticle.pt(), mcCollision.centFT0M()); // K0s if (evFlag == 1) { - registry.fill(HIST("Reconstructed_MCRecoColl_INELgt0_K0Short"), v0mcparticle.pt(), v0mcparticle.y()); // K0s + registry.fill(HIST("Reconstructed_MCRecoColl_INELgt0_K0Short"), v0mcparticle.pt(), mcCollision.centFT0M()); // K0s } } if (v0mcparticle.pdgCode() == 3122) { - registry.fill(HIST("Reconstructed_MCRecoColl_INEL_Lambda"), v0mcparticle.pt(), v0mcparticle.y()); // Lambda + registry.fill(HIST("Reconstructed_MCRecoColl_INEL_Lambda"), v0mcparticle.pt(), mcCollision.centFT0M()); // Lambda if (evFlag == 1) { - registry.fill(HIST("Reconstructed_MCRecoColl_INELgt0_Lambda"), v0mcparticle.pt(), v0mcparticle.y()); // Lambda + registry.fill(HIST("Reconstructed_MCRecoColl_INELgt0_Lambda"), v0mcparticle.pt(), mcCollision.centFT0M()); // Lambda } } if (v0mcparticle.pdgCode() == -3122) { - registry.fill(HIST("Reconstructed_MCRecoColl_INEL_AntiLambda"), v0mcparticle.pt(), v0mcparticle.y()); // AntiLambda + registry.fill(HIST("Reconstructed_MCRecoColl_INEL_AntiLambda"), v0mcparticle.pt(), mcCollision.centFT0M()); // AntiLambda if (evFlag == 1) { - registry.fill(HIST("Reconstructed_MCRecoColl_INELgt0_AntiLambda"), v0mcparticle.pt(), v0mcparticle.y()); // AntiLambda + registry.fill(HIST("Reconstructed_MCRecoColl_INELgt0_AntiLambda"), v0mcparticle.pt(), mcCollision.centFT0M()); // AntiLambda } } } int lPDG = 0; + bool isDauK0Short = false, isDauLambda = false, isDauAntiLambda = false; bool isprimary = false; - if (TMath::Abs(v0mcparticle.pdgCode()) == 310 || TMath::Abs(v0mcparticle.pdgCode()) == 3122) { + if (std::abs(v0mcparticle.pdgCode()) == 310 || std::abs(v0mcparticle.pdgCode()) == 3122) { lPDG = v0mcparticle.pdgCode(); isprimary = v0mcparticle.isPhysicalPrimary(); } - - int posITSNhits = 0, negITSNhits = 0; - for (unsigned int i = 0; i < 7; i++) { - if (v0.posTrack_as().itsClusterMap() & (1 << i)) { - posITSNhits++; + for (auto& mcparticleDaughter0 : v0mcparticle.daughters_as()) { + for (auto& mcparticleDaughter1 : v0mcparticle.daughters_as()) { + if (mcparticleDaughter0.pdgCode() == 211 && mcparticleDaughter1.pdgCode() == -211) { + isDauK0Short = true; + } + if (mcparticleDaughter0.pdgCode() == -211 && mcparticleDaughter1.pdgCode() == 2212) { + isDauLambda = true; + } + if (mcparticleDaughter0.pdgCode() == 211 && mcparticleDaughter1.pdgCode() == -2212) { + isDauAntiLambda = true; + } } - if (v0.negTrack_as().itsClusterMap() & (1 << i)) { - negITSNhits++; + } + + float ptMotherMC = 0.; + float pdgMother = 0.; + + if (std::abs(v0mcparticle.pdgCode()) == 3122 && v0mcparticle.has_mothers()) { + for (auto& mcparticleMother0 : v0mcparticle.mothers_as()) { + if (std::abs(mcparticleMother0.pdgCode()) == 3312 || std::abs(mcparticleMother0.pdgCode()) == 3322) { + ptMotherMC = mcparticleMother0.pt(); + pdgMother = mcparticleMother0.pdgCode(); + } } } + const int posITSNhits = v0.posTrack_as().itsNCls(); + const int negITSNhits = v0.negTrack_as().itsNCls(); + float ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; float ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0Bar; float ctauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short; if (v0.v0radius() > v0radius && v0.v0cosPA() > v0cospa && - TMath::Abs(v0.posTrack_as().eta()) < etadau && - TMath::Abs(v0.negTrack_as().eta()) < etadau // && + std::abs(v0.posTrack_as().eta()) < etadau && + std::abs(v0.negTrack_as().eta()) < etadau // && ) { - float cent = 0.; - // Fill table - myv0s(v0.globalIndex(), v0.pt(), v0.yLambda(), v0.yK0Short(), + myv0s(v0.pt(), ptMotherMC, v0mcparticle.y(), v0.yLambda(), v0.yK0Short(), v0.mLambda(), v0.mAntiLambda(), v0.mK0Short(), v0.v0radius(), v0.v0cosPA(), v0.dcapostopv(), v0.dcanegtopv(), v0.dcaV0daughters(), v0.posTrack_as().eta(), v0.negTrack_as().eta(), - v0.posTrack_as().phi(), v0.negTrack_as().phi(), posITSNhits, negITSNhits, ctauLambda, ctauAntiLambda, ctauK0s, v0.negTrack_as().tpcNSigmaPr(), v0.posTrack_as().tpcNSigmaPr(), v0.negTrack_as().tpcNSigmaPi(), v0.posTrack_as().tpcNSigmaPi(), v0.negTrack_as().tofNSigmaPr(), v0.posTrack_as().tofNSigmaPr(), v0.negTrack_as().tofNSigmaPi(), v0.posTrack_as().tofNSigmaPi(), - v0.posTrack_as().hasTOF(), v0.negTrack_as().hasTOF(), lPDG, isprimary, - cent, cent, evFlag); + v0.posTrack_as().hasTOF(), v0.negTrack_as().hasTOF(), lPDG, pdgMother, isDauK0Short, isDauLambda, isDauAntiLambda, isprimary, + mcCollision.centFT0M(), cent, evFlag, v0.alpha(), v0.qtarm(), + v0.posTrack_as().tpcNClsCrossedRows(), + v0.posTrack_as().tpcNClsShared(), v0.posTrack_as().itsChi2NCl(), + v0.posTrack_as().tpcChi2NCl(), + v0.negTrack_as().tpcNClsCrossedRows(), + v0.negTrack_as().tpcNClsShared(), v0.negTrack_as().itsChi2NCl(), + v0.negTrack_as().tpcChi2NCl()); } } // Generated particles - const auto particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, collision.mcCollision().globalIndex(), cache1); + const auto particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache1); for (auto& mcParticle : particlesInCollision) { if (!mcParticle.isPhysicalPrimary()) { continue; } + + if (std::abs(mcParticle.y()) > 0.5f) { + continue; + } + if (mcParticle.pdgCode() == 310) { - registry.fill(HIST("Generated_MCRecoColl_INEL_K0Short"), mcParticle.pt(), mcParticle.y()); // K0s + registry.fill(HIST("Generated_MCRecoCollCheck_INEL_K0Short"), mcParticle.pt(), mcCollision.centFT0M()); // K0s if (evFlag == 1) { - registry.fill(HIST("Generated_MCRecoColl_INELgt0_K0Short"), mcParticle.pt(), mcParticle.y()); // K0s + registry.fill(HIST("Generated_MCRecoCollCheck_INELgt0_K0Short"), mcParticle.pt(), mcCollision.centFT0M()); // K0s } } if (mcParticle.pdgCode() == 3122) { - registry.fill(HIST("Generated_MCRecoColl_INEL_Lambda"), mcParticle.pt(), mcParticle.y()); // Lambda + registry.fill(HIST("Generated_MCRecoCollCheck_INEL_Lambda"), mcParticle.pt(), mcCollision.centFT0M()); // Lambda if (evFlag == 1) { - registry.fill(HIST("Generated_MCRecoColl_INELgt0_Lambda"), mcParticle.pt(), mcParticle.y()); // Lambda + registry.fill(HIST("Generated_MCRecoCollCheck_INELgt0_Lambda"), mcParticle.pt(), mcCollision.centFT0M()); // Lambda } } if (mcParticle.pdgCode() == -3122) { - registry.fill(HIST("Generated_MCRecoColl_INEL_AntiLambda"), mcParticle.pt(), mcParticle.y()); // AntiLambda + registry.fill(HIST("Generated_MCRecoCollCheck_INEL_AntiLambda"), mcParticle.pt(), mcCollision.centFT0M()); // AntiLambda if (evFlag == 1) { - registry.fill(HIST("Generated_MCRecoColl_INELgt0_AntiLambda"), mcParticle.pt(), mcParticle.y()); // AntiLambda + registry.fill(HIST("Generated_MCRecoCollCheck_INELgt0_AntiLambda"), mcParticle.pt(), mcCollision.centFT0M()); // AntiLambda } } } } } - PROCESS_SWITCH(LfV0qaanalysis, processMCReco, "Process MC Reco", true); + PROCESS_SWITCH(LfV0qaanalysis, processMCReco, "Process MC Reco", false); - void processMCGen(aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + void processMCGen(soa::Join::iterator const& mcCollision, + aod::McParticles const& mcParticles, + soa::SmallGroups> const& collisions) { - for (const auto& mccollision : mcCollisions) { + //==================================== + //===== Event Loss Denominator ======= + //==================================== + + registry.fill(HIST("hNEventsMCGen"), 0.5); - registry.fill(HIST("hNEventsMCGen"), 0.5); + if (std::abs(mcCollision.posZ()) > MCcutzvertex) { + return; + } + registry.fill(HIST("hNEventsMCGen"), 1.5); + registry.fill(HIST("hCentFT0M_GenColl_MC"), mcCollision.centFT0M()); - if (TMath::Abs(mccollision.posZ()) > cutzvertex) { + bool isINELgt0true = false; + + if (pwglf::isINELgtNmc(mcParticles, 0, pdgDB)) { + isINELgt0true = true; + registry.fill(HIST("hNEventsMCGen"), 2.5); + registry.fill(HIST("hCentFT0M_GenColl_MC_INELgt0"), mcCollision.centFT0M()); + } + + //===================================== + //===== Signal Loss Denominator ======= + //===================================== + + for (auto& mcParticle : mcParticles) { + + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + if (std::abs(mcParticle.y()) > 0.5f) { continue; } - registry.fill(HIST("hNEventsMCGen"), 1.5); - bool isFT0A = false; - bool isFT0C = false; + if (mcParticle.pdgCode() == 310) { + registry.fill(HIST("Generated_MCGenColl_INEL_K0Short"), mcParticle.pt(), mcCollision.centFT0M()); // K0s + if (isINELgt0true) { + registry.fill(HIST("Generated_MCGenColl_INELgt0_K0Short"), mcParticle.pt(), mcCollision.centFT0M()); // K0s + } + } + if (mcParticle.pdgCode() == 3122) { + registry.fill(HIST("Generated_MCGenColl_INEL_Lambda"), mcParticle.pt(), mcCollision.centFT0M()); // Lambda + if (isINELgt0true) { + registry.fill(HIST("Generated_MCGenColl_INELgt0_Lambda"), mcParticle.pt(), mcCollision.centFT0M()); // Lambda + } + } + if (mcParticle.pdgCode() == -3122) { + registry.fill(HIST("Generated_MCGenColl_INEL_AntiLambda"), mcParticle.pt(), mcCollision.centFT0M()); // AntiLambda + if (isINELgt0true) { + registry.fill(HIST("Generated_MCGenColl_INELgt0_AntiLambda"), mcParticle.pt(), mcCollision.centFT0M()); // AntiLambda + } + } + } + + int recoCollIndex_INEL = 0; + int recoCollIndex_INELgt0 = 0; + for (auto& collision : collisions) { // loop on reconstructed collisions + + //===================================== + //====== Event Split Numerator ======== + //===================================== - const auto particlesInMCCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mccollision.globalIndex(), cache2); + registry.fill(HIST("hNEventsMCReco"), 0.5); + if (!AcceptEvent(collision)) { + continue; + } + registry.fill(HIST("hNEvents"), 8.5); + registry.fill(HIST("hNEventsMCReco"), 1.5); + registry.fill(HIST("hCentFT0M_RecoColl_MC"), mcCollision.centFT0M()); + + recoCollIndex_INEL++; - registry.fill(HIST("hNEventsMC_AllColl"), 0.5); + if (collision.isInelGt0() && isINELgt0true) { + registry.fill(HIST("hNEventsMCReco"), 2.5); + registry.fill(HIST("hCentFT0M_RecoColl_MC_INELgt0"), mcCollision.centFT0M()); - bool isINELgt0true = false; - if (isTrueINELgt0(particlesInMCCollision)) { - isINELgt0true = true; - registry.fill(HIST("hNEventsMCGen"), 2.5); - registry.fill(HIST("hNEventsMC_AllColl"), 1.5); + recoCollIndex_INELgt0++; } - for (auto& mcParticle : particlesInMCCollision) { + //===================================== + //======== Sgn Split Numerator ======== + //===================================== - if (std::abs(mcParticle.pdgCode()) == 211) { // simulated sel8 - if (mcParticle.eta() <= -2.3 && mcParticle.eta() >= -3.4) { - isFT0C = true; - } - if (mcParticle.eta() <= 5.0 && mcParticle.eta() >= 3.8) { - isFT0A = true; - } - } + for (auto& mcParticle : mcParticles) { if (!mcParticle.isPhysicalPrimary()) { continue; } + + if (std::abs(mcParticle.y()) > 0.5f) { + continue; + } + if (mcParticle.pdgCode() == 310) { - registry.fill(HIST("Generated_MCAllColl_INEL_K0Short"), mcParticle.pt(), mcParticle.y()); // K0s - if (isINELgt0true) { - registry.fill(HIST("Generated_MCAllColl_INELgt0_K0Short"), mcParticle.pt(), mcParticle.y()); // K0s + registry.fill(HIST("Generated_MCRecoColl_INEL_K0Short"), mcParticle.pt(), mcCollision.centFT0M()); // K0s + if (recoCollIndex_INELgt0 > 0) { + registry.fill(HIST("Generated_MCRecoColl_INELgt0_K0Short"), mcParticle.pt(), mcCollision.centFT0M()); // K0s } } if (mcParticle.pdgCode() == 3122) { - registry.fill(HIST("Generated_MCAllColl_INEL_Lambda"), mcParticle.pt(), mcParticle.y()); // Lambda - if (isINELgt0true) { - registry.fill(HIST("Generated_MCAllColl_INELgt0_Lambda"), mcParticle.pt(), mcParticle.y()); // Lambda + registry.fill(HIST("Generated_MCRecoColl_INEL_Lambda"), mcParticle.pt(), mcCollision.centFT0M()); // Lambda + if (recoCollIndex_INELgt0 > 0) { + registry.fill(HIST("Generated_MCRecoColl_INELgt0_Lambda"), mcParticle.pt(), mcCollision.centFT0M()); // Lambda } } if (mcParticle.pdgCode() == -3122) { - registry.fill(HIST("Generated_MCAllColl_INEL_AntiLambda"), mcParticle.pt(), mcParticle.y()); // AntiLambda - if (isINELgt0true) { - registry.fill(HIST("Generated_MCAllColl_INELgt0_AntiLambda"), mcParticle.pt(), mcParticle.y()); // AntiLambda + registry.fill(HIST("Generated_MCRecoColl_INEL_AntiLambda"), mcParticle.pt(), mcCollision.centFT0M()); // AntiLambda + if (recoCollIndex_INELgt0 > 0) { + registry.fill(HIST("Generated_MCRecoColl_INELgt0_AntiLambda"), mcParticle.pt(), mcCollision.centFT0M()); // AntiLambda } } } + } + + // From now on keep only mc collisions with at least one reconstructed collision (INEL) + if (recoCollIndex_INEL < 1) { + return; + } - if (isFT0A && isFT0C) { - registry.fill(HIST("hNEventsMCGen"), 3.5); + //===================================== + //====== Event Loss Numerator ========= + //===================================== + + registry.fill(HIST("hNEventsMCGenReco"), 0.5); + registry.fill(HIST("hCentFT0M_GenRecoColl_MC"), mcCollision.centFT0M()); + + if (recoCollIndex_INELgt0 > 0) { + registry.fill(HIST("hNEventsMCGenReco"), 1.5); + registry.fill(HIST("hCentFT0M_GenRecoColl_MC_INELgt0"), mcCollision.centFT0M()); + } + + //===================================== + //===== Signal Loss Numerator ========= + //===================================== + + for (auto& mcParticle : mcParticles) { + + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + + if (std::abs(mcParticle.y()) > 0.5f) { + continue; + } + + if (mcParticle.pdgCode() == 310) { + registry.fill(HIST("Generated_MCGenRecoColl_INEL_K0Short"), mcParticle.pt(), mcCollision.centFT0M()); // K0s + if (recoCollIndex_INELgt0 > 0) { + registry.fill(HIST("Generated_MCGenRecoColl_INELgt0_K0Short"), mcParticle.pt(), mcCollision.centFT0M()); // K0s + } + } + if (mcParticle.pdgCode() == 3122) { + registry.fill(HIST("Generated_MCGenRecoColl_INEL_Lambda"), mcParticle.pt(), mcCollision.centFT0M()); // Lambda + if (recoCollIndex_INELgt0 > 0) { + registry.fill(HIST("Generated_MCGenRecoColl_INELgt0_Lambda"), mcParticle.pt(), mcCollision.centFT0M()); // Lambda + } + } + if (mcParticle.pdgCode() == -3122) { + registry.fill(HIST("Generated_MCGenRecoColl_INEL_AntiLambda"), mcParticle.pt(), mcCollision.centFT0M()); // AntiLambda + if (recoCollIndex_INELgt0 > 0) { + registry.fill(HIST("Generated_MCGenRecoColl_INELgt0_AntiLambda"), mcParticle.pt(), mcCollision.centFT0M()); // AntiLambda + } + } + if (mcParticle.pdgCode() == 3312) { + registry.fill(HIST("Generated_MCGenRecoColl_INEL_XiMinus"), mcParticle.pt(), mcCollision.centFT0M()); // XiMinus + if (recoCollIndex_INELgt0 > 0) { + registry.fill(HIST("Generated_MCGenRecoColl_INELgt0_XiMinus"), mcParticle.pt(), mcCollision.centFT0M()); // XiMinus + } + } + if (mcParticle.pdgCode() == -3312) { + registry.fill(HIST("Generated_MCGenRecoColl_INEL_XiPlus"), mcParticle.pt(), mcCollision.centFT0M()); // XiPlus + if (recoCollIndex_INELgt0 > 0) { + registry.fill(HIST("Generated_MCGenRecoColl_INELgt0_XiPlus"), mcParticle.pt(), mcCollision.centFT0M()); // XiPlus + } } } } - PROCESS_SWITCH(LfV0qaanalysis, processMCGen, "Process MC Gen", true); + PROCESS_SWITCH(LfV0qaanalysis, processMCGen, "Process MC", false); }; struct LfMyV0s { @@ -461,6 +660,7 @@ struct LfMyV0s { registry.add("TPCNSigmaNegPr", "TPCNSigmaNegPr", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); registry.add("PosITSHits", "PosITSHits", {HistType::kTH1F, {{8, -0.5f, 7.5f}}}); registry.add("NegITSHits", "NegITSHits", {HistType::kTH1F, {{8, -0.5f, 7.5f}}}); + registry.add("multft0m", "multft0m", {HistType::kTH1F, {{100, 0.f, 100.f}}}); } void process(aod::MyV0Candidates const& myv0s) @@ -488,6 +688,7 @@ struct LfMyV0s { registry.fill(HIST("TPCNSigmaNegPr"), candidate.ntpcsigmanegpr()); registry.fill(HIST("PosITSHits"), candidate.v0positshits()); registry.fill(HIST("NegITSHits"), candidate.v0negitshits()); + registry.fill(HIST("multft0m"), candidate.multft0m()); } } }; diff --git a/PWGLF/TableProducer/Strangeness/v0selector.cxx b/PWGLF/TableProducer/Strangeness/v0selector.cxx new file mode 100644 index 00000000000..7d06871d78c --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/v0selector.cxx @@ -0,0 +1,299 @@ +// 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 Task to select V0s based on cuts +/// +/// \author Gijs van Weelden + +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/RecoDecay.h" + +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/V0SelectorTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct V0SelectorTask { + Produces v0FlagTable; + + Configurable> K0SPtBins{"K0SPtBins", {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0}, "K0S pt Vals"}; + Configurable> K0SRminVals{"K0SRminVals", {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}, "K0S min R values"}; + Configurable> K0SRmaxVals{"K0SRmaxVals", {40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0}, "K0S max R values"}; + Configurable> K0SCtauminVals{"K0SCtauminVals", {-1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3}, "K0S min ctau values"}; + Configurable> K0SCtaumaxVals{"K0SCtaumaxVals", {20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0}, "K0S max ctau values"}; + Configurable> K0SCosPAminVals{"K0SCosPAminVals", {0.997, 0.997, 0.997, 0.997, 0.997, 0.997, 0.997, 0.997, 0.997, 0.997}, "K0S min cosPA values"}; + Configurable> K0SCosPAmaxVals{"K0SCosPAmaxVals", {-1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3}, "K0S max cosPA values"}; + Configurable> K0SDCAminVals{"K0SDCAminVals", {0.20, 0.20, 0.20, 0.20, 0.20, 0.20, 0.15, 0.15, 0.10, 0.10}, "K0S min DCA +- values"}; + Configurable> K0SDCAmaxVals{"K0SDCAmaxVals", {-1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3}, "K0S max DCA +- values"}; + Configurable> K0SDCAdminVals{"K0SDCAdminVals", {-1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3}, "K0S min DCAd values"}; + Configurable> K0SDCAdmaxVals{"K0SDCAdmaxVals", {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}, "K0S max DCAd values"}; + + Configurable> LambdaPtBins{"LambdaPtBins", {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 10.0, 15.0, 20.0}, "Lambda pt Vals"}; + Configurable> LambdaRminVals{"LambdaRminVals", {1.0, 10.0, 10.0, 10.0, 10.0, 10.0, 20.0, 20.0}, "Lambda min R values"}; + Configurable> LambdaRmaxVals{"LambdaRmaxVals", {40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0}, "Lambda max R values"}; + Configurable> LambdaCtauminVals{"LambdaCtauminVals", {-1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3}, "Lambda min ctau values"}; + Configurable> LambdaCtaumaxVals{"LambdaCtaumaxVals", {22.5, 25.0, 25.0, 25.0, 25.0, 25.0, 25.0, 25.0}, "Lambda max ctau values"}; + Configurable> LambdaCosPAminVals{"LambdaCosPAminVals", {0.997, 0.997, 0.997, 0.997, 0.997, 0.997, 0.997, 0.997}, "Lambda min cosPA values"}; + Configurable> LambdaCosPAmaxVals{"LambdaCosPAmaxVals", {-1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3}, "Lambda max cosPA values"}; + Configurable> LambdaDCApminVals{"LambdaDCApminVals", {0.20, 0.10, 0.10, 0.10, 0.10, 0.10, 0.10, 0.10}, "Lambda min DCA+ values"}; + Configurable> LambdaDCApmaxVals{"LambdaDCApmaxVals", {-1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3}, "Lambda max DCA+ values"}; + Configurable> LambdaDCAnminVals{"LambdaDCAnminVals", {0.20, 0.20, 0.20, 0.20, 0.20, 0.20, 0.15, 0.15}, "Lambda min DCA- values"}; + Configurable> LambdaDCAnmaxVals{"LambdaDCAnmaxVals", {-1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3}, "Lambda max DCA- values"}; + Configurable> LambdaDCAdminVals{"LambdaDCAdminVals", {-1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3}, "Lambda max DCAd values"}; + Configurable> LambdaDCAdmaxVals{"LambdaDCAdmaxVals", {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}, "Lambda max DCAd values"}; + + Configurable> AntiLambdaPtBins{"AntiLambdaPtBins", {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 10.0, 15.0, 20.0}, "AntiLambda pt Vals"}; + Configurable> AntiLambdaRminVals{"AntiLambdaRminVals", {10.0, 10.0, 10.0, 10.0, 20.0, 20.0, 20.0, 20.0}, "AntiLambda min R values"}; + Configurable> AntiLambdaRmaxVals{"AntiLambdaRmaxVals", {40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0}, "AntiLambda max R values"}; + Configurable> AntiLambdaCtauminVals{"AntiLambdaCtauminVals", {-1e-3, -1e-3, -1e-3, -1e-3, -1e-3, -1e-3, -1e-3, -1e-3}, "AntiLambda min ctau values"}; + Configurable> AntiLambdaCtaumaxVals{"AntiLambdaCtaumaxVals", {22.5, 25.0, 25.0, 25.0, 25.0, 25.0, 25.0, 25.0}, "AntiLambda max ctau values"}; + Configurable> AntiLambdaCosPAminVals{"AntiLambdaCosPAminVals", {0.997, 0.997, 0.997, 0.997, 0.997, 0.997, 0.997, 0.997}, "AntiLambda min cosPA values"}; + Configurable> AntiLambdaCosPAmaxVals{"AntiLambdaCosPAmaxVals", {-1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3}, "AntiLambda max cosPA values"}; + Configurable> AntiLambdaDCApminVals{"AntiLambdaDCApminVals", {0.20, 0.20, 0.20, 0.20, 0.20, 0.20, 0.20, 0.20}, "AntiLambda min DCA+ values"}; + Configurable> AntiLambdaDCApmaxVals{"AntiLambdaDCApmaxVals", {-1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3}, "AntiLambda max DCA+ values"}; + Configurable> AntiLambdaDCAnminVals{"AntiLambdaDCAnminVals", {0.20, 0.10, 0.10, 0.10, 0.10, 0.10, 0.10, 0.10}, "AntiLambda min DCA- values"}; + Configurable> AntiLambdaDCAnmaxVals{"AntiLambdaDCAnmaxVals", {-1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3}, "AntiLambda max DCA- values"}; + Configurable> AntiLambdaDCAdminVals{"AntiLambdaDCAdminVals", {-1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3, -1e3}, "AntiLambda min DCAd values"}; + Configurable> AntiLambdaDCAdmaxVals{"AntiLambdaDCAdmaxVals", {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}, "AntiLambda max DCAd values"}; + + Configurable massCuts{"massCuts", true, "Apply mass cuts"}; + Configurable competingMassCuts{"competingMassCuts", true, "Apply competing mass cuts"}; + Configurable> K0SMassLowVals{"K0SMassLowVals", {0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4}, "K0S mass cut lower values (MeV)"}; + Configurable> K0SMassHighVals{"K0SMassHighVals", {0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6}, "K0S mass cut upper values (MeV)"}; + Configurable> LambdaMassLowVals{"LambdaMassLowVals", {1.08, 1.08, 1.08, 1.08, 1.08, 1.08, 1.08, 1.08}, "Lambda mass cut lower values (MeV)"}; + Configurable> LambdaMassHighVals{"LambdaMassHighVals", {1.125, 1.125, 1.125, 1.125, 1.125, 1.125, 1.125, 1.125}, "Lambda mass cut upper values (MeV)"}; + Configurable> AntiLambdaMassLowVals{"AntiLambdaMassLowVals", {1.08, 1.08, 1.08, 1.08, 1.08, 1.08, 1.08, 1.08}, "AntiLambda mass cut lower values (MeV)"}; + Configurable> AntiLambdaMassHighVals{"AntiLambdaMassHighVals", {1.125, 1.125, 1.125, 1.125, 1.125, 1.125, 1.125, 1.125}, "AntiLambda mass cut upper values (MeV)"}; + + Configurable randomSelection{"randomSelection", true, "Randomly select V0s"}; + Configurable> K0SFraction{"K0SFraction", {2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0}, "Fraction of K0S to randomly select"}; + Configurable> LambdaFraction{"LambdaFraction", {2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0}, "Fraction of Lambda to randomly select"}; + Configurable> AntiLambdaFraction{"AntiLambdaFraction", {2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0}, "Fraction of AntiLambda to randomly select"}; + + void init(InitContext const&) + { + } + + int getPtBin(float pt, std::vector ptBins) + { + if (pt < ptBins.at(0)) + return -1; + if (pt > ptBins.at(ptBins.size() - 1)) + return -2; + + for (unsigned int i = 0; i < ptBins.size() - 1; i++) { + if (pt >= ptBins.at(i) && pt < ptBins.at(i + 1)) { + return i; + } + } + return -3; + } + bool cuts(std::vector values, std::vector mincuts, std::vector maxcuts) + { + for (unsigned int i = 0; i < values.size(); i++) { + float val = values.at(i); + float min = mincuts.at(i); + float max = maxcuts.at(i); + + if (val < min && min > -1e2) + return false; + if (val > max && max > -1e2) + return false; + } + return true; + } + template + bool K0SCuts(T const& collision, U const& v0) + { + int ptBin = getPtBin(v0.pt(), K0SPtBins); + if (ptBin < 0) + return false; + + // This is the only time we need to check min and max simultaneously + // K0S and Lambda(bar) do not share pt binning, so check the ptBin for Lambda(bar) separately + if (competingMassCuts) { + int ptBinCMC = getPtBin(v0.pt(), LambdaPtBins); + if (ptBinCMC >= 0) { // TODO: Should we still do CMC when v0 is out of pT range for Lambda(bar)? + if (v0.mLambda() > LambdaMassLowVals->at(ptBinCMC) && v0.mLambda() < LambdaMassHighVals->at(ptBinCMC)) { + return false; + } + } + ptBinCMC = getPtBin(v0.pt(), AntiLambdaPtBins); + if (ptBinCMC >= 0) { + if (v0.mAntiLambda() > AntiLambdaMassLowVals->at(ptBinCMC) && v0.mAntiLambda() < AntiLambdaMassHighVals->at(ptBinCMC)) { + return false; + } + } + } + + float rmin = K0SRminVals->at(ptBin); + float rmax = K0SRmaxVals->at(ptBin); + float ctaumin = K0SCtauminVals->at(ptBin); + float ctaumax = K0SCtaumaxVals->at(ptBin); + float cospamin = K0SCosPAminVals->at(ptBin); + float cospamax = K0SCosPAmaxVals->at(ptBin); + float dcapmin = K0SDCAminVals->at(ptBin); + float dcapmax = K0SDCAmaxVals->at(ptBin); + float dcanmin = K0SDCAminVals->at(ptBin); + float dcanmax = K0SDCAmaxVals->at(ptBin); + float dcadmin = K0SDCAdminVals->at(ptBin); + float dcadmax = K0SDCAdmaxVals->at(ptBin); + + float ctau = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short; + std::vector vals = {v0.v0radius(), ctau, v0.v0cosPA(), v0.dcaV0daughters(), TMath::Abs(v0.dcapostopv()), TMath::Abs(v0.dcanegtopv())}; + std::vector mincuts = {rmin, ctaumin, cospamin, dcadmin, dcapmin, dcanmin}; + std::vector maxcuts = {rmax, ctaumax, cospamax, dcadmax, dcapmax, dcanmax}; + + if (massCuts) { + vals.push_back(v0.mK0Short()); + mincuts.push_back(K0SMassLowVals->at(ptBin)); + maxcuts.push_back(K0SMassHighVals->at(ptBin)); + } + + return cuts(vals, mincuts, maxcuts); + } + template + bool LambdaCuts(T const& collision, U const& v0) + { + int ptBin = getPtBin(v0.pt(), LambdaPtBins); + if (ptBin < 0) + return false; + + if (competingMassCuts) { + int ptBinCMC = getPtBin(v0.pt(), K0SPtBins); + if (ptBinCMC >= 0) { + if (v0.mK0Short() > K0SMassLowVals->at(ptBinCMC) && v0.mK0Short() < K0SMassHighVals->at(ptBinCMC)) + return false; + } + } + + float rmin = LambdaRminVals->at(ptBin); + float rmax = LambdaRmaxVals->at(ptBin); + float ctaumin = LambdaCtauminVals->at(ptBin); + float ctaumax = LambdaCtaumaxVals->at(ptBin); + float cospamin = LambdaCosPAminVals->at(ptBin); + float cospamax = LambdaCosPAmaxVals->at(ptBin); + float dcapmin = LambdaDCApminVals->at(ptBin); + float dcapmax = LambdaDCApmaxVals->at(ptBin); + float dcanmin = LambdaDCAnminVals->at(ptBin); + float dcanmax = LambdaDCAnmaxVals->at(ptBin); + float dcadmin = LambdaDCAdminVals->at(ptBin); + float dcadmax = LambdaDCAdmaxVals->at(ptBin); + + float ctau = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; + std::vector vals = {v0.v0radius(), ctau, v0.v0cosPA(), v0.dcaV0daughters(), TMath::Abs(v0.dcapostopv()), TMath::Abs(v0.dcanegtopv())}; + std::vector mincuts = {rmin, ctaumin, cospamin, dcadmin, dcapmin, dcanmin}; + std::vector maxcuts = {rmax, ctaumax, cospamax, dcadmax, dcapmax, dcanmax}; + + if (massCuts) { + vals.push_back(v0.mLambda()); + mincuts.push_back(LambdaMassLowVals->at(ptBin)); + maxcuts.push_back(LambdaMassHighVals->at(ptBin)); + } + return cuts(vals, mincuts, maxcuts); + } + template + bool AntiLambdaCuts(T const& collision, U const& v0) + { + int ptBin = getPtBin(v0.pt(), AntiLambdaPtBins); + if (ptBin < 0) + return false; + + if (competingMassCuts) { + int ptBinCMC = getPtBin(v0.pt(), K0SPtBins); + if (ptBinCMC >= 0) { + if (v0.mK0Short() > K0SMassLowVals->at(ptBinCMC) && v0.mK0Short() < K0SMassHighVals->at(ptBinCMC)) + return false; + } + } + + float rmin = AntiLambdaRminVals->at(ptBin); + float rmax = AntiLambdaRmaxVals->at(ptBin); + float ctaumin = AntiLambdaCtauminVals->at(ptBin); + float ctaumax = AntiLambdaCtaumaxVals->at(ptBin); + float cospamin = AntiLambdaCosPAminVals->at(ptBin); + float cospamax = AntiLambdaCosPAmaxVals->at(ptBin); + float dcapmin = AntiLambdaDCApminVals->at(ptBin); + float dcapmax = AntiLambdaDCApmaxVals->at(ptBin); + float dcanmin = AntiLambdaDCAnminVals->at(ptBin); + float dcanmax = AntiLambdaDCAnmaxVals->at(ptBin); + float dcadmin = AntiLambdaDCAdminVals->at(ptBin); + float dcadmax = AntiLambdaDCAdmaxVals->at(ptBin); + + float ctau = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; + std::vector vals = {v0.v0radius(), ctau, v0.v0cosPA(), v0.dcaV0daughters(), TMath::Abs(v0.dcapostopv()), TMath::Abs(v0.dcanegtopv())}; + std::vector mincuts = {rmin, ctaumin, cospamin, dcadmin, dcapmin, dcanmin}; + std::vector maxcuts = {rmax, ctaumax, cospamax, dcadmax, dcapmax, dcanmax}; + + if (competingMassCuts) { + vals.push_back(v0.mAntiLambda()); + mincuts.push_back(AntiLambdaMassLowVals->at(ptBin)); + maxcuts.push_back(AntiLambdaMassHighVals->at(ptBin)); + } + return cuts(vals, mincuts, maxcuts); + } + template + bool RandomlyReject(T const& v0, uint8_t flag) + { + // In case of multiple candidate types, only check the lowest threshold value + float threshold = 2.; + if (flag & aod::v0flags::FK0S) { + int ptBin = getPtBin(v0.pt(), K0SPtBins); + threshold = std::min(threshold, K0SFraction->at(ptBin)); + } + if (flag & aod::v0flags::FLAMBDA) { + int ptBin = getPtBin(v0.pt(), LambdaPtBins); + threshold = std::min(threshold, LambdaFraction->at(ptBin)); + } + if (flag & aod::v0flags::FANTILAMBDA) { + int ptBin = getPtBin(v0.pt(), AntiLambdaPtBins); + threshold = std::min(threshold, AntiLambdaFraction->at(ptBin)); + } + // If gRandom > threshold, reject the candidate + return (gRandom->Uniform() > threshold); + } + + void processV0(aod::Collision const& collision, aod::V0Datas const& v0s) + { + for (const auto& v0 : v0s) { + uint8_t flag = 0; + flag += K0SCuts(collision, v0) * aod::v0flags::FK0S; + flag += LambdaCuts(collision, v0) * aod::v0flags::FLAMBDA; + flag += AntiLambdaCuts(collision, v0) * aod::v0flags::FANTILAMBDA; + + if (flag == 0) + flag += aod::v0flags::FREJECTED; + else + flag += RandomlyReject(v0, flag) * aod::v0flags::FREJECTED; + + v0FlagTable(flag); + } + } + PROCESS_SWITCH(V0SelectorTask, processV0, "flags V0 candidates as potential signal", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"v0-selector"})}; +} diff --git a/PWGLF/Tasks/CMakeLists.txt b/PWGLF/Tasks/CMakeLists.txt index 972d36a7251..f4c5eea7f02 100644 --- a/PWGLF/Tasks/CMakeLists.txt +++ b/PWGLF/Tasks/CMakeLists.txt @@ -13,6 +13,7 @@ add_subdirectory(QC) # PAGs +add_subdirectory(GlobalEventProperties) add_subdirectory(Nuspex) add_subdirectory(Resonances) add_subdirectory(Strangeness) diff --git a/PWGLF/Tasks/GlobalEventProperties/CMakeLists.txt b/PWGLF/Tasks/GlobalEventProperties/CMakeLists.txt new file mode 100644 index 00000000000..ed61c203672 --- /dev/null +++ b/PWGLF/Tasks/GlobalEventProperties/CMakeLists.txt @@ -0,0 +1,25 @@ +# 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(ucc-zdc + SOURCES uccZdc.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + + o2physics_add_dpl_workflow(heavyion-multiplicity + SOURCES heavyionMultiplicity.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(dndeta-mft-pp + SOURCES dndeta-mft-pp.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGLF/Tasks/GlobalEventProperties/dndeta-mft-pp.cxx b/PWGLF/Tasks/GlobalEventProperties/dndeta-mft-pp.cxx new file mode 100644 index 00000000000..b168c1d2abc --- /dev/null +++ b/PWGLF/Tasks/GlobalEventProperties/dndeta-mft-pp.cxx @@ -0,0 +1,1002 @@ +// Copyright 2020-2022 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 dndeta-mft.cxx +// \author Sarah Herrmann +// +// \brief This code loops over MFT tracks and collisions and fills histograms +// useful to compute dNdeta + +#include +#include +#include +#include +#include +#include +#include + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RuntimeError.h" +#include "Framework/runDataProcessing.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "CommonConstants/MathConstants.h" +#include "MathUtils/Utils.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "TDatabasePDG.h" + +#include "PWGMM/Mult/DataModel/bestCollisionTable.h" +#include "TFile.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::track; + +AxisSpec PtAxis = {1001, -0.005, 10.005}; +AxisSpec DeltaZAxis = {61, -6.1, 6.1}; +AxisSpec ZAxis = {301, -30.1, 30.1}; +AxisSpec PhiAxis = {629, 0, 2 * M_PI, "Rad", "phi axis"}; +// AxisSpec EtaAxis = {18, -4.6, -1.}; +AxisSpec DCAxyAxis = {100, -1, 10}; +AxisSpec CentAxis = {{0, 10, 20, 30, 40, 50, 60, 70, 80, 100}}; + +static constexpr TrackSelectionFlags::flagtype trackSelectionITS = + TrackSelectionFlags::kITSNCls | TrackSelectionFlags::kITSChi2NDF | + TrackSelectionFlags::kITSHits; + +static constexpr TrackSelectionFlags::flagtype trackSelectionTPC = + TrackSelectionFlags::kTPCNCls | + TrackSelectionFlags::kTPCCrossedRowsOverNCls | + TrackSelectionFlags::kTPCChi2NDF; + +static constexpr TrackSelectionFlags::flagtype trackSelectionDCA = + TrackSelectionFlags::kDCAz | TrackSelectionFlags::kDCAxy; + +using MFTTracksLabeled = soa::Join; + +struct PseudorapidityDensityMFT { + SliceCache cache; + Preslice perCol = o2::aod::fwdtrack::collisionId; + Preslice perMcCol = aod::mcparticle::mcCollisionId; + Preslice perColCentral = aod::track::collisionId; + + Service pdg; + + Configurable estimatorEta{"estimatorEta", 1.0, + "eta range for INEL>0 sample definition"}; + + Configurable useEvSel{"useEvSel", true, "use event selection"}; + ConfigurableAxis multBinning{"multBinning", {701, -0.5, 700.5}, ""}; + ConfigurableAxis EtaAxis = {"etaBinning", {18, -4.6, -1.}, ""}; + + Configurable useZDiffCut{"useZDiffCut", true, "use Z difference cut"}; + Configurable maxZDiff{ + "maxZDiff", 1.0f, + "max allowed Z difference for reconstruced collisions (cm)"}; + + Configurable usePhiCut{"usePhiCut", false, "use azimuthal angle cut"}; + Configurable cfgPhiCut{"cfgPhiCut", 0.1f, + "Cut on azimuthal angle of MFT tracks"}; + Configurable cfgVzCut1{"cfgVzCut1", -30.0f, + "Cut1 on vertex position of MFT tracks"}; + Configurable cfgVzCut2{"cfgVzCut2", 30.0f, + "Cut2 on vertex position of MFT tracks"}; + Configurable cfgnCluster{"cfgnCluster", 5.0f, + "Cut on no of clusters per MFT track"}; + Configurable cfgnEta1{"cfgnEta1", -4.5f, + "Cut on eta1"}; + Configurable cfgnEta2{"cfgnEta2", -1.0f, + "Cut on eta1"}; + HistogramRegistry registry{ + "registry", + { + {"TracksEtaZvtx", + "; #eta; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {EtaAxis, ZAxis}}}, // + {"Tracks/EtaZvtx_gt0", + "; #eta; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {EtaAxis, ZAxis}}}, // + {"TracksPhiEta", + "; #varphi; #eta; tracks", + {HistType::kTH2F, {PhiAxis, EtaAxis}}}, // + {"TracksPhiZvtx", + "; #varphi; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {PhiAxis, ZAxis}}}, // + {"TracksPtEta", + " ; p_{T} (GeV/c); #eta", + {HistType::kTH2F, {PtAxis, EtaAxis}}}, // + {"EventSelection", + ";status;events", + {HistType::kTH1F, {{15, 0.5, 15.5}}}}, + {"EventCounts", + ";status;events", + {HistType::kTH1F, {{2, 0.5, 2.5}}}}, + {"Tracks/Control/TrackCount", ";status;Track counts", {HistType::kTH1F, {{15, 0.5, 15.5}}}}, // added + }}; + + void init(InitContext&) + { + if (static_cast(doprocessMult) + + static_cast(doprocessMultReassoc) + + static_cast(doprocessCountingCentrality) > + 1) { + LOGP(fatal, + "Exactly one process function between processMult, " + "processMultReassoc and processCountingCentrality should be " + "enabled!"); + } + AxisSpec MultAxis = {multBinning, "N_{trk}"}; + auto hstat = registry.get(HIST("EventSelection")); + auto* x = hstat->GetXaxis(); + x->SetBinLabel(1, "All"); + x->SetBinLabel(2, "Selected"); + x->SetBinLabel(3, "Selected Vz Cut"); + x->SetBinLabel(4, "Sel8+Vz+INEL>0"); + x->SetBinLabel(5, "Sel INEL,INEL_fwd>0"); + x->SetBinLabel(6, "Rejected"); + x->SetBinLabel(7, "Good BCs"); + x->SetBinLabel(8, "BCs with collisions"); + x->SetBinLabel(9, "BCs with pile-up/splitting"); + x->SetBinLabel(10, "midtracks>0"); + x->SetBinLabel(11, "percollisionSample>0"); + x->SetBinLabel(12, "midtracks+percollisionSample>0"); + registry.add({"EventsNtrkZvtx", + "; N_{trk}; #it{z}_{vtx} (cm); events", + {HistType::kTH2F, {MultAxis, ZAxis}}}); + registry.add({"EventsNtrkZvtx_gt0", + "; N_{trk}; #it{z}_{vtx} (cm); events", + {HistType::kTH2F, {MultAxis, ZAxis}}}); + registry.add({"Tracks/Control/DCAXY", + " ; DCA_{XY} (cm)", + {HistType::kTH1F, {DCAxyAxis}}}); + if (doprocessGen) { + registry.add({"EventsNtrkZvtxGen", + "; N_{trk}; #it{z}_{vtx} (cm); events", + {HistType::kTH2F, {MultAxis, ZAxis}}}); + registry.add({"EventsNtrkZvtxGen_t", + "; N_{trk}; #it{z}_{vtx} (cm); events", + {HistType::kTH2F, {MultAxis, ZAxis}}}); + registry.add({"EventsNtrkZvtxGen_gt0", + "; N_{trk}; #it{z}_{vtx} (cm); events", + {HistType::kTH2F, {MultAxis, ZAxis}}}); + registry.add({"EventsNtrkZvtxGen_gt0t", + "; N_{trk}; #it{z}_{vtx} (cm); events", + {HistType::kTH2F, {MultAxis, ZAxis}}}); + registry.add({"TracksEtaZvtxGen", + "; #eta; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {EtaAxis, ZAxis}}}); + registry.add({"TracksEtaZvtxGen_t", + "; #eta; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {EtaAxis, ZAxis}}}); + registry.add({"TracksEtaZvtxGen_gt0", + "; #eta; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {EtaAxis, ZAxis}}}); + registry.add({"TracksEtaZvtxGen_gt0t", + "; #eta; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {EtaAxis, ZAxis}}}); + registry.add({"TracksPhiEtaGen", + "; #varphi; #eta; tracks", + {HistType::kTH2F, {PhiAxis, EtaAxis}}}); + registry.add({"TracksPhiEtaGen_gt0", + "; #varphi; #eta; tracks", + {HistType::kTH2F, {PhiAxis, EtaAxis}}}); + registry.add({"TracksPhiEtaGen_gt0t", + "; #varphi; #eta; tracks", + {HistType::kTH2F, {PhiAxis, EtaAxis}}}); + registry.add({"TracksPhiZvtxGen", + "; #varphi; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {PhiAxis, ZAxis}}}); // + registry.add({"TracksToPartPtEta", + " ; p_{T} (GeV/c); #eta", + {HistType::kTH2F, {PtAxis, EtaAxis}}}); // + registry.add({"TracksPtEtaGen", + " ; p_{T} (GeV/c); #eta", + {HistType::kTH2F, {PtAxis, EtaAxis}}}); + registry.add({"TracksPtEtaGen_t", + " ; p_{T} (GeV/c); #eta", + {HistType::kTH2F, {PtAxis, EtaAxis}}}); + registry.add({"EventEfficiency", + "; status; events", + {HistType::kTH1F, {{5, 0.5, 5.5}}}}); + registry.add({"NotFoundEventZvtx", + " ; #it{z}_{vtx} (cm)", + {HistType::kTH1F, {ZAxis}}}); + registry.add({"EventsZposDiff", + " ; Z_{rec} - Z_{gen} (cm)", + {HistType::kTH1F, {DeltaZAxis}}}); + registry.add({"EventsSplitMult", " ; N_{gen}", {HistType::kTH1F, {MultAxis}}}); + auto heff = registry.get(HIST("EventEfficiency")); + x = heff->GetXaxis(); + x->SetBinLabel(1, "Generated"); + x->SetBinLabel(2, "Generated INEL>0"); + x->SetBinLabel(3, "Reconstructed"); + x->SetBinLabel(4, "Selected"); + x->SetBinLabel(5, "Selected INEL>0"); + } + + if (doprocessMultReassoc) { + registry.add({"Tracks/Control/DeltaZ", + " ; #it{z_{orig}}-#it{z_{reass}}", + {HistType::kTH1F, {ZAxis}}}); + + registry.add({"Tracks/Control/TrackAmbDegree", + " ; N_{coll}^{comp}", + {HistType::kTH1F, {{51, -0.5, 50.5}}}}); + registry.add({"Tracks/Control/TrackIsAmb", + " ; isAmbiguous", + {HistType::kTH1I, {{2, -0.5, 1.5}}}}); + + auto htrk = registry.get(HIST("Tracks/Control/TrackCount")); + auto* x = htrk->GetXaxis(); + x->SetBinLabel(0, "All"); + x->SetBinLabel(1, "Reass"); + x->SetBinLabel(2, "Not Reass"); + x->SetBinLabel(3, "Amb"); + x->SetBinLabel(4, "Amb+Not-reass"); + x->SetBinLabel(5, "Non-Amb"); + x->SetBinLabel(6, "Not-Reass+Non-Amb"); + x->SetBinLabel(7, "Amb+Non-Amb"); + x->SetBinLabel(8, "colid<0"); + x->SetBinLabel(9, "wo orphan"); + + registry.add({"Tracks/Control/ReassignedTracksEtaZvtx", + "; #eta; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {EtaAxis, ZAxis}}}); + registry.add({"Tracks/Control/ReassignedTracksPhiEta", + "; #varphi; #eta; tracks", + {HistType::kTH2F, {PhiAxis, EtaAxis}}}); + registry.add({"Tracks/Control/ReassignedVertexCorr", + "; #it{z}_{vtx}^{orig} (cm); #it{z}_{vtx}^{re} (cm)", + {HistType::kTH2F, {ZAxis, ZAxis}}}); + + registry.add({"Tracks/Control/notReassignedTracksEtaZvtx", + "; #eta; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {EtaAxis, ZAxis}}}); + registry.add({"Tracks/Control/notReassignedTracksPhiEta", + "; #varphi; #eta; tracks", + {HistType::kTH2F, {PhiAxis, EtaAxis}}}); + registry.add({"Tracks/Control/notReassignedVertexCorr", + "; #it{z}_{vtx}^{orig} (cm); #it{z}_{vtx}^{re} (cm)", + {HistType::kTH2F, {ZAxis, ZAxis}}}); + + registry.add({"Tracks/Control/amb/AmbTracksEtaZvtx", + "; #eta; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {EtaAxis, ZAxis}}}); // + + registry.add({"Tracks/Control/woOrp/nTrk", + " ; N_{Trk}^{all}", + {HistType::kTH1F, {{701, -0.5, 700.5}}}}); // + registry.add({"Tracks/Control/amb/nTrkAmb", + " ; N_{Trk}^{amb}", + {HistType::kTH1F, {{701, -0.5, 700.5}}}}); // + registry.add({"Tracks/Control/nonamb/nTrkNonAmb", + " ; N_{Trk}^{nonamb}", + {HistType::kTH1F, {{701, -0.5, 700.5}}}}); // + + registry.add({"Tracks/Control/amb/AmbTracksPhiEta", + "; #varphi; #eta; tracks", + {HistType::kTH2F, {PhiAxis, EtaAxis}}}); // + registry.add({"Tracks/Control/amb/AmbVertexCorr", + "; #it{z}_{vtx}^{orig} (cm); #it{z}_{vtx}^{re} (cm)", + {HistType::kTH2F, {ZAxis, ZAxis}}}); // + registry.add({"Tracks/Control/amb/EtaZvtxAmb_gt0", + "; #eta; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {EtaAxis, ZAxis}}}); // + + registry.add({"Tracks/Control/nonamb/nonAmbTracksEtaZvtx", + "; #eta; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {EtaAxis, ZAxis}}}); // + + registry.add({"Tracks/Control/nonamb/nonAmbTracksPhiEta", + "; #varphi; #eta; tracks", + {HistType::kTH2F, {PhiAxis, EtaAxis}}}); // + registry.add({"Tracks/Control/nonamb/nonAmbVertexCorr", + "; #it{z}_{vtx}^{orig} (cm); #it{z}_{vtx}^{re} (cm)", + {HistType::kTH2F, {ZAxis, ZAxis}}}); // + registry.add({"Tracks/Control/nonamb/EtaZvtxNonAmb_gt0", + "; #eta; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {EtaAxis, ZAxis}}}); // + + registry.add({"Tracks/Control/woOrp/woOrpTracksEtaZvtx", + "; #eta; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {EtaAxis, ZAxis}}}); // + registry.add({"Tracks/Control/woOrp/woOrpEtaZvtx_gt0", + "; #eta; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {EtaAxis, ZAxis}}}); // + + registry.add({"Tracks/Control/woOrp/woOrpTracksPhiEta", + "; #varphi; #eta; tracks", + {HistType::kTH2F, {PhiAxis, EtaAxis}}}); // + registry.add({"Tracks/Control/woOrp/woOrpVertexCorr", + "; #it{z}_{vtx}^{orig} (cm); #it{z}_{vtx}^{re} (cm)", + {HistType::kTH2F, {ZAxis, ZAxis}}}); // + registry.add({"collisionID", " ; Collision ID", + // {HistType::kTH1F,{{100000, 0.5, 100000.0}}}}); // + {HistType::kTH1F, {{100000, -50000.0, 50000.0}}}}); // + registry.add({"collisionIDamb", " ; Collision ID amb", + // {HistType::kTH1F,{{100000, 0.5, 100000.0}}}}); // + {HistType::kTH1F, {{100000, -50000.0, 50000.0}}}}); // + registry.add({"NonambEventCounts", " ; EventCounts Nonamb", {HistType::kTH1F, {{1, 0.5, 1.5}}}}); // + registry.add({"hNumCollisionsNonAmb_InelMFT", " ; Number of Collisions with Non-Ambiguous Tracks;Count;Frequency", {HistType::kTH1F, {{1, 0.5, 1.5}}}}); // + registry.add({"hNumCollisionsAmb_InelMFT", " ; Number of Collisions with Non-Ambiguous Tracks;Count;Frequency", {HistType::kTH1F, {{1, 0.5, 1.5}}}}); // + registry.add({"hNumCollisions_InelMFT", " ; Number of selected events with Inel>0 and MFT>0;Count;Frequency", {HistType::kTH1F, {{1, 0.5, 1.5}}}}); // + registry.add({"hNumCollisions_Inel", " ; Number of selected events with Inel>0;Count;Frequency", {HistType::kTH1F, {{1, 0.5, 1.5}}}}); // + registry.add({"ambEventCounts", " ; EventCounts Nonamb", {HistType::kTH1F, {{1, 0.5, 1.5}}}}); // + } + + if (doprocessCountingCentrality) { + registry.add({"Events/Centrality/Selection", + ";status;centrality;events", + {HistType::kTH2F, {{3, 0.5, 3.5}, CentAxis}}}); + auto hstat = registry.get(HIST("Events/Centrality/Selection")); + auto* x = hstat->GetXaxis(); + x->SetBinLabel(1, "All"); + x->SetBinLabel(2, "Selected"); + x->SetBinLabel(3, "Rejected"); + + registry.add({"Events/Centrality/NtrkZvtx", + "; N_{trk}; Z_{vtx} (cm); centrality", + {HistType::kTH3F, {MultAxis, ZAxis, CentAxis}}}); + registry.add({"Tracks/Centrality/EtaZvtx", + "; #eta; Z_{vtx} (cm); centrality", + {HistType::kTH3F, {EtaAxis, ZAxis, CentAxis}}}); + registry.add({"Tracks/Centrality/PhiEta", + "; #varphi; #eta; centrality", + {HistType::kTH3F, {PhiAxis, EtaAxis, CentAxis}}}); + registry.add({"Tracks/Centrality/Control/PtEta", + " ; p_{T} (GeV/c); #eta; centrality", + {HistType::kTH3F, {PtAxis, EtaAxis, CentAxis}}}); + registry.add({"Tracks/Centrality/Control/DCAXYPt", + " ; p_{T} (GeV/c) ; DCA_{XY} (cm); centrality", + {HistType::kTH3F, {PtAxis, DCAxyAxis, CentAxis}}}); + registry.add({"Tracks/Centrality/Control/ReassignedDCAXYPt", + " ; p_{T} (GeV/c) ; DCA_{XY} (cm); centrality", + {HistType::kTH3F, {PtAxis, DCAxyAxis, CentAxis}}}); + registry.add({"Tracks/Centrality/Control/ExtraDCAXYPt", + " ; p_{T} (GeV/c) ; DCA_{XY} (cm); centrality", + {HistType::kTH3F, {PtAxis, DCAxyAxis, CentAxis}}}); + registry.add({"Tracks/Centrality/Control/ExtraTracksEtaZvtx", + "; #eta; Z_{vtx} (cm); centrality", + {HistType::kTH3F, {EtaAxis, ZAxis, CentAxis}}}); + registry.add({"Tracks/Centrality/Control/ExtraTracksPhiEta", + "; #varphi; #eta; centrality", + {HistType::kTH3F, {PhiAxis, EtaAxis, CentAxis}}}); + registry.add({"Tracks/Centrality/Control/ReassignedTracksEtaZvtx", + "; #eta; Z_{vtx} (cm); centrality", + {HistType::kTH3F, {EtaAxis, ZAxis, CentAxis}}}); + registry.add({"Tracks/Centrality/Control/ReassignedTracksPhiEta", + "; #varphi; #eta; centrality", + {HistType::kTH3F, {PhiAxis, EtaAxis, CentAxis}}}); + registry.add({"Tracks/Centrality/Control/ReassignedVertexCorr", + "; Z_{vtx}^{orig} (cm); Z_{vtx}^{re} (cm); centrality", + {HistType::kTH3F, {ZAxis, ZAxis, CentAxis}}}); + } + + if (doprocessGenCent) { + registry.add({"Events/Centrality/EventEfficiency", + ";status;centrality;events", + {HistType::kTH2F, {{2, 0.5, 2.5}, CentAxis}}}); + auto heff = registry.get(HIST("Events/Centrality/EventEfficiency")); + auto* x = heff->GetXaxis(); + x->SetBinLabel(1, "Generated"); + x->SetBinLabel(2, "Selected"); + + registry.add("Events/Centrality/CentPercentileMCGen", + "CentPercentileMCGen", kTH1D, {CentAxis}, false); + registry.add({"Events/Centrality/NtrkZvtxGen", + "; N_{trk}; Z_{vtx} (cm); centrality", + {HistType::kTH3F, {MultAxis, ZAxis, CentAxis}}}); + registry.add({"Events/Centrality/NtrkZvtxGen_t", + "; N_{trk}; Z_{vtx} (cm); centrality", + {HistType::kTH3F, {MultAxis, ZAxis, CentAxis}}}); + registry.add({"Tracks/Centrality/EtaZvtxGen_t", + "; #eta; Z_{vtx} (cm); centrality", + {HistType::kTH3F, {EtaAxis, ZAxis, CentAxis}}}); + registry.add({"Tracks/Centrality/EtaZvtxGen", + "; #eta; Z_{vtx} (cm); centrality", + {HistType::kTH3F, {EtaAxis, ZAxis, CentAxis}}}); + registry.add({"Tracks/Centrality/PhiEtaGen", + "; #varphi; #eta; centrality", + {HistType::kTH3F, {PhiAxis, EtaAxis, CentAxis}}}); + } + } + + using FullBCs = soa::Join; + void processTagging(FullBCs const& bcs, + soa::Join const& collisions) + { + + std::vector::iterator> cols; + for (auto& bc : bcs) { + if (!useEvSel || + (useEvSel && ((bc.selection_bit(aod::evsel::kIsBBT0A) && + bc.selection_bit(aod::evsel::kIsBBT0C)) != 0))) { + registry.fill(HIST("EventSelection"), 7); // added 5->12 + cols.clear(); + for (auto& collision : collisions) { + if (collision.has_foundBC()) { + if (collision.foundBCId() == bc.globalIndex()) { + cols.emplace_back(collision); + } + } else if (collision.bcId() == bc.globalIndex()) { + cols.emplace_back(collision); + } + } + LOGP(debug, "BC {} has {} collisions", bc.globalBC(), cols.size()); + if (!cols.empty()) { + registry.fill(HIST("EventSelection"), 8); // added 6->13 + if (cols.size() > 1) { + registry.fill(HIST("EventSelection"), 9); // added 7->14 + } + } + } + } + } + + PROCESS_SWITCH(PseudorapidityDensityMFT, processTagging, + "Collect event sample stats", true); + + Partition sample = + (aod::fwdtrack::eta < -2.8f) && (aod::fwdtrack::eta > -3.2f); + + Partition sampleCentral = (nabs(aod::track::eta) < 1.f); + + expressions::Filter atrackFilter = + (aod::fwdtrack::bestCollisionId >= 0) && (aod::fwdtrack::eta < -2.0f) && + (aod::fwdtrack::eta > -3.9f) && (nabs(aod::fwdtrack::bestDCAXY) <= 2.f); + + using CollwEv = soa::Join; + + expressions::Filter trackSelectionCentral = + ((aod::track::trackCutFlag & trackSelectionITS) == trackSelectionITS) && + ifnode((aod::track::v001::detectorMap & (uint8_t)o2::aod::track::TPC) == + (uint8_t)o2::aod::track::TPC, + (aod::track::trackCutFlag & trackSelectionTPC) == + trackSelectionTPC, + true) && + ((aod::track::trackCutFlag & trackSelectionDCA) == trackSelectionDCA) && + (nabs(aod::track::eta) < estimatorEta); + + using FiCentralTracks = soa::Filtered< + soa::Join>; // central tracks for INEL>0 + + void processMult(CollwEv::iterator const& collision, + aod::MFTTracks const& tracks, + FiCentralTracks const& midtracks, aod::Tracks const&) + { + + registry.fill(HIST("EventSelection"), 1.); + if (!useEvSel || (useEvSel && collision.sel8())) { + registry.fill(HIST("EventSelection"), 2.); + auto z = collision.posZ(); + auto perCollisionSample = sampleCentral->sliceByCached( + o2::aod::track::collisionId, collision.globalIndex(), cache); + auto Ntrk = perCollisionSample.size(); + + registry.fill(HIST("EventsNtrkZvtx"), Ntrk, z); + + if (midtracks.size() > 0) // INEL>0 + { + registry.fill(HIST("EventSelection"), 3.); + registry.fill(HIST("EventsNtrkZvtx_gt0"), Ntrk, z); + } + + if (tracks.size() > 0) { + for (auto& track : tracks) { + + float phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + + if (usePhiCut) { + if ((phi < cfgPhiCut) || + ((phi > M_PI - cfgPhiCut) && (phi < M_PI + cfgPhiCut)) || + (phi > 2. * M_PI - cfgPhiCut) || + ((phi > ((M_PI / 2. - 0.1) * M_PI) - cfgPhiCut) && + (phi < ((M_PI / 2. - 0.1) * M_PI) + cfgPhiCut))) + continue; + } + + registry.fill(HIST("TracksEtaZvtx"), track.eta(), z); + if (midtracks.size() > 0) // INEL>0 + { + registry.fill(HIST("Tracks/EtaZvtx_gt0"), track.eta(), z); + } + registry.fill(HIST("TracksPhiEta"), phi, track.eta()); + registry.fill(HIST("TracksPtEta"), track.pt(), track.eta()); + if ((track.eta() < -2.0f) && (track.eta() > -3.9f)) { + registry.fill(HIST("TracksPhiZvtx"), phi, z); + } + } + } + + } else { + registry.fill(HIST("EventSelection"), 4.); + } + } + + PROCESS_SWITCH(PseudorapidityDensityMFT, processMult, + "Process reco or data info", true); + void processMultReassoc(CollwEv::iterator const& collision, + o2::aod::MFTTracks const&, + soa::SmallGroups const& retracks, + FiCentralTracks const& midtracks, aod::Tracks const&) + { + registry.fill(HIST("EventSelection"), 1.); + if (!useEvSel || (useEvSel && collision.sel8())) { + registry.fill(HIST("EventSelection"), 2.); + auto z = collision.posZ(); + if ((z >= cfgVzCut1) && (z <= cfgVzCut2)) { + registry.fill(HIST("EventSelection"), 3.); + auto perCollisionSample = sampleCentral->sliceByCached( + o2::aod::track::collisionId, collision.globalIndex(), cache); + auto Ntrk = perCollisionSample.size(); + std::unordered_set uniqueEvents; + std::unordered_set uniqueEventsAmb; + std::unordered_set uniqueCollisions; + std::unordered_set uniqueCollisionsAmb; + std::unordered_set eventsInelMFT; + std::unordered_set eventsInel; + registry.fill(HIST("EventsNtrkZvtx"), Ntrk, z); + if (midtracks.size() > 0) { + registry.fill(HIST("EventSelection"), 4.); + registry.fill(HIST("EventSelection"), 10.); + registry.fill(HIST("EventsNtrkZvtx_gt0"), Ntrk, z); + eventsInel.insert(collision.globalIndex()); + } + if (perCollisionSample.size() > 0) { + registry.fill(HIST("EventSelection"), 11.); + } + if (midtracks.size() > 0 && perCollisionSample.size() > 0) { + registry.fill(HIST("EventSelection"), 12.); + } + int64_t i = 0.0, j = 0.0, k = 0.0; + if (retracks.size() > 0) { + registry.fill(HIST("EventSelection"), 5.); + for (auto& retrack : retracks) { + auto track = retrack.mfttrack(); + + if ((cfgnEta1 < track.eta()) && (track.eta() < cfgnEta2) && track.nClusters() >= cfgnCluster) { + registry.fill(HIST("TracksEtaZvtx"), track.eta(), z); + if (midtracks.size() > 0 && retrack.ambDegree() > 0) { + registry.fill(HIST("Tracks/EtaZvtx_gt0"), track.eta(), z); + eventsInelMFT.insert(retrack.bestCollisionId()); + } + if (retrack.ambDegree() != 0) { + registry.fill(HIST("Tracks/Control/woOrp/woOrpEtaZvtx_gt0"), track.eta(), z); + ++k; + } + float phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + registry.fill(HIST("Tracks/Control/TrackCount"), 0); + registry.fill(HIST("TracksPhiEta"), phi, track.eta()); + registry.fill(HIST("TracksPtEta"), track.pt(), track.eta()); + if ((track.eta() < -2.0f) && (track.eta() > -3.9f)) { + registry.fill(HIST("TracksPhiZvtx"), phi, z); + } + if (track.collisionId() > -1 && retrack.ambDegree() == 1) { + registry.fill(HIST("Tracks/Control/TrackCount"), 8); + registry.fill(HIST("collisionID"), track.collisionId()); + } + if (track.collisionId() > -1 && retrack.ambDegree() > 1) { + registry.fill(HIST("collisionIDamb"), track.collisionId()); + } + if (track.collisionId() != retrack.bestCollisionId()) { + registry.fill(HIST("Tracks/Control/ReassignedTracksEtaZvtx"), + track.eta(), z); + registry.fill(HIST("Tracks/Control/ReassignedTracksPhiEta"), phi, + track.eta()); + registry.fill(HIST("Tracks/Control/ReassignedVertexCorr"), + track.collision_as().posZ(), z); + + registry.fill(HIST("Tracks/Control/DeltaZ"), + track.collision_as().posZ() - + collision.posZ()); + registry.fill(HIST("Tracks/Control/TrackCount"), 1); + } + if (track.collisionId() == retrack.bestCollisionId()) { + registry.fill(HIST("Tracks/Control/notReassignedTracksEtaZvtx"), + track.eta(), z); + registry.fill(HIST("Tracks/Control/notReassignedTracksPhiEta"), phi, + track.eta()); + registry.fill(HIST("Tracks/Control/notReassignedVertexCorr"), + track.collision_as().posZ(), z); + registry.fill(HIST("Tracks/Control/TrackCount"), 2); + } + + registry.fill(HIST("Tracks/Control/TrackAmbDegree"), + retrack.ambDegree()); + registry.fill(HIST("Tracks/Control/DCAXY"), retrack.bestDCAXY()); + int isAmbiguous = 0; + + if (retrack.ambDegree() > 1 && retrack.ambDegree() != 0) { + isAmbiguous = 1; + ++i; + + registry.fill(HIST("Tracks/Control/amb/EtaZvtxAmb_gt0"), track.eta(), z); + + registry.fill(HIST("Tracks/Control/amb/AmbTracksEtaZvtx"), + track.eta(), z); + registry.fill(HIST("Tracks/Control/amb/AmbTracksPhiEta"), phi, + track.eta()); + registry.fill(HIST("Tracks/Control/amb/AmbVertexCorr"), + track.collision_as().posZ(), z); + registry.fill(HIST("Tracks/Control/TrackCount"), 3); + if (track.collisionId() == retrack.bestCollisionId()) { + registry.fill(HIST("Tracks/Control/TrackCount"), 5); + } + uniqueEventsAmb.insert(retrack.bestCollisionId()); + } + if (midtracks.size() > 0 && retrack.ambDegree() > 1 && retrack.ambDegree() != 0) { + uniqueCollisionsAmb.insert(collision.globalIndex()); + } + + registry.fill(HIST("Tracks/Control/TrackIsAmb"), isAmbiguous); + if (retrack.ambDegree() == 1 && retrack.ambDegree() != 0) { + ++j; + registry.fill(HIST("Tracks/Control/nonamb/EtaZvtxNonAmb_gt0"), track.eta(), z); + registry.fill(HIST("Tracks/Control/nonamb/nonAmbTracksEtaZvtx"), + track.eta(), z); + registry.fill(HIST("Tracks/Control/nonamb/nonAmbTracksPhiEta"), phi, + track.eta()); + registry.fill(HIST("Tracks/Control/nonamb/nonAmbVertexCorr"), + track.collision_as().posZ(), z); + registry.fill(HIST("Tracks/Control/TrackCount"), 4); + if (track.collisionId() == retrack.bestCollisionId()) { + registry.fill(HIST("Tracks/Control/TrackCount"), 6); + } + uniqueEvents.insert(retrack.bestCollisionId()); + } + if (midtracks.size() > 0 && retrack.ambDegree() == 1 && retrack.ambDegree() != 0) { + uniqueCollisions.insert(collision.globalIndex()); + } + if ((retrack.ambDegree() > 1) || (retrack.ambDegree() <= 1)) + registry.fill(HIST("Tracks/Control/TrackCount"), 7); + if (retrack.ambDegree() != 0) { + registry.fill(HIST("Tracks/Control/woOrp/woOrpTracksEtaZvtx"), + track.eta(), z); + registry.fill(HIST("Tracks/Control/woOrp/woOrpTracksPhiEta"), phi, + track.eta()); + registry.fill(HIST("Tracks/Control/woOrp/woOrpVertexCorr"), + track.collision_as().posZ(), z); + registry.fill(HIST("Tracks/Control/TrackCount"), 9); // without orphan + } + } + } + registry.fill(HIST("ambEventCounts"), 1, uniqueEventsAmb.size()); + registry.fill(HIST("NonambEventCounts"), 1, uniqueEvents.size()); + registry.fill(HIST("hNumCollisionsNonAmb_InelMFT"), 1, uniqueCollisions.size()); + registry.fill(HIST("hNumCollisionsAmb_InelMFT"), 1, uniqueCollisionsAmb.size()); + registry.fill(HIST("hNumCollisions_InelMFT"), 1, eventsInelMFT.size()); + } + registry.fill(HIST("Tracks/Control/amb/nTrkAmb"), i); + registry.fill(HIST("Tracks/Control/nonamb/nTrkNonAmb"), j); + registry.fill(HIST("Tracks/Control/woOrp/nTrk"), k); + registry.fill(HIST("hNumCollisions_Inel"), 1, eventsInel.size()); + } + } else { + registry.fill(HIST("EventSelection"), 6); + } + } + PROCESS_SWITCH(PseudorapidityDensityMFT, processMultReassoc, + "Process reco or data info", false); + + using ExColsCent = soa::Join; + + void processCountingCentrality(ExColsCent::iterator const& collision, + aod::MFTTracks const& tracks) + { + auto c = collision.centFT0C(); + registry.fill(HIST("Events/Centrality/Selection"), 1., c); + + if (!useEvSel || collision.sel8()) { + auto z = collision.posZ(); + registry.fill(HIST("Events/Centrality/Selection"), 2., c); + auto perCollisionSample = sample->sliceByCached( + o2::aod::fwdtrack::collisionId, collision.globalIndex(), cache); + auto Ntrk = perCollisionSample.size(); + + registry.fill(HIST("Events/Centrality/NtrkZvtx"), Ntrk, z, c); + + for (auto& track : tracks) { + + float phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + + if (usePhiCut) { + if ((phi < cfgPhiCut) || + ((phi > M_PI - cfgPhiCut) && (phi < M_PI + cfgPhiCut)) || + (phi > 2. * M_PI - cfgPhiCut) || + ((phi > ((M_PI / 2. - 0.1) * M_PI) - cfgPhiCut) && + (phi < ((M_PI / 2. - 0.1) * M_PI) + cfgPhiCut))) + continue; + } + + registry.fill(HIST("Tracks/Centrality/EtaZvtx"), track.eta(), z, c); + registry.fill(HIST("Tracks/Centrality/PhiEta"), phi, track.eta(), c); + } + + } else { + registry.fill(HIST("Events/Centrality/Selection"), 3., + c); // rejected events + } + } + + PROCESS_SWITCH(PseudorapidityDensityMFT, processCountingCentrality, + "Count tracks in centrality bins", false); + + using Particles = soa::Filtered; + expressions::Filter primaries = + (aod::mcparticle::flags & + (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary) == + (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary; + Partition mcSample = nabs(aod::mcparticle::eta) < 1.1f; + Partition mcSampleCentral = + nabs(aod::mcparticle::eta) < estimatorEta; + + void processGen( + aod::McCollisions::iterator const& mcCollision, + o2::soa::SmallGroups> const& collisions, + Particles const& particles, aod::MFTTracks const& /*tracks*/, + FiCentralTracks const& midtracks) + { + registry.fill(HIST("EventEfficiency"), 1.); + + auto perCollisionMCSample = mcSample->sliceByCached( + aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); + auto nCharged = 0; + for (auto& particle : perCollisionMCSample) { + auto charge = 0.; + auto p = pdg->GetParticle(particle.pdgCode()); + if (p != nullptr) { + charge = p->Charge(); + } + if (std::abs(charge) < 3.) { + continue; + } + nCharged++; + } + registry.fill(HIST("EventsNtrkZvtxGen_t"), nCharged, mcCollision.posZ()); + + //--------for INEL>0 + auto perCollisionMCSampleCentral = mcSampleCentral->sliceByCached( + aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); + auto nChargedCentral = 0; + for (auto& particle : perCollisionMCSampleCentral) { + auto charge = 0.; + auto p = pdg->GetParticle(particle.pdgCode()); + if (p != nullptr) { + charge = p->Charge(); + } + if (std::abs(charge) < 3.) { + continue; + } + nChargedCentral++; + } + if ((mcCollision.posZ() >= cfgVzCut1) && (mcCollision.posZ() <= cfgVzCut2)) { + if (nChargedCentral > 0) { + registry.fill(HIST("EventEfficiency"), 2.); + registry.fill(HIST("EventsNtrkZvtxGen_gt0t"), nCharged, + mcCollision.posZ()); + } + } + //----------- + bool atLeastOne = false; + bool atLeastOne_gt0 = false; + int moreThanOne = 0; + + LOGP(debug, "MC col {} has {} reco cols", mcCollision.globalIndex(), + collisions.size()); + for (auto& collision : collisions) { + registry.fill(HIST("EventEfficiency"), 3.); + if (!useEvSel || (useEvSel && collision.sel8())) { + atLeastOne = true; + auto perCollisionSample = sample->sliceByCached( + o2::aod::fwdtrack::collisionId, collision.globalIndex(), cache); + + registry.fill(HIST("EventEfficiency"), 4.); + + auto perCollisionSampleCentral = + midtracks.sliceBy(perColCentral, collision.globalIndex()); + if ((collision.posZ() >= cfgVzCut1) && (collision.posZ() <= cfgVzCut2) && (mcCollision.posZ() >= cfgVzCut1) && (mcCollision.posZ() <= cfgVzCut2)) { + if (perCollisionSampleCentral.size() > 0) { + registry.fill(HIST("EventEfficiency"), 5.); + atLeastOne_gt0 = true; + registry.fill(HIST("EventsNtrkZvtxGen_gt0"), + perCollisionSample.size(), collision.posZ()); + } + + registry.fill(HIST("EventsZposDiff"), + collision.posZ() - mcCollision.posZ()); + if (useZDiffCut) { + if (std::abs(collision.posZ() - mcCollision.posZ()) > maxZDiff) { + continue; + } + } + registry.fill(HIST("EventsNtrkZvtxGen"), perCollisionSample.size(), + collision.posZ()); + ++moreThanOne; + } + } + } + if (collisions.size() == 0) { + registry.fill(HIST("NotFoundEventZvtx"), mcCollision.posZ()); + } + if (moreThanOne > 1) { + registry.fill(HIST("EventsSplitMult"), nCharged); + } + if ((mcCollision.posZ() >= cfgVzCut1) && (mcCollision.posZ() <= cfgVzCut2)) { + for (auto& particle : particles) { + auto p = pdg->GetParticle(particle.pdgCode()); + auto charge = 0; + if (p != nullptr) { + charge = static_cast(p->Charge()); + } + if (std::abs(charge) < 3.) { + continue; + } + + registry.fill(HIST("TracksEtaZvtxGen_t"), particle.eta(), + mcCollision.posZ()); + if (perCollisionMCSampleCentral.size() > 0) { + registry.fill(HIST("TracksEtaZvtxGen_gt0t"), particle.eta(), + mcCollision.posZ()); + registry.fill(HIST("TracksPhiEtaGen_gt0t"), particle.phi(), particle.eta()); + } + if (atLeastOne) { + registry.fill(HIST("TracksEtaZvtxGen"), particle.eta(), + mcCollision.posZ()); + registry.fill(HIST("TracksPtEtaGen"), particle.pt(), particle.eta()); + if (atLeastOne_gt0) { + registry.fill(HIST("TracksEtaZvtxGen_gt0"), particle.eta(), + mcCollision.posZ()); + registry.fill(HIST("TracksPhiEtaGen_gt0"), particle.phi(), particle.eta()); + } + } + + registry.fill(HIST("TracksPhiEtaGen"), particle.phi(), particle.eta()); + registry.fill(HIST("TracksPhiZvtxGen"), particle.phi(), + mcCollision.posZ()); + registry.fill(HIST("TracksPtEtaGen_t"), particle.pt(), particle.eta()); + } + } + } + + PROCESS_SWITCH(PseudorapidityDensityMFT, processGen, + "Process generator-level info", false); + + using ExColsGenCent = + soa::SmallGroups>; + + void processGenCent(aod::McCollisions::iterator const& mcCollision, + ExColsGenCent const& collisions, + Particles const& particles, + MFTTracksLabeled const& /*tracks*/) + { + + LOGP(debug, "MC col {} has {} reco cols", mcCollision.globalIndex(), + collisions.size()); + + float c_gen = -1; + bool atLeastOne = false; + for (auto& collision : collisions) { + float c_rec = -1; + if constexpr (ExColsGenCent::template contains()) { + c_rec = collision.centFT0C(); + } + if (!useEvSel || (useEvSel && collision.sel8())) { + if constexpr (ExColsGenCent::template contains()) { + if (!atLeastOne) { + c_gen = c_rec; + } + } + atLeastOne = true; + + registry.fill(HIST("Events/Centrality/EventEfficiency"), 2., c_gen); + registry.fill(HIST("Events/Centrality/CentPercentileMCGen"), c_gen); + + auto perCollisionSample = sample->sliceByCached( + o2::aod::fwdtrack::collisionId, collision.globalIndex(), cache); + registry.fill(HIST("Events/Centrality/NtrkZvtxGen"), + perCollisionSample.size(), collision.posZ(), c_gen); + } + } + + registry.fill(HIST("Events/Centrality/EventEfficiency"), 1., c_gen); + + auto perCollisionMCSample = mcSample->sliceByCached( + aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); + auto nCharged = 0; + + for (auto& particle : perCollisionMCSample) { + auto p = pdg->GetParticle(particle.pdgCode()); + auto charge = 0; + if (p != nullptr) { + charge = static_cast(p->Charge()); + } + if (std::abs(charge) < 3.) { + continue; + } + nCharged++; + } + + if constexpr (ExColsGenCent::template contains()) { + registry.fill(HIST("Events/Centrality/NtrkZvtxGen_t"), nCharged, + mcCollision.posZ(), c_gen); + } + + for (auto& particle : particles) { + auto p = pdg->GetParticle(particle.pdgCode()); + auto charge = 0; + if (p != nullptr) { + charge = static_cast(p->Charge()); + } + if (std::abs(charge) < 3.) { + continue; + } + + if constexpr (ExColsGenCent::template contains()) { + registry.fill(HIST("Tracks/Centrality/EtaZvtxGen_t"), particle.eta(), + mcCollision.posZ(), c_gen); + } + + if (atLeastOne) { + if constexpr (ExColsGenCent::template contains()) { + registry.fill(HIST("Tracks/Centrality/EtaZvtxGen"), particle.eta(), + mcCollision.posZ(), c_gen); + float phi = particle.phi(); + o2::math_utils::bringTo02Pi(phi); + registry.fill(HIST("Tracks/Centrality/PhiEtaGen"), phi, + particle.eta(), c_gen); + } + } + } + } + + PROCESS_SWITCH(PseudorapidityDensityMFT, processGenCent, + "Process generator-level info in centrality bins", false); + + void processGenPt( + soa::Join::iterator const& collision, + MFTTracksLabeled const& tracks, aod::McParticles const&) + { + if (!useEvSel || (useEvSel && collision.sel8())) { + for (auto& track : tracks) { + if (!track.has_mcParticle()) { + continue; + } + auto particle = track.mcParticle(); + if (!particle.isPhysicalPrimary()) { + continue; + } + registry.fill(HIST("TracksToPartPtEta"), particle.pt(), particle.eta()); + } + } + } + + PROCESS_SWITCH(PseudorapidityDensityMFT, processGenPt, + "Process particle-level info of pt", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/GlobalEventProperties/heavyionMultiplicity.cxx b/PWGLF/Tasks/GlobalEventProperties/heavyionMultiplicity.cxx new file mode 100644 index 00000000000..435fc106062 --- /dev/null +++ b/PWGLF/Tasks/GlobalEventProperties/heavyionMultiplicity.cxx @@ -0,0 +1,818 @@ +// 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 heavyionMultiplicity.cxx +/// +/// \brief task for analysis of charged-particle multiplicity at midrapidity +/// \author Abhi Modak (abhi.modak@cern.ch) +/// \since September 15, 2023 + +#include +#include +#include +#include + +#include "PWGMM/Mult/DataModel/bestCollisionTable.h" +#include "CCDB/BasicCCDBManager.h" +#include "Common/Core/trackUtilities.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "CommonConstants/MathConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/Track.h" +#include "PWGMM/Mult/DataModel/Index.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::track; +using namespace o2::aod::evsel; + +using CollisionDataTable = soa::Join; +using TrackDataTable = soa::Join; +using FilTrackDataTable = soa::Filtered; +using CollisionMCTrueTable = aod::McCollisions; +using TrackMCTrueTable = aod::McParticles; +using CollisionMCRecTable = soa::SmallGroups>; +using TrackMCRecTable = soa::Join; +using FilTrackMCRecTable = soa::Filtered; +using V0TrackCandidates = soa::Join; + +enum { + kTrackTypebegin = 0, + kGlobalplusITS = 1, + kGlobalonly, + kITSonly, + kTrackTypeend +}; + +enum { + kGenpTbegin = 0, + kNoGenpTVar = 1, + kGenpTup, + kGenpTdown, + kGenpTend +}; + +enum { + kSpeciesbegin = 0, + kSpPion = 1, + kSpKaon, + kSpProton, + kSpOther, + kSpStrangeDecay, + kBkg, + kSpNotPrimary, + kSpAll, + kSpeciesend +}; + +static constexpr TrackSelectionFlags::flagtype TrackSelectionIts = + TrackSelectionFlags::kITSNCls | TrackSelectionFlags::kITSChi2NDF | + TrackSelectionFlags::kITSHits; +static constexpr TrackSelectionFlags::flagtype TrackSelectionTpc = + TrackSelectionFlags::kTPCNCls | + TrackSelectionFlags::kTPCCrossedRowsOverNCls | + TrackSelectionFlags::kTPCChi2NDF; +static constexpr TrackSelectionFlags::flagtype TrackSelectionDca = + TrackSelectionFlags::kDCAz | TrackSelectionFlags::kDCAxy; +static constexpr TrackSelectionFlags::flagtype TrackSelectionDcaxyOnly = + TrackSelectionFlags::kDCAxy; + +AxisSpec axisEvent{10, 0.5, 10.5, "#Event", "EventAxis"}; +AxisSpec axisVtxZ{40, -20, 20, "Vertex Z", "VzAxis"}; +AxisSpec axisEta{40, -2, 2, "#eta", "EtaAxis"}; +AxisSpec axisPhi{{0, o2::constants::math::PIQuarter, o2::constants::math::PIHalf, o2::constants::math::PIQuarter * 3., o2::constants::math::PI, o2::constants::math::PIQuarter * 5., o2::constants::math::PIHalf * 3., o2::constants::math::PIQuarter * 7., o2::constants::math::TwoPI}, "#phi", "PhiAxis"}; +AxisSpec axisPhi2{629, 0, o2::constants::math::TwoPI, "#phi"}; +AxisSpec axisCent{100, 0, 100, "#Cent"}; +AxisSpec axisTrackType = {kTrackTypeend - 1, +kTrackTypebegin + 0.5, +kTrackTypeend - 0.5, "", "TrackTypeAxis"}; +AxisSpec axisGenPtVary = {kGenpTend - 1, +kGenpTbegin + 0.5, +kGenpTend - 0.5, "", "GenpTVaryAxis"}; +AxisSpec axisSpecies = {kSpeciesend - 1, +kSpeciesbegin + 0.5, +kSpeciesend - 0.5, "", "SpeciesAxis"}; +AxisSpec axisMassK0s = {200, 0.4, 0.6, "K0sMass", "K0sMass"}; +AxisSpec axisMassLambda = {200, 1.07, 1.17, "Lambda/AntiLamda Mass", "Lambda/AntiLamda Mass"}; +AxisSpec axisTracks{9, 0.5, 9.5, "#tracks", "TrackAxis"}; +auto static constexpr kMinCharge = 3.f; +auto static constexpr kMinpTcut = 0.1f; +auto static constexpr kMinCent = 0.0f; +auto static constexpr kMaxCent = 100.0f; +auto static constexpr kEtaInelgt0 = 1.0f; +auto static constexpr kNItslayers = 7; + +struct HeavyionMultiplicity { + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Service pdg; + Preslice perCollision = aod::track::collisionId; + + Configurable etaRange{"etaRange", 1.0f, "Eta range to consider"}; + Configurable vtxRange{"vtxRange", 10.0f, "Vertex Z range to consider"}; + Configurable dcaZ{"dcaZ", 0.2f, "Custom DCA Z cut (ignored if negative)"}; + Configurable v0radiusCut{"v0radiusCut", 1.2f, "RadiusCut"}; + Configurable dcapostopvCut{"dcapostopvCut", 0.05f, "dcapostopvCut"}; + Configurable dcanegtopvCut{"dcanegtopvCut", 0.05f, "dcanegtopvCut"}; + Configurable v0cospaCut{"v0cospaCut", 0.995f, "v0cospaCut"}; + Configurable dcav0daughtercut{"dcav0daughtercut", 1.0f, "dcav0daughtercut"}; + Configurable minTPCnClsCut{"minTPCnClsCut", 50.0f, "minTPCnClsCut"}; + Configurable nSigmaTpcCut{"nSigmaTpcCut", 5.0f, "nSigmaTpcCut"}; + Configurable v0etaCut{"v0etaCut", 0.9f, "v0etaCut"}; + Configurable extraphicut1{"extraphicut1", 3.07666f, "Extra Phi cut 1"}; + Configurable extraphicut2{"extraphicut2", 3.12661f, "Extra Phi cut 2"}; + Configurable extraphicut3{"extraphicut3", 0.03f, "Extra Phi cut 3"}; + Configurable extraphicut4{"extraphicut4", 6.253f, "Extra Phi cut 4"}; + ConfigurableAxis multHistBin{"multHistBin", {501, -0.5, 500.5}, ""}; + ConfigurableAxis pvHistBin{"pvHistBin", {501, -0.5, 500.5}, ""}; + ConfigurableAxis fv0aMultHistBin{"fv0aMultHistBin", {501, -0.5, 500.5}, ""}; + ConfigurableAxis ft0aMultHistBin{"ft0aMultHistBin", {501, -0.5, 500.5}, ""}; + ConfigurableAxis ft0cMultHistBin{"ft0cMultHistBin", {501, -0.5, 500.5}, ""}; + ConfigurableAxis ptHistBin{"ptHistBin", {200, 0., 20.}, ""}; + ConfigurableAxis centralityBinning{"centralityBinning", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}, ""}; + ConfigurableAxis occupancyBin{"occupancyBin", {VARIABLE_WIDTH, 0, 500, 1000, 2000, 5000, 10000}, ""}; + + Configurable isApplySameBunchPileup{"isApplySameBunchPileup", true, "Enable SameBunchPileup cut"}; + Configurable isApplyGoodZvtxFT0vsPV{"isApplyGoodZvtxFT0vsPV", true, "Enable GoodZvtxFT0vsPV cut"}; + Configurable isApplyExtraCorrCut{"isApplyExtraCorrCut", false, "Enable extra NPVtracks vs FTOC correlation cut"}; + Configurable isApplyExtraPhiCut{"isApplyExtraPhiCut", false, "Enable extra phi cut"}; + Configurable npvTracksCut{"npvTracksCut", 1.0f, "Apply extra NPVtracks cut"}; + Configurable ft0cCut{"ft0cCut", 1.0f, "Apply extra FT0C cut"}; + Configurable isApplyNoCollInTimeRangeStandard{"isApplyNoCollInTimeRangeStandard", true, "Enable NoCollInTimeRangeStandard cut"}; + Configurable isApplyNoCollInRofStandard{"isApplyNoCollInRofStandard", false, "Enable NoCollInRofStandard cut"}; + Configurable isApplyNoHighMultCollInPrevRof{"isApplyNoHighMultCollInPrevRof", false, "Enable NoHighMultCollInPrevRof cut"}; + Configurable isApplyFT0CbasedOccupancy{"isApplyFT0CbasedOccupancy", false, "Enable FT0CbasedOccupancy cut"}; + Configurable isApplyCentFT0C{"isApplyCentFT0C", true, "Centrality based on FT0C"}; + Configurable isApplyCentFT0CVariant1{"isApplyCentFT0CVariant1", false, "Centrality based on FT0C variant1"}; + Configurable isApplyCentFT0M{"isApplyCentFT0M", false, "Centrality based on FT0A + FT0C"}; + Configurable isApplyCentNGlobal{"isApplyCentNGlobal", false, "Centrality based on global tracks"}; + Configurable isApplyCentMFT{"isApplyCentMFT", false, "Centrality based on MFT tracks"}; + + void init(InitContext const&) + { + AxisSpec axisMult = {multHistBin, "Mult", "MultAxis"}; + AxisSpec axisPV = {pvHistBin, "PV", "PVAxis"}; + AxisSpec axisFv0aMult = {fv0aMultHistBin, "fv0a", "FV0AMultAxis"}; + AxisSpec axisFt0aMult = {ft0aMultHistBin, "ft0a", "FT0AMultAxis"}; + AxisSpec axisFt0cMult = {ft0cMultHistBin, "ft0c", "FT0CMultAxis"}; + AxisSpec centAxis = {centralityBinning, "Centrality", "CentralityAxis"}; + AxisSpec axisPt = {ptHistBin, "pT", "pTAxis"}; + AxisSpec axisOccupancy = {occupancyBin, "occupancy", "OccupancyAxis"}; + + histos.add("EventHist", "EventHist", kTH1D, {axisEvent}, false); + histos.add("VtxZHist", "VtxZHist", kTH1D, {axisVtxZ}, false); + + auto hstat = histos.get(HIST("EventHist")); + auto* x = hstat->GetXaxis(); + x->SetBinLabel(1, "All events"); + x->SetBinLabel(2, "sel8"); + x->SetBinLabel(3, "kNoSameBunchPileup"); // reject collisions in case of pileup with another collision in the same foundBC + x->SetBinLabel(4, "kIsGoodZvtxFT0vsPV"); // small difference between z-vertex from PV and from FT0 + x->SetBinLabel(5, "Centrality"); + x->SetBinLabel(6, "ApplyExtraCorrCut"); + x->SetBinLabel(7, "ApplyNoCollInTimeRangeStandard"); + x->SetBinLabel(8, "ApplyNoCollInRofStandard"); + x->SetBinLabel(9, "ApplyNoHighMultCollInPrevRof"); + + if (doprocessData) { + histos.add("CentPercentileHist", "CentPercentileHist", kTH1D, {axisCent}, false); + histos.add("hdatazvtxcent", "hdatazvtxcent", kTH3D, {axisVtxZ, centAxis, axisOccupancy}, false); + histos.add("PhiVsEtaHist", "PhiVsEtaHist", kTH2D, {axisPhi2, axisEta}, false); + histos.add("hdatadndeta", "hdatadndeta", kTHnSparseD, {axisVtxZ, centAxis, axisOccupancy, axisEta, axisPhi, axisTrackType}, false); + } + + if (doprocessMonteCarlo || doprocessMCpTefficiency || doprocessMCcheckFakeTracks) { + histos.add("CentPercentileMCRecHist", "CentPercentileMCRecHist", kTH1D, {axisCent}, false); + histos.add("hmczvtxcent", "hmczvtxcent", kTH3D, {axisVtxZ, centAxis, axisOccupancy}, false); + } + + if (doprocessMonteCarlo) { + histos.add("MCrecPhiVsEtaHist", "MCrecPhiVsEtaHist", kTH2D, {axisPhi2, axisEta}, false); + histos.add("hmcrecdndeta", "hmcrecdndeta", kTHnSparseD, {axisVtxZ, centAxis, axisOccupancy, axisEta, axisPhi, axisSpecies, axisTrackType}, false); + histos.add("hmcgendndeta", "hmcgendndeta", kTHnSparseD, {axisVtxZ, centAxis, axisEta, axisPhi, axisSpecies, axisGenPtVary}, false); + } + + if (doprocessMCpTefficiency) { + histos.add("hmcrecdndpt", "hmcrecdndpt", kTHnSparseD, {centAxis, axisOccupancy, axisTrackType, axisPt}, false); + histos.add("hmcgendndpt", "hmcgendndpt", kTHnSparseD, {centAxis, axisPt, axisGenPtVary}, false); + } + + if (doprocessMCcheckFakeTracks) { + histos.add("hTracksCount", "hTracksCount", kTHnSparseD, {centAxis, axisTracks}, false); + auto htrack = histos.get(HIST("hTracksCount")); + auto* x2 = htrack->GetAxis(1); + x2->SetBinLabel(1, "All tracks"); + x2->SetBinLabel(2, "Non-fake tracks"); + for (int i = 0; i < kNItslayers; i++) { + x2->SetBinLabel(i + 3, Form("layer %d", i)); + } + } + + if (doprocessCorrelation) { + histos.add("GlobalMult_vs_FT0A", "GlobalMult_vs_FT0A", kTH2F, {axisMult, axisFt0aMult}, true); + histos.add("GlobalMult_vs_FT0C", "GlobalMult_vs_FT0C", kTH2F, {axisMult, axisFt0cMult}, true); + histos.add("NPVtracks_vs_FT0C", "NPVtracks_vs_FT0C", kTH2F, {axisPV, axisFt0cMult}, true); + histos.add("GlobalMult_vs_FV0A", "GlobalMult_vs_FV0A", kTH2F, {axisMult, axisFv0aMult}, true); + histos.add("NPVtracks_vs_GlobalMult", "NPVtracks_vs_GlobalMult", kTH2F, {axisPV, axisMult}, true); + } + + if (doprocessStrangeYield) { + histos.add("hzvtxcent", "hzvtxcent", kTH2D, {axisVtxZ, centAxis}, false); + histos.add("K0sCentEtaMass", "K0sCentEtaMass", kTH3D, {centAxis, axisEta, axisMassK0s}, false); + histos.add("LambdaCentEtaMass", "LambdaCentEtaMass", kTH3D, {centAxis, axisEta, axisMassLambda}, false); + histos.add("AntiLambdaCentEtaMass", "AntiLambdaCentEtaMass", kTH3D, {centAxis, axisEta, axisMassLambda}, false); + } + + if (doprocessppData) { + histos.add("MultPercentileHist", "MultPercentileHist", kTH1D, {axisCent}, false); + histos.add("hdatazvtxmultpp", "hdatazvtxmultpp", kTH2D, {axisVtxZ, centAxis}, false); + histos.add("PhiVsEtaHistpp", "PhiVsEtaHistpp", kTH2D, {axisPhi2, axisEta}, false); + histos.add("hdatadndetapp", "hdatadndetapp", kTHnSparseD, {axisVtxZ, centAxis, axisEta, axisPhi, axisTrackType}, false); + } + + if (doprocessppMonteCarlo) { + histos.add("MultPercentileMCRecHist", "MultPercentileMCRecHist", kTH1D, {axisCent}, false); + histos.add("hmczvtxmultpp", "hmczvtxmultpp", kTH2D, {axisVtxZ, centAxis}, false); + histos.add("MCrecPhiVsEtaHistpp", "MCrecPhiVsEtaHistpp", kTH2D, {axisPhi2, axisEta}, false); + histos.add("hmcrecdndetapp", "hmcrecdndetapp", kTHnSparseD, {axisVtxZ, centAxis, axisEta, axisPhi, axisSpecies, axisTrackType}, false); + histos.add("hmcgendndetapp", "hmcgendndetapp", kTHnSparseD, {axisVtxZ, centAxis, axisEta, axisPhi, axisSpecies, axisGenPtVary}, false); + } + } + + template + bool isEventSelected(CheckCol const& col) + { + histos.fill(HIST("EventHist"), 1); + + if (!col.sel8()) { + return false; + } + histos.fill(HIST("EventHist"), 2); + + if (isApplySameBunchPileup && !col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + histos.fill(HIST("EventHist"), 3); + + if (isApplyGoodZvtxFT0vsPV && !col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + histos.fill(HIST("EventHist"), 4); + + if (selColCent(col) < kMinCent || selColCent(col) > kMaxCent) { + return false; + } + histos.fill(HIST("EventHist"), 5); + + if (isApplyExtraCorrCut && col.multNTracksPV() > npvTracksCut && col.multFT0C() < (10 * col.multNTracksPV() - ft0cCut)) { + return false; + } + histos.fill(HIST("EventHist"), 6); + + if (isApplyNoCollInTimeRangeStandard && !col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + histos.fill(HIST("EventHist"), 7); + + if (isApplyNoCollInRofStandard && !col.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + histos.fill(HIST("EventHist"), 8); + + if (isApplyNoHighMultCollInPrevRof && !col.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + return false; + } + histos.fill(HIST("EventHist"), 9); + return true; + } + + template + float selColCent(CheckColCent const& col) + { + auto cent = -1; + if (isApplyCentFT0C) { + cent = col.centFT0C(); + } + if (isApplyCentFT0CVariant1) { + cent = col.centFT0CVariant1(); + } + if (isApplyCentFT0M) { + cent = col.centFT0M(); + } + if (isApplyCentNGlobal) { + cent = col.centNGlobal(); + } + if (isApplyCentMFT) { + cent = col.centMFT(); + } + return cent; + } + + template + float selColOccu(CheckColOccu const& col) + { + auto occu = isApplyFT0CbasedOccupancy ? col.ft0cOccupancyInTimeRange() : col.trackOccupancyInTimeRange(); + return occu; + } + + template + bool isTrackSelected(CheckTrack const& track) + { + if (std::abs(track.eta()) >= etaRange) { + return false; + } + if (isApplyExtraPhiCut && ((track.phi() > extraphicut1 && track.phi() < extraphicut2) || track.phi() <= extraphicut3 || track.phi() >= extraphicut4)) { + return false; + } + return true; + } + + template + bool isGenTrackSelected(CheckGenTrack const& track) + { + if (!track.isPhysicalPrimary()) { + return false; + } + if (!track.producedByGenerator()) { + return false; + } + auto pdgTrack = pdg->GetParticle(track.pdgCode()); + if (pdgTrack == nullptr) { + return false; + } + if (std::abs(pdgTrack->Charge()) < kMinCharge) { + return false; + } + if (std::abs(track.eta()) >= etaRange) { + return false; + } + if (isApplyExtraPhiCut && ((track.phi() > extraphicut1 && track.phi() < extraphicut2) || track.phi() <= extraphicut3 || track.phi() >= extraphicut4)) { + return false; + } + return true; + } + + expressions::Filter trackSelectionProperMixed = ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) && + ncheckbit(aod::track::trackCutFlag, TrackSelectionIts) && + ifnode(ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC), + ncheckbit(aod::track::trackCutFlag, TrackSelectionTpc), true) && + ifnode(dcaZ.node() > 0.f, nabs(aod::track::dcaZ) <= dcaZ && ncheckbit(aod::track::trackCutFlag, TrackSelectionDcaxyOnly), + ncheckbit(aod::track::trackCutFlag, TrackSelectionDca)); + + void processData(CollisionDataTable::iterator const& cols, FilTrackDataTable const& tracks) + { + if (!isEventSelected(cols)) { + return; + } + histos.fill(HIST("VtxZHist"), cols.posZ()); + histos.fill(HIST("CentPercentileHist"), selColCent(cols)); + histos.fill(HIST("hdatazvtxcent"), cols.posZ(), selColCent(cols), selColOccu(cols)); + + for (const auto& track : tracks) { + if (!isTrackSelected(track)) { + continue; + } + histos.fill(HIST("PhiVsEtaHist"), track.phi(), track.eta()); + histos.fill(HIST("hdatadndeta"), cols.posZ(), selColCent(cols), selColOccu(cols), track.eta(), track.phi(), kGlobalplusITS); + if (track.hasTPC()) { + histos.fill(HIST("hdatadndeta"), cols.posZ(), selColCent(cols), selColOccu(cols), track.eta(), track.phi(), kGlobalonly); + } else { + histos.fill(HIST("hdatadndeta"), cols.posZ(), selColCent(cols), selColOccu(cols), track.eta(), track.phi(), kITSonly); + } + } + } + PROCESS_SWITCH(HeavyionMultiplicity, processData, "process data CentFT0C", false); + + void processCorrelation(CollisionDataTable::iterator const& cols, FilTrackDataTable const& tracks) + { + if (!isEventSelected(cols)) { + return; + } + if (std::abs(cols.posZ()) >= vtxRange) { + return; + } + histos.fill(HIST("VtxZHist"), cols.posZ()); + + auto nchTracks = 0; + for (const auto& track : tracks) { + if (std::abs(track.eta()) >= etaRange) { + continue; + } + nchTracks++; + } + histos.fill(HIST("GlobalMult_vs_FT0A"), nchTracks, cols.multFT0A()); + histos.fill(HIST("GlobalMult_vs_FT0C"), nchTracks, cols.multFT0C()); + histos.fill(HIST("NPVtracks_vs_FT0C"), cols.multNTracksPV(), cols.multFT0C()); + histos.fill(HIST("GlobalMult_vs_FV0A"), nchTracks, cols.multFV0A()); + histos.fill(HIST("NPVtracks_vs_GlobalMult"), cols.multNTracksPV(), nchTracks); + } + PROCESS_SWITCH(HeavyionMultiplicity, processCorrelation, "do correlation study in data", false); + + void processMonteCarlo(CollisionMCTrueTable::iterator const&, CollisionMCRecTable const& RecCols, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + { + for (const auto& RecCol : RecCols) { + if (!isEventSelected(RecCol)) { + continue; + } + histos.fill(HIST("VtxZHist"), RecCol.posZ()); + histos.fill(HIST("CentPercentileMCRecHist"), selColCent(RecCol)); + histos.fill(HIST("hmczvtxcent"), RecCol.posZ(), selColCent(RecCol), selColOccu(RecCol)); + + auto recTracksPart = RecTracks.sliceBy(perCollision, RecCol.globalIndex()); + std::vector mclabels; + for (const auto& Rectrack : recTracksPart) { + if (!isTrackSelected(Rectrack)) { + continue; + } + histos.fill(HIST("MCrecPhiVsEtaHist"), Rectrack.phi(), Rectrack.eta()); + histos.fill(HIST("hmcrecdndeta"), RecCol.posZ(), selColCent(RecCol), selColOccu(RecCol), Rectrack.eta(), Rectrack.phi(), static_cast(kSpAll), kGlobalplusITS); + if (Rectrack.hasTPC()) { + histos.fill(HIST("hmcrecdndeta"), RecCol.posZ(), selColCent(RecCol), selColOccu(RecCol), Rectrack.eta(), Rectrack.phi(), static_cast(kSpAll), kGlobalonly); + } else { + histos.fill(HIST("hmcrecdndeta"), RecCol.posZ(), selColCent(RecCol), selColOccu(RecCol), Rectrack.eta(), Rectrack.phi(), static_cast(kSpAll), kITSonly); + } + + if (Rectrack.has_mcParticle()) { + int pid = kBkg; + auto mcpart = Rectrack.template mcParticle_as(); + if (mcpart.isPhysicalPrimary()) { + switch (std::abs(mcpart.pdgCode())) { + case PDG_t::kPiPlus: + pid = kSpPion; + break; + case PDG_t::kKPlus: + pid = kSpKaon; + break; + case PDG_t::kProton: + pid = kSpProton; + break; + default: + pid = kSpOther; + break; + } + } else { + pid = kSpNotPrimary; + } + if (mcpart.has_mothers()) { + auto mcpartMother = mcpart.template mothers_as().front(); + if (mcpartMother.pdgCode() == PDG_t::kK0Short || std::abs(mcpartMother.pdgCode()) == PDG_t::kLambda0) { + pid = kSpStrangeDecay; + } + } + if (find(mclabels.begin(), mclabels.end(), Rectrack.mcParticleId()) != mclabels.end()) { + pid = kBkg; + } + mclabels.push_back(Rectrack.mcParticleId()); + histos.fill(HIST("hmcrecdndeta"), RecCol.posZ(), selColCent(RecCol), selColOccu(RecCol), Rectrack.eta(), Rectrack.phi(), static_cast(pid), kGlobalplusITS); + } else { + histos.fill(HIST("hmcrecdndeta"), RecCol.posZ(), selColCent(RecCol), selColOccu(RecCol), Rectrack.eta(), Rectrack.phi(), static_cast(kBkg), kGlobalplusITS); + } + } // track (mcrec) loop + + for (const auto& particle : GenParticles) { + if (!isGenTrackSelected(particle)) { + continue; + } + histos.fill(HIST("hmcgendndeta"), RecCol.posZ(), selColCent(RecCol), particle.eta(), particle.phi(), static_cast(kSpAll), kNoGenpTVar); + if (particle.pt() < kMinpTcut) { + histos.fill(HIST("hmcgendndeta"), RecCol.posZ(), selColCent(RecCol), particle.eta(), particle.phi(), static_cast(kSpAll), kGenpTup, -10.0 * particle.pt() + 2); + histos.fill(HIST("hmcgendndeta"), RecCol.posZ(), selColCent(RecCol), particle.eta(), particle.phi(), static_cast(kSpAll), kGenpTdown, 5.0 * particle.pt() + 0.5); + } else { + histos.fill(HIST("hmcgendndeta"), RecCol.posZ(), selColCent(RecCol), particle.eta(), particle.phi(), static_cast(kSpAll), kGenpTup); + histos.fill(HIST("hmcgendndeta"), RecCol.posZ(), selColCent(RecCol), particle.eta(), particle.phi(), static_cast(kSpAll), kGenpTdown); + } + + int pid = 0; + switch (std::abs(particle.pdgCode())) { + case PDG_t::kPiPlus: + pid = kSpPion; + break; + case PDG_t::kKPlus: + pid = kSpKaon; + break; + case PDG_t::kProton: + pid = kSpProton; + break; + default: + pid = kSpOther; + break; + } + histos.fill(HIST("hmcgendndeta"), RecCol.posZ(), selColCent(RecCol), particle.eta(), particle.phi(), static_cast(pid), kNoGenpTVar); + } // track (mcgen) loop + } // collision loop + } + PROCESS_SWITCH(HeavyionMultiplicity, processMonteCarlo, "process MC CentFT0C", false); + + void processMCpTefficiency(CollisionMCTrueTable::iterator const&, CollisionMCRecTable const& RecCols, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + { + for (const auto& RecCol : RecCols) { + if (!isEventSelected(RecCol)) { + continue; + } + if (std::abs(RecCol.posZ()) >= vtxRange) { + continue; + } + histos.fill(HIST("VtxZHist"), RecCol.posZ()); + histos.fill(HIST("CentPercentileMCRecHist"), selColCent(RecCol)); + histos.fill(HIST("hmczvtxcent"), RecCol.posZ(), selColCent(RecCol), selColOccu(RecCol)); + + auto recTracksPart = RecTracks.sliceBy(perCollision, RecCol.globalIndex()); + for (const auto& Rectrack : recTracksPart) { + if (std::abs(Rectrack.eta()) >= etaRange) { + continue; + } + if (Rectrack.has_mcParticle()) { + auto mcpart = Rectrack.mcParticle(); + if (mcpart.isPhysicalPrimary()) { + histos.fill(HIST("hmcrecdndpt"), selColCent(RecCol), selColOccu(RecCol), kGlobalplusITS, mcpart.pt()); + if (Rectrack.hasTPC()) { + histos.fill(HIST("hmcrecdndpt"), selColCent(RecCol), selColOccu(RecCol), kGlobalonly, mcpart.pt()); + } else { + histos.fill(HIST("hmcrecdndpt"), selColCent(RecCol), selColOccu(RecCol), kITSonly, mcpart.pt()); + } + } + } + } + + for (const auto& particle : GenParticles) { + if (!isGenTrackSelected(particle)) { + continue; + } + histos.fill(HIST("hmcgendndpt"), selColCent(RecCol), particle.pt(), kNoGenpTVar); + if (particle.pt() < kMinpTcut) { + histos.fill(HIST("hmcgendndpt"), selColCent(RecCol), particle.pt(), kGenpTup, -10.0 * particle.pt() + 2); + histos.fill(HIST("hmcgendndpt"), selColCent(RecCol), particle.pt(), kGenpTdown, 5.0 * particle.pt() + 0.5); + } else { + histos.fill(HIST("hmcgendndpt"), selColCent(RecCol), particle.pt(), kGenpTup); + histos.fill(HIST("hmcgendndpt"), selColCent(RecCol), particle.pt(), kGenpTdown); + } + } + } + } + PROCESS_SWITCH(HeavyionMultiplicity, processMCpTefficiency, "process MC pTefficiency", false); + + void processMCcheckFakeTracks(CollisionMCTrueTable::iterator const&, CollisionMCRecTable const& RecCols, FilTrackMCRecTable const& RecTracks) + { + for (const auto& RecCol : RecCols) { + if (!isEventSelected(RecCol)) { + continue; + } + if (std::abs(RecCol.posZ()) >= vtxRange) { + continue; + } + histos.fill(HIST("VtxZHist"), RecCol.posZ()); + histos.fill(HIST("CentPercentileMCRecHist"), selColCent(RecCol)); + histos.fill(HIST("hmczvtxcent"), RecCol.posZ(), selColCent(RecCol), selColOccu(RecCol)); + + auto recTracksPart = RecTracks.sliceBy(perCollision, RecCol.globalIndex()); + for (const auto& Rectrack : recTracksPart) { + if (std::abs(Rectrack.eta()) >= etaRange) { + continue; + } + if (!Rectrack.hasTPC()) { + continue; + } + histos.fill(HIST("hTracksCount"), selColCent(RecCol), 1); + bool isFakeItsTracks = false; + for (int i = 0; i < kNItslayers; i++) { + if (Rectrack.mcMask() & 1 << i) { + isFakeItsTracks = true; + histos.fill(HIST("hTracksCount"), selColCent(RecCol), i + 3); + break; + } + } + if (isFakeItsTracks) { + continue; + } + histos.fill(HIST("hTracksCount"), selColCent(RecCol), 2); + } + } + } + PROCESS_SWITCH(HeavyionMultiplicity, processMCcheckFakeTracks, "Check Fake tracks", false); + + void processStrangeYield(CollisionDataTable::iterator const& cols, V0TrackCandidates const&, aod::V0Datas const& v0data) + { + if (!isEventSelected(cols)) { + return; + } + if (std::abs(cols.posZ()) >= vtxRange) { + return; + } + histos.fill(HIST("hzvtxcent"), cols.posZ(), selColCent(cols)); + for (const auto& v0track : v0data) { + auto v0pTrack = v0track.template posTrack_as(); + auto v0nTrack = v0track.template negTrack_as(); + if (std::abs(v0pTrack.eta()) > v0etaCut || std::abs(v0nTrack.eta()) > v0etaCut) { + continue; + } + if (v0pTrack.tpcNClsFound() < minTPCnClsCut) { + continue; + } + if (v0nTrack.tpcNClsFound() < minTPCnClsCut) { + continue; + } + if (std::abs(v0pTrack.tpcNSigmaPi()) > nSigmaTpcCut) { + continue; + } + if (std::abs(v0nTrack.tpcNSigmaPi()) > nSigmaTpcCut) { + continue; + } + if (std::abs(v0pTrack.tpcNSigmaPr()) > nSigmaTpcCut) { + continue; + } + if (std::abs(v0nTrack.tpcNSigmaPr()) > nSigmaTpcCut) { + continue; + } + if (std::abs(v0track.dcapostopv()) < dcapostopvCut || std::abs(v0track.dcanegtopv()) < dcanegtopvCut || v0track.v0radius() < v0radiusCut || v0track.v0cosPA() < v0cospaCut || std::abs(v0track.dcaV0daughters()) > dcav0daughtercut) { + continue; + } + histos.fill(HIST("K0sCentEtaMass"), selColCent(cols), v0track.eta(), v0track.mK0Short()); + histos.fill(HIST("LambdaCentEtaMass"), selColCent(cols), v0track.eta(), v0track.mLambda()); + histos.fill(HIST("AntiLambdaCentEtaMass"), selColCent(cols), v0track.eta(), v0track.mAntiLambda()); + } + } + PROCESS_SWITCH(HeavyionMultiplicity, processStrangeYield, "Strange particle yield", false); + + void processppData(CollisionDataTable::iterator const& cols, FilTrackDataTable const& tracks) + { + if (!isEventSelected(cols)) { + return; + } + + // INEL>0 sample + auto nTrks = 0; + for (const auto& track : tracks) { + if (!isTrackSelected(track)) { + continue; + } + if (track.eta() < kEtaInelgt0) { + nTrks++; + } + } // track loop + + if (nTrks > 0) { + histos.fill(HIST("EventHist"), 10); + histos.fill(HIST("VtxZHist"), cols.posZ()); + histos.fill(HIST("MultPercentileHist"), selColCent(cols)); + histos.fill(HIST("hdatazvtxmultpp"), cols.posZ(), selColCent(cols)); + + for (const auto& track : tracks) { + if (!isTrackSelected(track)) { + continue; + } + histos.fill(HIST("PhiVsEtaHistpp"), track.phi(), track.eta()); + histos.fill(HIST("hdatadndetapp"), cols.posZ(), selColCent(cols), track.eta(), track.phi(), kGlobalplusITS); + if (track.hasTPC()) { + histos.fill(HIST("hdatadndetapp"), cols.posZ(), selColCent(cols), track.eta(), track.phi(), kGlobalonly); + } else { + histos.fill(HIST("hdatadndetapp"), cols.posZ(), selColCent(cols), track.eta(), track.phi(), kITSonly); + } + } // track loop + } // nTrks>0 + } + PROCESS_SWITCH(HeavyionMultiplicity, processppData, "process pp data", false); + + void processppMonteCarlo(CollisionMCTrueTable::iterator const&, CollisionMCRecTable const& RecCols, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + { + for (const auto& RecCol : RecCols) { + if (!isEventSelected(RecCol)) { + continue; + } + auto recTracksPart = RecTracks.sliceBy(perCollision, RecCol.globalIndex()); + std::vector mclabels; + + // INEL>0 sample + auto nTrks = 0; + for (const auto& Rectrack : recTracksPart) { + if (!isTrackSelected(Rectrack)) { + continue; + } + if (Rectrack.eta() < kEtaInelgt0) { + nTrks++; + } + } + + if (nTrks > 0) { + histos.fill(HIST("EventHist"), 10); + histos.fill(HIST("VtxZHist"), RecCol.posZ()); + histos.fill(HIST("MultPercentileMCRecHist"), selColCent(RecCol)); + histos.fill(HIST("hmczvtxmultpp"), RecCol.posZ(), selColCent(RecCol)); + + for (const auto& Rectrack : recTracksPart) { + if (!isTrackSelected(Rectrack)) { + continue; + } + histos.fill(HIST("MCrecPhiVsEtaHistpp"), Rectrack.phi(), Rectrack.eta()); + histos.fill(HIST("hmcrecdndetapp"), RecCol.posZ(), selColCent(RecCol), Rectrack.eta(), Rectrack.phi(), static_cast(kSpAll), kGlobalplusITS); + if (Rectrack.hasTPC()) { + histos.fill(HIST("hmcrecdndetapp"), RecCol.posZ(), selColCent(RecCol), Rectrack.eta(), Rectrack.phi(), static_cast(kSpAll), kGlobalonly); + } else { + histos.fill(HIST("hmcrecdndetapp"), RecCol.posZ(), selColCent(RecCol), Rectrack.eta(), Rectrack.phi(), static_cast(kSpAll), kITSonly); + } + + if (Rectrack.has_mcParticle()) { + int pid = kBkg; + auto mcpart = Rectrack.template mcParticle_as(); + if (mcpart.isPhysicalPrimary()) { + switch (std::abs(mcpart.pdgCode())) { + case PDG_t::kPiPlus: + pid = kSpPion; + break; + case PDG_t::kKPlus: + pid = kSpKaon; + break; + case PDG_t::kProton: + pid = kSpProton; + break; + default: + pid = kSpOther; + break; + } + } else { + pid = kSpNotPrimary; + } + if (mcpart.has_mothers()) { + auto mcpartMother = mcpart.template mothers_as().front(); + if (mcpartMother.pdgCode() == PDG_t::kK0Short || std::abs(mcpartMother.pdgCode()) == PDG_t::kLambda0) { + pid = kSpStrangeDecay; + } + } + if (find(mclabels.begin(), mclabels.end(), Rectrack.mcParticleId()) != mclabels.end()) { + pid = kBkg; + } + mclabels.push_back(Rectrack.mcParticleId()); + histos.fill(HIST("hmcrecdndetapp"), RecCol.posZ(), selColCent(RecCol), Rectrack.eta(), Rectrack.phi(), static_cast(pid), kGlobalplusITS); + } else { + histos.fill(HIST("hmcrecdndetapp"), RecCol.posZ(), selColCent(RecCol), Rectrack.eta(), Rectrack.phi(), static_cast(kBkg), kGlobalplusITS); + } + } // track (mcrec) loop + } // nTrks>0 + + // INEL>0 sample + auto npart = 0; + for (const auto& particle : GenParticles) { + if (!isGenTrackSelected(particle)) { + continue; + } + if (particle.eta() < kEtaInelgt0) { + npart++; + } + } // particle loop + + if (npart > 0) { + for (const auto& particle : GenParticles) { + if (!isGenTrackSelected(particle)) { + continue; + } + histos.fill(HIST("hmcgendndetapp"), RecCol.posZ(), selColCent(RecCol), particle.eta(), particle.phi(), static_cast(kSpAll), kNoGenpTVar); + if (particle.pt() < kMinpTcut) { + histos.fill(HIST("hmcgendndetapp"), RecCol.posZ(), selColCent(RecCol), particle.eta(), particle.phi(), static_cast(kSpAll), kGenpTup, -10.0 * particle.pt() + 2); + histos.fill(HIST("hmcgendndetapp"), RecCol.posZ(), selColCent(RecCol), particle.eta(), particle.phi(), static_cast(kSpAll), kGenpTdown, 5.0 * particle.pt() + 0.5); + } else { + histos.fill(HIST("hmcgendndetapp"), RecCol.posZ(), selColCent(RecCol), particle.eta(), particle.phi(), static_cast(kSpAll), kGenpTup); + histos.fill(HIST("hmcgendndetapp"), RecCol.posZ(), selColCent(RecCol), particle.eta(), particle.phi(), static_cast(kSpAll), kGenpTdown); + } + + int pid = 0; + switch (std::abs(particle.pdgCode())) { + case PDG_t::kPiPlus: + pid = kSpPion; + break; + case PDG_t::kKPlus: + pid = kSpKaon; + break; + case PDG_t::kProton: + pid = kSpProton; + break; + default: + pid = kSpOther; + break; + } + histos.fill(HIST("hmcgendndetapp"), RecCol.posZ(), selColCent(RecCol), particle.eta(), particle.phi(), static_cast(pid), kNoGenpTVar); + } // track (mcgen) loop + } // npart>0 + } // collision loop + } + PROCESS_SWITCH(HeavyionMultiplicity, processppMonteCarlo, "process pp MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/GlobalEventProperties/uccZdc.cxx b/PWGLF/Tasks/GlobalEventProperties/uccZdc.cxx new file mode 100644 index 00000000000..de05a2bf275 --- /dev/null +++ b/PWGLF/Tasks/GlobalEventProperties/uccZdc.cxx @@ -0,0 +1,940 @@ +// 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 uccZdc.cxx +/// +/// \brief task for analysis of UCC with the ZDC +/// \author Omar Vazquez (omar.vazquez.rueda@cern.ch) +/// \since January 29, 2025 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/ZDCConstants.h" +#include "Framework/ASoAHelpers.h" // required for Filter op. +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/Track.h" +#include "TPDGCode.h" + +using namespace std; +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::evsel; +using namespace o2::constants::physics; +using namespace o2::constants::math; + +namespace o2::aod +{ +using ColEvSels = soa::Join; +using BCsRun3 = soa::Join; +using TracksSel = soa::Join; +using SimCollisions = soa::Join; +using SimTracks = soa::Join; +} // namespace o2::aod + +struct UccZdc { + // Event selection + Configurable posZcut{"posZcut", +10.0, "z-vertex position cut"}; + Configurable minT0CcentCut{"minT0CcentCut", 0.0, "Min T0C Cent. cut"}; + Configurable maxT0CcentCut{"maxT0CcentCut", 90.0, "Max T0C Cent. cut"}; + + Configurable minPt{"minPt", 0.1, "minimum pt of the tracks"}; + Configurable maxPt{"maxPt", 50., "maximum pt of the tracks"}; + Configurable minEta{"minEta", -0.8, "minimum eta"}; + Configurable maxEta{"maxEta", +0.8, "maximum eta"}; + + // Configurables, binning + Configurable nBinsAmpFV0{"nBinsAmpFV0", 100, "N bins FV0 amp"}; + Configurable maxAmpFV0{"maxAmpFV0", 2000, "Max FV0 amp"}; + Configurable nBinsAmpFT0{"nBinsAmpFT0", 100, "N bins FT0 amp"}; + Configurable maxAmpFT0{"maxAmpFT0", 2500, "Max FT0 amp"}; + Configurable nBinsNch{"nBinsNch", 2501, "N bins Nch (|eta|<0.8)"}; + Configurable minNch{"minNch", 0, "Min Nch (|eta|<0.8)"}; + Configurable maxNch{"maxNch", 2500, "Max Nch (|eta|<0.8)"}; + Configurable nBinsZDC{"nBinsZDC", 400, "nBinsZDC"}; + Configurable nBinsZEM{"nBinsZEM", 100, "nBinsZEM"}; + Configurable maxZN{"maxZN", 150, "Max ZN signal"}; + Configurable maxZP{"maxZP", 60, "Max ZP signal"}; + Configurable maxZEM{"maxZEM", 2200, "Max ZEM signal"}; + Configurable nBinsTDC{"nBinsTDC", 150, "nbinsTDC"}; + Configurable minTdc{"minTdc", -15.0, "minimum TDC"}; + Configurable maxTdc{"maxTdc", 15.0, "maximum TDC"}; + Configurable minMeanpT{"minMeanpT", 0.5, "minimum [pT]"}; + Configurable maxMeanpT{"maxMeanpT", 1.1, "maximum [pT]"}; + Configurable nBinsMeanpT{"nBinsMeanpT", 160, "# bins [pT]"}; + ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.12}, "pT binning"}; + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., 100.}, "T0C binning"}; + + // Configurables Event Selection + Configurable isNoCollInTimeRangeStrict{"isNoCollInTimeRangeStrict", true, "isNoCollInTimeRangeStrict?"}; + Configurable isNoCollInTimeRangeStandard{"isNoCollInTimeRangeStandard", false, "isNoCollInTimeRangeStandard?"}; + Configurable isNoCollInRofStrict{"isNoCollInRofStrict", true, "isNoCollInRofStrict?"}; + Configurable isNoCollInRofStandard{"isNoCollInRofStandard", false, "isNoCollInRofStandard?"}; + Configurable isNoHighMultCollInPrevRof{"isNoHighMultCollInPrevRof", true, "isNoHighMultCollInPrevRof?"}; + Configurable isNoCollInTimeRangeNarrow{"isNoCollInTimeRangeNarrow", false, "isNoCollInTimeRangeNarrow?"}; + Configurable isOccupancyCut{"isOccupancyCut", true, "Occupancy cut?"}; + Configurable isApplyFT0CbasedOccupancy{"isApplyFT0CbasedOccupancy", false, "T0C Occu cut?"}; + Configurable isTDCcut{"isTDCcut", false, "Use TDC cut?"}; + Configurable isZEMcut{"isZEMcut", true, "Use ZEM cut?"}; + + Configurable znBasedCut{"znBasedCut", 100, "ZN-based cut"}; + Configurable zemCut{"zemCut", 1000., "ZEM cut"}; + Configurable tdcCut{"tdcCut", 1., "TDC cut"}; + Configurable minOccCut{"minOccCut", 0, "min Occu cut"}; + Configurable maxOccCut{"maxOccCut", 500, "max Occu cut"}; + Configurable minITSnCls{"minITSnCls", 5, "min ITSnCls"}; + + enum EvCutLabel { + All = 1, + SelEigth, + NoSameBunchPileup, + IsGoodZvtxFT0vsPV, + NoCollInTimeRangeStrict, + NoCollInTimeRangeStandard, + NoCollInRofStrict, + NoCollInRofStandard, + NoHighMultCollInPrevRof, + NoCollInTimeRangeNarrow, + OccuCut, + Centrality, + VtxZ, + Zdc, + TZero, + Tdc, + Zem + }; + + static constexpr float zEro{0.}; + static constexpr float oneHalf{0.5}; + + // Filters + // Filter trackFilter = ((aod::track::eta > minEta) && (aod::track::eta < maxEta) && (aod::track::pt > minPt) && (aod::track::pt < maxPt) && requireGlobalTrackInFilter()); + // Remove the GlobalTrack filter to count also ITS tracks + Filter trackFilter = ((aod::track::eta > minEta) && (aod::track::eta < maxEta) && (aod::track::pt > minPt) && (aod::track::pt < maxPt)); + + // Apply Filters + // using TheFilteredCollisions = soa::Filtered; + // using TheFilteredCollision = TheFilteredCollisions::iterator; + using TheFilteredTracks = soa::Filtered; + // using TheFilteredTrack = TheFilteredTracks::iterator; + + // using TheFilteredSimCollisions = soa::Filtered; + using TheFilteredSimTracks = soa::Filtered; + + // Histograms: Data + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + Service ccdb; + Configurable paTH{"paTH", "Users/o/omvazque/TrackingEfficiency", "base path to the ccdb object"}; + Configurable uRl{"uRl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable noLaterThan{"noLaterThan", 1740173636328, "latest acceptable timestamp of creation for the object"}; + + // the efficiency has been previously stored in the CCDB as TH1F histogram + TH1F* efficiency = nullptr; + + void init(InitContext const&) + { + // define axes you want to use + const AxisSpec axisZpos{48, -12., 12., "Vtx_{z} (cm)"}; + const AxisSpec axisEvent{18, 0.5, 18.5, ""}; + const AxisSpec axisEta{30, -1.05, +1.05, "#eta"}; + const AxisSpec axisPt{binsPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisDeltaPt{100, -1.0, +1.0, "#Delta(p_{T})"}; + const AxisSpec axisCent{binsCent, "T0C centrality"}; + const AxisSpec axisAmpCh{250, 0., 2500., "Amplitude of non-zero channels"}; + const AxisSpec axisEneCh{300, 0., 300., "Energy of non-zero channels"}; + + registry.add("zPos", ";;Entries;", kTH1F, {axisZpos}); + registry.add("hEventCounter", ";;Events", kTH1F, {axisEvent}); + auto hstat = registry.get(HIST("hEventCounter")); + auto* x = hstat->GetXaxis(); + x->SetBinLabel(1, "All"); + x->SetBinLabel(2, "SelEigth"); + x->SetBinLabel(3, "NoSameBunchPileup"); + x->SetBinLabel(4, "GoodZvtxFT0vsPV"); + x->SetBinLabel(5, "NoCollInTimeRangeStrict"); + x->SetBinLabel(6, "NoCollInTimeRangeStandard"); + x->SetBinLabel(7, "NoCollInRofStrict"); + x->SetBinLabel(8, "NoCollInRofStandard"); + x->SetBinLabel(9, "NoHighMultCollInPrevRof"); + x->SetBinLabel(10, "NoCollInTimeRangeNarrow"); + x->SetBinLabel(11, "Occupancy Cut"); + x->SetBinLabel(12, "Cent. Sel."); + x->SetBinLabel(13, "VtxZ cut"); + x->SetBinLabel(14, "has ZDC?"); + x->SetBinLabel(15, "has T0?"); + x->SetBinLabel(16, "Within TDC cut?"); + x->SetBinLabel(17, "Within ZEM cut?"); + + // Histograms: paritcle-level info + if (doprocessZdcCollAss) { + registry.add("T0Ccent", ";;Entries", kTH1F, {axisCent}); + registry.add("ZposVsEta", "", kTProfile, {axisZpos}); + registry.add("EtaVsPhi", ";#eta;#varphi", kTH2F, {{{axisEta}, {100, -0.1 * PI, +2.1 * PI}}}); + registry.add("sigma1Pt", ";;#sigma(p_{T})/p_{T};", kTProfile, {axisPt}); + registry.add("dcaXYvspT", ";DCA_{xy} (cm);;", kTH2F, {{{50, -1., 1.}, {axisPt}}}); + + registry.add("NchRaw", ";#it{N}_{ch} (|#eta| < 0.8);", kTH1F, {{nBinsNch, minNch, maxNch}}); + registry.add("Nch", ";#it{N}_{ch} (|#eta| < 0.8, Corrected);", kTH1F, {{nBinsNch, minNch, maxNch}}); + registry.add("NchVsPt", ";#it{N}_{ch} (|#eta| < 0.8, Corrected);;", kTH2F, {{{nBinsNch, minNch, maxNch}, {axisPt}}}); + registry.add("NchVsOneParCorr", ";#it{N}_{ch} (|#eta| < 0.8, Corrected);#LT[#it{p}_{T}^{(1)}]#GT (GeV/#it{c})", kTProfile, {{nBinsNch, minNch, maxNch}}); + registry.add("NchVsOneParCorrVsZN", ";#it{N}_{ch} (|#eta| < 0.8, Corrected); ZNA+ZNC; #LT[#it{p}_{T}^{(1)}]#GT", kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, -0.5, maxZN}}}); + registry.add("NchVsTwoParCorrVsZN", ";#it{N}_{ch} (|#eta| < 0.8, Corrected);ZNA+ZNC;#LT[#it{p}_{T}^{(2)}]#GT", kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, -0.5, maxZN}}}); + registry.add("NchVsThreeParCorrVsZN", ";#it{N}_{ch} (|#eta| < 0.8, Corrected);ZNA+ZNC;#LT[#it{p}_{T}^{(3)}]#GT", kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, -0.5, maxZN}}}); + registry.add("NchVsFourParCorrVsZN", ";#it{N}_{ch} (|#eta| < 0.8, Corrected);ZNA+ZNC;#LT[#it{p}_{T}^{(4)}]#GT", kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, -0.5, maxZN}}}); + } + + // MC Histograms + if (doprocessMCclosure) { + registry.add("RandomNumber", "", kTH1F, {{100, 0., 1.}}); + registry.add("EvtsDivided", ";Event type;Entries;", kTH1F, {{2, -0.5, 1.5}}); + auto hEvtsDiv = registry.get(HIST("EvtsDivided")); + auto* xEvtsDiv = hEvtsDiv->GetXaxis(); + xEvtsDiv->SetBinLabel(1, "MC closure"); + xEvtsDiv->SetBinLabel(2, "Corrections"); + + registry.add("NchGen", "MC closure;#it{N}_{ch} (|#eta| < 0.8);Entries;", kTH1F, {{nBinsNch, minNch, maxNch}}); + registry.add("NchvsOneParCorrGen", "MC closure;#it{N}_{ch} (|#eta| < 0.8);#LT[#it{p}_{T}^{(1)}]#GT (GeV/#it{c})", kTProfile, {{nBinsNch, minNch, maxNch}}); + registry.add("NchvsTwoParCorrGen", "MC closure;#it{N}_{ch} (|#eta| < 0.8);#LT[#it{p}_{T}^{(2)}]#GT", kTProfile, {{nBinsNch, minNch, maxNch}}); + registry.add("NchvsThreeParCorrGen", "MC closure;#it{N}_{ch} (|#eta| < 0.8);#LT[#it{p}_{T}^{(3)}]#GT", kTProfile, {{nBinsNch, minNch, maxNch}}); + registry.add("NchvsFourParCorrGen", "MC closure;#it{N}_{ch} (|#eta| < 0.8);#LT[#it{p}_{T}^{(4)}]#GT", kTProfile, {{nBinsNch, minNch, maxNch}}); + + registry.add("T0Ccent", "Filled at MC closure + Corrections;;Entries", kTH1F, {axisCent}); + registry.add("NchRaw", "MC closure;#it{N}_{ch} (|#eta| < 0.8);Entries;", kTH1F, {{nBinsNch, minNch, maxNch}}); + registry.add("Nch", "MC closure;#it{N}_{ch} (|#eta| < 0.8, Corrected);Entries;", kTH1F, {{nBinsNch, minNch, maxNch}}); + registry.add("NchVsOneParCorr", "MC closure;#it{N}_{ch} (|#eta| < 0.8, Corrected);#LT[#it{p}_{T}^{(1)}]#GT (GeV/#it{c})", kTProfile, {{nBinsNch, minNch, maxNch}}); + registry.add("NchVsTwoParCorr", "MC closure;#it{N}_{ch} (|#eta| < 0.8, Corrected);#LT[#it{p}_{T}^{(2)}]#GT", kTProfile, {{nBinsNch, minNch, maxNch}}); + registry.add("NchVsThreeParCorr", "MC closure;#it{N}_{ch} (|#eta| < 0.8, Corrected);#LT[#it{p}_{T}^{(3)}]#GT", kTProfile, {{nBinsNch, minNch, maxNch}}); + registry.add("NchVsFourParCorr", "MC closure;#it{N}_{ch} (|#eta| < 0.8, Corrected);#LT[#it{p}_{T}^{(4)}]#GT", kTProfile, {{nBinsNch, minNch, maxNch}}); + + // Corrections + registry.add("nRecColvsCent", "", kTH2F, {{6, -0.5, 5.5}, {{axisCent}}}); + registry.add("Pt_all_ch", "Corrections;;;", kTH2F, {{axisCent}, {axisPt}}); + registry.add("Pt_ch", "Corrections;;;", kTH2F, {{axisCent}, {axisPt}}); + registry.add("Pt_pi", "Corrections;;;", kTH2F, {{axisCent}, {axisPt}}); + registry.add("Pt_ka", "Corrections;;;", kTH2F, {{axisCent}, {axisPt}}); + registry.add("Pt_pr", "Corrections;;;", kTH2F, {{axisCent}, {axisPt}}); + registry.add("Pt_sigpos", "Corrections;;;", kTH2F, {{axisCent}, {axisPt}}); + registry.add("Pt_signeg", "Corrections;;;", kTH2F, {{axisCent}, {axisPt}}); + registry.add("Pt_re", "Corrections;;;", kTH2F, {{axisCent}, {axisPt}}); + registry.add("EtaVsPhi", "Corrections;;#varphi;", kTH2F, {{{axisEta}, {100, -0.1 * PI, +2.1 * PI}}}); + registry.add("hEventCounterMC", "Event counter", kTH1F, {axisEvent}); + registry.add("zPosMC", "Filled at MC closure + Corrections;;Entries;", kTH1F, {axisZpos}); + registry.add("PtMC_ch", "Corrections;;;", kTH2F, {{axisCent}, {axisPt}}); + registry.add("PtMC_pi", "Corrections;;;", kTH2F, {{axisCent}, {axisPt}}); + registry.add("PtMC_ka", "Corrections;;;", kTH2F, {{axisCent}, {axisPt}}); + registry.add("PtMC_pr", "Corrections;;;", kTH2F, {{axisCent}, {axisPt}}); + registry.add("PtMC_sigpos", "Corrections;;;", kTH2F, {{axisCent}, {axisPt}}); + registry.add("PtMC_signeg", "Corrections;;;", kTH2F, {{axisCent}, {axisPt}}); + registry.add("PtMC_re", "Corrections;;;", kTH2F, {{axisCent}, {axisPt}}); + + auto hECMC = registry.get(HIST("hEventCounterMC")); + auto* x = hECMC->GetXaxis(); + x->SetBinLabel(1, "All"); + x->SetBinLabel(13, "VtxZ cut"); + } + + if (doprocessQA) { + registry.add("T0Ccent", ";;Entries", kTH1F, {axisCent}); + + registry.add("ZNVsFT0A", ";T0A (#times 1/100);ZNA+ZNC;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZN}}}); + registry.add("ZNVsFT0C", ";T0C (#times 1/100);ZNA+ZNC;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZN}}}); + registry.add("ZNVsFT0M", ";T0A+T0C (#times 1/100);ZNA+ZNC;", kTH2F, {{{nBinsAmpFT0, 0., 3000.}, {nBinsZDC, -0.5, maxZN}}}); + + registry.add("ZN", ";ZNA+ZNC;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZN}}); + registry.add("ZNA", ";ZNA;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZN}}); + registry.add("ZPA", ";ZPA;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZP}}); + registry.add("ZNC", ";ZNC;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZN}}); + registry.add("ZPC", ";ZPC;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZP}}); + registry.add("ZNAVsZNC", ";ZNC;ZNA", kTH2F, {{{30, -0.5, maxZN}, {30, -0.5, maxZN}}}); + registry.add("ZPAVsZPC", ";ZPC;ZPA;", kTH2F, {{{100, -0.5, maxZP}, {100, -0.5, maxZP}}}); + registry.add("ZNAVsZPA", ";ZPA;ZNA;", kTH2F, {{{20, -0.5, maxZP}, {30, -0.5, maxZN}}}); + registry.add("ZNCVsZPC", ";ZPC;ZNC;", kTH2F, {{{20, -0.5, maxZP}, {30, -0.5, maxZN}}}); + registry.add("ZNCcvsZNCsum", ";ZNC common;ZNC sum towers;", kTH2F, {{{30, -0.5, maxZN}, {30, -0.5, maxZN}}}); + registry.add("ZNAcvsZNAsum", ";ZNA common;ZNA sum towers;", kTH2F, {{{30, -0.5, maxZN}, {30, -0.5, maxZN}}}); + registry.add("ZPCcvsZPCsum", ";ZPC common;ZPC sum towers;", kTH2F, {{{30, -0.5, maxZP}, {30, -0.5, maxZP}}}); + registry.add("ZPAcvsZPAsum", ";ZPA common;ZPA sum towers;", kTH2F, {{{30, -0.5, maxZP}, {30, -0.5, maxZP}}}); + registry.add("ZNVsZEM", ";ZEM;ZNA+ZNC;", kTH2F, {{{60, -0.5, maxZEM}, {60, -0.5, maxZN}}}); + registry.add("ZNCVstdc", ";t_{ZNC};ZNC;", kTH2F, {{{30, -15., 15.}, {nBinsZDC, -0.5, maxZN}}}); + registry.add("ZNAVstdc", ";t_{ZNA};ZNA;", kTH2F, {{{30, -15., 15.}, {30, -0.5, maxZN}}}); + registry.add("ZPCVstdc", ";t_{ZPC};ZPC;", kTH2F, {{{30, -15., 15}, {20, -0.5, maxZP}}}); + registry.add("ZPAVstdc", ";t_{ZPA};ZPA;", kTH2F, {{{30, -15., 15.}, {20, -0.5, maxZP}}}); + registry.add("ZEM1Vstdc", ";t_{ZEM1};ZEM1;", kTH2F, {{{30, -15., 15.}, {30, -0.5, 2000.5}}}); + registry.add("ZEM2Vstdc", ";t_{ZEM2};ZEM2;", kTH2F, {{{30, -15., 15.}, {30, -0.5, 2000.5}}}); + registry.add("debunch", ";t_{ZDC}-t_{ZDA};t_{ZDC}+t_{ZDA}", kTH2F, {{{nBinsTDC, minTdc, maxTdc}, {nBinsTDC, minTdc, maxTdc}}}); + + registry.add("NchVsFT0C", ";T0C (#times 1/100, -3.3 < #eta < -2.1);#it{N}_{ch} (|#eta|<0.8);", kTH2F, {{{nBinsAmpFT0, 0., 950.}, {nBinsNch, minNch, maxNch}}}); + registry.add("NchVsFT0M", ";T0A+T0C (#times 1/100, -3.3 < #eta < -2.1 and 3.5 < #eta < 4.9);#it{N}_{ch} (|#eta|<0.8);", kTH2F, {{{nBinsAmpFT0, 0., 3000.}, {nBinsNch, minNch, maxNch}}}); + registry.add("NchVsFT0A", ";T0A (#times 1/100, 3.5 < #eta < 4.9);#it{N}_{ch} (|#eta|<0.8);", kTProfile, {{nBinsAmpFT0, 0., maxAmpFT0}}); + registry.add("NchVsFV0A", ";V0A (#times 1/100, 2.2 < #eta < 5);#it{N}_{ch} (|#eta|<0.8);", kTProfile, {{nBinsAmpFV0, 0., maxAmpFV0}}); + + registry.add("NchVsEt", ";#it{E}_{T} (|#eta|<0.8);#LTITS+TPC tracks#GT (|#eta|<0.8);", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsNch, minNch, maxNch}}}); + registry.add("NchVsMeanPt", ";#it{N}_{ch} (|#eta|<0.8);#LT[#it{p}_{T}]#GT (|#eta|<0.8);", kTProfile, {{nBinsNch, minNch, maxNch}}); + registry.add("NchVsNPV", ";#it{N}_{PV} (|#eta|<1);#LT ITS+TPC tracks #GT (|#eta|<0.8);", kTProfile, {{6000, -0.5, 5999.5}}); + registry.add("NchVsITStracks", ";ITS tracks nCls >= 5;#LTITS+TPC tracks#GT (|#eta|<0.8);", kTProfile, {{6000, -0.5, 5999.5}}); + registry.add("ZNCVsNch", ";#it{N}_{ch} (|#eta|<0.8);ZNC;", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZN}}}); + registry.add("ZNAVsNch", ";#it{N}_{ch} (|#eta|<0.8);ZNA;", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZN}}}); + registry.add("ZNVsNch", ";#it{N}_{ch} (|#eta|<0.8);ZNA+ZNC;", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZN}}}); + registry.add("ZNDifVsNch", ";#it{N}_{ch} (|#eta|<0.8);ZNA-ZNC;", kTH2F, {{{nBinsNch, minNch, maxNch}, {100, -50., 50.}}}); + } + + ccdb->setURL(uRl.value); + // Enabling object caching, otherwise each call goes to the CCDB server + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + // Not later than now, will be replaced by the value of the train creation + // This avoids that users can replace objects **while** a train is running + ccdb->setCreatedNotAfter(noLaterThan.value); + LOGF(info, "Getting object %s", paTH.value.data()); + efficiency = ccdb->getForTimeStamp(paTH.value, noLaterThan); + if (!efficiency) { + LOGF(fatal, "Efficiency object not found!"); + } + } + + template + bool isEventSelected(CheckCol const& col) + { + registry.fill(HIST("hEventCounter"), EvCutLabel::All); + if (!col.sel8()) { + return false; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::SelEigth); + + if (!col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::NoSameBunchPileup); + + if (!col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::IsGoodZvtxFT0vsPV); + + if (isNoCollInTimeRangeStrict) { + if (!col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::NoCollInTimeRangeStrict); + } + + if (isNoCollInTimeRangeStandard) { + if (!col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::NoCollInTimeRangeStandard); + } + + if (isNoCollInRofStrict) { + if (!col.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::NoCollInRofStrict); + } + + if (isNoCollInRofStandard) { + if (!col.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::NoCollInRofStandard); + } + + if (isNoHighMultCollInPrevRof) { + if (!col.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + return false; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::NoHighMultCollInPrevRof); + } + + // To be used in combination with FT0C-based occupancy + if (isNoCollInTimeRangeNarrow) { + if (!col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + return false; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::NoCollInTimeRangeNarrow); + } + + if (isOccupancyCut) { + auto occuValue{isApplyFT0CbasedOccupancy ? col.ft0cOccupancyInTimeRange() : col.trackOccupancyInTimeRange()}; + if (occuValue < minOccCut || occuValue > maxOccCut) { + return false; + } + } + registry.fill(HIST("hEventCounter"), EvCutLabel::OccuCut); + + if (col.centFT0C() < minT0CcentCut || col.centFT0C() > maxT0CcentCut) { + return false; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::Centrality); + + // Z-vertex position cut + if (std::fabs(col.posZ()) > posZcut) { + return false; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::VtxZ); + + return true; + } + + void processQA(o2::aod::ColEvSels::iterator const& collision, o2::aod::BCsRun3 const& /**/, aod::Zdcs const& /**/, aod::FV0As const& /**/, aod::FT0s const& /**/, TheFilteredTracks const& tracks) + { + + // LOG(info) << " Collisions size: " << collisions.size() << " Table's size: " << collisions.tableSize() << "\n"; + const auto& foundBC = collision.foundBC_as(); + // LOG(info) << "Run number: " << foundBC.runNumber() << "\n"; + if (!isEventSelected(collision)) { + return; + } + + // has ZDC? + if (!foundBC.has_zdc()) { + return; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::Zdc); + auto zdc = foundBC.zdc(); + + float aT0A = 0., aT0C = 0., aV0A = 0.; + if (foundBC.has_ft0()) { + for (const auto& amplitude : foundBC.ft0().amplitudeA()) { + aT0A += amplitude; + } + for (const auto& amplitude : foundBC.ft0().amplitudeC()) { + aT0C += amplitude; + } + } else { + return; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::TZero); + + if (foundBC.has_fv0a()) { + for (const auto& amplitude : foundBC.fv0a().amplitude()) { + aV0A += amplitude; + } + } else { + aV0A = -999.; + } + + float tZNA{zdc.timeZNA()}; + float tZNC{zdc.timeZNC()}; + float tZPA{zdc.timeZPA()}; + float tZPC{zdc.timeZPC()}; + float tZDCdif{tZNC + tZPC - tZNA - tZPA}; + float tZDCsum{tZNC + tZPC + tZNA + tZPA}; + + // TDC cut + if (isTDCcut) { + if (std::sqrt(std::pow(tZDCdif, 2.) + std::pow(tZDCsum, 2.)) > tdcCut) { + return; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::Tdc); + } + + float aZEM1{zdc.amplitudeZEM1()}; + float aZEM2{zdc.amplitudeZEM2()}; + float sumZEMs{aZEM1 + aZEM2}; + + // ZEM cut + if (isZEMcut) { + if (sumZEMs < zemCut) { + return; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::Zem); + } + + float znA{zdc.amplitudeZNA()}; + float znC{zdc.amplitudeZNC()}; + float zpA{zdc.amplitudeZPA()}; + float zpC{zdc.amplitudeZPC()}; + znA /= 2.81; + znC /= 2.81; + zpA /= 2.81; + zpC /= 2.81; + + float tZEM1{zdc.timeZEM1()}; + float tZEM2{zdc.timeZEM2()}; + float sumZNs{znA + znC}; + + float sumZNC = (zdc.energySectorZNC())[0] + (zdc.energySectorZNC())[1] + (zdc.energySectorZNC())[2] + (zdc.energySectorZNC())[3]; + float sumZNA = (zdc.energySectorZNA())[0] + (zdc.energySectorZNA())[1] + (zdc.energySectorZNA())[2] + (zdc.energySectorZNA())[3]; + float sumZPC = (zdc.energySectorZPC())[0] + (zdc.energySectorZPC())[1] + (zdc.energySectorZPC())[2] + (zdc.energySectorZPC())[3]; + float sumZPA = (zdc.energySectorZPA())[0] + (zdc.energySectorZPA())[1] + (zdc.energySectorZPA())[2] + (zdc.energySectorZPA())[3]; + + int itsTracks = 0, glbTracks = 0; + float et = 0., meanpt = 0.; + for (const auto& track : tracks) { + if (track.hasITS() && track.itsNCls() >= minITSnCls) { + itsTracks++; + } + // Track Selection + if (track.isGlobalTrack()) { + glbTracks++; + meanpt += track.pt(); + et += std::sqrt(std::pow(track.pt(), 2.) + std::pow(o2::constants::physics::MassPionCharged, 2.)); + } + } + + registry.fill(HIST("zPos"), collision.posZ()); + registry.fill(HIST("T0Ccent"), collision.centFT0C()); + + registry.fill(HIST("ZNCcvsZNCsum"), sumZNC / 2.81, zdc.energyCommonZNC() / 2.81); + registry.fill(HIST("ZNAcvsZNAsum"), sumZNA / 2.81, zdc.energyCommonZNA() / 2.81); + registry.fill(HIST("ZPCcvsZPCsum"), sumZPC / 2.81, zdc.energyCommonZPC() / 2.81); + registry.fill(HIST("ZPAcvsZPAsum"), sumZPA / 2.81, zdc.energyCommonZPA() / 2.81); + + registry.fill(HIST("ZNA"), znA); + registry.fill(HIST("ZNC"), znC); + registry.fill(HIST("ZPA"), zpA); + registry.fill(HIST("ZPC"), zpC); + registry.fill(HIST("ZN"), znA + znC); + registry.fill(HIST("ZNAVsZNC"), znC, znA); + registry.fill(HIST("ZNAVsZPA"), zpA, znA); + registry.fill(HIST("ZNCVsZPC"), zpC, znC); + registry.fill(HIST("ZPAVsZPC"), zpC, zpA); + registry.fill(HIST("ZNVsZEM"), sumZEMs, sumZNs); + registry.fill(HIST("ZNCVstdc"), tZNC, znC); + registry.fill(HIST("ZNAVstdc"), tZNA, znA); + registry.fill(HIST("ZPCVstdc"), tZPC, zpC); + registry.fill(HIST("ZPAVstdc"), tZPA, zpA); + registry.fill(HIST("ZEM1Vstdc"), tZEM1, aZEM1); + registry.fill(HIST("ZEM2Vstdc"), tZEM2, aZEM2); + registry.fill(HIST("debunch"), tZDCdif, tZDCsum); + + registry.fill(HIST("ZNVsFT0A"), aT0A / 100., sumZNs); + registry.fill(HIST("ZNVsFT0C"), aT0C / 100., sumZNs); + registry.fill(HIST("ZNVsFT0M"), (aT0A + aT0C) / 100., sumZNs); + + if (sumZNs > znBasedCut) { + return; + } + + registry.fill(HIST("NchVsFV0A"), aV0A / 100., glbTracks); + registry.fill(HIST("NchVsFT0A"), aT0A / 100., glbTracks); + registry.fill(HIST("NchVsFT0C"), aT0C / 100., glbTracks); + registry.fill(HIST("NchVsFT0M"), (aT0A + aT0C) / 100., glbTracks); + + registry.fill(HIST("NchVsEt"), et, glbTracks); + registry.fill(HIST("NchVsMeanPt"), glbTracks, meanpt / glbTracks); + registry.fill(HIST("NchVsNPV"), collision.multNTracksPVeta1(), glbTracks); + registry.fill(HIST("NchVsITStracks"), itsTracks, glbTracks); + registry.fill(HIST("ZNAVsNch"), glbTracks, znA); + registry.fill(HIST("ZNCVsNch"), glbTracks, znC); + registry.fill(HIST("ZNVsNch"), glbTracks, sumZNs); + registry.fill(HIST("ZNDifVsNch"), glbTracks, znA - znC); + } + PROCESS_SWITCH(UccZdc, processQA, "Process QA", true); + + void processZdcCollAss(o2::aod::ColEvSels::iterator const& collision, o2::aod::BCsRun3 const& /*bcs*/, aod::Zdcs const& /*zdcs*/, aod::FV0As const& /*fv0as*/, aod::FT0s const& /*ft0s*/, TheFilteredTracks const& tracks) + { + + if (!isEventSelected(collision)) { + return; + } + + const auto& foundBC = collision.foundBC_as(); + // has ZDC? + if (!foundBC.has_zdc()) { + return; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::Zdc); + + if (!foundBC.has_ft0()) { + return; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::TZero); + + float znA{foundBC.zdc().amplitudeZNA()}; + float znC{foundBC.zdc().amplitudeZNC()}; + float aZEM1{foundBC.zdc().amplitudeZEM1()}; + float aZEM2{foundBC.zdc().amplitudeZEM2()}; + float tZNA{foundBC.zdc().timeZNA()}; + float tZNC{foundBC.zdc().timeZNC()}; + float tZPA{foundBC.zdc().timeZPA()}; + float tZPC{foundBC.zdc().timeZPC()}; + float tZDCdif{tZNC + tZPC - tZNA - tZPA}; + float tZDCsum{tZNC + tZPC + tZNA + tZPA}; + znA /= 2.81; + znC /= 2.81; + float sumZNs{znA + znC}; + float sumZEMs{aZEM1 + aZEM2}; + + // TDC cut + if (isTDCcut) { + if (std::sqrt(std::pow(tZDCdif, 2.) + std::pow(tZDCsum, 2.)) > tdcCut) { + return; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::Tdc); + } + + // ZEM cut + if (isZEMcut) { + if (sumZEMs < zemCut) { + return; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::Zem); + } + + registry.fill(HIST("zPos"), collision.posZ()); + registry.fill(HIST("T0Ccent"), collision.centFT0C()); + + std::vector pTs; + std::vector wIs; + // Calculates the event weight, W_k + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + + registry.fill(HIST("ZposVsEta"), collision.posZ(), track.eta()); + registry.fill(HIST("EtaVsPhi"), track.eta(), track.phi()); + registry.fill(HIST("sigma1Pt"), track.pt(), track.sigma1Pt()); + registry.fill(HIST("dcaXYvspT"), track.dcaXY(), track.pt()); + + float pt{track.pt()}; + double weight{efficiency->GetBinContent(efficiency->FindBin(pt))}; + if (weight > 0.) { + pTs.emplace_back(pt); + wIs.emplace_back(weight); + } + } + + double p1, p2, p3, p4, w1, w2, w3, w4; + p1 = p2 = p3 = p4 = w1 = w2 = w3 = w4 = 0.0; + getPTpowers(pTs, wIs, p1, w1, p2, w2, p3, w3, p4, w4); + const double nch{static_cast(pTs.size())}; + if (!(nch != 0.)) { + return; + } + + // To calculate event-averaged + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + registry.fill(HIST("NchVsPt"), w1, track.pt()); + } + + // EbE one-particle pT correlation + double oneParCorr{p1 / w1}; + + // EbE two-particle pT correlation + double denTwoParCorr{std::pow(w1, 2.) - w2}; + double numTwoParCorr{std::pow(p1, 2.) - p2}; + double twoParCorr{numTwoParCorr / denTwoParCorr}; + + // EbE three-particle pT correlation + double denThreeParCorr{std::pow(w1, 3.) - 3. * w2 * w1 + 2. * w3}; + double numThreeParCorr{std::pow(p1, 3.) - 3. * p2 * p1 + 2. * p3}; + double threeParCorr{numThreeParCorr / denThreeParCorr}; + + // EbE four-particle pT correlation + double denFourParCorr{std::pow(w1, 4.) - 6. * w2 * std::pow(w1, 2.) + 3. * std::pow(w2, 2.) + 8 * w3 * w1 - 6. * w4}; + double numFourParCorr{std::pow(p1, 4.) - 6. * p2 * std::pow(p1, 2.) + 3. * std::pow(p2, 2.) + 8 * p3 * p1 - 6. * p4}; + double fourParCorr{numFourParCorr / denFourParCorr}; + + if (sumZNs > znBasedCut) { + return; + } + + registry.fill(HIST("Nch"), w1); + registry.fill(HIST("NchRaw"), nch); + registry.fill(HIST("NchVsOneParCorr"), w1, oneParCorr, w1); + registry.fill(HIST("NchVsOneParCorrVsZN"), w1, sumZNs, oneParCorr, w1); + registry.fill(HIST("NchVsTwoParCorrVsZN"), w1, sumZNs, twoParCorr, denTwoParCorr); + registry.fill(HIST("NchVsThreeParCorrVsZN"), w1, sumZNs, threeParCorr, denThreeParCorr); + registry.fill(HIST("NchVsFourParCorrVsZN"), w1, sumZNs, fourParCorr, denFourParCorr); + } + PROCESS_SWITCH(UccZdc, processZdcCollAss, "Process ZDC W/Coll Ass.", true); + + // Preslice perMCCollision = aod::mcparticle::mcCollisionId; + Preslice perCollision = aod::track::collisionId; + TRandom* randPointer = new TRandom(); + void processMCclosure(aod::McCollisions::iterator const& mccollision, soa::SmallGroups const& collisions, aod::McParticles const& mcParticles, TheFilteredSimTracks const& simTracks) + { + float rndNum = randPointer->Uniform(0.0, 1.0); + registry.fill(HIST("RandomNumber"), rndNum); + + // Half of the statistics for MC closure + if (rndNum >= zEro && rndNum < oneHalf) { + registry.fill(HIST("EvtsDivided"), 0); + //----- MC reconstructed -----// + for (const auto& collision : collisions) { + // Event selection + if (!isEventSelected(collision)) { + continue; + } + // MC collision? + if (!collision.has_mcCollision()) { + continue; + } + + registry.fill(HIST("T0Ccent"), collision.centFT0C()); + registry.fill(HIST("zPos"), collision.posZ()); + + const auto& groupedTracks{simTracks.sliceBy(perCollision, collision.globalIndex())}; + + std::vector pTs; + std::vector wIs; + // Calculates the event weight, W_k + for (const auto& track : groupedTracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + + float pt{track.pt()}; + double weight{efficiency->GetBinContent(efficiency->FindBin(pt))}; + if (weight > 0.) { + pTs.emplace_back(pt); + wIs.emplace_back(weight); + } + } + + const double nch{static_cast(pTs.size())}; + if (!(nch != 0.)) { + return; + } + + double p1, p2, p3, p4, w1, w2, w3, w4; + p1 = p2 = p3 = p4 = w1 = w2 = w3 = w4 = 0.0; + getPTpowers(pTs, wIs, p1, w1, p2, w2, p3, w3, p4, w4); + + const double denTwoParCorr{std::pow(w1, 2.) - w2}; + const double numTwoParCorr{std::pow(p1, 2.) - p2}; + const double denThreeParCorr{std::pow(w1, 3.) - 3. * w2 * w1 + 2. * w3}; + const double numThreeParCorr{std::pow(p1, 3.) - 3. * p2 * p1 + 2. * p3}; + const double denFourParCorr{std::pow(w1, 4.) - 6. * w2 * std::pow(w1, 2.) + 3. * std::pow(w2, 2.) + 8 * w3 * w1 - 6. * w4}; + const double numFourParCorr{std::pow(p1, 4.) - 6. * p2 * std::pow(p1, 2.) + 3. * std::pow(p2, 2.) + 8 * p3 * p1 - 6. * p4}; + + const double oneParCorr{p1 / w1}; + const double twoParCorr{numTwoParCorr / denTwoParCorr}; + const double threeParCorr{numThreeParCorr / denThreeParCorr}; + const double fourParCorr{numFourParCorr / denFourParCorr}; + + registry.fill(HIST("Nch"), w1); + registry.fill(HIST("NchRaw"), nch); + registry.fill(HIST("NchVsOneParCorr"), w1, oneParCorr, w1); + registry.fill(HIST("NchVsTwoParCorr"), w1, twoParCorr, denTwoParCorr); + registry.fill(HIST("NchVsThreeParCorr"), w1, threeParCorr, denThreeParCorr); + registry.fill(HIST("NchVsFourParCorr"), w1, fourParCorr, denFourParCorr); + + //--------------------------- Generated MC --------------------------- + registry.fill(HIST("hEventCounterMC"), EvCutLabel::All); + if (std::fabs(mccollision.posZ()) > posZcut) { + continue; + } + registry.fill(HIST("zPosMC"), mccollision.posZ()); + registry.fill(HIST("hEventCounterMC"), EvCutLabel::VtxZ); + + std::vector pTsMC; + std::vector wIsMC; + // Calculates the event weight, W_k + for (const auto& particle : mcParticles) { + if (particle.eta() < minEta || particle.eta() > maxEta) { + continue; + } + if (particle.pt() < minPt || particle.pt() > maxPt) { + continue; + } + if (!particle.isPhysicalPrimary()) { + continue; + } + + float pt{particle.pt()}; + pTsMC.emplace_back(pt); + wIsMC.emplace_back(1.); + } + + const double nchMC{static_cast(pTsMC.size())}; + double p1MC, p2MC, p3MC, p4MC, w1MC, w2MC, w3MC, w4MC; + p1MC = p2MC = p3MC = p4MC = w1MC = w2MC = w3MC = w4MC = 0.0; + getPTpowers(pTsMC, wIsMC, p1MC, w1MC, p2MC, w2MC, p3MC, w3MC, p4MC, w4MC); + + const double denTwoParCorrMC{std::pow(w1MC, 2.) - w2MC}; + const double numTwoParCorrMC{std::pow(p1MC, 2.) - p2MC}; + const double denThreeParCorrMC{std::pow(w1MC, 3.) - 3. * w2MC * w1MC + 2. * w3MC}; + const double numThreeParCorrMC{std::pow(p1MC, 3.) - 3. * p2MC * p1MC + 2. * p3MC}; + const double denFourParCorrMC{std::pow(w1MC, 4.) - 6. * w2MC * std::pow(w1MC, 2.) + 3. * std::pow(w2MC, 2.) + 8 * w3MC * w1MC - 6. * w4MC}; + const double numFourParCorrMC{std::pow(p1MC, 4.) - 6. * p2MC * std::pow(p1MC, 2.) + 3. * std::pow(p2MC, 2.) + 8 * p3MC * p1MC - 6. * p4MC}; + + const double oneParCorrMC{p1MC / w1MC}; + const double twoParCorrMC{numTwoParCorrMC / denTwoParCorrMC}; + const double threeParCorrMC{numThreeParCorrMC / denThreeParCorrMC}; + const double fourParCorrMC{numFourParCorrMC / denFourParCorrMC}; + + registry.fill(HIST("NchGen"), nchMC); + registry.fill(HIST("NchvsOneParCorrGen"), nchMC, oneParCorrMC, w1MC); + registry.fill(HIST("NchvsTwoParCorrGen"), nchMC, twoParCorrMC, denTwoParCorrMC); + registry.fill(HIST("NchvsThreeParCorrGen"), nchMC, threeParCorrMC, denThreeParCorrMC); + registry.fill(HIST("NchvsFourParCorrGen"), nchMC, fourParCorrMC, denFourParCorrMC); + } + } else { + registry.fill(HIST("EvtsDivided"), 1); + //----- MC reconstructed -----// + for (const auto& collision : collisions) { + // Event selection + if (!isEventSelected(collision)) { + continue; + } + // MC collision? + if (!collision.has_mcCollision()) { + continue; + } + + registry.fill(HIST("zPos"), collision.posZ()); + registry.fill(HIST("nRecColvsCent"), collisions.size(), collision.centFT0C()); + + const auto& cent{collision.centFT0C()}; + registry.fill(HIST("T0Ccent"), cent); + + const auto& groupedTracks{simTracks.sliceBy(perCollision, collision.globalIndex())}; + for (const auto& track : groupedTracks) { + if (!track.has_mcParticle()) { + continue; + } + + const auto& particle{track.mcParticle()}; + registry.fill(HIST("Pt_all_ch"), cent, track.pt()); + registry.fill(HIST("EtaVsPhi"), track.eta(), track.phi()); + + if (!particle.isPhysicalPrimary()) { + continue; + } + + registry.fill(HIST("Pt_ch"), cent, track.pt()); + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + registry.fill(HIST("Pt_pi"), cent, track.pt()); + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + registry.fill(HIST("Pt_ka"), cent, track.pt()); + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + registry.fill(HIST("Pt_pr"), cent, track.pt()); + } else if (particle.pdgCode() == PDG_t::kSigmaPlus || particle.pdgCode() == PDG_t::kSigmaBarMinus) { + registry.fill(HIST("Pt_sigpos"), cent, track.pt()); + } else if (particle.pdgCode() == PDG_t::kSigmaMinus || particle.pdgCode() == PDG_t::kSigmaBarPlus) { + registry.fill(HIST("Pt_signeg"), cent, track.pt()); + } else { + registry.fill(HIST("Pt_re"), cent, track.pt()); + } + } + + // Generated MC + registry.fill(HIST("hEventCounterMC"), EvCutLabel::All); + if (std::fabs(mccollision.posZ()) > posZcut) { + continue; + } + registry.fill(HIST("zPosMC"), mccollision.posZ()); + registry.fill(HIST("hEventCounterMC"), EvCutLabel::VtxZ); + + for (const auto& particle : mcParticles) { + if (particle.eta() < minEta || particle.eta() > maxEta) { + continue; + } + if (particle.pt() < minPt || particle.pt() > maxPt) { + continue; + } + if (!particle.isPhysicalPrimary()) { + continue; + } + + registry.fill(HIST("PtMC_ch"), cent, particle.pt()); + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { // pion + registry.fill(HIST("PtMC_pi"), cent, particle.pt()); + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { // kaon + registry.fill(HIST("PtMC_ka"), cent, particle.pt()); + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { // proton + registry.fill(HIST("PtMC_pr"), cent, particle.pt()); + } else if (particle.pdgCode() == PDG_t::kSigmaPlus || particle.pdgCode() == PDG_t::kSigmaBarMinus) { // positive sigma + registry.fill(HIST("PtMC_sigpos"), cent, particle.pt()); + } else if (particle.pdgCode() == PDG_t::kSigmaMinus || particle.pdgCode() == PDG_t::kSigmaBarPlus) { // negative sigma + registry.fill(HIST("PtMC_signeg"), cent, particle.pt()); + } else { // rest + registry.fill(HIST("PtMC_re"), cent, particle.pt()); + } + } + } + } // Half of statistics for corrections + } + PROCESS_SWITCH(UccZdc, processMCclosure, "Process MC closure", false); + + template + void getPTpowers(const T& pTs, const T& wIs, U& pOne, U& wOne, U& pTwo, U& wTwo, U& pThree, U& wThree, U& pFour, U& wFour) + { + pOne = wOne = pTwo = wTwo = pThree = wThree = pFour = wFour = 0.; + for (std::size_t i = 0; i < pTs.size(); ++i) { + const float pTi{pTs.at(i)}; + const float wEighti{wIs.at(i)}; + pOne += wEighti * pTi; + wOne += wEighti; + pTwo += std::pow(wEighti * pTi, 2.); + wTwo += std::pow(wEighti, 2.); + pThree += std::pow(wEighti * pTi, 3.); + wThree += std::pow(wEighti, 3.); + pFour += std::pow(wEighti * pTi, 4.); + wFour += std::pow(wEighti, 4.); + } + } + + // Single-Track Selection + // template + // bool passedTrackSelection(const T2& track) { + // if (track.eta() < minEta || track.eta() > maxEta) return false; + // if (track.pt() < minPt) return false; + // + // if (!track.hasITS()) return false; + // if (track.itsNCls() < minItsNclusters) return false; + // if (!track.hasTPC()) return false; + // if (track.tpcNClsFound() < minTpcNclusters) return false; + // if (track.tpcNClsCrossedRows() < minTpcNcrossedRows) return false; + // if (track.tpcChi2NCl() > maxChiSquareTpc) return false; + // if (track.itsChi2NCl() > maxChiSquareIts) return false; + // // pt-dependent selection + // if (setDCAselectionPtDep) { + // if (std::fabs(track.dcaXY()) > (par0 + par1 / track.pt())) return + // false; if (std::fabs(track.dcaZ()) > (par0 + par1 / track.pt())) + // return false; + // } + // // standard selection + // if (!setDCAselectionPtDep) { + // if (std::fabs(track.dcaXY()) > maxDcaxy) return false; + // if (std::fabs(track.dcaZ()) > maxDcaz) return false; + // } + // return true; + // } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Nuspex/AntimatterAbsorptionHMPID.cxx b/PWGLF/Tasks/Nuspex/AntimatterAbsorptionHMPID.cxx index 18d200510e2..b5a5a2c3ee4 100644 --- a/PWGLF/Tasks/Nuspex/AntimatterAbsorptionHMPID.cxx +++ b/PWGLF/Tasks/Nuspex/AntimatterAbsorptionHMPID.cxx @@ -26,22 +26,34 @@ #include "Framework/RunningWorkflowInfo.h" #include "Framework/DataTypes.h" #include "Common/Core/TrackSelection.h" -#include "Common/Core/trackUtilities.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/TrackSelectionTables.h" #include "Common/Core/PID/PIDTOF.h" -#include "Common/TableProducer/PID/pidTOFBase.h" #include "ReconstructionDataFormats/Track.h" -#include "ReconstructionDataFormats/PID.h" #include "ReconstructionDataFormats/TrackParametrization.h" #include "ReconstructionDataFormats/DCA.h" +#include "DetectorsBase/Propagator.h" +#include "Common/Core/trackUtilities.h" +#include "ReconstructionDataFormats/PID.h" +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "DataFormatsParameters/GRPMagField.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::constants::physics; +static constexpr int nCharges = 2; // Positive and negative +static constexpr int nSpecies = 4; // Number of species +static constexpr const char* particleTitle[nSpecies] = {"#pi", "K", "p", "d"}; +static constexpr const char* particleNames[nSpecies] = {"pi", "ka", "pr", "de"}; +static constexpr const char* chargeNames[nCharges] = {"pos", "neg"}; +std::array, nCharges>, nSpecies> hCorrelationMomentumVertexHMPID; +std::array, nCharges>, nSpecies> hCorrelationMomentumVertexPropagated; +std::array, nCharges>, nSpecies> hmpidEtaPhiMom; + struct AntimatterAbsorptionHMPID { // Histograms @@ -67,9 +79,23 @@ struct AntimatterAbsorptionHMPID { Configurable maxDCAxy{"maxDCAxy", 0.5f, "maxDCAxy"}; Configurable maxDCAz{"maxDCAz", 0.5f, "maxDCAz"}; Configurable use_hmpid_mom{"use_hmpid_mom", true, "use hmpid momentum"}; + // CCDB configurable + + Service ccdb; + struct : ConfigurableGroup { + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + } ccdbConfig; void init(o2::framework::InitContext&) { + // Configure CCDB + ccdb->setURL(ccdbConfig.ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + // Event Counter registryQC.add("number_of_events_data", "number of events in data", HistType::kTH1F, {{10, 0, 10, "counter"}}); @@ -82,6 +108,27 @@ struct AntimatterAbsorptionHMPID { registryDA.add("hmpidEtaPhiMomPos", "hmpidEtaPhiMomPos", HistType::kTH3F, {{29, 0.1, 3.0, "p (GeV/c)"}, {180, -0.9, 0.9, "#eta"}, {200, 0.0, TMath::Pi(), "#phi"}}); registryDA.add("hmpidEtaPhiMomNeg", "hmpidEtaPhiMomNeg", HistType::kTH3F, {{29, 0.1, 3.0, "p (GeV/c)"}, {180, -0.9, 0.9, "#eta"}, {200, 0.0, TMath::Pi(), "#phi"}}); + for (int i = 0; i < nCharges; i++) { + for (int j = 0; j < nSpecies; j++) { + hCorrelationMomentumVertexHMPID[j][i] = registryDA.add(Form("%s/%s/hCorrelationMomentumVertexHMPID", particleNames[j], chargeNames[i]), + Form("Correlation between momentum at vertex and HMPID for %s %s", particleTitle[j], chargeNames[i]), + kTH2D, + {{100, 0.0, 3.0, "p_{vtx} (GeV/c)"}, + {100, 0.0, 3.0, "p_{HMPID} (GeV/c)"}}); + hCorrelationMomentumVertexPropagated[j][i] = registryDA.add(Form("%s/%s/hCorrelationMomentumVertexPropagated", particleNames[j], chargeNames[i]), + Form("Correlation between momentum at vertex and propagated for %s %s", particleTitle[j], chargeNames[i]), + kTH2D, + {{100, 0.0, 3.0, "p_{vtx} (GeV/c)"}, + {100, 0.0, 3.0, "p_{propagated} (GeV/c)"}}); + hmpidEtaPhiMom[j][i] = registryDA.add(Form("%s/%s/hmpidEtaPhiMom", particleNames[j], chargeNames[i]), + Form("Map %s %s", particleTitle[j], chargeNames[i]), + kTH3D, + {{29, 0.1, 3.0, "p (GeV/c)"}, + {180, -0.9, 0.9, "#eta"}, + {200, 0.0, TMath::Pi(), "#phi"}}); + } + } + // Pion Pos registryDA.add("incomingPi_Pos_8cm", "incomingPi_Pos_8cm", HistType::kTH1F, {{290, 0.1, 3.0, "#it{p} (GeV/#it{c})"}}); registryDA.add("incomingPi_Pos_4cm", "incomingPi_Pos_4cm", HistType::kTH1F, {{290, 0.1, 3.0, "#it{p} (GeV/#it{c})"}}); @@ -181,10 +228,6 @@ struct AntimatterAbsorptionHMPID { return false; if (!track.hasTOF()) return false; - if (!track.passedITSRefit()) - return false; - if (!track.passedTPCRefit()) - return false; if (track.itsNCls() < minReqClusterITS) return false; if (track.tpcNClsFound() < minTPCnClsFound) @@ -276,12 +319,49 @@ struct AntimatterAbsorptionHMPID { return true; } + int mCCDBRunNumber = 0; + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mCCDBRunNumber == bc.runNumber()) { + return; + } + o2::parameters::GRPMagField* grpmag = ccdb->getForTimeStamp(ccdbConfig.grpmagPath, bc.timestamp()); + o2::base::MatLayerCylSet* lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbConfig.lutPath)); + o2::base::Propagator::initFieldFromGRP(grpmag); + o2::base::Propagator::Instance()->setMatLUT(lut); + mCCDBRunNumber = bc.runNumber(); + } + + o2::track::TrackParametrizationWithError mPropagatedTrack; + template + bool propagateToRadius(const trackType& track, const float radius, const o2::track::PID::ID pidForTracking) + { + mPropagatedTrack = getTrackParCov(track); + mPropagatedTrack.setPID(pidForTracking); + auto prop = o2::base::Propagator::Instance(); + float xprop = 0; + if (mPropagatedTrack.getXatLabR(radius, xprop, prop->getNominalBz(), o2::track::DirType::DirOutward)) { + if (!prop->PropagateToXBxByBz(mPropagatedTrack, xprop, 0.95, 10, o2::base::Propagator::MatCorrType::USEMatCorrLUT)) { + return false; + } + return true; + } + return false; + } + // Full Tracks - using FullTracks = soa::Join; + using CollisionCandidates = o2::soa::Join; + using TrackCandidates = soa::Join; // Process Data - void processData(o2::soa::Join::iterator const& event, o2::aod::HMPIDs const& hmpids) + void processData(CollisionCandidates::iterator const& event, + o2::aod::HMPIDs const& hmpids, + TrackCandidates const&, + aod::BCsWithTimestamps const&) { + initCCDB(event.bc_as()); // Event Selection registryQC.fill(HIST("number_of_events_data"), 0.5); @@ -296,11 +376,14 @@ struct AntimatterAbsorptionHMPID { // Event Counter registryQC.fill(HIST("number_of_events_data"), 2.5); + if (hmpids.size() > 0) { + registryQC.fill(HIST("number_of_events_data"), 3.5); + } for (const auto& hmpid : hmpids) { // Get Track - const auto& track = hmpid.track_as(); + const auto& track = hmpid.track_as(); // Track Momentum float momentum = track.p(); @@ -308,8 +391,9 @@ struct AntimatterAbsorptionHMPID { momentum = hmpid.hmpidMom(); // Track Selection - if (!passedTrackSelection(track)) + if (!passedTrackSelection(track)) { continue; + } if (track.sign() > 0) { registryDA.fill(HIST("hmpidXYpos"), hmpid.hmpidXMip(), hmpid.hmpidYMip()); @@ -327,9 +411,12 @@ struct AntimatterAbsorptionHMPID { bool hmpidAbs4cm = true; // Distance between extrapolated and matched point - float dx = hmpid.hmpidXTrack() - hmpid.hmpidXMip(); - float dy = hmpid.hmpidYTrack() - hmpid.hmpidYMip(); - float dr = sqrt(dx * dx + dy * dy); + const float dx = hmpid.hmpidXTrack() - hmpid.hmpidXMip(); + const float dy = hmpid.hmpidYTrack() - hmpid.hmpidYMip(); + const float dr = sqrt(dx * dx + dy * dy); + + // Propagate track to 5 meters + bool propOk = propagateToRadius(track, 500.0, o2::track::PID::Pion); // Fill Histograms for Positive Pions if (passedPionSelection(track) && track.sign() > 0) { @@ -345,6 +432,11 @@ struct AntimatterAbsorptionHMPID { registryDA.fill(HIST("survivingPi_Pos_4cm"), momentum, dr); registryDA.fill(HIST("Pi_Pos_Q_4cm"), momentum, hmpid.hmpidQMip()); registryDA.fill(HIST("Pi_Pos_ClsSize_4cm"), momentum, hmpid.hmpidClusSize()); + hCorrelationMomentumVertexHMPID[0][0]->Fill(track.p(), hmpid.hmpidMom()); + hmpidEtaPhiMom[0][0]->Fill(track.p(), track.eta(), track.phi()); + if (propOk) { + hCorrelationMomentumVertexPropagated[0][0]->Fill(track.p(), mPropagatedTrack.getP()); + } } } @@ -362,9 +454,16 @@ struct AntimatterAbsorptionHMPID { registryDA.fill(HIST("survivingPi_Neg_4cm"), momentum, dr); registryDA.fill(HIST("Pi_Neg_Q_4cm"), momentum, hmpid.hmpidQMip()); registryDA.fill(HIST("Pi_Neg_ClsSize_4cm"), momentum, hmpid.hmpidClusSize()); + hmpidEtaPhiMom[0][1]->Fill(track.p(), track.eta(), track.phi()); + hCorrelationMomentumVertexHMPID[0][1]->Fill(track.p(), hmpid.hmpidMom()); + if (propOk) { + hCorrelationMomentumVertexPropagated[0][1]->Fill(track.p(), mPropagatedTrack.getP()); + } } } + propOk = propagateToRadius(track, 500.0, o2::track::PID::Kaon); + // Fill Histograms for Positive Kaons if (passedKaonSelection(track) && track.sign() > 0) { @@ -379,6 +478,11 @@ struct AntimatterAbsorptionHMPID { registryDA.fill(HIST("survivingKa_Pos_4cm"), momentum, dr); registryDA.fill(HIST("Ka_Pos_Q_4cm"), momentum, hmpid.hmpidQMip()); registryDA.fill(HIST("Ka_Pos_ClsSize_4cm"), momentum, hmpid.hmpidClusSize()); + hmpidEtaPhiMom[1][0]->Fill(track.p(), track.eta(), track.phi()); + hCorrelationMomentumVertexHMPID[1][0]->Fill(track.p(), hmpid.hmpidMom()); + if (propOk) { + hCorrelationMomentumVertexPropagated[1][0]->Fill(track.p(), mPropagatedTrack.getP()); + } } } @@ -396,9 +500,16 @@ struct AntimatterAbsorptionHMPID { registryDA.fill(HIST("survivingKa_Neg_4cm"), momentum, dr); registryDA.fill(HIST("Ka_Neg_Q_4cm"), momentum, hmpid.hmpidQMip()); registryDA.fill(HIST("Ka_Neg_ClsSize_4cm"), momentum, hmpid.hmpidClusSize()); + hmpidEtaPhiMom[1][1]->Fill(track.p(), track.eta(), track.phi()); + hCorrelationMomentumVertexHMPID[1][1]->Fill(track.p(), hmpid.hmpidMom()); + if (propOk) { + hCorrelationMomentumVertexPropagated[1][1]->Fill(track.p(), mPropagatedTrack.getP()); + } } } + propOk = propagateToRadius(track, 500.0, o2::track::PID::Proton); + // Fill Histograms for Positive Protons if (passedProtonSelection(track) && track.sign() > 0) { @@ -413,6 +524,11 @@ struct AntimatterAbsorptionHMPID { registryDA.fill(HIST("survivingPr_Pos_4cm"), momentum, dr); registryDA.fill(HIST("Pr_Pos_Q_4cm"), momentum, hmpid.hmpidQMip()); registryDA.fill(HIST("Pr_Pos_ClsSize_4cm"), momentum, hmpid.hmpidClusSize()); + hmpidEtaPhiMom[2][0]->Fill(track.p(), track.eta(), track.phi()); + hCorrelationMomentumVertexHMPID[2][0]->Fill(track.p(), hmpid.hmpidMom()); + if (propOk) { + hCorrelationMomentumVertexPropagated[2][0]->Fill(track.p(), mPropagatedTrack.getP()); + } } } @@ -430,9 +546,15 @@ struct AntimatterAbsorptionHMPID { registryDA.fill(HIST("survivingPr_Neg_4cm"), momentum, dr); registryDA.fill(HIST("Pr_Neg_Q_4cm"), momentum, hmpid.hmpidQMip()); registryDA.fill(HIST("Pr_Neg_ClsSize_4cm"), momentum, hmpid.hmpidClusSize()); + hmpidEtaPhiMom[2][1]->Fill(track.p(), track.eta(), track.phi()); + hCorrelationMomentumVertexHMPID[2][1]->Fill(track.p(), hmpid.hmpidMom()); + if (propOk) { + hCorrelationMomentumVertexPropagated[2][1]->Fill(track.p(), mPropagatedTrack.getP()); + } } } + propOk = propagateToRadius(track, 500.0, o2::track::PID::Deuteron); // Fill Histograms for Positive Deuterons if (passedDeuteronSelection(track) && track.sign() > 0) { @@ -447,6 +569,11 @@ struct AntimatterAbsorptionHMPID { registryDA.fill(HIST("survivingDe_Pos_4cm"), momentum, dr); registryDA.fill(HIST("De_Pos_Q_4cm"), momentum, hmpid.hmpidQMip()); registryDA.fill(HIST("De_Pos_ClsSize_4cm"), momentum, hmpid.hmpidClusSize()); + hmpidEtaPhiMom[3][0]->Fill(track.p(), track.eta(), track.phi()); + hCorrelationMomentumVertexHMPID[3][0]->Fill(track.p(), hmpid.hmpidMom()); + if (propOk) { + hCorrelationMomentumVertexPropagated[3][0]->Fill(track.p(), mPropagatedTrack.getP()); + } } } @@ -464,6 +591,11 @@ struct AntimatterAbsorptionHMPID { registryDA.fill(HIST("survivingDe_Neg_4cm"), momentum, dr); registryDA.fill(HIST("De_Neg_Q_4cm"), momentum, hmpid.hmpidQMip()); registryDA.fill(HIST("De_Neg_ClsSize_4cm"), momentum, hmpid.hmpidClusSize()); + hmpidEtaPhiMom[3][1]->Fill(track.p(), track.eta(), track.phi()); + hCorrelationMomentumVertexHMPID[3][1]->Fill(track.p(), hmpid.hmpidMom()); + if (propOk) { + hCorrelationMomentumVertexPropagated[3][1]->Fill(track.p(), mPropagatedTrack.getP()); + } } } } diff --git a/PWGLF/Tasks/Nuspex/CMakeLists.txt b/PWGLF/Tasks/Nuspex/CMakeLists.txt index b282dafe81f..cc9e0599e7a 100644 --- a/PWGLF/Tasks/Nuspex/CMakeLists.txt +++ b/PWGLF/Tasks/Nuspex/CMakeLists.txt @@ -11,7 +11,7 @@ o2physics_add_dpl_workflow(nuclei-batask SOURCES LFNucleiBATask.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(hypertritonanalysis @@ -30,13 +30,8 @@ o2physics_add_dpl_workflow(hypertriton3bodyanalysis COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(hypertriton3bodymcqa - SOURCES hypertriton3bodyMCQA.cxx - PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(nuclei-in-jets - SOURCES nuclei_in_jets.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + SOURCES hypertriton3bodyMcqa.cxx + PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore O2::TOFBase COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(helium-flow @@ -89,6 +84,11 @@ o2physics_add_dpl_workflow(spectra-tpc-tiny PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(nuclei-tpcspectra + SOURCES NucleitpcPbPb.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(spectra-tpc-tiny-pikapr SOURCES spectraTPCtinyPiKaPr.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -123,3 +123,40 @@ o2physics_add_dpl_workflow(hadronnucleicorrelation SOURCES hadronnucleicorrelation.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(nuclei-efficiency-hist + SOURCES NucleiEfficiencyTask.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(nuclei-ebye + SOURCES nucleiEbye.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(nuclei-toward-transv + SOURCES nuclei_in_toward_transv_regions.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(ebye-mult + SOURCES ebyeMult.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(nuclei-from-hypertriton-map + SOURCES nucleiFromHypertritonMap.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +if(FastJet_FOUND) +o2physics_add_dpl_workflow(angular-correlations-in-jets + SOURCES angularCorrelationsInJets.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet FastJet::Contrib + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(antinuclei-in-jets + SOURCES antinucleiInJets.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet FastJet::Contrib + COMPONENT_NAME Analysis) +endif() diff --git a/PWGLF/Tasks/Nuspex/LFNucleiBATask.cxx b/PWGLF/Tasks/Nuspex/LFNucleiBATask.cxx index 5fb227f938d..f3f57325bac 100644 --- a/PWGLF/Tasks/Nuspex/LFNucleiBATask.cxx +++ b/PWGLF/Tasks/Nuspex/LFNucleiBATask.cxx @@ -16,7 +16,13 @@ /// /// \author Giovanni Malfattore and Rutuparna Rath /// + #include "PWGLF/DataModel/LFNucleiTables.h" + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" +#include "CCDB/BasicCCDBManager.h" +#include #include #include #include "ReconstructionDataFormats/Track.h" @@ -28,6 +34,7 @@ #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -41,10 +48,16 @@ using namespace o2::framework; using namespace o2::framework::expressions; struct LFNucleiBATask { + Service ccdb; + + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry spectraGen{"spectraGen", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; HistogramRegistry debugHistos{"debugHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry evtimeHistos{"evtimeHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry evLossHistos{"evLossHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; // Enable particle for analysis Configurable enablePr{"enablePr", true, "Flag to enable proton analysis."}; @@ -54,12 +67,21 @@ struct LFNucleiBATask { Configurable enableAl{"enableAl", true, "Flag to enable alpha analysis."}; Configurable enableTrackingEff{"enableTrackingEff", 0, "Flag to enable tracking efficiency hitos."}; + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + // Set the triggered events skimming scheme + struct : ConfigurableGroup { + Configurable applySkimming{"applySkimming", false, "Skimmed dataset processing"}; + Configurable cfgSkimming{"cfgSkimming", "fHe", "Configurable for skimming"}; + } skimmingOptions; // Set the event selection cuts - Configurable useSel8{"useSel8", true, "Use Sel8 for run3 Event Selection"}; - Configurable TVXtrigger{"TVXtrigger", false, "Use TVX for Event Selection (default w/ Sel8)"}; - Configurable removeTFBorder{"removeTFBorder", false, "Remove TimeFrame border (default w/ Sel8)"}; - Configurable removeITSROFBorder{"removeITSROFBorder", false, "Remove ITS Read-Out Frame border (default w/ Sel8)"}; + struct : ConfigurableGroup { + Configurable useSel8{"useSel8", true, "Use Sel8 for run3 Event Selection"}; + Configurable TVXtrigger{"TVXtrigger", false, "Use TVX for Event Selection (default w/ Sel8)"}; + Configurable removeTFBorder{"removeTFBorder", false, "Remove TimeFrame border (default w/ Sel8)"}; + Configurable removeITSROFBorder{"removeITSROFBorder", false, "Remove ITS Read-Out Frame border (default w/ Sel8)"}; + } evselOptions; // Set the multiplity event limits Configurable cfgLowMultCut{"cfgLowMultCut", 0.0f, "Accepted multiplicity percentage lower limit"}; @@ -70,62 +92,92 @@ struct LFNucleiBATask { Configurable cfgLowCutVertex{"cfgLowCutVertex", -10.0f, "Accepted z-vertex lower limit"}; // Set the quality cuts for tracks - Configurable rejectFakeTracks{"rejectFakeTracks", false, "Flag to reject ITS-TPC fake tracks (for MC)"}; - Configurable cfgCutITSClusters{"cfgCutITSClusters", -1.f, "Minimum number of ITS clusters"}; - Configurable cfgCutTPCXRows{"cfgCutTPCXRows", -1.f, "Minimum number of crossed TPC rows"}; - Configurable cfgCutTPCClusters{"cfgCutTPCClusters", -1.f, "Minimum number of found TPC clusters"}; - Configurable nITSLayer{"nITSLayer", 0, "ITS Layer (0-6)"}; + struct : ConfigurableGroup { + Configurable rejectFakeTracks{"rejectFakeTracks", false, "Flag to reject ITS-TPC fake tracks (for MC)"}; + Configurable cfgCutITSClusters{"cfgCutITSClusters", -1.f, "Minimum number of ITS clusters"}; + Configurable cfgCutTPCXRows{"cfgCutTPCXRows", -1.f, "Minimum number of crossed TPC rows"}; + Configurable cfgCutTPCClusters{"cfgCutTPCClusters", -1.f, "Minimum number of found TPC clusters"}; + Configurable cfgCutTPCCROFnd{"cfgCutTPCCROFnd", 0.8, "Minimum ratio of crossed TPC clusters over findable"}; + Configurable> tpcChi2NclCuts{"tpcChi2NclCuts", {0.5, 4}, "Range of accepted of Chi2/TPC clusters"}; + Configurable> itsChi2NclCuts{"itsChi2NclCuts", {0.f, 36}, "Range of accepted of Chi2/ITS clusters"}; + Configurable nITSLayer{"nITSLayer", 0, "ITS Layer (0-6)"}; + } trkqcOptions; // Set the kinematic and PID cuts for tracks - Configurable pCut{"pCut", 0.3f, "Value of the p selection for spectra (default 0.3)"}; - Configurable etaCut{"etaCut", 0.8f, "Value of the eta selection for spectra (default 0.8)"}; - Configurable yLowCut{"yLowCut", -1.0f, "Value of the low rapidity selection for spectra (default -1.0)"}; - Configurable yHighCut{"yHighCut", 1.0f, "Value of the high rapidity selection for spectra (default 1.0)"}; + struct : ConfigurableGroup { + Configurable pCut{"pCut", 0.3f, "Value of the p selection for spectra (default 0.3)"}; + Configurable etaCut{"etaCut", 0.8f, "Value of the eta selection for spectra (default 0.8)"}; + Configurable yLowCut{"yLowCut", -1.0f, "Value of the low rapidity selection for spectra (default -1.0)"}; + Configurable yHighCut{"yHighCut", 1.0f, "Value of the high rapidity selection for spectra (default 1.0)"}; + } kinemOptions; Configurable isPVContributorCut{"isPVContributorCut", false, "Flag to enable isPVContributor cut."}; - Configurable DCAxyCustomCut{"DCAxyCustomCut", 2.0f, "Value of the DCAxy selection for spectra (default 2.0 cm)"}; - Configurable DCAzCustomCut{"DCAzCustomCut", 2.0f, "Value of the DCAz selection for spectra (default 2.0 cm)"}; - Configurable nsigmaTPCPr{"nsigmaTPCPr", 3.f, "Value of the Nsigma TPC cut for protons"}; - Configurable nsigmaTPCDe{"nsigmaTPCDe", 3.f, "Value of the Nsigma TPC cut for deuterons"}; - Configurable nsigmaTPCTr{"nsigmaTPCTr", 3.f, "Value of the Nsigma TPC cut for tritons"}; - Configurable nsigmaTPCHe{"nsigmaTPCHe", 3.f, "Value of the Nsigma TPC cut for helium-3"}; - Configurable nsigmaTPCAl{"nsigmaTPCAl", 3.f, "Value of the Nsigma TPC cut for alpha"}; + struct : ConfigurableGroup { + Configurable nsigmaTPCPr{"nsigmaTPCPr", 3.f, "Value of the Nsigma TPC cut for protons"}; + Configurable nsigmaTPCDe{"nsigmaTPCDe", 3.f, "Value of the Nsigma TPC cut for deuterons"}; + Configurable nsigmaTPCTr{"nsigmaTPCTr", 3.f, "Value of the Nsigma TPC cut for tritons"}; + Configurable nsigmaTPCHe{"nsigmaTPCHe", 3.f, "Value of the Nsigma TPC cut for helium-3"}; + Configurable nsigmaTPCAl{"nsigmaTPCAl", 3.f, "Value of the Nsigma TPC cut for alpha"}; + } nsigmaTPCvar; + + struct : ConfigurableGroup { + Configurable useITSHeCut{"useITSHeCut", false, "Select Helium if compatible with helium hypothesis (via SigmaITS)"}; + Configurable nsigmaITSHe{"nsigmaITSHe", -1.f, "Value of the Nsigma ITS cut for helium-3 ( > nSigmaITSHe)"}; + Configurable showAverageClusterSize{"showAverageClusterSize", false, "Show average cluster size"}; + } nsigmaITSvar; // Set additional cuts (used for debug) Configurable betaCut{"betaCut", 0.4f, "Value of the beta selection for TOF cut (default 0.4)"}; // Set the axis used in this task ConfigurableAxis binsPercentile{"binsPercentile", {100, 0, 100}, "Centrality FT0M"}; - ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.5, 7.0, 7.5, 8.0}, ""}; + ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.425, 0.45, 0.475, 0.5, 0.5125, 0.525, 0.5375, 0.55, 0.5625, 0.575, 0.5875, 0.6, 0.6125, 0.625, 0.6375, 0.65, 0.6625, 0.675, 0.6875, 0.7, 0.7125, 0.725, 0.7375, 0.75, 0.7625, 0.775, 0.7875, 0.8, 0.8125, 0.825, 0.8375, 0.85, 0.8625, 0.875, 0.8875, 0.9, 0.9125, 0.925, 0.9375, 0.95, 0.9625, 0.975, 0.9875, 1.0, 1.0125, 1.025, 1.0375, 1.05, 1.0625, 1.075, 1.0875, 1.1, 1.1125, 1.125, 1.1375, 1.15, 1.1625, 1.175, 1.1875, 1.2, 1.2125, 1.225, 1.2375, 1.25, 1.2625, 1.275, 1.2875, 1.3, 1.3125, 1.325, 1.3375, 1.35, 1.3625, 1.375, 1.3875, 1.4, 1.4125, 1.425, 1.4375, 1.45, 1.4625, 1.475, 1.4875, 1.5, 1.5125, 1.525, 1.5375, 1.55, 1.5625, 1.575, 1.5875, 1.6, 1.6125, 1.625, 1.6375, 1.65, 1.6625, 1.675, 1.6875, 1.7, 1.7125, 1.725, 1.7375, 1.75, 1.7625, 1.775, 1.7875, 1.8, 1.8125, 1.825, 1.8375, 1.85, 1.8625, 1.875, 1.8875, 1.9, 1.9125, 1.925, 1.9375, 1.95, 1.9625, 1.975, 1.9875, 2.0, 2.0625, 2.125, 2.1875, 2.25, 2.3125, 2.375, 2.4375, 2.5, 2.625, 2.75, 2.875, 3.0, 3.25, 3.5, 3.75, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0}, ""}; ConfigurableAxis binsPtHe{"binsPtHe", {VARIABLE_WIDTH, 1.0, 1.25, 1.50, 1.75, 2.0, 2.25, 2.50, 2.75, 3.0, 3.25, 3.50, 3.75, 4.0, 4.50, 5.0, 6.0, 7.0, 8.0}, ""}; ConfigurableAxis binsPtZHe{"binsPtZHe", {VARIABLE_WIDTH, 0.5, 0.625, 0.75, 0.875, 1.0, 1.125, 1.25, 1.375, 1.5, 1.625, 1.75, 1.875, 2.0, 2.25, 2.5, 3.0, 3.5, 4.0}, ""}; - ConfigurableAxis binsdEdx{"binsdEdx", {1000, 0.f, 1000.f}, ""}; + ConfigurableAxis binsdEdx{"binsdEdx", {600, 0.f, 3000.f}, ""}; ConfigurableAxis binsBeta{"binsBeta", {120, 0.0, 1.2}, ""}; ConfigurableAxis binsDCA{"binsDCA", {400, -1.f, 1.f}, ""}; + ConfigurableAxis binsSigmaITS{"binsSigmaITS", {200, -20, 20}, ""}; ConfigurableAxis binsSigmaTPC{"binsSigmaTPC", {1000, -100, 100}, ""}; ConfigurableAxis binsSigmaTOF{"binsSigmaTOF", {1000, -100, 100}, ""}; ConfigurableAxis binsMassPr{"binsMassPr", {100, -1., 1.f}, ""}; ConfigurableAxis binsMassDe{"binsMassDe", {180, -1.8, 1.8f}, ""}; ConfigurableAxis binsMassTr{"binsMassTr", {250, -2.5, 2.5f}, ""}; ConfigurableAxis binsMassHe{"binsMassHe", {300, -3., 3.f}, ""}; + ConfigurableAxis avClsBins{"avClsBins", {200, 0, 20}, "Binning in average cluster size"}; // Enable custom cuts/debug functions - Configurable enableFiltering{"enableFiltering", false, "Flag to enable filtering for p,d,t,He only -- disable if launch on skimmed dataset!"}; - Configurable enableEvTimeSplitting{"enableEvTimeSplitting", false, "Flag to enable histograms splitting depending on the Event Time used"}; + struct : ConfigurableGroup { + Configurable enableFiltering{"enableFiltering", false, "Flag to enable filtering for p,d,t,He only -- disable if launch on skimmed dataset!"}; + Configurable enableIsGlobalTrack{"enableIsGlobalTrack", true, "Flag to enable IsGlobalTrackWoDCA"}; + Configurable enableEvTimeSplitting{"enableEvTimeSplitting", false, "Flag to enable histograms splitting depending on the Event Time used"}; + } filterOptions; + Configurable enableDCACustomCut{"enableDCACustomCut", false, "Flag to enable DCA custom cuts - unflag to use standard isGlobalCut DCA cut"}; + struct : ConfigurableGroup { + Configurable DCACustomConfig{"DCACustomConfig", 0, "Select to use: pT independent DCAxy and DCAz CustomCut (0), pT dependent DCAxy and DCAz cut (1), pt dependent DCAxy, DCAz CustomCut (2) DCAxy CustomCut, pT dependent DCAz (3) or a circular DCAxy,z cut (4) for tracks. Need 'enableDCACustomCut' to be enabled."}; + Configurable DCAxyCustomCut{"DCAxyCustomCut", 0.05f, "Value of the DCAxy selection for spectra (default 0.05 cm)"}; + Configurable DCAzCustomCut{"DCAzCustomCut", 0.5f, "Value of the DCAz selection for spectra (default 0.5 cm)"}; + } dcaConfOptions; + + Configurable> parDCAxycuts{"parDCAxycuts", {0.004f, 0.013f, 1, 1}, "Parameters for Pt dependent DCAxy cut (if enabled): |DCAxy| < [3] * ([O] + [1]/Pt^[2])."}; + Configurable> parDCAzcuts{"parDCAzcuts", {0.004f, 0.013f, 1, 1}, "Parameters for Pt dependent DCAz cut (if enabled): |DCAz| < [3] * ([O] + [1]/Pt^[2])."}; // Enable output histograms - Configurable makeDCABeforeCutPlots{"makeDCABeforeCutPlots", false, "Flag to enable plots of DCA before cuts"}; - Configurable makeDCAAfterCutPlots{"makeDCAAfterCutPlots", false, "Flag to enable plots of DCA after cuts"}; - Configurable doTOFplots{"doTOFplots", true, "Flag to export plots of tracks with 1 hit on TOF."}; - Configurable enableExpSignalTPC{"enableExpSignalTPC", true, "Flag to export dEdX - dEdX(exp) plots."}; - Configurable enableExpSignalTOF{"enableExpSignalTOF", false, "Flag to export T - T(exp) plots."}; + struct : ConfigurableGroup { + Configurable makeDCABeforeCutPlots{"makeDCABeforeCutPlots", false, "Flag to enable plots of DCA before cuts"}; + Configurable makeDCAAfterCutPlots{"makeDCAAfterCutPlots", false, "Flag to enable plots of DCA after cuts"}; + Configurable makeFakeTracksPlots{"makeFakeTracksPlots", false, "Flag to enable plots of misidentified particles"}; + Configurable makeWrongEventPlots{"makeWrongEventPlots", false, "Flag to enable plots of particles from wrong event"}; + Configurable doTOFplots{"doTOFplots", true, "Flag to export plots of tracks with 1 hit on TOF."}; + Configurable enableExpSignalTPC{"enableExpSignalTPC", true, "Flag to export dEdX - dEdX(exp) plots."}; + Configurable enableExpSignalTOF{"enableExpSignalTOF", false, "Flag to export T - T(exp) plots."}; + Configurable enableBetaCut{"enableBetaCut", false, "Flag to enable TOF histograms with beta cut for debug"}; + } outFlagOptions; Configurable enablePIDplot{"enablePIDplot", false, "Flag to enable PID histograms for debug"}; - Configurable enableBetaCut{"enableBetaCut", false, "Flag to enable TOF histograms with beta cut for debug"}; - Configurable enableDebug{"enableDebug", false, "Flag to enable histograms for debug"}; Configurable enablePtSpectra{"enablePtSpectra", false, "Flag to enable histograms for efficiency debug."}; @@ -139,26 +191,18 @@ struct LFNucleiBATask { // Additional function used for pT-shift calibration TF1* fShiftPtHe = 0; TF1* fShiftPtantiHe = 0; - TF1* fShiftPHe = 0; - TF1* fShiftPantiHe = 0; - // TF1* fShiftTPCmomHe = 0; - // TF1* fShiftTPCmomantiHe = 0; - TF1* fShiftAntiD = 0; TF1* fShiftD = 0; - // Configurable enableTPCmomShift{"enableTPCmomShift", false, "Flag to enable TPC momentum shift (for He only)"}; - // Configurable enablePShift{"enablePShift", false, "Flag to enable P shift (for He only)"}; - Configurable enablePtShift{"enablePtShift", false, "Flag to enable Pt shift (for He only)"}; + Configurable enablePtShiftAntiD{"enablePtShiftAntiD", true, "Flag to enable Pt shift (for antiDeuteron only)"}; Configurable enablePtShiftD{"enablePtShiftD", true, "Flag to enable Pt shift (for Deuteron only)"}; + Configurable> parShiftPtAntiD{"parShiftPtAntiD", {-0.0955412, 0.798164, -0.536111, 0.0887876, -1.11022e-13}, "Parameters for Pt shift (if enabled)."}; + Configurable> parShiftPtD{"parShiftPtD", {-0.0955412, 0.798164, -0.536111, 0.0887876, -1.11022e-13}, "Parameters for Pt shift (if enabled)."}; + Configurable enablePtShift{"enablePtShift", false, "Flag to enable Pt shift (for He only)"}; Configurable> parShiftPtHe{"parShiftPtHe", {0.0f, 0.1f, 0.1f, 0.1f, 0.1f}, "Parameters for helium3-Pt shift (if enabled)."}; Configurable> parShiftPtantiHe{"parShiftPtantiHe", {0.0f, 0.1f, 0.1f, 0.1f, 0.1f}, "Parameters for anti-helium3-Pt shift (if enabled)."}; - Configurable> parShiftPHe{"parShiftPHe", {0.0f, 0.1f, 0.1f, 0.1f, 0.1f}, "Parameters for helium3-P shift (if enabled)."}; - Configurable> parShiftPantiHe{"parShiftPantiHe", {0.0f, 0.1f, 0.1f, 0.1f, 0.1f}, "Parameters for anti-helium3-P shift (if enabled)."}; - Configurable> parShiftPtAntiD{"parShiftPtAntiD", {-0.0955412, 0.798164, -0.536111, 0.0887876, -1.11022e-13}, "Parameters for Pt shift (if enabled)."}; - Configurable> parShiftPtD{"parShiftPtD", {-0.0955412, 0.798164, -0.536111, 0.0887876, -1.11022e-13}, "Parameters for Pt shift (if enabled)."}; Configurable enableCentrality{"enableCentrality", true, "Flag to enable centrality 3D histos)"}; // PDG codes and masses used in this analysis @@ -169,17 +213,44 @@ struct LFNucleiBATask { static constexpr int PDGTriton = 1000010030; static constexpr int PDGHelium = 1000020030; static constexpr int PDGAlpha = 1000020040; - static constexpr float fMassProton = 0.938272088f; - static constexpr float fMassDeuteron = 1.87561f; - static constexpr float fMassTriton = 2.80892f; - static constexpr float fMassHelium = 2.80839f; - static constexpr float fMassAlpha = 3.72738f; + static constexpr float MassProtonVal = 0.938272088f; + static constexpr float MassDeuteronVal = 1.87561f; + static constexpr float MassTritonVal = 2.80892f; + static constexpr float MassHeliumVal = 2.80839f; + static constexpr float MassAlphaVal = 3.72738f; + + template + float averageClusterSizeTrk(const TrackType& track) + { + return o2::aod::ITSResponse::averageClusterSize(track.itsClusterSizes()); + } + + float averageClusterSizePerCoslInv(uint32_t itsClusterSizes, float eta) { return o2::aod::ITSResponse::averageClusterSize(itsClusterSizes) * std::cosh(eta); } + + template + float averageClusterSizePerCoslInv(const TrackType& track) + { + return averageClusterSizePerCoslInv(track.itsClusterSizes(), track.eta()); + } + + void initCCDB(o2::aod::BCsWithTimestamps::iterator const& bc) + { + if (skimmingOptions.applySkimming) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), skimmingOptions.cfgSkimming.value); + zorro.populateHistRegistry(histos, bc.runNumber()); + } + } void init(o2::framework::InitContext&) { + if (skimmingOptions.applySkimming) { + zorroSummary.setObject(zorro.getZorroSummary()); + } + const AxisSpec pAxis{binsPt, "#it{p} (GeV/#it{c})"}; const AxisSpec ptAxis{binsPt, "#it{p}_{T} (GeV/#it{c})"}; const AxisSpec ptHeAxis{binsPtHe, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec pZAxis{binsPt, "#it{p}/z (GeV/#it{c})"}; const AxisSpec ptZHeAxis{binsPtZHe, "#it{p}_{T}/z (GeV/#it{c})"}; const AxisSpec dedxAxis{binsdEdx, "d#it{E}/d#it{x} A.U."}; const AxisSpec betaAxis{binsBeta, "TOF #beta"}; @@ -189,29 +260,50 @@ struct LFNucleiBATask { const AxisSpec massDeAxis{binsMassDe, ""}; const AxisSpec massTrAxis{binsMassTr, ""}; const AxisSpec massHeAxis{binsMassHe, ""}; - const AxisSpec SigmaTPCAxis{binsSigmaTPC, ""}; - const AxisSpec SigmaTOFAxis{binsSigmaTOF, ""}; + const AxisSpec sigmaITSAxis{binsSigmaITS, ""}; + const AxisSpec sigmaTPCAxis{binsSigmaTPC, ""}; + const AxisSpec sigmaTOFAxis{binsSigmaTOF, ""}; + const AxisSpec avClsAxis{avClsBins, ""}; + const AxisSpec avClsEffAxis{avClsBins, " / cosh(#eta)"}; if (doprocessData == true && doprocessMCReco == true) { LOG(fatal) << "Can't enable processData and processMCReco in the same time, pick one!"; } - spectraGen.add("LfEv/pT_nocut", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{600, 0., 6.}}); - spectraGen.add("LfEv/pT_TVXtrigger", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{600, 0., 6.}}); - spectraGen.add("LfEv/pT_TFrameBorder", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{600, 0., 6.}}); - spectraGen.add("LfEv/pT_ITSROFBorder", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{600, 0., 6.}}); - spectraGen.add("LfEv/pT_sel8", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{600, 0., 6.}}); - - spectraGen.add("LfEv/helium/pT_nocut_He", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{600, 0., 6.}}); - spectraGen.add("LfEv/helium/pT_TVXtrigger_He", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{600, 0., 6.}}); - spectraGen.add("LfEv/helium/pT_TFrameBorder_He", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{600, 0., 6.}}); - spectraGen.add("LfEv/helium/pT_ITSROFBorder_He", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{600, 0., 6.}}); - spectraGen.add("LfEv/helium/pT_sel8_He", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{600, 0., 6.}}); - - spectraGen.add("LfEv/helium/pT_nocut_antiHe", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{600, 0., 6.}}); - spectraGen.add("LfEv/helium/pT_TVXtrigger_antiHe", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{600, 0., 6.}}); - spectraGen.add("LfEv/helium/pT_TFrameBorder_antiHe", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{600, 0., 6.}}); - spectraGen.add("LfEv/helium/pT_ITSROFBorder_antiHe", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{600, 0., 6.}}); - spectraGen.add("LfEv/helium/pT_sel8_antiHe", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{600, 0., 6.}}); + if (doprocessEvSgLossMC) { + evLossHistos.add("evLoss/hEvent", "Event loss histograms; ; counts", HistType::kTH1F, {{3, 0., 3.}}); + evLossHistos.get(HIST("evLoss/hEvent"))->GetXaxis()->SetBinLabel(1, "All Gen."); + evLossHistos.get(HIST("evLoss/hEvent"))->GetXaxis()->SetBinLabel(2, "TVX (reco.)"); + evLossHistos.get(HIST("evLoss/hEvent"))->GetXaxis()->SetBinLabel(3, "Sel8 (reco.)"); + + evLossHistos.add("evLoss/pt/hDeuteronTriggeredTVX", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{100, 0., 5.}}); + evLossHistos.add("evLoss/pt/hDeuteronTriggeredSel8", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{100, 0., 5.}}); + evLossHistos.add("evLoss/pt/hDeuteronGen", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{100, 0., 5.}}); + evLossHistos.add("evLoss/pt/hAntiDeuteronTriggeredTVX", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{100, 0., 5.}}); + evLossHistos.add("evLoss/pt/hAntiDeuteronTriggeredSel8", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{100, 0., 5.}}); + evLossHistos.add("evLoss/pt/hAntiDeuteronGen", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{100, 0., 5.}}); + } + spectraGen.add("LfEv/pT_nocut", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/pT_TVXtrigger", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/pT_TFrameBorder", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/pT_ITSROFBorder", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/pT_sel8", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/pT_MCsel8", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + + spectraGen.add("LfEv/helium/pT_nocut_He", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/pT_TVXtrigger_He", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/pT_TFrameBorder_He", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/pT_ITSROFBorder_He", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/pT_sel8_He", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/pT_MCsel8_He", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/pT_MCsel8_HePrim", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + + spectraGen.add("LfEv/helium/pT_nocut_antiHe", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/pT_TVXtrigger_antiHe", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/pT_TFrameBorder_antiHe", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/pT_ITSROFBorder_antiHe", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/pT_sel8_antiHe", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/pT_MCsel8_antiHe", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/pT_MCsel8_antiHePrim", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); if (enableDebug) { debugHistos.add("qa/h1VtxZ_nocut", "V_{z};V_{z} (in cm); counts", HistType::kTH1F, {{1500, -15, 15}}); @@ -227,9 +319,17 @@ struct LFNucleiBATask { } } + histos.add("event/eventSkimming", "eventSkimming", HistType::kTH1D, {{2, 0.0, 2.0}}); + auto hSkim = histos.get(HIST("event/eventSkimming")); + hSkim->GetXaxis()->SetBinLabel(1, "Total"); + hSkim->GetXaxis()->SetBinLabel(2, "Skimmed events"); + histos.add("event/eventSelection", "eventSelection", HistType::kTH1D, {{7, -0.5, 6.5}}); auto h = histos.get(HIST("event/eventSelection")); - h->GetXaxis()->SetBinLabel(1, "Total"); + if (skimmingOptions.applySkimming) + h->GetXaxis()->SetBinLabel(1, "Skimmed events"); + else + h->GetXaxis()->SetBinLabel(1, "Total"); h->GetXaxis()->SetBinLabel(2, "TVX trigger cut"); h->GetXaxis()->SetBinLabel(3, "TF border cut"); h->GetXaxis()->SetBinLabel(4, "ITS ROF cut"); @@ -238,8 +338,10 @@ struct LFNucleiBATask { h->GetXaxis()->SetBinLabel(7, "Z-vert Cut"); histos.add("event/h1VtxZ", "V_{z};V_{z} (in cm); counts", HistType::kTH1F, {{1500, -15, 15}}); - histos.add("tracks/h1pT", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{500, 0., 10.}}); - histos.add("tracks/h1p", "Track momentum; p (GeV/#it{c}); counts", HistType::kTH1F, {{500, 0., 10.}}); + if (enablePIDplot) { + histos.add("tracks/h1pT", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{500, 0., 10.}}); + histos.add("tracks/h1p", "Track momentum; p (GeV/#it{c}); counts", HistType::kTH1F, {{500, 0., 10.}}); + } histos.add("qa/h1ITSncr", "number of crossed rows in ITS; ITSncr; counts", HistType::kTH1F, {{12, 0, 12}}); histos.add("qa/h1TPCncr", "number of crossed rows in TPC; TPCncr; counts", HistType::kTH1F, {{150, 60, 170}}); @@ -249,48 +351,48 @@ struct LFNucleiBATask { histos.add("qa/h1chi2TPC", "#chi^{2}_{TPC}/n_{TPC}; #chi^{2}_{TPC}/n_{TPC}; counts", HistType::kTH1F, {{11, -0.5, 10.5}}); if (enablePtSpectra) { - histos.add("tracks/eff/h2pVsTPCmomentum", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - if (doTOFplots) - histos.add("tracks/eff/h2TPCmomentumVsTOFExpMomentum", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); + histos.add("tracks/eff/h2pVsTPCmomentum", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + if (outFlagOptions.doTOFplots) + histos.add("tracks/eff/h2TPCmomentumVsTOFExpMomentum", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); if (enablePr) { - histos.add("tracks/eff/proton/h2pVsTPCmomentumPr", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - histos.add("tracks/eff/proton/h2pVsTPCmomentumantiPr", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - if (doTOFplots) { - histos.add("tracks/eff/proton/h2pVsTOFExpMomentumPr", "#it{p}_{TOF} vs #it{p}; #it{p}_{TOF}; #it{p}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - histos.add("tracks/eff/proton/h2pVsTOFExpMomentumantiPr", "#it{p}_{TOF} vs #it{p}; #it{p}_{TOF}; #it{p}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - histos.add("tracks/eff/proton/h2TPCmomentumVsTOFExpMomentumPr", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - histos.add("tracks/eff/proton/h2TPCmomentumVsTOFExpMomentumantiPr", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); + histos.add("tracks/eff/proton/h2pVsTPCmomentumPr", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + histos.add("tracks/eff/proton/h2pVsTPCmomentumantiPr", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + if (outFlagOptions.doTOFplots) { + histos.add("tracks/eff/proton/h2pVsTOFExpMomentumPr", "#it{p}_{TOF} vs #it{p}; #it{p}_{TOF}; #it{p}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + histos.add("tracks/eff/proton/h2pVsTOFExpMomentumantiPr", "#it{p}_{TOF} vs #it{p}; #it{p}_{TOF}; #it{p}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + histos.add("tracks/eff/proton/h2TPCmomentumVsTOFExpMomentumPr", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + histos.add("tracks/eff/proton/h2TPCmomentumVsTOFExpMomentumantiPr", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); } } if (enableDe) { - histos.add("tracks/eff/deuteron/h2pVsTPCmomentumDe", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - histos.add("tracks/eff/deuteron/h2pVsTPCmomentumantiDe", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - if (doTOFplots) { - histos.add("tracks/eff/deuteron/h2pVsTOFExpMomentumDe", "#it{p}_{TOF} vs #it{p}; #it{p}_{TOF}; #it{p}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - histos.add("tracks/eff/deuteron/h2pVsTOFExpMomentumantiDe", "#it{p}_{TOF} vs #it{p}; #it{p}_{TOF}; #it{p}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - histos.add("tracks/eff/deuteron/h2TPCmomentumVsTOFExpMomentumDe", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - histos.add("tracks/eff/deuteron/h2TPCmomentumVsTOFExpMomentumantiDe", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); + histos.add("tracks/eff/deuteron/h2pVsTPCmomentumDe", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + histos.add("tracks/eff/deuteron/h2pVsTPCmomentumantiDe", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + if (outFlagOptions.doTOFplots) { + histos.add("tracks/eff/deuteron/h2pVsTOFExpMomentumDe", "#it{p}_{TOF} vs #it{p}; #it{p}_{TOF}; #it{p}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + histos.add("tracks/eff/deuteron/h2pVsTOFExpMomentumantiDe", "#it{p}_{TOF} vs #it{p}; #it{p}_{TOF}; #it{p}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + histos.add("tracks/eff/deuteron/h2TPCmomentumVsTOFExpMomentumDe", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + histos.add("tracks/eff/deuteron/h2TPCmomentumVsTOFExpMomentumantiDe", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); } } if (enableTr) { - histos.add("tracks/eff/triton/h2pVsTPCmomentumTr", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - histos.add("tracks/eff/triton/h2pVsTPCmomentumantiTr", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - if (doTOFplots) { - histos.add("tracks/eff/triton/h2pVsTOFExpMomentumTr", "#it{p}_{TOF} vs #it{p}; #it{p}_{TOF}; #it{p}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - histos.add("tracks/eff/triton/h2pVsTOFExpMomentumantiTr", "#it{p}_{TOF} vs #it{p}; #it{p}_{TOF}; #it{p}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - histos.add("tracks/eff/triton/h2TPCmomentumVsTOFExpMomentumTr", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - histos.add("tracks/eff/triton/h2TPCmomentumVsTOFExpMomentumantiTr", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); + histos.add("tracks/eff/triton/h2pVsTPCmomentumTr", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + histos.add("tracks/eff/triton/h2pVsTPCmomentumantiTr", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + if (outFlagOptions.doTOFplots) { + histos.add("tracks/eff/triton/h2pVsTOFExpMomentumTr", "#it{p}_{TOF} vs #it{p}; #it{p}_{TOF}; #it{p}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + histos.add("tracks/eff/triton/h2pVsTOFExpMomentumantiTr", "#it{p}_{TOF} vs #it{p}; #it{p}_{TOF}; #it{p}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + histos.add("tracks/eff/triton/h2TPCmomentumVsTOFExpMomentumTr", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + histos.add("tracks/eff/triton/h2TPCmomentumVsTOFExpMomentumantiTr", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); } } if (enableHe) { - histos.add("tracks/eff/helium/h2pVsTPCmomentumHe", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - histos.add("tracks/eff/helium/h2pVsTPCmomentumantiHe", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - if (doTOFplots) { - histos.add("tracks/eff/helium/h2pVsTOFExpMomentumHe", "#it{p}_{TOF} vs #it{p}; #it{p}_{TOF}; #it{p}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - histos.add("tracks/eff/helium/h2pVsTOFExpMomentumantiHe", "#it{p}_{TOF} vs #it{p}; #it{p}_{TOF}; #it{p}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - histos.add("tracks/eff/helium/h2TPCmomentumVsTOFExpMomentumHe", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); - histos.add("tracks/eff/helium/h2TPCmomentumVsTOFExpMomentumantiHe", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{800, 0.f, 8.f}, {800, 0.f, 8.f}}); + histos.add("tracks/eff/helium/h2pVsTPCmomentumHe", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + histos.add("tracks/eff/helium/h2pVsTPCmomentumantiHe", "#it{p}_{TPC} vs #it{p}; #it{p}_{TPC}; #it{p}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + if (outFlagOptions.doTOFplots) { + histos.add("tracks/eff/helium/h2pVsTOFExpMomentumHe", "#it{p}_{TOF} vs #it{p}; #it{p}_{TOF}; #it{p}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + histos.add("tracks/eff/helium/h2pVsTOFExpMomentumantiHe", "#it{p}_{TOF} vs #it{p}; #it{p}_{TOF}; #it{p}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + histos.add("tracks/eff/helium/h2TPCmomentumVsTOFExpMomentumHe", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); + histos.add("tracks/eff/helium/h2TPCmomentumVsTOFExpMomentumantiHe", "#it{p}_{TOF} vs #it{p}_{TPC}; #it{p}_{TOF}; #it{p}_{TPC}", HistType::kTH2F, {{200, 0.f, 8.f}, {200, 0.f, 8.f}}); } } } @@ -298,9 +400,10 @@ struct LFNucleiBATask { if (enableDebug) { debugHistos.add("debug/event/h1CentV0M", "V0M; Multiplicity; counts", HistType::kTH1F, {{27000, 0, 27000}}); // trackQA - debugHistos.add("debug/tracks/h1Eta", "pseudoRapidity; #eta; counts", HistType::kTH1F, {{200, -1.0, 1.0}}); + debugHistos.add("debug/tracks/h1Eta", "pseudoRapidity; #eta; counts", HistType::kTH1F, {{200, -2.0, 2.0}}); debugHistos.add("debug/tracks/h1VarPhi", "#phi; #phi; counts", HistType::kTH1F, {{63, 0.0, 6.3}}); - debugHistos.add("debug/tracks/h2EtaVsPhi", "#eta vs #phi; #eta; #phi", HistType::kTH2F, {{200, -1.0, 1.0}, {63, 0.0, 6.3}}); + debugHistos.add("debug/tracks/h2EtaVsPhi", "#eta vs #phi; #eta; #phi", HistType::kTH2F, {{200, -2.0, 2.0}, {63, 0.0, 6.3}}); + debugHistos.add("debug/tracks/h2PionYvsPt", "#it{y} vs #it{p}_{T} (#pi)", HistType::kTH2F, {{200, -2.0, 2.0}, {ptAxis}}); } if (enablePtSpectra) { @@ -310,7 +413,7 @@ struct LFNucleiBATask { debugHistos.add("tracks/eff/hPtPrebinned", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{50, 0., 5.}}); debugHistos.add("tracks/eff/hPtantiPrebinned", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{50, 0., 5.}}); - if (doTOFplots) { + if (outFlagOptions.doTOFplots) { debugHistos.add("tracks/eff/hPtPTOF", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); debugHistos.add("tracks/eff/hPtantiPTOF", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); debugHistos.add("tracks/eff/hPtPTOFrebinned", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{50, 0., 5.}}); @@ -341,28 +444,33 @@ struct LFNucleiBATask { histos.add("tracks/eff/triton/hPtantiTrTOF", "Track #it{p}_{T} (#bar{t}); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); } if (enableHe) { - histos.add("tracks/eff/helium/hPtHe", "Track #it{p}_{T}/z (He); #it{p}_{T}/z (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); - histos.add("tracks/eff/helium/hPtantiHe", "Track #it{p}_{T}/z (#bar{He}); #it{p}_{T}/z (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); - histos.add("tracks/eff/helium/hPtHeTOF", "Track #it{p}_{T}/z (He); #it{p}_{T}/z (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); - histos.add("tracks/eff/helium/hPtantiHeTOF", "Track #it{p}_{T}/z (#bar{He}); #it{p}_{T}/z (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); + histos.add("tracks/eff/helium/hPtHe", "Track #it{p}_{T} (He); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); + histos.add("tracks/eff/helium/hPtantiHe", "Track #it{p}_{T} (#bar{He}); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); + histos.add("tracks/eff/helium/hPtHeTOF", "Track #it{p}_{T} (He); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); + histos.add("tracks/eff/helium/hPtantiHeTOF", "Track #it{p}_{T} (#bar{He}); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); } } // tracks // DCAxy,z - if (makeDCABeforeCutPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { + histos.add("tracks/dca/before/hDCAxyVsDCAzVsPt", "DCAxy vs DCAz vs Pt/z; DCAxy; DCAz", HistType::kTH3F, {{140, -0.7f, 0.7f}, {160, -0.8f, 0.8f}, {binsPtHe}}); + histos.add("tracks/dca/before/hDCAxyVsDCAz", "DCAxy vs DCAz (before cuts)", HistType::kTH2F, {{550, -1.1, 1.1}, {550, -1.1, 1.1}}); histos.add("tracks/dca/before/hDCAxy", "DCAxy", HistType::kTH1F, {dcaxyAxis}); histos.add("tracks/dca/before/hDCAz", "DCAz", HistType::kTH1F, {dcazAxis}); - // histos.add("tracks/dca/before/hDCAxyVsDCAz", "DCAxy vs DCAz", HistType::kTH2F, {{dcaxyAxis}, {dcazAxis}}); - histos.add("tracks/dca/before/hDCAxyVsPt", "DCAxy vs Pt", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/dca/before/hDCAzVsPt", "DCAz vs Pt", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/dca/before/hDCAxyVsPt", "DCAxy vs Pt", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/dca/before/hDCAzVsPt", "DCAz vs Pt", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); if (enablePr) { + // histos.add("tracks/proton/dca/before/hDCAxyVsDCAzVsPtProton", "DCAxy vs DCAz vs Pt/z (p)", HistType::kTH3F, {{140, -0.7f, 0.7f}, {160, -0.8f, 0.8f}, {binsPtHe}}); + // histos.add("tracks/proton/dca/before/hDCAxyVsDCAzVsPtantiProton", "DCAxy vs DCAz vs Pt/z (#bar{p})", HistType::kTH3F, {{140, -0.7f, 0.7f}, {160, -0.8f, 0.8f}, {binsPtHe}}); histos.add("tracks/proton/dca/before/hDCAxyVsPtProton", "DCAxy vs Pt (p)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/proton/dca/before/hDCAxyVsPtantiProton", "DCAxy vs Pt (#bar{p})", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/proton/dca/before/hDCAzVsPtProton", "DCAz vs Pt (p)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/proton/dca/before/hDCAzVsPtantiProton", "DCAz vs Pt (#bar{p})", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); } if (enableDe) { + // histos.add("tracks/deuteron/dca/before/hDCAxyVsDCAzVsPtDeuteron", "DCAxy vs DCAz vs Pt/z (d)", HistType::kTH3F, {{140, -0.7f, 0.7f}, {160, -0.8f, 0.8f}, {binsPtHe}}); + // histos.add("tracks/deuteron/dca/before/hDCAxyVsDCAzVsPtantiDeuteron", "DCAxy vs DCAz vs Pt/z (#bar{d})", HistType::kTH3F, {{140, -0.7f, 0.7f}, {160, -0.8f, 0.8f}, {binsPtHe}}); if (enableCentrality) { histos.add("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronVsMult", "DCAxy vs Pt (d)", HistType::kTH3F, {{ptAxis}, {dcaxyAxis}, {binsPercentile}}); histos.add("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronVsMult", "DCAxy vs Pt (#bar{d})", HistType::kTH3F, {{ptAxis}, {dcaxyAxis}, {binsPercentile}}); @@ -372,27 +480,45 @@ struct LFNucleiBATask { } histos.add("tracks/deuteron/dca/before/hDCAzVsPtDeuteron", "DCAz vs Pt (d)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteron", "DCAz vs Pt (#bar{d})", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronNoTOF", "DCAxy vs Pt (d)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronNoTOF", "DCAxy vs Pt (#bar{d})", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/hDCAzVsPtDeuteronNoTOF", "DCAz vs Pt (d)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteronNoTOF", "DCAz vs Pt (#bar{d})", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); } if (enableTr) { + // histos.add("tracks/triton/dca/before/hDCAxyVsDCAzVsPtTriton", "DCAxy vs DCAz vs Pt/z (t)", HistType::kTH3F, {{140, -0.7f, 0.7f}, {160, -0.8f, 0.8f}, {binsPtHe}}); + // histos.add("tracks/triton/dca/before/hDCAxyVsDCAzVsPtantiTriton", "DCAxy vs DCAz vs Pt/z (#bar{t})", HistType::kTH3F, {{140, -0.7f, 0.7f}, {160, -0.8f, 0.8f}, {binsPtHe}}); histos.add("tracks/triton/dca/before/hDCAxyVsPtTriton", "DCAxy vs Pt (t)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/triton/dca/before/hDCAxyVsPtantiTriton", "DCAxy vs Pt (#bar{t})", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/triton/dca/before/hDCAzVsPtTriton", "DCAz vs Pt (t)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/triton/dca/before/hDCAzVsPtantiTriton", "DCAz vs Pt (#bar{t})", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); } if (enableHe) { - histos.add("tracks/helium/dca/before/hDCAxyVsPtHelium", "DCAxy vs Pt (He)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/hDCAxyVsPtantiHelium", "DCAxy vs Pt (#bar{He})", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/hDCAzVsPtHelium", "DCAz vs Pt (He)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/hDCAzVsPtantiHelium", "DCAz vs Pt (#bar{He})", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - - if (doTOFplots) { - histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtHelium", "DCAxy vs Pt (He)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHelium", "DCAxy vs Pt (#bar{He})", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtHelium", "DCAz vs Pt (He)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtantiHelium", "DCAz vs Pt (#bar{He})", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/hDCAxyVsDCAzVsPtHelium", "DCAxy vs DCAz vs Pt/z (He); DCAxy; DCAz", HistType::kTH3F, {{140, -0.7f, 0.7f}, {160, -0.8f, 0.8f}, {binsPtZHe}}); + histos.add("tracks/helium/dca/before/hDCAxyVsDCAzVsPtantiHelium", "DCAxy vs DCAz vs Pt/z (#bar{He}); DCAxy; DCAz", HistType::kTH3F, {{140, -0.7f, 0.7f}, {160, -0.8f, 0.8f}, {binsPtZHe}}); + histos.add("tracks/helium/dca/before/hDCAxyVsPtHelium", "DCAxy vs Pt (He)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/hDCAxyVsPtantiHelium", "DCAxy vs Pt (#bar{He})", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/hDCAzVsPtHelium", "DCAz vs Pt (He)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/hDCAzVsPtantiHelium", "DCAz vs Pt (#bar{He})", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + + histos.add("tracks/helium/dca/before/hDCAxyVsPtHeliumNoTOF", "DCAxy vs Pt (He)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/hDCAxyVsPtantiHeliumNoTOF", "DCAxy vs Pt (#bar{He})", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/hDCAzVsPtHeliumNoTOF", "DCAz vs Pt (He)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/hDCAzVsPtantiHeliumNoTOF", "DCAz vs Pt (#bar{He})", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + + if (outFlagOptions.doTOFplots) { + histos.add("tracks/helium/dca/before/TOF/hDCAxyVsDCAzVsPtHelium", "DCAxy vs DCAz vs Pt/z (He) (w/TOF); DCAxy; DCAz", HistType::kTH3F, {{140, -0.7f, 0.7f}, {160, -0.8f, 0.8f}, {binsPtZHe}}); + histos.add("tracks/helium/dca/before/TOF/hDCAxyVsDCAzVsPtantiHelium", "DCAxy vs DCAz vs Pt/z (#bar{He}) (w/TOF); DCAxy; DCAz", HistType::kTH3F, {{140, -0.7f, 0.7f}, {160, -0.8f, 0.8f}, {binsPtZHe}}); + histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtHelium", "DCAxy vs Pt (He)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHelium", "DCAxy vs Pt (#bar{He})", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtHelium", "DCAz vs Pt (He)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtantiHelium", "DCAz vs Pt (#bar{He})", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); } } if (enableAl) { + // histos.add("tracks/alpha/dca/before/hDCAxyVsDCAzVsPtAlpha", "DCAxy vs DCAz vs Pt/z (#alpha)", HistType::kTH3F, {{140, -0.7f, 0.7f}, {160, -0.8f, 0.8f}, {binsPtZHe}}); + // histos.add("tracks/alpha/dca/before/hDCAxyVsDCAzVsPtantiAlpha", "DCAxy vs DCAz vs Pt/z (#bar{#alpha})", HistType::kTH3F, {{140, -0.7f, 0.7f}, {160, -0.8f, 0.8f}, {binsPtZHe}}); histos.add("tracks/alpha/dca/before/hDCAxyVsPtAlpha", "DCAxy vs Pt (#alpha)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/before/hDCAxyVsPtantiAlpha", "DCAxy vs Pt (#bar{#alpha})", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/before/hDCAzVsPtAlpha", "DCAz vs Pt (#alpha)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); @@ -400,45 +526,48 @@ struct LFNucleiBATask { } } - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.add("tracks/dca/after/hDCAxy", "DCAxy; DCAxy; counts", HistType::kTH1F, {{dcaxyAxis}}); histos.add("tracks/dca/after/hDCAz", "DCAz; DCAz; counts", HistType::kTH1F, {{dcazAxis}}); - // histos.add("tracks/dca/after/hDCAxyVsDCAz", "DCAxy vs DCAz; DCAxy (cm); DCAz (cm)", HistType::kTH2F, {{dcaxyAxis}, {dcazAxis}}); - histos.add("tracks/dca/after/hDCAxyVsPt", "DCAxy vs Pt", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/dca/after/hDCAzVsPt", "DCAz vs Pt", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/dca/after/hDCAxyVsPt", "DCAxy vs Pt", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/dca/after/hDCAzVsPt", "DCAz vs Pt", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); } - if (enablePr && makeDCAAfterCutPlots) { + if (enablePr && outFlagOptions.makeDCAAfterCutPlots) { histos.add("tracks/proton/dca/after/hDCAxyVsPtProton", "DCAxy vs Pt (p)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/proton/dca/after/hDCAxyVsPtantiProton", "DCAxy vs Pt (#bar{p})", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/proton/dca/after/hDCAzVsPtProton", "DCAz vs Pt (p)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/proton/dca/after/hDCAzVsPtantiProton", "DCAz vs Pt (#bar{p})", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); } - if (enableDe && makeDCAAfterCutPlots) { + if (enableDe && outFlagOptions.makeDCAAfterCutPlots) { histos.add("tracks/deuteron/dca/after/hDCAxyVsPtDeuteron", "DCAxy vs Pt (d)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/deuteron/dca/after/hDCAxyVsPtantiDeuteron", "DCAxy vs Pt (#bar{d})", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/deuteron/dca/after/hDCAzVsPtDeuteron", "DCAz vs Pt (d)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/deuteron/dca/after/hDCAzVsPtantiDeuteron", "DCAz vs Pt (#bar{d})", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); } - if (enableTr && makeDCAAfterCutPlots) { + if (enableTr && outFlagOptions.makeDCAAfterCutPlots) { histos.add("tracks/triton/dca/after/hDCAxyVsPtTriton", "DCAxy vs Pt (t)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/triton/dca/after/hDCAxyVsPtantiTriton", "DCAxy vs Pt (#bar{t})", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/triton/dca/after/hDCAzVsPtTriton", "DCAz vs Pt (t)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/triton/dca/after/hDCAzVsPtantiTriton", "DCAz vs Pt (#bar{t})", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); } - if (enableHe && makeDCAAfterCutPlots) { - histos.add("tracks/helium/dca/after/hDCAxyVsPtHelium", "DCAxy vs Pt (He)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/hDCAxyVsPtantiHelium", "DCAxy vs Pt (#bar{He})", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/hDCAzVsPtHelium", "DCAz vs Pt (He)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/after/hDCAzVsPtantiHelium", "DCAz vs Pt (#bar{He})", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - - if (doTOFplots) { - histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtHelium", "DCAxy vs Pt (He)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtantiHelium", "DCAxy vs Pt (#bar{He})", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtHelium", "DCAz vs Pt (He)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtantiHelium", "DCAz vs Pt (#bar{He})", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + if (enableHe && outFlagOptions.makeDCAAfterCutPlots) { + histos.add("tracks/helium/dca/after/hDCAxyVsDCAzVsPtHelium", "DCAxy vs DCAz vs Pt/z (He); DCAxy; DCAz", HistType::kTH3F, {{140, -0.7f, 0.7f}, {160, -0.8f, 0.8f}, {binsPtZHe}}); + histos.add("tracks/helium/dca/after/hDCAxyVsDCAzVsPtantiHelium", "DCAxy vs DCAz vs Pt/z (#bar{He}); DCAxy; DCAz", HistType::kTH3F, {{140, -0.7f, 0.7f}, {160, -0.8f, 0.8f}, {binsPtZHe}}); + histos.add("tracks/helium/dca/after/hDCAxyVsPtHelium", "DCAxy vs Pt (He)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/hDCAxyVsPtantiHelium", "DCAxy vs Pt (#bar{He})", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/hDCAzVsPtHelium", "DCAz vs Pt (He)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/hDCAzVsPtantiHelium", "DCAz vs Pt (#bar{He})", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + + if (outFlagOptions.doTOFplots) { + histos.add("tracks/helium/dca/after/TOF/hDCAxyVsDCAzVsPtHelium", "DCAxy vs DCAz vs Pt/z (He); DCAxy; DCAz", HistType::kTH3F, {{140, -0.7f, 0.7f}, {160, -0.8f, 0.8f}, {binsPtZHe}}); + histos.add("tracks/helium/dca/after/TOF/hDCAxyVsDCAzVsPtantiHelium", "DCAxy vs DCAz vs Pt/z (#bar{He}); DCAxy; DCAz", HistType::kTH3F, {{140, -0.7f, 0.7f}, {160, -0.8f, 0.8f}, {binsPtZHe}}); + histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtHelium", "DCAxy vs Pt (He)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtantiHelium", "DCAxy vs Pt (#bar{He})", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtHelium", "DCAz vs Pt (He)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtantiHelium", "DCAz vs Pt (#bar{He})", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); } } - if (enableAl && makeDCAAfterCutPlots) { + if (enableAl && outFlagOptions.makeDCAAfterCutPlots) { histos.add("tracks/alpha/dca/after/hDCAxyVsPtAlpha", "DCAxy vs Pt (#alpha)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/after/hDCAxyVsPtantiAlpha", "DCAxy vs Pt (#bar{#alpha})", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/after/hDCAzVsPtAlpha", "DCAz vs Pt (#alpha)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); @@ -706,14 +835,14 @@ struct LFNucleiBATask { histos.add("tracks/helium/h1antiHeliumSpectraTrueSec_Z2", "#it{p}_{T} (He)", HistType::kTH1F, {ptHeAxis}); histos.add("tracks/helium/h1antiHeliumSpectraTrueTransport_Z2", "#it{p}_{T} (He)", HistType::kTH1F, {ptHeAxis}); - if (doTOFplots) { + if (outFlagOptions.doTOFplots) { histos.add("tracks/helium/TOF/h1HeliumSpectraTruePrim_Z2", "#it{p}_{T} (He)", HistType::kTH1F, {ptHeAxis}); histos.add("tracks/helium/TOF/h1antiHeliumSpectraTruePrim_Z2", "#it{p}_{T} (He)", HistType::kTH1F, {ptHeAxis}); } if (enablePtSpectra) { histos.add("tracks/eff/helium/hPtHeTrue", "Track #it{p}_{T} (He); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); histos.add("tracks/eff/helium/hPtantiHeTrue", "Track #it{p}_{T} (#bar{He}); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); - if (doTOFplots) { + if (outFlagOptions.doTOFplots) { histos.add("tracks/eff/helium/hPtHeTOFTrue", "Track #it{p}_{T} (He); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); histos.add("tracks/eff/helium/hPtantiHeTOFTrue", "Track #it{p}_{T} (#bar{He}); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); } @@ -732,21 +861,53 @@ struct LFNucleiBATask { } // 2D-DCAxy if (enablePr) { - if (makeDCABeforeCutPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.add("tracks/proton/dca/before/hDCAxyVsPtProtonTrue", "DCAxy vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/proton/dca/before/hDCAxyVsPtProtonTruePrim", "DCAxy vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/proton/dca/before/hDCAxyVsPtProtonTrueSec", "DCAxy vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/proton/dca/before/hDCAxyVsPtProtonTrueMaterial", "DCAxy vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/proton/dca/before/hDCAxyVsPtProtonTrueTransport", "DCAxy vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/proton/dca/before/hDCAxyVsPtantiProtonTrue", "DCAxy vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/proton/dca/before/hDCAxyVsPtantiProtonTruePrim", "DCAxy vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/proton/dca/before/hDCAxyVsPtantiProtonTrueSec", "DCAxy vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/proton/dca/before/hDCAxyVsPtantiProtonTrueMaterial", "DCAxy vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/proton/dca/before/hDCAxyVsPtantiProtonTrueTransport", "DCAxy vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + if (outFlagOptions.doTOFplots) { + histos.add("tracks/proton/dca/before/TOF/hDCAxyVsPtProtonTrue", "DCAxy vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/proton/dca/before/TOF/hDCAxyVsPtProtonTruePrim", "DCAxy vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/proton/dca/before/TOF/hDCAxyVsPtProtonTrueSec", "DCAxy vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/proton/dca/before/TOF/hDCAxyVsPtProtonTrueMaterial", "DCAxy vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/proton/dca/before/TOF/hDCAxyVsPtProtonTrueTransport", "DCAxy vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/proton/dca/before/TOF/hDCAxyVsPtantiProtonTrue", "DCAxy vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/proton/dca/before/TOF/hDCAxyVsPtantiProtonTruePrim", "DCAxy vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/proton/dca/before/TOF/hDCAxyVsPtantiProtonTrueSec", "DCAxy vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/proton/dca/before/TOF/hDCAxyVsPtantiProtonTrueMaterial", "DCAxy vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/proton/dca/before/TOF/hDCAxyVsPtantiProtonTrueTransport", "DCAxy vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/proton/dca/before/TOF/hDCAzVsPtProtonTrue", "DCAz vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/proton/dca/before/TOF/hDCAzVsPtProtonTruePrim", "DCAz vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/proton/dca/before/TOF/hDCAzVsPtProtonTrueSec", "DCAz vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/proton/dca/before/TOF/hDCAzVsPtProtonTrueMaterial", "DCAz vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/proton/dca/before/TOF/hDCAzVsPtProtonTrueTransport", "DCAz vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/proton/dca/before/TOF/hDCAzVsPtantiProtonTrue", "DCAz vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/proton/dca/before/TOF/hDCAzVsPtantiProtonTruePrim", "DCAz vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/proton/dca/before/TOF/hDCAzVsPtantiProtonTrueSec", "DCAz vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/proton/dca/before/TOF/hDCAzVsPtantiProtonTrueMaterial", "DCAz vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/proton/dca/before/TOF/hDCAzVsPtantiProtonTrueTransport", "DCAz vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + } } - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.add("tracks/proton/dca/after/hDCAxyVsPtProtonTrue", "DCAxy vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/proton/dca/after/hDCAxyVsPtProtonTruePrim", "DCAxy vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); @@ -761,21 +922,94 @@ struct LFNucleiBATask { } } if (enableDe) { - if (makeDCABeforeCutPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.add("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronTrue", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronTruePrim", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronTrueSec", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronTrueMaterial", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronTrueTransport", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronTrue", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronTruePrim", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronTrueSec", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronTrueMaterial", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronTrueTransport", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + // Fake & wrong histos + if (outFlagOptions.makeFakeTracksPlots) { + histos.add("tracks/deuteron/dca/before/fake/hDCAxyVsPtDeuteronTrue", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/deuteron/dca/before/fake/hDCAxyVsPtDeuteronTruePrim", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/fake/hDCAxyVsPtDeuteronTrueSec", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/fake/hDCAxyVsPtDeuteronTrueTransport", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/deuteron/dca/before/fake/hDCAxyVsPtantiDeuteronTrue", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/deuteron/dca/before/fake/hDCAxyVsPtantiDeuteronTruePrim", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/fake/hDCAxyVsPtantiDeuteronTrueSec", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/fake/hDCAxyVsPtantiDeuteronTrueTransport", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + } + + if (outFlagOptions.doTOFplots) { + histos.add("tracks/deuteron/dca/before/TOF/hDCAxyVsPtDeuteronTrue", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/deuteron/dca/before/TOF/hDCAxyVsPtDeuteronTruePrim", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/TOF/hDCAxyVsPtDeuteronTrueSec", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/TOF/hDCAxyVsPtDeuteronTrueMaterial", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/TOF/hDCAxyVsPtDeuteronTrueTransport", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/deuteron/dca/before/TOF/hDCAxyVsPtantiDeuteronTrue", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/deuteron/dca/before/TOF/hDCAxyVsPtantiDeuteronTruePrim", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/TOF/hDCAxyVsPtantiDeuteronTrueSec", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/TOF/hDCAxyVsPtantiDeuteronTrueMaterial", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/TOF/hDCAxyVsPtantiDeuteronTrueTransport", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/deuteron/dca/before/TOF/hDCAzVsPtDeuteronTrue", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/deuteron/dca/before/TOF/hDCAzVsPtDeuteronTruePrim", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/deuteron/dca/before/TOF/hDCAzVsPtDeuteronTrueSec", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/deuteron/dca/before/TOF/hDCAzVsPtDeuteronTrueMaterial", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/deuteron/dca/before/TOF/hDCAzVsPtDeuteronTrueTransport", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/deuteron/dca/before/TOF/hDCAzVsPtantiDeuteronTrue", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/deuteron/dca/before/TOF/hDCAzVsPtantiDeuteronTruePrim", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/deuteron/dca/before/TOF/hDCAzVsPtantiDeuteronTrueSec", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/deuteron/dca/before/TOF/hDCAzVsPtantiDeuteronTrueMaterial", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/deuteron/dca/before/TOF/hDCAzVsPtantiDeuteronTrueTransport", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + if (outFlagOptions.makeFakeTracksPlots) { + histos.add("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtDeuteronTrue", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtDeuteronTruePrim", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtDeuteronTrueSec", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtDeuteronTrueTransport", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtantiDeuteronTrue", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtantiDeuteronTruePrim", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtantiDeuteronTrueSec", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtantiDeuteronTrueTransport", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/deuteron/dca/before/fake/TOF/hDCAzVsPtDeuteronTrue", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/deuteron/dca/before/fake/TOF/hDCAzVsPtDeuteronTruePrim", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/deuteron/dca/before/fake/TOF/hDCAzVsPtDeuteronTrueSec", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/deuteron/dca/before/fake/TOF/hDCAzVsPtDeuteronTrueTransport", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/deuteron/dca/before/fake/TOF/hDCAzVsPtantiDeuteronTrue", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/deuteron/dca/before/fake/TOF/hDCAzVsPtantiDeuteronTruePrim", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/deuteron/dca/before/fake/TOF/hDCAzVsPtantiDeuteronTrueSec", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/deuteron/dca/before/fake/TOF/hDCAzVsPtantiDeuteronTrueTransport", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + } + } } - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.add("tracks/deuteron/dca/after/hDCAxyVsPtDeuteronTrue", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/deuteron/dca/after/hDCAxyVsPtDeuteronTruePrim", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); @@ -792,21 +1026,53 @@ struct LFNucleiBATask { } } if (enableTr) { - if (makeDCABeforeCutPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.add("tracks/triton/dca/before/hDCAxyVsPtTritonTrue", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/triton/dca/before/hDCAxyVsPtTritonTruePrim", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/triton/dca/before/hDCAxyVsPtTritonTrueSec", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/triton/dca/before/hDCAxyVsPtTritonTrueMaterial", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/triton/dca/before/hDCAxyVsPtTritonTrueTransport", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/triton/dca/before/hDCAxyVsPtantiTritonTrue", "DCAxy vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/triton/dca/before/hDCAxyVsPtantiTritonTruePrim", "DCAxy vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/triton/dca/before/hDCAxyVsPtantiTritonTrueSec", "DCAxy vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); - histos.add("tracks/triton/dca/before/hDCAxyVsPtantiTritonTrueTransport", "DCAxy vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/triton/dca/before/hDCAxyVsPtTritonTrueMaterial", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/triton/dca/before/hDCAxyVsPtTritonTrueTransport", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + if (outFlagOptions.doTOFplots) { + histos.add("tracks/triton/dca/before/TOF/hDCAxyVsPtTritonTrue", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/triton/dca/before/TOF/hDCAxyVsPtTritonTruePrim", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/triton/dca/before/TOF/hDCAxyVsPtTritonTrueSec", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/triton/dca/before/TOF/hDCAxyVsPtTritonTrueMaterial", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/triton/dca/before/TOF/hDCAxyVsPtTritonTrueTransport", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/triton/dca/before/TOF/hDCAxyVsPtantiTritonTrue", "DCAxy vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/triton/dca/before/TOF/hDCAxyVsPtantiTritonTruePrim", "DCAxy vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/triton/dca/before/TOF/hDCAxyVsPtantiTritonTrueSec", "DCAxy vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/triton/dca/before/TOF/hDCAxyVsPtantiTritonTrueMaterial", "DCAxy vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/triton/dca/before/TOF/hDCAxyVsPtantiTritonTrueTransport", "DCAxy vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/triton/dca/before/TOF/hDCAzVsPtTritonTrue", "DCAz vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/triton/dca/before/TOF/hDCAzVsPtTritonTruePrim", "DCAz vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/triton/dca/before/TOF/hDCAzVsPtTritonTrueSec", "DCAz vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/triton/dca/before/TOF/hDCAzVsPtTritonTrueMaterial", "DCAz vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/triton/dca/before/TOF/hDCAzVsPtTritonTrueTransport", "DCAz vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/triton/dca/before/TOF/hDCAzVsPtantiTritonTrue", "DCAz vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/triton/dca/before/TOF/hDCAzVsPtantiTritonTruePrim", "DCAz vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/triton/dca/before/TOF/hDCAzVsPtantiTritonTrueSec", "DCAz vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/triton/dca/before/TOF/hDCAzVsPtantiTritonTrueMaterial", "DCAz vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/triton/dca/before/TOF/hDCAzVsPtantiTritonTrueTransport", "DCAz vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + } } - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.add("tracks/triton/dca/after/hDCAxyVsPtTritonTrue", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/triton/dca/after/hDCAxyVsPtTritonTruePrim", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); @@ -818,159 +1084,305 @@ struct LFNucleiBATask { histos.add("tracks/triton/dca/after/hDCAxyVsPtantiTritonTruePrim", "DCAxy vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/triton/dca/after/hDCAxyVsPtantiTritonTrueSec", "DCAxy vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/triton/dca/after/hDCAxyVsPtantiTritonTrueTransport", "DCAxy vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + if (outFlagOptions.doTOFplots) { + histos.add("tracks/triton/dca/after/TOF/hDCAxyVsPtTritonTrue", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/triton/dca/after/TOF/hDCAxyVsPtTritonTruePrim", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/triton/dca/after/TOF/hDCAxyVsPtTritonTrueSec", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/triton/dca/after/TOF/hDCAxyVsPtTritonTrueTransport", "DCAxy vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/triton/dca/after/TOF/hDCAxyVsPtantiTritonTrue", "DCAxy vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/triton/dca/after/TOF/hDCAxyVsPtantiTritonTruePrim", "DCAxy vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/triton/dca/after/TOF/hDCAxyVsPtantiTritonTrueSec", "DCAxy vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/triton/dca/after/TOF/hDCAxyVsPtantiTritonTrueTransport", "DCAxy vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + + histos.add("tracks/triton/dca/after/TOF/hDCAzVsPtTritonTrue", "DCAz vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/triton/dca/after/TOF/hDCAzVsPtTritonTruePrim", "DCAz vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/triton/dca/after/TOF/hDCAzVsPtTritonTrueSec", "DCAz vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/triton/dca/after/TOF/hDCAzVsPtTritonTrueTransport", "DCAz vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/triton/dca/after/TOF/hDCAzVsPtantiTritonTrue", "DCAz vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/triton/dca/after/TOF/hDCAzVsPtantiTritonTruePrim", "DCAz vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/triton/dca/after/TOF/hDCAzVsPtantiTritonTrueSec", "DCAz vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/triton/dca/after/TOF/hDCAzVsPtantiTritonTrueTransport", "DCAz vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + } } } if (enableHe) { // all tracks - if (makeDCABeforeCutPlots) { - histos.add("tracks/helium/dca/before/hDCAxyVsPtHeliumTrue", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); + if (outFlagOptions.makeDCABeforeCutPlots) { + histos.add("tracks/helium/dca/before/hDCAxyVsPtHeliumTrue", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/hDCAxyVsPtHeliumTruePrim", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/hDCAxyVsPtHeliumTrueSec", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/hDCAxyVsPtHeliumTrueMaterial", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/hDCAxyVsPtHeliumTrueTransport", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/hDCAxyVsPtantiHeliumTrue", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/hDCAxyVsPtantiHeliumTruePrim", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/hDCAxyVsPtantiHeliumTrueSec", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/hDCAxyVsPtantiHeliumTrueMaterial", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/hDCAxyVsPtantiHeliumTrueTransport", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/hDCAzVsPtHeliumTrue", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + + histos.add("tracks/helium/dca/before/hDCAzVsPtHeliumTruePrim", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/hDCAzVsPtHeliumTrueSec", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/hDCAzVsPtHeliumTrueMaterial", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/hDCAzVsPtHeliumTrueTransport", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + + histos.add("tracks/helium/dca/before/hDCAzVsPtantiHeliumTrue", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + + histos.add("tracks/helium/dca/before/hDCAzVsPtantiHeliumTruePrim", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/hDCAzVsPtantiHeliumTrueSec", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/hDCAzVsPtantiHeliumTrueMaterial", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/hDCAzVsPtantiHeliumTrueTransport", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + + if (outFlagOptions.doTOFplots) { + histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtHeliumTrue", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtHeliumTruePrim", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtHeliumTrueSec", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtHeliumTrueMaterial", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtHeliumTrueTransport", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHeliumTrue", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/hDCAxyVsPtHeliumTruePrim", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/hDCAxyVsPtHeliumTrueSec", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/hDCAxyVsPtHeliumTrueTransport", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHeliumTruePrim", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHeliumTrueSec", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHeliumTrueMaterial", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHeliumTrueTransport", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/hDCAxyVsPtantiHeliumTrue", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTrue", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/hDCAxyVsPtantiHeliumTruePrim", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/hDCAxyVsPtantiHeliumTrueSec", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/hDCAxyVsPtantiHeliumTrueTransport", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTruePrim", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTrueSec", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTrueMaterial", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTrueTransport", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/hDCAzVsPtHeliumTrue", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTrue", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/hDCAzVsPtHeliumTruePrim", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/hDCAzVsPtHeliumTrueSec", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/hDCAzVsPtHeliumTrueTransport", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTruePrim", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTrueSec", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTrueMaterial", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTrueTransport", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + } + + // Fake & wrong histos + if (outFlagOptions.makeFakeTracksPlots) { + histos.add("tracks/helium/dca/before/fake/hDCAxyVsPtHeliumTrue", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/fake/hDCAxyVsPtHeliumTruePrim", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/fake/hDCAxyVsPtHeliumTrueSec", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/fake/hDCAxyVsPtHeliumTrueTransport", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/fake/hDCAxyVsPtantiHeliumTrue", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/fake/hDCAxyVsPtantiHeliumTruePrim", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/fake/hDCAxyVsPtantiHeliumTrueSec", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/fake/hDCAxyVsPtantiHeliumTrueTransport", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/fake/hDCAzVsPtHeliumTrue", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + + histos.add("tracks/helium/dca/before/fake/hDCAzVsPtHeliumTruePrim", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/fake/hDCAzVsPtHeliumTrueSec", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/fake/hDCAzVsPtHeliumTrueTransport", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + + histos.add("tracks/helium/dca/before/fake/hDCAzVsPtantiHeliumTrue", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + + histos.add("tracks/helium/dca/before/fake/hDCAzVsPtantiHeliumTruePrim", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/fake/hDCAzVsPtantiHeliumTrueSec", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/fake/hDCAzVsPtantiHeliumTrueTransport", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + } + + if (outFlagOptions.makeWrongEventPlots) { + histos.add("tracks/helium/dca/before/wrong/hDCAxyVsPtHeliumTrue", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/wrong/hDCAxyVsPtHeliumTruePrim", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/wrong/hDCAxyVsPtHeliumTrueSec", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/wrong/hDCAxyVsPtHeliumTrueTransport", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/wrong/hDCAxyVsPtantiHeliumTrue", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/wrong/hDCAxyVsPtantiHeliumTruePrim", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/wrong/hDCAxyVsPtantiHeliumTrueSec", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/wrong/hDCAxyVsPtantiHeliumTrueTransport", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/wrong/hDCAzVsPtHeliumTrue", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + + histos.add("tracks/helium/dca/before/wrong/hDCAzVsPtHeliumTruePrim", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/wrong/hDCAzVsPtHeliumTrueSec", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/wrong/hDCAzVsPtHeliumTrueTransport", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/hDCAzVsPtantiHeliumTrue", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/wrong/hDCAzVsPtantiHeliumTrue", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/hDCAzVsPtantiHeliumTruePrim", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/hDCAzVsPtantiHeliumTrueSec", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/hDCAzVsPtantiHeliumTrueTransport", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/wrong/hDCAzVsPtantiHeliumTruePrim", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/wrong/hDCAzVsPtantiHeliumTrueSec", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/wrong/hDCAzVsPtantiHeliumTrueTransport", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + } + if (outFlagOptions.doTOFplots) { + if (outFlagOptions.makeFakeTracksPlots) { + histos.add("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtHeliumTrue", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtHeliumTruePrim", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtHeliumTrueSec", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtHeliumTrueTransport", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtantiHeliumTrue", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtantiHeliumTruePrim", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtantiHeliumTrueSec", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtantiHeliumTrueTransport", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + + histos.add("tracks/helium/dca/before/fake/TOF/hDCAzVsPtHeliumTrue", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + + histos.add("tracks/helium/dca/before/fake/TOF/hDCAzVsPtHeliumTruePrim", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/fake/TOF/hDCAzVsPtHeliumTrueSec", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/fake/TOF/hDCAzVsPtHeliumTrueTransport", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + + histos.add("tracks/helium/dca/before/fake/TOF/hDCAzVsPtantiHeliumTrue", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + + histos.add("tracks/helium/dca/before/fake/TOF/hDCAzVsPtantiHeliumTruePrim", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/fake/TOF/hDCAzVsPtantiHeliumTrueSec", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/fake/TOF/hDCAzVsPtantiHeliumTrueTransport", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + } - if (doTOFplots) { - histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtHeliumTrue", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); + if (outFlagOptions.makeWrongEventPlots) { + histos.add("tracks/helium/dca/before/wrong/TOF/hDCAxyVsPtHeliumTrue", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtHeliumTruePrim", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtHeliumTrueSec", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtHeliumTrueTransport", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/wrong/TOF/hDCAxyVsPtHeliumTruePrim", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/wrong/TOF/hDCAxyVsPtHeliumTrueSec", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/wrong/TOF/hDCAxyVsPtHeliumTrueTransport", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHeliumTrue", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/wrong/TOF/hDCAxyVsPtantiHeliumTrue", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHeliumTruePrim", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHeliumTrueSec", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHeliumTrueTransport", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/wrong/TOF/hDCAxyVsPtantiHeliumTruePrim", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/wrong/TOF/hDCAxyVsPtantiHeliumTrueSec", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/before/wrong/TOF/hDCAxyVsPtantiHeliumTrueTransport", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTrue", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/wrong/TOF/hDCAzVsPtHeliumTrue", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTruePrim", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTrueSec", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTrueTransport", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/wrong/TOF/hDCAzVsPtHeliumTruePrim", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/wrong/TOF/hDCAzVsPtHeliumTrueSec", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/wrong/TOF/hDCAzVsPtHeliumTrueTransport", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTrue", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/wrong/TOF/hDCAzVsPtantiHeliumTrue", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTruePrim", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTrueSec", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTrueTransport", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/wrong/TOF/hDCAzVsPtantiHeliumTruePrim", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/wrong/TOF/hDCAzVsPtantiHeliumTrueSec", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/before/wrong/TOF/hDCAzVsPtantiHeliumTrueTransport", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + } } } - if (makeDCAAfterCutPlots) { - histos.add("tracks/helium/dca/after/hDCAxyVsPtHeliumTrue", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); + if (outFlagOptions.makeDCAAfterCutPlots) { + histos.add("tracks/helium/dca/after/hDCAxyVsPtHeliumTrue", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/hDCAxyVsPtHeliumTruePrim", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/hDCAxyVsPtHeliumTrueSec", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/hDCAxyVsPtHeliumTrueTransport", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/hDCAxyVsPtHeliumTruePrim", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/hDCAxyVsPtHeliumTrueSec", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/hDCAxyVsPtHeliumTrueTransport", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/hDCAxyVsPtantiHeliumTrue", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/hDCAxyVsPtantiHeliumTrue", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/hDCAxyVsPtantiHeliumTruePrim", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/hDCAxyVsPtantiHeliumTrueSec", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/hDCAxyVsPtantiHeliumTrueTransport", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/hDCAxyVsPtantiHeliumTruePrim", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/hDCAxyVsPtantiHeliumTrueSec", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/hDCAxyVsPtantiHeliumTrueTransport", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/hDCAzVsPtHeliumTrue", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/hDCAzVsPtHeliumTrue", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); - histos.add("tracks/helium/dca/after/hDCAzVsPtHeliumTruePrim", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/after/hDCAzVsPtHeliumTrueSec", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/after/hDCAzVsPtHeliumTrueTransport", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/hDCAzVsPtHeliumTruePrim", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/hDCAzVsPtHeliumTrueSec", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/hDCAzVsPtHeliumTrueTransport", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); - histos.add("tracks/helium/dca/after/hDCAzVsPtantiHeliumTrue", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/hDCAzVsPtantiHeliumTrue", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); - histos.add("tracks/helium/dca/after/hDCAzVsPtantiHeliumTruePrim", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/after/hDCAzVsPtantiHeliumTrueSec", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/after/hDCAzVsPtantiHeliumTrueTransport", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/hDCAzVsPtantiHeliumTruePrim", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/hDCAzVsPtantiHeliumTrueSec", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/hDCAzVsPtantiHeliumTrueTransport", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); - if (doTOFplots) { - histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtHeliumTrue", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); + if (outFlagOptions.doTOFplots) { + histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtHeliumTrue", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtHeliumTruePrim", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtHeliumTrueSec", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtHeliumTrueTransport", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtHeliumTruePrim", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtHeliumTrueSec", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtHeliumTrueTransport", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtantiHeliumTrue", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtantiHeliumTrue", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtantiHeliumTruePrim", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtantiHeliumTrueSec", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtantiHeliumTrueTransport", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtantiHeliumTruePrim", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtantiHeliumTrueSec", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAxyVsPtantiHeliumTrueTransport", "DCAxy vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtHeliumTrue", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtHeliumTrue", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtHeliumTruePrim", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtHeliumTrueSec", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtHeliumTrueTransport", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtHeliumTruePrim", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtHeliumTrueSec", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtHeliumTrueTransport", "DCAz vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtantiHeliumTrue", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtantiHeliumTrue", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtantiHeliumTruePrim", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtantiHeliumTrueSec", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); - histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtantiHeliumTrueTransport", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{900, 0.5f, 5.f}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtantiHeliumTruePrim", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtantiHeliumTrueSec", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); + histos.add("tracks/helium/dca/after/TOF/hDCAzVsPtantiHeliumTrueTransport", "DCAz vs Pt (#bar{He}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcazAxis}}); } } } if (enableAl) { - if (makeDCABeforeCutPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.add("tracks/alpha/dca/before/hDCAxyVsPtAlphaTrue", "DCAxy vs Pt (#alpha); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/before/hDCAxyVsPtAlphaTruePrim", "DCAxy vs Pt (#alpha); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/before/hDCAxyVsPtAlphaTrueSec", "DCAxy vs Pt (#alpha); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/alpha/dca/before/hDCAxyVsPtAlphaTrueMaterial", "DCAxy vs Pt (#alpha); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/before/hDCAxyVsPtAlphaTrueTransport", "DCAxy vs Pt (#alpha); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/before/hDCAxyVsPtantiAlphaTrue", "DCAxy vs Pt (#bar{#alpha}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/before/hDCAxyVsPtantiAlphaTruePrim", "DCAxy vs Pt (#bar{#alpha}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/before/hDCAxyVsPtantiAlphaTrueSec", "DCAxy vs Pt (#bar{#alpha}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/alpha/dca/before/hDCAxyVsPtantiAlphaTrueMaterial", "DCAxy vs Pt (#bar{#alpha}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/before/hDCAxyVsPtantiAlphaTrueTransport", "DCAxy vs Pt (#bar{#alpha}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); } - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.add("tracks/alpha/dca/after/hDCAxyVsPtAlphaTrue", "DCAxy vs Pt (#alpha); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/after/hDCAxyVsPtAlphaTruePrim", "DCAxy vs Pt (#alpha); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/after/hDCAxyVsPtAlphaTrueSec", "DCAxy vs Pt (#alpha); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/alpha/dca/after/hDCAxyVsPtAlphaTrueMaterial", "DCAxy vs Pt (#alpha); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/after/hDCAxyVsPtAlphaTrueTransport", "DCAxy vs Pt (#alpha); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/after/hDCAxyVsPtantiAlphaTrue", "DCAxy vs Pt (#bar{#alpha}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/after/hDCAxyVsPtantiAlphaTruePrim", "DCAxy vs Pt (#bar{#alpha}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/after/hDCAxyVsPtantiAlphaTrueSec", "DCAxy vs Pt (#bar{#alpha}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/alpha/dca/after/hDCAxyVsPtantiAlphaTrueMaterial", "DCAxy vs Pt (#bar{#alpha}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); histos.add("tracks/alpha/dca/after/hDCAxyVsPtantiAlphaTrueTransport", "DCAxy vs Pt (#bar{#alpha}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); } } // 2D-DCAz if (enablePr) { - if (makeDCABeforeCutPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.add("tracks/proton/dca/before/hDCAzVsPtProtonTrue", "DCAz vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/proton/dca/before/hDCAzVsPtProtonTruePrim", "DCAz vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/proton/dca/before/hDCAzVsPtProtonTrueSec", "DCAz vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/proton/dca/before/hDCAzVsPtProtonTrueMaterial", "DCAz vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/proton/dca/before/hDCAzVsPtProtonTrueTransport", "DCAz vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/proton/dca/before/hDCAzVsPtantiProtonTrue", "DCAz vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/proton/dca/before/hDCAzVsPtantiProtonTruePrim", "DCAz vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/proton/dca/before/hDCAzVsPtantiProtonTrueSec", "DCAz vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/proton/dca/before/hDCAzVsPtantiProtonTrueMaterial", "DCAz vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/proton/dca/before/hDCAzVsPtantiProtonTrueTransport", "DCAz vs Pt (#bar{p}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); } - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.add("tracks/proton/dca/after/hDCAzVsPtProtonTrue", "DCAz vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/proton/dca/after/hDCAzVsPtProtonTruePrim", "DCAz vs Pt (p); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); @@ -985,21 +1397,37 @@ struct LFNucleiBATask { } } if (enableDe) { - if (makeDCABeforeCutPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.add("tracks/deuteron/dca/before/hDCAzVsPtDeuteronTrue", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/deuteron/dca/before/hDCAzVsPtDeuteronTruePrim", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/deuteron/dca/before/hDCAzVsPtDeuteronTrueSec", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/deuteron/dca/before/hDCAzVsPtDeuteronTrueMaterial", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/deuteron/dca/before/hDCAzVsPtDeuteronTrueTransport", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteronTrue", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteronTruePrim", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteronTrueSec", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteronTrueMaterial", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteronTrueTransport", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + if (outFlagOptions.makeFakeTracksPlots) { + histos.add("tracks/deuteron/dca/before/fake/hDCAzVsPtDeuteronTrue", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/deuteron/dca/before/fake/hDCAzVsPtDeuteronTruePrim", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/deuteron/dca/before/fake/hDCAzVsPtDeuteronTrueSec", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/deuteron/dca/before/fake/hDCAzVsPtDeuteronTrueTransport", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/deuteron/dca/before/fake/hDCAzVsPtantiDeuteronTrue", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + + histos.add("tracks/deuteron/dca/before/fake/hDCAzVsPtantiDeuteronTruePrim", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/deuteron/dca/before/fake/hDCAzVsPtantiDeuteronTrueSec", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/deuteron/dca/before/fake/hDCAzVsPtantiDeuteronTrueTransport", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + } } - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.add("tracks/deuteron/dca/after/hDCAzVsPtDeuteronTrue", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/deuteron/dca/after/hDCAzVsPtDeuteronTruePrim", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); @@ -1016,21 +1444,23 @@ struct LFNucleiBATask { } } if (enableTr) { - if (makeDCABeforeCutPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.add("tracks/triton/dca/before/hDCAzVsPtTritonTrue", "DCAz vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/triton/dca/before/hDCAzVsPtTritonTruePrim", "DCAz vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/triton/dca/before/hDCAzVsPtTritonTrueSec", "DCAz vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/triton/dca/before/hDCAzVsPtTritonTrueMaterial", "DCAz vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/triton/dca/before/hDCAzVsPtTritonTrueTransport", "DCAz vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/triton/dca/before/hDCAzVsPtantiTritonTrue", "DCAz vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/triton/dca/before/hDCAzVsPtantiTritonTruePrim", "DCAz vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/triton/dca/before/hDCAzVsPtantiTritonTrueSec", "DCAz vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/triton/dca/before/hDCAzVsPtantiTritonTrueMaterial", "DCAz vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/triton/dca/before/hDCAzVsPtantiTritonTrueTransport", "DCAz vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); } - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.add("tracks/triton/dca/after/hDCAzVsPtTritonTrue", "DCAz vs Pt (#bar{t}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/triton/dca/after/hDCAzVsPtTritonTruePrim", "DCAz vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); @@ -1046,21 +1476,23 @@ struct LFNucleiBATask { } if (enableAl) { - if (makeDCABeforeCutPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.add("tracks/alpha/dca/before/hDCAzVsPtAlphaTrue", "DCAz vs Pt (#alpha); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/alpha/dca/before/hDCAzVsPtAlphaTruePrim", "DCAz vs Pt (#alpha); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/alpha/dca/before/hDCAzVsPtAlphaTrueSec", "DCAz vs Pt (#alpha); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/alpha/dca/before/hDCAzVsPtAlphaTrueMaterial", "DCAz vs Pt (#alpha); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/alpha/dca/before/hDCAzVsPtAlphaTrueTransport", "DCAz vs Pt (#alpha); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/alpha/dca/before/hDCAzVsPtantiAlphaTrue", "DCAz vs Pt (#bar{#alpha}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/alpha/dca/before/hDCAzVsPtantiAlphaTruePrim", "DCAz vs Pt (#bar{#alpha}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/alpha/dca/before/hDCAzVsPtantiAlphaTrueSec", "DCAz vs Pt (#bar{#alpha}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + histos.add("tracks/alpha/dca/before/hDCAzVsPtantiAlphaTrueMaterial", "DCAz vs Pt (#bar{#alpha}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/alpha/dca/before/hDCAzVsPtantiAlphaTrueTransport", "DCAz vs Pt (#bar{#alpha}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); } - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.add("tracks/alpha/dca/after/hDCAzVsPtAlphaTrue", "DCAz vs Pt (#alpha); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); histos.add("tracks/alpha/dca/after/hDCAzVsPtAlphaTruePrim", "DCAz vs Pt (#alpha); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); @@ -1077,42 +1509,53 @@ struct LFNucleiBATask { } // Bethe-Bloch TPC distribution and Beta vs pT TOF distribution - histos.add("tracks/h2TPCsignVsTPCmomentum", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{500, -5.f, 5.f}, {dedxAxis}}); + if (nsigmaITSvar.showAverageClusterSize && enablePIDplot) { + histos.add("tracks/averageClusterSize", "", HistType::kTH2F, {{pZAxis}, {avClsAxis}}); + histos.add("tracks/averageClusterSizePerCoslInv", "", HistType::kTH2F, {{pZAxis}, {avClsEffAxis}}); + } if (enableDebug) { - debugHistos.add("debug/h2TPCsignVsTPCmomentum_AllTracks", "TPC <-dE/dX> vs #it{p}/Z (w/o rejection); Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{500, -5.f, 5.f}, {dedxAxis}}); - debugHistos.add("debug/h2TPCsignVsTPCmomentum_FakeHits", "TPC <-dE/dX> vs #it{p}/Z (Fake hits); Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{500, -5.f, 5.f}, {dedxAxis}}); + debugHistos.add("debug/h2TPCsignVsTPCmomentum_AllTracks", "TPC <-dE/dX> vs #it{p}/Z (w/o rejection); Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{400, -8.f, 8.f}, {dedxAxis}}); + debugHistos.add("debug/h2TPCsignVsTPCmomentum_FakeHits", "TPC <-dE/dX> vs #it{p}/Z (Fake hits); Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{400, -8.f, 8.f}, {dedxAxis}}); } if (enablePIDplot) { + histos.add("tracks/h2TPCsignVsTPCmomentum", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{400, -8.f, 8.f}, {dedxAxis}}); if (enablePr) { - histos.add("tracks/proton/h2TPCsignVsTPCmomentumProton", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{250, 0.f, 5.f}, {dedxAxis}}); - histos.add("tracks/proton/h2TPCsignVsTPCmomentumantiProton", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{250, 0.f, 5.f}, {dedxAxis}}); + histos.add("tracks/proton/h2TPCsignVsTPCmomentumProton", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{400, 0.f, 8.f}, {dedxAxis}}); + histos.add("tracks/proton/h2TPCsignVsTPCmomentumantiProton", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{400, 0.f, 8.f}, {dedxAxis}}); } if (enableDe) { - histos.add("tracks/deuteron/h2TPCsignVsTPCmomentumDeuteron", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{250, 0.f, 5.f}, {dedxAxis}}); - histos.add("tracks/deuteron/h2TPCsignVsTPCmomentumantiDeuteron", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{250, 0.f, 5.f}, {dedxAxis}}); + histos.add("tracks/deuteron/h2TPCsignVsTPCmomentumDeuteron", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{400, 0.f, 8.f}, {dedxAxis}}); + histos.add("tracks/deuteron/h2TPCsignVsTPCmomentumantiDeuteron", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{400, 0.f, 8.f}, {dedxAxis}}); } if (enableTr) { - histos.add("tracks/triton/h2TPCsignVsTPCmomentumTriton", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{250, 0.f, 5.f}, {dedxAxis}}); - histos.add("tracks/triton/h2TPCsignVsTPCmomentumantiTriton", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{250, 0.f, 5.f}, {dedxAxis}}); + histos.add("tracks/triton/h2TPCsignVsTPCmomentumTriton", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{400, 0.f, 8.f}, {dedxAxis}}); + histos.add("tracks/triton/h2TPCsignVsTPCmomentumantiTriton", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{400, 0.f, 8.f}, {dedxAxis}}); } if (enableHe) { - histos.add("tracks/helium/h2TPCsignVsTPCmomentumHelium", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{250, 0.f, 5.f}, {dedxAxis}}); - histos.add("tracks/helium/h2TPCsignVsTPCmomentumantiHelium", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{250, 0.f, 5.f}, {dedxAxis}}); + histos.add("tracks/helium/h2TPCsignVsTPCmomentumHelium", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{400, 0.f, 8.f}, {dedxAxis}}); + histos.add("tracks/helium/h2TPCsignVsTPCmomentumantiHelium", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{400, 0.f, 8.f}, {dedxAxis}}); } if (enableAl) { - histos.add("tracks/alpha/h2TPCsignVsTPCmomentumAlpha", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{250, 0.f, 5.f}, {dedxAxis}}); - histos.add("tracks/alpha/h2TPCsignVsTPCmomentumantiAlpha", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{250, 0.f, 5.f}, {dedxAxis}}); + histos.add("tracks/alpha/h2TPCsignVsTPCmomentumAlpha", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{400, 0.f, 8.f}, {dedxAxis}}); + histos.add("tracks/alpha/h2TPCsignVsTPCmomentumantiAlpha", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{400, 0.f, 8.f}, {dedxAxis}}); } } - if (doTOFplots) { - histos.add("tracks/h2TPCsignVsBetaGamma", "TPC <-dE/dX> vs #beta#gamma/Z; Signed #beta#gamma; TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{600, -6.f, 6.f}, {dedxAxis}}); - histos.add("tracks/h2TOFbetaVsP", "TOF #beta vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TOF #beta", HistType::kTH2F, {{500, -5.f, 5.f}, {betaAxis}}); - if (enableBetaCut) - histos.add("tracks/h2TOFbetaVsP_BetaCut", "TOF #beta vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TOF #beta", HistType::kTH2F, {{500, -5.f, 5.f}, {betaAxis}}); + if (enableHe) { + if (nsigmaITSvar.showAverageClusterSize) { + histos.add("tracks/helium/averageClusterSize", "", HistType::kTH2F, {{pZAxis}, {avClsAxis}}); + histos.add("tracks/helium/averageClusterSizePerCoslInv", "", HistType::kTH2F, {{pZAxis}, {avClsEffAxis}}); + } + } + + if (outFlagOptions.doTOFplots && enablePIDplot) { + histos.add("tracks/h2TPCsignVsBetaGamma", "TPC <-dE/dX> vs #beta#gamma/Z; Signed #beta#gamma; TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{250, -5.f, 5.f}, {dedxAxis}}); + histos.add("tracks/h2TOFbetaVsP", "TOF #beta vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TOF #beta", HistType::kTH2F, {{250, -5.f, 5.f}, {betaAxis}}); + if (outFlagOptions.enableBetaCut) + histos.add("tracks/h2TOFbetaVsP_BetaCut", "TOF #beta vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TOF #beta", HistType::kTH2F, {{250, -5.f, 5.f}, {betaAxis}}); } - if (enableExpSignalTPC) { + if (outFlagOptions.enableExpSignalTPC) { // TPCExpSignal histograms if (enablePr) { histos.add("tracks/proton/h2ProtonTPCExpSignalDiffVsPt", "TPC <-dE/dX> - Exp <-dE/dX> (p) vs #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); TPC <-dE/dX> ExpDiff (p)", HistType::kTH2F, {{ptAxis}, {16000, -800, 800.}}); @@ -1130,40 +1573,55 @@ struct LFNucleiBATask { // NSigmasTPC histograms if (enableDebug) { - debugHistos.add("debug/tracks/pion/h2PionVspTNSigmaTPC", "NSigmaTPC(pi) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - debugHistos.add("debug/tracks/kaon/h2KaonVspTNSigmaTPC", "NSigmaTPC(Ka) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); + debugHistos.add("debug/tracks/pion/h2PionVspTNSigmaTPC", "NSigmaTPC(pi) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + debugHistos.add("debug/tracks/kaon/h2KaonVspTNSigmaTPC", "NSigmaTPC(Ka) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); } if (enablePr) { - histos.add("tracks/proton/h2ProtonVspTNSigmaTPC", "NSigmaTPC(p) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - histos.add("tracks/proton/h2antiProtonVspTNSigmaTPC", "NSigmaTPC(#bar{p}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); + histos.add("tracks/proton/h2ProtonVspTNSigmaTPC", "NSigmaTPC(p) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + histos.add("tracks/proton/h2antiProtonVspTNSigmaTPC", "NSigmaTPC(#bar{p}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); } if (enableDe) { if (enableCentrality) { - histos.add("tracks/deuteron/h3DeuteronVspTNSigmaTPCVsMult", "NSigmaTPC(d) vs pT; #it{p}_{T} (GeV/#it{c}) vs mult; NSigmaTPC", HistType::kTH3F, {{ptAxis}, {SigmaTPCAxis}, {binsPercentile}}); - histos.add("tracks/deuteron/h3antiDeuteronVspTNSigmaTPCVsMult", "NSigmaTPC(#bar{d}) vs pT; #it{p}_{T} (GeV/#it{c}) vs mult; NSigmaTPC", HistType::kTH3F, {{ptAxis}, {SigmaTPCAxis}, {binsPercentile}}); + histos.add("tracks/deuteron/h3DeuteronVspTNSigmaTPCVsMult", "NSigmaTPC(d) vs pT; #it{p}_{T} (GeV/#it{c}) vs mult; NSigmaTPC", HistType::kTH3F, {{ptAxis}, {sigmaTPCAxis}, {binsPercentile}}); + histos.add("tracks/deuteron/h3antiDeuteronVspTNSigmaTPCVsMult", "NSigmaTPC(#bar{d}) vs pT; #it{p}_{T} (GeV/#it{c}) vs mult; NSigmaTPC", HistType::kTH3F, {{ptAxis}, {sigmaTPCAxis}, {binsPercentile}}); } else { - histos.add("tracks/deuteron/h2DeuteronVspTNSigmaTPC", "NSigmaTPC(d) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - histos.add("tracks/deuteron/h2antiDeuteronVspTNSigmaTPC", "NSigmaTPC(#bar{d}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - histos.add("tracks/deuteron/h2DeuteronVspTNSigmaTPCTruePrim", "NSigmaTPC(d) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - histos.add("tracks/deuteron/h2antiDeuteronVspTNSigmaTPCTruePrim", "NSigmaTPC(#bar{d}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); + histos.add("tracks/deuteron/h2DeuteronVspTNSigmaTPC", "NSigmaTPC(d) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + histos.add("tracks/deuteron/h2antiDeuteronVspTNSigmaTPC", "NSigmaTPC(#bar{d}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + histos.add("tracks/deuteron/h2DeuteronVspTNSigmaTPCTruePrim", "NSigmaTPC(d) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + histos.add("tracks/deuteron/h2antiDeuteronVspTNSigmaTPCTruePrim", "NSigmaTPC(#bar{d}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); } } if (enableTr) { - histos.add("tracks/triton/h2TritonVspTNSigmaTPC", "NSigmaTPC(t) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - histos.add("tracks/triton/h2antiTritonVspTNSigmaTPC", "NSigmaTPC(#bar{t}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); + // histos.add("tracks/triton/h2TritonVspTNSigmaITS", "NSigmaITS(t) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaITS", HistType::kTH2F, {{ptAxis}, {sigmaITSAxis}}); + // histos.add("tracks/triton/h2antiTritonVspTNSigmaITS", "NSigmaITS(#bar{t}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaITS", HistType::kTH2F, {{ptAxis}, {sigmaITSAxis}}); + + histos.add("tracks/triton/h2TritonVspTNSigmaTPC", "NSigmaTPC(t) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + histos.add("tracks/triton/h2antiTritonVspTNSigmaTPC", "NSigmaTPC(#bar{t}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); } if (enableHe) { - histos.add("tracks/helium/h2HeliumVspTNSigmaTPC", "NSigmaTPC(He) vs pT/z; #it{p}_{T}/z (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptZHeAxis}, {SigmaTPCAxis}}); - histos.add("tracks/helium/h2antiHeliumVspTNSigmaTPC", "NSigmaTPC(#bar{He}) vs pT/z; #it{p}_{T}/z (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptZHeAxis}, {SigmaTPCAxis}}); + histos.add("tracks/helium/h2HeliumVspTNSigmaITSHe", "NSigmaITS(He) vs p/z; #it{p}/z (GeV/#it{c}); NSigmaITS(He)", HistType::kTH2F, {{pZAxis}, {sigmaITSAxis}}); + histos.add("tracks/helium/h2antiHeliumVspTNSigmaITSHe", "NSigmaITS(#bar{He}) vs p/z; #it{p}/z (GeV/#it{c}); NSigmaITS(#bar{He})", HistType::kTH2F, {{pZAxis}, {sigmaITSAxis}}); + + histos.add("tracks/helium/h2HeliumVspTNSigmaITSTr", "NSigmaITS(t) vs p/z; #it{p}/z (GeV/#it{c}); NSigmaITS(t)", HistType::kTH2F, {{pZAxis}, {sigmaITSAxis}}); + histos.add("tracks/helium/h2antiHeliumVspTNSigmaITSTr", "NSigmaITS(#bar{t}) vs p/z; #it{p}/z (GeV/#it{c}); NSigmaITS(#bar{t})", HistType::kTH2F, {{pZAxis}, {sigmaITSAxis}}); + + histos.add("tracks/helium/h2HeliumVspTNSigmaITSHe_wTPCpid", "NSigmaITS(He) vs p/z; #it{p}/z (GeV/#it{c}); NSigmaITS(He)", HistType::kTH2F, {{pZAxis}, {sigmaITSAxis}}); + histos.add("tracks/helium/h2antiHeliumVspTNSigmaITSHe_wTPCpid", "NSigmaITS(#bar{He}) vs p/z; #it{p}/z (GeV/#it{c}); NSigmaITS(#bar{He})", HistType::kTH2F, {{pZAxis}, {sigmaITSAxis}}); + + histos.add("tracks/helium/h2HeliumVspTNSigmaITSTr_wTPCpid", "NSigmaITS(t) vs p/z; #it{p}/z (GeV/#it{c}); NSigmaITS(t)", HistType::kTH2F, {{pZAxis}, {sigmaITSAxis}}); + histos.add("tracks/helium/h2antiHeliumVspTNSigmaITSTr_wTPCpid", "NSigmaITS(#bar{t}) vs p/z; #it{p}/z (GeV/#it{c}); NSigmaITS(#bar{t})", HistType::kTH2F, {{pZAxis}, {sigmaITSAxis}}); + + histos.add("tracks/helium/h2HeliumVspTNSigmaTPC", "NSigmaTPC(He) vs pT/z; #it{p}_{T}/z (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptZHeAxis}, {sigmaTPCAxis}}); + histos.add("tracks/helium/h2antiHeliumVspTNSigmaTPC", "NSigmaTPC(#bar{He}) vs pT/z; #it{p}_{T}/z (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptZHeAxis}, {sigmaTPCAxis}}); } if (enableAl) { - histos.add("tracks/alpha/h2AlphaVspTNSigmaTPC", "NSigmaTPC(#alpha) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - histos.add("tracks/alpha/h2antiAlphaVspTNSigmaTPC", "NSigmaTPC(#bar{#alpha}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); + histos.add("tracks/alpha/h2AlphaVspTNSigmaTPC", "NSigmaTPC(#alpha) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + histos.add("tracks/alpha/h2antiAlphaVspTNSigmaTPC", "NSigmaTPC(#bar{#alpha}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); } // TOF plots - if (doTOFplots) { + if (outFlagOptions.doTOFplots) { // TOF beta histograms if (enablePr) { histos.add("tracks/proton/h2ProtonTOFbetaVsP", "TOF #beta (p) vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TOF #beta (p)", HistType::kTH2F, {{250, 0.f, 5.f}, {betaAxis}}); @@ -1181,7 +1639,7 @@ struct LFNucleiBATask { histos.add("tracks/helium/h2HeliumTOFbetaVsP", "TOF #beta (He) vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TOF #beta (He)", HistType::kTH2F, {{250, 0.f, 5.f}, {betaAxis}}); histos.add("tracks/helium/h2antiHeliumTOFbetaVsP", "TOF #beta (#bar{He}) vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TOF #beta (#bar{He})", HistType::kTH2F, {{250, 0.f, 5.f}, {betaAxis}}); } - if (enableExpSignalTOF) { + if (outFlagOptions.enableExpSignalTOF) { // TOFExpSignal histograms if (enablePr) { histos.add("tracks/proton/h2ProtonTOFExpSignalDiffVsPt", "TOF t - t_{exp}(p) vs #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); TOF t - t_{exp} (p)", HistType::kTH2F, {{ptAxis}, {2000, -25000, 25000}}); @@ -1204,70 +1662,62 @@ struct LFNucleiBATask { } // NSigmaTOF histograms - histos.add("tracks/pion/h2PionVspTNSigmaTOF", "NSigmaTOF(pi) vs #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - histos.add("tracks/kaon/h2KaonVspTNSigmaTOF", "NSigmaTOF(Ka) vs #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); + if (enableDebug) { + histos.add("tracks/pion/h2PionVspTNSigmaTOF", "NSigmaTOF(pi) vs #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + histos.add("tracks/kaon/h2KaonVspTNSigmaTOF", "NSigmaTOF(Ka) vs #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + } if (enablePr) { - histos.add("tracks/proton/h2ProtonVspTNSigmaTOF", "NSigmaTOF(p) vs #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - histos.add("tracks/proton/h2antiProtonVspTNSigmaTOF", "NSigmaTOF(#bar{p}) vs #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); + histos.add("tracks/proton/h2ProtonVspTNSigmaTOF", "NSigmaTOF(p) vs #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + histos.add("tracks/proton/h2antiProtonVspTNSigmaTOF", "NSigmaTOF(#bar{p}) vs #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); } if (enableDe) { - histos.add("tracks/deuteron/h2DeuteronVspTNSigmaTOF", "NSigmaTOF(d) vs #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - histos.add("tracks/deuteron/h2antiDeuteronVspTNSigmaTOF", "NSigmaTOF(#bar{d}) vs #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); + histos.add("tracks/deuteron/h2DeuteronVspTNSigmaTOF", "NSigmaTOF(d) vs #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + histos.add("tracks/deuteron/h2antiDeuteronVspTNSigmaTOF", "NSigmaTOF(#bar{d}) vs #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); } if (enableHe) { - histos.add("tracks/helium/h2HeliumVspTNSigmaTOF", "NSigmaTOF(He) vs #it{p}_{T}/z; #it{p}_{T}/z (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptZHeAxis}, {SigmaTOFAxis}}); - histos.add("tracks/helium/h2antiHeliumVspTNSigmaTOF", "NSigmaTOF(#bar{He}) vs #it{p}_{T}/z; #it{p}_{T}/z (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptZHeAxis}, {SigmaTOFAxis}}); - } - if (enableDebug) { - // NSigmaTPC vs NSigmaTOF histograms - if (enablePr) { - debugHistos.add("debug/tracks/proton/h3ProtonNSigmaTPCvsNSigmaTOFvsPt", "NSigmaTPC (p) vs NSigmaTOF(p); NSigmaTPC; NSigmaTOF; #it{p}_{T} (GeV/#it{c})", HistType::kTH3F, {{100, -20, 20}, {100, -20, 20}, {ptAxis}}); - debugHistos.add("debug/tracks/proton/h3antiProtonNSigmaTPCvsNSigmaTOFvsPt", "NSigmaTPC (#bar{p}) vs NSigmaTOF(#bar{p}); NSigmaTPC; NSigmaTOF; #it{p}_{T} (GeV/#it{c})", HistType::kTH3F, {{100, -20, 20}, {100, -20, 20}, {ptAxis}}); - } - if (enableDe) { - debugHistos.add("debug/tracks/deuteron/h3DeuteronNSigmaTPCvsNSigmaTOFvsPt", "NSigmaTPC(d) vs NSigmaTOF(d); NSigmaTPC; NSigmaTOF; #it{p}_{T} (GeV/#it{c})", HistType::kTH3F, {{100, -20, 20}, {100, -20, 20}, {ptAxis}}); - debugHistos.add("debug/tracks/deuteron/h3antiDeuteronNSigmaTPCvsNSigmaTOFvsPt", "NSigmaTPC (#bar{d}) vs NSigmaTOF(#bar{d}); NSigmaTPC; NSigmaTOF; #it{p}_{T} (GeV/#it{c})", HistType::kTH3F, {{100, -20, 20}, {100, -20, 20}, {ptAxis}}); - } + histos.add("tracks/helium/h2HeliumVspTNSigmaTOF", "NSigmaTOF(He) vs #it{p}_{T}/z; #it{p}_{T}/z (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptZHeAxis}, {sigmaTOFAxis}}); + histos.add("tracks/helium/h2antiHeliumVspTNSigmaTOF", "NSigmaTOF(#bar{He}) vs #it{p}_{T}/z; #it{p}_{T}/z (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptZHeAxis}, {sigmaTOFAxis}}); } // TOF mass histograms - histos.add("tracks/h2TOFmassVsPt", "h2TOFmassVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{320, 0.4, 4.}, {250, 0., 5.}}); + if (enablePIDplot) + histos.add("tracks/h2TOFmassVsPt", "h2TOFmassVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {250, 0., 5.}}); if (enablePr) { - histos.add("tracks/proton/h2TOFmassProtonVsPt", "h2TOFmassProtonVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{320, 0.4, 4.}, {250, 0., 5.}}); - histos.add("tracks/proton/h2TOFmassantiProtonVsPt", "h2TOFmassantiProtonVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{320, 0.4, 4.}, {250, 0., 5.}}); - if (enableBetaCut) { - histos.add("tracks/proton/h2TOFmassProtonVsPt_BetaCut", "h2TOFmassProtonVsPt_BetaCut; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{320, 0.4, 4.}, {250, 0., 5.}}); - histos.add("tracks/proton/h2TOFmassantiProtonVsPt_BetaCut", "h2TOFmassantiProtonVsPt_BetaCut; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{320, 0.4, 4.}, {250, 0., 5.}}); + histos.add("tracks/proton/h2TOFmassProtonVsPt", "h2TOFmassProtonVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {250, 0., 5.}}); + histos.add("tracks/proton/h2TOFmassantiProtonVsPt", "h2TOFmassantiProtonVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {250, 0., 5.}}); + if (outFlagOptions.enableBetaCut) { + histos.add("tracks/proton/h2TOFmassProtonVsPt_BetaCut", "h2TOFmassProtonVsPt_BetaCut; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {250, 0., 5.}}); + histos.add("tracks/proton/h2TOFmassantiProtonVsPt_BetaCut", "h2TOFmassantiProtonVsPt_BetaCut; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {250, 0., 5.}}); } } if (enableDe) { - histos.add("tracks/deuteron/h2TOFmassDeuteronVsPt", "h2TOFmassDeuteronVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{320, 0.4, 4.}, {250, 0., 5.}}); - histos.add("tracks/deuteron/h2TOFmassantiDeuteronVsPt", "h2TOFmassantiDeuteronVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{320, 0.4, 4.}, {250, 0., 5.}}); - if (enableBetaCut) { - histos.add("tracks/deuteron/h2TOFmassDeuteronVsPt_BetaCut", "h2TOFmassDeuteronVsPt_BetaCut; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{320, 0.4, 4.}, {250, 0., 5.}}); - histos.add("tracks/deuteron/h2TOFmassantiDeuteronVsPt_BetaCut", "h2TOFmassantiDeuteronVsPt_BetaCut; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{320, 0.4, 4.}, {250, 0., 5.}}); + histos.add("tracks/deuteron/h2TOFmassDeuteronVsPt", "h2TOFmassDeuteronVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {250, 0., 5.}}); + histos.add("tracks/deuteron/h2TOFmassantiDeuteronVsPt", "h2TOFmassantiDeuteronVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {250, 0., 5.}}); + if (outFlagOptions.enableBetaCut) { + histos.add("tracks/deuteron/h2TOFmassDeuteronVsPt_BetaCut", "h2TOFmassDeuteronVsPt_BetaCut; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {250, 0., 5.}}); + histos.add("tracks/deuteron/h2TOFmassantiDeuteronVsPt_BetaCut", "h2TOFmassantiDeuteronVsPt_BetaCut; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {250, 0., 5.}}); } } if (enableTr) { - histos.add("tracks/triton/h2TOFmassTritonVsPt", "h2TOFmassTritonVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{320, 0.4, 4.}, {250, 0., 5.}}); - histos.add("tracks/triton/h2TOFmassantiTritonVsPt", "h2TOFmassantiTritonVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{320, 0.4, 4.}, {250, 0., 5.}}); - if (enableBetaCut) { - histos.add("tracks/triton/h2TOFmassTritonVsPt_BetaCut", "h2TOFmassTritonVsPt_BetaCut; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{320, 0.4, 4.}, {250, 0., 5.}}); - histos.add("tracks/triton/h2TOFmassantiTritonVsPt_BetaCut", "h2TOFmassantiTritonVsPt_BetaCut; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{320, 0.4, 4.}, {250, 0., 5.}}); + histos.add("tracks/triton/h2TOFmassTritonVsPt", "h2TOFmassTritonVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {250, 0., 5.}}); + histos.add("tracks/triton/h2TOFmassantiTritonVsPt", "h2TOFmassantiTritonVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {250, 0., 5.}}); + if (outFlagOptions.enableBetaCut) { + histos.add("tracks/triton/h2TOFmassTritonVsPt_BetaCut", "h2TOFmassTritonVsPt_BetaCut; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {250, 0., 5.}}); + histos.add("tracks/triton/h2TOFmassantiTritonVsPt_BetaCut", "h2TOFmassantiTritonVsPt_BetaCut; TOFmass; #it{p}_{T} (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {250, 0., 5.}}); } } if (enableHe) { - histos.add("tracks/helium/h2TOFmassHeliumVsPt", "h2TOFmassHeliumVsPt; TOFmass; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{320, 0.4, 4.}, {ptZHeAxis}}); - histos.add("tracks/helium/h2TOFmassantiHeliumVsPt", "h2TOFmassantiHeliumVsPt; TOFmass; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{320, 0.4, 4.}, {ptZHeAxis}}); - if (enableBetaCut) { - histos.add("tracks/helium/h2TOFmassHeliumVsPt_BetaCut", "h2TOFmassHeliumVsPt_BetaCut; TOFmass; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{320, 0.4, 4.}, {ptZHeAxis}}); - histos.add("tracks/helium/h2TOFmassantiHeliumVsPt_BetaCut", "h2TOFmassantiHeliumVsPt_BetaCut; TOFmass; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{320, 0.4, 4.}, {ptZHeAxis}}); + histos.add("tracks/helium/h2TOFmassHeliumVsPt", "h2TOFmassHeliumVsPt; TOFmass; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {ptZHeAxis}}); + histos.add("tracks/helium/h2TOFmassantiHeliumVsPt", "h2TOFmassantiHeliumVsPt; TOFmass; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {ptZHeAxis}}); + if (outFlagOptions.enableBetaCut) { + histos.add("tracks/helium/h2TOFmassHeliumVsPt_BetaCut", "h2TOFmassHeliumVsPt_BetaCut; TOFmass; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {ptZHeAxis}}); + histos.add("tracks/helium/h2TOFmassantiHeliumVsPt_BetaCut", "h2TOFmassantiHeliumVsPt_BetaCut; TOFmass; #it{p}_{T}/z (GeV)", HistType::kTH2F, {{180, 0.4, 4.}, {ptZHeAxis}}); } } // TOF mass squared histograms if (enablePr) { histos.add("tracks/proton/h2TOFmass2ProtonVsPt", "#Delta M^{2} (p) vs #it{p}_{T}; #Delta M^{2} (p); #it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{massPrAxis}, {250, 0., 5.}}); histos.add("tracks/proton/h2TOFmass2antiProtonVsPt", "#Delta M^{2} (#bar{p}) vs #it{p}_{T}; #Delta M^{2} (#bar{p}); #it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{massPrAxis}, {250, 0., 5.}}); - if (enableBetaCut) { + if (outFlagOptions.enableBetaCut) { histos.add("tracks/proton/h2TOFmass2ProtonVsPt_BetaCut", "#Delta M^{2} (p) vs #it{p}_{T}; #Delta M^{2} (p); #it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{massPrAxis}, {250, 0., 5.}}); histos.add("tracks/proton/h2TOFmass2antiProtonVsPt_BetaCut", "#Delta M^{2} (#bar{p}) vs #it{p}_{T}; #Delta M^{2} (#bar{p}); #it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{massPrAxis}, {250, 0., 5.}}); } @@ -1280,7 +1730,7 @@ struct LFNucleiBATask { histos.add("tracks/deuteron/h2TOFmass2DeuteronVsPt", "#Delta M^{2} (d) vs #it{p}_{T}; #Delta M^{2} (d); #it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{massDeAxis}, {250, 0., 5.}}); histos.add("tracks/deuteron/h2TOFmass2antiDeuteronVsPt", "#Delta M^{2} (#bar{d}) vs #it{p}_{T}; #Delta M^{2} (#bar{d}); #it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{massDeAxis}, {250, 0., 5.}}); } - if (enableBetaCut) { + if (outFlagOptions.enableBetaCut) { histos.add("tracks/deuteron/h2TOFmass2DeuteronVsPt_BetaCut", "#Delta M^{2} (d) vs #it{p}_{T}; #Delta M^{2} (d); #it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{massDeAxis}, {250, 0., 5.}}); histos.add("tracks/deuteron/h2TOFmass2antiDeuteronVsPt_BetaCut", "#Delta M^{2} (#bar{d}) vs #it{p}_{T}; #Delta M^{2} (#bar{d}); #it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{massDeAxis}, {250, 0., 5.}}); } @@ -1288,7 +1738,7 @@ struct LFNucleiBATask { if (enableTr) { histos.add("tracks/triton/h2TOFmass2TritonVsPt", "#Delta M^{2} (t) vs #it{p}_{T}; #Delta M^{2} (t); #it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{massTrAxis}, {250, 0., 5.}}); histos.add("tracks/triton/h2TOFmass2antiTritonVsPt", "#Delta M^{2} (#bar{t}) vs #it{p}_{T}; #Delta M^{2} (#bar{t}; #it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{massTrAxis}, {250, 0., 5.}}); - if (enableBetaCut) { + if (outFlagOptions.enableBetaCut) { histos.add("tracks/triton/h2TOFmass2TritonVsPt_BetaCut", "#Delta M^{2} (t) vs #it{p}_{T}; #Delta M^{2} (t); #it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{massTrAxis}, {250, 0., 5.}}); histos.add("tracks/triton/h2TOFmass2antiTritonVsPt_BetaCut", "#Delta M^{2} (#bar{t}) vs #it{p}_{T}; #Delta M^{2} (#bar{t}; #it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{massTrAxis}, {250, 0., 5.}}); } @@ -1298,13 +1748,13 @@ struct LFNucleiBATask { histos.add("tracks/helium/h2TOFmass2HeliumVsPt", "#Delta M^{2} (He) vs #it{p}_{T}/z; #Delta M^{2} (He); #it{p}_{T}/z (GeV/#it{c})", HistType::kTH2F, {{massHeAxis}, {ptZHeAxis}}); histos.add("tracks/helium/h2TOFmassDeltaHeliumVsPt", "#Delta M (He) vs #it{p}_{T}/z; #Delta M (He); #it{p}_{T}/z (GeV/#it{c})", HistType::kTH2F, {{massHeAxis}, {ptZHeAxis}}); histos.add("tracks/helium/h2TOFmassDeltaantiHeliumVsPt", "#Delta M (#bar{He}) vs #it{p}_{T}/z; #Delta M (#bar{He}); #it{p}_{T}/z (GeV/#it{c})", HistType::kTH2F, {{massHeAxis}, {ptZHeAxis}}); - if (enableBetaCut) { + if (outFlagOptions.enableBetaCut) { histos.add("tracks/helium/h2TOFmass2antiHeliumVsPt_BetaCut", "#Delta M^{2} (#bar{He}) vs #it{p}_{T}/z; #Delta M^{2} (#bar{He}); #it{p}_{T}/z (GeV/#it{c})", HistType::kTH2F, {{massHeAxis}, {ptZHeAxis}}); histos.add("tracks/helium/h2TOFmass2HeliumVsPt_BetaCut", "#Delta M^{2} (He) vs #it{p}_{T}/z; #Delta M^{2} (He); #it{p}_{T}/z (GeV/#it{c})", HistType::kTH2F, {{massHeAxis}, {ptZHeAxis}}); } } // TOF EvTime Splitting plots - if (enableEvTimeSplitting) { + if (filterOptions.enableEvTimeSplitting) { // Bethe-Bloch TPC distribution - TOF EvTime Splitted evtimeHistos.add("tracks/evtime/fill/h2TPCsignVsTPCmomentum", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{500, -5.f, 5.f}, {dedxAxis}}); evtimeHistos.add("tracks/evtime/tof/h2TPCsignVsTPCmomentum", "TPC <-dE/dX> vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TPC <-dE/dx> (a.u.)", HistType::kTH2F, {{500, -5.f, 5.f}, {dedxAxis}}); @@ -1317,7 +1767,7 @@ struct LFNucleiBATask { evtimeHistos.add("tracks/evtime/ft0/h2TOFbetaVsP", "TOF #beta vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TOF #beta", HistType::kTH2F, {{500, -5.f, 5.f}, {betaAxis}}); evtimeHistos.add("tracks/evtime/ft0tof/h2TOFbetaVsP", "TOF #beta vs #it{p}/Z; Signed #it{p} (GeV/#it{c}); TOF #beta", HistType::kTH2F, {{500, -5.f, 5.f}, {betaAxis}}); - if (enableExpSignalTOF) { + if (outFlagOptions.enableExpSignalTOF) { // TOFExpSignal histograms - TOF EvTime Splitted if (enablePr) { evtimeHistos.add("tracks/evtime/fill/proton/h2ProtonTOFExpSignalDiffVsPt", "TOF t - t_{exp}(p) vs #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); TOF t - t_{exp} (p)", HistType::kTH2F, {{ptAxis}, {2000, -25000, 25000}}); @@ -1347,24 +1797,24 @@ struct LFNucleiBATask { // NSigmaTOF histograms - TOF EvTime Splitted if (enablePr) { - evtimeHistos.add("tracks/evtime/fill/proton/h2ProtonVspTNSigmaTOF", "NSigmaTOF(p) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - evtimeHistos.add("tracks/evtime/fill/proton/h2antiProtonVspTNSigmaTOF", "NSigmaTOF(#bar{p}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - evtimeHistos.add("tracks/evtime/tof/proton/h2ProtonVspTNSigmaTOF", "NSigmaTOF(#bar{p}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - evtimeHistos.add("tracks/evtime/tof/proton/h2antiProtonVspTNSigmaTOF", "NSigmaTOF(#bar{p}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - evtimeHistos.add("tracks/evtime/ft0/proton/h2ProtonVspTNSigmaTOF", "NSigmaTOF(p) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - evtimeHistos.add("tracks/evtime/ft0/proton/h2antiProtonVspTNSigmaTOF", "NSigmaTOF(#bar{p}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - evtimeHistos.add("tracks/evtime/ft0tof/proton/h2ProtonVspTNSigmaTOF", "NSigmaTOF(p) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - evtimeHistos.add("tracks/evtime/ft0tof/proton/h2antiProtonVspTNSigmaTOF", "NSigmaTOF(#bar{p}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); + evtimeHistos.add("tracks/evtime/fill/proton/h2ProtonVspTNSigmaTOF", "NSigmaTOF(p) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + evtimeHistos.add("tracks/evtime/fill/proton/h2antiProtonVspTNSigmaTOF", "NSigmaTOF(#bar{p}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + evtimeHistos.add("tracks/evtime/tof/proton/h2ProtonVspTNSigmaTOF", "NSigmaTOF(#bar{p}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + evtimeHistos.add("tracks/evtime/tof/proton/h2antiProtonVspTNSigmaTOF", "NSigmaTOF(#bar{p}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + evtimeHistos.add("tracks/evtime/ft0/proton/h2ProtonVspTNSigmaTOF", "NSigmaTOF(p) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + evtimeHistos.add("tracks/evtime/ft0/proton/h2antiProtonVspTNSigmaTOF", "NSigmaTOF(#bar{p}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + evtimeHistos.add("tracks/evtime/ft0tof/proton/h2ProtonVspTNSigmaTOF", "NSigmaTOF(p) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + evtimeHistos.add("tracks/evtime/ft0tof/proton/h2antiProtonVspTNSigmaTOF", "NSigmaTOF(#bar{p}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); } if (enableDe) { - evtimeHistos.add("tracks/evtime/fill/deuteron/h2DeuteronVspTNSigmaTOF", "NSigmaTOF(d) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - evtimeHistos.add("tracks/evtime/fill/deuteron/h2antiDeuteronVspTNSigmaTOF", "NSigmaTOF(#bar{d}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - evtimeHistos.add("tracks/evtime/tof/deuteron/h2DeuteronVspTNSigmaTOF", "NSigmaTOF(d) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - evtimeHistos.add("tracks/evtime/tof/deuteron/h2antiDeuteronVspTNSigmaTOF", "NSigmaTOF(#bar{d}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - evtimeHistos.add("tracks/evtime/ft0/deuteron/h2DeuteronVspTNSigmaTOF", "NSigmaTOF(d) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - evtimeHistos.add("tracks/evtime/ft0/deuteron/h2antiDeuteronVspTNSigmaTOF", "NSigmaTOF(#bar{d}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - evtimeHistos.add("tracks/evtime/ft0tof/deuteron/h2DeuteronVspTNSigmaTOF", "NSigmaTOF(d) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - evtimeHistos.add("tracks/evtime/ft0tof/deuteron/h2antiDeuteronVspTNSigmaTOF", "NSigmaTOF(#bar{d}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); + evtimeHistos.add("tracks/evtime/fill/deuteron/h2DeuteronVspTNSigmaTOF", "NSigmaTOF(d) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + evtimeHistos.add("tracks/evtime/fill/deuteron/h2antiDeuteronVspTNSigmaTOF", "NSigmaTOF(#bar{d}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + evtimeHistos.add("tracks/evtime/tof/deuteron/h2DeuteronVspTNSigmaTOF", "NSigmaTOF(d) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + evtimeHistos.add("tracks/evtime/tof/deuteron/h2antiDeuteronVspTNSigmaTOF", "NSigmaTOF(#bar{d}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + evtimeHistos.add("tracks/evtime/ft0/deuteron/h2DeuteronVspTNSigmaTOF", "NSigmaTOF(d) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + evtimeHistos.add("tracks/evtime/ft0/deuteron/h2antiDeuteronVspTNSigmaTOF", "NSigmaTOF(#bar{d}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + evtimeHistos.add("tracks/evtime/ft0tof/deuteron/h2DeuteronVspTNSigmaTOF", "NSigmaTOF(d) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + evtimeHistos.add("tracks/evtime/ft0tof/deuteron/h2antiDeuteronVspTNSigmaTOF", "NSigmaTOF(#bar{d}) vs pT; #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); } // NSigmaTPC vs NSigmaTOF histograms - TOF EvTime Splitted @@ -1434,49 +1884,49 @@ struct LFNucleiBATask { // Beta < 0.5 // NSigmasTPC histograms if (enablePr) { - debugHistos.add("debug/evtime/fill/proton/h2ProtonVspTNSigmaTPC_BetaCut", "NSigmaTPC(p) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - debugHistos.add("debug/evtime/fill/proton/h2antiProtonVspTNSigmaTPC_BetaCut", "NSigmaTPC(#bar{p}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - debugHistos.add("debug/evtime/tof/proton/h2ProtonVspTNSigmaTPC_BetaCut", "NSigmaTPC(p) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - debugHistos.add("debug/evtime/tof/proton/h2antiProtonVspTNSigmaTPC_BetaCut", "NSigmaTPC(#bar{p}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - debugHistos.add("debug/evtime/ft0/proton/h2ProtonVspTNSigmaTPC_BetaCut", "NSigmaTPC(p) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - debugHistos.add("debug/evtime/ft0/proton/h2antiProtonVspTNSigmaTPC_BetaCut", "NSigmaTPC(#bar{p}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - debugHistos.add("debug/evtime/ft0tof/proton/h2ProtonVspTNSigmaTPC_BetaCut", "NSigmaTPC(p) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - debugHistos.add("debug/evtime/ft0tof/proton/h2antiProtonVspTNSigmaTPC_BetaCut", "NSigmaTPC(#bar{p}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); + debugHistos.add("debug/evtime/fill/proton/h2ProtonVspTNSigmaTPC_BetaCut", "NSigmaTPC(p) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + debugHistos.add("debug/evtime/fill/proton/h2antiProtonVspTNSigmaTPC_BetaCut", "NSigmaTPC(#bar{p}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + debugHistos.add("debug/evtime/tof/proton/h2ProtonVspTNSigmaTPC_BetaCut", "NSigmaTPC(p) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + debugHistos.add("debug/evtime/tof/proton/h2antiProtonVspTNSigmaTPC_BetaCut", "NSigmaTPC(#bar{p}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + debugHistos.add("debug/evtime/ft0/proton/h2ProtonVspTNSigmaTPC_BetaCut", "NSigmaTPC(p) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + debugHistos.add("debug/evtime/ft0/proton/h2antiProtonVspTNSigmaTPC_BetaCut", "NSigmaTPC(#bar{p}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + debugHistos.add("debug/evtime/ft0tof/proton/h2ProtonVspTNSigmaTPC_BetaCut", "NSigmaTPC(p) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + debugHistos.add("debug/evtime/ft0tof/proton/h2antiProtonVspTNSigmaTPC_BetaCut", "NSigmaTPC(#bar{p}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); } if (enableDe) { - debugHistos.add("debug/evtime/fill/deuteron/h2DeuteronVspTNSigmaTPC_BetaCut", "NSigmaTPC(d) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - debugHistos.add("debug/evtime/fill/deuteron/h2antiDeuteronVspTNSigmaTPC_BetaCut", "NSigmaTPC(#bar{d}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - debugHistos.add("debug/evtime/tof/deuteron/h2DeuteronVspTNSigmaTPC_BetaCut", "NSigmaTPC(d) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - debugHistos.add("debug/evtime/tof/deuteron/h2antiDeuteronVspTNSigmaTPC_BetaCut", "NSigmaTPC(#bar{d}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - debugHistos.add("debug/evtime/ft0/deuteron/h2DeuteronVspTNSigmaTPC_BetaCut", "NSigmaTPC(d) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - debugHistos.add("debug/evtime/ft0/deuteron/h2antiDeuteronVspTNSigmaTPC_BetaCut", "NSigmaTPC(#bar{d}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - debugHistos.add("debug/evtime/ft0tof/deuteron/h2DeuteronVspTNSigmaTPC_BetaCut", "NSigmaTPC(d) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); - debugHistos.add("debug/evtime/ft0tof/deuteron/h2antiDeuteronVspTNSigmaTPC_BetaCut", "NSigmaTPC(#bar{d}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {SigmaTPCAxis}}); + debugHistos.add("debug/evtime/fill/deuteron/h2DeuteronVspTNSigmaTPC_BetaCut", "NSigmaTPC(d) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + debugHistos.add("debug/evtime/fill/deuteron/h2antiDeuteronVspTNSigmaTPC_BetaCut", "NSigmaTPC(#bar{d}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + debugHistos.add("debug/evtime/tof/deuteron/h2DeuteronVspTNSigmaTPC_BetaCut", "NSigmaTPC(d) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + debugHistos.add("debug/evtime/tof/deuteron/h2antiDeuteronVspTNSigmaTPC_BetaCut", "NSigmaTPC(#bar{d}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + debugHistos.add("debug/evtime/ft0/deuteron/h2DeuteronVspTNSigmaTPC_BetaCut", "NSigmaTPC(d) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + debugHistos.add("debug/evtime/ft0/deuteron/h2antiDeuteronVspTNSigmaTPC_BetaCut", "NSigmaTPC(#bar{d}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + debugHistos.add("debug/evtime/ft0tof/deuteron/h2DeuteronVspTNSigmaTPC_BetaCut", "NSigmaTPC(d) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); + debugHistos.add("debug/evtime/ft0tof/deuteron/h2antiDeuteronVspTNSigmaTPC_BetaCut", "NSigmaTPC(#bar{d}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTPC", HistType::kTH2F, {{ptAxis}, {sigmaTPCAxis}}); } // NSigmaTOF histograms - TOF EvTime Splitted if (enablePr) { - debugHistos.add("debug/evtime/fill/proton/h2ProtonVspTNSigmaTOF_BetaCut", "NSigmaTOF(p) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - debugHistos.add("debug/evtime/fill/proton/h2antiProtonVspTNSigmaTOF_BetaCut", "NSigmaTOF(#bar{p}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - debugHistos.add("debug/evtime/tof/proton/h2ProtonVspTNSigmaTOF_BetaCut", "NSigmaTOF(p) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - debugHistos.add("debug/evtime/tof/proton/h2antiProtonVspTNSigmaTOF_BetaCut", "NSigmaTOF(#bar{p}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - debugHistos.add("debug/evtime/ft0/proton/h2ProtonVspTNSigmaTOF_BetaCut", "NSigmaTOF(p) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - debugHistos.add("debug/evtime/ft0/proton/h2antiProtonVspTNSigmaTOF_BetaCut", "NSigmaTOF(#bar{p}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - debugHistos.add("debug/evtime/ft0tof/proton/h2ProtonVspTNSigmaTOF_BetaCut", "NSigmaTOF(p) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - debugHistos.add("debug/evtime/ft0tof/proton/h2antiProtonVspTNSigmaTOF_BetaCut", "NSigmaTOF(#bar{p}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); + debugHistos.add("debug/evtime/fill/proton/h2ProtonVspTNSigmaTOF_BetaCut", "NSigmaTOF(p) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + debugHistos.add("debug/evtime/fill/proton/h2antiProtonVspTNSigmaTOF_BetaCut", "NSigmaTOF(#bar{p}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + debugHistos.add("debug/evtime/tof/proton/h2ProtonVspTNSigmaTOF_BetaCut", "NSigmaTOF(p) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + debugHistos.add("debug/evtime/tof/proton/h2antiProtonVspTNSigmaTOF_BetaCut", "NSigmaTOF(#bar{p}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + debugHistos.add("debug/evtime/ft0/proton/h2ProtonVspTNSigmaTOF_BetaCut", "NSigmaTOF(p) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + debugHistos.add("debug/evtime/ft0/proton/h2antiProtonVspTNSigmaTOF_BetaCut", "NSigmaTOF(#bar{p}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + debugHistos.add("debug/evtime/ft0tof/proton/h2ProtonVspTNSigmaTOF_BetaCut", "NSigmaTOF(p) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + debugHistos.add("debug/evtime/ft0tof/proton/h2antiProtonVspTNSigmaTOF_BetaCut", "NSigmaTOF(#bar{p}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); } if (enableDe) { - debugHistos.add("debug/evtime/fill/deuteron/h2DeuteronVspTNSigmaTOF_BetaCut", "NSigmaTOF(d) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - debugHistos.add("debug/evtime/fill/deuteron/h2antiDeuteronVspTNSigmaTOF_BetaCut", "NSigmaTOF(#bar{d}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - debugHistos.add("debug/evtime/tof/deuteron/h2DeuteronVspTNSigmaTOF_BetaCut", "NSigmaTOF(d) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - debugHistos.add("debug/evtime/tof/deuteron/h2antiDeuteronVspTNSigmaTOF_BetaCut", "NSigmaTOF(#bar{d}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - debugHistos.add("debug/evtime/ft0/deuteron/h2DeuteronVspTNSigmaTOF_BetaCut", "NSigmaTOF(d) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - debugHistos.add("debug/evtime/ft0/deuteron/h2antiDeuteronVspTNSigmaTOF_BetaCut", "NSigmaTOF(#bar{d}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - debugHistos.add("debug/evtime/ft0tof/deuteron/h2DeuteronVspTNSigmaTOF_BetaCut", "NSigmaTOF(d) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); - debugHistos.add("debug/evtime/ft0tof/deuteron/h2antiDeuteronVspTNSigmaTOF_BetaCut", "NSigmaTOF(#bar{d}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {SigmaTOFAxis}}); + debugHistos.add("debug/evtime/fill/deuteron/h2DeuteronVspTNSigmaTOF_BetaCut", "NSigmaTOF(d) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + debugHistos.add("debug/evtime/fill/deuteron/h2antiDeuteronVspTNSigmaTOF_BetaCut", "NSigmaTOF(#bar{d}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + debugHistos.add("debug/evtime/tof/deuteron/h2DeuteronVspTNSigmaTOF_BetaCut", "NSigmaTOF(d) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + debugHistos.add("debug/evtime/tof/deuteron/h2antiDeuteronVspTNSigmaTOF_BetaCut", "NSigmaTOF(#bar{d}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + debugHistos.add("debug/evtime/ft0/deuteron/h2DeuteronVspTNSigmaTOF_BetaCut", "NSigmaTOF(d) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + debugHistos.add("debug/evtime/ft0/deuteron/h2antiDeuteronVspTNSigmaTOF_BetaCut", "NSigmaTOF(#bar{d}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + debugHistos.add("debug/evtime/ft0tof/deuteron/h2DeuteronVspTNSigmaTOF_BetaCut", "NSigmaTOF(d) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); + debugHistos.add("debug/evtime/ft0tof/deuteron/h2antiDeuteronVspTNSigmaTOF_BetaCut", "NSigmaTOF(#bar{d}) vs pT (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); NSigmaTOF", HistType::kTH2F, {{ptAxis}, {sigmaTOFAxis}}); } - if (enableExpSignalTOF) { + if (outFlagOptions.enableExpSignalTOF) { // TOFExpSignal histograms - TOF EvTime Splitted if (enablePr) { debugHistos.add("debug/evtime/fill/proton/h2ProtonTOFExpSignalDiffVsPt_BetaCut", "TOF t - t_{exp}(p) vs #it{p}_{T} (#beta < 0.5); #it{p}_{T} (GeV/#it{c}); TOF t - t_{exp} (p)", HistType::kTH2F, {{ptAxis}, {2000, -25000, 25000}}); @@ -1501,8 +1951,10 @@ struct LFNucleiBATask { } } } - - if (!doprocessMCGen) { + // To be optimised + if (!doprocessMCGen && !doprocessMCReco && !doprocessMCRecoLfPid && !doprocessMCRecoFiltered && !doprocessMCRecoFilteredLight) { + LOG(info) << "Histograms of LFNucleiBATask:"; + histos.print(); return; } // MC histograms - all, primary, sec. from weak decay, sec. from material @@ -1549,8 +2001,6 @@ struct LFNucleiBATask { spectraGen.add("kaon/histSecTransportPtantiKaon", "generated particles", HistType::kTH1F, {ptAxis}); if (enablePr) { - // spectraGen.add("proton/histPtShift_Pr", "PtReco-PtGen vs PtReco (protons) ", HistType::kTH2F, {{800, 0.f, 8.f}, {400, -4.f, 4.f}}); - spectraGen.add("proton/histGenPtProton", "generated particles", HistType::kTH1F, {ptAxis}); spectraGen.add("proton/histGenPtProtonPrim", "generated particles", HistType::kTH1F, {ptAxis}); spectraGen.add("proton/histGenPtProtonSec", "generated particles", HistType::kTH1F, {ptAxis}); @@ -1628,6 +2078,19 @@ struct LFNucleiBATask { const TracksType& tracks, const ParticleType& /*particles*/) { + histos.fill(HIST("event/eventSkimming"), 0.5); + // Apply skimming + if constexpr (!IsFilteredData) { + const auto& bc = event.template bc_as(); + initCCDB(bc); + if (skimmingOptions.applySkimming) { + if (!zorro.isSelected(bc.globalBC())) { + return; + } + } + histos.fill(HIST("event/eventSkimming"), 1.5); + } + // Event histos fill histos.fill(HIST("event/eventSelection"), 0); if (enableDebug) @@ -1635,7 +2098,7 @@ struct LFNucleiBATask { if constexpr (!IsFilteredData) { if (!event.selection_bit(aod::evsel::kIsTriggerTVX)) { - if (TVXtrigger) + if (evselOptions.TVXtrigger) return; } else { histos.fill(HIST("event/eventSelection"), 1); @@ -1644,7 +2107,7 @@ struct LFNucleiBATask { } if (!event.selection_bit(aod::evsel::kNoTimeFrameBorder)) { - if (removeTFBorder) + if (evselOptions.removeTFBorder) return; } else { histos.fill(HIST("event/eventSelection"), 2); @@ -1653,7 +2116,7 @@ struct LFNucleiBATask { } if (!event.selection_bit(aod::evsel::kNoITSROFrameBorder)) { - if (removeITSROFBorder) + if (evselOptions.removeITSROFBorder) return; } else { histos.fill(HIST("event/eventSelection"), 3); @@ -1667,7 +2130,7 @@ struct LFNucleiBATask { histos.fill(HIST("event/eventSelection"), 4); } - if (useSel8 && !event.sel8()) + if (evselOptions.useSel8 && !event.sel8()) return; histos.fill(HIST("event/eventSelection"), 5); if (enableDebug) @@ -1688,17 +2151,17 @@ struct LFNucleiBATask { } else { if (event.posZ() < cfgLowCutVertex || event.posZ() > cfgHighCutVertex) return; - if (removeTFBorder && !event.selection_bit(aod::evsel::kNoTimeFrameBorder)) + if (evselOptions.removeTFBorder && !event.selection_bit(aod::evsel::kNoTimeFrameBorder)) return; } float gamma = 0., massTOF = 0., massTOFhe = 0., massTOFantihe = 0., heTPCmomentum = 0.f, antiheTPCmomentum = 0.f, heP = 0.f, antiheP = 0.f, hePt = 0.f, antihePt = 0.f, antiDPt = 0.f, DPt = 0.f; - bool isTriton = kFALSE; - bool prRapCut = kFALSE; - bool deRapCut = kFALSE; - bool trRapCut = kFALSE; - bool heRapCut = kFALSE; - bool alRapCut = kFALSE; + bool isTritonTPCpid = false; + bool prRapCut = false; + bool deRapCut = false; + bool trRapCut = false; + bool heRapCut = false; + bool alRapCut = false; // Event histos fill histos.fill(HIST("event/h1VtxZ"), event.posZ()); @@ -1710,34 +2173,47 @@ struct LFNucleiBATask { debugHistos.fill(HIST("event/hFV0M"), event.centFV0M()); } - for (auto& track : tracks) { - histos.fill(HIST("tracks/h1pT"), track.pt()); - histos.fill(HIST("tracks/h1p"), track.p()); + auto tracksWithITS = soa::Attach(tracks); + if (tracksWithITS.size() != tracks.size()) { + LOG(fatal) << "Problem with track size"; + } + + tracks.copyIndexBindings(tracksWithITS); + for (auto& track : tracksWithITS) { if constexpr (!IsFilteredData) { - if (!track.isGlobalTrackWoDCA()) { + if (!track.isGlobalTrackWoDCA() && filterOptions.enableIsGlobalTrack) { continue; } } std::bitset<8> itsClusterMap = track.itsClusterMap(); - if (track.itsNCls() < cfgCutITSClusters) + if (track.itsNCls() < trkqcOptions.cfgCutITSClusters) + continue; + if (track.tpcNClsCrossedRows() < trkqcOptions.cfgCutTPCXRows) continue; - if (track.tpcNClsCrossedRows() < cfgCutTPCXRows) + if (track.tpcNClsFound() < trkqcOptions.cfgCutTPCClusters) continue; - if (track.tpcNClsFound() < cfgCutTPCClusters) + if (track.tpcCrossedRowsOverFindableCls() < trkqcOptions.cfgCutTPCCROFnd) continue; + auto tpcChi2NclRange = (std::vector)trkqcOptions.tpcChi2NclCuts; + if ((track.tpcChi2NCl() < tpcChi2NclRange[0]) || (track.tpcChi2NCl() > tpcChi2NclRange[1])) + continue; + auto itsChi2NclRange = (std::vector)trkqcOptions.itsChi2NclCuts; + if ((track.itsChi2NCl() < itsChi2NclRange[0]) || (track.itsChi2NCl() > itsChi2NclRange[1])) + continue; + + if (enablePIDplot) { + histos.fill(HIST("tracks/h1pT"), track.pt()); + histos.fill(HIST("tracks/h1p"), track.p()); + } - isTriton = std::abs(track.tpcNSigmaTr()) < nsigmaTPCTr; + isTritonTPCpid = std::abs(track.tpcNSigmaTr()) < nsigmaTPCvar.nsigmaTPCTr; float shiftPtPos = 0.f; float shiftPtNeg = 0.f; - // float shiftPPos = 0.f; - // float shiftPNeg = 0.f; - - // float shiftTPCmomPos = 0.f; - // float shiftTPCmomNeg = 0.f; - if (enablePtShift && !fShiftPtHe) { fShiftPtHe = new TF1("fShiftPtHe", "[0] * TMath::Exp([1] + [2] * x) + [3] + [4] * x", 0.f, 8.f); auto par = (std::vector)parShiftPtHe; @@ -1750,30 +2226,6 @@ struct LFNucleiBATask { fShiftPtantiHe->SetParameters(par[0], par[1], par[2], par[3], par[4]); } - // if (enablePShift && !fShiftPHe) { - // fShiftPHe = new TF1("fShiftPHe", "[0] * TMath::Exp([1] + [2] * x) + [3] + [4] * x", 0.f, 8.f); - // auto par = (std::vector)parShiftPHe; - // fShiftPHe->SetParameters(par[0], par[1], par[2], par[3], par[4]); - // } - - // if (enablePShift && !fShiftPantiHe) { - // fShiftPantiHe = new TF1("fShiftPantiHe", "[0] * TMath::Exp([1] + [2] * x) + [3] + [4] * x", 0.f, 8.f); - // auto par = (std::vector)parShiftPantiHe; - // fShiftPantiHe->SetParameters(par[0], par[1], par[2], par[3], par[4]); - // } - - // if (enableTPCmomShift && !fShiftTPCmomHe) { - // fShiftTPCmomHe = new TF1("fShiftTPCmomHe", "[0] * TMath::Exp([1] + [2] * x) + [3] + [4] * x", 0.f, 8.f); - // auto par = (std::vector)parShiftPHe; - // fShiftTPCmomHe->SetParameters(par[0], par[1], par[2], par[3], par[4]); - // } - - // if (enableTPCmomShift && !fShiftTPCmomantiHe) { - // fShiftTPCmomantiHe = new TF1("fShiftTPCmomantiHe", "[0] * TMath::Exp([1] + [2] * x) + [3] + [4] * x", 0.f, 8.f); - // auto par = (std::vector)parShiftPantiHe; - // fShiftTPCmomantiHe->SetParameters(par[0], par[1], par[2], par[3], par[4]); - // } - if (enablePtShiftAntiD && !fShiftAntiD) { fShiftAntiD = new TF1("fShiftAntiD", "[0] * TMath::Exp([1] + [2] * x) + [3] + [4] * x", 0.f, 8.f); auto par = (std::vector)parShiftPtAntiD; @@ -1829,121 +2281,294 @@ struct LFNucleiBATask { break; } + float nITSTr = 99.f; + float nITSHe = 99.f; + if (!IsFilteredData) { + nITSTr = track.itsNSigmaTr(); + nITSHe = track.itsNSigmaHe(); + } heP = track.p(); antiheP = track.p(); heTPCmomentum = track.tpcInnerParam(); antiheTPCmomentum = track.tpcInnerParam(); - // if (enablePShift && fShiftPHe) { - // shiftPPos = fShiftPHe->Eval(2 * track.p()); - // heP = track.p() - shiftPPos / 2.f; - // } + auto parDCAxy = (std::vector)parDCAxycuts; + auto parDCAz = (std::vector)parDCAzcuts; + + bool passDCAxyCut = false; + bool passDCAzCut = false; + bool passDCAxyCutDe = false; + bool passDCAzCutDe = false; + bool passDCAxyCutAntiDe = false; + bool passDCAzCutAntiDe = false; + bool passDCAxyCutHe = false; + bool passDCAzCutHe = false; + bool passDCAxyCutAntiHe = false; + bool passDCAzCutAntiHe = false; + + bool isDeuteron = false; + bool isHelium = false; + bool isDe = false; + bool isAntiDe = false; + bool isHe = false; + bool isAntiHe = false; + + bool isDeWoDCAxy = false; + bool isAntiDeWoDCAxy = false; + bool isHeWoDCAxy = false; + bool isAntiHeWoDCAxy = false; + + bool isDeWoDCAz = false; + bool isAntiDeWoDCAz = false; + bool isHeWoDCAz = false; + bool isAntiHeWoDCAz = false; + + bool isDeWoDCAxyWTPCpid = false; + bool isAntiDeWoDCAxyWTPCpid = false; + bool isHeWoDCAxyWTPCpid = false; + bool isAntiHeWoDCAxyWTPCpid = false; + + bool isDeWoDCAzWTPCpid = false; + bool isAntiDeWoDCAzWTPCpid = false; + bool isHeWoDCAzWTPCpid = false; + bool isAntiHeWoDCAzWTPCpid = false; + + bool isDeWoTPCpid = false; + bool isAntiDeWoTPCpid = false; + bool isHeWoTPCpid = false; + bool isAntiHeWoTPCpid = false; + + bool isDeWTPCpid = false; + bool isAntiDeWTPCpid = false; + bool isHeWTPCpid = false; + bool isAntiHeWTPCpid = false; + + bool passDCAxyzCut = false; + + switch (dcaConfOptions.DCACustomConfig) { + case 0: + passDCAxyCut = (std::abs(track.dcaXY()) <= dcaConfOptions.DCAxyCustomCut); + passDCAzCut = (std::abs(track.dcaZ()) <= dcaConfOptions.DCAzCustomCut); + + passDCAxyCutDe = (std::abs(track.dcaXY()) <= dcaConfOptions.DCAxyCustomCut); + passDCAzCutDe = (std::abs(track.dcaZ()) <= dcaConfOptions.DCAzCustomCut); + passDCAxyCutAntiDe = (std::abs(track.dcaXY()) <= dcaConfOptions.DCAxyCustomCut); + passDCAzCutAntiDe = (std::abs(track.dcaZ()) <= dcaConfOptions.DCAzCustomCut); + + passDCAxyCutHe = (std::abs(track.dcaXY()) <= dcaConfOptions.DCAxyCustomCut); + passDCAzCutHe = (std::abs(track.dcaZ()) <= dcaConfOptions.DCAzCustomCut); + passDCAxyCutAntiHe = (std::abs(track.dcaXY()) <= dcaConfOptions.DCAxyCustomCut); + passDCAzCutAntiHe = (std::abs(track.dcaZ()) <= dcaConfOptions.DCAzCustomCut); + break; + case 1: + passDCAxyCut = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(track.pt(), parDCAxy[2]))); + passDCAzCut = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(track.pt(), parDCAz[2]))); + + passDCAxyCutDe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(DPt, parDCAxy[2]))); + passDCAzCutDe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(DPt, parDCAz[2]))); + passDCAxyCutAntiDe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(antiDPt, parDCAxy[2]))); + passDCAzCutAntiDe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(antiDPt, parDCAz[2]))); + + passDCAxyCutHe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(hePt, parDCAxy[2]))); + passDCAzCutHe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(hePt, parDCAz[2]))); + passDCAxyCutAntiHe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(antihePt, parDCAxy[2]))); + passDCAzCutAntiHe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(antihePt, parDCAz[2]))); + break; + case 2: + passDCAxyCut = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(track.pt(), parDCAxy[2]))); + passDCAzCut = (std::abs(track.dcaZ()) <= dcaConfOptions.DCAzCustomCut); + + passDCAxyCutDe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(DPt, parDCAxy[2]))); + passDCAzCutDe = (std::abs(track.dcaZ()) <= dcaConfOptions.DCAzCustomCut); + passDCAxyCutAntiDe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(antiDPt, parDCAxy[2]))); + passDCAzCutAntiDe = (std::abs(track.dcaZ()) <= dcaConfOptions.DCAzCustomCut); + + passDCAxyCutHe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(hePt, parDCAxy[2]))); + passDCAzCutHe = (std::abs(track.dcaZ()) <= dcaConfOptions.DCAzCustomCut); + passDCAxyCutAntiHe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(antihePt, parDCAxy[2]))); + passDCAzCutAntiHe = (std::abs(track.dcaZ()) <= dcaConfOptions.DCAzCustomCut); + break; + case 3: + passDCAxyCut = (std::abs(track.dcaXY()) <= dcaConfOptions.DCAxyCustomCut); + passDCAzCut = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(track.pt(), parDCAz[2]))); + + passDCAxyCutDe = (std::abs(track.dcaXY()) <= dcaConfOptions.DCAxyCustomCut); + passDCAzCutDe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(DPt, parDCAz[2]))); + passDCAxyCutAntiDe = (std::abs(track.dcaXY()) <= dcaConfOptions.DCAxyCustomCut); + passDCAzCutAntiDe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(antiDPt, parDCAz[2]))); + + passDCAxyCutHe = (std::abs(track.dcaXY()) <= dcaConfOptions.DCAxyCustomCut); + passDCAzCutHe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(hePt, parDCAz[2]))); + passDCAxyCutAntiHe = (std::abs(track.dcaXY()) <= dcaConfOptions.DCAxyCustomCut); + passDCAzCutAntiHe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(antihePt, parDCAz[2]))); + break; + case 4: + passDCAxyCut = std::pow(track.dcaXY(), 2) / std::pow(dcaConfOptions.DCAxyCustomCut, 2) + std::pow(track.dcaZ(), 2) / std::pow(dcaConfOptions.DCAzCustomCut, 2) <= 1; + passDCAzCut = std::pow(track.dcaXY(), 2) / std::pow(dcaConfOptions.DCAxyCustomCut, 2) + std::pow(track.dcaZ(), 2) / std::pow(dcaConfOptions.DCAzCustomCut, 2) <= 1; + + passDCAxyCutDe = std::pow(track.dcaXY(), 2) / std::pow(dcaConfOptions.DCAxyCustomCut, 2) + std::pow(track.dcaZ(), 2) / std::pow(dcaConfOptions.DCAzCustomCut, 2) <= 1; + passDCAzCutDe = std::pow(track.dcaXY(), 2) / std::pow(dcaConfOptions.DCAxyCustomCut, 2) + std::pow(track.dcaZ(), 2) / std::pow(dcaConfOptions.DCAzCustomCut, 2) <= 1; + passDCAxyCutAntiDe = std::pow(track.dcaXY(), 2) / std::pow(dcaConfOptions.DCAxyCustomCut, 2) + std::pow(track.dcaZ(), 2) / std::pow(dcaConfOptions.DCAzCustomCut, 2) <= 1; + passDCAzCutAntiDe = std::pow(track.dcaXY(), 2) / std::pow(dcaConfOptions.DCAxyCustomCut, 2) + std::pow(track.dcaZ(), 2) / std::pow(dcaConfOptions.DCAzCustomCut, 2) <= 1; + + passDCAxyCutHe = std::pow(track.dcaXY(), 2) / std::pow(dcaConfOptions.DCAxyCustomCut, 2) + std::pow(track.dcaZ(), 2) / std::pow(dcaConfOptions.DCAzCustomCut, 2) <= 1; + passDCAzCutHe = std::pow(track.dcaXY(), 2) / std::pow(dcaConfOptions.DCAxyCustomCut, 2) + std::pow(track.dcaZ(), 2) / std::pow(dcaConfOptions.DCAzCustomCut, 2) <= 1; + passDCAxyCutAntiHe = std::pow(track.dcaXY(), 2) / std::pow(dcaConfOptions.DCAxyCustomCut, 2) + std::pow(track.dcaZ(), 2) / std::pow(dcaConfOptions.DCAzCustomCut, 2) <= 1; + passDCAzCutAntiHe = std::pow(track.dcaXY(), 2) / std::pow(dcaConfOptions.DCAxyCustomCut, 2) + std::pow(track.dcaZ(), 2) / std::pow(dcaConfOptions.DCAzCustomCut, 2) <= 1; + break; + case 5: + passDCAxyCut = std::pow(track.dcaXY(), 2) / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(track.pt(), parDCAxy[2])), 2) + std::pow(track.dcaZ(), 2) / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(track.pt(), parDCAz[2])), 2) <= 1; + passDCAzCut = std::pow(track.dcaXY(), 2) / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(track.pt(), parDCAxy[2])), 2) + std::pow(track.dcaZ(), 2) / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(track.pt(), parDCAz[2])), 2) <= 1; + + passDCAxyCutDe = std::pow(track.dcaXY(), 2) / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(DPt, parDCAxy[2])), 2) + std::pow(track.dcaZ(), 2) / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(DPt, parDCAz[2])), 2) <= 1; + passDCAzCutDe = std::pow(track.dcaXY(), 2) / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(DPt, parDCAxy[2])), 2) + std::pow(track.dcaZ(), 2) / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(DPt, parDCAz[2])), 2) <= 1; + passDCAxyCutAntiDe = std::pow(track.dcaXY(), 2) / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(antiDPt, parDCAxy[2])), 2) + std::pow(track.dcaZ(), 2) / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(antiDPt, parDCAz[2])), 2) <= 1; + passDCAzCutAntiDe = std::pow(track.dcaXY(), 2) / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(antiDPt, parDCAxy[2])), 2) + std::pow(track.dcaZ(), 2) / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(antiDPt, parDCAz[2])), 2) <= 1; + + passDCAxyCutHe = std::pow(track.dcaXY(), 2) / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(hePt, parDCAxy[2])), 2) + std::pow(track.dcaZ(), 2) / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(hePt, parDCAz[2])), 2) <= 1; + passDCAzCutHe = std::pow(track.dcaXY(), 2) / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(hePt, parDCAxy[2])), 2) + std::pow(track.dcaZ(), 2) / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(hePt, parDCAz[2])), 2) <= 1; + passDCAxyCutAntiHe = std::pow(track.dcaXY(), 2) / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(antihePt, parDCAxy[2])), 2) + std::pow(track.dcaZ(), 2) / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(antihePt, parDCAz[2])), 2) <= 1; + passDCAzCutAntiHe = std::pow(track.dcaXY(), 2) / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(antihePt, parDCAxy[2])), 2) + std::pow(track.dcaZ(), 2) / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(antihePt, parDCAz[2])), 2) <= 1; + break; + } - // if (enablePShift && fShiftPantiHe) { - // shiftPNeg = fShiftPantiHe->Eval(2 * track.p()); - // antiheP = track.p() - shiftPNeg / 2.f; - // } + // p cut + if (std::abs(track.tpcInnerParam()) < kinemOptions.pCut) + continue; + // eta cut + if (std::abs(track.eta()) > kinemOptions.etaCut) + continue; - // if (enableTPCmomShift && fShiftTPCmomHe) { - // shiftTPCmomPos = fShiftTPCmomHe->Eval(2 * track.tpcInnerParam()); - // heTPCmomentum = track.tpcInnerParam() - shiftTPCmomPos / 2.f; - // } + // Rapidity cuts + prRapCut = track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Proton)) > kinemOptions.yLowCut && track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Proton)) < kinemOptions.yHighCut; + deRapCut = track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Deuteron)) > kinemOptions.yLowCut && track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Deuteron)) < kinemOptions.yHighCut; + trRapCut = track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Triton)) > kinemOptions.yLowCut && track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Triton)) < kinemOptions.yHighCut; + heRapCut = track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Helium3)) > kinemOptions.yLowCut && track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Helium3)) < kinemOptions.yHighCut; + alRapCut = track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Alpha)) > kinemOptions.yLowCut && track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Alpha)) < kinemOptions.yHighCut; - // if (enableTPCmomShift && fShiftTPCmomantiHe) { - // shiftTPCmomNeg = fShiftTPCmomantiHe->Eval(2 * track.tpcInnerParam()); - // antiheTPCmomentum = track.tpcInnerParam() - shiftTPCmomNeg / 2.f; - // } + isDeuteron = enableDe && deRapCut; + isHelium = enableHe && heRapCut; + isDe = isDeuteron && track.sign() > 0; + isAntiDe = isDeuteron && track.sign() < 0; - // p cut - if (TMath::Abs(track.tpcInnerParam()) < pCut) + // nSigmaITSHe cut + if (nsigmaITSvar.useITSHeCut && (nITSHe <= nsigmaITSvar.nsigmaITSHe)) { continue; + } - // debug on helium rapidity cut - prRapCut = track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Proton)) > yLowCut && track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Proton)) < yHighCut; - deRapCut = track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Deuteron)) > yLowCut && track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Deuteron)) < yHighCut; - trRapCut = track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Triton)) > yLowCut && track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Triton)) < yHighCut; - heRapCut = track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Helium3)) > yLowCut && track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Helium3)) < yHighCut; - alRapCut = track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Alpha)) > yLowCut && track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Alpha)) < yHighCut; - - // Tracks DCA histos fill - if (makeDCABeforeCutPlots) { - histos.fill(HIST("tracks/dca/before/hDCAxy"), track.dcaXY()); - histos.fill(HIST("tracks/dca/before/hDCAz"), track.dcaZ()); - // histos.fill(HIST("tracks/dca/before/hDCAxyVsDCAz"), track.dcaXY(), track.dcaZ()); - histos.fill(HIST("tracks/dca/before/hDCAxyVsPt"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/dca/before/hDCAzVsPt"), track.pt(), track.dcaZ()); - - if (enablePr && prRapCut) { - if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCPr) { - if (track.sign() > 0) { - histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtProton"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtProton"), track.pt(), track.dcaZ()); - } else { - histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtantiProton"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtantiProton"), track.pt(), track.dcaZ()); - } + isHe = isHelium && track.sign() > 0; + isAntiHe = isHelium && track.sign() < 0; + + isDeWoDCAxy = isDe && passDCAzCutDe; + isAntiDeWoDCAxy = isAntiDe && passDCAzCutAntiDe; + isHeWoDCAxy = isHe && passDCAzCutHe; + isAntiHeWoDCAxy = isAntiHe && passDCAzCutAntiHe; + + isDeWoDCAz = isDe && passDCAxyCutDe; + isAntiDeWoDCAz = isAntiDe && passDCAxyCutAntiDe; + isHeWoDCAz = isHe && passDCAxyCutHe; + isAntiHeWoDCAz = isAntiHe && passDCAxyCutAntiHe; + + isDeWoDCAxyWTPCpid = isDeWoDCAxy && std::abs(track.tpcNSigmaDe()) < nsigmaTPCvar.nsigmaTPCDe; + isAntiDeWoDCAxyWTPCpid = isAntiDeWoDCAxy && std::abs(track.tpcNSigmaDe()) < nsigmaTPCvar.nsigmaTPCDe; + isHeWoDCAxyWTPCpid = isHeWoDCAxy && std::abs(track.tpcNSigmaHe()) < nsigmaTPCvar.nsigmaTPCHe; + isAntiHeWoDCAxyWTPCpid = isAntiHeWoDCAxy && std::abs(track.tpcNSigmaHe()) < nsigmaTPCvar.nsigmaTPCHe; + + isDeWoDCAzWTPCpid = isDeWoDCAz && std::abs(track.tpcNSigmaDe()) < nsigmaTPCvar.nsigmaTPCDe; + isAntiDeWoDCAzWTPCpid = isAntiDeWoDCAz && std::abs(track.tpcNSigmaDe()) < nsigmaTPCvar.nsigmaTPCDe; + isHeWoDCAzWTPCpid = isHeWoDCAz && std::abs(track.tpcNSigmaHe()) < nsigmaTPCvar.nsigmaTPCHe; + isAntiHeWoDCAzWTPCpid = isAntiHeWoDCAz && std::abs(track.tpcNSigmaHe()) < nsigmaTPCvar.nsigmaTPCHe; + + isDeWoTPCpid = isDe && passDCAzCutDe && passDCAxyCutDe; + isAntiDeWoTPCpid = isAntiDe && passDCAzCutAntiDe && passDCAxyCutAntiDe; + isHeWoTPCpid = isHe && passDCAzCutHe && passDCAxyCutHe; + isAntiHeWoTPCpid = isAntiHe && passDCAzCutAntiHe && passDCAxyCutAntiHe; + + isDeWTPCpid = isDeWoTPCpid && std::abs(track.tpcNSigmaDe()) < nsigmaTPCvar.nsigmaTPCDe; + isAntiDeWTPCpid = isAntiDeWoTPCpid && std::abs(track.tpcNSigmaDe()) < nsigmaTPCvar.nsigmaTPCDe; + isHeWTPCpid = isHeWoTPCpid && std::abs(track.tpcNSigmaHe()) < nsigmaTPCvar.nsigmaTPCHe; + isAntiHeWTPCpid = isAntiHeWoTPCpid && std::abs(track.tpcNSigmaHe()) < nsigmaTPCvar.nsigmaTPCHe; + + passDCAxyzCut = passDCAxyCut && passDCAzCut; + + // DCAxy vs DCAz plots BEFORE cut + if (outFlagOptions.makeDCABeforeCutPlots) { + histos.fill(HIST("tracks/dca/before/hDCAxyVsDCAzVsPt"), track.dcaXY(), track.dcaZ(), track.pt()); + histos.fill(HIST("tracks/dca/before/hDCAxyVsDCAz"), track.dcaZ(), track.dcaXY()); + + if (isHe && std::abs(track.tpcNSigmaHe()) < nsigmaTPCvar.nsigmaTPCHe) { + histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsDCAzVsPtHelium"), track.dcaXY(), track.dcaZ(), hePt); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsDCAzVsPtHelium"), track.dcaXY(), track.dcaZ(), hePt); } } - if (enableDe && deRapCut) { - if (std::abs(track.tpcNSigmaDe()) < nsigmaTPCDe) { - if (usenITSLayer && !itsClusterMap.test(nITSLayer)) - continue; - if (track.sign() > 0) { - if (enableCentrality) - histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronVsMult"), DPt, track.dcaXY(), event.centFT0M()); - else - histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtDeuteron"), DPt, track.dcaXY()); - histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtDeuteron"), DPt, track.dcaZ()); - } else { - if (enableCentrality) - histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronVsMult"), antiDPt, track.dcaXY(), event.centFT0M()); - else - histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteron"), antiDPt, track.dcaXY()); - histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteron"), antiDPt, track.dcaZ()); - } + if (isAntiHe && std::abs(track.tpcNSigmaHe()) < nsigmaTPCvar.nsigmaTPCHe) { + histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsDCAzVsPtantiHelium"), track.dcaXY(), track.dcaZ(), antihePt); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsDCAzVsPtantiHelium"), track.dcaXY(), track.dcaZ(), antihePt); } } - if (enableTr && trRapCut) { - if (isTriton) { - if (track.sign() > 0) { - histos.fill(HIST("tracks/triton/dca/before/hDCAxyVsPtTriton"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtTriton"), track.pt(), track.dcaZ()); - } else { - histos.fill(HIST("tracks/triton/dca/before/hDCAxyVsPtantiTriton"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtantiTriton"), track.pt(), track.dcaZ()); + + if (passDCAxyCut) { + histos.fill(HIST("tracks/dca/before/hDCAz"), track.dcaZ()); + histos.fill(HIST("tracks/dca/before/hDCAzVsPt"), track.pt(), track.dcaZ()); + + if (enablePr && prRapCut) { + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCvar.nsigmaTPCPr) { + if (track.sign() > 0) { + histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtProton"), track.pt(), track.dcaZ()); + } else { + histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtantiProton"), track.pt(), track.dcaZ()); + } } } - } - } - if (enableHe && heRapCut && makeDCABeforeCutPlots) { - if (std::abs(track.tpcNSigmaHe()) < nsigmaTPCHe) { - if (track.sign() > 0) { - histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtHelium"), hePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtHelium"), hePt, track.dcaZ()); - if (track.hasTOF() && doTOFplots) { - histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtHelium"), hePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtHelium"), hePt, track.dcaZ()); + if (enableTr && trRapCut) { + if (isTritonTPCpid) { + if (track.sign() > 0) { + histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtTriton"), track.pt(), track.dcaZ()); + } else { + histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtantiTriton"), track.pt(), track.dcaZ()); + } } - } else { - histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtantiHelium"), antihePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtantiHelium"), antihePt, track.dcaZ()); - if (track.hasTOF() && doTOFplots) { - histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHelium"), antihePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtantiHelium"), antihePt, track.dcaZ()); + } + if (enableAl && alRapCut) { + if (std::abs(track.tpcNSigmaAl()) < nsigmaTPCvar.nsigmaTPCAl) { + if (track.sign() > 0) { + histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtAlpha"), track.pt(), track.dcaZ()); + } else { + histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtantiAlpha"), track.pt(), track.dcaZ()); + } } } } - } - if (makeDCABeforeCutPlots) { - if (enableAl && alRapCut) { - if (std::abs(track.tpcNSigmaAl()) < nsigmaTPCAl) { - if (track.sign() > 0) { - histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtAlpha"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtAlpha"), track.pt(), track.dcaZ()); - } else { - histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtantiAlpha"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtantiAlpha"), track.pt(), track.dcaZ()); - } + + if (isDeWoDCAzWTPCpid) { + histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtDeuteron"), DPt, track.dcaZ()); + if (!track.hasTOF()) + histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtDeuteronNoTOF"), DPt, track.dcaZ()); + } + + if (isAntiDeWoDCAzWTPCpid) { + histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteron"), antiDPt, track.dcaZ()); + if (!track.hasTOF()) + histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteronNoTOF"), antiDPt, track.dcaZ()); + } + + if (isHeWoDCAzWTPCpid) { + histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtHelium"), hePt, track.dcaZ()); + if (!track.hasTOF()) + histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtHeliumNoTOF"), hePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtHelium"), hePt, track.dcaZ()); + } + } + + if (isAntiHeWoDCAzWTPCpid) { + histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtantiHelium"), antihePt, track.dcaZ()); + if (!track.hasTOF()) + histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtantiHeliumNoTOF"), hePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtantiHelium"), antihePt, track.dcaZ()); } } } @@ -1952,19 +2577,14 @@ struct LFNucleiBATask { bool isPhysPrim = false; bool isProdByGen = false; bool isWeakDecay = false; - bool hasFakeHit = false; // PID int pdgCode = 0; - // gen Pt - float genPt = 0; if constexpr (IsFilteredData) { isPhysPrim = track.isPhysicalPrimary(); isProdByGen = track.producedByGenerator(); isWeakDecay = track.getProcess() == 4; pdgCode = track.pdgCode(); - genPt = TMath::Sqrt(TMath::Power(track.px(), 2) + TMath::Power(track.py(), 2)); - } else { if (!track.has_mcParticle()) { continue; @@ -1973,89 +2593,593 @@ struct LFNucleiBATask { isProdByGen = track.mcParticle().producedByGenerator(); isWeakDecay = track.mcParticle().getProcess() == 4; pdgCode = track.mcParticle().pdgCode(); - genPt = track.mcParticle().pt(); - - for (int i = 0; i < 10; i++) { // From ITS to TPC - if (track.mcMask() & 1 << i) { - hasFakeHit = true; - break; - } - } - if (hasFakeHit) { - debugHistos.fill(HIST("debug/h2TPCsignVsTPCmomentum_FakeHits"), track.tpcInnerParam() / (1.f * track.sign()), track.tpcSignal()); - } } - switch (pdgCode) { - case PDGProton: - if (enablePr && prRapCut && makeDCABeforeCutPlots) { - { - // if (makeDCABeforeCutPlots) { - histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtProtonTrue"), track.pt(), track.dcaXY()); + + if (outFlagOptions.makeDCABeforeCutPlots) { + switch (pdgCode) { + case PDGProton: + if (enablePr && prRapCut && passDCAxyCut) { histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtProtonTrue"), track.pt(), track.dcaZ()); - // } - } - if (isPhysPrim) { - // if constexpr (!IsFilteredData) { - // spectraGen.fill(HIST("proton/histPtShift_Pr"), track.pt(), track.pt() - track.mcParticle().pt()); - // } - // if (makeDCABeforeCutPlots) { - histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtProtonTruePrim"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtProtonTruePrim"), track.pt(), track.dcaZ()); - // } - } - if (!isPhysPrim && isProdByGen) { - // + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAzVsPtProtonTrue"), track.pt(), track.dcaZ()); + } + if (isPhysPrim) { + histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtProtonTruePrim"), track.pt(), track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAzVsPtProtonTruePrim"), track.pt(), track.dcaZ()); + } + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtProtonTrueTransport"), track.pt(), track.dcaZ()); + if (isWeakDecay) + histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtProtonTrueSec"), track.pt(), track.dcaZ()); + else + histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtProtonTrueMaterial"), track.pt(), track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAzVsPtProtonTrueTransport"), track.pt(), track.dcaZ()); + if (isWeakDecay) + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAzVsPtProtonTrueSec"), track.pt(), track.dcaZ()); + else + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAzVsPtProtonTrueMaterial"), track.pt(), track.dcaZ()); + } + } } - if (!isPhysPrim && !isProdByGen) { - // if (makeDCABeforeCutPlots) { - histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtProtonTrueTransport"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtProtonTrueTransport"), track.pt(), track.dcaZ()); - if (isWeakDecay) { - histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtProtonTrueSec"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtProtonTrueSec"), track.pt(), track.dcaZ()); + break; + case -PDGProton: + if (enablePr && prRapCut && passDCAxyCut) { + histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtantiProtonTrue"), track.pt(), track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAzVsPtantiProtonTrue"), track.pt(), track.dcaZ()); + } + if (isPhysPrim) { + histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtantiProtonTruePrim"), track.pt(), track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAzVsPtantiProtonTruePrim"), track.pt(), track.dcaZ()); + } + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtantiProtonTrueTransport"), track.pt(), track.dcaZ()); + if (isWeakDecay) + histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtantiProtonTrueSec"), track.pt(), track.dcaZ()); + else + histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtantiProtonTrueMaterial"), track.pt(), track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAzVsPtantiProtonTrueTransport"), hePt, track.dcaZ()); + if (isWeakDecay) + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAzVsPtantiProtonTrueSec"), hePt, track.dcaZ()); + else + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAzVsPtantiProtonTrueMaterial"), hePt, track.dcaZ()); + } + } + } + break; + case PDGDeuteron: + if (isDeWoDCAz) { + histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtDeuteronTrue"), DPt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAzVsPtDeuteronTrue"), DPt, track.dcaZ()); + } + if (isPhysPrim) { + histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtDeuteronTruePrim"), DPt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAzVsPtDeuteronTruePrim"), DPt, track.dcaZ()); + } + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtDeuteronTrueTransport"), DPt, track.dcaZ()); + if (isWeakDecay) + histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtDeuteronTrueSec"), DPt, track.dcaZ()); + else + histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtDeuteronTrueMaterial"), DPt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAzVsPtDeuteronTrueTransport"), DPt, track.dcaZ()); + if (isWeakDecay) + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAzVsPtDeuteronTrueSec"), DPt, track.dcaZ()); + else + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAzVsPtDeuteronTrueMaterial"), DPt, track.dcaZ()); + } + } + } + break; + case -PDGDeuteron: + if (isAntiDeWoDCAz) { + histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteronTrue"), antiDPt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAzVsPtantiDeuteronTrue"), antiDPt, track.dcaZ()); + } + if (isPhysPrim) { + histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteronTruePrim"), antiDPt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAzVsPtantiDeuteronTruePrim"), antiDPt, track.dcaZ()); + } + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteronTrueTransport"), antiDPt, track.dcaZ()); + if (isWeakDecay) + histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteronTrueSec"), antiDPt, track.dcaZ()); + else + histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteronTrueMaterial"), antiDPt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAzVsPtantiDeuteronTrueTransport"), antiDPt, track.dcaZ()); + if (isWeakDecay) + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAzVsPtantiDeuteronTrueSec"), antiDPt, track.dcaZ()); + else + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAzVsPtantiDeuteronTrueMaterial"), antiDPt, track.dcaZ()); + } + } + } + break; + case PDGTriton: + if (enableTr && trRapCut && passDCAxyCut) { + histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtTritonTrue"), track.pt(), track.dcaZ()); + if (isPhysPrim) { + histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtTritonTruePrim"), track.pt(), track.dcaZ()); + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtTritonTrueTransport"), track.pt(), track.dcaZ()); + if (isWeakDecay) + histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtTritonTrueSec"), track.pt(), track.dcaZ()); + else + histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtTritonTrueMaterial"), track.pt(), track.dcaZ()); + } + } + break; + case -PDGTriton: + if (enableTr && trRapCut && passDCAxyCut) { + histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtantiTritonTrue"), track.pt(), track.dcaZ()); + if (isPhysPrim) { + histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtantiTritonTruePrim"), track.pt(), track.dcaZ()); + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtantiTritonTrueTransport"), track.pt(), track.dcaZ()); + if (isWeakDecay) + histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtantiTritonTrueSec"), track.pt(), track.dcaZ()); + else + histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtantiTritonTrueMaterial"), track.pt(), track.dcaZ()); + } + } + break; + case PDGHelium: + if (isHeWoDCAz) { + histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtHeliumTrue"), hePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTrue"), hePt, track.dcaZ()); + } + if (isPhysPrim) { + histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtHeliumTruePrim"), hePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTruePrim"), hePt, track.dcaZ()); + } + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtHeliumTrueTransport"), hePt, track.dcaZ()); + if (isWeakDecay) + histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtHeliumTrueSec"), hePt, track.dcaZ()); + else + histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtHeliumTrueMaterial"), hePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTrueTransport"), hePt, track.dcaZ()); + if (isWeakDecay) + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTrueSec"), hePt, track.dcaZ()); + else + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTrueMaterial"), hePt, track.dcaZ()); + } + } + } + if constexpr (!IsFilteredData) { + if ((event.has_mcCollision() && (track.mcParticle().mcCollisionId() != event.mcCollisionId())) || !event.has_mcCollision()) { + if (isHeWoDCAz && outFlagOptions.makeWrongEventPlots) { + histos.fill(HIST("tracks/helium/dca/before/wrong/hDCAzVsPtHeliumTrue"), hePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/wrong/TOF/hDCAzVsPtHeliumTrue"), hePt, track.dcaZ()); + } + if (isPhysPrim) { + histos.fill(HIST("tracks/helium/dca/before/wrong/hDCAzVsPtHeliumTruePrim"), hePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/wrong/TOF/hDCAzVsPtHeliumTruePrim"), hePt, track.dcaZ()); + } + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/helium/dca/before/wrong/hDCAzVsPtHeliumTrueTransport"), hePt, track.dcaZ()); + if (isWeakDecay) { + histos.fill(HIST("tracks/helium/dca/before/wrong/hDCAzVsPtHeliumTrueSec"), hePt, track.dcaZ()); + } + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/wrong/TOF/hDCAzVsPtHeliumTrueTransport"), hePt, track.dcaZ()); + if (isWeakDecay) { + histos.fill(HIST("tracks/helium/dca/before/wrong/TOF/hDCAzVsPtHeliumTrueSec"), hePt, track.dcaZ()); + } + } + } + } + } + } + break; + case -PDGHelium: + if (isAntiHeWoDCAz) { + histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtantiHeliumTrue"), antihePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTrue"), antihePt, track.dcaZ()); + } + if (isPhysPrim) { + histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtantiHeliumTruePrim"), antihePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTruePrim"), antihePt, track.dcaZ()); + } + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtantiHeliumTrueTransport"), antihePt, track.dcaZ()); + if (isWeakDecay) + histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtantiHeliumTrueSec"), antihePt, track.dcaZ()); + else + histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtantiHeliumTrueMaterial"), antihePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTrueTransport"), antihePt, track.dcaZ()); + if (isWeakDecay) + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTrueSec"), antihePt, track.dcaZ()); + else + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTrueMaterial"), antihePt, track.dcaZ()); + } + } + } + if constexpr (!IsFilteredData) { + if ((event.has_mcCollision() && (track.mcParticle().mcCollisionId() != event.mcCollisionId())) || !event.has_mcCollision()) { + if (isAntiHeWoDCAz && outFlagOptions.makeWrongEventPlots) { + histos.fill(HIST("tracks/helium/dca/before/wrong/hDCAzVsPtantiHeliumTrue"), antihePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/wrong/TOF/hDCAzVsPtantiHeliumTrue"), antihePt, track.dcaZ()); + } + if (isPhysPrim) { + histos.fill(HIST("tracks/helium/dca/before/wrong/hDCAzVsPtantiHeliumTruePrim"), antihePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/wrong/TOF/hDCAzVsPtantiHeliumTruePrim"), antihePt, track.dcaZ()); + } + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/helium/dca/before/wrong/hDCAzVsPtantiHeliumTrueTransport"), antihePt, track.dcaZ()); + if (isWeakDecay) { + histos.fill(HIST("tracks/helium/dca/before/wrong/hDCAzVsPtantiHeliumTrueSec"), antihePt, track.dcaZ()); + } + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/wrong/TOF/hDCAzVsPtantiHeliumTrueTransport"), antihePt, track.dcaZ()); + if (isWeakDecay) { + histos.fill(HIST("tracks/helium/dca/before/wrong/TOF/hDCAzVsPtantiHeliumTrueSec"), antihePt, track.dcaZ()); + } + } + } + } + } + } + + break; + case PDGAlpha: + if (enableAl && alRapCut && passDCAxyCut) { + histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtAlphaTrue"), track.pt(), track.dcaZ()); + if (isPhysPrim) { + histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtAlphaTruePrim"), track.pt(), track.dcaZ()); + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtAlphaTrueTransport"), track.pt(), track.dcaZ()); + if (isWeakDecay) + histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtAlphaTrueSec"), track.pt(), track.dcaZ()); + else + histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtAlphaTrueMaterial"), track.pt(), track.dcaZ()); + } + } + break; + case -PDGAlpha: + if (enableAl && alRapCut && passDCAxyCut) { + histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtantiAlphaTrue"), track.pt(), track.dcaZ()); + if (isPhysPrim) { + histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtantiAlphaTruePrim"), track.pt(), track.dcaZ()); + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtantiAlphaTrueTransport"), track.pt(), track.dcaZ()); + if (isWeakDecay) + histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtantiAlphaTrueSec"), track.pt(), track.dcaZ()); + else + histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtantiAlphaTrueMaterial"), track.pt(), track.dcaZ()); + } + } + break; + default: + break; + } + switch (std::abs(pdgCode)) { + case PDGDeuteron: + // + break; + default: + if (isDeWoDCAzWTPCpid && outFlagOptions.makeFakeTracksPlots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAzVsPtDeuteronTrue"), DPt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAzVsPtDeuteronTrue"), DPt, track.dcaZ()); + } + if (isPhysPrim) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAzVsPtDeuteronTruePrim"), DPt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAzVsPtDeuteronTruePrim"), DPt, track.dcaZ()); + } + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAzVsPtDeuteronTrueTransport"), DPt, track.dcaZ()); + if (isWeakDecay) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAzVsPtDeuteronTrueSec"), DPt, track.dcaZ()); + } + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAzVsPtDeuteronTrueTransport"), DPt, track.dcaZ()); + if (isWeakDecay) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAzVsPtDeuteronTrueSec"), DPt, track.dcaZ()); + } + } + } + } else if (isAntiDeWoDCAzWTPCpid && outFlagOptions.makeFakeTracksPlots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAzVsPtantiDeuteronTrue"), antiDPt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAzVsPtantiDeuteronTrue"), antiDPt, track.dcaZ()); + } + if (isPhysPrim) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAzVsPtantiDeuteronTruePrim"), antiDPt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAzVsPtantiDeuteronTruePrim"), antiDPt, track.dcaZ()); + } + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAzVsPtantiDeuteronTrueTransport"), antiDPt, track.dcaZ()); + if (isWeakDecay) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAzVsPtantiDeuteronTrueSec"), antiDPt, track.dcaZ()); + } + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAzVsPtantiDeuteronTrueTransport"), antiDPt, track.dcaZ()); + if (isWeakDecay) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAzVsPtantiDeuteronTrueSec"), antiDPt, track.dcaZ()); + } + } + } + } + break; + } + + switch (std::abs(pdgCode)) { + case PDGHelium: + // + break; + default: + if (isHeWoDCAzWTPCpid && outFlagOptions.makeFakeTracksPlots) { + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAzVsPtHeliumTrue"), hePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAzVsPtHeliumTrue"), hePt, track.dcaZ()); + } + if (isPhysPrim) { + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAzVsPtHeliumTruePrim"), hePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAzVsPtHeliumTruePrim"), hePt, track.dcaZ()); + } + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAzVsPtHeliumTrueTransport"), hePt, track.dcaZ()); + if (isWeakDecay) { + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAzVsPtHeliumTrueSec"), hePt, track.dcaZ()); + } + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAzVsPtHeliumTrueTransport"), hePt, track.dcaZ()); + if (isWeakDecay) { + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAzVsPtHeliumTrueSec"), hePt, track.dcaZ()); + } + } + } + } + if (isAntiHeWoDCAzWTPCpid && outFlagOptions.makeFakeTracksPlots) { + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAzVsPtantiHeliumTrue"), antihePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAzVsPtantiHeliumTrue"), antihePt, track.dcaZ()); + } + if (isPhysPrim) { + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAzVsPtantiHeliumTruePrim"), antihePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAzVsPtantiHeliumTruePrim"), antihePt, track.dcaZ()); + } + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAzVsPtantiHeliumTrueTransport"), antihePt, track.dcaZ()); + if (isWeakDecay) { + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAzVsPtantiHeliumTrueSec"), antihePt, track.dcaZ()); + } + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAzVsPtantiHeliumTrueTransport"), antihePt, track.dcaZ()); + if (isWeakDecay) { + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAzVsPtantiHeliumTrueSec"), antihePt, track.dcaZ()); + } + } + } + } + break; + } + } + } + // Tracks DCA histos fill + if (outFlagOptions.makeDCABeforeCutPlots) { + if (passDCAzCut) { + histos.fill(HIST("tracks/dca/before/hDCAxy"), track.dcaXY()); + histos.fill(HIST("tracks/dca/before/hDCAxyVsPt"), track.pt(), track.dcaXY()); + + if (enablePr && prRapCut) { + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCvar.nsigmaTPCPr) { + if (track.sign() > 0) { + histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtProton"), track.pt(), track.dcaXY()); + } else { + histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtantiProton"), track.pt(), track.dcaXY()); + } + } + } + + if (enableTr && trRapCut) { + if (isTritonTPCpid) { + if (track.sign() > 0) { + histos.fill(HIST("tracks/triton/dca/before/hDCAxyVsPtTriton"), track.pt(), track.dcaXY()); + } else { + histos.fill(HIST("tracks/triton/dca/before/hDCAxyVsPtantiTriton"), track.pt(), track.dcaXY()); + } + } + } + if (enableAl && alRapCut) { + if (std::abs(track.tpcNSigmaAl()) < nsigmaTPCvar.nsigmaTPCAl) { + if (track.sign() > 0) { + histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtAlpha"), track.pt(), track.dcaXY()); + } else { + histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtantiAlpha"), track.pt(), track.dcaXY()); + } + } + } + } + + if (isDeWoDCAxyWTPCpid) { + if (usenITSLayer && !itsClusterMap.test(trkqcOptions.nITSLayer)) + continue; + if (enableCentrality) + histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronVsMult"), DPt, track.dcaXY(), event.centFT0M()); + else + histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtDeuteron"), DPt, track.dcaXY()); + if (!track.hasTOF()) + histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronNoTOF"), DPt, track.dcaXY()); + } + if (isAntiDeWoDCAxyWTPCpid) { + if (usenITSLayer && !itsClusterMap.test(trkqcOptions.nITSLayer)) + continue; + if (enableCentrality) + histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronVsMult"), antiDPt, track.dcaXY(), event.centFT0M()); + else + histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteron"), antiDPt, track.dcaXY()); + if (!track.hasTOF()) + histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronNoTOF"), antiDPt, track.dcaXY()); + } + + if (isHeWoDCAxyWTPCpid) { + histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtHelium"), hePt, track.dcaXY()); + if (!track.hasTOF()) + histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtHeliumNoTOF"), hePt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtHelium"), hePt, track.dcaXY()); + } + } + if (isAntiHeWoDCAxyWTPCpid) { + histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtantiHelium"), antihePt, track.dcaXY()); + if (!track.hasTOF()) + histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtantiHeliumNoTOF"), antihePt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHelium"), antihePt, track.dcaXY()); + } + } + } + + if constexpr (IsMC) { + bool isPhysPrim = false; + bool isProdByGen = false; + bool isWeakDecay = false; + bool hasFakeHit = false; + + // PID + int pdgCode = 0; + // gen Pt + float genPt = 0; + if constexpr (IsFilteredData) { + isPhysPrim = track.isPhysicalPrimary(); + isProdByGen = track.producedByGenerator(); + isWeakDecay = track.getProcess() == 4; + pdgCode = track.pdgCode(); + genPt = std::sqrt(std::pow(track.px(), 2) + std::pow(track.py(), 2)); + + } else { + if (!track.has_mcParticle()) { + continue; + } + isPhysPrim = track.mcParticle().isPhysicalPrimary(); + isProdByGen = track.mcParticle().producedByGenerator(); + isWeakDecay = track.mcParticle().getProcess() == 4; + pdgCode = track.mcParticle().pdgCode(); + genPt = track.mcParticle().pt(); + + for (int i = 0; i < 10; i++) { // From ITS to TPC + if (track.mcMask() & 1 << i) { + hasFakeHit = true; + break; + } + } + if (hasFakeHit && passDCAzCut) { + debugHistos.fill(HIST("debug/h2TPCsignVsTPCmomentum_FakeHits"), track.tpcInnerParam() / (1.f * track.sign()), track.tpcSignal()); + } + } + switch (pdgCode) { + case PDGProton: + if (enablePr && prRapCut && outFlagOptions.makeDCABeforeCutPlots && passDCAzCut) { + histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtProtonTrue"), track.pt(), track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAxyVsPtProtonTrue"), track.pt(), track.dcaXY()); + } + if (isPhysPrim) { + histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtProtonTruePrim"), track.pt(), track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAxyVsPtProtonTruePrim"), track.pt(), track.dcaXY()); + } + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtProtonTrueTransport"), track.pt(), track.dcaXY()); + if (isWeakDecay) + histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtProtonTrueSec"), track.pt(), track.dcaXY()); + else + histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtProtonTrueMaterial"), track.pt(), track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAxyVsPtProtonTrueTransport"), track.pt(), track.dcaXY()); + if (isWeakDecay) + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAxyVsPtProtonTrueSec"), track.pt(), track.dcaXY()); + else + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAxyVsPtProtonTrueMaterial"), track.pt(), track.dcaXY()); } - // } } } break; case -PDGProton: - if (enablePr && prRapCut && makeDCABeforeCutPlots) { - // if (makeDCABeforeCutPlots) { + if (enablePr && prRapCut && outFlagOptions.makeDCABeforeCutPlots && passDCAzCut) { histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtantiProtonTrue"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtantiProtonTrue"), track.pt(), track.dcaZ()); - // } - + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAxyVsPtantiProtonTrue"), track.pt(), track.dcaXY()); + } if (isPhysPrim) { - // if (makeDCABeforeCutPlots) { histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtantiProtonTruePrim"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtantiProtonTruePrim"), track.pt(), track.dcaZ()); - // } - } - if (!isPhysPrim && isProdByGen) { - // + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAxyVsPtantiProtonTruePrim"), track.pt(), track.dcaXY()); + } } if (!isPhysPrim && !isProdByGen) { - // if (makeDCABeforeCutPlots) { histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtantiProtonTrueTransport"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtantiProtonTrueTransport"), track.pt(), track.dcaZ()); - if (isWeakDecay) { + if (isWeakDecay) histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtantiProtonTrueSec"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/proton/dca/before/hDCAzVsPtantiProtonTrueSec"), track.pt(), track.dcaZ()); + else + histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtantiProtonTrueMaterial"), track.pt(), track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAxyVsPtantiProtonTrueTransport"), track.pt(), track.dcaXY()); + if (isWeakDecay) + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAxyVsPtantiProtonTrueSec"), track.pt(), track.dcaXY()); + else + histos.fill(HIST("tracks/proton/dca/before/TOF/hDCAxyVsPtantiProtonTrueMaterial"), track.pt(), track.dcaXY()); } - // } } } break; case PDGDeuteron: - if (enableDe && deRapCut) { - if (makeDCABeforeCutPlots) { + if (isDeWoDCAxy) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronTrue"), DPt, track.dcaXY()); - histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtDeuteronTrue"), DPt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAxyVsPtDeuteronTrue"), DPt, track.dcaXY()); + } } if (isPhysPrim) { - if (makeDCABeforeCutPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronTruePrim"), DPt, track.dcaXY()); - histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtDeuteronTruePrim"), DPt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAxyVsPtDeuteronTruePrim"), DPt, track.dcaXY()); + } } if constexpr (IsFilteredData) { spectraGen.fill(HIST("deuteron/histDeuteronPtShift"), track.pt(), track.pt() - genPt); @@ -2074,27 +3198,37 @@ struct LFNucleiBATask { } } if (!isPhysPrim && !isProdByGen) { - if (makeDCABeforeCutPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronTrueTransport"), DPt, track.dcaXY()); - histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtDeuteronTrueTransport"), DPt, track.dcaZ()); - if (isWeakDecay) { + if (isWeakDecay) histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronTrueSec"), DPt, track.dcaXY()); - histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtDeuteronTrueSec"), DPt, track.dcaZ()); + else + histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronTrueMaterial"), DPt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAxyVsPtDeuteronTrueTransport"), DPt, track.dcaXY()); + if (isWeakDecay) + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAxyVsPtDeuteronTrueSec"), DPt, track.dcaXY()); + else + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAxyVsPtDeuteronTrueMaterial"), DPt, track.dcaXY()); } } } } break; case -PDGDeuteron: - if (enableDe && deRapCut) { - if (makeDCABeforeCutPlots) { + if (isAntiDeWoDCAxy) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronTrue"), antiDPt, track.dcaXY()); - histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteronTrue"), antiDPt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAxyVsPtantiDeuteronTrue"), antiDPt, track.dcaXY()); + } } if (isPhysPrim) { - if (makeDCABeforeCutPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronTruePrim"), antiDPt, track.dcaXY()); - histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteronTruePrim"), antiDPt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAxyVsPtantiDeuteronTruePrim"), antiDPt, track.dcaXY()); + } } if constexpr (IsFilteredData) { spectraGen.fill(HIST("deuteron/histAntiDeuteronPtShift"), track.pt(), track.pt() - genPt); @@ -2113,70 +3247,97 @@ struct LFNucleiBATask { } } if (!isPhysPrim && !isProdByGen) { - if (makeDCABeforeCutPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronTrueTransport"), antiDPt, track.dcaXY()); - histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteronTrueTransport"), antiDPt, track.dcaZ()); - if (isWeakDecay) { + if (isWeakDecay) histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronTrueSec"), antiDPt, track.dcaXY()); - histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtantiDeuteronTrueSec"), antiDPt, track.dcaZ()); + else + histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronTrueMaterial"), antiDPt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAxyVsPtantiDeuteronTrueTransport"), antiDPt, track.dcaXY()); + if (isWeakDecay) + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAxyVsPtantiDeuteronTrueSec"), antiDPt, track.dcaXY()); + else + histos.fill(HIST("tracks/deuteron/dca/before/TOF/hDCAxyVsPtantiDeuteronTrueMaterial"), antiDPt, track.dcaXY()); } } } } break; case PDGTriton: - if (enableTr && trRapCut && makeDCABeforeCutPlots) { + if (enableTr && trRapCut && outFlagOptions.makeDCABeforeCutPlots && passDCAzCut) { histos.fill(HIST("tracks/triton/dca/before/hDCAxyVsPtTritonTrue"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtTritonTrue"), track.pt(), track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/triton/dca/before/TOF/hDCAxyVsPtTritonTrue"), track.pt(), track.dcaXY()); + } if (isPhysPrim) { histos.fill(HIST("tracks/triton/dca/before/hDCAxyVsPtTritonTruePrim"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtTritonTruePrim"), track.pt(), track.dcaZ()); - } - if (!isPhysPrim && isProdByGen) { - // + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/triton/dca/before/TOF/hDCAxyVsPtTritonTruePrim"), track.pt(), track.dcaXY()); + } } if (!isPhysPrim && !isProdByGen) { histos.fill(HIST("tracks/triton/dca/before/hDCAxyVsPtTritonTrueTransport"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtTritonTrueTransport"), track.pt(), track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/triton/dca/before/TOF/hDCAxyVsPtTritonTrueTransport"), track.pt(), track.dcaXY()); + } if (isWeakDecay) { histos.fill(HIST("tracks/triton/dca/before/hDCAxyVsPtTritonTrueSec"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtTritonTrueSec"), track.pt(), track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/triton/dca/before/TOF/hDCAxyVsPtTritonTrueSec"), track.pt(), track.dcaXY()); + } + } else { + histos.fill(HIST("tracks/triton/dca/before/hDCAxyVsPtTritonTrueMaterial"), track.pt(), track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/triton/dca/before/TOF/hDCAxyVsPtTritonTrueMaterial"), track.pt(), track.dcaXY()); + } } } } break; case -PDGTriton: - if (enableTr && trRapCut && makeDCABeforeCutPlots) { + if (enableTr && trRapCut && outFlagOptions.makeDCABeforeCutPlots && passDCAzCut) { histos.fill(HIST("tracks/triton/dca/before/hDCAxyVsPtantiTritonTrue"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtantiTritonTrue"), track.pt(), track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/triton/dca/before/TOF/hDCAxyVsPtantiTritonTrue"), track.pt(), track.dcaXY()); + } + if (isPhysPrim) { histos.fill(HIST("tracks/triton/dca/before/hDCAxyVsPtantiTritonTruePrim"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtantiTritonTruePrim"), track.pt(), track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/triton/dca/before/TOF/hDCAxyVsPtantiTritonTruePrim"), track.pt(), track.dcaXY()); + } } if (!isPhysPrim && isProdByGen) { // } if (!isPhysPrim && !isProdByGen) { histos.fill(HIST("tracks/triton/dca/before/hDCAxyVsPtantiTritonTrueTransport"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtantiTritonTrueTransport"), track.pt(), track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/triton/dca/before/TOF/hDCAxyVsPtantiTritonTrueTransport"), track.pt(), track.dcaXY()); + } if (isWeakDecay) { histos.fill(HIST("tracks/triton/dca/before/hDCAxyVsPtantiTritonTrueSec"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/triton/dca/before/hDCAzVsPtantiTritonTrueSec"), track.pt(), track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/triton/dca/before/TOF/hDCAxyVsPtantiTritonTrueSec"), track.pt(), track.dcaXY()); + } + } else { + histos.fill(HIST("tracks/triton/dca/before/hDCAxyVsPtantiTritonTrueMaterial"), track.pt(), track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/triton/dca/before/TOF/hDCAxyVsPtantiTritonTrueMaterial"), track.pt(), track.dcaXY()); + } } } } break; case PDGHelium: - if (enableHe && heRapCut) { - if (makeDCABeforeCutPlots) { + if (isHeWoDCAxy) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtHeliumTrue"), hePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtHeliumTrue"), hePt, track.dcaZ()); - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtHeliumTrue"), hePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTrue"), hePt, track.dcaZ()); } } - if (isPhysPrim) { if constexpr (!IsFilteredData) { spectraGen.fill(HIST("helium/histPtGenHe"), std::abs(track.mcParticle().pt())); @@ -2189,53 +3350,63 @@ struct LFNucleiBATask { spectraGen.fill(HIST("helium/histPShiftHe"), 2.f * heP, 2.f * heP - track.mcParticle().p()); spectraGen.fill(HIST("helium/histPShiftVsEtaHe"), track.eta(), 2.f * heP - track.mcParticle().p()); } - if (makeDCABeforeCutPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtHeliumTruePrim"), hePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtHeliumTruePrim"), hePt, track.dcaZ()); - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtHeliumTruePrim"), hePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTruePrim"), hePt, track.dcaZ()); } } } - // if (!isPhysPrim && isProdByGen) { - // // - // if (track.hasTOF() && doTOFplots) { - // // - // } - // } - if (!isPhysPrim && !isProdByGen && makeDCABeforeCutPlots) { - // if (makeDCABeforeCutPlots) { + if (!isPhysPrim && !isProdByGen && outFlagOptions.makeDCABeforeCutPlots) { histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtHeliumTrueTransport"), hePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtHeliumTrueTransport"), hePt, track.dcaZ()); - - if (isWeakDecay) { + if (isWeakDecay) histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtHeliumTrueSec"), hePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtHeliumTrueSec"), hePt, track.dcaZ()); - } - // } - - if (track.hasTOF() && doTOFplots) { - // if (makeDCABeforeCutPlots) { + else + histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtHeliumTrueMaterial"), hePt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtHeliumTrueTransport"), hePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTrueTransport"), hePt, track.dcaZ()); - if (isWeakDecay) { + if (isWeakDecay) histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtHeliumTrueSec"), hePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtHeliumTrueSec"), hePt, track.dcaZ()); + else + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtHeliumTrueMaterial"), hePt, track.dcaXY()); + } + } + } + if constexpr (!IsFilteredData) { + if ((event.has_mcCollision() && (track.mcParticle().mcCollisionId() != event.mcCollisionId())) || !event.has_mcCollision()) { + if (isHeWoDCAxy && outFlagOptions.makeDCABeforeCutPlots && outFlagOptions.makeWrongEventPlots) { + histos.fill(HIST("tracks/helium/dca/before/wrong/hDCAxyVsPtHeliumTrue"), hePt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/wrong/TOF/hDCAxyVsPtHeliumTrue"), hePt, track.dcaXY()); + } + if (isPhysPrim) { + histos.fill(HIST("tracks/helium/dca/before/wrong/hDCAxyVsPtHeliumTruePrim"), hePt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/wrong/TOF/hDCAxyVsPtHeliumTruePrim"), hePt, track.dcaXY()); + } + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/helium/dca/before/wrong/hDCAxyVsPtHeliumTrueTransport"), hePt, track.dcaXY()); + if (isWeakDecay) { + histos.fill(HIST("tracks/helium/dca/before/wrong/hDCAxyVsPtHeliumTrueSec"), hePt, track.dcaXY()); + } + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/wrong/TOF/hDCAxyVsPtHeliumTrueTransport"), hePt, track.dcaXY()); + if (isWeakDecay) { + histos.fill(HIST("tracks/helium/dca/before/wrong/TOF/hDCAxyVsPtHeliumTrueSec"), hePt, track.dcaXY()); + } + } } - // } } } } break; case -PDGHelium: - if (enableHe && heRapCut) { - if (makeDCABeforeCutPlots) { + if (isAntiHeWoDCAxy) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtantiHeliumTrue"), antihePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtantiHeliumTrue"), antihePt, track.dcaZ()); - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHeliumTrue"), antihePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTrue"), antihePt, track.dcaZ()); } } if (isPhysPrim) { @@ -2250,95 +3421,238 @@ struct LFNucleiBATask { spectraGen.fill(HIST("helium/histPShiftantiHe"), 2.f * antiheP, 2.f * antiheP - track.mcParticle().p()); spectraGen.fill(HIST("helium/histPShiftVsEtaantiHe"), track.eta(), 2.f * antiheP - track.mcParticle().p()); } - if (makeDCABeforeCutPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtantiHeliumTruePrim"), antihePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtantiHeliumTruePrim"), antihePt, track.dcaZ()); - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHeliumTruePrim"), antihePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTruePrim"), antihePt, track.dcaZ()); } } } - if (!isPhysPrim && !isProdByGen && makeDCABeforeCutPlots) { - // if (makeDCABeforeCutPlots) { + if (!isPhysPrim && !isProdByGen && outFlagOptions.makeDCABeforeCutPlots) { histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtantiHeliumTrueTransport"), antihePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtantiHeliumTrueTransport"), antihePt, track.dcaZ()); - if (isWeakDecay) { + if (isWeakDecay) histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtantiHeliumTrueSec"), antihePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtantiHeliumTrueSec"), antihePt, track.dcaZ()); - } - // } + else + histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtantiHeliumTrueMaterial"), antihePt, track.dcaXY()); - if (track.hasTOF() && doTOFplots) { - // if (makeDCABeforeCutPlots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHeliumTrueTransport"), antihePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTrueTransport"), antihePt, track.dcaZ()); - if (isWeakDecay) { + if (isWeakDecay) histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHeliumTrueSec"), antihePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAzVsPtantiHeliumTrueSec"), antihePt, track.dcaZ()); + else + histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHeliumTrueMaterial"), antihePt, track.dcaXY()); + } + } + } + if constexpr (!IsFilteredData) { + if ((event.has_mcCollision() && (track.mcParticle().mcCollisionId() != event.mcCollisionId())) || !event.has_mcCollision()) { + if (isAntiHeWoDCAxy && outFlagOptions.makeDCABeforeCutPlots && outFlagOptions.makeWrongEventPlots) { + histos.fill(HIST("tracks/helium/dca/before/wrong/hDCAxyVsPtantiHeliumTrue"), antihePt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/wrong/TOF/hDCAxyVsPtantiHeliumTrue"), antihePt, track.dcaXY()); + } + if (isPhysPrim) { + histos.fill(HIST("tracks/helium/dca/before/wrong/hDCAxyVsPtantiHeliumTruePrim"), antihePt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/wrong/TOF/hDCAxyVsPtantiHeliumTruePrim"), antihePt, track.dcaXY()); + } + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/helium/dca/before/wrong/hDCAxyVsPtantiHeliumTrueTransport"), antihePt, track.dcaXY()); + if (isWeakDecay) { + histos.fill(HIST("tracks/helium/dca/before/wrong/hDCAxyVsPtantiHeliumTrueSec"), antihePt, track.dcaXY()); + } + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/wrong/TOF/hDCAxyVsPtantiHeliumTrueTransport"), antihePt, track.dcaXY()); + if (isWeakDecay) { + histos.fill(HIST("tracks/helium/dca/before/wrong/TOF/hDCAxyVsPtantiHeliumTrueSec"), antihePt, track.dcaXY()); + } + } } - // } } } } break; case PDGAlpha: - if (enableAl && alRapCut && makeDCABeforeCutPlots) { + if (enableAl && alRapCut && outFlagOptions.makeDCABeforeCutPlots && passDCAzCut) { histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtAlphaTrue"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtAlphaTrue"), track.pt(), track.dcaZ()); if (isPhysPrim) { histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtAlphaTruePrim"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtAlphaTruePrim"), track.pt(), track.dcaZ()); } - // if (!isPhysPrim && isProdByGen) { - // // - // } if (!isPhysPrim && !isProdByGen) { histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtAlphaTrueTransport"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtAlphaTrueTransport"), track.pt(), track.dcaZ()); - if (isWeakDecay) { + if (isWeakDecay) histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtAlphaTrueSec"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtAlphaTrueSec"), track.pt(), track.dcaZ()); - } + else + histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtAlphaTrueMaterial"), track.pt(), track.dcaXY()); } } break; case -PDGAlpha: - if (enableAl && alRapCut && makeDCABeforeCutPlots) { + if (enableAl && alRapCut && outFlagOptions.makeDCABeforeCutPlots && passDCAzCut) { histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtantiAlphaTrue"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtantiAlphaTrue"), track.pt(), track.dcaZ()); if (isPhysPrim) { histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtantiAlphaTruePrim"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtantiAlphaTruePrim"), track.pt(), track.dcaZ()); } - // if (!isPhysPrim && isProdByGen) { - // // - // } if (!isPhysPrim && !isProdByGen) { histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtantiAlphaTrueTransport"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtantiAlphaTrueTransport"), track.pt(), track.dcaZ()); - if (isWeakDecay) { + if (isWeakDecay) histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtantiAlphaTrueSec"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/alpha/dca/before/hDCAzVsPtantiAlphaTrueSec"), track.pt(), track.dcaZ()); + else + histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtantiAlphaTrueMaterial"), track.pt(), track.dcaXY()); + } + } + break; + default: + break; + } + switch (std::abs(pdgCode)) { + case PDGDeuteron: + // + break; + default: + if (isDeWoDCAxyWTPCpid && outFlagOptions.makeFakeTracksPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAxyVsPtDeuteronTrue"), DPt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtDeuteronTrue"), DPt, track.dcaXY()); + } + } + if (isPhysPrim) { + if (outFlagOptions.makeDCABeforeCutPlots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAxyVsPtDeuteronTruePrim"), DPt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtDeuteronTruePrim"), DPt, track.dcaXY()); + } + } + } + if (!isPhysPrim && !isProdByGen) { + if (outFlagOptions.makeDCABeforeCutPlots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAxyVsPtDeuteronTrueTransport"), DPt, track.dcaXY()); + if (isWeakDecay) + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAxyVsPtDeuteronTrueSec"), DPt, track.dcaXY()); + else + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAxyVsPtDeuteronTrueMaterial"), DPt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtDeuteronTrueTransport"), DPt, track.dcaXY()); + if (isWeakDecay) + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtDeuteronTrueSec"), DPt, track.dcaXY()); + else + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtDeuteronTrueMaterial"), DPt, track.dcaXY()); + } + } + } + } + if (isAntiDeWoDCAxyWTPCpid && outFlagOptions.makeFakeTracksPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAxyVsPtantiDeuteronTrue"), antiDPt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtantiDeuteronTrue"), antiDPt, track.dcaXY()); + } + } + if (isPhysPrim) { + if (outFlagOptions.makeDCABeforeCutPlots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAxyVsPtantiDeuteronTruePrim"), antiDPt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtantiDeuteronTruePrim"), antiDPt, track.dcaXY()); + } + } + } + if (!isPhysPrim && !isProdByGen) { + if (outFlagOptions.makeDCABeforeCutPlots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAxyVsPtantiDeuteronTrueTransport"), antiDPt, track.dcaXY()); + if (isWeakDecay) + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAxyVsPtantiDeuteronTrueSec"), antiDPt, track.dcaXY()); + else + histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAxyVsPtantiDeuteronTrueMaterial"), antiDPt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtantiDeuteronTrueTransport"), antiDPt, track.dcaXY()); + if (isWeakDecay) + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtantiDeuteronTrueSec"), antiDPt, track.dcaXY()); + else + histos.fill(HIST("tracks/deuteron/dca/before/fake/TOF/hDCAxyVsPtantiDeuteronTrueMaterial"), antiDPt, track.dcaXY()); + } } } } break; + } + + switch (std::abs(pdgCode)) { + case PDGHelium: + // + break; default: + if (isHeWoDCAxyWTPCpid && outFlagOptions.makeFakeTracksPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAxyVsPtHeliumTrue"), hePt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtHeliumTrue"), hePt, track.dcaXY()); + } + if (isPhysPrim) { + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAxyVsPtHeliumTruePrim"), hePt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtHeliumTruePrim"), hePt, track.dcaXY()); + } + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAxyVsPtHeliumTrueTransport"), hePt, track.dcaXY()); + if (isWeakDecay) + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAxyVsPtHeliumTrueSec"), hePt, track.dcaXY()); + else + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAxyVsPtHeliumTrueMaterial"), hePt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtHeliumTrueTransport"), hePt, track.dcaXY()); + if (isWeakDecay) + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtHeliumTrueSec"), hePt, track.dcaXY()); + else + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtHeliumTrueMaterial"), hePt, track.dcaXY()); + } + } + } + } + if (isAntiHeWoDCAxyWTPCpid && outFlagOptions.makeFakeTracksPlots) { + if (outFlagOptions.makeDCABeforeCutPlots) { + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAxyVsPtantiHeliumTrue"), antihePt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtantiHeliumTrue"), antihePt, track.dcaXY()); + } + if (isPhysPrim) { + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAxyVsPtantiHeliumTruePrim"), antihePt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtantiHeliumTruePrim"), antihePt, track.dcaXY()); + } + } + if (!isPhysPrim && !isProdByGen) { + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAxyVsPtantiHeliumTrueTransport"), antihePt, track.dcaXY()); + if (isWeakDecay) + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAxyVsPtantiHeliumTrueSec"), antihePt, track.dcaXY()); + else + histos.fill(HIST("tracks/helium/dca/before/fake/hDCAxyVsPtantiHeliumTrueMaterial"), antihePt, track.dcaXY()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtantiHeliumTrueTransport"), antihePt, track.dcaXY()); + if (isWeakDecay) + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtantiHeliumTrueSec"), antihePt, track.dcaXY()); + else + histos.fill(HIST("tracks/helium/dca/before/fake/TOF/hDCAxyVsPtantiHeliumTrueMaterial"), antihePt, track.dcaXY()); + } + } + } + } break; } } // DCA Cut if constexpr (!IsFilteredData) { - if (!enableDCACustomCut) { - if (!track.isGlobalTrack()) - continue; - } else { - if (!track.isGlobalTrackWoDCA()) - continue; - if ((std::abs(track.dcaXY()) > DCAxyCustomCut) || (std::abs(track.dcaZ()) > DCAzCustomCut)) - continue; + if (filterOptions.enableIsGlobalTrack) { + if (!enableDCACustomCut) { + if (!track.isGlobalTrack()) + continue; + } else { + if (!track.isGlobalTrackWoDCA()) + continue; + } } } @@ -2346,607 +3660,520 @@ struct LFNucleiBATask { continue; } - if (makeDCAAfterCutPlots) { - histos.fill(HIST("tracks/dca/after/hDCAxy"), track.dcaXY()); - histos.fill(HIST("tracks/dca/after/hDCAz"), track.dcaZ()); - // histos.fill(HIST("tracks/dca/after/hDCAxyVsDCAz"), track.dcaXY(), track.dcaZ()); - histos.fill(HIST("tracks/dca/after/hDCAxyVsPt"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/dca/after/hDCAzVsPt"), track.pt(), track.dcaZ()); - } - if (enablePr && prRapCut && makeDCAAfterCutPlots) { - if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCPr) { - if (track.sign() > 0) { - histos.fill(HIST("tracks/proton/dca/after/hDCAxyVsPtProton"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/proton/dca/after/hDCAzVsPtProton"), track.pt(), track.dcaZ()); - } else { - histos.fill(HIST("tracks/proton/dca/after/hDCAxyVsPtantiProton"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/proton/dca/after/hDCAzVsPtantiProton"), track.pt(), track.dcaZ()); - } - } - } - if (enableDe && deRapCut && makeDCAAfterCutPlots) { - if (std::abs(track.tpcNSigmaDe()) < nsigmaTPCDe) { - - if (usenITSLayer && !itsClusterMap.test(nITSLayer)) - continue; + if (outFlagOptions.makeDCAAfterCutPlots) { - if (track.sign() > 0) { - histos.fill(HIST("tracks/deuteron/dca/after/hDCAxyVsPtDeuteron"), DPt, track.dcaXY()); - histos.fill(HIST("tracks/deuteron/dca/after/hDCAzVsPtDeuteron"), DPt, track.dcaZ()); - } else { - histos.fill(HIST("tracks/deuteron/dca/after/hDCAxyVsPtantiDeuteron"), antiDPt, track.dcaXY()); - histos.fill(HIST("tracks/deuteron/dca/after/hDCAzVsPtantiDeuteron"), antiDPt, track.dcaZ()); + if (isHeWTPCpid) { + histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsDCAzVsPtHelium"), track.dcaXY(), track.dcaZ(), hePt); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAxyVsDCAzVsPtHelium"), track.dcaXY(), track.dcaZ(), hePt); } } - } - if (enableTr && trRapCut && makeDCAAfterCutPlots) { - if (isTriton) { - if (track.sign() > 0) { - histos.fill(HIST("tracks/triton/dca/after/hDCAxyVsPtTriton"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/triton/dca/after/hDCAzVsPtTriton"), track.pt(), track.dcaZ()); - } else { - histos.fill(HIST("tracks/triton/dca/after/hDCAxyVsPtantiTriton"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/triton/dca/after/hDCAzVsPtantiTriton"), track.pt(), track.dcaZ()); + if (isAntiHeWTPCpid) { + histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsDCAzVsPtantiHelium"), track.dcaXY(), track.dcaZ(), antihePt); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAxyVsDCAzVsPtantiHelium"), track.dcaXY(), track.dcaZ(), antihePt); } } - } - if (enableHe && heRapCut && makeDCAAfterCutPlots) { - if (std::abs(track.tpcNSigmaHe()) < nsigmaTPCHe) { - if (track.sign() > 0) { - histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsPtHelium"), hePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/after/hDCAzVsPtHelium"), hePt, track.dcaZ()); - if (track.hasTOF() && doTOFplots) { - histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAxyVsPtHelium"), hePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAzVsPtHelium"), hePt, track.dcaZ()); + + if (passDCAxyzCut) { + histos.fill(HIST("tracks/dca/after/hDCAxy"), track.dcaXY()); + histos.fill(HIST("tracks/dca/after/hDCAz"), track.dcaZ()); + histos.fill(HIST("tracks/dca/after/hDCAxyVsPt"), track.pt(), track.dcaXY()); + histos.fill(HIST("tracks/dca/after/hDCAzVsPt"), track.pt(), track.dcaZ()); + + if (enablePr && prRapCut) { + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCvar.nsigmaTPCPr) { + if (track.sign() > 0) { + histos.fill(HIST("tracks/proton/dca/after/hDCAxyVsPtProton"), track.pt(), track.dcaXY()); + histos.fill(HIST("tracks/proton/dca/after/hDCAzVsPtProton"), track.pt(), track.dcaZ()); + } else { + histos.fill(HIST("tracks/proton/dca/after/hDCAxyVsPtantiProton"), track.pt(), track.dcaXY()); + histos.fill(HIST("tracks/proton/dca/after/hDCAzVsPtantiProton"), track.pt(), track.dcaZ()); + } } - } else { - histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsPtantiHelium"), antihePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/after/hDCAzVsPtantiHelium"), antihePt, track.dcaZ()); - if (track.hasTOF() && doTOFplots) { - histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAxyVsPtantiHelium"), antihePt, track.dcaXY()); - histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAzVsPtantiHelium"), antihePt, track.dcaZ()); + } + if (enableTr && trRapCut) { + if (isTritonTPCpid) { + if (track.sign() > 0) { + histos.fill(HIST("tracks/triton/dca/after/hDCAxyVsPtTriton"), track.pt(), track.dcaXY()); + histos.fill(HIST("tracks/triton/dca/after/hDCAzVsPtTriton"), track.pt(), track.dcaZ()); + } else { + histos.fill(HIST("tracks/triton/dca/after/hDCAxyVsPtantiTriton"), track.pt(), track.dcaXY()); + histos.fill(HIST("tracks/triton/dca/after/hDCAzVsPtantiTriton"), track.pt(), track.dcaZ()); + } + } + } + if (enableAl && alRapCut) { + if (std::abs(track.tpcNSigmaAl()) < nsigmaTPCvar.nsigmaTPCAl) { + if (track.sign() > 0) { + histos.fill(HIST("tracks/alpha/dca/after/hDCAxyVsPtAlpha"), track.pt(), track.dcaXY()); + histos.fill(HIST("tracks/alpha/dca/after/hDCAzVsPtAlpha"), track.pt(), track.dcaZ()); + } else { + histos.fill(HIST("tracks/alpha/dca/after/hDCAxyVsPtantiAlpha"), track.pt(), track.dcaXY()); + histos.fill(HIST("tracks/alpha/dca/after/hDCAzVsPtantiAlpha"), track.pt(), track.dcaZ()); + } } } } - } - if (enableAl && alRapCut && makeDCAAfterCutPlots) { - if (std::abs(track.tpcNSigmaAl()) < nsigmaTPCAl) { - if (track.sign() > 0) { - histos.fill(HIST("tracks/alpha/dca/after/hDCAxyVsPtAlpha"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/alpha/dca/after/hDCAzVsPtAlpha"), track.pt(), track.dcaZ()); - } else { - histos.fill(HIST("tracks/alpha/dca/after/hDCAxyVsPtantiAlpha"), track.pt(), track.dcaXY()); - histos.fill(HIST("tracks/alpha/dca/after/hDCAzVsPtantiAlpha"), track.pt(), track.dcaZ()); + if (isDeWTPCpid) { + if (usenITSLayer && !itsClusterMap.test(trkqcOptions.nITSLayer)) + continue; + histos.fill(HIST("tracks/deuteron/dca/after/hDCAxyVsPtDeuteron"), DPt, track.dcaXY()); + histos.fill(HIST("tracks/deuteron/dca/after/hDCAzVsPtDeuteron"), DPt, track.dcaZ()); + } + if (isAntiDeWTPCpid) { + if (usenITSLayer && !itsClusterMap.test(trkqcOptions.nITSLayer)) + continue; + histos.fill(HIST("tracks/deuteron/dca/after/hDCAxyVsPtantiDeuteron"), antiDPt, track.dcaXY()); + histos.fill(HIST("tracks/deuteron/dca/after/hDCAzVsPtantiDeuteron"), antiDPt, track.dcaZ()); + } + if (isHeWTPCpid) { + histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsPtHelium"), hePt, track.dcaXY()); + histos.fill(HIST("tracks/helium/dca/after/hDCAzVsPtHelium"), hePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAxyVsPtHelium"), hePt, track.dcaXY()); + histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAzVsPtHelium"), hePt, track.dcaZ()); + } + } + if (isAntiHeWTPCpid) { + histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsPtantiHelium"), antihePt, track.dcaXY()); + histos.fill(HIST("tracks/helium/dca/after/hDCAzVsPtantiHelium"), antihePt, track.dcaZ()); + if (track.hasTOF() && outFlagOptions.doTOFplots) { + histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAxyVsPtantiHelium"), antihePt, track.dcaXY()); + histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAzVsPtantiHelium"), antihePt, track.dcaZ()); } } } - // LOG(info)<<"\n collisionId ============>"< 0) { - debugHistos.fill(HIST("debug/qa/h2TPCncrVsPtPos"), track.tpcInnerParam(), track.tpcNClsCrossedRows()); - debugHistos.fill(HIST("debug/qa/h2TPCncrVsTPCsignalPos"), track.tpcSignal(), track.tpcNClsCrossedRows()); + if (passDCAxyzCut) { + // LOG(info)<<"\n collisionId ============>"<= 0.5f) && (track.tpcInnerParam() < 1.f)) { - debugHistos.fill(HIST("debug/qa/h1TPCncrMidPPos"), track.tpcNClsCrossedRows()); - } - if (track.tpcInnerParam() >= 1.f) { - debugHistos.fill(HIST("debug/qa/h1TPCncrHighPPos"), track.tpcNClsCrossedRows()); - } - } else { - debugHistos.fill(HIST("debug/qa/h2TPCncrVsPtNeg"), track.tpcInnerParam(), track.tpcNClsCrossedRows()); - debugHistos.fill(HIST("debug/qa/h2TPCncrVsTPCsignalNeg"), track.tpcSignal(), track.tpcNClsCrossedRows()); + // QA histos fill + histos.fill(HIST("qa/h1ITSncr"), track.itsNCls()); + histos.fill(HIST("qa/h1TPCnfound"), track.tpcNClsFound()); + histos.fill(HIST("qa/h1TPCncr"), track.tpcNClsCrossedRows()); + histos.fill(HIST("qa/h1rTPC"), track.tpcCrossedRowsOverFindableCls()); + histos.fill(HIST("qa/h1chi2ITS"), track.tpcChi2NCl()); + histos.fill(HIST("qa/h1chi2TPC"), track.itsChi2NCl()); - if (track.tpcInnerParam() < 0.5f) { - debugHistos.fill(HIST("debug/qa/h1TPCncrLowPNeg"), track.tpcNClsCrossedRows()); - } - if ((track.tpcInnerParam() >= 0.5f) && (track.tpcInnerParam() < 1.f)) { - debugHistos.fill(HIST("debug/qa/h1TPCncrMidPNeg"), track.tpcNClsCrossedRows()); - } - if (track.tpcInnerParam() >= 1.f) { - debugHistos.fill(HIST("debug/qa/h1TPCncrHighPNeg"), track.tpcNClsCrossedRows()); - } + if (enableDebug) { + debugHistos.fill(HIST("debug/h2TPCsignVsTPCmomentum_AllTracks"), track.tpcInnerParam() / (1.f * track.sign()), track.tpcSignal()); } - debugHistos.fill(HIST("debug/tracks/pion/h2PionVspTNSigmaTPC"), track.pt(), track.tpcNSigmaPi()); - debugHistos.fill(HIST("debug/tracks/kaon/h2KaonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaKa()); - } - - if (enablePtSpectra) - histos.fill(HIST("tracks/eff/h2pVsTPCmomentum"), track.tpcInnerParam(), track.p()); - - if (enableFiltering) { - if (track.tpcNSigmaKa() < 5) - continue; - } + if (enableDebug) { + debugHistos.fill(HIST("debug/tracks/h1Eta"), track.eta()); + debugHistos.fill(HIST("debug/tracks/h1VarPhi"), track.phi()); + debugHistos.fill(HIST("debug/tracks/h2EtaVsPhi"), track.eta(), track.phi()); + debugHistos.fill(HIST("debug/tracks/h2PionYvsPt"), track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Pion)), track.pt()); - // p,d,t,He - histos.fill(HIST("tracks/h2TPCsignVsTPCmomentum"), track.tpcInnerParam() / (1.f * track.sign()), track.tpcSignal()); + if (track.sign() > 0) { + debugHistos.fill(HIST("debug/qa/h2TPCncrVsPtPos"), track.tpcInnerParam(), track.tpcNClsCrossedRows()); + debugHistos.fill(HIST("debug/qa/h2TPCncrVsTPCsignalPos"), track.tpcSignal(), track.tpcNClsCrossedRows()); - if (track.sign() > 0) { - if (enablePr && prRapCut) { - if (enableExpSignalTPC) - histos.fill(HIST("tracks/proton/h2ProtonTPCExpSignalDiffVsPt"), track.pt(), track.tpcExpSignalDiffPr()); + if (track.tpcInnerParam() < 0.5f) { + debugHistos.fill(HIST("debug/qa/h1TPCncrLowPPos"), track.tpcNClsCrossedRows()); + } + if ((track.tpcInnerParam() >= 0.5f) && (track.tpcInnerParam() < 1.f)) { + debugHistos.fill(HIST("debug/qa/h1TPCncrMidPPos"), track.tpcNClsCrossedRows()); + } + if (track.tpcInnerParam() >= 1.f) { + debugHistos.fill(HIST("debug/qa/h1TPCncrHighPPos"), track.tpcNClsCrossedRows()); + } + } else { + debugHistos.fill(HIST("debug/qa/h2TPCncrVsPtNeg"), track.tpcInnerParam(), track.tpcNClsCrossedRows()); + debugHistos.fill(HIST("debug/qa/h2TPCncrVsTPCsignalNeg"), track.tpcSignal(), track.tpcNClsCrossedRows()); - switch (useHasTRDConfig) { - case 0: - histos.fill(HIST("tracks/proton/h2ProtonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaPr()); - break; - case 1: - if (track.hasTRD()) { - histos.fill(HIST("tracks/proton/h2ProtonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaPr()); - } - break; - case 2: - if (!track.hasTRD()) { - histos.fill(HIST("tracks/proton/h2ProtonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaPr()); - } - break; + if (track.tpcInnerParam() < 0.5f) { + debugHistos.fill(HIST("debug/qa/h1TPCncrLowPNeg"), track.tpcNClsCrossedRows()); + } + if ((track.tpcInnerParam() >= 0.5f) && (track.tpcInnerParam() < 1.f)) { + debugHistos.fill(HIST("debug/qa/h1TPCncrMidPNeg"), track.tpcNClsCrossedRows()); + } + if (track.tpcInnerParam() >= 1.f) { + debugHistos.fill(HIST("debug/qa/h1TPCncrHighPNeg"), track.tpcNClsCrossedRows()); + } } - } - if (enableDe && deRapCut) { - if (enableExpSignalTPC) - histos.fill(HIST("tracks/deuteron/h2DeuteronTPCExpSignalDiffVsPt"), DPt, track.tpcExpSignalDiffDe()); - switch (useHasTRDConfig) { - case 0: - if (enableCentrality) - histos.fill(HIST("tracks/deuteron/h3DeuteronVspTNSigmaTPCVsMult"), DPt, track.tpcNSigmaDe(), event.centFT0M()); - else - histos.fill(HIST("tracks/deuteron/h2DeuteronVspTNSigmaTPC"), DPt, track.tpcNSigmaDe()); - break; - case 1: - if (track.hasTRD()) { - histos.fill(HIST("tracks/deuteron/h2DeuteronVspTNSigmaTPC"), DPt, track.tpcNSigmaDe()); - } - break; - case 2: - if (!track.hasTRD()) { - histos.fill(HIST("tracks/deuteron/h2DeuteronVspTNSigmaTPC"), DPt, track.tpcNSigmaDe()); - } - break; - } + debugHistos.fill(HIST("debug/tracks/pion/h2PionVspTNSigmaTPC"), track.pt(), track.tpcNSigmaPi()); + debugHistos.fill(HIST("debug/tracks/kaon/h2KaonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaKa()); } - if (enableTr && trRapCut) { - histos.fill(HIST("tracks/triton/h2TritonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaTr()); - } - if (enableHe && heRapCut) { - if (enableExpSignalTPC) - histos.fill(HIST("tracks/helium/h2HeliumTPCExpSignalDiffVsPt"), hePt, track.tpcExpSignalDiffHe()); + if (enablePtSpectra) + histos.fill(HIST("tracks/eff/h2pVsTPCmomentum"), track.tpcInnerParam(), track.p()); - histos.fill(HIST("tracks/helium/h2HeliumVspTNSigmaTPC"), hePt, track.tpcNSigmaHe()); - } - if (enableAl && alRapCut) { - histos.fill(HIST("tracks/alpha/h2AlphaVspTNSigmaTPC"), track.pt(), track.tpcNSigmaAl()); + if (filterOptions.enableFiltering) { + if (track.tpcNSigmaKa() < 5) + continue; } - } else { - if (enablePr && prRapCut) { - if (enableExpSignalTPC) - histos.fill(HIST("tracks/proton/h2antiProtonTPCExpSignalDiffVsPt"), track.pt(), track.tpcExpSignalDiffPr()); - switch (useHasTRDConfig) { - case 0: - histos.fill(HIST("tracks/proton/h2antiProtonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaPr()); - break; - case 1: - if (track.hasTRD()) { - histos.fill(HIST("tracks/proton/h2antiProtonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaPr()); - } - break; - case 2: - if (!track.hasTRD()) { - histos.fill(HIST("tracks/proton/h2antiProtonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaPr()); - } - break; - } - } - if (enableDe && deRapCut) { - if (enableExpSignalTPC) - histos.fill(HIST("tracks/deuteron/h2antiDeuteronTPCExpSignalDiffVsPt"), antiDPt, track.tpcExpSignalDiffDe()); + if (enablePIDplot) + histos.fill(HIST("tracks/h2TPCsignVsTPCmomentum"), track.tpcInnerParam() / (1.f * track.sign()), track.tpcSignal()); - switch (useHasTRDConfig) { - case 0: - if (enableCentrality) - histos.fill(HIST("tracks/deuteron/h3antiDeuteronVspTNSigmaTPCVsMult"), antiDPt, track.tpcNSigmaDe(), event.centFT0M()); - else - histos.fill(HIST("tracks/deuteron/h2antiDeuteronVspTNSigmaTPC"), antiDPt, track.tpcNSigmaDe()); - break; - case 1: - if (track.hasTRD()) { - histos.fill(HIST("tracks/deuteron/h2antiDeuteronVspTNSigmaTPC"), antiDPt, track.tpcNSigmaDe()); - } - break; - case 2: - if (!track.hasTRD()) { - histos.fill(HIST("tracks/deuteron/h2antiDeuteronVspTNSigmaTPC"), antiDPt, track.tpcNSigmaDe()); - } - break; + if constexpr (!IsFilteredData) { + if (nsigmaITSvar.showAverageClusterSize && enablePIDplot) { + histos.fill(HIST("tracks/averageClusterSize"), track.p(), averageClusterSizeTrk(track)); + histos.fill(HIST("tracks/averageClusterSizePerCoslInv"), track.p(), averageClusterSizePerCoslInv(track)); } } - if (enableTr && trRapCut) { - histos.fill(HIST("tracks/triton/h2antiTritonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaTr()); - } - if (enableHe && heRapCut) { - if (enableExpSignalTPC) - histos.fill(HIST("tracks/helium/h2antiHeliumTPCExpSignalDiffVsPt"), antihePt, track.tpcExpSignalDiffHe()); - histos.fill(HIST("tracks/helium/h2antiHeliumVspTNSigmaTPC"), antihePt, track.tpcNSigmaHe()); - } - if (enableAl && alRapCut) { - histos.fill(HIST("tracks/alpha/h2antiAlphaVspTNSigmaTPC"), track.pt(), track.tpcNSigmaAl()); - } - } - - // TOF - if (doTOFplots) { - histos.fill(HIST("tracks/pion/h2PionVspTNSigmaTOF"), track.pt(), track.tofNSigmaPi()); - histos.fill(HIST("tracks/kaon/h2KaonVspTNSigmaTOF"), track.pt(), track.tofNSigmaKa()); if (track.sign() > 0) { if (enablePr && prRapCut) { + if (outFlagOptions.enableExpSignalTPC) + histos.fill(HIST("tracks/proton/h2ProtonTPCExpSignalDiffVsPt"), track.pt(), track.tpcExpSignalDiffPr()); switch (useHasTRDConfig) { case 0: - histos.fill(HIST("tracks/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); + histos.fill(HIST("tracks/proton/h2ProtonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaPr()); break; case 1: if (track.hasTRD()) { - histos.fill(HIST("tracks/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); + histos.fill(HIST("tracks/proton/h2ProtonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaPr()); } break; case 2: if (!track.hasTRD()) { - histos.fill(HIST("tracks/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); + histos.fill(HIST("tracks/proton/h2ProtonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaPr()); } break; } - if (enableExpSignalTOF) - histos.fill(HIST("tracks/proton/h2ProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); } - if (enableDe && deRapCut) { + if (enableTr && trRapCut) { + histos.fill(HIST("tracks/triton/h2TritonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaTr()); + } + if (enableAl && alRapCut) { + histos.fill(HIST("tracks/alpha/h2AlphaVspTNSigmaTPC"), track.pt(), track.tpcNSigmaAl()); + } + } else { + if (enablePr && prRapCut) { + if (outFlagOptions.enableExpSignalTPC) + histos.fill(HIST("tracks/proton/h2antiProtonTPCExpSignalDiffVsPt"), track.pt(), track.tpcExpSignalDiffPr()); switch (useHasTRDConfig) { case 0: - histos.fill(HIST("tracks/deuteron/h2DeuteronVspTNSigmaTOF"), DPt, track.tofNSigmaDe()); + histos.fill(HIST("tracks/proton/h2antiProtonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaPr()); break; case 1: if (track.hasTRD()) { - histos.fill(HIST("tracks/deuteron/h2DeuteronVspTNSigmaTOF"), DPt, track.tofNSigmaDe()); + histos.fill(HIST("tracks/proton/h2antiProtonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaPr()); } break; case 2: if (!track.hasTRD()) { - histos.fill(HIST("tracks/deuteron/h2DeuteronVspTNSigmaTOF"), DPt, track.tofNSigmaDe()); + histos.fill(HIST("tracks/proton/h2antiProtonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaPr()); } break; } - if (enableExpSignalTOF) - histos.fill(HIST("tracks/deuteron/h2DeuteronTOFExpSignalDiffVsPt"), DPt, track.tofExpSignalDiffDe()); } - if (enableHe && heRapCut) { - histos.fill(HIST("tracks/helium/h2HeliumVspTNSigmaTOF"), hePt, track.tofNSigmaHe()); - if (enableExpSignalTOF) - histos.fill(HIST("tracks/helium/h2HeliumTOFExpSignalDiffVsPt"), hePt, track.tofExpSignalDiffHe()); + if (enableTr && trRapCut) { + histos.fill(HIST("tracks/triton/h2antiTritonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaTr()); + } + if (enableAl && alRapCut) { + histos.fill(HIST("tracks/alpha/h2antiAlphaVspTNSigmaTPC"), track.pt(), track.tpcNSigmaAl()); } - if (enableEvTimeSplitting && track.hasTOF()) { - if (track.isEvTimeTOF() && track.isEvTimeT0AC()) { - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); - if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/deuteron/h2DeuteronVspTNSigmaTOF"), DPt, track.tofNSigmaDe()); - if (enableExpSignalTOF) { - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h2ProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); - if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/deuteron/h2DeuteronTOFExpSignalDiffVsPt"), DPt, track.tofExpSignalDiffDe()); + } + + // TOF + if (outFlagOptions.doTOFplots) { + if (enableDebug) { + histos.fill(HIST("tracks/pion/h2PionVspTNSigmaTOF"), track.pt(), track.tofNSigmaPi()); + histos.fill(HIST("tracks/kaon/h2KaonVspTNSigmaTOF"), track.pt(), track.tofNSigmaKa()); + } + if (track.sign() > 0) { + if (enablePr && prRapCut) { + + switch (useHasTRDConfig) { + case 0: + histos.fill(HIST("tracks/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); + break; + case 1: + if (track.hasTRD()) { + histos.fill(HIST("tracks/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); + } + break; + case 2: + if (!track.hasTRD()) { + histos.fill(HIST("tracks/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); + } + break; } - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h3ProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); - if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/deuteron/h3DeuteronNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaDe(), track.tofNSigmaDe(), track.pt()); - if (enableDebug && (track.beta() > betaCut)) { - if (enablePr) - debugHistos.fill(HIST("debug/evtime/ft0tof/proton/h2ProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); - if (enableDe) - debugHistos.fill(HIST("debug/evtime/ft0tof/deuteron/h2DeuteronVspTNSigmaTPC_BetaCut"), DPt, track.tpcNSigmaDe()); + if (outFlagOptions.enableExpSignalTOF) + histos.fill(HIST("tracks/proton/h2ProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); + } + if (filterOptions.enableEvTimeSplitting && track.hasTOF()) { + if (track.isEvTimeTOF() && track.isEvTimeT0AC()) { if (enablePr) - debugHistos.fill(HIST("debug/evtime/ft0tof/proton/h2ProtonVspTNSigmaTOF_BetaCut"), track.pt(), track.tofNSigmaPr()); + evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); if (enableDe) - debugHistos.fill(HIST("debug/evtime/ft0tof/deuteron/h2DeuteronVspTNSigmaTOF_BetaCut"), DPt, track.tofNSigmaDe()); - if (enableExpSignalTOF) { - debugHistos.fill(HIST("debug/evtime/ft0tof/proton/h2ProtonTOFExpSignalDiffVsPt_BetaCut"), track.pt(), track.tofExpSignalDiffPr()); + evtimeHistos.fill(HIST("tracks/evtime/ft0tof/deuteron/h2DeuteronVspTNSigmaTOF"), DPt, track.tofNSigmaDe()); + if (outFlagOptions.enableExpSignalTOF) { + if (enablePr) + evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h2ProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); if (enableDe) - debugHistos.fill(HIST("debug/evtime/ft0tof/deuteron/h2DeuteronTOFExpSignalDiffVsPt_BetaCut"), DPt, track.tofExpSignalDiffDe()); + evtimeHistos.fill(HIST("tracks/evtime/ft0tof/deuteron/h2DeuteronTOFExpSignalDiffVsPt"), DPt, track.tofExpSignalDiffDe()); } - } - - } else if (track.isEvTimeT0AC()) { - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); - if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/ft0/deuteron/h2DeuteronVspTNSigmaTOF"), DPt, track.tofNSigmaDe()); - if (enableExpSignalTOF) { if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h2ProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); + evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h3ProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/ft0/deuteron/h2DeuteronTOFExpSignalDiffVsPt"), DPt, track.tofExpSignalDiffDe()); - } - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h3ProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); - if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/ft0/deuteron/h3DeuteronNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaDe(), track.tofNSigmaDe(), DPt); - if (enableDebug && (track.beta() > betaCut)) { - if (enablePr) - debugHistos.fill(HIST("debug/evtime/ft0/proton/h2ProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); - if (enableDe) - debugHistos.fill(HIST("debug/evtime/ft0/deuteron/h2DeuteronVspTNSigmaTPC_BetaCut"), DPt, track.tpcNSigmaDe()); + evtimeHistos.fill(HIST("tracks/evtime/ft0tof/deuteron/h3DeuteronNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaDe(), track.tofNSigmaDe(), DPt); + if (enableDebug && (track.beta() > betaCut)) { + if (enablePr) + debugHistos.fill(HIST("debug/evtime/ft0tof/proton/h2ProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/ft0tof/deuteron/h2DeuteronVspTNSigmaTPC_BetaCut"), DPt, track.tpcNSigmaDe()); - if (enablePr) - debugHistos.fill(HIST("debug/evtime/ft0/proton/h2ProtonVspTNSigmaTOF_BetaCut"), track.pt(), track.tofNSigmaPr()); - if (enableDe) - debugHistos.fill(HIST("debug/evtime/ft0/deuteron/h2DeuteronVspTNSigmaTOF_BetaCut"), DPt, track.tofNSigmaDe()); - if (enableExpSignalTOF) { if (enablePr) - debugHistos.fill(HIST("debug/evtime/ft0/proton/h2ProtonTOFExpSignalDiffVsPt_BetaCut"), track.pt(), track.tofExpSignalDiffPr()); + debugHistos.fill(HIST("debug/evtime/ft0tof/proton/h2ProtonVspTNSigmaTOF_BetaCut"), track.pt(), track.tofNSigmaPr()); if (enableDe) - debugHistos.fill(HIST("debug/evtime/ft0/deuteron/h2DeuteronTOFExpSignalDiffVsPt_BetaCut"), DPt, track.tofExpSignalDiffDe()); + debugHistos.fill(HIST("debug/evtime/ft0tof/deuteron/h2DeuteronVspTNSigmaTOF_BetaCut"), DPt, track.tofNSigmaDe()); + if (outFlagOptions.enableExpSignalTOF) { + debugHistos.fill(HIST("debug/evtime/ft0tof/proton/h2ProtonTOFExpSignalDiffVsPt_BetaCut"), track.pt(), track.tofExpSignalDiffPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/ft0tof/deuteron/h2DeuteronTOFExpSignalDiffVsPt_BetaCut"), DPt, track.tofExpSignalDiffDe()); + } } - } - } else if (track.isEvTimeTOF()) { - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); - if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/tof/deuteron/h2DeuteronVspTNSigmaTOF"), DPt, track.tofNSigmaDe()); - if (enableExpSignalTOF) { + } else if (track.isEvTimeT0AC()) { if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h2ProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); + evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/tof/deuteron/h2DeuteronTOFExpSignalDiffVsPt"), DPt, track.tofExpSignalDiffDe()); - } - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h3ProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); - if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/tof/deuteron/h3DeuteronNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaDe(), track.tofNSigmaDe(), DPt); - if (enableDebug && (track.beta() > betaCut)) { + evtimeHistos.fill(HIST("tracks/evtime/ft0/deuteron/h2DeuteronVspTNSigmaTOF"), DPt, track.tofNSigmaDe()); + if (outFlagOptions.enableExpSignalTOF) { + if (enablePr) + evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h2ProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); + if (enableDe) + evtimeHistos.fill(HIST("tracks/evtime/ft0/deuteron/h2DeuteronTOFExpSignalDiffVsPt"), DPt, track.tofExpSignalDiffDe()); + } if (enablePr) - debugHistos.fill(HIST("debug/evtime/tof/proton/h2ProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); + evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h3ProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); if (enableDe) - debugHistos.fill(HIST("debug/evtime/tof/deuteron/h2DeuteronVspTNSigmaTPC_BetaCut"), DPt, track.tpcNSigmaDe()); + evtimeHistos.fill(HIST("tracks/evtime/ft0/deuteron/h3DeuteronNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaDe(), track.tofNSigmaDe(), DPt); + if (enableDebug && (track.beta() > betaCut)) { + if (enablePr) + debugHistos.fill(HIST("debug/evtime/ft0/proton/h2ProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/ft0/deuteron/h2DeuteronVspTNSigmaTPC_BetaCut"), DPt, track.tpcNSigmaDe()); + if (enablePr) + debugHistos.fill(HIST("debug/evtime/ft0/proton/h2ProtonVspTNSigmaTOF_BetaCut"), track.pt(), track.tofNSigmaPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/ft0/deuteron/h2DeuteronVspTNSigmaTOF_BetaCut"), DPt, track.tofNSigmaDe()); + if (outFlagOptions.enableExpSignalTOF) { + if (enablePr) + debugHistos.fill(HIST("debug/evtime/ft0/proton/h2ProtonTOFExpSignalDiffVsPt_BetaCut"), track.pt(), track.tofExpSignalDiffPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/ft0/deuteron/h2DeuteronTOFExpSignalDiffVsPt_BetaCut"), DPt, track.tofExpSignalDiffDe()); + } + } + } else if (track.isEvTimeTOF()) { if (enablePr) - debugHistos.fill(HIST("debug/evtime/tof/proton/h2ProtonVspTNSigmaTOF_BetaCut"), track.pt(), track.tofNSigmaPr()); + evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); if (enableDe) - debugHistos.fill(HIST("debug/evtime/tof/deuteron/h2DeuteronVspTNSigmaTOF_BetaCut"), DPt, track.tofNSigmaDe()); - - if (enableExpSignalTOF) { + evtimeHistos.fill(HIST("tracks/evtime/tof/deuteron/h2DeuteronVspTNSigmaTOF"), DPt, track.tofNSigmaDe()); + if (outFlagOptions.enableExpSignalTOF) { if (enablePr) - debugHistos.fill(HIST("debug/evtime/tof/proton/h2ProtonTOFExpSignalDiffVsPt_BetaCut"), track.pt(), track.tofExpSignalDiffPr()); + evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h2ProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); if (enableDe) - debugHistos.fill(HIST("debug/evtime/tof/deuteron/h2DeuteronTOFExpSignalDiffVsPt_BetaCut"), DPt, track.tofExpSignalDiffDe()); + evtimeHistos.fill(HIST("tracks/evtime/tof/deuteron/h2DeuteronTOFExpSignalDiffVsPt"), DPt, track.tofExpSignalDiffDe()); } - } - - } else { - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); - if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h2DeuteronVspTNSigmaTOF"), DPt, track.tofNSigmaDe()); - if (enableExpSignalTOF) { if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h2ProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); + evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h3ProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h2DeuteronTOFExpSignalDiffVsPt"), DPt, track.tofExpSignalDiffDe()); - } - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h3ProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); - if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h3DeuteronNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaDe(), track.tofNSigmaDe(), DPt); - if (enableDebug && (track.beta() > betaCut)) { + evtimeHistos.fill(HIST("tracks/evtime/tof/deuteron/h3DeuteronNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaDe(), track.tofNSigmaDe(), DPt); + if (enableDebug && (track.beta() > betaCut)) { + if (enablePr) + debugHistos.fill(HIST("debug/evtime/tof/proton/h2ProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/tof/deuteron/h2DeuteronVspTNSigmaTPC_BetaCut"), DPt, track.tpcNSigmaDe()); + + if (enablePr) + debugHistos.fill(HIST("debug/evtime/tof/proton/h2ProtonVspTNSigmaTOF_BetaCut"), track.pt(), track.tofNSigmaPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/tof/deuteron/h2DeuteronVspTNSigmaTOF_BetaCut"), DPt, track.tofNSigmaDe()); + + if (outFlagOptions.enableExpSignalTOF) { + if (enablePr) + debugHistos.fill(HIST("debug/evtime/tof/proton/h2ProtonTOFExpSignalDiffVsPt_BetaCut"), track.pt(), track.tofExpSignalDiffPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/tof/deuteron/h2DeuteronTOFExpSignalDiffVsPt_BetaCut"), DPt, track.tofExpSignalDiffDe()); + } + } + + } else { if (enablePr) - debugHistos.fill(HIST("debug/evtime/fill/proton/h2ProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); + evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); if (enableDe) - debugHistos.fill(HIST("debug/evtime/fill/deuteron/h2DeuteronVspTNSigmaTPC_BetaCut"), DPt, track.tpcNSigmaDe()); - + evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h2DeuteronVspTNSigmaTOF"), DPt, track.tofNSigmaDe()); + if (outFlagOptions.enableExpSignalTOF) { + if (enablePr) + evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h2ProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); + if (enableDe) + evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h2DeuteronTOFExpSignalDiffVsPt"), DPt, track.tofExpSignalDiffDe()); + } if (enablePr) - debugHistos.fill(HIST("debug/evtime/fill/proton/h2ProtonVspTNSigmaTOF_BetaCut"), track.pt(), track.tofNSigmaPr()); + evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h3ProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); if (enableDe) - debugHistos.fill(HIST("debug/evtime/fill/deuteron/h2DeuteronVspTNSigmaTOF_BetaCut"), DPt, track.tofNSigmaDe()); + evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h3DeuteronNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaDe(), track.tofNSigmaDe(), DPt); + if (enableDebug && (track.beta() > betaCut)) { + if (enablePr) + debugHistos.fill(HIST("debug/evtime/fill/proton/h2ProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/fill/deuteron/h2DeuteronVspTNSigmaTPC_BetaCut"), DPt, track.tpcNSigmaDe()); - if (enableExpSignalTOF) { if (enablePr) - debugHistos.fill(HIST("debug/evtime/fill/proton/h2ProtonTOFExpSignalDiffVsPt_BetaCut"), track.pt(), track.tofExpSignalDiffPr()); + debugHistos.fill(HIST("debug/evtime/fill/proton/h2ProtonVspTNSigmaTOF_BetaCut"), track.pt(), track.tofNSigmaPr()); if (enableDe) - debugHistos.fill(HIST("debug/evtime/fill/deuteron/h2DeuteronTOFExpSignalDiffVsPt_BetaCut"), DPt, track.tofExpSignalDiffDe()); + debugHistos.fill(HIST("debug/evtime/fill/deuteron/h2DeuteronVspTNSigmaTOF_BetaCut"), DPt, track.tofNSigmaDe()); + + if (outFlagOptions.enableExpSignalTOF) { + if (enablePr) + debugHistos.fill(HIST("debug/evtime/fill/proton/h2ProtonTOFExpSignalDiffVsPt_BetaCut"), track.pt(), track.tofExpSignalDiffPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/fill/deuteron/h2DeuteronTOFExpSignalDiffVsPt_BetaCut"), DPt, track.tofExpSignalDiffDe()); + } } } } - } - - } else { - if (enablePr && prRapCut) { - switch (useHasTRDConfig) { - case 0: - histos.fill(HIST("tracks/proton/h2antiProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); - break; - case 1: - if (track.hasTRD()) { - histos.fill(HIST("tracks/proton/h2antiProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); - } - break; - case 2: - if (!track.hasTRD()) { + } else { + if (enablePr && prRapCut) { + switch (useHasTRDConfig) { + case 0: histos.fill(HIST("tracks/proton/h2antiProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); - } - break; - } - if (enableExpSignalTOF) - histos.fill(HIST("tracks/proton/h2antiProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); - } - if (enableDe && deRapCut) { - switch (useHasTRDConfig) { - case 0: - histos.fill(HIST("tracks/deuteron/h2antiDeuteronVspTNSigmaTOF"), antiDPt, track.tofNSigmaDe()); - break; - case 1: - if (track.hasTRD()) { - histos.fill(HIST("tracks/deuteron/h2antiDeuteronVspTNSigmaTOF"), antiDPt, track.tofNSigmaDe()); - } - break; - case 2: - if (!track.hasTRD()) { - histos.fill(HIST("tracks/deuteron/h2antiDeuteronVspTNSigmaTOF"), antiDPt, track.tofNSigmaDe()); - } - break; - } - if (enableExpSignalTOF) - histos.fill(HIST("tracks/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt"), antiDPt, track.tofExpSignalDiffDe()); - } - if (enableHe && heRapCut) { - histos.fill(HIST("tracks/helium/h2antiHeliumVspTNSigmaTOF"), antihePt, track.tofNSigmaHe()); - if (enableExpSignalTOF) - histos.fill(HIST("tracks/helium/h2antiHeliumTOFExpSignalDiffVsPt"), antihePt, track.tofExpSignalDiffHe()); - } - if (enableEvTimeSplitting && track.hasTOF()) { - if (track.isEvTimeTOF() && track.isEvTimeT0AC()) { - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h2antiProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); - if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/deuteron/h2antiDeuteronVspTNSigmaTOF"), antiDPt, track.tofNSigmaDe()); - if (enableExpSignalTOF) { - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h2antiProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); - if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt"), antiDPt, track.tofExpSignalDiffDe()); + break; + case 1: + if (track.hasTRD()) { + histos.fill(HIST("tracks/proton/h2antiProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); + } + break; + case 2: + if (!track.hasTRD()) { + histos.fill(HIST("tracks/proton/h2antiProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); + } + break; } - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h3antiProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); - if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/deuteron/h3antiDeuteronNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaDe(), track.tofNSigmaDe(), antiDPt); - if (enableDebug && (track.beta() > betaCut)) { - if (enablePr) - debugHistos.fill(HIST("debug/evtime/ft0tof/proton/h2antiProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); - if (enableDe) - debugHistos.fill(HIST("debug/evtime/ft0tof/deuteron/h2antiDeuteronVspTNSigmaTPC_BetaCut"), antiDPt, track.tpcNSigmaDe()); + if (outFlagOptions.enableExpSignalTOF) + histos.fill(HIST("tracks/proton/h2antiProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); + } + if (filterOptions.enableEvTimeSplitting && track.hasTOF()) { + if (track.isEvTimeTOF() && track.isEvTimeT0AC()) { if (enablePr) - debugHistos.fill(HIST("debug/evtime/ft0tof/proton/h2antiProtonVspTNSigmaTOF_BetaCut"), track.pt(), track.tofNSigmaPr()); + evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h2antiProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); if (enableDe) - debugHistos.fill(HIST("debug/evtime/ft0tof/deuteron/h2antiDeuteronVspTNSigmaTOF_BetaCut"), antiDPt, track.tofNSigmaDe()); - - if (enableExpSignalTOF) { + evtimeHistos.fill(HIST("tracks/evtime/ft0tof/deuteron/h2antiDeuteronVspTNSigmaTOF"), antiDPt, track.tofNSigmaDe()); + if (outFlagOptions.enableExpSignalTOF) { if (enablePr) - debugHistos.fill(HIST("debug/evtime/ft0tof/proton/h2antiProtonTOFExpSignalDiffVsPt_BetaCut"), track.pt(), track.tofExpSignalDiffPr()); + evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h2antiProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); if (enableDe) - debugHistos.fill(HIST("debug/evtime/ft0tof/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt_BetaCut"), antiDPt, track.tofExpSignalDiffDe()); + evtimeHistos.fill(HIST("tracks/evtime/ft0tof/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt"), antiDPt, track.tofExpSignalDiffDe()); } - } - - } else if (track.isEvTimeT0AC()) { - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h2antiProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); - if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/ft0/deuteron/h2antiDeuteronVspTNSigmaTOF"), antiDPt, track.tofNSigmaDe()); - if (enableExpSignalTOF) { - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h2antiProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); - if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/ft0/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt"), antiDPt, track.tofExpSignalDiffDe()); if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h3antiProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); - if (enablePr) - debugHistos.fill(HIST("debug/evtime/ft0/proton/h2antiProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); - if (enableDe) - debugHistos.fill(HIST("debug/evtime/ft0/deuteron/h2antiDeuteronVspTNSigmaTPC_BetaCut"), antiDPt, track.tpcNSigmaDe()); - if (enablePr) - debugHistos.fill(HIST("debug/evtime/ft0/proton/h2antiProtonVspTNSigmaTOF_BetaCut"), track.pt(), track.tofNSigmaPr()); + evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h3antiProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); if (enableDe) - debugHistos.fill(HIST("debug/evtime/ft0/deuteron/h2antiDeuteronVspTNSigmaTOF_BetaCut"), antiDPt, track.tofNSigmaDe()); - - if (enableExpSignalTOF) { + evtimeHistos.fill(HIST("tracks/evtime/ft0tof/deuteron/h3antiDeuteronNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaDe(), track.tofNSigmaDe(), antiDPt); + if (enableDebug && (track.beta() > betaCut)) { if (enablePr) - debugHistos.fill(HIST("debug/evtime/ft0/proton/h2antiProtonTOFExpSignalDiffVsPt_BetaCut"), track.pt(), track.tofExpSignalDiffPr()); + debugHistos.fill(HIST("debug/evtime/ft0tof/proton/h2antiProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); if (enableDe) - debugHistos.fill(HIST("debug/evtime/ft0/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt_BetaCut"), antiDPt, track.tofExpSignalDiffDe()); + debugHistos.fill(HIST("debug/evtime/ft0tof/deuteron/h2antiDeuteronVspTNSigmaTPC_BetaCut"), antiDPt, track.tpcNSigmaDe()); + if (enablePr) + debugHistos.fill(HIST("debug/evtime/ft0tof/proton/h2antiProtonVspTNSigmaTOF_BetaCut"), track.pt(), track.tofNSigmaPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/ft0tof/deuteron/h2antiDeuteronVspTNSigmaTOF_BetaCut"), antiDPt, track.tofNSigmaDe()); + + if (outFlagOptions.enableExpSignalTOF) { + if (enablePr) + debugHistos.fill(HIST("debug/evtime/ft0tof/proton/h2antiProtonTOFExpSignalDiffVsPt_BetaCut"), track.pt(), track.tofExpSignalDiffPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/ft0tof/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt_BetaCut"), antiDPt, track.tofExpSignalDiffDe()); + } } - } - } else if (track.isEvTimeTOF()) { - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h2antiProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); - if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/tof/deuteron/h2antiDeuteronVspTNSigmaTOF"), antiDPt, track.tofNSigmaDe()); - if (enableExpSignalTOF) { + } else if (track.isEvTimeT0AC()) { if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h2antiProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); + evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h2antiProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/tof/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt"), antiDPt, track.tofExpSignalDiffDe()); - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h3antiProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); - if (enablePr) - debugHistos.fill(HIST("debug/evtime/tof/proton/h2antiProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); - if (enableDe) - debugHistos.fill(HIST("debug/evtime/tof/deuteron/h2antiDeuteronVspTNSigmaTPC_BetaCut"), antiDPt, track.tpcNSigmaDe()); + evtimeHistos.fill(HIST("tracks/evtime/ft0/deuteron/h2antiDeuteronVspTNSigmaTOF"), antiDPt, track.tofNSigmaDe()); + if (outFlagOptions.enableExpSignalTOF) { + if (enablePr) + evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h2antiProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); + if (enableDe) + evtimeHistos.fill(HIST("tracks/evtime/ft0/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt"), antiDPt, track.tofExpSignalDiffDe()); + if (enablePr) + evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h3antiProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); + if (enablePr) + debugHistos.fill(HIST("debug/evtime/ft0/proton/h2antiProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/ft0/deuteron/h2antiDeuteronVspTNSigmaTPC_BetaCut"), antiDPt, track.tpcNSigmaDe()); + if (enablePr) + debugHistos.fill(HIST("debug/evtime/ft0/proton/h2antiProtonVspTNSigmaTOF_BetaCut"), track.pt(), track.tofNSigmaPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/ft0/deuteron/h2antiDeuteronVspTNSigmaTOF_BetaCut"), antiDPt, track.tofNSigmaDe()); + if (outFlagOptions.enableExpSignalTOF) { + if (enablePr) + debugHistos.fill(HIST("debug/evtime/ft0/proton/h2antiProtonTOFExpSignalDiffVsPt_BetaCut"), track.pt(), track.tofExpSignalDiffPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/ft0/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt_BetaCut"), antiDPt, track.tofExpSignalDiffDe()); + } + } + + } else if (track.isEvTimeTOF()) { if (enablePr) - debugHistos.fill(HIST("debug/evtime/tof/proton/h2antiProtonVspTNSigmaTOF_BetaCut"), track.pt(), track.tofNSigmaPr()); + evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h2antiProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); if (enableDe) - debugHistos.fill(HIST("debug/evtime/tof/deuteron/h2antiDeuteronVspTNSigmaTOF_BetaCut"), antiDPt, track.tofNSigmaDe()); + evtimeHistos.fill(HIST("tracks/evtime/tof/deuteron/h2antiDeuteronVspTNSigmaTOF"), antiDPt, track.tofNSigmaDe()); + if (outFlagOptions.enableExpSignalTOF) { + if (enablePr) + evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h2antiProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); + if (enableDe) + evtimeHistos.fill(HIST("tracks/evtime/tof/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt"), antiDPt, track.tofExpSignalDiffDe()); + if (enablePr) + evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h3antiProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); + if (enablePr) + debugHistos.fill(HIST("debug/evtime/tof/proton/h2antiProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/tof/deuteron/h2antiDeuteronVspTNSigmaTPC_BetaCut"), antiDPt, track.tpcNSigmaDe()); - if (enableExpSignalTOF) { if (enablePr) - debugHistos.fill(HIST("debug/evtime/tof/proton/h2antiProtonTOFExpSignalDiffVsPt_BetaCut"), track.pt(), track.tofExpSignalDiffPr()); + debugHistos.fill(HIST("debug/evtime/tof/proton/h2antiProtonVspTNSigmaTOF_BetaCut"), track.pt(), track.tofNSigmaPr()); if (enableDe) - debugHistos.fill(HIST("debug/evtime/tof/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt_BetaCut"), antiDPt, track.tofExpSignalDiffDe()); - } - } + debugHistos.fill(HIST("debug/evtime/tof/deuteron/h2antiDeuteronVspTNSigmaTOF_BetaCut"), antiDPt, track.tofNSigmaDe()); - } else { - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h2antiProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); - if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h2antiDeuteronVspTNSigmaTOF"), antiDPt, track.tofNSigmaDe()); - if (enableExpSignalTOF) { - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h2antiProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); - if (enableDe) - evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt"), antiDPt, track.tofExpSignalDiffDe()); - if (enablePr) - evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h3antiProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); - if (enablePr) - debugHistos.fill(HIST("debug/evtime/fill/proton/h2antiProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); - if (enableDe) - debugHistos.fill(HIST("debug/evtime/fill/deuteron/h2antiDeuteronVspTNSigmaTPC_BetaCut"), antiDPt, track.tpcNSigmaDe()); + if (outFlagOptions.enableExpSignalTOF) { + if (enablePr) + debugHistos.fill(HIST("debug/evtime/tof/proton/h2antiProtonTOFExpSignalDiffVsPt_BetaCut"), track.pt(), track.tofExpSignalDiffPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/tof/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt_BetaCut"), antiDPt, track.tofExpSignalDiffDe()); + } + } + } else { if (enablePr) - debugHistos.fill(HIST("debug/evtime/fill/proton/h2antiProtonVspTNSigmaTOF_BetaCut"), track.pt(), track.tofNSigmaPr()); + evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h2antiProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); if (enableDe) - debugHistos.fill(HIST("debug/evtime/fill/deuteron/h2antiDeuteronVspTNSigmaTOF_BetaCut"), antiDPt, track.tofNSigmaDe()); + evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h2antiDeuteronVspTNSigmaTOF"), antiDPt, track.tofNSigmaDe()); + if (outFlagOptions.enableExpSignalTOF) { + if (enablePr) + evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h2antiProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); + if (enableDe) + evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt"), antiDPt, track.tofExpSignalDiffDe()); + if (enablePr) + evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h3antiProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); + if (enablePr) + debugHistos.fill(HIST("debug/evtime/fill/proton/h2antiProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/fill/deuteron/h2antiDeuteronVspTNSigmaTPC_BetaCut"), antiDPt, track.tpcNSigmaDe()); - if (enableExpSignalTOF) { if (enablePr) - debugHistos.fill(HIST("debug/evtime/fill/proton/h2antiProtonTOFExpSignalDiffVsPt_BetaCut"), track.pt(), track.tofExpSignalDiffPr()); + debugHistos.fill(HIST("debug/evtime/fill/proton/h2antiProtonVspTNSigmaTOF_BetaCut"), track.pt(), track.tofNSigmaPr()); if (enableDe) - debugHistos.fill(HIST("debug/evtime/fill/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt_BetaCut"), antiDPt, track.tofExpSignalDiffDe()); + debugHistos.fill(HIST("debug/evtime/fill/deuteron/h2antiDeuteronVspTNSigmaTOF_BetaCut"), antiDPt, track.tofNSigmaDe()); + + if (outFlagOptions.enableExpSignalTOF) { + if (enablePr) + debugHistos.fill(HIST("debug/evtime/fill/proton/h2antiProtonTOFExpSignalDiffVsPt_BetaCut"), track.pt(), track.tofExpSignalDiffPr()); + if (enableDe) + debugHistos.fill(HIST("debug/evtime/fill/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt_BetaCut"), antiDPt, track.tofExpSignalDiffDe()); + } } } } @@ -2954,143 +4181,217 @@ struct LFNucleiBATask { } } - // PID - if (enablePtSpectra && enableDebug) { - if (track.sign() > 0) { - debugHistos.fill(HIST("tracks/eff/hPtP"), track.pt()); - debugHistos.fill(HIST("tracks/eff/hPtPrebinned"), track.pt()); - } else { - debugHistos.fill(HIST("tracks/eff/hPtantiP"), track.pt()); - debugHistos.fill(HIST("tracks/eff/hPtantiPrebinned"), track.pt()); + if (isDeWoTPCpid) { + if (outFlagOptions.enableExpSignalTPC) + histos.fill(HIST("tracks/deuteron/h2DeuteronTPCExpSignalDiffVsPt"), DPt, track.tpcExpSignalDiffDe()); + + switch (useHasTRDConfig) { + case 0: + if (enableCentrality) + histos.fill(HIST("tracks/deuteron/h3DeuteronVspTNSigmaTPCVsMult"), DPt, track.tpcNSigmaDe(), event.centFT0M()); + else + histos.fill(HIST("tracks/deuteron/h2DeuteronVspTNSigmaTPC"), DPt, track.tpcNSigmaDe()); + break; + case 1: + if (track.hasTRD()) { + histos.fill(HIST("tracks/deuteron/h2DeuteronVspTNSigmaTPC"), DPt, track.tpcNSigmaDe()); + } + break; + case 2: + if (!track.hasTRD()) { + histos.fill(HIST("tracks/deuteron/h2DeuteronVspTNSigmaTPC"), DPt, track.tpcNSigmaDe()); + } + break; } } - - if (enablePr) { - if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCPr && prRapCut) { - if (track.sign() > 0) { - if (enablePtSpectra) { - histos.fill(HIST("tracks/eff/proton/hPtPr"), track.pt()); - histos.fill(HIST("tracks/eff/proton/hPtPrrebinned"), track.pt()); - histos.fill(HIST("tracks/eff/proton/h2pVsTPCmomentumPr"), track.tpcInnerParam(), track.p()); + if (isAntiDeWoTPCpid) { + if (outFlagOptions.enableExpSignalTPC) + histos.fill(HIST("tracks/deuteron/h2antiDeuteronTPCExpSignalDiffVsPt"), antiDPt, track.tpcExpSignalDiffDe()); + + switch (useHasTRDConfig) { + case 0: + if (enableCentrality) + histos.fill(HIST("tracks/deuteron/h3antiDeuteronVspTNSigmaTPCVsMult"), antiDPt, track.tpcNSigmaDe(), event.centFT0M()); + else + histos.fill(HIST("tracks/deuteron/h2antiDeuteronVspTNSigmaTPC"), antiDPt, track.tpcNSigmaDe()); + break; + case 1: + if (track.hasTRD()) { + histos.fill(HIST("tracks/deuteron/h2antiDeuteronVspTNSigmaTPC"), antiDPt, track.tpcNSigmaDe()); } - histos.fill(HIST("tracks/proton/h1ProtonSpectra"), track.pt()); - histos.fill(HIST("tracks/proton/h2ProtonYvsPt"), track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Proton)), track.pt()); - histos.fill(HIST("tracks/proton/h2ProtonEtavsPt"), track.eta(), track.pt()); - - if (enablePIDplot) - histos.fill(HIST("tracks/proton/h2TPCsignVsTPCmomentumProton"), track.tpcInnerParam(), track.tpcSignal()); - } else { - if (enablePtSpectra) { - histos.fill(HIST("tracks/eff/proton/hPtantiPr"), track.pt()); - histos.fill(HIST("tracks/eff/proton/hPtantiPrrebinned"), track.pt()); - histos.fill(HIST("tracks/eff/proton/h2pVsTPCmomentumantiPr"), track.tpcInnerParam(), track.p()); + break; + case 2: + if (!track.hasTRD()) { + histos.fill(HIST("tracks/deuteron/h2antiDeuteronVspTNSigmaTPC"), antiDPt, track.tpcNSigmaDe()); } - histos.fill(HIST("tracks/proton/h1antiProtonSpectra"), track.pt()); - histos.fill(HIST("tracks/proton/h2antiProtonYvsPt"), track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Proton)), track.pt()); - histos.fill(HIST("tracks/proton/h2antiProtonEtavsPt"), track.eta(), track.pt()); + break; + } + } - if (enablePIDplot) - histos.fill(HIST("tracks/proton/h2TPCsignVsTPCmomentumantiProton"), track.tpcInnerParam(), track.tpcSignal()); + if (isHeWoTPCpid) { + if (outFlagOptions.enableExpSignalTPC) + histos.fill(HIST("tracks/helium/h2HeliumTPCExpSignalDiffVsPt"), hePt, track.tpcExpSignalDiffHe()); + histos.fill(HIST("tracks/helium/h2HeliumVspTNSigmaITSTr"), track.p(), nITSTr); + histos.fill(HIST("tracks/helium/h2HeliumVspTNSigmaITSHe"), track.p(), nITSHe); + histos.fill(HIST("tracks/helium/h2HeliumVspTNSigmaTPC"), hePt, track.tpcNSigmaHe()); + } + if (isAntiHeWoTPCpid) { + if (outFlagOptions.enableExpSignalTPC) + histos.fill(HIST("tracks/helium/h2antiHeliumTPCExpSignalDiffVsPt"), antihePt, track.tpcExpSignalDiffHe()); + histos.fill(HIST("tracks/helium/h2antiHeliumVspTNSigmaITSTr"), track.p(), nITSTr); + histos.fill(HIST("tracks/helium/h2antiHeliumVspTNSigmaITSHe"), track.p(), nITSHe); + histos.fill(HIST("tracks/helium/h2antiHeliumVspTNSigmaTPC"), antihePt, track.tpcNSigmaHe()); + } + if (isHeWTPCpid) { + histos.fill(HIST("tracks/helium/h2HeliumVspTNSigmaITSTr_wTPCpid"), track.p(), nITSTr); + histos.fill(HIST("tracks/helium/h2HeliumVspTNSigmaITSHe_wTPCpid"), track.p(), nITSHe); + } + if (isAntiHeWTPCpid) { + histos.fill(HIST("tracks/helium/h2antiHeliumVspTNSigmaITSTr_wTPCpid"), track.p(), nITSTr); + histos.fill(HIST("tracks/helium/h2antiHeliumVspTNSigmaITSHe_wTPCpid"), track.p(), nITSHe); + } + if constexpr (!IsFilteredData) { + if (isHeWTPCpid || isAntiHeWTPCpid) { + if (nsigmaITSvar.showAverageClusterSize) { + histos.fill(HIST("tracks/helium/averageClusterSize"), track.p(), averageClusterSizeTrk(track)); + histos.fill(HIST("tracks/helium/averageClusterSizePerCoslInv"), track.p(), averageClusterSizePerCoslInv(track)); } } } - if (enableDe) { - if ((std::abs(track.tpcNSigmaDe()) < nsigmaTPCDe) && deRapCut) { - if (track.sign() > 0) { - if (enablePtSpectra) { - histos.fill(HIST("tracks/eff/deuteron/hPtDe"), DPt); - histos.fill(HIST("tracks/eff/deuteron/h2pVsTPCmomentumDe"), track.tpcInnerParam(), track.p()); - } - histos.fill(HIST("tracks/deuteron/h1DeuteronSpectra"), DPt); - histos.fill(HIST("tracks/deuteron/h2DeuteronYvsPt"), track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Deuteron)), DPt); - if (enablePIDplot) - histos.fill(HIST("tracks/deuteron/h2TPCsignVsTPCmomentumDeuteron"), track.tpcInnerParam(), track.tpcSignal()); - } else { - if (enablePtSpectra) { - histos.fill(HIST("tracks/eff/deuteron/hPtantiDe"), antiDPt); - histos.fill(HIST("tracks/eff/deuteron/h2pVsTPCmomentumantiDe"), track.tpcInnerParam(), track.p()); - } - histos.fill(HIST("tracks/deuteron/h1antiDeuteronSpectra"), antiDPt); - histos.fill(HIST("tracks/deuteron/h2antiDeuteronYvsPt"), track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Deuteron)), antiDPt); - if (enablePIDplot) - histos.fill(HIST("tracks/deuteron/h2TPCsignVsTPCmomentumantiDeuteron"), track.tpcInnerParam(), track.tpcSignal()); + // TOF + if (outFlagOptions.doTOFplots) { + + if (isDeWoTPCpid) { + switch (useHasTRDConfig) { + case 0: + histos.fill(HIST("tracks/deuteron/h2DeuteronVspTNSigmaTOF"), DPt, track.tofNSigmaDe()); + break; + case 1: + if (track.hasTRD()) { + histos.fill(HIST("tracks/deuteron/h2DeuteronVspTNSigmaTOF"), DPt, track.tofNSigmaDe()); + } + break; + case 2: + if (!track.hasTRD()) { + histos.fill(HIST("tracks/deuteron/h2DeuteronVspTNSigmaTOF"), DPt, track.tofNSigmaDe()); + } + break; + } + if (outFlagOptions.enableExpSignalTOF) + histos.fill(HIST("tracks/deuteron/h2DeuteronTOFExpSignalDiffVsPt"), DPt, track.tofExpSignalDiffDe()); + } + + if (isAntiDeWoTPCpid) { + switch (useHasTRDConfig) { + case 0: + histos.fill(HIST("tracks/deuteron/h2antiDeuteronVspTNSigmaTOF"), antiDPt, track.tofNSigmaDe()); + break; + case 1: + if (track.hasTRD()) { + histos.fill(HIST("tracks/deuteron/h2antiDeuteronVspTNSigmaTOF"), antiDPt, track.tofNSigmaDe()); + } + break; + case 2: + if (!track.hasTRD()) { + histos.fill(HIST("tracks/deuteron/h2antiDeuteronVspTNSigmaTOF"), antiDPt, track.tofNSigmaDe()); + } + break; } + if (outFlagOptions.enableExpSignalTOF) + histos.fill(HIST("tracks/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt"), antiDPt, track.tofExpSignalDiffDe()); + } + + if (isHeWoTPCpid) { + histos.fill(HIST("tracks/helium/h2HeliumVspTNSigmaTOF"), hePt, track.tofNSigmaHe()); + if (outFlagOptions.enableExpSignalTOF) + histos.fill(HIST("tracks/helium/h2HeliumTOFExpSignalDiffVsPt"), hePt, track.tofExpSignalDiffHe()); + } + + if (isAntiHeWoTPCpid) { + histos.fill(HIST("tracks/helium/h2antiHeliumVspTNSigmaTOF"), antihePt, track.tofNSigmaHe()); + if (outFlagOptions.enableExpSignalTOF) + histos.fill(HIST("tracks/helium/h2antiHeliumTOFExpSignalDiffVsPt"), antihePt, track.tofExpSignalDiffHe()); } } - if (enableTr) { - if ((isTriton) && trRapCut) { + if (passDCAxyzCut) { + // PID + if (enablePtSpectra && enableDebug) { if (track.sign() > 0) { - if (enablePtSpectra) { - histos.fill(HIST("tracks/eff/triton/hPtTr"), track.pt()); - histos.fill(HIST("tracks/eff/triton/h2pVsTPCmomentumTr"), track.tpcInnerParam(), track.p()); - } - histos.fill(HIST("tracks/triton/h1TritonSpectra"), track.pt()); - if (enablePIDplot) - histos.fill(HIST("tracks/triton/h2TPCsignVsTPCmomentumTriton"), track.tpcInnerParam(), track.tpcSignal()); + debugHistos.fill(HIST("tracks/eff/hPtP"), track.pt()); + debugHistos.fill(HIST("tracks/eff/hPtPrebinned"), track.pt()); } else { - if (enablePtSpectra) { - histos.fill(HIST("tracks/eff/triton/hPtantiTr"), track.pt()); - histos.fill(HIST("tracks/eff/triton/h2pVsTPCmomentumantiTr"), track.tpcInnerParam(), track.p()); - } - histos.fill(HIST("tracks/triton/h1antiTritonSpectra"), track.pt()); - if (enablePIDplot) - histos.fill(HIST("tracks/triton/h2TPCsignVsTPCmomentumantiTriton"), track.tpcInnerParam(), track.tpcSignal()); + debugHistos.fill(HIST("tracks/eff/hPtantiP"), track.pt()); + debugHistos.fill(HIST("tracks/eff/hPtantiPrebinned"), track.pt()); } } - } - if (enableHe) { - if ((std::abs(track.tpcNSigmaHe()) < nsigmaTPCHe) && heRapCut) { - if (track.sign() > 0) { - if (enablePtSpectra) { - histos.fill(HIST("tracks/eff/helium/hPtHe"), hePt); - histos.fill(HIST("tracks/eff/helium/h2pVsTPCmomentumHe"), heTPCmomentum, heP); - } - histos.fill(HIST("tracks/helium/h1HeliumSpectra"), hePt); - histos.fill(HIST("tracks/helium/h1HeliumSpectra_Z2"), 2 * hePt); - histos.fill(HIST("tracks/helium/h2HeliumYvsPt"), track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Helium3)), hePt); - histos.fill(HIST("tracks/helium/h2HeliumYvsPt_Z2"), track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Helium3)), 2 * hePt); - histos.fill(HIST("tracks/helium/h2HeliumEtavsPt"), track.eta(), hePt); - histos.fill(HIST("tracks/helium/h2HeliumEtavsPt_Z2"), track.eta(), 2 * hePt); - // if (enablePIDplot) - // histos.fill(HIST("tracks/helium/h2TPCsignVsTPCmomentumHelium"), heTPCmomentum, track.tpcSignal()); + if (enablePr) { + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCvar.nsigmaTPCPr && prRapCut) { + if (track.sign() > 0) { + if (enablePtSpectra) { + histos.fill(HIST("tracks/eff/proton/hPtPr"), track.pt()); + histos.fill(HIST("tracks/eff/proton/hPtPrrebinned"), track.pt()); + histos.fill(HIST("tracks/eff/proton/h2pVsTPCmomentumPr"), track.tpcInnerParam(), track.p()); + } + histos.fill(HIST("tracks/proton/h1ProtonSpectra"), track.pt()); + histos.fill(HIST("tracks/proton/h2ProtonYvsPt"), track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Proton)), track.pt()); + histos.fill(HIST("tracks/proton/h2ProtonEtavsPt"), track.eta(), track.pt()); - } else { - if (enablePtSpectra) { - histos.fill(HIST("tracks/eff/helium/hPtantiHe"), antihePt); - histos.fill(HIST("tracks/eff/helium/h2pVsTPCmomentumantiHe"), antiheTPCmomentum, antiheP); + if (enablePIDplot) + histos.fill(HIST("tracks/proton/h2TPCsignVsTPCmomentumProton"), track.tpcInnerParam(), track.tpcSignal()); + } else { + if (enablePtSpectra) { + histos.fill(HIST("tracks/eff/proton/hPtantiPr"), track.pt()); + histos.fill(HIST("tracks/eff/proton/hPtantiPrrebinned"), track.pt()); + histos.fill(HIST("tracks/eff/proton/h2pVsTPCmomentumantiPr"), track.tpcInnerParam(), track.p()); + } + histos.fill(HIST("tracks/proton/h1antiProtonSpectra"), track.pt()); + histos.fill(HIST("tracks/proton/h2antiProtonYvsPt"), track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Proton)), track.pt()); + histos.fill(HIST("tracks/proton/h2antiProtonEtavsPt"), track.eta(), track.pt()); + + if (enablePIDplot) + histos.fill(HIST("tracks/proton/h2TPCsignVsTPCmomentumantiProton"), track.tpcInnerParam(), track.tpcSignal()); } - histos.fill(HIST("tracks/helium/h1antiHeliumSpectra"), antihePt); - histos.fill(HIST("tracks/helium/h1antiHeliumSpectra_Z2"), 2 * antihePt); - histos.fill(HIST("tracks/helium/h2antiHeliumYvsPt"), track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Helium3)), antihePt); - histos.fill(HIST("tracks/helium/h2antiHeliumYvsPt_Z2"), track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Helium3)), 2 * antihePt); - histos.fill(HIST("tracks/helium/h2antiHeliumEtavsPt"), track.eta(), antihePt); - histos.fill(HIST("tracks/helium/h2antiHeliumEtavsPt_Z2"), track.eta(), 2 * antihePt); - // if (enablePIDplot) - // histos.fill(HIST("tracks/helium/h2TPCsignVsTPCmomentumantiHelium"), antiheTPCmomentum, track.tpcSignal()); - // } } } - } - if (enableAl) { - if ((std::abs(track.tpcNSigmaAl()) < nsigmaTPCAl) && alRapCut) { - if (track.sign() > 0) { - histos.fill(HIST("tracks/alpha/h1AlphaSpectra"), track.pt()); - if (enablePIDplot) - histos.fill(HIST("tracks/alpha/h2TPCsignVsTPCmomentumAlpha"), track.tpcInnerParam(), track.tpcSignal()); - } else { - histos.fill(HIST("tracks/alpha/h1antiAlphaSpectra"), track.pt()); - if (enablePIDplot) - histos.fill(HIST("tracks/alpha/h2TPCsignVsTPCmomentumantiAlpha"), track.tpcInnerParam(), track.tpcSignal()); + if (enableTr) { + if ((isTritonTPCpid) && trRapCut) { + if (track.sign() > 0) { + if (enablePtSpectra) { + histos.fill(HIST("tracks/eff/triton/hPtTr"), track.pt()); + histos.fill(HIST("tracks/eff/triton/h2pVsTPCmomentumTr"), track.tpcInnerParam(), track.p()); + } + histos.fill(HIST("tracks/triton/h1TritonSpectra"), track.pt()); + if (enablePIDplot) + histos.fill(HIST("tracks/triton/h2TPCsignVsTPCmomentumTriton"), track.tpcInnerParam(), track.tpcSignal()); + } else { + if (enablePtSpectra) { + histos.fill(HIST("tracks/eff/triton/hPtantiTr"), track.pt()); + histos.fill(HIST("tracks/eff/triton/h2pVsTPCmomentumantiTr"), track.tpcInnerParam(), track.p()); + } + histos.fill(HIST("tracks/triton/h1antiTritonSpectra"), track.pt()); + if (enablePIDplot) + histos.fill(HIST("tracks/triton/h2TPCsignVsTPCmomentumantiTriton"), track.tpcInnerParam(), track.tpcSignal()); + } + } + } + if (enableAl) { + if ((std::abs(track.tpcNSigmaAl()) < nsigmaTPCvar.nsigmaTPCAl) && alRapCut) { + if (track.sign() > 0) { + histos.fill(HIST("tracks/alpha/h1AlphaSpectra"), track.pt()); + if (enablePIDplot) + histos.fill(HIST("tracks/alpha/h2TPCsignVsTPCmomentumAlpha"), track.tpcInnerParam(), track.tpcSignal()); + } else { + histos.fill(HIST("tracks/alpha/h1antiAlphaSpectra"), track.pt()); + if (enablePIDplot) + histos.fill(HIST("tracks/alpha/h2TPCsignVsTPCmomentumantiAlpha"), track.tpcInnerParam(), track.tpcSignal()); + } } } - } - - if (doTOFplots) { - if (track.hasTOF()) { + if (outFlagOptions.doTOFplots && track.hasTOF()) { if (enablePtSpectra && enableDebug) { if (track.sign() > 0) { debugHistos.fill(HIST("tracks/eff/hPtPTOF"), track.pt()); @@ -3101,36 +4402,38 @@ struct LFNucleiBATask { } } - if (enableBetaCut && (track.beta() > betaCut)) + if (outFlagOptions.enableBetaCut && (track.beta() > betaCut) && enablePIDplot) histos.fill(HIST("tracks/h2TOFbetaVsP_BetaCut"), track.p() / (1.f * track.sign()), track.beta()); - switch (useHasTRDConfig) { - case 0: - histos.fill(HIST("tracks/h2TOFbetaVsP"), track.p() / (1.f * track.sign()), track.beta()); - break; - case 1: - if (track.hasTRD()) { - histos.fill(HIST("tracks/h2TOFbetaVsP"), track.p() / (1.f * track.sign()), track.beta()); - } - break; - case 2: - if (!track.hasTRD()) { + if (enablePIDplot) { + switch (useHasTRDConfig) { + case 0: histos.fill(HIST("tracks/h2TOFbetaVsP"), track.p() / (1.f * track.sign()), track.beta()); - } - break; + break; + case 1: + if (track.hasTRD()) { + histos.fill(HIST("tracks/h2TOFbetaVsP"), track.p() / (1.f * track.sign()), track.beta()); + } + break; + case 2: + if (!track.hasTRD()) { + histos.fill(HIST("tracks/h2TOFbetaVsP"), track.p() / (1.f * track.sign()), track.beta()); + } + break; + } } if (enablePtSpectra) histos.fill(HIST("tracks/eff/h2TPCmomentumVsTOFExpMomentum"), track.tofExpMom(), track.tpcInnerParam()); if (enablePr && prRapCut) { - if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCPr && track.sign() > 0) { + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCvar.nsigmaTPCPr && track.sign() > 0) { histos.fill(HIST("tracks/proton/h2ProtonTOFbetaVsP"), track.p(), track.beta()); if (enablePtSpectra) { histos.fill(HIST("tracks/eff/proton/h2pVsTOFExpMomentumPr"), track.tofExpMom(), track.p()); histos.fill(HIST("tracks/eff/proton/h2TPCmomentumVsTOFExpMomentumPr"), track.tofExpMom(), track.tpcInnerParam()); } } - if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCPr && track.sign() < 0) { + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCvar.nsigmaTPCPr && track.sign() < 0) { histos.fill(HIST("tracks/proton/h2antiProtonTOFbetaVsP"), track.p(), track.beta()); if (enablePtSpectra) { histos.fill(HIST("tracks/eff/proton/h2pVsTOFExpMomentumantiPr"), track.tofExpMom(), track.p()); @@ -3138,31 +4441,15 @@ struct LFNucleiBATask { } } } - if (enableDe && deRapCut) { - if (std::abs(track.tpcNSigmaDe()) < nsigmaTPCDe && track.sign() > 0) { - histos.fill(HIST("tracks/deuteron/h2DeuteronTOFbetaVsP"), track.p(), track.beta()); - if (enablePtSpectra) { - histos.fill(HIST("tracks/eff/deuteron/h2pVsTOFExpMomentumDe"), track.tofExpMom(), track.p()); - histos.fill(HIST("tracks/eff/deuteron/h2TPCmomentumVsTOFExpMomentumDe"), track.tofExpMom(), track.tpcInnerParam()); - } - } - if (std::abs(track.tpcNSigmaDe()) < nsigmaTPCDe && track.sign() < 0) { - histos.fill(HIST("tracks/deuteron/h2antiDeuteronTOFbetaVsP"), track.p(), track.beta()); - if (enablePtSpectra) { - histos.fill(HIST("tracks/eff/deuteron/h2pVsTOFExpMomentumantiDe"), track.tofExpMom(), track.p()); - histos.fill(HIST("tracks/eff/deuteron/h2TPCmomentumVsTOFExpMomentumantiDe"), track.tofExpMom(), track.tpcInnerParam()); - } - } - } if (enableTr && trRapCut) { - if (isTriton && track.sign() > 0) { + if (isTritonTPCpid && track.sign() > 0) { histos.fill(HIST("tracks/triton/h2TritonTOFbetaVsP"), track.p(), track.beta()); if (enablePtSpectra) { histos.fill(HIST("tracks/eff/triton/h2pVsTOFExpMomentumTr"), track.tofExpMom(), track.p()); histos.fill(HIST("tracks/eff/triton/h2TPCmomentumVsTOFExpMomentumTr"), track.tofExpMom(), track.tpcInnerParam()); } } - if (isTriton && track.sign() < 0) { + if (isTritonTPCpid && track.sign() < 0) { histos.fill(HIST("tracks/triton/h2antiTritonTOFbetaVsP"), track.p(), track.beta()); if (enablePtSpectra) { histos.fill(HIST("tracks/eff/triton/h2pVsTOFExpMomentumantiTr"), track.tofExpMom(), track.p()); @@ -3170,38 +4457,7 @@ struct LFNucleiBATask { } } } - if (enableHe && heRapCut) { - if (std::abs(track.tpcNSigmaHe()) < nsigmaTPCHe && track.sign() > 0) { - histos.fill(HIST("tracks/helium/h2HeliumTOFbetaVsP"), heP, track.beta()); - if (enablePtSpectra) { - histos.fill(HIST("tracks/eff/helium/h2pVsTOFExpMomentumHe"), track.tofExpMom(), heP); - histos.fill(HIST("tracks/eff/helium/h2TPCmomentumVsTOFExpMomentumHe"), track.tofExpMom(), heTPCmomentum); - } - } - if (std::abs(track.tpcNSigmaHe()) < nsigmaTPCHe && track.sign() < 0) { - histos.fill(HIST("tracks/helium/h2antiHeliumTOFbetaVsP"), antiheP, track.beta()); - if (enablePtSpectra) { - histos.fill(HIST("tracks/eff/helium/h2pVsTOFExpMomentumantiHe"), track.tofExpMom(), antiheP); - histos.fill(HIST("tracks/eff/helium/h2TPCmomentumVsTOFExpMomentumantiHe"), track.tofExpMom(), antiheTPCmomentum); - } - } - } - - if (enableDebug) { - if (enablePr && prRapCut) { - if (track.sign() > 0) - debugHistos.fill(HIST("debug/tracks/proton/h3ProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); - else - debugHistos.fill(HIST("debug/tracks/proton/h3antiProtonNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); - } - if (enableDe && deRapCut) { - if (track.sign() > 0) - debugHistos.fill(HIST("debug/tracks/deuteron/h3DeuteronNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaDe(), track.tofNSigmaDe(), DPt); - else - debugHistos.fill(HIST("debug/tracks/deuteron/h3antiDeuteronNSigmaTPCvsNSigmaTOFvsPt"), track.tpcNSigmaDe(), track.tofNSigmaDe(), antiDPt); - } - } - if (enableEvTimeSplitting) { + if (filterOptions.enableEvTimeSplitting) { if (track.isEvTimeTOF() && track.isEvTimeT0AC()) { evtimeHistos.fill(HIST("tracks/evtime/ft0tof/h2TOFbetaVsP"), track.p() / (1.f * track.sign()), track.beta()); evtimeHistos.fill(HIST("tracks/evtime/ft0tof/h2TPCsignVsTPCmomentum"), track.tpcInnerParam() / (1.f * track.sign()), track.tpcSignal()); @@ -3216,35 +4472,120 @@ struct LFNucleiBATask { evtimeHistos.fill(HIST("tracks/evtime/fill/h2TPCsignVsTPCmomentum"), track.tpcInnerParam() / (1.f * track.sign()), track.tpcSignal()); } } + } + } - if ((track.beta() * track.beta()) < 1.) { - gamma = 1.f / TMath::Sqrt(1.f - (track.beta() * track.beta())); + if (isDeWTPCpid) { + if (enablePtSpectra) { + histos.fill(HIST("tracks/eff/deuteron/hPtDe"), DPt); + histos.fill(HIST("tracks/eff/deuteron/h2pVsTPCmomentumDe"), track.tpcInnerParam(), track.p()); + } + histos.fill(HIST("tracks/deuteron/h1DeuteronSpectra"), DPt); + histos.fill(HIST("tracks/deuteron/h2DeuteronYvsPt"), track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Deuteron)), DPt); + if (enablePIDplot) + histos.fill(HIST("tracks/deuteron/h2TPCsignVsTPCmomentumDeuteron"), track.tpcInnerParam(), track.tpcSignal()); + } + if (isAntiDeWTPCpid) { + if (enablePtSpectra) { + histos.fill(HIST("tracks/eff/deuteron/hPtantiDe"), antiDPt); + histos.fill(HIST("tracks/eff/deuteron/h2pVsTPCmomentumantiDe"), track.tpcInnerParam(), track.p()); + } + histos.fill(HIST("tracks/deuteron/h1antiDeuteronSpectra"), antiDPt); + histos.fill(HIST("tracks/deuteron/h2antiDeuteronYvsPt"), track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Deuteron)), antiDPt); + if (enablePIDplot) + histos.fill(HIST("tracks/deuteron/h2TPCsignVsTPCmomentumantiDeuteron"), track.tpcInnerParam(), track.tpcSignal()); + } + if (isHeWTPCpid) { + if (enablePtSpectra) { + histos.fill(HIST("tracks/eff/helium/hPtHe"), 2 * hePt); + histos.fill(HIST("tracks/eff/helium/h2pVsTPCmomentumHe"), heTPCmomentum, heP); + } + histos.fill(HIST("tracks/helium/h1HeliumSpectra"), hePt); + histos.fill(HIST("tracks/helium/h1HeliumSpectra_Z2"), 2 * hePt); + histos.fill(HIST("tracks/helium/h2HeliumYvsPt"), track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Helium3)), hePt); + histos.fill(HIST("tracks/helium/h2HeliumYvsPt_Z2"), track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Helium3)), 2 * hePt); + histos.fill(HIST("tracks/helium/h2HeliumEtavsPt"), track.eta(), hePt); + histos.fill(HIST("tracks/helium/h2HeliumEtavsPt_Z2"), track.eta(), 2 * hePt); + if (enablePIDplot) + histos.fill(HIST("tracks/helium/h2TPCsignVsTPCmomentumHelium"), heTPCmomentum, track.tpcSignal()); + } + if (isAntiHeWTPCpid) { + if (enablePtSpectra) { + histos.fill(HIST("tracks/eff/helium/hPtantiHe"), 2 * antihePt); + histos.fill(HIST("tracks/eff/helium/h2pVsTPCmomentumantiHe"), antiheTPCmomentum, antiheP); + } + histos.fill(HIST("tracks/helium/h1antiHeliumSpectra"), antihePt); + histos.fill(HIST("tracks/helium/h1antiHeliumSpectra_Z2"), 2 * antihePt); + histos.fill(HIST("tracks/helium/h2antiHeliumYvsPt"), track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Helium3)), antihePt); + histos.fill(HIST("tracks/helium/h2antiHeliumYvsPt_Z2"), track.rapidity(o2::track::PID::getMass2Z(o2::track::PID::Helium3)), 2 * antihePt); + histos.fill(HIST("tracks/helium/h2antiHeliumEtavsPt"), track.eta(), antihePt); + histos.fill(HIST("tracks/helium/h2antiHeliumEtavsPt_Z2"), track.eta(), 2 * antihePt); + if (enablePIDplot) + histos.fill(HIST("tracks/helium/h2TPCsignVsTPCmomentumantiHelium"), antiheTPCmomentum, track.tpcSignal()); + } - switch (massTOFConfig) { - case 0: - massTOF = track.tpcInnerParam() * TMath::Sqrt(1.f / (track.beta() * track.beta()) - 1.f); - massTOFhe = heTPCmomentum * TMath::Sqrt(1.f / (track.beta() * track.beta()) - 1.f); - massTOFantihe = antiheTPCmomentum * TMath::Sqrt(1.f / (track.beta() * track.beta()) - 1.f); - break; - case 1: - massTOF = track.tofExpMom() * TMath::Sqrt(1.f / (track.beta() * track.beta()) - 1.f); - break; - case 2: - massTOF = track.p() * TMath::Sqrt(1.f / (track.beta() * track.beta()) - 1.f); - massTOFhe = heP * TMath::Sqrt(1.f / (track.beta() * track.beta()) - 1.f); - massTOFantihe = antiheP * TMath::Sqrt(1.f / (track.beta() * track.beta()) - 1.f); - break; - } - histos.fill(HIST("tracks/h2TPCsignVsBetaGamma"), (track.beta() * gamma) / (1.f * track.sign()), track.tpcSignal()); - } else { - massTOF = -99.f; - massTOFhe = -99.f; - massTOFantihe = -99.f; + if (outFlagOptions.doTOFplots && track.hasTOF()) { + if (isDeWTPCpid) { + histos.fill(HIST("tracks/deuteron/h2DeuteronTOFbetaVsP"), track.p(), track.beta()); + if (enablePtSpectra) { + histos.fill(HIST("tracks/eff/deuteron/h2pVsTOFExpMomentumDe"), track.tofExpMom(), track.p()); + histos.fill(HIST("tracks/eff/deuteron/h2TPCmomentumVsTOFExpMomentumDe"), track.tofExpMom(), track.tpcInnerParam()); + } + } + if (isAntiDeWTPCpid) { + histos.fill(HIST("tracks/deuteron/h2antiDeuteronTOFbetaVsP"), track.p(), track.beta()); + if (enablePtSpectra) { + histos.fill(HIST("tracks/eff/deuteron/h2pVsTOFExpMomentumantiDe"), track.tofExpMom(), track.p()); + histos.fill(HIST("tracks/eff/deuteron/h2TPCmomentumVsTOFExpMomentumantiDe"), track.tofExpMom(), track.tpcInnerParam()); } + } + + if (isHeWTPCpid) { + histos.fill(HIST("tracks/helium/h2HeliumTOFbetaVsP"), heP, track.beta()); + if (enablePtSpectra) { + histos.fill(HIST("tracks/eff/helium/h2pVsTOFExpMomentumHe"), track.tofExpMom(), heP); + histos.fill(HIST("tracks/eff/helium/h2TPCmomentumVsTOFExpMomentumHe"), track.tofExpMom(), heTPCmomentum); + } + } + + if (isAntiHeWTPCpid) { + histos.fill(HIST("tracks/helium/h2antiHeliumTOFbetaVsP"), antiheP, track.beta()); + if (enablePtSpectra) { + histos.fill(HIST("tracks/eff/helium/h2pVsTOFExpMomentumantiHe"), track.tofExpMom(), antiheP); + histos.fill(HIST("tracks/eff/helium/h2TPCmomentumVsTOFExpMomentumantiHe"), track.tofExpMom(), antiheTPCmomentum); + } + } + + if ((track.beta() * track.beta()) < 1.) { + gamma = 1.f / std::sqrt(1.f - (track.beta() * track.beta())); - histos.fill(HIST("tracks/h2TOFmassVsPt"), massTOF, track.pt()); + switch (massTOFConfig) { + case 0: + massTOF = track.tpcInnerParam() * std::sqrt(1.f / (track.beta() * track.beta()) - 1.f); + massTOFhe = heTPCmomentum * std::sqrt(1.f / (track.beta() * track.beta()) - 1.f); + massTOFantihe = antiheTPCmomentum * std::sqrt(1.f / (track.beta() * track.beta()) - 1.f); + break; + case 1: + massTOF = track.tofExpMom() * std::sqrt(1.f / (track.beta() * track.beta()) - 1.f); + break; + case 2: + massTOF = track.p() * std::sqrt(1.f / (track.beta() * track.beta()) - 1.f); + massTOFhe = heP * std::sqrt(1.f / (track.beta() * track.beta()) - 1.f); + massTOFantihe = antiheP * std::sqrt(1.f / (track.beta() * track.beta()) - 1.f); + break; + } + if (passDCAxyzCut && outFlagOptions.doTOFplots && enablePIDplot) + histos.fill(HIST("tracks/h2TPCsignVsBetaGamma"), (track.beta() * gamma) / (1.f * track.sign()), track.tpcSignal()); + } else { + massTOF = -99.f; + massTOFhe = -99.f; + massTOFantihe = -99.f; + } - if (enableEvTimeSplitting) { + if (passDCAxyzCut) { + if (enablePIDplot) + histos.fill(HIST("tracks/h2TOFmassVsPt"), massTOF, track.pt()); + if (filterOptions.enableEvTimeSplitting) { if (track.isEvTimeTOF() && track.isEvTimeT0AC()) { evtimeHistos.fill(HIST("tracks/evtime/ft0tof/h2TOFmassVsPt"), massTOF, track.pt()); } else if (track.isEvTimeT0AC()) { @@ -3257,29 +4598,29 @@ struct LFNucleiBATask { } if (enablePr) { - if ((std::abs(track.tpcNSigmaPr()) < nsigmaTPCPr) && prRapCut) { + if ((std::abs(track.tpcNSigmaPr()) < nsigmaTPCvar.nsigmaTPCPr) && prRapCut) { if (track.sign() > 0) { if (enablePtSpectra) { histos.fill(HIST("tracks/eff/proton/hPtPrTOF"), track.pt()); histos.fill(HIST("tracks/eff/proton/hPtPrTOFrebinned"), track.pt()); } histos.fill(HIST("tracks/proton/h2TOFmassProtonVsPt"), massTOF, track.pt()); - histos.fill(HIST("tracks/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - fMassProton * fMassProton, track.pt()); - if (enableBetaCut && (track.beta() > betaCut)) { + histos.fill(HIST("tracks/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); + if (outFlagOptions.enableBetaCut && (track.beta() > betaCut)) { histos.fill(HIST("tracks/proton/h2TOFmassProtonVsPt_BetaCut"), massTOF, track.pt()); - histos.fill(HIST("tracks/proton/h2TOFmass2ProtonVsPt_BetaCut"), massTOF * massTOF - fMassProton * fMassProton, track.pt()); + histos.fill(HIST("tracks/proton/h2TOFmass2ProtonVsPt_BetaCut"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); } - if (enableExpSignalTOF) + if (outFlagOptions.enableExpSignalTOF) histos.fill(HIST("tracks/proton/h2ProtonTOFExpSignalDiffVsPtCut"), track.pt(), track.tofExpSignalDiffPr()); - if (enableEvTimeSplitting) { + if (filterOptions.enableEvTimeSplitting) { if (track.isEvTimeTOF() && track.isEvTimeT0AC()) { - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - fMassProton * fMassProton, track.pt()); + evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); } else if (track.isEvTimeT0AC()) { - evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - fMassProton * fMassProton, track.pt()); + evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); } else if (track.isEvTimeTOF()) { - evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - fMassProton * fMassProton, track.pt()); + evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); } else { - evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - fMassProton * fMassProton, track.pt()); + evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); } } } else { @@ -3288,78 +4629,22 @@ struct LFNucleiBATask { histos.fill(HIST("tracks/eff/proton/hPtantiPrTOFrebinned"), track.pt()); } histos.fill(HIST("tracks/proton/h2TOFmassantiProtonVsPt"), massTOF, track.pt()); - histos.fill(HIST("tracks/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - fMassProton * fMassProton, track.pt()); - if (enableBetaCut && (track.beta() > betaCut)) { + histos.fill(HIST("tracks/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); + if (outFlagOptions.enableBetaCut && (track.beta() > betaCut)) { histos.fill(HIST("tracks/proton/h2TOFmassantiProtonVsPt_BetaCut"), massTOF, track.pt()); - histos.fill(HIST("tracks/proton/h2TOFmass2antiProtonVsPt_BetaCut"), massTOF * massTOF - fMassProton * fMassProton, track.pt()); + histos.fill(HIST("tracks/proton/h2TOFmass2antiProtonVsPt_BetaCut"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); } - if (enableExpSignalTOF) + if (outFlagOptions.enableExpSignalTOF) histos.fill(HIST("tracks/proton/h2antiProtonTOFExpSignalDiffVsPtCut"), track.pt(), track.tofExpSignalDiffPr()); - if (enableEvTimeSplitting) { - if (track.isEvTimeTOF() && track.isEvTimeT0AC()) { - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - fMassProton * fMassProton, track.pt()); - } else if (track.isEvTimeT0AC()) { - evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - fMassProton * fMassProton, track.pt()); - } else if (track.isEvTimeTOF()) { - evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - fMassProton * fMassProton, track.pt()); - } else { - evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - fMassProton * fMassProton, track.pt()); - } - } - } - } - } - if (enableDe) { - if ((std::abs(track.tpcNSigmaDe()) < nsigmaTPCDe) && deRapCut) { - if (track.sign() > 0) { - if (enablePtSpectra) - histos.fill(HIST("tracks/eff/deuteron/hPtDeTOF"), DPt); - histos.fill(HIST("tracks/deuteron/h2TOFmassDeuteronVsPt"), massTOF, DPt); - if (enableCentrality) - histos.fill(HIST("tracks/deuteron/h3TOFmass2DeuteronVsPtVsMult"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, DPt, event.centFT0M()); - else - histos.fill(HIST("tracks/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, DPt); - if (enableBetaCut && (track.beta() > betaCut)) { - histos.fill(HIST("tracks/deuteron/h2TOFmassDeuteronVsPt_BetaCut"), massTOF, DPt); - histos.fill(HIST("tracks/deuteron/h2TOFmass2DeuteronVsPt_BetaCut"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, DPt); - } - if (enableExpSignalTOF) - histos.fill(HIST("tracks/deuteron/h2DeuteronTOFExpSignalDiffVsPtCut"), DPt, track.tofExpSignalDiffDe()); - if (enableEvTimeSplitting) { - if (track.isEvTimeTOF() && track.isEvTimeT0AC()) { - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, DPt); - } else if (track.isEvTimeT0AC()) { - evtimeHistos.fill(HIST("tracks/evtime/ft0/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, DPt); - } else if (track.isEvTimeTOF()) { - evtimeHistos.fill(HIST("tracks/evtime/tof/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, DPt); - } else { - evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, DPt); - } - } - - } else { - if (enablePtSpectra) - histos.fill(HIST("tracks/eff/deuteron/hPtantiDeTOF"), antiDPt); - histos.fill(HIST("tracks/deuteron/h2TOFmassantiDeuteronVsPt"), massTOF, antiDPt); - if (enableCentrality) - histos.fill(HIST("tracks/deuteron/h3TOFmass2antiDeuteronVsPtVsMult"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, antiDPt, event.centFT0M()); - else - histos.fill(HIST("tracks/deuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, antiDPt); - if (enableBetaCut && (track.beta() > betaCut)) { - histos.fill(HIST("tracks/deuteron/h2TOFmassantiDeuteronVsPt_BetaCut"), massTOF, antiDPt); - histos.fill(HIST("tracks/deuteron/h2TOFmass2antiDeuteronVsPt_BetaCut"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, antiDPt); - } - if (enableExpSignalTOF) - histos.fill(HIST("tracks/deuteron/h2antiDeuteronTOFExpSignalDiffVsPtCut"), antiDPt, track.tofExpSignalDiffDe()); - if (enableEvTimeSplitting) { + if (filterOptions.enableEvTimeSplitting) { if (track.isEvTimeTOF() && track.isEvTimeT0AC()) { - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/deuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, antiDPt); + evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); } else if (track.isEvTimeT0AC()) { - evtimeHistos.fill(HIST("tracks/evtime/ft0/deuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, antiDPt); + evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); } else if (track.isEvTimeTOF()) { - evtimeHistos.fill(HIST("tracks/evtime/tof/deuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, antiDPt); + evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); } else { - evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, antiDPt); + evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); } } } @@ -3367,58 +4652,109 @@ struct LFNucleiBATask { } if (enableTr) { - if ((isTriton) && trRapCut) { + if ((isTritonTPCpid) && trRapCut) { if (track.sign() > 0) { if (enablePtSpectra) histos.fill(HIST("tracks/eff/triton/hPtTrTOF"), track.pt()); histos.fill(HIST("tracks/triton/h2TOFmassTritonVsPt"), massTOF, track.pt()); - histos.fill(HIST("tracks/triton/h2TOFmass2TritonVsPt"), massTOF * massTOF - fMassTriton * fMassTriton, track.pt()); - if (enableBetaCut && (track.beta() > betaCut)) { + histos.fill(HIST("tracks/triton/h2TOFmass2TritonVsPt"), massTOF * massTOF - MassTritonVal * MassTritonVal, track.pt()); + if (outFlagOptions.enableBetaCut && (track.beta() > betaCut)) { histos.fill(HIST("tracks/triton/h2TOFmassTritonVsPt_BetaCut"), massTOF, track.pt()); - histos.fill(HIST("tracks/triton/h2TOFmass2TritonVsPt_BetaCut"), massTOF * massTOF - fMassTriton * fMassTriton, track.pt()); + histos.fill(HIST("tracks/triton/h2TOFmass2TritonVsPt_BetaCut"), massTOF * massTOF - MassTritonVal * MassTritonVal, track.pt()); } } else { if (enablePtSpectra) histos.fill(HIST("tracks/eff/triton/hPtantiTrTOF"), track.pt()); histos.fill(HIST("tracks/triton/h2TOFmassantiTritonVsPt"), massTOF, track.pt()); - histos.fill(HIST("tracks/triton/h2TOFmass2antiTritonVsPt"), massTOF * massTOF - fMassTriton * fMassTriton, track.pt()); - if (enableBetaCut && (track.beta() > betaCut)) { + histos.fill(HIST("tracks/triton/h2TOFmass2antiTritonVsPt"), massTOF * massTOF - MassTritonVal * MassTritonVal, track.pt()); + if (outFlagOptions.enableBetaCut && (track.beta() > betaCut)) { histos.fill(HIST("tracks/triton/h2TOFmassantiTritonVsPt_BetaCut"), massTOF, track.pt()); - histos.fill(HIST("tracks/triton/h2TOFmass2antiTritonVsPt_BetaCut"), massTOF * massTOF - fMassTriton * fMassTriton, track.pt()); + histos.fill(HIST("tracks/triton/h2TOFmass2antiTritonVsPt_BetaCut"), massTOF * massTOF - MassTritonVal * MassTritonVal, track.pt()); } } } } - if (enableHe) { - if ((std::abs(track.tpcNSigmaHe()) < nsigmaTPCHe) && heRapCut) { - if (track.sign() > 0) { - if (enablePtSpectra) - histos.fill(HIST("tracks/eff/helium/hPtHeTOF"), hePt); - histos.fill(HIST("tracks/helium/h2TOFmassHeliumVsPt"), 2.f * massTOFhe, hePt); - histos.fill(HIST("tracks/helium/h2TOFmassDeltaHeliumVsPt"), 2.f * massTOFhe - fMassHelium, hePt); - histos.fill(HIST("tracks/helium/h2TOFmass2HeliumVsPt"), 2.f * massTOFhe * 2.f * massTOFhe - fMassHelium * fMassHelium, hePt); - if (enableBetaCut && (track.beta() > betaCut)) { - histos.fill(HIST("tracks/helium/h2TOFmassHeliumVsPt_BetaCut"), 2.f * massTOFhe, hePt); - histos.fill(HIST("tracks/helium/h2TOFmass2HeliumVsPt_BetaCut"), 2.f * massTOFhe * 2.f * massTOFhe - fMassHelium * fMassHelium, hePt); - } - if (enableExpSignalTOF) - histos.fill(HIST("tracks/helium/h2HeliumTOFExpSignalDiffVsPtCut"), hePt, track.tofExpSignalDiffHe()); - } else { - if (enablePtSpectra) - histos.fill(HIST("tracks/eff/helium/hPtantiHeTOF"), antihePt); - histos.fill(HIST("tracks/helium/h2TOFmassantiHeliumVsPt"), 2.f * massTOFantihe, antihePt); - histos.fill(HIST("tracks/helium/h2TOFmassDeltaantiHeliumVsPt"), 2.f * massTOFantihe - fMassHelium, antihePt); - histos.fill(HIST("tracks/helium/h2TOFmass2antiHeliumVsPt"), 2.f * massTOFantihe * 2.f * massTOFantihe - fMassHelium * fMassHelium, antihePt); - if (enableBetaCut && (track.beta() > betaCut)) { - histos.fill(HIST("tracks/helium/h2TOFmassantiHeliumVsPt_BetaCut"), 2.f * massTOFantihe, antihePt); - histos.fill(HIST("tracks/helium/h2TOFmass2antiHeliumVsPt_BetaCut"), 2.f * massTOFantihe * 2.f * massTOFantihe - fMassHelium * fMassHelium, antihePt); - } - if (enableExpSignalTOF) - histos.fill(HIST("tracks/helium/h2antiHeliumTOFExpSignalDiffVsPtCut"), antihePt, track.tofExpSignalDiffHe()); - } + } + + if (isDeWTPCpid) { + if (enablePtSpectra) + histos.fill(HIST("tracks/eff/deuteron/hPtDeTOF"), DPt); + histos.fill(HIST("tracks/deuteron/h2TOFmassDeuteronVsPt"), massTOF, DPt); + if (enableCentrality) + histos.fill(HIST("tracks/deuteron/h3TOFmass2DeuteronVsPtVsMult"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, DPt, event.centFT0M()); + else + histos.fill(HIST("tracks/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, DPt); + if (outFlagOptions.enableBetaCut && (track.beta() > betaCut)) { + histos.fill(HIST("tracks/deuteron/h2TOFmassDeuteronVsPt_BetaCut"), massTOF, DPt); + histos.fill(HIST("tracks/deuteron/h2TOFmass2DeuteronVsPt_BetaCut"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, DPt); + } + if (outFlagOptions.enableExpSignalTOF) + histos.fill(HIST("tracks/deuteron/h2DeuteronTOFExpSignalDiffVsPtCut"), DPt, track.tofExpSignalDiffDe()); + if (filterOptions.enableEvTimeSplitting) { + if (track.isEvTimeTOF() && track.isEvTimeT0AC()) { + evtimeHistos.fill(HIST("tracks/evtime/ft0tof/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, DPt); + } else if (track.isEvTimeT0AC()) { + evtimeHistos.fill(HIST("tracks/evtime/ft0/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, DPt); + } else if (track.isEvTimeTOF()) { + evtimeHistos.fill(HIST("tracks/evtime/tof/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, DPt); + } else { + evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, DPt); + } + } + } + if (isAntiDeWTPCpid) { + if (enablePtSpectra) + histos.fill(HIST("tracks/eff/deuteron/hPtantiDeTOF"), antiDPt); + histos.fill(HIST("tracks/deuteron/h2TOFmassantiDeuteronVsPt"), massTOF, antiDPt); + if (enableCentrality) + histos.fill(HIST("tracks/deuteron/h3TOFmass2antiDeuteronVsPtVsMult"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, antiDPt, event.centFT0M()); + else + histos.fill(HIST("tracks/deuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, antiDPt); + if (outFlagOptions.enableBetaCut && (track.beta() > betaCut)) { + histos.fill(HIST("tracks/deuteron/h2TOFmassantiDeuteronVsPt_BetaCut"), massTOF, antiDPt); + histos.fill(HIST("tracks/deuteron/h2TOFmass2antiDeuteronVsPt_BetaCut"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, antiDPt); + } + if (outFlagOptions.enableExpSignalTOF) + histos.fill(HIST("tracks/deuteron/h2antiDeuteronTOFExpSignalDiffVsPtCut"), antiDPt, track.tofExpSignalDiffDe()); + if (filterOptions.enableEvTimeSplitting) { + if (track.isEvTimeTOF() && track.isEvTimeT0AC()) { + evtimeHistos.fill(HIST("tracks/evtime/ft0tof/deuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, antiDPt); + } else if (track.isEvTimeT0AC()) { + evtimeHistos.fill(HIST("tracks/evtime/ft0/deuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, antiDPt); + } else if (track.isEvTimeTOF()) { + evtimeHistos.fill(HIST("tracks/evtime/tof/deuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, antiDPt); + } else { + evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, antiDPt); } } } + + if (isHeWTPCpid) { + if (enablePtSpectra) + histos.fill(HIST("tracks/eff/helium/hPtHeTOF"), 2 * hePt); + histos.fill(HIST("tracks/helium/h2TOFmassHeliumVsPt"), 2.f * massTOFhe, hePt); + histos.fill(HIST("tracks/helium/h2TOFmassDeltaHeliumVsPt"), 2.f * massTOFhe - MassHeliumVal, hePt); + histos.fill(HIST("tracks/helium/h2TOFmass2HeliumVsPt"), 2.f * massTOFhe * 2.f * massTOFhe - MassHeliumVal * MassHeliumVal, hePt); + if (outFlagOptions.enableBetaCut && (track.beta() > betaCut)) { + histos.fill(HIST("tracks/helium/h2TOFmassHeliumVsPt_BetaCut"), 2.f * massTOFhe, hePt); + histos.fill(HIST("tracks/helium/h2TOFmass2HeliumVsPt_BetaCut"), 2.f * massTOFhe * 2.f * massTOFhe - MassHeliumVal * MassHeliumVal, hePt); + } + if (outFlagOptions.enableExpSignalTOF) + histos.fill(HIST("tracks/helium/h2HeliumTOFExpSignalDiffVsPtCut"), hePt, track.tofExpSignalDiffHe()); + } + if (isAntiHeWTPCpid) { + if (enablePtSpectra) + histos.fill(HIST("tracks/eff/helium/hPtantiHeTOF"), 2 * antihePt); + histos.fill(HIST("tracks/helium/h2TOFmassantiHeliumVsPt"), 2.f * massTOFantihe, antihePt); + histos.fill(HIST("tracks/helium/h2TOFmassDeltaantiHeliumVsPt"), 2.f * massTOFantihe - MassHeliumVal, antihePt); + histos.fill(HIST("tracks/helium/h2TOFmass2antiHeliumVsPt"), 2.f * massTOFantihe * 2.f * massTOFantihe - MassHeliumVal * MassHeliumVal, antihePt); + if (outFlagOptions.enableBetaCut && (track.beta() > betaCut)) { + histos.fill(HIST("tracks/helium/h2TOFmassantiHeliumVsPt_BetaCut"), 2.f * massTOFantihe, antihePt); + histos.fill(HIST("tracks/helium/h2TOFmass2antiHeliumVsPt_BetaCut"), 2.f * massTOFantihe * 2.f * massTOFantihe - MassHeliumVal * MassHeliumVal, antihePt); + } + if (outFlagOptions.enableExpSignalTOF) + histos.fill(HIST("tracks/helium/h2antiHeliumTOFExpSignalDiffVsPtCut"), antihePt, track.tofExpSignalDiffHe()); + } } if constexpr (IsMC) { @@ -3470,106 +4806,107 @@ struct LFNucleiBATask { isGoodHit = !hasFakeHit; } - if ((track.sign() > 0) && enableTrackingEff) { - if (isItsPassed) { - debugHistos.fill(HIST("tracks/trackingEff/h1_its"), track.pt()); - if (isGoodHit) { - debugHistos.fill(HIST("tracks/trackingEff/h1GoodHit_its"), track.pt()); + if (passDCAxyzCut) { + if ((track.sign() > 0) && enableTrackingEff) { + if (isItsPassed) { + debugHistos.fill(HIST("tracks/trackingEff/h1_its"), track.pt()); + if (isGoodHit) { + debugHistos.fill(HIST("tracks/trackingEff/h1GoodHit_its"), track.pt()); + } } - } - if (isTpcPassed) { - debugHistos.fill(HIST("tracks/trackingEff/h1_tpc"), track.pt()); - if (isGoodHit) { - debugHistos.fill(HIST("tracks/trackingEff/h1GoodHit_tpc"), track.pt()); + if (isTpcPassed) { + debugHistos.fill(HIST("tracks/trackingEff/h1_tpc"), track.pt()); + if (isGoodHit) { + debugHistos.fill(HIST("tracks/trackingEff/h1GoodHit_tpc"), track.pt()); + } } - } - if (isItsPassed && isTpcPassed) { - debugHistos.fill(HIST("tracks/trackingEff/h1_its_tpc"), track.pt()); - if (isGoodHit) { - debugHistos.fill(HIST("tracks/trackingEff/h1GoodHit_its_tpc"), track.pt()); + if (isItsPassed && isTpcPassed) { + debugHistos.fill(HIST("tracks/trackingEff/h1_its_tpc"), track.pt()); + if (isGoodHit) { + debugHistos.fill(HIST("tracks/trackingEff/h1GoodHit_its_tpc"), track.pt()); + } } - } - if (isItsPassed && isTpcPassed && track.hasTOF()) { - debugHistos.fill(HIST("tracks/trackingEff/h1_its_tpc_tof"), track.pt()); - if (isGoodHit) { - debugHistos.fill(HIST("tracks/trackingEff/h1GoodHit_its_tpc_tof"), track.pt()); + if (isItsPassed && isTpcPassed && track.hasTOF()) { + debugHistos.fill(HIST("tracks/trackingEff/h1_its_tpc_tof"), track.pt()); + if (isGoodHit) { + debugHistos.fill(HIST("tracks/trackingEff/h1GoodHit_its_tpc_tof"), track.pt()); + } } - } - if (isItsPassed && isTpcPassed && track.hasTRD()) { - debugHistos.fill(HIST("tracks/trackingEff/h1_its_tpc_trd"), track.pt()); - if (isGoodHit) { - debugHistos.fill(HIST("tracks/trackingEff/h1GoodHit_its_tpc_trd"), track.pt()); + if (isItsPassed && isTpcPassed && track.hasTRD()) { + debugHistos.fill(HIST("tracks/trackingEff/h1_its_tpc_trd"), track.pt()); + if (isGoodHit) { + debugHistos.fill(HIST("tracks/trackingEff/h1GoodHit_its_tpc_trd"), track.pt()); + } } - } - if (isItsPassed && isTpcPassed && track.hasTOF() && track.hasTRD()) { - debugHistos.fill(HIST("tracks/trackingEff/h1_its_tpc_trd_tof"), track.pt()); - if (isGoodHit) { - debugHistos.fill(HIST("tracks/trackingEff/h1GoodHit_its_tpc_trd_tof"), track.pt()); + if (isItsPassed && isTpcPassed && track.hasTOF() && track.hasTRD()) { + debugHistos.fill(HIST("tracks/trackingEff/h1_its_tpc_trd_tof"), track.pt()); + if (isGoodHit) { + debugHistos.fill(HIST("tracks/trackingEff/h1GoodHit_its_tpc_trd_tof"), track.pt()); + } } - } - } else if ((track.sign() < 0) && enableTrackingEff) { - if (isItsPassed) { - debugHistos.fill(HIST("tracks/trackingEff/h1anti_its"), track.pt()); - if (isGoodHit) { - debugHistos.fill(HIST("tracks/trackingEff/h1antiGoodHit_its"), track.pt()); + } else if ((track.sign() < 0) && enableTrackingEff) { + if (isItsPassed) { + debugHistos.fill(HIST("tracks/trackingEff/h1anti_its"), track.pt()); + if (isGoodHit) { + debugHistos.fill(HIST("tracks/trackingEff/h1antiGoodHit_its"), track.pt()); + } } - } - if (isTpcPassed) { - debugHistos.fill(HIST("tracks/trackingEff/h1anti_tpc"), track.pt()); - if (isGoodHit) { - debugHistos.fill(HIST("tracks/trackingEff/h1antiGoodHit_tpc"), track.pt()); + if (isTpcPassed) { + debugHistos.fill(HIST("tracks/trackingEff/h1anti_tpc"), track.pt()); + if (isGoodHit) { + debugHistos.fill(HIST("tracks/trackingEff/h1antiGoodHit_tpc"), track.pt()); + } } - } - if (isItsPassed && isTpcPassed) { - debugHistos.fill(HIST("tracks/trackingEff/h1anti_its_tpc"), track.pt()); - if (isGoodHit) { - debugHistos.fill(HIST("tracks/trackingEff/h1antiGoodHit_its_tpc"), track.pt()); + if (isItsPassed && isTpcPassed) { + debugHistos.fill(HIST("tracks/trackingEff/h1anti_its_tpc"), track.pt()); + if (isGoodHit) { + debugHistos.fill(HIST("tracks/trackingEff/h1antiGoodHit_its_tpc"), track.pt()); + } } - } - if (isItsPassed && isTpcPassed && track.hasTOF()) { - debugHistos.fill(HIST("tracks/trackingEff/h1anti_its_tpc_tof"), track.pt()); - if (isGoodHit) { - debugHistos.fill(HIST("tracks/trackingEff/h1antiGoodHit_its_tpc_tof"), track.pt()); + if (isItsPassed && isTpcPassed && track.hasTOF()) { + debugHistos.fill(HIST("tracks/trackingEff/h1anti_its_tpc_tof"), track.pt()); + if (isGoodHit) { + debugHistos.fill(HIST("tracks/trackingEff/h1antiGoodHit_its_tpc_tof"), track.pt()); + } } - } - if (isItsPassed && isTpcPassed && track.hasTRD()) { - debugHistos.fill(HIST("tracks/trackingEff/h1anti_its_tpc_trd"), track.pt()); - if (isGoodHit) { - debugHistos.fill(HIST("tracks/trackingEff/h1antiGoodHit_its_tpc_trd"), track.pt()); + if (isItsPassed && isTpcPassed && track.hasTRD()) { + debugHistos.fill(HIST("tracks/trackingEff/h1anti_its_tpc_trd"), track.pt()); + if (isGoodHit) { + debugHistos.fill(HIST("tracks/trackingEff/h1antiGoodHit_its_tpc_trd"), track.pt()); + } } - } - if (isItsPassed && isTpcPassed && track.hasTOF() && track.hasTRD()) { - debugHistos.fill(HIST("tracks/trackingEff/h1anti_its_tpc_trd_tof"), track.pt()); - if (isGoodHit) { - debugHistos.fill(HIST("tracks/trackingEff/h1antiGoodHit_its_tpc_trd_tof"), track.pt()); + if (isItsPassed && isTpcPassed && track.hasTOF() && track.hasTRD()) { + debugHistos.fill(HIST("tracks/trackingEff/h1anti_its_tpc_trd_tof"), track.pt()); + if (isGoodHit) { + debugHistos.fill(HIST("tracks/trackingEff/h1antiGoodHit_its_tpc_trd_tof"), track.pt()); + } } } } - switch (pdgCode) { case PDGProton: - if (enablePr && prRapCut) { + if (enablePr && prRapCut && passDCAxyzCut) { histos.fill(HIST("tracks/proton/h1ProtonSpectraTrue"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/proton/dca/after/hDCAxyVsPtProtonTrue"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/proton/dca/after/hDCAzVsPtProtonTrue"), track.pt(), track.dcaZ()); } - if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCPr) { + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCvar.nsigmaTPCPr) { histos.fill(HIST("tracks/proton/h1ProtonSpectraTrueWPID"), track.pt()); } if (isPhysPrim) { histos.fill(HIST("tracks/proton/h1ProtonSpectraTruePrim"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/proton/dca/after/hDCAxyVsPtProtonTruePrim"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/proton/dca/after/hDCAzVsPtProtonTruePrim"), track.pt(), track.dcaZ()); } @@ -3618,7 +4955,7 @@ struct LFNucleiBATask { } } - if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCPr) { + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCvar.nsigmaTPCPr) { if (enableTrackingEff) { if (isItsPassed) { debugHistos.fill(HIST("tracks/proton/trackingEffPID/h1ProtonSpectraPIDTruePrim_its"), track.pt()); @@ -3666,13 +5003,13 @@ struct LFNucleiBATask { } if (!isPhysPrim && !isProdByGen) { histos.fill(HIST("tracks/proton/h1ProtonSpectraTrueTransport"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/proton/dca/after/hDCAxyVsPtProtonTrueTransport"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/proton/dca/after/hDCAzVsPtProtonTrueTransport"), track.pt(), track.dcaZ()); } if (isWeakDecay) { histos.fill(HIST("tracks/proton/h1ProtonSpectraTrueSec"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/proton/dca/after/hDCAxyVsPtProtonTrueSec"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/proton/dca/after/hDCAzVsPtProtonTrueSec"), track.pt(), track.dcaZ()); } @@ -3681,18 +5018,18 @@ struct LFNucleiBATask { } break; case -PDGProton: - if (enablePr && prRapCut) { + if (enablePr && prRapCut && passDCAxyzCut) { histos.fill(HIST("tracks/proton/h1antiProtonSpectraTrue"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/proton/dca/after/hDCAxyVsPtantiProtonTrue"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/proton/dca/after/hDCAzVsPtantiProtonTrue"), track.pt(), track.dcaZ()); } - if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCPr) { + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCvar.nsigmaTPCPr) { histos.fill(HIST("tracks/proton/h1antiProtonSpectraTrueWPID"), track.pt()); } if (isPhysPrim) { histos.fill(HIST("tracks/proton/h1antiProtonSpectraTruePrim"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/proton/dca/after/hDCAxyVsPtantiProtonTruePrim"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/proton/dca/after/hDCAzVsPtantiProtonTruePrim"), track.pt(), track.dcaZ()); } @@ -3741,7 +5078,7 @@ struct LFNucleiBATask { } } - if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCPr) { + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCvar.nsigmaTPCPr) { if (enableTrackingEff) { if (isItsPassed) { debugHistos.fill(HIST("tracks/proton/trackingEffPID/h1antiProtonSpectraPIDTruePrim_its"), track.pt()); @@ -3790,13 +5127,13 @@ struct LFNucleiBATask { if (!isPhysPrim && !isProdByGen) { histos.fill(HIST("tracks/proton/h1antiProtonSpectraTrueTransport"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/proton/dca/after/hDCAxyVsPtantiProtonTrueTransport"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/proton/dca/after/hDCAzVsPtantiProtonTrueTransport"), track.pt(), track.dcaZ()); } if (isWeakDecay) { histos.fill(HIST("tracks/proton/h1antiProtonSpectraTrueSec"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/proton/dca/after/hDCAxyVsPtantiProtonTrueSec"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/proton/dca/after/hDCAzVsPtantiProtonTrueSec"), track.pt(), track.dcaZ()); } @@ -3805,22 +5142,22 @@ struct LFNucleiBATask { } break; case PDGDeuteron: - if (enableDe && deRapCut) { + if (isDeuteron && passDCAzCutDe && passDCAxyCutDe) { histos.fill(HIST("tracks/deuteron/h1DeuteronSpectraTrue"), DPt); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/deuteron/dca/after/hDCAxyVsPtDeuteronTrue"), DPt, track.dcaXY()); histos.fill(HIST("tracks/deuteron/dca/after/hDCAzVsPtDeuteronTrue"), DPt, track.dcaZ()); } - if (std::abs(track.tpcNSigmaDe()) < nsigmaTPCDe) { + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPCvar.nsigmaTPCDe) { histos.fill(HIST("tracks/deuteron/h1DeuteronSpectraTrueWPID"), DPt); - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/deuteron/hPtDeuteronTOFTrue"), DPt); } } if (isPhysPrim) { histos.fill(HIST("tracks/deuteron/h2DeuteronVspTNSigmaTPCTruePrim"), DPt, track.tpcNSigmaDe()); histos.fill(HIST("tracks/deuteron/h1DeuteronSpectraTruePrim"), DPt); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/deuteron/dca/after/hDCAxyVsPtDeuteronTruePrim"), DPt, track.dcaXY()); histos.fill(HIST("tracks/deuteron/dca/after/hDCAzVsPtDeuteronTruePrim"), DPt, track.dcaZ()); } @@ -3869,13 +5206,13 @@ struct LFNucleiBATask { } } - if (std::abs(track.tpcNSigmaDe()) < nsigmaTPCDe) { + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPCvar.nsigmaTPCDe) { histos.fill(HIST("tracks/deuteron/h1DeuteronSpectraTrueWPIDPrim"), DPt); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/deuteron/dca/after/hDCAxyVsPtDeuteronTrueWPIDPrim"), DPt, track.dcaXY()); histos.fill(HIST("tracks/deuteron/dca/after/hDCAzVsPtDeuteronTrueWPIDPrim"), DPt, track.dcaZ()); } - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/deuteron/hPtDeuteronTOFTrueWPIDPrim"), DPt); } @@ -3926,13 +5263,13 @@ struct LFNucleiBATask { } if (!isPhysPrim && !isProdByGen) { histos.fill(HIST("tracks/deuteron/h1DeuteronSpectraTrueTransport"), DPt); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/deuteron/dca/after/hDCAxyVsPtDeuteronTrueTransport"), DPt, track.dcaXY()); histos.fill(HIST("tracks/deuteron/dca/after/hDCAzVsPtDeuteronTrueTransport"), DPt, track.dcaZ()); } if (isWeakDecay) { histos.fill(HIST("tracks/deuteron/h1DeuteronSpectraTrueSec"), DPt); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/deuteron/dca/after/hDCAxyVsPtDeuteronTrueSec"), DPt, track.dcaXY()); histos.fill(HIST("tracks/deuteron/dca/after/hDCAzVsPtDeuteronTrueSec"), DPt, track.dcaZ()); } @@ -3941,22 +5278,22 @@ struct LFNucleiBATask { } break; case -PDGDeuteron: - if (enableDe && deRapCut) { + if (isDeuteron && passDCAzCutAntiDe && passDCAxyCutAntiDe) { histos.fill(HIST("tracks/deuteron/h1antiDeuteronSpectraTrue"), antiDPt); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/deuteron/dca/after/hDCAxyVsPtantiDeuteronTrue"), antiDPt, track.dcaXY()); histos.fill(HIST("tracks/deuteron/dca/after/hDCAzVsPtantiDeuteronTrue"), antiDPt, track.dcaZ()); } - if (std::abs(track.tpcNSigmaDe()) < nsigmaTPCDe) { + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPCvar.nsigmaTPCDe) { histos.fill(HIST("tracks/deuteron/h1antiDeuteronSpectraTrueWPID"), antiDPt); - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/deuteron/hPtantiDeuteronTOFTrue"), antiDPt); } } if (isPhysPrim) { histos.fill(HIST("tracks/deuteron/h2antiDeuteronVspTNSigmaTPCTruePrim"), antiDPt, track.tpcNSigmaDe()); histos.fill(HIST("tracks/deuteron/h1antiDeuteronSpectraTruePrim"), antiDPt); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/deuteron/dca/after/hDCAxyVsPtantiDeuteronTruePrim"), antiDPt, track.dcaXY()); histos.fill(HIST("tracks/deuteron/dca/after/hDCAzVsPtantiDeuteronTruePrim"), antiDPt, track.dcaZ()); } @@ -4005,13 +5342,13 @@ struct LFNucleiBATask { } } - if (std::abs(track.tpcNSigmaDe()) < nsigmaTPCDe) { + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPCvar.nsigmaTPCDe) { histos.fill(HIST("tracks/deuteron/h1antiDeuteronSpectraTrueWPIDPrim"), antiDPt); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/deuteron/dca/after/hDCAxyVsPtantiDeuteronTrueWPIDPrim"), antiDPt, track.dcaXY()); histos.fill(HIST("tracks/deuteron/dca/after/hDCAzVsPtantiDeuteronTrueWPIDPrim"), antiDPt, track.dcaZ()); } - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/deuteron/hPtantiDeuteronTOFTrueWPIDPrim"), antiDPt); } @@ -4062,13 +5399,13 @@ struct LFNucleiBATask { } if (!isPhysPrim && !isProdByGen) { histos.fill(HIST("tracks/deuteron/h1antiDeuteronSpectraTrueTransport"), antiDPt); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/deuteron/dca/after/hDCAxyVsPtantiDeuteronTrueTransport"), antiDPt, track.dcaXY()); histos.fill(HIST("tracks/deuteron/dca/after/hDCAzVsPtantiDeuteronTrueTransport"), antiDPt, track.dcaZ()); } if (isWeakDecay) { histos.fill(HIST("tracks/deuteron/h1antiDeuteronSpectraTrueSec"), antiDPt); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/deuteron/dca/after/hDCAxyVsPtantiDeuteronTrueSec"), antiDPt, track.dcaXY()); histos.fill(HIST("tracks/deuteron/dca/after/hDCAzVsPtantiDeuteronTrueSec"), antiDPt, track.dcaZ()); } @@ -4077,28 +5414,28 @@ struct LFNucleiBATask { } break; case PDGTriton: - if (enableTr && trRapCut) { + if (enableTr && trRapCut && passDCAxyzCut) { histos.fill(HIST("tracks/triton/h1TritonSpectraTrue"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/triton/dca/after/hDCAxyVsPtTritonTrue"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/triton/dca/after/hDCAzVsPtTritonTrue"), track.pt(), track.dcaZ()); } if (isPhysPrim) { histos.fill(HIST("tracks/triton/h1TritonSpectraTruePrim"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/triton/dca/after/hDCAxyVsPtTritonTruePrim"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/triton/dca/after/hDCAzVsPtTritonTruePrim"), track.pt(), track.dcaZ()); } } if (!isPhysPrim && !isProdByGen) { histos.fill(HIST("tracks/triton/h1TritonSpectraTrueTransport"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/triton/dca/after/hDCAxyVsPtTritonTrueTransport"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/triton/dca/after/hDCAzVsPtTritonTrueTransport"), track.pt(), track.dcaZ()); } if (isWeakDecay) { histos.fill(HIST("tracks/triton/h1TritonSpectraTrueSec"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/triton/dca/after/hDCAxyVsPtTritonTrueSec"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/triton/dca/after/hDCAzVsPtTritonTrueSec"), track.pt(), track.dcaZ()); } @@ -4107,28 +5444,28 @@ struct LFNucleiBATask { } break; case -PDGTriton: - if (enableTr && trRapCut) { + if (enableTr && trRapCut && passDCAxyzCut) { histos.fill(HIST("tracks/triton/h1antiTritonSpectraTrue"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/triton/dca/after/hDCAxyVsPtantiTritonTrue"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/triton/dca/after/hDCAzVsPtantiTritonTrue"), track.pt(), track.dcaZ()); } if (isPhysPrim) { histos.fill(HIST("tracks/triton/h1antiTritonSpectraTruePrim"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/triton/dca/after/hDCAxyVsPtantiTritonTruePrim"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/triton/dca/after/hDCAzVsPtantiTritonTruePrim"), track.pt(), track.dcaZ()); } } if (!isPhysPrim && !isProdByGen) { histos.fill(HIST("tracks/triton/h1antiTritonSpectraTrueTransport"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/triton/dca/after/hDCAxyVsPtantiTritonTrueTransport"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/triton/dca/after/hDCAzVsPtantiTritonTrueTransport"), track.pt(), track.dcaZ()); } if (isWeakDecay) { histos.fill(HIST("tracks/triton/h1antiTritonSpectraTrueSec"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/triton/dca/after/hDCAxyVsPtantiTritonTrueSec"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/triton/dca/after/hDCAzVsPtantiTritonTrueSec"), track.pt(), track.dcaZ()); } @@ -4137,25 +5474,25 @@ struct LFNucleiBATask { } break; case PDGHelium: - if (enableHe && heRapCut) { + if (isHelium && passDCAzCutHe && passDCAxyCutHe) { histos.fill(HIST("tracks/helium/h1HeliumSpectraTrue"), hePt); histos.fill(HIST("tracks/helium/h1HeliumSpectraTrue_Z2"), 2 * hePt); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsPtHeliumTrue"), hePt, track.dcaXY()); histos.fill(HIST("tracks/helium/dca/after/hDCAzVsPtHeliumTrue"), hePt, track.dcaZ()); - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAxyVsPtHeliumTrue"), hePt, track.dcaXY()); histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAzVsPtHeliumTrue"), hePt, track.dcaZ()); } } - if (std::abs(track.tpcNSigmaHe()) < nsigmaTPCHe) { + if (std::abs(track.tpcNSigmaHe()) < nsigmaTPCvar.nsigmaTPCHe) { histos.fill(HIST("tracks/helium/h1HeliumSpectraTrueWPID"), hePt); histos.fill(HIST("tracks/helium/h1HeliumSpectraTrueWPID_Z2"), 2 * hePt); if (enablePtSpectra) { histos.fill(HIST("tracks/eff/helium/hPtHeTrue"), 2 * hePt); - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/eff/helium/hPtHeTOFTrue"), 2 * hePt); } } @@ -4164,16 +5501,16 @@ struct LFNucleiBATask { histos.fill(HIST("tracks/helium/h1HeliumSpectraTruePrim"), hePt); histos.fill(HIST("tracks/helium/h1HeliumSpectraTruePrim_Z2"), 2 * hePt); - if (std::abs(track.tpcNSigmaHe()) < nsigmaTPCHe) { - if (track.hasTOF() && doTOFplots) { + if (std::abs(track.tpcNSigmaHe()) < nsigmaTPCvar.nsigmaTPCHe) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/TOF/h1HeliumSpectraTruePrim_Z2"), 2 * hePt); } } - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsPtHeliumTruePrim"), hePt, track.dcaXY()); histos.fill(HIST("tracks/helium/dca/after/hDCAzVsPtHeliumTruePrim"), hePt, track.dcaZ()); - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAxyVsPtHeliumTruePrim"), hePt, track.dcaXY()); histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAzVsPtHeliumTruePrim"), hePt, track.dcaZ()); } @@ -4184,10 +5521,10 @@ struct LFNucleiBATask { histos.fill(HIST("tracks/helium/h1HeliumSpectraTrueTransport"), hePt); histos.fill(HIST("tracks/helium/h1HeliumSpectraTrueTransport_Z2"), 2 * hePt); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsPtHeliumTrueTransport"), hePt, track.dcaXY()); histos.fill(HIST("tracks/helium/dca/after/hDCAzVsPtHeliumTrueTransport"), hePt, track.dcaZ()); - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAxyVsPtHeliumTrueTransport"), hePt, track.dcaXY()); histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAzVsPtHeliumTrueTransport"), hePt, track.dcaZ()); } @@ -4196,10 +5533,10 @@ struct LFNucleiBATask { histos.fill(HIST("tracks/helium/h1HeliumSpectraTrueSec"), hePt); histos.fill(HIST("tracks/helium/h1HeliumSpectraTrueSec_Z2"), 2 * hePt); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsPtHeliumTrueSec"), hePt, track.dcaXY()); histos.fill(HIST("tracks/helium/dca/after/hDCAzVsPtHeliumTrueSec"), hePt, track.dcaZ()); - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAxyVsPtHeliumTrueSec"), hePt, track.dcaXY()); histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAzVsPtHeliumTrueSec"), hePt, track.dcaZ()); } @@ -4209,24 +5546,24 @@ struct LFNucleiBATask { } break; case -PDGHelium: - if (enableHe && heRapCut) { + if (isHelium && passDCAzCutAntiHe && passDCAxyCutAntiHe) { histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTrue"), antihePt); histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTrue_Z2"), 2 * antihePt); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsPtantiHeliumTrue"), antihePt, track.dcaXY()); histos.fill(HIST("tracks/helium/dca/after/hDCAzVsPtantiHeliumTrue"), antihePt, track.dcaZ()); - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAxyVsPtantiHeliumTrue"), antihePt, track.dcaXY()); histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAzVsPtantiHeliumTrue"), antihePt, track.dcaZ()); } } - if (std::abs(track.tpcNSigmaHe()) < nsigmaTPCHe) { + if (std::abs(track.tpcNSigmaHe()) < nsigmaTPCvar.nsigmaTPCHe) { histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTrueWPID"), antihePt); histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTrueWPID_Z2"), 2 * antihePt); if (enablePtSpectra) { histos.fill(HIST("tracks/eff/helium/hPtantiHeTrue"), 2 * antihePt); - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/eff/helium/hPtantiHeTOFTrue"), 2 * antihePt); } } @@ -4235,16 +5572,16 @@ struct LFNucleiBATask { histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTruePrim"), antihePt); histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTruePrim_Z2"), 2 * antihePt); - if (std::abs(track.tpcNSigmaHe()) < nsigmaTPCHe) { - if (track.hasTOF() && doTOFplots) { + if (std::abs(track.tpcNSigmaHe()) < nsigmaTPCvar.nsigmaTPCHe) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/TOF/h1antiHeliumSpectraTruePrim_Z2"), 2 * antihePt); } } - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsPtantiHeliumTruePrim"), antihePt, track.dcaXY()); histos.fill(HIST("tracks/helium/dca/after/hDCAzVsPtantiHeliumTruePrim"), antihePt, track.dcaZ()); - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAxyVsPtantiHeliumTruePrim"), antihePt, track.dcaXY()); histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAzVsPtantiHeliumTruePrim"), antihePt, track.dcaZ()); } @@ -4254,10 +5591,10 @@ struct LFNucleiBATask { histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTrueTransport"), antihePt); histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTrueTransport_Z2"), 2 * antihePt); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsPtantiHeliumTrueTransport"), antihePt, track.dcaXY()); histos.fill(HIST("tracks/helium/dca/after/hDCAzVsPtantiHeliumTrueTransport"), antihePt, track.dcaZ()); - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAxyVsPtantiHeliumTrueTransport"), antihePt, track.dcaXY()); histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAzVsPtantiHeliumTrueTransport"), antihePt, track.dcaZ()); } @@ -4267,10 +5604,10 @@ struct LFNucleiBATask { histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTrueSec"), antihePt); histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTrueSec_Z2"), 2 * antihePt); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsPtantiHeliumTrueSec"), antihePt, track.dcaXY()); histos.fill(HIST("tracks/helium/dca/after/hDCAzVsPtantiHeliumTrueSec"), antihePt, track.dcaZ()); - if (track.hasTOF() && doTOFplots) { + if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAxyVsPtantiHeliumTrueSec"), antihePt, track.dcaXY()); histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAzVsPtantiHeliumTrueSec"), antihePt, track.dcaZ()); } @@ -4280,29 +5617,29 @@ struct LFNucleiBATask { } break; case PDGAlpha: - if (enableAl && alRapCut) { + if (enableAl && alRapCut && passDCAxyzCut) { histos.fill(HIST("tracks/alpha/h1AlphaSpectraTrue"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/alpha/dca/after/hDCAxyVsPtAlphaTrue"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/alpha/dca/after/hDCAzVsPtAlphaTrue"), track.pt(), track.dcaZ()); } if (isPhysPrim) { histos.fill(HIST("tracks/alpha/h1AlphaSpectraTruePrim"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/alpha/dca/after/hDCAxyVsPtAlphaTruePrim"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/alpha/dca/after/hDCAzVsPtAlphaTruePrim"), track.pt(), track.dcaZ()); } } if (!isPhysPrim && !isProdByGen) { histos.fill(HIST("tracks/alpha/h1AlphaSpectraTrueTransport"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/alpha/dca/after/hDCAxyVsPtAlphaTrueTransport"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/alpha/dca/after/hDCAzVsPtAlphaTrueTransport"), track.pt(), track.dcaZ()); } if (isWeakDecay) { histos.fill(HIST("tracks/alpha/h1AlphaSpectraTrueSec"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/alpha/dca/after/hDCAxyVsPtAlphaTrueSec"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/alpha/dca/after/hDCAzVsPtAlphaTrueSec"), track.pt(), track.dcaZ()); } @@ -4311,28 +5648,28 @@ struct LFNucleiBATask { } break; case -PDGAlpha: - if (enableAl && alRapCut) { + if (enableAl && alRapCut && passDCAxyzCut) { histos.fill(HIST("tracks/alpha/h1antiAlphaSpectraTrue"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/alpha/dca/after/hDCAxyVsPtantiAlphaTrue"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/alpha/dca/after/hDCAzVsPtantiAlphaTrue"), track.pt(), track.dcaZ()); } if (isPhysPrim) { histos.fill(HIST("tracks/alpha/h1antiAlphaSpectraTruePrim"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/alpha/dca/after/hDCAxyVsPtantiAlphaTruePrim"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/alpha/dca/after/hDCAzVsPtantiAlphaTruePrim"), track.pt(), track.dcaZ()); } } if (!isPhysPrim && !isProdByGen) { histos.fill(HIST("tracks/alpha/h1antiAlphaSpectraTrueTransport"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/alpha/dca/after/hDCAxyVsPtantiAlphaTrueTransport"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/alpha/dca/after/hDCAzVsPtantiAlphaTrueTransport"), track.pt(), track.dcaZ()); } if (isWeakDecay) { histos.fill(HIST("tracks/alpha/h1antiAlphaSpectraTrueSec"), track.pt()); - if (makeDCAAfterCutPlots) { + if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/alpha/dca/after/hDCAxyVsPtantiAlphaTrueSec"), track.pt(), track.dcaXY()); histos.fill(HIST("tracks/alpha/dca/after/hDCAzVsPtantiAlphaTrueSec"), track.pt(), track.dcaZ()); } @@ -4379,37 +5716,41 @@ struct LFNucleiBATask { // Process function that runs on the original AO2D void processData(EventCandidates::iterator const& event, - TrackCandidates const& tracks) + TrackCandidates const& tracks, + o2::aod::BCsWithTimestamps const&) { fillHistograms(event, tracks, true /*dummy*/); - } // CLOSING PROCESS DATA + } PROCESS_SWITCH(LFNucleiBATask, processData, "process data", true); // Process function that runs on the original AO2D void processDataLfPid(EventCandidates::iterator const& event, - TrackCandidatesLfPid const& tracks) + TrackCandidatesLfPid const& tracks, + o2::aod::BCsWithTimestamps const&) { fillHistograms(event, tracks, true /*dummy*/); - } // CLOSING PROCESS DATA + } PROCESS_SWITCH(LFNucleiBATask, processDataLfPid, "process data with LF PID", false); // Process function that runs on the filtered data void processDataFiltered(o2::aod::LfNuclEvents::iterator const& event, - o2::aod::LfCandNucleusFull const& tracks) + o2::aod::LfCandNucleusFull const& tracks, + o2::aod::BCsWithTimestamps const&) { // Runs on data filtered on the fly with LF Tree creator nuclei task // Takes as input full AO2Ds fillHistograms(event, tracks, true /*dummy*/); - } // CLOSING PROCESS DATA ON FILTERED DATA + } PROCESS_SWITCH(LFNucleiBATask, processDataFiltered, "process data on the filtered data", false); void processDataLight(o2::aod::LfNuclEvents::iterator const& event, - o2::aod::LfCandNucleusDummy const& tracks) + o2::aod::LfCandNucleusDummy const& tracks, + o2::aod::BCsWithTimestamps const&) { // Runs on derived tables produced with LF Tree creator nuclei task // Takes as input derived trees fillHistograms(event, tracks, true /*dummy*/); - } // CLOSING PROCESS DATA ON FILTERED DATA + } PROCESS_SWITCH(LFNucleiBATask, processDataLight, "process data on the derived trees", false); ///////////// @@ -4417,18 +5758,20 @@ struct LFNucleiBATask { ///////////// // Process function that runs on the original AO2D (for the MC) - void processMCReco(EventCandidates::iterator const& event, + void processMCReco(EventCandidatesMC::iterator const& event, soa::Join const& tracks, - aod::McParticles const& mcParticles) + aod::McParticles const& mcParticles, + o2::aod::BCsWithTimestamps const&) { fillHistograms(event, tracks, mcParticles); } // CLOSING PROCESS MC RECO PROCESS_SWITCH(LFNucleiBATask, processMCReco, "process mc reco", false); // Process function that runs on the original AO2D (for the MC) with the LfPIDcalibration - void processMCRecoLfPid(EventCandidates::iterator const& event, + void processMCRecoLfPid(EventCandidatesMC::iterator const& event, soa::Join const& tracks, - aod::McParticles const& mcParticles) + aod::McParticles const& mcParticles, + o2::aod::BCsWithTimestamps const&) { fillHistograms(event, tracks, mcParticles); } // CLOSING PROCESS MC RECO @@ -4442,21 +5785,16 @@ struct LFNucleiBATask { aod::McParticles const& mcParticles, aod::McCollisions const&) { - /* - for (const auto& track : tracks) { - if (!track.has_collision()) - continue; - // const auto& mcParticle = track.mcParticle(); - } - */ - for (const auto& collision : collisions) { if (!collision.has_mcCollision()) { continue; } - // const auto& mcParticle = track.mcParticle(); const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, collision.mcCollision().globalIndex(), cache); + for (const auto& mcParticle : particlesInCollision) { + if (mcParticle.y() > kinemOptions.yHighCut || mcParticle.y() < kinemOptions.yLowCut) { + continue; + } spectraGen.fill(HIST("LfEv/pT_nocut"), mcParticle.pt()); if (mcParticle.pdgCode() == PDGHelium) { spectraGen.fill(HIST("LfEv/helium/pT_nocut_He"), mcParticle.pt()); @@ -4467,6 +5805,10 @@ struct LFNucleiBATask { } if (collision.selection_bit(aod::evsel::kIsTriggerTVX)) { for (const auto& mcParticle : particlesInCollision) { + if (mcParticle.y() > kinemOptions.yHighCut || mcParticle.y() < kinemOptions.yLowCut) { + continue; + } + spectraGen.fill(HIST("LfEv/pT_TVXtrigger"), mcParticle.pt()); if (mcParticle.pdgCode() == PDGHelium) { spectraGen.fill(HIST("LfEv/helium/pT_TVXtrigger_He"), mcParticle.pt()); @@ -4478,6 +5820,10 @@ struct LFNucleiBATask { } if (collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { for (const auto& mcParticle : particlesInCollision) { + if (mcParticle.y() > kinemOptions.yHighCut || mcParticle.y() < kinemOptions.yLowCut) { + continue; + } + spectraGen.fill(HIST("LfEv/pT_TFrameBorder"), mcParticle.pt()); if (mcParticle.pdgCode() == PDGHelium) { spectraGen.fill(HIST("LfEv/helium/pT_TFrameBorder_He"), mcParticle.pt()); @@ -4489,6 +5835,10 @@ struct LFNucleiBATask { } if (collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { for (const auto& mcParticle : particlesInCollision) { + if (mcParticle.y() > kinemOptions.yHighCut || mcParticle.y() < kinemOptions.yLowCut) { + continue; + } + spectraGen.fill(HIST("LfEv/pT_ITSROFBorder"), mcParticle.pt()); if (mcParticle.pdgCode() == PDGHelium) { spectraGen.fill(HIST("LfEv/helium/pT_ITSROFBorder_He"), mcParticle.pt()); @@ -4498,8 +5848,33 @@ struct LFNucleiBATask { } } } + if ((collision.selection_bit(aod::evsel::kIsTriggerTVX)) && (collision.selection_bit(aod::evsel::kNoTimeFrameBorder))) { + for (const auto& mcParticle : particlesInCollision) { + if (mcParticle.y() > kinemOptions.yHighCut || mcParticle.y() < kinemOptions.yLowCut) { + continue; + } + + bool isPhysPrim = mcParticle.isPhysicalPrimary(); + + spectraGen.fill(HIST("LfEv/pT_MCsel8"), mcParticle.pt()); + if (mcParticle.pdgCode() == PDGHelium) { + spectraGen.fill(HIST("LfEv/helium/pT_MCsel8_He"), mcParticle.pt()); + if (isPhysPrim) + spectraGen.fill(HIST("LfEv/helium/pT_MCsel8_HePrim"), mcParticle.pt()); + } + if (mcParticle.pdgCode() == -PDGHelium) { + spectraGen.fill(HIST("LfEv/helium/pT_MCsel8_antiHe"), mcParticle.pt()); + if (isPhysPrim) + spectraGen.fill(HIST("LfEv/helium/pT_MCsel8_antiHePrim"), mcParticle.pt()); + } + } + } if (collision.sel8()) { for (const auto& mcParticle : particlesInCollision) { + if (mcParticle.y() > kinemOptions.yHighCut || mcParticle.y() < kinemOptions.yLowCut) { + continue; + } + spectraGen.fill(HIST("LfEv/pT_sel8"), mcParticle.pt()); if (mcParticle.pdgCode() == PDGHelium) { spectraGen.fill(HIST("LfEv/helium/pT_sel8_He"), mcParticle.pt()); @@ -4517,14 +5892,16 @@ struct LFNucleiBATask { // Process function that runs on the filtered AO2D (for the MC) void processMCRecoFiltered(o2::aod::LfNuclEvents::iterator const& event, - soa::Join const& tracks) + soa::Join const& tracks, + o2::aod::BCsWithTimestamps const&) { fillHistograms(event, tracks, true /*dummy*/); } // CLOSING PROCESS MC RECO ON FILTERED DATA PROCESS_SWITCH(LFNucleiBATask, processMCRecoFiltered, "process mc reco on the filtered data", false); void processMCRecoFilteredLight(o2::aod::LfNuclEvents::iterator const& event, - soa::Join const& tracks) + soa::Join const& tracks, + o2::aod::BCsWithTimestamps const&) { fillHistograms(event, tracks, true /*dummy*/); } // CLOSING PROCESS MC RECO ON FILTERED DATA @@ -4540,7 +5917,7 @@ struct LFNucleiBATask { { spectraGen.fill(HIST("histGenVetxZ"), mcCollision.posZ()); for (auto& mcParticleGen : mcParticles) { - if (mcParticleGen.y() > yHighCut || mcParticleGen.y() < yLowCut) { + if (mcParticleGen.y() > kinemOptions.yHighCut || mcParticleGen.y() < kinemOptions.yLowCut) { continue; } @@ -4548,10 +5925,6 @@ struct LFNucleiBATask { bool isProdByGen = mcParticleGen.producedByGenerator(); bool isWeakDecay = mcParticleGen.getProcess() == 4; - // if (mcParticleGen.pdgCode() == PDGHelium) { - // LOG(info) << "I AM POSITIVE HELIUM, get process output is: " << mcParticleGen.getProcess(); - // } - if (mcParticleGen.pdgCode() == PDGPion) { spectraGen.fill(HIST("pion/histGenPtPion"), mcParticleGen.pt()); if (isPhysPrim) @@ -4774,6 +6147,63 @@ struct LFNucleiBATask { } } // Close processMCGen PROCESS_SWITCH(LFNucleiBATask, processMCGen, "process MC Generated", true); + void processEvSgLossMC(aod::McCollision const& mcCollision, + aod::McParticles const& mcParticles, + const soa::SmallGroups& recoColls) + { + if (std::abs(mcCollision.posZ()) < cfgHighCutVertex) { + evLossHistos.fill(HIST("evLoss/hEvent"), 0.5); + } + + bool isSel8Event = false; + bool isTvxEvent = false; + + // Check if there is an event reconstructed for a generated event + for (const auto& recoColl : recoColls) { + if (std::abs(recoColl.posZ()) > cfgHighCutVertex) + continue; + if (recoColl.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + isTvxEvent = true; + } + if (recoColl.sel8()) { + isSel8Event = true; + } + } + + if (isTvxEvent) { + evLossHistos.fill(HIST("evLoss/hEvent"), 1.5); + } + if (isSel8Event) { + evLossHistos.fill(HIST("evLoss/hEvent"), 2.5); + } + + // Loop over all the Generated level particles + for (const auto& mcPart : mcParticles) { + if (!mcPart.isPhysicalPrimary()) + continue; + if (std::abs(mcPart.y()) >= 0.5) + continue; + if (mcPart.pdgCode() == PDGDeuteron) { + evLossHistos.fill(HIST("evLoss/pt/hDeuteronGen"), mcPart.pt()); + if (isTvxEvent) { + evLossHistos.fill(HIST("evLoss/pt/hDeuteronTriggeredTVX"), mcPart.pt()); + } + if (isSel8Event) { + evLossHistos.fill(HIST("evLoss/pt/hDeuteronTriggeredSel8"), mcPart.pt()); + } + } + if (mcPart.pdgCode() == -PDGDeuteron) { + evLossHistos.fill(HIST("evLoss/pt/hAntiDeuteronGen"), mcPart.pt()); + if (isTvxEvent) { + evLossHistos.fill(HIST("evLoss/pt/hAntiDeuteronTriggeredTVX"), mcPart.pt()); + } + if (isSel8Event) { + evLossHistos.fill(HIST("evLoss/pt/hAntiDeuteronTriggeredSel8"), mcPart.pt()); + } + } + } // MC particles + } + PROCESS_SWITCH(LFNucleiBATask, processEvSgLossMC, "process MC Sig Event", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Nuspex/NucleiEfficiencyTask.cxx b/PWGLF/Tasks/Nuspex/NucleiEfficiencyTask.cxx new file mode 100644 index 00000000000..4ca2bd51c6f --- /dev/null +++ b/PWGLF/Tasks/Nuspex/NucleiEfficiencyTask.cxx @@ -0,0 +1,575 @@ +// 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. +// +// Authors: Rafael Manhart, +// Date: 06.05.2024 + +#include +#include +#include +#include +#include +#include +#include + +#include "ReconstructionDataFormats/Track.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Framework/HistogramRegistry.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "TPDGCode.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/Core/TrackSelection.h" +#include "Framework/StaticFor.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "PWGLF/DataModel/spectraTOF.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "PWGLF/Utils/inelGt.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "Common/Core/RecoDecay.h" + +using namespace o2; +using namespace o2::track; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct NucleiEfficiencyTask { + + HistogramRegistry MC_gen_reg{"MC_particles_gen", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry MC_recon_reg{"MC_particles_reco", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + OutputObj histPDG_gen{TH1F("PDG_gen", "PDG;PDG code", 18, 0.0, 18)}; + OutputObj histPDG_gen_reco{TH1F("PDG_gen_reco", "PDG;PDG code", 18, 0.0, 18)}; + OutputObj histPDG_reco{TH1F("PDG_reco", "PDG;PDG code", 18, 0.0, 18)}; + + void init(o2::framework::InitContext&) + { + + std::vector ptBinning = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4., 5., 6., 8., 10., 12., 14.}; + std::vector etaBinning = {-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}; + std::vector PDGBinning = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0}; + + AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec pAxis = {ptBinning, "#it{p} (GeV/#it{c})"}; + AxisSpec centralityAxis = {100, 0.0, 105.0, "VT0C (%)"}; + AxisSpec etaAxis = {etaBinning, "#eta"}; + AxisSpec ImPaAxis = {100, 0.0, 105.0, "Impact parameter"}; + AxisSpec PDGBINNING = {PDGBinning, "PDG code"}; + + // *********************** Generated ********************** + MC_gen_reg.add("histGenVtxMC", "MC generated vertex z position", HistType::kTH1F, {{400, -40., +40., "z position (cm)"}}); + MC_gen_reg.add("histCentrality", "Impact parameter", HistType::kTH1F, {centralityAxis}); + MC_gen_reg.add("hist_gen_p", "generated p distribution", HistType::kTH2F, {pAxis, PDGBINNING}); + MC_gen_reg.add("hist_gen_pT", "generated p_{T} distribution", HistType::kTH2F, {ptAxis, PDGBINNING}); + MC_gen_reg.add("histPhi", "#phi", HistType::kTH2F, {{100, 0., 2. * TMath::Pi()}, PDGBINNING}); + MC_gen_reg.add("histEta", "#eta", HistType::kTH2F, {{102, -2.01, 2.01}, PDGBINNING}); + MC_gen_reg.add("histRapid", "#gamma", HistType::kTH2F, {{1000, -5.0, 5.0}, PDGBINNING}); + + // *********************** Generated reco ********************** + + MC_gen_reg.add("histGenVtxMC_reco", "MC generated (reco) vertex z position", HistType::kTH1F, {{400, -40., +40., "z position (cm)"}}); + MC_gen_reg.add("histCentrality_reco", "Centrality", HistType::kTH1F, {centralityAxis}); + MC_gen_reg.add("histEta_reco", "generated (reco) #eta", HistType::kTH2F, {{102, -2.01, 2.01}, PDGBINNING}); + MC_gen_reg.add("hist_gen_reco_p", "generated (reco) p distribution", HistType::kTH2F, {pAxis, PDGBINNING}); + MC_gen_reg.add("hist_gen_reco_pT", "generated (reco) p_{T} distribution", HistType::kTH2F, {ptAxis, PDGBINNING}); + + // ********************** Reconstructed ********************* + MC_recon_reg.add("histRecVtxMC", "MC reconstructed vertex z position", HistType::kTH1F, {{400, -40., +40., "z position (cm)"}}); + MC_recon_reg.add("histCentrality", "Centrality", HistType::kTH1F, {centralityAxis}); + MC_recon_reg.add("histPhi", "#phi", HistType::kTH2F, {{100, 0., 2. * TMath::Pi()}, PDGBINNING}); + MC_recon_reg.add("histEta", "#eta", HistType::kTH2F, {{102, -2.01, 2.01}, PDGBINNING}); + MC_recon_reg.add("hist_rec_ITS_vs_p", "ITS reconstructed p distribution", HistType::kTH2F, {pAxis, PDGBINNING}); + MC_recon_reg.add("hist_rec_ITS_TPC_vs_p", "ITS_TPC reconstructed p distribution", HistType::kTH2F, {pAxis, PDGBINNING}); + MC_recon_reg.add("hist_rec_ITS_TPC_TOF_vs_p", "ITS_TPC_TOF reconstructed p distribution", HistType::kTH2F, {pAxis, PDGBINNING}); + MC_recon_reg.add("hist_rec_ITS_vs_pT", "ITS reconstructed p_{T} distribution", HistType::kTH2F, {ptAxis, PDGBINNING}); + MC_recon_reg.add("hist_rec_ITS_TPC_vs_pT", "ITS_TPC reconstructed p_{T} distribution", HistType::kTH2F, {ptAxis, PDGBINNING}); + MC_recon_reg.add("hist_rec_ITS_TPC_TOF_vs_pT", "ITS_TPC_TOF reconstructed p_{T} distribution", HistType::kTH2F, {ptAxis, PDGBINNING}); + } + + // ************************ Configurables *********************** + Configurable event_selection_MC_sel8{"event_selection_MC_sel8", true, "Enable sel8 event selection in MC processing"}; + Configurable applyPvZCutGenColl{"applyPvZCutGenColl", true, "applyPvZCutGenColl"}; + Configurable yMin{"yMin", -0.5, "Minimum rapidity"}; + Configurable yMax{"yMax", 0.5, "Maximum rapidity"}; + Configurable p_min{"p_min", 0.1f, "min track.pt()"}; + Configurable p_max{"p_max", 1e+10f, "max track.pt()"}; + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutEta{"cfgCutEta", 0.8f, "Eta range for tracks"}; + Configurable minCentrality{"minCentrality", 0.0, "min Centrality used"}; + Configurable maxCentrality{"maxCentrality", 80.0, "max Centrality used"}; + Configurable enable_Centrality_cut{"enable_Centrality_cut", true, "enable Centrality cut"}; + + // Track filter + Configurable requireITS{"requireITS", true, "Additional cut on the ITS requirement"}; + Configurable requireTPC{"requireTPC", true, "Additional cut on the TPC requirement"}; + Configurable passedITSRefit{"passedITSRefit", true, "Additional cut on the ITS refit requirement"}; + Configurable passedTPCRefit{"passedTPCRefit", true, "Additional cut on the TPC refit requirement"}; + Configurable minReqClusterITS{"minReqClusterITS", 1.0, "min number of clusters required in ITS"}; + Configurable minReqClusterITSib{"minReqClusterITSib", 1.0, "min number of clusters required in ITS inner barrel"}; + Configurable minTPCnClsFound{"minTPCnClsFound", 0.0f, "min number of crossed rows TPC"}; + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 70.0f, "min number of crossed rows TPC"}; + Configurable minRatioCrossedRowsTPC{"minRatioCrossedRowsTPC", 0.8f, "min ratio of crossed rows over findable clusters TPC"}; + Configurable maxRatioCrossedRowsTPC{"maxRatioCrossedRowsTPC", 2.0f, "max ratio of crossed rows over findable clusters TPC"}; + Configurable maxChi2PerClusterTPC{"maxChi2PerClusterTPC", 4.f, "Cut on the maximum value of the chi2 per cluster in the TPC"}; + Configurable minChi2PerClusterTPC{"minChi2PerClusterTPC", 0.5f, "Cut on the minimum value of the chi2 per cluster in the TPC"}; + Configurable maxChi2PerClusterITS{"maxChi2PerClusterITS", 36.f, "Cut on the maximum value of the chi2 per cluster in the ITS"}; + Configurable maxDcaXYFactor{"maxDcaXYFactor", 0.5f, "DCA xy factor"}; + Configurable maxDCA_Z{"maxDCA_Z", 2.0f, "max DCA to vertex z"}; + Configurable lastRequiredTrdCluster{"lastRequiredTrdCluster", -1, "Last cluster to required in TRD for track selection. -1 does not require any TRD cluster"}; + Configurable requireGoldenChi2{"requireGoldenChi2", false, "Enable the requirement of GoldenChi2"}; + + Configurable calc_cent{"calc_cent", false, "Enable centrality processing"}; + + Configurable eta_cut_MC_gen{"eta_cut_MC_gen", true, "Enable eta cut for generated MC"}; + Configurable use_pT_cut{"use_pT_cut", true, "0: p is used | 1: pT is used"}; + + Configurable removeITSROFrameBorder{"removeITSROFrameBorder", false, "Remove TF border"}; + Configurable removeNoSameBunchPileup{"removeNoSameBunchPileup", false, "Remove TF border"}; + Configurable requireIsGoodZvtxFT0vsPV{"requireIsGoodZvtxFT0vsPV", false, "Remove TF border"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "Remove TF border"}; + Configurable removeNoTimeFrameBorder{"removeNoTimeFrameBorder", false, "Remove TF border"}; + + //*********************************************************************************** + + template + bool isInAcceptance(const particleType& particle) + { + if (particle.pt() < p_min || particle.pt() > p_max) + return false; + if (particle.eta() < -cfgCutEta || particle.eta() > cfgCutEta) + return false; + // if (particle.phi() < phiMin || particle.phi() > phiMax) return false; + if (particle.y() < yMin || particle.y() > yMax) + return false; + if (!particle.isPhysicalPrimary()) + return false; + + return true; + } + + //*********************************************************************************** + + template + bool isEventSelected(CollisionType const& collision) + { + if (removeITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) + return false; + if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) + return false; + if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + return false; + if (requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) + return false; + if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + return false; + + return true; + } + + //*********************************************************************************** + + template + bool isCollisionSelected(const CollType& collision) + { + if (event_selection_MC_sel8 && !collision.sel8()) + return false; + if (collision.posZ() < -cfgCutVertex || collision.posZ() > cfgCutVertex) + return false; + if (removeITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) + return false; + if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) + return false; + if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + return false; + if (requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) + return false; + if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + return false; + + return true; + } + + //*********************************************************************************** + + template + bool isTrackSelected(trackType& track) + { + if (!track.has_mcParticle()) + return false; + + const auto mcParticle = track.mcParticle(); + if (!isInAcceptance(mcParticle)) + return false; // pt eta phi y + if (!track.has_collision()) + return false; + + float TPCnumberClsFound = track.tpcNClsFound(); + float TPC_nCls_Crossed_Rows = track.tpcNClsCrossedRows(); + float RatioCrossedRowsOverFindableTPC = track.tpcCrossedRowsOverFindableCls(); + float Chi2perClusterTPC = track.tpcChi2NCl(); + float Chi2perClusterITS = track.itsChi2NCl(); + + bool insideDCAxy = (std::abs(track.dcaXY()) <= (maxDcaXYFactor.value * (0.0105f + 0.0350f / pow(track.pt(), 1.1f)))); + + if (!(insideDCAxy) || TMath::Abs(track.dcaZ()) > maxDCA_Z || TPCnumberClsFound < minTPCnClsFound || TPC_nCls_Crossed_Rows < minNCrossedRowsTPC || RatioCrossedRowsOverFindableTPC < minRatioCrossedRowsTPC || RatioCrossedRowsOverFindableTPC > maxRatioCrossedRowsTPC || Chi2perClusterTPC > maxChi2PerClusterTPC || Chi2perClusterTPC < minChi2PerClusterTPC || Chi2perClusterITS > maxChi2PerClusterITS || !(track.passedTPCRefit()) || !(track.passedITSRefit()) || (track.itsNClsInnerBarrel()) < minReqClusterITSib || (track.itsNCls()) < minReqClusterITS) + return false; + if ((requireITS && !(track.hasITS())) || (requireTPC && !(track.hasTPC()))) + return false; + if (requireGoldenChi2 && !(track.passedGoldenChi2())) + return false; + + return true; + } + + //*********************************************************************************** + using CollisionCandidates = o2::soa::Join; + using CollisionCandidatesMC = o2::soa::Join; + using TrackCandidates = o2::soa::Join; + using TrackCandidatesMC = o2::soa::Join; + + SliceCache cache; + Preslice perCollision = o2::aod::track::collisionId; + Preslice perCollisionMc = o2::aod::mcparticle::mcCollisionId; + PresliceUnsorted collPerCollMc = o2::aod::mccollisionlabel::mcCollisionId; + + void processMC(o2::aod::McCollisions const& mcCollisions, + // o2::soa::SmallGroups const& collisions, + CollisionCandidatesMC const& collisions, + TrackCandidatesMC const& tracks, + o2::aod::McParticles const& mcParticles) + { + /// loop over generated collisions + for (const auto& mcCollision : mcCollisions) { + + const auto groupedCollisions = collisions.sliceBy(collPerCollMc, mcCollision.globalIndex()); + const auto groupedMcParticles = mcParticles.sliceBy(perCollisionMc, mcCollision.globalIndex()); + + if (groupedCollisions.size() < 1) + continue; + float centrality = -1.; + + /// loop over reconstructed collisions + for (const auto& collision : groupedCollisions) { + if (!isCollisionSelected(collision)) + continue; + + centrality = collision.centFT0C(); + if (centrality < minCentrality || centrality > maxCentrality) + continue; + + MC_recon_reg.fill(HIST("histCentrality"), centrality); + MC_recon_reg.fill(HIST("histRecVtxMC"), collision.posZ()); + + const auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex()); + + // Track loop + for (const auto& track : groupedTracks) { + if (!isTrackSelected(track)) + continue; + + const auto& particle = track.mcParticle(); + // TLorentzVector lorentzVector_particle_MC{}; + + int pdgbin = -10; + switch (particle.pdgCode()) { + case +211: + histPDG_reco->AddBinContent(1); + pdgbin = 0; + break; + case -211: + histPDG_reco->AddBinContent(2); + pdgbin = 1; + break; + case +321: + histPDG_reco->AddBinContent(3); + pdgbin = 2; + break; + case -321: + histPDG_reco->AddBinContent(4); + pdgbin = 3; + break; + case +2212: + histPDG_reco->AddBinContent(5); + pdgbin = 4; + break; + case -2212: + histPDG_reco->AddBinContent(6); + pdgbin = 5; + break; + case +1000010020: + histPDG_reco->AddBinContent(7); + pdgbin = 6; + break; + case -1000010020: + histPDG_reco->AddBinContent(8); + pdgbin = 7; + break; + case +1000010030: + histPDG_reco->AddBinContent(9); + pdgbin = 8; + break; + case -1000010030: + histPDG_reco->AddBinContent(10); + pdgbin = 9; + break; + case +1000020030: + histPDG_reco->AddBinContent(11); + pdgbin = 10; + break; + case -1000020030: + histPDG_reco->AddBinContent(12); + pdgbin = 11; + break; + case +1000020040: + histPDG_reco->AddBinContent(13); + pdgbin = 12; + break; + case -1000020040: + histPDG_reco->AddBinContent(14); + pdgbin = 13; + break; + default: + pdgbin = -10; + continue; + break; + } + + MC_recon_reg.fill(HIST("histPhi"), track.phi(), pdgbin); + MC_recon_reg.fill(HIST("histEta"), track.eta(), pdgbin); + + if ((particle.pdgCode() == 1000020030) || (particle.pdgCode() == -1000020030) || (particle.pdgCode() == 1000020040) || (particle.pdgCode() == -1000020040)) { + if (track.hasITS()) { + MC_recon_reg.fill(HIST("hist_rec_ITS_vs_p"), track.p() * 2, pdgbin); + MC_recon_reg.fill(HIST("hist_rec_ITS_vs_pT"), track.pt() * 2, pdgbin); + if (track.hasTPC()) { + MC_recon_reg.fill(HIST("hist_rec_ITS_TPC_vs_p"), track.p() * 2, pdgbin); + MC_recon_reg.fill(HIST("hist_rec_ITS_TPC_vs_pT"), track.pt() * 2, pdgbin); + if (track.hasTOF()) { + MC_recon_reg.fill(HIST("hist_rec_ITS_TPC_TOF_vs_p"), track.p() * 2, pdgbin); + MC_recon_reg.fill(HIST("hist_rec_ITS_TPC_TOF_vs_pT"), track.pt() * 2, pdgbin); + } + } + } + } else { + if (track.hasITS()) { + MC_recon_reg.fill(HIST("hist_rec_ITS_vs_p"), track.p(), pdgbin); + MC_recon_reg.fill(HIST("hist_rec_ITS_vs_pT"), track.pt(), pdgbin); + if (track.hasTPC()) { + MC_recon_reg.fill(HIST("hist_rec_ITS_TPC_vs_p"), track.p(), pdgbin); + MC_recon_reg.fill(HIST("hist_rec_ITS_TPC_vs_pT"), track.pt(), pdgbin); + if (track.hasTOF()) { + MC_recon_reg.fill(HIST("hist_rec_ITS_TPC_TOF_vs_p"), track.p(), pdgbin); + MC_recon_reg.fill(HIST("hist_rec_ITS_TPC_TOF_vs_pT"), track.pt(), pdgbin); + } + } + } + } + } + + // Skipping collisions without the generated collisions + // Actually this should never happen, since we group per MC collision + if (!collision.has_mcCollision()) { + continue; + } else { + // skip generated collisions outside the allowed vtx-z range + // putting this condition here avoids the particle loop a few lines below + if (applyPvZCutGenColl) { + const float genPvZ = mcCollision.posZ(); + if (genPvZ < -cfgCutVertex || genPvZ > cfgCutVertex) + continue; + } + } + + MC_gen_reg.fill(HIST("histGenVtxMC_reco"), mcCollision.posZ()); + MC_gen_reg.fill(HIST("histCentrality_reco"), centrality); + + /// only to fill denominator of ITS-TPC matched primary tracks only in MC events with at least 1 reco. vtx + for (const auto& particle : groupedMcParticles) { // Particle loop + + /// require generated particle in acceptance + if (!isInAcceptance(particle)) + continue; + + int pdgbin = -10; + switch (particle.pdgCode()) { + case +211: + histPDG_gen_reco->AddBinContent(1); + pdgbin = 0; + break; + case -211: + histPDG_gen_reco->AddBinContent(2); + pdgbin = 1; + break; + case +321: + histPDG_gen_reco->AddBinContent(3); + pdgbin = 2; + break; + case -321: + histPDG_gen_reco->AddBinContent(4); + pdgbin = 3; + break; + case +2212: + histPDG_gen_reco->AddBinContent(5); + pdgbin = 4; + break; + case -2212: + histPDG_gen_reco->AddBinContent(6); + pdgbin = 5; + break; + case +1000010020: + histPDG_gen_reco->AddBinContent(7); + pdgbin = 6; + break; + case -1000010020: + histPDG_gen_reco->AddBinContent(8); + pdgbin = 7; + break; + case +1000010030: + histPDG_gen_reco->AddBinContent(9); + pdgbin = 8; + break; + case -1000010030: + histPDG_gen_reco->AddBinContent(10); + pdgbin = 9; + break; + case +1000020030: + histPDG_gen_reco->AddBinContent(11); + pdgbin = 10; + break; + case -1000020030: + histPDG_gen_reco->AddBinContent(12); + pdgbin = 11; + break; + case +1000020040: + histPDG_gen_reco->AddBinContent(13); + pdgbin = 12; + break; + case -1000020040: + histPDG_gen_reco->AddBinContent(14); + pdgbin = 13; + break; + default: + pdgbin = -10; + continue; + break; + } + MC_gen_reg.fill(HIST("histEta_reco"), particle.eta(), pdgbin); + MC_gen_reg.fill(HIST("hist_gen_reco_p"), particle.p(), pdgbin); + MC_gen_reg.fill(HIST("hist_gen_reco_pT"), particle.pt(), pdgbin); + } + } /// end loop over reconstructed collisions + + // skip generated collisions outside the allowed vtx-z range + // putting this condition here avoids the particle loop a few lines below + if (applyPvZCutGenColl) { + const float genPvZ = mcCollision.posZ(); + if (genPvZ < -cfgCutVertex || genPvZ > cfgCutVertex) { + continue; + } + } + + // Loop on particles to fill the denominator + for (const auto& mcParticle : groupedMcParticles) { + if (!isInAcceptance(mcParticle)) + continue; + + MC_gen_reg.fill(HIST("histGenVtxMC"), mcCollision.posZ()); + // MC_gen_reg.fill(HIST("histCentrality"), mcParticle.impactParameter()); + + int pdgbin = -10; + switch (mcParticle.pdgCode()) { + case +211: + histPDG_gen->AddBinContent(1); + pdgbin = 0; + break; + case -211: + histPDG_gen->AddBinContent(2); + pdgbin = 1; + break; + case +321: + histPDG_gen->AddBinContent(3); + pdgbin = 2; + break; + case -321: + histPDG_gen->AddBinContent(4); + pdgbin = 3; + break; + case +2212: + histPDG_gen->AddBinContent(5); + pdgbin = 4; + break; + case -2212: + histPDG_gen->AddBinContent(6); + pdgbin = 5; + break; + case +1000010020: + histPDG_gen->AddBinContent(7); + pdgbin = 6; + break; + case -1000010020: + histPDG_gen->AddBinContent(8); + pdgbin = 7; + break; + case +1000010030: + histPDG_gen->AddBinContent(9); + pdgbin = 8; + break; + case -1000010030: + histPDG_gen->AddBinContent(10); + pdgbin = 9; + break; + case +1000020030: + histPDG_gen->AddBinContent(11); + pdgbin = 10; + break; + case -1000020030: + histPDG_gen->AddBinContent(12); + pdgbin = 11; + break; + case +1000020040: + histPDG_gen->AddBinContent(13); + pdgbin = 12; + break; + case -1000020040: + histPDG_gen->AddBinContent(14); + pdgbin = 13; + break; + default: + pdgbin = -10; + continue; + break; + } + + MC_gen_reg.fill(HIST("histPhi"), mcParticle.phi(), pdgbin); + MC_gen_reg.fill(HIST("histEta"), mcParticle.eta(), pdgbin); + MC_gen_reg.fill(HIST("histRapid"), mcParticle.y(), pdgbin); + MC_gen_reg.fill(HIST("hist_gen_p"), mcParticle.p(), pdgbin); + MC_gen_reg.fill(HIST("hist_gen_pT"), mcParticle.pt(), pdgbin); + } + } /// end loop over generated collisions + } + PROCESS_SWITCH(NucleiEfficiencyTask, processMC, "process generated MC", true); +}; + +//*********************************************************************************** + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"nuclei-efficiency-hist"})}; +} diff --git a/PWGLF/Tasks/Nuspex/NucleiHistTask.cxx b/PWGLF/Tasks/Nuspex/NucleiHistTask.cxx index 9dbc7275563..e3152c05cfb 100644 --- a/PWGLF/Tasks/Nuspex/NucleiHistTask.cxx +++ b/PWGLF/Tasks/Nuspex/NucleiHistTask.cxx @@ -16,6 +16,9 @@ #include #include #include +#include +#include +#include #include "ReconstructionDataFormats/Track.h" #include "Framework/runDataProcessing.h" @@ -24,20 +27,30 @@ #include "Framework/ASoAHelpers.h" #include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/TrackSelectionTables.h" - +#include "Common/DataModel/McCollisionExtra.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Centrality.h" - #include "Framework/HistogramRegistry.h" - #include "PWGLF/DataModel/LFParticleIdentification.h" #include "PWGDQ/DataModel/ReducedInfoTables.h" #include "TPDGCode.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/Core/TrackSelection.h" +#include "Framework/StaticFor.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "PWGLF/DataModel/spectraTOF.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "PWGLF/Utils/inelGt.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "Common/Core/RecoDecay.h" using namespace o2; +using namespace o2::track; using namespace o2::framework; using namespace o2::framework::expressions; +std::vector ptBinning = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4., 5., 6., 8., 10., 12., 14.}; + struct NucleiHistTask { // Data @@ -54,67 +67,105 @@ struct NucleiHistTask { HistogramRegistry aHelium3_reg{"aHelium3", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry Helium4_reg{"Helium4", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry aHelium4_reg{"aHelium4", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + OutputObj histTrackcuts_data_spectra{TH1I("histTrackcuts_data_spectra", "Entires;Track cut", 18, 0, 18)}; + OutputObj histTrackcuts_data_particle{TH1I("histTrackcuts_data_particle", "Entires;Track cut", 18, 0, 18)}; // MC - HistogramRegistry MC_truth_reg{"MC_particles", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry MC_recon_reg{"MC_particles_reconstructed", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry MC_recon_diff_reg{"MC_reconstructed_diff", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry MC_eff{"MC_efficiency", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - OutputObj histPDG{TH1F("PDG", "PDG;PDG code", 100, 0.0, 100.0)}; - OutputObj histPDG_eff{TH1F("PDG_eff", "PDG;PDG code", 100, 0.0, 100.0)}; + HistogramRegistry MC_recon_reg{"MC_particles_reco", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry MC_gen_reg{"MC_particles_gen", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry MC_DCA{"MC_DCA", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + OutputObj histPDG_reco{TH1I("PDG reconstructed", "PDG;PDG code", 18, 0.0, 18)}; + OutputObj histPDG_gen{TH1I("PDG generated", "PDG;PDG code", 18, 0.0, 18)}; + OutputObj histTrackcuts_MC{TH1I("histTrackcuts_MC", "Entires;Track cut", 18, 0, 18)}; void init(o2::framework::InitContext&) { - if (doprocessData == true && doprocessDataCent == true) { - LOG(fatal) << "Can't enable processData and processDataCent in the same time, pick one!"; - } + // +++++++++++++++++++++ Spectra ++++++++++++++++++++++++ + histTrackcuts_data_spectra->GetXaxis()->SetBinLabel(1, "Events read"); + histTrackcuts_data_spectra->GetXaxis()->SetBinLabel(2, "Ev. sel. passed"); + histTrackcuts_data_spectra->GetXaxis()->SetBinLabel(3, "DCA cut passed"); + histTrackcuts_data_spectra->GetXaxis()->SetBinLabel(4, "TPCnCls cut passed"); + histTrackcuts_data_spectra->GetXaxis()->SetBinLabel(5, "TPCCrossedRowsOverFindable cut passed"); + histTrackcuts_data_spectra->GetXaxis()->SetBinLabel(6, "Chi2 cut passed"); + histTrackcuts_data_spectra->GetXaxis()->SetBinLabel(7, "Passed TPC refit cut"); + histTrackcuts_data_spectra->GetXaxis()->SetBinLabel(8, "Passed ITS refit cut"); + histTrackcuts_data_spectra->GetXaxis()->SetBinLabel(9, "ITSnCls cut passed"); + histTrackcuts_data_spectra->GetXaxis()->SetBinLabel(10, "track.pt() cut passed"); + histTrackcuts_data_spectra->GetXaxis()->SetBinLabel(11, "hasITS & hasTPC cut passed"); + histTrackcuts_data_spectra->GetXaxis()->SetBinLabel(12, "GoldenChi2 cut passed"); + + // +++++++++++++++++++++ Data particle ++++++++++++++++++++++++ + histTrackcuts_data_particle->GetXaxis()->SetBinLabel(1, "Events read"); + histTrackcuts_data_particle->GetXaxis()->SetBinLabel(2, "Ev. sel. passed"); + histTrackcuts_data_particle->GetXaxis()->SetBinLabel(3, "Rap. cut passed"); + histTrackcuts_data_particle->GetXaxis()->SetBinLabel(4, "TPCnCls cut passed"); + histTrackcuts_data_particle->GetXaxis()->SetBinLabel(5, "TPCCrossedRowsOverFindable cut passed"); + histTrackcuts_data_particle->GetXaxis()->SetBinLabel(6, "Chi2 cut passed"); + histTrackcuts_data_particle->GetXaxis()->SetBinLabel(7, "Passed TPC refit cut"); + histTrackcuts_data_particle->GetXaxis()->SetBinLabel(8, "Passed ITS refit cut"); + histTrackcuts_data_particle->GetXaxis()->SetBinLabel(9, "ITSnCls cut passed"); + histTrackcuts_data_particle->GetXaxis()->SetBinLabel(10, "track.pt() cut passed"); + histTrackcuts_data_particle->GetXaxis()->SetBinLabel(11, "hasITS & hasTPC cut passed"); + histTrackcuts_data_particle->GetXaxis()->SetBinLabel(12, "GoldenChi2 cut passed"); + histTrackcuts_data_particle->GetXaxis()->SetBinLabel(13, "DCA cut passed"); + + // +++++++++++++++++++ reconstructed MC ++++++++++++++++++++++ + histTrackcuts_MC->GetXaxis()->SetBinLabel(1, "Events read"); + histTrackcuts_MC->GetXaxis()->SetBinLabel(2, "Is Physical Primary"); + histTrackcuts_MC->GetXaxis()->SetBinLabel(3, "Rap. cut passed"); + histTrackcuts_MC->GetXaxis()->SetBinLabel(4, "DCA cut passed"); + histTrackcuts_MC->GetXaxis()->SetBinLabel(5, "TPCnCls cut passed"); + histTrackcuts_MC->GetXaxis()->SetBinLabel(6, "TPCCrossedRowsOverFindable cut passed"); + histTrackcuts_MC->GetXaxis()->SetBinLabel(7, "Chi2 cut passed"); + histTrackcuts_MC->GetXaxis()->SetBinLabel(8, "Passed TPC refit cut"); + histTrackcuts_MC->GetXaxis()->SetBinLabel(9, "Passed ITS refit cut"); + histTrackcuts_MC->GetXaxis()->SetBinLabel(10, "ITSnCls cut passed"); + histTrackcuts_MC->GetXaxis()->SetBinLabel(11, "track.pt() cut passed"); + histTrackcuts_MC->GetXaxis()->SetBinLabel(12, "hasITS & hasTPC cut passed"); + histTrackcuts_MC->GetXaxis()->SetBinLabel(13, "GoldenChi2 cut passed"); std::vector ptBinning = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4., 5., 6., 8., 10., 12., 14.}; - std::vector ptBinning_short = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4}; - std::vector ptBinning_diff = {-14.0, -12.0, -10.0, -8.0, -6.0, -5.0, -4.0, -3.6, -3.2, -2.8, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.3, -1.2, -1.1, -1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4., 5., 6., 8., 10., 12., 14.}; - std::vector centBinning = {0., 1., 5., 10., 20., 30., 40., 50., 70., 100.}; std::vector etaBinning = {-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}; + std::vector PDGBinning = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0}; AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; - AxisSpec ptAxis_reduced = {ptBinning_short, "#it{p}_{T} (GeV/#it{c})"}; - AxisSpec centAxis = {centBinning, "V0M (%)"}; - AxisSpec centralityAxis = {100, 0.0, 100.0, "VT0C (%)"}; - AxisSpec centralityAxis_extended = {105, 0.0, 105.0, "VT0C (%)"}; + AxisSpec pAxis = {ptBinning, "#it{p} (GeV/#it{c})"}; + AxisSpec centralityAxis = {100, 0.0, 105.0, "VT0C (%)"}; AxisSpec etaAxis = {etaBinning, "#eta"}; - AxisSpec PDGBINNING = {20, 0.0, 20.0, "PDG code"}; - AxisSpec ptAxis_diff = {ptBinning_diff, "#it{p}_{T,diff} (GeV/#it{c})"}; + AxisSpec PDGBINNING = {PDGBinning, "PDG code"}; // +++++++++++++++++++++ Data ++++++++++++++++++++++++ // QA histograms spectra_reg.add("histRecVtxZData", "collision z position", HistType::kTH1F, {{200, -20., +20., "z position (cm)"}}); - spectra_reg.add("histTpcSignalData", "Specific energy loss", HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); - spectra_reg.add("histTofSignalData", "TOF signal", HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); - spectra_reg.add("histDcaVsPtData_particle", "dcaXY vs Pt (particle)", HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); + spectra_reg.add("histTpcSignalData", "Specific energy loss", HistType::kTH2F, {{600, -6., 6., "#it{p*} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); + spectra_reg.add("histTofSignalData", "TOF signal", HistType::kTH2F, {{600, -6., 6., "#it{p*} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); + spectra_reg.add("histDcaVsPtData_particle", "dcaXY vs Pt (particle)", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); spectra_reg.add("histDcaZVsPtData_particle", "dcaZ vs Pt (particle)", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); - spectra_reg.add("histDcaVsPtData_antiparticle", "dcaXY vs Pt (antiparticle)", HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); + spectra_reg.add("histDcaVsPtData_antiparticle", "dcaXY vs Pt (antiparticle)", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); spectra_reg.add("histDcaZVsPtData_antiparticle", "dcaZ vs Pt (antiparticle)", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); - spectra_reg.add("histTOFm2", "TOF m^2 vs Pt", HistType::kTH2F, {ptAxis, {400, 0.0, 10.0, "m^2"}}); + spectra_reg.add("histTOFm2", "TOF m^2 vs P", HistType::kTH2F, {pAxis, {400, 0.0, 10.0, "m^2"}}); spectra_reg.add("histNClusterTPC", "Number of Clusters in TPC vs Pt", HistType::kTH2F, {ptAxis, {160, 0.0, 160.0, "nCluster"}}); spectra_reg.add("histNClusterITS", "Number of Clusters in ITS vs Pt", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); spectra_reg.add("histNClusterITSib", "Number of Clusters in ib of ITS vs Pt", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); spectra_reg.add("histChi2TPC", "chi^2 TPC vs Pt", HistType::kTH2F, {ptAxis, {100, 0.0, 5.0, "chi^2"}}); spectra_reg.add("histChi2ITS", "chi^2 ITS vs Pt", HistType::kTH2F, {ptAxis, {500, 0.0, 50.0, "chi^2"}}); - spectra_reg.add("histCentrality", "Centrality", HistType::kTH1F, {centralityAxis_extended}); + spectra_reg.add("histCentrality", "Centrality", HistType::kTH1F, {centralityAxis}); spectra_reg.add("histEtaWithOverFlow", "Pseudorapidity 0 - 105%% centrality", HistType::kTH1F, {etaAxis}); spectra_reg.add("histEta", "Pseudorapidity with centrality cut", HistType::kTH1F, {etaAxis}); - spectra_reg.add("histEta_cent", "Pseudorapidity vs Centrality", HistType::kTH2F, {centralityAxis_extended, etaAxis}); + spectra_reg.add("histEta_cent", "Pseudorapidity vs Centrality", HistType::kTH2F, {centralityAxis, etaAxis}); // histograms for pi⁺ - pion_reg.add("histKeepEventData", "skimming histogram (#pi^{+})", HistType::kTH1F, {{2, -0.5, +1.5, "true: keep event, false: reject event"}}); pion_reg.add("histTpcSignalData", "Specific energy loss (#pi^{+})", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); pion_reg.add("histTofSignalData", "TOF signal (#pi^{+})", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); - pion_reg.add("histDcaVsPtData", "dcaXY vs Pt (#pi^{+})", HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); + pion_reg.add("histDcaVsPtData", "dcaXY vs Pt (#pi^{+})", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); pion_reg.add("histDcaZVsPtData", "dcaZ vs Pt (#pi^{+})", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); - pion_reg.add("histTOFm2", "TOF m^2 vs Pt (#pi^{+})", HistType::kTH2F, {ptAxis, {400, 0.0, 10.0, "m^2"}}); - pion_reg.add("histTpcNsigmaData", "n-sigma TPC (#pi^{+})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); - pion_reg.add("histTofNsigmaData", "n-sigma TOF (#pi^{+})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); + pion_reg.add("histDcaVsPtData_after_cut", "dcaXY vs Pt (#pi^{+}) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + pion_reg.add("histDcaZVsPtData_after_cut", "dcaZ vs Pt (#pi^{+}) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + pion_reg.add("histTOFm2", "TOF m^2 vs Pt (#pi^{+})", HistType::kTH2F, {pAxis, {400, 0.0, 10.0, "m^2"}}); + pion_reg.add("histTpcNsigmaData", "n-sigma TPC (#pi^{+})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); + pion_reg.add("histTofNsigmaData", "n-sigma TOF (#pi^{+})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); pion_reg.add("histNClusterTPC", "Number of Clusters in TPC vs Pt (#pi^{+})", HistType::kTH2F, {ptAxis, {160, 0.0, 160.0, "nCluster"}}); pion_reg.add("histNClusterITS", "Number of Clusters in ITS vs Pt (#pi^{+})", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); pion_reg.add("histNClusterITSib", "Number of Clusters in ib of ITS vs Pt (#pi^{+})", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); @@ -128,14 +179,15 @@ struct NucleiHistTask { pion_reg.add("histTofm2_eta", "mass^2 TOF (#pi^{+}) vs eta", HistType::kTH3F, {ptAxis, {400, 0.0, 10.0, "m^2_{#pi^{+}}"}, etaAxis}); // histograms for pi⁻ - apion_reg.add("histKeepEventData", "skimming histogram (#pi^{-})", HistType::kTH1F, {{2, -0.5, +1.5, "true: keep event, false: reject event"}}); apion_reg.add("histTpcSignalData", "Specific energy loss (#pi^{-})", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); apion_reg.add("histTofSignalData", "TOF signal (#pi^{-})", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); - apion_reg.add("histDcaVsPtData", "dcaXY vs Pt (#pi^{-})", HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); + apion_reg.add("histDcaVsPtData", "dcaXY vs Pt (#pi^{-})", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); apion_reg.add("histDcaZVsPtData", "dcaZ vs Pt (#pi^{-})", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); - apion_reg.add("histTOFm2", "TOF m^2 vs Pt (#pi^{-})", HistType::kTH2F, {ptAxis, {400, 0.0, 10.0, "m^2"}}); - apion_reg.add("histTpcNsigmaData", "n-sigma TPC (#pi^{-})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); - apion_reg.add("histTofNsigmaData", "n-sigma TOF (#pi^{-})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); + apion_reg.add("histDcaVsPtData_after_cut", "dcaXY vs Pt (#pi^{-}) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + apion_reg.add("histDcaZVsPtData_after_cut", "dcaZ vs Pt (#pi^{-}) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + apion_reg.add("histTOFm2", "TOF m^2 vs Pt (#pi^{-})", HistType::kTH2F, {pAxis, {400, 0.0, 10.0, "m^2"}}); + apion_reg.add("histTpcNsigmaData", "n-sigma TPC (#pi^{-})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); + apion_reg.add("histTofNsigmaData", "n-sigma TOF (#pi^{-})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); apion_reg.add("histNClusterTPC", "Number of Clusters in TPC vs Pt (#pi^{-})", HistType::kTH2F, {ptAxis, {160, 0.0, 160.0, "nCluster"}}); apion_reg.add("histNClusterITS", "Number of Clusters in ITS vs Pt (#pi^{-})", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); apion_reg.add("histNClusterITSib", "Number of Clusters in ib of ITS vs Pt (#pi^{-})", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); @@ -149,14 +201,15 @@ struct NucleiHistTask { apion_reg.add("histTofm2_eta", "mass^2 TOF (#pi^{-}) vs eta", HistType::kTH3F, {ptAxis, {400, 0.0, 10.0, "m^2_{#pi^{+}}"}, etaAxis}); // histograms for Proton - proton_reg.add("histKeepEventData", "skimming histogram (p)", HistType::kTH1F, {{2, -0.5, +1.5, "true: keep event, false: reject event"}}); proton_reg.add("histTpcSignalData", "Specific energy loss (p)", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); proton_reg.add("histTofSignalData", "TOF signal (p)", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); - proton_reg.add("histDcaVsPtData", "dcaXY vs Pt (p)", HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); + proton_reg.add("histDcaVsPtData", "dcaXY vs Pt (p)", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); proton_reg.add("histDcaZVsPtData", "dcaZ vs Pt (p)", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); - proton_reg.add("histTOFm2", "TOF m^2 vs Pt (p)", HistType::kTH2F, {ptAxis, {400, 0.0, 10.0, "m^2"}}); - proton_reg.add("histTpcNsigmaData", "n-sigma TPC (p)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{p}"}}); - proton_reg.add("histTofNsigmaData", "n-sigma TOF (p)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{p}"}}); + proton_reg.add("histDcaVsPtData_after_cut", "dcaXY vs Pt (p) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + proton_reg.add("histDcaZVsPtData_after_cut", "dcaZ vs Pt (p) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + proton_reg.add("histTOFm2", "TOF m^2 vs Pt (p)", HistType::kTH2F, {pAxis, {400, 0.0, 10.0, "m^2"}}); + proton_reg.add("histTpcNsigmaData", "n-sigma TPC (p)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{p}"}}); + proton_reg.add("histTofNsigmaData", "n-sigma TOF (p)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{p}"}}); proton_reg.add("histNClusterTPC", "Number of Clusters in TPC vs Pt (p)", HistType::kTH2F, {ptAxis, {160, 0.0, 160.0, "nCluster"}}); proton_reg.add("histNClusterITS", "Number of Clusters in ITS vs Pt (p)", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); proton_reg.add("histNClusterITSib", "Number of Clusters in ib of ITS vs Pt (p)", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); @@ -170,14 +223,15 @@ struct NucleiHistTask { proton_reg.add("histTofm2_eta", "mass^2 TOF (p) vs eta", HistType::kTH3F, {ptAxis, {400, 0.0, 10.0, "m^2_{p}"}, etaAxis}); // histograms for antiProton - aproton_reg.add("histKeepEventData", "skimming histogram (#bar{p})", HistType::kTH1F, {{2, -0.5, +1.5, "true: keep event, false: reject event"}}); aproton_reg.add("histTpcSignalData", "Specific energy loss (#bar{p})", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); aproton_reg.add("histTofSignalData", "TOF signal (#bar{p})", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); - aproton_reg.add("histDcaVsPtData", "dcaXY vs Pt (#bar{p})", HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); + aproton_reg.add("histDcaVsPtData", "dcaXY vs Pt (#bar{p})", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); aproton_reg.add("histDcaZVsPtData", "dcaZ vs Pt (#bar{p})", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); - aproton_reg.add("histTOFm2", "TOF m^2 vs Pt (#bar{p})", HistType::kTH2F, {ptAxis, {400, 0.0, 10.0, "m^2"}}); - aproton_reg.add("histTpcNsigmaData", "n-sigma TPC (#bar{p})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#bar{p}}"}}); - aproton_reg.add("histTofNsigmaData", "n-sigma TOF (#bar{p})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#bar{p}}"}}); + aproton_reg.add("histDcaVsPtData_after_cut", "dcaXY vs Pt (#bar{p}) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + aproton_reg.add("histDcaZVsPtData_after_cut", "dcaZ vs Pt (#bar{p}) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + aproton_reg.add("histTOFm2", "TOF m^2 vs Pt (#bar{p})", HistType::kTH2F, {pAxis, {400, 0.0, 10.0, "m^2"}}); + aproton_reg.add("histTpcNsigmaData", "n-sigma TPC (#bar{p})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{#bar{p}}"}}); + aproton_reg.add("histTofNsigmaData", "n-sigma TOF (#bar{p})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{#bar{p}}"}}); aproton_reg.add("histNClusterTPC", "Number of Clusters in TPC vs Pt (#bar{p})", HistType::kTH2F, {ptAxis, {160, 0.0, 160.0, "nCluster"}}); aproton_reg.add("histNClusterITS", "Number of Clusters in ITS vs Pt (#bar{p})", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); aproton_reg.add("histNClusterITSib", "Number of Clusters in ib of ITS vs Pt (#bar{p})", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); @@ -191,56 +245,59 @@ struct NucleiHistTask { aproton_reg.add("histTofm2_eta", "mass^2 TOF (#bar{p}) vs eta", HistType::kTH3F, {ptAxis, {400, 0.0, 10.0, "m^2_{#bar{p}}"}, etaAxis}); // histograms for Deuterons - deuteron_reg.add("histKeepEventData", "skimming histogram (d)", HistType::kTH1F, {{2, -0.5, +1.5, "true: keep event, false: reject event"}}); deuteron_reg.add("histTpcSignalData", "Specific energy loss (d)", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); deuteron_reg.add("histTofSignalData", "TOF signal (d)", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); - deuteron_reg.add("histDcaVsPtData", "dcaXY vs Pt (d)", HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); + deuteron_reg.add("histDcaVsPtData", "dcaXY vs Pt (d)", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); deuteron_reg.add("histDcaZVsPtData", "dcaZ vs Pt (d)", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); - deuteron_reg.add("histTOFm2", "TOF m^2 vs Pt (d)", HistType::kTH2F, {ptAxis, {400, 0.0, 10.0, "m^2"}}); - deuteron_reg.add("histTpcNsigmaData", "n-sigma TPC (d)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{d}"}}); - deuteron_reg.add("histTofNsigmaData", "n-sigma TOF (d)", HistType::kTH2F, {ptAxis_reduced, {160, -20., +20., "n#sigma_{d}"}}); + deuteron_reg.add("histDcaVsPtData_after_cut", "dcaXY vs Pt (d) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + deuteron_reg.add("histDcaZVsPtData_after_cut", "dcaZ vs Pt (d) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + deuteron_reg.add("histTOFm2", "TOF m^2 vs Pt (d)", HistType::kTH2F, {pAxis, {400, 0.0, 10.0, "m^2"}}); + deuteron_reg.add("histTpcNsigmaData", "n-sigma TPC (d)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{d}"}}); + deuteron_reg.add("histTofNsigmaData", "n-sigma TOF (d)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{d}"}}); deuteron_reg.add("histNClusterTPC", "Number of Clusters in TPC vs Pt (d)", HistType::kTH2F, {ptAxis, {160, 0.0, 160.0, "nCluster"}}); deuteron_reg.add("histNClusterITS", "Number of Clusters in ITS vs Pt (d)", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); deuteron_reg.add("histNClusterITSib", "Number of Clusters in ib of ITS vs Pt (d)", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); deuteron_reg.add("histChi2TPC", "chi^2 TPC vs Pt (d)", HistType::kTH2F, {ptAxis, {100, 0.0, 5.0, "chi^2"}}); deuteron_reg.add("histChi2ITS", "chi^2 ITS vs Pt (d)", HistType::kTH2F, {ptAxis, {500, 0.0, 50.0, "chi^2"}}); deuteron_reg.add("histTpcNsigmaData_cent", "n-sigma TPC (d) centrality", HistType::kTH3F, {ptAxis, {160, -20., +20., "n#sigma_{d}"}, centralityAxis}); - deuteron_reg.add("histTofNsigmaData_cent", "n-sigma TOF (d) centrality", HistType::kTH3F, {ptAxis_reduced, {160, -20., +20., "n#sigma_{d}"}, centralityAxis}); + deuteron_reg.add("histTofNsigmaData_cent", "n-sigma TOF (d) centrality", HistType::kTH3F, {ptAxis, {160, -20., +20., "n#sigma_{d}"}, centralityAxis}); deuteron_reg.add("histTofm2_cent", "mass^2 TOF (d) centrality", HistType::kTH3F, {ptAxis, {400, 0.0, 10.0, "m^2_{d}"}, centralityAxis}); deuteron_reg.add("histTpcNsigmaData_eta", "n-sigma TPC (d) vs eta", HistType::kTH3F, {ptAxis, {160, -20., +20., "n#sigma_{d}"}, etaAxis}); - deuteron_reg.add("histTofNsigmaData_eta", "n-sigma TOF (d) vs eta", HistType::kTH3F, {ptAxis_reduced, {160, -20., +20., "n#sigma_{d}"}, etaAxis}); + deuteron_reg.add("histTofNsigmaData_eta", "n-sigma TOF (d) vs eta", HistType::kTH3F, {ptAxis, {160, -20., +20., "n#sigma_{d}"}, etaAxis}); deuteron_reg.add("histTofm2_eta", "mass^2 TOF (d) vs eta", HistType::kTH3F, {ptAxis, {400, 0.0, 10.0, "m^2_{d}"}, etaAxis}); // histograms for antiDeuterons - adeuteron_reg.add("histKeepEventData", "skimming histogram (#bar{d})", HistType::kTH1F, {{2, -0.5, +1.5, "true: keep event, false: reject event"}}); adeuteron_reg.add("histTpcSignalData", "Specific energy loss (#bar{d})", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); adeuteron_reg.add("histTofSignalData", "TOF signal (#bar{d})", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); - adeuteron_reg.add("histDcaVsPtData", "dcaXY vs Pt (#bar{d})", HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); + adeuteron_reg.add("histDcaVsPtData", "dcaXY vs Pt (#bar{d})", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); adeuteron_reg.add("histDcaZVsPtData", "dcaZ vs Pt (#bar{d})", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); - adeuteron_reg.add("histTOFm2", "TOF m^2 vs Pt (#bar{d})", HistType::kTH2F, {ptAxis, {400, 0.0, 10.0, "m^2"}}); - adeuteron_reg.add("histTpcNsigmaData", "n-sigma TPC (#bar{d})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#bar{d}}"}}); - adeuteron_reg.add("histTofNsigmaData", "n-sigma TOF (#bar{d})", HistType::kTH2F, {ptAxis_reduced, {160, -20., +20., "n#sigma_{#bar{d}}"}}); + adeuteron_reg.add("histDcaVsPtData_after_cut", "dcaXY vs Pt (#bar{d}) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + adeuteron_reg.add("histDcaZVsPtData_after_cut", "dcaZ vs Pt (#bar{d}) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + adeuteron_reg.add("histTOFm2", "TOF m^2 vs Pt (#bar{d})", HistType::kTH2F, {pAxis, {400, 0.0, 10.0, "m^2"}}); + adeuteron_reg.add("histTpcNsigmaData", "n-sigma TPC (#bar{d})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{#bar{d}}"}}); + adeuteron_reg.add("histTofNsigmaData", "n-sigma TOF (#bar{d})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{#bar{d}}"}}); adeuteron_reg.add("histNClusterTPC", "Number of Clusters in TPC vs Pt (#bar{d})", HistType::kTH2F, {ptAxis, {160, 0.0, 160.0, "nCluster"}}); adeuteron_reg.add("histNClusterITS", "Number of Clusters in ITS vs Pt (#bar{d})", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); adeuteron_reg.add("histNClusterITSib", "Number of Clusters in ib of ITS vs Pt (#bar{d})", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); adeuteron_reg.add("histChi2TPC", "chi^2 TPC vs Pt (#bar{d})", HistType::kTH2F, {ptAxis, {100, 0.0, 5.0, "chi^2"}}); adeuteron_reg.add("histChi2ITS", "chi^2 ITS vs Pt (#bar{d})", HistType::kTH2F, {ptAxis, {500, 0.0, 50.0, "chi^2"}}); adeuteron_reg.add("histTpcNsigmaData_cent", "n-sigma TPC (#bar{d}) centrality", HistType::kTH3F, {ptAxis, {160, -20., +20., "n#sigma_{#bar{d}}"}, centralityAxis}); - adeuteron_reg.add("histTofNsigmaData_cent", "n-sigma TOF (#bar{d}) centrality", HistType::kTH3F, {ptAxis_reduced, {160, -20., +20., "n#sigma_{#bar{d}}"}, centralityAxis}); + adeuteron_reg.add("histTofNsigmaData_cent", "n-sigma TOF (#bar{d}) centrality", HistType::kTH3F, {ptAxis, {160, -20., +20., "n#sigma_{#bar{d}}"}, centralityAxis}); adeuteron_reg.add("histTofm2_cent", "mass^2 TOF (#bar{d}) centrality", HistType::kTH3F, {ptAxis, {400, 0.0, 10.0, "m^2_{#bar{d}}"}, centralityAxis}); adeuteron_reg.add("histTpcNsigmaData_eta", "n-sigma TPC (#bar{d}) vs eta", HistType::kTH3F, {ptAxis, {160, -20., +20., "n#sigma_{#bar{d}}"}, etaAxis}); - adeuteron_reg.add("histTofNsigmaData_eta", "n-sigma TOF (#bar{d}) vs eta", HistType::kTH3F, {ptAxis_reduced, {160, -20., +20., "n#sigma_{#bar{d}}"}, etaAxis}); + adeuteron_reg.add("histTofNsigmaData_eta", "n-sigma TOF (#bar{d}) vs eta", HistType::kTH3F, {ptAxis, {160, -20., +20., "n#sigma_{#bar{d}}"}, etaAxis}); adeuteron_reg.add("histTofm2_eta", "mass^2 TOF (#bar{d}) vs eta", HistType::kTH3F, {ptAxis, {400, 0.0, 10.0, "m^2_{#bar{d}}"}, etaAxis}); // histograms for Triton - triton_reg.add("histKeepEventData", "skimming histogram (t)", HistType::kTH1F, {{2, -0.5, +1.5, "true: keep event, false: reject event"}}); triton_reg.add("histTpcSignalData", "Specific energy loss (t)", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); triton_reg.add("histTofSignalData", "TOF signal (t)", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); - triton_reg.add("histDcaVsPtData", "dcaXY vs Pt (t)", HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); + triton_reg.add("histDcaVsPtData", "dcaXY vs Pt (t)", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); triton_reg.add("histDcaZVsPtData", "dcaZ vs Pt (t)", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); - triton_reg.add("histTOFm2", "TOF m^2 vs Pt (t)", HistType::kTH2F, {ptAxis, {400, 0.0, 10.0, "m^2"}}); - triton_reg.add("histTpcNsigmaData", "n-sigma TPC (t)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{t}"}}); - triton_reg.add("histTofNsigmaData", "n-sigma TOF (t)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{t}"}}); + triton_reg.add("histDcaVsPtData_after_cut", "dcaXY vs Pt (t) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + triton_reg.add("histDcaZVsPtData_after_cut", "dcaZ vs Pt (t) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + triton_reg.add("histTOFm2", "TOF m^2 vs Pt (t)", HistType::kTH2F, {pAxis, {400, 0.0, 10.0, "m^2"}}); + triton_reg.add("histTpcNsigmaData", "n-sigma TPC (t)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{t}"}}); + triton_reg.add("histTofNsigmaData", "n-sigma TOF (t)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{t}"}}); triton_reg.add("histNClusterTPC", "Number of Clusters in TPC vs Pt (t)", HistType::kTH2F, {ptAxis, {160, 0.0, 160.0, "nCluster"}}); triton_reg.add("histNClusterITS", "Number of Clusters in ITS vs Pt (t)", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); triton_reg.add("histNClusterITSib", "Number of Clusters in ib of ITS vs Pt (t)", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); @@ -254,14 +311,15 @@ struct NucleiHistTask { triton_reg.add("histTofm2_eta", "mass^2 TOF (t) vs eta", HistType::kTH3F, {ptAxis, {400, 0.0, 10.0, "m^2_{t}"}, etaAxis}); // histograms for antiTriton - atriton_reg.add("histKeepEventData", "skimming histogram (#bar{t})", HistType::kTH1F, {{2, -0.5, +1.5, "true: keep event, false: reject event"}}); atriton_reg.add("histTpcSignalData", "Specific energy loss (#bar{t})", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); atriton_reg.add("histTofSignalData", "TOF signal (#bar{t})", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); - atriton_reg.add("histDcaVsPtData", "dcaXY vs Pt (#bar{t})", HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); + atriton_reg.add("histDcaVsPtData", "dcaXY vs Pt (#bar{t})", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); atriton_reg.add("histDcaZVsPtData", "dcaZ vs Pt (#bar{t})", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); - atriton_reg.add("histTOFm2", "TOF m^2 vs Pt (#bar{t})", HistType::kTH2F, {ptAxis, {400, 0.0, 10.0, "m^2"}}); - atriton_reg.add("histTpcNsigmaData", "n-sigma TPC (#bar{t})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#bar{t}}"}}); - atriton_reg.add("histTofNsigmaData", "n-sigma TOF (#bar{t})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#bar{t}}"}}); + atriton_reg.add("histDcaVsPtData_after_cut", "dcaXY vs Pt (#bar{t}) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + atriton_reg.add("histDcaZVsPtData_after_cut", "dcaZ vs Pt (#bar{t}) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + atriton_reg.add("histTOFm2", "TOF m^2 vs Pt (#bar{t})", HistType::kTH2F, {pAxis, {400, 0.0, 10.0, "m^2"}}); + atriton_reg.add("histTpcNsigmaData", "n-sigma TPC (#bar{t})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{#bar{t}}"}}); + atriton_reg.add("histTofNsigmaData", "n-sigma TOF (#bar{t})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{#bar{t}}"}}); atriton_reg.add("histNClusterTPC", "Number of Clusters in TPC vs Pt (#bar{t})", HistType::kTH2F, {ptAxis, {160, 0.0, 160.0, "nCluster"}}); atriton_reg.add("histNClusterITS", "Number of Clusters in ITS vs Pt (#bar{t})", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); atriton_reg.add("histNClusterITSib", "Number of Clusters in ib of ITS vs Pt (#bar{t})", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); @@ -275,14 +333,15 @@ struct NucleiHistTask { atriton_reg.add("histTofm2_eta", "mass^2 TOF (#bar{t}) vs eta", HistType::kTH3F, {ptAxis, {400, 0.0, 10.0, "m^2_{#bar{t}}"}, etaAxis}); // histograms for Helium-3 - Helium3_reg.add("histKeepEventData", "skimming histogram (^{3}He)", HistType::kTH1F, {{2, -0.5, +1.5, "true: keep event, false: reject event"}}); Helium3_reg.add("histTpcSignalData", "Specific energy loss (^{3}He)", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); Helium3_reg.add("histTofSignalData", "TOF signal (^{3}He)", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); - Helium3_reg.add("histDcaVsPtData", "dcaXY vs Pt (^{3}He)", HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); + Helium3_reg.add("histDcaVsPtData", "dcaXY vs Pt (^{3}He)", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); Helium3_reg.add("histDcaZVsPtData", "dcaZ vs Pt (^{3}He)", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); - Helium3_reg.add("histTOFm2", "TOF m^2 vs Pt (^{3}He)", HistType::kTH2F, {ptAxis, {400, 0.0, 10.0, "m^2"}}); - Helium3_reg.add("histTpcNsigmaData", "n-sigma TPC (^{3}He)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{^{3}He}"}}); - Helium3_reg.add("histTofNsigmaData", "n-sigma TOF (^{3}He)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{^{3}He}"}}); + Helium3_reg.add("histDcaVsPtData_after_cut", "dcaXY vs Pt (^{3}He) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + Helium3_reg.add("histDcaZVsPtData_after_cut", "dcaZ vs Pt (^{3}He) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + Helium3_reg.add("histTOFm2", "TOF m^2 vs Pt (^{3}He)", HistType::kTH2F, {pAxis, {400, 0.0, 10.0, "m^2"}}); + Helium3_reg.add("histTpcNsigmaData", "n-sigma TPC (^{3}He)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{^{3}He}"}}); + Helium3_reg.add("histTofNsigmaData", "n-sigma TOF (^{3}He)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{^{3}He}"}}); Helium3_reg.add("histNClusterTPC", "Number of Clusters in TPC vs Pt (^{3}He)", HistType::kTH2F, {ptAxis, {160, 0.0, 160.0, "nCluster"}}); Helium3_reg.add("histNClusterITS", "Number of Clusters in ITS vs Pt (^{3}He)", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); Helium3_reg.add("histNClusterITSib", "Number of Clusters in ib of ITS vs Pt (^{3}He)", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); @@ -296,14 +355,15 @@ struct NucleiHistTask { Helium3_reg.add("histTofm2_eta", "mass^2 TOF (^{3}He) vs eta", HistType::kTH3F, {ptAxis, {400, 0.0, 10.0, "m^2_{^{3}He}"}, etaAxis}); // histograms for antiHelium-3 - aHelium3_reg.add("histKeepEventData", "skimming histogram (^{3}#bar{He})", HistType::kTH1F, {{2, -0.5, +1.5, "true: keep event, false: reject event"}}); aHelium3_reg.add("histTpcSignalData", "Specific energy loss (^{3}#bar{He})", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); aHelium3_reg.add("histTofSignalData", "TOF signal (^{3}#bar{He})", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); - aHelium3_reg.add("histDcaVsPtData", "dcaXY vs Pt (^{3}#bar{He})", HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); + aHelium3_reg.add("histDcaVsPtData", "dcaXY vs Pt (^{3}#bar{He})", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); aHelium3_reg.add("histDcaZVsPtData", "dcaZ vs Pt (^{3}#bar{He})", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); - aHelium3_reg.add("histTOFm2", "TOF m^2 vs Pt (^{3}#bar{He})", HistType::kTH2F, {ptAxis, {400, 0.0, 10.0, "m^2"}}); - aHelium3_reg.add("histTpcNsigmaData", "n-sigma TPC (^{3}#bar{He})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{^{3}He}"}}); - aHelium3_reg.add("histTofNsigmaData", "n-sigma TOF (^{3}#bar{He})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{^{3}He}"}}); + aHelium3_reg.add("histDcaVsPtData_after_cut", "dcaXY vs Pt (^{3}#bar{He}) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + aHelium3_reg.add("histDcaZVsPtData_after_cut", "dcaZ vs Pt (^{3}#bar{He}) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + aHelium3_reg.add("histTOFm2", "TOF m^2 vs Pt (^{3}#bar{He})", HistType::kTH2F, {pAxis, {400, 0.0, 10.0, "m^2"}}); + aHelium3_reg.add("histTpcNsigmaData", "n-sigma TPC (^{3}#bar{He})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{^{3}He}"}}); + aHelium3_reg.add("histTofNsigmaData", "n-sigma TOF (^{3}#bar{He})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{^{3}He}"}}); aHelium3_reg.add("histNClusterTPC", "Number of Clusters in TPC vs Pt (^{3}#bar{He})", HistType::kTH2F, {ptAxis, {160, 0.0, 160.0, "nCluster"}}); aHelium3_reg.add("histNClusterITS", "Number of Clusters in ITS vs Pt (^{3}#bar{He})", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); aHelium3_reg.add("histNClusterITSib", "Number of Clusters in ib of ITS vs Pt (^{3}#bar{He})", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); @@ -317,14 +377,15 @@ struct NucleiHistTask { aHelium3_reg.add("histTofm2_eta", "mass^2 TOF (^{3}#bar{He}) vs eta", HistType::kTH3F, {ptAxis, {400, 0.0, 10.0, "m^2_{^{3}He}"}, etaAxis}); // histograms for Helium-4 (alpha) - Helium4_reg.add("histKeepEventData", "skimming histogram (^{4}He)", HistType::kTH1F, {{2, -0.5, +1.5, "true: keep event, false: reject event"}}); Helium4_reg.add("histTpcSignalData", "Specific energy loss (^{4}He)", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); Helium4_reg.add("histTofSignalData", "TOF signal (^{4}He)", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); - Helium4_reg.add("histDcaVsPtData", "dcaXY vs Pt (^{4}He)", HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); + Helium4_reg.add("histDcaVsPtData", "dcaXY vs Pt (^{4}He)", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); Helium4_reg.add("histDcaZVsPtData", "dcaZ vs Pt (^{4}He)", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); - Helium4_reg.add("histTOFm2", "TOF m^2 vs Pt (^{4}He)", HistType::kTH2F, {ptAxis, {400, 0.0, 10.0, "m^2"}}); - Helium4_reg.add("histTpcNsigmaData", "n-sigma TPC (^{4}He)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{^{4}He}"}}); - Helium4_reg.add("histTofNsigmaData", "n-sigma TOF (^{4}He)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{^{4}He}"}}); + Helium4_reg.add("histDcaVsPtData_after_cut", "dcaXY vs Pt (^{4}He) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + Helium4_reg.add("histDcaZVsPtData_after_cut", "dcaZ vs Pt (^{4}He) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + Helium4_reg.add("histTOFm2", "TOF m^2 vs Pt (^{4}He)", HistType::kTH2F, {pAxis, {400, 0.0, 10.0, "m^2"}}); + Helium4_reg.add("histTpcNsigmaData", "n-sigma TPC (^{4}He)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{^{4}He}"}}); + Helium4_reg.add("histTofNsigmaData", "n-sigma TOF (^{4}He)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{^{4}He}"}}); Helium4_reg.add("histNClusterTPC", "Number of Clusters in TPC vs Pt (^{4}He)", HistType::kTH2F, {ptAxis, {160, 0.0, 160.0, "nCluster"}}); Helium4_reg.add("histNClusterITS", "Number of Clusters in ITS vs Pt (^{4}He)", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); Helium4_reg.add("histNClusterITSib", "Number of Clusters in ib of ITS vs Pt (^{4}He)", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); @@ -338,14 +399,15 @@ struct NucleiHistTask { Helium4_reg.add("histTofm2_eta", "mass^2 TOF (^{4}He) vs eta", HistType::kTH3F, {ptAxis, {400, 0.0, 10.0, "m^2_{^{4}He}"}, etaAxis}); // histograms for antiHelium-4 (alpha) - aHelium4_reg.add("histKeepEventData", "skimming histogram (^{4}#bar{He})", HistType::kTH1F, {{2, -0.5, +1.5, "true: keep event, false: reject event"}}); aHelium4_reg.add("histTpcSignalData", "Specific energy loss (^{4}#bar{He})", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); aHelium4_reg.add("histTofSignalData", "TOF signal (^{4}#bar{He})", HistType::kTH2F, {{600, 0., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); - aHelium4_reg.add("histDcaVsPtData", "dcaXY vs Pt (^{4}#bar{He})", HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); + aHelium4_reg.add("histDcaVsPtData", "dcaXY vs Pt (^{4}#bar{He})", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); aHelium4_reg.add("histDcaZVsPtData", "dcaZ vs Pt (^{4}#bar{He})", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); - aHelium4_reg.add("histTOFm2", "TOF m^2 vs Pt (^{4}#bar{He})", HistType::kTH2F, {ptAxis, {400, 0.0, 10.0, "m^2"}}); - aHelium4_reg.add("histTpcNsigmaData", "n-sigma TPC (^{4}#bar{He})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{antiHe-4}"}}); - aHelium4_reg.add("histTofNsigmaData", "n-sigma TOF (^{4}#bar{He})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{antiHe-4}"}}); + aHelium4_reg.add("histDcaVsPtData_after_cut", "dcaXY vs Pt (^{4}#bar{He}) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + aHelium4_reg.add("histDcaZVsPtData_after_cut", "dcaZ vs Pt (^{4}#bar{He}) after cut", HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + aHelium4_reg.add("histTOFm2", "TOF m^2 vs Pt (^{4}#bar{He})", HistType::kTH2F, {pAxis, {400, 0.0, 10.0, "m^2"}}); + aHelium4_reg.add("histTpcNsigmaData", "n-sigma TPC (^{4}#bar{He})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{antiHe-4}"}}); + aHelium4_reg.add("histTofNsigmaData", "n-sigma TOF (^{4}#bar{He})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{antiHe-4}"}}); aHelium4_reg.add("histNClusterTPC", "Number of Clusters in TPC vs Pt (^{4}#bar{He})", HistType::kTH2F, {ptAxis, {160, 0.0, 160.0, "nCluster"}}); aHelium4_reg.add("histNClusterITS", "Number of Clusters in ITS vs Pt (^{4}#bar{He})", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); aHelium4_reg.add("histNClusterITSib", "Number of Clusters in ib of ITS vs Pt (^{4}#bar{He})", HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "nCluster"}}); @@ -360,112 +422,79 @@ struct NucleiHistTask { // +++++++++++++++++++++ MC ++++++++++++++++++++++++++ - // MC truth - MC_truth_reg.add("histPhi", "#phi", HistType::kTH2F, {{100, 0., 2. * TMath::Pi()}, PDGBINNING}); - MC_truth_reg.add("histEta", "#eta", HistType::kTH2F, {{102, -2.01, 2.01}, PDGBINNING}); - MC_truth_reg.add("histPt", "p_{t}", HistType::kTH2F, {ptAxis, PDGBINNING}); - MC_truth_reg.add("histRecVtxMC", "MC collision z position", HistType::kTH1F, {{400, -40., +40., "z position (cm)"}}); - MC_truth_reg.add("histCentrality", "Centrality", HistType::kTH1F, {centralityAxis_extended}); + // MC generated + MC_gen_reg.add("histGenVtxMC", "MC generated vertex z position", HistType::kTH1F, {{400, -40., +40., "z position (cm)"}}); + MC_gen_reg.add("histCentrality", "Centrality", HistType::kTH1F, {centralityAxis}); + MC_gen_reg.add("histEta", "#eta", HistType::kTH2F, {{102, -2.01, 2.01}, PDGBINNING}); + MC_gen_reg.add("histPt", "p_{t}", HistType::kTH2F, {ptAxis, PDGBINNING}); // MC reconstructed - MC_recon_reg.add("histPhi", "#phi", HistType::kTH2F, {{100, 0., 2. * TMath::Pi()}, PDGBINNING}); + MC_recon_reg.add("histRecVtxMC", "MC reconstructed vertex z position", HistType::kTH1F, {{400, -40., +40., "z position (cm)"}}); + MC_recon_reg.add("histCentrality", "Centrality", HistType::kTH1F, {centralityAxis}); MC_recon_reg.add("histEta", "#eta", HistType::kTH2F, {{102, -2.01, 2.01}, PDGBINNING}); MC_recon_reg.add("histPt", "p_{t}", HistType::kTH2F, {ptAxis, PDGBINNING}); - MC_recon_reg.add("histDCA", "DCA xy", HistType::kTH3F, {ptAxis, {250, -0.5, 0.5, "dca"}, PDGBINNING}); + MC_recon_reg.add("histDCA", "DCA xy", HistType::kTH3F, {ptAxis, {1000, -2.0, 2.0, "dca"}, PDGBINNING}); MC_recon_reg.add("histDCAz", "DCA z", HistType::kTH3F, {ptAxis, {1000, -2.0, 2.0, "dca"}, PDGBINNING}); MC_recon_reg.add("histTpcSignalData", "Specific energy loss", HistType::kTH3F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}, PDGBINNING}); - MC_recon_reg.add("histTpcSignalData_all_species", "Specific energy loss", HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); MC_recon_reg.add("histTofSignalData", "TOF signal", HistType::kTH3F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}, PDGBINNING}); + MC_recon_reg.add("histTpcSignalData_all_species", "Specific energy loss", HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); MC_recon_reg.add("histTofSignalData_all_species", "TOF signal", HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); - MC_recon_reg.add("histTOFm2", "TOF m^2 vs Pt", HistType::kTH3F, {ptAxis, {400, 0.0, 10.0, "m^2"}, PDGBINNING}); + MC_recon_reg.add("histTOFm2", "TOF m^2 vs Pt", HistType::kTH3F, {pAxis, {400, 0.0, 10.0, "m^2"}, PDGBINNING}); MC_recon_reg.add("histNClusterTPC", "Number of Clusters in TPC vs Pt", HistType::kTH3F, {ptAxis, {80, 0.0, 160.0, "nCluster"}, PDGBINNING}); MC_recon_reg.add("histNClusterITS", "Number of Clusters in ITS vs Pt", HistType::kTH3F, {ptAxis, {10, 0.0, 10.0, "ITS nCls"}, PDGBINNING}); MC_recon_reg.add("histNClusterITSib", "Number of Clusters in ib of ITS vs Pt", HistType::kTH3F, {ptAxis, {10, 0.0, 10.0, "ITS ib nCls"}, PDGBINNING}); - MC_recon_reg.add("histTPCnClsFindable", "Findable TPC clusters", HistType::kTH3F, {ptAxis, {200, 0.0, 200.0, "nCluster"}, PDGBINNING}); - MC_recon_reg.add("histTPCnClsFindableMinusFound", "TPC Clusters: Findable - Found", HistType::kTH3F, {ptAxis, {60, 0.0, 60.0, "nCluster"}, PDGBINNING}); - MC_recon_reg.add("histTPCnClsFindableMinusCrossedRows", "TPC Clusters: Findable - crossed rows", HistType::kTH3F, {ptAxis, {60, 0.0, 60.0, "nCluster"}, PDGBINNING}); - MC_recon_reg.add("histTPCnClsShared", "Number of shared TPC clusters", HistType::kTH3F, {ptAxis, {70, 0.0, 70.0, "nCluster"}, PDGBINNING}); - MC_recon_reg.add("histTPCCrossedRowsOverFindableCls", "Ratio crossed rows over findable clusters", HistType::kTH2F, {{100, 0., 2.0, "Crossed Rows / Findable Cls"}, PDGBINNING}); - MC_recon_reg.add("histTPCFoundOverFindable", "Ratio of found over findable clusters", HistType::kTH2F, {{100, 0., 2.0, "Found Cls / Findable Cls"}, PDGBINNING}); MC_recon_reg.add("histChi2TPC", "chi^2 TPC vs Pt", HistType::kTH3F, {ptAxis, {100, 0.0, 5.0, "chi^2"}, PDGBINNING}); MC_recon_reg.add("histChi2ITS", "chi^2 ITS vs Pt", HistType::kTH3F, {ptAxis, {500, 0.0, 50.0, "chi^2"}, PDGBINNING}); - MC_recon_reg.add("histChi2ITSvsITSnCls", "chi^2 ITS vs ITS nCls", HistType::kTH2F, {{125, 0.0, 50.0, "chi^2"}, {10, 0.0, 10.0, "ITS nCls"}}); - MC_recon_reg.add("histChi2ITSvsITSibnCls", "chi^2 ITS vs ITS ib nCls", HistType::kTH2F, {{125, 0.0, 50.0, "chi^2"}, {10, 0.0, 10.0, "ITS ib nCls"}}); - MC_recon_reg.add("histChi2ITSvsITSnClsAll", "chi^2 ITS vs ITS nCls", HistType::kTH2F, {{125, 0.0, 50.0, "chi^2"}, {10, 0.0, 10.0, "ITS nCls"}}); MC_recon_reg.add("histChi2TOF", "chi^2 TOF vs Pt", HistType::kTH3F, {ptAxis, {75, 0.0, 15.0, "chi^2"}, PDGBINNING}); - MC_recon_reg.add("histTrackLength", "Track length", HistType::kTH2F, {{350, 0., 700., "length (cm)"}, PDGBINNING}); - MC_recon_reg.add("histTPCFractionSharedCls", "Fraction of shared TPC clusters", HistType::kTH2F, {{100, -2.0, 2.0, "Shared Cls"}, PDGBINNING}); - MC_recon_reg.add("histTpcNsigmaDataPi", "TPC nSigma (#pi^{+})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); - MC_recon_reg.add("histTpcNsigmaDataaPi", "TPC nSigma (#pi^{-})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); - MC_recon_reg.add("histTpcNsigmaDataPr", "TPC nSigma (p)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{p}"}}); - MC_recon_reg.add("histTpcNsigmaDataaPr", "TPC nSigma (#bar{p})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{p}"}}); - MC_recon_reg.add("histTpcNsigmaDataDe", "TPC nSigma (d)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{d}"}}); - MC_recon_reg.add("histTpcNsigmaDataaDe", "TPC nSigma (#bar{d})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{d}"}}); - MC_recon_reg.add("histTpcNsigmaDataTr", "TPC nSigma (t)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{t}"}}); - MC_recon_reg.add("histTpcNsigmaDataaTr", "TPC nSigma (#bar{t})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{t}"}}); - MC_recon_reg.add("histTpcNsigmaDataHe", "TPC nSigma (^{3}He)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{He-3}"}}); - MC_recon_reg.add("histTpcNsigmaDataaHe", "TPC nSigma (^{3}#bar{He})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{He-3}"}}); - MC_recon_reg.add("histTpcNsigmaDataAl", "TPC nSigma (^{4}He)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{He-4}"}}); - MC_recon_reg.add("histTpcNsigmaDataaAl", "TPC nSigma (^{4}#bar{He})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{He-4}"}}); - MC_recon_reg.add("histTofNsigmaDataPi", "TOF nSigma (#pi^{+})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); - MC_recon_reg.add("histTofNsigmaDataaPi", "TOF nSigma (#pi^{-})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); - MC_recon_reg.add("histTofNsigmaDataPr", "TOF nSigma (p)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{p}"}}); - MC_recon_reg.add("histTofNsigmaDataaPr", "TOF nSigma (#bar{p})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{p}"}}); - MC_recon_reg.add("histTofNsigmaDataDe", "TOF nSigma (d)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{d}"}}); - MC_recon_reg.add("histTofNsigmaDataaDe", "TOF nSigma (#bar{d})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{d}"}}); - MC_recon_reg.add("histTofNsigmaDataTr", "TOF nSigma (t)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{t}"}}); - MC_recon_reg.add("histTofNsigmaDataaTr", "TOF nSigma (#bar{t})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{t}"}}); - MC_recon_reg.add("histTofNsigmaDataHe", "TOF nSigma (^{3}He)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{^{3}He}"}}); - MC_recon_reg.add("histTofNsigmaDataaHe", "TOF nSigma (^{3}#bar{He})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{^{3}He}"}}); - MC_recon_reg.add("histTofNsigmaDataAl", "TOF nSigma (^{4}He)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{^{4}He}"}}); - MC_recon_reg.add("histTofNsigmaDataaAl", "TOF nSigma (^{4}#bar{He})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{^{4}He}"}}); - - // MC diff (truth - reconstructed) - MC_recon_diff_reg.add("histPhiDiff", "MC t", HistType::kTH2F, {ptAxis_diff, PDGBINNING}); - MC_recon_diff_reg.add("histEtaDiff", "MC t", HistType::kTH2F, {ptAxis_diff, PDGBINNING}); - MC_recon_diff_reg.add("histPtDiff", "MC t", HistType::kTH2F, {ptAxis_diff, PDGBINNING}); - - // MC efficencies - MC_eff.add("histEffSkimming", "Efficiency skimming", HistType::kTH2F, {{10, 0.0, 10.0}, PDGBINNING}); - MC_eff.add("histITS_vs_pT", "ITS pT distribution", HistType::kTH2F, {ptAxis, PDGBINNING}); - MC_eff.add("histITS_TPC_vs_pT", "ITS_TPC pT distribution", HistType::kTH2F, {ptAxis, PDGBINNING}); - MC_eff.add("histITS_TPC_TOFvs_pT", "ITS_TPC_TOF pT distribution", HistType::kTH2F, {ptAxis, PDGBINNING}); - - MC_eff.add("histPt_TPC_Pi", "#pi^{+} reconstructed p_{T} TPC", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TPC_aPi", "#pi^{-} reconstructed p_{T} TPC", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TPC_Pr", "p reconstructed p_{T} TPC", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TPC_aPr", "#bar{p} reconstructed p_{T} TPC", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TPC_De", "d reconstructed p_{T} TPC", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TPC_aDe", "#bar{d} reconstructed p_{T} TPC", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TPC_Tr", "t reconstructed p_{T} TPC", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TPC_aTr", "#bar{t} reconstructed p_{T} TPC", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TPC_He3", "^{3}He reconstructed p_{T} TPC", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TPC_aHe3", "^{3}#bar{He} reconstructed p_{T} TPC", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TPC_He4", "^{4}He reconstructed p_{T} TPC", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TPC_aHe4", "^{4}#bar{He} reconstructed p_{T} TPC", HistType::kTH1F, {ptAxis}); - - MC_eff.add("histPt_TOF_Pi", "#pi^{+} reconstructed p_{T} TOF", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TOF_aPi", "#pi^{-} reconstructed p_{T} TOF", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TOF_Pr", "p reconstructed p_{T} TOF", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TOF_aPr", "#bar{p} reconstructed p_{T} TOF", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TOF_De", "d reconstructed p_{T} TOF", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TOF_aDe", "#bar{d} reconstructed p_{T} TOF", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TOF_Tr", "t reconstructed p_{T} TOF", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TOF_aTr", "#bar{t} reconstructed p_{T} TOF", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TOF_He3", "^{3}He reconstructed p_{T} TOF", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TOF_aHe3", "^{3}#bar{He} reconstructed p_{T} TOF", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TOF_He4", "^{4}He reconstructed p_{T} TOF", HistType::kTH1F, {ptAxis}); - MC_eff.add("histPt_TOF_aHe4", "^{4}#bar{He} reconstructed p_{T} TOF", HistType::kTH1F, {ptAxis}); + MC_recon_reg.add("histTpcNsigmaDataPi", "TPC nSigma (#pi^{+})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); + MC_recon_reg.add("histTpcNsigmaDataaPi", "TPC nSigma (#pi^{-})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); + MC_recon_reg.add("histTpcNsigmaDataPr", "TPC nSigma (p)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{p}"}}); + MC_recon_reg.add("histTpcNsigmaDataaPr", "TPC nSigma (#bar{p})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{p}"}}); + MC_recon_reg.add("histTpcNsigmaDataDe", "TPC nSigma (d)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{d}"}}); + MC_recon_reg.add("histTpcNsigmaDataaDe", "TPC nSigma (#bar{d})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{d}"}}); + MC_recon_reg.add("histTpcNsigmaDataTr", "TPC nSigma (t)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{t}"}}); + MC_recon_reg.add("histTpcNsigmaDataaTr", "TPC nSigma (#bar{t})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{t}"}}); + MC_recon_reg.add("histTpcNsigmaDataHe", "TPC nSigma (^{3}He)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{He-3}"}}); + MC_recon_reg.add("histTpcNsigmaDataaHe", "TPC nSigma (^{3}#bar{He})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{He-3}"}}); + MC_recon_reg.add("histTpcNsigmaDataAl", "TPC nSigma (^{4}He)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{He-4}"}}); + MC_recon_reg.add("histTpcNsigmaDataaAl", "TPC nSigma (^{4}#bar{He})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{He-4}"}}); + MC_recon_reg.add("histTofNsigmaDataPi", "TOF nSigma (#pi^{+})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); + MC_recon_reg.add("histTofNsigmaDataaPi", "TOF nSigma (#pi^{-})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); + MC_recon_reg.add("histTofNsigmaDataPr", "TOF nSigma (p)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{p}"}}); + MC_recon_reg.add("histTofNsigmaDataaPr", "TOF nSigma (#bar{p})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{p}"}}); + MC_recon_reg.add("histTofNsigmaDataDe", "TOF nSigma (d)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{d}"}}); + MC_recon_reg.add("histTofNsigmaDataaDe", "TOF nSigma (#bar{d})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{d}"}}); + MC_recon_reg.add("histTofNsigmaDataTr", "TOF nSigma (t)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{t}"}}); + MC_recon_reg.add("histTofNsigmaDataaTr", "TOF nSigma (#bar{t})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{t}"}}); + MC_recon_reg.add("histTofNsigmaDataHe", "TOF nSigma (^{3}He)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{^{3}He}"}}); + MC_recon_reg.add("histTofNsigmaDataaHe", "TOF nSigma (^{3}#bar{He})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{^{3}He}"}}); + MC_recon_reg.add("histTofNsigmaDataAl", "TOF nSigma (^{4}He)", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{^{4}He}"}}); + MC_recon_reg.add("histTofNsigmaDataaAl", "TOF nSigma (^{4}#bar{He})", HistType::kTH2F, {pAxis, {160, -20., +20., "n#sigma_{^{4}He}"}}); + + MC_DCA.add("histEta", "#eta", HistType::kTH2F, {{204, -2.01, 2.01}, PDGBINNING}); + MC_DCA.add("histDCA_prim", "DCA xy", HistType::kTH3F, {ptAxis, {1000, -2.0, 2.0, "dca"}, PDGBINNING}); + MC_DCA.add("histDCAz_prim", "DCA z", HistType::kTH3F, {ptAxis, {1000, -2.0, 2.0, "dca"}, PDGBINNING}); + MC_DCA.add("histDCA_weak", "DCA xy", HistType::kTH3F, {ptAxis, {1000, -2.0, 2.0, "dca"}, PDGBINNING}); + MC_DCA.add("histDCAz_weak", "DCA z", HistType::kTH3F, {ptAxis, {1000, -2.0, 2.0, "dca"}, PDGBINNING}); + MC_DCA.add("histDCA_mat", "DCA xy", HistType::kTH3F, {ptAxis, {1000, -2.0, 2.0, "dca"}, PDGBINNING}); + MC_DCA.add("histDCAz_mat", "DCA z", HistType::kTH3F, {ptAxis, {1000, -2.0, 2.0, "dca"}, PDGBINNING}); } + // particle configurables + Configurable do_pion{"do_pion", false, "fill pion histograms"}; + Configurable do_proton{"do_proton", false, "fill proton histograms"}; + Configurable do_deuteron{"do_deuteron", false, "fill deuteron histograms"}; + Configurable do_triton{"do_triton", false, "fill triton histograms"}; + Configurable do_He3{"do_He3", false, "fill Helium-3 histograms"}; + Configurable do_He4{"do_He4", false, "fill Helium-4 histograms"}; + // Configurables Configurable yMin{"yMin", -0.5, "Maximum rapidity"}; Configurable yMax{"yMax", 0.5, "Minimum rapidity"}; - Configurable pTmin{"pTmin", 0.1f, "min pT"}; - Configurable pTmax{"pTmax", 1e+10f, "max pT"}; - + Configurable p_min{"p_min", 0.1f, "min track.pt()"}; + Configurable p_max{"p_max", 1e+10f, "max track.pt()"}; Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; - Configurable cfgCutEta{"cfgCutEta", 0.8f, "Eta range for tracks"}; + Configurable cfgCutEta{"cfgCutEta", 0.9f, "Eta range for tracks"}; Configurable nsigmacutLow{"nsigmacutLow", -3.0, "Value of the Nsigma cut"}; Configurable nsigmacutHigh{"nsigmacutHigh", +3.0, "Value of the Nsigma cut"}; Configurable minCentrality{"minCentrality", 0.0, "min Centrality used"}; @@ -473,216 +502,322 @@ struct NucleiHistTask { Configurable enable_Centrality_cut_global{"enable_Centrality_cut_global", true, "use Centrality cut"}; // Replacement for globalTrack filter - Configurable minReqClusterITS{"minReqClusterITS", 1.0, "min number of clusters required in ITS"}; // ITS_nCls - Configurable minReqClusterITSib{"minReqClusterITSib", 1.0, "min number of clusters required in ITS inner barrel"}; // ITS_nCls - Configurable minTPCnClsFound{"minTPCnClsFound", 0.0f, "min number of crossed rows TPC"}; // TPC_nCls_found - Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 70.0f, "min number of crossed rows TPC"}; // TPC_nCls_crossed_Rows - Configurable minRatioCrossedRowsTPC{"minRatioCrossedRowsTPC", 0.8f, "min ratio of crossed rows over findable clusters TPC"}; // TPC_crossed_Rows_over_findable_Cls_min - Configurable maxRatioCrossedRowsTPC{"maxRatioCrossedRowsTPC", 1.5f, "max ratio of crossed rows over findable clusters TPC"}; // TPC_crossed_Rows_over_findable_Cls_max - Configurable maxChi2ITS{"maxChi2ITS", 36.0f, "max chi2 per cluster ITS"}; - Configurable maxChi2TPC{"maxChi2TPC", 4.0f, "max chi2 per cluster TPC"}; - Configurable maxDCA_XY{"maxDCA_XY", 0.5f, "max DCA to vertex xy"}; + Configurable requireITS{"requireITS", true, "Additional cut on the ITS requirement"}; + Configurable requireTPC{"requireTPC", true, "Additional cut on the TPC requirement"}; + Configurable passedITSRefit{"passedITSRefit", true, "Additional cut on the ITS refit requirement"}; + Configurable passedTPCRefit{"passedTPCRefit", true, "Additional cut on the TPC refit requirement"}; + Configurable minReqClusterITS{"minReqClusterITS", 1.0, "min number of clusters required in ITS"}; + Configurable minReqClusterITSib{"minReqClusterITSib", 1.0, "min number of clusters required in ITS inner barrel"}; + Configurable minTPCnClsFound{"minTPCnClsFound", 0.0f, "min number of crossed rows TPC"}; + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 70.0f, "min number of crossed rows TPC"}; + Configurable minRatioCrossedRowsTPC{"minRatioCrossedRowsTPC", 0.8f, "min ratio of crossed rows over findable clusters TPC"}; + Configurable maxRatioCrossedRowsTPC{"maxRatioCrossedRowsTPC", 2.0f, "max ratio of crossed rows over findable clusters TPC"}; + Configurable maxChi2PerClusterTPC{"maxChi2PerClusterTPC", 4.f, "Cut on the maximum value of the chi2 per cluster in the TPC"}; + Configurable minChi2PerClusterTPC{"minChi2PerClusterTPC", 0.5f, "Cut on the minimum value of the chi2 per cluster in the TPC"}; + Configurable maxChi2PerClusterITS{"maxChi2PerClusterITS", 36.f, "Cut on the maximum value of the chi2 per cluster in the ITS"}; + // Configurable maxDCA_XY{"maxDCA_XY", 0.5f, "max DCA to vertex xy"}; + Configurable maxDcaXYFactor{"maxDcaXYFactor", 0.5f, "DCA xy factor"}; Configurable maxDCA_Z{"maxDCA_Z", 2.0f, "max DCA to vertex z"}; - Configurable lastRequiredTrdCluster{"lastRequiredTrdCluster", 5, "Last cluster to required in TRD for track selection. -1 does not require any TRD cluster"}; - + Configurable lastRequiredTrdCluster{"lastRequiredTrdCluster", -1, "Last cluster to required in TRD for track selection. -1 does not require any TRD cluster"}; + Configurable requireGoldenChi2{"requireGoldenChi2", false, "Enable the requirement of GoldenChi2"}; Configurable event_selection_sel8{"event_selection_sel8", true, "Enable sel8 event selection"}; + Configurable event_selection_MC_sel8{"event_selection_MC_sel8", true, "Enable sel8 event selection in MC processing"}; + Configurable require_PhysicalPrimary_MC_reco{"require_PhysicalPrimary_MC_reco", true, "Enable PhysicalPrimary selection in reconstructed MC processing"}; + Configurable require_PhysicalPrimary_MC_gen{"require_PhysicalPrimary_MC_gen", true, "Enable PhysicalPrimary selection in generated MC processing"}; + Configurable removeITSROFrameBorder{"removeITSROFrameBorder", false, "Remove TF border"}; + Configurable removeNoSameBunchPileup{"removeNoSameBunchPileup", false, "Remove TF border"}; + Configurable requireIsGoodZvtxFT0vsPV{"requireIsGoodZvtxFT0vsPV", false, "Remove TF border"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "Remove TF border"}; + Configurable removeNoTimeFrameBorder{"removeNoTimeFrameBorder", false, "Remove TF border"}; + + TF1* Particle_Tpc_nSigma_shift = 0; + Configurable enable_pT_shift_tpc_nSigma{"enable_pT_shift_tpc_nSigma", false, "Enable Data TPC nSigma recentering by TF1"}; + Configurable> parShiftPt{"parShiftPt", {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, "Parameters for pT shift."}; + + TF1* Pion_Tpc_nSigma_shift = 0; + TF1* Proton_Tpc_nSigma_shift = 0; + TF1* Deuteron_Tpc_nSigma_shift = 0; + TF1* Triton_Tpc_nSigma_shift = 0; + TF1* He3_Tpc_nSigma_shift = 0; + TF1* He4_Tpc_nSigma_shift = 0; + + Configurable enable_pT_shift_pion_tpc_nSigma{"enable_pT_shift_pion_tpc_nSigma", false, "Enable MC Pi plus TPC nSigma recentering by TF1"}; + Configurable enable_pT_shift_proton_tpc_nSigma{"enable_pT_shift_proton_tpc_nSigma", false, "Enable MC Proton TPC nSigma recentering by TF1"}; + Configurable enable_pT_shift_deuteron_tpc_nSigma{"enable_pT_shift_deuteron_tpc_nSigma", false, "Enable MC Deuteron TPC nSigma recentering by TF1"}; + Configurable enable_pT_shift_triton_tpc_nSigma{"enable_pT_shift_triton_tpc_nSigma", false, "Enable MC Triton TPC nSigma recentering by TF1"}; + Configurable enable_pT_shift_He3_tpc_nSigma{"enable_pT_shift_He3_tpc_nSigma", false, "Enable MC Helium-3 TPC nSigma recentering by TF1"}; + Configurable enable_pT_shift_He4_tpc_nSigma{"enable_pT_shift_He4_tpc_nSigma", false, "Enable MC Helium-4 TPC nSigma recentering by TF1"}; + Configurable> parShiftPtPion{"parShiftPtPion", {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, "MC Parameters for Pi plus pT shift."}; + Configurable> parShiftPtProton{"parShiftPtProton", {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, "MC Parameters for Proton pT shift."}; + Configurable> parShiftPtDeuteron{"parShiftPtDeuteron", {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, "MC Parameters for Deuteron pT shift."}; + Configurable> parShiftPtTriton{"parShiftPtTriton", {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, "MC Parameters for Triton pT shift."}; + Configurable> parShiftPtHe3{"parShiftPtHe3", {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, "MC Parameters for Helium-3 pT shift."}; + Configurable> parShiftPtHe4{"parShiftPtHe4", {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, "MC Parameters for Alpha pT shift."}; + + //*********************************************************************************** + + template + bool isEventSelected(CollisionType const& collision) + { + if (removeITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) + return false; + if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) + return false; + if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + return false; + if (requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) + return false; + if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + return false; + return true; + } - Configurable enable_PVcontributor_global{"enable_PVcontributor_global", true, "is PV contributor (global)"}; - Configurable enable_PVcontributor_pion{"enable_PVcontributor_pion", true, "is PV contributor (global)"}; - Configurable enable_PVcontributor_antipion{"enable_PVcontributor_antipion", true, "is PV contributor (global)"}; - Configurable enable_PVcontributor_proton{"enable_PVcontributor_proton", true, "is PV contributor (global)"}; - Configurable enable_PVcontributor_antiproton{"enable_PVcontributor_antiproton", true, "is PV contributor (global)"}; - Configurable enable_PVcontributor_deuteron{"enable_PVcontributor_deuteron", true, "is PV contributor (global)"}; - Configurable enable_PVcontributor_antideuteron{"enable_PVcontributor_antideuteron", true, "is PV contributor (global)"}; - Configurable enable_PVcontributor_triton{"enable_PVcontributor_triton", true, "is PV contributor (global)"}; - Configurable enable_PVcontributor_antitriton{"enable_PVcontributor_antitriton", true, "is PV contributor (global)"}; - Configurable enable_PVcontributor_Helium3{"enable_PVcontributor_Helium3", true, "is PV contributor (global)"}; - Configurable enable_PVcontributor_antiHelium3{"enable_PVcontributor_antiHelium3", true, "is PV contributor (global)"}; - Configurable enable_PVcontributor_Helium4{"enable_PVcontributor_Helium4", true, "is PV contributor (global)"}; - Configurable enable_PVcontributor_antiHelium4{"enable_PVcontributor_antiHelium4", true, "is PV contributor (global)"}; + //*********************************************************************************** template - void fillHistograms(const CollisionType& event, const TracksType& tracks) + void fillHistograms_spectra(const CollisionType& event, const TracksType& tracks) { - - // collision process loop - bool keepEvent_pi = kFALSE; - bool keepEvent_p = kFALSE; - bool keepEvent_d = kFALSE; - bool keepEvent_t = kFALSE; - bool keepEvent_He3 = kFALSE; - bool keepEvent_He4 = kFALSE; - - bool keepEvent_antipi = kFALSE; - bool keepEvent_antip = kFALSE; - bool keepEvent_antid = kFALSE; - bool keepEvent_antit = kFALSE; - bool keepEvent_antiHe3 = kFALSE; - bool keepEvent_antiHe4 = kFALSE; - if (event_selection_sel8 && event.sel8()) { spectra_reg.fill(HIST("histRecVtxZData"), event.posZ()); } - if (!event_selection_sel8) { spectra_reg.fill(HIST("histRecVtxZData"), event.posZ()); } + if (!isEventSelected(event)) + return; - for (auto track : tracks) { // start loop over tracks + for (auto track : tracks) { // start loop over all tracks - if (event_selection_sel8 && !event.sel8()) { + histTrackcuts_data_spectra->AddBinContent(1); + if (event_selection_sel8 && !event.sel8()) continue; - } - - float TPCnumberClsFound = track.tpcNClsFound(); - float TPC_nCls_Crossed_Rows = track.tpcNClsCrossedRows(); - float RatioCrossedRowsOverFindableTPC = track.tpcCrossedRowsOverFindableCls(); - float Chi2perClusterTPC = track.tpcChi2NCl(); - float Chi2perClusterITS = track.itsChi2NCl(); + histTrackcuts_data_spectra->AddBinContent(2); if (track.sign() > 0) { spectra_reg.fill(HIST("histDcaVsPtData_particle"), track.pt(), track.dcaXY()); spectra_reg.fill(HIST("histDcaZVsPtData_particle"), track.pt(), track.dcaZ()); } - if (track.sign() < 0) { spectra_reg.fill(HIST("histDcaVsPtData_antiparticle"), track.pt(), track.dcaXY()); spectra_reg.fill(HIST("histDcaZVsPtData_antiparticle"), track.pt(), track.dcaZ()); } + spectra_reg.fill(HIST("histNClusterTPC"), track.pt(), track.tpcNClsCrossedRows()); + spectra_reg.fill(HIST("histNClusterITS"), track.pt(), track.itsNCls()); + spectra_reg.fill(HIST("histNClusterITSib"), track.pt(), track.itsNClsInnerBarrel()); + spectra_reg.fill(HIST("histChi2TPC"), track.pt(), track.tpcChi2NCl()); + spectra_reg.fill(HIST("histChi2ITS"), track.pt(), track.itsChi2NCl()); - if (TMath::Abs(track.dcaXY()) > maxDCA_XY || TMath::Abs(track.dcaZ()) > maxDCA_Z) { - continue; - } + float TPCnumberClsFound = track.tpcNClsFound(); + float TPC_nCls_Crossed_Rows = track.tpcNClsCrossedRows(); + float RatioCrossedRowsOverFindableTPC = track.tpcCrossedRowsOverFindableCls(); + float Chi2perClusterTPC = track.tpcChi2NCl(); + float Chi2perClusterITS = track.itsChi2NCl(); - if (TPCnumberClsFound < minTPCnClsFound || TPC_nCls_Crossed_Rows < minNCrossedRowsTPC || RatioCrossedRowsOverFindableTPC < minRatioCrossedRowsTPC || RatioCrossedRowsOverFindableTPC > maxRatioCrossedRowsTPC || Chi2perClusterTPC > maxChi2TPC || Chi2perClusterITS > maxChi2ITS || !(track.passedTPCRefit()) || !(track.passedITSRefit()) || (track.itsNClsInnerBarrel()) < minReqClusterITSib || (track.itsNCls()) < minReqClusterITS) { - continue; - } + bool insideDCAxy = (std::abs(track.dcaXY()) <= (maxDcaXYFactor.value * (0.0105f + 0.0350f / pow(track.pt(), 1.1f)))); - if (enable_PVcontributor_global && !(track.isPVContributor())) { + if (!(insideDCAxy) || TMath::Abs(track.dcaZ()) > maxDCA_Z) continue; - } - - // cut on rapidity - TLorentzVector lorentzVector_pion{}; - TLorentzVector lorentzVector_proton{}; - TLorentzVector lorentzVector_deuteron{}; - TLorentzVector lorentzVector_triton{}; - TLorentzVector lorentzVector_He3{}; - TLorentzVector lorentzVector_He4{}; - - lorentzVector_pion.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassPiPlus); - lorentzVector_proton.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassProton); - lorentzVector_deuteron.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassDeuteron); - lorentzVector_triton.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassTriton); - lorentzVector_He3.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassHelium3); - lorentzVector_He4.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassAlpha); - - if (lorentzVector_pion.Rapidity() < yMin || lorentzVector_pion.Rapidity() > yMax || - lorentzVector_proton.Rapidity() < yMin || lorentzVector_proton.Rapidity() > yMax || - lorentzVector_deuteron.Rapidity() < yMin || lorentzVector_deuteron.Rapidity() > yMax || - lorentzVector_triton.Rapidity() < yMin || lorentzVector_triton.Rapidity() > yMax || - lorentzVector_He3.Rapidity() < yMin || lorentzVector_He3.Rapidity() > yMax || - lorentzVector_He4.Rapidity() < yMin || lorentzVector_He4.Rapidity() > yMax) { + histTrackcuts_data_spectra->AddBinContent(3); + if (TPCnumberClsFound < minTPCnClsFound || TPC_nCls_Crossed_Rows < minNCrossedRowsTPC) continue; - } - - // fill QA histograms - float nSigmaPion = track.tpcNSigmaPi(); - float nSigmaProton = track.tpcNSigmaPr(); - float nSigmaDeut = track.tpcNSigmaDe(); - float nSigmaTriton = track.tpcNSigmaTr(); - float nSigmaHe3 = track.tpcNSigmaHe(); - float nSigmaHe4 = track.tpcNSigmaAl(); + histTrackcuts_data_spectra->AddBinContent(4); + if (RatioCrossedRowsOverFindableTPC < minRatioCrossedRowsTPC || RatioCrossedRowsOverFindableTPC > maxRatioCrossedRowsTPC) + continue; + histTrackcuts_data_spectra->AddBinContent(5); + if (Chi2perClusterTPC > maxChi2PerClusterTPC || Chi2perClusterTPC < minChi2PerClusterTPC || Chi2perClusterITS > maxChi2PerClusterITS) + continue; + histTrackcuts_data_spectra->AddBinContent(6); + if (!(track.passedTPCRefit())) + continue; + histTrackcuts_data_spectra->AddBinContent(7); + if (!(track.passedITSRefit())) + continue; + histTrackcuts_data_spectra->AddBinContent(8); + if ((track.itsNClsInnerBarrel()) < minReqClusterITSib || (track.itsNCls()) < minReqClusterITS) + continue; + histTrackcuts_data_spectra->AddBinContent(9); + if (track.pt() < p_min || track.pt() > p_max) + continue; + histTrackcuts_data_spectra->AddBinContent(10); + if ((requireITS && !(track.hasITS())) || (requireTPC && !(track.hasTPC()))) + continue; + histTrackcuts_data_spectra->AddBinContent(11); + if (requireGoldenChi2 && !(track.passedGoldenChi2())) + continue; + histTrackcuts_data_spectra->AddBinContent(12); spectra_reg.fill(HIST("histTpcSignalData"), track.pt() * track.sign(), track.tpcSignal()); - spectra_reg.fill(HIST("histNClusterTPC"), track.pt(), track.tpcNClsCrossedRows()); - spectra_reg.fill(HIST("histNClusterITS"), track.pt(), track.itsNCls()); - spectra_reg.fill(HIST("histNClusterITSib"), track.pt(), track.itsNClsInnerBarrel()); - spectra_reg.fill(HIST("histChi2TPC"), track.pt(), track.tpcChi2NCl()); - spectra_reg.fill(HIST("histChi2ITS"), track.pt(), track.itsChi2NCl()); + if (track.hasTOF()) { + spectra_reg.fill(HIST("histTOFm2"), track.pt(), track.mass() * track.mass()); + spectra_reg.fill(HIST("histTofSignalData"), track.pt() * track.sign(), track.beta()); + } + } + } - if (track.sign() > 0) { - pion_reg.fill(HIST("histTpcNsigmaData"), track.pt(), nSigmaPion); - proton_reg.fill(HIST("histTpcNsigmaData"), track.pt(), nSigmaProton); - deuteron_reg.fill(HIST("histTpcNsigmaData"), track.pt(), nSigmaDeut); - triton_reg.fill(HIST("histTpcNsigmaData"), track.pt(), nSigmaTriton); - Helium3_reg.fill(HIST("histTpcNsigmaData"), track.pt() * 2.0, nSigmaHe3); - Helium4_reg.fill(HIST("histTpcNsigmaData"), track.pt() * 2.0, nSigmaHe4); - - // fill TOF m^2 histogram - if (track.hasTOF()) { + //*********************************************************************************** - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } + template + void fillHistograms_particle(const CollisionType& event, const TracksType& tracks, const int Partilce_type) + { - Float_t TOFmass2 = ((track.mass()) * (track.mass())); + if (!isEventSelected(event)) + return; - spectra_reg.fill(HIST("histTOFm2"), track.pt(), TOFmass2); - } + if (enable_pT_shift_tpc_nSigma) { + Particle_Tpc_nSigma_shift = new TF1("Particle_Tpc_nSigma_shift", "[0] * TMath::Exp([1] + [2] * x) + [3] + [4] * x + [5] * x * x", 0.f, 14.f); + auto par = (std::vector)parShiftPt; + Particle_Tpc_nSigma_shift->SetParameters(par[0], par[1], par[2], par[3], par[4], par[5]); + } + for (auto track : tracks) { + + float TPCnSigma_particle = -100; + float TOFnSigma_particle = -100; + float momentum; + TLorentzVector lorentzVector_particle{}; + HistogramRegistry particle_reg; + HistogramRegistry aparticle_reg; + + switch (Partilce_type) { + case 0: // pi plus/minus + lorentzVector_particle.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassPiPlus); + TPCnSigma_particle = track.tpcNSigmaPi(); + TOFnSigma_particle = track.tofNSigmaPi(); + particle_reg = pion_reg; + aparticle_reg = apion_reg; + momentum = track.pt(); + break; + case 1: // (anti)proton + lorentzVector_particle.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassProton); + TPCnSigma_particle = track.tpcNSigmaPr(); + TOFnSigma_particle = track.tofNSigmaPr(); + particle_reg = proton_reg; + aparticle_reg = aproton_reg; + momentum = track.pt(); + break; + case 2: // (anti)deuteron + lorentzVector_particle.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassDeuteron); + TPCnSigma_particle = track.tpcNSigmaDe(); + TOFnSigma_particle = track.tofNSigmaDe(); + particle_reg = deuteron_reg; + aparticle_reg = adeuteron_reg; + momentum = track.pt(); + break; + case 3: // (anti)triton + lorentzVector_particle.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassTriton); + TPCnSigma_particle = track.tpcNSigmaTr(); + TOFnSigma_particle = track.tofNSigmaTr(); + particle_reg = triton_reg; + aparticle_reg = atriton_reg; + momentum = track.pt(); + break; + case 4: // (anti)Helium-3 + lorentzVector_particle.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassHelium3); + TPCnSigma_particle = track.tpcNSigmaHe(); + TOFnSigma_particle = track.tofNSigmaHe(); + particle_reg = Helium3_reg; + aparticle_reg = aHelium3_reg; + momentum = track.pt() * 2.0; + break; + case 5: // (anti)Helium-4 + lorentzVector_particle.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassAlpha); + TPCnSigma_particle = track.tpcNSigmaAl(); + TOFnSigma_particle = track.tofNSigmaAl(); + particle_reg = Helium4_reg; + aparticle_reg = aHelium4_reg; + momentum = track.pt() * 2.0; + break; + default: + continue; + break; } - if (track.sign() < 0) { - apion_reg.fill(HIST("histTpcNsigmaData"), track.pt(), nSigmaPion); - aproton_reg.fill(HIST("histTpcNsigmaData"), track.pt(), nSigmaProton); - adeuteron_reg.fill(HIST("histTpcNsigmaData"), track.pt(), nSigmaDeut); - atriton_reg.fill(HIST("histTpcNsigmaData"), track.pt(), nSigmaTriton); - aHelium3_reg.fill(HIST("histTpcNsigmaData"), track.pt() * 2.0, nSigmaHe3); - aHelium4_reg.fill(HIST("histTpcNsigmaData"), track.pt() * 2.0, nSigmaHe4); - - // fill TOF m^2 histogram - if (track.hasTOF()) { + if (enable_pT_shift_tpc_nSigma) { + float nSigma_shift = Particle_Tpc_nSigma_shift->Eval(momentum); + TPCnSigma_particle -= nSigma_shift; + } - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } + histTrackcuts_data_particle->AddBinContent(1); + if (event_selection_sel8 && !event.sel8()) + continue; + histTrackcuts_data_particle->AddBinContent(2); - Float_t TOFmass2 = ((track.mass()) * (track.mass())); + float TPCnumberClsFound = track.tpcNClsFound(); + float TPC_nCls_Crossed_Rows = track.tpcNClsCrossedRows(); + float RatioCrossedRowsOverFindableTPC = track.tpcCrossedRowsOverFindableCls(); + float Chi2perClusterTPC = track.tpcChi2NCl(); + float Chi2perClusterITS = track.itsChi2NCl(); + + if (lorentzVector_particle.Rapidity() < yMin || lorentzVector_particle.Rapidity() > yMax) + continue; + histTrackcuts_data_particle->AddBinContent(3); + if (TPCnumberClsFound < minTPCnClsFound || TPC_nCls_Crossed_Rows < minNCrossedRowsTPC) + continue; + histTrackcuts_data_particle->AddBinContent(4); + if (RatioCrossedRowsOverFindableTPC < minRatioCrossedRowsTPC || RatioCrossedRowsOverFindableTPC > maxRatioCrossedRowsTPC) + continue; + histTrackcuts_data_particle->AddBinContent(5); + if (Chi2perClusterTPC > maxChi2PerClusterTPC || Chi2perClusterTPC < minChi2PerClusterTPC || Chi2perClusterITS > maxChi2PerClusterITS) + continue; + histTrackcuts_data_particle->AddBinContent(6); + if (!(track.passedTPCRefit())) + continue; + histTrackcuts_data_particle->AddBinContent(7); + if (!(track.passedITSRefit())) + continue; + histTrackcuts_data_particle->AddBinContent(8); + if ((track.itsNClsInnerBarrel()) < minReqClusterITSib || (track.itsNCls()) < minReqClusterITS) + continue; + histTrackcuts_data_particle->AddBinContent(9); + if (momentum < p_min || momentum > p_max) + continue; + histTrackcuts_data_particle->AddBinContent(10); + if ((requireITS && !(track.hasITS())) || (requireTPC && !(track.hasTPC()))) + continue; + histTrackcuts_data_particle->AddBinContent(11); + if (requireGoldenChi2 && !(track.passedGoldenChi2())) + continue; - spectra_reg.fill(HIST("histTOFm2"), track.pt(), TOFmass2); + histTrackcuts_data_particle->AddBinContent(12); + + if (TPCnSigma_particle > nsigmacutLow && TPCnSigma_particle < nsigmacutHigh) { + if (track.sign() > 0) { + particle_reg.fill(HIST("histDcaVsPtData"), momentum, track.dcaXY()); + particle_reg.fill(HIST("histDcaZVsPtData"), momentum, track.dcaZ()); + } + if (track.sign() < 0) { + aparticle_reg.fill(HIST("histDcaVsPtData"), momentum, track.dcaXY()); + aparticle_reg.fill(HIST("histDcaZVsPtData"), momentum, track.dcaZ()); } } - //************** check offline-trigger (skimming) condidition Pion ******************* + bool insideDCAxy = (std::abs(track.dcaXY()) <= (maxDcaXYFactor.value * (0.0105f + 0.0350f / pow(momentum, 1.1f)))); - if (nSigmaPion > nsigmacutLow && nSigmaPion < nsigmacutHigh) { + if (!(insideDCAxy) || TMath::Abs(track.dcaZ()) > maxDCA_Z) + continue; + histTrackcuts_data_particle->AddBinContent(13); - if (enable_PVcontributor_pion && !(track.isPVContributor())) { - continue; - } + //******* Fill particle histograms *********** + if (track.sign() > 0) { + particle_reg.fill(HIST("histTpcNsigmaData"), momentum, TPCnSigma_particle); + } - if (track.sign() > 0) { - keepEvent_pi = kTRUE; + if (track.sign() < 0) { + aparticle_reg.fill(HIST("histTpcNsigmaData"), momentum, TPCnSigma_particle); + } - pion_reg.fill(HIST("histDcaVsPtData"), track.pt(), track.dcaXY()); - pion_reg.fill(HIST("histDcaZVsPtData"), track.pt(), track.dcaZ()); - pion_reg.fill(HIST("histTpcSignalData"), track.pt(), track.tpcSignal()); - pion_reg.fill(HIST("histNClusterTPC"), track.pt(), track.tpcNClsFound()); - pion_reg.fill(HIST("histNClusterITS"), track.pt(), track.itsNCls()); - pion_reg.fill(HIST("histNClusterITSib"), track.pt(), track.itsNClsInnerBarrel()); - pion_reg.fill(HIST("histChi2TPC"), track.pt(), track.tpcChi2NCl()); - pion_reg.fill(HIST("histChi2ITS"), track.pt(), track.itsChi2NCl()); + if (TPCnSigma_particle > nsigmacutLow && TPCnSigma_particle < nsigmacutHigh) { - if (track.hasTOF()) { + if (track.sign() > 0) { + particle_reg.fill(HIST("histDcaVsPtData_after_cut"), momentum, track.dcaXY()); + particle_reg.fill(HIST("histDcaZVsPtData_after_cut"), momentum, track.dcaZ()); + particle_reg.fill(HIST("histTpcSignalData"), momentum, track.tpcSignal()); + particle_reg.fill(HIST("histNClusterTPC"), momentum, track.tpcNClsFound()); + particle_reg.fill(HIST("histNClusterITS"), momentum, track.itsNCls()); + particle_reg.fill(HIST("histNClusterITSib"), momentum, track.itsNClsInnerBarrel()); + particle_reg.fill(HIST("histChi2TPC"), momentum, track.tpcChi2NCl()); + particle_reg.fill(HIST("histChi2ITS"), momentum, track.itsChi2NCl()); + if (track.hasTOF()) { if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { int lastLayer = 0; for (int l = 7; l >= 0; l--) { @@ -691,38 +826,28 @@ struct NucleiHistTask { break; } } - if (lastLayer < lastRequiredTrdCluster) { + if (lastLayer < lastRequiredTrdCluster) continue; - } } - Float_t TOFmass2 = ((track.mass()) * (track.mass())); Float_t beta = track.beta(); - - pion_reg.fill(HIST("histTOFm2"), track.pt(), TOFmass2); - pion_reg.fill(HIST("histTofSignalData"), track.pt(), beta); - pion_reg.fill(HIST("histTofNsigmaData"), track.pt(), track.tofNSigmaPi()); + particle_reg.fill(HIST("histTOFm2"), momentum, TOFmass2); + particle_reg.fill(HIST("histTofSignalData"), momentum, beta); + particle_reg.fill(HIST("histTofNsigmaData"), momentum, TOFnSigma_particle); } } - if (enable_PVcontributor_antipion && !(track.isPVContributor())) { - continue; - } - if (track.sign() < 0) { - keepEvent_antipi = kTRUE; - - apion_reg.fill(HIST("histDcaVsPtData"), track.pt(), track.dcaXY()); - apion_reg.fill(HIST("histDcaZVsPtData"), track.pt(), track.dcaZ()); - apion_reg.fill(HIST("histTpcSignalData"), track.pt(), track.tpcSignal()); - apion_reg.fill(HIST("histNClusterTPC"), track.pt(), track.tpcNClsFound()); - apion_reg.fill(HIST("histNClusterITS"), track.pt(), track.itsNCls()); - apion_reg.fill(HIST("histNClusterITSib"), track.pt(), track.itsNClsInnerBarrel()); - apion_reg.fill(HIST("histChi2TPC"), track.pt(), track.tpcChi2NCl()); - apion_reg.fill(HIST("histChi2ITS"), track.pt(), track.itsChi2NCl()); + aparticle_reg.fill(HIST("histDcaVsPtData_after_cut"), momentum, track.dcaXY()); + aparticle_reg.fill(HIST("histDcaZVsPtData_after_cut"), momentum, track.dcaZ()); + aparticle_reg.fill(HIST("histTpcSignalData"), momentum, track.tpcSignal()); + aparticle_reg.fill(HIST("histNClusterTPC"), momentum, track.tpcNClsFound()); + aparticle_reg.fill(HIST("histNClusterITS"), momentum, track.itsNCls()); + aparticle_reg.fill(HIST("histNClusterITSib"), momentum, track.itsNClsInnerBarrel()); + aparticle_reg.fill(HIST("histChi2TPC"), momentum, track.tpcChi2NCl()); + aparticle_reg.fill(HIST("histChi2ITS"), momentum, track.itsChi2NCl()); if (track.hasTOF()) { - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { int lastLayer = 0; for (int l = 7; l >= 0; l--) { @@ -731,125 +856,182 @@ struct NucleiHistTask { break; } } - if (lastLayer < lastRequiredTrdCluster) { + if (lastLayer < lastRequiredTrdCluster) continue; - } } - Float_t TOFmass2 = ((track.mass()) * (track.mass())); Float_t beta = track.beta(); - - apion_reg.fill(HIST("histTOFm2"), track.pt(), TOFmass2); - apion_reg.fill(HIST("histTofSignalData"), track.pt(), beta); - apion_reg.fill(HIST("histTofNsigmaData"), track.pt(), track.tofNSigmaPi()); + aparticle_reg.fill(HIST("histTOFm2"), momentum, TOFmass2); + aparticle_reg.fill(HIST("histTofSignalData"), momentum, beta); + aparticle_reg.fill(HIST("histTofNsigmaData"), momentum, TOFnSigma_particle); } } + } + } + } - if (track.hasTOF()) { + //*********************************************************************************** - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } + template + void fillHistograms_particle_cent(const CollisionType& event, const TracksType& tracks, const int Partilce_type) + { + if (!isEventSelected(event)) + return; - spectra_reg.fill(HIST("histTofSignalData"), track.pt() * track.sign(), track.beta()); - } - } + if (enable_pT_shift_tpc_nSigma) { + Particle_Tpc_nSigma_shift = new TF1("Particle_Tpc_nSigma_shift", "[0] * TMath::Exp([1] + [2] * x) + [3] + [4] * x + [5] * x * x", 0.f, 14.f); + auto par = (std::vector)parShiftPt; + Particle_Tpc_nSigma_shift->SetParameters(par[0], par[1], par[2], par[3], par[4], par[5]); + } - //************** check offline-trigger (skimming) condidition Proton ******************* + if (event_selection_sel8 && event.sel8()) + spectra_reg.fill(HIST("histCentrality"), event.centFT0C()); + if (!event_selection_sel8) + spectra_reg.fill(HIST("histCentrality"), event.centFT0C()); - if (nSigmaProton > nsigmacutLow && nSigmaProton < nsigmacutHigh) { + for (auto track : tracks) { + if ((event_selection_sel8 && !event.sel8()) || (enable_Centrality_cut_global && (event.centFT0C() < minCentrality) && (event.centFT0C() > maxCentrality))) + continue; - if (enable_PVcontributor_proton && !(track.isPVContributor())) { + float TPCnSigma_particle = -100; + float TOFnSigma_particle = -100; + float momentum; + TLorentzVector lorentzVector_particle{}; + HistogramRegistry particle_reg; + HistogramRegistry aparticle_reg; + + switch (Partilce_type) { + case 0: // pi plus/minus + lorentzVector_particle.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassPiPlus); + TPCnSigma_particle = track.tpcNSigmaPi(); + TOFnSigma_particle = track.tofNSigmaPi(); + particle_reg = pion_reg; + aparticle_reg = apion_reg; + momentum = track.pt(); + break; + case 1: // (anti)proton + lorentzVector_particle.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassProton); + TPCnSigma_particle = track.tpcNSigmaPr(); + TOFnSigma_particle = track.tofNSigmaPr(); + particle_reg = proton_reg; + aparticle_reg = aproton_reg; + momentum = track.pt(); + break; + case 2: // (anti)deuteron + lorentzVector_particle.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassDeuteron); + TPCnSigma_particle = track.tpcNSigmaDe(); + TOFnSigma_particle = track.tofNSigmaDe(); + particle_reg = deuteron_reg; + aparticle_reg = adeuteron_reg; + momentum = track.pt(); + break; + case 3: // (anti)triton + lorentzVector_particle.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassTriton); + TPCnSigma_particle = track.tpcNSigmaTr(); + TOFnSigma_particle = track.tofNSigmaTr(); + particle_reg = triton_reg; + aparticle_reg = atriton_reg; + momentum = track.pt(); + break; + case 4: // (anti)Helium-3 + lorentzVector_particle.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassHelium3); + TPCnSigma_particle = track.tpcNSigmaHe(); + TOFnSigma_particle = track.tofNSigmaHe(); + particle_reg = Helium3_reg; + aparticle_reg = aHelium3_reg; + momentum = track.pt() * 2.0; + break; + case 5: // (anti)Helium-4 + lorentzVector_particle.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassAlpha); + TPCnSigma_particle = track.tpcNSigmaAl(); + TOFnSigma_particle = track.tofNSigmaAl(); + particle_reg = Helium4_reg; + aparticle_reg = aHelium4_reg; + momentum = track.pt() * 2.0; + break; + default: continue; - } - - if (track.sign() > 0) { - keepEvent_p = kTRUE; - - proton_reg.fill(HIST("histDcaVsPtData"), track.pt(), track.dcaXY()); - proton_reg.fill(HIST("histDcaZVsPtData"), track.pt(), track.dcaZ()); - proton_reg.fill(HIST("histTpcSignalData"), track.pt(), track.tpcSignal()); - proton_reg.fill(HIST("histNClusterTPC"), track.pt(), track.tpcNClsFound()); - proton_reg.fill(HIST("histNClusterITS"), track.pt(), track.itsNCls()); - proton_reg.fill(HIST("histNClusterITSib"), track.pt(), track.itsNClsInnerBarrel()); - proton_reg.fill(HIST("histChi2TPC"), track.pt(), track.tpcChi2NCl()); - proton_reg.fill(HIST("histChi2ITS"), track.pt(), track.itsChi2NCl()); + break; + } - if (track.hasTOF()) { + if (enable_pT_shift_tpc_nSigma) { + float nSigma_shift = Particle_Tpc_nSigma_shift->Eval(momentum); + TPCnSigma_particle -= nSigma_shift; + } - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } + spectra_reg.fill(HIST("histEtaWithOverFlow"), track.eta()); + spectra_reg.fill(HIST("histEta_cent"), event.centFT0C(), track.eta()); - Float_t TOFmass2 = ((track.mass()) * (track.mass())); - Float_t beta = track.beta(); + if ((event.centFT0C() > minCentrality) && (event.centFT0C() < maxCentrality)) { + spectra_reg.fill(HIST("histEta"), track.eta()); + } - proton_reg.fill(HIST("histTOFm2"), track.pt(), TOFmass2); - proton_reg.fill(HIST("histTofSignalData"), track.pt(), beta); - proton_reg.fill(HIST("histTofNsigmaData"), track.pt(), track.tofNSigmaPr()); - } - } + float TPCnumberClsFound = track.tpcNClsFound(); + float TPC_nCls_Crossed_Rows = track.tpcNClsCrossedRows(); + float RatioCrossedRowsOverFindableTPC = track.tpcCrossedRowsOverFindableCls(); + float Chi2perClusterTPC = track.tpcChi2NCl(); + float Chi2perClusterITS = track.itsChi2NCl(); - if (enable_PVcontributor_antiproton && !(track.isPVContributor())) { - continue; - } + if (lorentzVector_particle.Rapidity() < yMin || lorentzVector_particle.Rapidity() > yMax) + continue; - if (track.sign() < 0) { - keepEvent_antip = kTRUE; + bool insideDCAxy = (std::abs(track.dcaXY()) <= (maxDcaXYFactor.value * (0.0105f + 0.0350f / pow(momentum, 1.1f)))); - aproton_reg.fill(HIST("histDcaVsPtData"), track.pt(), track.dcaXY()); - aproton_reg.fill(HIST("histDcaZVsPtData"), track.pt(), track.dcaZ()); - aproton_reg.fill(HIST("histTpcSignalData"), track.pt(), track.tpcSignal()); - aproton_reg.fill(HIST("histNClusterTPC"), track.pt(), track.tpcNClsFound()); - aproton_reg.fill(HIST("histNClusterITS"), track.pt(), track.itsNCls()); - aproton_reg.fill(HIST("histNClusterITSib"), track.pt(), track.itsNClsInnerBarrel()); - aproton_reg.fill(HIST("histChi2TPC"), track.pt(), track.tpcChi2NCl()); - aproton_reg.fill(HIST("histChi2ITS"), track.pt(), track.itsChi2NCl()); + if (!(insideDCAxy) || TMath::Abs(track.dcaZ()) > maxDCA_Z) + continue; + if (TPCnumberClsFound < minTPCnClsFound || TPC_nCls_Crossed_Rows < minNCrossedRowsTPC) + continue; + if (RatioCrossedRowsOverFindableTPC < minRatioCrossedRowsTPC || RatioCrossedRowsOverFindableTPC > maxRatioCrossedRowsTPC) + continue; + if (Chi2perClusterTPC > maxChi2PerClusterTPC || Chi2perClusterTPC < minChi2PerClusterTPC || Chi2perClusterITS > maxChi2PerClusterITS) + continue; + if (!(track.passedTPCRefit())) + continue; + if (!(track.passedITSRefit())) + continue; + if ((track.itsNClsInnerBarrel()) < minReqClusterITSib || (track.itsNCls()) < minReqClusterITS) + continue; + if (momentum < p_min || momentum > p_max) + continue; + if ((requireITS && !(track.hasITS())) || (requireTPC && !(track.hasTPC()))) + continue; + if (requireGoldenChi2 && !(track.passedGoldenChi2())) + continue; - if (track.hasTOF()) { + if (track.sign() > 0) { + particle_reg.fill(HIST("histTpcNsigmaData_cent"), momentum, TPCnSigma_particle, event.centFT0C()); + if ((event.centFT0C() > minCentrality) && (event.centFT0C() < maxCentrality)) { + particle_reg.fill(HIST("histTpcNsigmaData_eta"), momentum, TPCnSigma_particle, track.eta()); + } - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; + if (track.hasTOF()) { + if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { + int lastLayer = 0; + for (int l = 7; l >= 0; l--) { + if (track.trdPattern() & (1 << l)) { + lastLayer = l; + break; } } + if (lastLayer < lastRequiredTrdCluster) + continue; + } + particle_reg.fill(HIST("histTofNsigmaData_cent"), momentum, TOFnSigma_particle, event.centFT0C()); + particle_reg.fill(HIST("histTofm2_cent"), momentum, track.mass() * track.mass(), event.centFT0C()); - Float_t TOFmass2 = ((track.mass()) * (track.mass())); - Float_t beta = track.beta(); - - aproton_reg.fill(HIST("histTOFm2"), track.pt(), TOFmass2); - aproton_reg.fill(HIST("histTofSignalData"), track.pt(), beta); - aproton_reg.fill(HIST("histTofNsigmaData"), track.pt(), track.tofNSigmaPr()); + if ((event.centFT0C() > minCentrality) && (event.centFT0C() < maxCentrality)) { + particle_reg.fill(HIST("histTofm2_eta"), momentum, track.mass() * track.mass(), track.eta()); + particle_reg.fill(HIST("histTofNsigmaData_eta"), momentum, TOFnSigma_particle, track.eta()); } } + } + if (track.sign() < 0) { + aparticle_reg.fill(HIST("histTpcNsigmaData_cent"), momentum, TPCnSigma_particle, event.centFT0C()); + if ((event.centFT0C() > minCentrality) && (event.centFT0C() < maxCentrality)) { + aparticle_reg.fill(HIST("histTpcNsigmaData_eta"), momentum, TPCnSigma_particle, track.eta()); + } if (track.hasTOF()) { - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { int lastLayer = 0; for (int l = 7; l >= 0; l--) { @@ -858,471 +1040,326 @@ struct NucleiHistTask { break; } } - if (lastLayer < lastRequiredTrdCluster) { + if (lastLayer < lastRequiredTrdCluster) continue; - } } + aparticle_reg.fill(HIST("histTofNsigmaData_cent"), momentum, TOFnSigma_particle, event.centFT0C()); + aparticle_reg.fill(HIST("histTofm2_cent"), momentum, track.mass() * track.mass(), event.centFT0C()); - spectra_reg.fill(HIST("histTofSignalData"), track.pt() * track.sign(), track.beta()); + if ((event.centFT0C() > minCentrality) && (event.centFT0C() < maxCentrality)) { + aparticle_reg.fill(HIST("histTofm2_eta"), momentum, track.mass() * track.mass(), track.eta()); + aparticle_reg.fill(HIST("histTofNsigmaData_eta"), momentum, TOFnSigma_particle, track.eta()); + } } } + } + } - //************** check offline-trigger (skimming) condidition Deuteron ******************* + //*********************************************************************************** - if (nSigmaDeut > nsigmacutLow && nSigmaDeut < nsigmacutHigh) { + Filter collisionFilter = (nabs(aod::collision::posZ) < cfgCutVertex); + Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta && requireGlobalTrackWoDCAInFilter()); - if (enable_PVcontributor_deuteron && !(track.isPVContributor())) { - continue; - } + using EventCandidates = soa::Filtered>; - if (track.sign() > 0) { - keepEvent_d = kTRUE; + using EventCandidatesCent = soa::Filtered>; - deuteron_reg.fill(HIST("histDcaVsPtData"), track.pt(), track.dcaXY()); - deuteron_reg.fill(HIST("histDcaZVsPtData"), track.pt(), track.dcaZ()); - deuteron_reg.fill(HIST("histTpcSignalData"), track.pt(), track.tpcSignal()); - deuteron_reg.fill(HIST("histNClusterTPC"), track.pt(), track.tpcNClsFound()); - deuteron_reg.fill(HIST("histNClusterITS"), track.pt(), track.itsNCls()); - deuteron_reg.fill(HIST("histNClusterITSib"), track.pt(), track.itsNClsInnerBarrel()); - deuteron_reg.fill(HIST("histChi2TPC"), track.pt(), track.tpcChi2NCl()); - deuteron_reg.fill(HIST("histChi2ITS"), track.pt(), track.itsChi2NCl()); + using TrackCandidates = soa::Filtered>; - if (track.hasTOF()) { + void processData(EventCandidates::iterator const& event, TrackCandidates const& tracks) + { + fillHistograms_spectra(event, tracks); + if (do_pion) + fillHistograms_particle(event, tracks, 0); // pion + if (do_proton) + fillHistograms_particle(event, tracks, 1); // proton + if (do_deuteron) + fillHistograms_particle(event, tracks, 2); // deuteron + if (do_triton) + fillHistograms_particle(event, tracks, 3); // triton + if (do_He3) + fillHistograms_particle(event, tracks, 4); // He3 + if (do_He4) + fillHistograms_particle(event, tracks, 5); // He4 + } + PROCESS_SWITCH(NucleiHistTask, processData, "process data", true); - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } - - Float_t TOFmass2 = ((track.mass()) * (track.mass())); - Float_t beta = track.beta(); - - deuteron_reg.fill(HIST("histTOFm2"), track.pt(), TOFmass2); - deuteron_reg.fill(HIST("histTofSignalData"), track.pt(), beta); - deuteron_reg.fill(HIST("histTofNsigmaData"), track.pt(), track.tofNSigmaDe()); - } - } - - if (enable_PVcontributor_antideuteron && !(track.isPVContributor())) { - continue; - } - - if (track.sign() < 0) { - keepEvent_antid = kTRUE; - - adeuteron_reg.fill(HIST("histDcaVsPtData"), track.pt(), track.dcaXY()); - adeuteron_reg.fill(HIST("histDcaZVsPtData"), track.pt(), track.dcaZ()); - adeuteron_reg.fill(HIST("histTpcSignalData"), track.pt(), track.tpcSignal()); - adeuteron_reg.fill(HIST("histNClusterTPC"), track.pt(), track.tpcNClsFound()); - adeuteron_reg.fill(HIST("histNClusterITS"), track.pt(), track.itsNCls()); - adeuteron_reg.fill(HIST("histNClusterITSib"), track.pt(), track.itsNClsInnerBarrel()); - adeuteron_reg.fill(HIST("histChi2TPC"), track.pt(), track.tpcChi2NCl()); - adeuteron_reg.fill(HIST("histChi2ITS"), track.pt(), track.itsChi2NCl()); - - if (track.hasTOF()) { - - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } - - Float_t TOFmass2 = ((track.mass()) * (track.mass())); - Float_t beta = track.beta(); - - adeuteron_reg.fill(HIST("histTOFm2"), track.pt(), TOFmass2); - adeuteron_reg.fill(HIST("histTofSignalData"), track.pt(), beta); - adeuteron_reg.fill(HIST("histTofNsigmaData"), track.pt(), track.tofNSigmaDe()); - } - } - - if (track.hasTOF()) { - - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } - - spectra_reg.fill(HIST("histTofSignalData"), track.pt() * track.sign(), track.beta()); - } - } - - //************** check offline-trigger (skimming) condidition Triton ******************* - - if (nSigmaTriton > nsigmacutLow && nSigmaTriton < nsigmacutHigh) { - - if (enable_PVcontributor_triton && !(track.isPVContributor())) { - continue; - } - - if (track.sign() > 0) { - keepEvent_t = kTRUE; - - triton_reg.fill(HIST("histDcaVsPtData"), track.pt(), track.dcaXY()); - triton_reg.fill(HIST("histDcaZVsPtData"), track.pt(), track.dcaZ()); - triton_reg.fill(HIST("histTpcSignalData"), track.pt(), track.tpcSignal()); - triton_reg.fill(HIST("histNClusterTPC"), track.pt(), track.tpcNClsFound()); - triton_reg.fill(HIST("histNClusterITS"), track.pt(), track.itsNCls()); - triton_reg.fill(HIST("histNClusterITSib"), track.pt(), track.itsNClsInnerBarrel()); - triton_reg.fill(HIST("histChi2TPC"), track.pt(), track.tpcChi2NCl()); - triton_reg.fill(HIST("histChi2ITS"), track.pt(), track.itsChi2NCl()); - - if (track.hasTOF()) { - - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } - - Float_t TOFmass2 = ((track.mass()) * (track.mass())); - Float_t beta = track.beta(); - - triton_reg.fill(HIST("histTOFm2"), track.pt(), TOFmass2); - triton_reg.fill(HIST("histTofSignalData"), track.pt(), beta); - triton_reg.fill(HIST("histTofNsigmaData"), track.pt(), track.tofNSigmaTr()); - } - } - - if (enable_PVcontributor_antitriton && !(track.isPVContributor())) { - continue; - } - - if (track.sign() < 0) { - keepEvent_antit = kTRUE; - - atriton_reg.fill(HIST("histDcaVsPtData"), track.pt(), track.dcaXY()); - atriton_reg.fill(HIST("histDcaZVsPtData"), track.pt(), track.dcaZ()); - atriton_reg.fill(HIST("histTpcSignalData"), track.pt(), track.tpcSignal()); - atriton_reg.fill(HIST("histNClusterTPC"), track.pt(), track.tpcNClsFound()); - atriton_reg.fill(HIST("histNClusterITS"), track.pt(), track.itsNCls()); - atriton_reg.fill(HIST("histNClusterITSib"), track.pt(), track.itsNClsInnerBarrel()); - atriton_reg.fill(HIST("histChi2TPC"), track.pt(), track.tpcChi2NCl()); - atriton_reg.fill(HIST("histChi2ITS"), track.pt(), track.itsChi2NCl()); - - if (track.hasTOF()) { + void processDataCent(EventCandidatesCent::iterator const& event, TrackCandidates const& tracks) + { + fillHistograms_spectra(event, tracks); + if (do_pion) + fillHistograms_particle(event, tracks, 0); // pion + if (do_proton) + fillHistograms_particle(event, tracks, 1); // proton + if (do_deuteron) + fillHistograms_particle(event, tracks, 2); // deuteron + if (do_triton) + fillHistograms_particle(event, tracks, 3); // triton + if (do_He3) + fillHistograms_particle(event, tracks, 4); // He3 + if (do_He4) + fillHistograms_particle(event, tracks, 5); // He4 + if (do_pion) + fillHistograms_particle_cent(event, tracks, 0); // pion + if (do_proton) + fillHistograms_particle_cent(event, tracks, 1); // proton + if (do_deuteron) + fillHistograms_particle_cent(event, tracks, 2); // deuteron + if (do_triton) + fillHistograms_particle_cent(event, tracks, 3); // triton + if (do_He3) + fillHistograms_particle_cent(event, tracks, 4); // He3 + if (do_He4) + fillHistograms_particle_cent(event, tracks, 5); // He4 + } + PROCESS_SWITCH(NucleiHistTask, processDataCent, "process data with centralities", false); - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } + //********************** MC **************************************** - Float_t TOFmass2 = ((track.mass()) * (track.mass())); - Float_t beta = track.beta(); - - atriton_reg.fill(HIST("histTOFm2"), track.pt(), TOFmass2); - atriton_reg.fill(HIST("histTofSignalData"), track.pt(), beta); - atriton_reg.fill(HIST("histTofNsigmaData"), track.pt(), track.tofNSigmaTr()); - } - } + void processMCgen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) + { + MC_gen_reg.fill(HIST("histGenVtxMC"), mcCollision.posZ()); + MC_gen_reg.fill(HIST("histCentrality"), mcCollision.impactParameter()); - if (track.hasTOF()) { + for (const auto& mcParticleGen : mcParticles) { + if (require_PhysicalPrimary_MC_gen && !mcParticleGen.isPhysicalPrimary()) + continue; + int pdgCode = mcParticleGen.pdgCode(); - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } + if (mcParticleGen.y() > yMax || mcParticleGen.y() < yMin) + continue; + if (mcParticleGen.eta() > cfgCutEta || mcParticleGen.eta() < -cfgCutEta) + continue; - spectra_reg.fill(HIST("histTofSignalData"), track.pt() * track.sign(), track.beta()); - } + int pdgbin = 0; + switch (pdgCode) { + case +211: + histPDG_gen->AddBinContent(1); + pdgbin = 0; + break; + case -211: + histPDG_gen->AddBinContent(2); + pdgbin = 1; + break; + case +321: + histPDG_gen->AddBinContent(3); + pdgbin = 2; + break; + case -321: + histPDG_gen->AddBinContent(4); + pdgbin = 3; + break; + case +2212: + histPDG_gen->AddBinContent(5); + pdgbin = 4; + break; + case -2212: + histPDG_gen->AddBinContent(6); + pdgbin = 5; + break; + case +1000010020: + histPDG_gen->AddBinContent(7); + pdgbin = 6; + break; + case -1000010020: + histPDG_gen->AddBinContent(8); + pdgbin = 7; + break; + case +1000010030: + histPDG_gen->AddBinContent(9); + pdgbin = 8; + break; + case -1000010030: + histPDG_gen->AddBinContent(10); + pdgbin = 9; + break; + case +1000020030: + histPDG_gen->AddBinContent(11); + pdgbin = 10; + break; + case -1000020030: + histPDG_gen->AddBinContent(12); + pdgbin = 11; + break; + case +1000020040: + histPDG_gen->AddBinContent(13); + pdgbin = 12; + break; + case -1000020040: + histPDG_gen->AddBinContent(14); + pdgbin = 13; + break; + default: + break; } - - //************** check offline-trigger (skimming) condidition Helium-3 ******************* - - if (nSigmaHe3 > nsigmacutLow && nSigmaHe3 < nsigmacutHigh) { - - if (enable_PVcontributor_Helium3 && !(track.isPVContributor())) { - continue; - } - - if (track.sign() > 0) { - keepEvent_He3 = kTRUE; - - Helium3_reg.fill(HIST("histDcaVsPtData"), track.pt() * 2.0, track.dcaXY()); - Helium3_reg.fill(HIST("histDcaZVsPtData"), track.pt() * 2.0, track.dcaZ()); - Helium3_reg.fill(HIST("histTpcSignalData"), track.pt() * 2.0, track.tpcSignal()); - Helium3_reg.fill(HIST("histNClusterTPC"), track.pt() * 2.0, track.tpcNClsFound()); - Helium3_reg.fill(HIST("histNClusterITS"), track.pt() * 2.0, track.itsNCls()); - Helium3_reg.fill(HIST("histNClusterITSib"), track.pt() * 2.0, track.itsNClsInnerBarrel()); - Helium3_reg.fill(HIST("histChi2TPC"), track.pt() * 2.0, track.tpcChi2NCl()); - Helium3_reg.fill(HIST("histChi2ITS"), track.pt() * 2.0, track.itsChi2NCl()); - - if (track.hasTOF()) { - - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } - - Float_t TOFmass2 = ((track.mass()) * (track.mass())); - Float_t beta = track.beta(); - - Helium3_reg.fill(HIST("histTOFm2"), track.pt() * 2.0, TOFmass2); - Helium3_reg.fill(HIST("histTofSignalData"), track.pt() * 2.0, beta); - Helium3_reg.fill(HIST("histTofNsigmaData"), track.pt() * 2.0, track.tofNSigmaHe()); - } - } - - if (enable_PVcontributor_antiHelium3 && !(track.isPVContributor())) { - continue; - } - - if (track.sign() < 0) { - keepEvent_antiHe3 = kTRUE; - aHelium3_reg.fill(HIST("histDcaVsPtData"), track.pt() * 2.0, track.dcaXY()); - aHelium3_reg.fill(HIST("histDcaZVsPtData"), track.pt() * 2.0, track.dcaZ()); - aHelium3_reg.fill(HIST("histTpcSignalData"), track.pt() * 2.0, track.tpcSignal()); - aHelium3_reg.fill(HIST("histNClusterTPC"), track.pt() * 2.0, track.tpcNClsFound()); - aHelium3_reg.fill(HIST("histNClusterITS"), track.pt() * 2.0, track.itsNCls()); - aHelium3_reg.fill(HIST("histNClusterITSib"), track.pt() * 2.0, track.itsNClsInnerBarrel()); - aHelium3_reg.fill(HIST("histChi2TPC"), track.pt() * 2.0, track.tpcChi2NCl()); - aHelium3_reg.fill(HIST("histChi2ITS"), track.pt() * 2.0, track.itsChi2NCl()); - - if (track.hasTOF()) { - - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } - - Float_t TOFmass2 = ((track.mass()) * (track.mass())); - Float_t beta = track.beta(); - - aHelium3_reg.fill(HIST("histTOFm2"), track.pt() * 2.0, TOFmass2); - aHelium3_reg.fill(HIST("histTofSignalData"), track.pt() * 2.0, beta); - aHelium3_reg.fill(HIST("histTofNsigmaData"), track.pt() * 2.0, track.tofNSigmaHe()); - } - } - - if (track.hasTOF()) { - - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } - - spectra_reg.fill(HIST("histTofSignalData"), track.pt() * 2.0 * track.sign(), track.beta()); - } + MC_gen_reg.fill(HIST("histEta"), mcParticleGen.eta(), pdgbin); + if ((pdgCode == 1000020030) || (pdgCode == -1000020030) || (pdgCode == 1000020040) || (pdgCode == -1000020040)) { + MC_gen_reg.fill(HIST("histPt"), mcParticleGen.pt() * 2.0, pdgbin); + } else { + MC_gen_reg.fill(HIST("histPt"), mcParticleGen.pt(), pdgbin); } - - //************** check offline-trigger (skimming) condidition Helium-4 ******************* - - if (nSigmaHe4 > nsigmacutLow && nSigmaHe4 < nsigmacutHigh) { - - if (enable_PVcontributor_Helium4 && !(track.isPVContributor())) { - continue; - } - - if (track.sign() > 0) { - keepEvent_He4 = kTRUE; - - Helium4_reg.fill(HIST("histDcaVsPtData"), track.pt() * 2.0, track.dcaXY()); - Helium4_reg.fill(HIST("histDcaZVsPtData"), track.pt() * 2.0, track.dcaZ()); - Helium4_reg.fill(HIST("histTpcSignalData"), track.pt() * 2.0, track.tpcSignal()); - Helium4_reg.fill(HIST("histNClusterTPC"), track.pt() * 2.0, track.tpcNClsFound()); - Helium4_reg.fill(HIST("histNClusterITS"), track.pt() * 2.0, track.itsNCls()); - Helium4_reg.fill(HIST("histNClusterITSib"), track.pt() * 2.0, track.itsNClsInnerBarrel()); - Helium4_reg.fill(HIST("histChi2TPC"), track.pt() * 2.0, track.tpcChi2NCl()); - Helium4_reg.fill(HIST("histChi2ITS"), track.pt() * 2.0, track.itsChi2NCl()); - - if (track.hasTOF()) { - - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } - - Float_t TOFmass2 = ((track.mass()) * (track.mass())); - Float_t beta = track.beta(); - - Helium4_reg.fill(HIST("histTOFm2"), track.pt() * 2.0, TOFmass2); - Helium4_reg.fill(HIST("histTofSignalData"), track.pt() * 2.0, beta); - Helium4_reg.fill(HIST("histTofNsigmaData"), track.pt() * 2.0, track.tofNSigmaAl()); - } - } - - if (enable_PVcontributor_antiHelium4 && !(track.isPVContributor())) { - continue; - } - - if (track.sign() < 0) { - keepEvent_antiHe4 = kTRUE; - aHelium4_reg.fill(HIST("histDcaVsPtData"), track.pt() * 2.0, track.dcaXY()); - aHelium4_reg.fill(HIST("histDcaZVsPtData"), track.pt() * 2.0, track.dcaZ()); - aHelium4_reg.fill(HIST("histTpcSignalData"), track.pt() * 2.0, track.tpcSignal()); - aHelium4_reg.fill(HIST("histNClusterTPC"), track.pt() * 2.0, track.tpcNClsFound()); - aHelium4_reg.fill(HIST("histNClusterITS"), track.pt() * 2.0, track.itsNCls()); - aHelium4_reg.fill(HIST("histNClusterITSib"), track.pt() * 2.0, track.itsNClsInnerBarrel()); - aHelium4_reg.fill(HIST("histChi2TPC"), track.pt() * 2.0, track.tpcChi2NCl()); - aHelium4_reg.fill(HIST("histChi2ITS"), track.pt() * 2.0, track.itsChi2NCl()); - - if (track.hasTOF()) { - - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } - - Float_t TOFmass2 = ((track.mass()) * (track.mass())); - Float_t beta = track.beta(); - - aHelium4_reg.fill(HIST("histTOFm2"), track.pt() * 2.0, TOFmass2); - aHelium4_reg.fill(HIST("histTofSignalData"), track.pt() * 2.0, beta); - aHelium4_reg.fill(HIST("histTofNsigmaData"), track.pt() * 2.0, track.tofNSigmaAl()); - } - } - - if (track.hasTOF()) { - - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } - - spectra_reg.fill(HIST("histTofSignalData"), track.pt() * 2.0 * track.sign(), track.beta()); - } - } - - } // end loop over tracks - - // fill trigger (skimming) results - pion_reg.fill(HIST("histKeepEventData"), keepEvent_pi); - apion_reg.fill(HIST("histKeepEventData"), keepEvent_antipi); - proton_reg.fill(HIST("histKeepEventData"), keepEvent_p); - aproton_reg.fill(HIST("histKeepEventData"), keepEvent_antip); - deuteron_reg.fill(HIST("histKeepEventData"), keepEvent_d); - adeuteron_reg.fill(HIST("histKeepEventData"), keepEvent_antid); - triton_reg.fill(HIST("histKeepEventData"), keepEvent_t); - atriton_reg.fill(HIST("histKeepEventData"), keepEvent_antit); - Helium3_reg.fill(HIST("histKeepEventData"), keepEvent_He3); - aHelium3_reg.fill(HIST("histKeepEventData"), keepEvent_antiHe3); - Helium4_reg.fill(HIST("histKeepEventData"), keepEvent_He4); - aHelium4_reg.fill(HIST("histKeepEventData"), keepEvent_antiHe4); + } } + PROCESS_SWITCH(NucleiHistTask, processMCgen, "process generated MC", false); - //**************************************************************************************************** - - template - void fillCentHistorgrams(const CollisionType& event, const TracksType& tracks) + void processMCreco(soa::Join::iterator const& collisions, soa::Filtered> const& tracks, + aod::McParticles& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) { - if (event_selection_sel8 && event.sel8()) { - spectra_reg.fill(HIST("histCentrality"), event.centFT0C()); + if (event_selection_MC_sel8 && !collisions.sel8()) + return; + MC_recon_reg.fill(HIST("histRecVtxMC"), collisions.posZ()); + MC_recon_reg.fill(HIST("histCentrality"), collisions.centFT0C()); + if (!isEventSelected(collisions)) + return; + + if (enable_pT_shift_pion_tpc_nSigma) { + Pion_Tpc_nSigma_shift = new TF1("Pion_Tpc_nSigma_shift", "[0] * TMath::Exp([1] + [2] * x) + [3] + [4] * x + [5] * x * x", 0.f, 14.f); + auto par = (std::vector)parShiftPtPion; + Pion_Tpc_nSigma_shift->SetParameters(par[0], par[1], par[2], par[3], par[4], par[5]); } - - if (!event_selection_sel8) { - spectra_reg.fill(HIST("histCentrality"), event.centFT0C()); + if (enable_pT_shift_proton_tpc_nSigma) { + Proton_Tpc_nSigma_shift = new TF1("Proton_Tpc_nSigma_shift", "[0] * TMath::Exp([1] + [2] * x) + [3] + [4] * x + [5] * x * x", 0.f, 14.f); + auto par = (std::vector)parShiftPtProton; + Proton_Tpc_nSigma_shift->SetParameters(par[0], par[1], par[2], par[3], par[4], par[5]); + } + if (enable_pT_shift_deuteron_tpc_nSigma) { + Deuteron_Tpc_nSigma_shift = new TF1("Deuteron_Tpc_nSigma_shift", "[0] * TMath::Exp([1] + [2] * x) + [3] + [4] * x + [5] * x * x", 0.f, 14.f); + auto par = (std::vector)parShiftPtDeuteron; + Deuteron_Tpc_nSigma_shift->SetParameters(par[0], par[1], par[2], par[3], par[4], par[5]); + } + if (enable_pT_shift_triton_tpc_nSigma) { + Triton_Tpc_nSigma_shift = new TF1("Triton_Tpc_nSigma_shift", "[0] * TMath::Exp([1] + [2] * x) + [3] + [4] * x + [5] * x * x", 0.f, 14.f); + auto par = (std::vector)parShiftPtTriton; + Triton_Tpc_nSigma_shift->SetParameters(par[0], par[1], par[2], par[3], par[4], par[5]); + } + if (enable_pT_shift_He3_tpc_nSigma) { + He3_Tpc_nSigma_shift = new TF1("He3_Tpc_nSigma_shift", "[0] * TMath::Exp([1] + [2] * x) + [3] + [4] * x + [5] * x * x", 0.f, 14.f); + auto par = (std::vector)parShiftPtHe3; + He3_Tpc_nSigma_shift->SetParameters(par[0], par[1], par[2], par[3], par[4], par[5]); + } + if (enable_pT_shift_He4_tpc_nSigma) { + He4_Tpc_nSigma_shift = new TF1("He4_Tpc_nSigma_shift", "[0] * TMath::Exp([1] + [2] * x) + [3] + [4] * x + [5] * x * x", 0.f, 14.f); + auto par = (std::vector)parShiftPtHe4; + He4_Tpc_nSigma_shift->SetParameters(par[0], par[1], par[2], par[3], par[4], par[5]); } - for (auto track : tracks) { // start loop over tracks + for (auto& track : tracks) { + histTrackcuts_MC->AddBinContent(1); + const auto particle = track.mcParticle(); - if (event_selection_sel8 && !event.sel8()) { - continue; + int pdgbin = 0; + TLorentzVector lorentzVector_particle_MC{}; + switch (particle.pdgCode()) { + case +211: + pdgbin = 0; + histPDG_reco->AddBinContent(1); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassPiPlus); + break; + case -211: + pdgbin = 1; + histPDG_reco->AddBinContent(2); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassPiPlus); + break; + case +321: + pdgbin = 2; + histPDG_reco->AddBinContent(3); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassKPlus); + break; + case -321: + pdgbin = 3; + histPDG_reco->AddBinContent(4); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassKPlus); + break; + case +2212: + pdgbin = 4; + histPDG_reco->AddBinContent(5); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassProton); + break; + case -2212: + pdgbin = 5; + histPDG_reco->AddBinContent(6); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassProton); + break; + case +1000010020: + pdgbin = 6; + histPDG_reco->AddBinContent(7); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassDeuteron); + break; + case -1000010020: + pdgbin = 7; + histPDG_reco->AddBinContent(8); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassDeuteron); + break; + case +1000010030: + pdgbin = 8; + histPDG_reco->AddBinContent(9); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassTriton); + break; + case -1000010030: + pdgbin = 9; + histPDG_reco->AddBinContent(10); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassTriton); + break; + case +1000020030: + pdgbin = 10; + histPDG_reco->AddBinContent(11); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassHelium3); + break; + case -1000020030: + pdgbin = 11; + histPDG_reco->AddBinContent(12); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassHelium3); + break; + case +1000020040: + pdgbin = 12; + histPDG_reco->AddBinContent(13); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassAlpha); + break; + case -1000020040: + pdgbin = 13; + histPDG_reco->AddBinContent(14); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassAlpha); + break; + default: + pdgbin = -1; + break; } - if (enable_Centrality_cut_global && (event.centFT0C() < minCentrality) && (event.centFT0C() > maxCentrality)) { + if (require_PhysicalPrimary_MC_reco && !particle.isPhysicalPrimary()) continue; - } + histTrackcuts_MC->AddBinContent(2); - spectra_reg.fill(HIST("histEtaWithOverFlow"), track.eta()); - spectra_reg.fill(HIST("histEta_cent"), event.centFT0C(), track.eta()); + if (lorentzVector_particle_MC.Rapidity() < yMin || lorentzVector_particle_MC.Rapidity() > yMax) + continue; + histTrackcuts_MC->AddBinContent(3); - if ((event.centFT0C() > minCentrality) && (event.centFT0C() < maxCentrality)) { - spectra_reg.fill(HIST("histEta"), track.eta()); + MC_recon_reg.fill(HIST("histEta"), track.eta(), pdgbin); + + if ((particle.pdgCode() == 1000020030) || (particle.pdgCode() == -1000020030) || (particle.pdgCode() == 1000020040) || (particle.pdgCode() == -1000020040)) { + MC_recon_reg.fill(HIST("histPt"), track.pt() * 2.0, pdgbin); + MC_recon_reg.fill(HIST("histDCA"), track.pt() * 2.0, track.dcaXY(), pdgbin); + MC_recon_reg.fill(HIST("histDCAz"), track.pt() * 2.0, track.dcaZ(), pdgbin); + MC_recon_reg.fill(HIST("histTpcSignalData"), track.pt() * 2.0 * track.sign(), track.tpcSignal(), pdgbin); + MC_recon_reg.fill(HIST("histTpcSignalData_all_species"), track.pt() * 2.0 * track.sign(), track.tpcSignal()); + MC_recon_reg.fill(HIST("histNClusterTPC"), track.pt() * 2.0, track.tpcNClsCrossedRows(), pdgbin); + MC_recon_reg.fill(HIST("histNClusterITS"), track.pt() * 2.0, track.itsNCls(), pdgbin); + MC_recon_reg.fill(HIST("histNClusterITSib"), track.pt() * 2.0, track.itsNClsInnerBarrel(), pdgbin); + MC_recon_reg.fill(HIST("histChi2TPC"), track.pt() * 2.0, track.tpcChi2NCl(), pdgbin); + MC_recon_reg.fill(HIST("histChi2ITS"), track.pt() * 2.0, track.itsChi2NCl(), pdgbin); + MC_recon_reg.fill(HIST("histChi2TOF"), track.pt() * 2.0, track.tofChi2(), pdgbin); + } else { + MC_recon_reg.fill(HIST("histPt"), track.pt(), pdgbin); + MC_recon_reg.fill(HIST("histDCA"), track.pt(), track.dcaXY(), pdgbin); + MC_recon_reg.fill(HIST("histDCAz"), track.pt(), track.dcaZ(), pdgbin); + MC_recon_reg.fill(HIST("histTpcSignalData"), track.pt() * track.sign(), track.tpcSignal(), pdgbin); + MC_recon_reg.fill(HIST("histTpcSignalData_all_species"), track.pt() * track.sign(), track.tpcSignal()); + MC_recon_reg.fill(HIST("histNClusterTPC"), track.pt(), track.tpcNClsCrossedRows(), pdgbin); + MC_recon_reg.fill(HIST("histNClusterITS"), track.pt(), track.itsNCls(), pdgbin); + MC_recon_reg.fill(HIST("histNClusterITSib"), track.pt(), track.itsNClsInnerBarrel(), pdgbin); + MC_recon_reg.fill(HIST("histChi2TPC"), track.pt(), track.tpcChi2NCl(), pdgbin); + MC_recon_reg.fill(HIST("histChi2ITS"), track.pt(), track.itsChi2NCl(), pdgbin); + MC_recon_reg.fill(HIST("histChi2TOF"), track.pt(), track.tofChi2(), pdgbin); } float TPCnumberClsFound = track.tpcNClsFound(); @@ -1331,238 +1368,38 @@ struct NucleiHistTask { float Chi2perClusterTPC = track.tpcChi2NCl(); float Chi2perClusterITS = track.itsChi2NCl(); - // track cuts - if (enable_PVcontributor_global && !(track.isPVContributor())) { - continue; - } + bool insideDCAxy = (std::abs(track.dcaXY()) <= (maxDcaXYFactor.value * (0.0105f + 0.0350f / pow(track.pt(), 1.1f)))); - if (TPCnumberClsFound < minTPCnClsFound || TPC_nCls_Crossed_Rows < minNCrossedRowsTPC || RatioCrossedRowsOverFindableTPC < minRatioCrossedRowsTPC || RatioCrossedRowsOverFindableTPC > maxRatioCrossedRowsTPC || Chi2perClusterTPC > maxChi2TPC || Chi2perClusterITS > maxChi2ITS || !(track.passedTPCRefit()) || !(track.passedITSRefit()) || (track.itsNClsInnerBarrel()) < minReqClusterITSib || (track.itsNCls()) < minReqClusterITS) { + if (!(insideDCAxy) || TMath::Abs(track.dcaZ()) > maxDCA_Z) continue; - } - - // cut on rapidity - TLorentzVector lorentzVector_pion{}; - TLorentzVector lorentzVector_proton{}; - TLorentzVector lorentzVector_deuteron{}; - TLorentzVector lorentzVector_triton{}; - TLorentzVector lorentzVector_He3{}; - TLorentzVector lorentzVector_He4{}; - - lorentzVector_pion.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassPiPlus); - lorentzVector_proton.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassProton); - lorentzVector_deuteron.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassDeuteron); - lorentzVector_triton.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassTriton); - lorentzVector_He3.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassHelium3); - lorentzVector_He4.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassAlpha); - - if (lorentzVector_pion.Rapidity() < yMin || lorentzVector_pion.Rapidity() > yMax || - lorentzVector_proton.Rapidity() < yMin || lorentzVector_proton.Rapidity() > yMax || - lorentzVector_deuteron.Rapidity() < yMin || lorentzVector_deuteron.Rapidity() > yMax || - lorentzVector_triton.Rapidity() < yMin || lorentzVector_triton.Rapidity() > yMax || - lorentzVector_He3.Rapidity() < yMin || lorentzVector_He3.Rapidity() > yMax || - lorentzVector_He4.Rapidity() < yMin || lorentzVector_He4.Rapidity() > yMax) { + histTrackcuts_MC->AddBinContent(4); + if (TPCnumberClsFound < minTPCnClsFound || TPC_nCls_Crossed_Rows < minNCrossedRowsTPC) continue; - } - - // fill 3D centrality histograms - if (track.sign() > 0) { - - pion_reg.fill(HIST("histTpcNsigmaData_cent"), track.pt(), track.tpcNSigmaPi(), event.centFT0C()); - proton_reg.fill(HIST("histTpcNsigmaData_cent"), track.pt(), track.tpcNSigmaPr(), event.centFT0C()); - deuteron_reg.fill(HIST("histTpcNsigmaData_cent"), track.pt(), track.tpcNSigmaDe(), event.centFT0C()); - triton_reg.fill(HIST("histTpcNsigmaData_cent"), track.pt(), track.tpcNSigmaTr(), event.centFT0C()); - Helium3_reg.fill(HIST("histTpcNsigmaData_cent"), track.pt() * 2.0, track.tpcNSigmaHe(), event.centFT0C()); - Helium4_reg.fill(HIST("histTpcNsigmaData_cent"), track.pt() * 2.0, track.tpcNSigmaAl(), event.centFT0C()); - - if ((event.centFT0C() > minCentrality) && (event.centFT0C() < maxCentrality)) { - pion_reg.fill(HIST("histTpcNsigmaData_eta"), track.pt(), track.tpcNSigmaPi(), track.eta()); - proton_reg.fill(HIST("histTpcNsigmaData_eta"), track.pt(), track.tpcNSigmaPr(), track.eta()); - deuteron_reg.fill(HIST("histTpcNsigmaData_eta"), track.pt(), track.tpcNSigmaDe(), track.eta()); - triton_reg.fill(HIST("histTpcNsigmaData_eta"), track.pt(), track.tpcNSigmaTr(), track.eta()); - Helium3_reg.fill(HIST("histTpcNsigmaData_eta"), track.pt() * 2.0, track.tpcNSigmaHe(), track.eta()); - Helium4_reg.fill(HIST("histTpcNsigmaData_eta"), track.pt() * 2.0, track.tpcNSigmaAl(), track.eta()); - } - - if (track.hasTOF()) { - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } - - pion_reg.fill(HIST("histTofNsigmaData_cent"), track.pt(), track.tofNSigmaPi(), event.centFT0C()); - proton_reg.fill(HIST("histTofNsigmaData_cent"), track.pt(), track.tofNSigmaPr(), event.centFT0C()); - deuteron_reg.fill(HIST("histTofNsigmaData_cent"), track.pt(), track.tofNSigmaDe(), event.centFT0C()); - triton_reg.fill(HIST("histTofNsigmaData_cent"), track.pt(), track.tofNSigmaTr(), event.centFT0C()); - Helium3_reg.fill(HIST("histTofNsigmaData_cent"), track.pt() * 2.0, track.tofNSigmaHe(), event.centFT0C()); - Helium4_reg.fill(HIST("histTofNsigmaData_cent"), track.pt() * 2.0, track.tofNSigmaAl(), event.centFT0C()); - - pion_reg.fill(HIST("histTofm2_cent"), track.pt(), track.mass() * track.mass(), event.centFT0C()); - proton_reg.fill(HIST("histTofm2_cent"), track.pt(), track.mass() * track.mass(), event.centFT0C()); - deuteron_reg.fill(HIST("histTofm2_cent"), track.pt(), track.mass() * track.mass(), event.centFT0C()); - triton_reg.fill(HIST("histTofm2_cent"), track.pt(), track.mass() * track.mass(), event.centFT0C()); - Helium3_reg.fill(HIST("histTofm2_cent"), track.pt() * 2.0, track.mass() * track.mass(), event.centFT0C()); - Helium4_reg.fill(HIST("histTofm2_cent"), track.pt() * 2.0, track.mass() * track.mass(), event.centFT0C()); - - if ((event.centFT0C() > minCentrality) && (event.centFT0C() < maxCentrality)) { - pion_reg.fill(HIST("histTofm2_eta"), track.pt(), track.mass() * track.mass(), track.eta()); - pion_reg.fill(HIST("histTofNsigmaData_eta"), track.pt(), track.tofNSigmaPi(), track.eta()); - proton_reg.fill(HIST("histTofm2_eta"), track.pt(), track.mass() * track.mass(), track.eta()); - proton_reg.fill(HIST("histTofNsigmaData_eta"), track.pt(), track.tofNSigmaPr(), track.eta()); - deuteron_reg.fill(HIST("histTofm2_eta"), track.pt(), track.mass() * track.mass(), track.eta()); - deuteron_reg.fill(HIST("histTofNsigmaData_eta"), track.pt(), track.tofNSigmaDe(), track.eta()); - triton_reg.fill(HIST("histTofm2_eta"), track.pt(), track.mass() * track.mass(), track.eta()); - triton_reg.fill(HIST("histTofNsigmaData_eta"), track.pt(), track.tofNSigmaTr(), track.eta()); - Helium3_reg.fill(HIST("histTofm2_eta"), track.pt() * 2.0, track.mass() * track.mass(), track.eta()); - Helium3_reg.fill(HIST("histTofNsigmaData_eta"), track.pt() * 2.0, track.tofNSigmaHe(), track.eta()); - Helium4_reg.fill(HIST("histTofm2_eta"), track.pt() * 2.0, track.mass() * track.mass(), track.eta()); - Helium4_reg.fill(HIST("histTofNsigmaData_eta"), track.pt() * 2.0, track.tofNSigmaAl(), track.eta()); - } - } - } - - if (track.sign() < 0) { - - apion_reg.fill(HIST("histTpcNsigmaData_cent"), track.pt(), track.tpcNSigmaPi(), event.centFT0C()); - aproton_reg.fill(HIST("histTpcNsigmaData_cent"), track.pt(), track.tpcNSigmaPr(), event.centFT0C()); - adeuteron_reg.fill(HIST("histTpcNsigmaData_cent"), track.pt(), track.tpcNSigmaDe(), event.centFT0C()); - atriton_reg.fill(HIST("histTpcNsigmaData_cent"), track.pt(), track.tpcNSigmaTr(), event.centFT0C()); - aHelium3_reg.fill(HIST("histTpcNsigmaData_cent"), track.pt() * 2.0, track.tpcNSigmaHe(), event.centFT0C()); - aHelium4_reg.fill(HIST("histTpcNsigmaData_cent"), track.pt() * 2.0, track.tpcNSigmaAl(), event.centFT0C()); - - if ((event.centFT0C() > minCentrality) && (event.centFT0C() < maxCentrality)) { - apion_reg.fill(HIST("histTpcNsigmaData_eta"), track.pt(), track.tpcNSigmaPi(), track.eta()); - aproton_reg.fill(HIST("histTpcNsigmaData_eta"), track.pt(), track.tpcNSigmaPr(), track.eta()); - adeuteron_reg.fill(HIST("histTpcNsigmaData_eta"), track.pt(), track.tpcNSigmaDe(), track.eta()); - atriton_reg.fill(HIST("histTpcNsigmaData_eta"), track.pt(), track.tpcNSigmaTr(), track.eta()); - aHelium3_reg.fill(HIST("histTpcNsigmaData_eta"), track.pt() * 2.0, track.tpcNSigmaHe(), track.eta()); - aHelium4_reg.fill(HIST("histTpcNsigmaData_eta"), track.pt() * 2.0, track.tpcNSigmaAl(), track.eta()); - } - - if (track.hasTOF()) { - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { - int lastLayer = 0; - for (int l = 7; l >= 0; l--) { - if (track.trdPattern() & (1 << l)) { - lastLayer = l; - break; - } - } - if (lastLayer < lastRequiredTrdCluster) { - continue; - } - } - - apion_reg.fill(HIST("histTofNsigmaData_cent"), track.pt(), track.tofNSigmaPi(), event.centFT0C()); - aproton_reg.fill(HIST("histTofNsigmaData_cent"), track.pt(), track.tofNSigmaPr(), event.centFT0C()); - adeuteron_reg.fill(HIST("histTofNsigmaData_cent"), track.pt(), track.tofNSigmaDe(), event.centFT0C()); - atriton_reg.fill(HIST("histTofNsigmaData_cent"), track.pt(), track.tofNSigmaTr(), event.centFT0C()); - aHelium3_reg.fill(HIST("histTofNsigmaData_cent"), track.pt() * 2.0, track.tofNSigmaHe(), event.centFT0C()); - aHelium4_reg.fill(HIST("histTofNsigmaData_cent"), track.pt() * 2.0, track.tofNSigmaAl(), event.centFT0C()); - - apion_reg.fill(HIST("histTofm2_cent"), track.pt(), track.mass() * track.mass(), event.centFT0C()); - aproton_reg.fill(HIST("histTofm2_cent"), track.pt(), track.mass() * track.mass(), event.centFT0C()); - adeuteron_reg.fill(HIST("histTofm2_cent"), track.pt(), track.mass() * track.mass(), event.centFT0C()); - atriton_reg.fill(HIST("histTofm2_cent"), track.pt(), track.mass() * track.mass(), event.centFT0C()); - aHelium3_reg.fill(HIST("histTofm2_cent"), track.pt() * 2.0, track.mass() * track.mass(), event.centFT0C()); - aHelium4_reg.fill(HIST("histTofm2_cent"), track.pt() * 2.0, track.mass() * track.mass(), event.centFT0C()); - - if ((event.centFT0C() > minCentrality) && (event.centFT0C() < maxCentrality)) { - apion_reg.fill(HIST("histTofm2_eta"), track.pt(), track.mass() * track.mass(), track.eta()); - apion_reg.fill(HIST("histTofNsigmaData_eta"), track.pt(), track.tofNSigmaPi(), track.eta()); - aproton_reg.fill(HIST("histTofm2_eta"), track.pt(), track.mass() * track.mass(), track.eta()); - aproton_reg.fill(HIST("histTofNsigmaData_eta"), track.pt(), track.tofNSigmaPr(), track.eta()); - adeuteron_reg.fill(HIST("histTofm2_eta"), track.pt(), track.mass() * track.mass(), track.eta()); - adeuteron_reg.fill(HIST("histTofNsigmaData_eta"), track.pt(), track.tofNSigmaDe(), track.eta()); - atriton_reg.fill(HIST("histTofm2_eta"), track.pt(), track.mass() * track.mass(), track.eta()); - atriton_reg.fill(HIST("histTofNsigmaData_eta"), track.pt(), track.tofNSigmaTr(), track.eta()); - aHelium3_reg.fill(HIST("histTofm2_eta"), track.pt() * 2.0, track.mass() * track.mass(), track.eta()); - aHelium3_reg.fill(HIST("histTofNsigmaData_eta"), track.pt() * 2.0, track.tofNSigmaHe(), track.eta()); - aHelium4_reg.fill(HIST("histTofm2_eta"), track.pt() * 2.0, track.mass() * track.mass(), track.eta()); - aHelium4_reg.fill(HIST("histTofNsigmaData_eta"), track.pt() * 2.0, track.tofNSigmaAl(), track.eta()); - } - } - } - } - } - - //**************************************************************************************************** - - Filter collisionFilter = (nabs(aod::collision::posZ) < cfgCutVertex); - Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta && requireGlobalTrackWoDCAInFilter()); - - using EventCandidates = soa::Filtered>; - - using EventCandidatesCent = soa::Filtered>; - - using TrackCandidates = soa::Filtered>; - - void processData(EventCandidates::iterator const& event, TrackCandidates const& tracks) - { - fillHistograms(event, tracks); - } - PROCESS_SWITCH(NucleiHistTask, processData, "process data", true); - - void processDataCent(EventCandidatesCent::iterator const& event, TrackCandidates const& tracks) - { - fillHistograms(event, tracks); - fillCentHistorgrams(event, tracks); - } - PROCESS_SWITCH(NucleiHistTask, processDataCent, "process data with centralities", false); - - void processMC(soa::Join::iterator const& collisions, soa::Filtered> const& tracks, - aod::McParticles& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) - { - - MC_truth_reg.fill(HIST("histRecVtxMC"), collisions.posZ()); - MC_truth_reg.fill(HIST("histCentrality"), collisions.centFT0C()); - - for (auto& track : tracks) { - const auto particle = track.mcParticle(); - const auto pdg = Form("%i", particle.pdgCode()); - - if (!particle.isPhysicalPrimary()) + histTrackcuts_MC->AddBinContent(5); + if (RatioCrossedRowsOverFindableTPC < minRatioCrossedRowsTPC || RatioCrossedRowsOverFindableTPC > maxRatioCrossedRowsTPC) continue; - - histPDG->Fill(pdg, 1); - const float pdgbin = histPDG->GetXaxis()->GetBinCenter(histPDG->GetXaxis()->FindBin(pdg)); - - MC_truth_reg.fill(HIST("histPhi"), particle.phi(), pdgbin); - MC_truth_reg.fill(HIST("histEta"), particle.eta(), pdgbin); - MC_truth_reg.fill(HIST("histPt"), particle.pt(), pdgbin); - - MC_recon_reg.fill(HIST("histPhi"), track.phi(), pdgbin); - MC_recon_reg.fill(HIST("histEta"), track.eta(), pdgbin); - MC_recon_reg.fill(HIST("histPt"), track.pt(), pdgbin); - MC_recon_reg.fill(HIST("histDCA"), track.pt(), track.dcaXY(), pdgbin); - MC_recon_reg.fill(HIST("histDCAz"), track.pt(), track.dcaZ(), pdgbin); - MC_recon_reg.fill(HIST("histTpcSignalData"), track.pt() * track.sign(), track.tpcSignal(), pdgbin); - MC_recon_reg.fill(HIST("histTpcSignalData_all_species"), track.pt() * track.sign(), track.tpcSignal()); - MC_recon_reg.fill(HIST("histNClusterTPC"), track.pt(), track.tpcNClsCrossedRows(), pdgbin); - MC_recon_reg.fill(HIST("histNClusterITS"), track.pt(), track.itsNCls(), pdgbin); - MC_recon_reg.fill(HIST("histNClusterITSib"), track.pt(), track.itsNClsInnerBarrel(), pdgbin); - MC_recon_reg.fill(HIST("histTPCnClsFindable"), track.pt(), track.tpcNClsFindable(), pdgbin); - MC_recon_reg.fill(HIST("histTPCnClsFindableMinusFound"), track.pt(), track.tpcNClsFindableMinusFound(), pdgbin); - MC_recon_reg.fill(HIST("histTPCnClsFindableMinusCrossedRows"), track.pt(), track.tpcNClsFindableMinusCrossedRows(), pdgbin); - MC_recon_reg.fill(HIST("histTPCnClsShared"), track.pt(), track.tpcNClsShared(), pdgbin); - MC_recon_reg.fill(HIST("histTPCCrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls(), pdgbin); - MC_recon_reg.fill(HIST("histTPCFoundOverFindable"), track.tpcFoundOverFindableCls(), pdgbin); - MC_recon_reg.fill(HIST("histChi2TPC"), track.pt(), track.tpcChi2NCl(), pdgbin); - MC_recon_reg.fill(HIST("histChi2ITS"), track.pt(), track.itsChi2NCl(), pdgbin); - MC_recon_reg.fill(HIST("histChi2ITSvsITSnCls"), track.itsChi2NCl(), track.itsNCls()); - MC_recon_reg.fill(HIST("histChi2ITSvsITSibnCls"), track.itsChi2NCl(), track.itsNClsInnerBarrel()); - MC_recon_reg.fill(HIST("histChi2ITSvsITSnClsAll"), track.itsChi2NCl(), track.itsNCls()); - MC_recon_reg.fill(HIST("histChi2ITSvsITSnClsAll"), track.itsChi2NCl(), track.itsNClsInnerBarrel()); - MC_recon_reg.fill(HIST("histChi2TOF"), track.pt(), track.tofChi2(), pdgbin); - MC_recon_reg.fill(HIST("histTrackLength"), track.length(), pdgbin); - MC_recon_reg.fill(HIST("histTPCFractionSharedCls"), track.tpcFractionSharedCls(), pdgbin); + histTrackcuts_MC->AddBinContent(6); + if (Chi2perClusterTPC > maxChi2PerClusterTPC || Chi2perClusterTPC < minChi2PerClusterTPC || Chi2perClusterITS > maxChi2PerClusterITS) + continue; + histTrackcuts_MC->AddBinContent(7); + if (!(track.passedTPCRefit())) + continue; + histTrackcuts_MC->AddBinContent(8); + if (!(track.passedITSRefit())) + continue; + histTrackcuts_MC->AddBinContent(9); + if ((track.itsNClsInnerBarrel()) < minReqClusterITSib || (track.itsNCls()) < minReqClusterITS) + continue; + histTrackcuts_MC->AddBinContent(10); + if (track.pt() < p_min || track.pt() > p_max) + continue; + histTrackcuts_MC->AddBinContent(11); + if ((requireITS && !(track.hasITS())) || (requireTPC && !(track.hasTPC()))) + continue; + histTrackcuts_MC->AddBinContent(12); + if (requireGoldenChi2 && !(track.passedGoldenChi2())) + continue; + histTrackcuts_MC->AddBinContent(13); float nSigmaPion = track.tpcNSigmaPi(); float nSigmaProton = track.tpcNSigmaPr(); @@ -1571,21 +1408,46 @@ struct NucleiHistTask { float nSigmaHe3 = track.tpcNSigmaHe(); float nSigmaHe4 = track.tpcNSigmaAl(); + if (enable_pT_shift_pion_tpc_nSigma) { + float nSigmaPion_shift = Pion_Tpc_nSigma_shift->Eval(track.pt()); + nSigmaPion -= nSigmaPion_shift; + } + if (enable_pT_shift_proton_tpc_nSigma) { + float nSigmaProton_shift = Proton_Tpc_nSigma_shift->Eval(track.pt()); + nSigmaProton -= nSigmaProton_shift; + } + if (enable_pT_shift_deuteron_tpc_nSigma) { + float nSigmaDeuteron_shift = Deuteron_Tpc_nSigma_shift->Eval(track.pt()); + nSigmaDeuteron -= nSigmaDeuteron_shift; + } + if (enable_pT_shift_triton_tpc_nSigma) { + float nSigmaTriton_shift = Triton_Tpc_nSigma_shift->Eval(track.pt()); + nSigmaTriton -= nSigmaTriton_shift; + } + if (enable_pT_shift_He3_tpc_nSigma) { + float nSigmaHe3_shift = He3_Tpc_nSigma_shift->Eval(track.pt() * 2.0); + nSigmaHe3 -= nSigmaHe3_shift; + } + if (enable_pT_shift_He4_tpc_nSigma) { + float nSigmaHe4_shift = He4_Tpc_nSigma_shift->Eval(track.pt() * 2.0); + nSigmaHe4 -= nSigmaHe4_shift; + } + if (track.sign() > 0) { MC_recon_reg.fill(HIST("histTpcNsigmaDataPi"), track.pt(), nSigmaPion); MC_recon_reg.fill(HIST("histTpcNsigmaDataPr"), track.pt(), nSigmaProton); MC_recon_reg.fill(HIST("histTpcNsigmaDataDe"), track.pt(), nSigmaDeuteron); MC_recon_reg.fill(HIST("histTpcNsigmaDataTr"), track.pt(), nSigmaTriton); - MC_recon_reg.fill(HIST("histTpcNsigmaDataHe"), track.pt(), nSigmaHe3); - MC_recon_reg.fill(HIST("histTpcNsigmaDataAl"), track.pt(), nSigmaHe4); + MC_recon_reg.fill(HIST("histTpcNsigmaDataHe"), track.pt() * 2.0, nSigmaHe3); + MC_recon_reg.fill(HIST("histTpcNsigmaDataAl"), track.pt() * 2.0, nSigmaHe4); } if (track.sign() < 0) { MC_recon_reg.fill(HIST("histTpcNsigmaDataaPi"), track.pt(), nSigmaPion); MC_recon_reg.fill(HIST("histTpcNsigmaDataaPr"), track.pt(), nSigmaProton); MC_recon_reg.fill(HIST("histTpcNsigmaDataaDe"), track.pt(), nSigmaDeuteron); MC_recon_reg.fill(HIST("histTpcNsigmaDataaTr"), track.pt(), nSigmaTriton); - MC_recon_reg.fill(HIST("histTpcNsigmaDataaHe"), track.pt(), nSigmaHe3); - MC_recon_reg.fill(HIST("histTpcNsigmaDataaAl"), track.pt(), nSigmaHe4); + MC_recon_reg.fill(HIST("histTpcNsigmaDataaHe"), track.pt() * 2.0, nSigmaHe3); + MC_recon_reg.fill(HIST("histTpcNsigmaDataaAl"), track.pt() * 2.0, nSigmaHe4); } if (track.hasTOF()) { @@ -1605,9 +1467,9 @@ struct NucleiHistTask { if (nSigmaTriton > nsigmacutLow && nSigmaTriton < nsigmacutHigh) MC_recon_reg.fill(HIST("histTofNsigmaDataTr"), track.pt(), track.tofNSigmaTr()); if (nSigmaHe3 > nsigmacutLow && nSigmaHe3 < nsigmacutHigh) - MC_recon_reg.fill(HIST("histTofNsigmaDataHe"), track.pt(), track.tofNSigmaHe()); + MC_recon_reg.fill(HIST("histTofNsigmaDataHe"), track.pt() * 2.0, track.tofNSigmaHe()); if (nSigmaHe4 > nsigmacutLow && nSigmaHe4 < nsigmacutHigh) - MC_recon_reg.fill(HIST("histTofNsigmaDataAl"), track.pt(), track.tofNSigmaAl()); + MC_recon_reg.fill(HIST("histTofNsigmaDataAl"), track.pt() * 2.0, track.tofNSigmaAl()); } if (track.sign() < 0) { if (nSigmaPion > nsigmacutLow && nSigmaPion < nsigmacutHigh) @@ -1619,177 +1481,152 @@ struct NucleiHistTask { if (nSigmaTriton > nsigmacutLow && nSigmaTriton < nsigmacutHigh) MC_recon_reg.fill(HIST("histTofNsigmaDataaTr"), track.pt(), track.tofNSigmaTr()); if (nSigmaHe3 > nsigmacutLow && nSigmaHe3 < nsigmacutHigh) - MC_recon_reg.fill(HIST("histTofNsigmaDataaHe"), track.pt(), track.tofNSigmaHe()); + MC_recon_reg.fill(HIST("histTofNsigmaDataaHe"), track.pt() * 2.0, track.tofNSigmaHe()); if (nSigmaHe4 > nsigmacutLow && nSigmaHe4 < nsigmacutHigh) - MC_recon_reg.fill(HIST("histTofNsigmaDataaAl"), track.pt(), track.tofNSigmaAl()); + MC_recon_reg.fill(HIST("histTofNsigmaDataaAl"), track.pt() * 2.0, track.tofNSigmaAl()); } } - - MC_recon_diff_reg.fill(HIST("histEtaDiff"), particle.eta() - track.eta(), pdgbin); - auto delta = particle.phi() - track.phi(); - if (delta > TMath::Pi()) { - delta -= 2 * TMath::Pi(); - } - if (delta < -TMath::Pi()) { - delta += 2 * TMath::Pi(); - } - - MC_recon_diff_reg.fill(HIST("histPhiDiff"), delta, pdgbin); - MC_recon_diff_reg.fill(HIST("histPtDiff"), particle.pt() - track.pt(), pdgbin); } } - PROCESS_SWITCH(NucleiHistTask, processMC, "process MC", false); + PROCESS_SWITCH(NucleiHistTask, processMCreco, "process reconstructed MC", false); - void processMCefficiency(soa::Join::iterator const& /*collisions*/, - soa::Filtered> const& tracks, - aod::McParticles& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) + void processMCdca(soa::Join::iterator const& collisions, soa::Filtered> const& tracks, + aod::McParticles& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) { + if (event_selection_MC_sel8 && !collisions.sel8()) + return; + if (!isEventSelected(collisions)) + return; + for (auto& track : tracks) { + histTrackcuts_MC->AddBinContent(1); const auto particle = track.mcParticle(); - const auto pdg = Form("%i", particle.pdgCode()); - - if (!particle.isPhysicalPrimary()) - continue; - - histPDG_eff->Fill(pdg, 1); - const float pdgbin = histPDG_eff->GetXaxis()->GetBinCenter(histPDG_eff->GetXaxis()->FindBin(pdg)); - MC_eff.fill(HIST("histEffSkimming"), 0, pdgbin); - - TLorentzVector lorentzVector_pion{}; - TLorentzVector lorentzVector_proton{}; - TLorentzVector lorentzVector_deuteron{}; - TLorentzVector lorentzVector_triton{}; - TLorentzVector lorentzVector_He3{}; - TLorentzVector lorentzVector_He4{}; - - lorentzVector_pion.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassPiPlus); - lorentzVector_proton.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassProton); - lorentzVector_deuteron.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassDeuteron); - lorentzVector_triton.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassTriton); - lorentzVector_He3.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassHelium3); - lorentzVector_He4.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassAlpha); - - if (lorentzVector_pion.Rapidity() < yMin || lorentzVector_pion.Rapidity() > yMax || - lorentzVector_proton.Rapidity() < yMin || lorentzVector_proton.Rapidity() > yMax || - lorentzVector_deuteron.Rapidity() < yMin || lorentzVector_deuteron.Rapidity() > yMax || - lorentzVector_triton.Rapidity() < yMin || lorentzVector_triton.Rapidity() > yMax || - lorentzVector_He3.Rapidity() < yMin || lorentzVector_He3.Rapidity() > yMax || - lorentzVector_He4.Rapidity() < yMin || lorentzVector_He4.Rapidity() > yMax) { - continue; - } - - bool passedITS = track.hasITS(); - bool passedTPC = track.hasTPC(); - bool passedTOF = track.hasTOF(); - - if (passedITS) { - MC_eff.fill(HIST("histITS_vs_pT"), particle.pt(), pdgbin); - MC_eff.fill(HIST("histEffSkimming"), 1, pdgbin); - - if (passedTPC) { - MC_eff.fill(HIST("histITS_TPC_vs_pT"), particle.pt(), pdgbin); - MC_eff.fill(HIST("histEffSkimming"), 2, pdgbin); - if (passedTOF) { - MC_eff.fill(HIST("histITS_TPC_TOFvs_pT"), particle.pt(), pdgbin); - MC_eff.fill(HIST("histEffSkimming"), 3, pdgbin); - } - } + int pdgbin = 0; + TLorentzVector lorentzVector_particle_MC{}; + switch (particle.pdgCode()) { + case +211: + pdgbin = 0; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassPiPlus); + break; + case -211: + pdgbin = 1; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassPiPlus); + break; + case +321: + pdgbin = 2; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassKPlus); + break; + case -321: + pdgbin = 3; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassKPlus); + break; + case +2212: + pdgbin = 4; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassProton); + break; + case -2212: + pdgbin = 5; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassProton); + break; + case +1000010020: + pdgbin = 6; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassDeuteron); + break; + case -1000010020: + pdgbin = 7; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassDeuteron); + break; + case +1000010030: + pdgbin = 8; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassTriton); + break; + case -1000010030: + pdgbin = 9; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassTriton); + break; + case +1000020030: + pdgbin = 10; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassHelium3); + break; + case -1000020030: + pdgbin = 11; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassHelium3); + break; + case +1000020040: + pdgbin = 12; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassAlpha); + break; + case -1000020040: + pdgbin = 13; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassAlpha); + break; + default: + pdgbin = -1; + break; } + if (lorentzVector_particle_MC.Rapidity() < yMin || lorentzVector_particle_MC.Rapidity() > yMax) + continue; float TPCnumberClsFound = track.tpcNClsFound(); float TPC_nCls_Crossed_Rows = track.tpcNClsCrossedRows(); float RatioCrossedRowsOverFindableTPC = track.tpcCrossedRowsOverFindableCls(); float Chi2perClusterTPC = track.tpcChi2NCl(); float Chi2perClusterITS = track.itsChi2NCl(); - if (TPCnumberClsFound < minTPCnClsFound || TPC_nCls_Crossed_Rows < minNCrossedRowsTPC || RatioCrossedRowsOverFindableTPC < minRatioCrossedRowsTPC || RatioCrossedRowsOverFindableTPC > maxRatioCrossedRowsTPC || Chi2perClusterTPC > maxChi2TPC || Chi2perClusterITS > maxChi2ITS || !(track.passedTPCRefit()) || !(track.passedITSRefit()) || (track.itsNClsInnerBarrel()) < minReqClusterITSib || (track.itsNCls()) < minReqClusterITS || TMath::Abs(track.dcaXY()) > maxDCA_XY || TMath::Abs(track.dcaZ()) > maxDCA_Z) { + if (TPCnumberClsFound < minTPCnClsFound || TPC_nCls_Crossed_Rows < minNCrossedRowsTPC) + continue; + if (RatioCrossedRowsOverFindableTPC < minRatioCrossedRowsTPC || RatioCrossedRowsOverFindableTPC > maxRatioCrossedRowsTPC) + continue; + if (Chi2perClusterTPC > maxChi2PerClusterTPC || Chi2perClusterTPC < minChi2PerClusterTPC || Chi2perClusterITS > maxChi2PerClusterITS) + continue; + if (!(track.passedTPCRefit())) + continue; + if (!(track.passedITSRefit())) + continue; + if ((track.itsNClsInnerBarrel()) < minReqClusterITSib || (track.itsNCls()) < minReqClusterITS) + continue; + if (track.pt() < p_min || track.pt() > p_max) + continue; + if ((requireITS && !(track.hasITS())) || (requireTPC && !(track.hasTPC()))) + continue; + if (requireGoldenChi2 && !(track.passedGoldenChi2())) continue; - } - - MC_eff.fill(HIST("histEffSkimming"), 4, pdgbin); - - float nSigmaPion = track.tpcNSigmaPi(); - float nSigmaProton = track.tpcNSigmaPr(); - float nSigmaDeuteron = track.tpcNSigmaDe(); - float nSigmaTriton = track.tpcNSigmaTr(); - float nSigmaHe3 = track.tpcNSigmaHe(); - float nSigmaHe4 = track.tpcNSigmaAl(); - - float TOFnSigmaPion = track.tofNSigmaPi(); - float TOFnSigmaProton = track.tofNSigmaPr(); - float TOFnSigmaDeuteron = track.tofNSigmaDe(); - float TOFnSigmaTriton = track.tofNSigmaTr(); - float TOFnSigmaHe3 = track.tofNSigmaHe(); - float TOFnSigmaHe4 = track.tofNSigmaAl(); - - if (track.sign() > 0) { - if (nSigmaPion > nsigmacutLow && nSigmaPion < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TPC_Pi"), track.pt()); - if (nSigmaProton > nsigmacutLow && nSigmaProton < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TPC_Pr"), track.pt()); - if (nSigmaDeuteron > nsigmacutLow && nSigmaDeuteron < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TPC_De"), track.pt()); - if (nSigmaTriton > nsigmacutLow && nSigmaTriton < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TPC_Tr"), track.pt()); - if (nSigmaHe3 > nsigmacutLow && nSigmaHe3 < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TPC_He3"), track.pt()); - if (nSigmaHe4 > nsigmacutLow && nSigmaHe4 < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TPC_He4"), track.pt()); - } - if (track.sign() < 0) { - if (nSigmaPion > nsigmacutLow && nSigmaPion < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TPC_aPi"), track.pt()); - if (nSigmaProton > nsigmacutLow && nSigmaProton < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TPC_aPr"), track.pt()); - if (nSigmaDeuteron > nsigmacutLow && nSigmaDeuteron < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TPC_aDe"), track.pt()); - if (nSigmaTriton > nsigmacutLow && nSigmaTriton < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TPC_aTr"), track.pt()); - if (nSigmaHe3 > nsigmacutLow && nSigmaHe3 < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TPC_aHe3"), track.pt()); - if (nSigmaHe4 > nsigmacutLow && nSigmaHe4 < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TPC_aHe4"), track.pt()); - } - if (track.hasTOF()) { + MC_DCA.fill(HIST("histEta"), track.eta(), pdgbin); - if (track.sign() > 0) { - if (nSigmaPion > nsigmacutLow && nSigmaPion < nsigmacutHigh && TOFnSigmaPion > nsigmacutLow && TOFnSigmaPion < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TOF_Pi"), track.pt()); - if (nSigmaProton > nsigmacutLow && nSigmaProton < nsigmacutHigh && TOFnSigmaProton > nsigmacutLow && TOFnSigmaProton < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TOF_Pr"), track.pt()); - if (nSigmaDeuteron > nsigmacutLow && nSigmaDeuteron < nsigmacutHigh && TOFnSigmaDeuteron > nsigmacutLow && TOFnSigmaDeuteron < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TOF_De"), track.pt()); - if (nSigmaTriton > nsigmacutLow && nSigmaTriton < nsigmacutHigh && TOFnSigmaTriton > nsigmacutLow && TOFnSigmaTriton < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TOF_Tr"), track.pt()); - if (nSigmaHe3 > nsigmacutLow && nSigmaHe3 < nsigmacutHigh && TOFnSigmaHe3 > nsigmacutLow && TOFnSigmaHe3 < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TOF_He3"), track.pt()); - if (nSigmaHe4 > nsigmacutLow && nSigmaHe4 < nsigmacutHigh && TOFnSigmaHe4 > nsigmacutLow && TOFnSigmaHe4 < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TOF_He4"), track.pt()); + if (particle.isPhysicalPrimary()) { + if ((particle.pdgCode() == 1000020030) || (particle.pdgCode() == -1000020030) || (particle.pdgCode() == 1000020040) || (particle.pdgCode() == -1000020040)) { + MC_DCA.fill(HIST("histDCA_prim"), track.pt() * 2.0, track.dcaXY(), pdgbin); + MC_DCA.fill(HIST("histDCAz_prim"), track.pt() * 2.0, track.dcaZ(), pdgbin); + } else { + MC_DCA.fill(HIST("histDCA_prim"), track.pt(), track.dcaXY(), pdgbin); + MC_DCA.fill(HIST("histDCAz_prim"), track.pt(), track.dcaZ(), pdgbin); } - if (track.sign() < 0) { - if (nSigmaPion > nsigmacutLow && nSigmaPion < nsigmacutHigh && TOFnSigmaPion > nsigmacutLow && TOFnSigmaPion < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TOF_aPi"), track.pt()); - if (nSigmaProton > nsigmacutLow && nSigmaProton < nsigmacutHigh && TOFnSigmaProton > nsigmacutLow && TOFnSigmaProton < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TOF_aPr"), track.pt()); - if (nSigmaDeuteron > nsigmacutLow && nSigmaDeuteron < nsigmacutHigh && TOFnSigmaDeuteron > nsigmacutLow && TOFnSigmaDeuteron < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TOF_aDe"), track.pt()); - if (nSigmaTriton > nsigmacutLow && nSigmaTriton < nsigmacutHigh && TOFnSigmaTriton > nsigmacutLow && TOFnSigmaTriton < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TOF_aTr"), track.pt()); - if (nSigmaHe3 > nsigmacutLow && nSigmaHe3 < nsigmacutHigh && TOFnSigmaHe3 > nsigmacutLow && TOFnSigmaHe3 < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TOF_aHe3"), track.pt()); - if (nSigmaHe4 > nsigmacutLow && nSigmaHe4 < nsigmacutHigh && TOFnSigmaHe4 > nsigmacutLow && TOFnSigmaHe4 < nsigmacutHigh) - MC_eff.fill(HIST("histPt_TOF_aHe4"), track.pt()); + } else if (particle.getProcess() == 4) { + if ((particle.pdgCode() == 1000020030) || (particle.pdgCode() == -1000020030) || (particle.pdgCode() == 1000020040) || (particle.pdgCode() == -1000020040)) { + MC_DCA.fill(HIST("histDCA_weak"), track.pt() * 2.0, track.dcaXY(), pdgbin); + MC_DCA.fill(HIST("histDCAz_weak"), track.pt() * 2.0, track.dcaZ(), pdgbin); + } else { + MC_DCA.fill(HIST("histDCA_weak"), track.pt(), track.dcaXY(), pdgbin); + MC_DCA.fill(HIST("histDCAz_weak"), track.pt(), track.dcaZ(), pdgbin); + } + } else if (particle.getProcess() == 23) { + if ((particle.pdgCode() == 1000020030) || (particle.pdgCode() == -1000020030) || (particle.pdgCode() == 1000020040) || (particle.pdgCode() == -1000020040)) { + MC_DCA.fill(HIST("histDCA_mat"), track.pt() * 2.0, track.dcaXY(), pdgbin); + MC_DCA.fill(HIST("histDCAz_mat"), track.pt() * 2.0, track.dcaZ(), pdgbin); + } else { + MC_DCA.fill(HIST("histDCA_mat"), track.pt(), track.dcaXY(), pdgbin); + MC_DCA.fill(HIST("histDCAz_mat"), track.pt(), track.dcaZ(), pdgbin); } } } } - PROCESS_SWITCH(NucleiHistTask, processMCefficiency, "process MC efficencies", false); + PROCESS_SWITCH(NucleiHistTask, processMCdca, "process MC DCA", false); }; -//**************************************************************************************************** +//*********************************************************************************** WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGLF/Tasks/Nuspex/NucleitpcPbPb.cxx b/PWGLF/Tasks/Nuspex/NucleitpcPbPb.cxx new file mode 100644 index 00000000000..b3e72ed23a5 --- /dev/null +++ b/PWGLF/Tasks/Nuspex/NucleitpcPbPb.cxx @@ -0,0 +1,522 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// \author jaideep tanwar +/// +#include +#include +#include +#include +#include +#include +#include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "DetectorsBase/Propagator.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/PID/TPCPIDResponse.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "Common/DataModel/PIDResponse.h" +#include "TRandom3.h" +#include "Common/DataModel/CollisionAssociationTables.h" + +using namespace o2; +using namespace o2::track; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using CollisionsFull = soa::Join; +/* +using CollisionsFullMC = soa::Join; +*/ +using TracksFull = soa::Join; +namespace +{ +static const int number_of_particles = 6; +static const std::vector particleNames{"pion", "proton", "deuteron", "triton", "helium3", "alpha"}; +static const std::vector antiparticleNames{"anti-pion", "anti-proton", "anti-deuteron", "anti-triton", "anti-helium3", "anti-alpha"}; +static const std::vector particlePdgCodes{211, 2212, o2::constants::physics::kDeuteron, o2::constants::physics::kTriton, o2::constants::physics::kHelium3, o2::constants::physics::kAlpha}; +static const std::vector particleMasses{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron, o2::constants::physics::MassTriton, o2::constants::physics::MassHelium3, o2::constants::physics::MassAlpha}; +static const std::vector particleCharge{1, 1, 1, 1, 2, 2}; +const int no_BBparam = 6; +static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; +// default bethbloch parameters +constexpr double betheBlochDefault[number_of_particles][no_BBparam]{ + {13.611469, 3.598765, -0.021138, 2.039562, 0.651040, 0.09}, // pion + {5.393020, 7.859534, 0.004048, 2.323197, 1.609307, 0.09}, // proton + {5.393020, 7.859534, 0.004048, 2.323197, 1.609307, 0.09}, // deuteron + {5.393020, 7.859534, 0.004048, 2.323197, 1.609307, 0.09}, // triton + {-126.557359, -0.858569, 1.111643, 1.210323, 2.656374, 0.09}, // helium3 + {-126.557359, -0.858569, 1.111643, 1.210323, 2.656374, 0.09}}; // alpha +const int no_trackcuts = 15; +static const std::vector trackPIDsettingsNames{"useBBparams", "minITSnCls", "minTPCnCls", "maxTPCchi2", "maxITSchi2", "minRigidity", "maxRigidity", "maxTPCnSigma", "TOFrequiredabove", "minTOFmass", "maxTOFmass", "minDcaToPvXY", "minDcaToPvZ", "minITSclsSize", "maxITSclsSize"}; +constexpr double trackPIDsettings[number_of_particles][no_trackcuts]{ + {0, 0, 60, 3.0, 100, 0.15, 1.2, 3.0, 1, 0, 100, 0., 0., 0., 1000}, + {1, 0, 60, 3.0, 100, 0.20, 4.0, 3.0, 1, 0, 100, 0., 0., 0., 1000}, + {1, 0, 60, 3.0, 100, 0.50, 5.0, 3.0, 1, 0, 100, 0., 0., 0., 1000}, + {1, 0, 60, 3.0, 100, 0.50, 5.0, 3.0, 1, 0, 100, 0., 0., 0., 1000}, + {1, 0, 60, 3.0, 100, 0.50, 5.0, 3.0, 1, 0, 100, 0., 0., 0., 1000}, + {1, 0, 60, 3.0, 100, 0.50, 5.0, 3.0, 1, 0, 100, 0., 0., 0., 1000}}; +struct Particle { + TString name; + int pdgCode, charge; + double mass, resolution; + std::vector betheParams; + bool active; + Particle(std::string name_, int pdgCode_, double mass_, int charge_, LabeledArray bethe) : name(name_), pdgCode(pdgCode_), charge(charge_), mass(mass_), active(false) + { + resolution = bethe.get(name, "resolution"); + betheParams.clear(); + for (unsigned int i = 0; i < 5; i++) + betheParams.push_back(bethe.get(name, i)); + } +}; // struct Particle +//---------------------------------------------------------------------------------------------------------------- +std::vector> hDeDx; +std::vector> hDeDxanti; +std::vector> hnsigma_pt; +std::vector> hnsigma_ptanti; +std::vector> hdcaXY_pt; +std::vector> hdcaXY_ptanti; +std::vector> hrapidity; +std::vector> hmass_pt; +std::vector> hmass_ptanti; +std::vector> hdelta_mass; +} // namespace +//---------------------------------------------------------------------------------------------------------------- +struct NucleitpcPbPb { + Preslice perCollision = aod::track_association::collisionId; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Configurable cfgDebug{"cfgDebug", 1, "debug level"}; + Configurable cfgRigidityCorrection{"cfgRigidityCorrection", false, "apply rigidity correction"}; + Configurable cfgCutEta{"cfgCutEta", 0.8f, "Eta range for tracks"}; + Configurable centcut{"centcut", 80.0f, "centrality cut"}; + Configurable cfgUsePVcontributors{"cfgUsePVcontributors", true, "use tracks that are PV contibutors"}; + Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {betheBlochDefault[0], number_of_particles, no_BBparam, particleNames, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for light nuclei"}; + Configurable> cfgTrackPIDsettings{"cfgTrackPIDsettings", {trackPIDsettings[0], number_of_particles, no_trackcuts, particleNames, trackPIDsettingsNames}, "track selection and PID criteria"}; + Configurable maxDcaXYFactor{"maxDcaXYFactor", 2.0f, "DCA xy factor"}; + // CCDB + Service ccdb; + Configurable bField{"bField", -999, "bz field, -999 is automatic"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable pidPath{"pidPath", "", "Path to the PID response object"}; + //-------------------------------------------------------------------------------------------------------------------- + std::vector primaryParticles; + std::vector primVtx, cents; + bool collHasCandidate, collPassedEvSel; + int mRunNumber, occupancy; + float dBz; + TRandom3 rand; + double momn; + //---------------------------------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------------------------- + void init(InitContext const&) + { + mRunNumber = 0; + dBz = 0; + rand.SetSeed(0); + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + for (int i = 0; i < number_of_particles; i++) { // create primaryparticles + primaryParticles.push_back(Particle(particleNames.at(i), particlePdgCodes.at(i), particleMasses.at(i), particleCharge.at(i), cfgBetheBlochParams)); + } + std::vector ptBinning = {0.1, 0.5, 1.0, 1.5, 2.0, 2.4, 3.2, 4., 5., 6., 8., 10., 12., 14.}; + std::vector etaBinning = {-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}; + // define histogram axes + const AxisSpec axisMagField{10, -10., 10., "magnetic field"}; + const AxisSpec axisNev{3, 0., 5., "Number of events"}; + const AxisSpec axisRigidity{4000, -10., 10., "#it{p}^{TPC}/#it{z}"}; + const AxisSpec axisdEdx{30000, 0, 3000, "d#it{E}/d#it{x}"}; + const AxisSpec axisCent{100, 0, 100, "centrality"}; + const AxisSpec axisVtxZ{100, -20, 20, "z"}; + const AxisSpec axisDCAZ{100, -10, 10, "z"}; + // const AxisSpec axiseta{100, -1, 1, "eta"}; + const AxisSpec axisrapidity{100, -2, 2, "rapidity"}; + AxisSpec axiseta = {etaBinning, "#eta"}; + AxisSpec axismass = {100, -0.5, 15, "mass^{2}"}; + AxisSpec axisdelta_mass = {100, -6, 6, "#delta mass^{2}"}; + AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec dcaXY = {100, -2, 2, "dcaXY"}; + AxisSpec nsigmaAxis = {160, -20, 20, "n#sigma_{#pi^{+}}"}; + // create histograms + histos.add("histMagField", "histMagField", kTH1F, {axisMagField}); + histos.add("histNev", "histNev", kTH1F, {axisNev}); + histos.add("histVtxZ", "histVtxZ", kTH1F, {axisVtxZ}); + histos.add("histCentFT0A", "histCentFT0A", kTH1F, {axisCent}); + histos.add("histCentFT0C", "histCentFT0C", kTH1F, {axisCent}); + histos.add("histCentFTOC_cut", "histCentFTOC_cut", kTH1F, {axisCent}); + histos.add("histCentFT0M", "histCentFT0M", kTH1F, {axisCent}); + histos.add("histeta", "histeta", kTH1F, {axiseta}); + histos.add("Tof_signal", "Tof_signal", kTH2F, {axisRigidity, {4000, 0.2, 1.2, "#beta"}}); + histos.add("histDcaZVsPtData_particle", "dcaZ vs Pt (particle)", HistType::kTH2F, {{1000, 0, 20}, {1000, -2.5, 2.5, "dca"}}); + histos.add("histDcaXYVsPtData_particle", "dcaXY vs Pt (particle)", HistType::kTH2F, {{1000, 0, 20}, {1000, -2.0, 2.0, "dca"}}); + histos.add("histDcaZVsPtData_antiparticle", "dcaZ vs Pt (antiparticle)", HistType::kTH2F, {{1000, 0, 20}, {1000, -2.5, 2.5, "dca"}}); + histos.add("histDcaXYVsPtData_antiparticle", "dcaXY vs Pt (antiparticle)", HistType::kTH2F, {{1000, 0, 20}, {1000, -2.0, 2.0, "dca"}}); + hDeDx.resize(2 * number_of_particles + 2); + hDeDxanti.resize(2 * number_of_particles + 2); + hnsigma_pt.resize(2 * number_of_particles + 2); + hnsigma_ptanti.resize(2 * number_of_particles + 2); + hdcaXY_pt.resize(2 * number_of_particles + 2); + hdcaXY_ptanti.resize(2 * number_of_particles + 2); + hrapidity.resize(2 * number_of_particles + 2); + hmass_pt.resize(2 * number_of_particles + 2); + hmass_ptanti.resize(2 * number_of_particles + 2); + hdelta_mass.resize(2 * number_of_particles + 2); + for (int i = 0; i <= number_of_particles; i++) { + TString histName = i < number_of_particles ? primaryParticles[i].name : "all"; + hDeDx[2 * i] = histos.add(Form("full/histdEdx_%s", histName.Data()), ";p_{TPC}/z (GeV/#it{c}); d#it{E}/d#it{x}", HistType::kTH2F, {axisRigidity, axisdEdx}); + hDeDx[2 * i + 1] = histos.add(Form("cuts/histdEdx_%s_Cuts", histName.Data()), ";p_{TPC}/z (GeV/#it{c}); d#it{E}/d#it{x}", HistType::kTH2F, {axisRigidity, axisdEdx}); + hDeDxanti[2 * i] = histos.add(Form("antifull/histdEdx_%s", histName.Data()), ";p_{TPC}/z (GeV/#it{c}); d#it{E}/d#it{x}", HistType::kTH2F, {axisRigidity, axisdEdx}); + hDeDxanti[2 * i + 1] = histos.add(Form("anticuts/histdEdx_%s_Cuts", histName.Data()), ";p_{TPC}/z (GeV/#it{c}); d#it{E}/d#it{x}", HistType::kTH2F, {axisRigidity, axisdEdx}); + } + for (int i = 0; i < number_of_particles; i++) { + TString histName = primaryParticles[i].name; + hnsigma_pt[2 * i] = histos.add(Form("histnsigma_pt/histnsigmaTPC_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); TPCnsigma", HistType::kTH2F, {ptAxis, nsigmaAxis}); + hnsigma_ptanti[2 * i] = histos.add(Form("histnsigma_ptanti/histnsigmaTPC_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); TPCnsigma", HistType::kTH2F, {ptAxis, nsigmaAxis}); + hdcaXY_pt[2 * i] = histos.add(Form("histdcaXY_pt/histdcaXY_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); dcaXY", HistType::kTH2F, {ptAxis, dcaXY}); + hdcaXY_ptanti[2 * i] = histos.add(Form("histdcaXY_ptanti/histdcaXY_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); dcaXY", HistType::kTH2F, {ptAxis, dcaXY}); + hmass_pt[2 * i] = histos.add(Form("histmass_pt/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); mass^{2}", HistType::kTH2F, {ptAxis, axismass}); + hmass_ptanti[2 * i] = histos.add(Form("histmass_ptanti/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); mass^{2}", HistType::kTH2F, {ptAxis, axismass}); + hrapidity[2 * i] = histos.add(Form("rapidity/histrapidity_%s", histName.Data()), "; rapidity", HistType::kTH1F, {axisrapidity}); + hdelta_mass[2 * i] = histos.add(Form("histdelta/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); #Delta mass", HistType::kTH2F, {ptAxis, axisdelta_mass}); + } + } // completed void init bracket + //---------------------------------------------------------------------------------------------------------------- + void findprimaryParticles(aod::TrackAssoc const& tracksByColl, TracksFull const& tracks) + { + // track loop, store primary candidates in std::vector + for (const auto& trackId : tracksByColl) { + const auto& track = tracks.rawIteratorAt(trackId.trackId()); + /* + if (!track.isPVContributor()) + continue; + */ + filldedx(track, number_of_particles); + if (track.sign() > 0) { + histos.fill(HIST("histDcaZVsPtData_particle"), track.pt(), track.dcaZ()); + histos.fill(HIST("histDcaXYVsPtData_particle"), track.pt(), track.dcaXY()); + } + if (track.sign() < 0) { + histos.fill(HIST("histDcaZVsPtData_antiparticle"), track.pt(), track.dcaZ()); + histos.fill(HIST("histDcaXYVsPtData_antiparticle"), track.pt(), track.dcaXY()); + } + if (std::abs(track.eta()) > cfgCutEta) + continue; + histos.fill(HIST("histeta"), track.eta()); + for (size_t i = 0; i < primaryParticles.size(); i++) { + if (track.tpcNClsFound() < cfgTrackPIDsettings->get(i, "minTPCnCls")) + continue; + if (track.tpcChi2NCl() > cfgTrackPIDsettings->get(i, "maxTPCchi2")) + continue; + if (track.itsNCls() < cfgTrackPIDsettings->get(i, "minITSnCls")) + continue; + if (track.itsChi2NCl() > cfgTrackPIDsettings->get(i, "maxITSchi2")) + continue; + if (getMeanItsClsSize(track) < cfgTrackPIDsettings->get(i, "minITSclsSize")) + continue; + if (getMeanItsClsSize(track) > cfgTrackPIDsettings->get(i, "maxITSclsSize")) + continue; + if (i == 4 || i == 5) { + momn = 2 * track.pt(); + } else { + momn = track.pt(); + } + bool insideDCAxy = (std::abs(track.dcaXY()) <= (maxDcaXYFactor.value * (0.0105f + 0.0350f / pow(track.pt(), 1.1f)))); + if (!(insideDCAxy) || TMath::Abs(track.dcaZ()) > 2) + continue; + if (TMath::Abs(getRapidity(track, i)) > 0.5) + continue; + fillhsigma(track, i); + if (std::abs(getTPCnSigma(track, primaryParticles.at(i))) > cfgTrackPIDsettings->get(i, "maxTPCnSigma")) + continue; + filldedx(track, i); + fillhdcaXY(track, i); + fillhmass(track, i); + fillhrapidity(track, i); + fillhdelta_mass(track, i); + if (getRigidity(track) < cfgTrackPIDsettings->get(i, "minRigidity") || getRigidity(track) > cfgTrackPIDsettings->get(i, "maxRigidity")) + continue; + if (cfgTrackPIDsettings->get(i, "TOFrequiredabove") >= 0 && getRigidity(track) > cfgTrackPIDsettings->get(i, "TOFrequiredabove") && (track.mass() < cfgTrackPIDsettings->get(i, "minTOFmass") || track.mass() > cfgTrackPIDsettings->get(i, "maxTOFmass"))) + continue; + histos.fill(HIST("Tof_signal"), track.sign() * momn, track.beta()); + } + } // track loop + } + //---------------------------------------------------------------------------------------------------------------- + void processData(CollisionsFull const& collisions, TracksFull const& tracks, aod::BCsWithTimestamps const&, aod::TrackAssoc const& tracksColl) + { + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + initCollision(collision); + if (!collPassedEvSel) + continue; + const uint64_t collIdx = collision.globalIndex(); + auto tracksByColl = tracksColl.sliceBy(perCollision, collIdx); + findprimaryParticles(tracksByColl, tracks); + if (!collHasCandidate) + continue; + if (collision.centFT0C() > centcut) + continue; + } + } + PROCESS_SWITCH(NucleitpcPbPb, processData, "data analysis", true); + //---------------------------------------------------------------------------------------------------------------- + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + auto run3grpTimestamp = bc.timestamp(); + dBz = 0; + o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grpTimestamp); + o2::parameters::GRPMagField* grpmag = 0x0; + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + if (bField < -990) { + // Fetch magnetic field from ccdb for current collision + dBz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grpTimestamp << " with magnetic field of " << dBz << " kZG"; + } else { + dBz = bField; + } + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grpTimestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grpTimestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + if (bField < -990) { + // Fetch magnetic field from ccdb for current collision + dBz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grpTimestamp << " with magnetic field of " << dBz << " kZG"; + } else { + dBz = bField; + } + } + mRunNumber = bc.runNumber(); + } + //---------------------------------------------------------------------------------------------------------------- + template + void initCollision(const T& collision) + { + collHasCandidate = false; + histos.fill(HIST("histMagField"), dBz); + histos.fill(HIST("histNev"), 0.5); + collPassedEvSel = collision.sel8() && std::abs(collision.posZ()) < 10; + if (collision.sel8()) { + histos.fill(HIST("histNev"), 1.5); + if (std::abs(collision.posZ()) < 10.0000000000000000) { + histos.fill(HIST("histNev"), 2.5); + } + } + if (collPassedEvSel) { + histos.fill(HIST("histVtxZ"), collision.posZ()); + histos.fill(HIST("histCentFT0A"), collision.centFT0A()); + histos.fill(HIST("histCentFT0C"), collision.centFT0C()); + histos.fill(HIST("histCentFT0M"), collision.centFT0M()); + if (collision.centFT0C() < centcut) { + histos.fill(HIST("histCentFTOC_cut"), collision.centFT0C()); + } + } + occupancy = collision.trackOccupancyInTimeRange(); + primVtx.assign({collision.posX(), collision.posY(), collision.posZ()}); + cents.assign({collision.centFT0A(), collision.centFT0C(), collision.centFT0M()}); + } + //---------------------------------------------------------------------------------------------------------------- + template + void filldedx(T const& track, int species) + { + const float rigidity = getRigidity(track); + int idx = 2 * species; + if (species != 6) { + auto& hist = (track.sign() > 0) ? hDeDx[idx] : hDeDxanti[idx]; + hist->Fill(track.sign() * rigidity, track.tpcSignal()); + } else { + hDeDx[idx]->Fill(track.sign() * rigidity, track.tpcSignal()); + hDeDxanti[idx]->Fill(track.sign() * rigidity, track.tpcSignal()); + } + if (track.tpcNClsFound() < 100 || track.itsNCls() < 2) + return; + + auto& hist2 = (track.sign() > 0) ? hDeDx[idx + 1] : hDeDxanti[idx + 1]; + hist2->Fill(track.sign() * rigidity, track.tpcSignal()); + } + template + void fillhsigma(T const& track, int species) + { + if (track.tpcNClsFound() < 100 || track.itsNCls() < 2) + return; + int i = species; + const float tpcNsigma = getTPCnSigma(track, primaryParticles.at(i)); + double momn; + if (species == 4 || species == 5) { + momn = 2 * track.pt(); + } else { + momn = track.pt(); + } + if (track.sign() > 0) { + hnsigma_pt[2 * species]->Fill(momn, tpcNsigma); + } + if (track.sign() < 0) { + hnsigma_ptanti[2 * species]->Fill(momn, tpcNsigma); + } + } + template + void fillhdcaXY(T const& track, int species) + { + if (track.tpcNClsFound() < 100 || track.itsNCls() < 2) + return; + double momn; + if (species == 4 || species == 5) { + momn = 2 * track.pt(); + } else { + momn = track.pt(); + } + const float dcaXY = track.dcaXY(); + if (track.sign() > 0) { + hdcaXY_pt[2 * species]->Fill(momn, dcaXY); + } + if (track.sign() < 0) { + hdcaXY_ptanti[2 * species]->Fill(momn, dcaXY); + } + } + template + void fillhmass(T const& track, int species) + { + if (track.tpcNClsFound() < 100 || track.itsNCls() < 2) + return; + double mass; + if (species == 4 || species == 5) { + mass = 2 * track.mass(); + } else { + mass = track.mass(); + } + double momn; + if (species == 4 || species == 5) { + momn = 2 * track.pt(); + } else { + momn = track.pt(); + } + if (track.sign() > 0) { + hmass_pt[2 * species]->Fill(momn, mass * mass); + } + if (track.sign() < 0) { + hmass_ptanti[2 * species]->Fill(momn, mass * mass); + } + } + template + void fillhdelta_mass(T const& track, int species) + { + if (track.tpcNClsFound() < 100 || track.itsNCls() < 2) + return; + double mass; + if (species == 4 || species == 5) { + mass = 2 * track.mass(); + } else { + mass = track.mass(); + } + + double delta_mass = (mass - particleMasses[species]); + + hdelta_mass[2 * species]->Fill(track.pt() * particleCharge[species], delta_mass); + } + template + void fillhrapidity(T const& track, int species) + { + if (track.tpcNClsFound() < 100 || track.itsNCls() < 2) + return; + double rap = getRapidity(track, species); + hrapidity[2 * species]->Fill(rap); + } + //---------------------------------------------------------------------------------------------------------------- + template + float getTPCnSigma(T const& track, Particle const& particle) + { + const float rigidity = getRigidity(track); + if (!track.hasTPC()) + return -999; + if (particle.name == "pion" && cfgTrackPIDsettings->get("pion", "useBBparams") == 0) + return track.tpcNSigmaPi(); + if (particle.name == "proton" && cfgTrackPIDsettings->get("proton", "useBBparams") == 0) + return track.tpcNSigmaPr(); + if (particle.name == "deuteron" && cfgTrackPIDsettings->get("deuteron", "useBBparams") == 0) + return track.tpcNSigmaDe(); + if (particle.name == "triton" && cfgTrackPIDsettings->get("triton", "useBBparams") == 0) + return track.tpcNSigmaTr(); + if (particle.name == "helium3" && cfgTrackPIDsettings->get("helium3", "useBBparams") == 0) + return track.tpcNSigmaHe(); + if (particle.name == "alpha" && cfgTrackPIDsettings->get("alpha", "useBBparams") == 0) + return track.tpcNSigmaAl(); + double expBethe{tpc::BetheBlochAleph(static_cast(particle.charge * rigidity / particle.mass), particle.betheParams[0], particle.betheParams[1], particle.betheParams[2], particle.betheParams[3], particle.betheParams[4])}; + double expSigma{expBethe * particle.resolution}; + float sigmaTPC = static_cast((track.tpcSignal() - expBethe) / expSigma); + return sigmaTPC; + } + //---------------------------------------------------------------------------------------------------------------- + template + float getMeanItsClsSize(T const& track) + { + int sum = 0, n = 0; + for (int i = 0; i < 8; i++) { + sum += (track.itsClusterSizes() >> (4 * i) & 15); + if (track.itsClusterSizes() >> (4 * i) & 15) + n++; + } + return n > 0 ? static_cast(sum) / n : 0.f; + } + //---------------------------------------------------------------------------------------------------------------- + template + float getRigidity(T const& track) + { + if (!cfgRigidityCorrection) + return track.tpcInnerParam(); + bool hePID = track.pidForTracking() == o2::track::PID::Helium3 || track.pidForTracking() == o2::track::PID::Alpha; + return hePID ? track.tpcInnerParam() / 2 : track.tpcInnerParam(); + } + template + float getRapidity(T const& track, int species) + { + double momn; + TLorentzVector lorentzVector_particle; + if (species == 4 || species == 5) { + momn = 2 * track.pt(); + } else { + momn = track.pt(); + } + lorentzVector_particle.SetPtEtaPhiM(momn, track.eta(), track.phi(), particleMasses[species]); + return lorentzVector_particle.Rapidity(); + } +}; // end of the task here +//---------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------- +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Nuspex/QAHistTask.cxx b/PWGLF/Tasks/Nuspex/QAHistTask.cxx index 665195356fe..2afc40a7261 100644 --- a/PWGLF/Tasks/Nuspex/QAHistTask.cxx +++ b/PWGLF/Tasks/Nuspex/QAHistTask.cxx @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include "ReconstructionDataFormats/Track.h" @@ -44,35 +46,33 @@ struct QAHistTask { // Data HistogramRegistry QA_reg{"data_all_species", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry QA_species{"data_species", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry QA_species_pos{"data_positive", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry QA_species_neg{"data_negative", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry MC_truth_reg{"MC_particles", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry MC_recon_reg{"MC_particles_reconstructed", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry MC_recon_diff_reg{"MC_reconstructed_diff", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - OutputObj histPDG{TH1F("PDG", "PDG;PDG code", 100, 0.0, 100.0)}; + HistogramRegistry particle_reg{"data_positive", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry aparticle_reg{"data_negative", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry MC_recon_reg{"MC_particles_reco", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + OutputObj histPDG_reco{TH1I("PDG reconstructed", "PDG;PDG code", 18, 0.0, 18)}; void init(o2::framework::InitContext&) { - if ((process_pion == true && (process_kaon == true || process_proton == true || process_deuteron == true || process_triton == true || process_He3 == true || process_He4 == true)) || (process_kaon == true && (process_proton == true || process_deuteron == true || process_triton == true || process_He3 == true || process_He4 == true)) || (process_proton == true && (process_deuteron == true || process_triton == true || process_He3 == true || process_He4 == true)) || (process_deuteron == true && (process_triton == true || process_He3 == true || process_He4 == true)) || (process_triton == true && (process_He3 == true || process_He4 == true)) || (process_He3 == true && process_He4 == true)) { + if ((do_pion == true && (do_kaon == true || do_proton == true || do_deuteron == true || do_triton == true || do_He3 == true || do_He4 == true)) || (do_kaon == true && (do_proton == true || do_deuteron == true || do_triton == true || do_He3 == true || do_He4 == true)) || (do_proton == true && (do_deuteron == true || do_triton == true || do_He3 == true || do_He4 == true)) || (do_deuteron == true && (do_triton == true || do_He3 == true || do_He4 == true)) || (do_triton == true && (do_He3 == true || do_He4 == true)) || (do_He3 == true && do_He4 == true)) { LOG(fatal) << "++++++++ Can't enable more than one species at a time, use subwagons for that purpose. ++++++++"; } std::string species; - if (process_pion) + if (do_pion) species = "pi"; - if (process_kaon) + if (do_kaon) species = "ka"; - if (process_proton) + if (do_proton) species = "p"; - if (process_deuteron) + if (do_deuteron) species = "d"; - if (process_triton) + if (do_triton) species = "t"; - if (process_He3) + if (do_He3) species = "He3"; - if (process_He4) + if (do_He4) species = "He4"; std::vector ptBinning = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4., 5., 6., 8., 10., 12., 14.}; @@ -80,6 +80,7 @@ struct QAHistTask { std::vector ptBinning_diff = {-14.0, -12.0, -10.0, -8.0, -6.0, -5.0, -4.0, -3.6, -3.2, -2.8, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.3, -1.2, -1.1, -1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4., 5., 6., 8., 10., 12., 14.}; std::vector centBinning = {0., 1., 5., 10., 20., 30., 40., 50., 70., 100.}; std::vector etaBinning = {-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}; + std::vector PDGBinning = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0}; AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; AxisSpec ptAxis_short = {ptBinning_short, "Global #it{p}_{T} (GeV/#it{c})"}; @@ -88,8 +89,7 @@ struct QAHistTask { AxisSpec centralityAxis = {100, 0.0, 100.0, "VT0C (%)"}; AxisSpec centralityAxis_extended = {105, 0.0, 105.0, "VT0C (%)"}; AxisSpec etaAxis = {etaBinning, "#eta"}; - AxisSpec PDGBINNING = {20, 0.0, 20.0, "PDG code"}; - AxisSpec ptAxis_diff = {ptBinning_diff, "#it{p}_{T,diff} (GeV/#it{c})"}; + AxisSpec PDGBINNING = {PDGBinning, "PDG code"}; // +++++++++++++++++++++ Data ++++++++++++++++++++++++ @@ -131,71 +131,66 @@ struct QAHistTask { QA_species.add("histpTCorralation", "TPC-glo pT vs glo pT", HistType::kTH2F, {{100, -5.0, 5.0, "#it{p}^{global} (GeV/#it{c})"}, {80, -4.0, 4.0, "#it{p}^{TPC} - #it{p}^{global} (GeV/#it{c})"}}); // QA choosen species (positive) - QA_species_pos.add("histTpcSignalData", Form("Specific energy loss (%s)", species.c_str()), HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); - QA_species_pos.add("histTofSignalData", Form("TOF signal (%s)", species.c_str()), HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); - QA_species_pos.add("histDcaVsPtData", Form("dcaXY vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); - QA_species_pos.add("histDcaZVsPtData", Form("dcaZ vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); - QA_species_pos.add("histTOFm2", Form("TOF m^2 vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {400, 0.0, 10.0, "m^2"}}); - QA_species_pos.add("histNClusterTPC", Form("Number of Clusters in TPC vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {80, 0.0, 160.0, "nCluster"}}); - QA_species_pos.add("histNClusterITS", Form("Number of Clusters in ITS vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "ITS nCls"}}); - QA_species_pos.add("histNClusterITSib", Form("Number of Clusters in ib of ITS vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "ITS ib nCls"}}); - QA_species_pos.add("histTPCnClsFindable", Form("Findable TPC clusters (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {200, 0.0, 200.0, "nCluster"}}); - QA_species_pos.add("histTPCnClsFindableMinusFound", Form("TPC Clusters: Findable - Found (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {60, 0.0, 60.0, "nCluster"}}); - QA_species_pos.add("histTPCnClsFindableMinusCrossedRows", Form("TPC Clusters: Findable - crossed rows (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {60, 0.0, 60.0, "nCluster"}}); - QA_species_pos.add("histTPCnClsShared", Form("Number of shared TPC clusters (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {70, 0.0, 70.0, "nCluster"}}); - QA_species_pos.add("histTPCCrossedRowsOverFindableCls", Form("Ratio crossed rows over findable clusters (%s)", species.c_str()), HistType::kTH1F, {{100, 0., 2.0, "Crossed Rows / Findable Cls"}}); - QA_species_pos.add("histTPCFoundOverFindable", Form("Ratio of found over findable clusters (%s)", species.c_str()), HistType::kTH1F, {{100, 0., 2.0, "Found Cls / Findable Cls"}}); - QA_species_pos.add("histTPCFractionSharedCls", Form("Fraction of shared TPC clusters (%s)", species.c_str()), HistType::kTH1F, {{100, -2.0, 2.0, "Shared Cls"}}); - QA_species_pos.add("histChi2TPC", Form("chi^2 TPC vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {100, 0.0, 5.0, "chi^2"}}); - QA_species_pos.add("histChi2ITS", Form("chi^2 ITS vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {125, 0.0, 50.0, "chi^2"}}); - QA_species_pos.add("histChi2ITSvsITSnCls", "chi^2 ITS vs ITS nCls", HistType::kTH2F, {{125, 0.0, 50.0, "chi^2"}, {10, 0.0, 10.0, "ITS nCls"}}); - QA_species_pos.add("histChi2ITSvsITSibnCls", "chi^2 ITS vs ITS ib nCls", HistType::kTH2F, {{125, 0.0, 50.0, "chi^2"}, {10, 0.0, 10.0, "ITS ib nCls"}}); - QA_species_pos.add("histChi2ITSvsITSnClsAll", "chi^2 ITS vs ITS nCls", HistType::kTH2F, {{125, 0.0, 50.0, "chi^2"}, {10, 0.0, 10.0, "ITS nCls"}}); - QA_species_pos.add("histChi2TOF", Form("chi^2 TOF vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {75, 0.0, 15.0, "chi^2"}}); - QA_species_pos.add("histEtaWithOverFlow", Form("Pseudorapidity 0 - 105%% centrality (%s)", species.c_str()), HistType::kTH1F, {etaAxis}); - QA_species_pos.add("histEta", Form("Pseudorapidity with centrality cut (%s)", species.c_str()), HistType::kTH1F, {etaAxis}); - QA_species_pos.add("histEta_cent", Form("Pseudorapidity vs Centrality (%s)", species.c_str()), HistType::kTH2F, {centralityAxis_extended, etaAxis}); - QA_species_pos.add("histTrackLength", Form("Track length (%s)", species.c_str()), HistType::kTH1F, {{350, 0., 700., "length (cm)"}}); - QA_species_pos.add("histpTCorralation", "TPC-glo pT vs glo pT", HistType::kTH2F, {{100, -5.0, 5.0, "#it{p}^{global} (GeV/#it{c})"}, {80, -4.0, 4.0, "#it{p}^{TPC} - #it{p}^{global} (GeV/#it{c})"}}); + particle_reg.add("histTpcSignalData", Form("Specific energy loss (%s)", species.c_str()), HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); + particle_reg.add("histTofSignalData", Form("TOF signal (%s)", species.c_str()), HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); + particle_reg.add("histDcaVsPtData", Form("dcaXY vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); + particle_reg.add("histDcaZVsPtData", Form("dcaZ vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + particle_reg.add("histTOFm2", Form("TOF m^2 vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {400, 0.0, 10.0, "m^2"}}); + particle_reg.add("histNClusterTPC", Form("Number of Clusters in TPC vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {80, 0.0, 160.0, "nCluster"}}); + particle_reg.add("histNClusterITS", Form("Number of Clusters in ITS vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "ITS nCls"}}); + particle_reg.add("histNClusterITSib", Form("Number of Clusters in ib of ITS vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "ITS ib nCls"}}); + particle_reg.add("histTPCnClsFindable", Form("Findable TPC clusters (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {200, 0.0, 200.0, "nCluster"}}); + particle_reg.add("histTPCnClsFindableMinusFound", Form("TPC Clusters: Findable - Found (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {60, 0.0, 60.0, "nCluster"}}); + particle_reg.add("histTPCnClsFindableMinusCrossedRows", Form("TPC Clusters: Findable - crossed rows (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {60, 0.0, 60.0, "nCluster"}}); + particle_reg.add("histTPCnClsShared", Form("Number of shared TPC clusters (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {70, 0.0, 70.0, "nCluster"}}); + particle_reg.add("histTPCCrossedRowsOverFindableCls", Form("Ratio crossed rows over findable clusters (%s)", species.c_str()), HistType::kTH1F, {{100, 0., 2.0, "Crossed Rows / Findable Cls"}}); + particle_reg.add("histTPCFoundOverFindable", Form("Ratio of found over findable clusters (%s)", species.c_str()), HistType::kTH1F, {{100, 0., 2.0, "Found Cls / Findable Cls"}}); + particle_reg.add("histTPCFractionSharedCls", Form("Fraction of shared TPC clusters (%s)", species.c_str()), HistType::kTH1F, {{100, -2.0, 2.0, "Shared Cls"}}); + particle_reg.add("histChi2TPC", Form("chi^2 TPC vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {100, 0.0, 5.0, "chi^2"}}); + particle_reg.add("histChi2ITS", Form("chi^2 ITS vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {125, 0.0, 50.0, "chi^2"}}); + particle_reg.add("histChi2ITSvsITSnCls", "chi^2 ITS vs ITS nCls", HistType::kTH2F, {{125, 0.0, 50.0, "chi^2"}, {10, 0.0, 10.0, "ITS nCls"}}); + particle_reg.add("histChi2ITSvsITSibnCls", "chi^2 ITS vs ITS ib nCls", HistType::kTH2F, {{125, 0.0, 50.0, "chi^2"}, {10, 0.0, 10.0, "ITS ib nCls"}}); + particle_reg.add("histChi2ITSvsITSnClsAll", "chi^2 ITS vs ITS nCls", HistType::kTH2F, {{125, 0.0, 50.0, "chi^2"}, {10, 0.0, 10.0, "ITS nCls"}}); + particle_reg.add("histChi2TOF", Form("chi^2 TOF vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {75, 0.0, 15.0, "chi^2"}}); + particle_reg.add("histEtaWithOverFlow", Form("Pseudorapidity 0 - 105%% centrality (%s)", species.c_str()), HistType::kTH1F, {etaAxis}); + particle_reg.add("histEta", Form("Pseudorapidity with centrality cut (%s)", species.c_str()), HistType::kTH1F, {etaAxis}); + particle_reg.add("histEta_cent", Form("Pseudorapidity vs Centrality (%s)", species.c_str()), HistType::kTH2F, {centralityAxis_extended, etaAxis}); + particle_reg.add("histTrackLength", Form("Track length (%s)", species.c_str()), HistType::kTH1F, {{350, 0., 700., "length (cm)"}}); + particle_reg.add("histpTCorralation", "TPC-glo pT vs glo pT", HistType::kTH2F, {{100, -5.0, 5.0, "#it{p}^{global} (GeV/#it{c})"}, {80, -4.0, 4.0, "#it{p}^{TPC} - #it{p}^{global} (GeV/#it{c})"}}); // QA choosen species (negative) - QA_species_neg.add("histTpcSignalData", Form("Specific energy loss (anti-%s)", species.c_str()), HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); - QA_species_neg.add("histTofSignalData", Form("TOF signal (%s)", species.c_str()), HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); - QA_species_neg.add("histDcaVsPtData", Form("dcaXY vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); - QA_species_neg.add("histDcaZVsPtData", Form("dcaZ vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); - QA_species_neg.add("histTOFm2", Form("TOF m^2 vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {400, 0.0, 10.0, "m^2"}}); - QA_species_neg.add("histNClusterTPC", Form("Number of Clusters in TPC vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {80, 0.0, 160.0, "nCluster"}}); - QA_species_neg.add("histNClusterITS", Form("Number of Clusters in ITS vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "ITS nCls"}}); - QA_species_neg.add("histNClusterITSib", Form("Number of Clusters in ib of ITS vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "ITS ib nCls"}}); - QA_species_neg.add("histTPCnClsFindable", Form("Findable TPC clusters (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {200, 0.0, 200.0, "nCluster"}}); - QA_species_neg.add("histTPCnClsFindableMinusFound", Form("TPC Clusters: Findable - Found (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {60, 0.0, 60.0, "nCluster"}}); - QA_species_neg.add("histTPCnClsFindableMinusCrossedRows", Form("TPC Clusters: Findable - crossed rows (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {60, 0.0, 60.0, "nCluster"}}); - QA_species_neg.add("histTPCnClsShared", Form("Number of shared TPC clusters (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {70, 0.0, 70.0, "nCluster"}}); - QA_species_neg.add("histTPCCrossedRowsOverFindableCls", Form("Ratio crossed rows over findable clusters (%s)", species.c_str()), HistType::kTH1F, {{100, 0., 2.0, "Crossed Rows / Findable Cls"}}); - QA_species_neg.add("histTPCFoundOverFindable", Form("Ratio of found over findable clusters (%s)", species.c_str()), HistType::kTH1F, {{100, 0., 2.0, "Found Cls / Findable Cls"}}); - QA_species_neg.add("histTPCFractionSharedCls", Form("Fraction of shared TPC clusters (%s)", species.c_str()), HistType::kTH1F, {{100, -2.0, 2.0, "Shared Cls"}}); - QA_species_neg.add("histChi2TPC", Form("chi^2 TPC vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {100, 0.0, 5.0, "chi^2"}}); - QA_species_neg.add("histChi2ITS", Form("chi^2 ITS vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {125, 0.0, 50.0, "chi^2"}}); - QA_species_neg.add("histChi2ITSvsITSnCls", "chi^2 ITS vs ITS nCls", HistType::kTH2F, {{125, 0.0, 50.0, "chi^2"}, {10, 0.0, 10.0, "ITS nCls"}}); - QA_species_neg.add("histChi2ITSvsITSibnCls", "chi^2 ITS vs ITS ib nCls", HistType::kTH2F, {{125, 0.0, 50.0, "chi^2"}, {10, 0.0, 10.0, "ITS ib nCls"}}); - QA_species_neg.add("histChi2ITSvsITSnClsAll", "chi^2 ITS vs ITS nCls", HistType::kTH2F, {{125, 0.0, 50.0, "chi^2"}, {10, 0.0, 10.0, "ITS nCls"}}); - QA_species_neg.add("histChi2TOF", Form("chi^2 TOF vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {75, 0.0, 15.0, "chi^2"}}); - QA_species_neg.add("histEtaWithOverFlow", Form("Pseudorapidity 0 - 105%% centrality (%s)", species.c_str()), HistType::kTH1F, {etaAxis}); - QA_species_neg.add("histEta", Form("Pseudorapidity with centrality cut (%s)", species.c_str()), HistType::kTH1F, {etaAxis}); - QA_species_neg.add("histEta_cent", Form("Pseudorapidity vs Centrality (%s)", species.c_str()), HistType::kTH2F, {centralityAxis_extended, etaAxis}); - QA_species_neg.add("histTrackLength", Form("Track length (%s)", species.c_str()), HistType::kTH1F, {{350, 0., 700., "length (cm)"}}); - QA_species_neg.add("histpTCorralation", "TPC-glo pT vs glo pT", HistType::kTH2F, {{100, -5.0, 5.0, "#it{p}^{global} (GeV/#it{c})"}, {80, -4.0, 4.0, "#it{p}^{TPC} - #it{p}^{global} (GeV/#it{c})"}}); + aparticle_reg.add("histTpcSignalData", Form("Specific energy loss (anti-%s)", species.c_str()), HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); + aparticle_reg.add("histTofSignalData", Form("TOF signal (%s)", species.c_str()), HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {550, 0.0, 1.1, "#beta (TOF)"}}); + aparticle_reg.add("histDcaVsPtData", Form("dcaXY vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {250, -0.5, 0.5, "dca"}}); + aparticle_reg.add("histDcaZVsPtData", Form("dcaZ vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {1000, -2.0, 2.0, "dca"}}); + aparticle_reg.add("histTOFm2", Form("TOF m^2 vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {400, 0.0, 10.0, "m^2"}}); + aparticle_reg.add("histNClusterTPC", Form("Number of Clusters in TPC vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {80, 0.0, 160.0, "nCluster"}}); + aparticle_reg.add("histNClusterITS", Form("Number of Clusters in ITS vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "ITS nCls"}}); + aparticle_reg.add("histNClusterITSib", Form("Number of Clusters in ib of ITS vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {10, 0.0, 10.0, "ITS ib nCls"}}); + aparticle_reg.add("histTPCnClsFindable", Form("Findable TPC clusters (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {200, 0.0, 200.0, "nCluster"}}); + aparticle_reg.add("histTPCnClsFindableMinusFound", Form("TPC Clusters: Findable - Found (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {60, 0.0, 60.0, "nCluster"}}); + aparticle_reg.add("histTPCnClsFindableMinusCrossedRows", Form("TPC Clusters: Findable - crossed rows (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {60, 0.0, 60.0, "nCluster"}}); + aparticle_reg.add("histTPCnClsShared", Form("Number of shared TPC clusters (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {70, 0.0, 70.0, "nCluster"}}); + aparticle_reg.add("histTPCCrossedRowsOverFindableCls", Form("Ratio crossed rows over findable clusters (%s)", species.c_str()), HistType::kTH1F, {{100, 0., 2.0, "Crossed Rows / Findable Cls"}}); + aparticle_reg.add("histTPCFoundOverFindable", Form("Ratio of found over findable clusters (%s)", species.c_str()), HistType::kTH1F, {{100, 0., 2.0, "Found Cls / Findable Cls"}}); + aparticle_reg.add("histTPCFractionSharedCls", Form("Fraction of shared TPC clusters (%s)", species.c_str()), HistType::kTH1F, {{100, -2.0, 2.0, "Shared Cls"}}); + aparticle_reg.add("histChi2TPC", Form("chi^2 TPC vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {100, 0.0, 5.0, "chi^2"}}); + aparticle_reg.add("histChi2ITS", Form("chi^2 ITS vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {125, 0.0, 50.0, "chi^2"}}); + aparticle_reg.add("histChi2ITSvsITSnCls", "chi^2 ITS vs ITS nCls", HistType::kTH2F, {{125, 0.0, 50.0, "chi^2"}, {10, 0.0, 10.0, "ITS nCls"}}); + aparticle_reg.add("histChi2ITSvsITSibnCls", "chi^2 ITS vs ITS ib nCls", HistType::kTH2F, {{125, 0.0, 50.0, "chi^2"}, {10, 0.0, 10.0, "ITS ib nCls"}}); + aparticle_reg.add("histChi2ITSvsITSnClsAll", "chi^2 ITS vs ITS nCls", HistType::kTH2F, {{125, 0.0, 50.0, "chi^2"}, {10, 0.0, 10.0, "ITS nCls"}}); + aparticle_reg.add("histChi2TOF", Form("chi^2 TOF vs Pt (%s)", species.c_str()), HistType::kTH2F, {ptAxis, {75, 0.0, 15.0, "chi^2"}}); + aparticle_reg.add("histEtaWithOverFlow", Form("Pseudorapidity 0 - 105%% centrality (%s)", species.c_str()), HistType::kTH1F, {etaAxis}); + aparticle_reg.add("histEta", Form("Pseudorapidity with centrality cut (%s)", species.c_str()), HistType::kTH1F, {etaAxis}); + aparticle_reg.add("histEta_cent", Form("Pseudorapidity vs Centrality (%s)", species.c_str()), HistType::kTH2F, {centralityAxis_extended, etaAxis}); + aparticle_reg.add("histTrackLength", Form("Track length (%s)", species.c_str()), HistType::kTH1F, {{350, 0., 700., "length (cm)"}}); + aparticle_reg.add("histpTCorralation", "TPC-glo pT vs glo pT", HistType::kTH2F, {{100, -5.0, 5.0, "#it{p}^{global} (GeV/#it{c})"}, {80, -4.0, 4.0, "#it{p}^{TPC} - #it{p}^{global} (GeV/#it{c})"}}); // +++++++++++++++++++++ MC ++++++++++++++++++++++++++ - // MC truth - MC_truth_reg.add("histPhi", "#phi", HistType::kTH2F, {{100, 0., 2. * TMath::Pi()}, PDGBINNING}); - MC_truth_reg.add("histEta", "#eta", HistType::kTH2F, {{102, -2.01, 2.01}, PDGBINNING}); - MC_truth_reg.add("histPt", "p_{t}", HistType::kTH2F, {ptAxis, PDGBINNING}); - MC_truth_reg.add("histRecVtxMC", "MC collision z position", HistType::kTH1F, {{400, -40., +40., "z position (cm)"}}); - MC_truth_reg.add("histCentrality", "Centrality", HistType::kTH1F, {centralityAxis_extended}); - // MC reconstructed + MC_recon_reg.add("histRecVtxMC", "MC reconstructed vertex z position", HistType::kTH1F, {{400, -40., +40., "z position (cm)"}}); + MC_recon_reg.add("histCentrality", "Centrality", HistType::kTH1F, {centralityAxis_extended}); MC_recon_reg.add("histPhi", "#phi", HistType::kTH2F, {{100, 0., 2. * TMath::Pi()}, PDGBINNING}); MC_recon_reg.add("histEta", "#eta", HistType::kTH2F, {{102, -2.01, 2.01}, PDGBINNING}); MC_recon_reg.add("histPt", "p_{t}", HistType::kTH2F, {ptAxis, PDGBINNING}); @@ -223,31 +218,23 @@ struct QAHistTask { MC_recon_reg.add("histChi2TOF", "chi^2 TOF vs Pt", HistType::kTH3F, {ptAxis, {75, 0.0, 15.0, "chi^2"}, PDGBINNING}); MC_recon_reg.add("histTrackLength", "Track length", HistType::kTH2F, {{350, 0., 700., "length (cm)"}, PDGBINNING}); MC_recon_reg.add("histGlobalpDist", "Global p distribution", HistType::kTH2F, {{150, -10, +10, "#it{p} (GeV/c)"}, PDGBINNING}); - MC_recon_reg.add("histTPCpDist", "TPC p distribution", HistType::kTH2F, {{150, -10, +10, "#it{p} (GeV/c)"}, PDGBINNING}); + MC_recon_reg.add("histTPCpDist", "TPC p distribution", HistType::kTH2F, {{500, -20, +20, "#it{p} (GeV/c)"}, PDGBINNING}); MC_recon_reg.add("histTPCFractionSharedCls", "Fraction of shared TPC clusters", HistType::kTH2F, {{100, -2.0, 2.0, "Shared Cls"}, PDGBINNING}); MC_recon_reg.add("histpTCorralation", "TPC-glo p vs glo p", HistType::kTH2F, {{100, -5.0, 5.0, "#it{p}^{global} (GeV/#it{c})"}, {80, -4.0, 4.0, "#it{p}^{TPC} - #it{p}^{global} (GeV/#it{c})"}}); MC_recon_reg.add("histpTCorralation_PDG", "TPC-glo p vs glo p", HistType::kTH3F, {{100, -5.0, 5.0, "#it{p}^{global} (GeV/#it{c})"}, {80, -4.0, 4.0, "#it{p}^{TPC} - #it{p}^{global} (GeV/#it{c})"}, PDGBINNING}); - - MC_recon_reg.add("histpTCorralation_pion", "TPC-glo p vs glo p", HistType::kTH2F, {{100, -5.0, 5.0, "#it{p}^{global} (GeV/#it{c})"}, {80, -4.0, 4.0, "#it{p}^{TPC} - #it{p}^{global} (GeV/#it{c})"}}); - MC_recon_reg.add("histpTCorralation_apion", "TPC-glo p vs glo p", HistType::kTH2F, {{100, -5.0, 5.0, "#it{p}^{global} (GeV/#it{c})"}, {80, -4.0, 4.0, "#it{p}^{TPC} - #it{p}^{global} (GeV/#it{c})"}}); - MC_recon_reg.add("histpTCorralation_2", "TPC p vs global p", HistType::kTH3F, {{110, -0.5, 5.0, "#it{p}^{global} (GeV/#it{c})"}, {110, -0.5, 5.0, "#it{p}^{TPC} (GeV/#it{c})"}, PDGBINNING}); - - // MC diff (truth - reconstructed) - MC_recon_diff_reg.add("histPhiDiff", "MC t", HistType::kTH2F, {ptAxis_diff, PDGBINNING}); - MC_recon_diff_reg.add("histEtaDiff", "MC t", HistType::kTH2F, {ptAxis_diff, PDGBINNING}); - MC_recon_diff_reg.add("histPtDiff", "MC t", HistType::kTH2F, {ptAxis_diff, PDGBINNING}); } // Configurables - Configurable process_pion{"process_pion", false, "0: disabled, 1: enabled"}; - Configurable process_kaon{"process_kaon", false, "0: disabled, 1: enabled"}; - Configurable process_proton{"process_proton", false, "0: disabled, 1: enabled"}; - Configurable process_deuteron{"process_deuteron", false, "0: disabled, 1: enabled"}; - Configurable process_triton{"process_triton", false, "0: disabled, 1: enabled"}; - Configurable process_He3{"process_He3", false, "0: disabled, 1: enabled"}; - Configurable process_He4{"process_He4", false, "0: disabled, 1: enabled"}; + Configurable do_pion{"do_pion", false, "0: disabled, 1: enabled"}; + Configurable do_kaon{"do_kaon", false, "0: disabled, 1: enabled"}; + Configurable do_proton{"do_proton", false, "0: disabled, 1: enabled"}; + Configurable do_deuteron{"do_deuteron", false, "0: disabled, 1: enabled"}; + Configurable do_triton{"do_triton", false, "0: disabled, 1: enabled"}; + Configurable do_He3{"do_He3", false, "0: disabled, 1: enabled"}; + Configurable do_He4{"do_He4", false, "0: disabled, 1: enabled"}; Configurable event_selection_sel8{"event_selection_sel8", true, "0: disabled, 1: enabled"}; + Configurable event_selection_MC_sel8{"event_selection_MC_sel8", true, "Enable sel8 event selection in MC processing"}; Configurable yMin{"yMin", -0.5, "Maximum rapidity"}; Configurable yMax{"yMax", 0.5, "Minimum rapidity"}; Configurable pTmin{"pTmin", 0.1f, "min pT"}; @@ -281,9 +268,34 @@ struct QAHistTask { Configurable maxChi2TOF{"maxChi2TOF", 100.0f, "max chi2 for the TOF track segment"}; Configurable minTPCFoundOverFindable{"minTPCFoundOverFindable", 0.0f, "min ratio of found over findable clusters TPC"}; Configurable maxTPCFoundOverFindable{"maxTPCFoundOverFindable", 2.0f, "max ratio of found over findable clusters TPC"}; + Configurable removeITSROFrameBorder{"removeITSROFrameBorder", false, "Remove TF border"}; + Configurable removeNoSameBunchPileup{"removeNoSameBunchPileup", false, "Remove TF border"}; + Configurable requireIsGoodZvtxFT0vsPV{"requireIsGoodZvtxFT0vsPV", false, "Remove TF border"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "Remove TF border"}; + Configurable removeNoTimeFrameBorder{"removeNoTimeFrameBorder", false, "Remove TF border"}; + + //*********************************************************************************** + + template + bool isEventSelected(CollisionType const& collision) + { + if (removeITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) + return false; + if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) + return false; + if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + return false; + if (requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) + return false; + if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + return false; + return true; + } + + //*********************************************************************************** template - void fillDataHistograms(const CollisionType& event, const TracksType& tracks) + void fillDataHistograms(const CollisionType& event, const TracksType& tracks, const int Partilce_type) { if (event_selection_sel8 && event.sel8()) { @@ -294,28 +306,63 @@ struct QAHistTask { QA_reg.fill(HIST("histRecVtxZData"), event.posZ()); } - for (auto track : tracks) { // start loop over tracks + if (!isEventSelected(event)) + return; + + for (auto track : tracks) { // start loop over all tracks + + if (event_selection_sel8 && !event.sel8()) + continue; QA_reg.fill(HIST("histDcaVsPID"), track.dcaXY(), track.pidForTracking()); QA_reg.fill(HIST("histDcaZVsPID"), track.dcaZ(), track.pidForTracking()); QA_reg.fill(HIST("histpTCorralation"), track.sign() * track.pt(), track.tpcInnerParam() - track.pt()); - float nSigmaSpecies = 999.0; - - if (process_pion) - nSigmaSpecies = track.tpcNSigmaPi(); - if (process_kaon) - nSigmaSpecies = track.tpcNSigmaKa(); - if (process_proton) - nSigmaSpecies = track.tpcNSigmaPr(); - if (process_deuteron) - nSigmaSpecies = track.tpcNSigmaDe(); - if (process_triton) - nSigmaSpecies = track.tpcNSigmaTr(); - if (process_He3) - nSigmaSpecies = track.tpcNSigmaHe(); - if (process_He4) - nSigmaSpecies = track.tpcNSigmaAl(); + float TPCnSigma_particle = -100; + + float momentum; + TLorentzVector lorentzVector{}; + + switch (Partilce_type) { + case 0: // pi plus/minus + lorentzVector.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassPiPlus); + TPCnSigma_particle = track.tpcNSigmaPi(); + momentum = track.pt(); + break; + case 1: // (anti)kaon + lorentzVector.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassKPlus); + TPCnSigma_particle = track.tpcNSigmaKa(); + momentum = track.pt(); + break; + case 2: // (anti)proton + lorentzVector.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassProton); + TPCnSigma_particle = track.tpcNSigmaPr(); + momentum = track.pt(); + break; + case 3: // (anti)deuteron + lorentzVector.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassDeuteron); + TPCnSigma_particle = track.tpcNSigmaDe(); + momentum = track.pt(); + break; + case 4: // (anti)triton + lorentzVector.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassTriton); + TPCnSigma_particle = track.tpcNSigmaTr(); + momentum = track.pt(); + break; + case 5: // (anti)Helium-3 + lorentzVector.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassHelium3); + TPCnSigma_particle = track.tpcNSigmaHe(); + momentum = track.pt() * 2.0; + break; + case 6: // (anti)Helium-4 + lorentzVector.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassAlpha); + TPCnSigma_particle = track.tpcNSigmaAl(); + momentum = track.pt() * 2.0; + break; + default: + continue; + break; + } if (event_selection_sel8 && !event.sel8()) { continue; @@ -330,17 +377,16 @@ struct QAHistTask { float Chi2perClusterITS = track.itsChi2NCl(); if (track.sign() > 0) { - QA_reg.fill(HIST("histDcaVsPtData_particle"), track.pt(), track.dcaXY()); - QA_reg.fill(HIST("histDcaZVsPtData_particle"), track.pt(), track.dcaZ()); + QA_reg.fill(HIST("histDcaVsPtData_particle"), momentum, track.dcaXY()); + QA_reg.fill(HIST("histDcaZVsPtData_particle"), momentum, track.dcaZ()); } if (track.sign() < 0) { - QA_reg.fill(HIST("histDcaVsPtData_antiparticle"), track.pt(), track.dcaXY()); - QA_reg.fill(HIST("histDcaZVsPtData_antiparticle"), track.pt(), track.dcaZ()); + QA_reg.fill(HIST("histDcaVsPtData_antiparticle"), momentum, track.dcaXY()); + QA_reg.fill(HIST("histDcaZVsPtData_antiparticle"), momentum, track.dcaZ()); } if (custom_Track_selection && (TMath::Abs(track.dcaXY()) > maxDCA_XY || TMath::Abs(track.dcaZ()) > maxDCA_Z || TPCnumberClsFound < minTPCnClsFound || TPC_nCls_Crossed_Rows < minNCrossedRowsTPC || RatioCrossedRowsOverFindableTPC < minRatioCrossedRowsTPC || RatioCrossedRowsOverFindableTPC > maxRatioCrossedRowsTPC || Chi2perClusterTPC > maxChi2TPC || Chi2perClusterITS > maxChi2ITS || !(track.passedTPCRefit()) || !(track.passedITSRefit()) || (track.itsNClsInnerBarrel()) < minReqClusterITSib || (track.itsNCls()) < minReqClusterITS || track.length() < minTrackLength || track.length() > maxTrackLength || track.tpcNClsFindable() < minTPCNClsFindable || track.tpcNClsShared() > maxTPCNClsShared || track.tpcFoundOverFindableCls() < minTPCFoundOverFindable || track.tpcFoundOverFindableCls() > maxTPCFoundOverFindable)) { - if (track.hasTOF() && track.tofChi2() > maxChi2TOF) continue; continue; @@ -350,45 +396,28 @@ struct QAHistTask { continue; } - // cut on rapidity - TLorentzVector lorentzVector_proton{}; - TLorentzVector lorentzVector_deuteron{}; - TLorentzVector lorentzVector_triton{}; - TLorentzVector lorentzVector_He3{}; - TLorentzVector lorentzVector_He4{}; - - lorentzVector_proton.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassProton); - lorentzVector_deuteron.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassDeuteron); - lorentzVector_triton.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassTriton); - lorentzVector_He3.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassHelium3); - lorentzVector_He4.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassAlpha); - - if (lorentzVector_proton.Rapidity() < yMin || lorentzVector_proton.Rapidity() > yMax || - lorentzVector_deuteron.Rapidity() < yMin || lorentzVector_deuteron.Rapidity() > yMax || - lorentzVector_triton.Rapidity() < yMin || lorentzVector_triton.Rapidity() > yMax || - lorentzVector_He3.Rapidity() < yMin || lorentzVector_He3.Rapidity() > yMax || - lorentzVector_He4.Rapidity() < yMin || lorentzVector_He4.Rapidity() > yMax) { + if (lorentzVector.Rapidity() < yMin || lorentzVector.Rapidity() > yMax) { continue; } - if (track.pt() < pTmin || track.pt() > pTmax) + if (momentum < pTmin || momentum > pTmax) continue; - QA_reg.fill(HIST("histTpcSignalData"), track.pt() * track.sign(), track.tpcSignal()); - QA_reg.fill(HIST("histNClusterTPC"), track.pt(), track.tpcNClsCrossedRows()); - QA_reg.fill(HIST("histNClusterITS"), track.pt(), track.itsNCls()); - QA_reg.fill(HIST("histNClusterITSib"), track.pt(), track.itsNClsInnerBarrel()); - QA_reg.fill(HIST("histChi2TPC"), track.pt(), track.tpcChi2NCl()); - QA_reg.fill(HIST("histChi2ITS"), track.pt(), track.itsChi2NCl()); + QA_reg.fill(HIST("histTpcSignalData"), momentum * track.sign(), track.tpcSignal()); + QA_reg.fill(HIST("histNClusterTPC"), momentum, track.tpcNClsCrossedRows()); + QA_reg.fill(HIST("histNClusterITS"), momentum, track.itsNCls()); + QA_reg.fill(HIST("histNClusterITSib"), momentum, track.itsNClsInnerBarrel()); + QA_reg.fill(HIST("histChi2TPC"), momentum, track.tpcChi2NCl()); + QA_reg.fill(HIST("histChi2ITS"), momentum, track.itsChi2NCl()); QA_reg.fill(HIST("histChi2ITSvsITSnCls"), track.itsChi2NCl(), track.itsNCls()); QA_reg.fill(HIST("histChi2ITSvsITSibnCls"), track.itsChi2NCl(), track.itsNClsInnerBarrel()); QA_reg.fill(HIST("histChi2ITSvsITSnClsAll"), track.itsChi2NCl(), track.itsNCls()); QA_reg.fill(HIST("histChi2ITSvsITSnClsAll"), track.itsChi2NCl(), track.itsNClsInnerBarrel()); - QA_reg.fill(HIST("histTPCnClsFindable"), track.pt(), track.tpcNClsFindable()); - QA_reg.fill(HIST("histTPCnClsFindableMinusFound"), track.pt(), track.tpcNClsFindableMinusFound()); - QA_reg.fill(HIST("histTPCnClsFindableMinusCrossedRows"), track.pt(), track.tpcNClsFindableMinusCrossedRows()); - QA_reg.fill(HIST("histTPCnClsShared"), track.pt(), track.tpcNClsShared()); - QA_reg.fill(HIST("histChi2TOF"), track.pt(), track.tofChi2()); + QA_reg.fill(HIST("histTPCnClsFindable"), momentum, track.tpcNClsFindable()); + QA_reg.fill(HIST("histTPCnClsFindableMinusFound"), momentum, track.tpcNClsFindableMinusFound()); + QA_reg.fill(HIST("histTPCnClsFindableMinusCrossedRows"), momentum, track.tpcNClsFindableMinusCrossedRows()); + QA_reg.fill(HIST("histTPCnClsShared"), momentum, track.tpcNClsShared()); + QA_reg.fill(HIST("histChi2TOF"), momentum, track.tofChi2()); QA_reg.fill(HIST("histTrackLength"), track.length()); QA_reg.fill(HIST("histTPCCrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls()); QA_reg.fill(HIST("histTPCFoundOverFindable"), track.tpcFoundOverFindableCls()); @@ -411,38 +440,37 @@ struct QAHistTask { Float_t TOFmass2 = ((track.mass()) * (track.mass())); - QA_reg.fill(HIST("histTOFm2"), track.pt(), TOFmass2); - QA_reg.fill(HIST("histTofSignalData"), track.pt() * track.sign(), track.beta()); + QA_reg.fill(HIST("histTOFm2"), momentum, TOFmass2); + QA_reg.fill(HIST("histTofSignalData"), momentum * track.sign(), track.beta()); } - // fill QA histograms - if (TMath::Abs(nSigmaSpecies) < nsigmacut) { + if (TMath::Abs(TPCnSigma_particle) < nsigmacut) { - QA_species.fill(HIST("histpTCorralation"), track.sign() * track.pt(), track.tpcInnerParam() - track.pt()); + QA_species.fill(HIST("histpTCorralation"), track.sign() * momentum, track.tpcInnerParam() - momentum); if (track.sign() > 0) { - QA_species_pos.fill(HIST("histDcaVsPtData"), track.pt(), track.dcaXY()); - QA_species_pos.fill(HIST("histDcaZVsPtData"), track.pt(), track.dcaZ()); - QA_species_pos.fill(HIST("histTpcSignalData"), track.pt(), track.tpcSignal()); - QA_species_pos.fill(HIST("histNClusterTPC"), track.pt(), track.tpcNClsCrossedRows()); - QA_species_pos.fill(HIST("histNClusterITS"), track.pt(), track.itsNCls()); - QA_species_pos.fill(HIST("histNClusterITSib"), track.pt(), track.itsNClsInnerBarrel()); - QA_species_pos.fill(HIST("histChi2TPC"), track.pt(), track.tpcChi2NCl()); - QA_species_pos.fill(HIST("histChi2ITS"), track.pt(), track.itsChi2NCl()); - QA_species_pos.fill(HIST("histChi2ITSvsITSnCls"), track.itsChi2NCl(), track.itsNCls()); - QA_species_pos.fill(HIST("histChi2ITSvsITSibnCls"), track.itsChi2NCl(), track.itsNClsInnerBarrel()); - QA_species_pos.fill(HIST("histChi2ITSvsITSnClsAll"), track.itsChi2NCl(), track.itsNCls()); - QA_species_pos.fill(HIST("histChi2ITSvsITSnClsAll"), track.itsChi2NCl(), track.itsNClsInnerBarrel()); - QA_species_pos.fill(HIST("histTPCnClsFindable"), track.pt(), track.tpcNClsFindable()); - QA_species_pos.fill(HIST("histTPCnClsFindableMinusFound"), track.pt(), track.tpcNClsFindableMinusFound()); - QA_species_pos.fill(HIST("histTPCnClsFindableMinusCrossedRows"), track.pt(), track.tpcNClsFindableMinusCrossedRows()); - QA_species_pos.fill(HIST("histTPCnClsShared"), track.pt(), track.tpcNClsShared()); - QA_species_pos.fill(HIST("histChi2TOF"), track.pt(), track.tofChi2()); - QA_species_pos.fill(HIST("histTrackLength"), track.length()); - QA_species_pos.fill(HIST("histTPCCrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls()); - QA_species_pos.fill(HIST("histTPCFoundOverFindable"), track.tpcFoundOverFindableCls()); - QA_species_pos.fill(HIST("histTPCFractionSharedCls"), track.tpcFractionSharedCls()); - QA_species_pos.fill(HIST("histpTCorralation"), track.sign() * track.pt(), track.tpcInnerParam() - track.pt()); + particle_reg.fill(HIST("histDcaVsPtData"), momentum, track.dcaXY()); + particle_reg.fill(HIST("histDcaZVsPtData"), momentum, track.dcaZ()); + particle_reg.fill(HIST("histTpcSignalData"), momentum, track.tpcSignal()); + particle_reg.fill(HIST("histNClusterTPC"), momentum, track.tpcNClsCrossedRows()); + particle_reg.fill(HIST("histNClusterITS"), momentum, track.itsNCls()); + particle_reg.fill(HIST("histNClusterITSib"), momentum, track.itsNClsInnerBarrel()); + particle_reg.fill(HIST("histChi2TPC"), momentum, track.tpcChi2NCl()); + particle_reg.fill(HIST("histChi2ITS"), momentum, track.itsChi2NCl()); + particle_reg.fill(HIST("histChi2ITSvsITSnCls"), track.itsChi2NCl(), track.itsNCls()); + particle_reg.fill(HIST("histChi2ITSvsITSibnCls"), track.itsChi2NCl(), track.itsNClsInnerBarrel()); + particle_reg.fill(HIST("histChi2ITSvsITSnClsAll"), track.itsChi2NCl(), track.itsNCls()); + particle_reg.fill(HIST("histChi2ITSvsITSnClsAll"), track.itsChi2NCl(), track.itsNClsInnerBarrel()); + particle_reg.fill(HIST("histTPCnClsFindable"), momentum, track.tpcNClsFindable()); + particle_reg.fill(HIST("histTPCnClsFindableMinusFound"), momentum, track.tpcNClsFindableMinusFound()); + particle_reg.fill(HIST("histTPCnClsFindableMinusCrossedRows"), momentum, track.tpcNClsFindableMinusCrossedRows()); + particle_reg.fill(HIST("histTPCnClsShared"), momentum, track.tpcNClsShared()); + particle_reg.fill(HIST("histChi2TOF"), momentum, track.tofChi2()); + particle_reg.fill(HIST("histTrackLength"), track.length()); + particle_reg.fill(HIST("histTPCCrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls()); + particle_reg.fill(HIST("histTPCFoundOverFindable"), track.tpcFoundOverFindableCls()); + particle_reg.fill(HIST("histTPCFractionSharedCls"), track.tpcFractionSharedCls()); + particle_reg.fill(HIST("histpTCorralation"), track.sign() * momentum, track.tpcInnerParam() - momentum); if (track.hasTOF()) { @@ -461,33 +489,33 @@ struct QAHistTask { Float_t TOFmass2 = ((track.mass()) * (track.mass())); - QA_species_pos.fill(HIST("histTOFm2"), track.pt(), TOFmass2); - QA_species_pos.fill(HIST("histTofSignalData"), track.pt() * track.sign(), track.beta()); + particle_reg.fill(HIST("histTOFm2"), momentum, TOFmass2); + particle_reg.fill(HIST("histTofSignalData"), momentum * track.sign(), track.beta()); } } if (track.sign() < 0) { - QA_species_neg.fill(HIST("histDcaVsPtData"), track.pt(), track.dcaXY()); - QA_species_neg.fill(HIST("histDcaZVsPtData"), track.pt(), track.dcaZ()); - QA_species_neg.fill(HIST("histTpcSignalData"), track.pt(), track.tpcSignal()); - QA_species_neg.fill(HIST("histNClusterTPC"), track.pt(), track.tpcNClsCrossedRows()); - QA_species_neg.fill(HIST("histNClusterITS"), track.pt(), track.itsNCls()); - QA_species_neg.fill(HIST("histNClusterITSib"), track.pt(), track.itsNClsInnerBarrel()); - QA_species_neg.fill(HIST("histChi2TPC"), track.pt(), track.tpcChi2NCl()); - QA_species_neg.fill(HIST("histChi2ITS"), track.pt(), track.itsChi2NCl()); - QA_species_neg.fill(HIST("histChi2ITSvsITSnCls"), track.itsChi2NCl(), track.itsNCls()); - QA_species_neg.fill(HIST("histChi2ITSvsITSibnCls"), track.itsChi2NCl(), track.itsNClsInnerBarrel()); - QA_species_neg.fill(HIST("histChi2ITSvsITSnClsAll"), track.itsChi2NCl(), track.itsNCls()); - QA_species_neg.fill(HIST("histChi2ITSvsITSnClsAll"), track.itsChi2NCl(), track.itsNClsInnerBarrel()); - QA_species_neg.fill(HIST("histTPCnClsFindable"), track.pt(), track.tpcNClsFindable()); - QA_species_neg.fill(HIST("histTPCnClsFindableMinusFound"), track.pt(), track.tpcNClsFindableMinusFound()); - QA_species_neg.fill(HIST("histTPCnClsFindableMinusCrossedRows"), track.pt(), track.tpcNClsFindableMinusCrossedRows()); - QA_species_neg.fill(HIST("histTPCnClsShared"), track.pt(), track.tpcNClsShared()); - QA_species_neg.fill(HIST("histChi2TOF"), track.pt(), track.tofChi2()); - QA_species_neg.fill(HIST("histTrackLength"), track.length()); - QA_species_neg.fill(HIST("histTPCCrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls()); - QA_species_neg.fill(HIST("histTPCFoundOverFindable"), track.tpcFoundOverFindableCls()); - QA_species_neg.fill(HIST("histTPCFractionSharedCls"), track.tpcFractionSharedCls()); - QA_species_neg.fill(HIST("histpTCorralation"), track.sign() * track.pt(), track.tpcInnerParam() - track.pt()); + aparticle_reg.fill(HIST("histDcaVsPtData"), momentum, track.dcaXY()); + aparticle_reg.fill(HIST("histDcaZVsPtData"), momentum, track.dcaZ()); + aparticle_reg.fill(HIST("histTpcSignalData"), momentum, track.tpcSignal()); + aparticle_reg.fill(HIST("histNClusterTPC"), momentum, track.tpcNClsCrossedRows()); + aparticle_reg.fill(HIST("histNClusterITS"), momentum, track.itsNCls()); + aparticle_reg.fill(HIST("histNClusterITSib"), momentum, track.itsNClsInnerBarrel()); + aparticle_reg.fill(HIST("histChi2TPC"), momentum, track.tpcChi2NCl()); + aparticle_reg.fill(HIST("histChi2ITS"), momentum, track.itsChi2NCl()); + aparticle_reg.fill(HIST("histChi2ITSvsITSnCls"), track.itsChi2NCl(), track.itsNCls()); + aparticle_reg.fill(HIST("histChi2ITSvsITSibnCls"), track.itsChi2NCl(), track.itsNClsInnerBarrel()); + aparticle_reg.fill(HIST("histChi2ITSvsITSnClsAll"), track.itsChi2NCl(), track.itsNCls()); + aparticle_reg.fill(HIST("histChi2ITSvsITSnClsAll"), track.itsChi2NCl(), track.itsNClsInnerBarrel()); + aparticle_reg.fill(HIST("histTPCnClsFindable"), momentum, track.tpcNClsFindable()); + aparticle_reg.fill(HIST("histTPCnClsFindableMinusFound"), momentum, track.tpcNClsFindableMinusFound()); + aparticle_reg.fill(HIST("histTPCnClsFindableMinusCrossedRows"), momentum, track.tpcNClsFindableMinusCrossedRows()); + aparticle_reg.fill(HIST("histTPCnClsShared"), momentum, track.tpcNClsShared()); + aparticle_reg.fill(HIST("histChi2TOF"), momentum, track.tofChi2()); + aparticle_reg.fill(HIST("histTrackLength"), track.length()); + aparticle_reg.fill(HIST("histTPCCrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls()); + aparticle_reg.fill(HIST("histTPCFoundOverFindable"), track.tpcFoundOverFindableCls()); + aparticle_reg.fill(HIST("histTPCFractionSharedCls"), track.tpcFractionSharedCls()); + aparticle_reg.fill(HIST("histpTCorralation"), track.sign() * momentum, track.tpcInnerParam() - momentum); if (track.hasTOF()) { @@ -506,12 +534,12 @@ struct QAHistTask { Float_t TOFmass2 = ((track.mass()) * (track.mass())); - QA_species_neg.fill(HIST("histTOFm2"), track.pt(), TOFmass2); - QA_species_neg.fill(HIST("histTofSignalData"), track.pt() * track.sign(), track.beta()); + aparticle_reg.fill(HIST("histTOFm2"), momentum, TOFmass2); + aparticle_reg.fill(HIST("histTofSignalData"), momentum * track.sign(), track.beta()); } } } - } // end loop over tracks + } } //******************************************************************************************************* @@ -528,7 +556,10 @@ struct QAHistTask { QA_reg.fill(HIST("histCentrality"), event.centFT0C()); } - for (auto track : tracks) { // start loop over tracks + if (!isEventSelected(event)) + return; + + for (auto track : tracks) { if (event_selection_sel8 && !event.sel8()) { continue; @@ -547,111 +578,219 @@ struct QAHistTask { Filter collisionFilter = (nabs(aod::collision::posZ) < cfgCutVertex); Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta && requireGlobalTrackWoDCAInFilter()); - using EventCandidatesData = soa::Filtered>; + using EventCandidates = soa::Filtered>; - using EventCandidatesDataCent = soa::Filtered>; + using EventCandidatesCent = soa::Filtered>; - using TrackCandidatesData = soa::Filtered>; + using TrackCandidates = soa::Filtered>; - void processData(EventCandidatesData::iterator const& event, TrackCandidatesData const& tracks) + void processData(EventCandidates::iterator const& event, TrackCandidates const& tracks) { - fillDataHistograms(event, tracks); + if (do_pion) + fillDataHistograms(event, tracks, 0); // pion + if (do_kaon) + fillDataHistograms(event, tracks, 1); // kaon + if (do_proton) + fillDataHistograms(event, tracks, 2); // proton + if (do_deuteron) + fillDataHistograms(event, tracks, 3); // deuteron + if (do_triton) + fillDataHistograms(event, tracks, 4); // triton + if (do_He3) + fillDataHistograms(event, tracks, 5); // He3 + if (do_He4) + fillDataHistograms(event, tracks, 6); // He4 } PROCESS_SWITCH(QAHistTask, processData, "process data", true); - void processDataCent(EventCandidatesDataCent::iterator const& event, TrackCandidatesData const& tracks) + void processDataCent(EventCandidatesCent::iterator const& event, TrackCandidates const& tracks) { - fillDataHistograms(event, tracks); + if (do_pion) + fillDataHistograms(event, tracks, 0); // pion + if (do_kaon) + fillDataHistograms(event, tracks, 1); // kaon + if (do_proton) + fillDataHistograms(event, tracks, 2); // proton + if (do_deuteron) + fillDataHistograms(event, tracks, 3); // deuteron + if (do_triton) + fillDataHistograms(event, tracks, 4); // triton + if (do_He3) + fillDataHistograms(event, tracks, 5); // He3 + if (do_He4) + fillDataHistograms(event, tracks, 6); // He4 fillDataCentHistorgrams(event, tracks); } PROCESS_SWITCH(QAHistTask, processDataCent, "process data containing centralities", false); - void processMC(soa::Join::iterator const& collisions, soa::Filtered> const& tracks, - aod::McParticles& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) + void processMCreco(soa::Join::iterator const& collisions, soa::Filtered> const& tracks, + aod::McParticles& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) { - MC_truth_reg.fill(HIST("histRecVtxMC"), collisions.posZ()); + if (event_selection_MC_sel8 && !collisions.sel8()) + return; + MC_recon_reg.fill(HIST("histRecVtxMC"), collisions.posZ()); + MC_recon_reg.fill(HIST("histCentrality"), collisions.centFT0C()); + if (!isEventSelected(collisions)) + return; for (auto& track : tracks) { const auto particle = track.mcParticle(); - const auto pdg = Form("%i", particle.pdgCode()); - if (!particle.isPhysicalPrimary()) continue; - histPDG->Fill(pdg, 1); - const float pdgbin = histPDG->GetXaxis()->GetBinCenter(histPDG->GetXaxis()->FindBin(pdg)); + MC_recon_reg.fill(HIST("histChi2ITSvsITSnCls"), track.itsChi2NCl(), track.itsNCls()); + MC_recon_reg.fill(HIST("histChi2ITSvsITSibnCls"), track.itsChi2NCl(), track.itsNClsInnerBarrel()); + MC_recon_reg.fill(HIST("histChi2ITSvsITSnClsAll"), track.itsChi2NCl(), track.itsNCls()); + MC_recon_reg.fill(HIST("histChi2ITSvsITSnClsAll"), track.itsChi2NCl(), track.itsNClsInnerBarrel()); + MC_recon_reg.fill(HIST("histpTCorralation"), track.sign() * track.p(), track.tpcInnerParam() - track.p()); - MC_truth_reg.fill(HIST("histPhi"), particle.phi(), pdgbin); - MC_truth_reg.fill(HIST("histEta"), particle.eta(), pdgbin); - MC_truth_reg.fill(HIST("histPt"), particle.pt(), pdgbin); + if ((particle.pdgCode() == 1000020030) || (particle.pdgCode() == -1000020030) || (particle.pdgCode() == 1000020040) || (particle.pdgCode() == -1000020040)) { + MC_recon_reg.fill(HIST("histTpcSignalData_all_species"), track.pt() * 2.0 * track.sign(), track.tpcSignal()); + } else { + MC_recon_reg.fill(HIST("histTpcSignalData_all_species"), track.pt() * track.sign(), track.tpcSignal()); + } + if (track.hasTOF()) { + if ((particle.pdgCode() == 1000020030) || (particle.pdgCode() == -1000020030) || (particle.pdgCode() == 1000020040) || (particle.pdgCode() == -1000020040)) { + MC_recon_reg.fill(HIST("histTofSignalData_all_species"), track.pt() * 2.0 * track.sign(), track.beta()); + } else { + MC_recon_reg.fill(HIST("histTofSignalData_all_species"), track.pt() * track.sign(), track.beta()); + } + } + + int pdgbin = -10; + TLorentzVector lorentzVector_particle_MC{}; + switch (particle.pdgCode()) { + case +211: + histPDG_reco->AddBinContent(1); + pdgbin = 0; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassPiPlus); + break; + case -211: + histPDG_reco->AddBinContent(2); + pdgbin = 1; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassPiPlus); + break; + case +321: + histPDG_reco->AddBinContent(3); + pdgbin = 2; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassKPlus); + break; + case -321: + histPDG_reco->AddBinContent(4); + pdgbin = 3; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassKPlus); + break; + case +2212: + histPDG_reco->AddBinContent(5); + pdgbin = 4; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassProton); + break; + case -2212: + histPDG_reco->AddBinContent(6); + pdgbin = 5; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassProton); + break; + case +1000010020: + histPDG_reco->AddBinContent(7); + pdgbin = 6; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassDeuteron); + break; + case -1000010020: + histPDG_reco->AddBinContent(8); + pdgbin = 7; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassDeuteron); + break; + case +1000010030: + histPDG_reco->AddBinContent(9); + pdgbin = 8; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassTriton); + break; + case -1000010030: + histPDG_reco->AddBinContent(10); + pdgbin = 9; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassTriton); + break; + case +1000020030: + histPDG_reco->AddBinContent(11); + pdgbin = 10; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassHelium3); + break; + case -1000020030: + histPDG_reco->AddBinContent(12); + pdgbin = 11; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassHelium3); + break; + case +1000020040: + histPDG_reco->AddBinContent(13); + pdgbin = 12; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassAlpha); + break; + case -1000020040: + histPDG_reco->AddBinContent(14); + pdgbin = 13; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassAlpha); + break; + default: + pdgbin = -10; + continue; + break; + } MC_recon_reg.fill(HIST("histPhi"), track.phi(), pdgbin); MC_recon_reg.fill(HIST("histEta"), track.eta(), pdgbin); - MC_recon_reg.fill(HIST("histPt"), track.pt(), pdgbin); - MC_recon_reg.fill(HIST("histDCA"), track.pt(), track.dcaXY(), pdgbin); - MC_recon_reg.fill(HIST("histDCAz"), track.pt(), track.dcaZ(), pdgbin); - MC_recon_reg.fill(HIST("histTpcSignalData"), track.pt() * track.sign(), track.tpcSignal(), pdgbin); - MC_recon_reg.fill(HIST("histTpcSignalData_all_species"), track.pt() * track.sign(), track.tpcSignal()); - MC_recon_reg.fill(HIST("histNClusterTPC"), track.pt(), track.tpcNClsCrossedRows(), pdgbin); - MC_recon_reg.fill(HIST("histNClusterITS"), track.pt(), track.itsNCls(), pdgbin); - MC_recon_reg.fill(HIST("histNClusterITSib"), track.pt(), track.itsNClsInnerBarrel(), pdgbin); - MC_recon_reg.fill(HIST("histTPCnClsFindable"), track.pt(), track.tpcNClsFindable(), pdgbin); - MC_recon_reg.fill(HIST("histTPCnClsFindableMinusFound"), track.pt(), track.tpcNClsFindableMinusFound(), pdgbin); - MC_recon_reg.fill(HIST("histTPCnClsFindableMinusCrossedRows"), track.pt(), track.tpcNClsFindableMinusCrossedRows(), pdgbin); - MC_recon_reg.fill(HIST("histTPCnClsShared"), track.pt(), track.tpcNClsShared(), pdgbin); MC_recon_reg.fill(HIST("histTPCCrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls(), pdgbin); MC_recon_reg.fill(HIST("histTPCFoundOverFindable"), track.tpcFoundOverFindableCls(), pdgbin); - MC_recon_reg.fill(HIST("histChi2TPC"), track.pt(), track.tpcChi2NCl(), pdgbin); - MC_recon_reg.fill(HIST("histChi2ITS"), track.pt(), track.itsChi2NCl(), pdgbin); - MC_recon_reg.fill(HIST("histChi2ITSvsITSnCls"), track.itsChi2NCl(), track.itsNCls()); - MC_recon_reg.fill(HIST("histChi2ITSvsITSibnCls"), track.itsChi2NCl(), track.itsNClsInnerBarrel()); - MC_recon_reg.fill(HIST("histChi2ITSvsITSnClsAll"), track.itsChi2NCl(), track.itsNCls()); - MC_recon_reg.fill(HIST("histChi2ITSvsITSnClsAll"), track.itsChi2NCl(), track.itsNClsInnerBarrel()); - MC_recon_reg.fill(HIST("histChi2TOF"), track.pt(), track.tofChi2(), pdgbin); MC_recon_reg.fill(HIST("histTrackLength"), track.length(), pdgbin); MC_recon_reg.fill(HIST("histTPCFractionSharedCls"), track.tpcFractionSharedCls(), pdgbin); - MC_recon_reg.fill(HIST("histpTCorralation"), track.sign() * track.p(), track.tpcInnerParam() - track.p()); MC_recon_reg.fill(HIST("histpTCorralation_PDG"), track.sign() * track.p(), track.tpcInnerParam() - track.p(), pdgbin); - MC_recon_reg.fill(HIST("histGlobalpDist"), track.p(), pdgbin); MC_recon_reg.fill(HIST("histTPCpDist"), track.tpcInnerParam(), pdgbin); - MC_recon_reg.fill(HIST("histpTCorralation_2"), track.p(), track.tpcInnerParam(), pdgbin); - - if (particle.pdgCode() == 211) - MC_recon_reg.fill(HIST("histpTCorralation_pion"), track.sign() * track.p(), track.tpcInnerParam() - track.p()); - if (particle.pdgCode() == -211) - MC_recon_reg.fill(HIST("histpTCorralation_apion"), track.sign() * track.p(), track.tpcInnerParam() - track.p()); + if ((particle.pdgCode() == 1000020030) || (particle.pdgCode() == -1000020030) || (particle.pdgCode() == 1000020040) || (particle.pdgCode() == -1000020040)) { + MC_recon_reg.fill(HIST("histPt"), track.pt() * 2.0, pdgbin); + MC_recon_reg.fill(HIST("histDCA"), track.pt() * 2.0, track.dcaXY(), pdgbin); + MC_recon_reg.fill(HIST("histDCAz"), track.pt() * 2.0, track.dcaZ(), pdgbin); + MC_recon_reg.fill(HIST("histTpcSignalData"), track.pt() * 2.0 * track.sign(), track.tpcSignal(), pdgbin); + MC_recon_reg.fill(HIST("histNClusterTPC"), track.pt() * 2.0, track.tpcNClsCrossedRows(), pdgbin); + MC_recon_reg.fill(HIST("histNClusterITS"), track.pt() * 2.0, track.itsNCls(), pdgbin); + MC_recon_reg.fill(HIST("histNClusterITSib"), track.pt() * 2.0, track.itsNClsInnerBarrel(), pdgbin); + MC_recon_reg.fill(HIST("histTPCnClsFindable"), track.pt() * 2.0, track.tpcNClsFindable(), pdgbin); + MC_recon_reg.fill(HIST("histTPCnClsFindableMinusFound"), track.pt() * 2.0, track.tpcNClsFindableMinusFound(), pdgbin); + MC_recon_reg.fill(HIST("histTPCnClsFindableMinusCrossedRows"), track.pt() * 2.0, track.tpcNClsFindableMinusCrossedRows(), pdgbin); + MC_recon_reg.fill(HIST("histTPCnClsShared"), track.pt() * 2.0, track.tpcNClsShared(), pdgbin); + MC_recon_reg.fill(HIST("histChi2TPC"), track.pt() * 2.0, track.tpcChi2NCl(), pdgbin); + MC_recon_reg.fill(HIST("histChi2ITS"), track.pt() * 2.0, track.itsChi2NCl(), pdgbin); + MC_recon_reg.fill(HIST("histChi2TOF"), track.pt() * 2.0, track.tofChi2(), pdgbin); + } else { + MC_recon_reg.fill(HIST("histPt"), track.pt(), pdgbin); + MC_recon_reg.fill(HIST("histDCA"), track.pt(), track.dcaXY(), pdgbin); + MC_recon_reg.fill(HIST("histDCAz"), track.pt(), track.dcaZ(), pdgbin); + MC_recon_reg.fill(HIST("histTpcSignalData"), track.pt() * track.sign(), track.tpcSignal(), pdgbin); + MC_recon_reg.fill(HIST("histNClusterTPC"), track.pt(), track.tpcNClsCrossedRows(), pdgbin); + MC_recon_reg.fill(HIST("histNClusterITS"), track.pt(), track.itsNCls(), pdgbin); + MC_recon_reg.fill(HIST("histNClusterITSib"), track.pt(), track.itsNClsInnerBarrel(), pdgbin); + MC_recon_reg.fill(HIST("histTPCnClsFindable"), track.pt(), track.tpcNClsFindable(), pdgbin); + MC_recon_reg.fill(HIST("histTPCnClsFindableMinusFound"), track.pt(), track.tpcNClsFindableMinusFound(), pdgbin); + MC_recon_reg.fill(HIST("histTPCnClsFindableMinusCrossedRows"), track.pt(), track.tpcNClsFindableMinusCrossedRows(), pdgbin); + MC_recon_reg.fill(HIST("histTPCnClsShared"), track.pt(), track.tpcNClsShared(), pdgbin); + MC_recon_reg.fill(HIST("histChi2TPC"), track.pt(), track.tpcChi2NCl(), pdgbin); + MC_recon_reg.fill(HIST("histChi2ITS"), track.pt(), track.itsChi2NCl(), pdgbin); + MC_recon_reg.fill(HIST("histChi2TOF"), track.pt(), track.tofChi2(), pdgbin); + } if (track.hasTOF()) { Float_t TOFmass2 = ((track.mass()) * (track.mass())); - - MC_recon_reg.fill(HIST("histTOFm2"), track.pt(), TOFmass2, pdgbin); - MC_recon_reg.fill(HIST("histTofSignalData"), track.pt() * track.sign(), track.beta(), pdgbin); - MC_recon_reg.fill(HIST("histTofSignalData_all_species"), track.pt() * track.sign(), track.beta()); - } - - MC_recon_diff_reg.fill(HIST("histEtaDiff"), particle.eta() - track.eta(), pdgbin); - auto delta = particle.phi() - track.phi(); - if (delta > TMath::Pi()) { - delta -= 2 * TMath::Pi(); - } - if (delta < -TMath::Pi()) { - delta += 2 * TMath::Pi(); + if ((particle.pdgCode() == 1000020030) || (particle.pdgCode() == -1000020030) || (particle.pdgCode() == 1000020040) || (particle.pdgCode() == -1000020040)) { + MC_recon_reg.fill(HIST("histTOFm2"), track.pt() * 2.0, TOFmass2, pdgbin); + MC_recon_reg.fill(HIST("histTofSignalData"), track.pt() * 2.0 * track.sign(), track.beta(), pdgbin); + } else { + MC_recon_reg.fill(HIST("histTOFm2"), track.pt(), TOFmass2, pdgbin); + MC_recon_reg.fill(HIST("histTofSignalData"), track.pt() * track.sign(), track.beta(), pdgbin); + } } - - MC_recon_diff_reg.fill(HIST("histPhiDiff"), delta, pdgbin); - MC_recon_diff_reg.fill(HIST("histPtDiff"), particle.pt() - track.pt(), pdgbin); } } - PROCESS_SWITCH(QAHistTask, processMC, "process MC", false); - - void processMCCent(soa::Join::iterator const& collisions) - { - - MC_truth_reg.fill(HIST("histCentrality"), collisions.centFT0C()); - } - PROCESS_SWITCH(QAHistTask, processMCCent, "process MC with centrality", false); + PROCESS_SWITCH(QAHistTask, processMCreco, "process MC", false); }; //**************************************************************************************************** diff --git a/PWGLF/Tasks/Nuspex/QCspectraTPC.cxx b/PWGLF/Tasks/Nuspex/QCspectraTPC.cxx index 9f6f917cedf..079b0d44a31 100644 --- a/PWGLF/Tasks/Nuspex/QCspectraTPC.cxx +++ b/PWGLF/Tasks/Nuspex/QCspectraTPC.cxx @@ -21,10 +21,12 @@ #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/Core/TrackSelection.h" - +#include "Common/DataModel/McCollisionExtra.h" #include "Common/Core/TrackSelectionDefaults.h" #include "PWGLF/DataModel/LFParticleIdentification.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "TPDGCode.h" + using namespace o2; using namespace o2::framework; using namespace std; @@ -53,8 +55,9 @@ struct QCspectraTPC { Configurable cfgCutDCAZ{"cfgCutDCAZ", 2.0f, "DCAZ range for tracks"}; Configurable maxChi2PerClusterTPC{"maxChi2PerClusterTPC", 4, "Additional cut on the maximum value of the chi2 per cluster in the TPC"}; Configurable maxChi2PerClusterITS{"maxChi2PerClusterITS", 36, "Additional cut on the maximum value of the chi2 per cluster in the ITS"}; - Configurable minTPCNClsFound{"minTPCNClsFound", 100, "Additional cut on the minimum value of the number of found clusters in the TPC"}; + Configurable minTPCNClsFound{"minTPCNClsFound", 70, "Additional cut on the minimum value of the number of found clusters in the TPC"}; Configurable minNCrossedRowsOverFindableClustersTPC{"minNCrossedRowsOverFindableClustersTPC", 0.8f, "Additional cut on the minimum value of the ratio between crossed rows and findable clusters in the TPC"}; + Configurable multiplicityEstimator{"multiplicityEstimator", 8, "Flag to use a multiplicity estimator: 0 no multiplicity, 1 MultFV0M, 2 MultFT0M, 3 MultFDDM, 4 MultTracklets, 5 MultTPC, 6 MultNTracksPV, 7 MultNTracksPVeta1, 8 CentralityFT0C, 9 CentralityFT0M, 10 CentralityFV0A"}; Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 100, "Additional cut on the minimum number of crossed rows in the TPC"}; Configurable ITSNCls{"ITSNCls", 7, "Additional cut on the minimum number of ITS clusters"}; ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0}, "Binning of the pT axis"}; @@ -65,6 +68,7 @@ struct QCspectraTPC { ConfigurableAxis binsPTPC{"binsPTPC", {300, -3, 3}, "Binning of the TPC p axis"}; ConfigurableAxis binsDeltaP{"binsDeltaP", {600, -3, 3}, "Binning of the #delta P axis"}; ConfigurableAxis binsnsigmaTPC{"binsnsigmaTPC", {200, -10, 10}, "Binning of the n_{#sigma, TPC} axis"}; + ConfigurableAxis binsMultiplicity{"binsMultiplicity", {100, 0, 100}, "Binning for multiplicity"}; // Histograms HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(o2::framework::InitContext&) @@ -81,7 +85,7 @@ struct QCspectraTPC { const AxisSpec dcaXyAxis{binsDca, "DCA_{xy} (cm)"}; const AxisSpec phiAxis{200, 0, 7, "#it{#varphi} (rad)"}; const AxisSpec dcaZAxis{binsDca, "DCA_{z} (cm)"}; - + const AxisSpec multAxis{binsMultiplicity, "multiplicity estimator"}; histos.add("event/vertexz", "collision z position", HistType::kTH1F, {{100, -10., +10., "z position (cm)"}}); histos.add("etaHistogram", "etaHistogram", kTH1F, {axisEta}); histos.add("rapidityHistogram", "rapidityHistogram", kTH1F, {axisY}); @@ -131,12 +135,71 @@ struct QCspectraTPC { histos.add("spectraGen/proton/pos/histGenPtProtonSec", "generated particles", HistType::kTH1F, {ptAxis}); histos.add("spectraRec/proton/pos/histRecPtProton", "recosntructed particles", HistType::kTH1F, {ptAxis}); histos.add("spectraRec/proton/pos/histRecPtProtonPrim", "recosntructed particles", HistType::kTH1F, {ptAxis}); + histos.add("MC/pi/pos/prm/pt/num", "recosntructed MC #pi^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/pos/prm/pt/num", "recosntructed MC k^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/pos/prm/pt/num", "recosntructed MC p", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pi/neg/prm/pt/num", "recosntructed MC #pi^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/neg/prm/pt/num", "recosntructed MC k^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/neg/prm/pt/num", "recosntructed MC #bar{p}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pi/pos/str/pt/num", "recosntructed MC #pi^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pi/neg/str/pt/num", "recosntructed MC #pi^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/pos/str/pt/num", "recosntructed MC k^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/neg/str/pt/num", "recosntructed MC k^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/pos/str/pt/num", "recosntructed MC p", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/neg/str/pt/num", "recosntructed MC #bar{p}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pi/pos/mat/pt/num", "recosntructed MC #pi^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pi/neg/mat/pt/num", "recosntructed MC #pi^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/pos/mat/pt/num", "recosntructed MC k^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/neg/mat/pt/num", "recosntructed MC k^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/pos/mat/pt/num", "recosntructed MC p", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/neg/mat/pt/num", "recosntructed MC #bar{p}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pi/pos/prm/pt/numtof", "recosntructed MC TOF #pi^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/pos/prm/pt/numtof", "recosntructed MC TOF k^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/pos/prm/pt/numtof", "recosntructed MC TOF p", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pi/neg/prm/pt/numtof", "recosntructed MC TOF #pi^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/neg/prm/pt/numtof", "recosntructed MC TOF k^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/neg/prm/pt/numtof", "recosntructed MC TOF #bar{p}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pi/pos/str/pt/numtof", "recosntructed MC TOF #pi^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pi/neg/str/pt/numtof", "recosntructed MC TOF #pi^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/pos/str/pt/numtof", "recosntructed MC TOF k^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/neg/str/pt/numtof", "recosntructed MC TOF k^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/pos/str/pt/numtof", "recosntructed MC TOF p", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/neg/str/pt/numtof", "recosntructed MC TOF #bar{p}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pi/pos/mat/pt/numtof", "recosntructed MC TOF #pi^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pi/neg/mat/pt/numtof", "recosntructed MC TOF #pi^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/pos/mat/pt/numtof", "recosntructed MC TOF k^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/neg/mat/pt/numtof", "recosntructed MC TOF k^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/pos/mat/pt/numtof", "recosntructed MC TOF p", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/neg/mat/pt/numtof", "recosntructed MC TOF #bar{p}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pi/pos/prm/pt/den", "generated MC #pi^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pi/neg/prm/pt/den", "generated MC #pi^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/pos/prm/pt/den", "generated MC K^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/neg/prm/pt/den", "generated MC K^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/pos/prm/pt/den", "generated MC p", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/neg/prm/pt/den", "generated MC #bar{p}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pi/pos/str/pt/den", "generated MC #pi^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pi/neg/str/pt/den", "generated MC #pi^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/pos/str/pt/den", "generated MC K^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/neg/str/pt/den", "generated MC K^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/pos/str/pt/den", "generated MC p", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/neg/str/pt/den", "generated MC #bar{p}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pi/pos/mat/pt/den", "generated MC #pi^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pi/neg/mat/pt/den", "generated MC #pi^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/pos/mat/pt/den", "generated MC K^{+}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/ka/neg/mat/pt/den", "generated MC K^{-}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/pos/mat/pt/den", "generated MC p", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/pr/neg/mat/pt/den", "generated MC #bar{p}", HistType::kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add("MC/test/pi/pos/prm/pt/den", "generated MC #pi^{+}", HistType::kTHnSparseD, {ptAxis}); + histos.add("MC/test/pi/neg/prm/pt/den", "generated MC #pi^{-}", HistType::kTHnSparseD, {ptAxis}); + histos.add("MC/test/ka/pos/prm/pt/den", "generated MC K^{+}", HistType::kTHnSparseD, {ptAxis}); + histos.add("MC/test/ka/neg/prm/pt/den", "generated MC K^{-}", HistType::kTHnSparseD, {ptAxis}); + histos.add("MC/test/pr/pos/prm/pt/den", "generated MC p", HistType::kTHnSparseD, {ptAxis}); + histos.add("MC/test/pr/neg/prm/pt/den", "generated MC #bar{p}", HistType::kTHnSparseD, {ptAxis}); } } // init loop end using CollisionCandidate = soa::Join; using TrackCandidates = soa::Join; - void process(CollisionCandidate::iterator const& collision, TrackCandidates const& tracks) { if (!collision.sel8()) { @@ -168,7 +231,7 @@ struct QCspectraTPC { continue; if (track.tpcNClsCrossedRows() < 100) continue; - if (track.tpcChi2NCl() > 4) + if (track.tpcChi2NCl() > maxChi2PerClusterTPC) continue; if (track.itsChi2NCl() > 36) continue; @@ -352,8 +415,351 @@ struct QCspectraTPC { } } } // process_mc loop end + using CollisionCandidateMCRec = soa::Join; + void processTrackHistograms_MC(CollisionCandidateMCRec::iterator const& collision, soa::Join const& tracks, aod::McParticles const& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) + { + const float multiplicity = collision.centFT0C(); + for (auto& track : tracks) { + + const auto& mcParticle = track.mcParticle(); + if (abs(track.eta()) > cfgCutEta) { + return; + } + if (track.tpcNClsCrossedRows() < minTPCNClsFound) + continue; + if (track.tpcCrossedRowsOverFindableCls() < minNCrossedRowsOverFindableClustersTPC) + continue; + if (track.tpcChi2NCl() > maxChi2PerClusterTPC) + continue; + if (track.itsChi2NCl() > maxChi2PerClusterITS) + continue; + if (abs(track.dcaXY()) > cfgCutDCAXY) + continue; + if (abs(track.dcaZ()) > cfgCutDCAZ) + continue; + if (mcParticle.isPhysicalPrimary()) { + // pions + if (mcParticle.pdgCode() == 211) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + histos.fill(HIST("MC/pi/pos/prm/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/pi/pos/prm/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } + if (mcParticle.pdgCode() == -211) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + histos.fill(HIST("MC/pi/neg/prm/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/pi/neg/prm/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } + // kaons + if (mcParticle.pdgCode() == 321) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + histos.fill(HIST("MC/ka/pos/prm/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/ka/pos/prm/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } + if (mcParticle.pdgCode() == -321) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + histos.fill(HIST("MC/ka/neg/prm/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/ka/neg/prm/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } + // Protons + if (mcParticle.pdgCode() == 2212) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + histos.fill(HIST("MC/pr/pos/prm/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/pr/pos/prm/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } + // Anti-Protons + if (mcParticle.pdgCode() == -2212) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + histos.fill(HIST("MC/pr/neg/prm/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/pr/neg/prm/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } + } // primaries + if (!mcParticle.isPhysicalPrimary()) { // secondaries loop start + if (mcParticle.pdgCode() == 211) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/pi/pos/str/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/pi/pos/str/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } else { + histos.fill(HIST("MC/pi/pos/mat/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/pi/pos/mat/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } + } + if (mcParticle.pdgCode() == -211) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/pi/neg/str/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/pi/neg/str/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } else { + histos.fill(HIST("MC/pi/neg/mat/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/pi/neg/mat/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } + } + if (mcParticle.pdgCode() == 321) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/ka/pos/str/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/ka/pos/str/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } else { + histos.fill(HIST("MC/ka/pos/mat/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/ka/pos/mat/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } + } + if (mcParticle.pdgCode() == -321) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/ka/neg/str/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/ka/neg/str/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } else { + histos.fill(HIST("MC/ka/neg/mat/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/ka/neg/mat/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } + } + if (mcParticle.pdgCode() == 2212) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/pr/pos/str/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/pr/pos/str/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } else { + histos.fill(HIST("MC/pr/pos/mat/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/pr/pos/mat/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } + } + if (mcParticle.pdgCode() == -2212) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/pr/neg/str/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/pr/neg/str/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } else { + histos.fill(HIST("MC/pr/neg/mat/pt/num"), track.pt(), multiplicity, track.dcaXY()); + if (track.hasTOF()) { + histos.fill(HIST("MC/pr/neg/mat/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); + } + } + } + } // secondaries loop end + } + } + PROCESS_SWITCH(QCspectraTPC, processTrackHistograms_MC, "process MC Reconstructed tracks", true); + + void processParticleHistograms_MC(CollisionCandidateMCRec::iterator const& collision, soa::Join const& tracks, + aod::McParticles const& /*mcParticles*/, + aod::McCollisions const& /*mcCollision*/) + { + + const float multiplicity = collision.centFT0C(); + for (auto& track : tracks) { + const auto& mcParticle = track.mcParticle(); + if (mcParticle.isPhysicalPrimary()) { + // pions + if (mcParticle.pdgCode() == 211) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + histos.fill(HIST("MC/pi/pos/prm/pt/den"), mcParticle.pt(), multiplicity, track.dcaXY()); + } + if (mcParticle.pdgCode() == -211) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + histos.fill(HIST("MC/pi/neg/prm/pt/den"), mcParticle.pt(), multiplicity, track.dcaXY()); + } + if (mcParticle.pdgCode() == 321) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + histos.fill(HIST("MC/ka/pos/prm/pt/den"), mcParticle.pt(), multiplicity, track.dcaXY()); + } + if (mcParticle.pdgCode() == -321) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + histos.fill(HIST("MC/ka/neg/prm/pt/den"), mcParticle.pt(), multiplicity, track.dcaXY()); + } + + if (mcParticle.pdgCode() == 2212) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + histos.fill(HIST("MC/pr/pos/prm/pt/den"), mcParticle.pt(), multiplicity, track.dcaXY()); + } + if (mcParticle.pdgCode() == -2212) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + histos.fill(HIST("MC/pr/neg/prm/pt/den"), mcParticle.pt(), multiplicity, track.dcaXY()); + } + if (!mcParticle.isPhysicalPrimary()) { // secondaries loop start + if (mcParticle.pdgCode() == 211) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/pi/pos/str/pt/den"), track.pt(), multiplicity, track.dcaXY()); + } else { + histos.fill(HIST("MC/pi/pos/mat/pt/den"), track.pt(), multiplicity, track.dcaXY()); + } + } + if (mcParticle.pdgCode() == -211) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/pi/neg/str/pt/den"), track.pt(), multiplicity, track.dcaXY()); + } else { + histos.fill(HIST("MC/pi/neg/mat/pt/den"), track.pt(), multiplicity, track.dcaXY()); + } + } + if (mcParticle.pdgCode() == 321) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/ka/pos/str/pt/den"), track.pt(), multiplicity, track.dcaXY()); + } else { + histos.fill(HIST("MC/ka/pos/mat/pt/den"), track.pt(), multiplicity, track.dcaXY()); + } + } + if (mcParticle.pdgCode() == -321) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/ka/neg/str/pt/den"), track.pt(), multiplicity, track.dcaXY()); + } else { + histos.fill(HIST("MC/ka/neg/mat/pt/den"), track.pt(), multiplicity, track.dcaXY()); + } + } + if (mcParticle.pdgCode() == 2212) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/pr/pos/str/pt/den"), track.pt(), multiplicity, track.dcaXY()); + } else { + histos.fill(HIST("MC/pr/pos/mat/pt/den"), track.pt(), multiplicity, track.dcaXY()); + } + } + if (mcParticle.pdgCode() == -2212) { + if (std::abs(mcParticle.y()) > cfgCutY) { + return; + } + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/pr/neg/str/pt/den"), track.pt(), multiplicity, track.dcaXY()); + } else { + histos.fill(HIST("MC/pr/neg/mat/pt/den"), track.pt(), multiplicity, track.dcaXY()); + } + } + } // secondaries loop end + } + } + } // process_mc loop end + PROCESS_SWITCH(QCspectraTPC, processParticleHistograms_MC, "process MC Generated tracks", true); + void processParticleGen(aod::McCollision const& /*mcCollision*/, aod::McParticles& mcParticles) + { - PROCESS_SWITCH(QCspectraTPC, processMCRec, "process MC Reconstructed", true); + for (auto& mcParticleGen : mcParticles) { + bool isPhysPrim = mcParticleGen.isPhysicalPrimary(); + if (doProcessMC) { + if (isPhysPrim) { + if (mcParticleGen.pdgCode() == 2212) { + if (abs(mcParticleGen.y()) > std::abs(cfgCutY)) { + continue; + } + histos.fill(HIST("MC/test/pr/pos/prm/pt/den"), mcParticleGen.pt()); + } + if (mcParticleGen.pdgCode() == -2212) { + if (abs(mcParticleGen.y()) > std::abs(cfgCutY)) { + continue; + } + histos.fill(HIST("MC/test/pr/neg/prm/pt/den"), mcParticleGen.pt()); + } + if (mcParticleGen.pdgCode() == 211) { + if (abs(mcParticleGen.y()) > std::abs(cfgCutY)) { + continue; + } + histos.fill(HIST("MC/test/pi/pos/prm/pt/den"), mcParticleGen.pt()); + } + if (mcParticleGen.pdgCode() == -211) { + if (abs(mcParticleGen.y()) > std::abs(cfgCutY)) { + continue; + } + histos.fill(HIST("MC/test/pi/neg/prm/pt/den"), mcParticleGen.pt()); + } + if (mcParticleGen.pdgCode() == 321) { + if (abs(mcParticleGen.y()) > std::abs(cfgCutY)) { + continue; + } + histos.fill(HIST("MC/test/ka/pos/prm/pt/den"), mcParticleGen.pt()); + } + if (mcParticleGen.pdgCode() == -321) { + if (abs(mcParticleGen.y()) > std::abs(cfgCutY)) { + continue; + } + histos.fill(HIST("MC/test/ka/neg/prm/pt/den"), mcParticleGen.pt()); + } + } + } + } + } // process_mc loop end + PROCESS_SWITCH(QCspectraTPC, processParticleGen, "process MC Generated tracks", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Nuspex/angularCorrelationsInJets.cxx b/PWGLF/Tasks/Nuspex/angularCorrelationsInJets.cxx new file mode 100644 index 00000000000..a0cbae145e3 --- /dev/null +++ b/PWGLF/Tasks/Nuspex/angularCorrelationsInJets.cxx @@ -0,0 +1,1330 @@ +// 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 angularCorrelationsInJets.cxx +/// +/// \author Lars Jörgensen (lars.christian.joergensen@cern.ch) +/// \brief task for analysis of angular correlations in jets using Fastjet + +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "CCDB/BasicCCDBManager.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/PID/PIDTOF.h" +#include "Common/TableProducer/PID/pidTOFBase.h" +#include "Common/Core/RecoDecay.h" + +#include "fastjet/PseudoJet.hh" +#include "fastjet/AreaDefinition.hh" +#include "fastjet/ClusterSequenceArea.hh" +#include "fastjet/GhostedAreaSpec.hh" +#include "PWGJE/Core/JetBkgSubUtils.h" +#include "TVector3.h" +#include "TPDGCode.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct AxisSpecs { + AxisSpec ptAxisPos = {1000, 0, 100, "#it{p}_{T} [GeV/#it{c}]"}; + AxisSpec ptAxisFull = {2000, -100, 100, "#it{p}_{T} [GeV/#it{c}]"}; + AxisSpec nsigmapTAxis = {500, 0, 50, "#it{p}_{T} [GeV/#it{c}]"}; + AxisSpec nsigmaAxis = {300, -15, 15, "n#sigma"}; + AxisSpec dcazAxis = {1000, -1, 1, "DCA_{z} [cm]"}; + AxisSpec dcaxyAxis = {1000, -0.5, 0.5, "DCA_{xy} [cm]"}; + AxisSpec angDistPhiAxis = {1000, -2, 5, "#Delta#varphi"}; + AxisSpec angDistEtaAxis = {1000, -2, 2, "#Delta#eta"}; +}; + +struct AngularCorrelationsInJets { + // Switches + Configurable useRejectionCut{"useRejectionCut", true, "use nsigmaRejection for correlations"}; + Configurable outputQC{"outputQC", true, "add QC output"}; + Configurable doppCorrelations{"doppCorrelations", true, "measure correlations for p-p"}; + Configurable doapapCorrelations{"doapapCorrelations", false, "measure correlations for pbar-pbar"}; + Configurable dopapCorrelations{"dopapCorrelations", false, "measure correlations for p-pbar"}; + Configurable dopipiCorrelations{"dopipiCorrelations", false, "measure correlations for pi+-p+, pi--pi-"}; + Configurable doJetCorrelations{"doJetCorrelations", false, "measure correlations for all particles inside jets"}; + Configurable doFullCorrelations{"doFullCorrelations", false, "measure correlations for all particles in an event"}; + Configurable measureKaons{"measureKaons", false, "measure correlations for K-K"}; + + // Track Cuts + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 80, "min number of crossed rows TPC"}; + Configurable minReqClusterITS{"minReqClusterITS", 5, "min number of clusters required in ITS"}; + Configurable minRatioCrossedRowsTPC{"minRatioCrossedRowsTPC", 0.8, "min ratio of crossed rows over findable clusters TPC"}; + Configurable maxChi2ITS{"maxChi2ITS", 36.0, "max chi2 per cluster ITS"}; + Configurable maxChi2TPC{"maxChi2TPC", 4.0, "max chi2 per cluster TPC"}; + Configurable maxDCAxy{"maxDCAxy", 0.05, "max DCA to vertex xy"}; + Configurable maxDCAz{"maxDCAz", 0.05, "max DCA to vertex z"}; + Configurable maxEta{"maxEta", 0.8, "max pseudorapidity"}; + Configurable deltaEtaEdge{"deltaEtaEdge", 0.05, "min eta distance of jet from acceptance edge"}; + Configurable minTrackPt{"minTrackPt", 0.3, "minimum track pT"}; + Configurable requirePVContributor{"requirePVContributor", false, "require track to be PV contributor"}; + + // Jet Cuts + Configurable jetR{"jetR", 0.3, "jet resolution parameter"}; + Configurable minJetPt{"minJetPt", 10.0, "minimum total pT to accept jet"}; + + // Proton Cuts + Configurable protonDCAxy{"protonDCAxy", 0.05, "[proton] DCAxy cut"}; + Configurable protonDCAz{"protonDCAz", 0.02, "[proton] DCAz cut"}; + Configurable protonTPCTOFpT{"protonTPCTOFpT", 0.7, "[proton] pT for switch in TPC/TPC+TOF nsigma"}; + Configurable protonTPCnsigma{"protonTPCnsigma", 4.0, "[proton] max TPC nsigma for pt > 0/1.5/3.0 GeV"}; + Configurable protonTOFnsigma{"protonTOFnsigma", 3.0, "[proton] max TOF nsigma for pt > 0/1.5/3.0 GeV"}; + + // Antiproton Cuts + Configurable antiprotonDCAxy{"antiprotonDCAxy", 0.05, "[antiproton] DCAxy cut"}; + Configurable antiprotonDCAz{"antiprotonDCAz", 0.02, "[antiproton] DCAz cut"}; + Configurable antiprotonTPCTOFpT{"antiprotonTPCTOFpT", 0.7, "[antiproton] pT for switch in TPC/TPC+TOF nsigma"}; + Configurable antiprotonTPCnsigma{"antiprotonTPCnsigma", 4.0, "[antiproton] max TPC nsigma for pt > 0/1.5/3.0 GeV"}; + Configurable antiprotonTOFnsigma{"antiprotonTOFnsigma", 3.0, "[antiproton] max TOF nsigma for pt > 0/1.5/3.0 GeV"}; + + // Pion & Kaon PID + Configurable pionDCAxy{"pionDCAxy", 0.05, "[pion] DCAxy cut"}; + Configurable pionDCAz{"pionDCAz", 0.05, "[pion] DCAz cut"}; + Configurable pionTPCTOFpT{"pionTPCTOFpT", 0.7, "[pion] pT for switch in TPC/TPC+TOF nsigma"}; + Configurable pionTPCnsigmaLowPt{"pionTPCnsigmaLowPt", 3.0, "[pion] max TPC nsigma with low pT"}; + Configurable pionTPCnsigmaHighPt{"pionTPCnsigmaHighPt", 3.0, "[pion] max TPC nsigma with high pT"}; + Configurable pionTOFnsigma{"pionTOFnsigma", 3.0, "[pion] max TOF nsigma"}; + Configurable kaonDCAxy{"kaonDCAxy", 0.05, "[kaon] DCAxy cut"}; + Configurable kaonDCAz{"kaonDCAz", 0.05, "[kaon] DCAz cut"}; + Configurable kaonTPCTOFpT{"kaonTPCTOFpT", 0.7, "[kaon] pT for switch in TPC/TPC+TOF nsigma"}; + Configurable kaonTPCnsigmaLowPt{"kaonTPCnsigmaLowPt", 3.0, "[kaon] max TPC nsigma with low pT"}; + Configurable kaonTPCnsigmaHighPt{"kaonTPCnsigmaHighPt", 3.0, "[kaon] max TPC nsigma with high pT"}; + Configurable kaonTOFnsigma{"kaonTOFnsigma", 3.0, "[kaon] max TOF nsigma"}; + + Configurable nsigmaRejection{"nsigmaRejection", 1.0, "reject tracks with nsigma < nsigmaRejection for >1 species"}; + Configurable trackBufferSize{"trackBufferSize", 200, "Number of mixed-event tracks being stored"}; + + // QC Configurables + Configurable zVtx{"zVtx", 10.0, "max zVertex"}; + Configurable rMax{"rMax", 0.3, "Maximum radius for jet and UE regions"}; + + Service ccdb; + int mRunNumber; + + using FullTracksRun2 = soa::Join; + using FullTracksRun3 = soa::Join; + using McTracksRun2 = soa::Join; + using McTracksRun3 = soa::Join; + using BCsWithRun2Info = soa::Join; + using McCollisions = soa::Join; + + Filter prelimTrackCuts = (aod::track::itsChi2NCl < maxChi2ITS && + aod::track::tpcChi2NCl < maxChi2TPC && + nabs(aod::track::dcaXY) < maxDCAxy && + nabs(aod::track::dcaZ) < maxDCAz && + nabs(aod::track::eta) < maxEta); + + Preslice perCollisionFullTracksRun2 = o2::aod::track::collisionId; + Preslice perCollisionFullTracksRun3 = o2::aod::track::collisionId; + Preslice perCollisionMcTracksRun2 = o2::aod::track::collisionId; + Preslice perCollisionMcTracksRun3 = o2::aod::track::collisionId; + + AxisSpecs axisSpecs; + + HistogramRegistry registryData{"data", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry registryMC{"MC", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry registryQC{"QC", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + + JetBkgSubUtils bkgSub; + std::vector eventSelection; + + void init(o2::framework::InitContext&) + { + mRunNumber = 0; + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + // Counters + registryData.add("numberOfEvents", "Number of events", HistType::kTH1I, {{1, 0, 1}}); + registryData.add("numberOfJets", "Total number of jets", HistType::kTH1I, {{1, 0, 1}}); + registryData.add("eventProtocol", "Event protocol", HistType::kTH1I, {{20, 0, 20}}); + registryData.add("trackProtocol", "Track protocol", HistType::kTH1I, {{20, 0, 20}}); + registryData.add("numPartInJet", "Number of particles in a jet", HistType::kTH1I, {{200, 0, 200}}); + registryData.add("numJetsInEvent", "Number of jets selected", HistType::kTH1I, {{10, 0, 10}}); + registryData.add("jetRapidity", "Jet rapidity;#it{y}", HistType::kTH1F, {{200, -1, 1}}); + + if (doFullCorrelations) { + registryData.add("deltaPhiSEFull", "#Delta#varphi of particles in same event", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiMEFull", "#Delta#varphi of particles in mixed events", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiEtaSEFull", "#Delta#varphi vs #Delta#eta of full particles in same event", HistType::kTH2D, {axisSpecs.angDistPhiAxis, axisSpecs.angDistEtaAxis}); + registryData.add("deltaPhiEtaMEFull", "#Delta#varphi vs #Delta#eta of particles in mixed events", HistType::kTH2D, {axisSpecs.angDistPhiAxis, axisSpecs.angDistEtaAxis}); + } + + if (doJetCorrelations) { + registryData.add("deltaPhiSEJet", "#Delta#varphi of jet particles in same event", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiMEJet", "#Delta#varphi of jet particles in mixed events", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiEtaSEJet", "#Delta#varphi vs #Delta#eta of jet particles in same event", HistType::kTH2D, {axisSpecs.angDistPhiAxis, axisSpecs.angDistEtaAxis}); + registryData.add("deltaPhiEtaMEJet", "#Delta#varphi vs #Delta#eta of jet particles in mixed events", HistType::kTH2D, {axisSpecs.angDistPhiAxis, axisSpecs.angDistEtaAxis}); + } + + if (doppCorrelations) { + registryData.add("deltaPhiSEProton", "#Delta#varphi of protons in same event", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiMEProton", "#Delta#varphi of protons in mixed events", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiEtaSEProton", "#Delta#varphi vs #Delta#eta of protons in same event", HistType::kTH2D, {axisSpecs.angDistPhiAxis, axisSpecs.angDistEtaAxis}); + registryData.add("deltaPhiEtaMEProton", "#Delta#varphi vs #Delta#eta of protons in mixed events", HistType::kTH2D, {axisSpecs.angDistPhiAxis, axisSpecs.angDistEtaAxis}); + } + + if (doapapCorrelations) { + registryData.add("deltaPhiSEAntiproton", "#Delta#varphi of antiprotons in same event", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiMEAntiproton", "#Delta#varphi of antiprotons in mixed events", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiEtaSEAntiproton", "#Delta#varphi vs #Delta#eta of antiprotons in same event", HistType::kTH2D, {axisSpecs.angDistPhiAxis, axisSpecs.angDistEtaAxis}); + registryData.add("deltaPhiEtaMEAntiproton", "#Delta#varphi vs #Delta#eta of antiprotons in mixed events", HistType::kTH2D, {axisSpecs.angDistPhiAxis, axisSpecs.angDistEtaAxis}); + } + + if (dopipiCorrelations) { + registryData.add("dcaZJetPion", "DCA_{z} of high purity pions", HistType::kTH2F, {axisSpecs.ptAxisPos, axisSpecs.dcazAxis}); + registryQC.add("ptJetPionVsTotalJet", "Pion p_{T} vs. jet p_{T}", HistType::kTH2D, {axisSpecs.ptAxisPos, {1000, 0, 500, "jet p_{T} [GeV/#it{c}]"}}); + registryData.add("tpcNSigmaPion", "TPC n#sigma for pion", HistType::kTH2F, {axisSpecs.nsigmapTAxis, axisSpecs.nsigmaAxis}); + registryData.add("tofNSigmaPion", "TOF n#sigma for pion", HistType::kTH2F, {axisSpecs.nsigmapTAxis, axisSpecs.nsigmaAxis}); + registryData.add("deltaPhiSEPion", "#Delta#varphi of pions in same event", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiMEPion", "#Delta#varphi of pions in mixed events", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiEtaSEPion", "#Delta#varphi vs #Delta#eta of pions in same event", HistType::kTH2D, {axisSpecs.angDistPhiAxis, axisSpecs.angDistEtaAxis}); + registryData.add("deltaPhiEtaMEPion", "#Delta#varphi vs #Delta#eta of pions in mixed events", HistType::kTH2D, {axisSpecs.angDistPhiAxis, axisSpecs.angDistEtaAxis}); + } + + if (dopapCorrelations) { + registryData.add("deltaPhiSEProtonAntiproton", "#Delta#varphi of proton-antiproton in same event", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiMEProtonAntiproton", "#Delta#varphi of proton-antiproton in mixed events", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiEtaSEProtonAntiproton", "#Delta#varphi vs #Delta#eta of proton-antiproton in same event", HistType::kTH2D, {axisSpecs.angDistPhiAxis, axisSpecs.angDistEtaAxis}); + registryData.add("deltaPhiEtaMEProtonAntiproton", "#Delta#varphi vs #Delta#eta of proton-antiproton in mixed events", HistType::kTH2D, {axisSpecs.angDistPhiAxis, axisSpecs.angDistEtaAxis}); + } + + if (doprocessMCRun2 || doprocessMCRun3 || doppCorrelations || doapapCorrelations || dopapCorrelations) { + registryData.add("ptJetProton", "p_{T} of protons", HistType::kTH1D, {axisSpecs.ptAxisPos}); + registryData.add("dcaZJetProton", "DCA_{z} of high purity protons", HistType::kTH2F, {axisSpecs.ptAxisPos, axisSpecs.dcazAxis}); + registryQC.add("ptJetProtonVsTotalJet", "Proton p_{T} vs. jet p_{T}", HistType::kTH2D, {axisSpecs.ptAxisPos, {1000, 0, 500, "jet p_{T} [GeV/#it{c}]"}}); + registryData.add("ptJetAntiproton", "p_{T} of antiprotons", HistType::kTH1D, {axisSpecs.ptAxisPos}); + registryData.add("dcaZJetAntiproton", "DCA_{z} of high purity antiprotons", HistType::kTH2F, {axisSpecs.ptAxisPos, axisSpecs.dcazAxis}); + registryQC.add("ptJetAntiprotonVsTotalJet", "Antiproton p_{T} vs. jet p_{T}", HistType::kTH2D, {axisSpecs.ptAxisPos, {1000, 0, 500, "jet p_{T} [GeV/#it{c}]"}}); + registryData.add("tpcNSigmaProton", "TPC n#sigma for proton", HistType::kTH2F, {axisSpecs.nsigmapTAxis, axisSpecs.nsigmaAxis}); + registryData.add("tofNSigmaProton", "TOF n#sigma for proton", HistType::kTH2F, {axisSpecs.nsigmapTAxis, axisSpecs.nsigmaAxis}); + registryData.add("tpcNSigmaAntiproton", "TPC n#sigma for antiproton", HistType::kTH2F, {axisSpecs.nsigmapTAxis, axisSpecs.nsigmaAxis}); + registryData.add("tofNSigmaAntiproton", "TOF n#sigma for antiproton", HistType::kTH2F, {axisSpecs.nsigmapTAxis, axisSpecs.nsigmaAxis}); + } + + if (measureKaons) { + registryData.add("dcaZJetKaon", "DCA_{z} of high purity kaons", HistType::kTH2F, {axisSpecs.ptAxisPos, axisSpecs.dcazAxis}); + registryQC.add("ptJetKaonVsTotalJet", "Kaon p_{T} vs. jet p_{T}", HistType::kTH2D, {axisSpecs.ptAxisPos, {1000, 0, 500, "jet p_{T} [GeV/#it{c}]"}}); + registryData.add("tpcNSigmaKaon", "TPC n#sigma for kaon", HistType::kTH2F, {axisSpecs.nsigmapTAxis, axisSpecs.nsigmaAxis}); + registryData.add("tofNSigmaKaon", "TOF n#sigma for kaon", HistType::kTH2F, {axisSpecs.nsigmapTAxis, axisSpecs.nsigmaAxis}); + } + + // pT + registryData.add("ptJetParticle", "p_{T} of particles in jets", HistType::kTH1D, {axisSpecs.ptAxisPos}); + registryData.add("ptTotalSubJetPerp", "Subtracted full jet p_{T} (perpendicular)", HistType::kTH1D, {axisSpecs.ptAxisPos}); + registryData.add("ptTotalJet", "p_{T} of entire jet;#it{p}_{T} [GeV/#it{c}]", HistType::kTH1F, {{1000, 0, 500}}); + + // nSigma + registryData.add("tpcSignal", "TPC signal", HistType::kTH2F, {{800, -10, 10, "#it{p} [GeV/#it{c}]"}, {1000, 0, 500, "d#it{E}/d#it{X} (a.u.)"}}); + registryData.add("tofSignal", "TOF signal", HistType::kTH2F, {{800, -20, 20, "#it{p} [GeV/#it{c}]"}, {800, 0.75, 1.05, "#beta (TOF)"}}); + + // Angular Distributions + registryQC.add("phiFullEvent", "#varphi in full event", HistType::kTH1F, {{1000, 0, 6.3}}); + registryQC.add("phiPtFullEvent", "#varphi vs. p_{T} in full event", HistType::kTH2F, {axisSpecs.ptAxisPos, {1000, 0, 6.3}}); + registryQC.add("phiJet", "#varphi in jet", HistType::kTH1F, {{1000, 0, 6.3}}); + registryQC.add("phiPtJet", "#varphi vs. p_{T} in jet", HistType::kTH2F, {axisSpecs.ptAxisPos, {1000, 0, 6.3}}); + registryQC.add("etaFullEvent", "#eta in full event", HistType::kTH1F, {{1000, -1, 1}}); + registryQC.add("etaPtFullEvent", "#eta vs. p_{T} in full event", HistType::kTH2F, {axisSpecs.ptAxisPos, {1000, -1, 1}}); + registryQC.add("etaJet", "#eta in jet", HistType::kTH1F, {{1000, -1, 1}}); + registryQC.add("etaPtJet", "#eta vs. p_{T} in jet", HistType::kTH2F, {axisSpecs.ptAxisPos, {1000, -1, 1}}); + + // QA + registryQC.add("rhoEstimatePerp", "Background #rho (perp)", HistType::kTH2F, {{axisSpecs.ptAxisPos}, {200, 0, 20}}); + registryQC.add("rhoMEstimatePerp", "Background #rho_{m} (perp)", HistType::kTH2F, {{axisSpecs.ptAxisPos}, {200, 0, 20}}); + registryQC.add("jetPtVsNumPart", "Total jet p_{T} vs number of constituents", HistType::kTH2F, {axisSpecs.ptAxisPos, {100, 0, 100}}); + + if (doprocessMCRun2 || doprocessMCRun3) { + registryMC.add("ptJetProtonMC", "Truth jet proton p_{T}", HistType::kTH1F, {axisSpecs.ptAxisPos}); + registryMC.add("ptJetAntiprotonMC", "Truth jet antiproton p_{T}", HistType::kTH1F, {axisSpecs.ptAxisPos}); + registryMC.add("numberOfTruthParticles", "Truth yields (anti)p, (anti)d, (anti)He-3", HistType::kTH1I, {{6, 0, 6}}); + } + + if (outputQC) { + registryQC.add("ptDiff", "p_{T} difference PseudoJet/original track;#it{p}_{T} [GeV/#it{c}]", HistType::kTH1D, {{2000, -0.0001, 0.0001}}); + registryQC.add("jetConeRadius", "Jet Radius;#it{R}", HistType::kTH1F, {{100, 0, 1}}); + registryQC.add("maxRadiusVsPt", "Max Cone Radius vs p_{T}", HistType::kTH2F, {{axisSpecs.ptAxisPos}, {100, 0, 1}}); + registryQC.add("jetBkgDeltaPt", "#Delta p_{T} Clustered Cone - Pure Jet", HistType::kTH1F, {{200, 0, 10}}); + + registryQC.add("ptFullEvent", "p_{T} after basic cuts", HistType::kTH1F, {axisSpecs.ptAxisPos}); + registryQC.add("crossedRowsTPC", "Crossed rows TPC", HistType::kTH2I, {axisSpecs.ptAxisPos, {135, 65, 200}}); + registryQC.add("clusterITS", "ITS clusters", HistType::kTH2I, {axisSpecs.ptAxisPos, {10, 0, 10}}); + registryQC.add("clusterTPC", "TPC clusters", HistType::kTH2I, {axisSpecs.ptAxisPos, {135, 65, 200}}); + registryQC.add("ratioCrossedRowsTPC", "Ratio crossed rows/findable TPC", HistType::kTH2F, {axisSpecs.ptAxisPos, {100, 0.5, 1.5}}); + registryQC.add("chi2ITS", "ITS #chi^{2}", HistType::kTH2F, {axisSpecs.ptAxisPos, {400, 0, 40}}); + registryQC.add("chi2TPC", "TPC #chi^{2}", HistType::kTH2F, {axisSpecs.ptAxisPos, {50, 0, 5}}); + registryQC.add("dcaXYFullEvent", "DCA_{xy} of full event", HistType::kTH2F, {axisSpecs.ptAxisPos, axisSpecs.dcaxyAxis}); + registryQC.add("dcaZFullEvent", "DCA_{z} of full event", HistType::kTH2F, {axisSpecs.ptAxisPos, axisSpecs.dcazAxis}); + + registryQC.add("multiplicityJetPlusUE", "multiplicityJetPlusUE", HistType::kTH1F, {{100, 0, 100, "#it{N}_{ch}"}}); + registryQC.add("multiplicityJet", "multiplicityJet", HistType::kTH1F, {{100, 0, 100, "#it{N}_{ch}"}}); + registryQC.add("multiplicityUE", "multiplicityUE", HistType::kTH1F, {{100, 0, 100, "#it{N}_{ch}"}}); + registryQC.add("ptJetPlusUE", "ptJetPlusUE", HistType::kTH1F, {{500, 0, 50, "#it{p}_{T} (GeV/#it{c})"}}); + registryQC.add("ptJet", "ptJet", HistType::kTH1F, {{500, 0, 50, "#it{p}_{T} (GeV/#it{c})"}}); + registryQC.add("ptUE", "ptUE", HistType::kTH1F, {{500, 0, 50, "#it{p}_{T} (GeV/#it{c})"}}); + registryQC.add("deltaEtadeltaPhiJet", "deltaEtadeltaPhiJet", HistType::kTH2F, {{200, -0.5, 0.5, "#Delta#eta"}, {200, 0, constants::math::PIHalf, "#Delta#phi"}}); + registryQC.add("deltaEtadeltaPhiUE", "deltaEtadeltaPhiUE", HistType::kTH2F, {{200, -0.5, 0.5, "#Delta#eta"}, {200, 0, constants::math::PIHalf, "#Delta#phi"}}); + registryQC.add("deltaJetPt", "deltaJetPt", HistType::kTH1F, {{200, -2, 2, "#Delta#it{p}_{T} (GeV/#it{c})"}}); + registryQC.add("nParticlesClusteredInJet", "nParticlesClusteredInJet", HistType::kTH1F, {{50, 0, 50, "#it{N}_{ch}"}}); + registryQC.add("ptParticlesClusteredInJet", "ptParticlesClusteredInJet", HistType::kTH1F, {{200, 0, 10, "#it{p}_{T} (GeV/#it{c})"}}); + } + } + + std::vector> fBufferProton; + std::vector> fBufferAntiproton; + std::vector> fBufferPiPlus; + std::vector> fBufferPiMinus; + std::vector> fBufferJet; + std::vector> fBufferFull; + + template + void initCCDB(Bc const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + } + + template + bool hasITSHit(const T& track, int layer) + { + int bit = layer - 1; + return (track.itsClusterMap() & (1 << bit)); + } + + template + bool selectTrackForJetReco(const T& track) + { + if (track.dcaZ() > maxDCAz) + return false; + double maxEtaForJetReco = 0.8; + if (track.eta() > maxEtaForJetReco) + return false; + double minTrackPtForJetReco = 0.1; + if (track.pt() < minTrackPtForJetReco) + return false; + if (!track.hasITS()) + return false; + if (!track.hasTPC()) + return false; + int minCrossedRowsForJetReco = 70; + if (track.tpcNClsCrossedRows() < minCrossedRowsForJetReco) + return false; + if ((!hasITSHit(track, 1)) && (!hasITSHit(track, 2)) && (!hasITSHit(track, 3))) + return false; + double minRatioCrRowsFindableJetReco = 0.8; + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < minRatioCrRowsFindableJetReco) + return false; + if (std::fabs(track.dcaXY()) > (0.0105 + 0.035 / std::pow(track.pt(), 1.1))) + return false; + if (doprocessRun2 || doprocessMCRun2) { + if (!(track.trackType() & o2::aod::track::Run2Track) || + !(track.flags() & o2::aod::track::TPCrefit) || + !(track.flags() & o2::aod::track::ITSrefit)) { + return false; + } + } + return true; + } + + template + bool selectTrack(const T& track) + { + if (requirePVContributor && !(track.isPVContributor())) + return false; + if (!track.hasITS()) + return false; + if (track.itsNCls() < minReqClusterITS) + return false; + if (!track.hasTPC()) + return false; + if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < minRatioCrossedRowsTPC) + return false; + if (track.tpcChi2NCl() > maxChi2TPC) + return false; + if (track.itsChi2NCl() > maxChi2ITS) + return false; + if (std::fabs(track.eta()) > maxEta) + return false; + if (track.pt() < minTrackPt) + return false; + + return true; + } + + template + bool singleSpeciesTPCNSigma(T const& track) // reject any track that has TPC nsigma < 3 for more than 1 species + { + if (useRejectionCut && (track.tpcNSigmaStoreEl() < nsigmaRejection || track.tpcNSigmaStoreMu() < nsigmaRejection || track.tpcNSigmaPi() < nsigmaRejection || track.tpcNSigmaKa() < nsigmaRejection || track.tpcNSigmaStoreTr() < nsigmaRejection || track.tpcNSigmaStoreAl() < nsigmaRejection || track.tpcNSigmaDe() < nsigmaRejection || track.tpcNSigmaHe() < nsigmaRejection)) + return false; + return true; + } + + template + bool isProton(const T& track) + { + if (track.sign() < 0) + return false; + + double pt = track.pt(); + + // DCA + double maxDCApt = 1.2; + if (pt < maxDCApt) { + if (std::abs(track.dcaXY()) > protonDCAxy) + return false; + if (std::abs(track.dcaZ()) > protonDCAz) + return false; + } + + // nsigma + double midPt = 1.5; + double highPt = 3.0; + + double maxTPCnsigma = protonTPCnsigma; + double maxTOFnsigma = protonTOFnsigma; + if (pt > midPt) { + maxTPCnsigma = protonTPCnsigma - 1; + maxTOFnsigma = protonTOFnsigma - 1; + } + if (pt > highPt) { + maxTPCnsigma = protonTPCnsigma - 2; + maxTOFnsigma = protonTOFnsigma - 2; + } + + registryData.fill(HIST("tpcNSigmaProton"), track.pt(), track.tpcNSigmaPr()); + if (pt < protonTPCTOFpT && (std::abs(track.tpcNSigmaPr()) > maxTPCnsigma)) + return false; + + double tofNSigma = 999; + if (track.hasTOF()) { + registryData.fill(HIST("tofNSigmaProton"), track.pt(), track.tofNSigmaPr()); + tofNSigma = track.tofNSigmaPr(); + } + + if (pt > protonTPCTOFpT && ((std::abs(tofNSigma) > maxTOFnsigma) || std::abs(track.tpcNSigmaPr()) > maxTPCnsigma)) + return false; + + if (useRejectionCut && !singleSpeciesTPCNSigma(track)) + return false; + + return true; + } + + template + bool isAntiproton(const T& track) + { + if (track.sign() > 0) + return false; + + double pt = track.pt(); + + // DCA + double maxDCApt = 1.2; + if (pt < maxDCApt) { + if (std::abs(track.dcaXY()) > antiprotonDCAxy) + return false; + if (std::abs(track.dcaZ()) > antiprotonDCAz) + return false; + } + + // nsigma + double midPt = 1.5; + double highPt = 3.0; + + double maxTPCnsigma = antiprotonTPCnsigma; + double maxTOFnsigma = antiprotonTOFnsigma; + if (pt > midPt) { + maxTPCnsigma = antiprotonTPCnsigma - 1; + maxTOFnsigma = antiprotonTOFnsigma - 1; + } + if (pt > highPt) { + maxTPCnsigma = antiprotonTPCnsigma - 2; + maxTOFnsigma = antiprotonTOFnsigma - 2; + } + + registryData.fill(HIST("tpcNSigmaAntiproton"), track.pt(), track.tpcNSigmaPr()); + if (pt < antiprotonTPCTOFpT && (std::abs(track.tpcNSigmaPr()) > maxTPCnsigma)) + return false; + + double tofNSigma = 999; + if (track.hasTOF()) { + registryData.fill(HIST("tofNSigmaAntiproton"), track.pt(), track.tofNSigmaPr()); + tofNSigma = track.tofNSigmaPr(); + } + + if (pt > antiprotonTPCTOFpT && ((std::abs(tofNSigma) > maxTOFnsigma) || std::abs(track.tpcNSigmaPr()) > maxTPCnsigma)) + return false; + + if (useRejectionCut && !singleSpeciesTPCNSigma(track)) + return false; + + return true; + } + + template + bool isPion(const T& track) + { + // DCA + if (std::abs(track.dcaXY()) > pionDCAxy) + return false; + if (std::abs(track.dcaZ()) > pionDCAz) + return false; + + registryData.fill(HIST("tpcNSigmaPion"), track.pt(), track.tpcNSigmaPi()); + + // TPC + if (track.pt() < pionTPCTOFpT && std::abs(track.tpcNSigmaPi()) > pionTPCnsigmaLowPt) + return false; + if (track.pt() > pionTPCTOFpT && std::abs(track.tpcNSigmaPi()) > pionTPCnsigmaHighPt) + return false; + + // TOF + if (track.hasTOF()) { + registryData.fill(HIST("tofNSigmaPion"), track.pt(), track.tofNSigmaPi()); + if (track.pt() > pionTPCTOFpT && std::abs(track.tofNSigmaPi()) > pionTOFnsigma) + return false; + } + + return true; + } + + template + bool isKaon(const T& track) + { + // DCA + if (std::abs(track.dcaXY()) > kaonDCAxy) + return false; + if (std::abs(track.dcaZ()) > kaonDCAz) + return false; + + registryData.fill(HIST("tpcNSigmaKaon"), track.pt(), track.tpcNSigmaKa()); + + // TPC + if (track.pt() < kaonTPCTOFpT && std::abs(track.tpcNSigmaKa()) > kaonTPCnsigmaLowPt) + return false; + if (track.pt() > kaonTPCTOFpT && std::abs(track.tpcNSigmaKa()) > kaonTPCnsigmaHighPt) + return false; + + // TOF + if (track.hasTOF()) { + registryData.fill(HIST("tofNSigmaKaon"), track.pt(), track.tofNSigmaKa()); + if (track.pt() > kaonTPCTOFpT && std::abs(track.tofNSigmaKa()) > kaonTOFnsigma) + return false; + } + + return true; + } + + void setTrackBuffer(const auto& tempBuffer, auto& buffer) // refresh track buffer + { + for (const auto& pair : tempBuffer) { + if (static_cast(buffer.size()) == trackBufferSize) { + buffer.insert(buffer.begin(), pair); + buffer.resize(trackBufferSize); + } else if (static_cast(buffer.size()) < trackBufferSize) { + buffer.emplace_back(pair); + } + } + } + + void fillMixedEventDeltas(const auto& track, const auto& buffer, int particleType, const TVector3 jetAxis) // correlate tracks from current event with tracks from buffer, i.e. other events + { + if (buffer.size() == 0) + return; + if (std::isnan(track.phi()) || std::isnan(jetAxis.Phi())) + return; + for (int i = 0; i < static_cast(buffer.size()); i++) { // loop over tracks in buffer + if (std::isnan(buffer.at(i).first)) + continue; + if (buffer.at(i).first > constants::math::TwoPI || buffer.at(i).first < -constants::math::TwoPI) { + registryData.fill(HIST("trackProtocol"), 13); // # buffer tracks failed with phi > 2 pi + continue; + } + + double phiToAxis = RecoDecay::constrainAngle(track.phi() - jetAxis.Phi(), 0); + double etaToAxis = track.eta() - jetAxis.Eta(); + double deltaPhi = RecoDecay::constrainAngle(phiToAxis - buffer.at(i).first, -constants::math::PIHalf); + double deltaEta = etaToAxis - buffer.at(i).second; + + switch (particleType) { + case -1: + registryData.fill(HIST("deltaPhiMEFull"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaMEFull"), deltaPhi, deltaEta); + break; + case 0: + registryData.fill(HIST("deltaPhiMEJet"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaMEJet"), deltaPhi, deltaEta); + break; + case 1: + registryData.fill(HIST("deltaPhiMEProton"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaMEProton"), deltaPhi, deltaEta); + break; + case 2: + registryData.fill(HIST("deltaPhiMEAntiproton"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaMEAntiproton"), deltaPhi, deltaEta); + break; + case 3: + registryData.fill(HIST("deltaPhiMEPion"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaMEPion"), deltaPhi, deltaEta); + break; + case 4: + registryData.fill(HIST("deltaPhiMEProtonAntiproton"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaMEProtonAntiproton"), deltaPhi, deltaEta); + break; + } + } // for (int i = 0; i < static_cast(buffer.size()); i++) + } + + void doCorrelations(const auto& particleVector, const auto& buffer, auto& tempBuffer, int particleType, const TVector3 jetAxis) + { + if (std::isnan(jetAxis.Phi())) + return; + for (int i = 0; i < static_cast(particleVector.size()); i++) { + if (std::isnan(particleVector.at(i).phi())) + continue; + double phiToAxis = RecoDecay::constrainAngle(particleVector.at(i).phi() - jetAxis.Phi(), 0); + double etaToAxis = particleVector.at(i).eta() - jetAxis.Eta(); + if (std::abs(particleVector.at(i).phi()) > constants::math::TwoPI) { + registryData.fill(HIST("trackProtocol"), 11); // # tracks failed with phi > 2 pi + continue; + } + for (int j = i + 1; j < static_cast(particleVector.size()); j++) { + if ((j == static_cast(particleVector.size())) || std::isnan(particleVector.at(j).phi())) + continue; + if (std::abs(particleVector.at(j).phi()) > constants::math::TwoPI) { + registryData.fill(HIST("trackProtocol"), 12); // # tracks failed with phi > 2 pi + continue; + } + + double deltaPhi = RecoDecay::constrainAngle(particleVector.at(i).phi() - particleVector.at(j).phi(), -constants::math::PIHalf); + double deltaEta = particleVector.at(i).eta() - particleVector.at(j).eta(); + switch (particleType) { + case -1: + registryData.fill(HIST("deltaPhiSEFull"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaSEFull"), deltaPhi, deltaEta); + break; + case 0: + registryData.fill(HIST("deltaPhiSEJet"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaSEJet"), deltaPhi, deltaEta); + break; + case 1: + registryData.fill(HIST("deltaPhiSEProton"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaSEProton"), deltaPhi, deltaEta); + break; + case 2: + registryData.fill(HIST("deltaPhiSEAntiproton"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaSEAntiproton"), deltaPhi, deltaEta); + break; + case 3: + registryData.fill(HIST("deltaPhiSEPion"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaSEPion"), deltaPhi, deltaEta); + break; + } + } + fillMixedEventDeltas(particleVector.at(i), buffer, particleType, jetAxis); + tempBuffer.emplace_back(std::make_pair(phiToAxis, etaToAxis)); + } + } + + void doCorrelationsAnti(const auto& particleVector, const auto& particleVectorAnti, const auto& bufferAnti, auto& tempBuffer, const TVector3 jetAxis) // correlations between particle/antiparticle + { + if (std::isnan(jetAxis.Phi())) + return; + for (int i = 0; i < static_cast(particleVector.size()); i++) { + if (std::isnan(particleVector.at(i).phi())) + continue; + double phiToAxis = RecoDecay::constrainAngle(particleVector.at(i).phi() - jetAxis.Phi(), 0); + double etaToAxis = particleVector.at(i).eta() - jetAxis.Eta(); + if (std::abs(particleVector.at(i).phi()) > constants::math::TwoPI) { + registryData.fill(HIST("trackProtocol"), 14); // # tracks failed with phi > 2 pi + continue; + } + for (int j = 0; j < static_cast(particleVectorAnti.size()); j++) { + if (std::isnan(particleVectorAnti.at(j).phi())) + continue; + if (std::abs(particleVectorAnti.at(j).phi()) > constants::math::TwoPI) { + registryData.fill(HIST("trackProtocol"), 15); // # tracks failed with phi > 2 pi + continue; + } + + double deltaPhi = RecoDecay::constrainAngle(particleVector.at(i).phi() - particleVectorAnti.at(j).phi(), -constants::math::PIHalf); + double deltaEta = particleVector.at(i).eta() - particleVectorAnti.at(j).eta(); + registryData.fill(HIST("deltaPhiSEProtonAntiproton"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaSEProtonAntiproton"), deltaPhi, deltaEta); + break; + } + fillMixedEventDeltas(particleVector.at(i), bufferAnti, 4, jetAxis); + tempBuffer.emplace_back(std::make_pair(phiToAxis, etaToAxis)); + } + } + + double getDeltaPhi(double a1, double a2) + { + double failedPhi = -999; + if (std::isnan(a1) || std::isnan(a2) || a1 == failedPhi || a2 == failedPhi) + return -999; + double deltaPhi(0); + double phi1 = RecoDecay::constrainAngle(a1, 0); + double phi2 = RecoDecay::constrainAngle(a2, 0); + double diff = std::abs(phi1 - phi2); + + if (diff <= constants::math::PI) + deltaPhi = diff; + if (diff > constants::math::PI) + deltaPhi = constants::math::TwoPI - diff; + + return deltaPhi; + } + + void getPerpendicularAxis(TVector3 p, TVector3& u, double sign) + { + // Initialization + double ux(0), uy(0), uz(0); + + // Components of Vector p + double px = p.X(); + double py = p.Y(); + double pz = p.Z(); + + // Protection 1 + if (px == 0 && py != 0) { + uy = -(pz * pz) / py; + ux = sign * std::abs(py * py - (pz * pz * pz * pz) / (py * py)); + uz = pz; + u.SetXYZ(ux, uy, uz); + return; + } + + // Protection 2 + if (py == 0 && px != 0) { + ux = -(pz * pz) / px; + uy = sign * std::abs(px * px - (pz * pz * pz * pz) / (px * px)); + uz = pz; + u.SetXYZ(ux, uy, uz); + return; + } + + // Equation Parameters + double a = px * px + py * py; + double b = 2.0 * px * pz * pz; + double c = pz * pz * pz * pz - py * py * py * py - px * px * py * py; + double delta = b * b - 4.0 * a * c; + + // Protection agains delta<0 + if (delta < 0) { + return; + } + + // Solutions + ux = (-b + sign * std::abs(delta)) / (2.0 * a); + uy = (-pz * pz - px * ux) / py; + uz = pz; + u.SetXYZ(ux, uy, uz); + return; + } + + int analyseJet(int jetCounter, fastjet::PseudoJet jet, const auto& particles, auto& jetProtons, auto& jetAntiprotons, auto& jetPiPlus, auto& jetPiMinus, auto& jetAll, double rhoPerp, double rhoMPerp) + { + if (!jet.has_constituents()) + return jetCounter; + fastjet::PseudoJet subtractedJetPerp(0., 0., 0., 0.); + subtractedJetPerp = bkgSub.doRhoAreaSub(jet, rhoPerp, rhoMPerp); + + if (subtractedJetPerp.pt() < minJetPt) // cut on jet w/o bkg + return jetCounter; + if ((std::fabs(jet.eta()) + jetR) > (maxEta - deltaEtaEdge)) + return jetCounter; + registryData.fill(HIST("ptTotalSubJetPerp"), subtractedJetPerp.pt()); + registryQC.fill(HIST("rhoEstimatePerp"), jet.pt(), rhoPerp); + registryQC.fill(HIST("rhoMEstimatePerp"), jet.pt(), rhoMPerp); + double jetBkgDeltaPt = jet.pt() - subtractedJetPerp.pt(); + + registryData.fill(HIST("eventProtocol"), 4); + std::vector constituents = jet.constituents(); + + if (constituents.size() <= 1) + return jetCounter; + + jetCounter++; + + registryData.fill(HIST("eventProtocol"), 5); + registryData.fill(HIST("numberOfJets"), 0); + registryData.fill(HIST("ptTotalJet"), jet.pt()); + registryData.fill(HIST("jetRapidity"), jet.rap()); + registryData.fill(HIST("numPartInJet"), jet.constituents().size()); + + TVector3 pJet(0., 0., 0.); + pJet.SetXYZ(jet.px(), jet.py(), jet.pz()); + + if (outputQC) { + registryQC.fill(HIST("jetBkgDeltaPt"), jetBkgDeltaPt); + registryQC.fill(HIST("jetPtVsNumPart"), jet.pt(), jet.constituents().size()); + + double maxRadius = 0; + for (const auto& constituent : constituents) { + registryData.fill(HIST("ptJetParticle"), constituent.pt()); + registryQC.fill(HIST("phiJet"), constituent.phi()); + registryQC.fill(HIST("phiPtJet"), constituent.pt(), constituent.phi()); + registryQC.fill(HIST("etaJet"), constituent.eta()); + registryQC.fill(HIST("etaPtJet"), constituent.pt(), constituent.eta()); + + if (std::isnan(constituent.phi()) || std::isnan(jet.phi())) // geometric jet cone + continue; + double deltaPhi = RecoDecay::constrainAngle(constituent.phi() - jet.phi(), -constants::math::PIHalf); + double deltaEta = constituent.eta() - jet.eta(); + double delta = std::abs(deltaPhi * deltaPhi + deltaEta * deltaEta); + registryQC.fill(HIST("jetConeRadius"), delta); + if (delta > maxRadius) + maxRadius = delta; + } + registryQC.fill(HIST("maxRadiusVsPt"), jet.pt(), maxRadius); + + TVector3 ueAxis1(0.0, 0.0, 0.0); + TVector3 ueAxis2(0.0, 0.0, 0.0); + getPerpendicularAxis(pJet, ueAxis1, +1.0); + getPerpendicularAxis(pJet, ueAxis2, -1.0); + + double nchJetPlusUE(0); + double nchJet(0); + double nchUE(0); + double ptJetPlusUE(0); + double ptJet(0); + double ptUE(0); + + for (const auto& [index, track] : particles) { + TVector3 particleDir(track.px(), track.py(), track.pz()); + double deltaEtaJet = particleDir.Eta() - pJet.Eta(); + double deltaPhiJet = getDeltaPhi(particleDir.Phi(), pJet.Phi()); + double deltaRJet = std::abs(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + double deltaEtaUE1 = particleDir.Eta() - ueAxis1.Eta(); + double deltaPhiUE1 = getDeltaPhi(particleDir.Phi(), ueAxis1.Phi()); + double deltaRUE1 = std::abs(deltaEtaUE1 * deltaEtaUE1 + deltaPhiUE1 * deltaPhiUE1); + double deltaEtaUE2 = particleDir.Eta() - ueAxis2.Eta(); + double deltaPhiUE2 = getDeltaPhi(particleDir.Phi(), ueAxis2.Phi()); + double deltaRUE2 = std::abs(deltaEtaUE2 * deltaEtaUE2 + deltaPhiUE2 * deltaPhiUE2); + double failedPhi = -999; + if (deltaRJet < rMax) { + if (deltaPhiJet != failedPhi) + registryQC.fill(HIST("deltaEtadeltaPhiJet"), deltaEtaJet, deltaPhiJet); + nchJetPlusUE++; + ptJetPlusUE = ptJetPlusUE + track.pt(); + } + if (deltaRUE1 < rMax) { + if (deltaPhiUE1 != failedPhi) + registryQC.fill(HIST("deltaEtadeltaPhiUE"), deltaEtaUE1, deltaPhiUE1); + nchUE++; + ptUE = ptUE + track.pt(); + } + if (deltaRUE2 < rMax) { + if (deltaPhiUE2 != failedPhi) + registryQC.fill(HIST("deltaEtadeltaPhiUE"), deltaEtaUE2, deltaPhiUE2); + nchUE++; + ptUE = ptUE + track.pt(); + } + } // for (const auto& [index, track] : particles) + + nchJet = nchJetPlusUE - 0.5 * nchUE; + ptJet = ptJetPlusUE - 0.5 * ptUE; + registryQC.fill(HIST("multiplicityJetPlusUE"), nchJetPlusUE); + registryQC.fill(HIST("multiplicityJet"), nchJet); + registryQC.fill(HIST("multiplicityUE"), 0.5 * nchUE); + registryQC.fill(HIST("ptJetPlusUE"), ptJetPlusUE); + registryQC.fill(HIST("ptJet"), ptJet); + registryQC.fill(HIST("ptUE"), 0.5 * ptUE); + registryQC.fill(HIST("deltaJetPt"), jet.pt() - ptJetPlusUE); + + int nPartClusteredJet = static_cast(constituents.size()); + + // Fill QA Histograms + if (ptJetPlusUE < minJetPt) { // swap for sub pt? + + registryQC.fill(HIST("nParticlesClusteredInJet"), nPartClusteredJet); + + for (const auto& track : constituents) { + registryQC.fill(HIST("ptParticlesClusteredInJet"), track.pt()); + } + } + } + + std::vector> fTempBufferProton; + std::vector> fTempBufferAntiproton; + std::vector> fTempBufferPiPlus; + std::vector> fTempBufferPiMinus; + std::vector> fTempBufferJet; + fTempBufferProton.clear(); + fTempBufferPiPlus.clear(); + fTempBufferPiMinus.clear(); + fTempBufferAntiproton.clear(); + fTempBufferJet.clear(); + + for (const auto& pseudoParticle : constituents) { // analyse jet constituents - this is where the magic happens + registryData.fill(HIST("trackProtocol"), 2); + int id = pseudoParticle.user_index(); + const auto& jetParticle = particles.at(id); + if (!selectTrack(jetParticle)) + continue; + jetAll.emplace_back(jetParticle); + + registryData.fill(HIST("tpcSignal"), jetParticle.pt() * jetParticle.sign(), jetParticle.tpcSignal()); + if (jetParticle.hasTOF()) { + registryData.fill(HIST("tofSignal"), jetParticle.pt() * jetParticle.sign(), jetParticle.beta()); + } + if (outputQC) { + double ptDiff = pseudoParticle.pt() - jetParticle.pt(); + registryQC.fill(HIST("ptDiff"), ptDiff); + } + + if ((doppCorrelations || dopapCorrelations) && isProton(jetParticle)) { + registryData.fill(HIST("trackProtocol"), 3); // # high purity protons + registryData.fill(HIST("ptJetProton"), jetParticle.pt()); + registryData.fill(HIST("dcaZJetProton"), jetParticle.pt(), jetParticle.dcaZ()); + registryQC.fill(HIST("ptJetProtonVsTotalJet"), jetParticle.pt(), subtractedJetPerp.pt()); + jetProtons.emplace_back(jetParticle); + } else if ((doapapCorrelations || dopapCorrelations) && isAntiproton(jetParticle)) { + registryData.fill(HIST("trackProtocol"), 4); // # high purity antiprotons + registryData.fill(HIST("ptJetAntiproton"), jetParticle.pt()); + registryData.fill(HIST("dcaZJetAntiproton"), jetParticle.pt(), jetParticle.dcaZ()); + registryQC.fill(HIST("ptJetAntiprotonVsTotalJet"), jetParticle.pt(), subtractedJetPerp.pt()); + jetAntiprotons.emplace_back(jetParticle); + } else if (dopipiCorrelations && isPion(jetParticle)) { + registryQC.fill(HIST("ptJetPionVsTotalJet"), jetParticle.pt(), subtractedJetPerp.pt()); + registryData.fill(HIST("trackProtocol"), 5); + registryData.fill(HIST("dcaZJetPion"), jetParticle.pt(), jetParticle.dcaZ()); + if (jetParticle.sign() > 0) { + jetPiPlus.emplace_back(jetParticle); + } else if (jetParticle.sign() < 0) { + jetPiMinus.emplace_back(jetParticle); + } + } + if (measureKaons && isKaon(jetParticle)) { + registryQC.fill(HIST("ptJetKaonVsTotalJet"), jetParticle.pt(), subtractedJetPerp.pt()); + registryData.fill(HIST("trackProtocol"), 6); + registryData.fill(HIST("dcaZJetKaon"), jetParticle.pt(), jetParticle.dcaZ()); + } + } // for (const auto& pseudoParticle : constituents) + + if (doJetCorrelations && jetAll.size() > 1) { // general correlation function + doCorrelations(jetAll, fBufferJet, fTempBufferJet, 0, pJet); + setTrackBuffer(fTempBufferJet, fBufferJet); + } + + if (dopapCorrelations && (jetProtons.size() > 0) && (jetAntiprotons.size() > 0)) { + doCorrelationsAnti(jetProtons, jetAntiprotons, fBufferAntiproton, fTempBufferProton, pJet); + doCorrelationsAnti(jetAntiprotons, jetProtons, fBufferProton, fTempBufferAntiproton, pJet); // divide SE distributions by 2 in post + } + int minNumPartForCorrelations = 2; + if ((static_cast(jetProtons.size()) < minNumPartForCorrelations) && (static_cast(jetAntiprotons.size()) < minNumPartForCorrelations) && (static_cast(jetPiPlus.size()) < minNumPartForCorrelations) && (static_cast(jetPiMinus.size()) < minNumPartForCorrelations)) + return jetCounter; + registryData.fill(HIST("eventProtocol"), 6); + + if (doppCorrelations && jetProtons.size() > 1) { + doCorrelations(jetProtons, fBufferProton, fTempBufferProton, 1, pJet); + setTrackBuffer(fTempBufferProton, fBufferProton); + } + if (doapapCorrelations && jetAntiprotons.size() > 1) { + doCorrelations(jetAntiprotons, fBufferAntiproton, fTempBufferAntiproton, 2, pJet); + setTrackBuffer(fTempBufferAntiproton, fBufferAntiproton); + } + if (dopipiCorrelations && jetPiPlus.size() > 1) { + doCorrelations(jetPiPlus, fBufferPiPlus, fTempBufferPiPlus, 3, pJet); + setTrackBuffer(fTempBufferPiPlus, fBufferPiPlus); + } + if (dopipiCorrelations && jetPiMinus.size() > 1) { + doCorrelations(jetPiMinus, fBufferPiMinus, fTempBufferPiMinus, 3, pJet); + setTrackBuffer(fTempBufferPiMinus, fBufferPiMinus); + } + return jetCounter; + } + + template + void fillHistograms(U const& tracks) + { + std::vector jetProtons; + std::vector jetAntiprotons; + std::vector jetPiPlus; + std::vector jetPiMinus; + std::vector jetAll; + jetProtons.clear(); + jetAntiprotons.clear(); + jetPiPlus.clear(); + jetPiMinus.clear(); + jetAll.clear(); + std::vector> fTempBufferFull; + fTempBufferFull.clear(); + std::vector jetInput; // input for jet finder + std::map particles; // all selected particles in event + std::vector particlesForCF; // particles for full event angular correlations + jetInput.clear(); + particles.clear(); + int index = 0; + int jetCounter = 0; + + for (const auto& track : tracks) { + registryData.fill(HIST("trackProtocol"), 0); // # all tracks + if (!selectTrackForJetReco(track)) + continue; + + registryData.fill(HIST("trackProtocol"), 1); // # tracks selected for jet reconstruction + + if (outputQC && (track.tpcNClsFindable() != 0)) { + registryQC.fill(HIST("ratioCrossedRowsTPC"), track.pt(), track.tpcNClsCrossedRows() / track.tpcNClsFindable()); + } + + if (outputQC) { + registryQC.fill(HIST("ptFullEvent"), track.pt()); + registryQC.fill(HIST("crossedRowsTPC"), track.pt(), track.tpcNClsCrossedRows()); + registryQC.fill(HIST("clusterITS"), track.pt(), track.itsNCls()); + registryQC.fill(HIST("clusterTPC"), track.pt(), track.tpcNClsFound()); + registryQC.fill(HIST("chi2ITS"), track.pt(), track.itsChi2NCl()); + registryQC.fill(HIST("chi2TPC"), track.pt(), track.tpcChi2NCl()); + registryQC.fill(HIST("dcaXYFullEvent"), track.pt(), track.dcaXY()); + registryQC.fill(HIST("dcaZFullEvent"), track.pt(), track.dcaZ()); + registryQC.fill(HIST("phiFullEvent"), track.phi()); + registryQC.fill(HIST("phiPtFullEvent"), track.pt(), track.phi()); + registryQC.fill(HIST("etaFullEvent"), track.eta()); + registryQC.fill(HIST("etaPtFullEvent"), track.pt(), track.eta()); + } + fastjet::PseudoJet inputPseudoJet(track.px(), track.py(), track.pz(), track.energy(o2::constants::physics::MassPionCharged)); + inputPseudoJet.set_user_index(index); + particles[index] = track; + particlesForCF.emplace_back(track); + jetInput.emplace_back(inputPseudoJet); + + index++; + } // for (const auto& track : tracks) + + int minNumPartForJetReco = 2; + if (static_cast(jetInput.size()) < minNumPartForJetReco) + return; + registryData.fill(HIST("eventProtocol"), 2); + + // Reconstruct Jets + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, jetR); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); + fastjet::ClusterSequenceArea clusterSeq(jetInput, jetDef, areaDef); + std::vector jets = sorted_by_pt(clusterSeq.inclusive_jets()); + + if (jets.size() == 0) + return; + + registryData.fill(HIST("eventProtocol"), 3); + + auto [rhoPerp, rhoMPerp] = bkgSub.estimateRhoPerpCone(jetInput, jets); + + for (const auto& jet : jets) { + jetCounter = analyseJet(jetCounter, jet, particles, jetProtons, jetAntiprotons, jetPiPlus, jetPiMinus, jetAll, rhoPerp, rhoMPerp); + } + registryData.fill(HIST("numJetsInEvent"), jetCounter); + + TVector3 hardestJetAxis(jets.at(0).px(), jets.at(0).py(), jets.at(0).pz()); // for full event, use hardest jet as orientation + doCorrelations(particlesForCF, fBufferFull, fTempBufferFull, -1, hardestJetAxis); + setTrackBuffer(fTempBufferFull, fBufferFull); + } + + template + void fillHistogramsMC(U const& tracks) + { + std::vector jetInput; // input for jet finder + std::map particles; // all selected particles in event + jetInput.clear(); + particles.clear(); + int index = 0; + + for (const auto& track : tracks) { + if (outputQC && (track.tpcNClsFindable() != 0)) { + registryQC.fill(HIST("ratioCrossedRowsTPC"), track.pt(), track.tpcNClsCrossedRows() / track.tpcNClsFindable()); + } + registryQC.fill(HIST("ptFullEvent"), track.pt()); + registryQC.fill(HIST("crossedRowsTPC"), track.pt(), track.tpcNClsCrossedRows()); + registryQC.fill(HIST("clusterITS"), track.pt(), track.itsNCls()); + registryQC.fill(HIST("clusterTPC"), track.pt(), track.tpcNClsFound()); + registryQC.fill(HIST("chi2ITS"), track.pt(), track.itsChi2NCl()); + registryQC.fill(HIST("chi2TPC"), track.pt(), track.tpcChi2NCl()); + registryQC.fill(HIST("dcaXYFullEvent"), track.pt(), track.dcaXY()); + registryQC.fill(HIST("dcaZFullEvent"), track.pt(), track.dcaZ()); + registryQC.fill(HIST("phiFullEvent"), track.phi()); + registryQC.fill(HIST("phiPtFullEvent"), track.pt(), track.phi()); + registryQC.fill(HIST("etaFullEvent"), track.eta()); + registryQC.fill(HIST("etaPtFullEvent"), track.pt(), track.eta()); + + fastjet::PseudoJet inputPseudoJet(track.px(), track.py(), track.pz(), track.energy(o2::constants::physics::MassPionCharged)); + inputPseudoJet.set_user_index(index); + particles[index] = track; + jetInput.emplace_back(inputPseudoJet); + + index++; + } // for (const auto& track : tracks) + + int minNumPartForJetReco = 2; + if (static_cast(jetInput.size()) < minNumPartForJetReco) + return; + registryData.fill(HIST("eventProtocol"), 2); + + // Reconstruct Jets + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, jetR); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); + fastjet::ClusterSequenceArea clusterSeq(jetInput, jetDef, areaDef); + std::vector jets = sorted_by_pt(clusterSeq.inclusive_jets()); + + if (jets.size() == 0) + return; + + registryData.fill(HIST("eventProtocol"), 3); + + auto [rhoPerp, rhoMPerp] = bkgSub.estimateRhoPerpCone(jetInput, jets); + + for (auto& jet : jets) { // o2-linter: disable=const-ref-in-for-loop (jets are modified) + if (!jet.has_constituents()) + continue; + fastjet::PseudoJet subtractedJetPerp(0., 0., 0., 0.); + subtractedJetPerp = bkgSub.doRhoAreaSub(jet, rhoPerp, rhoMPerp); + + if (subtractedJetPerp.pt() < minJetPt) // cut on jet w/o bkg + continue; + registryData.fill(HIST("ptTotalSubJetPerp"), subtractedJetPerp.pt()); + registryQC.fill(HIST("rhoEstimatePerp"), jet.pt(), rhoPerp); + registryQC.fill(HIST("rhoMEstimatePerp"), jet.pt(), rhoMPerp); + double jetBkgDeltaPt = jet.pt() - subtractedJetPerp.pt(); + registryQC.fill(HIST("jetBkgDeltaPt"), jetBkgDeltaPt); + + registryData.fill(HIST("eventProtocol"), 4); + std::vector constituents = jet.constituents(); + + registryData.fill(HIST("eventProtocol"), 5); + registryData.fill(HIST("numberOfJets"), 0); + registryData.fill(HIST("ptTotalJet"), jet.pt()); + registryData.fill(HIST("jetRapidity"), jet.rap()); + registryData.fill(HIST("numPartInJet"), jet.constituents().size()); + registryQC.fill(HIST("jetPtVsNumPart"), jet.pt(), jet.constituents().size()); + + double maxRadius = 0; + for (const auto& constituent : constituents) { + registryData.fill(HIST("ptJetParticle"), constituent.pt()); + registryQC.fill(HIST("phiJet"), constituent.phi()); + registryQC.fill(HIST("phiPtJet"), constituent.pt(), constituent.phi()); + registryQC.fill(HIST("etaJet"), constituent.eta()); + registryQC.fill(HIST("etaPtJet"), constituent.pt(), constituent.eta()); + + if (std::isnan(constituent.phi()) || std::isnan(jet.phi())) // geometric jet cone + continue; + double deltaPhi = RecoDecay::constrainAngle(constituent.phi() - jet.phi(), -constants::math::PIHalf); + double deltaEta = constituent.eta() - jet.eta(); + double delta = std::abs(deltaPhi * deltaPhi + deltaEta * deltaEta); + registryQC.fill(HIST("jetConeRadius"), delta); + if (delta > maxRadius) + maxRadius = delta; + } + registryQC.fill(HIST("maxRadiusVsPt"), jet.pt(), maxRadius); + + TVector3 pJet(0., 0., 0.); + pJet.SetXYZ(jet.px(), jet.py(), jet.pz()); + TVector3 ueAxis1(0.0, 0.0, 0.0); + TVector3 ueAxis2(0.0, 0.0, 0.0); + getPerpendicularAxis(pJet, ueAxis1, +1.0); + getPerpendicularAxis(pJet, ueAxis2, -1.0); + + double nchJetPlusUE(0); + double nchJet(0); + double nchUE(0); + + for (const auto& [index, track] : particles) { + TVector3 particleDir(track.px(), track.py(), track.pz()); + double deltaEtaJet = particleDir.Eta() - pJet.Eta(); + double deltaPhiJet = getDeltaPhi(particleDir.Phi(), pJet.Phi()); + double deltaRJet = std::abs(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + double deltaEtaUE1 = particleDir.Eta() - ueAxis1.Eta(); + double deltaPhiUE1 = getDeltaPhi(particleDir.Phi(), ueAxis1.Phi()); + double deltaRUE1 = std::abs(deltaEtaUE1 * deltaEtaUE1 + deltaPhiUE1 * deltaPhiUE1); + double deltaEtaUE2 = particleDir.Eta() - ueAxis2.Eta(); + double deltaPhiUE2 = getDeltaPhi(particleDir.Phi(), ueAxis2.Phi()); + double deltaRUE2 = std::abs(deltaEtaUE2 * deltaEtaUE2 + deltaPhiUE2 * deltaPhiUE2); + + double failedPhi = -999; + if (deltaRJet < rMax) { + if (deltaPhiJet != failedPhi) + registryQC.fill(HIST("deltaEtadeltaPhiJet"), deltaEtaJet, deltaPhiJet); + nchJetPlusUE++; + } + if (deltaRUE1 < rMax) { + if (deltaPhiUE1 != failedPhi) + registryQC.fill(HIST("deltaEtadeltaPhiUE"), deltaEtaUE1, deltaPhiUE1); + nchUE++; + } + if (deltaRUE2 < rMax) { + if (deltaPhiUE2 != failedPhi) + registryQC.fill(HIST("deltaEtadeltaPhiUE"), deltaEtaUE2, deltaPhiUE2); + nchUE++; + } + } // for (const auto& [index, track] : particles) + + nchJet = nchJetPlusUE - 0.5 * nchUE; + registryQC.fill(HIST("multiplicityJetPlusUE"), nchJetPlusUE); + registryQC.fill(HIST("multiplicityJet"), nchJet); + registryQC.fill(HIST("multiplicityUE"), 0.5 * nchUE); + + for (const auto& pseudoParticle : constituents) { // analyse jet constituents - this is where the magic happens + registryData.fill(HIST("trackProtocol"), 3); + int id = pseudoParticle.user_index(); + const auto& jetParticle = particles.at(id); + if (!selectTrack(jetParticle)) + continue; + + registryData.fill(HIST("tpcSignal"), jetParticle.pt() * jetParticle.sign(), jetParticle.tpcSignal()); + if (jetParticle.hasTOF()) { + registryData.fill(HIST("tofSignal"), jetParticle.pt() * jetParticle.sign(), jetParticle.beta()); + } + if (outputQC) { + double ptDiff = pseudoParticle.pt() - jetParticle.pt(); + registryQC.fill(HIST("ptDiff"), ptDiff); + } + + // if (jetParticle.pt() < minJetParticlePt) + // continue; + if (!jetParticle.has_mcParticle()) + continue; + switch (jetParticle.mcParticle().pdgCode()) { + case kProton: + registryMC.fill(HIST("numberOfTruthParticles"), 0); + registryMC.fill(HIST("ptJetProtonMC"), jetParticle.pt()); + break; + case kProtonBar: + registryMC.fill(HIST("numberOfTruthParticles"), 1); + registryMC.fill(HIST("ptJetAntiprotonMC"), jetParticle.pt()); + break; + default: + continue; + } + + if (!selectTrackForJetReco(jetParticle)) + continue; + switch (jetParticle.mcParticle().pdgCode()) { + case kProton: + registryData.fill(HIST("ptJetProton"), jetParticle.pt()); + registryQC.fill(HIST("ptJetProtonVsTotalJet"), jetParticle.pt(), subtractedJetPerp.pt()); + registryData.fill(HIST("trackProtocol"), 4); // # protons + break; + case kProtonBar: + registryData.fill(HIST("ptJetAntiproton"), jetParticle.pt()); + registryQC.fill(HIST("ptJetAntiprotonVsTotalJet"), jetParticle.pt(), subtractedJetPerp.pt()); + registryData.fill(HIST("trackProtocol"), 6); // # antiprotons + break; + default: + continue; + } + } // for (const auto& pseudoParticle : constituents) + } // for (auto& jet : jets) + } + + void processRun2(soa::Join const& collisions, + soa::Filtered const& tracks, + BCsWithRun2Info const&) + { + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + + registryData.fill(HIST("eventProtocol"), 0); + if (!collision.alias_bit(kINT7)) + continue; + registryData.fill(HIST("numberOfEvents"), 0); + registryData.fill(HIST("eventProtocol"), 1); + + auto slicedTracks = tracks.sliceBy(perCollisionFullTracksRun2, collision.globalIndex()); + + fillHistograms(slicedTracks); + } + } + PROCESS_SWITCH(AngularCorrelationsInJets, processRun2, "process Run 2 data w/o jet tables", false); + + void processRun3(soa::Join const& collisions, + soa::Filtered const& tracks) + { + for (const auto& collision : collisions) { + registryData.fill(HIST("eventProtocol"), 0); + if (!collision.sel8()) + continue; + registryData.fill(HIST("numberOfEvents"), 0); + registryData.fill(HIST("eventProtocol"), 1); + if (std::abs(collision.posZ()) > zVtx) + continue; + + auto slicedTracks = tracks.sliceBy(perCollisionFullTracksRun3, collision.globalIndex()); + + fillHistograms(slicedTracks); + } + } + PROCESS_SWITCH(AngularCorrelationsInJets, processRun3, "process Run 3 data w/o jet tables", false); + + void processMCRun2(McCollisions const& collisions, soa::Filtered const& tracks, BCsWithRun2Info const&, aod::McParticles const&, aod::McCollisions const&) + { + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + + registryData.fill(HIST("eventProtocol"), 0); + if (!collision.alias_bit(kINT7)) + continue; + registryData.fill(HIST("numberOfEvents"), 0); + registryData.fill(HIST("eventProtocol"), 1); + + auto slicedTracks = tracks.sliceBy(perCollisionMcTracksRun2, collision.globalIndex()); + + fillHistogramsMC(slicedTracks); + } + } + PROCESS_SWITCH(AngularCorrelationsInJets, processMCRun2, "process Run 2 MC w/o jet tables, not currently usable", false); + + void processMCRun3(McCollisions const& collisions, soa::Filtered const& tracks, aod::McParticles const&, aod::McCollisions const&) + { + for (const auto& collision : collisions) { + registryData.fill(HIST("eventProtocol"), 0); + if (!collision.sel8()) + continue; + registryData.fill(HIST("numberOfEvents"), 0); + registryData.fill(HIST("eventProtocol"), 1); + if (std::abs(collision.posZ()) > zVtx) + continue; + + auto slicedTracks = tracks.sliceBy(perCollisionMcTracksRun3, collision.globalIndex()); + + fillHistogramsMC(slicedTracks); + } + } + PROCESS_SWITCH(AngularCorrelationsInJets, processMCRun3, "process Run 3 MC w/o jet tables, not currently usable", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Nuspex/antidLambdaEbye.cxx b/PWGLF/Tasks/Nuspex/antidLambdaEbye.cxx index 86fb967c341..7ee32edd1f8 100644 --- a/PWGLF/Tasks/Nuspex/antidLambdaEbye.cxx +++ b/PWGLF/Tasks/Nuspex/antidLambdaEbye.cxx @@ -138,11 +138,19 @@ float etaFromMom(std::array const& momA, std::array const& m (1.f * momA[2] + 1.f * momB[2]) * (1.f * momA[2] + 1.f * momB[2])) - (1.f * momA[2] + 1.f * momB[2]))); } +float CalculateDCAStraightToPV(float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) +{ + return std::sqrt((std::pow((pvY - Y) * Pz - (pvZ - Z) * Py, 2) + std::pow((pvX - X) * Pz - (pvZ - Z) * Px, 2) + std::pow((pvX - X) * Py - (pvY - Y) * Px, 2)) / (Px * Px + Py * Py + Pz * Pz)); +} } // namespace struct CandidateV0 { float pt; float eta; + float mass; + float cpa; + float dcav0daugh; + float dcav0pv; int64_t globalIndexPos = -999; int64_t globalIndexNeg = -999; }; @@ -165,9 +173,6 @@ struct antidLambdaEbye { float d_bz; // o2::base::MatLayerCylSet* lut = nullptr; - Configurable cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Type of material correction"}; - Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {betheBlochDefault[0], 2, 6, particleNamesBB, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for deuteron"}; - ConfigurableAxis centAxis{"centAxis", {106, 0, 106}, "binning for the centrality"}; ConfigurableAxis subsampleAxis{"subsampleAxis", {30, 0, 30}, "binning of the subsample axis"}; ConfigurableAxis deltaEtaAxis{"deltaEtaAxis", {4, 0, 0.8}, "binning of the delta eta axis"}; @@ -195,66 +200,71 @@ struct antidLambdaEbye { ConfigurableAxis momResAxis{"momResAxis", {1.e2, -1.f, 1.f}, "momentum resolution binning"}; ConfigurableAxis tpcAxis{"tpcAxis", {4.e2, 0.f, 4.e3f}, "tpc signal axis binning"}; ConfigurableAxis tofAxis{"tofAxis", {1.e3, 0.f, 1.f}, "tof signal axis binning"}; - ConfigurableAxis tpcClsAxis{"tpcClsAxis", {160, 0, 160}, "tpc n clusters binning"}; - - Configurable zVtxMax{"zVtxMax", 10.0f, "maximum z position of the primary vertex"}; - Configurable etaMax{"etaMax", 0.8f, "maximum eta"}; - Configurable etaMaxV0dau{"etaMaxV0dau", 0.8f, "maximum eta V0 daughters"}; - - Configurable fillOnlySignal{"fillOnlySignal", false, "fill histograms only for true signal candidates (MC)"}; - - Configurable kINT7Intervals{"kINT7Intervals", false, "toggle kINT7 trigger selection in the 10-30% and 50-90% centrality intervals (2018 Pb-Pb)"}; - Configurable kUseTPCPileUpCut{"kUseTPCPileUpCut", false, "toggle strong correlation cuts (Run 2)"}; - Configurable kUseEstimatorsCorrelationCut{"kUseEstimatorsCorrelationCut", false, "toggle cut on the correlation between centrality estimators (2018 Pb-Pb)"}; - - Configurable antidPtMin{"antidPtMin", 0.8f, "minimum antideuteron pT (GeV/c)"}; - Configurable antidPtTof{"antidPtTof", 1.0f, "antideuteron pT to switch to TOF pid (GeV/c) "}; - Configurable antidPtMax{"antidPtMax", 1.8f, "maximum antideuteron pT (GeV/c)"}; - - Configurable antipPtMin{"antipPtMin", 0.4f, "minimum antiproton pT (GeV/c)"}; - Configurable antipPtTof{"antipPtTof", 0.6f, "antiproton pT to switch to TOF pid (GeV/c) "}; - Configurable antipPtMax{"antipPtMax", 0.9f, "maximum antiproton pT (GeV/c)"}; - - Configurable lambdaPtMin{"lambdaPtMin", 0.5f, "minimum (anti)lambda pT (GeV/c)"}; - Configurable lambdaPtMax{"lambdaPtMax", 3.0f, "maximum (anti)lambda pT (GeV/c)"}; - - Configurable trackNcrossedRows{"trackNcrossedRows", 70, "Minimum number of crossed TPC rows"}; - Configurable trackNclusItsCut{"trackNclusITScut", 5, "Minimum number of ITS clusters"}; - Configurable trackNclusTpcCut{"trackNclusTPCcut", 70, "Minimum number of TPC clusters"}; - Configurable trackDcaCut{"trackDcaCut", 0.1f, "DCA antid to PV"}; - - Configurable v0trackNcrossedRows{"v0trackNcrossedRows", 70, "Minimum number of crossed TPC rows for V0 daughter"}; - Configurable v0trackNclusItsCut{"v0trackNclusITScut", 1, "Minimum number of ITS clusters for V0 daughter"}; - Configurable v0trackNclusTpcCut{"v0trackNclusTPCcut", 70, "Minimum number of TPC clusters for V0 daughter"}; - Configurable v0trackNsharedClusTpc{"v0trackNsharedClusTpc", 10, "Maximum number of shared TPC clusters for V0 daughter"}; - Configurable v0requireITSrefit{"v0requireITSrefit", false, "require ITS refit for V0 daughter"}; - Configurable vetoMassK0Short{"vetoMassK0Short", -999.f, "veto for V0 compatible with K0s mass"}; - Configurable v0radiusMax{"v0radiusMax", 100.f, "maximum V0 radius eccepted"}; - - Configurable antidNsigmaTpcCutLow{"antidNsigmaTpcCutLow", 4.f, "TPC PID cut low"}; - Configurable antidNsigmaTpcCutUp{"antidNsigmaTpcCutUp", 4.f, "TPC PID cut up"}; - Configurable antidNsigmaTofCut{"antidNsigmaTofCut", 4.f, "TOF PID cut"}; - Configurable antidTpcInnerParamMax{"tpcInnerParamMax", 0.6f, "(temporary) tpc inner param cut"}; - Configurable antidTofMassMax{"tofMassMax", 0.3f, "(temporary) tof mass cut"}; - - Configurable antipNsigmaTpcCutLow{"antipNsigmaTpcCutLow", 4.f, "TPC PID cut low"}; - Configurable antipNsigmaTpcCutUp{"antipNsigmaTpcCutUp", 4.f, "TPC PID cut up"}; - Configurable antipNsigmaTofCut{"antipNsigmaTofCut", 4.f, "TOF PID cut"}; - Configurable antipTpcInnerParamMax{"antipTpcInnerParamMax", 0.6f, "(temporary) tpc inner param cut"}; - Configurable antipTofMassMax{"antipTofMassMax", 0.3f, "(temporary) tof mass cut"}; - Configurable tofMassMaxQA{"tofMassMaxQA", 0.6f, "(temporary) tof mass cut (for QA histograms)"}; - - Configurable v0setting_dcav0dau{"v0setting_dcav0dau", 1, "DCA V0 Daughters"}; - Configurable v0setting_dcapostopv{"v0setting_dcapostopv", 0.1f, "DCA Pos To PV"}; - Configurable v0setting_dcanegtopv{"v0setting_dcanegtopv", 0.1f, "DCA Neg To PV"}; - Configurable v0setting_cospa{"v0setting_cospa", 0.98, "V0 CosPA"}; - Configurable v0setting_radius{"v0setting_radius", 0.5f, "v0radius"}; - Configurable v0setting_nsigmatpc{"v0setting_nsigmatpc", 4.f, "nsigmatpc"}; - Configurable lambdaMassCut{"lambdaMassCut", 0.005f, "maximum deviation from PDG mass"}; - Configurable lambdaMassCutQA{"lambdaMassCutQA", 0.02f, "maximum deviation from PDG mass (for QA histograms)"}; - - Configurable antidItsClsSizeCut{"antidItsClsSizeCut", 2.f, "cluster size cut for antideuterons"}; - Configurable antidPtItsClsSizeCut{"antidPtItsClsSizeCut", 1.f, "pt for cluster size cut for antideuterons"}; + ConfigurableAxis tpcClsAxis{"tpcClsAxis", {160, 0.f, 160.f}, "tpc n clusters binning"}; + + struct : ConfigurableGroup { + Configurable cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Type of material correction"}; + Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {betheBlochDefault[0], 2, 6, particleNamesBB, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for deuteron"}; + Configurable zVtxMax{"zVtxMax", 10.0f, "maximum z position of the primary vertex"}; + Configurable etaMax{"etaMax", 0.8f, "maximum eta"}; + Configurable etaMaxV0dau{"etaMaxV0dau", 0.8f, "maximum eta V0 daughters"}; + + Configurable fillOnlySignal{"fillOnlySignal", false, "fill histograms only for true signal candidates (MC)"}; + + Configurable kINT7Intervals{"kINT7Intervals", false, "toggle kINT7 trigger selection in the 10-30% and 50-90% centrality intervals (2018 Pb-Pb)"}; + Configurable kUseTPCPileUpCut{"kUseTPCPileUpCut", false, "toggle strong correlation cuts (Run 2)"}; + Configurable kUseEstimatorsCorrelationCut{"kUseEstimatorsCorrelationCut", false, "toggle cut on the correlation between centrality estimators (2018 Pb-Pb)"}; + + Configurable antidPtMin{"antidPtMin", 0.8f, "minimum antideuteron pT (GeV/c)"}; + Configurable antidPtTof{"antidPtTof", 1.0f, "antideuteron pT to switch to TOF pid (GeV/c) "}; + Configurable antidPtMax{"antidPtMax", 1.8f, "maximum antideuteron pT (GeV/c)"}; + + Configurable antipPtMin{"antipPtMin", 0.4f, "minimum antiproton pT (GeV/c)"}; + Configurable antipPtTof{"antipPtTof", 0.6f, "antiproton pT to switch to TOF pid (GeV/c) "}; + Configurable antipPtMax{"antipPtMax", 0.9f, "maximum antiproton pT (GeV/c)"}; + + Configurable lambdaPtMin{"lambdaPtMin", 0.5f, "minimum (anti)lambda pT (GeV/c)"}; + Configurable lambdaPtMax{"lambdaPtMax", 3.0f, "maximum (anti)lambda pT (GeV/c)"}; + + Configurable trackNcrossedRows{"trackNcrossedRows", 70, "Minimum number of crossed TPC rows"}; + Configurable trackNclusItsCut{"trackNclusITScut", 5, "Minimum number of ITS clusters"}; + Configurable trackNclusTpcCut{"trackNclusTPCcut", 70, "Minimum number of TPC clusters"}; + Configurable trackDcaCut{"trackDcaCut", 0.1f, "DCA antid to PV"}; + + Configurable v0trackNcrossedRows{"v0trackNcrossedRows", 70, "Minimum number of crossed TPC rows for V0 daughter"}; + Configurable v0trackNclusItsCut{"v0trackNclusITScut", 1, "Minimum number of ITS clusters for V0 daughter"}; + Configurable v0trackNclusTpcCut{"v0trackNclusTPCcut", 70, "Minimum number of TPC clusters for V0 daughter"}; + Configurable v0trackNsharedClusTpc{"v0trackNsharedClusTpc", 10, "Maximum number of shared TPC clusters for V0 daughter"}; + Configurable v0requireITSrefit{"v0requireITSrefit", false, "require ITS refit for V0 daughter"}; + Configurable vetoMassK0Short{"vetoMassK0Short", -999.f, "veto for V0 compatible with K0s mass"}; + Configurable v0radiusMax{"v0radiusMax", 100.f, "maximum V0 radius eccepted"}; + + Configurable antidNsigmaTpcCutLow{"antidNsigmaTpcCutLow", 4.f, "TPC PID cut low"}; + Configurable antidNsigmaTpcCutUp{"antidNsigmaTpcCutUp", 4.f, "TPC PID cut up"}; + Configurable antidNsigmaTofCut{"antidNsigmaTofCut", 4.f, "TOF PID cut"}; + Configurable antidTpcInnerParamMax{"tpcInnerParamMax", 0.6f, "(temporary) tpc inner param cut"}; + Configurable antidTofMassMax{"tofMassMax", 0.3f, "(temporary) tof mass cut"}; + + Configurable antipNsigmaTpcCutLow{"antipNsigmaTpcCutLow", 4.f, "TPC PID cut low"}; + Configurable antipNsigmaTpcCutUp{"antipNsigmaTpcCutUp", 4.f, "TPC PID cut up"}; + Configurable antipNsigmaTofCut{"antipNsigmaTofCut", 4.f, "TOF PID cut"}; + Configurable antipTpcInnerParamMax{"antipTpcInnerParamMax", 0.6f, "(temporary) tpc inner param cut"}; + Configurable antipTofMassMax{"antipTofMassMax", 0.3f, "(temporary) tof mass cut"}; + Configurable tofMassMaxQA{"tofMassMaxQA", 0.6f, "(temporary) tof mass cut (for QA histograms)"}; + + Configurable v0setting_dcav0dau{"v0setting_dcav0dau", 1, "DCA V0 Daughters"}; + Configurable v0setting_dcav0pv{"v0setting_dcav0pv", 1, "DCA V0 to Pv"}; + Configurable v0setting_dcadaughtopv{"v0setting_dcadaughtopv", 0.1f, "DCA Pos To PV"}; + Configurable v0setting_cospa{"v0setting_cospa", 0.98, "V0 CosPA"}; + Configurable v0setting_radius{"v0setting_radius", 0.5f, "v0radius"}; + Configurable v0setting_lifetime{"v0setting_lifetime", 40.f, "v0 lifetime cut"}; + Configurable v0setting_nsigmatpc{"v0setting_nsigmatpc", 4.f, "nsigmatpc"}; + Configurable lambdaMassCut{"lambdaMassCut", 0.005f, "maximum deviation from PDG mass"}; + Configurable lambdaMassCutQA{"lambdaMassCutQA", 0.02f, "maximum deviation from PDG mass (for QA histograms)"}; + + Configurable antidItsClsSizeCut{"antidItsClsSizeCut", 2.f, "cluster size cut for antideuterons"}; + Configurable antidPtItsClsSizeCut{"antidPtItsClsSizeCut", 1.f, "pt for cluster size cut for antideuterons"}; + } config; std::array ptMin; std::array ptTof; @@ -276,21 +286,22 @@ struct antidLambdaEbye { template bool selectV0Daughter(T const& track) { - if (std::abs(track.eta()) > etaMaxV0dau) { + if (std::abs(track.eta()) > config.etaMaxV0dau) { return false; } - if (track.itsNCls() < v0trackNclusItsCut || - track.tpcNClsFound() < v0trackNclusTpcCut || - track.tpcNClsCrossedRows() < v0trackNclusTpcCut || + if (track.itsNCls() < config.v0trackNclusItsCut || + track.tpcNClsFound() < config.v0trackNclusTpcCut || + track.tpcNClsCrossedRows() < config.v0trackNclusTpcCut || track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || - track.tpcNClsShared() > v0trackNsharedClusTpc) { + track.tpcNClsShared() > config.v0trackNsharedClusTpc) { return false; } if (doprocessRun2 || doprocessMcRun2) { - if (!(track.flags() & o2::aod::track::TrackFlagsRun2Enum::TPCrefit)) { + if (!(track.trackType() & o2::aod::track::Run2Track) || + !(track.flags() & o2::aod::track::TPCrefit)) { return false; } - if (v0requireITSrefit && !(track.flags() & o2::aod::track::TrackFlagsRun2Enum::ITSrefit)) { + if (config.v0requireITSrefit && !(track.flags() & o2::aod::track::ITSrefit)) { return false; } } @@ -300,23 +311,24 @@ struct antidLambdaEbye { template bool selectTrack(T const& track) { - if (std::abs(track.eta()) > etaMax) { + if (std::abs(track.eta()) > config.etaMax) { return false; } if (!(track.itsClusterMap() & 0x01) && !(track.itsClusterMap() & 0x02)) { return false; } - if (track.itsNCls() < trackNclusItsCut || - track.tpcNClsFound() < trackNclusTpcCut || - track.tpcNClsCrossedRows() < trackNcrossedRows || + if (track.itsNCls() < config.trackNclusItsCut || + track.tpcNClsFound() < config.trackNclusTpcCut || + track.tpcNClsCrossedRows() < config.trackNcrossedRows || track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || track.tpcChi2NCl() > 4.f || track.itsChi2NCl() > 36.f) { return false; } if (doprocessRun2 || doprocessMcRun2) { - if (!(track.flags() & o2::aod::track::TrackFlagsRun2Enum::TPCrefit) || - !(track.flags() & o2::aod::track::TrackFlagsRun2Enum::ITSrefit)) { + if (!(track.trackType() & o2::aod::track::Run2Track) || + !(track.flags() & o2::aod::track::TPCrefit) || + !(track.flags() & o2::aod::track::ITSrefit)) { return false; } } @@ -413,10 +425,12 @@ struct antidLambdaEbye { fitter.setMaxR(200.); fitter.setMinParamChange(1e-3); fitter.setMinRelChi2Change(0.9); - fitter.setMaxDZIni(1e9); + fitter.setMaxDZIni(4); + fitter.setMaxDXYIni(1); fitter.setMaxChi2(1e9); fitter.setUseAbsDCA(true); - int mat{static_cast(cfgMaterialCorrection)}; + fitter.setWeightedFinalPCA(false); + int mat{static_cast(config.cfgMaterialCorrection)}; fitter.setMatCorrType(static_cast(mat)); uint32_t randomSeed = static_cast(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); @@ -431,6 +445,8 @@ struct antidLambdaEbye { histos.add("QA/nRecPerEvAntip", ";Centrality (%);#it{N}_{#bar{p}};#it{N}_{ev}", HistType::kTH2D, {centAxis, nGenRecAxis}); histos.add("QA/nRecPerEvAntiL", ";Centrality (%);#it{N}_{#bar{#Lambda}};#it{N}_{ev}", HistType::kTH2D, {centAxis, nGenRecAxis}); histos.add("QA/nRecPerEvL", ";Centrality (%);#it{N}_{#Lambda};#it{N}_{ev}", HistType::kTH2D, {centAxis, nGenRecAxis}); + histos.add("QA/nTrklCorrelation", ";Tracklets |#eta| > 0.6; Tracklets |#eta| < 0.6", HistType::kTH2D, {{201, -0.5, 200.5}, {201, -0.5, 200.5}}); + histos.add("QA/TrklEta", ";Tracklets #eta; Entries", HistType::kTH1D, {{100, -3., 3.}}); nAntid = histos.add("nAntid", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{d}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptAntidAxis}); nAntip = histos.add("nAntip", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{p}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptAntipAxis}); @@ -475,13 +491,26 @@ struct antidLambdaEbye { // v0 QA histos.add("QA/massLambda", ";Centrality (%);#it{p}_{T} (GeV/#it{c});#it{M}(p + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH3F, {centAxis, momAxis, massLambdaAxis}); histos.add("QA/cosPa", ";cosPa;Entries", HistType::kTH1F, {cosPaAxis}); + histos.add("QA/cosPaSig", ";cosPa;Entries", HistType::kTH1F, {cosPaAxis}); + histos.add("QA/cosPaBkg", ";cosPa;Entries", HistType::kTH1F, {cosPaAxis}); + histos.add("QA/dcaV0daughSig", ";dcaV0daugh;Entries", HistType::kTH1F, {dcaV0daughAxis}); + histos.add("QA/dcaV0daughBkg", ";dcaV0daugh;Entries", HistType::kTH1F, {dcaV0daughAxis}); + histos.add("QA/dcaV0PvSig", ";dcaV0Pv;Entries", HistType::kTH1F, {dcaV0daughAxis}); + histos.add("QA/dcaV0PvBkg", ";dcaV0Pv;Entries", HistType::kTH1F, {dcaV0daughAxis}); + histos.add("QA/cosPaDcaV0daughSig", ";cosPa;dcaV0daugh", HistType::kTH2F, {cosPaAxis, dcaV0daughAxis}); + histos.add("QA/cosPaDcaV0daughBkg", ";cosPa;dcaV0daugh", HistType::kTH2F, {cosPaAxis, dcaV0daughAxis}); + histos.add("QA/massLambdaEvRej", ";Centrality (%);#it{p}_{T} (GeV/#it{c});#it{M}(p + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH3F, {centAxis, momAxis, massLambdaAxis}); + histos.add("QA/massLambdaEvRejSig", ";Centrality (%);#it{p}_{T} (GeV/#it{c});#it{M}(p + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH3F, {centAxis, momAxis, massLambdaAxis}); + histos.add("QA/massLambdaEvRejBkg", ";Centrality (%);#it{p}_{T} (GeV/#it{c});#it{M}(p + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH3F, {centAxis, momAxis, massLambdaAxis}); histos.add("QA/radius", ";radius;Entries", HistType::kTH1F, {radiusAxis}); histos.add("QA/dcaV0daugh", ";dcaV0daugh;Entries", HistType::kTH1F, {dcaV0daughAxis}); + histos.add("QA/dcaV0Pv", ";dcaV0Pv;Entries", HistType::kTH1F, {dcaV0daughAxis}); histos.add("QA/dcaPosPv", ";dcaPosPv;Entries", HistType::kTH1F, {dcaDaughPvAxis}); histos.add("QA/dcaNegPv", ";dcaNegPv;Entries", HistType::kTH1F, {dcaDaughPvAxis}); histos.add("QA/cosPaBeforeCut", ";cosPa;Entries", HistType::kTH1F, {cosPaAxis}); histos.add("QA/radiusBeforeCut", ";radius;Entries", HistType::kTH1F, {radiusAxis}); histos.add("QA/dcaV0daughBeforeCut", ";dcaV0daugh;Entries", HistType::kTH1F, {dcaV0daughAxis}); + histos.add("QA/dcaV0PvBeforeCut", ";dcaV0Pv;Entries", HistType::kTH1F, {dcaV0daughAxis}); // d QA histos.add("QA/dcaPv", ";#it{p}_{T} (GeV/#it{c});dcaPv;Entries", HistType::kTH2F, {momAxis, dcaDaughPvAxis}); @@ -529,15 +558,15 @@ struct antidLambdaEbye { tempLambda = tempHistos.add("tempLambda", ";#Delta#eta;#it{p}_{T} (GeV/#it{c})", HistType::kTH2D, {deltaEtaAxis, ptLambdaAxis}); tempAntiLambda = tempHistos.add("tempAntiLambda", ";#Delta#eta;#it{p}_{T} (GeV/#it{c})", HistType::kTH2D, {deltaEtaAxis, ptLambdaAxis}); - ptMin = std::array{antipPtMin, antidPtMin}; - ptMax = std::array{antipPtMax, antidPtMax}; - ptTof = std::array{antipPtTof, antidPtTof}; + ptMin = std::array{config.antipPtMin, config.antidPtMin}; + ptMax = std::array{config.antipPtMax, config.antidPtMax}; + ptTof = std::array{config.antipPtTof, config.antidPtTof}; - nSigmaTpcCutLow = std::array{antipNsigmaTpcCutLow, antidNsigmaTpcCutLow}; - nSigmaTpcCutUp = std::array{antipNsigmaTpcCutUp, antidNsigmaTpcCutUp}; - nSigmaTofCut = std::array{antipNsigmaTofCut, antidNsigmaTofCut}; - tpcInnerParamMax = std::array{antipTpcInnerParamMax, antidTpcInnerParamMax}; - tofMassMax = std::array{antipTofMassMax, antidTofMassMax}; + nSigmaTpcCutLow = std::array{config.antipNsigmaTpcCutLow, config.antidNsigmaTpcCutLow}; + nSigmaTpcCutUp = std::array{config.antipNsigmaTpcCutUp, config.antidNsigmaTpcCutUp}; + nSigmaTofCut = std::array{config.antipNsigmaTofCut, config.antidNsigmaTofCut}; + tpcInnerParamMax = std::array{config.antipTpcInnerParamMax, config.antidTpcInnerParamMax}; + tofMassMax = std::array{config.antipTofMassMax, config.antidTofMassMax}; } template @@ -556,11 +585,17 @@ struct antidLambdaEbye { auto subsample = static_cast(rnd * nSubsamples); gpu::gpustd::array dcaInfo; + int nTracklets[2]{0, 0}; for (const auto& track : tracks) { histos.fill(HIST("QA/nClsTPCBeforeCut"), track.tpcNClsFound()); histos.fill(HIST("QA/nCrossedRowsTPCBeforeCut"), track.tpcNClsCrossedRows()); + if (track.trackType() == 255 && std::abs(track.eta()) < 1.2) { // tracklet + nTracklets[std::abs(track.eta()) < 0.6]++; + histos.fill(HIST("QA/TrklEta"), track.eta()); + } + if (!selectTrack(track)) { continue; } @@ -575,7 +610,7 @@ struct antidLambdaEbye { auto trackPt = trackParCov.getPt(); auto trackEta = trackParCov.getEta(); histos.fill(HIST("QA/dcaPvBefore"), trackPt, dca); - if (dca > trackDcaCut) { + if (dca > config.trackDcaCut) { continue; } histos.fill(HIST("QA/dcaPv"), trackPt, dca); @@ -592,21 +627,21 @@ struct antidLambdaEbye { if (doprocessRun3 || doprocessMcRun3) { float cosL = 1 / std::sqrt(1.f + track.tgl() * track.tgl()); - if (iP && getITSClSize(track) * cosL < antidItsClsSizeCut && trackPt < antidPtItsClsSizeCut) { + if (iP && getITSClSize(track) * cosL < config.antidItsClsSizeCut && trackPt < config.antidPtItsClsSizeCut) { continue; } } - double expBethe{tpc::BetheBlochAleph(static_cast(track.tpcInnerParam() / partMass[iP]), cfgBetheBlochParams->get(iP, "p0"), cfgBetheBlochParams->get(iP, "p1"), cfgBetheBlochParams->get(iP, "p2"), cfgBetheBlochParams->get(iP, "p3"), cfgBetheBlochParams->get(iP, "p4"))}; - double expSigma{expBethe * cfgBetheBlochParams->get(iP, "resolution")}; + double expBethe{tpc::BetheBlochAleph(static_cast(track.tpcInnerParam() / partMass[iP]), config.cfgBetheBlochParams->get(iP, "p0"), config.cfgBetheBlochParams->get(iP, "p1"), config.cfgBetheBlochParams->get(iP, "p2"), config.cfgBetheBlochParams->get(iP, "p3"), config.cfgBetheBlochParams->get(iP, "p4"))}; + double expSigma{expBethe * config.cfgBetheBlochParams->get(iP, "resolution")}; auto nSigmaTPC = static_cast((track.tpcSignal() - expBethe) / expSigma); - float beta{track.hasTOF() ? track.length() / (track.tofSignal() - track.tofEvTime()) * o2::pid::tof::kCSPEDDInv : -999.f}; + float beta{track.hasTOF() ? track.length() / (track.tofSignal() - track.tofEvTime()) * o2::constants::physics::invLightSpeedCm2PS : -999.f}; beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); float mass{track.tpcInnerParam() * std::sqrt(1.f / (beta * beta) - 1.f)}; bool hasTof = track.hasTOF() && track.tofChi2() < 3; - if (trackPt <= ptTof[iP] || (trackPt > ptTof[iP] && hasTof && std::abs(mass - partMass[iP]) < tofMassMaxQA)) { // for QA histograms + if (trackPt <= ptTof[iP] || (trackPt > ptTof[iP] && hasTof && std::abs(mass - partMass[iP]) < config.tofMassMaxQA)) { // for QA histograms tpcNsigmaGlo[iP]->Fill(centrality, trackPt, nSigmaTPC); if (nSigmaTPC > nSigmaTpcCutLow[iP] && nSigmaTPC < nSigmaTpcCutUp[iP]) { tofMass[iP]->Fill(centrality, trackPt, mass); @@ -641,6 +676,7 @@ struct antidLambdaEbye { } } } + histos.fill(HIST("QA/nTrklCorrelation"), nTracklets[0], nTracklets[1]); std::vector trkId; for (const auto& v0 : V0s) { @@ -653,8 +689,8 @@ struct antidLambdaEbye { continue; if (doprocessRun2 || doprocessMcRun2) { - bool checkPosPileUp = posTrack.hasTOF() || (posTrack.flags() & o2::aod::track::TrackFlagsRun2Enum::ITSrefit); - bool checkNegPileUp = negTrack.hasTOF() || (negTrack.flags() & o2::aod::track::TrackFlagsRun2Enum::ITSrefit); + bool checkPosPileUp = posTrack.hasTOF() || (posTrack.flags() & o2::aod::track::ITSrefit); + bool checkNegPileUp = negTrack.hasTOF() || (negTrack.flags() & o2::aod::track::ITSrefit); if (!checkPosPileUp && !checkNegPileUp) { continue; } @@ -685,12 +721,12 @@ struct antidLambdaEbye { momTotXYZ(momV0, momPos, momNeg); auto ptV0 = std::hypot(momV0[0], momV0[1]); - if (ptV0 < lambdaPtMin || ptV0 > lambdaPtMax) { + if (ptV0 < config.lambdaPtMin || ptV0 > config.lambdaPtMax) { continue; } auto etaV0 = etaFromMom(momPos, momNeg); - if (std::abs(etaV0) > etaMax) { + if (std::abs(etaV0) > config.etaMax) { continue; } @@ -701,14 +737,26 @@ struct antidLambdaEbye { auto mLambda = invMass2Body(momV0, momPos, momNeg, massPos, massNeg); auto mK0Short = invMass2Body(momV0, momPos, momNeg, o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged); + // pid selections + double expBethePos{tpc::BetheBlochAleph(static_cast(posTrack.tpcInnerParam() / massPos), config.cfgBetheBlochParams->get("p0"), config.cfgBetheBlochParams->get("p1"), config.cfgBetheBlochParams->get("p2"), config.cfgBetheBlochParams->get("p3"), config.cfgBetheBlochParams->get("p4"))}; + double expSigmaPos{expBethePos * config.cfgBetheBlochParams->get("resolution")}; + auto nSigmaTPCPos = static_cast((posTrack.tpcSignal() - expBethePos) / expSigmaPos); + double expBetheNeg{tpc::BetheBlochAleph(static_cast(negTrack.tpcInnerParam() / massNeg), config.cfgBetheBlochParams->get("p0"), config.cfgBetheBlochParams->get("p1"), config.cfgBetheBlochParams->get("p2"), config.cfgBetheBlochParams->get("p3"), config.cfgBetheBlochParams->get("p4"))}; + double expSigmaNeg{expBetheNeg * config.cfgBetheBlochParams->get("resolution")}; + auto nSigmaTPCNeg = static_cast((negTrack.tpcSignal() - expBetheNeg) / expSigmaNeg); + + if (std::abs(nSigmaTPCPos) > config.v0setting_nsigmatpc || std::abs(nSigmaTPCNeg) > config.v0setting_nsigmatpc) { + continue; + } + // veto on K0s mass - if (std::abs(mK0Short - o2::constants::physics::MassK0Short) < vetoMassK0Short) { + if (std::abs(mK0Short - o2::constants::physics::MassK0Short) < config.vetoMassK0Short) { continue; } float dcaV0dau = std::sqrt(fitter.getChi2AtPCACandidate()); histos.fill(HIST("QA/dcaV0daughBeforeCut"), dcaV0dau); - if (dcaV0dau > v0setting_dcav0dau) { + if (dcaV0dau > config.v0setting_dcav0dau) { continue; } @@ -717,34 +765,52 @@ struct antidLambdaEbye { float radiusV0 = std::hypot(vtx[0], vtx[1]); histos.fill(HIST("QA/radiusBeforeCut"), radiusV0); - if (radiusV0 < v0setting_radius || radiusV0 > v0radiusMax) { + if (radiusV0 < config.v0setting_radius || radiusV0 > config.v0radiusMax) { + continue; + } + + float dcaV0Pv = CalculateDCAStraightToPV( + vtx[0], vtx[1], vtx[2], + momPos[0] + momNeg[0], + momPos[1] + momNeg[1], + momPos[2] + momNeg[2], + collision.posX(), collision.posY(), collision.posZ()); + histos.fill(HIST("QA/dcaV0PvBeforeCut"), dcaV0Pv); + if (std::abs(dcaV0Pv) > config.v0setting_dcav0pv) { continue; } double cosPA = RecoDecay::cpa(primVtx, vtx, momV0); histos.fill(HIST("QA/cosPaBeforeCut"), cosPA); - if (cosPA < v0setting_cospa) { + if (cosPA < config.v0setting_cospa) { + continue; + } + + auto ptotal = RecoDecay::sqrtSumOfSquares(momV0[0], momV0[1], momV0[2]); + auto lengthTraveled = RecoDecay::sqrtSumOfSquares(vtx[0] - primVtx[0], vtx[1] - primVtx[1], vtx[2] - primVtx[2]); + float ML2P_Lambda = o2::constants::physics::MassLambda * lengthTraveled / ptotal; + if (ML2P_Lambda > config.v0setting_lifetime) { continue; } o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, posTrackCov, 2.f, fitter.getMatCorrType(), &dcaInfo); auto posDcaToPv = std::hypot(dcaInfo[0], dcaInfo[1]); - if (posDcaToPv < v0setting_dcapostopv) { + if (posDcaToPv < config.v0setting_dcadaughtopv && std::abs(dcaInfo[0]) < config.v0setting_dcadaughtopv) { continue; } o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, negTrackCov, 2.f, fitter.getMatCorrType(), &dcaInfo); auto negDcaToPv = std::hypot(dcaInfo[0], dcaInfo[1]); - if (negDcaToPv < v0setting_dcanegtopv) { + if (negDcaToPv < config.v0setting_dcadaughtopv && std::abs(dcaInfo[0]) < config.v0setting_dcadaughtopv) { continue; } - if (std::abs(mLambda - o2::constants::physics::MassLambda0) > lambdaMassCutQA) { // for QA histograms + if (std::abs(mLambda - o2::constants::physics::MassLambda0) > config.lambdaMassCutQA) { // for QA histograms continue; } histos.fill(HIST("QA/massLambda"), centrality, ptV0, mLambda); - if (std::abs(mLambda - o2::constants::physics::MassLambda0) > lambdaMassCut) { + if (std::abs(mLambda - o2::constants::physics::MassLambda0) > config.lambdaMassCut) { continue; } histos.fill(HIST("QA/cosPa"), cosPA); @@ -752,6 +818,7 @@ struct antidLambdaEbye { histos.fill(HIST("QA/dcaV0daugh"), dcaV0dau); histos.fill(HIST("QA/dcaPosPv"), posDcaToPv); histos.fill(HIST("QA/dcaNegPv"), negDcaToPv); + histos.fill(HIST("QA/dcaV0Pv"), dcaV0Pv); if (matter) { tempHistos.fill(HIST("tempLambda"), std::abs(etaV0), ptV0); @@ -765,6 +832,10 @@ struct antidLambdaEbye { CandidateV0 candV0; candV0.pt = ptV0; candV0.eta = etaV0; + candV0.mass = mLambda; + candV0.cpa = cosPA; + candV0.dcav0daugh = dcaV0dau; + candV0.dcav0pv = dcaV0Pv; candV0.globalIndexPos = posTrack.globalIndex(); candV0.globalIndexNeg = negTrack.globalIndex(); candidateV0s.push_back(candV0); @@ -772,7 +843,7 @@ struct antidLambdaEbye { // reject events having multiple v0s from same tracks (TODO: also across collisions?) std::sort(trkId.begin(), trkId.end()); - if (std::adjacent_find(trkId.begin(), trkId.end()) != trkId.end()) { + if ((std::adjacent_find(trkId.begin(), trkId.end()) != trkId.end()) && config.fillOnlySignal) { candidateV0s.clear(); CandidateV0 candV0; @@ -783,10 +854,13 @@ struct antidLambdaEbye { candidateV0s.push_back(candV0); return -1; } + for (auto& candidateV0 : candidateV0s) { + histos.fill(HIST("QA/massLambdaEvRej"), centrality, candidateV0.pt, candidateV0.mass); + } histos.fill(HIST("nEv"), subsample, centrality); - if ((doprocessMcRun3 || doprocessMcRun2) && fillOnlySignal) + if ((doprocessMcRun3 || doprocessMcRun2) && config.fillOnlySignal) return subsample; fillHistoN(nAntip, tempTracks[0], subsample, centrality); @@ -820,7 +894,7 @@ struct antidLambdaEbye { return; } - if (fillOnlySignal) { + if (config.fillOnlySignal) { tempTracks[0]->Reset(); tempTracks[1]->Reset(); tempLambda->Reset(); @@ -842,7 +916,7 @@ struct antidLambdaEbye { recTracks[iP]->Fill(centrality, candidateTrack.pt, std::abs(candidateTrack.eta)); } else { recAntiTracks[iP]->Fill(centrality, candidateTrack.pt, std::abs(candidateTrack.eta)); - if (fillOnlySignal) + if (config.fillOnlySignal) tempTracks[iP]->Fill(std::abs(candidateTrack.eta), candidateTrack.pt); } } @@ -862,19 +936,30 @@ struct antidLambdaEbye { continue; if (!((mcTrackPos.pdgCode() == 2212 && mcTrackNeg.pdgCode() == -211) || (mcTrackPos.pdgCode() == 211 && mcTrackNeg.pdgCode() == -2212))) continue; - if (std::abs(posMother.pdgCode()) != 3122) + if (std::abs(posMother.pdgCode()) != 3122) { + histos.fill(HIST("QA/cosPaBkg"), candidateV0.cpa); + histos.fill(HIST("QA/dcaV0daughBkg"), candidateV0.dcav0daugh); + histos.fill(HIST("QA/dcaV0PvBkg"), candidateV0.dcav0pv); + histos.fill(HIST("QA/cosPaDcaV0daughBkg"), candidateV0.cpa, candidateV0.dcav0daugh); + histos.fill(HIST("QA/massLambdaEvRejBkg"), centrality, candidateV0.pt, candidateV0.mass); continue; + } if (!posMother.isPhysicalPrimary() && !posMother.has_mothers()) continue; if (((posMother.flags() & 0x8) && doprocessMcRun2) || (posMother.flags() & 0x2) || (posMother.flags() & 0x1)) continue; + histos.fill(HIST("QA/cosPaSig"), candidateV0.cpa); + histos.fill(HIST("QA/dcaV0daughSig"), candidateV0.dcav0daugh); + histos.fill(HIST("QA/dcaV0PvSig"), candidateV0.dcav0pv); + histos.fill(HIST("QA/cosPaDcaV0daughSig"), candidateV0.cpa, candidateV0.dcav0daugh); + histos.fill(HIST("QA/massLambdaEvRejSig"), centrality, candidateV0.pt, candidateV0.mass); if (posMother.pdgCode() > 0) { histos.fill(HIST("recL"), centrality, candidateV0.pt, std::abs(candidateV0.eta)); - if (fillOnlySignal) + if (config.fillOnlySignal) tempLambda->Fill(std::abs(candidateV0.eta), candidateV0.pt); } else { histos.fill(HIST("recAntiL"), centrality, candidateV0.pt, std::abs(candidateV0.eta)); - if (fillOnlySignal) + if (config.fillOnlySignal) tempAntiLambda->Fill(std::abs(candidateV0.eta), candidateV0.pt); } } @@ -883,7 +968,7 @@ struct antidLambdaEbye { } } - if (fillOnlySignal) { + if (config.fillOnlySignal) { fillHistoN(nAntip, tempTracks[0], subsample, centrality); fillHistoN(nAntid, tempTracks[1], subsample, centrality); fillHistoN(nAntiL, tempAntiLambda, subsample, centrality); @@ -924,7 +1009,7 @@ struct antidLambdaEbye { auto mcParticles_thisCollision = mcParticles.sliceBy(perCollisionMcParts, iC); for (auto& mcPart : mcParticles_thisCollision) { auto genEta = mcPart.eta(); - if (std::abs(genEta) > etaMax) { + if (std::abs(genEta) > config.etaMax) { continue; } if (((mcPart.flags() & 0x8) && doprocessMcRun2) || (mcPart.flags() & 0x2) || (mcPart.flags() & 0x1)) @@ -995,7 +1080,7 @@ struct antidLambdaEbye { if (!collision.sel8()) continue; - if (std::abs(collision.posZ()) > zVtxMax) + if (std::abs(collision.posZ()) > config.zVtxMax) continue; if (!collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) @@ -1032,21 +1117,21 @@ struct antidLambdaEbye { auto bc = collision.bc_as(); initCCDB(bc); - if (std::abs(collision.posZ()) > zVtxMax) + if (std::abs(collision.posZ()) > config.zVtxMax) continue; if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kAliEventCutsAccepted))) continue; - if (kUseTPCPileUpCut && !(bc.eventCuts() & BIT(aod::Run2EventCuts::kTPCPileUp))) + if (config.kUseTPCPileUpCut && !(bc.eventCuts() & BIT(aod::Run2EventCuts::kTPCPileUp))) continue; auto centrality = collision.centRun2V0M(); - if (!(collision.sel7() && collision.alias_bit(kINT7)) && (!kINT7Intervals || (kINT7Intervals && ((centrality >= 10 && centrality < 30) || centrality > 50)))) + if (!(collision.sel7() && collision.alias_bit(kINT7)) && (!config.kINT7Intervals || (config.kINT7Intervals && ((centrality >= 10 && centrality < 30) || centrality > 50)))) continue; auto centralityCl0 = collision.centRun2CL0(); - if (kUseEstimatorsCorrelationCut) { + if (config.kUseEstimatorsCorrelationCut) { const auto& x = centralityCl0; const double center = estimatorsCorrelationCoef[0] + estimatorsCorrelationCoef[1] * x; const double sigma = estimatorsSigmaPars[0] + estimatorsSigmaPars[1] * x + estimatorsSigmaPars[2] * std::pow(x, 2) + estimatorsSigmaPars[3] * std::pow(x, 3); @@ -1092,7 +1177,7 @@ struct antidLambdaEbye { if (!collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) continue; - if (std::abs(collision.posZ()) > zVtxMax) + if (std::abs(collision.posZ()) > config.zVtxMax) continue; auto centrality = collision.centFT0C(); @@ -1122,7 +1207,7 @@ struct antidLambdaEbye { auto bc = collision.bc_as(); initCCDB(bc); - if (std::abs(collision.posZ()) > zVtxMax) + if (std::abs(collision.posZ()) > config.zVtxMax) continue; if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kAliEventCutsAccepted))) diff --git a/PWGLF/Tasks/Nuspex/antinucleiInJets.cxx b/PWGLF/Tasks/Nuspex/antinucleiInJets.cxx new file mode 100644 index 00000000000..5ddaa882de8 --- /dev/null +++ b/PWGLF/Tasks/Nuspex/antinucleiInJets.cxx @@ -0,0 +1,1573 @@ +// 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 antinucleiInJets.cxx +/// +/// \brief task for analysis of antinuclei in jets using Fastjet +/// \author Alberto Caliva (alberto.caliva@cern.ch), Chiara Pinto (chiara.pinto@cern.ch) +/// \since February 13, 2025 + +#include +#include +#include +#include +#include +#include +#include +#include +#include "TGrid.h" +#include +#include + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/DataTypes.h" +#include "Framework/Logger.h" +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/DCA.h" +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include "PWGJE/Core/JetBkgSubUtils.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/Jet.h" + +using namespace std; +using namespace o2; +using namespace o2::soa; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; +using namespace o2::constants::math; +using std::array; + +using SelectedCollisions = soa::Join; +using SimCollisions = soa::Join; + +using FullNucleiTracks = soa::Join; + +using MCTracks = soa::Join; + +struct AntinucleiInJets { + + // histogram registries + HistogramRegistry registryData{"registryData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryMC{"registryMC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryQC{"registryQC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // global parameters + Configurable minJetPt{"minJetPt", 10.0, "Minimum pt of the jet"}; + Configurable rJet{"rJet", 0.3, "Jet resolution parameter R"}; + Configurable zVtx{"zVtx", 10.0, "Maximum zVertex"}; + Configurable deltaEtaEdge{"deltaEtaEdge", 0.05, "eta gap from the edge"}; + + // track parameters + Configurable requirePvContributor{"requirePvContributor", false, "require that the track is a PV contributor"}; + Configurable applyItsPid{"applyItsPid", true, "apply ITS PID"}; + Configurable rejectEvents{"rejectEvents", false, "reject some events"}; + Configurable rejectionPercentage{"rejectionPercentage", 3, "percentage of events to reject"}; + Configurable minItsNclusters{"minItsNclusters", 5, "minimum number of ITS clusters"}; + Configurable minTpcNcrossedRows{"minTpcNcrossedRows", 80, "minimum number of TPC crossed pad rows"}; + Configurable minTpcNcrossedRowsOverFindable{"minTpcNcrossedRowsOverFindable", 0.8, "crossed rows/findable"}; + Configurable maxChiSquareTpc{"maxChiSquareTpc", 4.0, "maximum TPC chi^2/Ncls"}; + Configurable maxChiSquareIts{"maxChiSquareIts", 36.0, "maximum ITS chi^2/Ncls"}; + Configurable minPt{"minPt", 0.3, "minimum pt of the tracks"}; + Configurable minEta{"minEta", -0.8, "minimum eta"}; + Configurable maxEta{"maxEta", +0.8, "maximum eta"}; + Configurable maxDcaxy{"maxDcaxy", 0.05, "Maximum DCAxy"}; + Configurable maxDcaz{"maxDcaz", 0.05, "Maximum DCAz"}; + Configurable minNsigmaTpc{"minNsigmaTpc", -3.0, "Minimum nsigma TPC"}; + Configurable maxNsigmaTpc{"maxNsigmaTpc", +3.0, "Maximum nsigma TPC"}; + Configurable minNsigmaTof{"minNsigmaTof", -3.0, "Minimum nsigma TOF"}; + Configurable maxNsigmaTof{"maxNsigmaTof", +3.5, "Maximum nsigma TOF"}; + Configurable ptMaxItsPidProt{"ptMaxItsPidProt", 1.0, "maximum pt for ITS PID for protons"}; + Configurable ptMaxItsPidDeut{"ptMaxItsPidDeut", 1.0, "maximum pt for ITS PID for deuterons"}; + Configurable ptMaxItsPidHel{"ptMaxItsPidHel", 1.0, "maximum pt for ITS PID for helium"}; + Configurable nSigmaItsMin{"nSigmaItsMin", -2.0, "nSigmaITS min"}; + Configurable nSigmaItsMax{"nSigmaItsMax", +2.0, "nSigmaITS max"}; + + // reweighting + Configurable applyReweighting{"applyReweighting", true, "apply reweighting"}; + Configurable urlToCcdb{"urlToCcdb", "http://alice-ccdb.cern.ch", "url of the personal ccdb"}; + Configurable pathToFile{"pathToFile", "", "path to file with reweighting"}; + Configurable histoNameWeightAntipJet{"histoNameWeightAntipJet", "", "reweighting histogram: antip in jet"}; + Configurable histoNameWeightAntipUe{"histoNameWeightAntipUe", "", "reweighting histogram: antip in ue"}; + TH2F* twoDweightsAntipJet; + TH2F* twoDweightsAntipUe; + + // jet pt unfolding + Configurable applyPtUnfolding{"applyPtUnfolding", true, "apply jet pt unfolding"}; + Configurable urlToCcdbPtUnfolding{"urlToCcdbPtUnfolding", "http://alice-ccdb.cern.ch", "url of the personal ccdb"}; + Configurable pathToFilePtUnfolding{"pathToFilePtUnfolding", "Users/c/chpinto/My/Object/ResponseMatrix", "path to file with pt unfolding"}; + Configurable histoNamePtUnfolding{"histoNamePtUnfolding", "detectorResponseMatrix", "pt unfolding histogram"}; + TH2F* responseMatrix; + + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + + JetBkgSubUtils backgroundSub; + + void init(InitContext const&) + { + ccdb->setURL(urlToCcdb.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + ccdb->setFatalWhenNull(false); + + if (applyReweighting) { + getReweightingHistograms(ccdb, TString(pathToFile), TString(histoNameWeightAntipJet), TString(histoNameWeightAntipUe)); + } else { + twoDweightsAntipJet = nullptr; + twoDweightsAntipUe = nullptr; + } + + if (applyPtUnfolding) { + getPtUnfoldingHistogram(ccdb, TString(pathToFilePtUnfolding), TString(histoNamePtUnfolding)); + } else { + responseMatrix = nullptr; + } + + // binning + double min = 0.0; + double max = 6.0; + int nbins = 120; + + // QC histograms + if (doprocessQC) { + registryQC.add("deltaEta_deltaPhi_jet", "deltaEta_deltaPhi_jet", HistType::kTH2F, {{200, -0.5, 0.5, "#Delta#eta"}, {200, 0, PIHalf, "#Delta#phi"}}); + registryQC.add("deltaEta_deltaPhi_ue", "deltaEta_deltaPhi_ue", HistType::kTH2F, {{200, -0.5, 0.5, "#Delta#eta"}, {200, 0, PIHalf, "#Delta#phi"}}); + registryQC.add("eta_phi_jet", "eta_phi_jet", HistType::kTH2F, {{200, -0.5, 0.5, "#eta_{jet}"}, {200, 0, TwoPI, "#phi_{jet}"}}); + registryQC.add("eta_phi_ue", "eta_phi_ue", HistType::kTH2F, {{200, -0.5, 0.5, "#eta_{UE}"}, {200, 0, TwoPI, "#phi_{UE}"}}); + registryQC.add("NchJetCone", "NchJetCone", HistType::kTH1F, {{100, 0, 100, "#it{N}_{ch}"}}); + registryQC.add("NchJet", "NchJet", HistType::kTH1F, {{100, 0, 100, "#it{N}_{ch}"}}); + registryQC.add("NchUE", "NchUE", HistType::kTH1F, {{100, 0, 100, "#it{N}_{ch}"}}); + registryQC.add("sumPtJetCone", "sumPtJetCone", HistType::kTH1F, {{500, 0, 50, "#it{p}_{T} (GeV/#it{c})"}}); + registryQC.add("sumPtJet", "sumPtJet", HistType::kTH1F, {{500, 0, 50, "#it{p}_{T} (GeV/#it{c})"}}); + registryQC.add("sumPtUE", "sumPtUE", HistType::kTH1F, {{500, 0, 50, "#it{p}_{T} (GeV/#it{c})"}}); + registryQC.add("nJetsFound", "nJetsFound", HistType::kTH1F, {{50, 0, 50, "#it{n}_{Jet}"}}); + registryQC.add("nJetsInAcceptance", "nJetsInAcceptance", HistType::kTH1F, {{50, 0, 50, "#it{n}_{Jet}"}}); + registryQC.add("nJetsSelectedHighPt", "nJetsSelectedHighPt", HistType::kTH1F, {{50, 0, 50, "#it{n}_{Jet}"}}); + registryQC.add("jetEffectiveArea", "jetEffectiveArea", HistType::kTH1F, {{2000, 0, 2, "Area/#piR^{2}"}}); + registryQC.add("jetPtDifference", "jetPtDifference", HistType::kTH1F, {{200, -1, 1, "#Deltap_{T}^{jet}"}}); + } + + // data histograms + if (doprocessData) { + + // event counter data + registryData.add("number_of_events_data", "number of events in data", HistType::kTH1F, {{10, 0, 10, "counter"}}); + registryData.add("number_of_rejected_events", "check on number of events rejected", HistType::kTH1F, {{10, 0, 10, "counter"}}); + + // antiprotons + registryData.add("antiproton_jet_tpc", "antiproton_jet_tpc", HistType::kTH2F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("antiproton_jet_tof", "antiproton_jet_tof", HistType::kTH2F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); + registryData.add("antiproton_ue_tpc", "antiproton_ue_tpc", HistType::kTH2F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("antiproton_ue_tof", "antiproton_ue_tof", HistType::kTH2F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); + registryData.add("antiproton_dca_jet", "antiproton_dca_jet", HistType::kTH2F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {200, -0.5, 0.5, "DCA_{xy} (cm)"}}); + registryData.add("antiproton_dca_ue", "antiproton_dca_ue", HistType::kTH2F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {200, -0.5, 0.5, "DCA_{xy} (cm)"}}); + + // antideuterons + registryData.add("antideuteron_jet_tpc", "antideuteron_jet_tpc", HistType::kTH2F, {{nbins, min * 2, max * 2, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("antideuteron_jet_tof", "antideuteron_jet_tof", HistType::kTH2F, {{nbins, min * 2, max * 2, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); + registryData.add("antideuteron_ue_tpc", "antideuteron_ue_tpc", HistType::kTH2F, {{nbins, min * 2, max * 2, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("antideuteron_ue_tof", "antideuteron_ue_tof", HistType::kTH2F, {{nbins, min * 2, max * 2, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); + + // deuterons + registryData.add("deuteron_jet_tof", "deuteron_jet_tof", HistType::kTH2F, {{nbins, min * 2, max * 2, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); + registryData.add("deuteron_ue_tof", "deuteron_ue_tof", HistType::kTH2F, {{nbins, min * 2, max * 2, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); + + // antihelium-3 + registryData.add("antihelium3_jet_tpc", "antihelium3_jet_tpc", HistType::kTH2F, {{nbins, min * 3, max * 3, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("antihelium3_ue_tpc", "antihelium3_ue_tpc", HistType::kTH2F, {{nbins, min * 3, max * 3, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); + + // helium-3 + registryData.add("helium3_jet_tpc", "helium3_jet_tpc", HistType::kTH2F, {{nbins, min * 3, max * 3, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("helium3_ue_tpc", "helium3_ue_tpc", HistType::kTH2F, {{nbins, min * 3, max * 3, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); + } + + // monte carlo histograms + if (doprocessEfficiency) { + + // event counter MC + registryMC.add("number_of_events_mc", "number of events in mc", HistType::kTH1F, {{10, 0, 10, "counter"}}); + + // generated spectra + registryMC.add("antiproton_incl_gen", "antiproton_incl_gen", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("deuteron_incl_gen", "deuteron_incl_gen", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antideuteron_incl_gen", "antideuteron_incl_gen", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("helium3_incl_gen", "helium3_incl_gen", HistType::kTH1F, {{nbins, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antihelium3_incl_gen", "antihelium3_incl_gen", HistType::kTH1F, {{nbins, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}}); + + // reconstructed TPC + registryMC.add("antiproton_incl_rec_tpc", "antiproton_incl_rec_tpc", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antideuteron_incl_rec_tpc", "antideuteron_incl_rec_tpc", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("deuteron_incl_rec_tpc", "deuteron_incl_rec_tpc", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antihelium3_incl_rec_tpc", "antihelium3_incl_rec_tpc", HistType::kTH1F, {{nbins, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("helium3_incl_rec_tpc", "helium3_incl_rec_tpc", HistType::kTH1F, {{nbins, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}}); + + // reconstructed TOF + registryMC.add("antiproton_incl_rec_tof", "antiproton_incl_rec_tof", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antideuteron_incl_rec_tof", "antideuteron_incl_rec_tof", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("deuteron_incl_rec_tof", "deuteron_incl_rec_tof", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + + // fraction of primary antiprotons from MC + registryMC.add("antiproton_incl_prim", "antiproton_incl_prim", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_incl_all", "antiproton_incl_all", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + + // antiproton reweighting + registryMC.add("antiproton_eta_pt_pythia", "antiproton_eta_pt_pythia", HistType::kTH2F, {{200, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {20, -1.0, 1.0, "#it{#eta}"}}); + } + + if (doprocessJetsMCgen) { + registryMC.add("antiproton_jet_gen", "antiproton_jet_gen", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_ue_gen", "antiproton_ue_gen", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_eta_pt_jet", "antiproton_eta_pt_jet", HistType::kTH2F, {{200, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {20, -1.0, 1.0, "#it{#eta}"}}); + registryMC.add("antiproton_eta_pt_ue", "antiproton_eta_pt_ue", HistType::kTH2F, {{200, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {20, -1.0, 1.0, "#it{#eta}"}}); + } + + if (doprocessJetsMCrec) { + registryMC.add("antiproton_jet_prim", "antiproton_jet_prim", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_jet_all", "antiproton_jet_all", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_ue_prim", "antiproton_ue_prim", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_ue_all", "antiproton_all_ue", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_jet_rec_tpc", "antiproton_jet_rec_tpc", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_ue_rec_tpc", "antiproton_ue_rec_tpc", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_jet_rec_tof", "antiproton_jet_rec_tof", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_ue_rec_tof", "antiproton_ue_rec_tof", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_jet_tpc_rec_vs_generatedptjet", "antiproton_jet_tpc_rec_vs_generatedptjet", HistType::kTH2F, {{nbins, min, max, "#it{p}_{T, antiproton}^{rec} (GeV/#it{c})"}, {1000, 0., 100., "#it{p}_{T, jet}^{gen} (GeV/#it{c})"}}); + registryMC.add("antiproton_jet_tof_rec_vs_generatedptjet", "antiproton_jet_tof_rec_vs_generatedptjet", HistType::kTH2F, {{nbins, min, max, "#it{p}_{T, antiproton}^{rec} (GeV/#it{c})"}, {1000, 0., 100., "#it{p}_{T, jet}^{gen} (GeV/#it{c})"}}); + + // detector response matrix + registryMC.add("detectorResponseMatrix", "detectorResponseMatrix", HistType::kTH2F, {{1000, 0.0, 100.0, "#it{p}_{T}^{rec} (GeV/#it{c})"}, {2000, -20.0, 20.0, "#it{p}_{T}^{gen} - #it{p}_{T}^{rec} (GeV/#it{c})"}}); + registryMC.add("generatedVsReconstructedPt", "generatedVsReconstructedPt", HistType::kTH2F, {{1000, 0.0, 100.0, "#it{p}_{T}^{rec} (GeV/#it{c})"}, {1000, 0.0, 100.0, "#it{p}_{T}^{gen} (GeV/#it{c})"}}); + } + + // systematic uncertainties + if (doprocessSystematicsData) { + registryData.add("number_of_rejected_events_syst", "check on number of events rejected", HistType::kTH1F, {{10, 0, 10, "counter"}}); + registryData.add("antiproton_tpc_syst", "antiproton_tpc_syst", HistType::kTHnSparseF, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}, {10, 0, 10, "systematic uncertainty"}}); + registryData.add("antiproton_tof_syst", "antiproton_tof_syst", HistType::kTHnSparseF, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}, {10, 0, 10, "systematic uncertainty"}}); + registryData.add("antideuteron_tpc_syst", "antideuteron_tpc_syst", HistType::kTHnSparseF, {{nbins, min * 2, max * 2, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}, {10, 0, 10, "systematic uncertainty"}}); + registryData.add("antideuteron_tof_syst", "antideuteron_tof_syst", HistType::kTHnSparseF, {{nbins, min * 2, max * 2, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}, {10, 0, 10, "systematic uncertainty"}}); + } + + if (doprocessSystematicsEfficiency) { + registryMC.add("antiproton_incl_gen_syst", "antiproton_incl_gen_syst", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antideuteron_incl_gen_syst", "antideuteron_incl_gen_syst", HistType::kTH1F, {{nbins, min * 2, max * 2, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_incl_prim_syst", "antiproton_incl_prim_syst", HistType::kTHnSparseF, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {10, 0, 10, "systematic uncertainty"}}); + registryMC.add("antiproton_incl_rec_tpc_syst", "antiproton_incl_rec_tpc_syst", HistType::kTHnSparseF, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {10, 0, 10, "systematic uncertainty"}}); + registryMC.add("antiproton_incl_rec_tof_syst", "antiproton_incl_rec_tof_syst", HistType::kTHnSparseF, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {10, 0, 10, "systematic uncertainty"}}); + registryMC.add("antideuteron_incl_rec_tpc_syst", "antideuteron_incl_rec_tpc_syst", HistType::kTHnSparseF, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}, {10, 0, 10, "systematic uncertainty"}}); + registryMC.add("antideuteron_incl_rec_tof_syst", "antideuteron_incl_rec_tof_syst", HistType::kTHnSparseF, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}, {10, 0, 10, "systematic uncertainty"}}); + } + } + + void getPerpendicularAxis(const TVector3& p, TVector3& u, double sign) + { + double px = p.X(); + double py = p.Y(); + double pz = p.Z(); + + double px2 = px * px; + double py2 = py * py; + double pz2 = pz * pz; + double pz4 = pz2 * pz2; + + // px and py are both zero + if (px == 0 && py == 0) { + u.SetXYZ(0, 0, 0); + return; + } + + // protection 1 + if (px == 0 && py != 0) { + double ux = sign * std::sqrt(py2 - pz4 / py2); + double uy = -pz2 / py; + u.SetXYZ(ux, uy, pz); + return; + } + + // protection 2 + if (py == 0 && px != 0) { + double ux = -pz2 / px; + double uy = sign * std::sqrt(px2 - pz4 / px2); + u.SetXYZ(ux, uy, pz); + return; + } + + // General case + double a = px2 + py2; + double b = 2.0 * px * pz2; + double c = pz4 - py2 * py2 - px2 * py2; + + double delta = b * b - 4.0 * a * c; + + if (delta < 0 || a == 0) { + LOGP(warn, "Invalid input in getPerpendicularAxis: delta = {}, a = {}", delta, a); + u.SetXYZ(0, 0, 0); + return; + } + + double ux = (-b + sign * std::sqrt(delta)) / (2.0 * a); + double uy = (-pz2 - px * ux) / py; + u.SetXYZ(ux, uy, pz); + } + + double getDeltaPhi(double a1, double a2) + { + double deltaPhi(0); + double phi1 = TVector2::Phi_0_2pi(a1); + double phi2 = TVector2::Phi_0_2pi(a2); + double diff = std::fabs(phi1 - phi2); + + if (diff <= PI) + deltaPhi = diff; + if (diff > PI) + deltaPhi = TwoPI - diff; + + return deltaPhi; + } + + // ITS hit + template + bool hasITSHit(const TrackIts& track, int layer) + { + int ibit = layer - 1; + return (track.itsClusterMap() & (1 << ibit)); + } + + // single-track selection for particles inside jets + template + bool passedTrackSelectionForJetReconstruction(const JetTrack& track) + { + + const int minTpcCr = 70; + const double minCrFindable = 0.8; + const double maxChi2Tpc = 4.0; + const double maxChi2Its = 36.0; + const double maxPseudorapidity = 0.8; + const double minPtTrack = 0.1; + const double dcaxyMaxTrackPar0 = 0.0105; + const double dcaxyMaxTrackPar1 = 0.035; + const double dcaxyMaxTrackPar2 = 1.1; + const double dcazMaxTrack = 2.0; + + if (!track.hasITS()) + return false; + if ((!hasITSHit(track, 1)) && (!hasITSHit(track, 2)) && (!hasITSHit(track, 3))) + return false; + if (!track.hasTPC()) + return false; + if (track.tpcNClsCrossedRows() < minTpcCr) + return false; + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < minCrFindable) + return false; + if (track.tpcChi2NCl() > maxChi2Tpc) + return false; + if (track.itsChi2NCl() > maxChi2Its) + return false; + if (track.eta() < -maxPseudorapidity || track.eta() > maxPseudorapidity) + return false; + if (track.pt() < minPtTrack) + return false; + if (std::fabs(track.dcaXY()) > (dcaxyMaxTrackPar0 + dcaxyMaxTrackPar1 / std::pow(track.pt(), dcaxyMaxTrackPar2))) + return false; + if (std::fabs(track.dcaZ()) > dcazMaxTrack) + return false; + return true; + } + + // single-track selection + template + bool passedTrackSelection(const AntinucleusTrack& track) + { + if (requirePvContributor && !(track.isPVContributor())) + return false; + if (!track.hasITS()) + return false; + if (track.itsNCls() < minItsNclusters) + return false; + if (!track.hasTPC()) + return false; + if (track.tpcNClsCrossedRows() < minTpcNcrossedRows) + return false; + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < minTpcNcrossedRowsOverFindable) + return false; + if (track.tpcChi2NCl() > maxChiSquareTpc) + return false; + if (track.itsChi2NCl() > maxChiSquareIts) + return false; + if (track.eta() < minEta || track.eta() > maxEta) + return false; + if (track.pt() < minPt) + return false; + + return true; + } + + template + bool isHighPurityAntiproton(const AntiprotonTrack& track) + { + // variables + double nsigmaTPCPr = track.tpcNSigmaPr(); + double nsigmaTOFPr = track.tofNSigmaPr(); + double pt = track.pt(); + double ptThreshold = 0.5; + double nsigmaMaxPr = 2.0; + + if (pt < ptThreshold && std::fabs(nsigmaTPCPr) < nsigmaMaxPr) + return true; + if (pt >= ptThreshold && std::fabs(nsigmaTPCPr) < nsigmaMaxPr && track.hasTOF() && std::fabs(nsigmaTOFPr) < nsigmaMaxPr) + return true; + return false; + } + + double getCorrectedPt(double ptRec, TH2* responseMatrix) + { + if (!responseMatrix) { + LOGP(error, "Response matrix is null. Returning uncorrected pt."); + return ptRec; + } + + int binX = responseMatrix->GetXaxis()->FindBin(ptRec); + if (binX < 1 || binX > responseMatrix->GetNbinsX()) { + LOGP(error, "Bin index out of range: binX = {}", binX); + return ptRec; // Return uncorrected pt if bin index is invalid + } + std::unique_ptr proj(responseMatrix->ProjectionY("proj", binX, binX)); + + // add a protection in case the projection is empty + if (proj->GetEntries() == 0) { + return ptRec; + } + + double deltaPt = proj->GetRandom(); + double ptGen = ptRec + deltaPt; + + return ptGen; + } + + void getPtUnfoldingHistogram(o2::framework::Service const& ccdbObj, TString filepath, TString histoNamePtUnfolding) + { + TList* l = ccdbObj->get(filepath.Data()); + if (!l) { + LOGP(error, "Could not open the file {}", Form("%s", filepath.Data())); + return; + } + TObject* obj = l->FindObject(Form("%s", histoNamePtUnfolding.Data())); + if (!obj || !obj->InheritsFrom(TH2F::Class())) { + LOGP(error, "Could not find a valid TH2F histogram {}", Form("%s", histoNamePtUnfolding.Data())); + return; + } + responseMatrix = static_cast(obj); + LOGP(info, "Opened histogram {}", Form("%s", histoNamePtUnfolding.Data())); + } + + void getReweightingHistograms(o2::framework::Service const& ccdbObj, TString filepath, TString histname_antip_jet, TString histname_antip_ue) + { + TList* l = ccdbObj->get(filepath.Data()); + if (!l) { + LOGP(error, "Could not open the file {}", Form("%s", filepath.Data())); + return; + } + twoDweightsAntipJet = static_cast(l->FindObject(Form("%s_antiproton", histname_antip_jet.Data()))); + if (!twoDweightsAntipJet) { + LOGP(error, "Could not open histogram {}", Form("%s_antiproton", histname_antip_jet.Data())); + return; + } + twoDweightsAntipUe = static_cast(l->FindObject(Form("%s_antiproton", histname_antip_ue.Data()))); + if (!twoDweightsAntipUe) { + LOGP(error, "Could not open histogram {}", Form("%s_antiproton", histname_antip_ue.Data())); + return; + } + LOGP(info, "Opened histogram {}", Form("%s_antiproton", histname_antip_jet.Data())); + LOGP(info, "Opened histogram {}", Form("%s_antiproton", histname_antip_ue.Data())); + } + + bool shouldRejectEvent() + { + static std::random_device rd; + static std::mt19937 gen(rd()); + static std::uniform_int_distribution<> dis(0, 99); + int randomNumber = dis(gen); + if (randomNumber > rejectionPercentage) { + return false; // accept event + } + return true; // reject event + } + + // Process Data + void processData(SelectedCollisions::iterator const& collision, FullNucleiTracks const& tracks) + { + if (rejectEvents) { + // event counter: before event rejection + registryData.fill(HIST("number_of_rejected_events"), 0.5); + + if (shouldRejectEvent()) + return; + + // event counter: after event rejection + registryData.fill(HIST("number_of_rejected_events"), 1.5); + } + + // event counter: before event selection + registryData.fill(HIST("number_of_events_data"), 0.5); + + // event selection + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + return; + + // event counter: after event selection + registryData.fill(HIST("number_of_events_data"), 1.5); + + // loop over reconstructed tracks + int id(-1); + std::vector fjParticles; + for (auto const& track : tracks) { + id++; + if (!passedTrackSelectionForJetReconstruction(track)) + continue; + + // 4-momentum representation of a particle + fastjet::PseudoJet fourMomentum(track.px(), track.py(), track.pz(), track.energy(MassPionCharged)); + fourMomentum.set_user_index(id); + fjParticles.emplace_back(fourMomentum); + } + + // reject empty events + if (fjParticles.size() < 1) + return; + registryData.fill(HIST("number_of_events_data"), 2.5); + + // cluster particles using the anti-kt algorithm + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); // active_area_explicit_ghosts + fastjet::ClusterSequenceArea cs(fjParticles, jetDef, areaDef); + std::vector jets = fastjet::sorted_by_pt(cs.inclusive_jets()); + auto [rhoPerp, rhoMPerp] = backgroundSub.estimateRhoPerpCone(fjParticles, jets); + + // loop over reconstructed jets + bool isAtLeastOneJetSelected = false; + for (const auto& jet : jets) { + + // jet must be fully contained in the acceptance + if ((std::fabs(jet.eta()) + rJet) > (maxEta - deltaEtaEdge)) + continue; + + // jet pt must be larger than threshold + auto jetForSub = jet; + fastjet::PseudoJet jetMinusBkg = backgroundSub.doRhoAreaSub(jetForSub, rhoPerp, rhoMPerp); + if (getCorrectedPt(jetMinusBkg.pt(), responseMatrix) < minJetPt) + continue; + isAtLeastOneJetSelected = true; + + // perpendicular cone + double coneRadius = std::sqrt(jet.area() / PI); + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); // before or after subtraction of perpendicular cone? + TVector3 ueAxis1(0, 0, 0); + TVector3 ueAxis2(0, 0, 0); + getPerpendicularAxis(jetAxis, ueAxis1, +1); + getPerpendicularAxis(jetAxis, ueAxis2, -1); + + // get jet constituents + std::vector jetConstituents = jet.constituents(); + o2::aod::ITSResponse itsResponse; + + // loop over jet constituents + for (const auto& particle : jetConstituents) { + + // get corresponding track and apply track selection criteria + auto const& track = tracks.iteratorAt(particle.user_index()); + if (!passedTrackSelection(track)) + continue; + + // variables + double nsigmaTPCPr = track.tpcNSigmaPr(); + double nsigmaTOFPr = track.tofNSigmaPr(); + double nsigmaTPCDe = track.tpcNSigmaDe(); + double nsigmaTOFDe = track.tofNSigmaDe(); + double nsigmaTPCHe = track.tpcNSigmaHe(); + double pt = track.pt(); + double dcaxy = track.dcaXY(); + double dcaz = track.dcaZ(); + + // fill DCA distribution for antiprotons + if (track.sign() < 0 && isHighPurityAntiproton(track) && std::fabs(dcaz) < maxDcaz) { + registryData.fill(HIST("antiproton_dca_jet"), pt, dcaxy); + } + + // DCA selections + if (std::fabs(dcaxy) > maxDcaxy || std::fabs(dcaz) > maxDcaz) + continue; + + // particle identification using the ITS cluster size + bool passedItsPidProt(false), passedItsPidDeut(false), passedItsPidHel(false); + if (itsResponse.nSigmaITS(track) > nSigmaItsMin && itsResponse.nSigmaITS(track) < nSigmaItsMax) { + passedItsPidProt = true; + } + if (itsResponse.nSigmaITS(track) > nSigmaItsMin && itsResponse.nSigmaITS(track) < nSigmaItsMax) { + passedItsPidDeut = true; + } + if (itsResponse.nSigmaITS(track) > nSigmaItsMin && itsResponse.nSigmaITS(track) < nSigmaItsMax) { + passedItsPidHel = true; + } + if (!applyItsPid) { + passedItsPidProt = true; + passedItsPidDeut = true; + passedItsPidHel = true; + } + if (pt > ptMaxItsPidProt) + passedItsPidProt = true; + if (pt > ptMaxItsPidDeut) + passedItsPidDeut = true; + if ((2.0 * pt) > ptMaxItsPidHel) + passedItsPidHel = true; + + // antimatter + if (track.sign() < 0) { + if (passedItsPidProt) { + registryData.fill(HIST("antiproton_jet_tpc"), pt, nsigmaTPCPr); + if (nsigmaTPCPr > minNsigmaTpc && nsigmaTPCPr < maxNsigmaTpc && track.hasTOF()) + registryData.fill(HIST("antiproton_jet_tof"), pt, nsigmaTOFPr); + } + if (passedItsPidDeut) { + registryData.fill(HIST("antideuteron_jet_tpc"), pt, nsigmaTPCDe); + if (nsigmaTPCDe > minNsigmaTpc && nsigmaTPCDe < maxNsigmaTpc && track.hasTOF()) + registryData.fill(HIST("antideuteron_jet_tof"), pt, nsigmaTOFDe); + } + if (passedItsPidHel) { + registryData.fill(HIST("antihelium3_jet_tpc"), 2.0 * pt, nsigmaTPCHe); + } + } + + // matter + if (track.sign() > 0) { + if (passedItsPidDeut && nsigmaTPCDe > minNsigmaTpc && nsigmaTPCDe < maxNsigmaTpc && track.hasTOF()) + registryData.fill(HIST("deuteron_jet_tof"), pt, nsigmaTOFDe); + if (passedItsPidHel) { + registryData.fill(HIST("helium3_jet_tpc"), 2.0 * pt, nsigmaTPCHe); + } + } + } + + // underlying event + for (auto const& track : tracks) { + + // get corresponding track and apply track selection criteria + if (!passedTrackSelection(track)) + continue; + + double deltaEtaUe1 = track.eta() - ueAxis1.Eta(); + double deltaPhiUe1 = getDeltaPhi(track.phi(), ueAxis1.Phi()); + double deltaRUe1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + double deltaEtaUe2 = track.eta() - ueAxis2.Eta(); + double deltaPhiUe2 = getDeltaPhi(track.phi(), ueAxis2.Phi()); + double deltaRUe2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + if (deltaRUe1 > coneRadius && deltaRUe2 > coneRadius) + continue; + + // variables + double nsigmaTPCPr = track.tpcNSigmaPr(); + double nsigmaTOFPr = track.tofNSigmaPr(); + double nsigmaTPCDe = track.tpcNSigmaDe(); + double nsigmaTOFDe = track.tofNSigmaDe(); + double nsigmaTPCHe = track.tpcNSigmaHe(); + double pt = track.pt(); + double dcaxy = track.dcaXY(); + double dcaz = track.dcaZ(); + + // fill DCA distribution for antiprotons + if (track.sign() < 0 && isHighPurityAntiproton(track) && std::fabs(dcaz) < maxDcaz) { + registryData.fill(HIST("antiproton_dca_ue"), pt, dcaxy); + } + + // DCA selections + if (std::fabs(dcaxy) > maxDcaxy || std::fabs(dcaz) > maxDcaz) + continue; + + // particle identification using the ITS cluster size + bool passedItsPidProt(false), passedItsPidDeut(false), passedItsPidHel(false); + if (itsResponse.nSigmaITS(track) > nSigmaItsMin && itsResponse.nSigmaITS(track) < nSigmaItsMax) { + passedItsPidProt = true; + } + if (itsResponse.nSigmaITS(track) > nSigmaItsMin && itsResponse.nSigmaITS(track) < nSigmaItsMax) { + passedItsPidDeut = true; + } + if (itsResponse.nSigmaITS(track) > nSigmaItsMin && itsResponse.nSigmaITS(track) < nSigmaItsMax) { + passedItsPidHel = true; + } + if (!applyItsPid) { + passedItsPidProt = true; + passedItsPidDeut = true; + passedItsPidHel = true; + } + if (pt > ptMaxItsPidProt) + passedItsPidProt = true; + if (pt > ptMaxItsPidDeut) + passedItsPidDeut = true; + if ((2.0 * pt) > ptMaxItsPidHel) + passedItsPidHel = true; + + // antimatter + if (track.sign() < 0) { + if (passedItsPidProt) { + registryData.fill(HIST("antiproton_ue_tpc"), pt, nsigmaTPCPr); + if (nsigmaTPCPr > minNsigmaTpc && nsigmaTPCPr < maxNsigmaTpc && track.hasTOF()) + registryData.fill(HIST("antiproton_ue_tof"), pt, nsigmaTOFPr); + } + if (passedItsPidDeut) { + registryData.fill(HIST("antideuteron_ue_tpc"), pt, nsigmaTPCDe); + if (nsigmaTPCDe > minNsigmaTpc && nsigmaTPCDe < maxNsigmaTpc && track.hasTOF()) + registryData.fill(HIST("antideuteron_ue_tof"), pt, nsigmaTOFDe); + } + if (passedItsPidHel) { + registryData.fill(HIST("antihelium3_ue_tpc"), 2.0 * pt, nsigmaTPCHe); + } + } + + // matter + if (track.sign() > 0) { + if (passedItsPidDeut && nsigmaTPCDe > minNsigmaTpc && nsigmaTPCDe < maxNsigmaTpc && track.hasTOF()) + registryData.fill(HIST("deuteron_ue_tof"), pt, nsigmaTOFDe); + // helium3 + if (passedItsPidHel) { + registryData.fill(HIST("helium3_ue_tpc"), 2.0 * pt, nsigmaTPCHe); + } + } + } + } + if (isAtLeastOneJetSelected) { + registryData.fill(HIST("number_of_events_data"), 3.5); + } + } + PROCESS_SWITCH(AntinucleiInJets, processData, "Process Data", true); + + // Process QC + void processQC(SelectedCollisions::iterator const& collision, FullNucleiTracks const& tracks) + { + // event selection + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + return; + + // loop over reconstructed tracks + std::vector fjParticles; + for (auto const& track : tracks) { + if (!passedTrackSelectionForJetReconstruction(track)) + continue; + + // 4-momentum representation of a particle + fastjet::PseudoJet fourMomentum(track.px(), track.py(), track.pz(), track.energy(MassPionCharged)); + fjParticles.emplace_back(fourMomentum); + } + + // reject empty events + if (fjParticles.size() < 1) + return; + + // cluster particles using the anti-kt algorithm + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); // active_area_explicit_ghosts + fastjet::ClusterSequenceArea cs(fjParticles, jetDef, areaDef); + std::vector jets = fastjet::sorted_by_pt(cs.inclusive_jets()); + auto [rhoPerp, rhoMPerp] = backgroundSub.estimateRhoPerpCone(fjParticles, jets); + + // loop over reconstructed jets + int njetsInAcc(0); + int njetsHighPt(0); + for (const auto& jet : jets) { + + // jet must be fully contained in the acceptance + if ((std::fabs(jet.eta()) + rJet) > (maxEta - deltaEtaEdge)) + continue; + njetsInAcc++; + registryQC.fill(HIST("sumPtJetCone"), jet.pt()); + double ptJetBeforeSub = jet.pt(); + + // jet pt must be larger than threshold + auto jetForSub = jet; + fastjet::PseudoJet jetMinusBkg = backgroundSub.doRhoAreaSub(jetForSub, rhoPerp, rhoMPerp); + double ptJetAfterSub = jetForSub.pt(); + registryQC.fill(HIST("jetPtDifference"), ptJetAfterSub - ptJetBeforeSub); + + if (getCorrectedPt(jetMinusBkg.pt(), responseMatrix) < minJetPt) + continue; + njetsHighPt++; + registryQC.fill(HIST("sumPtJet"), jet.pt()); + + // jet properties and perpendicular cone + std::vector jetConstituents = jet.constituents(); + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + double coneRadius = std::sqrt(jet.area() / PI); + TVector3 ueAxis1(0, 0, 0); + TVector3 ueAxis2(0, 0, 0); + getPerpendicularAxis(jetAxis, ueAxis1, +1); + getPerpendicularAxis(jetAxis, ueAxis2, -1); + + registryQC.fill(HIST("jetEffectiveArea"), jet.area() / (PI * rJet * rJet)); + registryQC.fill(HIST("NchJetCone"), static_cast(jetConstituents.size())); + + // loop over jet constituents + for (const auto& particle : jetConstituents) { + + double deltaEta = particle.eta() - jetAxis.Eta(); + double deltaPhi = getDeltaPhi(particle.phi(), jetAxis.Phi()); + registryQC.fill(HIST("deltaEta_deltaPhi_jet"), deltaEta, deltaPhi); + registryQC.fill(HIST("eta_phi_jet"), particle.eta(), particle.phi()); + } + + // loop over particles in perpendicular cones + double nParticlesPerp(0); + double ptPerp(0); + for (auto const& track : tracks) { + + if (!passedTrackSelectionForJetReconstruction(track)) + continue; + + double deltaEtaUe1 = track.eta() - ueAxis1.Eta(); + double deltaPhiUe1 = getDeltaPhi(track.phi(), ueAxis1.Phi()); + double deltaRUe1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + double deltaEtaUe2 = track.eta() - ueAxis2.Eta(); + double deltaPhiUe2 = getDeltaPhi(track.phi(), ueAxis2.Phi()); + double deltaRUe2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + if (deltaRUe1 > coneRadius && deltaRUe2 > coneRadius) + continue; + + ptPerp = ptPerp + track.pt(); + nParticlesPerp++; + registryQC.fill(HIST("deltaEta_deltaPhi_ue"), deltaEtaUe1, deltaPhiUe1); + registryQC.fill(HIST("deltaEta_deltaPhi_ue"), deltaEtaUe2, deltaPhiUe2); + registryQC.fill(HIST("eta_phi_ue"), track.eta(), track.phi()); + } + registryQC.fill(HIST("NchUE"), 0.5 * nParticlesPerp); + registryQC.fill(HIST("NchJet"), static_cast(jetConstituents.size()) - 0.5 * nParticlesPerp); + registryQC.fill(HIST("sumPtUE"), 0.5 * ptPerp); + } + registryQC.fill(HIST("nJetsFound"), static_cast(jets.size())); + registryQC.fill(HIST("nJetsInAcceptance"), njetsInAcc); + registryQC.fill(HIST("nJetsSelectedHighPt"), njetsHighPt); + } + PROCESS_SWITCH(AntinucleiInJets, processQC, "Process QC", false); + + void processEfficiency(SimCollisions const& collisions, MCTracks const& mcTracks, aod::McParticles const& mcParticles) + { + for (const auto& collision : collisions) { + + // event counter before event selection + registryMC.fill(HIST("number_of_events_mc"), 0.5); + + // event selection + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + continue; + + // event counter after event selection + registryMC.fill(HIST("number_of_events_mc"), 1.5); + + // generated + for (const auto& particle : mcParticles) { + + if (!particle.isPhysicalPrimary()) + continue; + + if (particle.pdgCode() == kProtonBar) { + registryMC.fill(HIST("antiproton_eta_pt_pythia"), particle.pt(), particle.eta()); + } + + if (particle.eta() < minEta || particle.eta() > maxEta) + continue; + + switch (particle.pdgCode()) { + case kProtonBar: + registryMC.fill(HIST("antiproton_incl_gen"), particle.pt()); + break; + case o2::constants::physics::Pdg::kDeuteron: + registryMC.fill(HIST("deuteron_incl_gen"), particle.pt()); + break; + case -o2::constants::physics::Pdg::kDeuteron: + registryMC.fill(HIST("antideuteron_incl_gen"), particle.pt()); + break; + case o2::constants::physics::Pdg::kHelium3: + registryMC.fill(HIST("helium3_incl_gen"), particle.pt()); + break; + case -o2::constants::physics::Pdg::kHelium3: + registryMC.fill(HIST("antihelium3_incl_gen"), particle.pt()); + break; + } + } + + // ITS pid using cluster size + o2::aod::ITSResponse itsResponse; + + // Reconstructed Tracks + for (auto const& track : mcTracks) { + + // Track Selection + if (!passedTrackSelection(track)) + continue; + if (std::fabs(track.dcaXY()) > maxDcaxy) + continue; + if (std::fabs(track.dcaZ()) > maxDcaz) + continue; + + // Get MC Particle + if (!track.has_mcParticle()) + continue; + const auto particle = track.mcParticle(); + + // Variables + double nsigmaTPCPr = track.tpcNSigmaPr(); + double nsigmaTOFPr = track.tofNSigmaPr(); + double nsigmaTPCDe = track.tpcNSigmaDe(); + double nsigmaTOFDe = track.tofNSigmaDe(); + double nsigmaTPCHe = track.tpcNSigmaHe(); + + // particle identification using the ITS cluster size + bool passedItsPidProt(false), passedItsPidDeut(false), passedItsPidHel(false); + if (itsResponse.nSigmaITS(track) > nSigmaItsMin && itsResponse.nSigmaITS(track) < nSigmaItsMax) { + passedItsPidProt = true; + } + if (itsResponse.nSigmaITS(track) > nSigmaItsMin && itsResponse.nSigmaITS(track) < nSigmaItsMax) { + passedItsPidDeut = true; + } + if (itsResponse.nSigmaITS(track) > nSigmaItsMin && itsResponse.nSigmaITS(track) < nSigmaItsMax) { + passedItsPidHel = true; + } + if (!applyItsPid) { + passedItsPidProt = true; + passedItsPidDeut = true; + passedItsPidHel = true; + } + if (track.pt() > ptMaxItsPidProt) + passedItsPidProt = true; + if (track.pt() > ptMaxItsPidDeut) + passedItsPidDeut = true; + if ((2.0 * track.pt()) > ptMaxItsPidHel) + passedItsPidHel = true; + + if (particle.pdgCode() == kProtonBar) + registryMC.fill(HIST("antiproton_incl_all"), track.pt()); + + if (!particle.isPhysicalPrimary()) + continue; + + if (particle.pdgCode() == kProtonBar) + registryMC.fill(HIST("antiproton_incl_prim"), track.pt()); + + // antiprotons + if (particle.pdgCode() == kProtonBar && passedItsPidProt) { + if (nsigmaTPCPr > minNsigmaTpc && nsigmaTPCPr < maxNsigmaTpc) { + registryMC.fill(HIST("antiproton_incl_rec_tpc"), track.pt()); + if (track.hasTOF() && nsigmaTOFPr > minNsigmaTof && nsigmaTOFPr < maxNsigmaTof) + registryMC.fill(HIST("antiproton_incl_rec_tof"), track.pt()); + } + } + + // antideuterons + if (particle.pdgCode() == -o2::constants::physics::Pdg::kDeuteron && passedItsPidDeut) { + if (nsigmaTPCDe > minNsigmaTpc && nsigmaTPCDe < maxNsigmaTpc) { + registryMC.fill(HIST("antideuteron_incl_rec_tpc"), track.pt()); + if (track.hasTOF() && nsigmaTOFDe > minNsigmaTof && nsigmaTOFDe < maxNsigmaTof) + registryMC.fill(HIST("antideuteron_incl_rec_tof"), track.pt()); + } + } + + // deuterons + if (particle.pdgCode() == o2::constants::physics::Pdg::kDeuteron && passedItsPidDeut) { + if (nsigmaTPCDe > minNsigmaTpc && nsigmaTPCDe < maxNsigmaTpc) { + registryMC.fill(HIST("deuteron_incl_rec_tpc"), track.pt()); + if (track.hasTOF() && nsigmaTOFDe > minNsigmaTof && nsigmaTOFDe < maxNsigmaTof) + registryMC.fill(HIST("deuteron_incl_rec_tof"), track.pt()); + } + } + + // antihelium3 + if (particle.pdgCode() == -o2::constants::physics::Pdg::kHelium3 && passedItsPidHel) { + if (nsigmaTPCHe > minNsigmaTpc && nsigmaTPCHe < maxNsigmaTpc) { + registryMC.fill(HIST("antihelium3_incl_rec_tpc"), 2.0 * track.pt()); + } + } + + // helium3 + if (particle.pdgCode() == o2::constants::physics::Pdg::kHelium3 && passedItsPidHel) { + if (nsigmaTPCHe > minNsigmaTpc && nsigmaTPCHe < maxNsigmaTpc) { + registryMC.fill(HIST("helium3_incl_rec_tpc"), 2.0 * track.pt()); + } + } + } + } + } + PROCESS_SWITCH(AntinucleiInJets, processEfficiency, "process efficiency", false); + + void processJetsMCgen(SimCollisions const& collisions, aod::McParticles const& mcParticles) + { + for (const auto& collision : collisions) { + + // event selection + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + continue; + + std::vector fjParticles; + for (const auto& particle : mcParticles) { + + if (!particle.isPhysicalPrimary()) + continue; + double minPtParticle = 0.1; + if (particle.eta() < minEta || particle.eta() > maxEta || particle.pt() < minPtParticle) + continue; + + double energy = std::sqrt(particle.p() * particle.p() + MassPionCharged * MassPionCharged); + fastjet::PseudoJet fourMomentum(particle.px(), particle.py(), particle.pz(), energy); + fourMomentum.set_user_index(particle.pdgCode()); + fjParticles.emplace_back(fourMomentum); + } + // reject empty events + if (fjParticles.size() < 1) + continue; + + // cluster particles using the anti-kt algorithm + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); // active_area_explicit_ghosts + fastjet::ClusterSequenceArea cs(fjParticles, jetDef, areaDef); + std::vector jets = fastjet::sorted_by_pt(cs.inclusive_jets()); + auto [rhoPerp, rhoMPerp] = backgroundSub.estimateRhoPerpCone(fjParticles, jets); + + // loop over jets + for (const auto& jet : jets) { + + // jet must be fully contained in the acceptance + if ((std::fabs(jet.eta()) + rJet) > (maxEta - deltaEtaEdge)) + continue; + + // jet pt must be larger than threshold + auto jetForSub = jet; + fastjet::PseudoJet jetMinusBkg = backgroundSub.doRhoAreaSub(jetForSub, rhoPerp, rhoMPerp); + if (jetMinusBkg.pt() < minJetPt) + continue; + + // jet properties and perpendicular cone + std::vector jetConstituents = jet.constituents(); + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + double coneRadius = std::sqrt(jet.area() / PI); + TVector3 ueAxis1(0, 0, 0); + TVector3 ueAxis2(0, 0, 0); + getPerpendicularAxis(jetAxis, ueAxis1, +1); + getPerpendicularAxis(jetAxis, ueAxis2, -1); + + // loop over jet constituents + for (const auto& particle : jetConstituents) { + + if (particle.user_index() != kProtonBar) + continue; + registryMC.fill(HIST("antiproton_jet_gen"), particle.pt()); + registryMC.fill(HIST("antiproton_eta_pt_jet"), particle.pt(), particle.eta()); + } + + // loop over underlying-event + for (const auto& particle : mcParticles) { + + if (!particle.isPhysicalPrimary()) + continue; + double minPtParticle = 0.1; + if (particle.eta() < minEta || particle.eta() > maxEta || particle.pt() < minPtParticle) + continue; + + double deltaEtaUe1 = particle.eta() - ueAxis1.Eta(); + double deltaPhiUe1 = getDeltaPhi(particle.phi(), ueAxis1.Phi()); + double deltaRUe1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + double deltaEtaUe2 = particle.eta() - ueAxis2.Eta(); + double deltaPhiUe2 = getDeltaPhi(particle.phi(), ueAxis2.Phi()); + double deltaRUe2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + if (deltaRUe1 > coneRadius && deltaRUe2 > coneRadius) + continue; + + if (particle.pdgCode() != kProtonBar) + continue; + + registryMC.fill(HIST("antiproton_ue_gen"), particle.pt()); + registryMC.fill(HIST("antiproton_eta_pt_ue"), particle.pt(), particle.eta()); + } + } + } + } + PROCESS_SWITCH(AntinucleiInJets, processJetsMCgen, "process jets mc gen", false); + + void processJetsMCrec(SimCollisions const& collisions, MCTracks const& mcTracks, McParticles const&) + { + for (const auto& collision : collisions) { + + // event selection + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + return; + + // loop over reconstructed tracks + int id(-1); + std::vector fjParticles; + for (auto const& track : mcTracks) { + id++; + if (!passedTrackSelectionForJetReconstruction(track)) + continue; + + // 4-momentum representations of a particle + fastjet::PseudoJet fourMomentum(track.px(), track.py(), track.pz(), track.energy(MassPionCharged)); + fourMomentum.set_user_index(id); + fjParticles.emplace_back(fourMomentum); + } + // reject empty events + if (fjParticles.size() < 1) + continue; + + // cluster particles using the anti-kt algorithm + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); + fastjet::ClusterSequenceArea cs(fjParticles, jetDef, areaDef); + std::vector jets = fastjet::sorted_by_pt(cs.inclusive_jets()); + auto [rhoPerp, rhoMPerp] = backgroundSub.estimateRhoPerpCone(fjParticles, jets); + + // loop over reconstructed jets + for (const auto& jet : jets) { + + // get jet constituents + std::vector jetConstituents = jet.constituents(); + + // calculate generated jet pt + double jetPtGen(0); + for (const auto& particle : jetConstituents) { + + // get corresponding track + auto const& track = mcTracks.iteratorAt(particle.user_index()); + if (!track.has_mcParticle()) + continue; + const auto mcparticle = track.mcParticle(); + jetPtGen = jetPtGen + mcparticle.pt(); + } + + // jet must be fully contained in the acceptance + if ((std::fabs(jet.eta()) + rJet) > (maxEta - deltaEtaEdge)) + continue; + + // fill detector response matrix + registryMC.fill(HIST("detectorResponseMatrix"), jet.pt(), jetPtGen - jet.pt()); // maybe it should be filled after bkg sub + registryMC.fill(HIST("generatedVsReconstructedPt"), jet.pt(), jetPtGen); + + // jet pt must be larger than threshold + auto jetForSub = jet; + fastjet::PseudoJet jetMinusBkg = backgroundSub.doRhoAreaSub(jetForSub, rhoPerp, rhoMPerp); + if (getCorrectedPt(jetMinusBkg.pt(), responseMatrix) < minJetPt) + continue; + + // perpendicular cone + double coneRadius = std::sqrt(jet.area() / PI); + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + TVector3 ueAxis1(0, 0, 0); + TVector3 ueAxis2(0, 0, 0); + getPerpendicularAxis(jetAxis, ueAxis1, +1); + getPerpendicularAxis(jetAxis, ueAxis2, -1); + + o2::aod::ITSResponse itsResponse; // to be implemented + + // loop over jet constituents + for (const auto& particle : jetConstituents) { + + // get corresponding track and apply track selection criteria + auto const& track = mcTracks.iteratorAt(particle.user_index()); + if (!passedTrackSelection(track)) + continue; + if (std::fabs(track.dcaXY()) > maxDcaxy || std::fabs(track.dcaZ()) > maxDcaz) + continue; + if (track.sign() > 0) + continue; + if (!track.has_mcParticle()) + continue; + const auto mcparticle = track.mcParticle(); + if (mcparticle.pdgCode() != kProtonBar) + continue; + + // variables + double nsigmaTPCPr = track.tpcNSigmaPr(); + double nsigmaTOFPr = track.tofNSigmaPr(); + + registryMC.fill(HIST("antiproton_jet_all"), track.pt()); + + if (!mcparticle.isPhysicalPrimary()) + continue; + + registryMC.fill(HIST("antiproton_jet_prim"), track.pt()); + + // particle identification using the ITS cluster size + bool passedItsPidProt(false); + if (itsResponse.nSigmaITS(track) > nSigmaItsMin && itsResponse.nSigmaITS(track) < nSigmaItsMax) { + passedItsPidProt = true; + } + if (!applyItsPid) + passedItsPidProt = true; + if (track.pt() > ptMaxItsPidProt) + passedItsPidProt = true; + + if (passedItsPidProt) { + registryMC.fill(HIST("antiproton_jet_rec_tpc"), track.pt(), nsigmaTPCPr); + registryMC.fill(HIST("antiproton_jet_tpc_rec_vs_generatedptjet"), track.pt(), jetPtGen); + if (nsigmaTPCPr > minNsigmaTpc && nsigmaTPCPr < maxNsigmaTpc && track.hasTOF()) + registryMC.fill(HIST("antiproton_jet_rec_tof"), track.pt(), nsigmaTOFPr); + registryMC.fill(HIST("antiproton_jet_tof_rec_vs_generatedptjet"), track.pt(), jetPtGen); + } + } + + // underlying event + for (auto const& track : mcTracks) { + + // get corresponding track and apply track selection criteria + if (!passedTrackSelection(track)) + continue; + if (std::fabs(track.dcaXY()) > maxDcaxy || std::fabs(track.dcaZ()) > maxDcaz) + continue; + if (track.sign() > 0) + continue; + + if (!track.has_mcParticle()) + continue; + const auto mcparticle = track.mcParticle(); + if (mcparticle.pdgCode() != kProtonBar) + continue; + + double deltaEtaUe1 = track.eta() - ueAxis1.Eta(); + double deltaPhiUe1 = getDeltaPhi(track.phi(), ueAxis1.Phi()); + double deltaRUe1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + double deltaEtaUe2 = track.eta() - ueAxis2.Eta(); + double deltaPhiUe2 = getDeltaPhi(track.phi(), ueAxis2.Phi()); + double deltaRUe2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + if (deltaRUe1 > coneRadius && deltaRUe2 > coneRadius) + continue; + + // variables + double nsigmaTPCPr = track.tpcNSigmaPr(); + double nsigmaTOFPr = track.tofNSigmaPr(); + + registryMC.fill(HIST("antiproton_ue_all"), track.pt()); + if (!mcparticle.isPhysicalPrimary()) + continue; + registryMC.fill(HIST("antiproton_ue_prim"), track.pt()); + + // particle identification using the ITS cluster size + bool passedItsPidProt(false); + if (itsResponse.nSigmaITS(track) > nSigmaItsMin && itsResponse.nSigmaITS(track) < nSigmaItsMax) { + passedItsPidProt = true; + } + if (!applyItsPid) + passedItsPidProt = true; + if (track.pt() > ptMaxItsPidProt) + passedItsPidProt = true; + + if (passedItsPidProt) { + if (nsigmaTPCPr > minNsigmaTpc && nsigmaTPCPr < maxNsigmaTpc) { + registryMC.fill(HIST("antiproton_ue_rec_tpc"), track.pt()); + if (track.hasTOF() && nsigmaTOFPr > minNsigmaTof && nsigmaTOFPr < maxNsigmaTof) + registryMC.fill(HIST("antiproton_ue_rec_tof"), track.pt()); + } + } + } + } + } + } + PROCESS_SWITCH(AntinucleiInJets, processJetsMCrec, "process jets MC rec", false); + + // Process Systematics + void processSystematicsData(SelectedCollisions::iterator const& collision, FullNucleiTracks const& tracks) + { + if (rejectEvents) { + // event counter: before event rejection + registryData.fill(HIST("number_of_rejected_events_syst"), 0.5); + + if (shouldRejectEvent()) + return; + + // event counter: after event rejection + registryData.fill(HIST("number_of_rejected_events_syst"), 1.5); + } + + const int nSystematics = 10; + int itsNclustersSyst[nSystematics] = {5, 6, 5, 4, 5, 3, 5, 6, 3, 4}; + float tpcNcrossedRowsSyst[nSystematics] = {100, 85, 80, 110, 95, 90, 105, 95, 100, 105}; + float dcaxySyst[nSystematics] = {0.05, 0.07, 0.10, 0.03, 0.06, 0.15, 0.08, 0.04, 0.09, 0.10}; + float dcazSyst[nSystematics] = {0.1, 0.15, 0.3, 0.075, 0.12, 0.18, 0.2, 0.1, 0.15, 0.2}; + + // event selection + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + return; + + // loop over reconstructed tracks + int id(-1); + std::vector fjParticles; + for (auto const& track : tracks) { + id++; + if (!passedTrackSelectionForJetReconstruction(track)) + continue; + + // 4-momentum representation of a particle + fastjet::PseudoJet fourMomentum(track.px(), track.py(), track.pz(), track.energy(MassPionCharged)); + fourMomentum.set_user_index(id); + fjParticles.emplace_back(fourMomentum); + } + + // reject empty events + if (fjParticles.size() < 1) + return; + + // cluster particles using the anti-kt algorithm + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); // active_area_explicit_ghosts + fastjet::ClusterSequenceArea cs(fjParticles, jetDef, areaDef); + std::vector jets = fastjet::sorted_by_pt(cs.inclusive_jets()); + auto [rhoPerp, rhoMPerp] = backgroundSub.estimateRhoPerpCone(fjParticles, jets); + + // loop over reconstructed jets + for (const auto& jet : jets) { + + // jet must be fully contained in the acceptance + if ((std::fabs(jet.eta()) + rJet) > (maxEta - deltaEtaEdge)) + continue; + + // jet pt must be larger than threshold + auto jetForSub = jet; + fastjet::PseudoJet jetMinusBkg = backgroundSub.doRhoAreaSub(jetForSub, rhoPerp, rhoMPerp); + if (getCorrectedPt(jetMinusBkg.pt(), responseMatrix) < minJetPt) + continue; + + // get jet constituents + std::vector jetConstituents = jet.constituents(); + o2::aod::ITSResponse itsResponse; + + // loop over jet constituents + for (const auto& particle : jetConstituents) { + for (int i = 0; i < nSystematics; i++) { + // get corresponding track and apply track selection criteria + auto const& track = tracks.iteratorAt(particle.user_index()); + + // variables + double nsigmaTPCPr = track.tpcNSigmaPr(); + double nsigmaTOFPr = track.tofNSigmaPr(); + double nsigmaTPCDe = track.tpcNSigmaDe(); + double nsigmaTOFDe = track.tofNSigmaDe(); + double pt = track.pt(); + double dcaxy = track.dcaXY(); + double dcaz = track.dcaZ(); + + if (requirePvContributor && !(track.isPVContributor())) + continue; + if (!track.hasITS()) + continue; + if (track.itsNCls() < itsNclustersSyst[i]) + continue; + if (!track.hasTPC()) + continue; + if (track.tpcNClsCrossedRows() < tpcNcrossedRowsSyst[i]) + continue; + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < minTpcNcrossedRowsOverFindable) + continue; + if (track.tpcChi2NCl() > maxChiSquareTpc) + continue; + if (track.itsChi2NCl() > maxChiSquareIts) + continue; + if (track.eta() < minEta || track.eta() > maxEta) + continue; + if (track.pt() < minPt) + continue; + if (std::fabs(dcaxy) > dcaxySyst[i]) + continue; + if (std::fabs(dcaz) > dcazSyst[i]) + continue; + + bool passedItsPidProt(false), passedItsPidDeut(false); + if (itsResponse.nSigmaITS(track) > nSigmaItsMin && itsResponse.nSigmaITS(track) < nSigmaItsMax) { + passedItsPidProt = true; + } + if (itsResponse.nSigmaITS(track) > nSigmaItsMin && itsResponse.nSigmaITS(track) < nSigmaItsMax) { + passedItsPidDeut = true; + } + if (!applyItsPid) { + passedItsPidProt = true; + passedItsPidDeut = true; + } + if (pt > ptMaxItsPidProt) + passedItsPidProt = true; + if (pt > ptMaxItsPidDeut) + passedItsPidDeut = true; + + // antimatter + if (track.sign() < 0) { + if (passedItsPidProt) { + registryData.fill(HIST("antiproton_tpc_syst"), pt, nsigmaTPCPr, i); + if (nsigmaTPCPr > minNsigmaTpc && nsigmaTPCPr < maxNsigmaTpc && track.hasTOF()) + registryData.fill(HIST("antiproton_tof_syst"), pt, nsigmaTOFPr, i); + } + if (passedItsPidDeut) { + registryData.fill(HIST("antideuteron_tpc_syst"), pt, nsigmaTPCDe, i); + if (nsigmaTPCDe > minNsigmaTpc && nsigmaTPCDe < maxNsigmaTpc && track.hasTOF()) + registryData.fill(HIST("antideuteron_tof_syst"), pt, nsigmaTOFDe, i); + } + } + } + } + } + } + PROCESS_SWITCH(AntinucleiInJets, processSystematicsData, "Process Systematics", false); + + void processSystematicsEfficiency(SimCollisions const& collisions, MCTracks const& mcTracks, aod::McParticles const& mcParticles) + { + const int nSystematics = 10; + int itsNclustersSyst[nSystematics] = {5, 6, 5, 4, 5, 3, 5, 6, 3, 4}; + float tpcNcrossedRowsSyst[nSystematics] = {100, 85, 80, 110, 95, 90, 105, 95, 100, 105}; + float dcaxySyst[nSystematics] = {0.05, 0.07, 0.10, 0.03, 0.06, 0.15, 0.08, 0.04, 0.09, 0.10}; + float dcazSyst[nSystematics] = {0.1, 0.15, 0.3, 0.075, 0.12, 0.18, 0.2, 0.1, 0.15, 0.2}; + + for (const auto& collision : collisions) { + + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + continue; + + // generated + for (const auto& particle : mcParticles) { + + if (!particle.isPhysicalPrimary()) + continue; + + if (particle.eta() < minEta || particle.eta() > maxEta) + continue; + + switch (particle.pdgCode()) { + case kProtonBar: + registryMC.fill(HIST("antiproton_incl_gen_syst"), particle.pt()); + break; + case -o2::constants::physics::Pdg::kDeuteron: + registryMC.fill(HIST("antideuteron_incl_gen_syst"), particle.pt()); + break; + } + } + + // ITS pid using cluster size + o2::aod::ITSResponse itsResponse; + + // Reconstructed Tracks + for (auto const& track : mcTracks) { + + // Get MC Particle + if (!track.has_mcParticle()) + continue; + const auto particle = track.mcParticle(); + + // Variables + double nsigmaTPCPr = track.tpcNSigmaPr(); + double nsigmaTOFPr = track.tofNSigmaPr(); + double nsigmaTPCDe = track.tpcNSigmaDe(); + double nsigmaTOFDe = track.tofNSigmaDe(); + double dcaxy = track.dcaXY(); + double dcaz = track.dcaZ(); + + for (int i = 0; i < nSystematics; i++) { + + // Track Selection + if (requirePvContributor && !(track.isPVContributor())) + continue; + if (!track.hasITS()) + continue; + if (track.itsNCls() < itsNclustersSyst[i]) + continue; + if (!track.hasTPC()) + continue; + if (track.tpcNClsCrossedRows() < tpcNcrossedRowsSyst[i]) + continue; + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < minTpcNcrossedRowsOverFindable) + continue; + if (track.tpcChi2NCl() > maxChiSquareTpc) + continue; + if (track.itsChi2NCl() > maxChiSquareIts) + continue; + if (track.eta() < minEta || track.eta() > maxEta) + continue; + if (track.pt() < minPt) + continue; + if (std::fabs(dcaxy) > dcaxySyst[i]) + continue; + if (std::fabs(dcaz) > dcazSyst[i]) + continue; + + // particle identification using the ITS cluster size + bool passedItsPidProt(false), passedItsPidDeut(false); + if (itsResponse.nSigmaITS(track) > nSigmaItsMin && itsResponse.nSigmaITS(track) < nSigmaItsMax) { + passedItsPidProt = true; + } + if (itsResponse.nSigmaITS(track) > nSigmaItsMin && itsResponse.nSigmaITS(track) < nSigmaItsMax) { + passedItsPidDeut = true; + } + if (!applyItsPid) { + passedItsPidProt = true; + passedItsPidDeut = true; + } + if (track.pt() > ptMaxItsPidProt) + passedItsPidProt = true; + if (track.pt() > ptMaxItsPidDeut) + passedItsPidDeut = true; + if (!particle.isPhysicalPrimary()) + continue; + + if (particle.pdgCode() == kProtonBar) + registryMC.fill(HIST("antiproton_incl_prim_syst"), track.pt(), i); + + // antiprotons + if (particle.pdgCode() == kProtonBar && passedItsPidProt) { + if (nsigmaTPCPr > minNsigmaTpc && nsigmaTPCPr < maxNsigmaTpc) { + registryMC.fill(HIST("antiproton_incl_rec_tpc_syst"), track.pt(), i); + if (track.hasTOF() && nsigmaTOFPr > minNsigmaTof && nsigmaTOFPr < maxNsigmaTof) + registryMC.fill(HIST("antiproton_incl_rec_tof_syst"), track.pt(), i); + } + } + + // antideuterons + if (particle.pdgCode() == -o2::constants::physics::Pdg::kDeuteron && passedItsPidDeut) { + if (nsigmaTPCDe > minNsigmaTpc && nsigmaTPCDe < maxNsigmaTpc) { + registryMC.fill(HIST("antideuteron_incl_rec_tpc_syst"), track.pt(), i); + if (track.hasTOF() && nsigmaTOFDe > minNsigmaTof && nsigmaTOFDe < maxNsigmaTof) + registryMC.fill(HIST("antideuteron_incl_rec_tof_syst"), track.pt(), i); + } + } + } + } + } + } + PROCESS_SWITCH(AntinucleiInJets, processSystematicsEfficiency, "process efficiency for systematics", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Nuspex/ebyeMult.cxx b/PWGLF/Tasks/Nuspex/ebyeMult.cxx new file mode 100644 index 00000000000..7fc0ca8e941 --- /dev/null +++ b/PWGLF/Tasks/Nuspex/ebyeMult.cxx @@ -0,0 +1,584 @@ +// 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 ebyeMult.cxx +/// \brief task to carry out multiplicity measurements for lf ebye analyses +/// \author Mario Ciacco + +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +// #include "Common/DataModel/Multiplicity.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + +#include "TFormula.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using TracksFull = soa::Join; +using BCsWithRun2Info = soa::Join; + +namespace +{ +constexpr float dcaSels[3]{10., 10., 10.}; +static const std::vector dcaSelsNames{"dcaxy", "dcaz", "dca"}; +static const std::vector particleName{"tracks"}; +} // namespace + +struct CandidateTrack { + float pt = -999.f; + float eta = -999.f; + float dcapv = 0; + float dcaxypv = 0; + float dcazpv = 0; + float genpt = -999.f; + float geneta = -999.f; + int pdgcode = -999; + bool isreco = 0; + int64_t mcIndex = -999; + int64_t globalIndex = -999; +}; + +struct CandidateEvent { + int nTrkRec = -1; + int nTklRec = -1; +}; + +struct TagRun2V0MCalibration { + bool mCalibrationStored = false; + TH1* mhVtxAmpCorrV0A = nullptr; + TH1* mhVtxAmpCorrV0C = nullptr; + TH1* mhMultSelCalib = nullptr; + float mMCScalePars[6] = {0.0}; + TFormula* mMCScale = nullptr; +} Run2V0MInfo; + +enum PartTypes { + kPi = 0, + kKa = 1, + kPr = 2, + kEl = 3, + kMu = 4, + kSig = 5, + kXi = 6, + kOm = 7, + kOther = 8 +}; + +struct EbyeMult { + std::vector candidateTracks; + Service ccdb; + CandidateEvent candidateEvent; + + int mRunNumber; + float dBz; + uint8_t nTrackletsColl; + + ConfigurableAxis centAxis{"centAxis", {106, 0, 106}, "binning for the centrality"}; + ConfigurableAxis zVtxAxis{"zVtxAxis", {100, -20.f, 20.f}, "Binning for the vertex z in cm"}; + ConfigurableAxis multAxis{"multAxis", {100, 0.f, 100.f}, "Binning for the multiplicity axis"}; + ConfigurableAxis multFt0Axis{"multFt0Axis", {100, 0.f, 100.f}, "Binning for the ft0 multiplicity axis"}; + Configurable genName{"genName", "", "Genearator name: HIJING, PYTHIA8, ... Default: \"\""}; + + Configurable zVtxMax{"zVtxMax", 10.0f, "maximum z position of the primary vertex"}; + Configurable etaMax{"etaMax", 0.8f, "maximum eta"}; + + Configurable ptMin{"ptMin", 0.05f, "minimum pT (GeV/c)"}; + Configurable ptMax{"ptMax", 10.f, "maximum pT (GeV/c)"}; + + Configurable trackNcrossedRows{"trackNcrossedRows", 70, "Minimum number of crossed TPC rows"}; + Configurable trackNclusITScut{"trackNclusITScut", 2, "Minimum number of ITS clusters"}; + Configurable trackNclusTPCcut{"trackNclusTPCcut", 60, "Minimum number of TPC clusters"}; + Configurable trackChi2Cut{"trackChi2Cut", 4.f, "Maximum chi2/ncls in TPC"}; + Configurable> cfgDcaSels{"cfgDcaSels", {dcaSels, 1, 3, particleName, dcaSelsNames}, "DCA selections"}; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Preslice perCollisionTracksFull = o2::aod::track::collisionId; + Preslice perCollisionMcParts = o2::aod::mcparticle::mcCollisionId; + + // TODO: add function to extract the particle type based on the pdg code + int getPartType(int const pdgCode) + { + switch (std::abs(pdgCode)) { + case 211: + return PartTypes::kPi; + case 321: + return PartTypes::kKa; + case 2212: + return PartTypes::kPr; + case 11: + return PartTypes::kEl; + case 13: + return PartTypes::kMu; + case 3222: + return PartTypes::kSig; + case 3112: + return PartTypes::kSig; + case 3312: + return PartTypes::kXi; + case 3334: + return PartTypes::kOm; + default: + return PartTypes::kOther; + } + } + + template + bool selectTrack(T const& track) + { + if (std::abs(track.eta()) > etaMax) { + return false; + } + if (!(track.itsClusterMap() & 0x01) && !(track.itsClusterMap() & 0x02)) { + return false; + } + if (track.itsNCls() < trackNclusITScut || + track.tpcNClsFound() < trackNclusTPCcut || + track.tpcNClsCrossedRows() < trackNcrossedRows || + track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || + track.tpcChi2NCl() > trackChi2Cut || + track.itsChi2NCl() > 36.f) { + return false; + } + if (doprocessRun2 || doprocessMcRun2) { + if (!(track.trackType() & o2::aod::track::Run2Track) || + !(track.flags() & o2::aod::track::TPCrefit) || + !(track.flags() & o2::aod::track::ITSrefit)) { + return false; + } + } + return true; + } + + template + void initCCDB(Bc const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + auto timestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = 0x0; + o2::parameters::GRPMagField* grpmag = 0x0; + if (doprocessRun2 || doprocessMcRun2) { + auto grpPath{"GLO/GRP/GRP"}; + grpo = ccdb->getForTimeStamp("GLO/GRP/GRP", timestamp); + if (!grpo) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpPath << " of object GRPObject for timestamp " << timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpo); + TList* callst = ccdb->getForTimeStamp("Centrality/Estimators", bc.timestamp()); + auto getccdb = [callst](const char* ccdbhname) { + TH1* h = reinterpret_cast(callst->FindObject(ccdbhname)); + return h; + }; + auto getformulaccdb = [callst](const char* ccdbhname) { + TFormula* f = reinterpret_cast(callst->FindObject(ccdbhname)); + return f; + }; + Run2V0MInfo.mhVtxAmpCorrV0A = getccdb("hVtx_fAmplitude_V0A_Normalized"); + Run2V0MInfo.mhVtxAmpCorrV0C = getccdb("hVtx_fAmplitude_V0C_Normalized"); + Run2V0MInfo.mhMultSelCalib = getccdb("hMultSelCalib_V0M"); + Run2V0MInfo.mMCScale = getformulaccdb(TString::Format("%s-V0M", genName->c_str()).Data()); + if ((Run2V0MInfo.mhVtxAmpCorrV0A != nullptr) && (Run2V0MInfo.mhVtxAmpCorrV0C != nullptr) && (Run2V0MInfo.mhMultSelCalib != nullptr)) { + if (genName->length() != 0) { + if (Run2V0MInfo.mMCScale != nullptr) { + for (int ixpar = 0; ixpar < 6; ++ixpar) { + Run2V0MInfo.mMCScalePars[ixpar] = Run2V0MInfo.mMCScale->GetParameter(ixpar); + } + } else { + LOGF(fatal, "MC Scale information from V0M for run %d not available", bc.runNumber()); + } + } + Run2V0MInfo.mCalibrationStored = true; + } else { + LOGF(fatal, "Calibration information from V0M for run %d corrupted", bc.runNumber()); + } + } else { + auto grpmagPath{"GLO/Config/GRPMagField"}; + grpmag = ccdb->getForTimeStamp("GLO/Config/GRPMagField", timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField for timestamp " << timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + } + // Fetch magnetic field from ccdb for current collision + dBz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "Retrieved GRP for timestamp " << timestamp << " with magnetic field of " << dBz << " kG"; + mRunNumber = bc.runNumber(); + } + + float getV0M(int64_t const id, float const zvtx, aod::FV0As const& fv0as, aod::FV0Cs const& fv0cs) + { + auto fv0a = fv0as.rawIteratorAt(id); + auto fv0c = fv0cs.rawIteratorAt(id); + float multFV0A = 0; + float multFV0C = 0; + for (float const& amplitude : fv0a.amplitude()) { + multFV0A += amplitude; + } + + for (float const& amplitude : fv0c.amplitude()) { + multFV0C += amplitude; + } + + float v0m = -1; + auto scaleMC = [](float x, float pars[6]) { + return std::pow(((pars[0] + pars[1] * std::pow(x, pars[2])) - pars[3]) / pars[4], 1.0f / pars[5]); + }; + + if (Run2V0MInfo.mMCScale != nullptr) { + float multFV0M = multFV0A + multFV0C; + v0m = scaleMC(multFV0M, Run2V0MInfo.mMCScalePars); + LOGF(debug, "Unscaled v0m: %f, scaled v0m: %f", multFV0M, v0m); + } else { + v0m = multFV0A * Run2V0MInfo.mhVtxAmpCorrV0A->GetBinContent(Run2V0MInfo.mhVtxAmpCorrV0A->FindFixBin(zvtx)) + + multFV0C * Run2V0MInfo.mhVtxAmpCorrV0C->GetBinContent(Run2V0MInfo.mhVtxAmpCorrV0C->FindFixBin(zvtx)); + } + return v0m; + } + + void init(o2::framework::InitContext&) + { + + mRunNumber = 0; + dBz = 0; + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + // event QA + histos.add("QA/zVtx", ";#it{z}_{vtx} (cm);Entries", HistType::kTH1F, {zVtxAxis}); + histos.add("QA/V0MvsCL0", ";Centrality CL0 (%);Centrality V0M (%)", HistType::kTH2F, {centAxis, centAxis}); + histos.add("QA/trackletsVsV0M", ";Centrality CL0 (%);Centrality V0M (%)", HistType::kTH2F, {centAxis, multAxis}); + histos.add("QA/nTrklCorrelation", ";Tracklets |#eta| > 0.7; Tracklets |#eta| < 0.6", HistType::kTH2D, {{201, -0.5, 200.5}, {201, -0.5, 200.5}}); + histos.add("QA/nV0MCorrelation", ";V0M Multiplicity (%); Tracklets |#eta| < 0.6", HistType::kTH2D, {multAxis, {201, -0.5, 200.5}}); + histos.add("QA/TrklEta", ";Tracklets #eta; Entries", HistType::kTH1D, {{100, -3., 3.}}); + + // rec tracks + histos.add("RecTracks", ";Tracklets |#eta| > 0.7;#it{p}_{T} (GeV/#it{c});DCA_{#it{xy}} (cm)", HistType::kTH3D, {{201, -0.5, 200.5}, {100, -5., 5.}, {200, -1., 1.}}); + histos.add("RecTracksV0M", ";V0M Multiplicity (%);#it{p}_{T} (GeV/#it{c});DCA_{#it{xy}} (cm)", HistType::kTH3D, {multAxis, {100, -5., 5.}, {200, -1., 1.}}); + + // rec tracks and tracklets distribution + histos.add("TracksDistr", ";Tracklets |#eta| > 0.7;#it{N}_{trk}", HistType::kTH2D, {{201, -0.5, 200.5}, {201, -0.5, 200.5}}); + histos.add("TrackletsDistr", ";Tracklets |#eta| > 0.7;#it{N}_{tkl}", HistType::kTH2D, {{201, -0.5, 200.5}, {201, -0.5, 200.5}}); + + histos.add("TracksDistrV0M", ";V0M Multiplicity (%);#it{N}_{trk}", HistType::kTH2D, {multAxis, {201, -0.5, 200.5}}); + histos.add("TrackletsDistrV0M", ";V0M Multiplicity (%);#it{N}_{tkl}", HistType::kTH2D, {multAxis, {201, -0.5, 200.5}}); + + if (doprocessMcRun2) { + // rec & gen particles (per species) + histos.add("RecPart", ";Tracklets |#eta| > 0.7;#it{p}_{T} (GeV/#it{c});Species", HistType::kTH3D, {{201, -0.5, 200.5}, {100, -5., 5.}, {10, 0, 10}}); + histos.add("GenPart", ";Tracklets |#eta| > 0.7;#it{p}_{T} (GeV/#it{c});Species", HistType::kTH3D, {{201, -0.5, 200.5}, {100, -5., 5.}, {10, 0, 10}}); + + histos.add("RecPartV0M", ";V0M Multiplicity (%);#it{p}_{T} (GeV/#it{c});Species", HistType::kTH3D, {multAxis, {100, -5., 5.}, {10, 0, 10}}); + histos.add("GenPartV0M", ";V0M Multiplicity (%);#it{p}_{T} (GeV/#it{c});Species", HistType::kTH3D, {multAxis, {100, -5., 5.}, {10, 0, 10}}); + + // dca_xy templates + histos.add("PrimTracks", ";Tracklets |#eta| > 0.7;#it{p}_{T} (GeV/#it{c});DCA_{#it{xy}} (cm)", HistType::kTH3D, {{201, -0.5, 200.5}, {100, -5., 5.}, {200, -1., 1.}}); + histos.add("SecWDTracks", ";Tracklets |#eta| > 0.7;#it{p}_{T} (GeV/#it{c});DCA_{#it{xy}} (cm)", HistType::kTH3D, {{201, -0.5, 200.5}, {100, -5., 5.}, {200, -1., 1.}}); + histos.add("SecTracks", ";Tracklets |#eta| > 0.7;#it{p}_{T} (GeV/#it{c});DCA_{#it{xy}} (cm)", HistType::kTH3D, {{201, -0.5, 200.5}, {100, -5., 5.}, {200, -1., 1.}}); + + histos.add("PrimTracksV0M", ";V0M Multiplicity (%);#it{p}_{T} (GeV/#it{c});DCA_{#it{xy}} (cm)", HistType::kTH3D, {multAxis, {100, -5., 5.}, {200, -1., 1.}}); + histos.add("SecWDTracksV0M", ";V0M Multiplicity (%);#it{p}_{T} (GeV/#it{c});DCA_{#it{xy}} (cm)", HistType::kTH3D, {multAxis, {100, -5., 5.}, {200, -1., 1.}}); + histos.add("SecTracksV0M", ";V0M Multiplicity (%);#it{p}_{T} (GeV/#it{c});DCA_{#it{xy}} (cm)", HistType::kTH3D, {multAxis, {100, -5., 5.}, {200, -1., 1.}}); + + // response + histos.add("GenRecTracks", ";Tracklets |#eta| > 0.7;#it{N}_{trk};#it{N}_{gen}", HistType::kTH3D, {{201, -0.5, 200.5}, {201, -0.5, 200.5}, {201, -0.5, 200.5}}); + histos.add("GenRecTracklets", ";Tracklets |#eta| > 0.7;#it{N}_{tkl};#it{N}_{gen}", HistType::kTH3D, {{201, -0.5, 200.5}, {201, -0.5, 200.5}, {201, -0.5, 200.5}}); + + histos.add("GenRecTracksV0M", ";V0M Multiplicity (%);#it{N}_{trk};#it{N}_{gen}", HistType::kTH3D, {multAxis, {201, -0.5, 200.5}, {201, -0.5, 200.5}}); + histos.add("GenRecTrackletsV0M", ";V0M Multiplicity (%);#it{N}_{tkl};#it{N}_{gen}", HistType::kTH3D, {multAxis, {201, -0.5, 200.5}, {201, -0.5, 200.5}}); + } + + // histograms for the evaluation of trigger efficiency + histos.add("GenINELgtZERO", ";#it{N}_{gen}", HistType::kTH1D, {multAxis}); + histos.add("RecINELgtZERO", ";#it{N}_{gen}", HistType::kTH1D, {multAxis}); + } + + template + void fillRecoEvent(C const& collision, T const& tracksAll, float const& centrality) + { + auto tracks = tracksAll.sliceBy(perCollisionTracksFull, collision.globalIndex()); + candidateTracks.clear(); + + gpu::gpustd::array dcaInfo; + int nTracklets[2]{0, 0}; + int nTracks{0}; + for (const auto& track : tracks) { + + if (track.trackType() == 255 && std::abs(track.eta()) < 1.2) { // tracklet + if (std::abs(track.eta()) < 0.6) + nTracklets[0]++; + else if (std::abs(track.eta()) > 0.7) + nTracklets[1]++; + } + + if (!selectTrack(track)) { + continue; + } + + auto trackParCov = getTrackParCov(track); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParCov, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrNONE, &dcaInfo); + auto dca = std::hypot(dcaInfo[0], dcaInfo[1]); + auto trackPt = trackParCov.getPt(); + auto trackEta = trackParCov.getEta(); + if (dca > cfgDcaSels->get("dca")) { // dca + continue; + } + if (std::abs(dcaInfo[1]) > cfgDcaSels->get("dcaz")) { // dcaz + continue; + } + + CandidateTrack candTrack; + candTrack.pt = track.sign() > 0. ? trackPt : -trackPt; + if (trackPt < ptMin || trackPt > ptMax) + continue; + candTrack.eta = trackEta; + candTrack.dcapv = dca; + candTrack.dcaxypv = dcaInfo[0]; + candTrack.dcazpv = dcaInfo[1]; + candTrack.globalIndex = track.globalIndex(); + candidateTracks.push_back(candTrack); + + if (std::abs(dcaInfo[0]) < cfgDcaSels->get("dcaxy")) { // dcaxy TODO: add pt dependent dcaxy cut + ++nTracks; + } + } + + histos.fill(HIST("QA/nTrklCorrelation"), nTracklets[1], nTracklets[0]); + histos.fill(HIST("QA/nV0MCorrelation"), centrality, nTracklets[0]); + nTrackletsColl = nTracklets[1]; + + candidateEvent.nTklRec = nTracklets[0]; + histos.fill(HIST("TracksDistr"), nTracklets[1], nTracks); + histos.fill(HIST("TrackletsDistr"), nTracklets[1], nTracklets[0]); + histos.fill(HIST("TracksDistrV0M"), centrality, nTracks); + histos.fill(HIST("TrackletsDistrV0M"), centrality, nTracklets[0]); + } + + template + void fillMcEvent(C const& collision, T const& tracks, float const& centrality, aod::McParticles const&, aod::McTrackLabels const& mcLabels) + { + fillRecoEvent(collision, tracks, centrality); + + int nTracks{0}; + for (int iT{0}; iT < static_cast(candidateTracks.size()); ++iT) { + candidateTracks[iT].isreco = true; + + auto mcLab = mcLabels.rawIteratorAt(candidateTracks[iT].globalIndex); + if (mcLab.has_mcParticle()) { + auto mcTrack = mcLab.template mcParticle_as(); + if (((mcTrack.flags() & 0x8) && (doprocessMcRun2)) || (mcTrack.flags() & 0x2) || (mcTrack.flags() & 0x1)) + continue; + if (!mcTrack.isPhysicalPrimary()) { + if (mcTrack.has_mothers()) { // sec WD + histos.fill(HIST("SecWDTracks"), nTrackletsColl, candidateTracks[iT].pt, candidateTracks[iT].dcaxypv); + histos.fill(HIST("SecWDTracksV0M"), centrality, candidateTracks[iT].pt, candidateTracks[iT].dcaxypv); + } else { // from material + histos.fill(HIST("SecTracks"), nTrackletsColl, candidateTracks[iT].pt, candidateTracks[iT].dcaxypv); + histos.fill(HIST("SecTracksV0M"), centrality, candidateTracks[iT].pt, candidateTracks[iT].dcaxypv); + } + } + if (std::abs(candidateTracks[iT].dcaxypv) > cfgDcaSels->get("dcaxy")) { // TODO: add pt dependent cut + ++nTracks; + } + + if (mcTrack.isPhysicalPrimary()) { // primary + histos.fill(HIST("PrimTracks"), nTrackletsColl, candidateTracks[iT].pt, candidateTracks[iT].dcaxypv); + histos.fill(HIST("PrimTracksV0M"), centrality, candidateTracks[iT].pt, candidateTracks[iT].dcaxypv); + } + + if (std::abs(candidateTracks[iT].dcaxypv) > cfgDcaSels->get("dcaxy")) + continue; + int partType = getPartType(mcTrack.pdgCode()); + if (mcTrack.isPhysicalPrimary()) { // primary + histos.fill(HIST("RecPart"), nTrackletsColl, candidateTracks[iT].pt, partType); + histos.fill(HIST("RecPartV0M"), centrality, candidateTracks[iT].pt, partType); + } + auto genPt = std::hypot(mcTrack.px(), mcTrack.py()); + candidateTracks[iT].pdgcode = mcTrack.pdgCode(); + candidateTracks[iT].genpt = genPt; + candidateTracks[iT].geneta = mcTrack.eta(); + candidateTracks[iT].mcIndex = mcTrack.globalIndex(); + } + } + candidateEvent.nTrkRec = nTracks; + } + + void fillMcGen(aod::McParticles const& mcParticles, aod::McTrackLabels const& /*mcLab*/, uint64_t const& collisionId, float const& centrality) + { + int nParticles = 0; + auto mcParticlesThisCollision = mcParticles.sliceBy(perCollisionMcParts, collisionId); + for (auto const& mcPart : mcParticlesThisCollision) { + auto genEta = mcPart.eta(); + if (std::abs(genEta) > etaMax) { + continue; + } + if (((mcPart.flags() & 0x8) && (doprocessMcRun2)) || (mcPart.flags() & 0x2) || (mcPart.flags() & 0x1)) + continue; + if (!mcPart.isPhysicalPrimary() /* && !mcPart.has_mothers() */) + continue; + auto genPt = std::hypot(mcPart.px(), mcPart.py()); + if (genPt < ptMin || genPt > ptMax) + continue; + CandidateTrack candTrack; + candTrack.genpt = genPt; + candTrack.geneta = mcPart.eta(); + candTrack.pdgcode = mcPart.pdgCode(); + + int partType = getPartType(mcPart.pdgCode()); + if (partType < PartTypes::kOther) { + ++nParticles; + } + histos.fill(HIST("GenPart"), nTrackletsColl, mcPart.pdgCode() > 0 ? genPt : -genPt, partType); + histos.fill(HIST("GenPartV0M"), centrality, mcPart.pdgCode() > 0 ? genPt : -genPt, partType); + + auto it = find_if(candidateTracks.begin(), candidateTracks.end(), [&](CandidateTrack trk) { return trk.mcIndex == mcPart.globalIndex(); }); + if (it != candidateTracks.end()) { + continue; + } else { + candidateTracks.emplace_back(candTrack); + } + } + histos.fill(HIST("RecINELgtZERO"), nParticles); + histos.fill(HIST("GenRecTracks"), nTrackletsColl, candidateEvent.nTrkRec, nParticles); + histos.fill(HIST("GenRecTracklets"), nTrackletsColl, candidateEvent.nTklRec, nParticles); + histos.fill(HIST("GenRecTracksV0M"), centrality, candidateEvent.nTrkRec, nParticles); + histos.fill(HIST("GenRecTrackletsV0M"), centrality, candidateEvent.nTklRec, nParticles); + } + + template + int genMultINELgtZERO(C const& collision, P const& particles) + { + if (std::abs(collision.posZ()) > zVtxMax) + return -1; + + int nParticles = 0; + int partInAcc = 0; + auto particlesThisCollision = particles.sliceBy(perCollisionMcParts, collision.globalIndex()); + for (auto const& particle : particlesThisCollision) { + if (((particle.flags() & 0x8) && (doprocessMcRun2)) || (particle.flags() & 0x2) || (particle.flags() & 0x1)) + continue; + if (!particle.isPhysicalPrimary() /* && !particle.has_mothers() */) + continue; + auto pt = std::hypot(particle.px(), particle.py()); + if (pt < ptMin || pt > ptMax) + continue; + + int partType = getPartType(particle.pdgCode()); + if (partType < PartTypes::kOther) { + if (std::abs(particle.eta()) < etaMax) + ++nParticles; + if (std::abs(particle.eta()) < 1.f) { + ++partInAcc; + } + } + } + if (partInAcc >= 0) + return nParticles; + return -1; + } + + void processRun2(soa::Join const& collisions, TracksFull const& tracks, aod::FV0As const& fv0as, aod::FV0Cs const& fv0cs, BCsWithRun2Info const&) + { + + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + + if (std::abs(collision.posZ()) > zVtxMax) + continue; + + if (!collision.alias_bit(kINT7)) + continue; + + if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kAliEventCutsAccepted))) + continue; + + if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kINELgtZERO))) + continue; + + float v0m = getV0M(bc.globalIndex(), collision.posZ(), fv0as, fv0cs); + float cV0M = Run2V0MInfo.mhMultSelCalib->GetBinContent(Run2V0MInfo.mhMultSelCalib->FindFixBin(v0m)); + + histos.fill(HIST("QA/zVtx"), collision.posZ()); + + fillRecoEvent(collision, tracks, cV0M); + + for (auto const& t : candidateTracks) { + histos.fill(HIST("RecTracks"), nTrackletsColl, t.pt, t.dcaxypv); + histos.fill(HIST("RecTracksV0M"), cV0M, t.pt, t.dcaxypv); + } + } + } + PROCESS_SWITCH(EbyeMult, processRun2, "process (Run 2)", false); + + void processMcRun2(soa::Join const& collisions, aod::McCollisions const& mcCollisions, TracksFull const& tracks, aod::FV0As const& fv0as, aod::FV0Cs const& fv0cs, aod::McParticles const& mcParticles, aod::McTrackLabels const& mcLab, BCsWithRun2Info const&) + { + + for (const auto& collision : collisions) { // TODO: fill numerator for trigger efficiency + auto bc = collision.bc_as(); + initCCDB(bc); + + if (std::abs(collision.posZ()) > zVtxMax) + continue; + + if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kAliEventCutsAccepted))) + continue; + + if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kINELgtZERO))) + continue; + + float v0m = getV0M(bc.globalIndex(), collision.posZ(), fv0as, fv0cs); + float cV0M = Run2V0MInfo.mhMultSelCalib->GetBinContent(Run2V0MInfo.mhMultSelCalib->FindFixBin(v0m)); + + histos.fill(HIST("QA/zVtx"), collision.posZ()); + + fillMcEvent(collision, tracks, cV0M, mcParticles, mcLab); + fillMcGen(mcParticles, mcLab, collision.mcCollisionId(), cV0M); + } + + // search generated INEL > 0 (one charged particle in |eta| < 1) + for (const auto& mcCollision : mcCollisions) { + int mult = genMultINELgtZERO(mcCollision, mcParticles); + if (mult >= 0) { + histos.fill(HIST("GenINELgtZERO"), mult); + } + } + } + PROCESS_SWITCH(EbyeMult, processMcRun2, "process mc (Run 2)", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Nuspex/hadronnucleicorrelation.cxx b/PWGLF/Tasks/Nuspex/hadronnucleicorrelation.cxx index dd27ab6e5f2..6407e12a3c9 100644 --- a/PWGLF/Tasks/Nuspex/hadronnucleicorrelation.cxx +++ b/PWGLF/Tasks/Nuspex/hadronnucleicorrelation.cxx @@ -13,14 +13,25 @@ /// \author Francesca Ercolessi /// \since 21 April 2024 -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" #include -#include +#include +#include +#include +#include #include +#include +#include +#include +#include #include #include +#include "TGrid.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" #include "Framework/ASoA.h" #include "MathUtils/Utils.h" @@ -41,13 +52,29 @@ using namespace o2::framework::expressions; struct hadronnucleicorrelation { + // PDG codes and masses used in this analysis + static constexpr int pdgProton = 2212; + static constexpr int pdgDeuteron = 1000010020; + Configurable doQA{"doQA", true, "save QA histograms"}; - Configurable disable_pantip{"disable_pantip", false, "disable_pantip"}; + Configurable doMCQA{"doMCQA", false, "save MC QA histograms"}; + Configurable isMC{"isMC", false, "is MC"}; + Configurable isMCGen{"isMCGen", false, "is isMCGen"}; + Configurable isPrim{"isPrim", true, "is isPrim"}; + Configurable domatterGen{"domatterGen", true, "domatterGen"}; + Configurable mcCorrelation{"mcCorrelation", false, "true: build the correlation function only for SE"}; + Configurable docorrection{"docorrection", false, "do efficiency correction"}; + + Configurable fCorrectionPath{"fCorrectionPath", "", "Correction path to file"}; + Configurable fCorrectionHisto{"fCorrectionHisto", "", "Correction histogram"}; + Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; // Event selection Configurable cutzvertex{"cutzvertex", 10.0, "|vertexZ| value limit"}; // Track selection + Configurable par0{"par0", 0.004, "par 0"}; + Configurable par1{"par1", 0.013, "par 1"}; Configurable min_TPC_nClusters{"min_TPC_nClusters", 80, "minimum number of found TPC clusters"}; Configurable min_TPC_nCrossedRowsOverFindableCls{"min_TPC_nCrossedRowsOverFindableCls", 0.8, "n TPC Crossed Rows Over Findable Cls"}; Configurable max_chi2_TPC{"max_chi2_TPC", 4.0f, "maximum TPC chi^2/Ncls"}; @@ -56,124 +83,311 @@ struct hadronnucleicorrelation { Configurable max_dcaxy{"max_dcaxy", 0.14f, "Maximum DCAxy"}; Configurable max_dcaz{"max_dcaz", 0.1f, "Maximum DCAz"}; Configurable nsigmaTPC{"nsigmaTPC", 3.0f, "cut nsigma TPC"}; + Configurable nsigmaElPr{"nsigmaElPr", 1.0f, "cut nsigma TPC El for protons"}; + Configurable nsigmaElDe{"nsigmaElDe", 3.0f, "cut nsigma TPC El for protons"}; Configurable nsigmaTOF{"nsigmaTOF", 3.5f, "cut nsigma TOF"}; + Configurable pTthrpr_TOF{"pTthrpr_TOF", 0.8f, "threshold pT proton to use TOF"}; + Configurable pTthrpr_TPCEl{"pTthrpr_TPCEl", 1.0f, "threshold pT proton to use TPC El rejection"}; + Configurable pTthrde_TOF{"pTthrde_TOF", 1.0f, "threshold pT deuteron to use TOF"}; + Configurable pTthrde_TPCEl{"pTthrde_TPCEl", 1.0f, "threshold pT deuteron to use TPC El rejection"}; + Configurable rejectionEl{"rejectionEl", true, "use TPC El rejection"}; + Configurable max_tpcSharedCls{"max_tpcSharedCls", 0.4, "maximum fraction of TPC shared clasters"}; + Configurable min_itsNCls{"min_itsNCls", 0, "minimum allowed number of ITS clasters"}; + Configurable maxmixcollsGen{"maxmixcollsGen", 100, "maxmixcollsGen"}; // Mixing parameters Configurable _vertexNbinsToMix{"vertexNbinsToMix", 10, "Number of vertexZ bins for the mixing"}; Configurable _multNsubBins{"multSubBins", 10, "number of sub-bins to perform the mixing within"}; // pT/A bins - Configurable> pTA{"pTA", {0.4f, 0.6f, 0.8f}, "p_{T}/A bins"}; - ConfigurableAxis AxisNSigma{"AxisNSigma", {50, -10.f, 10.f}, "n#sigma"}; + Configurable> pTBins{"pTBins", {0.6f, 1.0f, 1.2f, 2.f}, "p_{T} bins"}; + + ConfigurableAxis AxisNSigma{"AxisNSigma", {35, -7.f, 7.f}, "n#sigma"}; - using FilteredCollisions = aod::SingleCollSels; - using FilteredTracks = aod::SingleTrackSels; - using FilteredTracksMC = soa::Join; + using FilteredCollisions = soa::Filtered; + using SimCollisions = aod::McCollisions; + using SimParticles = aod::McParticles; + using FilteredTracks = soa::Filtered>; // new tables (v3) + using FilteredTracksMC = soa::Filtered>; // new tables (v3) HistogramRegistry registry{"registry"}; HistogramRegistry QA{"QA"}; - typedef std::shared_ptr::iterator> trkType; - typedef std::shared_ptr::iterator> colType; + typedef std::shared_ptr trkType; + typedef std::shared_ptr trkTypeMC; + typedef std::shared_ptr partTypeMC; + typedef std::shared_ptr colType; + typedef std::shared_ptr MCcolType; // key: int64_t - value: vector of trkType objects std::map> selectedtracks_p; + std::map> selectedtracks_d; std::map> selectedtracks_antid; std::map> selectedtracks_antip; + // key: int64_t - value: vector of trkType objects + std::map> selectedparticlesMC_d; + std::map> selectedparticlesMC_p; + std::map> selectedparticlesMC_antid; + std::map> selectedparticlesMC_antip; + + // key: int64_t - value: vector of trkType objects + std::map> selectedtracksMC_d; + std::map> selectedtracksMC_p; + std::map> selectedtracksMC_antid; + std::map> selectedtracksMC_antip; + std::map> selectedtracksPIDMC_d; + std::map> selectedtracksPIDMC_p; + std::map> selectedtracksPIDMC_antid; + std::map> selectedtracksPIDMC_antip; + // key: pair of an integer and a float - value: vector of colType objects // for each key I have a vector of collisions std::map, std::vector> mixbins_antidantip; - std::map, std::vector> mixbins_pantip; + std::map, std::vector> mixbinsPID_antidantip; + std::map> mixbinsMC_antidantip; + std::map> mixbinsMC_dp; - std::vector> hEtaPhi_PrAntiPr_SE; - std::vector> hEtaPhi_PrAntiPr_ME; std::vector> hEtaPhi_AntiDeAntiPr_SE; std::vector> hEtaPhi_AntiDeAntiPr_ME; - - int nBins; + std::vector> hCorrEtaPhi_AntiDeAntiPr_SE; + std::vector> hCorrEtaPhi_AntiDeAntiPr_ME; + + std::vector> hEtaPhiRec_AntiDeAntiPr_SE; + std::vector> hEtaPhiGen_AntiDeAntiPr_SE; + std::vector> hEtaPhiRec_AntiDeAntiPr_ME; + std::vector> hEtaPhiGen_AntiDeAntiPr_ME; + std::vector> hPIDEtaPhiRec_AntiDeAntiPr_SE; + std::vector> hPIDEtaPhiGen_AntiDeAntiPr_SE; + std::vector> hPIDEtaPhiRec_AntiDeAntiPr_ME; + std::vector> hPIDEtaPhiGen_AntiDeAntiPr_ME; + + std::vector> hEtaPhiGen_AntiPrAntiPr_SE; + std::vector> hEtaPhiGen_AntiPrAntiPr_ME; + + int nBinspT; + TH2F* hEffpTEta_proton; + TH2F* hEffpTEta_antiproton; + TH2F* hEffpTEta_deuteron; + TH2F* hEffpTEta_antideuteron; + + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; void init(o2::framework::InitContext&) { - AxisSpec ptAxis = {pTA, "#it{p}_{T}/A of #bar{p} (GeV/c)"}; - AxisSpec etaAxis = {100, -1.5, 1.5, "#Delta#eta"}; - AxisSpec phiAxis = {157, -TMath::Pi() / 2, 1.5 * TMath::Pi(), "#Delta#phi"}; + ccdb->setURL(url.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + ccdb->setFatalWhenNull(false); + + if (docorrection) { + GetCorrection(ccdb, TString(fCorrectionPath), TString(fCorrectionHisto)); + } else { + hEffpTEta_proton = nullptr; + hEffpTEta_antiproton = nullptr; + hEffpTEta_deuteron = nullptr; + hEffpTEta_antideuteron = nullptr; + } + + AxisSpec ptBinnedAxis = {pTBins, "#it{p}_{T} of #bar{p} (GeV/c)"}; + AxisSpec etaAxis = {100, -1., 1., "#eta"}; + AxisSpec phiAxis = {157, 0., 2 * o2::constants::math::PI, "#phi (rad)"}; + AxisSpec pTAxis = {200, -10.f, 10.f, "p_{T} GeV/c"}; + AxisSpec pTAxis_small = {100, -5.f, 5.f, "p_{T} GeV/c"}; + + AxisSpec DeltaEtaAxis = {100, -1.5, 1.5, "#Delta#eta"}; + AxisSpec DeltaPhiAxis = {60, -o2::constants::math::PI / 2, 1.5 * o2::constants::math::PI, "#Delta#phi (rad)"}; - registry.add("hNEvents", "hNEvents", {HistType::kTH1I, {{3, 0.f, 3.f}}}); + registry.add("hNEvents", "hNEvents", {HistType::kTH1D, {{5, 0.f, 5.f}}}); registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(1, "Selected"); - registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(2, "#bar{d}-#bar{p}"); - registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(3, "p-#bar{p}"); - - registry.add("hDebug", "hDebug", {HistType::kTH1I, {{4, 0.f, 4.f}}}); - registry.get(HIST("hDebug"))->GetXaxis()->SetBinLabel(1, "all"); - registry.get(HIST("hDebug"))->GetXaxis()->SetBinLabel(2, "ev. with #bar{d}"); - registry.get(HIST("hDebug"))->GetXaxis()->SetBinLabel(3, "ev. with #bar{p}"); - registry.get(HIST("hDebug"))->GetXaxis()->SetBinLabel(4, "ev. with p"); - - registry.add("hDebugdp", "hDebugdp", {HistType::kTH1I, {{6, 0.f, 6.f}}}); - registry.get(HIST("hDebugdp"))->GetXaxis()->SetBinLabel(1, "N coll with #bar{d}"); - registry.get(HIST("hDebugdp"))->GetXaxis()->SetBinLabel(2, "N mixing bins"); - registry.get(HIST("hDebugdp"))->GetXaxis()->SetBinLabel(3, "N coll with #bar{d}"); - registry.get(HIST("hDebugdp"))->GetXaxis()->SetBinLabel(4, "#bar{d}-#bar{p} pairs SE"); - registry.get(HIST("hDebugdp"))->GetXaxis()->SetBinLabel(5, "#bar{d}-#bar{p} pairs ME"); - - nBins = pTA.value.size() - 1; - for (int i = 0; i < nBins; i++) { - if (!disable_pantip) { - auto htempSE_PrAntiPr = registry.add(Form("hEtaPhi_PrAntiPr_SE_ptA%02.0f%02.0f", pTA.value.at(i) * 10, pTA.value.at(i + 1) * 10), Form("#Delta#eta#Delta#phi (%.1f(Form("hEtaPhi_PrAntiPr_ME_ptA%02.0f%02.0f", pTA.value.at(i) * 10, pTA.value.at(i + 1) * 10), Form("#Delta#eta#Delta#phi (%.1f(Form("hEtaPhi_AntiDeAntiPr_SE_ptA%02.0f%02.0f", pTA.value.at(i) * 10, pTA.value.at(i + 1) * 10), Form("#Delta#eta#Delta#phi (%.1f(Form("hEtaPhi_AntiDeAntiPr_ME_ptA%02.0f%02.0f", pTA.value.at(i) * 10, pTA.value.at(i + 1) * 10), Form("#Delta#eta#Delta#phi (%.1f(HIST("hNEvents"))->GetXaxis()->SetBinLabel(2, "events with #bar{d}-#bar{p}"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(3, "events with d-p"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(4, "events with #bar{d}"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(5, "events with d"); + + nBinspT = pTBins.value.size() - 1; + + if (mcCorrelation) { + for (int i = 0; i < nBinspT; i++) { + auto htempSERec_AntiDeAntiPr = registry.add(Form("hEtaPhiRec_AntiDeAntiPr_SE_pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), + Form("Rec #Delta#eta#Delta#phi (%.1f(Form("hEtaPhiRec_AntiDeAntiPr_ME_pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), + Form("Rec #Delta#eta#Delta#phi (%.1f(Form("hPIDEtaPhiRec_AntiDeAntiPr_SE_pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), + Form("Rec #Delta#eta#Delta#phi (%.1f(Form("hPIDEtaPhiGen_AntiDeAntiPr_SE_pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), + Form("Gen #Delta#eta#Delta#phi (%.1f(Form("hPIDEtaPhiRec_AntiDeAntiPr_ME_pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), + Form("Rec #Delta#eta#Delta#phi (%.1f(Form("hPIDEtaPhiGen_AntiDeAntiPr_ME_pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), + Form("Gen #Delta#eta#Delta#phi (%.1f(Form("hEtaPhiGen_AntiDeAntiPr_SE_pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), + Form("Gen #Delta#eta#Delta#phi (%.1f(Form("hEtaPhiGen_AntiDeAntiPr_ME_pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), + Form("Gen #Delta#eta#Delta#phi (%.1f(Form("hEtaPhiGen_AntiPrAntiPr_SE_pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), + Form("Gen #Delta#eta#Delta#phi (%.1f(Form("hEtaPhiGen_AntiPrAntiPr_ME_pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), + Form("Gen #Delta#eta#Delta#phi (%.1f(Form("hEtaPhi_AntiDeAntiPr_SE_pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), Form("Raw #Delta#eta#Delta#phi (%.1f(Form("hEtaPhi_AntiDeAntiPr_ME_pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), Form("Raw #Delta#eta#Delta#phi (%.1f(Form("hCorrEtaPhi_AntiDeAntiPr_SE_pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), Form("#Delta#eta#Delta#phi (%.1f(Form("hCorrEtaPhi_AntiDeAntiPr_ME_pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), Form("#Delta#eta#Delta#phi (%.1f(HIST("Generated/hNEventsMC"))->GetXaxis()->SetBinLabel(1, "All"); + + registry.add("Generated/hQAProtons", "hQAProtons", {HistType::kTH1D, {{5, 0.f, 5.f}}}); + registry.get(HIST("Generated/hQAProtons"))->GetXaxis()->SetBinLabel(1, "All"); + registry.get(HIST("Generated/hQAProtons"))->GetXaxis()->SetBinLabel(2, "PhysicalPrimary"); + registry.get(HIST("Generated/hQAProtons"))->GetXaxis()->SetBinLabel(3, "|#eta|<0.8"); + registry.get(HIST("Generated/hQAProtons"))->GetXaxis()->SetBinLabel(4, "no daughters"); + registry.get(HIST("Generated/hQAProtons"))->GetXaxis()->SetBinLabel(5, "d daughter"); + + registry.add("Generated/hQADeuterons", "hQADeuterons", {HistType::kTH1D, {{3, 0.f, 3.f}}}); + registry.get(HIST("Generated/hQADeuterons"))->GetXaxis()->SetBinLabel(1, "All"); + registry.get(HIST("Generated/hQADeuterons"))->GetXaxis()->SetBinLabel(2, "PhysicalPrimary"); + registry.get(HIST("Generated/hQADeuterons"))->GetXaxis()->SetBinLabel(3, "|#eta|<0.8"); + + registry.add("Generated/hDeuteronsVsPt", "hDeuteronsVsPt; p_{T} (GeV/c);", {HistType::kTH1D, {{100, 0.f, 10.f}}}); + registry.add("Generated/hAntiDeuteronsVsPt", "hAntiDeuteronsVsPt; p_{T} (GeV/c);", {HistType::kTH1D, {{100, 0.f, 10.f}}}); } } @@ -184,43 +398,209 @@ struct hadronnucleicorrelation { o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedTpcCrossedRowsOverFindableCls) >= min_TPC_nCrossedRowsOverFindableCls && o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedItsChi2NCl) <= max_chi2_ITS && nabs(o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedDcaXY)) <= max_dcaxy && - nabs(o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedDcaZ)) <= max_dcaz && + nabs(o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedDcaXY)) <= max_dcaz && nabs(o2::aod::singletrackselector::eta) <= etacut; - template - void mixTracks(Type const& tracks1, Type const& tracks2, bool isDe) + template + bool IsProton(Type const& track, int sign) + { + bool isProton = false; + + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC) { + if (track.pt() < pTthrpr_TOF) { + if (sign > 0) { + if (track.sign() > 0) { + isProton = true; + } else if (track.sign() < 0) { + isProton = false; + } + } else if (sign < 0) { + if (track.sign() > 0) { + isProton = false; + } else if (track.sign() < 0) { + isProton = true; + } + } + } else if (rejectionEl && track.beta() < -100 && track.pt() < pTthrpr_TPCEl && track.tpcNSigmaEl() >= nsigmaElPr) { + if (sign > 0) { + if (track.sign() > 0) { + isProton = true; + } else if (track.sign() < 0) { + isProton = false; + } + } else if (sign < 0) { + if (track.sign() > 0) { + isProton = false; + } else if (track.sign() < 0) { + isProton = true; + } + } + } else if (std::abs(track.tofNSigmaPr()) < nsigmaTOF) { + if (sign > 0) { + if (track.sign() > 0) { + isProton = true; + } else if (track.sign() < 0) { + isProton = false; + } + } else if (sign < 0) { + if (track.sign() > 0) { + isProton = false; + } else if (track.sign() < 0) { + isProton = true; + } + } + } + } + return isProton; + } + + template + bool IsDeuteron(Type const& track, int sign) + { + bool isDeuteron = false; + + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC) { + if (track.pt() < pTthrde_TOF) { + if (sign > 0) { + if (track.sign() > 0) { + isDeuteron = true; + } else if (track.sign() < 0) { + isDeuteron = false; + } + } else if (sign < 0) { + if (track.sign() > 0) { + isDeuteron = false; + } else if (track.sign() < 0) { + isDeuteron = true; + } + } + } else if (rejectionEl && track.beta() < -100 && track.pt() < pTthrde_TPCEl && track.tpcNSigmaEl() >= nsigmaElDe) { + if (sign > 0) { + if (track.sign() > 0) { + isDeuteron = true; + } else if (track.sign() < 0) { + isDeuteron = false; + } + } else if (sign < 0) { + if (track.sign() > 0) { + isDeuteron = false; + } else if (track.sign() < 0) { + isDeuteron = true; + } + } + } else if (std::abs(track.tofNSigmaDe()) < nsigmaTOF) { + if (sign > 0) { + if (track.sign() > 0) { + isDeuteron = true; + } else if (track.sign() < 0) { + isDeuteron = false; + } + } else if (sign < 0) { + if (track.sign() > 0) { + isDeuteron = false; + } else if (track.sign() < 0) { + isDeuteron = true; + } + } + } + } + return isDeuteron; + } + + template + bool applyDCAcut(const T1& track) + { + bool passcut = true; + // pt-dependent selection + if (std::abs(track.dcaXY()) > (par0 + par1 / track.pt())) + passcut = false; + if (std::abs(track.dcaZ()) > (par0 + par1 / track.pt())) + passcut = false; + + return passcut; + } + + template + void mixTracks(Type const& tracks1, Type const& tracks2, bool isMCPID) { // last value: 0 -- SE; 1 -- ME for (auto it1 : tracks1) { for (auto it2 : tracks2) { - // Variables + // Calculate Delta-eta Delta-phi (reco) float deltaEta = it2->eta() - it1->eta(); float deltaPhi = it2->phi() - it1->phi(); - - while (deltaPhi < -TMath::Pi() / 2) { - deltaPhi += 2 * TMath::Pi(); + deltaPhi = getDeltaPhi(deltaPhi); + + // Calculate Delta-eta Delta-phi (gen) + float deltaEtaGen = -999.; + float deltaPhiGen = -999.; + if constexpr (doMC) { + deltaEtaGen = it2->eta_MC() - it1->eta_MC(); + deltaPhiGen = it2->phi_MC() - it1->phi_MC(); + deltaPhiGen = getDeltaPhi(deltaPhiGen); } - while (deltaPhi >= 3 * TMath::Pi() / 2) { - deltaPhi -= 2 * TMath::Pi(); - } + float antipcorr = 1, antidcorr = 1; - for (int k = 0; k < nBins; k++) { - if (!isDe && !disable_pantip) { - if (it1->pt() > pTA.value.at(k) && it1->pt() <= pTA.value.at(k + 1)) { - if (ME) { - hEtaPhi_PrAntiPr_ME[k]->Fill(deltaEta, deltaPhi, it2->pt()); - } else { - hEtaPhi_PrAntiPr_SE[k]->Fill(deltaEta, deltaPhi, it2->pt()); - } + for (int k = 0; k < nBinspT; k++) { + + if (it1->pt() >= pTBins.value.at(k) && it1->pt() < pTBins.value.at(k + 1)) { + + if (docorrection) { // Apply corrections + antipcorr = hEffpTEta_antiproton->Interpolate(it2->pt(), it2->eta()); + antidcorr = hEffpTEta_antideuteron->Interpolate(it1->pt(), it1->eta()); } - } else { - if (it1->pt() > pTA.value.at(k) * 2 && it1->pt() <= pTA.value.at(k + 1) * 2) { - if (ME) { + + if (ME) { + if constexpr (!doMC) { // Data hEtaPhi_AntiDeAntiPr_ME[k]->Fill(deltaEta, deltaPhi, it2->pt()); - } else { + hCorrEtaPhi_AntiDeAntiPr_ME[k]->Fill(deltaEta, deltaPhi, it2->pt(), 1. / (antipcorr * antidcorr)); + } else { // MC + if (isMCPID) { + hPIDEtaPhiRec_AntiDeAntiPr_ME[k]->Fill(deltaEta, deltaPhi, it2->pt()); + hPIDEtaPhiGen_AntiDeAntiPr_ME[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + } else { + hEtaPhiRec_AntiDeAntiPr_ME[k]->Fill(deltaEta, deltaPhi, it2->pt()); + hEtaPhiGen_AntiDeAntiPr_ME[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + } + } + } else { + if constexpr (!doMC) { // Data hEtaPhi_AntiDeAntiPr_SE[k]->Fill(deltaEta, deltaPhi, it2->pt()); + hCorrEtaPhi_AntiDeAntiPr_SE[k]->Fill(deltaEta, deltaPhi, it2->pt(), 1. / (antipcorr * antidcorr)); + } else { // MC + if (isMCPID) { + hPIDEtaPhiRec_AntiDeAntiPr_SE[k]->Fill(deltaEta, deltaPhi, it2->pt()); + hPIDEtaPhiGen_AntiDeAntiPr_SE[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + } else { + hEtaPhiRec_AntiDeAntiPr_SE[k]->Fill(deltaEta, deltaPhi, it2->pt()); + hEtaPhiGen_AntiDeAntiPr_SE[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + } } + } // SE + } // pT condition + } // nBinspT loop + } // tracks 2 + } // tracks 1 + } + + template + void mixMCParticles(Type const& particles1, Type const& particles2) + { + for (auto it1 : particles1) { + for (auto it2 : particles2) { + // Calculate Delta-eta Delta-phi (gen) + float deltaEtaGen = it2->eta() - it1->eta(); + float deltaPhiGen = getDeltaPhi(it2->phi() - it1->phi()); + + // Loop over pT bins + for (int k = 0; k < nBinspT; k++) { + if (it1->pt() >= pTBins.value.at(k) && it1->pt() < pTBins.value.at(k + 1)) { + // Use correct histogram based on ME flag + if constexpr (ME) { + hEtaPhiGen_AntiDeAntiPr_ME[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + } else { + hEtaPhiGen_AntiDeAntiPr_SE[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); } } } @@ -228,10 +608,88 @@ struct hadronnucleicorrelation { } } - void processData(soa::Filtered const& collisions, soa::Filtered const& tracks) + template + void mixMCParticlesIdentical(Type const& particles1, Type const& particles2) + { + for (auto it1 : particles1) { + for (auto it2 : particles2) { + // Calculate Delta-eta Delta-phi (gen) + float deltaEtaGen = it2->eta() - it1->eta(); + float deltaPhiGen = getDeltaPhi(it2->phi() - it1->phi()); + + if (!ME && std::abs(deltaPhiGen) < 0.001 && std::abs(deltaEtaGen) < 0.001) { + continue; + } + + // Loop over pT bins + for (int k = 0; k < nBinspT; k++) { + if (it1->pt() >= pTBins.value.at(k) && it1->pt() < pTBins.value.at(k + 1)) { + // Use correct histogram based on ME flag + if constexpr (ME) { + hEtaPhiGen_AntiPrAntiPr_ME[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + } else { + hEtaPhiGen_AntiPrAntiPr_SE[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + } + } + } + } + } + } + + float getDeltaPhi(float deltaPhi) + { + if (deltaPhi < -o2::constants::math::PI / 2) { + return deltaPhi += 2 * o2::constants::math::PI; + } else if (deltaPhi >= 3 * o2::constants::math::PI / 2) { + return deltaPhi -= 2 * o2::constants::math::PI; + } + return deltaPhi; + } + + void GetCorrection(o2::framework::Service const& ccdbObj, TString filepath, TString histname) + { + TList* l = ccdbObj->get(filepath.Data()); + if (!l) { + LOGP(error, "Could not open corrections file {}", Form("%s", filepath.Data())); + return; + } + hEffpTEta_proton = static_cast(l->FindObject(Form("%s_proton", histname.Data()))); + if (!hEffpTEta_proton) { + LOGP(error, "Could not open histogram {}", Form("%s_proton", histname.Data())); + return; + } + hEffpTEta_antiproton = static_cast(l->FindObject(Form("%s_antiproton", histname.Data()))); + if (!hEffpTEta_antiproton) { + LOGP(error, "Could not open histogram {}", Form("%s_antiproton", histname.Data())); + return; + } + hEffpTEta_deuteron = static_cast(l->FindObject(Form("%s_deuteron", histname.Data()))); + if (!hEffpTEta_deuteron) { + LOGP(error, "Could not open histogram {}", Form("%s_deuteron", histname.Data())); + return; + } + hEffpTEta_antideuteron = static_cast(l->FindObject(Form("%s_antideuteron", histname.Data()))); + if (!hEffpTEta_antideuteron) { + LOGP(error, "Could not open histogram {}", Form("%s_antideuteron", histname.Data())); + return; + } + LOGP(info, "Opened histogram {}", Form("%s_proton", histname.Data())); + LOGP(info, "Opened histogram {}", Form("%s_antiproton", histname.Data())); + LOGP(info, "Opened histogram {}", Form("%s_deuteron", histname.Data())); + LOGP(info, "Opened histogram {}", Form("%s_antideuteron", histname.Data())); + } + + void processData(FilteredCollisions const& collisions, FilteredTracks const& tracks) { for (auto track : tracks) { - if (abs(track.template singleCollSel_as>().posZ()) > cutzvertex) + if (std::abs(track.template singleCollSel_as().posZ()) > cutzvertex) + continue; + + if (track.tpcFractionSharedCls() > max_tpcSharedCls) + continue; + if (track.itsNCls() < min_itsNCls) + continue; + if (!applyDCAcut(track)) continue; if (doQA) { @@ -239,67 +697,67 @@ struct hadronnucleicorrelation { QA.fill(HIST("QA/hTPCchi2"), track.tpcChi2NCl()); QA.fill(HIST("QA/hTPCcrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls()); QA.fill(HIST("QA/hITSchi2"), track.itsChi2NCl()); - QA.fill(HIST("QA/hDCAxy"), track.dcaXY()); - QA.fill(HIST("QA/hDCAz"), track.dcaZ()); - QA.fill(HIST("QA/hVtxZ_trk"), track.template singleCollSel_as>().posZ()); + QA.fill(HIST("QA/hDCAxy"), track.dcaXY(), track.pt()); + QA.fill(HIST("QA/hDCAz"), track.dcaZ(), track.pt()); + QA.fill(HIST("QA/TPCChi2VsPZ"), track.tpcInnerParam() / track.sign(), track.tpcChi2NCl()); + QA.fill(HIST("QA/hVtxZ_trk"), track.template singleCollSel_as().posZ()); + QA.fill(HIST("QA/hnSigmaTPCVsPt_El"), track.pt() * track.sign(), track.tpcNSigmaEl()); QA.fill(HIST("QA/hnSigmaTPCVsPt_Pr"), track.pt() * track.sign(), track.tpcNSigmaPr()); QA.fill(HIST("QA/hnSigmaTPCVsPt_De"), track.pt() * track.sign(), track.tpcNSigmaDe()); QA.fill(HIST("QA/hnSigmaTOFVsPt_Pr"), track.pt() * track.sign(), track.tofNSigmaPr()); QA.fill(HIST("QA/hnSigmaTOFVsPt_De"), track.pt() * track.sign(), track.tofNSigmaDe()); } - bool isPr = false; - bool isAntiPr = false; - bool isDeTPCTOF = false; - bool isAntiDeTPCTOF = false; + // Discard candidates outside pT of interest + if (track.pt() > pTBins.value.at(nBinspT) || track.pt() < pTBins.value.at(0)) + continue; - if (TMath::Abs(track.tpcNSigmaPr()) < nsigmaTPC && track.sign() > 0) - isPr = true; - if (TMath::Abs(track.tpcNSigmaPr()) < nsigmaTPC && track.sign() < 0) - isAntiPr = true; - if (TMath::Abs(track.tpcNSigmaDe()) < nsigmaTPC && TMath::Abs(track.tofNSigmaDe()) < nsigmaTOF && track.sign() > 0) - isDeTPCTOF = true; - if (TMath::Abs(track.tpcNSigmaDe()) < nsigmaTPC && TMath::Abs(track.tofNSigmaDe()) < nsigmaTOF && track.sign() < 0) - isAntiDeTPCTOF = true; + bool isPr = IsProton(track, +1); + bool isAntiPr = IsProton(track, -1); + bool isDe = IsDeuteron(track, +1); + bool isAntiDe = IsDeuteron(track, -1); - // Deuterons - if (isAntiDeTPCTOF) { + if (!isPr && !isAntiPr && !isDe && !isAntiDe) + continue; + + if (isPr && isDe) { + isDe = 0; + } + if (isAntiPr && isAntiDe) { + isAntiDe = 0; + } + + // Deuterons Fill & QA + if (isAntiDe) { selectedtracks_antid[track.singleCollSelId()].push_back(std::make_shared(track)); if (doQA) { QA.fill(HIST("QA/hEtaAntiDe"), track.eta()); QA.fill(HIST("QA/hPhiAntiDe"), track.phi()); - QA.fill(HIST("QA/hnSigmaTPCVsPhi_AntiDe"), track.phi(), track.tpcNSigmaDe()); - QA.fill(HIST("QA/hnSigmaTPCVsEta_AntiDe"), track.eta(), track.tpcNSigmaDe()); - QA.fill(HIST("QA/hnSigmaTOFVsPhi_AntiDe"), track.phi(), track.tofNSigmaDe()); - QA.fill(HIST("QA/hnSigmaTOFVsEta_AntiDe"), track.eta(), track.tofNSigmaDe()); QA.fill(HIST("QA/hnSigmaTOFVsPt_De_AfterSel"), track.pt() * track.sign(), track.tofNSigmaDe()); QA.fill(HIST("QA/hnSigmaTPCVsPt_De_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaDe()); } } - if (isDeTPCTOF) { + if (isDe) { + selectedtracks_d[track.singleCollSelId()].push_back(std::make_shared(track)); + if (doQA) { QA.fill(HIST("QA/hEtaDe"), track.eta()); QA.fill(HIST("QA/hPhiDe"), track.phi()); - QA.fill(HIST("QA/hnSigmaTPCVsPhi_De"), track.phi(), track.tpcNSigmaDe()); - QA.fill(HIST("QA/hnSigmaTPCVsEta_De"), track.eta(), track.tpcNSigmaDe()); - QA.fill(HIST("QA/hnSigmaTOFVsPhi_De"), track.phi(), track.tofNSigmaDe()); - QA.fill(HIST("QA/hnSigmaTOFVsEta_De"), track.eta(), track.tofNSigmaDe()); QA.fill(HIST("QA/hnSigmaTOFVsPt_De_AfterSel"), track.pt() * track.sign(), track.tofNSigmaDe()); QA.fill(HIST("QA/hnSigmaTPCVsPt_De_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaDe()); } } - // Protons + // Protons Fill & QA if (isPr) { selectedtracks_p[track.singleCollSelId()].push_back(std::make_shared(track)); if (doQA) { QA.fill(HIST("QA/hEtaPr"), track.eta()); QA.fill(HIST("QA/hPhiPr"), track.phi()); - QA.fill(HIST("QA/hnSigmaTPCVsPhi_Pr"), track.phi(), track.tpcNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTPCVsEta_Pr"), track.eta(), track.tpcNSigmaPr()); QA.fill(HIST("QA/hnSigmaTPCVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaPr()); + QA.fill(HIST("QA/hnSigmaTOFVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tofNSigmaPr()); } } else if (isAntiPr) { selectedtracks_antip[track.singleCollSelId()].push_back(std::make_shared(track)); @@ -307,124 +765,527 @@ struct hadronnucleicorrelation { if (doQA) { QA.fill(HIST("QA/hEtaAntiPr"), track.eta()); QA.fill(HIST("QA/hPhiAntiPr"), track.phi()); - QA.fill(HIST("QA/hnSigmaTPCVsPhi_AntiPr"), track.phi(), track.tpcNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTPCVsEta_AntiPr"), track.eta(), track.tpcNSigmaPr()); QA.fill(HIST("QA/hnSigmaTPCVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaPr()); + QA.fill(HIST("QA/hnSigmaTOFVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tofNSigmaPr()); } } } for (auto collision : collisions) { - if (TMath::Abs(collision.posZ()) > cutzvertex) + if (std::abs(collision.posZ()) > cutzvertex) continue; registry.fill(HIST("hNEvents"), 0.5); - registry.fill(HIST("hDebug"), 0.5); - - if (selectedtracks_p.find(collision.globalIndex()) != selectedtracks_p.end() && - selectedtracks_antip.find(collision.globalIndex()) != selectedtracks_antip.end()) { - registry.fill(HIST("hNEvents"), 2.5); - } if (selectedtracks_antid.find(collision.globalIndex()) != selectedtracks_antid.end() && selectedtracks_antip.find(collision.globalIndex()) != selectedtracks_antip.end()) { registry.fill(HIST("hNEvents"), 1.5); } - int vertexBinToMix = std::floor((collision.posZ() + cutzvertex) / (2 * cutzvertex / _vertexNbinsToMix)); - int centBinToMix = std::floor(collision.multPerc() / (100.0 / _multNsubBins)); - - if (selectedtracks_p.find(collision.globalIndex()) != selectedtracks_p.end()) { - registry.fill(HIST("hDebug"), 3.5); - mixbins_pantip[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision)); + if (selectedtracks_d.find(collision.globalIndex()) != selectedtracks_d.end() && + selectedtracks_p.find(collision.globalIndex()) != selectedtracks_p.end()) { + registry.fill(HIST("hNEvents"), 2.5); } - if (selectedtracks_antip.find(collision.globalIndex()) != selectedtracks_antip.end()) { - registry.fill(HIST("hDebug"), 2.5); - } + int vertexBinToMix = std::floor((collision.posZ() + cutzvertex) / (2 * cutzvertex / _vertexNbinsToMix)); + int centBinToMix = std::floor(collision.multPerc() / (100.0 / _multNsubBins)); if (selectedtracks_antid.find(collision.globalIndex()) != selectedtracks_antid.end()) { - registry.fill(HIST("hDebug"), 1.5); - registry.fill(HIST("hDebugdp"), 0.5); // numero tot di collisioni nella mappa mixbins_antidantip + registry.fill(HIST("hNEvents"), 3.5); + mixbins_antidantip[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision)); } } - registry.get(HIST("hDebugdp"))->SetBinContent(6, mixbins_antidantip.size()); + if (!mixbins_antidantip.empty()) { - if (!disable_pantip) { - if (!mixbins_pantip.empty()) { - for (auto i = mixbins_pantip.begin(); i != mixbins_pantip.end(); i++) { // iterating over all vertex&mult bins + for (auto i = mixbins_antidantip.begin(); i != mixbins_antidantip.end(); i++) { // iterating over all vertex&mult bins - int EvPerBin = (i->second).size(); // number of collisions in each vertex&mult bin + std::vector value = i->second; + int EvPerBin = value.size(); // number of collisions in each vertex&mult bin - for (int indx1 = 0; indx1 < EvPerBin; indx1++) { // loop over all the events in each vertex&mult bin + for (int indx1 = 0; indx1 < EvPerBin; indx1++) { // loop over all the events in each vertex&mult bin - auto col1 = (i->second)[indx1]; + auto col1 = value[indx1]; + + if (selectedtracks_antip.find(col1->index()) != selectedtracks_antip.end()) { + mixTracks<0, 0>(selectedtracks_antid[col1->index()], selectedtracks_antip[col1->index()], 0); // mixing SE + } + + for (int indx2 = 0; indx2 < EvPerBin; indx2++) { // nested loop for all the combinations of collisions in a chosen mult/vertex bin + + auto col2 = value[indx2]; - if (selectedtracks_antip.find(col1->index()) != selectedtracks_antip.end()) { - mixTracks<0>(selectedtracks_p[col1->index()], selectedtracks_antip[col1->index()], 0); // mixing SE + if (col1 == col2) { + continue; } - int indx3 = EvPerBin; - if (indx1 < (EvPerBin - 11)) { - indx3 = indx1 + 11; + if (selectedtracks_antip.find(col2->index()) != selectedtracks_antip.end()) { + mixTracks<1, 0>(selectedtracks_antid[col1->index()], selectedtracks_antip[col2->index()], 0); // mixing ME } + } + } + } + } - for (int indx2 = indx1 + 1; indx2 < indx3; indx2++) { // nested loop for all the combinations of collisions in a chosen mult/vertex bin + // clearing up + for (auto i = selectedtracks_antid.begin(); i != selectedtracks_antid.end(); i++) + (i->second).clear(); + selectedtracks_antid.clear(); - auto col2 = (i->second)[indx2]; + for (auto i = selectedtracks_antip.begin(); i != selectedtracks_antip.end(); i++) + (i->second).clear(); + selectedtracks_antip.clear(); - if (col1 == col2) { - continue; - } + for (auto i = selectedtracks_p.begin(); i != selectedtracks_p.end(); i++) + (i->second).clear(); + selectedtracks_p.clear(); - if (selectedtracks_antip.find(col2->index()) != selectedtracks_antip.end()) { - mixTracks<1>(selectedtracks_p[col1->index()], selectedtracks_antip[col2->index()], 0); // mixing ME - } - } + for (auto i = selectedtracks_d.begin(); i != selectedtracks_d.end(); i++) + (i->second).clear(); + selectedtracks_d.clear(); + + for (auto& pair : mixbins_antidantip) { + pair.second.clear(); // Clear the vector associated with the key + } + mixbins_antidantip.clear(); // Then clear the map itself + } + PROCESS_SWITCH(hadronnucleicorrelation, processData, "processData", true); + + void processMC(FilteredCollisions const& collisions, FilteredTracksMC const& tracks) + { + for (auto track : tracks) { + if (std::abs(track.template singleCollSel_as().posZ()) > cutzvertex) + continue; + + if (track.tpcFractionSharedCls() > max_tpcSharedCls) + continue; + if (track.itsNCls() < min_itsNCls) + continue; + if (!applyDCAcut(track)) + continue; + + // Keep only protons and deuterons + // if (std::abs(track.pdgCode()) != pdgProton && std::abs(track.pdgCode()) != pdgDeuteron) + // continue; + + if (doQA) { + QA.fill(HIST("QA/hTPCnClusters"), track.tpcNClsFound()); + QA.fill(HIST("QA/hTPCchi2"), track.tpcChi2NCl()); + QA.fill(HIST("QA/hTPCcrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls()); + QA.fill(HIST("QA/hITSchi2"), track.itsChi2NCl()); + QA.fill(HIST("QA/hDCAxy"), track.dcaXY(), track.pt()); + QA.fill(HIST("QA/hDCAz"), track.dcaZ(), track.pt()); + QA.fill(HIST("QA/hVtxZ_trk"), track.template singleCollSel_as().posZ()); + QA.fill(HIST("QA/hnSigmaTPCVsPt_El"), track.pt() * track.sign(), track.tpcNSigmaEl()); + QA.fill(HIST("QA/hnSigmaTPCVsPt_Pr"), track.pt() * track.sign(), track.tpcNSigmaPr()); + QA.fill(HIST("QA/hnSigmaTPCVsPt_De"), track.pt() * track.sign(), track.tpcNSigmaDe()); + QA.fill(HIST("QA/hnSigmaTOFVsPt_Pr"), track.pt() * track.sign(), track.tofNSigmaPr()); + QA.fill(HIST("QA/hnSigmaTOFVsPt_De"), track.pt() * track.sign(), track.tofNSigmaDe()); + } + + bool isPr = (IsProton(track, +1) && track.pdgCode() == pdgProton); + bool isAntiPr = (IsProton(track, -1) && track.pdgCode() == -pdgProton); + bool isDe = (IsDeuteron(track, +1) && track.pdgCode() == pdgDeuteron); + bool isAntiDe = (IsDeuteron(track, -1) && track.pdgCode() == -pdgDeuteron); + + if (track.origin() == 1 || track.origin() == 0) { // primaries and secondaries + if (isPr) { + registry.fill(HIST("hPrimSec_EtaPhiPt_Proton"), track.eta(), track.phi(), track.pt() * +1); + if (track.origin() == 1) { // secondaries + registry.fill(HIST("hSec_EtaPhiPt_Proton"), track.eta(), track.phi(), track.pt() * +1); } } + if (isAntiPr) { + registry.fill(HIST("hPrimSec_EtaPhiPt_Proton"), track.eta(), track.phi(), track.pt() * -1); + if (track.origin() == 1) { + registry.fill(HIST("hSec_EtaPhiPt_Proton"), track.eta(), track.phi(), track.pt() * -1); + } + } + } + + if (track.origin() != 0) + continue; + + if (track.pdgCode() == pdgProton) { + registry.fill(HIST("hReco_EtaPhiPt_Proton"), track.eta(), track.phi(), track.pt()); + registry.fill(HIST("hReco_EtaPhiPtMC_Proton"), track.eta_MC(), track.phi_MC(), track.pt_MC()); + registry.fill(HIST("hResPt_Proton"), track.pt_MC(), track.pt() - track.pt_MC()); + if (doMCQA) { + registry.fill(HIST("hResEta_Proton"), track.eta_MC(), track.eta() - track.eta_MC()); + registry.fill(HIST("hResPhi_Proton"), track.phi_MC(), track.phi() - track.phi_MC()); + } + if (isPr) { + registry.fill(HIST("hReco_PID_EtaPhiPt_Proton"), track.eta(), track.phi(), track.pt()); + } + registry.fill(HIST("hnSigmaTPCVsPt_Pr_MC"), track.pt(), track.tpcNSigmaPr()); + registry.fill(HIST("hnSigmaTOFVsPt_Pr_MC"), track.pt(), track.tofNSigmaPr()); + } + if (track.pdgCode() == -pdgProton) { + registry.fill(HIST("hReco_EtaPhiPt_Proton"), track.eta(), track.phi(), track.pt() * -1); + registry.fill(HIST("hReco_EtaPhiPtMC_Proton"), track.eta_MC(), track.phi_MC(), track.pt_MC() * -1); + registry.fill(HIST("hResPt_AntiProton"), track.pt_MC(), track.pt() - track.pt_MC()); + if (doMCQA) { + registry.fill(HIST("hResEta_AntiProton"), track.eta_MC(), track.eta() - track.eta_MC()); + registry.fill(HIST("hResPhi_AntiProton"), track.phi_MC(), track.phi() - track.phi_MC()); + } + if (isAntiPr) { + registry.fill(HIST("hReco_PID_EtaPhiPt_Proton"), track.eta(), track.phi(), track.pt() * -1); + } + registry.fill(HIST("hnSigmaTPCVsPt_Pr_MC"), track.pt() * -1, track.tpcNSigmaPr()); + registry.fill(HIST("hnSigmaTOFVsPt_Pr_MC"), track.pt() * -1, track.tofNSigmaPr()); + } + if (track.pdgCode() == pdgDeuteron) { + registry.fill(HIST("hReco_EtaPhiPt_Deuteron"), track.eta(), track.phi(), track.pt()); + registry.fill(HIST("hReco_EtaPhiPtMC_Deuteron"), track.eta_MC(), track.phi_MC(), track.pt_MC()); + registry.fill(HIST("hResPt_Deuteron"), track.pt_MC(), track.pt() - track.pt_MC()); + if (doMCQA) { + registry.fill(HIST("hResEta_Deuteron"), track.eta_MC(), track.eta() - track.eta_MC()); + registry.fill(HIST("hResPhi_Deuteron"), track.phi_MC(), track.phi() - track.phi_MC()); + } + if (isDe) { + registry.fill(HIST("hReco_PID_EtaPhiPt_Deuteron"), track.eta(), track.phi(), track.pt()); + } + registry.fill(HIST("hnSigmaTPCVsPt_De_MC"), track.pt(), track.tpcNSigmaDe()); + registry.fill(HIST("hnSigmaTOFVsPt_De_MC"), track.pt(), track.tofNSigmaDe()); + } + if (track.pdgCode() == -pdgDeuteron) { + registry.fill(HIST("hReco_EtaPhiPt_Deuteron"), track.eta(), track.phi(), track.pt() * -1); + registry.fill(HIST("hReco_EtaPhiPtMC_Deuteron"), track.eta_MC(), track.phi_MC(), track.pt_MC() * -1); + registry.fill(HIST("hResPt_AntiDeuteron"), track.pt_MC(), track.pt() - track.pt_MC()); + if (doMCQA) { + registry.fill(HIST("hResEta_AntiDeuteron"), track.eta_MC(), track.eta() - track.eta_MC()); + registry.fill(HIST("hResPhi_AntiDeuteron"), track.phi_MC(), track.phi() - track.phi_MC()); + } + if (isAntiDe) { + registry.fill(HIST("hReco_PID_EtaPhiPt_Deuteron"), track.eta(), track.phi(), track.pt() * -1); + } + registry.fill(HIST("hnSigmaTPCVsPt_De_MC"), track.pt() * -1, track.tpcNSigmaDe()); + registry.fill(HIST("hnSigmaTOFVsPt_De_MC"), track.pt() * -1, track.tofNSigmaDe()); + } + + // Purity + // Numerators + if (isPr) { + registry.fill(HIST("hNumeratorPurity_Proton"), track.pt()); + registry.fill(HIST("hReco_Pt_Proton"), track.pt()); + } + if (isAntiPr) { + registry.fill(HIST("hNumeratorPurity_Proton"), track.pt() * -1); + registry.fill(HIST("hReco_Pt_Proton"), track.pt() * -1); + } + if (isDe) { + registry.fill(HIST("hNumeratorPurity_Deuteron"), track.pt()); + registry.fill(HIST("hReco_Pt_Deuteron"), track.pt()); + } + if (isAntiDe) { + registry.fill(HIST("hNumeratorPurity_Deuteron"), track.pt() * -1); + registry.fill(HIST("hReco_Pt_Deuteron"), track.pt() * -1); + } + if (IsProton(track, +1)) + registry.fill(HIST("hDenominatorPurity_Proton"), track.pt()); + if (IsProton(track, -1)) + registry.fill(HIST("hDenominatorPurity_Proton"), track.pt() * -1); + if (IsDeuteron(track, +1)) + registry.fill(HIST("hDenominatorPurity_Deuteron"), track.pt()); + if (IsDeuteron(track, -1)) + registry.fill(HIST("hDenominatorPurity_Deuteron"), track.pt() * -1); + + if (doMCQA) { + // Proton + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.pdgCode() == pdgProton) { + registry.fill(HIST("hNumeratorPurity_Proton_TPC"), track.pt()); + registry.fill(HIST("hReco_Pt_Proton_TPC"), track.pt()); + } + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF && + track.pdgCode() == pdgProton) { + registry.fill(HIST("hNumeratorPurity_Proton_TPCTOF"), track.pt()); + registry.fill(HIST("hReco_Pt_Proton_TPCTOF"), track.pt()); + } + if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.beta() < -100) || + (track.beta() > -100 && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && + track.pdgCode() == pdgProton) { + registry.fill(HIST("hNumeratorPurity_Proton_TPC_or_TOF"), track.pt()); + registry.fill(HIST("hReco_Pt_Proton_TPC_or_TOF"), track.pt()); + } + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && + track.tpcNSigmaEl() >= nsigmaElPr && track.pdgCode() == pdgProton) { + registry.fill(HIST("hNumeratorPurity_Proton_TPCEl"), track.pt()); + registry.fill(HIST("hReco_Pt_Proton_TPCEl"), track.pt()); + } + if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElPr && track.beta() < -100) || + (track.beta() > -100 && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && + track.pdgCode() == pdgProton) { + registry.fill(HIST("hNumeratorPurity_Proton_TPCEl_or_TOF"), track.pt()); + registry.fill(HIST("hReco_Pt_Proton_TPCEl_or_TOF"), track.pt()); + } + + // AntiProton + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.pdgCode() == -pdgProton) { + registry.fill(HIST("hNumeratorPurity_Proton_TPC"), track.pt() * -1); + registry.fill(HIST("hReco_Pt_Proton_TPC"), track.pt() * -1); + } + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF && + track.pdgCode() == -pdgProton) { + registry.fill(HIST("hNumeratorPurity_Proton_TPCTOF"), track.pt() * -1); + registry.fill(HIST("hReco_Pt_Proton_TPCTOF"), track.pt() * -1); + } + if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.beta() < -100) || + (track.beta() > -100 && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && + track.pdgCode() == -pdgProton) { + registry.fill(HIST("hNumeratorPurity_Proton_TPC_or_TOF"), track.pt() * -1); + registry.fill(HIST("hReco_Pt_Proton_TPC_or_TOF"), track.pt() * -1); + } + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && + track.tpcNSigmaEl() >= nsigmaElPr && track.pdgCode() == -pdgProton) { + registry.fill(HIST("hNumeratorPurity_Proton_TPCEl"), track.pt() * -1); + registry.fill(HIST("hReco_Pt_Proton_TPCEl"), track.pt() * -1); + } + if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElPr && track.beta() < -100) || + (track.beta() > -100 && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && + track.pdgCode() == -pdgProton) { + registry.fill(HIST("hNumeratorPurity_Proton_TPCEl_or_TOF"), track.pt() * -1); + registry.fill(HIST("hReco_Pt_Proton_TPCEl_or_TOF"), track.pt() * -1); + } + + // Deuteron + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.pdgCode() == pdgDeuteron) { + registry.fill(HIST("hNumeratorPurity_Deuteron_TPC"), track.pt()); + registry.fill(HIST("hReco_Pt_Deuteron_TPC"), track.pt()); + } + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF && + track.pdgCode() == pdgDeuteron) { + registry.fill(HIST("hNumeratorPurity_Deuteron_TPCTOF"), track.pt()); + registry.fill(HIST("hReco_Pt_Deuteron_TPCTOF"), track.pt()); + } + if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.beta() < -100) || + (track.beta() > -100 && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && + track.pdgCode() == pdgDeuteron) { + registry.fill(HIST("hNumeratorPurity_Deuteron_TPC_or_TOF"), track.pt()); + registry.fill(HIST("hReco_Pt_Deuteron_TPC_or_TOF"), track.pt()); + } + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && + track.tpcNSigmaEl() >= nsigmaElDe && track.pdgCode() == pdgDeuteron) { + registry.fill(HIST("hNumeratorPurity_Deuteron_TPCEl"), track.pt()); + registry.fill(HIST("hReco_Pt_Deuteron_TPCEl"), track.pt()); + } + if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElDe && track.beta() < -100) || + (track.beta() > -100 && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && + track.pdgCode() == pdgDeuteron) { + registry.fill(HIST("hNumeratorPurity_Deuteron_TPCEl_or_TOF"), track.pt()); + registry.fill(HIST("hReco_Pt_Deuteron_TPCEl_or_TOF"), track.pt()); + } + + // AntiDeuteron + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.pdgCode() == -pdgDeuteron) { + registry.fill(HIST("hNumeratorPurity_Deuteron_TPC"), track.pt() * -1); + registry.fill(HIST("hReco_Pt_Deuteron_TPC"), track.pt() * -1); + } + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF && + track.pdgCode() == -pdgDeuteron) { + registry.fill(HIST("hNumeratorPurity_Deuteron_TPCTOF"), track.pt() * -1); + registry.fill(HIST("hReco_Pt_Deuteron_TPCTOF"), track.pt() * -1); + } + if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.beta() < -100) || + (track.beta() > -100 && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && + track.pdgCode() == -pdgDeuteron) { + registry.fill(HIST("hNumeratorPurity_Deuteron_TPC_or_TOF"), track.pt() * -1); + registry.fill(HIST("hReco_Pt_Deuteron_TPC_or_TOF"), track.pt() * -1); + } + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && + track.tpcNSigmaEl() >= nsigmaElDe && track.pdgCode() == -pdgDeuteron) { + registry.fill(HIST("hNumeratorPurity_Deuteron_TPCEl"), track.pt() * -1); + registry.fill(HIST("hReco_Pt_Deuteron_TPCEl"), track.pt() * -1); + } + if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElDe && track.beta() < -100) || + (track.beta() > -100 && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && + track.pdgCode() == -pdgDeuteron) { + registry.fill(HIST("hNumeratorPurity_Deuteron_TPCEl_or_TOF"), track.pt() * -1); + registry.fill(HIST("hReco_Pt_Deuteron_TPCEl_or_TOF"), track.pt() * -1); + } + + // Denominators + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.sign() > 0) + registry.fill(HIST("hDenominatorPurity_Proton_TPC"), track.pt()); + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF && track.sign() > 0) + registry.fill(HIST("hDenominatorPurity_Proton_TPCTOF"), track.pt()); + if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.beta() < -100) || + (track.beta() > -100 && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && + track.sign() > 0) + registry.fill(HIST("hDenominatorPurity_Proton_TPC_or_TOF"), track.pt()); + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && + track.tpcNSigmaEl() >= nsigmaElPr && track.sign() > 0) { + registry.fill(HIST("hDenominatorPurity_Proton_TPCEl"), track.pt()); + } + if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElPr && track.beta() < -100) || + (track.beta() > -100 && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && + track.sign() > 0) { + registry.fill(HIST("hDenominatorPurity_Proton_TPCEl_or_TOF"), track.pt()); + } + + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.sign() < 0) + registry.fill(HIST("hDenominatorPurity_Proton_TPC"), track.pt() * -1); + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF && track.sign() < 0) + registry.fill(HIST("hDenominatorPurity_Proton_TPCTOF"), track.pt() * -1); + if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.beta() < -100) || + (track.beta() > -100 && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && + track.sign() < 0) + registry.fill(HIST("hDenominatorPurity_Proton_TPC_or_TOF"), track.pt() * -1); + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && + track.tpcNSigmaEl() >= nsigmaElPr && track.sign() < 0) { + registry.fill(HIST("hDenominatorPurity_Proton_TPCEl"), track.pt() * -1); + } + if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElPr && track.beta() < -100) || + (track.beta() > -100 && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && + track.sign() < 0) { + registry.fill(HIST("hDenominatorPurity_Proton_TPCEl_or_TOF"), track.pt() * -1); + } + + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.sign() > 0) + registry.fill(HIST("hDenominatorPurity_Deuteron_TPC"), track.pt()); + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF && track.sign() > 0) + registry.fill(HIST("hDenominatorPurity_Deuteron_TPCTOF"), track.pt()); + if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.beta() < -100) || + (track.beta() > -100 && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && + track.sign() > 0) { + registry.fill(HIST("hDenominatorPurity_Deuteron_TPC_or_TOF"), track.pt()); + } + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && + track.tpcNSigmaEl() >= nsigmaElDe && track.sign() > 0) { + registry.fill(HIST("hDenominatorPurity_Deuteron_TPCEl"), track.pt()); + } + if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElDe && track.beta() < -100) || + (track.beta() > -100 && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && + track.sign() > 0) + registry.fill(HIST("hDenominatorPurity_Deuteron_TPCEl_or_TOF"), track.pt()); + + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.sign() < 0) + registry.fill(HIST("hDenominatorPurity_Deuteron_TPC"), track.pt() * -1); + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF && track.sign() < 0) + registry.fill(HIST("hDenominatorPurity_Deuteron_TPCTOF"), track.pt() * -1); + if (( + (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.beta() < -100) || + (track.beta() > -100 && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && + track.sign() < 0) + registry.fill(HIST("hDenominatorPurity_Deuteron_TPC_or_TOF"), track.pt() * -1); + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && + track.tpcNSigmaEl() >= nsigmaElDe && track.sign() < 0) { + registry.fill(HIST("hDenominatorPurity_Deuteron_TPCEl"), track.pt() * -1); + } + if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElDe && track.beta() < -100) || + (track.beta() > -100 && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && + track.sign() < 0) + registry.fill(HIST("hDenominatorPurity_Deuteron_TPCEl_or_TOF"), track.pt() * -1); + } + + if (!mcCorrelation) { + continue; } + + if (isDe) { + selectedtracksPIDMC_d[track.singleCollSelId()].push_back(std::make_shared(track)); + } + if (track.pdgCode() == pdgDeuteron) { + selectedtracksMC_d[track.singleCollSelId()].push_back(std::make_shared(track)); + } + if (isAntiDe) { + selectedtracksPIDMC_antid[track.singleCollSelId()].push_back(std::make_shared(track)); + } + if (track.pdgCode() == -pdgDeuteron) { + selectedtracksMC_antid[track.singleCollSelId()].push_back(std::make_shared(track)); + } + if (isPr) { + selectedtracksPIDMC_p[track.singleCollSelId()].push_back(std::make_shared(track)); + } + if (track.pdgCode() == pdgProton) { + selectedtracksMC_p[track.singleCollSelId()].push_back(std::make_shared(track)); + } + if (isAntiPr) { + selectedtracksPIDMC_antip[track.singleCollSelId()].push_back(std::make_shared(track)); + } + if (track.pdgCode() == -pdgProton) { + selectedtracksMC_antip[track.singleCollSelId()].push_back(std::make_shared(track)); + } + } // track + + if (!mcCorrelation) { + return; } + for (auto collision : collisions) { + if (std::abs(collision.posZ()) > cutzvertex) + continue; + registry.fill(HIST("hNEvents"), 0.5); + + int vertexBinToMix = std::floor((collision.posZ() + cutzvertex) / (2 * cutzvertex / _vertexNbinsToMix)); + int centBinToMix = std::floor(collision.multPerc() / (100.0 / _multNsubBins)); + + if (selectedtracksMC_antid.find(collision.globalIndex()) != selectedtracksMC_antid.end()) { + mixbins_antidantip[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision)); + } + + if (selectedtracksPIDMC_antid.find(collision.globalIndex()) != selectedtracksPIDMC_antid.end()) { + mixbinsPID_antidantip[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision)); + } + } // coll + if (!mixbins_antidantip.empty()) { for (auto i = mixbins_antidantip.begin(); i != mixbins_antidantip.end(); i++) { // iterating over all vertex&mult bins - registry.fill(HIST("hDebugdp"), 1.5); // numero di keys (vertex&mult bins) nella mappa mixbins_antidantip - std::vector value = i->second; int EvPerBin = value.size(); // number of collisions in each vertex&mult bin for (int indx1 = 0; indx1 < EvPerBin; indx1++) { // loop over all the events in each vertex&mult bin - registry.fill(HIST("hDebugdp"), 2.5); - auto col1 = value[indx1]; - if (selectedtracks_antip.find(col1->index()) != selectedtracks_antip.end()) { - registry.fill(HIST("hDebugdp"), 3.5); - mixTracks<0>(selectedtracks_antid[col1->index()], selectedtracks_antip[col1->index()], 1); // mixing SE + if (selectedtracksMC_antip.find(col1->index()) != selectedtracksMC_antip.end()) { + mixTracks<0, 1>(selectedtracksMC_antid[col1->index()], selectedtracksMC_antip[col1->index()], 0); // mixing SE } - int indx3 = EvPerBin; - if (indx1 < (EvPerBin - 11)) { - indx3 = indx1 + 11; + for (int indx2 = indx1 + 1; indx2 < EvPerBin; indx2++) { // nested loop for all the combinations of collisions in a chosen mult/vertex bin + + auto col2 = (i->second)[indx2]; + + if (col1 == col2) { + continue; + } + + if (selectedtracksMC_antip.find(col2->index()) != selectedtracksMC_antip.end()) { + mixTracks<1, 1>(selectedtracksMC_antid[col1->index()], selectedtracksMC_antip[col2->index()], 0); // mixing ME + } } + } + } + } - for (int indx2 = 0; indx2 < indx3; indx2++) { // nested loop for all the combinations of collisions in a chosen mult/vertex bin + if (!mixbinsPID_antidantip.empty()) { - auto col2 = value[indx2]; + for (auto i = mixbinsPID_antidantip.begin(); i != mixbinsPID_antidantip.end(); i++) { // iterating over all vertex&mult bins + + std::vector value = i->second; + int EvPerBin = value.size(); // number of collisions in each vertex&mult bin + + for (int indx1 = 0; indx1 < EvPerBin; indx1++) { // loop over all the events in each vertex&mult bin + + auto col1 = value[indx1]; + + if (selectedtracksPIDMC_antip.find(col1->index()) != selectedtracksPIDMC_antip.end()) { + mixTracks<0, 1>(selectedtracksPIDMC_antid[col1->index()], selectedtracksPIDMC_antip[col1->index()], 1); // mixing SE + } + + for (int indx2 = indx1 + 1; indx2 < EvPerBin; indx2++) { // nested loop for all the combinations of collisions in a chosen mult/vertex bin + + auto col2 = (i->second)[indx2]; if (col1 == col2) { continue; } - if (selectedtracks_antip.find(col2->index()) != selectedtracks_antip.end()) { - registry.fill(HIST("hDebugdp"), 4.5); - mixTracks<1>(selectedtracks_antid[col1->index()], selectedtracks_antip[col2->index()], 1); // mixing ME + if (selectedtracksPIDMC_antip.find(col2->index()) != selectedtracksPIDMC_antip.end()) { + mixTracks<1, 1>(selectedtracksPIDMC_antid[col1->index()], selectedtracksPIDMC_antip[col2->index()], 1); // mixing ME } } } @@ -432,30 +1293,249 @@ struct hadronnucleicorrelation { } // clearing up - for (auto i = selectedtracks_antid.begin(); i != selectedtracks_antid.end(); i++) + for (auto i = selectedtracksMC_antid.begin(); i != selectedtracksMC_antid.end(); i++) (i->second).clear(); - selectedtracks_antid.clear(); + selectedtracksMC_antid.clear(); - for (auto i = selectedtracks_antip.begin(); i != selectedtracks_antip.end(); i++) + for (auto i = selectedtracksMC_d.begin(); i != selectedtracksMC_d.end(); i++) (i->second).clear(); - selectedtracks_antip.clear(); + selectedtracksMC_d.clear(); - for (auto i = selectedtracks_p.begin(); i != selectedtracks_p.end(); i++) + for (auto i = selectedtracksMC_antip.begin(); i != selectedtracksMC_antip.end(); i++) (i->second).clear(); - selectedtracks_p.clear(); + selectedtracksMC_antip.clear(); + + for (auto i = selectedtracksMC_p.begin(); i != selectedtracksMC_p.end(); i++) + (i->second).clear(); + selectedtracksMC_p.clear(); + + for (auto i = selectedtracksPIDMC_antid.begin(); i != selectedtracksPIDMC_antid.end(); i++) + (i->second).clear(); + selectedtracksPIDMC_antid.clear(); + + for (auto i = selectedtracksPIDMC_d.begin(); i != selectedtracksPIDMC_d.end(); i++) + (i->second).clear(); + selectedtracksPIDMC_d.clear(); + + for (auto i = selectedtracksPIDMC_antip.begin(); i != selectedtracksPIDMC_antip.end(); i++) + (i->second).clear(); + selectedtracksPIDMC_antip.clear(); - for (auto i = mixbins_antidantip.begin(); i != mixbins_antidantip.end(); i++) + for (auto i = selectedtracksPIDMC_p.begin(); i != selectedtracksPIDMC_p.end(); i++) (i->second).clear(); - mixbins_antidantip.clear(); + selectedtracksPIDMC_p.clear(); + + for (auto& pair : mixbinsPID_antidantip) { + pair.second.clear(); // clear the vector associated with the key + } + mixbinsPID_antidantip.clear(); // clear the map + + for (auto& pair : mixbins_antidantip) { + pair.second.clear(); // clear the vector associated with the key + } + mixbins_antidantip.clear(); // clear the map + } + PROCESS_SWITCH(hadronnucleicorrelation, processMC, "processMC", false); + + void processGen(SimCollisions const& mcCollisions, + SimParticles const& mcParticles) + { + for (auto particle : mcParticles) { + + if (particle.pdgCode() == pdgProton) { + registry.fill(HIST("Generated/hQAProtons"), 0.5); + } + if (particle.pdgCode() == pdgDeuteron) { + registry.fill(HIST("Generated/hQADeuterons"), 0.5); + } + + if (isPrim && !particle.isPhysicalPrimary()) { + continue; + } + if (particle.pdgCode() == pdgProton) { + registry.fill(HIST("Generated/hQAProtons"), 1.5); + } + if (particle.pdgCode() == pdgDeuteron) { + registry.fill(HIST("Generated/hQADeuterons"), 1.5); + } - for (auto i = mixbins_pantip.begin(); i != mixbins_pantip.end(); i++) + if (particle.pdgCode() == pdgDeuteron && std::abs(particle.y()) < 0.5) { + registry.fill(HIST("Generated/hDeuteronsVsPt"), particle.pt()); + } + if (particle.pdgCode() == -pdgDeuteron && std::abs(particle.y()) < 0.5) { + registry.fill(HIST("Generated/hAntiDeuteronsVsPt"), particle.pt()); + } + + if (std::abs(particle.eta()) > etacut) { + continue; + } + if (particle.pdgCode() == pdgProton) { + registry.fill(HIST("Generated/hQAProtons"), 2.5); + } + if (particle.pdgCode() == pdgDeuteron) { + registry.fill(HIST("Generated/hQADeuterons"), 2.5); + } + + if (particle.pdgCode() == pdgDeuteron) { + selectedparticlesMC_d[particle.mcCollisionId()].push_back(std::make_shared(particle)); + } + if (particle.pdgCode() == -pdgDeuteron) { + selectedparticlesMC_antid[particle.mcCollisionId()].push_back(std::make_shared(particle)); + } + if (particle.pdgCode() == pdgProton) { + if (!particle.has_daughters()) { + selectedparticlesMC_p[particle.mcCollisionId()].push_back(std::make_shared(particle)); + registry.fill(HIST("Generated/hQAProtons"), 3.5); + } else { + bool isd = false; + for (auto& dau : particle.daughters_as()) { + if (dau.pdgCode() == pdgDeuteron) { + isd = true; + } + } + if (isd) { + registry.fill(HIST("Generated/hQAProtons"), 4.5); + } + } + } + if (particle.pdgCode() == -pdgProton) { + if (!particle.has_daughters()) { + selectedparticlesMC_antip[particle.mcCollisionId()].push_back(std::make_shared(particle)); + } + } + } + + for (auto collision1 : mcCollisions) { // loop on collisions + + registry.fill(HIST("Generated/hNEventsMC"), 0.5); + + // anti-d - anti-p correlation + if (selectedparticlesMC_antid.find(collision1.globalIndex()) != selectedparticlesMC_antid.end()) { + if (selectedparticlesMC_antip.find(collision1.globalIndex()) != selectedparticlesMC_antip.end()) { + mixMCParticles<0>(selectedparticlesMC_antid[collision1.globalIndex()], selectedparticlesMC_antip[collision1.globalIndex()]); // mixing SE + } + + int stop1 = 0; + + for (auto collision2 : mcCollisions) { // nested loop on collisions + + if (collision1.globalIndex() == collision2.globalIndex()) { + continue; + } + + if (stop1 > maxmixcollsGen) { + break; + } + + if (selectedparticlesMC_antip.find(collision2.globalIndex()) != selectedparticlesMC_antip.end()) { + mixMCParticles<1>(selectedparticlesMC_antid[collision1.globalIndex()], selectedparticlesMC_antip[collision2.globalIndex()]); // mixing ME + } + + stop1++; + } + } + + // d - p correlation + if (domatterGen) { + if (selectedparticlesMC_d.find(collision1.globalIndex()) != selectedparticlesMC_d.end()) { + if (selectedparticlesMC_p.find(collision1.globalIndex()) != selectedparticlesMC_p.end()) { + mixMCParticles<0>(selectedparticlesMC_d[collision1.globalIndex()], selectedparticlesMC_p[collision1.globalIndex()]); // mixing SE + } + + int stop2 = 0; + + for (auto collision2 : mcCollisions) { // nested loop on collisions + + if (collision1.globalIndex() == collision2.globalIndex()) { + continue; + } + + if (stop2 > maxmixcollsGen) { + break; + } + + if (selectedparticlesMC_p.find(collision2.globalIndex()) != selectedparticlesMC_p.end()) { + mixMCParticles<1>(selectedparticlesMC_d[collision1.globalIndex()], selectedparticlesMC_p[collision2.globalIndex()]); // mixing ME + } + + stop2++; + } + } + } + + // anti-p - anti-p correlation + if (selectedparticlesMC_antip.find(collision1.globalIndex()) != selectedparticlesMC_antip.end()) { + + mixMCParticlesIdentical<0>(selectedparticlesMC_antip[collision1.globalIndex()], selectedparticlesMC_antip[collision1.globalIndex()]); // mixing SE + + int stop3 = 0; + + for (auto collision2 : mcCollisions) { // nested loop on collisions + + if (collision1.globalIndex() == collision2.globalIndex()) { + continue; + } + + if (stop3 > maxmixcollsGen) { + break; + } + + if (selectedparticlesMC_antip.find(collision2.globalIndex()) != selectedparticlesMC_antip.end()) { + mixMCParticlesIdentical<1>(selectedparticlesMC_antip[collision1.globalIndex()], selectedparticlesMC_antip[collision2.globalIndex()]); // mixing ME + } + + stop3++; + } + } + // p - p correlation + if (domatterGen) { + if (selectedparticlesMC_p.find(collision1.globalIndex()) != selectedparticlesMC_p.end()) { + + mixMCParticlesIdentical<0>(selectedparticlesMC_p[collision1.globalIndex()], selectedparticlesMC_p[collision1.globalIndex()]); // mixing SE + + int stop4 = 0; + + for (auto collision2 : mcCollisions) { // nested loop on collisions + + if (collision1.globalIndex() == collision2.globalIndex()) { + continue; + } + + if (stop4 > maxmixcollsGen) { + break; + } + + if (selectedparticlesMC_p.find(collision2.globalIndex()) != selectedparticlesMC_p.end()) { + mixMCParticlesIdentical<1>(selectedparticlesMC_p[collision1.globalIndex()], selectedparticlesMC_p[collision2.globalIndex()]); // mixing ME + } + + stop4++; + } + } + } + } + + // clearing up + for (auto i = selectedparticlesMC_antid.begin(); i != selectedparticlesMC_antid.end(); i++) + (i->second).clear(); + selectedparticlesMC_antid.clear(); + + for (auto i = selectedparticlesMC_d.begin(); i != selectedparticlesMC_d.end(); i++) + (i->second).clear(); + selectedparticlesMC_d.clear(); + + for (auto i = selectedparticlesMC_antip.begin(); i != selectedparticlesMC_antip.end(); i++) (i->second).clear(); - mixbins_pantip.clear(); + selectedparticlesMC_antip.clear(); + + for (auto i = selectedparticlesMC_p.begin(); i != selectedparticlesMC_p.end(); i++) + (i->second).clear(); + selectedparticlesMC_p.clear(); } - PROCESS_SWITCH(hadronnucleicorrelation, processData, "processData", true); + PROCESS_SWITCH(hadronnucleicorrelation, processGen, "processGen", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} \ No newline at end of file +} diff --git a/PWGLF/Tasks/Nuspex/hypertriton3bodyMCQA.cxx b/PWGLF/Tasks/Nuspex/hypertriton3bodyMCQA.cxx deleted file mode 100644 index a01b19ba2be..00000000000 --- a/PWGLF/Tasks/Nuspex/hypertriton3bodyMCQA.cxx +++ /dev/null @@ -1,723 +0,0 @@ -// 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. -// ======================== -// -// This code perform a check for all mcparticles and tracks -// which has corresponding mcparticles to find out the properties -// of hypertriton 3-body decay -// -// author: yuanzhe.wang@cern.ch - -#include -#include -#include -#include - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" -#include "CommonConstants/PhysicsConstants.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; - -using FullTracksExtIU = soa::Join; -using MCLabeledTracksIU = soa::Join; - -template -bool is3bodyDecayedH3L(TMCParticle const& particle) -{ - if (std::abs(particle.pdgCode()) != 1010010030) { - return false; - } - bool haveProton = false, havePion = false, haveDeuteron = false; - bool haveAntiProton = false, haveAntiPion = false, haveAntiDeuteron = false; - for (auto& mcDaughter : particle.template daughters_as()) { - if (mcDaughter.pdgCode() == 2212) - haveProton = true; - if (mcDaughter.pdgCode() == -2212) - haveAntiProton = true; - if (mcDaughter.pdgCode() == 211) - havePion = true; - if (mcDaughter.pdgCode() == -211) - haveAntiPion = true; - if (mcDaughter.pdgCode() == 1000010020) - haveDeuteron = true; - if (mcDaughter.pdgCode() == -1000010020) - haveAntiDeuteron = true; - } - if (haveProton && haveAntiPion && haveDeuteron && particle.pdgCode() > 0) { - return true; - } else if (haveAntiProton && havePion && haveAntiDeuteron && particle.pdgCode() < 0) { - return true; - } - return false; -} - -template -bool isPairedH3LDaughters(TMCParticle const& mctrack0, TMCParticle const& mctrack1, TMCParticle const& mctrack2) -{ - for (auto& particleMother : mctrack0.template mothers_as()) { - if (!(particleMother.pdgCode() == 1010010030 && mctrack0.pdgCode() == 2212 && mctrack1.pdgCode() == -211 && mctrack2.pdgCode() == 1000010020) && - !(particleMother.pdgCode() == -1010010030 && mctrack0.pdgCode() == -2212 && mctrack1.pdgCode() == 211 && mctrack2.pdgCode() == -1000010020)) { - continue; - } - bool flag1 = false, flag2 = false; - for (auto& mcDaughter : particleMother.template daughters_as()) { - if (mcDaughter.globalIndex() == mctrack1.globalIndex()) - flag1 = true; - if (mcDaughter.globalIndex() == mctrack2.globalIndex()) - flag2 = true; - } - if (!flag1 || !flag2) - continue; - // move the requirement in mass region into the loop to draw a histogram - // double hypertritonMCMass = RecoDecay::m(array{array{mctrack0.px(), mctrack0.py(), mctrack0.pz()}, array{mctrack1.px(), mctrack1.py(), mctrack1.pz()}, array{mctrack2.px(), mctrack2.py(), mctrack2.pz()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); - // if (hypertritonMCMass > 2.990 && hypertritonMCMass < 2.993) - return true; - } - return false; -} - -// check the properties of daughters candidates and true daughters -struct hypertriton3bodyTrackMcinfo { - // Basic checks - HistogramRegistry registry{ - "registry", - { - {"hEventCounter", "hEventCounter", {HistType::kTH1F, {{3, 0.0f, 3.0f}}}}, - {"hParticleCount", "hParticleCount", {HistType::kTH1F, {{7, 0.0f, 7.0f}}}}, - - {"hTPCNCls", "hTPCNCls", {HistType::kTH1F, {{160, 0.0f, 160.0f}}}}, - {"hTPCNClsCrossedRows", "hTPCNClsCrossedRows", {HistType::kTH1F, {{160, 0.0f, 160.0f}}}}, - {"hTrackEta", "hTrackEta", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hTrackITSNcls", "hTrackITSNcls", {HistType::kTH1F, {{10, 0.0f, 10.0f}}}}, - {"hTrackMcRapidity", "hTrackMcRapidity", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hTrackNsigmaProton", "hTrackNsigmaProton", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hTrackNsigmaPion", "hTrackNsigmaPion", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hTrackNsigmaDeuteron", "hTrackNsigmaDeuteron", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - - {"hHypertritonEta", "hHypertritomEta", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hHypertritonMcRapidity", "hHypertritonMcRapidity", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hHypertritonMcPt", "hHypertritonMcPt", {HistType::kTH1F, {{300, 0.0f, 15.0f}}}}, - - {"hProtonCount", "hProtonCount", {HistType::kTH1F, {{6, 0.0f, 6.0f}}}}, - {"hProtonPt", "hProtonPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hProtonP", "hProtonP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hProtonMcPt", "hProtonMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hProtonMcP", "hProtonMcP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hProtonEta", "hProtonEta", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hProtonMcRapidity", "hProtonMcRapidity", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hProtonNsigmaProton", "hProtonNsigmaProton", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hProtonTPCNCls", "hProtonTPCNCls", {HistType::kTH1F, {{120, 0.0f, 120.0f}}}}, - {"hProtonTPCBB", "hProtonTPCBB", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hProtonTPCBBAfterTPCNclsCut", "hProtonTPCBBAfterTPCNclsCut", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hDauProtonPt", "hDauProtonPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDauProtonMcPt", "hDauProtonMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDauProtonNsigmaProton", "hDauProtonNsigmaProton", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hDauProtonTPCVsPt", "hDauProtonTPCVsPt", {HistType::kTH2F, {{50, 0.0f, 5.0f, "#it{p}_{T} (GeV/c)"}, {120, -6.0f, 6.0f, "TPC n#sigma"}}}}, - - {"hPionCount", "hPionCount", {HistType::kTH1F, {{7, 0.0f, 7.0f}}}}, - {"hPionPt", "hPionPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPionP", "hPionP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPionMcPt", "hPionMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPionMcP", "hPionMcP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hPionEta", "hPionEta", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hPionMcRapidity", "hPionMcRapidity", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hPionNsigmaPion", "hPionNsigmaPion", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hPionTPCNCls", "hPionTPCNCls", {HistType::kTH1F, {{160, 0.0f, 160.0f}}}}, - {"hPionTPCBB", "hPionTPCBB", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hPionTPCBBAfterTPCNclsCut", "hPionTPCBBAfterTPCNclsCut", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hDauPionPt", "hDauPionPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDauPionMcPt", "hDauPionMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDauPionNsigmaPion", "hDauPionNsigmaPion", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hDauPionTPCVsPt", "hDauPionTPCVsPt", {HistType::kTH2F, {{20, 0.0f, 2.0f, "#it{p}_{T} (GeV/c)"}, {120, -6.0f, 6.0f, "TPC n#sigma"}}}}, - - {"hDeuteronCount", "hDeuteronCount", {HistType::kTH1F, {{7, 0.0f, 7.0f}}}}, - {"hDeuteronPt", "hDeuteronPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDeuteronP", "hDeuteronP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDeuteronMcPt", "hDeuteronMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDeuteronMcP", "hDeuteronMcP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDeuteronEta", "hDeuteronEta", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hDeuteronMcRapidity", "hDeuteronMcRapidity", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, - {"hDeuteronNsigmaDeuteron", "hDeuteronNsigmaDeuteron", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hDeuteronTPCNCls", "hDeuteronTPCNCls", {HistType::kTH1F, {{120, 0.0f, 120.0f}}}}, - {"hDeuteronTPCBB", "hDeuteronTPCBB", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hDeuteronTPCBBAfterTPCNclsCut", "hDeuteronTPCBBAfterTPCNclsCut", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, - {"hDauDeuteronPt", "hDauDeuteronPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDauDeuteronMcPt", "hDauDeuteronMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hDauDeuteronTPCVsPt", "hDauDeuteronTPCVsPt", {HistType::kTH2F, {{80, 0.0f, 8.0f, "#it{p}_{T} (GeV/c)"}, {120, -6.0f, 6.0f, "TPC n#sigma"}}}}, - {"hDauDeuteronTOFNSigmaVsP", "hDauDeuteronTOFNSigmaVsP", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, - {"hDauDeuteronTOFNSigmaVsPHasTOF", "hDauDeuteronTOFNSigmaVsPHasTOF", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, - {"hDeuteronTOFMatchCounter", "hDeuteronTOFMatchCounter", {HistType::kTH1F, {{8, 0.0f, 8.0f}}}}, - {"hDauDeuteronMatchCounter", "hDauDeuteronMatchCounter", {HistType::kTH1F, {{4, 0.0f, 4.0f}}}}, - - {"hTPCBB", "hTPCBB", {HistType::kTH2F, {{120, -8.0f, 8.0f, "p/z(GeV/c)"}, {100, 0.0f, 1000.0f, "TPCSignal"}}}}, - - {"hPairedH3LDaughers", "hPairedH3LDaughers", {HistType::kTH1F, {{3, 0.0f, 3.0f}}}}, - {"hPairedH3LDaughersInvMass", "hPairedH3LDaughersInvMass", {HistType::kTH1F, {{300, 2.9f, 3.2f}}}}, - {"hDuplicatedH3LDaughers", "hDuplicatedH3LDaughers", {HistType::kTH1F, {{3, 0.0f, 3.0f}}}}, - {"hTestCounter", "hTestCounter", {HistType::kTH1F, {{22, 0.0f, 22.0f}}}}, - }, - }; - - void init(InitContext&) - { - registry.get(HIST("hParticleCount"))->GetXaxis()->SetBinLabel(1, "Readin"); - registry.get(HIST("hParticleCount"))->GetXaxis()->SetBinLabel(2, "Has_mcparticle"); - registry.get(HIST("hParticleCount"))->GetXaxis()->SetBinLabel(3, "Rapidity Cut"); - registry.get(HIST("hParticleCount"))->GetXaxis()->SetBinLabel(4, "McisHypertriton"); - registry.get(HIST("hParticleCount"))->GetXaxis()->SetBinLabel(5, "McisProton"); - registry.get(HIST("hParticleCount"))->GetXaxis()->SetBinLabel(6, "McisPion"); - registry.get(HIST("hParticleCount"))->GetXaxis()->SetBinLabel(7, "McisDeuteron"); - - registry.get(HIST("hTestCounter"))->GetXaxis()->SetBinLabel(1, "All track"); - registry.get(HIST("hTestCounter"))->GetXaxis()->SetBinLabel(2, "hasMC"); - registry.get(HIST("hTestCounter"))->GetXaxis()->SetBinLabel(3, "hasMC&TPC&TOF"); - for (int i = 0; i < 16; i++) { - registry.get(HIST("hTestCounter"))->GetXaxis()->SetBinLabel(i + 4, Form("Bit %d", i)); - } - registry.get(HIST("hTestCounter"))->GetXaxis()->SetBinLabel(20, "hasMC&TPC&TOF&(!Bit15)"); - registry.get(HIST("hTestCounter"))->GetXaxis()->SetBinLabel(21, "hasMC&TPC&TOF&(!Bit11)"); - registry.get(HIST("hTestCounter"))->GetXaxis()->SetBinLabel(21, "hasMC&TPC&TOF&(!Bit13)&(Bit15)"); - - TString TrackCounterbinLabel[6] = {"hasMom", "FromHypertriton", "TPCNcls", "Eta", "Pt", "TPCPID"}; - for (int i{0}; i < 6; i++) { - registry.get(HIST("hProtonCount"))->GetXaxis()->SetBinLabel(i + 1, TrackCounterbinLabel[i]); - registry.get(HIST("hPionCount"))->GetXaxis()->SetBinLabel(i + 1, TrackCounterbinLabel[i]); - registry.get(HIST("hDeuteronCount"))->GetXaxis()->SetBinLabel(i + 1, TrackCounterbinLabel[i]); - } - registry.get(HIST("hPionCount"))->GetXaxis()->SetBinLabel(7, "DcatoPV"); - registry.get(HIST("hDeuteronCount"))->GetXaxis()->SetBinLabel(7, "hasTOF"); - registry.get(HIST("hDuplicatedH3LDaughers"))->GetXaxis()->SetBinLabel(1, "proton"); - registry.get(HIST("hDuplicatedH3LDaughers"))->GetXaxis()->SetBinLabel(2, "pion"); - registry.get(HIST("hDuplicatedH3LDaughers"))->GetXaxis()->SetBinLabel(3, "deuteron"); - - registry.get(HIST("hDauDeuteronMatchCounter"))->GetXaxis()->SetBinLabel(1, "Total"); - registry.get(HIST("hDauDeuteronMatchCounter"))->GetXaxis()->SetBinLabel(2, "correct collision"); - registry.get(HIST("hDauDeuteronMatchCounter"))->GetXaxis()->SetBinLabel(3, "hasTOF"); - registry.get(HIST("hDauDeuteronMatchCounter"))->GetXaxis()->SetBinLabel(4, "hasTOF & correct collsion"); - } - - Configurable dcapiontopv{"dcapiontopv", .05, "DCA Pion To PV"}; - Configurable minProtonPt{"minProtonPt", 0.3, "minProtonPt"}; - Configurable maxProtonPt{"maxProtonPt", 5, "maxProtonPt"}; - Configurable minPionPt{"minPionPt", 0.1, "minPionPt"}; - Configurable maxPionPt{"maxPionPt", 1.2, "maxPionPt"}; - Configurable minDeuteronPt{"minDeuteronPt", 0.6, "minDeuteronPt"}; - Configurable maxDeuteronPt{"maxDeuteronPt", 10, "maxDeuteronPt"}; - Configurable event_sel8_selection{"event_sel8_selection", true, "event selection count post sel8 cut"}; - Configurable event_posZ_selection{"event_posZ_selection", true, "event selection count post poZ cut"}; - - struct Indexdaughters { // check duplicated paired daughters - int64_t index0; - int64_t index1; - int64_t index2; - bool operator==(const Indexdaughters& t) const - { - return (this->index0 == t.index0 && this->index1 == t.index1 && this->index2 == t.index2); - } - }; - - void process(soa::Join::iterator const& collision, aod::McParticles const& /*particlesMC*/, MCLabeledTracksIU const& tracks, aod::McCollisions const& /*mcCollisions*/) - { - - registry.fill(HIST("hEventCounter"), 0.5); - if (event_sel8_selection && !collision.sel8()) { - return; - } - registry.fill(HIST("hEventCounter"), 1.5); - if (event_posZ_selection && abs(collision.posZ()) > 10.f) { // 10cm - return; - } - registry.fill(HIST("hEventCounter"), 2.5); - - std::vector protons, pions, deuterons; // index for daughter tracks - std::unordered_set set_proton, set_pion, set_deuteron; // check duplicated daughters - int itrack = -1; - - for (auto& track : tracks) { - - ++itrack; - registry.fill(HIST("hParticleCount"), 0.5); - registry.fill(HIST("hTrackITSNcls"), track.itsNCls()); - registry.fill(HIST("hTPCNCls"), track.tpcNClsFound()); - registry.fill(HIST("hTPCNClsCrossedRows"), track.tpcNClsCrossedRows()); - registry.fill(HIST("hTrackNsigmaDeuteron"), track.tpcNSigmaDe()); - registry.fill(HIST("hTrackNsigmaProton"), track.tpcNSigmaPr()); - registry.fill(HIST("hTrackNsigmaPion"), track.tpcNSigmaPi()); - - registry.fill(HIST("hTestCounter"), 0.5); - for (int i = 0; i < 16; i++) { - if (track.mcMask() & 1 << i) { // Bit ON means mismatch - registry.fill(HIST("hTestCounter"), i + 3.5); - } - } - - if (!track.has_mcParticle()) { - continue; - } - registry.fill(HIST("hTestCounter"), 1.5); - auto mcparticle = track.mcParticle_as(); - registry.fill(HIST("hTPCBB"), track.p() * track.sign(), track.tpcSignal()); - - if (track.hasTOF() && track.hasTPC()) { - registry.fill(HIST("hTestCounter"), 2.5); - if (!(track.mcMask() & 1 << 15)) { - registry.fill(HIST("hTestCounter"), 19.5); - } - if (!(track.mcMask() & 1 << 11)) { - registry.fill(HIST("hTestCounter"), 20.5); - } - if (!(track.mcMask() & 1 << 13) && (track.mcMask() & 1 << 15)) { - registry.fill(HIST("hTestCounter"), 21.5); - } - } - registry.fill(HIST("hParticleCount"), 1.5); - - // if (TMath::Abs(mcparticle.y()) > 0.9) {continue;} - registry.fill(HIST("hParticleCount"), 2.5); - registry.fill(HIST("hTrackEta"), track.eta()); - registry.fill(HIST("hTrackMcRapidity"), mcparticle.y()); - - // Hypertriton detected directly - if (mcparticle.pdgCode() == 1010010030 || mcparticle.pdgCode() == -1010010030) { - registry.fill(HIST("hParticleCount"), 3.5); - registry.fill(HIST("hHypertritonMcPt"), mcparticle.pt()); - registry.fill(HIST("hHypertritonEta"), track.eta()); - registry.fill(HIST("hHypertritonMcRapidity"), mcparticle.y()); - } - - // Proton - if (mcparticle.pdgCode() == 2212 || mcparticle.pdgCode() == -2212) { - registry.fill(HIST("hParticleCount"), 4.5); - if (track.tpcNClsFound() > 70) { - registry.fill(HIST("hProtonTPCBBAfterTPCNclsCut"), track.p() * track.sign(), track.tpcSignal()); - } - - if (mcparticle.has_mothers()) { - registry.fill(HIST("hProtonCount"), 0.5); - for (auto& particleMother : mcparticle.mothers_as()) { - bool flag_H3L = is3bodyDecayedH3L(particleMother); - if (!flag_H3L) { - continue; - } - protons.push_back(itrack); - auto p = set_proton.insert(mcparticle.globalIndex()); - if (p.second == false) - registry.fill(HIST("hDuplicatedH3LDaughers"), 0); - registry.fill(HIST("hProtonCount"), 1.5); - registry.fill(HIST("hDauProtonPt"), track.pt()); - registry.fill(HIST("hDauProtonMcPt"), mcparticle.pt()); - registry.fill(HIST("hDauProtonNsigmaProton"), track.tpcNSigmaPr()); - registry.fill(HIST("hDauProtonTPCVsPt"), track.pt(), track.tpcNSigmaPr()); - if (track.tpcNClsFound() < 70) { - continue; - } - registry.fill(HIST("hProtonCount"), 2.5); - if (TMath::Abs(track.eta()) > 0.9) { - continue; - } - registry.fill(HIST("hProtonCount"), 3.5); - if (track.pt() < minProtonPt || track.pt() > maxProtonPt) { - continue; - } - registry.fill(HIST("hProtonCount"), 4.5); - if (TMath::Abs(track.tpcNSigmaPr()) > 5) { - continue; - } - registry.fill(HIST("hProtonCount"), 5.5); - } - } - - registry.fill(HIST("hProtonMcPt"), mcparticle.pt()); - registry.fill(HIST("hProtonMcP"), mcparticle.p()); - registry.fill(HIST("hProtonPt"), track.pt()); - registry.fill(HIST("hProtonP"), track.p()); - - registry.fill(HIST("hProtonNsigmaProton"), track.tpcNSigmaPr()); - registry.fill(HIST("hProtonTPCNCls"), track.tpcNClsFound()); - registry.fill(HIST("hProtonEta"), track.eta()); - registry.fill(HIST("hProtonMcRapidity"), mcparticle.y()); - registry.fill(HIST("hProtonTPCBB"), track.p() * track.sign(), track.tpcSignal()); - } - - // Pion - if (mcparticle.pdgCode() == 211 || mcparticle.pdgCode() == -211) { - registry.fill(HIST("hParticleCount"), 5.5); - if (track.tpcNClsFound() > 70) { - registry.fill(HIST("hPionTPCBBAfterTPCNclsCut"), track.p() * track.sign(), track.tpcSignal()); - } - - if (mcparticle.has_mothers()) { - registry.fill(HIST("hPionCount"), 0.5); - for (auto& particleMother : mcparticle.mothers_as()) { - bool flag_H3L = is3bodyDecayedH3L(particleMother); - if (!flag_H3L) { - continue; - } - pions.push_back(itrack); - auto p = set_pion.insert(mcparticle.globalIndex()); - if (p.second == false) - registry.fill(HIST("hDuplicatedH3LDaughers"), 1); - registry.fill(HIST("hPionCount"), 1.5); - registry.fill(HIST("hDauPionPt"), track.pt()); - registry.fill(HIST("hDauPionMcPt"), mcparticle.pt()); - registry.fill(HIST("hDauPionTPCVsPt"), track.pt(), track.tpcNSigmaPi()); - if (track.tpcNClsFound() < 70) { - continue; - } - registry.fill(HIST("hPionCount"), 2.5); - if (TMath::Abs(track.eta()) > 0.9) { - continue; - } - registry.fill(HIST("hPionCount"), 3.5); - if (track.pt() < minPionPt || track.pt() > maxPionPt) { - continue; - } - registry.fill(HIST("hPionCount"), 4.5); - if (TMath::Abs(track.tpcNSigmaPi()) > 5) { - continue; - } - registry.fill(HIST("hPionCount"), 5.5); - if (TMath::Abs(track.dcaXY()) < dcapiontopv) { - continue; - } - registry.fill(HIST("hPionCount"), 6.5); - } - } - - registry.fill(HIST("hPionMcPt"), mcparticle.pt()); - registry.fill(HIST("hPionMcP"), mcparticle.p()); - registry.fill(HIST("hPionPt"), track.pt()); - registry.fill(HIST("hPionP"), track.p()); - - registry.fill(HIST("hPionNsigmaPion"), track.tpcNSigmaPi()); - registry.fill(HIST("hPionTPCNCls"), track.tpcNClsFound()); - registry.fill(HIST("hPionEta"), track.eta()); - registry.fill(HIST("hPionMcRapidity"), mcparticle.y()); - registry.fill(HIST("hPionTPCBB"), track.p() * track.sign(), track.tpcSignal()); - } - - // Deuteron - if (mcparticle.pdgCode() == 1000010020 || mcparticle.pdgCode() == -1000010020) { - registry.fill(HIST("hParticleCount"), 6.5); - if (track.tpcNClsFound() > 70) { - registry.fill(HIST("hDeuteronTPCBBAfterTPCNclsCut"), track.p() * track.sign(), track.tpcSignal()); - } - - if (mcparticle.has_mothers()) { - registry.fill(HIST("hDeuteronCount"), 0.5); - for (auto& particleMother : mcparticle.mothers_as()) { - bool flag_H3L = is3bodyDecayedH3L(particleMother); - if (!flag_H3L) { - continue; - } - deuterons.push_back(itrack); - auto p = set_deuteron.insert(mcparticle.globalIndex()); - if (p.second == false) - registry.fill(HIST("hDuplicatedH3LDaughers"), 2); - registry.fill(HIST("hDeuteronCount"), 1.5); - registry.fill(HIST("hDauDeuteronPt"), track.pt()); - registry.fill(HIST("hDauDeuteronMcPt"), mcparticle.pt()); - registry.fill(HIST("hDauDeuteronTPCVsPt"), track.pt(), track.tpcNSigmaDe()); - registry.fill(HIST("hDauDeuteronTOFNSigmaVsP"), track.sign() * track.p(), track.tofNSigmaDe()); - if (track.hasTOF()) { - registry.fill(HIST("hDauDeuteronTOFNSigmaVsPHasTOF"), track.sign() * track.p(), track.tofNSigmaDe()); - } - registry.fill(HIST("hDauDeuteronMatchCounter"), 0.5); - if (mcparticle.mcCollisionId() == collision.mcCollisionId()) { - registry.fill(HIST("hDauDeuteronMatchCounter"), 1.5); - } - if (track.hasTOF()) { - registry.fill(HIST("hDauDeuteronMatchCounter"), 2.5); - if (mcparticle.mcCollisionId() == collision.mcCollisionId()) { - registry.fill(HIST("hDauDeuteronMatchCounter"), 3.5); - } - } - if (track.tpcNClsFound() < 70) { - continue; - } - registry.fill(HIST("hDeuteronCount"), 2.5); - if (TMath::Abs(track.eta()) > 0.9) { - continue; - } - registry.fill(HIST("hDeuteronCount"), 3.5); - if (track.pt() < minDeuteronPt || track.pt() > maxDeuteronPt) { - continue; - } - registry.fill(HIST("hDeuteronCount"), 4.5); - if (TMath::Abs(track.tpcNSigmaDe()) > 5) { - continue; - } - registry.fill(HIST("hDeuteronCount"), 5.5); - if (!track.hasTOF()) { - continue; - } - registry.fill(HIST("hDeuteronCount"), 6.5); - } - } - - registry.fill(HIST("hDeuteronMcPt"), mcparticle.pt()); - registry.fill(HIST("hDeuteronMcP"), mcparticle.p()); - registry.fill(HIST("hDeuteronPt"), track.pt()); - registry.fill(HIST("hDeuteronP"), track.p()); - - registry.fill(HIST("hDeuteronNsigmaDeuteron"), track.tpcNSigmaDe()); - registry.fill(HIST("hDeuteronTPCNCls"), track.tpcNClsFound()); - registry.fill(HIST("hDeuteronEta"), track.eta()); - registry.fill(HIST("hDeuteronMcRapidity"), mcparticle.y()); - registry.fill(HIST("hDeuteronTPCBB"), track.p() * track.sign(), track.tpcSignal()); - registry.fill(HIST("hDeuteronTOFMatchCounter"), 0.5); - if (!(track.mcMask() & 1 << 15)) { - registry.fill(HIST("hDeuteronTOFMatchCounter"), 1.5); - if (track.hasTPC() && track.hasTOF()) { - registry.fill(HIST("hDeuteronTOFMatchCounter"), 2.5); - if (!(track.mcMask() & 1 << 11)) { // Bit ON means mismatch - registry.fill(HIST("hDeuteronTOFMatchCounter"), 3.5); - } - } - } - } - } - - std::vector set_pair; - for (size_t iproton = 0; iproton < protons.size(); iproton++) { - auto track0 = tracks.iteratorAt(protons[iproton]); - auto mctrack0 = track0.mcParticle_as(); - for (size_t ipion = 0; ipion < pions.size(); ipion++) { - auto track1 = tracks.iteratorAt(pions[ipion]); - auto mctrack1 = track1.mcParticle_as(); - for (size_t ideuteron = 0; ideuteron < deuterons.size(); ideuteron++) { - auto track2 = tracks.iteratorAt(deuterons[ideuteron]); - auto mctrack2 = track2.mcParticle_as(); - if (isPairedH3LDaughters(mctrack0, mctrack1, mctrack2)) { - registry.fill(HIST("hPairedH3LDaughers"), 0); - // MC mass cut, to check if the daughters are from materials - double hypertritonMCMass = RecoDecay::m(array{array{mctrack0.px(), mctrack0.py(), mctrack0.pz()}, array{mctrack1.px(), mctrack1.py(), mctrack1.pz()}, array{mctrack2.px(), mctrack2.py(), mctrack2.pz()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); - registry.fill(HIST("hPairedH3LDaughersInvMass"), hypertritonMCMass); - if (hypertritonMCMass < 2.990 || hypertritonMCMass > 2.993) - continue; - registry.fill(HIST("hPairedH3LDaughers"), 1); - // duplicated daughters check - Indexdaughters temp = {mctrack0.globalIndex(), mctrack1.globalIndex(), mctrack2.globalIndex()}; - auto p = std::find(set_pair.begin(), set_pair.end(), temp); - if (p == set_pair.end()) { - set_pair.push_back(temp); - registry.fill(HIST("hPairedH3LDaughers"), 2); - } - } - } - } - } - } -}; - -// check the performance of mcparticle -struct hypertriton3bodyMcParticleCount { - // Basic checks - HistogramRegistry registry{ - "registry", - { - {"hTotalMcCollCounter", "hTotalMcCollCounter", {HistType::kTH1F, {{2, 0.0f, 2.0f}}}}, - - {"h3dMCDecayedHypertriton", "h3dMCDecayedHypertriton", {HistType::kTH3F, {{20, -1.0f, 1.0f, "Rapidity"}, {200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}, {50, 0.0f, 50.0f, "ct(cm)"}}}}, - {"hMcPhysicalPrimaryParticleCount", "hMcPhysicalPrimaryParticleCount", {HistType::kTH1F, {{8, 0.0f, 8.0f}}}}, - - {"hMcHypertritonCount", "hMcHypertritonCount", {HistType::kTH1F, {{9, 0.0f, 9.0f}}}}, - {"hMcHypertritonPt", "hMcHypertritonPt", {HistType::kTH1F, {{300, 0.0f, 15.0f}}}}, - {"hMcProtonPt", "hMcProtonPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hMcPionPt", "hMcPionPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hMcDeuteronPt", "hMcDeuteronPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - - {"hMcRecoInvMass", "hMcRecoInvMass", {HistType::kTH1F, {{100, 2.95, 3.05f}}}}, - }, - }; - - void init(InitContext&) - { - registry.get(HIST("hTotalMcCollCounter"))->GetXaxis()->SetBinLabel(1, "Total Count"); - registry.get(HIST("hTotalMcCollCounter"))->GetXaxis()->SetBinLabel(2, "Recoonstructed"); - - registry.get(HIST("hMcPhysicalPrimaryParticleCount"))->GetXaxis()->SetBinLabel(1, "Readin"); - registry.get(HIST("hMcPhysicalPrimaryParticleCount"))->GetXaxis()->SetBinLabel(2, "IsPhysicalPrimary"); - registry.get(HIST("hMcPhysicalPrimaryParticleCount"))->GetXaxis()->SetBinLabel(3, "y<0.9(off)"); - registry.get(HIST("hMcPhysicalPrimaryParticleCount"))->GetXaxis()->SetBinLabel(4, "(Anti)Proton"); - registry.get(HIST("hMcPhysicalPrimaryParticleCount"))->GetXaxis()->SetBinLabel(5, "(Anti)Pion"); - registry.get(HIST("hMcPhysicalPrimaryParticleCount"))->GetXaxis()->SetBinLabel(6, "(Anti)Deuteron"); - registry.get(HIST("hMcPhysicalPrimaryParticleCount"))->GetXaxis()->SetBinLabel(7, "(Anti)Hypertriton"); - registry.get(HIST("hMcPhysicalPrimaryParticleCount"))->GetXaxis()->SetBinLabel(8, "HasDaughter"); - registry.get(HIST("hMcHypertritonCount"))->GetXaxis()->SetBinLabel(1, "Hypertriton All"); - registry.get(HIST("hMcHypertritonCount"))->GetXaxis()->SetBinLabel(2, "Matter All"); - registry.get(HIST("hMcHypertritonCount"))->GetXaxis()->SetBinLabel(3, "AntiMatter All"); - registry.get(HIST("hMcHypertritonCount"))->GetXaxis()->SetBinLabel(4, "confirm to 3-body decay"); - registry.get(HIST("hMcHypertritonCount"))->GetXaxis()->SetBinLabel(5, "Matter"); - registry.get(HIST("hMcHypertritonCount"))->GetXaxis()->SetBinLabel(6, "AntiMatter"); - registry.get(HIST("hMcHypertritonCount"))->GetXaxis()->SetBinLabel(7, "Rapidity"); - registry.get(HIST("hMcHypertritonCount"))->GetXaxis()->SetBinLabel(8, "Lifetime"); - registry.get(HIST("hMcHypertritonCount"))->GetXaxis()->SetBinLabel(9, "PtCut"); - } - - Configurable rapidityMCcut{"rapidityMCcut", 1, "rapidity cut MC count"}; - Configurable event_sel8_selection{"event_sel8_selection", true, "event selection count post sel8 cut"}; - Configurable event_posZ_selection{"event_posZ_selection", true, "event selection count post poZ cut"}; - - void process(aod::McCollision const& mcCollision, aod::McParticles const& particlesMC, const soa::SmallGroups>& collisions) - { - std::vector SelectedEvents(collisions.size()); - int nevts = 0; - for (const auto& collision : collisions) { - if (event_sel8_selection && !collision.sel8()) { - continue; - } - if (event_posZ_selection && abs(collision.posZ()) > 10.f) { // 10cm - continue; - } - SelectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); - } - SelectedEvents.resize(nevts); - - registry.fill(HIST("hTotalMcCollCounter"), 0.5); - - const auto evtReconstructedAndSelected = std::find(SelectedEvents.begin(), SelectedEvents.end(), mcCollision.globalIndex()) != SelectedEvents.end(); - if (evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection - registry.fill(HIST("hTotalMcCollCounter"), 1.5); - // return; - } - - for (auto& mcparticle : particlesMC) { - - registry.fill(HIST("hMcPhysicalPrimaryParticleCount"), 0.5); - - if (mcparticle.pdgCode() == 2212 || mcparticle.pdgCode() == -2212) { - registry.fill(HIST("hMcProtonPt"), mcparticle.pt()); - } - if (mcparticle.pdgCode() == 211 || mcparticle.pdgCode() == -211) { - registry.fill(HIST("hMcPionPt"), mcparticle.pt()); - } - if (mcparticle.pdgCode() == 1000010020 || mcparticle.pdgCode() == -1000010020) { - registry.fill(HIST("hMcDeuteronPt"), mcparticle.pt()); - } - if (mcparticle.pdgCode() == 1010010030) { - registry.fill(HIST("hMcHypertritonCount"), 1.5); - } else if (mcparticle.pdgCode() == -1010010030) { - registry.fill(HIST("hMcHypertritonCount"), 2.5); - } - if (mcparticle.pdgCode() == 1010010030 || mcparticle.pdgCode() == -1010010030) { - registry.fill(HIST("hMcHypertritonCount"), 0.5); - registry.fill(HIST("hMcHypertritonPt"), mcparticle.pt()); - - double dauDeuteronPos[3] = {-999, -999, -999}; - double dauProtonMom[3] = {-999, -999, -999}; - double dauPionMom[3] = {-999, -999, -999}; - double dauDeuteronMom[3] = {-999, -999, -999}; - double MClifetime = 999; - bool flag_H3L = is3bodyDecayedH3L(mcparticle); - if (!flag_H3L) { - continue; - } - for (auto& mcparticleDaughter : mcparticle.daughters_as()) { - if (std::abs(mcparticleDaughter.pdgCode()) == 2212) { - dauProtonMom[0] = mcparticleDaughter.px(); - dauProtonMom[1] = mcparticleDaughter.py(); - dauProtonMom[2] = mcparticleDaughter.pz(); - } - if (std::abs(mcparticleDaughter.pdgCode()) == 211) { - dauPionMom[0] = mcparticleDaughter.px(); - dauPionMom[1] = mcparticleDaughter.py(); - dauPionMom[2] = mcparticleDaughter.pz(); - } - if (std::abs(mcparticleDaughter.pdgCode()) == 1000010020) { - dauDeuteronPos[0] = mcparticleDaughter.vx(); - dauDeuteronPos[1] = mcparticleDaughter.vy(); - dauDeuteronPos[2] = mcparticleDaughter.vz(); - dauDeuteronMom[0] = mcparticleDaughter.px(); - dauDeuteronMom[1] = mcparticleDaughter.py(); - dauDeuteronMom[2] = mcparticleDaughter.pz(); - } - } - if (mcparticle.pdgCode() == 1010010030) { - registry.fill(HIST("hMcHypertritonCount"), 3.5); - registry.fill(HIST("hMcHypertritonCount"), 4.5); - } - if (mcparticle.pdgCode() == -1010010030) { - registry.fill(HIST("hMcHypertritonCount"), 3.5); - registry.fill(HIST("hMcHypertritonCount"), 5.5); - } - MClifetime = RecoDecay::sqrtSumOfSquares(dauDeuteronPos[0] - mcparticle.vx(), dauDeuteronPos[1] - mcparticle.vy(), dauDeuteronPos[2] - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); - registry.fill(HIST("hMcRecoInvMass"), RecoDecay::m(array{array{dauProtonMom[0], dauProtonMom[1], dauProtonMom[2]}, array{dauPionMom[0], dauPionMom[1], dauPionMom[2]}, array{dauDeuteronMom[0], dauDeuteronMom[1], dauDeuteronMom[2]}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron})); - registry.fill(HIST("h3dMCDecayedHypertriton"), mcparticle.y(), mcparticle.pt(), MClifetime); - - // int daughterPionCount = 0; - // for (auto& mcparticleDaughter : mcparticle.daughters_as()) { - // if (std::abs(mcparticleDaughter.pdgCode()) == 211) { - // daughterPionCount++; - // } - // } - - // Count for hypertriton N_gen - if (TMath::Abs(mcparticle.y()) < 1) { - registry.fill(HIST("hMcHypertritonCount"), 6.5); - if (MClifetime < 40) { - registry.fill(HIST("hMcHypertritonCount"), 7.5); - if (mcparticle.pt() > 1 && mcparticle.pt() < 10) { - registry.fill(HIST("hMcHypertritonCount"), 8.5); - } - } - } - } - - if (!mcparticle.isPhysicalPrimary()) { - continue; - } - registry.fill(HIST("hMcPhysicalPrimaryParticleCount"), 1.5); - if (TMath::Abs(mcparticle.y()) > rapidityMCcut) { - continue; - } - registry.fill(HIST("hMcPhysicalPrimaryParticleCount"), 2.5); - - if (mcparticle.pdgCode() == 211 || mcparticle.pdgCode() == -211) { - registry.fill(HIST("hMcPhysicalPrimaryParticleCount"), 3.5); - } else if (mcparticle.pdgCode() == 2212 || mcparticle.pdgCode() == -2212) { - registry.fill(HIST("hMcPhysicalPrimaryParticleCount"), 4.5); - } else if (mcparticle.pdgCode() == 1000010020 || mcparticle.pdgCode() == -1000010020) { - registry.fill(HIST("hMcPhysicalPrimaryParticleCount"), 5.5); - } else if (mcparticle.pdgCode() == 1010010030 || mcparticle.pdgCode() == -1010010030) { - registry.fill(HIST("hMcPhysicalPrimaryParticleCount"), 6.5); - } - - if (!mcparticle.has_daughters()) { - continue; - } - registry.fill(HIST("hMcPhysicalPrimaryParticleCount"), 7.5); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - }; -} diff --git a/PWGLF/Tasks/Nuspex/hypertriton3bodyMcqa.cxx b/PWGLF/Tasks/Nuspex/hypertriton3bodyMcqa.cxx new file mode 100644 index 00000000000..ef8dfb4b958 --- /dev/null +++ b/PWGLF/Tasks/Nuspex/hypertriton3bodyMcqa.cxx @@ -0,0 +1,908 @@ +// 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 hypertriton3bodyMcqa.cxx +/// \brief QA for MC productions which contain hypertriton 3body decay process, including special checks for TOF PID +/// \author Yuanzhe Wang + +#include +#include +#include +#include +#include +#include +#include + +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/IRFrame.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/pidTOFGeneric.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTOFBase.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "CommonConstants/PhysicsConstants.h" +#include "CCDB/BasicCCDBManager.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; +using ColwithEvTimes = o2::soa::Join; +using FullTracksExtIU = soa::Join; +using MCLabeledTracksIU = soa::Join; + +template +bool is3bodyDecayedH3L(TMCParticle const& particle) +{ + if (std::abs(particle.pdgCode()) != 1010010030) { + return false; + } + bool haveProton = false, havePion = false, haveDeuteron = false; + bool haveAntiProton = false, haveAntiPion = false, haveAntiDeuteron = false; + for (const auto& mcDaughter : particle.template daughters_as()) { + if (mcDaughter.pdgCode() == 2212) + haveProton = true; + if (mcDaughter.pdgCode() == -2212) + haveAntiProton = true; + if (mcDaughter.pdgCode() == 211) + havePion = true; + if (mcDaughter.pdgCode() == -211) + haveAntiPion = true; + if (mcDaughter.pdgCode() == 1000010020) + haveDeuteron = true; + if (mcDaughter.pdgCode() == -1000010020) + haveAntiDeuteron = true; + } + if (haveProton && haveAntiPion && haveDeuteron && particle.pdgCode() > 0) { + return true; + } else if (haveAntiProton && havePion && haveAntiDeuteron && particle.pdgCode() < 0) { + return true; + } + return false; +} + +template +bool isPairedH3LDaughters(TMCParticle const& mctrack0, TMCParticle const& mctrack1, TMCParticle const& mctrack2) +{ + for (const auto& particleMother : mctrack0.template mothers_as()) { + if (!(particleMother.pdgCode() == 1010010030 && mctrack0.pdgCode() == 2212 && mctrack1.pdgCode() == -211 && mctrack2.pdgCode() == 1000010020) && + !(particleMother.pdgCode() == -1010010030 && mctrack0.pdgCode() == -2212 && mctrack1.pdgCode() == 211 && mctrack2.pdgCode() == -1000010020)) { + continue; + } + bool flag1 = false, flag2 = false; + for (const auto& mcDaughter : particleMother.template daughters_as()) { + if (mcDaughter.globalIndex() == mctrack1.globalIndex()) + flag1 = true; + if (mcDaughter.globalIndex() == mctrack2.globalIndex()) + flag2 = true; + } + if (!flag1 || !flag2) + continue; + // move the requirement in mass region into the loop to draw a histogram + // double hypertritonMCMass = RecoDecay::m(array{array{mctrack0.px(), mctrack0.py(), mctrack0.pz()}, array{mctrack1.px(), mctrack1.py(), mctrack1.pz()}, array{mctrack2.px(), mctrack2.py(), mctrack2.pz()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); + // if (hypertritonMCMass > 2.990 && hypertritonMCMass < 2.993) + return true; + } + return false; +} + +// check the properties of daughters candidates and true daughters +struct Hypertriton3bodyMcqa { + + Service ccdb; + Preslice perCollisionTracks = aod::track::collisionId; + + int mRunNumber; + + // Basic checks + HistogramRegistry registry{ + "registry", + { + {"hEventCounter", "hEventCounter", {HistType::kTH1F, {{3, 0.0f, 3.0f}}}}, + {"hParticleCounter", "hParticleCounter", {HistType::kTH1F, {{7, 0.0f, 7.0f}}}}, + + {"hTPCNCls", "hTPCNCls", {HistType::kTH1F, {{160, 0.0f, 160.0f}}}}, + {"hTPCNClsCrossedRows", "hTPCNClsCrossedRows", {HistType::kTH1F, {{160, 0.0f, 160.0f}}}}, + {"hTrackEta", "hTrackEta", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, + {"hTrackITSNcls", "hTrackITSNcls", {HistType::kTH1F, {{10, 0.0f, 10.0f}}}}, + {"hTrackMcRapidity", "hTrackMcRapidity", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, + {"hTrackNsigmaProton", "hTrackNsigmaProton", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, + {"hTrackNsigmaPion", "hTrackNsigmaPion", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, + {"hTrackNsigmaDeuteron", "hTrackNsigmaDeuteron", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, + + {"hHypertritonEta", "hHypertritomEta", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, + {"hHypertritonMcRapidity", "hHypertritonMcRapidity", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, + {"hHypertritonMcPt", "hHypertritonMcPt", {HistType::kTH1F, {{300, 0.0f, 15.0f}}}}, + + {"hProtonCounter", "hProtonCounter", {HistType::kTH1F, {{2, 0.0f, 2.0f}}}}, + {"hProtonPt", "hProtonPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hProtonP", "hProtonP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hProtonMcPt", "hProtonMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hProtonMcP", "hProtonMcP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hProtonEta", "hProtonEta", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, + {"hProtonMcRapidity", "hProtonMcRapidity", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, + {"hProtonNsigmaProton", "hProtonNsigmaProton", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, + {"hProtonTPCNCls", "hProtonTPCNCls", {HistType::kTH1F, {{120, 0.0f, 120.0f}}}}, + {"hProtonTPCBB", "hProtonTPCBB", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, + {"hProtonTPCBBAfterTPCNclsCut", "hProtonTPCBBAfterTPCNclsCut", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, + {"hDauProtonPt", "hDauProtonPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hDauProtonMcPt", "hDauProtonMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hDauProtonNsigmaProton", "hDauProtonNsigmaProton", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, + {"hDauProtonTPCVsPt", "hDauProtonTPCVsPt", {HistType::kTH2F, {{50, 0.0f, 5.0f, "#it{p}_{T} (GeV/c)"}, {120, -6.0f, 6.0f, "TPC n#sigma"}}}}, + + {"hPionCounter", "hPionCounter", {HistType::kTH1F, {{2, 0.0f, 2.0f}}}}, + {"hPionPt", "hPionPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hPionP", "hPionP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hPionMcPt", "hPionMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hPionMcP", "hPionMcP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hPionEta", "hPionEta", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, + {"hPionMcRapidity", "hPionMcRapidity", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, + {"hPionNsigmaPion", "hPionNsigmaPion", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, + {"hPionTPCNCls", "hPionTPCNCls", {HistType::kTH1F, {{160, 0.0f, 160.0f}}}}, + {"hPionTPCBB", "hPionTPCBB", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, + {"hPionTPCBBAfterTPCNclsCut", "hPionTPCBBAfterTPCNclsCut", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, + {"hDauPionPt", "hDauPionPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hDauPionMcPt", "hDauPionMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hDauPionNsigmaPion", "hDauPionNsigmaPion", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, + {"hDauPionTPCVsPt", "hDauPionTPCVsPt", {HistType::kTH2F, {{20, 0.0f, 2.0f, "#it{p}_{T} (GeV/c)"}, {120, -6.0f, 6.0f, "TPC n#sigma"}}}}, + {"hDauPionDcaXY", "hDauPionDcaXY", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}}, + + {"hDeuteronCounter", "hDeuteronCounter", {HistType::kTH1F, {{2, 0.0f, 2.0f}}}}, + {"hDeuteronPt", "hDeuteronPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hDeuteronP", "hDeuteronP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hDeuteronMcPt", "hDeuteronMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hDeuteronMcP", "hDeuteronMcP", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hDeuteronEta", "hDeuteronEta", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, + {"hDeuteronMcRapidity", "hDeuteronMcRapidity", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, + {"hDeuteronNsigmaDeuteron", "hDeuteronNsigmaDeuteron", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, + {"hDeuteronTPCNCls", "hDeuteronTPCNCls", {HistType::kTH1F, {{120, 0.0f, 120.0f}}}}, + {"hDeuteronTPCBB", "hDeuteronTPCBB", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, + {"hDeuteronTPCBBAfterTPCNclsCut", "hDeuteronTPCBBAfterTPCNclsCut", {HistType::kTH2F, {{320, -8.0f, 8.0f, "p/z(GeV/c)"}, {200, 0.0f, 1000.0f, "TPCSignal"}}}}, + {"hDauDeuteronPt", "hDauDeuteronPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hDauDeuteronMcPt", "hDauDeuteronMcPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hDauDeuteronTPCVsPt", "hDauDeuteronTPCVsPt", {HistType::kTH2F, {{80, 0.0f, 8.0f, "#it{p}_{T} (GeV/c)"}, {120, -6.0f, 6.0f, "TPC n#sigma"}}}}, + {"hDauDeuteronTOFNSigmaVsP", "hDauDeuteronTOFNSigmaVsP", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, + {"hDauDeuteronTOFNSigmaVsPHasTOF", "hDauDeuteronTOFNSigmaVsPHasTOF", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, + {"hDauDeuteronMatchCounter", "hDauDeuteronMatchCounter", {HistType::kTH1F, {{4, 0.0f, 4.0f}}}}, + + {"hTPCBB", "hTPCBB", {HistType::kTH2F, {{120, -8.0f, 8.0f, "p/z(GeV/c)"}, {100, 0.0f, 1000.0f, "TPCSignal"}}}}, + + {"hPairedH3LDaughers", "hPairedH3LDaughers", {HistType::kTH1F, {{3, 0.0f, 3.0f}}}}, + {"hPairedH3LDaughersInvMass", "hPairedH3LDaughersInvMass", {HistType::kTH1F, {{300, 2.9f, 3.2f}}}}, + {"hDuplicatedH3LDaughers", "hDuplicatedH3LDaughers", {HistType::kTH1F, {{3, 0.0f, 3.0f}}}}, + + // Diff checks always requir hasTOF + {"hDiffTrackTOFSignal", "hDiffTrackTOFSignal", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}}, + {"hDiffEvTimeForTrack", "hDiffEvTimeForTrack", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}}, + {"hDiffTrackTOFNSigmaDe", "hDiffTrackTOFNSigmaDe", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}}, + {"hDauDeuteronNewTOFNSigmaVsP", "hDauDeuteronNewTOFNSigmaVsP", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, + {"hWrongDeuteronTOFNSigmaVsP", "hWrongDeuteronTOFNSigmaVsP", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, + {"hWrongDeuteronNewTOFNSigmaVsP", "hWrongDeuteronNewTOFNSigmaVsP", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, + {"hDiffColTime", "hDiffColTime", {HistType::kTH1F, {{200, -100.0f, 100.0f}}}}, + {"hDauDeuteronDiffTOFNsigmaDeHasTOF", "hDauDeuteronDiffTOFNsigmaDeHasTOF", {HistType::kTH1F, {{200, -100.0f, 100.0f}}}}, + + // _v2 for using relinked collision + {"hDauDeuteronTOFNSigmaVsP_CorrectCol", "hDauDeuteronTOFNSigmaVsP_CorrectCol", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, + {"hDauDeuteronNewTOFNSigmaVsP_CorrectCol", "hDauDeuteronNewTOFNSigmaVsP_CorrectCol", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, + {"hDauDeuteronTOFNSigmaVsP_v2", "hDauDeuteronTOFNSigmaVsP_v2", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, + {"hDauDeuteronNewTOFNSigmaVsP_v2_AO2D", "hDauDeuteronNewTOFNSigmaVsP_v2 AO2D", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, + {"hDauDeuteronNewTOFNSigmaVsP_v2_EvSel", "hDauDeuteronNewTOFNSigmaVsP_v2 EvSel", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, + {"hDauDeuteronTOFNSigmaVsColTimeRes_v2", "hDauDeuteronTOFNSigmaVsColTimeRes_v2", {HistType::kTH2F, {{100, 0.0f, 400.0f, "CollisionTimeRes(ns)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, + {"hDauDeuteronTOFNSigmaVsColTimeRes_v2_AO2D", "hDauDeuteronTOFNSigmaVsColTimeRes_v2 AO2D", {HistType::kTH2F, {{100, 0.0f, 400.0f, "CollisionTimeRes(ns)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, + {"hDauDeuteronTOFNSigmaVsColTimeRes_v2_EvSel", "hDauDeuteronTOFNSigmaVsColTimeRes_v2 EvSel", {HistType::kTH2F, {{100, 0.0f, 400.0f, "CollisionTimeRes(ns)"}, {600, -300.0f, 300.0f, "TOF n#sigma"}}}}, + {"hDauDeuteronTOFPIDCounter", "hDauDeuteronTOFPIDCounter", {HistType::kTH1F, {{5, 0.0f, 5.0f}}}}, + {"hDauDeuteronTOFPIDCounter_CloseBC", "hDauDeuteronTOFPIDCounter CloseBC", {HistType::kTH1F, {{5, 0.0f, 5.0f}}}}, + }, + }; + + void init(InitContext&) + { + registry.get(HIST("hParticleCounter"))->GetXaxis()->SetBinLabel(1, "Readin"); + registry.get(HIST("hParticleCounter"))->GetXaxis()->SetBinLabel(2, "Has_mcparticle"); + registry.get(HIST("hParticleCounter"))->GetXaxis()->SetBinLabel(3, "Rapidity Cut"); + registry.get(HIST("hParticleCounter"))->GetXaxis()->SetBinLabel(4, "McisHypertriton"); + registry.get(HIST("hParticleCounter"))->GetXaxis()->SetBinLabel(5, "McisProton"); + registry.get(HIST("hParticleCounter"))->GetXaxis()->SetBinLabel(6, "McisPion"); + registry.get(HIST("hParticleCounter"))->GetXaxis()->SetBinLabel(7, "McisDeuteron"); + + TString trackCounterbinLabel[2] = {"hasMom", "FromHypertriton"}; + for (int i{0}; i < 2; i++) { + registry.get(HIST("hProtonCounter"))->GetXaxis()->SetBinLabel(i + 1, trackCounterbinLabel[i]); + registry.get(HIST("hPionCounter"))->GetXaxis()->SetBinLabel(i + 1, trackCounterbinLabel[i]); + registry.get(HIST("hDeuteronCounter"))->GetXaxis()->SetBinLabel(i + 1, trackCounterbinLabel[i]); + } + registry.get(HIST("hDuplicatedH3LDaughers"))->GetXaxis()->SetBinLabel(1, "proton"); + registry.get(HIST("hDuplicatedH3LDaughers"))->GetXaxis()->SetBinLabel(2, "pion"); + registry.get(HIST("hDuplicatedH3LDaughers"))->GetXaxis()->SetBinLabel(3, "deuteron"); + + registry.get(HIST("hDauDeuteronMatchCounter"))->GetXaxis()->SetBinLabel(1, "Total"); + registry.get(HIST("hDauDeuteronMatchCounter"))->GetXaxis()->SetBinLabel(2, "correct collision"); + registry.get(HIST("hDauDeuteronMatchCounter"))->GetXaxis()->SetBinLabel(3, "hasTOF"); + registry.get(HIST("hDauDeuteronMatchCounter"))->GetXaxis()->SetBinLabel(4, "hasTOF & correct collsion"); + + registry.get(HIST("hDauDeuteronTOFPIDCounter"))->GetXaxis()->SetBinLabel(1, "Origin |n#sigma| >= 5"); + registry.get(HIST("hDauDeuteronTOFPIDCounter"))->GetXaxis()->SetBinLabel(2, "BothBC work"); + registry.get(HIST("hDauDeuteronTOFPIDCounter"))->GetXaxis()->SetBinLabel(3, "Only BCAO2D work"); + registry.get(HIST("hDauDeuteronTOFPIDCounter"))->GetXaxis()->SetBinLabel(4, "Only BCEvSel work"); + registry.get(HIST("hDauDeuteronTOFPIDCounter"))->GetXaxis()->SetBinLabel(5, "BothBC not work"); + registry.get(HIST("hDauDeuteronTOFPIDCounter_CloseBC"))->GetXaxis()->SetBinLabel(1, "Origin |n#sigma| < 6"); + registry.get(HIST("hDauDeuteronTOFPIDCounter_CloseBC"))->GetXaxis()->SetBinLabel(2, "BothBC work"); + registry.get(HIST("hDauDeuteronTOFPIDCounter_CloseBC"))->GetXaxis()->SetBinLabel(3, "Only BCAO2D work"); + registry.get(HIST("hDauDeuteronTOFPIDCounter_CloseBC"))->GetXaxis()->SetBinLabel(4, "Only BCEvSel work"); + registry.get(HIST("hDauDeuteronTOFPIDCounter_CloseBC"))->GetXaxis()->SetBinLabel(5, "BothBC not work"); + } + + Configurable dcapiontopv{"dcapiontopv", .05, "DCA Pion To PV"}; + Configurable minProtonPt{"minProtonPt", 0.3, "minProtonPt"}; + Configurable maxProtonPt{"maxProtonPt", 5, "maxProtonPt"}; + Configurable minPionPt{"minPionPt", 0.1, "minPionPt"}; + Configurable maxPionPt{"maxPionPt", 1.2, "maxPionPt"}; + Configurable minDeuteronPt{"minDeuteronPt", 0.6, "minDeuteronPt"}; + Configurable maxDeuteronPt{"maxDeuteronPt", 10, "maxDeuteronPt"}; + Configurable mc_event_selection{"mc_event_selection", true, "mc event selection count post kIsTriggerTVX and kNoTimeFrameBorder"}; + Configurable event_posZ_selection{"event_posZ_selection", true, "event selection count post poZ cut"}; + + // CCDB TOF PID paras + Configurable timestamp{"ccdb-timestamp", -1, "timestamp of the object"}; + Configurable paramFileName{"paramFileName", "", "Path to the parametrization object. If empty the parametrization is not taken from file"}; + Configurable parametrizationPath{"parametrizationPath", "TOF/Calib/Params", "Path of the TOF parametrization on the CCDB or in the file, if the paramFileName is not empty"}; + Configurable passName{"passName", "", "Name of the pass inside of the CCDB parameter collection. If empty, the automatically deceted from metadata (to be implemented!!!)"}; + Configurable timeShiftCCDBPath{"timeShiftCCDBPath", "", "Path of the TOF time shift vs eta. If empty none is taken"}; + Configurable loadResponseFromCCDB{"loadResponseFromCCDB", false, "Flag to load the response from the CCDB"}; + Configurable fatalOnPassNotAvailable{"fatalOnPassNotAvailable", true, "Flag to throw a fatal if the pass is not available in the retrieved CCDB object"}; + + o2::aod::pidtofgeneric::TofPidNewCollision bachelorTOFPID; + o2::pid::tof::TOFResoParamsV2 mRespParamsV2; + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + + // Initial TOF PID Paras, copied from PIDTOF.h + timestamp.value = bc.timestamp(); + ccdb->setTimestamp(timestamp.value); + // Not later than now objects + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + // TODO: implement the automatic pass name detection from metadata + if (passName.value == "") { + passName.value = "unanchored"; // temporary default + LOG(warning) << "Passed autodetect mode for pass, not implemented yet, waiting for metadata. Taking '" << passName.value << "'"; + } + LOG(info) << "Using parameter collection, starting from pass '" << passName.value << "'"; + + const std::string fname = paramFileName.value; + if (!fname.empty()) { // Loading the parametrization from file + LOG(info) << "Loading exp. sigma parametrization from file " << fname << ", using param: " << parametrizationPath.value; + if (1) { + o2::tof::ParameterCollection paramCollection; + paramCollection.loadParamFromFile(fname, parametrizationPath.value); + LOG(info) << "+++ Loaded parameter collection from file +++"; + if (!paramCollection.retrieveParameters(mRespParamsV2, passName.value)) { + if (fatalOnPassNotAvailable) { + LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + } else { + LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + } + } else { + mRespParamsV2.setShiftParameters(paramCollection.getPars(passName.value)); + mRespParamsV2.printShiftParameters(); + } + } else { + mRespParamsV2.loadParamFromFile(fname.data(), parametrizationPath.value); + } + } else if (loadResponseFromCCDB) { // Loading it from CCDB + LOG(info) << "Loading exp. sigma parametrization from CCDB, using path: " << parametrizationPath.value << " for timestamp " << timestamp.value; + o2::tof::ParameterCollection* paramCollection = ccdb->getForTimeStamp(parametrizationPath.value, timestamp.value); + paramCollection->print(); + if (!paramCollection->retrieveParameters(mRespParamsV2, passName.value)) { // Attempt at loading the parameters with the pass defined + if (fatalOnPassNotAvailable) { + LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + } else { + LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", passName.value.data()); + } + } else { // Pass is available, load non standard parameters + mRespParamsV2.setShiftParameters(paramCollection->getPars(passName.value)); + mRespParamsV2.printShiftParameters(); + } + } + mRespParamsV2.print(); + if (timeShiftCCDBPath.value != "") { + if (timeShiftCCDBPath.value.find(".root") != std::string::npos) { + mRespParamsV2.setTimeShiftParameters(timeShiftCCDBPath.value, "gmean_Pos", true); + mRespParamsV2.setTimeShiftParameters(timeShiftCCDBPath.value, "gmean_Neg", false); + } else { + mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/pos", timeShiftCCDBPath.value.c_str()), timestamp.value), true); + mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/neg", timeShiftCCDBPath.value.c_str()), timestamp.value), false); + } + } + + bachelorTOFPID.SetParams(mRespParamsV2); + } + + struct Indexdaughters { // check duplicated paired daughters + int64_t index0; + int64_t index1; + int64_t index2; + bool operator==(const Indexdaughters& t) const + { + return (this->index0 == t.index0 && this->index1 == t.index1 && this->index2 == t.index2); + } + }; + + void process(ColwithEvTimes const& collisions, MCLabeledTracksIU const& tracks, aod::McParticles const& /*particlesMC*/, aod::McCollisions const& /*mcCollisions*/, aod::BCsWithTimestamps const&) + { + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + + registry.fill(HIST("hEventCounter"), 0.5); + if (mc_event_selection && (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder))) { + continue; + } + registry.fill(HIST("hEventCounter"), 1.5); + if (event_posZ_selection && std::abs(collision.posZ()) > 10.f) { // 10cm + continue; + } + registry.fill(HIST("hEventCounter"), 2.5); + + std::vector protons, pions, deuterons; // index for daughter tracks + std::unordered_set set_proton, set_pion, set_deuteron; // check duplicated daughters + int itrack = -1; + + auto coltracks = tracks.sliceBy(perCollisionTracks, collision.globalIndex()); + + for (const auto& track : coltracks) { + + ++itrack; + registry.fill(HIST("hParticleCounter"), 0.5); + registry.fill(HIST("hTrackITSNcls"), track.itsNCls()); + registry.fill(HIST("hTPCNCls"), track.tpcNClsFound()); + registry.fill(HIST("hTPCNClsCrossedRows"), track.tpcNClsCrossedRows()); + registry.fill(HIST("hTrackNsigmaDeuteron"), track.tpcNSigmaDe()); + registry.fill(HIST("hTrackNsigmaProton"), track.tpcNSigmaPr()); + registry.fill(HIST("hTrackNsigmaPion"), track.tpcNSigmaPi()); + + if (!track.has_mcParticle()) { + continue; + } + auto mcparticle = track.mcParticle_as(); + registry.fill(HIST("hTPCBB"), track.p() * track.sign(), track.tpcSignal()); + + registry.fill(HIST("hParticleCounter"), 1.5); + + // if (TMath::Abs(mcparticle.y()) > 0.9) {continue;} + registry.fill(HIST("hParticleCounter"), 2.5); + registry.fill(HIST("hTrackEta"), track.eta()); + registry.fill(HIST("hTrackMcRapidity"), mcparticle.y()); + + // Hypertriton detected directly + if (mcparticle.pdgCode() == 1010010030 || mcparticle.pdgCode() == -1010010030) { + registry.fill(HIST("hParticleCounter"), 3.5); + registry.fill(HIST("hHypertritonMcPt"), mcparticle.pt()); + registry.fill(HIST("hHypertritonEta"), track.eta()); + registry.fill(HIST("hHypertritonMcRapidity"), mcparticle.y()); + } + + // Proton + if (mcparticle.pdgCode() == 2212 || mcparticle.pdgCode() == -2212) { + registry.fill(HIST("hParticleCounter"), 4.5); + if (track.tpcNClsFound() > 70) { + registry.fill(HIST("hProtonTPCBBAfterTPCNclsCut"), track.p() * track.sign(), track.tpcSignal()); + } + + if (mcparticle.has_mothers()) { + registry.fill(HIST("hProtonCounter"), 0.5); + for (const auto& particleMother : mcparticle.mothers_as()) { + bool flag_H3L = is3bodyDecayedH3L(particleMother); + if (!flag_H3L) { + continue; + } + protons.push_back(itrack); + auto p = set_proton.insert(mcparticle.globalIndex()); + if (p.second == false) + registry.fill(HIST("hDuplicatedH3LDaughers"), 0); + registry.fill(HIST("hProtonCounter"), 1.5); + registry.fill(HIST("hDauProtonPt"), track.pt()); + registry.fill(HIST("hDauProtonMcPt"), mcparticle.pt()); + registry.fill(HIST("hDauProtonNsigmaProton"), track.tpcNSigmaPr()); + registry.fill(HIST("hDauProtonTPCVsPt"), track.pt(), track.tpcNSigmaPr()); + } + } + + registry.fill(HIST("hProtonMcPt"), mcparticle.pt()); + registry.fill(HIST("hProtonMcP"), mcparticle.p()); + registry.fill(HIST("hProtonPt"), track.pt()); + registry.fill(HIST("hProtonP"), track.p()); + + registry.fill(HIST("hProtonNsigmaProton"), track.tpcNSigmaPr()); + registry.fill(HIST("hProtonTPCNCls"), track.tpcNClsFound()); + registry.fill(HIST("hProtonEta"), track.eta()); + registry.fill(HIST("hProtonMcRapidity"), mcparticle.y()); + registry.fill(HIST("hProtonTPCBB"), track.p() * track.sign(), track.tpcSignal()); + } + + // Pion + if (mcparticle.pdgCode() == 211 || mcparticle.pdgCode() == -211) { + registry.fill(HIST("hParticleCounter"), 5.5); + if (track.tpcNClsFound() > 70) { + registry.fill(HIST("hPionTPCBBAfterTPCNclsCut"), track.p() * track.sign(), track.tpcSignal()); + } + + if (mcparticle.has_mothers()) { + registry.fill(HIST("hPionCounter"), 0.5); + for (const auto& particleMother : mcparticle.mothers_as()) { + bool flag_H3L = is3bodyDecayedH3L(particleMother); + if (!flag_H3L) { + continue; + } + pions.push_back(itrack); + auto p = set_pion.insert(mcparticle.globalIndex()); + if (p.second == false) { + registry.fill(HIST("hDuplicatedH3LDaughers"), 1); + } + registry.fill(HIST("hPionCounter"), 1.5); + registry.fill(HIST("hDauPionPt"), track.pt()); + registry.fill(HIST("hDauPionMcPt"), mcparticle.pt()); + registry.fill(HIST("hDauPionTPCVsPt"), track.pt(), track.tpcNSigmaPi()); + registry.fill(HIST("hDauPionDcaXY"), track.dcaXY()); + } + } + + registry.fill(HIST("hPionMcPt"), mcparticle.pt()); + registry.fill(HIST("hPionMcP"), mcparticle.p()); + registry.fill(HIST("hPionPt"), track.pt()); + registry.fill(HIST("hPionP"), track.p()); + + registry.fill(HIST("hPionNsigmaPion"), track.tpcNSigmaPi()); + registry.fill(HIST("hPionTPCNCls"), track.tpcNClsFound()); + registry.fill(HIST("hPionEta"), track.eta()); + registry.fill(HIST("hPionMcRapidity"), mcparticle.y()); + registry.fill(HIST("hPionTPCBB"), track.p() * track.sign(), track.tpcSignal()); + } + + float tofNsigmaDe = -999; + static constexpr float kCSPEED = TMath::C() * 1.0e2f * 1.0e-12f; // c in cm/ps + + if (track.hasTOF() && track.has_collision()) { + auto responseDe = o2::pid::tof::ExpTimes(); + // float bachExpTime = track.length() * sqrt((o2::constants::physics::MassDeuteron * o2::constants::physics::MassDeuteron) + (track.tofExpMom() * track.tofExpMom())) / (kCSPEED * track.tofExpMom()); // L*E/(p*c) = L/v + + float mMassHyp = o2::track::pid_constants::sMasses2Z[track.pidForTracking()]; + float bachExpTime = track.length() * std::sqrt((mMassHyp * mMassHyp) + (track.tofExpMom() * track.tofExpMom())) / (kCSPEED * track.tofExpMom()); // L*E/(p*c) = L/v + float tofsignal = track.trackTime() * 1000 + bachExpTime; // in ps + + float expSigma = responseDe.GetExpectedSigma(mRespParamsV2, track, tofsignal, track.tofEvTimeErr()); + // tofNsigmaDe = (track.tofSignal() - track.tofEvTime() - responseDe.GetCorrectedExpectedSignal(mRespParamsV2, track)) / expSigma; + tofNsigmaDe = (tofsignal - track.tofEvTime() - responseDe.GetCorrectedExpectedSignal(mRespParamsV2, track)) / expSigma; + // tofNsigmaDe = (tofsignal - track.evTimeForTrack() - responseDe.GetCorrectedExpectedSignal(mRespParamsV2, track)) / expSigma; + + if (collision.bcId() == collision.foundBCId()) { + registry.fill(HIST("hDiffColTime"), track.tofEvTime() - collision.collisionTime()); + } + + // Assume deuterons linked to the correct collision, result of new TOF PID should be same as the default one + registry.fill(HIST("hDiffTrackTOFSignal"), track.tofSignal() - tofsignal); + registry.fill(HIST("hDiffEvTimeForTrack"), track.tofEvTime() - track.evTimeForTrack()); + registry.fill(HIST("hDiffTrackTOFNSigmaDe"), track.tofNSigmaDe() - bachelorTOFPID.GetTOFNSigma(o2::track::PID::Deuteron, track, collision, collision)); + // registry.fill(HIST("hDiffTrackTOFNSigmaDe"), track.tofExpSigmaDe() - bachelorTOFPID.GetTOFNSigma(o2::track::PID::Deuteron, track, collision, collision)); + } + + // Deuteron + if (mcparticle.pdgCode() == 1000010020 || mcparticle.pdgCode() == -1000010020) { + registry.fill(HIST("hParticleCounter"), 6.5); + if (track.tpcNClsFound() > 70) { + registry.fill(HIST("hDeuteronTPCBBAfterTPCNclsCut"), track.p() * track.sign(), track.tpcSignal()); + } + + if (mcparticle.has_mothers()) { + registry.fill(HIST("hDeuteronCounter"), 0.5); + for (const auto& particleMother : mcparticle.mothers_as()) { + bool flag_H3L = is3bodyDecayedH3L(particleMother); + if (!flag_H3L) { + continue; + } + deuterons.push_back(itrack); + auto p = set_deuteron.insert(mcparticle.globalIndex()); + if (p.second == false) + registry.fill(HIST("hDuplicatedH3LDaughers"), 2); + registry.fill(HIST("hDeuteronCounter"), 1.5); + registry.fill(HIST("hDauDeuteronPt"), track.pt()); + registry.fill(HIST("hDauDeuteronMcPt"), mcparticle.pt()); + registry.fill(HIST("hDauDeuteronTPCVsPt"), track.pt(), track.tpcNSigmaDe()); + registry.fill(HIST("hDauDeuteronTOFNSigmaVsP"), track.sign() * track.p(), track.tofNSigmaDe()); + + registry.fill(HIST("hDauDeuteronNewTOFNSigmaVsP"), track.sign() * track.p(), tofNsigmaDe); + if (track.hasTOF()) { + registry.fill(HIST("hDauDeuteronTOFNSigmaVsPHasTOF"), track.sign() * track.p(), track.tofNSigmaDe()); + registry.fill(HIST("hDauDeuteronDiffTOFNsigmaDeHasTOF"), track.tofNSigmaDe() - tofNsigmaDe); + } + registry.fill(HIST("hDauDeuteronMatchCounter"), 0.5); + if (mcparticle.mcCollisionId() == collision.mcCollisionId()) { + registry.fill(HIST("hDauDeuteronMatchCounter"), 1.5); + } + if (track.hasTOF()) { + registry.fill(HIST("hDauDeuteronMatchCounter"), 2.5); + if (mcparticle.mcCollisionId() == collision.mcCollisionId()) { + registry.fill(HIST("hDauDeuteronMatchCounter"), 3.5); + } + } + } + } + + registry.fill(HIST("hDeuteronMcPt"), mcparticle.pt()); + registry.fill(HIST("hDeuteronMcP"), mcparticle.p()); + registry.fill(HIST("hDeuteronPt"), track.pt()); + registry.fill(HIST("hDeuteronP"), track.p()); + + registry.fill(HIST("hDeuteronNsigmaDeuteron"), track.tpcNSigmaDe()); + registry.fill(HIST("hDeuteronTPCNCls"), track.tpcNClsFound()); + registry.fill(HIST("hDeuteronEta"), track.eta()); + registry.fill(HIST("hDeuteronMcRapidity"), mcparticle.y()); + registry.fill(HIST("hDeuteronTPCBB"), track.p() * track.sign(), track.tpcSignal()); + } else { + if (track.hasTOF()) { + registry.fill(HIST("hWrongDeuteronTOFNSigmaVsP"), track.sign() * track.p(), track.tofNSigmaDe()); + registry.fill(HIST("hWrongDeuteronNewTOFNSigmaVsP"), track.sign() * track.p(), tofNsigmaDe); + } + } + } + + std::vector set_pair; + for (size_t iproton = 0; iproton < protons.size(); iproton++) { + auto track0 = tracks.iteratorAt(protons[iproton]); + auto mctrack0 = track0.mcParticle_as(); + for (size_t ipion = 0; ipion < pions.size(); ipion++) { + auto track1 = tracks.iteratorAt(pions[ipion]); + auto mctrack1 = track1.mcParticle_as(); + for (size_t ideuteron = 0; ideuteron < deuterons.size(); ideuteron++) { + auto track2 = tracks.iteratorAt(deuterons[ideuteron]); + auto mctrack2 = track2.mcParticle_as(); + if (isPairedH3LDaughters(mctrack0, mctrack1, mctrack2)) { + registry.fill(HIST("hPairedH3LDaughers"), 0); + // MC mass cut, to check if the daughters are from materials + double hypertritonMCMass = RecoDecay::m(std::array{std::array{mctrack0.px(), mctrack0.py(), mctrack0.pz()}, std::array{mctrack1.px(), mctrack1.py(), mctrack1.pz()}, std::array{mctrack2.px(), mctrack2.py(), mctrack2.pz()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); + registry.fill(HIST("hPairedH3LDaughersInvMass"), hypertritonMCMass); + if (hypertritonMCMass < 2.990 || hypertritonMCMass > 2.993) + continue; + registry.fill(HIST("hPairedH3LDaughers"), 1); + // duplicated daughters check + Indexdaughters temp = {mctrack0.globalIndex(), mctrack1.globalIndex(), mctrack2.globalIndex()}; + auto p = std::find(set_pair.begin(), set_pair.end(), temp); + if (p == set_pair.end()) { + set_pair.push_back(temp); + registry.fill(HIST("hPairedH3LDaughers"), 2); + } + } + } + } + } + } + + // Check for recalculated TOF PID for secondary deuterons + + std::vector SelectedEvents(collisions.size()); + int nevts = 0; + for (const auto& collision : collisions) { + SelectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); + } + + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + continue; + } + auto mcparticle = track.mcParticle_as(); + if (mcparticle.pdgCode() == 1000010020 || mcparticle.pdgCode() == -1000010020) { + if (!mcparticle.has_mothers()) { + continue; + } + const auto evtReconstructed = std::find(SelectedEvents.begin(), SelectedEvents.end(), mcparticle.mcCollision_as().globalIndex()); + if (evtReconstructed == SelectedEvents.end() || !track.has_collision()) { + continue; + } + if (!track.has_collision()) { + continue; + } + auto collision = collisions.iteratorAt(evtReconstructed - SelectedEvents.begin()); + auto originalcollision = track.collision_as(); + + for (const auto& particleMother : mcparticle.mothers_as()) { + bool flag_H3L = is3bodyDecayedH3L(particleMother); + if (!flag_H3L) { + continue; + } + + auto bc = collision.bc_as(); + initCCDB(bc); + float tofNsigmaDeAO2D = -999; + float tofNsigmaDeEvSel = -999; + + if (track.hasTOF()) { + /*auto responseDe = o2::pid::tof::ExpTimes(); + //float bachExpTime = track.length() * sqrt((o2::constants::physics::MassDeuteron * o2::constants::physics::MassDeuteron) + (track.tofExpMom() * track.tofExpMom())) / (kCSPEED * track.tofExpMom()); // L*E/(p*c) = L/v + float mMassHyp = o2::track::pid_constants::sMasses2Z[track.pidForTracking()]; + float bachExpTime = track.length() * std::sqrt((mMassHyp * mMassHyp) + (track.tofExpMom() * track.tofExpMom())) / (kCSPEED * track.tofExpMom()); // L*E/(p*c) = L/v + */ + + tofNsigmaDeAO2D = bachelorTOFPID.GetTOFNSigma(o2::track::PID::Deuteron, track, originalcollision, collision); + tofNsigmaDeEvSel = bachelorTOFPID.GetTOFNSigma(o2::track::PID::Deuteron, track, originalcollision, collision, false); + + if (collision.globalIndex() == originalcollision.globalIndex()) { + registry.fill(HIST("hDauDeuteronTOFNSigmaVsP_CorrectCol"), track.sign() * track.p(), track.tofNSigmaDe()); + registry.fill(HIST("hDauDeuteronNewTOFNSigmaVsP_CorrectCol"), track.sign() * track.p(), tofNsigmaDeAO2D); + continue; + } + + /*if (originalcollision.collisionTimeRes() > 40){ + continue; + }*/ + registry.fill(HIST("hDauDeuteronTOFNSigmaVsP_v2"), track.sign() * track.p(), track.tofNSigmaDe()); + registry.fill(HIST("hDauDeuteronNewTOFNSigmaVsP_v2_AO2D"), track.sign() * track.p(), tofNsigmaDeAO2D); + registry.fill(HIST("hDauDeuteronNewTOFNSigmaVsP_v2_EvSel"), track.sign() * track.p(), tofNsigmaDeEvSel); + registry.fill(HIST("hDauDeuteronTOFNSigmaVsColTimeRes_v2"), collision.collisionTimeRes(), track.tofNSigmaDe()); + registry.fill(HIST("hDauDeuteronTOFNSigmaVsColTimeRes_v2_AO2D"), originalcollision.collisionTimeRes(), tofNsigmaDeAO2D); + registry.fill(HIST("hDauDeuteronTOFNSigmaVsColTimeRes_v2_EvSel"), originalcollision.collisionTimeRes(), tofNsigmaDeEvSel); + + if (std::abs(track.tofNSigmaDe()) >= 5) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter"), 0.5); + if (std::abs(tofNsigmaDeAO2D) < 5 && std::abs(tofNsigmaDeEvSel) < 5) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter"), 1.5); + } else if (std::abs(tofNsigmaDeAO2D) < 5 && std::abs(tofNsigmaDeEvSel) >= 5) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter"), 2.5); + } else if (std::abs(tofNsigmaDeAO2D) >= 5 && std::abs(tofNsigmaDeEvSel) < 5) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter"), 3.5); + } else if (std::abs(tofNsigmaDeAO2D) >= 5 && std::abs(tofNsigmaDeEvSel) >= 5) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter"), 4.5); + } + } else if (std::abs(track.tofNSigmaDe()) < 5) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter_CloseBC"), 0.5); + if (std::abs(tofNsigmaDeAO2D) < 5 && std::abs(tofNsigmaDeEvSel) < 5) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter_CloseBC"), 1.5); + } else if (std::abs(tofNsigmaDeAO2D) < 5 && std::abs(tofNsigmaDeEvSel) >= 5) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter_CloseBC"), 2.5); + } else if (std::abs(tofNsigmaDeAO2D) >= 5 && std::abs(tofNsigmaDeEvSel) < 5) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter_CloseBC"), 3.5); + } else if (std::abs(tofNsigmaDeAO2D) >= 5 && std::abs(tofNsigmaDeEvSel) >= 5) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter_CloseBC"), 4.5); + } + } + } + } + } + } + } +}; + +// check the performance of mcparticle +struct Hypertriton3bodyMcParticleCheck { + // Basic checks + HistogramRegistry registry{ + "registry", + { + {"hMcCollCounter", "hMcCollCounter", {HistType::kTH1F, {{2, 0.0f, 2.0f}}}}, + + {"h3dMCDecayedHypertriton", "h3dMCDecayedHypertriton", {HistType::kTH3F, {{20, -1.0f, 1.0f, "Rapidity"}, {200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}, {50, 0.0f, 50.0f, "ct(cm)"}}}}, + + {"hMcHypertritonCounter", "hMcHypertritonCounter", {HistType::kTH1F, {{9, 0.0f, 9.0f}}}}, + {"hMcHypertritonPt", "hMcHypertritonPt", {HistType::kTH1F, {{300, 0.0f, 15.0f}}}}, + {"hMcProtonPt", "hMcProtonPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hMcPionPt", "hMcPionPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hMcDeuteronPt", "hMcDeuteronPt", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + + {"hMcRecoInvMass", "hMcRecoInvMass", {HistType::kTH1F, {{100, 2.95, 3.05f}}}}, + + {"hDiffDaughterR", "hDiffDaughterR", {HistType::kTH1F, {{10000, -100, 100}}}}, // difference between minR of pion&proton and R of deuteron(bachelor) + {"hTrackX", "hTrackX", {HistType::kTH1F, {{10000, -100, 100}}}}, + {"hTrackY", "hTrackY", {HistType::kTH1F, {{10000, -100, 100}}}}, + {"hTrackZ", "hTrackZ", {HistType::kTH1F, {{10000, -100, 100}}}}, + }, + }; + + o2::pid::tof::TOFResoParamsV2 mRespParamsV2; + + void init(InitContext&) + { + registry.get(HIST("hMcCollCounter"))->GetXaxis()->SetBinLabel(1, "Total Counter"); + registry.get(HIST("hMcCollCounter"))->GetXaxis()->SetBinLabel(2, "Reconstructed"); + + registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(1, "Hypertriton All"); + registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(2, "Matter All"); + registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(3, "AntiMatter All"); + registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(4, "confirm to 3-body decay"); + registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(5, "Matter"); + registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(6, "AntiMatter"); + registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(7, "Rapidity"); + registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(8, "Lifetime"); + registry.get(HIST("hMcHypertritonCounter"))->GetXaxis()->SetBinLabel(9, "PtCut"); + } + + Configurable mc_event_selection{"mc_event_selection", true, "mc event selection count post kIsTriggerTVX and kNoTimeFrameBorder"}; + Configurable event_posZ_selection{"event_posZ_selection", true, "event selection count post poZ cut"}; + + Preslice permcCollision = o2::aod::mcparticle::mcCollisionId; + + std::vector mcPartIndices; + template + void SetTrackIDForMC(aod::McParticles const& particlesMC, TTrackTable const& tracks) + { + mcPartIndices.clear(); + mcPartIndices.resize(particlesMC.size()); + std::fill(mcPartIndices.begin(), mcPartIndices.end(), -1); + for (const auto& track : tracks) { + if (track.has_mcParticle()) { + auto mcparticle = track.template mcParticle_as(); + if (mcPartIndices[mcparticle.globalIndex()] == -1) { + mcPartIndices[mcparticle.globalIndex()] = track.globalIndex(); + } else { + auto candTrack = tracks.rawIteratorAt(mcPartIndices[mcparticle.globalIndex()]); + // Use the track which has innest information (also best quality? + if (track.x() < candTrack.x()) { + mcPartIndices[mcparticle.globalIndex()] = track.globalIndex(); + } + } + + // Checks for TrackR + registry.fill(HIST("hTrackX"), track.x()); + registry.fill(HIST("hTrackY"), track.y()); + registry.fill(HIST("hTrackZ"), track.z()); + } + } + } + + void process(aod::McCollisions const& mcCollisions, aod::McParticles const& particlesMC, const o2::soa::Join& collisions, MCLabeledTracksIU const& tracks) + { + SetTrackIDForMC(particlesMC, tracks); + std::vector SelectedEvents(collisions.size()); + int nevts = 0; + for (const auto& collision : collisions) { + if (mc_event_selection && (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder))) { + continue; + } + if (event_posZ_selection && std::abs(collision.posZ()) > 10.f) { // 10cm + continue; + } + SelectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); + } + SelectedEvents.resize(nevts); + + for (const auto& mcCollision : mcCollisions) { + registry.fill(HIST("hMcCollCounter"), 0.5); + const auto evtReconstructedAndSelected = std::find(SelectedEvents.begin(), SelectedEvents.end(), mcCollision.globalIndex()) != SelectedEvents.end(); + if (!evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection + continue; + } + registry.fill(HIST("hMcCollCounter"), 1.5); + + const auto& dparticlesMC = particlesMC.sliceBy(permcCollision, mcCollision.globalIndex()); + + for (const auto& mcparticle : dparticlesMC) { + + if (mcparticle.pdgCode() == 2212 || mcparticle.pdgCode() == -2212) { + registry.fill(HIST("hMcProtonPt"), mcparticle.pt()); + } + if (mcparticle.pdgCode() == 211 || mcparticle.pdgCode() == -211) { + registry.fill(HIST("hMcPionPt"), mcparticle.pt()); + } + if (mcparticle.pdgCode() == 1000010020 || mcparticle.pdgCode() == -1000010020) { + registry.fill(HIST("hMcDeuteronPt"), mcparticle.pt()); + } + if (mcparticle.pdgCode() == 1010010030) { + registry.fill(HIST("hMcHypertritonCounter"), 1.5); + } else if (mcparticle.pdgCode() == -1010010030) { + registry.fill(HIST("hMcHypertritonCounter"), 2.5); + } + if (mcparticle.pdgCode() == 1010010030 || mcparticle.pdgCode() == -1010010030) { + registry.fill(HIST("hMcHypertritonCounter"), 0.5); + registry.fill(HIST("hMcHypertritonPt"), mcparticle.pt()); + + double dauDeuteronPos[3] = {-999, -999, -999}; + double dauProtonMom[3] = {-999, -999, -999}; + double dauPionMom[3] = {-999, -999, -999}; + double dauDeuteronMom[3] = {-999, -999, -999}; + double MClifetime = 999; + double dauProtonTrackR = 9999, dauPionTrackR = 99999, dauDeuteronTrackR = 999999; + bool flag_H3L = is3bodyDecayedH3L(mcparticle); + if (!flag_H3L) { + continue; + } + for (const auto& mcparticleDaughter : mcparticle.daughters_as()) { + if (std::abs(mcparticleDaughter.pdgCode()) == 2212) { + dauProtonMom[0] = mcparticleDaughter.px(); + dauProtonMom[1] = mcparticleDaughter.py(); + dauProtonMom[2] = mcparticleDaughter.pz(); + if (mcPartIndices[mcparticleDaughter.globalIndex()] != -1) { + auto trackProton = tracks.rawIteratorAt(mcPartIndices[mcparticleDaughter.globalIndex()]); + dauProtonTrackR = trackProton.x(); + } + } + if (std::abs(mcparticleDaughter.pdgCode()) == 211) { + dauPionMom[0] = mcparticleDaughter.px(); + dauPionMom[1] = mcparticleDaughter.py(); + dauPionMom[2] = mcparticleDaughter.pz(); + if (mcPartIndices[mcparticleDaughter.globalIndex()] != -1) { + auto trackPion = tracks.rawIteratorAt(mcPartIndices[mcparticleDaughter.globalIndex()]); + dauPionTrackR = trackPion.x(); + } + } + if (std::abs(mcparticleDaughter.pdgCode()) == 1000010020) { + dauDeuteronPos[0] = mcparticleDaughter.vx(); + dauDeuteronPos[1] = mcparticleDaughter.vy(); + dauDeuteronPos[2] = mcparticleDaughter.vz(); + dauDeuteronMom[0] = mcparticleDaughter.px(); + dauDeuteronMom[1] = mcparticleDaughter.py(); + dauDeuteronMom[2] = mcparticleDaughter.pz(); + if (mcPartIndices[mcparticleDaughter.globalIndex()] != -1) { + auto trackDeuteron = tracks.rawIteratorAt(mcPartIndices[mcparticleDaughter.globalIndex()]); + dauDeuteronTrackR = trackDeuteron.x(); + } + } + } + if (mcparticle.pdgCode() == 1010010030) { + registry.fill(HIST("hMcHypertritonCounter"), 3.5); + registry.fill(HIST("hMcHypertritonCounter"), 4.5); + } + if (mcparticle.pdgCode() == -1010010030) { + registry.fill(HIST("hMcHypertritonCounter"), 3.5); + registry.fill(HIST("hMcHypertritonCounter"), 5.5); + } + double hypertritonMCMass = RecoDecay::m(std::array{std::array{dauProtonMom[0], dauProtonMom[1], dauProtonMom[2]}, std::array{dauPionMom[0], dauPionMom[1], dauPionMom[2]}, std::array{dauDeuteronMom[0], dauDeuteronMom[1], dauDeuteronMom[2]}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); + registry.fill(HIST("hMcRecoInvMass"), hypertritonMCMass); + + if (hypertritonMCMass > 2.990 && hypertritonMCMass < 2.993) { + MClifetime = RecoDecay::sqrtSumOfSquares(dauDeuteronPos[0] - mcparticle.vx(), dauDeuteronPos[1] - mcparticle.vy(), dauDeuteronPos[2] - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); + registry.fill(HIST("h3dMCDecayedHypertriton"), mcparticle.y(), mcparticle.pt(), MClifetime); + + double diffTrackR = dauDeuteronTrackR - std::min(dauPionTrackR, dauProtonTrackR); + registry.fill(HIST("hDiffDaughterR"), diffTrackR); + + // int daughterPionCount = 0; + // for (auto& mcparticleDaughter : mcparticle.daughters_as()) { + // if (std::abs(mcparticleDaughter.pdgCode()) == 211) { + // daughterPionCount++; + // } + // } + + // Counter for hypertriton N_gen + if (std::abs(mcparticle.y()) < 1) { + registry.fill(HIST("hMcHypertritonCounter"), 6.5); + if (MClifetime < 40) { + registry.fill(HIST("hMcHypertritonCounter"), 7.5); + if (mcparticle.pt() > 1 && mcparticle.pt() < 10) { + registry.fill(HIST("hMcHypertritonCounter"), 8.5); + } + } + } + } + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGLF/Tasks/Nuspex/hypertriton3bodyanalysis.cxx b/PWGLF/Tasks/Nuspex/hypertriton3bodyanalysis.cxx index 33e79f68fa2..b8aeb1d34c3 100644 --- a/PWGLF/Tasks/Nuspex/hypertriton3bodyanalysis.cxx +++ b/PWGLF/Tasks/Nuspex/hypertriton3bodyanalysis.cxx @@ -9,20 +9,15 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // -// StoredVtx3BodyDatas analysis task -// ======================== -// -// This code loops over a StoredVtx3BodyDatas table and produces some -// standard analysis output. It requires either -// the hypertriton3bodybuilder or hypertriton3bodyfinder (not recommended) tasks -// to have been executed in the workflow (before). -// -// author: yuanzhe.wang@cern.ch -// +/// \file hypertriton3bodyanalysis.cxx +/// \brief Standard analysis workflow for hypertriton 3-body decay +/// \author Yuanzhe Wang #include #include #include +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -31,7 +26,7 @@ #include "ReconstructionDataFormats/Track.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" +// #include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGLF/DataModel/Vtx3BodyTables.h" #include "Common/Core/TrackSelection.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -43,9 +38,9 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -using std::array; -using FullTracksExtIU = soa::Join; +using FullTracksExtIU = soa::Join; +// using FullTracksExtIU = soa::Join; // For TOF PID check using MCLabeledTracksIU = soa::Join; struct hypertriton3bodyQa { @@ -61,6 +56,9 @@ struct hypertriton3bodyQa { {"hPtAntiProton", "hPtAntiProton", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, {"hPtPionPlus", "hPtPionPlus", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, {"hPtAntiDeuteron", "hPtAntiDeuteron", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, + {"hDCAXYProtonToPV", "hDCAXYProtonToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, + {"hDCAXYPionToPV", "hDCAXYPionToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, + {"hDCAXYDeuteronToPV", "hDCAXYDeuteronToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, {"hDCAProtonToPV", "hDCAProtonToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, {"hDCAPionToPV", "hDCAPionToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, {"hDCADeuteronToPV", "hDCADeuteronToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, @@ -74,15 +72,22 @@ struct hypertriton3bodyQa { {"hDeuTOFNsigmaWithTPC", "Deuteron TOF Nsigma distribution", {HistType::kTH2F, {{1200, -6, 6, "#it{p} (GeV/#it{c})"}, {1000, -100, 100, "TOF n#sigma"}}}}, }, }; + void init(InitContext const&) { AxisSpec massAxis = {120, 2.9f, 3.2f, "Inv. Mass (GeV/c^{2})"}; registry.add("hMassHypertriton", "hMassHypertriton", {HistType::kTH1F, {massAxis}}); registry.add("hMassAntiHypertriton", "hMassAntiHypertriton", {HistType::kTH1F, {massAxis}}); + // Check for selection criteria + registry.add("hDiffRVtxProton", "hDiffRVtxProton", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of proton + registry.add("hDiffRVtxPion", "hDiffRVtxPion", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of pion + registry.add("hDiffRVtxDeuteron", "hDiffRVtxDeuteron", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of deuteron + registry.add("hDiffDaughterR", "hDiffDaughterR", HistType::kTH1F, {{10000, -100, 100}}); // difference between minR of pion&proton and R of deuteron(bachelor) } + void process(aod::Collision const& collision, aod::Vtx3BodyDatas const& vtx3bodydatas, FullTracksExtIU const& /*tracks*/) { - for (auto& vtx : vtx3bodydatas) { + for (const auto& vtx : vtx3bodydatas) { auto track0 = vtx.track0_as(); auto track1 = vtx.track1_as(); auto track2 = vtx.track2_as(); @@ -93,46 +98,61 @@ struct hypertriton3bodyQa { registry.fill(HIST("hVtxPt"), vtx.pt()); registry.fill(HIST("hMassHypertriton"), vtx.mHypertriton()); registry.fill(HIST("hMassAntiHypertriton"), vtx.mAntiHypertriton()); - registry.fill(HIST("hTOFPIDDeuteron"), track2.tofNSigmaDe()); - registry.fill(HIST("hDeuTOFNsigma"), track2.tpcInnerParam() * track2.sign(), track2.tofNSigmaDe()); if (std::abs(track2.tpcNSigmaDe()) < 5) { - registry.fill(HIST("hDeuTOFNsigmaWithTPC"), track2.tpcInnerParam() * track2.sign(), track2.tofNSigmaDe()); + registry.fill(HIST("hDeuTOFNsigmaWithTPC"), track2.tpcInnerParam() * track2.sign(), vtx.tofNSigmaBachDe()); } if (track2.sign() > 0) { registry.fill(HIST("hPtProton"), track0.pt()); registry.fill(HIST("hPtPionMinus"), track1.pt()); registry.fill(HIST("hPtDeuteron"), track2.pt()); + registry.fill(HIST("hDCAXYProtonToPV"), vtx.dcaXYtrack0topv()); + registry.fill(HIST("hDCAXYPionToPV"), vtx.dcaXYtrack1topv()); registry.fill(HIST("hDCAProtonToPV"), vtx.dcatrack0topv()); registry.fill(HIST("hDCAPionToPV"), vtx.dcatrack1topv()); registry.fill(HIST("hProtonTPCNcls"), track0.tpcNClsCrossedRows()); registry.fill(HIST("hPionTPCNcls"), track1.tpcNClsCrossedRows()); + registry.fill(HIST("hDiffRVtxProton"), track0.x() - vtx.vtxradius()); + registry.fill(HIST("hDiffRVtxPion"), track1.x() - vtx.vtxradius()); } else { registry.fill(HIST("hPtPionPlus"), track0.pt()); registry.fill(HIST("hPtAntiProton"), track1.pt()); registry.fill(HIST("hPtAntiDeuteron"), track2.pt()); + registry.fill(HIST("hDCAXYProtonToPV"), vtx.dcaXYtrack1topv()); + registry.fill(HIST("hDCAXYPionToPV"), vtx.dcaXYtrack0topv()); registry.fill(HIST("hDCAProtonToPV"), vtx.dcatrack1topv()); registry.fill(HIST("hDCAPionToPV"), vtx.dcatrack0topv()); registry.fill(HIST("hProtonTPCNcls"), track1.tpcNClsCrossedRows()); registry.fill(HIST("hPionTPCNcls"), track0.tpcNClsCrossedRows()); + registry.fill(HIST("hDiffRVtxProton"), track1.x() - vtx.vtxradius()); + registry.fill(HIST("hDiffRVtxPion"), track0.x() - vtx.vtxradius()); } + registry.fill(HIST("hDCAXYDeuteronToPV"), vtx.dcaXYtrack2topv()); registry.fill(HIST("hDCADeuteronToPV"), vtx.dcatrack2topv()); registry.fill(HIST("hDeuteronTPCNcls"), track2.tpcNClsCrossedRows()); + registry.fill(HIST("hTOFPIDDeuteron"), vtx.tofNSigmaBachDe()); + registry.fill(HIST("hDeuTOFNsigma"), track2.tpcInnerParam() * track2.sign(), vtx.tofNSigmaBachDe()); + registry.fill(HIST("hDiffRVtxDeuteron"), track2.x() - vtx.vtxradius()); + float diffTrackR = track2.x() - std::min(track0.x(), track1.x()); + registry.fill(HIST("hDiffDaughterR"), diffTrackR); } } }; struct hypertriton3bodyAnalysis { + Preslice perCollisionVtx3BodyDatas = o2::aod::vtx3body::collisionId; + // Selection criteria Configurable vtxcospa{"vtxcospa", 0.99, "Vtx CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0) Configurable dcavtxdau{"dcavtxdau", 1.0, "DCA Vtx Daughters"}; // loose cut Configurable dcapiontopv{"dcapiontopv", .05, "DCA Pion To PV"}; Configurable etacut{"etacut", 0.9, "etacut"}; Configurable rapiditycut{"rapiditycut", 1, "rapiditycut"}; - Configurable TofPidNsigmaMin{"TofPidNsigmaMin", -5, "TofPidNsigmaMin"}; - Configurable TofPidNsigmaMax{"TofPidNsigmaMax", 5, "TofPidNsigmaMax"}; - Configurable TpcPidNsigmaCut{"TpcPidNsigmaCut", 5, "TpcPidNsigmaCut"}; + Configurable tofPIDNSigmaMin{"tofPIDNSigmaMin", -5, "tofPIDNSigmaMin"}; + Configurable tofPIDNSigmaMax{"tofPIDNSigmaMax", 5, "tofPIDNSigmaMax"}; + Configurable tpcPIDNSigmaCut{"tpcPIDNSigmaCut", 5, "tpcPIDNSigmaCut"}; Configurable event_sel8_selection{"event_sel8_selection", true, "event selection count post sel8 cut"}; + Configurable mc_event_selection{"mc_event_selection", true, "mc event selection count post kIsTriggerTVX and kNoTimeFrameBorder"}; Configurable event_posZ_selection{"event_posZ_selection", true, "event selection count post poZ cut"}; Configurable lifetimecut{"lifetimecut", 40., "lifetimecut"}; // ct Configurable minProtonPt{"minProtonPt", 0.3, "minProtonPt"}; @@ -149,6 +169,12 @@ struct hypertriton3bodyAnalysis { Configurable mintpcNClsdeuteron{"mintpcNClsdeuteron", 100, "min tpc Nclusters for deuteron"}; Configurable mcsigma{"mcsigma", 0.0015, "sigma of mc invariant mass fit"}; // obtained from MC + Configurable bachelorPdgCode{"bachelorPdgCode", 1000010020, "pdgCode of bachelor daughter"}; + Configurable motherPdgCode{"motherPdgCode", 1010010030, "pdgCode of mother track"}; + + // 3sigma region for Dalitz plot + float lowersignallimit = o2::constants::physics::MassHyperTriton - 3 * mcsigma; + float uppersignallimit = o2::constants::physics::MassHyperTriton + 3 * mcsigma; HistogramRegistry registry{ "registry", @@ -164,6 +190,9 @@ struct hypertriton3bodyAnalysis { {"hPtAntiProton", "hPtAntiProton", {HistType::kTH1F, {{200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}}}, {"hPtPionPlus", "hPtPionPlus", {HistType::kTH1F, {{200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}}}, {"hPtAntiDeuteron", "hPtAntiDeuteron", {HistType::kTH1F, {{200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}}}, + {"hDCAXYProtonToPV", "hDCAXYProtonToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, + {"hDCAXYPionToPV", "hDCAXYPionToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, + {"hDCAXYDeuteronToPV", "hDCAXYDeuteronToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, {"hDCAProtonToPV", "hDCAProtonToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, {"hDCAPionToPV", "hDCAPionToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, {"hDCADeuteronToPV", "hDCADeuteronToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}}, @@ -183,44 +212,37 @@ struct hypertriton3bodyAnalysis { {"hPionTPCVsPt", "hPionTPCVsPt", {HistType::kTH2F, {{20, 0.0f, 2.0f, "#it{p}_{T} (GeV/c)"}, {120, -6.0f, 6.0f, "TPC n#sigma"}}}}, {"hDeuteronTPCVsPt", "hDeuteronTPCVsPt", {HistType::kTH2F, {{80, 0.0f, 8.0f, "#it{p}_{T} (GeV/c)"}, {120, -6.0f, 6.0f, "TPC n#sigma"}}}}, {"hDeuteronTOFVsPBeforeTOFCut", "hDeuteronTOFVsPBeforeTOFCut", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, - {"hDeuteronTOFVsPAtferTOFCut", "hDeuteronTOFVsPAtferTOFCut", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, + {"hDeuteronTOFVsPAfterTOFCut", "hDeuteronTOFVsPAfterTOFCut", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, {"hDalitz", "hDalitz", {HistType::kTH2F, {{120, 7.85, 8.45, "M^{2}(dp) (GeV^{2}/c^{4})"}, {60, 1.1, 1.4, "M^{2}(p#pi) (GeV^{2}/c^{4})"}}}}, {"h3dMassHypertriton", "h3dMassHypertriton", {HistType::kTH3F, {{20, 0.0f, 100.0f, "Cent (%)"}, {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}, {80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"}}}}, {"h3dMassAntiHypertriton", "h3dMassAntiHypertriton", {HistType::kTH3F, {{20, 0.0f, 100.0f, "Cent (%)"}, {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}, {80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"}}}}, {"h3dTotalHypertriton", "h3dTotalHypertriton", {HistType::kTH3F, {{50, 0, 50, "ct(cm)"}, {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}, {80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"}}}}, - {"hTrueHypertritonCounter", "hTrueHypertritonCounter", {HistType::kTH1F, {{12, 0.0f, 12.0f}}}}, {"hDeuteronTOFVsPBeforeTOFCutSig", "hDeuteronTOFVsPBeforeTOFCutSig", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, - {"hDeuteronTOFVsPAtferTOFCutSig", "hDeuteronTOFVsPAtferTOFCutSig", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, + {"hDeuteronTOFVsPAfterTOFCutSig", "hDeuteronTOFVsPAfterTOFCutSig", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, {"h3dTotalTrueHypertriton", "h3dTotalTrueHypertriton", {HistType::kTH3F, {{50, 0, 50, "ct(cm)"}, {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}, {80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"}}}}, - - // for mcparticles information - {"hGeneratedHypertritonCounter", "hGeneratedHypertritonCounter", {HistType::kTH1F, {{2, 0.0f, 2.0f}}}}, - {"hPtGeneratedHypertriton", "hPtGeneratedHypertriton", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hctGeneratedHypertriton", "hctGeneratedHypertriton", {HistType::kTH1F, {{50, 0, 50, "ct(cm)"}}}}, - {"hEtaGeneratedHypertriton", "hEtaGeneratedHypertriton", {HistType::kTH1F, {{40, -2.0f, 2.0f}}}}, - {"hRapidityGeneratedHypertriton", "hRapidityGeneratedHypertriton", {HistType::kTH1F, {{40, -2.0f, 2.0f}}}}, - {"hPtGeneratedAntiHypertriton", "hPtGeneratedAntiHypertriton", {HistType::kTH1F, {{200, 0.0f, 10.0f}}}}, - {"hctGeneratedAntiHypertriton", "hctGeneratedAntiHypertriton", {HistType::kTH1F, {{50, 0, 50, "ct(cm)"}}}}, - {"hEtaGeneratedAntiHypertriton", "hEtaGeneratedAntiHypertriton", {HistType::kTH1F, {{40, -2.0f, 2.0f}}}}, - {"hRapidityGeneratedAntiHypertriton", "hRapidityGeneratedAntiHypertriton", {HistType::kTH1F, {{40, -2.0f, 2.0f}}}}, + // For TOF PID check + /*{"hDeuteronDefaultTOFVsPBeforeTOFCut", "hDeuteronDefaultTOFVsPBeforeTOFCut", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, + {"hDeuteronDefaultTOFVsPAtferTOFCut", "hDeuteronDefaultTOFVsPAtferTOFCut", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, + {"hDeuteronDefaultTOFVsPBeforeTOFCutSig", "hDeuteronDefaultTOFVsPBeforeTOFCutSig", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, + {"hDeuteronDefaultTOFVsPAfterTOFCutSig", "hDeuteronDefaultTOFVsPAfterTOFCutSig", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}},*/ }, }; //------------------------------------------------------------------ // Fill stats histograms enum vtxstep { kCandAll = 0, - kCandCosPA, kCandDauEta, + kCandDauPt, + kCandTPCNcls, + kCandTPCPID, + kCandTOFPID, + kCandDcaToPV, kCandRapidity, kCandct, + kCandCosPA, kCandDcaDau, - kCandTOFPID, - kCandTPCPID, - kCandTPCNcls, - kCandDauPt, - kCandDcaToPV, kCandInvMass, kNCandSteps }; @@ -231,7 +253,7 @@ struct hypertriton3bodyAnalysis { void resetHistos() { - for (Int_t ii = 0; ii < kNCandSteps; ii++) { + for (int ii = 0; ii < kNCandSteps; ii++) { statisticsRegistry.candstats[ii] = 0; statisticsRegistry.truecandstats[ii] = 0; } @@ -245,9 +267,11 @@ struct hypertriton3bodyAnalysis { } void fillHistos() { - for (Int_t ii = 0; ii < kNCandSteps; ii++) { + for (int ii = 0; ii < kNCandSteps; ii++) { registry.fill(HIST("hCandidatesCounter"), ii, statisticsRegistry.candstats[ii]); - registry.fill(HIST("hTrueHypertritonCounter"), ii, statisticsRegistry.truecandstats[ii]); + if (doprocessMC == true) { + registry.fill(HIST("hTrueHypertritonCounter"), ii, statisticsRegistry.truecandstats[ii]); + } } } @@ -256,150 +280,158 @@ struct hypertriton3bodyAnalysis { void init(InitContext const&) { - /*AxisSpec dcaAxis = {dcaBinning, "DCA (cm)"}; - AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/c)"}; - AxisSpec massAxisHypertriton = {80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"};*/ - registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(1, "total"); registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(2, "sel8"); registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(3, "vertexZ"); registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(4, "has Candidate"); - TString CandCounterbinLabel[12] = {"Total", "VtxCosPA", "TrackEta", "MomRapidity", "Lifetime", "VtxDcaDau", "d TOFPID", "TPCPID", "TPCNcls", "DauPt", "PionDcatoPV", "InvMass"}; + if (doprocessMC == true) { + registry.add("hTrueHypertritonCounter", "hTrueHypertritonCounter", HistType::kTH1F, {{12, 0.0f, 12.0f}}); + auto hGeneratedHypertritonCounter = registry.add("hGeneratedHypertritonCounter", "hGeneratedHypertritonCounter", HistType::kTH1F, {{2, 0.0f, 2.0f}}); + hGeneratedHypertritonCounter->GetXaxis()->SetBinLabel(1, "Total"); + hGeneratedHypertritonCounter->GetXaxis()->SetBinLabel(2, "3-body decay"); + registry.add("hPtGeneratedHypertriton", "hPtGeneratedHypertriton", HistType::kTH1F, {{200, 0.0f, 10.0f}}); + registry.add("hctGeneratedHypertriton", "hctGeneratedHypertriton", HistType::kTH1F, {{50, 0, 50, "ct(cm)"}}); + registry.add("hEtaGeneratedHypertriton", "hEtaGeneratedHypertriton", HistType::kTH1F, {{40, -2.0f, 2.0f}}); + registry.add("hRapidityGeneratedHypertriton", "hRapidityGeneratedHypertriton", HistType::kTH1F, {{40, -2.0f, 2.0f}}); + registry.add("hPtGeneratedAntiHypertriton", "hPtGeneratedAntiHypertriton", HistType::kTH1F, {{200, 0.0f, 10.0f}}); + registry.add("hctGeneratedAntiHypertriton", "hctGeneratedAntiHypertriton", HistType::kTH1F, {{50, 0, 50, "ct(cm)"}}); + registry.add("hEtaGeneratedAntiHypertriton", "hEtaGeneratedAntiHypertriton", HistType::kTH1F, {{40, -2.0f, 2.0f}}); + registry.add("hRapidityGeneratedAntiHypertriton", "hRapidityGeneratedAntiHypertriton", HistType::kTH1F, {{40, -2.0f, 2.0f}}); + } + + TString CandCounterbinLabel[kNCandSteps] = {"Total", "TrackEta", "DauPt", "TPCNcls", "TPCPID", "d TOFPID", "PionDcatoPV", "MomRapidity", "Lifetime", "VtxCosPA", "VtxDcaDau", "InvMass"}; for (int i{0}; i < kNCandSteps; i++) { registry.get(HIST("hCandidatesCounter"))->GetXaxis()->SetBinLabel(i + 1, CandCounterbinLabel[i]); - registry.get(HIST("hTrueHypertritonCounter"))->GetXaxis()->SetBinLabel(i + 1, CandCounterbinLabel[i]); + if (doprocessMC == true) { + registry.get(HIST("hTrueHypertritonCounter"))->GetXaxis()->SetBinLabel(i + 1, CandCounterbinLabel[i]); + } } - - registry.get(HIST("hGeneratedHypertritonCounter"))->GetXaxis()->SetBinLabel(1, "Total"); - registry.get(HIST("hGeneratedHypertritonCounter"))->GetXaxis()->SetBinLabel(2, "3-body decay"); } //------------------------------------------------------------------ - Preslice perCollisionVtx3BodyDatas = o2::aod::vtx3body::collisionId; - //------------------------------------------------------------------ - // Analysis process for a single candidate - template - void CandidateAnalysis(TCollisionTable const& dCollision, TCandTable const& candData, bool& if_hasvtx, bool isTrueCand = false, double MClifetime = -1, double lPt = -1) + // Selections for candidates + template + bool SelectCand(TCollisionTable const& collision, TCandTable const& candData, TTrackTable const& trackProton, TTrackTable const& trackPion, TTrackTable const& trackDeuteron, bool isMatter, bool isTrueCand = false, double MClifetime = -1, double lPt = -1) { - FillCandCounter(kCandAll, isTrueCand); - auto track0 = candData.template track0_as(); - auto track1 = candData.template track1_as(); - auto track2 = candData.template track2_as(); - - auto& trackProton = (track2.sign() > 0) ? track0 : track1; - auto& trackPion = (track2.sign() > 0) ? track1 : track0; - auto& trackDeuteron = track2; - - if (candData.vtxcosPA(dCollision.posX(), dCollision.posY(), dCollision.posZ()) < vtxcospa) { - return; - } - FillCandCounter(kCandCosPA, isTrueCand); - if (TMath::Abs(trackProton.eta()) > etacut || TMath::Abs(trackPion.eta()) > etacut || TMath::Abs(trackDeuteron.eta()) > etacut) { - return; + // Selection on daughters + if (std::abs(trackProton.eta()) > etacut || std::abs(trackPion.eta()) > etacut || std::abs(trackDeuteron.eta()) > etacut) { + return false; } FillCandCounter(kCandDauEta, isTrueCand); - if (TMath::Abs(candData.yHypertriton()) > rapiditycut) { - return; + + if (trackProton.pt() < minProtonPt || trackProton.pt() > maxProtonPt || trackPion.pt() < minPionPt || trackPion.pt() > maxPionPt || trackDeuteron.pt() < minDeuteronPt || trackDeuteron.pt() > maxDeuteronPt) { + return false; } - FillCandCounter(kCandRapidity, isTrueCand); - double ct = candData.distovertotmom(dCollision.posX(), dCollision.posY(), dCollision.posZ()) * o2::constants::physics::MassHyperTriton; - if (ct > lifetimecut) { - return; + FillCandCounter(kCandDauPt, isTrueCand); + + if (trackProton.tpcNClsFound() < mintpcNClsproton || trackPion.tpcNClsFound() < mintpcNClspion || trackDeuteron.tpcNClsFound() < mintpcNClsdeuteron) { + return false; } - FillCandCounter(kCandct, isTrueCand); - if (candData.dcaVtxdaughters() > dcavtxdau) { - return; + FillCandCounter(kCandTPCNcls, isTrueCand); + + if (std::abs(trackProton.tpcNSigmaPr()) > tpcPIDNSigmaCut || std::abs(trackPion.tpcNSigmaPi()) > tpcPIDNSigmaCut || std::abs(trackDeuteron.tpcNSigmaDe()) > tpcPIDNSigmaCut) { + return false; } - FillCandCounter(kCandDcaDau, isTrueCand); + FillCandCounter(kCandTPCPID, isTrueCand); - registry.fill(HIST("hDeuteronTOFVsPBeforeTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tofNSigmaDe()); + // registry.fill(HIST("hDeuteronDefaultTOFVsPBeforeTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tofNSigmaDe()); + registry.fill(HIST("hDeuteronTOFVsPBeforeTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); if (isTrueCand) { - registry.fill(HIST("hDeuteronTOFVsPBeforeTOFCutSig"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tofNSigmaDe()); + // registry.fill(HIST("hDeuteronDefaultTOFVsPBeforeTOFCutSig"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tofNSigmaDe()); + registry.fill(HIST("hDeuteronTOFVsPBeforeTOFCutSig"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); } - if ((trackDeuteron.tofNSigmaDe() < TofPidNsigmaMin || trackDeuteron.tofNSigmaDe() > TofPidNsigmaMax) && trackDeuteron.p() > minDeuteronPUseTOF) { - return; + if ((candData.tofNSigmaBachDe() < tofPIDNSigmaMin || candData.tofNSigmaBachDe() > tofPIDNSigmaMax) && trackDeuteron.p() > minDeuteronPUseTOF) { + return false; } FillCandCounter(kCandTOFPID, isTrueCand); - registry.fill(HIST("hDeuteronTOFVsPAtferTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tofNSigmaDe()); + // registry.fill(HIST("hDeuteronDefaultTOFVsPAtferTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tofNSigmaDe()); + registry.fill(HIST("hDeuteronTOFVsPAfterTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); if (isTrueCand) { - registry.fill(HIST("hDeuteronTOFVsPAtferTOFCutSig"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tofNSigmaDe()); + // registry.fill(HIST("hDeuteronDefaultTOFVsPAfterTOFCutSig"), trackDeuteron.sign() * trackDeuteron.p(), trackDeuteron.tofNSigmaDe()); + registry.fill(HIST("hDeuteronTOFVsPAfterTOFCutSig"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); } - if (TMath::Abs(trackProton.tpcNSigmaPr()) > TpcPidNsigmaCut || TMath::Abs(trackPion.tpcNSigmaPi()) > TpcPidNsigmaCut || TMath::Abs(trackDeuteron.tpcNSigmaDe()) > TpcPidNsigmaCut) { - return; + double dcapion = isMatter ? candData.dcatrack1topv() : candData.dcatrack0topv(); + if (std::abs(dcapion) < dcapiontopv) { + return false; } - FillCandCounter(kCandTPCPID, isTrueCand); + FillCandCounter(kCandDcaToPV, isTrueCand); - if (trackProton.tpcNClsFound() < mintpcNClsproton || trackPion.tpcNClsFound() < mintpcNClspion || trackDeuteron.tpcNClsFound() < mintpcNClsdeuteron) { - return; + // Selection on candidate hypertriton + if (std::abs(candData.yHypertriton()) > rapiditycut) { + return false; } - FillCandCounter(kCandTPCNcls, isTrueCand); + FillCandCounter(kCandRapidity, isTrueCand); - if (trackProton.pt() < minProtonPt || trackProton.pt() > maxProtonPt || trackPion.pt() < minPionPt || trackPion.pt() > maxPionPt || trackDeuteron.pt() < minDeuteronPt || trackDeuteron.pt() > maxDeuteronPt) { - return; + double ct = candData.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassHyperTriton; + if (ct > lifetimecut) { + return false; } - FillCandCounter(kCandDauPt, isTrueCand); + FillCandCounter(kCandct, isTrueCand); - double dcapion = (track2.sign() > 0) ? candData.dcatrack1topv() : candData.dcatrack0topv(); - if (TMath::Abs(dcapion) < dcapiontopv) { - return; + double cospa = candData.vtxcosPA(collision.posX(), collision.posY(), collision.posZ()); + if (cospa < vtxcospa) { + return false; } - FillCandCounter(kCandDcaToPV, isTrueCand); - - // 3sigma region for Dalitz plot - double lowersignallimit = o2::constants::physics::MassHyperTriton - 3 * mcsigma; - double uppersignallimit = o2::constants::physics::MassHyperTriton + 3 * mcsigma; + FillCandCounter(kCandCosPA, isTrueCand); - // Hypertriton - if ((track2.sign() > 0 && candData.mHypertriton() > h3LMassLowerlimit && candData.mHypertriton() < h3LMassUpperlimit)) { - if_hasvtx = true; - FillCandCounter(kCandInvMass, isTrueCand); + if (candData.dcaVtxdaughters() > dcavtxdau) { + return false; + } + FillCandCounter(kCandDcaDau, isTrueCand); + if ((isMatter && candData.mHypertriton() > h3LMassLowerlimit && candData.mHypertriton() < h3LMassUpperlimit)) { + // Hypertriton registry.fill(HIST("hPtProton"), trackProton.pt()); registry.fill(HIST("hPtPionMinus"), trackPion.pt()); registry.fill(HIST("hPtDeuteron"), trackDeuteron.pt()); + registry.fill(HIST("hDCAXYProtonToPV"), candData.dcaXYtrack0topv()); + registry.fill(HIST("hDCAXYPionToPV"), candData.dcaXYtrack1topv()); registry.fill(HIST("hDCAProtonToPV"), candData.dcatrack0topv()); registry.fill(HIST("hDCAPionToPV"), candData.dcatrack1topv()); registry.fill(HIST("hMassHypertriton"), candData.mHypertriton()); registry.fill(HIST("hMassHypertritonTotal"), candData.mHypertriton()); - registry.fill(HIST("h3dMassHypertriton"), 0., candData.pt(), candData.mHypertriton()); // dCollision.centV0M() instead of 0. once available + registry.fill(HIST("h3dMassHypertriton"), 0., candData.pt(), candData.mHypertriton()); // collision.centV0M() instead of 0. once available registry.fill(HIST("h3dTotalHypertriton"), ct, candData.pt(), candData.mHypertriton()); if (candData.mHypertriton() > lowersignallimit && candData.mHypertriton() < uppersignallimit) { - registry.fill(HIST("hDalitz"), RecoDecay::m2(array{array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}, array{candData.pxtrack2(), candData.pytrack2(), candData.pztrack2()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}), RecoDecay::m2(array{array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}, array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged})); + registry.fill(HIST("hDalitz"), RecoDecay::m2(std::array{std::array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}, std::array{candData.pxtrack2(), candData.pytrack2(), candData.pztrack2()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}), RecoDecay::m2(std::array{std::array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}, std::array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged})); } if (isTrueCand) { registry.fill(HIST("h3dTotalTrueHypertriton"), MClifetime, lPt, candData.mHypertriton()); } - } else if ((track2.sign() < 0 && candData.mAntiHypertriton() > h3LMassLowerlimit && candData.mAntiHypertriton() < h3LMassUpperlimit)) { + } else if ((!isMatter && candData.mAntiHypertriton() > h3LMassLowerlimit && candData.mAntiHypertriton() < h3LMassUpperlimit)) { // AntiHypertriton - if_hasvtx = true; - FillCandCounter(kCandInvMass, isTrueCand); - registry.fill(HIST("hPtAntiProton"), trackProton.pt()); registry.fill(HIST("hPtPionPlus"), trackPion.pt()); registry.fill(HIST("hPtAntiDeuteron"), trackDeuteron.pt()); + registry.fill(HIST("hDCAXYProtonToPV"), candData.dcaXYtrack1topv()); + registry.fill(HIST("hDCAXYPionToPV"), candData.dcaXYtrack0topv()); registry.fill(HIST("hDCAProtonToPV"), candData.dcatrack1topv()); registry.fill(HIST("hDCAPionToPV"), candData.dcatrack0topv()); registry.fill(HIST("hMassAntiHypertriton"), candData.mAntiHypertriton()); registry.fill(HIST("hMassHypertritonTotal"), candData.mAntiHypertriton()); - registry.fill(HIST("h3dMassAntiHypertriton"), 0., candData.pt(), candData.mAntiHypertriton()); // dCollision.centV0M() instead of 0. once available + registry.fill(HIST("h3dMassAntiHypertriton"), 0., candData.pt(), candData.mAntiHypertriton()); // collision.centV0M() instead of 0. once available registry.fill(HIST("h3dTotalHypertriton"), ct, candData.pt(), candData.mAntiHypertriton()); if (candData.mAntiHypertriton() > lowersignallimit && candData.mAntiHypertriton() < uppersignallimit) { - registry.fill(HIST("hDalitz"), RecoDecay::m2(array{array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}, array{candData.pxtrack2(), candData.pytrack2(), candData.pztrack2()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}), RecoDecay::m2(array{array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}, array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged})); + registry.fill(HIST("hDalitz"), RecoDecay::m2(std::array{std::array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}, std::array{candData.pxtrack2(), candData.pytrack2(), candData.pztrack2()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}), RecoDecay::m2(std::array{std::array{candData.pxtrack1(), candData.pytrack1(), candData.pztrack1()}, std::array{candData.pxtrack0(), candData.pytrack0(), candData.pztrack0()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged})); } if (isTrueCand) { registry.fill(HIST("h3dTotalTrueHypertriton"), MClifetime, lPt, candData.mHypertriton()); } } else { - return; + return false; } + + FillCandCounter(kCandInvMass, isTrueCand); + + registry.fill(HIST("hDCAXYDeuteronToPV"), candData.dcaXYtrack2topv()); registry.fill(HIST("hDCADeuteronToPV"), candData.dcatrack2topv()); - registry.fill(HIST("hVtxCosPA"), candData.vtxcosPA(dCollision.posX(), dCollision.posY(), dCollision.posZ())); + registry.fill(HIST("hVtxCosPA"), candData.vtxcosPA(collision.posX(), collision.posY(), collision.posZ())); registry.fill(HIST("hDCAVtxDau"), candData.dcaVtxdaughters()); registry.fill(HIST("hProtonTPCNcls"), trackProton.tpcNClsCrossedRows()); registry.fill(HIST("hPionTPCNcls"), trackPion.tpcNClsCrossedRows()); @@ -413,15 +445,38 @@ struct hypertriton3bodyAnalysis { registry.fill(HIST("hProtonTPCVsPt"), trackProton.pt(), trackProton.tpcNSigmaPr()); registry.fill(HIST("hPionTPCVsPt"), trackProton.pt(), trackPion.tpcNSigmaPi()); registry.fill(HIST("hDeuteronTPCVsPt"), trackDeuteron.pt(), trackDeuteron.tpcNSigmaDe()); - registry.fill(HIST("hTOFPIDDeuteron"), trackDeuteron.tofNSigmaDe()); + registry.fill(HIST("hTOFPIDDeuteron"), candData.tofNSigmaBachDe()); + + return true; + } + + //------------------------------------------------------------------ + // Analysis process for a single candidate + template + void CandidateAnalysis(TCollisionTable const& collision, TCandTable const& candData, bool& if_hasvtx, bool isTrueCand = false, double MClifetime = -1, double lPt = -1) + { + + auto track0 = candData.template track0_as(); + auto track1 = candData.template track1_as(); + auto track2 = candData.template track2_as(); + + bool isMatter = track2.sign() > 0; + + auto& trackProton = isMatter ? track0 : track1; + auto& trackPion = isMatter ? track1 : track0; + auto& trackDeuteron = track2; + + if (SelectCand(collision, candData, trackProton, trackPion, trackDeuteron, isMatter, isTrueCand, MClifetime, lPt)) { + if_hasvtx = true; + } } //------------------------------------------------------------------ // collect information for generated hypertriton (should be called after event selection) void GetGeneratedH3LInfo(aod::McParticles const& particlesMC) { - for (auto& mcparticle : particlesMC) { - if (std::abs(mcparticle.pdgCode()) != 1010010030) { + for (const auto& mcparticle : particlesMC) { + if (std::abs(mcparticle.pdgCode()) != motherPdgCode) { continue; } registry.fill(HIST("hGeneratedHypertritonCounter"), 0.5); @@ -429,7 +484,7 @@ struct hypertriton3bodyAnalysis { bool haveProton = false, havePionPlus = false, haveDeuteron = false; bool haveAntiProton = false, havePionMinus = false, haveAntiDeuteron = false; double MClifetime = -1; - for (auto& mcparticleDaughter : mcparticle.template daughters_as()) { + for (const auto& mcparticleDaughter : mcparticle.template daughters_as()) { if (mcparticleDaughter.pdgCode() == 2212) haveProton = true; if (mcparticleDaughter.pdgCode() == -2212) @@ -438,22 +493,22 @@ struct hypertriton3bodyAnalysis { havePionPlus = true; if (mcparticleDaughter.pdgCode() == -211) havePionMinus = true; - if (mcparticleDaughter.pdgCode() == 1000010020) { + if (mcparticleDaughter.pdgCode() == bachelorPdgCode) { haveDeuteron = true; MClifetime = RecoDecay::sqrtSumOfSquares(mcparticleDaughter.vx() - mcparticle.vx(), mcparticleDaughter.vy() - mcparticle.vy(), mcparticleDaughter.vz() - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); } - if (mcparticleDaughter.pdgCode() == -1000010020) { + if (mcparticleDaughter.pdgCode() == -bachelorPdgCode) { haveAntiDeuteron = true; MClifetime = RecoDecay::sqrtSumOfSquares(mcparticleDaughter.vx() - mcparticle.vx(), mcparticleDaughter.vy() - mcparticle.vy(), mcparticleDaughter.vz() - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); } } - if (haveProton && havePionMinus && haveDeuteron && mcparticle.pdgCode() == 1010010030) { + if (haveProton && havePionMinus && haveDeuteron && mcparticle.pdgCode() == motherPdgCode) { registry.fill(HIST("hGeneratedHypertritonCounter"), 1.5); registry.fill(HIST("hPtGeneratedHypertriton"), mcparticle.pt()); registry.fill(HIST("hctGeneratedHypertriton"), MClifetime); registry.fill(HIST("hEtaGeneratedHypertriton"), mcparticle.eta()); registry.fill(HIST("hRapidityGeneratedHypertriton"), mcparticle.y()); - } else if (haveAntiProton && havePionPlus && haveAntiDeuteron && mcparticle.pdgCode() == -1010010030) { + } else if (haveAntiProton && havePionPlus && haveAntiDeuteron && mcparticle.pdgCode() == -motherPdgCode) { registry.fill(HIST("hGeneratedHypertritonCounter"), 1.5); registry.fill(HIST("hPtGeneratedAntiHypertriton"), mcparticle.pt()); registry.fill(HIST("hctGeneratedAntiHypertriton"), MClifetime); @@ -472,14 +527,14 @@ struct hypertriton3bodyAnalysis { return; } registry.fill(HIST("hEventCounter"), 1.5); - if (event_posZ_selection && abs(collision.posZ()) > 10.f) { // 10cm + if (event_posZ_selection && std::abs(collision.posZ()) > 10.f) { // 10cm return; } registry.fill(HIST("hEventCounter"), 2.5); bool if_hasvtx = false; - for (auto& vtx : vtx3bodydatas) { + for (const auto& vtx : vtx3bodydatas) { CandidateAnalysis(collision, vtx, if_hasvtx); } @@ -498,19 +553,19 @@ struct hypertriton3bodyAnalysis { for (const auto& collision : collisions) { registry.fill(HIST("hEventCounter"), 0.5); - if (event_sel8_selection && !collision.sel8()) { + if (mc_event_selection && (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder))) { continue; } registry.fill(HIST("hEventCounter"), 1.5); - if (event_posZ_selection && abs(collision.posZ()) > 10.f) { // 10cm - return; + if (event_posZ_selection && std::abs(collision.posZ()) > 10.f) { // 10cm + continue; } registry.fill(HIST("hEventCounter"), 2.5); bool if_hasvtx = false; auto vtxsthiscol = vtx3bodydatas.sliceBy(perCollisionVtx3BodyDatas, collision.globalIndex()); - for (auto& vtx : vtxsthiscol) { + for (const auto& vtx : vtxsthiscol) { // int lLabel = -1; int lPDG = -1; float lPt = -1; @@ -524,15 +579,15 @@ struct hypertriton3bodyAnalysis { auto lMCTrack1 = track1.mcParticle_as(); auto lMCTrack2 = track2.mcParticle_as(); if (lMCTrack0.has_mothers() && lMCTrack1.has_mothers() && lMCTrack2.has_mothers()) { - for (auto& lMother0 : lMCTrack0.mothers_as()) { - for (auto& lMother1 : lMCTrack1.mothers_as()) { - for (auto& lMother2 : lMCTrack2.mothers_as()) { + for (const auto& lMother0 : lMCTrack0.mothers_as()) { + for (const auto& lMother1 : lMCTrack1.mothers_as()) { + for (const auto& lMother2 : lMCTrack2.mothers_as()) { if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { // lLabel = lMother1.globalIndex(); lPt = lMother1.pt(); lPDG = lMother1.pdgCode(); - if ((lPDG == 1010010030 && lMCTrack0.pdgCode() == 2212 && lMCTrack1.pdgCode() == -211 && lMCTrack2.pdgCode() == 1000010020) || - (lPDG == -1010010030 && lMCTrack0.pdgCode() == 211 && lMCTrack1.pdgCode() == -2212 && lMCTrack2.pdgCode() == -1000010020)) { + if ((lPDG == motherPdgCode && lMCTrack0.pdgCode() == 2212 && lMCTrack1.pdgCode() == -211 && lMCTrack2.pdgCode() == bachelorPdgCode) || + (lPDG == -motherPdgCode && lMCTrack0.pdgCode() == 211 && lMCTrack1.pdgCode() == -2212 && lMCTrack2.pdgCode() == -bachelorPdgCode)) { isTrueCand = true; MClifetime = RecoDecay::sqrtSumOfSquares(lMCTrack2.vx() - lMother2.vx(), lMCTrack2.vy() - lMother2.vy(), lMCTrack2.vz() - lMother2.vz()) * o2::constants::physics::MassHyperTriton / lMother2.p(); } @@ -557,45 +612,48 @@ struct hypertriton3bodyAnalysis { // check vtx3body with mclabels struct hypertriton3bodyLabelCheck { - HistogramRegistry registry{ - "registry", - { - {"hLabeledVtxCounter", "hLabeledVtxCounter", {HistType::kTH1F, {{3, 0.0f, 3.0f}}}}, - {"hMassTrueH3L", "hMassTrueH3L", {HistType::kTH1F, {{80, 2.96f, 3.04f}}}}, - {"hMassTrueH3LMatter", "hMassTrueH3LMatter", {HistType::kTH1F, {{80, 2.96f, 3.04f}}}}, - {"hMassTrueH3LAntiMatter", "hMassTrueH3LAntiMatter", {HistType::kTH1F, {{80, 2.96f, 3.04f}}}}, - {"hPIDCounter", "hPIDCounter", {HistType::kTH1F, {{6, 0.0f, 6.0f}}}}, - {"hHypertritonCounter", "hHypertritonCounter", {HistType::kTH1F, {{4, 0.0f, 4.0f}}}}, - {"hDecay3BodyCounter", "hDecay3BodyCounter", {HistType::kTH1F, {{5, 0.0f, 5.0f}}}}, - }, - }; + + Configurable mc_event_selection{"mc_event_selection", true, "mc event selection count post kIsTriggerTVX and kNoTimeFrameBorder"}; + Configurable event_posZ_selection{"event_posZ_selection", false, "event selection count post poZ cut"}; + Configurable tpcPIDNSigmaCut{"tpcPIDNSigmaCut", 5, "tpcPIDNSigmaCut"}; + Configurable motherPdgCode{"motherPdgCode", 1010010030, "pdgCode of mother track"}; + + HistogramRegistry registry{"registry", {}}; void init(InitContext const&) { - registry.get(HIST("hLabeledVtxCounter"))->GetXaxis()->SetBinLabel(1, "Readin"); - registry.get(HIST("hLabeledVtxCounter"))->GetXaxis()->SetBinLabel(2, "TrueMCH3L"); - registry.get(HIST("hLabeledVtxCounter"))->GetXaxis()->SetBinLabel(3, "Nonrepetitive"); - registry.get(HIST("hPIDCounter"))->GetXaxis()->SetBinLabel(1, "H3L Proton PID > 5"); - registry.get(HIST("hPIDCounter"))->GetXaxis()->SetBinLabel(2, "H3L Pion PID > 5"); - registry.get(HIST("hPIDCounter"))->GetXaxis()->SetBinLabel(3, "H3L Deuteron PID > 5"); - registry.get(HIST("hPIDCounter"))->GetXaxis()->SetBinLabel(4, "#bar{H3L} Proton PID > 5"); - registry.get(HIST("hPIDCounter"))->GetXaxis()->SetBinLabel(5, "#bar{H3L} Pion PID > 5"); - registry.get(HIST("hPIDCounter"))->GetXaxis()->SetBinLabel(6, "#bar{H3L} Deuteron PID > 5"); - registry.get(HIST("hHypertritonCounter"))->GetXaxis()->SetBinLabel(1, "H3L"); - registry.get(HIST("hHypertritonCounter"))->GetXaxis()->SetBinLabel(2, "H3L daughters pass PID"); - registry.get(HIST("hHypertritonCounter"))->GetXaxis()->SetBinLabel(3, "#bar{H3L}"); - registry.get(HIST("hHypertritonCounter"))->GetXaxis()->SetBinLabel(4, "#bar{H3L} daughters pass PID"); - registry.get(HIST("hDecay3BodyCounter"))->GetXaxis()->SetBinLabel(1, "Total"); - registry.get(HIST("hDecay3BodyCounter"))->GetXaxis()->SetBinLabel(2, "True H3L"); - registry.get(HIST("hDecay3BodyCounter"))->GetXaxis()->SetBinLabel(3, "Unduplicated H3L"); - registry.get(HIST("hDecay3BodyCounter"))->GetXaxis()->SetBinLabel(4, "Correct collision"); - registry.get(HIST("hDecay3BodyCounter"))->GetXaxis()->SetBinLabel(4, "Same ColID for daughters"); + if (doprocessData == false) { + auto hLabeledVtxCounter = registry.add("hLabeledVtxCounter", "hLabeledVtxCounter", HistType::kTH1F, {{3, 0.0f, 3.0f}}); + hLabeledVtxCounter->GetXaxis()->SetBinLabel(1, "Readin"); + hLabeledVtxCounter->GetXaxis()->SetBinLabel(2, "TrueMCH3L"); + hLabeledVtxCounter->GetXaxis()->SetBinLabel(3, "Nonrepetitive"); + registry.add("hMassTrueH3L", "hMassTrueH3L", HistType::kTH1F, {{80, 2.96f, 3.04f}}); + registry.add("hMassTrueH3LMatter", "hMassTrueH3LMatter", HistType::kTH1F, {{80, 2.96f, 3.04f}}); + registry.add("hMassTrueH3LAntiMatter", "hMassTrueH3LAntiMatter", HistType::kTH1F, {{80, 2.96f, 3.04f}}); + auto hPIDCounter = registry.add("hPIDCounter", "hPIDCounter", HistType::kTH1F, {{6, 0.0f, 6.0f}}); + hPIDCounter->GetXaxis()->SetBinLabel(1, "H3L Proton PID > 5"); + hPIDCounter->GetXaxis()->SetBinLabel(2, "H3L Pion PID > 5"); + hPIDCounter->GetXaxis()->SetBinLabel(3, "H3L Deuteron PID > 5"); + hPIDCounter->GetXaxis()->SetBinLabel(4, "#bar{H3L} Proton PID > 5"); + hPIDCounter->GetXaxis()->SetBinLabel(5, "#bar{H3L} Pion PID > 5"); + hPIDCounter->GetXaxis()->SetBinLabel(6, "#bar{H3L} Deuteron PID > 5"); + auto hHypertritonCounter = registry.add("hHypertritonCounter", "hHypertritonCounter", HistType::kTH1F, {{4, 0.0f, 4.0f}}); + hHypertritonCounter->GetXaxis()->SetBinLabel(1, "H3L"); + hHypertritonCounter->GetXaxis()->SetBinLabel(2, "H3L daughters pass PID"); + hHypertritonCounter->GetXaxis()->SetBinLabel(3, "#bar{H3L}"); + hHypertritonCounter->GetXaxis()->SetBinLabel(4, "#bar{H3L} daughters pass PID"); + auto hDecay3BodyCounter = registry.add("hDecay3BodyCounter", "hDecay3BodyCounter", HistType::kTH1F, {{5, 0.0f, 5.0f}}); + hDecay3BodyCounter->GetXaxis()->SetBinLabel(1, "Total"); + hDecay3BodyCounter->GetXaxis()->SetBinLabel(2, "True H3L"); + hDecay3BodyCounter->GetXaxis()->SetBinLabel(3, "Unduplicated H3L"); + hDecay3BodyCounter->GetXaxis()->SetBinLabel(4, "Correct collision"); + hDecay3BodyCounter->GetXaxis()->SetBinLabel(5, "Same ColID for daughters"); + registry.add("hDiffRVtxProton", "hDiffRVtxProton", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of proton + registry.add("hDiffRVtxPion", "hDiffRVtxPion", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of pion + registry.add("hDiffRVtxDeuteron", "hDiffRVtxDeuteron", HistType::kTH1F, {{100, -10, 10}}); // difference between the radius of decay vertex and minR of deuteron + } } - Configurable event_sel8_selection{"event_sel8_selection", false, "event selection count post sel8 cut"}; - Configurable event_posZ_selection{"event_posZ_selection", false, "event selection count post poZ cut"}; - Configurable TpcPidNsigmaCut{"TpcPidNsigmaCut", 5, "TpcPidNsigmaCut"}; - struct Indexdaughters { // check duplicated paired daughters int64_t index0; int64_t index1; @@ -606,17 +664,17 @@ struct hypertriton3bodyLabelCheck { } }; - void process(soa::Join::iterator const&) + void processData(soa::Join::iterator const&) { // dummy function } - PROCESS_SWITCH(hypertriton3bodyLabelCheck, process, "Donot check MC label tables", true); + PROCESS_SWITCH(hypertriton3bodyLabelCheck, processData, "Donot check MC label tables", true); void processCheckLabel(soa::Join::iterator const& collision, aod::Decay3Bodys const& decay3bodys, soa::Join const& vtx3bodydatas, MCLabeledTracksIU const& /*tracks*/, aod::McParticles const& /*particlesMC*/, aod::McCollisions const& /*mcCollisions*/) { // check the decay3body table std::vector set_pair; - for (auto& d3body : decay3bodys) { + for (const auto& d3body : decay3bodys) { registry.fill(HIST("hDecay3BodyCounter"), 0.5); auto lTrack0 = d3body.track0_as(); auto lTrack1 = d3body.track1_as(); @@ -631,9 +689,9 @@ struct hypertriton3bodyLabelCheck { continue; } - for (auto& lMother0 : lMCTrack0.mothers_as()) { - for (auto& lMother1 : lMCTrack1.mothers_as()) { - for (auto& lMother2 : lMCTrack2.mothers_as()) { + for (const auto& lMother0 : lMCTrack0.mothers_as()) { + for (const auto& lMother1 : lMCTrack1.mothers_as()) { + for (const auto& lMother2 : lMCTrack2.mothers_as()) { if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { registry.fill(HIST("hDecay3BodyCounter"), 1.5); // duplicated daughters check @@ -655,64 +713,71 @@ struct hypertriton3bodyLabelCheck { } } - if (event_sel8_selection && !collision.sel8()) { + if (mc_event_selection && (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder))) { return; } - if (event_posZ_selection && abs(collision.posZ()) > 10.f) { // 10cm + if (event_posZ_selection && std::abs(collision.posZ()) > 10.f) { // 10cm return; } std::vector set_mothertrack; - for (auto& vtx : vtx3bodydatas) { + for (const auto& vtx : vtx3bodydatas) { registry.fill(HIST("hLabeledVtxCounter"), 0.5); if (vtx.mcParticleId() != -1) { auto mcparticle = vtx.mcParticle_as(); auto lTrack0 = vtx.track0_as(); auto lTrack1 = vtx.track1_as(); auto lTrack2 = vtx.track2_as(); - if (mcparticle.pdgCode() == 1010010030) { - registry.fill(HIST("hLabeledVtxCounter"), 1.5); + if (std::abs(mcparticle.pdgCode()) != motherPdgCode) { + continue; + } + registry.fill(HIST("hLabeledVtxCounter"), 1.5); + registry.fill(HIST("hDiffRVtxDeuteron"), lTrack2.x() - vtx.vtxradius()); + if (mcparticle.pdgCode() > 0) { registry.fill(HIST("hHypertritonCounter"), 0.5); registry.fill(HIST("hMassTrueH3L"), vtx.mHypertriton()); registry.fill(HIST("hMassTrueH3LMatter"), vtx.mHypertriton()); + registry.fill(HIST("hDiffRVtxProton"), lTrack0.x() - vtx.vtxradius()); + registry.fill(HIST("hDiffRVtxPion"), lTrack1.x() - vtx.vtxradius()); auto p = std::find(set_mothertrack.begin(), set_mothertrack.end(), mcparticle.globalIndex()); if (p == set_mothertrack.end()) { set_mothertrack.push_back(mcparticle.globalIndex()); registry.fill(HIST("hLabeledVtxCounter"), 2.5); } - if (TMath::Abs(lTrack0.tpcNSigmaPr()) > TpcPidNsigmaCut) { + if (std::abs(lTrack0.tpcNSigmaPr()) > tpcPIDNSigmaCut) { registry.fill(HIST("hPIDCounter"), 0.5); } - if (TMath::Abs(lTrack1.tpcNSigmaPi()) > TpcPidNsigmaCut) { + if (std::abs(lTrack1.tpcNSigmaPi()) > tpcPIDNSigmaCut) { registry.fill(HIST("hPIDCounter"), 1.5); } - if (TMath::Abs(lTrack2.tpcNSigmaDe()) > TpcPidNsigmaCut) { + if (std::abs(lTrack2.tpcNSigmaDe()) > tpcPIDNSigmaCut) { registry.fill(HIST("hPIDCounter"), 2.5); } - if (TMath::Abs(lTrack0.tpcNSigmaPr()) < TpcPidNsigmaCut && TMath::Abs(lTrack1.tpcNSigmaPi()) < TpcPidNsigmaCut && TMath::Abs(lTrack2.tpcNSigmaDe()) < TpcPidNsigmaCut) { + if (std::abs(lTrack0.tpcNSigmaPr()) < tpcPIDNSigmaCut && std::abs(lTrack1.tpcNSigmaPi()) < tpcPIDNSigmaCut && std::abs(lTrack2.tpcNSigmaDe()) < tpcPIDNSigmaCut) { registry.fill(HIST("hHypertritonCounter"), 1.5); } - } else if (mcparticle.pdgCode() == -1010010030) { - registry.fill(HIST("hLabeledVtxCounter"), 1.5); + } else { registry.fill(HIST("hHypertritonCounter"), 2.5); registry.fill(HIST("hMassTrueH3L"), vtx.mAntiHypertriton()); registry.fill(HIST("hMassTrueH3LAntiMatter"), vtx.mAntiHypertriton()); + registry.fill(HIST("hDiffRVtxProton"), lTrack1.x() - vtx.vtxradius()); + registry.fill(HIST("hDiffRVtxPion"), lTrack0.x() - vtx.vtxradius()); auto p = std::find(set_mothertrack.begin(), set_mothertrack.end(), mcparticle.globalIndex()); if (p == set_mothertrack.end()) { set_mothertrack.push_back(mcparticle.globalIndex()); registry.fill(HIST("hLabeledVtxCounter"), 2.5); } - if (TMath::Abs(lTrack0.tpcNSigmaPi()) > TpcPidNsigmaCut) { + if (std::abs(lTrack0.tpcNSigmaPi()) > tpcPIDNSigmaCut) { registry.fill(HIST("hPIDCounter"), 4.5); } - if (TMath::Abs(lTrack1.tpcNSigmaPr()) > TpcPidNsigmaCut) { + if (std::abs(lTrack1.tpcNSigmaPr()) > tpcPIDNSigmaCut) { registry.fill(HIST("hPIDCounter"), 3.5); } - if (TMath::Abs(lTrack2.tpcNSigmaDe()) > TpcPidNsigmaCut) { + if (std::abs(lTrack2.tpcNSigmaDe()) > tpcPIDNSigmaCut) { registry.fill(HIST("hPIDCounter"), 5.5); } - if (TMath::Abs(lTrack0.tpcNSigmaPi()) < TpcPidNsigmaCut && TMath::Abs(lTrack1.tpcNSigmaPr()) < TpcPidNsigmaCut && TMath::Abs(lTrack2.tpcNSigmaDe()) < TpcPidNsigmaCut) { + if (std::abs(lTrack0.tpcNSigmaPi()) < tpcPIDNSigmaCut && std::abs(lTrack1.tpcNSigmaPr()) < tpcPIDNSigmaCut && std::abs(lTrack2.tpcNSigmaDe()) < tpcPIDNSigmaCut) { registry.fill(HIST("hHypertritonCounter"), 3.5); } } diff --git a/PWGLF/Tasks/Nuspex/nucleiEbye.cxx b/PWGLF/Tasks/Nuspex/nucleiEbye.cxx new file mode 100644 index 00000000000..681d8b2892e --- /dev/null +++ b/PWGLF/Tasks/Nuspex/nucleiEbye.cxx @@ -0,0 +1,706 @@ +// 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. + +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#include "PWGLF/DataModel/LFEbyeTables.h" + +#include "TDatabasePDG.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace +{ +constexpr int kNpart = 2; +constexpr double partMass[kNpart]{o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}; +constexpr double partPdg[kNpart]{2212, o2::constants::physics::kDeuteron}; +std::shared_ptr nAntid; +std::shared_ptr nAntip; +std::shared_ptr nAntiL; +std::shared_ptr nL; +std::shared_ptr nSqAntid; +std::shared_ptr nSqAntip; +std::shared_ptr nSqAntiL; +std::shared_ptr nSqL; +std::shared_ptr nAntipAntid; +std::shared_ptr nLantiL; +std::shared_ptr nLantid; +std::shared_ptr nAntiLantid; +std::shared_ptr nGenAntid; +std::shared_ptr nGenAntip; +std::shared_ptr nGenAntiL; +std::shared_ptr nGenL; +std::shared_ptr nGenSqAntid; +std::shared_ptr nGenSqAntip; +std::shared_ptr nGenSqAntiL; +std::shared_ptr nGenSqL; +std::shared_ptr nGenAntipAntid; +std::shared_ptr nGenLantiL; +std::shared_ptr nGenLantid; +std::shared_ptr nGenAntiLantid; +std::shared_ptr tempAntiLambda; +std::shared_ptr tempLambda; +std::array, kNpart> tempTracks; +std::array, kNpart> recTracks; +std::array, kNpart> recAntiTracks; +std::array, kNpart> genTracks; +std::array, kNpart> genAntiTracks; +std::array, kNpart> tpcNsigmaGlo; +std::array, kNpart> tofMass; +} // namespace + +struct CandidateV0 { + float pt; + float eta; + float mass; + float cpa; + float dcav0daugh; + float dcav0pv; + int64_t globalIndexPos = -999; + int64_t globalIndexNeg = -999; + int64_t globalIndex = -999; +}; + +struct CandidateTrack { + float pt; + float eta; + int64_t globalIndex = -999; +}; + +struct nucleiEbye { + std::mt19937 gen32; + std::vector candidateV0s; + std::array, 2> candidateTracks; + PresliceUnsorted perCollTrack = o2::aod::LFEbyeTable::collEbyeTableId; + PresliceUnsorted perCollV0s = o2::aod::LFEbyeTable::collEbyeTableId; + int nSubsamples; + + ConfigurableAxis centAxis{"centAxis", {106, 0, 106}, "binning for the centrality"}; + ConfigurableAxis subsampleAxis{"subsampleAxis", {30, 0, 30}, "binning of the subsample axis"}; + ConfigurableAxis deltaEtaAxis{"deltaEtaAxis", {4, 0, 0.8}, "binning of the delta eta axis"}; + ConfigurableAxis ptAntidAxis{"ptAntidAxis", {VARIABLE_WIDTH, 0.7f, 0.8f, 0.9f, 1.0f, 1.2f, 1.4f, 1.6f, 1.8f}, "binning of the antideuteron pT axis (GeV/c)"}; + ConfigurableAxis ptAntipAxis{"ptAntipAxis", {VARIABLE_WIDTH, 0.4f, 0.6f, 0.7f, 0.8f, 0.9f}, "binning of the antiproton pT axis (GeV/c)"}; + ConfigurableAxis ptLambdaAxis{"ptLambdaAxis", {VARIABLE_WIDTH, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f}, "binning of the (anti)lambda pT axis (GeV/c)"}; + + ConfigurableAxis zVtxAxis{"zVtxBins", {100, -20.f, 20.f}, "Binning for the vertex z in cm"}; + ConfigurableAxis nGenRecAxis{"nGenRecAxis", {20, 0, 20}, "binning for the number of reconstructed or generated candidates per event"}; + + // binning of (anti)lambda QA histograms + ConfigurableAxis massLambdaAxis{"massLambdaAxis", {400, o2::constants::physics::MassLambda0 - 0.03f, o2::constants::physics::MassLambda0 + 0.03f}, "binning for the lambda invariant-mass"}; + ConfigurableAxis cosPaAxis{"cosPaAxis", {1e3, 0.95f, 1.00f}, "binning for the cosPa axis"}; + ConfigurableAxis radiusAxis{"radiusAxis", {1e3, 0.f, 100.f}, "binning for the radius axis"}; + ConfigurableAxis dcaV0daughAxis{"dcaV0daughAxis", {2e2, 0.f, 2.f}, "binning for the dca of V0 daughters"}; + ConfigurableAxis dcaDaughPvAxis{"dcaDaughPvAxis", {1e3, -10.f, 10.f}, "binning for the dca of positive daughter to PV"}; + + // binning of deuteron QA histograms + ConfigurableAxis tpcNsigmaAxis{"tpcNsigmaAxis", {100, -5.f, 5.f}, "tpc nsigma axis"}; + ConfigurableAxis tofMassAxis{"tofMassAxis", {1000, 0., 3.f}, "tof mass axis"}; + ConfigurableAxis momAxis{"momAxis", {60., 0.f, 3.f}, "momentum axis binning"}; + ConfigurableAxis momAxisFine{"momAxisFine", {5.e2, 0.f, 5.f}, "momentum axis binning"}; + ConfigurableAxis momResAxis{"momResAxis", {1.e2, -1.f, 1.f}, "momentum resolution binning"}; + ConfigurableAxis tpcAxis{"tpcAxis", {4.e2, 0.f, 4.e3f}, "tpc signal axis binning"}; + ConfigurableAxis tofAxis{"tofAxis", {1.e3, 0.f, 1.f}, "tof signal axis binning"}; + ConfigurableAxis tpcClsAxis{"tpcClsAxis", {160, 0.f, 160.f}, "tpc n clusters binning"}; + + Configurable zVtxMax{"zVtxMax", 10.0f, "maximum z position of the primary vertex"}; + Configurable etaMax{"etaMax", 0.8f, "maximum eta"}; + + Configurable fillOnlySignal{"fillOnlySignal", false, "fill histograms only for true signal candidates (MC)"}; + + Configurable antidPtMin{"antidPtMin", 0.8f, "minimum antideuteron pT (GeV/c)"}; + Configurable antidPtTof{"antidPtTof", 1.0f, "antideuteron pT to switch to TOF pid (GeV/c) "}; + Configurable antidPtMax{"antidPtMax", 1.8f, "maximum antideuteron pT (GeV/c)"}; + + Configurable antipPtMin{"antipPtMin", 0.4f, "minimum antiproton pT (GeV/c)"}; + Configurable antipPtTof{"antipPtTof", 0.6f, "antiproton pT to switch to TOF pid (GeV/c) "}; + Configurable antipPtMax{"antipPtMax", 0.9f, "maximum antiproton pT (GeV/c)"}; + + Configurable lambdaPtMin{"lambdaPtMin", 0.5f, "minimum (anti)lambda pT (GeV/c)"}; + Configurable lambdaPtMax{"lambdaPtMax", 3.0f, "maximum (anti)lambda pT (GeV/c)"}; + + Configurable trackNclusTpcCut{"trackNclusTPCcut", 70, "Minimum number of TPC clusters"}; + Configurable trackDcaCut{"trackDcaCut", 0.1f, "DCA antid to PV"}; + + Configurable antidNsigmaTpcCutLow{"antidNsigmaTpcCutLow", 4.f, "TPC PID cut low"}; + Configurable antidNsigmaTpcCutUp{"antidNsigmaTpcCutUp", 4.f, "TPC PID cut up"}; + Configurable antidTofMassMax{"tofMassMax", 0.3f, "(temporary) tof mass cut"}; + + Configurable antipNsigmaTpcCutLow{"antipNsigmaTpcCutLow", 4.f, "TPC PID cut low"}; + Configurable antipNsigmaTpcCutUp{"antipNsigmaTpcCutUp", 4.f, "TPC PID cut up"}; + Configurable antipTofMassMax{"antipTofMassMax", 0.3f, "(temporary) tof mass cut"}; + Configurable tofMassMaxQA{"tofMassMaxQA", 0.6f, "(temporary) tof mass cut (for QA histograms)"}; + + Configurable v0setting_dcav0dau{"v0setting_dcav0dau", 1, "DCA V0 Daughters"}; + Configurable v0setting_dcav0pv{"v0setting_dcav0pv", 1, "DCA V0 to Pv"}; + Configurable v0setting_dcadaughtopv{"v0setting_dcadaughtopv", 0.1f, "DCA Pos To PV"}; + Configurable v0setting_cospa{"v0setting_cospa", 0.98, "V0 CosPA"}; + Configurable v0setting_nsigmatpc{"v0setting_nsigmatpc", 4.f, "nsigmatpc"}; + Configurable lambdaMassCut{"lambdaMassCut", 0.005f, "maximum deviation from PDG mass"}; + Configurable lambdaMassCutQA{"lambdaMassCutQA", 0.02f, "maximum deviation from PDG mass (for QA histograms)"}; + + std::array ptMin; + std::array ptTof; + std::array ptMax; + std::array nSigmaTpcCutLow; + std::array nSigmaTpcCutUp; + std::array tofMassMax; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry tempHistos{"tempHistos", {}, OutputObjHandlingPolicy::TransientObject}; + + template + bool selectTrack(T const& track) + { + if (std::abs(track.eta()) > etaMax) { + return false; + } + if (track.tpcNcls() < trackNclusTpcCut) { + return false; + } + return true; + } + + void fillHistoN(std::shared_ptr hFull, std::shared_ptr const& hTmp, int const subsample, int const centrality) + { + for (int iEta{1}; iEta < hTmp->GetNbinsX() + 1; ++iEta) { + for (int iPt{1}; iPt < hTmp->GetNbinsY() + 1; ++iPt) { + auto eta = hTmp->GetXaxis()->GetBinCenter(iEta); + auto pt = hTmp->GetYaxis()->GetBinCenter(iPt); + auto num = hTmp->Integral(1, iEta, iPt, iPt); + + hFull->Fill(subsample, centrality, eta, pt, num); + } + } + } + + void fillHistoN(std::shared_ptr hFull, std::shared_ptr const& hTmpA, std::shared_ptr const& hTmpB, int const subsample, int const centrality) + { + for (int iEta{1}; iEta < hTmpA->GetNbinsX() + 1; ++iEta) { + auto eta = hTmpA->GetXaxis()->GetBinCenter(iEta); + for (int iPtA{1}; iPtA < hTmpA->GetNbinsY() + 1; ++iPtA) { + for (int iPtB{1}; iPtB < hTmpB->GetNbinsY() + 1; ++iPtB) { + auto ptA = hTmpA->GetYaxis()->GetBinCenter(iPtA); + auto ptB = hTmpB->GetYaxis()->GetBinCenter(iPtB); + auto numA = hTmpA->Integral(1, iEta, iPtA, iPtA); + auto numB = hTmpB->Integral(1, iEta, iPtB, iPtB); + + hFull->Fill(subsample, centrality, eta, ptA, ptB, numA * numB); + } + } + } + } + + void init(o2::framework::InitContext&) + { + + uint32_t randomSeed = static_cast(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + gen32.seed(randomSeed); + + histos.add("QA/zVtx", ";#it{z}_{vtx} (cm);Entries", HistType::kTH1F, {zVtxAxis}); + + auto hNev = histos.add("nEv", ";Subsample;Centrality (%);", HistType::kTHnSparseD, {subsampleAxis, centAxis}); + nSubsamples = hNev->GetAxis(0)->GetNbins(); + + histos.add("QA/nRecPerEvAntid", ";Centrality (%);#it{N}_{#bar{d}};#it{N}_{ev}", HistType::kTH2D, {centAxis, nGenRecAxis}); + histos.add("QA/nRecPerEvAntip", ";Centrality (%);#it{N}_{#bar{p}};#it{N}_{ev}", HistType::kTH2D, {centAxis, nGenRecAxis}); + histos.add("QA/nRecPerEvAntiL", ";Centrality (%);#it{N}_{#bar{#Lambda}};#it{N}_{ev}", HistType::kTH2D, {centAxis, nGenRecAxis}); + histos.add("QA/nRecPerEvL", ";Centrality (%);#it{N}_{#Lambda};#it{N}_{ev}", HistType::kTH2D, {centAxis, nGenRecAxis}); + + nAntid = histos.add("nAntid", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{d}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptAntidAxis}); + nAntip = histos.add("nAntip", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{p}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptAntipAxis}); + nAntiL = histos.add("nAntiL", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{#Lambda}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptLambdaAxis}); + nL = histos.add("nL", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#Lambda) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptLambdaAxis}); + + nSqAntid = histos.add("nSqAntid", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{d}) (GeV/#it{c});#it{p}_{T}(#bar{d}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptAntidAxis, ptAntidAxis}); + nSqAntip = histos.add("nSqAntip", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{p}) (GeV/#it{c});#it{p}_{T}(#bar{p}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptAntipAxis, ptAntipAxis}); + nSqAntiL = histos.add("nSqAntiL", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{#Lambda}) (GeV/#it{c});#it{p}_{T}(#bar{#Lambda}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptLambdaAxis, ptLambdaAxis}); + nSqL = histos.add("nSqL", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#Lambda) (GeV/#it{c});#it{p}_{T}(#Lambda) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptLambdaAxis, ptLambdaAxis}); + + nAntipAntid = histos.add("nAntipAntid", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{p}) (GeV/#it{c});#it{p}_{T}(#bar{d}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptAntipAxis, ptAntidAxis}); + nLantiL = histos.add("nLantiL", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#Lambda) (GeV/#it{c});#it{p}_{T}(#bar{#Lambda}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptLambdaAxis, ptLambdaAxis}); + nLantid = histos.add("nLantid", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#Lambda) (GeV/#it{c});#it{p}_{T}(#bar{d}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptLambdaAxis, ptAntidAxis}); + nAntiLantid = histos.add("nAntiLantid", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{#Lambda}) (GeV/#it{c});#it{p}_{T}(#bar{d}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptLambdaAxis, ptAntidAxis}); + + // mc generated + nGenAntid = histos.add("nGenAntid", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{d}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptAntidAxis}); + nGenAntip = histos.add("nGenAntip", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{p}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptAntipAxis}); + nGenAntiL = histos.add("nGenAntiL", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{#Lambda}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptLambdaAxis}); + nGenL = histos.add("nGenL", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#Lambda) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptLambdaAxis}); + + nGenSqAntid = histos.add("nGenSqAntid", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{d}) (GeV/#it{c});#it{p}_{T}(#bar{d}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptAntidAxis, ptAntidAxis}); + nGenSqAntip = histos.add("nGenSqAntip", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{p}) (GeV/#it{c});#it{p}_{T}(#bar{p}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptAntipAxis, ptAntipAxis}); + nGenSqAntiL = histos.add("nGenSqAntiL", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{#Lambda}) (GeV/#it{c});#it{p}_{T}(#bar{#Lambda}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptLambdaAxis, ptLambdaAxis}); + nGenSqL = histos.add("nGenSqL", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#Lambda) (GeV/#it{c});#it{p}_{T}(#Lambda) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptLambdaAxis, ptLambdaAxis}); + + nGenAntipAntid = histos.add("nGenAntipAntid", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{p}) (GeV/#it{c});#it{p}_{T}(#bar{d}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptAntipAxis, ptAntidAxis}); + nGenLantiL = histos.add("nGenLantiL", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#Lambda) (GeV/#it{c});#it{p}_{T}(#bar{#Lambda}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptLambdaAxis, ptLambdaAxis}); + nGenLantid = histos.add("nGenLantid", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#Lambda) (GeV/#it{c});#it{p}_{T}(#bar{d}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptLambdaAxis, ptAntidAxis}); + nGenAntiLantid = histos.add("nGenAntiLantid", ";Subsample;Centrality (%);#Delta#eta;#it{p}_{T}(#bar{#Lambda}) (GeV/#it{c});#it{p}_{T}(#bar{d}) (GeV/#it{c});", HistType::kTHnSparseD, {subsampleAxis, centAxis, deltaEtaAxis, ptLambdaAxis, ptAntidAxis}); + + // v0 QA + histos.add("QA/massLambda", ";Centrality (%);#it{p}_{T} (GeV/#it{c});#it{M}(p + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH3F, {centAxis, momAxis, massLambdaAxis}); + histos.add("QA/cosPa", ";cosPa;Entries", HistType::kTH1F, {cosPaAxis}); + histos.add("QA/cosPaSig", ";cosPa;Entries", HistType::kTH1F, {cosPaAxis}); + histos.add("QA/cosPaBkg", ";cosPa;Entries", HistType::kTH1F, {cosPaAxis}); + histos.add("QA/dcaV0daughSig", ";dcaV0daugh;Entries", HistType::kTH1F, {dcaV0daughAxis}); + histos.add("QA/dcaV0daughBkg", ";dcaV0daugh;Entries", HistType::kTH1F, {dcaV0daughAxis}); + histos.add("QA/dcaV0PvSig", ";dcaV0Pv;Entries", HistType::kTH1F, {dcaV0daughAxis}); + histos.add("QA/dcaV0PvBkg", ";dcaV0Pv;Entries", HistType::kTH1F, {dcaV0daughAxis}); + histos.add("QA/cosPaDcaV0daughSig", ";cosPa;dcaV0daugh", HistType::kTH2F, {cosPaAxis, dcaV0daughAxis}); + histos.add("QA/cosPaDcaV0daughBkg", ";cosPa;dcaV0daugh", HistType::kTH2F, {cosPaAxis, dcaV0daughAxis}); + histos.add("QA/massLambdaEvRej", ";Centrality (%);#it{p}_{T} (GeV/#it{c});#it{M}(p + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH3F, {centAxis, momAxis, massLambdaAxis}); + histos.add("QA/massLambdaEvRejSig", ";Centrality (%);#it{p}_{T} (GeV/#it{c});#it{M}(p + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH3F, {centAxis, momAxis, massLambdaAxis}); + histos.add("QA/massLambdaEvRejBkg", ";Centrality (%);#it{p}_{T} (GeV/#it{c});#it{M}(p + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH3F, {centAxis, momAxis, massLambdaAxis}); + histos.add("QA/dcaV0daugh", ";dcaV0daugh;Entries", HistType::kTH1F, {dcaV0daughAxis}); + histos.add("QA/dcaV0Pv", ";dcaV0Pv;Entries", HistType::kTH1F, {dcaV0daughAxis}); + histos.add("QA/dcaPosPv", ";dcaPosPv;Entries", HistType::kTH1F, {dcaDaughPvAxis}); + histos.add("QA/dcaNegPv", ";dcaNegPv;Entries", HistType::kTH1F, {dcaDaughPvAxis}); + histos.add("QA/cosPaBeforeCut", ";cosPa;Entries", HistType::kTH1F, {cosPaAxis}); + histos.add("QA/dcaV0daughBeforeCut", ";dcaV0daugh;Entries", HistType::kTH1F, {dcaV0daughAxis}); + histos.add("QA/dcaV0PvBeforeCut", ";dcaV0Pv;Entries", HistType::kTH1F, {dcaV0daughAxis}); + + // d QA + histos.add("QA/dcaPv", ";#it{p}_{T} (GeV/#it{c});dcaPv;Entries", HistType::kTH2F, {momAxis, dcaDaughPvAxis}); + histos.add("QA/nClsTPC", ";tpcCls;Entries", HistType::kTH1F, {tpcClsAxis}); + histos.add("QA/dcaPvBefore", ";#it{p}_{T} (GeV/#it{c});dcaPv;Entries", HistType::kTH2F, {momAxis, dcaDaughPvAxis}); + histos.add("QA/nClsTPCBeforeCut", ";tpcCls;Entries", HistType::kTH1F, {tpcClsAxis}); + + tpcNsigmaGlo[0] = histos.add("QA/tpcNsigmaGlo_p", ";Centrality (%);#it{p}_{T} (GeV/#it{c});n#sigma_{TPC} (a.u.)", HistType::kTH3F, {centAxis, momAxis, tpcNsigmaAxis}); + tofMass[0] = histos.add("QA/tofMass_p", ";Centrality (%);#it{p}_{T} (GeV/#it{c});Mass (GeV/#it{c}^{2});Entries", HistType::kTH3F, {centAxis, momAxis, tofMassAxis}); + + tpcNsigmaGlo[1] = histos.add("QA/tpcNsigmaGlo_d", ";Centrality (%);#it{p}_{T} (GeV/#it{c});n#sigma_{TPC} (a.u.)", HistType::kTH3F, {centAxis, momAxis, tpcNsigmaAxis}); + tofMass[1] = histos.add("QA/tofMass_d", ";Centrality (%);#it{p}_{T} (GeV/#it{c});Mass (GeV/#it{c}^{2});Entries", HistType::kTH3F, {centAxis, momAxis, tofMassAxis}); + + // mc histograms + if (doprocessMc) { + histos.add("recL", ";Centrality (%); #it{p}_{T} (GeV/#it{c});#Delta#eta", HistType::kTH3D, {centAxis, ptLambdaAxis, deltaEtaAxis}); + histos.add("recAntiL", ";Centrality (%); #it{p}_{T} (GeV/#it{c});#Delta#eta", HistType::kTH3D, {centAxis, ptLambdaAxis, deltaEtaAxis}); + recTracks[0] = histos.add("recP", ";Centrality (%); #it{p}_{T} (GeV/#it{c});#Delta#eta", HistType::kTH3D, {centAxis, ptAntipAxis, deltaEtaAxis}); + recTracks[1] = histos.add("recD", ";Centrality (%); #it{p}_{T} (GeV/#it{c});#Delta#eta", HistType::kTH3D, {centAxis, ptAntidAxis, deltaEtaAxis}); + recAntiTracks[0] = histos.add("recAntip", ";Centrality (%); #it{p}_{T} (GeV/#it{c});#Delta#eta", HistType::kTH3D, {centAxis, ptAntipAxis, deltaEtaAxis}); + recAntiTracks[1] = histos.add("recAntid", ";Centrality (%); #it{p}_{T} (GeV/#it{c});#Delta#eta", HistType::kTH3D, {centAxis, ptAntidAxis, deltaEtaAxis}); + histos.add("genL", ";Centrality (%); #it{p}_{T} (GeV/#it{c});#Delta#eta", HistType::kTH3D, {centAxis, ptLambdaAxis, deltaEtaAxis}); + histos.add("genAntiL", ";Centrality (%); #it{p}_{T} (GeV/#it{c});#Delta#eta", HistType::kTH3D, {centAxis, ptLambdaAxis, deltaEtaAxis}); + genTracks[0] = histos.add("genP", ";Centrality (%); #it{p}_{T} (GeV/#it{c});#Delta#eta", HistType::kTH3D, {centAxis, ptAntipAxis, deltaEtaAxis}); + genTracks[1] = histos.add("genD", ";Centrality (%); #it{p}_{T} (GeV/#it{c});#Delta#eta", HistType::kTH3D, {centAxis, ptAntidAxis, deltaEtaAxis}); + genAntiTracks[0] = histos.add("genAntip", ";Centrality (%); #it{p}_{T} (GeV/#it{c});#Delta#eta", HistType::kTH3D, {centAxis, ptAntipAxis, deltaEtaAxis}); + genAntiTracks[1] = histos.add("genAntid", ";Centrality (%); #it{p}_{T} (GeV/#it{c});#Delta#eta", HistType::kTH3D, {centAxis, ptAntidAxis, deltaEtaAxis}); + } + + // temporary histograms + tempTracks[0] = tempHistos.add("tempAntip", ";#Delta#eta;#it{p}_{T} (GeV/#it{c})", HistType::kTH2D, {deltaEtaAxis, ptAntipAxis}); + tempTracks[1] = tempHistos.add("tempAntid", ";#Delta#eta;#it{p}_{T} (GeV/#it{c})", HistType::kTH2D, {deltaEtaAxis, ptAntidAxis}); + tempLambda = tempHistos.add("tempLambda", ";#Delta#eta;#it{p}_{T} (GeV/#it{c})", HistType::kTH2D, {deltaEtaAxis, ptLambdaAxis}); + tempAntiLambda = tempHistos.add("tempAntiLambda", ";#Delta#eta;#it{p}_{T} (GeV/#it{c})", HistType::kTH2D, {deltaEtaAxis, ptLambdaAxis}); + + ptMin = std::array{antipPtMin, antidPtMin}; + ptMax = std::array{antipPtMax, antidPtMax}; + ptTof = std::array{antipPtTof, antidPtTof}; + + nSigmaTpcCutLow = std::array{antipNsigmaTpcCutLow, antidNsigmaTpcCutLow}; + nSigmaTpcCutUp = std::array{antipNsigmaTpcCutUp, antidNsigmaTpcCutUp}; + tofMassMax = std::array{antipTofMassMax, antidTofMassMax}; + } + + template + int fillRecoEvent(C const& /*collision*/, T const& tracks, V0 const& V0s, float const& centrality) + { + candidateTracks[0].clear(); + candidateTracks[1].clear(); + candidateV0s.clear(); + + tempTracks[0]->Reset(); + tempTracks[1]->Reset(); + tempLambda->Reset(); + tempAntiLambda->Reset(); + auto rnd = static_cast(gen32()) / static_cast(gen32.max()); + auto subsample = static_cast(rnd * nSubsamples); + + for (const auto& track : tracks) { + + histos.fill(HIST("QA/nClsTPCBeforeCut"), track.tpcNcls()); + + if (!selectTrack(track)) { + continue; + } + + if (track.pt() > 0.) { + continue; + } + + auto dca = track.dcaPV(); + auto trackPt = std::abs(track.pt()); + auto trackEta = track.eta(); + histos.fill(HIST("QA/dcaPvBefore"), trackPt, dca); + if (dca > trackDcaCut) { + continue; + } + histos.fill(HIST("QA/dcaPv"), trackPt, dca); + histos.fill(HIST("QA/nClsTPC"), track.tpcNcls()); + + for (int iP{0}; iP < kNpart; ++iP) { + if (track.mass() != iP) + continue; + if (trackPt < ptMin[iP] || trackPt > ptMax[iP]) { + continue; + } + + auto nSigmaTPC = track.tpcNsigma(); + float mass{track.tofMass()}; + bool hasTof = track.tofMass() > 0; + + if (trackPt <= ptTof[iP] || (trackPt > ptTof[iP] && hasTof && std::abs(mass - partMass[iP]) < tofMassMaxQA)) { // for QA histograms + tpcNsigmaGlo[iP]->Fill(centrality, trackPt, nSigmaTPC); + if (nSigmaTPC > nSigmaTpcCutLow[iP] && nSigmaTPC < nSigmaTpcCutUp[iP]) { + tofMass[iP]->Fill(centrality, trackPt, mass); + } + } + + if (nSigmaTPC < nSigmaTpcCutLow[iP] || nSigmaTPC > nSigmaTpcCutUp[iP]) { + continue; + } + + if (trackPt > ptTof[iP] && !hasTof) { + continue; + } + + if (trackPt <= ptTof[iP] || (trackPt > ptTof[iP] && hasTof && std::abs(mass - partMass[iP]) < tofMassMax[iP])) { + tempTracks[iP]->Fill(std::abs(trackEta), trackPt); + CandidateTrack candTrack; + candTrack.pt = trackPt; + candTrack.eta = trackEta; + candTrack.globalIndex = track.globalIndex(); + candidateTracks[iP].push_back(candTrack); + } + } + } + + std::vector trkId; + for (const auto& v0 : V0s) { + + auto ptV0 = std::abs(v0.pt()); + if (ptV0 < lambdaPtMin || ptV0 > lambdaPtMax) { + continue; + } + + auto etaV0 = v0.eta(); + if (std::abs(etaV0) > etaMax) { + continue; + } + + bool matter = v0.pt() > 0; + auto mLambda = v0.mass(); + + // pid selections + // auto nSigmaTPCPos = v0.tpcNsigmaPos(); + // auto nSigmaTPCNeg = v0.tpcNsigmaNeg(); + + // if (std::abs(nSigmaTPCPos) > v0setting_nsigmatpc || std::abs(nSigmaTPCNeg) > v0setting_nsigmatpc) { + // continue; + // } + + float dcaV0dau = v0.dcaV0tracks(); + histos.fill(HIST("QA/dcaV0daughBeforeCut"), dcaV0dau); + if (dcaV0dau > v0setting_dcav0dau) { + continue; + } + + float dcaV0Pv = v0.dcaV0Pv(); + histos.fill(HIST("QA/dcaV0PvBeforeCut"), dcaV0Pv); + if (std::abs(dcaV0Pv) > v0setting_dcav0pv) { + continue; + } + + double cosPA = v0.cosPa(); + histos.fill(HIST("QA/cosPaBeforeCut"), cosPA); + if (cosPA < v0setting_cospa) { + continue; + } + + // auto posDcaToPv = v0.dcaPosPv(); + // if (posDcaToPv < v0setting_dcadaughtopv) { + // continue; + // } + + // auto negDcaToPv = v0.dcaNegPv(); + // if (negDcaToPv < v0setting_dcadaughtopv) { + // continue; + // } + + if (std::abs(mLambda - o2::constants::physics::MassLambda0) > lambdaMassCutQA) { // for QA histograms + continue; + } + histos.fill(HIST("QA/massLambda"), centrality, ptV0, mLambda); + + if (std::abs(mLambda - o2::constants::physics::MassLambda0) > lambdaMassCut) { + continue; + } + histos.fill(HIST("QA/cosPa"), cosPA); + histos.fill(HIST("QA/dcaV0daugh"), dcaV0dau); + // histos.fill(HIST("QA/dcaPosPv"), posDcaToPv); + // histos.fill(HIST("QA/dcaNegPv"), negDcaToPv); + histos.fill(HIST("QA/dcaV0Pv"), dcaV0Pv); + + if (matter) { + tempHistos.fill(HIST("tempLambda"), std::abs(etaV0), ptV0); + } else { + tempHistos.fill(HIST("tempAntiLambda"), std::abs(etaV0), ptV0); + } + + trkId.emplace_back(v0.idNeg()); + trkId.emplace_back(v0.idPos()); + + CandidateV0 candV0; + candV0.pt = ptV0; + candV0.eta = etaV0; + candV0.mass = mLambda; + candV0.cpa = cosPA; + candV0.dcav0daugh = dcaV0dau; + candV0.dcav0pv = dcaV0Pv; + candV0.globalIndexPos = v0.idPos(); + candV0.globalIndexNeg = v0.idNeg(); + candV0.globalIndex = v0.globalIndex(); + candidateV0s.push_back(candV0); + } + + // reject events having multiple v0s from same tracks (TODO: also across collisions?) + std::sort(trkId.begin(), trkId.end()); + if (std::adjacent_find(trkId.begin(), trkId.end()) != trkId.end()) { + candidateV0s.clear(); + + CandidateV0 candV0; + candV0.pt = -999.f; + candV0.eta = -999.f; + candV0.globalIndexPos = -999; + candV0.globalIndexNeg = -999; + candidateV0s.push_back(candV0); + return -1; + } + for (auto& candidateV0 : candidateV0s) { + histos.fill(HIST("QA/massLambdaEvRej"), centrality, candidateV0.pt, candidateV0.mass); + } + + histos.fill(HIST("nEv"), subsample, centrality); + + if (doprocessMc && fillOnlySignal) + return subsample; + + fillHistoN(nAntip, tempTracks[0], subsample, centrality); + fillHistoN(nAntid, tempTracks[1], subsample, centrality); + fillHistoN(nAntiL, tempAntiLambda, subsample, centrality); + fillHistoN(nL, tempLambda, subsample, centrality); + + fillHistoN(nSqAntip, tempTracks[0], tempTracks[0], subsample, centrality); + fillHistoN(nSqAntid, tempTracks[1], tempTracks[1], subsample, centrality); + fillHistoN(nSqAntiL, tempAntiLambda, tempAntiLambda, subsample, centrality); + fillHistoN(nSqL, tempLambda, tempLambda, subsample, centrality); + + fillHistoN(nAntipAntid, tempTracks[0], tempTracks[1], subsample, centrality); + fillHistoN(nLantid, tempLambda, tempTracks[1], subsample, centrality); + fillHistoN(nLantiL, tempLambda, tempAntiLambda, subsample, centrality); + fillHistoN(nAntiLantid, tempAntiLambda, tempTracks[1], subsample, centrality); + + histos.fill(HIST("QA/nRecPerEvAntip"), centrality, tempTracks[0]->GetEntries()); + histos.fill(HIST("QA/nRecPerEvAntid"), centrality, tempTracks[1]->GetEntries()); + histos.fill(HIST("QA/nRecPerEvAntiL"), centrality, tempAntiLambda->GetEntries()); + histos.fill(HIST("QA/nRecPerEvL"), centrality, tempLambda->GetEntries()); + + return 0; + } + + template + void fillMcEvent(C const& collision, T const& tracks, V0 const& v0s, float const& centrality) + { + int subsample = fillRecoEvent(collision, tracks, v0s, centrality); + if (candidateV0s.size() == 1 && candidateV0s[0].pt < -998.f && candidateV0s[0].eta < -998.f && candidateV0s[0].globalIndexPos == -999 && candidateV0s[0].globalIndexPos == -999) { + return; + } + + if (fillOnlySignal) { + tempTracks[0]->Reset(); + tempTracks[1]->Reset(); + tempLambda->Reset(); + tempAntiLambda->Reset(); + } + + for (int iP{0}; iP < kNpart; ++iP) { + for (auto& candidateTrack : candidateTracks[iP]) { + auto mcTrack = tracks.rawIteratorAt(candidateTrack.globalIndex); + if (std::abs(mcTrack.pdgCode()) != partPdg[iP]) + continue; + if (!mcTrack.isReco()) + continue; + if (mcTrack.pdgCode() > 0) { + recTracks[iP]->Fill(centrality, candidateTrack.pt, std::abs(candidateTrack.eta)); + } else { + recAntiTracks[iP]->Fill(centrality, candidateTrack.pt, std::abs(candidateTrack.eta)); + if (fillOnlySignal) + tempTracks[iP]->Fill(std::abs(candidateTrack.eta), candidateTrack.pt); + } + } + } + for (auto& candidateV0 : candidateV0s) { + auto mcTrack = v0s.rawIteratorAt(candidateV0.globalIndex); + if (!mcTrack.isReco()) + continue; + if (std::abs(mcTrack.pdgCode()) != 3122) { + histos.fill(HIST("QA/cosPaBkg"), candidateV0.cpa); + histos.fill(HIST("QA/dcaV0daughBkg"), candidateV0.dcav0daugh); + histos.fill(HIST("QA/dcaV0PvBkg"), candidateV0.dcav0pv); + histos.fill(HIST("QA/cosPaDcaV0daughBkg"), candidateV0.cpa, candidateV0.dcav0daugh); + histos.fill(HIST("QA/massLambdaEvRejBkg"), centrality, candidateV0.pt, candidateV0.mass); + continue; + } + histos.fill(HIST("QA/cosPaSig"), candidateV0.cpa); + histos.fill(HIST("QA/dcaV0daughSig"), candidateV0.dcav0daugh); + histos.fill(HIST("QA/dcaV0PvSig"), candidateV0.dcav0pv); + histos.fill(HIST("QA/cosPaDcaV0daughSig"), candidateV0.cpa, candidateV0.dcav0daugh); + histos.fill(HIST("QA/massLambdaEvRejSig"), centrality, candidateV0.pt, candidateV0.mass); + if (mcTrack.pdgCode() > 0) { + histos.fill(HIST("recL"), centrality, candidateV0.pt, std::abs(candidateV0.eta)); + if (fillOnlySignal) + tempLambda->Fill(std::abs(candidateV0.eta), candidateV0.pt); + } else { + histos.fill(HIST("recAntiL"), centrality, candidateV0.pt, std::abs(candidateV0.eta)); + if (fillOnlySignal) + tempAntiLambda->Fill(std::abs(candidateV0.eta), candidateV0.pt); + } + } + + if (fillOnlySignal) { + fillHistoN(nAntip, tempTracks[0], subsample, centrality); + fillHistoN(nAntid, tempTracks[1], subsample, centrality); + fillHistoN(nAntiL, tempAntiLambda, subsample, centrality); + fillHistoN(nL, tempLambda, subsample, centrality); + + fillHistoN(nSqAntip, tempTracks[0], tempTracks[0], subsample, centrality); + fillHistoN(nSqAntid, tempTracks[1], tempTracks[1], subsample, centrality); + fillHistoN(nSqAntiL, tempAntiLambda, tempAntiLambda, subsample, centrality); + fillHistoN(nSqL, tempLambda, tempLambda, subsample, centrality); + + fillHistoN(nAntipAntid, tempTracks[0], tempTracks[1], subsample, centrality); + fillHistoN(nLantid, tempLambda, tempTracks[1], subsample, centrality); + fillHistoN(nLantiL, tempLambda, tempAntiLambda, subsample, centrality); + fillHistoN(nAntiLantid, tempAntiLambda, tempTracks[1], subsample, centrality); + + histos.fill(HIST("QA/nRecPerEvAntip"), centrality, tempTracks[0]->GetEntries()); + histos.fill(HIST("QA/nRecPerEvAntid"), centrality, tempTracks[1]->GetEntries()); + histos.fill(HIST("QA/nRecPerEvAntiL"), centrality, tempAntiLambda->GetEntries()); + histos.fill(HIST("QA/nRecPerEvL"), centrality, tempLambda->GetEntries()); + } + } + + template + void fillMcGen(C const& /*collision*/, T const& tracks, V0 const& v0s, float const& centrality) + { + + tempTracks[0]->Reset(); + tempTracks[1]->Reset(); + tempLambda->Reset(); + tempAntiLambda->Reset(); + + auto rnd = static_cast(gen32()) / static_cast(gen32.max()); + auto subsample = static_cast(rnd * nSubsamples); + for (auto& mcPart : v0s) { + auto genEta = mcPart.genEta(); + if (std::abs(genEta) > etaMax) { + continue; + } + auto pdgCode = mcPart.pdgCode(); + if (std::abs(pdgCode) == 3122) { + auto genPt = mcPart.genPt(); + if (pdgCode > 0) { + histos.fill(HIST("genL"), centrality, genPt, std::abs(genEta)); + tempHistos.fill(HIST("tempLambda"), std::abs(genEta), genPt); + } else { + histos.fill(HIST("genAntiL"), centrality, genPt, std::abs(genEta)); + tempHistos.fill(HIST("tempAntiLambda"), std::abs(genEta), genPt); + } + } + } + for (auto& mcPart : tracks) { + auto genEta = mcPart.genEta(); + if (std::abs(genEta) > etaMax) { + continue; + } + auto pdgCode = mcPart.pdgCode(); + if (std::abs(pdgCode) == partPdg[0] || std::abs(pdgCode) == partPdg[1]) { + int iP = 1; + if (std::abs(pdgCode) == partPdg[0]) { + iP = 0; + } + auto genPt = mcPart.genPt(); + if (pdgCode > 0) { + genTracks[iP]->Fill(centrality, genPt, std::abs(genEta)); + } else { + genAntiTracks[iP]->Fill(centrality, genPt, std::abs(genEta)); + tempTracks[iP]->Fill(std::abs(genEta), genPt); + } + } + } + + fillHistoN(nGenAntip, tempTracks[0], subsample, centrality); + fillHistoN(nGenAntid, tempTracks[1], subsample, centrality); + fillHistoN(nGenAntiL, tempAntiLambda, subsample, centrality); + fillHistoN(nGenL, tempLambda, subsample, centrality); + + fillHistoN(nGenSqAntip, tempTracks[0], tempTracks[0], subsample, centrality); + fillHistoN(nGenSqAntid, tempTracks[1], tempTracks[1], subsample, centrality); + fillHistoN(nGenSqAntiL, tempAntiLambda, tempAntiLambda, subsample, centrality); + fillHistoN(nGenSqL, tempLambda, tempLambda, subsample, centrality); + + fillHistoN(nGenAntipAntid, tempTracks[0], tempTracks[1], subsample, centrality); + fillHistoN(nGenLantid, tempLambda, tempTracks[1], subsample, centrality); + fillHistoN(nGenLantiL, tempLambda, tempAntiLambda, subsample, centrality); + fillHistoN(nGenAntiLantid, tempAntiLambda, tempTracks[1], subsample, centrality); + } + + void processData(aod::CollEbyeTable const& collision, aod::NucleiEbyeTables const& tracks, aod::LambdaEbyeTables const& v0s) + { + if (std::abs(collision.zvtx()) > zVtxMax) + return; + histos.fill(HIST("QA/zVtx"), collision.zvtx()); + fillRecoEvent(collision, tracks, v0s, collision.centrality()); + } + PROCESS_SWITCH(nucleiEbye, processData, "process data", false); + + void processMc(aod::CollEbyeTables const& collisions, aod::McNucleiEbyeTables const& tracksTot, aod::McLambdaEbyeTables const& v0sTot) + { + for (auto& collision : collisions) { + if (std::abs(collision.zvtx()) > zVtxMax) + continue; + auto tracks = tracksTot.sliceBy(perCollTrack, collision.globalIndex()); + auto v0s = v0sTot.sliceBy(perCollV0s, collision.globalIndex()); + histos.fill(HIST("QA/zVtx"), collision.zvtx()); + fillMcEvent(collision, tracks, v0s, collision.centrality()); + fillMcGen(collision, tracks, v0s, collision.centrality()); + } + } + PROCESS_SWITCH(nucleiEbye, processMc, "process Mc", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Nuspex/nucleiFromHypertritonMap.cxx b/PWGLF/Tasks/Nuspex/nucleiFromHypertritonMap.cxx new file mode 100644 index 00000000000..dc4e70c2ee3 --- /dev/null +++ b/PWGLF/Tasks/Nuspex/nucleiFromHypertritonMap.cxx @@ -0,0 +1,180 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \author Roberta Ferioli (roberta.ferioli@cern.ch) +/// \since November, 2024 + +#include +#include +#include +#include +#include +#include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/DataTypes.h" +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/DCA.h" +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" + +using namespace std; +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; +using std::array; + +using MCTracks = soa::Join; + +struct nucleiFromHypertritonMap { + HistogramRegistry registryMC{ + "registryMC", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; + + // Track Parameters + Configurable min_ITS_nClusters{"min_ITS_nClusters", 7, "minimum number of found ITS clusters"}; + Configurable min_TPC_nClusters{"min_TPC_nClusters", 100, "minimum number of found TPC clusters"}; + Configurable min_TPC_nCrossedRows{"min_TPC_nCrossedRows", 70, "minimum number of TPC crossed pad rows"}; + Configurable max_chi2_TPC{"max_chi2_TPC", 4.0f, "maximum TPC chi^2/Ncls"}; + Configurable min_chi2_TPC{"min_chi2_ITS", 0.5f, "minimum TPC chi^2/Ncls"}; + Configurable min_eta{"min_eta", -0.8f, "minimum_eta"}; + Configurable max_eta{"max_eta", +0.8f, "maximum_eta"}; + Configurable max_dcaxy{"max_dcaxy", 0.05f, "Maximum DCAxy"}; + Configurable max_dcaz{"max_dcaz", 0.05f, "Maximum DCAz"}; + Configurable min_nsigmaTPC{"min_nsigmaTPC", -2.0f, "Minimum nsigma TPC"}; + Configurable max_nsigmaTPC{"max_nsigmaTPC", +2.0f, "Maximum nsigma TPC"}; + Configurable min_pt{"min_pt", 0.0f, "minimum pt of the tracks"}; + Configurable max_pt{"max_pt", 10.0f, "maximum pt of the tracks"}; + Configurable nbin_pt{"nbin_pt", 50, "number of pt bins"}; + Configurable nbin_dca = {"nbin_dca", 50, "number of DCA bins"}; + Configurable saveHelium{"saveHelium", false, "Save helium candidates"}; + + int AntideuteronPDG = -1000010020; + int AntihePDG = -1000020030; + int AntiHypertritonPDG = -1010010030; + int AntiHyperHelium4PDG = -1010020040; + + void init(InitContext const&) + { + registryMC.add("hypertritonPtgen", "hypertritonPtGen", HistType::kTH1F, {{nbin_pt, min_pt, max_pt, "p_{T} (GeV/c)"}}); + if (saveHelium) { + registryMC.add("he3SecPtRec_from_hypertriton", "he3SecPtRec_from_hypertriton", HistType::kTH1F, {{nbin_pt, min_pt, max_pt, "p_{T} (GeV/c)"}}); + registryMC.add("hyperHe4Ptgen", "hyperHe4PtGen", HistType::kTH1F, {{nbin_pt, min_pt, max_pt, "p_{T} (GeV/c)"}}); + registryMC.add("he3SecPtRec_from_hyperHe4", "he3SecPtRec_from_hyperHe4", HistType::kTH1F, {{nbin_pt, min_pt, max_pt, "p_{T} (GeV/c)"}}); + registryMC.add("he3PtRec", "he3PtRec", HistType::kTH1F, {{nbin_pt, min_pt, max_pt, "p_{T} (GeV/c)"}}); + registryMC.add("he3PtGen", "he3PtGen", HistType::kTH1F, {{nbin_pt, min_pt, max_pt, "p_{T} (GeV/c)"}}); + } else { + registryMC.add("deutSecPtRec_from_hypertriton", "deutSecPtRec_from_hypertriton", HistType::kTH1F, {{nbin_pt, min_pt, max_pt, "p_{T} (GeV/c)"}}); + registryMC.add("deutPtRec", "deutPtRec", HistType::kTH1F, {{nbin_pt, min_pt, max_pt, "p_{T} (GeV/c)"}}); + registryMC.add("deutPtgen", "deutPtGen", HistType::kTH1F, {{nbin_pt, min_pt, max_pt, "p_{T} (GeV/c)"}}); + } + } + + void processMC(const aod::McParticles& mcParticles, const MCTracks& tracks) + { + int selectedPDG = 0; + if (saveHelium) { + selectedPDG = AntihePDG; + } else { + selectedPDG = AntideuteronPDG; + } + + for (const auto& mcparticle : mcParticles) { + if (((mcparticle.pdgCode() == AntiHypertritonPDG || mcparticle.pdgCode() == AntiHyperHelium4PDG) && mcparticle.has_daughters()) || mcparticle.pdgCode() == selectedPDG) { + if (mcparticle.pdgCode() == AntiHypertritonPDG) { + for (auto& daughter : mcparticle.daughters_as()) { + if (daughter.pdgCode() == selectedPDG) { + registryMC.fill(HIST("hypertritonPtgen"), mcparticle.pt()); + } + } + } + if (mcparticle.pdgCode() == AntiHyperHelium4PDG) { + for (auto& daughter : mcparticle.daughters_as()) { + if (daughter.pdgCode() == selectedPDG) { + registryMC.fill(HIST("hyperHe4Ptgen"), mcparticle.pt()); + } + } + } + if (mcparticle.pdgCode() == AntihePDG) { + registryMC.fill(HIST("he3PtGen"), mcparticle.pt()); + } + if (mcparticle.pdgCode() == AntideuteronPDG) { + registryMC.fill(HIST("deutPtGen"), mcparticle.pt()); + } + } + } + + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + continue; + } + auto mcparticle = track.mcParticle(); + if (mcparticle.pdgCode() != selectedPDG) { + continue; + } + + if (track.itsNCls() < min_ITS_nClusters || + track.tpcNClsFound() < min_TPC_nClusters || + track.tpcNClsCrossedRows() < min_TPC_nCrossedRows || + track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || + track.tpcChi2NCl() > 4.f || + track.tpcChi2NCl() < min_chi2_TPC || + track.eta() < min_eta || track.eta() > max_eta || + track.dcaXY() > max_dcaxy || track.dcaXY() < -max_dcaxy || + track.dcaZ() > max_dcaz || track.dcaZ() < -max_dcaz || + track.itsChi2NCl() > 36.f) { + continue; + } + if (mcparticle.pdgCode() == AntideuteronPDG) { + registryMC.fill(HIST("deutPtRec"), track.pt()); + } + if (mcparticle.pdgCode() == AntihePDG) { + registryMC.fill(HIST("he3PtRec"), 2 * track.pt()); + } + + for (auto& motherparticle : mcparticle.mothers_as()) { + if (motherparticle.pdgCode() == AntiHypertritonPDG || motherparticle.pdgCode() == AntiHyperHelium4PDG) { + if (motherparticle.pdgCode() == AntiHypertritonPDG) { + if (mcparticle.pdgCode() == AntihePDG) { + registryMC.fill(HIST("he3SecPtRec_from_hypertriton"), 2 * track.pt()); + } else { + registryMC.fill(HIST("deutSecPtRec_from_hypertriton"), track.pt()); + } + } + if (motherparticle.pdgCode() == AntiHyperHelium4PDG) { + registryMC.fill(HIST("he3SecPtRec_from_hyperHe4"), 2 * track.pt()); + } + } + } + } + } + PROCESS_SWITCH(nucleiFromHypertritonMap, processMC, "Process MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Nuspex/nuclei_in_jets.cxx b/PWGLF/Tasks/Nuspex/nuclei_in_jets.cxx deleted file mode 100644 index 983c71469a3..00000000000 --- a/PWGLF/Tasks/Nuspex/nuclei_in_jets.cxx +++ /dev/null @@ -1,1231 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \author Alberto Caliva (alberto.caliva@cern.ch) -/// \since November 22, 2023 - -#include -#include -#include -#include -#include -#include -#include -#include -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/DataTypes.h" -#include "ReconstructionDataFormats/Track.h" -#include "ReconstructionDataFormats/PID.h" -#include "ReconstructionDataFormats/DCA.h" -#include "Common/Core/trackUtilities.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" - -using namespace std; -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::constants::physics; -using std::array; - -using SelectedCollisions = soa::Join; -using SimCollisions = soa::Join; - -using FullTracks = soa::Join; - -using MCTracks = soa::Join; - -struct nuclei_in_jets { - - // QC Histograms - HistogramRegistry registryQC{ - "registryQC", - {}, - OutputObjHandlingPolicy::AnalysisObject, - true, - true}; - - // Analysis Histograms: Data - HistogramRegistry registryData{ - "registryData", - {}, - OutputObjHandlingPolicy::AnalysisObject, - true, - true}; - - // Analysis Histograms: MC - HistogramRegistry registryMC{ - "registryMC", - {}, - OutputObjHandlingPolicy::AnalysisObject, - true, - true}; - - // Global Parameters - Configurable min_pt_leading{"min_pt_leading", 5.0f, "minimum pt of leading particle"}; - Configurable Rparameter_jet{"Rparameter_jet", 0.3f, "jet resolution parameter R"}; - Configurable Rmax_jet_ue{"Rmax_jet_ue", 0.3f, "Maximum radius"}; - Configurable particle_of_interest{"particle_of_interest", 0, "0=antiproton, 1=antideuteron, 2=antihelium3"}; - - // Track Parameters - Configurable min_ITS_nClusters{"min_ITS_nClusters", 4, "minimum number of found ITS clusters"}; - Configurable min_TPC_nClusters{"min_TPC_nClusters", 80, "minimum number of found TPC clusters"}; - Configurable min_TPC_nCrossedRows{"min_TPC_nCrossedRows", 80, "minimum number of TPC crossed pad rows"}; - Configurable max_chi2_TPC{"max_chi2_TPC", 4.0f, "maximum TPC chi^2/Ncls"}; - Configurable max_chi2_ITS{"max_chi2_ITS", 36.0f, "maximum ITS chi^2/Ncls"}; - Configurable min_pt{"min_pt", 0.2f, "minimum pt of the tracks"}; - Configurable min_eta{"min_eta", -0.8f, "minimum eta"}; - Configurable max_eta{"max_eta", +0.8f, "maximum eta"}; - Configurable min_y{"min_y", -0.5f, "minimum y"}; - Configurable max_y{"max_y", +0.5f, "maximum y"}; - Configurable max_dcaxy{"max_dcaxy", 0.1f, "Maximum DCAxy"}; - Configurable max_dcaz{"max_dcaz", 0.1f, "Maximum DCAz"}; - Configurable min_nsigmaTPC{"min_nsigmaTPC", -3.0f, "Minimum nsigma TPC"}; - Configurable max_nsigmaTPC{"max_nsigmaTPC", +3.0f, "Maximum nsigma TPC"}; - Configurable min_nsigmaTOF{"min_nsigmaTOF", -3.0f, "Minimum nsigma TOF"}; - Configurable max_nsigmaTOF{"max_nsigmaTOF", +3.5f, "Maximum nsigma TOF"}; - Configurable require_primVtx_contributor{"require_primVtx_contributor", true, "require that the track is a PV contributor"}; - Configurable applyReweighting{"applyReweighting", true, "apply Reweighting"}; - Configurable> param_proton_ref{"param_proton_ref", {0.000000000151, 984.796940000000, 0.458560000000, 0.000360000000}, "Parameters of Levi-Tsallis fit of Protons from pythia"}; - Configurable> param_proton_jet{"param_proton_jet", {0.025285984480, 4.271090000000, 0.511730000000, 2.261760000000}, "Parameters for reweighting protons in jets"}; - Configurable> param_deuteron_jet{"param_deuteron_jet", {20.121453090900, 2.096620000000, 1.000000000000, 1.875610000000}, "Parameters for reweighting deuterons in jets"}; - Configurable> param_helium3_jet{"param_helium3_jet", {0.00026, 2.09662, 1.00000, 1.87561}, "Parameters for reweighting helium3 in jets"}; - Configurable> param_proton_ue{"param_proton_ue", {0.000000977546, 88.480170000000, 0.539520000000, 0.062120000000}, "Parameters for reweighting protons in ue"}; - Configurable> param_deuteron_ue{"param_deuteron_ue", {0.000294563800, 25.000000000000, 0.514970000000, 1.000000000000}, "Parameters for reweighting deuterons in ue"}; - Configurable> param_helium3_ue{"param_helium3_ue", {0.00000, 25.00000, 0.51497, 1.00000}, "Parameters for reweighting helium3 in ue"}; - - // List of Particles - enum nucleus { proton, - deuteron, - helium }; - - enum region { jet, - underlying_event }; - - void init(InitContext const&) - { - // Global Properties and QC - registryQC.add("number_of_events_data", "number of events in data", HistType::kTH1F, {{15, 0, 15, "counter"}}); - registryQC.add("number_of_events_mc", "number of events in mc", HistType::kTH1F, {{10, 0, 10, "counter"}}); - registryQC.add("jet_plus_ue_multiplicity", "jet + underlying-event multiplicity", HistType::kTH1F, {{100, 0, 100, "#it{N}_{ch}"}}); - registryQC.add("jet_multiplicity", "jet multiplicity", HistType::kTH1F, {{100, 0, 100, "#it{N}_{ch}"}}); - registryQC.add("ue_multiplicity", "underlying-event multiplicity", HistType::kTH1F, {{100, 0, 100, "#it{N}_{ch}"}}); - registryQC.add("pt_leading", "pt leading", HistType::kTH1F, {{500, 0, 50, "#it{p}_{T} (GeV/#it{c})"}}); - registryQC.add("eta_phi_jet", "DeltaEta DeltaPhi jet", HistType::kTH2F, {{200, -0.5, 0.5, "#Delta#eta"}, {200, 0, 0.5 * TMath::Pi(), "#Delta#phi"}}); - registryQC.add("eta_phi_ue", "DeltaEta DeltaPhi UE", HistType::kTH2F, {{200, -0.5, 0.5, "#Delta#eta"}, {200, 0, 0.5 * TMath::Pi(), "#Delta#phi"}}); - registryQC.add("r_max_jet", "R Max jet", HistType::kTH1F, {{200, 0.0, 6.0, "#it{R}_{max}"}}); - registryQC.add("r_jet", "R jet", HistType::kTH1F, {{200, 0.0, 1.0, "#it{R}"}}); - registryQC.add("r_ue", "R ue", HistType::kTH1F, {{200, 0.0, 1.0, "#it{R}"}}); - registryQC.add("eta_leading", "eta_leading", HistType::kTH1F, {{100, -1, 1, "#eta"}}); - registryQC.add("phi_leading", "phi_leading", HistType::kTH1F, {{100, -TMath::Pi(), TMath::Pi(), "#phi"}}); - registryQC.add("angle_jet_leading_track", "angle_jet_leading_track", HistType::kTH1F, {{200, 0.0, TMath::Pi() / 4.0, "#theta"}}); - - // Antiprotons - registryData.add("antiproton_jet_tpc", "antiproton_jet_tpc", HistType::kTH3F, {{20, 0.0, 1.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}, {2, 0, 100, "#it{N}_{ch}"}}); - registryData.add("antiproton_jet_tof", "antiproton_jet_tof", HistType::kTH3F, {{90, 0.5, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}, {2, 0, 100, "#it{N}_{ch}"}}); - registryData.add("antiproton_ue_tpc", "antiproton_ue_tpc", HistType::kTH3F, {{20, 0.0, 1.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}, {2, 0, 100, "#it{N}_{ch}"}}); - registryData.add("antiproton_ue_tof", "antiproton_ue_tof", HistType::kTH3F, {{90, 0.5, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}, {2, 0, 100, "#it{N}_{ch}"}}); - - // Eta - pt Maps Antiprotons - registryData.add("antip_tpc_jet_eta_pt", "antip_tpc_jet_eta_pt", HistType::kTH2F, {{60, 0.0, 3.0, "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#eta"}}); - registryData.add("antip_tpc_ue_eta_pt", "antip_tpc_ue_eta_pt", HistType::kTH2F, {{60, 0.0, 3.0, "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#eta"}}); - registryData.add("antip_tof_jet_eta_pt", "antip_tof_jet_eta_pt", HistType::kTH2F, {{60, 0.0, 3.0, "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#eta"}}); - registryData.add("antip_tof_ue_eta_pt", "antip_tof_ue_eta_pt", HistType::kTH2F, {{60, 0.0, 3.0, "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#eta"}}); - - // DCA Distributions - registryData.add("antiproton_dca_jet", "antiproton_dca_jet", HistType::kTH3F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -0.5, 0.5, "DCA_{xy} (cm)"}, {2, 0, 100, "#it{N}_{ch}"}}); - registryData.add("antiproton_dca_ue", "antiproton_dca_ue", HistType::kTH3F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -0.5, 0.5, "DCA_{xy} (cm)"}, {2, 0, 100, "#it{N}_{ch}"}}); - - // Antideuterons - registryData.add("antideuteron_jet_tpc", "antideuteron_jet_tpc", HistType::kTH3F, {{10, 0.0, 1.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}, {2, 0, 100, "#it{N}_{ch}"}}); - registryData.add("antideuteron_jet_tof", "antideuteron_jet_tof", HistType::kTH3F, {{45, 0.5, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}, {2, 0, 100, "#it{N}_{ch}"}}); - registryData.add("antideuteron_ue_tpc", "antideuteron_ue_tpc", HistType::kTH3F, {{10, 0.0, 1.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}, {2, 0, 100, "#it{N}_{ch}"}}); - registryData.add("antideuteron_ue_tof", "antideuteron_ue_tof", HistType::kTH3F, {{45, 0.5, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}, {2, 0, 100, "#it{N}_{ch}"}}); - - // Antihelium-3 - registryData.add("antihelium3_jet_tpc", "antihelium3_jet_tpc", HistType::kTH3F, {{40, 1.0, 7.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -10.0, 10.0, "n#sigma_{TPC}"}, {2, 0, 100, "#it{N}_{ch}"}}); - registryData.add("antihelium3_ue_tpc", "antihelium3_ue_tpc", HistType::kTH3F, {{40, 1.0, 7.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -10.0, 10.0, "n#sigma_{TPC}"}, {2, 0, 100, "#it{N}_{ch}"}}); - - // Input Antiproton Distribution - registryMC.add("antiproton_input", "antiproton_input", HistType::kTH1F, {{1000, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antiproton_weighted_jet", "antiproton_weighted_jet", HistType::kTH1F, {{1000, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antiproton_weighted_ue", "antiproton_weighted_ue", HistType::kTH1F, {{1000, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - - // Generated - registryMC.add("antiproton_jet_gen", "antiproton_jet_gen", HistType::kTH1F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antideuteron_jet_gen", "antideuteron_jet_gen", HistType::kTH1F, {{50, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antihelium3_jet_gen", "antihelium3_jet_gen", HistType::kTH1F, {{40, 1.0, 7.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antiproton_ue_gen", "antiproton_ue_gen", HistType::kTH1F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antideuteron_ue_gen", "antideuteron_ue_gen", HistType::kTH1F, {{50, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antihelium3_ue_gen", "antihelium3_ue_gen", HistType::kTH1F, {{40, 1.0, 7.0, "#it{p}_{T} (GeV/#it{c})"}}); - - // Reconstructed TPC - registryMC.add("antiproton_jet_rec_tpc", "antiproton_jet_rec_tpc", HistType::kTH1F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antideuteron_jet_rec_tpc", "antideuteron_jet_rec_tpc", HistType::kTH1F, {{50, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antihelium3_jet_rec_tpc", "antihelium3_jet_rec_tpc", HistType::kTH1F, {{40, 1.0, 7.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antiproton_ue_rec_tpc", "antiproton_ue_rec_tpc", HistType::kTH1F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antideuteron_ue_rec_tpc", "antideuteron_ue_rec_tpc", HistType::kTH1F, {{50, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antihelium3_ue_rec_tpc", "antihelium3_ue_rec_tpc", HistType::kTH1F, {{40, 1.0, 7.0, "#it{p}_{T} (GeV/#it{c})"}}); - - // Reconstructed TOF - registryMC.add("antiproton_jet_rec_tof", "antiproton_jet_rec_tof", HistType::kTH1F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antideuteron_jet_rec_tof", "antideuteron_jet_rec_tof", HistType::kTH1F, {{50, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antiproton_ue_rec_tof", "antiproton_ue_rec_tof", HistType::kTH1F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antideuteron_ue_rec_tof", "antideuteron_ue_rec_tof", HistType::kTH1F, {{50, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - - // DCA Templates - registryMC.add("antiproton_dca_prim", "antiproton_dca_prim", HistType::kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -0.5, 0.5, "DCA_{xy} (cm)"}}); - registryMC.add("antiproton_dca_sec", "antiproton_dca_sec", HistType::kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -0.5, 0.5, "DCA_{xy} (cm)"}}); - - // Fraction of Primary Antiprotons from MC - registryMC.add("antiproton_prim", "antiproton_prim", HistType::kTH1F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antiproton_all", "antiproton_all", HistType::kTH1F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - - // Histograms for reweighting - registryMC.add("antiproton_eta_pt_pythia", "antiproton_eta_pt_pythia", HistType::kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {80, -0.8, 0.8, "#eta"}}); - registryMC.add("antideuteron_eta_pt", "antideuteron_eta_pt", HistType::kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {80, -0.8, 0.8, "#eta"}}); - registryMC.add("antiproton_eta_pt_jet", "antiproton_eta_pt_jet", HistType::kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {80, -0.8, 0.8, "#eta"}}); - registryMC.add("antiproton_eta_pt_ue", "antiproton_eta_pt_ue", HistType::kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {80, -0.8, 0.8, "#eta"}}); - } - - // Single-Track Selection for the Particle of Interest - template - bool passedTrackSelection(const T1& track) - { - if (!track.hasITS()) - return false; - if (track.itsNCls() < min_ITS_nClusters) - return false; - if (!track.hasTPC()) - return false; - if (track.tpcNClsFound() < min_TPC_nClusters) - return false; - if (track.tpcNClsCrossedRows() < min_TPC_nCrossedRows) - return false; - if (track.tpcChi2NCl() > max_chi2_TPC) - return false; - if (track.itsChi2NCl() > max_chi2_ITS) - return false; - if (track.eta() < min_eta || track.eta() > max_eta) - return false; - if (track.pt() < min_pt) - return false; - - // Rapidity Cut - double mass(0); - if (particle_of_interest == nucleus::proton) - mass = 0.93827208816; // Proton - if (particle_of_interest == nucleus::deuteron) - mass = 1.87561294257; // Deuteron - if (particle_of_interest == nucleus::helium) - mass = 2.80839160743; // Helium-3 - - TLorentzVector lorentzVect; - lorentzVect.SetXYZM(track.px(), track.py(), track.pz(), mass); - if (lorentzVect.Rapidity() < min_y || lorentzVect.Rapidity() > max_y) - return false; - - return true; - } - - // Single-Track Selection for Particles inside Jets - template - bool passedMinimalTrackSelection(const T2& track) - { - if (!track.hasITS()) - return false; - if (track.itsNCls() < 2) - return false; - if (!track.hasTPC()) - return false; - if (track.tpcNClsFound() < 70) - return false; - if (track.tpcNClsCrossedRows() < 70) - return false; - if (track.tpcChi2NCl() > 4) - return false; - if (track.itsChi2NCl() > 36) - return false; - if (track.eta() < -0.8 || track.eta() > 0.8) - return false; - if (track.pt() < 0.15) - return false; - if (TMath::Abs(track.dcaXY()) > 0.5) - return false; - if (TMath::Abs(track.dcaZ()) > 0.5) - return false; - - return true; - } - - template - bool isParticleOfInterest(const T3& track) - { - // Variables - float nsigmaTPCPr = track.tpcNSigmaPr(); - float nsigmaTOFPr = track.tofNSigmaPr(); - float nsigmaTPCDe = track.tpcNSigmaDe(); - float nsigmaTOFDe = track.tofNSigmaDe(); - float nsigmaTPCHe = track.tpcNSigmaHe(); - float pt = track.pt(); - - // Antimatter Only - if (track.sign() > 0) - return false; - - // Proton ID - if (particle_of_interest == nucleus::proton) { - if (pt < 1.0 && TMath::Abs(nsigmaTPCPr) < 8.0) - return true; - if (pt >= 1.0 && nsigmaTPCPr > min_nsigmaTPC && nsigmaTPCPr < max_nsigmaTPC && track.hasTOF() && TMath::Abs(nsigmaTOFPr) < 10.0) - return true; - return false; - } - - // Deuteron ID - if (particle_of_interest == nucleus::deuteron) { - if (pt < 1.0 && TMath::Abs(nsigmaTPCDe) < 8.0) - return true; - if (pt >= 1.0 && nsigmaTPCDe > min_nsigmaTPC && nsigmaTPCDe < max_nsigmaTPC && track.hasTOF() && TMath::Abs(nsigmaTOFDe) < 10.0) - return true; - return false; - } - - // Helium-3 ID - if (particle_of_interest == nucleus::helium) { - if ((0.5 * pt) >= 1.0 && TMath::Abs(nsigmaTPCHe) < 8.0) - return true; - return false; - } - - return false; - } - - template - bool isHighPurityAntiproton(const T4& track) - { - // Variables - float nsigmaTPCPr = track.tpcNSigmaPr(); - float nsigmaTOFPr = track.tofNSigmaPr(); - float pt = track.pt(); - - if (pt < 0.5 && TMath::Abs(nsigmaTPCPr) < 2.0) - return true; - if (pt >= 0.5 && TMath::Abs(nsigmaTPCPr) < 2.0 && track.hasTOF() && TMath::Abs(nsigmaTOFPr) < 2.0) - return true; - return false; - } - - // Minimum - float Minimum(float x1, float x2) - { - float x_min(x1); - if (x1 < x2) - x_min = x1; - if (x1 >= x2) - x_min = x2; - - return x_min; - } - - // Deltaphi - double GetDeltaPhi(double a1, double a2) - { - - double delta_phi(0); - - double phi1 = TVector2::Phi_0_2pi(a1); - double phi2 = TVector2::Phi_0_2pi(a2); - double diff = TMath::Abs(phi1 - phi2); - - if (diff <= TMath::Pi()) - delta_phi = diff; - if (diff > TMath::Pi()) - delta_phi = TMath::TwoPi() - diff; - - return delta_phi; - } - - float Weight(float pt, int event_region, int nucleus_of_interest) - { - - if (!applyReweighting) - return 1; - - auto par_proton_ref = static_cast>(param_proton_ref); - auto par_proton_jet = static_cast>(param_proton_jet); - auto par_deuteron_jet = static_cast>(param_deuteron_jet); - auto par_helium3_jet = static_cast>(param_helium3_jet); - auto par_proton_ue = static_cast>(param_proton_ue); - auto par_deuteron_ue = static_cast>(param_deuteron_ue); - auto par_helium3_ue = static_cast>(param_helium3_ue); - - float dNdpt_proton_ref = GetTsallis(par_proton_ref[0], par_proton_ref[1], par_proton_ref[2], par_proton_ref[3], pt); - float dNdpt_proton_jet = GetTsallis(par_proton_jet[0], par_proton_jet[1], par_proton_jet[2], par_proton_jet[3], pt); - float dNdpt_proton_ue = GetTsallis(par_proton_ue[0], par_proton_ue[1], par_proton_ue[2], par_proton_ue[3], pt); - float dNdpt_deuteron_jet = GetTsallis(par_deuteron_jet[0], par_deuteron_jet[1], par_deuteron_jet[2], par_deuteron_jet[3], pt); - float dNdpt_deuteron_ue = GetTsallis(par_deuteron_ue[0], par_deuteron_ue[1], par_deuteron_ue[2], par_deuteron_ue[3], pt); - float dNdpt_helium3_jet = GetTsallis(par_helium3_jet[0], par_helium3_jet[1], par_helium3_jet[2], par_helium3_jet[3], pt); - float dNdpt_helium3_ue = GetTsallis(par_helium3_ue[0], par_helium3_ue[1], par_helium3_ue[2], par_helium3_ue[3], pt); - - if (nucleus_of_interest == nucleus::proton && event_region == region::jet) - return dNdpt_proton_jet / dNdpt_proton_ref; - if (nucleus_of_interest == nucleus::proton && event_region == region::underlying_event) - return dNdpt_proton_ue / dNdpt_proton_ref; - if (nucleus_of_interest == nucleus::deuteron && event_region == region::jet) - return dNdpt_deuteron_jet; - if (nucleus_of_interest == nucleus::deuteron && event_region == region::underlying_event) - return dNdpt_deuteron_ue; - if (nucleus_of_interest == nucleus::helium && event_region == region::jet) - return dNdpt_helium3_jet; - if (nucleus_of_interest == nucleus::helium && event_region == region::underlying_event) - return dNdpt_helium3_ue; - - return 1; - } - - float GetTsallis(float p0, float p1, float p2, float p3, float pt) - { - - float dNdpt(1); - float part1 = p0 * pt * (p1 - 1.0) * (p1 - 2.0); - float part2 = part1 * TMath::Power(1.0 + (TMath::Sqrt(p3 * p3 + pt * pt) - p3) / (p1 * p2), -p1); - float part3 = part2 / TMath::TwoPi() * (p1 * p2 * (p1 * p2 + p3 * (p1 - 2.0))); - dNdpt = part3; - - return dNdpt; - } - - void get_perpendicular_cone(TVector3 p, TVector3& u, float sign) - { - - // Initialization - float ux(0), uy(0), uz(0); - - // Components of Vector p - float px = p.X(); - float py = p.Y(); - float pz = p.Z(); - - // Protection 1 - if (px == 0 && py != 0) { - - uy = -(pz * pz) / py; - ux = sign * sqrt(py * py - (pz * pz * pz * pz) / (py * py)); - uz = pz; - u.SetXYZ(ux, uy, uz); - return; - } - - // Protection 2 - if (py == 0 && px != 0) { - - ux = -(pz * pz) / px; - uy = sign * sqrt(px * px - (pz * pz * pz * pz) / (px * px)); - uz = pz; - u.SetXYZ(ux, uy, uz); - return; - } - - // Equation Parameters - float a = px * px + py * py; - float b = 2.0 * px * pz * pz; - float c = pz * pz * pz * pz - py * py * py * py - px * px * py * py; - float delta = b * b - 4.0 * a * c; - - // Protection agains delta<0 - if (delta < 0) { - return; - } - - // Solutions - ux = (-b + sign * sqrt(delta)) / (2.0 * a); - uy = (-pz * pz - px * ux) / py; - uz = pz; - u.SetXYZ(ux, uy, uz); - return; - } - - // Process Data - void processData(SelectedCollisions::iterator const& collision, FullTracks const& tracks) - { - - // Event Counter: before event selection - registryQC.fill(HIST("number_of_events_data"), 0.5); - - // Event Selection - if (!collision.sel8()) - return; - - // Event Counter: after event selection sel8 - registryQC.fill(HIST("number_of_events_data"), 1.5); - - // Cut on Zvertex - if (abs(collision.posZ()) > 10.0) - return; - - // Event Counter: after |z|<10 cm cut - registryQC.fill(HIST("number_of_events_data"), 2.5); - - // Reduced Event - std::vector particle_ID; - int leading_ID; - bool containsParticleOfInterest(false); - float pt_max(0); - - // Track Index Initialization - int i = -1; - - // Loop over Reconstructed Tracks - for (auto track : tracks) { - - // Track Index - i++; - - // Track Selection for Jet - if (!passedMinimalTrackSelection(track)) - continue; - if (!track.passedITSRefit()) - continue; - if (!track.passedTPCRefit()) - continue; - - // Trigger: Particle of Interest - if (isParticleOfInterest(track)) - containsParticleOfInterest = true; - - // Find pt Leading - if (track.pt() > pt_max) { - leading_ID = i; - pt_max = track.pt(); - } - - // Store Array Element - particle_ID.push_back(i); - } - - // Event Counter: Skip Events with no trigger Particle (pmax=0) - if (pt_max == 0) - return; - registryQC.fill(HIST("number_of_events_data"), 3.5); - - // Histogram with pt_leading - registryQC.fill(HIST("pt_leading"), pt_max); - - // Event Counter: Skip Events with pt(particle_ID.size()); - - // Event Counter: Skip Events with 0 Particles - if (nParticles < 1) - return; - registryQC.fill(HIST("number_of_events_data"), 5.5); - - // Momentum of the Leading Particle - auto const& leading_track = tracks.iteratorAt(leading_ID); - TVector3 p_leading(leading_track.px(), leading_track.py(), leading_track.pz()); - TVector3 p_highest_pt_track(leading_track.px(), leading_track.py(), leading_track.pz()); - - // Event Counter: Skip Events with no Particle of Interest - if (!containsParticleOfInterest) - return; - registryQC.fill(HIST("number_of_events_data"), 6.5); - - // Array of Particles inside Jet - std::vector jet_particle_ID; - jet_particle_ID.push_back(leading_ID); - - // Labels - Int_t exit(0); - Int_t nPartAssociated(0); - - // Jet Finder - do { - // Initialization - float distance_jet_min(1e+08); - float distance_bkg_min(1e+08); - int label_jet_particle(0); - int i_jet_particle(0); - - for (int i = 0; i < nParticles; i++) { - - // Skip Leading Particle & Elements already associated to the Jet - if (particle_ID[i] == leading_ID || particle_ID[i] == -1) - continue; - - // Get Particle Momentum - auto stored_track = tracks.iteratorAt(particle_ID[i]); - TVector3 p_particle(stored_track.px(), stored_track.py(), stored_track.pz()); - - // Variables - float one_over_pt2_part = 1.0 / (p_particle.Pt() * p_particle.Pt()); - float one_over_pt2_lead = 1.0 / (p_leading.Pt() * p_leading.Pt()); - float deltaEta = p_particle.Eta() - p_leading.Eta(); - float deltaPhi = GetDeltaPhi(p_particle.Phi(), p_leading.Phi()); - float min = Minimum(one_over_pt2_part, one_over_pt2_lead); - float Delta2 = deltaEta * deltaEta + deltaPhi * deltaPhi; - - // Distances - float distance_jet = min * Delta2 / (Rparameter_jet * Rparameter_jet); - float distance_bkg = one_over_pt2_part; - - // Find Minimum Distance Jet - if (distance_jet < distance_jet_min) { - distance_jet_min = distance_jet; - label_jet_particle = particle_ID[i]; - i_jet_particle = i; - } - - // Find Minimum Distance Bkg - if (distance_bkg < distance_bkg_min) { - distance_bkg_min = distance_bkg; - } - } - - if (distance_jet_min <= distance_bkg_min) { - - // Add Particle to Jet - jet_particle_ID.push_back(label_jet_particle); - - // Update Momentum of Leading Particle - auto jet_track = tracks.iteratorAt(label_jet_particle); - TVector3 p_i(jet_track.px(), jet_track.py(), jet_track.pz()); - p_leading = p_leading + p_i; - - // Remove Element - particle_ID[i_jet_particle] = -1; - nPartAssociated++; - } - - if (nPartAssociated >= (nParticles - 1)) - exit = 1; - if (distance_jet_min > distance_bkg_min) - exit = 2; - - } while (exit == 0); - - // Multiplicity inside Jet + UE - int nParticlesJetUE = static_cast(jet_particle_ID.size()); - - // QA Plots - registryQC.fill(HIST("eta_leading"), p_leading.Eta()); - registryQC.fill(HIST("phi_leading"), TVector2::Phi_0_2pi(p_leading.Phi())); - registryQC.fill(HIST("angle_jet_leading_track"), p_leading.Angle(p_highest_pt_track)); - - // Rmax and Area Cut - float Rmax(0); - int nParticlesJetAndUE(0); - for (int i = 0; i < nParticlesJetUE; i++) { - - const auto& jet_track = tracks.iteratorAt(jet_particle_ID[i]); - TVector3 p_i(jet_track.px(), jet_track.py(), jet_track.pz()); - - float deltaEta = p_i.Eta() - p_leading.Eta(); - float deltaPhi = GetDeltaPhi(p_i.Phi(), p_leading.Phi()); - float R = TMath::Sqrt(deltaEta * deltaEta + deltaPhi * deltaPhi); - if (R < Rmax_jet_ue) - nParticlesJetAndUE++; - if (R > Rmax) - Rmax = R; - } - - // Rmax Distribution - registryQC.fill(HIST("r_max_jet"), Rmax); - - // Event Counter: Skip Events with jet not fully inside acceptance - float eta_jet_axis = p_leading.Eta(); - if ((TMath::Abs(eta_jet_axis) + Rmax_jet_ue) > max_eta) - return; - registryQC.fill(HIST("number_of_events_data"), 7.5); - - // Fill Jet Multiplicity - registryQC.fill(HIST("jet_plus_ue_multiplicity"), nParticlesJetAndUE); - - // Perpendicular Cones for UE Estimate - TVector3 ue_axis1(0.0, 0.0, 0.0); - TVector3 ue_axis2(0.0, 0.0, 0.0); - get_perpendicular_cone(p_leading, ue_axis1, +1.0); - get_perpendicular_cone(p_leading, ue_axis2, -1.0); - - // Protection against delta<0 - if (ue_axis1.X() == 0 && ue_axis1.Y() == 0 && ue_axis1.Z() == 0) - return; - if (ue_axis2.X() == 0 && ue_axis2.Y() == 0 && ue_axis2.Z() == 0) - return; - - registryQC.fill(HIST("number_of_events_data"), 8.5); - - // Store UE - std::vector ue_particle_ID; - - for (int i = 0; i < nParticles; i++) { - - // Skip Leading Particle & Elements already associated to the Jet - if (particle_ID[i] == leading_ID || particle_ID[i] == -1) - continue; - - // Get UE Track - const auto& ue_track = tracks.iteratorAt(particle_ID[i]); - - // Variables - float deltaEta1 = ue_track.eta() - ue_axis1.Eta(); - float deltaPhi1 = GetDeltaPhi(ue_track.phi(), ue_axis1.Phi()); - float dr1 = TMath::Sqrt(deltaEta1 * deltaEta1 + deltaPhi1 * deltaPhi1); - float deltaEta2 = ue_track.eta() - ue_axis2.Eta(); - float deltaPhi2 = GetDeltaPhi(ue_track.phi(), ue_axis2.Phi()); - float dr2 = TMath::Sqrt(deltaEta2 * deltaEta2 + deltaPhi2 * deltaPhi2); - - // Store Particles in the UE - if (dr1 < Rmax_jet_ue) { - registryQC.fill(HIST("eta_phi_ue"), deltaEta1, deltaPhi1); - registryQC.fill(HIST("r_ue"), dr1); - ue_particle_ID.push_back(particle_ID[i]); - } - - if (dr2 < Rmax_jet_ue) { - registryQC.fill(HIST("eta_phi_ue"), deltaEta2, deltaPhi2); - registryQC.fill(HIST("r_ue"), dr2); - ue_particle_ID.push_back(particle_ID[i]); - } - } - - // UE Multiplicity - int nParticlesUE = static_cast(ue_particle_ID.size()); - registryQC.fill(HIST("ue_multiplicity"), static_cast(nParticlesUE) / 2.0); - - // Jet Multiplicity - float jet_Nch = static_cast(nParticlesJetAndUE) - static_cast(nParticlesUE) / 2.0; - registryQC.fill(HIST("jet_multiplicity"), jet_Nch); - - // Loop over particles inside Jet - for (int i = 0; i < nParticlesJetUE; i++) { - - const auto& jet_track = tracks.iteratorAt(jet_particle_ID[i]); - TVector3 p_i(jet_track.px(), jet_track.py(), jet_track.pz()); - - float deltaEta = p_i.Eta() - p_leading.Eta(); - float deltaPhi = GetDeltaPhi(p_i.Phi(), p_leading.Phi()); - float R = TMath::Sqrt(deltaEta * deltaEta + deltaPhi * deltaPhi); - if (R > Rmax_jet_ue) - continue; - - if (deltaEta != 0 && deltaPhi != 0) { - registryQC.fill(HIST("eta_phi_jet"), deltaEta, deltaPhi); - registryQC.fill(HIST("r_jet"), TMath::Sqrt(deltaEta * deltaEta + deltaPhi * deltaPhi)); - } - - // Track Selection - if (!passedTrackSelection(jet_track)) - continue; - if (require_primVtx_contributor && !(jet_track.isPVContributor())) - continue; - - // Variables - float nsigmaTPCPr = jet_track.tpcNSigmaPr(); - float nsigmaTOFPr = jet_track.tofNSigmaPr(); - float nsigmaTPCDe = jet_track.tpcNSigmaDe(); - float nsigmaTOFDe = jet_track.tofNSigmaDe(); - float nsigmaTPCHe = jet_track.tpcNSigmaHe(); - float pt = jet_track.pt(); - float eta = jet_track.eta(); - - // DCA - if (isHighPurityAntiproton(jet_track) && TMath::Abs(jet_track.dcaZ()) < max_dcaz) { - registryData.fill(HIST("antiproton_dca_jet"), pt, jet_track.dcaXY(), jet_Nch); - } - - // DCA Cuts - if (TMath::Abs(jet_track.dcaXY()) > max_dcaxy) - continue; - if (TMath::Abs(jet_track.dcaZ()) > max_dcaz) - continue; - - // Antiproton - if (particle_of_interest == nucleus::proton) { - if (pt < 1.0) - registryData.fill(HIST("antiproton_jet_tpc"), pt, nsigmaTPCPr, jet_Nch); - if (pt >= 0.5 && nsigmaTPCPr > min_nsigmaTPC && nsigmaTPCPr < max_nsigmaTPC && jet_track.hasTOF()) - registryData.fill(HIST("antiproton_jet_tof"), pt, nsigmaTOFPr, jet_Nch); - if (pt < 1.0 && TMath::Abs(nsigmaTPCPr) < 2.0) - registryData.fill(HIST("antip_tpc_jet_eta_pt"), pt, eta); - if (pt >= 0.5 && TMath::Abs(nsigmaTPCPr) < 2.0 && jet_track.hasTOF() && TMath::Abs(nsigmaTOFPr) < 2.0) - registryData.fill(HIST("antip_tof_jet_eta_pt"), pt, eta); - } - - // Antideuteron - if (particle_of_interest == nucleus::deuteron) { - if (pt < 1.0) - registryData.fill(HIST("antideuteron_jet_tpc"), pt, nsigmaTPCDe, jet_Nch); - if (pt >= 0.5 && nsigmaTPCDe > min_nsigmaTPC && nsigmaTPCDe < max_nsigmaTPC && jet_track.hasTOF()) - registryData.fill(HIST("antideuteron_jet_tof"), pt, nsigmaTOFDe, jet_Nch); - } - - // Antihelium3 - if (particle_of_interest == nucleus::helium) { - registryData.fill(HIST("antihelium3_jet_tpc"), 2.0 * pt, nsigmaTPCHe, jet_Nch); - } - } - - // Loop over particles inside UE - for (int i = 0; i < nParticlesUE; i++) { - - const auto& ue_track = tracks.iteratorAt(ue_particle_ID[i]); - - // Track Selection - if (!passedTrackSelection(ue_track)) - continue; - if (require_primVtx_contributor && !(ue_track.isPVContributor())) - continue; - - // Variables - float nsigmaTPCPr = ue_track.tpcNSigmaPr(); - float nsigmaTOFPr = ue_track.tofNSigmaPr(); - float nsigmaTPCDe = ue_track.tpcNSigmaDe(); - float nsigmaTOFDe = ue_track.tofNSigmaDe(); - float nsigmaTPCHe = ue_track.tpcNSigmaHe(); - float pt = ue_track.pt(); - float eta = ue_track.eta(); - - // DCA - if (isHighPurityAntiproton(ue_track) && TMath::Abs(ue_track.dcaZ()) < max_dcaz) { - registryData.fill(HIST("antiproton_dca_ue"), pt, ue_track.dcaXY(), jet_Nch); - } - - // DCA Cuts - if (TMath::Abs(ue_track.dcaXY()) > max_dcaxy) - continue; - if (TMath::Abs(ue_track.dcaZ()) > max_dcaz) - continue; - - // Antiproton - if (particle_of_interest == nucleus::proton) { - if (pt < 1.0) - registryData.fill(HIST("antiproton_ue_tpc"), pt, nsigmaTPCPr, jet_Nch); - if (pt >= 0.5 && nsigmaTPCPr > min_nsigmaTPC && nsigmaTPCPr < max_nsigmaTPC && ue_track.hasTOF()) - registryData.fill(HIST("antiproton_ue_tof"), pt, nsigmaTOFPr, jet_Nch); - if (pt < 1.0 && TMath::Abs(nsigmaTPCPr) < 2.0) - registryData.fill(HIST("antip_tpc_ue_eta_pt"), pt, eta); - if (pt >= 0.5 && TMath::Abs(nsigmaTPCPr) < 2.0 && ue_track.hasTOF() && TMath::Abs(nsigmaTOFPr) < 2.0) - registryData.fill(HIST("antip_tof_ue_eta_pt"), pt, eta); - } - - // Antideuteron - if (particle_of_interest == nucleus::deuteron) { - if (pt < 1.0) - registryData.fill(HIST("antideuteron_ue_tpc"), pt, nsigmaTPCDe, jet_Nch); - if (pt >= 0.5 && nsigmaTPCDe > min_nsigmaTPC && nsigmaTPCDe < max_nsigmaTPC && ue_track.hasTOF()) - registryData.fill(HIST("antideuteron_ue_tof"), pt, nsigmaTOFDe, jet_Nch); - } - - // Antihelium3 - if (particle_of_interest == nucleus::helium) { - registryData.fill(HIST("antihelium3_ue_tpc"), 2.0 * pt, nsigmaTPCHe, jet_Nch); - } - } - - } // end processData - PROCESS_SWITCH(nuclei_in_jets, processData, "Process data", true); - - Preslice perMCCollision = o2::aod::mcparticle::mcCollisionId; - Preslice perCollision = o2::aod::track::collisionId; - - void processGen(o2::aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) - { - for (const auto& mccollision : mcCollisions) { - - // Event Counter (before event sel) - registryQC.fill(HIST("number_of_events_mc"), 0.5); - - auto mcParticles_per_coll = mcParticles.sliceBy(perMCCollision, mccollision.globalIndex()); - - // Generated Particles - for (auto& particle : mcParticles_per_coll) { - - if (!particle.isPhysicalPrimary()) - continue; - if ((particle.pdgCode() != -2212) && (particle.pdgCode() != -1000010020) && (particle.pdgCode() != -1000020030)) - continue; - if (particle.y() < min_y || particle.y() > max_y) - continue; - - // Reweighting - float wpr_jet = Weight(particle.pt(), region::jet, nucleus::proton); - float wpr_ue = Weight(particle.pt(), region::underlying_event, nucleus::proton); - float wde_jet = Weight(particle.pt(), region::jet, nucleus::deuteron); - float wde_ue = Weight(particle.pt(), region::underlying_event, nucleus::deuteron); - float whe_jet = Weight(particle.pt(), region::jet, nucleus::helium); - float whe_ue = Weight(particle.pt(), region::underlying_event, nucleus::helium); - - // Fill Histograms - if (particle.pdgCode() == -2212) { - registryMC.fill(HIST("antiproton_input"), particle.pt()); - registryMC.fill(HIST("antiproton_weighted_jet"), particle.pt(), wpr_jet); - registryMC.fill(HIST("antiproton_weighted_ue"), particle.pt(), wpr_ue); - registryMC.fill(HIST("antiproton_jet_gen"), particle.pt(), wpr_jet); - registryMC.fill(HIST("antiproton_ue_gen"), particle.pt(), wpr_ue); - registryMC.fill(HIST("antiproton_eta_pt_pythia"), particle.pt(), particle.eta()); - } - if (particle.pdgCode() == -1000010020) { - registryMC.fill(HIST("antideuteron_jet_gen"), particle.pt(), wde_jet); - registryMC.fill(HIST("antideuteron_ue_gen"), particle.pt(), wde_ue); - registryMC.fill(HIST("antideuteron_eta_pt"), particle.pt(), particle.eta()); - } - if (particle.pdgCode() == -1000020030) { - registryMC.fill(HIST("antihelium3_jet_gen"), particle.pt(), whe_jet); - registryMC.fill(HIST("antihelium3_ue_gen"), particle.pt(), whe_ue); - } - } - } - } - - void processRec(SimCollisions const& collisions, MCTracks const& mcTracks, aod::McCollisions const&, const aod::McParticles&) - { - - for (const auto& collision : collisions) { - - // Event Counter (before event sel) - registryQC.fill(HIST("number_of_events_mc"), 1.5); - - // Event Selection - if (!collision.sel8()) - continue; - - if (abs(collision.posZ()) > 10) - continue; - - // Event Counter (after event sel) - registryQC.fill(HIST("number_of_events_mc"), 2.5); - - auto tracks_per_coll = mcTracks.sliceBy(perCollision, collision.globalIndex()); - - // Reconstructed Tracks - for (auto track : tracks_per_coll) { - - // Get MC Particle - if (!track.has_mcParticle()) - continue; - - const auto particle = track.mcParticle(); - if ((particle.pdgCode() != -2212) && (particle.pdgCode() != -1000010020) && (particle.pdgCode() != -1000020030)) - continue; - - if (!track.passedITSRefit()) - continue; - if (!track.passedTPCRefit()) - continue; - - // Track Selection - if (!passedTrackSelection(track)) - continue; - if (require_primVtx_contributor && !(track.isPVContributor())) - continue; - - // Reweighting - float wpr_jet = Weight(particle.pt(), region::jet, nucleus::proton); - float wpr_ue = Weight(particle.pt(), region::underlying_event, nucleus::proton); - float wde_jet = Weight(particle.pt(), region::jet, nucleus::deuteron); - float wde_ue = Weight(particle.pt(), region::underlying_event, nucleus::deuteron); - float whe_jet = Weight(particle.pt(), region::jet, nucleus::helium); - float whe_ue = Weight(particle.pt(), region::underlying_event, nucleus::helium); - - // Variables - float nsigmaTPCPr = track.tpcNSigmaPr(); - float nsigmaTOFPr = track.tofNSigmaPr(); - float nsigmaTPCDe = track.tpcNSigmaDe(); - float nsigmaTOFDe = track.tofNSigmaDe(); - float nsigmaTPCHe = track.tpcNSigmaHe(); - float pt = track.pt(); - - // DCA Templates - if (particle.pdgCode() == -2212 && particle.isPhysicalPrimary() && TMath::Abs(track.dcaZ()) < max_dcaz) - registryMC.fill(HIST("antiproton_dca_prim"), pt, track.dcaXY()); - - if (particle.pdgCode() == -2212 && (!particle.isPhysicalPrimary()) && TMath::Abs(track.dcaZ()) < max_dcaz) - registryMC.fill(HIST("antiproton_dca_sec"), pt, track.dcaXY()); - - // DCA Cuts - if (TMath::Abs(track.dcaXY()) > max_dcaxy) - continue; - if (TMath::Abs(track.dcaZ()) > max_dcaz) - continue; - - // Fraction of Primary Antiprotons - if (particle.pdgCode() == -2212) { - registryMC.fill(HIST("antiproton_all"), pt); - if (particle.isPhysicalPrimary()) { - registryMC.fill(HIST("antiproton_prim"), pt); - } - } - - if (!particle.isPhysicalPrimary()) - continue; - - // Antiproton - if (particle.pdgCode() == -2212) { - if (pt < 1.0 && nsigmaTPCPr > min_nsigmaTPC && nsigmaTPCPr < max_nsigmaTPC) { - registryMC.fill(HIST("antiproton_jet_rec_tpc"), pt, wpr_jet); - registryMC.fill(HIST("antiproton_ue_rec_tpc"), pt, wpr_ue); - } - if (pt >= 0.5 && nsigmaTPCPr > min_nsigmaTPC && nsigmaTPCPr < max_nsigmaTPC && track.hasTOF() && nsigmaTOFPr > min_nsigmaTOF && nsigmaTOFPr < max_nsigmaTOF) { - registryMC.fill(HIST("antiproton_jet_rec_tof"), pt, wpr_jet); - registryMC.fill(HIST("antiproton_ue_rec_tof"), pt, wpr_ue); - } - } - - // Antideuteron - if (particle.pdgCode() == -1000010020) { - if (pt < 1.0 && nsigmaTPCDe > min_nsigmaTPC && nsigmaTPCDe < max_nsigmaTPC) { - registryMC.fill(HIST("antideuteron_jet_rec_tpc"), pt, wde_jet); - registryMC.fill(HIST("antideuteron_ue_rec_tpc"), pt, wde_ue); - } - if (pt >= 0.5 && nsigmaTPCDe > min_nsigmaTPC && nsigmaTPCDe < max_nsigmaTPC && track.hasTOF() && nsigmaTOFDe > min_nsigmaTOF && nsigmaTOFDe < max_nsigmaTOF) { - registryMC.fill(HIST("antideuteron_jet_rec_tof"), pt, wde_jet); - registryMC.fill(HIST("antideuteron_ue_rec_tof"), pt, wde_ue); - } - } - - // Antihelium-3 - if (particle.pdgCode() == -1000020030) { - if (nsigmaTPCHe > min_nsigmaTPC && nsigmaTPCHe < max_nsigmaTPC) { - registryMC.fill(HIST("antihelium3_jet_rec_tpc"), 2.0 * pt, whe_jet); - registryMC.fill(HIST("antihelium3_ue_rec_tpc"), 2.0 * pt, whe_ue); - } - } - } - } - } - - void processWeights(o2::aod::McCollisions const& mcCollisions, - aod::McParticles const& mcParticles) - { - - for (const auto& mccollision : mcCollisions) { - - if (abs(mccollision.posZ()) > 10) - continue; - - auto mcParticles_per_coll = - mcParticles.sliceBy(perMCCollision, mccollision.globalIndex()); - - // Reduced Event - std::vector particle_ID; - int leading_ID; - float pt_max(0); - - // Track Index Initialization - int i = -1; - - // Generated Particles - for (auto& particle : mcParticles_per_coll) { - - if (!particle.isPhysicalPrimary()) - continue; - if (particle.pdgCode() != -2212) - continue; - - // Index - i++; - - // Find pt Leading - if (particle.pt() > pt_max) { - leading_ID = i; - pt_max = particle.pt(); - } - - // Store Array Element - particle_ID.push_back(i); - } - - // Skip Events with pt(particle_ID.size()); - - // Momentum of the Leading Particle - auto const& leading_track = mcParticles_per_coll.iteratorAt(leading_ID); - TVector3 p_leading(leading_track.px(), leading_track.py(), - leading_track.pz()); - - // Array of Particles inside Jet - std::vector jet_particle_ID; - jet_particle_ID.push_back(leading_ID); - - // Labels - Int_t exit(0); - Int_t nPartAssociated(0); - - // Jet Finder - do { - // Initialization - float distance_jet_min(1e+08); - float distance_bkg_min(1e+08); - int label_jet_particle(0); - int i_jet_particle(0); - - for (int i = 0; i < nParticles; i++) { - - // Skip Leading Particle & Elements already associated to the Jet - if (particle_ID[i] == leading_ID || particle_ID[i] == -1) - continue; - - // Get Particle Momentum - auto stored_track = mcParticles_per_coll.iteratorAt(particle_ID[i]); - TVector3 p_particle(stored_track.px(), stored_track.py(), - stored_track.pz()); - - // Variables - float one_over_pt2_part = 1.0 / (p_particle.Pt() * p_particle.Pt()); - float one_over_pt2_lead = 1.0 / (p_leading.Pt() * p_leading.Pt()); - float deltaEta = p_particle.Eta() - p_leading.Eta(); - float deltaPhi = GetDeltaPhi(p_particle.Phi(), p_leading.Phi()); - float min = Minimum(one_over_pt2_part, one_over_pt2_lead); - float Delta2 = deltaEta * deltaEta + deltaPhi * deltaPhi; - - // Distances - float distance_jet = min * Delta2 / (Rparameter_jet * Rparameter_jet); - float distance_bkg = one_over_pt2_part; - - // Find Minimum Distance Jet - if (distance_jet < distance_jet_min) { - distance_jet_min = distance_jet; - label_jet_particle = particle_ID[i]; - i_jet_particle = i; - } - - // Find Minimum Distance Bkg - if (distance_bkg < distance_bkg_min) { - distance_bkg_min = distance_bkg; - } - } - - if (distance_jet_min <= distance_bkg_min) { - - // Add Particle to Jet - jet_particle_ID.push_back(label_jet_particle); - - // Update Momentum of Leading Particle - auto jet_track = mcParticles_per_coll.iteratorAt(label_jet_particle); - TVector3 p_i(jet_track.px(), jet_track.py(), jet_track.pz()); - p_leading = p_leading + p_i; - - // Remove Element - particle_ID[i_jet_particle] = -1; - nPartAssociated++; - } - - if (nPartAssociated >= (nParticles - 1)) - exit = 1; - if (distance_jet_min > distance_bkg_min) - exit = 2; - - } while (exit == 0); - - // Multiplicity inside Jet + UE - int nParticlesJetUE = static_cast(jet_particle_ID.size()); - - // Event Counter: Skip Events with jet not fully inside acceptance - float eta_jet_axis = p_leading.Eta(); - if ((TMath::Abs(eta_jet_axis) + Rmax_jet_ue) > max_eta) - return; - - // Perpendicular Cones for UE Estimate - TVector3 ue_axis1(0.0, 0.0, 0.0); - TVector3 ue_axis2(0.0, 0.0, 0.0); - get_perpendicular_cone(p_leading, ue_axis1, +1.0); - get_perpendicular_cone(p_leading, ue_axis2, -1.0); - - // Protection against delta<0 - if (ue_axis1.X() == 0 && ue_axis1.Y() == 0 && ue_axis1.Z() == 0) - return; - if (ue_axis2.X() == 0 && ue_axis2.Y() == 0 && ue_axis2.Z() == 0) - return; - - // Store UE - std::vector ue_particle_ID; - - for (int i = 0; i < nParticles; i++) { - - // Skip Leading Particle & Elements already associated to the Jet - if (particle_ID[i] == leading_ID || particle_ID[i] == -1) - continue; - - // Get UE Track - const auto& ue_track = mcParticles_per_coll.iteratorAt(particle_ID[i]); - - // Variables - float deltaEta1 = ue_track.eta() - ue_axis1.Eta(); - float deltaPhi1 = GetDeltaPhi(ue_track.phi(), ue_axis1.Phi()); - float dr1 = TMath::Sqrt(deltaEta1 * deltaEta1 + deltaPhi1 * deltaPhi1); - float deltaEta2 = ue_track.eta() - ue_axis2.Eta(); - float deltaPhi2 = GetDeltaPhi(ue_track.phi(), ue_axis2.Phi()); - float dr2 = TMath::Sqrt(deltaEta2 * deltaEta2 + deltaPhi2 * deltaPhi2); - - // Store Particles in the UE - if (dr1 < Rmax_jet_ue) { - ue_particle_ID.push_back(particle_ID[i]); - } - - if (dr2 < Rmax_jet_ue) { - ue_particle_ID.push_back(particle_ID[i]); - } - } - - // UE Multiplicity - int nParticlesUE = static_cast(ue_particle_ID.size()); - - // Loop over particles inside Jet - for (int i = 0; i < nParticlesJetUE; i++) { - - const auto& jet_track = mcParticles_per_coll.iteratorAt(particle_ID[i]); - - float deltaEta = jet_track.eta() - p_leading.Eta(); - float deltaPhi = GetDeltaPhi(jet_track.phi(), p_leading.Phi()); - float R = TMath::Sqrt(deltaEta * deltaEta + deltaPhi * deltaPhi); - if (R > Rmax_jet_ue) - continue; - - registryMC.fill(HIST("antiproton_eta_pt_jet"), jet_track.pt(), - jet_track.eta()); - } - // Loop over particles inside UE - for (int i = 0; i < nParticlesUE; i++) { - - const auto& ue_track = mcParticles_per_coll.iteratorAt(ue_particle_ID[i]); - registryMC.fill(HIST("antiproton_eta_pt_ue"), ue_track.pt(), - ue_track.eta()); - } - } - } - - PROCESS_SWITCH(nuclei_in_jets, processGen, "process Gen MC", false); - PROCESS_SWITCH(nuclei_in_jets, processRec, "process Rec MC", false); - PROCESS_SWITCH(nuclei_in_jets, processWeights, "process Weights MC", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} diff --git a/PWGLF/Tasks/Nuspex/nuclei_in_toward_transv_regions.cxx b/PWGLF/Tasks/Nuspex/nuclei_in_toward_transv_regions.cxx new file mode 100644 index 00000000000..a64ba6dc09c --- /dev/null +++ b/PWGLF/Tasks/Nuspex/nuclei_in_toward_transv_regions.cxx @@ -0,0 +1,392 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \author Alberto Caliva (alberto.caliva@cern.ch) +/// \since August 22, 2024 + +#include +#include +#include +#include +#include +#include +#include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/DataTypes.h" +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/DCA.h" +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" + +using namespace std; +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; +using std::array; + +using SelectedCollisions = soa::Join; +using SimCollisions = soa::Join; + +using FullTracks = soa::Join; + +using MCTracks = soa::Join; + +struct nuclei_in_toward_transv_regions { + + // Analysis Histograms: Data + HistogramRegistry registryData{ + "registryData", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; + + // Analysis Histograms: MC + HistogramRegistry registryMC{ + "registryMC", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; + + // Global Parameters + Configurable min_pt_leading{"min_pt_leading", 5.0, "Minimum pt of leading particle"}; + Configurable zVtx{"zVtx", 10.0, "Maximum zVertex"}; + + // Track Parameters + Configurable min_ITS_nClusters{"min_ITS_nClusters", 5, "minimum number of ITS clusters"}; + Configurable min_TPC_nClusters{"min_TPC_nClusters", 80, "minimum number of TPC clusters"}; + Configurable min_TPC_nCrossedRows{"min_TPC_nCrossedRows", 80, "minimum number of TPC crossed pad rows"}; + Configurable max_chi2_TPC{"max_chi2_TPC", 4.0, "maximum TPC chi^2/Ncls"}; + Configurable max_chi2_ITS{"max_chi2_ITS", 36.0, "maximum ITS chi^2/Ncls"}; + Configurable min_pt{"min_pt", 0.3, "minimum pt of the tracks"}; + Configurable min_eta{"min_eta", -0.8, "minimum eta"}; + Configurable max_eta{"max_eta", +0.8, "maximum eta"}; + Configurable min_y{"min_y", -0.5, "minimum y"}; + Configurable max_y{"max_y", +0.5, "maximum y"}; + Configurable max_dcaxy{"max_dcaxy", 0.1, "Maximum DCAxy"}; + Configurable max_dcaz{"max_dcaz", 0.1, "Maximum DCAz"}; + Configurable min_nsigmaTPC{"min_nsigmaTPC", -3.0, "Minimum nsigma TPC"}; + Configurable max_nsigmaTPC{"max_nsigmaTPC", +3.0, "Maximum nsigma TPC"}; + Configurable min_nsigmaTOF{"min_nsigmaTOF", -3.0, "Minimum nsigma TOF"}; + Configurable max_nsigmaTOF{"max_nsigmaTOF", +3.5, "Maximum nsigma TOF"}; + Configurable require_PV_contributor{"require_PV_contributor", true, "require that the track is a PV contributor"}; + + void init(InitContext const&) + { + // Event Counters + registryData.add("number_of_events_data", "number of events in data", HistType::kTH1F, {{10, 0, 10, "counter"}}); + registryMC.add("number_of_events_mc", "number of events in mc", HistType::kTH1F, {{10, 0, 10, "counter"}}); + + // Data + registryData.add("antiproton_jet_tpc", "antiproton_jet_tpc", HistType::kTH2F, {{120, 0.0, 6.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("antiproton_jet_tof", "antiproton_jet_tof", HistType::kTH2F, {{120, 0.0, 6.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); + registryData.add("antiproton_ue_tpc", "antiproton_ue_tpc", HistType::kTH2F, {{120, 0.0, 6.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("antiproton_ue_tof", "antiproton_ue_tof", HistType::kTH2F, {{120, 0.0, 6.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); + + // MC + registryMC.add("antiproton_prim_jet", "antiproton_prim_jet", HistType::kTH1F, {{120, 0.0, 6.0, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_all_jet", "antiproton_all_jet", HistType::kTH1F, {{120, 0.0, 6.0, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_prim_ue", "antiproton_prim_ue", HistType::kTH1F, {{120, 0.0, 6.0, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_all_ue", "antiproton_all_ue", HistType::kTH1F, {{120, 0.0, 6.0, "#it{p}_{T} (GeV/#it{c})"}}); + } + + // Single-Track Selection for Particles inside Jets + template + bool passedTrackSelectionForJetReconstruction(const JetTrackType& track) + { + if (!track.hasITS()) + return false; + if (track.itsNCls() < 3) + return false; + if (!track.hasTPC()) + return false; + if (track.tpcNClsCrossedRows() < 70) + return false; + if (track.tpcChi2NCl() > 4) + return false; + if (track.itsChi2NCl() > 36) + return false; + if (track.eta() < -0.8 || track.eta() > 0.8) + return false; + if (track.pt() < 0.1) + return false; + if (TMath::Abs(track.dcaXY()) > (0.004f + 0.013f / track.pt())) + return false; + if (TMath::Abs(track.dcaZ()) > 2.0) + return false; + + return true; + } + + // Single-Track Selection + template + bool passedTrackSelection(const TrackType& track) + { + if (!track.hasITS()) + return false; + if (track.itsNCls() < min_ITS_nClusters) + return false; + if (!track.hasTPC()) + return false; + if (track.tpcNClsFound() < min_TPC_nClusters) + return false; + if (track.tpcNClsCrossedRows() < min_TPC_nCrossedRows) + return false; + if (track.tpcChi2NCl() > max_chi2_TPC) + return false; + if (track.itsChi2NCl() > max_chi2_ITS) + return false; + if (track.eta() < min_eta || track.eta() > max_eta) + return false; + if (track.pt() < min_pt) + return false; + + return true; + } + + // Rapidity + double get_rapidity(double px, double py, double pz, double mass) + { + double rap(0); + TLorentzVector lorentzVect; + lorentzVect.SetXYZM(px, py, pz, mass); + rap = lorentzVect.Rapidity(); + return rap; + } + + template + bool isTrackInTowardRegion(const T1& track, const T2& leading_track) + { + // Initialization + bool isInTowardRegion = false; + + // DeltaPhi + double phi_ref = TVector2::Phi_0_2pi(leading_track.phi()); + double phi_trk = TVector2::Phi_0_2pi(track.phi()); + double delta_phi = (180.0 / TMath::Pi()) * TVector2::Phi_0_2pi(phi_trk - phi_ref); + if (delta_phi >= 0.0 && delta_phi < 60.0) + isInTowardRegion = true; + if (delta_phi >= 300.0 && delta_phi <= 360.0) + isInTowardRegion = true; + + return isInTowardRegion; + } + + template + bool isTrackInTransverseRegion(const T3& track, const T4& leading_track) + { + // Initialization + bool isInTransverseRegion = false; + + // DeltaPhi + double phi_ref = TVector2::Phi_0_2pi(leading_track.phi()); + double phi_trk = TVector2::Phi_0_2pi(track.phi()); + double delta_phi = (180.0 / TMath::Pi()) * TVector2::Phi_0_2pi(phi_trk - phi_ref); + if (delta_phi >= 60.0 && delta_phi < 120.0) + isInTransverseRegion = true; + if (delta_phi >= 240.0 && delta_phi < 300.0) + isInTransverseRegion = true; + + return isInTransverseRegion; + } + + // Process Data + void processData(SelectedCollisions::iterator const& collision, FullTracks const& tracks) + { + // Event Counter: before event selection + registryData.fill(HIST("number_of_events_data"), 0.5); + + // Event Selection + if (!collision.sel8()) + return; + + // Event Counter: after event selection sel8 + registryData.fill(HIST("number_of_events_data"), 1.5); + + // Cut on z-vertex + if (abs(collision.posZ()) > zVtx) + return; + + // Event Counter: after z-vertex cut + registryData.fill(HIST("number_of_events_data"), 2.5); + + // Leading Track + int leading_ID(0); + double pt_max(0); + + // Track Index + int i = -1; + + // Loop over Reconstructed Tracks + for (auto track : tracks) { + + i++; + if (!passedTrackSelectionForJetReconstruction(track)) + continue; + + if (track.pt() > pt_max) { + leading_ID = i; + pt_max = track.pt(); + } + } + // Event Counter: Skip Events with pt 0) + continue; + if (TMath::Abs(track.dcaXY()) > max_dcaxy) + continue; + if (TMath::Abs(track.dcaZ()) > max_dcaz) + continue; + + // Variables + double nsigmaTPCPr = track.tpcNSigmaPr(); + double nsigmaTOFPr = track.tofNSigmaPr(); + double y_proton = get_rapidity(track.px(), track.py(), track.pz(), 0.93827208816); + if (y_proton < min_y || y_proton > max_y) + continue; + + // Jet + if (isTrackInTowardRegion(track, leading_track)) { + if (track.pt() < 1.0) + registryData.fill(HIST("antiproton_jet_tpc"), track.pt(), nsigmaTPCPr); + if (track.pt() >= 0.5 && nsigmaTPCPr > min_nsigmaTPC && nsigmaTPCPr < max_nsigmaTPC && track.hasTOF()) + registryData.fill(HIST("antiproton_jet_tof"), track.pt(), nsigmaTOFPr); + } + + // UE + if (isTrackInTransverseRegion(track, leading_track)) { + if (track.pt() < 1.0) + registryData.fill(HIST("antiproton_ue_tpc"), track.pt(), nsigmaTPCPr); + if (track.pt() >= 0.5 && nsigmaTPCPr > min_nsigmaTPC && nsigmaTPCPr < max_nsigmaTPC && track.hasTOF()) + registryData.fill(HIST("antiproton_ue_tof"), track.pt(), nsigmaTOFPr); + } + } + } + + Preslice perCollision = o2::aod::track::collisionId; + + void processSecAntiprotons(SimCollisions const& collisions, MCTracks const& mcTracks, aod::McCollisions const&, const aod::McParticles&) + { + for (const auto& collision : collisions) { + + registryMC.fill(HIST("number_of_events_mc"), 0.5); + + // Event Selection + if (!collision.sel8()) + continue; + registryMC.fill(HIST("number_of_events_mc"), 1.5); + + if (abs(collision.posZ()) > zVtx) + continue; + registryMC.fill(HIST("number_of_events_mc"), 2.5); + + auto tracks_per_coll = mcTracks.sliceBy(perCollision, collision.globalIndex()); + + int leading_ID(0); + double pt_max(0); + int i = -1; + + // Loop over Reconstructed Tracks + for (auto track : tracks_per_coll) { + + i++; + if (!passedTrackSelectionForJetReconstruction(track)) + continue; + + if (track.pt() > pt_max) { + leading_ID = i; + pt_max = track.pt(); + } + } + if (pt_max < min_pt_leading) + continue; + registryMC.fill(HIST("number_of_events_mc"), 3.5); + + // Momentum of the Leading Particle + auto const& leading_track = tracks_per_coll.iteratorAt(leading_ID); + + // Loop over Reconstructed Tracks + for (auto track : tracks_per_coll) { + + if (!passedTrackSelection(track)) + continue; + if (require_PV_contributor && !(track.isPVContributor())) + continue; + if (track.sign() > 0) + continue; + if (TMath::Abs(track.dcaXY()) > max_dcaxy) + continue; + if (TMath::Abs(track.dcaZ()) > max_dcaz) + continue; + double y_proton = get_rapidity(track.px(), track.py(), track.pz(), 0.93827208816); + if (y_proton < min_y || y_proton > max_y) + continue; + + // Get MC Particle + if (!track.has_mcParticle()) + continue; + const auto particle = track.mcParticle(); + if (particle.pdgCode() != -2212) + continue; + + // Jet + if (isTrackInTowardRegion(track, leading_track)) { + registryMC.fill(HIST("antiproton_all_jet"), track.pt()); + if (particle.isPhysicalPrimary()) { + registryMC.fill(HIST("antiproton_prim_jet"), track.pt()); + } + } + // UE + if (isTrackInTransverseRegion(track, leading_track)) { + registryMC.fill(HIST("antiproton_all_ue"), track.pt()); + if (particle.isPhysicalPrimary()) { + registryMC.fill(HIST("antiproton_prim_ue"), track.pt()); + } + } + } + } + } + PROCESS_SWITCH(nuclei_in_toward_transv_regions, processData, "Process Data", true); + PROCESS_SWITCH(nuclei_in_toward_transv_regions, processSecAntiprotons, "Process sec antip", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Nuspex/spectraTOF.cxx b/PWGLF/Tasks/Nuspex/spectraTOF.cxx index 9dff04fa83e..813a3da63c5 100644 --- a/PWGLF/Tasks/Nuspex/spectraTOF.cxx +++ b/PWGLF/Tasks/Nuspex/spectraTOF.cxx @@ -18,6 +18,8 @@ /// // O2 includes +#include +#include #include "ReconstructionDataFormats/Track.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -34,48 +36,93 @@ #include "PWGLF/DataModel/LFParticleIdentification.h" #include "PWGLF/DataModel/spectraTOF.h" #include "Framework/O2DatabasePDGPlugin.h" - +#include "PWGLF/Utils/inelGt.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "Common/Core/RecoDecay.h" #include "TPDGCode.h" - using namespace o2; using namespace o2::track; using namespace o2::framework; using namespace o2::framework::expressions; +// Histograms +std::array, NpCharge> hDcaXYZ; +std::array, NpCharge> hDcaXYZPrm; +std::array, NpCharge> hDcaXYZStr; +std::array, NpCharge> hDcaXYZMat; +std::array, NpCharge> hDcaXYWrongCollisionPrm; +std::array, NpCharge> hDcaXYWrongCollisionStr; +std::array, NpCharge> hDcaXYWrongCollisionMat; +std::array, NpCharge> hDcaXYMC; // DCA xy in the MC +std::array, NpCharge> hDcaZMC; // DCA z in the MC +std::array, NpCharge> hDcaXYMCD0; // DCA xy in the MC for particles from D0 +std::array, NpCharge> hDcaZMCD0; // DCA z in the MC for particles from D0 +std::array, NpCharge> hDcaXYMCCharm; // DCA xy in the MC for particles from charm +std::array, NpCharge> hdcaZMCCharm; // DCA z in the MC for particles from charm +std::array, NpCharge> hDcaXYMCBeauty; // DCA xy in the MC for particles from beauty +std::array, NpCharge> hDcaZMCBeauty; // DCA z in the MC for particles from beauty +std::array, NpCharge> hDcaXYMCNotHF; // DCA xy in the MC for particles from not a HF +std::array, NpCharge> hDcaZMCNotHF; // DCA z in the MC for particles from not a HF +std::array, NpCharge> hDecayLengthStr; // Decay Length for particles from Strange +std::array, NpCharge> hDecayLengthMCD0; // Decay Length in the MC for particles from D0 +std::array, NpCharge> hDecayLengthMCCharm; // Decay Length in the MC for particles from charm +std::array, NpCharge> hDecayLengthMCBeauty; // Decay Length in the MC for particles from charm +std::array, NpCharge> hDecayLengthMCNotHF; // Decay Length in the MC for particles from not a HF + +std::array, NpCharge> hPtNumTOFMatchWithPIDSignalPrm; // Pt distribution of particles with a hit in the TOF and a compatible signal + // Spectra task struct tofSpectra { - Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; - Configurable cfgCutEtaMax{"cfgCutEtaMax", 0.8f, "Max eta range for tracks"}; - Configurable cfgCutEtaMin{"cfgCutEtaMin", -0.8f, "Min eta range for tracks"}; - Configurable cfgCutY{"cfgCutY", 0.5f, "Y range for tracks"}; - Configurable cfgINELCut{"cfgINELCut", 0, "INEL event selection: 0 no sel, 1 INEL>0, 2 INEL>1"}; - Configurable removeITSROFrameBorder{"removeITSROFrameBorder", false, "Remove TF border"}; - Configurable removeNoSameBunchPileup{"removeNoSameBunchPileup", false, "Remove TF border"}; - Configurable requireIsGoodZvtxFT0vsPV{"requireIsGoodZvtxFT0vsPV", false, "Remove TF border"}; - Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "Remove TF border"}; - Configurable removeNoTimeFrameBorder{"removeNoTimeFrameBorder", false, "Remove TF border"}; + struct : ConfigurableGroup { + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgINELCut{"cfgINELCut", 0, "INEL event selection: 0 no sel, 1 INEL>0, 2 INEL>1"}; + Configurable askForCustomTVX{"askForCustomTVX", false, "Ask fro custom TVX rather than sel8"}; + Configurable removeITSROFrameBorder{"removeITSROFrameBorder", false, "Remove TF border"}; + Configurable removeNoSameBunchPileup{"removeNoSameBunchPileup", false, "Remove TF border"}; + Configurable requireIsGoodZvtxFT0vsPV{"requireIsGoodZvtxFT0vsPV", false, "Remove TF border"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "Remove TF border"}; + Configurable removeNoTimeFrameBorder{"removeNoTimeFrameBorder", false, "Remove TF border"}; + Configurable requirekIsVertexTOFmatched{"requirekIsVertexTOFmatched", false, "Require requirekIsVertexTOFmatched"}; + } evselOptions; + + struct : ConfigurableGroup { + Configurable cfgCutEtaMax{"cfgCutEtaMax", 0.8f, "Max eta range for tracks"}; + Configurable cfgCutNsigma{"cfgCutNsigma", 100.0f, "nsigma cut range for tracks"}; + Configurable cfgCutEtaMin{"cfgCutEtaMin", -0.8f, "Min eta range for tracks"}; + Configurable cfgCutY{"cfgCutY", 0.5f, "Y range for tracks"}; + Configurable lastRequiredTrdCluster{"lastRequiredTrdCluster", 5, "Last cluster to require in TRD for track selection. -1 does not require any TRD cluster"}; + Configurable requireTrdOnly{"requireTrdOnly", false, "Require only tracks from TRD"}; + Configurable requireNoTrd{"requireNoTrd", false, "Require tracks without TRD"}; + Configurable selectEvTime{"selectEvTime", 0, "Select event time flags; 0: any event time, 1: isEvTimeDefined, 2: IsEvTimeTOF, 3: IsEvTimeT0AC, 4: IsEvTimeTOFT0AV, 5: NOT isEvTimeDefined"}; + } trkselOptions; + Configurable enableDcaGoodEvents{"enableDcaGoodEvents", true, "Enables the MC plots with the correct match between data and MC"}; Configurable enableTrackCutHistograms{"enableTrackCutHistograms", true, "Enables track cut histograms, before and after the cut"}; Configurable enableDeltaHistograms{"enableDeltaHistograms", true, "Enables the delta TPC and TOF histograms"}; Configurable enableTPCTOFHistograms{"enableTPCTOFHistograms", true, "Enables TPC TOF histograms"}; Configurable enableDCAxyzHistograms{"enableDCAxyzHistograms", false, "Enables DCAxyz correlation histograms"}; - Configurable lastRequiredTrdCluster{"lastRequiredTrdCluster", 5, "Last cluster to require in TRD for track selection. -1 does not require any TRD cluster"}; - Configurable requireTrdOnly{"requireTrdOnly", false, "Require only tracks from TRD"}; - Configurable requireNoTrd{"requireNoTrd", false, "Require tracks without TRD"}; - Configurable selectEvTime{"selectEvTime", 0, "Select event time flags; 0: any event time, 1: isEvTimeDefined, 2: IsEvTimeTOF, 3: IsEvTimeT0AC, 4: IsEvTimeTOFT0AV, 5: NOT isEvTimeDefined"}; - ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0}, "Binning of the pT axis"}; - ConfigurableAxis binsEta{"binsEta", {100, -1, 1}, "Binning of the eta axis"}; - ConfigurableAxis binsnsigmaTPC{"binsnsigmaTPC", {200, -10, 10}, "Binning of the nsigmaTPC axis"}; - ConfigurableAxis binsnsigmaTOF{"binsnsigmaTOF", {200, -10, 10}, "Binning of the nsigmaTOF axis"}; - ConfigurableAxis binsdeltaTPC{"binsdeltaTPC", {500, -1000, 1000}, "Binning of the nsigmaTPC axis"}; - ConfigurableAxis binsdeltaTOF{"binsdeltaTOF", {500, -1000, 1000}, "Binning of the nsigmaTOF axis"}; - ConfigurableAxis binsDca{"binsDca", {VARIABLE_WIDTH, -3.0, -2.95, -2.9, -2.85, -2.8, -2.75, -2.7, -2.65, -2.6, -2.55, -2.5, -2.45, -2.4, -2.35, -2.3, -2.25, -2.2, -2.15, -2.1, -2.05, -2.0, -1.975, -1.95, -1.925, -1.9, -1.875, -1.85, -1.825, -1.8, -1.775, -1.75, -1.725, -1.7, -1.675, -1.65, -1.625, -1.6, -1.575, -1.55, -1.525, -1.5, -1.475, -1.45, -1.425, -1.4, -1.375, -1.35, -1.325, -1.3, -1.275, -1.25, -1.225, -1.2, -1.175, -1.15, -1.125, -1.1, -1.075, -1.05, -1.025, -1.0, -0.99, -0.98, -0.97, -0.96, -0.95, -0.94, -0.93, -0.92, -0.91, -0.9, -0.89, -0.88, -0.87, -0.86, -0.85, -0.84, -0.83, -0.82, -0.81, -0.8, -0.79, -0.78, -0.77, -0.76, -0.75, -0.74, -0.73, -0.72, -0.71, -0.7, -0.69, -0.68, -0.67, -0.66, -0.65, -0.64, -0.63, -0.62, -0.61, -0.6, -0.59, -0.58, -0.57, -0.56, -0.55, -0.54, -0.53, -0.52, -0.51, -0.5, -0.49, -0.48, -0.47, -0.46, -0.45, -0.44, -0.43, -0.42, -0.41, -0.4, -0.396, -0.392, -0.388, -0.384, -0.38, -0.376, -0.372, -0.368, -0.364, -0.36, -0.356, -0.352, -0.348, -0.344, -0.34, -0.336, -0.332, -0.328, -0.324, -0.32, -0.316, -0.312, -0.308, -0.304, -0.3, -0.296, -0.292, -0.288, -0.284, -0.28, -0.276, -0.272, -0.268, -0.264, -0.26, -0.256, -0.252, -0.248, -0.244, -0.24, -0.236, -0.232, -0.228, -0.224, -0.22, -0.216, -0.212, -0.208, -0.204, -0.2, -0.198, -0.196, -0.194, -0.192, -0.19, -0.188, -0.186, -0.184, -0.182, -0.18, -0.178, -0.176, -0.174, -0.172, -0.17, -0.168, -0.166, -0.164, -0.162, -0.16, -0.158, -0.156, -0.154, -0.152, -0.15, -0.148, -0.146, -0.144, -0.142, -0.14, -0.138, -0.136, -0.134, -0.132, -0.13, -0.128, -0.126, -0.124, -0.122, -0.12, -0.118, -0.116, -0.114, -0.112, -0.11, -0.108, -0.106, -0.104, -0.102, -0.1, -0.099, -0.098, -0.097, -0.096, -0.095, -0.094, -0.093, -0.092, -0.091, -0.09, -0.089, -0.088, -0.087, -0.086, -0.085, -0.084, -0.083, -0.082, -0.081, -0.08, -0.079, -0.078, -0.077, -0.076, -0.075, -0.074, -0.073, -0.072, -0.071, -0.07, -0.069, -0.068, -0.067, -0.066, -0.065, -0.064, -0.063, -0.062, -0.061, -0.06, -0.059, -0.058, -0.057, -0.056, -0.055, -0.054, -0.053, -0.052, -0.051, -0.05, -0.049, -0.048, -0.047, -0.046, -0.045, -0.044, -0.043, -0.042, -0.041, -0.04, -0.039, -0.038, -0.037, -0.036, -0.035, -0.034, -0.033, -0.032, -0.031, -0.03, -0.029, -0.028, -0.027, -0.026, -0.025, -0.024, -0.023, -0.022, -0.021, -0.02, -0.019, -0.018, -0.017, -0.016, -0.015, -0.014, -0.013, -0.012, -0.011, -0.01, -0.009, -0.008, -0.007, -0.006, -0.005, -0.004, -0.003, -0.002, -0.001, -0.0, 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, 0.01, 0.011, 0.012, 0.013, 0.014, 0.015, 0.016, 0.017, 0.018, 0.019, 0.02, 0.021, 0.022, 0.023, 0.024, 0.025, 0.026, 0.027, 0.028, 0.029, 0.03, 0.031, 0.032, 0.033, 0.034, 0.035, 0.036, 0.037, 0.038, 0.039, 0.04, 0.041, 0.042, 0.043, 0.044, 0.045, 0.046, 0.047, 0.048, 0.049, 0.05, 0.051, 0.052, 0.053, 0.054, 0.055, 0.056, 0.057, 0.058, 0.059, 0.06, 0.061, 0.062, 0.063, 0.064, 0.065, 0.066, 0.067, 0.068, 0.069, 0.07, 0.071, 0.072, 0.073, 0.074, 0.075, 0.076, 0.077, 0.078, 0.079, 0.08, 0.081, 0.082, 0.083, 0.084, 0.085, 0.086, 0.087, 0.088, 0.089, 0.09, 0.091, 0.092, 0.093, 0.094, 0.095, 0.096, 0.097, 0.098, 0.099, 0.1, 0.102, 0.104, 0.106, 0.108, 0.11, 0.112, 0.114, 0.116, 0.118, 0.12, 0.122, 0.124, 0.126, 0.128, 0.13, 0.132, 0.134, 0.136, 0.138, 0.14, 0.142, 0.144, 0.146, 0.148, 0.15, 0.152, 0.154, 0.156, 0.158, 0.16, 0.162, 0.164, 0.166, 0.168, 0.17, 0.172, 0.174, 0.176, 0.178, 0.18, 0.182, 0.184, 0.186, 0.188, 0.19, 0.192, 0.194, 0.196, 0.198, 0.2, 0.204, 0.208, 0.212, 0.216, 0.22, 0.224, 0.228, 0.232, 0.236, 0.24, 0.244, 0.248, 0.252, 0.256, 0.26, 0.264, 0.268, 0.272, 0.276, 0.28, 0.284, 0.288, 0.292, 0.296, 0.3, 0.304, 0.308, 0.312, 0.316, 0.32, 0.324, 0.328, 0.332, 0.336, 0.34, 0.344, 0.348, 0.352, 0.356, 0.36, 0.364, 0.368, 0.372, 0.376, 0.38, 0.384, 0.388, 0.392, 0.396, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.7, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.8, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.9, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.0, 1.025, 1.05, 1.075, 1.1, 1.125, 1.15, 1.175, 1.2, 1.225, 1.25, 1.275, 1.3, 1.325, 1.35, 1.375, 1.4, 1.425, 1.45, 1.475, 1.5, 1.525, 1.55, 1.575, 1.6, 1.625, 1.65, 1.675, 1.7, 1.725, 1.75, 1.775, 1.8, 1.825, 1.85, 1.875, 1.9, 1.925, 1.95, 1.975, 2.0, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3.0}, "Binning of DCA xy and z axis"}; - ConfigurableAxis binsMultiplicity{"binsMultiplicity", {100, 0, 100}, "Binning for multiplicity"}; - ConfigurableAxis binsPercentile{"binsPercentile", {100, 0, 100}, "Binning for percentiles"}; + Configurable enableDCAxyphiHistograms{"enableDCAxyphiHistograms", false, "Enables DCAxyphi correlation histograms"}; + Configurable enableDCAvsmotherHistograms{"enableDCAvsmotherHistograms", false, "Enables DCA vs mother histograms"}; + + struct : ConfigurableGroup { + ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0}, "Binning of the pT axis"}; + ConfigurableAxis binsEta{"binsEta", {100, -1, 1}, "Binning of the eta axis"}; + ConfigurableAxis binsnsigmaTPC{"binsnsigmaTPC", {200, -10, 10}, "Binning of the nsigmaTPC axis"}; + ConfigurableAxis binsnsigmaTOF{"binsnsigmaTOF", {200, -10, 10}, "Binning of the nsigmaTOF axis"}; + ConfigurableAxis binsdeltaTPC{"binsdeltaTPC", {500, -1000, 1000}, "Binning of the nsigmaTPC axis"}; + ConfigurableAxis binsdeltaTOF{"binsdeltaTOF", {500, -1000, 1000}, "Binning of the nsigmaTOF axis"}; + ConfigurableAxis binsDca{"binsDca", {VARIABLE_WIDTH, -3.0, -2.95, -2.9, -2.85, -2.8, -2.75, -2.7, -2.65, -2.6, -2.55, -2.5, -2.45, -2.4, -2.35, -2.3, -2.25, -2.2, -2.15, -2.1, -2.05, -2.0, -1.975, -1.95, -1.925, -1.9, -1.875, -1.85, -1.825, -1.8, -1.775, -1.75, -1.725, -1.7, -1.675, -1.65, -1.625, -1.6, -1.575, -1.55, -1.525, -1.5, -1.475, -1.45, -1.425, -1.4, -1.375, -1.35, -1.325, -1.3, -1.275, -1.25, -1.225, -1.2, -1.175, -1.15, -1.125, -1.1, -1.075, -1.05, -1.025, -1.0, -0.99, -0.98, -0.97, -0.96, -0.95, -0.94, -0.93, -0.92, -0.91, -0.9, -0.89, -0.88, -0.87, -0.86, -0.85, -0.84, -0.83, -0.82, -0.81, -0.8, -0.79, -0.78, -0.77, -0.76, -0.75, -0.74, -0.73, -0.72, -0.71, -0.7, -0.69, -0.68, -0.67, -0.66, -0.65, -0.64, -0.63, -0.62, -0.61, -0.6, -0.59, -0.58, -0.57, -0.56, -0.55, -0.54, -0.53, -0.52, -0.51, -0.5, -0.49, -0.48, -0.47, -0.46, -0.45, -0.44, -0.43, -0.42, -0.41, -0.4, -0.396, -0.392, -0.388, -0.384, -0.38, -0.376, -0.372, -0.368, -0.364, -0.36, -0.356, -0.352, -0.348, -0.344, -0.34, -0.336, -0.332, -0.328, -0.324, -0.32, -0.316, -0.312, -0.308, -0.304, -0.3, -0.296, -0.292, -0.288, -0.284, -0.28, -0.276, -0.272, -0.268, -0.264, -0.26, -0.256, -0.252, -0.248, -0.244, -0.24, -0.236, -0.232, -0.228, -0.224, -0.22, -0.216, -0.212, -0.208, -0.204, -0.2, -0.198, -0.196, -0.194, -0.192, -0.19, -0.188, -0.186, -0.184, -0.182, -0.18, -0.178, -0.176, -0.174, -0.172, -0.17, -0.168, -0.166, -0.164, -0.162, -0.16, -0.158, -0.156, -0.154, -0.152, -0.15, -0.148, -0.146, -0.144, -0.142, -0.14, -0.138, -0.136, -0.134, -0.132, -0.13, -0.128, -0.126, -0.124, -0.122, -0.12, -0.118, -0.116, -0.114, -0.112, -0.11, -0.108, -0.106, -0.104, -0.102, -0.1, -0.099, -0.098, -0.097, -0.096, -0.095, -0.094, -0.093, -0.092, -0.091, -0.09, -0.089, -0.088, -0.087, -0.086, -0.085, -0.084, -0.083, -0.082, -0.081, -0.08, -0.079, -0.078, -0.077, -0.076, -0.075, -0.074, -0.073, -0.072, -0.071, -0.07, -0.069, -0.068, -0.067, -0.066, -0.065, -0.064, -0.063, -0.062, -0.061, -0.06, -0.059, -0.058, -0.057, -0.056, -0.055, -0.054, -0.053, -0.052, -0.051, -0.05, -0.049, -0.048, -0.047, -0.046, -0.045, -0.044, -0.043, -0.042, -0.041, -0.04, -0.039, -0.038, -0.037, -0.036, -0.035, -0.034, -0.033, -0.032, -0.031, -0.03, -0.029, -0.028, -0.027, -0.026, -0.025, -0.024, -0.023, -0.022, -0.021, -0.02, -0.019, -0.018, -0.017, -0.016, -0.015, -0.014, -0.013, -0.012, -0.011, -0.01, -0.009, -0.008, -0.007, -0.006, -0.005, -0.004, -0.003, -0.002, -0.001, -0.0, 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, 0.01, 0.011, 0.012, 0.013, 0.014, 0.015, 0.016, 0.017, 0.018, 0.019, 0.02, 0.021, 0.022, 0.023, 0.024, 0.025, 0.026, 0.027, 0.028, 0.029, 0.03, 0.031, 0.032, 0.033, 0.034, 0.035, 0.036, 0.037, 0.038, 0.039, 0.04, 0.041, 0.042, 0.043, 0.044, 0.045, 0.046, 0.047, 0.048, 0.049, 0.05, 0.051, 0.052, 0.053, 0.054, 0.055, 0.056, 0.057, 0.058, 0.059, 0.06, 0.061, 0.062, 0.063, 0.064, 0.065, 0.066, 0.067, 0.068, 0.069, 0.07, 0.071, 0.072, 0.073, 0.074, 0.075, 0.076, 0.077, 0.078, 0.079, 0.08, 0.081, 0.082, 0.083, 0.084, 0.085, 0.086, 0.087, 0.088, 0.089, 0.09, 0.091, 0.092, 0.093, 0.094, 0.095, 0.096, 0.097, 0.098, 0.099, 0.1, 0.102, 0.104, 0.106, 0.108, 0.11, 0.112, 0.114, 0.116, 0.118, 0.12, 0.122, 0.124, 0.126, 0.128, 0.13, 0.132, 0.134, 0.136, 0.138, 0.14, 0.142, 0.144, 0.146, 0.148, 0.15, 0.152, 0.154, 0.156, 0.158, 0.16, 0.162, 0.164, 0.166, 0.168, 0.17, 0.172, 0.174, 0.176, 0.178, 0.18, 0.182, 0.184, 0.186, 0.188, 0.19, 0.192, 0.194, 0.196, 0.198, 0.2, 0.204, 0.208, 0.212, 0.216, 0.22, 0.224, 0.228, 0.232, 0.236, 0.24, 0.244, 0.248, 0.252, 0.256, 0.26, 0.264, 0.268, 0.272, 0.276, 0.28, 0.284, 0.288, 0.292, 0.296, 0.3, 0.304, 0.308, 0.312, 0.316, 0.32, 0.324, 0.328, 0.332, 0.336, 0.34, 0.344, 0.348, 0.352, 0.356, 0.36, 0.364, 0.368, 0.372, 0.376, 0.38, 0.384, 0.388, 0.392, 0.396, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.7, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.8, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.9, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.0, 1.025, 1.05, 1.075, 1.1, 1.125, 1.15, 1.175, 1.2, 1.225, 1.25, 1.275, 1.3, 1.325, 1.35, 1.375, 1.4, 1.425, 1.45, 1.475, 1.5, 1.525, 1.55, 1.575, 1.6, 1.625, 1.65, 1.675, 1.7, 1.725, 1.75, 1.775, 1.8, 1.825, 1.85, 1.875, 1.9, 1.925, 1.95, 1.975, 2.0, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3.0}, "Binning of DCA xy and z axis"}; + ConfigurableAxis binsMultiplicity{"binsMultiplicity", {100, 0, 100}, "Binning for multiplicity"}; + ConfigurableAxis binsOccupancy{"binsOccupancy", {3000, 0, 15000}, "Binning for occupancy"}; + ConfigurableAxis binsPercentile{"binsPercentile", {100, 0, 100}, "Binning for percentiles"}; + ConfigurableAxis binsImpactParam{"binsImpactParam", {2500, 0, 25}, "Binning for impact parameter"}; + } binsOptions; + Configurable multiplicityEstimator{"multiplicityEstimator", 0, "Flag to use a multiplicity estimator: 0 no multiplicity, 1 MultFV0M, 2 MultFT0M, 3 MultFDDM, 4 MultTracklets, 5 MultTPC, 6 MultNTracksPV, 7 MultNTracksPVeta1, 8 CentralityFT0C, 9 CentralityFT0M, 10 CentralityFV0A"}; + // Custom track cuts for the cut variation study TrackSelection customTrackCuts; - Configurable ckeckKaonIsPvContrib{"ckeckKaonIsPvContrib", false, "Flag to ckeck if kaon tracks are from pv"}; + Configurable kaonIsPvContrib{"kaonIsPvContrib", false, "Flag to ckeck if kaon tracks are from pv"}; Configurable useCustomTrackCuts{"useCustomTrackCuts", false, "Flag to use custom track cuts"}; Configurable itsPattern{"itsPattern", 0, "0 = Run3ITSibAny, 1 = Run3ITSallAny, 2 = Run3ITSall7Layers, 3 = Run3ITSibTwo"}; Configurable requireITS{"requireITS", true, "Additional cut on the ITS requirement"}; @@ -84,13 +131,19 @@ struct tofSpectra { Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 70.f, "Additional cut on the minimum number of crossed rows in the TPC"}; Configurable minNCrossedRowsOverFindableClustersTPC{"minNCrossedRowsOverFindableClustersTPC", 0.8f, "Additional cut on the minimum value of the ratio between crossed rows and findable clusters in the TPC"}; Configurable maxChi2PerClusterTPC{"maxChi2PerClusterTPC", 4.f, "Additional cut on the maximum value of the chi2 per cluster in the TPC"}; + Configurable minChi2PerClusterTPC{"minChi2PerClusterTPC", 0.5f, "Additional cut on the minimum value of the chi2 per cluster in the TPC"}; Configurable maxChi2PerClusterITS{"maxChi2PerClusterITS", 36.f, "Additional cut on the maximum value of the chi2 per cluster in the ITS"}; Configurable maxDcaXYFactor{"maxDcaXYFactor", 1.f, "Additional cut on the maximum value of the DCA xy (multiplicative factor)"}; Configurable maxDcaZ{"maxDcaZ", 2.f, "Additional cut on the maximum value of the DCA z"}; - Configurable minTPCNClsFound{"minTPCNClsFound", 0.f, "Additional cut on the minimum value of the number of found clusters in the TPC"}; + Configurable minTPCNClsFound{"minTPCNClsFound", 100.f, "Additional cut on the minimum value of the number of found clusters in the TPC"}; Configurable makeTHnSparseChoice{"makeTHnSparseChoice", false, "choose if produce thnsparse"}; // RD - Configurable includeCentralityMC{"includeCentralityMC", true, "choose if include Centrality to MC"}; - Configurable tpctofVsMult{"tpctofVsMult", false, "Produce TPC-TOF plots vs multiplicity"}; + Configurable enableTPCTOFvsEtaHistograms{"enableTPCTOFvsEtaHistograms", false, "choose if produce TPC tof vs Eta"}; + Configurable includeCentralityMC{"includeCentralityMC", false, "choose if include Centrality to MC"}; + Configurable isImpactParam{"isImpactParam", false, "choose if include impactparam to MC"}; + Configurable usePDGcode{"usePDGcode", false, "choose if include PDG code for MC closure test"}; + Configurable enableTPCTOFVsMult{"enableTPCTOFVsMult", false, "Produce TPC-TOF plots vs multiplicity"}; + Configurable includeCentralityToTracks{"includeCentralityToTracks", false, "choose if include Centrality to tracks"}; + Configurable min_ITS_nClusters{"min_ITS_nClusters", 5, "minimum number of found ITS clusters"}; // Histograms HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -155,6 +208,8 @@ struct tofSpectra { LOG(info) << "Enabling process function processLfFullAl"; } + LOG(info) << "\tKaonIsPvContrib=" << kaonIsPvContrib.value; + // Custom track cuts if (useCustomTrackCuts.value) { LOG(info) << "Using custom track cuts from values:"; @@ -162,17 +217,19 @@ struct tofSpectra { LOG(info) << "\trequireTPC=" << requireTPC.value; LOG(info) << "\trequireGoldenChi2=" << requireGoldenChi2.value; LOG(info) << "\tmaxChi2PerClusterTPC=" << maxChi2PerClusterTPC.value; + LOG(info) << "\tminChi2PerClusterTPC=" << minChi2PerClusterTPC.value; LOG(info) << "\tminNCrossedRowsTPC=" << minNCrossedRowsTPC.value; + LOG(info) << "\tmin_ITS_nClusters=" << min_ITS_nClusters.value; LOG(info) << "\tminTPCNClsFound=" << minTPCNClsFound.value; LOG(info) << "\tmaxChi2PerClusterITS=" << maxChi2PerClusterITS.value; LOG(info) << "\tmaxDcaZ=" << maxDcaZ.value; LOG(info) << "\tmakeTHnSparseChoice=" << makeTHnSparseChoice.value; - LOG(info) << "\tckeckKaonIsPvContrib=" << ckeckKaonIsPvContrib.value; customTrackCuts = getGlobalTrackSelectionRun3ITSMatch(itsPattern.value); LOG(info) << "Customizing track cuts:"; customTrackCuts.SetRequireITSRefit(requireITS.value); customTrackCuts.SetRequireTPCRefit(requireTPC.value); + customTrackCuts.SetMinNClustersITS(min_ITS_nClusters.value); customTrackCuts.SetRequireGoldenChi2(requireGoldenChi2.value); customTrackCuts.SetMaxChi2PerClusterTPC(maxChi2PerClusterTPC.value); customTrackCuts.SetMaxChi2PerClusterITS(maxChi2PerClusterITS.value); @@ -185,30 +242,71 @@ struct tofSpectra { } // Histograms const AxisSpec vtxZAxis{100, -20, 20, "Vtx_{z} (cm)"}; - const AxisSpec pAxis{binsPt, "#it{p} (GeV/#it{c})"}; - const AxisSpec ptAxis{binsPt, "#it{p}_{T} (GeV/#it{c})"}; - const AxisSpec etaAxis{binsEta, "#eta"}; + const AxisSpec pAxis{binsOptions.binsPt, "#it{p} (GeV/#it{c})"}; + const AxisSpec ptAxis{binsOptions.binsPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec etaAxis{binsOptions.binsEta, "#eta"}; + const AxisSpec impParamAxis{binsOptions.binsImpactParam, "Impact parameter"}; + const AxisSpec occupancyAxis{binsOptions.binsOccupancy, "Occupancy Axis"}; + AxisSpec multAxis{binsOptions.binsMultiplicity, "Undefined multiplicity estimator"}; + switch (multiplicityEstimator) { + case MultCodes::kNoMultiplicity: // No multiplicity + break; + case MultCodes::kMultFV0M: // MultFV0M + multAxis.name = "MultFV0M"; + break; + case MultCodes::kMultFT0M: // MultFT0M + multAxis.name = "MultFT0M"; + break; + case MultCodes::kMultFDDM: // MultFDDM + multAxis.name = "MultFDDM"; + break; + case MultCodes::kMultTracklets: // MultTracklets + multAxis.name = "MultTracklets"; + break; + case MultCodes::kMultTPC: // MultTPC + multAxis.name = "MultTPC"; + break; + case MultCodes::kMultNTracksPV: // MultNTracksPV + multAxis.name = "MultNTracksPV"; + break; + case MultCodes::kMultNTracksPVeta1: // MultNTracksPVeta1 + multAxis.name = "MultNTracksPVeta1"; + break; + case MultCodes::kCentralityFT0C: // Centrality FT0C + multAxis = {binsOptions.binsPercentile, "Centrality FT0C"}; + break; + case MultCodes::kCentralityFT0M: // Centrality FT0M + multAxis = {binsOptions.binsPercentile, "Centrality FT0M"}; + break; + case MultCodes::kCentralityFV0A: // Centrality FV0A + multAxis = {binsOptions.binsPercentile, "Centrality FV0A"}; + break; + default: + LOG(fatal) << "Unrecognized option for multiplicity " << multiplicityEstimator; + } histos.add("event/vertexz", "", HistType::kTH1D, {vtxZAxis}); + histos.add("test_occupancy/event/vertexz", "", HistType::kTH1D, {vtxZAxis}); auto h = histos.add("evsel", "evsel", HistType::kTH1D, {{20, 0.5, 20.5}}); h->GetXaxis()->SetBinLabel(1, "Events read"); h->GetXaxis()->SetBinLabel(2, "INEL>0 (fraction)"); h->GetXaxis()->SetBinLabel(3, "INEL>1 (fraction)"); h->GetXaxis()->SetBinLabel(4, "Ev. sel. passed"); h->GetXaxis()->SetBinLabel(5, "NoITSROFrameBorder"); - h->GetXaxis()->SetBinLabel(6, "NoSameBunchPileup"); - h->GetXaxis()->SetBinLabel(7, "IsGoodZvtxFT0vsPV"); - h->GetXaxis()->SetBinLabel(8, "IsVertexITSTPC"); - h->GetXaxis()->SetBinLabel(9, "NoTimeFrameBorder"); - h->GetXaxis()->SetBinLabel(10, "INEL>0 (fraction)"); - h->GetXaxis()->SetBinLabel(11, "INEL>1 (fraction)"); - h->GetXaxis()->SetBinLabel(12, "posZ passed"); - h->GetXaxis()->SetBinLabel(13, cfgINELCut.value == 1 ? "INEL>0" : "INEL>0 (fraction)"); - h->GetXaxis()->SetBinLabel(14, cfgINELCut.value == 2 ? "INEL>1" : "INEL>1 (fraction)"); + h->GetXaxis()->SetBinLabel(6, "NoITSROFrameBorder"); + h->GetXaxis()->SetBinLabel(7, "NoSameBunchPileup"); + h->GetXaxis()->SetBinLabel(8, "IsGoodZvtxFT0vsPV"); + h->GetXaxis()->SetBinLabel(9, "IsVertexITSTPC"); + h->GetXaxis()->SetBinLabel(10, "NoTimeFrameBorder"); + h->GetXaxis()->SetBinLabel(11, "INEL>0 (fraction)"); + h->GetXaxis()->SetBinLabel(12, "INEL>1 (fraction)"); + h->GetXaxis()->SetBinLabel(13, "posZ passed"); + h->GetXaxis()->SetBinLabel(14, evselOptions.cfgINELCut.value == 1 ? "INEL>0" : "INEL>0 (fraction)"); + h->GetXaxis()->SetBinLabel(15, evselOptions.cfgINELCut.value == 2 ? "INEL>1" : "INEL>1 (fraction)"); h = histos.add("tracksel", "tracksel", HistType::kTH1D, {{10, 0.5, 10.5}}); h->GetXaxis()->SetBinLabel(1, "Tracks read"); - h->GetXaxis()->SetBinLabel(2, Form(" %.2f < #eta < %.2f ", cfgCutEtaMin.value, cfgCutEtaMax.value)); + h->GetXaxis()->SetBinLabel(2, Form(" %.2f < #eta < %.2f ", trkselOptions.cfgCutEtaMin.value, trkselOptions.cfgCutEtaMax.value)); h->GetXaxis()->SetBinLabel(3, "Quality passed"); h->GetXaxis()->SetBinLabel(4, "TOF passed (partial)"); @@ -224,31 +322,42 @@ struct tofSpectra { h->GetXaxis()->SetBinLabel(9, "EvTimeT0AC (selected)"); h->GetXaxis()->SetBinLabel(10, "EvTimeTOFT0AC (selected)"); - histos.add("Centrality/FV0A", "FV0A", HistType::kTH1D, {{binsPercentile, "Centrality FV0A"}}); - histos.add("Centrality/FT0M", "FT0M", HistType::kTH1D, {{binsPercentile, "Centrality FT0M"}}); - histos.add("Centrality/FT0A", "FT0A", HistType::kTH1D, {{binsPercentile, "Centrality FT0A"}}); - histos.add("Centrality/FT0C", "FT0C", HistType::kTH1D, {{binsPercentile, "Centrality FT0C"}}); - histos.add("Centrality/FDDM", "FDDM", HistType::kTH1D, {{binsPercentile, "Centrality FDDM"}}); - histos.add("Centrality/NTPV", "NTPV", HistType::kTH1D, {{binsPercentile, "Centrality NTPV"}}); - - histos.add("Mult/FV0M", "MultFV0M", HistType::kTH1D, {{binsMultiplicity, "MultFV0M"}}); - histos.add("Mult/FT0M", "MultFT0M", HistType::kTH1D, {{binsMultiplicity, "MultFT0M"}}); - histos.add("Mult/FDDM", "MultFDDM", HistType::kTH1D, {{binsMultiplicity, "MultFDDM"}}); - - // histos.add("Mult/Tracklets", "MultTracklets", HistType::kTH1D, {{binsMultiplicity, "MultTracklets"}}); - histos.add("Mult/TPC", "MultTPC", HistType::kTH1D, {{binsMultiplicity, "MultTPC"}}); - histos.add("Mult/NTracksPV", "MultNTracksPV", HistType::kTH1D, {{binsMultiplicity, "MultNTracksPV"}}); - histos.add("Mult/NTracksPVeta1", "MultNTracksPVeta1", HistType::kTH1D, {{binsMultiplicity, "MultNTracksPVeta1"}}); - - const AxisSpec dcaXyAxis{binsDca, "DCA_{xy} (cm)"}; + histos.add("Centrality/FV0A", "FV0A", HistType::kTH1D, {{binsOptions.binsPercentile, "Centrality FV0A"}}); + histos.add("Centrality/FT0M", "FT0M", HistType::kTH1D, {{binsOptions.binsPercentile, "Centrality FT0M"}}); + histos.add("Centrality/FT0A", "FT0A", HistType::kTH1D, {{binsOptions.binsPercentile, "Centrality FT0A"}}); + histos.add("Centrality/FT0C", "FT0C", HistType::kTH1D, {{binsOptions.binsPercentile, "Centrality FT0C"}}); + histos.add("Centrality/FDDM", "FDDM", HistType::kTH1D, {{binsOptions.binsPercentile, "Centrality FDDM"}}); + histos.add("Centrality/NTPV", "NTPV", HistType::kTH1D, {{binsOptions.binsPercentile, "Centrality NTPV"}}); + + histos.add("Mult/FV0M", "MultFV0M", HistType::kTH1D, {{binsOptions.binsMultiplicity, "MultFV0M"}}); + histos.add("Mult/FT0M", "MultFT0M", HistType::kTH1D, {{binsOptions.binsMultiplicity, "MultFT0M"}}); + histos.add("Mult/FDDM", "MultFDDM", HistType::kTH1D, {{binsOptions.binsMultiplicity, "MultFDDM"}}); + if (doprocessBC) { + histos.add("Mult/PerBC/FT0M", "FT0M", HistType::kTH1D, {{binsOptions.binsMultiplicity, "Multiplicity FT0M"}}); + histos.add("Mult/PerBC/FT0A", "FT0A", HistType::kTH1D, {{binsOptions.binsMultiplicity, "Multiplicity FT0A"}}); + histos.add("Mult/PerBC/FT0C", "FT0C", HistType::kTH1D, {{binsOptions.binsMultiplicity, "Multiplicity FT0C"}}); + histos.add("Mult/PerBC/sel8/FT0M", "FT0M", HistType::kTH1D, {{binsOptions.binsMultiplicity, "Multiplicity FT0M"}}); + histos.add("Mult/PerBC/sel8/FT0A", "FT0A", HistType::kTH1D, {{binsOptions.binsMultiplicity, "Multiplicity FT0A"}}); + histos.add("Mult/PerBC/sel8/FT0C", "FT0C", HistType::kTH1D, {{binsOptions.binsMultiplicity, "Multiplicity FT0C"}}); + histos.add("Mult/PerBC/sel8/FT0AvsFT0C", "FT0C", HistType::kTH2D, {{binsOptions.binsMultiplicity, "Multiplicity FT0A"}, {binsOptions.binsMultiplicity, "Multiplicity FT0C"}}); + } + // histos.add("Mult/Tracklets", "MultTracklets", HistType::kTH1D, {{binsOptions.binsMultiplicity, "MultTracklets"}}); + histos.add("Mult/TPC", "MultTPC", HistType::kTH1D, {{binsOptions.binsMultiplicity, "MultTPC"}}); + histos.add("Mult/NTracksPV", "MultNTracksPV", HistType::kTH1D, {{binsOptions.binsMultiplicity, "MultNTracksPV"}}); + histos.add("Mult/NTracksPVeta1", "MultNTracksPVeta1", HistType::kTH1D, {{binsOptions.binsMultiplicity, "MultNTracksPVeta1"}}); + histos.add("test_occupancy/tpcCount", "TPC Track Count", HistType::kTH1F, {{100, 0, 10000, "Number of TPC Tracks"}}); + histos.add("test_occupancy/tofCount", "TOF Track Count", HistType::kTH1F, {{100, 0, 10000, "Number of TOF Tracks"}}); + + const AxisSpec dcaXyAxis{binsOptions.binsDca, "DCA_{xy} (cm)"}; const AxisSpec phiAxis{200, 0, 7, "#it{#varphi} (rad)"}; - const AxisSpec dcaZAxis{binsDca, "DCA_{z} (cm)"}; + const AxisSpec dcaZAxis{binsOptions.binsDca, "DCA_{z} (cm)"}; const AxisSpec lengthAxis{100, 0, 600, "Track length (cm)"}; + const AxisSpec decayLengthAxis{100, 0, 1.0, "Decay Length (cm)"}; if (enableTrackCutHistograms) { const AxisSpec chargeAxis{2, -2.f, 2.f, "Charge"}; - histos.add("track/pos/Eta", "Eta Positive tracks", HistType::kTH1D, {{binsEta, "#eta tracks"}}); - histos.add("track/neg/Eta", "Eta Negative tracks", HistType::kTH1D, {{binsEta, "#eta tracks"}}); + histos.add("track/pos/Eta", "Eta Positive tracks", HistType::kTH1D, {{binsOptions.binsEta, "#eta tracks"}}); + histos.add("track/neg/Eta", "Eta Negative tracks", HistType::kTH1D, {{binsOptions.binsEta, "#eta tracks"}}); // its histograms histos.add("track/ITS/itsNCls", "number of found ITS clusters;# clusters ITS", kTH2D, {{8, -0.5, 7.5}, chargeAxis}); histos.add("track/ITS/itsChi2NCl", "chi2 per ITS cluster;chi2 / cluster ITS", kTH2D, {{100, 0, 40}, chargeAxis}); @@ -261,6 +370,10 @@ struct tofSpectra { histos.add("track/TPC/tpcFractionSharedCls", "fraction of shared TPC clusters;fraction shared clusters TPC", kTH2D, {{100, 0., 1.}, chargeAxis}); histos.add("track/TPC/tpcCrossedRowsOverFindableCls", "crossed TPC rows over findable clusters;crossed rows / findable clusters TPC", kTH2D, {{60, 0.7, 1.3}, chargeAxis}); histos.add("track/TPC/tpcChi2NCl", "chi2 per cluster in TPC;chi2 / cluster TPC", kTH2D, {{100, 0, 10}, chargeAxis}); + histos.add("Vertex/histGenVtxMC", "MC generated vertex z position", HistType::kTH1F, {{400, -40., +40., "z position (cm)"}}); + histos.add("Vertex/RecoEvs/histGenVtxMC", "MC generated vertex z position", HistType::kTH1F, {{400, -40., +40., "z position (cm)"}}); + histos.add("Centrality/ImpParm", "Centrality", HistType::kTH1F, {impParamAxis}); + histos.add("Centrality/RecoEvs/ImpParm", "Centrality", HistType::kTH1F, {impParamAxis}); histos.addClone("track/ITS/itsNCls", "track/selected/ITS/itsNCls"); histos.addClone("track/ITS/itsChi2NCl", "track/selected/ITS/itsChi2NCl"); @@ -320,19 +433,153 @@ struct tofSpectra { histos.add("Data/pos/pt/tpc", "pos TPC", kTH1D, {ptAxis}); histos.add("Data/neg/pt/tpc", "neg TPC", kTH1D, {ptAxis}); + if (includeCentralityToTracks) { + histos.add("Data/cent/pos/pt/its_tpc_tof", "pos ITS-TPC-TOF", kTH3D, {ptAxis, multAxis, occupancyAxis}); + histos.add("Data/cent/neg/pt/its_tpc_tof", "neg ITS-TPC-TOF", kTH3D, {ptAxis, multAxis, occupancyAxis}); + histos.add("Data/cent/pos/pt/its_tpc", "pos ITS-TPC", kTH3D, {ptAxis, multAxis, occupancyAxis}); + histos.add("Data/cent/neg/pt/its_tpc", "neg ITS-TPC", kTH3D, {ptAxis, multAxis, occupancyAxis}); + histos.add("Data/cent/pos/pt/its_tof", "pos ITS-TOF", kTH3D, {ptAxis, multAxis, occupancyAxis}); + histos.add("Data/cent/neg/pt/its_tof", "neg ITS-TOF", kTH3D, {ptAxis, multAxis, occupancyAxis}); + } + const AxisSpec nsigmaTPCAxisOccupancy{binsOptions.binsnsigmaTPC, "nsigmaTPC"}; + if (doprocessMCclosure) { + histos.add("nsigmatpc/mc_closure/pos/pi", "mc_closure dependent pion", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis}); + histos.add("nsigmatpc/mc_closure/neg/pi", "mc_closure dependent pion", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis}); + histos.add("nsigmatof/mc_closure/pos/pi", "mc_closure dependent pion", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis}); + histos.add("nsigmatof/mc_closure/neg/pi", "mc_closure dependent pion", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis}); + + histos.add("nsigmatpc/mc_closure/pos/ka", "mc_closure dependent kaon", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis}); + histos.add("nsigmatpc/mc_closure/neg/ka", "mc_closure dependent kaon", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis}); + histos.add("nsigmatof/mc_closure/pos/ka", "mc_closure dependent kaon", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis}); + histos.add("nsigmatof/mc_closure/neg/ka", "mc_closure dependent kaon", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis}); + + histos.add("nsigmatpc/mc_closure/pos/pr", "mc_closure dependent proton", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis}); + histos.add("nsigmatpc/mc_closure/neg/pr", "mc_closure dependent proton", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis}); + histos.add("nsigmatof/mc_closure/pos/pr", "mc_closure dependent proton", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis}); + histos.add("nsigmatof/mc_closure/neg/pr", "mc_closure dependent proton", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis}); + } + + if (doprocessOccupancy) { + histos.add("nsigmatpc/test_occupancy/Mult_vs_Occupancy", "occuppancy vs Multiplicity", kTHnSparseD, {multAxis, occupancyAxis}); + histos.add("nsigmatpc/test_occupancy/pos/pi", "occuppancy dependent pion", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis, occupancyAxis}); + histos.add("nsigmatpc/test_occupancy/neg/pi", "occuppancy dependent pion", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis, occupancyAxis}); + histos.add("nsigmatpc/test_occupancy/pos/ka", "occuppancy dependent kaon", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis, occupancyAxis}); + histos.add("nsigmatpc/test_occupancy/neg/ka", "occuppancy dependent kaon", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis, occupancyAxis}); + histos.add("nsigmatpc/test_occupancy/pos/pr", "occuppancy dependent proton", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis, occupancyAxis}); + histos.add("nsigmatpc/test_occupancy/neg/pr", "occuppancy dependent proton", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis, occupancyAxis}); + + histos.add("nsigmatof/test_occupancy/pos/pi", "occuppancy dependent pion", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis, occupancyAxis}); + histos.add("nsigmatof/test_occupancy/neg/pi", "occuppancy dependent pion", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis, occupancyAxis}); + histos.add("nsigmatof/test_occupancy/pos/ka", "occuppancy dependent kaon", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis, occupancyAxis}); + histos.add("nsigmatof/test_occupancy/neg/ka", "occuppancy dependent kaon", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis, occupancyAxis}); + histos.add("nsigmatof/test_occupancy/pos/pr", "occuppancy dependent proton", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis, occupancyAxis}); + histos.add("nsigmatof/test_occupancy/neg/pr", "occuppancy dependent proton", kTHnSparseD, {ptAxis, nsigmaTPCAxisOccupancy, multAxis, occupancyAxis}); + } + if (doprocessMC) { histos.add("MC/fake/pos", "Fake positive tracks", kTH1D, {ptAxis}); histos.add("MC/fake/neg", "Fake negative tracks", kTH1D, {ptAxis}); histos.add("MC/no_collision/pos", "No collision pos track", kTH1D, {ptAxis}); histos.add("MC/no_collision/neg", "No collision neg track", kTH1D, {ptAxis}); + if (isImpactParam) { + histos.add("MC/withPID/pi/pos/prm/pt/num", "recons. MC #pi^{+}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pi/neg/prm/pt/num", "recons. MC #pi^{-}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/ka/pos/prm/pt/num", "recons. MC K^{+}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/ka/neg/prm/pt/num", "recons. MC K^{-}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pr/pos/prm/pt/num", "recons. MC p", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pr/neg/prm/pt/num", "recons. MC #bar{p}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pi/pos/prm/pt/num_str", "recons. MC #pi^{+}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pi/neg/prm/pt/num_str", "recons. MC #pi^{-}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/ka/pos/prm/pt/num_str", "recons. MC K^{+}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/ka/neg/prm/pt/num_str", "recons. MC K^{-}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pr/pos/prm/pt/num_str", "recons. MC p", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pr/neg/prm/pt/num_str", "recons. MC #bar{p}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pi/pos/prm/pt/num_mat", "recons. MC #pi^{+}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pi/neg/prm/pt/num_mat", "recons. MC #pi^{-}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/ka/pos/prm/pt/num_mat", "recons. MC K^{+}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/ka/neg/prm/pt/num_mat", "recons. MC K^{-}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pr/pos/prm/pt/num_mat", "recons. MC p", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pr/neg/prm/pt/num_mat", "recons. MC #bar{p}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pi/pos/prm/pt/numtof", "recons. MC #pi^{+}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pi/neg/prm/pt/numtof", "recons. MC #pi^{-}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/ka/pos/prm/pt/numtof", "recons. MC K^{+}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/ka/neg/prm/pt/numtof", "recons. MC K^{-}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pr/pos/prm/pt/numtof", "recons. MC p", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pr/neg/prm/pt/numtof", "recons. MC #bar{p}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pi/pos/prm/pt/numtof_matched", "recons. MC #pi^{+}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pi/neg/prm/pt/numtof_matched", "recons. MC #pi^{-}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/ka/pos/prm/pt/numtof_matched", "recons. MC K^{+}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/ka/neg/prm/pt/numtof_matched", "recons. MC K^{-}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pr/pos/prm/pt/numtof_matched", "recons. MC p", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/withPID/pr/neg/prm/pt/numtof_matched", "recons. MC #bar{p}", kTHnSparseD, {ptAxis, impParamAxis}); + } else { + histos.add("MC/withPID/pi/pos/prm/pt/num", "recons. MC #pi^{+}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pi/neg/prm/pt/num", "recons. MC #pi^{-}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/ka/pos/prm/pt/num", "recons. MC K^{+}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/ka/neg/prm/pt/num", "recons. MC K^{-}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pr/pos/prm/pt/num", "recons. MC p", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pr/neg/prm/pt/num", "recons. MC #bar{p}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pi/pos/prm/pt/num_str", "recons. MC #pi^{+}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pi/neg/prm/pt/num_str", "recons. MC #pi^{-}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/ka/pos/prm/pt/num_str", "recons. MC K^{+}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/ka/neg/prm/pt/num_str", "recons. MC K^{-}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pr/pos/prm/pt/num_str", "recons. MC p", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pr/neg/prm/pt/num_str", "recons. MC #bar{p}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pi/pos/prm/pt/num_mat", "recons. MC #pi^{+}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pi/neg/prm/pt/num_mat", "recons. MC #pi^{-}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/ka/pos/prm/pt/num_mat", "recons. MC K^{+}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/ka/neg/prm/pt/num_mat", "recons. MC K^{-}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pr/pos/prm/pt/num_mat", "recons. MC p", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pr/neg/prm/pt/num_mat", "recons. MC #bar{p}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pi/pos/prm/pt/numtof", "recons. MC #pi^{+}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pi/neg/prm/pt/numtof", "recons. MC #pi^{-}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/ka/pos/prm/pt/numtof", "recons. MC K^{+}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/ka/neg/prm/pt/numtof", "recons. MC K^{-}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pr/pos/prm/pt/numtof", "recons. MC p", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pr/neg/prm/pt/numtof", "recons. MC #bar{p}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pi/pos/prm/pt/numtof_matched", "recons. MC #pi^{+}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pi/neg/prm/pt/numtof_matched", "recons. MC #pi^{-}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/ka/pos/prm/pt/numtof_matched", "recons. MC K^{+}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/ka/neg/prm/pt/numtof_matched", "recons. MC K^{-}", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pr/pos/prm/pt/numtof_matched", "recons. MC p", kTHnSparseD, {ptAxis, multAxis}); + histos.add("MC/withPID/pr/neg/prm/pt/numtof_matched", "recons. MC #bar{p}", kTHnSparseD, {ptAxis, multAxis}); + } + if (doprocessMCgen) { + histos.add("MC/test/pi/pos/prm/pt/den", "generated MC #pi^{+}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/test/pi/neg/prm/pt/den", "generated MC #pi^{-}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/test/ka/pos/prm/pt/den", "generated MC K^{+}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/test/ka/neg/prm/pt/den", "generated MC K^{-}", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/test/pr/pos/prm/pt/den", "generated MC p", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/test/pr/neg/prm/pt/den", "generated MC #bar{p}", kTHnSparseD, {ptAxis, impParamAxis}); + if (doprocessMCgen_RecoEvs) { + histos.add("MC/test/RecoEvs/pi/pos/prm/pt/num", "generated MC #pi^{+} from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/test/RecoEvs/pi/neg/prm/pt/num", "generated MC #pi^{-} from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/test/RecoEvs/ka/pos/prm/pt/num", "generated MC K^{+} from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/test/RecoEvs/ka/neg/prm/pt/num", "generated MC K^{-} from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/test/RecoEvs/pr/pos/prm/pt/num", "generated MC p from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/test/RecoEvs/pr/neg/prm/pt/num", "generated MC #bar{p} from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/test/RecoEvs/pi/pos/prm/pt/numtof", "generated MC #pi^{+} from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/test/RecoEvs/pi/neg/prm/pt/numtof", "generated MC #pi^{-} from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/test/RecoEvs/ka/pos/prm/pt/numtof", "generated MC K^{+} from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/test/RecoEvs/ka/neg/prm/pt/numtof", "generated MC K^{-} from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/test/RecoEvs/pr/pos/prm/pt/numtof", "generated MC p from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); + histos.add("MC/test/RecoEvs/pr/neg/prm/pt/numtof", "generated MC #bar{p} from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); + } + } auto hh = histos.add("MC/GenRecoCollisions", "Generated and Reconstructed MC Collisions", kTH1D, {{10, 0.5, 10.5}}); hh->GetXaxis()->SetBinLabel(1, "Collisions generated"); hh->GetXaxis()->SetBinLabel(2, "Collisions reconstructed"); hh->GetXaxis()->SetBinLabel(3, "INEL>0"); hh->GetXaxis()->SetBinLabel(4, "INEL>1"); hh->GetXaxis()->SetBinLabel(5, "hasParticleInFT0C && hasParticleInFT0A"); + histos.add("MC/MultiplicityRecoEv", "MC multiplicity", kTH1D, {multAxis}); + histos.add("MC/Multiplicity", "MC multiplicity", kTH1D, {multAxis}); + histos.add("MC/MultiplicityMCINELgt0", "MC multiplicity", kTH1D, {multAxis}); + histos.add("MC/MultiplicityMCINELgt1", "MC multiplicity", kTH1D, {multAxis}); } + hMultiplicityvsPercentile = histos.add("Mult/vsPercentile", "Multiplicity vs percentile", HistType::kTH2D, {{150, 0, 150}, {100, 0, 100, "Track multiplicity"}}); + for (int i = 0; i < NpCharge; i++) { switch (i) { case 0: @@ -391,48 +638,10 @@ struct tofSpectra { break; } - const AxisSpec nsigmaTPCAxis{binsnsigmaTPC, Form("N_{#sigma}^{TPC}(%s)", pTCharge[i])}; - const AxisSpec nsigmaTOFAxis{binsnsigmaTOF, Form("N_{#sigma}^{TOF}(%s)", pTCharge[i])}; - const AxisSpec deltaTPCAxis{binsdeltaTPC, Form("#Delta^{TPC}(%s)", pTCharge[i])}; - const AxisSpec deltaTOFAxis{binsdeltaTOF, Form("#Delta^{TOF}(%s)", pTCharge[i])}; - AxisSpec multAxis{binsMultiplicity, "Undefined multiplicity estimator"}; - - switch (multiplicityEstimator) { - case MultCodes::kNoMultiplicity: // No multiplicity - break; - case MultCodes::kMultFV0M: // MultFV0M - multAxis.name = "MultFV0M"; - break; - case MultCodes::kMultFT0M: // MultFT0M - multAxis.name = "MultFT0M"; - break; - case MultCodes::kMultFDDM: // MultFDDM - multAxis.name = "MultFDDM"; - break; - case MultCodes::kMultTracklets: // MultTracklets - multAxis.name = "MultTracklets"; - break; - case MultCodes::kMultTPC: // MultTPC - multAxis.name = "MultTPC"; - break; - case MultCodes::kMultNTracksPV: // MultNTracksPV - multAxis.name = "MultNTracksPV"; - break; - case MultCodes::kMultNTracksPVeta1: // MultNTracksPVeta1 - multAxis.name = "MultNTracksPVeta1"; - break; - case MultCodes::kCentralityFT0C: // Centrality FT0C - multAxis = {binsPercentile, "Centrality FT0C"}; - break; - case MultCodes::kCentralityFT0M: // Centrality FT0M - multAxis = {binsPercentile, "Centrality FT0M"}; - break; - case MultCodes::kCentralityFV0A: // Centrality FV0A - multAxis = {binsPercentile, "Centrality FV0A"}; - break; - default: - LOG(fatal) << "Unrecognized option for multiplicity " << multiplicityEstimator; - } + const AxisSpec nsigmaTPCAxis{binsOptions.binsnsigmaTPC, Form("N_{#sigma}^{TPC}(%s)", pTCharge[i])}; + const AxisSpec nsigmaTOFAxis{binsOptions.binsnsigmaTOF, Form("N_{#sigma}^{TOF}(%s)", pTCharge[i])}; + const AxisSpec deltaTPCAxis{binsOptions.binsdeltaTPC, Form("#Delta^{TPC}(%s)", pTCharge[i])}; + const AxisSpec deltaTOFAxis{binsOptions.binsdeltaTOF, Form("#Delta^{TOF}(%s)", pTCharge[i])}; if (multiplicityEstimator == MultCodes::kNoMultiplicity) { histos.add(hnsigmatof[i].data(), pTCharge[i], kTH2D, {ptAxis, nsigmaTOFAxis}); histos.add(hnsigmatpc[i].data(), pTCharge[i], kTH2D, {ptAxis, nsigmaTPCAxis}); @@ -441,16 +650,16 @@ struct tofSpectra { histos.add(hdeltatpc[i].data(), pTCharge[i], kTH2D, {ptAxis, deltaTPCAxis}); } if (enableTPCTOFHistograms) { - if (makeTHnSparseChoice) { // JL - histos.add(hnsigmatpctof[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, etaAxis, nsigmaTPCAxis, nsigmaTOFAxis}); // JL + if (enableTPCTOFvsEtaHistograms) { + histos.add(hnsigmatpctof[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, etaAxis, nsigmaTPCAxis, nsigmaTOFAxis}); } else { histos.add(hnsigmatpctof[i].data(), pTCharge[i], kTH3D, {ptAxis, nsigmaTPCAxis, nsigmaTOFAxis}); } } } else { - if (makeTHnSparseChoice) { // RD - histos.add(hnsigmatof[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, nsigmaTOFAxis, multAxis, dcaXyAxis, dcaZAxis, etaAxis}); // RD - histos.add(hnsigmatpc[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, nsigmaTPCAxis, multAxis, dcaXyAxis, dcaZAxis, etaAxis}); // RD + if (makeTHnSparseChoice) { // RD + histos.add(hnsigmatof[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, nsigmaTOFAxis, multAxis, dcaXyAxis}); // RD + histos.add(hnsigmatpc[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, nsigmaTPCAxis, multAxis, dcaXyAxis}); // RD } else { histos.add(hnsigmatof[i].data(), pTCharge[i], kTH3D, {ptAxis, nsigmaTOFAxis, multAxis}); histos.add(hnsigmatpc[i].data(), pTCharge[i], kTH3D, {ptAxis, nsigmaTPCAxis, multAxis}); @@ -460,83 +669,125 @@ struct tofSpectra { histos.add(hdeltatpc[i].data(), pTCharge[i], kTH3D, {ptAxis, deltaTPCAxis, multAxis}); } if (enableTPCTOFHistograms) { - if (makeTHnSparseChoice) { // JL - histos.add(hnsigmatpctof[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, etaAxis, nsigmaTPCAxis, nsigmaTOFAxis}); // JL - } else { - if (tpctofVsMult) { + if (enableTPCTOFVsMult) { + if (enableTPCTOFvsEtaHistograms) { + histos.add(hnsigmatpctof[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, etaAxis, nsigmaTPCAxis, nsigmaTOFAxis, multAxis}); + } else { histos.add(hnsigmatpctof[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, nsigmaTPCAxis, nsigmaTOFAxis, multAxis}); + } + } else { + if (enableTPCTOFvsEtaHistograms) { + histos.add(hnsigmatpctof[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, etaAxis, nsigmaTPCAxis, nsigmaTOFAxis}); } else { histos.add(hnsigmatpctof[i].data(), pTCharge[i], kTH3D, {ptAxis, nsigmaTPCAxis, nsigmaTOFAxis}); } } } } - if (enableDCAxyzHistograms) { - histos.add(hdcaxy[i].data(), pTCharge[i], kTH3D, {ptAxis, dcaXyAxis, dcaZAxis}); + if (enableDCAxyphiHistograms) { histos.add(hdcaxyphi[i].data(), Form("%s -- 0.9 < #it{p}_{T} < 1.1 GeV/#it{c}", pTCharge[i]), kTH3D, {phiAxis, dcaXyAxis, dcaZAxis}); + } + if (enableDCAxyzHistograms) { + hDcaXYZ[i] = histos.add(Form("dca/%s/%s", (i < Np) ? "pos" : "neg", pN[i % Np]), pTCharge[i], kTH3D, {ptAxis, dcaXyAxis, dcaZAxis}); } else { histos.add(hdcaxy[i].data(), pTCharge[i], kTH2D, {ptAxis, dcaXyAxis}); histos.add(hdcaz[i].data(), pTCharge[i], kTH2D, {ptAxis, dcaZAxis}); - histos.add(hdcaxyphi[i].data(), Form("%s -- 0.9 < #it{p}_{T} < 1.1 GeV/#it{c}", pTCharge[i]), kTH2D, {phiAxis, dcaXyAxis}); } if (doprocessMC) { + const std::string cpName = Form("/%s/%s", (i < Np) ? "pos" : "neg", pN[i % Np]); if (includeCentralityMC) { //*************************************RD********************************************** - histos.add(hpt_num_prm[i].data(), pTCharge[i], kTH3D, {ptAxis, multAxis, etaAxis}); - histos.add(hpt_num_str[i].data(), pTCharge[i], kTH3D, {ptAxis, multAxis, etaAxis}); - histos.add(hpt_num_mat[i].data(), pTCharge[i], kTH3D, {ptAxis, multAxis, etaAxis}); + if (isImpactParam) { + histos.add(hpt_num_prm[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, impParamAxis, dcaXyAxis, occupancyAxis}); + histos.add(hpt_num_str[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, impParamAxis, dcaXyAxis}); + histos.add(hpt_num_mat[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, impParamAxis, dcaXyAxis}); + + histos.add(hpt_numtof_prm[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, impParamAxis, dcaXyAxis, occupancyAxis}); + histos.add(hpt_numtof_str[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, impParamAxis, dcaXyAxis}); + histos.add(hpt_numtof_mat[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, impParamAxis, dcaXyAxis}); + } else { + histos.add(hpt_num_prm[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, multAxis, dcaXyAxis, occupancyAxis}); + histos.add(hpt_num_str[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add(hpt_num_mat[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + + histos.add(hpt_numtof_prm[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, multAxis, dcaXyAxis, occupancyAxis}); + histos.add(hpt_numtof_str[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + histos.add(hpt_numtof_mat[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); + } - histos.add(hpt_numtof_prm[i].data(), pTCharge[i], kTH3D, {ptAxis, multAxis, etaAxis}); - histos.add(hpt_numtof_str[i].data(), pTCharge[i], kTH3D, {ptAxis, multAxis, etaAxis}); - histos.add(hpt_numtof_mat[i].data(), pTCharge[i], kTH3D, {ptAxis, multAxis, etaAxis}); + histos.add(hpt_numtofgoodmatch_prm[i].data(), pTCharge[i], kTH3D, {ptAxis, multAxis, etaAxis}); - histos.add(hpt_den_prm[i].data(), pTCharge[i], kTH3D, {ptAxis, multAxis, etaAxis}); - histos.add(hpt_den_str[i].data(), pTCharge[i], kTH3D, {ptAxis, multAxis, etaAxis}); - histos.add(hpt_den_mat[i].data(), pTCharge[i], kTH3D, {ptAxis, multAxis, etaAxis}); + histos.add(hpt_den_prm[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, multAxis}); + histos.add(hpt_den_str[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, multAxis}); + histos.add(hpt_den_mat[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, multAxis}); histos.add(hpt_den_prm_recoev[i].data(), pTCharge[i], kTH3D, {ptAxis, multAxis, etaAxis}); histos.add(hpt_den_prm_evsel[i].data(), pTCharge[i], kTH3D, {ptAxis, multAxis, etaAxis}); histos.add(hpt_den_prm_goodev[i].data(), pTCharge[i], kTH3D, {ptAxis, multAxis, etaAxis}); //*************************************************************************************** } else { - histos.add(hpt_num_prm[i].data(), pTCharge[i], kTH1D, {ptAxis}); - histos.add(hpt_num_str[i].data(), pTCharge[i], kTH1D, {ptAxis}); - histos.add(hpt_num_mat[i].data(), pTCharge[i], kTH1D, {ptAxis}); + histos.add(hpt_num_prm[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); + histos.add(hpt_num_str[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); + histos.add(hpt_num_mat[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); + + histos.add(hpt_numtof_prm[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); + histos.add(hpt_numtof_str[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); + histos.add(hpt_numtof_mat[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); - histos.add(hpt_numtof_prm[i].data(), pTCharge[i], kTH1D, {ptAxis}); - histos.add(hpt_numtof_str[i].data(), pTCharge[i], kTH1D, {ptAxis}); - histos.add(hpt_numtof_mat[i].data(), pTCharge[i], kTH1D, {ptAxis}); + histos.add(hpt_numtofgoodmatch_prm[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); + hPtNumTOFMatchWithPIDSignalPrm[i] = histos.add("MC" + cpName + "/prm/pt/numtofwithpid", pTCharge[i], kTH2D, {ptAxis, multAxis}); - histos.add(hpt_den_prm[i].data(), pTCharge[i], kTH1D, {ptAxis}); - histos.add(hpt_den_str[i].data(), pTCharge[i], kTH1D, {ptAxis}); - histos.add(hpt_den_mat[i].data(), pTCharge[i], kTH1D, {ptAxis}); + histos.add(hpt_den_prm[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); + histos.add(hpt_den_str[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); + histos.add(hpt_den_mat[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); - histos.add(hpt_den_prm_recoev[i].data(), pTCharge[i], kTH1D, {ptAxis}); - histos.add(hpt_den_prm_evsel[i].data(), pTCharge[i], kTH1D, {ptAxis}); - histos.add(hpt_den_prm_goodev[i].data(), pTCharge[i], kTH1D, {ptAxis}); + histos.add(hpt_den_prm_recoev[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); + histos.add(hpt_den_prm_evsel[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); + histos.add(hpt_den_prm_goodev[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); } - histos.add(hpt_den_prm_mcgoodev[i].data(), pTCharge[i], kTH1D, {ptAxis}); - histos.add(hpt_den_prm_mcbadev[i].data(), pTCharge[i], kTH1D, {ptAxis}); + histos.add(hpt_den_prm_mcgoodev[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); + histos.add(hpt_den_prm_mcbadev[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); if (enableDCAxyzHistograms) { - histos.add(hdcaxyprm[i].data(), pTCharge[i], kTH3D, {ptAxis, dcaXyAxis, dcaZAxis}); - histos.add(hdcaxystr[i].data(), pTCharge[i], kTH3D, {ptAxis, dcaXyAxis, dcaZAxis}); - histos.add(hdcaxymat[i].data(), pTCharge[i], kTH3D, {ptAxis, dcaXyAxis, dcaZAxis}); + hDcaXYZPrm[i] = histos.add("dcaprm" + cpName, pTCharge[i], kTH3D, {ptAxis, dcaXyAxis, dcaZAxis}); + hDcaXYZStr[i] = histos.add("dcastr" + cpName, pTCharge[i], kTH3D, {ptAxis, dcaXyAxis, dcaZAxis}); + hDcaXYZMat[i] = histos.add("dcamat" + cpName, pTCharge[i], kTH3D, {ptAxis, dcaXyAxis, dcaZAxis}); if (enableDcaGoodEvents) { histos.add(hdcaxyprmgoodevs[i].data(), pTCharge[i], kTH3D, {ptAxis, dcaXyAxis, dcaZAxis}); } } else { + hDcaXYWrongCollisionPrm[i] = histos.add("dcaxywrongcollprm" + cpName, pTCharge[i], kTH2D, {ptAxis, dcaXyAxis}); + hDcaXYWrongCollisionStr[i] = histos.add("dcaxywrongcollstr" + cpName, pTCharge[i], kTH2D, {ptAxis, dcaXyAxis}); + hDcaXYWrongCollisionMat[i] = histos.add("dcaxywrongcollmat" + cpName, pTCharge[i], kTH2D, {ptAxis, dcaXyAxis}); + histos.add(hdcaxyprm[i].data(), pTCharge[i], kTH2D, {ptAxis, dcaXyAxis}); histos.add(hdcazprm[i].data(), pTCharge[i], kTH2D, {ptAxis, dcaZAxis}); histos.add(hdcaxystr[i].data(), pTCharge[i], kTH2D, {ptAxis, dcaXyAxis}); histos.add(hdcazstr[i].data(), pTCharge[i], kTH2D, {ptAxis, dcaZAxis}); histos.add(hdcaxymat[i].data(), pTCharge[i], kTH2D, {ptAxis, dcaXyAxis}); histos.add(hdcazmat[i].data(), pTCharge[i], kTH2D, {ptAxis, dcaZAxis}); + hDecayLengthStr[i] = histos.add("decaylengthstr" + cpName, pTCharge[i], kTH2D, {ptAxis, decayLengthAxis}); if (enableDcaGoodEvents) { histos.add(hdcaxyprmgoodevs[i].data(), pTCharge[i], kTH2D, {ptAxis, dcaXyAxis}); histos.add(hdcazprmgoodevs[i].data(), pTCharge[i], kTH2D, {ptAxis, dcaZAxis}); } + if (enableDCAvsmotherHistograms) { + hDcaXYMC[i] = histos.add("dcaxymc" + cpName, pTCharge[i], kTH2D, {ptAxis, dcaXyAxis}); + hDcaZMC[i] = histos.add("dcazmc" + cpName, pTCharge[i], kTH2D, {ptAxis, dcaZAxis}); + hDcaXYMCNotHF[i] = histos.add("dcaxynothf" + cpName, pTCharge[i], kTH2D, {ptAxis, dcaXyAxis}); + hDcaZMCNotHF[i] = histos.add("dcaznothf" + cpName, pTCharge[i], kTH2D, {ptAxis, dcaZAxis}); + hDcaXYMCD0[i] = histos.add("dcaxyD0" + cpName, pTCharge[i], kTH2D, {ptAxis, dcaXyAxis}); + hDcaZMCD0[i] = histos.add("dcazD0" + cpName, pTCharge[i], kTH2D, {ptAxis, dcaZAxis}); + hDcaXYMCCharm[i] = histos.add("dcaxycharm" + cpName, pTCharge[i], kTH2D, {ptAxis, dcaXyAxis}); + hdcaZMCCharm[i] = histos.add("dcazcharm" + cpName, pTCharge[i], kTH2D, {ptAxis, dcaZAxis}); + hDcaXYMCBeauty[i] = histos.add("dcaxybeauty" + cpName, pTCharge[i], kTH2D, {ptAxis, dcaXyAxis}); + hDcaZMCBeauty[i] = histos.add("dcazbeauty" + cpName, pTCharge[i], kTH2D, {ptAxis, dcaZAxis}); + hDecayLengthMCD0[i] = histos.add("decaylengthD0" + cpName, pTCharge[i], kTH2D, {ptAxis, decayLengthAxis}); + hDecayLengthMCCharm[i] = histos.add("decaylengthcharm" + cpName, pTCharge[i], kTH2D, {ptAxis, decayLengthAxis}); + hDecayLengthMCBeauty[i] = histos.add("decaylengthbeauty" + cpName, pTCharge[i], kTH2D, {ptAxis, decayLengthAxis}); + hDecayLengthMCNotHF[i] = histos.add("decaylengthnothf" + cpName, pTCharge[i], kTH2D, {ptAxis, decayLengthAxis}); + } } // Mismatched info @@ -551,34 +802,60 @@ struct tofSpectra { histos.print(); } + void processBC(soa::Join::iterator const& bc, + aod::FT0s const&) + { + if (!bc.has_ft0()) { + return; + } + const bool sel8 = bc.selection_bit(aod::evsel::kIsTriggerTVX) && bc.selection_bit(aod::evsel::kNoTimeFrameBorder) && bc.selection_bit(aod::evsel::kNoITSROFrameBorder); + const auto& ft0 = bc.ft0(); + + histos.fill(HIST("Mult/PerBC/FT0M"), ft0.sumAmpA() + ft0.sumAmpC()); + histos.fill(HIST("Mult/PerBC/FT0A"), ft0.sumAmpA()); + histos.fill(HIST("Mult/PerBC/FT0C"), ft0.sumAmpC()); + + if (!sel8) { + return; + } + + histos.fill(HIST("Mult/PerBC/sel8/FT0M"), ft0.sumAmpA() + ft0.sumAmpC()); + histos.fill(HIST("Mult/PerBC/sel8/FT0A"), ft0.sumAmpA()); + histos.fill(HIST("Mult/PerBC/sel8/FT0C"), ft0.sumAmpC()); + + histos.fill(HIST("Mult/PerBC/sel8/FT0AvsFT0C"), ft0.sumAmpA(), ft0.sumAmpC()); + + } // end of the process function + PROCESS_SWITCH(tofSpectra, processBC, "Processor of BCs for the FT0 calibration", true); + template void fillParticleHistos(const T& track, const C& collision) { - if (abs(track.rapidity(PID::getMass(id))) > cfgCutY) { + if (std::abs(track.rapidity(PID::getMass(id))) > trkselOptions.cfgCutY) { return; } if constexpr (id == PID::Kaon) { - if (ckeckKaonIsPvContrib && !track.isPVContributor()) { + if (kaonIsPvContrib && !track.isPVContributor()) { return; } } const auto& nsigmaTOF = o2::aod::pidutils::tofNSigma(track); const auto& nsigmaTPC = o2::aod::pidutils::tpcNSigma(track); + // const auto id = track.sign() > 0 ? id : id + Np; const float multiplicity = getMultiplicity(collision); - if (multiplicityEstimator == MultCodes::kNoMultiplicity) { if (track.sign() > 0) { histos.fill(HIST(hnsigmatpc[id]), track.pt(), nsigmaTPC); } else { histos.fill(HIST(hnsigmatpc[id + Np]), track.pt(), nsigmaTPC); } - } else if (makeTHnSparseChoice) { // RD - if (track.sign() > 0) { // RD - histos.fill(HIST(hnsigmatpc[id]), track.pt(), nsigmaTPC, multiplicity, track.dcaXY(), track.dcaZ(), track.eta()); // RD - } else { // RD - histos.fill(HIST(hnsigmatpc[id + Np]), track.pt(), nsigmaTPC, multiplicity, track.dcaXY(), track.dcaZ(), track.eta()); // RD - } // RD + } else if (makeTHnSparseChoice) { // RD + if (track.sign() > 0) { // RD + histos.fill(HIST(hnsigmatpc[id]), track.pt(), nsigmaTPC, multiplicity, track.dcaXY()); // RD + } else { // RD + histos.fill(HIST(hnsigmatpc[id + Np]), track.pt(), nsigmaTPC, multiplicity, track.dcaXY()); // RD + } } else { if (track.sign() > 0) { histos.fill(HIST(hnsigmatpc[id]), track.pt(), nsigmaTPC, multiplicity); @@ -610,10 +887,10 @@ struct tofSpectra { if (!track.hasTOF()) { return; } - if (requireTrdOnly == true && !track.hasTRD()) { + if (trkselOptions.requireTrdOnly == true && !track.hasTRD()) { return; } - if (requireNoTrd == true && track.hasTRD()) { + if (trkselOptions.requireNoTrd == true && track.hasTRD()) { return; } histos.fill(HIST("evtime_tof"), 0.f); @@ -629,7 +906,7 @@ struct tofSpectra { if (track.isEvTimeTOFT0AC()) { histos.fill(HIST("evtime_tof"), 4.f); } - switch (selectEvTime) { + switch (trkselOptions.selectEvTime) { case 0: break; case 1: @@ -658,7 +935,7 @@ struct tofSpectra { } break; default: - LOG(fatal) << "Fatal did not recognise value select event time" << selectEvTime; + LOG(fatal) << "Fatal did not recognise value select event time" << trkselOptions.selectEvTime; } histos.fill(HIST("evtime_tof"), 5.f); if (track.isEvTimeDefined()) { @@ -674,7 +951,7 @@ struct tofSpectra { histos.fill(HIST("evtime_tof"), 9.f); } - if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { + if (track.hasTRD() && (trkselOptions.lastRequiredTrdCluster > 0)) { int lastLayer = 0; for (int l = 7; l >= 0; l--) { if (track.trdPattern() & (1 << l)) { @@ -682,7 +959,7 @@ struct tofSpectra { break; } } - if (lastLayer < lastRequiredTrdCluster) { + if (lastLayer < trkselOptions.lastRequiredTrdCluster) { return; } } @@ -694,12 +971,12 @@ struct tofSpectra { histos.fill(HIST(hnsigmatof[id + Np]), track.pt(), nsigmaTOF); } } else { - if (makeTHnSparseChoice) { // RD - if (track.sign() > 0) { // RD - histos.fill(HIST(hnsigmatof[id]), track.pt(), nsigmaTOF, multiplicity, track.dcaXY(), track.dcaZ(), track.eta()); // RD - } else { // RD - histos.fill(HIST(hnsigmatof[id + Np]), track.pt(), nsigmaTOF, multiplicity, track.dcaXY(), track.dcaZ(), track.eta()); // RD - } // RD + if (makeTHnSparseChoice) { // RD + if (track.sign() > 0) { // RD + histos.fill(HIST(hnsigmatof[id]), track.pt(), nsigmaTOF, multiplicity, track.dcaXY()); // RD + } else { // RD + histos.fill(HIST(hnsigmatof[id + Np]), track.pt(), nsigmaTOF, multiplicity, track.dcaXY()); // RD + } } else { if (track.sign() > 0) { histos.fill(HIST(hnsigmatof[id]), track.pt(), nsigmaTOF, multiplicity); @@ -710,19 +987,27 @@ struct tofSpectra { } if (enableTPCTOFHistograms) { - if (makeTHnSparseChoice) { - if (track.sign() > 0) { - histos.fill(HIST(hnsigmatpctof[id]), track.pt(), track.eta(), nsigmaTPC, nsigmaTOF); + if (enableTPCTOFVsMult) { + if (enableTPCTOFvsEtaHistograms) { + if (track.sign() > 0) { + histos.fill(HIST(hnsigmatpctof[id]), track.pt(), track.eta(), nsigmaTPC, nsigmaTOF, multiplicity); + } else { + histos.fill(HIST(hnsigmatpctof[id + Np]), track.pt(), track.eta(), nsigmaTPC, nsigmaTOF, multiplicity); + } } else { - histos.fill(HIST(hnsigmatpctof[id + Np]), track.pt(), track.eta(), nsigmaTPC, nsigmaTOF); - } - } else { - if (tpctofVsMult) { if (track.sign() > 0) { histos.fill(HIST(hnsigmatpctof[id]), track.pt(), nsigmaTPC, nsigmaTOF, multiplicity); } else { histos.fill(HIST(hnsigmatpctof[id + Np]), track.pt(), nsigmaTPC, nsigmaTOF, multiplicity); } + } + } else { + if (enableTPCTOFvsEtaHistograms) { + if (track.sign() > 0) { + histos.fill(HIST(hnsigmatpctof[id]), track.pt(), track.eta(), nsigmaTPC, nsigmaTOF); + } else { + histos.fill(HIST(hnsigmatpctof[id + Np]), track.pt(), track.eta(), nsigmaTPC, nsigmaTOF); + } } else { if (track.sign() > 0) { histos.fill(HIST(hnsigmatpctof[id]), track.pt(), nsigmaTPC, nsigmaTOF); @@ -761,14 +1046,18 @@ struct tofSpectra { const bool isInPtRangeForPhi = track.pt() < 1.1f && track.pt() > 0.9f; if (enableDCAxyzHistograms) { if (track.sign() > 0) { - histos.fill(HIST(hdcaxy[id]), track.pt(), track.dcaXY(), track.dcaZ()); + hDcaXYZ[id]->Fill(track.pt(), track.dcaXY(), track.dcaZ()); if (isInPtRangeForPhi) { - histos.fill(HIST(hdcaxyphi[id]), track.phi(), track.dcaXY(), track.dcaZ()); + if (enableDCAxyphiHistograms) { + histos.fill(HIST(hdcaxyphi[id]), track.phi(), track.dcaXY(), track.dcaZ()); + } } } else { - histos.fill(HIST(hdcaxy[id + Np]), track.pt(), track.dcaXY(), track.dcaZ()); + hDcaXYZ[id + Np]->Fill(track.pt(), track.dcaXY(), track.dcaZ()); if (isInPtRangeForPhi) { - histos.fill(HIST(hdcaxyphi[id + Np]), track.phi(), track.dcaXY(), track.dcaZ()); + if (enableDCAxyphiHistograms) { + histos.fill(HIST(hdcaxyphi[id + Np]), track.phi(), track.dcaXY(), track.dcaZ()); + } } } } else { @@ -776,13 +1065,17 @@ struct tofSpectra { histos.fill(HIST(hdcaxy[id]), track.pt(), track.dcaXY()); histos.fill(HIST(hdcaz[id]), track.pt(), track.dcaZ()); if (isInPtRangeForPhi) { - histos.fill(HIST(hdcaxyphi[id]), track.phi(), track.dcaXY()); + if (enableDCAxyphiHistograms) { + histos.fill(HIST(hdcaxyphi[id]), track.phi(), track.dcaXY()); + } } } else { histos.fill(HIST(hdcaxy[id + Np]), track.pt(), track.dcaXY()); histos.fill(HIST(hdcaz[id + Np]), track.pt(), track.dcaZ()); if (isInPtRangeForPhi) { - histos.fill(HIST(hdcaxyphi[id + Np]), track.phi(), track.dcaXY()); + if (enableDCAxyphiHistograms) { + histos.fill(HIST(hdcaxyphi[id + Np]), track.phi(), track.dcaXY()); + } } } } @@ -802,68 +1095,80 @@ struct tofSpectra { histos.fill(HIST("evsel"), 1.f); } if constexpr (fillHistograms) { - if (collision.multNTracksPVeta1() >= 1) { + if (collision.isInelGt0()) { histos.fill(HIST("evsel"), 2.f); } - if (collision.multNTracksPVeta1() >= 2) { + if (collision.isInelGt1()) { histos.fill(HIST("evsel"), 3.f); } } - if (!collision.sel8()) { - return false; + if (evselOptions.askForCustomTVX) { + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + } else { + if (!collision.sel8()) { + return false; + } } - if (removeITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + if (evselOptions.requirekIsVertexTOFmatched && !collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { return false; } if constexpr (fillHistograms) { histos.fill(HIST("evsel"), 4.f); } - if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + if (evselOptions.removeITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { return false; } if constexpr (fillHistograms) { histos.fill(HIST("evsel"), 5.f); } - if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + if (evselOptions.removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { return false; } if constexpr (fillHistograms) { histos.fill(HIST("evsel"), 6.f); } - if (requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) { + if (evselOptions.requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { return false; } if constexpr (fillHistograms) { histos.fill(HIST("evsel"), 7.f); } - if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + if (evselOptions.requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) { return false; } if constexpr (fillHistograms) { histos.fill(HIST("evsel"), 8.f); } + if (evselOptions.removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } if constexpr (fillHistograms) { histos.fill(HIST("evsel"), 9.f); - if (collision.multNTracksPVeta1() >= 1) { - histos.fill(HIST("evsel"), 10.f); - } - if (collision.multNTracksPVeta1() >= 2) { + } + if constexpr (fillHistograms) { + histos.fill(HIST("evsel"), 10.f); + if (collision.isInelGt0()) { histos.fill(HIST("evsel"), 11.f); } + if (collision.isInelGt1()) { + histos.fill(HIST("evsel"), 12.f); + } } - if (abs(collision.posZ()) > cfgCutVertex) { + if (std::abs(collision.posZ()) > evselOptions.cfgCutVertex) { return false; } if constexpr (fillHistograms) { - histos.fill(HIST("evsel"), 12.f); - if (collision.multNTracksPVeta1() >= 1) { - histos.fill(HIST("evsel"), 13.f); - } else if (cfgINELCut == 1) { + histos.fill(HIST("evsel"), 13.f); + if (collision.isInelGt0()) { + histos.fill(HIST("evsel"), 14.f); + } else if (evselOptions.cfgINELCut == 1) { return false; } - if (collision.multNTracksPVeta1() >= 2) { - histos.fill(HIST("evsel"), 14.f); - } else if (cfgINELCut == 2) { + if (collision.isInelGt1()) { + histos.fill(HIST("evsel"), 15.f); + } else if (evselOptions.cfgINELCut == 2) { return false; } histos.fill(HIST("event/vertexz"), collision.posZ()); @@ -901,7 +1206,7 @@ struct tofSpectra { return false; } } - return (abs(track.dcaXY()) <= (maxDcaXYFactor.value * (0.0105f + 0.0350f / pow(track.pt(), 1.1f)))); + return (std::abs(track.dcaXY()) <= (maxDcaXYFactor.value * (0.0105f + 0.0350f / pow(track.pt(), 1.1f)))); } return track.isGlobalTrack(); } @@ -926,13 +1231,13 @@ struct tofSpectra { return track.isGlobalTrackWoDCA(); } - template - bool isTrackSelected(TrackType const& track) + template + bool isTrackSelected(TrackType const& track, CollisionType const& /*collision*/) { if constexpr (fillHistograms) { histos.fill(HIST("tracksel"), 1); } - if (track.eta() < cfgCutEtaMin || track.eta() > cfgCutEtaMax) { + if (track.eta() < trkselOptions.cfgCutEtaMin || track.eta() > trkselOptions.cfgCutEtaMax) { return false; } if constexpr (fillHistograms) { @@ -979,6 +1284,10 @@ struct tofSpectra { } } + if (track.tpcChi2NCl() < minChi2PerClusterTPC || track.tpcChi2NCl() > maxChi2PerClusterTPC) { + return false; + } + if (!passesCutWoDCA(track)) { return false; } @@ -1123,18 +1432,254 @@ struct tofSpectra { return false; } - using CollisionCandidate = soa::Join; + using CollisionCandidates = soa::Join; using TrackCandidates = soa::Join; + void processMCclosure(CollisionCandidates::iterator const& collisions, + soa::Join const& tracks, + aod::McTrackLabels const& mcTrackLabels, aod::McParticles const& mcParticles) + { + const float multiplicity = getMultiplicity(collisions); + // int trackwoCut = 0; int trackwCut = 0; + + for (const auto& track : tracks) { + if (!track.has_collision()) { + continue; + } + const auto& collision = track.collision_as(); + if (!isEventSelected(collision)) { + continue; + } + if (!isTrackSelected(track, collision)) { + continue; + } + // trackwoCut++; + if (std::abs(track.dcaXY()) > 0.05) { // Skipping tracks that don't pass the standard cuts + return; + } + + // trackwCut++; + const auto& mcLabel = mcTrackLabels.iteratorAt(track.globalIndex()); + const auto& mcParticle = mcParticles.iteratorAt(mcLabel.mcParticleId()); + int pdgCode = mcParticle.pdgCode(); + const auto& nsigmaTPCPi = o2::aod::pidutils::tpcNSigma<2>(track); + const auto& nsigmaTPCKa = o2::aod::pidutils::tpcNSigma<3>(track); + const auto& nsigmaTPCPr = o2::aod::pidutils::tpcNSigma<4>(track); + + bool isTPCPion = std::abs(nsigmaTPCPi) < trkselOptions.cfgCutNsigma; + bool isTPCKaon = std::abs(nsigmaTPCKa) < trkselOptions.cfgCutNsigma; + bool isTPCProton = std::abs(nsigmaTPCPr) < trkselOptions.cfgCutNsigma; + + const auto& nsigmaTOFPi = o2::aod::pidutils::tofNSigma<2>(track); + const auto& nsigmaTOFKa = o2::aod::pidutils::tofNSigma<3>(track); + const auto& nsigmaTOFPr = o2::aod::pidutils::tofNSigma<4>(track); + + bool isTOFPion = track.hasTOF() && std::abs(nsigmaTOFPi) < trkselOptions.cfgCutNsigma; + bool isTOFKaon = track.hasTOF() && std::abs(nsigmaTOFKa) < trkselOptions.cfgCutNsigma; + bool isTOFProton = track.hasTOF() && std::abs(nsigmaTOFPr) < trkselOptions.cfgCutNsigma; + // Precompute rapidity values to avoid redundant calculations + double rapidityPi = std::abs(track.rapidity(PID::getMass(2))); + double rapidityKa = std::abs(track.rapidity(PID::getMass(3))); + double rapidityPr = std::abs(track.rapidity(PID::getMass(4))); + if (track.eta() < trkselOptions.cfgCutEtaMin || track.eta() > trkselOptions.cfgCutEtaMax) { + return; + } + if (mcParticle.isPhysicalPrimary()) { + if (isTPCPion && rapidityPi <= trkselOptions.cfgCutY) { + if (usePDGcode) { + if (pdgCode == 211) { + histos.fill(HIST("nsigmatpc/mc_closure/pos/pi"), track.pt(), nsigmaTPCPi, multiplicity); + } else if (pdgCode == -211) { + histos.fill(HIST("nsigmatpc/mc_closure/neg/pi"), track.pt(), nsigmaTPCPi, multiplicity); + } + } else { + histos.fill(HIST("nsigmatpc/mc_closure/pos/pi"), track.pt(), nsigmaTPCPi, multiplicity); + histos.fill(HIST("nsigmatpc/mc_closure/neg/pi"), track.pt(), nsigmaTPCPi, multiplicity); + } + } + if (isTPCKaon && rapidityKa <= trkselOptions.cfgCutY) { + if (usePDGcode) { + if (pdgCode == 321) { + histos.fill(HIST("nsigmatpc/mc_closure/pos/ka"), track.pt(), nsigmaTPCKa, multiplicity); + } else if (pdgCode == -321) { + histos.fill(HIST("nsigmatpc/mc_closure/neg/ka"), track.pt(), nsigmaTPCKa, multiplicity); + } + } else { + histos.fill(HIST("nsigmatpc/mc_closure/pos/ka"), track.pt(), nsigmaTPCKa, multiplicity); + histos.fill(HIST("nsigmatpc/mc_closure/neg/ka"), track.pt(), nsigmaTPCKa, multiplicity); + } + } + if (isTPCProton && rapidityPr <= trkselOptions.cfgCutY) { + if (usePDGcode) { + if (pdgCode == 2212) { + histos.fill(HIST("nsigmatpc/mc_closure/pos/pr"), track.pt(), nsigmaTPCPr, multiplicity); + } else if (pdgCode == -2212) { + histos.fill(HIST("nsigmatpc/mc_closure/neg/pr"), track.pt(), nsigmaTPCPr, multiplicity); + } + } else { + histos.fill(HIST("nsigmatpc/mc_closure/pos/pr"), track.pt(), nsigmaTPCPr, multiplicity); + histos.fill(HIST("nsigmatpc/mc_closure/neg/pr"), track.pt(), nsigmaTPCPr, multiplicity); + } + } + + // TOF Selection and Histogram Filling + if (isTOFPion && rapidityPi <= trkselOptions.cfgCutY) { + if (usePDGcode) { + if (pdgCode == 211) { + histos.fill(HIST("nsigmatof/mc_closure/pos/pi"), track.pt(), nsigmaTOFPi, multiplicity); + } else if (pdgCode == -211) { + histos.fill(HIST("nsigmatof/mc_closure/neg/pi"), track.pt(), nsigmaTOFPi, multiplicity); + } + } else { + histos.fill(HIST("nsigmatof/mc_closure/pos/pi"), track.pt(), nsigmaTOFPi, multiplicity); + histos.fill(HIST("nsigmatof/mc_closure/neg/pi"), track.pt(), nsigmaTOFPi, multiplicity); + } + } + if (isTOFKaon && rapidityKa <= trkselOptions.cfgCutY) { + if (usePDGcode) { + if (pdgCode == 321) { + histos.fill(HIST("nsigmatof/mc_closure/pos/ka"), track.pt(), nsigmaTOFKa, multiplicity); + } else if (pdgCode == -321) { + histos.fill(HIST("nsigmatof/mc_closure/neg/ka"), track.pt(), nsigmaTOFKa, multiplicity); + } + } else { + histos.fill(HIST("nsigmatof/mc_closure/pos/ka"), track.pt(), nsigmaTOFKa, multiplicity); + histos.fill(HIST("nsigmatof/mc_closure/neg/ka"), track.pt(), nsigmaTOFKa, multiplicity); + } + } + if (isTOFProton && rapidityPr <= trkselOptions.cfgCutY) { + if (usePDGcode) { + if (pdgCode == 2212) { + histos.fill(HIST("nsigmatof/mc_closure/pos/pr"), track.pt(), nsigmaTOFPr, multiplicity); + } else if (pdgCode == -2212) { + histos.fill(HIST("nsigmatof/mc_closure/neg/pr"), track.pt(), nsigmaTOFPr, multiplicity); + } + } else { + histos.fill(HIST("nsigmatof/mc_closure/pos/pr"), track.pt(), nsigmaTOFPr, multiplicity); + histos.fill(HIST("nsigmatof/mc_closure/neg/pr"), track.pt(), nsigmaTOFPr, multiplicity); + } + } + } + } + } + PROCESS_SWITCH(tofSpectra, processMCclosure, "MC closure test", false); + + void processOccupancy(CollisionCandidates::iterator const& collision, + soa::Join const& tracks) + { + // Event selection criteria + /*if (!collision.sel8() || std::abs(collision.posZ()) > 10 || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder) || + !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || + !collision.selection_bit(aod::evsel::kNoSameBunchPileup) || + !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; + }*/ + if (!isEventSelected(collision)) { + return; + } + histos.fill(HIST("test_occupancy/event/vertexz"), collision.posZ()); + + // Multiplicity and occupancy + int occupancy = collision.trackOccupancyInTimeRange(); + const float multiplicity = getMultiplicity(collision); + histos.fill(HIST("nsigmatpc/test_occupancy/Mult_vs_Occupancy"), multiplicity, occupancy); + + int tpcCount = 0, tofCount = 0; + + for (const auto& track : tracks) { + // Track selection criteria + /* if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC || track.tpcChi2NCl() > maxChi2PerClusterTPC || track.tpcChi2NCl() > maxChi2PerClusterTPC || + track.itsChi2NCl() > maxChi2PerClusterITS || std::abs(track.dcaXY()) > maxDcaXYFactor.value * (0.0105f + 0.0350f / pow(track.pt(), 1.1f)) || std::abs(track.dcaZ()) > maxDcaZ.value || track.eta() < trkselOptions.cfgCutEtaMin || track.eta() > trkselOptions.cfgCutEtaMax || track.tpcCrossedRowsOverFindableCls() < minNCrossedRowsOverFindableClustersTPC || track.tpcNClsFound() < minTPCNClsFound || + !(o2::aod::track::ITSrefit) || !(o2::aod::track::TPCrefit)) { + continue; + }*/ + if (!isTrackSelected(track, collision)) { + continue; + } + const auto& nsigmaTPCPi = o2::aod::pidutils::tpcNSigma<2>(track); + const auto& nsigmaTPCKa = o2::aod::pidutils::tpcNSigma<3>(track); + const auto& nsigmaTPCPr = o2::aod::pidutils::tpcNSigma<4>(track); + + const bool isTPCPion = std::abs(nsigmaTPCPi) < trkselOptions.cfgCutNsigma; + const bool isTPCKaon = std::abs(nsigmaTPCKa) < trkselOptions.cfgCutNsigma; + const bool isTPCProton = std::abs(nsigmaTPCPr) < trkselOptions.cfgCutNsigma; + + const auto& nsigmaTOFPi = o2::aod::pidutils::tofNSigma<2>(track); + const auto& nsigmaTOFKa = o2::aod::pidutils::tofNSigma<3>(track); + const auto& nsigmaTOFPr = o2::aod::pidutils::tofNSigma<4>(track); + + const bool isTOFPion = track.hasTOF() && std::abs(nsigmaTOFPi) < trkselOptions.cfgCutNsigma; + const bool isTOFKaon = track.hasTOF() && std::abs(nsigmaTOFKa) < trkselOptions.cfgCutNsigma; + const bool isTOFProton = track.hasTOF() && std::abs(nsigmaTOFPr) < trkselOptions.cfgCutNsigma; + + // Apply rapidity cut for identified particles + if (isTPCPion && std::abs(track.rapidity(PID::getMass(2))) < trkselOptions.cfgCutY) { + tpcCount++; + if (track.sign() > 0) { + histos.fill(HIST("nsigmatpc/test_occupancy/pos/pi"), track.pt(), nsigmaTPCPi, multiplicity, occupancy); + } else { + histos.fill(HIST("nsigmatpc/test_occupancy/neg/pi"), track.pt(), nsigmaTPCPi, multiplicity, occupancy); + } + } else if (isTPCKaon && std::abs(track.rapidity(PID::getMass(3))) < trkselOptions.cfgCutY) { + tpcCount++; + if (track.sign() > 0) { + histos.fill(HIST("nsigmatpc/test_occupancy/pos/ka"), track.pt(), nsigmaTPCKa, multiplicity, occupancy); + } else { + histos.fill(HIST("nsigmatpc/test_occupancy/neg/ka"), track.pt(), nsigmaTPCKa, multiplicity, occupancy); + } + } else if (isTPCProton && std::abs(track.rapidity(PID::getMass(4))) < trkselOptions.cfgCutY) { + tpcCount++; + if (track.sign() > 0) { + histos.fill(HIST("nsigmatpc/test_occupancy/pos/pr"), track.pt(), nsigmaTPCPr, multiplicity, occupancy); + } else { + histos.fill(HIST("nsigmatpc/test_occupancy/neg/pr"), track.pt(), nsigmaTPCPr, multiplicity, occupancy); + } + } + + // TOF PID histograms + if (isTOFPion && std::abs(track.rapidity(PID::getMass(2))) < trkselOptions.cfgCutY) { + tofCount++; + if (track.sign() > 0) { + histos.fill(HIST("nsigmatof/test_occupancy/pos/pi"), track.pt(), nsigmaTOFPi, multiplicity, occupancy); + } else { + histos.fill(HIST("nsigmatof/test_occupancy/neg/pi"), track.pt(), nsigmaTOFPi, multiplicity, occupancy); + } + } else if (isTOFKaon && std::abs(track.rapidity(PID::getMass(3))) < trkselOptions.cfgCutY) { + tofCount++; + if (track.sign() > 0) { + histos.fill(HIST("nsigmatof/test_occupancy/pos/ka"), track.pt(), nsigmaTOFKa, multiplicity, occupancy); + } else { + histos.fill(HIST("nsigmatof/test_occupancy/neg/ka"), track.pt(), nsigmaTOFKa, multiplicity, occupancy); + } + } else if (isTOFProton && std::abs(track.rapidity(PID::getMass(4))) < trkselOptions.cfgCutY) { + tofCount++; + if (track.sign() > 0) { + histos.fill(HIST("nsigmatof/test_occupancy/pos/pr"), track.pt(), nsigmaTOFPr, multiplicity, occupancy); + } else { + histos.fill(HIST("nsigmatof/test_occupancy/neg/pr"), track.pt(), nsigmaTOFPr, multiplicity, occupancy); + } + } + } + histos.fill(HIST("test_occupancy/tpcCount"), tpcCount); + histos.fill(HIST("test_occupancy/tofCount"), tofCount); + } // process function + PROCESS_SWITCH(tofSpectra, processOccupancy, "check for occupancy plots", true); - void processStandard(CollisionCandidate::iterator const& collision, + void processStandard(CollisionCandidates::iterator const& collision, TrackCandidates const& tracks) { if (!isEventSelected(collision)) { return; } + hMultiplicityvsPercentile->Fill(getMultiplicity(collision), collision.multNTracksPV()); for (const auto& track : tracks) { - if (!isTrackSelected(track)) { + if (!isTrackSelected(track, collision)) { continue; } } @@ -1152,7 +1697,7 @@ struct tofSpectra { } const auto& tracksInCollision = tracks.sliceByCached(aod::spectra::collisionId, collision.globalIndex(), cacheTrk); for (const auto& track : tracksInCollision) { - if (!isTrackSelected(track)) { + if (!isTrackSelected(track, collision)) { continue; } fillParticleHistos(track, collision); @@ -1164,7 +1709,7 @@ struct tofSpectra { PROCESS_SWITCH(tofSpectra, processDerived, "Derived data processor", false); #define makeProcessFunction(processorName, inputPid, particleId, isFull, tofTable, tpcTable) \ - void process##processorName##inputPid(CollisionCandidate::iterator const& collision, \ + void process##processorName##inputPid(CollisionCandidates::iterator const& collision, \ soa::Join const& tracks) \ @@ -1173,7 +1718,7 @@ struct tofSpectra { return; \ } \ for (const auto& track : tracks) { \ - if (!isTrackSelected(track)) { \ + if (!isTrackSelected(track, collision)) { \ continue; \ } \ fillParticleHistos(track, collision); \ @@ -1209,42 +1754,74 @@ struct tofSpectra { makeProcessFunctionFull(Al, Alpha); #undef makeProcessFunctionFull - template + template float getMultiplicity(const CollisionType& collision) { switch (multiplicityEstimator) { case MultCodes::kNoMultiplicity: // No multiplicity - return 50; // to check if its filled + return 50.f; // to check if its filled break; case MultCodes::kMultFV0M: // MultFV0M - return collision.multZeqFV0A(); + if constexpr (!isMC) { + return collision.multZeqFV0A(); + } else { + return 50.f; // Not implemented yet + } break; case MultCodes::kMultFT0M: - return collision.multZeqFT0A() + collision.multZeqFT0C(); + if constexpr (!isMC) { + return collision.multZeqFT0A() + collision.multZeqFT0C(); + } else { + return 50.f; // Not implemented yet + } break; case MultCodes::kMultFDDM: // MultFDDM - return collision.multZeqFDDA() + collision.multZeqFDDC(); + if constexpr (!isMC) { + return collision.multZeqFDDA() + collision.multZeqFDDC(); + } else { + return 50.f; // Not implemented yet + } break; case MultCodes::kMultTracklets: // MultTracklets - // return collision.multTracklets(); + if constexpr (!isMC) { + // return collision.multTracklets(); + } else { + return 50.f; // Not implemented yet + } return 0.f; // Undefined in Run3 break; case MultCodes::kMultTPC: // MultTPC - return collision.multTPC(); + if constexpr (!isMC) { + return collision.multTPC(); + } else { + return 50.f; // Not implemented yet + } break; case MultCodes::kMultNTracksPV: // MultNTracksPV - // return collision.multNTracksPV(); - return collision.multZeqNTracksPV(); + if constexpr (!isMC) { + // return collision.multNTracksPV(); + return collision.multZeqNTracksPV(); + } else { + return 50.f; // Not implemented yet + } break; case MultCodes::kMultNTracksPVeta1: // MultNTracksPVeta1 - return collision.multNTracksPVeta1(); + if constexpr (!isMC) { + return collision.multNTracksPVeta1(); + } else { + return 50.f; // Not implemented yet + } break; case MultCodes::kCentralityFT0C: // Centrality FT0C - return collision.centFT0C(); + if constexpr (!isMC) { + return collision.centFT0C(); + } else { + return 50.f; // Not implemented yet + } break; case MultCodes::kCentralityFT0M: // Centrality FT0M - return collision.centFT0M(); // collision.centFT0A() + return collision.centFT0M(); break; default: LOG(fatal) << "Unknown multiplicity estimator: " << multiplicityEstimator; @@ -1252,152 +1829,400 @@ struct tofSpectra { } } - using CollisionCandidateMC = soa::Join; // RD + using GenMCCollisions = soa::Join; + float getMultiplicityMC(const GenMCCollisions::iterator& collision) { return getMultiplicity(collision); } + + template + bool isParticleEnabled() + { + if constexpr (id == 0 || id == Np) { + if (doprocessFullEl == true || doprocessLfFullEl == true) { + return true; + } + } else if constexpr (id == 1 || id == Np + 1) { + if (doprocessFullMu == true || doprocessLfFullMu == true) { + return true; + } + } else if constexpr (id == 2 || id == Np + 2) { + if (doprocessFullPi == true || doprocessLfFullPi == true) { + return true; + } + } else if constexpr (id == 3 || id == Np + 3) { + if (doprocessFullKa == true || doprocessLfFullKa == true) { + return true; + } + } else if constexpr (id == 4 || id == Np + 4) { + if (doprocessFullPr == true || doprocessLfFullPr == true) { + return true; + } + } else if constexpr (id == 5 || id == Np + 5) { + if (doprocessFullDe == true || doprocessLfFullDe == true) { + return true; + } + } else if constexpr (id == 6 || id == Np + 6) { + if (doprocessFullTr == true || doprocessLfFullTr == true) { + return true; + } + } else if constexpr (id == 7 || id == Np + 7) { + if (doprocessFullHe == true || doprocessLfFullHe == true) { + return true; + } + } else if constexpr (id == 8 || id == Np + 8) { + if (doprocessFullAl == true || doprocessLfFullAl == true) { + return true; + } + } else { + LOG(fatal) << "Unknown particle id: " << id; + } + return false; + } + + using RecoMCCollisions = soa::Join; // RD template - void fillTrackHistograms_MC(TrackType const& track, ParticleType const& mcParticle, CollisionCandidateMC::iterator const& collision) + void fillTrackHistograms_MC(TrackType const& track, + ParticleType::iterator const& mcParticle, + RecoMCCollisions::iterator const& collision, + ParticleType const& mcParticles) { + if (!isParticleEnabled()) { // Check if the particle is enabled + return; + } - switch (i) { - case 0: - case Np: - if (doprocessFullEl == false && doprocessLfFullEl == false) { - return; - } - break; - case 1: - case Np + 1: - if (doprocessFullMu == false && doprocessLfFullMu == false) { - return; - } - break; - case 2: - case Np + 2: - if (doprocessFullPi == false && doprocessLfFullPi == false) { - return; - } - break; - case 3: - case Np + 3: - if (doprocessFullKa == false && doprocessLfFullKa == false) { - return; - } - break; - case 4: - case Np + 4: - if (doprocessFullPr == false && doprocessLfFullPr == false) { - return; - } - break; - case 5: - case Np + 5: - if (doprocessFullDe == false && doprocessLfFullDe == false) { - return; - } - break; - case 6: - case Np + 6: - if (doprocessFullTr == false && doprocessLfFullTr == false) { - return; - } - break; - case 7: - case Np + 7: - if (doprocessFullHe == false && doprocessLfFullHe == false) { - return; - } - break; - case 8: - case Np + 8: - if (doprocessFullAl == false && doprocessLfFullAl == false) { - return; - } - break; - } - + const auto& mcCollision = collision.mcCollision_as(); + const float multiplicity = getMultiplicityMC(mcCollision); + const int occupancy = collision.trackOccupancyInTimeRange(); //************************************RD************************************************** - const float multiplicity = getMultiplicity(collision); + const float impParam = mcCollision.impactParameter(); //************************************RD************************************************** if (mcParticle.pdgCode() != PDGs[i]) { return; } - if (track.eta() < cfgCutEtaMin || track.eta() > cfgCutEtaMax) { + + if (track.eta() < trkselOptions.cfgCutEtaMin || track.eta() > trkselOptions.cfgCutEtaMax) { return; } - if (std::abs(mcParticle.y()) > cfgCutY) { + if (std::abs(mcParticle.y()) > trkselOptions.cfgCutY) { return; } - if (!mcParticle.isPhysicalPrimary()) { - if (mcParticle.getProcess() == 4) { - if (enableDCAxyzHistograms) { - histos.fill(HIST(hdcaxystr[i]), track.pt(), track.dcaXY(), track.dcaZ()); - } else { - histos.fill(HIST(hdcaxystr[i]), track.pt(), track.dcaXY()); - histos.fill(HIST(hdcazstr[i]), track.pt(), track.dcaZ()); + + const auto& nsigmaTPCKa = o2::aod::pidutils::tpcNSigma<3>(track); + const bool isKaonTPC = std::abs(nsigmaTPCKa) < trkselOptions.cfgCutNsigma; + + const auto& nsigmaTOFKa = o2::aod::pidutils::tofNSigma<3>(track); + const bool isKaonTOF = std::abs(nsigmaTOFKa) < trkselOptions.cfgCutNsigma; + + // Filling DCA info with the TPC+TOF PID + bool isDCAPureSample = (std::sqrt(nsigmaTOFKa * nsigmaTOFKa + nsigmaTPCKa * nsigmaTPCKa) < 2.f); + if (track.pt() <= 0.4) { + isDCAPureSample = (nsigmaTPCKa < 1.f); + } + + if (isDCAPureSample) { + if (enableDCAvsmotherHistograms) { + hDcaXYMC[i]->Fill(track.pt(), track.dcaXY()); + hDcaZMC[i]->Fill(track.pt(), track.dcaZ()); + } + + if (!mcParticle.isPhysicalPrimary()) { // Secondaries (weak decays and material) + if (mcParticle.getProcess() == 4) { // Particles from decay + if (enableDCAxyzHistograms) { + hDcaXYZStr[i]->Fill(track.pt(), track.dcaXY(), track.dcaZ()); + } else { + histos.fill(HIST(hdcaxystr[i]), track.pt(), track.dcaXY()); + histos.fill(HIST(hdcazstr[i]), track.pt(), track.dcaZ()); + } + + if (mcParticle.has_mothers()) { + for (const auto& mother : mcParticle.template mothers_as()) { + auto daughter0 = mother.template daughters_as().begin(); + double vertexDau[3] = {daughter0.vx(), daughter0.vy(), daughter0.vz()}; + double vertexMoth[3] = {mother.vx(), mother.vy(), mother.vz()}; + auto decayLength = RecoDecay::distance(vertexMoth, vertexDau); + hDecayLengthStr[i]->Fill(track.pt(), decayLength); + } + } + } else { // Particles from the material + if (enableDCAxyzHistograms) { + hDcaXYZMat[i]->Fill(track.pt(), track.dcaXY(), track.dcaZ()); + } else { + histos.fill(HIST(hdcaxymat[i]), track.pt(), track.dcaXY()); + histos.fill(HIST(hdcazmat[i]), track.pt(), track.dcaZ()); + } } - } else { + } else { // Primaries if (enableDCAxyzHistograms) { - histos.fill(HIST(hdcaxymat[i]), track.pt(), track.dcaXY(), track.dcaZ()); + hDcaXYZPrm[i]->Fill(track.pt(), track.dcaXY(), track.dcaZ()); + if (enableDcaGoodEvents.value && collision.has_mcCollision()) { + histos.fill(HIST(hdcaxyprmgoodevs[i]), track.pt(), track.dcaXY(), track.dcaZ()); + } } else { - histos.fill(HIST(hdcaxymat[i]), track.pt(), track.dcaXY()); - histos.fill(HIST(hdcazmat[i]), track.pt(), track.dcaZ()); - } - } - } else { - if (enableDCAxyzHistograms) { - histos.fill(HIST(hdcaxyprm[i]), track.pt(), track.dcaXY(), track.dcaZ()); - if (enableDcaGoodEvents.value && collision.has_mcCollision()) { - histos.fill(HIST(hdcaxyprmgoodevs[i]), track.pt(), track.dcaXY(), track.dcaZ()); + // DCAxy for all primaries + histos.fill(HIST(hdcaxyprm[i]), track.pt(), track.dcaXY()); + histos.fill(HIST(hdcazprm[i]), track.pt(), track.dcaZ()); } - } else { - histos.fill(HIST(hdcaxyprm[i]), track.pt(), track.dcaXY()); - histos.fill(HIST(hdcazprm[i]), track.pt(), track.dcaZ()); if (enableDcaGoodEvents.value && collision.has_mcCollision()) { histos.fill(HIST(hdcaxyprmgoodevs[i]), track.pt(), track.dcaXY()); histos.fill(HIST(hdcazprmgoodevs[i]), track.pt(), track.dcaZ()); } + + if (enableDCAvsmotherHistograms) { + bool IsD0Mother = false; + bool IsCharmMother = false; + bool IsBeautyMother = false; + bool IsNotHFMother = false; + if (mcParticle.has_mothers()) { + const int charmOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, false); + for (const auto& mother : mcParticle.template mothers_as()) { + const int motherPdgCode = std::abs(mother.pdgCode()); + if (motherPdgCode == 421) { + IsD0Mother = true; + } + if (charmOrigin == RecoDecay::OriginType::NonPrompt) { + IsBeautyMother = true; + } + if (charmOrigin == RecoDecay::OriginType::Prompt) { + IsCharmMother = true; + } + if (charmOrigin == RecoDecay::OriginType::None) { + IsNotHFMother = true; + } + } + } + if (IsD0Mother) { + hDcaXYMCD0[i]->Fill(track.pt(), track.dcaXY()); + hDcaZMCD0[i]->Fill(track.pt(), track.dcaZ()); + } + if (IsCharmMother) { + hDcaXYMCCharm[i]->Fill(track.pt(), track.dcaXY()); + hdcaZMCCharm[i]->Fill(track.pt(), track.dcaZ()); + } + if (IsBeautyMother) { + hDcaXYMCBeauty[i]->Fill(track.pt(), track.dcaXY()); + hDcaZMCBeauty[i]->Fill(track.pt(), track.dcaZ()); + } + if (IsNotHFMother) { + hDcaXYMCNotHF[i]->Fill(track.pt(), track.dcaXY()); + hDcaZMCNotHF[i]->Fill(track.pt(), track.dcaZ()); + } + + if (mcParticle.has_mothers()) { + for (const auto& mother : mcParticle.template mothers_as()) { + auto daughter0 = mother.template daughters_as().begin(); + double vertexDau[3] = {daughter0.vx(), daughter0.vy(), daughter0.vz()}; + double vertexMoth[3] = {mother.vx(), mother.vy(), mother.vz()}; + auto decayLength = RecoDecay::distance(vertexMoth, vertexDau); + + if (IsD0Mother) { + hDecayLengthMCD0[i]->Fill(track.pt(), decayLength); + } + if (IsCharmMother) { + hDecayLengthMCCharm[i]->Fill(track.pt(), decayLength); + } + if (IsBeautyMother) { + hDecayLengthMCBeauty[i]->Fill(track.pt(), decayLength); + } + if (IsNotHFMother) { + hDecayLengthMCNotHF[i]->Fill(track.pt(), decayLength); + } + } + } + } + } + } + + if ((collision.has_mcCollision() && (mcParticle.mcCollisionId() != collision.mcCollisionId())) || !collision.has_mcCollision()) { + if (!mcParticle.isPhysicalPrimary()) { + if (mcParticle.getProcess() == 4) { + hDcaXYWrongCollisionStr[i]->Fill(track.pt(), track.dcaXY()); + } else { + hDcaXYWrongCollisionMat[i]->Fill(track.pt(), track.dcaXY()); + } + } else { + hDcaXYWrongCollisionPrm[i]->Fill(track.pt(), track.dcaXY()); } } if (!passesDCAxyCut(track)) { // Skipping tracks that don't pass the standard cuts return; } + const int pdgCode = mcParticle.pdgCode(); + const auto& nsigmaTPCPi = o2::aod::pidutils::tpcNSigma<2>(track); + const auto& nsigmaTPCPr = o2::aod::pidutils::tpcNSigma<4>(track); - if (!mcParticle.isPhysicalPrimary()) { - if (mcParticle.getProcess() == 4) { + const bool isPionTPC = std::abs(nsigmaTPCPi) < trkselOptions.cfgCutNsigma; + const bool isProtonTPC = std::abs(nsigmaTPCPr) < trkselOptions.cfgCutNsigma; + + const auto& nsigmaTOFPi = o2::aod::pidutils::tofNSigma<2>(track); + const auto& nsigmaTOFPr = o2::aod::pidutils::tofNSigma<4>(track); + + const bool isPionTOF = std::abs(nsigmaTOFPi) < trkselOptions.cfgCutNsigma; + const bool isProtonTOF = std::abs(nsigmaTOFPr) < trkselOptions.cfgCutNsigma; + + if (!mcParticle.isPhysicalPrimary()) { // Is not physical primary + if (mcParticle.getProcess() == 4) { // Is from decay if (includeCentralityMC) { - histos.fill(HIST(hpt_num_str[i]), track.pt(), multiplicity, track.eta()); // RD - if (track.hasTOF()) { - histos.fill(HIST(hpt_numtof_str[i]), track.pt(), multiplicity, track.eta()); // RD + if (includeCentralityMC) { + histos.fill(HIST(hpt_num_str[i]), track.pt(), multiplicity, track.dcaXY()); } } else { - histos.fill(HIST(hpt_num_str[i]), track.pt()); - if (track.hasTOF()) { - histos.fill(HIST(hpt_numtof_str[i]), track.pt()); + histos.fill(HIST(hpt_num_str[i]), track.pt(), multiplicity); + } + if (track.hasTOF()) { + if (includeCentralityMC) { + histos.fill(HIST(hpt_numtof_str[i]), track.pt(), multiplicity, track.dcaXY()); + } else { + histos.fill(HIST(hpt_numtof_str[i]), track.pt(), multiplicity); } } } else { if (includeCentralityMC) { - histos.fill(HIST(hpt_num_mat[i]), track.pt(), multiplicity, track.eta()); // RD + histos.fill(HIST(hpt_num_mat[i]), track.pt(), multiplicity, track.dcaXY()); if (track.hasTOF()) { - histos.fill(HIST(hpt_numtof_mat[i]), track.pt(), multiplicity, track.eta()); // RD + histos.fill(HIST(hpt_numtof_mat[i]), track.pt(), multiplicity, track.dcaXY()); } - } else { - histos.fill(HIST(hpt_num_mat[i]), track.pt()); + histos.fill(HIST(hpt_num_mat[i]), track.pt(), multiplicity); if (track.hasTOF()) { - histos.fill(HIST(hpt_numtof_mat[i]), track.pt()); + histos.fill(HIST(hpt_numtof_mat[i]), track.pt(), multiplicity); } } } - } else { + } else { // Is physical primary if (includeCentralityMC) { - histos.fill(HIST(hpt_num_prm[i]), track.pt(), multiplicity, track.eta()); // RD + if (isImpactParam) { + histos.fill(HIST(hpt_num_prm[i]), track.pt(), impParam, track.dcaXY(), occupancy); + } else { + histos.fill(HIST(hpt_num_prm[i]), track.pt(), multiplicity, track.dcaXY(), occupancy); + } } else { - histos.fill(HIST(hpt_num_prm[i]), track.pt()); + histos.fill(HIST(hpt_num_prm[i]), track.pt(), multiplicity); + } + if (isPionTPC || isKaonTPC || isProtonTPC) { + if (pdgCode == 2212) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/pr/pos/prm/pt/num"), track.pt(), impParam); + if (!mcParticle.isPhysicalPrimary()) { + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/withPID/pr/pos/prm/pt/num_str"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/pr/pos/prm/pt/num_mat"), track.pt(), impParam); + } + } + } else { + histos.fill(HIST("MC/withPID/pr/pos/prm/pt/num"), track.pt(), multiplicity); + if (!mcParticle.isPhysicalPrimary()) { + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/withPID/pr/pos/prm/pt/num_str"), track.pt(), multiplicity); + } else { + histos.fill(HIST("MC/withPID/pr/pos/prm/pt/num_mat"), track.pt(), multiplicity); + } + } + } + } else if (pdgCode == -2212) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/pr/neg/prm/pt/num"), track.pt(), impParam); + if (!mcParticle.isPhysicalPrimary()) { + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/withPID/pr/neg/prm/pt/num_str"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/pr/neg/prm/pt/num_mat"), track.pt(), impParam); + } + } + } else { + histos.fill(HIST("MC/withPID/pr/neg/prm/pt/num"), track.pt(), multiplicity); + if (!mcParticle.isPhysicalPrimary()) { + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/withPID/pr/neg/prm/pt/num_str"), track.pt(), multiplicity); + } else { + histos.fill(HIST("MC/withPID/pr/neg/prm/pt/num_mat"), track.pt(), multiplicity); + } + } + } + } else if (pdgCode == 211) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/pi/pos/prm/pt/num"), track.pt(), impParam); + if (!mcParticle.isPhysicalPrimary()) { + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/withPID/pi/pos/prm/pt/num_str"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/pi/pos/prm/pt/num_mat"), track.pt(), impParam); + } + } + } else { + histos.fill(HIST("MC/withPID/pi/pos/prm/pt/num"), track.pt(), multiplicity); + if (!mcParticle.isPhysicalPrimary()) { + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/withPID/pi/pos/prm/pt/num_str"), track.pt(), multiplicity); + } else { + histos.fill(HIST("MC/withPID/pi/pos/prm/pt/num_mat"), track.pt(), multiplicity); + } + } + } + } else if (pdgCode == -211) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/pi/neg/prm/pt/num"), track.pt(), impParam); + if (!mcParticle.isPhysicalPrimary()) { + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/withPID/pi/neg/prm/pt/num_str"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/pi/neg/prm/pt/num_mat"), track.pt(), impParam); + } + } + } else { + histos.fill(HIST("MC/withPID/pi/neg/prm/pt/num"), track.pt(), multiplicity); + if (!mcParticle.isPhysicalPrimary()) { + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/withPID/pi/neg/prm/pt/num_str"), track.pt(), multiplicity); + } else { + histos.fill(HIST("MC/withPID/pi/neg/prm/pt/num_mat"), track.pt(), multiplicity); + } + } + } + } else if (pdgCode == 321) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/ka/pos/prm/pt/num"), track.pt(), impParam); + if (!mcParticle.isPhysicalPrimary()) { + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/withPID/ka/pos/prm/pt/num_str"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/ka/pos/prm/pt/num_mat"), track.pt(), impParam); + } + } + } else { + histos.fill(HIST("MC/withPID/ka/pos/prm/pt/num"), track.pt(), multiplicity); + if (!mcParticle.isPhysicalPrimary()) { + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/withPID/ka/pos/prm/pt/num_str"), track.pt(), multiplicity); + } else { + histos.fill(HIST("MC/withPID/ka/pos/prm/pt/num_mat"), track.pt(), multiplicity); + } + } + } + } else if (pdgCode == -321) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/ka/neg/prm/pt/num"), track.pt(), impParam); + if (!mcParticle.isPhysicalPrimary()) { + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/withPID/ka/neg/prm/pt/num_str"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/ka/neg/prm/pt/num_mat"), track.pt(), impParam); + } + } + } else { + histos.fill(HIST("MC/withPID/ka/neg/prm/pt/num"), track.pt(), multiplicity); + if (!mcParticle.isPhysicalPrimary()) { + if (mcParticle.getProcess() == 4) { + histos.fill(HIST("MC/withPID/ka/neg/prm/pt/num_str"), track.pt(), multiplicity); + } else { + histos.fill(HIST("MC/withPID/ka/neg/prm/pt/num_mat"), track.pt(), multiplicity); + } + } + } + } } - if (track.hasTRD() && lastRequiredTrdCluster > 0) { + if (track.hasTRD() && trkselOptions.lastRequiredTrdCluster > 0) { int lastLayer = 0; for (int l = 7; l >= 0; l--) { if (track.trdPattern() & (1 << l)) { @@ -1405,15 +2230,135 @@ struct tofSpectra { break; } } - if (lastLayer < lastRequiredTrdCluster) { + if (lastLayer < trkselOptions.lastRequiredTrdCluster) { return; } } if (track.hasTOF()) { + if (isPionTOF || isKaonTOF || isProtonTOF) { + // Proton (positive) + if (pdgCode == 2212) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/pr/pos/prm/pt/numtof"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/pr/pos/prm/pt/numtof"), track.pt(), multiplicity); + } + // Matched proton condition + if (!(track.mcMask() & (1 << 11))) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/pr/pos/prm/pt/numtof_matched"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/pr/pos/prm/pt/numtof_matched"), track.pt(), multiplicity); + } + } + } else if (pdgCode == -2212) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/pr/neg/prm/pt/numtof"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/pr/neg/prm/pt/numtof"), track.pt(), multiplicity); + } + if (!(track.mcMask() & (1 << 11))) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/pr/neg/prm/pt/numtof_matched"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/pr/neg/prm/pt/numtof_matched"), track.pt(), multiplicity); + } + } + } else if (pdgCode == 211) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/pi/pos/prm/pt/numtof"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/pi/pos/prm/pt/numtof"), track.pt(), multiplicity); + } + // Matched pion condition + if (!(track.mcMask() & (1 << 11))) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/pi/pos/prm/pt/numtof_matched"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/pi/pos/prm/pt/numtof_matched"), track.pt(), multiplicity); + } + } + } else if (pdgCode == -211) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/pi/neg/prm/pt/numtof"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/pi/neg/prm/pt/numtof"), track.pt(), multiplicity); + } + // Matched pion condition + if (!(track.mcMask() & (1 << 11))) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/pi/neg/prm/pt/numtof_matched"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/pi/neg/prm/pt/numtof_matched"), track.pt(), multiplicity); + } + } + } else if (pdgCode == 321) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/ka/pos/prm/pt/numtof"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/ka/pos/prm/pt/numtof"), track.pt(), multiplicity); + } + // Matched kaon condition + if (!(track.mcMask() & (1 << 11))) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/ka/pos/prm/pt/numtof_matched"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/ka/pos/prm/pt/numtof_matched"), track.pt(), multiplicity); + } + } + } else if (pdgCode == -321) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/ka/neg/prm/pt/numtof"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/ka/neg/prm/pt/numtof"), track.pt(), multiplicity); + } + // Matched kaon condition + if (!(track.mcMask() & (1 << 11))) { + if (isImpactParam) { + histos.fill(HIST("MC/withPID/ka/neg/prm/pt/numtof_matched"), track.pt(), impParam); + } else { + histos.fill(HIST("MC/withPID/ka/neg/prm/pt/numtof_matched"), track.pt(), multiplicity); + } + } + } + } if (includeCentralityMC) { - histos.fill(HIST(hpt_numtof_prm[i]), track.pt(), multiplicity, track.eta()); // RD + if (isImpactParam) { + histos.fill(HIST(hpt_numtof_prm[i]), track.pt(), impParam, track.dcaXY(), occupancy); + } else { + histos.fill(HIST(hpt_numtof_prm[i]), track.pt(), multiplicity, track.dcaXY(), occupancy); + } } else { - histos.fill(HIST(hpt_numtof_prm[i]), track.pt()); + histos.fill(HIST(hpt_numtof_prm[i]), track.pt(), multiplicity); + } + if (!(track.mcMask() & (1 << 11))) { + if (includeCentralityMC) { + histos.fill(HIST(hpt_numtofgoodmatch_prm[i]), track.pt(), multiplicity, track.eta()); // RD + } else { + histos.fill(HIST(hpt_numtofgoodmatch_prm[i]), track.pt(), multiplicity); + } + } + // Check if the signal is compatible with the PID hypothesis + float nsigma = 0.f; + switch (i) { + case 2: + case Np + 2: + nsigma = track.tofNSigmaPi(); + break; + case 3: + case Np + 3: + nsigma = track.tofNSigmaKa(); + break; + case 4: + case Np + 4: + nsigma = track.tofNSigmaPr(); + break; + default: + break; + } + if (std::abs(nsigma) <= trkselOptions.cfgCutNsigma) { + if (hPtNumTOFMatchWithPIDSignalPrm[i]) + hPtNumTOFMatchWithPIDSignalPrm[i]->Fill(track.pt(), multiplicity); } } @@ -1434,297 +2379,123 @@ struct tofSpectra { } template - void fillParticleHistograms_MC(CollisionCandidateMC::iterator const& collision, ParticleType const& mcParticle) + void fillParticleHistograms_MC(const float multiplicity, ParticleType const& mcParticle) { - - switch (i) { - case 0: - case Np: - if (doprocessFullEl == false && doprocessLfFullEl == false) { - return; - } - break; - case 1: - case Np + 1: - if (doprocessFullMu == false && doprocessLfFullMu == false) { - return; - } - break; - case 2: - case Np + 2: - if (doprocessFullPi == false && doprocessLfFullPi == false) { - return; - } - break; - case 3: - case Np + 3: - if (doprocessFullKa == false && doprocessLfFullKa == false) { - return; - } - break; - case 4: - case Np + 4: - if (doprocessFullPr == false && doprocessLfFullPr == false) { - return; - } - break; - case 5: - case Np + 5: - if (doprocessFullDe == false && doprocessLfFullDe == false) { - return; - } - break; - case 6: - case Np + 6: - if (doprocessFullTr == false && doprocessLfFullTr == false) { - return; - } - break; - case 7: - case Np + 7: - if (doprocessFullHe == false && doprocessLfFullHe == false) { - return; - } - break; - case 8: - case Np + 8: - if (doprocessFullAl == false && doprocessLfFullAl == false) { - return; - } - break; + if (!isParticleEnabled()) { // Check if the particle is enabled + return; } if (mcParticle.pdgCode() != PDGs[i]) { return; } - const float multiplicity = getMultiplicity(collision); if (!mcParticle.isPhysicalPrimary()) { if (mcParticle.getProcess() == 4) { - if (includeCentralityMC) { - histos.fill(HIST(hpt_den_str[i]), mcParticle.pt(), multiplicity, mcParticle.eta()); // RD - } else { - histos.fill(HIST(hpt_den_str[i]), mcParticle.pt()); - } + histos.fill(HIST(hpt_den_str[i]), mcParticle.pt(), multiplicity); } else { - if (includeCentralityMC) { - histos.fill(HIST(hpt_den_mat[i]), mcParticle.pt(), multiplicity, mcParticle.eta()); // RD - } else { - histos.fill(HIST(hpt_den_mat[i]), mcParticle.pt()); - } + histos.fill(HIST(hpt_den_mat[i]), mcParticle.pt(), multiplicity); } } else { if (includeCentralityMC) { - histos.fill(HIST(hpt_den_prm[i]), mcParticle.pt(), multiplicity, mcParticle.eta()); // RD + histos.fill(HIST(hpt_den_prm[i]), mcParticle.pt(), multiplicity); } else { - histos.fill(HIST(hpt_den_prm[i]), mcParticle.pt()); + histos.fill(HIST(hpt_den_prm[i]), mcParticle.pt(), multiplicity); } } } template - void fillParticleHistograms_MCRecoEvs(ParticleType const& mcParticle, CollisionCandidateMC::iterator const& collision) + void fillParticleHistograms_MCRecoEvs(ParticleType const& mcParticle, RecoMCCollisions::iterator const& collision) { - - switch (i) { - case 0: - case Np: - if (doprocessFullEl == false && doprocessLfFullEl == false) { - return; - } - break; - case 1: - case Np + 1: - if (doprocessFullMu == false && doprocessLfFullMu == false) { - return; - } - break; - case 2: - case Np + 2: - if (doprocessFullPi == false && doprocessLfFullPi == false) { - return; - } - break; - case 3: - case Np + 3: - if (doprocessFullKa == false && doprocessLfFullKa == false) { - return; - } - break; - case 4: - case Np + 4: - if (doprocessFullPr == false && doprocessLfFullPr == false) { - return; - } - break; - case 5: - case Np + 5: - if (doprocessFullDe == false && doprocessLfFullDe == false) { - return; - } - break; - case 6: - case Np + 6: - if (doprocessFullTr == false && doprocessLfFullTr == false) { - return; - } - break; - case 7: - case Np + 7: - if (doprocessFullHe == false && doprocessLfFullHe == false) { - return; - } - break; - case 8: - case Np + 8: - if (doprocessFullAl == false && doprocessLfFullAl == false) { - return; - } - break; + if (!isParticleEnabled()) { // Check if the particle is enabled + return; } if (mcParticle.pdgCode() != PDGs[i]) { return; } - const float multiplicity = getMultiplicity(collision); + const auto& mcCollision = collision.mcCollision_as(); + const float multiplicity = getMultiplicityMC(mcCollision); if (mcParticle.isPhysicalPrimary()) { if (isEventSelected(collision)) { if (includeCentralityMC) { histos.fill(HIST(hpt_den_prm_goodev[i]), mcParticle.pt(), multiplicity, mcParticle.eta()); } else { - histos.fill(HIST(hpt_den_prm_goodev[i]), mcParticle.pt()); + histos.fill(HIST(hpt_den_prm_goodev[i]), mcParticle.pt(), multiplicity); } - } else if (collision.sel8()) { - if (includeCentralityMC) { - histos.fill(HIST(hpt_den_prm_evsel[i]), mcParticle.pt(), multiplicity, mcParticle.eta()); + } else { + bool isSelected = collision.sel8(); + if (evselOptions.askForCustomTVX) { + isSelected = collision.selection_bit(aod::evsel::kIsTriggerTVX); + if (evselOptions.removeITSROFrameBorder) { + isSelected = isSelected && collision.selection_bit(aod::evsel::kNoITSROFrameBorder); + } + if (evselOptions.removeNoSameBunchPileup) { + isSelected = isSelected && collision.selection_bit(aod::evsel::kNoSameBunchPileup); + } + if (evselOptions.requireIsGoodZvtxFT0vsPV) { + isSelected = isSelected && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV); + } + if (evselOptions.requireIsVertexITSTPC) { + isSelected = isSelected && collision.selection_bit(aod::evsel::kIsVertexITSTPC); + } + if (evselOptions.removeNoTimeFrameBorder) { + isSelected = isSelected && collision.selection_bit(aod::evsel::kNoTimeFrameBorder); + } + if (isSelected) { + if (includeCentralityMC) { + histos.fill(HIST(hpt_den_prm_evsel[i]), mcParticle.pt(), multiplicity, mcParticle.eta()); + } else { + histos.fill(HIST(hpt_den_prm_evsel[i]), mcParticle.pt(), multiplicity); + } + } } else { - histos.fill(HIST(hpt_den_prm_evsel[i]), mcParticle.pt()); + if (includeCentralityMC) { + histos.fill(HIST(hpt_den_prm_recoev[i]), mcParticle.pt(), multiplicity, mcParticle.eta()); + } else { + histos.fill(HIST(hpt_den_prm_recoev[i]), mcParticle.pt(), multiplicity); + } } } - } else { - if (includeCentralityMC) { - histos.fill(HIST(hpt_den_prm_recoev[i]), mcParticle.pt(), multiplicity, mcParticle.eta()); - } else { - histos.fill(HIST(hpt_den_prm_recoev[i]), mcParticle.pt()); - } } } template - void fillParticleHistograms_MCGenEvs(ParticleType const& mcParticle, aod::McCollision const& mcCollision) + void fillParticleHistograms_MCGenEvs(ParticleType const& mcParticle, GenMCCollisions::iterator const& mcCollision) { - switch (i) { - case 0: - case Np: - if (doprocessFullEl == false && doprocessLfFullEl == false) { - return; - } - break; - case 1: - case Np + 1: - if (doprocessFullMu == false && doprocessLfFullMu == false) { - return; - } - break; - case 2: - case Np + 2: - if (doprocessFullPi == false && doprocessLfFullPi == false) { - return; - } - break; - case 3: - case Np + 3: - if (doprocessFullKa == false && doprocessLfFullKa == false) { - return; - } - break; - case 4: - case Np + 4: - if (doprocessFullPr == false && doprocessLfFullPr == false) { - return; - } - break; - case 5: - case Np + 5: - if (doprocessFullDe == false && doprocessLfFullDe == false) { - return; - } - break; - case 6: - case Np + 6: - if (doprocessFullTr == false && doprocessLfFullTr == false) { - return; - } - break; - case 7: - case Np + 7: - if (doprocessFullHe == false && doprocessLfFullHe == false) { - return; - } - break; - case 8: - case Np + 8: - if (doprocessFullAl == false && doprocessLfFullAl == false) { - return; - } - break; + if (!isParticleEnabled()) { // Check if the particle is enabled + return; } if (mcParticle.pdgCode() != PDGs[i]) { return; } + const float multiplicity = getMultiplicityMC(mcCollision); if (mcParticle.isPhysicalPrimary()) { - if (abs(mcCollision.posZ()) < cfgCutVertex) { - histos.fill(HIST(hpt_den_prm_mcgoodev[i]), mcParticle.pt()); + if (std::abs(mcCollision.posZ()) < evselOptions.cfgCutVertex) { + histos.fill(HIST(hpt_den_prm_mcgoodev[i]), mcParticle.pt(), multiplicity); } else { - histos.fill(HIST(hpt_den_prm_mcbadev[i]), mcParticle.pt()); + histos.fill(HIST(hpt_den_prm_mcbadev[i]), mcParticle.pt(), multiplicity); } } } Service pdgDB; - // Event selection - template - bool isTrueINELgt0(TMcParticles particles) - { - int nPart = 0; - for (const auto& particle : particles) { - if (particle.isPhysicalPrimary() == 0) - continue; // consider only primaries - - const auto& pdgInfo = pdgDB->GetParticle(particle.pdgCode()); - if (!pdgInfo) { - continue; - } - if (TMath::Abs(pdgInfo->Charge()) < 0.001) { - continue; // consider only charged particles - } - - if (particle.eta() < -1.0 || particle.eta() > 1.0) - continue; // consider only particles in |eta| < 1 - - nPart++; - } - if (nPart > 0) - return true; - else - return false; - } - Preslice perMCCol = aod::mcparticle::mcCollisionId; SliceCache cache; void processMC(soa::Join const& tracks, aod::McParticles const& mcParticles, - aod::McCollisions const& mcCollisions, - CollisionCandidateMC const& collisions) + GenMCCollisions const& mcCollisions, + RecoMCCollisions const& collisions) { // Fill number of generated and reconstructed collisions for normalization histos.fill(HIST("MC/GenRecoCollisions"), 1.f, mcCollisions.size()); @@ -1739,7 +2510,7 @@ struct tofSpectra { } continue; } - if (!isEventSelected(track.collision_as())) { + if (!isEventSelected(track.collision_as())) { continue; } if (!passesCutWoDCA(track)) { @@ -1756,7 +2527,7 @@ struct tofSpectra { const auto& mcParticle = track.mcParticle(); static_for<0, 17>([&](auto i) { - fillTrackHistograms_MC(track, mcParticle, track.collision_as()); + fillTrackHistograms_MC(track, mcParticle, track.collision_as(), mcParticles); }); } if (includeCentralityMC) { @@ -1764,30 +2535,31 @@ struct tofSpectra { if (!collision.has_mcCollision()) { continue; } - const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, collision.mcCollision().globalIndex(), cache); + const auto& mcCollision = collision.mcCollision_as(); + const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); + const float multiplicity = getMultiplicity(collision); for (const auto& mcParticle : particlesInCollision) { - if (std::abs(mcParticle.y()) > cfgCutY) { + if (std::abs(mcParticle.y()) > trkselOptions.cfgCutY) { continue; } static_for<0, 17>([&](auto i) { - fillParticleHistograms_MC(collision, mcParticle); + fillParticleHistograms_MC(multiplicity, mcParticle); }); } } } else { - for (const auto& collision : collisions) { - for (const auto& mcParticle : mcParticles) { - // if (std::abs(mcParticle.eta()) > cfgCutEta) { - // continue; - // } - if (std::abs(mcParticle.y()) > cfgCutY) { - continue; - } - static_for<0, 17>([&](auto i) { - fillParticleHistograms_MC(collision, mcParticle); - }); + for (const auto& mcParticle : mcParticles) { + if (std::abs(mcParticle.y()) > trkselOptions.cfgCutY) { + continue; } + + const auto& mcCollision = mcParticle.mcCollision_as(); + const float multiplicity = getMultiplicityMC(mcCollision); + + static_for<0, 17>([&](auto i) { + fillParticleHistograms_MC(multiplicity, mcParticle); + }); } } // Loop on reconstructed collisions @@ -1795,9 +2567,24 @@ struct tofSpectra { if (!collision.has_mcCollision()) { continue; } - const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, collision.mcCollision().globalIndex(), cache); + const auto& mcCollision = collision.mcCollision_as(); + const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); + if (evselOptions.cfgINELCut.value == 1) { + if (!o2::pwglf::isINELgt0mc(particlesInCollision, pdgDB)) { + continue; + } + } + if (evselOptions.cfgINELCut.value == 2) { + if (!o2::pwglf::isINELgt1mc(particlesInCollision, pdgDB)) { + continue; + } + } + + if (isEventSelected(collision)) { + histos.fill(HIST("MC/MultiplicityRecoEv"), getMultiplicityMC(mcCollision)); + } for (const auto& mcParticle : particlesInCollision) { - if (std::abs(mcParticle.y()) > cfgCutY) { + if (std::abs(mcParticle.y()) > trkselOptions.cfgCutY) { continue; } static_for<0, 17>([&](auto i) { @@ -1808,40 +2595,37 @@ struct tofSpectra { // Loop on generated collisions for (const auto& mcCollision : mcCollisions) { + if (std::abs(mcCollision.posZ()) > evselOptions.cfgCutVertex) { + continue; + } + histos.fill(HIST("MC/Multiplicity"), getMultiplicityMC(mcCollision)); const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); bool hasParticleInFT0C = false; bool hasParticleInFT0A = false; - if (cfgINELCut.value == 1) { - if (!isTrueINELgt0(particlesInCollision)) { + if (evselOptions.cfgINELCut.value == 1) { + if (!o2::pwglf::isINELgt0mc(particlesInCollision, pdgDB)) { continue; } } - - int nInelPart = 0; - for (const auto& mcParticle : particlesInCollision) { - if (mcParticle.isPhysicalPrimary()) { - if (mcParticle.eta() >= -3.4f && mcParticle.eta() <= -2.3f) { // Acceptance of the FT0C - hasParticleInFT0C = true; - } - if (mcParticle.eta() >= 3.8f && mcParticle.eta() <= 5.0f) { // Acceptance of the FT0A - hasParticleInFT0A = true; - } - if (std::abs(mcParticle.eta()) < 1.f) { - nInelPart++; - } + histos.fill(HIST("MC/MultiplicityMCINELgt0"), getMultiplicityMC(mcCollision)); + if (evselOptions.cfgINELCut.value == 2) { + if (!o2::pwglf::isINELgt1mc(particlesInCollision, pdgDB)) { + continue; } - - if (std::abs(mcParticle.y()) > cfgCutY) { + } + histos.fill(HIST("MC/MultiplicityMCINELgt1"), getMultiplicityMC(mcCollision)); + for (const auto& mcParticle : particlesInCollision) { + if (std::abs(mcParticle.y()) > trkselOptions.cfgCutY) { continue; } static_for<0, 17>([&](auto i) { fillParticleHistograms_MCGenEvs(mcParticle, mcCollision); }); } - if (nInelPart >= 1) { + if (mcCollision.isInelGt0()) { histos.fill(HIST("MC/GenRecoCollisions"), 3.f); } - if (nInelPart >= 2) { + if (mcCollision.isInelGt1()) { histos.fill(HIST("MC/GenRecoCollisions"), 4.f); } if (hasParticleInFT0C && hasParticleInFT0A) { @@ -1850,6 +2634,138 @@ struct tofSpectra { } } PROCESS_SWITCH(tofSpectra, processMC, "Process MC", false); + + void processMCgen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) + { + histos.fill(HIST("Vertex/histGenVtxMC"), mcCollision.posZ()); + histos.fill(HIST("Centrality/ImpParm"), mcCollision.impactParameter()); + const float multiplicity = mcCollision.impactParameter(); + for (const auto& mcParticleGen : mcParticles) { + if (!mcParticleGen.isPhysicalPrimary()) + continue; + int pdgCode = mcParticleGen.pdgCode(); + float pt = mcParticleGen.pt(); + float absY = std::abs(mcParticleGen.y()); + if (absY > trkselOptions.cfgCutY) { + continue; + } + + if (pdgCode == 2212) { + histos.fill(HIST("MC/test/pr/pos/prm/pt/den"), pt, multiplicity); + } else if (pdgCode == -2212) { + histos.fill(HIST("MC/test/pr/neg/prm/pt/den"), pt, multiplicity); + } else if (pdgCode == 211) { + histos.fill(HIST("MC/test/pi/pos/prm/pt/den"), pt, multiplicity); + } else if (pdgCode == -211) { + histos.fill(HIST("MC/test/pi/neg/prm/pt/den"), pt, multiplicity); + } else if (pdgCode == 321) { + histos.fill(HIST("MC/test/ka/pos/prm/pt/den"), pt, multiplicity); + } else if (pdgCode == -321) { + histos.fill(HIST("MC/test/ka/neg/prm/pt/den"), pt, multiplicity); + } + } + } + PROCESS_SWITCH(tofSpectra, processMCgen, "process generated MC", false); + void processMCgen_RecoEvs(soa::Join const& tracks, + aod::McTrackLabels const& mcTrackLabels, + GenMCCollisions const&, + RecoMCCollisions const& collisions, + aod::McParticles const& mcParticles) + { + for (const auto& collision : collisions) { + if (!collision.has_mcCollision()) { + continue; + } + + const auto& mcCollision = collision.mcCollision_as(); + histos.fill(HIST("Vertex/RecoEvs/histGenVtxMC"), mcCollision.posZ()); + histos.fill(HIST("Centrality/RecoEvs/ImpParm"), mcCollision.impactParameter()); + const float multiplicity = mcCollision.impactParameter(); + + for (const auto& track : tracks) { + if (track.tpcNClsCrossedRows() < 70 || + track.tpcChi2NCl() > 4 || + track.tpcChi2NCl() < 0.5 || + track.itsChi2NCl() > 36 || + std::abs(track.dcaXY()) > 0.05 || + std::abs(track.dcaZ()) > 2.0 || + std::abs(track.eta()) > 0.8 || + track.tpcCrossedRowsOverFindableCls() < 0.8 || + track.tpcNClsFound() < 100 || + !(o2::aod::track::TPCrefit) || + !(o2::aod::track::ITSrefit)) { + continue; + } + const auto& mcLabel = mcTrackLabels.iteratorAt(track.globalIndex()); + if (mcLabel.mcParticleId() < 0 || mcLabel.mcParticleId() >= mcParticles.size()) { + continue; + } + const auto& mcParticle = mcParticles.iteratorAt(mcLabel.mcParticleId()); + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + + int pdgCode = mcParticle.pdgCode(); + float pt = mcParticle.pt(); + float absY = std::abs(mcParticle.y()); + if (absY > trkselOptions.cfgCutY) { + continue; + } + + const auto& nsigmaTPCPi = o2::aod::pidutils::tpcNSigma<2>(track); + const auto& nsigmaTPCKa = o2::aod::pidutils::tpcNSigma<3>(track); + const auto& nsigmaTPCPr = o2::aod::pidutils::tpcNSigma<4>(track); + + const bool isPionTPC = std::abs(nsigmaTPCPi) < trkselOptions.cfgCutNsigma; + const bool isKaonTPC = std::abs(nsigmaTPCKa) < trkselOptions.cfgCutNsigma; + const bool isProtonTPC = std::abs(nsigmaTPCPr) < trkselOptions.cfgCutNsigma; + + const auto& nsigmaTOFPi = o2::aod::pidutils::tofNSigma<2>(track); + const auto& nsigmaTOFKa = o2::aod::pidutils::tofNSigma<3>(track); + const auto& nsigmaTOFPr = o2::aod::pidutils::tofNSigma<4>(track); + + const bool isPionTOF = track.hasTOF() && std::abs(nsigmaTOFPi) < trkselOptions.cfgCutNsigma; + const bool isKaonTOF = track.hasTOF() && std::abs(nsigmaTOFKa) < trkselOptions.cfgCutNsigma; + const bool isProtonTOF = track.hasTOF() && std::abs(nsigmaTOFPr) < trkselOptions.cfgCutNsigma; + + if (isPionTPC || isKaonTPC || isProtonTPC) { + if (pdgCode == 2212) { + histos.fill(HIST("MC/test/RecoEvs/pr/pos/prm/pt/num"), pt, multiplicity); + } else if (pdgCode == -2212) { + histos.fill(HIST("MC/test/RecoEvs/pr/neg/prm/pt/num"), pt, multiplicity); + } else if (pdgCode == 211) { + histos.fill(HIST("MC/test/RecoEvs/pi/pos/prm/pt/num"), pt, multiplicity); + } else if (pdgCode == -211) { + histos.fill(HIST("MC/test/RecoEvs/pi/neg/prm/pt/num"), pt, multiplicity); + } else if (pdgCode == 321) { + histos.fill(HIST("MC/test/RecoEvs/ka/pos/prm/pt/num"), pt, multiplicity); + } else if (pdgCode == -321) { + histos.fill(HIST("MC/test/RecoEvs/ka/neg/prm/pt/num"), pt, multiplicity); + } + } + + if (isPionTOF || isKaonTOF || isProtonTOF) { + if (pdgCode == 2212) { + histos.fill(HIST("MC/test/RecoEvs/pr/pos/prm/pt/numtof"), pt, multiplicity); + } else if (pdgCode == -2212) { + histos.fill(HIST("MC/test/RecoEvs/pr/neg/prm/pt/numtof"), pt, multiplicity); + } else if (pdgCode == 211) { + histos.fill(HIST("MC/test/RecoEvs/pi/pos/prm/pt/numtof"), pt, multiplicity); + } else if (pdgCode == -211) { + histos.fill(HIST("MC/test/RecoEvs/pi/neg/prm/pt/numtof"), pt, multiplicity); + } else if (pdgCode == 321) { + histos.fill(HIST("MC/test/RecoEvs/ka/pos/prm/pt/numtof"), pt, multiplicity); + } else if (pdgCode == -321) { + histos.fill(HIST("MC/test/RecoEvs/ka/neg/prm/pt/numtof"), pt, multiplicity); + } + } + } + } + } + PROCESS_SWITCH(tofSpectra, processMCgen_RecoEvs, "process generated MC (reconstructed events)", false); + }; // end of spectra task WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/Nuspex/spectraTOFRun2.cxx b/PWGLF/Tasks/Nuspex/spectraTOFRun2.cxx index efcc58dd55d..9c31160f0a1 100644 --- a/PWGLF/Tasks/Nuspex/spectraTOFRun2.cxx +++ b/PWGLF/Tasks/Nuspex/spectraTOFRun2.cxx @@ -348,7 +348,7 @@ struct tofSpectraRun2 { template void fillParticleHistos(const T& track, const C& /*collision*/) { - if (abs(track.rapidity(PID::getMass(id))) > cfgCutY) { + if (std::abs(track.rapidity(PID::getMass(id))) > cfgCutY) { return; } const auto& nsigmaTOF = o2::aod::pidutils::tofNSigma(track); @@ -468,7 +468,7 @@ struct tofSpectraRun2 { if constexpr (fillHistograms) { histos.fill(HIST("evsel"), 2); } - if (abs(collision.posZ()) > cfgCutVertex) { + if (std::abs(collision.posZ()) > cfgCutVertex) { return false; } if constexpr (fillHistograms) { @@ -496,7 +496,7 @@ struct tofSpectraRun2 { if constexpr (fillHistograms) { histos.fill(HIST("tracksel"), 1); } - if (abs(track.eta()) > cfgCutEta) { + if (std::abs(track.eta()) > cfgCutEta) { return false; } if constexpr (fillHistograms) { diff --git a/PWGLF/Tasks/Nuspex/spectraTPC.cxx b/PWGLF/Tasks/Nuspex/spectraTPC.cxx index 18f7275e523..fd929553fb6 100644 --- a/PWGLF/Tasks/Nuspex/spectraTPC.cxx +++ b/PWGLF/Tasks/Nuspex/spectraTPC.cxx @@ -117,7 +117,7 @@ struct tpcSpectra { void fillParticleHistos(const T& track) { const float y = TMath::ASinH(track.pt() / TMath::Sqrt(PID::getMass2(id) + track.pt() * track.pt()) * TMath::SinH(track.eta())); - if (abs(y) > 0.5) { + if (std::abs(y) > 0.5) { return; } const auto& nsigma = o2::aod::pidutils::tpcNSigma(track); @@ -131,7 +131,7 @@ struct tpcSpectra { if (!track.isGlobalTrack()) { return; } - if (abs(nsigma) > cfgNSigmaCut) { + if (std::abs(nsigma) > cfgNSigmaCut) { return; } histos.fill(HIST(hp[id]), track.p()); @@ -155,7 +155,7 @@ struct tpcSpectra { return; } histos.fill(HIST("evsel"), 2); - if (abs(collision.posZ()) > cfgCutVertex) { + if (std::abs(collision.posZ()) > cfgCutVertex) { return; } histos.fill(HIST("evsel"), 3); @@ -163,7 +163,7 @@ struct tpcSpectra { for (const auto& track : tracks) { histos.fill(HIST("tracksel"), 1); - if (abs(track.eta()) > cfgCutEta) { + if (std::abs(track.eta()) > cfgCutEta) { continue; } histos.fill(HIST("tracksel"), 2); @@ -279,7 +279,7 @@ struct tpcPidQaSignalwTof { TrackCandidates const& tracks) { histos.fill(HIST("evsel"), 1); - if (abs(collision.posZ()) > cfgCutVertex) { + if (std::abs(collision.posZ()) > cfgCutVertex) { return; } histos.fill(HIST("evsel"), 2); @@ -287,7 +287,7 @@ struct tpcPidQaSignalwTof { for (const auto& track : tracks) { histos.fill(HIST("tracksel"), 1); - if (abs(track.eta()) > cfgCutEta) { + if (std::abs(track.eta()) > cfgCutEta) { continue; } histos.fill(HIST("tracksel"), 2); diff --git a/PWGLF/Tasks/Nuspex/spectraTPCtiny.cxx b/PWGLF/Tasks/Nuspex/spectraTPCtiny.cxx index 12fc53f6bfc..d58a8777771 100644 --- a/PWGLF/Tasks/Nuspex/spectraTPCtiny.cxx +++ b/PWGLF/Tasks/Nuspex/spectraTPCtiny.cxx @@ -58,7 +58,7 @@ struct tpcSpectraTiny { template void fillParticleHistos(const T& track, const float& nsigma) { - if (abs(nsigma) > cfgNSigmaCut) { + if (std::abs(nsigma) > cfgNSigmaCut) { return; } histos.fill(HIST(hp[i]), track.p()); @@ -78,7 +78,7 @@ struct tpcSpectraTiny { TrackCandidates const& tracks) { histos.fill(HIST("evsel"), 1); - if (abs(collision.posZ()) > cfgCutVertex) { + if (std::abs(collision.posZ()) > cfgCutVertex) { return; } histos.fill(HIST("evsel"), 2); @@ -86,7 +86,7 @@ struct tpcSpectraTiny { for (const auto& track : tracks) { histos.fill(HIST("tracksel"), 1); - if (abs(track.eta()) > cfgCutEta) { + if (std::abs(track.eta()) > cfgCutEta) { continue; } histos.fill(HIST("tracksel"), 2); diff --git a/PWGLF/Tasks/Nuspex/spectraTPCtinyPiKaPr.cxx b/PWGLF/Tasks/Nuspex/spectraTPCtinyPiKaPr.cxx index 328b44d5477..9c9a340bfcf 100644 --- a/PWGLF/Tasks/Nuspex/spectraTPCtinyPiKaPr.cxx +++ b/PWGLF/Tasks/Nuspex/spectraTPCtinyPiKaPr.cxx @@ -49,7 +49,7 @@ struct tpcSpectraTinyPiKaPr { template void fillParticleHistos(const T& track, const float& nsigma) { - if (abs(nsigma) > cfgNSigmaCut) { + if (std::abs(nsigma) > cfgNSigmaCut) { return; } histos.fill(HIST(hp[i]), track.p()); diff --git a/PWGLF/Tasks/QC/CMakeLists.txt b/PWGLF/Tasks/QC/CMakeLists.txt old mode 100755 new mode 100644 index adca83a1334..dd0c14d1c91 --- a/PWGLF/Tasks/QC/CMakeLists.txt +++ b/PWGLF/Tasks/QC/CMakeLists.txt @@ -44,6 +44,17 @@ o2physics_add_dpl_workflow(its-tpc-matching-qa PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(strangeness-tracking-qc + SOURCES strangenessTrackingQC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::ReconstructionDataFormats O2Physics::AnalysisCore O2::DetectorsBase + COMPONENT_NAME Analysis) + + +o2physics_add_dpl_workflow(mc-signal-loss + SOURCES mcSignalLoss.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(lfpropstudy SOURCES lfpropStudy.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -61,7 +72,7 @@ o2physics_add_dpl_workflow(tpc-dedx-qa o2physics_add_dpl_workflow(vertexqa SOURCES vertexQA.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(efficiencyqa @@ -87,4 +98,44 @@ o2physics_add_dpl_workflow(stqa o2physics_add_dpl_workflow(kfstrangenessstudy SOURCES kfStrangenessStudy.cxx PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(findable-study + SOURCES findableStudy.cxx + PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2Physics::AnalysisCore O2Physics::v0SelectionGroup + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(mcinelgt0 + SOURCES mcinelgt0.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(tracked-cascade-properties + SOURCES tracked_cascade_properties.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(mc-particle-predictions + SOURCES mcParticlePrediction.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(strange-derived-qa + SOURCES strangederivedqa.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(str-derived-genqa + SOURCES strderivedGenQA.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(its-tpc-matching-vzeros + SOURCES lfITSTPCMatchingSecondaryTracksQA.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(v0assoqa + SOURCES v0assoqa.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle O2Physics::TPCDriftManager COMPONENT_NAME Analysis) \ No newline at end of file diff --git a/PWGLF/Tasks/QC/findableStudy.cxx b/PWGLF/Tasks/QC/findableStudy.cxx new file mode 100644 index 00000000000..d8ca8cc8c80 --- /dev/null +++ b/PWGLF/Tasks/QC/findableStudy.cxx @@ -0,0 +1,472 @@ +// 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. +// +// Strangeness findable study +// +// --- deals with derived data that has been specifically +// generated to do the findable exercise. +// +// Comments, questions, complaints, suggestions? +// Please write to: +// david.dobrigkeit.chinellato@cern.ch +// + +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "PWGLF/Utils/v0SelectionBits.h" +#include "PWGLF/Utils/v0SelectionGroup.h" +#include "PWGLF/Utils/v0SelectionTools.h" + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +using recoStraCollisions = soa::Join; +using reconstructedV0s = soa::Join; +using reconstructedV0sNoMC = soa::Join; + +using dauTracks = soa::Join; + +// simple checkers, but ensure 64 bit integers +#define bitset(var, nbit) ((var) |= (static_cast(1) << static_cast(nbit))) +#define bitcheck(var, nbit) ((var) & (static_cast(1) << static_cast(nbit))) + +struct findableStudy { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // master PDG code selection + Configurable pdgCode{"pdgCode", 310, "PDG code to select"}; + Configurable skipITSonly{"skipITSonly", true, "skip reco V0s if an ITS-only (no TPC) prong present"}; + + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for analysis"}; + ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f}, "Centrality"}; + + // +-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+ + // Full wrapper for configurables related to actual analysis + Configurable v0Selections{"v0Selections", {}, "V0 selection criteria for analysis"}; + // +-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+ + + // pack track quality but separte also afterburner + // dynamic range: 0-31 + enum selection : int { hasTPC = 0, + hasITSTracker, + hasITSAfterburner, + hasTRD, + hasTOF }; + + uint64_t maskTopological; + uint64_t maskTrackProperties; + + uint64_t maskK0ShortSpecific; + uint64_t maskLambdaSpecific; + uint64_t maskAntiLambdaSpecific; + + uint64_t maskSelectionK0Short; + uint64_t maskSelectionLambda; + uint64_t maskSelectionAntiLambda; + + void init(InitContext const&) + { + v0Selections->PrintSelections(); // for the logs + + v0Selections->provideMasks(maskTopological, maskTrackProperties, maskK0ShortSpecific, maskLambdaSpecific, maskAntiLambdaSpecific); + + // Primary particle selection, central to analysis + maskSelectionK0Short = maskTopological | maskTrackProperties | maskK0ShortSpecific; + maskSelectionLambda = maskTopological | maskTrackProperties | maskLambdaSpecific; + maskSelectionAntiLambda = maskTopological | maskTrackProperties | maskAntiLambdaSpecific; + + // Event counting + histos.add("hCentrality", "hCentrality", kTH1D, {axisCentrality}); + + // Duplicate counting + histos.add("hNRecoV0s", "hNRecoV0s", kTH1D, {{50, -0.5, 49.5f}}); + histos.add("hNRecoV0sWithTPC", "hNRecoV0sWithTPC", kTH1D, {{50, -0.5, 49.5f}}); + histos.add("hNRecoV0sWrongColl", "hNRecoV0sWrongColl", kTH1D, {{50, -0.5, 49.5f}}); + + // For broad correctness check + histos.add("hFoundVsTracksOK", "hFoundVsTracksOK", kTH2D, {{2, -0.5, 1.5f}, {2, -0.5, 1.5f}}); + + // Global findable + histos.add("h2dPtVsCentrality_Findable", "hPtVsCentrality_Findable", kTH2D, {axisCentrality, axisPt}); + + // Acceptably (for svertexer) tracked + histos.add("h2dPtVsCentrality_AcceptablyTracked", "h2dPtVsCentrality_AcceptablyTracked", kTH2D, {axisCentrality, axisPt}); + + // Found in any capacity, including ITSonly + histos.add("h2dPtVsCentrality_FoundAny", "h2dPtVsCentrality_FoundAny", kTH2D, {axisCentrality, axisPt}); + + // Found with prongs with the TPC (typical analysis setting) + histos.add("h2dPtVsCentrality_Found", "h2dPtVsCentrality_Found", kTH2D, {axisCentrality, axisPt}); + + // Found in loop (may have duplicates, meant as cross-check too) + histos.add("h2dPtVsCentrality_FoundInLoop", "h2dPtVsCentrality_FoundInLoop", kTH2D, {axisCentrality, axisPt}); + + // Passes analysis-level track quality checks + histos.add("h2dPtVsCentrality_PassesTrackQuality", "h2dPtVsCentrality_Analysis_PassesTrackQuality", kTH2D, {axisCentrality, axisPt}); + + // Passes analysis-level topological selection criteria + histos.add("h2dPtVsCentrality_PassesTopological", "h2dPtVsCentrality_PassesTopological", kTH2D, {axisCentrality, axisPt}); + + // Passes analysis-level species-specific + histos.add("h2dPtVsCentrality_PassesThisSpecies", "h2dPtVsCentrality_PassesThisSpecies", kTH2D, {axisCentrality, axisPt}); + + // one-on-one test for topology, operating with track quality and species-specific checks ON + histos.add("h2dPtVsCentrality_V0Radius", "h2dPtVsCentrality_V0Radius", kTH2D, {axisCentrality, axisPt}); + histos.add("h2dPtVsCentrality_V0RadiusMax", "h2dPtVsCentrality_V0RadiusMax", kTH2D, {axisCentrality, axisPt}); + histos.add("h2dPtVsCentrality_V0CosPA", "h2dPtVsCentrality_V0CosPA", kTH2D, {axisCentrality, axisPt}); + histos.add("h2dPtVsCentrality_DcaPosToPV", "h2dPtVsCentrality_DcaPosToPV", kTH2D, {axisCentrality, axisPt}); + histos.add("h2dPtVsCentrality_DcaNegToPV", "h2dPtVsCentrality_DcaNegToPV", kTH2D, {axisCentrality, axisPt}); + histos.add("h2dPtVsCentrality_DcaV0Dau", "h2dPtVsCentrality_DcaV0Dau", kTH2D, {axisCentrality, axisPt}); + + // Track quality tests in steps + histos.add("h2dTrackPropAcceptablyTracked", "h2dTrackPropAcceptablyTracked", kTH3D, {{32, -0.5, 31.5f}, {32, -0.5, 31.5f}, axisCentrality}); + histos.add("h2dTrackPropFound", "h2dTrackPropFound", kTH3D, {{32, -0.5, 31.5f}, {32, -0.5, 31.5f}, axisCentrality}); + histos.add("h2dTrackPropAnalysisTracks", "h2dTrackPropAnalysisTracks", kTH3D, {{32, -0.5, 31.5f}, {32, -0.5, 31.5f}, axisCentrality}); + histos.add("h2dTrackPropAnalysisTopo", "h2dTrackPropAnalysisTopo", kTH3D, {{32, -0.5, 31.5f}, {32, -0.5, 31.5f}, axisCentrality}); + histos.add("h2dTrackPropAnalysisSpecies", "h2dTrackPropAnalysisSpecies", kTH3D, {{32, -0.5, 31.5f}, {32, -0.5, 31.5f}, axisCentrality}); + } + + void processEvents( + recoStraCollisions::iterator const& collision // reco collisions for collision counting + ) + { + histos.fill(HIST("hCentrality"), collision.centFT0C()); + } + + void processDebugCrossCheck( + reconstructedV0sNoMC::iterator const& recV0, // reco V0s for cross-check + dauTracks const& // daughter track extras + ) + { + if (recV0.v0Type() == 1) { + // de-reference daughter track extras + auto pTrack = recV0.posTrackExtra_as(); + auto nTrack = recV0.negTrackExtra_as(); + + // cross-check correctness of new getter + if (pTrack.hasTPC() && !pTrack.hasITS() && !pTrack.hasTRD() && !pTrack.hasTOF()) { + LOGF(info, "X-check: Positive track is TPC only and this is a found V0. Puzzling!"); + } + if (nTrack.hasTPC() && !nTrack.hasITS() && !nTrack.hasTRD() && !nTrack.hasTOF()) { + LOGF(info, "X-check: Negative track is TPC only and this is a found V0. Puzzling!"); + } + } + } + + void processDebugCrossCheckMC( + reconstructedV0s::iterator const& recV0, // reco V0s for cross-check + dauTracks const& // daughter track extras + ) + { + if (recV0.isFound() && recV0.v0Type() == 1) { + // de-reference daughter track extras + auto pTrack = recV0.posTrackExtra_as(); + auto nTrack = recV0.negTrackExtra_as(); + + // cross-check correctness of new getter + if (pTrack.hasTPC() && !pTrack.hasITS() && !pTrack.hasTRD() && !pTrack.hasTOF()) { + LOGF(info, "X-check: Positive track is TPC only and this is a found V0. Puzzling!"); + } + if (nTrack.hasTPC() && !nTrack.hasITS() && !nTrack.hasTRD() && !nTrack.hasTOF()) { + LOGF(info, "X-check: Negative track is TPC only and this is a found V0. Puzzling!"); + } + } + } + + void processV0s( + aod::V0MCCores::iterator const& v0, // non-duplicated MC V0 decays + soa::SmallGroups const& recv0s, // reconstructed versions of the v0 + recoStraCollisions const&, // reco collisions for de-reference + aod::StraMCCollisions const&, // MC collisions for de-reference + dauTracks const& // daughter track extras + ) + { + int pdgCodePositive = 211; + int pdgCodeNegative = -211; + if (pdgCode == 3122) + pdgCodePositive = 2212; + if (pdgCode == -3122) + pdgCodePositive = -2212; + if (pdgCode == 22) { + pdgCodePositive = -11; + pdgCodeNegative = +11; + } + + if (v0.pdgCode() != pdgCode || v0.pdgCodePositive() != pdgCodePositive || v0.pdgCodeNegative() != pdgCodeNegative) + return; + if (!v0.isPhysicalPrimary()) + return; + + float rapidity = 2.0; + if (pdgCode == 310) + rapidity = RecoDecay::y(std::array{v0.pxPosMC() + v0.pxNegMC(), v0.pyPosMC() + v0.pyNegMC(), v0.pzPosMC() + v0.pzNegMC()}, o2::constants::physics::MassKaonNeutral); + if (pdgCode == 22) + rapidity = RecoDecay::y(std::array{v0.pxPosMC() + v0.pxNegMC(), v0.pyPosMC() + v0.pyNegMC(), v0.pzPosMC() + v0.pzNegMC()}, o2::constants::physics::MassPhoton); + if (pdgCode == 3122 || pdgCode == -3122) + rapidity = RecoDecay::y(std::array{v0.pxPosMC() + v0.pxNegMC(), v0.pyPosMC() + v0.pyNegMC(), v0.pzPosMC() + v0.pzNegMC()}, o2::constants::physics::MassLambda0); + + if (std::abs(rapidity) > 0.5f) + return; + + double ptmc = std::hypot(v0.pxPosMC() + v0.pxNegMC(), v0.pyPosMC() + v0.pyNegMC(), v0.pzPosMC() + v0.pzNegMC()); + + // step 1: count number of times this candidate was actually reconstructed + histos.fill(HIST("hNRecoV0s"), recv0s.size()); + bool hasWrongCollision = false; + float centrality = 100.5f; + bool hasBeenAcceptablyTracked = false; + bool hasBeenFoundAny = false; + bool hasBeenFound = false; + int nCandidatesWithTPC = 0; + + for (auto& recv0 : recv0s) { + if (recv0.v0Type() != 1) + continue; // skip anything other than a standard V0 + + // de-reference daughter track extras + auto pTrack = recv0.posTrackExtra_as(); + auto nTrack = recv0.negTrackExtra_as(); + + // skip ITS-only for simplicity + if (skipITSonly) { + if (!pTrack.hasTPC() || !nTrack.hasTPC()) + continue; + } + + // define properties for this V0 + bool pTrackOK = false, nTrackOK = false; // tracks are acceptably tracked + + // Detailed analysis level + bool topoV0RadiusOK = false, topoV0RadiusMaxOK = false, topoV0CosPAOK = false, topoDcaPosToPVOK = false, topoDcaNegToPVOK = false, topoDcaV0DauOK = false; + + if (recv0.has_straCollision()) { + auto coll = recv0.straCollision_as(); + int mcCollID_fromCollision = coll.straMCCollisionId(); + int mcCollID_fromV0 = recv0.straMCCollisionId(); + if (mcCollID_fromCollision != mcCollID_fromV0) { + hasWrongCollision = true; + } else { + // if this is a correctly collision-associated V0, take centrality from here + // N.B.: this could still be an issue if collision <-> mc collision is imperfect + centrality = coll.centFT0C(); + } + + if (recv0.isFound()) { + hasBeenFoundAny = true; // includes also ITS-only, checked before skipITSonly check + } + + if ( + (pTrack.hasTPC() && pTrack.hasITS()) || // full global track + (pTrack.hasTPC() && pTrack.hasTOF()) || // TPC + TOF is accepted + (pTrack.hasTPC() && pTrack.hasTRD()) || // TPC + TRD is accepted + (!pTrack.hasTPC() && pTrack.itsNCls() >= 6) // long ITS-only + ) { + pTrackOK = true; // for this V0 only + } + if ( + (nTrack.hasTPC() && nTrack.hasITS()) || + (nTrack.hasTPC() && nTrack.hasTOF()) || // TPC + TOF is accepted + (nTrack.hasTPC() && nTrack.hasTRD()) || // TPC + TRD is accepted + (!nTrack.hasTPC() && nTrack.itsNCls() >= 6)) { + nTrackOK = true; // for this V0 only + } + + if (pTrackOK && nTrackOK) + hasBeenAcceptablyTracked = true; + + // cross-check correctness of new getter + if (pTrack.hasITSTracker() && (pTrack.hasITS() && pTrack.itsChi2PerNcl() < -1e-3)) { + LOGF(fatal, "Positive track: inconsistent outcome of ITS tracker getter and explicit check!"); + } + if (nTrack.hasITSTracker() && (pTrack.hasITS() && nTrack.itsChi2PerNcl() < -1e-3)) { + LOGF(fatal, "Negative track: inconsistent outcome of ITS tracker getter and explicit check!"); + } + if (pTrack.hasITSAfterburner() && (pTrack.hasITS() && pTrack.itsChi2PerNcl() > -1e-3)) { + LOGF(fatal, "Positive track: inconsistent outcome of ITS tracker getter and explicit check!"); + } + if (nTrack.hasITSAfterburner() && (pTrack.hasITS() && nTrack.itsChi2PerNcl() > -1e-3)) { + LOGF(fatal, "Negative track: inconsistent outcome of ITS tracker getter and explicit check!"); + } + + // Cross-checking consistency: found should be a subset of nTrack, pTrack OK + histos.fill(HIST("hFoundVsTracksOK"), nTrackOK && pTrackOK, recv0.isFound()); + + // encode conditions of tracks + uint8_t positiveTrackCode = ((uint8_t(pTrack.hasTPC()) << hasTPC) | + (uint8_t(pTrack.hasITSTracker()) << hasITSTracker) | + (uint8_t(pTrack.hasITSAfterburner()) << hasITSAfterburner) | + (uint8_t(pTrack.hasTRD()) << hasTRD) | + (uint8_t(pTrack.hasTOF()) << hasTOF)); + + uint8_t negativeTrackCode = ((uint8_t(nTrack.hasTPC()) << hasTPC) | + (uint8_t(nTrack.hasITSTracker()) << hasITSTracker) | + (uint8_t(nTrack.hasITSAfterburner()) << hasITSAfterburner) | + (uint8_t(nTrack.hasTRD()) << hasTRD) | + (uint8_t(nTrack.hasTOF()) << hasTOF)); + + if (pTrackOK && nTrackOK && ptmc > 1.0 && ptmc < 1.1) { + // this particular V0 reco entry has been acceptably tracked. Do bookkeeping + histos.fill(HIST("h2dTrackPropAcceptablyTracked"), positiveTrackCode, negativeTrackCode, centrality); + } + + // determine if this V0 would go to analysis or not + if (recv0.isFound() && pTrackOK && nTrackOK) { // hack to avoid type check; only interested in found type 1 + // at this stage, this should be REALLY mostly unique (unless you switch skipITSonly to false or so) + // ... but we will cross-check this assumption (hNRecoV0sWithTPC, h2dPtVsCentrality_FoundInLoop) + if (pTrack.hasTPC() && !pTrack.hasITS() && !pTrack.hasTRD() && !pTrack.hasTOF()) { + LOGF(info, "Positive track is TPC only and this is a found V0. Puzzling!"); + } + if (nTrack.hasTPC() && !nTrack.hasITS() && !nTrack.hasTRD() && !nTrack.hasTOF()) { + LOGF(info, "Negative track is TPC only and this is a found V0. Puzzling!"); + } + + nCandidatesWithTPC++; + hasBeenFound = true; + histos.fill(HIST("h2dPtVsCentrality_FoundInLoop"), centrality, ptmc); + if (ptmc > 1.0 && ptmc < 1.1) { + histos.fill(HIST("h2dTrackPropFound"), positiveTrackCode, negativeTrackCode, centrality); + } + + uint64_t selMap = v0data::computeReconstructionBitmap(recv0, pTrack, nTrack, coll, recv0.yLambda(), recv0.yK0Short(), v0Selections); + + // Consider in all cases + selMap = selMap | (uint64_t(1) << v0data::selConsiderK0Short) | (uint64_t(1) << v0data::selConsiderLambda) | (uint64_t(1) << v0data::selConsiderAntiLambda); + + // selection checker: ensure this works on subset of actual svertexer-findable + bool validTrackProperties = v0Selections->verifyMask(selMap, maskTrackProperties) && pTrackOK && nTrackOK; + bool validTopology = v0Selections->verifyMask(selMap, maskTopological); + + uint64_t thisSpeciesMask = maskK0ShortSpecific; + if (pdgCode == 3122) + thisSpeciesMask = maskLambdaSpecific; + if (pdgCode == -3122) + thisSpeciesMask = maskAntiLambdaSpecific; + // add other species masks as necessary + + bool validThisSpecies = v0Selections->verifyMask(selMap, thisSpeciesMask); + + // specific selection (not cumulative) + topoV0RadiusOK = v0Selections->verifyMask(selMap, uint64_t(1) << v0data::selRadius); + topoV0RadiusMaxOK = v0Selections->verifyMask(selMap, uint64_t(1) << v0data::selRadiusMax); + topoV0CosPAOK = v0Selections->verifyMask(selMap, uint64_t(1) << v0data::selCosPA); + topoDcaPosToPVOK = v0Selections->verifyMask(selMap, uint64_t(1) << v0data::selDCAPosToPV); + topoDcaNegToPVOK = v0Selections->verifyMask(selMap, uint64_t(1) << v0data::selDCANegToPV); + topoDcaV0DauOK = v0Selections->verifyMask(selMap, uint64_t(1) << v0data::selDCAV0Dau); + // trackTPCRowsOK = v0Selections->verifyMask(selMap, (uint64_t(1) << v0data::selPosGoodTPCTrack) | (uint64_t(1) << v0data::selNegGoodTPCTrack) ); + + // uint64_t tpcPidMask = (uint64_t(1) << v0data::selTPCPIDPositivePion) | (uint64_t(1) << v0data::selTPCPIDNegativePion); + // if(pdgCode==3122) + // tpcPidMask = (uint64_t(1) << v0data::selTPCPIDPositiveProton) | (uint64_t(1) << v0data::selTPCPIDNegativePion); + // if(pdgCode==-3122) + // tpcPidMask = (uint64_t(1) << v0data::selTPCPIDPositivePion) | (uint64_t(1) << v0data::selTPCPIDNegativeProton); + + // trackTPCPIDOK = v0Selections->verifyMask(selMap, tpcPidMask); + + // Broad level + if (validTrackProperties) { + histos.fill(HIST("h2dPtVsCentrality_PassesTrackQuality"), centrality, ptmc); + if (ptmc > 1.0 && ptmc < 1.1) { + histos.fill(HIST("h2dTrackPropAnalysisTracks"), positiveTrackCode, negativeTrackCode, centrality); + } + } + if (validTrackProperties && validTopology) { + histos.fill(HIST("h2dPtVsCentrality_PassesTopological"), centrality, ptmc); + if (ptmc > 1.0 && ptmc < 1.1) { + histos.fill(HIST("h2dTrackPropAnalysisTopo"), positiveTrackCode, negativeTrackCode, centrality); + } + } + if (validTrackProperties && validTopology && validThisSpecies) { + histos.fill(HIST("h2dPtVsCentrality_PassesThisSpecies"), centrality, ptmc); + if (ptmc > 1.0 && ptmc < 1.1) { + histos.fill(HIST("h2dTrackPropAnalysisSpecies"), positiveTrackCode, negativeTrackCode, centrality); + } + } + + // topological + if (validTrackProperties && validThisSpecies && topoV0RadiusOK) + histos.fill(HIST("h2dPtVsCentrality_V0Radius"), centrality, ptmc); + if (validTrackProperties && validThisSpecies && topoV0RadiusMaxOK) + histos.fill(HIST("h2dPtVsCentrality_V0RadiusMax"), centrality, ptmc); + if (validTrackProperties && validThisSpecies && topoV0CosPAOK) + histos.fill(HIST("h2dPtVsCentrality_V0CosPA"), centrality, ptmc); + if (validTrackProperties && validThisSpecies && topoDcaPosToPVOK) + histos.fill(HIST("h2dPtVsCentrality_DcaPosToPV"), centrality, ptmc); + if (validTrackProperties && validThisSpecies && topoDcaNegToPVOK) + histos.fill(HIST("h2dPtVsCentrality_DcaNegToPV"), centrality, ptmc); + if (validTrackProperties && validThisSpecies && topoDcaV0DauOK) + histos.fill(HIST("h2dPtVsCentrality_DcaV0Dau"), centrality, ptmc); + } + } else { + continue; + } + } + histos.fill(HIST("hNRecoV0sWithTPC"), nCandidatesWithTPC); + + // Major check 1: Findable versus found in some capacity + histos.fill(HIST("h2dPtVsCentrality_Findable"), centrality, ptmc); + if (hasBeenAcceptablyTracked) { + histos.fill(HIST("h2dPtVsCentrality_AcceptablyTracked"), centrality, ptmc); + } + if (hasBeenFoundAny) { + histos.fill(HIST("h2dPtVsCentrality_FoundAny"), centrality, ptmc); + } + if (hasBeenFound) { + histos.fill(HIST("h2dPtVsCentrality_Found"), centrality, ptmc); + } + if (hasWrongCollision) { + histos.fill(HIST("hNRecoV0sWrongColl"), recv0s.size()); + } + } + + PROCESS_SWITCH(findableStudy, processEvents, "process collision counters", true); + PROCESS_SWITCH(findableStudy, processDebugCrossCheck, "process debug cross-check of V0 with TPC-only", true); + PROCESS_SWITCH(findableStudy, processDebugCrossCheckMC, "process debug cross-check of V0 with TPC-only, MC version", false); + PROCESS_SWITCH(findableStudy, processV0s, "process V0s", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/QC/kfPerformanceStudy.cxx b/PWGLF/Tasks/QC/kfPerformanceStudy.cxx old mode 100755 new mode 100644 diff --git a/PWGLF/Tasks/QC/kfStrangenessStudy.cxx b/PWGLF/Tasks/QC/kfStrangenessStudy.cxx old mode 100755 new mode 100644 diff --git a/PWGLF/Tasks/QC/lfITSTPCMatchingQA.cxx b/PWGLF/Tasks/QC/lfITSTPCMatchingQA.cxx index f3bd0adecb7..c31258d51ae 100644 --- a/PWGLF/Tasks/QC/lfITSTPCMatchingQA.cxx +++ b/PWGLF/Tasks/QC/lfITSTPCMatchingQA.cxx @@ -94,7 +94,7 @@ struct lfmatchingqa { float getITSClSize(T const& track) { float sum{0.f}; - for (int iL{0}; iL < 6; ++iL) { + for (int iL{0}; iL < 7; ++iL) { sum += (track.itsClusterSizes() >> (iL * 4)) & 0xf; } return sum / track.itsNCls(); diff --git a/PWGLF/Tasks/QC/lfITSTPCMatchingSecondaryTracksQA.cxx b/PWGLF/Tasks/QC/lfITSTPCMatchingSecondaryTracksQA.cxx new file mode 100644 index 00000000000..14aebdb354a --- /dev/null +++ b/PWGLF/Tasks/QC/lfITSTPCMatchingSecondaryTracksQA.cxx @@ -0,0 +1,343 @@ +// 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 lfITSTPCMatchingSecondaryTracksQA.cxx +/// +/// \brief task for QA of ITS-TPC matching efficiency of secondary tracks from V0s +/// \author Alberto Caliva (alberto.caliva@cern.ch), Francesca Ercolessi (francesca.ercolessi@cern.ch), Nicolò Jacazio (nicolo.jacazio@cern.ch) +/// \since Feb 11, 2025 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "ReconstructionDataFormats/Track.h" + +using namespace std; +using namespace o2; +using namespace o2::soa; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; +using namespace o2::constants::math; +using std::array; + +using SelCollisions = soa::Join; +using SimCollisions = soa::Join; +using StrHadronDaughterTracks = soa::Join; +using MCTracks = soa::Join; + +struct LfITSTPCMatchingSecondaryTracksQA { + + HistogramRegistry registryData{"registryData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryMC{"registryMC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Global Parameters + Configurable zVtx{"zVtx", 10.0, "Maximum zVertex"}; + + // Track Parameters + Configurable minITSnCls{"minITSnCls", 1.0f, "min number of ITS clusters"}; + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 80.0f, "min number of TPC crossed rows"}; + Configurable maxChi2TPC{"maxChi2TPC", 4.0f, "max chi2 per cluster TPC"}; + Configurable maxChi2ITS{"maxChi2ITS", 36.0f, "max chi2 per cluster ITS"}; + Configurable etaMin{"etaMin", -0.8f, "eta min"}; + Configurable etaMax{"etaMax", +0.8f, "eta max"}; + Configurable nsigmaTPCmin{"nsigmaTPCmin", -3.0f, "Minimum nsigma TPC"}; + Configurable nsigmaTPCmax{"nsigmaTPCmax", +3.0f, "Maximum nsigma TPC"}; + Configurable nsigmaTOFmin{"nsigmaTOFmin", -3.0f, "Minimum nsigma TOF"}; + Configurable nsigmaTOFmax{"nsigmaTOFmax", +3.0f, "Maximum nsigma TOF"}; + Configurable dcaxyMax{"dcaxyMax", 0.1f, "dcaxy max"}; + Configurable dcazMax{"dcazMax", 0.1f, "dcaz max"}; + Configurable dcaMin{"dcaMin", 0.1f, "dca min"}; + Configurable requireTOF{"requireTOF", false, "require TOF hit"}; + Configurable requireItsHits{"requireItsHits", false, "require ITS hits"}; + Configurable> requiredHit{"requiredHit", {0, 0, 0, 0, 0, 0, 0}, "required ITS Hits (1=required, 0=not required)"}; + + // V0 Parameters + Configurable minimumV0Radius{"minimumV0Radius", 0.0f, "Minimum V0 Radius"}; + Configurable maximumV0Radius{"maximumV0Radius", 100.0f, "Maximum V0 Radius"}; + Configurable dcanegtoPVmin{"dcanegtoPVmin", 0.1f, "Minimum DCA Neg To PV"}; + Configurable dcapostoPVmin{"dcapostoPVmin", 0.1f, "Minimum DCA Pos To PV"}; + Configurable v0cospaMin{"v0cospaMin", 0.99f, "Minimum V0 CosPA"}; + Configurable dcaV0DaughtersMax{"dcaV0DaughtersMax", 0.5f, "Maximum DCA Daughters"}; + Configurable mK0Min{"mK0Min", 0.48f, "K0 mass lower cut"}; + Configurable mK0Max{"mK0Max", 0.52f, "K0 mass upper cut"}; + + void init(InitContext const&) + { + // Event Counters + if (doprocessData) { + registryData.add("number_of_events_data", "number of events in data", HistType::kTH1D, {{20, 0, 20, "Event Cuts"}}); + registryData.add("dcaxyDatavspt", "dcaxyDatavspt", HistType::kTH2D, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {400, -2, 2, "DCA_{xy} (cm)"}}); + registryData.add("dcazDatavspt", "dcazDatavspt", HistType::kTH2D, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {400, -2, 2, "DCA_{z} (cm)"}}); + registryData.add("primPionTPC", "primPionTPC", HistType::kTH3D, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#eta"}, {100, 0, TwoPI, "#phi"}}); + registryData.add("primPionTPC_ITS", "primPionTPC_ITS", HistType::kTH3D, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#eta"}, {100, 0, TwoPI, "#phi"}}); + registryData.add("secPionTPC", "secPionTPC", HistType::kTH3D, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#eta"}, {100, 0, TwoPI, "#phi"}}); + registryData.add("secPionTPC_ITS", "secPionTPC_ITS", HistType::kTH3D, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#eta"}, {100, 0, TwoPI, "#phi"}}); + registryData.add("secPionV0TPC", "secPionV0TPC", HistType::kTH3D, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#eta"}, {100, 0, TwoPI, "#phi"}}); + registryData.add("secPionV0TPC_ITS", "secPionV0TPC_ITS", HistType::kTH3D, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#eta"}, {100, 0, TwoPI, "#phi"}}); + } + + if (doprocessMC) { + registryMC.add("number_of_events_mc", "number of events in mc", HistType::kTH1D, {{20, 0, 20, "Event Cuts"}}); + registryMC.add("dcaxyMCvspt", "dcaxyMCvspt", HistType::kTH2D, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {400, -2, 2, "DCA_{xy} (cm)"}}); + registryMC.add("dcazMCvspt", "dcazMCvspt", HistType::kTH2D, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {400, -2, 2, "DCA_{z} (cm)"}}); + registryMC.add("primPionTPC_MC", "primPionTPC_MC", HistType::kTH3D, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#eta"}, {100, 0, TwoPI, "#phi"}}); + registryMC.add("primPionTPC_ITS_MC", "primPionTPC_ITS_MC", HistType::kTH3D, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#eta"}, {100, 0, TwoPI, "#phi"}}); + registryMC.add("secPionTPC_MC", "secPionTPC_MC", HistType::kTH3D, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#eta"}, {100, 0, TwoPI, "#phi"}}); + registryMC.add("secPionTPC_ITS_MC", "secPionTPC_ITS_MC", HistType::kTH3D, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#eta"}, {100, 0, TwoPI, "#phi"}}); + registryMC.add("secPionV0TPC_MC", "secPionV0TPC_MC", HistType::kTH3D, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#eta"}, {100, 0, TwoPI, "#phi"}}); + registryMC.add("secPionV0TPC_ITS_MC", "secPionV0TPC_ITS_MC", HistType::kTH3D, {{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#eta"}, {100, 0, TwoPI, "#phi"}}); + } + } + + bool hasHitOnITSlayer(uint8_t itsClsmap, int layer) + { + unsigned char testBit = 1 << layer; + return (itsClsmap & testBit); + } + + template + bool passedTrackSelectionTpcPrimary(const TpcPrimTrack& track) + { + if (!track.hasTPC()) + return false; + if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + if (track.tpcChi2NCl() > maxChi2TPC) + return false; + if (track.eta() < etaMin || track.eta() > etaMax) + return false; + if (std::fabs(track.dcaXY()) > dcaxyMax) + return false; + if (std::fabs(track.dcaZ()) > dcazMax) + return false; + return true; + } + + template + bool passedTrackSelectionTpcSecondary(const TpcSecTrack& track) + { + if (!track.hasTPC()) + return false; + if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + if (track.tpcChi2NCl() > maxChi2TPC) + return false; + if (track.eta() < etaMin || track.eta() > etaMax) + return false; + if (std::sqrt(track.dcaXY() * track.dcaXY() + track.dcaZ() * track.dcaZ()) < dcaMin) + return false; + return true; + } + + template + bool passedTrackSelectionV0daughTPC(const v0Track& track) + { + if (!track.hasTPC()) + return false; + if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + if (track.tpcChi2NCl() > maxChi2TPC) + return false; + if (track.eta() < etaMin || track.eta() > etaMax) + return false; + return true; + } + + // K0s Selections + template + bool passedK0ShortSelection(const K0short& v0) + { + if (v0.v0cosPA() < v0cospaMin) + return false; + if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) + return false; + if (v0.dcaV0daughters() > dcaV0DaughtersMax) + return false; + if (std::fabs(v0.dcapostopv()) < dcapostoPVmin) + return false; + if (std::fabs(v0.dcanegtopv()) < dcanegtoPVmin) + return false; + if (v0.mK0Short() < mK0Min || v0.mK0Short() > mK0Max) + return false; + + return true; + } + + template + bool passedPionSelection(const pionTrack& track) + { + // TPC Selection + if (track.tpcNSigmaPi() < nsigmaTPCmin || track.tpcNSigmaPi() > nsigmaTPCmax) + return false; + + // TOF Selection + if (requireTOF) { + if (track.tofNSigmaPi() < nsigmaTOFmin || track.tofNSigmaPi() > nsigmaTOFmax) + return false; + } + return true; + } + + template + bool passedTrackSelectionIts(const ItsTrack& track) + { + /* + if (!track.hasITS()) + return false; + if (track.itsNCls() < minITSnCls) + return false; + if (track.itsChi2NCl() > maxChi2ITS) + return false; + */ + + if (track.itsNCls() < minITSnCls) + return false; + + auto requiredItsHit = static_cast>(requiredHit); + if (requireItsHits) { + for (int i = 0; i < 7; i++) { + if (requiredItsHit[i] > 0 && !hasHitOnITSlayer(track.itsClusterMap(), i)) { + return false; + } + } + } + return true; + } + + void processData(SelCollisions::iterator const& collision, aod::V0Datas const& fullV0s, StrHadronDaughterTracks const& tracks) + { + registryData.fill(HIST("number_of_events_data"), 0.5); + + // Event Selection + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + return; + registryData.fill(HIST("number_of_events_data"), 1.5); + + for (const auto& track : tracks) { + + // DCA distributions + if (passedTrackSelectionV0daughTPC(track) && passedPionSelection(track)) { + registryData.fill(HIST("dcaxyDatavspt"), track.pt(), track.dcaXY()); + registryData.fill(HIST("dcazDatavspt"), track.pt(), track.dcaZ()); + } + + // Primary Tracks + if (passedTrackSelectionTpcPrimary(track) && passedPionSelection(track)) + registryData.fill(HIST("primPionTPC"), track.pt(), track.eta(), TVector2::Phi_0_2pi(track.phi())); + if (passedTrackSelectionTpcPrimary(track) && passedPionSelection(track) && passedTrackSelectionIts(track)) + registryData.fill(HIST("primPionTPC_ITS"), track.pt(), track.eta(), TVector2::Phi_0_2pi(track.phi())); + + // Secondary Tracks + if (passedTrackSelectionTpcSecondary(track) && passedPionSelection(track)) + registryData.fill(HIST("secPionTPC"), track.pt(), track.eta(), TVector2::Phi_0_2pi(track.phi())); + if (passedTrackSelectionTpcSecondary(track) && passedPionSelection(track) && passedTrackSelectionIts(track)) + registryData.fill(HIST("secPionTPC_ITS"), track.pt(), track.eta(), TVector2::Phi_0_2pi(track.phi())); + } + + for (const auto& v0 : fullV0s) { + + const auto& posTrack = v0.posTrack_as(); + const auto& negTrack = v0.negTrack_as(); + if (!passedK0ShortSelection(v0)) + continue; + + if (passedTrackSelectionV0daughTPC(posTrack) && passedPionSelection(posTrack)) + registryData.fill(HIST("secPionV0TPC"), posTrack.pt(), posTrack.eta(), TVector2::Phi_0_2pi(posTrack.phi())); + if (passedTrackSelectionV0daughTPC(negTrack) && passedPionSelection(negTrack)) + registryData.fill(HIST("secPionV0TPC"), negTrack.pt(), negTrack.eta(), TVector2::Phi_0_2pi(negTrack.phi())); + if (passedTrackSelectionV0daughTPC(posTrack) && passedPionSelection(posTrack) && passedTrackSelectionIts(posTrack)) + registryData.fill(HIST("secPionV0TPC_ITS"), posTrack.pt(), posTrack.eta(), TVector2::Phi_0_2pi(posTrack.phi())); + if (passedTrackSelectionV0daughTPC(negTrack) && passedPionSelection(negTrack) && passedTrackSelectionIts(negTrack)) + registryData.fill(HIST("secPionV0TPC_ITS"), negTrack.pt(), negTrack.eta(), TVector2::Phi_0_2pi(negTrack.phi())); + } + } + PROCESS_SWITCH(LfITSTPCMatchingSecondaryTracksQA, processData, "Process data", true); + + Preslice perCollisionV0 = o2::aod::v0data::collisionId; + Preslice perCollisionTrk = o2::aod::track::collisionId; + + void processMC(SimCollisions const& collisions, MCTracks const& mcTracks, aod::V0Datas const& fullV0s, const aod::McParticles&) + { + for (const auto& collision : collisions) { + registryMC.fill(HIST("number_of_events_mc"), 0.5); + + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + continue; + registryMC.fill(HIST("number_of_events_mc"), 1.5); + + auto v0sPerColl = fullV0s.sliceBy(perCollisionV0, collision.globalIndex()); + auto tracksPerColl = mcTracks.sliceBy(perCollisionTrk, collision.globalIndex()); + + for (const auto& track : tracksPerColl) { + + // DCA distributions + if (passedTrackSelectionV0daughTPC(track) && passedPionSelection(track)) { + registryMC.fill(HIST("dcaxyMCvspt"), track.pt(), track.dcaXY()); + registryMC.fill(HIST("dcazMCvspt"), track.pt(), track.dcaZ()); + } + + // Primary Tracks + if (passedTrackSelectionTpcPrimary(track) && passedPionSelection(track)) + registryMC.fill(HIST("primPionTPC_MC"), track.pt(), track.eta(), TVector2::Phi_0_2pi(track.phi())); + if (passedTrackSelectionTpcPrimary(track) && passedPionSelection(track) && passedTrackSelectionIts(track)) + registryMC.fill(HIST("primPionTPC_ITS_MC"), track.pt(), track.eta(), TVector2::Phi_0_2pi(track.phi())); + + // Secondary Tracks + if (passedTrackSelectionTpcSecondary(track) && passedPionSelection(track)) + registryMC.fill(HIST("secPionTPC_MC"), track.pt(), track.eta(), TVector2::Phi_0_2pi(track.phi())); + if (passedTrackSelectionTpcSecondary(track) && passedPionSelection(track) && passedTrackSelectionIts(track)) + registryMC.fill(HIST("secPionTPC_ITS_MC"), track.pt(), track.eta(), TVector2::Phi_0_2pi(track.phi())); + } + + for (const auto& v0 : v0sPerColl) { + + const auto& posTrack = v0.posTrack_as(); + const auto& negTrack = v0.negTrack_as(); + if (!passedK0ShortSelection(v0)) + continue; + + if (passedTrackSelectionV0daughTPC(posTrack) && passedPionSelection(posTrack)) + registryMC.fill(HIST("secPionV0TPC_MC"), posTrack.pt(), posTrack.eta(), TVector2::Phi_0_2pi(posTrack.phi())); + if (passedTrackSelectionV0daughTPC(negTrack) && passedPionSelection(negTrack)) + registryMC.fill(HIST("secPionV0TPC_MC"), negTrack.pt(), negTrack.eta(), TVector2::Phi_0_2pi(negTrack.phi())); + if (passedTrackSelectionV0daughTPC(posTrack) && passedPionSelection(posTrack) && passedTrackSelectionIts(posTrack)) + registryMC.fill(HIST("secPionV0TPC_ITS_MC"), posTrack.pt(), posTrack.eta(), TVector2::Phi_0_2pi(posTrack.phi())); + if (passedTrackSelectionV0daughTPC(negTrack) && passedPionSelection(negTrack) && passedTrackSelectionIts(negTrack)) + registryMC.fill(HIST("secPionV0TPC_ITS_MC"), negTrack.pt(), negTrack.eta(), TVector2::Phi_0_2pi(negTrack.phi())); + } + } + } + PROCESS_SWITCH(LfITSTPCMatchingSecondaryTracksQA, processMC, "Process MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/QC/mcParticlePrediction.cxx b/PWGLF/Tasks/QC/mcParticlePrediction.cxx new file mode 100644 index 00000000000..ba66cabe648 --- /dev/null +++ b/PWGLF/Tasks/QC/mcParticlePrediction.cxx @@ -0,0 +1,661 @@ +// 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 mcParticlePrediction.cxx +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \author Francesca Ercolessi francesca.ercolessi@cern.ch +/// \brief Task to build the predictions from the models based on the generated particles +/// + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StaticFor.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "PWGLF/Utils/mcParticle.h" +#include "PWGLF/Utils/inelGt.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "CommonConstants/LHCConstants.h" + +#include "TPDGCode.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::pwglf; + +// Particles +static const std::vector parameterNames{"Enable"}; +static constexpr int nParameters = 1; +static const int defaultParticles[PIDExtended::NIDsTot][nParameters]{{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {1}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}}; +bool enabledParticlesArray[PIDExtended::NIDsTot]; + +// Estimators +struct Estimators { + typedef int estID; + static constexpr estID FT0A = 0; + static constexpr estID FT0C = 1; + static constexpr estID FT0AC = 2; + static constexpr estID FV0A = 3; + static constexpr estID FDDA = 4; + static constexpr estID FDDC = 5; + static constexpr estID FDDAC = 6; + static constexpr estID ZNA = 7; + static constexpr estID ZNC = 8; + static constexpr estID ZEM1 = 9; + static constexpr estID ZEM2 = 10; + static constexpr estID ZPA = 11; + static constexpr estID ZPC = 12; + static constexpr estID ITSIB = 13; + static constexpr estID ETA05 = 14; + static constexpr estID ETA08 = 15; + static constexpr estID V0A = 16; // (Run2) + static constexpr estID V0C = 17; // (Run2) + static constexpr estID V0AC = 18; // (Run2 V0M) + static constexpr estID nEstimators = 19; + + static constexpr const char* estimatorNames[nEstimators] = {"FT0A", + "FT0C", + "FT0AC", + "FV0A", + "FDDA", + "FDDC", + "FDDAC", + "ZNA", + "ZNC", + "ZEM1", + "ZEM2", + "ZPA", + "ZPC", + "ITSIB", + "ETA05", + "ETA08", + "V0A", + "V0C", + "V0AC"}; + static std::vector arrayNames() + { + static std::vector names; + if (!names.empty()) { + return names; + } + for (int i = 0; i < nEstimators; i++) { + names.push_back(estimatorNames[i]); + } + return names; + } +}; +bool enabledEstimatorsArray[Estimators::nEstimators]; +static const int defaultEstimators[Estimators::nEstimators][nParameters]{{0}, // FT0A + {0}, // FT0C + {1}, // FT0AC + {0}, // FV0A + {0}, // FDDA + {0}, // FDDC + {0}, // FDDAC + {0}, // ZNA + {0}, // ZNC + {0}, // ZEM1 + {0}, // ZEM2 + {0}, // ZPA + {0}, // ZPC + {0}, // ITSIB + {0}, // ETA05 + {0}, // ETA08 + {0}, // V0A (Run2) + {0}, // V0C (Run2) + {0}}; // V0AC (Run2 V0M) + +// Histograms +std::array, Estimators::nEstimators> hestimators; +std::array, Estimators::nEstimators> hestimatorsVsITS; +std::array, Estimators::nEstimators> hestimatorsVsETA05; +std::array, Estimators::nEstimators> hestimatorsVsETA08; +std::array, Estimators::nEstimators> hestimatorsRecoEvGenVsReco; +std::array, Estimators::nEstimators> hestimatorsRecoEvGenVsReco_BCMC; +std::array, Estimators::nEstimators> hestimatorsRecoEvGenVsRecoITS; +std::array, Estimators::nEstimators> hestimatorsRecoEvRecoVsITS; +std::array, Estimators::nEstimators> hestimatorsRecoEvRecoVsRecoITS; +std::array, Estimators::nEstimators> hestimatorsRecoEvRecoVsRecoITS_BCMC; +std::array, Estimators::nEstimators> hestimatorsRecoEvRecoVsFT0A; +std::array, Estimators::nEstimators> hestimatorsRecoEvRecoVsBCId; +std::array, Estimators::nEstimators> hestimatorsRecoEvVsBCId; +std::array, Estimators::nEstimators> hvertexPosZ; +std::array, PIDExtended::NIDsTot>, Estimators::nEstimators> hpt; +std::array, PIDExtended::NIDsTot>, Estimators::nEstimators> hyield; + +struct mcParticlePrediction { + + // Histograms + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry histosRecoEvs{"HistosRecoEvs", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry histosYield{"HistosYield", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry histosPt{"HistosPt", {}, OutputObjHandlingPolicy::AnalysisObject}; + ConfigurableAxis binsEta{"binsEta", {100, -20, 20}, "Binning of the Eta axis"}; + ConfigurableAxis binsVxy{"binsVxy", {100, -10, 10}, "Binning of the production vertex (x and y) axis"}; + ConfigurableAxis binsVz{"binsVz", {100, -10, 10}, "Binning of the production vertex (z) axis"}; + ConfigurableAxis binsPt{"binsPt", {100, 0, 10}, "Binning of the Pt axis"}; + ConfigurableAxis binsMultiplicity{"binsMultiplicity", {300, -0.5, 299.5}, "Binning of the Multiplicity axis"}; + ConfigurableAxis binsMultiplicityReco{"binsMultiplicityReco", {1000, -0.5, -0.5 + 10000}, "Binning of the Multiplicity axis"}; + Configurable> enabledSpecies{"enabledSpecies", + {defaultParticles[0], PIDExtended::NIDsTot, nParameters, PIDExtended::arrayNames(), parameterNames}, + "Particles enabled"}; + Configurable> enabledEstimators{"enabledEstimators", + {defaultEstimators[0], Estimators::nEstimators, nParameters, Estimators::arrayNames(), parameterNames}, + "Estimators enabled"}; + Configurable selectInelGt0{"selectInelGt0", true, "Select only inelastic events"}; + Configurable selectPrimaries{"selectPrimaries", true, "Select only primary particles"}; + Configurable requireCoincidenceEstimators{"requireCoincidenceEstimators", false, "Asks for a coincidence when two estimators are used"}; + Configurable discardkIsGoodZvtxFT0vsPV{"discardkIsGoodZvtxFT0vsPV", false, "Select only collisions with matching BC and MC BC"}; + Configurable discardMismatchedBCs{"discardMismatchedBCs", false, "Select only collisions with matching BC and MC BC"}; + Configurable discardMismatchedFoundBCs{"discardMismatchedFoundBCs", false, "Select only collisions with matching found BC and MC BC"}; + Configurable posZCut{"posZCut", 10.f, "Cut in the Z position of the primary vertex"}; + Configurable collisionTimeResCut{"collisionTimeResCut", -40.f, "Cut in the collisionTimeRes"}; + Configurable requirekIsGoodZvtxFT0vsPV{"requirekIsGoodZvtxFT0vsPV", false, "Require kIsGoodZvtxFT0vsPV: small difference between z-vertex from PV and from FT0"}; + Configurable requirekIsVertexITSTPC{"requirekIsVertexITSTPC", false, "Require kIsVertexITSTPC: at least one ITS-TPC track (reject vertices built from ITS-only tracks)"}; + Configurable requirekIsVertexTOFmatched{"requirekIsVertexTOFmatched", false, "Require kIsVertexTOFmatched: at least one of vertex contributors is matched to TOF"}; + Configurable requirekIsVertexTRDmatched{"requirekIsVertexTRDmatched", false, "Require kIsVertexTRDmatched: at least one of vertex contributors is matched to TRD"}; + Configurable enableVsITSHistograms{"enableVsITSHistograms", true, "Enables the correlation between ITS and other estimators"}; + Configurable enableVsEta05Histograms{"enableVsEta05Histograms", true, "Enables the correlation between ETA05 and other estimators"}; + Configurable enableVsEta08Histograms{"enableVsEta08Histograms", true, "Enables the correlation between ETA08 and other estimators"}; + + Service pdgDB; + o2::pwglf::ParticleCounter mCounter; + + void init(o2::framework::InitContext&) + { + mCounter.mPdgDatabase = pdgDB.service; + mCounter.mSelectPrimaries = selectPrimaries.value; + const AxisSpec axisEta{binsEta, "#eta"}; + const AxisSpec axisVx{binsVxy, "Vx"}; + const AxisSpec axisVy{binsVxy, "Vy"}; + const AxisSpec axisVz{binsVz, "Vz"}; + const AxisSpec axisPt{binsPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisMultiplicity{binsMultiplicity, "Multiplicity (undefined)"}; + const AxisSpec axisMultiplicityReco{binsMultiplicityReco, "Multiplicity Reco. (undefined)"}; + const AxisSpec axisMultiplicityRecoITS{100, 0, 100, "Multiplicity Reco. ITSIB"}; + const AxisSpec axisMultiplicityGenV0s{100, 0, 100, "K0s gen"}; + const AxisSpec axisMultiplicityRecoV0s{20, 0, 20, "K0s reco"}; + const AxisSpec axisBCID{o2::constants::lhc::LHCMaxBunches, -0.5, -0.5 + o2::constants::lhc::LHCMaxBunches, "BC ID in orbit"}; + const AxisSpec axisBCIDMC{o2::constants::lhc::LHCMaxBunches, -0.5, -0.5 + o2::constants::lhc::LHCMaxBunches, "MC BC ID in orbit"}; + const AxisSpec axisFT0{1000, -5, 5, "Coll time FT0 (ps)"}; + + auto h = histos.add("collisions/generated", "collisions", kTH1D, {{10, -0.5, 9.5}}); + h->GetXaxis()->SetBinLabel(1, "Read"); + h->GetXaxis()->SetBinLabel(2, "INELgt0"); + h->GetXaxis()->SetBinLabel(3, "|Z|<10"); + h = histos.add("collisions/reconstructed", "collisions", kTH1D, {{20, -0.5, 19.5}}); + h->GetXaxis()->SetBinLabel(1, "Read"); + h->GetXaxis()->SetBinLabel(2, "has_mcCollision"); + h->GetXaxis()->SetBinLabel(3, "sel8"); + h->GetXaxis()->SetBinLabel(4, "kIsBBT0A"); + h->GetXaxis()->SetBinLabel(5, "kIsBBT0C"); + h->GetXaxis()->SetBinLabel(6, "collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))"); + h->GetXaxis()->SetBinLabel(7, "globalBC == MC globalBC"); + h->GetXaxis()->SetBinLabel(8, "found globalBC == MC globalBC"); + h->GetXaxis()->SetBinLabel(9, "isINELgt0mc"); + h->GetXaxis()->SetBinLabel(10, "VTXz"); + h->GetXaxis()->SetBinLabel(11, "collisionTimeRes"); + h->GetXaxis()->SetBinLabel(11, "collisionTimeRes"); + h->GetXaxis()->SetBinLabel(12, "kIsGoodZvtxFT0vsPV"); + h->GetXaxis()->SetBinLabel(13, "kIsVertexITSTPC"); + h->GetXaxis()->SetBinLabel(14, "kIsVertexTOFmatched"); + h->GetXaxis()->SetBinLabel(15, "kIsVertexTRDmatched"); + + histos.add("collisions/Reco/BCvsMCBC", "BC vs MC BC", kTH2D, {axisBCID, axisBCIDMC}); + histos.add("collisions/Reco/FoundBCvsMCBC", "Found BC vs MC BC", kTH2D, {axisBCID, axisBCIDMC})->GetXaxis()->SetTitle("Found BC ID in orbit"); + histos.add("collisions/Reco/FoundBCvsBC", "Found BC vs MC BC", kTH2D, {axisBCID, axisBCID})->GetXaxis()->SetTitle("Found BC ID in orbit"); + histos.add("collisions/Reco/collisionTime", "Collision Time", kTH1D, {{1000, -20, 20, "collisionTime"}}); + histos.add("collisions/Reco/collisionTimeRes", "Collision Time Res", kTH1D, {{1600, 0, 1600, "collisionTimeRes (ns)"}}); + histos.add("collisions/Reco/bcMinusfoundBc", "bcMinusfoundBc", kTH1D, {{1600, -1000, 1000, "bc - foundBc (ns)"}}); + histos.add("collisions/Reco/bcMinusfoundBcRatio", "bcMinusfoundBcRatio", kTH1D, {{1600, -40, 40, "(bc - foundBc)/collisionTimeRes"}}); + histos.add("collisions/Reco/bcMinusMcBcRatio", "bcMinusMcBcRatio", kTH1D, {{1600, -40, 40, "(bc - mcBc)/collisionTimeRes"}}); + histos.add("collisions/Reco/foundbcMinusMcBcRatio", "foundbcMinusMcBcRatio", kTH1D, {{1600, -40, 40, "(foundBc-mcBc)/collisionTimeRes"}}); + histos.add("collisions/Reco/FT0A", "FT0A", kTH1D, {axisFT0})->GetXaxis()->SetTitle("Coll time FT0A (ps)"); + histos.add("collisions/Reco/FT0C", "FT0C", kTH1D, {axisFT0})->GetXaxis()->SetTitle("Coll time FT0C (ps)"); + histos.add("collisions/Reco/FT0AC", "FT0AC", kTH1D, {axisFT0})->GetXaxis()->SetTitle("Coll time FT0AC (ps)"); + histos.add("particles/eta/charged", "eta", kTH1D, {axisEta}); + histos.add("particles/eta/neutral", "eta", kTH1D, {axisEta}); + histos.add("particles/vtx/x", "Vx", kTH1D, {axisVx}); + histos.add("particles/vtx/y", "Vy", kTH1D, {axisVy}); + histos.add("particles/vtx/z", "Vz", kTH1D, {axisVz}); + histos.add("particles/FromCollVsFromMCColl", "FromCollVsFromMCColl", kTH2D, {{binsMultiplicity, "PV contributor particles (good bc)"}, {binsMultiplicityReco, "Particles in MC collision"}}); + histos.add("particles/FromCollVsFromMCCollBad", "FromCollVsFromMCCollBad", kTH2D, {{binsMultiplicity, "PV contributor particles (bad bc)"}, {binsMultiplicityReco, "Particles in MC collision"}}); + histos.add("particles/FromCollVsFromCollBad", "FromCollVsFromCollBad", kTH2D, {{binsMultiplicity, "PV contributor particles (good bc)"}, {binsMultiplicity, "PV contributor particles (bad bc)"}}); + histos.add("particles/FromCollBadOverFromCollVsVsFromMCColl", "FromCollBadOverFromCollVsVsFromMCColl", kTH2D, {{100, 0, 2, "bad/good"}, {binsMultiplicityReco, "Particles in MC collision"}}); + histos.add("V0s/V0RecovsPV", "V0s Reco + Ass vs PV", kTH2D, {axisMultiplicityRecoITS, axisMultiplicityRecoV0s}); + histos.add("V0s/V0RecoAssvsPV", "V0s Reco + Ass vs PV", kTH2D, {axisMultiplicityRecoITS, axisMultiplicityRecoV0s}); + histos.add("V0s/V0AssvsPV", "V0s Ass vs PV", kTH2D, {axisMultiplicityRecoITS, axisMultiplicityGenV0s}); + histos.add("V0s/V0RecoAssvsPV_TOFOneLeg", "V0s Reco + Ass + TOF 1 Leg vs PV", kTH2D, {axisMultiplicityRecoITS, axisMultiplicityRecoV0s}); + histos.add("V0s/V0RecoAssvsPV_TOFTwoLegs", "V0s Reco + Ass + TOF 2 Legs vs PV", kTH2D, {axisMultiplicityRecoITS, axisMultiplicityRecoV0s}); + + for (int i = 0; i < Estimators::nEstimators; i++) { + if (enabledEstimators->get(Estimators::estimatorNames[i], "Enable") != 1) { + enabledEstimatorsArray[i] = false; + continue; + } + LOG(info) << "Enabling estimator " << i << " " << Estimators::estimatorNames[i]; + enabledEstimatorsArray[i] = true; + } + + h = histos.add("particles/yields", "particles", kTH1D, {{PIDExtended::NIDsTot, -0.5, -0.5 + PIDExtended::NIDsTot}}); + for (int i = 0; i < PIDExtended::NIDsTot; i++) { + h->GetXaxis()->SetBinLabel(i + 1, PIDExtended::getName(i)); + } + + for (int i = 0; i < Estimators::nEstimators; i++) { + if (!enabledEstimatorsArray[i]) { + continue; + } + const char* name = Estimators::estimatorNames[i]; + hestimators[i] = histos.add(Form("multiplicity/%s", name), name, kTH1D, {axisMultiplicity}); + hestimators[i]->GetXaxis()->SetTitle(Form("Multiplicity %s", name)); + + auto make2DH = [&](const std::string& h, const char* ytitle) { + auto hist = histos.add(Form("%s%s", h.c_str(), name), + name, + kTH2D, + {axisMultiplicity, axisMultiplicity}); + hist->GetXaxis()->SetTitle(Form("Multiplicity %s", name)); + hist->GetXaxis()->SetTitle(Form("Multiplicity %s", ytitle)); + return hist; + }; + if (enableVsITSHistograms) { + hestimatorsVsITS[i] = make2DH("multiplicity/vsITS/", Estimators::estimatorNames[Estimators::ITSIB]); + } + if (enableVsEta05Histograms) { + hestimatorsVsETA05[i] = make2DH("multiplicity/vsETA05/", Estimators::estimatorNames[Estimators::ETA05]); + } + if (enableVsEta08Histograms) { + hestimatorsVsETA08[i] = make2DH("multiplicity/vsETA08/", Estimators::estimatorNames[Estimators::ETA08]); + } + + hvertexPosZ[i] = histos.add(Form("multiplicity/posZ/%s", name), name, kTH2D, {{200, -20, 20, "pos Z"}, axisMultiplicity}); + hvertexPosZ[i]->GetYaxis()->SetTitle(Form("Multiplicity %s", name)); + + if (!doprocessReco) { // Reco events + continue; + } + + hestimatorsRecoEvGenVsReco[i] = histosRecoEvs.add(Form("multiplicity/Reco/GenVsReco/%s", name), name, kTH2D, {axisMultiplicity, axisMultiplicityReco}); + hestimatorsRecoEvGenVsReco[i]->GetXaxis()->SetTitle(Form("Multiplicity %s", name)); + hestimatorsRecoEvGenVsReco[i]->GetYaxis()->SetTitle(Form("Multiplicity Reco. %s", name)); + + hestimatorsRecoEvGenVsReco_BCMC[i] = histosRecoEvs.add(Form("multiplicity/Reco/GenVsReco_BCMC/%s", name), name, kTH2D, {axisMultiplicity, axisMultiplicityReco}); + hestimatorsRecoEvGenVsReco_BCMC[i]->GetXaxis()->SetTitle(Form("Multiplicity %s", name)); + hestimatorsRecoEvGenVsReco_BCMC[i]->GetYaxis()->SetTitle(Form("Multiplicity Reco. %s (BCMC)", name)); + + hestimatorsRecoEvGenVsRecoITS[i] = histosRecoEvs.add(Form("multiplicity/Reco/GenVsRecoITS/%s", name), name, kTH2D, {axisMultiplicity, axisMultiplicityRecoITS}); + hestimatorsRecoEvGenVsRecoITS[i]->GetXaxis()->SetTitle(Form("Multiplicity %s", name)); + + hestimatorsRecoEvRecoVsITS[i] = histosRecoEvs.add(Form("multiplicity/Reco/RecoVsITS/%s", name), name, kTH2D, {axisMultiplicityReco, axisMultiplicity}); + hestimatorsRecoEvRecoVsITS[i]->GetXaxis()->SetTitle(Form("Multiplicity Reco. %s", name)); + hestimatorsRecoEvRecoVsITS[i]->GetYaxis()->SetTitle(Form("Multiplicity %s", Estimators::estimatorNames[Estimators::ITSIB])); + + hestimatorsRecoEvRecoVsRecoITS[i] = histosRecoEvs.add(Form("multiplicity/Reco/RecoVsRecoITS/%s", name), name, kTH2D, {axisMultiplicityReco, axisMultiplicityRecoITS}); + hestimatorsRecoEvRecoVsRecoITS[i]->GetXaxis()->SetTitle(Form("Multiplicity Reco. %s", name)); + + hestimatorsRecoEvRecoVsRecoITS_BCMC[i] = histosRecoEvs.add(Form("multiplicity/Reco/RecoVsRecoITS_BCMC/%s", name), name, kTH2D, {axisMultiplicityReco, axisMultiplicityRecoITS}); + hestimatorsRecoEvRecoVsRecoITS_BCMC[i]->GetXaxis()->SetTitle(Form("Multiplicity Reco. %s (BCMC)", name)); + + hestimatorsRecoEvRecoVsFT0A[i] = histosRecoEvs.add(Form("multiplicity/Reco/RecovsFT0A/%s", name), name, kTH2D, {axisMultiplicityReco, axisMultiplicity}); + hestimatorsRecoEvRecoVsFT0A[i]->GetXaxis()->SetTitle(Form("Multiplicity Reco. %s", name)); + hestimatorsRecoEvRecoVsFT0A[i]->GetYaxis()->SetTitle(Form("Multiplicity %s", Estimators::estimatorNames[Estimators::FT0A])); + + hestimatorsRecoEvRecoVsBCId[i] = histosRecoEvs.add(Form("multiplicity/Reco/RecoVsBCId/%s", name), name, kTH2D, {axisBCID, axisMultiplicityReco}); + hestimatorsRecoEvRecoVsBCId[i]->GetYaxis()->SetTitle(Form("Multiplicity Reco. %s", name)); + + hestimatorsRecoEvVsBCId[i] = histosRecoEvs.add(Form("multiplicity/Reco/VsBCId/%s", name), name, kTH2D, {axisBCID, axisMultiplicity}); + hestimatorsRecoEvVsBCId[i]->GetYaxis()->SetTitle(Form("Multiplicity %s", name)); + } + + for (int i = 0; i < PIDExtended::NIDsTot; i++) { + if (enabledSpecies->get(PIDExtended::getName(i), "Enable") != 1) { + enabledParticlesArray[i] = false; + continue; + } + LOG(info) << "Enabling particle " << i << " " << PIDExtended::getName(i); + enabledParticlesArray[i] = true; + for (int j = 0; j < Estimators::nEstimators; j++) { + if (!enabledEstimatorsArray[j]) { + continue; + } + const char* name = Estimators::estimatorNames[j]; + hpt[j][i] = histosPt.add(Form("prediction/pt/%s/%s", name, PIDExtended::getName(i)), PIDExtended::getName(i), kTH2D, {axisPt, axisMultiplicity}); + hpt[j][i]->GetYaxis()->SetTitle(Form("Multiplicity %s", name)); + + hyield[j][i] = histosYield.add(Form("prediction/yield/%s/%s", name, PIDExtended::getName(i)), PIDExtended::getName(i), kTH1D, {axisMultiplicity}); + hyield[j][i]->GetYaxis()->SetTitle(Form("Multiplicity %s", name)); + } + } + histos.print(); + histosRecoEvs.print(); + histosPt.print(); + histosYield.print(); + } + + std::array genMult(const auto& mcParticles) + { + std::array nMult; + if (enabledEstimatorsArray[Estimators::FT0A] || enabledEstimatorsArray[Estimators::FT0AC]) { + nMult[Estimators::FT0A] = mCounter.countFT0A(mcParticles); + } + if (enabledEstimatorsArray[Estimators::FT0C] || enabledEstimatorsArray[Estimators::FT0AC]) { + nMult[Estimators::FT0C] = mCounter.countFT0C(mcParticles); + } + if (enabledEstimatorsArray[Estimators::FT0AC]) { + nMult[Estimators::FT0AC] = nMult[Estimators::FT0A] + nMult[Estimators::FT0C]; + if (requireCoincidenceEstimators && (nMult[Estimators::FT0A] <= 0.f || nMult[Estimators::FT0C] <= 0.f)) { + nMult[Estimators::FT0AC] = 0; + } + } + if (enabledEstimatorsArray[Estimators::FV0A]) { + nMult[Estimators::FV0A] = mCounter.countFV0A(mcParticles); + } + if (enabledEstimatorsArray[Estimators::FDDA]) { + nMult[Estimators::FDDA] = mCounter.countFDDA(mcParticles); + } + if (enabledEstimatorsArray[Estimators::FDDC]) { + nMult[Estimators::FDDC] = mCounter.countFDDC(mcParticles); + } + if (enabledEstimatorsArray[Estimators::FDDAC]) { + nMult[Estimators::FDDAC] = nMult[Estimators::FDDA] + nMult[Estimators::FDDC]; + if (requireCoincidenceEstimators && (nMult[Estimators::FDDA] <= 0.f || nMult[Estimators::FDDC] <= 0.f)) { + nMult[Estimators::FDDAC] = 0; + } + } + if (enabledEstimatorsArray[Estimators::ZNA]) { + nMult[Estimators::ZNA] = mCounter.countZNA(mcParticles); + } + if (enabledEstimatorsArray[Estimators::ZNC]) { + nMult[Estimators::ZNC] = mCounter.countZNC(mcParticles); + } + if (enabledEstimatorsArray[Estimators::ITSIB] || enableVsITSHistograms) { + nMult[Estimators::ITSIB] = mCounter.countITSIB(mcParticles); + } + if (enabledEstimatorsArray[Estimators::ETA05] || enableVsEta05Histograms) { + nMult[Estimators::ETA05] = mCounter.countEta05(mcParticles); + } + if (enabledEstimatorsArray[Estimators::ETA08] || enableVsEta08Histograms) { + nMult[Estimators::ETA08] = mCounter.countEta08(mcParticles); + } + if (enabledEstimatorsArray[Estimators::V0A] || enabledEstimatorsArray[Estimators::V0AC]) { + nMult[Estimators::V0A] = mCounter.countV0A(mcParticles); + } + if (enabledEstimatorsArray[Estimators::V0C] || enabledEstimatorsArray[Estimators::V0AC]) { + nMult[Estimators::V0C] = mCounter.countV0C(mcParticles); + } + if (enabledEstimatorsArray[Estimators::V0AC]) { + nMult[Estimators::V0AC] = nMult[Estimators::V0A] + nMult[Estimators::V0C]; + if (requireCoincidenceEstimators && (nMult[Estimators::V0A] <= 0 || nMult[Estimators::V0C] <= 0)) { + nMult[Estimators::V0AC] = 0; + } + } + return nMult; + } + + void process(aod::McCollision const& mcCollision, + aod::McParticles const& mcParticles) + { + histos.fill(HIST("collisions/generated"), 0); + if (selectInelGt0.value && !o2::pwglf::isINELgt0mc(mcParticles, pdgDB)) { + return; + } + + histos.fill(HIST("collisions/generated"), 1); + if (std::abs(mcCollision.posZ()) > 10.f) { + return; + } + histos.fill(HIST("collisions/generated"), 2); + + const std::array& nMult = genMult(mcParticles); + + for (int i = 0; i < Estimators::nEstimators; i++) { + if (!enabledEstimatorsArray[i]) { + continue; + } + + hestimators[i]->Fill(nMult[i]); + if (enableVsITSHistograms) { + hestimatorsVsITS[i]->Fill(nMult[i], nMult[Estimators::ITSIB]); + } + if (enableVsEta05Histograms) { + hestimatorsVsETA05[i]->Fill(nMult[i], nMult[Estimators::ETA05]); + } + if (enableVsEta08Histograms) { + hestimatorsVsETA08[i]->Fill(nMult[i], nMult[Estimators::ETA08]); + } + hvertexPosZ[i]->Fill(mcCollision.posZ(), nMult[i]); + } + + for (const auto& particle : mcParticles) { + particle.pdgCode(); + const auto id = PIDExtended::pdgToId(particle); + if (id < 0) { + continue; + } + if (!enabledParticlesArray[id]) { + continue; + } + + if (!particle.isPhysicalPrimary()) { + continue; + } + + TParticlePDG* p = pdgDB->GetParticle(particle.pdgCode()); + if (p) { + if (std::abs(p->Charge()) > 1e-3) { + histos.fill(HIST("particles/eta/charged"), particle.eta()); + } else { + histos.fill(HIST("particles/eta/neutral"), particle.eta()); + } + } + + if (std::abs(particle.y()) > 0.5) { + continue; + } + + histos.fill(HIST("particles/vtx/x"), particle.vx()); + histos.fill(HIST("particles/vtx/y"), particle.vy()); + histos.fill(HIST("particles/vtx/z"), particle.vz() - mcCollision.posZ()); + + histos.fill(HIST("particles/yields"), id); + for (int i = 0; i < Estimators::nEstimators; i++) { + if (!enabledEstimatorsArray[i]) { + continue; + } + hpt[i][id]->Fill(particle.pt(), nMult[i]); + hyield[i][id]->Fill(nMult[i]); + } + } + } + + using TracksMC = soa::Join; + + Preslice perMCCol = aod::mcparticle::mcCollisionId; + SliceCache cache; + void processReco(soa::Join::iterator const& collision, + aod::McCollisions const& /*mcCollisions*/, + soa::Join const& /*bcs*/, + aod::McParticles const& mcParticles, + TracksMC const& tracks, + aod::FT0s const&) + { + histos.fill(HIST("collisions/reconstructed"), 0); + if (!collision.has_mcCollision()) { + return; + } + const auto& mcCollision = collision.mcCollision(); + histos.fill(HIST("collisions/reconstructed"), 1); + if (!collision.sel8()) { + return; + } + histos.fill(HIST("collisions/reconstructed"), 2); + if (!collision.selection_bit(aod::evsel::kIsBBT0A)) { + return; + } + histos.fill(HIST("collisions/reconstructed"), 3); + if (!collision.selection_bit(aod::evsel::kIsBBT0C)) { + return; + } + histos.fill(HIST("collisions/reconstructed"), 4); + if (discardkIsGoodZvtxFT0vsPV.value && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; + } + histos.fill(HIST("collisions/reconstructed"), 5); + + const auto& recoBC = collision.bc_as>(); + const auto& foundBC = collision.foundBC_as>(); + const auto& mcBC = mcCollision.bc_as>(); + + // Check that the BC in data and MC is the same + if (discardMismatchedBCs.value && recoBC.globalBC() != mcBC.globalBC()) { + return; + } + histos.fill(HIST("collisions/reconstructed"), 6); + if (discardMismatchedFoundBCs.value && foundBC.globalBC() != mcBC.globalBC()) { + return; + } + histos.fill(HIST("collisions/reconstructed"), 7); + + const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); + + if (selectInelGt0.value && !o2::pwglf::isINELgt0mc(particlesInCollision, pdgDB)) { + return; + } + histos.fill(HIST("collisions/reconstructed"), 8); + + if (std::abs(collision.posZ()) > posZCut.value) { + return; + } + histos.fill(HIST("collisions/reconstructed"), 9); + if (collisionTimeResCut.value > 0.f && collision.collisionTimeRes() > collisionTimeResCut.value) { + return; + } + histos.fill(HIST("collisions/reconstructed"), 10); + if (requirekIsGoodZvtxFT0vsPV.value && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; + } + histos.fill(HIST("collisions/reconstructed"), 11); + + if (requirekIsVertexITSTPC.value && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) { + return; + } + histos.fill(HIST("collisions/reconstructed"), 12); + + if (requirekIsVertexTOFmatched.value && !collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { + return; + } + histos.fill(HIST("collisions/reconstructed"), 13); + + if (requirekIsVertexTRDmatched.value && !collision.selection_bit(aod::evsel::kIsVertexTRDmatched)) { + return; + } + histos.fill(HIST("collisions/reconstructed"), 14); + + if (collision.t0ACorrectedValid()) { + histos.fill(HIST("collisions/Reco/FT0A"), collision.t0ACorrected()); + } + if (collision.t0CCorrectedValid()) { + histos.fill(HIST("collisions/Reco/FT0C"), collision.t0CCorrected()); + } + if (collision.t0ACValid()) { + histos.fill(HIST("collisions/Reco/FT0AC"), collision.t0AC()); + } + + const auto& recoBCid = recoBC.globalBC() % o2::constants::lhc::LHCMaxBunches; + const auto& mcBCid = mcBC.globalBC() % o2::constants::lhc::LHCMaxBunches; + const auto& foundBCid = foundBC.globalBC() % o2::constants::lhc::LHCMaxBunches; + const int diffRecoFoundBC = foundBC.globalBC() - recoBC.globalBC(); + const int diffRecoMCBC = recoBC.globalBC() - mcBC.globalBC(); + const int diffFoundMCBC = foundBC.globalBC() - mcBC.globalBC(); + histos.fill(HIST("collisions/Reco/BCvsMCBC"), recoBCid, mcBCid); + histos.fill(HIST("collisions/Reco/FoundBCvsMCBC"), foundBCid, mcBCid); + histos.fill(HIST("collisions/Reco/FoundBCvsBC"), foundBCid, recoBCid); + histos.fill(HIST("collisions/Reco/bcMinusfoundBc"), (diffRecoFoundBC)*o2::constants::lhc::LHCBunchSpacingNS); + histos.fill(HIST("collisions/Reco/bcMinusfoundBcRatio"), (diffRecoFoundBC)*o2::constants::lhc::LHCBunchSpacingNS / collision.collisionTimeRes()); + histos.fill(HIST("collisions/Reco/foundbcMinusMcBcRatio"), (diffFoundMCBC)*o2::constants::lhc::LHCBunchSpacingNS / collision.collisionTimeRes()); + histos.fill(HIST("collisions/Reco/bcMinusMcBcRatio"), (diffRecoMCBC)*o2::constants::lhc::LHCBunchSpacingNS / collision.collisionTimeRes()); + + int particlesFromColl = 0; + int particlesFromCollWrongBC = 0; + for (const auto& track : tracks) { + if (!track.isPVContributor()) { + continue; + } + if (!track.has_mcParticle()) { + continue; + } + const auto& mcParticle = track.mcParticle(); + if (mcParticle.mcCollision().bc_as>().globalBC() == mcBC.globalBC()) { + particlesFromColl++; + } else { + particlesFromCollWrongBC++; + } + } + histos.fill(HIST("collisions/Reco/collisionTime"), collision.collisionTime()); + histos.fill(HIST("collisions/Reco/collisionTimeRes"), collision.collisionTimeRes()); + histos.fill(HIST("particles/FromCollVsFromMCColl"), particlesFromColl, particlesInCollision.size()); + histos.fill(HIST("particles/FromCollVsFromMCCollBad"), particlesFromCollWrongBC, particlesInCollision.size()); + histos.fill(HIST("particles/FromCollVsFromCollBad"), particlesFromColl, particlesFromCollWrongBC); + histos.fill(HIST("particles/FromCollBadOverFromCollVsVsFromMCColl"), 1.f * particlesFromCollWrongBC / particlesFromColl, particlesInCollision.size()); + + const std::array& nMult = genMult(particlesInCollision); + + float nMultReco[Estimators::nEstimators]; + nMultReco[Estimators::FT0A] = collision.multFT0A(); + nMultReco[Estimators::FT0C] = collision.multFT0C(); + nMultReco[Estimators::FT0AC] = collision.multFT0M(); + nMultReco[Estimators::FV0A] = collision.multFV0A(); + nMultReco[Estimators::FDDA] = collision.multFDDA(); + nMultReco[Estimators::FDDC] = collision.multFDDC(); + nMultReco[Estimators::FDDAC] = collision.multFDDM(); + nMultReco[Estimators::ZNA] = collision.multZNA(); + nMultReco[Estimators::ZNC] = collision.multZNC(); + nMultReco[Estimators::ITSIB] = collision.multNTracksPV(); + + float nMultRecoMCBC[Estimators::nEstimators] = {0}; + if (mcBC.has_ft0()) { + const auto& ft0 = mcBC.ft0(); + for (auto amplitude : ft0.amplitudeA()) { + nMultRecoMCBC[Estimators::FT0A] += amplitude; + } + for (auto amplitude : ft0.amplitudeC()) { + nMultRecoMCBC[Estimators::FT0C] += amplitude; + } + nMultRecoMCBC[Estimators::FT0AC] = nMultRecoMCBC[Estimators::FT0A] + nMultRecoMCBC[Estimators::FT0C]; + } else { + nMultRecoMCBC[Estimators::FT0A] = -999.f; + nMultRecoMCBC[Estimators::FT0C] = -999.f; + } + + for (int i = 0; i < Estimators::nEstimators; i++) { + if (!enabledEstimatorsArray[i]) { + continue; + } + hestimatorsRecoEvGenVsReco[i]->Fill(nMult[i], nMultReco[i]); + hestimatorsRecoEvGenVsReco_BCMC[i]->Fill(nMult[i], nMultRecoMCBC[i]); + hestimatorsRecoEvGenVsRecoITS[i]->Fill(nMult[i], nMultReco[Estimators::ITSIB]); + hestimatorsRecoEvRecoVsITS[i]->Fill(nMultReco[i], nMult[Estimators::ITSIB]); + hestimatorsRecoEvRecoVsRecoITS[i]->Fill(nMultReco[i], nMultReco[Estimators::ITSIB]); + hestimatorsRecoEvRecoVsRecoITS_BCMC[i]->Fill(nMultRecoMCBC[i], nMultReco[Estimators::ITSIB]); + hestimatorsRecoEvRecoVsFT0A[i]->Fill(nMultReco[i], nMult[Estimators::FT0A]); + hestimatorsRecoEvRecoVsBCId[i]->Fill(foundBCid, nMult[i]); + hestimatorsRecoEvVsBCId[i]->Fill(foundBCid, nMultReco[i]); + } + } + PROCESS_SWITCH(mcParticlePrediction, processReco, "Process the reco info", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/QC/mcSignalLoss.cxx b/PWGLF/Tasks/QC/mcSignalLoss.cxx new file mode 100644 index 00000000000..aefb6c98c1b --- /dev/null +++ b/PWGLF/Tasks/QC/mcSignalLoss.cxx @@ -0,0 +1,151 @@ +// 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. +// +// Compute signal loss for pions, protons, kaons, k0s, lambdas + +// 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. +// +// Build hypertriton candidates from V0s and tracks + +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "Common/Core/PID/PIDTOF.h" +#include "Common/TableProducer/PID/pidTOFBase.h" +#include "Framework/HistogramRegistry.h" +#include "Common/Core/PID/TPCPIDResponse.h" +#include "Common/DataModel/PIDResponse.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "PWGLF/Utils/inelGt.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; +using CollisionsFullMC = soa::Join; + +namespace +{ +static const std::vector pdgCodes{211, 321, 2212, 1000010020, 1000020030, 310, 3122, 1010010030}; +} // namespace + +struct mcsignalloss { + ConfigurableAxis ptAxis{"ptAxis", {80., 0.f, 10.f}, "pt axis binning"}; + ConfigurableAxis decLAxis{"decLAxis", {100., 0.f, 50.f}, "decay length binning"}; + ConfigurableAxis zAxis{"zAxis", {100, -20, 20}, "z axis binning"}; + ConfigurableAxis pdgAxis{"pdgAxis", {static_cast(pdgCodes.size()), 0, static_cast(pdgCodes.size())}, "pdg axis binning"}; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + std::vector isRecoCollision; + Service pdgDB; + SliceCache cache; + Preslice perMCCollision = o2::aod::mcparticle::mcCollisionId; + + float calcDecL(const aod::McParticle& mcPart, aod::McParticles const&) + { + // look for the pion daughter and compute the decay length + float decL = -1; + if (mcPart.has_daughters()) { + for (auto& daughter : mcPart.daughters_as()) { + if (std::abs(daughter.pdgCode()) != 211) { + continue; + } + if (daughter.getProcess() == 4) { // TMCProcess::kPDecay + auto posPrimVtx = array{mcPart.vx(), mcPart.vy(), mcPart.vz()}; + auto secVtx = array{daughter.vx(), daughter.vy(), daughter.vz()}; + decL = std::hypot(secVtx[0] - posPrimVtx[0], secVtx[1] - posPrimVtx[1], secVtx[2] - posPrimVtx[2]); + return decL; + } + } + } + return decL; + } + + void init(o2::framework::InitContext&) + { + histos.add("mcGenCollisionVtx", ";#it{z} (cm)", HistType::kTH1F, {zAxis}); + histos.add("recCollisionVtx", ";#it{z} (cm)", HistType::kTH1F, {zAxis}); + histos.add("mcGenAll", ";#it{p_{T}(GeV/#it{c}); pdg", HistType::kTH2F, {ptAxis, pdgAxis}); + histos.add("mcGenAllRecoColl", ";#it{p_{T}(GeV/#it{c}); pdg", HistType::kTH2F, {ptAxis, pdgAxis}); + histos.add("mcGenV0s", ";#it{p_{T}(GeV/#it{c}); Decay Length (cm); pdg", HistType::kTH3F, {ptAxis, decLAxis, pdgAxis}); + histos.add("mcGenV0sRecoColl", ";#it{p_{T}(GeV/#it{c}); Decay Length (cm); pdg", HistType::kTH3F, {ptAxis, decLAxis, pdgAxis}); + }; + + void process(CollisionsFullMC const& collisions, aod::McCollisions const& mcCollisions, aod::McParticles const& particlesMC) + { + isRecoCollision.clear(); + isRecoCollision.resize(mcCollisions.size(), false); + + for (const auto& collision : collisions) { + + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || std::abs(collision.posZ()) > 10) + continue; + + histos.fill(HIST("recCollisionVtx"), collision.posZ()); + + if (collision.has_mcCollision()) { + isRecoCollision[collision.mcCollisionId()] = true; + } + } + + for (const auto& mcCollision : mcCollisions) { + auto mcParticles_per_coll = particlesMC.sliceBy(perMCCollision, mcCollision.globalIndex()); + if (!pwglf::isINELgtNmc(mcParticles_per_coll, 0, pdgDB)) { + continue; + } + + histos.fill(HIST("mcGenCollisionVtx"), mcCollision.posZ()); + for (const auto& mcPart : mcParticles_per_coll) { + if (!mcPart.isPhysicalPrimary() || mcPart.mcCollisionId() < 0) { + continue; + } + for (unsigned int i = 0; i < pdgCodes.size(); i++) { + if (std::abs(mcPart.pdgCode()) == pdgCodes[i]) { + bool fillV0s = i > 4; + histos.fill(HIST("mcGenAll"), mcPart.pt(), i); + if (fillV0s) { + histos.fill(HIST("mcGenV0s"), mcPart.pt(), calcDecL(mcPart, particlesMC), i); + } + if (isRecoCollision[mcPart.mcCollisionId()]) { + histos.fill(HIST("mcGenAllRecoColl"), mcPart.pt(), i); + if (fillV0s) { + histos.fill(HIST("mcGenV0sRecoColl"), mcPart.pt(), calcDecL(mcPart, particlesMC), i); + } + } + } + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/QC/mcinelgt0.cxx b/PWGLF/Tasks/QC/mcinelgt0.cxx new file mode 100644 index 00000000000..40acd66a67f --- /dev/null +++ b/PWGLF/Tasks/QC/mcinelgt0.cxx @@ -0,0 +1,65 @@ +// 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. + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "PWGLF/Utils/inelGt.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct mcInelGt0 { + HistogramRegistry registry{"registry"}; + + void init(InitContext const&) + { + registry.add("selected", "selected", HistType::kTH1D, {{10, 0, 10}}); + registry.add("ITScontributors", "ITScontributors", HistType::kTH2D, {{10, 0, 10}, {10, 0, 10}}); + } + + Service pdgDB; + SliceCache cache; + Preslice perCollision = o2::aod::track::collisionId; + void process(o2::aod::McCollision const& /*collisionMC*/, + o2::soa::SmallGroups> const& collisions, + const soa::Join& tracks, + o2::aod::McParticles const& mcParticles) + { + if (pwglf::isINELgtNmc(mcParticles, 0, pdgDB)) { + registry.fill(HIST("selected"), 0.5); + } + if (pwglf::isINELgtNmc(mcParticles, 1, pdgDB)) { + registry.fill(HIST("selected"), 1.5); + } + for (auto const& collision : collisions) { + const auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex()); + for (auto const& track : groupedTracks) { + if (!track.isPVContributor()) { + continue; + } + if (std::abs(track.eta()) > 1) { + LOG(info) << "Track with eta > 1: " << track.eta() + << (track.hasTPC() + ? "hasTPC" + : "no TPC ") + << (track.hasITS() + ? "hasITS" + : "no ITS"); + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/QC/strangederivedqa.cxx b/PWGLF/Tasks/QC/strangederivedqa.cxx new file mode 100644 index 00000000000..2e709e07338 --- /dev/null +++ b/PWGLF/Tasks/QC/strangederivedqa.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. +// +// V0 analysis task +// ================ +// +// This code does basic QA of strangeness derived data + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace std; +using std::array; + +struct strangederivedqa { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + ConfigurableAxis axisNCollisions{"axisNCollisions", {50000, -0.5f, 49999.5f}, "collisions"}; + ConfigurableAxis axisNV0s{"axisNV0s", {50000, -0.5f, 49999.5f}, "V0s"}; + + Configurable verbose{"verbose", false, "do more printouts"}; + + void init(InitContext const&) + { + auto h = histos.add("hDFCounter", "hDFCounter", kTH1D, {{6, -0.5f, 5.5f}}); + h->GetXaxis()->SetBinLabel(1, "All"); + h->GetXaxis()->SetBinLabel(2, "Ordered"); + h->GetXaxis()->SetBinLabel(3, "Unordered"); + + auto h2 = histos.add("hEventCounter", "hEventCounter", kTH2D, {{1, -0.5f, 0.5f}, {3, -0.5f, 2.5f}}); + auto h3 = histos.add("hEventsPerDF", "hEventsPerDF", kTH2D, {axisNCollisions, {3, -0.5f, 2.5f}}); + auto h4 = histos.add("hV0sPerDF", "hV0sPerDF", kTH2D, {axisNV0s, {3, -0.5f, 2.5f}}); + + h2->GetYaxis()->SetBinLabel(1, "All"); + h2->GetYaxis()->SetBinLabel(2, "Ordered"); + h2->GetYaxis()->SetBinLabel(3, "Unordered"); + h3->GetYaxis()->SetBinLabel(1, "All"); + h3->GetYaxis()->SetBinLabel(2, "Ordered"); + h3->GetYaxis()->SetBinLabel(3, "Unordered"); + h4->GetYaxis()->SetBinLabel(1, "All"); + h4->GetYaxis()->SetBinLabel(2, "Ordered"); + h4->GetYaxis()->SetBinLabel(3, "Unordered"); + } + + // Real data processing + void processOriginal(aod::Collisions const& collisions, aod::Origins const& origins, soa::Join const& fullV0s) + { + histos.fill(HIST("hDFCounter"), 0.0f); + histos.fill(HIST("hEventCounter"), 0.0f, 0.0f, collisions.size()); + histos.fill(HIST("hEventsPerDF"), collisions.size(), 0.0f); + histos.fill(HIST("hV0sPerDF"), fullV0s.size(), 0.0f); + bool ordered = true; + int previousIndex = -100; + for (auto const& v0 : fullV0s) { + if (v0.collisionId() < previousIndex) { + ordered = false; + } + previousIndex = v0.collisionId(); + } + if (ordered) { + histos.fill(HIST("hEventCounter"), 0.0f, 1.0f, collisions.size()); + histos.fill(HIST("hEventsPerDF"), collisions.size(), 1.0f); + histos.fill(HIST("hV0sPerDF"), fullV0s.size(), 1.0f); + + if (verbose) { + auto origin = origins.begin(); + LOGF(info, "Sorted DF ID: %lld collisions: %i V0s: %i", origin.dataframeID(), collisions.size(), fullV0s.size()); + } + } else { + histos.fill(HIST("hEventCounter"), 0.0f, 2.0f, collisions.size()); + histos.fill(HIST("hEventsPerDF"), collisions.size(), 2.0f); + histos.fill(HIST("hV0sPerDF"), fullV0s.size(), 2.0f); + + if (verbose) { + auto origin = origins.begin(); + LOGF(info, "Unsorted DF ID: %lld collisions: %i V0s: %i", origin.dataframeID(), collisions.size(), fullV0s.size()); + } + } + } + + // Real data processing + void processDerived(aod::StraCollisions const& collisions, aod::StraOrigins const& origins, soa::Join const& fullV0s) + { + histos.fill(HIST("hDFCounter"), 0.0f); + histos.fill(HIST("hEventCounter"), 0.0f, 0.0f, collisions.size()); + histos.fill(HIST("hEventsPerDF"), collisions.size(), 0.0f); + histos.fill(HIST("hV0sPerDF"), fullV0s.size(), 0.0f); + bool ordered = true; + int previousIndex = -100; + for (auto const& v0 : fullV0s) { + if (v0.straCollisionId() < previousIndex) { + ordered = false; + } + previousIndex = v0.straCollisionId(); + } + if (ordered) { + histos.fill(HIST("hEventCounter"), 0.0f, 1.0f, collisions.size()); + histos.fill(HIST("hEventsPerDF"), collisions.size(), 1.0f); + histos.fill(HIST("hV0sPerDF"), fullV0s.size(), 1.0f); + + if (verbose) { + auto origin = origins.begin(); + LOGF(info, "Sorted DF ID: %lld collisions: %i V0s: %i Origins size: %i", origin.dataframeID(), collisions.size(), fullV0s.size(), origins.size()); + } + } else { + histos.fill(HIST("hEventCounter"), 0.0f, 2.0f, collisions.size()); + histos.fill(HIST("hEventsPerDF"), collisions.size(), 2.0f); + histos.fill(HIST("hV0sPerDF"), fullV0s.size(), 2.0f); + + if (verbose) { + auto origin = origins.begin(); + LOGF(info, "Unsorted DF ID: %lld collisions: %i V0s: %i Origins size: %i", origin.dataframeID(), collisions.size(), fullV0s.size(), origins.size()); + uint64_t directoryName = origin.dataframeID(); + for (auto const& orig : origins) { + LOGF(info, "Unsorted DF ID: %lld separate origin: %lld", directoryName, orig.dataframeID()); + } + } + } + } + + PROCESS_SWITCH(strangederivedqa, processOriginal, "Process original data", false); + PROCESS_SWITCH(strangederivedqa, processDerived, "Process derived data", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/QC/strangenessTrackingQC.cxx b/PWGLF/Tasks/QC/strangenessTrackingQC.cxx new file mode 100644 index 00000000000..09c5698fd92 --- /dev/null +++ b/PWGLF/Tasks/QC/strangenessTrackingQC.cxx @@ -0,0 +1,311 @@ +// 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. + +#include "CCDB/BasicCCDBManager.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "DCAFitter/DCAFitterN.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +// #include "PWGHF/Core/PDG.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/Track.h" +#include "PWGLF/DataModel/LFNonPromptCascadeTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace +{ + +}; + +struct miniCasc { + bool fillOmega; + float pt; + float eta; + float phi; + float radius; + float massOmega; + float massXi; + float dcaXYCasc; + float dcaXYTracked; +}; + +struct strangenessTrackingQC { + + using TrackCandidates = soa::Join; + using CollisionCandidates = soa::Join; + + Configurable setting_materialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrLUT), "Type of material correction"}; + + Configurable cascsetting_dcaCascDaughters{"casc_setting_dcaV0daughters", 0.1f, "DCA between the V0 daughters"}; + Configurable cascsetting_cosPA{"casc_setting_cosPA", 0.995f, "Cosine of the pointing angle of the V0"}; + Configurable cascsetting_massWindowXi{"casc_setting_massWindowXi", 0.01f, "Mass window for the Xi"}; + + Configurable cfgGRPmagPath{"cfgGRPmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable cfgGRPpath{"cfgGRPpath", "GLO/GRP/GRP", "Path of the grp file"}; + + Configurable cfgCutNclusTPC{"cfgCutNclusTPC", 70, "Minimum number of TPC clusters"}; + + ConfigurableAxis ptBins{"ptBins", {200, -10.f, 10.f}, "Binning for #it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis dcaBins{"dcaBins", {1e3, -0.1, 0.1}, "Binning for DCA (cm)"}; + ConfigurableAxis decayRadBins{"decayRadBins", {100, 0.f, 40.f}, "Binning for decay radius (cm)"}; + ConfigurableAxis omegaMassBins{"omegaMassBins", {125, 1.650, 1.700}, "Invariant mass (GeV/#it{c}^{2})"}; + ConfigurableAxis xiMassBins{"xiMassBins", {125, 1.296, 1.346}, "Invariant mass (GeV/#it{c}^{2})"}; + + Service ccdb; + int mRunNumber = 0; + float bz = 0.f; + o2::vertexing::DCAFitterN<2> m_fitter; + + HistogramRegistry registry{ + "registry", + { + {"omegaMass", "; Mass (GeV/#it{c}^{2}); Counts", {HistType::kTH1F, {{125, 1.650, 1.700}}}}, + {"xiMass", "; Mass (GeV/#it{c}^{2}); Counts", {HistType::kTH1F, {{125, 1.296, 1.346}}}}, + {"omegaMassTracked", "; Mass (GeV/#it{c}^{2}); Counts", {HistType::kTH1F, {{125, 1.650, 1.700}}}}, + {"xiMassTracked", "; Mass (GeV/#it{c}^{2}); Counts", {HistType::kTH1F, {{125, 1.296, 1.346}}}}, + + {"omegaHist", "; #it{p}_{T} (GeV/#it{c}); Radius (cm); Mass", {HistType::kTH3F, {{ptBins, decayRadBins, omegaMassBins}}}}, + {"xiHist", "; #it{p}_{T} (GeV/#it{c}); Radius (cm); Mass", {HistType::kTH3F, {{ptBins, decayRadBins, xiMassBins}}}}, + {"xiHistTracked", "; #it{p}_{T} (GeV/#it{c}); Radius (cm); Mass", {HistType::kTH3F, {{ptBins, decayRadBins, xiMassBins}}}}, + {"omegaHistTracked", "; #it{p}_{T} (GeV/#it{c}); Radius (cm); Mass", {HistType::kTH3F, {{ptBins, decayRadBins, omegaMassBins}}}}, + + {"xiDCAvsPt", "; #it{p}_{T} (GeV/#it{c}); DCA (cm)", {HistType::kTH2F, {{ptBins, dcaBins}}}}, + {"omegaDCAvsPt", "; #it{p}_{T} (GeV/#it{c}); DCA (cm)", {HistType::kTH2F, {{ptBins, dcaBins}}}}, + {"xiDCAvsPtTracked", "; #it{p}_{T} (GeV/#it{c}); DCA (cm)", {HistType::kTH2F, {{ptBins, dcaBins}}}}, + {"omegaDCAvsPtTracked", "; #it{p}_{T} (GeV/#it{c}); DCA (cm)", {HistType::kTH2F, {{ptBins, dcaBins}}}}, + }}; + + template + float dcaToPV(o2::dataformats::VertexBase& PV, T& trackParCov) + { + auto matCorr = static_cast(setting_materialCorrection.value); + o2::dataformats::DCA impactParameterTrk; + o2::base::Propagator::Instance()->propagateToDCA(PV, trackParCov, bz, 2.f, matCorr, &impactParameterTrk); + return impactParameterTrk.getY(); + } + + template + bool qualityTrackSelection(const T& track) + { + if (std::abs(track.eta()) > 0.9) { + return false; + } + if (track.tpcNClsFound() < cfgCutNclusTPC) { + return false; + } + return true; + } + + float computeMassMother(const float massA, const float massB, const std::array& momA, const std::array& momB) const + { + float eA = std::hypot(massA, std::hypot(momA[0], momA[1], momA[2])); + float eB = std::hypot(massB, std::hypot(momB[0], momB[1], momB[2])); + float momTot = std::hypot(momA[0] + momB[0], momA[1] + momB[1], momA[2] + momB[2]); + float eMother = eA + eB; + return std::sqrt(eMother * eMother - momTot * momTot); + } + + template + bool buildCascade(TCasc const& casc, CollisionCandidates::iterator const& collision, aod::V0s const&, TrackCandidates const&, miniCasc& miniCasc) + { + const auto& v0 = casc.template v0_as(); + const auto& bachelor = casc.template bachelor_as(); + const auto& ptrack = v0.template posTrack_as(); + const auto& ntrack = v0.template negTrack_as(); + if (!qualityTrackSelection(ptrack) || !qualityTrackSelection(ntrack) || !qualityTrackSelection(bachelor)) { + return false; + } + const auto& protonTrack = bachelor.sign() > 0 ? ntrack : ptrack; + const auto& pionTrack = bachelor.sign() > 0 ? ptrack : ntrack; + if (std::abs(protonTrack.tpcNSigmaPr()) > 3 || std::abs(pionTrack.tpcNSigmaPi()) > 3) { + return false; + } + auto primaryVertex = getPrimaryVertex(collision); + std::array pvPos = {primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}; + + float cascCpa = -1; + float cascDauDCA = -1; + + std::array cascMom; + std::array v0Mom; + std::array bachelorMom; + + // track propagation + o2::track::TrackParCov trackParCovV0; + o2::track::TrackPar trackParV0; + o2::track::TrackPar trackParBachelor; + o2::track::TrackParCov trackParCovCasc; + if (m_fitter.process(getTrackParCov(pionTrack), getTrackParCov(protonTrack))) { + trackParCovV0 = m_fitter.createParentTrackParCov(0); // V0 track retrieved from p and pi daughters + if (m_fitter.process(trackParCovV0, getTrackParCov(bachelor))) { + trackParV0 = m_fitter.getTrackParamAtPCA(0); + trackParBachelor = m_fitter.getTrackParamAtPCA(1); + trackParV0.getPxPyPzGlo(v0Mom); + trackParBachelor.getPxPyPzGlo(bachelorMom); + trackParCovCasc = m_fitter.createParentTrackParCov(); + trackParCovCasc.getPxPyPzGlo(cascMom); + cascCpa = RecoDecay::cpa(pvPos, m_fitter.getPCACandidate(), cascMom); + cascDauDCA = std::sqrt(std::abs(m_fitter.getChi2AtPCACandidate())); + } else { + return false; + } + } else { + return false; + } + + if (cascCpa < cascsetting_cosPA) { + return false; + } + + if (cascDauDCA > cascsetting_dcaCascDaughters) { + return false; + } + + int chargeFactor = bachelor.sign() > 0 ? 1 : -1; + miniCasc.pt = chargeFactor * std::hypot(cascMom[0], cascMom[1]); + miniCasc.massOmega = computeMassMother(constants::physics::MassLambda0, constants::physics::MassKaonCharged, v0Mom, bachelorMom); + miniCasc.massXi = computeMassMother(constants::physics::MassLambda0, constants::physics::MassPionCharged, v0Mom, bachelorMom); + miniCasc.fillOmega = false; + if (TMath::Abs(miniCasc.massXi - constants::physics::MassXiMinus) > cascsetting_massWindowXi && std::abs(bachelor.tpcNSigmaKa()) < 3) { + miniCasc.fillOmega = true; + } + + miniCasc.dcaXYCasc = dcaToPV(primaryVertex, trackParCovCasc); + auto svPos = m_fitter.getPCACandidate(); + miniCasc.radius = std::hypot(svPos[0], svPos[1]); + + return true; + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + auto timestamp = bc.timestamp(); + + if (o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(cfgGRPpath, timestamp)) { + o2::base::Propagator::initFieldFromGRP(grpo); + bz = grpo->getNominalL3Field(); + } else if (o2::parameters::GRPMagField* grpmag = ccdb->getForTimeStamp(cfgGRPmagPath, timestamp)) { + o2::base::Propagator::initFieldFromGRP(grpmag); + bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(debug) << "bz = " << bz; + } else { + LOG(fatal) << "Got nullptr from CCDB for path " << cfgGRPmagPath << " of object GRPMagField and " << cfgGRPpath << " of object GRPObject for timestamp " << timestamp; + } + } + + void init(InitContext const&) + { + mRunNumber = 0; + bz = 0; + + if (static_cast(setting_materialCorrection.value) == o2::base::Propagator::MatCorrType::USEMatCorrLUT) { + auto* lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get("GLO/Param/MatLUT")); + LOG(info) << "Setting material correction LUT"; + o2::base::Propagator::Instance(true)->setMatLUT(lut); + } + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + m_fitter.setPropagateToPCA(true); + m_fitter.setMaxR(200.); + m_fitter.setMinParamChange(1e-3); + m_fitter.setMinRelChi2Change(0.9); + m_fitter.setMaxDZIni(4); + m_fitter.setMaxDXYIni(4); + m_fitter.setMaxChi2(1e9); + m_fitter.setUseAbsDCA(true); + m_fitter.setWeightedFinalPCA(false); + // int mat{static_cast(setting_materialCorrection)}; + // m_fitter.setMatCorrType(static_cast(mat)); + } + + void process(CollisionCandidates const&, aod::AssignedTrackedCascades const& trackedCascades, aod::Cascades const& cascades, aod::V0s const& v0s, TrackCandidates const& tracks, aod::BCsWithTimestamps const&) + { + + for (const auto& trackedCascade : trackedCascades) { + miniCasc miniCasc; + const auto& casc = trackedCascade.cascade(); + auto collision = trackedCascade.collision_as(); + if (!collision.sel8() || std::abs(collision.posZ()) > 10) { + continue; + } + initCCDB(collision.bc_as()); + m_fitter.setBz(bz); + if (buildCascade(casc, collision, v0s, tracks, miniCasc)) { + + // compute the dca of the tracked cascade + const auto& track = trackedCascade.track_as(); + auto trackCovTrk = getTrackParCov(track); + + auto primaryVertex = getPrimaryVertex(collision); + miniCasc.dcaXYTracked = dcaToPV(primaryVertex, trackCovTrk); + // fill the histograms + if (miniCasc.fillOmega) { + registry.fill(HIST("omegaMassTracked"), miniCasc.massOmega); + registry.fill(HIST("omegaDCAvsPtTracked"), miniCasc.pt, miniCasc.dcaXYTracked); + registry.fill(HIST("omegaHistTracked"), miniCasc.pt, miniCasc.radius, miniCasc.massOmega); + } + registry.fill(HIST("xiMassTracked"), miniCasc.massXi); + registry.fill(HIST("xiDCAvsPtTracked"), miniCasc.pt, miniCasc.dcaXYTracked); + registry.fill(HIST("xiHistTracked"), miniCasc.pt, miniCasc.radius, miniCasc.massXi); + } + } + + for (auto& cascade : cascades) { + miniCasc miniCasc; + auto collision = cascade.collision_as(); + if (!collision.sel8() || std::abs(collision.posZ()) > 10) { + continue; + } + initCCDB(collision.bc_as()); + m_fitter.setBz(bz); + if (buildCascade(cascade, collision, v0s, tracks, miniCasc)) { + if (miniCasc.fillOmega) { + registry.fill(HIST("omegaMass"), miniCasc.massOmega); + registry.fill(HIST("omegaDCAvsPt"), miniCasc.pt, miniCasc.dcaXYCasc); + registry.fill(HIST("omegaHist"), miniCasc.pt, miniCasc.radius, miniCasc.massOmega); + } + registry.fill(HIST("xiMass"), miniCasc.massXi); + registry.fill(HIST("xiDCAvsPt"), miniCasc.pt, miniCasc.dcaXYCasc); + registry.fill(HIST("xiHist"), miniCasc.pt, miniCasc.radius, miniCasc.massXi); + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/QC/strderivedGenQA.cxx b/PWGLF/Tasks/QC/strderivedGenQA.cxx new file mode 100644 index 00000000000..7e232b1dd97 --- /dev/null +++ b/PWGLF/Tasks/QC/strderivedGenQA.cxx @@ -0,0 +1,1209 @@ +// 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. +// +// This code does basic QA of strangeness derived data +// *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* +// Strange Derived Generation QA +// *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* +// +// Comments, questions, complaints, suggestions? +// Please write to: +// gianni.shigeru.setoue.liveraro@cern.ch +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/trackUtilities.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessMLTables.h" +#include "CCDB/BasicCCDBManager.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace std; +using std::array; +using dauTracks = soa::Join; +using StrCollisionsDatas = soa::Join; +using V0DerivedDatas = soa::Join; +using V0DerivedMCDatas = soa::Join; +using CascDerivedMCDatas = soa::Join; +using CascDerivedDatas = soa::Join; + +struct strderivedGenQA { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // pack track quality but separte also afterburner + // dynamic range: 0-31 + enum selection : int { hasTPC = 0, + hasITSTracker, + hasITSAfterburner, + hasTRD, + hasTOF }; + + Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; + + struct : ConfigurableGroup { + Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; + Configurable requireTriggerTVX{"requireTriggerTVX", true, "require FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level"}; + Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border"}; + Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "require events with at least one ITS-TPC track"}; + Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "require events with PV position along z consistent (within 1 cm) between PV reconstructed using tracks and PV using FT0 A-C time difference"}; + Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", false, "require events with at least one of vertex contributors matched to TOF"}; + Configurable requireIsVertexTRDmatched{"requireIsVertexTRDmatched", false, "require events with at least one of vertex contributors matched to TRD"}; + Configurable rejectSameBunchPileup{"rejectSameBunchPileup", true, "reject collisions in case of pileup with another collision in the same foundBC"}; + Configurable requireNoCollInTimeRangeStd{"requireNoCollInTimeRangeStd", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds"}; + Configurable requireNoCollInTimeRangeStrict{"requireNoCollInTimeRangeStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds"}; + Configurable requireNoCollInTimeRangeNarrow{"requireNoCollInTimeRangeNarrow", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds"}; + Configurable requireNoCollInROFStd{"requireNoCollInROFStd", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF with mult. above a certain threshold"}; + Configurable requireNoCollInROFStrict{"requireNoCollInROFStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF"}; + Configurable requireINEL0{"requireINEL0", true, "require INEL>0 event selection"}; + Configurable requireINEL1{"requireINEL1", false, "require INEL>1 event selection"}; + + Configurable maxZVtxPosition{"maxZVtxPosition", 10., "max Z vtx position"}; + + Configurable useFT0CbasedOccupancy{"useFT0CbasedOccupancy", false, "Use sum of FT0-C amplitudes for estimating occupancy? (if not, use track-based definition)"}; + // fast check on occupancy + Configurable minOccupancy{"minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; + Configurable maxOccupancy{"maxOccupancy", -1, "maximum occupancy from neighbouring collisions"}; + } eventSelections; + + struct : ConfigurableGroup { + Configurable v0TypeSelection{"v0TypeSelection", 1, "select on a certain V0 type (leave negative if no selection desired)"}; + + // Selection criteria: acceptance + Configurable rapidityCut{"rapidityCut", 0.5, "rapidity"}; + Configurable daughterEtaCut{"daughterEtaCut", 0.8, "max eta for daughters"}; + + // Standard 5 topological criteria + Configurable v0cospa{"v0cospa", 0.97, "min V0 CosPA"}; + Configurable dcav0dau{"dcav0dau", 1.0, "max DCA V0 Daughters (cm)"}; + Configurable dcanegtopv{"dcanegtopv", .05, "min DCA Neg To PV (cm)"}; + Configurable dcapostopv{"dcapostopv", .05, "min DCA Pos To PV (cm)"}; + Configurable v0radius{"v0radius", 1.2, "minimum V0 radius (cm)"}; + Configurable v0radiusMax{"v0radiusMax", 1E5, "maximum V0 radius (cm)"}; + + // Additional selection on the AP plot (exclusive for K0Short) + // original equation: lArmPt*5>TMath::Abs(lArmAlpha) + Configurable armPodCut{"armPodCut", 5.0f, "pT * (cut) > |alpha|, AP cut. Negative: no cut"}; + + // Track quality + Configurable minTPCrows{"minTPCrows", 70, "minimum TPC crossed rows"}; + Configurable minITSclusters{"minITSclusters", -1, "minimum ITS clusters"}; + Configurable skipTPConly{"skipTPConly", false, "skip V0s comprised of at least one TPC only prong"}; + Configurable requirePosITSonly{"requirePosITSonly", false, "require that positive track is ITSonly (overrides TPC quality)"}; + Configurable requireNegITSonly{"requireNegITSonly", false, "require that negative track is ITSonly (overrides TPC quality)"}; + Configurable rejectPosITSafterburner{"rejectPosITSafterburner", false, "reject positive track formed out of afterburner ITS tracks"}; + Configurable rejectNegITSafterburner{"rejectNegITSafterburner", false, "reject negative track formed out of afterburner ITS tracks"}; + + // PID (TPC/TOF) + Configurable TpcPidNsigmaCut{"TpcPidNsigmaCut", 5, "TpcPidNsigmaCut"}; + Configurable TofPidNsigmaCutLaPr{"TofPidNsigmaCutLaPr", 1e+6, "TofPidNsigmaCutLaPr"}; + Configurable TofPidNsigmaCutLaPi{"TofPidNsigmaCutLaPi", 1e+6, "TofPidNsigmaCutLaPi"}; + Configurable TofPidNsigmaCutK0Pi{"TofPidNsigmaCutK0Pi", 1e+6, "TofPidNsigmaCutK0Pi"}; + + // PID (TOF) + Configurable maxDeltaTimeProton{"maxDeltaTimeProton", 1e+9, "check maximum allowed time"}; + Configurable maxDeltaTimePion{"maxDeltaTimePion", 1e+9, "check maximum allowed time"}; + } v0Selections; + + // Axis declarations + ConfigurableAxis axisPosZ{"axisPosZ", {100, -50.0f, 50.0f}, "Z Position"}; + ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Centrality"}; + + // Boolean axes + ConfigurableAxis axisBool{"axisBool", {2, 0.0f, 2.0f}, "axisBool"}; + ConfigurableAxis axisFt0cOccupancyInTimeRange{"axisFt0cOccupancyInTimeRange", {50, 0, 80000}, "FT0C occupancy"}; + ConfigurableAxis axisTrackOccupancyInTimeRange{"axisTrackOccupancyInTimeRange", {50, 0, 5000}, "Track occupancy"}; + ConfigurableAxis axisMultFT0C{"axisMultFT0C", {1000, 0, 100000}, "FT0C amplitude"}; + ConfigurableAxis axisMultNTracksPVeta1{"axisMultNTracksPVeta1", {200, 0, 6000}, "Mult NTracks PV eta 1"}; + ConfigurableAxis axisMultPVTotalContributors{"axisMultPVTotalContributors", {200, 0, 6000}, "Number of PV Contributors"}; + ConfigurableAxis axisMultAllTracksTPCOnly{"axisMultAllTracksTPCOnly", {200, 0, 6000}, "Mult All Tracks TPC Only"}; + ConfigurableAxis axisMultAllTracksITSTPC{"axisMultAllTracksITSTPC", {200, 0, 6000}, "Mult All Tracks ITS TPC"}; + ConfigurableAxis axisNch{"axisNch", {500, 0.0f, +5000.0f}, "Number of charged particles"}; + ConfigurableAxis axisNumV0sPerColl{"axisNumV0sPerColl", {50000, -0.5f, 49999.5f}, "Num V0s Per Coll"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "Pt Axis"}; + ConfigurableAxis axisPt2{"axisPt2", {VARIABLE_WIDTH, -50.0f, -40.0f, -35.0f, -30.0f, -25.0f, -23.0f, -21.0f, -19.0f, -17.0f, -15.0f, -14.0f, -13.0f, -12.0f, -11.0f, -10.0f, -9.0f, -8.0f, -7.5f, -7.0f, -6.5f, -6.0f, -5.6f, -5.2f, -4.8f, -4.4f, -4.0f, -3.8f, -3.6f, -3.4f, -3.2f, -3.0f, -2.8f, -2.6f, -2.4f, -2.2f, -2.0f, -1.9f, -1.8f, -1.7f, -1.6f, -1.5f, -1.4f, -1.3f, -1.2f, -1.1f, -1.0f, -0.9f, -0.8f, -0.7f, -0.6f, -0.5f, -0.4f, -0.3f, -0.2f, -0.1f, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "Pt Axis"}; + ConfigurableAxis axisAlpha{"axisAlpha", {220, -1.1f, 1.1f}, "Alpha"}; + ConfigurableAxis axisQtarm{"axisQtarm", {220, 0.0f, 0.5f}, "Qtarm"}; + ConfigurableAxis axisCosPA{"axisCosPA", {240, 0.0f, 1.2f}, "CosPA"}; + ConfigurableAxis axisDCAdau{"axisDCAdau", {50, 0.0f, 5.0f}, "DCA V0 Daughters"}; + ConfigurableAxis axisEta{"axisEta", {100, -3.0f, 3.0f}, "Eta"}; + ConfigurableAxis axisPhi{"axisPhi", {100, 0.0f, TMath::TwoPi()}, "Phi"}; + ConfigurableAxis axisMassGamma{"axisMassGamma", {400, 0.0f, 0.5f}, "Mass Gamma"}; + ConfigurableAxis axisMassLambda{"axisMassLambda", {400, 1.0f, 1.2f}, "Mass Lambda"}; + ConfigurableAxis axisMassK0Short{"axisMassK0Short", {400, 0.4f, 0.6f}, "Mass K0Short"}; + ConfigurableAxis axisV0Type{"axisV0Type", {5, 0.0f, 5.0f}, "V0 Type"}; + ConfigurableAxis axisStraCollisionId{"axisStraCollisionId", {4000, 0.0f, 40000.0f}, "Stra Collision Id"}; + ConfigurableAxis axisGlobalIndex{"axisGlobalIndex", {4000, 0.0f, 40000.0f}, "Global Index"}; + ConfigurableAxis axisNCls{"axisNCls", {8, -0.5, 7.5}, "NCls"}; + ConfigurableAxis axisTPCrows{"axisTPCrows", {160, 0.0f, 160.0f}, "N TPC rows"}; + ConfigurableAxis axisChi2PerNcl{"axisChi2PerNcl", {100, 0, 40}, "Chi2 Per Ncl"}; + ConfigurableAxis axisTPCNSigma{"axisTPCNSigma", {100, -50.0f, 50.0f}, "TPC N Sigma"}; + ConfigurableAxis axisTPCSignal{"axisTPCSignal", {400, -100.0, 300.0}, "TPC Signal"}; + ConfigurableAxis axisTOFNSigma{"axisTOFNSigma", {100, -50.0f, 50.0f}, "TOF N Sigma"}; + ConfigurableAxis axisTOFDeltaT{"axisTOFDeltaT", {200, -1000.0f, +1000.0f}, "TOF Delta T"}; + ConfigurableAxis axisPtResolution{"axisPtResolution", {100, -1.0f, 1.0f}, "Pt Resolution"}; + ConfigurableAxis axisPDGCode{"axisPDGCode", {10001, -5000.5f, +5000.5f}, "PDG Code"}; + ConfigurableAxis axisV0Radius{"axisV0Radius", {400, 0.0f, 200.0f}, "V0 Radius"}; + ConfigurableAxis axisCascRadius{"axisCascRadius", {500, 0.0f, 50.0f}, "Casc Radius"}; + ConfigurableAxis axisDCAToPV{"axisDCAToPV", {500, -50.0f, 50.0f}, "DCA Dau to PV"}; + ConfigurableAxis axisDCAXYCascToPV{"axisDCAXYCascToPV", {1000, 0.0f, 10.0f}, "DCA XY Casc to PV"}; + ConfigurableAxis axisDCAZCascToPV{"axisDCAZCascToPV", {500, -10.0f, 10.0f}, "DCA Z Casc to PV"}; + ConfigurableAxis axisDCAV0ToPV{"axisDCAV0ToPV", {1000, -10.0f, 10.0f}, "DCA V0 to PV"}; + ConfigurableAxis axisDCAV0Dau{"axisDCAV0Dau", {1000, 0.0f, 10.0f}, "DCA V0 Daughters"}; + ConfigurableAxis axisDCACascDau{"axisDCACascDau", {1000, 0.0f, 10.0f}, "DCA Casc Daughters"}; + ConfigurableAxis axisOmegaMass{"axisOmegaMass", {400, 1.6f, 1.8f}, "Omega Mass"}; + ConfigurableAxis axisXiMass{"axisXiMass", {400, 1.2f, 1.4f}, "Xi Mass"}; + ConfigurableAxis axisTrackProperties{"axisTrackProperties", {32, -0.5, 31.5f}, "Track Properties"}; + + PresliceUnsorted> perMcCollision = aod::v0data::straMCCollisionId; + + void init(InitContext const&) + { + // Histogram declarations (can be improved!) + histos.add("Event/hPosZ", "hPosZ", kTH1F, {axisPosZ}); + + // Event Counters + histos.add("Event/hEventProperties", "hEventProperties", kTH1F, {{20, -0.5f, +18.5f}}); + histos.get(HIST("Event/hEventProperties"))->GetXaxis()->SetBinLabel(1, "All collisions"); + histos.get(HIST("Event/hEventProperties"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + histos.get(HIST("Event/hEventProperties"))->GetXaxis()->SetBinLabel(3, "kIsTriggerTVX"); + histos.get(HIST("Event/hEventProperties"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + histos.get(HIST("Event/hEventProperties"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + histos.get(HIST("Event/hEventProperties"))->GetXaxis()->SetBinLabel(6, "kIsVertexITSTPC"); + histos.get(HIST("Event/hEventProperties"))->GetXaxis()->SetBinLabel(7, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("Event/hEventProperties"))->GetXaxis()->SetBinLabel(8, "kIsVertexTOFmatched"); + histos.get(HIST("Event/hEventProperties"))->GetXaxis()->SetBinLabel(9, "kIsVertexTRDmatched"); + histos.get(HIST("Event/hEventProperties"))->GetXaxis()->SetBinLabel(10, "kNoSameBunchPileup"); + histos.get(HIST("Event/hEventProperties"))->GetXaxis()->SetBinLabel(11, "kNoCollInTimeRangeStd"); + histos.get(HIST("Event/hEventProperties"))->GetXaxis()->SetBinLabel(12, "kNoCollInTimeRangeStrict"); + histos.get(HIST("Event/hEventProperties"))->GetXaxis()->SetBinLabel(13, "kNoCollInTimeRangeNarrow"); + histos.get(HIST("Event/hEventProperties"))->GetXaxis()->SetBinLabel(14, "kNoCollInRofStd"); + histos.get(HIST("Event/hEventProperties"))->GetXaxis()->SetBinLabel(15, "kNoCollInRofStrict"); + + histos.add("Event/hft0cOccupancyInTimeRange", "hft0cOccupancyInTimeRange", kTH1F, {axisFt0cOccupancyInTimeRange}); + histos.add("Event/htrackOccupancyInTimeRange", "htrackOccupancyInTimeRange", kTH1F, {axisTrackOccupancyInTimeRange}); + histos.add("Event/h2dMultFT0C", "h2dMultFT0C", kTH2F, {axisCentrality, axisMultFT0C}); + histos.add("Event/h2dMultNTracksPVeta1", "h2dMultNTracksPVeta1", kTH2F, {axisCentrality, axisMultNTracksPVeta1}); + histos.add("Event/h2dMultPVTotalContributors", "h2dMultPVTotalContributors", kTH2F, {axisCentrality, axisMultPVTotalContributors}); + histos.add("Event/h2dMultAllTracksTPCOnly", "h2dMultAllTracksTPCOnly", kTH2F, {axisCentrality, axisMultAllTracksTPCOnly}); + histos.add("Event/h2dMultAllTracksITSTPC", "h2dMultAllTracksITSTPC", kTH2F, {axisCentrality, axisMultAllTracksITSTPC}); + histos.add("Event/h2dNumV0sPerColl", "h2dNumV0sPerColl", kTH2F, {axisCentrality, axisNumV0sPerColl}); + + histos.add("V0/hpT", "hpT", kTH1F, {axisPt}); + histos.add("V0/h2dArmenterosP", "h2dArmenterosP", kTH2F, {axisAlpha, axisQtarm}); + histos.add("V0/hRadius", "hRadius", kTH1F, {axisV0Radius}); + histos.add("V0/hZ", "hZ", kTH1F, {axisPosZ}); + histos.add("V0/hCosPA", "hCosPA", kTH1F, {axisCosPA}); + histos.add("V0/hdcaDau", "hdcaDau", kTH1F, {axisDCAdau}); + histos.add("V0/hdcaNegtopv", "hdcaNegtopv", kTH1F, {axisDCAToPV}); + histos.add("V0/hdcaPostopv", "hdcaPostopv", kTH1F, {axisDCAToPV}); + histos.add("V0/h2dEtaPhi", "h2dEtaPhi", kTH2F, {axisEta, axisPhi}); + histos.add("V0/hYGamma", "hYGamma", kTH1F, {axisEta}); + histos.add("V0/hYLambda", "hYLambda", kTH1F, {axisEta}); + histos.add("V0/hYK0Short", "hYK0Short", kTH1F, {axisEta}); + histos.add("V0/hMassGamma", "hMassGamma", kTH1F, {axisMassGamma}); + histos.add("V0/hMassLambda", "hMassLambda", kTH1F, {axisMassLambda}); + histos.add("V0/hMassK0Short", "hMassK0Short", kTH1F, {axisMassK0Short}); + histos.add("V0/hV0Type", "hV0Type", kTH1F, {axisV0Type}); + histos.add("V0/h2dV0Indices", "h2dV0Indices", kTH2F, {axisStraCollisionId, axisGlobalIndex}); + + histos.add("V0/Track/h2dITSNCls", "h2dITSNCls", kTH2F, {axisPt2, axisNCls}); + histos.add("V0/Track/h2dITSChi2PerNcl", "h2dITSChi2PerNcl", kTH2F, {axisPt2, axisChi2PerNcl}); + histos.add("V0/Track/h2dTPCCrossedRows", "h2dTPCCrossedRows", kTH2F, {axisPt2, axisTPCrows}); + + histos.add("V0/Track/h2dPosTrackProperties", "h2dPosTrackProperties", kTH2F, {axisTrackProperties, axisPt}); + histos.add("V0/Track/h3dTrackPropertiesVspT", "h3dTrackPropertiesVspT", kTH3F, {axisTrackProperties, axisTrackProperties, axisPt}); + histos.add("V0/Track/h2dNegTrackProperties", "h2dNegTrackProperties", kTH2F, {axisTrackProperties, axisPt}); + + // Add histogram to the list + histos.add("V0/Track/hTrackCode", "hTrackCode", kTH1F, {axisTrackProperties}); + + // Set bin labels for all combinations + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(1, "None"); // Code 0 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(2, "TPC"); // Code 1 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(3, "ITSTracker"); // Code 2 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(4, "ITSTracker + TPC"); // Code 3 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(5, "ITSAfterburner"); // Code 4 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(6, "ITSAfterburner + TPC"); // Code 5 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(7, "ITSAfterburner + ITSTracker"); // Code 6 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(8, "ITSAfterburner + ITSTracker + TPC"); // Code 7 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(9, "TRD"); // Code 8 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(10, "TRD + TPC"); // Code 9 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(11, "TRD + ITSTracker"); // Code 10 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(12, "TRD + ITSTracker + TPC"); // Code 11 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(13, "TRD + ITSAfterburner"); // Code 12 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(14, "TRD + ITSAfterburner + TPC"); // Code 13 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(15, "TRD + ITSAfterburner + ITSTracker"); // Code 14 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(16, "TRD + ITSAfterburner + ITSTracker + TPC"); // Code 15 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(17, "TOF"); // Code 16 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(18, "TOF + TPC"); // Code 17 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(19, "TOF + ITSTracker"); // Code 18 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(20, "TOF + ITSTracker + TPC"); // Code 19 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(21, "TOF + ITSAfterburner"); // Code 20 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(22, "TOF + ITSAfterburner + TPC"); // Code 21 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(23, "TOF + ITSAfterburner + ITSTracker"); // Code 22 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(24, "TOF + ITSAfterburner + ITSTracker + TPC"); // Code 23 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(25, "TOF + TRD"); // Code 24 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(26, "TOF + TRD + TPC"); // Code 25 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(27, "TOF + TRD + ITSTracker"); // Code 26 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(28, "TOF + TRD + ITSTracker + TPC"); // Code 27 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(29, "TOF + TRD + ITSAfterburner"); // Code 28 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(30, "TOF + TRD + ITSAfterburner + TPC"); // Code 29 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(31, "TOF + TRD + ITSAfterburner + ITSTracker"); // Code 30 + histos.get(HIST("V0/Track/hTrackCode"))->GetXaxis()->SetBinLabel(32, "All"); // Code 31 + + histos.add("V0/PID/h2dTPCNSigmaEl", "h2dTPCNSigmaEl", kTH2F, {axisPt2, axisTPCNSigma}); + histos.add("V0/PID/h2dTPCNSigmaPr", "h2dTPCNSigmaPr", kTH2F, {axisPt2, axisTPCNSigma}); + histos.add("V0/PID/h2dTPCNSigmaPi", "h2dTPCNSigmaPi", kTH2F, {axisPt2, axisTPCNSigma}); + histos.add("V0/PID/h2dTPCSignal", "h2dTPCSignal", kTH2F, {axisPt2, axisTPCSignal}); + + histos.add("V0/PID/h2dTOFNSigmaLaPr", "h2dTOFNSigmaLaPr", kTH2F, {axisPt, axisTOFNSigma}); + histos.add("V0/PID/h2dTOFNSigmaLaPi", "h2dTOFNSigmaLaPi", kTH2F, {axisPt, axisTOFNSigma}); + histos.add("V0/PID/h2dposTOFDeltaTLaPr", "h2dposTOFDeltaTLaPr", kTH2F, {axisPt, axisTOFDeltaT}); + histos.add("V0/PID/h2dnegTOFDeltaTLaPi", "h2dnegTOFDeltaTLaPi", kTH2F, {axisPt, axisTOFDeltaT}); + histos.add("V0/PID/h2dnegTOFDeltaTLaPr", "h2dnegTOFDeltaTLaPr", kTH2F, {axisPt, axisTOFDeltaT}); + histos.add("V0/PID/h2dposTOFDeltaTLaPi", "h2dposTOFDeltaTLaPi", kTH2F, {axisPt, axisTOFDeltaT}); + histos.add("V0/PID/h2dTOFNSigmaALaPr", "h2dTOFNSigmaALaPr", kTH2F, {axisPt, axisTOFNSigma}); + histos.add("V0/PID/h2dTOFNSigmaALaPi", "h2dTOFNSigmaALaPi", kTH2F, {axisPt, axisTOFNSigma}); + histos.add("V0/PID/h2dTOFNSigmaK0PiPlus", "h2dTOFNSigmaK0PiPlus", kTH2F, {axisPt, axisTOFNSigma}); + histos.add("V0/PID/h2dTOFNSigmaK0PiMinus", "h2dTOFNSigmaK0PiMinus", kTH2F, {axisPt, axisTOFNSigma}); + histos.add("V0/PID/h3dTPCVsTOFNSigmaLaPr", "h3dTPCVsTOFNSigmaLaPr", kTH3F, {axisTPCNSigma, axisTOFNSigma, axisPt}); + histos.add("V0/PID/h3dTPCVsTOFNSigmaLaPi", "h3dTPCVsTOFNSigmaLaPi", kTH3F, {axisTPCNSigma, axisTOFNSigma, axisPt}); + + histos.add("MCV0/hv0MCCore", "hv0MCCore", kTH1F, {axisBool}); + histos.add("MCV0/h2dPDGV0VsMother", "h2dPDGV0VsMother", kTHnSparseD, {axisPDGCode, axisPDGCode}); + histos.add("MCV0/h2dPDGV0VsPositive", "h2dPDGV0VsPositive", kTHnSparseD, {axisPDGCode, axisPDGCode}); + histos.add("MCV0/h2dPDGV0VsNegative", "h2dPDGV0VsNegative", kTHnSparseD, {axisPDGCode, axisPDGCode}); + histos.add("MCV0/h2dPDGV0VsIsPhysicalPrimary", "h2dPDGV0VsIsPhysicalPrimary", kTH2F, {axisPDGCode, axisBool}); + histos.add("MCV0/h2dArmenterosP", "h2dArmenterosP", kTH2F, {axisAlpha, axisQtarm}); + histos.add("MCV0/Gamma/h2dpTResolution", "h2dpTResolution", kTH2F, {axisPt, axisPtResolution}); + histos.add("MCV0/Gamma/h2dMass", "h2dMass", kTH2F, {axisPt, axisMassGamma}); + histos.add("MCV0/Gamma/h2dTPCNSigmaEl", "h2dTPCNSigmaEl", kTH2F, {axisPt2, axisTPCNSigma}); + histos.add("MCV0/Gamma/h2dTPCSignal", "h2dTPCSignal", kTH2F, {axisPt2, axisTPCSignal}); + histos.add("MCV0/Gamma/hRadius", "hRadius", kTH1F, {axisV0Radius}); + histos.add("MCV0/Gamma/hCosPA", "hCosPA", kTH1F, {axisCosPA}); + histos.add("MCV0/Gamma/hdcaDau", "hdcaDau", kTH1F, {axisDCAdau}); + histos.add("MCV0/Gamma/hdcaNegtopv", "hdcaNegtopv", kTH1F, {axisDCAToPV}); + histos.add("MCV0/Gamma/hdcaPostopv", "hdcaPostopv", kTH1F, {axisDCAToPV}); + + histos.add("MCV0/Lambda/h2dpTResolution", "h2dpTResolution", kTH2F, {axisPt, axisPtResolution}); + histos.add("MCV0/Lambda/h2dMass", "h2dMass", kTH2F, {axisPt, axisMassLambda}); + histos.add("MCV0/Lambda/h2dTPCNSigmaPr", "h2dTPCNSigmaPr", kTH2F, {axisPt, axisTPCNSigma}); + histos.add("MCV0/Lambda/h2dTPCNSigmaPi", "h2dTPCNSigmaPi", kTH2F, {axisPt, axisTPCNSigma}); + histos.add("MCV0/Lambda/h2dTPCSignal", "h2dTPCSignal", kTH2F, {axisPt2, axisTPCSignal}); + histos.add("MCV0/Lambda/hRadius", "hRadius", kTH1F, {axisV0Radius}); + histos.add("MCV0/Lambda/hCosPA", "hCosPA", kTH1F, {axisCosPA}); + histos.add("MCV0/Lambda/hdcaDau", "hdcaDau", kTH1F, {axisDCAdau}); + histos.add("MCV0/Lambda/hdcaNegtopv", "hdcaNegtopv", kTH1F, {axisDCAToPV}); + histos.add("MCV0/Lambda/hdcaPostopv", "hdcaPostopv", kTH1F, {axisDCAToPV}); + + histos.add("MCV0/AntiLambda/h2dpTResolution", "h2dpTResolution", kTH2F, {axisPt, axisPtResolution}); + histos.add("MCV0/AntiLambda/h2dMass", "h2dMass", kTH2F, {axisPt, axisMassLambda}); + histos.add("MCV0/AntiLambda/h2dTPCNSigmaPr", "h2dTPCNSigmaPr", kTH2F, {axisPt, axisTPCNSigma}); + histos.add("MCV0/AntiLambda/h2dTPCNSigmaPi", "h2dTPCNSigmaPi", kTH2F, {axisPt, axisTPCNSigma}); + histos.add("MCV0/AntiLambda/h2dTPCSignal", "h2dTPCSignal", kTH2F, {axisPt2, axisTPCSignal}); + histos.add("MCV0/AntiLambda/hRadius", "hRadius", kTH1F, {axisV0Radius}); + histos.add("MCV0/AntiLambda/hCosPA", "hCosPA", kTH1F, {axisCosPA}); + histos.add("MCV0/AntiLambda/hdcaDau", "hdcaDau", kTH1F, {axisDCAdau}); + histos.add("MCV0/AntiLambda/hdcaNegtopv", "hdcaNegtopv", kTH1F, {axisDCAToPV}); + histos.add("MCV0/AntiLambda/hdcaPostopv", "hdcaPostopv", kTH1F, {axisDCAToPV}); + + histos.add("MCV0/K0Short/h2dpTResolution", "h2dpTResolution", kTH2F, {axisPt, axisPtResolution}); + histos.add("MCV0/K0Short/h2dMass", "h2dMass", kTH2F, {axisPt, axisMassK0Short}); + histos.add("MCV0/K0Short/h2dTPCNSigmaPi", "h2dTPCNSigmaPi", kTH2F, {axisPt2, axisTPCNSigma}); + histos.add("MCV0/K0Short/h2dTPCSignal", "h2dTPCSignal", kTH2F, {axisPt2, axisTPCSignal}); + histos.add("MCV0/K0Short/hRadius", "hRadius", kTH1F, {axisV0Radius}); + histos.add("MCV0/K0Short/hCosPA", "hCosPA", kTH1F, {axisCosPA}); + histos.add("MCV0/K0Short/hdcaDau", "hdcaDau", kTH1F, {axisDCAdau}); + histos.add("MCV0/K0Short/hdcaNegtopv", "hdcaNegtopv", kTH1F, {axisDCAToPV}); + histos.add("MCV0/K0Short/hdcaPostopv", "hdcaPostopv", kTH1F, {axisDCAToPV}); + + histos.add("Casc/Sign", "Sign", kTH1F, {{3, -1.5f, 1.5f}}); + histos.add("Casc/hpT", "hpT", kTH1F, {axisPt}); + histos.add("Casc/hV0Radius", "hV0Radius", kTH1F, {axisV0Radius}); + histos.add("Casc/hCascRadius", "hCascRadius", kTH1F, {axisCascRadius}); + histos.add("Casc/hV0CosPA", "hV0CosPA", kTH1F, {axisCosPA}); + histos.add("Casc/hCascCosPA", "hCascCosPA", kTH1F, {axisCosPA}); + histos.add("Casc/hDCAPosToPV", "hDCAPosToPV", kTH1F, {axisDCAToPV}); + histos.add("Casc/hDCANegToPV", "hDCANegToPV", kTH1F, {axisDCAToPV}); + histos.add("Casc/hDCABachToPV", "hDCABachToPV", kTH1F, {axisDCAToPV}); + histos.add("Casc/hDCAXYCascToPV", "hDCAXYCascToPV", kTH1F, {axisDCAXYCascToPV}); + histos.add("Casc/hDCAZCascToPV", "hDCAZCascToPV", kTH1F, {axisDCAZCascToPV}); + histos.add("Casc/hDCAV0ToPV", "hDCAV0ToPV", kTH1F, {axisDCAV0ToPV}); + histos.add("Casc/hDCAV0Dau", "hDCAV0Dau", kTH1F, {axisDCAV0Dau}); + histos.add("Casc/hDCACascDau", "hDCACascDau", kTH1F, {axisDCACascDau}); + histos.add("Casc/hLambdaMass", "hLambdaMass", kTH1F, {axisMassLambda}); + + histos.add("Casc/Track/h3dTrackProperties", "h3dTrackProperties", kTH3F, {axisTrackProperties, axisTrackProperties, axisTrackProperties}); + histos.add("Casc/Track/h2dPosTrackProperties", "h2dPosTrackProperties", kTH2F, {axisTrackProperties, axisPt}); + histos.add("Casc/Track/h2dNegTrackProperties", "h2dNegTrackProperties", kTH2F, {axisTrackProperties, axisPt}); + histos.add("Casc/Track/h2dBachTrackProperties", "h2dBachTrackProperties", kTH2F, {axisTrackProperties, axisPt}); + histos.add("Casc/Track/h2dV0ITSChi2PerNcl", "h2dV0ITSChi2PerNcl", kTH2F, {axisPt2, axisChi2PerNcl}); + histos.add("Casc/Track/h2dV0TPCCrossedRows", "h2dV0TPCCrossedRows", kTH2F, {axisPt2, axisTPCrows}); + histos.add("Casc/Track/h2dV0ITSNCls", "h2dV0ITSNCls", kTH2F, {axisPt2, axisNCls}); + + histos.add("Casc/PID/h2dV0TPCNSigmaPr", "h2dV0TPCNSigmaPr", kTH2F, {axisPt2, axisTPCNSigma}); + histos.add("Casc/PID/h2dV0TPCNSigmaPi", "h2dV0TPCNSigmaPi", kTH2F, {axisPt2, axisTPCNSigma}); + histos.add("Casc/PID/h2dV0TPCSignal", "h2dV0TPCSignal", kTH2F, {axisPt2, axisTPCSignal}); + histos.add("Casc/PID/h2dTOFNSigmaXiLaPi", "h2dTOFNSigmaXiLaPi", kTH2F, {axisPt, axisTOFNSigma}); + histos.add("Casc/PID/h2dTOFNSigmaXiLaPr", "h2dTOFNSigmaXiLaPr", kTH2F, {axisPt, axisTOFNSigma}); + histos.add("Casc/PID/h2dTOFNSigmaXiPi", "h2dTOFNSigmaXiPi", kTH2F, {axisPt, axisTOFNSigma}); + histos.add("Casc/PID/h2dTOFNSigmaOmLaPi", "h2dTOFNSigmaOmLaPi", kTH2F, {axisPt, axisTOFNSigma}); + histos.add("Casc/PID/h2dTOFNSigmaOmLaPr", "h2dTOFNSigmaOmLaPr", kTH2F, {axisPt, axisTOFNSigma}); + histos.add("Casc/PID/h2dTOFNSigmaOmKa", "h2dTOFNSigmaOmKa", kTH2F, {axisPt, axisTOFNSigma}); + + histos.add("Casc/hMassXiMinus", "hMassXiMinus", kTH1F, {axisXiMass}); + histos.add("Casc/hMassOmegaMinus", "hMassOmegaMinus", kTH1F, {axisOmegaMass}); + histos.add("Casc/hMassXiPlus", "hMassXiPlus", kTH1F, {axisXiMass}); + histos.add("Casc/hMassOmegaPlus", "hMassOmegaPlus", kTH1F, {axisOmegaMass}); + histos.add("Casc/Track/h2dBachITSNCls", "h2dBachITSNCls", kTH2F, {axisPt2, axisNCls}); + histos.add("Casc/Track/h2dBachITSChi2PerNcl", "h2dBachITSChi2PerNcl", kTH2F, {axisPt2, axisChi2PerNcl}); + histos.add("Casc/Track/h2dBachTPCCrossedRows", "h2dBachTPCCrossedRows", kTH2F, {axisPt2, axisTPCrows}); + histos.add("Casc/PID/h2dBachTPCSignal", "h2dBachTPCSignal", kTH2F, {axisPt2, axisTPCSignal}); + + histos.add("MCCasc/hcascMCCore", "hcascMCCore", kTH1F, {axisBool}); + histos.add("MCCasc/h2dPDGV0VsMother", "h2dPDGV0VsMother", kTHnSparseD, {axisPDGCode, axisPDGCode}); + histos.add("MCCasc/h2dPDGV0VsPositive", "h2dPDGV0VsPositive", kTHnSparseD, {axisPDGCode, axisPDGCode}); + histos.add("MCCasc/h2dPDGV0VsNegative", "h2dPDGV0VsNegative", kTHnSparseD, {axisPDGCode, axisPDGCode}); + histos.add("MCCasc/h2dPDGV0VsBach", "h2dPDGV0VsBach", kTHnSparseD, {axisPDGCode, axisPDGCode}); + histos.add("MCCasc/h2dPDGV0VsIsPhysicalPrimary", "h2dPDGV0VsIsPhysicalPrimary", kTH2F, {axisPDGCode, axisBool}); + + histos.add("MCCasc/XiMinus/h2dpTResolution", "h2dpTResolution", kTH2F, {axisPt, axisPtResolution}); + histos.add("MCCasc/XiMinus/h2dMass", "h2dMass", kTH2F, {axisPt, axisXiMass}); + histos.add("MCCasc/XiMinus/h2dV0TPCSignal", "h2dV0TPCSignal", kTH2F, {axisPt2, axisTPCSignal}); + histos.add("MCCasc/XiMinus/h2dBachTPCSignal", "h2dBachTPCSignal", kTH2F, {axisPt, axisTPCSignal}); + histos.add("MCCasc/XiMinus/hV0Radius", "hV0Radius", kTH1F, {axisV0Radius}); + histos.add("MCCasc/XiMinus/hCascRadius", "hCascRadius", kTH1F, {axisCascRadius}); + histos.add("MCCasc/XiMinus/hV0CosPA", "hV0CosPA", kTH1F, {axisCosPA}); + histos.add("MCCasc/XiMinus/hCascCosPA", "hCascCosPA", kTH1F, {axisCosPA}); + histos.add("MCCasc/XiMinus/hDCAPosToPV", "hDCAPosToPV", kTH1F, {axisDCAToPV}); + histos.add("MCCasc/XiMinus/hDCANegToPV", "hDCANegToPV", kTH1F, {axisDCAToPV}); + histos.add("MCCasc/XiMinus/hDCABachToPV", "hDCABachToPV", kTH1F, {axisDCAToPV}); + histos.add("MCCasc/XiMinus/hDCAXYCascToPV", "hDCAXYCascToPV", kTH1F, {axisDCAXYCascToPV}); + histos.add("MCCasc/XiMinus/hDCAZCascToPV", "hDCAZCascToPV", kTH1F, {axisDCAZCascToPV}); + histos.add("MCCasc/XiMinus/hDCAV0ToPV", "hDCAV0ToPV", kTH1F, {axisDCAV0ToPV}); + histos.add("MCCasc/XiMinus/hDCAV0Dau", "hDCAV0Dau", kTH1F, {axisDCAV0Dau}); + histos.add("MCCasc/XiMinus/hDCACascDau", "hDCACascDau", kTH1F, {axisDCACascDau}); + histos.add("MCCasc/XiMinus/hLambdaMass", "hLambdaMass", kTH1F, {axisMassLambda}); + + histos.add("MCCasc/XiPlus/h2dpTResolution", "h2dpTResolution", kTH2F, {axisPt, axisPtResolution}); + histos.add("MCCasc/XiPlus/h2dMass", "h2dMass", kTH2F, {axisPt, axisXiMass}); + histos.add("MCCasc/XiPlus/h2dV0TPCSignal", "h2dV0TPCSignal", kTH2F, {axisPt2, axisTPCSignal}); + histos.add("MCCasc/XiPlus/h2dBachTPCSignal", "h2dBachTPCSignal", kTH2F, {axisPt, axisTPCSignal}); + histos.add("MCCasc/XiPlus/hV0Radius", "hV0Radius", kTH1F, {axisV0Radius}); + histos.add("MCCasc/XiPlus/hCascRadius", "hCascRadius", kTH1F, {axisCascRadius}); + histos.add("MCCasc/XiPlus/hV0CosPA", "hV0CosPA", kTH1F, {axisCosPA}); + histos.add("MCCasc/XiPlus/hCascCosPA", "hCascCosPA", kTH1F, {axisCosPA}); + histos.add("MCCasc/XiPlus/hDCAPosToPV", "hDCAPosToPV", kTH1F, {axisDCAToPV}); + histos.add("MCCasc/XiPlus/hDCANegToPV", "hDCANegToPV", kTH1F, {axisDCAToPV}); + histos.add("MCCasc/XiPlus/hDCABachToPV", "hDCABachToPV", kTH1F, {axisDCAToPV}); + histos.add("MCCasc/XiPlus/hDCAXYCascToPV", "hDCAXYCascToPV", kTH1F, {axisDCAXYCascToPV}); + histos.add("MCCasc/XiPlus/hDCAZCascToPV", "hDCAZCascToPV", kTH1F, {axisDCAZCascToPV}); + histos.add("MCCasc/XiPlus/hDCAV0ToPV", "hDCAV0ToPV", kTH1F, {axisDCAV0ToPV}); + histos.add("MCCasc/XiPlus/hDCAV0Dau", "hDCAV0Dau", kTH1F, {axisDCAV0Dau}); + histos.add("MCCasc/XiPlus/hDCACascDau", "hDCACascDau", kTH1F, {axisDCACascDau}); + histos.add("MCCasc/XiPlus/hLambdaMass", "hLambdaMass", kTH1F, {axisMassLambda}); + + histos.add("MCCasc/OmegaMinus/h2dpTResolution", "h2dpTResolution", kTH2F, {axisPt, axisPtResolution}); + histos.add("MCCasc/OmegaMinus/h2dMass", "h2dMass", kTH2F, {axisPt, axisOmegaMass}); + histos.add("MCCasc/OmegaMinus/h2dV0TPCSignal", "h2dV0TPCSignal", kTH2F, {axisPt2, axisTPCSignal}); + histos.add("MCCasc/OmegaMinus/h2dBachTPCSignal", "h2dBachTPCSignal", kTH2F, {axisPt, axisTPCSignal}); + histos.add("MCCasc/OmegaMinus/hV0Radius", "hV0Radius", kTH1F, {axisV0Radius}); + histos.add("MCCasc/OmegaMinus/hCascRadius", "hCascRadius", kTH1F, {axisCascRadius}); + histos.add("MCCasc/OmegaMinus/hV0CosPA", "hV0CosPA", kTH1F, {axisCosPA}); + histos.add("MCCasc/OmegaMinus/hCascCosPA", "hCascCosPA", kTH1F, {axisCosPA}); + histos.add("MCCasc/OmegaMinus/hDCAPosToPV", "hDCAPosToPV", kTH1F, {axisDCAToPV}); + histos.add("MCCasc/OmegaMinus/hDCANegToPV", "hDCANegToPV", kTH1F, {axisDCAToPV}); + histos.add("MCCasc/OmegaMinus/hDCABachToPV", "hDCABachToPV", kTH1F, {axisDCAToPV}); + histos.add("MCCasc/OmegaMinus/hDCAXYCascToPV", "hDCAXYCascToPV", kTH1F, {axisDCAXYCascToPV}); + histos.add("MCCasc/OmegaMinus/hDCAZCascToPV", "hDCAZCascToPV", kTH1F, {axisDCAZCascToPV}); + histos.add("MCCasc/OmegaMinus/hDCAV0ToPV", "hDCAV0ToPV", kTH1F, {axisDCAV0ToPV}); + histos.add("MCCasc/OmegaMinus/hDCAV0Dau", "hDCAV0Dau", kTH1F, {axisDCAV0Dau}); + histos.add("MCCasc/OmegaMinus/hDCACascDau", "hDCACascDau", kTH1F, {axisDCACascDau}); + histos.add("MCCasc/OmegaMinus/hLambdaMass", "hLambdaMass", kTH1F, {axisMassLambda}); + + histos.add("MCCasc/OmegaPlus/h2dpTResolution", "h2dpTResolution", kTH2F, {axisPt, axisPtResolution}); + histos.add("MCCasc/OmegaPlus/h2dMass", "h2dMass", kTH2F, {axisPt, axisOmegaMass}); + histos.add("MCCasc/OmegaPlus/h2dV0TPCSignal", "h2dV0TPCSignal", kTH2F, {axisPt2, axisTPCSignal}); + histos.add("MCCasc/OmegaPlus/h2dBachTPCSignal", "h2dBachTPCSignal", kTH2F, {axisPt, axisTPCSignal}); + histos.add("MCCasc/OmegaPlus/hV0Radius", "hV0Radius", kTH1F, {axisV0Radius}); + histos.add("MCCasc/OmegaPlus/hCascRadius", "hCascRadius", kTH1F, {axisCascRadius}); + histos.add("MCCasc/OmegaPlus/hV0CosPA", "hV0CosPA", kTH1F, {axisCosPA}); + histos.add("MCCasc/OmegaPlus/hCascCosPA", "hCascCosPA", kTH1F, {axisCosPA}); + histos.add("MCCasc/OmegaPlus/hDCAPosToPV", "hDCAPosToPV", kTH1F, {axisDCAToPV}); + histos.add("MCCasc/OmegaPlus/hDCANegToPV", "hDCANegToPV", kTH1F, {axisDCAToPV}); + histos.add("MCCasc/OmegaPlus/hDCABachToPV", "hDCABachToPV", kTH1F, {axisDCAToPV}); + histos.add("MCCasc/OmegaPlus/hDCAXYCascToPV", "hDCAXYCascToPV", kTH1F, {axisDCAXYCascToPV}); + histos.add("MCCasc/OmegaPlus/hDCAZCascToPV", "hDCAZCascToPV", kTH1F, {axisDCAZCascToPV}); + histos.add("MCCasc/OmegaPlus/hDCAV0ToPV", "hDCAV0ToPV", kTH1F, {axisDCAV0ToPV}); + histos.add("MCCasc/OmegaPlus/hDCAV0Dau", "hDCAV0Dau", kTH1F, {axisDCAV0Dau}); + histos.add("MCCasc/OmegaPlus/hDCACascDau", "hDCACascDau", kTH1F, {axisDCACascDau}); + histos.add("MCCasc/OmegaPlus/hLambdaMass", "hLambdaMass", kTH1F, {axisMassLambda}); + + // MC Generated level + histos.add("GenMC/hGenEvents", "hGenEvents", kTH2F, {{axisNch}, {2, -0.5f, +1.5f}}); + histos.get(HIST("GenMC/hGenEvents"))->GetYaxis()->SetBinLabel(1, "All gen. events"); + histos.get(HIST("GenMC/hGenEvents"))->GetYaxis()->SetBinLabel(2, "Gen. with at least 1 rec. events"); + histos.add("GenMC/hGenEventCentrality", "hGenEventCentrality", kTH1F, {{101, 0.0f, 101.0f}}); + histos.add("GenMC/hCentralityVsNcoll_beforeEvSel", "hCentralityVsNcoll_beforeEvSel", kTH2F, {axisCentrality, {50, -0.5f, 49.5f}}); + histos.add("GenMC/hCentralityVsNcoll_afterEvSel", "hCentralityVsNcoll_afterEvSel", kTH2F, {axisCentrality, {50, -0.5f, 49.5f}}); + histos.add("GenMC/hCentralityVsMultMC", "hCentralityVsMultMC", kTH2F, {{101, 0.0f, 101.0f}, axisNch}); + histos.add("GenMC/h2dGenGamma", "h2dGenGamma", kTH2D, {axisCentrality, axisPt}); + histos.add("GenMC/h2dGenK0Short", "h2dGenK0Short", kTH2D, {axisCentrality, axisPt}); + histos.add("GenMC/h2dGenLambda", "h2dGenLambda", kTH2D, {axisCentrality, axisPt}); + histos.add("GenMC/h2dGenAntiLambda", "h2dGenAntiLambda", kTH2D, {axisCentrality, axisPt}); + histos.add("GenMC/h2dGenXiMinus", "h2dGenXiMinus", kTH2D, {axisCentrality, axisPt}); + histos.add("GenMC/h2dGenXiPlus", "h2dGenXiPlus", kTH2D, {axisCentrality, axisPt}); + histos.add("GenMC/h2dGenOmegaMinus", "h2dGenOmegaMinus", kTH2D, {axisCentrality, axisPt}); + histos.add("GenMC/h2dGenOmegaPlus", "h2dGenOmegaPlus", kTH2D, {axisCentrality, axisPt}); + histos.add("GenMC/h2dGenK0ShortVsMultMC_RecoedEvt", "h2dGenK0ShortVsMultMC_RecoedEvt", kTH2D, {axisNch, axisPt}); + histos.add("GenMC/h2dGenLambdaVsMultMC_RecoedEvt", "h2dGenLambdaVsMultMC_RecoedEvt", kTH2D, {axisNch, axisPt}); + histos.add("GenMC/h2dGenAntiLambdaVsMultMC_RecoedEvt", "h2dGenAntiLambdaVsMultMC_RecoedEvt", kTH2D, {axisNch, axisPt}); + histos.add("GenMC/h2dGenXiMinusVsMultMC_RecoedEvt", "h2dGenXiMinusVsMultMC_RecoedEvt", kTH2D, {axisNch, axisPt}); + histos.add("GenMC/h2dGenXiPlusVsMultMC_RecoedEvt", "h2dGenXiPlusVsMultMC_RecoedEvt", kTH2D, {axisNch, axisPt}); + histos.add("GenMC/h2dGenOmegaMinusVsMultMC_RecoedEvt", "h2dGenOmegaMinusVsMultMC_RecoedEvt", kTH2D, {axisNch, axisPt}); + histos.add("GenMC/h2dGenOmegaPlusVsMultMC_RecoedEvt", "h2dGenOmegaPlusVsMultMC_RecoedEvt", kTH2D, {axisNch, axisPt}); + histos.add("GenMC/h2dGenGammaVsMultMC", "h2dGenGammaVsMultMC", kTH2D, {axisNch, axisPt}); + histos.add("GenMC/h2dGenK0ShortVsMultMC", "h2dGenK0ShortVsMultMC", kTH2D, {axisNch, axisPt}); + histos.add("GenMC/h2dGenLambdaVsMultMC", "h2dGenLambdaVsMultMC", kTH2D, {axisNch, axisPt}); + histos.add("GenMC/h2dGenAntiLambdaVsMultMC", "h2dGenAntiLambdaVsMultMC", kTH2D, {axisNch, axisPt}); + histos.add("GenMC/h2dGenXiMinusVsMultMC", "h2dGenXiMinusVsMultMC", kTH2D, {axisNch, axisPt}); + histos.add("GenMC/h2dGenXiPlusVsMultMC", "h2dGenXiPlusVsMultMC", kTH2D, {axisNch, axisPt}); + histos.add("GenMC/h2dGenOmegaMinusVsMultMC", "h2dGenOmegaMinusVsMultMC", kTH2D, {axisNch, axisPt}); + histos.add("GenMC/h2dGenOmegaPlusVsMultMC", "h2dGenOmegaPlusVsMultMC", kTH2D, {axisNch, axisPt}); + } + + template + bool IsEventAccepted(TCollision collision) + // check whether the collision passes our collision selections + { + if (eventSelections.requireSel8 && !collision.sel8()) { + return false; + } + if (eventSelections.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + if (eventSelections.rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if (eventSelections.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { + return false; + } + if (eventSelections.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (eventSelections.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (eventSelections.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (eventSelections.requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + return false; + } + if (eventSelections.rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (eventSelections.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if (eventSelections.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + if (eventSelections.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + return false; + } + if (eventSelections.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + if (eventSelections.requireNoCollInROFStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } + if (doPPAnalysis) { // we are in pp + if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) { + return false; + } + if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { + return false; + } + } else { // we are in Pb-Pb + float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) { + return false; + } + if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { + return false; + } + } + + return true; + } + + // ______________________________________________________ + // Simulated processing + // Return the list of indices to the recoed collision associated to a given MC collision. + std::vector getListOfRecoCollIndices(soa::Join const& mcCollisions, soa::Join const& collisions) + { + std::vector listBestCollisionIdx(mcCollisions.size()); + for (auto const& mcCollision : mcCollisions) { + auto groupedCollisions = collisions.sliceBy(perMcCollision, mcCollision.globalIndex()); + // Find the collision with the biggest nbr of PV contributors + // Follows what was done here: https://github.com/AliceO2Group/O2Physics/blob/master/Common/TableProducer/mcCollsExtra.cxx#L93 + int biggestNContribs = -1; + int bestCollisionIndex = -1; + for (auto const& collision : groupedCollisions) { + if (biggestNContribs < collision.multPVTotalContributors()) { + biggestNContribs = collision.multPVTotalContributors(); + bestCollisionIndex = collision.globalIndex(); + } + } + listBestCollisionIdx[mcCollision.globalIndex()] = bestCollisionIndex; + } + return listBestCollisionIdx; + } + + // ______________________________________________________ + // Simulated processing + // Fill generated event information (for event loss/splitting estimation) + void fillGeneratedEventProperties(soa::Join const& mcCollisions, soa::Join const& collisions) + { + std::vector listBestCollisionIdx(mcCollisions.size()); + for (auto const& mcCollision : mcCollisions) { + histos.fill(HIST("GenMC/hGenEvents"), mcCollision.multMCNParticlesEta05(), 0 /* all gen. events*/); + + auto groupedCollisions = collisions.sliceBy(perMcCollision, mcCollision.globalIndex()); + // Check if there is at least one of the reconstructed collisions associated to this MC collision + // If so, we consider it + bool atLeastOne = false; + int biggestNContribs = -1; + float centrality = 100.5f; + int nCollisions = 0; + for (auto const& collision : groupedCollisions) { + + if (!IsEventAccepted(collision)) { + continue; + } + + if (biggestNContribs < collision.multPVTotalContributors()) { + biggestNContribs = collision.multPVTotalContributors(); + centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + } + nCollisions++; + + atLeastOne = true; + } + + histos.fill(HIST("GenMC/hCentralityVsNcoll_beforeEvSel"), centrality, groupedCollisions.size()); + histos.fill(HIST("GenMC/hCentralityVsNcoll_afterEvSel"), centrality, nCollisions); + histos.fill(HIST("GenMC/hCentralityVsMultMC"), centrality, mcCollision.multMCNParticlesEta05()); + + if (atLeastOne) { + histos.fill(HIST("GenMC/hGenEvents"), mcCollision.multMCNParticlesEta05(), 1 /* at least 1 rec. event*/); + histos.fill(HIST("GenMC/hGenEventCentrality"), centrality); + } + } + return; + } + + void processDerivedV0s(StrCollisionsDatas::iterator const& coll, V0DerivedDatas const& V0s, dauTracks const&) + { + // Event Level + float centrality = coll.centFT0C(); + histos.fill(HIST("Event/hPosZ"), coll.posZ()); + histos.fill(HIST("Event/hEventProperties"), 0. /* all collisions */); + + if (coll.sel8()) + histos.fill(HIST("Event/hEventProperties"), 1.); + if (coll.selection_bit(aod::evsel::kIsTriggerTVX)) + histos.fill(HIST("Event/hEventProperties"), 2.); + if (coll.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) + histos.fill(HIST("Event/hEventProperties"), 3.); + if (coll.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) + histos.fill(HIST("Event/hEventProperties"), 4.); + if (coll.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) + histos.fill(HIST("Event/hEventProperties"), 5.); + if (coll.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + histos.fill(HIST("Event/hEventProperties"), 6.); + if (coll.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) + histos.fill(HIST("Event/hEventProperties"), 7.); + if (coll.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) + histos.fill(HIST("Event/hEventProperties"), 8.); + if (coll.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + histos.fill(HIST("Event/hEventProperties"), 9.); + if (coll.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) + histos.fill(HIST("Event/hEventProperties"), 10.); + if (coll.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) + histos.fill(HIST("Event/hEventProperties"), 11.); + if (coll.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) + histos.fill(HIST("Event/hEventProperties"), 12.); + if (coll.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) + histos.fill(HIST("Event/hEventProperties"), 13.); + if (coll.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) + histos.fill(HIST("Event/hEventProperties"), 14.); + + histos.fill(HIST("Event/hft0cOccupancyInTimeRange"), coll.ft0cOccupancyInTimeRange()); + histos.fill(HIST("Event/htrackOccupancyInTimeRange"), coll.trackOccupancyInTimeRange()); + histos.fill(HIST("Event/h2dMultFT0C"), centrality, coll.multFT0C()); + histos.fill(HIST("Event/h2dMultNTracksPVeta1"), centrality, coll.multNTracksPVeta1()); + histos.fill(HIST("Event/h2dMultPVTotalContributors"), centrality, coll.multPVTotalContributors()); + histos.fill(HIST("Event/h2dMultAllTracksTPCOnly"), centrality, coll.multAllTracksTPCOnly()); + histos.fill(HIST("Event/h2dMultAllTracksITSTPC"), centrality, coll.multAllTracksITSTPC()); + histos.fill(HIST("Event/h2dNumV0sPerColl"), centrality, V0s.size()); + + for (auto const& v0 : V0s) { + + // V0-Level + float V0Y_Gamma = RecoDecay::y(std::array{v0.px(), v0.py(), v0.pz()}, o2::constants::physics::MassGamma); + float V0Y_Lambda = RecoDecay::y(std::array{v0.px(), v0.py(), v0.pz()}, o2::constants::physics::MassLambda); + float V0Y_K0Short = RecoDecay::y(std::array{v0.px(), v0.py(), v0.pz()}, o2::constants::physics::MassK0Short); + + float pT = v0.pt(); + histos.fill(HIST("V0/hpT"), pT); + histos.fill(HIST("V0/h2dArmenterosP"), v0.alpha(), v0.qtarm()); + histos.fill(HIST("V0/hRadius"), v0.v0radius()); + histos.fill(HIST("V0/hZ"), v0.z()); + histos.fill(HIST("V0/hCosPA"), v0.v0cosPA()); + histos.fill(HIST("V0/hdcaDau"), v0.dcaV0daughters()); + histos.fill(HIST("V0/hdcaNegtopv"), v0.dcanegtopv()); + histos.fill(HIST("V0/hdcaPostopv"), v0.dcapostopv()); + histos.fill(HIST("V0/h2dEtaPhi"), v0.eta(), RecoDecay::phi(v0.px(), v0.py())); + histos.fill(HIST("V0/hYGamma"), V0Y_Gamma); + histos.fill(HIST("V0/hYLambda"), V0Y_Lambda); + histos.fill(HIST("V0/hYK0Short"), V0Y_K0Short); + histos.fill(HIST("V0/hMassGamma"), v0.mGamma()); + histos.fill(HIST("V0/hMassLambda"), v0.mLambda()); + histos.fill(HIST("V0/hMassK0Short"), v0.mK0Short()); + histos.fill(HIST("V0/hV0Type"), v0.v0Type()); + histos.fill(HIST("V0/h2dV0Indices"), v0.straCollisionId(), coll.globalIndex()); // cross-check index correctness + + // Track-level + auto posTrack = v0.template posTrackExtra_as(); + auto negTrack = v0.template negTrackExtra_as(); + + uint8_t positiveTrackCode = ((uint8_t(posTrack.hasTPC()) << hasTPC) | + (uint8_t(posTrack.hasITSTracker()) << hasITSTracker) | + (uint8_t(posTrack.hasITSAfterburner()) << hasITSAfterburner) | + (uint8_t(posTrack.hasTRD()) << hasTRD) | + (uint8_t(posTrack.hasTOF()) << hasTOF)); + + uint8_t negativeTrackCode = ((uint8_t(negTrack.hasTPC()) << hasTPC) | + (uint8_t(negTrack.hasITSTracker()) << hasITSTracker) | + (uint8_t(negTrack.hasITSAfterburner()) << hasITSAfterburner) | + (uint8_t(negTrack.hasTRD()) << hasTRD) | + (uint8_t(negTrack.hasTOF()) << hasTOF)); + + histos.fill(HIST("V0/Track/h2dITSNCls"), v0.positivept(), posTrack.itsNCls()); + histos.fill(HIST("V0/Track/h2dITSNCls"), -1 * v0.negativept(), negTrack.itsNCls()); + histos.fill(HIST("V0/Track/h2dITSChi2PerNcl"), v0.positivept(), posTrack.itsChi2PerNcl()); + histos.fill(HIST("V0/Track/h2dITSChi2PerNcl"), -1 * v0.negativept(), negTrack.itsChi2PerNcl()); + histos.fill(HIST("V0/Track/h2dTPCCrossedRows"), v0.positivept(), posTrack.tpcCrossedRows()); + histos.fill(HIST("V0/Track/h2dTPCCrossedRows"), -1 * v0.negativept(), negTrack.tpcCrossedRows()); + histos.fill(HIST("V0/Track/hTrackCode"), positiveTrackCode); // pos track info + histos.fill(HIST("V0/Track/hTrackCode"), negativeTrackCode); // neg track info + histos.fill(HIST("V0/Track/h3dTrackPropertiesVspT"), positiveTrackCode, negativeTrackCode, pT); // tracking complete info + histos.fill(HIST("V0/Track/h2dPosTrackProperties"), positiveTrackCode, v0.positivept()); // pos track info + histos.fill(HIST("V0/Track/h2dNegTrackProperties"), negativeTrackCode, v0.negativept()); // neg track info + + // PID (TPC) + histos.fill(HIST("V0/PID/h2dTPCNSigmaEl"), v0.positivept(), posTrack.tpcNSigmaEl()); + histos.fill(HIST("V0/PID/h2dTPCNSigmaEl"), -1 * v0.negativept(), negTrack.tpcNSigmaEl()); + histos.fill(HIST("V0/PID/h2dTPCNSigmaPr"), v0.positivept(), posTrack.tpcNSigmaPr()); + histos.fill(HIST("V0/PID/h2dTPCNSigmaPr"), -1 * v0.negativept(), negTrack.tpcNSigmaPr()); + histos.fill(HIST("V0/PID/h2dTPCNSigmaPi"), v0.positivept(), posTrack.tpcNSigmaPi()); + histos.fill(HIST("V0/PID/h2dTPCNSigmaPi"), -1 * v0.negativept(), negTrack.tpcNSigmaPi()); + histos.fill(HIST("V0/PID/h2dTPCSignal"), v0.positivept(), posTrack.tpcSignal()); + histos.fill(HIST("V0/PID/h2dTPCSignal"), -1 * v0.negativept(), negTrack.tpcSignal()); + + // PID (TOF) + histos.fill(HIST("V0/PID/h2dTOFNSigmaLaPr"), pT, v0.tofNSigmaLaPr()); + histos.fill(HIST("V0/PID/h2dTOFNSigmaLaPi"), pT, v0.tofNSigmaLaPi()); + histos.fill(HIST("V0/PID/h2dposTOFDeltaTLaPr"), pT, v0.posTOFDeltaTLaPr()); + histos.fill(HIST("V0/PID/h2dnegTOFDeltaTLaPi"), pT, v0.negTOFDeltaTLaPi()); + histos.fill(HIST("V0/PID/h2dnegTOFDeltaTLaPr"), pT, v0.negTOFDeltaTLaPr()); + histos.fill(HIST("V0/PID/h2dposTOFDeltaTLaPi"), pT, v0.posTOFDeltaTLaPi()); + histos.fill(HIST("V0/PID/h2dTOFNSigmaALaPr"), pT, v0.tofNSigmaALaPr()); + histos.fill(HIST("V0/PID/h2dTOFNSigmaALaPi"), pT, v0.tofNSigmaALaPi()); + + histos.fill(HIST("V0/PID/h2dTOFNSigmaK0PiPlus"), pT, v0.tofNSigmaK0PiPlus()); + histos.fill(HIST("V0/PID/h2dTOFNSigmaK0PiMinus"), pT, v0.tofNSigmaK0PiMinus()); + + // PID TPC + TOF + histos.fill(HIST("V0/PID/h3dTPCVsTOFNSigmaLaPr"), posTrack.tpcNSigmaPr(), v0.tofNSigmaLaPr(), v0.positivept()); + histos.fill(HIST("V0/PID/h3dTPCVsTOFNSigmaLaPi"), negTrack.tpcNSigmaPi(), v0.tofNSigmaLaPi(), v0.negativept()); + } + } + + void processMCDerivedV0s(V0DerivedMCDatas const& V0s, dauTracks const&, aod::MotherMCParts const&, soa::Join const&) + { + for (auto const& v0 : V0s) { + histos.fill(HIST("MCV0/hv0MCCore"), v0.has_v0MCCore()); + if (!v0.has_v0MCCore()) + continue; + + auto v0MC = v0.v0MCCore_as>(); + + // General + histos.fill(HIST("MCV0/h2dPDGV0VsMother"), v0MC.pdgCode(), v0MC.pdgCodeMother()); + histos.fill(HIST("MCV0/h2dPDGV0VsPositive"), v0MC.pdgCode(), v0MC.pdgCodePositive()); + histos.fill(HIST("MCV0/h2dPDGV0VsNegative"), v0MC.pdgCode(), v0MC.pdgCodeNegative()); + histos.fill(HIST("MCV0/h2dPDGV0VsIsPhysicalPrimary"), v0MC.pdgCode(), v0MC.isPhysicalPrimary()); + + // Track-level + auto posTrack = v0.template posTrackExtra_as(); + auto negTrack = v0.template negTrackExtra_as(); + + // Specific analysis by species: + if (v0MC.pdgCode() == 22) { // IsGamma + histos.fill(HIST("MCV0/h2dArmenterosP"), v0.alpha(), v0.qtarm()); + histos.fill(HIST("MCV0/Gamma/h2dpTResolution"), v0.pt(), v0.pt() - v0MC.ptMC()); + histos.fill(HIST("MCV0/Gamma/h2dMass"), v0.pt(), v0.mGamma()); + histos.fill(HIST("MCV0/Gamma/h2dTPCNSigmaEl"), v0.positivept(), posTrack.tpcNSigmaEl()); + histos.fill(HIST("MCV0/Gamma/h2dTPCNSigmaEl"), -1 * v0.negativept(), negTrack.tpcNSigmaEl()); + histos.fill(HIST("MCV0/Gamma/h2dTPCSignal"), v0.positivept(), posTrack.tpcSignal()); + histos.fill(HIST("MCV0/Gamma/h2dTPCSignal"), -1 * v0.negativept(), negTrack.tpcSignal()); + histos.fill(HIST("MCV0/Gamma/hRadius"), v0.v0radius()); + histos.fill(HIST("MCV0/Gamma/hCosPA"), v0.v0cosPA()); + histos.fill(HIST("MCV0/Gamma/hdcaDau"), v0.dcaV0daughters()); + histos.fill(HIST("MCV0/Gamma/hdcaNegtopv"), v0.dcanegtopv()); + histos.fill(HIST("MCV0/Gamma/hdcaPostopv"), v0.dcapostopv()); + } + if (v0MC.pdgCode() == 3122) { // IsLambda + histos.fill(HIST("MCV0/h2dArmenterosP"), v0.alpha(), v0.qtarm()); + histos.fill(HIST("MCV0/Lambda/h2dpTResolution"), v0.pt(), v0.pt() - v0MC.ptMC()); + histos.fill(HIST("MCV0/Lambda/h2dMass"), v0.pt(), v0.mLambda()); + histos.fill(HIST("MCV0/Lambda/h2dTPCNSigmaPr"), v0.positivept(), posTrack.tpcNSigmaPr()); + histos.fill(HIST("MCV0/Lambda/h2dTPCNSigmaPi"), v0.negativept(), negTrack.tpcNSigmaPi()); + histos.fill(HIST("MCV0/Lambda/h2dTPCSignal"), v0.positivept(), posTrack.tpcSignal()); + histos.fill(HIST("MCV0/Lambda/h2dTPCSignal"), -1 * v0.negativept(), negTrack.tpcSignal()); + histos.fill(HIST("MCV0/Lambda/hRadius"), v0.v0radius()); + histos.fill(HIST("MCV0/Lambda/hCosPA"), v0.v0cosPA()); + histos.fill(HIST("MCV0/Lambda/hdcaDau"), v0.dcaV0daughters()); + histos.fill(HIST("MCV0/Lambda/hdcaNegtopv"), v0.dcanegtopv()); + histos.fill(HIST("MCV0/Lambda/hdcaPostopv"), v0.dcapostopv()); + } + if (v0MC.pdgCode() == -3122) { // IsAntiLambda + histos.fill(HIST("MCV0/h2dArmenterosP"), v0.alpha(), v0.qtarm()); + histos.fill(HIST("MCV0/AntiLambda/h2dpTResolution"), v0.pt(), v0.pt() - v0MC.ptMC()); + histos.fill(HIST("MCV0/AntiLambda/h2dMass"), v0.pt(), v0.mAntiLambda()); + histos.fill(HIST("MCV0/AntiLambda/h2dTPCNSigmaPr"), v0.negativept(), negTrack.tpcNSigmaPr()); + histos.fill(HIST("MCV0/AntiLambda/h2dTPCNSigmaPi"), v0.positivept(), posTrack.tpcNSigmaPi()); + histos.fill(HIST("MCV0/AntiLambda/h2dTPCSignal"), v0.positivept(), posTrack.tpcSignal()); + histos.fill(HIST("MCV0/AntiLambda/h2dTPCSignal"), -1 * v0.negativept(), negTrack.tpcSignal()); + histos.fill(HIST("MCV0/AntiLambda/hRadius"), v0.v0radius()); + histos.fill(HIST("MCV0/AntiLambda/hCosPA"), v0.v0cosPA()); + histos.fill(HIST("MCV0/AntiLambda/hdcaDau"), v0.dcaV0daughters()); + histos.fill(HIST("MCV0/AntiLambda/hdcaNegtopv"), v0.dcanegtopv()); + histos.fill(HIST("MCV0/AntiLambda/hdcaPostopv"), v0.dcapostopv()); + } + if (v0MC.pdgCode() == 310) { // IsK0Short + histos.fill(HIST("MCV0/h2dArmenterosP"), v0.alpha(), v0.qtarm()); + histos.fill(HIST("MCV0/K0Short/h2dpTResolution"), v0.pt(), v0.pt() - v0MC.ptMC()); + histos.fill(HIST("MCV0/K0Short/h2dMass"), v0.pt(), v0.mK0Short()); + histos.fill(HIST("MCV0/K0Short/h2dTPCNSigmaPi"), v0.positivept(), posTrack.tpcNSigmaPi()); + histos.fill(HIST("MCV0/K0Short/h2dTPCNSigmaPi"), -1 * v0.negativept(), negTrack.tpcNSigmaPi()); + histos.fill(HIST("MCV0/K0Short/h2dTPCSignal"), v0.positivept(), posTrack.tpcSignal()); + histos.fill(HIST("MCV0/K0Short/h2dTPCSignal"), -1 * v0.negativept(), negTrack.tpcSignal()); + histos.fill(HIST("MCV0/K0Short/hRadius"), v0.v0radius()); + histos.fill(HIST("MCV0/K0Short/hCosPA"), v0.v0cosPA()); + histos.fill(HIST("MCV0/K0Short/hdcaDau"), v0.dcaV0daughters()); + histos.fill(HIST("MCV0/K0Short/hdcaNegtopv"), v0.dcanegtopv()); + histos.fill(HIST("MCV0/K0Short/hdcaPostopv"), v0.dcapostopv()); + } + } + } + + void processDerivedCascades(StrCollisionsDatas::iterator const& coll, CascDerivedDatas const& Cascades, dauTracks const&) + { + for (auto& casc : Cascades) { + // Cascade level + float pT = casc.pt(); + histos.fill(HIST("Casc/Sign"), casc.sign()); + histos.fill(HIST("Casc/hpT"), pT); + histos.fill(HIST("Casc/hV0Radius"), casc.v0radius()); + histos.fill(HIST("Casc/hCascRadius"), casc.cascradius()); + histos.fill(HIST("Casc/hV0CosPA"), casc.v0cosPA(casc.x(), casc.y(), casc.z())); + histos.fill(HIST("Casc/hCascCosPA"), casc.casccosPA(casc.x(), casc.y(), casc.z())); + histos.fill(HIST("Casc/hDCAPosToPV"), casc.dcapostopv()); + histos.fill(HIST("Casc/hDCANegToPV"), casc.dcanegtopv()); + histos.fill(HIST("Casc/hDCABachToPV"), casc.dcabachtopv()); + histos.fill(HIST("Casc/hDCAXYCascToPV"), casc.dcaXYCascToPV()); + histos.fill(HIST("Casc/hDCAZCascToPV"), casc.dcaZCascToPV()); + histos.fill(HIST("Casc/hDCAV0ToPV"), casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ())); + histos.fill(HIST("Casc/hDCAV0Dau"), casc.dcaV0daughters()); + histos.fill(HIST("Casc/hDCACascDau"), casc.dcacascdaughters()); + histos.fill(HIST("Casc/hLambdaMass"), casc.mLambda()); + + // Track level + auto negTrack = casc.template negTrackExtra_as(); + auto posTrack = casc.template posTrackExtra_as(); + auto bachTrack = casc.template bachTrackExtra_as(); + + uint8_t positiveTrackCode = ((uint8_t(posTrack.hasTPC()) << hasTPC) | + (uint8_t(posTrack.hasITSTracker()) << hasITSTracker) | + (uint8_t(posTrack.hasITSAfterburner()) << hasITSAfterburner) | + (uint8_t(posTrack.hasTRD()) << hasTRD) | + (uint8_t(posTrack.hasTOF()) << hasTOF)); + + uint8_t negativeTrackCode = ((uint8_t(negTrack.hasTPC()) << hasTPC) | + (uint8_t(negTrack.hasITSTracker()) << hasITSTracker) | + (uint8_t(negTrack.hasITSAfterburner()) << hasITSAfterburner) | + (uint8_t(negTrack.hasTRD()) << hasTRD) | + (uint8_t(negTrack.hasTOF()) << hasTOF)); + + uint8_t bachTrackCode = ((uint8_t(bachTrack.hasTPC()) << hasTPC) | + (uint8_t(bachTrack.hasITSTracker()) << hasITSTracker) | + (uint8_t(bachTrack.hasITSAfterburner()) << hasITSAfterburner) | + (uint8_t(bachTrack.hasTRD()) << hasTRD) | + (uint8_t(bachTrack.hasTOF()) << hasTOF)); + + histos.fill(HIST("Casc/Track/h3dTrackProperties"), positiveTrackCode, negativeTrackCode, bachTrackCode); // complete tracking info + histos.fill(HIST("Casc/Track/h2dPosTrackProperties"), positiveTrackCode, casc.positivept()); // positive track info + histos.fill(HIST("Casc/Track/h2dNegTrackProperties"), negativeTrackCode, casc.negativept()); // negative track info + histos.fill(HIST("Casc/Track/h2dBachTrackProperties"), bachTrackCode, casc.bachelorpt()); // bach track info + histos.fill(HIST("Casc/Track/h2dV0ITSChi2PerNcl"), casc.positivept(), posTrack.itsChi2PerNcl()); + histos.fill(HIST("Casc/Track/h2dV0ITSChi2PerNcl"), -1 * casc.negativept(), negTrack.itsChi2PerNcl()); + histos.fill(HIST("Casc/Track/h2dV0TPCCrossedRows"), casc.positivept(), posTrack.tpcCrossedRows()); + histos.fill(HIST("Casc/Track/h2dV0TPCCrossedRows"), -1 * casc.negativept(), negTrack.tpcCrossedRows()); + histos.fill(HIST("Casc/Track/h2dV0ITSNCls"), casc.positivept(), posTrack.itsNCls()); + histos.fill(HIST("Casc/Track/h2dV0ITSNCls"), -1 * casc.negativept(), negTrack.itsNCls()); + + // PID (TPC) + histos.fill(HIST("Casc/PID/h2dV0TPCNSigmaPr"), casc.positivept(), posTrack.tpcNSigmaPr()); + histos.fill(HIST("Casc/PID/h2dV0TPCNSigmaPr"), -1 * casc.negativept(), negTrack.tpcNSigmaPr()); + histos.fill(HIST("Casc/PID/h2dV0TPCNSigmaPi"), casc.positivept(), posTrack.tpcNSigmaPi()); + histos.fill(HIST("Casc/PID/h2dV0TPCNSigmaPi"), -1 * casc.negativept(), negTrack.tpcNSigmaPi()); + histos.fill(HIST("Casc/PID/h2dV0TPCSignal"), casc.positivept(), posTrack.tpcSignal()); + histos.fill(HIST("Casc/PID/h2dV0TPCSignal"), -1 * casc.negativept(), negTrack.tpcSignal()); + + // PID (TOF) + histos.fill(HIST("Casc/PID/h2dTOFNSigmaXiLaPi"), pT, casc.tofNSigmaXiLaPi()); //! meson track NSigma from pion <- lambda <- xi expectation + histos.fill(HIST("Casc/PID/h2dTOFNSigmaXiLaPr"), pT, casc.tofNSigmaXiLaPr()); //! baryon track NSigma from proton <- lambda <- xi expectation + histos.fill(HIST("Casc/PID/h2dTOFNSigmaXiPi"), pT, casc.tofNSigmaXiPi()); //! bachelor track NSigma from pion <- xi expectation + histos.fill(HIST("Casc/PID/h2dTOFNSigmaOmLaPi"), pT, casc.tofNSigmaOmLaPi()); //! meson track NSigma from pion <- lambda <- om expectation + histos.fill(HIST("Casc/PID/h2dTOFNSigmaOmLaPr"), pT, casc.tofNSigmaOmLaPr()); //! baryon track NSigma from proton <- lambda <- om expectation + histos.fill(HIST("Casc/PID/h2dTOFNSigmaOmKa"), pT, casc.tofNSigmaOmKa()); //! bachelor track NSigma from kaon <- om expectation + + // By particle species + if (casc.sign() < 0) { + histos.fill(HIST("Casc/hMassXiMinus"), casc.mXi()); + histos.fill(HIST("Casc/hMassOmegaMinus"), casc.mOmega()); + histos.fill(HIST("Casc/Track/h2dBachITSNCls"), -1 * casc.bachelorpt(), bachTrack.itsNCls()); + histos.fill(HIST("Casc/Track/h2dBachITSChi2PerNcl"), -1 * casc.bachelorpt(), bachTrack.itsChi2PerNcl()); + histos.fill(HIST("Casc/Track/h2dBachTPCCrossedRows"), -1 * casc.bachelorpt(), bachTrack.tpcCrossedRows()); + histos.fill(HIST("Casc/PID/h2dBachTPCSignal"), -1 * casc.bachelorpt(), bachTrack.tpcSignal()); + } else { + histos.fill(HIST("Casc/hMassXiPlus"), casc.mXi()); + histos.fill(HIST("Casc/hMassOmegaPlus"), casc.mOmega()); + histos.fill(HIST("Casc/Track/h2dBachITSNCls"), casc.bachelorpt(), bachTrack.itsNCls()); + histos.fill(HIST("Casc/Track/h2dBachITSChi2PerNcl"), casc.bachelorpt(), bachTrack.itsChi2PerNcl()); + histos.fill(HIST("Casc/Track/h2dBachTPCCrossedRows"), casc.bachelorpt(), bachTrack.tpcCrossedRows()); + histos.fill(HIST("Casc/PID/h2dBachTPCSignal"), casc.bachelorpt(), bachTrack.tpcSignal()); + } + } + } + + void processMCDerivedCascades(StrCollisionsDatas::iterator const& coll, CascDerivedMCDatas const& Cascades, dauTracks const&, soa::Join const&) + { + for (auto& casc : Cascades) { + + float pT = casc.pt(); + histos.fill(HIST("MCCasc/hcascMCCore"), casc.has_cascMCCore()); + if (!casc.has_cascMCCore()) + continue; + auto cascMC = casc.cascMCCore_as>(); + + // General + histos.fill(HIST("MCCasc/h2dPDGV0VsMother"), cascMC.pdgCode(), cascMC.pdgCodeMother()); + histos.fill(HIST("MCCasc/h2dPDGV0VsPositive"), cascMC.pdgCode(), cascMC.pdgCodePositive()); + histos.fill(HIST("MCCasc/h2dPDGV0VsNegative"), cascMC.pdgCode(), cascMC.pdgCodeNegative()); + histos.fill(HIST("MCCasc/h2dPDGV0VsBach"), cascMC.pdgCode(), cascMC.pdgCodeBachelor()); + histos.fill(HIST("MCCasc/h2dPDGV0VsIsPhysicalPrimary"), cascMC.pdgCode(), cascMC.isPhysicalPrimary()); + + // Track level + auto negTrack = casc.template negTrackExtra_as(); + auto posTrack = casc.template posTrackExtra_as(); + auto bachTrack = casc.template bachTrackExtra_as(); + + // Specific analysis by species: + if (cascMC.pdgCode() == 3312) { // XiMinus + histos.fill(HIST("MCCasc/XiMinus/h2dpTResolution"), pT, pT - cascMC.ptMC()); + histos.fill(HIST("MCCasc/XiMinus/h2dMass"), pT, casc.mXi()); + histos.fill(HIST("MCCasc/XiMinus/h2dV0TPCSignal"), casc.positivept(), posTrack.tpcSignal()); + histos.fill(HIST("MCCasc/XiMinus/h2dV0TPCSignal"), -1 * casc.negativept(), negTrack.tpcSignal()); + histos.fill(HIST("MCCasc/XiMinus/h2dBachTPCSignal"), casc.bachelorpt(), bachTrack.tpcSignal()); + histos.fill(HIST("MCCasc/XiMinus/hV0Radius"), casc.v0radius()); + histos.fill(HIST("MCCasc/XiMinus/hCascRadius"), casc.cascradius()); + histos.fill(HIST("MCCasc/XiMinus/hV0CosPA"), casc.v0cosPA(casc.x(), casc.y(), casc.z())); + histos.fill(HIST("MCCasc/XiMinus/hCascCosPA"), casc.casccosPA(casc.x(), casc.y(), casc.z())); + histos.fill(HIST("MCCasc/XiMinus/hDCAPosToPV"), casc.dcapostopv()); + histos.fill(HIST("MCCasc/XiMinus/hDCANegToPV"), casc.dcanegtopv()); + histos.fill(HIST("MCCasc/XiMinus/hDCABachToPV"), casc.dcabachtopv()); + histos.fill(HIST("MCCasc/XiMinus/hDCAXYCascToPV"), casc.dcaXYCascToPV()); + histos.fill(HIST("MCCasc/XiMinus/hDCAZCascToPV"), casc.dcaZCascToPV()); + histos.fill(HIST("MCCasc/XiMinus/hDCAV0ToPV"), casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ())); + histos.fill(HIST("MCCasc/XiMinus/hDCAV0Dau"), casc.dcaV0daughters()); + histos.fill(HIST("MCCasc/XiMinus/hDCACascDau"), casc.dcacascdaughters()); + histos.fill(HIST("MCCasc/XiMinus/hLambdaMass"), casc.mLambda()); + } + if (cascMC.pdgCode() == -3312) { // XiPlus + histos.fill(HIST("MCCasc/XiPlus/h2dpTResolution"), pT, pT - cascMC.ptMC()); + histos.fill(HIST("MCCasc/XiPlus/h2dMass"), pT, casc.mXi()); + histos.fill(HIST("MCCasc/XiPlus/h2dV0TPCSignal"), casc.positivept(), posTrack.tpcSignal()); + histos.fill(HIST("MCCasc/XiPlus/h2dV0TPCSignal"), -1 * casc.negativept(), negTrack.tpcSignal()); + histos.fill(HIST("MCCasc/XiPlus/h2dBachTPCSignal"), casc.bachelorpt(), bachTrack.tpcSignal()); + histos.fill(HIST("MCCasc/XiPlus/hV0Radius"), casc.v0radius()); + histos.fill(HIST("MCCasc/XiPlus/hCascRadius"), casc.cascradius()); + histos.fill(HIST("MCCasc/XiPlus/hV0CosPA"), casc.v0cosPA(casc.x(), casc.y(), casc.z())); + histos.fill(HIST("MCCasc/XiPlus/hCascCosPA"), casc.casccosPA(casc.x(), casc.y(), casc.z())); + histos.fill(HIST("MCCasc/XiPlus/hDCAPosToPV"), casc.dcapostopv()); + histos.fill(HIST("MCCasc/XiPlus/hDCANegToPV"), casc.dcanegtopv()); + histos.fill(HIST("MCCasc/XiPlus/hDCABachToPV"), casc.dcabachtopv()); + histos.fill(HIST("MCCasc/XiPlus/hDCAXYCascToPV"), casc.dcaXYCascToPV()); + histos.fill(HIST("MCCasc/XiPlus/hDCAZCascToPV"), casc.dcaZCascToPV()); + histos.fill(HIST("MCCasc/XiPlus/hDCAV0ToPV"), casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ())); + histos.fill(HIST("MCCasc/XiPlus/hDCAV0Dau"), casc.dcaV0daughters()); + histos.fill(HIST("MCCasc/XiPlus/hDCACascDau"), casc.dcacascdaughters()); + histos.fill(HIST("MCCasc/XiPlus/hLambdaMass"), casc.mLambda()); + } + if (cascMC.pdgCode() == 3334) { // OmegaMinus + histos.fill(HIST("MCCasc/OmegaMinus/h2dpTResolution"), pT, pT - cascMC.ptMC()); + histos.fill(HIST("MCCasc/OmegaMinus/h2dMass"), pT, casc.mOmega()); + histos.fill(HIST("MCCasc/OmegaMinus/h2dV0TPCSignal"), casc.positivept(), posTrack.tpcSignal()); + histos.fill(HIST("MCCasc/OmegaMinus/h2dV0TPCSignal"), -1 * casc.negativept(), negTrack.tpcSignal()); + histos.fill(HIST("MCCasc/OmegaMinus/h2dBachTPCSignal"), casc.bachelorpt(), bachTrack.tpcSignal()); + histos.fill(HIST("MCCasc/OmegaMinus/hV0Radius"), casc.v0radius()); + histos.fill(HIST("MCCasc/OmegaMinus/hCascRadius"), casc.cascradius()); + histos.fill(HIST("MCCasc/OmegaMinus/hV0CosPA"), casc.v0cosPA(casc.x(), casc.y(), casc.z())); + histos.fill(HIST("MCCasc/OmegaMinus/hCascCosPA"), casc.casccosPA(casc.x(), casc.y(), casc.z())); + histos.fill(HIST("MCCasc/OmegaMinus/hDCAPosToPV"), casc.dcapostopv()); + histos.fill(HIST("MCCasc/OmegaMinus/hDCANegToPV"), casc.dcanegtopv()); + histos.fill(HIST("MCCasc/OmegaMinus/hDCABachToPV"), casc.dcabachtopv()); + histos.fill(HIST("MCCasc/OmegaMinus/hDCAXYCascToPV"), casc.dcaXYCascToPV()); + histos.fill(HIST("MCCasc/OmegaMinus/hDCAZCascToPV"), casc.dcaZCascToPV()); + histos.fill(HIST("MCCasc/OmegaMinus/hDCAV0ToPV"), casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ())); + histos.fill(HIST("MCCasc/OmegaMinus/hDCAV0Dau"), casc.dcaV0daughters()); + histos.fill(HIST("MCCasc/OmegaMinus/hDCACascDau"), casc.dcacascdaughters()); + histos.fill(HIST("MCCasc/OmegaMinus/hLambdaMass"), casc.mLambda()); + } + if (cascMC.pdgCode() == -3334) { // OmegaPlus + histos.fill(HIST("MCCasc/OmegaPlus/h2dpTResolution"), pT, pT - cascMC.ptMC()); + histos.fill(HIST("MCCasc/OmegaPlus/h2dMass"), pT, casc.mOmega()); + histos.fill(HIST("MCCasc/OmegaPlus/h2dV0TPCSignal"), casc.positivept(), posTrack.tpcSignal()); + histos.fill(HIST("MCCasc/OmegaPlus/h2dV0TPCSignal"), -1 * casc.negativept(), negTrack.tpcSignal()); + histos.fill(HIST("MCCasc/OmegaPlus/h2dBachTPCSignal"), casc.bachelorpt(), bachTrack.tpcSignal()); + histos.fill(HIST("MCCasc/OmegaPlus/hV0Radius"), casc.v0radius()); + histos.fill(HIST("MCCasc/OmegaPlus/hCascRadius"), casc.cascradius()); + histos.fill(HIST("MCCasc/OmegaPlus/hV0CosPA"), casc.v0cosPA(casc.x(), casc.y(), casc.z())); + histos.fill(HIST("MCCasc/OmegaPlus/hCascCosPA"), casc.casccosPA(casc.x(), casc.y(), casc.z())); + histos.fill(HIST("MCCasc/OmegaPlus/hDCAPosToPV"), casc.dcapostopv()); + histos.fill(HIST("MCCasc/OmegaPlus/hDCANegToPV"), casc.dcanegtopv()); + histos.fill(HIST("MCCasc/OmegaPlus/hDCABachToPV"), casc.dcabachtopv()); + histos.fill(HIST("MCCasc/OmegaPlus/hDCAXYCascToPV"), casc.dcaXYCascToPV()); + histos.fill(HIST("MCCasc/OmegaPlus/hDCAZCascToPV"), casc.dcaZCascToPV()); + histos.fill(HIST("MCCasc/OmegaPlus/hDCAV0ToPV"), casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ())); + histos.fill(HIST("MCCasc/OmegaPlus/hDCAV0Dau"), casc.dcaV0daughters()); + histos.fill(HIST("MCCasc/OmegaPlus/hDCACascDau"), casc.dcacascdaughters()); + histos.fill(HIST("MCCasc/OmegaPlus/hLambdaMass"), casc.mLambda()); + } + } + } + + // ______________________________________________________ + // Simulated processing (subscribes to MC information too) + void processGenerated(soa::Join const& mcCollisions, soa::Join const& V0MCCores, soa::Join const& CascMCCores, soa::Join const& collisions) + { + fillGeneratedEventProperties(mcCollisions, collisions); + std::vector listBestCollisionIdx = getListOfRecoCollIndices(mcCollisions, collisions); + for (auto const& v0MC : V0MCCores) { + if (!v0MC.has_straMCCollision()) + continue; + + if (!v0MC.isPhysicalPrimary()) + continue; + + float ptmc = v0MC.ptMC(); + float ymc = 1e3; + if (v0MC.pdgCode() == 310) + ymc = v0MC.rapidityMC(0); + else if (TMath::Abs(v0MC.pdgCode()) == 3122) + ymc = v0MC.rapidityMC(1); + + if (TMath::Abs(ymc) > v0Selections.rapidityCut) + continue; + + auto mcCollision = v0MC.straMCCollision_as>(); + if (doPPAnalysis) { // we are in pp + if (eventSelections.requireINEL0 && mcCollision.multMCNParticlesEta10() < 1) { + continue; + } + + if (eventSelections.requireINEL1 && mcCollision.multMCNParticlesEta10() < 2) { + continue; + } + } + + float centrality = 100.5f; + if (listBestCollisionIdx[mcCollision.globalIndex()] > -1) { + auto collision = collisions.iteratorAt(listBestCollisionIdx[mcCollision.globalIndex()]); + centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + + if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) { + continue; + } + if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { + continue; + } + + if (v0MC.pdgCode() == 310) { + histos.fill(HIST("GenMC/h2dGenK0ShortVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCode() == 3122) { + histos.fill(HIST("GenMC/h2dGenLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCode() == -3122) { + histos.fill(HIST("GenMC/h2dGenAntiLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + if (v0MC.pdgCode() == 22) { + histos.fill(HIST("GenMC/h2dGenGamma"), centrality, ptmc); + histos.fill(HIST("GenMC/h2dGenGammaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCode() == 310) { + histos.fill(HIST("GenMC/h2dGenK0Short"), centrality, ptmc); + histos.fill(HIST("GenMC/h2dGenK0ShortVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCode() == 3122) { + histos.fill(HIST("GenMC/h2dGenLambda"), centrality, ptmc); + histos.fill(HIST("GenMC/h2dGenLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCode() == -3122) { + histos.fill(HIST("GenMC/h2dGenAntiLambda"), centrality, ptmc); + histos.fill(HIST("GenMC/h2dGenAntiLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + + for (auto const& cascMC : CascMCCores) { + if (!cascMC.has_straMCCollision()) + continue; + + if (!cascMC.isPhysicalPrimary()) + continue; + + float ptmc = cascMC.ptMC(); + float ymc = 1e3; + if (TMath::Abs(cascMC.pdgCode()) == 3312) + ymc = cascMC.rapidityMC(0); + else if (TMath::Abs(cascMC.pdgCode()) == 3334) + ymc = cascMC.rapidityMC(2); + + if (TMath::Abs(ymc) > v0Selections.rapidityCut) + continue; + + auto mcCollision = cascMC.straMCCollision_as>(); + if (doPPAnalysis) { // we are in pp + if (eventSelections.requireINEL0 && mcCollision.multMCNParticlesEta10() < 1) { + continue; + } + + if (eventSelections.requireINEL1 && mcCollision.multMCNParticlesEta10() < 2) { + continue; + } + } + + float centrality = 100.5f; + if (listBestCollisionIdx[mcCollision.globalIndex()] > -1) { + auto collision = collisions.iteratorAt(listBestCollisionIdx[mcCollision.globalIndex()]); + centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + + if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) { + continue; + } + if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { + continue; + } + + if (cascMC.pdgCode() == 3312) { + histos.fill(HIST("GenMC/h2dGenXiMinusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == -3312) { + histos.fill(HIST("GenMC/h2dGenXiPlusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == 3334) { + histos.fill(HIST("GenMC/h2dGenOmegaMinusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == -3334) { + histos.fill(HIST("GenMC/h2dGenOmegaPlusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + + if (cascMC.pdgCode() == 3312) { + histos.fill(HIST("GenMC/h2dGenXiMinus"), centrality, ptmc); + histos.fill(HIST("GenMC/h2dGenXiMinusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == -3312) { + histos.fill(HIST("GenMC/h2dGenXiPlus"), centrality, ptmc); + histos.fill(HIST("GenMC/h2dGenXiPlusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == 3334) { + histos.fill(HIST("GenMC/h2dGenOmegaMinus"), centrality, ptmc); + histos.fill(HIST("GenMC/h2dGenOmegaMinusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == -3334) { + histos.fill(HIST("GenMC/h2dGenOmegaPlus"), centrality, ptmc); + histos.fill(HIST("GenMC/h2dGenOmegaPlusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + } + + PROCESS_SWITCH(strderivedGenQA, processDerivedV0s, "Process derived data", true); + PROCESS_SWITCH(strderivedGenQA, processMCDerivedV0s, "Process derived data", false); + PROCESS_SWITCH(strderivedGenQA, processDerivedCascades, "Process derived data", true); + PROCESS_SWITCH(strderivedGenQA, processMCDerivedCascades, "Process derived data", false); + PROCESS_SWITCH(strderivedGenQA, processGenerated, "process MC generated", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/QC/tracked_cascade_properties.cxx b/PWGLF/Tasks/QC/tracked_cascade_properties.cxx new file mode 100644 index 00000000000..e2f93dbe481 --- /dev/null +++ b/PWGLF/Tasks/QC/tracked_cascade_properties.cxx @@ -0,0 +1,241 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \author Alberto Caliva (alberto.caliva@cern.ch), Francesca Ercolessi (francesca.ercolessi@cern.ch) +/// \since May 31, 2024 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/DCA.h" +#define mXi 1.32171 +#define mOmega 1.67245 + +using namespace std; +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; +using std::array; + +using SelectedCollisions = soa::Join; + +using FullTracks = soa::Join; + +struct tracked_cascade_properties { + + // QC Histograms + HistogramRegistry registryQC{ + "registryQC", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; + + // Analysis Histograms: Data + HistogramRegistry registryData{ + "registryData", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; + + // Global Parameters + Configurable zVtx{"zVtx", 10.0f, "z vertex cut"}; + + // Cascade Parameters + Configurable minimumCascRadius{"minimumCascRadius", 5.0f, "Minimum Cascade Radius"}; + Configurable maximumCascRadius{"maximumCascRadius", 18.0f, "Maximum Cascade Radius"}; + + // Mass Cuts + Configurable mMin_xi{"mMin_xi", 1.315f, "mMin Xi"}; + Configurable mMax_xi{"mMax_xi", 1.328f, "mMax Xi"}; + Configurable mMin_omega{"mMin_omega", 1.665f, "mMin Omega"}; + Configurable mMax_omega{"mMax_omega", 1.680f, "mMax Omega"}; + + void init(InitContext const&) + { + registryQC.add("matchingChi2", "matching Chi2", HistType::kTH1F, {{200, 0, 1000, "#chi^{2}_{matching}"}}); + registryQC.add("topologyChi2", "topology Chi2", HistType::kTH1F, {{500, 0, 0.5, "#chi^{2}_{topology}"}}); + registryQC.add("nITScls_vs_p_xi", "nITS Xi", HistType::kTH2F, {{100, 0, 10, "#it{p} (GeV/#it{c})"}, {8, 0, 8, "n_{ITS}^{cls}"}}); + registryQC.add("nITScls_vs_p_omega", "nITS Omega", HistType::kTH2F, {{100, 0, 10, "#it{p} (GeV/#it{c})"}, {8, 0, 8, "n_{ITS}^{cls}"}}); + registryQC.add("decayXY", "decayXY", HistType::kTH2F, {{500, -50, 50, "x"}, {500, -50, 50, "y"}}); + registryQC.add("deltaClsSize", "deltaClsSize", HistType::kTH1F, {{40, -20, 20, "#DeltaClsSize"}}); + registryQC.add("deltaP", "deltaP", HistType::kTH1F, {{1000, -1, 1, "#Deltap"}}); + registryQC.add("deltaEta", "deltaEta", HistType::kTH1F, {{200, -0.5, 0.5, "#Delta#eta"}}); + registryQC.add("deltaNclsITS", "deltaNclsITS", HistType::kTH1F, {{20, -10, 10, "#DeltaN"}}); + registryQC.add("deltaNclsITS_track", "deltaNclsITS_track", HistType::kTH1F, {{20, -10, 10, "#DeltaN"}}); + registryQC.add("deltaNclsITS_itstrack", "deltaNclsITS_itstrack", HistType::kTH1F, {{20, -10, 10, "#DeltaN"}}); + + registryData.add("number_of_events_data", "number of events in data", HistType::kTH1F, {{5, 0, 5, "Event Cuts"}}); + registryData.add("xi_pos_avgclustersize", "xi_pos_avgclustersize", HistType::kTH3F, {{100, 0.0, 10.0, "#it{p} (GeV/#it{c})"}, {100, 0.0, 20.0, "#LT ITS cluster size #GT"}, {16, -0.8, 0.8, "#eta"}}); + registryData.add("xi_neg_avgclustersize", "xi_neg_avgclustersize", HistType::kTH3F, {{100, 0.0, 10.0, "#it{p} (GeV/#it{c})"}, {100, 0.0, 20.0, "#LT ITS cluster size #GT"}, {16, -0.8, 0.8, "#eta"}}); + registryData.add("omega_pos_avgclustersize", "omega_pos_avgclustersize", HistType::kTH3F, {{100, 0.0, 10.0, "#it{p} (GeV/#it{c})"}, {100, 0.0, 20.0, "#LT ITS cluster size #GT"}, {16, -0.8, 0.8, "#eta"}}); + registryData.add("omega_neg_avgclustersize", "omega_neg_avgclustersize", HistType::kTH3F, {{100, 0.0, 10.0, "#it{p} (GeV/#it{c})"}, {100, 0.0, 20.0, "#LT ITS cluster size #GT"}, {16, -0.8, 0.8, "#eta"}}); + + registryData.add("xi_pos_avgclustersize_cosL", "xi_pos_avgclustersize_cosL", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p} (GeV/#it{c})"}, {100, 0.0, 20.0, "#LT ITS cluster size #GT cos(#lambda)"}}); + registryData.add("xi_neg_avgclustersize_cosL", "xi_neg_avgclustersize_cosL", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p} (GeV/#it{c})"}, {100, 0.0, 20.0, "#LT ITS cluster size #GT cos(#lambda)"}}); + registryData.add("omega_pos_avgclustersize_cosL", "omega_pos_avgclustersize_cosL", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p} (GeV/#it{c})"}, {100, 0.0, 20.0, "#LT ITS cluster size #GT cos(#lambda)"}}); + registryData.add("omega_neg_avgclustersize_cosL", "omega_neg_avgclustersize_cosL", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p} (GeV/#it{c})"}, {100, 0.0, 20.0, "#LT ITS cluster size #GT cos(#lambda)"}}); + + registryData.add("xi_pos_avgclustersize_cosL_vs_betagamma", "xi_pos_avgclustersize_cosL_vs_betagamma", HistType::kTH2F, {{200, 0.0, 10.0, "#beta#gamma"}, {100, 0.0, 20.0, "#LT ITS cluster size #GT cos(#lambda)"}}); + registryData.add("xi_neg_avgclustersize_cosL_vs_betagamma", "xi_neg_avgclustersize_cosL_vs_betagamma", HistType::kTH2F, {{200, 0.0, 10.0, "#beta#gamma"}, {100, 0.0, 20.0, "#LT ITS cluster size #GT cos(#lambda)"}}); + registryData.add("omega_pos_avgclustersize_cosL_vs_betagamma", "omega_pos_avgclustersize_cosL_vs_betagamma", HistType::kTH2F, {{200, 0.0, 10.0, "#beta#gamma"}, {100, 0.0, 20.0, "#LT ITS cluster size #GT cos(#lambda)"}}); + registryData.add("omega_neg_avgclustersize_cosL_vs_betagamma", "omega_neg_avgclustersize_cosL_vs_betagamma", HistType::kTH2F, {{200, 0.0, 10.0, "#beta#gamma"}, {100, 0.0, 20.0, "#LT ITS cluster size #GT cos(#lambda)"}}); + + registryData.add("xi_mass_pos", "xi_mass_pos", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p} (GeV/#it{c})"}, {200, 1.28, 1.36, "m_{p#pi#pi} (GeV/#it{c}^{2})"}}); + registryData.add("xi_mass_neg", "xi_mass_neg", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p} (GeV/#it{c})"}, {200, 1.28, 1.36, "m_{p#pi#pi} (GeV/#it{c}^{2})"}}); + registryData.add("omega_mass_pos", "omega_mass_pos", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p} (GeV/#it{c})"}, {200, 1.63, 1.71, "m_{p#piK} (GeV/#it{c}^{2})"}}); + registryData.add("omega_mass_neg", "omega_mass_neg", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p} (GeV/#it{c})"}, {200, 1.63, 1.71, "m_{p#piK} (GeV/#it{c}^{2})"}}); + } + + double track_inclination(double eta) + { + double lambda(0); + double theta = 2.0 * atan(exp(-eta)); + if (theta <= TMath::Pi() / 2.0) + lambda = 0.5 * TMath::Pi() - theta; + if (theta > TMath::Pi() / 2.0) + lambda = theta - 0.5 * TMath::Pi(); + return lambda; + } + + void processData(SelectedCollisions::iterator const& collision, aod::AssignedTrackedCascades const& trackedCascades, + aod::Cascades const&, FullTracks const&) + { + registryData.fill(HIST("number_of_events_data"), 0.5); + if (!collision.sel8()) + return; + + registryData.fill(HIST("number_of_events_data"), 1.5); + if (abs(collision.posZ()) > zVtx) + return; + + registryData.fill(HIST("number_of_events_data"), 2.5); + + for (const auto& trackedCascade : trackedCascades) { + + const auto track = trackedCascade.track_as(); + const auto trackITS = trackedCascade.itsTrack_as(); + + // Comparison between track and ITStrack + registryQC.fill(HIST("deltaP"), track.p() - trackITS.p()); + registryQC.fill(HIST("deltaEta"), track.eta() - trackITS.eta()); + registryQC.fill(HIST("deltaNclsITS"), track.itsNCls() - trackITS.itsNCls()); + for (int i = 0; i < 7; i++) { + registryQC.fill(HIST("deltaClsSize"), track.itsClsSizeInLayer(i) - trackITS.itsClsSizeInLayer(i)); + } + + const auto& casc = trackedCascade.cascade(); + const auto& btrack = casc.bachelor_as(); + double dx = trackedCascade.decayX(); + double dy = trackedCascade.decayY(); + double r = sqrt(dx * dx + dy * dy); + if (r < minimumCascRadius || r > maximumCascRadius) + continue; + + registryQC.fill(HIST("matchingChi2"), trackedCascade.matchingChi2()); + registryQC.fill(HIST("topologyChi2"), trackedCascade.topologyChi2()); + registryQC.fill(HIST("decayXY"), dx, dy); + + // Calculate (Average) Cluster Size + double averageClusterSize(0); + int nCls(0); + for (int i = 0; i < 7; i++) { + int clusterSize = trackITS.itsClsSizeInLayer(i); + averageClusterSize += static_cast(clusterSize); + if (clusterSize > 0) + nCls++; + } + averageClusterSize = averageClusterSize / static_cast(nCls); + + registryQC.fill(HIST("deltaNclsITS_track"), nCls - track.itsNCls()); + registryQC.fill(HIST("deltaNclsITS_itstrack"), nCls - trackITS.itsNCls()); + + // Xi Mass + if (btrack.sign() > 0) { + registryData.fill(HIST("xi_mass_pos"), track.p(), trackedCascade.xiMass()); + } + if (btrack.sign() < 0) { + registryData.fill(HIST("xi_mass_neg"), track.p(), trackedCascade.xiMass()); + } + + // Track Inclination + double lambda = track_inclination(track.eta()); + + // Xi + if (trackedCascade.xiMass() > mMin_xi && trackedCascade.xiMass() < mMax_xi) { + registryQC.fill(HIST("nITScls_vs_p_xi"), track.p(), trackITS.itsNCls()); + if (btrack.sign() > 0) { + registryData.fill(HIST("xi_pos_avgclustersize"), track.p(), averageClusterSize, track.eta()); + registryData.fill(HIST("xi_pos_avgclustersize_cosL"), track.p(), averageClusterSize * cos(lambda)); + registryData.fill(HIST("xi_pos_avgclustersize_cosL_vs_betagamma"), track.p() / mXi, averageClusterSize * cos(lambda)); + } + if (btrack.sign() < 0) { + registryData.fill(HIST("xi_neg_avgclustersize"), track.p(), averageClusterSize, track.eta()); + registryData.fill(HIST("xi_neg_avgclustersize_cosL"), track.p(), averageClusterSize * cos(lambda)); + registryData.fill(HIST("xi_neg_avgclustersize_cosL_vs_betagamma"), track.p() / mXi, averageClusterSize * cos(lambda)); + } + continue; + } + + // Omega Mass + if (btrack.sign() > 0) { + registryData.fill(HIST("omega_mass_pos"), track.p(), trackedCascade.omegaMass()); + } + if (btrack.sign() < 0) { + registryData.fill(HIST("omega_mass_neg"), track.p(), trackedCascade.omegaMass()); + } + + // Omega + if (trackedCascade.omegaMass() > mMin_omega && trackedCascade.omegaMass() < mMax_omega) { + registryQC.fill(HIST("nITScls_vs_p_omega"), track.p(), trackITS.itsNCls()); + if (btrack.sign() > 0) { + registryData.fill(HIST("omega_pos_avgclustersize"), track.p(), averageClusterSize, track.eta()); + registryData.fill(HIST("omega_pos_avgclustersize_cosL"), track.p(), averageClusterSize * cos(lambda)); + registryData.fill(HIST("omega_pos_avgclustersize_cosL_vs_betagamma"), track.p() / mOmega, averageClusterSize * cos(lambda)); + } + if (btrack.sign() < 0) { + registryData.fill(HIST("omega_neg_avgclustersize"), track.p(), averageClusterSize, track.eta()); + registryData.fill(HIST("omega_neg_avgclustersize_cosL"), track.p(), averageClusterSize * cos(lambda)); + registryData.fill(HIST("omega_neg_avgclustersize_cosL_vs_betagamma"), track.p() / mOmega, averageClusterSize * cos(lambda)); + } + } + } + } + PROCESS_SWITCH(tracked_cascade_properties, processData, "Process data", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/QC/v0assoqa.cxx b/PWGLF/Tasks/QC/v0assoqa.cxx new file mode 100644 index 00000000000..fcfd8d59b01 --- /dev/null +++ b/PWGLF/Tasks/QC/v0assoqa.cxx @@ -0,0 +1,481 @@ +// 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. +// +// Strangeness-to-collision association tests +// +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "PWGLF/Utils/strangenessBuilderHelper.h" +#include "Common/Core/TPCVDriftManager.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Framework/ASoAHelpers.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +// using MyTracks = soa::Join; +using TracksCompleteIU = soa::Join; +using TracksCompleteIUMC = soa::Join; +using V0DataLabeled = soa::Join; +using CascMC = soa::Join; +using TraCascMC = soa::Join; +using RecoedMCCollisions = soa::Join; +using CollisionsWithEvSels = soa::Join; + +// For MC association in pre-selection +using LabeledTracksExtra = soa::Join; + +struct v0assoqa { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // helper object + o2::pwglf::strangenessBuilderHelper straHelper; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + + int mRunNumber; + o2::base::MatLayerCylSet* lut = nullptr; + + // for handling TPC-only tracks (photons) + o2::aod::common::TPCVDriftManager mVDriftMgr; + + // CCDB options + struct : ConfigurableGroup { + std::string prefix = "ccdb"; + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + } ccdbConfigurations; + + // V0 building options + struct : ConfigurableGroup { + std::string prefix = "v0BuilderOpts"; + Configurable moveTPCOnlyTracks{"moveTPCOnlyTracks", true, "if dealing with TPC-only tracks, move them according to TPC drift / time info"}; + + // baseline conditionals of V0 building + Configurable minCrossedRows{"minCrossedRows", -1, "minimum TPC crossed rows for daughter tracks"}; + Configurable dcanegtopv{"dcanegtopv", .0, "DCA Neg To PV"}; + Configurable dcapostopv{"dcapostopv", .0, "DCA Pos To PV"}; + Configurable v0cospa{"v0cospa", -2, "V0 CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0) + Configurable dcav0dau{"dcav0dau", 10000.0, "DCA V0 Daughters"}; + Configurable v0radius{"v0radius", 0.0, "v0radius"}; + Configurable maxDaughterEta{"maxDaughterEta", 5.0, "Maximum daughter eta (in abs value)"}; + } v0BuilderOpts; + + // cascade building options + struct : ConfigurableGroup { + std::string prefix = "cascadeBuilderOpts"; + // conditionals + Configurable minCrossedRows{"minCrossedRows", 50, "minimum TPC crossed rows for daughter tracks"}; + Configurable dcabachtopv{"dcabachtopv", .05, "DCA Bach To PV"}; + Configurable cascradius{"cascradius", 0.9, "cascradius"}; + Configurable casccospa{"casccospa", 0.95, "casccospa"}; + Configurable dcacascdau{"dcacascdau", 1.0, "DCA cascade Daughters"}; + Configurable lambdaMassWindow{"lambdaMassWindow", .010, "Distance from Lambda mass (does not apply to KF path)"}; + Configurable maxDaughterEta{"maxDaughterEta", 5.0, "Maximum daughter eta (in abs value)"}; + } cascadeBuilderOpts; + + //_______________________________________________________________________ + template + int findMotherFromLabels(int const& p1, int const& p2, const int expected_pdg1, const int expected_pdg2, const int expected_mother_pdg, TMCParticles const& mcparticles) + { + // encompasses a simple check for labels existing + if (p1 < 0 || p2 < 0) { + return -1; + } + auto mcParticle1 = mcparticles.rawIteratorAt(p1); + auto mcParticle2 = mcparticles.rawIteratorAt(p2); + return (findMother(mcParticle1, mcParticle2, expected_pdg1, expected_pdg2, expected_mother_pdg, mcparticles)); + } + + //_______________________________________________________________________ + template + int findMother(TMCParticle1 const& p1, TMCParticle2 const& p2, const int expected_pdg1, const int expected_pdg2, const int expected_mother_pdg, TMCParticles const& mcparticles) + { + if (p1.globalIndex() == p2.globalIndex()) + return -1; + if (p1.pdgCode() != expected_pdg1 || p2.pdgCode() != expected_pdg2) + return -1; + if (!p1.has_mothers() || !p2.has_mothers()) + return -1; + + int motherid1 = p1.mothersIds()[0]; + auto mother1 = mcparticles.iteratorAt(motherid1); + int mother1_pdg = mother1.pdgCode(); + int motherid2 = p2.mothersIds()[0]; + auto mother2 = mcparticles.iteratorAt(motherid2); + int mother2_pdg = mother2.pdgCode(); + + if (motherid1 != motherid2 || mother1_pdg != mother2_pdg || mother1_pdg != expected_mother_pdg) + return -1; + + return motherid1; + } + + void init(InitContext const&) + { + histos.add("hDuplicateCount", "hDuplicateCount", kTH1F, {{50, -0.5f, 49.5f}}); + histos.add("hDuplicateCountType7", "hDuplicateCountType7", kTH1F, {{50, -0.5f, 49.5f}}); + histos.add("hDuplicateCountType7allTPConly", "hDuplicateCountType7allTPConly", kTH1F, {{50, -0.5f, 49.5f}}); + + histos.add("hPhotonPt", "hPhotonPt", kTH1F, {{200, 0.0f, 20.0f}}); + histos.add("hPhotonPt_Duplicates", "hPhotonPt_Duplicates", kTH1F, {{200, 0.0f, 20.0f}}); + histos.add("hPhotonPt_withRecoedMcCollision", "hPhotonPt_withRecoedMcCollision", kTH1F, {{200, 0.0f, 20.0f}}); + histos.add("hPhotonPt_withCorrectCollisionCopy", "hPhotonPt_withCorrectCollisionCopy", kTH1F, {{200, 0.0f, 20.0f}}); + + histos.add("hPA_All", "hPA_All", kTH1F, {{100, 0.0f, 1.0f}}); + histos.add("hPA_Correct", "hPA_Correct", kTH1F, {{100, 0.0f, 1.0f}}); + + // 2D for vs pT + histos.add("hPAvsPt_All", "hPAvsPt_All", kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}); + histos.add("hPAvsPt_Correct", "hPAvsPt_Correct", kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}); + histos.add("hDCADaughtersvsPt_All", "hDCADaughtersvsPt_All", kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 5.0f}}); + histos.add("hDCADaughtersvsPt_Correct", "hDCADaughtersvsPt_Correct", kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 5.0f}}); + histos.add("hDCADaughters3DvsPt_All", "hDCADaughters3DvsPt_All", kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 5.0f}}); + histos.add("hDCADaughters3DvsPt_Correct", "hDCADaughters3DvsPt_Correct", kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 5.0f}}); + histos.add("hDCADaughtersXYvsPt_All", "hDCADaughtersXYvsPt_All", kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 5.0f}}); + histos.add("hDCADaughtersXYvsPt_Correct", "hDCADaughtersXYvsPt_Correct", kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 5.0f}}); + histos.add("hDCADaughtersZvsPt_All", "hDCADaughtersZvsPt_All", kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 5.0f}}); + histos.add("hDCADaughtersZvsPt_Correct", "hDCADaughtersZvsPt_Correct", kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 5.0f}}); + + // winner-takes-all criteria spectra + histos.add("hCorrect_BestPA", "hCorrect_BestPA", kTH1F, {{200, 0.0f, 20.0f}}); + histos.add("hCorrect_BestDCADau", "hCorrect_DCADau", kTH1F, {{200, 0.0f, 20.0f}}); + histos.add("hCorrect_BestDCADau3D", "hCorrect_DCADau3D", kTH1F, {{200, 0.0f, 20.0f}}); + histos.add("hCorrect_BestDCADauXY", "hCorrect_DCADauXY", kTH1F, {{200, 0.0f, 20.0f}}); + histos.add("hCorrect_BestDCADauZ", "hCorrect_DCADauZ", kTH1F, {{200, 0.0f, 20.0f}}); + histos.add("hCorrect_BestPAandDCADau3D", "hCorrect_BestPAandDCADau3D", kTH1F, {{200, 0.0f, 20.0f}}); + + ccdb->setURL(ccdbConfigurations.ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + // set V0 parameters in the helper + straHelper.v0selections.minCrossedRows = v0BuilderOpts.minCrossedRows; + straHelper.v0selections.dcanegtopv = v0BuilderOpts.dcanegtopv; + straHelper.v0selections.dcapostopv = v0BuilderOpts.dcapostopv; + straHelper.v0selections.v0cospa = v0BuilderOpts.v0cospa; + straHelper.v0selections.dcav0dau = v0BuilderOpts.dcav0dau; + straHelper.v0selections.v0radius = v0BuilderOpts.v0radius; + straHelper.v0selections.maxDaughterEta = v0BuilderOpts.maxDaughterEta; + + // set cascade parameters in the helper + straHelper.cascadeselections.minCrossedRows = cascadeBuilderOpts.minCrossedRows; + straHelper.cascadeselections.dcabachtopv = cascadeBuilderOpts.dcabachtopv; + straHelper.cascadeselections.cascradius = cascadeBuilderOpts.cascradius; + straHelper.cascadeselections.casccospa = cascadeBuilderOpts.casccospa; + straHelper.cascadeselections.dcacascdau = cascadeBuilderOpts.dcacascdau; + straHelper.cascadeselections.lambdaMassWindow = cascadeBuilderOpts.lambdaMassWindow; + straHelper.cascadeselections.maxDaughterEta = cascadeBuilderOpts.maxDaughterEta; + } + + template + bool initCCDB(aod::BCsWithTimestamps const& bcs, TCollisions const& collisions) + { + auto bc = collisions.size() ? collisions.begin().template bc_as() : bcs.begin(); + if (!bcs.size()) { + LOGF(warn, "No BC found, skipping this DF."); + return false; // signal to skip this DF + } + + if (mRunNumber == bc.runNumber()) { + return true; + } + + auto timestamp = bc.timestamp(); + o2::parameters::GRPMagField* grpmag = 0x0; + + grpmag = ccdb->getForTimeStamp(ccdbConfigurations.grpmagPath, timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConfigurations.grpmagPath << " of object GRPMagField for timestamp " << timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + + // Fetch magnetic field from ccdb for current collision + auto magneticField = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "Retrieved GRP for timestamp " << timestamp << " with magnetic field of " << magneticField << " kG"; + + // Set magnetic field value once known + straHelper.fitter.setBz(magneticField); + + // acquire LUT for this timestamp + LOG(info) << "Loading material look-up table for timestamp: " << timestamp; + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->getForTimeStamp(ccdbConfigurations.lutPath, timestamp)); + o2::base::Propagator::Instance()->setMatLUT(lut); + straHelper.lut = lut; + + LOG(info) << "Fully configured for run: " << bc.runNumber(); + // mmark this run as configured + mRunNumber = bc.runNumber(); + + // initialize only if needed, avoid unnecessary CCDB calls + mVDriftMgr.init(&ccdb->instance()); + mVDriftMgr.update(timestamp); + + return true; + } + + void process(soa::Join const& collisions, aod::McCollisions const& mcCollisions, aod::V0s const& V0s, LabeledTracksExtra const& tracks, aod::McParticles const& mcParticles, aod::BCsWithTimestamps const& bcs) + { + if (!initCCDB(bcs, collisions)) + return; + + std::vector v0tableGrouped = o2::pwglf::groupDuplicates(V0s); + + // determine map of McCollisions -> Collisions + std::vector> mcCollToColl(mcCollisions.size()); + for (auto const& collision : collisions) { + if (collision.mcCollisionId() > -1) { + // useful to determine if collision has been reconstructed afterwards + mcCollToColl[collision.mcCollisionId()].push_back(collision.globalIndex()); + } + } + + // simple inspection of grouped duplicates + for (size_t iV0 = 0; iV0 < v0tableGrouped.size(); iV0++) { + // base QA histograms + histos.fill(HIST("hDuplicateCount"), v0tableGrouped[iV0].collisionIds.size()); + if (v0tableGrouped[iV0].v0Type == 7) { + histos.fill(HIST("hDuplicateCountType7"), v0tableGrouped[iV0].collisionIds.size()); + } + + // Monte Carlo exclusive: process + auto pTrack = tracks.rawIteratorAt(v0tableGrouped[iV0].posTrackId); + auto nTrack = tracks.rawIteratorAt(v0tableGrouped[iV0].negTrackId); + bool pTrackTPCOnly = (pTrack.hasTPC() && !pTrack.hasITS() && !pTrack.hasTRD() && !pTrack.hasTOF()); + bool nTrackTPCOnly = (nTrack.hasTPC() && !nTrack.hasITS() && !nTrack.hasTRD() && !nTrack.hasTOF()); + + if (v0tableGrouped[iV0].v0Type == 7 && pTrackTPCOnly && nTrackTPCOnly) { + histos.fill(HIST("hDuplicateCountType7allTPConly"), v0tableGrouped[iV0].collisionIds.size()); + } + + int pTrackLabel = pTrack.mcParticleId(); + int nTrackLabel = nTrack.mcParticleId(); + int v0Label = findMotherFromLabels(pTrackLabel, nTrackLabel, -11, 11, 22, mcParticles); + int correctMcCollision = -1; + if (v0Label > -1) { + // this mc particle exists and is a gamma + auto mcV0 = mcParticles.rawIteratorAt(v0Label); + correctMcCollision = mcV0.mcCollisionId(); + + histos.fill(HIST("hPhotonPt"), mcV0.pt()); + + if (mcCollToColl[mcV0.mcCollisionId()].size() > 0) { + histos.fill(HIST("hPhotonPt_withRecoedMcCollision"), mcV0.pt()); + } + + bool hasCorrectCollisionCopy = false; + for (size_t ic = 0; ic < v0tableGrouped[iV0].collisionIds.size(); ic++) { + for (size_t imcc = 0; imcc < mcCollToColl[mcV0.mcCollisionId()].size(); imcc++) { + if (v0tableGrouped[iV0].collisionIds[ic] == mcCollToColl[mcV0.mcCollisionId()][imcc]) { + hasCorrectCollisionCopy = true; + } + } + } + + if (hasCorrectCollisionCopy) { + histos.fill(HIST("hPhotonPt_withCorrectCollisionCopy"), mcV0.pt()); + } + + std::vector v0duplicates; // Vector of v0 candidate duplicates + std::vector v0duplicatesCorrectlyAssociated; + + // de-duplication strategy tests start here + // store best-of index for cross-checking strict de-duplication techniques + + float bestPointingAngle = .99; + float bestDCADaughters = 1e+6; + float bestDCADaughters3D = 1e+6; + float bestDCADaughtersXY = 1e+6; + float bestDCADaughtersZ = 1e+6; + + bool bestPointingAngleCorrect = false; + bool bestDCADaughtersCorrect = false; + bool bestDCADaughters3DCorrect = false; + bool bestDCADaughtersXYCorrect = false; + bool bestDCADaughtersZCorrect = false; + + // START OF MAIN DUPLICATE LOOP IS HERE + for (size_t ic = 0; ic < v0tableGrouped[iV0].collisionIds.size(); ic++) { + // simple duplicate accounting + histos.fill(HIST("hPhotonPt_Duplicates"), mcV0.pt()); + + // check if candidate is correctly associated + bool correctlyAssociated = false; + for (size_t imcc = 0; imcc < mcCollToColl[correctMcCollision].size(); imcc++) { + if (v0tableGrouped[iV0].collisionIds[ic] == mcCollToColl[correctMcCollision][imcc]) { + correctlyAssociated = true; + } + } + // store check for correct association + v0duplicatesCorrectlyAssociated.push_back(correctlyAssociated); + + // actually treat tracks + auto posTrackPar = getTrackParCov(pTrack); + auto negTrackPar = getTrackParCov(nTrack); + + auto const& collision = collisions.rawIteratorAt(v0tableGrouped[iV0].collisionIds[ic]); + + // handle TPC-only tracks properly (photon conversions) + if (v0BuilderOpts.moveTPCOnlyTracks) { + bool isPosTPCOnly = (pTrack.hasTPC() && !pTrack.hasITS() && !pTrack.hasTRD() && !pTrack.hasTOF()); + if (isPosTPCOnly) { + // Nota bene: positive is TPC-only -> this entire V0 merits treatment as photon candidate + posTrackPar.setPID(o2::track::PID::Electron); + negTrackPar.setPID(o2::track::PID::Electron); + + if (!mVDriftMgr.moveTPCTrack>(collision, pTrack, posTrackPar)) { + return; + } + } + + bool isNegTPCOnly = (nTrack.hasTPC() && !nTrack.hasITS() && !nTrack.hasTRD() && !nTrack.hasTOF()); + if (isNegTPCOnly) { + // Nota bene: negative is TPC-only -> this entire V0 merits treatment as photon candidate + posTrackPar.setPID(o2::track::PID::Electron); + negTrackPar.setPID(o2::track::PID::Electron); + + if (!mVDriftMgr.moveTPCTrack>(collision, nTrack, negTrackPar)) { + return; + } + } + } // end TPC drift treatment + + // process candidate with helper + bool buildOK = straHelper.buildV0Candidate(v0tableGrouped[iV0].collisionIds[ic], collision.posX(), collision.posY(), collision.posZ(), pTrack, nTrack, posTrackPar, negTrackPar, true, false); + + v0duplicates.push_back(straHelper.v0); + + float daughterDCA3D = std::hypot( + straHelper.v0.positivePosition[0] - straHelper.v0.negativePosition[0], + straHelper.v0.positivePosition[1] - straHelper.v0.negativePosition[1], + straHelper.v0.positivePosition[2] - straHelper.v0.negativePosition[2]); + float daughterDCAXY = std::hypot( + straHelper.v0.positivePosition[0] - straHelper.v0.negativePosition[0], + straHelper.v0.positivePosition[1] - straHelper.v0.negativePosition[1]); + float daughterDCAZ = std::abs( + straHelper.v0.positivePosition[2] - straHelper.v0.negativePosition[2]); + + if (!buildOK) { + daughterDCA3D = daughterDCAXY = daughterDCAZ = 1e+6; + } + + histos.fill(HIST("hPA_All"), straHelper.v0.pointingAngle); + histos.fill(HIST("hPAvsPt_All"), mcV0.pt(), straHelper.v0.pointingAngle); + histos.fill(HIST("hDCADaughtersvsPt_All"), mcV0.pt(), straHelper.v0.daughterDCA); + histos.fill(HIST("hDCADaughters3DvsPt_All"), mcV0.pt(), daughterDCA3D); + histos.fill(HIST("hDCADaughtersXYvsPt_All"), mcV0.pt(), daughterDCAXY); + histos.fill(HIST("hDCADaughtersZvsPt_All"), mcV0.pt(), daughterDCAZ); + + if (correctlyAssociated) { + histos.fill(HIST("hPA_Correct"), straHelper.v0.pointingAngle); + histos.fill(HIST("hPAvsPt_Correct"), mcV0.pt(), straHelper.v0.pointingAngle); + histos.fill(HIST("hDCADaughtersvsPt_Correct"), mcV0.pt(), straHelper.v0.daughterDCA); + histos.fill(HIST("hDCADaughters3DvsPt_Correct"), mcV0.pt(), daughterDCA3D); + histos.fill(HIST("hDCADaughtersXYvsPt_Correct"), mcV0.pt(), daughterDCAXY); + histos.fill(HIST("hDCADaughtersZvsPt_Correct"), mcV0.pt(), daughterDCAZ); + } + + // check criteria + if (straHelper.v0.pointingAngle < bestPointingAngle) { + bestPointingAngle = straHelper.v0.pointingAngle; + bestPointingAngleCorrect = correctlyAssociated; + } + if (straHelper.v0.daughterDCA < bestDCADaughters) { + bestDCADaughters = straHelper.v0.daughterDCA; + bestDCADaughtersCorrect = correctlyAssociated; + } + if (daughterDCA3D < bestDCADaughters3D) { + bestDCADaughters3D = daughterDCA3D; + bestDCADaughters3DCorrect = correctlyAssociated; + } + if (daughterDCAXY < bestDCADaughtersXY) { + bestDCADaughtersXY = daughterDCAXY; + bestDCADaughtersXYCorrect = correctlyAssociated; + } + if (daughterDCAZ < bestDCADaughtersZ) { + bestDCADaughtersZ = daughterDCAZ; + bestDCADaughtersZCorrect = correctlyAssociated; + } + } // end duplicate loop + + if (hasCorrectCollisionCopy) { + // check individual criteria for winner-is-correct + if (bestPointingAngleCorrect) { + histos.fill(HIST("hCorrect_BestPA"), mcV0.pt()); + } + if (bestDCADaughtersCorrect) { + histos.fill(HIST("hCorrect_BestDCADau"), mcV0.pt()); + } + if (bestDCADaughters3DCorrect) { + histos.fill(HIST("hCorrect_BestDCADau3D"), mcV0.pt()); + } + if (bestDCADaughtersXYCorrect) { + histos.fill(HIST("hCorrect_BestDCADauXY"), mcV0.pt()); + } + if (bestDCADaughtersZCorrect) { + histos.fill(HIST("hCorrect_BestDCADauZ"), mcV0.pt()); + } + if (bestPointingAngleCorrect && bestDCADaughtersZCorrect) { + histos.fill(HIST("hCorrect_BestPAandDCADau3D"), mcV0.pt()); + } + } + + // printout for inspection + // TString cosPAString = ""; + // for (size_t iCollisionId = 0; iCollisionId < v0tableGrouped[iV0].collisionIds.size(); iCollisionId++) { + // cosPAString.Append(Form("%.5f ", v0duplicates[iCollisionId].pointingAngle)); + // } + // LOGF(info, "#%i (p,n) = (%i,%i), type %i, point. angles: %s", iV0, v0tableGrouped[iV0].posTrackId, v0tableGrouped[iV0].negTrackId, v0tableGrouped[iV0].v0Type, cosPAString.Data()); + } // end this-is-a-mc-gamma check + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/QC/vertexQA.cxx b/PWGLF/Tasks/QC/vertexQA.cxx index 5e9060d51ce..66ae298813d 100644 --- a/PWGLF/Tasks/QC/vertexQA.cxx +++ b/PWGLF/Tasks/QC/vertexQA.cxx @@ -9,14 +9,18 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include #include -#include #include -#include +#include +#include +#include -#include "Framework/runDataProcessing.h" +#include "CCDB/BasicCCDBManager.h" +#include "Common/CCDB/ctpRateFetcher.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" using namespace o2; using namespace o2::framework; @@ -34,7 +38,7 @@ double deltaTimeColl(BCcoll const bccoll1, BCcoll const bccoll2) auto coll2 = std::get(bccoll2); auto bc1 = std::get(bccoll1); auto bc2 = std::get(bccoll2); - int64_t tmpDT = int64_t(bc1.globalBC()) - int64_t(bc2.globalBC()); + int64_t tmpDT = static_cast(bc1.globalBC()) - static_cast(bc2.globalBC()); double deltaT = tmpDT * LHCBunchSpacingNS + coll1.collisionTime() - coll2.collisionTime(); return deltaT; } @@ -57,6 +61,9 @@ DECLARE_SOA_TABLE(VtxQAtable, "AOD", "VTXQATABLE", } // namespace o2::aod struct vertexQA { + Service ccdb; + ctpRateFetcher mRateFetcher; + Produces vtxQAtable; Configurable storeTree{"storeTree", 1000, "Store in tree collisions from BC's with more than 'storeTree' vertices, for in-depth analysis"}; @@ -87,10 +94,15 @@ struct vertexQA { ConfigurableAxis nContribAxis{"nContribBins", {1000, 0, 5000}, "Binning for number of contributors to PV"}; ConfigurableAxis nContribDiffAxis{"nContribDiffBins", {1000, -5000, 5000}, "Binning for the difference in number of contributors to PV"}; + ConfigurableAxis irBinning{"IRbinning", {500, 0, 100}, "Binning for the interaction rate (kHz)"}; + Configurable irSource{"irSource", "ZNC hadronic", "Source of the interaction rate"}; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; std::deque colls; + int64_t mFirstBCid = -1; + void init(InitContext const&) { histos.add("nVtxHistogram", ";#it{N}_{vtx}^{rec};Entries", HistType::kTH1F, {nVtxAxis}); @@ -121,6 +133,11 @@ struct vertexQA { histos.add("nContribITSRofTimeSeriesHistogram", ";#it{N}_{contrib}^{1};#it{N}_{contrib}^{2}", HistType::kTH2F, {nContribAxis, nContribAxis}); histos.add("tDiffDuplicateTimeSeriesHistogram", ";#Delta#it{t}_{vtx} (ns);Entries", HistType::kTH1F, {tDiffVtxAxisExtend}); + histos.add("tIRvsCollisionRateHistogram", Form(";IR from %s (kHz);IR from reconstructed vertices (kHz)", irSource.value.data()), HistType::kTH2D, {irBinning, irBinning}); + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); } void process(aod::BC const& bc, aod::Collisions const& collisions) @@ -231,6 +248,48 @@ struct vertexQA { } } } + PROCESS_SWITCH(vertexQA, process, "Standard vertex QA", true); + + void processIR(aod::BCsWithTimestamps const& bcs, aod::Collisions const& collisions) + { + if (collisions.size() <= 2) { + return; + } + + std::vector jumps{0ll}; + int64_t lastBC = bcs.rawIteratorAt(0).globalBC(); + for (auto bc : bcs) { + if (bc.globalBC() - lastBC > 3564 * 32) { // 32 orbits + jumps.push_back(bc.globalIndex()); + lastBC = bc.globalBC(); + } + } + uint64_t jumpsSentinel{1}; + std::vector collisionsIndices{0ll}; + for (auto col : collisions) { + if (jumpsSentinel == jumps.size()) { + break; + } + if (col.bcId() > jumps[jumpsSentinel]) { + collisionsIndices.push_back(col.globalIndex()); + jumpsSentinel++; + } + } + jumps.push_back(bcs.size()); + collisionsIndices.push_back(collisions.size()); + + for (size_t i{0}; i < jumps.size() - 1; ++i) { + auto startBC = bcs.rawIteratorAt(jumps[i]); + auto endBC = bcs.rawIteratorAt(jumps[i + 1] - 1); + double startIR = mRateFetcher.fetch(ccdb.service, startBC.timestamp(), startBC.runNumber(), irSource.value); + double endIR = mRateFetcher.fetch(ccdb.service, endBC.timestamp(), endBC.runNumber(), irSource.value); + double deltaT = (endBC.globalBC() - startBC.globalBC()) * LHCBunchSpacingNS * 1.e-9; + double collisionRate = (collisionsIndices[i + 1] - collisionsIndices[i]) / deltaT; /// -1 to remove the bias of the collisions at extremities? + double ir = (startIR + endIR) * 0.5; + histos.fill(HIST("tIRvsCollisionRateHistogram"), ir * 1.e-3, collisionRate * 1.e-3); + } + } + PROCESS_SWITCH(vertexQA, processIR, "Checks on interaction rate", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Resonances/CMakeLists.txt b/PWGLF/Tasks/Resonances/CMakeLists.txt index e6cc019ae50..aec43e97f65 100644 --- a/PWGLF/Tasks/Resonances/CMakeLists.txt +++ b/PWGLF/Tasks/Resonances/CMakeLists.txt @@ -24,6 +24,16 @@ o2physics_add_dpl_workflow(k892analysis PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(k892analysispbpb + SOURCES k892analysispbpb.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(kstar892analysis + SOURCES kstar892analysis.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(k892pmanalysis SOURCES k892pmanalysis.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -49,6 +59,11 @@ o2physics_add_dpl_workflow(f0980analysis PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(f0980pbpbanalysis + SOURCES f0980pbpbanalysis.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(lambda1520spherocityanalysis SOURCES lambda1520SpherocityAnalysis.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -85,7 +100,7 @@ o2physics_add_dpl_workflow(lambda1520-pbpb COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(kshortkshort - SOURCES KshortKshort.cxx + SOURCES higherMassResonances.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) @@ -119,18 +134,77 @@ o2physics_add_dpl_workflow(kstarpbpb PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(lstarpbpbv2 + SOURCES lstarpbpbv2.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(xi1530analysis SOURCES xi1530Analysis.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(xi1530analysisqa + SOURCES xi1530Analysisqa.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(kaonkaonanalysis SOURCES kaonkaonanalysis.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(highmasslambda +o2physics_add_dpl_workflow(highmasslambda SOURCES highmasslambda.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(lambdav2 + SOURCES lambdav2.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(highmasslambdasvx + SOURCES highmasslambdasvx.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(chk892flow + SOURCES chk892Flow.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(chk892pp + SOURCES chk892pp.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(doublephimeson + SOURCES doublephimeson.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(kshortlambda + SOURCES kshortlambda.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(rho770analysis + SOURCES rho770analysis.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(kstarpbpbv1 + SOURCES kstarFlowv1.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(heptaquark + SOURCES heptaquark.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(double-resonance-scan + SOURCES doubleResonanceScan.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGLF/Tasks/Resonances/KshortKshort.cxx b/PWGLF/Tasks/Resonances/KshortKshort.cxx deleted file mode 100644 index 18e0f657447..00000000000 --- a/PWGLF/Tasks/Resonances/KshortKshort.cxx +++ /dev/null @@ -1,645 +0,0 @@ -// 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 glueball resonance -/// \author Sawan (sawan.sawan@cern.ch) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "TF1.h" - -#include -#include -#include - -#include "Common/Core/TrackSelection.h" -#include "Common/Core/trackUtilities.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/StepTHn.h" -#include "ReconstructionDataFormats/Track.h" - -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/EventSelection.h" // -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponse.h" // -#include "Common/DataModel/TrackSelectionTables.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/AnalysisTask.h" // -#include "Framework/runDataProcessing.h" // -#include "PWGLF/DataModel/LFStrangenessTables.h" // -// #include "CommonConstants/PhysicsConstants.h" -// #include "Framework/HistogramRegistry.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::soa; -// using namespace o2::constants::physics; -using std::array; - -struct strangeness_tutorial { - SliceCache cache; - - HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rKzeroShort{"kzeroShort", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry hglue{"hglueball", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - - Configurable QAv0{"QAv0", false, "QAv0"}; - Configurable QAPID{"QAPID", false, "QAPID"}; - Configurable QAv0_daughters{"QAv0_daughters", false, "QA of v0 daughters"}; - Configurable inv_mass1D{"inv_mass1D", false, "1D invariant mass histograms"}; - Configurable DCAv0topv{"DCAv0topv", false, "DCA V0 to PV"}; - Configurable armcut{"armcut", true, "arm cut"}; - - // Configurable for event selection - Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; - Configurable cfgETAcut{"cfgETAcut", 0.8f, "Track ETA cut"}; - Configurable timFrameEvsel{"timFrameEvsel", false, "TPC Time frame boundary cut"}; - Configurable piluprejection{"piluprejection", false, "Pileup rejection"}; - Configurable goodzvertex{"goodzvertex", false, "removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference."}; - Configurable itstpctracks{"itstpctracks", false, "selects collisions with at least one ITS-TPC track,"}; - Configurable additionalEvsel{"additionalEvsel", false, "Additional event selcection"}; - - // Configurable parameters for V0 selection - Configurable ConfV0DCADaughMax{"ConfV0DCADaughMax", 1.0f, "DCA b/w V0 daughters"}; - Configurable v0setting_dcapostopv{"v0setting_dcapostopv", 0.06, "DCA Pos To PV"}; - Configurable v0setting_dcanegtopv{"v0setting_dcanegtopv", 0.06, "DCA Neg To PV"}; - Configurable cMaxV0DCA{"cMaxV0DCA", 1, "DCA V0 to PV"}; - // Configurable isStandarv0{"isStandarv0", false, "Standard V0"}; - // Configurable ConfDaughDCAMin{"ConfDaughDCAMin", 0.06f, "V0 Daugh sel: Max. DCA Daugh to PV (cm)"}; // same as DCA pos to pv and neg to pv - - Configurable ConfV0PtMin{"ConfV0PtMin", 0.f, "Minimum transverse momentum of V0"}; - Configurable ConfV0CPAMin{"ConfV0CPAMin", 0.97f, "Minimum CPA of V0"}; - Configurable ConfV0TranRadV0Min{"ConfV0TranRadV0Min", 0.5f, "Minimum transverse radius"}; - Configurable ConfV0TranRadV0Max{"ConfV0TranRadV0Max", 200.f, "Maximum transverse radius"}; - Configurable cMaxV0LifeTime{"cMaxV0LifeTime", 15, "Maximum V0 life time"}; - Configurable cSigmaMassKs0{"cSigmaMassKs0", 4, "n Sigma cut on Ks0 mass (Mass (Ks) - cSigmaMassKs0*cWidthKs0)"}; - Configurable cWidthKs0{"cWidthKs0", 0.005, "Width of KS0"}; - Configurable ConfDaughEta{"ConfDaughEta", 0.8f, "V0 Daugh sel: max eta"}; - Configurable ConfDaughTPCnclsMin{"ConfDaughTPCnclsMin", 70.f, "V0 Daugh sel: Min. nCls TPC"}; - Configurable ConfDaughPIDCuts{"ConfDaughPIDCuts", 5, "PID selections for KS0 daughters"}; - Configurable Confarmcut{"Confarmcut", 0.2f, "Armenteros cut"}; - Configurable ConfKsrapidity{"ConfKsrapidity", 0.5f, "Rapidity cut on K0s"}; - // Configurable lowmasscutks0{"lowmasscutks0", 0.497 - 4 * 0.005, "Low mass cut on K0s"}; - // Configurable highmasscutks0{"highmasscutks0", 0.497 + 4 * 0.005, "High mass cut on K0s"}; - - // Configurable for track selection and multiplicity - Configurable cfgPTcut{"cfgPTcut", 0.2f, "Track PT cut"}; - Configurable cfgNmixedEvents{"cfgNmixedEvents", 5, "Number of mixed events"}; - Configurable cfgMultFOTM{"cfgMultFOTM", true, "Use FOTM multiplicity if pp else use 0 here for PbPb (FT0C)"}; - ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 5., 10., 30., 50., 70., 100., 110., 150.}, "Binning of the centrality axis"}; - - // Other cuts on Ks and glueball - Configurable rapidityks{"rapidityks", true, "rapidity cut on K0s"}; - Configurable masslambda{"masslambda", false, "mass under lambda hypothesis"}; - Configurable competingcascrejlambda{"competingcascrejlambda", 4.3, "rejecting competing cascade lambda"}; - Configurable competingcascrejlambdaanti{"competingcascrejlambdaanti", 4.3, "rejecting competing cascade anti-lambda"}; - Configurable tpcCrossedrows{"tpcCrossedrows", 70, "TPC crossed rows"}; - Configurable tpcCrossedrowsOverfcls{"tpcCrossedrowsOverfcls", 0.8, "TPC crossed rows over findable clusters"}; - - // Mass and pT axis as configurables - Configurable cPtMin{"cPtMin", 0.0f, "Minimum pT"}; - Configurable cPtMax{"cPtMax", 15.0f, "Maximum pT"}; - Configurable cPtBins{"cPtBins", 150, "Number of pT bins"}; - Configurable cMassMin{"cMassMin", 0.9f, "Minimum mass of glueball"}; - Configurable cMassMax{"cMassMax", 2.4f, "Maximum mass of glueball"}; - Configurable cMassBins{"cMassBins", 150, "Number of mass bins for glueball"}; - Configurable ksMassMin{"ksMassMin", 0.45f, "Minimum mass of K0s"}; - Configurable ksMassMax{"ksMassMax", 0.55f, "Maximum mass of K0s"}; - Configurable ksMassBins{"ksMassBins", 200, "Number of mass bins for K0s"}; - - // Event selection cuts - Alex (Temporary, need to fix!) - TF1* fMultPVCutLow = nullptr; - TF1* fMultPVCutHigh = nullptr; - TF1* fMultCutLow = nullptr; - TF1* fMultCutHigh = nullptr; - TF1* fMultMultPVCut = nullptr; - - void init(InitContext const&) - { - // Axes - AxisSpec K0ShortMassAxis = {ksMassBins, ksMassMin, ksMassMax, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; - AxisSpec glueballMassAxis = {cMassBins, cMassMin, cMassMax, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; - AxisSpec vertexZAxis = {100, -15.f, 15.f, "vrtx_{Z} [cm]"}; // for histogram - AxisSpec ptAxis = {cPtBins, cPtMin, cPtMax, "#it{p}_{T} (GeV/#it{c})"}; - // AxisSpec multiplicityAxis = {110, 0.0f, 150.0f, "Multiplicity Axis"}; - AxisSpec multiplicityAxis = {binsCent, "Multiplicity Axis"}; - - // Histograms - // Event selection - rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); - rEventSelection.add("hmultiplicity", "hmultiplicity", {HistType::kTH1F, {{150, 0.0f, 150.0f}}}); - - if (inv_mass1D) { - hglue.add("h1glueInvMassDS", "h1glueInvMassDS", kTH1F, {glueballMassAxis}); - hglue.add("h1glueInvMassME", "h1glueInvMassME", kTH1F, {glueballMassAxis}); - } - hglue.add("h3glueInvMassDS", "h3glueInvMassDS", kTHnSparseF, {multiplicityAxis, ptAxis, glueballMassAxis}, true); - hglue.add("h3glueInvMassME", "h3glueInvMassME", kTHnSparseF, {multiplicityAxis, ptAxis, glueballMassAxis}, true); - hglue.add("heventscheck", "heventscheck", kTH1F, {{9, 0, 9}}); - - // K0s topological/PID cuts - if (QAv0) { - // Invariant Mass - rKzeroShort.add("hMassK0Shortbefore", "hMassK0Shortbefore", kTHnSparseF, {K0ShortMassAxis, ptAxis}); - rKzeroShort.add("hMassK0ShortSelected", "hMassK0ShortSelected", kTHnSparseF, {K0ShortMassAxis, ptAxis}); - // Topological histograms (after the selection) - rKzeroShort.add("hDCAV0Daughters", "DCA between v0 daughters", {HistType::kTH1F, {{60, -3.0f, 3.0f}}}); - rKzeroShort.add("hV0CosPA", "hV0CosPA", {HistType::kTH1F, {{100, 0.96f, 1.1f}}}); - rKzeroShort.add("hLT", "hLT", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); - rKzeroShort.add("Mass_lambda", "Mass under lambda hypothesis", kTH1F, {glueballMassAxis}); - rKzeroShort.add("mass_AntiLambda", "Mass under anti-lambda hypothesis", kTH1F, {glueballMassAxis}); - rKzeroShort.add("mass_Gamma", "Mass under Gamma hypothesis", kTH1F, {glueballMassAxis}); - // rKzeroShort.add("mass_Hypertriton", "Mass under hypertriton hypothesis", kTH1F, {glueballMassAxis}); - // rKzeroShort.add("mass_AnitHypertriton", "Mass under anti-hypertriton hypothesis", kTH1F, {glueballMassAxis}); - rKzeroShort.add("rapidity", "Rapidity distribution", kTH1F, {{100, -1.0f, 1.0f}}); - rKzeroShort.add("hv0radius", "hv0radius", kTH1F, {{100, 0.0f, 200.0f}}); - rKzeroShort.add("hDCApostopv", "DCA positive daughter to PV", kTH1F, {{1000, -10.0f, 10.0f}}); - rKzeroShort.add("hDCAnegtopv", "DCA negative daughter to PV", kTH1F, {{1000, -10.0f, 10.0f}}); - rKzeroShort.add("hDCAv0topv", "DCA V0 to PV", kTH1F, {{60, -3.0f, 3.0f}}); - rKzeroShort.add("halpha", "Armenteros alpha", kTH1F, {{100, -5.0f, 5.0f}}); - rKzeroShort.add("hqtarm", "qtarm", kTH1F, {{100, 0.0f, 1.0f}}); - rKzeroShort.add("hpsipair", "psi pair angle", kTH1F, {{100, -5.0f, 5.0f}}); - - // // Topological histograms (before the selection) - // rKzeroShort.add("hDCAV0Daughters_before", "DCA between v0 daughters before the selection", {HistType::kTH1F, {{60, -3.0f, 3.0f}}}); - // rKzeroShort.add("hV0CosPA_before", "hV0CosPA_before", {HistType::kTH1F, {{200, 0.91f, 1.1f}}}); - // rKzeroShort.add("hLT_before", "hLT_before", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); - } - if (QAPID) { - rKzeroShort.add("hNSigmaPosPionK0s_before", "hNSigmaPosPionK0s_before", {HistType::kTH2F, {{ptAxis}, {100, -5.f, 5.f}}}); - rKzeroShort.add("hNSigmaPosPionK0s_after", "hNSigmaPosPionK0s_after", {HistType::kTH2F, {{ptAxis}, {100, -5.f, 5.f}}}); - rKzeroShort.add("hNSigmaNegPionK0s_before", "hNSigmaNegPionK0s_before", {HistType::kTH2F, {{ptAxis}, {100, -5.f, 5.f}}}); - rKzeroShort.add("hNSigmaNegPionK0s_after", "hNSigmaNegPionK0s_after", {HistType::kTH2F, {{ptAxis}, {100, -5.f, 5.f}}}); - } - if (QAv0_daughters) { - rKzeroShort.add("negative_pt", "Negative daughter pT", kTH1F, {ptAxis}); - rKzeroShort.add("positive_pt", "Positive daughter pT", kTH1F, {ptAxis}); - rKzeroShort.add("negative_eta", "Negative daughter eta", kTH1F, {{100, -1.0f, 1.0f}}); - rKzeroShort.add("positive_eta", "Positive daughter eta", kTH1F, {{100, -1.0f, 1.0f}}); - rKzeroShort.add("negative_phi", "Negative daughter phi", kTH1F, {{70, 0.0f, 7.0f}}); - rKzeroShort.add("positive_phi", "Positive daughter phi", kTH1F, {{70, 0.0f, 7.0f}}); - } - if (additionalEvsel) { - fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); - fMultPVCutLow->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05); - fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); - fMultPVCutHigh->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05); - fMultCutLow = new TF1("fMultCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.5*([4]+[5]*x)", 0, 100); - fMultCutLow->SetParameters(1893.94, -53.86, 0.502913, -0.0015122, 109.625, -1.19253); - fMultCutHigh = new TF1("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 3.*([4]+[5]*x)", 0, 100); - fMultCutHigh->SetParameters(1893.94, -53.86, 0.502913, -0.0015122, 109.625, -1.19253); - fMultMultPVCut = new TF1("fMultMultPVCut", "[0]+[1]*x+[2]*x*x", 0, 5000); - fMultMultPVCut->SetParameters(-0.1, 0.785, -4.7e-05); - } - } - - template - bool eventselection(Collision const& collision, const float& multiplicity) - { - if (!collision.sel8()) { - return false; - } - if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { - return false; - } - if (piluprejection && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { - return false; - } - if (goodzvertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { - return false; - } - if (itstpctracks && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { - return false; - } - // if (collision.alias_bit(kTVXinTRD)) { - // // TRD triggered - // // return 0; - // } - auto multNTracksPV = collision.multNTracksPV(); - if (additionalEvsel && multNTracksPV < fMultPVCutLow->Eval(multiplicity)) { - return false; - } - if (additionalEvsel && multNTracksPV > fMultPVCutHigh->Eval(multiplicity)) { - return false; - } - // if (multTrk < fMultCutLow->Eval(multiplicity)) - // return 0; - // if (multTrk > fMultCutHigh->Eval(multiplicity)) - // return 0; - // if (multTrk > fMultMultPVCut->Eval(multNTracksPV)) - // return 0; - return true; - } - - template - bool SelectionV0(Collision const& collision, V0 const& candidate, - float /*multiplicity*/) - { - const float qtarm = candidate.qtarm(); - const float alph = candidate.alpha(); - float arm = qtarm / alph; - const float pT = candidate.pt(); - const float tranRad = candidate.v0radius(); - const float dcaDaughv0 = candidate.dcaV0daughters(); - const float cpav0 = candidate.v0cosPA(); - - float CtauK0s = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * TDatabasePDG::Instance()->GetParticle(kK0Short)->Mass(); // FIXME: Get from the common header - float lowmasscutks0 = 0.497 - cWidthKs0 * cSigmaMassKs0; - float highmasscutks0 = 0.497 + cWidthKs0 * cSigmaMassKs0; - // float decayLength = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * RecoDecay::sqrtSumOfSquares(candidate.px(), candidate.py(), candidate.pz()); - - if (QAv0) { - rKzeroShort.fill(HIST("hMassK0Shortbefore"), candidate.mK0Short(), candidate.pt()); - rKzeroShort.fill(HIST("hLT"), CtauK0s); - rKzeroShort.fill(HIST("hDCAV0Daughters"), candidate.dcaV0daughters()); - rKzeroShort.fill(HIST("hV0CosPA"), candidate.v0cosPA()); - rKzeroShort.fill(HIST("Mass_lambda"), candidate.mLambda()); - rKzeroShort.fill(HIST("mass_AntiLambda"), candidate.mAntiLambda()); - rKzeroShort.fill(HIST("mass_Gamma"), candidate.mGamma()); - // rKzeroShort.fill(HIST("mass_Hypertriton"), candidate.mHypertriton()); - // rKzeroShort.fill(HIST("mass_AnitHypertriton"), candidate.mAntiHypertriton()); - rKzeroShort.fill(HIST("rapidity"), candidate.yK0Short()); - rKzeroShort.fill(HIST("hv0radius"), candidate.v0radius()); - rKzeroShort.fill(HIST("hDCApostopv"), candidate.dcapostopv()); - rKzeroShort.fill(HIST("hDCAnegtopv"), candidate.dcanegtopv()); - rKzeroShort.fill(HIST("hDCAv0topv"), candidate.dcav0topv()); - rKzeroShort.fill(HIST("halpha"), candidate.alpha()); - rKzeroShort.fill(HIST("hqtarm"), candidate.qtarm()); - rKzeroShort.fill(HIST("hpsipair"), candidate.psipair()); - } - - if (!DCAv0topv && fabs(candidate.dcav0topv()) > cMaxV0DCA) { - return false; - } - - if (rapidityks && TMath::Abs(candidate.yK0Short()) >= ConfKsrapidity) { - return false; - } - - if (masslambda && TMath::Abs(candidate.mLambda() - candidate.mK0Short()) >= competingcascrejlambda && TMath::Abs(candidate.mAntiLambda() - candidate.mK0Short()) >= competingcascrejlambdaanti) { - return false; - } - - // if (isStandarv0 && candidate.isStandardV0 == 0) { - // return false; - // } - - if (pT < ConfV0PtMin) { - return false; - } - if (dcaDaughv0 > ConfV0DCADaughMax) { - return false; - } - if (cpav0 < ConfV0CPAMin) { - return false; - } - if (tranRad < ConfV0TranRadV0Min) { - return false; - } - if (tranRad > ConfV0TranRadV0Max) { - return false; - } - if (fabs(CtauK0s) > cMaxV0LifeTime || candidate.mK0Short() < lowmasscutks0 || candidate.mK0Short() > highmasscutks0) { - return false; - } - if (!armcut && arm < Confarmcut) { - return false; - } - - if (QAv0) { - rKzeroShort.fill(HIST("hMassK0ShortSelected"), candidate.mK0Short(), candidate.pt()); - } - return true; - } - - template - bool isSelectedV0Daughter(T const& track, float charge, - double nsigmaV0Daughter, V0s const& /*candidate*/) - { - if (QAPID) { - // Filling the PID of the V0 daughters in the region of the K0 peak. - // tpcInnerParam is the momentum at the inner wall of TPC. So momentum of tpc vs nsigma of tpc is plotted. - // if (0.45 < candidate.mK0Short() && candidate.mK0Short() < 0.55) { - (charge == 1) ? rKzeroShort.fill(HIST("hNSigmaPosPionK0s_before"), track.tpcInnerParam(), track.tpcNSigmaPi()) : rKzeroShort.fill(HIST("hNSigmaNegPionK0s_before"), track.tpcInnerParam(), track.tpcNSigmaPi()); - // } - } - const auto eta = track.eta(); - const auto tpcNClsF = track.tpcNClsFound(); - // const auto dcaXY = track.dcaXY(); // for this we need TrackDCA table - const auto sign = track.sign(); - - if (!track.hasTPC()) - return false; - if (track.tpcNClsCrossedRows() < tpcCrossedrows) - return false; - if (track.tpcCrossedRowsOverFindableCls() < tpcCrossedrowsOverfcls) - return false; - - if (charge < 0 && sign > 0) { - return false; - } - if (charge > 0 && sign < 0) { - return false; - } - if (std::abs(eta) > ConfDaughEta) { - return false; - } - if (tpcNClsF < ConfDaughTPCnclsMin) { - return false; - } - // if (std::abs(dcaXY) < ConfDaughDCAMin) { - // return false; - // } - // v0 PID selection - if (std::abs(nsigmaV0Daughter) > ConfDaughPIDCuts) { - return false; - } - - if (QAPID) { - // if (0.45 < candidate.mK0Short() && candidate.mK0Short() < 0.55) { - (charge == 1) ? rKzeroShort.fill(HIST("hNSigmaPosPionK0s_after"), track.tpcInnerParam(), track.tpcNSigmaPi()) : rKzeroShort.fill(HIST("hNSigmaNegPionK0s_after"), track.tpcInnerParam(), track.tpcNSigmaPi()); - // } - } - - if (QAv0_daughters) { - (charge == 1) ? rKzeroShort.fill(HIST("positive_pt"), track.pt()) : rKzeroShort.fill(HIST("negative_pt"), track.pt()); - (charge == 1) ? rKzeroShort.fill(HIST("positive_eta"), track.eta()) : rKzeroShort.fill(HIST("negative_eta"), track.eta()); - (charge == 1) ? rKzeroShort.fill(HIST("positive_phi"), track.phi()) : rKzeroShort.fill(HIST("negative_phi"), track.phi()); - } - - return true; - } - - // Defining filters for events (event selection) - // Filter eventFilter = (o2::aod::evsel::sel8 == true); - Filter posZFilter = (nabs(o2::aod::collision::posZ) < cutzvertex); - Filter AcceptenceFilter = (nabs(aod::track::eta) < cfgETAcut && nabs(aod::track::pt) > cfgPTcut); - - // Filters on V0s - Filter preFilterV0 = (nabs(aod::v0data::dcapostopv) > v0setting_dcapostopv && - nabs(aod::v0data::dcanegtopv) > v0setting_dcanegtopv); - - // Defining the type of the daughter tracks - using DaughterTracks = soa::Join; - using EventCandidates = soa::Filtered>; - using TrackCandidates = soa::Filtered>; - using V0TrackCandidate = aod::V0Datas; - - // void processSE(soa::Filtered>::iterator const& collision, - // soa::Filtered const& V0s, - // DaughterTracks const&) - - void processSE(EventCandidates::iterator const& collision, TrackCandidates const& /*tracks*/, aod::V0Datas const& V0s) - { - hglue.fill(HIST("heventscheck"), 0.5); - const double massK0s = TDatabasePDG::Instance()->GetParticle(kK0Short)->Mass(); - float multiplicity = 0.0f; - if (cfgMultFOTM) { - multiplicity = collision.centFT0M(); - } else { - multiplicity = collision.centFT0C(); - } - if (!eventselection(collision, multiplicity)) { - return; - } - - hglue.fill(HIST("heventscheck"), 1.5); - - rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); - rEventSelection.fill(HIST("hmultiplicity"), multiplicity); - - for (auto& [v1, v2] : combinations(CombinationsStrictlyUpperIndexPolicy(V0s, V0s))) { - - hglue.fill(HIST("heventscheck"), 2.5); - - if (v1.size() == 0 || v2.size() == 0) { - continue; - } - - if (!SelectionV0(collision, v1, multiplicity)) { - continue; - } - if (!SelectionV0(collision, v2, multiplicity)) { - continue; - } - - auto postrack1 = v1.template posTrack_as(); - auto negtrack1 = v1.template negTrack_as(); - auto postrack2 = v2.template posTrack_as(); - auto negtrack2 = v2.template negTrack_as(); - - if (postrack1.globalIndex() == postrack2.globalIndex()) { - continue; - } - if (negtrack1.globalIndex() == negtrack2.globalIndex()) { - continue; - } - double nTPCSigmaPos1[1]{postrack1.tpcNSigmaPi()}; - double nTPCSigmaNeg1[1]{negtrack1.tpcNSigmaPi()}; - double nTPCSigmaPos2[1]{postrack2.tpcNSigmaPi()}; - double nTPCSigmaNeg2[1]{negtrack2.tpcNSigmaPi()}; - - if (!isSelectedV0Daughter(postrack1, 1, nTPCSigmaPos1[0], v1)) { - continue; - } - if (!isSelectedV0Daughter(postrack2, 1, nTPCSigmaPos2[0], v2)) { - continue; - } - if (!isSelectedV0Daughter(negtrack1, -1, nTPCSigmaNeg1[0], v1)) { - continue; - } - if (!isSelectedV0Daughter(negtrack2, -1, nTPCSigmaNeg2[0], v2)) { - continue; - } - - hglue.fill(HIST("heventscheck"), 3.5); - - TLorentzVector lv1, lv2, lv3; - lv1.SetPtEtaPhiM(v1.pt(), v1.eta(), v1.phi(), massK0s); - lv2.SetPtEtaPhiM(v2.pt(), v2.eta(), v2.phi(), massK0s); - lv3 = lv1 + lv2; - - if (TMath::Abs(lv3.Rapidity() < 0.5)) { - if (inv_mass1D) { - hglue.fill(HIST("h1glueInvMassDS"), lv3.M()); - } - - hglue.fill(HIST("h3glueInvMassDS"), multiplicity, lv3.Pt(), lv3.M()); - } - } - } - - PROCESS_SWITCH(strangeness_tutorial, processSE, "same event process", true); - - // use any one of 3 alias depending on the dataset. If pp then FT0M and if pbpb then FTOC - using BinningTypeTPCMultiplicity = ColumnBinningPolicy; - using BinningTypeCentralityM = ColumnBinningPolicy; - using BinningTypeVertexContributor = ColumnBinningPolicy; - ConfigurableAxis mevz = {"mevz", {10, -10., 10.}, "mixed event vertex z binning"}; - ConfigurableAxis memult = {"memult", {2000, 0, 10000}, "mixed event multiplicity binning"}; - - void processME(EventCandidates const& collisions, TrackCandidates const& /*tracks*/, V0TrackCandidate const& v0s) - { - hglue.fill(HIST("heventscheck"), 4.5); - - const double massK0s = TDatabasePDG::Instance()->GetParticle(kK0Short)->Mass(); - auto tracksTuple = std::make_tuple(v0s); - BinningTypeVertexContributor binningOnPositions1{{mevz, memult}, true}; - BinningTypeCentralityM binningOnPositions2{{mevz, memult}, true}; - - SameKindPair pair1{binningOnPositions1, cfgNmixedEvents, -1, collisions, tracksTuple, &cache}; // for PbPb - SameKindPair pair2{binningOnPositions2, cfgNmixedEvents, -1, collisions, tracksTuple, &cache}; // for pp - - if (cfgMultFOTM) { - for (auto& [c1, tracks1, c2, tracks2] : pair2) // two different centrality c1 and c2 and tracks corresponding to them - { - hglue.fill(HIST("heventscheck"), 5.5); - - float multiplicity = 0.0f; - multiplicity = c1.centFT0M(); - - if (!eventselection(c1, multiplicity) || !eventselection(c2, multiplicity)) { - continue; - } - hglue.fill(HIST("heventscheck"), 6.5); - - for (auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - hglue.fill(HIST("heventscheck"), 7.5); - - if (t1.size() == 0 || t2.size() == 0) { - continue; - } - - if (!SelectionV0(c1, t1, multiplicity)) - continue; - if (!SelectionV0(c2, t2, multiplicity)) - continue; - - auto postrack1 = t1.template posTrack_as(); - auto negtrack1 = t1.template negTrack_as(); - auto postrack2 = t2.template posTrack_as(); - auto negtrack2 = t2.template negTrack_as(); - if (postrack1.globalIndex() == postrack2.globalIndex()) { - continue; - } - if (negtrack1.globalIndex() == negtrack2.globalIndex()) { - continue; - } - double nTPCSigmaPos1[1]{postrack1.tpcNSigmaPi()}; - double nTPCSigmaNeg1[1]{negtrack1.tpcNSigmaPi()}; - double nTPCSigmaPos2[1]{postrack2.tpcNSigmaPi()}; - double nTPCSigmaNeg2[1]{negtrack2.tpcNSigmaPi()}; - - if (!isSelectedV0Daughter(postrack1, 1, nTPCSigmaPos1[0], t1)) { - continue; - } - if (!isSelectedV0Daughter(postrack2, 1, nTPCSigmaPos2[0], t2)) { - continue; - } - if (!isSelectedV0Daughter(negtrack1, -1, nTPCSigmaNeg1[0], t1)) { - continue; - } - if (!isSelectedV0Daughter(negtrack2, -1, nTPCSigmaNeg2[0], t2)) { - continue; - } - - hglue.fill(HIST("heventscheck"), 8.5); - - TLorentzVector lv1, lv2, lv3; - lv1.SetPtEtaPhiM(t1.pt(), t1.eta(), t1.phi(), massK0s); - lv2.SetPtEtaPhiM(t2.pt(), t2.eta(), t2.phi(), massK0s); - lv3 = lv1 + lv2; - if (TMath::Abs(lv3.Rapidity() < 0.5)) { - if (inv_mass1D) { - hglue.fill(HIST("h1glueInvMassME"), lv3.M()); - } - hglue.fill(HIST("h3glueInvMassME"), multiplicity, lv3.Pt(), lv3.M()); - } - } - } - } else { - for (auto& [c1, tracks1, c2, tracks2] : pair1) // two different centrality c1 and c2 and tracks corresponding to them - { - float multiplicity = 0.0f; - multiplicity = c1.centFT0C(); - - if (!eventselection(c1, multiplicity) || !eventselection(c2, multiplicity)) { - continue; - } - - for (auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - if (t1.size() == 0 || t2.size() == 0) { - continue; - } - - if (!SelectionV0(c1, t1, multiplicity)) - continue; - if (!SelectionV0(c2, t2, multiplicity)) - continue; - - auto postrack1 = t1.template posTrack_as(); - auto negtrack1 = t1.template negTrack_as(); - auto postrack2 = t2.template posTrack_as(); - auto negtrack2 = t2.template negTrack_as(); - if (postrack1.globalIndex() == postrack2.globalIndex()) { - continue; - } - if (negtrack1.globalIndex() == negtrack2.globalIndex()) { - continue; - } - double nTPCSigmaPos1[1]{postrack1.tpcNSigmaPi()}; - double nTPCSigmaNeg1[1]{negtrack1.tpcNSigmaPi()}; - double nTPCSigmaPos2[1]{postrack2.tpcNSigmaPi()}; - double nTPCSigmaNeg2[1]{negtrack2.tpcNSigmaPi()}; - - if (!isSelectedV0Daughter(postrack1, 1, nTPCSigmaPos1[0], t1)) { - continue; - } - if (!isSelectedV0Daughter(postrack2, 1, nTPCSigmaPos2[0], t2)) { - continue; - } - if (!isSelectedV0Daughter(negtrack1, -1, nTPCSigmaNeg1[0], t1)) { - continue; - } - if (!isSelectedV0Daughter(negtrack2, -1, nTPCSigmaNeg2[0], t2)) { - continue; - } - - TLorentzVector lv1, lv2, lv3; - lv1.SetPtEtaPhiM(t1.pt(), t1.eta(), t1.phi(), massK0s); - lv2.SetPtEtaPhiM(t2.pt(), t2.eta(), t2.phi(), massK0s); - lv3 = lv1 + lv2; - if (TMath::Abs(lv3.Rapidity() < 0.5)) { - if (inv_mass1D) { - hglue.fill(HIST("h1glueInvMassME"), lv3.M()); - } - hglue.fill(HIST("h3glueInvMassME"), multiplicity, lv3.Pt(), lv3.M()); - } - } - } - } - } - PROCESS_SWITCH(strangeness_tutorial, processME, "mixed event process", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx b/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx index 4aa162408ba..8286f876bc8 100644 --- a/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx +++ b/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx @@ -8,12 +8,15 @@ // 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 chargedkstaranalysis.cxx +/// \brief Reconstruction of track-track decay resonance candidates +/// /// -/// \brief this is a code for the CKS resonance -/// \author prottay das -/// \since 13/01/2024 +/// \author Protay -#include +#include "TF1.h" +// #include #include #include #include @@ -23,7 +26,7 @@ #include #include #include -#include "TF1.h" +#include #include #include @@ -48,885 +51,481 @@ #include "PWGLF/DataModel/LFStrangenessTables.h" #include "ReconstructionDataFormats/Track.h" +// For charged kstarpp analysis +#include "PWGLF/DataModel/LFResonanceTables.h" + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::soa; using std::array; struct chargedkstaranalysis { // Connect to ccdb - Service ccdb; - Configurable nolaterthan{ - "ccdb-no-later-than", - std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()) - .count(), - "latest acceptable timestamp of creation for the object"}; - Configurable url{"ccdb-url", "http://ccdb-test.cern.ch:8080", - "url of the ccdb repository"}; - SliceCache cache; - - // Histograms are defined with HistogramRegistry - HistogramRegistry rEventSelection{"eventSelection", - {}, - OutputObjHandlingPolicy::AnalysisObject, - true, - true}; - HistogramRegistry histos{ - "histos", + Preslice perRCol = aod::resodaughter::resoCollisionId; + Preslice perCollision = aod::track::collisionId; + // For charged Kstarpp analysis use Resonance Initalizer and THnSparse + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 1., 5., 10., 30., 50., 70., 100., 110.}, "Binning of the centrality axis"}; + ConfigurableAxis binsPt{"binsPt", + {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12.0, 12.1, 12.2, 12.3, 12.4, 12.5, 12.6, 12.7, 12.8, 12.9, 13.0, 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7, 13.8, 13.9, 14.0, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15.0}, + "Binning of the pT axis"}; + ConfigurableAxis etabins{"etabins", + {VARIABLE_WIDTH, -1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}, + "Eta Binning"}; + Configurable cDCABinsQA{"cDCABinsQA", 150, "DCA binning"}; + ConfigurableAxis binsPtQA{"binsPtQA", + {VARIABLE_WIDTH, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2, 6.4, 6.6, 6.8, 7.0, 7.2, 7.4, 7.6, 7.8, 8.0, 8.2, 8.4, 8.6, 8.8, 9.0, 9.2, 9.4, 9.6, 9.8, 10.0}, + "Binning of the pT axis"}; + + AxisSpec k892pmCountAxis = {2, 0., 2., "K*^{+}(892) = 1, K*^{-}(892) = 2"}; + + HistogramRegistry histos1{ + "histos1", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rGenParticles{"genParticles", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rRecParticles{"recParticles", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + // Pre-selection cuts + Configurable cMinPtcut{"cMinPtcut", 0.15, "Track minimum pt cut"}; + Configurable confevtcollintimerangestandard{"confevtcollintimerangestandard", true, "Evt sel: apply NoCollInTimeRangeStandard"}; + /// PID Selections + Configurable nsigmaCutCombinedPion{"nsigmaCutCombinedPion", -999, + "Combined nSigma cut for Pion"}; // Combined + + // DCAr to PV + Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 0.5, + "Track DCAr cut to PV Maximum"}; + // DCAz to PV + Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 2.0, + "Track DCAz cut to PV Maximum"}; + // Track selections + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, + "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, + "Global track selection without DCA"}; // kQualityTracks (kTrackType | + // kTPCNCls | kTPCCrossedRows | + // kTPCCrossedRowsOverNCls | + // kTPCChi2NDF | kTPCRefit | + // kITSNCls | kITSChi2NDF | + // kITSRefit | kITSHits) | + // kInAcceptanceTracks (kPtRange | + // kEtaRange) + Configurable cfgPVContributor{"cfgPVContributor", true, + "PV contributor track selection"}; // PV Contributor + // V0 selections + Configurable cV0MinCosPA{"cV0MinCosPA", 0.97, + "V0 minimum pointing angle cosine"}; + Configurable cV0MaxDaughDCA{"cV0MaxDaughDCA", 1.0, + "V0 daughter DCA Maximum"}; + // Competing V0 rejection + Configurable cV0MassWindow{"cV0MassWindow", 0.0043, "Mass window for competing Lambda0 rejection"}; + Configurable cInvMassStart{"cInvMassStart", 0.6, "Invariant mass start"}; + Configurable cInvMassEnd{"cInvMassEnd", 1.5, "Invariant mass end"}; + Configurable cInvMassBins{"cInvMassBins", 900, "Invariant mass binning"}; + + // Rapidity Cut + Configurable confRapidity{"confRapidity", 0.5, "Rapidity cut"}; + + // Event mixing + Configurable nEvtMixing{"nEvtMixing", 5, "Number of events to mix"}; + ConfigurableAxis cfgvtxbins{"cfgvtxbins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis cfgmultbins{"cfgmultbins", {VARIABLE_WIDTH, 0., 1., 5., 10., 30., 50., 70., 100., 110.}, "Mixing bins - multiplicity"}; + Configurable cTpcNsigmaPionBinsQA{"cTpcNsigmaPionBinsQA", 140, "tpcNSigmaPi binning"}; // Configurable for histograms Configurable nBins{"nBins", 100, "N bins in all histos"}; - // Confugrable for QA histograms - Configurable QAbefore{"QAbefore", false, "QAbefore"}; - Configurable QAafter{"QAafter", false, "QAafter"}; - Configurable QAv0{"QAv0", false, "QAv0"}; - - // Configurable for event selection - Configurable cutzvertex{"cutzvertex", 10.0f, - "Accepted z-vertex range (cm)"}; - // Configurable parameters for V0 selection - Configurable ConfV0PtMin{"ConfV0PtMin", 0.f, - "Minimum transverse momentum of V0"}; - Configurable ConfV0DCADaughMax{"ConfV0DCADaughMax", 1.0f, - "Maximum DCA between the V0 daughters"}; - Configurable ConfV0CPAMin{"ConfV0CPAMin", 0.985f, "Minimum CPA of V0"}; - Configurable ConfV0TranRadV0Min{"ConfV0TranRadV0Min", 0.5f, - "Minimum transverse radius"}; - Configurable ConfV0TranRadV0Max{"ConfV0TranRadV0Max", 200.f, - "Maximum transverse radius"}; - Configurable cMaxV0LifeTime{"cMaxV0LifeTime", 15, - "Maximum V0 life time"}; - Configurable cMaxV0DCA{"cMaxV0DCA", 0.3, "DCA V0 to PV"}; - Configurable cSigmaMassKs0{"cSigmaMassKs0", 4, - "n Sigma cut on KS0 mass"}; - Configurable cWidthKs0{"cWidthKs0", 0.005, "Width of KS0"}; - - Configurable ConfDaughEta{"ConfDaughEta", 0.8f, - "V0 Daugh sel: max eta"}; - Configurable ConfDaughTPCnclsMin{"ConfDaughTPCnclsMin", 70.f, - "V0 Daugh sel: Min. nCls TPC"}; - Configurable ConfDaughDCAMin{ - "ConfDaughDCAMin", 0.06f, "V0 Daugh sel: Max. DCA Daugh to PV (cm)"}; - Configurable ConfDaughPIDCuts{"ConfDaughPIDCuts", 4, - "PID selections for KS0 daughters"}; - - // Configurables for track selections - Configurable cfgCutPT{"cfgCutPT", 0.2f, "PT cut on daughter track"}; - Configurable cfgCutEta{"cfgCutEta", 0.8f, "Eta cut on daughter track"}; - Configurable cfgCutDCAxy{"cfgCutDCAxy", 2.0f, - "DCAxy range for tracks"}; - Configurable cfgCutDCAz{"cfgCutDCAz", 2.0f, "DCAz range for tracks"}; - Configurable nsigmaCutTPC{"nsigmacutTPC", 3.0, - "Value of the TPC Nsigma cut"}; - Configurable nsigmaCutCombined{"nsigmaCutCombined", 3.0, - "Value of the Combined Nsigma cut"}; - Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 5, - "Number of mixed events per event"}; - Configurable cfgMultFT0{"cfgMultFT0", false, "cfgMultFT0"}; - Configurable cfgCentFT0C{"cfgCentFT0C", true, "cfgCentFT0C"}; - Configurable iscustomDCAcut{"iscustomDCAcut", false, "iscustomDCAcut"}; - Configurable ismanualDCAcut{"ismanualDCAcut", true, "ismanualDCAcut"}; - Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; - ConfigurableAxis cMixMultBins{"cMixMultBins", {VARIABLE_WIDTH, 0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f}, "Mixing bins - multiplicity"}; - Configurable isMC{"isMC", true, "Run MC"}; - Configurable timFrameEvsel{"timFrameEvsel", false, "TPC Time frame boundary cut"}; - Configurable additionalEvsel{"additionalEvsel", false, "Additional event selcection"}; - - // Event selection cuts - Alex - TF1* fMultPVCutLow = nullptr; - TF1* fMultPVCutHigh = nullptr; - TF1* fMultCutLow = nullptr; - TF1* fMultCutHigh = nullptr; - TF1* fMultMultPVCut = nullptr; + Configurable confdaugheta{"confdaugheta", 0.8f, "V0 Daugh sel: max eta"}; + Configurable nSigmaCutTPC{"nSigmaCutTPC", 3.0, "Value of the TPC Nsigma cut"}; + Configurable nSigmaCutTOF{"nSigmaCutTOF", 3.0, + "Value of the TOF Nsigma cut"}; + Configurable nsigmaCutCombined{"nsigmaCutCombined", 3.0, "Value of the Combined Nsigma cut"}; + Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 5, "Number of mixed events per event"}; + + // For rotational background + Configurable fillRotation{"fillRotation", true, "fill rotation"}; + Configurable confMinRot{"confMinRot", 5.0 * o2::constants::math::PI / 6.0, "Minimum of rotation"}; + Configurable confMaxRot{"confMaxRot", 7.0 * o2::constants::math::PI / 6.0, "Maximum of rotation"}; + Configurable nBkgRotations{"nBkgRotations", 9, "Number of rotated copies (background) per each original candidate"}; void init(InitContext const&) { - // Axes - AxisSpec K0ShortMassAxis = {200, 0.45f, 0.55f, - "#it{M}_{inv} [GeV/#it{c}^{2}]"}; - AxisSpec vertexZAxis = {nBins, -10., 10., "vrtx_{Z} [cm]"}; - AxisSpec ptAxis = {200, 0.0f, 20.0f, "#it{p}_{T} (GeV/#it{c})"}; - AxisSpec multAxis = {100, 0.0f, 100.0f, "Multiplicity"}; - - // Histograms - // Event selection - rEventSelection.add("hVertexZRec", "hVertexZRec", - {HistType::kTH1F, {vertexZAxis}}); - rEventSelection.add("hmult", "Centrality distribution", kTH1F, - {{200, 0.0f, 200.0f}}); - - // for primary tracks - if (QAbefore && QAafter) { - histos.add("hNsigmaPionTPC_before", "NsigmaPion TPC distribution before", - kTH1F, {{200, -10.0f, 10.0f}}); - histos.add("hNsigmaPionTOF_before", "NsigmaPion TOF distribution before", - kTH1F, {{200, -10.0f, 10.0f}}); - - histos.add("hEta_after", "Eta distribution", kTH1F, {{200, -1.0f, 1.0f}}); - histos.add("hDcaxy_after", "Dcaxy distribution", kTH1F, - {{200, -10.0f, 10.0f}}); - histos.add("hDcaz_after", "Dcaz distribution", kTH1F, - {{200, -10.0f, 10.0f}}); - histos.add("hNsigmaPionTPC_after", "NsigmaPion TPC distribution", kTH1F, - {{200, -10.0f, 10.0f}}); - histos.add("hNsigmaPionTOF_after", "NsigmaPion TOF distribution", kTH1F, - {{200, -10.0f, 10.0f}}); + AxisSpec dcaxyAxisQA = {cDCABinsQA, 0.0, 3.0, "DCA_{#it{xy}} (cm)"}; + AxisSpec dcazAxisQA = {cDCABinsQA, 0.0, 3.0, "DCA_{#it{xy}} (cm)"}; + AxisSpec ptAxisQA = {binsPtQA, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec tpcNSigmaPiAxisQA = {cTpcNsigmaPionBinsQA, -7.0, 7.0, + "N#sigma_{TPC}"}; + AxisSpec pidQAAxis = {130, -6.5, 6.5}; + AxisSpec centAxis = {binsCent, "V0M (%)"}; + AxisSpec ptAxis = {binsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec invMassAxis = {cInvMassBins, cInvMassStart, cInvMassEnd, + "Invariant Mass (GeV/#it{c}^2)"}; + AxisSpec etaAxis = {etabins, "#eta"}; + AxisSpec goodTrackCountAxis = { + 3, 0., 3., "Passed track = 1, Passed V0 = 2, Passed track and V0 = 3"}; + // register histograms + histos1.add("hVertexZ", "hVertexZ", HistType::kTH1F, {{nBins, -15., 15.}}); + // Multiplicity and accepted events QA + histos1.add("QAbefore/collMult", "Collision multiplicity", HistType::kTH1F, + {centAxis}); + // QA before + histos1.add("QAbefore/pi_Eta", "Primary pion track eta", kTH1F, {etaAxis}); + histos1.add("QAbefore/k0s_Eta", "K0short track eta", kTH1F, {etaAxis}); + histos1.add("QAbefore/chargedkstarpmRapidity", + "Reconstructed K*^{#pm} rapidity", kTH1F, {etaAxis}); + histos1.add("QAbefore/trkpionTOFPID", "TOF PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos1.add("QAbefore/trkpionTPCTOFPID", "TPC-TOF PID map of bachelor pion candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + + histos1.add("QAbefore/DCAxy_pi", + "DCAxy distribution of pion track candidates", HistType::kTH1F, + {dcaxyAxisQA}); + histos1.add("QAbefore/DCAz_pi", + "DCAz distribution of pion track candidates", HistType::kTH1F, + {dcazAxisQA}); + histos1.add("QAbefore/pT_pi", "pT distribution of pion track candidates", + kTH1F, {ptAxisQA}); + histos1.add("QAbefore/tpcNsigmaPionQA", + "NsigmaTPC distribution of primary pion candidates", kTH2F, + {ptAxisQA, tpcNSigmaPiAxisQA}); + + // QA after + histos1.add("QAAfter/DCAxy_pi", + "DCAxy distribution of pion track candidates", HistType::kTH1F, + {dcaxyAxisQA}); + histos1.add("QAAfter/DCAz_pi", "DCAz distribution of pion track candidates", + HistType::kTH1F, {dcazAxisQA}); + histos1.add("QAAfter/pT_pi", "pT distribution of pion track candidates", + kTH1F, {ptAxisQA}); + histos1.add("QAAfter/tpcNsigmaPionQA", + "NsigmaTPC distribution of primary pion candidates", kTH2F, + {ptAxisQA, tpcNSigmaPiAxisQA}); + histos1.add("QAAfter/pi_Eta", "Primary pion track eta", kTH1F, {etaAxis}); + + // Good tracks and V0 counts QA + histos1.add("QAafter/hGoodTracksV0s", "Number of good track and V0 passed", + kTH1F, {goodTrackCountAxis}); + histos1.add("chargedkstarinvmassUlikeSign", + "Invariant mass of charged K*(892)", kTH1F, {invMassAxis}); + histos1.add("chargedkstarinvmassMixedEvent", + "Invariant mass of charged K*(892)", kTH1F, {invMassAxis}); + + // Mass vs Pt vs Multiplicity 3-dimensional histogram + // histos1.add("chargekstarMassPtMult", "Charged K*(892) mass vs pT vs V0 + // multiplicity distribution", kTH3F, {invMassAxis, ptAxis, centAxis}); + + histos1.add("chargekstarMassPtMultPtUnlikeSign", + "Invariant mass of CKS meson Unlike Sign", kTHnSparseF, + {invMassAxis, ptAxis, centAxis}, true); + histos1.add("hSparseChargeKstarSameEventRotational", "hSparseChargeKstarSameEventRotational", HistType::kTHnSparseF, {invMassAxis, ptAxis, centAxis}, true); + + histos1.add("chargekstarMassPtMultPtMixedEvent", + "Invariant mass of CKS meson MixedEvent Sign", kTHnSparseF, + {invMassAxis, ptAxis, centAxis}, true); + if (fillRotation) { + histos1.add("hRotation", "hRotation", kTH1F, {{360, 0.0, o2::constants::math::TwoPI}}); + } + + // for MC production + if (doprocessMCTrue) { + // DEBUG HISTOGRAMS + histos1.add("hK892pmCounter", "Generated MC resonances", kTH1F, {k892pmCountAxis}); + histos1.add("k892pmPtGen", "pT distribution of True MC charged K*(892)", kTH1F, {ptAxis}); + histos1.add("k892pPtGen", "pT distribution of True MC K*(892) Plus", kTH1F, {ptAxis}); + histos1.add("k892mPtGen", "pT distribution of True MC K*(892) Minus", kTH1F, {ptAxis}); + + // histos.add("hDaughterCounter", "Generated MC resonance daughters", kTH1F, {daughterCountAxis}); + } + if (doprocessMCLight) { + // MC QA + histos1.add("k892pmPtRec", "pT distribution of Reconstructed MC charged K*(892)", kTH1F, {ptAxis}); } + } + double massPi = o2::constants::physics::MassPionCharged; + double massK0s = o2::constants::physics::MassK0Short; + double massKa = o2::constants::physics::MassKPlus; + ROOT::Math::PtEtaPhiMVector cksvector; + + double massK0 = o2::constants::physics::MassK0Short; + double massPicharged = o2::constants::physics::MassPionCharged; + double massLambda0 = o2::constants::physics::MassLambda; + double massAntiLambda0 = o2::constants::physics::MassLambda0Bar; + // Fill histograms (main function) + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks, + const V0sType& dV0s) + { + // auto multiplicity = collision.cent(); + auto multiplicity = collision.cent(); + histos1.fill(HIST("QAbefore/collMult"), multiplicity); + TLorentzVector lDecayDaughter, lDecayV0, lResonance, pionrot, chargekstarrot; + + for (const auto& track : dTracks) { // loop over all dTracks1 to find the bachelor pion + auto trackId = track.index(); + auto trackptPi = track.pt(); + auto tracketaPi = track.eta(); + auto istrkhasTOF = track.hasTOF(); + auto trkNSigmaPiTPC = track.tpcNSigmaPi(); + auto trkNSigmaPiTOF = (istrkhasTOF) ? track.tofNSigmaPi() : -999.; + + histos1.fill(HIST("QAbefore/pi_Eta"), tracketaPi); + + if (!IsMix) { + // TPC PID (before cuts) + histos1.fill(HIST("QAbefore/tpcNsigmaPionQA"), trackptPi, trkNSigmaPiTPC); + if (istrkhasTOF) { + histos1.fill(HIST("QAbefore/trkpionTOFPID"), trackptPi, trkNSigmaPiTOF); + histos1.fill(HIST("QAbefore/trkpionTPCTOFPID"), trkNSigmaPiTPC, trkNSigmaPiTOF); + } + // DCA QA (before cuts) + histos1.fill(HIST("QAbefore/DCAxy_pi"), track.dcaXY()); + histos1.fill(HIST("QAbefore/DCAz_pi"), track.dcaZ()); + // Pseudo-rapidity QA (before cuts) + histos1.fill(HIST("QAbefore/pi_Eta"), tracketaPi); + // pT QA (before cuts) + histos1.fill(HIST("QAbefore/pT_pi"), trackptPi); + } - if (QAv0) { - // K0s reconstruction - histos.add( - "hMassvsptvsmult", "hMassvsptvsmult", - {HistType::kTHnSparseF, {{K0ShortMassAxis}, {ptAxis}, {multAxis}}}, - true); - // K0s topological/PID cuts - histos.add("hDCAV0Daughters", "hDCAV0Daughters", - {HistType::kTH1F, {{50, 0.0f, 5.0f}}}); - histos.add("hLT", "hLT", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); - histos.add("hV0CosPA", "hV0CosPA", - {HistType::kTH1F, {{100, 0.95f, 1.f}}}); - } + // apply the track cut + if (!trackCutpp(track) || !selectionPIDpp(track)) + continue; - // CKStar histograms - histos.add("h3CKSInvMassUnlikeSign", - "Invariant mass of CKS meson Unlike Sign", kTHnSparseF, - {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {90, 0.6, 1.5}}, true); - histos.add("h3CKSInvMassMixed", "Invariant mass of CKS meson Mixed", - kTHnSparseF, - {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {90, 0.6, 1.5}}, true); - - if (isMC) { - rGenParticles.add("hMC", "Gen MC Event statistics", kTH1F, {{10, 0.0f, 10.0f}}); - rRecParticles.add("hMCRec", "Rec MC Event statistics", kTH1F, {{10, 0.0f, 10.0f}}); - rGenParticles.add("hPtK0ShortGen", "hPtK0ShortGen", {HistType::kTH1F, {{ptAxis}}}); - rGenParticles.add("hCKSGen", "hCKSGen", {HistType::kTH1F, {{ptAxis}}}); - rRecParticles.add("hCKSRec", "hCKSRec", {HistType::kTH1F, {{ptAxis}}}); - } + histos1.fill(HIST("QAafter/hGoodTracksV0s"), 0.5); + + if (!IsMix) { + // DCA QA (before cuts) + histos1.fill(HIST("QAAfter/DCAxy_pi"), track.dcaXY()); + histos1.fill(HIST("QAAfter/DCAz_pi"), track.dcaZ()); + // Pseudo-rapidity QA (before cuts) + histos1.fill(HIST("QAAfter/pi_Eta"), tracketaPi); + // pT QA (before cuts) + histos1.fill(HIST("QAAfter/pT_pi"), trackptPi); + // TPC PID (before cuts) + histos1.fill(HIST("QAAfter/tpcNsigmaPionQA"), trackptPi, + track.tpcNSigmaPi()); + } - // Event selection cut additional - Alex - if (additionalEvsel) { - fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); - fMultPVCutLow->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05); - fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); - fMultPVCutHigh->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05); - fMultCutLow = new TF1("fMultCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.5*([4]+[5]*x)", 0, 100); - fMultCutLow->SetParameters(1893.94, -53.86, 0.502913, -0.0015122, 109.625, -1.19253); - fMultCutHigh = new TF1("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 3.*([4]+[5]*x)", 0, 100); - fMultCutHigh->SetParameters(1893.94, -53.86, 0.502913, -0.0015122, 109.625, -1.19253); - fMultMultPVCut = new TF1("fMultMultPVCut", "[0]+[1]*x+[2]*x*x", 0, 5000); - fMultMultPVCut->SetParameters(-0.1, 0.785, -4.7e-05); - } - } + for (const auto& v0 : dV0s) { - double massPi = TDatabasePDG::Instance() - ->GetParticle(kPiPlus) - ->Mass(); // FIXME: Get from the common header - double massK0s = TDatabasePDG::Instance() - ->GetParticle(kK0Short) - ->Mass(); // FIXME: Get from the common header - double massKa = o2::constants::physics::MassKPlus; - ROOT::Math::PtEtaPhiMVector CKSVector; + // Full index policy is needed to consider all possible combinations + if (v0.indices()[0] == trackId || v0.indices()[1] == trackId) + continue; // To avoid combining secondary and primary pions + //// Initialize variables + // trk: Pion, v0: K0s + // apply the track cut + if (!v0cut(v0)) + continue; + histos1.fill(HIST("QAafter/hGoodTracksV0s"), 1.5); - template - bool eventSelected(TCollision collision, const float& centrality) - { - if (collision.alias_bit(kTVXinTRD)) { - // TRD triggered - // return 0; - } - auto multNTracksPV = collision.multNTracksPV(); - if (multNTracksPV < fMultPVCutLow->Eval(centrality)) - return 0; - if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) - return 0; - // if (multTrk < fMultCutLow->Eval(centrality)) - // return 0; - // if (multTrk > fMultCutHigh->Eval(centrality)) - // return 0; - // if (multTrk > fMultMultPVCut->Eval(multNTracksPV)) - // return 0; - - return 1; - } + lDecayDaughter.SetXYZM(track.px(), track.py(), track.pz(), massPi); + lDecayV0.SetXYZM(v0.px(), v0.py(), v0.pz(), massK0); + lResonance = lDecayDaughter + lDecayV0; + // Counting how many resonances passed + histos1.fill(HIST("QAafter/hGoodTracksV0s"), 2.5); - template - bool selectionTrack(const T& candidate) - { - if (iscustomDCAcut && - (!candidate.isGlobalTrack() || !candidate.isPVContributor() || - candidate.itsNCls() < cfgITScluster)) { - return false; - } - if (ismanualDCAcut && - (!candidate.isGlobalTrackWoDCA() || !candidate.isPVContributor() || - std::abs(candidate.dcaXY()) > cfgCutDCAxy || - std::abs(candidate.dcaZ()) > cfgCutDCAz || - candidate.itsNCls() < cfgITScluster)) { - return false; + // Checking whether the mid-rapidity condition is met + if (std::abs(lResonance.Rapidity()) > confRapidity) + continue; + if constexpr (!IsMix) { + histos1.fill(HIST("chargedkstarinvmassUlikeSign"), lResonance.M()); + // Reconstructed K*(892)pm 3d mass, pt, multiplicity histogram + histos1.fill(HIST("chargekstarMassPtMultPtUnlikeSign"), + lResonance.M(), lResonance.Pt(), multiplicity); + if constexpr (IsMC) { + bool pass1 = false; + bool pass2 = false; + // LOG(info) << "track PDG:\t" << trk.pdgCode() << "\tV0 PDG:\t" << v0.pdgCode(); + if ((track.pdgCode() != PDG_t::kPiPlus) && (v0.pdgCode() != PDG_t::kK0Short)) { // One decay to K0s and the other to pi+ (K*(892)+ mother) - Particle pass + pass1 = true; + } + if ((track.pdgCode() != PDG_t::kPiMinus) && (v0.pdgCode() != -310)) { // One decay to K0s and the other to pi+ (K*(892)+ mother) - Particle pass + pass2 = true; + } + if (!pass1 && !pass2) // Go on only if we have both decay products, else skip to next iteration + continue; + if (track.motherPDG() != v0.motherPDG()) + continue; + // LOG(info) << "track PDG:\t" << trk.pdgCode() << "\tV0 PDG:\t" << v0.pdgCode(); + if (track.motherPDG() != o2::constants::physics::Pdg::kKPlusStar892) + continue; + histos1.fill(HIST("k892pmPtRec"), lResonance.Pt()); + } + } else { + histos1.fill(HIST("chargedkstarinvmassMixedEvent"), lResonance.M()); + // Reconstructed K*(892)pm 3d mass, pt, multiplicity histogram + histos1.fill(HIST("chargekstarMassPtMultPtMixedEvent"), + lResonance.M(), lResonance.Pt(), multiplicity); + } + if constexpr (!IsMix) { + if (fillRotation) { + for (int nrotbkg = 0; nrotbkg < nBkgRotations; nrotbkg++) { + auto rotangle = o2::constants::math::PI; + if (nBkgRotations > 1) { + auto anglestart = confMinRot; + auto angleend = confMaxRot; + auto anglestep = (angleend - anglestart) / (1.0 * (nBkgRotations - 1)); + rotangle = anglestart + nrotbkg * anglestep; + } + histos1.fill(HIST("hRotation"), rotangle); + auto rotpionPx = lDecayDaughter.Px() * std::cos(rotangle) - lDecayDaughter.Py() * std::sin(rotangle); + auto rotpionPy = lDecayDaughter.Px() * std::sin(rotangle) + lDecayDaughter.Py() * std::cos(rotangle); + pionrot.SetXYZM(rotpionPx, rotpionPy, lDecayDaughter.Pz(), massPi); + chargekstarrot = pionrot + lDecayV0; + if (std::abs(chargekstarrot.Rapidity()) > confRapidity) { + continue; + } + histos1.fill(HIST("hSparseChargeKstarSameEventRotational"), chargekstarrot.M(), chargekstarrot.Pt(), multiplicity); + } + } + } + } } - return true; } template - bool selectionPID(const T& candidate) + bool selectionPIDpp(const T& candidate) { - - if (candidate.hasTOF() && - (candidate.tofNSigmaPi() * candidate.tofNSigmaPi() + - candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi()) < - (nsigmaCutCombined * nsigmaCutCombined)) { - return true; - } - if (!candidate.hasTOF() && - std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC) { - return true; + bool tpcPIDPassed{false}, tofPIDPassed{false}; + if (std::abs(candidate.tpcNSigmaPi()) < nSigmaCutTPC) { + tpcPIDPassed = true; } - - /* - if (candidate.hasTOF() && - (candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + - candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa()) < - (nsigmaCutCombined * nsigmaCutCombined)) { - return true; + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaPi()) < nSigmaCutTOF) { + tofPIDPassed = true; + } + if ((nsigmaCutCombinedPion > 0) && + (candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi() + + candidate.tofNSigmaPi() * candidate.tofNSigmaPi() < + nsigmaCutCombinedPion * nsigmaCutCombinedPion)) { + tofPIDPassed = true; + } + } else { + tofPIDPassed = true; } - if (!candidate.hasTOF() && - std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + if (tpcPIDPassed && tofPIDPassed) { return true; } - */ return false; } - template - bool SelectionV0(Collision const& collision, V0 const& candidate, - float multiplicity) + template + bool trackCutpp(const TrackType track) { - if (fabs(candidate.dcav0topv()) > cMaxV0DCA) { - return false; - } - - if (TMath::Abs(candidate.yK0Short()) > 0.5) { - return false; - } - - const float qtarm = candidate.qtarm(); - const float alph = candidate.alpha(); - float arm = qtarm / alph; - const float pT = candidate.pt(); - const float tranRad = candidate.v0radius(); - const float dcaDaughv0 = candidate.dcaV0daughters(); - const float cpav0 = candidate.v0cosPA(); - float CtauK0s = candidate.distovertotmom(collision.posX(), collision.posY(), - collision.posZ()) * - TDatabasePDG::Instance() - ->GetParticle(kK0Short) - ->Mass(); // FIXME: Get from the common header - float lowmasscutks0 = 0.497 - cWidthKs0 * cSigmaMassKs0; - float highmasscutks0 = 0.497 + cWidthKs0 * cSigmaMassKs0; - // float decayLength = candidate.distovertotmom(collision.posX(), - // collision.posY(), collision.posZ()) * - // RecoDecay::sqrtSumOfSquares(candidate.px(), candidate.py(), - // candidate.pz()); - - if (pT < ConfV0PtMin) { + // basic track cuts + if (std::abs(track.pt()) < cMinPtcut) return false; - } - if (dcaDaughv0 > ConfV0DCADaughMax) { + if (std::abs(track.eta()) > confdaugheta) return false; - } - if (cpav0 < ConfV0CPAMin) { + if (std::abs(track.dcaXY()) > cMaxDCArToPVcut) return false; - } - if (tranRad < ConfV0TranRadV0Min) { + if (std::abs(track.dcaZ()) > cMaxDCAzToPVcut) return false; - } - if (tranRad > ConfV0TranRadV0Max) { + if (cfgPrimaryTrack && !track.isPrimaryTrack()) return false; - } - if (fabs(CtauK0s) > cMaxV0LifeTime || - candidate.mK0Short() < lowmasscutks0 || - candidate.mK0Short() > highmasscutks0) { + if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) return false; - } - if (arm < 0.2) { + if (cfgPVContributor && !track.isPVContributor()) return false; - } - if (QAv0) { - histos.fill(HIST("hLT"), CtauK0s); - histos.fill(HIST("hMassvsptvsmult"), candidate.mK0Short(), candidate.pt(), - multiplicity); - histos.fill(HIST("hDCAV0Daughters"), candidate.dcaV0daughters()); - histos.fill(HIST("hV0CosPA"), candidate.v0cosPA()); - } return true; } - - template - bool isSelectedV0Daughter(T const& track, float charge, - double nsigmaV0Daughter) + template + bool v0cut(const V0Type v0) { - const auto eta = track.eta(); - const auto tpcNClsF = track.tpcNClsFound(); - const auto dcaXY = track.dcaXY(); - const auto sign = track.sign(); - - if (!track.hasTPC()) + // V0 track cuts + if (std::abs(v0.eta()) > confdaugheta) return false; - if (track.tpcNClsCrossedRows() < 70) + if (v0.v0CosPA() < cV0MinCosPA) return false; - if (track.tpcCrossedRowsOverFindableCls() < 0.8) + if (v0.daughDCA() > cV0MaxDaughDCA) return false; - if (charge < 0 && sign > 0) { - return false; - } - if (charge > 0 && sign < 0) { - return false; - } - if (std::abs(eta) > ConfDaughEta) { - return false; - } - if (tpcNClsF < ConfDaughTPCnclsMin) { - return false; - } - if (std::abs(dcaXY) < ConfDaughDCAMin) { + // apply the competing V0 rejection cut (excluding Lambda0 candidates, + // massLambdaPDG = 1115.683 MeV/c2) + + if (std::abs(v0.mLambda() - massLambda0) < cV0MassWindow) return false; - } - if (std::abs(nsigmaV0Daughter) > ConfDaughPIDCuts) { + if (std::abs(v0.mAntiLambda() - massAntiLambda0) < cV0MassWindow) return false; - } return true; } - // 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); - - Filter acceptanceFilter = - (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPT); - Filter DCAcutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && - (nabs(aod::track::dcaZ) < cfgCutDCAz); - - using EventCandidatesMC = soa::Join; - /*using EventCandidates = soa::Filtered< - soa::Join>;*/ - using EventCandidates = soa::Filtered>; - - using TrackCandidates = soa::Filtered< - soa::Join>; - using TrackCandidatesMC = soa::Filtered< - soa::Join>; - - using V0TrackCandidatesMC = soa::Join; - using V0TrackCandidate = aod::V0Datas; - - ConfigurableAxis axisVertex{ - "axisVertex", - {20, -10, 10}, - "vertex axis for bin"}; - ConfigurableAxis axisMultiplicityClass{ - "axisMultiplicityClass", - {1, 0, 100}, - "multiplicity percentile for bin"}; - ConfigurableAxis axisMultiplicity{ - "axisMultiplicity", - {2, 0, 100}, - "TPC multiplicity for bin"}; - - using BinningTypeTPCMultiplicity = - ColumnBinningPolicy; - // using BinningTypeVertexContributor = - // ColumnBinningPolicy; - using BinningTypeCentralityM = - ColumnBinningPolicy; - using BinningTypeVertexContributor = - ColumnBinningPolicy; - - BinningTypeVertexContributor binningOnPositions{ - {axisVertex, axisMultiplicity}, - true}; - - Pair - pair{binningOnPositions, cfgNoMixedEvents, -1, &cache}; - /* SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, &cache}; */ - void processSE(EventCandidates::iterator const& collision, - TrackCandidates const& tracks, aod::V0Datas const& V0s, - aod::BCs const&) - + void processSEnew(aod::ResoCollision const& collision, + aod::ResoTracks const& resotracks, + aod::ResoV0s const& resov0s) { - - if (!collision.sel8()) { - return; - } - - std::vector pions, kshorts; - std::vector pions2; - std::vector PionIndex = {}; - std::vector PionSign = {}; - std::vector PioncollIndex = {}; - std::vector PionIndex2 = {}; - std::vector PionSign2 = {}; - std::vector PioncollIndex2 = {}; - std::vector V0collIndex = {}; - std::vector KshortPosDaughIndex = {}; - std::vector KshortNegDaughIndex = {}; - /* - float multiplicity = 0.0f; - if (cfgMultFT0) - multiplicity = collision.multZeqFT0A() + collision.multZeqFT0C(); - if (cfgMultFT0 == 0 && cfgCentFT0C == 1) - multiplicity = collision.centFT0C(); - if (cfgMultFT0 == 0 && cfgCentFT0C == 0) - multiplicity = collision.centFT0M(); - */ - float centrality = 0.0f; - centrality = collision.centFT0C(); - - if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { - return; - } - - if (additionalEvsel && !eventSelected(collision, centrality)) { - return; - } - // Fill the event counter - rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); - rEventSelection.fill(HIST("hmult"), centrality); - - for (auto track1 : tracks) { - - if (QAbefore) { - histos.fill(HIST("hNsigmaPionTPC_before"), track1.tpcNSigmaPi()); - histos.fill(HIST("hNsigmaPionTOF_before"), track1.tofNSigmaPi()); - } - - if (!selectionPID(track1)) - continue; // for primary particle PID - - if (!selectionTrack(track1)) { - continue; - } - - if (QAafter) { - histos.fill(HIST("hEta_after"), track1.eta()); - histos.fill(HIST("hDcaxy_after"), track1.dcaXY()); - histos.fill(HIST("hDcaz_after"), track1.dcaZ()); - histos.fill(HIST("hNsigmaPionTPC_after"), track1.tpcNSigmaPi()); - histos.fill(HIST("hNsigmaPionTOF_after"), track1.tofNSigmaPi()); - } - - ROOT::Math::PtEtaPhiMVector temp1(track1.pt(), track1.eta(), track1.phi(), - massPi); - pions.push_back(temp1); - PionIndex.push_back(track1.globalIndex()); - PioncollIndex.push_back(track1.collisionId()); - PionSign.push_back(track1.sign()); - } // track loop ends - - for (auto& v0 : V0s) { - - auto postrack = v0.template posTrack_as(); - auto negtrack = v0.template negTrack_as(); - double nTPCSigmaPos[1]{postrack.tpcNSigmaPi()}; - double nTPCSigmaNeg[1]{negtrack.tpcNSigmaPi()}; - - if (!isSelectedV0Daughter(postrack, 1, nTPCSigmaPos[0])) { - continue; - } - if (!isSelectedV0Daughter(negtrack, -1, nTPCSigmaNeg[0])) { - continue; - } - - if (!SelectionV0(collision, v0, centrality)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector temp2(v0.pt(), v0.eta(), v0.phi(), massK0s); - kshorts.push_back(temp2); - V0collIndex.push_back(v0.collisionId()); - KshortPosDaughIndex.push_back(postrack.globalIndex()); - KshortNegDaughIndex.push_back(negtrack.globalIndex()); - } - - if (pions.size() != 0 && kshorts.size() != 0) { - // if (pions.size() != 0 && pions2.size() != 0) { - for (auto ipion = pions.begin(); ipion != pions.end(); ++ipion) { - auto i1 = std::distance(pions.begin(), ipion); - if (PionSign.at(i1) == 0) - continue; - for (auto ikshort = kshorts.begin(); ikshort != kshorts.end(); - ++ikshort) { - // for (auto ikshort = pions2.begin(); ikshort != pions2.end(); - // ++ikshort) { - auto i3 = std::distance(kshorts.begin(), ikshort); - if (PionIndex.at(i1) == KshortPosDaughIndex.at(i3)) - continue; - if (PionIndex.at(i1) == KshortNegDaughIndex.at(i3)) - continue; - // if (PioncollIndex.at(i1) != V0collIndex.at(i3)) - // continue; - - CKSVector = pions.at(i1) + kshorts.at(i3); - if (TMath::Abs(CKSVector.Rapidity()) < 0.5) { - histos.fill(HIST("h3CKSInvMassUnlikeSign"), centrality, - CKSVector.Pt(), CKSVector.M()); - } - } - } - } + histos1.fill(HIST("hVertexZ"), collision.posZ()); + fillHistograms(collision, resotracks, + resov0s); // Fill histograms, no MC, no mixing } - - PROCESS_SWITCH(chargedkstaranalysis, processSE, "Process Same event", false); - - void processME(EventCandidates const& /*collisions*/, - TrackCandidates const& /*tracks*/, V0TrackCandidate const& /*V0s*/) - + PROCESS_SWITCH(chargedkstaranalysis, processSEnew, "Process Same event new", + true); + + using BinningTypeVtxZT0M = + ColumnBinningPolicy; + void processMEnew(aod::ResoCollisions const& collisions, + aod::ResoTracks const& resotracks, + aod::ResoV0s const& resov0s) { - - for (auto& [c1, tracks1, c2, tracks2] : pair) { - - if (!c1.sel8()) { - continue; - } - if (!c2.sel8()) { - continue; - } - /* - float multiplicity = 0.0f; - if (cfgMultFT0) - multiplicity = c1.multZeqFT0A() + c1.multZeqFT0C(); - if (cfgMultFT0 == 0 && cfgCentFT0C == 1) - multiplicity = c1.centFT0C(); - if (cfgMultFT0 == 0 && cfgCentFT0C == 0) - multiplicity = c1.centFT0M(); - */ - auto centrality = c1.centFT0C(); - auto centrality2 = c2.centFT0C(); - - if (timFrameEvsel && (!c1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !c2.selection_bit(aod::evsel::kNoTimeFrameBorder) || !c1.selection_bit(aod::evsel::kNoITSROFrameBorder) || !c2.selection_bit(aod::evsel::kNoITSROFrameBorder))) { - continue; - } - - if (additionalEvsel && !eventSelected(c1, centrality)) { - continue; - } - if (additionalEvsel && !eventSelected(c2, centrality2)) { - continue; - } - - for (auto& [t1, t2] : o2::soa::combinations( - o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - - if (!selectionTrack(t1)) - continue; - if (!selectionPID(t1)) - continue; - if (t1.sign() == 0) - continue; - - if (!SelectionV0(c2, t2, centrality2)) - continue; - - auto postrack = t2.template posTrack_as(); - auto negtrack = t2.template negTrack_as(); - double nTPCSigmaPos[1]{postrack.tpcNSigmaPi()}; - double nTPCSigmaNeg[1]{negtrack.tpcNSigmaPi()}; - - if (!isSelectedV0Daughter(postrack, 1, nTPCSigmaPos[0])) { - continue; - } - if (!isSelectedV0Daughter(negtrack, -1, nTPCSigmaNeg[0])) { - continue; - } - - TLorentzVector pi; - pi.SetPtEtaPhiM(t1.pt(), t1.eta(), t1.phi(), massPi); - TLorentzVector KSh; - KSh.SetPtEtaPhiM(t2.pt(), t2.eta(), t2.phi(), massK0s); - - TLorentzVector CKSmix = pi + KSh; - - if (TMath::Abs(CKSmix.Rapidity()) < 0.5) { - histos.fill(HIST("h3CKSInvMassMixed"), centrality, CKSmix.Pt(), - CKSmix.M()); - } - } + auto tracksV0sTuple = std::make_tuple(resotracks, resov0s); + auto v0stuple = std::make_tuple(resov0s); + BinningTypeVtxZT0M colBinning{{cfgvtxbins, cfgmultbins}, true}; + Pair + pairs{colBinning, nEvtMixing, -1, collisions, + tracksV0sTuple, &cache}; // -1 is the number of the bin to skip + for (const auto& [c1, restrk1, c2, resov0s2] : pairs) { + fillHistograms(c1, restrk1, resov0s2); } } + PROCESS_SWITCH(chargedkstaranalysis, processMEnew, "Process Mixed events new", + true); - PROCESS_SWITCH(chargedkstaranalysis, processME, "Process Mixed event", false); - - // taken from Sourav da - void processGenMC(aod::McCollision const& mcCollision, aod::McParticles& mcParticles, const soa::SmallGroups& collisions) + void processMCTrue(aod::ResoMCParents const& resoParents) { - - if (std::abs(mcCollision.posZ()) < cutzvertex) - rGenParticles.fill(HIST("hMC"), 0.5); - std::vector SelectedEvents(collisions.size()); - int nevts = 0; - for (const auto& collision : collisions) { - if (!collision.sel8() || std::abs(collision.mcCollision().posZ()) > cutzvertex) { + for (const auto& part : resoParents) { // loop over all pre-filtered MC particles + if (std::abs(part.pdgCode()) != o2::constants::physics::Pdg::kKPlusStar892) // K*892(pm) continue; - } - rGenParticles.fill(HIST("hMC"), 1.5); - if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + if (std::abs(part.y()) > 0.5) // rapidity cut continue; - } - rGenParticles.fill(HIST("hMC"), 2.5); - SelectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); - } - SelectedEvents.resize(nevts); - const auto evtReconstructedAndSelected = std::find(SelectedEvents.begin(), SelectedEvents.end(), mcCollision.globalIndex()) != SelectedEvents.end(); + bool pass1 = false; + bool pass2 = false; - if (!evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection - return; - } - - rGenParticles.fill(HIST("hMC"), 3.5); - for (auto& mcParticle : mcParticles) { - if (std::abs(mcParticle.y()) >= 0.5) { - continue; + if (part.daughterPDG1() == PDG_t::kPiPlus && part.daughterPDG2() == PDG_t::kK0Short) { // One decay to K0s and the other to pi+ (K*(892)+ mother) - Particle pass + pass1 = true; + histos1.fill(HIST("hK892pmCounter"), 0.5); + histos1.fill(HIST("k892pPtGen"), part.pt()); } - rGenParticles.fill(HIST("hMC"), 4.5); - if (std::abs(mcParticle.pdgCode()) != 323) { - continue; + if (part.daughterPDG1() == PDG_t::kPiMinus && part.daughterPDG2() == -310) { // One decay to AntiK0s and the other to pi- (K*(892)- mother) - Antiparticle pass + pass2 = true; + histos1.fill(HIST("hK892pmCounter"), 1.5); + histos1.fill(HIST("k892mPtGen"), part.pt()); } - rGenParticles.fill(HIST("hMC"), 5.5); - auto kDaughters = mcParticle.daughters_as(); - if (kDaughters.size() != 2) { + if (!pass1 && !pass2) // Go on only if we have both decay products, else skip to next iteration continue; - } - - rGenParticles.fill(HIST("hMC"), 6.5); - auto daughts = false; - auto daughtp = false; - // int count = 0; - for (auto kCurrentDaughter : kDaughters) { - // LOG(info) << "Daughters PDG:\t" << count<<" "<(); - for (auto kCurrentDaughter2 : kDaughter2) { - if (kCurrentDaughter2.pdgCode() == 310) - daughts = true; - } - } else if (std::abs(kCurrentDaughter.pdgCode()) == 211) { - if (kCurrentDaughter.isPhysicalPrimary() == 1) - daughtp = true; - } - // count += 1; - } - rGenParticles.fill(HIST("hMC"), 7.5); - if (daughtp && daughts) { - rGenParticles.fill(HIST("hCKSGen"), mcParticle.pt()); - } + histos1.fill(HIST("k892pmPtGen"), part.pt()); } } + PROCESS_SWITCH(chargedkstaranalysis, processMCTrue, "Process Event for MC", false); - void processRecMC(EventCandidatesMC::iterator const& collision, - TrackCandidatesMC const& tracks, V0TrackCandidatesMC const& V0s, - aod::McParticles const& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) - + void processMCLight(aod::ResoCollision const& collision, + soa::Join const& resotracks, + soa::Join const& resov0s) { - - if (!collision.has_mcCollision()) { - return; - } - if (std::abs(collision.mcCollision().posZ()) > cutzvertex || !collision.sel8()) { - return; - } - - rRecParticles.fill(HIST("hMCRec"), 0.5); - - if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { - return; - } - - rRecParticles.fill(HIST("hMCRec"), 1.5); - - float centrality = 0.0f; - - for (auto track1 : tracks) { - - if (!selectionPID(track1)) - continue; // for primary particle PID - - if (!track1.has_mcParticle()) { - continue; - } - - if (!selectionTrack(track1)) { - continue; - } - - auto mctrack1 = track1.mcParticle(); - - if (!mctrack1.isPhysicalPrimary()) { - continue; - } - - for (auto& v0 : V0s) { - - if (!v0.has_mcParticle()) { - continue; - } - - auto postrack = v0.template posTrack_as(); - auto negtrack = v0.template negTrack_as(); - - if (!postrack.has_mcParticle()) - continue; // Checking that the daughter tracks come from particles and are not fake - if (!negtrack.has_mcParticle()) // Checking that the daughter tracks come from particles and are not fake - continue; - - // auto posParticle = postrack.mcParticle(); - // auto negParticle = negtrack.mcParticle(); - - double nTPCSigmaPos[1]{postrack.tpcNSigmaPi()}; - double nTPCSigmaNeg[1]{negtrack.tpcNSigmaPi()}; - - if (!isSelectedV0Daughter(postrack, 1, nTPCSigmaPos[0])) { - continue; - } - - if (!isSelectedV0Daughter(negtrack, -1, nTPCSigmaNeg[0])) { - continue; - } - - if (!SelectionV0(collision, v0, centrality)) { - continue; - } - - auto mctrackv0 = v0.mcParticle(); - - /* - for (auto track2 : tracks) { - - if (!selectionPID(track2)) - continue; // for primary particle PID - - if (!track2.has_mcParticle()) { - continue; - } - - if (!selectionTrack(track2)) { - continue; - } - - auto mctrack2 = track2.mcParticle(); - - - if (!mctrack2.isPhysicalPrimary()) { - continue; - } - */ - - int track1PDG = std::abs(mctrack1.pdgCode()); - // int track2PDG = std::abs(mctrack2.pdgCode()); - int trackv0PDG = std::abs(mctrackv0.pdgCode()); - - if (postrack.globalIndex() == track1.globalIndex()) - continue; - if (negtrack.globalIndex() == track1.globalIndex()) - continue; - - rRecParticles.fill(HIST("hMCRec"), 2.5); - - if (track1PDG != 211) { - continue; - } - // if (track2PDG != 321) { - // continue; - // } - if (trackv0PDG != 310) { - continue; - } - - rRecParticles.fill(HIST("hMCRec"), 3.5); - - for (auto& mothertrack1 : mctrack1.mothers_as()) { - // for (auto& mothertrack2 : mctrack2.mothers_as()) { - for (auto& mothertrack2 : mctrackv0.mothers_as()) { - - rRecParticles.fill(HIST("hMCRec"), 4.5); - // LOG(info) << "Initial Mothers PDG:\t" <()) { - - // LOG(info) << "final Mothers PDG:\t" <= 0.5) { - continue; - } - - rRecParticles.fill(HIST("hMCRec"), 7.5); - - rRecParticles.fill(HIST("hCKSRec"), mothertrack1.pt()); - } - } - } - } - } // track loop ends + fillHistograms(collision, resotracks, resov0s); } - - PROCESS_SWITCH(chargedkstaranalysis, processGenMC, "Process Gen event", true); - PROCESS_SWITCH(chargedkstaranalysis, processRecMC, "Process Rec event", true); + PROCESS_SWITCH(chargedkstaranalysis, processMCLight, "Process Event for MC", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Resonances/chk892Flow.cxx b/PWGLF/Tasks/Resonances/chk892Flow.cxx new file mode 100644 index 00000000000..18e21f5dd11 --- /dev/null +++ b/PWGLF/Tasks/Resonances/chk892Flow.cxx @@ -0,0 +1,1106 @@ +// 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 chk892Flow.cxx +/// \brief Reconstruction of track-track decay resonance candidates +/// \author Su-Jeong Ji , Bong-Hwi Lim +/// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "TRandom3.h" +#include "TF1.h" +#include "TVector2.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/StaticFor.h" +#include "DCAFitter/DCAFitterN.h" + +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Qvectors.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/RecoDecay.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "CommonConstants/MathConstants.h" + +#include "ReconstructionDataFormats/Track.h" + +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" + +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" + +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/collisionCuts.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; +using namespace o2::aod::rctsel; + +struct Chk892Flow { + enum BinType : unsigned int { + kKstarP = 0, + kKstarN, + kKstarP_Mix, + kKstarN_Mix, + kKstarP_Rot, + kKstarN_Rot, + kTYEnd + }; + + SliceCache cache; + Preslice perCollision = aod::track::collisionId; + + using EventCandidates = soa::Join; + using TrackCandidates = soa::Join; + using V0Candidates = aod::V0Datas; + + using MCEventCandidates = soa::Join; + using MCTrackCandidates = soa::Join; + using MCV0Candidates = soa::Join; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + + struct : ConfigurableGroup { + Configurable cfgURL{"cfgURL", "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; + } CCDBConfig; + // Configurable nolaterthan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "Latest acceptable timestamp of creation for the object"}; + + // Configurables + struct : ConfigurableGroup { + ConfigurableAxis cfgBinsPt{"cfgBinsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12.0, 12.1, 12.2, 12.3, 12.4, 12.5, 12.6, 12.7, 12.8, 12.9, 13.0, 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7, 13.8, 13.9, 14.0, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15.0}, "Binning of the pT axis"}; + ConfigurableAxis cfgBinsPtQA{"cfgBinsPtQA", {VARIABLE_WIDTH, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2, 6.4, 6.6, 6.8, 7.0, 7.2, 7.4, 7.6, 7.8, 8.0, 8.2, 8.4, 8.6, 8.8, 9.0, 9.2, 9.4, 9.6, 9.8, 10.0}, "Binning of the pT axis"}; + ConfigurableAxis cfgBinsCent{"cfgBinsCent", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0}, "Binning of the centrality axis"}; + ConfigurableAxis cfgBinsVtxZ{"cfgBinsVtxZ", {VARIABLE_WIDTH, -10.0, -9.0, -8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0}, "Binning of the z-vertex axis"}; + Configurable cNbinsDiv{"cNbinsDiv", 1, "Integer to divide the number of bins"}; + Configurable cNbinsDivQA{"cNbinsDivQA", 1, "Integer to divide the number of bins for QA"}; + ConfigurableAxis cfgAxisV2{"cfgAxisV2", {200, -1, 1}, "Binning of the v2 axis (+-1 for EP method)"}; + ConfigurableAxis cfgAxisPhi{"cfgAxisPhi", {8, 0, constants::math::PI}, "Binning of the #phi axis"}; + } AxisConfig; + + struct : ConfigurableGroup { + Configurable cfgFillQAPlots{"cfgFillQAPlots", true, "Fill QA plots"}; + Configurable cfgQvecSel{"cfgQvecSel", true, "Reject events when no QVector"}; + Configurable cfgCentEst{"cfgCentEst", 1, "Centrality estimator, 1: FT0C, 2: FT0M"}; + Configurable cfgFillAdditionalAxis{"cfgFillAdditionalAxis", false, "Fill additional axis"}; + Configurable cfgUseScalProduct{"cfgUseScalProduct", false, "Use scalar product method"}; + } AnalysisConfig; + + // Event cuts + o2::analysis::CollisonCuts colCuts; + struct : ConfigurableGroup { + Configurable cfgEvtZvtx{"cfgEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; + Configurable cfgEvtOccupancyInTimeRangeMax{"cfgEvtOccupancyInTimeRangeMax", -1, "Evt sel: maximum track occupancy"}; + Configurable cfgEvtOccupancyInTimeRangeMin{"cfgEvtOccupancyInTimeRangeMin", -1, "Evt sel: minimum track occupancy"}; + Configurable cfgEvtTriggerCheck{"cfgEvtTriggerCheck", false, "Evt sel: check for trigger"}; + Configurable cfgEvtOfflineCheck{"cfgEvtOfflineCheck", true, "Evt sel: check for offline selection"}; + Configurable cfgEvtTriggerTVXSel{"cfgEvtTriggerTVXSel", false, "Evt sel: triggerTVX selection (MB)"}; + Configurable cfgEvtTFBorderCut{"cfgEvtTFBorderCut", false, "Evt sel: apply TF border cut"}; + Configurable cfgEvtUseITSTPCvertex{"cfgEvtUseITSTPCvertex", false, "Evt sel: use at lease on ITS-TPC track for vertexing"}; + Configurable cfgEvtZvertexTimedifference{"cfgEvtZvertexTimedifference", true, "Evt sel: apply Z-vertex time difference"}; + Configurable cfgEvtPileupRejection{"cfgEvtPileupRejection", true, "Evt sel: apply pileup rejection"}; + Configurable cfgEvtNoITSROBorderCut{"cfgEvtNoITSROBorderCut", false, "Evt sel: apply NoITSRO border cut"}; + Configurable cfgEvtCollInTimeRangeStandard{"cfgEvtCollInTimeRangeStandard", true, "Evt sel: apply NoCollInTimeRangeStandard"}; + Configurable cfgEventCentralityMin{"cfgEventCentralityMin", 0.0f, "Event sel: minimum centrality"}; + Configurable cfgEventCentralityMax{"cfgEventCentralityMax", 80.0f, "Event sel: maximum centrality"}; + Configurable cfgEvtUseRCTFlagChecker{"cfgEvtUseRCTFlagChecker", false, "Evt sel: use RCT flag checker"}; + Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; + Configurable cfgEvtRCTFlagCheckerZDCCheck{"cfgEvtRCTFlagCheckerZDCCheck", false, "Evt sel: RCT flag checker ZDC check"}; + Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", false, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } EventCuts; + RCTFlagsChecker rctChecker; + + /// PID Selections, pion + struct : ConfigurableGroup { + Configurable cfgTPConly{"cfgTPConly", false, "Use only TPC for PID"}; // bool + Configurable cfgMaxTPCnSigmaPion{"cfgMaxTPCnSigmaPion", 3.0, "TPC nSigma cut for Pion"}; // TPC + Configurable cfgMaxTOFnSigmaPion{"cfgMaxTOFnSigmaPion", 3.0, "TOF nSigma cut for Pion"}; // TOF + Configurable cfgNsigmaCutCombinedPion{"cfgNsigmaCutCombinedPion", -999, "Combined nSigma cut for Pion"}; // Combined + Configurable cfgTOFVeto{"cfgTOFVeto", true, "TOF Veto, if false, TOF is nessessary for PID selection"}; // TOF Veto + } PIDCuts; + + // Track selections + struct : ConfigurableGroup { + Configurable cfgMinPtcut{"cfgMinPtcut", 0.6, "Track minium pt cut"}; + Configurable cfgMaxEtacut{"cfgMaxEtacut", 0.8, "Track maximum eta cut"}; + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) + Configurable cfgGlobalTrack{"cfgGlobalTrack", false, "Global track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgPVContributor{"cfgPVContributor", false, "PV contributor track selection"}; // PV Contriuibutor + Configurable cfgpTdepDCAxyCut{"cfgpTdepDCAxyCut", false, "pT-dependent DCAxy cut"}; + Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 0, "Number of TPC cluster"}; + Configurable cfgRatioTPCRowsOverFindableCls{"cfgRatioTPCRowsOverFindableCls", 0.0f, "TPC Crossed Rows to Findable Clusters"}; + Configurable cfgITSChi2NCl{"cfgITSChi2NCl", 999.0, "ITS Chi2/NCl"}; + Configurable cfgTPCChi2NCl{"cfgTPCChi2NCl", 999.0, "TPC Chi2/NCl"}; + Configurable cfgUseTPCRefit{"cfgUseTPCRefit", false, "Require TPC Refit"}; + Configurable cfgUseITSRefit{"cfgUseITSRefit", false, "Require ITS Refit"}; + Configurable cfgHasITS{"cfgHasITS", false, "Require ITS"}; + Configurable cfgHasTPC{"cfgHasTPC", false, "Require TPC"}; + Configurable cfgHasTOF{"cfgHasTOF", false, "Require TOF"}; + // DCA to PV + Configurable cfgMaxbDCArToPVcut{"cfgMaxbDCArToPVcut", 0.1, "Track DCAr cut to PV Maximum"}; + Configurable cfgMaxbDCAzToPVcut{"cfgMaxbDCAzToPVcut", 0.1, "Track DCAz cut to PV Maximum"}; + } TrackCuts; + + // Secondary Selection + struct : ConfigurableGroup { + Configurable cfgReturnFlag{"cfgReturnFlag", false, "Return Flag for debugging"}; + Configurable cfgSecondaryRequire{"cfgSecondaryRequire", true, "Secondary cuts on/off"}; + Configurable cfgSecondaryArmenterosCut{"cfgSecondaryArmenterosCut", true, "cut on Armenteros-Podolanski graph"}; + Configurable cfgSecondaryCrossMassHypothesisCut{"cfgSecondaryCrossMassHypothesisCut", false, "Apply cut based on the lambda mass hypothesis"}; + + Configurable cfgByPassDauPIDSelection{"cfgByPassDauPIDSelection", true, "Bypass Daughters PID selection"}; + Configurable cfgSecondaryDauDCAMax{"cfgSecondaryDauDCAMax", 0.2, "Maximum DCA Secondary daughters to PV"}; + Configurable cfgSecondaryDauPosDCAtoPVMin{"cfgSecondaryDauPosDCAtoPVMin", 0.1, "Minimum DCA Secondary positive daughters to PV"}; + Configurable cfgSecondaryDauNegDCAtoPVMin{"cfgSecondaryDauNegDCAtoPVMin", 0.1, "Minimum DCA Secondary negative daughters to PV"}; + + Configurable cfgSecondaryPtMin{"cfgSecondaryPtMin", 0.f, "Minimum transverse momentum of Secondary"}; + Configurable cfgSecondaryRapidityMax{"cfgSecondaryRapidityMax", 0.8, "Maximum rapidity of Secondary"}; + Configurable cfgSecondaryRadiusMin{"cfgSecondaryRadiusMin", 0.0, "Minimum transverse radius of Secondary"}; + Configurable cfgSecondaryRadiusMax{"cfgSecondaryRadiusMax", 999.9, "Maximum transverse radius of Secondary"}; + Configurable cfgSecondaryCosPAMin{"cfgSecondaryCosPAMin", 0.995, "Mininum cosine pointing angle of Secondary"}; + Configurable cfgSecondaryDCAtoPVMax{"cfgSecondaryDCAtoPVMax", 0.4, "Maximum DCA Secondary to PV"}; + Configurable cfgSecondaryProperLifetimeMax{"cfgSecondaryProperLifetimeMax", 20., "Maximum Secondary Lifetime"}; + Configurable cfgSecondaryparamArmenterosCut{"cfgSecondaryparamArmenterosCut", 0.2, "parameter for Armenteros Cut"}; + Configurable cfgSecondaryMassWindow{"cfgSecondaryMassWindow", 0.03, "Secondary inv mass selection window"}; + Configurable cfgSecondaryCrossMassCutWindow{"cfgSecondaryCrossMassCutWindow", 0.05, "Secondary inv mass selection window with (anti)lambda hypothesis"}; + } SecondaryCuts; + + // K* selection + struct : ConfigurableGroup { + Configurable cfgKstarMaxRap{"cfgKstarMaxRap", 0.5, "Kstar maximum rapidity"}; + Configurable cfgKstarMinRap{"cfgKstarMinRap", -0.5, "Kstar minimum rapidity"}; + } KstarCuts; + + // Confs from flow analysis + struct : ConfigurableGroup { + Configurable cfgnMods{"cfgnMods", 2, "The number of modulations of interest starting from 2"}; + Configurable cfgNQvec{"cfgNQvec", 7, "The number of total Qvectors for looping over the task"}; + + Configurable cfgQvecDetName{"cfgQvecDetName", "FT0C", "The name of detector to be analyzed"}; + Configurable cfgQvecRefAName{"cfgQvecRefAName", "TPCpos", "The name of detector for reference A"}; + Configurable cfgQvecRefBName{"cfgQvecRefBName", "TPCneg", "The name of detector for reference B"}; + } EventPlaneConfig; + + // Bkg estimation + struct : ConfigurableGroup { + Configurable cfgFillRotBkg{"cfgFillRotBkg", true, "Fill rotated background"}; + Configurable cfgMinRot{"cfgMinRot", 5.0 * constants::math::PI / 6.0, "Minimum of rotation"}; + Configurable cfgMaxRot{"cfgMaxRot", 7.0 * constants::math::PI / 6.0, "Maximum of rotation"}; + Configurable cfgRotPion{"cfgRotPion", true, "Rotate pion"}; + Configurable cfgNrotBkg{"cfgNrotBkg", 9, "Number of rotated copies (background) per each original candidate"}; + } BkgEstimationConfig; + + int lDetId; + int lRefAId; + int lRefBId; + + int lQvecDetInd; + int lQvecRefAInd; + int lQvecRefBInd; + + float lCentrality; + + // PDG code + int kPDGK0s = kK0Short; + int kPDGK0 = kK0; + int kKstarPlus = o2::constants::physics::Pdg::kKPlusStar892; + + void init(o2::framework::InitContext&) + { + lCentrality = -999; + + colCuts.setCuts(EventCuts.cfgEvtZvtx, EventCuts.cfgEvtTriggerCheck, EventCuts.cfgEvtOfflineCheck, /*checkRun3*/ true, /*triggerTVXsel*/ false, EventCuts.cfgEvtOccupancyInTimeRangeMax, EventCuts.cfgEvtOccupancyInTimeRangeMin); + colCuts.init(&histos); + colCuts.setTriggerTVX(EventCuts.cfgEvtTriggerTVXSel); + colCuts.setApplyTFBorderCut(EventCuts.cfgEvtTFBorderCut); + colCuts.setApplyITSTPCvertex(EventCuts.cfgEvtUseITSTPCvertex); + colCuts.setApplyZvertexTimedifference(EventCuts.cfgEvtZvertexTimedifference); + colCuts.setApplyPileupRejection(EventCuts.cfgEvtPileupRejection); + colCuts.setApplyNoITSROBorderCut(EventCuts.cfgEvtNoITSROBorderCut); + colCuts.setApplyCollInTimeRangeStandard(EventCuts.cfgEvtCollInTimeRangeStandard); + colCuts.printCuts(); + + rctChecker.init(EventCuts.cfgEvtRCTFlagCheckerLabel, EventCuts.cfgEvtRCTFlagCheckerZDCCheck, EventCuts.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + + AxisSpec centAxis = {AxisConfig.cfgBinsCent, "T0M (%)"}; + AxisSpec vtxzAxis = {AxisConfig.cfgBinsVtxZ, "Z Vertex (cm)"}; + AxisSpec epAxis = {100, -1.0 * constants::math::PI, constants::math::PI}; + AxisSpec ptAxis = {AxisConfig.cfgBinsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptAxisQA = {AxisConfig.cfgBinsPtQA, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec v2Axis = {AxisConfig.cfgAxisV2, "#v_{2}"}; + AxisSpec phiAxis = {AxisConfig.cfgAxisPhi, "2(#phi-#Psi_{2})"}; + AxisSpec radiusAxis = {50, 0, 5, "Radius (cm)"}; + AxisSpec cpaAxis = {30, 0.97, 1.0, "CPA"}; + AxisSpec tauAxis = {250, 0, 25, "Lifetime (cm)"}; + AxisSpec dcaAxis = {100, 0, 2, "DCA (cm)"}; + AxisSpec dcaxyAxis = {100, 0, 1, "DCA_{#it{xy}} (cm)"}; + AxisSpec dcazAxis = {200, 0, 2, "DCA_{#it{z}} (cm)"}; + AxisSpec yAxis = {50, -1, 1, "Rapidity"}; + AxisSpec invMassAxisK0s = {400 / AxisConfig.cNbinsDiv, 0.3, 0.7, "Invariant Mass (GeV/#it{c}^2)"}; // K0s ~497.611 + AxisSpec invMassAxisReso = {900 / AxisConfig.cNbinsDiv, 0.5f, 1.4f, "Invariant Mass (GeV/#it{c}^2)"}; // chK(892) ~892 + AxisSpec pidQAAxis = {130 / AxisConfig.cNbinsDivQA, -6.5, 6.5}; + + // THnSparse + AxisSpec axisType = {BinType::kTYEnd, 0, BinType::kTYEnd, "Type of bin with charge and mix"}; + AxisSpec mcLabelAxis = {5, -0.5, 4.5, "MC Label"}; + + if (SecondaryCuts.cfgReturnFlag) { + histos.add("QA/K0sCutCheck", "Check K0s cut", HistType::kTH1D, {AxisSpec{13, -0.5, 12.5, "Check"}}); + } + histos.add("QA/before/CentDist", "Centrality distribution", {HistType::kTH1D, {centAxis}}); + histos.add("QA/before/VtxZ", "Centrality distribution", {HistType::kTH1D, {vtxzAxis}}); + + // EventPlane + histos.add("QA/EP/hEPDet", "Event plane distribution of FT0C (Det = A)", {HistType::kTH2D, {centAxis, epAxis}}); + histos.add("QA/EP/hEPB", "Event plane distribution of TPCpos (B)", {HistType::kTH2D, {centAxis, epAxis}}); + histos.add("QA/EP/hEPC", "Event plane distribution of TPCneg (C)", {HistType::kTH2D, {centAxis, epAxis}}); + histos.add("QA/EP/hEPResAB", "cos(n(A-B))", {HistType::kTH2D, {centAxis, epAxis}}); + histos.add("QA/EP/hEPResAC", "cos(n(A-C))", {HistType::kTH2D, {centAxis, epAxis}}); + histos.add("QA/EP/hEPResBC", "cos(n(B-C))", {HistType::kTH2D, {centAxis, epAxis}}); + + if (AnalysisConfig.cfgUseScalProduct) { + histos.add("QA/EP/hEPSPResAB", "cos(n(A-B))", {HistType::kTH2D, {centAxis, epAxis}}); + histos.add("QA/EP/hEPSPResAC", "cos(n(A-C))", {HistType::kTH2D, {centAxis, epAxis}}); + histos.add("QA/EP/hEPSPResBC", "cos(n(B-C))", {HistType::kTH2D, {centAxis, epAxis}}); + } + + if (AnalysisConfig.cfgFillQAPlots) { + // Rotated background + if (BkgEstimationConfig.cfgFillRotBkg) { + histos.add("QA/RotBkg/hRotBkg", "Rotated angle of rotated background", HistType::kTH1F, {{360, 0.0, o2::constants::math::TwoPI}}); + } + + // Bachelor pion + histos.add("QA/before/trkbpionDCAxy", "DCAxy distribution of bachelor pion candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/before/trkbpionDCAz", "DCAz distribution of bachelor pion candidates", HistType::kTH1D, {dcazAxis}); + histos.add("QA/before/trkbpionpT", "pT distribution of bachelor pion candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/before/trkbpionTPCPID", "TPC PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkbpionTOFPID", "TOF PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkbpionTPCTOFPID", "TPC-TOF PID map of bachelor pion candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + + histos.add("QA/after/trkbpionDCAxy", "DCAxy distribution of bachelor pion candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/after/trkbpionDCAz", "DCAz distribution of bachelor pion candidates", HistType::kTH1D, {dcazAxis}); + histos.add("QA/after/trkbpionpT", "pT distribution of bachelor pion candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/after/trkbpionTPCPID", "TPC PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkbpionTOFPID", "TOF PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkbpionTPCTOFPID", "TPC-TOF PID map of bachelor pion candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + + // Secondary pion 1 + histos.add("QA/before/trkppionTPCPID", "TPC PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkppionTOFPID", "TOF PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkppionTPCTOFPID", "TPC-TOF PID map of secondary pion 1 (positive) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/before/trkppionpT", "pT distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/before/trkppionDCAxy", "DCAxy distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/before/trkppionDCAz", "DCAz distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcazAxis}); + + histos.add("QA/after/trkppionTPCPID", "TPC PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkppionTOFPID", "TOF PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkppionTPCTOFPID", "TPC-TOF PID map of secondary pion 1 (positive) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/after/trkppionpT", "pT distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/after/trkppionDCAxy", "DCAxy distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/after/trkppionDCAz", "DCAz distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcazAxis}); + + // Secondary pion 2 + histos.add("QA/before/trknpionTPCPID", "TPC PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trknpionTOFPID", "TOF PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trknpionTPCTOFPID", "TPC-TOF PID map of secondary pion 2 (negative) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/before/trknpionpT", "pT distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/before/trknpionDCAxy", "DCAxy distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/before/trknpionDCAz", "DCAz distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcazAxis}); + + histos.add("QA/after/trknpionTPCPID", "TPC PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trknpionTOFPID", "TOF PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trknpionTPCTOFPID", "TPC-TOF PID map of secondary pion 2 (negative) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/after/trknpionpT", "pT distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/after/trknpionDCAxy", "DCAxy distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/after/trknpionDCAz", "DCAz distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcazAxis}); + + // K0s + histos.add("QA/before/hDauDCASecondary", "DCA of daughters of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/before/hy_Secondary", "Rapidity distribution of secondary resonance", HistType::kTH1D, {yAxis}); + histos.add("QA/before/hCPASecondary", "Cosine pointing angle distribution of secondary resonance", HistType::kTH1D, {cpaAxis}); + histos.add("QA/before/hDCAtoPVSecondary", "DCA to PV distribution of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/before/hPropTauSecondary", "Proper Lifetime distribution of secondary resonance", HistType::kTH1D, {tauAxis}); + histos.add("QA/before/hInvmassSecondary", "Invariant mass of unlike-sign secondary resonance", HistType::kTH1D, {invMassAxisK0s}); + + histos.add("QA/after/hDauDCASecondary", "DCA of daughters of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/after/hy_Secondary", "Rapidity distribution of secondary resonance", HistType::kTH1D, {yAxis}); + histos.add("QA/after/hCPASecondary", "Cosine pointing angle distribution of secondary resonance", HistType::kTH1D, {cpaAxis}); + histos.add("QA/after/hDCAtoPVSecondary", "DCA to PV distribution of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/after/hPropTauSecondary", "Proper Lifetime distribution of secondary resonance", HistType::kTH1D, {tauAxis}); + histos.add("QA/after/hInvmassSecondary", "Invariant mass of unlike-sign secondary resonance", HistType::kTH1D, {invMassAxisK0s}); + + // Mass QA (quick check) + histos.add("QA/before/KstarRapidity", "Rapidity distribution of chK(892)", HistType::kTH1D, {yAxis}); + histos.add("QA/before/kstarinvmass", "Invariant mass of unlike-sign chK(892)", HistType::kTH1D, {invMassAxisReso}); + histos.add("QA/before/k0sv2vsinvmass", "Invariant mass vs v2 of unlike-sign K0s", HistType::kTH2D, {invMassAxisK0s, v2Axis}); + histos.add("QA/before/kstarv2vsinvmass", "Invariant mass vs v2 of unlike-sign chK(892)", HistType::kTH2D, {invMassAxisReso, v2Axis}); + histos.add("QA/before/kstarinvmass_Mix", "Invariant mass of unlike-sign chK(892) from mixed event", HistType::kTH1D, {invMassAxisReso}); + + histos.add("QA/after/KstarRapidity", "Rapidity distribution of chK(892)", HistType::kTH1D, {yAxis}); + histos.add("QA/after/kstarinvmass", "Invariant mass of unlike-sign chK(892)", HistType::kTH1D, {invMassAxisReso}); + histos.add("QA/after/k0sv2vsinvmass", "Invariant mass vs v2 of unlike-sign K0s", HistType::kTH2D, {invMassAxisK0s, v2Axis}); + histos.add("QA/after/kstarv2vsinvmass", "Invariant mass vs v2 of unlike-sign chK(892)", HistType::kTH2D, {invMassAxisReso, v2Axis}); + histos.add("QA/after/kstarinvmass_Mix", "Invariant mass of unlike-sign chK(892) from mixed event", HistType::kTH1D, {invMassAxisReso}); + + // MC + if (doprocessMC) { + // Bachelor pion + histos.add("QAMC/trkbpionDCAxy", "DCAxy distribution of bachelor pion candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QAMC/trkbpionDCAz", "DCAz distribution of bachelor pion candidates", HistType::kTH1D, {dcazAxis}); + histos.add("QAMC/trkbpionpT", "pT distribution of bachelor pion candidates", HistType::kTH1D, {ptAxis}); + histos.add("QAMC/trkbpionTPCPID", "TPC PID of bachelor pion candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkbpionTOFPID", "TOF PID of bachelor pion candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkbpionTPCTOFPID", "TPC-TOF PID map of bachelor pion candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + + // Secondary pion 1 + histos.add("QAMC/trkppionDCAxy", "DCAxy distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QAMC/trkppionDCAz", "DCAz distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcazAxis}); + histos.add("QAMC/trkppionpT", "pT distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {ptAxis}); + histos.add("QAMC/trkppionTPCPID", "TPC PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkppionTOFPID", "TOF PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkppionTPCTOFPID", "TPC-TOF PID map of secondary pion 1 (positive) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + + // Secondary pion 2 + histos.add("QAMC/trknpionTPCPID", "TPC PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trknpionTOFPID", "TOF PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trknpionTPCTOFPID", "TPC-TOF PID map of secondary pion 2 (negative) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QAMC/trknpionpT", "pT distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {ptAxis}); + histos.add("QAMC/trknpionDCAxy", "DCAxy distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QAMC/trknpionDCAz", "DCAz distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcazAxis}); + + // Secondary Resonance (K0s candidates) + histos.add("QAMC/hDauDCASecondary", "DCA of daughters of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QAMC/hDauPosDCAtoPVSecondary", "Pos DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QAMC/hDauNegDCAtoPVSecondary", "Neg DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + + histos.add("QAMC/hy_Secondary", "Rapidity distribution of secondary resonance", HistType::kTH1D, {yAxis}); + histos.add("QAMC/hCPASecondary", "Cosine pointing angle distribution of secondary resonance", HistType::kTH1D, {cpaAxis}); + histos.add("QAMC/hDCAtoPVSecondary", "DCA to PV distribution of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QAMC/hPropTauSecondary", "Proper Lifetime distribution of secondary resonance", HistType::kTH1D, {tauAxis}); + histos.add("QAMC/hInvmassSecondary", "Invariant mass of unlike-sign secondary resonance", HistType::kTH1D, {invMassAxisK0s}); + + // K892 + histos.add("QAMC/KstarOA", "Opening angle of chK(892)", HistType::kTH1D, {AxisSpec{100, 0, 3.14, "Opening angle"}}); + histos.add("QAMC/KstarPairAsym", "Pair asymmetry of chK(892)", HistType::kTH1D, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); + histos.add("QAMC/KstarRapidity", "Rapidity distribution of chK(892)", HistType::kTH1D, {yAxis}); + + histos.add("QAMC/kstarinvmass", "Invariant mass of unlike-sign chK(892)", HistType::kTH1D, {invMassAxisReso}); + histos.add("QAMC/k0sv2vsinvmass", "Invariant mass vs v2 of unlike-sign K0s", HistType::kTH2D, {invMassAxisK0s, v2Axis}); + histos.add("QAMC/kstarv2vsinvmass", "Invariant mass vs v2 of unlike-sign chK(892)", HistType::kTH2D, {invMassAxisReso, v2Axis}); + histos.add("QAMC/kstarinvmass_noKstar", "Invariant mass of unlike-sign no chK(892)", HistType::kTH1D, {invMassAxisReso}); + histos.add("QAMC/kstarv2vsinvmass_noKstar", "Invariant mass vs v2 of unlike-sign no chK(892)", HistType::kTH2D, {invMassAxisReso, v2Axis}); + } + } + + // Invariant mass nSparse + if (AnalysisConfig.cfgFillAdditionalAxis) { + histos.add("hInvmass_Kstar", "Invariant mass of unlike-sign chK(892)", HistType::kTHnSparseD, {axisType, centAxis, ptAxis, invMassAxisReso, v2Axis, phiAxis}); + histos.add("hInvmass_K0s", "Invariant mass of unlike-sign K0s", HistType::kTHnSparseD, {centAxis, ptAxis, invMassAxisK0s, v2Axis, phiAxis}); + if (doprocessMC) { + histos.add("hInvmass_Kstar_MC", "Invariant mass of unlike chK(892)", HistType::kTHnSparseD, {axisType, centAxis, ptAxis, invMassAxisReso, v2Axis, phiAxis}); + } + } else { + histos.add("hInvmass_Kstar", "Invariant mass of unlike-sign chK(892)", HistType::kTHnSparseD, {axisType, centAxis, ptAxis, invMassAxisReso, v2Axis}); + histos.add("hInvmass_K0s", "Invariant mass of unlike-sign K0s", HistType::kTHnSparseD, {centAxis, ptAxis, invMassAxisK0s, v2Axis}); + if (doprocessMC) { + histos.add("hInvmass_Kstar_MC", "Invariant mass of unlike chK(892)", HistType::kTHnSparseD, {axisType, centAxis, ptAxis, invMassAxisReso, v2Axis}); + } + } + + lDetId = getlDetId(EventPlaneConfig.cfgQvecDetName); + lRefAId = getlDetId(EventPlaneConfig.cfgQvecRefAName); + lRefBId = getlDetId(EventPlaneConfig.cfgQvecRefBName); + + if (lDetId == lRefAId || lDetId == lRefBId || lRefAId == lRefBId) { + LOGF(info, "Wrong detector configuration \n The FT0C will be used to get Q-Vector \n The TPCpos and TPCneg will be used as reference systems"); + lDetId = 0; + lRefAId = 4; + lRefBId = 5; + } + if (EventPlaneConfig.cfgNQvec < 2) { + LOG(fatal) << "nMode must be larger than 1, current input (cfgNQvec): " << EventPlaneConfig.cfgNQvec; + } + LOGF(info, "lDetId: %d, lRefAId: %d, lRefBId: %d", lDetId, lRefAId, lRefBId); + + // MC + if (doprocessMC) { + // Bachelor pion + histos.add("QAMC/trkbpionDCAxy", "DCAxy distribution of bachelor pion candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QAMC/trkbpionDCAz", "DCAz distribution of bachelor pion candidates", HistType::kTH1D, {dcazAxis}); + histos.add("QAMC/trkbpionpT", "pT distribution of bachelor pion candidates", HistType::kTH1D, {ptAxis}); + histos.add("QAMC/trkbpionTPCPID", "TPC PID of bachelor pion candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkbpionTOFPID", "TOF PID of bachelor pion candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkbpionTPCTOFPID", "TPC-TOF PID map of bachelor pion candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + + // Secondary pion 1 + histos.add("QAMC/trkppionDCAxy", "DCAxy distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QAMC/trkppionDCAz", "DCAz distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcazAxis}); + histos.add("QAMC/trkppionpT", "pT distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {ptAxis}); + histos.add("QAMC/trkppionTPCPID", "TPC PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkppionTOFPID", "TOF PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkppionTPCTOFPID", "TPC-TOF PID map of secondary pion 1 (positive) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + + // Secondary pion 2 + histos.add("QAMC/trknpionTPCPID", "TPC PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trknpionTOFPID", "TOF PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trknpionTPCTOFPID", "TPC-TOF PID map of secondary pion 2 (negative) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QAMC/trknpionpT", "pT distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {ptAxis}); + histos.add("QAMC/trknpionDCAxy", "DCAxy distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QAMC/trknpionDCAz", "DCAz distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcazAxis}); + + // Secondary Resonance (K0s candidates) + histos.add("QAMC/hDauDCASecondary", "DCA of daughters of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QAMC/hDauPosDCAtoPVSecondary", "Pos DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QAMC/hDauNegDCAtoPVSecondary", "Neg DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + + histos.add("QAMC/hy_Secondary", "Rapidity distribution of secondary resonance", HistType::kTH1D, {yAxis}); + histos.add("QAMC/hCPASecondary", "Cosine pointing angle distribution of secondary resonance", HistType::kTH1D, {cpaAxis}); + histos.add("QAMC/hDCAtoPVSecondary", "DCA to PV distribution of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QAMC/hPropTauSecondary", "Proper Lifetime distribution of secondary resonance", HistType::kTH1D, {tauAxis}); + histos.add("QAMC/hInvmassSecondary", "Invariant mass of unlike-sign secondary resonance", HistType::kTH1D, {invMassAxisK0s}); + + // K892 + histos.add("QAMC/KstarOA", "Opening angle of chK(892)", HistType::kTH1D, {AxisSpec{100, 0, 3.14, "Opening angle"}}); + histos.add("QAMC/KstarPairAsym", "Pair asymmetry of chK(892)", HistType::kTH1D, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); + histos.add("QAMC/KstarRapidity", "Rapidity distribution of chK(892)", HistType::kTH1D, {yAxis}); + + histos.add("QAMC/kstarinvmass", "Invariant mass of unlike-sign chK(892)", HistType::kTH1D, {invMassAxisReso}); + histos.add("QAMC/k0sv2vsinvmass", "Invariant mass vs v2 of unlike-sign K0s", HistType::kTH2D, {invMassAxisK0s, v2Axis}); + histos.add("QAMC/kstarv2vsinvmass", "Invariant mass vs v2 of unlike-sign chK(892)", HistType::kTH2D, {invMassAxisReso, v2Axis}); + histos.add("QAMC/kstarinvmass_noKstar", "Invariant mass of unlike-sign no chK(892)", HistType::kTH1D, {invMassAxisReso}); + histos.add("QAMC/kstarv2vsinvmass_noKstar", "Invariant mass vs v2 of unlike-sign no chK(892)", HistType::kTH2D, {invMassAxisReso, v2Axis}); + + if (AnalysisConfig.cfgFillAdditionalAxis) { + histos.add("hInvmass_Kstar_MC", "Invariant mass of unlike chK(892)", HistType::kTHnSparseD, {axisType, centAxis, ptAxis, invMassAxisReso, v2Axis, phiAxis}); + } else { + histos.add("hInvmass_Kstar_MC", "Invariant mass of unlike chK(892)", HistType::kTHnSparseD, {axisType, centAxis, ptAxis, invMassAxisReso, v2Axis}); + } + } + + ccdb->setURL(CCDBConfig.cfgURL); + ccdbApi.init("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + + // Print output histograms statistics + LOG(info) << "Size of the histograms in chK(892) Analysis Task"; + histos.print(); + } + + template + float getCentrality(CollisionType const& collision) + { + if (AnalysisConfig.cfgCentEst == 1) { + return collision.centFT0C(); + } else if (AnalysisConfig.cfgCentEst == 2) { + return collision.centFT0M(); + } else { + return -999; + } + } + + template + int getlDetId(DetNameType const& name) + { + LOGF(info, "GetlDetID running"); + if (name.value == "FT0C") { + return 0; + } else if (name.value == "FT0A") { + return 1; + } else if (name.value == "FT0M") { + return 2; + } else if (name.value == "FV0A") { + return 3; + } else if (name.value == "TPCpos") { + return 4; + } else if (name.value == "TPCneg") { + return 5; + } else { + return false; + } + } + + // Track selection + template + bool trackCut(TrackType const& track) + { + // basic track cuts + if (std::abs(track.pt()) < TrackCuts.cfgMinPtcut) + return false; + if (std::abs(track.eta()) > TrackCuts.cfgMaxEtacut) + return false; + if (track.itsNCls() < TrackCuts.cfgITScluster) + return false; + if (track.tpcNClsFound() < TrackCuts.cfgTPCcluster) + return false; + if (track.tpcCrossedRowsOverFindableCls() < TrackCuts.cfgRatioTPCRowsOverFindableCls) + return false; + if (track.itsChi2NCl() >= TrackCuts.cfgITSChi2NCl) + return false; + if (track.tpcChi2NCl() >= TrackCuts.cfgTPCChi2NCl) + return false; + if (TrackCuts.cfgHasITS && !track.hasITS()) + return false; + if (TrackCuts.cfgHasTPC && !track.hasTPC()) + return false; + if (TrackCuts.cfgHasTOF && !track.hasTOF()) + return false; + if (TrackCuts.cfgUseITSRefit && !track.passedITSRefit()) + return false; + if (TrackCuts.cfgUseTPCRefit && !track.passedTPCRefit()) + return false; + if (TrackCuts.cfgPVContributor && !track.isPVContributor()) + return false; + if (TrackCuts.cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (TrackCuts.cfgGlobalTrack && !track.isGlobalTrack()) + return false; + if (TrackCuts.cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (TrackCuts.cfgpTdepDCAxyCut) { + // Tuned on the LHC22f anchored MC LHC23d1d on primary pions. 7 Sigmas of the resolution + if (std::abs(track.dcaXY()) > (0.004 + (0.013 / track.pt()))) + return false; + } else { + if (std::abs(track.dcaXY()) > TrackCuts.cfgMaxbDCArToPVcut) + return false; + } + if (std::abs(track.dcaZ()) > TrackCuts.cfgMaxbDCAzToPVcut) + return false; + return true; + } + + // PID selection tools + template + bool selectionPIDPion(TrackType const& candidate) + { + bool tpcPIDPassed = std::abs(candidate.tpcNSigmaPi()) < PIDCuts.cfgMaxTPCnSigmaPion; + bool tofPIDPassed = false; + + if (PIDCuts.cfgTPConly) { + return tpcPIDPassed; + } + + if (candidate.hasTOF()) { + tofPIDPassed = std::abs(candidate.tofNSigmaPi()) < PIDCuts.cfgMaxTOFnSigmaPion || + (PIDCuts.cfgNsigmaCutCombinedPion > 0 && + candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi() + + candidate.tofNSigmaPi() * candidate.tofNSigmaPi() < + PIDCuts.cfgNsigmaCutCombinedPion * PIDCuts.cfgNsigmaCutCombinedPion); + } else { + tofPIDPassed = PIDCuts.cfgTOFVeto; + } + + return tpcPIDPassed && tofPIDPassed; + } + + template + bool selectionK0s(CollisionType const& collision, K0sType const& candidate) + { + auto lDauDCA = candidate.dcaV0daughters(); + auto lDauPosDCAtoPV = std::abs(candidate.dcapostopv()); + auto lDauNegDCAtoPV = std::abs(candidate.dcanegtopv()); + auto lPt = candidate.pt(); + auto lRapidity = candidate.yK0Short(); + auto lRadius = candidate.v0radius(); + auto lDCAtoPV = candidate.dcav0topv(); + auto lCPA = candidate.v0cosPA(); + auto lPropTauK0s = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassK0Short; + auto lMk0s = candidate.mK0Short(); + auto lMLambda = candidate.mLambda(); + auto lMALambda = candidate.mAntiLambda(); + + auto checkCommonCuts = [&]() { + if (lDauDCA > SecondaryCuts.cfgSecondaryDauDCAMax) + return false; + if (lDauPosDCAtoPV < SecondaryCuts.cfgSecondaryDauPosDCAtoPVMin) + return false; + if (lDauNegDCAtoPV < SecondaryCuts.cfgSecondaryDauNegDCAtoPVMin) + return false; + if (lPt < SecondaryCuts.cfgSecondaryPtMin) + return false; + if (std::fabs(lRapidity) > SecondaryCuts.cfgSecondaryRapidityMax) + return false; + if (lRadius < SecondaryCuts.cfgSecondaryRadiusMin || lRadius > SecondaryCuts.cfgSecondaryRadiusMax) + return false; + if (lDCAtoPV > SecondaryCuts.cfgSecondaryDCAtoPVMax) + return false; + if (lCPA < SecondaryCuts.cfgSecondaryCosPAMin) + return false; + if (lPropTauK0s > SecondaryCuts.cfgSecondaryProperLifetimeMax) + return false; + if (candidate.qtarm() < SecondaryCuts.cfgSecondaryparamArmenterosCut * std::abs(candidate.alpha())) + return false; + if (std::fabs(lMk0s - MassK0Short) > SecondaryCuts.cfgSecondaryMassWindow) + return false; + if (SecondaryCuts.cfgSecondaryCrossMassHypothesisCut && + ((std::fabs(lMLambda - MassLambda0) < SecondaryCuts.cfgSecondaryCrossMassCutWindow) || (std::fabs(lMALambda - MassLambda0Bar) < SecondaryCuts.cfgSecondaryCrossMassCutWindow))) + return false; + return true; + }; + + if (SecondaryCuts.cfgReturnFlag) { // For cut study + bool returnFlag = true; + histos.fill(HIST("QA/K0sCutCheck"), 0); + if (lDauDCA > SecondaryCuts.cfgSecondaryDauDCAMax) { + histos.fill(HIST("QA/K0sCutCheck"), 1); + returnFlag = false; + } + if (lDauPosDCAtoPV < SecondaryCuts.cfgSecondaryDauPosDCAtoPVMin) { + histos.fill(HIST("QA/K0sCutCheck"), 2); + returnFlag = false; + } + if (lDauNegDCAtoPV < SecondaryCuts.cfgSecondaryDauNegDCAtoPVMin) { + histos.fill(HIST("QA/K0sCutCheck"), 3); + returnFlag = false; + } + if (lPt < SecondaryCuts.cfgSecondaryPtMin) { + histos.fill(HIST("QA/K0sCutCheck"), 4); + returnFlag = false; + } + if (std::fabs(lRapidity) > SecondaryCuts.cfgSecondaryRapidityMax) { + histos.fill(HIST("QA/K0sCutCheck"), 5); + returnFlag = false; + } + if (lRadius < SecondaryCuts.cfgSecondaryRadiusMin || lRadius > SecondaryCuts.cfgSecondaryRadiusMax) { + histos.fill(HIST("QA/K0sCutCheck"), 6); + returnFlag = false; + } + if (lDCAtoPV > SecondaryCuts.cfgSecondaryDCAtoPVMax) { + histos.fill(HIST("QA/K0sCutCheck"), 7); + returnFlag = false; + } + if (lCPA < SecondaryCuts.cfgSecondaryCosPAMin) { + histos.fill(HIST("QA/K0sCutCheck"), 8); + returnFlag = false; + } + if (lPropTauK0s > SecondaryCuts.cfgSecondaryProperLifetimeMax) { + histos.fill(HIST("QA/K0sCutCheck"), 9); + returnFlag = false; + } + if (candidate.qtarm() < SecondaryCuts.cfgSecondaryparamArmenterosCut * std::abs(candidate.alpha())) { + histos.fill(HIST("QA/K0sCutCheck"), 10); + returnFlag = false; + } + if (std::fabs(lMk0s - MassK0Short) > SecondaryCuts.cfgSecondaryMassWindow) { + histos.fill(HIST("QA/K0sCutCheck"), 11); + returnFlag = false; + } + if (SecondaryCuts.cfgSecondaryCrossMassHypothesisCut && + ((std::fabs(lMLambda - MassLambda0) < SecondaryCuts.cfgSecondaryCrossMassCutWindow) || (std::fabs(lMALambda - MassLambda0Bar) < SecondaryCuts.cfgSecondaryCrossMassCutWindow))) { + histos.fill(HIST("QA/K0sCutCheck"), 12); + returnFlag = false; + } + return returnFlag; + } else { // normal usage + if (SecondaryCuts.cfgSecondaryRequire) { + return checkCommonCuts(); + } else { + return std::fabs(lMk0s - MassK0Short) <= SecondaryCuts.cfgSecondaryMassWindow; // always apply mass window cut + } + } + } // selectionK0s + + template + bool isTrueKstar(const TrackTemplate& bTrack, const V0Template& k0sCand) + { + if (std::abs(bTrack.PDGCode()) != kPiPlus) // Are you pion? + return false; + if (std::abs(k0sCand.PDGCode()) != kPDGK0s) // Are you K0s? + return false; + + auto motherbTrack = bTrack.template mothers_as(); + auto motherkV0 = k0sCand.template mothers_as(); + + // Check bTrack first + if (std::abs(motherbTrack.pdgCode()) != kKstarPlus) // Are you charged Kstar's daughter? + return false; // Apply first since it's more restrictive + + if (std::abs(motherkV0.pdgCode()) != 310) // Is it K0s? + return false; + // Check if K0s's mother is K0 (311) + auto motherK0 = motherkV0.template mothers_as(); + if (std::abs(motherK0.pdgCode()) != 311) + return false; + + // Check if K0's mother is Kstar (323) + auto motherKstar = motherK0.template mothers_as(); + if (std::abs(motherKstar.pdgCode()) != 323) + return false; + + // Check if bTrack and K0 have the same mother (global index) + if (motherbTrack.globalIndex() != motherK0.globalIndex()) + return false; + + return true; + } + + int count = 0; + + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksTypeK0s& dTracks2, int nmode) + { + histos.fill(HIST("QA/before/CentDist"), lCentrality); + + lQvecDetInd = lDetId * 4 + 3 + (nmode - 2) * EventPlaneConfig.cfgNQvec * 4; + lQvecRefAInd = lRefAId * 4 + 3 + (nmode - 2) * EventPlaneConfig.cfgNQvec * 4; + lQvecRefBInd = lRefBId * 4 + 3 + (nmode - 2) * EventPlaneConfig.cfgNQvec * 4; + + double lEPDet = std::atan2(collision.qvecIm()[lQvecDetInd], collision.qvecRe()[lQvecDetInd]) / static_cast(nmode); + double lEPRefB = std::atan2(collision.qvecIm()[lQvecRefAInd], collision.qvecRe()[lQvecRefAInd]) / static_cast(nmode); + double lEPRefC = std::atan2(collision.qvecIm()[lQvecRefBInd], collision.qvecRe()[lQvecRefBInd]) / static_cast(nmode); + + double lEPResAB = std::cos(static_cast(nmode) * (lEPDet - lEPRefB)); + double lEPResAC = std::cos(static_cast(nmode) * (lEPDet - lEPRefC)); + double lEPResBC = std::cos(static_cast(nmode) * (lEPRefB - lEPRefC)); + + // EP method + histos.fill(HIST("QA/EP/hEPDet"), lCentrality, lEPDet); + histos.fill(HIST("QA/EP/hEPB"), lCentrality, lEPRefB); + histos.fill(HIST("QA/EP/hEPC"), lCentrality, lEPRefC); + histos.fill(HIST("QA/EP/hEPResAB"), lCentrality, lEPResAB); + histos.fill(HIST("QA/EP/hEPResAC"), lCentrality, lEPResAC); + histos.fill(HIST("QA/EP/hEPResBC"), lCentrality, lEPResBC); + // Scalar product method + if (AnalysisConfig.cfgUseScalProduct) { + double lEPSPResAB = (collision.qvecRe()[lQvecDetInd] * collision.qvecRe()[lQvecRefAInd] + collision.qvecIm()[lQvecDetInd] * collision.qvecIm()[lQvecRefAInd]); + double lEPSPResAC = (collision.qvecRe()[lQvecDetInd] * collision.qvecRe()[lQvecRefBInd] + collision.qvecIm()[lQvecDetInd] * collision.qvecIm()[lQvecRefBInd]); + double lEPSPResBC = (collision.qvecRe()[lQvecRefAInd] * collision.qvecRe()[lQvecRefBInd] + collision.qvecIm()[lQvecRefAInd] * collision.qvecIm()[lQvecRefBInd]); + + histos.fill(HIST("QA/EP/hEPSPResAB"), lCentrality, lEPSPResAB); + histos.fill(HIST("QA/EP/hEPSPResAC"), lCentrality, lEPSPResAC); + histos.fill(HIST("QA/EP/hEPSPResBC"), lCentrality, lEPSPResBC); + } + + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResoSecondary, lDecayDaughter_bach, lResoKstar, lDaughterRot, lResonanceRot; + std::vector trackIndicies = {}; + std::vector k0sIndicies = {}; + + for (const auto& bTrack : dTracks1) { + auto trkbpt = bTrack.pt(); + auto istrkbhasTOF = bTrack.hasTOF(); + auto trkbNSigmaPiTPC = bTrack.tpcNSigmaPi(); + auto trkbNSigmaPiTOF = (istrkbhasTOF) ? bTrack.tofNSigmaPi() : -999.; + + if constexpr (!IsMix) { + if (AnalysisConfig.cfgFillQAPlots) { + // Bachelor pion QA plots + histos.fill(HIST("QA/before/trkbpionTPCPID"), trkbpt, trkbNSigmaPiTPC); + if (istrkbhasTOF) { + histos.fill(HIST("QA/before/trkbpionTOFPID"), trkbpt, trkbNSigmaPiTOF); + histos.fill(HIST("QA/before/trkbpionTPCTOFPID"), trkbNSigmaPiTPC, trkbNSigmaPiTOF); + } + histos.fill(HIST("QA/before/trkbpionpT"), trkbpt); + histos.fill(HIST("QA/before/trkbpionDCAxy"), bTrack.dcaXY()); + histos.fill(HIST("QA/before/trkbpionDCAz"), bTrack.dcaZ()); + } + } + + if (!trackCut(bTrack)) + continue; + if (!selectionPIDPion(bTrack)) + continue; + + if constexpr (!IsMix) { + if (AnalysisConfig.cfgFillQAPlots) { + // Bachelor pion QA plots after applying cuts + histos.fill(HIST("QA/after/trkbpionTPCPID"), trkbpt, trkbNSigmaPiTPC); + if (istrkbhasTOF) { + histos.fill(HIST("QA/after/trkbpionTOFPID"), trkbpt, trkbNSigmaPiTOF); + histos.fill(HIST("QA/after/trkbpionTPCTOFPID"), trkbNSigmaPiTPC, trkbNSigmaPiTOF); + } + histos.fill(HIST("QA/after/trkbpionpT"), trkbpt); + histos.fill(HIST("QA/after/trkbpionDCAxy"), bTrack.dcaXY()); + histos.fill(HIST("QA/after/trkbpionDCAz"), bTrack.dcaZ()); + } + } + trackIndicies.push_back(bTrack.index()); + } + + for (const auto& k0sCand : dTracks2) { + auto posDauTrack = k0sCand.template posTrack_as(); + auto negDauTrack = k0sCand.template negTrack_as(); + + /// Daughters + // Positve pion + auto trkppt = posDauTrack.pt(); + auto istrkphasTOF = posDauTrack.hasTOF(); + auto trkpNSigmaPiTPC = posDauTrack.tpcNSigmaPi(); + auto trkpNSigmaPiTOF = (istrkphasTOF) ? posDauTrack.tofNSigmaPi() : -999.; + // Negative pion + auto trknpt = negDauTrack.pt(); + auto istrknhasTOF = negDauTrack.hasTOF(); + auto trknNSigmaPiTPC = negDauTrack.tpcNSigmaPi(); + auto trknNSigmaPiTOF = (istrknhasTOF) ? negDauTrack.tofNSigmaPi() : -999.; + + /// K0s + auto trkkDauDCA = k0sCand.dcaV0daughters(); + auto trkky = k0sCand.yK0Short(); + auto trkkDCAtoPV = k0sCand.dcav0topv(); + auto trkkCPA = k0sCand.v0cosPA(); + auto trkkPropTau = k0sCand.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassK0Short; + auto trkkMass = k0sCand.mK0Short(); + + lResoSecondary.SetXYZM(k0sCand.px(), k0sCand.py(), k0sCand.pz(), MassK0Short); + auto lPhiMinusPsiK0s = RecoDecay::constrainAngle(lResoSecondary.Phi() - lEPDet, 0.0, 2); // constrain angle to range 0, Pi + auto v2K0s = std::cos(static_cast(nmode) * lPhiMinusPsiK0s); + if constexpr (!IsMix) { + if (AnalysisConfig.cfgFillQAPlots) { + // Seconddary QA plots + histos.fill(HIST("QA/before/trkppionTPCPID"), trkppt, trkpNSigmaPiTPC); + if (istrkphasTOF) { + histos.fill(HIST("QA/before/trkppionTOFPID"), trkppt, trkpNSigmaPiTOF); + histos.fill(HIST("QA/before/trkppionTPCTOFPID"), trkpNSigmaPiTPC, trkpNSigmaPiTOF); + } + histos.fill(HIST("QA/before/trkppionpT"), trkppt); + histos.fill(HIST("QA/before/trkppionDCAxy"), posDauTrack.dcaXY()); + histos.fill(HIST("QA/before/trkppionDCAz"), posDauTrack.dcaZ()); + + histos.fill(HIST("QA/before/trknpionTPCPID"), trknpt, trknNSigmaPiTPC); + if (istrknhasTOF) { + histos.fill(HIST("QA/before/trknpionTOFPID"), trknpt, trknNSigmaPiTOF); + histos.fill(HIST("QA/before/trknpionTPCTOFPID"), trknNSigmaPiTPC, trknNSigmaPiTOF); + } + histos.fill(HIST("QA/before/trknpionpT"), trknpt); + histos.fill(HIST("QA/before/trknpionDCAxy"), negDauTrack.dcaXY()); + histos.fill(HIST("QA/before/trknpionDCAz"), negDauTrack.dcaZ()); + histos.fill(HIST("QA/before/hDauDCASecondary"), trkkDauDCA); + histos.fill(HIST("QA/before/hy_Secondary"), trkky); + histos.fill(HIST("QA/before/hDCAtoPVSecondary"), trkkDCAtoPV); + histos.fill(HIST("QA/before/hCPASecondary"), trkkCPA); + histos.fill(HIST("QA/before/hPropTauSecondary"), trkkPropTau); + histos.fill(HIST("QA/before/hInvmassSecondary"), trkkMass); + + histos.fill(HIST("QA/before/k0sv2vsinvmass"), lResoSecondary.M(), v2K0s); + } + } + + if (!SecondaryCuts.cfgByPassDauPIDSelection && !selectionPIDPion(posDauTrack)) + continue; + if (!SecondaryCuts.cfgByPassDauPIDSelection && !selectionPIDPion(negDauTrack)) + continue; + if (!selectionK0s(collision, k0sCand)) + continue; + + if constexpr (!IsMix) { + if (AnalysisConfig.cfgFillQAPlots) { + // Seconddary QA plots after applying cuts + histos.fill(HIST("QA/after/trkppionTPCPID"), trkppt, trkpNSigmaPiTPC); + if (istrkphasTOF) { + histos.fill(HIST("QA/after/trkppionTOFPID"), trkppt, trkpNSigmaPiTOF); + histos.fill(HIST("QA/after/trkppionTPCTOFPID"), trkpNSigmaPiTPC, trkpNSigmaPiTOF); + } + histos.fill(HIST("QA/after/trkppionpT"), trkppt); + histos.fill(HIST("QA/after/trkppionDCAxy"), posDauTrack.dcaXY()); + histos.fill(HIST("QA/after/trkppionDCAz"), posDauTrack.dcaZ()); + + histos.fill(HIST("QA/after/trknpionTPCPID"), trknpt, trknNSigmaPiTPC); + if (istrknhasTOF) { + histos.fill(HIST("QA/after/trknpionTOFPID"), trknpt, trknNSigmaPiTOF); + histos.fill(HIST("QA/after/trknpionTPCTOFPID"), trknNSigmaPiTPC, trknNSigmaPiTOF); + } + histos.fill(HIST("QA/after/trknpionpT"), trknpt); + histos.fill(HIST("QA/after/trknpionDCAxy"), negDauTrack.dcaXY()); + histos.fill(HIST("QA/after/trknpionDCAz"), negDauTrack.dcaZ()); + + histos.fill(HIST("QA/after/hDauDCASecondary"), trkkDauDCA); + histos.fill(HIST("QA/after/hy_Secondary"), trkky); + histos.fill(HIST("QA/after/hDCAtoPVSecondary"), trkkDCAtoPV); + histos.fill(HIST("QA/after/hCPASecondary"), trkkCPA); + histos.fill(HIST("QA/after/hPropTauSecondary"), trkkPropTau); + histos.fill(HIST("QA/after/hInvmassSecondary"), trkkMass); + + histos.fill(HIST("QA/after/k0sv2vsinvmass"), lResoSecondary.M(), v2K0s); + if (AnalysisConfig.cfgFillAdditionalAxis) { + histos.fill(HIST("hInvmass_K0s"), lCentrality, lResoSecondary.Pt(), lResoSecondary.M(), v2K0s, static_cast(nmode) * lPhiMinusPsiK0s); + } else { + histos.fill(HIST("hInvmass_K0s"), lCentrality, lResoSecondary.Pt(), lResoSecondary.M(), v2K0s); + } + } + if (AnalysisConfig.cfgFillAdditionalAxis) { + histos.fill(HIST("hInvmass_K0s"), lCentrality, lResoSecondary.Pt(), lResoSecondary.M(), v2K0s, static_cast(nmode) * lPhiMinusPsiK0s); + } else { + histos.fill(HIST("hInvmass_K0s"), lCentrality, lResoSecondary.Pt(), lResoSecondary.M(), v2K0s); + } + k0sIndicies.push_back(k0sCand.index()); + } + } + + for (const auto& trackIndex : trackIndicies) { + for (const auto& k0sIndex : k0sIndicies) { + auto bTrack = dTracks1.rawIteratorAt(trackIndex); + auto k0sCand = dTracks2.rawIteratorAt(k0sIndex); + + lDecayDaughter_bach.SetXYZM(bTrack.px(), bTrack.py(), bTrack.pz(), MassPionCharged); + lResoSecondary.SetXYZM(k0sCand.px(), k0sCand.py(), k0sCand.pz(), MassK0Short); + lResoKstar = lResoSecondary + lDecayDaughter_bach; + auto resoPhi = lResoKstar.Phi(); + // EP method + auto lPhiMinusPsiKstar = RecoDecay::constrainAngle(resoPhi - lEPDet, 0.0, 2); // constrain angle to range 0, Pi + auto resoFlowValue = std::cos(static_cast(nmode) * lPhiMinusPsiKstar); + // Scalar product method + if (AnalysisConfig.cfgUseScalProduct) { + float cosNPhi = std::cos(static_cast(nmode) * resoPhi); + float sinNPhi = std::sin(static_cast(nmode) * resoPhi); + resoFlowValue = cosNPhi * collision.qvecRe()[lQvecDetInd] + sinNPhi * collision.qvecIm()[lQvecDetInd]; + } + + // QA plots + if constexpr (!IsMix) { + if (AnalysisConfig.cfgFillQAPlots) { + histos.fill(HIST("QA/before/KstarRapidity"), lResoKstar.Rapidity()); + histos.fill(HIST("QA/before/kstarinvmass"), lResoKstar.M()); + histos.fill(HIST("QA/before/kstarv2vsinvmass"), lResoKstar.M(), resoFlowValue); + } + } + + if (lResoKstar.Rapidity() > KstarCuts.cfgKstarMaxRap || lResoKstar.Rapidity() < KstarCuts.cfgKstarMinRap) + continue; + + if constexpr (!IsMix) { + unsigned int typeKstar = bTrack.sign() > 0 ? BinType::kKstarP : BinType::kKstarN; + + if (AnalysisConfig.cfgFillQAPlots) { + histos.fill(HIST("QA/after/KstarRapidity"), lResoKstar.Rapidity()); + histos.fill(HIST("QA/after/kstarinvmass"), lResoKstar.M()); + histos.fill(HIST("QA/after/kstarv2vsinvmass"), lResoKstar.M(), resoFlowValue); + } + if (AnalysisConfig.cfgFillAdditionalAxis) { + histos.fill(HIST("hInvmass_Kstar"), typeKstar, lCentrality, lResoKstar.Pt(), lResoKstar.M(), resoFlowValue, static_cast(nmode) * lPhiMinusPsiKstar); + } else { + histos.fill(HIST("hInvmass_Kstar"), typeKstar, lCentrality, lResoKstar.Pt(), lResoKstar.M(), resoFlowValue); + } + + if (BkgEstimationConfig.cfgFillRotBkg) { + for (int i = 0; i < BkgEstimationConfig.cfgNrotBkg; i++) { + auto lRotAngle = BkgEstimationConfig.cfgMinRot + i * ((BkgEstimationConfig.cfgMaxRot - BkgEstimationConfig.cfgMinRot) / (BkgEstimationConfig.cfgNrotBkg - 1)); + if (AnalysisConfig.cfgFillQAPlots) { + histos.fill(HIST("QA/RotBkg/hRotBkg"), lRotAngle); + } + if (BkgEstimationConfig.cfgRotPion) { + lDaughterRot = lDecayDaughter_bach; + lDaughterRot.RotateZ(lRotAngle); + lResonanceRot = lDaughterRot + lResoSecondary; + } else { + lDaughterRot = lResoSecondary; + lDaughterRot.RotateZ(lRotAngle); + lResonanceRot = lDecayDaughter_bach + lDaughterRot; + } + resoPhi = lResonanceRot.Phi(); + auto lPhiMinusPsiKstar = RecoDecay::constrainAngle(resoPhi - lEPDet, 0.0, 2); // constrain angle to range 0, Pi + auto resoFlowValue = std::cos(static_cast(nmode) * lPhiMinusPsiKstar); + if (AnalysisConfig.cfgUseScalProduct) { + float cosNPhi = std::cos(static_cast(nmode) * resoPhi); + float sinNPhi = std::sin(static_cast(nmode) * resoPhi); + resoFlowValue = cosNPhi * collision.qvecRe()[lQvecDetInd] + sinNPhi * collision.qvecIm()[lQvecDetInd]; + } + typeKstar = bTrack.sign() > 0 ? BinType::kKstarP_Rot : BinType::kKstarN_Rot; + if (AnalysisConfig.cfgFillAdditionalAxis) { + histos.fill(HIST("hInvmass_Kstar"), typeKstar, lCentrality, lResonanceRot.Pt(), lResonanceRot.M(), resoFlowValue, static_cast(nmode) * lPhiMinusPsiKstar); + } else { + histos.fill(HIST("hInvmass_Kstar"), typeKstar, lCentrality, lResonanceRot.Pt(), lResonanceRot.M(), resoFlowValue); + } + } + } + } // IsMix + } // k0sCand + } // bTrack + + count++; + + } // fillHistograms + + // process dummy + void processDummy(aod::Collisions const&) + { + } + PROCESS_SWITCH(Chk892Flow, processDummy, "process Dummy", true); + + // process data + void processData(EventCandidates::iterator const& collision, + TrackCandidates const& tracks, + V0Candidates const& v0s, + aod::BCsWithTimestamps const&) + { + if (!colCuts.isSelected(collision)) // Default event selection + return; + if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) { + return; + } + if (AnalysisConfig.cfgQvecSel && (collision.qvecAmp()[lDetId] < 1e-4 || collision.qvecAmp()[lRefAId] < 1e-4 || collision.qvecAmp()[lRefBId] < 1e-4)) + return; // If we don't have a Q-vector + lCentrality = getCentrality(collision); + if (lCentrality < EventCuts.cfgEventCentralityMin || lCentrality > EventCuts.cfgEventCentralityMax) + return; + colCuts.fillQA(collision); + + fillHistograms(collision, tracks, v0s, EventPlaneConfig.cfgnMods); // second order + } + PROCESS_SWITCH(Chk892Flow, processData, "Process Event for data without Partitioning", false); + + // process MC reconstructed level + void processMC(EventCandidates::iterator const& collision, + MCTrackCandidates const& tracks, + MCV0Candidates const& v0s) + { + if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) { + return; + } + fillHistograms(collision, tracks, v0s, EventPlaneConfig.cfgnMods); + } + PROCESS_SWITCH(Chk892Flow, processMC, "Process Event for MC", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/chk892flow_pp.cxx b/PWGLF/Tasks/Resonances/chk892flow_pp.cxx new file mode 100644 index 00000000000..7e1d65bd7e8 --- /dev/null +++ b/PWGLF/Tasks/Resonances/chk892flow_pp.cxx @@ -0,0 +1,930 @@ +// 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 chk892_pp.cxx +/// \brief Reconstruction of track-track decay resonance candidates +/// +/// +/// \author Su-Jeong Ji + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // FIXME +#include // FIXME + +#include +#include +#include +#include +#include +#include + +#include "TRandom3.h" +#include "TF1.h" +#include "TVector2.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/StaticFor.h" +#include "DCAFitter/DCAFitterN.h" + +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/RecoDecay.h" + +#include "CommonConstants/PhysicsConstants.h" + +#include "ReconstructionDataFormats/Track.h" + +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" + +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" + +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/collisionCuts.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; + +struct chk892_pp { + enum binType : unsigned int { + kKstarP = 0, + kKstarN, + kKstarP_Mix, + kKstarN_Mix, + kKstarP_GenINEL10, + kKstarN_GenINEL10, + kKstarP_GenINELgt10, + kKstarN_GenINELgt10, + kKstarP_GenTrig10, + kKstarN_GenTrig10, + kKstarP_GenEvtSel, + kKstarN_GenEvtSel, + kKstarP_Rec, + kKstarN_Rec, + kTYEnd + }; + + SliceCache cache; + Preslice perCollision = aod::track::collisionId; + + using EventCandidates = soa::Join; + // using EventCandidates = soa::Join; + using TrackCandidates = soa::Join; + using V0Candidates = aod::V0Datas; + + using MCEventCandidates = soa::Join; + using MCTrackCandidates = soa::Join; + using MCV0Candidates = soa::Join; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Service ccdb; + Service pdg; + o2::ccdb::CcdbApi ccdbApi; + + Configurable cfgURL{"cfgURL", "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; + Configurable nolaterthan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "Latest acceptable timestamp of creation for the object"}; + + // Configurables + ConfigurableAxis cfgBinsPt{"cfgBinsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12.0, 12.1, 12.2, 12.3, 12.4, 12.5, 12.6, 12.7, 12.8, 12.9, 13.0, 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7, 13.8, 13.9, 14.0, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15.0}, "Binning of the pT axis"}; + ConfigurableAxis cfgBinsPtQA{"cfgBinsPtQA", {VARIABLE_WIDTH, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2, 6.4, 6.6, 6.8, 7.0, 7.2, 7.4, 7.6, 7.8, 8.0, 8.2, 8.4, 8.6, 8.8, 9.0, 9.2, 9.4, 9.6, 9.8, 10.0}, "Binning of the pT axis"}; + ConfigurableAxis cfgBinsCent{"cfgBinsCent", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0}, "Binning of the centrality axis"}; + ConfigurableAxis cfgBinsVtxZ{"cfgBinsVtxZ", {VARIABLE_WIDTH, -10.0, -9.0, -8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0}, "Binning of the z-vertex axis"}; + Configurable cNbinsDiv{"cNbinsDiv", 1, "Integer to divide the number of bins"}; + + /// Event cuts + o2::analysis::CollisonCuts colCuts; + Configurable ConfEvtZvtx{"ConfEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; + Configurable ConfEvtOccupancyInTimeRangeMax{"ConfEvtOccupancyInTimeRangeMax", -1, "Evt sel: maximum track occupancy"}; + Configurable ConfEvtOccupancyInTimeRangeMin{"ConfEvtOccupancyInTimeRangeMin", -1, "Evt sel: minimum track occupancy"}; + Configurable ConfEvtTriggerCheck{"ConfEvtTriggerCheck", false, "Evt sel: check for trigger"}; + Configurable ConfEvtOfflineCheck{"ConfEvtOfflineCheck", true, "Evt sel: check for offline selection"}; + Configurable ConfEvtTriggerTVXSel{"ConfEvtTriggerTVXSel", false, "Evt sel: triggerTVX selection (MB)"}; + Configurable ConfEvtTFBorderCut{"ConfEvtTFBorderCut", false, "Evt sel: apply TF border cut"}; + Configurable ConfEvtUseITSTPCvertex{"ConfEvtUseITSTPCvertex", false, "Evt sel: use at lease on ITS-TPC track for vertexing"}; + Configurable ConfEvtZvertexTimedifference{"ConfEvtZvertexTimedifference", true, "Evt sel: apply Z-vertex time difference"}; + Configurable ConfEvtPileupRejection{"ConfEvtPileupRejection", true, "Evt sel: apply pileup rejection"}; + Configurable ConfEvtNoITSROBorderCut{"ConfEvtNoITSROBorderCut", false, "Evt sel: apply NoITSRO border cut"}; + Configurable ConfincludeCentralityMC{"ConfincludeCentralityMC", false, "Include centrality in MC"}; + Configurable ConfEvtCollInTimeRangeStandard{"ConfEvtCollInTimeRangeStandard", true, "Evt sel: apply NoCollInTimeRangeStandard"}; + + /// Track selections + Configurable cMinPtcut{"cMinPtcut", 0.15, "Track minium pt cut"}; + Configurable cMaxEtacut{"cMaxEtacut", 0.8, "Track maximum eta cut"}; + + /* + // Cuts from polarization analysis + Configurable cfgOccupancySel{"cfgOccupancySel", false, "Occupancy selection"}; + Configurable cfgMaxOccupancy{"cfgMaxOccupancy", 999999, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable cfgMinOccupancy{"cfgMinOccupancy", -100, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable cfgNCollinTR{"cfgNCollinTR", false, "Additional selection for the number of coll in time range"}; +*/ + Configurable cfgCentEst{"cfgCentEst", 1, "Centrality estimator, 1: FT0C, 2: FT0M"}; + + // DCAr to PV + Configurable cMaxbDCArToPVcut{"cMaxbDCArToPVcut", 0.1, "Track DCAr cut to PV Maximum"}; + // DCAz to PV + Configurable cMaxbDCAzToPVcut{"cMaxbDCAzToPVcut", 0.1, "Track DCAz cut to PV Maximum"}; + + /// PID Selections, pion + Configurable cTPConly{"cTPConly", true, "Use only TPC for PID"}; // bool + Configurable cMaxTPCnSigmaPion{"cMaxTPCnSigmaPion", 3.0, "TPC nSigma cut for Pion"}; // TPC + Configurable cMaxTOFnSigmaPion{"cMaxTOFnSigmaPion", 3.0, "TOF nSigma cut for Pion"}; // TOF + Configurable nsigmaCutCombinedPion{"nsigmaCutCombinedPion", -999, "Combined nSigma cut for Pion"}; // Combined + Configurable cTOFVeto{"cTOFVeto", true, "TOF Veto, if false, TOF is nessessary for PID selection"}; // TOF Veto + + // Track selections + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) + Configurable cfgGlobalTrack{"cfgGlobalTrack", false, "Global track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgPVContributor{"cfgPVContributor", false, "PV contributor track selection"}; // PV Contriuibutor + + Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 0, "Number of TPC cluster"}; + Configurable cfgRatioTPCRowsOverFindableCls{"cfgRatioTPCRowsOverFindableCls", 0.0f, "TPC Crossed Rows to Findable Clusters"}; + Configurable cfgITSChi2NCl{"cfgITSChi2NCl", 999.0, "ITS Chi2/NCl"}; + Configurable cfgTPCChi2NCl{"cfgTPCChi2NCl", 999.0, "TPC Chi2/NCl"}; + Configurable cfgUseTPCRefit{"cfgUseTPCRefit", false, "Require TPC Refit"}; + Configurable cfgUseITSRefit{"cfgUseITSRefit", false, "Require ITS Refit"}; + Configurable cfgHasITS{"cfgHasITS", false, "Require ITS"}; + Configurable cfgHasTPC{"cfgHasTPC", false, "Require TPC"}; + Configurable cfgHasTOF{"cfgHasTOF", false, "Require TOF"}; + + // Secondary Selection + Configurable cfgReturnFlag{"boolReturnFlag", false, "Return Flag for debugging"}; + Configurable cSecondaryRequire{"bool", true, "Secondary cuts on/off"}; + Configurable cSecondaryArmenterosCut{"boolArmenterosCut", true, "cut on Armenteros-Podolanski graph"}; + + Configurable cfgByPassDauPIDSelection{"cfgByPassDauPIDSelection", true, "Bypass Daughters PID selection"}; + Configurable cSecondaryDauDCAMax{"cSecondaryDauDCAMax", 1., "Maximum DCA Secondary daughters to PV"}; + Configurable cSecondaryDauPosDCAtoPVMin{"cSecondaryDauPosDCAtoPVMin", 0.0, "Minimum DCA Secondary positive daughters to PV"}; + Configurable cSecondaryDauNegDCAtoPVMin{"cSecondaryDauNegDCAtoPVMin", 0.0, "Minimum DCA Secondary negative daughters to PV"}; + + Configurable cSecondaryPtMin{"cSecondaryPtMin", 0.f, "Minimum transverse momentum of Secondary"}; + Configurable cSecondaryRapidityMax{"cSecondaryRapidityMax", 0.5, "Maximum rapidity of Secondary"}; + Configurable cSecondaryRadiusMin{"cSecondaryRadiusMin", 1.2, "Minimum transverse radius of Secondary"}; + Configurable cSecondaryCosPAMin{"cSecondaryCosPAMin", 0.995, "Mininum cosine pointing angle of Secondary"}; + Configurable cSecondaryDCAtoPVMax{"cSecondaryDCAtoPVMax", 0.3, "Maximum DCA Secondary to PV"}; + Configurable cSecondaryProperLifetimeMax{"cSecondaryProperLifetimeMax", 20, "Maximum Secondary Lifetime"}; + Configurable cSecondaryparamArmenterosCut{"paramArmenterosCut", 0.2, "parameter for Armenteros Cut"}; + Configurable cSecondaryMassWindow{"cSecondaryMassWindow", 0.075, "Secondary inv mass selciton window"}; + + // K* selection + Configurable cKstarMaxRap{"cKstarMaxRap", 0.5, "Kstar maximum rapidity"}; + Configurable cKstarMinRap{"cKstarMinRap", -0.5, "Kstar minimum rapidity"}; + + float centrality; + + // PDG code + int kPDGK0s = 310; + int kPDGK0 = 311; + int kKstarPlus = 323; + int kPiPlus = 211; + + void init(o2::framework::InitContext&) + { + centrality = -999; + + colCuts.setCuts(ConfEvtZvtx, ConfEvtTriggerCheck, ConfEvtOfflineCheck, /*checkRun3*/ true, /*triggerTVXsel*/ false, ConfEvtOccupancyInTimeRangeMax, ConfEvtOccupancyInTimeRangeMin); + colCuts.init(&histos); + colCuts.setTriggerTVX(ConfEvtTriggerTVXSel); + colCuts.setApplyTFBorderCut(ConfEvtTFBorderCut); + colCuts.setApplyITSTPCvertex(ConfEvtUseITSTPCvertex); + colCuts.setApplyZvertexTimedifference(ConfEvtZvertexTimedifference); + colCuts.setApplyPileupRejection(ConfEvtPileupRejection); + colCuts.setApplyNoITSROBorderCut(ConfEvtNoITSROBorderCut); + colCuts.setApplyCollInTimeRangeStandard(ConfEvtCollInTimeRangeStandard); + + AxisSpec centAxis = {cfgBinsCent, "T0M (%)"}; + AxisSpec vtxzAxis = {cfgBinsVtxZ, "Z Vertex (cm)"}; + AxisSpec epAxis = {100, -1.0 * constants::math::PI, constants::math::PI}; + AxisSpec epresAxis = {100, -1.02, 1.02}; + AxisSpec ptAxis = {cfgBinsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptAxisQA = {cfgBinsPtQA, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec radiusAxis = {50, 0, 5, "Radius (cm)"}; + AxisSpec cpaAxis = {50, 0.95, 1.0, "CPA"}; + AxisSpec tauAxis = {250, 0, 25, "Lifetime (cm)"}; + AxisSpec dcaAxis = {200, 0, 2, "DCA (cm)"}; + AxisSpec dcaxyAxis = {200, 0, 2, "DCA_{#it{xy}} (cm)"}; + AxisSpec dcazAxis = {200, 0, 2, "DCA_{#it{z}} (cm)"}; + AxisSpec yAxis = {100, -1, 1, "Rapidity"}; + AxisSpec invMassAxisK0s = {400 / cNbinsDiv, 0.3, 0.7, "Invariant Mass (GeV/#it{c}^2)"}; // K0s ~497.611 + AxisSpec invMassAxisReso = {900 / cNbinsDiv, 0.5f, 1.4f, "Invariant Mass (GeV/#it{c}^2)"}; // chK(892) ~892 + AxisSpec invMassAxisScan = {150, 0, 1.5, "Invariant Mass (GeV/#it{c}^2)"}; // For selection + AxisSpec pidQAAxis = {130, -6.5, 6.5}; + AxisSpec dataTypeAxis = {9, 0, 9, "Histogram types"}; + AxisSpec mcTypeAxis = {4, 0, 4, "Histogram types"}; + + // THnSparse + AxisSpec axisType = {binType::kTYEnd, 0, binType::kTYEnd, "Type of bin with charge and mix"}; + AxisSpec mcLabelAxis = {5, -0.5, 4.5, "MC Label"}; + + histos.add("QA/K0sCutCheck", "Check K0s cut", HistType::kTH1D, {AxisSpec{12, -0.5, 11.5, "Check"}}); + + histos.add("QA/before/CentDist", "Centrality distribution", {HistType::kTH1D, {centAxis}}); + histos.add("QA/before/VtxZ", "Centrality distribution", {HistType::kTH1D, {vtxzAxis}}); + histos.add("QA/before/hEvent", "Number of Events", HistType::kTH1F, {{1, 0.5, 1.5}}); + + // Bachelor pion + histos.add("QA/before/trkbpionDCAxy", "DCAxy distribution of bachelor pion candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/before/trkbpionDCAz", "DCAz distribution of bachelor pion candidates", HistType::kTH1D, {dcazAxis}); + histos.add("QA/before/trkbpionpT", "pT distribution of bachelor pion candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/before/trkbpionTPCPID", "TPC PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkbpionTOFPID", "TOF PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkbpionTPCTOFPID", "TPC-TOF PID map of bachelor pion candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + + histos.add("QA/after/trkbpionDCAxy", "DCAxy distribution of bachelor pion candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/after/trkbpionDCAz", "DCAz distribution of bachelor pion candidates", HistType::kTH1D, {dcazAxis}); + histos.add("QA/after/trkbpionpT", "pT distribution of bachelor pion candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/after/trkbpionTPCPID", "TPC PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkbpionTOFPID", "TOF PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkbpionTPCTOFPID", "TPC-TOF PID map of bachelor pion candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + + // Secondary pion 1 + histos.add("QA/before/trkppionTPCPID", "TPC PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkppionTOFPID", "TOF PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkppionTPCTOFPID", "TPC-TOF PID map of secondary pion 1 (positive) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/before/trkppionpT", "pT distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/before/trkppionDCAxy", "DCAxy distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/before/trkppionDCAz", "DCAz distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcazAxis}); + + histos.add("QA/after/trkppionTPCPID", "TPC PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkppionTOFPID", "TOF PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkppionTPCTOFPID", "TPC-TOF PID map of secondary pion 1 (positive) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/after/trkppionpT", "pT distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/after/trkppionDCAxy", "DCAxy distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/after/trkppionDCAz", "DCAz distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcazAxis}); + + // Secondary pion 2 + histos.add("QA/before/trknpionTPCPID", "TPC PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trknpionTOFPID", "TOF PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trknpionTPCTOFPID", "TPC-TOF PID map of secondary pion 2 (negative) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/before/trknpionpT", "pT distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/before/trknpionDCAxy", "DCAxy distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/before/trknpionDCAz", "DCAz distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcazAxis}); + + histos.add("QA/after/trknpionTPCPID", "TPC PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trknpionTOFPID", "TOF PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trknpionTPCTOFPID", "TPC-TOF PID map of secondary pion 2 (negative) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/after/trknpionpT", "pT distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/after/trknpionDCAxy", "DCAxy distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/after/trknpionDCAz", "DCAz distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcazAxis}); + + // K0s + histos.add("QA/before/hDauDCASecondary", "DCA of daughters of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/before/hDauPosDCAtoPVSecondary", "Pos DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/before/hDauNegDCAtoPVSecondary", "Neg DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/before/hpT_Secondary", "pT distribution of secondary resonance", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/before/hy_Secondary", "Rapidity distribution of secondary resonance", HistType::kTH1D, {yAxis}); + histos.add("QA/before/hRadiusSecondary", "Radius distribution of secondary resonance", HistType::kTH1D, {radiusAxis}); + histos.add("QA/before/hCPASecondary", "Cosine pointing angle distribution of secondary resonance", HistType::kTH1D, {cpaAxis}); + histos.add("QA/before/hDCAtoPVSecondary", "DCA to PV distribution of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/before/hPropTauSecondary", "Proper Lifetime distribution of secondary resonance", HistType::kTH1D, {tauAxis}); + histos.add("QA/before/hPtAsymSecondary", "pT asymmetry distribution of secondary resonance", HistType::kTH1D, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); + histos.add("QA/before/hInvmassSecondary", "Invariant mass of unlike-sign secondary resonance", HistType::kTH1D, {invMassAxisK0s}); + + histos.add("QA/after/hDauDCASecondary", "DCA of daughters of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/after/hDauPosDCAtoPVSecondary", "Pos DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/after/hDauNegDCAtoPVSecondary", "Neg DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/after/hpT_Secondary", "pT distribution of secondary resonance", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/after/hy_Secondary", "Rapidity distribution of secondary resonance", HistType::kTH1D, {yAxis}); + histos.add("QA/after/hRadiusSecondary", "Radius distribution of secondary resonance", HistType::kTH1D, {radiusAxis}); + histos.add("QA/after/hCPASecondary", "Cosine pointing angle distribution of secondary resonance", HistType::kTH1D, {cpaAxis}); + histos.add("QA/after/hDCAtoPVSecondary", "DCA to PV distribution of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/after/hPropTauSecondary", "Proper Lifetime distribution of secondary resonance", HistType::kTH1D, {tauAxis}); + histos.add("QA/after/hPtAsymSecondary", "pT asymmetry distribution of secondary resonance", HistType::kTH1D, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); + histos.add("QA/after/hInvmassSecondary", "Invariant mass of unlike-sign secondary resonance", HistType::kTH1D, {invMassAxisK0s}); + + // Kstar + // Invariant mass nSparse + histos.add("QA/before/KstarRapidity", "Rapidity distribution of chK(892)", HistType::kTH1D, {yAxis}); + histos.add("hInvmass_Kstar", "Invariant mass of unlike-sign chK(892)", HistType::kTHnSparseD, {axisType, centAxis, ptAxis, invMassAxisReso}); + histos.add("hInvmass_Kstar_Mix", "Invariant mass of unlike-sign chK(892) from mixed event", HistType::kTHnSparseD, {axisType, centAxis, ptAxis, invMassAxisReso}); + + // Mass QA (quick check) + histos.add("QA/before/kstarinvmass", "Invariant mass of unlike-sign chK(892)", HistType::kTH1D, {invMassAxisReso}); + histos.add("QA/before/kstarinvmass_Mix", "Invariant mass of unlike-sign chK(892) from mixed event", HistType::kTH1D, {invMassAxisReso}); + + histos.add("QA/after/KstarRapidity", "Rapidity distribution of chK(892)", HistType::kTH1D, {yAxis}); + histos.add("QA/after/kstarinvmass", "Invariant mass of unlike-sign chK(892)", HistType::kTH1D, {invMassAxisReso}); + histos.add("QA/after/kstarinvmass_Mix", "Invariant mass of unlike-sign chK(892) from mixed event", HistType::kTH1D, {invMassAxisReso}); + + // MC + if (doprocessMC) { + + histos.add("QAMC/hEvent", "Number of Events", HistType::kTH1F, {{1, 0.5, 1.5}}); + // Bachelor pion + histos.add("QAMC/trkbpionDCAxy", "DCAxy distribution of bachelor pion candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QAMC/trkbpionDCAz", "DCAz distribution of bachelor pion candidates", HistType::kTH1D, {dcazAxis}); + histos.add("QAMC/trkbpionpT", "pT distribution of bachelor pion candidates", HistType::kTH1D, {ptAxis}); + histos.add("QAMC/trkbpionTPCPID", "TPC PID of bachelor pion candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkbpionTOFPID", "TOF PID of bachelor pion candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkbpionTPCTOFPID", "TPC-TOF PID map of bachelor pion candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + + // Secondary pion 1 + histos.add("QAMC/trkppionDCAxy", "DCAxy distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QAMC/trkppionDCAz", "DCAz distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcazAxis}); + histos.add("QAMC/trkppionpT", "pT distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {ptAxis}); + histos.add("QAMC/trkppionTPCPID", "TPC PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkppionTOFPID", "TOF PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkppionTPCTOFPID", "TPC-TOF PID map of secondary pion 1 (positive) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + + // Secondary pion 2 + histos.add("QAMC/trknpionTPCPID", "TPC PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trknpionTOFPID", "TOF PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trknpionTPCTOFPID", "TPC-TOF PID map of secondary pion 2 (negative) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QAMC/trknpionpT", "pT distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {ptAxis}); + histos.add("QAMC/trknpionDCAxy", "DCAxy distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QAMC/trknpionDCAz", "DCAz distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcazAxis}); + + // Secondary Resonance (K0s cand) + histos.add("QAMC/hDauDCASecondary", "DCA of daughters of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QAMC/hDauPosDCAtoPVSecondary", "Pos DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QAMC/hDauNegDCAtoPVSecondary", "Neg DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + + histos.add("QAMC/hpT_Secondary", "pT distribution of secondary resonance", HistType::kTH1D, {ptAxis}); + histos.add("QAMC/hy_Secondary", "Rapidity distribution of secondary resonance", HistType::kTH1D, {yAxis}); + histos.add("QAMC/hRadiusSecondary", "Radius distribution of secondary resonance", HistType::kTH1D, {radiusAxis}); + histos.add("QAMC/hCPASecondary", "Cosine pointing angle distribution of secondary resonance", HistType::kTH1D, {cpaAxis}); + histos.add("QAMC/hDCAtoPVSecondary", "DCA to PV distribution of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QAMC/hPropTauSecondary", "Proper Lifetime distribution of secondary resonance", HistType::kTH1D, {tauAxis}); + histos.add("QAMC/hPtAsymSecondary", "pT asymmetry distribution of secondary resonance", HistType::kTH1D, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); + histos.add("QAMC/hInvmassSecondary", "Invariant mass of unlike-sign secondary resonance", HistType::kTH1D, {invMassAxisK0s}); + + // K892 + histos.add("QAMC/KstarOA", "Opening angle of chK(892)", HistType::kTH1D, {AxisSpec{100, 0, 3.14, "Opening angle"}}); + histos.add("QAMC/KstarPairAsym", "Pair asymmetry of chK(892)", HistType::kTH1D, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); + histos.add("QAMC/KstarRapidity", "Rapidity distribution of chK(892)", HistType::kTH1D, {yAxis}); + + histos.add("QAMC/kstarinvmass", "Invariant mass of unlike-sign chK(892)", HistType::kTH1D, {invMassAxisReso}); + histos.add("QAMC/kstarinvmass_noKstar", "Invariant mass of unlike-sign no chK(892)", HistType::kTH1D, {invMassAxisReso}); + + histos.add("hInvmass_Kstar_MC", "Invariant mass of unlike chK(892)", HistType::kTHnSparseD, {axisType, centAxis, ptAxis, invMassAxisReso}); + + ccdb->setURL(cfgURL); + ccdbApi.init("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + } + + // Print output histograms statistics + LOG(info) << "Size of the histograms in chK(892) Analysis Task"; + histos.print(); + } + + template + float GetCentrality(CollisionType const& collision) + { + if (cfgCentEst == 1) { + return collision.multFT0C(); + } else if (cfgCentEst == 2) { + return collision.multFT0M(); + } else { + return -999; + } + } + + template + int GetDetId(DetNameType const& name) + { + LOGF(info, "GetDetID running"); + if (name.value == "FT0C") { + return 0; + } else if (name.value == "FT0A") { + return 1; + } else if (name.value == "FT0M") { + return 2; + } else if (name.value == "FV0A") { + return 3; + } else if (name.value == "TPCpos") { + return 4; + } else if (name.value == "TPCneg") { + return 5; + } else { + return false; + } + } + + // Track selection + template + bool trackCut(TrackType const& track) + { + // basic track cuts + if (std::abs(track.pt()) < cMinPtcut) + return false; + if (std::abs(track.eta()) > cMaxEtacut) + return false; + if (track.itsNCls() < cfgITScluster) + return false; + if (track.tpcNClsFound() < cfgTPCcluster) + return false; + if (track.tpcCrossedRowsOverFindableCls() < cfgRatioTPCRowsOverFindableCls) + return false; + if (track.itsChi2NCl() >= cfgITSChi2NCl) + return false; + if (track.tpcChi2NCl() >= cfgTPCChi2NCl) + return false; + if (cfgHasITS && !track.hasITS()) + return false; + if (cfgHasTPC && !track.hasTPC()) + return false; + if (cfgHasTOF && !track.hasTOF()) + return false; + if (cfgUseITSRefit && !track.passedITSRefit()) + return false; + if (cfgUseTPCRefit && !track.passedTPCRefit()) + return false; + if (cfgPVContributor && !track.isPVContributor()) + return false; + if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (cfgGlobalTrack && !track.isGlobalTrack()) + return false; + if (cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (std::abs(track.dcaXY()) > cMaxbDCArToPVcut) + return false; + if (std::abs(track.dcaZ()) > cMaxbDCAzToPVcut) + return false; + return true; + } + + // PID selection tools + template + bool selectionPIDPion(TrackType const& candidate) + { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + + if (cTPConly) { + + if (std::abs(candidate.tpcNSigmaPi()) < cMaxTPCnSigmaPion) { + tpcPIDPassed = true; + } else { + return false; + } + tofPIDPassed = true; + + } else { + + if (std::abs(candidate.tpcNSigmaPi()) < cMaxTPCnSigmaPion) { + tpcPIDPassed = true; + } else { + return false; + } + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaPi()) < cMaxTOFnSigmaPion) { + tofPIDPassed = true; + } + if ((nsigmaCutCombinedPion > 0) && (candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi() + candidate.tofNSigmaPi() * candidate.tofNSigmaPi() < nsigmaCutCombinedPion * nsigmaCutCombinedPion)) { + tofPIDPassed = true; + } + } else { + if (!cTOFVeto) { + return false; + } + tofPIDPassed = true; + } + } + + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + return false; + } + + template + bool selectionK0s(CollisionType const& collision, K0sType const& candidate) + { + auto DauDCA = candidate.dcaV0daughters(); + auto DauPosDCAtoPV = candidate.dcapostopv(); + auto DauNegDCAtoPV = candidate.dcanegtopv(); + auto pT = candidate.pt(); + auto Rapidity = candidate.yK0Short(); + auto Radius = candidate.v0radius(); + auto DCAtoPV = candidate.dcav0topv(); + auto CPA = candidate.v0cosPA(); + auto PropTauK0s = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassK0Short; + auto mK0s = candidate.mK0Short(); + + if (cfgReturnFlag) { + bool returnFlag = true; + + if (cSecondaryRequire) { + histos.fill(HIST("QA/K0sCutCheck"), 0); + if (DauDCA > cSecondaryDauDCAMax) { + histos.fill(HIST("QA/K0sCutCheck"), 1); + returnFlag = false; + } + if (DauPosDCAtoPV < cSecondaryDauPosDCAtoPVMin) { + histos.fill(HIST("QA/K0sCutCheck"), 2); + returnFlag = false; + } + if (DauNegDCAtoPV < cSecondaryDauNegDCAtoPVMin) { + histos.fill(HIST("QA/K0sCutCheck"), 3); + returnFlag = false; + } + if (pT < cSecondaryPtMin) { + histos.fill(HIST("QA/K0sCutCheck"), 4); + returnFlag = false; + } + if (Rapidity > cSecondaryRapidityMax) { + histos.fill(HIST("QA/K0sCutCheck"), 5); + returnFlag = false; + } + if (Radius < cSecondaryRadiusMin) { + histos.fill(HIST("QA/K0sCutCheck"), 6); + returnFlag = false; + } + if (DCAtoPV > cSecondaryDCAtoPVMax) { + histos.fill(HIST("QA/K0sCutCheck"), 7); + returnFlag = false; + } + if (CPA < cSecondaryCosPAMin) { + histos.fill(HIST("QA/K0sCutCheck"), 8); + returnFlag = false; + } + if (PropTauK0s > cSecondaryProperLifetimeMax) { + histos.fill(HIST("QA/K0sCutCheck"), 9); + returnFlag = false; + } + if (candidate.qtarm() < cSecondaryparamArmenterosCut * TMath::Abs(candidate.alpha())) { + histos.fill(HIST("QA/K0sCutCheck"), 11); + returnFlag = false; + } + if (fabs(mK0s - MassK0Short) > cSecondaryMassWindow) { + histos.fill(HIST("QA/K0sCutCheck"), 10); + returnFlag = false; + } + + return returnFlag; + + } else { + if (fabs(mK0s - MassK0Short) > cSecondaryMassWindow) { + histos.fill(HIST("QA/K0sCutCheck"), 10); + returnFlag = false; + } + + return returnFlag; + } + + } else { + if (cSecondaryRequire) { + + histos.fill(HIST("QA/K0sCutCheck"), 0); + if (DauDCA > cSecondaryDauDCAMax) { + histos.fill(HIST("QA/K0sCutCheck"), 1); + return false; + } + if (DauPosDCAtoPV < cSecondaryDauPosDCAtoPVMin) { + histos.fill(HIST("QA/K0sCutCheck"), 2); + return false; + } + if (DauNegDCAtoPV < cSecondaryDauNegDCAtoPVMin) { + histos.fill(HIST("QA/K0sCutCheck"), 3); + return false; + } + if (pT < cSecondaryPtMin) { + histos.fill(HIST("QA/K0sCutCheck"), 4); + return false; + } + if (Rapidity > cSecondaryRapidityMax) { + histos.fill(HIST("QA/K0sCutCheck"), 5); + return false; + } + if (Radius < cSecondaryRadiusMin) { + histos.fill(HIST("QA/K0sCutCheck"), 6); + return false; + } + if (DCAtoPV > cSecondaryDCAtoPVMax) { + histos.fill(HIST("QA/K0sCutCheck"), 7); + return false; + } + if (CPA < cSecondaryCosPAMin) { + histos.fill(HIST("QA/K0sCutCheck"), 8); + return false; + } + if (PropTauK0s > cSecondaryProperLifetimeMax) { + histos.fill(HIST("QA/K0sCutCheck"), 9); + return false; + } + if (candidate.qtarm() < cSecondaryparamArmenterosCut * TMath::Abs(candidate.alpha())) { + histos.fill(HIST("QA/K0sCutCheck"), 11); + return false; + } + if (fabs(mK0s - MassK0Short) > cSecondaryMassWindow) { + histos.fill(HIST("QA/K0sCutCheck"), 10); + return false; + } + return true; + + } else { + if (fabs(mK0s - MassK0Short) > cSecondaryMassWindow) { + histos.fill(HIST("QA/K0sCutCheck"), 10); + return false; + } + return true; + } + } + } // selectionK0s + + double GetPhiInRange(double phi) + { + double result = phi; + while (result < 0) { + result = result + 2. * TMath::Pi() / 2; + } + while (result > 2. * TMath::Pi() / 2) { + result = result - 2. * TMath::Pi() / 2; + } + return result; + } + + template + bool isTrueKstar(const TrackTemplate& bTrack, const V0Template& K0scand) + { + if (abs(bTrack.PDGCode()) != kPiPlus) // Are you pion? + return false; + if (abs(K0scand.PDGCode()) != kPDGK0s) // Are you K0s? + return false; + + auto motherbTrack = bTrack.template mothers_as(); + auto motherkV0 = K0scand.template mothers_as(); + + // Check bTrack first + if (abs(motherbTrack.pdgCode()) != kKstarPlus) // Are you charged Kstar's daughter? + return false; // Apply first since it's more restrictive + + if (abs(motherkV0.pdgCode()) != 310) // Is it K0s? + return false; + // Check if K0s's mother is K0 (311) + auto motherK0 = motherkV0.template mothers_as(); + if (abs(motherK0.pdgCode()) != 311) + return false; + + // Check if K0's mother is Kstar (323) + auto motherKstar = motherK0.template mothers_as(); + if (abs(motherKstar.pdgCode()) != 323) + return false; + + // Check if bTrack and K0 have the same mother (global index) + if (motherbTrack.globalIndex() != motherK0.globalIndex()) + return false; + + return true; + } + + int count = 0; + + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksTypeK0s& dTracks2) + { + histos.fill(HIST("QA/before/CentDist"), centrality); + + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResoSecondary, lDecayDaughter_bach, lResoKstar; + std::vector trackIndicies = {}; + std::vector k0sIndicies = {}; + + for (auto& bTrack : dTracks1) { + auto trkbpt = bTrack.pt(); + auto istrkbhasTOF = bTrack.hasTOF(); + auto trkbNSigmaPiTPC = bTrack.tpcNSigmaPi(); + auto trkbNSigmaPiTOF = (istrkbhasTOF) ? bTrack.tofNSigmaPi() : -999.; + + if constexpr (!IsMix) { + // Bachelor pion QA plots + histos.fill(HIST("QA/before/trkbpionTPCPID"), trkbpt, trkbNSigmaPiTPC); + if (istrkbhasTOF) { + histos.fill(HIST("QA/before/trkbpionTOFPID"), trkbpt, trkbNSigmaPiTOF); + histos.fill(HIST("QA/before/trkbpionTPCTOFPID"), trkbNSigmaPiTPC, trkbNSigmaPiTOF); + } + histos.fill(HIST("QA/before/trkbpionpT"), trkbpt); + histos.fill(HIST("QA/before/trkbpionDCAxy"), bTrack.dcaXY()); + histos.fill(HIST("QA/before/trkbpionDCAz"), bTrack.dcaZ()); + } + + if (!trackCut(bTrack)) + continue; + if (!selectionPIDPion(bTrack)) + continue; + + if constexpr (!IsMix) { + // Bachelor pion QA plots after applying cuts + histos.fill(HIST("QA/after/trkbpionTPCPID"), trkbpt, trkbNSigmaPiTPC); + if (istrkbhasTOF) { + histos.fill(HIST("QA/after/trkbpionTOFPID"), trkbpt, trkbNSigmaPiTOF); + histos.fill(HIST("QA/after/trkbpionTPCTOFPID"), trkbNSigmaPiTPC, trkbNSigmaPiTOF); + } + histos.fill(HIST("QA/after/trkbpionpT"), trkbpt); + histos.fill(HIST("QA/after/trkbpionDCAxy"), bTrack.dcaXY()); + histos.fill(HIST("QA/after/trkbpionDCAz"), bTrack.dcaZ()); + } + trackIndicies.push_back(bTrack.index()); + } + + for (auto& K0scand : dTracks2) { + auto posDauTrack = K0scand.template posTrack_as(); + auto negDauTrack = K0scand.template negTrack_as(); + + /// Daughters + // Positve pion + auto trkppt = posDauTrack.pt(); + auto istrkphasTOF = posDauTrack.hasTOF(); + auto trkpNSigmaPiTPC = posDauTrack.tpcNSigmaPi(); + auto trkpNSigmaPiTOF = (istrkphasTOF) ? posDauTrack.tofNSigmaPi() : -999.; + // Negative pion + auto trknpt = negDauTrack.pt(); + auto istrknhasTOF = negDauTrack.hasTOF(); + auto trknNSigmaPiTPC = negDauTrack.tpcNSigmaPi(); + auto trknNSigmaPiTOF = (istrknhasTOF) ? negDauTrack.tofNSigmaPi() : -999.; + + /// K0s + auto trkkDauDCA = K0scand.dcaV0daughters(); + auto trkkDauDCAPostoPV = K0scand.dcapostopv(); + auto trkkDauDCANegtoPV = K0scand.dcanegtopv(); + auto trkkpt = K0scand.pt(); + auto trkky = K0scand.yK0Short(); + auto trkkRadius = K0scand.v0radius(); + auto trkkDCAtoPV = K0scand.dcav0topv(); + auto trkkCPA = K0scand.v0cosPA(); + auto trkkPropTau = K0scand.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassK0Short; + auto trkkMass = K0scand.mK0Short(); + + if constexpr (!IsMix) { + // Seconddary QA plots + histos.fill(HIST("QA/before/trkppionTPCPID"), trkppt, trkpNSigmaPiTPC); + if (istrkphasTOF) { + histos.fill(HIST("QA/before/trkppionTOFPID"), trkppt, trkpNSigmaPiTOF); + histos.fill(HIST("QA/before/trkppionTPCTOFPID"), trkpNSigmaPiTPC, trkpNSigmaPiTOF); + } + histos.fill(HIST("QA/before/trkppionpT"), trkppt); + histos.fill(HIST("QA/before/trkppionDCAxy"), posDauTrack.dcaXY()); + histos.fill(HIST("QA/before/trkppionDCAz"), posDauTrack.dcaZ()); + + histos.fill(HIST("QA/before/trknpionTPCPID"), trknpt, trknNSigmaPiTPC); + if (istrknhasTOF) { + histos.fill(HIST("QA/before/trknpionTOFPID"), trknpt, trknNSigmaPiTOF); + histos.fill(HIST("QA/before/trknpionTPCTOFPID"), trknNSigmaPiTPC, trknNSigmaPiTOF); + } + histos.fill(HIST("QA/before/trknpionpT"), trknpt); + histos.fill(HIST("QA/before/trknpionDCAxy"), negDauTrack.dcaXY()); + histos.fill(HIST("QA/before/trknpionDCAz"), negDauTrack.dcaZ()); + + histos.fill(HIST("QA/before/hDauDCASecondary"), trkkDauDCA); + histos.fill(HIST("QA/before/hDauPosDCAtoPVSecondary"), trkkDauDCAPostoPV); + histos.fill(HIST("QA/before/hDauNegDCAtoPVSecondary"), trkkDauDCANegtoPV); + + histos.fill(HIST("QA/before/hpT_Secondary"), trkkpt); + histos.fill(HIST("QA/before/hy_Secondary"), trkky); + histos.fill(HIST("QA/before/hRadiusSecondary"), trkkRadius); + histos.fill(HIST("QA/before/hDCAtoPVSecondary"), trkkDCAtoPV); + histos.fill(HIST("QA/before/hCPASecondary"), trkkCPA); + histos.fill(HIST("QA/before/hPropTauSecondary"), trkkPropTau); + histos.fill(HIST("QA/before/hInvmassSecondary"), trkkMass); + } + + // if (!trackCut(posDauTrack) || !trackCut(negDauTrack)) // Too tight cut for K0s daugthers + // continue; + if (!cfgByPassDauPIDSelection && !selectionPIDPion(posDauTrack)) // Perhaps it's already applied in trackCut (need to check QA plots) + continue; + if (!cfgByPassDauPIDSelection && !selectionPIDPion(negDauTrack)) + continue; + if (!selectionK0s(collision, K0scand)) + continue; + + if constexpr (!IsMix) { + // Seconddary QA plots after applying cuts + + histos.fill(HIST("QA/after/trkppionTPCPID"), trkppt, trkpNSigmaPiTPC); + if (istrkphasTOF) { + histos.fill(HIST("QA/after/trkppionTOFPID"), trkppt, trkpNSigmaPiTOF); + histos.fill(HIST("QA/after/trkppionTPCTOFPID"), trkpNSigmaPiTPC, trkpNSigmaPiTOF); + } + histos.fill(HIST("QA/after/trkppionpT"), trkppt); + histos.fill(HIST("QA/after/trkppionDCAxy"), posDauTrack.dcaXY()); + histos.fill(HIST("QA/after/trkppionDCAz"), posDauTrack.dcaZ()); + + histos.fill(HIST("QA/after/trknpionTPCPID"), trknpt, trknNSigmaPiTPC); + if (istrknhasTOF) { + histos.fill(HIST("QA/after/trknpionTOFPID"), trknpt, trknNSigmaPiTOF); + histos.fill(HIST("QA/after/trknpionTPCTOFPID"), trknNSigmaPiTPC, trknNSigmaPiTOF); + } + histos.fill(HIST("QA/after/trknpionpT"), trknpt); + histos.fill(HIST("QA/after/trknpionDCAxy"), negDauTrack.dcaXY()); + histos.fill(HIST("QA/after/trknpionDCAz"), negDauTrack.dcaZ()); + + histos.fill(HIST("QA/after/hDauDCASecondary"), trkkDauDCA); + histos.fill(HIST("QA/after/hDauPosDCAtoPVSecondary"), trkkDauDCAPostoPV); + histos.fill(HIST("QA/after/hDauNegDCAtoPVSecondary"), trkkDauDCANegtoPV); + + histos.fill(HIST("QA/after/hpT_Secondary"), trkkpt); + histos.fill(HIST("QA/after/hy_Secondary"), trkky); + histos.fill(HIST("QA/after/hRadiusSecondary"), trkkRadius); + histos.fill(HIST("QA/after/hDCAtoPVSecondary"), trkkDCAtoPV); + histos.fill(HIST("QA/after/hCPASecondary"), trkkCPA); + histos.fill(HIST("QA/after/hPropTauSecondary"), trkkPropTau); + histos.fill(HIST("QA/after/hInvmassSecondary"), trkkMass); + } + k0sIndicies.push_back(K0scand.index()); + } + + for (auto& trackIndex : trackIndicies) { + for (auto& k0sIndex : k0sIndicies) { + auto bTrack = dTracks1.rawIteratorAt(trackIndex); + auto K0scand = dTracks2.rawIteratorAt(k0sIndex); + + lDecayDaughter_bach.SetXYZM(bTrack.px(), bTrack.py(), bTrack.pz(), MassPionCharged); + lResoSecondary.SetXYZM(K0scand.px(), K0scand.py(), K0scand.pz(), MassK0Short); + lResoKstar = lResoSecondary + lDecayDaughter_bach; + + // QA plots + if constexpr (!IsMix) { + histos.fill(HIST("QA/before/KstarRapidity"), lResoKstar.Rapidity()); + histos.fill(HIST("QA/before/kstarinvmass"), lResoKstar.M()); + } + + if (lResoKstar.Rapidity() > cKstarMaxRap || lResoKstar.Rapidity() < cKstarMinRap) + continue; + + if constexpr (!IsMix) { + unsigned int typeKstar = bTrack.sign() > 0 ? binType::kKstarP : binType::kKstarN; + + histos.fill(HIST("QA/after/KstarRapidity"), lResoKstar.Rapidity()); + histos.fill(HIST("QA/after/kstarinvmass"), lResoKstar.M()); + histos.fill(HIST("hInvmass_Kstar"), typeKstar, centrality, lResoKstar.Pt(), lResoKstar.M()); + + } // IsMix + } // K0scand + } // bTrack + + count++; + + } // fillHistograms + + // process data + void processData(EventCandidates::iterator const& collision, + TrackCandidates const& tracks, + V0Candidates const& v0s, + aod::BCsWithTimestamps const&) + { + if (!colCuts.isSelected(collision)) // Default event selection + return; + colCuts.fillQA(collision); + centrality = GetCentrality(collision); + + fillHistograms(collision, tracks, v0s); // second order + } + PROCESS_SWITCH(chk892_pp, processData, "Process Event for data without Partitioning", true); + + // process MC reconstructed level + void processMC(EventCandidates::iterator const& collision, + MCTrackCandidates const& tracks, + MCV0Candidates const& v0s) + { + + histos.fill(HIST("QAMC/hEvent"), 1.0); + + fillHistograms(collision, tracks, v0s); + } + PROCESS_SWITCH(chk892_pp, processMC, "Process Event for MC", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"lf-chk892pp"})}; +} diff --git a/PWGLF/Tasks/Resonances/chk892pp.cxx b/PWGLF/Tasks/Resonances/chk892pp.cxx new file mode 100644 index 00000000000..269e8d0845d --- /dev/null +++ b/PWGLF/Tasks/Resonances/chk892pp.cxx @@ -0,0 +1,930 @@ +// 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 chk892pp.cxx +/// \brief Reconstruction of track-track decay resonance candidates +/// +/// +/// \author Su-Jeong Ji + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // FIXME +#include // FIXME + +#include +#include +#include +#include +#include +#include + +#include "TRandom3.h" +#include "TF1.h" +#include "TVector2.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/StaticFor.h" +#include "DCAFitter/DCAFitterN.h" + +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/RecoDecay.h" + +#include "CommonConstants/PhysicsConstants.h" + +#include "ReconstructionDataFormats/Track.h" + +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" + +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" + +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/collisionCuts.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; + +struct chk892pp { + enum binType : unsigned int { + kKstarP = 0, + kKstarN, + kKstarP_Mix, + kKstarN_Mix, + kKstarP_GenINEL10, + kKstarN_GenINEL10, + kKstarP_GenINELgt10, + kKstarN_GenINELgt10, + kKstarP_GenTrig10, + kKstarN_GenTrig10, + kKstarP_GenEvtSel, + kKstarN_GenEvtSel, + kKstarP_Rec, + kKstarN_Rec, + kTYEnd + }; + + SliceCache cache; + Preslice perCollision = aod::track::collisionId; + + using EventCandidates = soa::Join; + // using EventCandidates = soa::Join; + using TrackCandidates = soa::Join; + using V0Candidates = aod::V0Datas; + + using MCEventCandidates = soa::Join; + using MCTrackCandidates = soa::Join; + using MCV0Candidates = soa::Join; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Service ccdb; + Service pdg; + o2::ccdb::CcdbApi ccdbApi; + + Configurable cfgURL{"cfgURL", "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; + Configurable nolaterthan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "Latest acceptable timestamp of creation for the object"}; + + // Configurables + ConfigurableAxis cfgBinsPt{"cfgBinsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12.0, 12.1, 12.2, 12.3, 12.4, 12.5, 12.6, 12.7, 12.8, 12.9, 13.0, 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7, 13.8, 13.9, 14.0, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15.0}, "Binning of the pT axis"}; + ConfigurableAxis cfgBinsPtQA{"cfgBinsPtQA", {VARIABLE_WIDTH, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2, 6.4, 6.6, 6.8, 7.0, 7.2, 7.4, 7.6, 7.8, 8.0, 8.2, 8.4, 8.6, 8.8, 9.0, 9.2, 9.4, 9.6, 9.8, 10.0}, "Binning of the pT axis"}; + ConfigurableAxis cfgBinsCent{"cfgBinsCent", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0}, "Binning of the centrality axis"}; + ConfigurableAxis cfgBinsVtxZ{"cfgBinsVtxZ", {VARIABLE_WIDTH, -10.0, -9.0, -8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0}, "Binning of the z-vertex axis"}; + Configurable cNbinsDiv{"cNbinsDiv", 1, "Integer to divide the number of bins"}; + + /// Event cuts + o2::analysis::CollisonCuts colCuts; + Configurable ConfEvtZvtx{"ConfEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; + Configurable ConfEvtOccupancyInTimeRangeMax{"ConfEvtOccupancyInTimeRangeMax", -1, "Evt sel: maximum track occupancy"}; + Configurable ConfEvtOccupancyInTimeRangeMin{"ConfEvtOccupancyInTimeRangeMin", -1, "Evt sel: minimum track occupancy"}; + Configurable ConfEvtTriggerCheck{"ConfEvtTriggerCheck", false, "Evt sel: check for trigger"}; + Configurable ConfEvtOfflineCheck{"ConfEvtOfflineCheck", true, "Evt sel: check for offline selection"}; + Configurable ConfEvtTriggerTVXSel{"ConfEvtTriggerTVXSel", false, "Evt sel: triggerTVX selection (MB)"}; + Configurable ConfEvtTFBorderCut{"ConfEvtTFBorderCut", false, "Evt sel: apply TF border cut"}; + Configurable ConfEvtUseITSTPCvertex{"ConfEvtUseITSTPCvertex", false, "Evt sel: use at lease on ITS-TPC track for vertexing"}; + Configurable ConfEvtZvertexTimedifference{"ConfEvtZvertexTimedifference", true, "Evt sel: apply Z-vertex time difference"}; + Configurable ConfEvtPileupRejection{"ConfEvtPileupRejection", true, "Evt sel: apply pileup rejection"}; + Configurable ConfEvtNoITSROBorderCut{"ConfEvtNoITSROBorderCut", false, "Evt sel: apply NoITSRO border cut"}; + Configurable ConfincludeCentralityMC{"ConfincludeCentralityMC", false, "Include centrality in MC"}; + Configurable ConfEvtCollInTimeRangeStandard{"ConfEvtCollInTimeRangeStandard", true, "Evt sel: apply NoCollInTimeRangeStandard"}; + + /// Track selections + Configurable cMinPtcut{"cMinPtcut", 0.15, "Track minium pt cut"}; + Configurable cMaxEtacut{"cMaxEtacut", 0.8, "Track maximum eta cut"}; + + /* + // Cuts from polarization analysis + Configurable cfgOccupancySel{"cfgOccupancySel", false, "Occupancy selection"}; + Configurable cfgMaxOccupancy{"cfgMaxOccupancy", 999999, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable cfgMinOccupancy{"cfgMinOccupancy", -100, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable cfgNCollinTR{"cfgNCollinTR", false, "Additional selection for the number of coll in time range"}; +*/ + Configurable cfgCentEst{"cfgCentEst", 1, "Centrality estimator, 1: FT0C, 2: FT0M"}; + + // DCAr to PV + Configurable cMaxbDCArToPVcut{"cMaxbDCArToPVcut", 0.1, "Track DCAr cut to PV Maximum"}; + // DCAz to PV + Configurable cMaxbDCAzToPVcut{"cMaxbDCAzToPVcut", 0.1, "Track DCAz cut to PV Maximum"}; + + /// PID Selections, pion + Configurable cTPConly{"cTPConly", true, "Use only TPC for PID"}; // bool + Configurable cMaxTPCnSigmaPion{"cMaxTPCnSigmaPion", 3.0, "TPC nSigma cut for Pion"}; // TPC + Configurable cMaxTOFnSigmaPion{"cMaxTOFnSigmaPion", 3.0, "TOF nSigma cut for Pion"}; // TOF + Configurable nsigmaCutCombinedPion{"nsigmaCutCombinedPion", -999, "Combined nSigma cut for Pion"}; // Combined + Configurable cTOFVeto{"cTOFVeto", true, "TOF Veto, if false, TOF is nessessary for PID selection"}; // TOF Veto + + // Track selections + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) + Configurable cfgGlobalTrack{"cfgGlobalTrack", false, "Global track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgPVContributor{"cfgPVContributor", false, "PV contributor track selection"}; // PV Contriuibutor + + Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 0, "Number of TPC cluster"}; + Configurable cfgRatioTPCRowsOverFindableCls{"cfgRatioTPCRowsOverFindableCls", 0.0f, "TPC Crossed Rows to Findable Clusters"}; + Configurable cfgITSChi2NCl{"cfgITSChi2NCl", 999.0, "ITS Chi2/NCl"}; + Configurable cfgTPCChi2NCl{"cfgTPCChi2NCl", 999.0, "TPC Chi2/NCl"}; + Configurable cfgUseTPCRefit{"cfgUseTPCRefit", false, "Require TPC Refit"}; + Configurable cfgUseITSRefit{"cfgUseITSRefit", false, "Require ITS Refit"}; + Configurable cfgHasITS{"cfgHasITS", false, "Require ITS"}; + Configurable cfgHasTPC{"cfgHasTPC", false, "Require TPC"}; + Configurable cfgHasTOF{"cfgHasTOF", false, "Require TOF"}; + + // Secondary Selection + Configurable cfgReturnFlag{"boolReturnFlag", false, "Return Flag for debugging"}; + Configurable cSecondaryRequire{"bool", true, "Secondary cuts on/off"}; + Configurable cSecondaryArmenterosCut{"boolArmenterosCut", true, "cut on Armenteros-Podolanski graph"}; + + Configurable cfgByPassDauPIDSelection{"cfgByPassDauPIDSelection", true, "Bypass Daughters PID selection"}; + Configurable cSecondaryDauDCAMax{"cSecondaryDauDCAMax", 1., "Maximum DCA Secondary daughters to PV"}; + Configurable cSecondaryDauPosDCAtoPVMin{"cSecondaryDauPosDCAtoPVMin", 0.0, "Minimum DCA Secondary positive daughters to PV"}; + Configurable cSecondaryDauNegDCAtoPVMin{"cSecondaryDauNegDCAtoPVMin", 0.0, "Minimum DCA Secondary negative daughters to PV"}; + + Configurable cSecondaryPtMin{"cSecondaryPtMin", 0.f, "Minimum transverse momentum of Secondary"}; + Configurable cSecondaryRapidityMax{"cSecondaryRapidityMax", 0.5, "Maximum rapidity of Secondary"}; + Configurable cSecondaryRadiusMin{"cSecondaryRadiusMin", 1.2, "Minimum transverse radius of Secondary"}; + Configurable cSecondaryCosPAMin{"cSecondaryCosPAMin", 0.995, "Mininum cosine pointing angle of Secondary"}; + Configurable cSecondaryDCAtoPVMax{"cSecondaryDCAtoPVMax", 0.3, "Maximum DCA Secondary to PV"}; + Configurable cSecondaryProperLifetimeMax{"cSecondaryProperLifetimeMax", 20, "Maximum Secondary Lifetime"}; + Configurable cSecondaryparamArmenterosCut{"paramArmenterosCut", 0.2, "parameter for Armenteros Cut"}; + Configurable cSecondaryMassWindow{"cSecondaryMassWindow", 0.075, "Secondary inv mass selciton window"}; + + // K* selection + Configurable cKstarMaxRap{"cKstarMaxRap", 0.5, "Kstar maximum rapidity"}; + Configurable cKstarMinRap{"cKstarMinRap", -0.5, "Kstar minimum rapidity"}; + + float centrality; + + // PDG code + int kPDGK0s = 310; + int kPDGK0 = 311; + int kKstarPlus = 323; + int kPiPlus = 211; + + void init(o2::framework::InitContext&) + { + centrality = -999; + + colCuts.setCuts(ConfEvtZvtx, ConfEvtTriggerCheck, ConfEvtOfflineCheck, /*checkRun3*/ true, /*triggerTVXsel*/ false, ConfEvtOccupancyInTimeRangeMax, ConfEvtOccupancyInTimeRangeMin); + colCuts.init(&histos); + colCuts.setTriggerTVX(ConfEvtTriggerTVXSel); + colCuts.setApplyTFBorderCut(ConfEvtTFBorderCut); + colCuts.setApplyITSTPCvertex(ConfEvtUseITSTPCvertex); + colCuts.setApplyZvertexTimedifference(ConfEvtZvertexTimedifference); + colCuts.setApplyPileupRejection(ConfEvtPileupRejection); + colCuts.setApplyNoITSROBorderCut(ConfEvtNoITSROBorderCut); + colCuts.setApplyCollInTimeRangeStandard(ConfEvtCollInTimeRangeStandard); + + AxisSpec centAxis = {cfgBinsCent, "T0M (%)"}; + AxisSpec vtxzAxis = {cfgBinsVtxZ, "Z Vertex (cm)"}; + AxisSpec epAxis = {100, -1.0 * constants::math::PI, constants::math::PI}; + AxisSpec epresAxis = {100, -1.02, 1.02}; + AxisSpec ptAxis = {cfgBinsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptAxisQA = {cfgBinsPtQA, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec radiusAxis = {50, 0, 5, "Radius (cm)"}; + AxisSpec cpaAxis = {50, 0.95, 1.0, "CPA"}; + AxisSpec tauAxis = {250, 0, 25, "Lifetime (cm)"}; + AxisSpec dcaAxis = {200, 0, 2, "DCA (cm)"}; + AxisSpec dcaxyAxis = {200, 0, 2, "DCA_{#it{xy}} (cm)"}; + AxisSpec dcazAxis = {200, 0, 2, "DCA_{#it{z}} (cm)"}; + AxisSpec yAxis = {100, -1, 1, "Rapidity"}; + AxisSpec invMassAxisK0s = {400 / cNbinsDiv, 0.3, 0.7, "Invariant Mass (GeV/#it{c}^2)"}; // K0s ~497.611 + AxisSpec invMassAxisReso = {900 / cNbinsDiv, 0.5f, 1.4f, "Invariant Mass (GeV/#it{c}^2)"}; // chK(892) ~892 + AxisSpec invMassAxisScan = {150, 0, 1.5, "Invariant Mass (GeV/#it{c}^2)"}; // For selection + AxisSpec pidQAAxis = {130, -6.5, 6.5}; + AxisSpec dataTypeAxis = {9, 0, 9, "Histogram types"}; + AxisSpec mcTypeAxis = {4, 0, 4, "Histogram types"}; + + // THnSparse + AxisSpec axisType = {binType::kTYEnd, 0, binType::kTYEnd, "Type of bin with charge and mix"}; + AxisSpec mcLabelAxis = {5, -0.5, 4.5, "MC Label"}; + + histos.add("QA/K0sCutCheck", "Check K0s cut", HistType::kTH1D, {AxisSpec{12, -0.5, 11.5, "Check"}}); + + histos.add("QA/before/CentDist", "Centrality distribution", {HistType::kTH1D, {centAxis}}); + histos.add("QA/before/VtxZ", "Centrality distribution", {HistType::kTH1D, {vtxzAxis}}); + histos.add("QA/before/hEvent", "Number of Events", HistType::kTH1F, {{1, 0.5, 1.5}}); + + // Bachelor pion + histos.add("QA/before/trkbpionDCAxy", "DCAxy distribution of bachelor pion candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/before/trkbpionDCAz", "DCAz distribution of bachelor pion candidates", HistType::kTH1D, {dcazAxis}); + histos.add("QA/before/trkbpionpT", "pT distribution of bachelor pion candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/before/trkbpionTPCPID", "TPC PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkbpionTOFPID", "TOF PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkbpionTPCTOFPID", "TPC-TOF PID map of bachelor pion candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + + histos.add("QA/after/trkbpionDCAxy", "DCAxy distribution of bachelor pion candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/after/trkbpionDCAz", "DCAz distribution of bachelor pion candidates", HistType::kTH1D, {dcazAxis}); + histos.add("QA/after/trkbpionpT", "pT distribution of bachelor pion candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/after/trkbpionTPCPID", "TPC PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkbpionTOFPID", "TOF PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkbpionTPCTOFPID", "TPC-TOF PID map of bachelor pion candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + + // Secondary pion 1 + histos.add("QA/before/trkppionTPCPID", "TPC PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkppionTOFPID", "TOF PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trkppionTPCTOFPID", "TPC-TOF PID map of secondary pion 1 (positive) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/before/trkppionpT", "pT distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/before/trkppionDCAxy", "DCAxy distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/before/trkppionDCAz", "DCAz distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcazAxis}); + + histos.add("QA/after/trkppionTPCPID", "TPC PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkppionTOFPID", "TOF PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trkppionTPCTOFPID", "TPC-TOF PID map of secondary pion 1 (positive) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/after/trkppionpT", "pT distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/after/trkppionDCAxy", "DCAxy distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/after/trkppionDCAz", "DCAz distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcazAxis}); + + // Secondary pion 2 + histos.add("QA/before/trknpionTPCPID", "TPC PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trknpionTOFPID", "TOF PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/before/trknpionTPCTOFPID", "TPC-TOF PID map of secondary pion 2 (negative) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/before/trknpionpT", "pT distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/before/trknpionDCAxy", "DCAxy distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/before/trknpionDCAz", "DCAz distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcazAxis}); + + histos.add("QA/after/trknpionTPCPID", "TPC PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trknpionTOFPID", "TOF PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + histos.add("QA/after/trknpionTPCTOFPID", "TPC-TOF PID map of secondary pion 2 (negative) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QA/after/trknpionpT", "pT distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/after/trknpionDCAxy", "DCAxy distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QA/after/trknpionDCAz", "DCAz distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcazAxis}); + + // K0s + histos.add("QA/before/hDauDCASecondary", "DCA of daughters of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/before/hDauPosDCAtoPVSecondary", "Pos DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/before/hDauNegDCAtoPVSecondary", "Neg DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/before/hpT_Secondary", "pT distribution of secondary resonance", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/before/hy_Secondary", "Rapidity distribution of secondary resonance", HistType::kTH1D, {yAxis}); + histos.add("QA/before/hRadiusSecondary", "Radius distribution of secondary resonance", HistType::kTH1D, {radiusAxis}); + histos.add("QA/before/hCPASecondary", "Cosine pointing angle distribution of secondary resonance", HistType::kTH1D, {cpaAxis}); + histos.add("QA/before/hDCAtoPVSecondary", "DCA to PV distribution of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/before/hPropTauSecondary", "Proper Lifetime distribution of secondary resonance", HistType::kTH1D, {tauAxis}); + histos.add("QA/before/hPtAsymSecondary", "pT asymmetry distribution of secondary resonance", HistType::kTH1D, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); + histos.add("QA/before/hInvmassSecondary", "Invariant mass of unlike-sign secondary resonance", HistType::kTH1D, {invMassAxisK0s}); + + histos.add("QA/after/hDauDCASecondary", "DCA of daughters of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/after/hDauPosDCAtoPVSecondary", "Pos DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/after/hDauNegDCAtoPVSecondary", "Neg DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/after/hpT_Secondary", "pT distribution of secondary resonance", HistType::kTH1D, {ptAxisQA}); + histos.add("QA/after/hy_Secondary", "Rapidity distribution of secondary resonance", HistType::kTH1D, {yAxis}); + histos.add("QA/after/hRadiusSecondary", "Radius distribution of secondary resonance", HistType::kTH1D, {radiusAxis}); + histos.add("QA/after/hCPASecondary", "Cosine pointing angle distribution of secondary resonance", HistType::kTH1D, {cpaAxis}); + histos.add("QA/after/hDCAtoPVSecondary", "DCA to PV distribution of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QA/after/hPropTauSecondary", "Proper Lifetime distribution of secondary resonance", HistType::kTH1D, {tauAxis}); + histos.add("QA/after/hPtAsymSecondary", "pT asymmetry distribution of secondary resonance", HistType::kTH1D, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); + histos.add("QA/after/hInvmassSecondary", "Invariant mass of unlike-sign secondary resonance", HistType::kTH1D, {invMassAxisK0s}); + + // Kstar + // Invariant mass nSparse + histos.add("QA/before/KstarRapidity", "Rapidity distribution of chK(892)", HistType::kTH1D, {yAxis}); + histos.add("hInvmass_Kstar", "Invariant mass of unlike-sign chK(892)", HistType::kTHnSparseD, {axisType, centAxis, ptAxis, invMassAxisReso}); + histos.add("hInvmass_Kstar_Mix", "Invariant mass of unlike-sign chK(892) from mixed event", HistType::kTHnSparseD, {axisType, centAxis, ptAxis, invMassAxisReso}); + + // Mass QA (quick check) + histos.add("QA/before/kstarinvmass", "Invariant mass of unlike-sign chK(892)", HistType::kTH1D, {invMassAxisReso}); + histos.add("QA/before/kstarinvmass_Mix", "Invariant mass of unlike-sign chK(892) from mixed event", HistType::kTH1D, {invMassAxisReso}); + + histos.add("QA/after/KstarRapidity", "Rapidity distribution of chK(892)", HistType::kTH1D, {yAxis}); + histos.add("QA/after/kstarinvmass", "Invariant mass of unlike-sign chK(892)", HistType::kTH1D, {invMassAxisReso}); + histos.add("QA/after/kstarinvmass_Mix", "Invariant mass of unlike-sign chK(892) from mixed event", HistType::kTH1D, {invMassAxisReso}); + + // MC + if (doprocessMC) { + + histos.add("QAMC/hEvent", "Number of Events", HistType::kTH1F, {{1, 0.5, 1.5}}); + // Bachelor pion + histos.add("QAMC/trkbpionDCAxy", "DCAxy distribution of bachelor pion candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QAMC/trkbpionDCAz", "DCAz distribution of bachelor pion candidates", HistType::kTH1D, {dcazAxis}); + histos.add("QAMC/trkbpionpT", "pT distribution of bachelor pion candidates", HistType::kTH1D, {ptAxis}); + histos.add("QAMC/trkbpionTPCPID", "TPC PID of bachelor pion candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkbpionTOFPID", "TOF PID of bachelor pion candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkbpionTPCTOFPID", "TPC-TOF PID map of bachelor pion candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + + // Secondary pion 1 + histos.add("QAMC/trkppionDCAxy", "DCAxy distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QAMC/trkppionDCAz", "DCAz distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {dcazAxis}); + histos.add("QAMC/trkppionpT", "pT distribution of secondary pion 1 (positive) candidates", HistType::kTH1D, {ptAxis}); + histos.add("QAMC/trkppionTPCPID", "TPC PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkppionTOFPID", "TOF PID of secondary pion 1 (positive) candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkppionTPCTOFPID", "TPC-TOF PID map of secondary pion 1 (positive) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + + // Secondary pion 2 + histos.add("QAMC/trknpionTPCPID", "TPC PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trknpionTOFPID", "TOF PID of secondary pion 2 (negative) candidates", HistType::kTH2D, {ptAxis, pidQAAxis}); + histos.add("QAMC/trknpionTPCTOFPID", "TPC-TOF PID map of secondary pion 2 (negative) candidates", HistType::kTH2D, {pidQAAxis, pidQAAxis}); + histos.add("QAMC/trknpionpT", "pT distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {ptAxis}); + histos.add("QAMC/trknpionDCAxy", "DCAxy distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcaxyAxis}); + histos.add("QAMC/trknpionDCAz", "DCAz distribution of secondary pion 2 (negative) candidates", HistType::kTH1D, {dcazAxis}); + + // Secondary Resonance (K0s cand) + histos.add("QAMC/hDauDCASecondary", "DCA of daughters of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QAMC/hDauPosDCAtoPVSecondary", "Pos DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QAMC/hDauNegDCAtoPVSecondary", "Neg DCA to PV of daughters secondary resonance", HistType::kTH1D, {dcaAxis}); + + histos.add("QAMC/hpT_Secondary", "pT distribution of secondary resonance", HistType::kTH1D, {ptAxis}); + histos.add("QAMC/hy_Secondary", "Rapidity distribution of secondary resonance", HistType::kTH1D, {yAxis}); + histos.add("QAMC/hRadiusSecondary", "Radius distribution of secondary resonance", HistType::kTH1D, {radiusAxis}); + histos.add("QAMC/hCPASecondary", "Cosine pointing angle distribution of secondary resonance", HistType::kTH1D, {cpaAxis}); + histos.add("QAMC/hDCAtoPVSecondary", "DCA to PV distribution of secondary resonance", HistType::kTH1D, {dcaAxis}); + histos.add("QAMC/hPropTauSecondary", "Proper Lifetime distribution of secondary resonance", HistType::kTH1D, {tauAxis}); + histos.add("QAMC/hPtAsymSecondary", "pT asymmetry distribution of secondary resonance", HistType::kTH1D, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); + histos.add("QAMC/hInvmassSecondary", "Invariant mass of unlike-sign secondary resonance", HistType::kTH1D, {invMassAxisK0s}); + + // K892 + histos.add("QAMC/KstarOA", "Opening angle of chK(892)", HistType::kTH1D, {AxisSpec{100, 0, 3.14, "Opening angle"}}); + histos.add("QAMC/KstarPairAsym", "Pair asymmetry of chK(892)", HistType::kTH1D, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); + histos.add("QAMC/KstarRapidity", "Rapidity distribution of chK(892)", HistType::kTH1D, {yAxis}); + + histos.add("QAMC/kstarinvmass", "Invariant mass of unlike-sign chK(892)", HistType::kTH1D, {invMassAxisReso}); + histos.add("QAMC/kstarinvmass_noKstar", "Invariant mass of unlike-sign no chK(892)", HistType::kTH1D, {invMassAxisReso}); + + histos.add("hInvmass_Kstar_MC", "Invariant mass of unlike chK(892)", HistType::kTHnSparseD, {axisType, centAxis, ptAxis, invMassAxisReso}); + + ccdb->setURL(cfgURL); + ccdbApi.init("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + } + + // Print output histograms statistics + LOG(info) << "Size of the histograms in chK(892) Analysis Task"; + histos.print(); + } + + template + float GetCentrality(CollisionType const& collision) + { + if (cfgCentEst == 1) { + return collision.multFT0C(); + } else if (cfgCentEst == 2) { + return collision.multFT0M(); + } else { + return -999; + } + } + + template + int GetDetId(DetNameType const& name) + { + LOGF(info, "GetDetID running"); + if (name.value == "FT0C") { + return 0; + } else if (name.value == "FT0A") { + return 1; + } else if (name.value == "FT0M") { + return 2; + } else if (name.value == "FV0A") { + return 3; + } else if (name.value == "TPCpos") { + return 4; + } else if (name.value == "TPCneg") { + return 5; + } else { + return false; + } + } + + // Track selection + template + bool trackCut(TrackType const& track) + { + // basic track cuts + if (std::abs(track.pt()) < cMinPtcut) + return false; + if (std::abs(track.eta()) > cMaxEtacut) + return false; + if (track.itsNCls() < cfgITScluster) + return false; + if (track.tpcNClsFound() < cfgTPCcluster) + return false; + if (track.tpcCrossedRowsOverFindableCls() < cfgRatioTPCRowsOverFindableCls) + return false; + if (track.itsChi2NCl() >= cfgITSChi2NCl) + return false; + if (track.tpcChi2NCl() >= cfgTPCChi2NCl) + return false; + if (cfgHasITS && !track.hasITS()) + return false; + if (cfgHasTPC && !track.hasTPC()) + return false; + if (cfgHasTOF && !track.hasTOF()) + return false; + if (cfgUseITSRefit && !track.passedITSRefit()) + return false; + if (cfgUseTPCRefit && !track.passedTPCRefit()) + return false; + if (cfgPVContributor && !track.isPVContributor()) + return false; + if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (cfgGlobalTrack && !track.isGlobalTrack()) + return false; + if (cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (std::abs(track.dcaXY()) > cMaxbDCArToPVcut) + return false; + if (std::abs(track.dcaZ()) > cMaxbDCAzToPVcut) + return false; + return true; + } + + // PID selection tools + template + bool selectionPIDPion(TrackType const& candidate) + { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + + if (cTPConly) { + + if (std::abs(candidate.tpcNSigmaPi()) < cMaxTPCnSigmaPion) { + tpcPIDPassed = true; + } else { + return false; + } + tofPIDPassed = true; + + } else { + + if (std::abs(candidate.tpcNSigmaPi()) < cMaxTPCnSigmaPion) { + tpcPIDPassed = true; + } else { + return false; + } + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaPi()) < cMaxTOFnSigmaPion) { + tofPIDPassed = true; + } + if ((nsigmaCutCombinedPion > 0) && (candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi() + candidate.tofNSigmaPi() * candidate.tofNSigmaPi() < nsigmaCutCombinedPion * nsigmaCutCombinedPion)) { + tofPIDPassed = true; + } + } else { + if (!cTOFVeto) { + return false; + } + tofPIDPassed = true; + } + } + + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + return false; + } + + template + bool selectionK0s(CollisionType const& collision, K0sType const& candidate) + { + auto DauDCA = candidate.dcaV0daughters(); + auto DauPosDCAtoPV = candidate.dcapostopv(); + auto DauNegDCAtoPV = candidate.dcanegtopv(); + auto pT = candidate.pt(); + auto Rapidity = candidate.yK0Short(); + auto Radius = candidate.v0radius(); + auto DCAtoPV = candidate.dcav0topv(); + auto CPA = candidate.v0cosPA(); + auto PropTauK0s = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassK0Short; + auto mK0s = candidate.mK0Short(); + + if (cfgReturnFlag) { + bool returnFlag = true; + + if (cSecondaryRequire) { + histos.fill(HIST("QA/K0sCutCheck"), 0); + if (DauDCA > cSecondaryDauDCAMax) { + histos.fill(HIST("QA/K0sCutCheck"), 1); + returnFlag = false; + } + if (DauPosDCAtoPV < cSecondaryDauPosDCAtoPVMin) { + histos.fill(HIST("QA/K0sCutCheck"), 2); + returnFlag = false; + } + if (DauNegDCAtoPV < cSecondaryDauNegDCAtoPVMin) { + histos.fill(HIST("QA/K0sCutCheck"), 3); + returnFlag = false; + } + if (pT < cSecondaryPtMin) { + histos.fill(HIST("QA/K0sCutCheck"), 4); + returnFlag = false; + } + if (Rapidity > cSecondaryRapidityMax) { + histos.fill(HIST("QA/K0sCutCheck"), 5); + returnFlag = false; + } + if (Radius < cSecondaryRadiusMin) { + histos.fill(HIST("QA/K0sCutCheck"), 6); + returnFlag = false; + } + if (DCAtoPV > cSecondaryDCAtoPVMax) { + histos.fill(HIST("QA/K0sCutCheck"), 7); + returnFlag = false; + } + if (CPA < cSecondaryCosPAMin) { + histos.fill(HIST("QA/K0sCutCheck"), 8); + returnFlag = false; + } + if (PropTauK0s > cSecondaryProperLifetimeMax) { + histos.fill(HIST("QA/K0sCutCheck"), 9); + returnFlag = false; + } + if (candidate.qtarm() < cSecondaryparamArmenterosCut * TMath::Abs(candidate.alpha())) { + histos.fill(HIST("QA/K0sCutCheck"), 11); + returnFlag = false; + } + if (fabs(mK0s - MassK0Short) > cSecondaryMassWindow) { + histos.fill(HIST("QA/K0sCutCheck"), 10); + returnFlag = false; + } + + return returnFlag; + + } else { + if (fabs(mK0s - MassK0Short) > cSecondaryMassWindow) { + histos.fill(HIST("QA/K0sCutCheck"), 10); + returnFlag = false; + } + + return returnFlag; + } + + } else { + if (cSecondaryRequire) { + + histos.fill(HIST("QA/K0sCutCheck"), 0); + if (DauDCA > cSecondaryDauDCAMax) { + histos.fill(HIST("QA/K0sCutCheck"), 1); + return false; + } + if (DauPosDCAtoPV < cSecondaryDauPosDCAtoPVMin) { + histos.fill(HIST("QA/K0sCutCheck"), 2); + return false; + } + if (DauNegDCAtoPV < cSecondaryDauNegDCAtoPVMin) { + histos.fill(HIST("QA/K0sCutCheck"), 3); + return false; + } + if (pT < cSecondaryPtMin) { + histos.fill(HIST("QA/K0sCutCheck"), 4); + return false; + } + if (Rapidity > cSecondaryRapidityMax) { + histos.fill(HIST("QA/K0sCutCheck"), 5); + return false; + } + if (Radius < cSecondaryRadiusMin) { + histos.fill(HIST("QA/K0sCutCheck"), 6); + return false; + } + if (DCAtoPV > cSecondaryDCAtoPVMax) { + histos.fill(HIST("QA/K0sCutCheck"), 7); + return false; + } + if (CPA < cSecondaryCosPAMin) { + histos.fill(HIST("QA/K0sCutCheck"), 8); + return false; + } + if (PropTauK0s > cSecondaryProperLifetimeMax) { + histos.fill(HIST("QA/K0sCutCheck"), 9); + return false; + } + if (candidate.qtarm() < cSecondaryparamArmenterosCut * TMath::Abs(candidate.alpha())) { + histos.fill(HIST("QA/K0sCutCheck"), 11); + return false; + } + if (fabs(mK0s - MassK0Short) > cSecondaryMassWindow) { + histos.fill(HIST("QA/K0sCutCheck"), 10); + return false; + } + return true; + + } else { + if (fabs(mK0s - MassK0Short) > cSecondaryMassWindow) { + histos.fill(HIST("QA/K0sCutCheck"), 10); + return false; + } + return true; + } + } + } // selectionK0s + + double GetPhiInRange(double phi) + { + double result = phi; + while (result < 0) { + result = result + 2. * TMath::Pi() / 2; + } + while (result > 2. * TMath::Pi() / 2) { + result = result - 2. * TMath::Pi() / 2; + } + return result; + } + + template + bool isTrueKstar(const TrackTemplate& bTrack, const V0Template& K0scand) + { + if (abs(bTrack.PDGCode()) != kPiPlus) // Are you pion? + return false; + if (abs(K0scand.PDGCode()) != kPDGK0s) // Are you K0s? + return false; + + auto motherbTrack = bTrack.template mothers_as(); + auto motherkV0 = K0scand.template mothers_as(); + + // Check bTrack first + if (abs(motherbTrack.pdgCode()) != kKstarPlus) // Are you charged Kstar's daughter? + return false; // Apply first since it's more restrictive + + if (abs(motherkV0.pdgCode()) != 310) // Is it K0s? + return false; + // Check if K0s's mother is K0 (311) + auto motherK0 = motherkV0.template mothers_as(); + if (abs(motherK0.pdgCode()) != 311) + return false; + + // Check if K0's mother is Kstar (323) + auto motherKstar = motherK0.template mothers_as(); + if (abs(motherKstar.pdgCode()) != 323) + return false; + + // Check if bTrack and K0 have the same mother (global index) + if (motherbTrack.globalIndex() != motherK0.globalIndex()) + return false; + + return true; + } + + int count = 0; + + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksTypeK0s& dTracks2) + { + histos.fill(HIST("QA/before/CentDist"), centrality); + + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResoSecondary, lDecayDaughter_bach, lResoKstar; + std::vector trackIndicies = {}; + std::vector k0sIndicies = {}; + + for (auto& bTrack : dTracks1) { + auto trkbpt = bTrack.pt(); + auto istrkbhasTOF = bTrack.hasTOF(); + auto trkbNSigmaPiTPC = bTrack.tpcNSigmaPi(); + auto trkbNSigmaPiTOF = (istrkbhasTOF) ? bTrack.tofNSigmaPi() : -999.; + + if constexpr (!IsMix) { + // Bachelor pion QA plots + histos.fill(HIST("QA/before/trkbpionTPCPID"), trkbpt, trkbNSigmaPiTPC); + if (istrkbhasTOF) { + histos.fill(HIST("QA/before/trkbpionTOFPID"), trkbpt, trkbNSigmaPiTOF); + histos.fill(HIST("QA/before/trkbpionTPCTOFPID"), trkbNSigmaPiTPC, trkbNSigmaPiTOF); + } + histos.fill(HIST("QA/before/trkbpionpT"), trkbpt); + histos.fill(HIST("QA/before/trkbpionDCAxy"), bTrack.dcaXY()); + histos.fill(HIST("QA/before/trkbpionDCAz"), bTrack.dcaZ()); + } + + if (!trackCut(bTrack)) + continue; + if (!selectionPIDPion(bTrack)) + continue; + + if constexpr (!IsMix) { + // Bachelor pion QA plots after applying cuts + histos.fill(HIST("QA/after/trkbpionTPCPID"), trkbpt, trkbNSigmaPiTPC); + if (istrkbhasTOF) { + histos.fill(HIST("QA/after/trkbpionTOFPID"), trkbpt, trkbNSigmaPiTOF); + histos.fill(HIST("QA/after/trkbpionTPCTOFPID"), trkbNSigmaPiTPC, trkbNSigmaPiTOF); + } + histos.fill(HIST("QA/after/trkbpionpT"), trkbpt); + histos.fill(HIST("QA/after/trkbpionDCAxy"), bTrack.dcaXY()); + histos.fill(HIST("QA/after/trkbpionDCAz"), bTrack.dcaZ()); + } + trackIndicies.push_back(bTrack.index()); + } + + for (auto& K0scand : dTracks2) { + auto posDauTrack = K0scand.template posTrack_as(); + auto negDauTrack = K0scand.template negTrack_as(); + + /// Daughters + // Positve pion + auto trkppt = posDauTrack.pt(); + auto istrkphasTOF = posDauTrack.hasTOF(); + auto trkpNSigmaPiTPC = posDauTrack.tpcNSigmaPi(); + auto trkpNSigmaPiTOF = (istrkphasTOF) ? posDauTrack.tofNSigmaPi() : -999.; + // Negative pion + auto trknpt = negDauTrack.pt(); + auto istrknhasTOF = negDauTrack.hasTOF(); + auto trknNSigmaPiTPC = negDauTrack.tpcNSigmaPi(); + auto trknNSigmaPiTOF = (istrknhasTOF) ? negDauTrack.tofNSigmaPi() : -999.; + + /// K0s + auto trkkDauDCA = K0scand.dcaV0daughters(); + auto trkkDauDCAPostoPV = K0scand.dcapostopv(); + auto trkkDauDCANegtoPV = K0scand.dcanegtopv(); + auto trkkpt = K0scand.pt(); + auto trkky = K0scand.yK0Short(); + auto trkkRadius = K0scand.v0radius(); + auto trkkDCAtoPV = K0scand.dcav0topv(); + auto trkkCPA = K0scand.v0cosPA(); + auto trkkPropTau = K0scand.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassK0Short; + auto trkkMass = K0scand.mK0Short(); + + if constexpr (!IsMix) { + // Seconddary QA plots + histos.fill(HIST("QA/before/trkppionTPCPID"), trkppt, trkpNSigmaPiTPC); + if (istrkphasTOF) { + histos.fill(HIST("QA/before/trkppionTOFPID"), trkppt, trkpNSigmaPiTOF); + histos.fill(HIST("QA/before/trkppionTPCTOFPID"), trkpNSigmaPiTPC, trkpNSigmaPiTOF); + } + histos.fill(HIST("QA/before/trkppionpT"), trkppt); + histos.fill(HIST("QA/before/trkppionDCAxy"), posDauTrack.dcaXY()); + histos.fill(HIST("QA/before/trkppionDCAz"), posDauTrack.dcaZ()); + + histos.fill(HIST("QA/before/trknpionTPCPID"), trknpt, trknNSigmaPiTPC); + if (istrknhasTOF) { + histos.fill(HIST("QA/before/trknpionTOFPID"), trknpt, trknNSigmaPiTOF); + histos.fill(HIST("QA/before/trknpionTPCTOFPID"), trknNSigmaPiTPC, trknNSigmaPiTOF); + } + histos.fill(HIST("QA/before/trknpionpT"), trknpt); + histos.fill(HIST("QA/before/trknpionDCAxy"), negDauTrack.dcaXY()); + histos.fill(HIST("QA/before/trknpionDCAz"), negDauTrack.dcaZ()); + + histos.fill(HIST("QA/before/hDauDCASecondary"), trkkDauDCA); + histos.fill(HIST("QA/before/hDauPosDCAtoPVSecondary"), trkkDauDCAPostoPV); + histos.fill(HIST("QA/before/hDauNegDCAtoPVSecondary"), trkkDauDCANegtoPV); + + histos.fill(HIST("QA/before/hpT_Secondary"), trkkpt); + histos.fill(HIST("QA/before/hy_Secondary"), trkky); + histos.fill(HIST("QA/before/hRadiusSecondary"), trkkRadius); + histos.fill(HIST("QA/before/hDCAtoPVSecondary"), trkkDCAtoPV); + histos.fill(HIST("QA/before/hCPASecondary"), trkkCPA); + histos.fill(HIST("QA/before/hPropTauSecondary"), trkkPropTau); + histos.fill(HIST("QA/before/hInvmassSecondary"), trkkMass); + } + + // if (!trackCut(posDauTrack) || !trackCut(negDauTrack)) // Too tight cut for K0s daugthers + // continue; + if (!cfgByPassDauPIDSelection && !selectionPIDPion(posDauTrack)) // Perhaps it's already applied in trackCut (need to check QA plots) + continue; + if (!cfgByPassDauPIDSelection && !selectionPIDPion(negDauTrack)) + continue; + if (!selectionK0s(collision, K0scand)) + continue; + + if constexpr (!IsMix) { + // Seconddary QA plots after applying cuts + + histos.fill(HIST("QA/after/trkppionTPCPID"), trkppt, trkpNSigmaPiTPC); + if (istrkphasTOF) { + histos.fill(HIST("QA/after/trkppionTOFPID"), trkppt, trkpNSigmaPiTOF); + histos.fill(HIST("QA/after/trkppionTPCTOFPID"), trkpNSigmaPiTPC, trkpNSigmaPiTOF); + } + histos.fill(HIST("QA/after/trkppionpT"), trkppt); + histos.fill(HIST("QA/after/trkppionDCAxy"), posDauTrack.dcaXY()); + histos.fill(HIST("QA/after/trkppionDCAz"), posDauTrack.dcaZ()); + + histos.fill(HIST("QA/after/trknpionTPCPID"), trknpt, trknNSigmaPiTPC); + if (istrknhasTOF) { + histos.fill(HIST("QA/after/trknpionTOFPID"), trknpt, trknNSigmaPiTOF); + histos.fill(HIST("QA/after/trknpionTPCTOFPID"), trknNSigmaPiTPC, trknNSigmaPiTOF); + } + histos.fill(HIST("QA/after/trknpionpT"), trknpt); + histos.fill(HIST("QA/after/trknpionDCAxy"), negDauTrack.dcaXY()); + histos.fill(HIST("QA/after/trknpionDCAz"), negDauTrack.dcaZ()); + + histos.fill(HIST("QA/after/hDauDCASecondary"), trkkDauDCA); + histos.fill(HIST("QA/after/hDauPosDCAtoPVSecondary"), trkkDauDCAPostoPV); + histos.fill(HIST("QA/after/hDauNegDCAtoPVSecondary"), trkkDauDCANegtoPV); + + histos.fill(HIST("QA/after/hpT_Secondary"), trkkpt); + histos.fill(HIST("QA/after/hy_Secondary"), trkky); + histos.fill(HIST("QA/after/hRadiusSecondary"), trkkRadius); + histos.fill(HIST("QA/after/hDCAtoPVSecondary"), trkkDCAtoPV); + histos.fill(HIST("QA/after/hCPASecondary"), trkkCPA); + histos.fill(HIST("QA/after/hPropTauSecondary"), trkkPropTau); + histos.fill(HIST("QA/after/hInvmassSecondary"), trkkMass); + } + k0sIndicies.push_back(K0scand.index()); + } + + for (auto& trackIndex : trackIndicies) { + for (auto& k0sIndex : k0sIndicies) { + auto bTrack = dTracks1.rawIteratorAt(trackIndex); + auto K0scand = dTracks2.rawIteratorAt(k0sIndex); + + lDecayDaughter_bach.SetXYZM(bTrack.px(), bTrack.py(), bTrack.pz(), MassPionCharged); + lResoSecondary.SetXYZM(K0scand.px(), K0scand.py(), K0scand.pz(), MassK0Short); + lResoKstar = lResoSecondary + lDecayDaughter_bach; + + // QA plots + if constexpr (!IsMix) { + histos.fill(HIST("QA/before/KstarRapidity"), lResoKstar.Rapidity()); + histos.fill(HIST("QA/before/kstarinvmass"), lResoKstar.M()); + } + + if (lResoKstar.Rapidity() > cKstarMaxRap || lResoKstar.Rapidity() < cKstarMinRap) + continue; + + if constexpr (!IsMix) { + unsigned int typeKstar = bTrack.sign() > 0 ? binType::kKstarP : binType::kKstarN; + + histos.fill(HIST("QA/after/KstarRapidity"), lResoKstar.Rapidity()); + histos.fill(HIST("QA/after/kstarinvmass"), lResoKstar.M()); + histos.fill(HIST("hInvmass_Kstar"), typeKstar, centrality, lResoKstar.Pt(), lResoKstar.M()); + + } // IsMix + } // K0scand + } // bTrack + + count++; + + } // fillHistograms + + // process data + void processData(EventCandidates::iterator const& collision, + TrackCandidates const& tracks, + V0Candidates const& v0s, + aod::BCsWithTimestamps const&) + { + if (!colCuts.isSelected(collision)) // Default event selection + return; + colCuts.fillQA(collision); + centrality = GetCentrality(collision); + + fillHistograms(collision, tracks, v0s); // second order + } + PROCESS_SWITCH(chk892pp, processData, "Process Event for data without Partitioning", true); + + // process MC reconstructed level + void processMC(EventCandidates::iterator const& collision, + MCTrackCandidates const& tracks, + MCV0Candidates const& v0s) + { + + histos.fill(HIST("QAMC/hEvent"), 1.0); + + fillHistograms(collision, tracks, v0s); + } + PROCESS_SWITCH(chk892pp, processMC, "Process Event for MC", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"lf-chk892pp"})}; +} diff --git a/PWGLF/Tasks/Resonances/doubleResonanceScan.cxx b/PWGLF/Tasks/Resonances/doubleResonanceScan.cxx new file mode 100644 index 00000000000..5d8772ef7e9 --- /dev/null +++ b/PWGLF/Tasks/Resonances/doubleResonanceScan.cxx @@ -0,0 +1,548 @@ +// 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 doubleResonanceScan.cxx +/// \brief Resonance Scanner with ResoTracks and ResoMicroTracks +/// \author Bong-Hwi Lim +/// \since 27/03/2025 +/// + +#include +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFResonanceTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "CommonConstants/MathConstants.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; +using namespace o2::constants::math; +// Extract STEP +// Handle resomicrotracks +struct DoubleResonanceScan { + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Configurables + struct : ConfigurableGroup { + ConfigurableAxis cfgBinsPt{"cfgBinsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12.0, 12.1, 12.2, 12.3, 12.4, 12.5, 12.6, 12.7, 12.8, 12.9, 13.0, 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7, 13.8, 13.9, 14.0, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15.0}, "Binning of the pT axis"}; + ConfigurableAxis cfgBinsPtQA{"cfgBinsPtQA", {VARIABLE_WIDTH, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2, 6.4, 6.6, 6.8, 7.0, 7.2, 7.4, 7.6, 7.8, 8.0, 8.2, 8.4, 8.6, 8.8, 9.0, 9.2, 9.4, 9.6, 9.8, 10.0}, "Binning of the pT axis"}; + ConfigurableAxis cfgBinsCent{"cfgBinsCent", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0}, "Binning of the centrality axis"}; + ConfigurableAxis cfgBinsVtxZ{"cfgBinsVtxZ", {VARIABLE_WIDTH, -10.0, -9.0, -8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0}, "Binning of the z-vertex axis"}; + Configurable cNbinsDiv{"cNbinsDiv", 1, "Integer to divide the number of bins"}; + Configurable cNbinsDivQA{"cNbinsDivQA", 1, "Integer to divide the number of bins for QA"}; + Configurable cfgInvMassNBins1{"cfgInvMassNBins1", 400, "Number of bins for the invariant mass pair"}; + Configurable cfgInvMassPairStart1{"cfgInvMassPairStart1", 0.9, "Start of the invariant mass pair"}; + Configurable cfgInvMassPairEnd1{"cfgInvMassPairEnd1", 1.3, "Start of the invariant mass pair"}; + Configurable cfgInvMassNBins2{"cfgInvMassNBins2", 400, "Number of bins for the invariant mass pair"}; + Configurable cfgInvMassPairStart2{"cfgInvMassPairStart2", 0.9, "Start of the invariant mass pair"}; + Configurable cfgInvMassPairEnd2{"cfgInvMassPairEnd2", 1.3, "Start of the invariant mass pair"}; + Configurable cfgInvMassNBinsReso{"cfgInvMassNBinsReso", 800, "Number of bins for the invariant mass final pair"}; + Configurable cfgInvMassPairStartReso{"cfgInvMassPairStartReso", 2.4, "Start of the invariant mass final pair"}; + Configurable cfgInvMassPairEndReso{"cfgInvMassPairEndReso", 4.0, "Start of the invariant mass final pair"}; + } AxisConfig; + + struct : ConfigurableGroup { + Configurable cfgFillQAPlots{"cfgFillQAPlots", true, "Fill QA plots"}; + } AnalysisConfig; + + // Configurable for min pT cut + Configurable cMinPtcut{"cMinPtcut", 0.15, "Track minium pt cut"}; + + // Track selection + // primary track condition + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; + Configurable cfgPVContributor{"cfgPVContributor", false, "PV contributor track selection"}; + + // DCA Selections + Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 0.15, "Track DCAr cut to PV Maximum"}; + Configurable cUsePtDependentDCArCut{"cUsePtDependentDCArCut", false, "Use Pt dependent DCAr cut"}; + Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 0.15, "Track DCAz cut to PV Maximum"}; + + // PID selection + Configurable cfgFirstDaughter{"cfgFirstDaughter", 0, "code of the first daughter, 0: pion, 1: kaon, 2: proton"}; + Configurable cfgSecondDaughter{"cfgSecondDaughter", 0, "code of the second daughter, 0: pion, 1: kaon, 2: proton"}; + Configurable cfgThirdDaughter{"cfgThirdDaughter", 0, "code of the third daughter, 0: pion, 1: kaon, 2: proton"}; + Configurable cfgFourthDaughter{"cfgFourthDaughter", 0, "code of the fourth daughter, 0: pion, 1: kaon, 2: proton"}; + // PID selection values + Configurable nSigmaCutTPC{"nSigmaCutTPC", 3.0, "Value of the TPC Nsigma cut"}; + Configurable nSigmaCutTOF{"nSigmaCutTOF", 3.0, "Value of the TOF Nsigma cut, if negative, TOF is not used"}; + + struct : ConfigurableGroup { + Configurable> cfgPairMassesLow{"cfgPairMassesLow", {1.01, 1.01}, "Low mass cut for pair_1 pair_2"}; + Configurable> cfgPairMassesHigh{"cfgPairMassesHigh", {1.03, 1.03}, "High mass cut for pair_1 pair_2"}; + Configurable> cfgPairOACut{"cfgPairOACut", {0.04, 0.04}, "Opening angle cut for pair_1 pair_2"}; + } PairCuts; + + struct : ConfigurableGroup { + Configurable cfgPairOALow{"cfgPairOALow", -999, "Low opening angle cut for pair_1 pair_2"}; + Configurable cfgPairOAHigh{"cfgPairOAHigh", 999, "High opening angle cut for pair_1 pair_2"}; + } ResoCuts; + + /// Event Mixing + Configurable nEvtMixing{"nEvtMixing", 5, "Number of events to mix"}; + ConfigurableAxis cfgVtxBins{"cfgVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis cfgMultBins{"cfgMultBins", {VARIABLE_WIDTH, 0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Mixing bins - z-vertex"}; + + /// Rotation background + struct : ConfigurableGroup { + Configurable cfgFillRotBkg{"cfgFillRotBkg", true, "Fill rotated background"}; + Configurable cfgMinRot{"cfgMinRot", 5.0 * constants::math::PI / 6.0, "Minimum of rotation"}; + Configurable cfgMaxRot{"cfgMaxRot", 7.0 * constants::math::PI / 6.0, "Maximum of rotation"}; + Configurable cfgNrotBkg{"cfgNrotBkg", 9, "Number of rotated copies (background) per each original candidate"}; + } BkgEstimationConfig; + + float mass1{MassPionCharged}, mass2{MassPionCharged}, mass3{MassPionCharged}, mass4{MassPionCharged}; + + float getMassFromCode(int code) + { + switch (code) { + case 0: + return MassPionCharged; + case 1: + return MassKaonCharged; + case 2: + return MassProton; + default: + return 0.f; + } + } + void init(o2::framework::InitContext&) + { + LOG(info) << "Initializing DoubleResonanceScan"; + LOG(info) << "First Daughter: " << cfgFirstDaughter << " Second Daughter: " << cfgSecondDaughter << " Third Daughter: " << cfgThirdDaughter << " Fourth Daughter: " << cfgFourthDaughter; + mass1 = getMassFromCode(cfgFirstDaughter); + mass2 = getMassFromCode(cfgSecondDaughter); + mass3 = getMassFromCode(cfgThirdDaughter); + mass4 = getMassFromCode(cfgFourthDaughter); + LOG(info) << "Masses: " << mass1 << " " << mass2 << " " << mass3 << " " << mass4; + + AxisSpec centAxis = {AxisConfig.cfgBinsCent, "T0M (%)"}; + AxisSpec vtxzAxis = {AxisConfig.cfgBinsVtxZ, "Z Vertex (cm)"}; + AxisSpec ptAxis = {AxisConfig.cfgBinsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptAxisQA = {AxisConfig.cfgBinsPtQA, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec dcaAxis = {200 / AxisConfig.cNbinsDivQA, 0, 2, "DCA (cm)"}; + AxisSpec dcaxyAxis = {100 / AxisConfig.cNbinsDivQA, 0, 1, "DCA_{#it{xy}} (cm)"}; + AxisSpec dcazAxis = {100 / AxisConfig.cNbinsDivQA, 0, 1, "DCA_{#it{z}} (cm)"}; + AxisSpec yAxis = {50, -1, 1, "Rapidity"}; + AxisSpec invMassAxisPair1 = {AxisConfig.cfgInvMassNBins1, AxisConfig.cfgInvMassPairStart1, AxisConfig.cfgInvMassPairEnd1, "Invariant Mass (GeV/#it{c}^2)"}; + AxisSpec invMassAxisPair2 = {AxisConfig.cfgInvMassNBins2, AxisConfig.cfgInvMassPairStart2, AxisConfig.cfgInvMassPairEnd2, "Invariant Mass (GeV/#it{c}^2)"}; + AxisSpec invMassAxisReso = {AxisConfig.cfgInvMassNBinsReso, AxisConfig.cfgInvMassPairStartReso, AxisConfig.cfgInvMassPairEndReso, "Invariant Mass (GeV/#it{c}^2)"}; + AxisSpec pidQAAxis = {130 / AxisConfig.cNbinsDivQA, -6.5, 6.5}; + // Event QA + histos.add("hVertexZ", "hVertexZ", HistType::kTH1F, {{300, -15., 15.}}); + histos.add("hMultiplicityPercent", "Multiplicity Percentile", kTH1F, {{120, 0.0f, 120.0f}}); + + if (AnalysisConfig.cfgFillQAPlots) { + // First Daughter + histos.add("hEta_1", "Eta distribution", kTH1F, {yAxis}); + histos.add("hPhi_1", "Phi distribution", kTH1F, {{200 / AxisConfig.cNbinsDivQA, 0, TwoPI}}); + histos.add("hPt_1", "Pt distribution", kTH1F, {ptAxisQA}); + histos.add("hDCAr_1", "DCAr distribution", kTH1F, {dcaxyAxis}); + histos.add("hDCAz_1", "DCAz distribution", kTH1F, {dcazAxis}); + histos.add("hNsigmaTPC_1", "nSigmaTPC distribution", kTH1F, {pidQAAxis}); + histos.add("hNsigmaTOF_1", "nSigmaTOF distribution", kTH1F, {pidQAAxis}); + + // Second Daughter + histos.add("hEta_2", "Eta distribution", kTH1F, {yAxis}); + histos.add("hPhi_2", "Phi distribution", kTH1F, {{200 / AxisConfig.cNbinsDivQA, 0, TwoPI}}); + histos.add("hPt_2", "Pt distribution", kTH1F, {ptAxisQA}); + histos.add("hDCAr_2", "DCAr distribution", kTH1F, {dcaxyAxis}); + histos.add("hDCAz_2", "DCAz distribution", kTH1F, {dcazAxis}); + histos.add("hNsigmaTPC_2", "nSigmaTPC distribution", kTH1F, {pidQAAxis}); + histos.add("hNsigmaTOF_2", "nSigmaTOF distribution", kTH1F, {pidQAAxis}); + + // Third Daughter + histos.add("hEta_3", "Eta distribution", kTH1F, {yAxis}); + histos.add("hPhi_3", "Phi distribution", kTH1F, {{200 / AxisConfig.cNbinsDivQA, 0, TwoPI}}); + histos.add("hPt_3", "Pt distribution", kTH1F, {ptAxisQA}); + histos.add("hDCAr_3", "DCAr distribution", kTH1F, {dcaxyAxis}); + histos.add("hDCAz_3", "DCAz distribution", kTH1F, {dcazAxis}); + histos.add("hNsigmaTPC_3", "nSigmaTPC distribution", kTH1F, {pidQAAxis}); + histos.add("hNsigmaTOF_3", "nSigmaTOF distribution", kTH1F, {pidQAAxis}); + + // Forth Daughter + histos.add("hEta_4", "Eta distribution", kTH1F, {yAxis}); + histos.add("hPhi_4", "Phi distribution", kTH1F, {{200 / AxisConfig.cNbinsDivQA, 0, TwoPI}}); + histos.add("hPt_4", "Pt distribution", kTH1F, {ptAxisQA}); + histos.add("hDCAr_4", "DCAr distribution", kTH1F, {dcaxyAxis}); + histos.add("hDCAz_4", "DCAz distribution", kTH1F, {dcazAxis}); + histos.add("hNsigmaTPC_4", "nSigmaTPC distribution", kTH1F, {pidQAAxis}); + histos.add("hNsigmaTOF_4", "nSigmaTOF distribution", kTH1F, {pidQAAxis}); + + // First Pair + histos.add("hPairInvMass_1", "Invariant mass distribution", kTH1F, {invMassAxisPair1}); + histos.add("hPairPt_1", "Pt distribution", kTH1F, {ptAxis}); + histos.add("hPairOA_1", "Opening angle distribution", kTH1F, {AxisSpec{100, 0, PI, "Opening Angle (rad)"}}); + + // Second Pair + histos.add("hPairInvMass_2", "Invariant mass distribution", kTH1F, {invMassAxisPair2}); + histos.add("hPairPt_2", "Pt distribution", kTH1F, {ptAxis}); + histos.add("hPairOA_2", "Opening angle distribution", kTH1F, {AxisSpec{100, 0, PI, "Opening Angle (rad)"}}); + + // Resonance + histos.add("h2PairInvMass", "Invariant mass distribution", kTH2F, {invMassAxisPair1, invMassAxisPair2}); + histos.add("hResoInvMass", "Invariant mass distribution", kTH1F, {invMassAxisReso}); + histos.add("hResoOA", "Opening angle distribution", kTH1F, {AxisSpec{100, 0, PI, "Opening Angle (rad)"}}); + histos.add("THnResoInvMass", "Invariant mass distribution with other axes", HistType::kTHnSparseD, {centAxis, ptAxis, invMassAxisReso}); + histos.add("THnResoInvMassBkg", "Invariant mass distribution with other axes", HistType::kTHnSparseD, {centAxis, ptAxis, invMassAxisReso}); + } + + LOG(info) << "Size of the histograms in double resonance scan with table combination:"; + histos.print(); + } + + template + bool trackCut(const TrackType track) + { + if constexpr (!IsResoMicrotrack) { + if (std::abs(track.pt()) < cMinPtcut) + return false; + if (cUsePtDependentDCArCut) { + // Tuned on the LHC22f anchored MC LHC23d1d on primary pions. 7 Sigmas of the resolution + if (std::abs(track.dcaXY()) > (0.004 + (0.013 / track.pt()))) + return false; + } else { + if (std::abs(track.dcaXY()) > cMaxDCArToPVcut) + return false; + } + if (std::abs(track.dcaZ()) > cMaxDCAzToPVcut) + return false; + if (cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (cfgPVContributor && !track.isPVContributor()) + return false; + } else { + if (std::abs(track.pt()) < cMinPtcut) + return false; + if (cUsePtDependentDCArCut) { + if (o2::aod::resodmciroaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags()) > -Epsilon) + return false; + } else { + if (o2::aod::resodmciroaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags()) > cMaxDCArToPVcut - Epsilon) + return false; + } + if (o2::aod::resodmciroaughter::ResoMicroTrackSelFlag::decodeDCAz(track.trackSelectionFlags()) > cMaxDCAzToPVcut - Epsilon) + return false; + if (cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (cfgPVContributor && !track.isPVContributor()) + return false; + } + return true; + } + + template + float getPIDTPC(const T& candidate, int particleType) + { + if constexpr (!IsResoMicrotrack) { + // switch based on particleType + switch (particleType) { + case 0: // pion + return candidate.tpcNSigmaPi(); + case 1: // kaon + return candidate.tpcNSigmaKa(); + case 2: // proton + return candidate.tpcNSigmaPr(); + default: + return -999; + } + } else { + switch (particleType) { + case 0: // pion + return o2::aod::resodmciroaughter::PidNSigma::getTPCnSigma(candidate.pidNSigmaPiFlag()); + case 1: // kaon + return o2::aod::resodmciroaughter::PidNSigma::getTPCnSigma(candidate.pidNSigmaKaFlag()); + case 2: // proton + return o2::aod::resodmciroaughter::PidNSigma::getTPCnSigma(candidate.pidNSigmaPrFlag()); + default: + return -999; + } + } + } + + template + float getPIDTOF(const T& candidate, int particleType) + { + if constexpr (!IsResoMicrotrack) { + // switch based on particleType + switch (particleType) { + case 0: // pion + return candidate.hasTOF() ? candidate.tofNSigmaPi() : -999; + case 1: // kaon + return candidate.hasTOF() ? candidate.tofNSigmaKa() : -999; + case 2: // proton + return candidate.hasTOF() ? candidate.tofNSigmaPr() : -999; + default: + return -999; + } + } else { + switch (particleType) { + case 0: // pion + return candidate.hasTOF() ? o2::aod::resodmciroaughter::PidNSigma::getTOFnSigma(candidate.pidNSigmaPiFlag()) : -999; + case 1: // kaon + return candidate.hasTOF() ? o2::aod::resodmciroaughter::PidNSigma::getTOFnSigma(candidate.pidNSigmaKaFlag()) : -999; + case 2: // proton + return candidate.hasTOF() ? o2::aod::resodmciroaughter::PidNSigma::getTOFnSigma(candidate.pidNSigmaPrFlag()) : -999; + default: + return -999; + } + } + } + + template + bool selectionPID(const T& candidate, int particleType) + { + bool tpcPass = std::abs(getPIDTPC(candidate, particleType)) < nSigmaCutTPC; + bool tofPass = (nSigmaCutTOF > 0) ? std::abs(getPIDTOF(candidate, particleType)) < nSigmaCutTOF : true; + if (tpcPass && tofPass) { + return true; + } + return false; + } + + template + std::vector selectTrackIndicesWithQA(const TracksType& dTracks, int daughterType, int daughterIndex) + { + std::vector selectedIndices; + for (auto const& track : dTracks) { + if (!trackCut(track)) { + continue; + } + if (!selectionPID(track, daughterType)) { + continue; + } + + if (AnalysisConfig.cfgFillQAPlots) { + auto dcaXY = -999; + auto dcaZ = -999; + if constexpr (!IsResoMicrotrack) { + dcaXY = track.dcaXY(); + dcaZ = track.dcaZ(); + } else { + dcaXY = o2::aod::resodmciroaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags()); + dcaZ = o2::aod::resodmciroaughter::ResoMicroTrackSelFlag::decodeDCAz(track.trackSelectionFlags()); + } + // FIXME: Apply better method + switch (daughterIndex) { + case 0: // First + histos.fill(HIST("hEta_1"), track.eta()); + histos.fill(HIST("hPhi_1"), track.phi()); + histos.fill(HIST("hPt_1"), track.pt()); + histos.fill(HIST("hDCAr_1"), dcaXY); + histos.fill(HIST("hDCAz_1"), dcaZ); + histos.fill(HIST("hNsigmaTPC_1"), getPIDTPC(track, daughterType)); + histos.fill(HIST("hNsigmaTOF_1"), getPIDTOF(track, daughterType)); + break; + case 1: // Second + histos.fill(HIST("hEta_2"), track.eta()); + histos.fill(HIST("hPhi_2"), track.phi()); + histos.fill(HIST("hPt_2"), track.pt()); + histos.fill(HIST("hDCAr_2"), dcaXY); + histos.fill(HIST("hDCAz_2"), dcaZ); + histos.fill(HIST("hNsigmaTPC_2"), getPIDTPC(track, daughterType)); + histos.fill(HIST("hNsigmaTOF_2"), getPIDTOF(track, daughterType)); + break; + case 2: // Third + histos.fill(HIST("hEta_3"), track.eta()); + histos.fill(HIST("hPhi_3"), track.phi()); + histos.fill(HIST("hPt_3"), track.pt()); + histos.fill(HIST("hDCAr_3"), dcaXY); + histos.fill(HIST("hDCAz_3"), dcaZ); + histos.fill(HIST("hNsigmaTPC_3"), getPIDTPC(track, daughterType)); + histos.fill(HIST("hNsigmaTOF_3"), getPIDTOF(track, daughterType)); + break; + case 3: // Forth + histos.fill(HIST("hEta_4"), track.eta()); + histos.fill(HIST("hPhi_4"), track.phi()); + histos.fill(HIST("hPt_4"), track.pt()); + histos.fill(HIST("hDCAr_4"), dcaXY); + histos.fill(HIST("hDCAz_4"), dcaZ); + histos.fill(HIST("hNsigmaTPC_4"), getPIDTPC(track, daughterType)); + histos.fill(HIST("hNsigmaTOF_4"), getPIDTOF(track, daughterType)); + break; + default: + break; + } + } + selectedIndices.push_back(track.index()); + } + return selectedIndices; + } + + bool isPairSelected(const TLorentzVector& lv1, const TLorentzVector& lv2, int pairType = 0) + { + TLorentzVector lvSum = lv1 + lv2; + // Mass window cut + auto pairMass = lvSum.M(); + auto pairMassesLow = PairCuts.cfgPairMassesLow.value; + auto pairMassesHigh = PairCuts.cfgPairMassesHigh.value; + if ((pairMassesLow[pairType] > 0) || (pairMassesHigh[pairType] > 0)) { + if (pairMass < pairMassesLow[pairType] || pairMass > pairMassesHigh[pairType]) { + return false; + } + } + // Opening angle cut + double angle = lv1.Vect().Angle(lv2.Vect()); + auto angleCut = PairCuts.cfgPairOACut.value; + if (angleCut[pairType] > 0) { + if (angle < angleCut[pairType]) { + return false; + } + } + if (AnalysisConfig.cfgFillQAPlots) { + // FIXME: Apply better method + if (pairType > 0) { + histos.fill(HIST("hPairInvMass_2"), pairMass); + histos.fill(HIST("hPairPt_2"), lvSum.Pt()); + histos.fill(HIST("hPairOA_2"), angle); + } else { + histos.fill(HIST("hPairInvMass_1"), pairMass); + histos.fill(HIST("hPairPt_1"), lvSum.Pt()); + histos.fill(HIST("hPairOA_1"), angle); + } + } + return true; + } + + template + std::vector> + getSelectedTrackPairs(const TracksType& dTracks, + const std::vector& indicesA, + const std::vector& indicesB, + float massA, float massB, + int pairType) + { + std::vector> selectedPairs; + TLorentzVector lv1, lv2; + for (const auto& indexA : indicesA) { + for (const auto& indexB : indicesB) { + if (indexA == indexB) { + continue; + } + + auto trackA = dTracks.rawIteratorAt(indexA); + auto trackB = dTracks.rawIteratorAt(indexB); + + lv1.SetXYZM(trackA.px(), trackA.py(), trackA.pz(), massA); + lv2.SetXYZM(trackB.px(), trackB.py(), trackB.pz(), massB); + + if (!isPairSelected(lv1, lv2, pairType)) { + continue; + } + selectedPairs.emplace_back(indexA, indexB); + } + } + return selectedPairs; + } + + bool isResoSelected(const TLorentzVector& par1, const TLorentzVector& pair2) + { + // Opening angle (3D) + double oa = par1.Vect().Angle(pair2.Vect()); + if (oa < ResoCuts.cfgPairOALow || oa > ResoCuts.cfgPairOAHigh) { + return false; + } + // Rapidity cut + TLorentzVector lvTotal = par1 + pair2; + if (lvTotal.Rapidity() < -0.5 || lvTotal.Rapidity() > 0.5) { + return false; + } + histos.fill(HIST("hResoOA"), oa); + return true; + } + + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks) + { + auto multiplicity = collision.cent(); + histos.fill(HIST("hVertexZ"), collision.posZ()); + histos.fill(HIST("hMultiplicityPercent"), multiplicity); + + auto trackIndices1 = selectTrackIndicesWithQA(dTracks, cfgFirstDaughter, 0); + auto trackIndices2 = selectTrackIndicesWithQA(dTracks, cfgSecondDaughter, 1); + auto trackIndices3 = selectTrackIndicesWithQA(dTracks, cfgThirdDaughter, 2); + auto trackIndices4 = selectTrackIndicesWithQA(dTracks, cfgFourthDaughter, 3); + + // First resconstructed pair + auto selectedPairs1 = getSelectedTrackPairs(dTracks, trackIndices1, trackIndices2, mass1, mass2, 0); + auto selectedPairs2 = getSelectedTrackPairs(dTracks, trackIndices3, trackIndices4, mass3, mass4, 1); + + // Resonance loop of selectedPairs1 and selectedPairs2 + for (const auto& pair1 : selectedPairs1) { + const auto& i1 = pair1.first; + const auto& i2 = pair1.second; + for (const auto& pair2 : selectedPairs2) { + const auto& j1 = pair2.first; + const auto& j2 = pair2.second; + // Remove the same track + if (i1 == j1 || i1 == j2 || i2 == j1 || i2 == j2) { + continue; + } + auto t1 = dTracks.rawIteratorAt(i1); + auto t2 = dTracks.rawIteratorAt(i2); + auto t3 = dTracks.rawIteratorAt(j1); + auto t4 = dTracks.rawIteratorAt(j2); + + TLorentzVector lv1, lv2, lv3, lv4, lvPair1, lvPair2, lvTotal, lResonanceRot; + lv1.SetXYZM(t1.px(), t1.py(), t1.pz(), mass1); + lv2.SetXYZM(t2.px(), t2.py(), t2.pz(), mass2); + lv3.SetXYZM(t3.px(), t3.py(), t3.pz(), mass3); + lv4.SetXYZM(t4.px(), t4.py(), t4.pz(), mass4); + lvPair1 = lv1 + lv2; + lvPair2 = lv3 + lv4; + if (!isResoSelected(lvPair1, lvPair2)) + continue; + lvTotal = lv1 + lv2 + lv3 + lv4; + histos.fill(HIST("h2PairInvMass"), lvPair1.M(), lvPair2.M()); + histos.fill(HIST("hResoInvMass"), lvTotal.M()); + histos.fill(HIST("THnResoInvMass"), multiplicity, lvTotal.Pt(), lvTotal.M()); + if (BkgEstimationConfig.cfgFillRotBkg) { + for (int i = 0; i < BkgEstimationConfig.cfgNrotBkg; i++) { + auto lRotAngle = BkgEstimationConfig.cfgMinRot + i * ((BkgEstimationConfig.cfgMaxRot - BkgEstimationConfig.cfgMinRot) / (BkgEstimationConfig.cfgNrotBkg - 1)); + lvPair2.RotateZ(lRotAngle); + lResonanceRot = lvPair1 + lvPair2; + histos.fill(HIST("THnResoInvMassBkg"), multiplicity, lResonanceRot.Pt(), lResonanceRot.M()); + } + } + } + } + } + + void processDummy(aod::ResoCollision const& /*collisions*/) + { + } + PROCESS_SWITCH(DoubleResonanceScan, processDummy, "Process Dummy", true); + + void processResoTracks(aod::ResoCollision const& collision, aod::ResoTracks const& resotracks) + { + fillHistograms(collision, resotracks); + } + PROCESS_SWITCH(DoubleResonanceScan, processResoTracks, "Process ResoTracks", false); + + void processResoMicroTracks(aod::ResoCollision const& collision, aod::ResoMicroTracks const& resomicrotracks) + { + fillHistograms(collision, resomicrotracks); + } + PROCESS_SWITCH(DoubleResonanceScan, processResoMicroTracks, "Process ResoMicroTracks", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/Resonances/doublephimeson.cxx b/PWGLF/Tasks/Resonances/doublephimeson.cxx new file mode 100644 index 00000000000..6669df802f5 --- /dev/null +++ b/PWGLF/Tasks/Resonances/doublephimeson.cxx @@ -0,0 +1,432 @@ +// 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 this is a starting point for the Resonances tutorial +/// \author sourav kundu +/// \since 02/11/2023 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/StepTHn.h" +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/ReducedDoublePhiTables.h" +#include "CommonConstants/PhysicsConstants.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct doublephimeson { + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Configurable strategyPID1{"strategyPID1", 0, "PID strategy 1"}; + Configurable strategyPID2{"strategyPID2", 0, "PID strategy 2"}; + Configurable minPhiMass{"minPhiMass", 1.01, "Minimum phi mass"}; + Configurable maxPhiMass{"maxPhiMass", 1.03, "Maximum phi mass"}; + Configurable minExoticMass{"minExoticMass", 2.4, "Minimum Exotic mass"}; + Configurable maxExoticMass{"maxExoticMass", 3.2, "Maximum Exotic mass"}; + Configurable additionalEvsel{"additionalEvsel", false, "Additional event selection"}; + Configurable isDeep{"isDeep", true, "Store deep angle"}; + Configurable cutMinNsigmaTPC{"cutMinNsigmaTPC", -2.5, "nsigma cut TPC"}; + Configurable cutNsigmaTPC{"cutNsigmaTPC", 3.0, "nsigma cut TPC"}; + Configurable cutNsigmaTOF{"cutNsigmaTOF", 3.0, "nsigma cut TOF"}; + Configurable momTOFCut{"momTOFCut", 1.8, "minimum pT cut for madnatory TOF"}; + Configurable maxKaonPt{"maxKaonPt", 4.0, "maximum kaon pt cut"}; + // Event Mixing + Configurable nEvtMixing{"nEvtMixing", 1, "Number of events to mix"}; + ConfigurableAxis CfgVtxBins{"CfgVtxBins", {10, -10, 10}, "Mixing bins - z-vertex"}; + ConfigurableAxis CfgMultBins{"CfgMultBins", {VARIABLE_WIDTH, 0.0, 20.0, 40.0, 60.0, 80.0, 500.0}, "Mixing bins - number of contributor"}; + + // THnsparse bining + ConfigurableAxis configThnAxisInvMass{"configThnAxisInvMass", {1500, 2.0, 3.5}, "#it{M} (GeV/#it{c}^{2})"}; + ConfigurableAxis configThnAxisInvMassPhi{"configThnAxisInvMassPhi", {20, 1.01, 1.03}, "#it{M} (GeV/#it{c}^{2})"}; + ConfigurableAxis configThnAxisInvMassDeltaPhi{"configThnAxisInvMassDeltaPhi", {80, 0.0, 0.08}, "#it{M} (GeV/#it{c}^{2})"}; + ConfigurableAxis configThnAxisDaugherPt{"configThnAxisDaugherPt", {25, 0.0, 50.}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis configThnAxisPt{"configThnAxisPt", {40, 0.0, 20.}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis configThnAxisKstar{"configThnAxisKstar", {200, 0.0, 2.0}, "#it{k}^{*} (GeV/#it{c})"}; + ConfigurableAxis configThnAxisDeltaR{"configThnAxisDeltaR", {200, 0.0, 2.0}, "#it{k}^{*} (GeV/#it{c})"}; + ConfigurableAxis configThnAxisCosTheta{"configThnAxisCosTheta", {160, 0.0, 3.2}, "cos #theta{*}"}; + ConfigurableAxis configThnAxisNumPhi{"configThnAxisNumPhi", {101, -0.5, 100.5}, "cos #theta{*}"}; + + // Initialize the ananlysis task + void init(o2::framework::InitContext&) + { + // register histograms + histos.add("hnsigmaTPCKaonPlus", "hnsigmaTPCKaonPlus", kTH2F, {{1000, -3.0, 3.0f}, {100, 0.0f, 10.0f}}); + histos.add("hnsigmaTPCKaonMinus", "hnsigmaTPCKaonMinus", kTH2F, {{1000, -3.0, 3.0f}, {100, 0.0f, 10.0f}}); + histos.add("hnsigmaTPCTOFKaon", "hnsigmaTPCTOFKaon", kTH3F, {{500, -3.0, 3.0f}, {500, -3.0, 3.0f}, {100, 0.0f, 10.0f}}); + histos.add("hPhiMass", "hPhiMass", kTH2F, {{40, 1.0, 1.04f}, {100, 0.0f, 10.0f}}); + histos.add("hPhiMass2", "hPhiMass2", kTH2F, {{40, 1.0, 1.04f}, {40, 1.0f, 1.04f}}); + + const AxisSpec thnAxisInvMass{configThnAxisInvMass, "#it{M} (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisInvMassPhi{configThnAxisInvMassPhi, "#it{M} (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisInvMassDeltaPhi{configThnAxisInvMassDeltaPhi, "#it{M} (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisPt{configThnAxisPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisDeltaR{configThnAxisDeltaR, "#Delta R)"}; + const AxisSpec thnAxisCosTheta{configThnAxisCosTheta, "cos #theta"}; + const AxisSpec thnAxisNumPhi{configThnAxisNumPhi, "Number of phi meson"}; + + histos.add("SEMassUnlike", "SEMassUnlike", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisDeltaR, thnAxisCosTheta, thnAxisInvMassDeltaPhi, thnAxisNumPhi}); + histos.add("MEMassUnlike", "MEMassUnlike", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisDeltaR, thnAxisCosTheta, thnAxisInvMassDeltaPhi}); + } + + // get kstar + TLorentzVector trackSum, PartOneCMS, PartTwoCMS, trackRelK; + float getkstar(const TLorentzVector part1, + const TLorentzVector part2) + { + // const TLorentzVector trackSum = part1 + part2; + trackSum = part1 + part2; + const float beta = trackSum.Beta(); + const float betax = beta * std::cos(trackSum.Phi()) * std::sin(trackSum.Theta()); + const float betay = beta * std::sin(trackSum.Phi()) * std::sin(trackSum.Theta()); + const float betaz = beta * std::cos(trackSum.Theta()); + // TLorentzVector PartOneCMS(part1); + // TLorentzVector PartTwoCMS(part2); + PartOneCMS.SetXYZM(part1.Px(), part1.Py(), part1.Pz(), part1.M()); + PartTwoCMS.SetXYZM(part2.Px(), part2.Py(), part2.Pz(), part2.M()); + const ROOT::Math::Boost boostPRF = ROOT::Math::Boost(-betax, -betay, -betaz); + PartOneCMS = boostPRF(PartOneCMS); + PartTwoCMS = boostPRF(PartTwoCMS); + // const TLorentzVector trackRelK = PartOneCMS - PartTwoCMS; + trackRelK = PartOneCMS - PartTwoCMS; + return 0.5 * trackRelK.P(); + } + + float deepangle(const TLorentzVector candidate1, + const TLorentzVector candidate2) + { + double pt1, pt2, pz1, pz2, p1, p2, angle; + pt1 = candidate1.Pt(); + pt2 = candidate2.Pt(); + pz1 = candidate1.Pz(); + pz2 = candidate2.Pz(); + p1 = candidate1.P(); + p2 = candidate2.P(); + angle = TMath::ACos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); + return angle; + } + + // get cosTheta + TLorentzVector daughterCMS; + ROOT::Math::XYZVector threeVecDauCM, threeVecMother; + float getCosTheta(const TLorentzVector mother, + const TLorentzVector daughter) + { + threeVecMother = mother.Vect(); + const float beta = mother.Beta(); + const float betax = beta * std::cos(mother.Phi()) * std::sin(mother.Theta()); + const float betay = beta * std::sin(mother.Phi()) * std::sin(mother.Theta()); + const float betaz = beta * std::cos(mother.Theta()); + const ROOT::Math::Boost boostPRF = ROOT::Math::Boost(-betax, -betay, -betaz); + daughterCMS = boostPRF(daughter); + threeVecDauCM = daughterCMS.Vect(); + float cosThetaStar = TMath::Abs(threeVecDauCM.Dot(threeVecMother) / std::sqrt(threeVecMother.Mag2()) / std::sqrt(threeVecDauCM.Mag2())); + return cosThetaStar; + } + + bool selectionPID(float nsigmaTPC, float nsigmaTOF, int TOFHit, int PIDStrategy, float ptcand) + { + if (PIDStrategy == 0) { + if (ptcand < 0.5) { + if (nsigmaTPC > cutMinNsigmaTPC && nsigmaTPC < cutNsigmaTPC) { + return true; + } + } + if (ptcand >= 0.5) { + if (TOFHit != 1) { + if (ptcand >= 0.5 && ptcand < 0.6 && nsigmaTPC > -1.5 && nsigmaTPC < cutNsigmaTPC) { + return true; + } + if (ptcand >= 0.6 && ptcand < 0.7 && nsigmaTPC > -1.0 && nsigmaTPC < cutNsigmaTPC) { + return true; + } + if (ptcand >= 0.7 && ptcand < 0.8 && nsigmaTPC > -0.4 && nsigmaTPC < cutNsigmaTPC) { + return true; + } + if (ptcand >= 0.8 && ptcand < 1.0 && nsigmaTPC > -0.0 && nsigmaTPC < cutNsigmaTPC) { + return true; + } + if (ptcand >= 1.0 && ptcand < 1.8 && nsigmaTPC > -2.0 && nsigmaTPC < 2.0) { + return true; + } + if (ptcand >= 1.8 && ptcand < 2.0 && nsigmaTPC > -2.0 && nsigmaTPC < 1.5) { + return true; + } + if (ptcand >= 2.0 && nsigmaTPC > -2.0 && nsigmaTPC < 1.0) { + return true; + } + } + if (TOFHit == 1) { + if (TMath::Sqrt((nsigmaTPC * nsigmaTPC + nsigmaTOF * nsigmaTOF) / 2.0) < cutNsigmaTOF) { + return true; + } + } + } + } + if (PIDStrategy == 1) { + if (ptcand < 0.5) { + if (nsigmaTPC > cutMinNsigmaTPC && nsigmaTPC < cutNsigmaTPC) { + return true; + } + } + if (ptcand >= 0.5) { + if (TOFHit == 1) { + if (nsigmaTPC > cutMinNsigmaTPC && nsigmaTPC < cutNsigmaTPC && TMath::Abs(nsigmaTOF) < cutNsigmaTOF) { + return true; + } + } + } + } + if (PIDStrategy == 2) { + if (ptcand < 0.5) { + if (nsigmaTPC > cutMinNsigmaTPC && nsigmaTPC < cutNsigmaTPC) { + return true; + } + } + if (ptcand >= 0.5) { + if (TOFHit != 1 && ptcand < momTOFCut) { + if (ptcand >= 0.5 && ptcand < 0.6 && nsigmaTPC > -1.5 && nsigmaTPC < cutNsigmaTPC) { + return true; + } + if (ptcand >= 0.6 && ptcand < 0.7 && nsigmaTPC > -1.0 && nsigmaTPC < cutNsigmaTPC) { + return true; + } + if (ptcand >= 0.7 && ptcand < 0.8 && nsigmaTPC > -0.4 && nsigmaTPC < cutNsigmaTPC) { + return true; + } + if (ptcand >= 0.8 && ptcand < 1.0 && nsigmaTPC > -0.0 && nsigmaTPC < cutNsigmaTPC) { + return true; + } + if (ptcand >= 1.0 && ptcand < 1.8 && nsigmaTPC > -2.0 && nsigmaTPC < 2.0) { + return true; + } + if (ptcand >= 1.8 && ptcand < 2.0 && nsigmaTPC > -2.0 && nsigmaTPC < 1.5) { + return true; + } + if (ptcand >= 2.0 && nsigmaTPC > -2.0 && nsigmaTPC < 1.0) { + return true; + } + } + if (TOFHit == 1) { + if (TMath::Sqrt((nsigmaTPC * nsigmaTPC + nsigmaTOF * nsigmaTOF) / 2.0) < cutNsigmaTOF) { + return true; + } + } + } + } + if (PIDStrategy == 3) { + if (ptcand < 0.5) { + if (nsigmaTPC > cutMinNsigmaTPC && nsigmaTPC < cutNsigmaTPC) { + return true; + } + } + if (ptcand >= 0.5) { + if (TOFHit != 1) { + if (nsigmaTPC > cutMinNsigmaTPC && nsigmaTPC < cutNsigmaTPC) { + return true; + } + } + if (TOFHit == 1) { + if (TMath::Sqrt((nsigmaTPC * nsigmaTPC + nsigmaTOF * nsigmaTOF) / 2.0) < cutNsigmaTOF) { + return true; + } + } + } + } + return false; + } + + TLorentzVector exotic, Phid1, Phid2; + // TLorentzVector exoticRot, Phid1Rot; + + void process(aod::RedPhiEvents::iterator const& collision, aod::PhiTracks const& phitracks) + { + if (additionalEvsel && (collision.numPos() < 2 || collision.numNeg() < 2)) { + return; + } + int phimult = 0; + for (auto phitrackd1 : phitracks) { + if (phitrackd1.phiMass() < minPhiMass || phitrackd1.phiMass() > maxPhiMass) { + continue; + } + auto kaonplusd1pt = TMath::Sqrt(phitrackd1.phid1Px() * phitrackd1.phid1Px() + phitrackd1.phid1Py() * phitrackd1.phid1Py()); + auto kaonminusd1pt = TMath::Sqrt(phitrackd1.phid2Px() * phitrackd1.phid2Px() + phitrackd1.phid2Py() * phitrackd1.phid2Py()); + if (kaonplusd1pt > maxKaonPt) { + continue; + } + if (kaonminusd1pt > maxKaonPt) { + continue; + } + if (!selectionPID(phitrackd1.phid1TPC(), phitrackd1.phid1TOF(), phitrackd1.phid1TOFHit(), strategyPID1, kaonplusd1pt)) { + continue; + } + if (!selectionPID(phitrackd1.phid2TPC(), phitrackd1.phid2TOF(), phitrackd1.phid2TOFHit(), strategyPID1, kaonminusd1pt)) { + continue; + } + phimult = phimult + 1; + } + for (auto phitrackd1 : phitracks) { + if (phitrackd1.phiMass() < minPhiMass || phitrackd1.phiMass() > maxPhiMass) { + continue; + } + auto kaonplusd1pt = TMath::Sqrt(phitrackd1.phid1Px() * phitrackd1.phid1Px() + phitrackd1.phid1Py() * phitrackd1.phid1Py()); + auto kaonminusd1pt = TMath::Sqrt(phitrackd1.phid2Px() * phitrackd1.phid2Px() + phitrackd1.phid2Py() * phitrackd1.phid2Py()); + if (kaonplusd1pt > maxKaonPt) { + continue; + } + if (kaonminusd1pt > maxKaonPt) { + continue; + } + if (!selectionPID(phitrackd1.phid1TPC(), phitrackd1.phid1TOF(), phitrackd1.phid1TOFHit(), strategyPID1, kaonplusd1pt)) { + continue; + } + histos.fill(HIST("hnsigmaTPCTOFKaon"), phitrackd1.phid1TPC(), phitrackd1.phid1TOF(), kaonplusd1pt); + histos.fill(HIST("hnsigmaTPCKaonPlus"), phitrackd1.phid1TPC(), kaonplusd1pt); + if (!selectionPID(phitrackd1.phid2TPC(), phitrackd1.phid2TOF(), phitrackd1.phid2TOFHit(), strategyPID1, kaonminusd1pt)) { + continue; + } + histos.fill(HIST("hnsigmaTPCKaonMinus"), phitrackd1.phid2TPC(), kaonminusd1pt); + histos.fill(HIST("hPhiMass"), Phid1.M(), Phid1.Pt()); + auto phid1id = phitrackd1.index(); + Phid1.SetXYZM(phitrackd1.phiPx(), phitrackd1.phiPy(), phitrackd1.phiPz(), phitrackd1.phiMass()); + for (auto phitrackd2 : phitracks) { + auto phid2id = phitrackd2.index(); + if (phid2id <= phid1id) { + continue; + } + if (phitrackd2.phiMass() < minPhiMass || phitrackd2.phiMass() > maxPhiMass) { + continue; + } + auto kaonplusd2pt = TMath::Sqrt(phitrackd2.phid1Px() * phitrackd2.phid1Px() + phitrackd2.phid1Py() * phitrackd2.phid1Py()); + auto kaonminusd2pt = TMath::Sqrt(phitrackd2.phid2Px() * phitrackd2.phid2Px() + phitrackd2.phid2Py() * phitrackd2.phid2Py()); + if (kaonplusd2pt > maxKaonPt) { + continue; + } + if (kaonminusd2pt > maxKaonPt) { + continue; + } + if (!selectionPID(phitrackd2.phid1TPC(), phitrackd2.phid1TOF(), phitrackd2.phid1TOFHit(), strategyPID2, kaonplusd2pt)) { + continue; + } + if (!selectionPID(phitrackd2.phid2TPC(), phitrackd2.phid2TOF(), phitrackd2.phid2TOFHit(), strategyPID2, kaonminusd2pt)) { + continue; + } + // if (phitrackd1.phid1Index() == phitrackd2.phid1Index()) { + // continue; + // } + // if (phitrackd1.phid2Index() == phitrackd2.phid2Index()) { + // continue; + // } + if (phitrackd1.phid1Index() == phitrackd2.phid1Index() && phitrackd1.phid2Index() == phitrackd2.phid2Index()) { + continue; + } + Phid2.SetXYZM(phitrackd2.phiPx(), phitrackd2.phiPy(), phitrackd2.phiPz(), phitrackd2.phiMass()); + exotic = Phid1 + Phid2; + if (exotic.M() < minExoticMass || exotic.M() > maxExoticMass) { + continue; + } + // auto cosThetaStar = getCosTheta(exotic, Phid1); + // auto kstar = getkstar(Phid1, Phid2); + auto deltaR = TMath::Sqrt(TMath::Power(Phid1.Phi() - Phid2.Phi(), 2.0) + TMath::Power(Phid1.Eta() - Phid2.Eta(), 2.0)); + auto costheta = (Phid1.Px() * Phid2.Px() + Phid1.Py() * Phid2.Py() + Phid1.Pz() * Phid2.Pz()) / (Phid1.P() * Phid2.P()); + auto deltam = TMath::Sqrt(TMath::Power(Phid1.M() - 1.0192, 2.0) + TMath::Power(Phid2.M() - 1.0192, 2.0)); + histos.fill(HIST("hPhiMass2"), Phid1.M(), Phid2.M()); + if (!isDeep) { + histos.fill(HIST("SEMassUnlike"), exotic.M(), exotic.Pt(), deltaR, costheta, deltam, phimult); + } + if (isDeep) { + histos.fill(HIST("SEMassUnlike"), exotic.M(), exotic.Pt(), deltaR, deepangle(Phid1, Phid2), deltam, phimult); + } + } + } + } + + SliceCache cache; + using BinningTypeVertexContributor = ColumnBinningPolicy; + void processMixedEvent(aod::RedPhiEvents& collisions, aod::PhiTracks& phitracks) + { + auto tracksTuple = std::make_tuple(phitracks); + BinningTypeVertexContributor binningOnPositions{{CfgVtxBins, CfgMultBins}, true}; + SameKindPair pair{binningOnPositions, nEvtMixing, -1, collisions, tracksTuple, &cache}; + + for (auto& [collision1, tracks1, collision2, tracks2] : pair) { + if (collision1.index() == collision2.index()) { + continue; + } + for (auto& [phitrackd1, phitrackd2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (phitrackd1.phiMass() < minPhiMass || phitrackd1.phiMass() > maxPhiMass) { + continue; + } + if (phitrackd2.phiMass() < minPhiMass || phitrackd2.phiMass() > maxPhiMass) { + continue; + } + auto kaonplusd1pt = TMath::Sqrt(phitrackd1.phid1Px() * phitrackd1.phid1Px() + phitrackd1.phid1Py() * phitrackd1.phid1Py()); + auto kaonminusd1pt = TMath::Sqrt(phitrackd1.phid2Px() * phitrackd1.phid2Px() + phitrackd1.phid2Py() * phitrackd1.phid2Py()); + auto kaonplusd2pt = TMath::Sqrt(phitrackd2.phid1Px() * phitrackd2.phid1Px() + phitrackd2.phid1Py() * phitrackd2.phid1Py()); + auto kaonminusd2pt = TMath::Sqrt(phitrackd2.phid2Px() * phitrackd2.phid2Px() + phitrackd2.phid2Py() * phitrackd2.phid2Py()); + if (kaonplusd1pt > maxKaonPt) { + continue; + } + if (kaonminusd1pt > maxKaonPt) { + continue; + } + if (kaonplusd2pt > maxKaonPt) { + continue; + } + if (kaonminusd2pt > maxKaonPt) { + continue; + } + if (!selectionPID(phitrackd1.phid1TPC(), phitrackd1.phid1TOF(), phitrackd1.phid1TOFHit(), strategyPID1, kaonplusd1pt)) { + continue; + } + if (!selectionPID(phitrackd1.phid2TPC(), phitrackd1.phid2TOF(), phitrackd1.phid2TOFHit(), strategyPID1, kaonminusd1pt)) { + continue; + } + Phid1.SetXYZM(phitrackd1.phiPx(), phitrackd1.phiPy(), phitrackd1.phiPz(), phitrackd1.phiMass()); + if (!selectionPID(phitrackd2.phid1TPC(), phitrackd2.phid1TOF(), phitrackd2.phid1TOFHit(), strategyPID2, kaonplusd2pt)) { + continue; + } + if (!selectionPID(phitrackd2.phid2TPC(), phitrackd2.phid2TOF(), phitrackd2.phid2TOFHit(), strategyPID2, kaonminusd2pt)) { + continue; + } + Phid2.SetXYZM(phitrackd2.phiPx(), phitrackd2.phiPy(), phitrackd2.phiPz(), phitrackd2.phiMass()); + exotic = Phid1 + Phid2; + auto deltaR = TMath::Sqrt(TMath::Power(Phid1.Phi() - Phid2.Phi(), 2.0) + TMath::Power(Phid1.Eta() - Phid2.Eta(), 2.0)); + auto costheta = (Phid1.Px() * Phid2.Px() + Phid1.Py() * Phid2.Py() + Phid1.Pz() * Phid2.Pz()) / (Phid1.P() * Phid2.P()); + auto deltam = TMath::Sqrt(TMath::Power(Phid1.M() - 1.0192, 2.0) + TMath::Power(Phid2.M() - 1.0192, 2.0)); + if (!isDeep) { + histos.fill(HIST("MEMassUnlike"), exotic.M(), exotic.Pt(), deltaR, costheta, deltam); + } + if (isDeep) { + histos.fill(HIST("MEMassUnlike"), exotic.M(), exotic.Pt(), deltaR, deepangle(Phid1, Phid2), deltam); + } + } + } + } + PROCESS_SWITCH(doublephimeson, processMixedEvent, "Process EventMixing for combinatorial background", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/Resonances/f0980analysis.cxx b/PWGLF/Tasks/Resonances/f0980analysis.cxx index 781fb837f1c..01b059a7f29 100644 --- a/PWGLF/Tasks/Resonances/f0980analysis.cxx +++ b/PWGLF/Tasks/Resonances/f0980analysis.cxx @@ -11,8 +11,10 @@ /// \author Junlee Kim (jikim1290@gmail.com) +#include #include #include "TVector2.h" +#include #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" @@ -32,8 +34,6 @@ using namespace o2::constants::physics; struct f0980analysis { SliceCache cache; - Preslice perRCol = aod::resodaughter::resoCollisionId; - Preslice perCollision = aod::track::collisionId; HistogramRegistry histos{ "histos", {}, @@ -43,22 +43,17 @@ struct f0980analysis { "Minimum transverse momentum for charged track"}; Configurable cfgMaxEta{"cfgMaxEta", 0.8, "Maximum pseudorapidiy for charged track"}; - Configurable cfgMinDCArToPVcut{"cfgMinDCArToPVcut", -0.5, - "Minimum transverse DCA"}; Configurable cfgMaxDCArToPVcut{"cfgMaxDCArToPVcut", 0.5, "Maximum transverse DCA"}; - Configurable cfgMinDCAzToPVcut{"cfgMinDCAzToPVcut", -2.0, - "Minimum longitudinal DCA"}; Configurable cfgMaxDCAzToPVcut{"cfgMaxDCAzToPVcut", 2.0, "Maximum longitudinal DCA"}; - Configurable cfgMaxTPCStandalone{"cfgMaxTPCStandalone", 2.0, - "Maximum TPC PID as standalone"}; Configurable cfgMaxTPC{"cfgMaxTPC", 5.0, "Maximum TPC PID with TOF"}; Configurable cfgMaxTOF{"cfgMaxTOF", 3.0, "Maximum TOF PID with TPC"}; Configurable cfgMinRap{"cfgMinRap", -0.5, "Minimum rapidity for pair"}; Configurable cfgMaxRap{"cfgMaxRap", 0.5, "Maximum rapidity for pair"}; - Configurable cfgMinTPCncr{"cfgMinTPCncr", 70, "minimum TPC cluster"}; + Configurable cfgFindRT{"cfgFindRT", false, "boolean for RT analysis"}; + // Track selection Configurable cfgPrimaryTrack{ "cfgPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz @@ -75,20 +70,28 @@ struct f0980analysis { Configurable cfgPVContributor{ "cfgPVContributor", true, "PV contributor track selection"}; // PV Contriuibutor - Configurable cfgUseTOF{ - "cfgUseTOF", false, - "Flag for the usage of TOF for PID"}; - + Configurable cfgGlobalTrack{ + "cfgGlobalTrack", false, + "Global track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgTPCcluster{"cfgTPCcluster", 0, "Number of TPC cluster"}; + Configurable cfgUseTPCRefit{"cfgUseTPCRefit", false, "Require TPC Refit"}; + Configurable cfgUseITSRefit{"cfgUseITSRefit", false, "Require ITS Refit"}; + Configurable cfgHasTOF{"cfgHasTOF", false, "Require TOF"}; + + // PID + Configurable cMaxTOFnSigmaPion{"cMaxTOFnSigmaPion", 3.0, "TOF nSigma cut for Pion"}; // TOF + Configurable cMaxTPCnSigmaPion{"cMaxTPCnSigmaPion", 3.0, "TPC nSigma cut for Pion"}; // TPC + Configurable nsigmaCutCombinedPion{"nsigmaCutCombinedPion", -999, "Combined nSigma cut for Pion"}; + Configurable SelectType{"SelectType", 0, "PID selection type"}; + + // Axis + ConfigurableAxis massAxis{"massAxis", {400, 0.2, 2.2}, "Invariant mass axis"}; + ConfigurableAxis ptAxis{"ptAxis", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.8, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 10.0, 13.0, 20.0}, "Transverse momentum Binning"}; + ConfigurableAxis centAxis{"centAxis", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0, 65.0, 70.0, 75.0, 80.0, 95.0, 100.0, 105.0, 110.0}, "Centrality Binning"}; void init(o2::framework::InitContext&) { - std::vector ptBinning = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.8, - 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, - 5.0, 6.0, 7.0, 8.0, 10.0, 13.0, 20.0}; std::vector lptBinning = {0, 5.0, 13.0, 20.0, 50.0, 1000.0}; - AxisSpec centAxis = {22, 0, 110}; - AxisSpec ptAxis = {ptBinning}; - AxisSpec massAxis = {400, 0.2, 2.2}; AxisSpec RTAxis = {3, 0, 3}; AxisSpec LptAxis = {lptBinning}; // Minimum leading hadron pT selection @@ -99,13 +102,14 @@ struct f0980analysis { AxisSpec EPqaAxis = {200, -constants::math::PI, constants::math::PI}; AxisSpec EPresAxis = {200, -2, 2}; - histos.add("hInvMass_f0980_US", "unlike invariant mass", - {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis, RTAxis, LptAxis}}); - histos.add("hInvMass_f0980_LSpp", "++ invariant mass", - {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis, RTAxis, LptAxis}}); - histos.add("hInvMass_f0980_LSmm", "-- invariant mass", - {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis, RTAxis, LptAxis}}); - + if (cfgFindRT) { + histos.add("hInvMass_f0980_US", "unlike invariant mass", + {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis, RTAxis, LptAxis}}); + histos.add("hInvMass_f0980_LSpp", "++ invariant mass", + {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis, RTAxis, LptAxis}}); + histos.add("hInvMass_f0980_LSmm", "-- invariant mass", + {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis, RTAxis, LptAxis}}); + } histos.add("hInvMass_f0980_US_EPA", "unlike invariant mass", {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis, EPAxis}}); histos.add("hInvMass_f0980_LSpp_EPA", "++ invariant mass", @@ -152,19 +156,29 @@ struct f0980analysis { template bool SelTrack(const TrackType track) { - if (track.pt() < cfgMinPt) + if (std::abs(track.pt()) < cfgMinPt) return false; if (std::fabs(track.eta()) > cfgMaxEta) return false; - if (track.dcaXY() < cfgMinDCArToPVcut || track.dcaXY() > cfgMaxDCArToPVcut) + if (std::abs(track.dcaXY()) > cfgMaxDCArToPVcut) + return false; + if (std::abs(track.dcaZ()) > cfgMaxDCAzToPVcut) + return false; + if (track.tpcNClsFound() < cfgTPCcluster) return false; - if (track.dcaZ() < cfgMinDCAzToPVcut || track.dcaZ() > cfgMaxDCAzToPVcut) + if (cfgHasTOF && !track.hasTOF()) + return false; + if (cfgUseITSRefit && !track.passedITSRefit()) + return false; + if (cfgUseTPCRefit && !track.passedTPCRefit()) + return false; + if (cfgPVContributor && !track.isPVContributor()) return false; if (cfgPrimaryTrack && !track.isPrimaryTrack()) return false; if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) return false; - if (cfgPVContributor && !track.isPVContributor()) + if (cfgGlobalTrack && !track.isGlobalTrack()) return false; return true; @@ -173,15 +187,17 @@ struct f0980analysis { template bool SelPion(const TrackType track) { - if (track.hasTOF() || !cfgUseTOF) { - if (std::fabs(track.tpcNSigmaPi()) > cfgMaxTPCStandalone) { + if (SelectType == 0) { + if (std::fabs(track.tpcNSigmaPi()) >= cMaxTPCnSigmaPion || std::fabs(track.tofNSigmaPi()) >= cMaxTOFnSigmaPion) return false; - } - } else { - if (std::fabs(track.tpcNSigmaPi()) > cfgMaxTPC || - std::fabs(track.tofNSigmaPi()) > cfgMaxTOF) { + } + if (SelectType == 1) { + if (std::fabs(track.tpcNSigmaPi()) >= cMaxTPCnSigmaPion) + return false; + } + if (SelectType == 2) { + if (track.tpcNSigmaPi() * track.tpcNSigmaPi() + track.tofNSigmaPi() * track.tofNSigmaPi() >= nsigmaCutCombinedPion * nsigmaCutCombinedPion) return false; - } } return true; } @@ -193,12 +209,15 @@ struct f0980analysis { double LHpt = 0.; double LHphi = 0.; double relPhi = 0.; - for (auto& trk : dTracks) { - if (trk.pt() > LHpt) { - LHpt = trk.pt(); - LHphi = trk.phi(); + if (cfgFindRT) { + for (auto& trk : dTracks) { + if (trk.pt() > LHpt) { + LHpt = trk.pt(); + LHphi = trk.phi(); + } } } + histos.fill(HIST("QA/EPhist"), collision.cent(), collision.evtPl()); histos.fill(HIST("QA/hEPResAB"), collision.cent(), collision.evtPlResAB()); histos.fill(HIST("QA/hEPResAC"), collision.cent(), collision.evtPlResBC()); @@ -207,7 +226,7 @@ struct f0980analysis { TLorentzVector Pion1, Pion2, Reco; for (auto& [trk1, trk2] : - combinations(CombinationsUpperIndexPolicy(dTracks, dTracks))) { + combinations(CombinationsStrictlyUpperIndexPolicy(dTracks, dTracks))) { if (trk1.index() == trk2.index()) { if (!SelTrack(trk1)) continue; @@ -235,8 +254,10 @@ struct f0980analysis { } if (trk1.sign() * trk2.sign() < 0) { - histos.fill(HIST("hInvMass_f0980_US"), Reco.M(), Reco.Pt(), - collision.cent(), RTIndex(Reco.Phi(), LHphi), LHpt); + if (cfgFindRT) { + histos.fill(HIST("hInvMass_f0980_US"), Reco.M(), Reco.Pt(), + collision.cent(), RTIndex(Reco.Phi(), LHphi), LHpt); + } histos.fill(HIST("hInvMass_f0980_US_EPA"), Reco.M(), Reco.Pt(), collision.cent(), relPhi); if constexpr (IsMC) { @@ -250,20 +271,24 @@ struct f0980analysis { collision.cent()); } } else if (trk1.sign() > 0 && trk2.sign() > 0) { - histos.fill(HIST("hInvMass_f0980_LSpp"), Reco.M(), Reco.Pt(), - collision.cent(), RTIndex(Reco.Phi(), LHphi), LHpt); + if (cfgFindRT) { + histos.fill(HIST("hInvMass_f0980_LSpp"), Reco.M(), Reco.Pt(), + collision.cent(), RTIndex(Reco.Phi(), LHphi), LHpt); + } histos.fill(HIST("hInvMass_f0980_LSpp_EPA"), Reco.M(), Reco.Pt(), collision.cent(), relPhi); } else if (trk1.sign() < 0 && trk2.sign() < 0) { - histos.fill(HIST("hInvMass_f0980_LSmm"), Reco.M(), Reco.Pt(), - collision.cent(), RTIndex(Reco.Phi(), LHphi), LHpt); + if (cfgFindRT) { + histos.fill(HIST("hInvMass_f0980_LSmm"), Reco.M(), Reco.Pt(), + collision.cent(), RTIndex(Reco.Phi(), LHphi), LHpt); + } histos.fill(HIST("hInvMass_f0980_LSmm_EPA"), Reco.M(), Reco.Pt(), collision.cent(), relPhi); } } } - void processData(aod::ResoCollision& collision, + void processData(soa::Join::iterator const& collision, aod::ResoTracks const& resotracks) { fillHistograms(collision, resotracks); @@ -271,7 +296,7 @@ struct f0980analysis { PROCESS_SWITCH(f0980analysis, processData, "Process Event for data", true); void processMCLight( - aod::ResoCollision& collision, + soa::Join::iterator const& collision, soa::Join const& resotracks) { fillHistograms(collision, resotracks); diff --git a/PWGLF/Tasks/Resonances/f0980pbpbanalysis.cxx b/PWGLF/Tasks/Resonances/f0980pbpbanalysis.cxx new file mode 100644 index 00000000000..9bc3c7d40f9 --- /dev/null +++ b/PWGLF/Tasks/Resonances/f0980pbpbanalysis.cxx @@ -0,0 +1,556 @@ +// 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 f0980pbpbanalysis.cxx +/// \brief f0980 resonance analysis in PbPb collisions +/// \author Junlee Kim (jikim1290@gmail.com) + +#include +#include +#include +#include +#include +#include +// #include +#include + +#include "TLorentzVector.h" +#include "TRandom3.h" +#include "TF1.h" +#include "TVector2.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/StaticFor.h" + +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Qvectors.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" + +#include "CommonConstants/PhysicsConstants.h" + +#include "ReconstructionDataFormats/Track.h" + +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" + +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" + +// from phi +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "Common/DataModel/PIDResponseITS.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; + +struct F0980pbpbanalysis { + HistogramRegistry histos{ + "histos", + {}, + OutputObjHandlingPolicy::AnalysisObject}; + + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + + Configurable cfgURL{"cfgURL", "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; + Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "Latest acceptable timestamp of creation for the object"}; + + Configurable cfgCutVertex{"cfgCutVertex", 10.0, "PV selection"}; + Configurable cfgQvecSel{"cfgQvecSel", true, "Reject events when no QVector"}; + Configurable cfgOccupancySel{"cfgOccupancySel", false, "Occupancy selection"}; + Configurable cfgMaxOccupancy{"cfgMaxOccupancy", 999999, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable cfgMinOccupancy{"cfgMinOccupancy", -100, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable cfgNCollinTR{"cfgNCollinTR", false, "Additional selection for the number of coll in time range"}; + Configurable cfgPVSel{"cfgPVSel", false, "Additional PV selection flag for syst"}; + Configurable cfgPV{"cfgPV", 8.0, "Additional PV selection range for syst"}; + + Configurable cfgCentSel{"cfgCentSel", 80., "Centrality selection"}; + Configurable cfgCentEst{"cfgCentEst", 1, "Centrality estimator, 1: FT0C, 2: FT0M"}; + + Configurable cfgMinPt{"cfgMinPt", 0.15, "Minimum transverse momentum for charged track"}; + Configurable cfgMaxEta{"cfgMaxEta", 0.8, "Maximum pseudorapidiy for charged track"}; + Configurable cfgMaxDCArToPVcut{"cfgMaxDCArToPVcut", 0.5, "Maximum transverse DCA"}; + Configurable cfgMaxDCAzToPVcut{"cfgMaxDCAzToPVcut", 2.0, "Maximum longitudinal DCA"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; + Configurable cfgRatioTPCRowsOverFindableCls{"cfgRatioTPCRowsOverFindableCls", 0.8, "TPC Crossed Rows to Findable Clusters"}; + + Configurable cfgMinRap{"cfgMinRap", -0.5, "Minimum rapidity for pair"}; + Configurable cfgMaxRap{"cfgMaxRap", 0.5, "Maximum rapidity for pair"}; + + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; + Configurable cfgPVContributor{"cfgPVContributor", true, "PV contributor track selection"}; + + Configurable cMaxTOFnSigmaPion{"cMaxTOFnSigmaPion", 3.0, "TOF nSigma cut for Pion"}; // TOF + Configurable cMaxTPCnSigmaPion{"cMaxTPCnSigmaPion", 5.0, "TPC nSigma cut for Pion"}; // TPC + Configurable cMaxTPCnSigmaPionS{"cMaxTPCnSigmaPionS", 3.0, "TPC nSigma cut for Pion as a standalone"}; + Configurable cfgUSETOF{"cfgUSETOF", false, "TPC usage"}; + Configurable cfgSelectPID{"cfgSelectPID", 0, "PID selection type"}; + Configurable cfgSelectPtl{"cfgSelectPtl", 0, "Particle selection type"}; + + Configurable cfgnMods{"cfgnMods", 1, "The number of modulations of interest starting from 2"}; + Configurable cfgNQvec{"cfgNQvec", 7, "The number of total Qvectors for looping over the task"}; + + Configurable cfgQvecDetName{"cfgQvecDetName", "FT0C", "The name of detector to be analyzed"}; + Configurable cfgQvecRefAName{"cfgQvecRefAName", "TPCpos", "The name of detector for reference A"}; + Configurable cfgQvecRefBName{"cfgQvecRefBName", "TPCneg", "The name of detector for reference B"}; + + Configurable cfgRotBkg{"cfgRotBkg", true, "flag to construct rotational backgrounds"}; + Configurable cfgNRotBkg{"cfgNRotBkg", 10, "the number of rotational backgrounds"}; + + // for phi test + Configurable cfgTPCFinableClsSel{"cfgTPCFinableClsSel", true, "TPC Crossed Rows to Findable Clusters selection flag"}; + Configurable cfgITSClsSel{"cfgITSClsSel", false, "ITS cluster selection flag"}; + Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; + Configurable cfgpTDepPID{"cfgpTDepPID", false, "pT dependent PID"}; + Configurable cfgBetaCutSel{"cfgBetaCutSel", false, "TOF beta cut selection flag"}; + Configurable cfgCutTOFBeta{"cfgCutTOFBeta", 0.0, "cut TOF beta"}; + Configurable isDeepAngle{"isDeepAngle", true, "Deep Angle cut"}; + Configurable cfgDeepAngle{"cfgDeepAngle", 0.04, "Deep Angle cut value"}; + + ConfigurableAxis massAxis{"massAxis", {400, 0.2, 2.2}, "Invariant mass axis"}; + ConfigurableAxis ptAxis{"ptAxis", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.8, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 10.0, 13.0, 20.0}, "Transverse momentum Binning"}; + ConfigurableAxis centAxis{"centAxis", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 100}, "Centrality interval"}; + + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + + int detId; + int refAId; + int refBId; + + int qVecDetInd; + int qVecRefAInd; + int qVecRefBInd; + + float centrality; + + double angle; + double relPhi; + double relPhiRot; + + // double massPi = o2::constants::physics::MassPionCharged; + double massPtl; + + enum CentEstList { + FT0C = 0, + FT0M = 1, + }; + + enum PIDList { + PIDRun3 = 0, + PIDRun2 = 1, + PIDTest = 2, + }; + + enum PtlList { + PtlPion = 0, + PtlKaon = 1, + }; + + TRandom* rn = new TRandom(); + // float theta2; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter acceptanceFilter = (nabs(aod::track::eta) < cfgMaxEta && nabs(aod::track::pt) > cfgMinPt); + Filter cutDCAFilter = (nabs(aod::track::dcaXY) < cfgMaxDCArToPVcut) && (nabs(aod::track::dcaZ) < cfgMaxDCAzToPVcut); + // from phi + // Filter centralityFilter = nabs(aod::cent::centFT0C) < cfgCentSel; + // Filter PIDcutFilter = nabs(aod::pidtpc::tpcNSigmaKa) < cMaxTPCnSigmaPion; + // Filter PIDcutFilter = nabs(aod::pidTPCFullKa::tpcNSigmaKa) < cMaxTPCnSigmaPion; + + using EventCandidates = soa::Filtered>; + // aod::EPCalibrationTables 추가됨 + using TrackCandidates = soa::Filtered>; + // aod::pidTOFbeta 추가됨 + + template + int getDetId(const T& name) + { + if (name.value == "FT0C") { + return 0; + } else if (name.value == "FT0A") { + return 1; + } else if (name.value == "FT0M") { + return 2; + } else if (name.value == "FV0A") { + return 3; + } else if (name.value == "TPCpos") { + return 4; + } else if (name.value == "TPCneg") { + return 5; + } else { + return 0; + } + } + + template + bool eventSelected(TCollision collision) + { + if (!collision.sel8()) { + return 0; + } + + if (cfgCentSel < centrality) { + return 0; + } + /* + auto multNTracksPV = collision.multNTracksPV(); + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) { + return 0; + } + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) { + return 0; + } + */ + if (!collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return 0; + } + if (!collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return 0; + } + if (cfgQvecSel && (collision.qvecAmp()[detId] < 1e-4 || collision.qvecAmp()[refAId] < 1e-4 || collision.qvecAmp()[refBId] < 1e-4)) { + return 0; + } + if (cfgOccupancySel && (collision.trackOccupancyInTimeRange() > cfgMaxOccupancy || collision.trackOccupancyInTimeRange() < cfgMinOccupancy)) { + return 0; + } + if (cfgNCollinTR && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return 0; + } + if (cfgPVSel && std::abs(collision.posZ()) > cfgPV) { + return 0; + } + return 1; + } // event selection + + template + bool trackSelected(const TrackType track) + { + if (std::abs(track.pt()) < cfgMinPt) { + return 0; + } + if (std::fabs(track.eta()) > cfgMaxEta) { + return 0; + } + if (std::fabs(track.dcaXY()) > cfgMaxDCArToPVcut) { + return 0; + } + if (std::fabs(track.dcaZ()) > cfgMaxDCAzToPVcut) { + return 0; + } + if (cfgPVContributor && !track.isPVContributor()) { + return 0; + } + if (cfgPrimaryTrack && !track.isPrimaryTrack()) { + return 0; + } + if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) { + return 0; + } + if (track.tpcNClsFound() < cfgTPCcluster) { + return 0; + } + if (cfgTPCFinableClsSel && track.tpcCrossedRowsOverFindableCls() < cfgRatioTPCRowsOverFindableCls) { + return 0; + } + if (cfgITSClsSel && track.itsNCls() < cfgITScluster) { + return 0; + } + return 1; + } + + template + bool selectionPID(const TrackType track) + { + if (cfgSelectPID == PIDList::PIDRun3) { + if (cfgUSETOF) { + if (std::fabs(track.tofNSigmaPi()) > cMaxTOFnSigmaPion) { + return 0; + } + if (std::fabs(track.tpcNSigmaPi()) > cMaxTPCnSigmaPion) { + return 0; + } + } + if (std::fabs(track.tpcNSigmaPi()) > cMaxTPCnSigmaPionS) { + return 0; + } + } else if (cfgSelectPID == PIDList::PIDRun2) { + if (cfgUSETOF) { + if (track.hasTOF()) { + if (std::fabs(track.tofNSigmaPi()) > cMaxTOFnSigmaPion) { + return 0; + } + if (std::fabs(track.tpcNSigmaPi()) > cMaxTPCnSigmaPion) { + return 0; + } + } else { + if (std::fabs(track.tpcNSigmaPi()) > cMaxTPCnSigmaPionS) { + return 0; + } + } + } else { + if (std::fabs(track.tpcNSigmaPi()) > cMaxTPCnSigmaPionS) { + return 0; + } + } + } else if (cfgSelectPID == PIDList::PIDTest) { + if (track.hasTOF()) { + if (std::fabs(getTofNSigma(track)) > cMaxTOFnSigmaPion) { + return 0; + } + if (std::fabs(getTpcNSigma(track)) > cMaxTPCnSigmaPion) { + return 0; + } + } else { + if (std::fabs(getTpcNSigma(track)) > cMaxTPCnSigmaPionS) { + return 0; + } + } + } + return 1; + } + + template + bool selectionPair(const TrackType1 track1, const TrackType2 track2) + { + double pt1, pt2, pz1, pz2, p1, p2, angle; + pt1 = track1.pt(); + pt2 = track2.pt(); + pz1 = track1.pz(); + pz2 = track2.pz(); + p1 = track1.p(); + p2 = track2.p(); + angle = std::acos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); + if (isDeepAngle && angle < cfgDeepAngle) { + return 0; + } + return 1; + } + + template + float getTpcNSigma(const TrackType track) + { + if (cfgSelectPtl == PtlList::PtlPion) { + return track.tpcNSigmaPi(); + } else { + return track.tpcNSigmaKa(); + } + } + + template + float getTofNSigma(const TrackType track) + { + if (cfgSelectPtl == PtlList::PtlPion) { + return track.tofNSigmaPi(); + } else { + return track.tofNSigmaKa(); + } + } + + template + void fillHistograms(const CollisionType& collision, + const TracksType& dTracks, int nmode) + { + qVecDetInd = detId * 4 + 3 + (nmode - 2) * cfgNQvec * 4; + qVecRefAInd = refAId * 4 + 3 + (nmode - 2) * cfgNQvec * 4; + qVecRefBInd = refBId * 4 + 3 + (nmode - 2) * cfgNQvec * 4; + + double eventPlaneDet = std::atan2(collision.qvecIm()[qVecDetInd], collision.qvecRe()[qVecDetInd]) / static_cast(nmode); + double eventPlaneRefA = std::atan2(collision.qvecIm()[qVecRefAInd], collision.qvecRe()[qVecRefAInd]) / static_cast(nmode); + double eventPlaneRefB = std::atan2(collision.qvecIm()[qVecRefBInd], collision.qvecRe()[qVecRefBInd]) / static_cast(nmode); + + histos.fill(HIST("QA/EPhist"), centrality, eventPlaneDet); + histos.fill(HIST("QA/EPResAB"), centrality, std::cos(static_cast(nmode) * (eventPlaneDet - eventPlaneRefA))); + histos.fill(HIST("QA/EPResAC"), centrality, std::cos(static_cast(nmode) * (eventPlaneDet - eventPlaneRefB))); + histos.fill(HIST("QA/EPResBC"), centrality, std::cos(static_cast(nmode) * (eventPlaneRefA - eventPlaneRefB))); + + TLorentzVector pion1, pion2, pion2Rot, reco, recoRot; + for (const auto& trk1 : dTracks) { + if (!trackSelected(trk1)) { + continue; + } + + if (!selectionPID(trk1)) { + continue; + } + + histos.fill(HIST("QA/Nsigma_TPC"), trk1.pt(), getTpcNSigma(trk1)); + histos.fill(HIST("QA/Nsigma_TOF"), trk1.pt(), getTofNSigma(trk1)); + histos.fill(HIST("QA/TPC_TOF"), getTpcNSigma(trk1), getTofNSigma(trk1)); + + for (const auto& trk2 : dTracks) { + if (!trackSelected(trk2)) { + continue; + } + + // PID + if (!selectionPID(trk2)) { + continue; + } + + if (trk1.index() == trk2.index()) { + histos.fill(HIST("QA/Nsigma_TPC_selected"), trk1.pt(), getTpcNSigma(trk2)); + histos.fill(HIST("QA/Nsigma_TOF_selected"), trk1.pt(), getTofNSigma(trk2)); + histos.fill(HIST("QA/TPC_TOF_selected"), getTpcNSigma(trk2), getTofNSigma(trk2)); + } + + if (cfgSelectPID == PIDList::PIDTest && trk2.globalIndex() == trk1.globalIndex()) { + continue; + } + + if (cfgSelectPID == PIDList::PIDTest && !selectionPair(trk1, trk2)) { + continue; + } + + pion1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massPtl); + pion2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massPtl); + reco = pion1 + pion2; + + if (reco.Rapidity() > cfgMaxRap || reco.Rapidity() < cfgMinRap) { + continue; + } + + relPhi = TVector2::Phi_0_2pi((reco.Phi() - eventPlaneDet) * static_cast(nmode)); + + if (trk1.sign() * trk2.sign() < 0) { + histos.fill(HIST("hInvMass_f0980_US_EPA"), reco.M(), reco.Pt(), centrality, relPhi); + } else if (trk1.sign() > 0 && trk2.sign() > 0) { + histos.fill(HIST("hInvMass_f0980_LSpp_EPA"), reco.M(), reco.Pt(), centrality, relPhi); + } else if (trk1.sign() < 0 && trk2.sign() < 0) { + histos.fill(HIST("hInvMass_f0980_LSmm_EPA"), reco.M(), reco.Pt(), centrality, relPhi); + } + + if (cfgRotBkg && trk1.sign() * trk2.sign() < 0) { + for (int nr = 0; nr < cfgNRotBkg; nr++) { + auto randomPhi = rn->Uniform(o2::constants::math::PI * 5.0 / 6.0, o2::constants::math::PI * 7.0 / 6.0); + randomPhi += pion2.Phi(); + pion2Rot.SetXYZM(pion2.Pt() * std::cos(randomPhi), pion2.Pt() * std::sin(randomPhi), trk2.pz(), massPtl); + recoRot = pion1 + pion2Rot; + relPhiRot = TVector2::Phi_0_2pi((recoRot.Phi() - eventPlaneDet) * static_cast(nmode)); + histos.fill(HIST("hInvMass_f0980_USRot_EPA"), recoRot.M(), recoRot.Pt(), centrality, relPhiRot); + } + } + } + } + } + + void init(o2::framework::InitContext&) + { + AxisSpec epAxis = {6, 0.0, o2::constants::math::TwoPI}; + AxisSpec qaCentAxis = {110, 0, 110}; + AxisSpec qaVzAxis = {100, -20, 20}; + AxisSpec qaPIDAxis = {100, -10, 10}; + AxisSpec qaPtAxis = {200, 0, 20}; + AxisSpec qaEpAxis = {100, -1.0 * o2::constants::math::PI, o2::constants::math::PI}; + AxisSpec epresAxis = {102, -1.02, 1.02}; + + histos.add("QA/CentDist", "", {HistType::kTH1F, {qaCentAxis}}); + histos.add("QA/Vz", "", {HistType::kTH1F, {qaVzAxis}}); + + histos.add("QA/Nsigma_TPC", "", {HistType::kTH2F, {qaPtAxis, qaPIDAxis}}); + histos.add("QA/Nsigma_TOF", "", {HistType::kTH2F, {qaPtAxis, qaPIDAxis}}); + histos.add("QA/TPC_TOF", "", {HistType::kTH2F, {qaPIDAxis, qaPIDAxis}}); + + histos.add("QA/Nsigma_TPC_selected", "", {HistType::kTH2F, {qaPtAxis, qaPIDAxis}}); + histos.add("QA/Nsigma_TOF_selected", "", {HistType::kTH2F, {qaPtAxis, qaPIDAxis}}); + histos.add("QA/TPC_TOF_selected", "", {HistType::kTH2F, {qaPIDAxis, qaPIDAxis}}); + + histos.add("QA/EPhist", "", {HistType::kTH2F, {qaCentAxis, qaEpAxis}}); + histos.add("QA/EPResAB", "", {HistType::kTH2F, {qaCentAxis, epresAxis}}); + histos.add("QA/EPResAC", "", {HistType::kTH2F, {qaCentAxis, epresAxis}}); + histos.add("QA/EPResBC", "", {HistType::kTH2F, {qaCentAxis, epresAxis}}); + + histos.add("hInvMass_f0980_US_EPA", "unlike invariant mass", + {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis, epAxis}}); + histos.add("hInvMass_f0980_LSpp_EPA", "++ invariant mass", + {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis, epAxis}}); + histos.add("hInvMass_f0980_LSmm_EPA", "-- invariant mass", + {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis, epAxis}}); + histos.add("hInvMass_f0980_USRot_EPA", "unlike invariant mass Rotation", + {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis, epAxis}}); + // if (doprocessMCLight) { + // histos.add("MCL/hpT_f0980_GEN", "generated f0 signals", HistType::kTH1F, {qaPtAxis}); + // histos.add("MCL/hpT_f0980_REC", "reconstructed f0 signals", HistType::kTH3F, {massAxis, qaPtAxis, centAxis}); + // } + + detId = getDetId(cfgQvecDetName); + refAId = getDetId(cfgQvecRefAName); + refBId = getDetId(cfgQvecRefBName); + + if (detId == refAId || detId == refBId || refAId == refBId) { + LOGF(info, "Wrong detector configuration \n The FT0C will be used to get Q-Vector \n The TPCpos and TPCneg will be used as reference systems"); + detId = 0; + refAId = 4; + refBId = 5; + } + + if (cfgSelectPtl == PtlList::PtlPion) { + massPtl = o2::constants::physics::MassPionCharged; + } else if (cfgSelectPtl == PtlList::PtlKaon) { + massPtl = o2::constants::physics::MassKaonCharged; + } + + fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultPVCutLow->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05); + fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultPVCutHigh->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05); + + ccdb->setURL(cfgURL); + ccdbApi.init("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + } + + void processData(EventCandidates::iterator const& collision, + TrackCandidates const& tracks, aod::BCsWithTimestamps const&) + { + if (cfgCentEst == CentEstList::FT0C) { + centrality = collision.centFT0C(); + } else if (cfgCentEst == CentEstList::FT0M) { + centrality = collision.centFT0M(); + } + if (!eventSelected(collision)) { + return; + } + histos.fill(HIST("QA/CentDist"), centrality, 1.0); + histos.fill(HIST("QA/Vz"), collision.posZ(), 1.0); + + fillHistograms(collision, tracks, 2); // second order + }; + PROCESS_SWITCH(F0980pbpbanalysis, processData, "Process Event for data", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/f1protoncorrelation.cxx b/PWGLF/Tasks/Resonances/f1protoncorrelation.cxx index 012d5e638a4..af45b89b8da 100644 --- a/PWGLF/Tasks/Resonances/f1protoncorrelation.cxx +++ b/PWGLF/Tasks/Resonances/f1protoncorrelation.cxx @@ -26,6 +26,9 @@ #include "Framework/AnalysisTask.h" #include "Framework/ASoAHelpers.h" #include "Framework/runDataProcessing.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/StepTHn.h" +#include "Common/Core/trackUtilities.h" #include "PWGLF/DataModel/ReducedF1ProtonTables.h" #include "CommonConstants/PhysicsConstants.h" @@ -39,43 +42,72 @@ struct f1protoncorrelation { // PID selection Configurable nsigmaCutTPC{"nsigmacutTPC", 3.0, "Value of the TPC Nsigma cut"}; Configurable nsigmaCutCombined{"nsigmaCutCombined", 3.0, "Value of the TOF Nsigma cut"}; + Configurable typeofCombined{"typeofCombined", 1, "type of combined"}; // PID selection + Configurable fillSparse{"fillSparse", 1, "Fill Sparse"}; + Configurable fillRotation{"fillRotation", 1, "Fill rotation"}; + Configurable pdepPID{"pdepPID", 1, "Momentum dependent pi, k PID"}; Configurable strategyPIDPion{"strategyPIDPion", 0, "PID strategy Pion"}; Configurable strategyPIDKaon{"strategyPIDKaon", 0, "PID strategy Kaon"}; + Configurable maxKKS0Mass{"maxKKS0Mass", 1.025, "Maximum kaon kshort mass"}; Configurable maxMomentumPion{"maxMomentumPion", 4.0, "Maximum momentum Pion"}; Configurable maxMomentumKaon{"maxMomentumKaon", 4.0, "Maximum momentum Kaon"}; - Configurable momentumTOFPion{"momentumTOFPion", 0.8, "Pion momentum TOF"}; - Configurable momentumTOFKaon{"momentumTOFKaon", 0.8, "Kaon momentum TOF"}; + Configurable momentumTOFPionMin{"momentumTOFPionMin", 0.8, "Pion momentum TOF Min"}; + Configurable momentumTOFKaonMin{"momentumTOFKaonMin", 0.5, "Kaon momentum TOF Min"}; + Configurable momentumTOFPionMax{"momentumTOFPionMax", 1.2, "Pion momentum TOF Max"}; + Configurable momentumTOFKaonMax{"momentumTOFKaonMax", 0.9, "Kaon momentum TOF Max"}; Configurable momentumTOFProton{"momentumTOFProton", 0.7, "Proton momentum TOF"}; + Configurable momentumProtonMax{"momentumProtonMax", 3.0, "Maximum proton momentum"}; Configurable lowPtF1{"lowPtF1", 1.0, "PT cut F1"}; // Event Mixing - Configurable nEvtMixing{"nEvtMixing", 1, "Number of events to mix"}; + Configurable nEvtMixing{"nEvtMixing", 10, "Number of events to mix"}; ConfigurableAxis CfgVtxBins{"CfgVtxBins", {10, -10, 10}, "Mixing bins - z-vertex"}; - ConfigurableAxis CfgMultBins{"CfgMultBins", {VARIABLE_WIDTH, 0.0, 30.0, 40.0, 50.0, 60.0, 80.0, 200.0}, "Mixing bins - number of contributor"}; + ConfigurableAxis CfgMultBins{"CfgMultBins", {VARIABLE_WIDTH, 0.0, 40.0, 80.0, 500.0}, "Mixing bins - number of contributor"}; + // THnsparse bining + ConfigurableAxis configThnAxisInvMass{"configThnAxisInvMass", {100, 1.0, 1.4}, "#it{M} (GeV/#it{c}^{2})"}; + ConfigurableAxis configThnAxisPt{"configThnAxisPt", {100, 0.0, 10.}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis configThnAxisKstar{"configThnAxisKstar", {100, 0.0, 1.0}, "#it{k}^{*} (GeV/#it{c})"}; + ConfigurableAxis configThnAxisPtProton{"configThnAxisPtProton", {20, 0.0, 4.}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis configThnAxisNsigma{"configThnAxisNsigma", {90, -9.0, 9.0}, "NsigmaCombined"}; + + // mix event bining policy + ColumnBinningPolicy colBinningFemto{{CfgVtxBins, CfgMultBins}, true}; // Initialize the ananlysis task void init(o2::framework::InitContext&) { + colBinningFemto = {{CfgVtxBins, CfgMultBins}, true}; + + const AxisSpec thnAxisInvMass{configThnAxisInvMass, "#it{M} (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisPt{configThnAxisPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisPtProton{configThnAxisPtProton, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisKstar{configThnAxisKstar, "#it{k}^{*} (GeV/#it{c})"}; + const AxisSpec thnAxisNsigma{configThnAxisNsigma, "NsigmaCombined"}; + // register histograms - histos.add("hNsigmaProtonTPCSE", "Nsigma Proton TPC distribution same event", kTH2F, {{200, -10.0f, 10.0f}, {100, 0.0f, 1.0f}}); - histos.add("hNsigmaProtonTPCME", "Nsigma Proton TPC distribution mixed event", kTH2F, {{200, -10.0f, 10.0f}, {100, 0.0f, 1.0f}}); + histos.add("hNsigmaProtonTPC", "Nsigma Proton TPC distribution", kTH2F, {{100, -5.0f, 5.0f}, {100, 0.0f, 10.0f}}); + histos.add("hNsigmaKaonTPC", "Nsigma Kaon TPC distribution", kTH2F, {{100, -5.0f, 5.0f}, {100, 0.0f, 10.0f}}); + histos.add("hNsigmaPionTPC", "Nsigma Pion TPC distribution", kTH2F, {{100, -5.0f, 5.0f}, {100, 0.0f, 10.0f}}); + histos.add("hNsigmaPionKaonTPC", "Nsigma Pion Kaon TPC correlation", kTH2F, {{100, -5.0f, 5.0f}, {100, -5.0f, 5.0f}}); histos.add("h2SameEventPtCorrelation", "Pt correlation of F1 and proton", kTH3F, {{100, 0.0f, 1.0f}, {100, 0.0, 10.0}, {100, 0.0, 10.0}}); - histos.add("h2SameEventInvariantMassUnlike_mass104", "Unlike Sign Invariant mass of f1 same event", kTH3F, {{100, 0.0f, 1.0f}, {100, 0.0, 10.0}, {800, 1.0, 1.8}}); - histos.add("h2MixEventInvariantMassUnlike_mass104", "Unlike Sign Invariant mass of f1 mix event", kTH3F, {{100, 0.0f, 1.0f}, {100, 0.0, 10.0}, {800, 1.0, 1.8}}); - histos.add("h2SameEventInvariantMassLike_mass104", "Like Sign Invariant mass of f1 same event", kTH3F, {{100, 0.0f, 1.0f}, {100, 0.0, 10.0}, {800, 1.0, 1.8}}); - histos.add("h2MixEventInvariantMassLike_mass104", "Like Sign Invariant mass of f1 mix event", kTH3F, {{100, 0.0f, 1.0f}, {100, 0.0, 10.0}, {800, 1.0, 1.8}}); - histos.add("h2SameEventInvariantMassUnlike_mass103", "Unlike Sign Invariant mass of f1 same event", kTH3F, {{100, 0.0f, 1.0f}, {100, 0.0, 10.0}, {800, 1.0, 1.8}}); - histos.add("h2MixEventInvariantMassUnlike_mass103", "Unlike Sign Invariant mass of f1 mix event", kTH3F, {{100, 0.0f, 1.0f}, {100, 0.0, 10.0}, {800, 1.0, 1.8}}); - histos.add("h2SameEventInvariantMassLike_mass103", "Like Sign Invariant mass of f1 same event", kTH3F, {{100, 0.0f, 1.0f}, {100, 0.0, 10.0}, {800, 1.0, 1.8}}); - histos.add("h2MixEventInvariantMassLike_mass103", "Like Sign Invariant mass of f1 mix event", kTH3F, {{100, 0.0f, 1.0f}, {100, 0.0, 10.0}, {800, 1.0, 1.8}}); - histos.add("h2SameEventInvariantMassUnlike_mass102", "Unlike Sign Invariant mass of f1 same event", kTH3F, {{100, 0.0f, 1.0f}, {100, 0.0, 10.0}, {800, 1.0, 1.8}}); - histos.add("h2MixEventInvariantMassUnlike_mass102", "Unlike Sign Invariant mass of f1 mix event", kTH3F, {{100, 0.0f, 1.0f}, {100, 0.0, 10.0}, {800, 1.0, 1.8}}); - histos.add("h2SameEventInvariantMassLike_mass102", "Like Sign Invariant mass of f1 same event", kTH3F, {{100, 0.0f, 1.0f}, {100, 0.0, 10.0}, {800, 1.0, 1.8}}); - histos.add("h2MixEventInvariantMassLike_mass102", "Like Sign Invariant mass of f1 mix event", kTH3F, {{100, 0.0f, 1.0f}, {100, 0.0, 10.0}, {800, 1.0, 1.8}}); - histos.add("h2SameEventInvariantMassUnlike_mass101", "Unlike Sign Invariant mass of f1 same event", kTH3F, {{100, 0.0f, 1.0f}, {100, 0.0, 10.0}, {800, 1.0, 1.8}}); - histos.add("h2MixEventInvariantMassUnlike_mass101", "Unlike Sign Invariant mass of f1 mix event", kTH3F, {{100, 0.0f, 1.0f}, {100, 0.0, 10.0}, {800, 1.0, 1.8}}); - histos.add("h2SameEventInvariantMassLike_mass101", "Like Sign Invariant mass of f1 same event", kTH3F, {{100, 0.0f, 1.0f}, {100, 0.0, 10.0}, {800, 1.0, 1.8}}); - histos.add("h2MixEventInvariantMassLike_mass101", "Like Sign Invariant mass of f1 mix event", kTH3F, {{100, 0.0f, 1.0f}, {100, 0.0, 10.0}, {800, 1.0, 1.8}}); + + histos.add("h2SameEventInvariantMassUnlike_mass", "Unlike Sign Invariant mass of f1 same event", kTH3F, {thnAxisKstar, thnAxisPt, thnAxisInvMass}); + histos.add("h2SameEventInvariantMassLike_mass", "Like Sign Invariant mass of f1 same event", kTH3F, {thnAxisKstar, thnAxisPt, thnAxisInvMass}); + histos.add("h2SameEventInvariantMassRot_mass", "Rotational Invariant mass of f1 same event", kTH3F, {thnAxisKstar, thnAxisPt, thnAxisInvMass}); + + histos.add("h2MixEventInvariantMassUnlike_mass", "Unlike Sign Invariant mass of f1 mix event", kTH3F, {thnAxisKstar, thnAxisPt, thnAxisInvMass}); + histos.add("h2MixEventInvariantMassLike_mass", "Like Sign Invariant mass of f1 mix event", kTH3F, {thnAxisKstar, thnAxisPt, thnAxisInvMass}); + histos.add("h2MixEventInvariantMassRot_mass", "Rotational Sign Invariant mass of f1 mix event", kTH3F, {thnAxisKstar, thnAxisPt, thnAxisInvMass}); + + if (fillSparse) { + histos.add("SEMassUnlike", "SEMassUnlike", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPtProton, thnAxisKstar, thnAxisNsigma}); + histos.add("SEMassLike", "SEMassLike", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPtProton, thnAxisKstar, thnAxisNsigma}); + histos.add("SEMassRot", "SEMassRot", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPtProton, thnAxisKstar, thnAxisNsigma}); + + histos.add("MEMassUnlike", "MEMassUnlike", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPtProton, thnAxisKstar, thnAxisNsigma}); + histos.add("MEMassLike", "MEMassLike", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPtProton, thnAxisKstar, thnAxisNsigma}); + histos.add("MEMassRot", "MEMassRot", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPtProton, thnAxisKstar, thnAxisNsigma}); + } } // get kstar @@ -100,71 +132,110 @@ struct f1protoncorrelation { trackRelK = PartOneCMS - PartTwoCMS; return 0.5 * trackRelK.P(); } - - TLorentzVector F1, Proton, F1ProtonPair, Pion, Kaon; + float combinedTPC; + TLorentzVector F1, Proton, F1ProtonPair, Pion, Kaon, Kshort; + TLorentzVector F1Rot, PionRot, KaonKshortPair, KaonKshortPairRot; // Process the data in same event void process(aod::RedF1PEvents::iterator const& /*collision*/, aod::F1Tracks const& f1tracks, aod::ProtonTracks const& protontracks) { for (auto f1track : f1tracks) { - F1.SetXYZM(f1track.f1Px(), f1track.f1Py(), f1track.f1Pz(), f1track.f1Mass()); - if (f1track.f1MassKaonKshort() > 1.04 || F1.Pt() < lowPtF1) { + if (f1track.f1MassKaonKshort() > maxKKS0Mass) { continue; } + F1.SetXYZM(f1track.f1Px(), f1track.f1Py(), f1track.f1Pz(), f1track.f1Mass()); Pion.SetXYZM(f1track.f1d1Px(), f1track.f1d1Py(), f1track.f1d1Pz(), 0.139); Kaon.SetXYZM(f1track.f1d2Px(), f1track.f1d2Py(), f1track.f1d2Pz(), 0.493); - if (Pion.P() > maxMomentumPion || Kaon.P() > maxMomentumKaon) { + Kshort.SetXYZM(f1track.f1d3Px(), f1track.f1d3Py(), f1track.f1d3Pz(), 0.497); + KaonKshortPair = Kaon + Kshort; + if (Pion.Pt() > maxMomentumPion || Kaon.Pt() > maxMomentumKaon) { + continue; + } + if (pdepPID) { + if (Kaon.Pt() <= 0.5 && (f1track.f1d2TPC() < -2.5 || f1track.f1d2TPC() > 2.5)) { + continue; + } + if (Kaon.Pt() > 0.5 && Kaon.Pt() <= 0.7 && (f1track.f1d2TPC() < -1.5 || f1track.f1d2TPC() > 2.5)) { + continue; + } + if (Kaon.Pt() > 0.7 && Kaon.Pt() <= 1.0 && (f1track.f1d2TPC() < -1.0 || f1track.f1d2TPC() > 2.5)) { + continue; + } + if (Kaon.Pt() > 1.0 && (f1track.f1d2TPC() < -2.5 || f1track.f1d2TPC() > 2.5)) { + continue; + } + if (Pion.Pt() < 2.0 && (f1track.f1d1TPC() < -2.5 || f1track.f1d1TPC() > 2.5)) { + continue; + } + if (Pion.Pt() > 2.0 && (f1track.f1d1TPC() < -2.5 || f1track.f1d1TPC() > 2.5)) { + continue; + } + } + if (strategyPIDPion == 1 && Pion.Pt() > momentumTOFPionMin && Pion.Pt() <= momentumTOFPionMax && f1track.f1d1TOFHit() != 1) { continue; } - if (strategyPIDPion == 1 && Pion.P() > momentumTOFPion && f1track.f1d1TOFHit() != 1) { + if (strategyPIDKaon == 1 && Kaon.Pt() > momentumTOFKaonMin && Kaon.Pt() <= momentumTOFKaonMax && f1track.f1d2TOFHit() != 1) { continue; } - if (strategyPIDKaon == 1 && Kaon.P() > momentumTOFKaon && f1track.f1d2TOFHit() != 1) { + if (strategyPIDKaon == 2 && Kaon.Pt() > momentumTOFKaonMin && Kaon.Pt() <= momentumTOFKaonMax && f1track.f1d2TPC() < -1.0 && f1track.f1d2TOFHit() != 1) { continue; } + histos.fill(HIST("hNsigmaKaonTPC"), f1track.f1d2TPC(), Kaon.Pt()); + histos.fill(HIST("hNsigmaPionTPC"), f1track.f1d1TPC(), Pion.Pt()); + histos.fill(HIST("hNsigmaPionKaonTPC"), f1track.f1d1TPC(), f1track.f1d2TPC()); + if (typeofCombined == 0) { + combinedTPC = TMath::Sqrt(f1track.f1d1TPC() * f1track.f1d1TPC() + f1track.f1d2TPC() * f1track.f1d2TPC()); + } + if (typeofCombined == 1) { + combinedTPC = (f1track.f1d1TPC() - f1track.f1d2TPC()) / (f1track.f1d1TPC() + f1track.f1d2TPC()); + } for (auto protontrack : protontracks) { Proton.SetXYZM(protontrack.protonPx(), protontrack.protonPy(), protontrack.protonPz(), 0.938); - if (Proton.P() < momentumTOFProton && TMath::Abs(protontrack.protonNsigmaTPC()) > 3) { + if (Proton.Pt() > momentumProtonMax) { + continue; + } + if (Proton.P() < momentumTOFProton && TMath::Abs(protontrack.protonNsigmaTPC()) > 2.5) { continue; } - if (Proton.P() >= momentumTOFProton && protontrack.protonTOFHit() != 1 && TMath::Abs(protontrack.protonNsigmaTOF()) > 3) { + if (Proton.P() >= momentumTOFProton && (protontrack.protonTOFHit() != 1 || TMath::Abs(protontrack.protonNsigmaTOF()) > 2.5)) { continue; } if ((f1track.f1PionIndex() == protontrack.f1ProtonIndex()) || (f1track.f1KaonIndex() == protontrack.f1ProtonIndex()) || (f1track.f1KshortPositiveIndex() == protontrack.f1ProtonIndex()) || (f1track.f1KshortNegativeIndex() == protontrack.f1ProtonIndex())) { continue; } auto relative_momentum = getkstar(F1, Proton); - histos.fill(HIST("h2SameEventPtCorrelation"), relative_momentum, F1.Pt(), Proton.Pt()); - if (f1track.f1MassKaonKshort() < 1.04) { - if (f1track.f1SignalStat() == 1) { - histos.fill(HIST("h2SameEventInvariantMassUnlike_mass104"), relative_momentum, F1.Pt(), F1.M()); // F1 sign = 1 unlike, F1 sign = -1 like - histos.fill(HIST("hNsigmaProtonTPCSE"), protontrack.protonNsigmaTPC(), relative_momentum); - } - if (f1track.f1SignalStat() == -1) { - histos.fill(HIST("h2SameEventInvariantMassLike_mass104"), relative_momentum, F1.Pt(), F1.M()); - } + if (relative_momentum <= 0.5) { + histos.fill(HIST("hNsigmaProtonTPC"), protontrack.protonNsigmaTPC(), Proton.Pt()); } - if (f1track.f1MassKaonKshort() < 1.03) { - if (f1track.f1SignalStat() == 1) { - histos.fill(HIST("h2SameEventInvariantMassUnlike_mass103"), relative_momentum, F1.Pt(), F1.M()); // F1 sign = 1 unlike, F1 sign = -1 like - } - if (f1track.f1SignalStat() == -1) { - histos.fill(HIST("h2SameEventInvariantMassLike_mass103"), relative_momentum, F1.Pt(), F1.M()); + histos.fill(HIST("h2SameEventPtCorrelation"), relative_momentum, F1.Pt(), Proton.Pt()); + if (f1track.f1SignalStat() == 1) { + histos.fill(HIST("h2SameEventInvariantMassUnlike_mass"), relative_momentum, F1.Pt(), F1.M()); // F1 sign = 1 unlike, F1 sign = -1 like + if (fillSparse) { + histos.fill(HIST("SEMassUnlike"), F1.M(), F1.Pt(), Proton.Pt(), relative_momentum, combinedTPC); } } - if (f1track.f1MassKaonKshort() < 1.02) { - if (f1track.f1SignalStat() == 1) { - histos.fill(HIST("h2SameEventInvariantMassUnlike_mass102"), relative_momentum, F1.Pt(), F1.M()); // F1 sign = 1 unlike, F1 sign = -1 like - } - if (f1track.f1SignalStat() == -1) { - histos.fill(HIST("h2SameEventInvariantMassLike_mass102"), relative_momentum, F1.Pt(), F1.M()); + if (f1track.f1SignalStat() == -1) { + histos.fill(HIST("h2SameEventInvariantMassLike_mass"), relative_momentum, F1.Pt(), F1.M()); + if (fillSparse) { + histos.fill(HIST("SEMassLike"), F1.M(), F1.Pt(), Proton.Pt(), relative_momentum, combinedTPC); } } - if (f1track.f1MassKaonKshort() < 1.01) { - if (f1track.f1SignalStat() == 1) { - histos.fill(HIST("h2SameEventInvariantMassUnlike_mass101"), relative_momentum, F1.Pt(), F1.M()); // F1 sign = 1 unlike, F1 sign = -1 like - } - if (f1track.f1SignalStat() == -1) { - histos.fill(HIST("h2SameEventInvariantMassLike_mass101"), relative_momentum, F1.Pt(), F1.M()); + if (fillRotation) { + for (int nrotbkg = 0; nrotbkg < 9; nrotbkg++) { + auto anglestart = 5.0 * TMath::Pi() / 6.0; + auto angleend = 7.0 * TMath::Pi() / 6.0; + auto anglestep = (angleend - anglestart) / (1.0 * (9.0 - 1.0)); + auto rotangle = anglestart + nrotbkg * anglestep; + auto rotKKPx = KaonKshortPair.Px() * std::cos(rotangle) - KaonKshortPair.Py() * std::sin(rotangle); + auto rotKKPy = KaonKshortPair.Px() * std::sin(rotangle) + KaonKshortPair.Py() * std::cos(rotangle); + KaonKshortPairRot.SetXYZM(rotKKPx, rotKKPy, KaonKshortPair.Pz(), KaonKshortPair.M()); + F1Rot = Pion + KaonKshortPairRot; + auto relative_momentum_rot = getkstar(F1Rot, Proton); + if (f1track.f1SignalStat() == 1) { + histos.fill(HIST("h2SameEventInvariantMassRot_mass"), relative_momentum_rot, F1Rot.Pt(), F1Rot.M()); + if (fillSparse) { + histos.fill(HIST("SEMassRot"), F1Rot.M(), F1Rot.Pt(), Proton.Pt(), relative_momentum_rot, combinedTPC); + } + } } } } @@ -172,12 +243,6 @@ struct f1protoncorrelation { } // Processing Event Mixing - // using BinningTypeVtxZT0M = ColumnBinningPolicy; - // for (auto& [collision1, tracks1, collision2, tracks2] : pairs) { - // Pair pairs{colBinning, nEvtMixing, -1, &cache}; // -1 is the number of the bin to skip - // - // tracks1 is an aod::Tracks table of f1tracks belonging to collision collision1 (aod::Collision::iterator) - // tracks2 is an aod::Tracks table of protontracks belonging to collision collision2 (aod::Collision::iterator) SliceCache cache; using BinningType = ColumnBinningPolicy; BinningType colBinning{{CfgVtxBins, CfgMultBins}, true}; @@ -197,69 +262,198 @@ struct f1protoncorrelation { auto groupProton = protontracks.sliceBy(tracksPerCollisionPresliceP, collision2.globalIndex()); // auto groupF1 = f1tracks.sliceByCached(aod::f1protondaughter::redF1PEventId, collision1.globalIndex(), cache); // auto groupProton = protontracks.sliceByCached(aod::f1protondaughter::redF1PEventId, collision2.globalIndex(), cache); - // for (auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(f1tracks, protontracks))) { for (auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(groupF1, groupProton))) { - // LOGF(info, "Mixed event collision1 track1: (%d, %d)", collision1.index(), t1.index()); - F1.SetXYZM(t1.f1Px(), t1.f1Py(), t1.f1Pz(), t1.f1Mass()); - if (t1.f1MassKaonKshort() > 1.04 || F1.Pt() < lowPtF1) { + if (t1.f1MassKaonKshort() > maxKKS0Mass) { continue; } + F1.SetXYZM(t1.f1Px(), t1.f1Py(), t1.f1Pz(), t1.f1Mass()); Pion.SetXYZM(t1.f1d1Px(), t1.f1d1Py(), t1.f1d1Pz(), 0.139); Kaon.SetXYZM(t1.f1d2Px(), t1.f1d2Py(), t1.f1d2Pz(), 0.493); - if (Pion.P() > maxMomentumPion || Kaon.P() > maxMomentumKaon) { + Kshort.SetXYZM(t1.f1d3Px(), t1.f1d3Py(), t1.f1d3Pz(), 0.497); + KaonKshortPair = Kaon + Kshort; + if (Pion.Pt() > maxMomentumPion || Kaon.Pt() > maxMomentumKaon) { continue; } - if (strategyPIDPion == 1 && Pion.P() > momentumTOFPion && t1.f1d1TOFHit() != 1) { + if (pdepPID) { + if (Kaon.Pt() <= 0.5 && (t1.f1d2TPC() < -2.5 || t1.f1d2TPC() > 2.5)) { + continue; + } + if (Kaon.Pt() > 0.5 && Kaon.Pt() <= 0.7 && (t1.f1d2TPC() < -1.5 || t1.f1d2TPC() > 2.5)) { + continue; + } + if (Kaon.Pt() > 0.7 && Kaon.Pt() <= 1.0 && (t1.f1d2TPC() < -1.0 || t1.f1d2TPC() > 2.5)) { + continue; + } + if (Kaon.Pt() > 1.0 && (t1.f1d2TPC() < -2.5 || t1.f1d2TPC() > 2.5)) { + continue; + } + if (Pion.Pt() < 2.0 && (t1.f1d1TPC() < -2.5 || t1.f1d1TPC() > 2.5)) { + continue; + } + if (Pion.Pt() > 2.0 && (t1.f1d1TPC() < -2.5 || t1.f1d1TPC() > 2.5)) { + continue; + } + } + if (strategyPIDPion == 1 && Pion.Pt() > momentumTOFPionMin && Pion.Pt() <= momentumTOFPionMax && t1.f1d1TOFHit() != 1) { continue; } - if (strategyPIDKaon == 1 && Kaon.P() > momentumTOFKaon && t1.f1d2TOFHit() != 1) { + if (strategyPIDKaon == 1 && Kaon.Pt() > momentumTOFKaonMin && Kaon.Pt() <= momentumTOFKaonMax && t1.f1d2TOFHit() != 1) { continue; } + if (typeofCombined == 0) { + combinedTPC = TMath::Sqrt(t1.f1d1TPC() * t1.f1d1TPC() + t1.f1d2TPC() * t1.f1d2TPC()); + } + if (typeofCombined == 1) { + combinedTPC = (t1.f1d1TPC() - t1.f1d2TPC()) / (t1.f1d1TPC() + t1.f1d2TPC()); + } Proton.SetXYZM(t2.protonPx(), t2.protonPy(), t2.protonPz(), 0.938); - if (Proton.P() < momentumTOFProton && TMath::Abs(t2.protonNsigmaTPC()) > 3) { + if (Proton.Pt() > momentumProtonMax) { continue; } - if (Proton.P() >= momentumTOFProton && t2.protonTOFHit() != 1 && TMath::Abs(t2.protonNsigmaTOF()) > 3) { + if (Proton.P() < momentumTOFProton && TMath::Abs(t2.protonNsigmaTPC()) > 2.5) { + continue; + } + if (Proton.P() >= momentumTOFProton && (t2.protonTOFHit() != 1 || TMath::Abs(t2.protonNsigmaTOF()) > 2.5)) { continue; } auto relative_momentum = getkstar(F1, Proton); - if (t1.f1MassKaonKshort() < 1.04) { - if (t1.f1SignalStat() == 1) { - histos.fill(HIST("h2MixEventInvariantMassUnlike_mass104"), relative_momentum, F1.Pt(), F1.M()); // F1 sign = 1 unlike, F1 sign = -1 like - histos.fill(HIST("hNsigmaProtonTPCME"), t2.protonNsigmaTPC(), relative_momentum); - } - if (t1.f1SignalStat() == -1) { - histos.fill(HIST("h2MixEventInvariantMassLike_mass104"), relative_momentum, F1.Pt(), F1.M()); + if (t1.f1SignalStat() == 1) { + histos.fill(HIST("h2MixEventInvariantMassUnlike_mass"), relative_momentum, F1.Pt(), F1.M()); // F1 sign = 1 unlike, F1 sign = -1 like + if (fillSparse) { + histos.fill(HIST("MEMassUnlike"), F1.M(), F1.Pt(), Proton.Pt(), relative_momentum, combinedTPC); } } - if (t1.f1MassKaonKshort() < 1.03) { - if (t1.f1SignalStat() == 1) { - histos.fill(HIST("h2MixEventInvariantMassUnlike_mass103"), relative_momentum, F1.Pt(), F1.M()); // F1 sign = 1 unlike, F1 sign = -1 like + if (t1.f1SignalStat() == -1) { + histos.fill(HIST("h2MixEventInvariantMassLike_mass"), relative_momentum, F1.Pt(), F1.M()); + if (fillSparse) { + histos.fill(HIST("MEMassLike"), F1.M(), F1.Pt(), Proton.Pt(), relative_momentum, combinedTPC); } - if (t1.f1SignalStat() == -1) { - histos.fill(HIST("h2MixEventInvariantMassLike_mass103"), relative_momentum, F1.Pt(), F1.M()); + } + if (fillRotation) { + for (int nrotbkg = 0; nrotbkg < 9; nrotbkg++) { + auto anglestart = 5.0 * TMath::Pi() / 6.0; + auto angleend = 7.0 * TMath::Pi() / 6.0; + auto anglestep = (angleend - anglestart) / (1.0 * (9.0 - 1.0)); + auto rotangle = anglestart + nrotbkg * anglestep; + auto rotKKPx = KaonKshortPair.Px() * std::cos(rotangle) - KaonKshortPair.Py() * std::sin(rotangle); + auto rotKKPy = KaonKshortPair.Px() * std::sin(rotangle) + KaonKshortPair.Py() * std::cos(rotangle); + KaonKshortPairRot.SetXYZM(rotKKPx, rotKKPy, KaonKshortPair.Pz(), KaonKshortPair.M()); + F1Rot = Pion + KaonKshortPairRot; + auto relative_momentum_rot = getkstar(F1Rot, Proton); + if (t1.f1SignalStat() == 1) { + histos.fill(HIST("h2MixEventInvariantMassRot_mass"), relative_momentum_rot, F1Rot.Pt(), F1Rot.M()); + if (fillSparse) { + histos.fill(HIST("MEMassRot"), F1Rot.M(), F1Rot.Pt(), Proton.Pt(), relative_momentum_rot, combinedTPC); + } + } } } - if (t1.f1MassKaonKshort() < 1.02) { - if (t1.f1SignalStat() == 1) { - histos.fill(HIST("h2MixEventInvariantMassUnlike_mass102"), relative_momentum, F1.Pt(), F1.M()); // F1 sign = 1 unlike, F1 sign = -1 like + } + } + } + PROCESS_SWITCH(f1protoncorrelation, processME, "Process EventMixing for combinatorial background", false); + void processMEOpti(aod::RedF1PEvents& collisions, aod::F1Tracks& f1tracks, aod::ProtonTracks& protontracks) + { + // for (auto const& [collision1, collision2] : combinations(soa::CombinationsBlockFullIndexPolicy(colBinningFemto, nEvtMixing, -1, collisions, collisions))){ + for (auto const& [collision1, collision2] : selfCombinations(colBinning, nEvtMixing, -1, collisions, collisions)) { + // LOGF(info, "Mixed event collisions: (%d, %d)", collision1.index(), collision2.index()); + if (collision1.index() == collision2.index()) { + continue; + } + auto groupF1 = f1tracks.sliceBy(tracksPerCollisionPresliceF1, collision1.globalIndex()); + auto groupProton = protontracks.sliceBy(tracksPerCollisionPresliceP, collision2.globalIndex()); + // auto groupF1 = f1tracks.sliceByCached(aod::f1protondaughter::redF1PEventId, collision1.globalIndex(), cache); + // auto groupProton = protontracks.sliceByCached(aod::f1protondaughter::redF1PEventId, collision2.globalIndex(), cache); + for (auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(groupF1, groupProton))) { + if (t1.f1MassKaonKshort() > maxKKS0Mass) { + continue; + } + F1.SetXYZM(t1.f1Px(), t1.f1Py(), t1.f1Pz(), t1.f1Mass()); + Pion.SetXYZM(t1.f1d1Px(), t1.f1d1Py(), t1.f1d1Pz(), 0.139); + Kaon.SetXYZM(t1.f1d2Px(), t1.f1d2Py(), t1.f1d2Pz(), 0.493); + Kshort.SetXYZM(t1.f1d3Px(), t1.f1d3Py(), t1.f1d3Pz(), 0.497); + KaonKshortPair = Kaon + Kshort; + if (Pion.Pt() > maxMomentumPion || Kaon.Pt() > maxMomentumKaon) { + continue; + } + if (pdepPID) { + if (Kaon.Pt() <= 0.5 && (t1.f1d2TPC() < -2.5 || t1.f1d2TPC() > 2.5)) { + continue; + } + if (Kaon.Pt() > 0.5 && Kaon.Pt() <= 0.7 && (t1.f1d2TPC() < -1.5 || t1.f1d2TPC() > 2.5)) { + continue; + } + if (Kaon.Pt() > 0.7 && Kaon.Pt() <= 1.0 && (t1.f1d2TPC() < -1.0 || t1.f1d2TPC() > 2.5)) { + continue; } - if (t1.f1SignalStat() == -1) { - histos.fill(HIST("h2MixEventInvariantMassLike_mass102"), relative_momentum, F1.Pt(), F1.M()); + if (Kaon.Pt() > 1.0 && (t1.f1d2TPC() < -2.5 || t1.f1d2TPC() > 2.5)) { + continue; } + if (Pion.Pt() < 2.0 && (t1.f1d1TPC() < -2.5 || t1.f1d1TPC() > 2.5)) { + continue; + } + if (Pion.Pt() > 2.0 && (t1.f1d1TPC() < -2.5 || t1.f1d1TPC() > 2.5)) { + continue; + } + } + if (strategyPIDPion == 1 && Pion.Pt() > momentumTOFPionMin && Pion.Pt() <= momentumTOFPionMax && t1.f1d1TOFHit() != 1) { + continue; + } + if (strategyPIDKaon == 1 && Kaon.Pt() > momentumTOFKaonMin && Kaon.Pt() <= momentumTOFKaonMax && t1.f1d2TOFHit() != 1) { + continue; } - if (t1.f1MassKaonKshort() < 1.01) { - if (t1.f1SignalStat() == 1) { - histos.fill(HIST("h2MixEventInvariantMassUnlike_mass101"), relative_momentum, F1.Pt(), F1.M()); // F1 sign = 1 unlike, F1 sign = -1 like + if (typeofCombined == 0) { + combinedTPC = TMath::Sqrt(t1.f1d1TPC() * t1.f1d1TPC() + t1.f1d2TPC() * t1.f1d2TPC()); + } + if (typeofCombined == 1) { + combinedTPC = (t1.f1d1TPC() - t1.f1d2TPC()) / (t1.f1d1TPC() + t1.f1d2TPC()); + } + Proton.SetXYZM(t2.protonPx(), t2.protonPy(), t2.protonPz(), 0.938); + if (Proton.Pt() > momentumProtonMax) { + continue; + } + if (Proton.P() < momentumTOFProton && TMath::Abs(t2.protonNsigmaTPC()) > 2.5) { + continue; + } + if (Proton.P() >= momentumTOFProton && (t2.protonTOFHit() != 1 || TMath::Abs(t2.protonNsigmaTOF()) > 2.5)) { + continue; + } + auto relative_momentum = getkstar(F1, Proton); + if (t1.f1SignalStat() == 1) { + histos.fill(HIST("h2MixEventInvariantMassUnlike_mass"), relative_momentum, F1.Pt(), F1.M()); // F1 sign = 1 unlike, F1 sign = -1 like + if (fillSparse) { + histos.fill(HIST("MEMassUnlike"), F1.M(), F1.Pt(), Proton.Pt(), relative_momentum, combinedTPC); } - if (t1.f1SignalStat() == -1) { - histos.fill(HIST("h2MixEventInvariantMassLike_mass101"), relative_momentum, F1.Pt(), F1.M()); + } + if (t1.f1SignalStat() == -1) { + histos.fill(HIST("h2MixEventInvariantMassLike_mass"), relative_momentum, F1.Pt(), F1.M()); + if (fillSparse) { + histos.fill(HIST("MEMassLike"), F1.M(), F1.Pt(), Proton.Pt(), relative_momentum, combinedTPC); + } + } + if (fillRotation) { + for (int nrotbkg = 0; nrotbkg < 9; nrotbkg++) { + auto anglestart = 5.0 * TMath::Pi() / 6.0; + auto angleend = 7.0 * TMath::Pi() / 6.0; + auto anglestep = (angleend - anglestart) / (1.0 * (9.0 - 1.0)); + auto rotangle = anglestart + nrotbkg * anglestep; + auto rotKKPx = KaonKshortPair.Px() * std::cos(rotangle) - KaonKshortPair.Py() * std::sin(rotangle); + auto rotKKPy = KaonKshortPair.Px() * std::sin(rotangle) + KaonKshortPair.Py() * std::cos(rotangle); + KaonKshortPairRot.SetXYZM(rotKKPx, rotKKPy, KaonKshortPair.Pz(), KaonKshortPair.M()); + F1Rot = Pion + KaonKshortPairRot; + auto relative_momentum_rot = getkstar(F1Rot, Proton); + if (t1.f1SignalStat() == 1) { + histos.fill(HIST("h2MixEventInvariantMassRot_mass"), relative_momentum_rot, F1Rot.Pt(), F1Rot.M()); + if (fillSparse) { + histos.fill(HIST("MEMassRot"), F1Rot.M(), F1Rot.Pt(), Proton.Pt(), relative_momentum_rot, combinedTPC); + } + } } } } } } - PROCESS_SWITCH(f1protoncorrelation, processME, "Process EventMixing for combinatorial background", false); + PROCESS_SWITCH(f1protoncorrelation, processMEOpti, "Process EventMixing for combinatorial background Optimal", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/Resonances/heptaquark.cxx b/PWGLF/Tasks/Resonances/heptaquark.cxx new file mode 100644 index 00000000000..407c3199073 --- /dev/null +++ b/PWGLF/Tasks/Resonances/heptaquark.cxx @@ -0,0 +1,358 @@ +// 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 this is a starting point for the Resonances tutorial +/// \author junlee kim + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/StepTHn.h" +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/ReducedHeptaQuarkTables.h" +#include "CommonConstants/PhysicsConstants.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct heptaquark { + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Configurable cfgRotBkg{"cfgRotBkg", true, "flag to construct rotational backgrounds"}; + Configurable cfgNRotBkg{"cfgNRotBkg", 10, "the number of rotational backgrounds"}; + + Configurable cfgPIDStrategy{"cfgPIDStrategy", 3, "PID strategy 1"}; + Configurable cfgPIDPrPi{"cfgPIDPrPi", 3, "PID selection for proton and pion"}; + + Configurable minPhiMass{"minPhiMass", 1.01, "Minimum phi mass"}; + Configurable maxPhiMass{"maxPhiMass", 1.03, "Maximum phi mass"}; + + Configurable minLambdaMass{"minLambdaMass", 1.1, "Minimum lambda mass"}; + Configurable maxLambdaMass{"maxLambdaMass", 1.13, "Maximum lambda mass"}; + + Configurable cutNsigmaTPC{"cutNsigmaTPC", 2.5, "nsigma cut TPC"}; + Configurable cutNsigmaTOF{"cutNsigmaTOF", 3.0, "nsigma cut TOF"}; + + ConfigurableAxis massAxis{"massAxis", {600, 2.8, 3.4}, "Invariant mass axis"}; + ConfigurableAxis ptAxis{"ptAxis", {VARIABLE_WIDTH, 0.2, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.5, 8.0, 10.0, 100.0}, "Transverse momentum bins"}; + ConfigurableAxis centAxis{"centAxis", {VARIABLE_WIDTH, 0, 20, 50, 100}, "Centrality interval"}; + ConfigurableAxis massPPAxis{"massPPAxis", {100, 3.0, 8.0}, "Mass square of phi phi"}; + ConfigurableAxis massPLAxis{"massPLAxis", {100, 3.0, 8.0}, "Mass square of phi lambda"}; + + void init(o2::framework::InitContext&) + { + histos.add("hnsigmaTPCPi", "hnsigmaTPCPi", kTH2F, {{1000, -7.0, 7.0f}, {100, 0.0f, 10.0f}}); + + histos.add("hnsigmaTPCKa", "hnsigmaTPCKa", kTH2F, {{1000, -7.0, 7.0f}, {100, 0.0f, 10.0f}}); + histos.add("hnsigmaTOFKa", "hnsigmaTOFKa", kTH2F, {{1000, -7.0, 7.0f}, {100, 0.0f, 10.0f}}); + + histos.add("hnsigmaTPCPr", "hnsigmaTPCPr", kTH2F, {{1000, -7.0, 7.0f}, {100, 0.0f, 10.0f}}); + + histos.add("hPhid1Mass", "hPhid1Mass", kTH2F, {{40, 1.0, 1.04f}, {100, 0.0f, 10.0f}}); + histos.add("hPhid2Mass", "hPhid2Mass", kTH2F, {{40, 1.0, 1.04f}, {100, 0.0f, 10.0f}}); + histos.add("hLambdaMass", "hLambdaMass", kTH2F, {{140, 1.095, 1.135}, {100, 0.0f, 10.0f}}); + + histos.add("h_InvMass_same", "h_InvMass_same", {HistType::kTH3F, {massAxis, ptAxis, centAxis}}); + histos.add("h_InvMass_rotPhi", "h_InvMass_rotPhi", {HistType::kTH3F, {massAxis, ptAxis, centAxis}}); + histos.add("h_InvMass_rotLambda", "h_InvMass_rotLambda", {HistType::kTH3F, {massAxis, ptAxis, centAxis}}); + histos.add("h_InvMass_rotPhiLambda", "h_InvMass_rotPhiLambda", {HistType::kTH3F, {massAxis, ptAxis, centAxis}}); + + histos.add("hDalitz", "hDalitz", {HistType::kTHnSparseF, {massPPAxis, massPLAxis, massAxis, ptAxis, {2, -0.5f, 1.5f}, centAxis}}); + histos.add("hDalitzRot", "hDalitzRot", {HistType::kTHnSparseF, {massPPAxis, massPLAxis, massAxis, ptAxis, {2, -0.5f, 1.5f}, centAxis}}); + } + + double massLambda = o2::constants::physics::MassLambda; + double massPr = o2::constants::physics::MassProton; + double massPi = o2::constants::physics::MassPionCharged; + double massKa = o2::constants::physics::MassKPlus; + + TRandom* rn = new TRandom(); + + bool selectionPIDKaon(float nsigmaTPC, float nsigmaTOF, int TOFHit, int PIDStrategy, float ptcand) + { + if (PIDStrategy == 0) { + if (TOFHit != 1) { + if (TMath::Abs(nsigmaTPC) < cutNsigmaTPC) { + return true; + } + } + if (TOFHit == 1) { + if (TMath::Abs(nsigmaTOF) < cutNsigmaTOF) { + return true; + } + } + } + if (PIDStrategy == 1) { + if (ptcand < 0.5) { + if (TOFHit != 1 && TMath::Abs(nsigmaTPC) < cutNsigmaTPC) { + return true; + } + if (TOFHit == 1 && TMath::Abs(nsigmaTOF) < cutNsigmaTOF) { + return true; + } + } + if (ptcand >= 0.5) { + if (TOFHit == 1 && TMath::Abs(nsigmaTOF) < cutNsigmaTOF) { + return true; + } + } + } + if (PIDStrategy == 2) { + if (ptcand < 0.5) { + if (TOFHit != 1 && TMath::Abs(nsigmaTPC) < cutNsigmaTPC) { + return true; + } + if (TOFHit == 1 && TMath::Abs(nsigmaTOF) < cutNsigmaTOF) { + return true; + } + } + if (ptcand >= 0.5 && ptcand < 1.2) { + if (TOFHit == 1 && TMath::Abs(nsigmaTOF) < cutNsigmaTOF) { + return true; + } + if (TOFHit != 1 && nsigmaTPC > -1.5 && nsigmaTPC < cutNsigmaTPC) { + return true; + } + } + if (ptcand >= 1.2) { + if (TOFHit == 1 && TMath::Abs(nsigmaTOF) < cutNsigmaTOF) { + return true; + } + if (TOFHit != 1 && TMath::Abs(nsigmaTPC) < cutNsigmaTPC) { + return true; + } + } + } + if (PIDStrategy == 3) { + if (ptcand < 0.5) { + if (TOFHit != 1 && TMath::Abs(nsigmaTPC) < cutNsigmaTPC) { + return true; + } + if (TOFHit == 1 && TMath::Abs(nsigmaTOF) < cutNsigmaTOF) { + return true; + } + } + if (ptcand >= 0.5 && ptcand < 1.2) { + if (TOFHit == 1 && TMath::Abs(nsigmaTOF) < cutNsigmaTOF) { + return true; + } + } + if (ptcand >= 1.2) { + if (TOFHit == 1 && TMath::Abs(nsigmaTOF) < cutNsigmaTOF) { + return true; + } + if (TOFHit != 1 && TMath::Abs(nsigmaTPC) < cutNsigmaTPC) { + return true; + } + } + } + return false; + } + + template + ROOT::Math::XYZVector getDCAofV0V0(V01 const& v01, V02 const& v02) + { + ROOT::Math::XYZVector v01pos, v02pos, v01mom, v02mom; + v01pos.SetXYZ(v01.x(), v01.y(), v01.z()); + v02pos.SetXYZ(v02.x(), v02.y(), v02.z()); + v01mom.SetXYZ(v01.px(), v01.py(), v01.pz()); + v02mom.SetXYZ(v02.px(), v02.py(), v02.pz()); + + ROOT::Math::XYZVector posdiff = v02pos - v01pos; + ROOT::Math::XYZVector cross = v01mom.Cross(v02mom); + ROOT::Math::XYZVector dcaVec = (posdiff.Dot(cross) / cross.Mag2()) * cross; + return dcaVec; + } + + template + float getCPA(V01 const& v01, V02 const& v02) + { + ROOT::Math::XYZVector v01mom, v02mom; + v01mom.SetXYZ(v01.px() / v01.p(), v01.py() / v01.p(), v01.pz() / v01.p()); + v02mom.SetXYZ(v02.px() / v02.p(), v02.py() / v02.p(), v02.pz() / v02.p()); + return v01mom.Dot(v02mom); + } + + ROOT::Math::PxPyPzMVector DauVec1, DauVec2; + + TLorentzVector exotic, HQ1, HQ2, HQ3; + TLorentzVector exoticRot2, HQ2Rot; + TLorentzVector exoticRot3, HQ3Rot; + TLorentzVector exoticRot23; + TLorentzVector HQ12, HQ13; + TLorentzVector HQ12Rot, HQ13Rot; + + void processSameEvent(aod::RedHQEvents::iterator const& collision, aod::HQTracks const& hqtracks) + { + if (collision.numLambda() < 1 || collision.numPhi() < 2) + return; + + for (auto hqtrackd1 : hqtracks) { + if (hqtrackd1.hqId() != 333) + continue; + + if (hqtrackd1.hqMass() < minPhiMass || hqtrackd1.hqMass() > maxPhiMass) + continue; + + DauVec1 = ROOT::Math::PxPyPzMVector(hqtrackd1.hqd1Px(), hqtrackd1.hqd1Py(), hqtrackd1.hqd1Pz(), massKa); + DauVec2 = ROOT::Math::PxPyPzMVector(hqtrackd1.hqd2Px(), hqtrackd1.hqd2Py(), hqtrackd1.hqd2Pz(), massKa); + + if (!selectionPIDKaon(hqtrackd1.hqd1TPC(), hqtrackd1.hqd1TOF(), hqtrackd1.hqd1TOFHit(), cfgPIDStrategy, DauVec1.Pt())) + continue; + + if (!selectionPIDKaon(hqtrackd1.hqd2TPC(), hqtrackd1.hqd2TOF(), hqtrackd1.hqd2TOFHit(), cfgPIDStrategy, DauVec2.Pt())) + continue; + + HQ1.SetXYZM(hqtrackd1.hqPx(), hqtrackd1.hqPy(), hqtrackd1.hqPz(), hqtrackd1.hqMass()); + + histos.fill(HIST("hnsigmaTPCKa"), hqtrackd1.hqd1TPC(), DauVec1.Pt()); + histos.fill(HIST("hnsigmaTPCKa"), hqtrackd1.hqd2TPC(), DauVec2.Pt()); + if (hqtrackd1.hqd1TOFHit()) + histos.fill(HIST("hnsigmaTOFKa"), hqtrackd1.hqd1TOF(), DauVec1.Pt()); + if (hqtrackd1.hqd2TOFHit()) + histos.fill(HIST("hnsigmaTOFKa"), hqtrackd1.hqd2TOF(), DauVec2.Pt()); + + auto hqd1id = hqtrackd1.index(); + histos.fill(HIST("hPhid1Mass"), HQ1.M(), HQ1.Pt()); + + for (auto hqtrackd2 : hqtracks) { + auto hqd2id = hqtrackd2.index(); + if (hqd2id <= hqd1id) + continue; + + if (hqtrackd2.hqId() != 333) + continue; + + if (hqtrackd2.hqMass() < minPhiMass || hqtrackd2.hqMass() > maxPhiMass) + continue; + + DauVec1 = ROOT::Math::PxPyPzMVector(hqtrackd2.hqd1Px(), hqtrackd2.hqd1Py(), hqtrackd2.hqd1Pz(), massKa); + DauVec2 = ROOT::Math::PxPyPzMVector(hqtrackd2.hqd2Px(), hqtrackd2.hqd2Py(), hqtrackd2.hqd2Pz(), massKa); + + if (!selectionPIDKaon(hqtrackd2.hqd1TPC(), hqtrackd2.hqd1TOF(), hqtrackd2.hqd1TOFHit(), cfgPIDStrategy, DauVec1.Pt())) + continue; + + if (!selectionPIDKaon(hqtrackd2.hqd2TPC(), hqtrackd2.hqd2TOF(), hqtrackd2.hqd2TOFHit(), cfgPIDStrategy, DauVec2.Pt())) + continue; + + if (hqtrackd1.hqd1Index() == hqtrackd2.hqd1Index()) + continue; + + if (hqtrackd1.hqd2Index() == hqtrackd2.hqd2Index()) + continue; + + HQ2.SetXYZM(hqtrackd2.hqPx(), hqtrackd2.hqPy(), hqtrackd2.hqPz(), hqtrackd2.hqMass()); + + histos.fill(HIST("hnsigmaTPCKa"), hqtrackd2.hqd1TPC(), DauVec1.Pt()); + histos.fill(HIST("hnsigmaTPCKa"), hqtrackd2.hqd2TPC(), DauVec2.Pt()); + if (hqtrackd2.hqd1TOFHit()) + histos.fill(HIST("hnsigmaTOFKa"), hqtrackd2.hqd1TOF(), DauVec1.Pt()); + if (hqtrackd2.hqd2TOFHit()) + histos.fill(HIST("hnsigmaTOFKa"), hqtrackd2.hqd2TOF(), DauVec2.Pt()); + histos.fill(HIST("hPhid2Mass"), HQ2.M(), HQ2.Pt()); + + for (auto hqtrackd3 : hqtracks) { + if (std::abs(hqtrackd3.hqId()) != 3122) + continue; + + if (hqtrackd3.hqMass() < minLambdaMass || hqtrackd3.hqMass() > maxLambdaMass) + continue; + + int isLambda = static_cast(hqtrackd3.hqId() < 0); + + if (hqtrackd3.hqId() > 0) { + DauVec1 = ROOT::Math::PxPyPzMVector(hqtrackd3.hqd1Px(), hqtrackd3.hqd1Py(), hqtrackd3.hqd1Pz(), massPr); + DauVec2 = ROOT::Math::PxPyPzMVector(hqtrackd3.hqd2Px(), hqtrackd3.hqd2Py(), hqtrackd3.hqd2Pz(), massPi); + } else if (hqtrackd3.hqId() < 0) { + DauVec1 = ROOT::Math::PxPyPzMVector(hqtrackd3.hqd1Px(), hqtrackd3.hqd1Py(), hqtrackd3.hqd1Pz(), massPi); + DauVec2 = ROOT::Math::PxPyPzMVector(hqtrackd3.hqd2Px(), hqtrackd3.hqd2Py(), hqtrackd3.hqd2Pz(), massPr); + } + + if (std::abs(hqtrackd3.hqd1TPC()) > cfgPIDPrPi || std::abs(hqtrackd3.hqd2TPC()) > cfgPIDPrPi) + continue; + + if (hqtrackd1.hqd1Index() == hqtrackd3.hqd1Index()) + continue; + + if (hqtrackd1.hqd2Index() == hqtrackd3.hqd2Index()) + continue; + + if (hqtrackd2.hqd1Index() == hqtrackd3.hqd1Index()) + continue; + + if (hqtrackd2.hqd2Index() == hqtrackd3.hqd2Index()) + continue; + + HQ3.SetXYZM(hqtrackd3.hqPx(), hqtrackd3.hqPy(), hqtrackd3.hqPz(), hqtrackd3.hqMass()); + histos.fill(HIST("hLambdaMass"), HQ3.M(), HQ3.Pt()); + + if (hqtrackd3.hqId() > 0) { + histos.fill(HIST("hnsigmaTPCPr"), hqtrackd3.hqd1TPC(), DauVec1.Pt()); + histos.fill(HIST("hnsigmaTPCPi"), hqtrackd3.hqd2TPC(), DauVec2.Pt()); + } else if (hqtrackd3.hqId() < 0) { + histos.fill(HIST("hnsigmaTPCPi"), hqtrackd3.hqd1TPC(), DauVec1.Pt()); + histos.fill(HIST("hnsigmaTPCPr"), hqtrackd3.hqd2TPC(), DauVec2.Pt()); + } + + exotic = HQ1 + HQ2 + HQ3; + HQ12 = HQ1 + HQ2; + HQ13 = HQ1 + HQ3; + + histos.fill(HIST("h_InvMass_same"), exotic.M(), exotic.Pt(), collision.centrality()); + histos.fill(HIST("hDalitz"), HQ12.M2(), HQ13.M2(), exotic.M(), exotic.Pt(), isLambda, collision.centrality()); + + if (cfgRotBkg) { + for (int nr = 0; nr < cfgNRotBkg; nr++) { + auto RanPhiForD2 = rn->Uniform(o2::constants::math::PI * 5.0 / 6.0, o2::constants::math::PI * 7.0 / 6.0); + auto RanPhiForD3 = rn->Uniform(o2::constants::math::PI * 5.0 / 6.0, o2::constants::math::PI * 7.0 / 6.0); + + RanPhiForD2 += HQ2.Phi(); + RanPhiForD3 += HQ3.Phi(); + + HQ2Rot.SetXYZM(HQ2.Pt() * std::cos(RanPhiForD2), HQ2.Pt() * std::sin(RanPhiForD2), HQ2.Pz(), HQ2.M()); + HQ3Rot.SetXYZM(HQ3.Pt() * std::cos(RanPhiForD3), HQ3.Pt() * std::sin(RanPhiForD3), HQ3.Pz(), HQ3.M()); + + exoticRot2 = HQ1 + HQ2Rot + HQ3; + exoticRot3 = HQ1 + HQ2 + HQ3Rot; + exoticRot23 = HQ1 + HQ2Rot + HQ3Rot; + + HQ12Rot = HQ1 + HQ2Rot; + HQ13Rot = HQ1 + HQ3Rot; + + histos.fill(HIST("h_InvMass_rotPhi"), exoticRot2.M(), exoticRot2.Pt(), collision.centrality()); + histos.fill(HIST("h_InvMass_rotLambda"), exoticRot3.M(), exoticRot3.Pt(), collision.centrality()); + histos.fill(HIST("h_InvMass_rotPhiLambda"), exoticRot23.M(), exoticRot23.Pt(), collision.centrality()); + histos.fill(HIST("hDalitzRot"), HQ12Rot.M2(), HQ13Rot.M2(), exoticRot23.M(), exoticRot23.Pt(), isLambda, collision.centrality()); + } + } + } + } + } + } + PROCESS_SWITCH(heptaquark, processSameEvent, "Process same event", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/Resonances/higherMassResonances.cxx b/PWGLF/Tasks/Resonances/higherMassResonances.cxx new file mode 100644 index 00000000000..252fdd6d658 --- /dev/null +++ b/PWGLF/Tasks/Resonances/higherMassResonances.cxx @@ -0,0 +1,1215 @@ +// 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 higherMassResonances.cxx +/// \brief glueball resonance +/// \author Sawan + +// #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "TF1.h" +#include "TRandom3.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/StepTHn.h" +#include "ReconstructionDataFormats/Track.h" +#include "Framework/O2DatabasePDGPlugin.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" // +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" // +#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" // +#include "Framework/runDataProcessing.h" // +#include "PWGLF/DataModel/LFStrangenessTables.h" // + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +// using namespace o2::constants::physics; +using std::array; + +struct HigherMassResonances { + SliceCache cache; + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rKzeroShort{"kzeroShort", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry hglue{"hglueball", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry hMChists{"hMChists", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + struct : ConfigurableGroup { + // PID and QA + Configurable qAv0{"qAv0", false, "qAv0"}; + Configurable qAPID{"qAPID", true, "qAPID"}; + // Configurable qAv0Daughters{"qAv0Daughters", false, "QA of v0 daughters"}; + Configurable qAevents{"qAevents", false, "QA of events"}; + // Configurable invMass1D{"invMass1D", false, "1D invariant mass histograms"}; + Configurable correlation2Dhist{"correlation2Dhist", true, "Lamda K0 mass correlation"}; + Configurable cDCAv0topv{"cDCAv0topv", false, "DCA V0 to PV"}; + Configurable armcut{"armcut", false, "arm cut"}; + Configurable globalTracks{"globalTracks", false, "Global tracks"}; + Configurable hasTPC{"hasTPC", false, "TPC"}; + Configurable selectTWOKsOnly{"selectTWOKsOnly", true, "Select only events with two K0s"}; + + // Configurables for event selection + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable cfgETAcut{"cfgETAcut", 0.8f, "Track ETA cut"}; + Configurable timFrameEvsel{"timFrameEvsel", false, "TPC Time frame boundary cut"}; + Configurable piluprejection{"piluprejection", false, "Pileup rejection"}; + Configurable goodzvertex{"goodzvertex", false, "removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference."}; + Configurable itstpctracks{"itstpctracks", false, "selects collisions with at least one ITS-TPC track,"}; + Configurable additionalEvsel{"additionalEvsel", false, "Additional event selcection"}; + // Configurable applyOccupancyCut{"applyOccupancyCut", false, "Apply occupancy cut"}; + // Configurable occupancyCut{"occupancyCut", 1000, "Mimimum Occupancy cut"}; + + // Configurable parameters for V0 selection + Configurable confV0DCADaughMax{"confV0DCADaughMax", 1.0f, "DCA b/w V0 daughters"}; + Configurable v0settingDcapostopv{"v0settingDcapostopv", 0.06, "DCA Pos To PV"}; + Configurable v0settingDcanegtopv{"v0settingDcanegtopv", 0.06, "DCA Neg To PV"}; + Configurable cMaxV0DCA{"cMaxV0DCA", 1, "DCA V0 to PV"}; + // Configurable isStandarv0{"isStandarv0", false, "Standard V0"}; + // Configurable ConfDaughDCAMin{"ConfDaughDCAMin", 0.06f, "V0 Daugh sel: Max. DCA Daugh to PV (cm)"}; // same as DCA pos to pv and neg to pv + Configurable confV0PtMin{"confV0PtMin", 0.f, "Minimum transverse momentum of V0"}; + Configurable confV0CPAMin{"confV0CPAMin", 0.97f, "Minimum CPA of V0"}; + Configurable confV0TranRadV0Min{"confV0TranRadV0Min", 0.5f, "Minimum transverse radius"}; + Configurable confV0TranRadV0Max{"confV0TranRadV0Max", 200.f, "Maximum transverse radius"}; + Configurable cMaxV0LifeTime{"cMaxV0LifeTime", 15, "Maximum V0 life time"}; + Configurable cSigmaMassKs0{"cSigmaMassKs0", 4, "n Sigma cut on Ks0 mass (Mass (Ks) - cSigmaMassKs0*cWidthKs0)"}; + Configurable cWidthKs0{"cWidthKs0", 0.005, "Width of KS0"}; + Configurable confDaughEta{"confDaughEta", 0.8f, "V0 Daugh sel: max eta"}; + Configurable confDaughTPCnclsMin{"confDaughTPCnclsMin", 70.f, "V0 Daugh sel: Min. nCls TPC"}; + Configurable confDaughPIDCuts{"confDaughPIDCuts", 5, "PID selections for KS0 daughters"}; + Configurable confarmcut{"confarmcut", 0.2f, "Armenteros cut"}; + Configurable confKsrapidity{"confKsrapidity", 0.5f, "Rapidity cut on K0s"}; + // Configurable lowmasscutks0{"lowmasscutks0", 0.497 - 4 * 0.005, "Low mass cut on K0s"}; + // Configurable highmasscutks0{"highmasscutks0", 0.497 + 4 * 0.005, "High mass cut on K0s"}; + Configurable applyAngSepCut{"applyAngSepCut", false, "Apply angular separation cut"}; + Configurable angSepCut{"angSepCut", 0.01f, "Angular separation cut"}; + + // Configurable for track selection and multiplicity + Configurable cfgPTcut{"cfgPTcut", 0.2f, "Track PT cut"}; + Configurable cfgNmixedEvents{"cfgNmixedEvents", 5, "Number of mixed events"}; + Configurable cfgMultFOTM{"cfgMultFOTM", true, "Use FOTM multiplicity if pp else use 0 here for PbPb (FT0C)"}; + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 5., 10., 30., 50., 70., 100., 110., 150.}, "Binning of the centrality axis"}; + + // Configurable for MC + Configurable allGenCollisions{"allGenCollisions", true, "To fill all generated collisions for the signal loss calculations"}; + Configurable cTVXEvsel{"cTVXEvsel", true, "Triggger selection"}; + Configurable avoidsplitrackMC{"avoidsplitrackMC", false, "avoid split track in MC"}; + Configurable selectMCparticles{"selectMCparticles", 1, "0: f0(1710), 1: f2(1525), 2: a2(1320), 3: f0(1370), 4: f0(1500)"}; + std::vector pdgCodes = {10331, 335, 115, 10221, 9030221}; + + // output THnSparses + Configurable activateTHnSparseCosThStarHelicity{"activateTHnSparseCosThStarHelicity", false, "Activate the THnSparse with cosThStar w.r.t. helicity axis"}; + Configurable activateTHnSparseCosThStarProduction{"activateTHnSparseCosThStarProduction", false, "Activate the THnSparse with cosThStar w.r.t. production axis"}; + Configurable activateTHnSparseCosThStarBeam{"activateTHnSparseCosThStarBeam", true, "Activate the THnSparse with cosThStar w.r.t. beam axis (Gottified jackson frame)"}; + Configurable activateTHnSparseCosThStarRandom{"activateTHnSparseCosThStarRandom", false, "Activate the THnSparse with cosThStar w.r.t. random axis"}; + Configurable cRotations{"cRotations", 3, "Number of random rotations in the rotational background"}; + + // Other cuts on Ks and glueball + // Configurable rapidityks{"rapidityks", true, "rapidity cut on K0s"}; + Configurable applyCompetingcut{"applyCompetingcut", false, "Competing cascade rejection cut"}; + Configurable competingcascrejlambda{"competingcascrejlambda", 0.005, "rejecting competing cascade lambda"}; + Configurable competingcascrejlambdaanti{"competingcascrejlambdaanti", 0.005, "rejecting competing cascade anti-lambda"}; // If one of the pions is misidentified as a proton, then instead of Ks we reconstruct lambda, therefore the competing cascade rejection cut is applied in which if the reconstrcted mass of a pion and proton (which we are assuming to be misidentified as proton) is close to lambda or anti-lambda, then the track is rejected + Configurable tpcCrossedrows{"tpcCrossedrows", 70, "TPC crossed rows"}; + Configurable tpcCrossedrowsOverfcls{"tpcCrossedrowsOverfcls", 0.8, "TPC crossed rows over findable clusters"}; + + // Mass and pT axis as configurables + Configurable cPtMin{"cPtMin", 0.0f, "Minimum pT"}; + Configurable cPtMax{"cPtMax", 30.0f, "Maximum pT"}; + Configurable cPtBins{"cPtBins", 300, "Number of pT bins"}; + Configurable cMassMin{"cMassMin", 0.9f, "Minimum mass of glueball"}; + Configurable cMassMax{"cMassMax", 3.0f, "Maximum mass of glueball"}; + Configurable cMassBins{"cMassBins", 210, "Number of mass bins for glueball"}; + Configurable ksMassMin{"ksMassMin", 0.45f, "Minimum mass of K0s"}; + Configurable ksMassMax{"ksMassMax", 0.55f, "Maximum mass of K0s"}; + Configurable ksMassBins{"ksMassBins", 200, "Number of mass bins for K0s"}; + Configurable rotationalCut{"rotationalCut", 10, "Cut value (Rotation angle pi - pi/cut and pi + pi/cut)"}; + ConfigurableAxis configThnAxisPOL{"configThnAxisPOL", {20, -1.0, 1.0}, "Costheta axis"}; + // ConfigurableAxis axisdEdx{"axisdEdx", {20000, 0.0f, 200.0f}, "dE/dx (a.u.)"}; + // ConfigurableAxis axisPtfordEbydx{"axisPtfordEbydx", {2000, 0, 20}, "pT (GeV/c)"}; + // ConfigurableAxis axisMultdist{"axisMultdist", {3500, 0, 70000}, "Multiplicity distribution"}; + // ConfigurableAxis occupancyBins{"occupancyBins", {VARIABLE_WIDTH, 0.0, 100, 500, 600, 1000, 1100, 1500, 1600, 2000, 2100, 2500, 2600, 3000, 3100, 3500, 3600, 4000, 4100, 4500, 4600, 5000, 5100, 9999}, "Binning: occupancy axis"}; + } config; + + // Service PDGdatabase; + TRandom* rn = new TRandom(); + + // variables declaration + TLorentzVector lv1, lv2, lv3, lv4, lv5; + float multiplicity = 0.0f; + float theta2; + ROOT::Math::PxPyPzMVector daughter1, daughter2, fourVecDau1, fourVecMother, fourVecDauCM; + ROOT::Math::XYZVector threeVecDauCM, helicityVec, randomVec, beamVec, normalVec; + // const double massK0s = o2::constants::physics::MassK0Short; + bool isMix = false; + + void init(InitContext const&) + { + // Axes + AxisSpec k0ShortMassAxis = {config.ksMassBins, config.ksMassMin, config.ksMassMax, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec glueballMassAxis = {config.cMassBins, config.cMassMin, config.cMassMax, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec vertexZAxis = {60, -15.f, 15.f, "vrtx_{Z} [cm]"}; // for histogram + AxisSpec ptAxis = {config.cPtBins, config.cPtMin, config.cPtMax, "#it{p}_{T} (GeV/#it{c})"}; + // AxisSpec multiplicityAxis = {110, 0.0f, 150.0f, "Multiplicity Axis"}; + AxisSpec multiplicityAxis = {config.binsCent, "Multiplicity Axis"}; + AxisSpec thnAxisPOL{config.configThnAxisPOL, "Configurabel theta axis"}; + // AxisSpec occupancyAxis = {occupancyBins, "Occupancy [-40,100]"}; + + // THnSparses + std::array sparses = {config.activateTHnSparseCosThStarHelicity, config.activateTHnSparseCosThStarProduction, config.activateTHnSparseCosThStarBeam, config.activateTHnSparseCosThStarRandom}; + + // std::array sparses = {config.activateTHnSparseCosThStarHelicity}; + + if (std::accumulate(sparses.begin(), sparses.end(), 0) == 0) { + LOGP(fatal, "No output THnSparses enabled"); + } else { + if (config.activateTHnSparseCosThStarHelicity) { + LOGP(info, "THnSparse with cosThStar w.r.t. helicity axis active."); + } + if (config.activateTHnSparseCosThStarProduction) { + LOGP(info, "THnSparse with cosThStar w.r.t. production axis active."); + } + if (config.activateTHnSparseCosThStarBeam) { + LOGP(info, "THnSparse with cosThStar w.r.t. beam axis active. (Gottified jackson frame)"); + } + if (config.activateTHnSparseCosThStarRandom) { + LOGP(info, "THnSparse with cosThStar w.r.t. random axis active."); + } + } + + // Event selection + if (config.qAevents) { + rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); + rEventSelection.add("hmultiplicity", "multiplicity percentile distribution", {HistType::kTH1F, {{150, 0.0f, 150.0f}}}); + // rEventSelection.add("multdist_FT0M", "FT0M Multiplicity distribution", kTH1F, {config.axisMultdist}); + // rEventSelection.add("multdist_FT0A", "FT0A Multiplicity distribution", kTH1F, {config.axisMultdist}); + // rEventSelection.add("multdist_FT0C", "FT0C Multiplicity distribution", kTH1F, {config.axisMultdist}); + // rEventSelection.add("hNcontributor", "Number of primary vertex contributor", kTH1F, {{2000, 0.0f, 10000.0f}}); + } + + hglue.add("h3glueInvMassDS", "h3glueInvMassDS", kTHnSparseF, {multiplicityAxis, ptAxis, glueballMassAxis, thnAxisPOL}, true); + hglue.add("h3glueInvMassME", "h3glueInvMassME", kTHnSparseF, {multiplicityAxis, ptAxis, glueballMassAxis, thnAxisPOL}, true); + hglue.add("h3glueInvMassRot", "h3glueInvMassRot", kTHnSparseF, {multiplicityAxis, ptAxis, glueballMassAxis, thnAxisPOL}, true); + hglue.add("heventscheck", "heventscheck", kTH1I, {{10, 0, 10}}); + hglue.add("htrackscheck_v0", "htrackscheck_v0", kTH1I, {{15, 0, 15}}); + hglue.add("htrackscheck_v0_daughters", "htrackscheck_v0_daughters", kTH1I, {{15, 0, 15}}); + + // K0s topological/PID cuts + if (config.correlation2Dhist) { + rKzeroShort.add("mass_lambda_kshort_before", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + // rKzeroShort.add("mass_lambda_kshort_after1", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + // rKzeroShort.add("mass_lambda_kshort_after2", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + // rKzeroShort.add("mass_lambda_kshort_after3", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + // rKzeroShort.add("mass_lambda_kshort_after4", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + // rKzeroShort.add("mass_lambda_kshort_after5", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + // rKzeroShort.add("mass_lambda_kshort_after6", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + // rKzeroShort.add("mass_lambda_kshort_after7", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + // rKzeroShort.add("mass_lambda_kshort_after8", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + // rKzeroShort.add("mass_lambda_kshort_after9", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + rKzeroShort.add("mass_lambda_kshort_after10", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + } + if (config.qAv0) { + // Invariant Mass + rKzeroShort.add("hMassK0Shortbefore", "hMassK0Shortbefore", kTHnSparseF, {k0ShortMassAxis, ptAxis}); + rKzeroShort.add("hMasscorrelationbefore", "hMasscorrelationbefore", kTH2F, {k0ShortMassAxis, k0ShortMassAxis}); + rKzeroShort.add("hMassK0ShortSelected", "hMassK0ShortSelected", kTHnSparseF, {k0ShortMassAxis, ptAxis}); + // Topological histograms (after the selection) + rKzeroShort.add("hDCAV0Daughters", "DCA between v0 daughters", {HistType::kTH1F, {{60, -3.0f, 3.0f}}}); + rKzeroShort.add("hV0CosPA", "hV0CosPA", {HistType::kTH1F, {{100, 0.96f, 1.1f}}}); + rKzeroShort.add("hLT", "hLT", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); + rKzeroShort.add("angularSeparation", "Angular distribution between two K0s vs pT", {HistType::kTH1F, {{200, 0.0f, 4.0f}}}); + // rKzeroShort.add("Mass_lambda", "Mass under lambda hypothesis", kTH1F, {glueballMassAxis}); + // rKzeroShort.add("mass_AntiLambda", "Mass under anti-lambda hypothesis", kTH1F, {glueballMassAxis}); + // rKzeroShort.add("mass_Gamma", "Mass under Gamma hypothesis", kTH1F, {glueballMassAxis}); + + // rKzeroShort.add("mass_Hypertriton", "Mass under hypertriton hypothesis", kTH1F, {glueballMassAxis}); + // rKzeroShort.add("mass_AnitHypertriton", "Mass under anti-hypertriton hypothesis", kTH1F, {glueballMassAxis}); + // rKzeroShort.add("rapidity", "Rapidity distribution", kTH1F, {{100, -1.0f, 1.0f}}); + // rKzeroShort.add("hv0radius", "hv0radius", kTH1F, {{100, 0.0f, 200.0f}}); + // rKzeroShort.add("hDCApostopv", "DCA positive daughter to PV", kTH1F, {{1000, -10.0f, 10.0f}}); + // rKzeroShort.add("hDCAnegtopv", "DCA negative daughter to PV", kTH1F, {{1000, -10.0f, 10.0f}}); + // rKzeroShort.add("hcDCAv0topv", "DCA V0 to PV", kTH1F, {{60, -3.0f, 3.0f}}); + // rKzeroShort.add("halpha", "Armenteros alpha", kTH1F, {{100, -5.0f, 5.0f}}); + // rKzeroShort.add("hqtarmbyalpha", "qtarm/alpha", kTH1F, {{100, 0.0f, 1.0f}}); + // rKzeroShort.add("hpsipair", "psi pair angle", kTH1F, {{100, -5.0f, 5.0f}}); + + // // Topological histograms (before the selection) + // rKzeroShort.add("hDCAV0Daughters_before", "DCA between v0 daughters before the selection", {HistType::kTH1F, {{60, -3.0f, 3.0f}}}); + // rKzeroShort.add("hV0CosPA_before", "hV0CosPA_before", {HistType::kTH1F, {{200, 0.91f, 1.1f}}}); + // rKzeroShort.add("hLT_before", "hLT_before", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); + } + rKzeroShort.add("NksProduced", "Number of K0s produced", kTH1I, {{15, -0.5, 14.5}}); + + if (config.qAPID) { + rKzeroShort.add("hNSigmaPosPionK0s_before", "hNSigmaPosPionK0s_before", {HistType::kTH2F, {{ptAxis}, {100, -5.f, 5.f}}}); + rKzeroShort.add("hNSigmaPosPionK0s_after", "hNSigmaPosPionK0s_after", {HistType::kTH2F, {{ptAxis}, {100, -5.f, 5.f}}}); + rKzeroShort.add("hNSigmaNegPionK0s_before", "hNSigmaNegPionK0s_before", {HistType::kTH2F, {{ptAxis}, {100, -5.f, 5.f}}}); + rKzeroShort.add("hNSigmaNegPionK0s_after", "hNSigmaNegPionK0s_after", {HistType::kTH2F, {{ptAxis}, {100, -5.f, 5.f}}}); + // rKzeroShort.add("dE_by_dx_TPC", "dE/dx signal in the TPC as a function of pT", kTH2F, {config.axisPtfordEbydx, config.axisdEdx}); + } + // if (config.qAv0Daughters) { + // rKzeroShort.add("negative_pt", "Negative daughter pT", kTH1F, {ptAxis}); + // rKzeroShort.add("positive_pt", "Positive daughter pT", kTH1F, {ptAxis}); + // rKzeroShort.add("negative_eta", "Negative daughter eta", kTH1F, {{100, -1.0f, 1.0f}}); + // rKzeroShort.add("positive_eta", "Positive daughter eta", kTH1F, {{100, -1.0f, 1.0f}}); + // rKzeroShort.add("negative_phi", "Negative daughter phi", kTH1F, {{70, 0.0f, 7.0f}}); + // rKzeroShort.add("positive_phi", "Positive daughter phi", kTH1F, {{70, 0.0f, 7.0f}}); + // } + + // For MC + hMChists.add("events_check", "No. of events in the generated MC", kTH1I, {{20, 0, 20}}); + hMChists.add("events_checkrec", "No. of events in the reconstructed MC", kTH1I, {{20, 0, 20}}); + hMChists.add("Genf1710", "Gen f_{0}(1710)", kTHnSparseF, {multiplicityAxis, ptAxis}); + hMChists.add("Recf1710_pt1", "Rec f_{0}(1710) p_{T}", kTHnSparseF, {multiplicityAxis, ptAxis, glueballMassAxis}); + hMChists.add("Recf1710_pt2", "Rec f_{0}(1710) p_{T}", kTHnSparseF, {multiplicityAxis, ptAxis, glueballMassAxis}); + hMChists.add("Recf1710_p", "Rec f_{0}(1710) p", kTH1F, {ptAxis}); + hMChists.add("h1Recsplit", "Rec p_{T}2", kTH1F, {ptAxis}); + + hMChists.add("Recf1710_mass", "Rec f_{0}(1710) mass", kTH1F, {glueballMassAxis}); + hMChists.add("Genf1710_mass", "Gen f_{0}(1710) mass", kTH1F, {glueballMassAxis}); + hMChists.add("GenEta", "Gen Eta", kTHnSparseF, {ptAxis, {100, -1.0f, 1.0f}}); + hMChists.add("GenPhi", "Gen Phi", kTH1F, {{70, -3.5f, 3.5f}}); + hMChists.add("GenRapidity", "Gen Rapidity", kTHnSparseF, {ptAxis, {100, -1.0f, 1.0f}}); + hMChists.add("RecEta", "Rec Eta", kTH1F, {{100, -1.0f, 1.0f}}); + hMChists.add("RecPhi", "Rec Phi", kTH1F, {{70, 0.0f, 7.0f}}); + hMChists.add("RecRapidity", "Rec Rapidity", kTH1F, {{100, -1.0f, 1.0f}}); + hMChists.add("MC_mult", "Multiplicity in MC", kTH1F, {multiplicityAxis}); + hMChists.add("MC_mult_after_event_sel", "Multiplicity in MC", kTH1F, {multiplicityAxis}); + // hMChists.add("GenPx", "Gen Px", kTH1F, {{100, -10.0f, 10.0f}}); + // hMChists.add("GenPy", "Gen Py", kTH1F, {{100, -10.0f, 10.0f}}); + // hMChists.add("GenPz", "Gen Pz", kTH1F, {{100, -10.0f, 10.0f}}); + } + + template + bool eventselection(Collision const& collision) + { + hglue.fill(HIST("heventscheck"), 1.5); + + if (config.timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + return false; + } + hglue.fill(HIST("heventscheck"), 2.5); + + if (!collision.sel8()) { + return false; + } + hglue.fill(HIST("heventscheck"), 3.5); + + if (config.piluprejection && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + hglue.fill(HIST("heventscheck"), 4.5); + + if (config.goodzvertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + hglue.fill(HIST("heventscheck"), 5.5); + + if (config.itstpctracks && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + hglue.fill(HIST("heventscheck"), 6.5); + + return true; + } + + template + bool selectionV0(Collision const& collision, V0 const& candidate, float /*multiplicity*/) + { + const float qtarm = candidate.qtarm(); + const float alph = candidate.alpha(); + float arm = qtarm / alph; + const float pT = candidate.pt(); + const float tranRad = candidate.v0radius(); + const float dcaDaughv0 = candidate.dcaV0daughters(); + const float cpav0 = candidate.v0cosPA(); + + float ctauK0s = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short; + float lowmasscutks0 = 0.497 - config.cWidthKs0 * config.cSigmaMassKs0; + float highmasscutks0 = 0.497 + config.cWidthKs0 * config.cSigmaMassKs0; + // float decayLength = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * RecoDecay::sqrtSumOfSquares(candidate.px(), candidate.py(), candidate.pz()); + + if (config.qAv0) { + rKzeroShort.fill(HIST("hMassK0Shortbefore"), candidate.mK0Short(), candidate.pt()); + rKzeroShort.fill(HIST("hLT"), ctauK0s); + rKzeroShort.fill(HIST("hDCAV0Daughters"), candidate.dcaV0daughters()); + rKzeroShort.fill(HIST("hV0CosPA"), candidate.v0cosPA()); + // rKzeroShort.fill(HIST("Mass_lambda"), candidate.mLambda()); + // rKzeroShort.fill(HIST("mass_AntiLambda"), candidate.mAntiLambda()); + // rKzeroShort.fill(HIST("mass_Gamma"), candidate.mGamma()); + // rKzeroShort.fill(HIST("mass_Hypertriton"), candidate.mHypertriton()); + // rKzeroShort.fill(HIST("mass_AnitHypertriton"), candidate.mAntiHypertriton()); + // rKzeroShort.fill(HIST("rapidity"), candidate.yK0Short()); + // rKzeroShort.fill(HIST("hv0radius"), candidate.v0radius()); + // rKzeroShort.fill(HIST("hDCApostopv"), candidate.dcapostopv()); + // rKzeroShort.fill(HIST("hDCAnegtopv"), candidate.dcanegtopv()); + // rKzeroShort.fill(HIST("hcDCAv0topv"), candidate.dcav0topv()); + // rKzeroShort.fill(HIST("halpha"), candidate.alpha()); + // rKzeroShort.fill(HIST("hqtarmbyalpha"), arm); + // rKzeroShort.fill(HIST("hpsipair"), candidate.psipair()); + } + if (config.correlation2Dhist) + rKzeroShort.fill(HIST("mass_lambda_kshort_before"), candidate.mK0Short(), candidate.mLambda()); + + hglue.fill(HIST("htrackscheck_v0"), 0.5); + + if (config.cDCAv0topv && std::fabs(candidate.dcav0topv()) > config.cMaxV0DCA) { + return false; + } + hglue.fill(HIST("htrackscheck_v0"), 1.5); + // if (config.correlation2Dhist) + // rKzeroShort.fill(HIST("mass_lambda_kshort_after1"), candidate.mK0Short(), candidate.mLambda()); + + // if (config.rapidityks && std::abs(candidate.yK0Short()) >= config.confKsrapidity) { + // return false; + // } + if (std::abs(candidate.yK0Short()) >= config.confKsrapidity) { + return false; + } + hglue.fill(HIST("htrackscheck_v0"), 2.5); + // if (config.correlation2Dhist) + // rKzeroShort.fill(HIST("mass_lambda_kshort_after2"), candidate.mK0Short(), candidate.mLambda()); + + if (pT < config.confV0PtMin) { + return false; + } + hglue.fill(HIST("htrackscheck_v0"), 3.5); + // if (config.correlation2Dhist) + // rKzeroShort.fill(HIST("mass_lambda_kshort_after3"), candidate.mK0Short(), candidate.mLambda()); + + if (dcaDaughv0 > config.confV0DCADaughMax) { + return false; + } + hglue.fill(HIST("htrackscheck_v0"), 4.5); + // if (config.correlation2Dhist) + // rKzeroShort.fill(HIST("mass_lambda_kshort_after4"), candidate.mK0Short(), candidate.mLambda()); + + if (cpav0 < config.confV0CPAMin) { + return false; + } + hglue.fill(HIST("htrackscheck_v0"), 5.5); + // if (config.correlation2Dhist) + // rKzeroShort.fill(HIST("mass_lambda_kshort_after5"), candidate.mK0Short(), candidate.mLambda()); + + if (tranRad < config.confV0TranRadV0Min) { + return false; + } + hglue.fill(HIST("htrackscheck_v0"), 6.5); + // if (config.correlation2Dhist) + // rKzeroShort.fill(HIST("mass_lambda_kshort_after6"), candidate.mK0Short(), candidate.mLambda()); + + if (tranRad > config.confV0TranRadV0Max) { + return false; + } + hglue.fill(HIST("htrackscheck_v0"), 7.5); + // if (config.correlation2Dhist) + // rKzeroShort.fill(HIST("mass_lambda_kshort_after7"), candidate.mK0Short(), candidate.mLambda()); + + if (std::fabs(ctauK0s) > config.cMaxV0LifeTime) { + return false; + } + hglue.fill(HIST("htrackscheck_v0"), 8.5); + // if (config.correlation2Dhist) + // rKzeroShort.fill(HIST("mass_lambda_kshort_after8"), candidate.mK0Short(), candidate.mLambda()); + + if (config.armcut && arm < config.confarmcut) { + return false; + } + hglue.fill(HIST("htrackscheck_v0"), 9.5); + // if (config.correlation2Dhist) + // rKzeroShort.fill(HIST("mass_lambda_kshort_after9"), candidate.mK0Short(), candidate.mLambda()); + + // if (config.applyCompetingcut && (std::abs(candidate.mLambda() - PDGdatabase->Mass(3122)) <= config.competingcascrejlambda || std::abs(candidate.mAntiLambda() - PDGdatabase->Mass(-3122)) <= config.competingcascrejlambdaanti)) + if (config.applyCompetingcut && (std::abs(candidate.mLambda() - o2::constants::physics::MassLambda0) <= config.competingcascrejlambda || std::abs(candidate.mAntiLambda() - o2::constants::physics::MassLambda0) <= config.competingcascrejlambdaanti)) { + return false; + } + hglue.fill(HIST("htrackscheck_v0"), 10.5); + if (config.correlation2Dhist) + rKzeroShort.fill(HIST("mass_lambda_kshort_after10"), candidate.mK0Short(), candidate.mLambda()); + + if (config.qAv0) { + rKzeroShort.fill(HIST("hMassK0ShortSelected"), candidate.mK0Short(), candidate.pt()); + // rKzeroShort.fill(HIST("mass_lambda_kshort_after"), candidate.mK0Short(), candidate.mLambda()); + } + + if (candidate.mK0Short() < lowmasscutks0 || candidate.mK0Short() > highmasscutks0) { + return false; + } + return true; + } + + template + bool isSelectedV0Daughter(T const& track, float charge, double nsigmaV0Daughter, V0s const& /*candidate*/) + { + if (config.qAPID) { + // Filling the PID of the V0 daughters in the region of the K0 peak. + (charge == 1) ? rKzeroShort.fill(HIST("hNSigmaPosPionK0s_before"), track.tpcInnerParam(), track.tpcNSigmaPi()) : rKzeroShort.fill(HIST("hNSigmaNegPionK0s_before"), track.tpcInnerParam(), track.tpcNSigmaPi()); + // rKzeroShort.fill(HIST("dE_by_dx_TPC"), track.p(), track.tpcSignal()); + } + const auto eta = track.eta(); + const auto tpcNClsF = track.tpcNClsFound(); + const auto sign = track.sign(); + + hglue.fill(HIST("htrackscheck_v0_daughters"), 0.5); + + if (config.hasTPC && !track.hasTPC()) + return false; + hglue.fill(HIST("htrackscheck_v0_daughters"), 1.5); + + if (!config.globalTracks) { + if (track.tpcNClsCrossedRows() < config.tpcCrossedrows) + return false; + hglue.fill(HIST("htrackscheck_v0_daughters"), 2.5); + + if (track.tpcCrossedRowsOverFindableCls() < config.tpcCrossedrowsOverfcls) + return false; + hglue.fill(HIST("htrackscheck_v0_daughters"), 3.5); + + if (tpcNClsF < config.confDaughTPCnclsMin) { + return false; + } + hglue.fill(HIST("htrackscheck_v0_daughters"), 4.5); + } else { + if (!track.isGlobalTrack()) + return false; + hglue.fill(HIST("htrackscheck_v0_daughters"), 4.5); + } + + if (charge < 0 && sign > 0) { + return false; + } + hglue.fill(HIST("htrackscheck_v0_daughters"), 5.5); + + if (charge > 0 && sign < 0) { + return false; + } + hglue.fill(HIST("htrackscheck_v0_daughters"), 6.5); + + if (std::abs(eta) > config.confDaughEta) { + return false; + } + hglue.fill(HIST("htrackscheck_v0_daughters"), 7.5); + + if (std::abs(nsigmaV0Daughter) > config.confDaughPIDCuts) { + return false; + } + hglue.fill(HIST("htrackscheck_v0_daughters"), 8.5); + + if (config.qAPID) { + (charge == 1) ? rKzeroShort.fill(HIST("hNSigmaPosPionK0s_after"), track.tpcInnerParam(), track.tpcNSigmaPi()) : rKzeroShort.fill(HIST("hNSigmaNegPionK0s_after"), track.tpcInnerParam(), track.tpcNSigmaPi()); + } + + return true; + } + + // Angular separation cut on KsKs pairs + template + bool applyAngSep(const T1& candidate1, const T2& candidate2) + { + double eta1, eta2, phi1, phi2; + eta1 = candidate1.eta(); + eta2 = candidate2.eta(); + phi1 = candidate1.phi(); + phi2 = candidate2.phi(); + + double angle = std::sqrt(std::pow(eta1 - eta2, 2) + std::pow(phi1 - phi2, 2)); + rKzeroShort.fill(HIST("angularSeparation"), angle); + if (config.applyAngSepCut && angle > config.angSepCut) { + return false; + } + return true; + } + + // Defining filters for events (event selection) + // Filter eventFilter = (o2::aod::evsel::sel8 == true); + Filter posZFilter = (nabs(o2::aod::collision::posZ) < config.cutzvertex); + Filter acceptenceFilter = (nabs(aod::track::eta) < config.cfgETAcut && nabs(aod::track::pt) > config.cfgPTcut); + + // Filters on V0s + Filter preFilterV0 = (nabs(aod::v0data::dcapostopv) > config.v0settingDcapostopv && nabs(aod::v0data::dcanegtopv) > config.v0settingDcanegtopv); + + // Defining the type of the daughter tracks + using EventCandidates = soa::Filtered>; + using TrackCandidates = soa::Filtered>; + using V0TrackCandidate = aod::V0Datas; + // For Monte Carlo + using EventCandidatesMC = soa::Join; + using TrackCandidatesMC = soa::Filtered>; + using V0TrackCandidatesMC = soa::Join; + + template + void fillInvMass(const T2& lv3, const T3& lv5, float multiplicity, const T4& daughter1, bool isMix) + { + + // polarization calculations + + fourVecDau1 = ROOT::Math::PxPyPzMVector(daughter1.Px(), daughter1.Py(), daughter1.Pz(), o2::constants::physics::MassK0Short); // Kaon or Pion + + fourVecMother = ROOT::Math::PxPyPzMVector(lv3.Px(), lv3.Py(), lv3.Pz(), lv3.M()); // mass of KshortKshort pair + ROOT::Math::Boost boost{fourVecMother.BoostToCM()}; // boost mother to center of mass frame + fourVecDauCM = boost(fourVecDau1); // boost the frame of daughter same as mother + threeVecDauCM = fourVecDauCM.Vect(); // get the 3 vector of daughter in the frame of mother + + if (std::abs(lv3.Rapidity()) < 0.5) { + if (config.activateTHnSparseCosThStarHelicity) { + helicityVec = fourVecMother.Vect(); // 3 vector of mother in COM frame + auto cosThetaStarHelicity = helicityVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(helicityVec.Mag2())); + if (!isMix) { + hglue.fill(HIST("h3glueInvMassDS"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarHelicity); + + for (int i = 0; i < config.cRotations; i++) { + theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / config.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / config.rotationalCut); + hglue.fill(HIST("h3glueInvMassRot"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarHelicity); + } + } else { + hglue.fill(HIST("h3glueInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarHelicity); + } + + } else if (config.activateTHnSparseCosThStarProduction) { + normalVec = ROOT::Math::XYZVector(lv3.Py(), -lv3.Px(), 0.f); + auto cosThetaStarProduction = normalVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(normalVec.Mag2())); + if (!isMix) { + hglue.fill(HIST("h3glueInvMassDS"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarProduction); + for (int i = 0; i < config.cRotations; i++) { + theta2 = rn->Uniform(0, o2::constants::math::PI); + hglue.fill(HIST("h3glueInvMassRot"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarProduction); + } + } else { + hglue.fill(HIST("h3glueInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarProduction); + } + + } else if (config.activateTHnSparseCosThStarBeam) { + beamVec = ROOT::Math::XYZVector(0.f, 0.f, 1.f); + auto cosThetaStarBeam = beamVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + if (!isMix) { + hglue.fill(HIST("h3glueInvMassDS"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarBeam); + for (int i = 0; i < config.cRotations; i++) { + theta2 = rn->Uniform(0, o2::constants::math::PI); + hglue.fill(HIST("h3glueInvMassRot"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarBeam); + } + } else { + hglue.fill(HIST("h3glueInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarBeam); + } + + } else if (config.activateTHnSparseCosThStarRandom) { + auto phiRandom = gRandom->Uniform(0.f, constants::math::TwoPI); + auto thetaRandom = gRandom->Uniform(0.f, constants::math::PI); + + randomVec = ROOT::Math::XYZVector(std::sin(thetaRandom) * std::cos(phiRandom), std::sin(thetaRandom) * std::sin(phiRandom), std::cos(thetaRandom)); + auto cosThetaStarRandom = randomVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + if (!isMix) { + hglue.fill(HIST("h3glueInvMassDS"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarRandom); + for (int i = 0; i < config.cRotations; i++) { + theta2 = rn->Uniform(0, o2::constants::math::PI); + hglue.fill(HIST("h3glueInvMassRot"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarRandom); + } + } else { + hglue.fill(HIST("h3glueInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarRandom); + } + } + } + } + + void processSE(EventCandidates::iterator const& collision, TrackCandidates const& /*tracks*/, aod::V0Datas const& V0s) + { + hglue.fill(HIST("heventscheck"), 0.5); + multiplicity = 0.0; + if (config.cfgMultFOTM) { + multiplicity = collision.centFT0M(); + } else { + multiplicity = collision.centFT0C(); + } + if (!eventselection(collision)) { + return; + } + + // auto occupancyNumber = collision.trackOccupancyInTimeRange(); + // if (applyOccupancyCut && occupancyNumber < occupancyCut) { + // return; + // } + + if (config.qAevents) { + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + rEventSelection.fill(HIST("hmultiplicity"), multiplicity); + // rEventSelection.fill(HIST("multdist_FT0M"), collision.multFT0M()); + // rEventSelection.fill(HIST("multdist_FT0A"), collision.multFT0A()); + // rEventSelection.fill(HIST("multdist_FT0C"), collision.multFT0C()); + // rEventSelection.fill(HIST("hNcontributor"), collision.numContrib()); + } + + std::vector v0indexes; + bool allConditionsMet = 0; + + for (const auto& [v1, v2] : combinations(CombinationsFullIndexPolicy(V0s, V0s))) { + + if (v1.size() == 0 || v2.size() == 0) { + continue; + } + + if (!selectionV0(collision, v1, multiplicity)) { + continue; + } + if (!selectionV0(collision, v2, multiplicity)) { + continue; + } + + auto postrack1 = v1.template posTrack_as(); + auto negtrack1 = v1.template negTrack_as(); + auto postrack2 = v2.template posTrack_as(); + auto negtrack2 = v2.template negTrack_as(); + + double nTPCSigmaPos1{postrack1.tpcNSigmaPi()}; + double nTPCSigmaNeg1{negtrack1.tpcNSigmaPi()}; + double nTPCSigmaPos2{postrack2.tpcNSigmaPi()}; + double nTPCSigmaNeg2{negtrack2.tpcNSigmaPi()}; + + if (!(isSelectedV0Daughter(negtrack1, -1, nTPCSigmaNeg1, v1) && isSelectedV0Daughter(postrack1, 1, nTPCSigmaPos1, v1))) { + continue; + } + if (!(isSelectedV0Daughter(postrack2, 1, nTPCSigmaPos2, v2) && isSelectedV0Daughter(negtrack2, -1, nTPCSigmaNeg2, v2))) { + continue; + } + + if (std::find(v0indexes.begin(), v0indexes.end(), v1.globalIndex()) == v0indexes.end()) { + v0indexes.push_back(v1.globalIndex()); + } + // if (!(std::find(v0indexes.begin(), v0indexes.end(), v2.globalIndex()) != v0indexes.end())) { + // v0indexes.push_back(v2.globalIndex()); + // } + + if (v2.globalIndex() <= v1.globalIndex()) { + continue; + } + + // if (config.qAv0Daughters) { + // rKzeroShort.fill(HIST("negative_pt"), negtrack1.pt()); + // rKzeroShort.fill(HIST("positive_pt"), postrack1.pt()); + // rKzeroShort.fill(HIST("negative_eta"), negtrack1.eta()); + // rKzeroShort.fill(HIST("positive_eta"), postrack1.eta()); + // rKzeroShort.fill(HIST("negative_phi"), negtrack1.phi()); + // rKzeroShort.fill(HIST("positive_phi"), postrack1.phi()); + // } + + if (postrack1.globalIndex() == postrack2.globalIndex()) { + continue; + } + if (negtrack1.globalIndex() == negtrack2.globalIndex()) { + continue; + } + + if (!applyAngSep(v1, v2)) { + continue; + } + + if (config.qAv0) { + rKzeroShort.fill(HIST("hMasscorrelationbefore"), v1.mK0Short(), v2.mK0Short()); + } + allConditionsMet = 1; + daughter1 = ROOT::Math::PxPyPzMVector(v1.px(), v1.py(), v1.pz(), o2::constants::physics::MassK0Short); // Kshort + + lv3.SetPtEtaPhiM(0.0, 0.0, 0.0, 0.0); + lv5.SetPtEtaPhiM(0.0, 0.0, 0.0, 0.0); + lv1.SetPtEtaPhiM(v1.pt(), v1.eta(), v1.phi(), o2::constants::physics::MassK0Short); + lv2.SetPtEtaPhiM(v2.pt(), v2.eta(), v2.phi(), o2::constants::physics::MassK0Short); + lv4.SetPtEtaPhiM(v1.pt(), v1.eta(), v1.phi() + theta2, o2::constants::physics::MassK0Short); // for rotated background + lv3 = lv1 + lv2; + lv5 = lv2 + lv4; + isMix = false; + + if (!config.selectTWOKsOnly) + fillInvMass(lv3, lv5, multiplicity, daughter1, isMix); + } + int sizeofv0indexes = v0indexes.size(); + rKzeroShort.fill(HIST("NksProduced"), sizeofv0indexes); + if (config.selectTWOKsOnly && sizeofv0indexes == 2 && allConditionsMet) { + fillInvMass(lv3, lv5, multiplicity, daughter1, false); + } + v0indexes.clear(); + } + + PROCESS_SWITCH(HigherMassResonances, processSE, "same event process", true); + + array pvec0; + array pvec1; + // use any one of 3 alias depending on the dataset. If pp then FT0M and if pbpb then FTOC + using BinningTypeTPCMultiplicity = ColumnBinningPolicy; + using BinningTypeCentralityM = ColumnBinningPolicy; + using BinningTypeVertexContributor = ColumnBinningPolicy; + ConfigurableAxis mevz = {"mevz", {10, -10., 10.}, "mixed event vertex z binning"}; + ConfigurableAxis memult = {"memult", {2000, 0, 10000}, "mixed event multiplicity binning"}; + + void processME(EventCandidates const& collisions, TrackCandidates const& /*tracks*/, V0TrackCandidate const& v0s) + { + auto tracksTuple = std::make_tuple(v0s); + BinningTypeVertexContributor binningOnPositions1{{mevz, memult}, true}; + BinningTypeCentralityM binningOnPositions2{{mevz, memult}, true}; + + SameKindPair pair1{binningOnPositions1, config.cfgNmixedEvents, -1, collisions, tracksTuple, &cache}; // for PbPb + SameKindPair pair2{binningOnPositions2, config.cfgNmixedEvents, -1, collisions, tracksTuple, &cache}; // for pp + + if (config.cfgMultFOTM) { + for (const auto& [c1, tracks1, c2, tracks2] : pair2) // two different centrality c1 and c2 and tracks corresponding to them + { + + multiplicity = 0.0; + multiplicity = c1.centFT0M(); + + if (!eventselection(c1) || !eventselection(c2)) { + continue; + } + // auto occupancyNumber = c1.trackOccupancyInTimeRange(); + // auto occupancyNumber2 = c2.trackOccupancyInTimeRange(); + // if (applyOccupancyCut && (occupancyNumber < occupancyCut || occupancyNumber2 < occupancyCut)) { + // return; + // } + + for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + + if (t1.size() == 0 || t2.size() == 0) { + continue; + } + + if (!selectionV0(c1, t1, multiplicity)) + continue; + if (!selectionV0(c2, t2, multiplicity)) + continue; + + auto postrack1 = t1.template posTrack_as(); + auto negtrack1 = t1.template negTrack_as(); + auto postrack2 = t2.template posTrack_as(); + auto negtrack2 = t2.template negTrack_as(); + if (postrack1.globalIndex() == postrack2.globalIndex()) { + continue; + } + if (negtrack1.globalIndex() == negtrack2.globalIndex()) { + continue; + } + double nTPCSigmaPos1{postrack1.tpcNSigmaPi()}; + double nTPCSigmaNeg1{negtrack1.tpcNSigmaPi()}; + double nTPCSigmaPos2{postrack2.tpcNSigmaPi()}; + double nTPCSigmaNeg2{negtrack2.tpcNSigmaPi()}; + + if (!isSelectedV0Daughter(postrack1, 1, nTPCSigmaPos1, t1)) { + continue; + } + if (!isSelectedV0Daughter(postrack2, 1, nTPCSigmaPos2, t2)) { + continue; + } + if (!isSelectedV0Daughter(negtrack1, -1, nTPCSigmaNeg1, t1)) { + continue; + } + if (!isSelectedV0Daughter(negtrack2, -1, nTPCSigmaNeg2, t2)) { + continue; + } + + daughter1 = ROOT::Math::PxPyPzMVector(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassK0Short); // Kshort + + lv3.SetPtEtaPhiM(0.0, 0.0, 0.0, 0.0); + lv1.SetPtEtaPhiM(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassK0Short); + lv2.SetPtEtaPhiM(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassK0Short); + lv4.SetPtEtaPhiM(t1.pt(), t1.eta(), t1.phi() + theta2, o2::constants::physics::MassK0Short); // for rotated background + lv3 = lv1 + lv2; + lv5 = lv2 + lv4; + isMix = true; + fillInvMass(lv3, lv5, multiplicity, daughter1, isMix); + } + } + } else { + for (const auto& [c1, tracks1, c2, tracks2] : pair1) // two different centrality c1 and c2 and tracks corresponding to them + { + multiplicity = 0.0f; + multiplicity = c1.centFT0C(); + + if (!eventselection(c1) || !eventselection(c2)) { + continue; + } + // auto occupancyNumber = c1.trackOccupancyInTimeRange(); + // auto occupancyNumber2 = c2.trackOccupancyInTimeRange(); + // if (applyOccupancyCut && (occupancyNumber < occupancyCut || occupancyNumber2 < occupancyCut)) { + // return; + // } + + for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (t1.size() == 0 || t2.size() == 0) { + continue; + } + + if (!selectionV0(c1, t1, multiplicity)) + continue; + if (!selectionV0(c2, t2, multiplicity)) + continue; + + auto postrack1 = t1.template posTrack_as(); + auto negtrack1 = t1.template negTrack_as(); + auto postrack2 = t2.template posTrack_as(); + auto negtrack2 = t2.template negTrack_as(); + if (postrack1.globalIndex() == postrack2.globalIndex()) { + continue; + } + if (negtrack1.globalIndex() == negtrack2.globalIndex()) { + continue; + } + double nTPCSigmaPos1{postrack1.tpcNSigmaPi()}; + double nTPCSigmaNeg1{negtrack1.tpcNSigmaPi()}; + double nTPCSigmaPos2{postrack2.tpcNSigmaPi()}; + double nTPCSigmaNeg2{negtrack2.tpcNSigmaPi()}; + + if (!isSelectedV0Daughter(postrack1, 1, nTPCSigmaPos1, t1)) { + continue; + } + if (!isSelectedV0Daughter(postrack2, 1, nTPCSigmaPos2, t2)) { + continue; + } + if (!isSelectedV0Daughter(negtrack1, -1, nTPCSigmaNeg1, t1)) { + continue; + } + if (!isSelectedV0Daughter(negtrack2, -1, nTPCSigmaNeg2, t2)) { + continue; + } + + daughter1 = ROOT::Math::PxPyPzMVector(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassK0Short); // Kshort + + lv3.SetPtEtaPhiM(0.0, 0.0, 0.0, 0.0); + lv1.SetPtEtaPhiM(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassK0Short); + lv2.SetPtEtaPhiM(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassK0Short); + lv4.SetPtEtaPhiM(t1.pt(), t1.eta(), t1.phi() + theta2, o2::constants::physics::MassK0Short); // for rotated background + lv3 = lv1 + lv2; + lv5 = lv2 + lv4; + isMix = true; + fillInvMass(lv3, lv5, multiplicity, daughter1, isMix); + } + } + } + } + PROCESS_SWITCH(HigherMassResonances, processME, "mixed event process", true); + + int counter = 0; + float multiplicityGen = 0.0; + void processGen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& collisions) + { + TLorentzVector genvec; + hMChists.fill(HIST("events_check"), 0.5); + if (std::abs(mcCollision.posZ()) < config.cutzvertex) { + hMChists.fill(HIST("events_check"), 1.5); + } + // int Nchinel = 0; + // for (const auto& mcParticle : mcParticles) { + // auto pdgcode = std::abs(mcParticle.pdgCode()); + // if (mcParticle.isPhysicalPrimary() && (pdgcode == 211 || pdgcode == 321 || pdgcode == 2212 || pdgcode == 11 || pdgcode == 13)) { + // if (std::abs(mcParticle.eta()) < 1.0) { + // Nchinel = Nchinel + 1; + // } + // } + // } + // if (Nchinel > 0 && std::abs(mcCollision.posZ()) < config.cutzvertex) + hMChists.fill(HIST("events_check"), 2.5); + + std::vector selectedEvents(collisions.size()); + int nevts = 0; + multiplicityGen = 0.0; + for (const auto& collision : collisions) { + if (std::abs(collision.mcCollision().posZ()) > config.cutzvertex) { + continue; + } + + if (config.timFrameEvsel && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + continue; + } + if (config.cTVXEvsel && (!collision.selection_bit(aod::evsel::kIsTriggerTVX))) { + continue; + } + + multiplicityGen = collision.centFT0M(); + + selectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); + } + selectedEvents.resize(nevts); + hMChists.fill(HIST("events_check"), 3.5); + const auto evtReconstructedAndSelected = std::find(selectedEvents.begin(), selectedEvents.end(), mcCollision.globalIndex()) != selectedEvents.end(); + + if (!config.allGenCollisions && !evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection + return; + } + hMChists.fill(HIST("events_check"), 4.5); + for (const auto& mcParticle : mcParticles) { + + if (std::abs(mcParticle.pdgCode()) != config.pdgCodes[config.selectMCparticles]) // f2(1525), f0(1710) + { + continue; + } + hMChists.fill(HIST("events_check"), 5.5); + + // if (counter < 1e3) + // std::cout << "px " << mcParticle.px() << " py " << mcParticle.py() << " pz " << mcParticle.pz() << " y " << mcParticle.y() << std::endl; + // counter++; + + hMChists.fill(HIST("GenRapidity"), mcParticle.pt(), mcParticle.y()); + hMChists.fill(HIST("GenPhi"), mcParticle.phi()); + hMChists.fill(HIST("GenEta"), mcParticle.pt(), mcParticle.eta()); + // hMChists.fill(HIST("GenPx"), mcParticle.px()); + // hMChists.fill(HIST("GenPy"), mcParticle.py()); + // hMChists.fill(HIST("GenPz"), mcParticle.pz()); + + if (std::abs(mcParticle.y()) >= 0.5) { + continue; + } + hMChists.fill(HIST("events_check"), 6.5); + + auto kDaughters = mcParticle.daughters_as(); + if (kDaughters.size() != 2) { + continue; + } + hMChists.fill(HIST("events_check"), 7.5); + + auto passKs = false; + for (const auto& kCurrentDaughter : kDaughters) { + // int daupdg = std::abs(kCurrentDaughter.pdgCode()); + + if (!kCurrentDaughter.isPhysicalPrimary()) { + continue; + } + hMChists.fill(HIST("events_check"), 8.5); + + if (std::abs(kCurrentDaughter.pdgCode()) == 310) { + passKs = true; + hMChists.fill(HIST("events_check"), 9.5); + } + } + if (passKs) { + genvec.SetPtEtaPhiE(mcParticle.pt(), mcParticle.eta(), mcParticle.phi(), mcParticle.e()); + hMChists.fill(HIST("Genf1710_mass"), genvec.M()); + hMChists.fill(HIST("Genf1710"), multiplicityGen, mcParticle.pt()); + } + } + } + PROCESS_SWITCH(HigherMassResonances, processGen, "Process Generated", false); + + int counter2 = 0; + int eventCounter = 0; + std::vector gindex1, gindex2; + void processRec(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const&, V0TrackCandidatesMC const& V0s, aod::McParticles const&, aod::McCollisions const& /*mcCollisions*/) + { + + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; + // lDecayDaughter1.SetXYZM(0.0,0.0,0.0,0.0); + // lDecayDaughter2.SetXYZM(0.0,0.0,0.0,0.0); + // lDecayDaughter1.SetXYZM(0.0,0.0,0.0,0.0); + auto multiplicity = collision.centFT0C(); + hMChists.fill(HIST("MC_mult"), multiplicity); + + hMChists.fill(HIST("events_checkrec"), 0.5); + if (!collision.has_mcCollision()) { + return; + } + hMChists.fill(HIST("events_checkrec"), 1.5); + // // if (std::abs(collision.mcCollision().posZ()) > config.cutzvertex || !collision.sel8()) { + if (std::abs(collision.mcCollision().posZ()) > config.cutzvertex) { + return; + } + hMChists.fill(HIST("events_checkrec"), 2.5); + + if (config.timFrameEvsel && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return; + } + hMChists.fill(HIST("events_checkrec"), 3.5); + if (config.cTVXEvsel && (!collision.selection_bit(aod::evsel::kIsTriggerTVX))) { + return; + } + hMChists.fill(HIST("events_checkrec"), 4.5); + hMChists.fill(HIST("MC_mult_after_event_sel"), multiplicity); + eventCounter++; + auto oldindex = -999; + + for (const auto& v01 : V0s) { + + for (const auto& v02 : V0s) { + + hMChists.fill(HIST("events_checkrec"), 5.5); + + if (v02.index() <= v01.index()) { + continue; + } + + if (!v01.has_mcParticle() || !v02.has_mcParticle()) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 6.5); + + auto postrack1 = v01.template posTrack_as(); + auto negtrack1 = v01.template negTrack_as(); + + auto postrack2 = v02.template posTrack_as(); + auto negtrack2 = v02.template negTrack_as(); + + if (!postrack1.has_mcParticle() || !postrack2.has_mcParticle()) + continue; // Checking that the daughter tracks come from particles and are not fake + hMChists.fill(HIST("events_checkrec"), 7.5); + + if (!negtrack1.has_mcParticle() || !negtrack2.has_mcParticle()) + continue; + hMChists.fill(HIST("events_checkrec"), 8.5); + + double nTPCSigmaPos1[1]{postrack1.tpcNSigmaPi()}; + double nTPCSigmaNeg1[1]{negtrack1.tpcNSigmaPi()}; + + double nTPCSigmaPos2[1]{postrack2.tpcNSigmaPi()}; + double nTPCSigmaNeg2[1]{negtrack2.tpcNSigmaPi()}; + + if (!isSelectedV0Daughter(postrack1, 1, nTPCSigmaPos1[0], v01) || !isSelectedV0Daughter(postrack2, 1, nTPCSigmaPos2[0], v02)) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 9.5); + + if (!isSelectedV0Daughter(negtrack1, -1, nTPCSigmaNeg1[0], v01) || !isSelectedV0Daughter(negtrack2, -1, nTPCSigmaNeg2[0], v02)) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 10.5); + + if (!selectionV0(collision, v01, multiplicity) || !selectionV0(collision, v02, multiplicity)) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 11.5); + + auto mctrackv01 = v01.mcParticle(); + auto mctrackv02 = v02.mcParticle(); + + int trackv0PDG1 = std::abs(mctrackv01.pdgCode()); + int trackv0PDG2 = std::abs(mctrackv02.pdgCode()); + + if (std::abs(trackv0PDG1) != 310 || std::abs(trackv0PDG2) != 310) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 12.5); + + for (const auto& mothertrack1 : mctrackv01.mothers_as()) { + + // int motpdgs = std::abs(mothertrack1.pdgCode()); + gindex1.push_back(mothertrack1.globalIndex()); + if (gindex1.size() > 1) { + if (std::find(gindex1.begin(), gindex1.end(), mothertrack1.globalIndex()) != gindex1.end()) { + continue; + } + } + // if (counter2 < 1e4) + // std::cout << "Mother1 pdg code: " << motpdgs << " p_{T} " << mothertrack1.pt() << "Global index " << mothertrack1.globalIndex() << " event " << eventCounter << std::endl; + // counter2++; + + // int counter_check = 0; + + for (const auto& mothertrack2 : mctrackv02.mothers_as()) { + + hMChists.fill(HIST("events_checkrec"), 13.5); + + if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 14.5); + + // int motpdgs2 = std::abs(mothertrack2.pdgCode()); + gindex2.push_back(mothertrack2.globalIndex()); + if (gindex2.size() > 1) { + if (std::find(gindex2.begin(), gindex2.end(), mothertrack2.globalIndex()) != gindex2.end()) { + continue; + } + } + // if (counter2 < 1e4) + // std::cout << "Mother2 pdg code: " << motpdgs2 << " p_{T} " << mothertrack2.pt() << "Global index " << mothertrack1.globalIndex() << " event " << eventCounter << std::endl; + + if (mothertrack1.pdgCode() != config.pdgCodes[config.selectMCparticles]) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 15.5); + + if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 16.5); + + if (!mothertrack1.producedByGenerator()) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 17.5); + + if (std::abs(mothertrack1.y()) >= 0.5) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 18.5); + + if (config.avoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { + hMChists.fill(HIST("h1Recsplit"), mothertrack1.pt()); + continue; + } + oldindex = mothertrack1.globalIndex(); + + // counter_check++; + // if (counter_check > 1) { + // std::cout << "Total mothers is " << counter_check << std::endl; + // } + // std::cout << "After selection " << " p_{T} " << mothertrack2.pt() << " event " << eventCounter << std::endl; + + pvec0 = std::array{v01.px(), v01.py(), v01.pz()}; + pvec1 = std::array{v02.px(), v02.py(), v02.pz()}; + auto arrMomrec = std::array{pvec0, pvec1}; + auto motherP = mothertrack1.p(); + // auto motherE = mothertrack1.e(); + // auto genMass = std::sqrt(motherE * motherE - motherP * motherP); + auto recMass = RecoDecay::m(arrMomrec, std::array{o2::constants::physics::MassK0Short, o2::constants::physics::MassK0Short}); + // auto recpt = TMath::Sqrt((track1.px() + track2.px()) * (track1.px() + track2.px()) + (track1.py() + track2.py()) * (track1.py() + track2.py())); + //// Resonance reconstruction + lDecayDaughter1.SetXYZM(v01.px(), v01.py(), v01.pz(), o2::constants::physics::MassK0Short); + lDecayDaughter2.SetXYZM(v02.px(), v02.py(), v02.pz(), o2::constants::physics::MassK0Short); + lResonance = lDecayDaughter1 + lDecayDaughter2; + + hMChists.fill(HIST("Recf1710_p"), motherP); + hMChists.fill(HIST("Recf1710_mass"), recMass); + hMChists.fill(HIST("Recf1710_pt1"), multiplicity, mothertrack1.pt(), recMass); + // hMChists.fill(HIST("Genf1710_mass"), genMass); + hMChists.fill(HIST("Recf1710_pt2"), multiplicity, lResonance.Pt(), recMass); + + hMChists.fill(HIST("RecRapidity"), mothertrack1.y()); + hMChists.fill(HIST("RecPhi"), mothertrack1.phi()); + hMChists.fill(HIST("RecEta"), mothertrack1.eta()); + } + gindex2.clear(); + } + gindex1.clear(); + } + } + } + PROCESS_SWITCH(HigherMassResonances, processRec, "Process Reconstructed", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/highmasslambda.cxx b/PWGLF/Tasks/Resonances/highmasslambda.cxx index 72f5c325fef..c799c1d0ba7 100644 --- a/PWGLF/Tasks/Resonances/highmasslambda.cxx +++ b/PWGLF/Tasks/Resonances/highmasslambda.cxx @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include "TRandom3.h" #include "Math/Vector3D.h" @@ -53,154 +55,192 @@ #include "DataFormatsParameters/GRPMagField.h" #include "CCDB/BasicCCDBManager.h" #include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Common/DataModel/PIDResponseITS.h" +// #include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsTrkCandHf.h" +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/V0.h" +#include "DCAFitter/DCAFitterN.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using std::array; struct highmasslambda { - - int mRunNumber; int multEstimator; - float d_bz; Service ccdb; Service pdg; + o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + o2::vertexing::DCAFitterN<2> df; + int runNumber{0}; + double bz{0.}; - // CCDB options Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + // Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; + // Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + // Configurable isRun2{"isRun2", false, "enable Run 2 or Run 3 GRP objects for magnetic field"}; + Configurable cnfabsdca{"cnfabsdca", false, "Use Abs DCA for secondary vertex fitting"}; // fill output - Configurable fillPolarization{"fillPolarization", false, "fill polarization"}; - + Configurable cfgOccupancyCut{"cfgOccupancyCut", 2500, "Occupancy cut"}; + Configurable fillRotation{"fillRotation", false, "fill rotation"}; + Configurable useSP{"useSP", false, "useSP"}; + Configurable useKshortOpti{"useKshortOpti", 1, "useKshortOpti"}; // events Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; - Configurable cfgCutCentralityMax{"cfgCutCentralityMax", 80.0f, "Accepted maximum Centrality"}; - Configurable cfgCutCentralityMin{"cfgCutCentralityMin", 20.0f, "Accepted minimum Centrality"}; - + Configurable cfgCutCentralityMax{"cfgCutCentralityMax", 50.0f, "Accepted maximum Centrality"}; + Configurable cfgCutCentralityMin{"cfgCutCentralityMin", 30.0f, "Accepted minimum Centrality"}; + Configurable additionalEvSel{"additionalEvSel", true, "additionalEvSel"}; // proton track cut - Configurable confRapidity{"confRapidity", 0.5, "cut on Rapidity"}; - Configurable cfgCutPT{"cfgCutPT", 0.3, "PT cut on daughter track"}; + Configurable confMinRot{"confMinRot", 5.0 * TMath::Pi() / 6.0, "Minimum of rotation"}; + Configurable confMaxRot{"confMaxRot", 7.0 * TMath::Pi() / 6.0, "Maximum of rotation"}; + Configurable confRapidity{"confRapidity", 0.8, "cut on Rapidity"}; + Configurable cfgCutPT{"cfgCutPT", 0.4, "PT cut on daughter track"}; Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; - Configurable cfgCutMinDCAxy{"cfgCutMinDCAxy", 0.0f, "Minimum DCAxy range for proton"}; + Configurable cfgCutDCAxymin1{"cfgCutDCAxymin1", 0.005f, "Minimum DCAxy range for tracks pt 0 to 0.5"}; + Configurable cfgCutDCAxymin2{"cfgCutDCAxymin2", 0.003f, "Minimum DCAxy range for tracks pt 0.5 to 1"}; + Configurable cfgCutDCAxymin3{"cfgCutDCAxymin3", 0.003f, "Minimum DCAxy range for tracks pt 1.0 to 1.5"}; + Configurable cfgCutDCAxymin4{"cfgCutDCAxymin4", 0.002f, "Minimum DCAxy range for tracks pt 1.5 to 2.0"}; + Configurable cfgCutDCAxymin5{"cfgCutDCAxymin5", 0.001f, "Minimum DCAxy range for tracks pt 2.0 to 1000.5"}; Configurable cfgCutDCAxy{"cfgCutDCAxy", 0.1f, "DCAxy range for tracks"}; Configurable cfgCutDCAz{"cfgCutDCAz", 1.0f, "DCAz range for tracks"}; - Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; + Configurable cfgITScluster{"cfgITScluster", 5, "Number of ITS cluster"}; Configurable cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; - Configurable ispTdepPID{"ispTdepPID", true, "pT dependent PID"}; + Configurable PIDstrategy{"PIDstrategy", 0, "0: default p dep TPC and TOF (TOF no mandatory), 1: 7 with relax TOF, 2: 7 with relax TPC and TOF, 3: TOF mandatory"}; Configurable nsigmaCutTPC{"nsigmacutTPC", 3.0, "Value of the TPC Nsigma cut"}; - Configurable nsigmaCutTOF{"nsigmacutTOF", 3.0, "Value of the TOF Nsigma cut"}; - Configurable nsigmaCutTPCPre{"nsigmacutTPCPre", 5.0, "Value of the TPC Nsigma cut Pre filter"}; + Configurable nsigmaCutTOF{"nsigmaCutTOF", 3.0, "TOF PID"}; + Configurable nsigmaCutITS{"nsigmaCutITS", 3.0, "Value of the ITS Nsigma cut"}; + // Configs for V0 Configurable ConfV0PtMin{"ConfV0PtMin", 0.f, "Minimum transverse momentum of V0"}; - Configurable ConfV0DCADaughMax{"ConfV0DCADaughMax", 0.4f, "Maximum DCA between the V0 daughters"}; - Configurable ConfV0CPAMin{"ConfV0CPAMin", 0.996f, "Minimum CPA of V0"}; + Configurable ConfV0DCADaughMax{"ConfV0DCADaughMax", 0.2f, "Maximum DCA between the V0 daughters"}; + Configurable ConfV0CPAMin{"ConfV0CPAMin", 0.9998f, "Minimum CPA of V0"}; Configurable ConfV0TranRadV0Min{"ConfV0TranRadV0Min", 1.5f, "Minimum transverse radius"}; Configurable ConfV0TranRadV0Max{"ConfV0TranRadV0Max", 100.f, "Maximum transverse radius"}; - Configurable cMaxV0DCA{"cMaxV0DCA", 0.5, "Maximum V0 DCA to PV"}; + Configurable cMaxV0DCA{"cMaxV0DCA", 0.2, "Maximum V0 DCA to PV"}; Configurable cMaxV0LifeTime{"cMaxV0LifeTime", 20, "Maximum V0 life time"}; Configurable cSigmaMassKs0{"cSigmaMassKs0", 0.006, "Sigma cut on KS0 mass"}; - + Configurable cMinLambdaMass{"cMinLambdaMass", 2.18, "Minimum lambda mass"}; + Configurable cMaxLambdaMass{"cMaxLambdaMass", 2.42, "Maximum lambda mass"}; // config for V0 daughters - Configurable ConfDaughEta{"ConfDaughEta", 0.8f, "V0 Daugh sel: max eta"}; - Configurable ConfDaughPt{"ConfDaughPt", 0.1f, "V0 Daugh sel: min pt"}; - Configurable ConfDaughTPCnclsMin{"ConfDaughTPCnclsMin", 70.f, "V0 Daugh sel: Min. nCls TPC"}; Configurable ConfDaughDCAMin{"ConfDaughDCAMin", 0.08f, "V0 Daugh sel: Max. DCA Daugh to PV (cm)"}; Configurable ConfDaughPIDCuts{"ConfDaughPIDCuts", 3, "PID selections for KS0 daughters"}; - + // config SVx + Configurable ConfMaxDecayLength{"ConfMaxDecayLength", 0.1f, "Maximum decay length (cm)"}; + Configurable ConfMinCPA{"ConfMinCPA", 0.9f, "Minimum CPA"}; // Mixed event Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 1, "Number of mixed events per event"}; - /// activate rotational background Configurable nBkgRotations{"nBkgRotations", 9, "Number of rotated copies (background) per each original candidate"}; - // THnsparse bining ConfigurableAxis configThnAxisInvMass{"configThnAxisInvMass", {60, 2.15, 2.45}, "#it{M} (GeV/#it{c}^{2})"}; - ConfigurableAxis configThnAxisPt{"configThnAxisPt", {30, 1.0, 31.}, "#it{p}_{T} (GeV/#it{c})"}; - ConfigurableAxis configThnAxisCosThetaStar{"configThnAxisCosThetaStar", {10, -1.0, 1.}, "cos(#vartheta)"}; - ConfigurableAxis configThnAxisCentrality{"configThnAxisCentrality", {8, 0., 80}, "Centrality"}; - ConfigurableAxis configThnAxisPhiminusPsi{"configThnAxisPhiminusPsi", {6, 0.0, TMath::Pi()}, "#phi - #psi"}; - ConfigurableAxis configThnAxisV2{"configThnAxisV2", {100, -1, 1}, "V2"}; - ConfigurableAxis configThnAxisSA{"configThnAxisSA", {100, -1, 1}, "SA"}; + ConfigurableAxis configThnAxisPt{"configThnAxisPt", {5, 1.0, 6.}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis configThnAxisV2{"configThnAxisV2", {80, -1, 1}, "V2"}; + ConfigurableAxis cnfigThnAxisDCA{"cnfigThnAxisDCA", {100, 0.0, 0.1}, "DCA"}; + ConfigurableAxis cnfigThnAxisDecayLength{"cnfigThnAxisDecayLength", {150, 0.0, 0.3}, "decay length"}; + ConfigurableAxis cnfigThnAxisPtProton{"cnfigThnAxisPtProton", {16, 0.0, 8.0}, "pT"}; + ConfigurableAxis cnfigThnAxisCPA{"cnfigThnAxisCPA", {300, 0.8, 1.1}, "CPA"}; + // ConfigurableAxis configThnAxisCosThetaStar{"configThnAxisCosThetaStar", {10, -1.0, 1.}, "cos(#vartheta)"}; + // ConfigurableAxis configThnAxisSA{"configThnAxisSA", {100, -1, 1}, "SA"}; Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; Filter centralityFilter = (nabs(aod::cent::centFT0C) < cfgCutCentralityMax && nabs(aod::cent::centFT0C) > cfgCutCentralityMin); Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPT); Filter dcaCutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); - Filter pidFilter = nabs(aod::pidtpc::tpcNSigmaPr) < nsigmaCutTPCPre; + Filter pidFilter = nabs(aod::pidtpc::tpcNSigmaPr) < nsigmaCutTPC; using EventCandidates = soa::Filtered>; - using TrackCandidates = soa::Filtered>; + + using TrackCandidates = soa::Filtered>; using AllTrackCandidates = soa::Join; using ResoV0s = aod::V0Datas; + using TrackCandidatesSvx = soa::Filtered>; + using AllTrackCandidatesSvx = soa::Join; + using ResoV0sSvx = soa::Join; + SliceCache cache; - // Partition posTracks = aod::track::signed1Pt > cfgCutCharge; - // Partition negTracks = aod::track::signed1Pt < cfgCutCharge; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(o2::framework::InitContext&) { + + // std::vector dcaBinning = {0.0, 0.0005, 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, 0.01, 0.012, 0.014, 0.016, 0.02, 0.03, 0.05, 0.1, 0.5, 1.0}; + // std::vector dcaBinning = {0.0, 0.0005, 0.001, 0.0012, 0.0014, 0.0016, 0.002, 0.0025, 0.003, 0.004, 0.005, 0.006, 0.008, 0.01, 0.015, 0.02, 0.04, 0.05, 0.06, 0.08, 0.1, 0.3, 1.0}; + // std::vector ptProtonBinning = {0.2, 0.3, 0.5, 0.6, 0.8, 1.2, 1.4, 1.6, 2.0, 3.0, 4.0, 6.0}; + // std::vector ptLambdaBinning = {2.0, 3.0, 4.0, 5.0, 6.0}; + + std::vector occupancyBinning = {-0.5, 500.0, 1000.0, 1500.0, 2000.0, 3000.0, 4000.0, 5000.0, 50000.0}; + std::vector dcaV0toPVBinning = {0.0, 0.1, 0.2, 0.3, 0.5, 3.0, 100.0}; + std::vector cpaV0Binning = {0.995, 0.996, 0.997, 0.998, 0.999, 0.9995, 0.9997, 0.9999, 1.005}; + std::vector ptV0Binning = {0.0, 0.2, 0.3, 0.4, 0.5, 0.6, 0.8, 1.0, 1.5, 100.0}; + std::vector dcaBetweenV0 = {0.0, 0.05, 0.1, 0.15, 0.2, 0.3, 0.4, 0.5, 0.6, 0.8, 1.0}; + std::vector dcaBetweenProtonV0 = {-2.0, -1.0, -0.5, -0.4, -0.3, -0.2, -0.18, -0.16, -0.14, -0.12, -0.1, -0.08, -0.06, -0.05, -0.04, -0.03, -0.025, -0.02, -0.01, -0.005, -0.004, -0.003, -0.003, -0.002, -0.001, 0.0, 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.01, 0.012, 0.014, 0.016, 0.018, 0.02, 0.025, 0.03, 0.04, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.3, 0.4, 0.5, 1.0, 2.0}; + std::vector nsigmaKaon = {-0.1, 0.0, 0.005, 0.01, 0.03, 0.05, 0.1, 0.15, 0.2, 0.5, 0.8, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 4.5, 5.0, 6.0, 8.0, 10.0, 20.0, 100.0, 1000.0}; + AxisSpec resAxis = {1600, -30, 30, "Res"}; + AxisSpec phiAxis = {500, -6.28, 6.28, "phi"}; + AxisSpec centAxis = {8, 0, 80, "V0M (%)"}; + AxisSpec dcaV0toPVAxis = {dcaV0toPVBinning, "dcaV0toPV"}; const AxisSpec thnAxisInvMass{configThnAxisInvMass, "#it{M} (GeV/#it{c}^{2})"}; const AxisSpec thnAxisPt{configThnAxisPt, "#it{p}_{T} (GeV/#it{c})"}; - const AxisSpec thnAxisCosThetaStar{configThnAxisCosThetaStar, "cos(#vartheta)"}; - const AxisSpec thnAxisPhiminusPsi{configThnAxisPhiminusPsi, "#phi - #psi"}; - const AxisSpec thnAxisCentrality{configThnAxisCentrality, "Centrality (%)"}; const AxisSpec thnAxisV2{configThnAxisV2, "V2"}; - const AxisSpec thnAxisSA{configThnAxisSA, "SA"}; + const AxisSpec thnAxisDCA{cnfigThnAxisDCA, "DCAxy"}; + const AxisSpec thnAxisDecayLength{cnfigThnAxisDecayLength, "Decay Length"}; + const AxisSpec thnAxisPtProton{cnfigThnAxisPtProton, "Proton Pt"}; + const AxisSpec thnAxisCPA{cnfigThnAxisCPA, "CPA"}; + AxisSpec occupancyAxis = {occupancyBinning, "occupancy"}; - AxisSpec phiAxis = {500, -6.28, 6.28, "phi"}; - AxisSpec resAxis = {400, -2, 2, "Res"}; - AxisSpec centAxis = {8, 0, 80, "V0M (%)"}; - AxisSpec dcaAxis = {100, 0.0, 0.1, "V0M (%)"}; - AxisSpec dcatoPVAxis = {10, 0.0, 0.5, "V0M (%)"}; + // const AxisSpec thnAxisCosThetaStar{configThnAxisCosThetaStar, "cos(#vartheta)"}; + // const AxisSpec thnAxisPhiminusPsi{configThnAxisPhiminusPsi, "#phi - #psi"}; + // const AxisSpec thnAxisCentrality{configThnAxisCentrality, "Centrality (%)"}; + // const AxisSpec thnAxisSA{configThnAxisSA, "SA"}; + histos.add("hMomCorr", "hMomCorr", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}); histos.add("hInvMassKs0", "hInvMassKs0", kTH1F, {{200, 0.4f, 0.6f}}); + histos.add("hInvMassKs0before", "hInvMassKs0before", kTH1F, {{200, 0.4f, 0.6f}}); + histos.add("hInvMassKs0before2", "hInvMassKs0before2", kTH1F, {{200, 0.4f, 0.6f}}); + histos.add("hInvMassKs0before3", "hInvMassKs0before3", kTH1F, {{200, 0.4f, 0.6f}}); histos.add("hV0Dca", "hV0Dca", kTH1F, {{2000, -1.0f, 1.0f}}); histos.add("hpTvsRapidity", "pT vs Rapidity", kTH2F, {{100, 0.0f, 10.0f}, {300, -1.5f, 1.5f}}); - histos.add("hFTOCvsTPCNoCut", "Mult correlation FT0C vs. TPC without any cut", kTH2F, {{80, 0.0f, 80.0f}, {100, -0.5f, 5999.5f}}); - histos.add("hFTOCvsTPC", "Mult correlation FT0C vs. TPC", kTH2F, {{80, 0.0f, 80.0f}, {100, -0.5f, 5999.5f}}); - histos.add("hFTOCvsTPCSelected", "Mult correlation FT0C vs. TPC after selection", kTH2F, {{80, 0.0f, 80.0f}, {100, -0.5f, 5999.5f}}); histos.add("hCentrality", "Centrality distribution", kTH1F, {{200, 0.0, 200.0}}); histos.add("hVtxZ", "Vertex distribution in Z;Z (cm)", kTH1F, {{400, -20.0, 20.0}}); + histos.add("hOccupancy", "Occupancy", kTH1F, {{5000, -0.5, 50000.5}}); + histos.add("hRotation", "hRotation", kTH1F, {{360, 0.0, 2.0 * TMath::Pi()}}); histos.add("hEta", "Eta distribution", kTH1F, {{200, -1.0f, 1.0f}}); - histos.add("hDcaxy", "Dcaxy distribution", kTH1F, {{1000, -0.5f, 0.5f}}); - histos.add("hDcaz", "Dcaz distribution", kTH1F, {{1000, -0.5f, 0.5f}}); - histos.add("hNsigmaProtonTPC", "NsigmaProton TPC distribution", kTH1F, {{200, -10.0f, 10.0f}}); - histos.add("hNsigmaProtonTOF", "NsigmaProton TOF distribution", kTH1F, {{200, -10.0f, 10.0f}}); - histos.add("hPsiFT0C", "PsiFT0C", kTH2F, {centAxis, phiAxis}); - histos.add("hPsiFT0A", "PsiFT0A", kTH2F, {centAxis, phiAxis}); - histos.add("hPsiTPC", "PsiTPC", kTH2F, {centAxis, phiAxis}); - histos.add("hPsiTPCR", "PsiTPCR", kTH2F, {centAxis, phiAxis}); - histos.add("hPsiTPCL", "PsiTPCL", kTH2F, {centAxis, phiAxis}); - - histos.add("hSparseV2SASameEvent_V2", "hSparseV2SASameEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, dcaAxis, dcatoPVAxis, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEvent_V2", "hSparseV2SAMixedEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, dcaAxis, dcatoPVAxis, thnAxisCentrality}); - histos.add("hSparseV2SASameEventRotational_V2", "hSparseV2SASameEventRotational_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, dcaAxis, dcatoPVAxis, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_V2_new", "hSparseV2SASameEvent_V2_new", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, dcaAxis, thnAxisCentrality}); - histos.add("hSparseV2SASameEventRotational_V2_new", "hSparseV2SASameEventRotational_V2_new", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, dcaAxis, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEvent_V2_new", "hSparseV2SAMixedEvent_V2_new", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, dcaAxis, thnAxisCentrality}); - - if (fillPolarization) { - histos.add("hSparseV2SASameEventplus_SA", "hSparseV2SASameEventplus_SA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEventplus_SA_A0", "hSparseV2SASameEventplus_SA_A0", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEventplus_SA_azimuth", "hSparseV2SASameEventplus_SA_azimuth", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisCentrality}); - histos.add("hSparseV2SASameEventminus_SA", "hSparseV2SASameEventminus_SA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEventminus_SA_A0", "hSparseV2SASameEventminus_SA_A0", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEventminus_SA_azimuth", "hSparseV2SASameEventminus_SA_azimuth", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisCentrality}); - - histos.add("hSparseV2SAMixedEventplus_SA", "hSparseV2SAMixedEventplus_SA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEventplus_SA_A0", "hSparseV2SAMixedEventplus_SA_A0", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEventplus_SA_azimuth", "hSparseV2SAMixedEventplus_SA_azimuth", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEventminus_SA", "hSparseV2SAMixedEventminus_SA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEventminus_SA_A0", "hSparseV2SAMixedEventminus_SA_A0", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEventminus_SA_azimuth", "hSparseV2SAMixedEventminus_SA_azimuth", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisCentrality}); - } + histos.add("hDcaxy", "Dcaxy distribution", kTH2F, {{1000, -0.5f, 0.5f}, {100, 0.0f, 10.0f}}); + histos.add("hDcaz", "Dcaz distribution", kTH2F, {{1000, -0.5f, 0.5f}, {100, 0.0f, 10.0f}}); + histos.add("hNsigmaProtonITS", "NsigmaProton ITS distribution", kTH2F, {{100, -5.0f, 5.0f}, {60, 0.0f, 6.0f}}); + histos.add("hNsigmaProtonTPC", "NsigmaProton TPC distribution", kTH2F, {{100, -5.0f, 5.0f}, {60, 0.0f, 6.0f}}); + histos.add("hNsigmaProtonTOF", "NsigmaProton TOF distribution", kTH2F, {{1000, -50.0f, 50.0f}, {60, 0.0f, 6.0f}}); + histos.add("hNsigmaProtonTPCPre", "NsigmaProton TPC distribution Pre sel", kTH2F, {{1000, -50.0f, 50.0f}, {60, 0.0f, 6.0f}}); + histos.add("hPsiFT0C", "PsiFT0C", kTH3F, {centAxis, phiAxis, occupancyAxis}); + histos.add("hPsiFT0A", "PsiFT0A", kTH3F, {centAxis, phiAxis, occupancyAxis}); + histos.add("hPsiTPC", "PsiTPC", kTH3F, {centAxis, phiAxis, occupancyAxis}); + // SVX histo + histos.add("hDecayLengthxy", "Decay length xy", kTH1F, {{500, 0.0f, 0.1f}}); + histos.add("hDecayLength", "Decay length", kTH1F, {{500, 0.0f, 0.1f}}); + histos.add("hImpactPar0", "hImpactPar0", kTH1F, {{500, 0.0f, 0.1f}}); + histos.add("hImpactPar1", "hImpactPar1", kTH1F, {{500, 0.0f, 0.1f}}); + histos.add("hCPA", "hCPA", kTH1F, {{220, -1.1f, 1.1f}}); + histos.add("hSparseV2SASameEvent_V2_SVX", "hSparseV2SASameEvent_V2_SVX", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisDecayLength, thnAxisCPA}); + histos.add("hSparseV2SASameEventRotational_V2_SVX", "hSparseV2SASameEventRotational_SVX", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisDecayLength, thnAxisCPA}); + histos.add("hSparseV2SASameEventRotational_V2", "hSparseV2SASameEventRotational", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2}); + if (useKshortOpti == 0) { + histos.add("hSparseV2SASameEvent_V2", "hSparseV2SASameEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisDCA, thnAxisPtProton}); + histos.add("hSparseV2SAMixedEvent_V2", "hSparseV2SAMixedEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisDCA, thnAxisPtProton}); + } + if (useKshortOpti == 1) { + histos.add("hSparseV2SASameEvent_V2", "hSparseV2SASameEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, dcaV0toPVBinning, cpaV0Binning, ptV0Binning, dcaBetweenV0, dcaBetweenProtonV0}); + histos.add("hSparseV2SAMixedEvent_V2", "hSparseV2SAMixedEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, dcaV0toPVBinning, cpaV0Binning, ptV0Binning, dcaBetweenV0, dcaBetweenProtonV0}); + } + if (useKshortOpti == 2) { + histos.add("hSparseV2SASameEvent_V2", "hSparseV2SASameEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisDCA, nsigmaKaon}); + histos.add("hSparseV2SAMixedEvent_V2", "hSparseV2SAMixedEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisDCA, nsigmaKaon}); + } // histogram for resolution histos.add("ResFT0CTPC", "ResFT0CTPC", kTH2F, {centAxis, resAxis}); histos.add("ResFT0CTPCR", "ResFT0CTPCR", kTH2F, {centAxis, resAxis}); @@ -208,60 +248,234 @@ struct highmasslambda { histos.add("ResTPCRTPCL", "ResTPCRTPCL", kTH2F, {centAxis, resAxis}); histos.add("ResFT0CFT0A", "ResFT0CFT0A", kTH2F, {centAxis, resAxis}); histos.add("ResFT0ATPC", "ResFT0ATPC", kTH2F, {centAxis, resAxis}); - } + df.setPropagateToPCA(true); + df.setMaxR(200); + df.setMaxDZIni(4); + df.setMinParamChange(1.e-3); + df.setMinRelChi2Change(0.9); + df.setUseAbsDCA(cnfabsdca); + df.setWeightedFinalPCA(cnfabsdca); + df.setMatCorrType(noMatCorr); + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + runNumber = 0; + bz = 0; + } template bool selectionTrack(const T& candidate) { - if (!(candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsFound() > cfgTPCcluster && TMath::Abs(candidate.dcaXY()) > cfgCutMinDCAxy)) { + if (!(candidate.isGlobalTrackWoDCA() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsCrossedRows() > cfgTPCcluster)) { + return false; + } + if (std::abs(candidate.dcaXY()) > (0.0105 + (0.035 / TMath::Power(candidate.pt(), 1.1)))) { + return false; + } + if (candidate.pt() > 0.0 && candidate.pt() < 0.5 && std::abs(candidate.dcaXY()) < cfgCutDCAxymin1) { + return false; + } + if (candidate.pt() >= 0.5 && candidate.pt() < 1.0 && std::abs(candidate.dcaXY()) < cfgCutDCAxymin2) { + return false; + } + if (candidate.pt() >= 1.0 && candidate.pt() < 1.5 && std::abs(candidate.dcaXY()) < cfgCutDCAxymin3) { + return false; + } + if (candidate.pt() >= 1.5 && candidate.pt() < 2.0 && std::abs(candidate.dcaXY()) < cfgCutDCAxymin4) { + return false; + } + if (candidate.pt() >= 2.0 && candidate.pt() < 10000000.0 && std::abs(candidate.dcaXY()) < cfgCutDCAxymin5) { return false; } return true; } + // TOF Veto template - bool selectionPIDpTdependent(const T& candidate) + bool selectionPID1(const T& candidate) { - if (candidate.p() <= 0.5 && TMath::Abs(candidate.tpcNSigmaPr()) < 5.0) { - return true; + if (candidate.hasTOF()) { + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; + } + if (candidate.p() >= 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOF) { + return true; + } } - if (candidate.p() > 0.5 && candidate.p() <= 0.8 && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0) { - return true; + if (!candidate.hasTOF()) { + if (std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; + } } - if (candidate.p() > 0.8 && candidate.hasTOF() && TMath::Sqrt(candidate.tofNSigmaPr() * candidate.tofNSigmaPr() + candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr()) < nsigmaCutTOF) { + return false; + } + // TPC TOF + template + bool selectionPID7(const T& candidate) + { + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { return true; } + if (candidate.pt() >= 0.7) { + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + if (candidate.pt() < 2.5 && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOF) { + return true; + } + if (candidate.pt() >= 2.5 && candidate.pt() < 4 && candidate.tofNSigmaPr() > -2.0 && candidate.tofNSigmaPr() < nsigmaCutTOF) { + return true; + } + if (candidate.pt() >= 4 && candidate.pt() < 5 && candidate.tofNSigmaPr() > -1.5 && candidate.tofNSigmaPr() < nsigmaCutTOF) { + return true; + } + if (candidate.pt() >= 5 && candidate.tofNSigmaPr() > -1.0 && candidate.tofNSigmaPr() < nsigmaCutTOF) { + return true; + } + } + if (!candidate.hasTOF()) { + if (candidate.pt() >= 0.7 && candidate.pt() < 0.8 && candidate.tpcNSigmaPr() > -1.8 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.8 && candidate.pt() < 0.9 && candidate.tpcNSigmaPr() > -1.7 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.9 && candidate.pt() < 1.0 && candidate.tpcNSigmaPr() > -1.6 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 1.0 && candidate.pt() < 1.8 && candidate.tpcNSigmaPr() > -0.5 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 1.8 && TMath::Abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; + } + } + } return false; } + // TPC TOF template - bool selectionPID(const T& candidate) + bool selectionPID8(const T& candidate) { - if (candidate.p() <= 0.5 && TMath::Abs(candidate.tpcNSigmaPr()) < 5.0) { + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { return true; } - if (candidate.p() > 0.5 && candidate.p() <= 0.8 && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0) { + if (candidate.pt() >= 0.7) { + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + if (candidate.pt() < 2.5 && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOF) { + return true; + } + if (candidate.pt() >= 2.5 && candidate.tofNSigmaPr() > -2.0 && candidate.tofNSigmaPr() < nsigmaCutTOF) { + return true; + } + } + if (!candidate.hasTOF()) { + if (candidate.pt() >= 0.7 && candidate.pt() < 0.8 && candidate.tpcNSigmaPr() > -1.8 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.8 && candidate.pt() < 0.9 && candidate.tpcNSigmaPr() > -1.7 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.9 && candidate.pt() < 1.0 && candidate.tpcNSigmaPr() > -1.6 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 1.0 && candidate.pt() < 1.8 && candidate.tpcNSigmaPr() > -0.5 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 1.8 && TMath::Abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; + } + } + } + return false; + } + + // TPC TOF + template + bool selectionPID9(const T& candidate) + { + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { return true; } - if (candidate.p() > 0.8 && !candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + if (candidate.pt() >= 0.7) { + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + if (candidate.pt() < 2.5 && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOF) { + return true; + } + if (candidate.pt() >= 2.5 && candidate.tofNSigmaPr() > -2.0 && candidate.tofNSigmaPr() < nsigmaCutTOF) { + return true; + } + } + if (!candidate.hasTOF()) { + if (candidate.pt() >= 0.7 && candidate.pt() < 0.8 && candidate.tpcNSigmaPr() > -1.8 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.8 && candidate.pt() < 0.9 && candidate.tpcNSigmaPr() > -1.7 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.9 && candidate.pt() < 1.0 && candidate.tpcNSigmaPr() > -1.6 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 1.0 && candidate.pt() < 1.8 && candidate.tpcNSigmaPr() > -1.5 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 1.8 && TMath::Abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; + } + } + } + return false; + } + + // TPC TOF + template + bool selectionPID10(const T& candidate) + { + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { return true; } - if (candidate.p() > 0.8 && candidate.hasTOF() && TMath::Sqrt(candidate.tofNSigmaPr() * candidate.tofNSigmaPr() + candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr()) < nsigmaCutTOF) { + if (candidate.pt() >= 0.7 && candidate.pt() < 1.8 && candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { return true; } + if (candidate.pt() >= 1.8) { + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + if (candidate.pt() < 2.5 && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOF) { + return true; + } + if (candidate.pt() >= 2.5 && candidate.tofNSigmaPr() > -2.0 && candidate.tofNSigmaPr() < nsigmaCutTOF) { + return true; + } + } + if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; + } + } return false; } + template + double combinekaon(const T& candidate) + { + if (candidate.pt() < 0.7) { + return std::abs(candidate.tpcNSigmaKa()); + } else if (candidate.pt() >= 0.7 && candidate.hasTOF()) { + return std::sqrt((candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa()) / 2.0); + } else if (candidate.pt() >= 0.7 && !candidate.hasTOF()) { + return std::abs(candidate.tpcNSigmaKa()); + } + return -0.1; + } + template bool SelectionV0(Collision const& collision, V0 const& candidate) { - if (fabs(candidate.dcav0topv()) > cMaxV0DCA) { + if (std::abs(candidate.dcav0topv()) > cMaxV0DCA) { return false; } const float pT = candidate.pt(); const std::vector decVtx = {candidate.x(), candidate.y(), candidate.z()}; const float tranRad = candidate.v0radius(); - const double dcaDaughv0 = TMath::Abs(candidate.dcaV0daughters()); + const double dcaDaughv0 = std::abs(candidate.dcaV0daughters()); const double cpav0 = candidate.v0cosPA(); float CtauK0s = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * TDatabasePDG::Instance()->GetParticle(kK0Short)->Mass(); // FIXME: Get from the common header @@ -283,18 +497,17 @@ struct highmasslambda { if (tranRad > ConfV0TranRadV0Max) { return false; } - if (fabs(CtauK0s) > cMaxV0LifeTime || candidate.mK0Short() < lowmasscutks0 || candidate.mK0Short() > highmasscutks0) { + if (std::abs(CtauK0s) > cMaxV0LifeTime || candidate.mK0Short() < lowmasscutks0 || candidate.mK0Short() > highmasscutks0) { return false; } return true; } - template bool isSelectedV0Daughter(T const& track, float charge) { const auto eta = track.eta(); const auto pt = track.pt(); - const auto tpcNClsF = track.tpcNClsFound(); + const auto tpcNClsF = track.tpcNClsCrossedRows(); const auto dcaXY = track.dcaXY(); const auto sign = track.sign(); if (charge < 0 && sign > 0) { @@ -303,13 +516,13 @@ struct highmasslambda { if (charge > 0 && sign < 0) { return false; } - if (std::abs(eta) > ConfDaughEta) { + if (std::abs(eta) > 0.8) { return false; } - if (std::abs(pt) < ConfDaughPt) { + if (std::abs(pt) < 0.15) { return false; } - if (tpcNClsF < ConfDaughTPCnclsMin) { + if (tpcNClsF < 50) { return false; } if (std::abs(dcaXY) < ConfDaughDCAMin) { @@ -338,20 +551,24 @@ struct highmasslambda { ConfigurableAxis axisEPAngle{"axisEPAngle", {1, -TMath::Pi() / 2, TMath::Pi() / 2}, "event plane angle"}; using BinningTypeVertexContributor = ColumnBinningPolicy; - ROOT::Math::PxPyPzMVector Lambdac, Proton, Kshort, LambdacRot, ProtonRot, fourVecDauCM; + ROOT::Math::PxPyPzMVector Lambdac, Proton, Kshort, LambdacRot, KshortRot, fourVecDauCM; ROOT::Math::XYZVector threeVecDauCM, threeVecDauCMXY, eventplaneVec, eventplaneVecNorm, beamvector; - double massPi = TDatabasePDG::Instance()->GetParticle(kPiPlus)->Mass(); // FIXME: Get from the common header double massPr = TDatabasePDG::Instance()->GetParticle(kProton)->Mass(); // FIXME: Get from the common header double massK0s = TDatabasePDG::Instance()->GetParticle(kK0Short)->Mass(); // FIXME: Get from the common header + double v2, v2Rot; void processSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks, AllTrackCandidates const&, ResoV0s const& V0s, aod::BCs const&) { - if (!collision.sel8()) { + if (!collision.sel8() || !collision.triggereventep() || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return; + } + if (additionalEvSel && (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll) || !collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { return; } + o2::aod::ITSResponse itsResponse; auto centrality = collision.centFT0C(); - auto multTPC = collision.multNTracksPV(); - histos.fill(HIST("hFTOCvsTPCNoCut"), centrality, multTPC); - if (!collision.triggereventep()) { + // auto multTPC = collision.multNTracksPV(); + int occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy > cfgOccupancyCut) { return; } auto psiFT0C = collision.psiFT0C(); @@ -359,46 +576,74 @@ struct highmasslambda { auto psiTPC = collision.psiTPC(); auto psiTPCR = collision.psiTPCR(); auto psiTPCL = collision.psiTPCL(); - histos.fill(HIST("hFTOCvsTPC"), centrality, multTPC); - histos.fill(HIST("hFTOCvsTPCSelected"), centrality, multTPC); - histos.fill(HIST("hPsiFT0C"), centrality, psiFT0C); - histos.fill(HIST("hPsiFT0A"), centrality, psiFT0A); - histos.fill(HIST("hPsiTPC"), centrality, psiTPC); - histos.fill(HIST("hPsiTPCR"), centrality, psiTPCR); - histos.fill(HIST("hPsiTPCL"), centrality, psiTPCL); - histos.fill(HIST("ResFT0CTPC"), centrality, TMath::Cos(2.0 * (psiFT0C - psiTPC))); - histos.fill(HIST("ResFT0CTPCR"), centrality, TMath::Cos(2.0 * (psiFT0C - psiTPCR))); - histos.fill(HIST("ResFT0CTPCL"), centrality, TMath::Cos(2.0 * (psiFT0C - psiTPCL))); - histos.fill(HIST("ResTPCRTPCL"), centrality, TMath::Cos(2.0 * (psiTPCR - psiTPCL))); - histos.fill(HIST("ResFT0CFT0A"), centrality, TMath::Cos(2.0 * (psiFT0C - psiFT0A))); - histos.fill(HIST("ResFT0ATPC"), centrality, TMath::Cos(2.0 * (psiTPC - psiFT0A))); + + auto QFT0C = collision.qFT0C(); + auto QFT0A = collision.qFT0A(); + auto QTPC = collision.qTPC(); + auto QTPCR = collision.qTPCR(); + auto QTPCL = collision.qTPCL(); + histos.fill(HIST("hPsiFT0C"), centrality, psiFT0C, occupancy); + histos.fill(HIST("hPsiFT0A"), centrality, psiFT0A, occupancy); + histos.fill(HIST("hPsiTPC"), centrality, psiTPC, occupancy); + histos.fill(HIST("ResFT0CTPC"), centrality, QFT0C * QTPC * TMath::Cos(2.0 * (psiFT0C - psiTPC))); + histos.fill(HIST("ResFT0CTPCR"), centrality, QFT0C * QTPCR * TMath::Cos(2.0 * (psiFT0C - psiTPCR))); + histos.fill(HIST("ResFT0CTPCL"), centrality, QFT0C * QTPCL * TMath::Cos(2.0 * (psiFT0C - psiTPCL))); + histos.fill(HIST("ResTPCRTPCL"), centrality, QTPCR * QTPCL * TMath::Cos(2.0 * (psiTPCR - psiTPCL))); + histos.fill(HIST("ResFT0CFT0A"), centrality, QFT0C * QFT0A * TMath::Cos(2.0 * (psiFT0C - psiFT0A))); + histos.fill(HIST("ResFT0ATPC"), centrality, QTPC * QFT0A * TMath::Cos(2.0 * (psiTPC - psiFT0A))); histos.fill(HIST("hCentrality"), centrality); histos.fill(HIST("hVtxZ"), collision.posZ()); + histos.fill(HIST("hOccupancy"), occupancy); auto firstprimarytrack = 0; for (auto track1 : tracks) { if (!selectionTrack(track1)) { continue; } - // PID check - if (ispTdepPID && !selectionPIDpTdependent(track1)) { + histos.fill(HIST("hNsigmaProtonITS"), itsResponse.nSigmaITS(track1), track1.pt()); + if (track1.pt() <= 0.6 && !(itsResponse.nSigmaITS(track1) > -2.0)) { + continue; + } + if (track1.pt() > 0.6 && track1.pt() <= 0.8 && !(itsResponse.nSigmaITS(track1) > -1.5)) { + continue; + } + histos.fill(HIST("hNsigmaProtonTPCPre"), track1.tpcNSigmaPr(), track1.pt()); + if (PIDstrategy == 0 && !selectionPID7(track1)) { + continue; + } + if (PIDstrategy == 1 && !selectionPID8(track1)) { continue; } - if (!ispTdepPID && !selectionPID(track1)) { + if (PIDstrategy == 2 && !selectionPID9(track1)) { + continue; + } + if (PIDstrategy == 3 && !selectionPID10(track1)) { + continue; + } + if (PIDstrategy == 4 && !selectionPID1(track1)) { continue; } histos.fill(HIST("hEta"), track1.eta()); - histos.fill(HIST("hDcaxy"), track1.dcaXY()); - histos.fill(HIST("hDcaz"), track1.dcaZ()); - histos.fill(HIST("hNsigmaProtonTPC"), track1.tpcNSigmaPr()); - histos.fill(HIST("hNsigmaProtonTOF"), track1.tofNSigmaPr()); + histos.fill(HIST("hDcaxy"), track1.dcaXY(), track1.pt()); + histos.fill(HIST("hDcaz"), track1.dcaZ(), track1.pt()); + histos.fill(HIST("hNsigmaProtonTPC"), track1.tpcNSigmaPr(), track1.pt()); + if (track1.hasTOF()) { + histos.fill(HIST("hNsigmaProtonTOF"), track1.tofNSigmaPr(), track1.pt()); + } auto track1ID = track1.globalIndex(); for (auto v0 : V0s) { if (firstprimarytrack == 0) { - histos.fill(HIST("hV0Dca"), v0.dcav0topv()); + histos.fill(HIST("hInvMassKs0before"), v0.mK0Short()); } if (!SelectionV0(collision, v0)) { continue; } + if (firstprimarytrack == 0) { + histos.fill(HIST("hInvMassKs0before2"), v0.mK0Short()); + } + + if (firstprimarytrack == 0) { + histos.fill(HIST("hV0Dca"), v0.dcav0topv()); + } auto postrack = v0.template posTrack_as(); auto negtrack = v0.template negTrack_as(); if (!isSelectedV0Daughter(postrack, 1)) { @@ -407,6 +652,10 @@ struct highmasslambda { if (!isSelectedV0Daughter(negtrack, -1)) { continue; } + if (firstprimarytrack == 0) { + histos.fill(HIST("hInvMassKs0before3"), v0.mK0Short()); + } + if (track1ID == postrack.globalIndex()) { continue; } @@ -418,47 +667,48 @@ struct highmasslambda { } firstprimarytrack = firstprimarytrack + 1; Proton = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massPr); - Kshort = ROOT::Math::PxPyPzMVector(v0.px(), v0.py(), v0.pz(), massK0s); + Kshort = ROOT::Math::PxPyPzMVector(v0.px(), v0.py(), v0.pz(), v0.mK0Short()); Lambdac = Proton + Kshort; - if (TMath::Abs(Lambdac.Rapidity()) > confRapidity) { - continue; - } auto phiminuspsi = GetPhiInRange(Lambdac.Phi() - psiFT0C); - auto v2 = TMath::Cos(2.0 * phiminuspsi); - auto diffangle = Proton.Phi() - Lambdac.Phi(); - auto decaylength = std::abs(track1.dcaXY() / TMath::Sin(diffangle)); - histos.fill(HIST("hSparseV2SASameEvent_V2"), Lambdac.M(), Lambdac.Pt(), v2, std::abs(track1.dcaXY()), std::abs(v0.dcav0topv()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_V2_new"), Lambdac.M(), Lambdac.Pt(), v2, decaylength, centrality); - for (int nrotbkg = 1; nrotbkg < nBkgRotations; nrotbkg++) { - auto anglestep = nrotbkg * (2.0 * TMath::Pi() / nBkgRotations); - auto rotProtonPx = track1.px() * std::cos(anglestep) - track1.py() * std::sin(anglestep); - auto rotProtonPy = track1.px() * std::sin(anglestep) + track1.py() * std::cos(anglestep); - ProtonRot = ROOT::Math::PxPyPzMVector(rotProtonPx, rotProtonPy, track1.pz(), massPr); - LambdacRot = ProtonRot + Kshort; - auto phiminuspsiRot = GetPhiInRange(LambdacRot.Phi() - psiFT0C); - auto v2Rot = TMath::Cos(2.0 * phiminuspsiRot); - auto diffangleRot = ProtonRot.Phi() - LambdacRot.Phi(); - auto decaylengthRot = std::abs(track1.dcaXY() / TMath::Sin(diffangleRot)); - histos.fill(HIST("hSparseV2SASameEventRotational_V2"), LambdacRot.M(), LambdacRot.Pt(), v2Rot, std::abs(track1.dcaXY()), std::abs(v0.dcav0topv()), centrality); - histos.fill(HIST("hSparseV2SASameEventRotational_V2_new"), LambdacRot.M(), LambdacRot.Pt(), v2Rot, decaylengthRot, centrality); - } - ROOT::Math::Boost boost{Lambdac.BoostToCM()}; - fourVecDauCM = boost(Kshort); - threeVecDauCM = fourVecDauCM.Vect(); - threeVecDauCMXY = ROOT::Math::XYZVector(threeVecDauCM.X(), threeVecDauCM.Y(), 0.); - beamvector = ROOT::Math::XYZVector(0, 0, 1); - auto cosThetaStar = beamvector.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(beamvector.Mag2()); - auto SA = cosThetaStar * TMath::Sin(2.0 * phiminuspsi); - if (fillPolarization) { - if (track1.sign() > 0) { - histos.fill(HIST("hSparseV2SASameEventplus_SA"), Lambdac.M(), Lambdac.Pt(), cosThetaStar, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEventplus_SA_A0"), Lambdac.M(), Lambdac.Pt(), cosThetaStar * cosThetaStar, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEventplus_SA_azimuth"), Lambdac.M(), Lambdac.Pt(), SA, centrality); + v2 = TMath::Cos(2.0 * phiminuspsi) * QFT0C; + if (useSP) { + v2 = TMath::Cos(2.0 * phiminuspsi); + } + auto dcaV0toPV = std::abs(v0.dcav0topv()); + auto cpaV0 = v0.v0cosPA(); + auto ptV0 = v0.pt(); + auto dcaV0Daughters = std::abs(v0.dcaV0daughters()); + auto dcaProtonV0 = v0.dcav0topv() - track1.dcaXY(); + if (Lambdac.M() > cMinLambdaMass && Lambdac.M() <= cMaxLambdaMass && std::abs(Lambdac.Rapidity()) < confRapidity && Lambdac.Pt() > 1.0 && Lambdac.Pt() <= 6.0) { + if (useKshortOpti == 0) { + histos.fill(HIST("hSparseV2SASameEvent_V2"), Lambdac.M(), Lambdac.Pt(), std::abs(track1.dcaXY()), Proton.Pt()); + } + if (useKshortOpti == 1) { + histos.fill(HIST("hSparseV2SASameEvent_V2"), Lambdac.M(), Lambdac.Pt(), dcaV0toPV, cpaV0, ptV0, dcaV0Daughters, dcaProtonV0); } - if (track1.sign() < 0) { - histos.fill(HIST("hSparseV2SASameEventminus_SA"), Lambdac.M(), Lambdac.Pt(), cosThetaStar, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEventminus_SA_A0"), Lambdac.M(), Lambdac.Pt(), cosThetaStar * cosThetaStar, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEventminus_SA_azimuth"), Lambdac.M(), Lambdac.Pt(), SA, centrality); + if (useKshortOpti == 2) { + histos.fill(HIST("hSparseV2SASameEvent_V2"), Lambdac.M(), Lambdac.Pt(), v2, std::abs(track1.dcaXY()), combinekaon(track1)); + } + } + if (fillRotation) { + for (int nrotbkg = 0; nrotbkg < nBkgRotations; nrotbkg++) { + auto anglestart = confMinRot; + auto angleend = confMaxRot; + auto anglestep = (angleend - anglestart) / (1.0 * (nBkgRotations - 1)); + auto rotangle = anglestart + nrotbkg * anglestep; + histos.fill(HIST("hRotation"), rotangle); + auto rotKaonPx = Kshort.px() * std::cos(rotangle) - Kshort.py() * std::sin(rotangle); + auto rotKaonPy = Kshort.px() * std::sin(rotangle) + Kshort.py() * std::cos(rotangle); + KshortRot = ROOT::Math::PxPyPzMVector(rotKaonPx, rotKaonPy, Kshort.pz(), massK0s); + LambdacRot = Proton + KshortRot; + auto phiminuspsiRot = GetPhiInRange(LambdacRot.Phi() - psiFT0C); + v2Rot = TMath::Cos(2.0 * phiminuspsiRot) * QFT0C; + if (useSP) { + v2Rot = TMath::Cos(2.0 * phiminuspsiRot); + } + if (LambdacRot.M() > cMinLambdaMass && LambdacRot.M() <= cMaxLambdaMass && std::abs(LambdacRot.Rapidity()) < confRapidity && LambdacRot.Pt() > 1.0 && LambdacRot.Pt() <= 6.0) { + histos.fill(HIST("hSparseV2SASameEventRotational_V2"), LambdacRot.M(), LambdacRot.Pt(), v2Rot); + } } } } @@ -471,24 +721,64 @@ struct highmasslambda { BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicityClass, axisEPAngle}, true}; Pair pairs{binningOnPositions, cfgNoMixedEvents, -1, collisions, tracksV0sTuple, &cache}; // -1 is the number of the bin to skip for (auto& [collision1, tracks1, collision2, tracks2] : pairs) { - if (!collision1.sel8() || !collision2.sel8()) { + if (!collision1.sel8() || !collision1.triggereventep() || !collision1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision1.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return; + } + if (additionalEvSel && (!collision1.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll) || !collision1.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !collision1.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + return; + } + if (!collision2.sel8() || !collision2.triggereventep() || !collision2.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision2.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return; + } + if (additionalEvSel && (!collision2.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll) || !collision2.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !collision2.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + return; + } + if (collision1.bcId() == collision2.bcId()) { continue; } - if (!collision1.triggereventep() || !collision2.triggereventep()) { + if (additionalEvSel && !collision1.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { continue; } - auto centrality = collision1.centFT0C(); - auto psiFT0C = collision1.psiFT0C(); + if (additionalEvSel && !collision2.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + continue; + } + o2::aod::ITSResponse itsResponse; + auto psiFT0C = collision1.psiFT0C(); + auto QFT0C = collision1.qFT0C(); + int occupancy1 = collision1.trackOccupancyInTimeRange(); + int occupancy2 = collision1.trackOccupancyInTimeRange(); + if (occupancy1 > cfgOccupancyCut) { + continue; + } + if (occupancy2 > cfgOccupancyCut) { + continue; + } for (auto& [track1, v0] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (!selectionTrack(track1)) { continue; } + if (track1.pt() <= 0.6 && !(itsResponse.nSigmaITS(track1) > -2.0)) { + continue; + } + if (track1.pt() > 0.6 && track1.pt() <= 0.8 && !(itsResponse.nSigmaITS(track1) > -1.5)) { + continue; + } // PID check - if (ispTdepPID && !selectionPIDpTdependent(track1)) { + if (PIDstrategy == 0 && !selectionPID7(track1)) { + continue; + } + if (PIDstrategy == 1 && !selectionPID8(track1)) { + continue; + } + if (PIDstrategy == 2 && !selectionPID9(track1)) { + continue; + } + if (PIDstrategy == 3 && !selectionPID10(track1)) { continue; } - if (!ispTdepPID && !selectionPID(track1)) { + if (PIDstrategy == 4 && !selectionPID1(track1)) { continue; } if (!SelectionV0(collision2, v0)) { @@ -502,43 +792,321 @@ struct highmasslambda { if (!isSelectedV0Daughter(negtrack, -1)) { continue; } - Proton = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massPr); - Kshort = ROOT::Math::PxPyPzMVector(v0.px(), v0.py(), v0.pz(), massK0s); + Kshort = ROOT::Math::PxPyPzMVector(v0.px(), v0.py(), v0.pz(), v0.mK0Short()); Lambdac = Proton + Kshort; - if (TMath::Abs(Lambdac.Rapidity()) > confRapidity) { + // if (Lambdac.Pt() > 6.0 || Lambdac.Pt() < 2.0) { + // continue; + // } + if (std::abs(Lambdac.Rapidity()) > confRapidity) { continue; } auto phiminuspsi = GetPhiInRange(Lambdac.Phi() - psiFT0C); - auto v2 = TMath::Cos(2.0 * phiminuspsi); - histos.fill(HIST("hSparseV2SAMixedEvent_V2"), Lambdac.M(), Lambdac.Pt(), v2, std::abs(track1.dcaXY()), std::abs(v0.dcav0topv()), centrality); - auto diffangle = Proton.Phi() - Lambdac.Phi(); - auto decaylength = std::abs(track1.dcaXY() / TMath::Sin(diffangle)); - histos.fill(HIST("hSparseV2SAMixedEvent_V2_new"), Lambdac.M(), Lambdac.Pt(), v2, decaylength, centrality); - - ROOT::Math::Boost boost{Lambdac.BoostToCM()}; - fourVecDauCM = boost(Kshort); - threeVecDauCM = fourVecDauCM.Vect(); - threeVecDauCMXY = ROOT::Math::XYZVector(threeVecDauCM.X(), threeVecDauCM.Y(), 0.); - beamvector = ROOT::Math::XYZVector(0, 0, 1); - auto cosThetaStar = beamvector.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(beamvector.Mag2()); - auto SA = cosThetaStar * TMath::Sin(2.0 * phiminuspsi); - if (fillPolarization) { - if (track1.sign() > 0) { - histos.fill(HIST("hSparseV2SAMixedEventplus_SA"), Lambdac.M(), Lambdac.Pt(), cosThetaStar, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SAMixedEventplus_SA_A0"), Lambdac.M(), Lambdac.Pt(), cosThetaStar * cosThetaStar, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SAMixedEventplus_SA_azimuth"), Lambdac.M(), Lambdac.Pt(), SA, centrality); + v2 = TMath::Cos(2.0 * phiminuspsi) * QFT0C; + if (useSP) { + v2 = TMath::Cos(2.0 * phiminuspsi); + } + auto dcaV0toPV = std::abs(v0.dcav0topv()); + auto cpaV0 = v0.v0cosPA(); + auto ptV0 = v0.pt(); + auto dcaV0Daughters = std::abs(v0.dcaV0daughters()); + auto dcaProtonV0 = v0.dcav0topv() - track1.dcaXY(); + if (Lambdac.M() > cMinLambdaMass && Lambdac.M() <= cMaxLambdaMass && std::abs(Lambdac.Rapidity()) < confRapidity && Lambdac.Pt() > 1.0 && Lambdac.Pt() <= 6.0) { + if (useKshortOpti == 0) { + histos.fill(HIST("hSparseV2SAMixedEvent_V2"), Lambdac.M(), Lambdac.Pt(), std::abs(track1.dcaXY()), Proton.Pt()); + } + if (useKshortOpti == 1) { + histos.fill(HIST("hSparseV2SAMixedEvent_V2"), Lambdac.M(), Lambdac.Pt(), dcaV0toPV, cpaV0, ptV0, dcaV0Daughters, dcaProtonV0); + } + if (useKshortOpti == 2) { + histos.fill(HIST("hSparseV2SAMixedEvent_V2"), Lambdac.M(), Lambdac.Pt(), v2, std::abs(track1.dcaXY()), combinekaon(track1)); } - if (track1.sign() < 0) { - histos.fill(HIST("hSparseV2SAMixedEventminus_SA"), Lambdac.M(), Lambdac.Pt(), cosThetaStar, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SAMixedEventminus_SA_A0"), Lambdac.M(), Lambdac.Pt(), cosThetaStar * cosThetaStar, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SAMixedEventminus_SA_azimuth"), Lambdac.M(), Lambdac.Pt(), SA, centrality); + } + } + } + } + PROCESS_SWITCH(highmasslambda, processMixedEventOpti, "Process Mixed event new", false); + void processSameEventSvx(EventCandidates::iterator const& collision, TrackCandidatesSvx const& tracks, AllTrackCandidatesSvx const&, ResoV0sSvx const& V0s, aod::BCsWithTimestamps const&) + { + if (!collision.sel8() || !collision.triggereventep() || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return; + } + if (additionalEvSel && (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll) || !collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + return; + } + /// Set the magnetic field from ccdb. + auto bc = collision.template bc_as(); + if (runNumber != bc.runNumber()) { + o2::parameters::GRPMagField* grpo = ccdb->getForTimeStamp(ccdbPathGrpMag, bc.timestamp()); + if (grpo == nullptr) { + LOGF(fatal, "Run 3 GRP object (type o2::parameters::GRPMagField) is not available in CCDB for run=%d at timestamp=%llu", bc.runNumber(), bc.timestamp()); + } + o2::base::Propagator::initFieldFromGRP(grpo); + bz = o2::base::Propagator::Instance()->getNominalBz(); + runNumber = bc.runNumber(); + } + df.setBz(bz); + int occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy > cfgOccupancyCut) { + return; + } + o2::aod::ITSResponse itsResponse; + auto centrality = collision.centFT0C(); + // auto multTPC = collision.multNTracksPV(); + auto psiFT0C = collision.psiFT0C(); + auto psiFT0A = collision.psiFT0A(); + auto psiTPC = collision.psiTPC(); + auto psiTPCR = collision.psiTPCR(); + auto psiTPCL = collision.psiTPCL(); + auto QFT0C = collision.qFT0C(); + auto QFT0A = collision.qFT0A(); + auto QTPC = collision.qTPC(); + auto QTPCR = collision.qTPCR(); + auto QTPCL = collision.qTPCL(); + histos.fill(HIST("hPsiFT0C"), centrality, psiFT0C, occupancy); + histos.fill(HIST("hPsiFT0A"), centrality, psiFT0A, occupancy); + histos.fill(HIST("hPsiTPC"), centrality, psiTPC, occupancy); + histos.fill(HIST("ResFT0CTPC"), centrality, QFT0C * QTPC * TMath::Cos(2.0 * (psiFT0C - psiTPC))); + histos.fill(HIST("ResFT0CTPCR"), centrality, QFT0C * QTPCR * TMath::Cos(2.0 * (psiFT0C - psiTPCR))); + histos.fill(HIST("ResFT0CTPCL"), centrality, QFT0C * QTPCL * TMath::Cos(2.0 * (psiFT0C - psiTPCL))); + histos.fill(HIST("ResTPCRTPCL"), centrality, QTPCR * QTPCL * TMath::Cos(2.0 * (psiTPCR - psiTPCL))); + histos.fill(HIST("ResFT0CFT0A"), centrality, QFT0C * QFT0A * TMath::Cos(2.0 * (psiFT0C - psiFT0A))); + histos.fill(HIST("ResFT0ATPC"), centrality, QTPC * QFT0A * TMath::Cos(2.0 * (psiTPC - psiFT0A))); + histos.fill(HIST("hCentrality"), centrality); + histos.fill(HIST("hVtxZ"), collision.posZ()); + histos.fill(HIST("hOccupancy"), occupancy); + auto firstprimarytrack = 0; + for (auto track1 : tracks) { + if (!selectionTrack(track1)) { + continue; + } + histos.fill(HIST("hNsigmaProtonITS"), itsResponse.nSigmaITS(track1), track1.pt()); + if (track1.p() < 1.0 && !(itsResponse.nSigmaITS(track1) > -nsigmaCutITS && itsResponse.nSigmaITS(track1) < nsigmaCutITS)) { + continue; + } + + histos.fill(HIST("hNsigmaProtonTPCPre"), track1.tpcNSigmaPr(), track1.pt()); + // PID check + if (PIDstrategy == 0 && !selectionPID7(track1)) { + continue; + } + if (PIDstrategy == 1 && !selectionPID8(track1)) { + continue; + } + if (PIDstrategy == 2 && !selectionPID9(track1)) { + continue; + } + if (PIDstrategy == 3 && !selectionPID10(track1)) { + continue; + } + histos.fill(HIST("hEta"), track1.eta()); + histos.fill(HIST("hDcaxy"), track1.dcaXY()); + histos.fill(HIST("hDcaz"), track1.dcaZ()); + histos.fill(HIST("hNsigmaProtonTPC"), track1.tpcNSigmaPr(), track1.pt()); + if (track1.hasTOF()) { + histos.fill(HIST("hNsigmaProtonTOF"), track1.tofNSigmaPr(), track1.pt()); + } + auto track1ID = track1.globalIndex(); + auto trackParCovBach = getTrackParCov(track1); + // auto trackParCovBach = getTrackParCov(bach); + + for (auto v0 : V0s) { + if (!SelectionV0(collision, v0)) { + continue; + } + if (firstprimarytrack == 0) { + histos.fill(HIST("hV0Dca"), v0.dcav0topv()); + } + auto postrack = v0.template posTrack_as(); + auto negtrack = v0.template negTrack_as(); + if (!isSelectedV0Daughter(postrack, 1)) { + continue; + } + if (!isSelectedV0Daughter(negtrack, -1)) { + continue; + } + if (track1ID == postrack.globalIndex()) { + continue; + } + if (track1ID == negtrack.globalIndex()) { + continue; + } + if (firstprimarytrack == 0) { + histos.fill(HIST("hInvMassKs0"), v0.mK0Short()); + } + firstprimarytrack = firstprimarytrack + 1; + // LOGF(info, "Before dca fitter"); + std::array pVecV0 = {0., 0., 0.}; + std::array pVecBach = {0., 0., 0.}; + // std::array pVecCand = {0., 0., 0.}; + const std::array vertexV0 = {v0.x(), v0.y(), v0.z()}; + const std::array momentumV0 = {v0.px(), v0.py(), v0.pz()}; + // we build the neutral track to then build the cascade + std::array covV = {0.}; + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 6; i++) { + covV[MomInd[i]] = v0.momentumCovMat()[i]; + covV[i] = v0.positionCovMat()[i]; + } + auto trackV0 = o2::track::TrackParCov(vertexV0, momentumV0, covV, 0, true); + trackV0.setAbsCharge(0); + trackV0.setPID(o2::track::PID::K0); + + int nCand2 = 0; + try { + nCand2 = df.process(trackV0, trackParCovBach); + } catch (...) { + continue; + } + + if (nCand2 == 0) { + continue; + } + df.propagateTracksToVertex(); // propagate the bach and V0 to the Lc vertex + df.getTrack(0).getPxPyPzGlo(pVecV0); // take the momentum at the Lc vertex + df.getTrack(1).getPxPyPzGlo(pVecBach); + // LOGF(info, "after dca fitter"); + + /* + float v0x, v0y, v0z, v0px, v0py, v0pz; + float posTrackX, negTrackX; + o2::track::TrackParCov trackParCovV0DaughPos; + o2::track::TrackParCov trackParCovV0DaughNeg; + trackParCovV0DaughPos = getTrackParCov(postrack); // check that aod::TracksWCov does not need TracksDCA! + trackParCovV0DaughNeg = getTrackParCov(negtrack); // check that aod::TracksWCov does not need TracksDCA! + posTrackX = v0.posX(); + negTrackX = v0.negX(); + v0x = v0.x(); + v0y = v0.y(); + v0z = v0.z(); + const std::array vertexV0 = {v0x, v0y, v0z}; + + v0px = v0.px(); + v0py = v0.py(); + v0pz = v0.pz(); + const std::array momentumV0 = {v0px, v0py, v0pz}; + + std::array covV0Pos = {0.}; + for (int i = 0; i < 6; i++) { + covV0Pos[i] = v0.positionCovMat()[i]; + } + trackParCovV0DaughPos.propagateTo(posTrackX, bz); // propagate the track to the X closest to the V0 vertex + trackParCovV0DaughNeg.propagateTo(negTrackX, bz); // propagate the track to the X closest to the V0 vertex + + // we build the neutral track to then build the cascade + // auto trackV0 = o2::dataformats::V0(vertexV0, momentumV0, {0, 0, 0, 0, 0, 0}, trackParCovV0DaughPos, trackParCovV0DaughNeg); // build the V0 track (indices for v0 daughters set to 0 for now) + auto trackV0 = o2::dataformats::V0(vertexV0, momentumV0, covV0Pos, trackParCovV0DaughPos, trackParCovV0DaughNeg); // build the V0 track (indices for v0 daughters set to 0 for now) + std::array pVecV0 = {0., 0., 0.}; + std::array pVecBach = {0., 0., 0.}; + std::array pVecCand = {0., 0., 0.}; + try { + if (df.process(trackV0, trackParCovBach) == 0) { + continue; + } else { + } + } catch (const std::runtime_error& error) { + continue; + } + df.propagateTracksToVertex(); // propagate the bachelor and V0 to the Lambdac vertex + trackV0.getPxPyPzGlo(pVecV0); // momentum of D0 at the Lambdac vertex + trackParCovBach.getPxPyPzGlo(pVecBach); // momentum of proton at the Lambdac vertex + */ + + const auto& secondaryVertex = df.getPCACandidate(); + auto primaryVertex = getPrimaryVertex(collision); + o2::dataformats::DCA impactParameter0; + o2::dataformats::DCA impactParameter1; + trackV0.propagateToDCA(primaryVertex, bz, &impactParameter0); + trackParCovBach.propagateToDCA(primaryVertex, bz, &impactParameter1); + double phi, theta; + getPointDirection(std::array{collision.posX(), collision.posY(), collision.posZ()}, secondaryVertex, phi, theta); + // auto errorDecayLength = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); + // auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); + + Kshort = ROOT::Math::PxPyPzMVector(pVecV0[0], pVecV0[1], pVecV0[2], massK0s); + Proton = ROOT::Math::PxPyPzMVector(pVecBach[0], pVecBach[1], pVecBach[2], massPr); + Lambdac = Proton + Kshort; + auto phiminuspsi = GetPhiInRange(Lambdac.Phi() - psiFT0C); + v2 = TMath::Cos(2.0 * phiminuspsi) * QFT0C; + if (useSP) { + v2 = TMath::Cos(2.0 * phiminuspsi); + } + double protonimpactparameter = impactParameter1.getY(); + double kshortimpactparameter = impactParameter0.getY(); + + double decaylengthx = secondaryVertex[0] - collision.posX(); + double decaylengthy = secondaryVertex[1] - collision.posY(); + double decaylengthz = secondaryVertex[2] - collision.posZ(); + double decaylength = TMath::Sqrt(decaylengthx * decaylengthx + decaylengthy * decaylengthy + decaylengthz * decaylengthz); + double decaylengthxy = TMath::Sqrt(decaylengthx * decaylengthx + decaylengthy * decaylengthy); + double anglesign = decaylengthx * Lambdac.Px() + decaylengthy * Lambdac.Py() + decaylengthz * Lambdac.Pz(); + double CPAlambdac = anglesign / (decaylength * Lambdac.P()); + + histos.fill(HIST("hDecayLengthxy"), decaylengthxy); + histos.fill(HIST("hDecayLength"), decaylength); + histos.fill(HIST("hImpactPar0"), protonimpactparameter); + histos.fill(HIST("hImpactPar1"), kshortimpactparameter); + histos.fill(HIST("hCPA"), CPAlambdac); + histos.fill(HIST("hMomCorr"), Proton.P() - track1.p(), v0.p() - Kshort.P()); + if (Lambdac.M() > cMinLambdaMass && Lambdac.M() <= cMaxLambdaMass && std::abs(Lambdac.Rapidity()) < confRapidity && Lambdac.Pt() > 1.0 && Lambdac.Pt() <= 6.0 && decaylength < ConfMaxDecayLength && CPAlambdac > ConfMinCPA) { + histos.fill(HIST("hSparseV2SASameEvent_V2_SVX"), Lambdac.M(), Lambdac.Pt(), v2, decaylength, CPAlambdac); + } + if (fillRotation) { + for (int nrotbkg = 0; nrotbkg < nBkgRotations; nrotbkg++) { + auto anglestart = confMinRot; + auto angleend = confMaxRot; + auto anglestep = (angleend - anglestart) / (1.0 * (nBkgRotations - 1)); + auto rotangle = anglestart + nrotbkg * anglestep; + histos.fill(HIST("hRotation"), rotangle); + float rotKaonPx = Kshort.px() * std::cos(rotangle) - Kshort.py() * std::sin(rotangle); + float rotKaonPy = Kshort.px() * std::sin(rotangle) + Kshort.py() * std::cos(rotangle); + ////////// DCA fitter //////////////// + // LOGF(info, "Before dca fitter"); + std::array pVecV0rot = {0., 0., 0.}; + std::array pVecBachrot = {0., 0., 0.}; + const std::array momentumV0rot = {rotKaonPx, rotKaonPy, v0.pz()}; + auto trackV0rot = o2::track::TrackParCov(vertexV0, momentumV0rot, covV, 0, true); + trackV0rot.setAbsCharge(0); + trackV0rot.setPID(o2::track::PID::K0); + int nCand2rot = 0; + try { + nCand2rot = df.process(trackV0rot, trackParCovBach); + } catch (...) { + continue; + } + if (nCand2rot == 0) { + continue; + } + df.propagateTracksToVertex(); // propagate the bach and V0 to the Lc vertex + df.getTrack(0).getPxPyPzGlo(pVecV0rot); // take the momentum at the Lc vertex + df.getTrack(1).getPxPyPzGlo(pVecBachrot); + const auto& secondaryVertexrot = df.getPCACandidate(); + double phirot, thetarot; + getPointDirection(std::array{collision.posX(), collision.posY(), collision.posZ()}, secondaryVertexrot, phirot, thetarot); + KshortRot = ROOT::Math::PxPyPzMVector(pVecV0rot[0], pVecV0rot[1], pVecV0rot[2], massK0s); + Proton = ROOT::Math::PxPyPzMVector(pVecBachrot[0], pVecBachrot[1], pVecBachrot[2], massPr); + LambdacRot = Proton + KshortRot; + auto phiminuspsiRot = GetPhiInRange(LambdacRot.Phi() - psiFT0C); + v2Rot = TMath::Cos(2.0 * phiminuspsiRot) * QFT0C; + if (useSP) { + v2Rot = TMath::Cos(2.0 * phiminuspsiRot); + } + double decaylengthxrot = secondaryVertexrot[0] - collision.posX(); + double decaylengthyrot = secondaryVertexrot[1] - collision.posY(); + double decaylengthzrot = secondaryVertexrot[2] - collision.posZ(); + double decaylengthrot = TMath::Sqrt(decaylengthxrot * decaylengthxrot + decaylengthyrot * decaylengthyrot + decaylengthzrot * decaylengthzrot); + // double decaylengthxyrot = TMath::Sqrt(decaylengthxrot * decaylengthxrot + decaylengthyrot * decaylengthyrot); + double anglesignrot = decaylengthxrot * LambdacRot.Px() + decaylengthyrot * LambdacRot.Py() + decaylengthzrot * LambdacRot.Pz(); + double CPAlambdacrot = anglesignrot / (decaylengthrot * LambdacRot.P()); + if (LambdacRot.M() > cMinLambdaMass && LambdacRot.M() <= cMaxLambdaMass && std::abs(LambdacRot.Rapidity()) < confRapidity && LambdacRot.Pt() > 1.0 && LambdacRot.Pt() <= 6.0 && decaylengthrot < ConfMaxDecayLength && CPAlambdacrot > ConfMinCPA) { + histos.fill(HIST("hSparseV2SASameEventRotational_V2_SVX"), LambdacRot.M(), LambdacRot.Pt(), v2Rot, decaylength, CPAlambdacrot); + } } } } } } - PROCESS_SWITCH(highmasslambda, processMixedEventOpti, "Process Mixed event new", true); + PROCESS_SWITCH(highmasslambda, processSameEventSvx, "Process Same event SVX", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGLF/Tasks/Resonances/highmasslambdasvx.cxx b/PWGLF/Tasks/Resonances/highmasslambdasvx.cxx new file mode 100644 index 00000000000..d6405483d13 --- /dev/null +++ b/PWGLF/Tasks/Resonances/highmasslambdasvx.cxx @@ -0,0 +1,927 @@ +// 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. +// Phi meson spin alignment task +// sourav.kundu@cern.ch + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TRandom3.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" +#include "TF1.h" + +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "Framework/runDataProcessing.h" +#include "DCAFitter/DCAFitterN.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/TrackSelection.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsTrkCandHf.h" +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/V0.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; +struct highmasslambdasvx { + + int mRunNumber; + int multEstimator; + float d_bz; + Service ccdb; + Service pdg; + + o2::vertexing::DCAFitterN<2> df; // 2-prong vertex fitter + o2::base::MatLayerCylSet* lut; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + int runNumber{0}; + double bz = 0.; + + // CCDB options + // Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + // Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + // Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + // Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + // Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + + // fill output + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; + Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + Configurable isRun2{"isRun2", false, "enable Run 2 or Run 3 GRP objects for magnetic field"}; + Configurable useSP{"useSP", false, "useSP"}; + Configurable additionalEvSel{"additionalEvSel", true, "additionalEvSel"}; + Configurable additionalEvSel2{"additionalEvSel2", false, "additionalEvSel2"}; + // events + Configurable cnfabsdca{"cnfabsdca", false, "Use Abs DCA for secondary vertex fitting"}; + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutCentralityMax{"cfgCutCentralityMax", 50.0f, "Accepted maximum Centrality"}; + Configurable cfgCutCentralityMin{"cfgCutCentralityMin", 30.0f, "Accepted minimum Centrality"}; + // proton track cut + Configurable useDecayLengthxy{"useDecayLengthxy", true, "use decay length xy"}; + Configurable ispTdifferentialDCA{"ispTdifferentialDCA", true, "is pT differential DCA"}; + Configurable confMinRot{"confMinRot", 5.0 * TMath::Pi() / 6.0, "Minimum of rotation"}; + Configurable confMaxRot{"confMaxRot", 7.0 * TMath::Pi() / 6.0, "Maximum of rotation"}; + Configurable confRapidity{"confRapidity", 0.8, "cut on Rapidity"}; + Configurable cfgCutPT{"cfgCutPT", 0.3, "PT cut on daughter track"}; + Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; + Configurable cfgCutDCAxymin1{"cfgCutDCAxymin1", 0.005f, "Minimum DCAxy range for tracks pt 0 to 0.5"}; + Configurable cfgCutDCAxymin2{"cfgCutDCAxymin2", 0.003f, "Minimum DCAxy range for tracks pt 0.5 to 1"}; + Configurable cfgCutDCAxymin3{"cfgCutDCAxymin3", 0.003f, "Minimum DCAxy range for tracks pt 1.0 to 1.5"}; + Configurable cfgCutDCAxymin4{"cfgCutDCAxymin4", 0.002f, "Minimum DCAxy range for tracks pt 1.5 to 2.0"}; + Configurable cfgCutDCAxymin5{"cfgCutDCAxymin5", 0.001f, "Minimum DCAxy range for tracks pt 2.0 to 2.5"}; + Configurable cfgCutDCAxymin6{"cfgCutDCAxymin6", 0.0003f, "Minimum DCAxy range for tracks pt 2.5 to 3.0"}; + Configurable cfgCutDCAxymin7{"cfgCutDCAxymin7", 0.0003f, "Minimum DCAxy range for tracks pt 3.0 to 4.0"}; + Configurable cfgCutDCAxymin8{"cfgCutDCAxymin8", 0.0003f, "Minimum DCAxy range for tracks pt 4.0 to 10.0"}; + Configurable cfgCutDCAxy{"cfgCutDCAxy", 0.1f, "DCAxy range for tracks"}; + Configurable cfgCutDCAz{"cfgCutDCAz", 1.0f, "DCAz range for tracks"}; + Configurable cfgITScluster{"cfgITScluster", 5, "Number of ITS cluster"}; + Configurable cfgITSclusterInnerlayer{"cfgITSclusterInnerlayer", 1, "Minimum Number of ITS cluster in inner barrel"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; + Configurable PIDstrategy{"PIDstrategy", 0, "0: TOF Veto, 1: TOF Veto opti, 2: TOF, 3: TOF loose 1, 4: TOF loose 2, 5: old pt dep"}; + Configurable nsigmaCutTPC{"nsigmacutTPC", 3.0, "Value of the TPC Nsigma cut"}; + Configurable nsigmaCutCombined{"nsigmaCutCombined", 3.0, "TPC TOF combined PID"}; + Configurable nsigmaCutTPCPre{"nsigmacutTPCPre", 3.0, "Value of the TPC Nsigma cut Pre filter"}; + // Configs for V0 + Configurable ConfV0DCADaughMax{"ConfV0DCADaughMax", 0.2f, "Maximum DCA between the V0 daughters"}; + Configurable ConfV0CPAMin{"ConfV0CPAMin", 0.9998f, "Minimum CPA of V0"}; + Configurable cMaxV0DCA{"cMaxV0DCA", 0.1, "Maximum V0 DCA to PV"}; + Configurable cMaxV0LifeTime{"cMaxV0LifeTime", 20, "Maximum V0 life time"}; + Configurable cSigmaMassKs0{"cSigmaMassKs0", 0.006, "Sigma cut on KS0 mass"}; + Configurable cMinLambdaMass{"cMinLambdaMass", 2.18, "Minimum lambda mass"}; + Configurable cMaxLambdaMass{"cMaxLambdaMass", 2.42, "Maximum lambda mass"}; + + // config for V0 daughters + Configurable ConfDaughPt{"ConfDaughPt", 0.1f, "V0 Daugh sel: min pt"}; + Configurable ConfDaughTPCnclsMin{"ConfDaughTPCnclsMin", 50.f, "V0 Daugh sel: Min. nCls TPC"}; + Configurable ConfDaughDCAMin{"ConfDaughDCAMin", 0.08f, "V0 Daugh sel: Max. DCA Daugh to PV (cm)"}; + Configurable ConfDaughPIDCuts{"ConfDaughPIDCuts", 3, "PID selections for KS0 daughters"}; + // Fill strategy + // Configurable cfgSelectDaughterTopology{"cfgSelectDaughterTopology", 2, "Select daughter for topology"}; + // Mixed event + Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 1, "Number of mixed events per event"}; + /// activate rotational background + Configurable nBkgRotations{"nBkgRotations", 9, "Number of rotated copies (background) per each original candidate"}; + Configurable cutchi2PCA{"cutchi2PCA", 0.1f, "cut on chi2PCA"}; + // THnsparse bining + ConfigurableAxis configThnAxisInvMass{"configThnAxisInvMass", {60, 2.15, 2.45}, "#it{M} (GeV/#it{c}^{2})"}; + ConfigurableAxis configThnAxisV2{"configThnAxisV2", {80, -1, 1}, "V2"}; + ConfigurableAxis configThnAxisSA{"configThnAxisSA", {100, -1, 1}, "SA"}; + ConfigurableAxis configThnAxisPhiminusPsi{"configThnAxisPhiminusPsi", {6, 0.0, TMath::Pi()}, "#phi - #psi"}; + ConfigurableAxis configThnAxisCentrality{"configThnAxisCentrality", {1, 30., 50}, "Centrality"}; + ConfigurableAxis configThnAxisDecayLength{"configThnAxisDecayLength", {60, 0.0, 0.06}, "Decay length"}; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter centralityFilter = (nabs(aod::cent::centFT0C) < cfgCutCentralityMax && nabs(aod::cent::centFT0C) > cfgCutCentralityMin); + Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPT); + Filter dcaCutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); + Filter pidFilter = nabs(aod::pidtpc::tpcNSigmaPr) < nsigmaCutTPCPre; + + using EventCandidates = soa::Filtered>; + // using TrackCandidates = soa::Filtered>; + // using AllTrackCandidates = soa::Join; + + using TrackCandidates = soa::Filtered>; + using AllTrackCandidates = soa::Join; + using ResoV0s = soa::Join; + + SliceCache cache; + // Partition posTracks = aod::track::signed1Pt > cfgCutCharge; + // Partition negTracks = aod::track::signed1Pt < cfgCutCharge; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + std::vector occupancyBinning = {0.0, 500.0, 1000.0, 1500.0, 2000.0, 3000.0, 4000.0, 5000.0, 50000.0}; + std::vector dcaBinning = {0.0, 0.0005, 0.001, 0.002, 0.003, 0.004, 0.006, 0.3}; + std::vector ptProtonBinning = {0.0, 0.3, 0.5, 0.8, 1.2, 6.0}; + std::vector ptLambdaBinning = {2.0, 3.0, 4.0, 5.0, 6.0}; + + AxisSpec phiAxis = {500, -6.28, 6.28, "phi"}; + AxisSpec decaylengthAxis = {configThnAxisDecayLength, "decaylength"}; + AxisSpec resAxis = {1000, -10, 10, "Res"}; + AxisSpec centAxis = {8, 0, 80, "V0M (%)"}; + const AxisSpec thnAxisInvMass{configThnAxisInvMass, "#it{M} (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisV2{configThnAxisV2, "V2"}; + const AxisSpec thnAxisCentrality{configThnAxisCentrality, "Centrality (%)"}; + const AxisSpec thnAxisPhiminusPsi{configThnAxisPhiminusPsi, "#phi - #psi"}; + AxisSpec occupancyAxis = {occupancyBinning, "occupancy"}; + AxisSpec ptAxis = {ptLambdaBinning, "pt"}; + AxisSpec dcaAxis = {dcaBinning, "dca"}; + AxisSpec ptProtonAxis = {ptProtonBinning, "daughter pt"}; + histos.add("hSparseV2SASameEvent_V2_EP", "hSparseV2SASameEvent_V2_EP", HistType::kTHnSparseF, {thnAxisInvMass, ptAxis, thnAxisV2, ptProtonAxis, decaylengthAxis, dcaAxis}); + histos.add("hSparseV2SASameEventRotational_V2_EP", "hSparseV2SASameEventRotational_V2_EP", HistType::kTHnSparseF, {thnAxisInvMass, ptAxis, thnAxisV2, ptProtonAxis, decaylengthAxis, dcaAxis}); + histos.add("hV0decaylength", "hV0decaylength", kTH1F, {{1000, 0.0f, 1000.0f}}); + histos.add("hMomCorr", "hMomCorr", kTH3F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}, {8, 0.0f, 80.0f}}); + histos.add("hInvMassKs0", "hInvMassKs0", kTH1F, {{200, 0.4f, 0.6f}}); + histos.add("hchi2PCA", "hchi2PCA", kTH1F, {{1000, 0.0f, 1.f}}); + histos.add("hFTOCvsTPCNoCut", "Mult correlation FT0C vs. TPC without any cut", kTH2F, {{80, 0.0f, 80.0f}, {100, -0.5f, 5999.5f}}); + histos.add("hFTOCvsTPC", "Mult correlation FT0C vs. TPC", kTH2F, {{80, 0.0f, 80.0f}, {100, -0.5f, 5999.5f}}); + histos.add("hFTOCvsTPCSelected", "Mult correlation FT0C vs. TPC after selection", kTH2F, {{80, 0.0f, 80.0f}, {100, -0.5f, 5999.5f}}); + histos.add("hCentrality", "Centrality distribution", kTH1F, {{200, 0.0, 200.0}}); + histos.add("hVtxZ", "Vertex distribution in Z;Z (cm)", kTH1F, {{400, -20.0, 20.0}}); + histos.add("hOccupancy", "Occupancy", kTH1F, {{5000, 0.0, 50000.0}}); + histos.add("hRotation", "hRotation", kTH1F, {{360, 0.0, 2.0 * TMath::Pi()}}); + + histos.add("hNsigmaProtonTPCDiff", "Difference NsigmaProton NsigmaKaon TPC distribution", kTH3F, {{100, -5.0f, 5.0f}, {100, -5.0f, 5.0f}, {80, 0.0f, 8.0f}}); + histos.add("hNsigmaProtonTPC", "NsigmaProton TPC distribution", kTH2F, {{100, -5.0f, 5.0f}, {80, 0.0f, 8.0f}}); + histos.add("hNsigmaProtonTOF", "NsigmaProton TOF distribution", kTH2F, {{100, -5.0f, 5.0f}, {80, 0.0f, 8.0f}}); + + histos.add("hEta", "Eta distribution", kTH1F, {{200, -1.0f, 1.0f}}); + histos.add("hDcaz", "Dcaz distribution", kTH1F, {{1000, -0.5f, 0.5f}}); + histos.add("hDcaxy", "Dcaxy distribution", kTH1F, {{1000, -0.5f, 0.5f}}); + histos.add("hsignprotonDca", "hsignprotonDca", kTH1F, {{2000, -1.0f, 1.0f}}); + histos.add("hunsignprotonDca", "hunsignprotonDca", kTH1F, {{2000, -1.0f, 1.0f}}); + histos.add("hsignCPALambdac", "hsignCPALambdac", kTH1F, {{2000, -1.0f, 1.0f}}); + + histos.add("hPsiFT0C", "PsiFT0C", kTH3F, {centAxis, phiAxis, occupancyAxis}); + histos.add("hPsiFT0A", "PsiFT0A", kTH3F, {centAxis, phiAxis, occupancyAxis}); + histos.add("hPsiTPC", "PsiTPC", kTH3F, {centAxis, phiAxis, occupancyAxis}); + histos.add("hPsiTPCR", "PsiTPCR", kTH3F, {centAxis, phiAxis, occupancyAxis}); + histos.add("hPsiTPCL", "PsiTPCL", kTH3F, {centAxis, phiAxis, occupancyAxis}); + + // histogram for resolution + histos.add("ResFT0CTPC", "ResFT0CTPC", kTH2F, {centAxis, resAxis}); + histos.add("ResFT0CTPCR", "ResFT0CTPCR", kTH2F, {centAxis, resAxis}); + histos.add("ResFT0CTPCL", "ResFT0CTPCL", kTH2F, {centAxis, resAxis}); + histos.add("ResTPCRTPCL", "ResTPCRTPCL", kTH2F, {centAxis, resAxis}); + histos.add("ResFT0CFT0A", "ResFT0CFT0A", kTH2F, {centAxis, resAxis}); + histos.add("ResFT0ATPC", "ResFT0ATPC", kTH2F, {centAxis, resAxis}); + + df.setPropagateToPCA(true); + df.setMaxR(200); + df.setMaxDZIni(4); + df.setMinParamChange(1.e-3); + df.setMinRelChi2Change(0.9); + df.setUseAbsDCA(cnfabsdca); + df.setWeightedFinalPCA(true); + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); + runNumber = 0; + } + template + bool selectionTrack(const T& candidate) + { + if (!(candidate.isGlobalTrackWoDCA() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsFound() > cfgTPCcluster && candidate.itsNClsInnerBarrel() >= cfgITSclusterInnerlayer)) { + return false; + } + if (candidate.pt() > 0.0 && candidate.pt() < 0.5 && TMath::Abs(candidate.dcaXY()) < cfgCutDCAxymin1) { + return false; + } + if (candidate.pt() >= 0.5 && candidate.pt() < 1.0 && TMath::Abs(candidate.dcaXY()) < cfgCutDCAxymin2) { + return false; + } + if (candidate.pt() >= 1.0 && candidate.pt() < 1.5 && TMath::Abs(candidate.dcaXY()) < cfgCutDCAxymin3) { + return false; + } + if (candidate.pt() >= 1.5 && candidate.pt() < 2.0 && TMath::Abs(candidate.dcaXY()) < cfgCutDCAxymin4) { + return false; + } + if (candidate.pt() >= 2.0 && candidate.pt() < 3.0 && TMath::Abs(candidate.dcaXY()) < cfgCutDCAxymin5) { + return false; + } + if (candidate.pt() >= 3.0 && TMath::Abs(candidate.dcaXY()) < cfgCutDCAxymin6) { + return false; + } + return true; + } + + template + bool rejectPi(const T& candidate) + { + if (candidate.tpcInnerParam() > 0.9 && candidate.tpcInnerParam() < 1.0 && candidate.tpcNSigmaPi() < 6.0) { + return false; + } + if (candidate.tpcInnerParam() > 1.0 && candidate.tpcInnerParam() < 1.1 && candidate.tpcNSigmaPi() < 4.0) { + return false; + } + if (candidate.tpcInnerParam() > 1.1 && candidate.tpcInnerParam() < 1.2 && candidate.tpcNSigmaPi() < 3.0) { + return false; + } + if (candidate.tpcInnerParam() > 1.2 && candidate.tpcInnerParam() < 1.4 && candidate.tpcNSigmaPi() < 1.0) { + return false; + } + if (candidate.tpcInnerParam() > 1.4 && candidate.tpcInnerParam() < 1.5 && candidate.tpcNSigmaPi() < 0.5) { + return false; + } + return true; + } + + template + bool rejectEl(const T& candidate) + { + + if (candidate.tpcInnerParam() > 0.7 && candidate.tpcInnerParam() < 0.8 && candidate.tpcNSigmaEl() < 2.0) { + return false; + } + if (candidate.tpcInnerParam() > 0.8 && candidate.tpcInnerParam() < 0.9 && candidate.tpcNSigmaEl() < 0.0) { + return false; + } + if (candidate.tpcInnerParam() > 0.9 && candidate.tpcInnerParam() < 1.0 && candidate.tpcNSigmaEl() < -1.0) { + return false; + } + if (candidate.tpcInnerParam() > 1.0 && candidate.tpcInnerParam() < 1.1 && candidate.tpcNSigmaEl() < -2.0) { + return false; + } + if (candidate.tpcInnerParam() > 1.1 && candidate.tpcInnerParam() < 1.2 && candidate.tpcNSigmaEl() < -3.0) { + return false; + } + + return true; + } + + template + bool rejectKa(const T& candidate) + { + if (candidate.tpcInnerParam() > 0.7 && candidate.tpcInnerParam() < 0.8 && candidate.tpcNSigmaKa() < 7.5) { + return false; + } + if (candidate.tpcInnerParam() > 0.8 && candidate.tpcInnerParam() < 0.9 && candidate.tpcNSigmaKa() < 6.0) { + return false; + } + if (candidate.tpcInnerParam() > 0.9 && candidate.tpcInnerParam() < 1.1 && candidate.tpcNSigmaKa() < 5.0) { + return false; + } + if (candidate.tpcInnerParam() > 1.1 && candidate.tpcInnerParam() < 1.2 && candidate.tpcNSigmaKa() < 3.5) { + return false; + } + if (candidate.tpcInnerParam() > 1.2 && candidate.tpcInnerParam() < 1.4 && candidate.tpcNSigmaKa() < 3.0) { + return false; + } + if (candidate.tpcInnerParam() > 1.4 && candidate.tpcInnerParam() < 1.5 && candidate.tpcNSigmaKa() < 2.5) { + return false; + } + return true; + } + + // TPC TOF + template + bool selectionPID1(const T& candidate) + { + if (candidate.tpcInnerParam() < 0.7 && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0) { + return true; + } + if (candidate.tpcInnerParam() >= 0.7) { + // printf("I am here: %.3f\n", candidate.tpcInnerParam()); + if (candidate.hasTOF()) { + auto combinedPID = TMath::Sqrt(candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr() + candidate.tofNSigmaPr() * candidate.tofNSigmaPr()) / TMath::Sqrt(2.0); + // printf("combine PIDA: %.3f\n", combinedPID); + if (combinedPID < nsigmaCutCombined) { + return true; + } + } + if (!candidate.hasTOF()) { + if (candidate.tpcInnerParam() < 1.5 && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0) { + return true; + } + if (candidate.tpcInnerParam() >= 1.5 && candidate.tpcNSigmaPr() > -2.0 && candidate.tpcNSigmaPr() < 2.0) { + return true; + } + } + } + return false; + } + + // TOF Veto + template + bool selectionPID2(const T& candidate) + { + if (candidate.tpcInnerParam() < 0.7 && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0) { + return true; + } + if (candidate.tpcInnerParam() >= 0.7) { + if (candidate.hasTOF()) { + auto combinedPID = TMath::Sqrt(candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr() + candidate.tofNSigmaPr() * candidate.tofNSigmaPr()) / TMath::Sqrt(2.0); + if (combinedPID < nsigmaCutCombined) { + return true; + } + } + } + return false; + } + + // TOF veto loose + template + bool selectionPID3(const T& candidate) + { + if (candidate.tpcInnerParam() < 0.7 && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0) { + return true; + } + if (candidate.tpcInnerParam() >= 0.7) { + if (candidate.hasTOF()) { + auto combinedPID = TMath::Sqrt(candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr() + candidate.tofNSigmaPr() * candidate.tofNSigmaPr()) / TMath::Sqrt(2.0); + if (combinedPID < nsigmaCutCombined) { + return true; + } + } + if (!candidate.hasTOF()) { + if (candidate.tpcInnerParam() < 1.5 && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0) { + return true; + } + } + } + return false; + } + + // TOF veto very loose + template + bool selectionPID4(const T& candidate) + { + if (candidate.tpcInnerParam() < 0.7 && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0) { + return true; + } + if (candidate.tpcInnerParam() >= 0.7) { + if (candidate.hasTOF()) { + auto combinedPID = TMath::Sqrt(candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr() + candidate.tofNSigmaPr() * candidate.tofNSigmaPr()) / TMath::Sqrt(2.0); + if (combinedPID < nsigmaCutCombined) { + return true; + } + } + if (!candidate.hasTOF()) { + if (candidate.tpcInnerParam() < 1.5 && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0) { + return true; + } + if (candidate.tpcInnerParam() >= 1.5 && candidate.tpcInnerParam() < 1.8 && candidate.tpcNSigmaPr() > -1.5 && candidate.tpcNSigmaPr() < 2.0) { + return true; + } + } + } + return false; + } + + template + bool SelectionV0(Collision const& collision, V0 const& candidate) + { + // const float pT = candidate.pt(); + const std::vector decVtx = {candidate.x(), candidate.y(), candidate.z()}; + const float tranRad = candidate.v0radius(); + const double dcaDaughv0 = TMath::Abs(candidate.dcaV0daughters()); + const double cpav0 = candidate.v0cosPA(); + float decaylength = TMath::Sqrt(TMath::Power(collision.posX() - candidate.x(), 2.0) + TMath::Power(collision.posY() - candidate.y(), 2.0) + TMath::Power(collision.posZ() - candidate.z(), 2.0)); + float CtauK0s = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * TDatabasePDG::Instance()->GetParticle(kK0Short)->Mass(); // FIXME: Get from the common header + float lowmasscutks0 = 0.497 - 2.0 * cSigmaMassKs0; + float highmasscutks0 = 0.497 + 2.0 * cSigmaMassKs0; + + if (TMath::Abs(CtauK0s) < 2.0 || TMath::Abs(CtauK0s) > cMaxV0LifeTime || candidate.mK0Short() < lowmasscutks0 || candidate.mK0Short() > highmasscutks0) { + return false; + } + if (dcaDaughv0 > ConfV0DCADaughMax) { + return false; + } + if (TMath::Abs(candidate.dcav0topv()) > cMaxV0DCA) { + return false; + } + if (cpav0 < ConfV0CPAMin) { + return false; + } + if (decaylength > 100) { + return false; + } + if (tranRad > 100) { + return false; + } + return true; + } + template + bool isSelectedV0Daughter(T const& track, float charge) + { + const auto eta = track.eta(); + const auto pt = track.pt(); + const auto tpcNClsF = track.tpcNClsFound(); + const auto dcaXY = track.dcaXY(); + const auto sign = track.sign(); + if (charge < 0 && sign > 0) { + return false; + } + if (charge > 0 && sign < 0) { + return false; + } + if (TMath::Abs(eta) > 0.8) { + return false; + } + if (TMath::Abs(pt) < ConfDaughPt) { + return false; + } + if (tpcNClsF < ConfDaughTPCnclsMin) { + return false; + } + if (TMath::Abs(dcaXY) < ConfDaughDCAMin) { + return false; + } + if (TMath::Abs(track.tpcNSigmaPi()) > ConfDaughPIDCuts) { + return false; + } + return true; + } + + double GetPhiInRange(double phi) + { + double result = phi; + while (result < 0) { + result = result + 2. * TMath::Pi() / 2; + } + while (result > 2. * TMath::Pi() / 2) { + result = result - 2. * TMath::Pi() / 2; + } + return result; + } + + ConfigurableAxis axisVertex{"axisVertex", {10, -10, 10}, "vertex axis for bin"}; + ConfigurableAxis axisMultiplicityClass{"axisMultiplicityClass", {10, 0, 100}, "multiplicity percentile for bin"}; + ConfigurableAxis axisEPAngle{"axisEPAngle", {1, -TMath::Pi() / 2, TMath::Pi() / 2}, "event plane angle"}; + + using BinningTypeVertexContributor = ColumnBinningPolicy; + ROOT::Math::PxPyPzMVector Lambdac, Proton, Kshort, LambdacRot, KshortRot; + // ROOT::Math::PxPyPzMVector fourVecDauCM; + // ROOT::Math::XYZVector threeVecDauCM, threeVecDauCMXY, eventplaneVec, eventplaneVecNorm, beamvector; + double massPr = TDatabasePDG::Instance()->GetParticle(kProton)->Mass(); // FIXME: Get from the common header + double massK0s = TDatabasePDG::Instance()->GetParticle(kK0Short)->Mass(); // FIXME: Get from the common header + double v2, v2Rot; + void processSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks, AllTrackCandidates const&, ResoV0s const& V0s, aod::BCsWithTimestamps const&) + { + if (!collision.sel8()) { + return; + } + auto bc = collision.template bc_as(); + if (runNumber != bc.runNumber()) { + initCCDB(bc, runNumber, ccdb, isRun2 ? ccdbPathGrp : ccdbPathGrpMag, lut, isRun2); + bz = o2::base::Propagator::Instance()->getNominalBz(); + // df.setBz(bz); /// put it outside the 'if'! Otherwise we have a difference wrt bz Configurable (< 1 permille) in Run2 conv. data + } + df.setBz(bz); + auto centrality = collision.centFT0C(); + auto multTPC = collision.multNTracksPV(); + histos.fill(HIST("hFTOCvsTPCNoCut"), centrality, multTPC); + if (!collision.triggereventep()) { + return; + } + if (additionalEvSel && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + if (additionalEvSel2 && (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + return; + } + int occupancy = collision.trackOccupancyInTimeRange(); + auto psiFT0C = collision.psiFT0C(); + auto psiFT0A = collision.psiFT0A(); + auto psiTPC = collision.psiTPC(); + auto psiTPCR = collision.psiTPCR(); + auto psiTPCL = collision.psiTPCL(); + + // auto QFT0C = collision.qFT0C(); + // auto QFT0A = collision.qFT0A(); + // auto QTPC = collision.qTPC(); + // auto QTPCR = collision.qTPCR(); + // auto QTPCL = collision.qTPCL(); + + histos.fill(HIST("hFTOCvsTPC"), centrality, multTPC); + histos.fill(HIST("hFTOCvsTPCSelected"), centrality, multTPC); + histos.fill(HIST("hPsiFT0C"), centrality, psiFT0C, occupancy); + histos.fill(HIST("hPsiFT0A"), centrality, psiFT0A, occupancy); + histos.fill(HIST("hPsiTPC"), centrality, psiTPC, occupancy); + histos.fill(HIST("hPsiTPCR"), centrality, psiTPCR, occupancy); + histos.fill(HIST("hPsiTPCL"), centrality, psiTPCL, occupancy); + histos.fill(HIST("ResFT0CTPC"), centrality, TMath::Cos(2.0 * (psiFT0C - psiTPC))); + histos.fill(HIST("ResFT0CTPCR"), centrality, TMath::Cos(2.0 * (psiFT0C - psiTPCR))); + histos.fill(HIST("ResFT0CTPCL"), centrality, TMath::Cos(2.0 * (psiFT0C - psiTPCL))); + histos.fill(HIST("ResTPCRTPCL"), centrality, TMath::Cos(2.0 * (psiTPCR - psiTPCL))); + histos.fill(HIST("ResFT0CFT0A"), centrality, TMath::Cos(2.0 * (psiFT0C - psiFT0A))); + histos.fill(HIST("ResFT0ATPC"), centrality, TMath::Cos(2.0 * (psiTPC - psiFT0A))); + histos.fill(HIST("hCentrality"), centrality); + histos.fill(HIST("hVtxZ"), collision.posZ()); + histos.fill(HIST("hOccupancy"), occupancy); + auto firstprimarytrack = 0; + for (auto track1 : tracks) { + if (!selectionTrack(track1)) { + continue; + } + + if (!track1.hasTOF()) { + if (!rejectPi(track1)) { + continue; + } + if (!rejectEl(track1)) { + continue; + } + if (!rejectKa(track1)) { + continue; + } + } + + // PID check + if (PIDstrategy == 0 && !selectionPID1(track1)) { + continue; + } + if (PIDstrategy == 1 && !selectionPID2(track1)) { + continue; + } + if (PIDstrategy == 2 && !selectionPID3(track1)) { + continue; + } + if (PIDstrategy == 3 && !selectionPID4(track1)) { + continue; + } + histos.fill(HIST("hMomCorr"), track1.p() / track1.sign(), track1.p() - track1.tpcInnerParam(), centrality); + histos.fill(HIST("hEta"), track1.eta()); + histos.fill(HIST("hDcaz"), track1.dcaZ()); + histos.fill(HIST("hNsigmaProtonTPCDiff"), track1.tpcNSigmaPr(), track1.tpcNSigmaKa(), track1.pt()); + histos.fill(HIST("hNsigmaProtonTPC"), track1.tpcNSigmaPr(), track1.pt()); + histos.fill(HIST("hNsigmaProtonTOF"), track1.tofNSigmaPr(), track1.pt()); + auto track1ID = track1.globalIndex(); + auto trackParCovBach = getTrackParCov(track1); + for (auto v0 : V0s) { + if (!SelectionV0(collision, v0)) { + continue; + } + auto postrack = v0.template posTrack_as(); + auto negtrack = v0.template negTrack_as(); + if (!isSelectedV0Daughter(postrack, 1)) { + continue; + } + if (!isSelectedV0Daughter(negtrack, -1)) { + continue; + } + if (track1ID == postrack.globalIndex()) { + continue; + } + if (track1ID == negtrack.globalIndex()) { + continue; + } + auto v0decaylength = TMath::Sqrt(TMath::Power(collision.posX() - v0.x(), 2.0) + TMath::Power(collision.posY() - v0.y(), 2.0) + TMath::Power(collision.posZ() - v0.z(), 2.0)); + if (firstprimarytrack == 0) { + histos.fill(HIST("hV0decaylength"), v0decaylength); + } + float v0x, v0y, v0z, v0px, v0py, v0pz; + // float v0PosPx, v0PosPy, v0PosPz, v0NegPx, v0NegPy, v0NegPz; + // float dcaV0dau, dcaPosToPV, dcaNegToPV, v0cosPA; + float posTrackX, negTrackX; + o2::track::TrackParCov trackParCovV0DaughPos; + o2::track::TrackParCov trackParCovV0DaughNeg; + + // const auto& trackV0DaughPos = v0.posTrack_as(); + // const auto& trackV0DaughNeg = v0.negTrack_as(); + + trackParCovV0DaughPos = getTrackParCov(postrack); // check that aod::TracksWCov does not need TracksDCA! + trackParCovV0DaughNeg = getTrackParCov(negtrack); // check that aod::TracksWCov does not need TracksDCA! + + posTrackX = v0.posX(); + negTrackX = v0.negX(); + v0x = v0.x(); + v0y = v0.y(); + v0z = v0.z(); + const std::array vertexV0 = {v0x, v0y, v0z}; + + v0px = v0.px(); + v0py = v0.py(); + v0pz = v0.pz(); + const std::array momentumV0 = {v0px, v0py, v0pz}; + + std::array covV0Pos = {0.}; + for (int i = 0; i < 6; i++) { + covV0Pos[i] = v0.positionCovMat()[i]; + } + // dcaV0dau = v0.dcaV0daughters(); + // dcaPosToPV = v0.dcapostopv(); + // dcaNegToPV = v0.dcanegtopv(); + // v0cosPA = v0.v0cosPA(); + + trackParCovV0DaughPos.propagateTo(posTrackX, bz); // propagate the track to the X closest to the V0 vertex + trackParCovV0DaughNeg.propagateTo(negTrackX, bz); // propagate the track to the X closest to the V0 vertex + + // we build the neutral track to then build the cascade + // auto trackV0 = o2::dataformats::V0(vertexV0, momentumV0, {0, 0, 0, 0, 0, 0}, trackParCovV0DaughPos, trackParCovV0DaughNeg); // build the V0 track (indices for v0 daughters set to 0 for now) + auto trackV0 = o2::dataformats::V0(vertexV0, momentumV0, covV0Pos, trackParCovV0DaughPos, trackParCovV0DaughNeg); // build the V0 track (indices for v0 daughters set to 0 for now) + std::array pVecV0 = {0., 0., 0.}; + std::array pVecBach = {0., 0., 0.}; + std::array pVecCand = {0., 0., 0.}; + + try { + if (df.process(trackV0, trackParCovBach) == 0) { + continue; + } else { + // LOG(info) << "Vertexing succeeded for Lc candidate"; + } + } catch (const std::runtime_error& error) { + // LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; + continue; + } + if (firstprimarytrack == 0) { + histos.fill(HIST("hInvMassKs0"), v0.mK0Short()); + } + + df.propagateTracksToVertex(); // propagate the bachelor and V0 to the Lambdac vertex + trackV0.getPxPyPzGlo(pVecV0); // momentum of D0 at the Lambdac vertex + trackParCovBach.getPxPyPzGlo(pVecBach); // momentum of proton at the Lambdac vertex + pVecCand = RecoDecay::pVec(pVecV0, pVecBach); + + const auto& secondaryVertex = df.getPCACandidate(); + auto chi2PCA = df.getChi2AtPCACandidate(); + if (chi2PCA > cutchi2PCA) { + continue; + } + // auto covMatrixPCA = df.calcPCACovMatrixFlat(); + if (firstprimarytrack == 0) { + histos.fill(HIST("hchi2PCA"), chi2PCA); + } + // get track impact parameters + // This modifies track momenta! + auto primaryVertex = getPrimaryVertex(collision); + // auto covMatrixPV = primaryVertex.getCov(); + o2::dataformats::DCA impactParameter0; + o2::dataformats::DCA impactParameter1; + trackV0.propagateToDCA(primaryVertex, bz, &impactParameter0); + trackParCovBach.propagateToDCA(primaryVertex, bz, &impactParameter1); + + // get uncertainty of the decay length + double phi, theta; + getPointDirection(std::array{collision.posX(), collision.posY(), collision.posZ()}, secondaryVertex, phi, theta); + // auto errorDecayLength = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); + // auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); + + Kshort = ROOT::Math::PxPyPzMVector(pVecV0[0], pVecV0[1], pVecV0[2], massK0s); + Proton = ROOT::Math::PxPyPzMVector(pVecBach[0], pVecBach[1], pVecBach[2], massPr); + Lambdac = Proton + Kshort; + + double protonimpactparameter = impactParameter1.getY(); + // double kshortimpactparameter=impactParameter0.getY(); + + double decaylengthx = secondaryVertex[0] - collision.posX(); + double decaylengthy = secondaryVertex[1] - collision.posY(); + double decaylengthz = secondaryVertex[2] - collision.posZ(); + double decaylength = TMath::Sqrt(decaylengthx * decaylengthx + decaylengthy * decaylengthy + decaylengthz * decaylengthz); + double decaylengthxy = TMath::Sqrt(decaylengthx * decaylengthx + decaylengthy * decaylengthy); + // double lambdaclifetime = (decaylength * Lambdac.M()) / Lambdac.P(); + // if (lambdaclifetime > cutmaxctaulambdac) { + // continue; + // } + double anglesign = decaylengthx * Lambdac.Px() + decaylengthy * Lambdac.Py() + decaylengthz * Lambdac.Pz(); + double CPAlambdac = anglesign / (decaylength * Lambdac.P()); + anglesign = anglesign / TMath::Abs(anglesign); + auto signprotonimpactparameter = protonimpactparameter * anglesign; + if (firstprimarytrack == 0) { + histos.fill(HIST("hDcaxy"), track1.dcaXY()); + histos.fill(HIST("hunsignprotonDca"), protonimpactparameter); + histos.fill(HIST("hsignCPALambdac"), TMath::Abs(CPAlambdac)); + histos.fill(HIST("hsignprotonDca"), signprotonimpactparameter); + } + firstprimarytrack = firstprimarytrack + 1; + auto phiminuspsi = GetPhiInRange(Lambdac.Phi() - psiFT0C); + v2 = TMath::Cos(2.0 * phiminuspsi); + // if (TMath::Abs(CPAlambdac) > cutCPAlambdac && Lambdac.M() > 2.18 && Lambdac.M() <= 2.42) { + if (Lambdac.M() > 2.18 && Lambdac.M() <= 2.42 && TMath::Abs(Lambdac.Rapidity()) < confRapidity && Lambdac.Pt() > 2 && Lambdac.Pt() <= 6.0) { + if (!useDecayLengthxy) { + histos.fill(HIST("hSparseV2SASameEvent_V2_EP"), Lambdac.M(), Lambdac.Pt(), v2, Proton.Pt(), decaylength, TMath::Abs(track1.dcaXY())); + } + if (useDecayLengthxy) { + histos.fill(HIST("hSparseV2SASameEvent_V2_EP"), Lambdac.M(), Lambdac.Pt(), v2, Proton.Pt(), decaylengthxy, TMath::Abs(track1.dcaXY())); + } + } + for (int nrotbkg = 0; nrotbkg < nBkgRotations; nrotbkg++) { + auto anglestart = confMinRot; + auto angleend = confMaxRot; + auto anglestep = (angleend - anglestart) / (1.0 * (nBkgRotations - 1)); + auto rotangle = anglestart + nrotbkg * anglestep; + histos.fill(HIST("hRotation"), rotangle); + auto rotKshortPx = Kshort.Px() * std::cos(rotangle) - Kshort.Py() * std::sin(rotangle); + auto rotKshortPy = Kshort.Px() * std::sin(rotangle) + Kshort.Py() * std::cos(rotangle); + KshortRot = ROOT::Math::PxPyPzMVector(rotKshortPx, rotKshortPy, Kshort.pz(), massK0s); + LambdacRot = Proton + KshortRot; + auto phiminuspsiRot = GetPhiInRange(LambdacRot.Phi() - psiFT0C); + v2Rot = TMath::Cos(2.0 * phiminuspsiRot); + // double CPAlambdacRot = (decaylengthx * LambdacRot.Px() + decaylengthy * LambdacRot.Py() + decaylengthz * LambdacRot.Pz()) / (decaylength * LambdacRot.P()); + // if (TMath::Abs(CPAlambdacRot) > cutCPAlambdac && LambdacRot.M() > 2.18 && LambdacRot.M() <= 2.42) { + if (LambdacRot.M() > 2.18 && LambdacRot.M() <= 2.42 && TMath::Abs(LambdacRot.Rapidity()) < confRapidity && LambdacRot.Pt() > 2 && LambdacRot.Pt() <= 6.0) { + if (!useDecayLengthxy) { + histos.fill(HIST("hSparseV2SASameEventRotational_V2_EP"), LambdacRot.M(), LambdacRot.Pt(), v2Rot, Proton.Pt(), decaylength, TMath::Abs(track1.dcaXY())); + } + if (useDecayLengthxy) { + histos.fill(HIST("hSparseV2SASameEventRotational_V2_EP"), LambdacRot.M(), LambdacRot.Pt(), v2Rot, Proton.Pt(), decaylengthxy, TMath::Abs(track1.dcaXY())); + } + } + } + + // ROOT::Math::Boost boost{Lambdac.BoostToCM()}; + // fourVecDauCM = boost(Kshort); + // threeVecDauCM = fourVecDauCM.Vect(); + // threeVecDauCMXY = ROOT::Math::XYZVector(threeVecDauCM.X(), threeVecDauCM.Y(), 0.); + // beamvector = ROOT::Math::XYZVector(0, 0, 1); + // auto cosThetaStar = beamvector.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(beamvector.Mag2()); + // auto SA = cosThetaStar * TMath::Sin(2.0 * phiminuspsi); + // if (fillPolarization) { + // if (track1.sign() > 0) { + // histos.fill(HIST("hSparseV2SASameEventplus_SA"), Lambdac.M(), Lambdac.Pt(), cosThetaStar, phiminuspsi, centrality); + // histos.fill(HIST("hSparseV2SASameEventplus_SA_A0"), Lambdac.M(), Lambdac.Pt(), cosThetaStar * cosThetaStar, phiminuspsi, centrality); + // histos.fill(HIST("hSparseV2SASameEventplus_SA_azimuth"), Lambdac.M(), Lambdac.Pt(), SA, centrality); + // } + // if (track1.sign() < 0) { + // histos.fill(HIST("hSparseV2SASameEventminus_SA"), Lambdac.M(), Lambdac.Pt(), cosThetaStar, phiminuspsi, centrality); + // histos.fill(HIST("hSparseV2SASameEventminus_SA_A0"), Lambdac.M(), Lambdac.Pt(), cosThetaStar * cosThetaStar, phiminuspsi, centrality); + // histos.fill(HIST("hSparseV2SASameEventminus_SA_azimuth"), Lambdac.M(), Lambdac.Pt(), SA, centrality); + // } + // } + } + } + } + PROCESS_SWITCH(highmasslambdasvx, processSameEvent, "Process Same event", true); + /* void processMixedEventOpti(EventCandidates const& collisions, TrackCandidates const& tracks, AllTrackCandidates const&, ResoV0s const& V0s) + { + auto tracksV0sTuple = std::make_tuple(tracks, V0s); + BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicityClass, axisEPAngle}, true}; + Pair pairs{binningOnPositions, cfgNoMixedEvents, -1, collisions, tracksV0sTuple, &cache}; // -1 is the number of the bin to skip + for (auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (!collision1.sel8() || !collision2.sel8()) { + continue; + } + if (!collision1.triggereventep() || !collision2.triggereventep()) { + continue; + } + if (additionalEvSel && (!collision1.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + if (additionalEvSel && (!collision2.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + if (additionalEvSel2 && (!collision1.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + return; + } + if (additionalEvSel2 && (!collision2.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + return; + } + auto centrality = collision1.centFT0C(); + auto psiFT0C = collision1.psiFT0C(); + auto QFT0C = collision1.qFT0C(); + int occupancy = collision1.trackOccupancyInTimeRange(); + for (auto& [track1, v0] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (!selectionTrack(track1)) { + continue; + } + // PID check + if (ispTdepPID && !selectionPIDNew(track1)) { + continue; + } + if (!ispTdepPID && !selectionPID(track1)) { + continue; + } + if (!SelectionV0(collision2, v0)) { + continue; + } + auto postrack = v0.template posTrack_as(); + auto negtrack = v0.template negTrack_as(); + if (!isSelectedV0Daughter(postrack, 1)) { + continue; + } + if (!isSelectedV0Daughter(negtrack, -1)) { + continue; + } + + Proton = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massPr); + Kshort = ROOT::Math::PxPyPzMVector(v0.px(), v0.py(), v0.pz(), massK0s); + Lambdac = Proton + Kshort; + if (TMath::Abs(Lambdac.Rapidity()) > confRapidity) { + continue; + } + auto phiminuspsi = GetPhiInRange(Lambdac.Phi() - psiFT0C); + if (useSP) { + v2 = TMath::Cos(2.0 * phiminuspsi) * QFT0C; + } + if (!useSP) { + v2 = TMath::Cos(2.0 * phiminuspsi); + } + auto anglesign = (v0.x() - collision1.posX()) * v0.px() + (v0.y() - collision1.posY()) * v0.py() + (v0.z() - collision1.posZ()) * v0.pz(); + anglesign = anglesign / TMath::Abs(anglesign); + auto dcasum = 0.0; + if (useSignDCAV0) { + dcasum = anglesign * (v0.dcav0topv()) - track1.dcaXY(); + } + if (!useSignDCAV0) { + dcasum = TMath::Sqrt((track1.dcaXY() + (v0.dcav0topv())) * (track1.dcaXY() + (v0.dcav0topv()))); + } + // auto diffangle = Proton.Phi() - Lambdac.Phi(); + // auto decaylength = TMath::Abs((track1.dcaXY() / TMath::Sin(diffangle)) / (Lambdac.P() / 2.286)); + // auto dcasum = TMath::Sqrt(track1.dcaXY() * track1.dcaXY() + v0.dcav0topv() * v0.dcav0topv()); + if (fillDefault && Lambdac.M() > 2.18 && Lambdac.M() <= 2.42) { + if (fillDecayLength) { + histos.fill(HIST("hSparseV2SAMixedEvent_V2"), Lambdac.M(), Lambdac.Pt(), v2, dcasum); + } + histos.fill(HIST("hSparseV2SAMixedEvent_V2_new"), Lambdac.M(), Lambdac.Pt(), v2, TMath::Abs(track1.dcaXY()), Proton.Pt()); + } + if (fillOccupancy && Lambdac.M() > 2.18 && Lambdac.M() <= 2.42) { + if (fillDecayLength) { + histos.fill(HIST("hSparseV2SAMixedEvent_V2_occupancy"), Lambdac.M(), Lambdac.Pt(), v2, dcasum, TMath::Abs(track1.dcaXY()), occupancy); + } + histos.fill(HIST("hSparseV2SAMixedEvent_V2_new_occupancy"), Lambdac.M(), Lambdac.Pt(), v2, TMath::Abs(track1.dcaXY()), Proton.Pt(), occupancy); + } + ROOT::Math::Boost boost{Lambdac.BoostToCM()}; + fourVecDauCM = boost(Kshort); + threeVecDauCM = fourVecDauCM.Vect(); + threeVecDauCMXY = ROOT::Math::XYZVector(threeVecDauCM.X(), threeVecDauCM.Y(), 0.); + beamvector = ROOT::Math::XYZVector(0, 0, 1); + auto cosThetaStar = beamvector.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(beamvector.Mag2()); + auto SA = cosThetaStar * TMath::Sin(2.0 * phiminuspsi); + if (fillPolarization) { + if (track1.sign() > 0) { + histos.fill(HIST("hSparseV2SAMixedEventplus_SA"), Lambdac.M(), Lambdac.Pt(), cosThetaStar, phiminuspsi, centrality); + histos.fill(HIST("hSparseV2SAMixedEventplus_SA_A0"), Lambdac.M(), Lambdac.Pt(), cosThetaStar * cosThetaStar, phiminuspsi, centrality); + histos.fill(HIST("hSparseV2SAMixedEventplus_SA_azimuth"), Lambdac.M(), Lambdac.Pt(), SA, centrality); + } + if (track1.sign() < 0) { + histos.fill(HIST("hSparseV2SAMixedEventminus_SA"), Lambdac.M(), Lambdac.Pt(), cosThetaStar, phiminuspsi, centrality); + histos.fill(HIST("hSparseV2SAMixedEventminus_SA_A0"), Lambdac.M(), Lambdac.Pt(), cosThetaStar * cosThetaStar, phiminuspsi, centrality); + histos.fill(HIST("hSparseV2SAMixedEventminus_SA_azimuth"), Lambdac.M(), Lambdac.Pt(), SA, centrality); + } + } + } + } + } + PROCESS_SWITCH(highmasslambdasvx, processMixedEventOpti, "Process Mixed event new", true);*/ +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"highmasslambdasvx"})}; +} diff --git a/PWGLF/Tasks/Resonances/k1analysis.cxx b/PWGLF/Tasks/Resonances/k1analysis.cxx index e3599531046..601227b666e 100644 --- a/PWGLF/Tasks/Resonances/k1analysis.cxx +++ b/PWGLF/Tasks/Resonances/k1analysis.cxx @@ -15,6 +15,7 @@ /// /// \author Bong-Hwi Lim +#include #include #include // FIXME #include // FIXME @@ -27,55 +28,90 @@ #include "Framework/runDataProcessing.h" #include "PWGLF/DataModel/LFResonanceTables.h" #include "DataFormatsParameters/GRPObject.h" +#include "CommonConstants/PhysicsConstants.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; +using namespace o2::constants::physics; struct k1analysis { + enum binAnti : unsigned int { + kNormal = 0, + kAnti, + kNAEnd + }; + enum binType : unsigned int { + kK1P = 0, + kK1N, + kK1P_Mix, + kK1N_Mix, + kK1P_GenINEL10, + kK1N_GenINEL10, + kK1P_GenINELgt10, + kK1N_GenINELgt10, + kK1P_GenTrig10, + kK1N_GenTrig10, + kK1P_GenEvtSel, + kK1N_GenEvtSel, + kK1P_Rec, + kK1N_Rec, + kTYEnd + }; SliceCache cache; Preslice perRCol = aod::resodaughter::resoCollisionId; Preslice perCollision = aod::track::collisionId; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + using ResoMCCols = soa::Join; ///// Configurables + Configurable cNbinsDiv{"cNbinsDiv", 1, "Integer to divide the number of bins"}; /// Event Mixing Configurable nEvtMixing{"nEvtMixing", 5, "Number of events to mix"}; ConfigurableAxis CfgVtxBins{"CfgVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; ConfigurableAxis CfgMultBins{"CfgMultBins", {VARIABLE_WIDTH, 0.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; /// Pre-selection cuts Configurable cMinPtcut{"cMinPtcut", 0.15, "Track minium pt cut"}; + /// DCA Selections // DCAr to PV Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 0.1, "Track DCAr cut to PV Maximum"}; // DCAz to PV Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 0.1, "Track DCAz cut to PV Maximum"}; Configurable cMinDCAzToPVcut{"cMinDCAzToPVcut", 0.0, "Track DCAz cut to PV Minimum"}; + /// PID Selections Configurable cMaxTPCnSigmaPion{"cMaxTPCnSigmaPion", 3.0, "TPC nSigma cut for Pion"}; // TPC Configurable cMaxTOFnSigmaPion{"cMaxTOFnSigmaPion", 3.0, "TOF nSigma cut for Pion"}; // TOF Configurable nsigmaCutCombinedPion{"nsigmaCutCombinedPion", -999, "Combined nSigma cut for Pion"}; // Combined + Configurable cTOFVeto{"cTOFVeto", true, "TOF Veto, if false, TOF is nessessary for PID selection"}; // TOF Veto Configurable cUseOnlyTOFTrackPi{"cUseOnlyTOFTrackPi", false, "Use only TOF track for PID selection"}; // Use only TOF track for Pion PID selection - Configurable cUseOnlyTOFTrackKa{"cUseOnlyTOFTrackKa", false, "Use only TOF track for PID selection"}; // Use only TOF track for Kaon PID selection // Kaon - Configurable cMaxTPCnSigmaKaon{"cMaxTPCnSigmaKaon", 3.0, "TPC nSigma cut for Kaon"}; // TPC - Configurable cMaxTOFnSigmaKaon{"cMaxTOFnSigmaKaon", 3.0, "TOF nSigma cut for Kaon"}; // TOF - Configurable nsigmaCutCombinedKaon{"nsigmaCutCombinedKaon", -999, "Combined nSigma cut for Kaon"}; // Combined + Configurable cMaxTPCnSigmaKaon{"cMaxTPCnSigmaKaon", 3.0, "TPC nSigma cut for Kaon"}; // TPC + Configurable cMaxTOFnSigmaKaon{"cMaxTOFnSigmaKaon", 3.0, "TOF nSigma cut for Kaon"}; // TOF + Configurable nsigmaCutCombinedKaon{"nsigmaCutCombinedKaon", -999, "Combined nSigma cut for Kaon"}; // Combined + Configurable cUseOnlyTOFTrackKa{"cUseOnlyTOFTrackKa", false, "Use only TOF track for PID selection"}; // Use only TOF track for Kaon PID selection // Track selections Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) - Configurable cfgPVContributor{"cfgPVContributor", true, "PV contributor track selection"}; // PV Contriuibutor - - // bachelor pion TOF PID? - Configurable cDoTOFPID{"cDoTOFPID", 1, "Do TOF PID"}; - - // K(892)0 selection - Configurable cK892masswindow{"cK892masswindow", 0.1, "K(892)0 inv mass selection window"}; - Configurable cPiPiMin{"cPiPiMin", 0, "Pion pair inv mass selection minimum"}; - Configurable cPiPiMax{"cPiPiMax", 999, "Pion pair inv mass selection maximum"}; - Configurable cPiKaMin{"cPiKaMin", 0, "bPion-Kaon pair inv mass selection minimum"}; - Configurable cPiKaMax{"cPiKaMax", 999, "bPion-Kaon pair inv mass selection maximum"}; + Configurable cfgGlobalTrack{"cfgGlobalTrack", false, "Global track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgPVContributor{"cfgPVContributor", false, "PV contributor track selection"}; // PV Contriuibutor + Configurable additionalQAplots{"additionalQAplots", true, "Additional QA plots"}; + Configurable tof_at_high_pt{"tof_at_high_pt", false, "Use TOF at high pT"}; + Configurable additionalEvsel{"additionalEvsel", true, "Additional event selcection"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 0, "Number of TPC cluster"}; + Configurable cfgUseTPCRefit{"cfgUseTPCRefit", false, "Require TPC Refit"}; + Configurable cfgUseITSRefit{"cfgUseITSRefit", false, "Require ITS Refit"}; + Configurable cfgHasTOF{"cfgHasTOF", false, "Require TOF"}; + + // Secondary selection + Configurable cfgModeK892orRho{"cfgModeK892orRho", true, "Secondary scenario for K892 (true) or Rho (false)"}; + Configurable cSecondaryMasswindow{"cSecondaryMasswindow", 0.1, "Secondary inv mass selection window"}; + Configurable cMinAnotherSecondaryMassCut{"cMinAnotherSecondaryMassCut", 0, "Min inv. mass selection of another secondary scenario"}; + Configurable cMaxAnotherSecondaryMassCut{"cMaxAnotherSecondaryMassCut", 999, "MAx inv. mass selection of another secondary scenario"}; + Configurable cMinPiKaMassCut{"cMinPiKaMassCut", 0, "bPion-Kaon pair inv mass selection minimum"}; + Configurable cMaxPiKaMassCut{"cMaxPiKaMassCut", 999, "bPion-Kaon pair inv mass selection maximum"}; Configurable cMinAngle{"cMinAngle", 0, "Minimum angle between K(892)0 and bachelor pion"}; Configurable cMaxAngle{"cMaxAngle", 4, "Maximum angle between K(892)0 and bachelor pion"}; Configurable cMinPairAsym{"cMinPairAsym", -1, "Minimum pair asymmetry"}; @@ -92,108 +128,162 @@ struct k1analysis { AxisSpec ptAxis = {150, 0, 15, "#it{p}_{T} (GeV/#it{c})"}; AxisSpec dcaxyAxis = {300, 0, 3, "DCA_{#it{xy}} (cm)"}; AxisSpec dcazAxis = {500, 0, 5, "DCA_{#it{xy}} (cm)"}; - AxisSpec invMassAxis = {900, 0.6, 1.5, "Invariant Mass (GeV/#it{c}^2)"}; // K(892)0 - AxisSpec invMassAxisReso = {1600, 0.9f, 2.5f, "Invariant Mass (GeV/#it{c}^2)"}; // K1 - AxisSpec invMassAxisScan = {250, 0, 2.5, "Invariant Mass (GeV/#it{c}^2)"}; // For selection + AxisSpec invMassAxisK892 = {1400 / cNbinsDiv, 0.6, 2.0, "Invariant Mass (GeV/#it{c}^2)"}; // K(892)0 + AxisSpec invMassAxisRho = {2000 / cNbinsDiv, 0.0, 2.0, "Invariant Mass (GeV/#it{c}^2)"}; // rho + AxisSpec invMassAxisReso = {1600 / cNbinsDiv, 0.9f, 2.5f, "Invariant Mass (GeV/#it{c}^2)"}; // K1 + AxisSpec invMassAxisScan = {250, 0, 2.5, "Invariant Mass (GeV/#it{c}^2)"}; // For selection AxisSpec pidQAAxis = {130, -6.5, 6.5}; AxisSpec dataTypeAxis = {9, 0, 9, "Histogram types"}; AxisSpec mcTypeAxis = {4, 0, 4, "Histogram types"}; - // Mass QA (quick check) - histos.add("k892invmass", "Invariant mass of K(892)0", HistType::kTH1F, {invMassAxis}); - histos.add("k1invmass", "Invariant mass of K1(1270)pm", HistType::kTH1F, {invMassAxisReso}); - histos.add("k1invmass_LS", "Invariant mass of K1(1270)pm", HistType::kTH1F, {invMassAxisReso}); - histos.add("k1invmass_Mix", "Invariant mass of K1(1270)pm", HistType::kTH1F, {invMassAxisReso}); - if (doprocessMC) { - histos.add("k1invmass_MC", "Invariant mass of K1(1270)pm", HistType::kTH1F, {invMassAxisReso}); - } + // THnSparse + AxisSpec axisAnti = {binAnti::kNAEnd, 0, binAnti::kNAEnd, "Type of bin: Normal or Anti"}; + AxisSpec axisType = {binType::kTYEnd, 0, binType::kTYEnd, "Type of bin with charge and mix"}; + AxisSpec mcLabelAxis = {5, -0.5, 4.5, "MC Label"}; + // DCA QA - histos.add("QA/trkDCAxy_pi", "DCAxy distribution of pion track candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QA/trkDCAxy_ka", "DCAxy distribution of kaon track candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QA/trkDCAxy_pi_bach", "DCAxy distribution of bachelor pion track candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QA/trkDCAz_pi", "DCAz distribution of pion track candidates", HistType::kTH1F, {dcazAxis}); - histos.add("QA/trkDCAz_ka", "DCAz distribution of kaon track candidates", HistType::kTH1F, {dcazAxis}); - histos.add("QA/trkDCAz_pi_bach", "DCAz distribution of bachelor pion track candidates", HistType::kTH1F, {dcazAxis}); - - // pT QA - histos.add("QA/trkpT_pi", "pT distribution of pion track candidates", HistType::kTH1F, {ptAxis}); - histos.add("QA/trkpT_ka", "pT distribution of kaon track candidates", HistType::kTH1F, {ptAxis}); - histos.add("QA/trkpT_pi_bach", "pT distribution of bachelor pion track candidates", HistType::kTH1F, {ptAxis}); - // PID QA after cuts - histos.add("QA/TOF_TPC_Map_pi", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); - histos.add("QA/TOF_Nsigma_pi", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Pion};", {HistType::kTH2F, {ptAxis, pidQAAxis}}); - histos.add("QA/TPC_Nsigma_pi", "TPC NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH2F, {ptAxis, pidQAAxis}}); - histos.add("QA/TOF_TPC_Map_ka", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Kaon};#sigma_{TPC}^{Kaon}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); - histos.add("QA/TOF_Nsigma_ka", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH2F, {ptAxis, pidQAAxis}}); - histos.add("QA/TPC_Nsigmaka", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH2F, {ptAxis, pidQAAxis}}); - histos.add("QA/TOF_TPC_Map_pi_bach", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); - histos.add("QA/TOF_Nsigma_pi_bach", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Pion};", {HistType::kTH2F, {ptAxis, pidQAAxis}}); - histos.add("QA/TPC_Nsigma_pi_bach", "TPC NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH2F, {ptAxis, pidQAAxis}}); - histos.add("QA/InvMass_piK_pipi", "Invariant mass of pion + kaon and pion+pion;Invariant Mass (GeV/#it{c}^{2});Invariant Mass (GeV/#it{c}^{2});", {HistType::kTH2F, {invMassAxisScan, invMassAxisScan}}); - histos.add("QA/InvMass_piK_pika", "Invariant mass of pion + kaon and pion+kaon;Invariant Mass (GeV/#it{c}^{2});Invariant Mass (GeV/#it{c}^{2});", {HistType::kTH2F, {invMassAxisScan, invMassAxisScan}}); - histos.add("QA/K1OA", "Opening angle of K1(1270)pm", HistType::kTH1F, {AxisSpec{100, 0, 3.14, "Opening angle of K1(1270)pm"}}); - histos.add("QA/K1PairAsymm", "Pair asymmetry of K1(1270)pm", HistType::kTH1F, {AxisSpec{100, -1, 1, "Pair asymmetry of K1(1270)pm"}}); - - // Invariant mass histograms - histos.add("hK892invmass_PP", "Invariant mass of K(892)0 (Matter + Matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxis}); - histos.add("hK892invmass_NP", "Invariant mass of K(892)0 (Matter + Anti-matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxis}); - histos.add("hK892invmass_PN", "Invariant mass of K(892)0 (Anti-matter + Matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxis}); - histos.add("hK892invmass_NN", "Invariant mass of K(892)0 (Anti-matter + Anti-matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxis}); - histos.add("hK1invmass_NPP", "Invariant mass of K(892)0 + pion (Matter + Matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxisReso}); - histos.add("hK1invmass_NPN", "Invariant mass of K(892)0 + pion (Matter + Anti-matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxisReso}); - histos.add("hK1invmass_PNP", "Invariant mass of K(892)0 + pion (Anti-matter + Matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxisReso}); - histos.add("hK1invmass_PNN", "Invariant mass of K(892)0 + pion (Anti-matter + Anti-matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxisReso}); - // K892-LS bkg - histos.add("hK1invmass_PPP", "Invariant mass of K(892)0 + pion (Matter + Anti-matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxisReso}); - histos.add("hK1invmass_PPN", "Invariant mass of K(892)0 + pion (Anti-matter + Matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxisReso}); - histos.add("hK1invmass_NNP", "Invariant mass of K(892)0 + pion (Anti-matter + Anti-matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxisReso}); - histos.add("hK1invmass_NNN", "Invariant mass of K(892)0 + pion (Anti-matter + Anti-matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxisReso}); - // Mixed event - histos.add("hK1invmass_NPP_Mix", "Invariant mass of K(892)0 + pion (Matter + Matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxisReso}); - histos.add("hK1invmass_NPN_Mix", "Invariant mass of K(892)0 + pion (Matter + Anti-matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxisReso}); - histos.add("hK1invmass_PNP_Mix", "Invariant mass of K(892)0 + pion (Anti-matter + Matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxisReso}); - histos.add("hK1invmass_PNN_Mix", "Invariant mass of K(892)0 + pion (Anti-matter + Anti-matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxisReso}); + // Primary pion + histos.add("QA/trkppionDCAxy", "DCAxy distribution of primary pion candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QA/trkppionDCAz", "DCAz distribution of primary pion candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QA/trkppionpT", "pT distribution of primary pion candidates", HistType::kTH1F, {ptAxis}); + histos.add("QA/trkppionTPCPID", "TPC PID of primary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QA/trkppionTOFPID", "TOF PID of primary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QA/trkppionTPCTOFPID", "TPC-TOF PID map of primary pion candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); + + histos.add("QAcut/trkppionDCAxy", "DCAxy distribution of primary pion candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QAcut/trkppionDCAz", "DCAz distribution of primary pion candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QAcut/trkppionpT", "pT distribution of primary pion candidates", HistType::kTH1F, {ptAxis}); + histos.add("QAcut/trkppionTPCPID", "TPC PID of primary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QAcut/trkppionTOFPID", "TOF PID of primary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QAcut/trkppionTPCTOFPID", "TPC-TOF PID map of primary pion candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); + + // Secondary pion + histos.add("QA/trkspionDCAxy", "DCAxy distribution of secondary pion candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QA/trkspionDCAz", "DCAz distribution of secondary pion candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QA/trkspionpT", "pT distribution of secondary pion candidates", HistType::kTH1F, {ptAxis}); + histos.add("QA/trkspionTPCPID", "TPC PID of secondary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QA/trkspionTOFPID", "TOF PID of secondary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QA/trkspionTPCTOFPID", "TPC-TOF PID map of secondary pion candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); + + histos.add("QAcut/trkspionDCAxy", "DCAxy distribution of secondary pion candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QAcut/trkspionDCAz", "DCAz distribution of secondary pion candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QAcut/trkspionpT", "pT distribution of secondary pion candidates", HistType::kTH1F, {ptAxis}); + histos.add("QAcut/trkspionTPCPID", "TPC PID of secondary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QAcut/trkspionTOFPID", "TOF PID of secondary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QAcut/trkspionTPCTOFPID", "TPC-TOF PID map of secondary pion candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); + + // Kaon + histos.add("QA/trkkaonDCAxy", "DCAxy distribution of kaon candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QA/trkkaonDCAz", "DCAz distribution of kaon candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QA/trkkaonpT", "pT distribution of kaon candidates", HistType::kTH1F, {ptAxis}); + histos.add("QA/trkkaonTPCPID", "TPC PID of kaon candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QA/trkkaonTOFPID", "TOF PID of kaon candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QA/trkkaonTPCTOFPID", "TPC-TOF PID map of kaon candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); + + histos.add("QAcut/trkkaonDCAxy", "DCAxy distribution of kaon candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QAcut/trkkaonDCAz", "DCAz distribution of kaon candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QAcut/trkkaonpT", "pT distribution of kaon candidates", HistType::kTH1F, {ptAxis}); + histos.add("QAcut/trkkaonTPCPID", "TPC PID of kaon candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QAcut/trkkaonTOFPID", "TOF PID of kaon candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QAcut/trkkaonTPCTOFPID", "TPC-TOF PID map of kaon candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); + + // K1 + histos.add("QA/K1OA", "Opening angle of K1(1270)", HistType::kTH1F, {AxisSpec{100, 0, 3.14, "Opening angle"}}); + histos.add("QA/K1PairAssym", "Pair asymmetry of K1(1270)", HistType::kTH1F, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); + histos.add("QA/hInvmassK892_Rho", "Invariant mass of K(892)0 vs Rho(770)", HistType::kTH2F, {invMassAxisK892, invMassAxisRho}); + histos.add("QA/hInvmassSecon_PiKa", "Invariant mass of secondary resonance vs pion-kaon", HistType::kTH2F, {invMassAxisK892, invMassAxisK892}); + histos.add("QA/hInvmassSecon", "Invariant mass of secondary resonance", HistType::kTH1F, {invMassAxisRho}); + histos.add("QA/hpT_Secondary", "pT distribution of secondary resonance", HistType::kTH1F, {ptAxis}); + + histos.add("QAcut/K1OA", "Opening angle of K1(1270)", HistType::kTH1F, {AxisSpec{100, 0, 3.14, "Opening angle"}}); + histos.add("QAcut/K1PairAssym", "Pair asymmetry of K1(1270)", HistType::kTH1F, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); + histos.add("QAcut/hInvmassK892_Rho", "Invariant mass of K(892)0 vs Rho(770)", HistType::kTH2F, {invMassAxisK892, invMassAxisRho}); + histos.add("QAcut/hInvmassSecon_PiKa", "Invariant mass of secondary resonance vs pion-kaon", HistType::kTH2F, {invMassAxisK892, invMassAxisK892}); + histos.add("QAcut/hInvmassSecon", "Invariant mass of secondary resonance", HistType::kTH1F, {invMassAxisRho}); + histos.add("QAcut/hpT_Secondary", "pT distribution of secondary resonance", HistType::kTH1F, {ptAxis}); + + // Invariant mass + histos.add("hInvmass_K1", "Invariant mass of K1(1270)", HistType::kTHnSparseD, {axisAnti, axisType, centAxis, ptAxis, invMassAxisReso}); + // Mass QA (quick check) + histos.add("k1invmass", "Invariant mass of K1(1270)", HistType::kTH1F, {invMassAxisReso}); + histos.add("k1invmass_Mix", "Invariant mass of K1(1270)", HistType::kTH1F, {invMassAxisReso}); + // MC if (doprocessMC) { - histos.add("QAMC/InvMass_piK_pipi", "Invariant mass of pion + kaon and pion+pion;Invariant Mass (GeV/#it{c}^{2});Invariant Mass (GeV/#it{c}^{2});", {HistType::kTH2F, {invMassAxisScan, invMassAxisScan}}); - histos.add("QAMC/InvMass_piK_pika", "Invariant mass of pion + kaon and pion+kaon;Invariant Mass (GeV/#it{c}^{2});Invariant Mass (GeV/#it{c}^{2});", {HistType::kTH2F, {invMassAxisScan, invMassAxisScan}}); - histos.add("QAMC/K1OA", "Opening angle of K1(1270)pm", HistType::kTH1F, {AxisSpec{100, 0, 3.14, "Opening angle of K1(1270)pm"}}); - histos.add("QAMC/K1PairAsymm", "Pair asymmetry of K1(1270)pm", HistType::kTH1F, {AxisSpec{100, 0, 1, "Pair asymmetry of K1(1270)pm"}}); - - histos.add("hK1invmass_NPP_MC", "Invariant mass of K(892)0 + pion (Matter + Matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxisReso}); - histos.add("hK1invmass_PNN_MC", "Invariant mass of K(892)0 + pion (Anti-matter + Anti-matter)", HistType::kTH3F, {centAxis, ptAxis, invMassAxisReso}); - - histos.add("hReconK892pt", "pT distribution of Reconstructed MC K(892)0", HistType::kTH1F, {ptAxis}); - histos.add("hTrueK1pt", "pT distribution of True MC K1", HistType::kTH1F, {ptAxis}); - histos.add("hReconK1pt", "pT distribution of Reconstructed MC K1", HistType::kTH1F, {ptAxis}); - - histos.add("k1invmass_noK1", "Invariant mass of K1(1270)pm", HistType::kTH1F, {invMassAxisReso}); + histos.add("k1invmass_MC", "Invariant mass of K1(1270)", HistType::kTH1F, {invMassAxisReso}); + histos.add("k1invmass_MC_noK1", "Invariant mass of K1(1270)", HistType::kTH1F, {invMassAxisReso}); + + histos.add("QAMC/trkppionDCAxy", "DCAxy distribution of primary pion candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QAMC/trkppionDCAz", "DCAz distribution of primary pion candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QAMC/trkppionpT", "pT distribution of primary pion candidates", HistType::kTH1F, {ptAxis}); + histos.add("QAMC/trkppionTPCPID", "TPC PID of primary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkppionTOFPID", "TOF PID of primary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkppionTPCTOFPID", "TPC-TOF PID map of primary pion candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); + + histos.add("QAMC/trkspionDCAxy", "DCAxy distribution of secondary pion candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QAMC/trkspionDCAz", "DCAz distribution of secondary pion candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QAMC/trkspionpT", "pT distribution of secondary pion candidates", HistType::kTH1F, {ptAxis}); + histos.add("QAMC/trkspionTPCPID", "TPC PID of secondary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkspionTOFPID", "TOF PID of secondary pion candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkspionTPCTOFPID", "TPC-TOF PID map of secondary pion candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); + + histos.add("QAMC/trkkaonDCAxy", "DCAxy distribution of kaon candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QAMC/trkkaonDCAz", "DCAz distribution of kaon candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QAMC/trkkaonpT", "pT distribution of kaon candidates", HistType::kTH1F, {ptAxis}); + histos.add("QAMC/trkkaonTPCPID", "TPC PID of kaon candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkkaonTOFPID", "TOF PID of kaon candidates", HistType::kTH2F, {ptAxis, pidQAAxis}); + histos.add("QAMC/trkkaonTPCTOFPID", "TPC-TOF PID map of kaon candidates", HistType::kTH2F, {pidQAAxis, pidQAAxis}); + + histos.add("QAMC/K1OA", "Opening angle of K1(1270)", HistType::kTH1F, {AxisSpec{100, 0, 3.14, "Opening angle"}}); + histos.add("QAMC/K1PairAssym", "Pair asymmetry of K1(1270)", HistType::kTH1F, {AxisSpec{100, -1, 1, "Pair asymmetry"}}); + histos.add("QAMC/hInvmassK892_Rho", "Invariant mass of K(892)0 vs Rho(770)", HistType::kTH2F, {invMassAxisK892, invMassAxisRho}); + histos.add("QAMC/hInvmassSecon_PiKa", "Invariant mass of secondary resonance vs pion-kaon", HistType::kTH2F, {invMassAxisK892, invMassAxisK892}); + histos.add("QAMC/hInvmassSecon", "Invariant mass of secondary resonance", HistType::kTH1F, {invMassAxisRho}); + histos.add("QAMC/hpT_Secondary", "pT distribution of secondary resonance", HistType::kTH1F, {ptAxis}); } // Print output histograms statistics - LOG(info) << "Size of the histograms in spectraTOF"; + LOG(info) << "Size of the histograms in K1 Analysis Task"; histos.print(); } - double massKa = TDatabasePDG::Instance()->GetParticle(kKPlus)->Mass(); // FIXME: Get from the common header - double massPi = TDatabasePDG::Instance()->GetParticle(kPiPlus)->Mass(); // FIXME: Get from the common header - double massK892 = TDatabasePDG::Instance()->GetParticle(313)->Mass(); // FIXME: Get from the common header + double massKa = MassKaonCharged; + double massPi = MassPionCharged; + // double massRho770 = MassRho770; + // double massK892 = MassKStar892; + double massRho770 = 0.77526; + double massK892 = 0.892; + + // PDG code + int kPDGRho770 = 113; + int kK1Plus = 10323; template bool trackCut(const TrackType track) { // basic track cuts - if (track.pt() < cMinPtcut) + if (std::abs(track.pt()) < cMinPtcut) + return false; + if (std::abs(track.dcaXY()) > cMaxDCArToPVcut) + return false; + if (std::abs(track.dcaZ()) > cMaxDCAzToPVcut) + return false; + if (track.tpcNClsFound() < cfgTPCcluster) + return false; + if (cfgHasTOF && !track.hasTOF()) return false; - if (track.dcaXY() > cMaxDCArToPVcut) + if (cfgUseITSRefit && !track.passedITSRefit()) return false; - if (track.dcaZ() < cMinDCAzToPVcut || track.dcaZ() > cMaxDCAzToPVcut) + if (cfgUseTPCRefit && !track.passedTPCRefit()) + return false; + if (cfgPVContributor && !track.isPVContributor()) return false; if (cfgPrimaryTrack && !track.isPrimaryTrack()) return false; if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) return false; - if (cfgPVContributor && !track.isPVContributor()) + if (cfgGlobalTrack && !track.isGlobalTrack()) return false; + return true; } @@ -204,6 +294,8 @@ struct k1analysis { bool tpcPIDPassed{false}, tofPIDPassed{false}; if (std::abs(candidate.tpcNSigmaPi()) < cMaxTPCnSigmaPion) { tpcPIDPassed = true; + } else { + return false; } if (candidate.hasTOF()) { if (std::abs(candidate.tofNSigmaPi()) < cMaxTOFnSigmaPion) { @@ -213,6 +305,9 @@ struct k1analysis { tofPIDPassed = true; } } else { + if (!cTOFVeto) { + return false; + } tofPIDPassed = true; } if (tpcPIDPassed && tofPIDPassed) { @@ -226,6 +321,8 @@ struct k1analysis { bool tpcPIDPassed{false}, tofPIDPassed{false}; if (std::abs(candidate.tpcNSigmaKa()) < cMaxTPCnSigmaKaon) { tpcPIDPassed = true; + } else { + return false; } if (candidate.hasTOF()) { if (std::abs(candidate.tofNSigmaKa()) < cMaxTOFnSigmaKaon) { @@ -235,6 +332,9 @@ struct k1analysis { tofPIDPassed = true; } } else { + if (!cTOFVeto) { + return false; + } tofPIDPassed = true; } if (tpcPIDPassed && tofPIDPassed) { @@ -245,6 +345,42 @@ struct k1analysis { template bool isTrueK1(const T& trk1, const T& trk2, const T2& bTrack) + { + if (abs(trk1.pdgCode()) != kPiPlus || abs(trk2.pdgCode()) != kKPlus) + return false; + if (abs(bTrack.pdgCode()) != kPiPlus) + return false; + if (cfgModeK892orRho) { // K892 mode + auto mother1 = trk1.motherId(); + auto mother2 = trk2.motherId(); + if (mother1 != mother2) + return false; + if (abs(trk1.motherPDG()) != kK0Star892) + return false; + if (abs(bTrack.motherPDG()) != kK1Plus) + return false; + auto siblings = bTrack.siblingIds(); + if (siblings[0] != mother1 && siblings[1] != mother1) + return false; + return true; + } else { // Rho mode + auto mother1 = trk1.motherId(); + auto motherb = bTrack.motherId(); + if (mother1 != motherb) + return false; + if (abs(trk1.motherPDG()) != kPDGRho770) + return false; + if (abs(trk2.motherPDG()) != kK1Plus) + return false; + auto siblings = trk2.siblingIds(); + if (siblings[0] != mother1 && siblings[1] != mother1) + return false; + return true; + } + } + + template + bool isTrueK892(const T& trk1, const T& trk2) { if (abs(trk1.pdgCode()) != kPiPlus || abs(trk2.pdgCode()) != kKPlus) return false; @@ -252,29 +388,21 @@ struct k1analysis { auto mother2 = trk2.motherId(); if (mother1 != mother2) return false; - if (abs(trk1.motherPDG()) != 313) - return false; - if (abs(bTrack.pdgCode()) != kPiPlus) - return false; - if (abs(bTrack.motherPDG()) != 10323) + if (abs(trk1.motherPDG()) != kK0Star892) return false; - auto siblings = bTrack.siblingIds(); - if (siblings[0] != mother1 && siblings[1] != mother1) - return false; - return true; } template - bool isTrueK892(const T& trk1, const T& trk2) + bool isTrueRho(const T& trk1, const T& trk2) { - if (abs(trk1.pdgCode()) != kPiPlus || abs(trk2.pdgCode()) != kKPlus) + if (abs(trk1.pdgCode()) != kPiPlus || abs(trk2.pdgCode()) != kPiPlus) return false; auto mother1 = trk1.motherId(); auto mother2 = trk2.motherId(); if (mother1 != mother2) return false; - if (abs(trk1.motherPDG()) != 313) + if (abs(trk1.motherPDG()) != kPDGRho770) return false; return true; } @@ -283,7 +411,7 @@ struct k1analysis { void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksType& dTracks2) { auto multiplicity = collision.cent(); - TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonanceK892, lDecayDaughter_bach, lResonanceK1; + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonanceSecondary, lDecayDaughter_bach, lResonanceK1; for (auto& [trk1, trk2] : combinations(CombinationsFullIndexPolicy(dTracks2, dTracks2))) { // Full index policy is needed to consider all possible combinations if (trk1.index() == trk2.index()) @@ -295,211 +423,217 @@ struct k1analysis { auto isTrk1hasTOF = trk1.hasTOF(); auto isTrk2hasTOF = trk2.hasTOF(); - auto trk1ptPi = trk1.pt(); + auto trk1pt = trk1.pt(); auto trk1NSigmaPiTPC = trk1.tpcNSigmaPi(); auto trk1NSigmaPiTOF = (isTrk1hasTOF) ? trk1.tofNSigmaPi() : -999.; - auto trk2ptKa = trk2.pt(); + auto trk2pt = trk2.pt(); auto trk2NSigmaKaTPC = trk2.tpcNSigmaKa(); auto trk2NSigmaKaTOF = (isTrk2hasTOF) ? trk2.tofNSigmaKa() : -999.; + // for rho mode + auto trk2NSigmaPiTPC = trk2.tpcNSigmaPi(); + auto trk2NSigmaPiTOF = (isTrk2hasTOF) ? trk2.tofNSigmaPi() : -999.; //// PID selections if (cUseOnlyTOFTrackPi && !isTrk1hasTOF) continue; if (cUseOnlyTOFTrackKa && !isTrk2hasTOF) continue; - if (!selectionPIDPion(trk1) || !selectionPIDKaon(trk2)) - continue; + + if (cfgModeK892orRho) { // K892 mode + if (!selectionPIDPion(trk1) || !selectionPIDKaon(trk2)) + continue; + } else { // Rho mode + if (!selectionPIDPion(trk1) || !selectionPIDPion(trk2)) + continue; + } //// QA plots after the selection - // --- PID QA Pion if constexpr (!IsMix) { - histos.fill(HIST("QA/TPC_Nsigma_pi"), trk1ptPi, trk1NSigmaPiTPC); + // --- PID QA Pion + histos.fill(HIST("QA/trkspionTPCPID"), trk1pt, trk1NSigmaPiTPC); if (isTrk1hasTOF) { - histos.fill(HIST("QA/TOF_Nsigma_pi"), trk1ptPi, trk1NSigmaPiTOF); - histos.fill(HIST("QA/TOF_TPC_Map_pi"), trk1NSigmaPiTOF, trk1NSigmaPiTPC); + histos.fill(HIST("QA/trkspionTOFPID"), trk1pt, trk1NSigmaPiTOF); + histos.fill(HIST("QA/trkspionTPCTOFPID"), trk1NSigmaPiTPC, trk1NSigmaPiTOF); } - // --- PID QA Kaon - histos.fill(HIST("QA/TPC_Nsigmaka"), trk2ptKa, trk2NSigmaKaTPC); - if (isTrk1hasTOF) { - histos.fill(HIST("QA/TOF_Nsigma_ka"), trk2ptKa, trk2NSigmaKaTOF); - histos.fill(HIST("QA/TOF_TPC_Map_ka"), trk2NSigmaKaTOF, trk2NSigmaKaTPC); + histos.fill(HIST("QA/trkspionpT"), trk1pt); + histos.fill(HIST("QA/trkspionDCAxy"), trk1.dcaXY()); + histos.fill(HIST("QA/trkspionDCAz"), trk1.dcaZ()); + + if (cfgModeK892orRho) { // K892 mode + // --- PID QA Kaon + histos.fill(HIST("QA/trkkaonTPCPID"), trk2pt, trk2NSigmaKaTPC); + if (isTrk1hasTOF) { + histos.fill(HIST("QA/trkkaonTOFPID"), trk2pt, trk2NSigmaKaTOF); + histos.fill(HIST("QA/trkkaonTPCTOFPID"), trk2NSigmaKaTPC, trk2NSigmaKaTOF); + } + histos.fill(HIST("QA/trkkaonpT"), trk2pt); + histos.fill(HIST("QA/trkkaonDCAxy"), trk2.dcaXY()); + histos.fill(HIST("QA/trkkaonDCAz"), trk2.dcaZ()); + } else { // Rho mode + // --- PID QA Pion + histos.fill(HIST("QA/trkppionTPCPID"), trk2pt, trk2NSigmaPiTPC); + if (isTrk2hasTOF) { + histos.fill(HIST("QA/trkppionTOFPID"), trk2pt, trk2NSigmaPiTOF); + histos.fill(HIST("QA/trkppionTPCTOFPID"), trk2NSigmaPiTPC, trk2NSigmaPiTOF); + } + histos.fill(HIST("QA/trkppionpT"), trk2pt); + histos.fill(HIST("QA/trkppionDCAxy"), trk2.dcaXY()); + histos.fill(HIST("QA/trkppionDCAz"), trk2.dcaZ()); } - histos.fill(HIST("QA/trkpT_pi"), trk1ptPi); - histos.fill(HIST("QA/trkpT_ka"), trk2ptKa); - - histos.fill(HIST("QA/trkDCAxy_pi"), trk1.dcaXY()); - histos.fill(HIST("QA/trkDCAxy_ka"), trk2.dcaXY()); - histos.fill(HIST("QA/trkDCAz_pi"), trk1.dcaZ()); - histos.fill(HIST("QA/trkDCAz_ka"), trk2.dcaZ()); } //// Resonance reconstruction lDecayDaughter1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massPi); - lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massKa); - lResonanceK892 = lDecayDaughter1 + lDecayDaughter2; + lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), (cfgModeK892orRho) ? massKa : massPi); + lResonanceSecondary = lDecayDaughter1 + lDecayDaughter2; if constexpr (!IsMix) { - histos.fill(HIST("k892invmass"), lResonanceK892.M()); // quick check - if (trk1.sign() > 0) { // Positive pion - if (trk2.sign() > 0) // Positive kaon - histos.fill(HIST("hK892invmass_PP"), multiplicity, lResonanceK892.Pt(), lResonanceK892.M()); - else // Negative kaon - histos.fill(HIST("hK892invmass_PN"), multiplicity, lResonanceK892.Pt(), lResonanceK892.M()); // Anti-K(892)0 - } else { // Negative pion - if (trk2.sign() > 0) // Positive kaon - histos.fill(HIST("hK892invmass_NP"), multiplicity, lResonanceK892.Pt(), lResonanceK892.M()); // K(892)0 - else // Negative kaon - histos.fill(HIST("hK892invmass_NN"), multiplicity, lResonanceK892.Pt(), lResonanceK892.M()); - } + histos.fill(HIST("QA/hInvmassSecon"), lResonanceSecondary.M()); } - // Like-sign rejection for K(892)0 - disabled for further LS bkg study - // if (trk1.sign() * trk2.sign() > 0) - // continue; - if constexpr (IsMC) { // MC Check of K(892)0 - if (isTrueK892(trk1, trk2)) - histos.fill(HIST("hReconK892pt"), lResonanceK892.Pt()); + if constexpr (IsMC) { // MC Check + if (cfgModeK892orRho) { + if (isTrueK892(trk1, trk2)) + histos.fill(HIST("QAMC/hpT_Secondary"), lResonanceSecondary.Pt()); + } else { + if (isTrueRho(trk1, trk2)) + histos.fill(HIST("QAMC/hpT_Secondary"), lResonanceSecondary.Pt()); + } } // Mass window cut - if (std::abs(lResonanceK892.M() - massK892) > cK892masswindow) + double massCut = cfgModeK892orRho ? massK892 : massRho770; + if (std::abs(lResonanceSecondary.M() - massCut) > cSecondaryMasswindow) continue; - // Add one more track loop for K1 reconstruction + + // bTrack loop for K1 reconstruction for (auto bTrack : dTracks1) { - // ID cut if (bTrack.index() == trk1.index() || bTrack.index() == trk2.index()) continue; - // Track cut if (!trackCut(bTrack)) continue; - auto bTrkPt = bTrack.pt(); - auto bTrkTPCnSigmaPi = bTrack.tpcNSigmaPi(); - auto isbTrkhasTOF = bTrack.hasTOF(); - auto bTrack_TOFnSigma = (isbTrkhasTOF) ? bTrack.tofNSigmaPi() : -999.; - - // PID selection - if (!selectionPIDPion(bTrack)) + // Kaon or Pion + if (cfgModeK892orRho && !selectionPIDPion(bTrack)) + continue; + if (!cfgModeK892orRho && !selectionPIDKaon(bTrack)) continue; - - if constexpr (!IsMix) { - histos.fill(HIST("QA/trkpT_pi_bach"), bTrkPt); - // --- PID QA Pion - histos.fill(HIST("QA/TPC_Nsigma_pi_bach"), bTrkPt, bTrkTPCnSigmaPi); - if (isbTrkhasTOF) { - histos.fill(HIST("QA/TOF_Nsigma_pi_bach"), bTrkPt, bTrack_TOFnSigma); - histos.fill(HIST("QA/TOF_TPC_Map_pi_bach"), bTrack_TOFnSigma, bTrkTPCnSigmaPi); - } - histos.fill(HIST("QA/trkDCAxy_pi_bach"), bTrack.dcaXY()); - histos.fill(HIST("QA/trkDCAz_pi_bach"), bTrack.dcaZ()); - } // K1 reconstruction - lDecayDaughter_bach.SetXYZM(bTrack.px(), bTrack.py(), bTrack.pz(), massPi); - lResonanceK1 = lResonanceK892 + lDecayDaughter_bach; + lDecayDaughter_bach.SetXYZM(bTrack.px(), bTrack.py(), bTrack.pz(), cfgModeK892orRho ? massPi : massKa); + lResonanceK1 = lResonanceSecondary + lDecayDaughter_bach; - // Rapidity cut + // Cuts if (lResonanceK1.Rapidity() > cK1MaxRap || lResonanceK1.Rapidity() < cK1MinRap) continue; - // Opening angle cut - auto lK1Angle = lResonanceK892.Angle(lDecayDaughter_bach.Vect()); - // Pair asymmetry cut - auto lPairAsym = (lResonanceK892.E() - lDecayDaughter_bach.E()) / (lResonanceK892.E() + lDecayDaughter_bach.E()); - // PiPi, PiKa mass range cut - TLorentzVector tempPiPi = lDecayDaughter1 + lDecayDaughter_bach; - TLorentzVector tempPiKa = lDecayDaughter2 + lDecayDaughter_bach; + + auto lK1Angle = lResonanceSecondary.Angle(lDecayDaughter_bach.Vect()); + auto lPairAsym = (lResonanceSecondary.E() - lDecayDaughter_bach.E()) / (lResonanceSecondary.E() + lDecayDaughter_bach.E()); + + TLorentzVector temp13 = lDecayDaughter1 + lDecayDaughter_bach; + TLorentzVector temp23 = lDecayDaughter2 + lDecayDaughter_bach; + + // QA histograms if constexpr (!IsMix) { - histos.fill(HIST("QA/InvMass_piK_pipi"), lResonanceK892.M(), tempPiPi.M()); - histos.fill(HIST("QA/InvMass_piK_pika"), lResonanceK892.M(), tempPiKa.M()); histos.fill(HIST("QA/K1OA"), lK1Angle); - histos.fill(HIST("QA/K1PairAsymm"), lPairAsym); + histos.fill(HIST("QA/K1PairAssym"), lPairAsym); + if (cfgModeK892orRho) { + histos.fill(HIST("QA/hInvmassK892_Rho"), lResonanceSecondary.M(), temp13.M()); + } else { + histos.fill(HIST("QA/hInvmassK892_Rho"), temp13.M(), lResonanceSecondary.M()); + } + histos.fill(HIST("QA/hInvmassSecon_PiKa"), lResonanceSecondary.M(), temp23.M()); + histos.fill(HIST("QA/hpT_Secondary"), lResonanceSecondary.Pt()); } - if (tempPiPi.M() < cPiPiMin || tempPiPi.M() > cPiPiMax) + + // Selection cuts + if (temp13.M() < cMinAnotherSecondaryMassCut || temp13.M() > cMaxAnotherSecondaryMassCut) continue; - if (tempPiKa.M() < cPiKaMin || tempPiKa.M() > cPiKaMax) + if (temp23.M() < cMinPiKaMassCut || temp23.M() > cMaxPiKaMassCut) continue; if (lK1Angle < cMinAngle || lK1Angle > cMaxAngle) continue; if (lPairAsym < cMinPairAsym || lPairAsym > cMaxPairAsym) continue; - if constexpr (!IsMix) { // Same event pair - if (trk1.sign() * trk2.sign() < 0) { // K892 - if (bTrack.sign() > 0) { // bachelor pi+ - if (trk2.sign() > 0) { // kaon + means K(892)0 is matter. - histos.fill(HIST("k1invmass"), lResonanceK1.M()); // quick check - histos.fill(HIST("hK1invmass_NPP"), multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); - } else { - histos.fill(HIST("k1invmass_LS"), lResonanceK1.M()); // quick check - histos.fill(HIST("hK1invmass_PNP"), multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); - } - } else { // bachelor pi- - if (trk2.sign() > 0) { // kaon + means K(892)0 is matter. - histos.fill(HIST("k1invmass_LS"), lResonanceK1.M()); // quick check - histos.fill(HIST("hK1invmass_NPN"), multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); - } else { - histos.fill(HIST("k1invmass"), lResonanceK1.M()); // quick check - histos.fill(HIST("hK1invmass_PNN"), multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); - } - } - } else { // K892-LS (false) - if (bTrack.sign() > 0) { // bachelor pi+ - if (trk2.sign() > 0) { // Kaon+ - histos.fill(HIST("hK1invmass_PPP"), multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); - } else { - histos.fill(HIST("hK1invmass_PPN"), multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); - } - } else { // bachelor pi- - if (trk2.sign() > 0) { // Kaon_ - histos.fill(HIST("hK1invmass_NNN"), multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); - } else { - histos.fill(HIST("hK1invmass_NNP"), multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); - } - } + // QA histograms after the cuts + if constexpr (!IsMix) { + histos.fill(HIST("QAcut/K1OA"), lK1Angle); + histos.fill(HIST("QAcut/K1PairAssym"), lPairAsym); + if (cfgModeK892orRho) { + histos.fill(HIST("QAcut/hInvmassK892_Rho"), lResonanceSecondary.M(), temp13.M()); + } else { + histos.fill(HIST("QAcut/hInvmassK892_Rho"), temp13.M(), lResonanceSecondary.M()); } + histos.fill(HIST("QAcut/hInvmassSecon_PiKa"), lResonanceSecondary.M(), temp23.M()); + histos.fill(HIST("QAcut/hInvmassSecon"), lResonanceSecondary.M()); + histos.fill(HIST("QAcut/hpT_Secondary"), lResonanceSecondary.Pt()); + } + + if constexpr (!IsMix) { + unsigned int typeK1 = bTrack.sign() > 0 ? binType::kK1P : binType::kK1N; + unsigned int typeNormal = cfgModeK892orRho ? (trk1.sign() < 0 ? binAnti::kNormal : binAnti::kAnti) : binAnti::kNormal; + histos.fill(HIST("k1invmass"), lResonanceK1.M()); + histos.fill(HIST("hInvmass_K1"), typeNormal, typeK1, multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); if constexpr (IsMC) { if (isTrueK1(trk1, trk2, bTrack)) { - histos.fill(HIST("hReconK1pt"), lResonanceK1.Pt()); - histos.fill(HIST("QAMC/InvMass_piK_pipi"), lResonanceK892.M(), tempPiPi.M()); - histos.fill(HIST("QAMC/InvMass_piK_pika"), lResonanceK892.M(), tempPiKa.M()); + typeK1 = bTrack.sign() > 0 ? binType::kK1P_Rec : binType::kK1N_Rec; + histos.fill(HIST("hInvmass_K1"), typeNormal, typeK1, multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); + histos.fill(HIST("k1invmass_MC"), lResonanceK1.M()); histos.fill(HIST("QAMC/K1OA"), lK1Angle); - histos.fill(HIST("QAMC/K1PairAsymm"), lPairAsym); - - if ((bTrack.sign() > 0) && (trk2.sign() > 0)) { // Matter - histos.fill(HIST("hK1invmass_NPP_MC"), multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); - histos.fill(HIST("k1invmass_MC"), lResonanceK1.M()); // quick check - } - if ((bTrack.sign() < 0) && (trk2.sign() < 0)) { // Anti-matter - histos.fill(HIST("hK1invmass_PNN_MC"), multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); - histos.fill(HIST("k1invmass_MC"), lResonanceK1.M()); // quick check - } - histos.fill(HIST("hTrueK1pt"), lResonanceK1.Pt()); - } else { - if (((bTrack.sign() > 0) && (trk2.sign() > 0)) || ((bTrack.sign() < 0) && (trk2.sign() < 0))) - histos.fill(HIST("k1invmass_noK1"), lResonanceK1.M()); // quick check - } - } - } else { // Mixed event pair - if (trk1.sign() * trk2.sign() < 0) { // K892 - if (bTrack.sign() > 0) { // bachelor pi+ - if (trk2.sign() > 0) { // kaon + means K(892)0 is matter. - histos.fill(HIST("k1invmass_Mix"), lResonanceK1.M()); // quick check - histos.fill(HIST("hK1invmass_NPP_Mix"), multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); + histos.fill(HIST("QAMC/K1PairAssym"), lPairAsym); + if (cfgModeK892orRho) { + histos.fill(HIST("QAMC/hInvmassK892_Rho"), lResonanceSecondary.M(), temp13.M()); } else { - histos.fill(HIST("hK1invmass_PNP_Mix"), multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); + histos.fill(HIST("QAMC/hInvmassK892_Rho"), temp13.M(), lResonanceSecondary.M()); } - } else { // bachelor pi- - if (trk2.sign() > 0) { // kaon + means K(892)0 is matter. - histos.fill(HIST("hK1invmass_NPN_Mix"), multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); - } else { - histos.fill(HIST("k1invmass_Mix"), lResonanceK1.M()); // quick check - histos.fill(HIST("hK1invmass_PNN_Mix"), multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); + histos.fill(HIST("QAMC/hInvmassSecon_PiKa"), lResonanceSecondary.M(), temp23.M()); + histos.fill(HIST("QAMC/hInvmassSecon"), lResonanceSecondary.M()); + histos.fill(HIST("QAMC/hpT_Secondary"), lResonanceSecondary.Pt()); + + // --- PID QA Pion + histos.fill(HIST("QAMC/trkspionTPCPID"), trk1pt, trk1NSigmaPiTPC); + if (isTrk1hasTOF) { + histos.fill(HIST("QAMC/trkspionTOFPID"), trk1pt, trk1NSigmaPiTOF); + histos.fill(HIST("QAMC/trkspionTPCTOFPID"), trk1NSigmaPiTPC, trk1NSigmaPiTOF); + } + histos.fill(HIST("QAMC/trkspionpT"), trk1pt); + histos.fill(HIST("QAMC/trkspionDCAxy"), trk1.dcaXY()); + histos.fill(HIST("QAMC/trkspionDCAz"), trk1.dcaZ()); + + if (cfgModeK892orRho) { // K892 mode + // --- PID QA Kaon + histos.fill(HIST("QAMC/trkkaonTPCPID"), trk2pt, trk2NSigmaKaTPC); + if (isTrk1hasTOF) { + histos.fill(HIST("QAMC/trkkaonTOFPID"), trk2pt, trk2NSigmaKaTOF); + histos.fill(HIST("QAMC/trkkaonTPCTOFPID"), trk2NSigmaKaTPC, trk2NSigmaKaTOF); + } + histos.fill(HIST("QAMC/trkkaonpT"), trk2pt); + histos.fill(HIST("QAMC/trkkaonDCAxy"), trk2.dcaXY()); + histos.fill(HIST("QAMC/trkkaonDCAz"), trk2.dcaZ()); + } else { // Rho mode + // --- PID QA Pion + histos.fill(HIST("QAMC/trkppionTPCPID"), trk2pt, trk2NSigmaPiTPC); + if (isTrk2hasTOF) { + histos.fill(HIST("QAMC/trkppionTOFPID"), trk2pt, trk2NSigmaPiTOF); + histos.fill(HIST("QAMC/trkppionTPCTOFPID"), trk2NSigmaPiTPC, trk2NSigmaPiTOF); + } + histos.fill(HIST("QAMC/trkppionpT"), trk2pt); + histos.fill(HIST("QAMC/trkppionDCAxy"), trk2.dcaXY()); + histos.fill(HIST("QAMC/trkppionDCAz"), trk2.dcaZ()); } + } else { + histos.fill(HIST("k1invmass_MC_noK1"), lResonanceK1.M()); } - } + } // MC + } else { // Mixed event handling + unsigned int typeK1 = bTrack.sign() > 0 ? binType::kK1P_Mix : binType::kK1N_Mix; + unsigned int typeNormal = cfgModeK892orRho ? (trk1.sign() < 0 ? binAnti::kNormal : binAnti::kAnti) : binAnti::kNormal; + histos.fill(HIST("hInvmass_K1"), typeNormal, typeK1, multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); + histos.fill(HIST("k1invmass_Mix"), lResonanceK1.M()); } - } + } // bTrack } } @@ -517,25 +651,57 @@ struct k1analysis { } PROCESS_SWITCH(k1analysis, processMC, "Process Event for MC", false); - void processMCTrue(aod::ResoMCParents& resoParents) + void processMCTrue(ResoMCCols::iterator const& collision, aod::ResoMCParents& resoParents) { - for (auto& part : resoParents) { // loop over all pre-filtered MC particles - if (abs(part.pdgCode()) != 10323) // K892(0) + auto multiplicity = collision.cent(); + for (auto& part : resoParents) { // loop over all pre-filtered MC particles + if (abs(part.pdgCode()) != kK1Plus) // K892(0) continue; if (abs(part.y()) > 0.5) { // rapidity cut continue; } bool pass1 = false; bool pass2 = false; - if (abs(part.daughterPDG1()) == 313 || abs(part.daughterPDG2()) == 313) { // At least one decay to Kaon - pass2 = true; + if (cfgModeK892orRho) { + if (abs(part.daughterPDG1()) == 313 || abs(part.daughterPDG2()) == 313) { // At least one decay to K892 + pass2 = true; + } + if (abs(part.daughterPDG1()) == kPiPlus || abs(part.daughterPDG2()) == kPiPlus) { // At least one decay to Pion + pass1 = true; + } + if (!pass1 || !pass2) // If we have both decay products + continue; + } else { + if (abs(part.daughterPDG1()) == kPDGRho770 || abs(part.daughterPDG2()) == kPDGRho770) { // At least one decay to Rho + pass2 = true; + } + if (abs(part.daughterPDG1()) == kKPlus || abs(part.daughterPDG2()) == kKPlus) { // At least one decay to Kaon + pass1 = true; + } + if (!pass1 || !pass2) // If we have both decay products + continue; } - if (abs(part.daughterPDG1()) == kPiPlus || abs(part.daughterPDG2()) == kPiPlus) { // At least one decay to Pion - pass1 = true; + auto typeNormal = part.pdgCode() > 0 ? binAnti::kNormal : binAnti::kAnti; + if (collision.isVtxIn10()) // INEL10 + { + auto typeK1 = part.pdgCode() > 0 ? binType::kK1P_GenINEL10 : binType::kK1N_GenINEL10; + histos.fill(HIST("hInvmass_K1"), typeNormal, typeK1, multiplicity, part.pt(), 1); + } + if (collision.isVtxIn10() && collision.isInSel8()) // INEL>10, vtx10 + { + auto typeK1 = part.pdgCode() > 0 ? binType::kK1P_GenINELgt10 : binType::kK1N_GenINELgt10; + histos.fill(HIST("hInvmass_K1"), typeNormal, typeK1, multiplicity, part.pt(), 1); + } + if (collision.isVtxIn10() && collision.isTriggerTVX()) // vtx10, TriggerTVX + { + auto typeK1 = part.pdgCode() > 0 ? binType::kK1P_GenTrig10 : binType::kK1N_GenTrig10; + histos.fill(HIST("hInvmass_K1"), typeNormal, typeK1, multiplicity, part.pt(), 1); + } + if (collision.isInAfterAllCuts()) // after all event selection + { + auto typeK1 = part.pdgCode() > 0 ? binType::kK1P_GenEvtSel : binType::kK1N_GenEvtSel; + histos.fill(HIST("hInvmass_K1"), typeNormal, typeK1, multiplicity, part.pt(), 1); } - if (!pass1 || !pass2) // If we have both decay products - continue; - histos.fill(HIST("hTrueK1pt"), part.pt()); } } PROCESS_SWITCH(k1analysis, processMCTrue, "Process Event for MC", false); diff --git a/PWGLF/Tasks/Resonances/k892SpherocityAnalysis.cxx b/PWGLF/Tasks/Resonances/k892SpherocityAnalysis.cxx index 1c3490e0164..7081f79c751 100644 --- a/PWGLF/Tasks/Resonances/k892SpherocityAnalysis.cxx +++ b/PWGLF/Tasks/Resonances/k892SpherocityAnalysis.cxx @@ -437,7 +437,7 @@ struct k892Analysis { } } - using resoCols = aod::ResoCollisions; + using resoCols = soa::Join; using resoTracks = aod::ResoTracks; void processData(resoCols::iterator const& collision, resoTracks const& tracks) diff --git a/PWGLF/Tasks/Resonances/k892analysis.cxx b/PWGLF/Tasks/Resonances/k892analysis.cxx index deac62b4cba..34e4cc662a0 100644 --- a/PWGLF/Tasks/Resonances/k892analysis.cxx +++ b/PWGLF/Tasks/Resonances/k892analysis.cxx @@ -8,7 +8,7 @@ // 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 k892analysis.cxx /// \brief Reconstruction of track-track decay resonance candidates /// @@ -17,6 +17,7 @@ #include #include "TF1.h" +#include "TRandom3.h" #include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/Centrality.h" @@ -34,17 +35,20 @@ using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::constants::physics; -struct k892analysis { +struct K892analysis { SliceCache cache; Preslice perRCol = aod::resodaughter::resoCollisionId; Preslice perCollision = aod::track::collisionId; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + using ResoMCCols = soa::Join; + ///// Configurables /// Histograms ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12.0, 12.1, 12.2, 12.3, 12.4, 12.5, 12.6, 12.7, 12.8, 12.9, 13.0, 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7, 13.8, 13.9, 14.0, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15.0}, "Binning of the pT axis"}; ConfigurableAxis binsPtQA{"binsPtQA", {VARIABLE_WIDTH, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2, 6.4, 6.6, 6.8, 7.0, 7.2, 7.4, 7.6, 7.8, 8.0, 8.2, 8.4, 8.6, 8.8, 9.0, 9.2, 9.4, 9.6, 9.8, 10.0}, "Binning of the pT axis"}; ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0}, "Binning of the centrality axis"}; + ConfigurableAxis occupancyBins{"occupancyBins", {VARIABLE_WIDTH, 0.0, 100, 500, 600, 1000, 1100, 1500, 1600, 2000, 2100, 2500, 2600, 3000, 3100, 3500, 3600, 4000, 4100, 4500, 4600, 5000, 5100, 9999}, "Binning of the occupancy axis"}; // ConfigurableAxis binsCent{"binsCent", {200, 0.0f, 200.0f}, "Binning of the centrality axis"}; Configurable cInvMassStart{"cInvMassStart", 0.6, "Invariant mass start"}; Configurable cInvMassEnd{"cInvMassEnd", 1.5, "Invariant mass end"}; @@ -52,10 +56,16 @@ struct k892analysis { Configurable cPIDBins{"cPIDBins", 65, "PID binning"}; Configurable cPIDQALimit{"cPIDQALimit", 6.5, "PID QA limit"}; Configurable cDCABins{"cDCABins", 150, "DCA binning"}; + Configurable invmass1D{"invmass1D", false, "Invariant mass 1D"}; + Configurable studyAntiparticle{"studyAntiparticle", false, "Study anti-particles separately"}; + Configurable fillPidPlots{"fillPidPlots", false, "Make TPC and TOF PID plots"}; + // Configurable applyOccupancyCut{"applyOccupancyCut", false, "Apply occupancy cut"}; + // Configurable occupancyCut{"occupancyCut", 1000, "Mimimum Occupancy cut"}; + /// Event Mixing Configurable nEvtMixing{"nEvtMixing", 5, "Number of events to mix"}; - ConfigurableAxis CfgVtxBins{"CfgVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - ConfigurableAxis CfgMultBins{"CfgMultBins", {VARIABLE_WIDTH, 0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Mixing bins - z-vertex"}; + ConfigurableAxis cfgVtxBins{"cfgVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis cfgMultBins{"cfgMultBins", {VARIABLE_WIDTH, 0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Mixing bins - z-vertex"}; /// Pre-selection cuts Configurable cMinPtcut{"cMinPtcut", 0.15, "Track minium pt cut"}; @@ -75,21 +85,30 @@ struct k892analysis { Configurable cMaxTPCnSigmaKaon{"cMaxTPCnSigmaKaon", 3.0, "TPC nSigma cut for Kaon"}; // TPC Configurable cMaxTOFnSigmaKaon{"cMaxTOFnSigmaKaon", 3.0, "TOF nSigma cut for Kaon"}; // TOF Configurable nsigmaCutCombinedKaon{"nsigmaCutCombinedKaon", -999, "Combined nSigma cut for Kaon"}; // Combined + Configurable cByPassTOF{"cByPassTOF", false, "By pass TOF PID selection"}; // By pass TOF PID selection // Track selections Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) Configurable cfgGlobalTrack{"cfgGlobalTrack", false, "Global track selection"}; // kGoldenChi2 | kDCAxy | kDCAz Configurable cfgPVContributor{"cfgPVContributor", false, "PV contributor track selection"}; // PV Contriuibutor Configurable additionalQAplots{"additionalQAplots", true, "Additional QA plots"}; - Configurable tof_at_high_pt{"tof_at_high_pt", false, "Use TOF at high pT"}; + Configurable additionalQAeventPlots{"additionalQAeventPlots", false, "Additional QA event plots"}; + Configurable additionalMEPlots{"additionalMEPlots", false, "Additional Mixed event plots"}; + + Configurable tofAtHighPt{"tofAtHighPt", false, "Use TOF at high pT"}; Configurable additionalEvsel{"additionalEvsel", true, "Additional event selcection"}; - Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; Configurable cfgTPCcluster{"cfgTPCcluster", 0, "Number of TPC cluster"}; - Configurable cfgRatioTPCRowsOverFindableCls{"cfgRatioTPCRowsOverFindableCls", 0.0f, "TPC Crossed Rows to Findable Clusters"}; - Configurable cfgITSChi2NCl{"cfgITSChi2NCl", 999.0, "ITS Chi2/NCl"}; - Configurable cfgTPCChi2NCl{"cfgTPCChi2NCl", 999.0, "TPC Chi2/NCl"}; Configurable cfgUseTPCRefit{"cfgUseTPCRefit", false, "Require TPC Refit"}; Configurable cfgUseITSRefit{"cfgUseITSRefit", false, "Require ITS Refit"}; + Configurable cfgHasTOF{"cfgHasTOF", false, "Require TOF"}; + + // Rotational background + Configurable isCalcRotBkg{"isCalcRotBkg", true, "Calculate rotational background"}; + Configurable rotationalCut{"rotationalCut", 10, "Cut value (Rotation angle pi - pi/cut and pi + pi/cut)"}; + Configurable cNofRotations{"cNofRotations", 3, "Number of random rotations in the rotational background"}; + + // MC Event selection + Configurable cZvertCutMC{"cZvertCutMC", 10.0, "MC Z-vertex cut"}; // Event selection cuts - Alex (Temporary, need to fix!) TF1* fMultPVCutLow = nullptr; @@ -98,22 +117,62 @@ struct k892analysis { TF1* fMultCutHigh = nullptr; TF1* fMultMultPVCut = nullptr; + // cuts on mother + Configurable cfgCutsOnMother{"cfgCutsOnMother", false, "Enamble additional cuts on mother"}; + Configurable cMaxPtMotherCut{"cMaxPtMotherCut", 15.0, "Maximum pt of mother cut"}; + Configurable cMaxMinvMotherCut{"cMaxMinvMotherCut", 1.5, "Maximum Minv of mother cut"}; + Configurable cfgCutsOnDaughters{"cfgCutsOnDaughters", false, "Enamble additional cuts on daughters"}; + Configurable cetaphiBins{"cetaphiBins", 400, "number of eta and phi bins"}; + Configurable cMaxDeltaEtaCut{"cMaxDeltaEtaCut", 0.7, "Maximum deltaEta between daughters"}; + Configurable cMaxDeltaPhiCut{"cMaxDeltaPhiCut", 1.5, "Maximum deltaPhi between daughters"}; + TRandom* rn = new TRandom(); + void init(o2::framework::InitContext&) { AxisSpec centAxis = {binsCent, "V0M (%)"}; AxisSpec dcaxyAxis = {cDCABins, 0.0, 3.0, "DCA_{#it{xy}} (cm)"}; AxisSpec dcazAxis = {cDCABins, 0.0, 3.0, "DCA_{#it{xy}} (cm)"}; + AxisSpec mcLabelAxis = {5, -0.5, 4.5, "MC Label"}; AxisSpec ptAxis = {binsPt, "#it{p}_{T} (GeV/#it{c})"}; AxisSpec ptAxisQA = {binsPtQA, "#it{p}_{T} (GeV/#it{c})"}; AxisSpec invMassAxis = {cInvMassBins, cInvMassStart, cInvMassEnd, "Invariant Mass (GeV/#it{c}^2)"}; AxisSpec pidQAAxis = {cPIDBins, -cPIDQALimit, cPIDQALimit}; + // AxisSpec occupancyAxis = {occupancyBins, "Occupancy [-40,100]"}; + + if (additionalQAeventPlots) { + // Test on Mixed event + histos.add("TestME/hCollisionIndexSameE", "coll index sameE", HistType::kTH1F, {{500, 0.0f, 500.0f}}); + histos.add("TestME/hCollisionIndexMixedE", "coll index mixedE", HistType::kTH1F, {{500, 0.0f, 500.0f}}); + histos.add("TestME/hnTrksSameE", "n tracks per event SameE", HistType::kTH1F, {{1000, 0.0f, 1000.0f}}); + histos.add("TestME/hnTrksMixedE", "n tracks per event MixedE", HistType::kTH1F, {{1000, 0.0f, 1000.0f}}); + histos.add("TestME/hPairsCounterSameE", "tot n pairs sameE", HistType::kTH1F, {{1, 0.5f, 1.5f}}); + histos.add("TestME/hPairsCounterMixedE", "tot n pairs mixedE", HistType::kTH1F, {{1, 0.5f, 1.5f}}); + + // event histograms + histos.add("QAevent/hEvtCounterSameE", "Number of analyzed Same Events", HistType::kTH1F, {{1, 0.5, 1.5}}); + histos.add("QAevent/hVertexZSameE", "Collision Vertex Z position", HistType::kTH1F, {{100, -15., 15.}}); + histos.add("QAevent/hMultiplicityPercentSameE", "Multiplicity percentile of collision", HistType::kTH1F, {{120, 0.0f, 120.0f}}); + + histos.add("QAevent/hEvtCounterMixedE", "Number of analyzed Mixed Events", HistType::kTH1F, {{1, 0.5, 1.5}}); + histos.add("QAevent/hVertexZMixedE", "Collision Vertex Z position", HistType::kTH1F, {{100, -15., 15.}}); + histos.add("QAevent/hMultiplicityPercentMixedE", "Multiplicity percentile of collision", HistType::kTH1F, {{120, 0.0f, 120.0f}}); + } // Mass QA (quick check) - histos.add("k892invmassDS", "Invariant mass of K(892)0 differnt sign", kTH1F, {invMassAxis}); - histos.add("k892invmassDSAnti", "Invariant mass of Anti-K(892)0 differnt sign", kTH1F, {invMassAxis}); - histos.add("k892invmassLS", "Invariant mass of K(892)0 like sign", kTH1F, {invMassAxis}); - histos.add("k892invmassLSAnti", "Invariant mass of Anti-K(892)0 like sign", kTH1F, {invMassAxis}); - histos.add("k892invmassME", "Invariant mass of K(892)0 mixed event", kTH1F, {invMassAxis}); + if (invmass1D) { + histos.add("k892invmassDS", "Invariant mass of K(892)0 differnt sign", kTH1F, {invMassAxis}); + histos.add("k892invmassLS", "Invariant mass of K(892)0 like sign", kTH1F, {invMassAxis}); + histos.add("k892invmassME", "Invariant mass of K(892)0 mixed event", kTH1F, {invMassAxis}); + if (studyAntiparticle) { + histos.add("k892invmassDSAnti", "Invariant mass of Anti-K(892)0 differnt sign", kTH1F, {invMassAxis}); + histos.add("k892invmassLSAnti", "Invariant mass of Anti-K(892)0 like sign", kTH1F, {invMassAxis}); + } + } + + if (additionalMEPlots) { + histos.add("k892invmassME_DS", "Invariant mass of K(892)0 mixed event DS", kTH1F, {invMassAxis}); + histos.add("k892invmassME_DSAnti", "Invariant mass of K(892)0 mixed event DSAnti", kTH1F, {invMassAxis}); + } if (additionalQAplots) { // TPC ncluster distirbutions @@ -149,26 +208,62 @@ struct k892analysis { histos.add("QAafter/trkpT_pi", "pT distribution of pion track candidates", kTH1F, {ptAxis}); histos.add("QAafter/trkpT_ka", "pT distribution of kaon track candidates", kTH1F, {ptAxis}); // PID QA before cuts - histos.add("QAbefore/TOF_TPC_Map_pi_all", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2D, {pidQAAxis, pidQAAxis}}); - histos.add("QAbefore/TOF_Nsigma_pi_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Pion};", {HistType::kTH2D, {ptAxisQA, pidQAAxis}}); - histos.add("QAbefore/TPC_Nsigma_pi_all", "TPC NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH2D, {ptAxisQA, pidQAAxis}}); - histos.add("QAbefore/TOF_TPC_Mapka_all", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Kaon};#sigma_{TPC}^{Kaon}", {HistType::kTH2D, {pidQAAxis, pidQAAxis}}); - histos.add("QAbefore/TOF_Nsigma_ka_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH2D, {ptAxisQA, pidQAAxis}}); - histos.add("QAbefore/TPC_Nsigmaka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH2D, {ptAxisQA, pidQAAxis}}); - // PID QA after cuts - histos.add("QAafter/TOF_TPC_Map_pi_all", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2D, {pidQAAxis, pidQAAxis}}); - histos.add("QAafter/TOF_Nsigma_pi_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Pion};", {HistType::kTH2D, {ptAxisQA, pidQAAxis}}); - histos.add("QAafter/TPC_Nsigma_pi_all", "TPC NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH2D, {ptAxisQA, pidQAAxis}}); - histos.add("QAafter/TOF_TPC_Mapka_all", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Kaon};#sigma_{TPC}^{Kaon}", {HistType::kTH2D, {pidQAAxis, pidQAAxis}}); - histos.add("QAafter/TOF_Nsigma_ka_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH2D, {ptAxisQA, pidQAAxis}}); - histos.add("QAafter/TPC_Nsigmaka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH2D, {ptAxisQA, pidQAAxis}}); + if (fillPidPlots) { + histos.add("QAbefore/TOF_TPC_Map_pi_all", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAbefore/TOF_Nsigma_pi_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAbefore/TPC_Nsigma_pi_all", "TPC NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAbefore/TOF_TPC_Mapka_all", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Kaon};#sigma_{TPC}^{Kaon}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAbefore/TOF_Nsigma_ka_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAbefore/TPC_Nsigmaka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + // PID QA after cuts + histos.add("QAafter/TOF_TPC_Map_pi_all", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAafter/TOF_Nsigma_pi_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAafter/TPC_Nsigma_pi_all", "TPC NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAafter/TOF_TPC_Mapka_all", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Kaon};#sigma_{TPC}^{Kaon}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAafter/TOF_Nsigma_ka_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAafter/TPC_Nsigmaka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + } + + // eta phi QA + if (cfgCutsOnDaughters) { + histos.add("QAbefore/deltaEta", "deltaEta of kaon and pion candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 3.15}}); + histos.add("QAbefore/deltaPhi", "deltaPhi of kaon and pion candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 3.15}}); + histos.add("QAbefore/Eta", "Eta of tracks candidates", HistType::kTH1F, {{cetaphiBins, -1.6, 1.6}}); + histos.add("QAbefore/Phi", "Phi of tracks candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 6.30}}); + + histos.add("QAafter/deltaEta", "deltaEta of kaon and pion candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 3.15}}); + histos.add("QAafter/deltaPhi", "deltaPhi of kaon and pion candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 3.15}}); + histos.add("QAafter/EtaPi", "Eta of pion candidates", HistType::kTH1F, {{cetaphiBins, -1.6, 1.6}}); + histos.add("QAafter/PhiPi", "Phi of pion candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 6.30}}); + histos.add("QAafter/EtaKa", "Eta of kaon candidates", HistType::kTH1F, {{cetaphiBins, -1.6, 1.6}}); + histos.add("QAafter/PhiKa", "Phi of kaon candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 6.30}}); + + histos.add("QAafter/deltaEtaafter", "deltaEta of kaon and pion candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 3.15}}); + histos.add("QAafter/deltaPhiafter", "deltaPhi of kaon and pion candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 3.15}}); + histos.add("QAafter/EtaPiafter", "Eta of pion candidates", HistType::kTH1F, {{cetaphiBins, -1.6, 1.6}}); + histos.add("QAafter/PhiPiafter", "Phi of pion candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 6.30}}); + histos.add("QAafter/EtaKaafter", "Eta of kaon candidates", HistType::kTH1F, {{cetaphiBins, -1.6, 1.6}}); + histos.add("QAafter/PhiKaafter", "Phi of kaon candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 6.30}}); + } // 3d histogram - histos.add("h3k892invmassDS", "Invariant mass of K(892)0 differnt sign", kTH3F, {centAxis, ptAxis, invMassAxis}); - histos.add("h3k892invmassDSAnti", "Invariant mass of Anti-K(892)0 differnt sign", kTH3F, {centAxis, ptAxis, invMassAxis}); - histos.add("h3k892invmassLS", "Invariant mass of K(892)0 same sign", kTH3F, {centAxis, ptAxis, invMassAxis}); - histos.add("h3k892invmassLSAnti", "Invariant mass of Anti-K(892)0 same sign", kTH3F, {centAxis, ptAxis, invMassAxis}); - histos.add("h3k892invmassME", "Invariant mass of K(892)0 mixed event", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassDS", "Invariant mass of K(892)0 differnt sign", kTHnSparseF, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassLS", "Invariant mass of K(892)0 same sign", kTHnSparseF, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassME", "Invariant mass of K(892)0 mixed event", kTHnSparseF, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassLSAnti", "Invariant mass of Anti-K(892)0 same sign", kTHnSparseF, {centAxis, ptAxis, invMassAxis}); + + if (studyAntiparticle) { + histos.add("h3k892invmassDSAnti", "Invariant mass of Anti-K(892)0 differnt sign", kTHnSparseF, {centAxis, ptAxis, invMassAxis}); + } + + if (isCalcRotBkg) { + histos.add("h3K892InvMassRotation", "Invariant mass of K(892)0 rotation", kTHnSparseF, {centAxis, ptAxis, invMassAxis}); + } + + if (additionalMEPlots) { + histos.add("h3k892invmassME_DS", "Invariant mass of K(892)0 mixed event DS", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassME_DSAnti", "Invariant mass of K(892)0 mixed event DSAnti", kTH3F, {centAxis, ptAxis, invMassAxis}); + } if (doprocessMCLight) { // MC QA @@ -176,16 +271,18 @@ struct k892analysis { histos.add("QAMCTrue/trkDCAxy_ka", "DCAxy distribution of kaon track candidates", HistType::kTH1F, {dcaxyAxis}); histos.add("QAMCTrue/trkDCAz_pi", "DCAz distribution of pion track candidates", HistType::kTH1F, {dcazAxis}); histos.add("QAMCTrue/trkDCAz_ka", "DCAz distribution of kaon track candidates", HistType::kTH1F, {dcazAxis}); - histos.add("QAMCTrue/TOF_Nsigma_pi_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Pion};", {HistType::kTH2D, {ptAxisQA, pidQAAxis}}); - histos.add("QAMCTrue/TPC_Nsigma_pi_all", "TPC NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH2D, {ptAxisQA, pidQAAxis}}); - histos.add("QAMCTrue/TOF_Nsigma_ka_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH2D, {ptAxisQA, pidQAAxis}}); - histos.add("QAMCTrue/TPC_Nsigmaka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH2D, {ptAxisQA, pidQAAxis}}); - histos.add("h3Reck892invmass", "Invariant mass of Reconstructed MC K(892)0", kTH3F, {centAxis, ptAxis, invMassAxis}); - histos.add("h3Reck892invmassAnti", "Invariant mass of Reconstructed MC Anti-K(892)0", kTH3F, {centAxis, ptAxis, invMassAxis}); - histos.add("k892Gen", "pT distribution of True MC K(892)0", kTH2D, {ptAxis, centAxis}); - histos.add("k892GenAnti", "pT distribution of True MC Anti-K(892)0", kTH2D, {ptAxis, centAxis}); - histos.add("k892Rec", "pT distribution of Reconstructed MC K(892)0", kTH2D, {ptAxis, centAxis}); - histos.add("k892RecAnti", "pT distribution of Reconstructed MC Anti-K(892)0", kTH2D, {ptAxis, centAxis}); + if (fillPidPlots) { + histos.add("QAMCTrue/TOF_Nsigma_pi_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAMCTrue/TPC_Nsigma_pi_all", "TPC NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAMCTrue/TOF_Nsigma_ka_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAMCTrue/TPC_Nsigmaka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + } + histos.add("h3Reck892invmass", "Invariant mass of Reconstructed MC K(892)0", kTHnSparseF, {centAxis, ptAxis, invMassAxis}); + histos.add("h3Reck892invmassAnti", "Invariant mass of Reconstructed MC Anti-K(892)0", kTHnSparseF, {centAxis, ptAxis, invMassAxis}); + histos.add("k892Gen", "pT distribution of True MC K(892)0", kTHnSparseF, {mcLabelAxis, ptAxis, centAxis}); + histos.add("k892GenAnti", "pT distribution of True MC Anti-K(892)0", kTHnSparseF, {mcLabelAxis, ptAxis, centAxis}); + histos.add("k892Rec", "pT distribution of Reconstructed MC K(892)0", kTH2F, {ptAxis, centAxis}); + histos.add("k892RecAnti", "pT distribution of Reconstructed MC Anti-K(892)0", kTH2F, {ptAxis, centAxis}); histos.add("k892Recinvmass", "Inv mass distribution of Reconstructed MC Phi", kTH1F, {invMassAxis}); } // Print output histograms statistics @@ -240,15 +337,9 @@ struct k892analysis { return false; if (std::abs(track.dcaZ()) > cMaxDCAzToPVcut) return false; - if (track.itsNCls() < cfgITScluster) - return false; if (track.tpcNClsFound() < cfgTPCcluster) return false; - if (track.tpcCrossedRowsOverFindableCls() < cfgRatioTPCRowsOverFindableCls) - return false; - if (track.itsChi2NCl() >= cfgITSChi2NCl) - return false; - if (track.tpcChi2NCl() >= cfgTPCChi2NCl) + if (cfgHasTOF && !track.hasTOF()) return false; if (cfgUseITSRefit && !track.passedITSRefit()) return false; @@ -269,7 +360,7 @@ struct k892analysis { template bool selectionPIDPion(const T& candidate) { - if (tof_at_high_pt) { + if (tofAtHighPt) { if (candidate.hasTOF() && (std::abs(candidate.tofNSigmaPi()) < cMaxTOFnSigmaPion)) { return true; } @@ -281,6 +372,9 @@ struct k892analysis { if (std::abs(candidate.tpcNSigmaPi()) < cMaxTPCnSigmaPion) { tpcPIDPassed = true; } + if (cByPassTOF && tpcPIDPassed) { + return true; + } if (candidate.hasTOF()) { if (std::abs(candidate.tofNSigmaPi()) < cMaxTOFnSigmaPion) { tofPIDPassed = true; @@ -300,7 +394,7 @@ struct k892analysis { template bool selectionPIDKaon(const T& candidate) { - if (tof_at_high_pt) { + if (tofAtHighPt) { if (candidate.hasTOF() && (std::abs(candidate.tofNSigmaKa()) < cMaxTOFnSigmaKaon)) { return true; } @@ -312,6 +406,9 @@ struct k892analysis { if (std::abs(candidate.tpcNSigmaKa()) < cMaxTPCnSigmaKaon) { tpcPIDPassed = true; } + if (cByPassTOF && tpcPIDPassed) { + return true; + } if (candidate.hasTOF()) { if (std::abs(candidate.tofNSigmaKa()) < cMaxTOFnSigmaKaon) { tofPIDPassed = true; @@ -334,12 +431,31 @@ struct k892analysis { { // auto multNTracksPV = collision.multNTracksPV(); auto multiplicity = collision.cent(); + if (additionalEvsel && !eventSelected(collision, multiplicity)) { + return; + } + // auto occupancyNo = collision.trackOccupancyInTimeRange(); + // if (applyOccupancyCut && occupancyNo < occupancyCut) { + // return; + // } + if (additionalQAplots) { histos.fill(HIST("MultCalib/centglopi_before"), multiplicity, dTracks1.size()); // centrality vs global tracks before the multiplicity calibration cuts histos.fill(HIST("MultCalib/GloPVpi_before"), dTracks1.size(), collision.multNTracksPV()); // global tracks vs PV tracks before the multiplicity calibration cuts } - if (additionalEvsel && !eventSelected(collision, multiplicity)) { - return; + + if (additionalQAeventPlots) { + if constexpr (!IsMix) { + histos.fill(HIST("QAevent/hVertexZSameE"), collision.posZ()); + histos.fill(HIST("QAevent/hMultiplicityPercentSameE"), collision.cent()); + histos.fill(HIST("TestME/hCollisionIndexSameE"), collision.globalIndex()); + histos.fill(HIST("TestME/hnTrksSameE"), dTracks1.size()); + } else { + histos.fill(HIST("QAevent/hVertexZMixedE"), collision.posZ()); + histos.fill(HIST("QAevent/hMultiplicityPercentMixedE"), collision.cent()); + histos.fill(HIST("TestME/hCollisionIndexMixedE"), collision.globalIndex()); + histos.fill(HIST("TestME/hnTrksMixedE"), dTracks1.size()); + } } if (additionalQAplots) { @@ -347,12 +463,21 @@ struct k892analysis { histos.fill(HIST("MultCalib/GloPVpi_after"), dTracks1.size(), collision.multNTracksPV()); // global tracks vs PV tracks after the multiplicity calibration cuts } - TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; - for (auto& [trk1, trk2] : combinations(CombinationsFullIndexPolicy(dTracks1, dTracks2))) { + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance, ldaughterRot, lresonanceRot; + for (const auto& [trk1, trk2] : combinations(CombinationsFullIndexPolicy(dTracks1, dTracks2))) { // Full index policy is needed to consider all possible combinations if (trk1.index() == trk2.index()) continue; // We need to run (0,1), (1,0) pairs as well. but same id pairs are not needed. + + if (additionalQAeventPlots) { + if constexpr (!IsMix) { + histos.fill(HIST("TestME/hPairsCounterSameE"), 1.0); + } else { + histos.fill(HIST("TestME/hPairsCounterMixedE"), 1.0); + } + } + //// Initialize variables // Trk1: Pion, Trk2: Kaon // apply the track cut @@ -368,19 +493,25 @@ struct k892analysis { auto trk2NSigmaKaTPC = trk2.tpcNSigmaKa(); auto trk2NSigmaKaTOF = (isTrk2hasTOF) ? trk2.tofNSigmaKa() : -999.; + auto deltaEta = std::abs(trk1.eta() - trk2.eta()); + auto deltaPhi = std::abs(trk1.phi() - trk2.phi()); + deltaPhi = (deltaPhi > constants::math::PI) ? (constants::math::TwoPI - deltaPhi) : deltaPhi; + if constexpr (!IsMix) { //// QA plots before the selection // --- PID QA Pion - histos.fill(HIST("QAbefore/TPC_Nsigma_pi_all"), trk1ptPi, trk1NSigmaPiTPC); - if (isTrk1hasTOF) { - histos.fill(HIST("QAbefore/TOF_Nsigma_pi_all"), trk1ptPi, trk1NSigmaPiTOF); - histos.fill(HIST("QAbefore/TOF_TPC_Map_pi_all"), trk1NSigmaPiTOF, trk1NSigmaPiTPC); - } - // --- PID QA Kaon - histos.fill(HIST("QAbefore/TPC_Nsigmaka_all"), trk2ptKa, trk2NSigmaKaTPC); - if (isTrk2hasTOF) { - histos.fill(HIST("QAbefore/TOF_Nsigma_ka_all"), trk2ptKa, trk2NSigmaKaTOF); - histos.fill(HIST("QAbefore/TOF_TPC_Mapka_all"), trk2NSigmaKaTOF, trk2NSigmaKaTPC); + if (fillPidPlots) { + histos.fill(HIST("QAbefore/TPC_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTPC); + if (isTrk1hasTOF) { + histos.fill(HIST("QAbefore/TOF_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTOF); + histos.fill(HIST("QAbefore/TOF_TPC_Map_pi_all"), trk1NSigmaPiTOF, trk1NSigmaPiTPC); + } + // --- PID QA Kaon + histos.fill(HIST("QAbefore/TPC_Nsigmaka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTPC); + if (isTrk2hasTOF) { + histos.fill(HIST("QAbefore/TOF_Nsigma_ka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTOF); + histos.fill(HIST("QAbefore/TOF_TPC_Mapka_all"), trk2NSigmaKaTOF, trk2NSigmaKaTPC); + } } histos.fill(HIST("QAbefore/trkpT_pi"), trk1ptPi); histos.fill(HIST("QAbefore/trkpT_ka"), trk2ptKa); @@ -388,6 +519,13 @@ struct k892analysis { histos.fill(HIST("QAbefore/trkDCAxy_ka"), trk2.dcaXY()); histos.fill(HIST("QAbefore/trkDCAz_pi"), trk1.dcaZ()); histos.fill(HIST("QAbefore/trkDCAz_ka"), trk2.dcaZ()); + + if (cfgCutsOnDaughters) { + histos.fill(HIST("QAbefore/Eta"), trk1.eta()); + histos.fill(HIST("QAbefore/Phi"), trk1.phi()); + histos.fill(HIST("QAbefore/deltaEta"), deltaEta); + histos.fill(HIST("QAbefore/deltaPhi"), deltaPhi); + } } // Apply the selection @@ -409,16 +547,18 @@ struct k892analysis { if constexpr (!IsMix) { //// QA plots after the selection // --- PID QA Pion - histos.fill(HIST("QAafter/TPC_Nsigma_pi_all"), trk1ptPi, trk1NSigmaPiTPC); - if (isTrk1hasTOF) { - histos.fill(HIST("QAafter/TOF_Nsigma_pi_all"), trk1ptPi, trk1NSigmaPiTOF); - histos.fill(HIST("QAafter/TOF_TPC_Map_pi_all"), trk1NSigmaPiTOF, trk1NSigmaPiTPC); - } - // --- PID QA Kaon - histos.fill(HIST("QAafter/TPC_Nsigmaka_all"), trk2ptKa, trk2NSigmaKaTPC); - if (isTrk2hasTOF) { - histos.fill(HIST("QAafter/TOF_Nsigma_ka_all"), trk2ptKa, trk2NSigmaKaTOF); - histos.fill(HIST("QAafter/TOF_TPC_Mapka_all"), trk2NSigmaKaTOF, trk2NSigmaKaTPC); + if (fillPidPlots) { + histos.fill(HIST("QAafter/TPC_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTPC); + if (isTrk1hasTOF) { + histos.fill(HIST("QAafter/TOF_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTOF); + histos.fill(HIST("QAafter/TOF_TPC_Map_pi_all"), trk1NSigmaPiTOF, trk1NSigmaPiTPC); + } + // --- PID QA Kaon + histos.fill(HIST("QAafter/TPC_Nsigmaka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTPC); + if (isTrk2hasTOF) { + histos.fill(HIST("QAafter/TOF_Nsigma_ka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTOF); + histos.fill(HIST("QAafter/TOF_TPC_Mapka_all"), trk2NSigmaKaTOF, trk2NSigmaKaTPC); + } } histos.fill(HIST("QAafter/trkpT_pi"), trk1ptPi); histos.fill(HIST("QAafter/trkpT_ka"), trk2ptKa); @@ -426,37 +566,98 @@ struct k892analysis { histos.fill(HIST("QAafter/trkDCAxy_ka"), trk2.dcaXY()); histos.fill(HIST("QAafter/trkDCAz_pi"), trk1.dcaZ()); histos.fill(HIST("QAafter/trkDCAz_ka"), trk2.dcaZ()); + + if (cfgCutsOnDaughters) { + histos.fill(HIST("QAafter/EtaPi"), trk1.eta()); + histos.fill(HIST("QAafter/PhiPi"), trk1.phi()); + histos.fill(HIST("QAafter/EtaKa"), trk2.eta()); + histos.fill(HIST("QAafter/PhiKa"), trk2.phi()); + + histos.fill(HIST("QAafter/deltaEta"), deltaEta); + histos.fill(HIST("QAafter/deltaPhi"), deltaPhi); + } } //// Resonance reconstruction - lDecayDaughter1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massPi); - lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massKa); + lDecayDaughter1.SetPtEtaPhiM(trk1.pt(), trk1.eta(), trk1.phi(), massPi); + lDecayDaughter2.SetPtEtaPhiM(trk2.pt(), trk2.eta(), trk2.phi(), massKa); lResonance = lDecayDaughter1 + lDecayDaughter2; // Rapidity cut - if (abs(lResonance.Rapidity()) >= 0.5) + if (std::abs(lResonance.Rapidity()) >= 0.5) continue; + if (cfgCutsOnMother) { + if (lResonance.Pt() >= cMaxPtMotherCut) // excluding candidates in overflow + continue; + if (lResonance.M() >= cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } + + if (cfgCutsOnDaughters) { + if (deltaEta >= cMaxDeltaEtaCut) + continue; + if (deltaPhi >= cMaxDeltaPhiCut) + continue; + + if constexpr (!IsMix) { + histos.fill(HIST("QAafter/EtaPiafter"), trk1.eta()); + histos.fill(HIST("QAafter/PhiPiafter"), trk1.phi()); + histos.fill(HIST("QAafter/EtaKaafter"), trk2.eta()); + histos.fill(HIST("QAafter/PhiKaafter"), trk2.phi()); + histos.fill(HIST("QAafter/deltaEtaafter"), deltaEta); + histos.fill(HIST("QAafter/deltaPhiafter"), deltaPhi); + } + } + //// Un-like sign pair only if (trk1.sign() * trk2.sign() < 0) { if constexpr (!IsMix) { - if (trk1.sign() < 0) { - histos.fill(HIST("k892invmassDS"), lResonance.M()); + if (isCalcRotBkg) { + for (int i = 0; i < cNofRotations; i++) { + float theta2 = rn->Uniform(constants::math::PI - constants::math::PI / rotationalCut, constants::math::PI + constants::math::PI / rotationalCut); + ldaughterRot.SetPtEtaPhiM(trk2.pt(), trk2.eta(), trk2.phi() + theta2, massKa); // for rotated background + lresonanceRot = lDecayDaughter1 + ldaughterRot; + histos.fill(HIST("h3K892InvMassRotation"), multiplicity, lresonanceRot.Pt(), lresonanceRot.M()); + } + } + if (studyAntiparticle) { + if (trk1.sign() < 0) { + if (invmass1D) + histos.fill(HIST("k892invmassDS"), lResonance.M()); + histos.fill(HIST("h3k892invmassDS"), multiplicity, lResonance.Pt(), lResonance.M()); + } else if (trk1.sign() > 0) { + if (invmass1D) + histos.fill(HIST("k892invmassDSAnti"), lResonance.M()); + histos.fill(HIST("h3k892invmassDSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + } + } else { + if (invmass1D) + histos.fill(HIST("k892invmassDS"), lResonance.M()); histos.fill(HIST("h3k892invmassDS"), multiplicity, lResonance.Pt(), lResonance.M()); - } else if (trk1.sign() > 0) { - histos.fill(HIST("k892invmassDSAnti"), lResonance.M()); - histos.fill(HIST("h3k892invmassDSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); } } else { - histos.fill(HIST("k892invmassME"), lResonance.M()); + if (invmass1D) + histos.fill(HIST("k892invmassME"), lResonance.M()); histos.fill(HIST("h3k892invmassME"), multiplicity, lResonance.Pt(), lResonance.M()); + if (additionalMEPlots) { + if (trk1.sign() < 0) { + if (invmass1D) + histos.fill(HIST("k892invmassME_DS"), lResonance.M()); + histos.fill(HIST("h3k892invmassME_DS"), multiplicity, lResonance.Pt(), lResonance.M()); + } else if (trk1.sign() > 0) { + if (invmass1D) + histos.fill(HIST("k892invmassME_DSAnti"), lResonance.M()); + histos.fill(HIST("h3k892invmassME_DSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + } + } } // MC if constexpr (IsMC) { - if (abs(trk1.pdgCode()) != 211 || abs(trk2.pdgCode()) != 321) + if (std::abs(trk1.pdgCode()) != 211 || std::abs(trk2.pdgCode()) != 321) continue; if (trk1.motherId() != trk2.motherId()) // Same mother continue; - if (abs(trk1.motherPDG()) != 313) + if (std::abs(trk1.motherPDG()) != 313) continue; // Track selection check. @@ -464,13 +665,15 @@ struct k892analysis { histos.fill(HIST("QAMCTrue/trkDCAxy_ka"), trk2.dcaXY()); histos.fill(HIST("QAMCTrue/trkDCAz_pi"), trk1.dcaZ()); histos.fill(HIST("QAMCTrue/trkDCAz_ka"), trk2.dcaZ()); - histos.fill(HIST("QAMCTrue/TPC_Nsigma_pi_all"), trk1ptPi, trk1NSigmaPiTPC); - if (isTrk1hasTOF) { - histos.fill(HIST("QAMCTrue/TOF_Nsigma_pi_all"), trk1ptPi, trk1NSigmaPiTOF); - } - histos.fill(HIST("QAMCTrue/TPC_Nsigmaka_all"), trk2ptKa, trk2NSigmaKaTPC); - if (isTrk2hasTOF) { - histos.fill(HIST("QAMCTrue/TOF_Nsigma_ka_all"), trk2ptKa, trk2NSigmaKaTOF); + if (fillPidPlots) { + histos.fill(HIST("QAMCTrue/TPC_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTPC); + if (isTrk1hasTOF) { + histos.fill(HIST("QAMCTrue/TOF_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTOF); + } + histos.fill(HIST("QAMCTrue/TPC_Nsigmaka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTPC); + if (isTrk2hasTOF) { + histos.fill(HIST("QAMCTrue/TOF_Nsigma_ka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTOF); + } } // MC histograms @@ -487,10 +690,12 @@ struct k892analysis { } else if (trk1.sign() * trk2.sign() > 0) { if constexpr (!IsMix) { if (trk1.sign() < 0) { - histos.fill(HIST("k892invmassLS"), lResonance.M()); + if (invmass1D) + histos.fill(HIST("k892invmassLS"), lResonance.M()); histos.fill(HIST("h3k892invmassLS"), multiplicity, lResonance.Pt(), lResonance.M()); } else if (trk1.sign() > 0) { - histos.fill(HIST("k892invmassLSAnti"), lResonance.M()); + if (invmass1D) + histos.fill(HIST("k892invmassLSAnti"), lResonance.M()); histos.fill(HIST("h3k892invmassLSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); } } @@ -498,64 +703,87 @@ struct k892analysis { } } - void processDataLight(aod::ResoCollision& collision, + void processDataLight(aod::ResoCollision const& collision, aod::ResoTracks const& resotracks) { // LOG(info) << "new collision, zvtx: " << collision.posZ(); + if (additionalQAeventPlots) + histos.fill(HIST("QAevent/hEvtCounterSameE"), 1.0); fillHistograms(collision, resotracks, resotracks); } - PROCESS_SWITCH(k892analysis, processDataLight, "Process Event for data", false); + PROCESS_SWITCH(K892analysis, processDataLight, "Process Event for data", false); - void processMCLight(aod::ResoCollision& collision, + void processMCLight(ResoMCCols::iterator const& collision, soa::Join const& resotracks) { + if (!collision.isInAfterAllCuts() || (std::abs(collision.posZ()) > cZvertCutMC)) // MC event selection, all cuts missing vtx cut + return; fillHistograms(collision, resotracks, resotracks); } - PROCESS_SWITCH(k892analysis, processMCLight, "Process Event for MC (Reconstructed)", false); + PROCESS_SWITCH(K892analysis, processMCLight, "Process Event for MC (Reconstructed)", false); - void processMCTrue(aod::ResoCollision& collision, aod::ResoMCParents& resoParents) + void processMCTrue(ResoMCCols::iterator const& collision, aod::ResoMCParents const& resoParents) { auto multiplicity = collision.cent(); - for (auto& part : resoParents) { // loop over all pre-filtered MC particles - if (abs(part.pdgCode()) != 313) // K892(0) + for (const auto& part : resoParents) { // loop over all pre-filtered MC particles + if (std::abs(part.pdgCode()) != 313 || std::abs(part.y()) >= 0.5) continue; - if (abs(part.y()) >= 0.5) { // rapidity cut + bool pass1 = std::abs(part.daughterPDG1()) == 211 || std::abs(part.daughterPDG2()) == 211; + bool pass2 = std::abs(part.daughterPDG1()) == 321 || std::abs(part.daughterPDG2()) == 321; + + if (!pass1 || !pass2) continue; + + if (collision.isVtxIn10()) // INEL10 + { + if (part.pdgCode() > 0) + histos.fill(HIST("k892Gen"), 0, part.pt(), multiplicity); + else + histos.fill(HIST("k892GenAnti"), 0, part.pt(), multiplicity); } - bool pass1 = false; - bool pass2 = false; - if (abs(part.daughterPDG1()) == 321 || abs(part.daughterPDG2()) == 321) { // At least one decay to Kaon - pass2 = true; + if (collision.isVtxIn10() && collision.isInSel8()) // INEL>10, vtx10 + { + if (part.pdgCode() > 0) + histos.fill(HIST("k892Gen"), 1, part.pt(), multiplicity); + else + histos.fill(HIST("k892GenAnti"), 1, part.pt(), multiplicity); } - if (abs(part.daughterPDG1()) == 211 || abs(part.daughterPDG2()) == 211) { // At least one decay to Pion - pass1 = true; + if (collision.isVtxIn10() && collision.isTriggerTVX()) // vtx10, TriggerTVX + { + if (part.pdgCode() > 0) + histos.fill(HIST("k892Gen"), 2, part.pt(), multiplicity); + else + histos.fill(HIST("k892GenAnti"), 2, part.pt(), multiplicity); + } + if (collision.isInAfterAllCuts()) // after all event selection + { + if (part.pdgCode() > 0) + histos.fill(HIST("k892Gen"), 3, part.pt(), multiplicity); + else + histos.fill(HIST("k892GenAnti"), 3, part.pt(), multiplicity); } - if (!pass1 || !pass2) // If we have both decay products - continue; - if (part.pdgCode() > 0) - histos.fill(HIST("k892Gen"), part.pt(), multiplicity); - else - histos.fill(HIST("k892GenAnti"), part.pt(), multiplicity); } } - PROCESS_SWITCH(k892analysis, processMCTrue, "Process Event for MC (Generated)", false); + PROCESS_SWITCH(K892analysis, processMCTrue, "Process Event for MC (Generated)", false); // Processing Event Mixing using BinningTypeVtxZT0M = ColumnBinningPolicy; - void processMELight(o2::aod::ResoCollisions& collisions, aod::ResoTracks const& resotracks) + void processMELight(o2::aod::ResoCollisions const& collisions, aod::ResoTracks const& resotracks) { auto tracksTuple = std::make_tuple(resotracks); - BinningTypeVtxZT0M colBinning{{CfgVtxBins, CfgMultBins}, true}; + BinningTypeVtxZT0M colBinning{{cfgVtxBins, cfgMultBins}, true}; SameKindPair pairs{colBinning, nEvtMixing, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip - for (auto& [collision1, tracks1, collision2, tracks2] : pairs) { + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (additionalQAeventPlots) + histos.fill(HIST("QAevent/hEvtCounterMixedE"), 1.0); fillHistograms(collision1, tracks1, tracks2); } }; - PROCESS_SWITCH(k892analysis, processMELight, "Process EventMixing light without partition", false); + PROCESS_SWITCH(K892analysis, processMELight, "Process EventMixing light without partition", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"lf-k892analysis"})}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/Resonances/k892analysispbpb.cxx b/PWGLF/Tasks/Resonances/k892analysispbpb.cxx new file mode 100644 index 00000000000..303a6cd6fc9 --- /dev/null +++ b/PWGLF/Tasks/Resonances/k892analysispbpb.cxx @@ -0,0 +1,1253 @@ +// 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 k892analysispbpb.cxx +/// \brief K*0 spectra in Pb-Pb +/// \author Marta Urioni + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/TrackSelection.h" +#include "Framework/ASoAHelpers.h" +#include "DataFormatsParameters/GRPObject.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; + +using std::array; +struct K892analysispbpb { + SliceCache cache; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // histos + ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12.0, 12.1, 12.2, 12.3, 12.4, 12.5, 12.6, 12.7, 12.8, 12.9, 13.0, 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7, 13.8, 13.9, 14.0, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15.0}, "Binning of the pT axis"}; + ConfigurableAxis binsPtQA{"binsPtQA", {VARIABLE_WIDTH, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2, 6.4, 6.6, 6.8, 7.0, 7.2, 7.4, 7.6, 7.8, 8.0, 8.2, 8.4, 8.6, 8.8, 9.0, 9.2, 9.4, 9.6, 9.8, 10.0}, "Binning of the pT axis"}; + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0}, "Binning of the centrality axis"}; + + Configurable cInvMassStart{"cInvMassStart", 0.6, "Invariant mass start"}; + Configurable cInvMassEnd{"cInvMassEnd", 1.5, "Invariant mass end"}; + Configurable cInvMassBins{"cInvMassBins", 900, "Invariant mass binning"}; + Configurable cPIDBins{"cPIDBins", 65, "PID binning"}; + Configurable cPIDQALimit{"cPIDQALimit", 6.5, "PID QA limit"}; + Configurable cDCABins{"cDCABins", 300, "DCA binning"}; + Configurable cPDGbins{"cPDGbins", 5000, "number of PDG bins"}; + Configurable cPDGMax{"cPDGMax", 9500000.0f, "PDG limit"}; + + // events + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable timFrameEvsel{"timFrameEvsel", false, "TPC Time frame boundary cut"}; + Configurable additionalEvSel2{"additionalEvSel2", true, "NoSameBunchPileUp and IsGoodZvtxFT0vsPV"}; + Configurable additionalEvSel3{"additionalEvSel3", false, "Additional evsel3"}; + + // presel + Configurable cfgCutCentrality{"cfgCutCentrality", 80.0f, "Accepted maximum Centrality"}; + Configurable cfgCutMaxOccupancy{"cfgCutMaxOccupancy", 2000.0f, "Accepted maximum Occupancy"}; + Configurable cfgApplyOccupancyCut{"cfgApplyOccupancyCut", false, "Apply maximum Occupancy"}; + + // Track selections + Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 0, "Number of TPC cluster"}; + Configurable cfgRatioTPCRowsOverFindableCls{"cfgRatioTPCRowsOverFindableCls", 0.0f, "TPC Crossed Rows to Findable Clusters"}; + + Configurable cfgIsPhysicalPrimary{"cfgIsPhysicalPrimary", true, "Primary track selection in MC"}; // for MC bkg study + + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) + Configurable cfgGlobalTrack{"cfgGlobalTrack", false, "Global track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgPVContributor{"cfgPVContributor", false, "PV contributor track selection"}; // PV Contriuibutor + Configurable cfgUseITSTPCrefit{"cfgUseITSTPCrefit", true, "Use ITS and TPC refit"}; + Configurable cfgITSChi2Ncl{"cfgITSChi2Ncl", 999.0, "ITS Chi2/NCl"}; + Configurable cfgTPCChi2Ncl{"cfgTPCChi2Ncl", 999.0, "TPC Chi2/NCl"}; + + Configurable cfgCutPT{"cfgCutPT", 0.2, "PT cut on daughter track"}; + Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; + Configurable cfgCutDCAxy{"cfgCutDCAxy", 2.0f, "DCAxy range for tracks"}; + Configurable cfgCutDCAz{"cfgCutDCAz", 2.0f, "DCAz range for tracks"}; + Configurable cMaxTPCnSigmaKaon{"cMaxTPCnSigmaKaon", 3.0, "TPC nSigma cut for Kaon"}; // TPC + Configurable cMaxTOFnSigmaKaon{"cMaxTOFnSigmaKaon", 3.0, "TOF nSigma cut for Kaon"}; // TOF + Configurable cMaxTPCnSigmaPion{"cMaxTPCnSigmaPion", 3.0, "TPC nSigma cut for Pion"}; // TPC + Configurable cMaxTOFnSigmaPion{"cMaxTOFnSigmaPion", 3.0, "TOF nSigma cut for Pion"}; // TOF + Configurable cByPassTOF{"cByPassTOF", false, "By pass TOF PID selection"}; // By pass TOF PID selection + Configurable cTofBetaCut{"cTofBetaCut", false, "selection on TOF beta"}; + + Configurable cTPClowpt{"cTPClowpt", true, "apply TPC at low pt"}; + Configurable cTOFonlyHighpt{"cTOFonlyHighpt", false, "apply TOF only at high pt"}; + Configurable cTOFandTPCHighpt{"cTOFandTPCHighpt", false, "apply TOF and TPC at high pt"}; + + // rotational bkg + Configurable cfgNoRotations{"cfgNoRotations", 3, "Number of rotations per pair for rotbkg"}; + Configurable rotationalCut{"rotationalCut", 10, "Cut value (Rotation angle pi - pi/cut and pi + pi/cut)"}; + Configurable cfgRotPi{"cfgRotPi", true, "rotate Pion"}; + + // event mixing + Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 5, "Number of mixed events per event"}; + + ConfigurableAxis cfgVtxBins{"cfgVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis cfgMultBins{"cfgMultBins", {VARIABLE_WIDTH, 0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f}, "Mixing bins - z-vertex"}; + ConfigurableAxis binsImpactPar{"binsImpactPar", {VARIABLE_WIDTH, 0.0, 3.00065, 4.28798, 6.14552, 7.6196, 8.90942, 10.0897, 11.2002, 12.2709, 13.3167, 14.4173, 23.2518}, "Binning of the impact parameter axis"}; + + // cuts on mother + Configurable cfgCutsOnMother{"cfgCutsOnMother", false, "Enamble additional cuts on mother"}; + Configurable cMaxPtMotherCut{"cMaxPtMotherCut", 15.0, "Maximum pt of mother cut"}; + Configurable cMaxMinvMotherCut{"cMaxMinvMotherCut", 1.5, "Maximum Minv of mother cut"}; + + // configurables for partitions + Configurable cMaxPtTPC{"cMaxPtTPC", 1.2, "maximum pt to apply TPC PID and TOF if available"}; + Configurable cMinPtTOF{"cMinPtTOF", 0.8, "minimum pt to require TOF PID in addition to TPC"}; + + // plots + Configurable additionalQAplots{"additionalQAplots", true, "Additional QA plots"}; + Configurable additionalQAeventPlots{"additionalQAeventPlots", false, "Additional QA event plots"}; + Configurable additionalMEPlots{"additionalMEPlots", false, "Additional Mixed event plots"}; + + // MC + Configurable avoidsplitrackMC{"avoidsplitrackMC", false, "avoid split track in MC"}; + + TRandom* rand = new TRandom(); + + void init(o2::framework::InitContext&) + { + AxisSpec centAxis = {binsCent, "V0M (%)"}; + AxisSpec dcaxyAxis = {cDCABins, 0.0, 3.0, "DCA_{#it{xy}} (cm)"}; + AxisSpec dcazAxis = {cDCABins, 0.0, 3.0, "DCA_{#it{z}} (cm)"}; + AxisSpec mcLabelAxis = {5, -0.5, 4.5, "MC Label"}; + AxisSpec ptAxis = {binsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptAxisQA = {binsPtQA, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptAxisMom = {binsPt, "Mom #it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptAxisDau = {binsPtQA, "Dau #it{p}_{T} (GeV/#it{c})"}; + AxisSpec invMassAxis = {cInvMassBins, cInvMassStart, cInvMassEnd, "Invariant Mass (GeV/#it{c}^2)"}; + AxisSpec pidQAAxis = {cPIDBins, -cPIDQALimit, cPIDQALimit}; + AxisSpec pdgCodeAxis = {cPDGbins, 0, cPDGMax}; + AxisSpec impactParAxis = {binsImpactPar, "Impact Parameter"}; + + if ((!doprocessMC && !doprocessMCRun2) || doprocessMixedEventMC || doprocessMixedEventMCRun2) { + // event histograms + histos.add("QAevent/hEvtCounterSameE", "Number of analyzed Same Events", HistType::kTH1F, {{1, 0.5, 1.5}}); + histos.add("QAevent/hMultiplicityPercentSameE", "Multiplicity percentile of collision", HistType::kTH1F, {{120, 0.0f, 120.0f}}); + histos.add("QAevent/hVertexZSameE", "Collision Vertex Z position", HistType::kTH1F, {{100, -15., 15.}}); + + if (additionalQAeventPlots) { + // Test on Mixed event + histos.add("TestME/hCollisionIndexSameE", "coll index sameE", HistType::kTH1F, {{500, 0.0f, 500.0f}}); + histos.add("TestME/hCollisionIndexMixedE", "coll index mixedE", HistType::kTH1F, {{500, 0.0f, 500.0f}}); + histos.add("TestME/hnTrksSameE", "n tracks per event SameE", HistType::kTH1F, {{1000, 0.0f, 1000.0f}}); + histos.add("TestME/hnTrksMixedE", "n tracks per event MixedE", HistType::kTH1F, {{1000, 0.0f, 1000.0f}}); + histos.add("TestME/hPairsCounterSameE", "tot n pairs sameE", HistType::kTH1F, {{1, 0.5f, 1.5f}}); + histos.add("TestME/hPairsCounterMixedE", "tot n pairs mixedE", HistType::kTH1F, {{1, 0.5f, 1.5f}}); + + // event histograms + histos.add("QAevent/hEvtCounterMixedE", "Number of analyzed Mixed Events", HistType::kTH1F, {{1, 0.5, 1.5}}); + histos.add("QAevent/hVertexZMixedE", "Collision Vertex Z position", HistType::kTH1F, {{100, -15., 15.}}); + histos.add("QAevent/hMultiplicityPercentMixedE", "Multiplicity percentile of collision", HistType::kTH1F, {{120, 0.0f, 120.0f}}); + } + } + + // Mass QA (quick check) + histos.add("k892invmassDS", "Invariant mass of K(892)0 different sign", kTH1F, {invMassAxis}); + histos.add("k892invmassDSAnti", "Invariant mass of Anti-K(892)0 different sign", kTH1F, {invMassAxis}); + histos.add("k892invmassLS", "Invariant mass of K(892)0 like sign", kTH1F, {invMassAxis}); + histos.add("k892invmassLSAnti", "Invariant mass of Anti-K(892)0 like sign", kTH1F, {invMassAxis}); + if (doprocessMixedEvent || doprocessMixedEventRun2 || doprocessMixedEventMC || doprocessMixedEventMCRun2) { + histos.add("k892invmassME", "Invariant mass of K(892)0 mixed event", kTH1F, {invMassAxis}); + if (additionalMEPlots) { + histos.add("k892invmassME_DS", "Invariant mass of K(892)0 mixed event DS", kTH1F, {invMassAxis}); + histos.add("k892invmassME_DSAnti", "Invariant mass of K(892)0 mixed event DSAnti", kTH1F, {invMassAxis}); + } + } + + if (additionalQAplots) { + // TPC ncluster distirbutions + histos.add("Ncluster/TPCnclusterpi", "TPC ncluster distribution", kTH1F, {{160, 0, 160, "TPC nCluster"}}); + histos.add("Ncluster/TPCnclusterka", "TPC ncluster distribution", kTH1F, {{160, 0, 160, "TPC nCluster"}}); + histos.add("Ncluster/TPCnclusterPhipi", "TPC ncluster vs phi", kTH2F, {{160, 0, 160, "TPC nCluster"}, {63, 0, 6.28, "#phi"}}); + histos.add("Ncluster/TPCnclusterPhika", "TPC ncluster vs phi", kTH2F, {{160, 0, 160, "TPC nCluster"}, {63, 0, 6.28, "#phi"}}); + + histos.add("Ncluster/TPCChi2ncluster", "TPC Chi2ncluster distribution", kTH1F, {{100, 0, 10, "TPC Chi2nCluster"}}); + histos.add("Ncluster/ITSChi2ncluster", "ITS Chi2ncluster distribution", kTH1F, {{100, 0, 40, "ITS Chi2nCluster"}}); + histos.add("Ncluster/ITSncluster", "ITS ncluster distribution", kTH1F, {{10, 0, 10, "ITS nCluster"}}); + + histos.add("QA/h2k892ptMothervsptPiDS", "Pt of K(892)0 differnt sign vs pt pion daughter", kTH2F, {ptAxisMom, ptAxisDau}); + histos.add("QA/h2k892ptMothervsptPiDSAnti", "Pt of Anti-K(892)0 differnt sign vs pt pion daughter", kTH2F, {ptAxisMom, ptAxisDau}); + histos.add("QA/h2k892ptMothervsptKaDS", "Pt of K(892)0 differnt sign vs pt kaon daughter", kTH2F, {ptAxisMom, ptAxisDau}); + histos.add("QA/h2k892ptMothervsptKaDSAnti", "Pt of Anti-K(892)0 differnt sign vs pt kaon daughter", kTH2F, {ptAxisMom, ptAxisDau}); + + histos.add("QAME/h2k892ptMothervsptPiDS", "Pt of Mother vs pt pion daughter, Mixed Event", kTH2F, {ptAxisMom, ptAxisDau}); + histos.add("QAME/h2k892ptMothervsptPiDSAnti", "Pt of Anti-Mother vs pt pion daughter, Mixed Event", kTH2F, {ptAxisMom, ptAxisDau}); + histos.add("QAME/h2k892ptMothervsptKaDS", "Pt of Mother vs pt kaon daughter, Mixed Event", kTH2F, {ptAxisMom, ptAxisDau}); + histos.add("QAME/h2k892ptMothervsptKaDSAnti", "Pt of Anti-Mother vs pt pion daughter, Mixed Event", kTH2F, {ptAxisMom, ptAxisDau}); + } + + // DCA QA + histos.add("QA/trkDCAxy_pi", "DCAxy distribution of pion track candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QA/trkDCAxy_ka", "DCAxy distribution of kaon track candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QA/trkDCAz_pi", "DCAz distribution of pion track candidates", HistType::kTH1F, {dcazAxis}); + histos.add("QA/trkDCAz_ka", "DCAz distribution of kaon track candidates", HistType::kTH1F, {dcazAxis}); + // pT QA + histos.add("QA/trkpT_pi", "pT distribution of pion track candidates", kTH1F, {ptAxis}); + histos.add("QA/trkpT_ka", "pT distribution of kaon track candidates", kTH1F, {ptAxis}); + // PID QA + histos.add("QA/TOF_TPC_Map_pi_all", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QA/TOF_Nsigma_pi_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QA/TPC_Nsigma_pi_all", "TPC NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QA/TOF_TPC_Mapka_all", "TOF + TPC Combined PID for Kaon;#sigma_{TOF}^{Kaon};#sigma_{TPC}^{Kaon}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QA/TOF_Nsigma_ka_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QA/TPC_Nsigmaka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + + // inv mass histograms + histos.add("h3k892invmassDS", "Invariant mass of K(892)0 differnt sign", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassDSAnti", "Invariant mass of Anti-K(892)0 differnt sign", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassLS", "Invariant mass of K(892)0 same sign", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassLSAnti", "Invariant mass of Anti-K(892)0 same sign", kTH3F, {centAxis, ptAxis, invMassAxis}); + + if (doprocessRotationalBkg || doprocessRotationalBkgMC) { + histos.add("k892invmassRotDS", "Invariant mass of K(892)0 RotBkg", kTH1F, {invMassAxis}); + histos.add("k892invmassRotDSAnti", "Invariant mass of Anti-K(892)0 RotBkg", kTH1F, {invMassAxis}); + + histos.add("h3k892invmassRotDS", "Invariant mass of K(892)0 Rotational Bkg", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassRotDSAnti", "Invariant mass of Anti-K(892)0 Rotational Bkg", kTH3F, {centAxis, ptAxis, invMassAxis}); + } + + if (doprocessMixedEvent || doprocessMixedEventRun2 || doprocessMixedEventMC || doprocessMixedEventMCRun2) { + histos.add("h3k892invmassME", "Invariant mass of K(892)0 mixed event", kTH3F, {centAxis, ptAxis, invMassAxis}); + + if (additionalMEPlots) { + histos.add("QAME/TOF_TPC_Map_pi_all", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAME/TOF_Nsigma_pi_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAME/TPC_Nsigma_pi_all", "TPC NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAME/TOF_TPC_Mapka_all", "TOF + TPC Combined PID for Kaon;#sigma_{TOF}^{Kaon};#sigma_{TPC}^{Kaon}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAME/TOF_Nsigma_ka_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAME/TPC_Nsigmaka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + + histos.add("h3k892invmassME_DS", "Invariant mass of K(892)0 mixed event DS", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassME_DSAnti", "Invariant mass of K(892)0 mixed event DSAnti", kTH3F, {centAxis, ptAxis, invMassAxis}); + } + } + + if (doprocessMixedEventMC || doprocessMixedEventMCRun2) { + histos.add("h3k892invmassWrongDaughtersME_DS", "Invariant mass ME with wrong daughters DS", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassWrongDaughtersME_DSAnti", "Invariant mass ME with wrong daughters DS anti", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassRightDaughtersME_DS", "Invariant mass ME with right daughters DS", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassRightDaughtersME_DSAnti", "Invariant mass ME with right daughters DS anti", kTH3F, {centAxis, ptAxis, invMassAxis}); + } + + if (doprocessMC || doprocessMCRun2) { + histos.add("QAevent/hMCrecCollSels", "MC Event statistics", HistType::kTH1F, {{10, 0.0f, 10.0f}}); + histos.add("QAevent/hMultiplicityPercentMC", "Multiplicity percentile of MCrec collision", HistType::kTH1F, {{120, 0.0f, 120.0f}}); + + histos.add("h1k892Recsplit", "k892 Rec split", HistType::kTH1F, {{200, 0.0f, 20.0f}}); + // MC QA + histos.add("QAMCTrue/hGlobalIndexMotherRec", "index of rec mothers", HistType::kTH1F, {{static_cast(1e5), 0.0f, 1e5f}}); + histos.add("QAMCTrue/hGlobalIndexMotherGen", "index of gen mothers", HistType::kTH1F, {{static_cast(1e5), 0.0f, 1e5f}}); + histos.add("QAMCTrue/TOF_Nsigma_pi_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAMCTrue/TPC_Nsigma_pi_all", "TPC NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAMCTrue/TOF_Nsigma_ka_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAMCTrue/TPC_Nsigmaka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + + histos.add("k892Recinvmass", "Inv mass distribution of Reconstructed MC K(892)", kTH1F, {invMassAxis}); + histos.add("k892RecinvmassAnti", "Inv mass distribution of Reconstructed MC AntiK(892)", kTH1F, {invMassAxis}); + histos.add("k892GenInvmass", "Invariant mass of generated K(892)0", kTH1F, {invMassAxis}); + histos.add("k892GenInvmassAnti", "Invariant mass of generated Anti-K(892)0", kTH1F, {invMassAxis}); + + histos.add("h3Reck892invmass", "Invariant mass of Reconstructed MC K(892)0", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3Reck892invmassAnti", "Invariant mass of Reconstructed MC Anti-K(892)0", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("k892Gen", "pT distribution of True MC K(892)0", kTH3F, {mcLabelAxis, ptAxis, centAxis}); + histos.add("k892GenAnti", "pT distribution of True MC Anti-K(892)0", kTH3F, {mcLabelAxis, ptAxis, centAxis}); + histos.add("k892Rec", "pT distribution of Reconstructed MC K(892)0", kTH2F, {ptAxis, centAxis}); + histos.add("k892RecAnti", "pT distribution of Reconstructed MC Anti-K(892)0", kTH2F, {ptAxis, centAxis}); + histos.add("h3k892GenInvmass", "Invariant mass of generated K(892)0", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892GenInvmassAnti", "Invariant mass of generated Anti-K(892)0", kTH3F, {centAxis, ptAxis, invMassAxis}); + + histos.add("h3Reck892invmassPtGen", "Invariant mass of Reconstructed MC K(892)0 with Pt Gen", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3Reck892invmassAntiPtGen", "Invariant mass of Reconstructed MC Anti-K(892)0 with Pt Gen", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3PtRecvsPtGenAnti", "reconstructed K* Pt vs generated K* pt", kTH3F, {centAxis, ptAxis, ptAxis}); + histos.add("h3PtRecvsPtGen", "reconstructed Anti-K* Pt vs generated Anti-K* pt", kTH3F, {centAxis, ptAxis, ptAxis}); + + histos.add("h3k892invmassWrongDaughters_DS", "Invariant mass of K*0 with wrong daughters DS", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassWrongDaughters_DSAnti", "Invariant mass of K*0 with wrong daughters DS anti", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassRightDaughters_DS", "Invariant mass of K*0 with right daughters DS", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassRightDaughters_DSAnti", "Invariant mass of K*0 with right daughters DS anti", kTH3F, {centAxis, ptAxis, invMassAxis}); + + histos.add("h3k892invmassSameMother_DS", "Invariant mass same mother DS", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassSameMother_DSAnti", "Invariant mass same mother DS anti", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3PdgCodeSameMother_DS", "PDG code same mother DS", kTH3F, {centAxis, ptAxis, pdgCodeAxis}); + histos.add("h3PdgCodeSameMother_DSAnti", "PDG code same mother DS anti", kTH3F, {centAxis, ptAxis, pdgCodeAxis}); + } + + if (doprocessEvtLossSigLossMC) { + histos.add("QAevent/hImpactParameterGen", "Impact parameter of generated MC events", kTH1F, {impactParAxis}); + histos.add("QAevent/hImpactParameterRec", "Impact parameter of selected MC events", kTH1F, {impactParAxis}); + histos.add("QAevent/hImpactParvsCentrRec", "Impact parameter of selected MC events vs centrality", kTH2F, {{120, 0.0f, 120.0f}, impactParAxis}); + histos.add("QAevent/k892genBeforeEvtSel", "K* before event selections", kTH2F, {ptAxis, impactParAxis}); + histos.add("QAevent/k892genBeforeEvtSelAnti", "K* before event selections", kTH2F, {ptAxis, impactParAxis}); + histos.add("QAevent/k892genAfterEvtSel", "K* after event selections", kTH2F, {ptAxis, impactParAxis}); + histos.add("QAevent/k892genAfterEvtSelAnti", "K* after event selections", kTH2F, {ptAxis, impactParAxis}); + } + + // Print output histograms statistics + LOG(info) << "Size of the histograms in spectraTOF"; + histos.print(); + } + + double massKa = o2::constants::physics::MassKPlus; + double massPi = o2::constants::physics::MassPiPlus; + + template + bool myEventSelections(const CollType& coll) + { + if (!coll.sel8()) + return false; + if (std::abs(coll.posZ()) > cfgCutVertex) + return false; + if (timFrameEvsel && (!coll.selection_bit(aod::evsel::kNoTimeFrameBorder) || !coll.selection_bit(aod::evsel::kNoITSROFrameBorder))) + return false; + if (additionalEvSel2 && (!coll.selection_bit(aod::evsel::kNoSameBunchPileup) || !coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) + return false; + if (additionalEvSel3 && (!coll.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) + return false; + auto centrality = coll.centFT0C(); + if (centrality > cfgCutCentrality) + return false; + auto occupancy = coll.trackOccupancyInTimeRange(); + if (cfgApplyOccupancyCut && (occupancy > cfgCutMaxOccupancy)) + return false; + + return true; + } + + template + bool myEventSelectionsRun2(const CollType& coll, const bcType&) + { + auto bc = coll.template bc_as(); + if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kAliEventCutsAccepted))) + return false; + if (std::abs(coll.posZ()) > cfgCutVertex) + return false; + auto centrality = coll.centRun2V0M(); + if (centrality > cfgCutCentrality) + return false; + + return true; + } + + template + bool trackCut(const TrackType& track) + { + // basic track cuts + if (track.itsNCls() < cfgITScluster) + return false; + if (track.tpcNClsFound() < cfgTPCcluster) + return false; + if (track.itsChi2NCl() > cfgITSChi2Ncl) + return false; + if (track.tpcChi2NCl() > cfgTPCChi2Ncl) + return false; + if (track.tpcCrossedRowsOverFindableCls() < cfgRatioTPCRowsOverFindableCls) + return false; + if (cfgPVContributor && !track.isPVContributor()) + return false; + if (cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (cfgGlobalTrack && !track.isGlobalTrack()) + return false; + if (cfgUseITSTPCrefit && (!(o2::aod::track::ITSrefit) || !(o2::aod::track::TPCrefit))) + return false; + + return true; + } + + template + bool selectionPIDKaon(const T& candidate) + { + if (cTOFonlyHighpt) { + + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) <= cMaxTOFnSigmaKaon) { // tof cut only + return true; + } + + } else if (cTOFandTPCHighpt) { + + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) <= cMaxTOFnSigmaKaon && candidate.hasTPC() && std::abs(candidate.tpcNSigmaKa()) <= cMaxTPCnSigmaKaon) { // tof and tpc cut + return true; + } + + } else { + + if (candidate.hasTPC() && std::abs(candidate.tpcNSigmaKa()) <= cMaxTPCnSigmaKaon) { // tpc cut, tof when available + + if (cTofBetaCut && candidate.hasTOF() && (candidate.beta() + 3 * candidate.betaerror() > 1)) + return false; + + if (cByPassTOF) // skip tof selection + return true; + + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaKa()) <= cMaxTOFnSigmaKaon) { + return true; + } + } else { + return true; + } + } + } + + return false; + } + + template + bool selectionPIDPion(const T& candidate) + { + if (cTOFonlyHighpt) { + + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) <= cMaxTOFnSigmaPion) { // tof cut only + return true; + } + + } else if (cTOFandTPCHighpt) { + + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) <= cMaxTOFnSigmaPion && candidate.hasTPC() && std::abs(candidate.tpcNSigmaPi()) <= cMaxTPCnSigmaPion) { // tof and tpc cut + return true; + } + + } else { + + if (candidate.hasTPC() && std::abs(candidate.tpcNSigmaPi()) <= cMaxTPCnSigmaPion) { // tpc cut, tof when available + + if (cTofBetaCut && candidate.hasTOF() && (candidate.beta() + 3 * candidate.betaerror() > 1)) + return false; + + if (cByPassTOF) // skip tof selection + return true; + + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaPi()) <= cMaxTOFnSigmaPion) { + return true; + } + } else { + return true; + } + } + } + + return false; + } + + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksType& dTracks2) + { + + auto multiplicity = -999; + + if constexpr (!IsRun2) + multiplicity = collision.centFT0C(); + else + multiplicity = collision.centRun2V0M(); + + auto oldindex = -999; + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance, ldaughterRot, lResonanceRot; + for (const auto& [trk1, trk2] : combinations(CombinationsFullIndexPolicy(dTracks1, dTracks2))) { + // Full index policy is needed to consider all possible combinations + if (trk1.index() == trk2.index()) + continue; // We need to run (0,1), (1,0) pairs as well. but same id pairs are not needed. + + if (additionalQAeventPlots) { + if constexpr (!IsMC && !IsRot) { + if constexpr (!IsMix) { + histos.fill(HIST("TestME/hPairsCounterSameE"), 1.0); + } else { + histos.fill(HIST("TestME/hPairsCounterMixedE"), 1.0); + } + } + } + + //// Initialize variables + // Trk1: Pion, Trk2: Kaon + // apply the track cut + if (!trackCut(trk1) || !trackCut(trk2)) + continue; + + auto isTrk1hasTOF = trk1.hasTOF(); + auto isTrk2hasTOF = trk2.hasTOF(); + auto trk1ptPi = trk1.pt(); + auto trk1NSigmaPiTPC = trk1.tpcNSigmaPi(); + auto trk1NSigmaPiTOF = (isTrk1hasTOF) ? trk1.tofNSigmaPi() : -999.; + auto trk2ptKa = trk2.pt(); + auto trk2NSigmaKaTPC = trk2.tpcNSigmaKa(); + auto trk2NSigmaKaTOF = (isTrk2hasTOF) ? trk2.tofNSigmaKa() : -999.; + + if (!selectionPIDPion(trk1) || !selectionPIDKaon(trk2)) + continue; + + if constexpr (IsMC) { + if (cTPClowpt) { + if (trk1ptPi >= cMaxPtTPC || trk2ptKa >= cMaxPtTPC) + continue; + } else if (cTOFonlyHighpt || cTOFandTPCHighpt) { + if (trk1ptPi <= cMinPtTOF || trk2ptKa <= cMinPtTOF) + continue; + } + } + + if (additionalQAplots && !IsMix && !IsRot) { + // TPCncluster distributions + histos.fill(HIST("Ncluster/TPCnclusterpi"), trk1.tpcNClsFound()); + histos.fill(HIST("Ncluster/TPCnclusterka"), trk2.tpcNClsFound()); + histos.fill(HIST("Ncluster/TPCnclusterPhipi"), trk1.tpcNClsFound(), trk1.phi()); + histos.fill(HIST("Ncluster/TPCnclusterPhika"), trk2.tpcNClsFound(), trk2.phi()); + histos.fill(HIST("Ncluster/TPCChi2ncluster"), trk1.tpcChi2NCl()); + histos.fill(HIST("Ncluster/ITSChi2ncluster"), trk1.itsChi2NCl()); + histos.fill(HIST("Ncluster/ITSncluster"), trk1.itsNCls()); + } + + if constexpr (!IsMix && !IsRot) { + //// QA plots after the selection + // --- PID QA Pion + histos.fill(HIST("QA/TPC_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTPC); + if (isTrk1hasTOF) { + histos.fill(HIST("QA/TOF_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTOF); + histos.fill(HIST("QA/TOF_TPC_Map_pi_all"), trk1NSigmaPiTOF, trk1NSigmaPiTPC); + } + // --- PID QA Kaon + histos.fill(HIST("QA/TPC_Nsigmaka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTPC); + if (isTrk2hasTOF) { + histos.fill(HIST("QA/TOF_Nsigma_ka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTOF); + histos.fill(HIST("QA/TOF_TPC_Mapka_all"), trk2NSigmaKaTOF, trk2NSigmaKaTPC); + } + histos.fill(HIST("QA/trkpT_pi"), trk1ptPi); + histos.fill(HIST("QA/trkpT_ka"), trk2ptKa); + histos.fill(HIST("QA/trkDCAxy_pi"), trk1.dcaXY()); + histos.fill(HIST("QA/trkDCAxy_ka"), trk2.dcaXY()); + histos.fill(HIST("QA/trkDCAz_pi"), trk1.dcaZ()); + histos.fill(HIST("QA/trkDCAz_ka"), trk2.dcaZ()); + } else if (IsMix && additionalMEPlots) { + // --- PID QA Pion + histos.fill(HIST("QAME/TPC_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTPC); + if (isTrk1hasTOF) { + histos.fill(HIST("QAME/TOF_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTOF); + histos.fill(HIST("QAME/TOF_TPC_Map_pi_all"), trk1NSigmaPiTOF, trk1NSigmaPiTPC); + } + // --- PID QA Kaon + histos.fill(HIST("QAME/TPC_Nsigmaka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTPC); + if (isTrk2hasTOF) { + histos.fill(HIST("QAME/TOF_Nsigma_ka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTOF); + histos.fill(HIST("QAME/TOF_TPC_Mapka_all"), trk2NSigmaKaTOF, trk2NSigmaKaTPC); + } + } + + int track1Sign = trk1.sign(); + int track2Sign = trk2.sign(); + + //// Resonance reconstruction + lDecayDaughter1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massPi); + lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massKa); + lResonance = lDecayDaughter1 + lDecayDaughter2; + // Rapidity cut + if (std::abs(lResonance.Rapidity()) >= 0.5) + continue; + if (cfgCutsOnMother && !IsRot) { + if (lResonance.Pt() >= cMaxPtMotherCut) // excluding candidates in overflow + continue; + if (lResonance.M() >= cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } + + //// Un-like sign pair only + if (track1Sign * track2Sign < 0) { + if constexpr (IsRot) { // rotational background + for (int i = 0; i < cfgNoRotations; i++) { + float theta = rand->Uniform(o2::constants::math::PI - o2::constants::math::PI / rotationalCut, o2::constants::math::PI + o2::constants::math::PI / rotationalCut); + if (cfgRotPi) { + ldaughterRot.SetPtEtaPhiM(trk1.pt(), trk1.eta(), trk1.phi() + theta, massPi); + lResonanceRot = lDecayDaughter2 + ldaughterRot; + } else { + ldaughterRot.SetPtEtaPhiM(trk2.pt(), trk2.eta(), trk2.phi() + theta, massKa); + lResonanceRot = lDecayDaughter1 + ldaughterRot; + } + if (std::abs(lResonanceRot.Rapidity()) >= 0.5) + continue; + if (cfgCutsOnMother) { + if (lResonanceRot.Pt() >= cMaxPtMotherCut) // excluding candidates in overflow + continue; + if (lResonanceRot.M() >= cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } + + if (track1Sign < 0) { + histos.fill(HIST("k892invmassRotDS"), lResonanceRot.M()); + histos.fill(HIST("h3k892invmassRotDS"), multiplicity, lResonanceRot.Pt(), lResonanceRot.M()); + } else if (track1Sign > 0) { + histos.fill(HIST("k892invmassRotDSAnti"), lResonance.M()); + histos.fill(HIST("h3k892invmassRotDSAnti"), multiplicity, lResonanceRot.Pt(), lResonanceRot.M()); + } + } + + } else if constexpr (!IsMix) { // same event + if (track1Sign < 0) { + histos.fill(HIST("k892invmassDS"), lResonance.M()); + histos.fill(HIST("h3k892invmassDS"), multiplicity, lResonance.Pt(), lResonance.M()); + if (additionalQAplots) { + histos.fill(HIST("QA/h2k892ptMothervsptPiDS"), lResonance.Pt(), lDecayDaughter1.Pt()); + histos.fill(HIST("QA/h2k892ptMothervsptKaDS"), lResonance.Pt(), lDecayDaughter2.Pt()); + } + } else if (track1Sign > 0) { + histos.fill(HIST("k892invmassDSAnti"), lResonance.M()); + histos.fill(HIST("h3k892invmassDSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + if (additionalQAplots) { + histos.fill(HIST("QA/h2k892ptMothervsptPiDSAnti"), lResonance.Pt(), lDecayDaughter1.Pt()); + histos.fill(HIST("QA/h2k892ptMothervsptKaDSAnti"), lResonance.Pt(), lDecayDaughter2.Pt()); + } + } + + } else { // mixed event + histos.fill(HIST("k892invmassME"), lResonance.M()); + histos.fill(HIST("h3k892invmassME"), multiplicity, lResonance.Pt(), lResonance.M()); + if (additionalMEPlots) { + if (track1Sign < 0) { + histos.fill(HIST("k892invmassME_DS"), lResonance.M()); + histos.fill(HIST("h3k892invmassME_DS"), multiplicity, lResonance.Pt(), lResonance.M()); + if (additionalQAplots) { + histos.fill(HIST("QAME/h2k892ptMothervsptPiDS"), lResonance.Pt(), lDecayDaughter1.Pt()); + histos.fill(HIST("QAME/h2k892ptMothervsptKaDS"), lResonance.Pt(), lDecayDaughter2.Pt()); + } + } else if (track1Sign > 0) { + histos.fill(HIST("k892invmassME_DSAnti"), lResonance.M()); + histos.fill(HIST("h3k892invmassME_DSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + if (additionalQAplots) { + histos.fill(HIST("QAME/h2k892ptMothervsptPiDSAnti"), lResonance.Pt(), lDecayDaughter1.Pt()); + histos.fill(HIST("QAME/h2k892ptMothervsptKaDSAnti"), lResonance.Pt(), lDecayDaughter2.Pt()); + } + } + } + } + + // MC + if constexpr (IsMC && !IsRot) { + + if (!trk1.has_mcParticle() || !trk2.has_mcParticle()) + continue; + + const auto mctrack1 = trk1.mcParticle(); + const auto mctrack2 = trk2.mcParticle(); + int track1PDG = std::abs(mctrack1.pdgCode()); + int track2PDG = std::abs(mctrack2.pdgCode()); + + if (cfgIsPhysicalPrimary && (!mctrack1.isPhysicalPrimary() || !mctrack2.isPhysicalPrimary())) + continue; + + if (track1PDG != 211 || track2PDG != 321) { + + if (track1Sign < 0) { + if constexpr (IsMix) + histos.fill(HIST("h3k892invmassWrongDaughtersME_DS"), multiplicity, lResonance.Pt(), lResonance.M()); + else + histos.fill(HIST("h3k892invmassWrongDaughters_DS"), multiplicity, lResonance.Pt(), lResonance.M()); + } else if (track1Sign > 0) { + if constexpr (IsMix) + histos.fill(HIST("h3k892invmassWrongDaughtersME_DSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + else + histos.fill(HIST("h3k892invmassWrongDaughters_DSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + } + + continue; + } + + if (track1Sign < 0) { + if constexpr (IsMix) + histos.fill(HIST("h3k892invmassRightDaughtersME_DS"), multiplicity, lResonance.Pt(), lResonance.M()); + else + histos.fill(HIST("h3k892invmassRightDaughters_DS"), multiplicity, lResonance.Pt(), lResonance.M()); + } else if (track1Sign > 0) { + if constexpr (IsMix) + histos.fill(HIST("h3k892invmassRightDaughtersME_DSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + else + histos.fill(HIST("h3k892invmassRightDaughters_DSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + } + + if constexpr (!IsMix) { + + bool isSameMother = false; + bool isMotherOk = false; + int pdgCodeMother = -999; + float ptMother = -9999.; + for (const auto& mothertrack1 : mctrack1.template mothers_as()) { + for (const auto& mothertrack2 : mctrack2.template mothers_as()) { + if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) + continue; + if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) + continue; + + if (std::abs(mothertrack1.pdgCode()) == 1000822080) // Pb PDG code + continue; + + pdgCodeMother = mothertrack1.pdgCode(); + ptMother = mothertrack1.pt(); + isSameMother = true; + + if (std::abs(mothertrack1.pdgCode()) != 313) + continue; + + if (avoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { + histos.fill(HIST("h1k892Recsplit"), mothertrack1.pt()); + continue; + } + oldindex = mothertrack1.globalIndex(); + isMotherOk = true; + } + } + + if (isSameMother) { + if (track1Sign < 0) { + histos.fill(HIST("h3k892invmassSameMother_DS"), multiplicity, lResonance.Pt(), lResonance.M()); + histos.fill(HIST("h3PdgCodeSameMother_DS"), multiplicity, lResonance.Pt(), pdgCodeMother); + } else if (track1Sign > 0) { + histos.fill(HIST("h3k892invmassSameMother_DSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + histos.fill(HIST("h3PdgCodeSameMother_DSAnti"), multiplicity, lResonance.Pt(), pdgCodeMother); + } + } + + if (!isMotherOk) + continue; + + histos.fill(HIST("QAMCTrue/hGlobalIndexMotherRec"), oldindex); + // Track selection check. + histos.fill(HIST("QAMCTrue/TPC_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTPC); + if (isTrk1hasTOF) { + histos.fill(HIST("QAMCTrue/TOF_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTOF); + } + histos.fill(HIST("QAMCTrue/TPC_Nsigmaka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTPC); + if (isTrk2hasTOF) { + histos.fill(HIST("QAMCTrue/TOF_Nsigma_ka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTOF); + } + + // MC histograms + if (pdgCodeMother > 0) { + histos.fill(HIST("k892Rec"), lResonance.Pt(), multiplicity); + histos.fill(HIST("k892Recinvmass"), lResonance.M()); + histos.fill(HIST("h3Reck892invmass"), multiplicity, lResonance.Pt(), lResonance.M()); + histos.fill(HIST("h3Reck892invmassPtGen"), multiplicity, ptMother, lResonance.M()); + histos.fill(HIST("h3PtRecvsPtGen"), multiplicity, lResonance.Pt(), ptMother); + } else { + histos.fill(HIST("k892RecAnti"), lResonance.Pt(), multiplicity); + histos.fill(HIST("k892RecinvmassAnti"), lResonance.M()); + histos.fill(HIST("h3Reck892invmassAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + histos.fill(HIST("h3Reck892invmassAntiPtGen"), multiplicity, ptMother, lResonance.M()); + histos.fill(HIST("h3PtRecvsPtGenAnti"), multiplicity, lResonance.Pt(), ptMother); + } + } + } // end of IsMC + + } else if (track1Sign * track2Sign > 0) { + if constexpr (!IsMix) { + if (track1Sign < 0) { + histos.fill(HIST("k892invmassLS"), lResonance.M()); + histos.fill(HIST("h3k892invmassLS"), multiplicity, lResonance.Pt(), lResonance.M()); + } else if (track1Sign > 0) { + histos.fill(HIST("k892invmassLSAnti"), lResonance.M()); + histos.fill(HIST("h3k892invmassLSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + } + } + } // end on DS or LS if + } // end of loop on track combinations + } // end of fill histograms + + Filter collisionFilter = nabs(aod::collision::posZ) <= cfgCutVertex; + Filter centralityFilter = nabs(aod::cent::centFT0C) <= cfgCutCentrality; + Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) >= cfgCutPT); + Filter dcaCutFilter = (nabs(aod::track::dcaXY) <= cfgCutDCAxy) && (nabs(aod::track::dcaZ) <= cfgCutDCAz); + + // Data + using EventCandidates = soa::Filtered>; + using TrackCandidates = soa::Filtered>; + // MC + using EventCandidatesMCrec = soa::Join; + using TrackCandidatesMCrec = soa::Filtered>; + // ME run 3 + using BinningTypeVtxCent = ColumnBinningPolicy; + + // Data Run 2 + using Run2Events = soa::Join; //, aod::TrackletMults>; + using BCsWithRun2Info = soa::Join; + // MC Run2 + using EventCandidatesMCrecRun2 = soa::Join; // aod::TrackletMults>; + // ME run 2 + using BinningTypeVtxCentRun2 = ColumnBinningPolicy; + + // partitions tpc low pt + Partition negPitpc = (aod::track::signed1Pt < static_cast(0)) && (nabs(aod::pidtpc::tpcNSigmaPi) <= cMaxTPCnSigmaPion) && (nabs(aod::track::pt) < cMaxPtTPC); + Partition posKatpc = (aod::track::signed1Pt > static_cast(0)) && (nabs(aod::pidtpc::tpcNSigmaKa) <= cMaxTPCnSigmaKaon) && (nabs(aod::track::pt) < cMaxPtTPC); + + Partition posPitpc = (aod::track::signed1Pt > static_cast(0)) && (nabs(aod::pidtpc::tpcNSigmaPi) <= cMaxTPCnSigmaPion) && (nabs(aod::track::pt) < cMaxPtTPC); + Partition negKatpc = (aod::track::signed1Pt < static_cast(0)) && (nabs(aod::pidtpc::tpcNSigmaKa) <= cMaxTPCnSigmaKaon) && (nabs(aod::track::pt) < cMaxPtTPC); + + // tpc & tof, high pt + Partition negPitoftpc = (aod::track::signed1Pt < static_cast(0)) && (nabs(aod::pidtof::tofNSigmaPi) <= cMaxTOFnSigmaPion) && (nabs(aod::pidtpc::tpcNSigmaPi) <= cMaxTPCnSigmaPion) && (nabs(aod::track::pt) > cMinPtTOF); + Partition posKatoftpc = (aod::track::signed1Pt > static_cast(0)) && (nabs(aod::pidtof::tofNSigmaKa) <= cMaxTOFnSigmaKaon) && (nabs(aod::pidtpc::tpcNSigmaKa) <= cMaxTPCnSigmaKaon) && (nabs(aod::track::pt) > cMinPtTOF); + + Partition posPitoftpc = (aod::track::signed1Pt > static_cast(0)) && (nabs(aod::pidtof::tofNSigmaPi) <= cMaxTOFnSigmaPion) && (nabs(aod::pidtpc::tpcNSigmaPi) <= cMaxTPCnSigmaPion) && (nabs(aod::track::pt) > cMinPtTOF); + Partition negKatoftpc = (aod::track::signed1Pt < static_cast(0)) && (nabs(aod::pidtof::tofNSigmaKa) <= cMaxTOFnSigmaKaon) && (nabs(aod::pidtpc::tpcNSigmaKa) <= cMaxTPCnSigmaKaon) && (nabs(aod::track::pt) > cMinPtTOF); + + // tof only, high pt + Partition negPitof = (aod::track::signed1Pt < static_cast(0)) && (nabs(aod::pidtof::tofNSigmaPi) <= cMaxTOFnSigmaPion) && (nabs(aod::track::pt) > cMinPtTOF); + Partition posKatof = (aod::track::signed1Pt > static_cast(0)) && (nabs(aod::pidtof::tofNSigmaKa) <= cMaxTOFnSigmaKaon) && (nabs(aod::track::pt) > cMinPtTOF); + + Partition posPitof = (aod::track::signed1Pt > static_cast(0)) && (nabs(aod::pidtof::tofNSigmaPi) <= cMaxTOFnSigmaPion) && (nabs(aod::track::pt) > cMinPtTOF); + Partition negKatof = (aod::track::signed1Pt < static_cast(0)) && (nabs(aod::pidtof::tofNSigmaKa) <= cMaxTOFnSigmaKaon) && (nabs(aod::track::pt) > cMinPtTOF); + + template + void callFillHistoswithPartitions(const CollisionType& collision1, const TracksType&, const CollisionType& collision2, const TracksType&) + { + if (cTPClowpt) { + //+- + auto candPosPitpc = posPitpc->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); + auto candNegKatpc = negKatpc->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); + + fillHistograms(collision1, candPosPitpc, candNegKatpc); + + //-+ + auto candNegPitpc = negPitpc->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); + auto candPosKatpc = posKatpc->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); + + fillHistograms(collision1, candNegPitpc, candPosKatpc); + + } else if (cTOFandTPCHighpt) { + //+- + auto candPosPitoftpc = posPitoftpc->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); + auto candNegKatoftpc = negKatoftpc->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); + + fillHistograms(collision1, candPosPitoftpc, candNegKatoftpc); + + //-+ + auto candNegPitoftpc = negPitoftpc->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); + auto candPosKatoftpc = posKatoftpc->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); + + fillHistograms(collision1, candNegPitoftpc, candPosKatoftpc); + + } else if (cTOFonlyHighpt) { + //+- + auto candPosPitof = posPitof->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); + auto candNegKatof = negKatof->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); + + fillHistograms(collision1, candPosPitof, candNegKatof); + + //-+ + auto candNegPitof = negPitof->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); + auto candPosKatof = posKatof->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); + + fillHistograms(collision1, candNegPitof, candPosKatof); + } + } + + void processSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) + { + + if (!myEventSelections(collision)) + return; + + auto centrality = collision.centFT0C(); + + histos.fill(HIST("QAevent/hEvtCounterSameE"), 1); + histos.fill(HIST("QAevent/hVertexZSameE"), collision.posZ()); + histos.fill(HIST("QAevent/hMultiplicityPercentSameE"), centrality); + + if (additionalQAeventPlots) { + histos.fill(HIST("TestME/hCollisionIndexSameE"), collision.globalIndex()); + histos.fill(HIST("TestME/hnTrksSameE"), tracks.size()); + } + // + callFillHistoswithPartitions(collision, tracks, collision, tracks); + } + PROCESS_SWITCH(K892analysispbpb, processSameEvent, "Process Same event", true); + + void processSameEventRun2(Run2Events::iterator const& collision, TrackCandidates const& tracks, BCsWithRun2Info const& bcs) + { + + if (!myEventSelectionsRun2(collision, bcs)) + return; + + histos.fill(HIST("QAevent/hEvtCounterSameE"), 1); + histos.fill(HIST("QAevent/hVertexZSameE"), collision.posZ()); + histos.fill(HIST("QAevent/hMultiplicityPercentSameE"), collision.centRun2V0M()); + + if (additionalQAeventPlots) { + histos.fill(HIST("TestME/hCollisionIndexSameE"), collision.globalIndex()); + histos.fill(HIST("TestME/hnTrksSameE"), tracks.size()); + } + + // + callFillHistoswithPartitions(collision, tracks, collision, tracks); + } + PROCESS_SWITCH(K892analysispbpb, processSameEventRun2, "Process Same event Run2", false); + + void processRotationalBkg(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) + { + + if (!myEventSelections(collision)) + return; + + // + callFillHistoswithPartitions(collision, tracks, collision, tracks); + } + PROCESS_SWITCH(K892analysispbpb, processRotationalBkg, "Process Rotational Background", false); + + void processRotationalBkgMC(EventCandidatesMCrec::iterator const& recCollision, TrackCandidatesMCrec const& RecTracks) + { + + if (!myEventSelections(recCollision)) + return; + + // + fillHistograms(recCollision, RecTracks, RecTracks); + } + PROCESS_SWITCH(K892analysispbpb, processRotationalBkgMC, "Process Rotational Background MC", false); + + void processMixedEvent(EventCandidates const& collisions, TrackCandidates const& tracks) + { + auto tracksTuple = std::make_tuple(tracks); + BinningTypeVtxCent colBinning{{cfgVtxBins, cfgMultBins}, true}; + SameKindPair pairs{colBinning, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; + + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + + if (!myEventSelections(collision1) || !myEventSelections(collision2)) + continue; + + auto centrality = collision1.centFT0C(); + + if (additionalQAeventPlots) { + histos.fill(HIST("QAevent/hEvtCounterMixedE"), 1.0); + histos.fill(HIST("QAevent/hVertexZMixedE"), collision1.posZ()); + histos.fill(HIST("QAevent/hMultiplicityPercentMixedE"), centrality); + histos.fill(HIST("TestME/hCollisionIndexMixedE"), collision1.globalIndex()); + histos.fill(HIST("TestME/hnTrksMixedE"), tracks1.size()); + } + + // + callFillHistoswithPartitions(collision1, tracks1, collision2, tracks2); + } + } + PROCESS_SWITCH(K892analysispbpb, processMixedEvent, "Process Mixed event", true); + + void processMixedEventRun2(Run2Events const& collisions, TrackCandidates const& tracks, BCsWithRun2Info const& bcs) + { + auto tracksTuple = std::make_tuple(tracks); + BinningTypeVtxCentRun2 colBinning{{cfgVtxBins, cfgMultBins}, true}; + SameKindPair pairs{colBinning, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; + + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + + if (!myEventSelectionsRun2(collision1, bcs) || !myEventSelectionsRun2(collision2, bcs)) + continue; + + if (additionalQAeventPlots) { + histos.fill(HIST("QAevent/hEvtCounterMixedE"), 1.0); + histos.fill(HIST("QAevent/hVertexZMixedE"), collision1.posZ()); + histos.fill(HIST("QAevent/hMultiplicityPercentMixedE"), collision1.centRun2V0M()); + histos.fill(HIST("TestME/hCollisionIndexMixedE"), collision1.globalIndex()); + histos.fill(HIST("TestME/hnTrksMixedE"), tracks1.size()); + } + + // + callFillHistoswithPartitions(collision1, tracks1, collision2, tracks2); + } + } + PROCESS_SWITCH(K892analysispbpb, processMixedEventRun2, "Process Mixed event Run2", false); + + void processMixedEventMC(EventCandidatesMCrec const& recCollisions, TrackCandidatesMCrec const& RecTracks, aod::McParticles const&) + { + auto tracksTuple = std::make_tuple(RecTracks); + BinningTypeVtxCent colBinning{{cfgVtxBins, cfgMultBins}, true}; + SameKindPair pairs{colBinning, cfgNoMixedEvents, -1, recCollisions, tracksTuple, &cache}; + + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + + if (!myEventSelections(collision1) || !myEventSelections(collision2)) + continue; + + if (additionalQAeventPlots) { + histos.fill(HIST("QAevent/hEvtCounterMixedE"), 1.0); + histos.fill(HIST("QAevent/hVertexZMixedE"), collision1.posZ()); + histos.fill(HIST("QAevent/hMultiplicityPercentMixedE"), collision1.centFT0C()); + histos.fill(HIST("TestME/hCollisionIndexMixedE"), collision1.globalIndex()); + histos.fill(HIST("TestME/hnTrksMixedE"), tracks1.size()); + } + + // + fillHistograms(collision1, tracks1, tracks2); + } + } + PROCESS_SWITCH(K892analysispbpb, processMixedEventMC, "Process Mixed event MC", false); + + void processMixedEventMCRun2(EventCandidatesMCrecRun2 const& recCollisions, TrackCandidatesMCrec const& RecTracks, BCsWithRun2Info const& bcs, aod::McParticles const&) + { + auto tracksTuple = std::make_tuple(RecTracks); + BinningTypeVtxCentRun2 colBinning{{cfgVtxBins, cfgMultBins}, true}; + SameKindPair pairs{colBinning, cfgNoMixedEvents, -1, recCollisions, tracksTuple, &cache}; + + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + + if (!myEventSelectionsRun2(collision1, bcs) || !myEventSelectionsRun2(collision2, bcs)) + continue; + + if (additionalQAeventPlots) { + histos.fill(HIST("QAevent/hEvtCounterMixedE"), 1.0); + histos.fill(HIST("QAevent/hVertexZMixedE"), collision1.posZ()); + histos.fill(HIST("QAevent/hMultiplicityPercentMixedE"), collision1.centRun2V0M()); + histos.fill(HIST("TestME/hCollisionIndexMixedE"), collision1.globalIndex()); + histos.fill(HIST("TestME/hnTrksMixedE"), tracks1.size()); + } + + // + fillHistograms(collision1, tracks1, tracks2); + } + } + PROCESS_SWITCH(K892analysispbpb, processMixedEventMCRun2, "Process Mixed event MC Run2", false); + + void processEvtLossSigLossMC(aod::McCollisions::iterator const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& recCollisions) + { + + // Event loss estimation + auto impactPar = mcCollision.impactParameter(); + histos.fill(HIST("QAevent/hImpactParameterGen"), impactPar); + + bool isSel = false; + auto centrality = -999.; + if (recCollisions.size() > 0) { + auto numcontributors = -999; + for (const auto& RecCollision : recCollisions) { + if (!myEventSelections(RecCollision)) + continue; + + if (RecCollision.numContrib() <= numcontributors) + continue; + else + numcontributors = RecCollision.numContrib(); + + centrality = RecCollision.centFT0C(); + isSel = true; + } + } + + if (isSel) { + histos.fill(HIST("QAevent/hImpactParameterRec"), impactPar); + histos.fill(HIST("QAevent/hImpactParvsCentrRec"), centrality, impactPar); + } + + // Generated MC + for (const auto& mcPart : mcParticles) { + if (std::abs(mcPart.y()) >= 0.5 || std::abs(mcPart.pdgCode()) != 313) + continue; + + // signal loss estimation + if (mcPart.pdgCode() > 0) // no cuts, purely generated + histos.fill(HIST("QAevent/k892genBeforeEvtSel"), mcPart.pt(), impactPar); + else + histos.fill(HIST("QAevent/k892genBeforeEvtSelAnti"), mcPart.pt(), impactPar); + + if (isSel) { + // signal loss estimation + if (mcPart.pdgCode() > 0) // no cuts, purely generated + histos.fill(HIST("QAevent/k892genAfterEvtSel"), mcPart.pt(), impactPar); + else + histos.fill(HIST("QAevent/k892genAfterEvtSelAnti"), mcPart.pt(), impactPar); + } + } // end loop on gen particles + } + PROCESS_SWITCH(K892analysispbpb, processEvtLossSigLossMC, "Process Signal Loss, Event Loss", false); + + void processMC(aod::McCollisions::iterator const& /*mcCollision*/, aod::McParticles const& mcParticles, const soa::SmallGroups& recCollisions, TrackCandidatesMCrec const& RecTracks) + { + + histos.fill(HIST("QAevent/hMCrecCollSels"), 0); + if (recCollisions.size() == 0) { + histos.fill(HIST("QAevent/hMCrecCollSels"), 1); + return; + } + if (recCollisions.size() > 1) { + histos.fill(HIST("QAevent/hMCrecCollSels"), 2); + return; + } + for (const auto& RecCollision : recCollisions) { + histos.fill(HIST("QAevent/hMCrecCollSels"), 3); + + if (!myEventSelections(RecCollision)) + continue; + + histos.fill(HIST("QAevent/hMCrecCollSels"), 8); + auto centrality = RecCollision.centFT0C(); + histos.fill(HIST("QAevent/hMultiplicityPercentMC"), centrality); + + auto tracks = RecTracks.sliceByCached(aod::track::collisionId, RecCollision.globalIndex(), cache); + + // + fillHistograms(RecCollision, tracks, tracks); + + // Generated MC + for (const auto& mcPart : mcParticles) { + if (std::abs(mcPart.y()) >= 0.5 || std::abs(mcPart.pdgCode()) != 313) + continue; + + auto kDaughters = mcPart.daughters_as(); + if (kDaughters.size() != 2) { + continue; + } + + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; + + auto daughtp = false; + auto daughtk = false; + for (const auto& kCurrentDaughter : kDaughters) { + if (!kCurrentDaughter.isPhysicalPrimary()) + break; + + if (std::abs(kCurrentDaughter.pdgCode()) == 211) { + daughtp = true; + lDecayDaughter1.SetXYZM(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massPi); + } else if (std::abs(kCurrentDaughter.pdgCode()) == 321) { + daughtk = true; + lDecayDaughter2.SetXYZM(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massKa); + } + } + + if (!daughtp || !daughtk) + continue; + + lResonance = lDecayDaughter1 + lDecayDaughter2; + + histos.fill(HIST("QAMCTrue/hGlobalIndexMotherGen"), mcPart.globalIndex()); + + if (mcPart.pdgCode() > 0) { // no cuts, purely generated + histos.fill(HIST("k892GenInvmass"), lResonance.M()); + histos.fill(HIST("h3k892GenInvmass"), centrality, lResonance.Pt(), lResonance.M()); + histos.fill(HIST("k892Gen"), 3, mcPart.pt(), centrality); + } else { + histos.fill(HIST("k892GenInvmassAnti"), lResonance.M()); + histos.fill(HIST("h3k892GenInvmassAnti"), centrality, lResonance.Pt(), lResonance.M()); + histos.fill(HIST("k892GenAnti"), 3, mcPart.pt(), centrality); + } + + } // end loop on gen particles + + } // end loop on rec collisions + } + PROCESS_SWITCH(K892analysispbpb, processMC, "Process Monte Carlo", false); + + void processMCRun2(aod::McCollisions::iterator const& /*mcCollision*/, aod::McParticles const& mcParticles, const soa::SmallGroups& recCollisions, TrackCandidatesMCrec const& RecTracks, BCsWithRun2Info const& bcs) + { + histos.fill(HIST("QAevent/hMCrecCollSels"), 0); + if (recCollisions.size() == 0) { + histos.fill(HIST("QAevent/hMCrecCollSels"), 1); + return; + } + if (recCollisions.size() > 1) { + histos.fill(HIST("QAevent/hMCrecCollSels"), 2); + return; + } + for (const auto& RecCollision : recCollisions) { + histos.fill(HIST("QAevent/hMCrecCollSels"), 3); + + if (!myEventSelectionsRun2(RecCollision, bcs)) + continue; + histos.fill(HIST("QAevent/hMCrecCollSels"), 8); + + auto centrality = RecCollision.centRun2V0M(); + histos.fill(HIST("QAevent/hMultiplicityPercentMC"), centrality); + auto tracks = RecTracks.sliceByCached(aod::track::collisionId, RecCollision.globalIndex(), cache); + + // + fillHistograms(RecCollision, tracks, tracks); + + // Generated MC + for (const auto& mcPart : mcParticles) { + if (std::abs(mcPart.y()) >= 0.5 || std::abs(mcPart.pdgCode()) != 313) + continue; + + auto kDaughters = mcPart.daughters_as(); + if (kDaughters.size() != 2) { + continue; + } + + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; + + auto daughtp = false; + auto daughtk = false; + for (const auto& kCurrentDaughter : kDaughters) { + if (!kCurrentDaughter.isPhysicalPrimary()) + break; + + if (std::abs(kCurrentDaughter.pdgCode()) == 211) { + daughtp = true; + lDecayDaughter1.SetXYZM(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massPi); + } else if (std::abs(kCurrentDaughter.pdgCode()) == 321) { + daughtk = true; + lDecayDaughter2.SetXYZM(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massKa); + } + } + + if (!daughtp || !daughtk) + continue; + + lResonance = lDecayDaughter1 + lDecayDaughter2; + + histos.fill(HIST("QAMCTrue/hGlobalIndexMotherGen"), mcPart.globalIndex()); + + if (mcPart.pdgCode() > 0) { // no cuts, purely generated + histos.fill(HIST("k892GenInvmass"), lResonance.M()); + histos.fill(HIST("h3k892GenInvmass"), centrality, lResonance.Pt(), lResonance.M()); + histos.fill(HIST("k892Gen"), 3, mcPart.pt(), centrality); + } else { + histos.fill(HIST("k892GenInvmassAnti"), lResonance.M()); + histos.fill(HIST("h3k892GenInvmassAnti"), centrality, lResonance.Pt(), lResonance.M()); + histos.fill(HIST("k892GenAnti"), 3, mcPart.pt(), centrality); + } + + } // end loop on gen particles + + } // end loop on rec collisions + } + PROCESS_SWITCH(K892analysispbpb, processMCRun2, "Process Monte Carlo Run2", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/k892pmanalysis.cxx b/PWGLF/Tasks/Resonances/k892pmanalysis.cxx index 1cdcf49f2fb..16963b77e6b 100644 --- a/PWGLF/Tasks/Resonances/k892pmanalysis.cxx +++ b/PWGLF/Tasks/Resonances/k892pmanalysis.cxx @@ -44,18 +44,30 @@ struct k892pmanalysis { ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12.0, 12.1, 12.2, 12.3, 12.4, 12.5, 12.6, 12.7, 12.8, 12.9, 13.0, 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7, 13.8, 13.9, 14.0, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15.0}, "Binning of the pT axis"}; ConfigurableAxis binsPtQA{"binsPtQA", {VARIABLE_WIDTH, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2, 6.4, 6.6, 6.8, 7.0, 7.2, 7.4, 7.6, 7.8, 8.0, 8.2, 8.4, 8.6, 8.8, 9.0, 9.2, 9.4, 9.6, 9.8, 10.0}, "Binning of the pT axis"}; ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 1., 5., 10., 30., 50., 70., 100., 110.}, "Binning of the centrality axis"}; + ConfigurableAxis binsEtaQA{"binsEtaQA", {VARIABLE_WIDTH, -1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}, "Binning of pseudo-rapidity eta"}; + ConfigurableAxis binsV0CosPointAngleQA{"binsV0CosPointAngleQA", {VARIABLE_WIDTH, 0.75, 0.80, 0.85, 0.90, 0.95, 1.0}, "Binning of V0 cosine of pointing angle"}; + Configurable cInvMassStart{"cInvMassStart", 0.6, "Invariant mass start"}; Configurable cInvMassEnd{"cInvMassEnd", 1.5, "Invariant mass end"}; Configurable cInvMassBins{"cInvMassBins", 900, "Invariant mass binning"}; + Configurable cK0shortMassStart{"cK0shortMassStart", 0.4, "K0Short mass start"}; Configurable cK0shortMassEnd{"cK0shortMassEnd", 0.6, "K0Short mass end"}; Configurable cK0shortMassBins{"cK0shortMassBins", 50, "K0Short mass binning"}; - Configurable cDCABins{"cDCABins", 150, "DCA binning"}; - /// Pre-selection cuts + + Configurable cLambdaAntiLambdaMassStart{"cLambdaAntiLambdaMassStart", 1.0, "V0 mass (in the (Anti)Lambda0 hypothesis) start"}; + Configurable cLambdaAntiLambdaMassEnd{"cLambdaAntiLambdaMassEnd", 2.0, "V0 mass (in the (Anti)Lambda0 hypothesis) end"}; + Configurable cLambdaAntiLambdaMassBins{"cLambdaAntiLambdaMassBins", 250, "V0 mass (in the (Anti)Lambda0 hypothesis) binning"}; + + Configurable cDCABinsQA{"cDCABinsQA", 150, "DCA binning"}; + + Configurable cTpcNsigmaPionBinsQA{"cTpcNsigmaPionBinsQA", 140, "tpcNSigmaPi binning"}; + + // Pre-selection cuts Configurable cMinPtcut{"cMinPtcut", 0.15, "Track minimum pt cut"}; Configurable cMaxEtacut{"cMaxEtacut", 0.8, "Track maximum eta cut"}; Configurable cMaxV0Etacut{"cMaxV0Etacut", 0.8, "V0 maximum eta cut"}; - /// DCA Selections + // DCA Selections // DCAr to PV Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 0.5, "Track DCAr cut to PV Maximum"}; // DCAz to PV @@ -73,6 +85,8 @@ struct k892pmanalysis { // V0 selections Configurable cV0MinCosPA{"cV0MinCosPA", 0.97, "V0 minimum pointing angle cosine"}; Configurable cV0MaxDaughDCA{"cV0MaxDaughDCA", 1.0, "V0 daughter DCA Maximum"}; + // Competing V0 rejection + Configurable cV0MassWindow{"cV0MassWindow", 0.0043, "Mass window for competing Lambda0 rejection"}; // Resonance selection // Configurable cMaxResRapidity{"cMaxResRapidity", 0.5, "Maximum pseudo-rapidity value of reconstructed K*(892)pm resonance"}; // Event mixing @@ -83,31 +97,67 @@ struct k892pmanalysis { void init(o2::framework::InitContext&) { AxisSpec centAxis = {binsCent, "V0M (%)"}; - AxisSpec dcaxyAxis = {cDCABins, 0.0, 3.0, "DCA_{#it{xy}} (cm)"}; - AxisSpec dcazAxis = {cDCABins, 0.0, 3.0, "DCA_{#it{xy}} (cm)"}; + AxisSpec etaAxisQA = {binsEtaQA, "#eta"}; + AxisSpec dcaxyAxisQA = {cDCABinsQA, 0.0, 3.0, "DCA_{#it{xy}} (cm)"}; + AxisSpec dcazAxisQA = {cDCABinsQA, 0.0, 3.0, "DCA_{#it{xy}} (cm)"}; + AxisSpec daughdcaAxisQa = {cDCABinsQA, 0.0, 3.0, "V0 daughters DCA (cm)"}; + AxisSpec CosPointAngleAxisQA = {binsV0CosPointAngleQA, "CosPA"}; + AxisSpec tpcNSigmaPiAxisQA = {cTpcNsigmaPionBinsQA, -7.0, 7.0, "N#sigma_{TPC}"}; AxisSpec ptAxis = {binsPt, "#it{p}_{T} (GeV/#it{c})"}; AxisSpec ptAxisQA = {binsPtQA, "#it{p}_{T} (GeV/#it{c})"}; AxisSpec invMassAxis = {cInvMassBins, cInvMassStart, cInvMassEnd, "Invariant Mass (GeV/#it{c}^2)"}; - AxisSpec k0sMassAxis = {cK0shortMassBins, cK0shortMassStart, cK0shortMassEnd, "K^{0}_{S} Mass (GeV/#it{c}^2)"}; + AxisSpec k0sMassAxisQA = {cK0shortMassBins, cK0shortMassStart, cK0shortMassEnd, "K^{0}_{S} Mass (GeV/#it{c}^2)"}; + AxisSpec lambdaAntilambdaMassAxisQA = {cLambdaAntiLambdaMassBins, cLambdaAntiLambdaMassStart, cLambdaAntiLambdaMassEnd, "(Anti-)#Lambda^{0} Mass (GeV/#it{c}^2)"}; AxisSpec k892pmCountAxis = {2, 0., 2., "K*^{+}(892) = 1, K*^{-}(892) = 2"}; AxisSpec goodTrackCountAxis = {3, 0., 3., "Passed track = 1, Passed V0 = 2, Passed track and V0 = 3"}; // Mass QA (quick check) + // QA before + histos.add("QAbefore/k0shortmassPt", "Invariant mass of K0Short vs K0Short Pt", kTH2F, {ptAxisQA, k0sMassAxisQA}); + histos.add("QAbefore/lambda0mass", "Invariant mass of V0 in Lambda0 hypothesis", kTH1F, {lambdaAntilambdaMassAxisQA}); + histos.add("QAbefore/antilambda0mass", "Invariant mass of V0 in AntiLambda0 hypothesis", kTH1F, {lambdaAntilambdaMassAxisQA}); + // QA after + histos.add("QAafter/k0shortmassPt", "Invariant mass of K0Short vs K0Short Pt", kTH2F, {ptAxisQA, k0sMassAxisQA}); + histos.add("QAafter/lambda0mass", "Invariant mass of V0 in Lambda0 hypothesis", kTH1F, {lambdaAntilambdaMassAxisQA}); + histos.add("QAafter/antilambda0mass", "Invariant mass of V0 in AntiLambda0 hypothesis", kTH1F, {lambdaAntilambdaMassAxisQA}); histos.add("k892pminvmass", "Invariant mass of charged K*(892)", kTH1F, {invMassAxis}); - histos.add("QAafter/k0shortmass", "Invariant mass of K0Short", kTH1F, {k0sMassAxis}); + // Multiplicity and accepted events QA + histos.add("QAbefore/collMult", "Collision multiplicity", HistType::kTH1F, {centAxis}); // DCA QA - histos.add("QAbefore/collMult", "Collision multiplicity", HistType::kTH1F, {binsCent}); - histos.add("QAbefore/trkDCAxy_pi", "DCAxy distribution of pion track candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QAbefore/trkDCAz_pi", "DCAz distribution of pion track candidates", HistType::kTH1F, {dcazAxis}); - // histos.add("QAbefore/trkDCAz_k0s", "DCAz distribution of k0short track candidates", HistType::kTH1F, {dcazAxis}); - histos.add("QAafter/trkDCAxy_pi", "DCAxy distribution of pion track candidates", HistType::kTH1F, {dcaxyAxis}); - histos.add("QAafter/trkDCAz_pi", "DCAz distribution of pion track candidates", HistType::kTH1F, {dcazAxis}); - // histos.add("QAafter/trkDCAz_k0s", "DCAz distribution of k0short track candidates", HistType::kTH1F, {dcazAxis}); - // pT QA + // QA before + histos.add("QAbefore/trkDCAxy_pi", "DCAxy distribution of pion track candidates", HistType::kTH1F, {dcaxyAxisQA}); + histos.add("QAbefore/trkDCAz_pi", "DCAz distribution of pion track candidates", HistType::kTH1F, {dcazAxisQA}); + histos.add("QAbefore/trkV0DaughDCA", "DCA distribution of V0 daughters", kTH1F, {daughdcaAxisQa}); + // QA after + histos.add("QAafter/trkDCAxy_pi", "DCAxy distribution of pion track candidates", HistType::kTH1F, {dcaxyAxisQA}); + histos.add("QAafter/trkDCAz_pi", "DCAz distribution of pion track candidates", HistType::kTH1F, {dcazAxisQA}); + histos.add("QAafter/trkV0DaughDCA", "DCA distribution of V0 daughters", kTH1F, {daughdcaAxisQa}); + // Pseudo-rapidity QA + // QA before + histos.add("QAbefore/trkEta_pi", "Primary pion track pseudo-rapidity eta", kTH1F, {etaAxisQA}); + histos.add("QAbefore/trkEta_k0s", "K0short track pseudo-rapidity eta", kTH1F, {etaAxisQA}); + histos.add("QAbefore/k892pmRapidity", "Reconstructed K*(892)^{#pm} rapidity", kTH1F, {etaAxisQA}); + // QA after + histos.add("QAafter/trkEta_pi", "Primary pion track pseudo-rapidity eta", kTH1F, {etaAxisQA}); + histos.add("QAafter/trkEta_k0s", "K0short track pseudo-rapidity eta", kTH1F, {etaAxisQA}); + histos.add("QAafter/k892pmRapidity", "Reconstructed K*(892)^{#pm} rapidity", kTH1F, {etaAxisQA}); + // Cosine pointing angle QA + // QA before + histos.add("QAbefore/V0CosPA", "V0 cosine of pointing angle", kTH1F, {CosPointAngleAxisQA}); + // QA after + histos.add("QAafter/V0CosPA", "V0 cosine of pointing angle", kTH1F, {CosPointAngleAxisQA}); + // pT QA + // QA before histos.add("QAbefore/trkpT_pi", "pT distribution of pion track candidates", kTH1F, {ptAxisQA}); histos.add("QAbefore/trkpT_k0s", "pT distribution of k0short track candidates", kTH1F, {ptAxisQA}); + // QA after histos.add("QAafter/trkpT_pi", "pT distribution of pion track candidates", kTH1F, {ptAxisQA}); histos.add("QAafter/trkpT_k0s", "pT distribution of k0short track candidates", kTH1F, {ptAxisQA}); + // Primary pion TPC PID + // QA before + histos.add("QAbefore/tpcNsigmaPionQA", "NsigmaTPC distribution of primary pion candidates", kTH2F, {ptAxisQA, tpcNSigmaPiAxisQA}); + // QA after + histos.add("QAafter/tpcNsigmaPionQA", "NsigmaTPC distribution of primary pion candidates", kTH2F, {ptAxisQA, tpcNSigmaPiAxisQA}); // Good tracks and V0 counts QA histos.add("QAafter/hGoodTracksV0s", "Number of good track and V0 passed", kTH1F, {goodTrackCountAxis}); // Mass vs Pt vs Multiplicity 3-dimensional histogram @@ -137,6 +187,8 @@ struct k892pmanalysis { double massK0 = MassK0Short; double massPi = MassPionCharged; + double massLambda0 = MassLambda; + double massAntiLambda0 = MassLambda0Bar; template bool trackCut(const TrackType track) @@ -227,13 +279,22 @@ struct k892pmanalysis { auto trkId = trk.index(); auto trkptPi = trk.pt(); + auto trketaPi = trk.eta(); + // LOG(INFO) << "Primary Pion Eta before cuts is: " << trketaPi; + + // Pseudo-rapidity QA (before cuts) + histos.fill(HIST("QAbefore/trkEta_pi"), trketaPi); if (!IsMix) { // DCA QA (before cuts) histos.fill(HIST("QAbefore/trkDCAxy_pi"), trk.dcaXY()); histos.fill(HIST("QAbefore/trkDCAz_pi"), trk.dcaZ()); + // Pseudo-rapidity QA (before cuts) + histos.fill(HIST("QAbefore/trkEta_pi"), trketaPi); // pT QA (before cuts) histos.fill(HIST("QAbefore/trkpT_pi"), trkptPi); + // TPC PID (before cuts) + histos.fill(HIST("QAbefore/tpcNsigmaPionQA"), trkptPi, trk.tpcNSigmaPi()); } // apply the track cut @@ -242,12 +303,18 @@ struct k892pmanalysis { histos.fill(HIST("QAafter/hGoodTracksV0s"), 0.5); + // LOG(INFO) << "Primary Pion Eta after cuts is: " << trketaPi; + if (!IsMix) { // DCA QA (QAafter cuts) histos.fill(HIST("QAafter/trkDCAxy_pi"), trk.dcaXY()); histos.fill(HIST("QAafter/trkDCAz_pi"), trk.dcaZ()); + // Pseudo-rapidity QA (after cuts) + histos.fill(HIST("QAafter/trkEta_pi"), trketaPi); // pT QA (after cuts) histos.fill(HIST("QAafter/trkpT_pi"), trk.pt()); + // TPC PID (after cuts) + histos.fill(HIST("QAafter/tpcNsigmaPionQA"), trkptPi, trk.tpcNSigmaPi()); } for (auto& v0 : dV0s) { @@ -260,8 +327,16 @@ struct k892pmanalysis { auto v0ptK0s = v0.pt(); if (!IsMix && !IsV0QAFilled) { + // V0 daughter DCA (before cuts) + histos.fill(HIST("QAbefore/trkV0DaughDCA"), v0.daughDCA()); + // Pseudo-rapidity QA (before cuts) + histos.fill(HIST("QAbefore/trkEta_k0s"), v0.eta()); + // CosPA (before cuts) + histos.fill(HIST("QAbefore/V0CosPA"), v0.v0CosPA()); // pT QA (before cuts) histos.fill(HIST("QAbefore/trkpT_k0s"), v0ptK0s); + // K0s mass QA (before cuts) + histos.fill(HIST("QAbefore/k0shortmassPt"), v0ptK0s, v0.mK0Short()); } // apply the track cut @@ -270,20 +345,52 @@ struct k892pmanalysis { histos.fill(HIST("QAafter/hGoodTracksV0s"), 1.5); + // QA (anti)Lamda0 mass before competing V0 rejection cut + if (!IsMix && !IsV0QAFilled) { + histos.fill(HIST("QAbefore/lambda0mass"), v0.mLambda()); + histos.fill(HIST("QAbefore/antilambda0mass"), v0.mAntiLambda()); + } + + // apply the competing V0 rejection cut (excluding Lambda0 candidates, massLambdaPDG = 1115.683 MeV/c2) + if (std::abs(v0.mLambda() - massLambda0) < cV0MassWindow) + continue; + if (std::abs(v0.mAntiLambda() - massAntiLambda0) < cV0MassWindow) + continue; + if (!IsMix && !IsV0QAFilled) { + // V0 daughter DCA (after cuts) + histos.fill(HIST("QAafter/trkV0DaughDCA"), v0.daughDCA()); + // Pseudo-rapidity QA (before cuts) + histos.fill(HIST("QAafter/trkEta_k0s"), v0.eta()); + // CosPA (after cuts) + histos.fill(HIST("QAafter/V0CosPA"), v0.v0CosPA()); // pt QA (after cuts) histos.fill(HIST("QAafter/trkpT_k0s"), v0ptK0s); // K0s mass QA (after cuts) - histos.fill(HIST("QAafter/k0shortmass"), v0.mK0Short()); + histos.fill(HIST("QAafter/k0shortmassPt"), v0ptK0s, v0.mK0Short()); + histos.fill(HIST("QAafter/lambda0mass"), v0.mLambda()); + histos.fill(HIST("QAafter/antilambda0mass"), v0.mAntiLambda()); } lDecayDaughter.SetXYZM(trk.px(), trk.py(), trk.pz(), massPi); lDecayV0.SetXYZM(v0.px(), v0.py(), v0.pz(), massK0); lResonance = lDecayDaughter + lDecayV0; + + if (!IsMix && !IsV0QAFilled) { + // Pseudo-rapidity QA (before eta cut) + histos.fill(HIST("QAbefore/k892pmRapidity"), lResonance.Rapidity()); + } + // Checking whether the mid-rapidity condition is met - if (lResonance.Rapidity() > 0.5) { + if (std::abs(lResonance.Rapidity()) > 0.5) { continue; } + + if (!IsMix && !IsV0QAFilled) { + // Pseudo-rapidity QA (before eta cut) + histos.fill(HIST("QAafter/k892pmRapidity"), lResonance.Rapidity()); + } + // Counting how many resonances passed histos.fill(HIST("QAafter/hGoodTracksV0s"), 2.5); // Filling invariant mass histograms @@ -294,7 +401,7 @@ struct k892pmanalysis { histos.fill(HIST("k892pmMassPtMult3d"), lResonance.M(), lResonance.Pt(), multiplicity); if constexpr (IsMC) { // LOG(info) << "track PDG:\t" << trk.pdgCode() << "\tV0 PDG:\t" << v0.pdgCode(); - if (abs(trk.pdgCode()) != 211 || abs(v0.pdgCode()) != 310) // Skip to next iteration if daughters are not charged pion + K0s/AntiK0s + if (std::abs(trk.pdgCode()) != 211 || std::abs(v0.pdgCode()) != 310) // Skip to next iteration if daughters are not charged pion + K0s/AntiK0s continue; if (trk.motherPDG() != v0.motherPDG()) continue; @@ -337,17 +444,17 @@ struct k892pmanalysis { void processMCTrue(aod::ResoMCParents& resoParents) { for (auto& part : resoParents) { // loop over all pre-filtered MC particles - if (abs(part.pdgCode()) != 323) // K*892(pm) + if (std::abs(part.pdgCode()) != 323) // K*892(pm) continue; - if (abs(part.y()) > 0.5) // rapidity cut + if (std::abs(part.y()) > 0.5) // rapidity cut continue; bool pass1 = false; bool pass2 = false; /*// Sanity check: looking for K*0 resonances for sanity check - if (abs(part.pdgCode()) == 323) { + if (std::abs(part.pdgCode()) == 323) { LOG(info) << "Found charged K*: " << part.pdgCode() << ". Daughters' PDG are " << part.daughterPDG1() << " and " << part.daughterPDG2(); } - if (abs(part.pdgCode()) == 313) { + if (std::abs(part.pdgCode()) == 313) { LOG(info) << "Found non-charged K*: " << part.pdgCode() << ". Daughters' PDG are " << part.daughterPDG1() << " and " << part.daughterPDG2(); }*/ @@ -359,11 +466,11 @@ struct k892pmanalysis { pass2 = true; histos.fill(HIST("hK892pmCounter"), 1.5); } - /*if (abs(part.daughterPDG1()) == 211) + /*if (std::abs(part.daughterPDG1()) == 211) histos.fill(HIST("hDaughterCounter"), 0.5); - if (abs(part.daughterPDG2()) == 310) + if (std::abs(part.daughterPDG2()) == 310) histos.fill(HIST("hDaughterCounter"), 1.5); - if (abs(part.daughterPDG1()) == 211 && abs(part.daughterPDG2()) == 310) + if (std::abs(part.daughterPDG1()) == 211 && std::abs(part.daughterPDG2()) == 310) histos.fill(HIST("hDaughterCounter"), 2.5);*/ // if (!pass1 || !pass2) // Go on only if we have both decay products, else skip to next iteration if (!pass1 && !pass2) // Go on only if we have both decay products, else skip to next iteration diff --git a/PWGLF/Tasks/Resonances/kaonkaonanalysis.cxx b/PWGLF/Tasks/Resonances/kaonkaonanalysis.cxx index 538332e9fb4..81af59575ab 100644 --- a/PWGLF/Tasks/Resonances/kaonkaonanalysis.cxx +++ b/PWGLF/Tasks/Resonances/kaonkaonanalysis.cxx @@ -29,11 +29,14 @@ #include #include #include -#include #include #include #include #include "TF1.h" +#include "TRandom3.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -55,7 +58,7 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using std::array; -struct phianalysisrun3 { +struct kaonkaonAnalysisRun3 { SliceCache cache; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -66,6 +69,10 @@ struct phianalysisrun3 { Configurable itstpctracks{"itstpctracks", false, "selects collisions with at least one ITS-TPC track,"}; Configurable timFrameEvsel{"timFrameEvsel", true, "TPC Time frame boundary cut"}; Configurable additionalEvsel{"additionalEvsel", false, "Additional event selcection"}; + Configurable otherQAplots{"otherQAplots", true, "Other QA plots"}; + Configurable QAPID{"QAPID", true, "QA PID plots"}; + Configurable QAevents{"QAevents", true, "QA events"}; + Configurable cfgMultFT0M{"cfgMultFT0M", true, "true for pp (FT0M estimator) and false for PbPb (FT0C estimator)"}; // Event selection cuts - Alex (Temporary, need to fix!) TF1* fMultPVCutLow = nullptr; @@ -75,6 +82,7 @@ struct phianalysisrun3 { TF1* fMultMultPVCut = nullptr; // track + Configurable rotational_cut{"rotational_cut", 10, "Cut value (Rotation angle pi - pi/cut and pi + pi/cut)"}; Configurable cfgCutPT{"cfgCutPT", 0.2, "PT cut on daughter track"}; Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; Configurable cfgCutDCAxy{"cfgCutDCAxy", 2.0f, "DCAxy range for tracks"}; @@ -83,7 +91,6 @@ struct phianalysisrun3 { Configurable nsigmaCutCombined{"nsigmaCutCombined", 3.0, "Value of the TOF Nsigma cut"}; Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 5, "Number of mixed events per event"}; Configurable isEtaAssym{"isEtaAssym", false, "isEtaAssym"}; - Configurable cfgMultFT0{"cfgMultFT0", true, "cfgMultFT0"}; Configurable iscustomDCAcut{"iscustomDCAcut", false, "iscustomDCAcut"}; Configurable isNoTOF{"isNoTOF", false, "isNoTOF"}; Configurable ismanualDCAcut{"ismanualDCAcut", true, "ismanualDCAcut"}; @@ -92,45 +99,101 @@ struct phianalysisrun3 { Configurable cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; Configurable isDeepAngle{"isDeepAngle", false, "Deep Angle cut"}; Configurable cfgDeepAngle{"cfgDeepAngle", 0.04, "Deep Angle cut value"}; - Configurable cmultLow{"cmultLow", -0.5f, "Low centrality percentile"}; - Configurable cmultHigh{"cmultHigh", 200.5f, "High centrality percentile"}; - Configurable cmultBins{"cmultBins", 201, "Number of centrality bins"}; + Configurable cmultLow{"cmultLow", 0.0f, "Low centrality percentile"}; + Configurable cmultHigh{"cmultHigh", 150.0f, "High centrality percentile"}; + Configurable cmultBins{"cmultBins", 150, "Number of centrality bins"}; Configurable cpTlow{"cpTlow", 0.0f, "Low pT"}; Configurable cpThigh{"cpThigh", 10.0f, "High pT"}; Configurable cpTbins{"cpTbins", 100, "Number of pT bins"}; Configurable cMasslow{"cMasslow", 0.9f, "Low mass"}; Configurable cMasshigh{"cMasshigh", 2.5f, "High mass"}; Configurable cMassbins{"cMassbins", 320, "Number of mass bins"}; + Configurable c_nof_rotations{"c_nof_rotations", 3, "Number of random rotations in the rotational background"}; + ConfigurableAxis axisdEdx{"axisdEdx", {20000, 0.0f, 200.0f}, "dE/dx (a.u.)"}; + ConfigurableAxis axisPtfordEbydx{"axisPtfordEbydx", {2000, 0, 20}, "pT (GeV/c)"}; + ConfigurableAxis axisMultdist{"axisMultdist", {3500, 0, 70000}, "Multiplicity distribution"}; + + // different frames + Configurable activateTHnSparseCosThStarHelicity{"activateTHnSparseCosThStarHelicity", true, "Activate the THnSparse with cosThStar w.r.t. helicity axis"}; + Configurable activateTHnSparseCosThStarProduction{"activateTHnSparseCosThStarProduction", false, "Activate the THnSparse with cosThStar w.r.t. production axis"}; + Configurable activateTHnSparseCosThStarBeam{"activateTHnSparseCosThStarBeam", false, "Activate the THnSparse with cosThStar w.r.t. beam axis (Gottified jackson frame)"}; + Configurable activateTHnSparseCosThStarRandom{"activateTHnSparseCosThStarRandom", false, "Activate the THnSparse with cosThStar w.r.t. random axis"}; + ConfigurableAxis configThnAxisPOL{"configThnAxisPOL", {20, -1.0, 1.0}, "Costheta axis"}; + // MC Configurable isMC{"isMC", false, "Run MC"}; Configurable avoidsplitrackMC{"avoidsplitrackMC", false, "avoid split track in MC"}; + TRandom* rn = new TRandom(); + void init(o2::framework::InitContext&) { - AxisSpec axisMult{cmultBins, cmultLow, cmultHigh}; - AxisSpec axisPt{cpTbins, cpTlow, cpThigh}; - AxisSpec axisMass{cMassbins, cMasslow, cMasshigh}; - histos.add("hCentrality", "Centrality distribution", kTH1F, {axisMult}); - histos.add("hVtxZ", "Vertex distribution in Z;Z (cm)", kTH1F, {{400, -20.0, 20.0}}); - histos.add("hNcontributor", "Number of primary vertex contributor", kTH1F, {{2000, 0.0f, 10000.0f}}); - histos.add("hEta", "Eta distribution", kTH1F, {{200, -1.0f, 1.0f}}); - histos.add("hDcaxy", "Dcaxy distribution", kTH1F, {{200, -1.0f, 1.0f}}); - histos.add("hDcaz", "Dcaz distribution", kTH1F, {{200, -1.0f, 1.0f}}); - histos.add("hNsigmaKaonTPC", "NsigmaKaon TPC distribution", kTH1F, {{200, -10.0f, 10.0f}}); - histos.add("hNsigmaKaonTOF", "NsigmaKaon TOF distribution", kTH1F, {{200, -10.0f, 10.0f}}); - if (!isMC) { - histos.add("h3PhiInvMassUnlikeSign", "Invariant mass of Phi meson Unlike Sign", kTHnSparseF, {axisMult, axisPt, axisMass}, true); - histos.add("h3PhiInvMassLikeSignPP", "Invariant mass of Phi meson Like Sign positive", kTHnSparseF, {axisMult, axisPt, axisMass}, true); - histos.add("h3PhiInvMassLikeSignMM", "Invariant mass of Phi meson Like Sign negative", kTHnSparseF, {axisMult, axisPt, axisMass}, true); - histos.add("h3PhiInvMassMixed", "Invariant mass of Phi meson Mixed", kTHnSparseF, {axisMult, axisPt, axisMass}, true); - histos.add("h3PhiInvMassRotation", "Invariant mass of Phi meson Rotation", kTHnSparseF, {axisMult, axisPt, axisMass}, true); - if (isEtaAssym) { - histos.add("h3PhiInvMassUnlikeSignAside", "Invariant mass of Phi meson Unlike Sign A side", kTHnSparseF, {axisMult, axisPt, axisMass}, true); - histos.add("h3PhiInvMassLikeSignAside", "Invariant mass of Phi meson Like Sign A side", kTHnSparseF, {axisMult, axisPt, axisMass}, true); - histos.add("h3PhiInvMassMixedAside", "Invariant mass of Phi meson Mixed A side", kTHnSparseF, {axisMult, axisPt, axisMass}, true); - histos.add("h3PhiInvMassUnlikeSignCside", "Invariant mass of Phi meson Unlike Sign C side", kTHnSparseF, {axisMult, axisPt, axisMass}, true); - histos.add("h3PhiInvMassLikeSignCside", "Invariant mass of Phi meson Like Sign C side", kTHnSparseF, {axisMult, axisPt, axisMass}, true); - histos.add("h3PhiInvMassMixedCside", "Invariant mass of Phi meson Mixed C side", kTHnSparseF, {axisMult, axisPt, axisMass}, true); + AxisSpec axisMult{cmultBins, cmultLow, cmultHigh, "Multiplicity"}; + AxisSpec axisPt{cpTbins, cpTlow, cpThigh, "pT (GeV/c)"}; + AxisSpec axisMass{cMassbins, cMasslow, cMasshigh, "Invariant mass (GeV/c^2)"}; + const AxisSpec thnAxisPOL{configThnAxisPOL, "Frame axis"}; + + // THnSparses + std::array sparses = {activateTHnSparseCosThStarHelicity, activateTHnSparseCosThStarProduction, activateTHnSparseCosThStarBeam, activateTHnSparseCosThStarRandom}; + + // std::array sparses = {activateTHnSparseCosThStarHelicity}; + + if (std::accumulate(sparses.begin(), sparses.end(), 0) == 0) { + LOGP(fatal, "No output THnSparses enabled"); + } else { + if (activateTHnSparseCosThStarHelicity) { + LOGP(info, "THnSparse with cosThStar w.r.t. helicity axis active."); + } + if (activateTHnSparseCosThStarProduction) { + LOGP(info, "THnSparse with cosThStar w.r.t. production axis active."); } + if (activateTHnSparseCosThStarBeam) { + LOGP(info, "THnSparse with cosThStar w.r.t. beam axis active. (Gottified jackson frame)"); + } + if (activateTHnSparseCosThStarRandom) { + LOGP(info, "THnSparse with cosThStar w.r.t. random axis active."); + } + } + + if (QAevents) { + histos.add("hmutiplicity", "Multiplicity percentile distribution", kTH1F, {axisMult}); + histos.add("hVtxZ", "Vertex distribution in Z;Z (cm)", kTH1F, {{400, -20.0, 20.0}}); + histos.add("hNcontributor", "Number of primary vertex contributor", kTH1F, {{2000, 0.0f, 10000.0f}}); + histos.add("multdist_FT0M", "FT0M Multiplicity distribution", kTH1F, {axisMultdist}); + histos.add("multdist_FT0A", "FT0A Multiplicity distribution", kTH1F, {axisMultdist}); + histos.add("multdist_FT0C", "FT0C Multiplicity distribution", kTH1F, {axisMultdist}); + } + + if (QAPID) { + histos.add("hEta", "Eta distribution", kTH1F, {{200, -1.0f, 1.0f}}); + histos.add("hDcaxy", "Dcaxy distribution", kTH1F, {{200, -1.0f, 1.0f}}); + histos.add("hDcaz", "Dcaz distribution", kTH1F, {{200, -1.0f, 1.0f}}); + histos.add("hNsigmaKaonTPC_before", "NsigmaKaon TPC distribution", kTH2F, {{axisPt}, {200, -10.0f, 10.0f}}); + histos.add("hNsigmaKaonTOF_before", "NsigmaKaon TOF distribution", kTH2F, {{axisPt}, {200, -10.0f, 10.0f}}); + // histos.add("hNsigmaKaonTPC_after", "NsigmaKaon TPC distribution", kTH2F, {{axisPt}, {200, -10.0f, 10.0f}}); + // histos.add("hNsigmaKaonTOF_after", "NsigmaKaon TOF distribution", kTH2F, {{axisPt}, {200, -10.0f, 10.0f}}); + histos.add("hNsigmaKaonTOF_TPC_before", "NsigmaKaon TOF-TPC distribution", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}); + // histos.add("hNsigmaKaonTOF_TPC_after", "NsigmaKaon TOF-TPC distribution", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}); + histos.add("dE_by_dx_TPC", "dE/dx signal in the TPC as a function of pT", kTH2F, {axisPtfordEbydx, axisdEdx}); + } + + if (otherQAplots) { + histos.add("hpTvsRapidity", "pT vs Rapidity", kTH2F, {{100, 0.0f, 10.0f}, {300, -1.5f, 1.5f}}); + histos.add("hFTOCvsTPCNoCut", "Mult correlation FT0C vs. TPC without any cut", kTH2F, {{80, 0.0f, 80.0f}, {100, -0.5f, 5999.5f}}); + histos.add("hFTOCvsTPC", "Mult correlation FT0C vs. TPC", kTH2F, {{80, 0.0f, 80.0f}, {100, -0.5f, 5999.5f}}); + histos.add("hFTOCvsTPCSelected", "Mult correlation FT0C vs. TPC after selection", kTH2F, {{80, 0.0f, 80.0f}, {100, -0.5f, 5999.5f}}); + + // chi2 plots + histos.add("Chi2perclusterITS", "Chi2 / cluster for the ITS track segment", kTH1F, {{50, 0.0f, 50.0f}}); + histos.add("Chi2perclusterTPC", "Chi2 / cluster for the TPC track segment", kTH1F, {{50, 0.0f, 50.0f}}); + histos.add("Chi2perclusterTRD", "Chi2 / cluster for the TRD track segment", kTH1F, {{50, 0.0f, 50.0f}}); + histos.add("Chi2perclusterTOF", "Chi2 / cluster for the TOF track segment", kTH1F, {{50, 0.0f, 50.0f}}); + } + if (!isMC) { + histos.add("h3PhiInvMassUnlikeSign", "KK Unlike Sign", kTHnSparseF, {axisMult, axisPt, axisMass, thnAxisPOL}, true); + histos.add("h3PhiInvMassLikeSignPP", "KK Like Sign +", kTHnSparseF, {axisMult, axisPt, axisMass, thnAxisPOL}, true); + histos.add("h3PhiInvMassLikeSignMM", "KK Like Sign -", kTHnSparseF, {axisMult, axisPt, axisMass, thnAxisPOL}, true); + histos.add("h3PhiInvMassMixed", "KK Mixed", kTHnSparseF, {axisMult, axisPt, axisMass, thnAxisPOL}, true); + histos.add("h3PhiInvMassRotation", "KK Rotation", kTHnSparseF, {axisMult, axisPt, axisMass, thnAxisPOL}, true); } else if (isMC) { histos.add("hMC", "MC Event statistics", kTH1F, {{6, 0.0f, 6.0f}}); histos.add("h1PhiGen", "Phi meson Gen", kTH1F, {axisPt}); @@ -155,11 +218,14 @@ struct phianalysisrun3 { double rapidity; double genMass, recMass, resolution; double mass{0.}; - double massrotation{0.}; + double massrotation1{0.}; + double massrotation2{0.}; double pT{0.}; array pvec0; array pvec1; array pvec1rotation; + array pvec2rotation; + ROOT::Math::PxPyPzMVector daughter1, daughter2; template bool eventselection(Collision const& collision, const float& multiplicity) @@ -244,61 +310,73 @@ struct phianalysisrun3 { } return true; } - template - void FillinvMass(const T1& candidate1, const T2& candidate2, float multiplicity, bool unlike, bool mix, bool likesign, bool rotation, float massd1, float massd2) + template + void FillinvMass(const T1& candidate1, const T2& candidate2, const T3& framecalculation, float multiplicity, bool unlike, bool mix, bool likesign, bool rotation, float massd1, float massd2) { - pvec0 = array{candidate1.px(), candidate1.py(), candidate1.pz()}; - pvec1 = array{candidate2.px(), candidate2.py(), candidate2.pz()}; - pvec1rotation = array{-candidate2.px(), -candidate2.py(), candidate2.pz()}; - auto arrMom = array{pvec0, pvec1}; - auto arrMomrotation = array{pvec0, pvec1rotation}; int track1Sign = candidate1.sign(); int track2Sign = candidate2.sign(); - mass = RecoDecay::m(arrMom, array{massd1, massd2}); - massrotation = RecoDecay::m(arrMomrotation, array{massd1, massd2}); - pT = RecoDecay::pt(array{candidate1.px() + candidate2.px(), candidate1.py() + candidate2.py()}); - rapidity = RecoDecay::y(array{candidate1.px() + candidate2.px(), candidate1.py() + candidate2.py(), candidate1.pz() + candidate2.pz()}, mass); - if (isEtaAssym && unlike && track1Sign * track2Sign < 0) { - if (candidate1.eta() > 0.2 && candidate1.eta() < 0.8 && candidate2.eta() > 0.2 && candidate2.eta() < 0.8) { - histos.fill(HIST("h3PhiInvMassUnlikeSignAside"), multiplicity, pT, mass); - } else if (candidate1.eta() > -0.6 && candidate1.eta() < 0.0 && candidate2.eta() > -0.6 && candidate2.eta() < 0.0) { - histos.fill(HIST("h3PhiInvMassUnlikeSignCside"), multiplicity, pT, mass); - } - } - if (isEtaAssym && mix && track1Sign * track2Sign < 0) { - if (candidate1.eta() > 0.2 && candidate1.eta() < 0.8 && candidate2.eta() > 0.2 && candidate2.eta() < 0.8) { - histos.fill(HIST("h3PhiInvMassMixedAside"), multiplicity, pT, mass); - } else if (candidate1.eta() > -0.6 && candidate1.eta() < 0.0 && candidate2.eta() > -0.6 && candidate2.eta() < 0.0) { - histos.fill(HIST("h3PhiInvMassMixedCside"), multiplicity, pT, mass); - } - } - if (isEtaAssym && likesign && track1Sign * track2Sign > 0) { - if (candidate1.eta() > 0.2 && candidate1.eta() < 0.8 && candidate2.eta() > 0.2 && candidate2.eta() < 0.8) { - histos.fill(HIST("h3PhiInvMassLikeSignAside"), multiplicity, pT, mass); - } else if (candidate1.eta() > -0.6 && candidate1.eta() < 0.0 && candidate2.eta() > -0.6 && candidate2.eta() < 0.0) { - histos.fill(HIST("h3PhiInvMassLikeSignCside"), multiplicity, pT, mass); - } + TLorentzVector vec1, vec2, vec3, vec4, vec5; + vec1.SetPtEtaPhiM(candidate1.pt(), candidate1.eta(), candidate1.phi(), massd1); + vec2.SetPtEtaPhiM(candidate2.pt(), candidate2.eta(), candidate2.phi(), massd2); + vec3 = vec1 + vec2; + // daughter1 = ROOT::Math::PxPyPzMVector(candidate1.px(), candidate1.py(), candidate1.pz(), massd1); // Kplus + // daughter2 = ROOT::Math::PxPyPzMVector(candidate2.px(), candidate2.py(), candidate2.pz(), massd2); // Kminus + double rapidity = vec3.Rapidity(); + + if (otherQAplots) { + histos.fill(HIST("Chi2perclusterITS"), candidate1.itsChi2NCl()); + histos.fill(HIST("Chi2perclusterITS"), candidate2.itsChi2NCl()); + histos.fill(HIST("Chi2perclusterTPC"), candidate1.tpcChi2NCl()); + histos.fill(HIST("Chi2perclusterTPC"), candidate2.tpcChi2NCl()); + histos.fill(HIST("Chi2perclusterTRD"), candidate1.trdChi2()); + histos.fill(HIST("Chi2perclusterTRD"), candidate2.trdChi2()); + histos.fill(HIST("Chi2perclusterTOF"), candidate1.tofChi2()); + histos.fill(HIST("Chi2perclusterTOF"), candidate2.tofChi2()); + } + if (QAPID) { + histos.fill(HIST("dE_by_dx_TPC"), candidate1.p(), candidate1.tpcSignal()); + histos.fill(HIST("dE_by_dx_TPC"), candidate2.p(), candidate2.tpcSignal()); } + // polarization calculations + // auto phiRandom = gRandom->Uniform(0.f, constants::math::TwoPI); + // auto thetaRandom = gRandom->Uniform(0.f, constants::math::PI); + // ROOT::Math::PxPyPzMVector fourVecDau = ROOT::Math::PxPyPzMVector(daughter1.Px(), daughter1.Py(), daughter1.Pz(), massd1); // Kaon + + // ROOT::Math::PxPyPzMVector fourVecMother = ROOT::Math::PxPyPzMVector(vec3.Px(), vec3.Py(), vec3.Pz(), vec3.M()); // mass of KaonKaon pair + // ROOT::Math::Boost boost{fourVecMother.BoostToCM()}; // boost mother to center of mass frame + // ROOT::Math::PxPyPzMVector fourVecDauCM = boost(fourVecDau); // boost the frame of daughter same as mother + // ROOT::Math::XYZVector threeVecDauCM = fourVecDauCM.Vect(); // get the 3 vector of daughter in the frame of mother + // default filling - if (std::abs(rapidity) < 0.5 && !isEtaAssym && track1Sign * track2Sign < 0) { + // if (activateTHnSparseCosThStarHelicity) { + // ROOT::Math::XYZVector helicityVec = fourVecMother.Vect(); // 3 vector of mother in COM frame + // auto cosThetaStarHelicity = helicityVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(helicityVec.Mag2())); + if (std::abs(rapidity) < 0.5 && track1Sign * track2Sign < 0) { if (unlike) { - histos.fill(HIST("h3PhiInvMassUnlikeSign"), multiplicity, pT, mass); + histos.fill(HIST("h3PhiInvMassUnlikeSign"), multiplicity, vec3.Pt(), vec3.M(), framecalculation); } if (mix) { - histos.fill(HIST("h3PhiInvMassMixed"), multiplicity, pT, mass); + histos.fill(HIST("h3PhiInvMassMixed"), multiplicity, vec3.Pt(), vec3.M(), framecalculation); } + if (rotation) { - histos.fill(HIST("h3PhiInvMassRotation"), multiplicity, pT, massrotation); + for (int i = 0; i < c_nof_rotations; i++) { + float theta2 = rn->Uniform(TMath::Pi() - TMath::Pi() / rotational_cut, TMath::Pi() + TMath::Pi() / rotational_cut); + vec4.SetPtEtaPhiM(candidate1.pt(), candidate1.eta(), candidate1.phi() + theta2, massd1); // for rotated background + vec5 = vec4 + vec2; + histos.fill(HIST("h3PhiInvMassRotation"), multiplicity, vec5.Pt(), vec5.M(), framecalculation); + } } } - if (std::abs(rapidity) < 0.5 && !isEtaAssym && track1Sign * track2Sign > 0 && likesign) { + if (std::abs(rapidity) < 0.5 && track1Sign * track2Sign > 0 && likesign) { if (track1Sign > 0 && track2Sign > 0) { - histos.fill(HIST("h3PhiInvMassLikeSignPP"), multiplicity, pT, mass); + histos.fill(HIST("h3PhiInvMassLikeSignPP"), multiplicity, vec3.Pt(), vec3.M(), framecalculation); } else { - histos.fill(HIST("h3PhiInvMassLikeSignMM"), multiplicity, pT, mass); + histos.fill(HIST("h3PhiInvMassLikeSignMM"), multiplicity, vec3.Pt(), vec3.M(), framecalculation); } } + // } } Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; @@ -306,28 +384,11 @@ struct phianalysisrun3 { Filter DCAcutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); using EventCandidates = soa::Filtered>; - using TrackCandidates = soa::Filtered>; + using TrackCandidates = soa::Filtered>; // using EventCandidatesMC = soa::Join; using EventCandidatesMC = soa::Join; - using TrackCandidatesMC = soa::Filtered>; - - ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for bin"}; - ConfigurableAxis axisMultiplicityClass{"axisMultiplicityClass", {20, 0, 100}, "multiplicity percentile for bin"}; - ConfigurableAxis axisMultiplicity{"axisMultiplicity", {2000, 0, 10000}, "TPC multiplicity for bin"}; - - // using BinningType = BinningPolicy>; - // BinningType binningOnPositions{{axisVertex, axisMultiplicityClass}, true}; - - // using BinningTypeTPCMultiplicity = ColumnBinningPolicy; - using BinningTypeVertexContributor = ColumnBinningPolicy; - // using BinningTypeCentrality = ColumnBinningPolicy; - - // using BinningType = ColumnBinningPolicy; - // BinningType binningOnPositions{{axisVertex, axisMultiplicity}, true}; + using TrackCandidatesMC = soa::Filtered>; void processSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) { @@ -335,22 +396,30 @@ struct phianalysisrun3 { return; } float multiplicity; - // if (cfgMultFT0) - multiplicity = collision.centFT0M(); - // if (!cfgMultFT0) - // multiplicity = collision.numContrib(); - histos.fill(HIST("hCentrality"), multiplicity); - histos.fill(HIST("hNcontributor"), collision.numContrib()); - histos.fill(HIST("hVtxZ"), collision.posZ()); + if (cfgMultFT0M == true) + multiplicity = collision.centFT0M(); + else + multiplicity = collision.centFT0C(); + if (QAevents) { + histos.fill(HIST("hmutiplicity"), multiplicity); + histos.fill(HIST("hVtxZ"), collision.posZ()); + histos.fill(HIST("hNcontributor"), collision.numContrib()); + histos.fill(HIST("multdist_FT0M"), collision.multFT0M()); + histos.fill(HIST("multdist_FT0A"), collision.multFT0A()); + histos.fill(HIST("multdist_FT0C"), collision.multFT0C()); + } for (auto track1 : tracks) { if (!selectionTrack(track1)) { continue; } - histos.fill(HIST("hEta"), track1.eta()); - histos.fill(HIST("hDcaxy"), track1.dcaXY()); - histos.fill(HIST("hDcaz"), track1.dcaZ()); - histos.fill(HIST("hNsigmaKaonTPC"), track1.tpcNSigmaKa()); - histos.fill(HIST("hNsigmaKaonTOF"), track1.tofNSigmaKa()); + if (QAPID) { + histos.fill(HIST("hEta"), track1.eta()); + histos.fill(HIST("hDcaxy"), track1.dcaXY()); + histos.fill(HIST("hDcaz"), track1.dcaZ()); + histos.fill(HIST("hNsigmaKaonTPC_before"), track1.pt(), track1.tpcNSigmaKa()); + histos.fill(HIST("hNsigmaKaonTOF_before"), track1.pt(), track1.tofNSigmaKa()); + histos.fill(HIST("hNsigmaKaonTOF_TPC_before"), track1.tofNSigmaKa(), track1.tpcNSigmaKa()); + } auto track1ID = track1.index(); for (auto track2 : tracks) { if (!selectionTrack(track2)) { @@ -363,65 +432,294 @@ struct phianalysisrun3 { if (!selectionPair(track1, track2)) { continue; } + + // calculation of event planes + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); // Kplus + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); // Kminus + + ROOT::Math::PxPyPzMVector fourVecDau = ROOT::Math::PxPyPzMVector(daughter1.Px(), daughter1.Py(), daughter1.Pz(), massKa); // Kaon + TLorentzVector lv1, lv2, lv3; + lv1.SetPtEtaPhiM(track1.pt(), track1.eta(), track1.phi(), massKa); + lv2.SetPtEtaPhiM(track2.pt(), track2.eta(), track2.phi(), massKa); + lv3 = lv1 + lv2; + + ROOT::Math::PxPyPzMVector fourVecMother = ROOT::Math::PxPyPzMVector(lv3.Px(), lv3.Py(), lv3.Pz(), lv3.M()); // mass of KaonKaon pair + ROOT::Math::Boost boost{fourVecMother.BoostToCM()}; // boost mother to center of mass frame + ROOT::Math::PxPyPzMVector fourVecDauCM = boost(fourVecDau); // boost the frame of daughter same as mother + ROOT::Math::XYZVector threeVecDauCM = fourVecDauCM.Vect(); // get the 3 vector of daughter in the frame of mother + bool unlike = true; bool mix = false; bool likesign = true; bool rotation = true; - if (isITSOnlycut) { - FillinvMass(track1, track2, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); - } - if (!isITSOnlycut && selectionPID(track1) && selectionPID(track2)) { - FillinvMass(track1, track2, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + if (activateTHnSparseCosThStarHelicity) { + ROOT::Math::XYZVector helicityVec = fourVecMother.Vect(); // 3 vector of mother in COM frame + auto cosThetaStarHelicity = helicityVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(helicityVec.Mag2())); + + if (isITSOnlycut) { + FillinvMass(track1, track2, cosThetaStarHelicity, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + if (!isITSOnlycut && selectionPID(track1) && selectionPID(track2)) { + FillinvMass(track1, track2, cosThetaStarHelicity, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + } else if (activateTHnSparseCosThStarProduction) { + ROOT::Math::XYZVector normalVec = ROOT::Math::XYZVector(lv3.Py(), -lv3.Px(), 0.f); + auto cosThetaStarProduction = normalVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(normalVec.Mag2())); + + if (isITSOnlycut) { + FillinvMass(track1, track2, cosThetaStarProduction, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + if (!isITSOnlycut && selectionPID(track1) && selectionPID(track2)) { + FillinvMass(track1, track2, cosThetaStarProduction, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + } else if (activateTHnSparseCosThStarBeam) { + ROOT::Math::XYZVector beamVec = ROOT::Math::XYZVector(0.f, 0.f, 1.f); + auto cosThetaStarBeam = beamVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + + if (isITSOnlycut) { + FillinvMass(track1, track2, cosThetaStarBeam, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + if (!isITSOnlycut && selectionPID(track1) && selectionPID(track2)) { + FillinvMass(track1, track2, cosThetaStarBeam, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + } else if (activateTHnSparseCosThStarRandom) { + auto phiRandom = gRandom->Uniform(0.f, constants::math::TwoPI); + auto thetaRandom = gRandom->Uniform(0.f, constants::math::PI); + ROOT::Math::XYZVector randomVec = ROOT::Math::XYZVector(std::sin(thetaRandom) * std::cos(phiRandom), std::sin(thetaRandom) * std::sin(phiRandom), std::cos(thetaRandom)); + auto cosThetaStarRandom = randomVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + + if (isITSOnlycut) { + FillinvMass(track1, track2, cosThetaStarRandom, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + if (!isITSOnlycut && selectionPID(track1) && selectionPID(track2)) { + FillinvMass(track1, track2, cosThetaStarRandom, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } } + + // if (!isITSOnlycut && selectionPID(track1) && selectionPID(track2)) { + // // histos.fill(HIST("hNsigmaKaonTPC_after"), track1.pt(), track1.tpcNSigmaKa()); + // // histos.fill(HIST("hNsigmaKaonTOF_after"), track1.pt(), track1.tofNSigmaKa()); + // // histos.fill(HIST("hNsigmaKaonTOF_TPC_after"), track1.tofNSigmaKa(), track1.tpcNSigmaKa()); + // } } } } - PROCESS_SWITCH(phianalysisrun3, processSameEvent, "Process Same event", false); + ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for bin"}; + ConfigurableAxis axisMultiplicityClass{"axisMultiplicityClass", {20, 0, 100}, "multiplicity percentile for bin"}; + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {2000, 0, 10000}, "TPC multiplicity for bin"}; + using BinningTypeVertexContributor1 = ColumnBinningPolicy; + using BinningTypeVertexContributor2 = ColumnBinningPolicy; + + PROCESS_SWITCH(kaonkaonAnalysisRun3, processSameEvent, "Process Same event", false); void processMixedEvent(EventCandidates const& collisions, TrackCandidates const& tracks) { auto tracksTuple = std::make_tuple(tracks); //////// currently mixing the event with similar TPC multiplicity //////// - BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicity}, true}; - SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; - for (auto& [c1, tracks1, c2, tracks2] : pair) { - if (!eventselection(c1, c1.centFT0M())) { - continue; - } - if (!eventselection(c2, c2.centFT0M())) { - continue; - } - float multiplicity; - // if (cfgMultFT0) - multiplicity = c1.centFT0M(); - // if (!cfgMultFT0) - // multiplicity = c1.numContrib(); - - for (auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - bool unlike = false; - bool mix = true; - bool likesign = false; - bool rotation = false; - if (!selectionTrack(t1)) { + BinningTypeVertexContributor1 binningOnPositions1{{axisVertex, axisMultiplicity}, true}; + BinningTypeVertexContributor2 binningOnPositions2{{axisVertex, axisMultiplicity}, true}; + SameKindPair pair1{binningOnPositions1, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; + SameKindPair pair2{binningOnPositions2, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; + if (cfgMultFT0M == true) { + for (auto& [c1, tracks1, c2, tracks2] : pair1) { + float multiplicity = c1.centFT0M(); + + if (!eventselection(c1, multiplicity)) { continue; } - if (!selectionTrack(t2)) { + if (!eventselection(c2, multiplicity)) { continue; } - if (!selectionPair(t1, t2)) { + + for (auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + bool unlike = false; + bool mix = true; + bool likesign = false; + bool rotation = false; + if (!selectionTrack(t1)) { + continue; + } + if (!selectionTrack(t2)) { + continue; + } + if (!selectionPair(t1, t2)) { + continue; + } + + // calculation of event planes + daughter1 = ROOT::Math::PxPyPzMVector(t1.px(), t1.py(), t1.pz(), massKa); // Kplus + daughter2 = ROOT::Math::PxPyPzMVector(t2.px(), t2.py(), t2.pz(), massKa); // Kminus + + ROOT::Math::PxPyPzMVector fourVecDau = ROOT::Math::PxPyPzMVector(daughter1.Px(), daughter1.Py(), daughter1.Pz(), massKa); // Kaon + TLorentzVector lv1, lv2, lv3; + lv1.SetPtEtaPhiM(t1.pt(), t1.eta(), t1.phi(), massKa); + lv2.SetPtEtaPhiM(t2.pt(), t2.eta(), t2.phi(), massKa); + lv3 = lv1 + lv2; + + ROOT::Math::PxPyPzMVector fourVecMother = ROOT::Math::PxPyPzMVector(lv3.Px(), lv3.Py(), lv3.Pz(), lv3.M()); // mass of KaonKaon pair + ROOT::Math::Boost boost{fourVecMother.BoostToCM()}; // boost mother to center of mass frame + ROOT::Math::PxPyPzMVector fourVecDauCM = boost(fourVecDau); // boost the frame of daughter same as mother + ROOT::Math::XYZVector threeVecDauCM = fourVecDauCM.Vect(); // get the 3 vector of daughter in the frame of mother + + if (activateTHnSparseCosThStarHelicity) { + ROOT::Math::XYZVector helicityVec = fourVecMother.Vect(); // 3 vector of mother in COM frame + auto cosThetaStarHelicity = helicityVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(helicityVec.Mag2())); + + if (isITSOnlycut) { + FillinvMass(t1, t2, cosThetaStarHelicity, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + if (!isITSOnlycut && selectionPID(t1) && selectionPID(t2)) { + FillinvMass(t1, t2, cosThetaStarHelicity, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + } else if (activateTHnSparseCosThStarProduction) { + ROOT::Math::XYZVector normalVec = ROOT::Math::XYZVector(lv3.Py(), -lv3.Px(), 0.f); + auto cosThetaStarProduction = normalVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(normalVec.Mag2())); + + if (isITSOnlycut) { + FillinvMass(t1, t2, cosThetaStarProduction, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + if (!isITSOnlycut && selectionPID(t1) && selectionPID(t2)) { + FillinvMass(t1, t2, cosThetaStarProduction, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + } else if (activateTHnSparseCosThStarBeam) { + ROOT::Math::XYZVector beamVec = ROOT::Math::XYZVector(0.f, 0.f, 1.f); + auto cosThetaStarBeam = beamVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + + if (isITSOnlycut) { + FillinvMass(t1, t2, cosThetaStarBeam, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + if (!isITSOnlycut && selectionPID(t1) && selectionPID(t2)) { + FillinvMass(t1, t2, cosThetaStarBeam, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + } else if (activateTHnSparseCosThStarRandom) { + auto phiRandom = gRandom->Uniform(0.f, constants::math::TwoPI); + auto thetaRandom = gRandom->Uniform(0.f, constants::math::PI); + ROOT::Math::XYZVector randomVec = ROOT::Math::XYZVector(std::sin(thetaRandom) * std::cos(phiRandom), std::sin(thetaRandom) * std::sin(phiRandom), std::cos(thetaRandom)); + auto cosThetaStarRandom = randomVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + + if (isITSOnlycut) { + FillinvMass(t1, t2, cosThetaStarRandom, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + if (!isITSOnlycut && selectionPID(t1) && selectionPID(t2)) { + FillinvMass(t1, t2, cosThetaStarRandom, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + } + + // if (!isITSOnlycut && selectionPID(t1) && selectionPID(t2)) { + // histos.fill(HIST("hNsigmaKaonTPC_after"), t1.pt(), t1.tpcNSigmaKa()); + // histos.fill(HIST("hNsigmaKaonTOF_after"), t1.pt(), t1.tofNSigmaKa()); + // histos.fill(HIST("hNsigmaKaonTOF_TPC_after"), t1.tofNSigmaKa(), t1.tpcNSigmaKa()); + // } + // if (isITSOnlycut) { + // FillinvMass(t1, t2, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + // } + // if (!isITSOnlycut && selectionPID(t1) && selectionPID(t2)) { + // FillinvMass(t1, t2, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + // } + } + } + } else { + for (auto& [c1, tracks1, c2, tracks2] : pair2) { + float multiplicity = c1.centFT0C(); + + if (!eventselection(c1, multiplicity)) { continue; } - if (isITSOnlycut) { - FillinvMass(t1, t2, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + if (!eventselection(c2, multiplicity)) { + continue; } - if (!isITSOnlycut && selectionPID(t1) && selectionPID(t2)) { - FillinvMass(t1, t2, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + for (auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + bool unlike = false; + bool mix = true; + bool likesign = false; + bool rotation = false; + if (!selectionTrack(t1)) { + continue; + } + if (!selectionTrack(t2)) { + continue; + } + if (!selectionPair(t1, t2)) { + continue; + } + + // calculation of event planes + daughter1 = ROOT::Math::PxPyPzMVector(t1.px(), t1.py(), t1.pz(), massKa); // Kplus + daughter2 = ROOT::Math::PxPyPzMVector(t2.px(), t2.py(), t2.pz(), massKa); // Kminus + + ROOT::Math::PxPyPzMVector fourVecDau = ROOT::Math::PxPyPzMVector(daughter1.Px(), daughter1.Py(), daughter1.Pz(), massKa); // Kaon + TLorentzVector lv1, lv2, lv3; + lv1.SetPtEtaPhiM(t1.pt(), t1.eta(), t1.phi(), massKa); + lv2.SetPtEtaPhiM(t2.pt(), t2.eta(), t2.phi(), massKa); + lv3 = lv1 + lv2; + + ROOT::Math::PxPyPzMVector fourVecMother = ROOT::Math::PxPyPzMVector(lv3.Px(), lv3.Py(), lv3.Pz(), lv3.M()); // mass of KaonKaon pair + ROOT::Math::Boost boost{fourVecMother.BoostToCM()}; // boost mother to center of mass frame + ROOT::Math::PxPyPzMVector fourVecDauCM = boost(fourVecDau); // boost the frame of daughter same as mother + ROOT::Math::XYZVector threeVecDauCM = fourVecDauCM.Vect(); // get the 3 vector of daughter in the frame of mother + + if (activateTHnSparseCosThStarHelicity) { + ROOT::Math::XYZVector helicityVec = fourVecMother.Vect(); // 3 vector of mother in COM frame + auto cosThetaStarHelicity = helicityVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(helicityVec.Mag2())); + + if (isITSOnlycut) { + FillinvMass(t1, t2, cosThetaStarHelicity, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + if (!isITSOnlycut && selectionPID(t1) && selectionPID(t2)) { + FillinvMass(t1, t2, cosThetaStarHelicity, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + } else if (activateTHnSparseCosThStarProduction) { + ROOT::Math::XYZVector normalVec = ROOT::Math::XYZVector(lv3.Py(), -lv3.Px(), 0.f); + auto cosThetaStarProduction = normalVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(normalVec.Mag2())); + + if (isITSOnlycut) { + FillinvMass(t1, t2, cosThetaStarProduction, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + if (!isITSOnlycut && selectionPID(t1) && selectionPID(t2)) { + FillinvMass(t1, t2, cosThetaStarProduction, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + } else if (activateTHnSparseCosThStarBeam) { + ROOT::Math::XYZVector beamVec = ROOT::Math::XYZVector(0.f, 0.f, 1.f); + auto cosThetaStarBeam = beamVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + + if (isITSOnlycut) { + FillinvMass(t1, t2, cosThetaStarBeam, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + if (!isITSOnlycut && selectionPID(t1) && selectionPID(t2)) { + FillinvMass(t1, t2, cosThetaStarBeam, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + } else if (activateTHnSparseCosThStarRandom) { + auto phiRandom = gRandom->Uniform(0.f, constants::math::TwoPI); + auto thetaRandom = gRandom->Uniform(0.f, constants::math::PI); + ROOT::Math::XYZVector randomVec = ROOT::Math::XYZVector(std::sin(thetaRandom) * std::cos(phiRandom), std::sin(thetaRandom) * std::sin(phiRandom), std::cos(thetaRandom)); + auto cosThetaStarRandom = randomVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + + if (isITSOnlycut) { + FillinvMass(t1, t2, cosThetaStarRandom, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + if (!isITSOnlycut && selectionPID(t1) && selectionPID(t2)) { + FillinvMass(t1, t2, cosThetaStarRandom, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + } + } + + // if (!isITSOnlycut && selectionPID(t1) && selectionPID(t2)) { + // histos.fill(HIST("hNsigmaKaonTPC_after"), t1.pt(), t1.tpcNSigmaKa()); + // histos.fill(HIST("hNsigmaKaonTOF_after"), t1.pt(), t1.tofNSigmaKa()); + // histos.fill(HIST("hNsigmaKaonTOF_TPC_after"), t1.tofNSigmaKa(), t1.tpcNSigmaKa()); + // } + + // if (isITSOnlycut) { + // FillinvMass(t1, t2, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + // } + // if (!isITSOnlycut && selectionPID(t1) && selectionPID(t2)) { + // FillinvMass(t1, t2, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + // } } } } } - PROCESS_SWITCH(phianalysisrun3, processMixedEvent, "Process Mixed event", false); + PROCESS_SWITCH(kaonkaonAnalysisRun3, processMixedEvent, "Process Mixed event", false); void processGen(aod::McCollision const& mcCollision, aod::McParticles& mcParticles, const soa::SmallGroups& collisions) { histos.fill(HIST("hMC"), 0.5); @@ -483,7 +781,7 @@ struct phianalysisrun3 { } } - PROCESS_SWITCH(phianalysisrun3, processGen, "Process Generated", false); + PROCESS_SWITCH(kaonkaonAnalysisRun3, processGen, "Process Generated", false); void processRec(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) { if (!collision.has_mcCollision()) { @@ -572,10 +870,10 @@ struct phianalysisrun3 { } } - PROCESS_SWITCH(phianalysisrun3, processRec, "Process Reconstructed", false); + PROCESS_SWITCH(kaonkaonAnalysisRun3, processRec, "Process Reconstructed", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"phianalysisrun3"})}; + adaptAnalysisTask(cfgc, TaskName{"kaonkaonAnalysisRun3"})}; } diff --git a/PWGLF/Tasks/Resonances/kshortlambda.cxx b/PWGLF/Tasks/Resonances/kshortlambda.cxx new file mode 100644 index 00000000000..225ea15e447 --- /dev/null +++ b/PWGLF/Tasks/Resonances/kshortlambda.cxx @@ -0,0 +1,943 @@ +// 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 kshortlambda.cxx +/// \brief higher mass resonance search in non-identical V0 pairs (K0s-L) +/// \author dukhishyam Mallick (dukhishyam.mallick@cern.ch) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "TF1.h" +#include "TRandom3.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/StepTHn.h" +#include "ReconstructionDataFormats/Track.h" +#include "Framework/O2DatabasePDGPlugin.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" // +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" // +#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" // +#include "Framework/runDataProcessing.h" // +#include "PWGLF/DataModel/LFStrangenessTables.h" // + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +// using namespace o2::constants::physics; +using std::array; + +struct Kshortlambda { + SliceCache cache; + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rKzeroShort{"kzeroShort", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry hvzero{"hvzeroball", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + Configurable qAv0{"qAv0", false, "qAv0"}; + Configurable qAPID{"qAPID", true, "qAPID"}; + Configurable qAv0daughters{"qAv0daughters", false, "qA of v0 daughters"}; + Configurable qAevents{"qAevents", false, "QA of events"}; + Configurable invMass1D{"invMass1D", false, "1D invariant mass histograms"}; + Configurable correlation2Dhist{"correlation2Dhist", true, "Lamda K0 mass correlation"}; + Configurable cDCAv0topv{"cDCAv0topv", false, "DCA V0 to PV"}; + Configurable armcut{"armcut", true, "arm cut"}; + Configurable globalTracks{"globalTracks", false, "Global tracks"}; + Configurable hasTPC{"hasTPC", false, "TPC"}; + + // Configurable for event selection + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable cfgETAcut{"cfgETAcut", 0.8f, "Track ETA cut"}; + Configurable timFrameEvsel{"timFrameEvsel", false, "TPC Time frame boundary cut"}; + Configurable piluprejection{"piluprejection", false, "Pileup rejection"}; + Configurable goodzvertex{"goodzvertex", false, "removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference."}; + Configurable itstpctracks{"itstpctracks", false, "selects collisions with at least one ITS-TPC track,"}; + Configurable additionalEvsel{"additionalEvsel", false, "Additional event selcection"}; + Configurable applyOccupancyCut{"applyOccupancyCut", false, "Apply occupancy cut"}; + Configurable occupancyCut{"occupancyCut", 1000, "Mimimum Occupancy cut"}; + + // Configurable parameters for V0 selection + Configurable confV0DCADaughMax{"confV0DCADaughMax", 1.0f, "DCA b/w V0 daughters"}; + Configurable v0settingdcapostopv{"v0settingdcapostopv", 0.06, "DCA Pos To PV"}; + Configurable v0settingdcanegtopv{"v0settingdcanegtopv", 0.06, "DCA Neg To PV"}; + Configurable cMaxV0DCA{"cMaxV0DCA", 1, "DCA V0 to PV"}; + // Configurable isStandarv0{"isStandarv0", false, "Standard V0"}; + // Configurable ConfDaughDCAMin{"ConfDaughDCAMin", 0.06f, "V0 Daugh sel: Max. DCA Daugh to PV (cm)"}; // same as DCA pos to pv and neg to pv + + Configurable confV0PtMin{"confV0PtMin", 0.f, "Minimum transverse momentum of V0"}; + Configurable confV0CPAMin{"confV0CPAMin", 0.97f, "Minimum CPA of V0"}; + Configurable confV0TranRadV0Min{"confV0TranRadV0Min", 0.5f, "Minimum transverse radius"}; + Configurable confV0TranRadV0Max{"confV0TranRadV0Max", 200.f, "Maximum transverse radius"}; + Configurable cMaxV0LifeTime{"cMaxV0LifeTime", 15, "Maximum V0 life time"}; + Configurable cSigmaMassKs0{"cSigmaMassKs0", 4, "n Sigma cut on Ks0 mass (Mass (Ks) - cSigmaMassKs0*cWidthKs0)"}; + Configurable cWidthKs0{"cWidthKs0", 0.005, "Width of KS0"}; + Configurable confDaughEta{"confDaughEta", 0.8f, "V0 Daugh sel: max eta"}; + Configurable confDaughTPCnclsMin{"confDaughTPCnclsMin", 70.f, "V0 Daugh sel: Min. nCls TPC"}; + Configurable confDaughPIDCuts{"confDaughPIDCuts", 5, "PID selections for KS0 daughters"}; + Configurable confarmcut{"confarmcut", 0.2f, "Armenteros cut"}; + Configurable confKsrapidity{"confKsrapidity", 0.5f, "Rapidity cut on K0s"}; + + // Configurable lowmasscutks0{"lowmasscutks0", 0.497 - 4 * 0.005, "Low mass cut on K0s"}; + // Configurable highmasscutks0{"highmasscutks0", 0.497 + 4 * 0.005, "High mass cut on K0s"}; + + // Configurable for track selection and multiplicity + Configurable cfgPTcut{"cfgPTcut", 0.2f, "Track PT cut"}; + Configurable cfgNmixedEvents{"cfgNmixedEvents", 5, "Number of mixed events"}; + Configurable cfgMultFOTM{"cfgMultFOTM", true, "Use FOTM multiplicity if pp else use 0 here for PbPb (FT0C)"}; + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 5., 10., 30., 50., 70., 100., 110., 150.}, "Binning of the centrality axis"}; + + // output THnSparses + Configurable activateTHnSparseCosThStarHelicity{"activateTHnSparseCosThStarHelicity", false, "Activate the THnSparse with cosThStar w.r.t. helicity axis"}; + Configurable activateTHnSparseCosThStarProduction{"activateTHnSparseCosThStarProduction", false, "Activate the THnSparse with cosThStar w.r.t. production axis"}; + Configurable activateTHnSparseCosThStarBeam{"activateTHnSparseCosThStarBeam", true, "Activate the THnSparse with cosThStar w.r.t. beam axis (Gottified jackson frame)"}; + Configurable activateTHnSparseCosThStarRandom{"activateTHnSparseCosThStarRandom", false, "Activate the THnSparse with cosThStar w.r.t. random axis"}; + Configurable cnofrotations{"cnofrotations", 3, "Number of random rotations in the rotational background"}; + + // Other cuts on Ks and glueball + Configurable rapidityks{"rapidityks", true, "rapidity cut on K0s"}; + Configurable applyCompetingcut{"applyCompetingcut", false, "Competing cascade rejection cut"}; + Configurable competingCascrejlambda{"competingCascrejlambda", 0.005, "rejecting competing cascade lambda"}; + Configurable competingCascrejlambdaanti{"competingCascrejlambdaanti", 0.005, "rejecting competing cascade anti-lambda"}; // If one of the pions is misidentified as a proton, then instead of Ks we reconstruct lambda, therefore the competing cascade rejection cut is applied in which if the reconstrcted mass of a pion and proton (which we are assuming to be misidentified as proton) is close to lambda or anti-lambda, then the track is rejected. + Configurable tpcCrossedrows{"tpcCrossedrows", 70, "TPC crossed rows"}; + Configurable tpcCrossedrowsOverfcls{"tpcCrossedrowsOverfcls", 0.8, "TPC crossed rows over findable clusters"}; + + // Mass and pT axis as configurables + Configurable cPtMin{"cPtMin", 0.0f, "Minimum pT"}; + Configurable cPtMax{"cPtMax", 50.0f, "Maximum pT"}; + Configurable cPtBins{"cPtBins", 500, "Number of pT bins"}; + Configurable cMassMin{"cMassMin", 0.9f, "Minimum mass bin"}; + Configurable cMassMax{"cMassMax", 3.0f, "Maximum mass bin"}; + Configurable cMassBins{"cMassBins", 210, "Number of mass binsl"}; + Configurable ksMassMin{"ksMassMin", 0.45f, "Minimum mass of K0s"}; + Configurable ksMassMax{"ksMassMax", 0.55f, "Maximum mass of K0s"}; + Configurable ksMassBins{"ksMassBins", 200, "Number of mass bins for K0s"}; + Configurable rotationalCut{"rotationalCut", 10, "Cut value (Rotation angle pi - pi/cut and pi + pi/cut)"}; + ConfigurableAxis configThnAxisPOL{"configThnAxisPOL", {20, -1.0, 1.0}, "Costheta axis"}; + ConfigurableAxis axisdEdx{"axisdEdx", {20000, 0.0f, 200.0f}, "dE/dx (a.u.)"}; + ConfigurableAxis axisPtfordEbydx{"axisPtfordEbydx", {2000, 0, 20}, "pT (GeV/c)"}; + ConfigurableAxis axisMultdist{"axisMultdist", {3500, 0, 70000}, "Multiplicity distribution"}; + ConfigurableAxis occupancyBins{"occupancyBins", {VARIABLE_WIDTH, 0.0, 100, 500, 600, 1000, 1100, 1500, 1600, 2000, 2100, 2500, 2600, 3000, 3100, 3500, 3600, 4000, 4100, 4500, 4600, 5000, 5100, 9999}, "Binning of the occupancy axis"}; + + // Event selection cuts - Alex (Temporary, need to fix!) + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + TF1* fMultCutLow = nullptr; + TF1* fMultCutHigh = nullptr; + TF1* fMultMultPVCut = nullptr; + + TRandom* rn = new TRandom(); + + void init(InitContext const&) + { + // Axes + AxisSpec k0ShortMassAxis = {ksMassBins, ksMassMin, ksMassMax, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec vzeroMassAxis = {cMassBins, cMassMin, cMassMax, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec vertexZAxis = {60, -15.f, 15.f, "vrtx_{Z} [cm]"}; // for histogram + AxisSpec ptAxis = {cPtBins, cPtMin, cPtMax, "#it{p}_{T} (GeV/#it{c})"}; + // AxisSpec multiplicityAxis = {110, 0.0f, 150.0f, "Multiplicity Axis"}; + AxisSpec multiplicityAxis = {binsCent, "Multiplicity Axis"}; + AxisSpec thnAxisPOL{configThnAxisPOL, "Configurabel theta axis"}; + AxisSpec occupancyAxis = {occupancyBins, "Occupancy [-40,100]"}; + + // THnSparses + std::array sparses = {activateTHnSparseCosThStarHelicity, activateTHnSparseCosThStarProduction, activateTHnSparseCosThStarBeam, activateTHnSparseCosThStarRandom}; + // std::array sparses = {activateTHnSparseCosThStarHelicity}; + if (std::accumulate(sparses.begin(), sparses.end(), 0) == 0) { + LOGP(fatal, "No output THnSparses enabled"); + } else { + if (activateTHnSparseCosThStarHelicity) { + LOGP(info, "THnSparse with cosThStar w.r.t. helicity axis active."); + } + if (activateTHnSparseCosThStarProduction) { + LOGP(info, "THnSparse with cosThStar w.r.t. production axis active."); + } + if (activateTHnSparseCosThStarBeam) { + LOGP(info, "THnSparse with cosThStar w.r.t. beam axis active. (Gottified jackson frame)"); + } + if (activateTHnSparseCosThStarRandom) { + LOGP(info, "THnSparse with cosThStar w.r.t. random axis active."); + } + } + + // Event selection + if (qAevents) { + rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); + rEventSelection.add("hmultiplicity", "multiplicity percentile distribution", {HistType::kTH1F, {{150, 0.0f, 150.0f}}}); + rEventSelection.add("multdist_FT0M", "FT0M Multiplicity distribution", kTH1F, {axisMultdist}); + rEventSelection.add("multdist_FT0A", "FT0A Multiplicity distribution", kTH1F, {axisMultdist}); + rEventSelection.add("multdist_FT0C", "FT0C Multiplicity distribution", kTH1F, {axisMultdist}); + rEventSelection.add("hNcontributor", "Number of primary vertex contributor", kTH1F, {{2000, 0.0f, 10000.0f}}); + } + + if (invMass1D) { + hvzero.add("h3vzeropairInvMassDS", "h1vzeropairInvMassDS", kTH1F, {vzeroMassAxis}); + hvzero.add("h3vzeropairInvMassME", "h1vzeropairInvMassME", kTH1F, {vzeroMassAxis}); + hvzero.add("h3vzeropairInvMassRot", "h1vzeropairInvMassRot", kTH1F, {vzeroMassAxis}); + } + hvzero.add("h3vzeropairInvMassDS", "h3vzeropairInvMassDS", kTHnSparseF, {multiplicityAxis, ptAxis, vzeroMassAxis, thnAxisPOL, occupancyAxis}, true); + hvzero.add("h3vzeropairInvMassME", "h3vzeropairInvMassME", kTHnSparseF, {multiplicityAxis, ptAxis, vzeroMassAxis, thnAxisPOL, occupancyAxis}, true); + hvzero.add("h3vzeropairInvMassRot", "h3vzeropairInvMassRot", kTHnSparseF, {multiplicityAxis, ptAxis, vzeroMassAxis, thnAxisPOL, occupancyAxis}, true); + hvzero.add("heventscheck", "heventscheck", kTH1I, {{10, 0, 10}}); + hvzero.add("htrackscheckv0", "htrackscheckv0", kTH1I, {{15, 0, 15}}); + hvzero.add("htrackscheckv0daughters", "htrackscheckv0daughters", kTH1I, {{15, 0, 15}}); + + // K0s topological/PID cuts + if (correlation2Dhist) { + rKzeroShort.add("mass_lambda_kshort_before", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + rKzeroShort.add("mass_lambda_kshort_after1", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + rKzeroShort.add("mass_lambda_kshort_after2", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + rKzeroShort.add("mass_lambda_kshort_after3", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + rKzeroShort.add("mass_lambda_kshort_after4", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + rKzeroShort.add("mass_lambda_kshort_after5", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + rKzeroShort.add("mass_lambda_kshort_after6", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + rKzeroShort.add("mass_lambda_kshort_after7", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + rKzeroShort.add("mass_lambda_kshort_after8", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + rKzeroShort.add("mass_lambda_kshort_after9", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + rKzeroShort.add("mass_lambda_kshort_after10", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); + } + if (qAv0) { + // Invariant Mass + rKzeroShort.add("hMassK0Shortbefore", "hMassK0Shortbefore", kTHnSparseF, {k0ShortMassAxis, ptAxis}); + rKzeroShort.add("hMasscorrelationbefore", "hMasscorrelationbefore", kTH2F, {k0ShortMassAxis, k0ShortMassAxis}); + rKzeroShort.add("hMassK0ShortSelected", "hMassK0ShortSelected", kTHnSparseF, {k0ShortMassAxis, ptAxis}); + + // Topological histograms (after the selection) + rKzeroShort.add("hDCAV0Daughters", "DCA between v0 daughters", {HistType::kTH1F, {{60, -3.0f, 3.0f}}}); + rKzeroShort.add("hV0CosPA", "hV0CosPA", {HistType::kTH1F, {{100, 0.96f, 1.1f}}}); + rKzeroShort.add("hLT", "hLT", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); + rKzeroShort.add("Mass_lambda", "Mass under lambda hypothesis", kTH1F, {vzeroMassAxis}); + rKzeroShort.add("mass_AntiLambda", "Mass under anti-lambda hypothesis", kTH1F, {vzeroMassAxis}); + rKzeroShort.add("mass_Gamma", "Mass under Gamma hypothesis", kTH1F, {vzeroMassAxis}); + + rKzeroShort.add("rapidity", "Rapidity distribution", kTH1F, {{100, -1.0f, 1.0f}}); + rKzeroShort.add("hv0radius", "hv0radius", kTH1F, {{100, 0.0f, 200.0f}}); + rKzeroShort.add("hDCApostopv", "DCA positive daughter to PV", kTH1F, {{1000, -10.0f, 10.0f}}); + rKzeroShort.add("hDCAnegtopv", "DCA negative daughter to PV", kTH1F, {{1000, -10.0f, 10.0f}}); + rKzeroShort.add("hDCAv0topv", "DCA V0 to PV", kTH1F, {{60, -3.0f, 3.0f}}); + rKzeroShort.add("halpha", "Armenteros alpha", kTH1F, {{100, -5.0f, 5.0f}}); + rKzeroShort.add("hqtarmbyalpha", "qtarm/alpha", kTH1F, {{100, 0.0f, 1.0f}}); + rKzeroShort.add("hpsipair", "psi pair angle", kTH1F, {{100, -5.0f, 5.0f}}); + rKzeroShort.add("NksProduced", "Number of K0s produced", kTH1I, {{15, 0, 15}}); + } + if (qAPID) { + rKzeroShort.add("hNSigmaPosPionK0s_before", "hNSigmaPosPionK0s_before", {HistType::kTH2F, {{ptAxis}, {100, -5.f, 5.f}}}); + rKzeroShort.add("hNSigmaNegPionK0s_before", "hNSigmaNegPionK0s_before", {HistType::kTH2F, {{ptAxis}, {100, -5.f, 5.f}}}); + rKzeroShort.add("dE_by_dx_TPC", "dE/dx signal in the TPC as a function of pT", kTH2F, {axisPtfordEbydx, axisdEdx}); + } + if (qAv0daughters) { + rKzeroShort.add("negative_pt", "Negative daughter pT", kTH1F, {ptAxis}); + rKzeroShort.add("positive_pt", "Positive daughter pT", kTH1F, {ptAxis}); + rKzeroShort.add("negative_eta", "Negative daughter eta", kTH1F, {{100, -1.0f, 1.0f}}); + rKzeroShort.add("positive_eta", "Positive daughter eta", kTH1F, {{100, -1.0f, 1.0f}}); + rKzeroShort.add("negative_phi", "Negative daughter phi", kTH1F, {{70, 0.0f, 7.0f}}); + rKzeroShort.add("positive_phi", "Positive daughter phi", kTH1F, {{70, 0.0f, 7.0f}}); + } + if (additionalEvsel) { + fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultPVCutLow->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05); + fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultPVCutHigh->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05); + // fMultCutLow = new TF1("fMultCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.5*([4]+[5]*x)", 0, 100); + // fMultCutLow->SetParameters(1893.94, -53.86, 0.502913, -0.0015122, 109.625, -1.19253); + // fMultCutHigh = new TF1("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 3.*([4]+[5]*x)", 0, 100); + // fMultCutHigh->SetParameters(1893.94, -53.86, 0.502913, -0.0015122, 109.625, -1.19253); + // fMultMultPVCut = new TF1("fMultMultPVCut", "[0]+[1]*x+[2]*x*x", 0, 5000); + // fMultMultPVCut->SetParameters(-0.1, 0.785, -4.7e-05); + } + } + + template + bool eventselection(Collision const& collision, float& multiplicity) + { + hvzero.fill(HIST("heventscheck"), 1.5); + + if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + return false; + } + hvzero.fill(HIST("heventscheck"), 2.5); + + if (!collision.sel8()) { + return false; + } + hvzero.fill(HIST("heventscheck"), 3.5); + + if (piluprejection && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + hvzero.fill(HIST("heventscheck"), 4.5); + + if (goodzvertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + hvzero.fill(HIST("heventscheck"), 5.5); + + if (itstpctracks && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + hvzero.fill(HIST("heventscheck"), 6.5); + + auto multNTracksPV = collision.multNTracksPV(); + if (additionalEvsel && multNTracksPV < fMultPVCutLow->Eval(multiplicity)) { + return false; + } + hvzero.fill(HIST("heventscheck"), 7.5); + if (additionalEvsel && multNTracksPV > fMultPVCutHigh->Eval(multiplicity)) { + return false; + } + hvzero.fill(HIST("heventscheck"), 8.5); + + return true; + } + + template + bool selectionV0(Collision const& collision, V0 const& candidate, float /*multiplicity*/) + { + const float qtarm = candidate.qtarm(); + const float alph = candidate.alpha(); + float arm = qtarm / alph; + const float pT = candidate.pt(); + const float tranRad = candidate.v0radius(); + const float dcaDaughv0 = candidate.dcaV0daughters(); + const float cpav0 = candidate.v0cosPA(); + + float ctauK0s = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short; + float lowmasscutks0 = 0.497 - cWidthKs0 * cSigmaMassKs0; + float highmasscutks0 = 0.497 + cWidthKs0 * cSigmaMassKs0; + // float decayLength = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * RecoDecay::sqrtSumOfSquares(candidate.px(), candidate.py(), candidate.pz()); + + if (qAv0) { + rKzeroShort.fill(HIST("hMassK0Shortbefore"), candidate.mK0Short(), candidate.pt()); + rKzeroShort.fill(HIST("hMasscorrelationbefore"), candidate.mK0Short(), candidate.mK0Short()); + rKzeroShort.fill(HIST("hLT"), ctauK0s); + rKzeroShort.fill(HIST("hDCAV0Daughters"), candidate.dcaV0daughters()); + rKzeroShort.fill(HIST("hV0CosPA"), candidate.v0cosPA()); + rKzeroShort.fill(HIST("Mass_lambda"), candidate.mLambda()); + rKzeroShort.fill(HIST("mass_AntiLambda"), candidate.mAntiLambda()); + rKzeroShort.fill(HIST("mass_Gamma"), candidate.mGamma()); + rKzeroShort.fill(HIST("rapidity"), candidate.yK0Short()); + rKzeroShort.fill(HIST("hv0radius"), candidate.v0radius()); + rKzeroShort.fill(HIST("hDCApostopv"), candidate.dcapostopv()); + rKzeroShort.fill(HIST("hDCAnegtopv"), candidate.dcanegtopv()); + rKzeroShort.fill(HIST("hDCAv0topv"), candidate.dcav0topv()); + rKzeroShort.fill(HIST("halpha"), candidate.alpha()); + rKzeroShort.fill(HIST("hqtarmbyalpha"), arm); + rKzeroShort.fill(HIST("hpsipair"), candidate.psipair()); + } + if (correlation2Dhist) + rKzeroShort.fill(HIST("mass_lambda_kshort_before"), candidate.mK0Short(), candidate.mLambda()); + + hvzero.fill(HIST("htrackscheckv0"), 0.5); + + if (cDCAv0topv && std::fabs(candidate.dcav0topv()) > cMaxV0DCA) { + return false; + } + hvzero.fill(HIST("htrackscheckv0"), 1.5); + if (correlation2Dhist) + rKzeroShort.fill(HIST("mass_lambda_kshort_after1"), candidate.mK0Short(), candidate.mLambda()); + + if (rapidityks && std::abs(candidate.yK0Short()) >= confKsrapidity) { + return false; + } + hvzero.fill(HIST("htrackscheckv0"), 2.5); + if (correlation2Dhist) + rKzeroShort.fill(HIST("mass_lambda_kshort_after2"), candidate.mK0Short(), candidate.mLambda()); + + if (pT < confV0PtMin) { + return false; + } + hvzero.fill(HIST("htrackscheckv0"), 3.5); + if (correlation2Dhist) + rKzeroShort.fill(HIST("mass_lambda_kshort_after3"), candidate.mK0Short(), candidate.mLambda()); + + if (dcaDaughv0 > confV0DCADaughMax) { + return false; + } + hvzero.fill(HIST("htrackscheckv0"), 4.5); + if (correlation2Dhist) + rKzeroShort.fill(HIST("mass_lambda_kshort_after4"), candidate.mK0Short(), candidate.mLambda()); + + if (cpav0 < confV0CPAMin) { + return false; + } + hvzero.fill(HIST("htrackscheckv0"), 5.5); + if (correlation2Dhist) + rKzeroShort.fill(HIST("mass_lambda_kshort_after5"), candidate.mK0Short(), candidate.mLambda()); + + if (tranRad < confV0TranRadV0Min) { + return false; + } + hvzero.fill(HIST("htrackscheckv0"), 6.5); + if (correlation2Dhist) + rKzeroShort.fill(HIST("mass_lambda_kshort_after6"), candidate.mK0Short(), candidate.mLambda()); + + if (tranRad > confV0TranRadV0Max) { + return false; + } + hvzero.fill(HIST("htrackscheckv0"), 7.5); + if (correlation2Dhist) + rKzeroShort.fill(HIST("mass_lambda_kshort_after7"), candidate.mK0Short(), candidate.mLambda()); + + if (std::fabs(ctauK0s) > cMaxV0LifeTime) { + return false; + } + hvzero.fill(HIST("htrackscheckv0"), 8.5); + if (correlation2Dhist) + rKzeroShort.fill(HIST("mass_lambda_kshort_after8"), candidate.mK0Short(), candidate.mLambda()); + + if (armcut && arm < confarmcut) { + return false; + } + hvzero.fill(HIST("htrackscheckv0"), 9.5); + if (correlation2Dhist) + rKzeroShort.fill(HIST("mass_lambda_kshort_after9"), candidate.mK0Short(), candidate.mLambda()); + + if (applyCompetingcut && (std::abs(candidate.mLambda() - o2::constants::physics::MassLambda0) <= competingCascrejlambda || std::abs(candidate.mAntiLambda() - o2::constants::physics::MassLambda0) <= competingCascrejlambdaanti)) { + return false; + } + + hvzero.fill(HIST("htrackscheckv0"), 10.5); + if (correlation2Dhist) + rKzeroShort.fill(HIST("mass_lambda_kshort_after10"), candidate.mK0Short(), candidate.mLambda()); + + if (qAv0) { + rKzeroShort.fill(HIST("hMassK0ShortSelected"), candidate.mK0Short(), candidate.pt()); + // rKzeroShort.fill(HIST("mass_lambda_kshort_after"), candidate.mK0Short(), candidate.mLambda()); + } + + if (candidate.mK0Short() < lowmasscutks0 || candidate.mK0Short() > highmasscutks0) { + return false; + } + return true; + } + + template + bool isSelectedV0Daughter(T const& track, float charge, double nsigmaV0Daughter, V0s const& /*candidate*/) + { + if (qAPID) { + // Filling the PID of the V0 daughters in the region of the K0 peak. + (charge == 1) ? rKzeroShort.fill(HIST("hNSigmaPosPionK0s_before"), track.tpcInnerParam(), track.tpcNSigmaPi()) : rKzeroShort.fill(HIST("hNSigmaNegPionK0s_before"), track.tpcInnerParam(), track.tpcNSigmaPi()); + rKzeroShort.fill(HIST("dE_by_dx_TPC"), track.p(), track.tpcSignal()); + } + const auto eta = track.eta(); + const auto tpcNClsF = track.tpcNClsFound(); + const auto sign = track.sign(); + + hvzero.fill(HIST("htrackscheckv0daughters"), 0.5); + + if (hasTPC && !track.hasTPC()) + return false; + hvzero.fill(HIST("htrackscheckv0daughters"), 1.5); + + if (!globalTracks) { + if (track.tpcNClsCrossedRows() < tpcCrossedrows) + return false; + hvzero.fill(HIST("htrackscheckv0daughters"), 2.5); + + if (track.tpcCrossedRowsOverFindableCls() < tpcCrossedrowsOverfcls) + return false; + hvzero.fill(HIST("htrackscheckv0daughters"), 3.5); + + if (tpcNClsF < confDaughTPCnclsMin) { + return false; + } + hvzero.fill(HIST("htrackscheckv0daughters"), 4.5); + } else { + if (!track.isGlobalTrack()) + return false; + hvzero.fill(HIST("htrackscheckv0daughters"), 4.5); + } + + if (charge < 0 && sign > 0) { + return false; + } + hvzero.fill(HIST("htrackscheckv0daughters"), 5.5); + + if (charge > 0 && sign < 0) { + return false; + } + hvzero.fill(HIST("htrackscheckv0daughters"), 6.5); + + if (std::abs(eta) > confDaughEta) { + return false; + } + hvzero.fill(HIST("htrackscheckv0daughters"), 7.5); + + if (std::abs(nsigmaV0Daughter) > confDaughPIDCuts) { + return false; + } + hvzero.fill(HIST("htrackscheckv0daughters"), 8.5); + + return true; + } + + double massK0s = o2::constants::physics::MassK0Short; + double massLambda = o2::constants::physics::MassLambda; + double massPr = o2::constants::physics::MassProton; + double massPi = o2::constants::physics::MassPionCharged; + + // Defining filters for events (event selection) + // Filter eventFilter = (o2::aod::evsel::sel8 == true); + + Filter posZFilter = (nabs(o2::aod::collision::posZ) < cutzvertex); + Filter acceptenceFilter = (nabs(aod::track::eta) < cfgETAcut && nabs(aod::track::pt) > cfgPTcut); + + // Filters on V0s + Filter preFilterV0 = (nabs(aod::v0data::dcapostopv) > v0settingdcapostopv && + nabs(aod::v0data::dcanegtopv) > v0settingdcanegtopv); + + // Defining the type of the daughter tracks + using DaughterTracks = soa::Join; + using EventCandidates = soa::Filtered>; + using TrackCandidates = soa::Filtered>; + using V0TrackCandidate = aod::V0Datas; + + ROOT::Math::PxPyPzMVector daughter1, daughter2; + ROOT::Math::PxPyPzMVector protonVec, pionVec, lambdaVec; + ROOT::Math::PxPyPzMVector fourVecDau, fourVecMother, fourVecDauCM; + ROOT::Math::XYZVector threeVecDauCM; + ROOT::Math::XYZVector helicityVec, normalVec, randomVec, beamVec; + + void processSE(EventCandidates::iterator const& collision, TrackCandidates const& /*tracks*/, aod::V0Datas const& V0s) + { + hvzero.fill(HIST("heventscheck"), 0.5); + + float multiplicity = 0.0f; + if (cfgMultFOTM) { + multiplicity = collision.centFT0M(); + } else { + multiplicity = collision.centFT0C(); + } + if (!eventselection(collision, multiplicity)) { + return; + } + + auto occupancyno = collision.trackOccupancyInTimeRange(); + if (applyOccupancyCut && occupancyno < occupancyCut) { + return; + } + + if (qAevents) { + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + rEventSelection.fill(HIST("hmultiplicity"), multiplicity); + rEventSelection.fill(HIST("multdist_FT0M"), collision.multFT0M()); + rEventSelection.fill(HIST("multdist_FT0A"), collision.multFT0A()); + rEventSelection.fill(HIST("multdist_FT0C"), collision.multFT0C()); + rEventSelection.fill(HIST("hNcontributor"), collision.numContrib()); + } + + std::vector v0indexes; + TLorentzVector lv1, lv3, lvLambda, lv4, lv5; + for (const auto& [v1, v2] : combinations(CombinationsStrictlyUpperIndexPolicy(V0s, V0s))) { + hvzero.fill(HIST("heventscheck"), 2.5); + if (v1.size() == 0 || v2.size() == 0) { + continue; + } + + if (!selectionV0(collision, v1, multiplicity)) { + continue; + } + if (!selectionV0(collision, v2, multiplicity)) { + continue; + } + + auto postrack1 = v1.template posTrack_as(); + auto negtrack1 = v1.template negTrack_as(); + + // selection for kshort + + double nTPCSigmaPosPi = postrack1.tpcNSigmaPi(); + double nTPCSigmaNegPi = negtrack1.tpcNSigmaPi(); + + if (!(isSelectedV0Daughter(negtrack1, -1, nTPCSigmaNegPi, v1) && isSelectedV0Daughter(postrack1, 1, nTPCSigmaPosPi, v1))) { + continue; + } + + // for lamba baryon selection + + auto postrack2 = v2.template posTrack_as(); + auto negtrack2 = v2.template negTrack_as(); + + double nTPCSigmaPosPr = postrack2.tpcNSigmaPr(); + double nTPCSigmaNegPiTrk2 = negtrack2.tpcNSigmaPi(); + + double nTPCSigmaNegPr = negtrack2.tpcNSigmaPr(); + double nTPCSigmaPosPiTrk2 = postrack2.tpcNSigmaPi(); + + int lambdaTag = 0; + int alambdaTag = 0; + + if (isSelectedV0Daughter(postrack2, 1, nTPCSigmaPosPr, v2) && isSelectedV0Daughter(negtrack2, -1, nTPCSigmaNegPiTrk2, v2)) { + lambdaTag = 1; + } + if (isSelectedV0Daughter(postrack2, 1, nTPCSigmaPosPiTrk2, v2) && isSelectedV0Daughter(negtrack2, -1, nTPCSigmaNegPr, v2)) { + alambdaTag = 1; + } + + if (!lambdaTag && !alambdaTag) + continue; + + if (lambdaTag) { + protonVec = ROOT::Math::PxPyPzMVector(postrack2.px(), postrack2.py(), postrack2.pz(), massPr); + pionVec = ROOT::Math::PxPyPzMVector(negtrack2.px(), negtrack2.py(), negtrack2.pz(), massPi); + } + if (alambdaTag) { + protonVec = ROOT::Math::PxPyPzMVector(negtrack2.px(), negtrack2.py(), negtrack2.pz(), massPr); + pionVec = ROOT::Math::PxPyPzMVector(postrack2.px(), postrack2.py(), postrack2.pz(), massPi); + } + lambdaVec = protonVec + pionVec; + + lv1.SetPtEtaPhiM(v1.pt(), v1.eta(), v1.phi(), massK0s); + lvLambda.SetPtEtaPhiM(lambdaVec.pt(), lambdaVec.eta(), lambdaVec.phi(), massLambda); + + lv3 = lv1 + lvLambda; + + if (qAv0daughters) { + rKzeroShort.fill(HIST("negative_pt"), negtrack1.pt()); + rKzeroShort.fill(HIST("positive_pt"), postrack1.pt()); + rKzeroShort.fill(HIST("negative_eta"), negtrack1.eta()); + rKzeroShort.fill(HIST("positive_eta"), postrack1.eta()); + rKzeroShort.fill(HIST("negative_phi"), negtrack1.phi()); + rKzeroShort.fill(HIST("positive_phi"), postrack1.phi()); + } + + daughter1 = ROOT::Math::PxPyPzMVector(v1.px(), v1.py(), v1.pz(), massK0s); // V01 + daughter2 = ROOT::Math::PxPyPzMVector(v2.px(), v2.py(), v2.pz(), massLambda); // V02 + + // polarization calculations + fourVecDau = ROOT::Math::PxPyPzMVector(daughter1.Px(), daughter1.Py(), daughter1.Pz(), massK0s); // Kshort + fourVecMother = ROOT::Math::PxPyPzMVector(lv3.Px(), lv3.Py(), lv3.Pz(), lv3.M()); // mass of KshortKshort pair + ROOT::Math::Boost boost{fourVecMother.BoostToCM()}; // boost mother to center of mass frame + fourVecDauCM = boost(fourVecDau); // boost the frame of daughter same as mother + threeVecDauCM = fourVecDauCM.Vect(); // get the 3 vector of daughter in the frame of mother + + if (std::abs(lv3.Rapidity()) < 0.5) { + if (invMass1D) { + hvzero.fill(HIST("h1vzeropairInvMassRot"), lv3.M()); + } + + if (activateTHnSparseCosThStarHelicity) { + helicityVec = fourVecMother.Vect(); // 3 vector of mother in COM frame + auto cosThetaStarHelicity = helicityVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(helicityVec.Mag2())); + hvzero.fill(HIST("h3vzeropairInvMassDS"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarHelicity, occupancyno); + + for (int i = 0; i < cnofrotations; i++) { + float theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / rotationalCut, o2::constants::math::PI + o2::constants::math::PI / rotationalCut); + lv4.SetPtEtaPhiM(lambdaVec.pt(), lambdaVec.eta(), lambdaVec.phi() + theta2, massLambda); // for rotated background + lv5 = lv1 + lv4; + hvzero.fill(HIST("h3vzeropairInvMassRot"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarHelicity, occupancyno); + } + + } else if (activateTHnSparseCosThStarProduction) { + normalVec = ROOT::Math::XYZVector(lv3.Py(), -lv3.Px(), 0.f); + auto cosThetaStarProduction = normalVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(normalVec.Mag2())); + hvzero.fill(HIST("h3vzeropairInvMassDS"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarProduction, occupancyno); + for (int i = 0; i < cnofrotations; i++) { + + auto theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / rotationalCut, o2::constants::math::PI + o2::constants::math::PI / rotationalCut); + + lv4.SetPtEtaPhiM(lambdaVec.pt(), lambdaVec.eta(), lambdaVec.phi() + theta2, massLambda); // for rotated background + lv5 = lv1 + lv4; + hvzero.fill(HIST("h3vzeropairInvMassRot"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarProduction, occupancyno); + } + } else if (activateTHnSparseCosThStarBeam) { + beamVec = ROOT::Math::XYZVector(0.f, 0.f, 1.f); + auto cosThetaStarBeam = beamVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + hvzero.fill(HIST("h3vzeropairInvMassDS"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarBeam, occupancyno); + for (int i = 0; i < cnofrotations; i++) { + auto theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / rotationalCut, o2::constants::math::PI + o2::constants::math::PI / rotationalCut); + lv4.SetPtEtaPhiM(lambdaVec.pt(), lambdaVec.eta(), lambdaVec.phi() + theta2, massLambda); // for rotated background + lv5 = lv1 + lv4; + hvzero.fill(HIST("h3vzeropairInvMassRot"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarBeam, occupancyno); + } + } else if (activateTHnSparseCosThStarRandom) { + auto phiRandom = gRandom->Uniform(0.f, constants::math::TwoPI); + auto thetaRandom = gRandom->Uniform(0.f, constants::math::PI); + randomVec = ROOT::Math::XYZVector(std::sin(thetaRandom) * std::cos(phiRandom), std::sin(thetaRandom) * std::sin(phiRandom), std::cos(thetaRandom)); + auto cosThetaStarRandom = randomVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + hvzero.fill(HIST("h3vzeropairInvMassDS"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarRandom, occupancyno); + + for (int i = 0; i < cnofrotations; i++) { + auto theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / rotationalCut, o2::constants::math::PI + o2::constants::math::PI / rotationalCut); + lv4.SetPtEtaPhiM(lambdaVec.pt(), lambdaVec.eta(), lambdaVec.phi() + theta2, massLambda); // for rotated background + lv5 = lv1 + lv4; + hvzero.fill(HIST("h3vzeropairInvMassRot"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarRandom, occupancyno); + } + } + } + } + if (qAv0) { + int sizeofv0indexes = v0indexes.size(); + rKzeroShort.fill(HIST("NksProduced"), sizeofv0indexes); + // std::cout << "Size of v0indexes: " << sizeofv0indexes << std::endl; + } + } + PROCESS_SWITCH(Kshortlambda, processSE, "same event process", true); + + // use any one of 3 alias depending on the dataset. If pp then FT0M and if pbpb then FTOC + using BinningTypeTPCMultiplicity = ColumnBinningPolicy; + using BinningTypeCentralityM = ColumnBinningPolicy; + using BinningTypeVertexContributor = ColumnBinningPolicy; + ConfigurableAxis mevz = {"mevz", {10, -10., 10.}, "mixed event vertex z binning"}; + ConfigurableAxis memult = {"memult", {2000, 0, 10000}, "mixed event multiplicity binning"}; + + void processME(EventCandidates const& collisions, TrackCandidates const& /*tracks*/, V0TrackCandidate const& v0s) + { + auto tracksTuple = std::make_tuple(v0s); + BinningTypeVertexContributor binningOnPositions1{{mevz, memult}, true}; + BinningTypeCentralityM binningOnPositions2{{mevz, memult}, true}; + + SameKindPair pair1{binningOnPositions1, cfgNmixedEvents, -1, collisions, tracksTuple, &cache}; // for PbPb + SameKindPair pair2{binningOnPositions2, cfgNmixedEvents, -1, collisions, tracksTuple, &cache}; // for pp + + if (cfgMultFOTM) { + TLorentzVector lv1, lv3, lvLambda, lv4, lv5; + + for (const auto& [c1, tracks1, c2, tracks2] : pair2) // two different centrality c1 and c2 and tracks corresponding to them + { + + float multiplicity = 0.0f; + + multiplicity = c1.centFT0M(); + + if (!eventselection(c1, multiplicity) || !eventselection(c2, multiplicity)) { + continue; + } + auto occupancyno = c1.trackOccupancyInTimeRange(); + auto occupancyno2 = c2.trackOccupancyInTimeRange(); + if (applyOccupancyCut && (occupancyno < occupancyCut || occupancyno2 < occupancyCut)) { + continue; + } + + for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + + if (t1.size() == 0 || t2.size() == 0) { + continue; + } + + if (!selectionV0(c1, t1, multiplicity)) + continue; + if (!selectionV0(c2, t2, multiplicity)) + continue; + + auto postrack1 = t1.template posTrack_as(); + auto negtrack1 = t1.template negTrack_as(); + + // selection for kshort + + double nTPCSigmaPosPi = postrack1.tpcNSigmaPi(); + double nTPCSigmaNegPi = negtrack1.tpcNSigmaPi(); + + if (!(isSelectedV0Daughter(negtrack1, -1, nTPCSigmaNegPi, t1) && isSelectedV0Daughter(postrack1, 1, nTPCSigmaPosPi, t1))) { + continue; + } + + // for lamba baryon selection + + auto postrack2 = t2.template posTrack_as(); + auto negtrack2 = t2.template negTrack_as(); + + double nTPCSigmaPosPr = postrack2.tpcNSigmaPr(); + double nTPCSigmaNegPiTrk2 = negtrack2.tpcNSigmaPi(); + + double nTPCSigmaNegPr = negtrack2.tpcNSigmaPr(); + double nTPCSigmaPosPiTrk2 = postrack2.tpcNSigmaPi(); + + int lambdaTag = 0; + int alambdaTag = 0; + + if (isSelectedV0Daughter(postrack2, 1, nTPCSigmaPosPr, t2) && isSelectedV0Daughter(negtrack2, -1, nTPCSigmaNegPiTrk2, t2)) { + lambdaTag = 1; + } + if (isSelectedV0Daughter(postrack2, 1, nTPCSigmaPosPiTrk2, t2) && isSelectedV0Daughter(negtrack2, -1, nTPCSigmaNegPr, t2)) { + alambdaTag = 1; + } + + if (!lambdaTag && !alambdaTag) + continue; + + if (lambdaTag) { + protonVec = ROOT::Math::PxPyPzMVector(postrack2.px(), postrack2.py(), postrack2.pz(), massPr); + pionVec = ROOT::Math::PxPyPzMVector(negtrack2.px(), negtrack2.py(), negtrack2.pz(), massPi); + } + if (alambdaTag) { + protonVec = ROOT::Math::PxPyPzMVector(negtrack2.px(), negtrack2.py(), negtrack2.pz(), massPr); + pionVec = ROOT::Math::PxPyPzMVector(postrack2.px(), postrack2.py(), postrack2.pz(), massPi); + } + lambdaVec = protonVec + pionVec; + lv1.SetPtEtaPhiM(t1.pt(), t1.eta(), t1.phi(), massK0s); + lvLambda.SetPtEtaPhiM(lambdaVec.pt(), lambdaVec.eta(), lambdaVec.phi(), massLambda); + lv3 = lv1 + lvLambda; + fourVecDau = ROOT::Math::PxPyPzMVector(daughter1.Px(), daughter1.Py(), daughter1.Pz(), massK0s); // Kshort + fourVecMother = ROOT::Math::PxPyPzMVector(lv3.Px(), lv3.Py(), lv3.Pz(), lv3.M()); // mass of KshortKshort pair + ROOT::Math::Boost boost{fourVecMother.BoostToCM()}; // boost mother to center of mass frame + fourVecDauCM = boost(fourVecDau); // boost the frame of daughter same as mother + threeVecDauCM = fourVecDauCM.Vect(); // get the 3 vector of daughter in the frame of mother + + if (std::abs(lv3.Rapidity()) < 0.5) { + if (activateTHnSparseCosThStarHelicity) { + helicityVec = fourVecMother.Vect(); // 3 vector of mother in COM frame + auto cosThetaStarHelicity = helicityVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(helicityVec.Mag2())); + hvzero.fill(HIST("h3vzeropairInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarHelicity, occupancyno); + } else if (activateTHnSparseCosThStarProduction) { + normalVec = ROOT::Math::XYZVector(lv3.Py(), -lv3.Px(), 0.f); + auto cosThetaStarProduction = normalVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(normalVec.Mag2())); + hvzero.fill(HIST("h3vzeropairInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarProduction, occupancyno); + } else if (activateTHnSparseCosThStarBeam) { + beamVec = ROOT::Math::XYZVector(0.f, 0.f, 1.f); + auto cosThetaStarBeam = beamVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + hvzero.fill(HIST("h3vzeropairInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarBeam, occupancyno); + } else if (activateTHnSparseCosThStarRandom) { + auto phiRandom = gRandom->Uniform(0.f, constants::math::TwoPI); + auto thetaRandom = gRandom->Uniform(0.f, constants::math::PI); + randomVec = ROOT::Math::XYZVector(std::sin(thetaRandom) * std::cos(phiRandom), std::sin(thetaRandom) * std::sin(phiRandom), std::cos(thetaRandom)); + auto cosThetaStarRandom = randomVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + hvzero.fill(HIST("h3vzeropairInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarRandom, occupancyno); + } + } + } + } + } else { + for (const auto& [c1, tracks1, c2, tracks2] : pair1) // two different centrality c1 and c2 and tracks corresponding to them + { + float multiplicity = 0.0f; + multiplicity = c1.centFT0C(); + + if (!eventselection(c1, multiplicity) || !eventselection(c2, multiplicity)) { + continue; + } + auto occupancyno = c1.trackOccupancyInTimeRange(); + auto occupancyno2 = c2.trackOccupancyInTimeRange(); + + if (applyOccupancyCut && (occupancyno < occupancyCut || occupancyno2 < occupancyCut)) { + continue; + } + TLorentzVector lv1, lv3, lvLambda, lv4, lv5; + for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + + if (t1.size() == 0 || t2.size() == 0) { + continue; + } + + if (!selectionV0(c1, t1, multiplicity)) + continue; + if (!selectionV0(c2, t2, multiplicity)) + continue; + + auto postrack1 = t1.template posTrack_as(); + auto negtrack1 = t1.template negTrack_as(); + + // selection for kshort + + double nTPCSigmaPosPi = postrack1.tpcNSigmaPi(); + double nTPCSigmaNegPi = negtrack1.tpcNSigmaPi(); + + if (!(isSelectedV0Daughter(negtrack1, -1, nTPCSigmaNegPi, t1) && isSelectedV0Daughter(postrack1, 1, nTPCSigmaPosPi, t1))) { + continue; + } + + // for lamba baryon selection + + auto postrack2 = t2.template posTrack_as(); + auto negtrack2 = t2.template negTrack_as(); + + double nTPCSigmaPosPr = postrack2.tpcNSigmaPr(); + double nTPCSigmaNegPiTrk2 = negtrack2.tpcNSigmaPi(); + + double nTPCSigmaNegPr = negtrack2.tpcNSigmaPr(); + double nTPCSigmaPosPiTrk2 = postrack2.tpcNSigmaPi(); + + int lambdaTag = 0; + int alambdaTag = 0; + + if (isSelectedV0Daughter(postrack2, 1, nTPCSigmaPosPr, t2) && isSelectedV0Daughter(negtrack2, -1, nTPCSigmaNegPiTrk2, t2)) { + lambdaTag = 1; + } + if (isSelectedV0Daughter(postrack2, 1, nTPCSigmaPosPiTrk2, t2) && isSelectedV0Daughter(negtrack2, -1, nTPCSigmaNegPr, t2)) { + alambdaTag = 1; + } + + if (!lambdaTag && !alambdaTag) + continue; + + if (lambdaTag) { + protonVec = ROOT::Math::PxPyPzMVector(postrack2.px(), postrack2.py(), postrack2.pz(), massPr); + pionVec = ROOT::Math::PxPyPzMVector(negtrack2.px(), negtrack2.py(), negtrack2.pz(), massPi); + } + if (alambdaTag) { + protonVec = ROOT::Math::PxPyPzMVector(negtrack2.px(), negtrack2.py(), negtrack2.pz(), massPr); + pionVec = ROOT::Math::PxPyPzMVector(postrack2.px(), postrack2.py(), postrack2.pz(), massPi); + } + lambdaVec = protonVec + pionVec; + + lv1.SetPtEtaPhiM(t1.pt(), t1.eta(), t1.phi(), massK0s); + lvLambda.SetPtEtaPhiM(lambdaVec.pt(), lambdaVec.eta(), lambdaVec.phi(), massLambda); + lv3 = lv1 + lvLambda; + + fourVecDau = ROOT::Math::PxPyPzMVector(daughter1.Px(), daughter1.Py(), daughter1.Pz(), massK0s); // Kshort + fourVecMother = ROOT::Math::PxPyPzMVector(lv3.Px(), lv3.Py(), lv3.Pz(), lv3.M()); // mass of KshortKshort pair + ROOT::Math::Boost boost{fourVecMother.BoostToCM()}; // boost mother to center of mass frame + fourVecDauCM = boost(fourVecDau); // boost the frame of daughter same as mother + threeVecDauCM = fourVecDauCM.Vect(); // get the 3 vector of daughter in the frame of mother + + if (std::abs(lv3.Rapidity()) < 0.5) { + + if (activateTHnSparseCosThStarHelicity) { + helicityVec = fourVecMother.Vect(); // 3 vector of mother in COM frame + auto cosThetaStarHelicity = helicityVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(helicityVec.Mag2())); + hvzero.fill(HIST("h3vzeropairInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarHelicity, occupancyno); + } else if (activateTHnSparseCosThStarProduction) { + normalVec = ROOT::Math::XYZVector(lv3.Py(), -lv3.Px(), 0.f); + auto cosThetaStarProduction = normalVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(normalVec.Mag2())); + hvzero.fill(HIST("h3vzeropairInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarProduction, occupancyno); + } else if (activateTHnSparseCosThStarBeam) { + beamVec = ROOT::Math::XYZVector(0.f, 0.f, 1.f); + auto cosThetaStarBeam = beamVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + hvzero.fill(HIST("h3vzeropairInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarBeam, occupancyno); + } else if (activateTHnSparseCosThStarRandom) { + auto phiRandom = gRandom->Uniform(0.f, constants::math::TwoPI); + auto thetaRandom = gRandom->Uniform(0.f, constants::math::PI); + randomVec = ROOT::Math::XYZVector(std::sin(thetaRandom) * std::cos(phiRandom), std::sin(thetaRandom) * std::sin(phiRandom), std::cos(thetaRandom)); + auto cosThetaStarRandom = randomVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + hvzero.fill(HIST("h3vzeropairInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarRandom, occupancyno); + } + } + } + } + } + } + PROCESS_SWITCH(Kshortlambda, processME, "mixed event process", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/kstar892analysis.cxx b/PWGLF/Tasks/Resonances/kstar892analysis.cxx new file mode 100644 index 00000000000..0a43e73bb5b --- /dev/null +++ b/PWGLF/Tasks/Resonances/kstar892analysis.cxx @@ -0,0 +1,949 @@ +// 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 kstar892analysis.cxx +/// \brief Reconstruction of track-track decay resonance candidates +/// +/// +/// adaped from k892analysis.cxx by Bong-Hwi Lim , Sawan Sawan +/// \author Marta Urioni + +#include +#include "TF1.h" +#include + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFResonanceTables.h" +#include "DataFormatsParameters/GRPObject.h" +#include "CommonConstants/PhysicsConstants.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; +using namespace o2::aod::resodaughter; + +struct kstar892analysis { + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + ///// Configurables + /// Histograms + ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12.0, 12.1, 12.2, 12.3, 12.4, 12.5, 12.6, 12.7, 12.8, 12.9, 13.0, 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7, 13.8, 13.9, 14.0, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15.0}, "Binning of the pT axis"}; + ConfigurableAxis binsPtQA{"binsPtQA", {VARIABLE_WIDTH, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2, 6.4, 6.6, 6.8, 7.0, 7.2, 7.4, 7.6, 7.8, 8.0, 8.2, 8.4, 8.6, 8.8, 9.0, 9.2, 9.4, 9.6, 9.8, 10.0}, "Binning of the pT axis"}; + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0}, "Binning of the centrality axis"}; + ConfigurableAxis binsImpactPar{"binsImpactPar", {VARIABLE_WIDTH, 0.0, 3.00065, 4.28798, 6.14552, 7.6196, 8.90942, 10.0897, 11.2002, 12.2709, 13.3167, 14.4173, 23.2518}, "Binning of the impact parameter axis"}; + + Configurable cInvMassStart{"cInvMassStart", 0.6, "Invariant mass start"}; + Configurable cInvMassEnd{"cInvMassEnd", 1.5, "Invariant mass end"}; + Configurable cInvMassBins{"cInvMassBins", 900, "Invariant mass binning"}; + Configurable cPIDBins{"cPIDBins", 65, "PID binning"}; + Configurable cPIDQALimit{"cPIDQALimit", 6.5, "PID QA limit"}; + Configurable cDCABins{"cDCABins", 150, "DCA binning"}; + /// Event Mixing + Configurable nEvtMixing{"nEvtMixing", 5, "Number of events to mix"}; + ConfigurableAxis CfgVtxBins{"CfgVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis CfgMultBins{"CfgMultBins", {VARIABLE_WIDTH, 0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Mixing bins - z-vertex"}; + + /// Pre-selection cuts + Configurable cMinPtcut{"cMinPtcut", 0.15, "Track minium pt cut"}; + /// DCA Selections + // DCAr to PV + Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 0.5, "Track DCAr cut to PV Maximum"}; + // DCAz to PV + Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; + Configurable cMinDCAzToPVcut{"cMinDCAzToPVcut", 0.0, "Track DCAz cut to PV Minimum"}; + /// PID Selections + Configurable cfgHighPt{"cfgHighPt", 999.0, "Minimum Pt to apply tighter PID selections on Mixed Event"}; + // Pion + Configurable cMaxTPCnSigmaPion{"cMaxTPCnSigmaPion", 3.0, "TPC nSigma cut for Pion"}; // TPC + Configurable cMaxTOFnSigmaPion{"cMaxTOFnSigmaPion", 3.0, "TOF nSigma cut for Pion"}; // TOF + Configurable cMaxTPCnSigmaPionHighPtME{"cMaxTPCnSigmaPionHighPtME", 2.0, "TPC nSigma cut for Pion at high pt for Mixed Event"}; // TPC + Configurable cMaxTOFnSigmaPionHighPtME{"cMaxTOFnSigmaPionHighPtME", 2.0, "TOF nSigma cut for Pion at high pt for Mixed Event"}; // TOF + Configurable nsigmaCutCombinedPion{"nsigmaCutCombinedPion", -999, "Combined nSigma cut for Pion"}; // Combined + // Kaon + Configurable cMaxTPCnSigmaKaon{"cMaxTPCnSigmaKaon", 3.0, "TPC nSigma cut for Kaon"}; // TPC + Configurable cMaxTOFnSigmaKaon{"cMaxTOFnSigmaKaon", 3.0, "TOF nSigma cut for Kaon"}; // TOF + Configurable cMaxTPCnSigmaKaonHighPtME{"cMaxTPCnSigmaKaonHighPtME", 2.0, "TPC nSigma cut for Kaon at pt>3GeV for Mixed Event"}; // TPC + Configurable cMaxTOFnSigmaKaonHighPtME{"cMaxTOFnSigmaKaonHighPtME", 2.0, "TOF nSigma cut for Kaon at pt>3GeV for Mixed Event"}; // TOF + Configurable nsigmaCutCombinedKaon{"nsigmaCutCombinedKaon", -999, "Combined nSigma cut for Kaon"}; // Combined + + Configurable cByPassTOF{"cByPassTOF", false, "By pass TOF PID selection"}; // By pass TOF PID selection + Configurable cfgGlobalTrack{"cfgGlobalTrack", false, "Global track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable additionalQAplots{"additionalQAplots", true, "Additional QA plots"}; + Configurable additionalQAeventPlots{"additionalQAeventPlots", false, "Additional QA event plots"}; + Configurable additionalMEPlots{"additionalMEPlots", false, "Additional Mixed event plots"}; + + Configurable tof_at_high_pt{"tof_at_high_pt", false, "Use TOF at high pT"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 0, "Number of TPC cluster"}; + Configurable cfgUseTPCRefit{"cfgUseTPCRefit", false, "Require TPC Refit"}; + Configurable cfgUseITSRefit{"cfgUseITSRefit", false, "Require ITS Refit"}; + + // MC Event selection + Configurable cZvertCutMC{"cZvertCutMC", 10.0, "MC Z-vertex cut"}; + + // cuts on mother + Configurable cfgCutsOnMother{"cfgCutsOnMother", false, "Enamble additional cuts on mother"}; + Configurable cMaxPtMotherCut{"cMaxPtMotherCut", 15.0, "Maximum pt of mother cut"}; + Configurable cMaxMinvMotherCut{"cMaxMinvMotherCut", 1.5, "Maximum Minv of mother cut"}; + + // configurables for partitions + Configurable cMaxPtTPC{"cMaxPtTPC", 1.2, "maximum pt to apply TPC PID and TOF if available"}; + Configurable cMinPtTOF{"cMinPtTOF", 0.8, "minimum pt to require TOF PID in addition to TPC"}; + + void init(o2::framework::InitContext&) + { + + // LOG(info)<< "\n cfgTPCcluster ============>"<< static_cast(cfgTPCcluster); + + AxisSpec centAxis = {binsCent, "V0M (%)"}; + AxisSpec ImpactParAxis = {binsImpactPar, "Impact Parameter"}; + AxisSpec dcaxyAxis = {cDCABins, 0.0, 3.0, "DCA_{#it{xy}} (cm)"}; + AxisSpec dcazAxis = {cDCABins, 0.0, 3.0, "DCA_{#it{z}} (cm)"}; + AxisSpec mcLabelAxis = {5, -0.5, 4.5, "MC Label"}; + AxisSpec ptAxis = {binsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptAxisQA = {binsPtQA, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec invMassAxis = {cInvMassBins, cInvMassStart, cInvMassEnd, "Invariant Mass (GeV/#it{c}^2)"}; + AxisSpec pidQAAxis = {cPIDBins, -cPIDQALimit, cPIDQALimit}; + + if (additionalQAeventPlots) { + // Test on Mixed event + histos.add("TestME/hCollisionIndexSameE", "coll index sameE", HistType::kTH1F, {{500, 0.0f, 500.0f}}); + histos.add("TestME/hCollisionIndexMixedE", "coll index mixedE", HistType::kTH1F, {{500, 0.0f, 500.0f}}); + histos.add("TestME/hnTrksSameE", "n tracks per event SameE", HistType::kTH1F, {{1000, 0.0f, 1000.0f}}); + histos.add("TestME/hnTrksMixedE", "n tracks per event MixedE", HistType::kTH1F, {{1000, 0.0f, 1000.0f}}); + histos.add("TestME/hPairsCounterSameE", "tot n pairs sameE", HistType::kTH1F, {{1, 0.5f, 1.5f}}); + histos.add("TestME/hPairsCounterMixedE", "tot n pairs mixedE", HistType::kTH1F, {{1, 0.5f, 1.5f}}); + + // event histograms + histos.add("QAevent/hEvtCounterSameE", "Number of analyzed Same Events", HistType::kTH1F, {{1, 0.5, 1.5}}); + histos.add("QAevent/hVertexZSameE", "Collision Vertex Z position", HistType::kTH1F, {{100, -15., 15.}}); + histos.add("QAevent/hMultiplicityPercentSameE", "Multiplicity percentile of collision", HistType::kTH1F, {{120, 0.0f, 120.0f}}); + + histos.add("QAevent/hEvtCounterMixedE", "Number of analyzed Mixed Events", HistType::kTH1F, {{1, 0.5, 1.5}}); + histos.add("QAevent/hVertexZMixedE", "Collision Vertex Z position", HistType::kTH1F, {{100, -15., 15.}}); + histos.add("QAevent/hMultiplicityPercentMixedE", "Multiplicity percentile of collision", HistType::kTH1F, {{120, 0.0f, 120.0f}}); + } + + // Mass QA (quick check) + histos.add("k892invmassDS", "Invariant mass of K(892)0 different sign", kTH1F, {invMassAxis}); + histos.add("k892invmassDSAnti", "Invariant mass of Anti-K(892)0 different sign", kTH1F, {invMassAxis}); + histos.add("k892invmassLS", "Invariant mass of K(892)0 like sign", kTH1F, {invMassAxis}); + histos.add("k892invmassLSAnti", "Invariant mass of Anti-K(892)0 like sign", kTH1F, {invMassAxis}); + if (doprocessMELight || doprocessMELightWithTof || doprocessMELightTPCLowPt || doprocessMELightTOFHighPt) { + histos.add("k892invmassME", "Invariant mass of K(892)0 mixed event", kTH1F, {invMassAxis}); + if (additionalMEPlots) { + histos.add("k892invmassME_DS", "Invariant mass of K(892)0 mixed event DS", kTH1F, {invMassAxis}); + histos.add("k892invmassME_DSAnti", "Invariant mass of K(892)0 mixed event DSAnti", kTH1F, {invMassAxis}); + } + } + + if (additionalQAplots) { + // TPC ncluster distirbutions + histos.add("TPCncluster/TPCnclusterpi", "TPC ncluster distribution", kTH1F, {{160, 0, 160, "TPC nCluster"}}); + histos.add("TPCncluster/TPCnclusterka", "TPC ncluster distribution", kTH1F, {{160, 0, 160, "TPC nCluster"}}); + histos.add("TPCncluster/TPCnclusterPhipi", "TPC ncluster vs phi", kTH2F, {{160, 0, 160, "TPC nCluster"}, {63, 0, 6.28, "#phi"}}); + histos.add("TPCncluster/TPCnclusterPhika", "TPC ncluster vs phi", kTH2F, {{160, 0, 160, "TPC nCluster"}, {63, 0, 6.28, "#phi"}}); + } + + // DCA QA + histos.add("QA/trkDCAxy_pi", "DCAxy distribution of pion track candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QA/trkDCAxy_ka", "DCAxy distribution of kaon track candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QA/trkDCAz_pi", "DCAz distribution of pion track candidates", HistType::kTH1F, {dcazAxis}); + histos.add("QA/trkDCAz_ka", "DCAz distribution of kaon track candidates", HistType::kTH1F, {dcazAxis}); + // pT QA + histos.add("QA/trkpT_pi", "pT distribution of pion track candidates", kTH1F, {ptAxis}); + histos.add("QA/trkpT_ka", "pT distribution of kaon track candidates", kTH1F, {ptAxis}); + // PID QA + histos.add("QA/TOF_TPC_Map_pi_all", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QA/TOF_Nsigma_pi_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QA/TPC_Nsigma_pi_all", "TPC NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QA/TOF_TPC_Mapka_all", "TOF + TPC Combined PID for Kaon;#sigma_{TOF}^{Kaon};#sigma_{TPC}^{Kaon}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QA/TOF_Nsigma_ka_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QA/TPC_Nsigmaka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + + // 3d histogram + histos.add("h3k892invmassDS", "Invariant mass of K(892)0 differnt sign", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassDSAnti", "Invariant mass of Anti-K(892)0 differnt sign", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassLS", "Invariant mass of K(892)0 same sign", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassLSAnti", "Invariant mass of Anti-K(892)0 same sign", kTH3F, {centAxis, ptAxis, invMassAxis}); + if (doprocessMELight || doprocessMELightWithTof || doprocessMELightTPCLowPt || doprocessMELightTOFHighPt) { + histos.add("h3k892invmassME", "Invariant mass of K(892)0 mixed event", kTH3F, {centAxis, ptAxis, invMassAxis}); + + if (additionalMEPlots) { + histos.add("QAME/TOF_TPC_Map_pi_all", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAME/TOF_Nsigma_pi_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAME/TPC_Nsigma_pi_all", "TPC NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAME/TOF_TPC_Mapka_all", "TOF + TPC Combined PID for Kaon;#sigma_{TOF}^{Kaon};#sigma_{TPC}^{Kaon}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAME/TOF_Nsigma_ka_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAME/TPC_Nsigmaka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + + histos.add("h3k892invmassME_DS", "Invariant mass of K(892)0 mixed event DS", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892invmassME_DSAnti", "Invariant mass of K(892)0 mixed event DSAnti", kTH3F, {centAxis, ptAxis, invMassAxis}); + } + } + + if (doprocessMCLight || doprocessMCLightWithTof || doprocessMCLightTPCLowPt || doprocessMCLightTOFHighPt) { + // MC QA + histos.add("QAMCTrue/ImpactParameter", "Impact parameter of event", HistType::kTH1F, {ImpactParAxis}); + histos.add("QAMCTrue/trkDCAxy_pi", "DCAxy distribution of pion track candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QAMCTrue/trkDCAxy_ka", "DCAxy distribution of kaon track candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QAMCTrue/trkDCAz_pi", "DCAz distribution of pion track candidates", HistType::kTH1F, {dcazAxis}); + histos.add("QAMCTrue/trkDCAz_ka", "DCAz distribution of kaon track candidates", HistType::kTH1F, {dcazAxis}); + histos.add("QAMCTrue/TOF_Nsigma_pi_all", "TOF NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAMCTrue/TPC_Nsigma_pi_all", "TPC NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAMCTrue/TOF_Nsigma_ka_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAMCTrue/TPC_Nsigmaka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + + histos.add("k892Recinvmass", "Inv mass distribution of Reconstructed MC K(892)", kTH1F, {invMassAxis}); + histos.add("k892GenInvmass", "Invariant mass of generated K(892)0", kTH1F, {invMassAxis}); + histos.add("k892GenInvmassAnti", "Invariant mass of generated Anti-K(892)0", kTH1F, {invMassAxis}); + + histos.add("h3Reck892invmass", "Invariant mass of Reconstructed MC K(892)0", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3Reck892invmassAnti", "Invariant mass of Reconstructed MC Anti-K(892)0", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("k892Gen", "pT distribution of True MC K(892)0", kTH3F, {mcLabelAxis, ptAxis, centAxis}); + histos.add("k892GenAnti", "pT distribution of True MC Anti-K(892)0", kTH3F, {mcLabelAxis, ptAxis, centAxis}); + histos.add("k892Rec", "pT distribution of Reconstructed MC K(892)0", kTH2F, {ptAxis, centAxis}); + histos.add("k892RecAnti", "pT distribution of Reconstructed MC Anti-K(892)0", kTH2F, {ptAxis, centAxis}); + histos.add("h3k892GenInvmass", "Invariant mass of generated K(892)0", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("h3k892GenInvmassAnti", "Invariant mass of generated Anti-K(892)0", kTH3F, {centAxis, ptAxis, invMassAxis}); + + histos.add("ImpactParPlots/h3Reck892invmass", "Invariant mass of Reconstructed MC K(892)0", kTH3F, {ImpactParAxis, ptAxis, invMassAxis}); + histos.add("ImpactParPlots/h3Reck892invmassAnti", "Invariant mass of Reconstructed MC Anti-K(892)0", kTH3F, {ImpactParAxis, ptAxis, invMassAxis}); + histos.add("ImpactParPlots/k892Gen", "pT distribution of True MC K(892)0", kTH3F, {mcLabelAxis, ptAxis, ImpactParAxis}); + histos.add("ImpactParPlots/k892GenAnti", "pT distribution of True MC Anti-K(892)0", kTH3F, {mcLabelAxis, ptAxis, ImpactParAxis}); + histos.add("ImpactParPlots/k892Rec", "pT distribution of Reconstructed MC K(892)0", kTH2F, {ptAxis, ImpactParAxis}); + histos.add("ImpactParPlots/k892RecAnti", "pT distribution of Reconstructed MC Anti-K(892)0", kTH2F, {ptAxis, ImpactParAxis}); + histos.add("ImpactParPlots/h3k892GenInvmass", "Invariant mass of generated K(892)0", kTH3F, {ImpactParAxis, ptAxis, invMassAxis}); + histos.add("ImpactParPlots/h3k892GenInvmassAnti", "Invariant mass of generated Anti-K(892)0", kTH3F, {ImpactParAxis, ptAxis, invMassAxis}); + } + // Print output histograms statistics + LOG(info) << "Size of the histograms in spectraTOF"; + histos.print(); + } + + /////////////////////////////////////////////////////// + + SliceCache cache; + Preslice perRCol = aod::resodaughter::resoCollisionId; + Preslice perCollision = aod::track::collisionId; + + // Filters + Filter acceptanceFilter = nabs(aod::resodaughter::pt) >= cMinPtcut; + Filter DCAcutFilter = (nabs(aod::track::dcaXY) <= cMaxDCArToPVcut) && (nabs(aod::track::dcaZ) <= cMaxDCAzToPVcut); + // Filter primarytrackFilter = aod::resodaughter::isPVContributor && aod::resodaughter::isPrimaryTrack && aod::resodaughter::isGlobalTrackWoDCA; + Filter primarytrackFilter = requirePVContributor() && requirePrimaryTrack() && requireGlobalTrackWoDCA(); + + // partitions for data + Partition resoKaWithTof = + (nabs(aod::resodaughter::tofNSigmaKa10) <= 10 * cMaxTOFnSigmaKaon) && + requireHasTOF(); + + Partition resoPiWithTof = + (nabs(aod::resodaughter::tofNSigmaPi10) <= 10 * cMaxTOFnSigmaPion) && + requireHasTOF(); + + Partition resoKa = + (nabs(aod::resodaughter::tpcNSigmaKa10) <= 10 * cMaxTPCnSigmaKaon); + + Partition resoPi = + (nabs(aod::resodaughter::tpcNSigmaPi10) <= 10 * cMaxTPCnSigmaPion); + + Partition resoKaTPClowPt = + (nabs(aod::resodaughter::tpcNSigmaKa10) <= 10 * cMaxTPCnSigmaKaon) && + (nabs(aod::resodaughter::pt) < cMaxPtTPC); + + Partition resoPiTPClowPt = + (nabs(aod::resodaughter::tpcNSigmaPi10) <= 10 * cMaxTPCnSigmaPion) && + (nabs(aod::resodaughter::pt) < cMaxPtTPC); + + Partition resoKaTOFhighPt = + (nabs(aod::resodaughter::tofNSigmaKa10) <= 10 * cMaxTOFnSigmaKaon) && + requireHasTOF() && (nabs(aod::resodaughter::pt) >= cMinPtTOF); + + Partition resoPiTOFhighPt = + (nabs(aod::resodaughter::tofNSigmaPi10) <= 10 * cMaxTOFnSigmaPion) && + requireHasTOF() && (nabs(aod::resodaughter::pt) >= cMinPtTOF); + + // Partitions for mc + Partition> resoMCrecKaWithTof = + (nabs(aod::resodaughter::tofNSigmaKa10) <= 10 * cMaxTOFnSigmaKaon) && + requireHasTOF(); + + Partition> resoMCrecPiWithTof = + (nabs(aod::resodaughter::tofNSigmaPi10) <= 10 * cMaxTOFnSigmaPion) && + requireHasTOF(); + + Partition> resoMCrecKa = + (nabs(aod::resodaughter::tpcNSigmaKa10) <= 10 * cMaxTPCnSigmaKaon); + + Partition> resoMCrecPi = + (nabs(aod::resodaughter::tpcNSigmaPi10) <= 10 * cMaxTPCnSigmaPion); + + Partition> resoMCrecKaTPClowPt = + (nabs(aod::resodaughter::tpcNSigmaKa10) <= 10 * cMaxTPCnSigmaKaon) && + (nabs(aod::resodaughter::pt) < cMaxPtTPC); + + Partition> resoMCrecPiTPClowPt = + (nabs(aod::resodaughter::tpcNSigmaPi10) <= 10 * cMaxTPCnSigmaPion) && + (nabs(aod::resodaughter::pt) < cMaxPtTPC); + + Partition> resoMCrecKaTOFhighPt = + (nabs(aod::resodaughter::tofNSigmaKa10) <= 10 * cMaxTOFnSigmaKaon) && + requireHasTOF() && (nabs(aod::resodaughter::pt) >= cMinPtTOF); + + Partition> resoMCrecPiTOFhighPt = + (nabs(aod::resodaughter::tofNSigmaPi10) <= 10 * cMaxTOFnSigmaPion) && + requireHasTOF() && (nabs(aod::resodaughter::pt) >= cMinPtTOF); + + using ResoMCCols = soa::Join; + + //****************************************** + + float massKa = MassKaonCharged; + float massPi = MassPionCharged; + + template + bool trackCut(const TrackType track) + { + // TPC + if (track.tpcNClsFound() < cfgTPCcluster) + return false; + // ITS + if (cfgUseITSRefit && !track.passedITSRefit()) + return false; + if (cfgUseTPCRefit && !track.passedTPCRefit()) + return false; + + if (cfgGlobalTrack && !track.isGlobalTrack()) + return false; + + return true; + } + // PID selection tools + + template + bool selectionPIDPion(const T& candidate) + { + if (tof_at_high_pt) { + if (candidate.hasTOF() && (std::abs(candidate.tofNSigmaPi()) < cMaxTOFnSigmaPion)) { + return true; + } + if (!candidate.hasTOF() && (std::abs(candidate.tpcNSigmaPi()) < cMaxTPCnSigmaPion)) { + return true; + } + } else { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + if (std::abs(candidate.tpcNSigmaPi()) < cMaxTPCnSigmaPion) { + tpcPIDPassed = true; + } + if (cByPassTOF && tpcPIDPassed) { + return true; + } + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaPi()) < cMaxTOFnSigmaPion) { + tofPIDPassed = true; + } + if ((nsigmaCutCombinedPion > 0) && (candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi() + candidate.tofNSigmaPi() * candidate.tofNSigmaPi() < nsigmaCutCombinedPion * nsigmaCutCombinedPion)) { + tofPIDPassed = true; + } + } else { + tofPIDPassed = true; + } + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + } + return false; + } + template + bool selectionPIDKaon(const T& candidate) + { + if (tof_at_high_pt) { + if (candidate.hasTOF() && (std::abs(candidate.tofNSigmaKa()) < cMaxTOFnSigmaKaon)) { + return true; + } + if (!candidate.hasTOF() && (std::abs(candidate.tpcNSigmaKa()) < cMaxTPCnSigmaKaon)) { + return true; + } + } else { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + if (std::abs(candidate.tpcNSigmaKa()) < cMaxTPCnSigmaKaon) { + tpcPIDPassed = true; + } + if (cByPassTOF && tpcPIDPassed) { + return true; + } + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaKa()) < cMaxTOFnSigmaKaon) { + tofPIDPassed = true; + } + if ((nsigmaCutCombinedKaon > 0) && (candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa() < nsigmaCutCombinedKaon * nsigmaCutCombinedKaon)) { + tofPIDPassed = true; + } + } else { + tofPIDPassed = true; + } + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + } + return false; + } + + template + bool selectionPIDPionME(const T& candidate) + { + float NsigmaTOF; + float NsigmaTPC; + + if (std::abs(candidate.pt()) < cfgHighPt) { + NsigmaTOF = cMaxTOFnSigmaPion; + NsigmaTPC = cMaxTPCnSigmaPion; + } else { + NsigmaTOF = cMaxTOFnSigmaPionHighPtME; + NsigmaTPC = cMaxTPCnSigmaPionHighPtME; + } + + bool tpcPIDPassed{false}, tofPIDPassed{false}; + if (std::abs(candidate.tpcNSigmaPi()) < NsigmaTPC) { + tpcPIDPassed = true; + } + if (cByPassTOF && tpcPIDPassed) { + return true; + } + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaPi()) < NsigmaTOF) { + tofPIDPassed = true; + } + } else { + tofPIDPassed = true; + } + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + return false; + } + template + bool selectionPIDKaonME(const T& candidate) + { + float NsigmaTOF; + float NsigmaTPC; + + if (std::abs(candidate.pt()) < cfgHighPt) { + NsigmaTOF = cMaxTOFnSigmaKaon; + NsigmaTPC = cMaxTPCnSigmaKaon; + } else { + NsigmaTOF = cMaxTOFnSigmaKaonHighPtME; + NsigmaTPC = cMaxTPCnSigmaKaonHighPtME; + } + + bool tpcPIDPassed{false}, tofPIDPassed{false}; + if (std::abs(candidate.tpcNSigmaKa()) < NsigmaTPC) { + tpcPIDPassed = true; + } + if (cByPassTOF && tpcPIDPassed) { + return true; + } + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaKa()) < NsigmaTOF) { + tofPIDPassed = true; + } + } else { + tofPIDPassed = true; + } + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + return false; + } + + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksType& dTracks2) + { + // auto multNTracksPV = collision.multNTracksPV(); + float impactpar = -999.0; + if constexpr (IsMC) { + impactpar = collision.impactParameter(); + } + auto multiplicity = collision.cent(); + + if (additionalQAeventPlots) { + if constexpr (!IsMix) { + histos.fill(HIST("QAevent/hVertexZSameE"), collision.posZ()); + histos.fill(HIST("QAevent/hMultiplicityPercentSameE"), collision.cent()); + histos.fill(HIST("TestME/hCollisionIndexSameE"), collision.globalIndex()); + histos.fill(HIST("TestME/hnTrksSameE"), dTracks1.size()); + } else { + histos.fill(HIST("QAevent/hVertexZMixedE"), collision.posZ()); + histos.fill(HIST("QAevent/hMultiplicityPercentMixedE"), collision.cent()); + histos.fill(HIST("TestME/hCollisionIndexMixedE"), collision.globalIndex()); + histos.fill(HIST("TestME/hnTrksMixedE"), dTracks1.size()); + } + } + + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; + for (auto& [trk1, trk2] : combinations(CombinationsFullIndexPolicy(dTracks1, dTracks2))) { + + // Full index policy is needed to consider all possible combinations + if (trk1.index() == trk2.index()) + continue; // We need to run (0,1), (1,0) pairs as well. but same id pairs are not needed. + + if (additionalQAeventPlots) { + if constexpr (!IsMix) { + histos.fill(HIST("TestME/hPairsCounterSameE"), 1.0); + } else { + histos.fill(HIST("TestME/hPairsCounterMixedE"), 1.0); + } + } + + //// Initialize variables + // Trk1: Pion, Trk2: Kaon + // apply the track cut + if (!trackCut(trk1) || !trackCut(trk2)) + continue; + + auto isTrk1hasTOF = trk1.hasTOF(); + auto isTrk2hasTOF = trk2.hasTOF(); + auto trk1ptPi = trk1.pt(); + auto trk1NSigmaPiTPC = trk1.tpcNSigmaPi(); + auto trk1NSigmaPiTOF = (isTrk1hasTOF) ? trk1.tofNSigmaPi() : -999.; + auto trk2ptKa = trk2.pt(); + auto trk2NSigmaKaTPC = trk2.tpcNSigmaKa(); + auto trk2NSigmaKaTOF = (isTrk2hasTOF) ? trk2.tofNSigmaKa() : -999.; + + if constexpr (!IsMix) { + if (!selectionPIDPion(trk1) || !selectionPIDKaon(trk2)) + continue; + } else { + if (!selectionPIDPionME(trk1) || !selectionPIDKaonME(trk2)) + continue; + } + + if (additionalQAplots) { + // TPCncluster distributions + histos.fill(HIST("TPCncluster/TPCnclusterpi"), trk1.tpcNClsFound()); + histos.fill(HIST("TPCncluster/TPCnclusterka"), trk2.tpcNClsFound()); + histos.fill(HIST("TPCncluster/TPCnclusterPhipi"), trk1.tpcNClsFound(), trk1.phi()); + histos.fill(HIST("TPCncluster/TPCnclusterPhika"), trk2.tpcNClsFound(), trk2.phi()); + } + + if constexpr (!IsMix) { + //// QA plots after the selection + // --- PID QA Pion + histos.fill(HIST("QA/TPC_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTPC); + if (isTrk1hasTOF) { + histos.fill(HIST("QA/TOF_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTOF); + histos.fill(HIST("QA/TOF_TPC_Map_pi_all"), trk1NSigmaPiTOF, trk1NSigmaPiTPC); + } + // --- PID QA Kaon + histos.fill(HIST("QA/TPC_Nsigmaka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTPC); + if (isTrk2hasTOF) { + histos.fill(HIST("QA/TOF_Nsigma_ka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTOF); + histos.fill(HIST("QA/TOF_TPC_Mapka_all"), trk2NSigmaKaTOF, trk2NSigmaKaTPC); + } + histos.fill(HIST("QA/trkpT_pi"), trk1ptPi); + histos.fill(HIST("QA/trkpT_ka"), trk2ptKa); + histos.fill(HIST("QA/trkDCAxy_pi"), trk1.dcaXY()); + histos.fill(HIST("QA/trkDCAxy_ka"), trk2.dcaXY()); + histos.fill(HIST("QA/trkDCAz_pi"), trk1.dcaZ()); + histos.fill(HIST("QA/trkDCAz_ka"), trk2.dcaZ()); + } else if (additionalMEPlots) { + // --- PID QA Pion + histos.fill(HIST("QAME/TPC_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTPC); + if (isTrk1hasTOF) { + histos.fill(HIST("QAME/TOF_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTOF); + histos.fill(HIST("QAME/TOF_TPC_Map_pi_all"), trk1NSigmaPiTOF, trk1NSigmaPiTPC); + } + // --- PID QA Kaon + histos.fill(HIST("QAME/TPC_Nsigmaka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTPC); + if (isTrk2hasTOF) { + histos.fill(HIST("QAME/TOF_Nsigma_ka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTOF); + histos.fill(HIST("QAME/TOF_TPC_Mapka_all"), trk2NSigmaKaTOF, trk2NSigmaKaTPC); + } + } + + //// Resonance reconstruction + lDecayDaughter1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massPi); + lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massKa); + lResonance = lDecayDaughter1 + lDecayDaughter2; + // Rapidity cut + if (abs(lResonance.Rapidity()) >= 0.5) + continue; + if (cfgCutsOnMother) { + if (lResonance.Pt() >= cMaxPtMotherCut) // excluding candidates in overflow + continue; + if (lResonance.M() >= cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } + + //// Un-like sign pair only + if (trk1.sign() * trk2.sign() < 0) { + if constexpr (!IsMix) { + if (trk1.sign() < 0) { + histos.fill(HIST("k892invmassDS"), lResonance.M()); + histos.fill(HIST("h3k892invmassDS"), multiplicity, lResonance.Pt(), lResonance.M()); + } else if (trk1.sign() > 0) { + histos.fill(HIST("k892invmassDSAnti"), lResonance.M()); + histos.fill(HIST("h3k892invmassDSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + } + } else { + histos.fill(HIST("k892invmassME"), lResonance.M()); + histos.fill(HIST("h3k892invmassME"), multiplicity, lResonance.Pt(), lResonance.M()); + if (additionalMEPlots) { + if (trk1.sign() < 0) { + histos.fill(HIST("k892invmassME_DS"), lResonance.M()); + histos.fill(HIST("h3k892invmassME_DS"), multiplicity, lResonance.Pt(), lResonance.M()); + } else if (trk1.sign() > 0) { + histos.fill(HIST("k892invmassME_DSAnti"), lResonance.M()); + histos.fill(HIST("h3k892invmassME_DSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + } + } + } + + // MC + if constexpr (IsMC) { + if (abs(trk1.pdgCode()) != 211 || abs(trk2.pdgCode()) != 321) + continue; + if (trk1.motherId() != trk2.motherId()) // Same mother + continue; + if (abs(trk1.motherPDG()) != 313) + continue; + + // Track selection check. + histos.fill(HIST("QAMCTrue/trkDCAxy_pi"), trk1.dcaXY()); + histos.fill(HIST("QAMCTrue/trkDCAxy_ka"), trk2.dcaXY()); + histos.fill(HIST("QAMCTrue/trkDCAz_pi"), trk1.dcaZ()); + histos.fill(HIST("QAMCTrue/trkDCAz_ka"), trk2.dcaZ()); + histos.fill(HIST("QAMCTrue/TPC_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTPC); + if (isTrk1hasTOF) { + histos.fill(HIST("QAMCTrue/TOF_Nsigma_pi_all"), multiplicity, trk1ptPi, trk1NSigmaPiTOF); + } + histos.fill(HIST("QAMCTrue/TPC_Nsigmaka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTPC); + if (isTrk2hasTOF) { + histos.fill(HIST("QAMCTrue/TOF_Nsigma_ka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTOF); + } + + // MC histograms + if (trk1.motherPDG() > 0) { + histos.fill(HIST("k892Rec"), lResonance.Pt(), multiplicity); + histos.fill(HIST("ImpactParPlots/k892Rec"), lResonance.Pt(), impactpar); + histos.fill(HIST("k892Recinvmass"), lResonance.M()); + histos.fill(HIST("h3Reck892invmass"), multiplicity, lResonance.Pt(), lResonance.M()); + histos.fill(HIST("ImpactParPlots/h3Reck892invmass"), impactpar, lResonance.Pt(), lResonance.M()); + } else { + histos.fill(HIST("k892RecAnti"), lResonance.Pt(), multiplicity); + histos.fill(HIST("ImpactParPlots/k892RecAnti"), lResonance.Pt(), impactpar); + histos.fill(HIST("k892Recinvmass"), lResonance.M()); + histos.fill(HIST("h3Reck892invmassAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + histos.fill(HIST("ImpactParPlots/h3Reck892invmassAnti"), impactpar, lResonance.Pt(), lResonance.M()); + } + } + } else if (trk1.sign() * trk2.sign() > 0) { + if constexpr (!IsMix) { + if (trk1.sign() < 0) { + histos.fill(HIST("k892invmassLS"), lResonance.M()); + histos.fill(HIST("h3k892invmassLS"), multiplicity, lResonance.Pt(), lResonance.M()); + } else if (trk1.sign() > 0) { + histos.fill(HIST("k892invmassLSAnti"), lResonance.M()); + histos.fill(HIST("h3k892invmassLSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + } + } + } + } + } // end of fillHistograms + + /////////////////////////////////////////////////////////////////////////////// + ///// ///// + ///// PROCESS FUNCTIONS ///// + ///// ///// + /////////////////////////////////////////////////////////////////////////////// + + void processDataLight(aod::ResoCollision& collision, + soa::Filtered const&) + { + // LOG(info) << "new collision, zvtx: " << collision.posZ(); + if (additionalQAeventPlots) + histos.fill(HIST("QAevent/hEvtCounterSameE"), 1.0); + + auto candPi = resoPi->sliceByCached(aod::resodaughter::resoCollisionId, collision.globalIndex(), cache); + auto candKa = resoKa->sliceByCached(aod::resodaughter::resoCollisionId, collision.globalIndex(), cache); + + fillHistograms(collision, candPi, candKa); + } + PROCESS_SWITCH(kstar892analysis, processDataLight, "Process Event for data", false); + + void processDataLightWithTof(aod::ResoCollision& collision, + soa::Filtered const&) + { + // LOG(info) << "new collision, zvtx: " << collision.posZ(); + if (additionalQAeventPlots) + histos.fill(HIST("QAevent/hEvtCounterSameE"), 1.0); + + auto candPiwithtof = resoPiWithTof->sliceByCached(aod::resodaughter::resoCollisionId, collision.globalIndex(), cache); + auto candKawithtof = resoKaWithTof->sliceByCached(aod::resodaughter::resoCollisionId, collision.globalIndex(), cache); + + fillHistograms(collision, candPiwithtof, candKawithtof); + } + PROCESS_SWITCH(kstar892analysis, processDataLightWithTof, "Process Event for data, tracks with TOF", false); + + void processDataTPCLowPt(aod::ResoCollision& collision, + soa::Filtered const&) + { + if (additionalQAeventPlots) + histos.fill(HIST("QAevent/hEvtCounterSameE"), 1.0); + + auto candPi = resoPiTPClowPt->sliceByCached(aod::resodaughter::resoCollisionId, collision.globalIndex(), cache); + auto candKa = resoKaTPClowPt->sliceByCached(aod::resodaughter::resoCollisionId, collision.globalIndex(), cache); + + fillHistograms(collision, candPi, candKa); + } + PROCESS_SWITCH(kstar892analysis, processDataTPCLowPt, "Process Event for data, TPC at low pt", false); + + void processDataTOFHighPt(aod::ResoCollision& collision, + soa::Filtered const&) + { + if (additionalQAeventPlots) + histos.fill(HIST("QAevent/hEvtCounterSameE"), 1.0); + + auto candPi = resoPiTOFhighPt->sliceByCached(aod::resodaughter::resoCollisionId, collision.globalIndex(), cache); + auto candKa = resoKaTOFhighPt->sliceByCached(aod::resodaughter::resoCollisionId, collision.globalIndex(), cache); + + fillHistograms(collision, candPi, candKa); + } + PROCESS_SWITCH(kstar892analysis, processDataTOFHighPt, "Process Event for data, TOF at high pt", false); + + void processMCLight(ResoMCCols::iterator const& collision, + soa::Filtered> const&) + { + if (!collision.isInAfterAllCuts() || (abs(collision.posZ()) > cZvertCutMC)) // MC event selection, all cuts missing vtx cut + return; + + auto candPi = resoMCrecPi->sliceByCached(aod::resodaughter::resoCollisionId, collision.globalIndex(), cache); + auto candKa = resoMCrecKa->sliceByCached(aod::resodaughter::resoCollisionId, collision.globalIndex(), cache); + + fillHistograms(collision, candPi, candKa); + } + PROCESS_SWITCH(kstar892analysis, processMCLight, "Process Event for MC (Reconstructed)", false); + + void processMCLightWithTof(ResoMCCols::iterator const& collision, + soa::Filtered> const&) + { + if (!collision.isInAfterAllCuts() || (abs(collision.posZ()) > cZvertCutMC)) // MC event selection, all cuts missing vtx cut + return; + + auto candPiwithtof = resoMCrecPiWithTof->sliceByCached(aod::resodaughter::resoCollisionId, collision.globalIndex(), cache); + auto candKawithtof = resoMCrecKaWithTof->sliceByCached(aod::resodaughter::resoCollisionId, collision.globalIndex(), cache); + + fillHistograms(collision, candPiwithtof, candKawithtof); + } + PROCESS_SWITCH(kstar892analysis, processMCLightWithTof, "Process Event for MC (Reconstructed), tracks with TOF", false); + + void processMCLightTPCLowPt(ResoMCCols::iterator const& collision, + soa::Filtered> const&) + { + if (!collision.isInAfterAllCuts() || (abs(collision.posZ()) > cZvertCutMC)) // MC event selection, all cuts missing vtx cut + return; + + auto candPi = resoMCrecPiTPClowPt->sliceByCached(aod::resodaughter::resoCollisionId, collision.globalIndex(), cache); + auto candKa = resoMCrecKaTPClowPt->sliceByCached(aod::resodaughter::resoCollisionId, collision.globalIndex(), cache); + + fillHistograms(collision, candPi, candKa); + } + PROCESS_SWITCH(kstar892analysis, processMCLightTPCLowPt, "Process Event for MC (reconstructed), TPC at low pt", false); + + void processMCLightTOFHighPt(ResoMCCols::iterator const& collision, + soa::Filtered> const&) + { + if (!collision.isInAfterAllCuts() || (abs(collision.posZ()) > cZvertCutMC)) // MC event selection, all cuts missing vtx cut + return; + + auto candPi = resoMCrecPiTOFhighPt->sliceByCached(aod::resodaughter::resoCollisionId, collision.globalIndex(), cache); + auto candKa = resoMCrecKaTOFhighPt->sliceByCached(aod::resodaughter::resoCollisionId, collision.globalIndex(), cache); + + fillHistograms(collision, candPi, candKa); + } + PROCESS_SWITCH(kstar892analysis, processMCLightTOFHighPt, "Process Event for MC (reconstructed), TOF at high pt", false); + + void processMCTrue(ResoMCCols::iterator const& collision, aod::ResoMCParents& resoParents, aod::McParticles& mcparticles) + { + auto multiplicity = collision.cent(); + float impactpar = collision.impactParameter(); + histos.fill(HIST("QAMCTrue/ImpactParameter"), impactpar); + + for (auto& part : resoParents) { // loop over all pre-filtered MC particles + if (abs(part.pdgCode()) != 313 || abs(part.y()) >= 0.5) + continue; + bool pass1 = abs(part.daughterPDG1()) == 211 || abs(part.daughterPDG2()) == 211; + bool pass2 = abs(part.daughterPDG1()) == 321 || abs(part.daughterPDG2()) == 321; + + if (!pass1 || !pass2) + continue; + + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; + + std::vector listDaughters{}; + std::array dauPdgs = {211, 321}; + + auto mcparticle = part.mcParticle_as(); + + RecoDecay::getDaughters(mcparticle, &listDaughters, dauPdgs, 1); + + for (const auto& dauIdx : listDaughters) { + auto dauPart = mcparticles.rawIteratorAt(dauIdx - mcparticles.offset()); + + if (std::abs(dauPart.pdgCode()) == 211) { + lDecayDaughter1.SetXYZM(dauPart.px(), dauPart.py(), dauPart.pz(), massPi); + } else if (std::abs(dauPart.pdgCode()) == 321) { + lDecayDaughter2.SetXYZM(dauPart.px(), dauPart.py(), dauPart.pz(), massKa); + } + } + lResonance = lDecayDaughter1 + lDecayDaughter2; + + if (part.pdgCode() > 0) { // no cuts, purely generated + histos.fill(HIST("k892GenInvmass"), lResonance.M()); + histos.fill(HIST("h3k892GenInvmass"), multiplicity, lResonance.Pt(), lResonance.M()); + histos.fill(HIST("ImpactParPlots/h3k892GenInvmass"), impactpar, lResonance.Pt(), lResonance.M()); + } else { + histos.fill(HIST("k892GenInvmassAnti"), lResonance.M()); + histos.fill(HIST("h3k892GenInvmassAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + histos.fill(HIST("ImpactParPlots/h3k892GenInvmassAnti"), impactpar, lResonance.Pt(), lResonance.M()); + } + + if (collision.isVtxIn10()) // INEL10 + { + if (part.pdgCode() > 0) { + histos.fill(HIST("k892Gen"), 0, part.pt(), multiplicity); + histos.fill(HIST("ImpactParPlots/k892Gen"), 0, part.pt(), impactpar); + } else { + histos.fill(HIST("k892GenAnti"), 0, part.pt(), multiplicity); + histos.fill(HIST("ImpactParPlots/k892GenAnti"), 0, part.pt(), impactpar); + } + } + if (collision.isVtxIn10() && collision.isInSel8()) // INEL>10, vtx10 + { + if (part.pdgCode() > 0) { + histos.fill(HIST("k892Gen"), 1, part.pt(), multiplicity); + histos.fill(HIST("ImpactParPlots/k892Gen"), 1, part.pt(), impactpar); + } else { + histos.fill(HIST("k892GenAnti"), 1, part.pt(), multiplicity); + histos.fill(HIST("ImpactParPlots/k892GenAnti"), 1, part.pt(), impactpar); + } + } + if (collision.isVtxIn10() && collision.isTriggerTVX()) // vtx10, TriggerTVX + { + if (part.pdgCode() > 0) { + histos.fill(HIST("k892Gen"), 2, part.pt(), multiplicity); + histos.fill(HIST("ImpactParPlots/k892Gen"), 2, part.pt(), impactpar); + } else { + histos.fill(HIST("k892GenAnti"), 2, part.pt(), multiplicity); + histos.fill(HIST("ImpactParPlots/k892GenAnti"), 2, part.pt(), impactpar); + } + } + if (collision.isInAfterAllCuts()) // after all event selection + { + if (part.pdgCode() > 0) { + histos.fill(HIST("k892Gen"), 3, part.pt(), multiplicity); + histos.fill(HIST("ImpactParPlots/k892Gen"), 3, part.pt(), impactpar); + } else { + histos.fill(HIST("k892GenAnti"), 3, part.pt(), multiplicity); + histos.fill(HIST("ImpactParPlots/k892GenAnti"), 3, part.pt(), impactpar); + } + } + } + } + PROCESS_SWITCH(kstar892analysis, processMCTrue, "Process Event for MC (Generated)", false); + + // Processing Event Mixing + using BinningTypeVtxZT0M = ColumnBinningPolicy; + void processMELight(o2::aod::ResoCollisions& collisions, soa::Filtered const& resotracks) + { + auto tracksTuple = std::make_tuple(resotracks); + BinningTypeVtxZT0M colBinning{{CfgVtxBins, CfgMultBins}, true}; + SameKindPair, BinningTypeVtxZT0M> pairs{colBinning, nEvtMixing, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + + for (auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (additionalQAeventPlots) + histos.fill(HIST("QAevent/hEvtCounterMixedE"), 1.0); + + auto candPi = resoPi->sliceByCached(aod::resodaughter::resoCollisionId, collision1.globalIndex(), cache); + auto candKa = resoKa->sliceByCached(aod::resodaughter::resoCollisionId, collision2.globalIndex(), cache); + + fillHistograms(collision1, candPi, candKa); + } + } + PROCESS_SWITCH(kstar892analysis, processMELight, "Process EventMixing light without partition", false); + + void processMELightWithTof(o2::aod::ResoCollisions& collisions, soa::Filtered const& resotracks) + { + auto tracksTuple = std::make_tuple(resotracks); + BinningTypeVtxZT0M colBinning{{CfgVtxBins, CfgMultBins}, true}; + SameKindPair, BinningTypeVtxZT0M> pairs{colBinning, nEvtMixing, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + + for (auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (additionalQAeventPlots) + histos.fill(HIST("QAevent/hEvtCounterMixedE"), 1.0); + + auto candPiwithtof = resoPiWithTof->sliceByCached(aod::resodaughter::resoCollisionId, collision1.globalIndex(), cache); + auto candKawithtof = resoKaWithTof->sliceByCached(aod::resodaughter::resoCollisionId, collision2.globalIndex(), cache); + + fillHistograms(collision1, candPiwithtof, candKawithtof); + } + } + PROCESS_SWITCH(kstar892analysis, processMELightWithTof, "Process EventMixing light with tof", false); + + void processMELightTPCLowPt(o2::aod::ResoCollisions& collisions, soa::Filtered const& resotracks) + { + auto tracksTuple = std::make_tuple(resotracks); + BinningTypeVtxZT0M colBinning{{CfgVtxBins, CfgMultBins}, true}; + SameKindPair, BinningTypeVtxZT0M> pairs{colBinning, nEvtMixing, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + + for (auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (additionalQAeventPlots) + histos.fill(HIST("QAevent/hEvtCounterMixedE"), 1.0); + + auto candPi = resoPiTPClowPt->sliceByCached(aod::resodaughter::resoCollisionId, collision1.globalIndex(), cache); + auto candKa = resoKaTPClowPt->sliceByCached(aod::resodaughter::resoCollisionId, collision2.globalIndex(), cache); + + fillHistograms(collision1, candPi, candKa); + } + } + PROCESS_SWITCH(kstar892analysis, processMELightTPCLowPt, "Process EventMixing light with TPC at low pt", false); + + void processMELightTOFHighPt(o2::aod::ResoCollisions& collisions, soa::Filtered const& resotracks) + { + auto tracksTuple = std::make_tuple(resotracks); + BinningTypeVtxZT0M colBinning{{CfgVtxBins, CfgMultBins}, true}; + SameKindPair, BinningTypeVtxZT0M> pairs{colBinning, nEvtMixing, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + + for (auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (additionalQAeventPlots) + histos.fill(HIST("QAevent/hEvtCounterMixedE"), 1.0); + + auto candPi = resoPiTOFhighPt->sliceByCached(aod::resodaughter::resoCollisionId, collision1.globalIndex(), cache); + auto candKa = resoKaTOFhighPt->sliceByCached(aod::resodaughter::resoCollisionId, collision2.globalIndex(), cache); + + fillHistograms(collision1, candPi, candKa); + } + } + PROCESS_SWITCH(kstar892analysis, processMELightTOFHighPt, "Process EventMixing light with TOF at high pt", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"lf-kstar892analysis"})}; +} diff --git a/PWGLF/Tasks/Resonances/kstarFlowv1.cxx b/PWGLF/Tasks/Resonances/kstarFlowv1.cxx new file mode 100644 index 00000000000..08139c3c2d2 --- /dev/null +++ b/PWGLF/Tasks/Resonances/kstarFlowv1.cxx @@ -0,0 +1,356 @@ +// 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 kstarFlowv1.cxx +/// \brief first order flow harmonic for resonance +/// \author Prottay Das , Dukhishyam Mallick +/// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include +#include +#include +#include + +#include "TRandom3.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" +#include "TF1.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/RecoDecay.h" + +#include "PWGLF/DataModel/SPCalibrationTables.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/TrackSelection.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; +using namespace o2::constants::physics; +struct KstarFlowv1 { + + Service ccdb; + // Service pdg; + + // events + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutCentrality{"cfgCutCentrality", 80.0f, "Accepted maximum Centrality"}; + // track + Configurable cfgCutCharge{"cfgCutCharge", 0.0, "cut on Charge"}; + Configurable cfgCutPT{"cfgCutPT", 0.2, "PT cut on daughter track"}; + Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; + Configurable cfgCutDCAxy{"cfgCutDCAxy", 2.0f, "DCAxy range for tracks"}; + Configurable cfgCutDCAz{"cfgCutDCAz", 2.0f, "DCAz range for tracks"}; + Configurable useGlobalTrack{"useGlobalTrack", true, "use Global track"}; + Configurable nsigmaCutTOF{"nsigmaCutTOF", 3.0, "Value of the TOF Nsigma cut"}; + Configurable nsigmaCutTPC{"nsigmaCutTPC", 3.0, "Value of the TPC Nsigma cut"}; + Configurable nsigmaCutCombined{"nsigmaCutCombined", 3.0, "Value of the TOF Nsigma cut"}; + Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 1, "Number of mixed events per event"}; + Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; + // Configurable removefaketrak{"removefaketrack", true, "Remove fake track from momentum difference"}; + Configurable confFakeKaonCut{"confFakeKaonCut", 0.1, "Cut based on track from momentum difference"}; + Configurable ispTdepPID{"ispTdepPID", true, "pT dependent PID"}; + Configurable onlyTOF{"onlyTOF", true, "onlyTOF"}; + Configurable strategyPID{"strategyPID", 2, "PID strategy"}; + Configurable cfgCutTOFBeta{"cfgCutTOFBeta", 0.0, "cut TOF beta"}; + Configurable confMinRot{"confMinRot", 5.0 * o2::constants::math::PI / 6.0, "Minimum of rotation"}; + Configurable confMaxRot{"confMaxRot", 7.0 * o2::constants::math::PI / 6.0, "Maximum of rotation"}; + Configurable nBkgRotations{"nBkgRotations", 9, "Number of rotated copies (background) per each original candidate"}; + Configurable fillRotation{"fillRotation", true, "fill rotation"}; + Configurable like{"like", true, "fill rotation"}; + Configurable spNbins{"spNbins", 2000, "Number of bins in sp"}; + Configurable lbinsp{"lbinsp", -1.0, "lower bin value in sp histograms"}; + Configurable hbinsp{"hbinsp", 1.0, "higher bin value in sp histograms"}; + + ConfigurableAxis configcentAxis{"configcentAxis", {VARIABLE_WIDTH, 0.0, 10.0, 30.0, 50.0, 80.0}, "Cent V0M"}; + ConfigurableAxis configthnAxisPt{"configthnAxisPt", {VARIABLE_WIDTH, 0.2, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.5, 8.0, 10.0, 50.0}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis configetaAxis{"configetaAxis", {VARIABLE_WIDTH, -0.8, -0.4, -0.2, 0, 0.2, 0.4, 0.8}, "Eta"}; + ConfigurableAxis configIMAxis{"configIMAxis", {VARIABLE_WIDTH, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, 1.05, 1.1, 1.15, 1.2}, "IM"}; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter centralityFilter = nabs(aod::cent::centFT0C) < cfgCutCentrality; + Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPT); + Filter dCAcutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); + + using EventCandidates = soa::Filtered>; + using TrackCandidates = soa::Filtered>; + + SliceCache cache; + Partition posTracks = aod::track::signed1Pt > cfgCutCharge; + Partition negTracks = aod::track::signed1Pt < cfgCutCharge; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + AxisSpec spAxis = {spNbins, lbinsp, hbinsp, "Sp"}; + + histos.add("hpQxtQxpvscent", "hpQxtQxpvscent", HistType::kTHnSparseF, {configcentAxis, spAxis}, true); + histos.add("hpQytQypvscent", "hpQytQypvscent", HistType::kTHnSparseF, {configcentAxis, spAxis}, true); + histos.add("hpQxytpvscent", "hpQxytpvscent", HistType::kTHnSparseF, {configcentAxis, spAxis}, true); + histos.add("hpQxtQypvscent", "hpQxtQypvscent", HistType::kTHnSparseF, {configcentAxis, spAxis}, true); + histos.add("hpQxpQytvscent", "hpQxpQytvscent", HistType::kTHnSparseF, {configcentAxis, spAxis}, true); + + histos.add("hpv1vscentpteta", "hpv1vscentpteta", HistType::kTHnSparseF, {configIMAxis, configcentAxis, configthnAxisPt, configetaAxis, spAxis}, true); + histos.add("hpv1vscentptetarot", "hpv1vscentptetarot", HistType::kTHnSparseF, {configIMAxis, configcentAxis, configthnAxisPt, configetaAxis, spAxis}, true); + histos.add("hpv1vscentptetalike", "hpv1vscentptetalike", HistType::kTHnSparseF, {configIMAxis, configcentAxis, configthnAxisPt, configetaAxis, spAxis}, true); + } + + double massKa = o2::constants::physics::MassKPlus; + double massPi = o2::constants::physics::MassPiMinus; + + template + bool selectionTrack(const T& candidate) + { + if (useGlobalTrack && !(candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsFound() > cfgTPCcluster)) { + return false; + } + if (!useGlobalTrack && !(candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster)) { + return false; + } + return true; + } + + template + bool strategySelectionPID(const T& candidate, int PID, int strategy) + { + if (PID == 0) { + if (strategy == 0) { + if (candidate.pt() < 0.5 && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.5 && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < nsigmaCutTOF && candidate.beta() > 0.5) { + return true; + } + } else if (strategy == 1) { + if (candidate.pt() < 0.5 && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.5 && std::sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < nsigmaCutTOF && candidate.beta() > 0.5) { + return true; + } + } else if (strategy == 2) { + if (candidate.pt() < 0.5 && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.5 && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < nsigmaCutTOF && candidate.beta() > 0.5) { + return true; + } + if (candidate.pt() >= 0.5 && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && !candidate.hasTOF()) { + return true; + } + } + } + if (PID == 1) { + if (strategy == 0) { + if (candidate.pt() < 0.5 && std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.5 && std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC && candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < nsigmaCutTOF && candidate.beta() > 0.5) { + return true; + } + } else if (strategy == 1) { + if (candidate.pt() < 0.5 && std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.5 && std::sqrt(candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi() + candidate.tofNSigmaPi() * candidate.tofNSigmaPi()) < nsigmaCutTOF && candidate.beta() > 0.5) { + return true; + } + } else if (strategy == 2) { + if (candidate.pt() < 0.5 && std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.5 && std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC && candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < nsigmaCutTOF && candidate.beta() > 0.5) { + return true; + } + if (candidate.pt() >= 0.5 && std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC && !candidate.hasTOF()) { + return true; + } + } + } + return false; + } + + double getPhiInRange(double phi) + { + double pi = o2::constants::math::PI; + double twoPi = 2.0 * pi; + double result = phi; + // Normalize to [-pi, pi] + // double result = std::fmod(phi + pi, twoPi); + // if (result < 0) { + // result += twoPi; + // } + // result -= pi; // Now result is in [-pi, pi] + + // Convert from [-pi, pi] to [0, pi] + if (result < 0) { + result += pi; // Shift negative values to positive + } + + // If phi > 2π, subtract π instead of normalizing by 2π + if (phi > twoPi) { + result -= pi; + } + + return result; // Ensures range is [0, π] + } + + template + bool isFakeKaon(T const& track, int /*PID*/) + { + const auto pglobal = track.p(); + const auto ptpc = track.tpcInnerParam(); + if (std::abs(pglobal - ptpc) > confFakeKaonCut) { + return true; + } + return false; + } + + ROOT::Math::PxPyPzMVector KstarMother, daughter1, daughter2, kaonrot, kstarrot; + + void processSE(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) + { + if (!collision.sel8() || !collision.triggereventsp() || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; + } + auto centrality = collision.centFT0C(); + + auto qxZDCA = collision.qxZDCA(); + auto qxZDCC = collision.qxZDCC(); + auto qyZDCA = collision.qyZDCA(); + auto qyZDCC = collision.qyZDCC(); + + auto proQxtQxp = qxZDCA * qxZDCC; + auto proQytQyp = qyZDCA * qyZDCC; + auto proQxytp = proQxtQxp + proQytQyp; + auto proQxpQyt = qxZDCA * qyZDCC; + auto proQxtQyp = qxZDCC * qyZDCA; + + histos.fill(HIST("hpQxtQxpvscent"), centrality, proQxtQxp); + histos.fill(HIST("hpQytQypvscent"), centrality, proQytQyp); + histos.fill(HIST("hpQxytpvscent"), centrality, proQxytp); + histos.fill(HIST("hpQxpQytvscent"), centrality, proQxpQyt); + histos.fill(HIST("hpQxtQypvscent"), centrality, proQxtQyp); + + for (const auto& track1 : tracks) { + if (!selectionTrack(track1)) { + continue; + } + bool track1kaon = false; + auto track1ID = track1.globalIndex(); + if (!strategySelectionPID(track1, 0, strategyPID)) { + continue; + } + track1kaon = true; + for (const auto& track2 : tracks) { + if (!selectionTrack(track2)) { + continue; + } + bool track2pion = false; + auto track2ID = track2.globalIndex(); + if (!strategySelectionPID(track2, 1, strategyPID)) { + continue; + } + track2pion = true; + if (track2ID == track1ID) { + continue; + } + if (!track1kaon || !track2pion) { + continue; + } + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); + KstarMother = daughter1 + daughter2; + if (std::abs(KstarMother.Rapidity()) > 0.9) { + continue; + } + + // // constrain angle to 0 -> [0,0+2pi] + // auto phi = RecoDecay::constrainAngle(KstarMother.Phi(), 0,o2::constants::math::TwoPI); + + auto ux = std::cos(getPhiInRange(KstarMother.Phi())); + auto uy = std::sin(getPhiInRange(KstarMother.Phi())); + auto v1 = ux * (qxZDCA - qxZDCC) + uy * (qyZDCA - qyZDCC); + + // unlike sign + if (track1.sign() * track2.sign() < 0) { + histos.fill(HIST("hpv1vscentpteta"), KstarMother.M(), centrality, KstarMother.Pt(), KstarMother.Rapidity(), v1); + if (fillRotation) { + for (int nrotbkg = 0; nrotbkg < nBkgRotations; nrotbkg++) { + auto anglestart = confMinRot; + auto angleend = confMaxRot; + auto anglestep = (angleend - anglestart) / (1.0 * (nBkgRotations - 1)); + auto rotangle = anglestart + nrotbkg * anglestep; + auto rotkaonPx = track1.px() * std::cos(rotangle) - track1.py() * std::sin(rotangle); + auto rotkaonPy = track1.px() * std::sin(rotangle) + track1.py() * std::cos(rotangle); + kaonrot = ROOT::Math::PxPyPzMVector(rotkaonPx, rotkaonPy, track1.pz(), massKa); + kstarrot = kaonrot + daughter2; + + if (std::abs(kstarrot.Rapidity()) > 0.9) { + continue; + } + + auto uxrot = std::cos(getPhiInRange(KstarMother.Phi())); + auto uyrot = std::sin(getPhiInRange(KstarMother.Phi())); + + auto v1rot = uxrot * (qxZDCA - qxZDCC) + uyrot * (qyZDCA - qyZDCC); + + histos.fill(HIST("hpv1vscentptetarot"), kstarrot.M(), centrality, kstarrot.Pt(), kstarrot.Rapidity(), v1rot); + } + } + } + // like sign + if (track1.sign() * track2.sign() > 0) { + histos.fill(HIST("hpv1vscentptetalike"), kstarrot.M(), centrality, kstarrot.Pt(), kstarrot.Rapidity(), v1); + } + } + } + } + PROCESS_SWITCH(KstarFlowv1, processSE, "Process Same event", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/kstarpbpb.cxx b/PWGLF/Tasks/Resonances/kstarpbpb.cxx index 55a78e3c968..b6a0cfb453b 100644 --- a/PWGLF/Tasks/Resonances/kstarpbpb.cxx +++ b/PWGLF/Tasks/Resonances/kstarpbpb.cxx @@ -8,7 +8,7 @@ // 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. -// sourav.kundu@cern.ch +// sourav.kundu@cern.ch , sarjeeta.gami@cern.ch #include #include @@ -20,10 +20,11 @@ #include #include #include -#include #include #include #include +#include +#include #include "TRandom3.h" #include "Math/Vector3D.h" @@ -37,7 +38,6 @@ #include "Framework/AnalysisDataModel.h" #include "Framework/HistogramRegistry.h" #include "Framework/StepTHn.h" -#include "Framework/O2DatabasePDGPlugin.h" #include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Centrality.h" @@ -51,6 +51,9 @@ #include "DataFormatsParameters/GRPObject.h" #include "DataFormatsParameters/GRPMagField.h" #include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table using namespace o2; using namespace o2::framework; @@ -58,53 +61,91 @@ using namespace o2::framework::expressions; using std::array; struct kstarpbpb { - int mRunNumber; - int multEstimator; - float d_bz; + struct : ConfigurableGroup { + Configurable cfgURL{"cfgURL", "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; + Configurable nolaterthan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "Latest acceptable timestamp of creation for the object"}; + } cfgCcdbParam; + + // Enable access to the CCDB for the offset and correction constants and save them in dedicated variables. Service ccdb; - Service pdg; + o2::ccdb::CcdbApi ccdbApi; + // Service pdg; // CCDB options - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + // Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + // Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + // Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + // Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + // Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; // events Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutCentrality{"cfgCutCentrality", 80.0f, "Accepted maximum Centrality"}; // track Configurable cfgCutCharge{"cfgCutCharge", 0.0, "cut on Charge"}; + Configurable additionalEvSel2{"additionalEvSel2", true, "Additional evsel2"}; + Configurable additionalEvSel3{"additionalEvSel3", true, "Additional evsel3"}; Configurable cfgCutPT{"cfgCutPT", 0.2, "PT cut on daughter track"}; Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; Configurable cfgCutDCAxy{"cfgCutDCAxy", 2.0f, "DCAxy range for tracks"}; Configurable cfgCutDCAz{"cfgCutDCAz", 2.0f, "DCAz range for tracks"}; Configurable useGlobalTrack{"useGlobalTrack", true, "use Global track"}; + Configurable nsigmaCutTOF{"nsigmacutTOF", 3.0, "Value of the TOF Nsigma cut"}; Configurable nsigmaCutTPC{"nsigmacutTPC", 3.0, "Value of the TPC Nsigma cut"}; + Configurable isTOFOnly{"isTOFOnly", false, "use TOF only PID"}; Configurable nsigmaCutCombined{"nsigmaCutCombined", 3.0, "Value of the TOF Nsigma cut"}; Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 1, "Number of mixed events per event"}; Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; Configurable cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; Configurable confRapidity{"confRapidity", 0.5, "Rapidity cut"}; - ConfigurableAxis configThnAxisInvMass{"configThnAxisInvMass", {120, 0.66, 1.2}, "#it{M} (GeV/#it{c}^{2})"}; + ConfigurableAxis configThnAxisInvMass{"configThnAxisInvMass", {180, 0.6, 1.5}, "#it{M} (GeV/#it{c}^{2})"}; ConfigurableAxis configThnAxisPt{"configThnAxisPt", {100, 0.0, 10.}, "#it{p}_{T} (GeV/#it{c})"}; ConfigurableAxis configThnAxisCentrality{"configThnAxisCentrality", {8, 0., 80}, "Centrality"}; - ConfigurableAxis configThnAxisPhiminusPsi{"configThnAxisPhiminusPsi", {6, 0.0, TMath::Pi()}, "#phi - #psi"}; - ConfigurableAxis configThnAxisV2{"configThnAxisV2", {200, -1, 1}, "V2"}; + ConfigurableAxis configrapAxis{"configrapAxis", {VARIABLE_WIDTH, -0.8, -0.4, 0.4, 0.8}, "Rapidity"}; + Configurable removefaketrak{"removefaketrack", true, "Remove fake track from momentum difference"}; + Configurable ConfFakeKaonCut{"ConfFakeKaonCut", 0.1, "Cut based on track from momentum difference"}; + ConfigurableAxis configThnAxisV2{"configThnAxisV2", {400, -16, 16}, "V2"}; Configurable additionalEvsel{"additionalEvsel", false, "Additional event selcection"}; Configurable timFrameEvsel{"timFrameEvsel", false, "TPC Time frame boundary cut"}; + Configurable additionalEvselITS{"additionalEvselITS", true, "Additional event selcection for ITS"}; Configurable ispTdepPID{"ispTdepPID", true, "pT dependent PID"}; + Configurable isNoTOF{"isNoTOF", true, "isNoTOF"}; + Configurable PDGcheck{"PDGcheck", true, "PDGcheck"}; + Configurable strategyPID{"strategyPID", 2, "PID strategy"}; + Configurable cfgCutTOFBeta{"cfgCutTOFBeta", 0.0, "cut TOF beta"}; Configurable additionalQAplots{"additionalQAplots", true, "Additional QA plots"}; + Configurable additionalQAplots1{"additionalQAplots1", true, "Additional QA plots"}; + Configurable confMinRot{"confMinRot", 5.0 * TMath::Pi() / 6.0, "Minimum of rotation"}; + Configurable confMaxRot{"confMaxRot", 7.0 * TMath::Pi() / 6.0, "Maximum of rotation"}; + Configurable nBkgRotations{"nBkgRotations", 9, "Number of rotated copies (background) per each original candidate"}; + Configurable fillRotation{"fillRotation", true, "fill rotation"}; + Configurable same{"same", true, "same event"}; + Configurable like{"like", false, "like-sign"}; + Configurable fillSA{"fillSA", true, "same event SA"}; + Configurable fillOccupancy{"fillOccupancy", false, "fill Occupancy"}; + Configurable cfgOccupancyCut{"cfgOccupancyCut", 500, "Occupancy cut"}; + Configurable useWeight{"useWeight", false, "use EP dep effi weight"}; + Configurable useSP{"useSP", false, "use SP"}; + Configurable genacceptancecut{"genacceptancecut", true, "use acceptance cut for generated"}; + Configurable avoidsplitrackMC{"avoidsplitrackMC", false, "avoid split track in MC"}; + Configurable ConfWeightPath{"ConfWeightPath", "Users/s/skundu/My/Object/fitweight", "Path to gain calibration"}; + ConfigurableAxis axisPtKaonWeight{"axisPtKaonWeight", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f}, "pt axis"}; Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter centralityFilter = nabs(aod::cent::centFT0C) < cfgCutCentrality; Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPT); Filter DCAcutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); using EventCandidates = soa::Filtered>; - using TrackCandidates = soa::Filtered>; + using TrackCandidates = soa::Filtered>; + + using CollisionMCTrueTable = aod::McCollisions; + using TrackMCTrueTable = aod::McParticles; + using CollisionMCRecTableCentFT0C = soa::SmallGroups>; + using TrackMCRecTable = soa::Join; + using FilTrackMCRecTable = soa::Filtered; - using EventCandidatesMC = soa::Join; - using TrackCandidatesMC = soa::Filtered>; + Preslice perCollision = aod::track::collisionId; SliceCache cache; Partition posTracks = aod::track::signed1Pt > cfgCutCharge; @@ -121,30 +162,72 @@ struct kstarpbpb { void init(o2::framework::InitContext&) { - const AxisSpec thnAxisInvMass{configThnAxisInvMass, "#it{M} (GeV/#it{c}^{2})"}; - const AxisSpec thnAxisPt{configThnAxisPt, "#it{p}_{T} (GeV/#it{c})"}; - const AxisSpec thnAxisPhiminusPsi{configThnAxisPhiminusPsi, "#phi - #psi"}; - const AxisSpec thnAxisCentrality{configThnAxisCentrality, "Centrality (%)"}; - const AxisSpec thnAxisV2{configThnAxisV2, "V2"}; + std::vector occupancyBinning = {0.0, 500.0, 1000.0, 1500.0, 2000.0, 3000.0, 4000.0, 5000.0, 50000.0}; AxisSpec phiAxis = {500, -6.28, 6.28, "phi"}; - AxisSpec resAxis = {400, -2, 2, "Res"}; + AxisSpec resAxis = {6000, -30, 30, "Res"}; AxisSpec centAxis = {8, 0, 80, "V0M (%)"}; + AxisSpec occupancyAxis = {occupancyBinning, "Occupancy"}; + if (!fillSA) { + if (same) { + histos.add("hSparseV2SASameEvent_V2", "hSparseV2SASameEvent_V2", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisPt, configThnAxisV2, configThnAxisCentrality}); + } + if (like) { + histos.add("hSparseV2SAlikeEventNN_V2", "hSparseV2SAlikeEventNN_V2", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisPt, configThnAxisV2, configThnAxisCentrality}); + histos.add("hSparseV2SAlikeEventPP_V2", "hSparseV2SAlikeEventPP_V2", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisPt, configThnAxisV2, configThnAxisCentrality}); + } + } + if (fillRotation) { + if (!fillSA) { + histos.add("hRotation", "hRotation", kTH1F, {{360, 0.0, 2.0 * TMath::Pi()}}); + histos.add("hSparseV2SASameEventRotational_V2", "hSparseV2SASameEventRotational_V2", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisPt, configThnAxisV2, configThnAxisCentrality}); + } + } - histos.add("hpTvsRapidity", "pT vs Rapidity", kTH2F, {{100, 0.0f, 10.0f}, {300, -1.5f, 1.5f}}); - histos.add("hFTOCvsTPC", "Mult correlation FT0C vs. TPC", kTH2F, {{80, 0.0f, 80.0f}, {100, -0.5f, 5999.5f}}); - histos.add("hFTOCvsTPCSelected", "Mult correlation FT0C vs. TPC after selection", kTH2F, {{80, 0.0f, 80.0f}, {100, -0.5f, 5999.5f}}); - histos.add("hCentrality", "Centrality distribution", kTH1F, {{200, 0.0, 200.0}}); - histos.add("hVtxZ", "Vertex distribution in Z;Z (cm)", kTH1F, {{400, -20.0, 20.0}}); - histos.add("hPsiFT0C", "PsiFT0C", kTH2F, {centAxis, phiAxis}); - histos.add("hPsiFT0A", "PsiFT0A", kTH2F, {centAxis, phiAxis}); - histos.add("hPsiTPC", "PsiTPC", kTH2F, {centAxis, phiAxis}); - histos.add("hSparseV2SASameEvent_V2", "hSparseV2SASameEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEvent_V2", "hSparseV2SAMixedEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); - - // histogram for resolution - histos.add("ResFT0CTPC", "ResFT0CTPC", kTH2F, {centAxis, resAxis}); - histos.add("ResFT0CFT0A", "ResFT0CFT0A", kTH2F, {centAxis, resAxis}); - histos.add("ResFT0ATPC", "ResFT0ATPC", kTH2F, {centAxis, resAxis}); + if (fillSA) { + histos.add("hSparseSAvsrapsameunlike", "hSparseSAvsrapsameunlike", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisPt, configThnAxisV2, configrapAxis, configThnAxisCentrality}, true); + histos.add("hSparseSAvsrapsamelike", "hSparseSAvsrapsamelike", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisPt, configThnAxisV2, configrapAxis, configThnAxisCentrality}, true); + histos.add("hSparseSAvsraprot", "hSparseSAvsraprot", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisPt, configThnAxisV2, configrapAxis, configThnAxisCentrality}, true); + histos.add("hSparseSAvsrapmix", "hSparseSAvsrapmix", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisPt, configThnAxisV2, configrapAxis, configThnAxisCentrality}, true); + } + if (!fillSA) { + histos.add("hSparseV2SAGen_V2", "hSparseV2SAGen_V2", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisPt, configThnAxisV2, configThnAxisCentrality}); + histos.add("hSparseV2SARec_V2", "hSparseV2SARec_V2", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisPt, configThnAxisV2, configThnAxisCentrality}); + histos.add("hpt", "hpt", kTH1F, {configThnAxisPt}); + histos.add("hMC", "MC Event statistics", kTH1F, {{10, 0.0f, 10.0f}}); + histos.add("h1PhiRecsplit", "Phi meson Rec split", kTH1F, {{100, 0.0f, 10.0f}}); + histos.add("CentPercentileMCRecHist", "MC Centrality", kTH1F, {{100, 0.0f, 100.0f}}); + histos.add("hSparseV2SAMixedEvent_V2", "hSparseV2SAMixedEvent_V2", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisPt, configThnAxisV2, configThnAxisCentrality}); + histos.add("h2PhiGen2", "Phi meson gen", kTH2F, {configThnAxisPt, configThnAxisCentrality}); + histos.add("h2PhiRec2", "Phi meson Rec", kTH2F, {configThnAxisPt, configThnAxisCentrality}); + histos.add("hImpactParameter", "Impact parameter", kTH1F, {{200, 0.0f, 20.0f}}); + histos.add("hEventPlaneAngle", "hEventPlaneAngle", kTH1F, {{200, -2.0f * TMath::Pi(), 2.0f * TMath::Pi()}}); + histos.add("hSparseKstarMCGenWeight", "hSparseKstarMCGenWeight", HistType::kTHnSparseD, {configThnAxisCentrality, {36, 0.0f, TMath::Pi()}, {400, 0.0f, 1}, configThnAxisPt, {8, -0.8, 0.8}}); + histos.add("hSparseKstarMCRecWeight", "hSparseKstarMCRecWeight", HistType::kTHnSparseD, {configThnAxisCentrality, {36, 0.0f, TMath::Pi()}, {400, 0.0f, 1}, configThnAxisPt, {8, -0.8, 0.8}}); + histos.add("hSparseKstarMCGenKaonWeight", "hSparseKstarMCGenKaonWeight", HistType::kTHnSparseD, {configThnAxisCentrality, {36, 0.0f, TMath::Pi()}, {400, 0.0f, 1}, axisPtKaonWeight, {8, -0.8, 0.8}}); + histos.add("hSparseKstarMCRecKaonWeight", "hSparseKstarMCRecKaonWeight", HistType::kTHnSparseD, {configThnAxisCentrality, {36, 0.0f, TMath::Pi()}, {400, 0.0f, 1}, axisPtKaonWeight, {8, -0.8, 0.8}}); + histos.add("hSparseKstarMCRecKaonMissMatchWeight", "hSparseKstarMCRecKaonMissMatchWeight", HistType::kTHnSparseD, {configThnAxisCentrality, {36, 0.0f, TMath::Pi()}, {400, 0.0f, 1}, axisPtKaonWeight, {8, -0.8, 0.8}}); + histos.add("hSparseKstarMCGenPionWeight", "hSparseKstarMCGenPionWeight", HistType::kTHnSparseD, {configThnAxisCentrality, {36, 0.0f, TMath::Pi()}, {400, 0.0f, 1}, axisPtKaonWeight, {8, -0.8, 0.8}}); + histos.add("hSparseKstarMCRecPionWeight", "hSparseKstarMCRecPionWeight", HistType::kTHnSparseD, {configThnAxisCentrality, {36, 0.0f, TMath::Pi()}, {400, 0.0f, 1}, axisPtKaonWeight, {8, -0.8, 0.8}}); + histos.add("hSparseKstarMCRecPionMissMatchWeight", "hSparseKstarMCRecPionMissMatchWeight", HistType::kTHnSparseD, {configThnAxisCentrality, {36, 0.0f, TMath::Pi()}, {400, 0.0f, 1}, axisPtKaonWeight, {8, -0.8, 0.8}}); + } + if (additionalQAplots1) { + histos.add("hFTOCvsTPCSelected", "Mult correlation FT0C vs. TPC after selection", kTH2F, {{80, 0.0f, 80.0f}, {100, -0.5f, 5999.5f}}); + histos.add("hCentrality", "Centrality distribution", kTH1F, {{200, 0.0, 200.0}}); + histos.add("hOccupancy", "Occupancy distribution", kTH1F, {occupancyAxis}); + histos.add("hVtxZ", "Vertex distribution in Z;Z (cm)", kTH1F, {{400, -20.0, 20.0}}); + histos.add("hPsiFT0C", "PsiFT0C", kTH2F, {centAxis, phiAxis}); + histos.add("hPsiFT0A", "PsiFT0A", kTH2F, {centAxis, phiAxis}); + histos.add("hPsiTPC", "PsiTPC", kTH2F, {centAxis, phiAxis}); + histos.add("ResFT0CTPC", "ResFT0CTPC", kTH2F, {centAxis, resAxis}); + histos.add("ResFT0CFT0A", "ResFT0CFT0A", kTH2F, {centAxis, resAxis}); + histos.add("ResFT0ATPC", "ResFT0ATPC", kTH2F, {centAxis, resAxis}); + histos.add("ResFT0CTPCSP", "ResFT0CTPCSP", kTH2F, {centAxis, resAxis}); + histos.add("ResFT0CFT0ASP", "ResFT0CFT0ASP", kTH2F, {centAxis, resAxis}); + histos.add("ResFT0ATPCSP", "ResFT0ATPCSP", kTH2F, {centAxis, resAxis}); + histos.add("ResTrackSPFT0CTPC", "ResTrackSPFT0CTPC", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("ResTrackSPFT0CFT0A", "ResTrackSPFT0CFT0A", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("ResTrackSPFT0ATPC", "ResTrackSPFT0ATPC", kTH3F, {centAxis, occupancyAxis, resAxis}); + } if (additionalQAplots) { // DCA QA histos.add("QAbefore/trkDCAxyka", "DCAxy distribution of kaon track candidates", HistType::kTH1F, {{150, 0.0f, 1.0f}}); @@ -153,12 +236,12 @@ struct kstarpbpb { histos.add("QAafter/trkDCAzka", "DCAz distribution of kaon track candidates", HistType::kTH1F, {{150, 0.0f, 1.0f}}); // PID QA before cuts histos.add("QAbefore/TOF_TPC_Mapka_allka", "TOF + TPC Combined PID for Kaon;#sigma_{TOF}^{Kaon};#sigma_{TPC}^{Kaon}", {HistType::kTH2D, {{100, -6, 6}, {100, -6, 6}}}); - histos.add("QAbefore/TOF_Nsigma_allka", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH2D, {{200, 0.0, 20.0}, {100, -6, 6}}}); - histos.add("QAbefore/TPC_Nsigma_allka", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH2D, {{200, 0.0, 20.0}, {100, -6, 6}}}); + histos.add("QAbefore/TOF_Nsigma_allka", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3D, {{200, 0.0, 20.0}, {100, -6, 6}, {100, 0.0, 100.0}}}); + histos.add("QAbefore/TPC_Nsigma_allka", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3D, {{200, 0.0, 20.0}, {100, -6, 6}, {100, 0.0, 100.0}}}); // PID QA after cuts histos.add("QAafter/TOF_TPC_Mapka_allka", "TOF + TPC Combined PID for Kaon;#sigma_{TOF}^{Kaon};#sigma_{TPC}^{Kaon}", {HistType::kTH2D, {{100, -6, 6}, {100, -6, 6}}}); - histos.add("QAafter/TOF_Nsigma_allka", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH2D, {{200, 0.0, 20.0}, {100, -6, 6}}}); - histos.add("QAafter/TPC_Nsigma_allka", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH2D, {{200, 0.0, 20.0}, {100, -6, 6}}}); + histos.add("QAafter/TOF_Nsigma_allka", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3D, {{200, 0.0, 20.0}, {100, -6, 6}, {100, 0.0, 100.0}}}); + histos.add("QAafter/TPC_Nsigma_allka", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3D, {{200, 0.0, 20.0}, {100, -6, 6}, {100, 0.0, 100.0}}}); // DCA QA histos.add("QAbefore/trkDCAxypi", "DCAxy distribution of pion track candidates", HistType::kTH1F, {{150, 0.0f, 1.0f}}); @@ -167,13 +250,14 @@ struct kstarpbpb { histos.add("QAafter/trkDCAzpi", "DCAz distribution of pion track candidates", HistType::kTH1F, {{150, 0.0f, 1.0f}}); // PID QA before cuts histos.add("QAbefore/TOF_TPC_Mapka_allpi", "TOF + TPC Combined PID for pion;#sigma_{TOF}^{pion};#sigma_{TPC}^{pion}", {HistType::kTH2D, {{100, -6, 6}, {100, -6, 6}}}); - histos.add("QAbefore/TOF_Nsigma_allpi", "TOF NSigma for pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{pion};", {HistType::kTH2D, {{200, 0.0, 20.0}, {100, -6, 6}}}); - histos.add("QAbefore/TPC_Nsigma_allpi", "TPC NSigma for pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{pion};", {HistType::kTH2D, {{200, 0.0, 20.0}, {100, -6, 6}}}); + histos.add("QAbefore/TOF_Nsigma_allpi", "TOF NSigma for pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{pion};", {HistType::kTH3D, {{200, 0.0, 20.0}, {100, -6, 6}, {100, 0.0, 100.0}}}); + histos.add("QAbefore/TPC_Nsigma_allpi", "TPC NSigma for pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{pion};", {HistType::kTH3D, {{200, 0.0, 20.0}, {100, -6, 6}, {100, 0.0, 100.0}}}); // PID QA after cuts histos.add("QAafter/TOF_TPC_Mapka_allpi", "TOF + TPC Combined PID for pion;#sigma_{TOF}^{pion};#sigma_{TPC}^{pion}", {HistType::kTH2D, {{100, -6, 6}, {100, -6, 6}}}); - histos.add("QAafter/TOF_Nsigma_allpi", "TOF NSigma for pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{pion};", {HistType::kTH2D, {{200, 0.0, 20.0}, {100, -6, 6}}}); - histos.add("QAafter/TPC_Nsigma_allpi", "TPC NSigma for pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{pion};", {HistType::kTH2D, {{200, 0.0, 20.0}, {100, -6, 6}}}); + histos.add("QAafter/TOF_Nsigma_allpi", "TOF NSigma for pion;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{pion};", {HistType::kTH3D, {{200, 0.0, 20.0}, {100, -6, 6}, {100, 0.0, 100.0}}}); + histos.add("QAafter/TPC_Nsigma_allpi", "TPC NSigma for pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{pion};", {HistType::kTH3D, {{200, 0.0, 20.0}, {100, -6, 6}, {100, 0.0, 100.0}}}); } + // Event selection cut additional - Alex if (additionalEvsel) { fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); @@ -187,13 +271,18 @@ struct kstarpbpb { fMultMultPVCut = new TF1("fMultMultPVCut", "[0]+[1]*x+[2]*x*x", 0, 5000); fMultMultPVCut->SetParameters(-0.1, 0.785, -4.7e-05); } + ccdb->setURL(cfgCcdbParam.cfgURL); + ccdbApi.init("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); } double massKa = o2::constants::physics::MassKPlus; double massPi = o2::constants::physics::MassPiMinus; template - bool eventSelected(TCollision collision, const int& /*multTrk*/, const float& centrality) + bool eventSelected(TCollision collision, const float& centrality) { if (collision.alias_bit(kTVXinTRD)) { // TRD triggered @@ -213,7 +302,6 @@ struct kstarpbpb { return 1; } - template bool selectionTrack(const T& candidate) { @@ -227,47 +315,145 @@ struct kstarpbpb { } template - bool selectionPIDpTdependent(const T& candidate, int PID) + bool selectionPIDNew(const T& candidate, int PID) { if (PID == 0) { - if (candidate.p() < 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + if (candidate.pt() < 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { return true; } - if (candidate.p() >= 0.5 && candidate.hasTOF() && ((candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) + (candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa())) < (nsigmaCutCombined * nsigmaCutCombined)) { + if (candidate.pt() >= 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && candidate.hasTOF() && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF && candidate.beta() > cfgCutTOFBeta) { + return true; + } + if (candidate.pt() >= 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && !candidate.hasTOF()) { return true; } } else if (PID == 1) { - if (candidate.p() < 0.5 && TMath::Abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC) { + if (candidate.pt() < 0.5 && TMath::Abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.5 && TMath::Abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC && candidate.hasTOF() && TMath::Abs(candidate.tofNSigmaPi()) < nsigmaCutTOF && candidate.beta() > cfgCutTOFBeta) { return true; } - if (candidate.p() >= 0.5 && candidate.hasTOF() && ((candidate.tofNSigmaPi() * candidate.tofNSigmaPi()) + (candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi())) < (nsigmaCutCombined * nsigmaCutCombined)) { + if (candidate.pt() >= 0.5 && TMath::Abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC && !candidate.hasTOF()) { + return true; + } + } + return false; + } + template + bool selectionPID2(const T& candidate, int PID) + { + if (PID == 0) { + if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF) { + return true; + } + } + if (PID == 1) { + if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && TMath::Abs(candidate.tofNSigmaPi()) < nsigmaCutTOF) { return true; } } return false; } - template bool selectionPID(const T& candidate, int PID) { if (PID == 0) { - if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + if (!isNoTOF && !candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return true; + } + if (!isNoTOF && candidate.hasTOF() && ((candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) + (candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa())) < (nsigmaCutCombined * nsigmaCutCombined)) { return true; } - if (candidate.hasTOF() && ((candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) + (candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa())) < (nsigmaCutCombined * nsigmaCutCombined)) { + if (isNoTOF && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { return true; } } else if (PID == 1) { - if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC) { + if (!isNoTOF && !candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC) { return true; } - if (candidate.hasTOF() && ((candidate.tofNSigmaPi() * candidate.tofNSigmaPi()) + (candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi())) < (nsigmaCutCombined * nsigmaCutCombined)) { + if (!isNoTOF && candidate.hasTOF() && ((candidate.tofNSigmaPi() * candidate.tofNSigmaPi()) + (candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi())) < (nsigmaCutCombined * nsigmaCutCombined)) { + return true; + } + if (isNoTOF && std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC) { return true; } } return false; } + template + bool strategySelectionPID(const T& candidate, int PID, int strategy) + { + if (PID == 0) { + if (strategy == 0) { + if (!isNoTOF && !candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return true; + } + if (!isNoTOF && candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF) { + return true; + } + if (isNoTOF && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return true; + } + } else if (strategy == 1) { + if (candidate.pt() < 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && candidate.hasTOF() && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF && candidate.beta() > cfgCutTOFBeta) { + return true; + } + if (!useGlobalTrack && !candidate.hasTPC()) { + return true; + } + } else if (strategy == 2) { + if (candidate.pt() < 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && candidate.hasTOF() && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF && candidate.beta() > cfgCutTOFBeta) { + return true; + } + if (candidate.pt() >= 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && !candidate.hasTOF()) { + return true; + } + } + } + if (PID == 1) { + if (strategy == 0) { + if (!isNoTOF && !candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC) { + return true; + } + if (!isNoTOF && candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC && TMath::Abs(candidate.tofNSigmaPi()) < nsigmaCutTOF) { + return true; + } + if (isNoTOF && std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC) { + return true; + } + } else if (strategy == 1) { + if (candidate.pt() < 0.5 && TMath::Abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.5 && TMath::Abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC && candidate.hasTOF() && TMath::Abs(candidate.tofNSigmaPi()) < nsigmaCutTOF && candidate.beta() > cfgCutTOFBeta) { + return true; + } + if (!useGlobalTrack && !candidate.hasTPC()) { + return true; + } + } else if (strategy == 2) { + if (candidate.pt() < 0.5 && TMath::Abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.5 && TMath::Abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC && candidate.hasTOF() && TMath::Abs(candidate.tofNSigmaPi()) < nsigmaCutTOF && candidate.beta() > cfgCutTOFBeta) { + return true; + } + if (candidate.pt() >= 0.5 && TMath::Abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC && !candidate.hasTOF()) { + return true; + } + } + } + return false; + } + double GetPhiInRange(double phi) { double result = phi; @@ -279,54 +465,285 @@ struct kstarpbpb { } return result; } - + template + bool isFakeKaon(T const& track, int /*PID*/) + { + const auto pglobal = track.p(); + const auto ptpc = track.tpcInnerParam(); + if (TMath::Abs(pglobal - ptpc) > ConfFakeKaonCut) { + return true; + } + return false; + } ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for bin"}; ConfigurableAxis axisMultiplicityClass{"axisMultiplicityClass", {20, 0, 100}, "multiplicity percentile for bin"}; ConfigurableAxis axisEPAngle{"axisEPAngle", {6, -TMath::Pi() / 2, TMath::Pi() / 2}, "event plane angle"}; + ConfigurableAxis axisOccup{"axisOccup", {20, -0.5, 40000.0}, "occupancy axis"}; + double v2, v2Rot; using BinningTypeVertexContributor = ColumnBinningPolicy; - ROOT::Math::PxPyPzMVector KstarMother, daughter1, daughter2; + ROOT::Math::PxPyPzMVector KstarMother, fourVecDauCM, daughter1, daughter2, kaonrot, kstarrot, KaonPlus, PionMinus; + ROOT::Math::XYZVector threeVecDauCM, threeVecDauCMXY, eventplaneVec, eventplaneVecNorm; + ROOT::Math::PxPyPzMVector daughter2rot, fourVecDauCMrot; + ROOT::Math::XYZVector threeVecDauCMrot, threeVecDauCMXYrot; - void processSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) + int currentRunNumber = -999; + int lastRunNumber = -999; + TH2D* hweight; + void processSE(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCsWithTimestamps const&) { - if (!collision.sel8()) { + if (!collision.sel8() || !collision.triggereventep() || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return; + } + auto centrality = collision.centFT0C(); + auto multTPC = collision.multNTracksPV(); + int occupancy = collision.trackOccupancyInTimeRange(); + auto psiFT0C = collision.psiFT0C(); + auto psiFT0A = collision.psiFT0A(); + auto psiTPC = collision.psiTPC(); + auto QFT0C = collision.qFT0C(); + auto QFT0A = collision.qFT0A(); + auto QTPC = collision.qTPC(); + if (fillOccupancy && occupancy >= cfgOccupancyCut) { return; } + if (additionalEvsel && !eventSelected(collision, centrality)) { + return; + } + if (additionalEvselITS && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return; + } + if (additionalQAplots1) { + histos.fill(HIST("hFTOCvsTPCSelected"), centrality, multTPC); + histos.fill(HIST("hPsiFT0C"), centrality, psiFT0C); + histos.fill(HIST("hPsiFT0A"), centrality, psiFT0A); + histos.fill(HIST("hPsiTPC"), centrality, psiTPC); + histos.fill(HIST("ResFT0CTPC"), centrality, TMath::Cos(2.0 * (psiFT0C - psiTPC))); + histos.fill(HIST("ResFT0CFT0A"), centrality, TMath::Cos(2.0 * (psiFT0C - psiFT0A))); + histos.fill(HIST("ResFT0ATPC"), centrality, TMath::Cos(2.0 * (psiTPC - psiFT0A))); + histos.fill(HIST("ResFT0CTPCSP"), centrality, QFT0C * QTPC * TMath::Cos(2.0 * (psiFT0C - psiTPC))); + histos.fill(HIST("ResFT0CFT0ASP"), centrality, QFT0C * QFT0A * TMath::Cos(2.0 * (psiFT0C - psiFT0A))); + histos.fill(HIST("ResFT0ATPCSP"), centrality, QTPC * QFT0A * TMath::Cos(2.0 * (psiTPC - psiFT0A))); + histos.fill(HIST("hCentrality"), centrality); + histos.fill(HIST("hOccupancy"), occupancy); + histos.fill(HIST("hVtxZ"), collision.posZ()); + } + auto bc = collision.bc_as(); + currentRunNumber = collision.bc_as().runNumber(); + if (useWeight && (currentRunNumber != lastRunNumber)) { + hweight = ccdb->getForTimeStamp(ConfWeightPath.value, bc.timestamp()); + } + lastRunNumber = currentRunNumber; + float weight1 = 1.0; + float weight2 = 1.0; + for (auto track1 : tracks) { + if (!selectionTrack(track1)) { + continue; + } + bool track1kaon = false; + auto track1ID = track1.globalIndex(); + if (!isTOFOnly && !strategySelectionPID(track1, 0, strategyPID)) { + continue; + } + if (isTOFOnly && !selectionPID2(track1, 0)) { + continue; + } + track1kaon = true; + + if (useWeight) { + if (track1.pt() < 10.0 && track1.pt() > 0.15) { + weight1 = 1 + hweight->GetBinContent(hweight->FindBin(centrality, track1.pt() + 0.000005)) * TMath::Cos(2.0 * GetPhiInRange(track1.phi() - psiFT0C)); + } else { + weight1 = 1; + } + } + for (auto track2 : tracks) { + if (!selectionTrack(track2)) { + continue; + } + bool track2pion = false; + auto track2ID = track2.globalIndex(); + if (!isTOFOnly && !strategySelectionPID(track2, 1, strategyPID)) { + continue; + } + if (isTOFOnly && !selectionPID2(track2, 1)) { + continue; + } + track2pion = true; + if (track2ID == track1ID) { + continue; + } + if (!track1kaon || !track2pion) { + continue; + } + if (additionalQAplots) { + histos.fill(HIST("QAafter/TPC_Nsigma_allka"), track1.pt(), track1.tpcNSigmaKa(), centrality); + histos.fill(HIST("QAafter/TOF_Nsigma_allka"), track1.pt(), track1.tofNSigmaKa(), centrality); + histos.fill(HIST("QAafter/trkDCAxyka"), track1.dcaXY()); + histos.fill(HIST("QAafter/trkDCAzka"), track1.dcaZ()); + histos.fill(HIST("QAafter/TOF_TPC_Mapka_allka"), track1.tofNSigmaKa(), track1.tpcNSigmaKa()); + histos.fill(HIST("QAafter/TOF_TPC_Mapka_allpi"), track2.tofNSigmaPi(), track2.tpcNSigmaPi()); + histos.fill(HIST("QAafter/TPC_Nsigma_allpi"), track2.pt(), track2.tpcNSigmaPi(), centrality); + histos.fill(HIST("QAafter/TOF_Nsigma_allpi"), track2.pt(), track2.tofNSigmaPi(), centrality); + histos.fill(HIST("QAafter/trkDCAxypi"), track2.dcaXY()); + histos.fill(HIST("QAafter/trkDCAzpi"), track2.dcaZ()); + } + if (useWeight) { + if (track2.pt() < 10.0 && track2.pt() > 0.15) { + weight2 = 1 + hweight->GetBinContent(hweight->FindBin(centrality, track2.pt() + 0.000005)) * TMath::Cos(2.0 * GetPhiInRange(track2.phi() - psiFT0C)); + } else { + weight2 = 1; + } + } + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); + KstarMother = daughter1 + daughter2; + if (TMath::Abs(KstarMother.Rapidity()) > confRapidity) { + continue; + } + auto phiminuspsi = GetPhiInRange(KstarMother.Phi() - psiFT0C); + + if (useSP) { + v2 = TMath::Cos(2.0 * phiminuspsi) * QFT0C; + } + if (!useSP) { + v2 = TMath::Cos(2.0 * phiminuspsi); + } + auto totalweight = weight1 * weight2; + if (totalweight <= 0.0000005) { + totalweight = 1.0; + } + if (additionalQAplots1) { + histos.fill(HIST("ResTrackSPFT0CTPC"), centrality, occupancy, QFT0C * QTPC * TMath::Cos(2.0 * (psiFT0C - psiTPC))); + histos.fill(HIST("ResTrackSPFT0CFT0A"), centrality, occupancy, QFT0C * QFT0A * TMath::Cos(2.0 * (psiFT0C - psiFT0A))); + histos.fill(HIST("ResTrackSPFT0ATPC"), centrality, occupancy, QTPC * QFT0A * TMath::Cos(2.0 * (psiTPC - psiFT0A))); + } + if (!fillSA) { + if (same) { + if (useWeight) { + histos.fill(HIST("hSparseV2SASameEvent_V2"), KstarMother.M(), KstarMother.Pt(), v2, centrality, 1 / totalweight); + } else { + histos.fill(HIST("hSparseV2SASameEvent_V2"), KstarMother.M(), KstarMother.Pt(), v2, centrality); + } + } + } + int track1Sign = track1.sign(); + int track2Sign = track2.sign(); + if (fillSA) { + ROOT::Math::Boost boost{KstarMother.BoostToCM()}; + fourVecDauCM = boost(daughter1); + threeVecDauCM = fourVecDauCM.Vect(); + threeVecDauCMXY = ROOT::Math::XYZVector(threeVecDauCM.X(), threeVecDauCM.Y(), 0.); + eventplaneVec = ROOT::Math::XYZVector(std::cos(2.0 * psiFT0C), std::sin(2.0 * psiFT0C), 0); + auto cosPhistarminuspsi = GetPhiInRange(fourVecDauCM.Phi() - psiFT0C); + auto SA = TMath::Cos(2.0 * cosPhistarminuspsi); + + if (track1Sign * track2Sign < 0) + histos.fill(HIST("hSparseSAvsrapsameunlike"), KstarMother.M(), KstarMother.Pt(), SA, KstarMother.Rapidity(), centrality); + else if (track1Sign * track2Sign > 0) + histos.fill(HIST("hSparseSAvsrapsamelike"), KstarMother.M(), KstarMother.Pt(), SA, KstarMother.Rapidity(), centrality); + } + + if (fillRotation) { + for (int nrotbkg = 0; nrotbkg < nBkgRotations; nrotbkg++) { + auto anglestart = confMinRot; + auto angleend = confMaxRot; + auto anglestep = (angleend - anglestart) / (1.0 * (nBkgRotations - 1)); + auto rotangle = anglestart + nrotbkg * anglestep; + histos.fill(HIST("hRotation"), rotangle); + auto rotkaonPx = track1.px() * std::cos(rotangle) - track1.py() * std::sin(rotangle); + auto rotkaonPy = track1.px() * std::sin(rotangle) + track1.py() * std::cos(rotangle); + kaonrot = ROOT::Math::PxPyPzMVector(rotkaonPx, rotkaonPy, track1.pz(), massKa); + kstarrot = kaonrot + daughter2; + if (TMath::Abs(kstarrot.Rapidity()) > confRapidity) { + continue; + } + auto phiminuspsiRot = GetPhiInRange(kstarrot.Phi() - psiFT0C); + + if (useSP) { + v2Rot = TMath::Cos(2.0 * phiminuspsiRot) * QFT0C; + } + if (!useSP) { + v2Rot = TMath::Cos(2.0 * phiminuspsiRot); + } + if (!fillSA) + histos.fill(HIST("hSparseV2SASameEventRotational_V2"), kstarrot.M(), kstarrot.Pt(), v2Rot, centrality); + + if (fillSA) { + if (track1Sign * track2Sign < 0) { + ROOT::Math::Boost boost{kstarrot.BoostToCM()}; + fourVecDauCMrot = boost(kaonrot); + threeVecDauCMrot = fourVecDauCMrot.Vect(); + threeVecDauCMXYrot = ROOT::Math::XYZVector(threeVecDauCMrot.X(), threeVecDauCMrot.Y(), 0.); + auto cosPhistarminuspsirot = GetPhiInRange(fourVecDauCMrot.Phi() - psiFT0C); + auto SArot = TMath::Cos(2.0 * cosPhistarminuspsirot); + + histos.fill(HIST("hSparseSAvsraprot"), kstarrot.M(), kstarrot.Pt(), SArot, kstarrot.Rapidity(), centrality); + } + } + } + } + } + } + } + PROCESS_SWITCH(kstarpbpb, processSE, "Process Same event latest", true); + /* + void processSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& , aod::BCsWithTimestamps const&) + { + if (!collision.sel8()) { + return; + } + auto centrality = collision.centFT0C(); + auto multTPC = collision.multNTracksPV(); + auto QFT0C = collision.qFT0C(); if (!collision.triggereventep()) { return; } if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { return; } + if (additionalEvSel2 && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + if (additionalEvSel3 && (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + return; + } + if (additionalEvselITS && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return; + } + int occupancy = collision.trackOccupancyInTimeRange(); auto posThisColl = posTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto negThisColl = negTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - auto centrality = collision.centFT0C(); - auto multTPC = collision.multNTracksPV(); auto psiFT0C = collision.psiFT0C(); auto psiFT0A = collision.psiFT0A(); auto psiTPC = collision.psiTPC(); - histos.fill(HIST("hFTOCvsTPC"), centrality, multTPC); - if (additionalEvsel && !eventSelected(collision, tracks.size(), centrality)) { + if (fillOccupancy && occupancy >= cfgOccupancyCut) // occupancy info is available for this collision (*) + { return; } - histos.fill(HIST("hFTOCvsTPCSelected"), centrality, multTPC); - histos.fill(HIST("hPsiFT0C"), centrality, psiFT0C); - histos.fill(HIST("hPsiFT0A"), centrality, psiFT0A); - histos.fill(HIST("hPsiTPC"), centrality, psiTPC); - histos.fill(HIST("ResFT0CTPC"), centrality, TMath::Cos(2.0 * (psiFT0C - psiTPC))); - histos.fill(HIST("ResFT0CFT0A"), centrality, TMath::Cos(2.0 * (psiFT0C - psiFT0A))); - histos.fill(HIST("ResFT0ATPC"), centrality, TMath::Cos(2.0 * (psiTPC - psiFT0A))); - histos.fill(HIST("hCentrality"), centrality); - histos.fill(HIST("hVtxZ"), collision.posZ()); - + if (additionalEvsel && !eventSelected(collision, centrality)) { + return; + } + if (additionalQAplots1) { + histos.fill(HIST("hFTOCvsTPCSelected"), centrality, multTPC); + histos.fill(HIST("hPsiFT0C"), centrality, psiFT0C); + histos.fill(HIST("hPsiFT0A"), centrality, psiFT0A); + histos.fill(HIST("hPsiTPC"), centrality, psiTPC); + histos.fill(HIST("ResFT0CTPC"), centrality, TMath::Cos(2.0 * (psiFT0C - psiTPC))); + histos.fill(HIST("ResFT0CFT0A"), centrality, TMath::Cos(2.0 * (psiFT0C - psiFT0A))); + histos.fill(HIST("ResFT0ATPC"), centrality, TMath::Cos(2.0 * (psiTPC - psiFT0A))); + histos.fill(HIST("hCentrality"), centrality); + histos.fill(HIST("hOccupancy"), occupancy); + histos.fill(HIST("hVtxZ"), collision.posZ()); + } for (auto track1 : posThisColl) { if (!selectionTrack(track1)) { continue; } if (additionalQAplots) { - histos.fill(HIST("QAbefore/TPC_Nsigma_allka"), track1.pt(), track1.tpcNSigmaKa()); - histos.fill(HIST("QAbefore/TOF_Nsigma_allka"), track1.pt(), track1.tofNSigmaKa()); + histos.fill(HIST("QAbefore/TPC_Nsigma_allka"), track1.pt(), track1.tpcNSigmaKa(), centrality); + histos.fill(HIST("QAbefore/TOF_Nsigma_allka"), track1.pt(), track1.tofNSigmaKa(), centrality); histos.fill(HIST("QAbefore/trkDCAxyka"), track1.dcaXY()); histos.fill(HIST("QAbefore/trkDCAzka"), track1.dcaZ()); histos.fill(HIST("QAbefore/TOF_TPC_Mapka_allka"), track1.tofNSigmaKa(), track1.tpcNSigmaKa()); @@ -334,12 +751,16 @@ struct kstarpbpb { bool track1pion = false; bool track1kaon = false; - if (ispTdepPID && !(selectionPIDpTdependent(track1, 0) || selectionPIDpTdependent(track1, 1))) { + if (ispTdepPID && !isTOFOnly && !(selectionPIDNew(track1, 0) || selectionPIDNew(track1, 1))) { continue; } - if (!ispTdepPID && !(selectionPID(track1, 0) || selectionPID(track1, 1))) { + if (!ispTdepPID && !isTOFOnly && !(selectionPID(track1, 0) || selectionPID(track1, 1))) { continue; } + if (isTOFOnly && !(selectionPID2(track1, 0) || selectionPID2(track1, 1))) { + continue; + } + auto track1ID = track1.globalIndex(); for (auto track2 : negThisColl) { bool track2pion = false; bool track2kaon = false; @@ -348,42 +769,87 @@ struct kstarpbpb { } if (additionalQAplots) { histos.fill(HIST("QAbefore/TOF_TPC_Mapka_allpi"), track2.tofNSigmaPi(), track2.tpcNSigmaPi()); - histos.fill(HIST("QAbefore/TPC_Nsigma_allpi"), track2.pt(), track2.tpcNSigmaPi()); - histos.fill(HIST("QAbefore/TOF_Nsigma_allpi"), track2.pt(), track2.tofNSigmaPi()); + histos.fill(HIST("QAbefore/TPC_Nsigma_allpi"), track2.pt(), track2.tpcNSigmaPi(), centrality); + histos.fill(HIST("QAbefore/TOF_Nsigma_allpi"), track2.pt(), track2.tofNSigmaPi(), centrality); histos.fill(HIST("QAbefore/trkDCAxypi"), track2.dcaXY()); histos.fill(HIST("QAbefore/trkDCAzpi"), track2.dcaZ()); } - if (ispTdepPID && !(selectionPIDpTdependent(track2, 0) || selectionPIDpTdependent(track2, 1))) { + if (ispTdepPID && !isTOFOnly && !(selectionPIDNew(track2, 0) || selectionPIDNew(track2, 1))) { + continue; + } + if (!ispTdepPID && !isTOFOnly && !(selectionPID(track2, 0) || selectionPID(track2, 1))) { continue; } - if (!ispTdepPID && !(selectionPID(track2, 0) || selectionPID(track2, 1))) { + if (isTOFOnly && !(selectionPID2(track2, 0) || selectionPID2(track2, 1))) { + continue; + } + auto track2ID = track2.globalIndex(); + if (track2ID == track1ID) { continue; } if (track1.sign() * track2.sign() > 0) { continue; } - if (ispTdepPID) { - if (selectionPIDpTdependent(track1, 1)) { + if (ispTdepPID && !isTOFOnly) { + if (selectionPIDNew(track1, 1) && selectionPIDNew(track2, 0)) { track1pion = true; - } else if (selectionPIDpTdependent(track1, 0)) { + track2kaon = true; + if (removefaketrak && isFakeKaon(track2, 0)) { + continue; + } + } + if (selectionPIDNew(track2, 1) && selectionPIDNew(track1, 0)) { + track2pion = true; track1kaon = true; + if (removefaketrak && isFakeKaon(track1, 0)) { + continue; + } + } + } + if (!ispTdepPID && !isTOFOnly) { + if (selectionPID(track1, 1) && selectionPID(track2, 0)) { + track1pion = true; + track2kaon = true; + if (removefaketrak && isFakeKaon(track2, 0)) { + continue; + } } - if (selectionPIDpTdependent(track2, 1)) { + if (selectionPID(track2, 1) && selectionPID(track1, 0)) { track2pion = true; - } else if (selectionPIDpTdependent(track2, 0)) { + track1kaon = true; + if (removefaketrak && isFakeKaon(track1, 0)) { + continue; + } + } + } + if (isTOFOnly) { + if (selectionPID2(track1, 1) && selectionPID2(track2, 0)) { + track1pion = true; track2kaon = true; + if (removefaketrak && isFakeKaon(track2, 0)) { + continue; + } } + if (selectionPID2(track2, 1) && selectionPID2(track1, 0)) { + track2pion = true; + track1kaon = true; + if (removefaketrak && isFakeKaon(track1, 0)) { + continue; + } + } + } + if (same) { if (track1kaon && track2pion) { if (additionalQAplots) { - histos.fill(HIST("QAafter/TPC_Nsigma_allka"), track1.pt(), track1.tpcNSigmaKa()); - histos.fill(HIST("QAafter/TOF_Nsigma_allka"), track1.pt(), track1.tofNSigmaKa()); + histos.fill(HIST("QAafter/TPC_Nsigma_allka"), track1.pt(), track1.tpcNSigmaKa(), centrality); + histos.fill(HIST("QAafter/TOF_Nsigma_allka"), track1.pt(), track1.tofNSigmaKa(), centrality); histos.fill(HIST("QAafter/trkDCAxyka"), track1.dcaXY()); histos.fill(HIST("QAafter/trkDCAzka"), track1.dcaZ()); histos.fill(HIST("QAafter/TOF_TPC_Mapka_allka"), track1.tofNSigmaKa(), track1.tpcNSigmaKa()); histos.fill(HIST("QAafter/TOF_TPC_Mapka_allpi"), track2.tofNSigmaPi(), track2.tpcNSigmaPi()); - histos.fill(HIST("QAafter/TPC_Nsigma_allpi"), track2.pt(), track2.tpcNSigmaPi()); - histos.fill(HIST("QAafter/TOF_Nsigma_allpi"), track2.pt(), track2.tofNSigmaPi()); + histos.fill(HIST("QAafter/TPC_Nsigma_allpi"), track2.pt(), track2.tpcNSigmaPi(), centrality); + histos.fill(HIST("QAafter/TOF_Nsigma_allpi"), track2.pt(), track2.tofNSigmaPi(), centrality); histos.fill(HIST("QAafter/trkDCAxypi"), track2.dcaXY()); histos.fill(HIST("QAafter/trkDCAzpi"), track2.dcaZ()); } @@ -395,79 +861,260 @@ struct kstarpbpb { } else { continue; } + + KstarMother = daughter1 + daughter2; + if (TMath::Abs(KstarMother.Rapidity()) > confRapidity) { + continue; + } + auto phiminuspsi = GetPhiInRange(KstarMother.Phi() - psiFT0C); + + if (useSP) { + v2 = TMath::Cos(2.0 * phiminuspsi) * QFT0C; + } + if (!useSP) { + v2 = TMath::Cos(2.0 * phiminuspsi); + } + + histos.fill(HIST("hSparseV2SASameEvent_V2"), KstarMother.M(), KstarMother.Pt(), v2, centrality); } - if (!ispTdepPID) { - if (selectionPID(track1, 1)) { + if (fillRotation) { + for (int nrotbkg = 0; nrotbkg < nBkgRotations; nrotbkg++) { + auto anglestart = confMinRot; + auto angleend = confMaxRot; + auto anglestep = (angleend - anglestart) / (1.0 * (nBkgRotations - 1)); + auto rotangle = anglestart + nrotbkg * anglestep; + histos.fill(HIST("hRotation"), rotangle); + if (track1kaon && track2pion) { + auto rotkaonPx = track1.px() * std::cos(rotangle) - track1.py() * std::sin(rotangle); + auto rotkaonPy = track1.px() * std::sin(rotangle) + track1.py() * std::cos(rotangle); + kaonrot = ROOT::Math::PxPyPzMVector(rotkaonPx, rotkaonPy, track1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); + } else if (track1pion && track2kaon) { + auto rotkaonPx = track2.px() * std::cos(rotangle) - track2.py() * std::sin(rotangle); + auto rotkaonPy = track2.px() * std::sin(rotangle) + track2.py() * std::cos(rotangle); + kaonrot = ROOT::Math::PxPyPzMVector(rotkaonPx, rotkaonPy, track2.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massPi); + } else { + continue; + } + kstarrot = kaonrot + daughter2; + if (TMath::Abs(kstarrot.Rapidity()) > confRapidity) { + continue; + } + auto phiminuspsiRot = GetPhiInRange(kstarrot.Phi() - psiFT0C); + + if (useSP) { + v2Rot = TMath::Cos(2.0 * phiminuspsiRot) * QFT0C; + } + if (!useSP) { + v2Rot = TMath::Cos(2.0 * phiminuspsiRot); + } + + histos.fill(HIST("hSparseV2SASameEventRotational_V2"), kstarrot.M(), kstarrot.Pt(), v2Rot, centrality); + } + } + } + } + } + PROCESS_SWITCH(kstarpbpb, processSameEvent, "Process Same event", false); + + void processlikeEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) + { + if (!collision.sel8()) { + return; + } + auto centrality = collision.centFT0C(); + auto QFT0C = collision.qFT0C(); + if (!collision.triggereventep()) { + return; + } + if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + return; + } + if (additionalEvSel2 && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + if (additionalEvSel3 && (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + return; + } + if (additionalEvselITS && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return; + } + int occupancy = collision.trackOccupancyInTimeRange(); + auto psiFT0C = collision.psiFT0C(); + if (fillOccupancy && occupancy >= cfgOccupancyCut) // occupancy info is available for this collision (*) + { + return; + } + + if (additionalEvsel && !eventSelected(collision, centrality)) { + return; + } + for (auto track1 : tracks) { + if (!selectionTrack(track1)) { + continue; + } + bool track1pion = false; + bool track1kaon = false; + if (ispTdepPID && !isTOFOnly && !(selectionPIDNew(track1, 0) || selectionPIDNew(track1, 1))) { + continue; + } + if (!ispTdepPID && !isTOFOnly && !(selectionPID(track1, 0) || selectionPID(track1, 1))) { + continue; + } + if (isTOFOnly && !(selectionPID2(track1, 0) || selectionPID2(track1, 1))) { + continue; + } + for (auto track2 : tracks) { + bool track2pion = false; + bool track2kaon = false; + if (!selectionTrack(track2)) { + continue; + } + if (ispTdepPID && !isTOFOnly && !(selectionPIDNew(track2, 0) || selectionPIDNew(track2, 1))) { + continue; + } + if (!ispTdepPID && !isTOFOnly && !(selectionPID(track2, 0) || selectionPID(track2, 1))) { + continue; + } + if (isTOFOnly && !(selectionPID2(track2, 0) || selectionPID2(track2, 1))) { + continue; + } + if (track1.sign() * track2.sign() < 0) { + continue; + } + + if (ispTdepPID && !isTOFOnly) { + if (selectionPIDNew(track1, 1) && selectionPIDNew(track2, 0)) { track1pion = true; - } else if (selectionPID(track1, 0)) { + track2kaon = true; + if (removefaketrak && isFakeKaon(track2, 0)) { + continue; + } + } + if (selectionPIDNew(track2, 1) && selectionPIDNew(track1, 0)) { + track2pion = true; track1kaon = true; + if (removefaketrak && isFakeKaon(track1, 0)) { + continue; + } } - if (selectionPID(track2, 1)) { + } + if (!ispTdepPID && !isTOFOnly) { + if (selectionPID(track1, 1) && selectionPID(track2, 0)) { + track1pion = true; + track2kaon = true; + if (removefaketrak && isFakeKaon(track2, 0)) { + continue; + } + } + if (selectionPID(track2, 1) && selectionPID(track1, 0)) { track2pion = true; - } else if (selectionPID(track2, 0)) { + track1kaon = true; + if (removefaketrak && isFakeKaon(track1, 0)) { + continue; + } + } + } + if (isTOFOnly) { + if (selectionPID2(track1, 1) && selectionPID2(track2, 0)) { + track1pion = true; track2kaon = true; + if (removefaketrak && isFakeKaon(track2, 0)) { + continue; + } } - if (track1kaon && track2pion) { - if (additionalQAplots) { - histos.fill(HIST("QAafter/TPC_Nsigma_allka"), track1.pt(), track1.tpcNSigmaKa()); - histos.fill(HIST("QAafter/TOF_Nsigma_allka"), track1.pt(), track1.tofNSigmaKa()); - histos.fill(HIST("QAafter/trkDCAxyka"), track1.dcaXY()); - histos.fill(HIST("QAafter/trkDCAzka"), track1.dcaZ()); - histos.fill(HIST("QAafter/TOF_TPC_Mapka_allka"), track1.tofNSigmaKa(), track1.tpcNSigmaKa()); - histos.fill(HIST("QAafter/TOF_TPC_Mapka_allpi"), track2.tofNSigmaPi(), track2.tpcNSigmaPi()); - histos.fill(HIST("QAafter/TPC_Nsigma_allpi"), track2.pt(), track2.tpcNSigmaPi()); - histos.fill(HIST("QAafter/TOF_Nsigma_allpi"), track2.pt(), track2.tofNSigmaPi()); - histos.fill(HIST("QAafter/trkDCAxypi"), track2.dcaXY()); - histos.fill(HIST("QAafter/trkDCAzpi"), track2.dcaZ()); + if (selectionPID2(track2, 1) && selectionPID2(track1, 0)) { + track2pion = true; + track1kaon = true; + if (removefaketrak && isFakeKaon(track1, 0)) { + continue; } + } + } + if (track1kaon && track2pion) { + if (track1.sign() < 0 && track2.sign() < 0) { + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); - } else if (track1pion && track2kaon) { + + KstarMother = daughter1 + daughter2; + if (TMath::Abs(KstarMother.Rapidity()) > confRapidity) { + continue; + } + auto phiminuspsi = GetPhiInRange(KstarMother.Phi() - psiFT0C); + + if (useSP) { + v2 = TMath::Cos(2.0 * phiminuspsi) * QFT0C; + } + if (!useSP) { + v2 = TMath::Cos(2.0 * phiminuspsi); + } + histos.fill(HIST("hSparseV2SAlikeEventNN_V2"), KstarMother.M(), KstarMother.Pt(), v2, centrality); + } + } else if (track1pion && track2kaon) { + if (track1.sign() > 0 && track2.sign() > 0) { daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massPi); daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); - } else { - continue; + KstarMother = daughter1 + daughter2; + if (TMath::Abs(KstarMother.Rapidity()) > confRapidity) { + continue; + } + auto phiminuspsi = GetPhiInRange(KstarMother.Phi() - psiFT0C); + + if (useSP) { + v2 = TMath::Cos(2.0 * phiminuspsi) * QFT0C; + } + if (!useSP) { + v2 = TMath::Cos(2.0 * phiminuspsi); + } + + histos.fill(HIST("hSparseV2SAlikeEventPP_V2"), KstarMother.M(), KstarMother.Pt(), v2, centrality); } } - KstarMother = daughter1 + daughter2; - histos.fill(HIST("hpTvsRapidity"), KstarMother.Pt(), KstarMother.Rapidity()); - if (TMath::Abs(KstarMother.Rapidity()) > confRapidity) { - continue; - } - auto phiminuspsi = GetPhiInRange(KstarMother.Phi() - psiFT0C); - auto v2 = TMath::Cos(2.0 * phiminuspsi); - histos.fill(HIST("hSparseV2SASameEvent_V2"), KstarMother.M(), KstarMother.Pt(), v2, centrality); } } } - PROCESS_SWITCH(kstarpbpb, processSameEvent, "Process Same event", true); + + PROCESS_SWITCH(kstarpbpb, processlikeEvent, "Process like event", false); + */ + void processMixedEvent(EventCandidates const& collisions, TrackCandidates const& tracks) { + auto tracksTuple = std::make_tuple(tracks); - BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicityClass, axisEPAngle}, true}; + BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicityClass, axisOccup}, true}; SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; for (auto& [collision1, tracks1, collision2, tracks2] : pair) { - if (!collision1.sel8() || !collision2.sel8()) { + if (!collision1.sel8() || !collision1.triggereventep() || !collision1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision1.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision1.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !collision1.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + continue; + } + if (!collision2.sel8() || !collision2.triggereventep() || !collision2.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision2.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision2.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !collision2.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { continue; } - if (!collision1.triggereventep() || !collision2.triggereventep()) { + if (collision1.bcId() == collision2.bcId()) { continue; } - if (timFrameEvsel && (!collision1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision2.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision1.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision2.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + int occupancy1 = collision1.trackOccupancyInTimeRange(); + int occupancy2 = collision2.trackOccupancyInTimeRange(); + if (fillOccupancy && occupancy1 >= cfgOccupancyCut && occupancy2 >= cfgOccupancyCut) // occupancy info is available for this collision (*) + { continue; } auto centrality = collision1.centFT0C(); auto centrality2 = collision2.centFT0C(); auto psiFT0C = collision1.psiFT0C(); - bool track1pion = false; - bool track1kaon = false; - bool track2pion = false; - bool track2kaon = false; - - if (additionalEvsel && !eventSelected(collision1, tracks.size(), centrality)) { + auto QFT0C = collision1.qFT0C(); + if (additionalEvsel && !eventSelected(collision1, centrality)) { + continue; + } + if (additionalEvsel && !eventSelected(collision2, centrality2)) { + continue; + } + if (additionalEvselITS && !collision1.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { continue; } - if (additionalEvsel && !eventSelected(collision2, tracks.size(), centrality2)) { + if (additionalEvselITS && !collision2.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { continue; } @@ -476,74 +1123,421 @@ struct kstarpbpb { continue; } if (!selectionTrack(track1) || !selectionTrack(track2)) { + continue; } - if (ispTdepPID && !(selectionPIDpTdependent(track1, 0) || selectionPIDpTdependent(track1, 1))) { + if (ispTdepPID && !isTOFOnly && !(selectionPIDNew(track1, 0))) { continue; } - if (ispTdepPID && !(selectionPIDpTdependent(track2, 1) || selectionPIDpTdependent(track2, 0))) { + if (ispTdepPID && !isTOFOnly && !(selectionPIDNew(track2, 1))) { continue; } - if (!ispTdepPID && !(selectionPID(track1, 0) || selectionPID(track1, 1))) { + if (!ispTdepPID && !isTOFOnly && !(selectionPID(track1, 0))) { continue; } - if (!ispTdepPID && !(selectionPID(track2, 1) || selectionPID(track2, 0))) { + if (!ispTdepPID && !isTOFOnly && !(selectionPID(track2, 1))) { continue; } - if (ispTdepPID) { - if (selectionPIDpTdependent(track1, 1)) { - track1pion = true; - } else if (selectionPIDpTdependent(track1, 0)) { - track1kaon = true; + if (isTOFOnly && !selectionPID2(track1, 0)) { + continue; + } + if (isTOFOnly && !selectionPID2(track2, 1)) { + continue; + } + // if (track1.sign() > 0 && track2.sign() < 0) { + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); + /*} else if (track1.sign() < 0 && track2.sign() > 0) { + daughter2 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + daughter1 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); + }*/ + KstarMother = daughter1 + daughter2; + if (TMath::Abs(KstarMother.Rapidity()) > confRapidity) { + continue; + } + auto phiminuspsi = GetPhiInRange(KstarMother.Phi() - psiFT0C); + + v2 = TMath::Cos(2.0 * phiminuspsi) * QFT0C; + if (!fillSA) { + if (track1.sign() * track2.sign() < 0) + histos.fill(HIST("hSparseV2SAMixedEvent_V2"), KstarMother.M(), KstarMother.Pt(), v2, centrality); + } + if (fillSA) { + ROOT::Math::Boost boost{KstarMother.BoostToCM()}; + fourVecDauCM = boost(daughter1); + threeVecDauCM = fourVecDauCM.Vect(); + threeVecDauCMXY = ROOT::Math::XYZVector(threeVecDauCM.X(), threeVecDauCM.Y(), 0.); + eventplaneVec = ROOT::Math::XYZVector(std::cos(2.0 * psiFT0C), std::sin(2.0 * psiFT0C), 0); + auto cosPhistarminuspsi = GetPhiInRange(fourVecDauCM.Phi() - psiFT0C); + auto SA = TMath::Cos(2.0 * cosPhistarminuspsi); + + histos.fill(HIST("hSparseSAvsrapmix"), KstarMother.M(), KstarMother.Pt(), SA, KstarMother.Rapidity(), centrality); + } + } + } + } + PROCESS_SWITCH(kstarpbpb, processMixedEvent, "Process Mixed event", true); + void processMC(CollisionMCTrueTable::iterator const& /*TrueCollision*/, CollisionMCRecTableCentFT0C const& RecCollisions, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + { + histos.fill(HIST("hMC"), 0); + if (RecCollisions.size() == 0) { + histos.fill(HIST("hMC"), 1); + return; + } + if (RecCollisions.size() > 1) { + histos.fill(HIST("hMC"), 2); + return; + } + for (auto& RecCollision : RecCollisions) { + auto psiFT0C = 0.0; + histos.fill(HIST("hMC"), 3); + if (!RecCollision.sel8()) { + histos.fill(HIST("hMC"), 4); + continue; + } + + if (!RecCollision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !RecCollision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + histos.fill(HIST("hMC"), 5); + continue; + } + if (TMath::Abs(RecCollision.posZ()) > cfgCutVertex) { + histos.fill(HIST("hMC"), 6); + continue; + } + histos.fill(HIST("hMC"), 7); + auto centrality = RecCollision.centFT0C(); + histos.fill(HIST("CentPercentileMCRecHist"), centrality); + auto oldindex = -999; + auto Rectrackspart = RecTracks.sliceBy(perCollision, RecCollision.globalIndex()); + // loop over reconstructed particle + for (auto track1 : Rectrackspart) { + if (!selectionTrack(track1)) { + continue; + } + if (ispTdepPID && !(selectionPIDNew(track1, 0))) { + continue; + } + if (!ispTdepPID && !(selectionPID(track1, 0))) { + continue; + } + if (!track1.has_mcParticle()) { + continue; + } + auto track1ID = track1.index(); + for (auto track2 : Rectrackspart) { + auto track2ID = track2.index(); + if (track2ID <= track1ID) { + continue; } - if (selectionPIDpTdependent(track2, 1)) { - track2pion = true; - } else if (selectionPIDpTdependent(track2, 0)) { - track2kaon = true; + if (!selectionTrack(track2)) { + continue; } - if (track1pion && track2kaon) { - daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massPi); - daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); - } else if (track1kaon && track2pion) { - daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); - daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); - } else { + if (ispTdepPID && !(selectionPIDNew(track2, 1))) { + continue; + } + if (!ispTdepPID && !(selectionPID(track2, 1))) { continue; } + if (!track2.has_mcParticle()) { + continue; + } + if (track1.sign() * track2.sign() > 0) { + continue; + } + const auto mctrack1 = track1.mcParticle(); + const auto mctrack2 = track2.mcParticle(); + int track1PDG = TMath::Abs(mctrack1.pdgCode()); + int track2PDG = TMath::Abs(mctrack2.pdgCode()); + if (!mctrack1.isPhysicalPrimary()) { + continue; + } + if (!mctrack2.isPhysicalPrimary()) { + continue; + } + if (!(track1PDG == 321 && track2PDG == 211)) { + continue; + } + for (auto& mothertrack1 : mctrack1.mothers_as()) { + for (auto& mothertrack2 : mctrack2.mothers_as()) { + if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) { + continue; + } + if (mothertrack1 != mothertrack2) { + continue; + } + if (TMath::Abs(mothertrack1.y()) > confRapidity) { + continue; + } + if (PDGcheck && TMath::Abs(mothertrack1.pdgCode()) != 313) { + continue; + } + if (ispTdepPID && !(selectionPIDNew(track1, 0) || selectionPIDNew(track2, 1))) { + continue; + } + if (!ispTdepPID && !(selectionPID(track1, 0) || selectionPID(track2, 1))) { + continue; + } + if (avoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { + continue; + } + oldindex = mothertrack1.globalIndex(); + if (track1.sign() > 0 && track2.sign() < 0) { + KaonPlus = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + PionMinus = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); + } + if (track1.sign() < 0 && track2.sign() > 0) { + PionMinus = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + KaonPlus = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); + } + KstarMother = KaonPlus + PionMinus; + if (TMath::Abs(KstarMother.Rapidity()) > confRapidity) { + continue; + } + auto phiminuspsi = GetPhiInRange(KstarMother.Phi() - psiFT0C); + + v2 = TMath::Cos(2.0 * phiminuspsi); + + histos.fill(HIST("hSparseV2SARec_V2"), KstarMother.M(), KstarMother.Pt(), v2, centrality); + histos.fill(HIST("h2PhiRec2"), KstarMother.pt(), centrality); + histos.fill(HIST("hpt"), KstarMother.Pt()); + } + } } - if (!ispTdepPID) { - if (selectionPID(track1, 1)) { - track1pion = true; - } else if (selectionPID(track1, 0)) { - track1kaon = true; + } + // loop over generated particle + for (auto& mcParticle : GenParticles) { + if (TMath::Abs(mcParticle.y()) > confRapidity) { + continue; + } + if (PDGcheck && mcParticle.pdgCode() != 313) { + continue; + } + auto kDaughters = mcParticle.daughters_as(); + if (kDaughters.size() != 2) { + continue; + } + auto daughtp = false; + auto daughtm = false; + for (auto kCurrentDaughter : kDaughters) { + if (!kCurrentDaughter.isPhysicalPrimary()) { + continue; } - if (selectionPID(track2, 1)) { - track2pion = true; - } else if (selectionPID(track2, 0)) { - track2kaon = true; + if (kCurrentDaughter.pdgCode() == +321) { + if (genacceptancecut && kCurrentDaughter.pt() > cfgCutPT && TMath::Abs(kCurrentDaughter.eta()) < cfgCutEta) { + daughtp = true; + } + if (!genacceptancecut) { + daughtp = true; + } + KaonPlus = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massKa); + } else if (kCurrentDaughter.pdgCode() == -211) { + if (genacceptancecut && kCurrentDaughter.pt() > cfgCutPT && TMath::Abs(kCurrentDaughter.eta()) < cfgCutEta) { + daughtm = true; + } + if (!genacceptancecut) { + daughtm = true; + } + PionMinus = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massPi); } - if (track1pion && track2kaon) { - daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massPi); - daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); - } else if (track1kaon && track2pion) { - daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); - daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); - } else { + } + if (daughtp && daughtm) { + KstarMother = KaonPlus + PionMinus; + if (TMath::Abs(KstarMother.Rapidity()) > confRapidity) { continue; } + auto phiminuspsi = GetPhiInRange(KstarMother.Phi() - psiFT0C); + + v2 = TMath::Cos(2.0 * phiminuspsi); + + histos.fill(HIST("hSparseV2SAGen_V2"), KstarMother.M(), KstarMother.Pt(), v2, centrality); + histos.fill(HIST("h2PhiGen2"), KstarMother.pt(), centrality); } + } + } // rec collision loop - KstarMother = daughter1 + daughter2; - if (TMath::Abs(KstarMother.Rapidity()) > confRapidity) { + } // process MC + PROCESS_SWITCH(kstarpbpb, processMC, "Process MC", false); + + void processMCkstarWeight(CollisionMCTrueTable::iterator const& TrueCollision, CollisionMCRecTableCentFT0C const& RecCollisions, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + { + float imp = TrueCollision.impactParameter(); + float evPhi = TrueCollision.eventPlaneAngle() / 2.0; + float centclass = -999; + if (imp >= 0 && imp < 3.49) { + centclass = 2.5; + } + if (imp >= 3.49 && imp < 4.93) { + centclass = 7.5; + } + if (imp >= 4.93 && imp < 6.98) { + centclass = 15.0; + } + if (imp >= 6.98 && imp < 8.55) { + centclass = 25.0; + } + if (imp >= 8.55 && imp < 9.87) { + centclass = 35.0; + } + if (imp >= 9.87 && imp < 11) { + centclass = 45.0; + } + if (imp >= 11 && imp < 12.1) { + centclass = 55.0; + } + if (imp >= 12.1 && imp < 13.1) { + centclass = 65.0; + } + if (imp >= 13.1 && imp < 14) { + centclass = 75.0; + } + histos.fill(HIST("hImpactParameter"), imp); + histos.fill(HIST("hEventPlaneAngle"), evPhi); + if (centclass < 0.0 || centclass > 80.0) { + return; + } + for (auto& RecCollision : RecCollisions) { + auto psiFT0C = TrueCollision.eventPlaneAngle(); + /* + if (!RecCollision.sel8()) { + continue; + } + if (!RecCollision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + continue; + } + */ + if (TMath::Abs(RecCollision.posZ()) > cfgCutVertex) { + continue; + } + auto oldindex = -999; + auto Rectrackspart = RecTracks.sliceBy(perCollision, RecCollision.globalIndex()); + // loop over reconstructed particle + for (auto track1 : Rectrackspart) { + if (!track1.has_mcParticle()) { continue; } - auto phiminuspsi = GetPhiInRange(KstarMother.Phi() - psiFT0C); - auto v2 = TMath::Cos(2.0 * phiminuspsi); - histos.fill(HIST("hSparseV2SAMixedEvent_V2"), KstarMother.M(), KstarMother.Pt(), v2, centrality); + + const auto mctrack1 = track1.mcParticle(); + + if (selectionTrack(track1) && strategySelectionPID(track1, 0, strategyPID) && TMath::Abs(mctrack1.pdgCode()) == 321 && mctrack1.isPhysicalPrimary()) { + histos.fill(HIST("hSparseKstarMCRecKaonWeight"), centclass, GetPhiInRange(mctrack1.phi() - psiFT0C), TMath::Power(TMath::Cos(2.0 * GetPhiInRange(mctrack1.phi() - psiFT0C)), 2.0), mctrack1.pt(), mctrack1.eta()); + } + if (selectionTrack(track1) && track1.pt() > 0.5 && track1.hasTOF() && TMath::Abs(track1.tofNSigmaKa()) > nsigmaCutTOF && TMath::Abs(track1.tpcNSigmaKa()) < nsigmaCutTPC && TMath::Abs(mctrack1.pdgCode()) == 321 && mctrack1.isPhysicalPrimary()) { + histos.fill(HIST("hSparseKstarMCRecKaonMissMatchWeight"), centclass, GetPhiInRange(mctrack1.phi() - psiFT0C), TMath::Power(TMath::Cos(2.0 * GetPhiInRange(mctrack1.phi() - psiFT0C)), 2.0), mctrack1.pt(), mctrack1.eta()); + } + if (selectionTrack(track1) && strategySelectionPID(track1, 1, strategyPID) && TMath::Abs(mctrack1.pdgCode()) == 211 && mctrack1.isPhysicalPrimary()) { + histos.fill(HIST("hSparseKstarMCRecPionWeight"), centclass, GetPhiInRange(mctrack1.phi() - psiFT0C), TMath::Power(TMath::Cos(2.0 * GetPhiInRange(mctrack1.phi() - psiFT0C)), 2.0), mctrack1.pt(), mctrack1.eta()); + } + if (selectionTrack(track1) && track1.pt() > 0.5 && track1.hasTOF() && TMath::Abs(track1.tofNSigmaPi()) > nsigmaCutTOF && TMath::Abs(track1.tpcNSigmaPi()) < nsigmaCutTPC && TMath::Abs(mctrack1.pdgCode()) == 211 && mctrack1.isPhysicalPrimary()) { + histos.fill(HIST("hSparseKstarMCRecPionMissMatchWeight"), centclass, GetPhiInRange(mctrack1.phi() - psiFT0C), TMath::Power(TMath::Cos(2.0 * GetPhiInRange(mctrack1.phi() - psiFT0C)), 2.0), mctrack1.pt(), mctrack1.eta()); + } + auto track1ID = track1.index(); + for (auto track2 : Rectrackspart) { + if (!track2.has_mcParticle()) { + continue; + } + auto track2ID = track2.index(); + if (track2ID <= track1ID) { + continue; + } + const auto mctrack2 = track2.mcParticle(); + int track1PDG = TMath::Abs(mctrack1.pdgCode()); + int track2PDG = TMath::Abs(mctrack2.pdgCode()); + if (!mctrack1.isPhysicalPrimary()) { + continue; + } + if (!mctrack2.isPhysicalPrimary()) { + continue; + } + if (!(track1PDG == 321 && track2PDG == 211)) { + continue; + } + if (!selectionTrack(track1) || !selectionTrack(track2) || track1.sign() * track2.sign() > 0) { + continue; + } + // PID check + if (ispTdepPID && !isTOFOnly && (!strategySelectionPID(track1, 0, strategyPID) || !strategySelectionPID(track2, 1, strategyPID))) { + continue; + } + if (!ispTdepPID && !isTOFOnly && (!selectionPID(track1, 0) || !selectionPID(track2, 1))) { + continue; + } + if (isTOFOnly && (!selectionPID2(track1, 0) || !selectionPID2(track2, 1))) { + continue; + } + for (auto& mothertrack1 : mctrack1.mothers_as()) { + for (auto& mothertrack2 : mctrack2.mothers_as()) { + if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) { + continue; + } + if (mothertrack1 != mothertrack2) { + continue; + } + if (TMath::Abs(mothertrack1.y()) > confRapidity) { + continue; + } + if (TMath::Abs(mothertrack1.pdgCode()) != 313) { + continue; + } + // if (avoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { + if (avoidsplitrackMC && oldindex == mothertrack1.index()) { + histos.fill(HIST("h1PhiRecsplit"), mothertrack1.pt()); + continue; + } + // oldindex = mothertrack1.globalIndex(); + oldindex = mothertrack1.index(); + auto PhiMinusPsi = GetPhiInRange(mothertrack1.phi() - psiFT0C); + histos.fill(HIST("hSparseKstarMCRecWeight"), centclass, PhiMinusPsi, TMath::Power(TMath::Cos(2.0 * PhiMinusPsi), 2.0), mothertrack1.pt(), mothertrack1.eta()); + } + } + } } - } - } - PROCESS_SWITCH(kstarpbpb, processMixedEvent, "Process Mixed event", true); + // loop over generated particle + for (auto& mcParticle : GenParticles) { + if (TMath::Abs(mcParticle.eta()) > 0.8) // main acceptance + continue; + if (TMath::Abs(mcParticle.pdgCode()) == 321 && mcParticle.isPhysicalPrimary()) { + histos.fill(HIST("hSparseKstarMCGenKaonWeight"), centclass, GetPhiInRange(mcParticle.phi() - psiFT0C), TMath::Power(TMath::Cos(2.0 * GetPhiInRange(mcParticle.phi() - psiFT0C)), 2.0), mcParticle.pt(), mcParticle.eta()); + } + if (TMath::Abs(mcParticle.pdgCode()) == 211 && mcParticle.isPhysicalPrimary()) { + histos.fill(HIST("hSparseKstarMCGenPionWeight"), centclass, GetPhiInRange(mcParticle.phi() - psiFT0C), TMath::Power(TMath::Cos(2.0 * GetPhiInRange(mcParticle.phi() - psiFT0C)), 2.0), mcParticle.pt(), mcParticle.eta()); + } + if (TMath::Abs(mcParticle.y()) > confRapidity) { + continue; + } + if (mcParticle.pdgCode() != 313) { + continue; + } + auto kDaughters = mcParticle.daughters_as(); + if (kDaughters.size() != 2) { + continue; + } + auto daughtp = false; + auto daughtm = false; + for (auto kCurrentDaughter : kDaughters) { + if (!kCurrentDaughter.isPhysicalPrimary()) { + continue; + } + if (kCurrentDaughter.pdgCode() == +321) { + if (kCurrentDaughter.pt() > cfgCutPT && TMath::Abs(kCurrentDaughter.eta()) < cfgCutEta) { + daughtp = true; + } + KaonPlus = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massKa); + } else if (kCurrentDaughter.pdgCode() == -211) { + if (kCurrentDaughter.pt() > cfgCutPT && TMath::Abs(kCurrentDaughter.eta()) < cfgCutEta) { + daughtm = true; + } + PionMinus = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massPi); + } + } + if (daughtp && daughtm) { + auto PhiMinusPsiGen = GetPhiInRange(mcParticle.phi() - psiFT0C); + histos.fill(HIST("hSparseKstarMCGenWeight"), centclass, PhiMinusPsiGen, TMath::Power(TMath::Cos(2.0 * PhiMinusPsiGen), 2.0), mcParticle.pt(), mcParticle.eta()); + } + } + } // rec collision loop + + } // process MC + PROCESS_SWITCH(kstarpbpb, processMCkstarWeight, "Process MC kstar Weight", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGLF/Tasks/Resonances/kstarqa.cxx b/PWGLF/Tasks/Resonances/kstarqa.cxx index 4cdd9fc866e..804e8538824 100644 --- a/PWGLF/Tasks/Resonances/kstarqa.cxx +++ b/PWGLF/Tasks/Resonances/kstarqa.cxx @@ -8,26 +8,27 @@ // 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 this is a code for the kstarqa resonance + +/// \file kstarqa.cxx +/// \brief Code for Kstar resonance without resonance initializer /// \author prottay das, sawan /// \since 13/03/2024 -#include +// #include #include #include #include #include #include +#include #include #include #include #include - -#include -#include -#include - +#include "TRandom3.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" #include "CCDB/BasicCCDBManager.h" #include "CCDB/CcdbApi.h" #include "Common/Core/TrackSelection.h" @@ -50,73 +51,88 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::soa; using std::array; -struct kstarqa { - - // Connect to ccdb - Service ccdb; - Configurable nolaterthan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; - Configurable url{"ccdb-url", "http://ccdb-test.cern.ch:8080", "url of the ccdb repository"}; +struct Kstarqa { SliceCache cache; // Histograms are defined with HistogramRegistry HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry hInvMass{"hInvMass", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry hPID{"hPID", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry hOthers{"hOthers", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; // Confugrable for QA histograms - Configurable QA{"QA", false, "QA"}; - Configurable QAbefore{"QAbefore", true, "QAbefore"}; - Configurable QAafter{"QAafter", true, "QAafter"}; + Configurable calcLikeSign{"calcLikeSign", true, "Calculate Like Sign"}; + Configurable calcRotational{"calcRotational", true, "Calculate Rotational"}; + Configurable cQAplots{"cQAplots", true, "cQAplots"}; + Configurable cQAevents{"cQAevents", true, "Multiplicity dist, DCAxy, DCAz"}; Configurable onlyTOF{"onlyTOF", false, "only TOF tracks"}; Configurable onlyTOFHIT{"onlyTOFHIT", false, "accept only TOF hit tracks at high pt"}; + Configurable onlyTPC{"onlyTPC", true, "only TPC tracks"}; // Configurables for track selections + Configurable rotationalCut{"rotationalCut", 10, "Cut value (Rotation angle pi - pi/cut and pi + pi/cut)"}; Configurable cfgCutPT{"cfgCutPT", 0.2f, "PT cut on daughter track"}; Configurable cfgCutEta{"cfgCutEta", 0.8f, "Eta cut on daughter track"}; Configurable cfgCutDCAxy{"cfgCutDCAxy", 2.0f, "DCAxy range for tracks"}; Configurable cfgCutDCAz{"cfgCutDCAz", 2.0f, "DCAz range for tracks"}; - Configurable nsigmaCutTPCPi{"nsigmacutTPCPi", 3.0, "Value of the TPC Nsigma cut for pions"}; - Configurable nsigmaCutTPCKa{"nsigmacutTPCKa", 3.0, "Value of the TPC Nsigma cut for kaons"}; - Configurable nsigmaCutTOFPi{"nsigmacutTOFPi", 3.0, "Value of the TOF Nsigma cut for pions"}; - Configurable nsigmaCutTOFKa{"nsigmacutTOFKa", 3.0, "Value of the TOF Nsigma cut for kaons"}; - Configurable nsigmaCutCombined{"nsigmaCutCombined", 3.0, "Value of the Combined Nsigma cut"}; Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 5, "Number of mixed events per event"}; - Configurable cfgMultFT0{"cfgMultFT0", false, "cfgMultFT0"}; - Configurable cfgCentFT0C{"cfgCentFT0C", true, "cfgCentFT0C"}; - Configurable iscustomDCAcut{"iscustomDCAcut", false, "iscustomDCAcut"}; - Configurable ismanulatrksel{"ismanulatrksel", true, "all manual track selection cuts"}; + Configurable ismanualDCAcut{"ismanualDCAcut", true, "ismanualDCAcut"}; Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; Configurable cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; Configurable cfgRCRFC{"cfgRCRFC", 0.8f, "Crossed Rows to Findable Clusters"}; Configurable cfgITSChi2NCl{"cfgITSChi2NCl", 36.0, "ITS Chi2/NCl"}; Configurable cfgTPCChi2NCl{"cfgTPCChi2NCl", 4.0, "TPC Chi2/NCl"}; - Configurable cfgUseTPCRefit{"cfgUseTPCRefit", false, "Require TPC Refit"}; - Configurable cfgUseITSRefit{"cfgUseITSRefit", false, "Require ITS Refit"}; - ConfigurableAxis cMixMultBins{"cMixMultBins", {VARIABLE_WIDTH, 0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f}, "Mixing bins - multiplicity"}; Configurable cfgPVContributor{"cfgPVContributor", false, "PV contributor track selection"}; // PV Contriuibutor Configurable cfgPrimaryTrack{"cfgPrimaryTrack", false, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", false, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) Configurable cfgGlobalTrack{"cfgGlobalTrack", false, "Global track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cBetaCutTOF{"cBetaCutTOF", 0.0, "cut TOF beta"}; + Configurable cFakeTrackCutKa{"cFakeTrackCutKa", 0.5, "Cut based on momentum difference in global and TPC tracks for Kaons"}; + Configurable cFakeTrackCutPi{"cFakeTrackCutPi", 0.5, "Cut based on momentum difference in global and TPC tracks for Pions"}; + Configurable cFakeTrack{"cFakeTrack", true, "Fake track selection"}; + + // PID selections + Configurable nsigmaCutTPCPi{"nsigmaCutTPCPi", 3.0, "TPC Nsigma cut for pions"}; + Configurable nsigmaCutTPCKa{"nsigmaCutTPCKa", 3.0, "TPC Nsigma cut for kaons"}; + Configurable nsigmaCutTOFPi{"nsigmaCutTOFPi", 3.0, "TOF Nsigma cut for pions"}; + Configurable nsigmaCutTOFKa{"nsigmaCutTOFKa", 3.0, "TOF Nsigma cut for kaons"}; + Configurable nsigmaCutCombined{"nsigmaCutCombined", 3.0, "Combined Nsigma cut"}; // Event selection configurables Configurable timFrameEvsel{"timFrameEvsel", false, "TPC Time frame boundary cut"}; + Configurable cTVXEvsel{"cTVXEvsel", false, "Triggger selection"}; Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; - Configurable piluprejection{"piluprejection", false, "Pileup rejection"}; - Configurable goodzvertex{"goodzvertex", false, "removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference."}; - Configurable itstpctracks{"itstpctracks", false, "selects collisions with at least one ITS-TPC track,"}; - Configurable MID{"MID", false, "Misidentification of tracks"}; + // Configurable cMID{"cMID", false, "Misidentification of tracks"}; // Configurable for histograms - Configurable nBins{"nBins", 100, "N bins in all histos"}; - Configurable nBinsinvMass{"nBinsinvMass", 360, "N bins in invMass histos"}; + Configurable nBins{"nBins", 100, "No. of bins in Vz distribution"}; + Configurable nBinsinvMass{"nBinsinvMass", 180, "N bins in invMass hInvMass"}; Configurable invMassbinlow{"invMassbinlow", 0.6, "invMass bin low"}; Configurable invMassbinhigh{"invMassbinhigh", 1.5, "invMass bin high"}; - Configurable nBinspT{"nBinspT", 200, "N bins in pT histos"}; + Configurable nBinspT{"nBinspT", 200, "N bins in pT hInvMass"}; Configurable pTbinlow{"pTbinlow", 0.0, "pT bin low"}; Configurable pTbinhigh{"pTbinhigh", 20.0, "pT bin high"}; - ConfigurableAxis binsMultPlot{"binsCent", {200, 0.0f, 200.0f}, "Binning of the centrality axis for plots"}; + Configurable avoidsplitrackMC{"avoidsplitrackMC", true, "avoid split track in MC"}; + Configurable cAllGenCollisions{"cAllGenCollisions", false, "To fill all generated collisions for the signal loss calculations"}; + ConfigurableAxis binsMultPlot{"binsMultPlot", {201, -0.5f, 200.5f}, "centrality axis bins"}; + ConfigurableAxis axisdEdx{"axisdEdx", {1, 0.0f, 200.0f}, "dE/dx (a.u.)"}; + ConfigurableAxis axisPtfordEbydx{"axisPtfordEbydx", {1, 0, 20}, "pT (GeV/c)"}; + ConfigurableAxis axisMultdist{"axisMultdist", {1, 0, 70000}, "Multiplicity distribution"}; + + // Event plane configurables + Configurable boostDaugter1{"boostDaugter1", false, "Boost daughter Kaon in the COM frame"}; + Configurable boostDaugter2{"boostDaugter2", true, "Boost daughter Pion in the COM frame"}; + Configurable activateTHnSparseCosThStarHelicity{"activateTHnSparseCosThStarHelicity", true, "Activate the THnSparse with cosThStar w.r.t. helicity axis"}; + Configurable activateTHnSparseCosThStarProduction{"activateTHnSparseCosThStarProduction", false, "Activate the THnSparse with cosThStar w.r.t. production axis"}; + Configurable activateTHnSparseCosThStarBeam{"activateTHnSparseCosThStarBeam", false, "Activate the THnSparse with cosThStar w.r.t. beam axis (Gottified jackson frame)"}; + Configurable activateTHnSparseCosThStarRandom{"activateTHnSparseCosThStarRandom", false, "Activate the THnSparse with cosThStar w.r.t. random axis"}; + Configurable cRotations{"cRotations", 3, "Number of random rotations in the rotational background"}; + ConfigurableAxis configThnAxisPOL{"configThnAxisPOL", {20, -1.0, 1.0}, "Costheta axis"}; + TRandom* rn = new TRandom(); void init(InitContext const&) { @@ -124,205 +140,177 @@ struct kstarqa { AxisSpec vertexZAxis = {nBins, -15., 15., "vrtx_{Z} [cm] for plots"}; AxisSpec ptAxis = {nBinspT, pTbinlow, pTbinhigh, "#it{p}_{T} (GeV/#it{c})"}; AxisSpec invmassAxis = {nBinsinvMass, invMassbinlow, invMassbinhigh, "Invariant mass (GeV/#it{c}^{2})"}; + AxisSpec thnAxisPOL{configThnAxisPOL, "cos(#theta)"}; // Histograms // Event selection rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); - rEventSelection.add("hmult", "Centrality distribution", kTH1F, {{binsMultPlot}}); + rEventSelection.add("hmult", "Multiplicity percentile", kTH1F, {{binsMultPlot}}); // for primary tracks - if (QAbefore && QAafter) { - histos.add("hNsigmaPionTPC_before", "NsigmaPion TPC distribution before", kTH2F, {{100, 0.0f, 10.0f}, {200, -10.0f, 10.0f}}); - histos.add("hNsigmaPionTOF_before", "NsigmaPion TOF distribution before", kTH2F, {{100, 0.0f, 10.0f}, {200, -10.0f, 10.0f}}); - histos.add("hNsigmaKaonTPC_before", "NsigmaKaon TPC distribution before", kTH2F, {{100, 0.0f, 10.0f}, {200, -10.0f, 10.0f}}); - histos.add("hNsigmaKaonTOF_before", "NsigmaKaon TOF distribution before", kTH2F, {{100, 0.0f, 10.0f}, {200, -10.0f, 10.0f}}); - - histos.add("hEta_after", "Eta distribution", kTH1F, {{200, -1.0f, 1.0f}}); - histos.add("hCRFC_after", "CRFC after distribution", kTH1F, {{100, 0.0f, 10.0f}}); - histos.add("hCRFC_before", "CRFC before distribution", kTH1F, {{100, 0.0f, 10.0f}}); - histos.add("hNsigmaPionTPC_after", "NsigmaPion TPC distribution", kTH2F, {{100, 0.0f, 10.0f}, {200, -10.0f, 10.0f}}); - histos.add("hNsigmaPionTOF_after", "NsigmaPion TOF distribution", kTH2F, {{100, 0.0f, 10.0f}, {200, -10.0f, 10.0f}}); - histos.add("hNsigmaKaonTPC_after", "NsigmaKaon TPC distribution", kTH2F, {{100, 0.0f, 10.0f}, {200, -10.0f, 10.0f}}); - histos.add("hNsigmaKaonTOF_after", "NsigmaKaon TOF distribution", kTH2F, {{100, 0.0f, 10.0f}, {200, -10.0f, 10.0f}}); + if (cQAplots) { + hOthers.add("dE_by_dx_TPC", "dE/dx signal in the TPC as a function of pT", kTH2F, {axisPtfordEbydx, axisdEdx}); + hOthers.add("hphi", "Phi distribution", kTH1F, {{65, 0, 6.5}}); + hOthers.add("hEta_after", "Eta distribution", kTH1F, {{200, -1.0f, 1.0f}}); + hOthers.add("hCRFC_after", "CRFC after distribution", kTH1F, {{100, 0.0f, 10.0f}}); + hOthers.add("hCRFC_before", "CRFC before distribution", kTH1F, {{100, 0.0f, 10.0f}}); + + hPID.add("Before/hNsigmaTPC_Ka_before", "N #sigma Kaon TPC before", kTH2F, {{100, 0.0f, 10.0f}, {200, -10.0f, 10.0f}}); + hPID.add("Before/hNsigmaTOF_Ka_before", "N #sigma Kaon TOF before", kTH2F, {{100, 0.0f, 10.0f}, {200, -10.0f, 10.0f}}); + hPID.add("Before/hNsigmaTPC_Pi_before", "N #sigma Pion TPC before", kTH2F, {{100, 0.0f, 10.0f}, {200, -10.0f, 10.0f}}); + hPID.add("Before/hNsigmaTOF_Pi_before", "N #sigma Pion TOF before", kTH2F, {{100, 0.0f, 10.0f}, {200, -10.0f, 10.0f}}); + hPID.add("Before/hNsigma_TPC_TOF_Ka_before", "N #sigma Kaon TOF before", kTH2F, {{100, -5.0f, 5.0f}, {100, -5.0f, 5.0f}}); + hPID.add("Before/hNsigma_TPC_TOF_Pi_before", "N #sigma Pion TOF before", kTH2F, {{100, -5.0f, 5.0f}, {100, -5.0f, 5.0f}}); + hPID.add("h1PID_TPC_kaon_data", "Kaon PID distribution in data", kTH1F, {{100, -10.0f, 10.0f}}); + hPID.add("h1PID_TPC_pion_data", "Pion PID distribution in data", kTH1F, {{100, -10.0f, 10.0f}}); + hPID.add("h1PID_TPC_kaon_MC", "Kaon PID distribution in MC", kTH1F, {{100, -10.0f, 10.0f}}); + hPID.add("h1PID_TPC_pion_MC", "Pion PID distribution in MC", kTH1F, {{100, -10.0f, 10.0f}}); + hPID.add("h1PID_TOF_kaon_data", "Kaon PID distribution in data", kTH1F, {{100, -10.0f, 10.0f}}); + hPID.add("h1PID_TOF_pion_data", "Pion PID distribution in data", kTH1F, {{100, -10.0f, 10.0f}}); + hPID.add("h1PID_TOF_kaon_MC", "Kaon PID distribution in MC", kTH1F, {{100, -10.0f, 10.0f}}); + hPID.add("h1PID_TOF_pion_MC", "Pion PID distribution in MC", kTH1F, {{100, -10.0f, 10.0f}}); + + hPID.add("After/hNsigmaPionTPC_after", "N #Pi TPC after", kTH2F, {{100, 0.0f, 10.0f}, {200, -10.0f, 10.0f}}); + hPID.add("After/hNsigmaPionTOF_after", "N #Pi TOF after", kTH2F, {{100, 0.0f, 10.0f}, {200, -10.0f, 10.0f}}); + hPID.add("After/hNsigmaKaonTPC_after", "N #sigma Kaon TPC after", kTH2F, {{100, 0.0f, 10.0f}, {200, -10.0f, 10.0f}}); + hPID.add("After/hNsigmaKaonTOF_after", "N #sigma Kaon TOF after", kTH2F, {{100, 0.0f, 10.0f}, {200, -10.0f, 10.0f}}); + hPID.add("After/hNsigma_TPC_TOF_Ka_after", "N #sigma Kaon TOF after", kTH2F, {{100, -5.0f, 5.0f}, {100, -5.0f, 5.0f}}); + hPID.add("After/hNsigma_TPC_TOF_Pi_after", "N #sigma Pion TOF after", kTH2F, {{100, -5.0f, 5.0f}, {100, -5.0f, 5.0f}}); } // KStar histograms - histos.add("h3KstarInvMassUnlikeSign", "Invariant mass of kstar meson Unlike Sign", kTHnSparseF, {{binsMultPlot}, {ptAxis}, {invmassAxis}}, true); - histos.add("h3KstarInvMasslikeSign", "Invariant mass of kstar meson like Sign", kTHnSparseF, {{binsMultPlot}, {ptAxis}, {invmassAxis}}, true); - histos.add("h3KstarInvMassMixed", "Invariant mass of kstar meson Mixed", kTHnSparseF, {{binsMultPlot}, {ptAxis}, {invmassAxis}}, true); + hInvMass.add("h3KstarInvMassUnlikeSign", "kstar Unlike Sign", kTHnSparseF, {binsMultPlot, ptAxis, invmassAxis, thnAxisPOL}); + hInvMass.add("h3KstarInvMassMixed", "kstar Mixed", kTHnSparseF, {binsMultPlot, ptAxis, invmassAxis, thnAxisPOL}); + if (calcLikeSign) + hInvMass.add("h3KstarInvMasslikeSign", "kstar like Sign", kTHnSparseF, {binsMultPlot, ptAxis, invmassAxis, thnAxisPOL}); + if (calcRotational) + hInvMass.add("h3KstarInvMassRotated", "kstar rotated", kTHnSparseF, {binsMultPlot, ptAxis, invmassAxis, thnAxisPOL}); // MC generated histograms - histos.add("k892Gen", "pT distribution of True MC K(892)0", kTH1D, {ptAxis}); - // histos.add("k892GenAnti", "pT distribution of True MC Anti-K(892)0", kTH1D, {ptAxis}); + hInvMass.add("hk892GenpT", "pT distribution of True MC K(892)0", kTH2F, {ptAxis, binsMultPlot}); + // hInvMass.add("hk892GenpTAnti", "pT distribution of True MC Anti-K(892)0", kTH2F, {ptAxis}, {binsMultPlot}); // Reconstructed MC histogram - histos.add("h3KstarRec", "pT of reconstructed kstar", kTH1D, {ptAxis}); - histos.add("h1KstarRecMass", "Invariant mass of kstar meson", kTH1D, {invmassAxis}); - // histos.add("h1KstarRecpt", "pT of kstar meson", kTH1D, {ptAxis}); - histos.add("h1genmass", "Invariant mass of generated kstar meson", kTH1D, {invmassAxis}); - histos.add("h1recpt", "pT of generated kstar meson", kTH1D, {ptAxis}); - histos.add("events_check", "No. of events in the reconstructed and generated MC", kTH1F, {{6, 0, 6}}); + hInvMass.add("h1KstarRecMass", "Invariant mass of kstar meson", kTH1F, {invmassAxis}); + hInvMass.add("h2KstarRecpt1", "pT of kstar meson", kTH2F, {ptAxis, binsMultPlot}); + hInvMass.add("h2KstarRecpt2", "pT of generated kstar meson", kTH2F, {ptAxis, binsMultPlot}); + hInvMass.add("h1genmass", "Invariant mass of generated kstar meson", kTH1F, {invmassAxis}); + rEventSelection.add("events_check_data", "No. of events in the data", kTH1I, {{20, 0, 20}}); + rEventSelection.add("events_check", "No. of events in the generated MC", kTH1I, {{20, 0, 20}}); + rEventSelection.add("events_checkrec", "No. of events in the reconstructed MC", kTH1I, {{20, 0, 20}}); + hInvMass.add("h1KSRecsplit", "KS meson Rec split", kTH1F, {{100, 0.0f, 10.0f}}); + + // Multplicity distribution + if (cQAevents) { + rEventSelection.add("multdist_FT0M", "FT0M Multiplicity distribution", kTH1F, {axisMultdist}); + // hInvMass.add("multdist_FT0A", "FT0A Multiplicity distribution", kTH1F, {axisMultdist}); + // hInvMass.add("multdist_FT0C", "FT0C Multiplicity distribution", kTH1F, {axisMultdist}); + // hInvMass.add("hNcontributor", "Number of primary vertex contributor", kTH1F, {{2000, 0.0f, 10000.0f}}); + rEventSelection.add("hDcaxy", "Dcaxy distribution", kTH1F, {{200, -1.0f, 1.0f}}); + rEventSelection.add("hDcaz", "Dcaz distribution", kTH1F, {{200, -1.0f, 1.0f}}); + } } - double massPi = TDatabasePDG::Instance()->GetParticle(kPiPlus)->Mass(); // FIXME: Get from the common header + // double massPi = TDatabasePDG::Instance()->GetParticle(kPiPlus)->Mass(); // FIXME: Get from the common header + double massPi = o2::constants::physics::MassPiPlus; double massKa = o2::constants::physics::MassKPlus; - ROOT::Math::PtEtaPhiMVector CKSVector; template bool selectionTrack(const T& candidate) { - // if (iscustomDCAcut && (!candidate.isGlobalTrack() || !candidate.isPVContributor() || candidate.itsNCls() < cfgITScluster)) { - // return false; - // } - // if (ismanulatrksel && - // !(candidate.isGlobalTrackWoDCA() && candidate.isPVContributor() && std::abs(candidate.dcaXY()) < cfgCutDCAxy && std::abs(candidate.dcaZ()) < cfgCutDCAz && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsFound() > cfgTPCcluster && candidate.tpcCrossedRowsOverFindableCls() > cfgRCRFC)) { - // return false; - // } - if (std::abs(candidate.pt()) < cfgCutPT) - return false; - if (std::abs(candidate.dcaXY()) > cfgCutDCAxy) - return false; - if (std::abs(candidate.dcaZ()) > cfgCutDCAz) - return false; - if (candidate.tpcCrossedRowsOverFindableCls() < cfgRCRFC) - return false; - if (candidate.itsNCls() < cfgITScluster) - return false; - if (candidate.tpcNClsFound() < cfgTPCcluster) - return false; - if (candidate.itsChi2NCl() >= cfgITSChi2NCl) - return false; - if (candidate.tpcChi2NCl() >= cfgTPCChi2NCl) - return false; - if (cfgUseITSRefit && !candidate.passedITSRefit()) - return false; - if (cfgUseTPCRefit && !candidate.passedTPCRefit()) - return false; - if (cfgPVContributor && !candidate.isPVContributor()) - return false; - if (cfgPrimaryTrack && !candidate.isPrimaryTrack()) - return false; - if (cfgGlobalWoDCATrack && !candidate.isGlobalTrackWoDCA()) - return false; - if (cfgGlobalTrack && !candidate.isGlobalTrack()) + if (ismanualDCAcut && !(candidate.isGlobalTrackWoDCA() && candidate.isPVContributor() && std::abs(candidate.dcaXY()) < cfgCutDCAxy && std::abs(candidate.dcaZ()) < cfgCutDCAz && candidate.itsNCls() > cfgITScluster)) { return false; + } else if (!ismanualDCAcut) { + if (std::abs(candidate.pt()) < cfgCutPT) + return false; + if (std::abs(candidate.dcaXY()) > cfgCutDCAxy) + return false; + if (std::abs(candidate.dcaZ()) > cfgCutDCAz) + return false; + if (candidate.tpcCrossedRowsOverFindableCls() < cfgRCRFC) + return false; + if (candidate.itsNCls() < cfgITScluster) + return false; + if (candidate.tpcNClsFound() < cfgTPCcluster) + return false; + if (candidate.itsChi2NCl() >= cfgITSChi2NCl) + return false; + if (candidate.tpcChi2NCl() >= cfgTPCChi2NCl) + return false; + if (cfgPVContributor && !candidate.isPVContributor()) + return false; + if (cfgPrimaryTrack && !candidate.isPrimaryTrack()) + return false; + if (cfgGlobalWoDCATrack && !candidate.isGlobalTrackWoDCA()) + return false; + if (cfgGlobalTrack && !candidate.isGlobalTrack()) + return false; + } return true; } template - bool selectionPID(const T& candidate, int PID) + bool isFakeTrack(const T& track, int PID) { - if (PID == 0) { - if (onlyTOF) { - // LOG(info) << "************I am inside ONLYTOF****************"; - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < nsigmaCutTOFPi) { - return true; - } - } else if (onlyTOFHIT) { - // LOG(info) << "************I am inside ONLYTOFHIT****************"; - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < nsigmaCutTOFPi) { - return true; - } - if (!candidate.hasTOF() && - std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPCPi) { - return true; - } - } else { - // LOG(info) << "************I am neither in ONLYTOF or ONLYTOFHIT****************"; - if (candidate.hasTOF() && (candidate.tofNSigmaPi() * candidate.tofNSigmaPi() + candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi()) < (nsigmaCutCombined * nsigmaCutCombined)) { - return true; - } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPCPi) { - return true; - } - } - } else if (PID == 1) { - if (onlyTOF) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < nsigmaCutTOFKa) { - return true; - } - } else if (onlyTOFHIT) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < nsigmaCutTOFKa) { - return true; - } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPCKa) { - return true; - } - } else { - if (candidate.hasTOF() && (candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa()) < (nsigmaCutCombined * nsigmaCutCombined)) { - return true; - } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPCKa) { - return true; - } - } + const auto pglobal = track.p(); + const auto ptpc = track.tpcInnerParam(); + if (PID == 0 && std::abs(pglobal - ptpc) > cFakeTrackCutPi) { + return true; + } + if (PID == 1 && std::abs(pglobal - ptpc) > cFakeTrackCutKa) { + return true; } return false; } template - bool MIDselectionPID(const T& candidate, int PID) + bool selectionPID(const T& candidate, int PID) { if (PID == 0) { if (onlyTOF) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < 3.0) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < nsigmaCutTOFPi && candidate.beta() > cBetaCutTOF) { return true; } } else if (onlyTOFHIT) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < 3.0) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < nsigmaCutTOFPi && candidate.beta() > cBetaCutTOF) { return true; } - if (!candidate.hasTOF() && - std::abs(candidate.tpcNSigmaPi()) < 3.0) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPCPi) { + return true; + } + } else if (onlyTPC) { + if (std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPCPi) { return true; } } else { - // LOG(info) << "************I am neither in ONLYTOF or ONLYTOFHIT****************"; - if (candidate.hasTOF() && (candidate.tofNSigmaPi() * candidate.tofNSigmaPi() + candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi()) < (3.0 * 3.0)) { + if (candidate.hasTOF() && (candidate.tofNSigmaPi() * candidate.tofNSigmaPi() + candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi()) < (nsigmaCutCombined * nsigmaCutCombined) && candidate.beta() > cBetaCutTOF) { return true; } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < 3.0) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPCPi) { return true; } } } else if (PID == 1) { if (onlyTOF) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < 3.0) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < nsigmaCutTOFKa && candidate.beta() > cBetaCutTOF) { return true; } } else if (onlyTOFHIT) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < 3.0) { - return true; - } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < 3.0) { - return true; - } - } else { - if (candidate.hasTOF() && (candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa()) < (3.0 * 3.0)) { - return true; - } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < 3.0) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < nsigmaCutTOFKa && candidate.beta() > cBetaCutTOF) { return true; } - } - } else if (PID == 2) { - if (onlyTOF) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPr()) < 3.0) { - return true; - } - } else if (onlyTOFHIT) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPr()) < 3.0) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPCKa) { return true; } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < 3.0) { + } else if (onlyTPC) { + if (std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPCKa) { return true; } } else { - // LOG(info) << "************I am neither in ONLYTOF or ONLYTOFHIT****************"; - if (candidate.hasTOF() && (candidate.tofNSigmaPr() * candidate.tofNSigmaPr() + candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr()) < (3.0 * 3.0)) { + if (candidate.hasTOF() && (candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa()) < (nsigmaCutCombined * nsigmaCutCombined) && candidate.beta() > cBetaCutTOF) { return true; } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < 3.0) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPCKa) { return true; } } @@ -330,8 +318,88 @@ struct kstarqa { return false; } - array pvec0; - array pvec1; + // template + // bool cMIDselectionPID(const T& candidate, int PID) + // { + // if (PID == 0) { + // if (onlyTOF) { + // if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < 3.0) { + // return true; + // } + // } else if (onlyTOFHIT) { + // if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < 3.0) { + // return true; + // } + // if (!candidate.hasTOF() && + // std::abs(candidate.tpcNSigmaPi()) < 3.0) { + // return true; + // } + // } else if (onlyTPC) { + // if (std::abs(candidate.tpcNSigmaPi()) < 3.0) { + // return true; + // } + // } else { + // if (candidate.hasTOF() && (candidate.tofNSigmaPi() * candidate.tofNSigmaPi() + candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi()) < (3.0 * 3.0)) { + // return true; + // } + // if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < 3.0) { + // return true; + // } + // } + // } else if (PID == 1) { + // if (onlyTOF) { + // if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < 3.0) { + // return true; + // } + // } else if (onlyTOFHIT) { + // if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < 3.0) { + // return true; + // } + // if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < 3.0) { + // return true; + // } + // } else if (onlyTPC) { + // if (std::abs(candidate.tpcNSigmaKa()) < 3.0) { + // return true; + // } + // } else { + // if (candidate.hasTOF() && (candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa()) < (3.0 * 3.0)) { + // return true; + // } + // if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < 3.0) { + // return true; + // } + // } + // } else if (PID == 2) { + // if (onlyTOF) { + // if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPr()) < 3.0) { + // return true; + // } + // } else if (onlyTOFHIT) { + // if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPr()) < 3.0) { + // return true; + // } + // if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < 3.0) { + // return true; + // } + // } else if (onlyTPC) { + // if (std::abs(candidate.tpcNSigmaPr()) < 3.0) { + // return true; + // } + // } else { + // if (candidate.hasTOF() && (candidate.tofNSigmaPr() * candidate.tofNSigmaPr() + candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr()) < (3.0 * 3.0)) { + // return true; + // } + // if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < 3.0) { + // return true; + // } + // } + // } + // return false; + // } + + std::array pvec0; + std::array pvec1; // Defining filters for events (event selection) // Processed events will be already fulfilling the event selection @@ -340,200 +408,276 @@ struct kstarqa { Filter posZFilter = (nabs(o2::aod::collision::posZ) < cutzvertex); Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPT); - Filter DCAcutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); + Filter fDCAcutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); using EventCandidates = soa::Filtered>; - using TrackCandidates = soa::Filtered>; - using V0TrackCandidate = aod::V0Datas; - using EventCandidatesMC = soa::Join; - using TrackCandidatesMC = soa::Filtered>; + using TrackCandidates = soa::Filtered>; + using EventCandidatesMC = soa::Join; - ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for ME mixing"}; - // ConfigurableAxis axisMultiplicityClass{"axisMultiplicityClass", {10, 0, 100}, "multiplicity percentile for ME mixing"}; - ConfigurableAxis axisMultiplicity{"axisMultiplicity", {2000, 0, 10000}, "TPC multiplicity for bin for ME mixing"}; + using TrackCandidatesMC = soa::Filtered>; - using BinningTypeTPCMultiplicity = ColumnBinningPolicy; - // using BinningTypeVertexContributor = - // ColumnBinningPolicy; - using BinningTypeCentralityM = ColumnBinningPolicy; - using BinningTypeVertexContributor = ColumnBinningPolicy; + //*********Varibles declaration*************** + TLorentzVector lv1, lv2, lv3, lv4, lv5; + float multiplicity = 0.0f; + float theta2; + ROOT::Math::PxPyPzMVector daughter1, daughter2, daughterSelected, fourVecDau1, fourVecMother, fourVecDauCM; + ROOT::Math::XYZVector threeVecDauCM, helicityVec, randomVec, beamVec, normalVec; + bool isMix = false; - BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicity}, true}; + template + void fillInvMass(const T1& track1, const T2& track2, const T3& lv2, const T4& lv3, float multiplicity, bool isMix) + { + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); // Kaon + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); // Pion + daughterSelected = (boostDaugter1) ? daughter1 : daughter2; + auto selectedDauMass = (boostDaugter1) ? massKa : massPi; + + // polarization calculations + + fourVecDau1 = ROOT::Math::PxPyPzMVector(daughterSelected.Px(), daughterSelected.Py(), daughterSelected.Pz(), selectedDauMass); // Kaon or Pion + + fourVecMother = ROOT::Math::PxPyPzMVector(lv3.Px(), lv3.Py(), lv3.Pz(), lv3.M()); // mass of KshortKshort pair + ROOT::Math::Boost boost{fourVecMother.BoostToCM()}; // boost mother to center of mass frame + fourVecDauCM = boost(fourVecDau1); // boost the frame of daughter same as mother + threeVecDauCM = fourVecDauCM.Vect(); // get the 3 vector of daughter in the frame of mother + + if (std::abs(lv3.Rapidity()) < 0.5) { + if (activateTHnSparseCosThStarHelicity) { + helicityVec = fourVecMother.Vect(); // 3 vector of mother in COM frame + auto cosThetaStarHelicity = helicityVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(helicityVec.Mag2())); + + if (track1.sign() * track2.sign() < 0) { + if (!isMix) { + hInvMass.fill(HIST("h3KstarInvMassUnlikeSign"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarHelicity); + + for (int i = 0; i < cRotations; i++) { + theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / rotationalCut, o2::constants::math::PI + o2::constants::math::PI / rotationalCut); + lv4.SetPtEtaPhiM(track1.pt(), track1.eta(), track1.phi() + theta2, massKa); // for rotated background + lv5 = lv2 + lv4; + if (calcRotational) + hInvMass.fill(HIST("h3KstarInvMassRotated"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarHelicity); + } + } else { + hInvMass.fill(HIST("h3KstarInvMassMixed"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarHelicity); + } + } else { + if (!isMix) { + if (calcLikeSign) + hInvMass.fill(HIST("h3KstarInvMasslikeSign"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarHelicity); + } + } - SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, &cache}; + } else if (activateTHnSparseCosThStarProduction) { + normalVec = ROOT::Math::XYZVector(lv3.Py(), -lv3.Px(), 0.f); + auto cosThetaStarProduction = normalVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(normalVec.Mag2())); - double totmomka = 0.0; - double totmompi = 0.0; - double totmomkamix = 0.0; - double totmompimix = 0.0; - // double openingangle = 0.0; - // double openinganglemix = 0.0; + if (track1.sign() * track2.sign() < 0) { + if (!isMix) { + hInvMass.fill(HIST("h3KstarInvMassUnlikeSign"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarProduction); + for (int i = 0; i < cRotations; i++) { + theta2 = rn->Uniform(0, o2::constants::math::PI); + lv4.SetPtEtaPhiM(track1.pt(), track1.eta(), track1.phi() + theta2, massKa); // for rotated background + lv5 = lv2 + lv4; + if (calcRotational) + hInvMass.fill(HIST("h3KstarInvMassRotated"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarProduction); + } + } else { + hInvMass.fill(HIST("h3KstarInvMassMixed"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarProduction); + } + } else { + if (!isMix) { + if (calcLikeSign) + hInvMass.fill(HIST("h3KstarInvMasslikeSign"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarProduction); + } + } + } else if (activateTHnSparseCosThStarBeam) { + beamVec = ROOT::Math::XYZVector(0.f, 0.f, 1.f); + auto cosThetaStarBeam = beamVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + + if (track1.sign() * track2.sign() < 0) { + if (!isMix) { + hInvMass.fill(HIST("h3KstarInvMassUnlikeSign"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarBeam); + for (int i = 0; i < cRotations; i++) { + theta2 = rn->Uniform(0, o2::constants::math::PI); + lv4.SetPtEtaPhiM(track1.pt(), track1.eta(), track1.phi() + theta2, massKa); // for rotated background + lv5 = lv2 + lv4; + if (calcRotational) + hInvMass.fill(HIST("h3KstarInvMassRotated"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarBeam); + } + } else { + hInvMass.fill(HIST("h3KstarInvMassMixed"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarBeam); + } + } else { + if (calcLikeSign) + hInvMass.fill(HIST("h3KstarInvMasslikeSign"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarBeam); + } + } else if (activateTHnSparseCosThStarRandom) { + auto phiRandom = gRandom->Uniform(0.f, constants::math::TwoPI); + auto thetaRandom = gRandom->Uniform(0.f, constants::math::PI); + + randomVec = ROOT::Math::XYZVector(std::sin(thetaRandom) * std::cos(phiRandom), std::sin(thetaRandom) * std::sin(phiRandom), std::cos(thetaRandom)); + auto cosThetaStarRandom = randomVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + + if (track1.sign() * track2.sign() < 0) { + if (!isMix) { + hInvMass.fill(HIST("h3KstarInvMassUnlikeSign"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarRandom); + for (int i = 0; i < cRotations; i++) { + theta2 = rn->Uniform(0, o2::constants::math::PI); + lv4.SetPtEtaPhiM(track1.pt(), track1.eta(), track1.phi() + theta2, massKa); // for rotated background + lv5 = lv2 + lv4; + if (calcRotational) + hInvMass.fill(HIST("h3KstarInvMassRotated"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarRandom); + } + } else { + hInvMass.fill(HIST("h3KstarInvMassMixed"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarRandom); + } + } else { + if (!isMix) { + if (calcLikeSign) + hInvMass.fill(HIST("h3KstarInvMasslikeSign"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarRandom); + } + } + } + } + } + + // int counter = 0; void processSE(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) { + rEventSelection.fill(HIST("events_check_data"), 0.5); - if (!collision.sel8()) { + if (cTVXEvsel && (!collision.selection_bit(aod::evsel::kIsTriggerTVX))) { return; } + rEventSelection.fill(HIST("events_check_data"), 1.5); - if (timFrameEvsel && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { return; } + rEventSelection.fill(HIST("events_check_data"), 2.5); - if (piluprejection && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { - return; - } - if (goodzvertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { - return; - } - if (itstpctracks && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + if (!collision.sel8()) { return; } + rEventSelection.fill(HIST("events_check_data"), 3.5); - std::vector pions, kaons; - std::vector PionIndex = {}; - std::vector KaonIndex = {}; - std::vector PioncollIndex = {}; - std::vector KaoncollIndex = {}; - std::vector PionSign = {}; - std::vector KaonSign = {}; - - std::vector PionPx = {}; - std::vector KaonPx = {}; - std::vector PionPy = {}; - std::vector KaonPy = {}; - std::vector PionPz = {}; - std::vector KaonPz = {}; - std::vector PionP = {}; - std::vector KaonP = {}; - - float multiplicity = 0.0f; - /* if (cfgMultFT0) - multiplicity = collision.multZeqFT0A() + collision.multZeqFT0C(); - if (cfgMultFT0 == 0 && cfgCentFT0C == 1) - multiplicity = collision.centFT0C(); - if (cfgMultFT0 == 0 && cfgCentFT0C == 0)*/ multiplicity = collision.centFT0M(); // Fill the event counter - rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); - rEventSelection.fill(HIST("hmult"), multiplicity); - - for (auto track1 : tracks) { + if (cQAevents) { + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + rEventSelection.fill(HIST("hmult"), multiplicity); + rEventSelection.fill(HIST("multdist_FT0M"), collision.multFT0M()); + // rEventSelection.fill(HIST("multdist_FT0A"), collision.multFT0A()); + // rEventSelection.fill(HIST("multdist_FT0C"), collision.multFT0C()); + // rEventSelection.fill(HIST("hNcontributor"), collision.numContrib()); + } - if (QAbefore) { - histos.fill(HIST("hNsigmaKaonTPC_before"), track1.pt(), track1.tpcNSigmaKa()); - histos.fill(HIST("hNsigmaKaonTOF_before"), track1.pt(), track1.tofNSigmaKa()); - histos.fill(HIST("hCRFC_before"), track1.tpcCrossedRowsOverFindableCls()); - } + for (const auto& [track1, track2] : combinations(CombinationsFullIndexPolicy(tracks, tracks))) { + if (cQAplots) { + hPID.fill(HIST("Before/hNsigmaTPC_Ka_before"), track1.pt(), track1.tpcNSigmaKa()); + hPID.fill(HIST("Before/hNsigmaTOF_Ka_before"), track1.pt(), track1.tofNSigmaKa()); + hPID.fill(HIST("Before/hNsigmaTPC_Pi_before"), track2.pt(), track2.tpcNSigmaPi()); + hPID.fill(HIST("Before/hNsigmaTOF_Pi_before"), track2.pt(), track2.tofNSigmaPi()); + hPID.fill(HIST("Before/hNsigma_TPC_TOF_Ka_before"), track1.tpcNSigmaKa(), track1.tofNSigmaKa()); + hPID.fill(HIST("Before/hNsigma_TPC_TOF_Pi_before"), track2.tpcNSigmaPi(), track2.tofNSigmaPi()); + hPID.fill(HIST("h1PID_TPC_kaon_data"), track1.tpcNSigmaKa()); + hPID.fill(HIST("h1PID_TPC_pion_data"), track2.tpcNSigmaPi()); + hPID.fill(HIST("h1PID_TOF_kaon_data"), track1.tofNSigmaKa()); + hPID.fill(HIST("h1PID_TOF_pion_data"), track2.tofNSigmaPi()); + + hOthers.fill(HIST("hCRFC_before"), track1.tpcCrossedRowsOverFindableCls()); + hOthers.fill(HIST("dE_by_dx_TPC"), track1.p(), track1.tpcSignal()); + hOthers.fill(HIST("hphi"), track1.phi()); + } + rEventSelection.fill(HIST("events_check_data"), 4.5); if (!selectionTrack(track1)) { continue; } - if (!selectionPID(track1, 1)) // kaon + if (!selectionTrack(track2)) { continue; - - if (MID) { - if (MIDselectionPID(track1, 0)) // misidentified as pion - continue; - - if (MIDselectionPID(track1, 2)) // misidentified as proton - continue; } + rEventSelection.fill(HIST("events_check_data"), 5.5); + // if (counter < 1e4) + // std::cout << "TOF beta value is " << track1.beta() << std::endl; + // counter++; - if (QAafter) { - histos.fill(HIST("hEta_after"), track1.eta()); - histos.fill(HIST("hCRFC_after"), track1.tpcCrossedRowsOverFindableCls()); - histos.fill(HIST("hNsigmaKaonTPC_after"), track1.pt(), track1.tpcNSigmaKa()); - histos.fill(HIST("hNsigmaKaonTOF_after"), track1.pt(), track1.tofNSigmaKa()); + if (cQAevents) { + rEventSelection.fill(HIST("hDcaxy"), track1.dcaXY()); + rEventSelection.fill(HIST("hDcaz"), track1.dcaZ()); } - totmomka = TMath::Sqrt(track1.px() * track1.px() + track1.py() * track1.py() + track1.pz() * track1.pz()); - - ROOT::Math::PtEtaPhiMVector temp1(track1.pt(), track1.eta(), track1.phi(), massKa); - kaons.push_back(temp1); - KaonIndex.push_back(track1.globalIndex()); - KaoncollIndex.push_back(track1.collisionId()); - KaonSign.push_back(track1.sign()); - KaonPx.push_back(track1.px()); - KaonPy.push_back(track1.py()); - KaonPz.push_back(track1.pz()); - KaonP.push_back(totmomka); - - } // track loop ends - - for (auto track2 : tracks) { + // since we are using combinations full index policy, so repeated pairs are allowed, so we can check one with Kaon and other with pion + if (!selectionPID(track1, 1)) // Track 1 is checked with Kaon + continue; + if (!selectionPID(track2, 0)) // Track 2 is checked with Pion + continue; - if (QAbefore) { - histos.fill(HIST("hNsigmaPionTPC_before"), track2.pt(), track2.tpcNSigmaPi()); - histos.fill(HIST("hNsigmaPionTOF_before"), track2.pt(), track2.tofNSigmaPi()); - } + rEventSelection.fill(HIST("events_check_data"), 6.5); - if (!selectionTrack(track2)) { + if (cFakeTrack && isFakeTrack(track1, 1)) // Kaon + continue; + if (cFakeTrack && isFakeTrack(track2, 0)) // Pion continue; - } - if (!selectionPID(track2, 0)) // pion + // if (cMID) { + // if (cMIDselectionPID(track1, 0)) // Kaon misidentified as pion + // continue; + // if (cMIDselectionPID(track1, 2)) // Kaon misidentified as proton + // continue; + // if (cMIDselectionPID(track2, 1)) // Pion misidentified as kaon + // continue; + // } + + rEventSelection.fill(HIST("events_check_data"), 7.5); + + if (cQAplots) { + hOthers.fill(HIST("hEta_after"), track1.eta()); + hOthers.fill(HIST("hCRFC_after"), track1.tpcCrossedRowsOverFindableCls()); + hPID.fill(HIST("After/hNsigmaKaonTPC_after"), track1.pt(), track1.tpcNSigmaKa()); + hPID.fill(HIST("After/hNsigmaKaonTOF_after"), track1.pt(), track1.tofNSigmaKa()); + hPID.fill(HIST("After/hNsigmaPionTPC_after"), track2.pt(), track2.tpcNSigmaPi()); + hPID.fill(HIST("After/hNsigmaPionTOF_after"), track2.pt(), track2.tofNSigmaPi()); + hPID.fill(HIST("After/hNsigma_TPC_TOF_Ka_after"), track1.tpcNSigmaKa(), track1.tofNSigmaKa()); + hPID.fill(HIST("After/hNsigma_TPC_TOF_Pi_after"), track2.tpcNSigmaPi(), track2.tofNSigmaPi()); + } + + if (track1.globalIndex() == track2.globalIndex()) continue; - if (MID) { - if (MIDselectionPID(track2, 1)) // misidentified as kaon - continue; - } - if (QAafter) { - histos.fill(HIST("hNsigmaPionTPC_after"), track2.pt(), track2.tpcNSigmaPi()); - histos.fill(HIST("hNsigmaPionTOF_after"), track2.pt(), track2.tofNSigmaPi()); - } + rEventSelection.fill(HIST("events_check_data"), 8.5); - totmompi = TMath::Sqrt(track2.px() * track2.px() + track2.py() * track2.py() + track2.pz() * track2.pz()); - - ROOT::Math::PtEtaPhiMVector temp2(track2.pt(), track2.eta(), track2.phi(), massPi); - pions.push_back(temp2); - PionIndex.push_back(track2.globalIndex()); - PioncollIndex.push_back(track2.collisionId()); - PionSign.push_back(track2.sign()); - PionPx.push_back(track2.px()); - PionPy.push_back(track2.py()); - PionPz.push_back(track2.pz()); - PionP.push_back(totmompi); - } // track loop ends - - if (!QA) { - if (pions.size() != 0 && kaons.size() != 0) { - for (auto ikaon = kaons.begin(); ikaon != kaons.end(); ++ikaon) { - auto i1 = std::distance(kaons.begin(), ikaon); - for (auto ipion = pions.begin(); ipion != pions.end(); ++ipion) { - auto i3 = std::distance(pions.begin(), ipion); - - if (PionIndex.at(i3) <= KaonIndex.at(i1)) - continue; - CKSVector = kaons.at(i1) + pions.at(i3); + lv3.SetPtEtaPhiM(0.0, 0.0, 0.0, 0.0); + lv1.SetPtEtaPhiM(track1.pt(), track1.eta(), track1.phi(), massKa); + lv2.SetPtEtaPhiM(track2.pt(), track2.eta(), track2.phi(), massPi); + lv3 = lv1 + lv2; + isMix = false; + fillInvMass(track1, track2, lv2, lv3, multiplicity, isMix); + } + } - // openingangle = TMath::Abs((PionPx.at(i3) * KaonPx.at(i1) + PionPy.at(i3) * KaonPy.at(i1) + PionPz.at(i3) * KaonPz.at(i1)) / (PionP.at(i3) * KaonP.at(i1))); + PROCESS_SWITCH(Kstarqa, processSE, "Process Same event", true); - // openingangle = (PionPx.at(i3)*KaonPx.at(i1) + PionPy.at(i3)*KaonPy.at(i1) + PionPz.at(i3)*KaonPz.at(i1)); - // LOG(info) << "opening angle" << openingangle; + ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for ME mixing"}; + // ConfigurableAxis axisMultiplicityClass{"axisMultiplicityClass", {10, 0, 100}, "multiplicity percentile for ME mixing"}; + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {2000, 0, 10000}, "TPC multiplicity axis for ME mixing"}; - if (TMath::Abs(CKSVector.Rapidity()) < 0.5) { - if (PionSign.at(i3) * KaonSign.at(i1) < 0) - histos.fill(HIST("h3KstarInvMassUnlikeSign"), multiplicity, CKSVector.Pt(), CKSVector.M()); - else if (PionSign.at(i3) * KaonSign.at(i1) > 0) - histos.fill(HIST("h3KstarInvMasslikeSign"), multiplicity, CKSVector.Pt(), CKSVector.M()); - } - } - } - } - } - } + // using BinningTypeTPCMultiplicity = ColumnBinningPolicy; + // using BinningTypeCentralityM = ColumnBinningPolicy; + using BinningTypeVertexContributor = ColumnBinningPolicy; - PROCESS_SWITCH(kstarqa, processSE, "Process Same event", true); + BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicity}, true}; + // BinningTypeCentralityM binningOnCentrality{{axisVertex, axisMultiplicity}, true}; - void processME(EventCandidates const&, TrackCandidates const&) + SameKindPair pair1{binningOnPositions, cfgNoMixedEvents, -1, &cache}; + // SameKindPair pair2{binningOnCentrality, cfgNoMixedEvents, -1, &cache}; + void processME(EventCandidates const&, TrackCandidates const&) { - - for (auto& [c1, tracks1, c2, tracks2] : pair) { + for (const auto& [c1, tracks1, c2, tracks2] : pair1) { if (!c1.sel8()) { continue; @@ -542,270 +686,321 @@ struct kstarqa { continue; } - if (timFrameEvsel && (!c1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !c2.selection_bit(aod::evsel::kNoTimeFrameBorder))) { + if (timFrameEvsel && (!c1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !c2.selection_bit(aod::evsel::kNoTimeFrameBorder) || !c1.selection_bit(aod::evsel::kNoITSROFrameBorder) || !c2.selection_bit(aod::evsel::kNoITSROFrameBorder))) { continue; } - if (piluprejection && (!c1.selection_bit(o2::aod::evsel::kNoSameBunchPileup) || !c2.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { - return; - } - if (goodzvertex && (!c1.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV) || c2.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV))) { - return; - } - if (itstpctracks && (!c1.selection_bit(o2::aod::evsel::kIsVertexITSTPC) || c2.selection_bit(o2::aod::evsel::kIsVertexITSTPC))) { + if (cTVXEvsel && (!c1.selection_bit(aod::evsel::kIsTriggerTVX) || !c2.selection_bit(aod::evsel::kIsTriggerTVX))) { return; } - // float multiplicity = 0.0f; - /* if (cfgMultFT0) - multiplicity = c1.multZeqFT0A() + c1.multZeqFT0C(); - if (cfgMultFT0 == 0 && cfgCentFT0C == 1) - multiplicity = c1.centFT0C(); - if (cfgMultFT0 == 0 && cfgCentFT0C == 0)*/ - auto multiplicity = c1.centFT0M(); + multiplicity = c1.centFT0M(); - for (auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - if (!selectionTrack(t1)) + if (!selectionTrack(t1)) // Kaon continue; - if (!selectionTrack(t2)) + if (!selectionTrack(t2)) // Pion continue; - if (!selectionPID(t1, 1)) + if (!selectionPID(t1, 1)) // Kaon continue; - if (!selectionPID(t2, 0)) + if (!selectionPID(t2, 0)) // Pion continue; - if (MID) { - if (MIDselectionPID(t1, 0)) // misidentified as pion - continue; - if (MIDselectionPID(t1, 2)) // misidentified as proton - continue; - if (MIDselectionPID(t2, 1)) // misidentified as kaon - continue; - } - - TLorentzVector KAON; - KAON.SetPtEtaPhiM(t1.pt(), t1.eta(), t1.phi(), massKa); - TLorentzVector PION; - PION.SetPtEtaPhiM(t2.pt(), t2.eta(), t2.phi(), massPi); - totmompimix = TMath::Sqrt(t2.px() * t2.px() + t2.py() * t2.py() + t2.pz() * t2.pz()); - totmomkamix = TMath::Sqrt(t1.px() * t1.px() + t1.py() * t1.py() + t1.pz() * t1.pz()); + // if (cMID) { + // if (cMIDselectionPID(t1, 0)) // misidentified as pion + // continue; + // if (cMIDselectionPID(t1, 2)) // misidentified as proton + // continue; + // if (cMIDselectionPID(t2, 1)) // misidentified as kaon + // continue; + // } - // openinganglemix = TMath::Abs((t1.px() * t2.px() + t1.py() * t2.py() + t1.pz() * t2.pz()) / (totmomkamix * totmompimix)); + // TLorentzVector vKAON; + // vKAON.SetPtEtaPhiM(t1.pt(), t1.eta(), t1.phi(), massKa); + // TLorentzVector vPION; + // vPION.SetPtEtaPhiM(t2.pt(), t2.eta(), t2.phi(), massPi); + lv3.SetPtEtaPhiM(0.0, 0.0, 0.0, 0.0); + lv1.SetPtEtaPhiM(t1.pt(), t1.eta(), t1.phi(), massKa); + lv2.SetPtEtaPhiM(t2.pt(), t2.eta(), t2.phi(), massPi); - // LOG(info) << "mix angle" << openinganglemix; + // TLorentzVector kstar = vKAON + vPION; + lv3 = lv1 + lv2; + isMix = true; - TLorentzVector CKSmix = KAON + PION; + // if (std::abs(kstar.Rapidity()) < 0.5) { + // fillInvMass(t1, t2, vPION, kstar, multiplicity, isMix); - if (!QA) { - if (TMath::Abs(CKSmix.Rapidity()) < 0.5) { - if (t1.sign() * t2.sign() < 0) - histos.fill(HIST("h3KstarInvMassMixed"), multiplicity, CKSmix.Pt(), CKSmix.M()); - } + if (std::abs(lv3.Rapidity()) < 0.5) { + fillInvMass(t1, t2, lv2, lv3, multiplicity, isMix); } } } } - PROCESS_SWITCH(kstarqa, processME, "Process Mixed event", true); + PROCESS_SWITCH(Kstarqa, processME, "Process Mixed event", true); - void processGen(aod::McCollision const& mcCollision, aod::McParticles& mcParticles, const soa::SmallGroups& collisions) + void processGen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& collisions) { - histos.fill(HIST("events_check"), 0.5); + rEventSelection.fill(HIST("events_check"), 0.5); if (std::abs(mcCollision.posZ()) < cutzvertex) { - histos.fill(HIST("events_check"), 1.5); + rEventSelection.fill(HIST("events_check"), 1.5); + } + + int nChInel = 0; + for (const auto& mcParticle : mcParticles) { + auto pdgcode = std::abs(mcParticle.pdgCode()); + if (mcParticle.isPhysicalPrimary() && (pdgcode == 211 || pdgcode == 321 || pdgcode == 2212 || pdgcode == 11 || pdgcode == 13)) { + if (std::abs(mcParticle.eta()) < 1.0) { + nChInel = nChInel + 1; + } + } } - // int Nchinel = 0; - // for (auto& mcParticle : mcParticles) { - // auto pdgcode = std::abs(mcParticle.pdgCode()); - // if (mcParticle.isPhysicalPrimary() && (pdgcode == 211 || pdgcode == 321 || pdgcode == 2212 || pdgcode == 11 || pdgcode == 13)) { - // if (std::abs(mcParticle.eta()) < 1.0) { - // Nchinel = Nchinel + 1; - // } - // } - // } - // if (Nchinel > 0 && std::abs(mcCollision.posZ()) < cutzvertex) - // histos.fill(HIST("events_check"), 2.5); - std::vector SelectedEvents(collisions.size()); + if (nChInel > 0 && std::abs(mcCollision.posZ()) < cutzvertex) + rEventSelection.fill(HIST("events_check"), 2.5); + + std::vector selectedEvents(collisions.size()); int nevts = 0; + + multiplicity = 0; for (const auto& collision : collisions) { - if (!collision.sel8() || std::abs(collision.mcCollision().posZ()) > cutzvertex) { - continue; - } - if (timFrameEvsel && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + // if (!collision.sel8() || std::abs(collision.mcCollision().posZ()) > cutzvertex) { + if (std::abs(collision.mcCollision().posZ()) > cutzvertex) { continue; } - if (piluprejection && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { - continue; - } - if (goodzvertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + if (timFrameEvsel && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { continue; } - if (itstpctracks && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + if (cTVXEvsel && (!collision.selection_bit(aod::evsel::kIsTriggerTVX))) { continue; } - SelectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); + multiplicity = collision.centFT0M(); + selectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); } + selectedEvents.resize(nevts); + rEventSelection.fill(HIST("events_check"), 3.5); + + const auto evtReconstructedAndSelected = std::find(selectedEvents.begin(), selectedEvents.end(), mcCollision.globalIndex()) != selectedEvents.end(); - // SelectedEvents.resize(nevts); - const auto evtReconstructedAndSelected = std::find(SelectedEvents.begin(), SelectedEvents.end(), mcCollision.globalIndex()) != SelectedEvents.end(); - histos.fill(HIST("events_check"), 3.5); - if (!evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection + if (!cAllGenCollisions && !evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection return; } - histos.fill(HIST("events_check"), 4.5); - for (auto& mcParticle : mcParticles) { + rEventSelection.fill(HIST("events_check"), 4.5); + + for (const auto& mcParticle : mcParticles) { if (std::abs(mcParticle.y()) >= 0.5) { continue; } - if (abs(mcParticle.pdgCode()) != 313) { + rEventSelection.fill(HIST("events_check"), 5.5); + + if (std::abs(mcParticle.pdgCode()) != 313) { continue; } + rEventSelection.fill(HIST("events_check"), 6.5); + auto kDaughters = mcParticle.daughters_as(); if (kDaughters.size() != 2) { continue; } + rEventSelection.fill(HIST("events_check"), 7.5); + auto passkaon = false; auto passpion = false; - for (auto kCurrentDaughter : kDaughters) { + for (const auto& kCurrentDaughter : kDaughters) { if (!kCurrentDaughter.isPhysicalPrimary()) { continue; } - if (abs(kCurrentDaughter.pdgCode()) == 321) { + rEventSelection.fill(HIST("events_check"), 8.5); + + if (std::abs(kCurrentDaughter.pdgCode()) == 321) { + // if (kCurrentDaughter.pdgCode() == +321) { passkaon = true; - } else if (abs(kCurrentDaughter.pdgCode()) == 211) { + rEventSelection.fill(HIST("events_check"), 9.5); + + } else if (std::abs(kCurrentDaughter.pdgCode()) == 211) { + //} else if (kCurrentDaughter.pdgCode() == -321) { passpion = true; + // rEventSelection.fill(HIST("events_check"), 10.5); } } if (passkaon && passpion) { // if (mcParticle.pdgCode() > 0) - histos.fill(HIST("k892Gen"), mcParticle.pt()); + hInvMass.fill(HIST("hk892GenpT"), mcParticle.pt(), multiplicity); // else - // histos.fill(HIST("k892GenAnti"), mcParticle.pt()); + // hInvMass.fill(HIST("hk892GenpTAnti"), mcParticle.pt()); } } } - PROCESS_SWITCH(kstarqa, processGen, "Process Generated", false); + PROCESS_SWITCH(Kstarqa, processGen, "Process Generated", false); void processRec(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const&, aod::McCollisions const& /*mcCollisions*/) { - TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; + // TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; + multiplicity = collision.centFT0M(); + + rEventSelection.fill(HIST("events_checkrec"), 0.5); if (!collision.has_mcCollision()) { return; } - if (std::abs(collision.mcCollision().posZ()) > cutzvertex || !collision.sel8()) { + rEventSelection.fill(HIST("events_checkrec"), 1.5); + + // if (std::abs(collision.mcCollision().posZ()) > cutzvertex || !collision.sel8()) { + if (std::abs(collision.mcCollision().posZ()) > cutzvertex) { return; } + rEventSelection.fill(HIST("events_checkrec"), 2.5); + if (timFrameEvsel && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { return; } + rEventSelection.fill(HIST("events_checkrec"), 3.5); - if (piluprejection && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { - return; - } - if (goodzvertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { - return; - } - if (itstpctracks && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + if (cTVXEvsel && (!collision.selection_bit(aod::evsel::kIsTriggerTVX))) { return; } + rEventSelection.fill(HIST("events_checkrec"), 4.5); - // histos.fill(HIST("events_check"), 5.5); - // auto oldindex = -999; - for (auto track1 : tracks) { + auto oldindex = -999; + for (const auto& track1 : tracks) { if (!selectionTrack(track1)) { continue; } + rEventSelection.fill(HIST("events_checkrec"), 5.5); + if (!track1.has_mcParticle()) { continue; } + rEventSelection.fill(HIST("events_checkrec"), 6.5); + auto track1ID = track1.index(); - for (auto track2 : tracks) { + for (const auto& track2 : tracks) { if (!track2.has_mcParticle()) { continue; } + rEventSelection.fill(HIST("events_checkrec"), 7.5); + if (!selectionTrack(track2)) { continue; } + rEventSelection.fill(HIST("events_checkrec"), 8.5); + auto track2ID = track2.index(); - if (track2ID == track1ID) { + if (track2ID <= track1ID) { continue; } - // if (!selectionPair(track1, track2)) { - // continue; - // } - if (track1.sign() * track2.sign() > 0) { + rEventSelection.fill(HIST("events_checkrec"), 9.5); + + if (track1.sign() * track2.sign() >= 0) { continue; } + rEventSelection.fill(HIST("events_checkrec"), 10.5); + const auto mctrack1 = track1.mcParticle(); const auto mctrack2 = track2.mcParticle(); int track1PDG = std::abs(mctrack1.pdgCode()); int track2PDG = std::abs(mctrack2.pdgCode()); + + if (cQAplots && track1PDG == 211) { + hPID.fill(HIST("h1PID_TPC_kaon_MC"), track1.tpcNSigmaKa()); + hPID.fill(HIST("h1PID_TOF_kaon_MC"), track1.tofNSigmaKa()); + } + if (cQAplots && track1PDG == 321) { + hPID.fill(HIST("h1PID_TPC_pion_MC"), track1.tpcNSigmaPi()); + hPID.fill(HIST("h1PID_TOF_pion_MC"), track1.tofNSigmaPi()); + } + if (!mctrack1.isPhysicalPrimary()) { continue; } + rEventSelection.fill(HIST("events_checkrec"), 11.5); + if (!mctrack2.isPhysicalPrimary()) { continue; } + rEventSelection.fill(HIST("events_checkrec"), 12.5); - if (!(selectionPID(track1, 0) && selectionPID(track2, 1))) { // pion and kaon + // if (!(track1PDG == 321 && track2PDG == 211)) { + // continue; + // } + if (!(track1PDG == 211) && !(track1PDG == 321)) { continue; } - if (!(track1PDG == 211 && track2PDG == 321)) { + if (!(track2PDG == 211) && !(track2PDG == 321)) { continue; } - for (auto& mothertrack1 : mctrack1.mothers_as()) { - for (auto& mothertrack2 : mctrack2.mothers_as()) { + rEventSelection.fill(HIST("events_checkrec"), 13.5); + + if (track1PDG == 211) { + if (!(selectionPID(track1, 0) && selectionPID(track2, 1))) { // pion and kaon + continue; + } + } else { + if (!(selectionPID(track1, 1) && selectionPID(track2, 0))) { // kaon and pion + continue; + } + } + rEventSelection.fill(HIST("events_checkrec"), 14.5); + + for (const auto& mothertrack1 : mctrack1.mothers_as()) { + for (const auto& mothertrack2 : mctrack2.mothers_as()) { if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) { continue; } + rEventSelection.fill(HIST("events_checkrec"), 15.5); + if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) { continue; } + rEventSelection.fill(HIST("events_checkrec"), 16.5); + if (!mothertrack1.producedByGenerator()) { continue; } + rEventSelection.fill(HIST("events_checkrec"), 17.5); + if (std::abs(mothertrack1.y()) >= 0.5) { continue; } + rEventSelection.fill(HIST("events_checkrec"), 18.5); + if (std::abs(mothertrack1.pdgCode()) != 313) { continue; } - // if (avoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { - // histos.fill(HIST("h1PhiRecsplit"), mothertrack1.pt()); - // continue; - // } - // oldindex = mothertrack1.globalIndex(); - pvec0 = array{track1.px(), track1.py(), track1.pz()}; - pvec1 = array{track2.px(), track2.py(), track2.pz()}; - auto arrMomrec = array{pvec0, pvec1}; + if (avoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { + hInvMass.fill(HIST("h1KSRecsplit"), mothertrack1.pt()); + continue; + } + oldindex = mothertrack1.globalIndex(); + pvec0 = std::array{track1.px(), track1.py(), track1.pz()}; + pvec1 = std::array{track2.px(), track2.py(), track2.pz()}; + auto arrMomrec = std::array{pvec0, pvec1}; auto motherP = mothertrack1.p(); auto motherE = mothertrack1.e(); auto genMass = std::sqrt(motherE * motherE - motherP * motherP); - auto recMass = RecoDecay::m(arrMomrec, array{massKa, massPi}); - // auto recpt = TMath::Sqrt((track1.px() + track2.px()) * (track1.px() + track2.px()) + (track1.py() + track2.py()) * (track1.py() + track2.py())); + auto recMass = RecoDecay::m(arrMomrec, std::array{massKa, massPi}); + auto recpt = std::sqrt((track1.px() + track2.px()) * (track1.px() + track2.px()) + (track1.py() + track2.py()) * (track1.py() + track2.py())); //// Resonance reconstruction - lDecayDaughter1.SetXYZM(track1.px(), track1.py(), track1.pz(), massPi); - lDecayDaughter2.SetXYZM(track2.px(), track2.py(), track2.pz(), massKa); - lResonance = lDecayDaughter1 + lDecayDaughter2; - histos.fill(HIST("h3KstarRec"), motherP); - histos.fill(HIST("h1KstarRecMass"), recMass); - // histos.fill(HIST("h1KstarRecpt"), recpt); - histos.fill(HIST("h1genmass"), genMass); - histos.fill(HIST("h1recpt"), lResonance.Pt()); + // lDecayDaughter1.SetXYZM(track1.px(), track1.py(), track1.pz(), massKa); + // lDecayDaughter2.SetXYZM(track2.px(), track2.py(), track2.pz(), massPi); + // lResonance = lDecayDaughter1 + lDecayDaughter2; + + hInvMass.fill(HIST("h1KstarRecMass"), recMass); + hInvMass.fill(HIST("h1genmass"), genMass); + hInvMass.fill(HIST("h2KstarRecpt1"), mothertrack1.pt(), multiplicity); + hInvMass.fill(HIST("h2KstarRecpt2"), recpt, multiplicity); } } } } } - PROCESS_SWITCH(kstarqa, processRec, "Process Reconstructed", false); + PROCESS_SWITCH(Kstarqa, processRec, "Process Reconstructed", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/Resonances/lambda1520SpherocityAnalysis.cxx b/PWGLF/Tasks/Resonances/lambda1520SpherocityAnalysis.cxx index bc671f2bc53..b8d6cfeae29 100644 --- a/PWGLF/Tasks/Resonances/lambda1520SpherocityAnalysis.cxx +++ b/PWGLF/Tasks/Resonances/lambda1520SpherocityAnalysis.cxx @@ -15,6 +15,7 @@ #include #include +#include #include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/Centrality.h" @@ -24,6 +25,7 @@ #include "Framework/runDataProcessing.h" #include "PWGLF/DataModel/LFResonanceTables.h" #include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/RecoDecay.h" using namespace o2; using namespace o2::framework; @@ -351,8 +353,58 @@ struct lambdaAnalysis { return true; } + template + void fillQAHistos(T const& track) + { + + // get total momentum + float p = RecoDecay::p(track.px(), track.py(), track.pz()); + + // fill before QA first + histos.fill(HIST("QAbefore/Proton/h2d_pr_nsigma_tpc_p"), p, track.tpcNSigmaPr()); + if (track.hasTOF()) { + histos.fill(HIST("QAbefore/Proton/h2d_pr_nsigma_tof_p"), p, track.tofNSigmaPr()); + histos.fill(HIST("QAbefore/Proton/h2d_pr_nsigma_tof_vs_tpc"), track.tpcNSigmaPr(), track.tofNSigmaPr()); + } + histos.fill(HIST("QAbefore/Kaon/h2d_ka_nsigma_tpc_p"), p, track.tpcNSigmaKa()); + if (track.hasTOF()) { + histos.fill(HIST("QAbefore/Kaon/h2d_ka_nsigma_tof_p"), p, track.tofNSigmaKa()); + histos.fill(HIST("QAbefore/Kaon/h2d_ka_nsigma_tof_vs_tpc"), track.tpcNSigmaKa(), track.tofNSigmaKa()); + } + + // select particle (Proton/Kaon) + // Proton + if (selectionPIDProton(track, p)) { + histos.fill(HIST("QAChecks/h1d_ka_pt"), track.pt()); + histos.fill(HIST("QAafter/Proton/h2d_pr_dca_z"), track.pt(), track.dcaZ()); + histos.fill(HIST("QAafter/Proton/h2d_pr_dca_xy"), track.pt(), track.dcaXY()); + histos.fill(HIST("QAafter/Proton/h2d_pr_dEdx_p"), p, track.tpcSignal()); + histos.fill(HIST("QAafter/Proton/h2d_pr_nsigma_tpc_p"), p, track.tpcNSigmaPr()); + histos.fill(HIST("QAafter/Proton/h2d_pr_nsigma_tpc_pt"), track.pt(), track.tpcNSigmaPr()); + if (!cUseTpcOnly && track.hasTOF()) { + histos.fill(HIST("QAafter/Proton/h2d_pr_nsigma_tof_p"), p, track.tofNSigmaPr()); + histos.fill(HIST("QAafter/Proton/h2d_pr_nsigma_tof_pt"), track.pt(), track.tofNSigmaPr()); + histos.fill(HIST("QAafter/Proton/h2d_pr_nsigma_tof_vs_tpc"), track.tpcNSigmaPr(), track.tofNSigmaPr()); + } + } + // Kaon + if (selectionPIDKaon(track, p)) { + histos.fill(HIST("QAChecks/h1d_ka_pt"), track.pt()); + histos.fill(HIST("QAafter/Kaon/h2d_ka_dca_z"), track.pt(), track.dcaZ()); + histos.fill(HIST("QAafter/Kaon/h2d_ka_dca_xy"), track.pt(), track.dcaXY()); + histos.fill(HIST("QAafter/Kaon/h2d_ka_dEdx_p"), p, track.tpcSignal()); + histos.fill(HIST("QAafter/Kaon/h2d_ka_nsigma_tpc_p"), p, track.tpcNSigmaKa()); + histos.fill(HIST("QAafter/Kaon/h2d_ka_nsigma_tpc_pt"), track.pt(), track.tpcNSigmaKa()); + if (!cUseTpcOnly && track.hasTOF()) { + histos.fill(HIST("QAafter/Kaon/h2d_ka_nsigma_tof_p"), p, track.tofNSigmaKa()); + histos.fill(HIST("QAafter/Kaon/h2d_ka_nsigma_tof_pt"), track.pt(), track.tofNSigmaKa()); + histos.fill(HIST("QAafter/Kaon/h2d_ka_nsigma_tof_vs_tpc"), track.tpcNSigmaKa(), track.tofNSigmaKa()); + } + } + } + template - void fillDataHistos(trackType const& trk1, trackType const& trk2, float const& sph, float const& mult) + void fillInvMassHistos(trackType const& trk1, trackType const& trk2, float const& sph, float const& mult) { TLorentzVector p1, p2, p; TRandom* rn = new TRandom(); @@ -367,22 +419,8 @@ struct lambdaAnalysis { if (!selTracks(trkPr) || !selTracks(trkKa)) continue; - p_ptot = TMath::Sqrt(trkPr.px() * trkPr.px() + trkPr.py() * trkPr.py() + trkPr.pz() * trkPr.pz()); - k_ptot = TMath::Sqrt(trkKa.px() * trkKa.px() + trkKa.py() * trkKa.py() + trkKa.pz() * trkKa.pz()); - - // Fill QA before track selection. - if (!mix) { - histos.fill(HIST("QAbefore/Proton/h2d_pr_nsigma_tpc_p"), p_ptot, trkPr.tpcNSigmaPr()); - if (trkPr.hasTOF()) { - histos.fill(HIST("QAbefore/Proton/h2d_pr_nsigma_tof_p"), p_ptot, trkPr.tofNSigmaPr()); - histos.fill(HIST("QAbefore/Proton/h2d_pr_nsigma_tof_vs_tpc"), trkPr.tpcNSigmaPr(), trkPr.tofNSigmaPr()); - } - histos.fill(HIST("QAbefore/Kaon/h2d_ka_nsigma_tpc_p"), k_ptot, trkKa.tpcNSigmaKa()); - if (trkKa.hasTOF()) { - histos.fill(HIST("QAbefore/Kaon/h2d_ka_nsigma_tof_p"), k_ptot, trkKa.tofNSigmaKa()); - histos.fill(HIST("QAbefore/Kaon/h2d_ka_nsigma_tof_vs_tpc"), trkKa.tpcNSigmaKa(), trkKa.tofNSigmaKa()); - } - } + p_ptot = RecoDecay::p(trkPr.px(), trkPr.py(), trkPr.pz()); + k_ptot = RecoDecay::p(trkKa.px(), trkKa.py(), trkKa.pz()); // Apply PID Selection if (cUseOnlyTOFTrackPr && !trkPr.hasTOF()) @@ -392,37 +430,12 @@ struct lambdaAnalysis { if (!selectionPIDProton(trkPr, p_ptot) || !selectionPIDKaon(trkKa, k_ptot)) continue; - // Fill QA after track selection. - if constexpr (!mix) { - // Proton - histos.fill(HIST("QAafter/Proton/h2d_pr_dca_z"), trkPr.pt(), trkPr.dcaZ()); - histos.fill(HIST("QAafter/Proton/h2d_pr_dca_xy"), trkPr.pt(), trkPr.dcaXY()); - histos.fill(HIST("QAafter/Proton/h2d_pr_dEdx_p"), p_ptot, trkPr.tpcSignal()); - histos.fill(HIST("QAafter/Proton/h2d_pr_nsigma_tpc_p"), p_ptot, trkPr.tpcNSigmaPr()); - histos.fill(HIST("QAafter/Proton/h2d_pr_nsigma_tpc_pt"), trkPr.pt(), trkPr.tpcNSigmaPr()); - if (!cUseTpcOnly && trkPr.hasTOF()) { - histos.fill(HIST("QAafter/Proton/h2d_pr_nsigma_tof_p"), p_ptot, trkPr.tofNSigmaPr()); - histos.fill(HIST("QAafter/Proton/h2d_pr_nsigma_tof_pt"), trkPr.pt(), trkPr.tofNSigmaPr()); - histos.fill(HIST("QAafter/Proton/h2d_pr_nsigma_tof_vs_tpc"), trkPr.tpcNSigmaPr(), trkPr.tofNSigmaPr()); - } - // Kaon - histos.fill(HIST("QAafter/Kaon/h2d_ka_dca_z"), trkKa.pt(), trkKa.dcaZ()); - histos.fill(HIST("QAafter/Kaon/h2d_ka_dca_xy"), trkKa.pt(), trkKa.dcaXY()); - histos.fill(HIST("QAafter/Kaon/h2d_ka_dEdx_p"), k_ptot, trkKa.tpcSignal()); - histos.fill(HIST("QAafter/Kaon/h2d_ka_nsigma_tpc_p"), k_ptot, trkKa.tpcNSigmaKa()); - histos.fill(HIST("QAafter/Kaon/h2d_ka_nsigma_tpc_pt"), trkKa.pt(), trkKa.tpcNSigmaKa()); - if (!cUseTpcOnly && trkKa.hasTOF()) { - histos.fill(HIST("QAafter/Kaon/h2d_ka_nsigma_tof_p"), k_ptot, trkKa.tofNSigmaKa()); - histos.fill(HIST("QAafter/Kaon/h2d_ka_nsigma_tof_pt"), trkKa.pt(), trkKa.tofNSigmaKa()); - histos.fill(HIST("QAafter/Kaon/h2d_ka_nsigma_tof_vs_tpc"), trkKa.tpcNSigmaKa(), trkKa.tofNSigmaKa()); - } - } - // Invariant mass reconstruction. p1.SetXYZM(trkPr.px(), trkPr.py(), trkPr.pz(), MassProton); p2.SetXYZM(trkKa.px(), trkKa.py(), trkKa.pz(), MassKaonCharged); p = p1 + p2; + // rapidity cut if (std::abs(p.Rapidity()) > 0.5) continue; @@ -448,7 +461,7 @@ struct lambdaAnalysis { histos.fill(HIST("Analysis/h1d_lstar_invm_US"), p.M()); histos.fill(HIST("Analysis/h4d_lstar_invm_US"), p.M(), p.Pt(), sph, mult); if (doRotate) { - float theta = rn->Uniform(1.56, 1.58); + float theta = rn->Uniform(0.01, 0.1); p1.RotateZ(theta); p = p1 + p2; if (std::abs(p.Rapidity()) < 0.5) { @@ -488,7 +501,7 @@ struct lambdaAnalysis { if (trkPr.motherId() != trkKa.motherId()) continue; - if (std::abs(trkPr.motherPDG()) != 3124) // L* pdg_code = 3124 + if (std::abs(trkPr.motherPDG()) != 102134) // L* pdg_code = 102134 continue; // MC histograms @@ -503,7 +516,7 @@ struct lambdaAnalysis { } } - using resoCols = aod::ResoCollisions; + using resoCols = soa::Join; using resoTracks = aod::ResoTracks; void processData(resoCols::iterator const& collision, resoTracks const& tracks) @@ -513,23 +526,16 @@ struct lambdaAnalysis { histos.fill(HIST("Event/h1d_spherocity"), collision.spherocity()); histos.fill(HIST("Event/h2d_sph_vs_multpercentile"), collision.cent(), collision.spherocity()); - fillDataHistos(tracks, tracks, collision.spherocity(), collision.cent()); - - // get proton and kaon pT-spectra for (auto const& track : tracks) { if (!selTracks(track)) continue; - float p = TMath::Sqrt(track.px() * track.px() + track.py() * track.py() + track.pz() * track.pz()); - - if (selectionPIDKaon(track, p)) { - histos.fill(HIST("QAChecks/h1d_ka_pt"), track.pt()); - } - - if (selectionPIDProton(track, p)) { - histos.fill(HIST("QAChecks/h1d_pr_pt"), track.pt()); - } + // QA histos + fillQAHistos(track); } + + // get invariant mass histograms + fillInvMassHistos(tracks, tracks, collision.spherocity(), collision.cent()); } PROCESS_SWITCH(lambdaAnalysis, processData, "Process for Same Event Data", true); @@ -538,7 +544,6 @@ struct lambdaAnalysis { soa::Join const& tracks) { histos.fill(HIST("Event/h1d_rec_sph"), collision.spherocity()); - fillDataHistos(tracks, tracks, collision.spherocity(), collision.cent()); // get MC reco pT-spectra for (auto const& track : tracks) { @@ -547,6 +552,9 @@ struct lambdaAnalysis { if (!selTracks(track)) continue; + // QA histos + fillQAHistos(track); + float p = TMath::Sqrt(track.px() * track.px() + track.py() * track.py() + track.pz() * track.pz()); if (selectionPIDKaon(track, p) && std::abs(track.pdgCode()) == 321) { @@ -557,6 +565,9 @@ struct lambdaAnalysis { histos.fill(HIST("QAChecks/h1d_pr_rec_pt"), track.pt()); } } + + // get invariant mass histograms + fillInvMassHistos(tracks, tracks, collision.spherocity(), collision.cent()); } PROCESS_SWITCH(lambdaAnalysis, processMC, "Process Event for MC", false); @@ -595,7 +606,7 @@ struct lambdaAnalysis { for (auto const& part : resoParents) { - if (abs(part.pdgCode()) != 3124) // // L* pdg_code = 3124 + if (abs(part.pdgCode()) != 102134) // // L* pdg_code = 102134 continue; if (abs(part.y()) > 0.5) { // rapidity cut continue; @@ -635,12 +646,12 @@ struct lambdaAnalysis { if (cMixSph) { SameKindPair pairs{binningPositions1, cNumMixEv, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip for (auto& [c1, t1, c2, t2] : pairs) { - fillDataHistos(t1, t2, c1.spherocity(), c1.cent()); + fillInvMassHistos(t1, t2, c1.spherocity(), c1.cent()); } } else { SameKindPair pairs{binningPositions2, cNumMixEv, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip for (auto& [c1, t1, c2, t2] : pairs) { - fillDataHistos(t1, t2, c1.spherocity(), c1.cent()); + fillInvMassHistos(t1, t2, c1.spherocity(), c1.cent()); } } } diff --git a/PWGLF/Tasks/Resonances/lambda1520_PbPb.cxx b/PWGLF/Tasks/Resonances/lambda1520_PbPb.cxx index 2f959dc9b8f..d032d0c90aa 100644 --- a/PWGLF/Tasks/Resonances/lambda1520_PbPb.cxx +++ b/PWGLF/Tasks/Resonances/lambda1520_PbPb.cxx @@ -13,13 +13,15 @@ /// /// Invariant Mass Reconstruction of Lambda(1520) Resonance. /// /// \author Yash Patley -/// \author Nasir Mehdi Malik +/// \author Nasir Mehdi Malik #include #include #include +#include #include #include +#include #include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/Centrality.h" @@ -28,7 +30,6 @@ #include "Framework/ASoAHelpers.h" #include "Framework/runDataProcessing.h" #include "PWGLF/DataModel/LFResonanceTables.h" -#include "PWGLF/DataModel/LFResonanceTablesMergeDF.h" #include "CommonConstants/PhysicsConstants.h" using namespace o2; @@ -41,6 +42,8 @@ struct lambdaAnalysis_pb { Preslice perRCol = aod::resodaughter::resoCollisionId; Preslice perCollision = aod::track::collisionId; // Configurables. + + Configurable ConfEvtOccupancyInTimeRange{"ConfEvtOccupancyInTimeRange", false, "occupancy selection true or false"}; Configurable nBinsPt{"nBinsPt", 100, "N bins in pT histogram"}; Configurable nBinsInvM{"nBinsInvM", 120, "N bins in InvMass histogram"}; Configurable lambda1520id{"lambda1520id", 3124, "pdg"}; @@ -52,6 +55,7 @@ struct lambdaAnalysis_pb { Configurable cEtaCut{"cEtaCut", 0.8, "Pseudorapidity cut"}; Configurable cDcaz{"cDcazMin", 1., "Minimum DCAz"}; Configurable cDcaxy{"cDcaxyMin", 0.1, "Minimum DCAxy"}; + Configurable isonlyQC{"isonlyQC", false, "only QC"}; Configurable isDeepAngle{"isDeepAngle", false, "Deep Angle cut"}; Configurable cfgDeepAngle{"cfgDeepAngle", 0.04, "Deep Angle cut value"}; Configurable cKinCuts{"cKinCuts", false, "Kinematic Cuts for p-K pair opening angle"}; @@ -64,7 +68,20 @@ struct lambdaAnalysis_pb { Configurable cUseOnlyTOFTrackKa{"cUseOnlyTOFTrackKa", false, "Use only TOF track for PID selection"}; // Use only TOF track for Kaon PID selection Configurable cUseTpcOnly{"cUseTpcOnly", false, "Use TPC Only selection"}; // TPC And TOF tracks Configurable cRejNsigmaTpc{"cRejNsigmaTpc", 3.0, "Reject tracks to improve purity of TPC PID"}; // Reject missidentified particles when tpc bands merge - Configurable cRejNsigmaTof{"cRejNsigmaTof", 3.0, "Reject tracks to improve purity of TOF PID"}; // Reject missidentified particles when tpc bands merge + Configurable cRejNsigmaTpcPi{"cRejNsigmaTpcPi", 3.0, "Reject tracks to improve purity of TPC PID"}; // TPC And TOF tracks + // Configurable cRejNsigmaTpcPr{"cRejNsigmaTpcPr", 3.0, "Reject tracks to improve purity of TPC PID"}; + Configurable cRejNsigmaTpcKa{"cRejNsigmaTpcKa", 3.0, "Reject tracks to improve purity of TPC PID"}; + Configurable cRejNsigmakTpcPi{"cRejNsigmakTpcPi", 3.0, "Reject tracks to improve purity of TPC PID"}; + Configurable cRejNsigmakTpcPr{"cRejNsigmakTpcPr", 3.0, "Reject tracks to improve purity of TPC PID"}; + Configurable minnsigmatpcKa{"minnsigmatpcKa", -6.0, "Reject tracks to improve purity of TPC PID"}; + Configurable minnsigmatpcPr{"minnsigmatpcPr", -6.0, "Reject tracks to improve purity of TPC PID"}; + Configurable minnsigmatofKa{"minnsigmatofKa", -6.0, "Reject tracks to improve purity of TofPID"}; + Configurable minnsigmatofPr{"minnsigmatofPr", -6.0, "Reject tracks to improve purity of Tof PID"}; + Configurable minnsigmatpctofKa{"minnsigmatpctofKa", -6.0, "Reject tracks to improve purity of TPC PID"}; + Configurable minnsigmatpctofPr{"minnsigmatpctofPr", -6.0, "Reject tracks to improve purity of TPC PID"}; + // Configurable cRejNsigmaTpcPr{"cRejNsigmaTpcPr", 3.0, "Reject tracks to improve purity of TPC PID"}; + Configurable cRejNsigmaTpcVeto{"cRejNsigmaTpcVeto", 3.0, "Reject tracks to improve purity of TPC PID"}; // Reject missidentified particles when tpc bands merge + Configurable cRejNsigmaTof{"cRejNsigmaTof", 3.0, "Reject tracks to improve purity of TOF PID"}; // Reject missidentified particles when tpc bands merge // Proton Configurable cMaxTPCnSigmaProton{"cMaxTPCnSigmaProton", 3.0, "TPC nSigma cut for Proton"}; // TPC // Configurable cMaxTOFnSigmaProton{"cMaxTOFnSigmaProton", 3.0, "TOF nSigma cut for Proton"}; // TOF @@ -87,7 +104,7 @@ struct lambdaAnalysis_pb { ConfigurableAxis cMixVtxBins{"cMixVtxBins", {VARIABLE_WIDTH, -10.0f, -9.f, -8.f, -7.f, -6.f, -5.f, -4.f, -3.f, -2.f, -1.f, 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f}, "Mixing bins - z-vertex"}; ConfigurableAxis cMixMultBins{"cMixMultBins", {VARIABLE_WIDTH, 0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 200.0f}, "Mixing bins - multiplicity"}; ConfigurableAxis cMixEPAngle{"cMixEPAngle", {VARIABLE_WIDTH, -1.5708f, -1.25664f, -0.942478f, -0.628319f, 0.f, 0.628319f, 0.942478f, 1.25664f, 1.5708f}, "event plane"}; - + ConfigurableAxis occupancy_bins{"occupancy_bins", {VARIABLE_WIDTH, 0.0, 100, 500, 600, 1000, 1100, 1500, 1600, 2000, 2100, 2500, 2600, 3000, 3100, 3500, 3600, 4000, 4100, 4500, 4600, 5000, 5100, 9999}, "Binning of the occupancy axis"}; // Histogram Registry. HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -105,11 +122,13 @@ struct lambdaAnalysis_pb { const AxisSpec axisTOFNsigma(401, -10.025, 10.025, {"n#sigma^{TOF}"}); const AxisSpec axisdEdx(380, 10, 200, {"#frac{dE}{dx}"}); const AxisSpec axisVz(120, -12, 12, {"vz"}); + const AxisSpec axisEP(120, -3.14, 3.14, {"#theta"}); const AxisSpec axisInvM(nBinsInvM, 1.44, 2.04, {"M_{inv} (GeV/c^{2})"}); + AxisSpec axisOccupancy = {occupancy_bins, "Occupancy [-40,100]"}; - histos.add("Event/h1d_ft0_mult_percentile", "FT0 (%)", kTH1F, {axisCent}); + histos.add("Event/h1d_ft0_mult_percentile", "FT0 (%)", kTH2F, {axisCent, axisOccupancy}); if (doprocessMix || doprocessMixDF || doprocessMixepDF) { - histos.add("Event/mixing_vzVsmultpercentile", "FT0(%)", kTH2F, {axisCent, axisVz}); + histos.add("Event/mixing_vzVsmultpercentile", "FT0(%)", kTH3F, {axisCent, axisVz, axisEP}); } // QA Before histos.add("QAbefore/Proton/h2d_pr_nsigma_tpc_p", "n#sigma^{TPC} Protons", kTH2F, {axisP_pid, axisTPCNsigma}); @@ -120,7 +139,7 @@ struct lambdaAnalysis_pb { histos.add("QAbefore/Kaon/h2d_ka_nsigma_tof_vs_tpc", "n#sigma^{TPC} vs n#sigma^{TOF} Kaons", kTH2F, {axisTPCNsigma, axisTOFNsigma}); // QA After - histos.add("QAafter/Proton/h1d_pr_pt", "p_{T}-spectra Protons", kTH1F, {axisPt_pid}); + histos.add("QAafter/Proton/hd_pr_pt", "p_{T}-spectra Protons", kTH2F, {axisPt_pid, axisCent}); histos.add("QAafter/Proton/h2d_pr_dca_z", "dca_{z} Protons", kTH2F, {axisPt_pid, axisDCAz}); histos.add("QAafter/Proton/h2d_pr_dca_xy", "dca_{xy} Protons", kTH2F, {axisPt_pid, axisDCAxy}); histos.add("QAafter/Proton/h2d_pr_dEdx_p", "TPC Signal Protons", kTH2F, {axisP_pid, axisdEdx}); @@ -133,7 +152,7 @@ struct lambdaAnalysis_pb { histos.add("QAafter/Proton/h2d_Prpi_nsigma_tof_p", " Protons pion", kTH2F, {axisP_pid, axisTOFNsigma}); histos.add("QAafter/Proton/h2d_Prka_nsigma_tof_p", " Protons kaon", kTH2F, {axisP_pid, axisTOFNsigma}); histos.add("QAafter/Proton/h2d_pr_nsigma_tof_vs_tpc", "n#sigma(TOF) vs n#sigma(TPC) Protons", kTH2F, {axisTPCNsigma, axisTOFNsigma}); - histos.add("QAafter/Kaon/h1d_ka_pt", "p_{T}-spectra Kaons", kTH1F, {axisPt_pid}); + histos.add("QAafter/Kaon/hd_ka_pt", "p_{T}-spectra Kaons", kTH2F, {axisPt_pid, axisCent}); histos.add("QAafter/Kaon/h2d_ka_dca_z", "dca_{z} Kaons", kTH2F, {axisPt_pid, axisDCAz}); histos.add("QAafter/Kaon/h2d_ka_dca_xy", "dca_{xy} Kaons", kTH2F, {axisPt_pid, axisDCAxy}); histos.add("QAafter/Kaon/h2d_ka_dEdx_p", "TPC Signal Kaon", kTH2F, {axisP_pid, axisdEdx}); @@ -147,22 +166,18 @@ struct lambdaAnalysis_pb { histos.add("QAafter/Kaon/h2d_Kapr_nsigma_tof_p", " Kaons proton", kTH2F, {axisP_pid, axisTOFNsigma}); histos.add("QAafter/Kaon/h2d_ka_nsigma_tof_vs_tpc", "n#sigma(TOF) vs n#sigma(TPC) Kaons", kTH2F, {axisTPCNsigma, axisTOFNsigma}); - // QA checks for protons and kaons - histos.add("QAChecks/h1d_pr_pt", "p_{T}-spectra Protons", kTH1F, {axisPt_pid}); - histos.add("QAChecks/h1d_ka_pt", "p_{T}-spectra Kaons", kTH1F, {axisPt_pid}); - // Analysis // Lambda Invariant Mass if (!doprocessMC) { - histos.add("Analysis/h4d_lstar_invm_US_PM", "THn #Lambda(1520)", kTHnSparseF, {axisInvM, axisPt, axisCent}); - histos.add("Analysis/h4d_lstar_invm_US_MP", "THn #bar #Lambda(1520)", kTHnSparseF, {axisInvM, axisPt, axisCent}); - histos.add("Analysis/h4d_lstar_invm_PP", "THn Like Signs p K^{+}", kTHnSparseF, {axisInvM, axisPt, axisCent}); - histos.add("Analysis/h4d_lstar_invm_MM", "THn Like Signs #bar{p} K^{-}", kTHnSparseF, {axisInvM, axisPt, axisCent}); - histos.add("Analysis/h4d_lstar_invm_rot", "THn Rotated", kTHnSparseF, {axisInvM, axisPt, axisCent}); - histos.add("Analysis/h4d_lstar_invm_US_PM_mix", "THn Mixed Events", kTHnSparseF, {axisInvM, axisPt, axisCent}); - histos.add("Analysis/h4d_lstar_invm_US_MP_mix", "THn anti Mixed Events", kTHnSparseF, {axisInvM, axisPt, axisCent}); - histos.add("Analysis/h4d_lstar_invm_LS_PP_mix", "THn Mixed Events PP", kTHnSparseF, {axisInvM, axisPt, axisCent}); - histos.add("Analysis/h4d_lstar_invm_LS_MM_mix", "THn Mixed Events MM", kTHnSparseF, {axisInvM, axisPt, axisCent}); + histos.add("Analysis/h4d_lstar_invm_US_PM", "THn #Lambda(1520)", kTHnSparseF, {axisInvM, axisPt, axisCent, axisOccupancy}); + histos.add("Analysis/h4d_lstar_invm_US_MP", "THn #bar #Lambda(1520)", kTHnSparseF, {axisInvM, axisPt, axisCent, axisOccupancy}); + histos.add("Analysis/h4d_lstar_invm_PP", "THn Like Signs p K^{+}", kTHnSparseF, {axisInvM, axisPt, axisCent, axisOccupancy}); + histos.add("Analysis/h4d_lstar_invm_MM", "THn Like Signs #bar{p} K^{-}", kTHnSparseF, {axisInvM, axisPt, axisCent, axisOccupancy}); + histos.add("Analysis/h4d_lstar_invm_rot", "THn Rotated", kTHnSparseF, {axisInvM, axisPt, axisCent, axisOccupancy}); + histos.add("Analysis/h4d_lstar_invm_US_PM_mix", "THn Mixed Events", kTHnSparseF, {axisInvM, axisPt, axisCent, axisOccupancy}); + histos.add("Analysis/h4d_lstar_invm_US_MP_mix", "THn anti Mixed Events", kTHnSparseF, {axisInvM, axisPt, axisCent, axisOccupancy}); + histos.add("Analysis/h4d_lstar_invm_LS_PP_mix", "THn Mixed Events PP", kTHnSparseF, {axisInvM, axisPt, axisCent, axisOccupancy}); + histos.add("Analysis/h4d_lstar_invm_LS_MM_mix", "THn Mixed Events MM", kTHnSparseF, {axisInvM, axisPt, axisCent, axisOccupancy}); } // MC if (doprocessMC) { @@ -232,12 +247,17 @@ struct lambdaAnalysis_pb { float combinedRejCut = cRejNsigmaTof * cRejNsigmaTpc; if (!cUseTpcOnly && candidate.hasTOF()) { + if (candidate.tofNSigmaPr() < minnsigmatofPr) + return false; if (nsigmaCutCombinedProton < 0 && p >= cPMin) { + for (int i = 0; i < nitrtof - 1; ++i) { if (p >= tofPIDp[i] && p < tofPIDp[i + 1] && (tofNsigmaPr < tofPIDcut[i] && tofNsigmaPi > cRejNsigmaTof && tofNsigmaKa > cRejNsigmaTof)) tofPIDPassed = true; } - if (tpcNsigmaPr < cMaxTPCnSigmaProton) + if (candidate.tpcNSigmaPr() < minnsigmatpctofPr) + return false; + if (tpcNsigmaPr < cMaxTPCnSigmaProton && tpcNsigmaPi > cRejNsigmaTpcVeto && tpcNsigmaKa > cRejNsigmaTpcVeto) tpcPIDPassed = true; } @@ -254,8 +274,10 @@ struct lambdaAnalysis_pb { } } else { tofPIDPassed = true; + if (candidate.tpcNSigmaPr() < minnsigmatpcPr) + return false; for (int i = 0; i < nitr - 1; ++i) { - if (p >= tpcPIDp[i] && p < tpcPIDp[i + 1] && (tpcNsigmaPr < tpcPIDcut[i] && tpcNsigmaPi > cRejNsigmaTpc && tpcNsigmaKa > cRejNsigmaTpc)) { + if (p >= tpcPIDp[i] && p < tpcPIDp[i + 1] && (tpcNsigmaPr < tpcPIDcut[i] && tpcNsigmaPi > cRejNsigmaTpcPi && tpcNsigmaKa > cRejNsigmaTpcKa)) { tpcPIDPassed = true; } } @@ -282,7 +304,6 @@ struct lambdaAnalysis_pb { float tofNsigmaPi = std::abs(candidate.tofNSigmaPi()); float tofNsigmaKa = std::abs(candidate.tofNSigmaKa()); float tofNsigmaPr = std::abs(candidate.tofNSigmaPr()); - // float tofNsigmaEl = std::abs(); float tpcTofNsigmaPi = tpcNsigmaPi * tpcNsigmaPi + tofNsigmaPi * tofNsigmaPi; float tpcTofNsigmaKa = tpcNsigmaKa * tpcNsigmaKa + tofNsigmaKa * tofNsigmaKa; @@ -291,12 +312,17 @@ struct lambdaAnalysis_pb { float combinedRejCut = cRejNsigmaTpc * cRejNsigmaTof; if (!cUseTpcOnly && candidate.hasTOF()) { + if (candidate.tofNSigmaKa() < minnsigmatofKa) + return false; if (nsigmaCutCombinedKaon < 0 && p >= cPMin) { + for (int i = 0; i < nitrtof - 1; ++i) { if (p >= tofPIDp[i] && p < tofPIDp[i + 1] && (tofNsigmaKa < tofPIDcut[i] && tofNsigmaPi > cRejNsigmaTof && tofNsigmaPr > cRejNsigmaTof)) tofPIDPassed = true; } - if (tpcNsigmaKa < cMaxTPCnSigmaKaon) + if (candidate.tpcNSigmaKa() < minnsigmatpctofKa) + return false; + if (tpcNsigmaKa < cMaxTPCnSigmaKaon && tpcNsigmaPi > cRejNsigmaTpcVeto && tpcNsigmaPr > cRejNsigmaTpcVeto) tpcPIDPassed = true; } @@ -314,8 +340,10 @@ struct lambdaAnalysis_pb { } else { tofPIDPassed = true; + if (candidate.tpcNSigmaKa() < minnsigmatpcKa) + return false; for (int i = 0; i < nitr - 1; ++i) { - if (p >= tpcPIDp[i] && p < tpcPIDp[i + 1] && (tpcNsigmaKa < tpcPIDcut[i] && tpcNsigmaPi > cRejNsigmaTpc && tpcNsigmaPr > cRejNsigmaTpc)) { + if (p >= tpcPIDp[i] && p < tpcPIDp[i + 1] && (tpcNsigmaKa < tpcPIDcut[i] && tpcNsigmaPi > cRejNsigmakTpcPi && tpcNsigmaPr > cRejNsigmakTpcPr)) { tpcPIDPassed = true; } } @@ -327,7 +355,7 @@ struct lambdaAnalysis_pb { } template - void fillDataHistos(trackType const& trk1, trackType const& trk2, float const& mult) + void fillDataHistos(trackType const& trk1, trackType const& trk2, float mult, int occup = 100) { TLorentzVector p1, p2, p; @@ -359,7 +387,6 @@ struct lambdaAnalysis_pb { auto _tpcnsigmaPr = trkPr.tpcNSigmaPr(); histos.fill(HIST("QAbefore/Proton/h2d_pr_nsigma_tpc_p"), p_ptot, _tpcnsigmaPr); - // histos.fill(HIST("QAbefore/Proton/h2d_prel_nsigma_tpc_p"), p_ptot, trkPr.tpcNSigmaEl()); if (trkPr.hasTOF()) { auto _tofnsigmaPr = trkPr.tofNSigmaPr(); histos.fill(HIST("QAbefore/Proton/h2d_pr_nsigma_tof_p"), p_ptot, _tofnsigmaPr); @@ -390,7 +417,7 @@ struct lambdaAnalysis_pb { auto _tpcnsigmaPr = trkPr.tpcNSigmaPr(); // Proton - histos.fill(HIST("QAafter/Proton/h1d_pr_pt"), _ptPr); + histos.fill(HIST("QAafter/Proton/hd_pr_pt"), _ptPr, mult); histos.fill(HIST("QAafter/Proton/h2d_pr_dca_z"), _ptPr, trkPr.dcaZ()); histos.fill(HIST("QAafter/Proton/h2d_pr_dca_xy"), _ptPr, trkPr.dcaXY()); histos.fill(HIST("QAafter/Proton/h2d_pr_dEdx_p"), p_ptot, trkPr.tpcSignal()); @@ -410,7 +437,7 @@ struct lambdaAnalysis_pb { auto _tpcnsigmaKa = trkKa.tpcNSigmaKa(); // Kaon - histos.fill(HIST("QAafter/Kaon/h1d_ka_pt"), _ptKa); + histos.fill(HIST("QAafter/Kaon/hd_ka_pt"), _ptKa, mult); histos.fill(HIST("QAafter/Kaon/h2d_ka_dca_z"), _ptKa, trkKa.dcaZ()); histos.fill(HIST("QAafter/Kaon/h2d_ka_dca_xy"), _ptKa, trkKa.dcaXY()); histos.fill(HIST("QAafter/Kaon/h2d_ka_dEdx_p"), k_ptot, trkKa.tpcSignal()); @@ -428,6 +455,8 @@ struct lambdaAnalysis_pb { } } + if (isonlyQC) + continue; // Invariant mass reconstruction. p1.SetXYZM(_pxPr, _pyPr, _pzPr, MassProton); p2.SetXYZM(_pxKa, _pyKa, _pzKa, MassKaonCharged); @@ -452,22 +481,22 @@ struct lambdaAnalysis_pb { if constexpr (!mix && !mc) { if (trkPr.sign() * trkKa.sign() < 0) { if (trkPr.sign() > 0) - histos.fill(HIST("Analysis/h4d_lstar_invm_US_PM"), _M, _pt, mult); + histos.fill(HIST("Analysis/h4d_lstar_invm_US_PM"), _M, _pt, mult, occup); else - histos.fill(HIST("Analysis/h4d_lstar_invm_US_MP"), _M, _pt, mult); + histos.fill(HIST("Analysis/h4d_lstar_invm_US_MP"), _M, _pt, mult, occup); if (doRotate) { float theta = rn->Uniform(1.56, 1.58); p1.RotateZ(theta); p = p1 + p2; if (std::abs(p.Rapidity()) < 0.5) { - histos.fill(HIST("Analysis/h4d_lstar_invm_rot"), p.M(), p.Pt(), mult); + histos.fill(HIST("Analysis/h4d_lstar_invm_rot"), p.M(), p.Pt(), mult, occup); } } } else { if (trkPr.sign() > 0) { - histos.fill(HIST("Analysis/h4d_lstar_invm_PP"), _M, _pt, mult); + histos.fill(HIST("Analysis/h4d_lstar_invm_PP"), _M, _pt, mult, occup); } else { - histos.fill(HIST("Analysis/h4d_lstar_invm_MM"), _M, _pt, mult); + histos.fill(HIST("Analysis/h4d_lstar_invm_MM"), _M, _pt, mult, occup); } } } @@ -475,14 +504,14 @@ struct lambdaAnalysis_pb { if constexpr (mix) { if (trkPr.sign() * trkKa.sign() < 0) { if (trkPr.sign() > 0) - histos.fill(HIST("Analysis/h4d_lstar_invm_US_PM_mix"), _M, _pt, mult); + histos.fill(HIST("Analysis/h4d_lstar_invm_US_PM_mix"), _M, _pt, mult, occup); else - histos.fill(HIST("Analysis/h4d_lstar_invm_US_MP_mix"), _M, _pt, mult); + histos.fill(HIST("Analysis/h4d_lstar_invm_US_MP_mix"), _M, _pt, mult, occup); } else { if (trkPr.sign() > 0) - histos.fill(HIST("Analysis/h4d_lstar_invm_LS_PP_mix"), _M, _pt, mult); + histos.fill(HIST("Analysis/h4d_lstar_invm_LS_PP_mix"), _M, _pt, mult, occup); else - histos.fill(HIST("Analysis/h4d_lstar_invm_LS_MM_mix"), _M, _pt, mult); + histos.fill(HIST("Analysis/h4d_lstar_invm_LS_MM_mix"), _M, _pt, mult, occup); } } @@ -508,31 +537,15 @@ struct lambdaAnalysis_pb { } } - using resoCols = aod::ResoCollisions; + using resoCols = soa::Join; using resoTracks = aod::ResoTracks; void processData(resoCols::iterator const& collision, resoTracks const& tracks) { // LOGF(info, " collisions: Index = %d %d", collision.globalIndex(),tracks.size()); - histos.fill(HIST("Event/h1d_ft0_mult_percentile"), collision.cent()); + histos.fill(HIST("Event/h1d_ft0_mult_percentile"), collision.cent(), 100); fillDataHistos(tracks, tracks, collision.cent()); - - // get proton and kaon pT-spectra - for (auto const& track : tracks) { - if (!selTracks(track)) - continue; - - float p = TMath::Sqrt(track.px() * track.px() + track.py() * track.py() + track.pz() * track.pz()); - - if (selectionPIDKaon(track, p)) { - histos.fill(HIST("QAChecks/h1d_ka_pt"), track.pt()); - } - - if (selectionPIDProton(track, p)) { - histos.fill(HIST("QAChecks/h1d_pr_pt"), track.pt()); - } - } } PROCESS_SWITCH(lambdaAnalysis_pb, processData, "Process for Same Event Data", true); @@ -570,7 +583,6 @@ struct lambdaAnalysis_pb { } for (auto const& part : resoParents) { - if (abs(part.pdgCode()) != lambda1520id) // // L* pdg_code = 3124 continue; if (abs(part.y()) > 0.5) { // rapidity cut @@ -589,7 +601,10 @@ struct lambdaAnalysis_pb { if (!pass1 || !pass2) // If we have both decay products continue; - auto mass = 1.520; // part.M() + + TLorentzVector p4; + p4.SetPxPyPzE(part.px(), part.py(), part.pz(), part.e()); + auto mass = p4.M(); if (part.pdgCode() > 0) histos.fill(HIST("Analysis/h3d_gen_lstar_PM"), mass, part.pt(), mult); else @@ -610,16 +625,15 @@ struct lambdaAnalysis_pb { SameKindPair pairs{binningPositions2, cNumMixEv, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip for (auto& [c1, t1, c2, t2] : pairs) { - // LOGF(info, "processMCMixedDerived: Mixed collisions : %d (%.3f, %.3f,%d), %d (%.3f, %.3f,%d)",c1.globalIndex(), c1.posZ(), c1.cent(),c1.mult(), c2.globalIndex(), c2.posZ(), c2.cent(),c2.mult()); - histos.fill(HIST("Event/mixing_vzVsmultpercentile"), c1.cent(), c1.posZ()); + histos.fill(HIST("Event/mixing_vzVsmultpercentile"), c1.cent(), c1.posZ(), c1.evtPl()); fillDataHistos(t1, t2, c1.cent()); } } PROCESS_SWITCH(lambdaAnalysis_pb, processMix, "Process for Mixed Events", false); - Preslice perRColdf = aod::resodaughterdf::resoCollisiondfId; + Preslice perRColdf = aod::resodaughter::resoCollisionDFId; using resoColDFs = aod::ResoCollisionDFs; using resoTrackDFs = aod::ResoTrackDFs; @@ -629,15 +643,18 @@ struct lambdaAnalysis_pb { if (doprocessData) LOG(error) << "Disable processData() first!"; + auto _occup = 100; + if (ConfEvtOccupancyInTimeRange) + _occup = collision.trackOccupancyInTimeRange(); // LOGF(info, "inside df collisions: Index = %d %d", collision.globalIndex(),tracks.size()); - histos.fill(HIST("Event/h1d_ft0_mult_percentile"), collision.cent()); - fillDataHistos(tracks, tracks, collision.cent()); + histos.fill(HIST("Event/h1d_ft0_mult_percentile"), collision.cent(), _occup); + fillDataHistos(tracks, tracks, collision.cent(), _occup); } PROCESS_SWITCH(lambdaAnalysis_pb, processDatadf, "Process for data merged DF", false); - using BinningTypeDF = ColumnBinningPolicy; + using BinningTypeDF = ColumnBinningPolicy; void processMixDF(resoColDFs& collisions, resoTrackDFs const& tracks) { if (doprocessMix) @@ -649,30 +666,31 @@ struct lambdaAnalysis_pb { SameKindPair pairs{binningPositions2, cNumMixEv, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip for (auto& [c1, t1, c2, t2] : pairs) { + auto _occup = 100; + if (ConfEvtOccupancyInTimeRange) + _occup = c1.trackOccupancyInTimeRange(); // LOGF(info, "processMCMixedDerived: Mixed collisions : %d (%.3f, %.3f,%d), %d (%.3f, %.3f,%d)",c1.globalIndex(), c1.posZ(), c1.cent(),c1.mult(), c2.globalIndex(), c2.posZ(), c2.cent(),c2.mult()); - histos.fill(HIST("Event/mixing_vzVsmultpercentile"), c1.cent(), c1.posZ()); - fillDataHistos(t1, t2, c1.cent()); + histos.fill(HIST("Event/mixing_vzVsmultpercentile"), c1.cent(), c1.posZ(), c1.evtPl()); + fillDataHistos(t1, t2, c1.cent(), _occup); } } PROCESS_SWITCH(lambdaAnalysis_pb, processMixDF, "Process for merged DF Mixed Events", false); - using BinningTypeEP = ColumnBinningPolicy; + using BinningTypeEP = ColumnBinningPolicy; void processMixepDF(resoColDFs& collisions, resoTrackDFs const& tracks) { if (doprocessMix || doprocessMixDF) LOG(fatal) << "Disable processMix() or processMixDF() first!"; LOGF(debug, "Event Mixing Started"); - BinningTypeEP binningPositions2{{cMixVtxBins, cMixMultBins, cMixEPAngle}, true}; auto tracksTuple = std::make_tuple(tracks); SameKindPair pairs{binningPositions2, cNumMixEv, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip for (auto& [c1, t1, c2, t2] : pairs) { - // LOGF(info, "processMCMixedDerived: Mixed collisions : %d (%.3f, %.3f,%.3f), %d (%.3f, %.3f, %.3f)",c1.globalIndex(), c1.posZ(), c1.cent(),c1.evtPl(), c2.globalIndex(), c2.posZ(), c2.cent(),c2.evtPl()); - histos.fill(HIST("Event/mixing_vzVsmultpercentile"), c1.cent(), c1.posZ()); + histos.fill(HIST("Event/mixing_vzVsmultpercentile"), c1.cent(), c1.posZ(), c1.evtPl()); fillDataHistos(t1, t2, c1.cent()); } } diff --git a/PWGLF/Tasks/Resonances/lambda1520analysis.cxx b/PWGLF/Tasks/Resonances/lambda1520analysis.cxx index d237e569106..3e6749d451d 100644 --- a/PWGLF/Tasks/Resonances/lambda1520analysis.cxx +++ b/PWGLF/Tasks/Resonances/lambda1520analysis.cxx @@ -13,7 +13,9 @@ /// \brief This task reconstructs track-track decay lambda(1520) resonance candidate /// \author Hirak Kumar Koley -#include +#include "TLorentzVector.h" +#include "TF1.h" +#include "TRandom3.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "PWGLF/DataModel/LFResonanceTables.h" @@ -24,7 +26,7 @@ using namespace o2::framework; using namespace o2::soa; using namespace o2::constants::physics; -struct lambda1520analysis { +struct Lambda1520analysis { // Define slice per Resocollision SliceCache cache; Preslice perResoCollision = aod::resodaughter::resoCollisionId; @@ -32,46 +34,57 @@ struct lambda1520analysis { HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + using ResoMCCols = soa::Join; + // Configurables // switches Configurable cEtaAssym{"cEtaAssym", false, "Turn on/off EtaAssym calculation"}; - // Configurable isFillQA{"isFillQA", false, "Turn on/off QA plots"}; - Configurable cAddlTrackcut{"cAddlTrackcut", false, "Switch to turn on/off Additional track cut"}; + Configurable isFilladditionalQA{"isFilladditionalQA", false, "Turn on/off additional QA plots"}; Configurable cOldPIDcut{"cOldPIDcut", false, "Switch to turn on/off old PID cut to apply pt dependent cut"}; + Configurable fixedPIDcut{"fixedPIDcut", false, "Switch to turn on/off FIXED PID cut to apply pt dependent cut"}; + Configurable crejectPion{"crejectPion", false, "Switch to turn on/off pion contamination"}; Configurable cDCAr7SigCut{"cDCAr7SigCut", false, "Track DCAr 7 Sigma cut to PV Maximum"}; Configurable cKinCuts{"cKinCuts", false, "Kinematic Cuts for p-K pair opening angle"}; Configurable cTPCNClsFound{"cTPCNClsFound", false, "Switch to turn on/off TPCNClsFound cut"}; + Configurable additionalQAeventPlots{"additionalQAeventPlots", false, "Additional QA event plots"}; + Configurable additionalMEPlots{"additionalMEPlots", false, "Additional Mixed event plots"}; // Pre-selection Track cuts Configurable cMinPtcut{"cMinPtcut", 0.15f, "Minimal pT for tracks"}; - Configurable cMinTPCncr{"cMinTPCncr", 70, "Minimum number of TPC X rows"}; - Configurable cMinRtpccut{"cMinRtpccut", 0.8f, "minimum ratio of number of Xrows to findable clusters in TPC"}; - Configurable cMaxChi2ITScut{"cMaxChi2ITScut", 36.0f, "Maximal pT for Chi2/cluster for ITS"}; - Configurable cMaxChi2TPCcut{"cMaxChi2TPCcut", 4.0f, "Maximal pT for Chi2/cluster for TPC"}; Configurable cMinTPCNClsFound{"cMinTPCNClsFound", 120, "minimum TPCNClsFound value for good track"}; + Configurable cMinTPCncr{"cMinTPCncr", 70, "Minimum number of TPC X rows"}; // DCA Selections // DCAr to PV Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 0.1f, "Track DCAr cut to PV Maximum"}; // DCAz to PV - Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 2.0f, "Track DCAz cut to PV Maximum"}; + Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 0.1f, "Track DCAz cut to PV Maximum"}; // Track selections Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) + Configurable cfgGlobalTrack{"cfgGlobalTrack", false, "Global track selection"}; // kGoldenChi2 | kDCAxy | kDCAz Configurable cfgPVContributor{"cfgPVContributor", false, "PV contributor track selection"}; // PV Contriuibutor + Configurable cfgHasTOF{"cfgHasTOF", false, "Require TOF"}; + Configurable cfgUseTPCRefit{"cfgUseTPCRefit", false, "Require TPC Refit"}; + Configurable cfgUseITSRefit{"cfgUseITSRefit", false, "Require ITS Refit"}; /// PID Selections Configurable cRejNsigmaTpc{"cRejNsigmaTpc", 3.0, "Reject tracks to improve purity of TPC PID"}; // Reject missidentified particles when tpc bands merge Configurable cRejNsigmaTof{"cRejNsigmaTof", 3.0, "Reject tracks to improve purity of TOF PID"}; // Reject missidentified particles when tpc bands merge Configurable cUseRejNsigma{"cUseRejNsigma", false, "Switch on/off track rejection method to improve purity"}; + Configurable tofAtHighPt{"tofAtHighPt", false, "Use TOF at high pT"}; + Configurable cByPassTOF{"cByPassTOF", false, "By pass TOF PID selection"}; // By pass TOF PID selection + Configurable pidCutType{"pidCutType", 2, "pidCutType = 1 for square cut, 2 for circular cut"}; // By pass TOF PID selection // Kaon // Old PID use case Configurable> kaonTPCPIDpTintv{"kaonTPCPIDpTintv", {999.}, "pT intervals for Kaon TPC PID cuts"}; - Configurable> kaonTPCPIDcuts{"kaonTPCPIDcuts", {2}, "nSigma list for Kaon TPC PID cuts"}; + Configurable> kaonTPCPIDcuts{"kaonTPCPIDcuts", {3}, "nSigma list for Kaon TPC PID cuts"}; Configurable> kaonTOFPIDpTintv{"kaonTOFPIDpTintv", {999.}, "pT intervals for Kaon TOF PID cuts"}; - Configurable> kaonTOFPIDcuts{"kaonTOFPIDcuts", {2}, "nSigma list for Kaon TOF PID cuts"}; + Configurable> kaonTOFPIDcuts{"kaonTOFPIDcuts", {3}, "nSigma list for Kaon TOF PID cuts"}; + Configurable> kaonTPCTOFCombinedpTintv{"kaonTPCTOFCombinedpTintv", {999.}, "pT intervals for Kaon TPC-TOF PID cuts"}; + Configurable> kaonTPCTOFCombinedPIDcuts{"kaonTPCTOFCombinedPIDcuts", {3}, "nSigma list for Kaon TPC-TOF PID cuts"}; Configurable cMaxTPCnSigmaKaonVETO{"cMaxTPCnSigmaKaonVETO", 3.0, "TPC nSigma VETO cut for Kaon"}; // TPC // New PID use case @@ -83,9 +96,11 @@ struct lambda1520analysis { // Proton // Old PID use case Configurable> protonTPCPIDpTintv{"protonTPCPIDpTintv", {999.}, "pT intervals for Kaon TPC PID cuts"}; - Configurable> protonTPCPIDcuts{"protonTPCPIDcuts", {2}, "nSigma list for Kaon TPC PID cuts"}; + Configurable> protonTPCPIDcuts{"protonTPCPIDcuts", {3}, "nSigma list for Kaon TPC PID cuts"}; Configurable> protonTOFPIDpTintv{"protonTOFPIDpTintv", {999.}, "pT intervals for Kaon TOF PID cuts"}; - Configurable> protonTOFPIDcuts{"protonTOFPIDcuts", {2}, "nSigma list for Kaon TOF PID cuts"}; + Configurable> protonTOFPIDcuts{"protonTOFPIDcuts", {3}, "nSigma list for Kaon TOF PID cuts"}; + Configurable> protonTPCTOFCombinedpTintv{"protonTPCTOFCombinedpTintv", {999.}, "pT intervals for Proton TPC-TOF PID cuts"}; + Configurable> protonTPCTOFCombinedPIDcuts{"protonTPCTOFCombinedPIDcuts", {3}, "nSigma list for Proton TPC-TOF PID cuts"}; Configurable cMaxTPCnSigmaProtonVETO{"cMaxTPCnSigmaProtonVETO", 3.0, "TPC nSigma VETO cut for Proton"}; // TPC // New PID use case @@ -96,19 +111,43 @@ struct lambda1520analysis { /// Event Mixing Configurable nEvtMixing{"nEvtMixing", 10, "Number of events to mix"}; - ConfigurableAxis CfgVtxBins{"CfgVtxBins", {VARIABLE_WIDTH, -10.0f, -9.f, -8.f, -7.f, -6.f, -5.f, -4.f, -3.f, -2.f, -1.f, 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f}, "Mixing bins - z-vertex"}; - ConfigurableAxis CfgMultBins{"CfgMultBins", {VARIABLE_WIDTH, 0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f}, "Mixing bins - multiplicity"}; + ConfigurableAxis cfgVtxBins{"cfgVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis cfgMultBins{"cfgMultBins", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Mixing bins - multiplicity"}; + + // MC Event selection + Configurable cZvertCutMC{"cZvertCutMC", 10.0, "MC Z-vertex cut"}; + + // cuts on mother + Configurable cfgCutsOnMother{"cfgCutsOnMother", false, "Enamble additional cuts on mother"}; + Configurable cMaxPtMotherCut{"cMaxPtMotherCut", 10.0, "Maximum pt of mother cut"}; + Configurable cMaxMinvMotherCut{"cMaxMinvMotherCut", 3.0, "Maximum Minv of mother cut"}; + Configurable cfgCutsOnDaughters{"cfgCutsOnDaughters", false, "Enamble additional cuts on daughters"}; + Configurable cetaphiBins{"cetaphiBins", 400, "number of eta and phi bins"}; + Configurable cMaxDeltaEtaCut{"cMaxDeltaEtaCut", 0.7, "Maximum deltaEta between daughters"}; + Configurable cMaxDeltaPhiCut{"cMaxDeltaPhiCut", 1.5, "Maximum deltaPhi between daughters"}; + Configurable invmass1D{"invmass1D", false, "Invariant mass 1D"}; + Configurable cAdditionalMCPlots{"cAdditionalMCPlots", false, "Draw additional plots related to MC"}; + + TRandom* rn = new TRandom(); /// Figures - ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12.0, 12.1, 12.2, 12.3, 12.4, 12.5, 12.6, 12.7, 12.8, 12.9, 13.0, 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7, 13.8, 13.9, 14.0, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15.0}, "Binning of the pT axis"}; + ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, 1.1, 1.2, 1.25, 1.3, 1.4, 1.5, 1.6, 1.7, 1.75, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.5, 4.6, 4.8, 4.9, 5.0, 5.5, 5.6, 6.0, 6.4, 6.5, 7.0, 7.2, 8.0, 9.0, 9.5, 9.6, 10.0, 11.0, 11.5, 12.0, 13.0, 14.0, 14.4, 15.0, 16.0, 18.0, 19.2, 20.}, "Binning of the pT axis"}; ConfigurableAxis binsEta{"binsEta", {100, -1, 1}, ""}; - ConfigurableAxis binsMass{"binsMass", {1700, 1.3, 3.0}, "Invariant Mass (GeV/#it{c}^2)"}; + ConfigurableAxis binsMass{"binsMass", {500, 1.3, 2.3}, "Invariant Mass (GeV/#it{c}^2)"}; ConfigurableAxis binsMult{"binsMult", {110, 0.0, 110.0}, "mult_{FT0M}"}; - ConfigurableAxis binsDCAz{"binsDCAz", {600, -3, 3}, ""}; - ConfigurableAxis binsDCAxy{"binsDCAxy", {300, -1.5, 1.5}, ""}; - ConfigurableAxis binsTPCXrows{"binsTPCXrows", {200, 0, 200}, ""}; + ConfigurableAxis binsDCAz{"binsDCAz", {40, -0.2, 0.2}, ""}; + ConfigurableAxis binsDCAxy{"binsDCAxy", {40, -0.2, 0.2}, ""}; + ConfigurableAxis binsTPCXrows{"binsTPCXrows", {100, 60, 160}, ""}; ConfigurableAxis binsnSigma{"binsnSigma", {130, -6.5, 6.5}, ""}; ConfigurableAxis binsnTPCSignal{"binsnTPCSignal", {1000, 0, 1000}, ""}; + ConfigurableAxis occupancybins{"occupancybins", {VARIABLE_WIDTH, 0.0, 100, 500, 600, 1000, 1100, 1500, 1600, 2000, 2100, 2500, 2600, 3000, 3100, 3500, 3600, 4000, 4100, 4500, 4600, 5000, 5100, 9999}, "Binning of the occupancy axis"}; + Configurable applyOccupancyCut{"applyOccupancyCut", false, "Apply occupancy cut"}; + Configurable occupancyCut{"occupancyCut", 1000, "Mimimum Occupancy cut"}; + + // Rotational background + Configurable isCalcRotBkg{"isCalcRotBkg", true, "Calculate rotational background"}; + Configurable rotationalcut{"rotationalcut", 10, "Cut value (Rotation angle pi - pi/cut and pi + pi/cut)"}; + Configurable cNofRotations{"cNofRotations", 3, "Number of random rotations in the rotational background"}; void init(o2::framework::InitContext&) { @@ -122,115 +161,175 @@ struct lambda1520analysis { AxisSpec axisTPCXrow{binsTPCXrows, "#Xrows_{TPC}"}; AxisSpec pidQAAxis = {binsnSigma, "#sigma"}; AxisSpec axisTPCSignal = {binsnTPCSignal, ""}; + AxisSpec mcLabelAxis = {5, -0.5, 4.5, "MC Label"}; + // AxisSpec occupancyaxis = {occupancybins, "Occupancy [-40,100]"}; + + if (additionalQAeventPlots) { + // Test on Mixed event + histos.add("TestME/hCollisionIndexSameE", "coll index sameE", HistType::kTH1F, {{500, 0.0f, 500.0f}}); + histos.add("TestME/hCollisionIndexMixedE", "coll index mixedE", HistType::kTH1F, {{500, 0.0f, 500.0f}}); + histos.add("TestME/hnTrksSameE", "n tracks per event SameE", HistType::kTH1F, {{1000, 0.0f, 1000.0f}}); + histos.add("TestME/hnTrksMixedE", "n tracks per event MixedE", HistType::kTH1F, {{1000, 0.0f, 1000.0f}}); + histos.add("TestME/hPairsCounterSameE", "tot n pairs sameE", HistType::kTH1F, {{1, 0.5f, 1.5f}}); + histos.add("TestME/hPairsCounterMixedE", "tot n pairs mixedE", HistType::kTH1F, {{1, 0.5f, 1.5f}}); + + // event histograms + histos.add("QAevent/hEvtCounterSameE", "Number of analyzed Same Events", HistType::kTH1F, {{1, 0.5, 1.5}}); + histos.add("QAevent/hVertexZSameE", "Collision Vertex Z position", HistType::kTH1F, {{100, -15., 15.}}); + histos.add("QAevent/hMultiplicityPercentSameE", "Multiplicity percentile of collision", HistType::kTH1F, {{120, 0.0f, 120.0f}}); + + histos.add("QAevent/hEvtCounterMixedE", "Number of analyzed Mixed Events", HistType::kTH1F, {{1, 0.5, 1.5}}); + histos.add("QAevent/hVertexZMixedE", "Collision Vertex Z position", HistType::kTH1F, {{100, -15., 15.}}); + histos.add("QAevent/hMultiplicityPercentMixedE", "Multiplicity percentile of collision", HistType::kTH1F, {{120, 0.0f, 120.0f}}); + } - // Track QA before cuts - // --- Track - histos.add("QA/QAbefore/Track/TOF_TPC_Map_ka_all", "TOF + TPC Combined PID for Kaon;#sigma_{TOF}^{Kaon};#sigma_{TPC}^{Kaon}", {HistType::kTH2D, {pidQAAxis, pidQAAxis}}); - histos.add("QA/QAbefore/Track/TOF_Nsigma_ka_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH2D, {axisPt, pidQAAxis}}); - histos.add("QA/QAbefore/Track/TPC_Nsigma_ka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH2D, {axisPt, pidQAAxis}}); - histos.add("QA/QAbefore/Track/TPC_Nsigma_ka_only", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH2D, {axisPt, pidQAAxis}}); - histos.add("QA/QAbefore/Track/TOF_TPC_Map_pr_all", "TOF + TPC Combined PID for Proton;#sigma_{TOF}^{Proton};#sigma_{TPC}^{Proton}", {HistType::kTH2D, {pidQAAxis, pidQAAxis}}); - histos.add("QA/QAbefore/Track/TOF_Nsigma_pr_all", "TOF NSigma for Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Proton};", {HistType::kTH2D, {axisPt, pidQAAxis}}); - histos.add("QA/QAbefore/Track/TPC_Nsigma_pr_all", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Proton};", {HistType::kTH2D, {axisPt, pidQAAxis}}); - histos.add("QA/QAbefore/Track/TPC_Nsigma_pr_only", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Proton};", {HistType::kTH2D, {axisPt, pidQAAxis}}); - histos.add("QA/QAbefore/Track/dcaZ", "DCA_{Z} distribution of selected Kaons; #it{p}_{T} (GeV/#it{c}); DCA_{Z} (cm); ", HistType::kTH2F, {axisPt, axisDCAz}); - histos.add("QA/QAbefore/Track/dcaXY", "DCA_{XY} momentum distribution of selected Kaons; #it{p}_{T} (GeV/#it{c}); DCA_{XY} (cm);", HistType::kTH2F, {axisPt, axisDCAxy}); - histos.add("QA/QAbefore/Track/TPC_CR", "# TPC Xrows distribution of selected Kaons; #it{p}_{T} (GeV/#it{c}); TPC X rows", HistType::kTH2F, {axisPt, axisTPCXrow}); - histos.add("QA/QAbefore/Track/pT", "pT distribution of Kaons; #it{p}_{T} (GeV/#it{c}); Counts;", {HistType::kTH1F, {axisPt}}); - histos.add("QA/QAbefore/Track/eta", "#eta distribution of Kaons; #eta; Counts;", {HistType::kTH1F, {axisEta}}); - - // TPC ncluster distirbutions - histos.add("TPCncluster/TPCnclusterpr", "TPC ncluster distribution", kTH1F, {{160, 0, 160, "TPC nCluster"}}); - histos.add("TPCncluster/TPCnclusterka", "TPC ncluster distribution", kTH1F, {{160, 0, 160, "TPC nCluster"}}); - histos.add("TPCncluster/TPCnclusterPhipr", "TPC ncluster vs phi", kTH2F, {{160, 0, 160, "TPC nCluster"}, {63, 0, 6.28, "#phi"}}); - histos.add("TPCncluster/TPCnclusterPhika", "TPC ncluster vs phi", kTH2F, {{160, 0, 160, "TPC nCluster"}, {63, 0, 6.28, "#phi"}}); - - // Multiplicity correlation calibrations - histos.add("MultCalib/centglopr", "Centrality vs Global-Tracks", kTH2F, {{110, 0, 110, "Centrality"}, {500, 0, 5000, "Global Tracks"}}); - histos.add("MultCalib/centgloka", "Centrality vs Global-Tracks", kTH2F, {{110, 0, 110, "Centrality"}, {500, 0, 5000, "Global Tracks"}}); - histos.add("MultCalib/GloPVpr", "Global tracks vs PV tracks", kTH2F, {{500, 0, 5000, "Global tracks"}, {500, 0, 5000, "PV tracks"}}); - histos.add("MultCalib/GloPVka", "Global tracks vs PV tracks", kTH2F, {{500, 0, 5000, "Global tracks"}, {500, 0, 5000, "PV tracks"}}); - - // PID QA after cuts - // --- Kaon - histos.add("QA/QAafter/Kaon/TOF_TPC_Map_ka_all", "TOF + TPC Combined PID for Kaon;#sigma_{TOF}^{Kaon};#sigma_{TPC}^{Kaon}", {HistType::kTH2D, {pidQAAxis, pidQAAxis}}); - histos.add("QA/QAafter/Kaon/TOF_Nsigma_ka_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH2D, {axisPt, pidQAAxis}}); - histos.add("QA/QAafter/Kaon/TPC_Nsigma_ka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH2D, {axisPt, pidQAAxis}}); - histos.add("QA/QAafter/Kaon/TPC_Nsigma_ka_TPConly", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH2D, {axisPt, pidQAAxis}}); - histos.add("QA/QAafter/Kaon/dcaZ", "DCA_{Z} distribution of selected Kaons; #it{p}_{T} (GeV/#it{c}); DCA_{Z} (cm); ", HistType::kTH2F, {axisPt, axisDCAz}); - histos.add("QA/QAafter/Kaon/dcaXY", "DCA_{XY} momentum distribution of selected Kaons; #it{p}_{T} (GeV/#it{c}); DCA_{XY} (cm);", HistType::kTH2F, {axisPt, axisDCAxy}); - histos.add("QA/QAafter/Kaon/TPC_CR", "# TPC Xrows distribution of selected Kaons; #it{p}_{T} (GeV/#it{c}); TPC X rows", HistType::kTH2F, {axisPt, axisTPCXrow}); - histos.add("QA/QAafter/Kaon/pT", "pT distribution of Kaons; #it{p}_{T} (GeV/#it{c}); Counts;", {HistType::kTH1F, {axisPt}}); - histos.add("QA/QAafter/Kaon/eta", "#eta distribution of Kaons; #eta; Counts;", {HistType::kTH1F, {axisEta}}); - histos.add("QA/QAafter/Kaon/TPC_Signal_ka_all", "TPC Signal for Kaon;#it{p}_{T} (GeV/#it{c});TPC Signal (A.U.)", {HistType::kTH2D, {axisPt, axisTPCSignal}}); - - // --- Proton - histos.add("QA/QAafter/Proton/TOF_TPC_Map_pr_all", "TOF + TPC Combined PID for Proton;#sigma_{TOF}^{Proton};#sigma_{TPC}^{Proton}", {HistType::kTH2D, {pidQAAxis, pidQAAxis}}); - histos.add("QA/QAafter/Proton/TOF_Nsigma_pr_all", "TOF NSigma for Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Proton};", {HistType::kTH2D, {axisPt, pidQAAxis}}); - histos.add("QA/QAafter/Proton/TPC_Nsigma_pr_all", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Proton};", {HistType::kTH2D, {axisPt, pidQAAxis}}); - histos.add("QA/QAafter/Proton/TPC_Nsigma_pr_TPConly", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Proton};", {HistType::kTH2D, {axisPt, pidQAAxis}}); - histos.add("QA/QAafter/Proton/dcaZ", "DCA_{Z} distribution of selected Protons; #it{p}_{T} (GeV/#it{c}); DCA_{Z} (cm);", HistType::kTH2F, {axisPt, axisDCAz}); - histos.add("QA/QAafter/Proton/dcaXY", "DCA_{XY} momentum distribution of selected Protons; #it{p}_{T} (GeV/#it{c}); DCA_{XY} (cm);", HistType::kTH2F, {axisPt, axisDCAxy}); - histos.add("QA/QAafter/Proton/TPC_CR", "# TPC Xrows distribution of selected Protons; #it{p}_{T} (GeV/#it{c}); TPC X rows", HistType::kTH2F, {axisPt, axisTPCXrow}); - histos.add("QA/QAafter/Proton/pT", "pT distribution of Protons; #it{p}_{T} (GeV/#it{c}); Counts;", {HistType::kTH1F, {axisPt}}); - histos.add("QA/QAafter/Proton/eta", "#eta distribution of Protons; #eta; Counts;", {HistType::kTH1F, {axisEta}}); - histos.add("QA/QAafter/Proton/TPC_Signal_pr_all", "TPC Signal for Proton;#it{p}_{T} (GeV/#it{c});TPC Signal (A.U.)", {HistType::kTH2D, {axisPt, axisTPCSignal}}); - - if (!doprocessMC || !doprocessMCTrue) { - // Mass QA 1D for quick check - histos.add("Result/Data/lambda1520invmass", "Invariant mass of #Lambda(1520) K^{#pm}p^{#mp}; Invariant Mass (GeV/#it{c}^2); Counts;", {HistType::kTH1F, {axisMassLambda1520}}); - histos.add("Result/Data/lambda1520invmassLSPP", "Invariant mass of #Lambda(1520) Like Sign Method K^{#plus}p^{#plus}; Invariant Mass (GeV/#it{c}^2); Counts;", {HistType::kTH1F, {axisMassLambda1520}}); // K+ + Pr - histos.add("Result/Data/lambda1520invmassLSMM", "Invariant mass of #Lambda(1520) Like Sign Method K^{#minus}p^{#minus}; Invariant Mass (GeV/#it{c}^2); Counts;", {HistType::kTH1F, {axisMassLambda1520}}); // K- + anti-Pr + if (doprocessData) { + // Track QA before cuts + // --- Track + histos.add("QA/QAbefore/Track/TOF_TPC_Map_ka_all", "TOF + TPC Combined PID for Kaon;#sigma_{TOF}^{Kaon};#sigma_{TPC}^{Kaon}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QA/QAbefore/Track/TOF_Nsigma_ka_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3F, {axisMult, axisPt, pidQAAxis}}); + histos.add("QA/QAbefore/Track/TPC_Nsigma_ka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3F, {axisMult, axisPt, pidQAAxis}}); + histos.add("QA/QAbefore/Track/TPConly_Nsigma_ka", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH2F, {axisPt, pidQAAxis}}); + histos.add("QA/QAbefore/Track/TOF_TPC_Map_pr_all", "TOF + TPC Combined PID for Proton;#sigma_{TOF}^{Proton};#sigma_{TPC}^{Proton}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QA/QAbefore/Track/TOF_Nsigma_pr_all", "TOF NSigma for Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Proton};", {HistType::kTH3F, {axisMult, axisPt, pidQAAxis}}); + histos.add("QA/QAbefore/Track/TPC_Nsigma_pr_all", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Proton};", {HistType::kTH3F, {axisMult, axisPt, pidQAAxis}}); + histos.add("QA/QAbefore/Track/TPConly_Nsigma_pr", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Proton};", {HistType::kTH2F, {axisPt, pidQAAxis}}); + histos.add("QA/QAbefore/Track/dcaZ", "DCA_{Z} distribution of selected Kaons; #it{p}_{T} (GeV/#it{c}); DCA_{Z} (cm); ", HistType::kTH2F, {axisPt, axisDCAz}); + histos.add("QA/QAbefore/Track/dcaXY", "DCA_{XY} momentum distribution of selected Kaons; #it{p}_{T} (GeV/#it{c}); DCA_{XY} (cm);", HistType::kTH2F, {axisPt, axisDCAxy}); + histos.add("QA/QAbefore/Track/TPC_CR", "# TPC Xrows distribution of selected Kaons; #it{p}_{T} (GeV/#it{c}); TPC X rows", HistType::kTH2F, {axisPt, axisTPCXrow}); + histos.add("QA/QAbefore/Track/pT", "pT distribution of Kaons; #it{p}_{T} (GeV/#it{c}); Counts;", {HistType::kTH1F, {axisPt}}); + histos.add("QA/QAbefore/Track/eta", "#eta distribution of Kaons; #eta; Counts;", {HistType::kTH1F, {axisEta}}); + + if (isFilladditionalQA) { + // TPC ncluster distirbutions + histos.add("TPCncluster/TPCnclusterpr", "TPC ncluster distribution", kTH1F, {{160, 0, 160, "TPC nCluster"}}); + histos.add("TPCncluster/TPCnclusterka", "TPC ncluster distribution", kTH1F, {{160, 0, 160, "TPC nCluster"}}); + histos.add("TPCncluster/TPCnclusterPhipr", "TPC ncluster vs phi", kTH2F, {{160, 0, 160, "TPC nCluster"}, {63, 0, 6.28, "#phi"}}); + histos.add("TPCncluster/TPCnclusterPhika", "TPC ncluster vs phi", kTH2F, {{160, 0, 160, "TPC nCluster"}, {63, 0, 6.28, "#phi"}}); + + // Multiplicity correlation calibrations + histos.add("MultCalib/centglopr", "Centrality vs Global-Tracks", kTH2F, {{110, 0, 110, "Centrality"}, {500, 0, 5000, "Global Tracks"}}); + histos.add("MultCalib/centgloka", "Centrality vs Global-Tracks", kTH2F, {{110, 0, 110, "Centrality"}, {500, 0, 5000, "Global Tracks"}}); + histos.add("MultCalib/GloPVpr", "Global tracks vs PV tracks", kTH2F, {{500, 0, 5000, "Global tracks"}, {500, 0, 5000, "PV tracks"}}); + histos.add("MultCalib/GloPVka", "Global tracks vs PV tracks", kTH2F, {{500, 0, 5000, "Global tracks"}, {500, 0, 5000, "PV tracks"}}); + } - // 3d histogram - histos.add("Result/Data/h3lambda1520invmass", "Invariant mass of #Lambda(1520) K^{#pm}p^{#mp}", HistType::kTH3F, {axisMult, axisPt, axisMassLambda1520}); - histos.add("Result/Data/h3lambda1520invmassLSPP", "Invariant mass of #Lambda(1520) Like Sign Method K^{#plus}p^{#plus}", HistType::kTH3F, {axisMult, axisPt, axisMassLambda1520}); // K+ + Pr - histos.add("Result/Data/h3lambda1520invmassLSMM", "Invariant mass of #Lambda(1520) Like Sign Method K^{#minus}p^{#minus}", HistType::kTH3F, {axisMult, axisPt, axisMassLambda1520}); // K- + anti-Pr + // PID QA after cuts + // --- Kaon + histos.add("QA/QAafter/Kaon/TOF_TPC_Map_ka_all", "TOF + TPC Combined PID for Kaon;#sigma_{TOF}^{Kaon};#sigma_{TPC}^{Kaon}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QA/QAafter/Kaon/TOF_Nsigma_ka_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3F, {axisMult, axisPt, pidQAAxis}}); + histos.add("QA/QAafter/Kaon/TPC_Nsigma_ka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3F, {axisMult, axisPt, pidQAAxis}}); + histos.add("QA/QAafter/Kaon/TPC_Nsigma_ka_TPConly", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH2F, {axisPt, pidQAAxis}}); + histos.add("QA/QAafter/Kaon/dcaZ", "DCA_{Z} distribution of selected Kaons; #it{p}_{T} (GeV/#it{c}); DCA_{Z} (cm); ", HistType::kTH2F, {axisPt, axisDCAz}); + histos.add("QA/QAafter/Kaon/dcaXY", "DCA_{XY} momentum distribution of selected Kaons; #it{p}_{T} (GeV/#it{c}); DCA_{XY} (cm);", HistType::kTH2F, {axisPt, axisDCAxy}); + histos.add("QA/QAafter/Kaon/TPC_CR", "# TPC Xrows distribution of selected Kaons; #it{p}_{T} (GeV/#it{c}); TPC X rows", HistType::kTH2F, {axisPt, axisTPCXrow}); + histos.add("QA/QAafter/Kaon/pT", "pT distribution of Kaons; #it{p}_{T} (GeV/#it{c}); Counts;", {HistType::kTH1F, {axisPt}}); + histos.add("QA/QAafter/Kaon/eta", "#eta distribution of Kaons; #eta; Counts;", {HistType::kTH1F, {axisEta}}); + histos.add("QA/QAafter/Kaon/TPC_Signal_ka_all", "TPC Signal for Kaon;#it{p}_{T} (GeV/#it{c});TPC Signal (A.U.)", {HistType::kTH2F, {axisPt, axisTPCSignal}}); + + // --- Proton + histos.add("QA/QAafter/Proton/TOF_TPC_Map_pr_all", "TOF + TPC Combined PID for Proton;#sigma_{TOF}^{Proton};#sigma_{TPC}^{Proton}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QA/QAafter/Proton/TOF_Nsigma_pr_all", "TOF NSigma for Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Proton};", {HistType::kTH3F, {axisMult, axisPt, pidQAAxis}}); + histos.add("QA/QAafter/Proton/TPC_Nsigma_pr_all", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Proton};", {HistType::kTH3F, {axisMult, axisPt, pidQAAxis}}); + histos.add("QA/QAafter/Proton/TPC_Nsigma_pr_TPConly", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Proton};", {HistType::kTH2F, {axisPt, pidQAAxis}}); + histos.add("QA/QAafter/Proton/dcaZ", "DCA_{Z} distribution of selected Protons; #it{p}_{T} (GeV/#it{c}); DCA_{Z} (cm);", HistType::kTH2F, {axisPt, axisDCAz}); + histos.add("QA/QAafter/Proton/dcaXY", "DCA_{XY} momentum distribution of selected Protons; #it{p}_{T} (GeV/#it{c}); DCA_{XY} (cm);", HistType::kTH2F, {axisPt, axisDCAxy}); + histos.add("QA/QAafter/Proton/TPC_CR", "# TPC Xrows distribution of selected Protons; #it{p}_{T} (GeV/#it{c}); TPC X rows", HistType::kTH2F, {axisPt, axisTPCXrow}); + histos.add("QA/QAafter/Proton/pT", "pT distribution of Protons; #it{p}_{T} (GeV/#it{c}); Counts;", {HistType::kTH1F, {axisPt}}); + histos.add("QA/QAafter/Proton/eta", "#eta distribution of Protons; #eta; Counts;", {HistType::kTH1F, {axisEta}}); + histos.add("QA/QAafter/Proton/TPC_Signal_pr_all", "TPC Signal for Proton;#it{p}_{T} (GeV/#it{c});TPC Signal (A.U.)", {HistType::kTH2F, {axisPt, axisTPCSignal}}); + + // Mass QA 1D for quick check + if (invmass1D) { + histos.add("Result/Data/lambda1520invmass", "Invariant mass of #Lambda(1520) K^{#pm}p^{#mp}; Invariant Mass (GeV/#it{c}^2); Counts;", {HistType::kTH1F, {axisMassLambda1520}}); + histos.add("Result/Data/antilambda1520invmass", "Invariant mass of #Lambda(1520) K^{#mp}p^{#pm}; Invariant Mass (GeV/#it{c}^2); Counts;", {HistType::kTH1F, {axisMassLambda1520}}); + histos.add("Result/Data/lambda1520invmassLSPP", "Invariant mass of #Lambda(1520) Like Sign Method K^{#plus}p^{#plus}; Invariant Mass (GeV/#it{c}^2); Counts;", {HistType::kTH1F, {axisMassLambda1520}}); // K+ + Pr + histos.add("Result/Data/lambda1520invmassLSMM", "Invariant mass of #Lambda(1520) Like Sign Method K^{#minus}p^{#minus}; Invariant Mass (GeV/#it{c}^2); Counts;", {HistType::kTH1F, {axisMassLambda1520}}); // K- + anti-Pr + } + // eta phi QA + if (cfgCutsOnDaughters) { + histos.add("QAbefore/deltaEta", "deltaEta of kaon and proton candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 3.15}}); + histos.add("QAbefore/deltaPhi", "deltaPhi of kaon and proton candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 3.15}}); + + histos.add("QAafter/deltaEta", "deltaEta of kaon and proton candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 3.15}}); + histos.add("QAafter/deltaPhi", "deltaPhi of kaon and proton candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 3.15}}); + + histos.add("QAafter/deltaEtaafter", "deltaEta of kaon and proton candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 3.15}}); + histos.add("QAafter/deltaPhiafter", "deltaPhi of kaon and proton candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 3.15}}); + histos.add("QAafter/EtaPrafter", "Eta of proton candidates", HistType::kTH1F, {{cetaphiBins, -1.6, 1.6}}); + histos.add("QAafter/PhiPrafter", "Phi of proton candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 6.30}}); + histos.add("QAafter/EtaKaafter", "Eta of kaon candidates", HistType::kTH1F, {{cetaphiBins, -1.6, 1.6}}); + histos.add("QAafter/PhiKaafter", "Phi of kaon candidates", HistType::kTH1F, {{cetaphiBins, 0.0, 6.30}}); + } - if (doprocessME) { + if (isCalcRotBkg) { + histos.add("Result/Data/h3lambda1520InvMassRotation", "Invariant mass of #Lambda(1520) rotation", kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + } + + // 3d histogram + histos.add("Result/Data/h3lambda1520invmass", "Invariant mass of #Lambda(1520) K^{#pm}p^{#mp}", HistType::kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + histos.add("Result/Data/h3antilambda1520invmass", "Invariant mass of #Lambda(1520) K^{#mp}p^{#pm}", HistType::kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + histos.add("Result/Data/h3lambda1520invmassLSPP", "Invariant mass of #Lambda(1520) Like Sign Method K^{#plus}p^{#plus}", HistType::kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); // K+ + Pr + histos.add("Result/Data/h3lambda1520invmassLSMM", "Invariant mass of #Lambda(1520) Like Sign Method K^{#minus}p^{#minus}", HistType::kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); // K- + anti-Pr + } + if (doprocessME) { + if (invmass1D) { histos.add("Result/Data/lambda1520invmassME", "Invariant mass of #Lambda(1520) mixed event K^{#pm}p^{#mp}; Invariant Mass (GeV/#it{c}^2); Counts;", {HistType::kTH1F, {axisMassLambda1520}}); - histos.add("Result/Data/h3lambda1520invmassME", "Invariant mass of #Lambda(1520) mixed event K^{#pm}p^{#mp}", HistType::kTH3F, {axisMult, axisPt, axisMassLambda1520}); } + histos.add("Result/Data/h3lambda1520invmassME", "Invariant mass of #Lambda(1520) mixed event K^{#pm}p^{#mp}", HistType::kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + + if (additionalMEPlots) { + histos.add("Result/Data/lambda1520invmassME_DS", "Invariant mass of #Lambda(1520) mixed event DS", kTH1F, {axisMassLambda1520}); + histos.add("Result/Data/lambda1520invmassME_DSAnti", "Invariant mass of #Lambda(1520) mixed event DSAnti", kTH1F, {axisMassLambda1520}); + histos.add("Result/Data/h3lambda1520invmassME_DS", "Invariant mass of #Lambda(1520) mixed event DS", kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + histos.add("Result/Data/h3lambda1520invmassME_DSAnti", "Invariant mass of #Lambda(1520) mixed event DSAnti", kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + } + } - if (cEtaAssym) { - histos.add("Result/Data/hlambda1520invmassUnlikeSignAside", "Invariant mass of #Lambda(1520) Unlike Sign A side", {HistType::kTH1F, {axisMassLambda1520}}); - histos.add("Result/Data/hlambda1520invmassLikeSignAside", "Invariant mass of #Lambda(1520) Like Sign A side", {HistType::kTH1F, {axisMassLambda1520}}); - histos.add("Result/Data/hlambda1520invmassUnlikeSignCside", "Invariant mass of #Lambda(1520) Unlike Sign C side", {HistType::kTH1F, {axisMassLambda1520}}); - histos.add("Result/Data/hlambda1520invmassLikeSignCside", "Invariant mass of #Lambda(1520) Like Sign C side", {HistType::kTH1F, {axisMassLambda1520}}); + if (cEtaAssym) { + histos.add("Result/Data/hlambda1520invmassUnlikeSignAside", "Invariant mass of #Lambda(1520) Unlike Sign A side", {HistType::kTH1F, {axisMassLambda1520}}); + histos.add("Result/Data/hlambda1520invmassLikeSignAside", "Invariant mass of #Lambda(1520) Like Sign A side", {HistType::kTH1F, {axisMassLambda1520}}); + histos.add("Result/Data/hlambda1520invmassUnlikeSignCside", "Invariant mass of #Lambda(1520) Unlike Sign C side", {HistType::kTH1F, {axisMassLambda1520}}); + histos.add("Result/Data/hlambda1520invmassLikeSignCside", "Invariant mass of #Lambda(1520) Like Sign C side", {HistType::kTH1F, {axisMassLambda1520}}); - histos.add("Result/Data/h3lambda1520invmassUnlikeSignAside", "Invariant mass of #Lambda(1520) Unlike Sign A side", HistType::kTH3F, {axisMult, axisPt, axisMassLambda1520}); - histos.add("Result/Data/h3lambda1520invmassLikeSignAside", "Invariant mass of #Lambda(1520) Like Sign A side", HistType::kTH3F, {axisMult, axisPt, axisMassLambda1520}); - histos.add("Result/Data/h3lambda1520invmassUnlikeSignCside", "Invariant mass of #Lambda(1520) Unlike Sign C side", HistType::kTH3F, {axisMult, axisPt, axisMassLambda1520}); - histos.add("Result/Data/h3lambda1520invmassLikeSignCside", "Invariant mass of #Lambda(1520) Like Sign C side", HistType::kTH3F, {axisMult, axisPt, axisMassLambda1520}); - if (doprocessME) { - histos.add("Result/Data/hlambda1520invmassMixedAside", "Invariant mass of #Lambda(1520) Mixed A side", {HistType::kTH1F, {axisMassLambda1520}}); - histos.add("Result/Data/hlambda1520invmassMixedCside", "Invariant mass of #Lambda(1520) Mixed C side", {HistType::kTH1F, {axisMassLambda1520}}); + histos.add("Result/Data/h3lambda1520invmassUnlikeSignAside", "Invariant mass of #Lambda(1520) Unlike Sign A side", HistType::kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + histos.add("Result/Data/h3lambda1520invmassLikeSignAside", "Invariant mass of #Lambda(1520) Like Sign A side", HistType::kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + histos.add("Result/Data/h3lambda1520invmassUnlikeSignCside", "Invariant mass of #Lambda(1520) Unlike Sign C side", HistType::kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + histos.add("Result/Data/h3lambda1520invmassLikeSignCside", "Invariant mass of #Lambda(1520) Like Sign C side", HistType::kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + if (doprocessME) { + histos.add("Result/Data/hlambda1520invmassMixedAside", "Invariant mass of #Lambda(1520) Mixed A side", {HistType::kTH1F, {axisMassLambda1520}}); + histos.add("Result/Data/hlambda1520invmassMixedCside", "Invariant mass of #Lambda(1520) Mixed C side", {HistType::kTH1F, {axisMassLambda1520}}); - histos.add("Result/Data/h3lambda1520invmassMixedAside", "Invariant mass of #Lambda(1520) Mixed A side", HistType::kTH3F, {axisMult, axisPt, axisMassLambda1520}); - histos.add("Result/Data/h3lambda1520invmassMixedCside", "Invariant mass of #Lambda(1520) Mixed C side", HistType::kTH3F, {axisMult, axisPt, axisMassLambda1520}); - } + histos.add("Result/Data/h3lambda1520invmassMixedAside", "Invariant mass of #Lambda(1520) Mixed A side", HistType::kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + histos.add("Result/Data/h3lambda1520invmassMixedCside", "Invariant mass of #Lambda(1520) Mixed C side", HistType::kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); } } + //} // MC QA if (doprocessMCTrue) { - histos.add("Result/MC/Genlambda1520pt", "pT distribution of True MC #Lambda(1520)0", kTH1F, {axisPt}); - histos.add("Result/MC/Genantilambda1520pt", "pT distribution of True MC Anti-#Lambda(1520)0", kTH1F, {axisPt}); - histos.add("Result/MC/GenTruelambda1520pt", "pT distribution of True MC #Lambda(1520)0", kTH1F, {axisPt}); + histos.add("Result/MC/Genlambda1520pt", "pT distribution of True MC #Lambda(1520)0", kTH3F, {mcLabelAxis, axisPt, axisMult}); + histos.add("Result/MC/Genantilambda1520pt", "pT distribution of True MC Anti-#Lambda(1520)0", kTH3F, {mcLabelAxis, axisPt, axisMult}); } if (doprocessMC) { - histos.add("QA/MC/trkDCAxy_pr", "DCAxy distribution of proton track candidates", HistType::kTH1F, {axisDCAxy}); - histos.add("QA/MC/trkDCAxy_ka", "DCAxy distribution of kaon track candidates", HistType::kTH1F, {axisDCAxy}); - histos.add("QA/MC/trkDCAz_pr", "DCAz distribution of proton track candidates", HistType::kTH1F, {axisDCAz}); - histos.add("QA/MC/trkDCAz_ka", "DCAz distribution of kaon track candidates", HistType::kTH1F, {axisDCAz}); + histos.add("QA/MC/trkDCAxy_pr", "DCAxy distribution of proton track candidates", HistType::kTH2F, {axisPt, axisDCAxy}); + histos.add("QA/MC/trkDCAxy_ka", "DCAxy distribution of kaon track candidates", HistType::kTH2F, {axisPt, axisDCAxy}); + histos.add("QA/MC/trkDCAz_pr", "DCAz distribution of proton track candidates", HistType::kTH2F, {axisPt, axisDCAz}); + histos.add("QA/MC/trkDCAz_ka", "DCAz distribution of kaon track candidates", HistType::kTH2F, {axisPt, axisDCAz}); + histos.add("QA/MC/TOF_Nsigma_pr_all", "TOF NSigma for Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Proton};", {HistType::kTH3F, {axisMult, axisPt, pidQAAxis}}); + histos.add("QA/MC/TPC_Nsigma_pr_all", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Proton};", {HistType::kTH3F, {axisMult, axisPt, pidQAAxis}}); + histos.add("QA/MC/TOF_Nsigma_ka_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3F, {axisMult, axisPt, pidQAAxis}}); + histos.add("QA/MC/TPC_Nsigma_ka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3F, {axisMult, axisPt, pidQAAxis}}); + histos.add("Result/MC/h3lambda1520Recoinvmass", "Invariant mass of Reconstructed MC #Lambda(1520)0", kTH3F, {axisMult, axisPt, axisMassLambda1520}); histos.add("Result/MC/h3antilambda1520Recoinvmass", "Invariant mass of Reconstructed MC Anti-#Lambda(1520)0", kTH3F, {axisMult, axisPt, axisMassLambda1520}); - histos.add("Result/MC/lambda1520GenpT", "pT distribution of True MC #Lambda(1520)0", kTH1F, {axisPt}); - histos.add("Result/MC/lambda1520GenAntipT", "pT distribution of True MC Anti-#Lambda(1520)0", kTH1F, {axisPt}); - histos.add("Result/MC/lambda1520RecopT", "pT distribution of Reconstructed MC #Lambda(1520)0", kTH1F, {axisPt}); - histos.add("Result/MC/antilambda1520RecopT", "pT distribution of Reconstructed MC Anti-#Lambda(1520)0", kTH1F, {axisPt}); - histos.add("Result/MC/hlambda1520Recoinvmass", "Inv mass distribution of Reconstructed MC #Lambda(1520)", kTH1F, {axisMassLambda1520}); - histos.add("Result/MC/hantilambda1520Recoinvmass", "Inv mass distribution of Reconstructed MC Anti-#Lambda(1520)", kTH1F, {axisMassLambda1520}); + if (cAdditionalMCPlots) { + histos.add("Result/MC/lambda1520Reco", "pT distribution of Reconstructed MC #Lambda(1520)0", kTH2F, {axisPt, axisMult}); + histos.add("Result/MC/antilambda1520Reco", "pT distribution of Reconstructed MC Anti-#Lambda(1520)0", kTH2F, {axisPt, axisMult}); + histos.add("Result/MC/hlambda1520Recoinvmass", "Inv mass distribution of Reconstructed MC #Lambda(1520)", kTH1F, {axisMassLambda1520}); + histos.add("Result/MC/hantilambda1520Recoinvmass", "Inv mass distribution of Reconstructed MC Anti-#Lambda(1520)", kTH1F, {axisMassLambda1520}); + } } + // Print output histograms statistics LOG(info) << "Size of the histograms in spectraTOF"; histos.print(); @@ -254,26 +353,24 @@ struct lambda1520analysis { } if (std::abs(track.dcaZ()) > cMaxDCAzToPVcut) return false; - if (track.tpcNClsCrossedRows() < cMinTPCncr) - return false; - if (cAddlTrackcut) { - if (!track.passedITSRefit() || !track.passedTPCRefit()) - return false; - if (track.tpcCrossedRowsOverFindableCls() < cMinRtpccut) - return false; - if (track.itsChi2NCl() > cMaxChi2ITScut) - return false; - if (track.tpcChi2NCl() > cMaxChi2TPCcut) - return false; - } if (cTPCNClsFound && (track.tpcNClsFound() < cMinTPCNClsFound)) return false; + if (cfgHasTOF && !track.hasTOF()) + return false; if (cfgPrimaryTrack && !track.isPrimaryTrack()) return false; if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) return false; if (cfgPVContributor && !track.isPVContributor()) return false; + if (cfgGlobalTrack && !track.isGlobalTrack()) + return false; + if (cfgUseITSRefit && !track.passedITSRefit()) + return false; + if (cfgUseTPCRefit && !track.passedTPCRefit()) + return false; + if (track.tpcNClsCrossedRows() < cMinTPCncr) + return false; return true; } @@ -282,39 +379,51 @@ struct lambda1520analysis { template bool selectionnewPIDProton(const T& candidate) { - bool tpcPIDPassed{false}, tofPIDPassed{false}; - if (std::abs(candidate.tpcNSigmaPr()) < cMaxTPCnSigmaProton) { - if (cUseRejNsigma) { - if (candidate.tpcNSigmaPi() > cRejNsigmaTpc && candidate.tpcNSigmaKa() > cRejNsigmaTpc) { + if (tofAtHighPt) { + if (candidate.hasTOF() && (std::abs(candidate.tofNSigmaPr()) < cMaxTOFnSigmaProton)) { + return true; + } + if (!candidate.hasTOF() && (std::abs(candidate.tpcNSigmaPr()) < cMaxTPCnSigmaKaon)) { + return true; + } + } else { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + if (std::abs(candidate.tpcNSigmaPr()) < cMaxTPCnSigmaProton) { + if (cUseRejNsigma) { + if (std::abs(candidate.tpcNSigmaPi()) > cRejNsigmaTpc && std::abs(candidate.tpcNSigmaKa()) > cRejNsigmaTpc) { + tpcPIDPassed = true; + } + } else if (!cUseRejNsigma) { tpcPIDPassed = true; } - } else { - tpcPIDPassed = true; } - } - if (candidate.hasTOF()) { - if ((nsigmaCutCombinedProton > 0) && ((candidate.tofNSigmaPr() * candidate.tofNSigmaPr() + candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr()) < (nsigmaCutCombinedProton * nsigmaCutCombinedProton))) { - if (cUseRejNsigma) { - if (candidate.tofNSigmaPi() > cRejNsigmaTof && candidate.tofNSigmaKa() > cRejNsigmaTof) { + if (cByPassTOF && tpcPIDPassed) { + return true; + } + if (candidate.hasTOF()) { + if ((nsigmaCutCombinedProton > 0) && ((candidate.tofNSigmaPr() * candidate.tofNSigmaPr() + candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr()) < (nsigmaCutCombinedProton * nsigmaCutCombinedProton))) { + if (cUseRejNsigma) { + if (std::abs(candidate.tofNSigmaPi()) > cRejNsigmaTof && std::abs(candidate.tofNSigmaKa()) > cRejNsigmaTof) { + tofPIDPassed = true; + } + } else if (!cUseRejNsigma) { tofPIDPassed = true; } - } else { - tofPIDPassed = true; - } - } else if (std::abs(candidate.tofNSigmaPr()) < cMaxTOFnSigmaProton) { - if (cUseRejNsigma) { - if (candidate.tofNSigmaPi() > cRejNsigmaTof && candidate.tofNSigmaKa() > cRejNsigmaTof) { + } else if ((nsigmaCutCombinedProton <= 0) && (std::abs(candidate.tofNSigmaPr()) < cMaxTOFnSigmaProton)) { + if (cUseRejNsigma) { + if (std::abs(candidate.tofNSigmaPi()) > cRejNsigmaTof && std::abs(candidate.tofNSigmaKa()) > cRejNsigmaTof) { + tofPIDPassed = true; + } + } else if (!cUseRejNsigma) { tofPIDPassed = true; } - } else { - tofPIDPassed = true; } + } else { + tofPIDPassed = true; + } + if (tpcPIDPassed && tofPIDPassed) { + return true; } - } else { - tofPIDPassed = true; - } - if (tpcPIDPassed && tofPIDPassed) { - return true; } return false; } @@ -322,40 +431,51 @@ struct lambda1520analysis { template bool selectionnewPIDKaon(const T& candidate) { - bool tpcPIDPassed{false}, tofPIDPassed{false}; - if (std::abs(candidate.tpcNSigmaKa()) < cMaxTPCnSigmaKaon) { - if (cUseRejNsigma) { - if (candidate.tpcNSigmaPi() > cRejNsigmaTpc && candidate.tpcNSigmaPr() > cRejNsigmaTpc) { - tpcPIDPassed = true; - } - } else { - tpcPIDPassed = true; + if (tofAtHighPt) { + if (candidate.hasTOF() && (std::abs(candidate.tofNSigmaKa()) < cMaxTOFnSigmaKaon)) { + return true; } - } - if (candidate.hasTOF()) { - if (std::abs(candidate.tofNSigmaKa()) < cMaxTOFnSigmaKaon) { + if (!candidate.hasTOF() && (std::abs(candidate.tpcNSigmaKa()) < cMaxTPCnSigmaKaon)) { + return true; + } + } else { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + if (std::abs(candidate.tpcNSigmaKa()) < cMaxTPCnSigmaKaon) { if (cUseRejNsigma) { - if (candidate.tofNSigmaPi() > cRejNsigmaTof && candidate.tofNSigmaPr() > cRejNsigmaTof) { - tofPIDPassed = true; + if (std::abs(candidate.tpcNSigmaPi()) > cRejNsigmaTpc && std::abs(candidate.tpcNSigmaPr()) > cRejNsigmaTpc) { + tpcPIDPassed = true; } - } else { - tofPIDPassed = true; + } else if (!cUseRejNsigma) { + tpcPIDPassed = true; } } - if ((nsigmaCutCombinedKaon > 0) && ((candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < (nsigmaCutCombinedKaon * nsigmaCutCombinedKaon))) { - if (cUseRejNsigma) { - if (candidate.tofNSigmaPi() > cRejNsigmaTof && candidate.tofNSigmaPr() > cRejNsigmaTof) { + if (cByPassTOF && tpcPIDPassed) { + return true; + } + if (candidate.hasTOF()) { + if ((nsigmaCutCombinedKaon > 0) && ((candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < (nsigmaCutCombinedKaon * nsigmaCutCombinedKaon))) { + if (cUseRejNsigma) { + if (std::abs(candidate.tofNSigmaPi()) > cRejNsigmaTof && std::abs(candidate.tofNSigmaPr()) > cRejNsigmaTof) { + tofPIDPassed = true; + } + } else if (!cUseRejNsigma) { + tofPIDPassed = true; + } + } else if ((nsigmaCutCombinedKaon <= 0) && (std::abs(candidate.tofNSigmaKa()) < cMaxTOFnSigmaKaon)) { + if (cUseRejNsigma) { + if (std::abs(candidate.tofNSigmaPi()) > cRejNsigmaTof && std::abs(candidate.tofNSigmaPr()) > cRejNsigmaTof) { + tofPIDPassed = true; + } + } else if (!cUseRejNsigma) { tofPIDPassed = true; } - } else { - tofPIDPassed = true; } + } else { + tofPIDPassed = true; + } + if (tpcPIDPassed && tofPIDPassed) { + return true; } - } else { - tofPIDPassed = true; - } - if (tpcPIDPassed && tofPIDPassed) { - return true; } return false; } @@ -368,24 +488,43 @@ struct lambda1520analysis { vProtonTPCPIDpTintv.insert(vProtonTPCPIDpTintv.begin(), cMinPtcut); auto vProtonTPCPIDcuts = static_cast>(protonTPCPIDcuts); auto vProtonTOFPIDpTintv = static_cast>(protonTOFPIDpTintv); + auto vProtonTPCTOFCombinedpTintv = static_cast>(protonTPCTOFCombinedpTintv); + auto vProtonTPCTOFCombinedPIDcuts = static_cast>(protonTPCTOFCombinedPIDcuts); auto vProtonTOFPIDcuts = static_cast>(protonTOFPIDcuts); auto lengthOfprotonTPCPIDpTintv = static_cast(vProtonTPCPIDpTintv.size()); auto lengthOfprotonTOFPIDpTintv = static_cast(vProtonTOFPIDpTintv.size()); + auto lengthOfprotonTPCTOFCombinedPIDpTintv = static_cast(vProtonTPCTOFCombinedpTintv.size()); bool isTrk1Selected{true}; // For Proton candidate: if (candidate.hasTOF()) { - if (lengthOfprotonTOFPIDpTintv > 0) { - if (candidate.pt() > vProtonTOFPIDpTintv[lengthOfprotonTOFPIDpTintv - 1]) { - isTrk1Selected = false; - } else { - for (int i = 0; i < lengthOfprotonTOFPIDpTintv; i++) { - if (candidate.pt() < vProtonTOFPIDpTintv[i]) { - if (std::abs(candidate.tofNSigmaPr()) > vProtonTOFPIDcuts[i]) - isTrk1Selected = false; - if (std::abs(candidate.tpcNSigmaPr()) > cMaxTPCnSigmaProtonVETO) - isTrk1Selected = false; + if (pidCutType == 1) { + if (lengthOfprotonTOFPIDpTintv > 0) { + if (candidate.pt() > vProtonTOFPIDpTintv[lengthOfprotonTOFPIDpTintv - 1]) { + isTrk1Selected = false; + } else { + for (int i = 0; i < lengthOfprotonTOFPIDpTintv; i++) { + if (candidate.pt() < vProtonTOFPIDpTintv[i]) { + + if (std::abs(candidate.tofNSigmaPr()) > vProtonTOFPIDcuts[i]) + isTrk1Selected = false; + if (std::abs(candidate.tpcNSigmaPr()) > cMaxTPCnSigmaProtonVETO) + isTrk1Selected = false; + } + } + } + } + } else if (pidCutType == 2) { + if (lengthOfprotonTPCTOFCombinedPIDpTintv > 0) { + if (candidate.pt() > vProtonTPCTOFCombinedpTintv[lengthOfprotonTPCTOFCombinedPIDpTintv - 1]) { + isTrk1Selected = false; + } else { + for (int i = 0; i < lengthOfprotonTPCTOFCombinedPIDpTintv; i++) { + if (candidate.pt() < vProtonTPCTOFCombinedpTintv[i]) { + if ((candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr() + candidate.tofNSigmaPr() * candidate.tofNSigmaPr()) > (vProtonTPCTOFCombinedPIDcuts[i] * vProtonTPCTOFCombinedPIDcuts[i])) + isTrk1Selected = false; + } } } } @@ -414,24 +553,43 @@ struct lambda1520analysis { vKaonTPCPIDpTintv.insert(vKaonTPCPIDpTintv.begin(), cMinPtcut); auto vKaonTPCPIDcuts = static_cast>(kaonTPCPIDcuts); auto vKaonTOFPIDpTintv = static_cast>(kaonTOFPIDpTintv); + auto vKaonTPCTOFCombinedpTintv = static_cast>(kaonTPCTOFCombinedpTintv); + auto vKaonTPCTOFCombinedPIDcuts = static_cast>(kaonTPCTOFCombinedPIDcuts); auto vKaonTOFPIDcuts = static_cast>(kaonTOFPIDcuts); auto lengthOfkaonTPCPIDpTintv = static_cast(vKaonTPCPIDpTintv.size()); auto lengthOfkaonTOFPIDpTintv = static_cast(vKaonTOFPIDpTintv.size()); + auto lengthOfkaonTPCTOFCombinedPIDpTintv = static_cast(vKaonTPCTOFCombinedpTintv.size()); bool isTrk2Selected{true}; // For Kaon candidate: if (candidate.hasTOF()) { - if (lengthOfkaonTOFPIDpTintv > 0) { - if (candidate.pt() > vKaonTOFPIDpTintv[lengthOfkaonTOFPIDpTintv - 1]) { - isTrk2Selected = false; - } else { - for (int i = 0; i < lengthOfkaonTOFPIDpTintv; i++) { - if (candidate.pt() < vKaonTOFPIDpTintv[i]) { - if (std::abs(candidate.tofNSigmaKa()) > vKaonTOFPIDcuts[i]) - isTrk2Selected = false; - if (std::abs(candidate.tpcNSigmaKa()) > cMaxTPCnSigmaKaonVETO) - isTrk2Selected = false; + if (pidCutType == 1) { + if (lengthOfkaonTOFPIDpTintv > 0) { + if (candidate.pt() > vKaonTOFPIDpTintv[lengthOfkaonTOFPIDpTintv - 1]) { + isTrk2Selected = false; + } else { + for (int i = 0; i < lengthOfkaonTOFPIDpTintv; i++) { + if (candidate.pt() < vKaonTOFPIDpTintv[i]) { + + if (std::abs(candidate.tofNSigmaKa()) > vKaonTOFPIDcuts[i]) + isTrk2Selected = false; + if (std::abs(candidate.tpcNSigmaKa()) > cMaxTPCnSigmaKaonVETO) + isTrk2Selected = false; + } + } + } + } + } else if (pidCutType == 2) { + if (lengthOfkaonTPCTOFCombinedPIDpTintv > 0) { + if (candidate.pt() > vKaonTPCTOFCombinedpTintv[lengthOfkaonTPCTOFCombinedPIDpTintv - 1]) { + isTrk2Selected = false; + } else { + for (int i = 0; i < lengthOfkaonTPCTOFCombinedPIDpTintv; i++) { + if (candidate.pt() < vKaonTPCTOFCombinedpTintv[i]) { + if ((candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) > (vKaonTPCTOFCombinedPIDcuts[i] * vKaonTPCTOFCombinedPIDcuts[i])) + isTrk2Selected = false; + } } } } @@ -453,18 +611,141 @@ struct lambda1520analysis { return isTrk2Selected; } - template + // newly added to test + template + bool selectionPIDProtonFixed(const T& candidate) + { + if (candidate.hasTOF()) { + if (candidate.pt() < 1.5 && candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < 3.0 && std::abs(candidate.tofNSigmaPr()) < 4.0) { + return true; + } + if (candidate.pt() >= 1.5 && candidate.pt() < 2.0 && candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < 3.0 && candidate.tofNSigmaPr() > -3.0 && candidate.tofNSigmaPr() < 4.0) { + return true; + } + if (candidate.pt() >= 2.0 && candidate.pt() < 2.5 && candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < 3.0 && candidate.tofNSigmaPr() > -2.0 && candidate.tofNSigmaPr() < 4.0) { + return true; + } + if (candidate.pt() >= 2.5 && candidate.pt() < 3.0 && candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < 3.0 && candidate.tofNSigmaPr() > -1.5 && candidate.tofNSigmaPr() < 3.0) { + return true; + } + if (candidate.pt() >= 3.0 && candidate.pt() < 4.0 && candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < 3.0 && candidate.tofNSigmaPr() > -1.0 && candidate.tofNSigmaPr() < 2.0) { + return true; + } + } + if (!candidate.hasTOF()) { + if (candidate.pt() < 0.4 && std::abs(candidate.tpcNSigmaPr()) < 4.0) { + return true; + } + if (candidate.pt() >= 0.4 && candidate.pt() < 0.5 && std::abs(candidate.tpcNSigmaPr()) < 3.0) { + return true; + } + if (candidate.pt() >= 0.5 && candidate.pt() < 0.7 && candidate.tpcNSigmaPr() > -2.0 && candidate.tpcNSigmaPr() < 2.5) { + return true; + } + if (candidate.pt() >= 0.7 && candidate.pt() < 0.8 && candidate.tpcNSigmaPr() > -1.5 && candidate.tpcNSigmaPr() < 2.5) { + return true; + } + if (candidate.pt() >= 0.8 && candidate.pt() < 0.9 && candidate.tpcNSigmaPr() > -1.0 && candidate.tpcNSigmaPr() < 2.5) { + return true; + } + } + return false; + } + + template + bool selectionPIDKaonFixed(const T& candidate) + { + if (candidate.hasTOF()) { + if (candidate.pt() < 0.8 && candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < 3.0 && std::abs(candidate.tofNSigmaKa()) < 4.0) { + return true; + } + if (candidate.pt() >= 0.8 && candidate.pt() < 1.3 && candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < 3.0 && candidate.tofNSigmaKa() > -3.0 && candidate.tofNSigmaKa() < 4.0) { + return true; + } + if (candidate.pt() >= 1.3 && candidate.pt() < 1.6 && candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < 3.0 && candidate.tofNSigmaKa() > -2.0 && candidate.tofNSigmaKa() < 3.0) { + return true; + } + if (candidate.pt() >= 1.6 && candidate.pt() < 1.8 && candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < 3.0 && candidate.tofNSigmaKa() > -1.5 && candidate.tofNSigmaKa() < 2.5) { + return true; + } + if (candidate.pt() >= 1.8 && candidate.pt() < 2.5 && candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < 3.0 && candidate.tofNSigmaKa() > -1.0 && candidate.tofNSigmaKa() < 2.0) { + return true; + } + } + if (!candidate.hasTOF()) { + if (candidate.pt() < 0.3 && std::abs(candidate.tpcNSigmaKa()) < 3.0) { + return true; + } + if (candidate.pt() >= 0.3 && candidate.pt() < 0.4 && candidate.tpcNSigmaKa() > -2.0 && candidate.tpcNSigmaKa() < 2.5) { + return true; + } + if (candidate.pt() >= 0.4 && candidate.pt() < 0.5 && candidate.tpcNSigmaKa() > -1.0 && candidate.tpcNSigmaKa() < 2.5) { + return true; + } + } + return false; + } + + template + bool rejectPion(const T& candidate) + { + if (candidate.pt() > 1.0 && candidate.pt() < 2.0 && !candidate.hasTOF() && candidate.tpcNSigmaPi() < 2) { + return false; + } + return true; + } + + template void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksType& dTracks2) { auto multiplicity = collision.cent(); - TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; + // LOG(info) << "Before pass, Collision index:" << collision.index() << "multiplicity: " << collision.cent() << std::endl; + + // auto occupancyNo = collision.trackOccupancyInTimeRange(); + // if (applyOccupancyCut && occupancyNo < occupancyCut) { + // return; + // } + + // Multiplicity correlation calibration plots + if (isFilladditionalQA) { + if constexpr (IsData) { + histos.fill(HIST("MultCalib/centglopr"), multiplicity, dTracks1.size()); + histos.fill(HIST("MultCalib/centgloka"), multiplicity, dTracks2.size()); + histos.fill(HIST("MultCalib/GloPVpr"), dTracks1.size(), collision.multNTracksPV()); + histos.fill(HIST("MultCalib/GloPVka"), dTracks2.size(), collision.multNTracksPV()); + } + } + + if (additionalQAeventPlots) { + if constexpr (!IsMix) { + histos.fill(HIST("QAevent/hVertexZSameE"), collision.posZ()); + histos.fill(HIST("QAevent/hMultiplicityPercentSameE"), multiplicity); + histos.fill(HIST("TestME/hCollisionIndexSameE"), collision.globalIndex()); + histos.fill(HIST("TestME/hnTrksSameE"), dTracks1.size()); + } else { + histos.fill(HIST("QAevent/hVertexZMixedE"), collision.posZ()); + histos.fill(HIST("QAevent/hMultiplicityPercentMixedE"), multiplicity); + histos.fill(HIST("TestME/hCollisionIndexMixedE"), collision.globalIndex()); + histos.fill(HIST("TestME/hnTrksMixedE"), dTracks1.size()); + } + } + // LOG(info) << "After pass, Collision index:" << collision.index() << "multiplicity: " << collision.cent() << std::endl; + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance, ldaughterRot, lresonanceRot; - for (auto& [trk1, trk2] : combinations(CombinationsFullIndexPolicy(dTracks1, dTracks2))) { + for (const auto& [trk1, trk2] : combinations(CombinationsFullIndexPolicy(dTracks1, dTracks2))) { // Full index policy is needed to consider all possible combinations if (trk1.index() == trk2.index()) continue; // We need to run (0,1), (1,0) pairs as well. but same id pairs are not needed. + if (additionalQAeventPlots) { + if constexpr (IsData) { + histos.fill(HIST("TestME/hPairsCounterSameE"), 1.0); + } else if (IsMix) { + histos.fill(HIST("TestME/hPairsCounterMixedE"), 1.0); + } + } + // apply the track cut if (!trackCut(trk1) || !trackCut(trk2)) continue; @@ -481,24 +762,28 @@ struct lambda1520analysis { auto trk2NSigmaKaTPC = trk2.tpcNSigmaKa(); auto trk2NSigmaKaTOF = (isTrk2hasTOF) ? trk2.tofNSigmaKa() : -999.; + auto deltaEta = std::abs(trk1.eta() - trk2.eta()); + auto deltaPhi = std::abs(trk1.phi() - trk2.phi()); + deltaPhi = (deltaPhi > o2::constants::math::PI) ? (o2::constants::math::TwoPI - deltaPhi) : deltaPhi; + //// QA plots before the selection // --- Track QA all - if constexpr (!IsMix) { - histos.fill(HIST("QA/QAbefore/Track/TPC_Nsigma_pr_all"), trk1ptPr, trk1NSigmaPrTPC); + if constexpr (IsData) { + histos.fill(HIST("QA/QAbefore/Track/TPC_Nsigma_pr_all"), multiplicity, trk1ptPr, trk1NSigmaPrTPC); if (isTrk1hasTOF) { - histos.fill(HIST("QA/QAbefore/Track/TOF_Nsigma_pr_all"), trk1ptPr, trk1NSigmaPrTOF); + histos.fill(HIST("QA/QAbefore/Track/TOF_Nsigma_pr_all"), multiplicity, trk1ptPr, trk1NSigmaPrTOF); histos.fill(HIST("QA/QAbefore/Track/TOF_TPC_Map_pr_all"), trk1NSigmaPrTOF, trk1NSigmaPrTPC); } if (!isTrk1hasTOF) { - histos.fill(HIST("QA/QAbefore/Track/TPC_Nsigma_pr_only"), trk1ptPr, trk1NSigmaPrTPC); + histos.fill(HIST("QA/QAbefore/Track/TPConly_Nsigma_pr"), trk1ptPr, trk1NSigmaPrTPC); } - histos.fill(HIST("QA/QAbefore/Track/TPC_Nsigma_ka_all"), trk2ptKa, trk2NSigmaKaTPC); + histos.fill(HIST("QA/QAbefore/Track/TPC_Nsigma_ka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTPC); if (isTrk2hasTOF) { - histos.fill(HIST("QA/QAbefore/Track/TOF_Nsigma_ka_all"), trk2ptKa, trk2NSigmaKaTOF); + histos.fill(HIST("QA/QAbefore/Track/TOF_Nsigma_ka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTOF); histos.fill(HIST("QA/QAbefore/Track/TOF_TPC_Map_ka_all"), trk2NSigmaKaTOF, trk2NSigmaKaTPC); } if (!isTrk2hasTOF) { - histos.fill(HIST("QA/QAbefore/Track/TPC_Nsigma_ka_only"), trk2ptKa, trk2NSigmaKaTPC); + histos.fill(HIST("QA/QAbefore/Track/TPConly_Nsigma_ka"), trk2ptKa, trk2NSigmaKaTPC); } histos.fill(HIST("QA/QAbefore/Track/dcaZ"), trk1ptPr, trk1.dcaZ()); @@ -506,6 +791,10 @@ struct lambda1520analysis { histos.fill(HIST("QA/QAbefore/Track/TPC_CR"), trk1ptPr, trk1.tpcNClsCrossedRows()); histos.fill(HIST("QA/QAbefore/Track/pT"), trk1ptPr); histos.fill(HIST("QA/QAbefore/Track/eta"), trk1.eta()); + if (cfgCutsOnDaughters) { + histos.fill(HIST("QAbefore/deltaEta"), deltaEta); + histos.fill(HIST("QAbefore/deltaPhi"), deltaPhi); + } } //// Apply the pid selection @@ -513,20 +802,25 @@ struct lambda1520analysis { continue; if (cUseOnlyTOFTrackKa && !isTrk2hasTOF) continue; + if (crejectPion && rejectPion(trk2)) + continue; if (cOldPIDcut) { if (!selectionoldPIDProton(trk1) || !selectionoldPIDKaon(trk2)) continue; - } else { + } else if (!cOldPIDcut && !fixedPIDcut) { if (!selectionnewPIDProton(trk1) || !selectionnewPIDKaon(trk2)) continue; + } else if (fixedPIDcut) { + if (!selectionPIDProtonFixed(trk1) || !selectionPIDKaonFixed(trk2)) + continue; } //// QA plots after the selection - if constexpr (!IsMix) { // --- PID QA Proton - histos.fill(HIST("QA/QAafter/Proton/TPC_Nsigma_pr_all"), trk1ptPr, trk1NSigmaPrTPC); + if constexpr (IsData) { // --- PID QA Proton + histos.fill(HIST("QA/QAafter/Proton/TPC_Nsigma_pr_all"), multiplicity, trk1ptPr, trk1NSigmaPrTPC); histos.fill(HIST("QA/QAafter/Proton/TPC_Signal_pr_all"), trk1ptPr, trk1.tpcSignal()); if (isTrk1hasTOF) { - histos.fill(HIST("QA/QAafter/Proton/TOF_Nsigma_pr_all"), trk1ptPr, trk1NSigmaPrTOF); + histos.fill(HIST("QA/QAafter/Proton/TOF_Nsigma_pr_all"), multiplicity, trk1ptPr, trk1NSigmaPrTOF); histos.fill(HIST("QA/QAafter/Proton/TOF_TPC_Map_pr_all"), trk1NSigmaPrTOF, trk1NSigmaPrTPC); } if (!isTrk1hasTOF) { @@ -539,10 +833,10 @@ struct lambda1520analysis { histos.fill(HIST("QA/QAafter/Proton/eta"), trk1.eta()); // --- PID QA Kaon - histos.fill(HIST("QA/QAafter/Kaon/TPC_Nsigma_ka_all"), trk2ptKa, trk2NSigmaKaTPC); + histos.fill(HIST("QA/QAafter/Kaon/TPC_Nsigma_ka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTPC); histos.fill(HIST("QA/QAafter/Kaon/TPC_Signal_ka_all"), trk2ptKa, trk2.tpcSignal()); if (isTrk2hasTOF) { - histos.fill(HIST("QA/QAafter/Kaon/TOF_Nsigma_ka_all"), trk2ptKa, trk2NSigmaKaTOF); + histos.fill(HIST("QA/QAafter/Kaon/TOF_Nsigma_ka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTOF); histos.fill(HIST("QA/QAafter/Kaon/TOF_TPC_Map_ka_all"), trk2NSigmaKaTOF, trk2NSigmaKaTPC); } if (!isTrk2hasTOF) { @@ -553,34 +847,19 @@ struct lambda1520analysis { histos.fill(HIST("QA/QAafter/Kaon/TPC_CR"), trk2ptKa, trk2.tpcNClsCrossedRows()); histos.fill(HIST("QA/QAafter/Kaon/pT"), trk2ptKa); histos.fill(HIST("QA/QAafter/Kaon/eta"), trk2.eta()); + if (cfgCutsOnDaughters) { + histos.fill(HIST("QAafter/deltaEta"), deltaEta); + histos.fill(HIST("QAafter/deltaPhi"), deltaPhi); + } + if (isFilladditionalQA) { + // TPCncluster distributions + histos.fill(HIST("TPCncluster/TPCnclusterpr"), trk1.tpcNClsFound()); + histos.fill(HIST("TPCncluster/TPCnclusterka"), trk2.tpcNClsFound()); + histos.fill(HIST("TPCncluster/TPCnclusterPhipr"), trk1.tpcNClsFound(), trk1.phi()); + histos.fill(HIST("TPCncluster/TPCnclusterPhika"), trk2.tpcNClsFound(), trk2.phi()); + } } - // TPCncluster distributions - histos.fill(HIST("TPCncluster/TPCnclusterpr"), trk1.tpcNClsFound()); - histos.fill(HIST("TPCncluster/TPCnclusterka"), trk2.tpcNClsFound()); - histos.fill(HIST("TPCncluster/TPCnclusterPhipr"), trk1.tpcNClsFound(), trk1.phi()); - histos.fill(HIST("TPCncluster/TPCnclusterPhika"), trk2.tpcNClsFound(), trk2.phi()); - - // Multiplicity correlation calibration plots - int counterglo1 = 0; - int counterglo2 = 0; - int counterpv1 = 0; - int counterpv2 = 0; - - if (trk1.isGlobalTrack()) - counterglo1 = 1; - if (trk2.isGlobalTrack()) - counterglo2 = 1; - if (trk1.isPrimaryTrack()) - counterpv1 = 1; - if (trk2.isPrimaryTrack()) - counterpv2 = 1; - - histos.fill(HIST("MultCalib/centglopr"), multiplicity, counterglo1); - histos.fill(HIST("MultCalib/centgloka"), multiplicity, counterglo2); - histos.fill(HIST("MultCalib/GloPVpr"), counterglo1, counterpv1); - histos.fill(HIST("MultCalib/GloPVka"), counterglo2, counterpv2); - // Apply kinematic cuts. if (cKinCuts) { TVector3 v1(trk1.px(), trk1.py(), trk1.pz()); @@ -591,33 +870,86 @@ struct lambda1520analysis { } //// Resonance reconstruction - lDecayDaughter1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massPr); - lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massKa); + lDecayDaughter1.SetPtEtaPhiM(trk1.pt(), trk1.eta(), trk1.phi(), massPr); + lDecayDaughter2.SetPtEtaPhiM(trk2.pt(), trk2.eta(), trk2.phi(), massKa); lResonance = lDecayDaughter1 + lDecayDaughter2; // Rapidity cut - if (abs(lResonance.Rapidity()) > 0.5) + if (std::abs(lResonance.Rapidity()) > 0.5) continue; + + if (cfgCutsOnMother) { + if (lResonance.Pt() >= cMaxPtMotherCut) // excluding candidates in overflow + continue; + if (lResonance.M() >= cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } + + if (cfgCutsOnDaughters) { + if (deltaEta >= cMaxDeltaEtaCut) + continue; + if (deltaPhi >= cMaxDeltaPhiCut) + continue; + + if constexpr (!IsMix) { + histos.fill(HIST("QAafter/EtaPrafter"), trk1.eta()); + histos.fill(HIST("QAafter/PhiPrafter"), trk1.phi()); + histos.fill(HIST("QAafter/EtaKaafter"), trk2.eta()); + histos.fill(HIST("QAafter/PhiKaafter"), trk2.phi()); + histos.fill(HIST("QAafter/deltaEtaafter"), deltaEta); + histos.fill(HIST("QAafter/deltaPhiafter"), deltaPhi); + } + } + //// Un-like sign pair only if (trk1.sign() * trk2.sign() < 0) { - if constexpr (!IsMix) { - histos.fill(HIST("Result/Data/lambda1520invmass"), lResonance.M()); - histos.fill(HIST("Result/Data/h3lambda1520invmass"), collision.cent(), lResonance.Pt(), lResonance.M()); + if constexpr (IsData) { + if (isCalcRotBkg) { + for (int i = 0; i < cNofRotations; i++) { + float theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / rotationalcut, o2::constants::math::PI + o2::constants::math::PI / rotationalcut); + ldaughterRot.SetPtEtaPhiM(trk2.pt(), trk2.eta(), trk2.phi() + theta2, massKa); // for rotated background + lresonanceRot = lDecayDaughter1 + ldaughterRot; + histos.fill(HIST("Result/Data/h3lambda1520InvMassRotation"), multiplicity, lresonanceRot.Pt(), lresonanceRot.M()); + } + } + + if (trk1.sign() < 0) { + if (invmass1D) { + histos.fill(HIST("Result/Data/lambda1520invmass"), lResonance.M()); + } + histos.fill(HIST("Result/Data/h3lambda1520invmass"), multiplicity, lResonance.Pt(), lResonance.M()); + } else if (trk1.sign() > 0) { + if (invmass1D) { + histos.fill(HIST("Result/Data/antilambda1520invmass"), lResonance.M()); + } + histos.fill(HIST("Result/Data/h3antilambda1520invmass"), multiplicity, lResonance.Pt(), lResonance.M()); + } if (cEtaAssym && trk1.eta() > 0.2 && trk1.eta() < 0.8 && trk2.eta() > 0.2 && trk2.eta() < 0.8) { // Eta-range will be updated histos.fill(HIST("Result/Data/hlambda1520invmassUnlikeSignAside"), lResonance.M()); - histos.fill(HIST("Result/Data/h3lambda1520invmassUnlikeSignAside"), collision.cent(), lResonance.Pt(), lResonance.M()); + histos.fill(HIST("Result/Data/h3lambda1520invmassUnlikeSignAside"), multiplicity, lResonance.Pt(), lResonance.M()); } else if (cEtaAssym && trk1.eta() > -0.6 && trk1.eta() < 0.0 && trk2.eta() > -0.6 && trk2.eta() < 0.0) { // Eta-range will be updated histos.fill(HIST("Result/Data/hlambda1520invmassUnlikeSignCside"), lResonance.M()); - histos.fill(HIST("Result/Data/h3lambda1520invmassUnlikeSignCside"), collision.cent(), lResonance.Pt(), lResonance.M()); + histos.fill(HIST("Result/Data/h3lambda1520invmassUnlikeSignCside"), multiplicity, lResonance.Pt(), lResonance.M()); } - } else { - histos.fill(HIST("Result/Data/lambda1520invmassME"), lResonance.M()); - histos.fill(HIST("Result/Data/h3lambda1520invmassME"), collision.cent(), lResonance.Pt(), lResonance.M()); + } else if (IsMix) { + if (invmass1D) { + histos.fill(HIST("Result/Data/lambda1520invmassME"), lResonance.M()); + } + histos.fill(HIST("Result/Data/h3lambda1520invmassME"), multiplicity, lResonance.Pt(), lResonance.M()); if (cEtaAssym && trk1.eta() > 0.2 && trk1.eta() < 0.8 && trk2.eta() > 0.2 && trk2.eta() < 0.8) { // Eta-range will be updated histos.fill(HIST("Result/Data/hlambda1520invmassMixedAside"), lResonance.M()); - histos.fill(HIST("Result/Data/h3lambda1520invmassMixedAside"), collision.cent(), lResonance.Pt(), lResonance.M()); + histos.fill(HIST("Result/Data/h3lambda1520invmassMixedAside"), multiplicity, lResonance.Pt(), lResonance.M()); } else if (cEtaAssym && trk1.eta() > -0.6 && trk1.eta() < 0.0 && trk2.eta() > -0.6 && trk2.eta() < 0.0) { // Eta-range will be updated histos.fill(HIST("Result/Data/hlambda1520invmassMixedCside"), lResonance.M()); - histos.fill(HIST("Result/Data/h3lambda1520invmassMixedCside"), collision.cent(), lResonance.Pt(), lResonance.M()); + histos.fill(HIST("Result/Data/h3lambda1520invmassMixedCside"), multiplicity, lResonance.Pt(), lResonance.M()); + } + if (additionalMEPlots) { + if (trk1.sign() < 0) { + histos.fill(HIST("Result/Data/lambda1520invmassME_DS"), lResonance.M()); + histos.fill(HIST("Result/Data/h3lambda1520invmassME_DS"), multiplicity, lResonance.Pt(), lResonance.M()); + } else if (trk1.sign() > 0) { + histos.fill(HIST("Result/Data/lambda1520invmassME_DSAnti"), lResonance.M()); + histos.fill(HIST("Result/Data/h3lambda1520invmassME_DSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + } } } @@ -625,109 +957,152 @@ struct lambda1520analysis { if constexpr (IsMC) { // LOG(info) << "trk1 pdgcode: " << trk1.pdgCode() << "trk2 pdgcode: " << trk2.pdgCode() << std::endl; - if (abs(trk1.pdgCode()) != 2212 || abs(trk2.pdgCode()) != 321) + if (std::abs(trk1.pdgCode()) != 2212 || std::abs(trk2.pdgCode()) != 321) continue; if (trk1.motherId() != trk2.motherId()) // Same mother continue; - if (abs(trk1.motherPDG()) != 3124) + if (std::abs(trk1.motherPDG()) != 102134) continue; // Track selection check. - histos.fill(HIST("QA/MC/trkDCAxy_pr"), trk1.dcaXY()); - histos.fill(HIST("QA/MC/trkDCAxy_ka"), trk2.dcaXY()); - histos.fill(HIST("QA/MC/trkDCAz_pr"), trk1.dcaZ()); - histos.fill(HIST("QA/MC/trkDCAz_ka"), trk2.dcaZ()); + histos.fill(HIST("QA/MC/trkDCAxy_pr"), trk1ptPr, trk1.dcaXY()); + histos.fill(HIST("QA/MC/trkDCAxy_ka"), trk2ptKa, trk2.dcaXY()); + histos.fill(HIST("QA/MC/trkDCAz_pr"), trk1ptPr, trk1.dcaZ()); + histos.fill(HIST("QA/MC/trkDCAz_ka"), trk2ptKa, trk2.dcaZ()); + + histos.fill(HIST("QA/MC/TPC_Nsigma_pr_all"), multiplicity, trk1ptPr, trk1NSigmaPrTPC); + if (isTrk1hasTOF) { + histos.fill(HIST("QA/MC/TOF_Nsigma_pr_all"), multiplicity, trk1ptPr, trk1NSigmaPrTOF); + } + histos.fill(HIST("QA/MC/TPC_Nsigma_ka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTPC); + if (isTrk2hasTOF) { + histos.fill(HIST("QA/MC/TOF_Nsigma_ka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTOF); + } // MC histograms if (trk1.motherPDG() > 0) { - histos.fill(HIST("Result/MC/lambda1520Reco"), lResonance.Pt()); - histos.fill(HIST("Result/MC/hlambda1520Recoinvmass"), lResonance.M()); - histos.fill(HIST("Result/MC/h3lambda1520Recoinvmass"), collision.cent(), lResonance.Pt(), lResonance.M()); + if (cAdditionalMCPlots) { + histos.fill(HIST("Result/MC/lambda1520Reco"), lResonance.Pt(), multiplicity); + histos.fill(HIST("Result/MC/hlambda1520Recoinvmass"), lResonance.M()); + } + histos.fill(HIST("Result/MC/h3lambda1520Recoinvmass"), multiplicity, lResonance.Pt(), lResonance.M()); } else { - histos.fill(HIST("Result/MC/antilambda1520Reco"), lResonance.Pt()); - histos.fill(HIST("Result/MC/hantilambda1520Recoinvmass"), lResonance.M()); - histos.fill(HIST("Result/MC/h3antilambda1520Recoinvmass"), collision.cent(), lResonance.Pt(), lResonance.M()); + if (cAdditionalMCPlots) { + histos.fill(HIST("Result/MC/antilambda1520Reco"), lResonance.Pt(), multiplicity); + histos.fill(HIST("Result/MC/hantilambda1520Recoinvmass"), lResonance.M()); + } + histos.fill(HIST("Result/MC/h3antilambda1520Recoinvmass"), multiplicity, lResonance.Pt(), lResonance.M()); } } } else { - if constexpr (!IsMix) { + if constexpr (IsData) { if (cEtaAssym && trk1.eta() > 0.2 && trk1.eta() < 0.8 && trk2.eta() > 0.2 && trk2.eta() < 0.8) { // Eta-range will be updated histos.fill(HIST("Result/Data/hlambda1520invmassLikeSignAside"), lResonance.M()); - histos.fill(HIST("Result/Data/h3lambda1520invmassLikeSignAside"), collision.cent(), lResonance.Pt(), lResonance.M()); + histos.fill(HIST("Result/Data/h3lambda1520invmassLikeSignAside"), multiplicity, lResonance.Pt(), lResonance.M()); } else if (cEtaAssym && trk1.eta() > -0.6 && trk1.eta() < 0.0 && trk2.eta() > -0.6 && trk2.eta() < 0.0) { // Eta-range will be updated histos.fill(HIST("Result/Data/hlambda1520invmassLikeSignCside"), lResonance.M()); - histos.fill(HIST("Result/Data/h3lambda1520invmassLikeSignCside"), collision.cent(), lResonance.Pt(), lResonance.M()); + histos.fill(HIST("Result/Data/h3lambda1520invmassLikeSignCside"), multiplicity, lResonance.Pt(), lResonance.M()); } // Like sign pair ++ if (trk1.sign() > 0) { - histos.fill(HIST("Result/Data/lambda1520invmassLSPP"), lResonance.M()); - histos.fill(HIST("Result/Data/h3lambda1520invmassLSPP"), collision.cent(), lResonance.Pt(), lResonance.M()); + if (invmass1D) { + histos.fill(HIST("Result/Data/lambda1520invmassLSPP"), lResonance.M()); + } + histos.fill(HIST("Result/Data/h3lambda1520invmassLSPP"), multiplicity, lResonance.Pt(), lResonance.M()); } else { // Like sign pair -- - histos.fill(HIST("Result/Data/lambda1520invmassLSMM"), lResonance.M()); - histos.fill(HIST("Result/Data/h3lambda1520invmassLSMM"), collision.cent(), lResonance.Pt(), lResonance.M()); + if (invmass1D) { + histos.fill(HIST("Result/Data/lambda1520invmassLSMM"), lResonance.M()); + } + histos.fill(HIST("Result/Data/h3lambda1520invmassLSMM"), multiplicity, lResonance.Pt(), lResonance.M()); } } } } } - void processData(aod::ResoCollision& collision, + void processData(aod::ResoCollision const& collision, aod::ResoTracks const& resotracks) { - fillHistograms(collision, resotracks, resotracks); + if (additionalQAeventPlots) + histos.fill(HIST("QAevent/hEvtCounterSameE"), 1.0); + fillHistograms(collision, resotracks, resotracks); } - PROCESS_SWITCH(lambda1520analysis, processData, "Process Event for data without partition", false); + PROCESS_SWITCH(Lambda1520analysis, processData, "Process Event for data without partition", false); - void processMC(aod::ResoCollision& collision, + void processMC(ResoMCCols::iterator const& collision, soa::Join const& resotracks) { - fillHistograms(collision, resotracks, resotracks); + if (!collision.isInAfterAllCuts() || (std::abs(collision.posZ()) > cZvertCutMC)) // MC event selection, all cuts missing vtx cut + return; + fillHistograms(collision, resotracks, resotracks); } - PROCESS_SWITCH(lambda1520analysis, processMC, "Process Event for MC Light without partition", false); + PROCESS_SWITCH(Lambda1520analysis, processMC, "Process Event for MC Light without partition", false); - void processMCTrue(aod::ResoMCParents& resoParents) + void processMCTrue(ResoMCCols::iterator const& collision, aod::ResoMCParents const& resoParents) { + auto multiplicity = collision.cent(); // Not related to the real collisions - for (auto& part : resoParents) { // loop over all MC particles - if (abs(part.pdgCode()) != 3124) // Lambda1520(0) + for (const auto& part : resoParents) { // loop over all MC particles + if (std::abs(part.pdgCode()) != 102134) // Lambda1520(0) continue; - if (abs(part.y()) > 0.5) // rapidity cut + if (std::abs(part.y()) > 0.5) // rapidity cut continue; - bool pass1 = false; - bool pass2 = false; - if (abs(part.daughterPDG1()) == 321 || abs(part.daughterPDG2()) == 321) { // At least one decay to Kaon - pass2 = true; - } - if (abs(part.daughterPDG1()) == 2212 || abs(part.daughterPDG2()) == 2212) { // At least one decay to Proton - pass1 = true; - } + bool pass1 = std::abs(part.daughterPDG1()) == 321 || std::abs(part.daughterPDG2()) == 321; // At least one decay to Kaon + bool pass2 = std::abs(part.daughterPDG1()) == 2212 || std::abs(part.daughterPDG2()) == 2212; // At least one decay to Proton + if (!pass1 || !pass2) // If we have both decay products continue; - histos.fill(HIST("Result/MC/GenTruelambda1520pt"), part.pt()); - if (part.pdgCode() > 0) - histos.fill(HIST("Result/MC/Genlambda1520pt"), part.pt()); - else - histos.fill(HIST("Result/MC/Genantilambda1520pt"), part.pt()); + + if (collision.isVtxIn10()) // INEL10 + { + if (part.pdgCode() > 0) + histos.fill(HIST("Result/MC/Genlambda1520pt"), 0, part.pt(), multiplicity); + else + histos.fill(HIST("Result/MC/Genantilambda1520pt"), 0, part.pt(), multiplicity); + } + if (collision.isVtxIn10() && collision.isInSel8()) // INEL>10, vtx10 + { + if (part.pdgCode() > 0) + histos.fill(HIST("Result/MC/Genlambda1520pt"), 1, part.pt(), multiplicity); + else + histos.fill(HIST("Result/MC/Genantilambda1520pt"), 1, part.pt(), multiplicity); + } + if (collision.isVtxIn10() && collision.isTriggerTVX()) // vtx10, TriggerTVX + { + if (part.pdgCode() > 0) + histos.fill(HIST("Result/MC/Genlambda1520pt"), 2, part.pt(), multiplicity); + else + histos.fill(HIST("Result/MC/Genantilambda1520pt"), 2, part.pt(), multiplicity); + } + if (collision.isInAfterAllCuts()) // after all event selection + { + if (part.pdgCode() > 0) + histos.fill(HIST("Result/MC/Genlambda1520pt"), 3, part.pt(), multiplicity); + else + histos.fill(HIST("Result/MC/Genantilambda1520pt"), 3, part.pt(), multiplicity); + } } } - PROCESS_SWITCH(lambda1520analysis, processMCTrue, "Process Event for MC only", false); + PROCESS_SWITCH(Lambda1520analysis, processMCTrue, "Process Event for MC only", false); // Processing Event Mixing using BinningTypeVtxZT0M = ColumnBinningPolicy; - void processME(o2::aod::ResoCollisions& collisions, aod::ResoTracks const& resotracks) + void processME(o2::aod::ResoCollisions const& collisions, aod::ResoTracks const& resotracks) { auto tracksTuple = std::make_tuple(resotracks); - BinningTypeVtxZT0M colBinning{{CfgVtxBins, CfgMultBins}, true}; + BinningTypeVtxZT0M colBinning{{cfgVtxBins, cfgMultBins}, true}; SameKindPair pairs{colBinning, nEvtMixing, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip - for (auto& [collision1, tracks1, collision2, tracks2] : pairs) { - fillHistograms(collision1, tracks1, tracks2); + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (additionalQAeventPlots) + histos.fill(HIST("QAevent/hEvtCounterMixedE"), 1.0); + fillHistograms(collision1, tracks1, tracks2); } }; - PROCESS_SWITCH(lambda1520analysis, processME, "Process EventMixing light without partition", false); + PROCESS_SWITCH(Lambda1520analysis, processME, "Process EventMixing light without partition", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"lf-lambda1520analysis"})}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/Resonances/lambdav2.cxx b/PWGLF/Tasks/Resonances/lambdav2.cxx new file mode 100644 index 00000000000..ae8c1b6446c --- /dev/null +++ b/PWGLF/Tasks/Resonances/lambdav2.cxx @@ -0,0 +1,394 @@ +// 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. +// Particle flow task +// prottay.das@cern.ch + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TRandom3.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" +#include "TF1.h" + +// #include "Common/DataModel/Qvectors.h" +#include "PWGLF/DataModel/SPCalibrationTables.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/TrackSelection.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Common/DataModel/FT0Corrected.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +struct lambdav2 { + + int mRunNumber; + int multEstimator; + float d_bz; + Service ccdb; + Service pdg; + + // fill output + Configurable additionalEvSel{"additionalEvSel", false, "additionalEvSel"}; + Configurable additionalEvSel2{"additionalEvSel2", false, "additionalEvSel2"}; + Configurable additionalEvSel3{"additionalEvSel3", false, "additionalEvSel3"}; + Configurable correction1{"correction1", false, "fill histograms including corrections 1"}; + Configurable correction2{"correction2", false, "fill histograms including corrections 2"}; + Configurable QA{"QA", false, "flag for QA"}; + Configurable mycut{"mycut", false, "select tracks based on my cuts"}; + Configurable tofhit{"tofhit", true, "select tracks based on tof hit"}; + Configurable globalpt{"globalpt", true, "select tracks based on pt global vs tpc"}; + Configurable useprofile{"useprofile", 3, "flag to select profile vs Sparse"}; + Configurable QxyNbins{"QxyNbins", 100, "Number of bins in QxQy histograms"}; + Configurable lbinQxy{"lbinQxy", -5.0, "lower bin value in QxQy histograms"}; + Configurable hbinQxy{"hbinQxy", 5.0, "higher bin value in QxQy histograms"}; + Configurable cfgMaxOccupancy{"cfgMaxOccupancy", 1000, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable cfgMinOccupancy{"cfgMinOccupancy", 0, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + + // events + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutCentralityMax{"cfgCutCentralityMax", 50.0f, "Accepted maximum Centrality"}; + Configurable cfgCutCentralityMin{"cfgCutCentralityMin", 30.0f, "Accepted minimum Centrality"}; + // proton track cut + Configurable confRapidity{"confRapidity", 0.8, "cut on Rapidity"}; + Configurable cfgCutPT{"cfgCutPT", 0.15, "PT cut on daughter track"}; + Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; + Configurable cfgCutDCAxy{"cfgCutDCAxy", 0.1f, "DCAxy range for tracks"}; + Configurable cfgCutDCAz{"cfgCutDCAz", 0.1f, "DCAz range for tracks"}; + Configurable cfgITScluster{"cfgITScluster", 5, "Number of ITS cluster"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; + Configurable isPVContributor{"isPVContributor", true, "is PV contributor"}; + Configurable checkwithpub{"checkwithpub", true, "checking results with published"}; + Configurable nsigmaCutTPCPi{"nsigmaCutTPCPi", 3, "PID selections for Pions"}; + Configurable nsigmaCutTPCKa{"nsigmaCutTPCKa", 3, "PID selections for Kaons"}; + Configurable nsigmaCutTPCPr{"nsigmaCutTPCPr", 3, "PID selections for Protons"}; + Configurable nsigmaCutTOFPi{"nsigmaCutTOFPi", 3, "PID selections for TOF Pions"}; + Configurable nsigmaCutTOFKa{"nsigmaCutTOFKa", 3, "PID selections for TOF Kaons"}; + Configurable nsigmaCutTOFPr{"nsigmaCutTOFPr", 3, "PID selections for TOF Protons"}; + Configurable cfgCutTOFBeta{"cfgCutTOFBeta", 0, "Beta selections for Particles"}; + + Configurable CentNbins{"CentNbins", 16, "Number of bins in cent histograms"}; + Configurable lbinCent{"lbinCent", 0.0, "lower bin value in cent histograms"}; + Configurable hbinCent{"hbinCent", 80.0, "higher bin value in cent histograms"}; + Configurable SANbins{"SANbins", 20, "Number of bins in costhetastar"}; + Configurable lbinSA{"lbinSA", -1.0, "lower bin value in costhetastar histograms"}; + Configurable hbinSA{"hbinSA", 1.0, "higher bin value in costhetastar histograms"}; + Configurable PolNbins{"PolNbins", 20, "Number of bins in polarisation"}; + Configurable lbinPol{"lbinPol", -1.0, "lower bin value in #phi-#psi histograms"}; + Configurable hbinPol{"hbinPol", 1.0, "higher bin value in #phi-#psi histograms"}; + Configurable IMNbins{"IMNbins", 100, "Number of bins in invariant mass"}; + Configurable lbinIM{"lbinIM", 1.0, "lower bin value in IM histograms"}; + Configurable hbinIM{"hbinIM", 1.2, "higher bin value in IM histograms"}; + Configurable ptNbins{"ptNbins", 50, "Number of bins in pt"}; + Configurable lbinpt{"lbinpt", 0.0, "lower bin value in pt histograms"}; + Configurable hbinpt{"hbinpt", 10.0, "higher bin value in pt histograms"}; + Configurable resNbins{"resNbins", 50, "Number of bins in reso"}; + Configurable lbinres{"lbinres", 0.0, "lower bin value in reso histograms"}; + Configurable hbinres{"hbinres", 10.0, "higher bin value in reso histograms"}; + Configurable etaNbins{"etaNbins", 20, "Number of bins in eta"}; + Configurable lbineta{"lbineta", -1.0, "lower bin value in eta histograms"}; + Configurable hbineta{"hbineta", 1.0, "higher bin value in eta histograms"}; + Configurable spNbins{"spNbins", 2000, "Number of bins in sp"}; + Configurable lbinsp{"lbinsp", -1.0, "lower bin value in sp histograms"}; + Configurable hbinsp{"hbinsp", 1.0, "higher bin value in sp histograms"}; + Configurable phiNbins{"phiNbins", 30, "Number of bins in phi"}; + + ConfigurableAxis configcentAxis{"configcentAxis", {VARIABLE_WIDTH, 0.0, 10.0, 40.0, 80.0}, "Cent V0M"}; + ConfigurableAxis configthnAxispT{"configthnAxisPt", {VARIABLE_WIDTH, 0.2, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.5, 8.0, 10.0, 100.0}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis configetaAxis{"configetaAxis", {VARIABLE_WIDTH, -0.8, -0.4, -0.2, 0, 0.2, 0.4, 0.8}, "Eta"}; + ConfigurableAxis configthnAxisPol{"configthnAxisPol", {VARIABLE_WIDTH, -1.0, -0.6, -0.2, 0, 0.2, 0.4, 0.8}, "Pol"}; + ConfigurableAxis configphiAxis{"configphiAxis", {VARIABLE_WIDTH, 0.0, 0.2, 0.4, 0.8, 1.0, 2.0, 2.5, 3.0, 4.0, 5.0, 5.5, 6.28}, "PhiAxis"}; + + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + AxisSpec thnAxispT{ptNbins, lbinpt, hbinpt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec thnAxisRap{100, -0.5, 0.5, "Rapidity"}; + AxisSpec thnAxisres{resNbins, lbinres, hbinres, "Reso"}; + AxisSpec thnAxisInvMass{IMNbins, lbinIM, hbinIM, "#it{M} (GeV/#it{c}^{2})"}; + AxisSpec thnAxisPol{PolNbins, lbinPol, hbinPol, "Sin(#phi - #psi)"}; + AxisSpec thnAxisCosThetaStar{SANbins, lbinSA, hbinSA, "SA"}; + AxisSpec centAxis = {CentNbins, lbinCent, hbinCent, "V0M (%)"}; + AxisSpec etaAxis = {etaNbins, lbineta, hbineta, "Eta"}; + AxisSpec spAxis = {spNbins, lbinsp, hbinsp, "Sp"}; + AxisSpec qxZDCAxis = {QxyNbins, lbinQxy, hbinQxy, "Qx"}; + AxisSpec phiAxis = {phiNbins, 0.0, 6.28, "phi-phiStar"}; + /* + histos.add("hpuxQxpvscentpteta", "hpuxQxpvscentpteta", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpuyQypvscentpteta", "hpuyQypvscentpteta", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpuxQxtvscentpteta", "hpuxQxtvscentpteta", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpuyQytvscentpteta", "hpuyQytvscentpteta", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpuxyQxytvscentpteta", "hpuxyQxytvscentpteta", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpuxyQxypvscentpteta", "hpuxyQxypvscentpteta", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true);*/ + histos.add("hpoddv1vscentpteta", "hpoddv1vscentpteta", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpevenv1vscentpteta", "hpevenv1vscentpteta", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpoddv1vscentptetakaon", "hpoddv1vscentptetakaon", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpevenv1vscentptetakaon", "hpevenv1vscentptetakaon", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpoddv1vscentptetaproton", "hpoddv1vscentptetaproton", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpevenv1vscentptetaproton", "hpevenv1vscentptetaproton", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + + /* histos.add("hpuxQxpvscentptetaneg", "hpuxQxpvscentptetaneg", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpuyQypvscentptetaneg", "hpuyQypvscentptetaneg", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpuxQxtvscentptetaneg", "hpuxQxtvscentptetaneg", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpuyQytvscentptetaneg", "hpuyQytvscentptetaneg", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpuxyQxytvscentptetaneg", "hpuxyQxytvscentptetaneg", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpuxyQxypvscentptetaneg", "hpuxyQxypvscentptetaneg", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true);*/ + histos.add("hpoddv1vscentptetaneg", "hpoddv1vscentptetaneg", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpevenv1vscentptetaneg", "hpevenv1vscentptetaneg", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpoddv1vscentptetakaonneg", "hpoddv1vscentptetakaonneg", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpevenv1vscentptetakaonneg", "hpevenv1vscentptetakaonneg", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpoddv1vscentptetaprotonneg", "hpoddv1vscentptetaprotonneg", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + histos.add("hpevenv1vscentptetaprotonneg", "hpevenv1vscentptetaprotonneg", HistType::kTHnSparseF, {centAxis, thnAxispT, etaAxis, spAxis}, true); + + histos.add("hpQxtQxpvscent", "hpQxtQxpvscent", HistType::kTHnSparseF, {centAxis, spAxis}, true); + histos.add("hpQytQypvscent", "hpQytQypvscent", HistType::kTHnSparseF, {centAxis, spAxis}, true); + histos.add("hpQxytpvscent", "hpQxytpvscent", HistType::kTHnSparseF, {centAxis, spAxis}, true); + histos.add("hpQxtQypvscent", "hpQxtQypvscent", HistType::kTHnSparseF, {centAxis, spAxis}, true); + histos.add("hpQxpQytvscent", "hpQxpQytvscent", HistType::kTHnSparseF, {centAxis, spAxis}, true); + + histos.add("hCentrality", "Centrality distribution", kTH1F, {{centAxis}}); + } + + template + bool selectionTrack(const T& candidate) + { + + if (mycut) { + if (!candidate.isGlobalTrack() || !candidate.isPVContributor() || !(candidate.itsNCls() > cfgITScluster) || !(candidate.tpcNClsFound() > cfgTPCcluster) || !(candidate.itsNClsInnerBarrel() >= 1)) { + return false; + } + } else { + if (!(candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsFound() > cfgTPCcluster && candidate.itsNClsInnerBarrel() >= 1)) { + return false; + } + } + return true; + } + + double GetPhiInRange(double phi) + { + double result = phi; + while (result < 0) { + result = result + 2. * TMath::Pi(); + } + while (result > 2. * TMath::Pi()) { + result = result - 2. * TMath::Pi(); + } + return result; + } + + template + bool SelectionPID(const T& candidate, int PID) + { + if (PID == 0) // pion + { + auto combPIDPi = TMath::Sqrt(TMath::Abs(candidate.tofNSigmaPi() * candidate.tofNSigmaPi() + candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi())); + if (!candidate.hasTOF() && candidate.tpcInnerParam() < 0.6 && TMath::Abs(candidate.tpcNSigmaPi()) < nsigmaCutTPCPi) { + return true; + } + if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && combPIDPi < nsigmaCutTOFPi) { + return true; + } + } else if (PID == 1) // kaon + { + auto combPIDKa = TMath::Sqrt(TMath::Abs(candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa())); + if (!candidate.hasTOF() && candidate.tpcInnerParam() < 0.45 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPCKa) { + return true; + } + if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && combPIDKa < nsigmaCutTOFKa) { + return true; + } + } else // proton + { + auto combPIDPr = TMath::Sqrt(TMath::Abs(candidate.tofNSigmaPr() * candidate.tofNSigmaPr() + candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr())); + if (!candidate.hasTOF() && candidate.tpcInnerParam() < 0.6 && TMath::Abs(candidate.tpcNSigmaPr()) < nsigmaCutTPCPr) { + return true; + } + if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && combPIDPr < nsigmaCutTOFPr) { + return true; + } + } + return false; + } + + ROOT::Math::PxPyPzMVector Lambda, Proton, Pion, fourVecDauCM; + // ROOT::Math::XYZVector threeVecDauCM, threeVecDauCMXY, eventplaneVec, eventplaneVecNorm, beamvector; + ROOT::Math::XYZVector threeVecDauCM, threeVecDauCMXY; + double phiangle = 0.0; + double massPi = o2::constants::physics::MassPionCharged; + double massKa = o2::constants::physics::MassKaonCharged; + double massPr = o2::constants::physics::MassProton; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter centralityFilter = (nabs(aod::cent::centFT0C) < cfgCutCentralityMax && nabs(aod::cent::centFT0C) > cfgCutCentralityMin); + Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPT); + Filter dcaCutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); + + using EventCandidates = soa::Filtered>; + // using AllTrackCandidates = soa::Join; + using AllTrackCandidates = soa::Filtered>; + using ResoV0s = aod::V0Datas; + + // void processData(EventCandidates::iterator const& collision, AllTrackCandidates const&, ResoV0s const& V0s, aod::BCs const&) + void processData(EventCandidates::iterator const& collision, AllTrackCandidates const& tracks, ResoV0s const& /*V0s*/, aod::BCs const&) + { + + if (!collision.sel8()) { + return; + } + auto centrality = collision.centFT0C(); + // histos.fill(HIST("hCentrality0"), centrality); + if (!collision.triggereventsp()) { + return; + } + // histos.fill(HIST("hCentrality1"), centrality); + + if (additionalEvSel && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + // histos.fill(HIST("hCentrality2"), centrality); + // if (additionalEvSel2 && (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + if (additionalEvSel2 && (collision.trackOccupancyInTimeRange() > cfgMaxOccupancy || collision.trackOccupancyInTimeRange() < cfgMinOccupancy)) { + return; + } + // histos.fill(HIST("hCentrality3"), centrality); + if (additionalEvSel3 && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + return; + } + + auto qxZDCA = collision.qxZDCA(); + auto qxZDCC = collision.qxZDCC(); + auto qyZDCA = collision.qyZDCA(); + auto qyZDCC = collision.qyZDCC(); + // auto psiZDCC = collision.psiZDCC(); + // auto psiZDCA = collision.psiZDCA(); + + histos.fill(HIST("hCentrality"), centrality); + + auto QxtQxp = qxZDCA * qxZDCC; + auto QytQyp = qyZDCA * qyZDCC; + auto Qxytp = QxtQxp + QytQyp; + auto QxpQyt = qxZDCA * qyZDCC; + auto QxtQyp = qxZDCC * qyZDCA; + + histos.fill(HIST("hpQxtQxpvscent"), centrality, QxtQxp); + histos.fill(HIST("hpQytQypvscent"), centrality, QytQyp); + histos.fill(HIST("hpQxytpvscent"), centrality, Qxytp); + histos.fill(HIST("hpQxpQytvscent"), centrality, QxpQyt); + histos.fill(HIST("hpQxtQypvscent"), centrality, QxtQyp); + + for (auto track : tracks) { + if (!selectionTrack(track)) { + continue; + } + + bool ispion = 0; + bool iskaon = 0; + bool isproton = 0; + + if (SelectionPID(track, 0)) + ispion = 1; + if (SelectionPID(track, 1)) + iskaon = 1; + if (SelectionPID(track, 2)) + isproton = 1; + + if (ispion && iskaon) + continue; + if (ispion && isproton) + continue; + if (iskaon && isproton) + continue; + + float sign = track.sign(); + if (sign == 0.0) // removing neutral particles + continue; + + auto ux = TMath::Cos(GetPhiInRange(track.phi())); + auto uy = TMath::Sin(GetPhiInRange(track.phi())); + + // auto uxQxp = ux * qxZDCA; + // auto uyQyp = uy * qyZDCA; + // auto uxyQxyp = uxQxp + uyQyp; + // auto uxQxt = ux * qxZDCC; + // auto uyQyt = uy * qyZDCC; + // auto uxyQxyt = uxQxt + uyQyt; + auto oddv1 = ux * (qxZDCA - qxZDCC) + uy * (qyZDCA - qyZDCC); + auto evenv1 = ux * (qxZDCA + qxZDCC) + uy * (qyZDCA + qyZDCC); + + if (sign > 0) { + if (ispion) { + histos.fill(HIST("hpoddv1vscentpteta"), centrality, track.pt(), track.rapidity(massPi), oddv1); + histos.fill(HIST("hpevenv1vscentpteta"), centrality, track.pt(), track.rapidity(massPi), evenv1); + } else if (iskaon) { + histos.fill(HIST("hpoddv1vscentptetakaon"), centrality, track.pt(), track.rapidity(massKa), oddv1); + histos.fill(HIST("hpevenv1vscentptetakaon"), centrality, track.pt(), track.rapidity(massKa), evenv1); + } else if (isproton) { + histos.fill(HIST("hpoddv1vscentptetaproton"), centrality, track.pt(), track.rapidity(massPr), oddv1); + histos.fill(HIST("hpevenv1vscentptetaproton"), centrality, track.pt(), track.rapidity(massPr), evenv1); + } + + } else { + if (ispion) { + histos.fill(HIST("hpoddv1vscentptetaneg"), centrality, track.pt(), track.rapidity(massPi), oddv1); + histos.fill(HIST("hpevenv1vscentptetaneg"), centrality, track.pt(), track.rapidity(massPi), evenv1); + } else if (iskaon) { + histos.fill(HIST("hpoddv1vscentptetakaonneg"), centrality, track.pt(), track.rapidity(massKa), oddv1); + histos.fill(HIST("hpevenv1vscentptetakaonneg"), centrality, track.pt(), track.rapidity(massKa), evenv1); + } else if (isproton) { + histos.fill(HIST("hpoddv1vscentptetaprotonneg"), centrality, track.pt(), track.rapidity(massPr), oddv1); + histos.fill(HIST("hpevenv1vscentptetaprotonneg"), centrality, track.pt(), track.rapidity(massPr), evenv1); + } + } + } + } + PROCESS_SWITCH(lambdav2, processData, "Process data", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"lambdav2"})}; +} diff --git a/PWGLF/Tasks/Resonances/lstarpbpbv2.cxx b/PWGLF/Tasks/Resonances/lstarpbpbv2.cxx new file mode 100644 index 00000000000..4b9bdb5aede --- /dev/null +++ b/PWGLF/Tasks/Resonances/lstarpbpbv2.cxx @@ -0,0 +1,530 @@ +// 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. +// L* baryon v2 +// Prottay Das (prottay.das@cern.ch) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TRandom3.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" +#include "TF1.h" + +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/TrackSelection.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "CCDB/BasicCCDBManager.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; +struct lstarpbpbv2 { + + Service ccdb; + Service pdg; + + // events + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutCentrality{"cfgCutCentrality", 80.0f, "Accepted maximum Centrality"}; + // track + Configurable cfgCutCharge{"cfgCutCharge", 0.0, "cut on Charge"}; + Configurable cfgCutPT{"cfgCutPT", 0.2, "PT cut on daughter track"}; + Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; + Configurable cfgCutDCAxy{"cfgCutDCAxy", 2.0f, "DCAxy range for tracks"}; + Configurable cfgCutDCAz{"cfgCutDCAz", 2.0f, "DCAz range for tracks"}; + Configurable useGlobalTrack{"useGlobalTrack", true, "use Global track"}; + Configurable nsigmaCutTOF{"nsigmacutTOF", 3.0, "Value of the TOF Nsigma cut"}; + Configurable nsigmaCutTPC{"nsigmacutTPC", 3.0, "Value of the TPC Nsigma cut"}; + Configurable nsigmaCutCombined{"nsigmaCutCombined", 3.0, "Value of the TOF Nsigma cut"}; + Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 1, "Number of mixed events per event"}; + Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; + Configurable removefaketrak{"removefaketrack", true, "Remove fake track from momentum difference"}; + Configurable ConfFakeKaonCut{"ConfFakeKaonCut", 0.1, "Cut based on track from momentum difference"}; + Configurable ispTdepPID{"ispTdepPID", true, "pT dependent PID"}; + Configurable OnlyTOF{"OnlyTOF", true, "OnlyTOF"}; + Configurable strategyPID{"strategyPID", 2, "PID strategy"}; + Configurable cfgCutTOFBeta{"cfgCutTOFBeta", 0.0, "cut TOF beta"}; + Configurable confMinRot{"confMinRot", 5.0 * TMath::Pi() / 6.0, "Minimum of rotation"}; + Configurable confMaxRot{"confMaxRot", 7.0 * TMath::Pi() / 6.0, "Maximum of rotation"}; + Configurable nBkgRotations{"nBkgRotations", 9, "Number of rotated copies (background) per each original candidate"}; + Configurable fillRotation{"fillRotation", true, "fill rotation"}; + Configurable like{"like", true, "fill rotation"}; + Configurable spNbins{"spNbins", 2000, "Number of bins in sp"}; + Configurable lbinsp{"lbinsp", -1.0, "lower bin value in sp histograms"}; + Configurable hbinsp{"hbinsp", 1.0, "higher bin value in sp histograms"}; + Configurable nsigmaCutITS{"nsigmaCutITS", 3.0, "Value of the ITS Nsigma cut"}; + Configurable PIDstrategy{"PIDstrategy", 0, "0: TOF Veto, 1: TOF Veto opti, 2: TOF, 3: TOF loose 1, 4: TOF loose 2, 5: old pt dep"}; + + ConfigurableAxis configcentAxis{"configcentAxis", {VARIABLE_WIDTH, 0.0, 10.0, 40.0, 80.0}, "Cent V0M"}; + ConfigurableAxis configresAxis{"configresAxis", {VARIABLE_WIDTH, -2.0, -1.5, -1.0, -0.6, -0.2, 0.2, 0.6, 1.0, 1.5, 2.0}, "Resolution"}; + ConfigurableAxis configthnAxispT{"configthnAxisPt", {VARIABLE_WIDTH, 0.2, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.5, 8.0, 10.0, 100.0}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis configIMAxis{"configIMAxis", {VARIABLE_WIDTH, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.5, 1.7, 1.8, 1.9, 2.0}, "IM"}; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter centralityFilter = nabs(aod::cent::centFT0C) < cfgCutCentrality; + Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPT); + Filter DCAcutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); + + using EventCandidates = soa::Filtered>; + using TrackCandidates = soa::Filtered>; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + AxisSpec spAxis = {spNbins, lbinsp, hbinsp, "Sp"}; + + histos.add("hCentrality", "Centrality distribution", kTH1F, {{20, 0.0, 100.0}}); + + histos.add("ResFT0CTPCSP", "ResFT0CTPCSP", HistType::kTHnSparseF, {configcentAxis, configresAxis}); + histos.add("ResFT0CFT0ASP", "ResFT0CFT0ASP", HistType::kTHnSparseF, {configcentAxis, configresAxis}); + histos.add("ResFT0ATPCSP", "ResFT0ATPCSP", HistType::kTHnSparseF, {configcentAxis, configresAxis}); + histos.add("hpv2vscentpt", "hpv2vscentpt", HistType::kTHnSparseF, {configIMAxis, configcentAxis, configthnAxispT, spAxis}, true); + histos.add("hpv2vscentptrot", "hpv2vscentptrot", HistType::kTHnSparseF, {configIMAxis, configcentAxis, configthnAxispT, spAxis}, true); + histos.add("hpv2vscentptlike", "hpv2vscentptlike", HistType::kTHnSparseF, {configIMAxis, configcentAxis, configthnAxispT, spAxis}, true); + } + + double massKa = o2::constants::physics::MassKPlus; + double massPr = o2::constants::physics::MassProton; + + template + bool selectionTrack(const T& candidate) + { + if (useGlobalTrack && !(candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsFound() > cfgTPCcluster)) { + return false; + } + if (!useGlobalTrack && !(candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster)) { + return false; + } + return true; + } + + template + bool strategySelectionPID(const T& candidate, int PID, int strategy) + { + if (PID == 0) { + if (strategy == 0) { + if (candidate.pt() < 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && candidate.hasTOF() && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF && candidate.beta() > 0.5) { + return true; + } + } else if (strategy == 1) { + if (candidate.pt() < 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.5 && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < nsigmaCutTOF && candidate.beta() > 0.5) { + return true; + } + } else if (strategy == 2) { + if (candidate.pt() < 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && candidate.hasTOF() && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF && candidate.beta() > 0.5) { + return true; + } + if (candidate.pt() >= 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && !candidate.hasTOF()) { + return true; + } + } + } + return false; + } + + // TOF Veto + template + bool selectionPID1(const T& candidate) + { + if (candidate.hasTOF()) { + if (candidate.p() < 0.5 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; + } + if (candidate.p() >= 0.5 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOF) { + return true; + } + } + if (!candidate.hasTOF()) { + if (std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; + } + } + return false; + } + + // TPC TOF + template + bool selectionPID2(const T& candidate) + { + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.7 && candidate.pt() < 1.4) { + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOF) { + return true; + } + if (!candidate.hasTOF()) { + if (candidate.pt() >= 0.7 && candidate.pt() < 0.8 && candidate.tpcNSigmaPr() > -1.8 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.8 && candidate.pt() < 0.9 && candidate.tpcNSigmaPr() > -1.7 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.9 && candidate.pt() < 1.0 && candidate.tpcNSigmaPr() > -1.6 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 1.0 && candidate.pt() < 1.4 && candidate.tpcNSigmaPr() > -1.0 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + } + } + if (candidate.pt() >= 1.4) { + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOF) { + return true; + } + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; + } + } + return false; + } + + // TPC TOF + template + bool selectionPID3(const T& candidate) + { + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.7 && candidate.pt() < 1.8) { + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOF) { + return true; + } + if (!candidate.hasTOF()) { + if (candidate.pt() >= 0.7 && candidate.pt() < 0.8 && candidate.tpcNSigmaPr() > -1.8 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.8 && candidate.pt() < 0.9 && candidate.tpcNSigmaPr() > -1.7 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.9 && candidate.pt() < 1.0 && candidate.tpcNSigmaPr() > -1.6 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + } + } + if (candidate.pt() >= 1.8) { + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOF) { + return true; + } + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; + } + } + return false; + } + + // TPC TOF + template + bool selectionPID4(const T& candidate) + { + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.7 && candidate.pt() < 1.4) { + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOF) { + return true; + } + if (!candidate.hasTOF()) { + if (candidate.pt() >= 0.7 && candidate.pt() < 0.8 && candidate.tpcNSigmaPr() > -1.8 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.8 && candidate.pt() < 0.9 && candidate.tpcNSigmaPr() > -1.7 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.9 && candidate.pt() < 1.0 && candidate.tpcNSigmaPr() > -1.6 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 1.0 && candidate.pt() < 1.4 && candidate.tpcNSigmaPr() > -1.0 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + } + } + if (candidate.pt() >= 1.4) { + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + if (candidate.pt() < 2.5 && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOF) { + return true; + } + if (candidate.pt() >= 2.5 && candidate.pt() < 4 && candidate.tofNSigmaPr() > -2.0 && candidate.tofNSigmaPr() < nsigmaCutTOF) { + return true; + } + if (candidate.pt() >= 4 && candidate.pt() < 5 && candidate.tofNSigmaPr() > -1.5 && candidate.tofNSigmaPr() < nsigmaCutTOF) { + return true; + } + if (candidate.pt() >= 5 && candidate.tofNSigmaPr() > -1.0 && candidate.tofNSigmaPr() < nsigmaCutTOF) { + return true; + } + } + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; + } + } + return false; + } + + // TPC TOF + template + bool selectionPID5(const T& candidate) + { + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.7 && candidate.pt() < 1.8) { + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOF) { + return true; + } + if (!candidate.hasTOF()) { + if (candidate.pt() >= 0.7 && candidate.pt() < 0.8 && candidate.tpcNSigmaPr() > -1.8 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.8 && candidate.pt() < 0.9 && candidate.tpcNSigmaPr() > -1.7 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.9 && candidate.pt() < 1.0 && candidate.tpcNSigmaPr() > -1.6 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + } + } + if (candidate.pt() >= 1.8) { + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + if (candidate.pt() < 2.5 && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOF) { + return true; + } + if (candidate.pt() >= 2.5 && candidate.pt() < 4 && candidate.tofNSigmaPr() > -2.0 && candidate.tofNSigmaPr() < nsigmaCutTOF) { + return true; + } + if (candidate.pt() >= 4 && candidate.pt() < 5 && candidate.tofNSigmaPr() > -1.5 && candidate.tofNSigmaPr() < nsigmaCutTOF) { + return true; + } + if (candidate.pt() >= 5 && candidate.tofNSigmaPr() > -1.0 && candidate.tofNSigmaPr() < nsigmaCutTOF) { + return true; + } + } + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; + } + } + return false; + } + // TPC TOF + template + bool selectionPID6(const T& candidate) + { + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.7) { + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + if (candidate.pt() < 2.5 && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOF) { + return true; + } + if (candidate.pt() >= 2.5 && candidate.pt() < 4 && candidate.tofNSigmaPr() > -2.0 && candidate.tofNSigmaPr() < nsigmaCutTOF) { + return true; + } + if (candidate.pt() >= 4 && candidate.pt() < 5 && candidate.tofNSigmaPr() > -1.5 && candidate.tofNSigmaPr() < nsigmaCutTOF) { + return true; + } + if (candidate.pt() >= 5 && candidate.tofNSigmaPr() > -1.0 && candidate.tofNSigmaPr() < nsigmaCutTOF) { + return true; + } + } + if (!candidate.hasTOF()) { + if (candidate.pt() >= 0.7 && candidate.pt() < 0.8 && candidate.tpcNSigmaPr() > -1.8 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.8 && candidate.pt() < 0.9 && candidate.tpcNSigmaPr() > -1.7 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + if (candidate.pt() >= 0.9 && candidate.pt() < 1.0 && candidate.tpcNSigmaPr() > -1.6 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + return true; + } + } + } + return false; + } + + double GetPhiInRange(double phi) + { + double result = phi; + while (result < 0) { + result = result + 2. * TMath::Pi() / 2; + } + while (result > 2. * TMath::Pi() / 2) { + result = result - 2. * TMath::Pi() / 2; + } + return result; + } + + ROOT::Math::PxPyPzMVector LstarMother, daughter1, daughter2, kaonrot, lstarrot; + + void processSE(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) + { + if (!collision.sel8() || !collision.triggereventep() || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; + } + + o2::aod::ITSResponse itsResponse; + + auto centrality = collision.centFT0C(); + auto QFT0C = collision.qFT0C(); + auto QFT0A = collision.qFT0A(); + auto QTPC = collision.qTPC(); + auto psiFT0C = collision.psiFT0C(); + auto psiFT0A = collision.psiFT0A(); + auto psiTPC = collision.psiTPC(); + + histos.fill(HIST("hCentrality"), centrality); + + histos.fill(HIST("ResFT0CTPCSP"), centrality, QFT0C * QTPC * TMath::Cos(2.0 * (psiFT0C - psiTPC))); + histos.fill(HIST("ResFT0CFT0ASP"), centrality, QFT0C * QFT0A * TMath::Cos(2.0 * (psiFT0C - psiFT0A))); + histos.fill(HIST("ResFT0ATPCSP"), centrality, QTPC * QFT0A * TMath::Cos(2.0 * (psiTPC - psiFT0A))); + + for (auto track1 : tracks) { + if (!selectionTrack(track1)) { + continue; + } + bool track1kaon = false; + auto track1ID = track1.globalIndex(); + if (!strategySelectionPID(track1, 0, strategyPID)) { + continue; + } + track1kaon = true; + + for (auto track2 : tracks) { + if (!selectionTrack(track2)) { + continue; + } + + if (track2.p() < 0.5 && !(itsResponse.nSigmaITS(track2) > -nsigmaCutITS && itsResponse.nSigmaITS(track2) < nsigmaCutITS)) { // required for protons only + continue; + } + + bool track2proton = false; + if (PIDstrategy == 0 && !selectionPID1(track2)) { + continue; + } + if (PIDstrategy == 1 && !selectionPID2(track2)) { + continue; + } + if (PIDstrategy == 2 && !selectionPID3(track2)) { + continue; + } + if (PIDstrategy == 3 && !selectionPID4(track2)) { + continue; + } + if (PIDstrategy == 4 && !selectionPID5(track2)) { + continue; + } + if (PIDstrategy == 5 && !selectionPID6(track2)) { + continue; + } + + track2proton = true; + auto track2ID = track2.globalIndex(); + + if (track2ID == track1ID) { + continue; + } + if (!track1kaon || !track2proton) { + continue; + } + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPr); + LstarMother = daughter1 + daughter2; + if (TMath::Abs(LstarMother.Rapidity()) >= 0.5) { + continue; + } + + auto phiminuspsi = GetPhiInRange(LstarMother.Phi() - psiFT0C); + auto v2 = TMath::Cos(2.0 * phiminuspsi) * QFT0C; + + // unlike sign + if (track1.sign() * track2.sign() < 0) { + histos.fill(HIST("hpv2vscentpt"), LstarMother.M(), centrality, LstarMother.Pt(), v2); + if (fillRotation) { + for (int nrotbkg = 0; nrotbkg < nBkgRotations; nrotbkg++) { + auto anglestart = confMinRot; + auto angleend = confMaxRot; + auto anglestep = (angleend - anglestart) / (1.0 * (nBkgRotations - 1)); + auto rotangle = anglestart + nrotbkg * anglestep; + auto rotkaonPx = track1.px() * std::cos(rotangle) - track1.py() * std::sin(rotangle); + auto rotkaonPy = track1.px() * std::sin(rotangle) + track1.py() * std::cos(rotangle); + kaonrot = ROOT::Math::PxPyPzMVector(rotkaonPx, rotkaonPy, track1.pz(), massKa); + lstarrot = kaonrot + daughter2; + if (TMath::Abs(lstarrot.Rapidity()) >= 0.5) { + continue; + } + + auto phiminuspsirot = GetPhiInRange(lstarrot.Phi() - psiFT0C); + auto v2rot = TMath::Cos(2.0 * phiminuspsirot) * QFT0C; + + histos.fill(HIST("hpv2vscentptrot"), lstarrot.M(), centrality, lstarrot.Pt(), v2rot); + } + } + } + // like sign + if (track1.sign() * track2.sign() > 0) { + histos.fill(HIST("hpv2vscentptlike"), lstarrot.M(), centrality, lstarrot.Pt(), v2); + } + } + } + } + PROCESS_SWITCH(lstarpbpbv2, processSE, "Process Same event", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"lstarpbpbv2"})}; +} diff --git a/PWGLF/Tasks/Resonances/phianalysis.cxx b/PWGLF/Tasks/Resonances/phianalysis.cxx index 93f038e28cb..b529cc1fb81 100644 --- a/PWGLF/Tasks/Resonances/phianalysis.cxx +++ b/PWGLF/Tasks/Resonances/phianalysis.cxx @@ -64,10 +64,13 @@ struct phianalysis { Configurable cMinDCAzToPVcut{"cMinDCAzToPVcut", 0.0, "Track DCAz cut to PV Minimum"}; /// PID Selections Configurable cUseOnlyTOFTrackKa{"cUseOnlyTOFTrackKa", false, "Use only TOF track for PID selection"}; // Use only TOF track for PID selection + /// TPC nCluster cut + Configurable cMinTPCNclsFound{"cMinTPCNclsFound", 70, "Minimum TPC cluster found"}; // Kaon Configurable cMaxTPCnSigmaKaon{"cMaxTPCnSigmaKaon", 3.0, "TPC nSigma cut for Kaon"}; // TPC Configurable cMaxTOFnSigmaKaon{"cMaxTOFnSigmaKaon", 3.0, "TOF nSigma cut for Kaon"}; // TOF Configurable nsigmaCutCombinedKaon{"nsigmaCutCombinedKaon", 3.0, "Combined nSigma cut for Kaon"}; // Combined + Configurable cByPassTOF{"cByPassTOF", false, "By pass TOF PID selection"}; // By pass TOF PID selection // Track selections Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) @@ -114,8 +117,8 @@ struct phianalysis { histos.add("QAMCTrue/trkDCAxy", "DCAxy distribution of kaon track candidates", HistType::kTH1F, {dcaxyAxis}); histos.add("QAMCTrue/trkDCAz", "DCAz distribution of kaon track candidates", HistType::kTH1F, {dcazAxis}); histos.add("h3Recphiinvmass", "Invariant mass of Reconstructed MC phi", kTH3F, {centAxis, ptAxis, invMassAxis}); - histos.add("phiGen", "pT distribution of True MC phi", kTH1F, {ptAxis}); - histos.add("phiRec", "pT distribution of Reconstructed MC phi", kTH1F, {ptAxis}); + histos.add("phiGen", "pT distribution of True MC phi", kTH2F, {ptAxis, centAxis}); + histos.add("phiRec", "pT distribution of Reconstructed MC phi", kTH2F, {ptAxis, centAxis}); histos.add("phiRecinvmass", "Inv mass distribution of Reconstructed MC Phi", kTH1F, {invMassAxis}); } // Print output histograms statistics @@ -135,6 +138,8 @@ struct phianalysis { return false; if (std::abs(track.dcaZ()) > cMaxDCAzToPVcut) return false; + if (track.tpcNClsFound() < cMinTPCNclsFound) + return false; if (cfgPrimaryTrack && !track.isPrimaryTrack()) return false; if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) @@ -152,6 +157,9 @@ struct phianalysis { if (std::abs(candidate.tpcNSigmaKa()) < cMaxTPCnSigmaKaon) { tpcPIDPassed = true; } + if (cByPassTOF && tpcPIDPassed) { + return true; + } if (candidate.hasTOF()) { if (std::abs(candidate.tofNSigmaKa()) < cMaxTOFnSigmaKaon) { tofPIDPassed = true; @@ -171,8 +179,9 @@ struct phianalysis { template void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksType& dTracks2) { + auto multiplicity = collision.cent(); TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; - for (auto& [trk1, trk2] : combinations(CombinationsFullIndexPolicy(dTracks1, dTracks2))) { + for (auto& [trk1, trk2] : combinations(CombinationsUpperIndexPolicy(dTracks1, dTracks2))) { // Full index policy is needed to consider all possible combinations if (trk1.index() == trk2.index()) continue; // We need to run (0,1), (1,0) pairs as well. but same id pairs are not needed. @@ -235,12 +244,12 @@ struct phianalysis { if constexpr (!IsMix) { if (trk1.sign() > 0) { histos.fill(HIST("phiinvmassDS"), lResonance.M()); - histos.fill(HIST("h3phiinvmassDS"), collision.cent(), lResonance.Pt(), lResonance.M()); + histos.fill(HIST("h3phiinvmassDS"), multiplicity, lResonance.Pt(), lResonance.M()); } else { } } else { histos.fill(HIST("phiinvmassME"), lResonance.M()); - histos.fill(HIST("h3phiinvmassME"), collision.cent(), lResonance.Pt(), lResonance.M()); + histos.fill(HIST("h3phiinvmassME"), multiplicity, lResonance.Pt(), lResonance.M()); } // MC @@ -257,16 +266,16 @@ struct phianalysis { histos.fill(HIST("QAMCTrue/trkDCAz"), trk2.dcaZ()); // MC histograms - histos.fill(HIST("phiRec"), lResonance.Pt()); + histos.fill(HIST("phiRec"), lResonance.Pt(), multiplicity); histos.fill(HIST("phiRecinvmass"), lResonance.M()); - histos.fill(HIST("h3Recphiinvmass"), collision.cent(), lResonance.Pt(), lResonance.M()); + histos.fill(HIST("h3Recphiinvmass"), multiplicity, lResonance.Pt(), lResonance.M()); } } else { if constexpr (!IsMix) continue; if (trk1.sign() > 0) { histos.fill(HIST("phiinvmassLS"), lResonance.M()); - histos.fill(HIST("h3phiinvmassLS"), collision.cent(), lResonance.Pt(), lResonance.M()); + histos.fill(HIST("h3phiinvmassLS"), multiplicity, lResonance.Pt(), lResonance.M()); } else { } } @@ -288,8 +297,9 @@ struct phianalysis { } PROCESS_SWITCH(phianalysis, processMCLight, "Process Event for MC", false); - void processMCTrue(aod::ResoMCParents& resoParents) + void processMCTrue(aod::ResoCollision& collision, aod::ResoMCParents& resoParents) { + auto multiplicity = collision.cent(); for (auto& part : resoParents) { // loop over all pre-filtered MC particles if (abs(part.pdgCode()) != 333) // phi(0) continue; @@ -299,7 +309,7 @@ struct phianalysis { if (abs(part.daughterPDG1()) != 321 || abs(part.daughterPDG2()) != 321) { // At least one decay to Kaon continue; } - histos.fill(HIST("phiGen"), part.pt()); + histos.fill(HIST("phiGen"), part.pt(), multiplicity); } } PROCESS_SWITCH(phianalysis, processMCTrue, "Process Event for MC", false); diff --git a/PWGLF/Tasks/Resonances/phianalysisTHnSparse.cxx b/PWGLF/Tasks/Resonances/phianalysisTHnSparse.cxx index baee967d4bc..b01295ac422 100644 --- a/PWGLF/Tasks/Resonances/phianalysisTHnSparse.cxx +++ b/PWGLF/Tasks/Resonances/phianalysisTHnSparse.cxx @@ -9,13 +9,17 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. /// +/// \file phianalysisTHnSparse.cxx +/// \brief Analysis of phi resonance using THnSparse histograms. /// \author Veronika Barbasova (veronika.barbasova@cern.ch) -/// \since April 3, 2024 #include +#include +#include #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/TrackSelectionTables.h" #include "Framework/ASoAHelpers.h" @@ -24,72 +28,80 @@ #include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/PID.h" #include "PWGLF/Utils/rsnOutput.h" -#include "TDatabasePDG.h" +// #include "TDatabasePDG.h" using namespace o2; using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; -struct phianalysisTHnSparse { +struct PhianalysisTHnSparse { SliceCache cache; struct : ConfigurableGroup { - Configurable QA{"produce-qa", false, "Produce QA histograms."}; - Configurable True{"produce-true", false, "Produce True and Gen histograms."}; - Configurable Likesign{"produce-likesign", false, "Produce Like sign histograms."}; - Configurable eventMixing{"produce-event-mixing", false, "Produce Event Mixing histograms."}; + Configurable produceQA{"produceQA", false, "Produce qa histograms."}; + Configurable produceTrue{"produceTrue", false, "Produce True and Gen histograms."}; + Configurable produceLikesign{"produceLikesign", false, "Produce Like sign histograms."}; + Configurable eventMixing{"eventMixing", "none", "Produce Event Mixing histograms of type."}; } produce; struct : ConfigurableGroup { - Configurable verboselevel{"verbose-level", 0, "Verbose level"}; - Configurable refresh{"print-refresh", 0, "Freqency of print event information."}; - Configurable refresh_index{"print-refresh-index", 0, "Freqency of print event information index."}; - Configurable ignorezeroevent{"ignore-zero-event", true, "Flag if zero event is skipped"}; + Configurable verboselevel{"verboselevel", 0, "Verbose level"}; + Configurable refresh{"refresh", 0, "Freqency of print event information."}; + Configurable refreshIndex{"refreshIndex", 0, "Freqency of print event information index."}; } verbose; - Configurable dautherPos{"dauther-type-pos", 3, "Particle type of the positive dauther according to ReconstructionDataFormats/PID.h (Default = Kaon)"}; - Configurable dautherNeg{"dauther-type-neg", 3, "Particle type of the negative dauther according to ReconstructionDataFormats/PID.h (Default = Kaon)"}; - Configurable motherPDG{"mother-pdg", 333, "PDG code of mother particle."}; - Configurable dautherPosPDG{"dauther-pdg-pos", 321, "PDG code of positive dauther particle."}; - Configurable dautherNegPDG{"dauther-pdg-neg", 321, "PDG code of negative dauther particle."}; + Configurable dautherPos{"dautherPos", 3, "Particle type of the positive dauther according to ReconstructionDataFormats/PID.h (Default = Kaon)"}; + Configurable dautherNeg{"dautherNeg", 3, "Particle type of the negative dauther according to ReconstructionDataFormats/PID.h (Default = Kaon)"}; + Configurable motherPDG{"motherPDG", 333, "PDG code of mother particle."}; + Configurable dautherPosPDG{"dautherPosPDG", 321, "PDG code of positive dauther particle."}; + Configurable dautherNegPDG{"dautherNegPDG", 321, "PDG code of negative dauther particle."}; struct : ConfigurableGroup { - Configurable tpcnSigmaPos{"tpc-ns-pos", 3.0f, "TPC NSigma cut of the positive particle."}; - Configurable tpcnSigmaNeg{"tpc-ns-neg", 3.0f, "TPC NSigma cut of the negative particle."}; - Configurable vZ{"zvertex-cut", 10.0f, "Z vertex range."}; - Configurable y{"rapidity-cut", 0.5, "Rapidity cut (maximum)."}; - Configurable pt{"pt-cut", 0.15f, "Cut: Minimal value of tracks pt."}; - Configurable dcaXY{"dcaXY-cut", 1.0f, "Cut: Maximal value of tracks DCA XY."}; - Configurable dcaZ{"dcaZ-cut", 1.0f, "Cut: Maximal value of tracks DCA Z."}; + Configurable tpcnSigmaPos{"tpcnSigmaPos", 3.0f, "TPC NSigma cut of the positive particle."}; + Configurable tpcnSigmaNeg{"tpcnSigmaNeg", 3.0f, "TPC NSigma cut of the negative particle."}; + Configurable vZ{"vZ", 10.0f, "Z vertex range."}; + Configurable y{"y", 0.5, "Rapidity cut (maximum)."}; + Configurable etatrack{"etatrack", 0.8, "Eta cut for track."}; + Configurable etapair{"etapair", 0.8, "Eta cut for pair."}; + Configurable pt{"pt", 0.15f, "Cut: Minimal value of tracks pt."}; + Configurable dcaXY{"dcaXY", 1.0f, "Cut: Maximal value of tracks DCA XY."}; + Configurable dcaZ{"dcaZ", 1.0f, "Cut: Maximal value of tracks DCA Z."}; + Configurable tpcNClsFound{"tpcNClsFound", 70, "Cut: Minimal value of found TPC clasters"}; } cut; - Configurable> sparseAxes{"sparse-axes", std::vector{o2::analysis::rsn::PariAxis::names}, "Axes."}; + Configurable> sparseAxes{"sparseAxes", std::vector{o2::analysis::rsn::pair_axis::names}, "Axes."}; + Configurable> sysAxes{"sysAxes", std::vector{o2::analysis::rsn::systematic_axis::names}, "Axes."}; - ConfigurableAxis invaxis{"inv-axis", {130, 0.97, 1.1}, "Invariant mass axis binning."}; - ConfigurableAxis ptaxis{"pt-axis", {20, 0., 20.}, "Pt axis binning."}; - ConfigurableAxis vzaxis{"vz-axis", {40, -20., 20.}, "Z vertex position axis binning."}; - ConfigurableAxis multiplicityaxis{"multiplicity-axis", {50, 0., 5000.}, "Multiplicity axis binning."}; - ConfigurableAxis rapidityaxis{"rapidity-axis", {10., -1.0 * static_cast(cut.y), static_cast(cut.y)}, "Rapidity axis binning."}; - ConfigurableAxis nsigmaaxisPos{"nsigma-pos-axis", {1, 0., static_cast(cut.tpcnSigmaPos)}, "NSigma of positive particle axis binning in THnSparse."}; - ConfigurableAxis nsigmaaxisNeg{"nsigma-neg-axis", {1, 0., static_cast(cut.tpcnSigmaNeg)}, "NSigma of negative particle axis binning in THnSparse."}; + ConfigurableAxis invaxis{"invaxis", {130, 0.97, 1.1}, "Invariant mass axis binning."}; + ConfigurableAxis ptaxis{"ptaxis", {20, 0., 20.}, "Pt axis binning."}; + ConfigurableAxis vzaxis{"vzaxis", {40, -20., 20.}, "Z vertex position axis binning."}; + ConfigurableAxis multiplicityaxis{"multiplicityaxis", {50, 0., 5000.}, "Multiplicity axis binning."}; + ConfigurableAxis centralityaxis{"centralityaxis", {20, 0., 100.}, "Centrality axis binning."}; + ConfigurableAxis etaaxis{"etaaxis", {16., -1.0 * static_cast(cut.etatrack), static_cast(cut.etatrack)}, "Pseudorapidity axis binning."}; + ConfigurableAxis rapidityaxis{"rapidityaxis", {10., -1.0 * static_cast(cut.y), static_cast(cut.y)}, "Rapidity axis binning."}; + ConfigurableAxis nsigmaaxisPos{"nsigmaaxisPos", {1, 0., static_cast(cut.tpcnSigmaPos)}, "NSigma of positive particle axis binning in THnSparse."}; + ConfigurableAxis nsigmaaxisNeg{"nsigmaaxisNeg", {1, 0., static_cast(cut.tpcnSigmaNeg)}, "NSigma of negative particle axis binning in THnSparse."}; // mixing - using BinningType = ColumnBinningPolicy>; - Configurable numberofMixedEvents{"number-of-mixed-events", 5, "Number of events that should be mixed."}; - ConfigurableAxis axisVertexMixing{"vertex-axis-mixing", {20, -10, 10}, "Z vertex axis for bin"}; - ConfigurableAxis axisMultiplicityMixing{"multiplicity-axis-mixing", {50, 0, 5000}, "TPC multiplicity for bin"}; - BinningType binning{{axisVertexMixing, axisMultiplicityMixing}, true}; + using BinningTypeVzMu = ColumnBinningPolicy>; + using BinningTypeVzCe = ColumnBinningPolicy; + Configurable numberofMixedEvents{"numberofMixedEvents", 5, "Number of events that should be mixed."}; + ConfigurableAxis axisVertexMixing{"axisVertexMixing", {5, -10, 10}, "Z vertex axis binning for mixing"}; + ConfigurableAxis axisMultiplicityMixing{"axisMultiplicityMixing", {5, 0, 5000}, "TPC multiplicity for bin"}; + ConfigurableAxis axisCentralityMixing{"axisCentralityMixing", {10, 0, 100}, "Multiplicity percentil binning for mixing"}; // defined in DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h float massPos = o2::track::PID::getMass(dautherPos); float massNeg = o2::track::PID::getMass(dautherNeg); // Axes specifications - AxisSpec posZaxis = {400, -20., 20., "V_z (cm)"}; + AxisSpec posZaxis = {400, -20., 20., "V_{z} (cm)"}; AxisSpec dcaXYaxis = {120, -3.0, 3.0, "DCA_{xy} (cm)"}; AxisSpec dcaZaxis = {120, -3.0, 3.0, "DCA_{z} (cm)"}; + AxisSpec etaQAaxis = {1000, -1.0, 1.0, "#eta"}; + AxisSpec tpcNClsFoundQAaxis = {110, 50., 160., "tpcNClsFound"}; HistogramRegistry registry{"registry"}; o2::analysis::rsn::Output* rsnOutput = nullptr; @@ -98,28 +110,41 @@ struct phianalysisTHnSparse { int n = 0; double* pointPair = nullptr; - double* pointEvent = nullptr; + double* pointSys = nullptr; TLorentzVector d1, d2, mother; + bool produceQA, dataQA, MCTruthQA, t1, t2 = false; + int id; + float etapair = 0.8; + float tpcnSigmaPos = 3.0f; + float tpcnSigmaNeg = 3.0f; + int tpcNClsFound = 70; + + rsn::MixingType mixingType = rsn::MixingType::none; Filter triggerFilter = (o2::aod::evsel::sel8 == true); Filter vtxFilter = (nabs(o2::aod::collision::posZ) < static_cast(cut.vZ)); Filter ptFilter = nabs(aod::track::pt) > static_cast(cut.pt); - Filter etaFilter = nabs(aod::track::eta) < static_cast(cut.y); + Filter etaFilter = nabs(aod::track::eta) < static_cast(cut.etatrack); Filter dcaFilter = (nabs(o2::aod::track::dcaXY) < static_cast(cut.dcaXY)) && (nabs(o2::aod::track::dcaZ) < static_cast(cut.dcaZ)); - using EventCandidates = soa::Filtered>; + using EventCandidates = soa::Filtered>; using EventCandidate = EventCandidates::iterator; using TrackCandidates = soa::Filtered>; - using EventCandidatesMC = soa::Filtered>; + using EventCandidatesMC = soa::Filtered>; using TrackCandidatesMC = soa::Filtered>; - Partition positive = (aod::track::signed1Pt > 0.0f) && (nabs(o2::aod::pidtpc::tpcNSigmaKa) < static_cast(cut.tpcnSigmaPos)); - Partition negative = (aod::track::signed1Pt < 0.0f) && (nabs(o2::aod::pidtpc::tpcNSigmaKa) < static_cast(cut.tpcnSigmaNeg)); + using EventCandidatesMCGen = soa::Join; + + using LabeledTracks = soa::Join; + Preslice perCollision = aod::track::collisionId; + + Partition positive = (aod::track::signed1Pt > 0.0f) && (nabs(o2::aod::pidtpc::tpcNSigmaKa) < std::abs(static_cast(cut.tpcnSigmaPos))); + Partition negative = (aod::track::signed1Pt < 0.0f) && (nabs(o2::aod::pidtpc::tpcNSigmaKa) < std::abs(static_cast(cut.tpcnSigmaNeg))); - Partition positiveMC = (aod::track::signed1Pt > 0.0f) && (nabs(o2::aod::pidtpc::tpcNSigmaKa) < static_cast(cut.tpcnSigmaPos)); - Partition negativeMC = (aod::track::signed1Pt < 0.0f) && (nabs(o2::aod::pidtpc::tpcNSigmaKa) < static_cast(cut.tpcnSigmaNeg)); + Partition positiveMC = (aod::track::signed1Pt > 0.0f) && (nabs(o2::aod::pidtpc::tpcNSigmaKa) < std::abs(static_cast(cut.tpcnSigmaPos))); + Partition negativeMC = (aod::track::signed1Pt < 0.0f) && (nabs(o2::aod::pidtpc::tpcNSigmaKa) < std::abs(static_cast(cut.tpcnSigmaNeg))); void init(o2::framework::InitContext&) { @@ -128,52 +153,258 @@ struct phianalysisTHnSparse { AxisSpec ptAxis = {ptaxis, "p_{T} (GeV/c)", "pt"}; AxisSpec muAxis = {multiplicityaxis, "N", "mu"}; AxisSpec mumAxis = {multiplicityaxis, "N", "mum"}; + AxisSpec ceAxis = {centralityaxis, "N", "ce"}; + AxisSpec cemAxis = {centralityaxis, "N", "cem"}; + AxisSpec etaAxis = {etaaxis, "#eta", "eta"}; AxisSpec yAxis = {rapidityaxis, "y", "y"}; AxisSpec nsAxisPos = {nsigmaaxisPos, fmt::format("nSigma of positive particle ({})", massPos), "ns1"}; AxisSpec nsAxisNeg = {nsigmaaxisNeg, fmt::format("nSigma of negative particle ({})", massNeg), "ns2"}; AxisSpec vzAxis = {vzaxis, "V_{z} (cm)", "vz"}; AxisSpec vzmAxis = {vzaxis, "V_{z} (cm)", "vzm"}; + // Systematics axes + std::vector tpcNClsFoundBins = {65., 66., 67., 68., 69., 70., 71., 72., 73.}; + AxisSpec tpcNClsFoundAxis = {tpcNClsFoundBins, "TPC NCl", "ncl"}; + // All axes has to have same order as defined enum o2::analysis::rsn::PairAxisType (name from AxisSpec is taken to compare in o2::analysis::rsn::Output::init()) - std::vector allAxes = {invAxis, ptAxis, muAxis, nsAxisPos, nsAxisNeg, yAxis, vzAxis, mumAxis, vzmAxis}; + std::vector allAxes = {invAxis, ptAxis, muAxis, ceAxis, nsAxisPos, nsAxisNeg, etaAxis, yAxis, vzAxis, mumAxis, cemAxis, vzmAxis}; + std::vector allAxesSys = {tpcNClsFoundAxis}; + + produceQA = static_cast(produce.produceQA); + mixingType = rsn::mixingTypeName(static_cast(produce.eventMixing)); + etapair = static_cast(cut.etapair); + tpcnSigmaPos = static_cast(cut.tpcnSigmaPos); + tpcnSigmaNeg = static_cast(cut.tpcnSigmaNeg); + tpcNClsFound = static_cast(cut.tpcNClsFound); pointPair = new double[static_cast(o2::analysis::rsn::PairAxisType::unknown)]; - pointEvent = new double[static_cast(o2::analysis::rsn::EventType::all)]; + pointSys = new double[static_cast(o2::analysis::rsn::SystematicsAxisType::unknown)]; rsnOutput = new o2::analysis::rsn::OutputSparse(); - rsnOutput->init(sparseAxes, allAxes, static_cast(produce.True), static_cast(produce.eventMixing), static_cast(produce.Likesign), ®istry); + rsnOutput->init(sparseAxes, allAxes, sysAxes, allAxesSys, static_cast(produce.produceTrue), mixingType, static_cast(produce.produceLikesign), ®istry); - if (static_cast(produce.QA)) { + if (produceQA) { // Event QA - registry.add("QAEvent/hVtxZ", "", kTH1F, {posZaxis}); - registry.add("QAEvent/s4Size", "", kTHnSparseF, {{30, 0., 30.}, {30, 0., 30.}, muAxis, vzAxis}); - // Track QA - registry.add("QATrack/unlikepm/beforeSelection/hTrack1pt", "", kTH1F, {ptAxis}); - registry.add("QATrack/unlikepm/beforeSelection/hTrackDCAxy", "", kTH1F, {dcaXYaxis}); - registry.add("QATrack/unlikepm/beforeSelection/hTrackDCAz", "", kTH1F, {dcaZaxis}); - registry.add("QATrack/unlikepm/beforeSelection/hTrack1eta", "", kTH1F, {{100, -1.0, 1.0}}); + registry.add("QAEvent/hSelection", "Event selection statistics", kTH1F, {{1, 0.0f, 1.0f}}); + auto hEvent = registry.get(HIST("QAEvent/hSelection")); + hEvent->GetXaxis()->SetBinLabel(1, "Full event statistics"); + hEvent->SetMinimum(0.1); - registry.add("QATrack/unlikepm/afterSelection/hTrack1pt", "", kTH1F, {ptAxis}); - registry.add("QATrack/unlikepm/afterSelection/hTrackDCAxy", "", kTH1F, {dcaXYaxis}); - registry.add("QATrack/unlikepm/afterSelection/hTrackDCAz", "", kTH1F, {dcaZaxis}); - registry.add("QATrack/unlikepm/afterSelection/hTrack1eta", "", kTH1F, {{100, -1.0, 1.0}}); - - registry.add("QATrack/unlikepm/TPCPID/h2TracknSigma", "", kTH2F, {{120, -static_cast(cut.tpcnSigmaPos), static_cast(cut.tpcnSigmaPos)}, {120, -static_cast(cut.tpcnSigmaNeg), static_cast(cut.tpcnSigmaNeg)}}); + registry.add("QAEvent/hVtxZ", "Vertex position along the z-axis", kTH1F, {posZaxis}); + registry.add("QAEvent/hCent", "Distribution of multiplicity percentile", kTH1F, {{100, 0., 100.}}); + registry.add("QAEvent/hMult", "Multiplicity (amplitude of non-zero channels in the FV0A + FV0C) ", kTH1F, {{300, 0., 30000.}}); + registry.add("QAEvent/h2Size", "Number of positive vs. negative Kaons per collision", kTH2F, {{30, 0., 30.}, {30, 0., 30.}}); + // Track QA + registry.add("QATrack/hSelection", "Tracks combinations statistics", kTH1F, {{11, 0.0f, 11.0f}}); + auto hTrack = registry.get(HIST("QATrack/hSelection")); + hTrack->GetXaxis()->SetBinLabel(1, "all K^{+} K^{-} combinations"); + hTrack->GetXaxis()->SetBinLabel(2, "all K^{+}"); + hTrack->GetXaxis()->SetBinLabel(3, "all K^{-}"); + hTrack->GetXaxis()->SetBinLabel(4, "K^{+} tpcNClsFound"); + hTrack->GetXaxis()->SetBinLabel(5, "K^{-} tpcNClsFound"); + hTrack->GetXaxis()->SetBinLabel(6, "K^{+} isPrimaryTrack"); + hTrack->GetXaxis()->SetBinLabel(7, "K^{-} isPrimaryTrack"); + hTrack->GetXaxis()->SetBinLabel(8, "K^{+} isPVContributor"); + hTrack->GetXaxis()->SetBinLabel(9, "K^{-} isPVContributor"); + hTrack->GetXaxis()->SetBinLabel(10, "selected combinations"); + hTrack->GetXaxis()->SetBinLabel(11, "selected pairs (eta cut)"); + hTrack->SetMinimum(0.1); + + // Track1 + registry.add("QATrack/bs/hTrack1pt", "K^{+} p_{T} before selection", kTH1F, {ptAxis}); + registry.add("QATrack/bs/hTrack1DCAxy", "K^{+} DCA_{xy} before selection", kTH1F, {dcaXYaxis}); + registry.add("QATrack/bs/hTrack1DCAz", "K^{+} DCA_{z} before selection", kTH1F, {dcaZaxis}); + registry.add("QATrack/bs/hTrack1eta", "K^{+} #eta before selection", kTH1F, {{etaQAaxis}}); + registry.add("QATrack/bs/hTrack1tpcNClsFound", "K^{+} tpcNClsFound before selection", kTH1F, {{tpcNClsFoundQAaxis}}); + + registry.add("QATrack/as/hTrack1pt", "K^{+} p_{T} after selection", kTH1F, {ptAxis}); + registry.add("QATrack/as/hTrack1DCAxy", "K^{+} DCA_{xy} after selection", kTH1F, {dcaXYaxis}); + registry.add("QATrack/as/hTrack1DCAz", "K^{+} DCA_{z} after selection", kTH1F, {dcaZaxis}); + registry.add("QATrack/as/hTrack1eta", "K^{+} #eta after selection", kTH1F, {{etaQAaxis}}); + registry.add("QATrack/as/hTrack1tpcNClsFound", "K^{+} tpcNClsFound after selection", kTH1F, {{tpcNClsFoundQAaxis}}); + + // Track2 + registry.add("QATrack/bs/hTrack2pt", "K^{-} p_{T} before selection", kTH1F, {ptAxis}); + registry.add("QATrack/bs/hTrack2DCAxy", "K^{-} DCA_{xy} before selection", kTH1F, {dcaXYaxis}); + registry.add("QATrack/bs/hTrack2DCAz", "K^{-} DCA_{z} before selection", kTH1F, {dcaZaxis}); + registry.add("QATrack/bs/hTrack2eta", "K^{-} #eta before selection", kTH1F, {{etaQAaxis}}); + registry.add("QATrack/bs/hTrack2tpcNClsFound", "K^{-} tpcNClsFound before selection", kTH1F, {{tpcNClsFoundQAaxis}}); + + registry.add("QATrack/as/hTrack2pt", "K^{-} p_{T} after selection", kTH1F, {ptAxis}); + registry.add("QATrack/as/hTrack2DCAxy", "K^{-} DCA_{xy} after selection", kTH1F, {dcaXYaxis}); + registry.add("QATrack/as/hTrack2DCAz", "K^{-} DCA_{z} after selection", kTH1F, {dcaZaxis}); + registry.add("QATrack/as/hTrack2eta", "K^{-} #eta after selection", kTH1F, {{etaQAaxis}}); + registry.add("QATrack/as/hTrack2tpcNClsFound", "K^{-} tpcNClsFound after selection", kTH1F, {{tpcNClsFoundQAaxis}}); + + // TPC PID + registry.add("QATrack/TPCPID/h2TracknSigma", "", kTH2F, {{120, -6, 6}, {120, -6, 6}}); + auto h2TracknSigma = registry.get(HIST("QATrack/TPCPID/h2TracknSigma")); + h2TracknSigma->GetXaxis()->SetTitle("n#sigma_{TPC} K^{+}"); + h2TracknSigma->GetYaxis()->SetTitle("n#sigma_{TPC} K^{-}"); + + registry.add("QATrack/TPCPID/h2nTrack1SigmaPt", "", kTH2F, {{100, 0, 10}, {120, -6, 6}}); + auto h2nTrack1SigmaPt = registry.get(HIST("QATrack/TPCPID/h2nTrack1SigmaPt")); + h2nTrack1SigmaPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); + h2nTrack1SigmaPt->GetYaxis()->SetTitle("n#sigma_{TPC} K^{+}"); + + registry.add("QATrack/TPCPID/h2nTrack2SigmaPt", "", kTH2F, {{100, 0, 10}, {120, -6, 6}}); + auto h2nTrack2SigmaPt = registry.get(HIST("QATrack/TPCPID/h2nTrack2SigmaPt")); + h2nTrack2SigmaPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); + h2nTrack2SigmaPt->GetYaxis()->SetTitle("n#sigma_{TPC} K^{-}"); + + // MC Truth + if (static_cast(produce.produceTrue)) { + registry.add("QAMC/Truth/hMCEvent", "MC Truth Event statistics", kTH1F, {{1, 0.0f, 1.0f}}); + auto hMCEventTruth = registry.get(HIST("QAMC/Truth/hMCEvent")); + hMCEventTruth->GetXaxis()->SetBinLabel(1, "Full MC Truth event statistics"); + hMCEventTruth->SetMinimum(0.1); + + registry.add("QAMC/Truth/hMCTrack", "MC Truth Track statistics", kTH1F, {{17, 0.0f, 17.0f}}); + auto hMCTrackTruth = registry.get(HIST("QAMC/Truth/hMCTrack")); + hMCTrackTruth->GetXaxis()->SetBinLabel(1, "all K^{+} K^{-} combinations"); + hMCTrackTruth->GetXaxis()->SetBinLabel(2, "all K^{+}"); + hMCTrackTruth->GetXaxis()->SetBinLabel(3, "all K^{-}"); + hMCTrackTruth->GetXaxis()->SetBinLabel(4, "K^{+} tpcNClsFound"); + hMCTrackTruth->GetXaxis()->SetBinLabel(5, "K^{-} tpcNClsFound"); + hMCTrackTruth->GetXaxis()->SetBinLabel(6, "K^{+} isPrimaryTrack"); + hMCTrackTruth->GetXaxis()->SetBinLabel(7, "K^{-} isPrimaryTrack"); + hMCTrackTruth->GetXaxis()->SetBinLabel(8, "K^{+} isPVContributor"); + hMCTrackTruth->GetXaxis()->SetBinLabel(9, "K^{-} isPVContributor"); + hMCTrackTruth->GetXaxis()->SetBinLabel(10, "selected combinations"); + hMCTrackTruth->GetXaxis()->SetBinLabel(11, "MCtrack PDG = 321"); + hMCTrackTruth->GetXaxis()->SetBinLabel(12, "all mothers"); + hMCTrackTruth->GetXaxis()->SetBinLabel(13, "equal mother PDGs"); + hMCTrackTruth->GetXaxis()->SetBinLabel(14, "equal mother IDs"); + hMCTrackTruth->GetXaxis()->SetBinLabel(15, "mother rapidity cut"); + hMCTrackTruth->GetXaxis()->SetBinLabel(16, "mother PDG = 333"); + hMCTrackTruth->GetXaxis()->SetBinLabel(17, "selected pairs (eta cut)"); + hMCTrackTruth->SetMinimum(0.1); + + registry.add("QAMC/hInvMassTrueFalse", "", kTH1F, {invAxis}); // not written events in True distribution due to repetition of mothers?? + + // MC Gen + registry.add("QAMC/Gen/hMCEvent", "MC Gen Event statistics", kTH1F, {{3, 0.0f, 3.0f}}); + auto hMCEventGen = registry.get(HIST("QAMC/Gen/hMCEvent")); + hMCEventGen->GetXaxis()->SetBinLabel(1, "Full McCollision statistics"); + hMCEventGen->GetXaxis()->SetBinLabel(2, "McCollision V_{z} cut"); + hMCEventGen->GetXaxis()->SetBinLabel(3, "collisions"); + hMCEventGen->SetMinimum(0.1); + + registry.add("QAMC/Gen/hMCTrack", "MC Gen Track statistics", kTH1D, {{7, 0.0f, 7.0f}}); + auto hMCTrackGen = registry.get(HIST("QAMC/Gen/hMCTrack")); + hMCTrackGen->GetXaxis()->SetBinLabel(1, "all mcParticles"); + hMCTrackGen->GetXaxis()->SetBinLabel(2, "rapidity cut"); + hMCTrackGen->GetXaxis()->SetBinLabel(3, "particle PDG = 333"); + hMCTrackGen->GetXaxis()->SetBinLabel(4, "has 2 dauthers"); + hMCTrackGen->GetXaxis()->SetBinLabel(5, "all dauthers"); + hMCTrackGen->GetXaxis()->SetBinLabel(6, "isPhysicalPrimary"); + hMCTrackGen->GetXaxis()->SetBinLabel(7, "selected pairs"); + hMCTrackGen->SetMinimum(0.1); + } // Mixing QA - registry.add("QAMixing/s4Multiplicity", "", kTHnSparseF, {axisMultiplicityMixing, axisMultiplicityMixing, axisVertexMixing, axisVertexMixing}); + if (mixingType != rsn::MixingType::none) { + registry.add("QAMixing/hSelection", "Event mixing selection statistics", kTH1F, {{1, 0.0f, 1.0f}}); + auto hEM = registry.get(HIST("QAMixing/hSelection")); + hEM->GetXaxis()->SetBinLabel(1, "Full event mixing statistics"); + hEM->SetMinimum(0.1); + + registry.add("QAMixing/hTrackSelection", "Event mixing tracks combinations statistics", kTH1F, {{4, 0.0f, 4.0f}}); + auto hEMTrack = registry.get(HIST("QAMixing/hTrackSelection")); + hEMTrack->GetXaxis()->SetBinLabel(1, "all K^{+} K^{-} combinations"); + hEMTrack->GetXaxis()->SetBinLabel(2, "all K^{+}"); + hEMTrack->GetXaxis()->SetBinLabel(3, "all K^{-}"); + hEMTrack->GetXaxis()->SetBinLabel(4, "selected pairs (eta cut)"); + hEMTrack->SetMinimum(0.1); + + registry.add("QAMixing/h2mu1_mu2", "Event Mixing Multiplicity", kTH2F, {axisMultiplicityMixing, axisMultiplicityMixing}); + auto h2EMmu = registry.get(HIST("QAMixing/h2mu1_mu2")); + h2EMmu->GetXaxis()->SetTitle("1.Event multiplicity"); + h2EMmu->GetYaxis()->SetTitle("2.Event multiplicity"); + + registry.add("QAMixing/h2ce1_ce2", "Event Mixing Centrality", kTH2F, {axisCentralityMixing, axisCentralityMixing}); + auto h2EMce = registry.get(HIST("QAMixing/h2ce1_ce2")); + h2EMce->GetXaxis()->SetTitle("1.Event centrality"); + h2EMce->GetYaxis()->SetTitle("2.Event centrality"); + + registry.add("QAMixing/h2vz1_vz2", "Event Mixing Vertex z", kTH2F, {axisVertexMixing, axisVertexMixing}); + auto hEMTvz = registry.get(HIST("QAMixing/h2vz1_vz2")); + hEMTvz->GetXaxis()->SetTitle("1.Event V_{z}"); + hEMTvz->GetYaxis()->SetTitle("2.Event V_{z}"); + } } + + pointSys[static_cast(o2::analysis::rsn::SystematicsAxisType::ncl)] = tpcNClsFound; + rsnOutput->fillSystematics(pointSys); } template bool selectedTrack(const T& track) { + if (produceQA) { + if (t1) { + if (dataQA) + registry.fill(HIST("QATrack/hSelection"), 1.5); + if (MCTruthQA) + registry.fill(HIST("QAMC/Truth/hMCTrack"), 1.5); + } + if (t2) { + if (dataQA) + registry.fill(HIST("QATrack/hSelection"), 2.5); + if (MCTruthQA) + registry.fill(HIST("QAMC/Truth/hMCTrack"), 2.5); + } + } + + if (track.tpcNClsFound() < tpcNClsFound) + return false; + if (produceQA) { + if (t1) { + if (dataQA) + registry.fill(HIST("QATrack/hSelection"), 3.5); + if (MCTruthQA) + registry.fill(HIST("QAMC/Truth/hMCTrack"), 3.5); + } + if (t2) { + if (dataQA) + registry.fill(HIST("QATrack/hSelection"), 4.5); + if (MCTruthQA) + registry.fill(HIST("QAMC/Truth/hMCTrack"), 4.5); + } + } if (!track.isPrimaryTrack()) return false; + if (produceQA) { + if (t1) { + if (dataQA) + registry.fill(HIST("QATrack/hSelection"), 5.5); + if (MCTruthQA) + registry.fill(HIST("QAMC/Truth/hMCTrack"), 5.5); + } + if (t2) { + if (dataQA) + registry.fill(HIST("QATrack/hSelection"), 6.5); + if (MCTruthQA) + registry.fill(HIST("QAMC/Truth/hMCTrack"), 6.5); + } + } if (!track.isPVContributor()) return false; + if (produceQA) { + if (t1) { + if (dataQA) + registry.fill(HIST("QATrack/hSelection"), 7.5); + if (MCTruthQA) + registry.fill(HIST("QAMC/Truth/hMCTrack"), 7.5); + } + if (t2) { + if (dataQA) + registry.fill(HIST("QATrack/hSelection"), 8.5); + if (MCTruthQA) + registry.fill(HIST("QAMC/Truth/hMCTrack"), 8.5); + } + } return true; } - template bool selectedPair(TLorentzVector& mother, const T& track1, const T& track2) { @@ -181,91 +412,130 @@ struct phianalysisTHnSparse { d2.SetXYZM(track2.px(), track2.py(), track2.pz(), massNeg); mother = d1 + d2; - if (std::abs(mother.Rapidity()) > 0.5) + if (std::abs(mother.Eta()) > etapair) return false; return true; } - template - float GetMultiplicity(const T& collision) + float getMultiplicity(const T& collision) { - float multiplicity = collision.multFV0C() + collision.multFV0A(); + float multiplicity = collision.multFT0C() + collision.multFT0A(); return multiplicity; } + template + float getCentrality(const T& collision) + { + float centrality = collision.centFT0M(); + return centrality; + } - void processData(EventCandidate const& collision, TrackCandidates const& /*tracks*/) + double* fillPointPair(double im, double pt, double mu, double ce, double ns1, double ns2, double eta, double y, double vz, double mum, double cem, double vzm) { - float multiplicity; + pointPair[static_cast(o2::analysis::rsn::PairAxisType::im)] = im; + pointPair[static_cast(o2::analysis::rsn::PairAxisType::pt)] = pt; + pointPair[static_cast(o2::analysis::rsn::PairAxisType::mu)] = mu; + pointPair[static_cast(o2::analysis::rsn::PairAxisType::ce)] = ce; + pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns1)] = ns1; + pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns2)] = ns2; + pointPair[static_cast(o2::analysis::rsn::PairAxisType::eta)] = eta; + pointPair[static_cast(o2::analysis::rsn::PairAxisType::y)] = y; + pointPair[static_cast(o2::analysis::rsn::PairAxisType::vz)] = vz; + pointPair[static_cast(o2::analysis::rsn::PairAxisType::mum)] = mum; + pointPair[static_cast(o2::analysis::rsn::PairAxisType::cem)] = cem; + pointPair[static_cast(o2::analysis::rsn::PairAxisType::vzm)] = vzm; + + return pointPair; + } + void processData(EventCandidate const& collision, TrackCandidates const& /*tracks*/) + { auto posDauthers = positive->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto negDauthers = negative->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - if (static_cast(verbose.ignorezeroevent) && collision.globalIndex() == 0) { - if (static_cast(verbose.verboselevel) > 0) - LOGF(info, "BAD pos=%lld neg=%lld, Z vertex position: %f [cm], %d, mult:%f.0", posDauthers.size(), negDauthers.size(), collision.posZ(), - collision.globalIndex(), GetMultiplicity(collision)); - return; + if (produceQA) { + registry.fill(HIST("QAEvent/hSelection"), 0.5); + registry.fill(HIST("QAEvent/h2Size"), posDauthers.size(), negDauthers.size()); + registry.fill(HIST("QAEvent/hVtxZ"), collision.posZ()); + registry.fill(HIST("QAEvent/hMult"), getMultiplicity(collision)); + registry.fill(HIST("QAEvent/hCent"), getCentrality(collision)); } - if (static_cast(produce.QA)) - registry.fill(HIST("QAEvent/s4Size"), posDauthers.size(), negDauthers.size(), GetMultiplicity(collision), collision.posZ()); - multiplicity = GetMultiplicity(collision); + if (static_cast(verbose.verboselevel) > 0 && static_cast(verbose.refresh) > 0 && collision.globalIndex() % static_cast(verbose.refresh) == static_cast(verbose.refreshIndex)) + LOGF(info, "%d pos=%lld neg=%lld, Z vertex position: %f [cm]", collision.globalIndex(), posDauthers.size(), negDauthers.size(), collision.posZ()); - if (static_cast(verbose.verboselevel) > 0 && static_cast(verbose.refresh) > 0 && collision.globalIndex() % static_cast(verbose.refresh) == static_cast(verbose.refresh_index)) - LOGF(info, "pos=%lld neg=%lld, Z vertex position: %f [cm], %d, mult:%f.0", posDauthers.size(), negDauthers.size(), collision.posZ(), - collision.globalIndex(), multiplicity); + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthers, negDauthers))) { + if (produceQA) { + registry.fill(HIST("QATrack/hSelection"), 0.5); - if (static_cast(produce.QA)) - registry.fill(HIST("QAEvent/hVtxZ"), collision.posZ()); - - pointEvent[0] = collision.posZ(); - rsnOutput->fill(o2::analysis::rsn::EventType::zvertex, pointEvent); + registry.fill(HIST("QATrack/bs/hTrack1pt"), track1.pt()); + registry.fill(HIST("QATrack/bs/hTrack1DCAxy"), track1.dcaXY()); + registry.fill(HIST("QATrack/bs/hTrack1DCAz"), track1.dcaZ()); + registry.fill(HIST("QATrack/bs/hTrack1eta"), track1.eta()); + registry.fill(HIST("QATrack/bs/hTrack1tpcNClsFound"), track1.tpcNClsFound()); - for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthers, negDauthers))) { - if (static_cast(produce.QA)) { - registry.fill(HIST("QATrack/unlikepm/beforeSelection/hTrack1pt"), track1.pt()); - registry.fill(HIST("QATrack/unlikepm/beforeSelection/hTrackDCAxy"), track1.dcaXY()); - registry.fill(HIST("QATrack/unlikepm/beforeSelection/hTrackDCAz"), track1.dcaZ()); - registry.fill(HIST("QATrack/unlikepm/beforeSelection/hTrack1eta"), track1.eta()); + registry.fill(HIST("QATrack/bs/hTrack2pt"), track2.pt()); + registry.fill(HIST("QATrack/bs/hTrack2DCAxy"), track2.dcaXY()); + registry.fill(HIST("QATrack/bs/hTrack2DCAz"), track2.dcaZ()); + registry.fill(HIST("QATrack/bs/hTrack2eta"), track2.eta()); + registry.fill(HIST("QATrack/bs/hTrack2tpcNClsFound"), track2.tpcNClsFound()); } + + dataQA = true; + t1 = true; if (!selectedTrack(track1)) continue; - + t1 = false; + t2 = true; if (!selectedTrack(track2)) continue; - - if (static_cast(produce.QA)) { - registry.fill(HIST("QATrack/unlikepm/afterSelection/hTrack1pt"), track1.pt()); - registry.fill(HIST("QATrack/unlikepm/afterSelection/hTrackDCAxy"), track1.dcaXY()); - registry.fill(HIST("QATrack/unlikepm/afterSelection/hTrackDCAz"), track1.dcaZ()); - registry.fill(HIST("QATrack/unlikepm/afterSelection/hTrack1eta"), track1.eta()); + t2 = false; + dataQA = false; + + if (produceQA) { + registry.fill(HIST("QATrack/hSelection"), 9.5); + + registry.fill(HIST("QATrack/as/hTrack1pt"), track1.pt()); + registry.fill(HIST("QATrack/as/hTrack1DCAxy"), track1.dcaXY()); + registry.fill(HIST("QATrack/as/hTrack1DCAz"), track1.dcaZ()); + registry.fill(HIST("QATrack/as/hTrack1eta"), track1.eta()); + registry.fill(HIST("QATrack/as/hTrack1tpcNClsFound"), track1.tpcNClsFound()); + + registry.fill(HIST("QATrack/as/hTrack2pt"), track2.pt()); + registry.fill(HIST("QATrack/as/hTrack2DCAxy"), track2.dcaXY()); + registry.fill(HIST("QATrack/as/hTrack2DCAz"), track2.dcaZ()); + registry.fill(HIST("QATrack/as/hTrack2eta"), track2.eta()); + registry.fill(HIST("QATrack/as/hTrack2tpcNClsFound"), track2.tpcNClsFound()); } if (!selectedPair(mother, track1, track2)) continue; - if (static_cast(produce.QA)) - registry.fill(HIST("QATrack/unlikepm/TPCPID/h2TracknSigma"), track1.tpcNSigmaKa(), track2.tpcNSigmaKa()); - - if (static_cast(verbose.verboselevel) > 1) - LOGF(info, "Unlike-sign: d1=%ld , d2=%ld , mother=%f", track1.globalIndex(), track2.globalIndex(), mother.Mag()); + if (produceQA) { + registry.fill(HIST("QATrack/hSelection"), 10.5); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::im)] = mother.Mag(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::pt)] = mother.Pt(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mu)] = multiplicity; - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns1)] = std::abs(track1.tpcNSigmaKa()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns2)] = std::abs(track2.tpcNSigmaKa()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::y)] = mother.Rapidity(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vz)] = collision.posZ(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mum)] = multiplicity; - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vzm)] = collision.posZ(); + registry.fill(HIST("QATrack/TPCPID/h2TracknSigma"), track1.tpcNSigmaKa(), track2.tpcNSigmaKa()); + registry.fill(HIST("QATrack/TPCPID/h2nTrack1SigmaPt"), track1.pt(), track1.tpcNSigmaKa()); + registry.fill(HIST("QATrack/TPCPID/h2nTrack2SigmaPt"), track2.pt(), track2.tpcNSigmaKa()); + } + pointPair = fillPointPair(mother.Mag(), + mother.Pt(), + getMultiplicity(collision), + getCentrality(collision), + (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), + (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + mother.Eta(), + mother.Rapidity(), + collision.posZ(), + 0, + 0, + 0); rsnOutput->fillUnlikepm(pointPair); } - if (static_cast(produce.Likesign)) { + if (static_cast(produce.produceLikesign)) { - for (auto& [track1, track2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(posDauthers, posDauthers))) { + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(posDauthers, posDauthers))) { if (!selectedTrack(track1)) continue; if (!selectedTrack(track2)) @@ -277,20 +547,23 @@ struct phianalysisTHnSparse { if (static_cast(verbose.verboselevel) > 1) LOGF(info, "Like-sign positive: d1=%ld , d2=%ld , mother=%f", track1.globalIndex(), track2.globalIndex(), mother.Mag()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::im)] = mother.Mag(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::pt)] = mother.Pt(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mu)] = multiplicity; - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns1)] = std::abs(track1.tpcNSigmaKa()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns2)] = std::abs(track2.tpcNSigmaKa()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::y)] = mother.Rapidity(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vz)] = collision.posZ(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mum)] = multiplicity; - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vzm)] = collision.posZ(); + pointPair = fillPointPair(mother.Mag(), + mother.Pt(), + getMultiplicity(collision), + getCentrality(collision), + (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), + (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + mother.Eta(), + mother.Rapidity(), + collision.posZ(), + 0, + 0, + 0); rsnOutput->fillLikepp(pointPair); } - for (auto& [track1, track2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(negDauthers, negDauthers))) { + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(negDauthers, negDauthers))) { if (!selectedTrack(track1)) continue; if (!selectedTrack(track2)) @@ -302,27 +575,32 @@ struct phianalysisTHnSparse { if (static_cast(verbose.verboselevel) > 1) LOGF(info, "Like-sign negative: d1=%ld , d2=%ld , mother=%f", track1.globalIndex(), track2.globalIndex(), mother.Mag()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::im)] = mother.Mag(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::pt)] = mother.Pt(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mu)] = multiplicity; - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns1)] = std::abs(track1.tpcNSigmaKa()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns2)] = std::abs(track2.tpcNSigmaKa()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::y)] = mother.Rapidity(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vz)] = collision.posZ(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mum)] = multiplicity; - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vzm)] = collision.posZ(); + pointPair = fillPointPair(mother.Mag(), + mother.Pt(), + getMultiplicity(collision), + getCentrality(collision), + (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), + (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + mother.Eta(), + mother.Rapidity(), + collision.posZ(), + 0, + 0, + 0); rsnOutput->fillLikemm(pointPair); } } } - PROCESS_SWITCH(phianalysisTHnSparse, processData, "Process Event for Data", true); + PROCESS_SWITCH(PhianalysisTHnSparse, processData, "Process Event for Data", true); void processTrue(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& /*tracks*/, aod::McParticles const& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) { - if (!static_cast(produce.True)) + if (!static_cast(produce.produceTrue)) return; + registry.fill(HIST("QAMC/Truth/hMCEvent"), 0.5); + auto posDauthersMC = positiveMC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto negDauthersMC = negativeMC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); @@ -331,10 +609,8 @@ struct phianalysisTHnSparse { return; } - if (std::abs(collision.posZ()) > static_cast(cut.vZ)) - return; - - for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthersMC, negDauthersMC))) { + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthersMC, negDauthersMC))) { + registry.fill(HIST("QAMC/Truth/hMCTrack"), 0.5); if (!track1.has_mcParticle()) { LOGF(warning, "No MC particle for track, skip..."); @@ -346,11 +622,18 @@ struct phianalysisTHnSparse { continue; } + MCTruthQA = true; + t1 = true; if (!selectedTrack(track1)) continue; - + t1 = false; + t2 = true; if (!selectedTrack(track2)) continue; + t2 = false; + MCTruthQA = false; + + registry.fill(HIST("QAMC/Truth/hMCTrack"), 9.5); const auto mctrack1 = track1.mcParticle(); const auto mctrack2 = track2.mcParticle(); @@ -360,165 +643,278 @@ struct phianalysisTHnSparse { if (!(track1PDG == dautherPosPDG && track2PDG == dautherNegPDG)) { continue; } - for (auto& mothertrack1 : mctrack1.mothers_as()) { - for (auto& mothertrack2 : mctrack2.mothers_as()) { + if (produceQA) + registry.fill(HIST("QAMC/Truth/hMCTrack"), 10.5); + + n = 0; + for (const auto& mothertrack1 : mctrack1.mothers_as()) { + for (const auto& mothertrack2 : mctrack2.mothers_as()) { + if (produceQA) + registry.fill(HIST("QAMC/Truth/hMCTrack"), 11.5); + if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) continue; + if (produceQA) + registry.fill(HIST("QAMC/Truth/hMCTrack"), 12.5); if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) continue; + if (produceQA) + registry.fill(HIST("QAMC/Truth/hMCTrack"), 13.5); if (std::abs(mothertrack1.y()) > static_cast(cut.y)) continue; - - if (std::abs(mothertrack2.y()) > static_cast(cut.y)) - continue; + if (produceQA) + registry.fill(HIST("QAMC/Truth/hMCTrack"), 14.5); if (std::abs(mothertrack1.pdgCode()) != motherPDG) continue; + if (produceQA) + registry.fill(HIST("QAMC/Truth/hMCTrack"), 15.5); - n++; - if (static_cast(verbose.verboselevel) > 1) + if (static_cast(verbose.verboselevel) > 1) { LOGF(info, "True: %d, d1=%d (%ld), d2=%d (%ld), mother=%d (%ld)", n, mctrack1.pdgCode(), mctrack1.globalIndex(), mctrack2.pdgCode(), mctrack2.globalIndex(), mothertrack1.pdgCode(), mothertrack1.globalIndex()); + LOGF(info, "%d px: %f, py=%f, pz=%f, px: %f, py=%f, pz=%f", n, mctrack1.px(), mctrack1.py(), mctrack1.pz(), mctrack2.px(), mctrack2.py(), mctrack2.pz()); + } if (!selectedPair(mother, mctrack1, mctrack2)) continue; + if (produceQA) + registry.fill(HIST("QAMC/Truth/hMCTrack"), 16.5); + + if (n > 0) { + if (produceQA) + registry.fill(HIST("QAMC/hInvMassTrueFalse"), mother.Mag()); + continue; + } - pointPair[static_cast(o2::analysis::rsn::PairAxisType::im)] = mother.Mag(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::pt)] = mother.Pt(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mu)] = GetMultiplicity(collision); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns1)] = std::abs(track1.tpcNSigmaKa()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns2)] = std::abs(track2.tpcNSigmaKa()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::y)] = mother.Rapidity(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vz)] = collision.posZ(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mum)] = GetMultiplicity(collision); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vzm)] = collision.posZ(); + pointPair = fillPointPair(mother.Mag(), + mother.Pt(), + getMultiplicity(collision), + getCentrality(collision), + (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), + (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + mother.Eta(), + mother.Rapidity(), + collision.posZ(), + 0, + 0, + 0); rsnOutput->fillUnliketrue(pointPair); + n++; } } } } + PROCESS_SWITCH(PhianalysisTHnSparse, processTrue, "Process Event for MC reconstruction.", false); - PROCESS_SWITCH(phianalysisTHnSparse, processTrue, "Process Event for MC reconstruction.", false); - - int numberofEntries = 0; - - void processGen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) + void processGen(aod::McCollision const& mcCollision, soa::SmallGroups const& collisions, LabeledTracks const& /*particles*/, aod::McParticles const& mcParticles) { - float multiplicity = 0; - - if (!static_cast(produce.True)) + registry.fill(HIST("QAMC/Gen/hMCEvent"), 0.5); + if (std::abs(mcCollision.posZ()) > static_cast(cut.vZ)) return; + registry.fill(HIST("QAMC/Gen/hMCEvent"), 1.5); - if (std::abs(mcCollision.posZ()) > static_cast(cut.vZ)) + if (collisions.size() == 0) return; - int nuberofPhi = 0; + for (const auto& collision : collisions) { + registry.fill(HIST("QAMC/Gen/hMCEvent"), 2.5); - for (auto& particle : mcParticles) { - if (std::abs(particle.y()) > static_cast(cut.y)) - continue; + if (!collision.has_mcCollision()) { + LOGF(warning, "No McCollision for this collision, skip..."); + return; + } - if (particle.pdgCode() == motherPDG) { - auto daughters = particle.daughters_as(); - if (daughters.size() != 2) + auto centralityGen = 0; + centralityGen = getCentrality(collision); + auto multiplicityGen = 0; + multiplicityGen = getMultiplicity(collision); + + for (const auto& particle : mcParticles) { + registry.fill(HIST("QAMC/Gen/hMCTrack"), 0.5); + + if (std::abs(particle.y()) > static_cast(cut.y)) continue; - auto daup = false; - auto daun = false; + registry.fill(HIST("QAMC/Gen/hMCTrack"), 1.5); - for (auto& dau : daughters) { - if (!dau.isPhysicalPrimary()) + if (particle.pdgCode() == motherPDG) { + registry.fill(HIST("QAMC/Gen/hMCTrack"), 2.5); + + auto daughters = particle.daughters_as(); + if (daughters.size() != 2) continue; - if (dau.pdgCode() == dautherPosPDG) { - daup = true; - d1.SetXYZM(dau.px(), dau.py(), dau.pz(), massPos); - } else if (dau.pdgCode() == -dautherNegPDG) { - daun = true; - d2.SetXYZM(dau.px(), dau.py(), dau.pz(), massNeg); - } - } - if (!daup && !daun) - continue; + registry.fill(HIST("QAMC/Gen/hMCTrack"), 3.5); - mother = d1 + d2; + auto daup = false; + auto daun = false; - pointPair[static_cast(o2::analysis::rsn::PairAxisType::im)] = mother.Mag(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::pt)] = mother.Pt(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mu)] = multiplicity; - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns1)] = std::abs(static_cast(cut.tpcnSigmaPos) / 2.0); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns2)] = std::abs(static_cast(cut.tpcnSigmaNeg) / 2.0); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::y)] = mother.Rapidity(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vz)] = mcCollision.posZ(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mum)] = multiplicity; - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vzm)] = mcCollision.posZ(); + for (const auto& dau : daughters) { + registry.fill(HIST("QAMC/Gen/hMCTrack"), 4.5); - rsnOutput->fillUnlikegen(pointPair); + if (!dau.isPhysicalPrimary()) + continue; - nuberofPhi++; - numberofEntries++; + registry.fill(HIST("QAMC/Gen/hMCTrack"), 5.5); - if (static_cast(verbose.verboselevel) > 1) - LOGF(info, "Gen: %d, #Phi =%d, mother=%d (%ld), Inv.mass:%f, Pt= %f", numberofEntries, nuberofPhi, particle.pdgCode(), particle.globalIndex(), mother.Mag(), mother.Pt()); + if (dau.pdgCode() == dautherPosPDG) { + daup = true; + d1.SetXYZM(dau.px(), dau.py(), dau.pz(), massPos); + } else if (dau.pdgCode() == -dautherNegPDG) { + daun = true; + d2.SetXYZM(dau.px(), dau.py(), dau.pz(), massNeg); + } + } + if (!daup && !daun) + continue; + + registry.fill(HIST("QAMC/Gen/hMCTrack"), 6.5); + + mother = d1 + d2; + + pointPair = fillPointPair(mother.Mag(), + mother.Pt(), + multiplicityGen, + centralityGen, + std::abs(static_cast(cut.tpcnSigmaPos) / 2.0), + std::abs(static_cast(cut.tpcnSigmaNeg) / 2.0), + mother.Eta(), + mother.Rapidity(), + mcCollision.posZ(), + 0, + 0, + 0); + + rsnOutput->fillUnlikegen(pointPair); + } } } } - - PROCESS_SWITCH(phianalysisTHnSparse, processGen, "Process generated.", false); + PROCESS_SWITCH(PhianalysisTHnSparse, processGen, "Process MC Mateched.", true); void processMixed(EventCandidates const& collisions, TrackCandidates const& tracks) { - if (!static_cast(produce.eventMixing)) + if (mixingType == rsn::MixingType::none) return; auto tracksTuple = std::make_tuple(tracks); - SameKindPair pair{binning, numberofMixedEvents, -1, collisions, tracksTuple, &cache}; - for (auto& [c1, tracks1, c2, tracks2] : pair) { - if (!c1.sel8()) { - continue; - } - if (!c2.sel8()) { - continue; - } + BinningTypeVzCe binningVzCe{{axisVertexMixing, axisCentralityMixing}, true}; + SameKindPair pairVzCe{binningVzCe, numberofMixedEvents, -1, collisions, tracksTuple, &cache}; - auto posDauthersc1 = positive->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); - auto posDauthersc2 = positive->sliceByCached(aod::track::collisionId, c2.globalIndex(), cache); - auto negDauthersc1 = negative->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); - auto negDauthersc2 = negative->sliceByCached(aod::track::collisionId, c2.globalIndex(), cache); + BinningTypeVzMu binningVzMu{{axisVertexMixing, axisMultiplicityMixing}, true}; + SameKindPair pairVzMu{binningVzMu, numberofMixedEvents, -1, collisions, tracksTuple, &cache}; - for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthersc1, negDauthersc2))) { + if (mixingType == rsn::MixingType::ce) { + for (const auto& [c1, tracks1, c2, tracks2] : pairVzCe) { + if (produceQA) + registry.fill(HIST("QAMixing/hSelection"), 0.5); - if (!selectedTrack(track1)) + auto posDauthersc1 = positive->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); + auto posDauthersc2 = positive->sliceByCached(aod::track::collisionId, c2.globalIndex(), cache); + auto negDauthersc1 = negative->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); + auto negDauthersc2 = negative->sliceByCached(aod::track::collisionId, c2.globalIndex(), cache); - continue; - if (!selectedTrack(track2)) - continue; + if (produceQA) { + registry.fill(HIST("QAMixing/h2mu1_mu2"), getMultiplicity(c1), getMultiplicity(c2)); + registry.fill(HIST("QAMixing/h2ce1_ce2"), getCentrality(c1), getCentrality(c2)); + registry.fill(HIST("QAMixing/h2vz1_vz2"), c1.posZ(), c2.posZ()); + } - if (!selectedPair(mother, track1, track2)) - continue; + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthersc1, negDauthersc2))) { + if (produceQA) + registry.fill(HIST("QAMixing/hTrackSelection"), 0.5); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::im)] = mother.Mag(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::pt)] = mother.Pt(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mu)] = GetMultiplicity(c1); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns1)] = std::abs(track1.tpcNSigmaKa()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns2)] = std::abs(track2.tpcNSigmaKa()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::y)] = mother.Rapidity(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vz)] = c1.posZ(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mum)] = GetMultiplicity(c2); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vzm)] = c2.posZ(); + if (!selectedTrack(track1)) + continue; + if (produceQA) + registry.fill(HIST("QAMixing/hTrackSelection"), 1.5); + if (!selectedTrack(track2)) + continue; + if (produceQA) + registry.fill(HIST("QAMixing/hTrackSelection"), 2.5); - rsnOutput->fillMixingpm(pointPair); + if (!selectedPair(mother, track1, track2)) + continue; + if (produceQA) + registry.fill(HIST("QAMixing/hTrackSelection"), 3.5); + + pointPair = fillPointPair(mother.Mag(), + mother.Pt(), + getMultiplicity(c1), + getCentrality(c1), + (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), + (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + mother.Eta(), + mother.Rapidity(), + c1.posZ(), + getMultiplicity(c2), + getCentrality(c2), + c2.posZ()); + + rsnOutput->fillMixingpm(pointPair); + } - if (static_cast(produce.QA)) - registry.fill(HIST("QAMixing/s4Multiplicity"), GetMultiplicity(c1), GetMultiplicity(c2), c1.posZ(), c2.posZ()); - } + if (static_cast(produce.produceLikesign)) { + + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthersc1, posDauthersc2))) { + + if (!selectedTrack(track1)) - if (static_cast(produce.Likesign)) { + continue; + if (!selectedTrack(track2)) + continue; - for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthersc1, posDauthersc2))) { + if (!selectedPair(mother, track1, track2)) + continue; + + pointPair = fillPointPair(mother.Mag(), + mother.Pt(), + getMultiplicity(c1), + getCentrality(c1), + (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), + (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + mother.Eta(), + mother.Rapidity(), + c1.posZ(), + getMultiplicity(c2), + getCentrality(c2), + c2.posZ()); + + rsnOutput->fillMixingpp(pointPair); + } + + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(negDauthersc1, negDauthersc2))) { + + if (!selectedTrack(track1)) + + continue; + if (!selectedTrack(track2)) + continue; + + if (!selectedPair(mother, track1, track2)) + continue; + pointPair = fillPointPair(mother.Mag(), + mother.Pt(), + getMultiplicity(c1), + getCentrality(c1), + (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), + (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + mother.Eta(), + mother.Rapidity(), + c1.posZ(), + getMultiplicity(c2), + getCentrality(c2), + c2.posZ()); + + rsnOutput->fillMixingmm(pointPair); + } + } + + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthersc2, negDauthersc1))) { if (!selectedTrack(track1)) @@ -529,20 +925,130 @@ struct phianalysisTHnSparse { if (!selectedPair(mother, track1, track2)) continue; - pointPair[static_cast(o2::analysis::rsn::PairAxisType::im)] = mother.Mag(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::pt)] = mother.Pt(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mu)] = GetMultiplicity(c1); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns1)] = std::abs(track1.tpcNSigmaKa()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns2)] = std::abs(track2.tpcNSigmaKa()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::y)] = mother.Rapidity(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vz)] = c1.posZ(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mum)] = GetMultiplicity(c2); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vzm)] = c2.posZ(); - - rsnOutput->fillMixingpp(pointPair); + pointPair = fillPointPair(mother.Mag(), + mother.Pt(), + getMultiplicity(c1), + getCentrality(c1), + (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), + (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + mother.Eta(), + mother.Rapidity(), + c1.posZ(), + getMultiplicity(c2), + getCentrality(c2), + c2.posZ()); + + rsnOutput->fillMixingmp(pointPair); + } + } + } + if (mixingType == rsn::MixingType::mu) { + for (const auto& [c1, tracks1, c2, tracks2] : pairVzMu) { + if (produceQA) + registry.fill(HIST("QAMixing/hSelection"), 0.5); + + auto posDauthersc1 = positive->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); + auto posDauthersc2 = positive->sliceByCached(aod::track::collisionId, c2.globalIndex(), cache); + auto negDauthersc1 = negative->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); + auto negDauthersc2 = negative->sliceByCached(aod::track::collisionId, c2.globalIndex(), cache); + + if (produceQA) { + registry.fill(HIST("QAMixing/h2mu1_mu2"), getMultiplicity(c1), getMultiplicity(c2)); + registry.fill(HIST("QAMixing/h2ce1_ce2"), getCentrality(c1), getCentrality(c2)); + registry.fill(HIST("QAMixing/h2vz1_vz2"), c1.posZ(), c2.posZ()); + } + + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthersc1, negDauthersc2))) { + if (produceQA) + registry.fill(HIST("QAMixing/hTrackSelection"), 0.5); + + if (!selectedTrack(track1)) + continue; + if (produceQA) + registry.fill(HIST("QAMixing/hTrackSelection"), 1.5); + if (!selectedTrack(track2)) + continue; + if (produceQA) + registry.fill(HIST("QAMixing/hTrackSelection"), 2.5); + + if (!selectedPair(mother, track1, track2)) + continue; + if (produceQA) + registry.fill(HIST("QAMixing/hTrackSelection"), 3.5); + + pointPair = fillPointPair(mother.Mag(), + mother.Pt(), + getMultiplicity(c1), + getCentrality(c1), + (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), + (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + mother.Eta(), + mother.Rapidity(), + c1.posZ(), + getMultiplicity(c2), + getCentrality(c2), + c2.posZ()); + + rsnOutput->fillMixingpm(pointPair); + } + + if (static_cast(produce.produceLikesign)) { + + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthersc1, posDauthersc2))) { + + if (!selectedTrack(track1)) + + continue; + if (!selectedTrack(track2)) + continue; + + if (!selectedPair(mother, track1, track2)) + continue; + + pointPair = fillPointPair(mother.Mag(), + mother.Pt(), + getMultiplicity(c1), + getCentrality(c1), + (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), + (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + mother.Eta(), + mother.Rapidity(), + c1.posZ(), + getMultiplicity(c2), + getCentrality(c2), + c2.posZ()); + + rsnOutput->fillMixingpp(pointPair); + } + + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(negDauthersc1, negDauthersc2))) { + + if (!selectedTrack(track1)) + + continue; + if (!selectedTrack(track2)) + continue; + + if (!selectedPair(mother, track1, track2)) + continue; + pointPair = fillPointPair(mother.Mag(), + mother.Pt(), + getMultiplicity(c1), + getCentrality(c1), + (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), + (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + mother.Eta(), + mother.Rapidity(), + c1.posZ(), + getMultiplicity(c2), + getCentrality(c2), + c2.posZ()); + + rsnOutput->fillMixingmm(pointPair); + } } - for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(negDauthersc1, negDauthersc2))) { + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthersc2, negDauthersc1))) { if (!selectedTrack(track1)) @@ -553,50 +1059,96 @@ struct phianalysisTHnSparse { if (!selectedPair(mother, track1, track2)) continue; - pointPair[static_cast(o2::analysis::rsn::PairAxisType::im)] = mother.Mag(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::pt)] = mother.Pt(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mu)] = GetMultiplicity(c1); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns1)] = std::abs(track1.tpcNSigmaKa()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns2)] = std::abs(track2.tpcNSigmaKa()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::y)] = mother.Rapidity(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vz)] = c1.posZ(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mum)] = GetMultiplicity(c2); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vzm)] = c2.posZ(); - - rsnOutput->fillMixingmm(pointPair); + pointPair = fillPointPair(mother.Mag(), + mother.Pt(), + getMultiplicity(c1), + getCentrality(c1), + (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), + (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + mother.Eta(), + mother.Rapidity(), + c1.posZ(), + getMultiplicity(c2), + getCentrality(c2), + c2.posZ()); + + rsnOutput->fillMixingmp(pointPair); } } + } + } + PROCESS_SWITCH(PhianalysisTHnSparse, processMixed, "Process Mixing Event.", true); - for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthersc2, negDauthersc1))) { + void processGenOld(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) + { + if (!static_cast(produce.produceTrue)) + return; - if (!selectedTrack(track1)) + registry.fill(HIST("QAMC/hMC"), 0.5); - continue; - if (!selectedTrack(track2)) + if (std::abs(mcCollision.posZ()) > static_cast(cut.vZ)) + return; + + registry.fill(HIST("QAMC/hMC"), 1.5); + + for (const auto& particle : mcParticles) { + registry.fill(HIST("QAMC/hMC"), 2.5); + if (std::abs(particle.y()) > static_cast(cut.y)) + continue; + + registry.fill(HIST("QAMC/hMC"), 3.5); + + if (particle.pdgCode() == motherPDG) { + auto daughters = particle.daughters_as(); + if (daughters.size() != 2) continue; - if (!selectedPair(mother, track1, track2)) + registry.fill(HIST("QAMC/hMC"), 4.5); + + auto daup = false; + auto daun = false; + + for (const auto& dau : daughters) { + if (!dau.isPhysicalPrimary()) + continue; + + if (dau.pdgCode() == dautherPosPDG) { + daup = true; + d1.SetXYZM(dau.px(), dau.py(), dau.pz(), massPos); + } else if (dau.pdgCode() == -dautherNegPDG) { + daun = true; + d2.SetXYZM(dau.px(), dau.py(), dau.pz(), massNeg); + } + } + if (!daup && !daun) continue; - pointPair[static_cast(o2::analysis::rsn::PairAxisType::im)] = mother.Mag(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::pt)] = mother.Pt(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mu)] = GetMultiplicity(c1); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns1)] = std::abs(track1.tpcNSigmaKa()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::ns2)] = std::abs(track2.tpcNSigmaKa()); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::y)] = mother.Rapidity(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vz)] = c1.posZ(); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::mum)] = GetMultiplicity(c2); - pointPair[static_cast(o2::analysis::rsn::PairAxisType::vzm)] = c2.posZ(); - - rsnOutput->fillMixingmp(pointPair); + registry.fill(HIST("QAMC/hMC"), 5.5); + + mother = d1 + d2; + + pointPair = fillPointPair(mother.Mag(), + mother.Pt(), + 0, + 0, + std::abs(static_cast(cut.tpcnSigmaPos) / 2.0), + std::abs(static_cast(cut.tpcnSigmaNeg) / 2.0), + mother.Eta(), + mother.Rapidity(), + mcCollision.posZ(), + 0, + 0, + 0); + + rsnOutput->fillUnlikegenOld(pointPair); } } } - PROCESS_SWITCH(phianalysisTHnSparse, processMixed, "Process Mixing Event.", true); + PROCESS_SWITCH(PhianalysisTHnSparse, processGenOld, "Process generated.", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/Resonances/phianalysisrun3_PbPb.cxx b/PWGLF/Tasks/Resonances/phianalysisrun3_PbPb.cxx index 61a7029b81a..425bb69d512 100644 --- a/PWGLF/Tasks/Resonances/phianalysisrun3_PbPb.cxx +++ b/PWGLF/Tasks/Resonances/phianalysisrun3_PbPb.cxx @@ -27,17 +27,24 @@ #include #include #include -#include #include #include #include +#include +#include "TRandom3.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" +#include "TF1.h" + +#include "PWGLF/DataModel/EPCalibrationTables.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/HistogramRegistry.h" #include "Framework/StepTHn.h" -#include "ReconstructionDataFormats/Track.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Centrality.h" @@ -47,13 +54,17 @@ #include "CommonConstants/PhysicsConstants.h" #include "Common/Core/TrackSelection.h" #include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using std::array; struct phianalysisrun3_PbPb { - SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; // events Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; @@ -62,53 +73,119 @@ struct phianalysisrun3_PbPb { Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; Configurable cfgCutDCAxy{"cfgCutDCAxy", 2.0f, "DCAxy range for tracks"}; Configurable cfgCutDCAz{"cfgCutDCAz", 2.0f, "DCAz range for tracks"}; - Configurable nsigmaCutTPC{"nsigmacutTPC", 3.0, "Value of the TPC Nsigma cut"}; + Configurable nsigmaCutTPC{"nsigmacutTPC", 2.0, "Value of the TPC Nsigma cut"}; + Configurable nsigmaCutTOF{"nsigmacutTOF", 2.0, "Value of the TOF Nsigma cut"}; Configurable nsigmaCutCombined{"nsigmaCutCombined", 3.0, "Value of the TOF Nsigma cut"}; Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 5, "Number of mixed events per event"}; - Configurable isEtaAssym{"isEtaAssym", false, "isEtaAssym"}; + Configurable fillOccupancy{"fillOccupancy", true, "fill Occupancy"}; + Configurable isNoTOF{"isNoTOF", false, "isNoTOF"}; + Configurable additionalEvSel2{"additionalEvSel2", true, "Additional evsel2"}; + Configurable additionalEvSel3{"additionalEvSel3", true, "Additional evsel3"}; Configurable cfgMultFT0{"cfgMultFT0", true, "cfgMultFT0"}; Configurable iscustomDCAcut{"iscustomDCAcut", false, "iscustomDCAcut"}; Configurable ismanualDCAcut{"ismanualDCAcut", true, "ismanualDCAcut"}; - Configurable isITSOnlycut{"isITSOnlycut", true, "isITSOnlycut"}; + Configurable ispTdepPID{"ispTdepPID", true, "pT dependent PID"}; Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; + Configurable confRapidity{"confRapidity", 0.5, "Rapidity cut"}; + Configurable timFrameEvsel{"timFrameEvsel", false, "TPC Time frame boundary cut"}; Configurable isDeepAngle{"isDeepAngle", false, "Deep Angle cut"}; Configurable cfgDeepAngle{"cfgDeepAngle", 0.04, "Deep Angle cut value"}; + Configurable nBkgRotations{"nBkgRotations", 3, "Number of rotated copies (background) per each original candidate"}; + Configurable fillRotation{"fillRotation", true, "fill rotation"}; + Configurable confMinRot{"confMinRot", 5.0 * TMath::Pi() / 6.0, "Minimum of rotation"}; + Configurable confMaxRot{"confMaxRot", 7.0 * TMath::Pi() / 6.0, "Maximum of rotation"}; + Configurable PDGcheck{"PDGcheck", true, "PDGcheck"}; + Configurable Reco{"Reco", true, "Reco"}; + ConfigurableAxis binsImpactPar{"binsImpactPar", {VARIABLE_WIDTH, 0, 3.5, 5.67, 7.45, 8.85, 10.0, 11.21, 12.26, 13.28, 14.23, 15.27}, "Binning of the impact parameter axis"}; + ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.6, 0.8, 1, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 10.0, 12.0}, "Binning of the pT axis"}; + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0}, "Binning of the centrality axis"}; + Configurable cfgCutCentrality{"cfgCutCentrality", 80.0f, "Accepted maximum Centrality"}; + Configurable cfgCutMaxOccupancy{"cfgCutMaxOccupancy", 2000.0f, "Accepted maximum Occupancy"}; + Configurable cfgApplyOccupancyCut{"cfgApplyOccupancyCut", false, "Apply maximum Occupancy"}; + Configurable cfgCutOccupancy{"cfgCutOccupancy", 3000, "Occupancy cut"}; + + Configurable genacceptancecut{"genacceptancecut", true, "use acceptance cut for generated"}; // MC Configurable isMC{"isMC", false, "Run MC"}; + Configurable avoidsplitrackMC{"avoidsplitrackMC", false, "avoid split track in MC"}; void init(o2::framework::InitContext&) { + AxisSpec impactParAxis = {binsImpactPar, "Impact Parameter"}; + AxisSpec ptAxis = {binsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec centAxis = {binsCent, "V0M (%)"}; histos.add("hCentrality", "Centrality distribution", kTH1F, {{200, 0.0, 200.0}}); histos.add("hVtxZ", "Vertex distribution in Z;Z (cm)", kTH1F, {{400, -20.0, 20.0}}); - histos.add("hNcontributor", "Number of primary vertex contributor", kTH1F, {{2000, 0.0f, 10000.0f}}); - histos.add("hFTOCvsTPC", "Mult correlation FT0C vs. TPC", kTH2F, {{90, 0.0f, 90.0f}, {600, -0.5f, 5999.5f}}); + histos.add("hOccupancy", "Occupancy distribution", kTH1F, {{500, 0, 50000}}); if (!isMC) { histos.add("h3PhiInvMassUnlikeSign", "Invariant mass of Phi meson Unlike Sign", kTH3F, {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {200, 0.9, 1.1}}); - histos.add("h3PhiInvMassLikeSignPP", "Invariant mass of Phi meson Like Sign positive", kTH3F, {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {200, 0.9, 1.1}}); - histos.add("h3PhiInvMassLikeSignMM", "Invariant mass of Phi meson Like Sign negative", kTH3F, {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {200, 0.9, 1.1}}); histos.add("h3PhiInvMassMixed", "Invariant mass of Phi meson Mixed", kTH3F, {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {200, 0.9, 1.1}}); - histos.add("h3PhiInvMassRotation", "Invariant mass of Phi meson Rotation", kTH3F, {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {200, 0.9, 1.1}}); - if (isEtaAssym) { - histos.add("h3PhiInvMassUnlikeSignAside", "Invariant mass of Phi meson Unlike Sign A side", kTH3F, {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {200, 0.9, 1.1}}); - histos.add("h3PhiInvMassLikeSignAside", "Invariant mass of Phi meson Like Sign A side", kTH3F, {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {200, 0.9, 1.1}}); - histos.add("h3PhiInvMassMixedAside", "Invariant mass of Phi meson Mixed A side", kTH3F, {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {200, 0.9, 1.1}}); - histos.add("h3PhiInvMassUnlikeSignCside", "Invariant mass of Phi meson Unlike Sign C side", kTH3F, {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {200, 0.9, 1.1}}); - histos.add("h3PhiInvMassLikeSignCside", "Invariant mass of Phi meson Like Sign C side", kTH3F, {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {200, 0.9, 1.1}}); - histos.add("h3PhiInvMassMixedCside", "Invariant mass of Phi meson Mixed C side", kTH3F, {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {200, 0.9, 1.1}}); - } + histos.add("h3PhiInvMassRot", "Invariant mass of Phi meson Rotation", kTH3F, {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {200, 0.9, 1.1}}); + histos.add("h3PhiInvMassSame", "Invariant mass of Phi meson same", kTH3F, {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {200, 0.9, 1.1}}); } else if (isMC) { - histos.add("hMC", "MC Event statistics", kTH1F, {{5, 0.0f, 4.0f}}); + histos.add("hMC", "MC Event statistics", kTH1F, {{10, 0.0f, 10.0f}}); + histos.add("EL1", "MC Event statistics", kTH1F, {impactParAxis}); + histos.add("EL2", "MC Event statistics", kTH1F, {centAxis}); + histos.add("ES1", "MC Event statistics", kTH1F, {impactParAxis}); + histos.add("ES3", "MC Event statistics", kTH1F, {impactParAxis}); + histos.add("ES2", "MC Event statistics", kTH1F, {centAxis}); + histos.add("ES4", "MC Event statistics", kTH1F, {centAxis}); + histos.add("h1PhiGen", "Phi meson Gen", kTH1F, {{200, 0.0f, 20.0f}}); histos.add("h1PhiGen1", "Phi meson Gen", kTH1F, {{200, 0.0f, 20.0f}}); - histos.add("h2PhiRec1", "Phi meson Rec", kTH2F, {{200, 0.0f, 20.0f}, {200, 0.0, 200.0}}); - histos.add("h2PhiGen1", "Phi meson gen", kTH2F, {{200, 0.0f, 20.0f}, {200, 0.0, 200.0}}); - histos.add("h1PhiRec1", "Phi meson Rec", kTH1F, {{200, 0.0f, 20.0f}}); + histos.add("h1PhiRecsplit", "Phi meson Rec split", kTH1F, {{200, 0.0f, 20.0f}}); histos.add("Centrec", "MC Centrality", kTH1F, {{200, 0.0, 200.0}}); histos.add("Centgen", "MC Centrality", kTH1F, {{200, 0.0, 200.0}}); + histos.add("h2PhiRec2", "Phi meson Rec", kTH2F, {{200, 0.0f, 20.0f}, {200, 0.0, 200.0}}); + histos.add("h3PhiRec3", "Phi meson Rec", kTH3F, {{200, 0.0f, 20.0f}, {200, 0.0, 200.0}, {200, 0.9, 1.1}}); + histos.add("h3Phi1Rec3", "Phi meson Rec", kTH3F, {{200, 0.0f, 20.0f}, {200, 0.0, 200.0}, {200, 0.9, 1.1}}); + histos.add("h3PhiGen3", "Phi meson Gen", kTH3F, {{200, 0.0f, 20.0f}, {200, 0.0, 200.0}, {200, 0.9, 1.1}}); + histos.add("h3PhiInvMassMixedMC", "Invariant mass of Phi meson Mixed", kTH3F, {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {200, 0.9, 1.1}}); + histos.add("h3PhiInvMassSameMC", "Invariant mass of Phi meson same", kTH3F, {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {200, 0.9, 1.1}}); + histos.add("h3PhiInvMassRotMC", "Invariant mass of Phi meson Rotation", kTH3F, {{200, 0.0, 200.0}, {200, 0.0f, 20.0f}, {200, 0.9, 1.1}}); + histos.add("h2PhiGen2", "Phi meson gen", kTH2F, {{200, 0.0f, 20.0f}, {200, 0.0, 200.0}}); + histos.add("h2PhiGen1", "Phi meson gen", kTH2F, {ptAxis, impactParAxis}); + histos.add("h1PhiRec1", "Phi meson Rec", kTH1F, {{200, 0.0f, 20.0f}}); + histos.add("h1Phimassgen", "Phi meson gen", kTH1F, {{200, 0.9, 1.1}}); + histos.add("h1Phimassrec", "Phi meson Rec", kTH1F, {{200, 0.9, 1.1}}); + histos.add("h1Phimasssame", "Phi meson Rec", kTH1F, {{200, 0.9, 1.1}}); + histos.add("h1Phimassmix", "Phi meson Rec", kTH1F, {{200, 0.9, 1.1}}); + histos.add("h1Phimassrot", "Phi meson Rec", kTH1F, {{200, 0.9, 1.1}}); + histos.add("h1Phi1massrec", "Phi meson Rec", kTH1F, {{200, 0.9, 1.1}}); + histos.add("h1Phipt", "Phi meson Rec", kTH1F, {{200, 0.0f, 20.0f}}); + histos.add("hOccupancy1", "Occupancy distribution", kTH1F, {{500, 0, 50000}}); + histos.add("hImpactParameterGen", "Impact parameter of generated MC events", kTH1F, {impactParAxis}); + histos.add("hImpactParameterRec", "Impact parameter of generated MC events", kTH1F, {impactParAxis}); + histos.add("hImpactParameterGenCen", "Impact parameter of generated MC events", kTH2F, {impactParAxis, centAxis}); + histos.add("hImpactParameterRecCen", "Impact parameter of generated MC events", kTH2F, {impactParAxis, centAxis}); + histos.add("TOF_Nsigma_MC", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3D, {{200, -12, 12}, {200, 0.0, 200.0}, {200, 0.0f, 20.0f}}}); + histos.add("TPC_Nsigma_MC", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3D, {{200, -12, 12}, {200, 0.0, 200.0}, {200, 0.0f, 20.0f}}}); + if (doprocessEvtLossSigLossMC) { + histos.add("QAevent/hImpactParameterGen", "Impact parameter of generated MC events", kTH1F, {impactParAxis}); + histos.add("QAevent/hImpactParameterRec", "Impact parameter of selected MC events", kTH1F, {impactParAxis}); + histos.add("QAevent/hImpactParvsCentrRec", "Impact parameter of selected MC events vs centrality", kTH2F, {{120, 0.0f, 120.0f}, impactParAxis}); + histos.add("QAevent/phigenBeforeEvtSel", "phi before event selections", kTH2F, {ptAxis, impactParAxis}); + histos.add("QAevent/phigenAfterEvtSel", "phi after event selections", kTH2F, {ptAxis, impactParAxis}); + } } + + // DCA QA + histos.add("QAbefore/trkDCAxy", "DCAxy distribution of kaon track candidates", HistType::kTH1F, {{150, 0.0f, 1.0f}}); + histos.add("QAbefore/trkDCAz", "DCAz distribution of kaon track candidates", HistType::kTH1F, {{150, 0.0f, 1.0f}}); + histos.add("QAafter/trkDCAxy", "DCAxy distribution of kaon track candidates", HistType::kTH1F, {{150, 0.0f, 1.0f}}); + histos.add("QAafter/trkDCAz", "DCAz distribution of kaon track candidates", HistType::kTH1F, {{150, 0.0f, 1.0f}}); + // PID QA before cuts + histos.add("QAbefore/TOF_TPC_Mapka_all", "TOF + TPC Combined PID for Kaon;#sigma_{TOF}^{Kaon};#sigma_{TPC}^{Kaon}", {HistType::kTH2D, {{100, -6, 6}, {100, -6, 6}}}); + histos.add("QAbefore/TOF_Nsigma_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3D, {{200, -12, 12}, {200, 0.0, 200.0}, {200, 0.0f, 20.0f}}}); + histos.add("QAbefore/TPC_Nsigma_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3D, {{200, -12, 12}, {200, 0.0, 200.0}, {200, 0.0f, 20.0f}}}); + // PID QA after cuts + histos.add("QAafter/TOF_TPC_Mapka_all", "TOF + TPC Combined PID for Kaon;#sigma_{TOF}^{Kaon};#sigma_{TPC}^{Kaon}", {HistType::kTH2D, {{100, -6, 6}, {100, -6, 6}}}); + histos.add("QAafter/TOF_Nsigma_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3D, {{200, -12, 12}, {200, 0.0, 200.0}, {200, 0.0f, 20.0f}}}); + histos.add("QAafter/TPC_Nsigma_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3D, {{200, -12, 12}, {200, 0.0, 200.0}, {200, 0.0f, 20.0f}}}); } double massKa = o2::constants::physics::MassKPlus; double rapidity; double genMass, recMass, resolution; + ROOT::Math::PxPyPzMVector phiMother, daughter1, daughter2; double mass{0.}; double massrotation{0.}; double pT{0.}; @@ -124,23 +201,50 @@ struct phianalysisrun3_PbPb { if (ismanualDCAcut && !(candidate.isGlobalTrackWoDCA() && candidate.isPVContributor() && std::abs(candidate.dcaXY()) < cfgCutDCAxy && std::abs(candidate.dcaZ()) < cfgCutDCAz && candidate.itsNCls() > cfgITScluster)) { return false; } - if (isITSOnlycut && !(candidate.isPVContributor() && std::abs(candidate.dcaXY()) < cfgCutDCAxy && std::abs(candidate.dcaZ()) < cfgCutDCAz && candidate.itsNCls() > cfgITScluster)) { - return false; - } return true; } template bool selectionPID(const T& candidate) { - if (candidate.hasTOF() && (candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa()) < (nsigmaCutCombined * nsigmaCutCombined)) { + if (!isNoTOF && candidate.hasTOF() && (candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa()) < (nsigmaCutCombined * nsigmaCutCombined)) { + return true; + } + if (!isNoTOF && !candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return true; + } + if (isNoTOF && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return true; + } + return false; + } + template + bool selectionPIDpTdependent(const T& candidate) + { + if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { return true; } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + if (candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF) { return true; } return false; } + template + bool myEventSelections(const CollType& collision) + { + if (std::abs(collision.posZ()) > cfgCutVertex) + return false; + if (!collision.sel8()) + return false; + if (additionalEvSel2 && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) + return false; + if (additionalEvSel3 && (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) + return false; + int occupancy = collision.trackOccupancyInTimeRange(); + if (fillOccupancy && (occupancy > cfgCutOccupancy)) + return false; + return true; + } // deep angle cut on pair to remove photon conversion template bool selectionPair(const T1& candidate1, const T2& candidate2) @@ -159,112 +263,86 @@ struct phianalysisrun3_PbPb { return true; } template - void FillinvMass(const T1& candidate1, const T2& candidate2, float multiplicity, bool unlike, bool mix, bool likesign, bool rotation, float massd1, float massd2) + void FillinvMass(const T1& candidate1, const T2& candidate2, float multiplicity, bool unlike, bool mix, float massd1, float massd2) { pvec0 = array{candidate1.px(), candidate1.py(), candidate1.pz()}; pvec1 = array{candidate2.px(), candidate2.py(), candidate2.pz()}; - pvec1rotation = array{-candidate2.px(), -candidate2.py(), candidate2.pz()}; auto arrMom = array{pvec0, pvec1}; - auto arrMomrotation = array{pvec0, pvec1rotation}; int track1Sign = candidate1.sign(); int track2Sign = candidate2.sign(); mass = RecoDecay::m(arrMom, array{massd1, massd2}); - massrotation = RecoDecay::m(arrMomrotation, array{massd1, massd2}); pT = RecoDecay::pt(array{candidate1.px() + candidate2.px(), candidate1.py() + candidate2.py()}); rapidity = RecoDecay::y(array{candidate1.px() + candidate2.px(), candidate1.py() + candidate2.py(), candidate1.pz() + candidate2.pz()}, mass); - if (isEtaAssym && unlike && track1Sign * track2Sign < 0) { - if (candidate1.eta() > 0.2 && candidate1.eta() < 0.8 && candidate2.eta() > 0.2 && candidate2.eta() < 0.8) { - histos.fill(HIST("h3PhiInvMassUnlikeSignAside"), multiplicity, pT, mass); - } else if (candidate1.eta() > -0.6 && candidate1.eta() < 0.0 && candidate2.eta() > -0.6 && candidate2.eta() < 0.0) { - histos.fill(HIST("h3PhiInvMassUnlikeSignCside"), multiplicity, pT, mass); - } - } - if (isEtaAssym && mix && track1Sign * track2Sign < 0) { - if (candidate1.eta() > 0.2 && candidate1.eta() < 0.8 && candidate2.eta() > 0.2 && candidate2.eta() < 0.8) { - histos.fill(HIST("h3PhiInvMassMixedAside"), multiplicity, pT, mass); - } else if (candidate1.eta() > -0.6 && candidate1.eta() < 0.0 && candidate2.eta() > -0.6 && candidate2.eta() < 0.0) { - histos.fill(HIST("h3PhiInvMassMixedCside"), multiplicity, pT, mass); - } - } - if (isEtaAssym && likesign && track1Sign * track2Sign > 0) { - if (candidate1.eta() > 0.2 && candidate1.eta() < 0.8 && candidate2.eta() > 0.2 && candidate2.eta() < 0.8) { - histos.fill(HIST("h3PhiInvMassLikeSignAside"), multiplicity, pT, mass); - } else if (candidate1.eta() > -0.6 && candidate1.eta() < 0.0 && candidate2.eta() > -0.6 && candidate2.eta() < 0.0) { - histos.fill(HIST("h3PhiInvMassLikeSignCside"), multiplicity, pT, mass); - } - } // default filling - if (std::abs(rapidity) < 0.5 && !isEtaAssym && track1Sign * track2Sign < 0) { + if (std::abs(rapidity) < 0.5 && track1Sign * track2Sign < 0) { if (unlike) { histos.fill(HIST("h3PhiInvMassUnlikeSign"), multiplicity, pT, mass); } if (mix) { histos.fill(HIST("h3PhiInvMassMixed"), multiplicity, pT, mass); } - if (rotation) { - histos.fill(HIST("h3PhiInvMassRotation"), multiplicity, pT, massrotation); - } - } - if (std::abs(rapidity) < 0.5 && !isEtaAssym && track1Sign * track2Sign > 0 && likesign) { - if (track1Sign > 0 && track2Sign > 0) { - histos.fill(HIST("h3PhiInvMassLikeSignPP"), multiplicity, pT, mass); - } else { - histos.fill(HIST("h3PhiInvMassLikeSignMM"), multiplicity, pT, mass); - } } } - Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPT); Filter DCAcutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); using EventCandidates = soa::Filtered>; - using TrackCandidates = soa::Filtered>; + using TrackCandidates = soa::Filtered>; // using EventCandidatesMC = soa::Join; using EventCandidatesMC = soa::Join; using TrackCandidatesMC = soa::Filtered>; + using CollisionMCTrueTable = aod::McCollisions; + using TrackMCTrueTable = aod::McParticles; + using CollisionMCRecTableCentFT0C = soa::SmallGroups>; + using TrackMCRecTable = soa::Join; + using FilTrackMCRecTable = soa::Filtered; ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for bin"}; ConfigurableAxis axisMultiplicityClass{"axisMultiplicityClass", {20, 0, 100}, "multiplicity percentile for bin"}; ConfigurableAxis axisMultiplicity{"axisMultiplicity", {2000, 0, 10000}, "TPC multiplicity for bin"}; - // using BinningType = BinningPolicy>; - // BinningType binningOnPositions{{axisVertex, axisMultiplicityClass}, true}; - - // using BinningTypeTPCMultiplicity = ColumnBinningPolicy; - using BinningTypeVertexContributor = ColumnBinningPolicy; - // using BinningTypeCentrality = ColumnBinningPolicy; + Preslice perCollision = aod::track::collisionId; - // using BinningType = ColumnBinningPolicy; - // BinningType binningOnPositions{{axisVertex, axisMultiplicity}, true}; + SliceCache cache; + using BinningTypeVertexContributor = ColumnBinningPolicy; + ROOT::Math::PxPyPzMVector PhiMesonMother, KaonPlus, KaonMinus; void processSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) { if (!collision.sel8()) { return; } - float multiplicity; + if (additionalEvSel2 && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + if (additionalEvSel3 && (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + return; + } + int occupancy = collision.trackOccupancyInTimeRange(); + if (fillOccupancy && (occupancy > cfgCutOccupancy)) { + return; + } + float multiplicity{-1}; if (cfgMultFT0) multiplicity = collision.centFT0C(); - if (!cfgMultFT0) - multiplicity = collision.numContrib(); histos.fill(HIST("hCentrality"), multiplicity); - histos.fill(HIST("hNcontributor"), collision.numContrib()); histos.fill(HIST("hVtxZ"), collision.posZ()); + histos.fill(HIST("hOccupancy"), occupancy); for (auto track1 : tracks) { if (!selectionTrack(track1)) { continue; } - histos.fill(HIST("hEta"), track1.eta()); - histos.fill(HIST("hDcaxy"), track1.dcaXY()); - histos.fill(HIST("hDcaz"), track1.dcaZ()); - histos.fill(HIST("hNsigmaKaonTPC"), track1.tpcNSigmaKa()); - histos.fill(HIST("hNsigmaKaonTOF"), track1.tofNSigmaKa()); + histos.fill(HIST("QAbefore/TPC_Nsigma_all"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAbefore/TOF_Nsigma_all"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAbefore/trkDCAxy"), track1.dcaXY()); + histos.fill(HIST("QAbefore/trkDCAz"), track1.dcaZ()); + histos.fill(HIST("QAbefore/TOF_TPC_Mapka_all"), track1.tofNSigmaKa(), track1.tpcNSigmaKa()); + auto track1ID = track1.globalIndex(); for (auto track2 : tracks) { if (!selectionTrack(track2)) { @@ -279,13 +357,21 @@ struct phianalysisrun3_PbPb { } bool unlike = true; bool mix = false; - bool likesign = true; - bool rotation = true; - if (isITSOnlycut) { - FillinvMass(track1, track2, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + if (!ispTdepPID && selectionPID(track1) && selectionPID(track2)) { + histos.fill(HIST("QAafter/TPC_Nsigma_all"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAafter/TOF_Nsigma_all"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAafter/trkDCAxy"), track1.dcaXY()); + histos.fill(HIST("QAafter/trkDCAz"), track1.dcaZ()); + histos.fill(HIST("QAafter/TOF_TPC_Mapka_all"), track1.tofNSigmaKa(), track1.tpcNSigmaKa()); + FillinvMass(track1, track2, multiplicity, unlike, mix, massKa, massKa); } - if (!isITSOnlycut && selectionPID(track1) && selectionPID(track2)) { - FillinvMass(track1, track2, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + if (ispTdepPID && selectionPIDpTdependent(track1) && selectionPIDpTdependent(track2)) { + histos.fill(HIST("QAafter/TPC_Nsigma_all"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAafter/TOF_Nsigma_all"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAafter/trkDCAxy"), track1.dcaXY()); + histos.fill(HIST("QAafter/trkDCAz"), track1.dcaZ()); + histos.fill(HIST("QAafter/TOF_TPC_Mapka_all"), track1.tofNSigmaKa(), track1.tpcNSigmaKa()); + FillinvMass(track1, track2, multiplicity, unlike, mix, massKa, massKa); } } } @@ -305,7 +391,26 @@ struct phianalysisrun3_PbPb { if (!c2.sel8()) { continue; } - + if (additionalEvSel2 && (!c1.selection_bit(aod::evsel::kNoSameBunchPileup) || !c1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + if (additionalEvSel2 && (!c2.selection_bit(aod::evsel::kNoSameBunchPileup) || !c2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + if (additionalEvSel3 && (!c1.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + continue; + } + if (additionalEvSel3 && (!c2.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + continue; + } + int occupancy1 = c1.trackOccupancyInTimeRange(); + int occupancy2 = c2.trackOccupancyInTimeRange(); + if (fillOccupancy && (occupancy1 > cfgCutOccupancy)) { + continue; + } + if (fillOccupancy && (occupancy2 > cfgCutOccupancy)) { + continue; + } float multiplicity; if (cfgMultFT0) multiplicity = c1.centFT0C(); @@ -315,8 +420,6 @@ struct phianalysisrun3_PbPb { for (auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { bool unlike = false; bool mix = true; - bool likesign = false; - bool rotation = false; if (!selectionTrack(t1)) { continue; } @@ -326,34 +429,286 @@ struct phianalysisrun3_PbPb { if (!selectionPair(t1, t2)) { continue; } - if (isITSOnlycut) { - FillinvMass(t1, t2, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + if (!ispTdepPID && selectionPID(t1) && selectionPID(t2)) { + FillinvMass(t1, t2, multiplicity, unlike, mix, massKa, massKa); } - if (!isITSOnlycut && selectionPID(t1) && selectionPID(t2)) { - FillinvMass(t1, t2, multiplicity, unlike, mix, likesign, rotation, massKa, massKa); + if (ispTdepPID && selectionPIDpTdependent(t1) && selectionPIDpTdependent(t2)) { + FillinvMass(t1, t2, multiplicity, unlike, mix, massKa, massKa); } } } } PROCESS_SWITCH(phianalysisrun3_PbPb, processMixedEvent, "Process Mixed event", false); + void processRotEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) + { + if (!collision.sel8()) { + return; + } + if (additionalEvSel2 && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + if (additionalEvSel3 && (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + return; + } + int occupancy = collision.trackOccupancyInTimeRange(); + if (fillOccupancy && (occupancy > cfgCutOccupancy)) { + return; + } + float multiplicity{-1}; + if (cfgMultFT0) + multiplicity = collision.centFT0C(); + histos.fill(HIST("hCentrality"), multiplicity); + histos.fill(HIST("hVtxZ"), collision.posZ()); + histos.fill(HIST("hOccupancy"), occupancy); + for (auto track1 : tracks) { + if (!selectionTrack(track1)) { + continue; + } + histos.fill(HIST("QAbefore/TPC_Nsigma_all"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAbefore/TOF_Nsigma_all"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAbefore/trkDCAxy"), track1.dcaXY()); + histos.fill(HIST("QAbefore/trkDCAz"), track1.dcaZ()); + histos.fill(HIST("QAbefore/TOF_TPC_Mapka_all"), track1.tofNSigmaKa(), track1.tpcNSigmaKa()); + + auto track1ID = track1.globalIndex(); + for (auto track2 : tracks) { + if (!selectionTrack(track2)) { + continue; + } + auto track2ID = track2.globalIndex(); + if (track2ID <= track1ID) { + continue; + } + if (!selectionPair(track1, track2)) { + continue; + } + if (!ispTdepPID && (!selectionPID(track1) || !selectionPID(track2))) { + continue; + } + if (ispTdepPID && (!selectionPIDpTdependent(track1) || !selectionPIDpTdependent(track2))) { + continue; + } + if (track1.sign() * track2.sign() < 0) { + KaonPlus = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + KaonMinus = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + } + PhiMesonMother = KaonPlus + KaonMinus; + if (TMath::Abs(PhiMesonMother.Rapidity()) > confRapidity) { + continue; + } + histos.fill(HIST("h3PhiInvMassSame"), multiplicity, PhiMesonMother.pt(), PhiMesonMother.M()); + if (fillRotation) { + for (int nrotbkg = 0; nrotbkg < nBkgRotations; nrotbkg++) { + auto anglestart = confMinRot; + auto angleend = confMaxRot; + auto anglestep = (angleend - anglestart) / (1.0 * (nBkgRotations - 1)); + auto rotangle = anglestart + nrotbkg * anglestep; + if (track1.sign() * track2.sign() < 0) { + auto rotkaonPx = track1.px() * std::cos(rotangle) - track1.py() * std::sin(rotangle); + auto rotkaonPy = track1.px() * std::sin(rotangle) + track1.py() * std::cos(rotangle); + KaonPlus = ROOT::Math::PxPyPzMVector(rotkaonPx, rotkaonPy, track1.pz(), massKa); + KaonMinus = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + } + PhiMesonMother = KaonPlus + KaonMinus; + if (TMath::Abs(PhiMesonMother.Rapidity()) > confRapidity) { + continue; + } + histos.fill(HIST("h3PhiInvMassRot"), multiplicity, PhiMesonMother.pt(), PhiMesonMother.M()); + } + } + } + } + } + + PROCESS_SWITCH(phianalysisrun3_PbPb, processRotEvent, "Process Rot event", false); + void processMC(CollisionMCTrueTable::iterator const& /*TrueCollision*/, CollisionMCRecTableCentFT0C const& RecCollisions, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + { + histos.fill(HIST("hMC"), 0); + if (RecCollisions.size() == 0) { + histos.fill(HIST("hMC"), 1); + return; + } + if (RecCollisions.size() > 1) { + histos.fill(HIST("hMC"), 2); + return; + } + for (auto& RecCollision : RecCollisions) { + histos.fill(HIST("hMC"), 3); + if (!RecCollision.sel8()) { + histos.fill(HIST("hMC"), 4); + continue; + } + if (timFrameEvsel && (!RecCollision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !RecCollision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + histos.fill(HIST("hMC"), 5); + continue; + } + if (additionalEvSel2 && (!RecCollision.selection_bit(aod::evsel::kNoSameBunchPileup) || !RecCollision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + int occupancy = RecCollision.trackOccupancyInTimeRange(); + if (fillOccupancy && (occupancy > cfgCutOccupancy)) { + continue; + } + if (TMath::Abs(RecCollision.posZ()) > cfgCutVertex) { + histos.fill(HIST("hMC"), 6); + continue; + } + histos.fill(HIST("hMC"), 7); + auto centrality = RecCollision.centFT0C(); + auto oldindex = -999; + auto Rectrackspart = RecTracks.sliceBy(perCollision, RecCollision.globalIndex()); + // loop over reconstructed particle + for (auto track1 : Rectrackspart) { + if (!selectionTrack(track1)) { + continue; + } + if (!ispTdepPID && !selectionPID(track1)) { + continue; + } + if (ispTdepPID && !selectionPIDpTdependent(track1)) { + continue; + } + if (!track1.has_mcParticle()) { + continue; + } + auto track1ID = track1.index(); + for (auto track2 : Rectrackspart) { + auto track2ID = track2.index(); + if (track2ID <= track1ID) { + continue; + } + if (!selectionTrack(track2)) { + continue; + } + if (!ispTdepPID && !selectionPID(track2)) { + continue; + } + if (ispTdepPID && !selectionPIDpTdependent(track2)) { + continue; + } + if (!track2.has_mcParticle()) { + continue; + } + if (!selectionPair(track1, track2)) { + continue; + } + if (track1.sign() * track2.sign() > 0) { + continue; + } + const auto mctrack1 = track1.mcParticle(); + const auto mctrack2 = track2.mcParticle(); + int track1PDG = TMath::Abs(mctrack1.pdgCode()); + int track2PDG = TMath::Abs(mctrack2.pdgCode()); + if (!mctrack1.isPhysicalPrimary()) { + continue; + } + if (!mctrack2.isPhysicalPrimary()) { + continue; + } + if (!(track1PDG == 321 && track2PDG == 321)) { + continue; + } + for (auto& mothertrack1 : mctrack1.mothers_as()) { + for (auto& mothertrack2 : mctrack2.mothers_as()) { + if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) { + continue; + } + if (mothertrack1 != mothertrack2) { + continue; + } + if (TMath::Abs(mothertrack1.y()) > confRapidity) { + continue; + } + if (PDGcheck && TMath::Abs(mothertrack1.pdgCode()) != 333) { + continue; + } + if (!ispTdepPID && (!selectionPID(track1) || !selectionPID(track2))) { + continue; + } + if (ispTdepPID && (!selectionPIDpTdependent(track1) || !selectionPIDpTdependent(track2))) { + continue; + } + if (avoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { + histos.fill(HIST("h1PhiRecsplit"), mothertrack1.pt()); + continue; + } + oldindex = mothertrack1.globalIndex(); + if (track1.sign() * track2.sign() < 0) { + KaonPlus = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + KaonMinus = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + } + PhiMesonMother = KaonPlus + KaonMinus; + + if (TMath::Abs(PhiMesonMother.Rapidity()) > confRapidity) { + continue; + } + histos.fill(HIST("h1PhiRec1"), PhiMesonMother.pt()); + histos.fill(HIST("h2PhiRec2"), PhiMesonMother.pt(), centrality); + histos.fill(HIST("h1Phimassrec"), PhiMesonMother.M()); + histos.fill(HIST("h3PhiRec3"), PhiMesonMother.pt(), centrality, PhiMesonMother.M()); + histos.fill(HIST("Centrec"), centrality); + } + } + } + } + // loop over generated particle + for (auto& mcParticle : GenParticles) { + if (TMath::Abs(mcParticle.y()) > confRapidity) { + continue; + } + if (PDGcheck && mcParticle.pdgCode() != 333) { + continue; + } + auto kDaughters = mcParticle.daughters_as(); + if (kDaughters.size() != 2) { + continue; + } + auto daughtp = false; + auto daughtm = false; + for (auto kCurrentDaughter : kDaughters) { + if (!kCurrentDaughter.isPhysicalPrimary()) { + continue; + } + if (kCurrentDaughter.pdgCode() == +321) { + if (genacceptancecut && kCurrentDaughter.pt() > cfgCutPT && TMath::Abs(kCurrentDaughter.eta()) < cfgCutEta) { + daughtp = true; + } + if (!genacceptancecut) { + daughtp = true; + } + KaonPlus = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massKa); + } else if (kCurrentDaughter.pdgCode() == -321) { + if (genacceptancecut && kCurrentDaughter.pt() > cfgCutPT && TMath::Abs(kCurrentDaughter.eta()) < cfgCutEta) { + daughtm = true; + } + if (!genacceptancecut) { + daughtm = true; + } + KaonMinus = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massKa); + } + } + if (daughtp && daughtm) { + PhiMesonMother = KaonPlus + KaonMinus; + histos.fill(HIST("h1PhiGen"), PhiMesonMother.pt()); + histos.fill(HIST("h2PhiGen2"), PhiMesonMother.pt(), centrality); + histos.fill(HIST("Centgen"), centrality); + histos.fill(HIST("h1Phimassgen"), PhiMesonMother.M()); + } + } + } // rec collision loop + + } // process MC + PROCESS_SWITCH(phianalysisrun3_PbPb, processMC, "Process Reconstructed", false); void processGen(aod::McCollision const& mcCollision, aod::McParticles& mcParticles, const soa::SmallGroups& collisions) { + histos.fill(HIST("hMC"), 0.5); if (std::abs(mcCollision.posZ()) < cfgCutVertex) { histos.fill(HIST("hMC"), 1.5); } - int Nchinel = 0; - for (auto& mcParticle : mcParticles) { - auto pdgcode = std::abs(mcParticle.pdgCode()); - if (mcParticle.isPhysicalPrimary() && (pdgcode == 211 || pdgcode == 321 || pdgcode == 2212 || pdgcode == 11 || pdgcode == 13)) { - if (std::abs(mcParticle.eta()) < 1.0) { - Nchinel = Nchinel + 1; - } - } - } - if (Nchinel > 0 && std::abs(mcCollision.posZ()) < cfgCutVertex) - histos.fill(HIST("hMC"), 2.5); + float imp = mcCollision.impactParameter(); + histos.fill(HIST("hImpactParameterGen"), imp); std::vector SelectedEvents(collisions.size()); int nevts = 0; auto multiplicity = 0; @@ -361,22 +716,36 @@ struct phianalysisrun3_PbPb { if (!collision.sel8() || std::abs(collision.mcCollision().posZ()) > cfgCutVertex) { continue; } + if (additionalEvSel2 && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + int occupancy = collision.trackOccupancyInTimeRange(); + if (fillOccupancy && (occupancy > cfgCutOccupancy)) { + continue; + } + histos.fill(HIST("hOccupancy1"), occupancy); multiplicity = collision.centFT0C(); histos.fill(HIST("Centgen"), multiplicity); + histos.fill(HIST("hImpactParameterGenCen"), imp, multiplicity); + SelectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); + histos.fill(HIST("hMC"), 2.5); } SelectedEvents.resize(nevts); - const auto evtReconstructedAndSelected = std::find(SelectedEvents.begin(), SelectedEvents.end(), mcCollision.globalIndex()) != SelectedEvents.end(); - if (!evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection + const auto evtReconstructedAndSelected = std::find(SelectedEvents.begin(), SelectedEvents.end(), mcCollision.globalIndex()) != SelectedEvents.end(); + histos.fill(HIST("EL1"), imp); + histos.fill(HIST("EL2"), multiplicity); + if (Reco && !evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection return; } - histos.fill(HIST("hMC"), 3.5); + histos.fill(HIST("ES1"), imp); + histos.fill(HIST("ES2"), multiplicity); for (auto& mcParticle : mcParticles) { - if (std::abs(mcParticle.y()) > 0.5) { + if (std::abs(mcParticle.y()) >= 0.5) { continue; } - if (mcParticle.pdgCode() != 333) { + if (PDGcheck && mcParticle.pdgCode() != 333) { continue; } auto kDaughters = mcParticle.daughters_as(); @@ -391,19 +760,24 @@ struct phianalysisrun3_PbPb { } if (kCurrentDaughter.pdgCode() == +321) { daughtp = true; + KaonPlus = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massKa); } else if (kCurrentDaughter.pdgCode() == -321) { daughtm = true; + KaonMinus = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massKa); } } if (daughtp && daughtm) { - histos.fill(HIST("h1PhiGen1"), mcParticle.pt()); - histos.fill(HIST("h2PhiGen1"), mcParticle.pt(), multiplicity); + PhiMesonMother = KaonPlus + KaonMinus; + histos.fill(HIST("h1PhiGen"), PhiMesonMother.pt()); + histos.fill(HIST("h2PhiGen2"), PhiMesonMother.pt(), multiplicity); + histos.fill(HIST("h2PhiGen1"), PhiMesonMother.pt(), imp); + histos.fill(HIST("h1Phimassgen"), PhiMesonMother.M()); + histos.fill(HIST("h3PhiGen3"), PhiMesonMother.pt(), multiplicity, PhiMesonMother.M()); } } } - PROCESS_SWITCH(phianalysisrun3_PbPb, processGen, "Process Generated", false); - void processRec(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const&, aod::McCollisions const&) + void processRec(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) { if (!collision.has_mcCollision()) { return; @@ -411,9 +785,21 @@ struct phianalysisrun3_PbPb { if (std::abs(collision.mcCollision().posZ()) > cfgCutVertex || !collision.sel8()) { return; } + if (additionalEvSel2 && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + int occupancy = collision.trackOccupancyInTimeRange(); + if (fillOccupancy && (occupancy > cfgCutOccupancy)) { + return; + } auto multiplicity = collision.centFT0C(); histos.fill(HIST("Centrec"), multiplicity); - histos.fill(HIST("hMC"), 4.5); + float imp = collision.mcCollision().impactParameter(); + histos.fill(HIST("hImpactParameterRec"), imp); + histos.fill(HIST("hImpactParameterRecCen"), imp, multiplicity); + histos.fill(HIST("ES3"), imp); + histos.fill(HIST("ES4"), multiplicity); + auto oldindex = -999; for (auto track1 : tracks) { if (!selectionTrack(track1)) { continue; @@ -421,7 +807,7 @@ struct phianalysisrun3_PbPb { if (!track1.has_mcParticle()) { continue; } - auto track1ID = track1.globalIndex(); + auto track1ID = track1.index(); for (auto track2 : tracks) { if (!track2.has_mcParticle()) { continue; @@ -429,7 +815,7 @@ struct phianalysisrun3_PbPb { if (!selectionTrack(track2)) { continue; } - auto track2ID = track2.globalIndex(); + auto track2ID = track2.index(); if (track2ID <= track1ID) { continue; } @@ -452,36 +838,56 @@ struct phianalysisrun3_PbPb { if (!(track1PDG == 321 && track2PDG == 321)) { continue; } + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + + phiMother = daughter1 + daughter2; + histos.fill(HIST("h1Phi1massrec"), phiMother.M()); + histos.fill(HIST("h3Phi1Rec3"), phiMother.pt(), multiplicity, phiMother.M()); for (auto& mothertrack1 : mctrack1.mothers_as()) { for (auto& mothertrack2 : mctrack2.mothers_as()) { if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) { continue; } - if (mothertrack1 != mothertrack2) { + if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) { continue; } - if (std::abs(mothertrack1.y()) > 0.5) { + if (!mothertrack1.producedByGenerator()) { continue; } - if (std::abs(mothertrack1.pdgCode()) != 333) { + if (std::abs(mothertrack1.y()) >= 0.5) { continue; } - if (!isITSOnlycut) { - if (!selectionPID(track1) || !selectionPID(track2)) { - continue; - } + if (PDGcheck && std::abs(mothertrack1.pdgCode()) != 333) { + continue; + } + if (!ispTdepPID && (!selectionPID(track1) || !selectionPID(track2))) { + continue; + } + if (ispTdepPID && (!selectionPIDpTdependent(track1) || !selectionPIDpTdependent(track2))) { + continue; } - pvec0 = array{track1.px(), track1.py(), track1.pz()}; - pvec1 = array{track2.px(), track2.py(), track2.pz()}; - auto arrMomrec = array{pvec0, pvec1}; - auto motherP = mothertrack1.p(); - auto motherE = mothertrack1.e(); - genMass = std::sqrt(motherE * motherE - motherP * motherP); + histos.fill(HIST("TPC_Nsigma_MC"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("TOF_Nsigma_MC"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + if (avoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { + histos.fill(HIST("h1PhiRecsplit"), mothertrack1.pt()); + continue; + } + oldindex = mothertrack1.globalIndex(); + if (track1.sign() * track2.sign() < 0) { + KaonPlus = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + KaonMinus = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + } + PhiMesonMother = KaonPlus + KaonMinus; - recMass = RecoDecay::m(arrMomrec, array{massKa, massKa}); - histos.fill(HIST("h1PhiRec1"), mothertrack1.pt()); - histos.fill(HIST("h2PhiRec1"), mothertrack1.pt(), multiplicity); + if (TMath::Abs(PhiMesonMother.Rapidity()) > confRapidity) { + continue; + } + histos.fill(HIST("h1PhiRec1"), PhiMesonMother.pt()); + histos.fill(HIST("h2PhiRec2"), PhiMesonMother.pt(), multiplicity); + histos.fill(HIST("h1Phimassrec"), PhiMesonMother.M()); + histos.fill(HIST("h3PhiRec3"), PhiMesonMother.pt(), multiplicity, PhiMesonMother.M()); } } } @@ -489,6 +895,181 @@ struct phianalysisrun3_PbPb { } PROCESS_SWITCH(phianalysisrun3_PbPb, processRec, "Process Reconstructed", false); + void processSameEventMC(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) + { + if (!collision.sel8()) { + return; + } + if (additionalEvSel2 && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + if (additionalEvSel3 && (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + return; + } + int occupancy = collision.trackOccupancyInTimeRange(); + if (fillOccupancy && (occupancy > cfgCutOccupancy)) { + return; + } + float multiplicity{-1}; + multiplicity = collision.centFT0C(); + for (auto track1 : tracks) { + if (!selectionTrack(track1)) { + continue; + } + auto track1ID = track1.globalIndex(); + for (auto track2 : tracks) { + if (!selectionTrack(track2)) { + continue; + } + auto track2ID = track2.globalIndex(); + if (track2ID <= track1ID) { + continue; + } + if (!selectionPair(track1, track2)) { + continue; + } + if (!ispTdepPID && (!selectionPID(track1) || !selectionPID(track2))) { + continue; + } + if (ispTdepPID && (!selectionPIDpTdependent(track1) || !selectionPIDpTdependent(track2))) { + continue; + } + if (track1.sign() * track2.sign() < 0) { + KaonPlus = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + KaonMinus = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + } + PhiMesonMother = KaonPlus + KaonMinus; + if (TMath::Abs(PhiMesonMother.Rapidity()) > confRapidity) { + continue; + } + histos.fill(HIST("h3PhiInvMassSameMC"), multiplicity, PhiMesonMother.pt(), PhiMesonMother.M()); + histos.fill(HIST("h1Phimasssame"), PhiMesonMother.M()); + if (fillRotation) { + for (int nrotbkg = 0; nrotbkg < nBkgRotations; nrotbkg++) { + auto anglestart = confMinRot; + auto angleend = confMaxRot; + auto anglestep = (angleend - anglestart) / (1.0 * (nBkgRotations - 1)); + auto rotangle = anglestart + nrotbkg * anglestep; + if (track1.sign() * track2.sign() < 0) { + auto rotkaonPx = track1.px() * std::cos(rotangle) - track1.py() * std::sin(rotangle); + auto rotkaonPy = track1.px() * std::sin(rotangle) + track1.py() * std::cos(rotangle); + KaonPlus = ROOT::Math::PxPyPzMVector(rotkaonPx, rotkaonPy, track1.pz(), massKa); + KaonMinus = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + } + PhiMesonMother = KaonPlus + KaonMinus; + if (TMath::Abs(PhiMesonMother.Rapidity()) > confRapidity) { + continue; + } + histos.fill(HIST("h3PhiInvMassRotMC"), multiplicity, PhiMesonMother.pt(), PhiMesonMother.M()); + histos.fill(HIST("h1Phimassrot"), PhiMesonMother.M()); + } + } + } + } + } + + PROCESS_SWITCH(phianalysisrun3_PbPb, processSameEventMC, "Process Same event", false); + void processMixedEventMC(EventCandidatesMC const& recCollisions, TrackCandidatesMC const& RecTracks, aod::McParticles const&) + { + + auto tracksTuple = std::make_tuple(RecTracks); + BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicity}, true}; + SameKindPair pairs{binningOnPositions, cfgNoMixedEvents, -1, recCollisions, tracksTuple, &cache}; + + for (auto& [c1, tracks1, c2, tracks2] : pairs) { + if (!c1.sel8()) { + continue; + } + if (!c2.sel8()) { + continue; + } + if (additionalEvSel2 && (!c1.selection_bit(aod::evsel::kNoSameBunchPileup) || !c1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + if (additionalEvSel2 && (!c2.selection_bit(aod::evsel::kNoSameBunchPileup) || !c2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + if (additionalEvSel3 && (!c1.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + continue; + } + if (additionalEvSel3 && (!c2.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + continue; + } + int occupancy1 = c1.trackOccupancyInTimeRange(); + int occupancy2 = c2.trackOccupancyInTimeRange(); + if (fillOccupancy && (occupancy1 > cfgCutOccupancy)) { + continue; + } + if (fillOccupancy && (occupancy2 > cfgCutOccupancy)) { + continue; + } + auto multiplicity = c1.centFT0C(); + for (auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + histos.fill(HIST("hMC"), 6.5); + if (!selectionTrack(t1)) { + continue; + } + if (!selectionTrack(t2)) { + continue; + } + if (!selectionPair(t1, t2)) { + continue; + } + if (!ispTdepPID && (!selectionPID(t1) || !selectionPID(t2))) { + continue; + } + if (ispTdepPID && (!selectionPIDpTdependent(t1) || !selectionPIDpTdependent(t2))) { + continue; + } + if (t1.sign() * t2.sign() < 0) { + KaonPlus = ROOT::Math::PxPyPzMVector(t1.px(), t1.py(), t1.pz(), massKa); + KaonMinus = ROOT::Math::PxPyPzMVector(t2.px(), t2.py(), t2.pz(), massKa); + } + PhiMesonMother = KaonPlus + KaonMinus; + if (TMath::Abs(PhiMesonMother.Rapidity()) > confRapidity) { + continue; + } + histos.fill(HIST("h3PhiInvMassMixedMC"), multiplicity, PhiMesonMother.pt(), PhiMesonMother.M()); + histos.fill(HIST("h1Phimassmix"), PhiMesonMother.M()); + } + } + } + PROCESS_SWITCH(phianalysisrun3_PbPb, processMixedEventMC, "Process Mixed event MC", true); + void processEvtLossSigLossMC(aod::McCollisions::iterator const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& recCollisions) + { + + // Event loss estimation + auto impactPar = mcCollision.impactParameter(); + histos.fill(HIST("QAevent/hImpactParameterGen"), impactPar); + + bool isSel = false; + auto centrality = -999.; + for (const auto& RecCollision : recCollisions) { + if (!myEventSelections(RecCollision)) + continue; + centrality = RecCollision.centFT0C(); + isSel = true; + } + + if (isSel) { + histos.fill(HIST("QAevent/hImpactParameterRec"), impactPar); + histos.fill(HIST("QAevent/hImpactParvsCentrRec"), centrality, impactPar); + } + + // Generated MC + for (const auto& mcPart : mcParticles) { + if (std::abs(mcPart.y()) >= 0.5 || std::abs(mcPart.pdgCode()) != 333) + continue; + + // signal loss estimation + histos.fill(HIST("QAevent/phigenBeforeEvtSel"), mcPart.pt(), impactPar); + if (isSel) { + // signal loss estimation + histos.fill(HIST("QAevent/phigenAfterEvtSel"), mcPart.pt(), impactPar); + } + } // end loop on gen particles + } + PROCESS_SWITCH(phianalysisrun3_PbPb, processEvtLossSigLossMC, "Process Signal Loss, Event Loss", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGLF/Tasks/Resonances/phipbpb.cxx b/PWGLF/Tasks/Resonances/phipbpb.cxx index 11728cd9ef0..c842017274d 100644 --- a/PWGLF/Tasks/Resonances/phipbpb.cxx +++ b/PWGLF/Tasks/Resonances/phipbpb.cxx @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include "TRandom3.h" #include "Math/Vector3D.h" @@ -52,6 +54,9 @@ #include "DataFormatsParameters/GRPObject.h" #include "DataFormatsParameters/GRPMagField.h" #include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table using namespace o2; using namespace o2::framework; @@ -62,35 +67,54 @@ struct phipbpb { int mRunNumber; int multEstimator; float d_bz; + + struct : ConfigurableGroup { + Configurable cfgURL{"cfgURL", "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; + Configurable nolaterthan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "Latest acceptable timestamp of creation for the object"}; + } cfgCcdbParam; + + // Enable access to the CCDB for the offset and correction constants and save them in dedicated variables. Service ccdb; + o2::ccdb::CcdbApi ccdbApi; Service pdg; // CCDB options - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + // Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + // Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + // Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + // Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + // Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + // filling + Configurable fillSA{"fillSA", false, "fill spin alignment"}; // events Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; Configurable cfgCutCentrality{"cfgCutCentrality", 80.0f, "Accepted maximum Centrality"}; + Configurable cfgCutOccupancy{"cfgCutOccupancy", 3000, "Occupancy cut"}; // track - Configurable fillRapidity{"fillRapidity", false, "fill rapidity bin"}; + Configurable useSP{"useSP", false, "use SP"}; + Configurable useDcaSyst{"useDcaSyst", false, "useDcaSyst"}; + Configurable additionalEvsel{"additionalEvsel", false, "Additional event selcection"}; + Configurable additionalEvselITS{"additionalEvselITS", true, "Additional event selcection for ITS"}; + Configurable removefaketrak{"removefaketrack", true, "Remove fake track from momentum difference"}; + Configurable ConfFakeKaonCut{"ConfFakeKaonCut", 0.1, "Cut based on track from momentum difference"}; Configurable useGlobalTrack{"useGlobalTrack", true, "use Global track"}; + Configurable cfgCutTOFBeta{"cfgCutTOFBeta", 0.0, "cut TOF beta"}; Configurable cfgCutCharge{"cfgCutCharge", 0.0, "cut on Charge"}; Configurable cfgCutPT{"cfgCutPT", 0.2, "PT cut on daughter track"}; Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; Configurable cfgCutDCAxy{"cfgCutDCAxy", 2.0f, "DCAxy range for tracks"}; Configurable cfgCutDCAz{"cfgCutDCAz", 2.0f, "DCAz range for tracks"}; Configurable nsigmaCutTPC{"nsigmacutTPC", 3.0, "Value of the TPC Nsigma cut"}; - Configurable nsigmaCutCombined{"nsigmaCutCombined", 3.0, "Value of the TOF Nsigma cut"}; + Configurable nsigmaCutTOF{"nsigmaCutTOF", 3.0, "Value of the TOF Nsigma cut"}; Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 1, "Number of mixed events per event"}; Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; Configurable cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; - Configurable isNoTOF{"isNoTOF", false, "isNoTOF"}; + Configurable cfgTPCSharedcluster{"cfgTPCSharedcluster", 0.4, "Maximum Number of TPC shared cluster"}; Configurable isDeepAngle{"isDeepAngle", false, "Deep Angle cut"}; Configurable ispTdepPID{"ispTdepPID", true, "pT dependent PID"}; + Configurable isTOFOnly{"isTOFOnly", false, "use TOF only PID"}; + Configurable checkAllCharge{"checkAllCharge", true, "check all charge for MC weight"}; Configurable cfgDeepAngle{"cfgDeepAngle", 0.04, "Deep Angle cut value"}; Configurable confRapidity{"confRapidity", 0.5, "Rapidity cut"}; ConfigurableAxis configThnAxisInvMass{"configThnAxisInvMass", {120, 0.98, 1.1}, "#it{M} (GeV/#it{c}^{2})"}; @@ -98,17 +122,18 @@ struct phipbpb { ConfigurableAxis configThnAxisCosThetaStar{"configThnAxisCosThetaStar", {10, -1.0, 1.}, "cos(#vartheta)"}; ConfigurableAxis configThnAxisCentrality{"configThnAxisCentrality", {8, 0., 80}, "Centrality"}; ConfigurableAxis configThnAxisPhiminusPsi{"configThnAxisPhiminusPsi", {6, 0.0, TMath::Pi()}, "#phi - #psi"}; - ConfigurableAxis configThnAxisV2{"configThnAxisV2", {200, -1, 1}, "V2"}; - ConfigurableAxis configThnAxisSP{"configThnAxisSP", {400, -4, 4}, "SP"}; + ConfigurableAxis configThnAxisV2{"configThnAxisV2", {200, -6, 6}, "V2"}; ConfigurableAxis configThnAxisRapidity{"configThnAxisRapidity", {8, 0, 0.8}, "Rapidity"}; ConfigurableAxis configThnAxisSA{"configThnAxisSA", {200, -1, 1}, "SA"}; ConfigurableAxis configThnAxiscosthetaSA{"configThnAxiscosthetaSA", {200, 0, 1}, "costhetaSA"}; - Configurable additionalEvsel{"additionalEvsel", false, "Additional event selcection"}; - Configurable timFrameEvsel{"timFrameEvsel", false, "TPC Time frame boundary cut"}; + ConfigurableAxis axisPtKaonWeight{"axisPtKaonWeight", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f}, "pt axis"}; Configurable isMC{"isMC", false, "use MC"}; Configurable genacceptancecut{"genacceptancecut", true, "use acceptance cut for generated"}; Configurable avoidsplitrackMC{"avoidsplitrackMC", false, "avoid split track in MC"}; Configurable islike{"islike", false, "use like"}; + Configurable useWeight{"useWeight", true, "use EP dep effi weight"}; + Configurable ConfWeightPath{"ConfWeightPath", "Users/s/skundu/My/Object/mcweight", "Path to gain calibration"}; + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; Filter centralityFilter = nabs(aod::cent::centFT0C) < cfgCutCentrality; Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPT); @@ -116,14 +141,14 @@ struct phipbpb { Filter PIDcutFilter = nabs(aod::pidtpc::tpcNSigmaKa) < nsigmaCutTPC; using EventCandidates = soa::Filtered>; - using TrackCandidates = soa::Filtered>; + using TrackCandidates = soa::Filtered>; using CollisionMCTrueTable = aod::McCollisions; using TrackMCTrueTable = aod::McParticles; + using CollisionMCRecTableCentFT0C = soa::SmallGroups>; - using TrackMCRecTable = soa::Join; + using TrackMCRecTable = soa::Join; using FilTrackMCRecTable = soa::Filtered; - Preslice perCollision = aod::track::collisionId; SliceCache cache; @@ -141,21 +166,26 @@ struct phipbpb { void init(o2::framework::InitContext&) { + // std::vector occupancyBinning = {0.0, 500.0, 1000.0, 3000.0, 6000.0, 50000.0}; + std::vector occupancyBinning = {-0.5, 500.0, 1000.0, 1500.0, 2000.0, 3000.0, 4000.0, 5000.0, 50000.0}; const AxisSpec thnAxisInvMass{configThnAxisInvMass, "#it{M} (GeV/#it{c}^{2})"}; const AxisSpec thnAxisPt{configThnAxisPt, "#it{p}_{T} (GeV/#it{c})"}; - const AxisSpec thnAxisCosThetaStarOP{configThnAxisCosThetaStar, "cos(#vartheta_{OP})"}; - const AxisSpec thnAxisCosThetaStarIP{configThnAxisCosThetaStar, "cos(#vartheta_{IP})"}; - const AxisSpec thnAxisPhiminusPsi{configThnAxisPhiminusPsi, "#phi - #psi"}; + const AxisSpec thnAxisCosThetaStar{configThnAxisCosThetaStar, "cos(#vartheta_{OP})"}; const AxisSpec thnAxisCentrality{configThnAxisCentrality, "Centrality (%)"}; const AxisSpec thnAxisV2{configThnAxisV2, "V2"}; - const AxisSpec thnAxisSP{configThnAxisSP, "SP"}; const AxisSpec thnAxisRapidity{configThnAxisRapidity, "Rapidity"}; const AxisSpec thnAxisSA{configThnAxisSA, "SA"}; - const AxisSpec thnAxiscosthetaSA{configThnAxiscosthetaSA, "costhetaSA"}; + AxisSpec cumulantAxis = {200, -1, 1, "phi"}; + AxisSpec itsAxis = {8, -0.5, 7.5, "its"}; + AxisSpec tpcAxis = {130, 69.5, 199.5, "its"}; + AxisSpec squareAxis = {200, 0, 1, "aossquare"}; AxisSpec phiAxis = {500, -6.28, 6.28, "phi"}; - AxisSpec resAxis = {1000, -5, 5, "Res"}; + AxisSpec resAxis = {6000, -30, 30, "Res"}; + AxisSpec resAxisSquare = {800, -1, 1, "Res"}; AxisSpec centAxis = {8, 0, 80, "V0M (%)"}; + AxisSpec occupancyAxis = {occupancyBinning, "Occupancy"}; + histos.add("hTPCglobalmomcorr", "Momentum correlation", kTH3F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}, {8, 0.0f, 80.0f}}); histos.add("hpTvsRapidity", "pT vs Rapidity", kTH2F, {{100, 0.0f, 10.0f}, {300, -1.5f, 1.5f}}); histos.add("hFTOCvsTPCNoCut", "Mult correlation FT0C vs. TPC without any cut", kTH2F, {{80, 0.0f, 80.0f}, {100, -0.5f, 5999.5f}}); histos.add("hFTOCvsTPC", "Mult correlation FT0C vs. TPC", kTH2F, {{80, 0.0f, 80.0f}, {100, -0.5f, 5999.5f}}); @@ -165,97 +195,121 @@ struct phipbpb { histos.add("hEta", "Eta distribution", kTH1F, {{200, -1.0f, 1.0f}}); histos.add("hDcaxy", "Dcaxy distribution", kTH1F, {{200, -1.0f, 1.0f}}); histos.add("hDcaz", "Dcaz distribution", kTH1F, {{200, -1.0f, 1.0f}}); + + histos.add("hITS", "ITS cluster", kTH2F, {{10, -0.5f, 9.5f}, {200, -1.0, 1.0}}); + histos.add("hTPC", "TPC crossed rows", kTH2F, {{90, 69.5f, 159.5f}, {200, -1.0, 1.0}}); + histos.add("hTPCScls", "TPC Shared cluster", kTH2F, {{16, -0.5f, 159.5f}, {200, -1.0, 1.0}}); + histos.add("hTPCSclsFrac", "Fraction of TPC Shared cluster", kTH2F, {{100, -0.0f, 2.0f}, {200, -1.0, 1.0}}); + histos.add("hNsigmaKaonTPC", "NsigmaKaon TPC distribution", kTH1F, {{200, -10.0f, 10.0f}}); histos.add("hNsigmaKaonTOF", "NsigmaKaon TOF distribution", kTH1F, {{200, -10.0f, 10.0f}}); - histos.add("hPsiFT0C", "PsiFT0C", kTH2F, {centAxis, phiAxis}); - histos.add("hPsiFT0A", "PsiFT0A", kTH2F, {centAxis, phiAxis}); - histos.add("hPsiTPC", "PsiTPC", kTH2F, {centAxis, phiAxis}); - histos.add("hPsiTPCR", "PsiTPCR", kTH2F, {centAxis, phiAxis}); - histos.add("hPsiTPCL", "PsiTPCL", kTH2F, {centAxis, phiAxis}); - if (!fillRapidity) { - histos.add("hSparseV2SASameEvent_costhetastarOP", "hSparseV2SASameEvent_costhetastarOP", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_costhetastarIP", "hSparseV2SASameEvent_costhetastarIP", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_SA", "hSparseV2SASameEvent_SA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_costheta_SA", "hSparseV2SASameEvent_costheta_SA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxiscosthetaSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_SA_A0", "hSparseV2SASameEvent_SA_A0", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_V2", "hSparseV2SASameEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEvent_costhetastarOP", "hSparseV2SAMixedEvent_costhetastarOP", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEvent_costhetastarIP", "hSparseV2SAMixedEvent_costhetastarIP", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEvent_SA", "hSparseV2SAMixedEvent_SA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEvent_costheta_SA", "hSparseV2SAMixedEvent_costheta_SA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxiscosthetaSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEvent_SA_A0", "hSparseV2SAMixedEvent_SA_A0", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEvent_V2", "hSparseV2SAMixedEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_SP", "hSparseV2SASameEvent_SP", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSP, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEvent_SP", "hSparseV2SAMixedEvent_SP", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSP, thnAxisCentrality}); - } - if (fillRapidity) { - histos.add("hSparseV2SASameEvent_costhetastarOP", "hSparseV2SASameEvent_costhetastarOP", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_costhetastarIP", "hSparseV2SASameEvent_costhetastarIP", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_SA", "hSparseV2SASameEvent_SA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_costheta_SA", "hSparseV2SASameEvent_costheta_SA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxiscosthetaSA, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_SA_A0", "hSparseV2SASameEvent_SA_A0", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_V2", "hSparseV2SASameEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEvent_costhetastarOP", "hSparseV2SAMixedEvent_costhetastarOP", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEvent_costhetastarIP", "hSparseV2SAMixedEvent_costhetastarIP", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEvent_SA", "hSparseV2SAMixedEvent_SA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEvent_costheta_SA", "hSparseV2SAMixedEvent_costheta_SA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxiscosthetaSA, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEvent_SA_A0", "hSparseV2SAMixedEvent_SA_A0", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEvent_V2", "hSparseV2SAMixedEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); + histos.add("hPsiFT0C", "PsiFT0C", kTH3F, {centAxis, occupancyAxis, phiAxis}); + histos.add("hPsiFT0A", "PsiFT0A", kTH3F, {centAxis, occupancyAxis, phiAxis}); + histos.add("hPsiTPC", "PsiTPC", kTH3F, {centAxis, occupancyAxis, phiAxis}); + histos.add("hPsiTPCR", "PsiTPCR", kTH3F, {centAxis, occupancyAxis, phiAxis}); + histos.add("hPsiTPCL", "PsiTPCL", kTH3F, {centAxis, occupancyAxis, phiAxis}); + + histos.add("hSparseV2SameEventCosPhi", "hSparseV2SameEventCosPhi", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, cumulantAxis, thnAxisCentrality}); + histos.add("hSparseV2SameEventSinPhi", "hSparseV2SameEventSinPhi", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, cumulantAxis, thnAxisCentrality}); + histos.add("hSparseV2SameEventCosPsi", "hSparseV2SameEventCosPsi", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, cumulantAxis, thnAxisCentrality}); + histos.add("hSparseV2SameEventSinPsi", "hSparseV2SameEventSinPsi", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, cumulantAxis, thnAxisCentrality}); + + histos.add("hSparseV2SameEventCosDeltaPhi", "hSparseV2SameEventCosDeltaPhi", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); + histos.add("hSparseV2MixedEventCosDeltaPhi", "hSparseV2MixedEventCosDeltaPhi", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); + + histos.add("hSparseV2SameEventCos2DeltaPhi", "hSparseV2SameEventCos2DeltaPhi", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); + histos.add("hSparseV2MixedEventCos2DeltaPhi", "hSparseV2MixedEventCos2DeltaPhi", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); + + histos.add("hSparseV2SameEventCosDeltaPhiSquare", "hSparseV2SameEventCosDeltaPhiSquare", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, squareAxis, thnAxisCentrality}); + histos.add("hSparseV2SameEventCosDeltaPhiCube", "hSparseV2SameEventCosDeltaPhiCube", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); + histos.add("hSparseV2MixedEventCosDeltaPhiSquare", "hSparseV2MixedEventCosDeltaPhiSquare", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, squareAxis, thnAxisCentrality}); + + histos.add("hSparseV2SameEventSinDeltaPhi", "hSparseV2SameEventSinDeltaPhi", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); + histos.add("hSparseV2MixedEventSinDeltaPhi", "hSparseV2MixedEventSinDeltaPhi", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); + + if (fillSA) { + histos.add("hSparseV2SameEventSA", "hSparseV2SameEventSA", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisRapidity, thnAxisCentrality}); + histos.add("hSparseV2MixedEventSA", "hSparseV2MixedEventSA", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisRapidity, thnAxisCentrality}); + histos.add("hSparseV2SameEventCosThetaStar", "hSparseV2SameEventCosThetaStar", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStar, thnAxisRapidity, thnAxisCentrality}); + histos.add("hSparseV2MixedEventCosThetaStar", "hSparseV2MixedEventCosThetaStar", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStar, thnAxisRapidity, thnAxisCentrality}); } // histogram for resolution - histos.add("ResFT0CTPC", "ResFT0CTPC", kTH2F, {centAxis, resAxis}); - histos.add("ResFT0CTPCR", "ResFT0CTPCR", kTH2F, {centAxis, resAxis}); - histos.add("ResFT0CTPCL", "ResFT0CTPCL", kTH2F, {centAxis, resAxis}); - histos.add("ResTPCRTPCL", "ResTPCRTPCL", kTH2F, {centAxis, resAxis}); - histos.add("ResFT0CFT0A", "ResFT0CFT0A", kTH2F, {centAxis, resAxis}); - histos.add("ResFT0ATPC", "ResFT0ATPC", kTH2F, {centAxis, resAxis}); - - histos.add("ResSPFT0CTPC", "ResSPFT0CTPC", kTH2F, {centAxis, resAxis}); - histos.add("ResSPFT0CTPCR", "ResSPFT0CTPCR", kTH2F, {centAxis, resAxis}); - histos.add("ResSPFT0CTPCL", "ResSPFT0CTPCL", kTH2F, {centAxis, resAxis}); - histos.add("ResSPTPCRTPCL", "ResSPTPCRTPCL", kTH2F, {centAxis, resAxis}); - histos.add("ResSPFT0CFT0A", "ResSPFT0CFT0A", kTH2F, {centAxis, resAxis}); - histos.add("ResSPFT0ATPC", "ResSPFT0ATPC", kTH2F, {centAxis, resAxis}); + histos.add("ResFT0CTPC", "ResFT0CTPC", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("ResFT0CTPCR", "ResFT0CTPCR", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("ResFT0CTPCL", "ResFT0CTPCL", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("ResTPCRTPCL", "ResTPCRTPCL", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("ResFT0CFT0A", "ResFT0CFT0A", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("ResFT0ATPC", "ResFT0ATPC", kTH3F, {centAxis, occupancyAxis, resAxis}); + + histos.add("Res4FT0CTPC", "Res4FT0CTPC", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("Res4FT0CTPCR", "Res4FT0CTPCR", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("Res4FT0CTPCL", "Res4FT0CTPCL", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("Res4TPCRTPCL", "Res4TPCRTPCL", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("Res4FT0CFT0A", "Res4FT0CFT0A", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("Res4FT0ATPC", "Res4FT0ATPC", kTH3F, {centAxis, occupancyAxis, resAxis}); + + histos.add("ResFT0CTPCSquare", "ResFT0CTPCSquare", kTH3F, {centAxis, occupancyAxis, resAxisSquare}); + histos.add("ResFT0CTPCRSquare", "ResFT0CTPCRSquare", kTH3F, {centAxis, occupancyAxis, resAxisSquare}); + histos.add("ResFT0CTPCLSquare", "ResFT0CTPCLSquare", kTH3F, {centAxis, occupancyAxis, resAxisSquare}); + histos.add("ResTPCRTPCLSquare", "ResTPCRTPCLSquare", kTH3F, {centAxis, occupancyAxis, resAxisSquare}); + histos.add("ResFT0CFT0ASquare", "ResFT0CFT0ASquare", kTH3F, {centAxis, occupancyAxis, resAxisSquare}); + histos.add("ResFT0ATPCSquare", "ResFT0ATPCSquare", kTH3F, {centAxis, occupancyAxis, resAxisSquare}); + + histos.add("ResSPFT0CTPC", "ResSPFT0CTPC", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("ResSPFT0CTPCR", "ResSPFT0CTPCR", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("ResSPFT0CTPCL", "ResSPFT0CTPCL", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("ResSPTPCRTPCL", "ResSPTPCRTPCL", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("ResSPFT0CFT0A", "ResSPFT0CFT0A", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("ResSPFT0ATPC", "ResSPFT0ATPC", kTH3F, {centAxis, occupancyAxis, resAxis}); + + histos.add("Res4SPFT0CTPC", "Res4SPFT0CTPC", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("Res4SPFT0CTPCR", "Res4SPFT0CTPCR", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("Res4SPFT0CTPCL", "Res4SPFT0CTPCL", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("Res4SPTPCRTPCL", "Res4SPTPCRTPCL", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("Res4SPFT0CFT0A", "Res4SPFT0CFT0A", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("Res4SPFT0ATPC", "Res4SPFT0ATPC", kTH3F, {centAxis, occupancyAxis, resAxis}); + + histos.add("ResTrackSPFT0CTPC", "ResTrackSPFT0CTPC", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("ResTrackSPFT0CTPCR", "ResTrackSPFT0CTPCR", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("ResTrackSPFT0CTPCL", "ResTrackSPFT0CTPCL", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("ResTrackSPTPCRTPCL", "ResTrackSPTPCRTPCL", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("ResTrackSPFT0CFT0A", "ResTrackSPFT0CFT0A", kTH3F, {centAxis, occupancyAxis, resAxis}); + histos.add("ResTrackSPFT0ATPC", "ResTrackSPFT0ATPC", kTH3F, {centAxis, occupancyAxis, resAxis}); // MC histogram if (isMC) { histos.add("hMC", "MC Event statistics", kTH1F, {{10, 0.0f, 10.0f}}); histos.add("h1PhiRecsplit", "Phi meson Rec split", kTH1F, {{100, 0.0f, 10.0f}}); histos.add("CentPercentileMCRecHist", "MC Centrality", kTH1F, {{100, 0.0f, 100.0f}}); - if (!fillRapidity) { - histos.add("hSparseV2SASameEvent_costhetastarOP_beam_MCGen", "hSparseV2SASameEvent_costhetastar_beamOP_MCGen", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_costhetastarOP_MCGen", "hSparseV2SASameEvent_costhetastarOP_MCGen", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_costhetastarIP_MCGen", "hSparseV2SASameEvent_costhetastarIP_MCGen", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_SA_MCGen", "hSparseV2SASameEvent_SA_MCGen", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_costheta_SA_MCGen", "hSparseV2SASameEvent_costheta_SA_MCGen", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxiscosthetaSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_SA_A0_MCGen", "hSparseV2SASameEvent_SA_A0_MCGen", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_V2_MCGen", "hSparseV2SASameEvent_V2_MCGen", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); - - histos.add("hSparseV2SASameEvent_costhetastarOP_beam_MCRec", "hSparseV2SASameEvent_costhetastar_beamOP_MCRec", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_costhetastarOP_MCRec", "hSparseV2SASameEvent_costhetastarOP_MCRec", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_costhetastarIP_MCRec", "hSparseV2SASameEvent_costhetastarIP_MCRec", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_SA_MCRec", "hSparseV2SASameEvent_SA_MCRec", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_costheta_SA_MCRec", "hSparseV2SASameEvent_costheta_SA_MCRec", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxiscosthetaSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_SA_A0_MCRec", "hSparseV2SASameEvent_SA_A0_MCRec", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_V2_MCRec", "hSparseV2SASameEvent_V2_MCRec", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); - } - if (fillRapidity) { - histos.add("hSparseV2SASameEvent_costhetastarOP_beam_MCGen", "hSparseV2SASameEvent_costhetastar_beamOP_MCGen", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_costhetastarOP_MCGen", "hSparseV2SASameEvent_costhetastarOP_MCGen", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_costhetastarIP_MCGen", "hSparseV2SASameEvent_costhetastarIP_MCGen", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_SA_MCGen", "hSparseV2SASameEvent_SA_MCGen", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_costheta_SA_MCGen", "hSparseV2SASameEvent_costheta_SA_MCGen", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxiscosthetaSA, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_SA_A0_MCGen", "hSparseV2SASameEvent_SA_A0_MCGen", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_V2_MCGen", "hSparseV2SASameEvent_V2_MCGen", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); - - histos.add("hSparseV2SASameEvent_costhetastarOP_beam_MCRec", "hSparseV2SASameEvent_costhetastar_beamOP_MCRec", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_costhetastarOP_MCRec", "hSparseV2SASameEvent_costhetastarOP_MCRec", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_costhetastarIP_MCRec", "hSparseV2SASameEvent_costhetastarIP_MCRec", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStarOP, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_SA_MCRec", "hSparseV2SASameEvent_SA_MCRec", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_costheta_SA_MCRec", "hSparseV2SASameEvent_costheta_SA_MCRec", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxiscosthetaSA, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_SA_A0_MCRec", "hSparseV2SASameEvent_SA_A0_MCRec", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisRapidity, thnAxisCentrality}); - histos.add("hSparseV2SASameEvent_V2_MCRec", "hSparseV2SASameEvent_V2_MCRec", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); - } + + histos.add("hSparseV2MCGenSA", "hSparseV2SameEventSA", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisRapidity, thnAxisCentrality}); + histos.add("hSparseV2MCGenCosThetaStar_effy", "hSparseV2SameEventCosThetaStar_effy", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStar, thnAxisRapidity, thnAxisCentrality}); + + histos.add("hSparseV2MCRecSA", "hSparseV2SameEventSA", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, thnAxisSA, thnAxisRapidity, thnAxisCentrality}); + histos.add("hSparseV2MCRecCosThetaStar_effy", "hSparseV2SameEventCosThetaStar_effy", HistType::kTHnSparseD, {thnAxisInvMass, thnAxisPt, thnAxisCosThetaStar, thnAxisRapidity, thnAxisCentrality}); + + // weight + + histos.add("hSparsePhiMCGenWeight", "hSparsePhiMCGenWeight", HistType::kTHnSparseD, {thnAxisCentrality, {36, 0.0f, TMath::Pi()}, {400, -1.0, 1}, thnAxisPt, {8, -0.8, 0.8}}); + histos.add("hSparsePhiMCRecWeight", "hSparsePhiMCRecWeight", HistType::kTHnSparseD, {thnAxisCentrality, {36, 0.0f, TMath::Pi()}, {400, -1.0, 1}, thnAxisPt, {8, -0.8, 0.8}}); + histos.add("hSparsePhiMCGenKaonWeight", "hSparsePhiMCGenKaonWeight", HistType::kTHnSparseD, {thnAxisCentrality, {36, 0.0f, TMath::Pi()}, {400, -1.0, 1}, axisPtKaonWeight, {8, -0.8, 0.8}}); + histos.add("hSparsePhiMCRecKaonWeight", "hSparsePhiMCRecKaonWeight", HistType::kTHnSparseD, {thnAxisCentrality, {36, 0.0f, TMath::Pi()}, {400, -1.0, 1}, axisPtKaonWeight, {8, -0.8, 0.8}}); + histos.add("hSparsePhiMCRecKaonMissMatchWeight", "hSparsePhiMCRecKaonMissMatchWeight", HistType::kTHnSparseD, {thnAxisCentrality, {36, 0.0f, TMath::Pi()}, {400, -1.0, 1}, axisPtKaonWeight, {8, -0.8, 0.8}}); + + histos.add("hSparseMCGenWeight", "hSparseMCGenWeight", HistType::kTHnSparseD, {thnAxisCentrality, {36, 0.0f, TMath::Pi()}, {400, -1.0, 1}, axisPtKaonWeight, {8, -0.8, 0.8}}); + histos.add("hSparseMCRecWeight", "hSparseMCRecWeight", HistType::kTHnSparseD, {thnAxisCentrality, {36, 0.0f, TMath::Pi()}, {400, -1.0, 1}, axisPtKaonWeight, {8, -0.8, 0.8}}); + histos.add("hSparseMCRecAllTrackWeight", "hSparseMCRecAllTrackWeight", HistType::kTHnSparseD, {thnAxisCentrality, {36, 0.0, TMath::Pi()}, {400, -1.0, 1}, axisPtKaonWeight, {8, -0.8, 0.8}}); + + histos.add("hImpactParameter", "Impact parameter", kTH1F, {{200, 0.0f, 20.0f}}); + histos.add("hEventPlaneAngle", "hEventPlaneAngle", kTH1F, {{200, -2.0f * TMath::Pi(), 2.0f * TMath::Pi()}}); + histos.add("hEventPlaneAngleRec", "hEventPlaneAngleRec", kTH1F, {{200, -2.0f * TMath::Pi(), 2.0f * TMath::Pi()}}); + histos.add("hNchVsImpactParameter", "hNchVsImpactParameter", kTH2F, {{200, 0.0f, 20.0f}, {500, -0.5f, 5000.5f}}); + histos.add("hSparseMCGenV2", "hSparseMCGenV2", HistType::kTHnSparseD, {thnAxisCentrality, {200, -1.0, 1.0}, axisPtKaonWeight}); + histos.add("hSparseMCRecV2", "hSparseMCRecV2", HistType::kTHnSparseD, {thnAxisCentrality, {200, -1.0, 1.0}, axisPtKaonWeight}); + // histos.add("hSparseMCGenV2Square", "hSparseMCGenV2Square", HistType::kTHnSparseD, {thnAxisCentrality, {1000, 0.0, 1.0}, axisPtKaonWeight}); + // histos.add("hSparseMCRecV2Square", "hSparseMCRecV2Square", HistType::kTHnSparseD, {thnAxisCentrality, {1000, 0.0, 1.0}, axisPtKaonWeight}); + histos.add("hSparseMCGenV2Square", "hSparseMCGenV2Square", HistType::kTH3D, {thnAxisCentrality, {1000, 0.0, 1.0}, axisPtKaonWeight}); + histos.add("hSparseMCRecV2Square", "hSparseMCRecV2Square", HistType::kTH3D, {thnAxisCentrality, {1000, 0.0, 1.0}, axisPtKaonWeight}); } // Event selection cut additional - Alex if (additionalEvsel) { @@ -270,6 +324,12 @@ struct phipbpb { fMultMultPVCut = new TF1("fMultMultPVCut", "[0]+[1]*x+[2]*x*x", 0, 5000); fMultMultPVCut->SetParameters(-0.1, 0.785, -4.7e-05); } + + ccdb->setURL(cfgCcdbParam.cfgURL); + ccdbApi.init("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); } double massKa = o2::constants::physics::MassKPlus; @@ -299,10 +359,13 @@ struct phipbpb { template bool selectionTrack(const T& candidate) { - if (useGlobalTrack && !(candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsFound() > cfgTPCcluster)) { + if (useGlobalTrack && !useDcaSyst && !(candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsCrossedRows() > cfgTPCcluster && candidate.tpcFractionSharedCls() < cfgTPCSharedcluster)) { + return false; + } + if (useGlobalTrack && useDcaSyst && !(candidate.itsNCls() > cfgITScluster && candidate.tpcNClsCrossedRows() > cfgTPCcluster && candidate.tpcFractionSharedCls() < cfgTPCSharedcluster)) { return false; } - if (!useGlobalTrack && !(candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster)) { + if (!useGlobalTrack && !(candidate.tpcNClsFound() > cfgTPCcluster)) { return false; } return true; @@ -310,10 +373,10 @@ struct phipbpb { template bool selectionPIDpTdependent(const T& candidate) { - if (candidate.p() < 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + if (candidate.pt() < 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { return true; } - if (candidate.p() >= 0.5 && candidate.hasTOF() && ((candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) + (candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa())) < (nsigmaCutCombined * nsigmaCutCombined)) { + if (candidate.pt() >= 0.5 && candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF) { return true; } if (!useGlobalTrack && !candidate.hasTPC()) { @@ -324,13 +387,19 @@ struct phipbpb { template bool selectionPID(const T& candidate) { - if (!isNoTOF && !candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { return true; } - if (!isNoTOF && candidate.hasTOF() && ((candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) + (candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa())) < (nsigmaCutCombined * nsigmaCutCombined)) { + if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF) { return true; } - if (isNoTOF && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return false; + } + + template + bool selectionPID2(const T& candidate) + { + if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF) { return true; } return false; @@ -376,28 +445,40 @@ struct phipbpb { return delta; } + template + bool isFakeKaon(T const& track) + { + const auto pglobal = track.p(); + const auto ptpc = track.tpcInnerParam(); + if (TMath::Abs(pglobal - ptpc) > ConfFakeKaonCut) { + return true; + } + return false; + } + ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for bin"}; ConfigurableAxis axisMultiplicityClass{"axisMultiplicityClass", {20, 0, 100}, "multiplicity percentile for bin"}; ConfigurableAxis axisEPAngle{"axisEPAngle", {6, -TMath::Pi() / 2, TMath::Pi() / 2}, "event plane angle"}; + ConfigurableAxis axisOccup{"axisOccup", {20, -0.5, 40000.0}, "occupancy axis"}; - using BinningTypeVertexContributor = ColumnBinningPolicy; + using BinningTypeVertexContributor = ColumnBinningPolicy; ROOT::Math::PxPyPzMVector PhiMesonMother, KaonPlus, KaonMinus, fourVecDauCM; ROOT::Math::XYZVector threeVecDauCM, threeVecDauCMXY, eventplaneVec, eventplaneVecNorm, beamvector; - - void processSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& /*tracks*/, aod::BCs const&) + int currentRunNumber = -999; + int lastRunNumber = -999; + // TH3D* hweight; + TH2D* hweight; + void processSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& /*tracks, aod::BCs const&*/, aod::BCsWithTimestamps const&) { - if (!collision.sel8()) { + // if (!collision.sel8() || !collision.triggereventep() || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // return; + // } + if (!collision.sel8() || !collision.triggereventep() || !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { return; } auto centrality = collision.centFT0C(); auto multTPC = collision.multNTracksPV(); histos.fill(HIST("hFTOCvsTPCNoCut"), centrality, multTPC); - if (!collision.triggereventep()) { - return; - } - if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { - return; - } auto posThisColl = posTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto negThisColl = negTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto psiFT0C = collision.psiFT0C(); @@ -405,68 +486,129 @@ struct phipbpb { auto psiTPC = collision.psiTPC(); auto psiTPCR = collision.psiTPCR(); auto psiTPCL = collision.psiTPCL(); - auto QFT0C = collision.qFT0C(); auto QFT0A = collision.qFT0A(); auto QTPC = collision.qTPC(); auto QTPCR = collision.qTPCR(); auto QTPCL = collision.qTPCL(); - + int occupancy = collision.trackOccupancyInTimeRange(); + o2::aod::ITSResponse itsResponse; + if (occupancy > cfgCutOccupancy) { + return; + } histos.fill(HIST("hFTOCvsTPC"), centrality, multTPC); - if (additionalEvsel && !eventSelected(collision, centrality)) { + if (additionalEvsel && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return; + } + if (additionalEvselITS && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { return; } histos.fill(HIST("hFTOCvsTPCSelected"), centrality, multTPC); - histos.fill(HIST("hPsiFT0C"), centrality, psiFT0C); - histos.fill(HIST("hPsiFT0A"), centrality, psiFT0A); - histos.fill(HIST("hPsiTPC"), centrality, psiTPC); - histos.fill(HIST("hPsiTPCR"), centrality, psiTPCR); - histos.fill(HIST("hPsiTPCL"), centrality, psiTPCL); - - histos.fill(HIST("ResFT0CTPC"), centrality, TMath::Cos(2.0 * (psiFT0C - psiTPC))); - histos.fill(HIST("ResFT0CTPCR"), centrality, TMath::Cos(2.0 * (psiFT0C - psiTPCR))); - histos.fill(HIST("ResFT0CTPCL"), centrality, TMath::Cos(2.0 * (psiFT0C - psiTPCL))); - histos.fill(HIST("ResTPCRTPCL"), centrality, TMath::Cos(2.0 * (psiTPCR - psiTPCL))); - histos.fill(HIST("ResFT0CFT0A"), centrality, TMath::Cos(2.0 * (psiFT0C - psiFT0A))); - histos.fill(HIST("ResFT0ATPC"), centrality, TMath::Cos(2.0 * (psiTPC - psiFT0A))); - - histos.fill(HIST("ResSPFT0CTPC"), centrality, QFT0C * QTPC * TMath::Cos(2.0 * (psiFT0C - psiTPC))); - histos.fill(HIST("ResSPFT0CTPCR"), centrality, QFT0C * QTPCR * TMath::Cos(2.0 * (psiFT0C - psiTPCR))); - histos.fill(HIST("ResSPFT0CTPCL"), centrality, QFT0C * QTPCL * TMath::Cos(2.0 * (psiFT0C - psiTPCL))); - histos.fill(HIST("ResSPTPCRTPCL"), centrality, QTPCR * QTPCL * TMath::Cos(2.0 * (psiTPCR - psiTPCL))); - histos.fill(HIST("ResSPFT0CFT0A"), centrality, QFT0C * QFT0A * TMath::Cos(2.0 * (psiFT0C - psiFT0A))); - histos.fill(HIST("ResSPFT0ATPC"), centrality, QTPC * QFT0A * TMath::Cos(2.0 * (psiTPC - psiFT0A))); + histos.fill(HIST("hPsiFT0C"), centrality, occupancy, psiFT0C); + histos.fill(HIST("hPsiFT0A"), centrality, occupancy, psiFT0A); + histos.fill(HIST("hPsiTPC"), centrality, occupancy, psiTPC); + histos.fill(HIST("hPsiTPCR"), centrality, occupancy, psiTPCR); + histos.fill(HIST("hPsiTPCL"), centrality, occupancy, psiTPCL); + + histos.fill(HIST("ResFT0CTPC"), centrality, occupancy, TMath::Cos(2.0 * (psiFT0C - psiTPC))); + histos.fill(HIST("ResFT0CTPCR"), centrality, occupancy, TMath::Cos(2.0 * (psiFT0C - psiTPCR))); + histos.fill(HIST("ResFT0CTPCL"), centrality, occupancy, TMath::Cos(2.0 * (psiFT0C - psiTPCL))); + histos.fill(HIST("ResTPCRTPCL"), centrality, occupancy, TMath::Cos(2.0 * (psiTPCR - psiTPCL))); + histos.fill(HIST("ResFT0CFT0A"), centrality, occupancy, TMath::Cos(2.0 * (psiFT0C - psiFT0A))); + histos.fill(HIST("ResFT0ATPC"), centrality, occupancy, TMath::Cos(2.0 * (psiTPC - psiFT0A))); + + histos.fill(HIST("Res4FT0CTPC"), centrality, occupancy, TMath::Cos(4.0 * (psiFT0C - psiTPC))); + histos.fill(HIST("Res4FT0CTPCR"), centrality, occupancy, TMath::Cos(4.0 * (psiFT0C - psiTPCR))); + histos.fill(HIST("Res4FT0CTPCL"), centrality, occupancy, TMath::Cos(4.0 * (psiFT0C - psiTPCL))); + histos.fill(HIST("Res4TPCRTPCL"), centrality, occupancy, TMath::Cos(4.0 * (psiTPCR - psiTPCL))); + histos.fill(HIST("Res4FT0CFT0A"), centrality, occupancy, TMath::Cos(4.0 * (psiFT0C - psiFT0A))); + histos.fill(HIST("Res4FT0ATPC"), centrality, occupancy, TMath::Cos(4.0 * (psiTPC - psiFT0A))); + + histos.fill(HIST("ResFT0CTPCSquare"), centrality, occupancy, TMath::Power(TMath::Cos(2.0 * (psiFT0C - psiTPC)), 2.0)); + histos.fill(HIST("ResFT0CTPCRSquare"), centrality, occupancy, TMath::Power(TMath::Cos(2.0 * (psiFT0C - psiTPCR)), 2.0)); + histos.fill(HIST("ResFT0CTPCLSquare"), centrality, occupancy, TMath::Power(TMath::Cos(2.0 * (psiFT0C - psiTPCL)), 2.0)); + histos.fill(HIST("ResTPCRTPCLSquare"), centrality, occupancy, TMath::Power(TMath::Cos(2.0 * (psiTPCR - psiTPCL)), 2.0)); + histos.fill(HIST("ResFT0CFT0ASquare"), centrality, occupancy, TMath::Power(TMath::Cos(2.0 * (psiFT0C - psiFT0A)), 2.0)); + histos.fill(HIST("ResFT0ATPCSquare"), centrality, occupancy, TMath::Power(TMath::Cos(2.0 * (psiTPC - psiFT0A)), 2.0)); + + histos.fill(HIST("ResSPFT0CTPC"), centrality, occupancy, QFT0C * QTPC * TMath::Cos(2.0 * (psiFT0C - psiTPC))); + histos.fill(HIST("ResSPFT0CTPCR"), centrality, occupancy, QFT0C * QTPCR * TMath::Cos(2.0 * (psiFT0C - psiTPCR))); + histos.fill(HIST("ResSPFT0CTPCL"), centrality, occupancy, QFT0C * QTPCL * TMath::Cos(2.0 * (psiFT0C - psiTPCL))); + histos.fill(HIST("ResSPTPCRTPCL"), centrality, occupancy, QTPCR * QTPCL * TMath::Cos(2.0 * (psiTPCR - psiTPCL))); + histos.fill(HIST("ResSPFT0CFT0A"), centrality, occupancy, QFT0C * QFT0A * TMath::Cos(2.0 * (psiFT0C - psiFT0A))); + histos.fill(HIST("ResSPFT0ATPC"), centrality, occupancy, QTPC * QFT0A * TMath::Cos(2.0 * (psiTPC - psiFT0A))); + + histos.fill(HIST("Res4SPFT0CTPC"), centrality, occupancy, QFT0C * QTPC * TMath::Cos(4.0 * (psiFT0C - psiTPC))); + histos.fill(HIST("Res4SPFT0CTPCR"), centrality, occupancy, QFT0C * QTPCR * TMath::Cos(4.0 * (psiFT0C - psiTPCR))); + histos.fill(HIST("Res4SPFT0CTPCL"), centrality, occupancy, QFT0C * QTPCL * TMath::Cos(4.0 * (psiFT0C - psiTPCL))); + histos.fill(HIST("Res4SPTPCRTPCL"), centrality, occupancy, QTPCR * QTPCL * TMath::Cos(4.0 * (psiTPCR - psiTPCL))); + histos.fill(HIST("Res4SPFT0CFT0A"), centrality, occupancy, QFT0C * QFT0A * TMath::Cos(4.0 * (psiFT0C - psiFT0A))); + histos.fill(HIST("Res4SPFT0ATPC"), centrality, occupancy, QTPC * QFT0A * TMath::Cos(4.0 * (psiTPC - psiFT0A))); histos.fill(HIST("hCentrality"), centrality); histos.fill(HIST("hVtxZ"), collision.posZ()); + + auto bc = collision.bc_as(); + currentRunNumber = collision.bc_as().runNumber(); + if (useWeight && (currentRunNumber != lastRunNumber)) { + // hweight = ccdb->getForTimeStamp(ConfWeightPath.value, bc.timestamp()); + hweight = ccdb->getForTimeStamp(ConfWeightPath.value, bc.timestamp()); + } + lastRunNumber = currentRunNumber; + int Npostrack = 0; + float weight1 = 1.0; + float weight2 = 1.0; for (auto track1 : posThisColl) { // track selection if (!selectionTrack(track1)) { continue; } // PID check - if (ispTdepPID && !selectionPIDpTdependent(track1)) { + if (ispTdepPID && !isTOFOnly && !selectionPIDpTdependent(track1)) { + continue; + } + if (!ispTdepPID && !isTOFOnly && !selectionPID(track1)) { + continue; + } + if (isTOFOnly && !selectionPID2(track1)) { continue; } - if (!ispTdepPID && !selectionPID(track1)) { + if (useGlobalTrack && track1.p() < 1.0 && !(itsResponse.nSigmaITS(track1) > -2.5 && itsResponse.nSigmaITS(track1) < 2.5)) { continue; } + histos.fill(HIST("hTPCglobalmomcorr"), track1.p() / track1.sign(), track1.p() - track1.tpcInnerParam(), centrality); histos.fill(HIST("hEta"), track1.eta()); histos.fill(HIST("hDcaxy"), track1.dcaXY()); histos.fill(HIST("hDcaz"), track1.dcaZ()); histos.fill(HIST("hNsigmaKaonTPC"), track1.tpcNSigmaKa()); histos.fill(HIST("hNsigmaKaonTOF"), track1.tofNSigmaKa()); + auto V2Track = TMath::Cos(2.0 * GetPhiInRange(track1.phi() - psiFT0C)); + histos.fill(HIST("hITS"), track1.itsNCls(), V2Track); + histos.fill(HIST("hTPC"), track1.tpcNClsCrossedRows(), V2Track); + histos.fill(HIST("hTPCScls"), track1.tpcNClsShared(), V2Track); + histos.fill(HIST("hTPCSclsFrac"), track1.tpcFractionSharedCls(), V2Track); auto track1ID = track1.globalIndex(); + if (useWeight) { + if (track1.pt() < 10.0 && track1.pt() > 0.15) { + // weight1 = hweight->GetBinContent(hweight->FindBin(centrality, GetPhiInRange(track1.phi() - psiFT0C), track1.pt() + 0.000005)); + weight1 = 1 + hweight->GetBinContent(hweight->FindBin(centrality, track1.pt() + 0.000005)) * TMath::Cos(2.0 * GetPhiInRange(track1.phi() - psiFT0C)); + } else { + weight1 = 1; + } + } for (auto track2 : negThisColl) { // track selection if (!selectionTrack(track2)) { continue; } // PID check - if (ispTdepPID && !selectionPIDpTdependent(track2)) { + if (ispTdepPID && !isTOFOnly && !selectionPIDpTdependent(track2)) { continue; } - if (!ispTdepPID && !selectionPID(track2)) { + if (!ispTdepPID && !isTOFOnly && !selectionPID(track2)) { + continue; + } + if (isTOFOnly && !selectionPID2(track2)) { continue; } auto track2ID = track2.globalIndex(); @@ -476,188 +618,177 @@ struct phipbpb { if (!selectionPair(track1, track2)) { continue; } - KaonPlus = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); - KaonMinus = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); - PhiMesonMother = KaonPlus + KaonMinus; - histos.fill(HIST("hpTvsRapidity"), PhiMesonMother.Pt(), PhiMesonMother.Rapidity()); - if (TMath::Abs(PhiMesonMother.Rapidity()) > confRapidity) { - continue; - } - ROOT::Math::Boost boost{PhiMesonMother.BoostToCM()}; - fourVecDauCM = boost(KaonMinus); - threeVecDauCM = fourVecDauCM.Vect(); - threeVecDauCMXY = ROOT::Math::XYZVector(threeVecDauCM.X(), threeVecDauCM.Y(), 0.); - eventplaneVec = ROOT::Math::XYZVector(std::cos(2.0 * psiFT0C), std::sin(2.0 * psiFT0C), 0); - eventplaneVecNorm = ROOT::Math::XYZVector(std::sin(2.0 * psiFT0C), -std::cos(2.0 * psiFT0C), 0); - - // auto cosinephidaughterstarminuspsi = eventplaneVec.Dot(threeVecDauCMXY) / std::sqrt(threeVecDauCMXY.Mag2()) / std::sqrt(eventplaneVec.Mag2()); - // auto SA = (2.0 * cosinephidaughterstarminuspsi * cosinephidaughterstarminuspsi) - 1.0; - auto cosPhistarminuspsi = GetPhiInRange(fourVecDauCM.Phi() - psiFT0C); - auto SA = TMath::Cos(2.0 * cosPhistarminuspsi); - // auto cosThetaStarOP = TMath::Abs(eventplaneVecNorm.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVecNorm.Mag2())); - auto cosThetaStarOP = eventplaneVecNorm.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVecNorm.Mag2()); - auto SA_A0 = 1 - (cosThetaStarOP * cosThetaStarOP); - // auto cosThetaStarIP = TMath::Abs(eventplaneVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVec.Mag2())); - auto cosThetaStarIP = eventplaneVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVec.Mag2()); - auto phiminuspsi = GetPhiInRange(PhiMesonMother.Phi() - psiFT0C); - auto v2 = TMath::Cos(2.0 * phiminuspsi); - if (!fillRapidity) { - histos.fill(HIST("hSparseV2SASameEvent_costhetastarOP"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEvent_costheta_SA"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP * cosThetaStarOP, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEvent_costhetastarIP"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarIP, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEvent_SA"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEvent_SA_A0"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA_A0, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEvent_V2"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2, centrality); - histos.fill(HIST("hSparseV2SASameEvent_SP"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2 * QFT0C, centrality); - } - - if (fillRapidity) { - histos.fill(HIST("hSparseV2SASameEvent_costhetastarOP"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_costheta_SA"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP * cosThetaStarOP, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_costhetastarIP"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarIP, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_SA"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_SA_A0"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA_A0, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_V2"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2, centrality); + if (Npostrack == 0) { + histos.fill(HIST("hTPCglobalmomcorr"), track2.p() / track2.sign(), track2.p() - track2.tpcInnerParam(), centrality); } - } - } - } - PROCESS_SWITCH(phipbpb, processSameEvent, "Process Same event", true); - void processMixedEvent(EventCandidates const& collisions, TrackCandidates const& /*tracks*/) - { - BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicityClass, axisEPAngle}, true}; - for (auto const& [collision1, collision2] : o2::soa::selfCombinations(binningOnPositions, cfgNoMixedEvents, -1, collisions, collisions)) { - if (!collision1.sel8() || !collision2.sel8()) { - // printf("Mix = %d\n", 1); - continue; - } - if (!collision1.triggereventep() || !collision2.triggereventep()) { - // printf("Mix = %d\n", 2); - continue; - } - if (timFrameEvsel && (!collision1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision2.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision1.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision2.selection_bit(aod::evsel::kNoITSROFrameBorder))) { - // printf("Mix = %d\n", 3); - continue; - } - auto posThisColl = posTracks->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); - auto negThisColl = negTracks->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); - auto centrality = collision1.centFT0C(); - auto centrality2 = collision2.centFT0C(); - auto psiFT0C = collision1.psiFT0C(); - auto QFT0C = collision1.qFT0C(); - if (additionalEvsel && !eventSelected(collision1, centrality)) { - // printf("Mix = %d\n", 4); - continue; - } - if (additionalEvsel && !eventSelected(collision2, centrality2)) { - // printf("Mix = %d\n", 5); - continue; - } - for (auto& [track1, track2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(posThisColl, negThisColl))) { - // track selection - if (!selectionTrack(track1) || !selectionTrack(track2)) { - // printf("Mix = %d\n", 6); + if (removefaketrak && isFakeKaon(track1)) { continue; } - // PID check - if (ispTdepPID && (!selectionPIDpTdependent(track1) || !selectionPIDpTdependent(track2))) { - // printf("Mix = %d\n", 7); + if (removefaketrak && isFakeKaon(track2)) { continue; } - if (!ispTdepPID && (!selectionPID(track1) || !selectionPID(track2))) { + if (useGlobalTrack && track2.p() < 1.0 && !(itsResponse.nSigmaITS(track2) > -2.5 && itsResponse.nSigmaITS(track2) < 2.5)) { continue; } - if (!selectionPair(track1, track2)) { - // printf("Mix = %d\n", 8); - continue; + if (useWeight) { + if (track2.pt() < 10.0 && track2.pt() > 0.15) { + // weight2 = hweight->GetBinContent(hweight->FindBin(centrality, GetPhiInRange(track2.phi() - psiFT0C), track2.pt() + 0.000005)); + weight2 = 1 + hweight->GetBinContent(hweight->FindBin(centrality, track2.pt() + 0.000005)) * TMath::Cos(2.0 * GetPhiInRange(track2.phi() - psiFT0C)); + } else { + weight2 = 1; + } } KaonPlus = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); KaonMinus = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); PhiMesonMother = KaonPlus + KaonMinus; - if (TMath::Abs(PhiMesonMother.Rapidity()) > confRapidity) { - continue; - } - ROOT::Math::Boost boost{PhiMesonMother.BoostToCM()}; - fourVecDauCM = boost(KaonMinus); - threeVecDauCM = fourVecDauCM.Vect(); - threeVecDauCMXY = ROOT::Math::XYZVector(threeVecDauCM.X(), threeVecDauCM.Y(), 0.); - eventplaneVec = ROOT::Math::XYZVector(std::cos(2.0 * psiFT0C), std::sin(2.0 * psiFT0C), 0); - eventplaneVecNorm = ROOT::Math::XYZVector(std::sin(2.0 * psiFT0C), -std::cos(2.0 * psiFT0C), 0); - - // auto cosinephidaughterstarminuspsi = eventplaneVec.Dot(threeVecDauCMXY) / std::sqrt(threeVecDauCMXY.Mag2()) / std::sqrt(eventplaneVec.Mag2()); - // auto SA = (2.0 * cosinephidaughterstarminuspsi * cosinephidaughterstarminuspsi) - 1.0; - auto cosPhistarminuspsi = GetPhiInRange(fourVecDauCM.Phi() - psiFT0C); - auto SA = TMath::Cos(2.0 * cosPhistarminuspsi); - // auto cosThetaStarOP = TMath::Abs(eventplaneVecNorm.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVecNorm.Mag2())); - auto cosThetaStarOP = eventplaneVecNorm.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVecNorm.Mag2()); - auto SA_A0 = 1 - (cosThetaStarOP * cosThetaStarOP); - // auto cosThetaStarIP = TMath::Abs(eventplaneVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVec.Mag2())); - auto cosThetaStarIP = eventplaneVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVec.Mag2()); auto phiminuspsi = GetPhiInRange(PhiMesonMother.Phi() - psiFT0C); auto v2 = TMath::Cos(2.0 * phiminuspsi); - if (!fillRapidity) { - histos.fill(HIST("hSparseV2SAMixedEvent_costhetastarOP"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_costheta_SA"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP * cosThetaStarOP, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_costhetastarIP"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarIP, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_SA"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_SA_A0"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA_A0, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_V2"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2, centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_SP"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2 * QFT0C, centrality); - } - if (fillRapidity) { - histos.fill(HIST("hSparseV2SAMixedEvent_costhetastarOP"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_costheta_SA"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP * cosThetaStarOP, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_costhetastarIP"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarIP, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_SA"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_SA_A0"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA_A0, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_V2"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2, centrality); + auto v2acc = TMath::Cos(4.0 * phiminuspsi); + auto v2sin = TMath::Sin(2.0 * phiminuspsi); + auto phimother = PhiMesonMother.Phi(); + histos.fill(HIST("hpTvsRapidity"), PhiMesonMother.Pt(), PhiMesonMother.Rapidity()); + auto totalweight = weight1 * weight2; + if (totalweight <= 0.0000005) { + totalweight = 1.0; + } + // LOGF(info, Form("weight %f %f",weight1, weight2)); + if (TMath::Abs(PhiMesonMother.Rapidity()) < confRapidity) { + histos.fill(HIST("ResTrackSPFT0CTPC"), centrality, occupancy, QFT0C * QTPC * TMath::Cos(2.0 * (psiFT0C - psiTPC))); + histos.fill(HIST("ResTrackSPFT0CTPCR"), centrality, occupancy, QFT0C * QTPCR * TMath::Cos(2.0 * (psiFT0C - psiTPCR))); + histos.fill(HIST("ResTrackSPFT0CTPCL"), centrality, occupancy, QFT0C * QTPCL * TMath::Cos(2.0 * (psiFT0C - psiTPCL))); + histos.fill(HIST("ResTrackSPTPCRTPCL"), centrality, occupancy, QTPCR * QTPCL * TMath::Cos(2.0 * (psiTPCR - psiTPCL))); + histos.fill(HIST("ResTrackSPFT0CFT0A"), centrality, occupancy, QFT0C * QFT0A * TMath::Cos(2.0 * (psiFT0C - psiFT0A))); + histos.fill(HIST("ResTrackSPFT0ATPC"), centrality, occupancy, QTPC * QFT0A * TMath::Cos(2.0 * (psiTPC - psiFT0A))); + if (useWeight) { + histos.fill(HIST("hSparseV2SameEventCosDeltaPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2 * QFT0C, centrality, 1 / totalweight); + histos.fill(HIST("hSparseV2SameEventCos2DeltaPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2acc * QFT0C, centrality, 1 / totalweight); + + histos.fill(HIST("hSparseV2SameEventCosDeltaPhiSquare"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2 * v2, centrality, 1 / totalweight); + histos.fill(HIST("hSparseV2SameEventSinDeltaPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2sin * QFT0C, centrality, 1 / totalweight); + + histos.fill(HIST("hSparseV2SameEventCosPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), TMath::Cos(2.0 * phimother), centrality, 1 / totalweight); + histos.fill(HIST("hSparseV2SameEventSinPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), TMath::Sin(2.0 * phimother), centrality, 1 / totalweight); + histos.fill(HIST("hSparseV2SameEventCosPsi"), PhiMesonMother.M(), PhiMesonMother.Pt(), TMath::Cos(2.0 * psiFT0C), centrality, 1 / totalweight); + histos.fill(HIST("hSparseV2SameEventSinPsi"), PhiMesonMother.M(), PhiMesonMother.Pt(), TMath::Sin(2.0 * psiFT0C), centrality, 1 / totalweight); + } else { + if (useSP) { + histos.fill(HIST("hSparseV2SameEventCosDeltaPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2 * QFT0C, centrality); + histos.fill(HIST("hSparseV2SameEventCos2DeltaPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2acc * QFT0C, centrality); + } else { + histos.fill(HIST("hSparseV2SameEventCosDeltaPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2, centrality); + histos.fill(HIST("hSparseV2SameEventCos2DeltaPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2acc, centrality); + } + histos.fill(HIST("hSparseV2SameEventCosDeltaPhiSquare"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2 * v2, centrality); + histos.fill(HIST("hSparseV2SameEventCosDeltaPhiCube"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2 * v2 * v2, centrality); + histos.fill(HIST("hSparseV2SameEventSinDeltaPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2sin * QFT0C, centrality); + + histos.fill(HIST("hSparseV2SameEventCosPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), TMath::Cos(2.0 * phimother), centrality); + histos.fill(HIST("hSparseV2SameEventSinPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), TMath::Sin(2.0 * phimother), centrality); + histos.fill(HIST("hSparseV2SameEventCosPsi"), PhiMesonMother.M(), PhiMesonMother.Pt(), TMath::Cos(2.0 * psiFT0C), centrality); + histos.fill(HIST("hSparseV2SameEventSinPsi"), PhiMesonMother.M(), PhiMesonMother.Pt(), TMath::Sin(2.0 * psiFT0C), centrality); + } + } + if (fillSA) { + ROOT::Math::Boost boost{PhiMesonMother.BoostToCM()}; + fourVecDauCM = boost(KaonMinus); + threeVecDauCM = fourVecDauCM.Vect(); + threeVecDauCMXY = ROOT::Math::XYZVector(threeVecDauCM.X(), threeVecDauCM.Y(), 0.); + eventplaneVec = ROOT::Math::XYZVector(std::cos(2.0 * psiFT0C), std::sin(2.0 * psiFT0C), 0); + eventplaneVecNorm = ROOT::Math::XYZVector(std::sin(2.0 * psiFT0C), -std::cos(2.0 * psiFT0C), 0); + auto cosPhistarminuspsi = GetPhiInRange(fourVecDauCM.Phi() - psiFT0C); + auto SA = TMath::Cos(2.0 * cosPhistarminuspsi); + auto cosThetaStar = eventplaneVecNorm.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVecNorm.Mag2()); + if (useWeight) { + histos.fill(HIST("hSparseV2SameEventSA"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA, TMath::Abs(PhiMesonMother.Rapidity()), centrality, 1 / totalweight); + histos.fill(HIST("hSparseV2SameEventCosThetaStar"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStar, TMath::Abs(PhiMesonMother.Rapidity()), centrality, 1 / totalweight); + } else { + histos.fill(HIST("hSparseV2SameEventSA"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA, TMath::Abs(PhiMesonMother.Rapidity()), centrality); + histos.fill(HIST("hSparseV2SameEventCosThetaStar"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStar, TMath::Abs(PhiMesonMother.Rapidity())); + } } } + Npostrack = Npostrack + 1; } } - PROCESS_SWITCH(phipbpb, processMixedEvent, "Process Mixed event", true); + PROCESS_SWITCH(phipbpb, processSameEvent, "Process Same event", true); void processMixedEventOpti(EventCandidates const& collisions, TrackCandidates const& tracks) { auto tracksTuple = std::make_tuple(tracks); - BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicityClass, axisEPAngle}, true}; + BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicityClass, axisOccup}, true}; SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; for (auto& [collision1, tracks1, collision2, tracks2] : pair) { - if (!collision1.sel8() || !collision2.sel8()) { + // if (!collision1.sel8() || !collision1.triggereventep() || !collision1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision1.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision1.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !collision1.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // continue; + // } + // if (!collision2.sel8() || !collision2.triggereventep() || !collision2.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision2.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision2.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !collision2.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // continue; + // } + if (!collision1.sel8() || !collision1.triggereventep() || !collision1.selection_bit(aod::evsel::kNoSameBunchPileup)) { + continue; + } + if (!collision2.sel8() || !collision2.triggereventep() || !collision2.selection_bit(aod::evsel::kNoSameBunchPileup)) { + continue; + } + if (collision1.bcId() == collision2.bcId()) { continue; } - if (!collision1.triggereventep() || !collision2.triggereventep()) { + o2::aod::ITSResponse itsResponse; + int occupancy1 = collision1.trackOccupancyInTimeRange(); + int occupancy2 = collision2.trackOccupancyInTimeRange(); + if (occupancy1 > cfgCutOccupancy) { continue; } - if (timFrameEvsel && (!collision1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision2.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision1.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision2.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + if (occupancy2 > cfgCutOccupancy) { continue; } auto centrality = collision1.centFT0C(); - auto centrality2 = collision2.centFT0C(); + // auto centrality2 = collision2.centFT0C(); auto psiFT0C = collision1.psiFT0C(); - if (additionalEvsel && !eventSelected(collision1, centrality)) { + auto QFT0C = collision1.qFT0C(); + if (additionalEvsel && !collision1.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { continue; } - if (additionalEvsel && !eventSelected(collision2, centrality2)) { + if (additionalEvsel && !collision2.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + continue; + } + if (additionalEvselITS && !collision1.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + continue; + } + if (additionalEvselITS && !collision2.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { continue; } - for (auto& [track1, track2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { if (track1.sign() * track2.sign() > 0) { continue; } + if (useGlobalTrack && track1.p() < 1.0 && !(itsResponse.nSigmaITS(track1) > -2.5 && itsResponse.nSigmaITS(track1) < 2.5)) { + continue; + } + if (useGlobalTrack && track2.p() < 1.0 && !(itsResponse.nSigmaITS(track2) > -2.5 && itsResponse.nSigmaITS(track2) < 2.5)) { + continue; + } if (!selectionTrack(track1) || !selectionTrack(track2)) { continue; } // PID check - if (ispTdepPID && (!selectionPIDpTdependent(track1) || !selectionPIDpTdependent(track2))) { + if (ispTdepPID && !isTOFOnly && (!selectionPIDpTdependent(track1) || !selectionPIDpTdependent(track2))) { continue; } - if (!ispTdepPID && (!selectionPID(track1) || !selectionPID(track2))) { + if (!ispTdepPID && !isTOFOnly && (!selectionPID(track1) || !selectionPID(track2))) { + continue; + } + if (isTOFOnly && (!selectionPID2(track1) || !selectionPID2(track2))) { continue; } if (!selectionPair(track1, track2)) { continue; } + if (removefaketrak && isFakeKaon(track1)) { + continue; + } + if (removefaketrak && isFakeKaon(track2)) { + continue; + } if (track1.sign() > 0 && track2.sign() < 0) { KaonPlus = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); KaonMinus = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); @@ -665,42 +796,35 @@ struct phipbpb { KaonMinus = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); KaonPlus = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); } - PhiMesonMother = KaonPlus + KaonMinus; - if (TMath::Abs(PhiMesonMother.Rapidity()) > confRapidity) { - continue; - } - ROOT::Math::Boost boost{PhiMesonMother.BoostToCM()}; - fourVecDauCM = boost(KaonMinus); - threeVecDauCM = fourVecDauCM.Vect(); - threeVecDauCMXY = ROOT::Math::XYZVector(threeVecDauCM.X(), threeVecDauCM.Y(), 0.); - eventplaneVec = ROOT::Math::XYZVector(std::cos(2.0 * psiFT0C), std::sin(2.0 * psiFT0C), 0); - eventplaneVecNorm = ROOT::Math::XYZVector(std::sin(2.0 * psiFT0C), -std::cos(2.0 * psiFT0C), 0); - - auto cosPhistarminuspsi = GetPhiInRange(fourVecDauCM.Phi() - psiFT0C); - auto SA = TMath::Cos(2.0 * cosPhistarminuspsi); - // auto cosThetaStarOP = TMath::Abs(eventplaneVecNorm.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVecNorm.Mag2())); - auto cosThetaStarOP = eventplaneVecNorm.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVecNorm.Mag2()); - auto SA_A0 = 1 - (cosThetaStarOP * cosThetaStarOP); - // auto cosThetaStarIP = TMath::Abs(eventplaneVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVec.Mag2())); - auto cosThetaStarIP = eventplaneVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVec.Mag2()); auto phiminuspsi = GetPhiInRange(PhiMesonMother.Phi() - psiFT0C); auto v2 = TMath::Cos(2.0 * phiminuspsi); - if (!fillRapidity) { - histos.fill(HIST("hSparseV2SAMixedEvent_costhetastarOP"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_costheta_SA"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP * cosThetaStarOP, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_costhetastarIP"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarIP, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_SA"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_SA_A0"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA_A0, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_V2"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2, centrality); - } - if (fillRapidity) { - histos.fill(HIST("hSparseV2SAMixedEvent_costhetastarOP"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_costheta_SA"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP * cosThetaStarOP, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_costhetastarIP"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarIP, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_SA"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_SA_A0"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA_A0, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SAMixedEvent_V2"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2, centrality); + auto v2acc = TMath::Cos(4.0 * phiminuspsi); + auto v2sin = TMath::Sin(2.0 * phiminuspsi); + histos.fill(HIST("hpTvsRapidity"), PhiMesonMother.Pt(), PhiMesonMother.Rapidity()); + if (TMath::Abs(PhiMesonMother.Rapidity()) < confRapidity) { + if (useSP) { + histos.fill(HIST("hSparseV2MixedEventCosDeltaPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2 * QFT0C, centrality); + histos.fill(HIST("hSparseV2MixedEventCos2DeltaPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2acc * QFT0C, centrality); + } else { + histos.fill(HIST("hSparseV2MixedEventCosDeltaPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2, centrality); + histos.fill(HIST("hSparseV2MixedEventCos2DeltaPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2acc, centrality); + } + histos.fill(HIST("hSparseV2MixedEventCosDeltaPhiSquare"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2 * v2, centrality); + histos.fill(HIST("hSparseV2MixedEventSinDeltaPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2sin * QFT0C, centrality); + } + if (fillSA) { + ROOT::Math::Boost boost{PhiMesonMother.BoostToCM()}; + fourVecDauCM = boost(KaonMinus); + threeVecDauCM = fourVecDauCM.Vect(); + threeVecDauCMXY = ROOT::Math::XYZVector(threeVecDauCM.X(), threeVecDauCM.Y(), 0.); + eventplaneVec = ROOT::Math::XYZVector(std::cos(2.0 * psiFT0C), std::sin(2.0 * psiFT0C), 0); + eventplaneVecNorm = ROOT::Math::XYZVector(std::sin(2.0 * psiFT0C), -std::cos(2.0 * psiFT0C), 0); + auto cosPhistarminuspsi = GetPhiInRange(fourVecDauCM.Phi() - psiFT0C); + auto SA = TMath::Cos(2.0 * cosPhistarminuspsi); + auto cosThetaStar = eventplaneVecNorm.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVecNorm.Mag2()); + histos.fill(HIST("hSparseV2MixedEventSA"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA, TMath::Abs(PhiMesonMother.Rapidity()), centrality); + histos.fill(HIST("hSparseV2MixedEventCosThetaStar"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStar, TMath::Abs(PhiMesonMother.Rapidity()), centrality); } } } @@ -724,11 +848,12 @@ struct phipbpb { histos.fill(HIST("hMC"), 4); continue; } - if (timFrameEvsel && (!RecCollision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !RecCollision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + + if (!RecCollision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !RecCollision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { histos.fill(HIST("hMC"), 5); continue; } - if (std::abs(RecCollision.posZ()) > cfgCutVertex) { + if (TMath::Abs(RecCollision.posZ()) > cfgCutVertex) { histos.fill(HIST("hMC"), 6); continue; } @@ -777,8 +902,8 @@ struct phipbpb { } const auto mctrack1 = track1.mcParticle(); const auto mctrack2 = track2.mcParticle(); - int track1PDG = std::abs(mctrack1.pdgCode()); - int track2PDG = std::abs(mctrack2.pdgCode()); + int track1PDG = TMath::Abs(mctrack1.pdgCode()); + int track2PDG = TMath::Abs(mctrack2.pdgCode()); if (!mctrack1.isPhysicalPrimary()) { continue; } @@ -796,10 +921,10 @@ struct phipbpb { if (mothertrack1 != mothertrack2) { continue; } - if (std::abs(mothertrack1.y()) > confRapidity) { + if (TMath::Abs(mothertrack1.y()) > confRapidity) { continue; } - if (std::abs(mothertrack1.pdgCode()) != 333) { + if (TMath::Abs(mothertrack1.pdgCode()) != 333) { continue; } if (!selectionPID(track1) || !selectionPID(track2)) { @@ -819,10 +944,6 @@ struct phipbpb { KaonPlus = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); } PhiMesonMother = KaonPlus + KaonMinus; - - if (TMath::Abs(PhiMesonMother.Rapidity()) > confRapidity) { - continue; - } ROOT::Math::Boost boost{PhiMesonMother.BoostToCM()}; fourVecDauCM = boost(KaonMinus); threeVecDauCM = fourVecDauCM.Vect(); @@ -832,39 +953,16 @@ struct phipbpb { eventplaneVecNorm = ROOT::Math::XYZVector(std::sin(2.0 * psiFT0C), -std::cos(2.0 * psiFT0C), 0); auto cosPhistarminuspsi = GetPhiInRange(fourVecDauCM.Phi() - psiFT0C); auto SA = TMath::Cos(2.0 * cosPhistarminuspsi); - // auto cosThetaStarOP = TMath::Abs(eventplaneVecNorm.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVecNorm.Mag2())); - auto cosThetaStarIP = eventplaneVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVec.Mag2()); - auto cosThetaStarOP = eventplaneVecNorm.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVecNorm.Mag2()); - auto cosThetaStarOPbeam = beamvector.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(beamvector.Mag2()); - auto SA_A0 = 1 - (cosThetaStarOP * cosThetaStarOP); - // auto cosThetaStarIP = TMath::Abs(eventplaneVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVec.Mag2())); - auto phiminuspsi = GetPhiInRange(PhiMesonMother.Phi() - psiFT0C); - auto v2 = TMath::Cos(2.0 * phiminuspsi); - if (!fillRapidity) { - histos.fill(HIST("hSparseV2SASameEvent_costhetastarOP_MCRec"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEvent_costhetastarOP_beam_MCRec"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOPbeam, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEvent_costheta_SA_MCRec"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP * cosThetaStarOP, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEvent_costhetastarIP_MCRec"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarIP, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEvent_SA_MCRec"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEvent_SA_A0_MCRec"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA_A0, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEvent_V2_MCRec"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2, centrality); - } - if (fillRapidity) { - histos.fill(HIST("hSparseV2SASameEvent_costhetastarOP_MCRec"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_costhetastarOP_beam_MCRec"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOPbeam, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_costheta_SA_MCRec"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP * cosThetaStarOP, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_costhetastarIP_MCRec"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarIP, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_SA_MCRec"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_SA_A0_MCRec"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA_A0, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_V2_MCRec"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2, centrality); - } + auto cosThetaStar = eventplaneVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVec.Mag2()); + histos.fill(HIST("hSparseV2MCRecCosThetaStar_effy"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStar, TMath::Abs(PhiMesonMother.Rapidity()), centrality); + histos.fill(HIST("hSparseV2MCRecSA"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA, TMath::Abs(PhiMesonMother.Rapidity()), centrality); } } } } // loop over generated particle for (auto& mcParticle : GenParticles) { - if (std::abs(mcParticle.y()) > confRapidity) { + if (TMath::Abs(mcParticle.y()) > confRapidity) { continue; } if (mcParticle.pdgCode() != 333) { @@ -909,36 +1007,276 @@ struct phipbpb { eventplaneVecNorm = ROOT::Math::XYZVector(std::sin(2.0 * psiFT0C), -std::cos(2.0 * psiFT0C), 0); auto cosPhistarminuspsi = GetPhiInRange(fourVecDauCM.Phi() - psiFT0C); auto SA = TMath::Cos(2.0 * cosPhistarminuspsi); - auto cosThetaStarIP = eventplaneVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVec.Mag2()); - auto cosThetaStarOP = eventplaneVecNorm.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVecNorm.Mag2()); - auto cosThetaStarOPbeam = beamvector.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(beamvector.Mag2()); - auto SA_A0 = 1 - (cosThetaStarOP * cosThetaStarOP); - auto phiminuspsi = GetPhiInRange(PhiMesonMother.Phi() - psiFT0C); - auto v2 = TMath::Cos(2.0 * phiminuspsi); - if (!fillRapidity) { - histos.fill(HIST("hSparseV2SASameEvent_costhetastarOP_MCGen"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEvent_costhetastarOP_beam_MCGen"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOPbeam, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEvent_costheta_SA_MCGen"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP * cosThetaStarOP, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEvent_costhetastarIP_MCGen"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarIP, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEvent_SA_MCGen"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEvent_SA_A0_MCGen"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA_A0, phiminuspsi, centrality); - histos.fill(HIST("hSparseV2SASameEvent_V2_MCGen"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2, centrality); + auto cosThetaStar = eventplaneVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVec.Mag2()); + histos.fill(HIST("hSparseV2MCGenCosThetaStar_effy"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStar, TMath::Abs(PhiMesonMother.Rapidity()), centrality); + histos.fill(HIST("hSparseV2MCGenSA"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA, TMath::Abs(PhiMesonMother.Rapidity()), centrality); + } + } + } // rec collision loop + + } // process MC + PROCESS_SWITCH(phipbpb, processMC, "Process MC", false); + using recoTracks = soa::Join; + void processMCweight(aod::McCollision const& mcCollision, soa::Join const& mcParticles, recoTracks const&) + { + float imp = mcCollision.impactParameter(); + float evPhi = mcCollision.eventPlaneAngle() / 2.0; + float centclass = -999; + if (imp >= 0 && imp < 3.49) { + centclass = 2.5; + } + if (imp >= 3.49 && imp < 4.93) { + centclass = 7.5; + } + if (imp >= 4.93 && imp < 6.98) { + centclass = 15.0; + } + if (imp >= 6.98 && imp < 8.55) { + centclass = 25.0; + } + if (imp >= 8.55 && imp < 9.87) { + centclass = 35.0; + } + if (imp >= 9.87 && imp < 11) { + centclass = 45.0; + } + if (imp >= 11 && imp < 12.1) { + centclass = 55.0; + } + if (imp >= 12.1 && imp < 13.1) { + centclass = 65.0; + } + if (imp >= 13.1 && imp < 14) { + centclass = 75.0; + } + // if (evPhi < 0) + // evPhi += 2. * TMath::Pi(); + + int nCh = 0; + + if (centclass > 0 && centclass < 80) { + // event within range + histos.fill(HIST("hImpactParameter"), imp); + histos.fill(HIST("hEventPlaneAngle"), evPhi); + for (auto const& mcParticle : mcParticles) { + + float deltaPhi = mcParticle.phi() - mcCollision.eventPlaneAngle(); + // focus on bulk: e, mu, pi, k, p + int pdgCode = TMath::Abs(mcParticle.pdgCode()); + if (checkAllCharge && pdgCode != 11 && pdgCode != 13 && pdgCode != 211 && pdgCode != 321 && pdgCode != 2212) + continue; + if (!checkAllCharge && pdgCode != 321) + continue; + if (!mcParticle.isPhysicalPrimary()) + continue; + if (TMath::Abs(mcParticle.eta()) > 0.8) // main acceptance + continue; + histos.fill(HIST("hSparseMCGenWeight"), centclass, GetPhiInRange(deltaPhi), TMath::Power(TMath::Cos(4.0 * GetPhiInRange(deltaPhi)), 1.0), mcParticle.pt(), mcParticle.eta()); + histos.fill(HIST("hSparseMCGenV2"), centclass, TMath::Cos(2.0 * GetPhiInRange(deltaPhi)), mcParticle.pt()); + histos.fill(HIST("hSparseMCGenV2Square"), centclass, TMath::Power(TMath::Cos(2.0 * GetPhiInRange(deltaPhi)), 2.0), mcParticle.pt()); + nCh++; + bool validGlobal = false; + bool validAny = false; + if (mcParticle.has_tracks()) { + auto const& tracks = mcParticle.tracks_as(); + for (auto const& track : tracks) { + if (track.hasTPC() && track.hasITS()) { + validGlobal = true; + } + if (track.hasTPC() || track.hasITS()) { + validAny = true; + } + } + } + // if valid global, fill + if (validGlobal) { + histos.fill(HIST("hSparseMCRecWeight"), centclass, GetPhiInRange(deltaPhi), TMath::Power(TMath::Cos(4.0 * GetPhiInRange(deltaPhi)), 1.0), mcParticle.pt(), mcParticle.eta()); + histos.fill(HIST("hSparseMCRecV2"), centclass, TMath::Cos(2.0 * GetPhiInRange(deltaPhi)), mcParticle.pt()); + histos.fill(HIST("hSparseMCRecV2Square"), centclass, TMath::Power(TMath::Cos(2.0 * GetPhiInRange(deltaPhi)), 2.0), mcParticle.pt()); + } + if (validAny) { + histos.fill(HIST("hSparseMCRecAllTrackWeight"), centclass, GetPhiInRange(deltaPhi), TMath::Power(TMath::Cos(4.0 * GetPhiInRange(deltaPhi)), 1.0), mcParticle.pt(), mcParticle.eta()); + histos.fill(HIST("hEventPlaneAngleRec"), GetPhiInRange(deltaPhi)); + } + // if any track present, fill + } + } + histos.fill(HIST("hNchVsImpactParameter"), imp, nCh); + } + PROCESS_SWITCH(phipbpb, processMCweight, "Process MC Weight", false); + + void processMCPhiWeight(CollisionMCTrueTable::iterator const& TrueCollision, CollisionMCRecTableCentFT0C const& RecCollisions, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + { + float imp = TrueCollision.impactParameter(); + float evPhi = TrueCollision.eventPlaneAngle() / 2.0; + float centclass = -999; + if (imp >= 0 && imp < 3.49) { + centclass = 2.5; + } + if (imp >= 3.49 && imp < 4.93) { + centclass = 7.5; + } + if (imp >= 4.93 && imp < 6.98) { + centclass = 15.0; + } + if (imp >= 6.98 && imp < 8.55) { + centclass = 25.0; + } + if (imp >= 8.55 && imp < 9.87) { + centclass = 35.0; + } + if (imp >= 9.87 && imp < 11) { + centclass = 45.0; + } + if (imp >= 11 && imp < 12.1) { + centclass = 55.0; + } + if (imp >= 12.1 && imp < 13.1) { + centclass = 65.0; + } + if (imp >= 13.1 && imp < 14) { + centclass = 75.0; + } + histos.fill(HIST("hImpactParameter"), imp); + histos.fill(HIST("hEventPlaneAngle"), evPhi); + if (centclass < 0.0 || centclass > 80.0) { + return; + } + for (auto& RecCollision : RecCollisions) { + auto psiFT0C = TrueCollision.eventPlaneAngle(); + /* + if (!RecCollision.sel8()) { + continue; + } + if (!RecCollision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + continue; + } + */ + if (TMath::Abs(RecCollision.posZ()) > cfgCutVertex) { + continue; + } + auto oldindex = -999; + auto Rectrackspart = RecTracks.sliceBy(perCollision, RecCollision.globalIndex()); + // loop over reconstructed particle + for (auto track1 : Rectrackspart) { + if (!track1.has_mcParticle()) { + continue; + } + + const auto mctrack1 = track1.mcParticle(); + + if (selectionTrack(track1) && selectionPIDpTdependent(track1) && TMath::Abs(mctrack1.pdgCode()) == 321 && mctrack1.isPhysicalPrimary()) { + histos.fill(HIST("hSparsePhiMCRecKaonWeight"), centclass, GetPhiInRange(mctrack1.phi() - psiFT0C), TMath::Power(TMath::Cos(4.0 * GetPhiInRange(mctrack1.phi() - psiFT0C)), 1.0), mctrack1.pt(), mctrack1.eta()); + } + + if (selectionTrack(track1) && track1.pt() > 0.5 && track1.hasTOF() && TMath::Abs(track1.tofNSigmaKa()) > nsigmaCutTOF && TMath::Abs(track1.tpcNSigmaKa()) < nsigmaCutTPC && TMath::Abs(mctrack1.pdgCode()) == 321 && mctrack1.isPhysicalPrimary()) { + histos.fill(HIST("hSparsePhiMCRecKaonMissMatchWeight"), centclass, GetPhiInRange(mctrack1.phi() - psiFT0C), TMath::Power(TMath::Cos(4.0 * GetPhiInRange(mctrack1.phi() - psiFT0C)), 1.0), mctrack1.pt(), mctrack1.eta()); + } + auto track1ID = track1.index(); + for (auto track2 : Rectrackspart) { + if (!track2.has_mcParticle()) { + continue; + } + auto track2ID = track2.index(); + if (track2ID <= track1ID) { + continue; + } + const auto mctrack2 = track2.mcParticle(); + int track1PDG = TMath::Abs(mctrack1.pdgCode()); + int track2PDG = TMath::Abs(mctrack2.pdgCode()); + if (!mctrack1.isPhysicalPrimary()) { + continue; } - if (fillRapidity) { - histos.fill(HIST("hSparseV2SASameEvent_costhetastarOP_MCGen"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_costhetastarOP_beam_MCGen"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOPbeam, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_costheta_SA_MCGen"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarOP * cosThetaStarOP, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_costhetastarIP_MCGen"), PhiMesonMother.M(), PhiMesonMother.Pt(), cosThetaStarIP, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_SA_MCGen"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_SA_A0_MCGen"), PhiMesonMother.M(), PhiMesonMother.Pt(), SA_A0, TMath::Abs(PhiMesonMother.Rapidity()), centrality); - histos.fill(HIST("hSparseV2SASameEvent_V2_MCGen"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2, centrality); + if (!mctrack2.isPhysicalPrimary()) { + continue; + } + if (!(track1PDG == 321 && track2PDG == 321)) { + continue; + } + if (!selectionTrack(track1) || !selectionTrack(track2) || track1.sign() * track2.sign() > 0) { + continue; + } + // PID check + if (ispTdepPID && !isTOFOnly && (!selectionPIDpTdependent(track1) || !selectionPIDpTdependent(track2))) { + continue; } + if (!ispTdepPID && !isTOFOnly && (!selectionPID(track1) || !selectionPID(track2))) { + continue; + } + if (isTOFOnly && (!selectionPID2(track1) || !selectionPID2(track2))) { + continue; + } + for (auto& mothertrack1 : mctrack1.mothers_as()) { + for (auto& mothertrack2 : mctrack2.mothers_as()) { + if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) { + continue; + } + if (mothertrack1 != mothertrack2) { + continue; + } + if (TMath::Abs(mothertrack1.y()) > confRapidity) { + continue; + } + if (TMath::Abs(mothertrack1.pdgCode()) != 333) { + continue; + } + // if (avoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { + if (avoidsplitrackMC && oldindex == mothertrack1.index()) { + histos.fill(HIST("h1PhiRecsplit"), mothertrack1.pt()); + continue; + } + // oldindex = mothertrack1.globalIndex(); + oldindex = mothertrack1.index(); + auto PhiMinusPsi = GetPhiInRange(mothertrack1.phi() - psiFT0C); + histos.fill(HIST("hSparsePhiMCRecWeight"), centclass, PhiMinusPsi, TMath::Power(TMath::Cos(4.0 * PhiMinusPsi), 1.0), mothertrack1.pt(), mothertrack1.eta()); + } + } + } + } + // loop over generated particle + for (auto& mcParticle : GenParticles) { + if (TMath::Abs(mcParticle.eta()) > 0.8) // main acceptance + continue; + if (TMath::Abs(mcParticle.pdgCode()) == 321 && mcParticle.isPhysicalPrimary()) { + histos.fill(HIST("hSparsePhiMCGenKaonWeight"), centclass, GetPhiInRange(mcParticle.phi() - psiFT0C), TMath::Power(TMath::Cos(4.0 * GetPhiInRange(mcParticle.phi() - psiFT0C)), 1.0), mcParticle.pt(), mcParticle.eta()); + } + if (TMath::Abs(mcParticle.y()) > confRapidity) { + continue; + } + if (mcParticle.pdgCode() != 333) { + continue; + } + auto kDaughters = mcParticle.daughters_as(); + if (kDaughters.size() != 2) { + continue; + } + auto daughtp = false; + auto daughtm = false; + for (auto kCurrentDaughter : kDaughters) { + if (!kCurrentDaughter.isPhysicalPrimary()) { + continue; + } + if (kCurrentDaughter.pdgCode() == +321) { + if (kCurrentDaughter.pt() > cfgCutPT && TMath::Abs(kCurrentDaughter.eta()) < cfgCutEta) { + daughtp = true; + } + KaonPlus = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massKa); + } else if (kCurrentDaughter.pdgCode() == -321) { + if (kCurrentDaughter.pt() > cfgCutPT && TMath::Abs(kCurrentDaughter.eta()) < cfgCutEta) { + daughtm = true; + } + KaonMinus = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massKa); + } + } + if (daughtp && daughtm) { + auto PhiMinusPsiGen = GetPhiInRange(mcParticle.phi() - psiFT0C); + histos.fill(HIST("hSparsePhiMCGenWeight"), centclass, PhiMinusPsiGen, TMath::Power(TMath::Cos(4.0 * PhiMinusPsiGen), 1.0), mcParticle.pt(), mcParticle.eta()); } } } // rec collision loop } // process MC - PROCESS_SWITCH(phipbpb, processMC, "Process MC", false); + PROCESS_SWITCH(phipbpb, processMCPhiWeight, "Process MC Phi Weight", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGLF/Tasks/Resonances/rho770analysis.cxx b/PWGLF/Tasks/Resonances/rho770analysis.cxx new file mode 100644 index 00000000000..07531afc724 --- /dev/null +++ b/PWGLF/Tasks/Resonances/rho770analysis.cxx @@ -0,0 +1,358 @@ +// 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 rho770analysis.cxx +/// \brief rho(770)0 analysis in pp 13 & 13.6 TeV +/// \author Hyunji Lim (hyunji.lim@cern.ch) +/// \since 03/12/2025 + +#include +#include +#include "TVector2.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFResonanceTables.h" +#include "CommonConstants/PhysicsConstants.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; + +struct rho770analysis { + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + using ResoMCCols = soa::Join; + + Configurable cfgMinPt{"cfgMinPt", 0.15, "Minimum transverse momentum for charged track"}; + Configurable cfgMaxEta{"cfgMaxEta", 0.8, "Maximum pseudorapidiy for charged track"}; + Configurable cfgMaxDCArToPVcut{"cfgMaxDCArToPVcut", 0.15, "Maximum transverse DCA"}; + Configurable cfgMaxDCAzToPVcut{"cfgMaxDCAzToPVcut", 2.0, "Maximum longitudinal DCA"}; + Configurable cfgMaxTPC{"cfgMaxTPC", 5.0, "Maximum TPC PID with TOF"}; + Configurable cfgMaxTOF{"cfgMaxTOF", 5.0, "Maximum TOF PID with TPC"}; + Configurable cfgMinRap{"cfgMinRap", -0.5, "Minimum rapidity for pair"}; + Configurable cfgMaxRap{"cfgMaxRap", 0.5, "Maximum rapidity for pair"}; + + // Track selection + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | + // kTPCNCls | kTPCCrossedRows | + // kTPCCrossedRowsOverNCls | + // kTPCChi2NDF | kTPCRefit | + // kITSNCls | kITSChi2NDF | + // kITSRefit | kITSHits) | + // kInAcceptanceTracks (kPtRange | + // kEtaRange) + Configurable cfgPVContributor{"cfgPVContributor", true, "PV contributor track selection"}; // PV Contriuibutor + Configurable cfgGlobalTrack{"cfgGlobalTrack", false, "Global track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgTPCcluster{"cfgTPCcluster", 0, "Number of TPC cluster"}; + Configurable cfgUseTPCRefit{"cfgUseTPCRefit", false, "Require TPC Refit"}; + Configurable cfgUseITSRefit{"cfgUseITSRefit", false, "Require ITS Refit"}; + Configurable cfgHasTOF{"cfgHasTOF", false, "Require TOF"}; + + // PID + Configurable cMaxTOFnSigmaPion{"cMaxTOFnSigmaPion", 3.0, "TOF nSigma cut for Pion"}; // TOF + Configurable cMaxTPCnSigmaPion{"cMaxTPCnSigmaPion", 5.0, "TPC nSigma cut for Pion"}; // TPC + Configurable cMaxTPCnSigmaPionnoTOF{"cMaxTPCnSigmaPionnoTOF", 2.0, "TPC nSigma cut for Pion in no TOF case"}; // TPC + Configurable nsigmaCutCombinedPion{"nsigmaCutCombinedPion", 3.0, "Combined nSigma cut for Pion"}; + Configurable selectType{"selectType", 0, "PID selection type"}; + + // Axis + ConfigurableAxis massAxis{"massAxis", {400, 0.2, 2.2}, "Invariant mass axis"}; + ConfigurableAxis massK0sAxis{"massK0sAxis", {200, 0.46, 0.54}, "K0s Invariant mass axis"}; + ConfigurableAxis massKstarAxis{"massKstarAxis", {200, 0.7, 1.1}, "Kstar Invariant mass axis"}; + ConfigurableAxis ptAxis{"ptAxis", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.8, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 10.0, 13.0, 20.0}, "Transverse momentum Binning"}; + ConfigurableAxis centAxis{"centAxis", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0, 65.0, 70.0, 75.0, 80.0, 95.0, 100.0, 105.0, 110.0}, "Centrality Binning"}; + + void init(o2::framework::InitContext&) + { + AxisSpec pidqaAxis = {120, -6, 6}; + AxisSpec pTqaAxis = {200, 0, 20}; + AxisSpec mcLabelAxis = {5, -0.5, 4.5, "MC Label"}; + + histos.add("hInvMass_rho770_US", "unlike invariant mass", {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis}}); + histos.add("hInvMass_rho770_LSpp", "++ invariant mass", {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis}}); + histos.add("hInvMass_rho770_LSmm", "-- invariant mass", {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis}}); + + histos.add("hInvMass_K0s_US", "K0s unlike invariant mass", {HistType::kTHnSparseF, {massK0sAxis, ptAxis, centAxis}}); + histos.add("hInvMass_K0s_LSpp", "K0s ++ invariant mass", {HistType::kTHnSparseF, {massK0sAxis, ptAxis, centAxis}}); + histos.add("hInvMass_K0s_LSmm", "K0s -- invariant mass", {HistType::kTHnSparseF, {massK0sAxis, ptAxis, centAxis}}); + + histos.add("hInvMass_Kstar_US", "Kstar unlike invariant mass", {HistType::kTHnSparseF, {massKstarAxis, ptAxis, centAxis}}); + histos.add("hInvMass_Kstar_LSpp", "Kstar ++ invariant mass", {HistType::kTHnSparseF, {massKstarAxis, ptAxis, centAxis}}); + histos.add("hInvMass_Kstar_LSmm", "Kstar -- invariant mass", {HistType::kTHnSparseF, {massKstarAxis, ptAxis, centAxis}}); + + histos.add("QA/Nsigma_TPC_BF", "", {HistType::kTH2F, {pTqaAxis, pidqaAxis}}); + histos.add("QA/Nsigma_TOF_BF", "", {HistType::kTH2F, {pTqaAxis, pidqaAxis}}); + histos.add("QA/TPC_TOF_BF", "", {HistType::kTH2F, {pidqaAxis, pidqaAxis}}); + + histos.add("QA/Nsigma_TPC", "", {HistType::kTH2F, {pTqaAxis, pidqaAxis}}); + histos.add("QA/Nsigma_TOF", "", {HistType::kTH2F, {pTqaAxis, pidqaAxis}}); + histos.add("QA/TPC_TOF", "", {HistType::kTH2F, {pidqaAxis, pidqaAxis}}); + + if (doprocessMCLight) { + histos.add("MCL/hpT_rho770_GEN", "generated rho770 signals", HistType::kTHnSparseF, {mcLabelAxis, massAxis, ptAxis, centAxis}); + histos.add("MCL/hpT_rho770_REC", "reconstructed rho770 signals", HistType::kTHnSparseF, {massAxis, ptAxis, centAxis}); + histos.add("MCL/hpT_omega_REC", "reconstructed omega signals", HistType::kTHnSparseF, {massAxis, ptAxis, centAxis}); + histos.add("MCL/hpT_K0s_REC", "reconstructed K0s signals", HistType::kTHnSparseF, {massAxis, ptAxis, centAxis}); + histos.add("MCL/hpT_Kstar_REC", "reconstructed Kstar signals", HistType::kTHnSparseF, {massAxis, ptAxis, centAxis}); + histos.add("MCL/hpT_K0s_pipi_REC", "reconstructed K0s signals in pipi hist", HistType::kTHnSparseF, {massK0sAxis, ptAxis, centAxis}); + histos.add("MCL/hpT_Kstar_Kpi_REC", "reconstructed rho770 signals in KK hist", HistType::kTHnSparseF, {massKstarAxis, ptAxis, centAxis}); + } + + histos.print(); + } + + double massPi = MassPionCharged; + double massKa = MassKaonCharged; + + template + bool selTrack(const TrackType track) + { + if (std::abs(track.pt()) < cfgMinPt) + return false; + if (std::fabs(track.eta()) > cfgMaxEta) + return false; + if (std::abs(track.dcaXY()) > cfgMaxDCArToPVcut) + return false; + if (std::abs(track.dcaZ()) > cfgMaxDCAzToPVcut) + return false; + if (track.tpcNClsFound() < cfgTPCcluster) + return false; + if (cfgHasTOF && !track.hasTOF()) + return false; + if (cfgUseITSRefit && !track.passedITSRefit()) + return false; + if (cfgUseTPCRefit && !track.passedTPCRefit()) + return false; + if (cfgPVContributor && !track.isPVContributor()) + return false; + if (cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (cfgGlobalTrack && !track.isGlobalTrack()) + return false; + + return true; + } + + template + bool selPion(const TrackType track) + { + if (selectType == 0) { + if (std::fabs(track.tpcNSigmaPi()) >= cMaxTPCnSigmaPion || std::fabs(track.tofNSigmaPi()) >= cMaxTOFnSigmaPion) + return false; + } + if (selectType == 1) { + if (std::fabs(track.tpcNSigmaPi()) >= cMaxTPCnSigmaPion) + return false; + } + if (selectType == 2) { + if (track.tpcNSigmaPi() * track.tpcNSigmaPi() + track.tofNSigmaPi() * track.tofNSigmaPi() >= nsigmaCutCombinedPion * nsigmaCutCombinedPion) + return false; + } + if (selectType == 3) { + if (track.hasTOF()) { + if (std::fabs(track.tpcNSigmaPi()) >= cMaxTPCnSigmaPion || std::fabs(track.tofNSigmaPi()) >= cMaxTOFnSigmaPion) + return false; + } else if (!track.hasTOF()) { + if (std::fabs(track.tpcNSigmaPi()) >= cMaxTPCnSigmaPionnoTOF) + return false; + } + } + return true; + } + + template + bool selKaon(const TrackType track) + { + if (selectType == 0) { + if (std::fabs(track.tpcNSigmaKa()) >= cMaxTPCnSigmaPion || std::fabs(track.tofNSigmaKa()) >= cMaxTOFnSigmaPion) + return false; + } + if (selectType == 1) { + if (std::fabs(track.tpcNSigmaKa()) >= cMaxTPCnSigmaPion) + return false; + } + if (selectType == 2) { + if (track.tpcNSigmaKa() * track.tpcNSigmaKa() + track.tofNSigmaKa() * track.tofNSigmaKa() >= nsigmaCutCombinedPion * nsigmaCutCombinedPion) + return false; + } + if (selectType == 3) { + if (track.hasTOF()) { + if (std::fabs(track.tpcNSigmaKa()) >= cMaxTPCnSigmaPion || std::fabs(track.tofNSigmaKa()) >= cMaxTOFnSigmaPion) + return false; + } else if (!track.hasTOF()) { + if (std::fabs(track.tpcNSigmaKa()) >= cMaxTPCnSigmaPionnoTOF) + return false; + } + } + return true; + } + + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks) + { + TLorentzVector part1, part2, reco; + for (const auto& [trk1, trk2] : combinations(CombinationsUpperIndexPolicy(dTracks, dTracks))) { + + if (trk1.index() == trk2.index()) { + histos.fill(HIST("QA/Nsigma_TPC_BF"), trk1.pt(), trk1.tpcNSigmaPi()); + histos.fill(HIST("QA/Nsigma_TOF_BF"), trk1.pt(), trk1.tofNSigmaPi()); + histos.fill(HIST("QA/TPC_TOF_BF"), trk1.tpcNSigmaPi(), trk1.tofNSigmaPi()); + + if (!selTrack(trk1)) + continue; + + histos.fill(HIST("QA/Nsigma_TPC"), trk1.pt(), trk1.tpcNSigmaPi()); + histos.fill(HIST("QA/Nsigma_TOF"), trk1.pt(), trk1.tofNSigmaPi()); + histos.fill(HIST("QA/TPC_TOF"), trk1.tpcNSigmaPi(), trk1.tofNSigmaPi()); + continue; + } + + if (!selTrack(trk1) || !selTrack(trk2)) + continue; + + if (selPion(trk1) && selPion(trk2)) { + part1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massPi); + part2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massPi); + reco = part1 + part2; + + if (reco.Rapidity() > cfgMaxRap || reco.Rapidity() < cfgMinRap) + continue; + + if (trk1.sign() * trk2.sign() < 0) { + histos.fill(HIST("hInvMass_rho770_US"), reco.M(), reco.Pt(), collision.cent()); + histos.fill(HIST("hInvMass_K0s_US"), reco.M(), reco.Pt(), collision.cent()); + + if constexpr (IsMC) { + if (trk1.motherId() != trk2.motherId()) + continue; + if (std::abs(trk1.pdgCode()) == 211 && std::abs(trk2.pdgCode()) == 211) { + if (std::abs(trk1.motherPDG()) == 113) { + histos.fill(HIST("MCL/hpT_rho770_REC"), reco.M(), reco.Pt(), collision.cent()); + } else if (std::abs(trk1.motherPDG()) == 223) { + histos.fill(HIST("MCL/hpT_omega_REC"), reco.M(), reco.Pt(), collision.cent()); + } else if (std::abs(trk1.motherPDG()) == 310) { + histos.fill(HIST("MCL/hpT_K0s_REC"), reco.M(), reco.Pt(), collision.cent()); + histos.fill(HIST("MCL/hpT_K0s_pipi_REC"), reco.M(), reco.Pt(), collision.cent()); + } + } else if ((std::abs(trk1.pdgCode()) == 211 && std::abs(trk2.pdgCode()) == 321) || (std::abs(trk1.pdgCode()) == 321 && std::abs(trk2.pdgCode()) == 211)) { + if (std::abs(trk1.motherPDG()) == 313) { + histos.fill(HIST("MCL/hpT_Kstar_REC"), reco.M(), reco.Pt(), collision.cent()); + } + } + } + } else if (trk1.sign() > 0 && trk2.sign() > 0) { + histos.fill(HIST("hInvMass_rho770_LSpp"), reco.M(), reco.Pt(), collision.cent()); + histos.fill(HIST("hInvMass_K0s_LSpp"), reco.M(), reco.Pt(), collision.cent()); + } else if (trk1.sign() < 0 && trk2.sign() < 0) { + histos.fill(HIST("hInvMass_rho770_LSmm"), reco.M(), reco.Pt(), collision.cent()); + histos.fill(HIST("hInvMass_K0s_LSmm"), reco.M(), reco.Pt(), collision.cent()); + } + } + + if ((selPion(trk1) && selKaon(trk2)) || (selKaon(trk1) && selPion(trk2))) { + if (selPion(trk1) && selKaon(trk2)) { + part1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massPi); + part2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massKa); + } else if (selKaon(trk1) && selPion(trk2)) { + part1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massKa); + part2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massPi); + } + reco = part1 + part2; + + if (reco.Rapidity() > cfgMaxRap || reco.Rapidity() < cfgMinRap) + continue; + + if (trk1.sign() * trk2.sign() < 0) { + histos.fill(HIST("hInvMass_Kstar_US"), reco.M(), reco.Pt(), collision.cent()); + + if constexpr (IsMC) { + if (trk1.motherId() != trk2.motherId()) + continue; + if ((std::abs(trk1.pdgCode()) == 211 && std::abs(trk2.pdgCode()) == 321) || (std::abs(trk1.pdgCode()) == 321 && std::abs(trk2.pdgCode()) == 211)) { + if (std::abs(trk1.motherPDG()) == 313) { + histos.fill(HIST("MCL/hpT_Kstar_Kpi_REC"), reco.M(), reco.Pt(), collision.cent()); + } + } + } + } else if (trk1.sign() > 0 && trk2.sign() > 0) { + histos.fill(HIST("hInvMass_Kstar_LSpp"), reco.M(), reco.Pt(), collision.cent()); + } else if (trk1.sign() < 0 && trk2.sign() < 0) { + histos.fill(HIST("hInvMass_Kstar_LSmm"), reco.M(), reco.Pt(), collision.cent()); + } + } + } + } + + void processData(aod::ResoCollision const& collision, aod::ResoTracks const& resotracks) + { + fillHistograms(collision, resotracks); + } + PROCESS_SWITCH(rho770analysis, processData, "Process Event for data", true); + + void processMCLight(aod::ResoCollision const& collision, soa::Join const& resotracks) + { + fillHistograms(collision, resotracks); + } + PROCESS_SWITCH(rho770analysis, processMCLight, "Process Event for MC", false); + + void processMCTrue(ResoMCCols::iterator const& collision, aod::ResoMCParents const& resoParents) + { + auto multiplicity = collision.cent(); + + for (const auto& part : resoParents) { // loop over all pre-filtered MC particles + if (std::abs(part.pdgCode()) != 113) + continue; + if (!part.producedByGenerator()) + continue; + if (part.y() < cfgMinRap || part.y() > cfgMaxRap) + continue; + if (!(std::abs(part.daughterPDG1()) == 211 && std::abs(part.daughterPDG2()) == 211)) + continue; + + TLorentzVector truthpar; + truthpar.SetPxPyPzE(part.px(), part.py(), part.pz(), part.e()); + auto mass = truthpar.M(); + + histos.fill(HIST("MCL/hpT_rho770_GEN"), 0, mass, part.pt(), multiplicity); + + if (collision.isVtxIn10()) { + histos.fill(HIST("MCL/hpT_rho770_GEN"), 1, mass, part.pt(), multiplicity); + } + if (collision.isVtxIn10() && collision.isInSel8()) { + histos.fill(HIST("MCL/hpT_rho770_GEN"), 2, mass, part.pt(), multiplicity); + } + if (collision.isVtxIn10() && collision.isTriggerTVX()) { + histos.fill(HIST("MCL/hpT_rho770_GEN"), 3, mass, part.pt(), multiplicity); + } + if (collision.isInAfterAllCuts()) { + histos.fill(HIST("MCL/hpT_rho770_GEN"), 4, mass, part.pt(), multiplicity); + } + } + }; + PROCESS_SWITCH(rho770analysis, processMCTrue, "Process Event for MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/xi1530Analysis.cxx b/PWGLF/Tasks/Resonances/xi1530Analysis.cxx index 6eb1fb9b47b..73694dda058 100644 --- a/PWGLF/Tasks/Resonances/xi1530Analysis.cxx +++ b/PWGLF/Tasks/Resonances/xi1530Analysis.cxx @@ -15,6 +15,7 @@ #include #include +#include #include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/Centrality.h" @@ -25,6 +26,7 @@ #include "PWGLF/DataModel/LFResonanceTables.h" #include "PWGLF/DataModel/LFStrangenessTables.h" #include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/RecoDecay.h" using namespace o2; using namespace o2::framework; @@ -47,45 +49,88 @@ struct cascadeXiAnalysis { Configurable cGlobalWoDCATrack{"cGlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) Configurable cPVContributor{"cPVContributor", true, "PV contributor track selection"}; // PV Contriuibutor - // PID Pions - Configurable cMaxTpcNsigmaPi{"cMaxTpcNsigmaPi", 3.0, "Max TPCNsigma Pions"}; - Configurable cMaxTofNsigmaPi{"cMaxTofNsigmaPi", 3.0, "Max TOFNsigma Pions"}; + // Kinematics cuts + Configurable cKinCuts{"cKinCuts", true, "Kinematic Cuts for p-K pair opening angle"}; + Configurable> cKinCutsPt{"cKinCutsPt", {0.0, 0.4, 0.6, 0.8, 1.0, 1.4, 1.8, 2.2, 2.6, 3.0, 4.0, 5.0, 6.0, 1e10}, "p_{T} of L* for kinematic cuts"}; + Configurable> cKinLowerCutsAlpha{"cKinLowerCutsAlpha", {1.5, 1.0, 0.5, 0.3, 0.2, 0.15, 0.1, 0.08, 0.07, 0.06, 0.04, 0.02}, "Lower cut on Opening angle of p-K of L*"}; + Configurable> cKinUpperCutsAlpha{"cKinUpperCutsAlpha", {3.0, 2.0, 1.5, 1.4, 1.0, 0.8, 0.6, 0.5, 0.45, 0.35, 0.3, 0.25, 0.2}, "Upper cut on Opening angle of p-K of L*"}; + + // PID Selections + Configurable cUseOnlyTOFTrackPi{"cUseOnlyTOFTrackPi", false, "Use only TOF track for PID selection"}; // Use only TOF track for Pion PID selection + Configurable cUseTpcOnly{"cUseTpcOnly", false, "Use TPC Only selection"}; // TPC only tracks + Configurable cRejNsigmaTpc{"cRejNsigmaTpc", 3.0, "Reject tracks to improve purity of TPC PID"}; // Reject missidentified particles when tpc bands merge + Configurable cRejNsigmaTof{"cRejNsigmaTof", 3.0, "Reject tracks to improve purity of TOF PID"}; // Reject missidentified particles when tpc bands merge + // Pion + Configurable cMaxTPCnSigmaPion{"cMaxTPCnSigmaPion", 4.0, "TPC nSigma cut for Pion"}; // TPC + Configurable cMaxTOFnSigmaPion{"cMaxTOFnSigmaPion", 3.0, "TOF nSigma cut for Pion"}; // TOF + Configurable nsigmaCutCombinedPion{"nsigmaCutCombinedPion", 3.0, "Combined nSigma cut for Pion"}; // Combined + Configurable> pionTPCPIDp{"pionTPCPIDp", {0.15, 0.3, 0.35, 0.40, 0.54}, "p dependent TPC cuts Pions"}; + Configurable> pionTPCPIDcut{"pionTPCPIDcut", {5., 4., 3., 2.}, "TPC nsigma cuts protons"}; // Histogram Registry. HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext const&) { - const AxisSpec axisP(400, 0, 4, "p (GeV/#it{c})"); + const AxisSpec axisCent(105, 0, 105, "FT0M (%)"); + const AxisSpec axisP_pid(600, 0., 6., "p (GeV/c)"); + const AxisSpec axisPt_pid(600, 0., 6., "p_{T} (GeV/c)"); + const AxisSpec axisDCAz(500, -0.5, 0.5, {"DCA_{z} (cm)"}); + const AxisSpec axisDCAxy(240, -0.12, 0.12, {"DCA_{xy} (cm)"}); + const AxisSpec axisTPCNsigma(401, -10.025, 10.025, {"n#sigma^{TPC}"}); + const AxisSpec axisTOFNsigma(401, -10.025, 10.025, {"n#sigma^{TOF}"}); + const AxisSpec axisdEdx(380, 10, 200, {"#frac{dE}{dx}"}); const AxisSpec axisTpcNsigma(401, -10.025, 10.025, "n#sigma(TPC)"); const AxisSpec axisTofNsigma(401, -10.025, 10.025, "n#sigma(TOF)"); const AxisSpec axisXiMass(3000, 0., 3., "Inv Mass (GeV/#it{c}^{2})"); const AxisSpec axisRadius(1000, 0, 100, "r(cm)"); - const AxisSpec axisCosPA(1000, 0.90, 1.1, "cos(#theta_{PA})(rad)"); - const AxisSpec axisDca(1000, -10., 10., "dca (cm)"); - const AxisSpec axisDcaDau(1000, 0., 10., "Daug DCA (cm^{2})"); - const AxisSpec axisLambdaMass(1000, 0., 10., "Inv Mass (GeV/#it{c}^{2})"); + const AxisSpec axisCosPA(60, 0.95, 1.01, "cos(#theta_{PA})(rad)"); + const AxisSpec axisDca(200, -10., 10., "dca (cm)"); + const AxisSpec axisDcaDau(100, 0., 10., "Daug DCA (cm^{2})"); + const AxisSpec axisLambdaMass(400, 1.24, 1.64, "Inv Mass (GeV/#it{c}^{2})"); + const AxisSpec axisAlpha(200, 0 - 0.15, 2 * TMath::Pi() + 0.15, "#alpha"); const AxisSpec axisPtXiStar(500, 0, 10, "p_{T} (GeV/#it{c})"); const AxisSpec axisInvMassXiStar(400, 1.4, 1.8, "m_{#Xi#pi} (GeV/#it{c}^{2})"); - histos.add("QA/CascXi/h1d_mass_Xi", "#Xi^{+} mass", kTH1F, {axisXiMass}); - histos.add("QA/CascXi/h1d_v0_radius", "V0 Radius", kTH1F, {axisRadius}); - histos.add("QA/CascXi/h1d_casc_radius", "Cascade Radius", kTH1F, {axisRadius}); - histos.add("QA/CascXi/h1d_v0_cosPA", "V0 Cosine of PA", kTH1F, {axisCosPA}); - histos.add("QA/CascXi/h1d_casc_cosPA", "Casc Cosine of PA", kTH1F, {axisCosPA}); - histos.add("QA/CascXi/h1d_dca_postoPV", "DCA Positive to PV", kTH1F, {axisDca}); - histos.add("QA/CascXi/h1d_dca_negtoPV", "DCA Negative to PV", kTH1F, {axisDca}); - histos.add("QA/CascXi/h1d_dca_bachtoPV", "DCA Bachelor to PV", kTH1F, {axisDca}); - histos.add("QA/CascXi/h1d_dca_v0toPV", "DCA V0 to PV", kTH1F, {axisDca}); - histos.add("QA/CascXi/h1d_dca_v0_dau", "DCA V0 Daughter", kTH1F, {axisDcaDau}); - histos.add("QA/CascXi/h1d_dca_casc_dau", "DCA Cascade Daughter", kTH1F, {axisDcaDau}); - histos.add("QA/Pions/h2d_pi_tpc_nsigma_vs_p", "Pions", kTH2D, {axisP, axisTpcNsigma}); - histos.add("QA/Pions/h2d_pi_tof_nsigma_vs_p", "Pions", kTH2D, {axisP, axisTofNsigma}); - histos.add("QA/Pions/h2d_pi_nsigma_tof_vs_tpc", "Pions", kTH2D, {axisTpcNsigma, axisTofNsigma}); + // Create Histograms. + // Event + histos.add("Event/h1d_ft0m_mult_percentile", "FT0M (%)", kTH1F, {axisCent}); + + // QA Pions + histos.add("QA_Bach_Pi/h2d_pi_dca_z", "Pions", kTH2F, {axisPt_pid, axisDCAz}); + histos.add("QA_Bach_Pi/h2d_pi_dca_xy", "Pions", kTH2F, {axisPt_pid, axisDCAxy}); + histos.add("QA_Bach_Pi/h2d_pi_dEdx_p", "TPC Signal Pion", kTH2F, {axisP_pid, axisdEdx}); + histos.add("QA_Bach_Pi/h2d_pi_nsigma_tpc_pt", "Pions", kTH2F, {axisPt_pid, axisTPCNsigma}); + histos.add("QA_Bach_Pi/h2d_pi_nsigma_tpc_p", "Pions", kTH2F, {axisP_pid, axisTPCNsigma}); + histos.add("QA_Bach_Pi/h2d_pi_nsigma_tof_pt", "Pions", kTH2F, {axisPt_pid, axisTOFNsigma}); + histos.add("QA_Bach_Pi/h2d_pi_nsigma_tof_p", "Pions", kTH2F, {axisP_pid, axisTOFNsigma}); + histos.add("QA_Bach_Pi/h2d_pi_nsigma_tof_vs_tpc", "n#sigma(TOF) vs n#sigma(TPC) Pions", kTH2F, {axisTPCNsigma, axisTOFNsigma}); + + // QA checks for Pions + histos.add("QA_Checks/h1d_pi_pt", "p_{T}-spectra Pions", kTH1F, {axisPt_pid}); + + // QA Xi + histos.add("QA_Casc_Xi/h1d_mass_Xi", "#Xi^{+} mass", kTH1F, {axisXiMass}); + histos.add("QA_Casc_Xi/h1d_v0_radius", "V0 Radius", kTH1F, {axisRadius}); + histos.add("QA_Casc_Xi/h1d_casc_radius", "Cascade Radius", kTH1F, {axisRadius}); + histos.add("QA_Casc_Xi/h1d_v0_cosPA", "V0 Cosine of PA", kTH1F, {axisCosPA}); + histos.add("QA_Casc_Xi/h1d_casc_cosPA", "Casc Cosine of PA", kTH1F, {axisCosPA}); + histos.add("QA_Casc_Xi/h1d_dca_postoPV", "DCA Positive to PV", kTH1F, {axisDca}); + histos.add("QA_Casc_Xi/h1d_dca_negtoPV", "DCA Negative to PV", kTH1F, {axisDca}); + histos.add("QA_Casc_Xi/h1d_dca_bachtoPV", "DCA Bachelor to PV", kTH1F, {axisDca}); + histos.add("QA_Casc_Xi/h1d_dca_v0toPV", "DCA V0 to PV", kTH1F, {axisDca}); + histos.add("QA_Casc_Xi/h1d_dca_v0_dau", "DCA V0 Daughter", kTH1F, {axisDcaDau}); + histos.add("QA_Casc_Xi/h1d_dca_casc_dau", "DCA Cascade Daughter", kTH1F, {axisDcaDau}); + + // QA Kinematic Cuts + histos.add("QA_Checks/h2d_xistar_alpha_vs_pt", "#alpha_{oa} vs p_{T} Before Cuts", kTH2F, {axisPtXiStar, axisAlpha}); + histos.add("QA_Checks/h2d_sel_kincuts_xistar_alpha_vs_pt", "#alpha_{oa} vs p_{T} After Cuts", kTH2F, {axisPtXiStar, axisAlpha}); + + // Invariant Mass Analysis histos.add("Analysis/h1d_mass_Xistar", "Inv Mass Xi(1530)", kTH1D, {axisInvMassXiStar}); - histos.add("Analysis/h2d_mass_vs_pt_Xistar", "Xi(1530)", kTH2D, {axisInvMassXiStar, axisPtXiStar}); + histos.add("Analysis/h3d_mass_vs_pt_Xistar", "Xi(1530)", kTHnSparseD, {axisInvMassXiStar, axisPtXiStar, axisCent}); histos.add("Analysis/h1d_mass_Xistar_LS", "Inv Mass Xi(1530)", kTH1D, {axisInvMassXiStar}); - histos.add("Analysis/h2d_mass_vs_pt_Xistar_LS", "Xi(1530)", kTH2D, {axisInvMassXiStar, axisPtXiStar}); + histos.add("Analysis/h3d_mass_vs_pt_Xistar_LS", "Xi(1530)", kTHnSparseD, {axisInvMassXiStar, axisPtXiStar, axisCent}); } template @@ -116,80 +161,162 @@ struct cascadeXiAnalysis { return true; } - template - bool selPIDPions(trackType const& track) + template + bool selectionPIDPions(const T& candidate) { - bool tpcPIDselFlag{false}, tofPIDselFlag{false}; - - float tpcNsigmaPi = std::abs(track.tpcNSigmaPi()); - float tofNsigmaPi = std::abs(track.tofNSigmaPi()); - - if (track.hasTOF()) { - if (tofNsigmaPi < cMaxTofNsigmaPi) { - tofPIDselFlag = true; + bool tpcPIDPassed{false}, tofPIDPassed{false}; + auto tpcPIDp = static_cast>(pionTPCPIDp); + auto tpcPIDcut = static_cast>(pionTPCPIDcut); + int nitr = static_cast(tpcPIDp.size()); + float p = RecoDecay::p(candidate.px(), candidate.py(), candidate.pz()); + + float tpcNsigmaPi = std::abs(candidate.tpcNSigmaPi()); + float tpcNsigmaKa = std::abs(candidate.tpcNSigmaKa()); + float tpcNsigmaPr = std::abs(candidate.tpcNSigmaPr()); + float tofNsigmaPi = std::abs(candidate.tofNSigmaPi()); + float tofNsigmaKa = std::abs(candidate.tofNSigmaKa()); + float tofNsigmaPr = std::abs(candidate.tofNSigmaPr()); + + float tpcTofNsigmaPi = tpcNsigmaPi * tpcNsigmaPi + tofNsigmaPi * tofNsigmaPi; + float tpcTofNsigmaKa = tpcNsigmaKa * tpcNsigmaKa + tofNsigmaKa * tofNsigmaKa; + float tpcTofNsigmaPr = tpcNsigmaPr * tpcNsigmaPr + tofNsigmaPr * tofNsigmaPr; + float combinedCut = nsigmaCutCombinedPion * nsigmaCutCombinedPion; + float combinedRejCut = cRejNsigmaTof * cRejNsigmaTpc; + + if (!cUseTpcOnly && candidate.hasTOF()) { + if (tofNsigmaPi < cMaxTOFnSigmaPion && tofNsigmaPr > cRejNsigmaTof && tofNsigmaKa > cRejNsigmaTof) { + tofPIDPassed = true; } - if (tpcNsigmaPi < cMaxTpcNsigmaPi) { - tpcPIDselFlag = true; + // square cut + if ((nsigmaCutCombinedPion < 0) && (tpcNsigmaPi < cMaxTPCnSigmaPion)) { + tpcPIDPassed = true; + } + // circular cut + if ((nsigmaCutCombinedPion > 0) && (tpcTofNsigmaPi < combinedCut && tpcTofNsigmaPr > combinedRejCut && tpcTofNsigmaKa > combinedRejCut)) { + tofPIDPassed = true; + tpcPIDPassed = true; } } else { - tofPIDselFlag = true; - if (tpcNsigmaPi < cMaxTofNsigmaPi) { - tpcPIDselFlag = true; + tofPIDPassed = true; + if (cUseTpcOnly) { + if (tpcNsigmaPi < cMaxTPCnSigmaPion && tpcNsigmaPr > cRejNsigmaTpc && tpcNsigmaKa > cRejNsigmaTpc) { + tpcPIDPassed = true; + } + } else { + for (int i = 0; i < nitr - 1; ++i) { + if (p >= tpcPIDp[i] && p < tpcPIDp[i + 1] && (tpcNsigmaPi < tpcPIDcut[i] && tpcNsigmaPr > cRejNsigmaTpc && tpcNsigmaKa > cRejNsigmaTpc)) { + tpcPIDPassed = true; + } + } + if (tpcPIDPassed && ((tpcNsigmaPi > tpcNsigmaKa) || (tpcNsigmaPi > tpcNsigmaPr))) { + tpcPIDPassed = false; + } } } - if (tofPIDselFlag && tpcPIDselFlag) { + if (tpcPIDPassed && tofPIDPassed) { return true; } return false; } + // kinematic cuts method + template + bool kinCuts(U trk1, K trk2, T p, float& alpha) + { + // initialize + std::vector kinCutsPt = static_cast>(cKinCutsPt); + std::vector kinLowerCutsAlpha = static_cast>(cKinLowerCutsAlpha); + std::vector kinUpperCutsAlpha = static_cast>(cKinUpperCutsAlpha); + int kinCutsSize = static_cast(kinUpperCutsAlpha.size()); + + TVector3 v1(trk1.px(), trk1.py(), trk1.pz()); + TVector3 v2(trk2.px(), trk2.py(), trk2.pz()); + alpha = v1.Angle(v2); + + for (int i = 0; i < kinCutsSize; ++i) { + if ((p.Pt() > kinCutsPt[i] && p.Pt() <= kinCutsPt[i + 1]) && (alpha < kinLowerCutsAlpha[i] || alpha > kinUpperCutsAlpha[i])) { + return false; + } + } + + return true; + } + + template + void fillPionQAHistos(T const& track) + { + + float p = RecoDecay::p(track.px(), track.py(), track.pz()); + + // select particle (Pion) + if (selectionPIDPions(track)) { + histos.fill(HIST("QA_Checks/h1d_pi_pt"), track.pt()); + histos.fill(HIST("QA_Bach_Pi/h2d_pi_dca_z"), track.pt(), track.dcaZ()); + histos.fill(HIST("QA_Bach_Pi/h2d_pi_dca_xy"), track.pt(), track.dcaXY()); + histos.fill(HIST("QA_Bach_Pi/h2d_pi_dEdx_p"), p, track.tpcSignal()); + histos.fill(HIST("QA_Bach_Pi/h2d_pi_nsigma_tpc_p"), p, track.tpcNSigmaPi()); + histos.fill(HIST("QA_Bach_Pi/h2d_pi_nsigma_tpc_pt"), track.pt(), track.tpcNSigmaPi()); + if (!cUseTpcOnly && track.hasTOF()) { + histos.fill(HIST("QA_Bach_Pi/h2d_pi_nsigma_tof_p"), p, track.tofNSigmaPi()); + histos.fill(HIST("QA_Bach_Pi/h2d_pi_nsigma_tof_pt"), track.pt(), track.tofNSigmaPi()); + histos.fill(HIST("QA_Bach_Pi/h2d_pi_nsigma_tof_vs_tpc"), track.tpcNSigmaPi(), track.tofNSigmaPi()); + } + } + } + template - void fillDataHisto(trackType const& bachTrks, cascType const& cascTrks, const float /*cent*/) + void fillDataHisto(cascType const& cascTrks, trackType const& bachTrks, float cent_class) { TLorentzVector p1, p2, p; - float pi_p_tot = 0; - // trk1 -> pi - // trk2 -> Xi + + // trk1 -> Xi | trk2 -> pi for (auto const& [trk1, trk2] : soa::combinations(soa::CombinationsFullIndexPolicy(cascTrks, bachTrks))) { - if (trk1.index() == trk2.index()) { - continue; - } - // select primary pions (one of the decay daughter of Xi*) + // // do not analyze same index tracks + // if (trk1.index() == trk2.index()) { + // continue; + // } + + // select primary tracks for Pion selection if (!selBachTracks(trk2)) { continue; } - if (!selPIDPions(trk2)) { + // Apply Pion PID + if (!selectionPIDPions(trk2)) { continue; } - pi_p_tot = TMath::Sqrt(trk2.px() * trk2.px() + trk2.py() * trk2.py() + trk2.pz() * trk2.pz()); - - // fill QA for pion selection - if constexpr (!mix) { - histos.fill(HIST("QA/Pions/h2d_pi_tpc_nsigma_vs_p"), pi_p_tot, trk2.tpcNSigmaPi()); - if (trk2.hasTOF()) { - histos.fill(HIST("QA/Pions/h2d_pi_tof_nsigma_vs_p"), pi_p_tot, trk2.tofNSigmaPi()); - histos.fill(HIST("QA/Pions/h2d_pi_nsigma_tof_vs_tpc"), trk2.tpcNSigmaPi(), trk2.tofNSigmaPi()); - } - } - // Make Lorentz 4-vector p1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), trk1.mXi()); p2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), MassPionCharged); p = p1 + p2; + // Get the opening angle b/w Xi and Pion and kinematic cut flag. + float alpha = 0; + bool kinCutFlag{true}; + if (cKinCuts) { + kinCutFlag = kinCuts(trk1, trk2, p, alpha); + if constexpr (!mix && !mc) { + histos.fill(HIST("QA_Checks/h2d_xistar_alpha_vs_pt"), p.Pt(), alpha); + } + } + + // apply kincuts + if (cKinCuts && !kinCutFlag) { + continue; + } + if (std::abs(p.Rapidity()) > 0.5) continue; if constexpr (!mix && !mc) { if (trk1.sign() * trk2.sign() < 0) { histos.fill(HIST("Analysis/h1d_mass_Xistar"), p.M()); - histos.fill(HIST("Analysis/h2d_mass_vs_pt_Xistar"), p.M(), p.Pt()); + histos.fill(HIST("Analysis/h3d_mass_vs_pt_Xistar"), p.M(), p.Pt(), cent_class); } else { histos.fill(HIST("Analysis/h1d_mass_Xistar_LS"), p.M()); - histos.fill(HIST("Analysis/h2d_mass_vs_pt_Xistar_LS"), p.M(), p.Pt()); + histos.fill(HIST("Analysis/h3d_mass_vs_pt_Xistar_LS"), p.M(), p.Pt(), cent_class); } } } @@ -197,28 +324,38 @@ struct cascadeXiAnalysis { void process(aod::ResoCollisions::iterator const& resoCollision, aod::ResoCascades const& cascTracks, aod::ResoTracks const& resoTracks) { - fillDataHisto(resoTracks, cascTracks, resoCollision.cent()); - } - void processReso(aod::ResoCollisions::iterator const& /*col*/, aod::ResoCascades const& cascTracks) - { + histos.fill(HIST("Event/h1d_ft0m_mult_percentile"), resoCollision.cent()); + // QA for pion + for (auto const& track : resoTracks) { + + // apply primary selection + if (!selBachTracks(track)) { + continue; + } + + // QA histos + fillPionQAHistos(track); + } + + // QA Xi for (auto const& casc : cascTracks) { - histos.fill(HIST("QA/CascXi/h1d_mass_Xi"), casc.mXi()); - histos.fill(HIST("QA/CascXi/h1d_v0_radius"), casc.transRadius()); - histos.fill(HIST("QA/CascXi/h1d_casc_radius"), casc.casctransRadius()); - histos.fill(HIST("QA/CascXi/h1d_v0_cosPA"), casc.v0CosPA()); - histos.fill(HIST("QA/CascXi/h1d_casc_cosPA"), casc.cascCosPA()); - histos.fill(HIST("QA/CascXi/h1d_dca_postoPV"), casc.dcapostopv()); - histos.fill(HIST("QA/CascXi/h1d_dca_negtoPV"), casc.dcanegtopv()); - histos.fill(HIST("QA/CascXi/h1d_dca_bachtoPV"), casc.dcabachtopv()); - histos.fill(HIST("QA/CascXi/h1d_dca_v0toPV"), casc.dcav0topv()); - histos.fill(HIST("QA/CascXi/h1d_dca_v0_dau"), casc.daughDCA()); - histos.fill(HIST("QA/CascXi/h1d_dca_casc_dau"), casc.cascdaughDCA()); + histos.fill(HIST("QA_Casc_Xi/h1d_mass_Xi"), casc.mXi()); + histos.fill(HIST("QA_Casc_Xi/h1d_v0_radius"), casc.transRadius()); + histos.fill(HIST("QA_Casc_Xi/h1d_casc_radius"), casc.cascTransRadius()); + histos.fill(HIST("QA_Casc_Xi/h1d_v0_cosPA"), casc.v0CosPA()); + histos.fill(HIST("QA_Casc_Xi/h1d_casc_cosPA"), casc.cascCosPA()); + histos.fill(HIST("QA_Casc_Xi/h1d_dca_postoPV"), casc.dcapostopv()); + histos.fill(HIST("QA_Casc_Xi/h1d_dca_negtoPV"), casc.dcanegtopv()); + histos.fill(HIST("QA_Casc_Xi/h1d_dca_bachtoPV"), casc.dcabachtopv()); + histos.fill(HIST("QA_Casc_Xi/h1d_dca_v0toPV"), casc.dcav0topv()); + histos.fill(HIST("QA_Casc_Xi/h1d_dca_v0_dau"), casc.daughDCA()); + histos.fill(HIST("QA_Casc_Xi/h1d_dca_casc_dau"), casc.cascDaughDCA()); } - } - PROCESS_SWITCH(cascadeXiAnalysis, processReso, "ResoProcess", false); + fillDataHisto(cascTracks, resoTracks, resoCollision.cent()); + } }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Resonances/xi1530Analysisqa.cxx b/PWGLF/Tasks/Resonances/xi1530Analysisqa.cxx new file mode 100755 index 00000000000..2361457f620 --- /dev/null +++ b/PWGLF/Tasks/Resonances/xi1530Analysisqa.cxx @@ -0,0 +1,1139 @@ +// 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 xi1530Analysisqa.cxx +/// \brief Reconstruction of Xi* resonance. +/// +/// \author Min-jae Kim , Bong-Hwi Lim +#include +#include "TF1.h" +#include "TRandom3.h" + +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFResonanceTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/RecoDecay.h" +#include "Framework/O2DatabasePDGPlugin.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; +// Service pdgDB; + +enum { + kData = 0, + kLS, + kMixing, + kMCReco, + kMCTrue, + kMCTruePS, + kINEL10, + kINELg010, + kAllType, + kXiStar = 3324 +}; + +struct Xi1530Analysisqa { + + // Basic set-up // + SliceCache cache; + // Preslice perRCol = aod::resodaughter::resoCollisionId; + // Preslice perCollision = aod::track::collisionId; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + using ResoMCCols = soa::Join; + Configurable cMassXiminus{"cMassXiminus", 1.32171, "Mass of Xi baryon"}; + + // Associated with histograms + ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12.0, 12.1, 12.2, 12.3, 12.4, 12.5, 12.6, 12.7, 12.8, 12.9, 13.0, 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7, 13.8, 13.9, 14.0, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15.0}, "Binning of the pT axis"}; + ConfigurableAxis binsPtQA{"binsPtQA", {VARIABLE_WIDTH, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2, 6.4, 6.6, 6.8, 7.0, 7.2, 7.4, 7.6, 7.8, 8.0, 8.2, 8.4, 8.6, 8.8, 9.0, 9.2, 9.4, 9.6, 9.8, 10.0}, "Binning of the pT axis"}; + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0}, "Binning of the centrality axis"}; + + Configurable cInvMassStart{"cInvMassStart", 1.4, "Invariant mass start"}; + Configurable cInvMassEnd{"cInvMassEnd", 3.0, "Invariant mass end"}; + Configurable cInvMassBins{"cInvMassBins", 800, "Invariant mass binning"}; + + Configurable invMass1D{"invMass1D", true, "Invariant mass 1D"}; + Configurable studyAntiparticle{"studyAntiparticle", true, "Study anti-particles separately"}; + Configurable pidPlots{"pidPlots", true, "Make TPC and TOF PID plots"}; + + Configurable additionalQAplots{"additionalQAplots", true, "Additional QA plots"}; + Configurable additionalQAeventPlots{"additionalQAeventPlots", true, "Additional QA event plots"}; + Configurable additionalMEPlots{"additionalMEPlots", true, "Additional Mixed event plots"}; + + // Event Mixing + Configurable nEvtMixing{"nEvtMixing", 10, "Number of events to mix"}; + ConfigurableAxis cfgVtxBins{"cfgVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis cfgMultBins{"cfgMultBins", {VARIABLE_WIDTH, 0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Mixing bins - z-vertex"}; + + //*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*// + + // Track selections (Except DCA selelctions) // + + // Primary track selections + Configurable cMinPtcut{"cMinPtcut", 0.15, "Track minium pt cut"}; + Configurable cMaxetacut{"cMaxetacut", 0.8, "Track maximum eta cut"}; + + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; + Configurable cfgPVContributor{"cfgPVContributor", true, "PV contributor track selection"}; + + Configurable tofAtHighPt{"tofAtHighPt", false, "Use TOF at high pT"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 1, "Minimum Number of TPC cluster"}; // Minmimum + + Configurable cfgTPCRows{"cfgTPCRows", 70, "Minimum Number of TPC Crossed Rows "}; + Configurable cfgRatioTPCRowsOverFindableCls{"cfgRatioTPCRowsOverFindableCls", 0.8, "Minimum of TPC Crossed Rows to Findable Clusters"}; // Minmimum + + Configurable cfgUseTPCRefit{"cfgUseTPCRefit", true, "Require TPC Refit"}; + Configurable cfgUseITSRefit{"cfgUseITSRefit", true, "Require ITS Refit"}; + + Configurable cfgHasTOF{"cfgHasTOF", false, "Require TOF"}; + + Configurable cfgRapidityCut{"cfgRapidityCut", 0.5, "Rapidity cut for tracks"}; + + //*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*// + + // Cascade and V0 selections // + + // Primary track DCAxy to PV + Configurable cDCAxytoPVByPtPiFirstP0{"cDCAxytoPVByPtPiFirstP0", 0.004, "Coeff. Track DCAxy cut to PV by pt for Pion First (p0)"}; + Configurable cDCAxyToPVByPtPiFirstExp{"cDCAxyToPVByPtPiFirstExp", 0.013, "Coeff. Track DCAxy cut to PV by pt for Pion First (exp)"}; + + Configurable cDCAxyToPVAsPtForCasc{"cDCAxyToPVAsPtForCasc", true, "Set DCAxy to PV selection as pt cut"}; + Configurable cDCAxyToPVByPtCascP0{"cDCAxyToPVByPtCascP0", 999., "Coeff. for Track DCAxy cut to PV by pt for Cascade (p0)"}; + Configurable cDCAxyToPVByPtCascExp{"cDCAxyToPVByPtCascExp", 1., "Coeff. Track DCAxy cut to PV by pt for Cascade (exp)"}; + + // Primary track DCAz to PV + Configurable cDCAzToPVAsPt{"cDCAzToPVAsPt", true, "DCAz to PV selection as pt"}; + Configurable cDCAzToPVAsPtForCasc{"cDCAzToPVAsPtForCasc", true, "Set DCA to PV selection as pt cut"}; + Configurable cMaxDCAzToPVCut{"cMaxDCAzToPVCut", 0.5, "Track DCAz cut to PV Maximum"}; + Configurable cMaxDCAzToPVCutCasc{"cMaxDCAzToPVCutCasc", 0.5, "Track DCAz cut to PV Maximum for casc"}; + + // Topological selections for V0 + Configurable cDCALambdaDaugtherscut{"cDCALambdaDaugtherscut", 0.7, "Lambda dauthers DCA cut"}; + Configurable cDCALambdaToPVcut{"cDCALambdaToPVcut", 0.02, "Lambda DCA cut to PV"}; + Configurable cDCAPionToPVcut{"cDCAPionToPVcut", 0.06, "pion DCA cut to PV"}; + Configurable cDCAProtonToPVcut{"cDCAProtonToPVcut", 0.07, "proton DCA cut to PV"}; + + Configurable cV0CosPACutPtDepP0{"cV0CosPACutPtDepP0", 0.25, "Coeff. for Cosine Pointing angle for V0 as pt (p0)"}; + Configurable cV0CosPACutPtDepP1{"cV0CosPACutPtDepP1", 0.022, "Coeff. for Cosine Pointing angle for V0 as pt (p1)"}; + + Configurable cMaxV0radiuscut{"cMaxV0radiuscut", 200., "V0 radius cut Maximum"}; + Configurable cMinV0radiuscut{"cMinV0radiuscut", 2.5, "V0 radius cut Minimum"}; + Configurable cMasswindowV0cut{"cMasswindowV0cut", 0.005, "V0 Mass window cut"}; + + // Topological selections for Cascade + + Configurable cDCABachlorToPVcut{"cDCABachlorToPVcut", 0.06, "Bachelor DCA cut to PV"}; + Configurable cDCAXiDaugthersCutPtRangeLower{"cDCAXiDaugthersCutPtRangeLower", 1., "Xi- DCA cut to PV as pt range lower"}; + Configurable cDCAXiDaugthersCutPtRangeUpper{"cDCAXiDaugthersCutPtRangeUpper", 4., "Xi- DCA cut to PV as pt range upper"}; + Configurable cDCAXiDaugthersCutPtDepLower{"cDCAXiDaugthersCutPtDepLower", 0.8, "Xi- DCA cut to PV as pt Under 1 GeV/c"}; + Configurable cDCAXiDaugthersCutPtDepMiddle{"cDCAXiDaugthersCutPtDepMiddle", 0.5, "Xi- DCA cut to PV as pt 1 - 4 GeV/c"}; + Configurable cDCAXiDaugthersCutPtDepUpper{"cDCAXiDaugthersCutPtDepUpper", 0.2, "Xi- DCA cut to PV as pt Over 4 GeV/c"}; + + Configurable cCosPACascCutPtDepP0{"cCosPACascCutPtDepP0", 0.2, "Coeff. for Cosine Pointing angle for Cascade as pt (p0)"}; + Configurable cCosPACascCutPtDepP1{"cCosPACascCutPtDepP1", 0.022, "Coeff. for Cosine Pointing angle for Cascade as pt (p1)"}; + + Configurable cMaxCascradiuscut{"cMaxCascradiuscut", 200., "Cascade radius cut Maximum"}; + Configurable cMinCascradiuscut{"cMinCascradiuscut", 1.1, "Cascade radius cut Minimum"}; + Configurable cMasswindowCasccut{"cMasswindowCasccut", 0.008, "Cascade Mass window cut"}; + + //*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*// + + // PID Selections// + + Configurable cPIDBound{"cPIDBound", 6.349, "configurable for replacing to .has"}; + + // PID Selections for Pion First + Configurable cMaxtpcnSigmaPionFirst{"cMaxtpcnSigmaPionFirst", 4.0, "TPC nSigma cut for Pion First"}; + Configurable cMaxtofnSigmaPionFirst{"cMaxtofnSigmaPionFirst", 3.0, "TOF nSigma cut for Pion First"}; + + Configurable nsigmaCutCombinedPionFirst{"nsigmaCutCombinedPionFirst", -4.0, "Combined nSigma cut for Pion First"}; + + Configurable cUseOnlyTOFTrackPionFirst{"cUseOnlyTOFTrackPionFirst", false, "Use only TOF track for PID selection Pion First"}; + Configurable cByPassTOFPionFirst{"cByPassTOFPionFirst", true, "By pass TOF Pion First PID selection"}; + + // PID Selections for Pion Bachelor + Configurable cMaxtpcnSigmaPionBachelor{"cMaxtpcnSigmaPionBachelor", 4.0, "TPC nSigma cut for Pion Bachelor"}; + Configurable cMaxtofnSigmaPionBachelor{"cMaxtofnSigmaPionBachelor", 3.0, "TOF nSigma cut for Pion Bachelor"}; + + Configurable nsigmaCutCombinedPionBachelor{"nsigmaCutCombinedPionBachelor", -4.0, "Combined nSigma cut for Pion Bachelor"}; + + Configurable cUseOnlyTOFTrackPionBachelor{"cUseOnlyTOFTrackPionBachelor", false, "Use only TOF track for PID selection Pion Bachelor"}; + Configurable cByPassTOFPionBachelor{"cByPassTOFPionBachelor", true, "By pass TOF Pion Bachelor PID selection"}; + + // PID Selections for Pion + Configurable cMaxtpcnSigmaPion{"cMaxtpcnSigmaPion", 4.0, "TPC nSigma cut for Pion"}; + Configurable cMaxtofnSigmaPion{"cMaxtofnSigmaPion", 3.0, "TOF nSigma cut for Pion"}; + + Configurable nsigmaCutCombinedPion{"nsigmaCutCombinedPion", -4.0, "Combined nSigma cut for Pion"}; + + Configurable cUseOnlyTOFTrackPion{"cUseOnlyTOFTrackPion", false, "Use only TOF track for PID selection Pion"}; + Configurable cByPassTOFPion{"cByPassTOFPion", true, "By pass TOF Pion PID selection"}; + + // PID Selections for Proton + Configurable cMaxtpcnSigmaProton{"cMaxtpcnSigmaProton", 4.0, "TPC nSigma cut for Proton"}; + Configurable cMaxtofnSigmaProton{"cMaxtofnSigmaProton", 3.0, "TOF nSigma cut for Proton"}; + + Configurable nsigmaCutCombinedProton{"nsigmaCutCombinedProton", -4.0, "Combined nSigma cut for Proton"}; + + Configurable cUseOnlyTOFTrackProton{"cUseOnlyTOFTrackProton", false, "Use only TOF track for PID selection Proton"}; + Configurable cByPassTOFProton{"cByPassTOFProton", true, "By pass TOF Proton PID selection"}; + + //*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*// + + // MC Event selection // + Configurable cZvertCutMC{"cZvertCutMC", 10.0, "MC Z-vertex cut"}; + Configurable cIsPhysicalPrimaryMC{"cIsPhysicalPrimaryMC", true, "Physical primary selection for a MC Parent"}; + + //*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*// + + // Cuts on mother particle and others + Configurable cfgCutsOnMother{"cfgCutsOnMother", true, "Enamble additional cuts on mother"}; + Configurable cMaxPtMotherCut{"cMaxPtMotherCut", 9.0, "Maximum pt of mother cut"}; + Configurable cMaxMinvMotherCut{"cMaxMinvMotherCut", 3.0, "Maximum Minv of mother cut"}; + + Configurable cMicroTrack{"cMicroTrack", false, "Using Micro track for first pion"}; + Configurable studyStableXi{"studyStableXi", true, "Study stable Xi"}; + TRandom* rn = new TRandom(); + + //*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*// + + struct PidSelectionParam { + double cMaxTPCnSigma; + double cMaxTOFnSigma; + bool cByPassTOF; + double nsigmaCutCombined; + }; + + void init(o2::framework::InitContext&) + { + AxisSpec centAxis = {binsCent, "FT0M (%)"}; + AxisSpec dcaxyAxis = {1500, 0.0, 0.3, "DCA_{#it{xy}} (cm)"}; + AxisSpec dcazAxis = {1500, 0.0, 0.3, "DCA_{#it{z}} (cm)"}; + AxisSpec dcaDaugAxis = {1000, 0.0, 1, "DCA_{#it{Daughter}} (cm)"}; + AxisSpec cosPAAxis = {3000, 0.0, 0.06, "1-cos(PA)"}; + AxisSpec mcLabelAxis = {6, -1.5, 4.5, "MC Label"}; + AxisSpec ptAxis = {binsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptAxisQA = {binsPtQA, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec invMassAxis = {cInvMassBins, cInvMassStart, cInvMassEnd, "Invariant Mass (GeV/#it{c}^2)"}; + AxisSpec invMassAxisCasc = {800, 1.25, 1.65, "Invariant Mass for Casc. (GeV/#it{c}^2)"}; + AxisSpec pidQAAxis = {65, -6.5, 6.5}; + AxisSpec flagAxis = {9, 0, 9, "Flags"}; + + if (additionalQAeventPlots) { + // Test on Mixed event + histos.add("TestME/hCollisionIndexSameE", "coll index sameE", HistType::kTH1F, {{500, 0.0f, 500.0f}}); + histos.add("TestME/hCollisionIndexMixedE", "coll index mixedE", HistType::kTH1F, {{500, 0.0f, 500.0f}}); + + histos.add("TestME/hnTrksSameE", "n tracks per event SameE", HistType::kTH1F, {{1000, 0.0f, 1000.0f}}); + histos.add("TestME/hnTrksMixedE", "n tracks per event MixedE", HistType::kTH1F, {{1000, 0.0f, 1000.0f}}); + + histos.add("TestME/hPairsCounterSameE", "tot n pairs sameE", HistType::kTH1F, {{1, 0.5f, 1.5f}}); + histos.add("TestME/hPairsCounterMixedE", "tot n pairs mixedE", HistType::kTH1F, {{1, 0.5f, 1.5f}}); + + // event histograms + histos.add("QAevent/hEvtCounterSameE", "Number of analyzed Same Events", HistType::kTH1F, {{1, 0.5, 1.5}}); + histos.add("QAevent/hVertexZSameE", "Collision Vertex Z position", HistType::kTH1F, {{100, -15., 15.}}); + histos.add("QAevent/hMultiplicityPercentSameE", "Multiplicity percentile of collision", HistType::kTH1F, {{120, 0.0f, 120.0f}}); + + histos.add("QAevent/hEvtCounterMixedE", "Number of analyzed Mixed Events", HistType::kTH1F, {{1, 0.5, 1.5}}); + histos.add("QAevent/hVertexZMixedE", "Collision Vertex Z position", HistType::kTH1F, {{100, -15., 15.}}); + histos.add("QAevent/hMultiplicityPercentMixedE", "Multiplicity percentile of collision", HistType::kTH1F, {{120, 0.0f, 120.0f}}); + } + + if (invMass1D) { + histos.add("Xi1530invmassDS", "Invariant mass of Xi(1530)0 differnt sign", kTH1F, {invMassAxis}); + histos.add("Xi1530invmassLS", "Invariant mass of Xi(1530)0 like sign", kTH1F, {invMassAxis}); + histos.add("Xi1530invmassME", "Invariant mass of Xi(1530)0 mixed event", kTH1F, {invMassAxis}); + + if (studyAntiparticle) { + histos.add("Xi1530invmassDSAnti", "Invariant mass of Anti-Xi(1530)0 differnt sign", kTH1F, {invMassAxis}); + histos.add("Xi1530invmassLSAnti", "Invariant mass of Anti-Xi(1530)0 like sign", kTH1F, {invMassAxis}); + } + } + + if (additionalMEPlots) { + histos.add("Xi1530invmassME_DS", "Invariant mass of Xi(1530)0 mixed event DS", kTH1F, {invMassAxis}); + histos.add("Xi1530invmassME_DSAnti", "Invariant mass of Xi(1530)0 mixed event DSAnti", kTH1F, {invMassAxis}); + } + + // TPC ncluster distirbutions + // histos.add("TPCncluster/TPCnclusterpifirst", "TPC ncluster distribution", kTH1F, {{160, 0, 160, "TPC nCluster"}}); + // histos.add("TPCncluster/TPCnclusterPhipifirst", "TPC ncluster vs phi", kTH2F, {{160, 0, 160, "TPC nCluster"}, {63, 0, 6.28, "#phi"}}); + + // DCA QA to candidates for first pion and Xi- + histos.add("QAbefore/trkDCAxy_pi", "DCAxy distribution of pion track candidates", HistType::kTH2F, {ptAxis, dcaxyAxis}); + histos.add("QAbefore/trkDCAxy_Xi", "DCAxy distribution of Xi- track candidates", HistType::kTH2F, {ptAxis, dcaxyAxis}); + + histos.add("QAbefore/trkDCAz_pi", "DCAz distribution of pion track candidates", HistType::kTH2F, {ptAxis, dcazAxis}); + histos.add("QAbefore/trkDCAz_Xi", "DCAz distribution of Xi- track candidates", HistType::kTH2F, {ptAxis, dcazAxis}); + + histos.add("QAafter/trkDCAxy_pi", "DCAxy distribution of pion track candidates", HistType::kTH2F, {ptAxis, dcaxyAxis}); + histos.add("QAafter/trkDCAxy_Xi", "DCAxy distribution of Xi- track candidates", HistType::kTH2F, {ptAxis, dcaxyAxis}); + + histos.add("QAafter/trkDCAz_pi", "DCAz distribution of pion track candidates", HistType::kTH2F, {ptAxis, dcazAxis}); + histos.add("QAafter/trkDCAz_Xi", "DCAz distribution of Xi- track candidates", HistType::kTH2F, {ptAxis, dcazAxis}); + + if (pidPlots) { + // Plots for QA before, Need to pt info. for the daugthers + histos.add("QAbefore/TOF_TPC_Map_pi_first_all", "TOF + TPC Combined PID for Pion_{First};#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAbefore/TOF_Nsigma_pi_first_all", "TOF NSigma for Pion_{First};#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAbefore/TPC_Nsigma_pi_first_all", "TPC NSigma for Pion_{First};#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + + histos.add("QAbefore/TOF_TPC_Map_pi_bachelor_all", "TOF + TPC Combined PID for Pion_{Bachelor};#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAbefore/TPC_Nsigma_pi_bachelor_all", "TPC NSigma for Pion_{Bachelor};#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + + histos.add("QAbefore/TOF_TPC_Map_pr_all", "TOF + TPC Combined PID for Proton;#sigma_{TOF}^{Proton};#sigma_{TPC}^{Proton}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAbefore/TOF_TPC_Map_antipr_all", "TOF + TPC Combined PID for Anti-Proton;#sigma_{TOF}^{Proton};#sigma_{TPC}^{Proton}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + + histos.add("QAbefore/TPC_Nsigma_pr_all", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Proton};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAbefore/TPC_Nsigma_antipr_all", "TPC NSigma for Anti-Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Proton};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + + histos.add("QAbefore/TOF_TPC_Map_pi_all", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAbefore/TOF_TPC_Map_piminus_all", "TOF + TPC Combined PID for Pion -;#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + + histos.add("QAbefore/TPC_Nsigma_pi_all", "TPC NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAbefore/TPC_Nsigma_piminus_all", "TPC NSigma for Pion -;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + + // Plots for QA after + histos.add("QAafter/TOF_TPC_Map_pi_first_all", "TOF + TPC Combined PID for Pion_{First};#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAafter/TOF_Nsigma_pi_first_all", "TOF NSigma for Pion_{First};#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAafter/TPC_Nsigma_pi_first_all", "TPC NSigma for Pion_{First};#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + + histos.add("QAafter/TOF_TPC_Map_pi_bachelor_all", "TOF + TPC Combined PID for Pion_{Bachelor};#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAafter/TPC_Nsigma_pi_bachelor_all", "TPC NSigma for Pion_{Bachelor};#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + + histos.add("QAafter/TOF_TPC_Map_pr_all", "TOF + TPC Combined PID for Proton;#sigma_{TOF}^{Proton};#sigma_{TPC}^{Proton}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAafter/TOF_TPC_Map_antipr_all", "TOF + TPC Combined PID for Anti-Proton;#sigma_{TOF}^{Proton};#sigma_{TPC}^{Proton}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + + histos.add("QAafter/TPC_Nsigma_pr_all", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Proton};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAafter/TPC_Nsigma_antipr_all", "TPC NSigma for Anti-Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Proton};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + + histos.add("QAafter/TOF_TPC_Map_pi_all", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAafter/TOF_TPC_Map_piminus_all", "TOF + TPC Combined PID for Pion -;#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + + histos.add("QAafter/TPC_Nsigma_pi_all", "TPC NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAafter/TPC_Nsigma_piminus_all", "TPC NSigma for Pion -;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + } + + // 3d histogram + Flags + histos.add("h3Xi1530invmassDS", "Invariant mass of Xi- differnt sign", kTHnSparseF, {centAxis, ptAxis, invMassAxis, flagAxis}); + histos.add("h3XiinvmassDS", "Invariant mass of Xi- differnt sign", kTHnSparseF, {centAxis, ptAxis, invMassAxisCasc, flagAxis}); + + histos.add("h3Xi1530invmassLS", "Invariant mass of Xi(1530)0 same sign", kTHnSparseF, {centAxis, ptAxis, invMassAxis, flagAxis}); + histos.add("h3XiinvmassLS", "Invariant mass of Xi- same sign", kTHnSparseF, {centAxis, ptAxis, invMassAxisCasc, flagAxis}); + + histos.add("h3Xi1530invmassME", "Invariant mass of Xi(1530)0 mixed event", kTHnSparseF, {centAxis, ptAxis, invMassAxis, flagAxis}); + histos.add("h3XiinvmassME", "Invariant mass of Xi- mixed event", kTHnSparseF, {centAxis, ptAxis, invMassAxisCasc, flagAxis}); + + if (studyAntiparticle) { + histos.add("h3Xi1530invmassDSAnti", "Invariant mass of Anti-Xi(1530)0 differnt sign", kTHnSparseF, {centAxis, ptAxis, invMassAxis, flagAxis}); + histos.add("h3XiinvmassDSAnti", "Invariant mass of Anti-Xi- differnt sign", kTHnSparseF, {centAxis, ptAxis, invMassAxisCasc, flagAxis}); + + histos.add("h3Xi1530invmassLSAnti", "Invariant mass of Anti-Xi(1530)0 same sign", kTHnSparseF, {centAxis, ptAxis, invMassAxis, flagAxis}); + histos.add("h3XiinvmassLSAnti", "Invariant mass of Anti-Xi- same sign", kTHnSparseF, {centAxis, ptAxis, invMassAxisCasc, flagAxis}); + } + + if (additionalMEPlots) { + histos.add("h3Xi1530invmassME_DS", "Invariant mass of Xi(1530)0 mixed event DS", kTHnSparseF, {centAxis, ptAxis, invMassAxis, flagAxis}); + histos.add("h3XiinvmassME_DS", "Invariant mass of Xi- mixed event DS", kTHnSparseF, {centAxis, ptAxis, invMassAxisCasc, flagAxis}); + + histos.add("h3Xi1530invmassME_DSAnti", "Invariant mass of Xi(1530)0 mixed event DSAnti", kTHnSparseF, {centAxis, ptAxis, invMassAxis, flagAxis}); + histos.add("h3XiinvmassME_DSAnti", "Invariant mass of Xi- mixed event DSAnti", kTHnSparseF, {centAxis, ptAxis, invMassAxisCasc, flagAxis}); + } + + if (doprocessMC) { + // MC QA + histos.add("QAMCTrue/trkDCAxy_pi", "DCAxy distribution of pion track candidates", HistType::kTH2F, {ptAxis, dcaxyAxis}); + histos.add("QAMCTrue/trkDCAxy_xi", "DCAxy distribution of Xi- track candidates", HistType::kTH2F, {ptAxis, dcaxyAxis}); + + histos.add("QAMCTrue/trkDCAz_pi", "DCAz distribution of pion track candidates", HistType::kTH2F, {ptAxis, dcazAxis}); + histos.add("QAMCTrue/trkDCAz_xi", "DCAz distribution of Xi- track candidates", HistType::kTH2F, {ptAxis, dcazAxis}); + + if (pidPlots) { + histos.add("QAMCTrue/TOF_TPC_Map_pi_first_all", "TOF + TPC Combined PID for Pion_{First};#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAMCTrue/TOF_Nsigma_pi_first_all", "TOF NSigma for Pion_{First};#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAMCTrue/TPC_Nsigma_pi_first_all", "TPC NSigma for Pion_{First};#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + + histos.add("QAMCTrue/TOF_TPC_Map_pi_bachelor_all", "TOF + TPC Combined PID for Pion_{Bachelor};#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAMCTrue/TPC_Nsigma_pi_bachelor_all", "TPC NSigma for Pion_{Bachelor};#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + + histos.add("QAMCTrue/TOF_TPC_Map_pr_all", "TOF + TPC Combined PID for Proton;#sigma_{TOF}^{Proton};#sigma_{TPC}^{Proton}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAMCTrue/TOF_TPC_Map_antipr_all", "TOF + TPC Combined PID for Anti-Proton;#sigma_{TOF}^{Proton};#sigma_{TPC}^{Proton}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + + histos.add("QAMCTrue/TPC_Nsigma_pr_all", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Proton};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAMCTrue/TPC_Nsigma_antipr_all", "TPC NSigma for Anti-Proton;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Proton};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + + histos.add("QAMCTrue/TOF_TPC_Map_pi_all", "TOF + TPC Combined PID for Pion;#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + histos.add("QAMCTrue/TOF_TPC_Map_piminus_all", "TOF + TPC Combined PID for Pion -;#sigma_{TOF}^{Pion};#sigma_{TPC}^{Pion}", {HistType::kTH2F, {pidQAAxis, pidQAAxis}}); + + histos.add("QAMCTrue/TPC_Nsigma_pi_all", "TPC NSigma for Pion;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + histos.add("QAMCTrue/TPC_Nsigma_piminus_all", "TPC NSigma for Pion -;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); + } + + histos.add("h3RecXi1530invmass", "Invariant mass of Reconstructed MC Xi(1530)0", kTHnSparseF, {centAxis, ptAxis, invMassAxis, flagAxis}); + histos.add("h3RecXiinvmass", "Invariant mass of Reconstructed MC Xi-", kTHnSparseF, {centAxis, ptAxis, invMassAxisCasc, flagAxis}); + + histos.add("h3RecXi1530invmassAnti", "Invariant mass of Reconstructed MC Anti-Xi(1530)0", kTHnSparseF, {centAxis, ptAxis, invMassAxis, flagAxis}); + histos.add("h3RecXiinvmassAnti", "Invariant mass of Reconstructed MC Anti-Xi-", kTHnSparseF, {centAxis, ptAxis, invMassAxisCasc, flagAxis}); + + histos.add("h3Xi1530Gen", "pT distribution of True MC Xi(1530)0", kTHnSparseF, {mcLabelAxis, ptAxis, centAxis}); + histos.add("h3Xi1530GenAnti", "pT distribution of True MC Anti-Xi(1530)0", kTHnSparseF, {mcLabelAxis, ptAxis, centAxis}); + + histos.add("Xi1530Rec", "pT distribution of Reconstructed MC Xi(1530)0", kTH2F, {ptAxis, centAxis}); + histos.add("Xi1530RecAnti", "pT distribution of Reconstructed MC Anti-Xi(1530)0", kTH2F, {ptAxis, centAxis}); + histos.add("Xi1530Recinvmass", "Inv mass distribution of Reconstructed MC Xi(1530)0", kTH1F, {invMassAxis}); + } + + if (additionalQAplots) { + histos.add("QAbefore/V0sDCADoughter_aspt", "V0s DCA Doughter distribution as pt", HistType::kTH2F, {ptAxis, dcaDaugAxis}); + histos.add("QAbefore/CascDCADoughter_aspt", "Casc DCA Doughter distribution as pt", HistType::kTH2F, {ptAxis, dcaDaugAxis}); + histos.add("QAbefore/CascMass_aspt", "Casc DCA Bachlor distribution as pt", HistType::kTH2F, {ptAxis, invMassAxisCasc}); + histos.add("QAbefore/V0sCosPA_aspt", "V0s CosPA distribution as pt", HistType::kTH2F, {ptAxis, cosPAAxis}); + histos.add("QAbefore/CascCosPA_aspt", "Casc CosPA distribution as pt", HistType::kTH2F, {ptAxis, cosPAAxis}); + + histos.add("QAafter/V0sDCADoughter_aspt", "V0s DCA Doughter distribution as pt", HistType::kTH2F, {ptAxis, dcaDaugAxis}); + histos.add("QAafter/CascDCADoughter_aspt", "Casc DCA Doughter distribution as pt", HistType::kTH2F, {ptAxis, dcaDaugAxis}); + histos.add("QAafter/CascMass_aspt", "Casc DCA Bachlor distribution as pt", HistType::kTH2F, {ptAxis, invMassAxisCasc}); + histos.add("QAafter/V0sCosPA_aspt", "V0s CosPA distribution as pt", HistType::kTH2F, {ptAxis, cosPAAxis}); + histos.add("QAafter/CascCosPA_aspt", "Casc CosPA distribution as pt", HistType::kTH2F, {ptAxis, cosPAAxis}); + + histos.add("QAMCTrue/V0sDCADoughter_aspt", "V0s DCA Doughter distribution as pt", HistType::kTH2F, {ptAxis, dcaDaugAxis}); + histos.add("QAMCTrue/CascDCADoughter_aspt", "Casc DCA Doughter distribution as pt", HistType::kTH2F, {ptAxis, dcaDaugAxis}); + histos.add("QAMCTrue/CascMass_aspt", "Casc DCA Bachlor distribution as pt", HistType::kTH2F, {ptAxis, invMassAxisCasc}); + histos.add("QAMCTrue/V0sCosPA_aspt", "V0s CosPA distribution as pt", HistType::kTH2F, {ptAxis, cosPAAxis}); + histos.add("QAMCTrue/CascCosPA_aspt", "Casc CosPA distribution as pt", HistType::kTH2F, {ptAxis, cosPAAxis}); + } + } + + double massPi = MassPionCharged; + + // Primary track selection for the first pion // + template + bool primaryTrackCut(const TrackType track) + { + if (std::abs(track.eta()) > cMaxetacut) + return false; + if (std::abs(track.pt()) < cMinPtcut) + return false; + if constexpr (IsResoMicrotrack) { + if (std::abs(o2::aod::resodmciroaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags())) > (cDCAxytoPVByPtPiFirstP0 + cDCAxyToPVByPtPiFirstExp * std::pow(track.pt(), -1.1))) + return false; + if (cDCAzToPVAsPt) { + if (std::abs(o2::aod::resodmciroaughter::ResoMicroTrackSelFlag::decodeDCAz(track.trackSelectionFlags())) > (cDCAxytoPVByPtPiFirstP0 + cDCAxyToPVByPtPiFirstExp * std::pow(track.pt(), -1.1))) + return false; + } else { + if (std::abs(o2::aod::resodmciroaughter::ResoMicroTrackSelFlag::decodeDCAz(track.trackSelectionFlags())) > cMaxDCAzToPVCut) + return false; + } + } else { + if (std::abs(track.dcaXY()) > (cDCAxytoPVByPtPiFirstP0 + cDCAxyToPVByPtPiFirstExp * std::pow(track.pt(), -1.1))) + return false; + if (cDCAzToPVAsPt) { + if (std::abs(track.dcaZ()) > (cDCAxytoPVByPtPiFirstP0 + cDCAxyToPVByPtPiFirstExp * std::pow(track.pt(), -1.1))) + return false; + } else { + if (std::abs(track.dcaZ()) > cMaxDCAzToPVCut) + return false; + } + if (track.tpcNClsFound() < cfgTPCcluster) + return false; + if (track.tpcNClsCrossedRows() < cfgTPCRows) + return false; + } + if (cfgHasTOF && !track.hasTOF()) + return false; + if (cfgUseITSRefit && !track.passedITSRefit()) + return false; + if (cfgUseTPCRefit && !track.passedTPCRefit()) + return false; + if (cfgPVContributor && !track.isPVContributor()) + return false; + if (cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + return true; + } + + bool hasSubsystemInfo(float Nsigma) // this will be replaced // .hasXX() was not appied in resocascade yet + { + return std::abs(Nsigma) < cPIDBound; + } + + // Primary track selection for cascades, Need to more informations for cascades // + template + bool cascprimaryTrackCut(const TracksTypeCasc track) + { + if (std::abs(track.eta()) > cMaxetacut) + return false; + if (std::abs(track.pt()) < cMinPtcut) + return false; + if (cDCAxyToPVAsPtForCasc) { + if (std::abs(track.dcaXYCascToPV()) > (cDCAxyToPVByPtCascP0 + cDCAxyToPVByPtCascExp * track.pt())) + return false; + } + if (cDCAzToPVAsPtForCasc) { + if (std::abs(track.dcaZCascToPV()) > (cDCAxyToPVByPtCascP0 + cDCAxyToPVByPtCascExp * std::pow(track.pt(), -1.1))) + return false; + } + + return true; + } + + // Secondary track selection for cascades // need to more information, + + // Topological cuts for cascades + template + bool casctopCut(const TracksTypeCasc track) + { + // Topological cuts for V0s + if (std::abs(track.daughDCA()) > cDCALambdaDaugtherscut) + return false; + if (std::abs(track.dcav0topv()) < cDCALambdaToPVcut) + return false; + if (track.sign() < 0) { + if (std::abs(track.dcanegtopv()) < cDCAPionToPVcut) + return false; + if (std::abs(track.dcapostopv()) < cDCAProtonToPVcut) + return false; + } else { + if (std::abs(track.dcanegtopv()) < cDCAProtonToPVcut) + return false; + if (std::abs(track.dcapostopv()) < cDCAPionToPVcut) + return false; + } + if (track.v0CosPA() < std::cos(cV0CosPACutPtDepP0 - cV0CosPACutPtDepP1 * track.pt())) + return false; + if (track.transRadius() > cMaxV0radiuscut || track.transRadius() < cMinV0radiuscut) + return false; + if (std::abs(track.mLambda() - MassLambda) > cMasswindowV0cut) + return false; + + // Topological Cuts for Cascades + if (std::abs(track.dcabachtopv()) < cDCABachlorToPVcut) + return false; + if (track.pt() < cDCAXiDaugthersCutPtRangeLower) { + if (track.cascDaughDCA() > cDCAXiDaugthersCutPtDepLower) + return false; + } + if (track.pt() >= cDCAXiDaugthersCutPtRangeLower && track.pt() < cDCAXiDaugthersCutPtRangeUpper) { + if (track.cascDaughDCA() > cDCAXiDaugthersCutPtDepMiddle) + return false; + } + if (track.pt() >= cDCAXiDaugthersCutPtRangeUpper) { + if (track.cascDaughDCA() > cDCAXiDaugthersCutPtDepUpper) + return false; + } + if (track.cascCosPA() < std::cos(cCosPACascCutPtDepP0 - cCosPACascCutPtDepP1 * track.pt())) + return false; + + if (track.cascTransRadius() > cMaxCascradiuscut || track.cascTransRadius() < cMinCascradiuscut) + return false; + if (std::abs(track.mXi() - cMassXiminus) > cMasswindowCasccut) + return false; + + return true; + } + + bool pidSelector(float TPCNsigma, float TOFNsigma, const PidSelectionParam& params, bool tofAtHighPt) + { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + + if (tofAtHighPt) { + // TOF based PID + if (hasSubsystemInfo(TOFNsigma) && std::abs(TOFNsigma) < params.cMaxTOFnSigma) { + return true; + } + if (!hasSubsystemInfo(TOFNsigma) && std::abs(TPCNsigma) < params.cMaxTPCnSigma) { + return true; + } + return false; + } else { + + if (std::abs(TPCNsigma) < params.cMaxTPCnSigma) { + tpcPIDPassed = true; + } + + if (params.cByPassTOF && tpcPIDPassed) { + return true; + } + + if (hasSubsystemInfo(TOFNsigma)) { + if (std::abs(TOFNsigma) < params.cMaxTOFnSigma) { + tofPIDPassed = true; + } + if ((params.nsigmaCutCombined > 0) && + (TPCNsigma * TPCNsigma + TOFNsigma * TOFNsigma < params.nsigmaCutCombined * params.nsigmaCutCombined)) { + tofPIDPassed = true; + } + } else { + tofPIDPassed = true; + } + + return tpcPIDPassed && tofPIDPassed; + } + } + + // PID selection for the First Pion // + template + bool selectionPIDPionFirst(const T& candidate) + { + + static float tpcNsigmaPionFirst, tofNsigmaPionFirst; + + if constexpr (IsResoMicrotrack) { + tpcNsigmaPionFirst = o2::aod::resodmciroaughter::PidNSigma::getTPCnSigma(candidate.pidNSigmaPiFlag()); + tofNsigmaPionFirst = o2::aod::resodmciroaughter::PidNSigma::getTOFnSigma(candidate.pidNSigmaPiFlag()); + } else { + tpcNsigmaPionFirst = candidate.tpcNSigmaPi(); + tofNsigmaPionFirst = candidate.tofNSigmaPi(); + } + + PidSelectionParam pionFirstParams = {cMaxtpcnSigmaPionFirst, cMaxtofnSigmaPionFirst, cByPassTOFPionFirst, nsigmaCutCombinedPionFirst}; + + return pidSelector(tpcNsigmaPionFirst, tofNsigmaPionFirst, pionFirstParams, tofAtHighPt); + } + + template + bool selectionPIDCascades(const TCascade& candidate) + { + bool lConsistentWithXi{false}, lConsistentWithLambda{false}, lConsistentWithPion{false}, lConsistentWithProton{false}; + + float tpcNsigmaBachelor, tofNsigmaBachelor; + float tpcNsigmaPion, tofNsigmaPion; + float tpcNsigmaProton, tofNsigmaProton; + + if (candidate.sign() < 0) { // Xi- candidates + tpcNsigmaBachelor = candidate.daughterTPCNSigmaBachPi(); + tofNsigmaBachelor = candidate.daughterTOFNSigmaBachPi(); + + tpcNsigmaPion = candidate.daughterTPCNSigmaNegPi(); + tofNsigmaPion = candidate.daughterTOFNSigmaNegPi(); + + tpcNsigmaProton = candidate.daughterTPCNSigmaPosPr(); + tofNsigmaProton = candidate.daughterTOFNSigmaPosPr(); + } else { // Anti-Xi- candidates + + tpcNsigmaBachelor = candidate.daughterTPCNSigmaBachPi(); + tofNsigmaBachelor = candidate.daughterTOFNSigmaBachPi(); + + tpcNsigmaPion = candidate.daughterTPCNSigmaPosPi(); + tofNsigmaPion = candidate.daughterTOFNSigmaPosPi(); + + tpcNsigmaProton = candidate.daughterTPCNSigmaNegPr(); + tofNsigmaProton = candidate.daughterTOFNSigmaNegPr(); + } + + PidSelectionParam bachelorParams = {cMaxtpcnSigmaPionBachelor, cMaxtofnSigmaPionBachelor, cByPassTOFPionBachelor, nsigmaCutCombinedPionBachelor}; + PidSelectionParam pionParams = {cMaxtpcnSigmaPion, cMaxtofnSigmaPion, cByPassTOFPion, nsigmaCutCombinedPion}; + PidSelectionParam protonParams = {cMaxtpcnSigmaProton, cMaxtofnSigmaProton, cByPassTOFProton, nsigmaCutCombinedProton}; + + lConsistentWithXi = pidSelector(tpcNsigmaBachelor, tofNsigmaBachelor, bachelorParams, tofAtHighPt); + lConsistentWithPion = pidSelector(tpcNsigmaPion, tofNsigmaPion, pionParams, tofAtHighPt); + lConsistentWithProton = pidSelector(tpcNsigmaProton, tofNsigmaProton, protonParams, tofAtHighPt); + + lConsistentWithLambda = lConsistentWithProton && lConsistentWithPion; + + return lConsistentWithXi && lConsistentWithLambda; + } + + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksTypeCasc& dTracks2) // Order: ResoColl, ResoTrack, ResoCascTrack + { + auto multiplicity = collision.cent(); + + if (additionalQAeventPlots) { + if constexpr (!IsMix) { + histos.fill(HIST("QAevent/hVertexZSameE"), collision.posZ()); + histos.fill(HIST("QAevent/hMultiplicityPercentSameE"), collision.cent()); + histos.fill(HIST("TestME/hCollisionIndexSameE"), collision.globalIndex()); + histos.fill(HIST("TestME/hnTrksSameE"), dTracks1.size()); + } else { + histos.fill(HIST("QAevent/hVertexZMixedE"), collision.posZ()); + histos.fill(HIST("QAevent/hMultiplicityPercentMixedE"), collision.cent()); + histos.fill(HIST("TestME/hCollisionIndexMixedE"), collision.globalIndex()); + histos.fill(HIST("TestME/hnTrksMixedE"), dTracks1.size()); + } + } + + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; // It will be replaced to use RecoDecay (In fixing...) + + for (const auto& [trk1, trk2] : combinations(CombinationsFullIndexPolicy(dTracks1, dTracks2))) { + + if (additionalQAeventPlots) { + if constexpr (!IsMix) { + histos.fill(HIST("TestME/hPairsCounterSameE"), 1.0); + } else { + histos.fill(HIST("TestME/hPairsCounterMixedE"), 1.0); + } + } + + auto trk1ptPi = trk1.pt(); + static float trk1DCAXY; + static float trk1DCAZ; + static float trk1NSigmaPiTPC; + static float trk1NSigmaPiTOF; + if constexpr (IsResoMicrotrack) { + trk1DCAXY = o2::aod::resodmciroaughter::ResoMicroTrackSelFlag::decodeDCAxy(trk1.trackSelectionFlags()); + trk1DCAZ = o2::aod::resodmciroaughter::ResoMicroTrackSelFlag::decodeDCAz(trk1.trackSelectionFlags()); + trk1NSigmaPiTPC = o2::aod::resodmciroaughter::PidNSigma::getTPCnSigma(trk1.pidNSigmaPiFlag()); + trk1NSigmaPiTOF = o2::aod::resodmciroaughter::PidNSigma::getTOFnSigma(trk1.pidNSigmaPiFlag()); + } else { + trk1DCAXY = trk1.dcaXY(); + trk1DCAZ = trk1.dcaZ(); + trk1NSigmaPiTPC = trk1.tpcNSigmaPi(); + trk1NSigmaPiTOF = trk1.tofNSigmaPi(); + } + + auto trk2ptXi = trk2.pt(); + + auto trk2DCAXY = trk2.dcaXYCascToPV(); + auto trk2DCAZ = trk2.dcaZCascToPV(); + + auto trk2DCAV0sDougthers = trk2.daughDCA(); + auto trk2DCACascDougthers = trk2.cascDaughDCA(); + auto trk2Mass = trk2.mXi(); + auto trk2CascCosPA = trk2.cascCosPA(); + auto trk2V0sCosPA = trk2.v0CosPA(); + + // Need to daughther's pt info. in the table + // auto trk2ptPiBachelor = trk2.pt(); + float trk2NSigmaPiBachelorTPC = trk2.daughterTPCNSigmaBachPi(); + float trk2NSigmaPiBachelorTOF = trk2.daughterTOFNSigmaBachPi(); + + // auto trk2ptPr = trk2.pt(); + float trk2NSigmaPrPosTPC = trk2.daughterTPCNSigmaPosPr(); + float trk2NSigmaPrNegTPC = trk2.daughterTPCNSigmaNegPr(); + + float trk2NSigmaPrPosTOF = trk2.daughterTOFNSigmaPosPr(); + float trk2NSigmaPrNegTOF = trk2.daughterTOFNSigmaNegPr(); + + // auto trk2ptPi = trk2.pt(); + float trk2NSigmaPiPosTPC = trk2.daughterTPCNSigmaPosPi(); + float trk2NSigmaPiNegTPC = trk2.daughterTPCNSigmaNegPi(); + + float trk2NSigmaPiPosTOF = trk2.daughterTOFNSigmaPosPi(); + float trk2NSigmaPiNegTOF = trk2.daughterTOFNSigmaNegPi(); + + if constexpr (!IsMix) { + //// QA plots before the selection // need to pt for cascade tracks + // --- PID QA + if (pidPlots) { + histos.fill(HIST("QAbefore/TPC_Nsigma_pi_first_all"), multiplicity, trk1ptPi, trk1NSigmaPiTPC); + if (hasSubsystemInfo(trk1NSigmaPiTOF)) { + histos.fill(HIST("QAbefore/TOF_Nsigma_pi_first_all"), multiplicity, trk1ptPi, trk1NSigmaPiTOF); + histos.fill(HIST("QAbefore/TOF_TPC_Map_pi_first_all"), trk1NSigmaPiTOF, trk1NSigmaPiTPC); + } + // hasSubsystemInfo is Temporary, it will be replaced. + + histos.fill(HIST("QAbefore/TPC_Nsigma_pi_bachelor_all"), multiplicity, 0, trk2NSigmaPiBachelorTPC); // can't take pt information for the cascade secondary + if (hasSubsystemInfo(trk2NSigmaPiBachelorTOF)) { + histos.fill(HIST("QAbefore/TOF_TPC_Map_pi_bachelor_all"), trk2NSigmaPiBachelorTOF, trk2NSigmaPiBachelorTPC); + } + + histos.fill(HIST("QAbefore/TPC_Nsigma_pr_all"), multiplicity, 0, trk2NSigmaPrPosTPC); + if (hasSubsystemInfo(trk2NSigmaPrPosTOF)) { + histos.fill(HIST("QAbefore/TOF_TPC_Map_pr_all"), trk2NSigmaPrPosTOF, trk2NSigmaPrPosTPC); + } + + histos.fill(HIST("QAbefore/TPC_Nsigma_antipr_all"), multiplicity, 0, trk2NSigmaPrNegTPC); + if (hasSubsystemInfo(trk2NSigmaPrNegTOF)) { + histos.fill(HIST("QAbefore/TOF_TPC_Map_antipr_all"), trk2NSigmaPrNegTOF, trk2NSigmaPrNegTPC); + } + + histos.fill(HIST("QAbefore/TPC_Nsigma_pi_all"), multiplicity, 0, trk2NSigmaPiPosTPC); + if (hasSubsystemInfo(trk2NSigmaPiPosTOF)) { + histos.fill(HIST("QAbefore/TOF_TPC_Map_pi_all"), trk2NSigmaPiPosTOF, trk2NSigmaPiPosTPC); + } + + histos.fill(HIST("QAbefore/TPC_Nsigma_piminus_all"), multiplicity, 0, trk2NSigmaPiNegTPC); + if (hasSubsystemInfo(trk2NSigmaPiNegTOF)) { + histos.fill(HIST("QAbefore/TOF_TPC_Map_piminus_all"), trk2NSigmaPiNegTOF, trk2NSigmaPiNegTPC); + } + } + + histos.fill(HIST("QAbefore/trkDCAxy_pi"), trk1ptPi, trk1DCAXY); + histos.fill(HIST("QAbefore/trkDCAxy_Xi"), trk2ptXi, trk2DCAXY); + + histos.fill(HIST("QAbefore/trkDCAz_pi"), trk1ptPi, trk1DCAZ); + histos.fill(HIST("QAbefore/trkDCAz_Xi"), trk2ptXi, trk2DCAZ); + + if (additionalQAplots) { + histos.fill(HIST("QAbefore/V0sDCADoughter_aspt"), trk2ptXi, trk2DCAV0sDougthers); + histos.fill(HIST("QAbefore/CascDCADoughter_aspt"), trk2ptXi, trk2DCACascDougthers); + histos.fill(HIST("QAbefore/CascMass_aspt"), trk2ptXi, trk2Mass); + histos.fill(HIST("QAbefore/V0sCosPA_aspt"), trk2ptXi, 1. - trk2V0sCosPA); + histos.fill(HIST("QAbefore/CascCosPA_aspt"), trk2ptXi, 1. - trk2CascCosPA); + } + } + + if (!primaryTrackCut(trk1) || !cascprimaryTrackCut(trk2)) // Primary track selections + continue; + + // PID selection + if (cUseOnlyTOFTrackPionFirst && !hasSubsystemInfo(trk1NSigmaPiTOF)) + continue; + + if (cUseOnlyTOFTrackPionBachelor && !hasSubsystemInfo(trk2NSigmaPiBachelorTOF)) + continue; + + if (cUseOnlyTOFTrackProton && !hasSubsystemInfo(trk2NSigmaPrPosTOF)) + continue; + if (cUseOnlyTOFTrackProton && !hasSubsystemInfo(trk2NSigmaPrNegTOF)) + continue; + + if (cUseOnlyTOFTrackPion && !hasSubsystemInfo(trk2NSigmaPiPosTOF)) + continue; + if (cUseOnlyTOFTrackPion && !hasSubsystemInfo(trk2NSigmaPiNegTOF)) + continue; + + if (!selectionPIDPionFirst(trk1) || !selectionPIDCascades(trk2)) + continue; + + if (!casctopCut(trk2)) + continue; + + // TPCncluster distributions + // histos.fill(HIST("TPCncluster/TPCnclusterpifirst"), trk1.tpcNClsFound()); + // histos.fill(HIST("TPCncluster/TPCnclusterPhipifirst"), trk1.tpcNClsFound(), trk1.phi()); + + if constexpr (!IsMix) { + //// QA plots after the selection + // --- PID QA + if (pidPlots) { + histos.fill(HIST("QAafter/TPC_Nsigma_pi_first_all"), multiplicity, trk1ptPi, trk1NSigmaPiTPC); + + if (hasSubsystemInfo(trk1NSigmaPiTOF)) { + histos.fill(HIST("QAafter/TOF_Nsigma_pi_first_all"), multiplicity, trk1ptPi, trk1NSigmaPiTOF); + histos.fill(HIST("QAafter/TOF_TPC_Map_pi_first_all"), trk1NSigmaPiTOF, trk1NSigmaPiTPC); + } + + if (trk2.sign() < 0) { + histos.fill(HIST("QAafter/TPC_Nsigma_pi_bachelor_all"), multiplicity, 0, trk2NSigmaPiBachelorTPC); // not exist pt information in resocascade yet. + if (hasSubsystemInfo(trk2NSigmaPiBachelorTOF)) { + histos.fill(HIST("QAafter/TOF_TPC_Map_pi_bachelor_all"), trk2NSigmaPiBachelorTOF, trk2NSigmaPiBachelorTPC); + } + + histos.fill(HIST("QAafter/TPC_Nsigma_pr_all"), multiplicity, 0, trk2NSigmaPrPosTPC); + if (hasSubsystemInfo(trk2NSigmaPrPosTOF)) { + histos.fill(HIST("QAafter/TOF_TPC_Map_pr_all"), trk2NSigmaPrPosTOF, trk2NSigmaPrPosTPC); + } + + histos.fill(HIST("QAafter/TPC_Nsigma_piminus_all"), multiplicity, 0, trk2NSigmaPiNegTPC); + if (hasSubsystemInfo(trk2NSigmaPiNegTOF)) { + histos.fill(HIST("QAafter/TOF_TPC_Map_piminus_all"), trk2NSigmaPiNegTOF, trk2NSigmaPiNegTPC); + } + + } else { + + histos.fill(HIST("QAafter/TPC_Nsigma_pi_bachelor_all"), multiplicity, 0, trk2NSigmaPiBachelorTPC); // not exist pt information in resocascade yet. + if (hasSubsystemInfo(trk2NSigmaPiBachelorTOF)) { + histos.fill(HIST("QAafter/TOF_TPC_Map_pi_bachelor_all"), trk2NSigmaPiBachelorTOF, trk2NSigmaPiBachelorTPC); + } + + histos.fill(HIST("QAafter/TPC_Nsigma_antipr_all"), multiplicity, 0, trk2NSigmaPrNegTPC); + if (hasSubsystemInfo(trk2NSigmaPrNegTOF)) { + histos.fill(HIST("QAafter/TOF_TPC_Map_antipr_all"), trk2NSigmaPrNegTOF, trk2NSigmaPrNegTPC); + } + + histos.fill(HIST("QAafter/TPC_Nsigma_pi_all"), multiplicity, 0, trk2NSigmaPiPosTPC); + if (hasSubsystemInfo(trk2NSigmaPiPosTOF)) { + histos.fill(HIST("QAafter/TOF_TPC_Map_pi_all"), trk2NSigmaPiPosTOF, trk2NSigmaPiPosTPC); + } + } + } + + histos.fill(HIST("QAafter/trkDCAxy_pi"), trk1ptPi, trk1DCAXY); + histos.fill(HIST("QAafter/trkDCAxy_Xi"), trk2ptXi, trk2DCAXY); + + histos.fill(HIST("QAafter/trkDCAz_pi"), trk1ptPi, trk1DCAZ); + histos.fill(HIST("QAafter/trkDCAz_Xi"), trk2ptXi, trk2DCAZ); + + if (additionalQAplots) { + histos.fill(HIST("QAafter/V0sDCADoughter_aspt"), trk2ptXi, trk2DCAV0sDougthers); + histos.fill(HIST("QAafter/CascDCADoughter_aspt"), trk2ptXi, trk2DCACascDougthers); + histos.fill(HIST("QAafter/CascMass_aspt"), trk2ptXi, trk2Mass); + histos.fill(HIST("QAafter/V0sCosPA_aspt"), trk2ptXi, 1. - trk2V0sCosPA); + histos.fill(HIST("QAafter/CascCosPA_aspt"), trk2ptXi, 1. - trk2CascCosPA); + } + } + + lDecayDaughter1.SetPtEtaPhiM(trk1ptPi, trk1.eta(), trk1.phi(), massPi); + lDecayDaughter2.SetPtEtaPhiM(trk2ptXi, trk2.eta(), trk2.phi(), trk2.mXi()); + lResonance = lDecayDaughter1 + lDecayDaughter2; + + auto lResonancePt = lResonance.Pt(); + auto lResonanceInMass = lResonance.M(); + + if (std::abs(lResonance.Rapidity()) >= cfgRapidityCut) + continue; + + if (cfgCutsOnMother) { + if (lResonancePt >= cMaxPtMotherCut) // excluding candidates in overflow + continue; + if (lResonanceInMass >= cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } + + if (trk1.sign() * trk2.sign() < 0) { + + if constexpr (!IsMix) { + if (studyAntiparticle) { + if (trk1.sign() > 0) { + if (invMass1D) + histos.fill(HIST("Xi1530invmassDS"), lResonanceInMass); + histos.fill(HIST("h3Xi1530invmassDS"), multiplicity, lResonancePt, lResonanceInMass, kData); + } else if (trk1.sign() < 0) { + if (invMass1D) + histos.fill(HIST("Xi1530invmassDSAnti"), lResonanceInMass); + histos.fill(HIST("h3Xi1530invmassDSAnti"), multiplicity, lResonancePt, lResonanceInMass, kData); + } + } else { + if (invMass1D) + histos.fill(HIST("Xi1530invmassDS"), lResonanceInMass); + histos.fill(HIST("h3Xi1530invmassDS"), multiplicity, lResonancePt, lResonanceInMass, kData); + } + + if (studyStableXi) { + if (trk1.sign() > 0) { + histos.fill(HIST("h3XiinvmassDS"), multiplicity, trk2ptXi, trk2Mass, kData); + } else if (trk1.sign() < 0) { + histos.fill(HIST("h3XiinvmassDSAnti"), multiplicity, trk2ptXi, trk2Mass, kData); + } + } + } else { + if (invMass1D) + histos.fill(HIST("Xi1530invmassME"), lResonanceInMass); + if (trk1.sign() > 0) { + if (invMass1D) + histos.fill(HIST("Xi1530invmassME_DS"), lResonanceInMass); + histos.fill(HIST("h3Xi1530invmassME_DS"), multiplicity, lResonancePt, lResonanceInMass, kMixing); + } else if (trk1.sign() < 0) { + if (invMass1D) + histos.fill(HIST("Xi1530invmassME_DSAnti"), lResonanceInMass); + histos.fill(HIST("h3Xi1530invmassME_DSAnti"), multiplicity, lResonancePt, lResonanceInMass, kMixing); + } + histos.fill(HIST("h3Xi1530invmassME"), multiplicity, lResonancePt, lResonanceInMass, kMixing); + + if (studyStableXi) { + if (trk1.sign() > 0) { + histos.fill(HIST("h3XiinvmassME_DS"), multiplicity, trk2ptXi, trk2Mass, kMixing); + } else if (trk1.sign() < 0) { + histos.fill(HIST("h3XiinvmassME_DSAnti"), multiplicity, trk2ptXi, trk2Mass, kMixing); + } + } + } + if constexpr (IsMC) { + if (std::abs(trk2.motherPDG()) != kXiStar) + continue; + if (std::abs(trk1.pdgCode()) != kPiPlus || std::abs(trk2.pdgCode()) != kXiMinus) + continue; + if (trk1.motherId() != trk2.motherId()) + continue; + + histos.fill(HIST("QAMCTrue/trkDCAxy_pi"), trk1ptPi, trk1DCAXY); + histos.fill(HIST("QAMCTrue/trkDCAxy_xi"), trk2ptXi, trk2DCAXY); + histos.fill(HIST("QAMCTrue/trkDCAz_pi"), trk1ptPi, trk1DCAZ); + histos.fill(HIST("QAMCTrue/trkDCAz_xi"), trk2ptXi, trk2DCAZ); + + if (additionalQAplots) { + histos.fill(HIST("QAMCTrue/V0sDCADoughter_aspt"), trk2ptXi, trk2DCAV0sDougthers); + histos.fill(HIST("QAMCTrue/CascDCADoughter_aspt"), trk2ptXi, trk2DCACascDougthers); + histos.fill(HIST("QAMCTrue/CascMass_aspt"), trk2ptXi, trk2Mass); + histos.fill(HIST("QAMCTrue/V0sCosPA_aspt"), trk2ptXi, 1. - trk2V0sCosPA); + histos.fill(HIST("QAMCTrue/CascCosPA_aspt"), trk2ptXi, 1. - trk2CascCosPA); + } + + histos.fill(HIST("QAMCTrue/TPC_Nsigma_pi_first_all"), multiplicity, trk1ptPi, trk1NSigmaPiTPC); + if (hasSubsystemInfo(trk1NSigmaPiTOF)) { + histos.fill(HIST("QAMCTrue/TOF_Nsigma_pi_first_all"), multiplicity, trk1ptPi, trk1NSigmaPiTOF); + histos.fill(HIST("QAMCTrue/TOF_TPC_Map_pi_first_all"), trk1NSigmaPiTOF, trk1NSigmaPiTPC); + } + + if (trk2.sign() < 0) { + histos.fill(HIST("QAMCTrue/TPC_Nsigma_pi_bachelor_all"), multiplicity, 0, trk2NSigmaPiBachelorTPC); // not exist pt information in resocascade yet. + if (hasSubsystemInfo(trk2NSigmaPiBachelorTOF)) { + histos.fill(HIST("QAMCTrue/TOF_TPC_Map_pi_bachelor_all"), trk2NSigmaPiBachelorTOF, trk2NSigmaPiBachelorTPC); + } + + histos.fill(HIST("QAMCTrue/TPC_Nsigma_pr_all"), multiplicity, 0, trk2NSigmaPrPosTPC); + if (hasSubsystemInfo(trk2NSigmaPrPosTOF)) { + histos.fill(HIST("QAMCTrue/TOF_TPC_Map_pr_all"), trk2NSigmaPrPosTOF, trk2NSigmaPrPosTPC); + } + + histos.fill(HIST("QAMCTrue/TPC_Nsigma_piminus_all"), multiplicity, 0, trk2NSigmaPiNegTPC); + if (hasSubsystemInfo(trk2NSigmaPiNegTOF)) { + histos.fill(HIST("QAMCTrue/TOF_TPC_Map_piminus_all"), trk2NSigmaPiNegTOF, trk2NSigmaPiNegTPC); + } + + } else { + + histos.fill(HIST("QAMCTrue/TPC_Nsigma_pi_bachelor_all"), multiplicity, 0, trk2NSigmaPiBachelorTPC); // not exist pt information in resocascade yet. + if (hasSubsystemInfo(trk2NSigmaPiBachelorTOF)) { + histos.fill(HIST("QAMCTrue/TOF_TPC_Map_pi_bachelor_all"), trk2NSigmaPiBachelorTOF, trk2NSigmaPiBachelorTPC); + } + + histos.fill(HIST("QAMCTrue/TPC_Nsigma_antipr_all"), multiplicity, 0, trk2NSigmaPrNegTPC); + if (hasSubsystemInfo(trk2NSigmaPrNegTOF)) { + histos.fill(HIST("QAMCTrue/TOF_TPC_Map_antipr_all"), trk2NSigmaPrNegTOF, trk2NSigmaPrNegTPC); + } + + histos.fill(HIST("QAMCTrue/TPC_Nsigma_pi_all"), multiplicity, 0, trk2NSigmaPiPosTPC); + if (hasSubsystemInfo(trk2NSigmaPiPosTOF)) { + histos.fill(HIST("QAMCTrue/TOF_TPC_Map_pi_all"), trk2NSigmaPiPosTOF, trk2NSigmaPiPosTPC); + } + } + // MC histograms + if (trk2.motherPDG() > 0) { + histos.fill(HIST("Xi1530Rec"), lResonancePt, multiplicity); + histos.fill(HIST("Xi1530Recinvmass"), lResonanceInMass); + histos.fill(HIST("h3RecXi1530invmass"), multiplicity, lResonancePt, lResonanceInMass, kMCReco); + histos.fill(HIST("h3RecXiinvmass"), multiplicity, trk2ptXi, trk2Mass, kMCReco); + } else { + histos.fill(HIST("Xi1530RecAnti"), lResonancePt, multiplicity); + histos.fill(HIST("Xi1530Recinvmass"), lResonanceInMass); + histos.fill(HIST("h3RecXi1530invmassAnti"), multiplicity, lResonancePt, lResonanceInMass, kMCReco); + histos.fill(HIST("h3RecXiinvmassAnti"), multiplicity, trk2ptXi, trk2Mass, kMCReco); + } + } + + } else { + if constexpr (!IsMix) { + if (studyAntiparticle) { + if (trk1.sign() < 0) { + if (invMass1D) + histos.fill(HIST("Xi1530invmassLS"), lResonanceInMass); + histos.fill(HIST("h3Xi1530invmassLS"), multiplicity, lResonancePt, lResonanceInMass, kLS); + histos.fill(HIST("h3XiinvmassLS"), multiplicity, trk2ptXi, trk2Mass, kLS); + } else if (trk1.sign() > 0) { + if (invMass1D) + histos.fill(HIST("Xi1530invmassLSAnti"), lResonanceInMass); + histos.fill(HIST("h3Xi1530invmassLSAnti"), multiplicity, lResonancePt, lResonanceInMass, kLS); + histos.fill(HIST("h3XiinvmassLSAnti"), multiplicity, trk2ptXi, trk2Mass, kLS); + } + } else { + if (invMass1D) + histos.fill(HIST("Xi1530invmassLS"), lResonanceInMass); + histos.fill(HIST("h3Xi1530invmassLS"), multiplicity, lResonancePt, lResonanceInMass, kLS); + histos.fill(HIST("h3XiinvmassLS"), multiplicity, trk2ptXi, trk2Mass, kLS); + } + } + } + } + } + + void processData(aod::ResoCollision const& resoCollision, aod::ResoTracks const& resoTracks, aod::ResoCascades const& cascTracks) + { + if (additionalQAeventPlots) + histos.fill(HIST("QAevent/hEvtCounterSameE"), 1.0); + fillHistograms(resoCollision, resoTracks, cascTracks); + } + + void processMC(ResoMCCols::iterator const& resoCollision, + soa::Join const& cascTracks, + soa::Join const& resoTracks) + { + if (!resoCollision.isInAfterAllCuts() || (std::abs(resoCollision.posZ()) > cZvertCutMC)) // MC event selection, all cuts missing vtx cut + return; + fillHistograms(resoCollision, resoTracks, cascTracks); + } + + void processMCTrue(ResoMCCols::iterator const& resoCollision, aod::ResoMCParents const& resoParents) + { + auto multiplicity = resoCollision.cent(); + for (const auto& part : resoParents) { // loop over all pre-filtered MC particles + if (std::abs(part.pdgCode()) != kXiStar || std::abs(part.y()) >= cfgRapidityCut) + continue; + bool pass1 = std::abs(part.daughterPDG1()) == kPiPlus || std::abs(part.daughterPDG2()) == kPiPlus; + bool pass2 = std::abs(part.daughterPDG1()) == kXiMinus || std::abs(part.daughterPDG2()) == kXiMinus; + + if (!pass1 || !pass2) + continue; + + if (cIsPhysicalPrimaryMC && !part.isPhysicalPrimary()) + continue; + + if (part.pdgCode() > 0) // INELt0 or INEL + histos.fill(HIST("h3Xi1530Gen"), -1, part.pt(), multiplicity); + else + histos.fill(HIST("h3Xi1530GenAnti"), -1, part.pt(), multiplicity); + + if (resoCollision.isVtxIn10()) // vtx10 + { + if (part.pdgCode() > 0) + histos.fill(HIST("h3Xi1530Gen"), 0, part.pt(), multiplicity); + else + histos.fill(HIST("h3Xi1530GenAnti"), 0, part.pt(), multiplicity); + } + if (resoCollision.isVtxIn10() && resoCollision.isInSel8()) // vtx10 && sel8 + { + if (part.pdgCode() > 0) + histos.fill(HIST("h3Xi1530Gen"), 1, part.pt(), multiplicity); + else + histos.fill(HIST("h3Xi1530GenAnti"), 1, part.pt(), multiplicity); + } + if (resoCollision.isVtxIn10() && resoCollision.isTriggerTVX()) // vtx10 && TriggerTVX + { + if (part.pdgCode() > 0) + histos.fill(HIST("h3Xi1530Gen"), 2, part.pt(), multiplicity); + else + histos.fill(HIST("h3Xi1530GenAnti"), 2, part.pt(), multiplicity); + } + if (resoCollision.isInAfterAllCuts()) // after all event selection + { + if (part.pdgCode() > 0) + histos.fill(HIST("h3Xi1530Gen"), 3, part.pt(), multiplicity); + else + histos.fill(HIST("h3Xi1530GenAnti"), 3, part.pt(), multiplicity); + } + } + } + + void processDataMicro(aod::ResoCollision const& resoCollision, aod::ResoMicroTracks const& resomicrotracks, aod::ResoCascades const& cascTracks) + { + if (additionalQAeventPlots) + histos.fill(HIST("QAevent/hEvtCounterSameE"), 1.0); + fillHistograms(resoCollision, resomicrotracks, cascTracks); + } + + using BinningTypeVtxZT0M = ColumnBinningPolicy; + void processMEMicro(aod::ResoCollisions const& resoCollisions, aod::ResoMicroTracks const& resomicrotracks, aod::ResoCascades const& cascTracks) + { + auto tracksTuple = std::make_tuple(resomicrotracks, cascTracks); + + BinningTypeVtxZT0M colBinning{{cfgVtxBins, cfgMultBins}, true}; + Pair pairs{colBinning, nEvtMixing, -1, resoCollisions, tracksTuple, &cache}; + + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (additionalQAeventPlots) + histos.fill(HIST("QAevent/hEvtCounterMixedE"), 1.0); + fillHistograms(collision1, tracks1, tracks2); + } + } + + PROCESS_SWITCH(Xi1530Analysisqa, processData, "Process Event for Data", false); + PROCESS_SWITCH(Xi1530Analysisqa, processMC, "Process Event for MC (Reconstructed)", false); + PROCESS_SWITCH(Xi1530Analysisqa, processMCTrue, "Process Event for MC (Generated)", false); + PROCESS_SWITCH(Xi1530Analysisqa, processDataMicro, "Process Event for Data (MicroTrack for first pion)", true); + PROCESS_SWITCH(Xi1530Analysisqa, processMEMicro, "Process EventMixing", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Strangeness/CMakeLists.txt b/PWGLF/Tasks/Strangeness/CMakeLists.txt index e765fe1e847..60106e5415b 100644 --- a/PWGLF/Tasks/Strangeness/CMakeLists.txt +++ b/PWGLF/Tasks/Strangeness/CMakeLists.txt @@ -16,7 +16,7 @@ o2physics_add_dpl_workflow(hyperon-reco-test o2physics_add_dpl_workflow(derivedlambdakzeroanalysis SOURCES derivedlambdakzeroanalysis.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(lambdakzeroanalysis-mc @@ -29,6 +29,11 @@ o2physics_add_dpl_workflow(cascadeanalysis PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(sigmaminus-task + SOURCES sigmaminustask.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(cascadeanalysismc SOURCES cascadeanalysisMC.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -41,17 +46,12 @@ o2physics_add_dpl_workflow(v0postprocessing o2physics_add_dpl_workflow(cascadecorrelations SOURCES cascadecorrelations.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(non-prompt-cascade SOURCES nonPromptCascade.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::ReconstructionDataFormats O2Physics::AnalysisCore O2::DetectorsBase - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(kinkanalysis - SOURCES kinkAnalysis.cxx - PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2::Framework O2::ReconstructionDataFormats O2Physics::AnalysisCore O2::DetectorsBase O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(k0mixedevents @@ -66,7 +66,7 @@ o2physics_add_dpl_workflow(vzero-cascade-absorption o2physics_add_dpl_workflow(derivedcascadeanalysis SOURCES derivedcascadeanalysis.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(cascpostprocessing @@ -76,10 +76,72 @@ o2physics_add_dpl_workflow(cascpostprocessing o2physics_add_dpl_workflow(hstrangecorrelation SOURCES hStrangeCorrelation.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(sigmaanalysis SOURCES sigmaanalysis.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(phik0shortanalysis + SOURCES phik0shortanalysis.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) \ No newline at end of file + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(lambdapolarization + SOURCES lambdapolarization.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(lambdapolsp + SOURCES lambdapolsp.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(task-lambda-spin-corr + SOURCES taskLambdaSpinCorr.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(cascpolsp + SOURCES cascpolsp.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +if(FastJet_FOUND) +o2physics_add_dpl_workflow(strangeness-in-jets + SOURCES strangenessInJets.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet FastJet::Contrib O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) +endif() + +o2physics_add_dpl_workflow(v0topologicalcuts + SOURCES v0topologicalcuts.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(v0ptinvmassplots + SOURCES v0ptinvmassplots.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(derivedupcanalysis + SOURCES derivedupcanalysis.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(lambdak0sflattenicity + SOURCES lambdak0sflattenicity.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(lambdalambda + SOURCES lambdalambda.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(lambdajetpolarization + SOURCES lambdaJetpolarization.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGLF/Tasks/Strangeness/cascadeanalysisMC.cxx b/PWGLF/Tasks/Strangeness/cascadeanalysisMC.cxx index 05df2504e4e..896d366a1fa 100644 --- a/PWGLF/Tasks/Strangeness/cascadeanalysisMC.cxx +++ b/PWGLF/Tasks/Strangeness/cascadeanalysisMC.cxx @@ -78,16 +78,23 @@ struct cascadeGenerated { Configurable maxPt{"maxPt", 20.0, "max generated pT"}; Configurable nPtBins{"nPtBins", 200, "number of pT bins"}; + Configurable rapidityCut{"rapidityCut", 0.5, "max (absolute) rapidity of generated cascade"}; + Configurable nRapidityBins{"nRapidityBins", 200, "number of pT bins"}; void init(InitContext const&) { - AxisSpec ptAxis = {nPtBins, 0.0f, maxPt, "it{p}_{T} (GeV/c)"}; + AxisSpec ptAxis = {nPtBins, 0.0f, maxPt, "#it{p}_{T} (GeV/c)"}; + AxisSpec rapidityAxis = {nRapidityBins, -rapidityCut, rapidityCut, "y"}; registry.add("hEventCounter", "hEventCounter", {HistType::kTH1F, {{10, 0.0f, 10.0f}}}); registry.add("hPtXiMinus", "hPtXiMinus", {HistType::kTH1F, {ptAxis}}); registry.add("hPtXiPlus", "hPtXiPlus", {HistType::kTH1F, {ptAxis}}); registry.add("hPtOmegaMinus", "hPtOmegaMinus", {HistType::kTH1F, {ptAxis}}); registry.add("hPtOmegaPlus", "hPtOmegaPlus", {HistType::kTH1F, {ptAxis}}); + registry.add("h2DXiMinus", "h2DXiMinus", {HistType::kTH2F, {ptAxis, rapidityAxis}}); + registry.add("h2DXiPlus", "h2DXiPlus", {HistType::kTH2F, {ptAxis, rapidityAxis}}); + registry.add("h2DOmegaMinus", "h2DOmegaMinus", {HistType::kTH2F, {ptAxis, rapidityAxis}}); + registry.add("h2DOmegaPlus", "h2DOmegaPlus", {HistType::kTH2F, {ptAxis, rapidityAxis}}); } void process(aod::McCollision const& /*collision*/, aod::McParticles const& mcparts) @@ -99,16 +106,24 @@ struct cascadeGenerated { // Count all generated MC particles // WARNING: event-level losses have to be understood too for (auto& particle : mcparts) { - if (TMath::Abs(particle.y()) > 0.5) + if (TMath::Abs(particle.y()) > rapidityCut) continue; - if (particle.pdgCode() == 3312) + if (particle.pdgCode() == 3312) { registry.fill(HIST("hPtXiMinus"), particle.pt()); - if (particle.pdgCode() == -3312) + registry.fill(HIST("h2DXiMinus"), particle.pt(), particle.y()); + } + if (particle.pdgCode() == -3312) { registry.fill(HIST("hPtXiPlus"), particle.pt()); - if (particle.pdgCode() == 3334) + registry.fill(HIST("h2DXiPlus"), particle.pt(), particle.y()); + } + if (particle.pdgCode() == 3334) { registry.fill(HIST("hPtOmegaMinus"), particle.pt()); - if (particle.pdgCode() == -3334) + registry.fill(HIST("h2DOmegaMinus"), particle.pt(), particle.y()); + } + if (particle.pdgCode() == -3334) { registry.fill(HIST("hPtOmegaPlus"), particle.pt()); + registry.fill(HIST("h2DOmegaPlus"), particle.pt(), particle.y()); + } } } }; @@ -184,9 +199,13 @@ struct cascadeAnalysisMC { {}, }; + Configurable rapidityCut{"rapidityCut", 0.5, "max (absolute) rapidity of cascade candidate"}; + Configurable nRapidityBins{"nRapidityBins", 200, "number of pT bins"}; + void init(InitContext const&) { - AxisSpec ptAxis = {200, 0.0f, 10.0f, "it{p}_{T} (GeV/c)"}; + AxisSpec ptAxis = {200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}; + AxisSpec rapidityAxis = {nRapidityBins, -rapidityCut, rapidityCut, "y"}; AxisSpec massAxisXi = {200, 1.222f, 1.422f, "Inv. Mass (GeV/c^{2})"}; AxisSpec massAxisOmega = {200, 1.572f, 1.772f, "Inv. Mass (GeV/c^{2})"}; @@ -195,6 +214,10 @@ struct cascadeAnalysisMC { registry.add("h2dMassXiPlus", "h2dMassXiPlus", {HistType::kTH2F, {ptAxis, massAxisXi}}); registry.add("h2dMassOmegaMinus", "h2dMassOmegaMinus", {HistType::kTH2F, {ptAxis, massAxisOmega}}); registry.add("h2dMassOmegaPlus", "h2dMassOmegaPlus", {HistType::kTH2F, {ptAxis, massAxisOmega}}); + registry.add("hPtYMassXiMinus", "hPtYMassXiMinus", {HistType::kTH3F, {ptAxis, rapidityAxis, massAxisXi}}); + registry.add("hPtYMassXiPlus", "hPtYMassXiPlus", {HistType::kTH3F, {ptAxis, rapidityAxis, massAxisXi}}); + registry.add("hPtYMassOmegaMinus", "hPtYMassOmegaMinus", {HistType::kTH3F, {ptAxis, rapidityAxis, massAxisOmega}}); + registry.add("hPtYMassOmegaPlus", "hPtYMassOmegaPlus", {HistType::kTH3F, {ptAxis, rapidityAxis, massAxisOmega}}); } // Selection criteria @@ -347,14 +370,16 @@ struct cascadeAnalysisMC { TMath::Abs(casc.mLambda() - 1.115683) < cascadesetting_v0masswindow) { registry.fill(HIST("hCandidateCounter"), 3.5); // pass cascade selections if (casc.sign() < 0) { // FIXME: could be done better... - if (TMath::Abs(casc.yXi()) < 0.5 && lCompatiblePID_Xi && ((!assocMC) || (lPDG == 3312))) { + if (TMath::Abs(casc.yXi()) < rapidityCut && lCompatiblePID_Xi && ((!assocMC) || (lPDG == 3312))) { + registry.fill(HIST("hPtYMassXiMinus"), casc.pt(), casc.yXi(), casc.mXi()); if (!doCentralityStudy) { registry.fill(HIST("h2dMassXiMinus"), casc.pt(), casc.mXi()); } else { registry.fill(HIST("h3dMassXiMinus"), lPercentile, casc.pt(), casc.mXi()); } } - if (TMath::Abs(casc.yOmega()) < 0.5 && lCompatiblePID_Om && ((!assocMC) || (lPDG == 3334))) { + if (TMath::Abs(casc.yOmega()) < rapidityCut && lCompatiblePID_Om && ((!assocMC) || (lPDG == 3334))) { + registry.fill(HIST("hPtYMassOmegaMinus"), casc.pt(), casc.yOmega(), casc.mOmega()); if (!doCentralityStudy) { registry.fill(HIST("h2dMassOmegaMinus"), casc.pt(), casc.mOmega()); } else { @@ -362,14 +387,16 @@ struct cascadeAnalysisMC { } } } else { - if (TMath::Abs(casc.yXi()) < 0.5 && lCompatiblePID_Xi && ((!assocMC) || (lPDG == -3312))) { + if (TMath::Abs(casc.yXi()) < rapidityCut && lCompatiblePID_Xi && ((!assocMC) || (lPDG == -3312))) { + registry.fill(HIST("hPtYMassXiPlus"), casc.pt(), casc.yXi(), casc.mXi()); if (!doCentralityStudy) { registry.fill(HIST("h2dMassXiPlus"), casc.pt(), casc.mXi()); } else { registry.fill(HIST("h3dMassXiPlus"), lPercentile, casc.pt(), casc.mXi()); } } - if (TMath::Abs(casc.yOmega()) < 0.5 && lCompatiblePID_Om && ((!assocMC) || (lPDG == -3334))) { + if (TMath::Abs(casc.yOmega()) < rapidityCut && lCompatiblePID_Om && ((!assocMC) || (lPDG == -3334))) { + registry.fill(HIST("hPtYMassOmegaPlus"), casc.pt(), casc.yOmega(), casc.mOmega()); if (!doCentralityStudy) { registry.fill(HIST("h2dMassOmegaPlus"), casc.pt(), casc.mOmega()); } else { diff --git a/PWGLF/Tasks/Strangeness/cascadecorrelations.cxx b/PWGLF/Tasks/Strangeness/cascadecorrelations.cxx index 152ca106846..ebeed8a76a0 100644 --- a/PWGLF/Tasks/Strangeness/cascadecorrelations.cxx +++ b/PWGLF/Tasks/Strangeness/cascadecorrelations.cxx @@ -19,11 +19,14 @@ #include #include #include +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "ReconstructionDataFormats/Track.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" @@ -34,12 +37,17 @@ #include "Common/DataModel/Centrality.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponse.h" +#include "CCDB/BasicCCDBManager.h" +#include "EventFiltering/Zorro.h" +#include "PWGLF/Utils/inelGt.h" + #include +#include #include #include #include #include -#include +// #include using namespace o2; using namespace o2::soa; @@ -54,6 +62,8 @@ using FullTracksExtIU = soa::Join; using FullTracksExtIUWithPID = soa::Join; +Zorro zorro; + // Add a column to the cascdataext table: IsSelected. // 0 = not selected, 1 = Xi, 2 = both, 3 = Omega namespace o2::aod @@ -67,16 +77,33 @@ DECLARE_SOA_TABLE(CascadeFlags, "AOD", "CASCADEFLAGS", //! using CascDataExtSelected = soa::Join; } // namespace o2::aod -struct cascadeSelector { +using MyCollisions = soa::Join; +using MyCollisionsMult = soa::Join; +using MyCascades = soa::Filtered; +using LabeledCascades = soa::Join; + +struct CascadeSelector { + Service ccdb; + Produces cascflags; // Configurables + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "CCDB url"}; + Configurable useTrigger{"useTrigger", false, "Use trigger selection on skimmed data"}; + Configurable triggerList{"triggerList", "fDoubleXi, fDoubleOmega, fOmegaXi", "List of triggers used to select events"}; + Configurable doTFBorderCut{"doTFBorderCut", true, "Switch to apply TimeframeBorderCut event selection"}; + Configurable doSel8{"doSel8", true, "Switch to apply sel8 event selection"}; + Configurable doNoSameBunchPileUp{"doNoSameBunchPileUp", true, "Switch to apply NoSameBunchPileUp event selection"}; + Configurable INEL{"INEL", 0, "Number of charged tracks within |eta| < 1 has to be greater than value"}; + Configurable maxVertexZ{"maxVertexZ", 10., "Maximum value of z coordinate of PV"}; + + // Tracklevel Configurable tpcNsigmaBachelor{"tpcNsigmaBachelor", 3, "TPC NSigma bachelor"}; Configurable tpcNsigmaProton{"tpcNsigmaProton", 3, "TPC NSigma proton <- lambda"}; Configurable tpcNsigmaPion{"tpcNsigmaPion", 3, "TPC NSigma pion <- lambda"}; Configurable minTPCCrossedRows{"minTPCCrossedRows", 80, "min N TPC crossed rows"}; // TODO: finetune! 80 > 159/2, so no split tracks? Configurable minITSClusters{"minITSClusters", 4, "minimum number of ITS clusters"}; - // Configurable etaTracks{"etaTracks", 0.8, "min/max of eta for tracks"} + Configurable etaTracks{"etaTracks", 1.0, "min/max of eta for tracks"}; // Selection criteria - compatible with core wagon autodetect - copied from cascadeanalysis.cxx //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* @@ -96,56 +123,115 @@ struct cascadeSelector { // TODO: variables as function of Omega mass, only do Xi for now AxisSpec vertexAxis = {100, -10.0f, 10.0f, "cm"}; AxisSpec dcaAxis = {50, 0.0f, 5.0f, "cm"}; - AxisSpec invMassAxis = {100, 1.25f, 1.45f, "Inv. Mass (GeV/c^{2})"}; - AxisSpec ptAxis = {100, 0, 15, "#it{p}_{T}"}; + // AxisSpec invMassAxis = {1000, 1.0f, 2.0f, "Inv. Mass (GeV/c^{2})"}; + AxisSpec invXiMassAxis = {100, 1.28f, 1.38f, "Inv. Mass (GeV/c^{2})"}; + AxisSpec invOmegaMassAxis = {100, 1.62f, 1.72f, "Inv. Mass (GeV/c^{2})"}; + AxisSpec ptAxis = {150, 0, 15, "#it{p}_{T}"}; + AxisSpec rapidityAxis{100, -1.f, 1.f, "y"}; HistogramRegistry registry{ "registry", { // basic selection variables - {"hV0Radius", "hV0Radius", {HistType::kTH3F, {{100, 0.0f, 100.0f, "cm"}, invMassAxis, ptAxis}}}, - {"hCascRadius", "hCascRadius", {HistType::kTH3F, {{100, 0.0f, 100.0f, "cm"}, invMassAxis, ptAxis}}}, - {"hV0CosPA", "hV0CosPA", {HistType::kTH3F, {{100, 0.95f, 1.0f}, invMassAxis, ptAxis}}}, - {"hCascCosPA", "hCascCosPA", {HistType::kTH3F, {{100, 0.95f, 1.0f}, invMassAxis, ptAxis}}}, - {"hDCAPosToPV", "hDCAPosToPV", {HistType::kTH3F, {vertexAxis, invMassAxis, ptAxis}}}, - {"hDCANegToPV", "hDCANegToPV", {HistType::kTH3F, {vertexAxis, invMassAxis, ptAxis}}}, - {"hDCABachToPV", "hDCABachToPV", {HistType::kTH3F, {vertexAxis, invMassAxis, ptAxis}}}, - {"hDCAV0ToPV", "hDCAV0ToPV", {HistType::kTH3F, {vertexAxis, invMassAxis, ptAxis}}}, - {"hDCAV0Dau", "hDCAV0Dau", {HistType::kTH3F, {dcaAxis, invMassAxis, ptAxis}}}, - {"hDCACascDau", "hDCACascDau", {HistType::kTH3F, {dcaAxis, invMassAxis, ptAxis}}}, - {"hLambdaMass", "hLambdaMass", {HistType::kTH3F, {{100, 1.0f, 1.2f, "Inv. Mass (GeV/c^{2})"}, invMassAxis, ptAxis}}}, - - // invariant mass per cut, start with Xi - {"hMassXi0", "Xi inv mass before selections", {HistType::kTH2F, {invMassAxis, ptAxis}}}, - {"hMassXi1", "Xi inv mass after TPCnCrossedRows cut", {HistType::kTH2F, {invMassAxis, ptAxis}}}, - {"hMassXi2", "Xi inv mass after ITSnClusters cut", {HistType::kTH2F, {invMassAxis, ptAxis}}}, - {"hMassXi3", "Xi inv mass after topo cuts", {HistType::kTH2F, {invMassAxis, ptAxis}}}, - {"hMassXi4", "Xi inv mass after V0 daughters PID cut", {HistType::kTH2F, {invMassAxis, ptAxis}}}, - {"hMassXi5", "Xi inv mass after bachelor PID cut", {HistType::kTH2F, {invMassAxis, ptAxis}}}, + {"hV0Radius", "hV0Radius", {HistType::kTH3F, {{100, 0.0f, 100.0f, "cm"}, invXiMassAxis, ptAxis}}}, + {"hCascRadius", "hCascRadius", {HistType::kTH3F, {{100, 0.0f, 100.0f, "cm"}, invXiMassAxis, ptAxis}}}, + {"hV0CosPA", "hV0CosPA", {HistType::kTH3F, {{100, 0.95f, 1.0f}, invXiMassAxis, ptAxis}}}, + {"hCascCosPA", "hCascCosPA", {HistType::kTH3F, {{100, 0.95f, 1.0f}, invXiMassAxis, ptAxis}}}, + {"hDCAPosToPV", "hDCAPosToPV", {HistType::kTH3F, {vertexAxis, invXiMassAxis, ptAxis}}}, + {"hDCANegToPV", "hDCANegToPV", {HistType::kTH3F, {vertexAxis, invXiMassAxis, ptAxis}}}, + {"hDCABachToPV", "hDCABachToPV", {HistType::kTH3F, {vertexAxis, invXiMassAxis, ptAxis}}}, + {"hDCAV0ToPV", "hDCAV0ToPV", {HistType::kTH3F, {vertexAxis, invXiMassAxis, ptAxis}}}, + {"hDCAV0Dau", "hDCAV0Dau", {HistType::kTH3F, {dcaAxis, invXiMassAxis, ptAxis}}}, + {"hDCACascDau", "hDCACascDau", {HistType::kTH3F, {dcaAxis, invXiMassAxis, ptAxis}}}, + {"hLambdaMass", "hLambdaMass", {HistType::kTH3F, {{100, 1.0f, 1.2f, "Inv. Mass (GeV/c^{2})"}, invXiMassAxis, ptAxis}}}, + + {"hMassXiMinus", "hMassXiMinus", {HistType::kTH3F, {invXiMassAxis, ptAxis, rapidityAxis}}}, + {"hMassXiPlus", "hMassXiPlus", {HistType::kTH3F, {invXiMassAxis, ptAxis, rapidityAxis}}}, + {"hMassOmegaMinus", "hMassOmegaMinus", {HistType::kTH3F, {invOmegaMassAxis, ptAxis, rapidityAxis}}}, + {"hMassOmegaPlus", "hMassOmegaPlus", {HistType::kTH3F, {invOmegaMassAxis, ptAxis, rapidityAxis}}}, + + // // invariant mass per cut, start with Xi + // {"hMassXi0", "Xi inv mass before selections", {HistType::kTH2F, {invMassAxis, ptAxis}}}, + // {"hMassXi1", "Xi inv mass after TPCnCrossedRows cut", {HistType::kTH2F, {invMassAxis, ptAxis}}}, + // {"hMassXi2", "Xi inv mass after ITSnClusters cut", {HistType::kTH2F, {invMassAxis, ptAxis}}}, + // {"hMassXi3", "Xi inv mass after topo cuts", {HistType::kTH2F, {invMassAxis, ptAxis}}}, + // {"hMassXi4", "Xi inv mass after V0 daughters PID cut", {HistType::kTH2F, {invMassAxis, ptAxis}}}, + // {"hMassXi5", "Xi inv mass after bachelor PID cut", {HistType::kTH2F, {invMassAxis, ptAxis}}}, // ITS & TPC clusters, with Xi inv mass - {"hTPCnCrossedRowsPos", "hTPCnCrossedRowsPos", {HistType::kTH3F, {{160, -0.5, 159.5, "TPC crossed rows"}, invMassAxis, ptAxis}}}, - {"hTPCnCrossedRowsNeg", "hTPCnCrossedRowsNeg", {HistType::kTH3F, {{160, -0.5, 159.5, "TPC crossed rows"}, invMassAxis, ptAxis}}}, - {"hTPCnCrossedRowsBach", "hTPCnCrossedRowsBach", {HistType::kTH3F, {{160, -0.5, 159.5, "TPC crossed rows"}, invMassAxis, ptAxis}}}, - {"hITSnClustersPos", "hITSnClustersPos", {HistType::kTH3F, {{8, -0.5, 7.5, "number of ITS clusters"}, invMassAxis, ptAxis}}}, - {"hITSnClustersNeg", "hITSnClustersNeg", {HistType::kTH3F, {{8, -0.5, 7.5, "number of ITS clusters"}, invMassAxis, ptAxis}}}, - {"hITSnClustersBach", "hITSnClustersBach", {HistType::kTH3F, {{8, -0.5, 7.5, "number of ITS clusters"}, invMassAxis, ptAxis}}}, + {"hTPCnCrossedRowsPos", "hTPCnCrossedRowsPos", {HistType::kTH3F, {{160, -0.5, 159.5, "TPC crossed rows"}, invXiMassAxis, ptAxis}}}, + {"hTPCnCrossedRowsNeg", "hTPCnCrossedRowsNeg", {HistType::kTH3F, {{160, -0.5, 159.5, "TPC crossed rows"}, invXiMassAxis, ptAxis}}}, + {"hTPCnCrossedRowsBach", "hTPCnCrossedRowsBach", {HistType::kTH3F, {{160, -0.5, 159.5, "TPC crossed rows"}, invXiMassAxis, ptAxis}}}, + {"hITSnClustersPos", "hITSnClustersPos", {HistType::kTH3F, {{8, -0.5, 7.5, "number of ITS clusters"}, invXiMassAxis, ptAxis}}}, + {"hITSnClustersNeg", "hITSnClustersNeg", {HistType::kTH3F, {{8, -0.5, 7.5, "number of ITS clusters"}, invXiMassAxis, ptAxis}}}, + {"hITSnClustersBach", "hITSnClustersBach", {HistType::kTH3F, {{8, -0.5, 7.5, "number of ITS clusters"}, invXiMassAxis, ptAxis}}}, + + {"hTriggerQA", "hTriggerQA", {HistType::kTH1F, {{2, -0.5, 1.5, "Trigger y/n"}}}}, }, }; // Keep track of which selections the candidates pass void init(InitContext const&) { + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + auto h = registry.add("hSelectionStatus", "hSelectionStatus", HistType::kTH1I, {{10, 0, 10, "status"}}); h->GetXaxis()->SetBinLabel(1, "All"); h->GetXaxis()->SetBinLabel(2, "nTPC OK"); h->GetXaxis()->SetBinLabel(3, "nITS OK"); h->GetXaxis()->SetBinLabel(4, "Topo OK"); - h->GetXaxis()->SetBinLabel(5, "V0 PID OK"); - h->GetXaxis()->SetBinLabel(6, "Bach PID OK"); + h->GetXaxis()->SetBinLabel(5, "Track eta OK"); + h->GetXaxis()->SetBinLabel(6, "V0 PID OK"); + h->GetXaxis()->SetBinLabel(7, "Bach PID OK"); + + auto hEventSel = registry.add("hEventSel", "hEventSel", HistType::kTH1I, {{10, 0, 10, "selection criteria"}}); + hEventSel->GetXaxis()->SetBinLabel(1, "All"); + hEventSel->GetXaxis()->SetBinLabel(2, "sel8"); + hEventSel->GetXaxis()->SetBinLabel(3, "INEL0"); + hEventSel->GetXaxis()->SetBinLabel(4, "V_z"); + hEventSel->GetXaxis()->SetBinLabel(5, "NoSameBunchPileUp"); + hEventSel->GetXaxis()->SetBinLabel(6, "Selected events"); } - void process(soa::Join::iterator const& collision, aod::CascDataExt const& Cascades, FullTracksExtIUWithPID const&) + + void process(MyCollisions::iterator const& collision, aod::CascDataExt const& Cascades, FullTracksExtIUWithPID const&, aod::BCsWithTimestamps const&) { - for (auto& casc : Cascades) { + bool evSel = true; + if (useTrigger) { + auto bc = collision.bc_as(); + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), triggerList); + bool eventTrigger = zorro.isSelected(bc.globalBC()); + if (eventTrigger) { + registry.fill(HIST("hTriggerQA"), 1); + } else { + registry.fill(HIST("hTriggerQA"), 0); + evSel = false; + } + } + + // fill event selection based on which selection criteria are applied and passed + // do not skip the collision - this will lead to the cascadeFlag table having less entries than the Cascade table, and therefor not joinable. + registry.fill(HIST("hEventSel"), 0); + if (doSel8 && !collision.sel8()) { + evSel = false; + registry.fill(HIST("hEventSel"), 1); + } else if (collision.multNTracksPVeta1() <= INEL) { + evSel = false; + registry.fill(HIST("hEventSel"), 2); + } else if (std::abs(collision.posZ()) > maxVertexZ) { + evSel = false; + registry.fill(HIST("hEventSel"), 3); + } else if (doNoSameBunchPileUp && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + evSel = false; + registry.fill(HIST("hEventSel"), 4); + } + if (evSel) // passes all selections + registry.fill(HIST("hEventSel"), 5); + + for (auto const& casc : Cascades) { + if (!evSel) { + cascflags(0); + continue; + } // these are the tracks: auto bachTrack = casc.bachelor_as(); @@ -173,23 +259,23 @@ struct cascadeSelector { registry.fill(HIST("hTPCnCrossedRowsBach"), bachTrack.tpcNClsCrossedRows(), casc.mXi(), casc.pt()); registry.fill(HIST("hSelectionStatus"), 0); // all the cascade before selections - registry.fill(HIST("hMassXi0"), casc.mXi(), casc.pt()); + // registry.fill(HIST("hMassXi0"), casc.mXi(), casc.pt()); - // TPC N crossed rows + // TPC N crossed rows todo: check if minTPCCrossedRows > 50 if (posTrack.tpcNClsCrossedRows() < minTPCCrossedRows || negTrack.tpcNClsCrossedRows() < minTPCCrossedRows || bachTrack.tpcNClsCrossedRows() < minTPCCrossedRows) { cascflags(0); continue; } registry.fill(HIST("hSelectionStatus"), 1); // passes nTPC crossed rows - registry.fill(HIST("hMassXi1"), casc.mXi(), casc.pt()); + // registry.fill(HIST("hMassXi1"), casc.mXi(), casc.pt()); - // ITS N clusters + // ITS N clusters todo: check if minITSClusters > 0 if (posTrack.itsNCls() < minITSClusters || negTrack.itsNCls() < minITSClusters || bachTrack.itsNCls() < minITSClusters) { cascflags(0); continue; } registry.fill(HIST("hSelectionStatus"), 2); // passes nITS clusters - registry.fill(HIST("hMassXi2"), casc.mXi(), casc.pt()); + // registry.fill(HIST("hMassXi2"), casc.mXi(), casc.pt()); //// TOPO CUTS //// TODO: improve! double pvx = collision.posX(); @@ -206,7 +292,13 @@ struct cascadeSelector { continue; } registry.fill(HIST("hSelectionStatus"), 3); // passes topo - registry.fill(HIST("hMassXi3"), casc.mXi(), casc.pt()); + // registry.fill(HIST("hMassXi3"), casc.mXi(), casc.pt()); + + if (TMath::Abs(posTrack.eta()) > etaTracks || TMath::Abs(negTrack.eta()) > etaTracks || TMath::Abs(bachTrack.eta()) > etaTracks) { + cascflags(0); + continue; + } + registry.fill(HIST("hSelectionStatus"), 4); // passes track eta // TODO: TOF (for pT > 2 GeV per track?) @@ -235,44 +327,111 @@ struct cascadeSelector { continue; } } - registry.fill(HIST("hSelectionStatus"), 4); // fails at V0 daughters PID - registry.fill(HIST("hMassXi4"), casc.mXi(), casc.pt()); + registry.fill(HIST("hSelectionStatus"), 5); // passes V0 daughters PID + // registry.fill(HIST("hMassXi4"), casc.mXi(), casc.pt()); // Bachelor check if (TMath::Abs(bachTrack.tpcNSigmaPi()) < tpcNsigmaBachelor) { if (TMath::Abs(bachTrack.tpcNSigmaKa()) < tpcNsigmaBachelor) { // consistent with both! cascflags(2); - registry.fill(HIST("hSelectionStatus"), 5); // passes bach PID - registry.fill(HIST("hMassXi5"), casc.mXi(), casc.pt()); + registry.fill(HIST("hSelectionStatus"), 6); // passes bach PID + // registry.fill(HIST("hMassXi5"), casc.mXi(), casc.pt()); + if (casc.sign() < 0) { + registry.fill(HIST("hMassXiMinus"), casc.mXi(), casc.pt(), casc.yXi()); + registry.fill(HIST("hMassOmegaMinus"), casc.mOmega(), casc.pt(), casc.yOmega()); + } else { + registry.fill(HIST("hMassXiPlus"), casc.mXi(), casc.pt(), casc.yXi()); + registry.fill(HIST("hMassOmegaPlus"), casc.mOmega(), casc.pt(), casc.yOmega()); + } continue; } cascflags(1); - registry.fill(HIST("hSelectionStatus"), 5); // passes bach PID - registry.fill(HIST("hMassXi5"), casc.mXi(), casc.pt()); + registry.fill(HIST("hSelectionStatus"), 6); // passes bach PID + // registry.fill(HIST("hMassXi5"), casc.mXi(), casc.pt()); + if (casc.sign() < 0) { + registry.fill(HIST("hMassXiMinus"), casc.mXi(), casc.pt(), casc.yXi()); + } else { + registry.fill(HIST("hMassXiPlus"), casc.mXi(), casc.pt(), casc.yXi()); + } continue; } else if (TMath::Abs(bachTrack.tpcNSigmaKa()) < tpcNsigmaBachelor) { cascflags(3); - registry.fill(HIST("hSelectionStatus"), 5); // passes bach PID + registry.fill(HIST("hSelectionStatus"), 6); // passes bach PID + if (casc.sign() < 0) { + registry.fill(HIST("hMassOmegaMinus"), casc.mOmega(), casc.pt(), casc.yOmega()); + } else { + registry.fill(HIST("hMassOmegaPlus"), casc.mOmega(), casc.pt(), casc.yOmega()); + } continue; } // if we reach here, the bachelor was neither pion nor kaon cascflags(0); } // cascade loop - } // process -}; // struct + } // process +}; // struct -struct cascadeCorrelations { +struct CascadeCorrelations { + Service ccdb; + OutputObj zorroSummary{"zorroSummary"}; + // Configurables + Configurable maxRapidity{"maxRapidity", 0.5, "|y| < maxRapidity"}; Configurable zVertexCut{"zVertexCut", 10, "Cut on PV position"}; - - AxisSpec invMassAxis = {2000, 1.0f, 3.0f, "Inv. Mass (GeV/c^{2})"}; - AxisSpec deltaPhiAxis = {100, -PI / 2, 1.5 * PI, "#Delta#varphi"}; - AxisSpec deltaEtaAxis = {40, -2, 2, "#Delta#eta"}; - AxisSpec ptAxis = {200, 0, 15, "#it{p}_{T}"}; + Configurable nMixedEvents{"nMixedEvents", 10, "Number of events to be mixed"}; + Configurable doEfficiencyCorrection{"doEfficiencyCorrection", true, "flag to do efficiency corrections"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "CCDB url"}; + Configurable useTrigger{"useTrigger", false, "Use trigger selection on skimmed data"}; + Configurable triggerList{"triggerList", "fDoubleXi, fDoubleOmega, fOmegaXi", "List of triggers used to select events"}; + Configurable efficiencyCCDBPath{"efficiencyCCDBPath", "Users/r/rspijker/test/EffTest", "Path of the efficiency corrections"}; + Configurable doTFBorderCut{"doTFBorderCut", true, "Switch to apply TimeframeBorderCut event selection"}; + Configurable doSel8{"doSel8", true, "Switch to apply sel8 event selection"}; + + AxisSpec invMassAxis = {1000, 1.0f, 2.0f, "Inv. Mass (GeV/c^{2})"}; + AxisSpec deltaPhiAxis = {180, -PIHalf, 3 * PIHalf, "#Delta#varphi"}; // 180 is divisible by 18 (tpc sectors) and 20 (run 2 binning) + AxisSpec deltaYAxis = {40, -2 * maxRapidity, 2 * maxRapidity, "#Delta y"}; // TODO: narrower range? + AxisSpec ptAxis = {150, 0, 15, "#it{p}_{T}"}; AxisSpec selectionFlagAxis = {4, -0.5f, 3.5f, "Selection flag of casc candidate"}; AxisSpec vertexAxis = {200, -10.0f, 10.0f, "cm"}; AxisSpec multiplicityAxis{100, 0, 100, "Multiplicity (MultFT0M?)"}; + AxisSpec rapidityAxis{100, -maxRapidity, maxRapidity, "y"}; + + // initialize efficiency maps + TH1D* hEffXiMin; + TH1D* hEffXiPlus; + TH1D* hEffOmegaMin; + TH1D* hEffOmegaPlus; + + // used in MC closure test + Service pdgDB; + o2::pwglf::ParticleCounter mCounter; + + void init(InitContext const&) + { + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + if (doEfficiencyCorrection) { + TList* effList = ccdb->getForTimeStamp(efficiencyCCDBPath, 1); + if (!effList) { + LOGF(fatal, "null ptr in efficiency list!"); + } + hEffXiMin = static_cast(effList->FindObject("hXiMinEff")); + hEffXiPlus = static_cast(effList->FindObject("hXiPlusEff")); + hEffOmegaMin = static_cast(effList->FindObject("hOmegaMinEff")); + hEffOmegaPlus = static_cast(effList->FindObject("hOmegaPlusEff")); + } + + zorroSummary.setObject(zorro.getZorroSummary()); + + mCounter.mPdgDatabase = pdgDB.service; + mCounter.mSelectPrimaries = true; + } + + double getEfficiency(TH1D* h, double pT) + { // TODO: make 2D (rapidity) + // This function returns the value of histogram h corresponding to the x-coordinate pT + return h->GetBinContent(h->GetXaxis()->FindFixBin(pT)); + } HistogramRegistry registry{ "registry", @@ -282,6 +441,12 @@ struct cascadeCorrelations { {"hMassXiPlus", "hMassXiPlus", {HistType::kTH2F, {invMassAxis, ptAxis}}}, {"hMassOmegaMinus", "hMassOmegaMinus", {HistType::kTH2F, {invMassAxis, ptAxis}}}, {"hMassOmegaPlus", "hMassOmegaPlus", {HistType::kTH2F, {invMassAxis, ptAxis}}}, + // efficiency corrected inv mass + {"hMassXiEffCorrected", "hMassXiEffCorrected", {HistType::kTHnSparseF, {invMassAxis, ptAxis, rapidityAxis, vertexAxis, multiplicityAxis}}, true}, + {"hMassOmegaEffCorrected", "hMassOmegaEffCorrected", {HistType::kTHnSparseF, {invMassAxis, ptAxis, rapidityAxis, vertexAxis, multiplicityAxis}}, true}, + + // trigger QA + {"hTriggerQA", "hTriggerQA", {HistType::kTH1F, {{2, -0.5, 1.5, "Trigger y/n"}}}}, // basic selection variables {"hV0Radius", "hV0Radius", {HistType::kTH1F, {{1000, 0.0f, 100.0f, "cm"}}}}, @@ -299,75 +464,105 @@ struct cascadeCorrelations { {"hSelectionFlag", "hSelectionFlag", {HistType::kTH1I, {selectionFlagAxis}}}, {"hAutoCorrelation", "hAutoCorrelation", {HistType::kTH1I, {{4, -0.5f, 3.5f, "Types of SS autocorrelation"}}}}, {"hAutoCorrelationOS", "hAutoCorrelationOS", {HistType::kTH1I, {{2, -1.f, 1.f, "Charge of OS autocorrelated track"}}}}, - {"hPhi", "hPhi", {HistType::kTH1F, {{100, 0, 2 * PI, "#varphi"}}}}, + {"hPhi", "hPhi", {HistType::kTH1F, {{180, 0, TwoPI, "#varphi"}}}}, {"hEta", "hEta", {HistType::kTH1F, {{100, -2, 2, "#eta"}}}}, + {"hRapidityXi", "hRapidityXi", {HistType::kTH1F, {rapidityAxis}}}, + {"hRapidityOmega", "hRapidityOmega", {HistType::kTH1F, {rapidityAxis}}}, // correlation histos {"hDeltaPhiSS", "hDeltaPhiSS", {HistType::kTH1F, {deltaPhiAxis}}}, {"hDeltaPhiOS", "hDeltaPhiOS", {HistType::kTH1F, {deltaPhiAxis}}}, - // THnSparses containing all relevant dimensions, to be extended with e.g. multiplicity - // TODO: maybe use a seperate table/tree for this? - {"hXiXiOS", "hXiXiOS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaEtaAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, selectionFlagAxis, selectionFlagAxis, vertexAxis, multiplicityAxis}}}, - {"hXiXiSS", "hXiXiSS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaEtaAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, selectionFlagAxis, selectionFlagAxis, vertexAxis, multiplicityAxis}}}, - {"hXiOmOS", "hXiOmOS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaEtaAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, selectionFlagAxis, selectionFlagAxis, vertexAxis, multiplicityAxis}}}, - {"hXiOmSS", "hXiOmSS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaEtaAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, selectionFlagAxis, selectionFlagAxis, vertexAxis, multiplicityAxis}}}, - {"hOmXiOS", "hOmXiOS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaEtaAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, selectionFlagAxis, selectionFlagAxis, vertexAxis, multiplicityAxis}}}, - {"hOmXiSS", "hOmXiSS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaEtaAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, selectionFlagAxis, selectionFlagAxis, vertexAxis, multiplicityAxis}}}, - {"hOmOmOS", "hOmOmOS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaEtaAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, selectionFlagAxis, selectionFlagAxis, vertexAxis, multiplicityAxis}}}, - {"hOmOmSS", "hOmOmSS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaEtaAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, selectionFlagAxis, selectionFlagAxis, vertexAxis, multiplicityAxis}}}, - - // ad hoc mixed events + + {"hXiXiOS", "hXiXiOS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"hXiXiSS", "hXiXiSS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"hXiOmOS", "hXiOmOS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"hXiOmSS", "hXiOmSS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"hOmXiOS", "hOmXiOS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"hOmXiSS", "hOmXiSS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"hOmOmOS", "hOmOmOS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"hOmOmSS", "hOmOmSS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + + // Mixed events {"MixedEvents/hMEVz1", "hMEVz1", {HistType::kTH1F, {vertexAxis}}}, {"MixedEvents/hMEVz2", "hMEVz2", {HistType::kTH1F, {vertexAxis}}}, {"MixedEvents/hMEDeltaPhiSS", "hMEDeltaPhiSS", {HistType::kTH1F, {deltaPhiAxis}}}, {"MixedEvents/hMEDeltaPhiOS", "hMEDeltaPhiOS", {HistType::kTH1F, {deltaPhiAxis}}}, - {"MixedEvents/hMEXiXiOS", "hMEXiXiOS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaEtaAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, selectionFlagAxis, selectionFlagAxis, vertexAxis, multiplicityAxis}}}, - {"MixedEvents/hMEXiXiSS", "hMEXiXiSS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaEtaAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, selectionFlagAxis, selectionFlagAxis, vertexAxis, multiplicityAxis}}}, - {"MixedEvents/hMEXiOmOS", "hMEXiOmOS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaEtaAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, selectionFlagAxis, selectionFlagAxis, vertexAxis, multiplicityAxis}}}, - {"MixedEvents/hMEXiOmSS", "hMEXiOmSS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaEtaAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, selectionFlagAxis, selectionFlagAxis, vertexAxis, multiplicityAxis}}}, - {"MixedEvents/hMEOmXiOS", "hMEOmXiOS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaEtaAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, selectionFlagAxis, selectionFlagAxis, vertexAxis, multiplicityAxis}}}, - {"MixedEvents/hMEOmXiSS", "hMEOmXiSS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaEtaAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, selectionFlagAxis, selectionFlagAxis, vertexAxis, multiplicityAxis}}}, - {"MixedEvents/hMEOmOmOS", "hMEOmOmOS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaEtaAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, selectionFlagAxis, selectionFlagAxis, vertexAxis, multiplicityAxis}}}, - {"MixedEvents/hMEOmOmSS", "hMEOmOmSS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaEtaAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, selectionFlagAxis, selectionFlagAxis, vertexAxis, multiplicityAxis}}}, + {"MixedEvents/hMEQA", "hMEQA", {HistType::kTH1I, {{2, 0, 2, "QA for exceptions in ME (this histogram should have 0 entries!)"}}}}, + {"MixedEvents/hMEAutoCorrelation", "hMEAutoCorrelation", {HistType::kTH1I, {{4, -0.5f, 3.5f, "Types of SS autocorrelation"}}}}, + {"MixedEvents/hMEAutoCorrelationOS", "hMEAutoCorrelationOS", {HistType::kTH1I, {{2, -1.f, 1.f, "Charge of OS autocorrelated track"}}}}, + + {"MixedEvents/hMEXiXiOS", "hMEXiXiOS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"MixedEvents/hMEXiXiSS", "hMEXiXiSS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"MixedEvents/hMEXiOmOS", "hMEXiOmOS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"MixedEvents/hMEXiOmSS", "hMEXiOmSS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"MixedEvents/hMEOmXiOS", "hMEOmXiOS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"MixedEvents/hMEOmXiSS", "hMEOmXiSS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"MixedEvents/hMEOmOmOS", "hMEOmOmOS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"MixedEvents/hMEOmOmSS", "hMEOmOmSS", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + + // MC closure + {"MC/hMCPlusMinus", "hMCPlusMinus", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, vertexAxis, multiplicityAxis}}, true}, + {"MC/hMCPlusPlus", "hMCPlusPlus", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, vertexAxis, multiplicityAxis}}, true}, + {"MC/hMCMinusPlus", "hMCMinusPlus", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, vertexAxis, multiplicityAxis}}, true}, + {"MC/hMCMinusMinus", "hMCMinusMinus", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, ptAxis, ptAxis, vertexAxis, multiplicityAxis}}, true}, + + {"MC/hGenMultNoReco", "hGenMultNoReco", {HistType::kTH1I, {{100, 0, 100, "Number of generated charged primaries"}}}}, + {"MC/hGenMultOneReco", "hGenMultOneReco", {HistType::kTH1I, {{100, 0, 100, "Number of generated charged primaries"}}}}, + {"MC/hSplitEvents", "hSplitEvents", {HistType::kTH1I, {{10, 0, 10, "Number of rec. events per gen event"}}}}, }, }; // cascade filter - Filter Selector = aod::cascadeflags::isSelected > 0; - - // Mixed events setup: - using myCascades = soa::Filtered; - using myCollisions = soa::Join; + Filter cascadeSelector = aod::cascadeflags::isSelected > 0; + // Warning: it is not possible to use this axis as configurable due to a bug - however, default values are sensible. SliceCache cache; ConfigurableAxis axisVtxZ{"axisVtxZ", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - ConfigurableAxis axisMult{"axisMult", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 100, 1000}, "Mixing bins - multiplicity"}; - using BinningType = ColumnBinningPolicy>; - BinningType colBinning{{axisVtxZ, axisMult}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. - // Preslice collisionSliceCascades = aod::CascDataExtSelected::collisionId; - SameKindPair pair{colBinning, 5, -1, &cache}; + // ConfigurableAxis axisMult{"axisMult", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 100, 1000}, "Mixing bins - multiplicity"}; + // using BinningType = ColumnBinningPolicy>; + // BinningType colBinning{{axisVtxZ, axisMult}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. + using BinningType = ColumnBinningPolicy; + BinningType colBinning{{axisVtxZ}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. - void processSameEvent(myCollisions::iterator const& collision, myCascades const& Cascades, aod::V0sLinked const&, aod::V0Datas const&, FullTracksExtIU const&) + void processSameEvent(MyCollisionsMult::iterator const& collision, MyCascades const& Cascades, FullTracksExtIU const&, aod::BCsWithTimestamps const&) { - if (!collision.sel8()) { - return; + if (useTrigger) { + auto bc = collision.bc_as(); + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), triggerList); + bool eventTrigger = zorro.isSelected(bc.globalBC()); + if (eventTrigger) { + registry.fill(HIST("hTriggerQA"), 1); + } else { + registry.fill(HIST("hTriggerQA"), 0); + return; + } } + double weight; // Some QA on the cascades - for (auto& casc : Cascades) { + for (auto const& casc : Cascades) { if (casc.isSelected() <= 2) { // not exclusively an Omega --> consistent with Xi or both if (casc.sign() < 0) { registry.fill(HIST("hMassXiMinus"), casc.mXi(), casc.pt()); + weight = 1. / getEfficiency(hEffXiMin, casc.pt()); } else { registry.fill(HIST("hMassXiPlus"), casc.mXi(), casc.pt()); + weight = 1. / getEfficiency(hEffXiPlus, casc.pt()); } + // LOGF(info, "casc pt %f, weight %f", casc.pt(), weight); + registry.fill(HIST("hMassXiEffCorrected"), casc.mXi(), casc.pt(), casc.yXi(), collision.posZ(), collision.multFT0M(), weight); + registry.fill(HIST("hRapidityXi"), casc.yXi()); } if (casc.isSelected() >= 2) { // consistent with Omega or both if (casc.sign() < 0) { registry.fill(HIST("hMassOmegaMinus"), casc.mOmega(), casc.pt()); + weight = 1. / getEfficiency(hEffOmegaMin, casc.pt()); } else { registry.fill(HIST("hMassOmegaPlus"), casc.mOmega(), casc.pt()); + weight = 1. / getEfficiency(hEffOmegaPlus, casc.pt()); } + registry.fill(HIST("hMassOmegaEffCorrected"), casc.mOmega(), casc.pt(), casc.yOmega(), collision.posZ(), collision.multFT0M(), weight); + registry.fill(HIST("hRapidityOmega"), casc.yOmega()); } registry.fill(HIST("hV0Radius"), casc.v0radius()); registry.fill(HIST("hCascRadius"), casc.cascradius()); @@ -404,17 +599,17 @@ struct cascadeCorrelations { int negIdAssoc = assoc.negTrackId(); // calculate angular correlations - double deta = trigger.eta() - assoc.eta(); - double dphi = RecoDecay::constrainAngle(trigger.phi() - assoc.phi(), -0.5 * PI); + double dphi = RecoDecay::constrainAngle(trigger.phi() - assoc.phi(), -PIHalf); double invMassXiTrigg = trigger.mXi(); double invMassOmTrigg = trigger.mOmega(); double invMassXiAssoc = assoc.mXi(); double invMassOmAssoc = assoc.mOmega(); - double weight = 1.; // Will be changed by Efficiency-correction + double weightTrigg = 1.; + double weightAssoc = 1.; - // Fill the correct histograms based on same-sign or opposite-sign + // split into opposite-sign or same-sign if (trigger.sign() * assoc.sign() < 0) { // opposite-sign // check for autocorrelations between mis-identified kaons (omega bach) and protons (lambda daughter) TODO: improve logic? if (trigger.isSelected() >= 2) { @@ -441,12 +636,36 @@ struct cascadeCorrelations { continue; } } - registry.fill(HIST("hDeltaPhiOS"), dphi); - registry.fill(HIST("hXiXiOS"), dphi, deta, trigger.pt(), assoc.pt(), invMassXiTrigg, invMassXiAssoc, trigger.isSelected(), assoc.isSelected(), collision.posZ(), collision.multFT0M(), weight); - registry.fill(HIST("hXiOmOS"), dphi, deta, trigger.pt(), assoc.pt(), invMassXiTrigg, invMassOmAssoc, trigger.isSelected(), assoc.isSelected(), collision.posZ(), collision.multFT0M(), weight); - registry.fill(HIST("hOmXiOS"), dphi, deta, trigger.pt(), assoc.pt(), invMassOmTrigg, invMassXiAssoc, trigger.isSelected(), assoc.isSelected(), collision.posZ(), collision.multFT0M(), weight); - registry.fill(HIST("hOmOmOS"), dphi, deta, trigger.pt(), assoc.pt(), invMassOmTrigg, invMassOmAssoc, trigger.isSelected(), assoc.isSelected(), collision.posZ(), collision.multFT0M(), weight); + // Fill the different THnSparses depending on PID logic (important for rapidity & inv mass information) + if (trigger.isSelected() <= 2 && TMath::Abs(trigger.yXi()) < maxRapidity) { // trigger Xi + if (doEfficiencyCorrection) + weightTrigg = trigger.sign() < 0 ? 1. / getEfficiency(hEffXiMin, trigger.pt()) : 1. / getEfficiency(hEffXiPlus, trigger.pt()); + if (assoc.isSelected() <= 2 && TMath::Abs(assoc.yXi()) < maxRapidity) { // assoc Xi + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? 1. / getEfficiency(hEffXiMin, assoc.pt()) : 1. / getEfficiency(hEffXiPlus, assoc.pt()); + registry.fill(HIST("hXiXiOS"), dphi, trigger.yXi() - assoc.yXi(), trigger.pt(), assoc.pt(), invMassXiTrigg, invMassXiAssoc, collision.posZ(), collision.multFT0M(), weightTrigg * weightAssoc); + } + if (assoc.isSelected() >= 2 && TMath::Abs(assoc.yOmega()) < maxRapidity) { // assoc Omega + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? 1. / getEfficiency(hEffOmegaMin, assoc.pt()) : 1. / getEfficiency(hEffOmegaPlus, assoc.pt()); + registry.fill(HIST("hXiOmOS"), dphi, trigger.yXi() - assoc.yOmega(), trigger.pt(), assoc.pt(), invMassXiTrigg, invMassOmAssoc, collision.posZ(), collision.multFT0M(), weightTrigg * weightAssoc); + } + } + if (trigger.isSelected() >= 2 && TMath::Abs(trigger.yOmega()) < maxRapidity) { // trigger Omega + if (doEfficiencyCorrection) + weightTrigg = trigger.sign() < 0 ? 1. / getEfficiency(hEffOmegaMin, trigger.pt()) : 1. / getEfficiency(hEffOmegaPlus, trigger.pt()); + if (assoc.isSelected() <= 2 && TMath::Abs(assoc.yXi()) < maxRapidity) { // assoc Xi + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? 1. / getEfficiency(hEffXiMin, assoc.pt()) : 1. / getEfficiency(hEffXiPlus, assoc.pt()); + registry.fill(HIST("hOmXiOS"), dphi, trigger.yOmega() - assoc.yXi(), trigger.pt(), assoc.pt(), invMassOmTrigg, invMassXiAssoc, collision.posZ(), collision.multFT0M(), weightTrigg * weightAssoc); + } + if (assoc.isSelected() >= 2 && TMath::Abs(assoc.yOmega()) < maxRapidity) { // assoc Omega + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? 1. / getEfficiency(hEffOmegaMin, assoc.pt()) : 1. / getEfficiency(hEffOmegaPlus, assoc.pt()); + registry.fill(HIST("hOmOmOS"), dphi, trigger.yOmega() - assoc.yOmega(), trigger.pt(), assoc.pt(), invMassOmTrigg, invMassOmAssoc, collision.posZ(), collision.multFT0M(), weightTrigg * weightAssoc); + } + } } else { // same-sign // make sure to check for autocorrelations - only possible in same-sign correlations (if PID is correct) if (posIdTrigg == posIdAssoc && negIdTrigg == negIdAssoc) { @@ -482,24 +701,53 @@ struct cascadeCorrelations { } } registry.fill(HIST("hDeltaPhiSS"), dphi); - registry.fill(HIST("hXiXiSS"), dphi, deta, trigger.pt(), assoc.pt(), invMassXiTrigg, invMassXiAssoc, trigger.isSelected(), assoc.isSelected(), collision.posZ(), collision.multFT0M(), weight); - registry.fill(HIST("hXiOmSS"), dphi, deta, trigger.pt(), assoc.pt(), invMassXiTrigg, invMassOmAssoc, trigger.isSelected(), assoc.isSelected(), collision.posZ(), collision.multFT0M(), weight); - registry.fill(HIST("hOmXiSS"), dphi, deta, trigger.pt(), assoc.pt(), invMassOmTrigg, invMassXiAssoc, trigger.isSelected(), assoc.isSelected(), collision.posZ(), collision.multFT0M(), weight); - registry.fill(HIST("hOmOmSS"), dphi, deta, trigger.pt(), assoc.pt(), invMassOmTrigg, invMassOmAssoc, trigger.isSelected(), assoc.isSelected(), collision.posZ(), collision.multFT0M(), weight); + // Fill the different THnSparses depending on PID logic (important for rapidity & inv mass information) + if (trigger.isSelected() <= 2 && TMath::Abs(trigger.yXi()) < maxRapidity) { // trigger Xi + if (doEfficiencyCorrection) + weightTrigg = trigger.sign() < 0 ? 1. / getEfficiency(hEffXiMin, trigger.pt()) : 1. / getEfficiency(hEffXiPlus, trigger.pt()); + if (assoc.isSelected() <= 2 && TMath::Abs(assoc.yXi()) < maxRapidity) { // assoc Xi + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? 1. / getEfficiency(hEffXiMin, assoc.pt()) : 1. / getEfficiency(hEffXiPlus, assoc.pt()); + registry.fill(HIST("hXiXiSS"), dphi, trigger.yXi() - assoc.yXi(), trigger.pt(), assoc.pt(), invMassXiTrigg, invMassXiAssoc, collision.posZ(), collision.multFT0M(), weightTrigg * weightAssoc); + } + if (assoc.isSelected() >= 2 && TMath::Abs(assoc.yOmega()) < maxRapidity) { // assoc Omega + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? 1. / getEfficiency(hEffOmegaMin, assoc.pt()) : 1. / getEfficiency(hEffOmegaPlus, assoc.pt()); + registry.fill(HIST("hXiOmSS"), dphi, trigger.yXi() - assoc.yOmega(), trigger.pt(), assoc.pt(), invMassXiTrigg, invMassOmAssoc, collision.posZ(), collision.multFT0M(), weightTrigg * weightAssoc); + } + } + if (trigger.isSelected() >= 2 && TMath::Abs(trigger.yOmega()) < maxRapidity) { // trigger Omega + if (doEfficiencyCorrection) + weightTrigg = trigger.sign() < 0 ? 1. / getEfficiency(hEffOmegaMin, trigger.pt()) : 1. / getEfficiency(hEffOmegaPlus, trigger.pt()); + if (assoc.isSelected() <= 2 && TMath::Abs(assoc.yXi()) < maxRapidity) { // assoc Xi + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? 1. / getEfficiency(hEffXiMin, assoc.pt()) : 1. / getEfficiency(hEffXiPlus, assoc.pt()); + registry.fill(HIST("hOmXiSS"), dphi, trigger.yOmega() - assoc.yXi(), trigger.pt(), assoc.pt(), invMassOmTrigg, invMassXiAssoc, collision.posZ(), collision.multFT0M(), weightTrigg * weightAssoc); + } + if (assoc.isSelected() >= 2 && TMath::Abs(assoc.yOmega()) < maxRapidity) { // assoc Omega + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? 1. / getEfficiency(hEffOmegaMin, assoc.pt()) : 1. / getEfficiency(hEffOmegaPlus, assoc.pt()); + registry.fill(HIST("hOmOmSS"), dphi, trigger.yOmega() - assoc.yOmega(), trigger.pt(), assoc.pt(), invMassOmTrigg, invMassOmAssoc, collision.posZ(), collision.multFT0M(), weightTrigg * weightAssoc); + } + } } } // correlations - } // process same event + } // process same event - void processMixedEvent(myCollisions const& /*collisions*/, myCascades const& /*Cascades*/, - aod::V0sLinked const&, aod::V0Datas const&, FullTracksExtIU const&) + void processMixedEvent(MyCollisionsMult const& collisions, MyCascades const& Cascades, FullTracksExtIU const&) { - // mixed events + auto cascadesTuple = std::make_tuple(Cascades); + SameKindPair pair{colBinning, nMixedEvents, -1, collisions, cascadesTuple, &cache}; - for (auto& [col1, cascades1, col2, cascades2] : pair) { + for (auto const& [col1, cascades1, col2, cascades2] : pair) { if (!col1.sel8() || !col2.sel8()) continue; if (TMath::Abs(col1.posZ()) > zVertexCut || TMath::Abs(col2.posZ()) > zVertexCut) continue; + if (col1.globalIndex() == col2.globalIndex()) { + registry.fill(HIST("hMEQA"), 0.5); + continue; + } registry.fill(HIST("MixedEvents/hMEVz1"), col1.posZ()); registry.fill(HIST("MixedEvents/hMEVz2"), col2.posZ()); @@ -514,41 +762,216 @@ struct cascadeCorrelations { auto trigger = *triggerAddress; auto assoc = *assocAddress; - double deta = trigger.eta() - assoc.eta(); - double dphi = RecoDecay::constrainAngle(trigger.phi() - assoc.phi(), -0.5 * PI); + if (trigger.collisionId() == assoc.collisionId()) { + registry.fill(HIST("hMEQA"), 1.5); + continue; + } + + double dphi = RecoDecay::constrainAngle(trigger.phi() - assoc.phi(), -PIHalf); double invMassXiTrigg = trigger.mXi(); double invMassOmTrigg = trigger.mOmega(); double invMassXiAssoc = assoc.mXi(); double invMassOmAssoc = assoc.mOmega(); - double weight = 1.; // Will be changed by Efficiency-correction + // V0 daughter track ID's used for autocorrelation check + int posIdTrigg = trigger.posTrackId(); + int negIdTrigg = trigger.negTrackId(); + int posIdAssoc = assoc.posTrackId(); + int negIdAssoc = assoc.negTrackId(); + + double weightTrigg = 1.; + double weightAssoc = 1.; if (trigger.sign() * assoc.sign() < 0) { // opposite-sign + + // check for autocorrelations between mis-identified kaons (omega bach) and protons (lambda daughter) TODO: improve logic? + if (trigger.isSelected() >= 2) { + if (trigger.sign() > 0 && trigger.bachelorId() == posIdAssoc) { + // K+ from trigger Omega is the same as proton from assoc lambda + registry.fill(HIST("MixedEvents/hMEAutoCorrelationOS"), 1); + continue; + } + if (trigger.sign() < 0 && trigger.bachelorId() == negIdAssoc) { + // K- from trigger Omega is the same as antiproton from assoc antilambda + registry.fill(HIST("MixedEvents/hMEAutoCorrelationOS"), -1); + continue; + } + } + if (assoc.isSelected() >= 2) { + if (assoc.sign() > 0 && assoc.bachelorId() == posIdTrigg) { + // K+ from assoc Omega is the same as proton from trigger lambda + registry.fill(HIST("MixedEvents/hMEAutoCorrelationOS"), 1); + continue; + } + if (assoc.sign() < 0 && assoc.bachelorId() == negIdTrigg) { + // K- from assoc Omega is the same as antiproton from trigger antilambda + registry.fill(HIST("MixedEvents/hMEAutoCorrelationOS"), -1); + continue; + } + } + registry.fill(HIST("MixedEvents/hMEDeltaPhiOS"), dphi); - registry.fill(HIST("MixedEvents/hMEXiXiOS"), dphi, deta, trigger.pt(), assoc.pt(), invMassXiTrigg, invMassXiAssoc, trigger.isSelected(), assoc.isSelected(), col1.posZ(), col1.multFT0M(), weight); - registry.fill(HIST("MixedEvents/hMEXiOmOS"), dphi, deta, trigger.pt(), assoc.pt(), invMassXiTrigg, invMassOmAssoc, trigger.isSelected(), assoc.isSelected(), col1.posZ(), col1.multFT0M(), weight); - registry.fill(HIST("MixedEvents/hMEOmXiOS"), dphi, deta, trigger.pt(), assoc.pt(), invMassOmTrigg, invMassXiAssoc, trigger.isSelected(), assoc.isSelected(), col1.posZ(), col1.multFT0M(), weight); - registry.fill(HIST("MixedEvents/hMEOmOmOS"), dphi, deta, trigger.pt(), assoc.pt(), invMassOmTrigg, invMassOmAssoc, trigger.isSelected(), assoc.isSelected(), col1.posZ(), col1.multFT0M(), weight); + + // Fill the different THnSparses depending on PID logic (important for rapidity & inv mass information) + if (trigger.isSelected() <= 2 && TMath::Abs(trigger.yXi()) < maxRapidity) { // trigger Xi + if (doEfficiencyCorrection) + weightTrigg = trigger.sign() < 0 ? 1. / getEfficiency(hEffXiMin, trigger.pt()) : 1. / getEfficiency(hEffXiPlus, trigger.pt()); + if (assoc.isSelected() <= 2 && TMath::Abs(assoc.yXi()) < maxRapidity) { // assoc Xi + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? 1. / getEfficiency(hEffXiMin, assoc.pt()) : 1. / getEfficiency(hEffXiPlus, assoc.pt()); + registry.fill(HIST("MixedEvents/hMEXiXiOS"), dphi, trigger.yXi() - assoc.yXi(), trigger.pt(), assoc.pt(), invMassXiTrigg, invMassXiAssoc, col1.posZ(), col1.multFT0M(), weightTrigg * weightAssoc); + } + if (assoc.isSelected() >= 2 && TMath::Abs(assoc.yOmega()) < maxRapidity) { // assoc Omega + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? 1. / getEfficiency(hEffOmegaMin, assoc.pt()) : 1. / getEfficiency(hEffOmegaPlus, assoc.pt()); + registry.fill(HIST("MixedEvents/hMEXiOmOS"), dphi, trigger.yXi() - assoc.yOmega(), trigger.pt(), assoc.pt(), invMassXiTrigg, invMassOmAssoc, col1.posZ(), col1.multFT0M(), weightTrigg * weightAssoc); + } + } + if (trigger.isSelected() >= 2 && TMath::Abs(trigger.yOmega()) < maxRapidity) { // trigger Omega + if (doEfficiencyCorrection) + weightTrigg = trigger.sign() < 0 ? 1. / getEfficiency(hEffOmegaMin, trigger.pt()) : 1. / getEfficiency(hEffOmegaPlus, trigger.pt()); + if (assoc.isSelected() <= 2 && TMath::Abs(assoc.yXi()) < maxRapidity) { // assoc Xi + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? 1. / getEfficiency(hEffXiMin, assoc.pt()) : 1. / getEfficiency(hEffXiPlus, assoc.pt()); + registry.fill(HIST("MixedEvents/hMEOmXiOS"), dphi, trigger.yOmega() - assoc.yXi(), trigger.pt(), assoc.pt(), invMassOmTrigg, invMassXiAssoc, col1.posZ(), col1.multFT0M(), weightTrigg * weightAssoc); + } + if (assoc.isSelected() >= 2 && TMath::Abs(assoc.yOmega()) < maxRapidity) { // assoc Omega + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? 1. / getEfficiency(hEffOmegaMin, assoc.pt()) : 1. / getEfficiency(hEffOmegaPlus, assoc.pt()); + registry.fill(HIST("MixedEvents/hMEOmOmOS"), dphi, trigger.yOmega() - assoc.yOmega(), trigger.pt(), assoc.pt(), invMassOmTrigg, invMassOmAssoc, col1.posZ(), col1.multFT0M(), weightTrigg * weightAssoc); + } + } } else { // same sign + // make sure to check for autocorrelations - only possible in same-sign correlations (if PID is correct) + if (posIdTrigg == posIdAssoc && negIdTrigg == negIdAssoc) { + // LOGF(info, "same v0 in SS correlation! %d %d", v0dataTrigg.v0Id(), v0dataAssoc.v0Id()); + registry.fill(HIST("MixedEvents/hMEAutoCorrelation"), 0); + continue; + } + int bachIdTrigg = trigger.bachelorId(); + int bachIdAssoc = assoc.bachelorId(); + + if (bachIdTrigg == bachIdAssoc) { + // LOGF(info, "same bachelor in SS correlation! %d %d", bachIdTrigg, bachIdAssoc); + registry.fill(HIST("MixedEvents/hMEAutoCorrelation"), 1); + continue; + } + // check for same tracks in v0's of cascades + if (negIdTrigg == negIdAssoc || posIdTrigg == posIdAssoc) { + // LOGF(info, "cascades have a v0-track in common in SS correlation!"); + registry.fill(HIST("MixedEvents/hMEAutoCorrelation"), 2); + continue; + } + if (trigger.sign() < 0) { // neg cascade + if (negIdTrigg == bachIdAssoc || negIdAssoc == bachIdTrigg) { + // LOGF(info, "bach of casc == v0-pion of other casc in neg SS correlation!"); + registry.fill(HIST("MixedEvents/hMEAutoCorrelation"), 3); + continue; + } + } else { // pos cascade + if (posIdTrigg == bachIdAssoc || posIdAssoc == bachIdTrigg) { + // LOGF(info, "bach of casc == v0-pion of other casc in pos SS correlation!"); + registry.fill(HIST("MixedEvents/hMEAutoCorrelation"), 3); + continue; + } + } + registry.fill(HIST("MixedEvents/hMEDeltaPhiSS"), dphi); - registry.fill(HIST("MixedEvents/hMEXiXiSS"), dphi, deta, trigger.pt(), assoc.pt(), invMassXiTrigg, invMassXiAssoc, trigger.isSelected(), assoc.isSelected(), col1.posZ(), col1.multFT0M(), weight); - registry.fill(HIST("MixedEvents/hMEXiOmSS"), dphi, deta, trigger.pt(), assoc.pt(), invMassXiTrigg, invMassOmAssoc, trigger.isSelected(), assoc.isSelected(), col1.posZ(), col1.multFT0M(), weight); - registry.fill(HIST("MixedEvents/hMEOmXiSS"), dphi, deta, trigger.pt(), assoc.pt(), invMassOmTrigg, invMassXiAssoc, trigger.isSelected(), assoc.isSelected(), col1.posZ(), col1.multFT0M(), weight); - registry.fill(HIST("MixedEvents/hMEOmOmSS"), dphi, deta, trigger.pt(), assoc.pt(), invMassOmTrigg, invMassOmAssoc, trigger.isSelected(), assoc.isSelected(), col1.posZ(), col1.multFT0M(), weight); - } + + if (trigger.isSelected() <= 2 && TMath::Abs(trigger.yXi()) < maxRapidity) { // trigger Xi + if (doEfficiencyCorrection) + weightTrigg = trigger.sign() < 0 ? 1. / getEfficiency(hEffXiMin, trigger.pt()) : 1. / getEfficiency(hEffXiPlus, trigger.pt()); + if (assoc.isSelected() <= 2 && TMath::Abs(assoc.yXi()) < maxRapidity) { // assoc Xi + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? 1. / getEfficiency(hEffXiMin, assoc.pt()) : 1. / getEfficiency(hEffXiPlus, assoc.pt()); + registry.fill(HIST("MixedEvents/hMEXiXiSS"), dphi, trigger.yXi() - assoc.yXi(), trigger.pt(), assoc.pt(), invMassXiTrigg, invMassXiAssoc, col1.posZ(), col1.multFT0M(), weightTrigg * weightAssoc); + } + if (assoc.isSelected() >= 2 && TMath::Abs(assoc.yOmega()) < maxRapidity) { // assoc Omega + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? 1. / getEfficiency(hEffOmegaMin, assoc.pt()) : 1. / getEfficiency(hEffOmegaPlus, assoc.pt()); + registry.fill(HIST("MixedEvents/hMEXiOmSS"), dphi, trigger.yXi() - assoc.yOmega(), trigger.pt(), assoc.pt(), invMassXiTrigg, invMassOmAssoc, col1.posZ(), col1.multFT0M(), weightTrigg * weightAssoc); + } + } + if (trigger.isSelected() >= 2 && TMath::Abs(trigger.yOmega()) < maxRapidity) { // trigger Omega + if (doEfficiencyCorrection) + weightTrigg = trigger.sign() < 0 ? 1. / getEfficiency(hEffOmegaMin, trigger.pt()) : 1. / getEfficiency(hEffOmegaPlus, trigger.pt()); + if (assoc.isSelected() <= 2 && TMath::Abs(assoc.yXi()) < maxRapidity) { // assoc Xi + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? 1. / getEfficiency(hEffXiMin, assoc.pt()) : 1. / getEfficiency(hEffXiPlus, assoc.pt()); + registry.fill(HIST("MixedEvents/hMEOmXiSS"), dphi, trigger.yOmega() - assoc.yXi(), trigger.pt(), assoc.pt(), invMassOmTrigg, invMassXiAssoc, col1.posZ(), col1.multFT0M(), weightTrigg * weightAssoc); + } + if (assoc.isSelected() >= 2 && TMath::Abs(assoc.yOmega()) < maxRapidity) { // assoc Omega + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? 1. / getEfficiency(hEffOmegaMin, assoc.pt()) : 1. / getEfficiency(hEffOmegaPlus, assoc.pt()); + registry.fill(HIST("MixedEvents/hMEOmOmSS"), dphi, trigger.yOmega() - assoc.yOmega(), trigger.pt(), assoc.pt(), invMassOmTrigg, invMassOmAssoc, col1.posZ(), col1.multFT0M(), weightTrigg * weightAssoc); + } + } + } // same sign } // correlations - } // collisions - } // process mixed events + } // collisions + } // process mixed events + + Filter genCascadesFilter = nabs(aod::mcparticle::pdgCode) == 3312; + + void processMC(aod::McCollision const&, soa::SmallGroups> const& collisions, soa::Filtered const& genCascades, aod::McParticles const& mcParticles) + { + // Let's do some logic on matched reconstructed collisions - if there less or more than one, fill some QA and skip the rest + double FT0mult = -1; // non-sensible default value just in case + double vtxz = -999.; // non-sensible default value just in case + if (collisions.size() < 1) { + registry.fill(HIST("MC/hSplitEvents"), 0); + registry.fill(HIST("MC/hGenMultNoReco"), mCounter.countFT0A(mcParticles) + mCounter.countFT0C(mcParticles)); + return; + } else if (collisions.size() == 1) { + registry.fill(HIST("MC/hSplitEvents"), 1); + registry.fill(HIST("MC/hGenMultOneReco"), mCounter.countFT0A(mcParticles) + mCounter.countFT0C(mcParticles)); + for (auto const& collision : collisions) { // not really a loop, as there is only one collision + FT0mult = collision.multFT0M(); + vtxz = collision.posZ(); + } + } else if (collisions.size() > 1) { + registry.fill(HIST("MC/hSplitEvents"), collisions.size()); + return; + } + + for (auto& [c0, c1] : combinations(genCascades, genCascades)) { // combinations automatically applies strictly upper in case of 2 identical tables + // Define the trigger as the particle with the highest pT. As we can't swap the cascade tables themselves, we swap the addresses and later dereference them + auto* triggerAddress = &c0; + auto* assocAddress = &c1; + if (assocAddress->pt() > triggerAddress->pt()) { + std::swap(triggerAddress, assocAddress); + } + auto trigger = *triggerAddress; + auto assoc = *assocAddress; + + double dphi = RecoDecay::constrainAngle(trigger.phi() - assoc.phi(), -PIHalf); + + if (trigger.pdgCode() < 0) { // anti-trigg --> Plus + if (assoc.pdgCode() < 0) { // anti-assoc --> Plus + registry.fill(HIST("MC/hMCPlusPlus"), dphi, trigger.y() - assoc.y(), trigger.pt(), assoc.pt(), vtxz, FT0mult); + } else { // assoc --> Minus + registry.fill(HIST("MC/hMCPlusMinus"), dphi, trigger.y() - assoc.y(), trigger.pt(), assoc.pt(), vtxz, FT0mult); + } + } else { // trig --> Minus + if (assoc.pdgCode() < 0) { // anti-assoc --> Plus + registry.fill(HIST("MC/hMCMinusPlus"), dphi, trigger.y() - assoc.y(), trigger.pt(), assoc.pt(), vtxz, FT0mult); + } else { + registry.fill(HIST("MC/hMCMinusMinus"), dphi, trigger.y() - assoc.y(), trigger.pt(), assoc.pt(), vtxz, FT0mult); + } + } + } + } - PROCESS_SWITCH(cascadeCorrelations, processSameEvent, "Process same events", true); - PROCESS_SWITCH(cascadeCorrelations, processMixedEvent, "Process mixed events", true); + PROCESS_SWITCH(CascadeCorrelations, processSameEvent, "Process same events", true); + PROCESS_SWITCH(CascadeCorrelations, processMixedEvent, "Process mixed events", true); + PROCESS_SWITCH(CascadeCorrelations, processMC, "Process MC", false); -}; // struct +}; // struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/Strangeness/cascpolsp.cxx b/PWGLF/Tasks/Strangeness/cascpolsp.cxx new file mode 100644 index 00000000000..237fe8ba375 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/cascpolsp.cxx @@ -0,0 +1,462 @@ +// 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. +// Cascade polarisation task +// prottay.das@cern.ch + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TRandom3.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" +#include "TF1.h" + +#include "PWGLF/DataModel/SPCalibrationTables.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/TrackSelection.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "Common/DataModel/FT0Corrected.h" +#include "PWGLF/DataModel/cascqaanalysis.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +using dauTracks = soa::Join; +using v0Candidates = soa::Join; + +struct cascpolsp { + + Service ccdb; + Service pdg; + + // fill output + Configurable additionalEvSel{"additionalEvSel", false, "additionalEvSel"}; + Configurable additionalEvSel3{"additionalEvSel3", false, "additionalEvSel3"}; + Configurable QxyNbins{"QxyNbins", 100, "Number of bins in QxQy histograms"}; + Configurable lbinQxy{"lbinQxy", -5.0, "lower bin value in QxQy histograms"}; + Configurable hbinQxy{"hbinQxy", 5.0, "higher bin value in QxQy histograms"}; + + // events + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutCentralityMax{"cfgCutCentralityMax", 50.0f, "Accepted maximum Centrality"}; + Configurable cfgCutCentralityMin{"cfgCutCentralityMin", 30.0f, "Accepted minimum Centrality"}; + // track cut + Configurable cfgCutPT{"cfgCutPT", 0.15, "PT cut on daughter track"}; + Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; + + // Configs for V0 + Configurable ConfV0PtMin{"ConfV0PtMin", 0.f, "Minimum transverse momentum of V0"}; + Configurable ConfV0Rap{"ConfV0Rap", 0.8f, "Rapidity range of V0"}; + Configurable ConfV0DCADaughMax{"ConfV0DCADaughMax", 0.2f, "Maximum DCA between the V0 daughters"}; + Configurable ConfV0CPAMin{"ConfV0CPAMin", 0.9998f, "Minimum CPA of V0"}; + Configurable ConfV0TranRadV0Min{"ConfV0TranRadV0Min", 1.5f, "Minimum transverse radius"}; + Configurable ConfV0TranRadV0Max{"ConfV0TranRadV0Max", 100.f, "Maximum transverse radius"}; + Configurable cMaxV0DCA{"cMaxV0DCA", 1.2, "Maximum V0 DCA to PV"}; + Configurable cMinV0DCA{"cMinV0DCA", 0.05, "Minimum V0 daughters DCA to PV"}; + Configurable cMaxV0LifeTime{"cMaxV0LifeTime", 20, "Maximum V0 life time"}; + + // config for V0 daughters + Configurable ConfDaughEta{"ConfDaughEta", 0.8f, "V0 Daugh sel: max eta"}; + Configurable cfgDaughPrPt{"cfgDaughPrPt", 0.4, "minimum daughter proton pt"}; + Configurable cfgDaughPiPt{"cfgDaughPiPt", 0.2, "minimum daughter pion pt"}; + Configurable ConfDaughTPCnclsMin{"ConfDaughTPCnclsMin", 50.f, "V0 Daugh sel: Min. nCls TPC"}; + Configurable ConfDaughDCAMin{"ConfDaughDCAMin", 0.08f, "V0 Daugh sel: Max. DCA Daugh to PV (cm)"}; + Configurable ConfDaughPIDCuts{"ConfDaughPIDCuts", 3, "PID selections for Lambda daughters"}; + + // config for cascades + Configurable cfgcasc_radius{"cfgcasc_radius", 0.8f, "Cascade radius"}; + Configurable cfgcasc_casccospa{"cfgcasc_casccospa", 0.99f, "Cascade cosPA"}; + Configurable cfgcasc_v0cospa{"cfgcasc_v0cospa", 0.99f, "Cascade v0cosPA"}; + Configurable cfgcasc_dcav0topv{"cfgcasc_dcav0topv", 0.3f, "Cascade dcav0"}; + Configurable cfgcasc_dcabachtopv{"cfgcasc_dcabachtopv", 0.3f, "Cascade dcabach"}; + Configurable cfgcasc_dcacascdau{"cfgcasc_dcacascdau", 0.3f, "Cascade dcadau"}; + Configurable cfgcasc_dcav0dau{"cfgcasc_dcav0dau", 0.3f, "Cascade dcav0dau"}; + Configurable cfgcasc_mlambdawindow{"cfgcasc_mlambdawindow", 0.43f, "Cascade masswindow"}; + Configurable cfgcascv0_radius{"cfgcascv0_radius", 0.8f, "Cascade v0 radius"}; + Configurable cfgcasc_dcapostopv{"cfgcasc_dcapostopv", 0.3f, "Cascade dcapostoPV"}; + Configurable cfgcasc_dcanegtopv{"cfgcasc_dcanegtopv", 0.3f, "Cascade dcanegtoPV"}; + Configurable cfgcasc_lowmass{"cfgcasc_lowmass", 1.311, "Cascade lowmass cut"}; + Configurable cfgcasc_highmass{"cfgcasc_highmass", 1.331, "Cascade highmass cut"}; + + // config for histograms + Configurable IMNbins{"IMNbins", 100, "Number of bins in invariant mass"}; + Configurable lbinIM{"lbinIM", 1.0, "lower bin value in IM histograms"}; + Configurable hbinIM{"hbinIM", 1.2, "higher bin value in IM histograms"}; + Configurable resNbins{"resNbins", 50, "Number of bins in reso"}; + Configurable lbinres{"lbinres", 0.0, "lower bin value in reso histograms"}; + Configurable hbinres{"hbinres", 10.0, "higher bin value in reso histograms"}; + + ConfigurableAxis configcentAxis{"configcentAxis", {VARIABLE_WIDTH, 0.0, 10.0, 40.0, 80.0}, "Cent V0M"}; + ConfigurableAxis configthnAxispT{"configthnAxisPt", {VARIABLE_WIDTH, 0.2, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.5, 8.0, 10.0, 100.0}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis configetaAxis{"configetaAxis", {VARIABLE_WIDTH, -0.8, -0.4, -0.2, 0, 0.2, 0.4, 0.8}, "Eta"}; + ConfigurableAxis configthnAxisPol{"configthnAxisPol", {VARIABLE_WIDTH, -1.0, -0.6, -0.2, 0, 0.2, 0.4, 0.8}, "Pol"}; + ConfigurableAxis configphiAxis{"configphiAxis", {VARIABLE_WIDTH, 0.0, 0.2, 0.4, 0.8, 1.0, 2.0, 2.5, 3.0, 4.0, 5.0, 5.5, 6.28}, "PhiAxis"}; + + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + AxisSpec thnAxisres{resNbins, lbinres, hbinres, "Reso"}; + AxisSpec thnAxisInvMass{IMNbins, lbinIM, hbinIM, "#it{M} (GeV/#it{c}^{2})"}; + + histos.add("hCentrality", "Centrality distribution", kTH1F, {{configcentAxis}}); + histos.add("hpRes", "hpRes", HistType::kTHnSparseF, {configcentAxis, thnAxisres}); + + histos.add("hSparseLambdaPolA", "hSparseLambdaPolA", HistType::kTHnSparseF, {thnAxisInvMass, configthnAxispT, configetaAxis, configthnAxisPol, configcentAxis}, true); + histos.add("hSparseLambdaPolC", "hSparseLambdaPolC", HistType::kTHnSparseF, {thnAxisInvMass, configthnAxispT, configetaAxis, configthnAxisPol, configcentAxis}, true); + histos.add("hSparseAntiLambdaPolA", "hSparseAntiLambdaPolA", HistType::kTHnSparseF, {thnAxisInvMass, configthnAxispT, configetaAxis, configthnAxisPol, configcentAxis}, true); + histos.add("hSparseAntiLambdaPolC", "hSparseAntiLambdaPolC", HistType::kTHnSparseF, {thnAxisInvMass, configthnAxispT, configetaAxis, configthnAxisPol, configcentAxis}, true); + + histos.add("hSparseLambda_corr1a", "hSparseLambda_corr1a", HistType::kTHnSparseF, {thnAxisInvMass, configthnAxispT, configetaAxis, configthnAxisPol, configcentAxis}, true); + histos.add("hSparseLambda_corr1b", "hSparseLambda_corr1b", HistType::kTHnSparseF, {thnAxisInvMass, configthnAxispT, configetaAxis, configthnAxisPol, configcentAxis}, true); + histos.add("hSparseLambda_corr1c", "hSparseLambda_corr1c", HistType::kTHnSparseF, {thnAxisInvMass, configthnAxispT, configetaAxis, configphiAxis, configcentAxis}, true); + histos.add("hSparseAntiLambda_corr1a", "hSparseAntiLambda_corr1a", HistType::kTHnSparseF, {thnAxisInvMass, configthnAxispT, configetaAxis, configthnAxisPol, configcentAxis}, true); + histos.add("hSparseAntiLambda_corr1b", "hSparseAntiLambda_corr1b", HistType::kTHnSparseF, {thnAxisInvMass, configthnAxispT, configetaAxis, configthnAxisPol, configcentAxis}, true); + histos.add("hSparseAntiLambda_corr1c", "hSparseAntiLambda_corr1c", HistType::kTHnSparseF, {thnAxisInvMass, configthnAxispT, configetaAxis, configphiAxis, configcentAxis}, true); + + histos.add("hSparseLambda_corr2a", "hSparseLambda_corr2a", HistType::kTHnSparseF, {thnAxisInvMass, configthnAxispT, configetaAxis, configthnAxisPol, configcentAxis}, true); + histos.add("hSparseLambda_corr2b", "hSparseLambda_corr2b", HistType::kTHnSparseF, {thnAxisInvMass, configthnAxispT, configetaAxis, configthnAxisPol, configcentAxis}, true); + histos.add("hSparseAntiLambda_corr2a", "hSparseAntiLambda_corr2a", HistType::kTHnSparseF, {thnAxisInvMass, configthnAxispT, configetaAxis, configthnAxisPol, configcentAxis}, true); + histos.add("hSparseAntiLambda_corr2b", "hSparseAntiLambda_corr2b", HistType::kTHnSparseF, {thnAxisInvMass, configthnAxispT, configetaAxis, configthnAxisPol, configcentAxis}, true); + } + + template + bool SelectionV0(Collision const& collision, V0 const& candidate) + { + if (TMath::Abs(candidate.dcav0topv()) > cMaxV0DCA) { + return false; + } + const float pT = candidate.pt(); + const float tranRad = candidate.v0radius(); + const float dcaDaughv0 = TMath::Abs(candidate.dcaV0daughters()); + const float cpav0 = candidate.v0cosPA(); + + float CtauLambda = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massLambda; + + if (pT < ConfV0PtMin) { + return false; + } + if (TMath::Abs(candidate.dcapostopv()) < cMinV0DCA) { + return false; + } + if (TMath::Abs(candidate.dcanegtopv()) < cMinV0DCA) { + return false; + } + if (dcaDaughv0 > ConfV0DCADaughMax) { + return false; + } + if (cpav0 < ConfV0CPAMin) { + return false; + } + if (tranRad < ConfV0TranRadV0Min) { + return false; + } + if (tranRad > ConfV0TranRadV0Max) { + return false; + } + if (TMath::Abs(CtauLambda) > cMaxV0LifeTime) { + return false; + } + if (TMath::Abs(candidate.yLambda()) > ConfV0Rap) { + return false; + } + return true; + } + template + bool isSelectedV0Daughter(T const& track, int pid) + { + const auto eta = track.eta(); + const auto pt = track.pt(); + const auto tpcNClsF = track.tpcNClsFound(); + if (track.tpcNClsCrossedRows() < 70) { + return false; + } + if (TMath::Abs(eta) > ConfDaughEta) { + return false; + } + if (tpcNClsF < ConfDaughTPCnclsMin) { + return false; + } + if (track.tpcCrossedRowsOverFindableCls() < 0.8) { + return false; + } + /* + if (TMath::Abs(dcaXY) < ConfDaughDCAMin) { + return false; + }*/ + + if (pid == 0 && TMath::Abs(track.tpcNSigmaPr()) > ConfDaughPIDCuts) { + return false; + } + if (pid == 1 && TMath::Abs(track.tpcNSigmaPi()) > ConfDaughPIDCuts) { + return false; + } + + if (pid == 0 && pt < cfgDaughPrPt) { + return false; + } + if (pid == 1 && pt < cfgDaughPiPt) { + return false; + } + + return true; + } + + double GetPhiInRange(double phi) + { + double result = phi; + while (result < 0) { + result = result + 2. * TMath::Pi(); + } + while (result > 2. * TMath::Pi()) { + result = result - 2. * TMath::Pi(); + } + return result; + } + + template + bool IsCascAccepted(TCascade casc, collision_t collision) + { + + if (casc.cascradius() < cfgcasc_radius) + return false; + if (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cfgcasc_casccospa) + return false; + if (casc.dcabachtopv() < cfgcasc_dcabachtopv) + return false; + if (casc.dcacascdaughters() > cfgcasc_dcacascdau) + return false; + if (std::fabs(casc.mLambda() - o2::constants::physics::MassLambda0) > cfgcasc_mlambdawindow) + return false; + + if (casc.v0radius() < cfgcascv0_radius) + return false; + if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cfgcasc_v0cospa) + return false; + if (TMath::Abs(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < cfgcasc_dcav0topv) + return false; + if (TMath::Abs(casc.dcaV0daughters()) > cfgcasc_dcav0dau) + return false; + if (TMath::Abs(casc.dcapostopv()) < cfgcasc_dcapostopv) + return false; + if (TMath::Abs(casc.dcanegtopv()) < cfgcasc_dcanegtopv) + return false; + if (casc.mXi() < cfgcasc_lowmass || casc.mXi() > cfgcasc_highmass) + return false; + + return true; + } + + bool shouldReject(bool LambdaTag, bool aLambdaTag, + const ROOT::Math::PxPyPzMVector& Lambdadummy, + const ROOT::Math::PxPyPzMVector& AntiLambdadummy) + { + const double minMass = 1.105; + const double maxMass = 1.125; + return (LambdaTag && aLambdaTag && + (Lambdadummy.M() > minMass && Lambdadummy.M() < maxMass) && + (AntiLambdadummy.M() > minMass && AntiLambdadummy.M() < maxMass)); + } + + void fillHistograms(bool tag1, bool tag2, const ROOT::Math::PxPyPzMVector& particle, + const ROOT::Math::PxPyPzMVector& daughter, + double psiZDCC, double psiZDCA, double centrality, + double candmass, double candpt, double candeta) + { + + ROOT::Math::Boost boost{particle.BoostToCM()}; + auto fourVecDauCM = boost(daughter); + auto phiangle = TMath::ATan2(fourVecDauCM.Py(), fourVecDauCM.Px()); + + auto phiminuspsiC = GetPhiInRange(phiangle - psiZDCC); + auto phiminuspsiA = GetPhiInRange(phiangle - psiZDCA); + auto cosThetaStar = fourVecDauCM.Pz() / fourVecDauCM.P(); + auto sinThetaStar = TMath::Sqrt(1 - (cosThetaStar * cosThetaStar)); + auto PolC = TMath::Sin(phiminuspsiC); + auto PolA = TMath::Sin(phiminuspsiA); + + auto sinPhiStar = TMath::Sin(GetPhiInRange(phiangle)); + auto cosPhiStar = TMath::Cos(GetPhiInRange(phiangle)); + auto sinThetaStarcosphiphiStar = sinThetaStar * TMath::Cos(2 * GetPhiInRange(particle.Phi() - phiangle)); + auto phiphiStar = GetPhiInRange(particle.Phi() - phiangle); + + // Fill histograms using constructed names + if (tag2) { + histos.fill(HIST("hSparseAntiLambdaPolA"), candmass, candpt, candeta, PolA, centrality); + histos.fill(HIST("hSparseAntiLambdaPolC"), candmass, candpt, candeta, PolC, centrality); + histos.fill(HIST("hSparseAntiLambda_corr1a"), candmass, candpt, candeta, sinPhiStar, centrality); + histos.fill(HIST("hSparseAntiLambda_corr1b"), candmass, candpt, candeta, cosPhiStar, centrality); + histos.fill(HIST("hSparseAntiLambda_corr1c"), candmass, candpt, candeta, phiphiStar, centrality); + histos.fill(HIST("hSparseAntiLambda_corr2a"), candmass, candpt, candeta, sinThetaStar, centrality); + histos.fill(HIST("hSparseAntiLambda_corr2b"), candmass, candpt, candeta, sinThetaStarcosphiphiStar, centrality); + } + if (tag1) { + histos.fill(HIST("hSparseLambdaPolA"), candmass, candpt, candeta, PolA, centrality); + histos.fill(HIST("hSparseLambdaPolC"), candmass, candpt, candeta, PolC, centrality); + histos.fill(HIST("hSparseLambda_corr1a"), candmass, candpt, candeta, sinPhiStar, centrality); + histos.fill(HIST("hSparseLambda_corr1b"), candmass, candpt, candeta, cosPhiStar, centrality); + histos.fill(HIST("hSparseLambda_corr1c"), candmass, candpt, candeta, phiphiStar, centrality); + histos.fill(HIST("hSparseLambda_corr2a"), candmass, candpt, candeta, sinThetaStar, centrality); + histos.fill(HIST("hSparseLambda_corr2b"), candmass, candpt, candeta, sinThetaStarcosphiphiStar, centrality); + } + } + + ROOT::Math::PxPyPzMVector Lambda, AntiLambda, Lambdadummy, AntiLambdadummy, Proton, Pion, AntiProton, AntiPion, fourVecDauCM, LC; + ROOT::Math::XYZVector threeVecDauCM, threeVecDauCMXY; + double phiangle = 0.0; + double massLambda = o2::constants::physics::MassLambda; + double massPr = o2::constants::physics::MassProton; + double massPi = o2::constants::physics::MassPionCharged; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter centralityFilter = (nabs(aod::cent::centFT0C) < cfgCutCentralityMax && nabs(aod::cent::centFT0C) > cfgCutCentralityMin); + Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPT); + + using EventCandidates = soa::Filtered>; + using AllTrackCandidates = soa::Filtered>; + using CascCandidates = soa::Join; + + void processcascData(EventCandidates::iterator const& collision, aod::CascDataExt const& Cascades, AllTrackCandidates const&, aod::BCs const&) + { + + if (!collision.sel8()) { + return; + } + auto centrality = collision.centFT0C(); + if (!collision.triggereventsp()) { + return; + } + + if (additionalEvSel && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + + if (additionalEvSel3 && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + return; + } + + auto psiZDCC = collision.psiZDCC(); + auto psiZDCA = collision.psiZDCA(); + + histos.fill(HIST("hCentrality"), centrality); + histos.fill(HIST("hpRes"), centrality, (TMath::Cos(GetPhiInRange(psiZDCA - psiZDCC)))); + + for (auto& casc : Cascades) { + + auto negtrack = casc.negTrack_as(); + auto postrack = casc.posTrack_as(); + auto bachtrack = casc.bachelor_as(); + + bool CascAcc = IsCascAccepted(casc, collision); + + if (!CascAcc) + continue; + + int LambdaTag = 0; + int aLambdaTag = 0; + + const auto signpos = postrack.sign(); + const auto signneg = negtrack.sign(); + const auto signbach = bachtrack.sign(); + + if (signpos < 0 || signneg > 0 || signbach == 0) { + continue; + } + + if (isSelectedV0Daughter(postrack, 0) && isSelectedV0Daughter(negtrack, 1)) { + LambdaTag = 1; + } + if (isSelectedV0Daughter(negtrack, 0) && isSelectedV0Daughter(postrack, 1)) { + aLambdaTag = 1; + } + + if (!isSelectedV0Daughter(bachtrack, 1)) // quality track selection for bachelor track + continue; + + if (!LambdaTag && !aLambdaTag) + continue; + + if (casc.sign() != signbach) // cascade sign to be equal to bachelor sign + continue; + + if (casc.sign() > 0) { + AntiProton = ROOT::Math::PxPyPzMVector(casc.pxneg(), casc.pyneg(), casc.pzneg(), massPr); + Pion = ROOT::Math::PxPyPzMVector(casc.pxpos(), casc.pypos(), casc.pzpos(), massPi); + AntiLambdadummy = AntiProton + Pion; + + } else { + Proton = ROOT::Math::PxPyPzMVector(casc.pxpos(), casc.pypos(), casc.pzpos(), massPr); + AntiPion = ROOT::Math::PxPyPzMVector(casc.pxneg(), casc.pyneg(), casc.pzneg(), massPi); + Lambdadummy = Proton + AntiPion; + } + + if (shouldReject(LambdaTag, aLambdaTag, Lambdadummy, AntiLambdadummy)) { + continue; + } + + int taga = LambdaTag; + int tagb = aLambdaTag; + + if (LambdaTag) { + Lambda = Proton + AntiPion; + tagb = 0; + fillHistograms(taga, tagb, Lambda, Proton, psiZDCC, psiZDCA, centrality, Lambda.M(), Lambda.Pt(), Lambda.Eta()); + } + + tagb = aLambdaTag; + if (aLambdaTag) { + AntiLambda = AntiProton + Pion; + taga = 0; + fillHistograms(taga, tagb, AntiLambda, AntiProton, psiZDCC, psiZDCA, centrality, AntiLambda.M(), AntiLambda.Pt(), AntiLambda.Eta()); + } + } + } + PROCESS_SWITCH(cascpolsp, processcascData, "Process cascade data", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"cascpolsp"})}; +} diff --git a/PWGLF/Tasks/Strangeness/cascpostprocessing.cxx b/PWGLF/Tasks/Strangeness/cascpostprocessing.cxx index c89a299b15c..d92e48733b5 100644 --- a/PWGLF/Tasks/Strangeness/cascpostprocessing.cxx +++ b/PWGLF/Tasks/Strangeness/cascpostprocessing.cxx @@ -158,8 +158,8 @@ struct cascpostprocessing { registry.add("hPt", "hPt", {HistType::kTH1F, {ptAxis}}); registry.add("hCascMinusInvMassvsPt", "hCascMinusInvMassvsPt", HistType::kTH2F, {ptAxis, massAxis}); registry.add("hCascPlusInvMassvsPt", "hCascPlusInvMassvsPt", HistType::kTH2F, {ptAxis, massAxis}); - registry.add("hCascMinusInvMassvsPt_FT0M", "hCascMinusInvMassvsPt_FT0M", HistType::kTH3F, {isMC ? nChargedFT0MGenAxis : centFT0MAxis, ptAxis, massAxis}); - registry.add("hCascPlusInvMassvsPt_FT0M", "hCascPlusInvMassvsPt_FT0M", HistType::kTH3F, {isMC ? nChargedFT0MGenAxis : centFT0MAxis, ptAxis, massAxis}); + registry.add("hCascMinusInvMassvsPt_FT0M", "hCascMinusInvMassvsPt_FT0M", HistType::kTH3F, {centFT0MAxis, ptAxis, massAxis}); + registry.add("hCascPlusInvMassvsPt_FT0M", "hCascPlusInvMassvsPt_FT0M", HistType::kTH3F, {centFT0MAxis, ptAxis, massAxis}); registry.add("hCascMinusInvMassvsPt_FV0A", "hCascMinusInvMassvsPt_FV0A", HistType::kTH3F, {centFV0AAxis, ptAxis, massAxis}); registry.add("hCascPlusInvMassvsPt_FV0A", "hCascPlusInvMassvsPt_FV0A", HistType::kTH3F, {centFV0AAxis, ptAxis, massAxis}); registry.add("hXiMinusInvMassvsPt_BefSels", "hXiMinusInvMassvsPt_BefSels", HistType::kTH2F, {ptAxis, ximassAxis}); @@ -213,17 +213,22 @@ struct cascpostprocessing { registry.add("hCascMinusEtaBach", "hCascMinusEtaBach", {HistType::kTH1F, {{100, -1.0f, 1.0f}}}); // Info for eff x acc from MC - registry.add("hPtCascPlusTrueRec", "hPtCascPlusTrueRec", {HistType::kTH3F, {ptAxis, rapidityAxis, nChargedFT0MGenAxis}}); - registry.add("hPtCascMinusTrueRec", "hPtCascMinusTrueRec", {HistType::kTH3F, {ptAxis, rapidityAxis, nChargedFT0MGenAxis}}); + registry.add("hPtCascPlusTrueRec", "hPtCascPlusTrueRec", {HistType::kTH3F, {ptAxis, rapidityAxis, centFT0MAxis}}); + registry.add("hPtCascMinusTrueRec", "hPtCascMinusTrueRec", {HistType::kTH3F, {ptAxis, rapidityAxis, centFT0MAxis}}); + + registry.add("hCascMinusMassvsPtTrueRec", "hCascMinusMassvsPtTrueRec", {HistType::kTH3F, {ptAxis, massAxis, centFT0MAxis}}); + registry.add("hCascPlusMassvsPtTrueRec", "hCascPlusMassvsPtTrueRec", {HistType::kTH3F, {ptAxis, massAxis, centFT0MAxis}}); + registry.add("hCascMinusMassvsPtBG", "hCascMinusMassvsPtBG", {HistType::kTH2F, {ptAxis, massAxis}}); + registry.add("hCascPlusMassvsPtBG", "hCascPlusMassvsPtBG", {HistType::kTH2F, {ptAxis, massAxis}}); if (isMC) { - registry.add("hPtXiPlusTrue", "hPtXiPlusTrue", {HistType::kTH3F, {ptAxis, rapidityAxis, nChargedFT0MGenAxis}}); - registry.add("hPtXiMinusTrue", "hPtXiMinusTrue", {HistType::kTH3F, {ptAxis, rapidityAxis, nChargedFT0MGenAxis}}); - registry.add("hPtOmegaPlusTrue", "hPtOmegaPlusTrue", {HistType::kTH3F, {ptAxis, rapidityAxis, nChargedFT0MGenAxis}}); - registry.add("hPtOmegaMinusTrue", "hPtOmegaMinusTrue", {HistType::kTH3F, {ptAxis, rapidityAxis, nChargedFT0MGenAxis}}); - registry.add("hPtXiPlusTrueAssocWithSelColl", "hPtXiPlusTrueAssocWithSelColl", {HistType::kTH3F, {ptAxis, rapidityAxis, nChargedFT0MGenAxis}}); - registry.add("hPtXiMinusTrueAssocWithSelColl", "hPtXiMinusTrueAssocWithSelColl", {HistType::kTH3F, {ptAxis, rapidityAxis, nChargedFT0MGenAxis}}); - registry.add("hPtOmegaPlusTrueAssocWithSelColl", "hPtOmegaPlusTrueAssocWithSelColl", {HistType::kTH3F, {ptAxis, rapidityAxis, nChargedFT0MGenAxis}}); - registry.add("hPtOmegaMinusTrueAssocWithSelColl", "hPtOmegaMinusTrueAssocWithSelColl", {HistType::kTH3F, {ptAxis, rapidityAxis, nChargedFT0MGenAxis}}); + registry.add("hPtXiPlusTrue", "hPtXiPlusTrue", {HistType::kTH3F, {ptAxis, rapidityAxis, centFT0MAxis}}); + registry.add("hPtXiMinusTrue", "hPtXiMinusTrue", {HistType::kTH3F, {ptAxis, rapidityAxis, centFT0MAxis}}); + registry.add("hPtOmegaPlusTrue", "hPtOmegaPlusTrue", {HistType::kTH3F, {ptAxis, rapidityAxis, centFT0MAxis}}); + registry.add("hPtOmegaMinusTrue", "hPtOmegaMinusTrue", {HistType::kTH3F, {ptAxis, rapidityAxis, centFT0MAxis}}); + registry.add("hPtXiPlusTrueAssocWithSelColl", "hPtXiPlusTrueAssocWithSelColl", {HistType::kTH3F, {ptAxis, rapidityAxis, centFT0MAxis}}); + registry.add("hPtXiMinusTrueAssocWithSelColl", "hPtXiMinusTrueAssocWithSelColl", {HistType::kTH3F, {ptAxis, rapidityAxis, centFT0MAxis}}); + registry.add("hPtOmegaPlusTrueAssocWithSelColl", "hPtOmegaPlusTrueAssocWithSelColl", {HistType::kTH3F, {ptAxis, rapidityAxis, centFT0MAxis}}); + registry.add("hPtOmegaMinusTrueAssocWithSelColl", "hPtOmegaMinusTrueAssocWithSelColl", {HistType::kTH3F, {ptAxis, rapidityAxis, centFT0MAxis}}); } } @@ -483,19 +488,25 @@ struct cascpostprocessing { if (candidate.sign() < 0) { if (isCorrectlyRec) { - registry.fill(HIST("hPtCascMinusTrueRec"), candidate.pt(), rapidity, candidate.multFT0M()); // 3rd axis is N charged in FT0M region from gen. MC + registry.fill(HIST("hPtCascMinusTrueRec"), candidate.pt(), rapidity, candidate.centFT0M()); // 3rd axis is from MC calibration + registry.fill(HIST("hCascMinusMassvsPtTrueRec"), candidate.pt(), invmass, candidate.centFT0M()); + } else { + registry.fill(HIST("hCascMinusMassvsPtBG"), candidate.pt(), invmass); } registry.fill(HIST("hCascMinusInvMassvsPt"), candidate.pt(), invmass); - registry.fill(HIST("hCascMinusInvMassvsPt_FT0M"), candidate.multFT0M(), candidate.pt(), invmass); - registry.fill(HIST("hCascMinusInvMassvsPt_FV0A"), isMC ? 0 : candidate.multFV0A(), candidate.pt(), invmass); + registry.fill(HIST("hCascMinusInvMassvsPt_FT0M"), candidate.centFT0M(), candidate.pt(), invmass); + registry.fill(HIST("hCascMinusInvMassvsPt_FV0A"), candidate.centFV0A(), candidate.pt(), invmass); } if (candidate.sign() > 0) { if (isCorrectlyRec) { - registry.fill(HIST("hPtCascPlusTrueRec"), candidate.pt(), rapidity, candidate.multFT0M()); // 3rd axis is N charged in FT0M region from gen. MC + registry.fill(HIST("hPtCascPlusTrueRec"), candidate.pt(), rapidity, candidate.centFT0M()); // 3rd axis is from MC calibration + registry.fill(HIST("hCascPlusMassvsPtTrueRec"), candidate.pt(), invmass, candidate.centFT0M()); + } else { + registry.fill(HIST("hCascPlusMassvsPtBG"), candidate.pt(), invmass); } registry.fill(HIST("hCascPlusInvMassvsPt"), candidate.pt(), invmass); - registry.fill(HIST("hCascPlusInvMassvsPt_FT0M"), candidate.multFT0M(), candidate.pt(), invmass); - registry.fill(HIST("hCascPlusInvMassvsPt_FV0A"), isMC ? 0 : candidate.multFV0A(), candidate.pt(), invmass); + registry.fill(HIST("hCascPlusInvMassvsPt_FT0M"), candidate.centFT0M(), candidate.pt(), invmass); + registry.fill(HIST("hCascPlusInvMassvsPt_FV0A"), candidate.centFV0A(), candidate.pt(), invmass); } } } @@ -529,18 +540,21 @@ struct cascpostprocessing { break; } + if (TMath::Abs(genCascade.y()) > rap) + continue; + // Histos of generated cascades from generated events with accepted z vrtx + chosen event type (evSelFlag) (for signal loss correction) if (genCascade.pdgCode() == -3312) { - registry.fill(HIST("hPtXiPlusTrue"), genCascade.pt(), genCascade.y(), genCascade.nChInFT0M()); + registry.fill(HIST("hPtXiPlusTrue"), genCascade.pt(), genCascade.y(), genCascade.centFT0M()); } if (genCascade.pdgCode() == 3312) { - registry.fill(HIST("hPtXiMinusTrue"), genCascade.pt(), genCascade.y(), genCascade.nChInFT0M()); + registry.fill(HIST("hPtXiMinusTrue"), genCascade.pt(), genCascade.y(), genCascade.centFT0M()); } if (genCascade.pdgCode() == -3334) { - registry.fill(HIST("hPtOmegaPlusTrue"), genCascade.pt(), genCascade.y(), genCascade.nChInFT0M()); + registry.fill(HIST("hPtOmegaPlusTrue"), genCascade.pt(), genCascade.y(), genCascade.centFT0M()); } if (genCascade.pdgCode() == 3334) { - registry.fill(HIST("hPtOmegaMinusTrue"), genCascade.pt(), genCascade.y(), genCascade.nChInFT0M()); + registry.fill(HIST("hPtOmegaMinusTrue"), genCascade.pt(), genCascade.y(), genCascade.centFT0M()); } // Histos of generated cascades from generated events with good z vrtx + chosen event type (evSelFlag) + associated to the accepted reconstructed event of the same type (for signal loss + efficiency x acceptance correction) @@ -566,16 +580,16 @@ struct cascpostprocessing { } if (genCascade.pdgCode() == -3312) { - registry.fill(HIST("hPtXiPlusTrueAssocWithSelColl"), genCascade.pt(), genCascade.y(), genCascade.nChInFT0M()); + registry.fill(HIST("hPtXiPlusTrueAssocWithSelColl"), genCascade.pt(), genCascade.y(), genCascade.centFT0M()); } if (genCascade.pdgCode() == 3312) { - registry.fill(HIST("hPtXiMinusTrueAssocWithSelColl"), genCascade.pt(), genCascade.y(), genCascade.nChInFT0M()); + registry.fill(HIST("hPtXiMinusTrueAssocWithSelColl"), genCascade.pt(), genCascade.y(), genCascade.centFT0M()); } if (genCascade.pdgCode() == -3334) { - registry.fill(HIST("hPtOmegaPlusTrueAssocWithSelColl"), genCascade.pt(), genCascade.y(), genCascade.nChInFT0M()); + registry.fill(HIST("hPtOmegaPlusTrueAssocWithSelColl"), genCascade.pt(), genCascade.y(), genCascade.centFT0M()); } if (genCascade.pdgCode() == 3334) { - registry.fill(HIST("hPtOmegaMinusTrueAssocWithSelColl"), genCascade.pt(), genCascade.y(), genCascade.nChInFT0M()); + registry.fill(HIST("hPtOmegaMinusTrueAssocWithSelColl"), genCascade.pt(), genCascade.y(), genCascade.centFT0M()); } } } diff --git a/PWGLF/Tasks/Strangeness/derivedcascadeanalysis.cxx b/PWGLF/Tasks/Strangeness/derivedcascadeanalysis.cxx index af9ce69646b..95a25f589e3 100644 --- a/PWGLF/Tasks/Strangeness/derivedcascadeanalysis.cxx +++ b/PWGLF/Tasks/Strangeness/derivedcascadeanalysis.cxx @@ -9,9 +9,12 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // -/// \ post processing for Cascade analysis runing on derived data +/// \file derivedcascadeanalysis.cxx +/// \brief Tasks processing derived data for Cascade analysis in PbPb collisions /// \author Lucia Anna Tarasovicova (lucia.anna.husova@cern.ch) +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -20,6 +23,7 @@ #include "ReconstructionDataFormats/Track.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" +#include "Common/CCDB/ctpRateFetcher.h" #include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGLF/DataModel/LFStrangenessPIDTables.h" #include "Common/Core/TrackSelection.h" @@ -27,18 +31,26 @@ #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/PIDResponse.h" +#include "Framework/StaticFor.h" + +#include "Framework/ConfigParamSpec.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/LHCConstants.h" +#include "Framework/HistogramRegistry.h" +#include "DataFormatsFT0/Digit.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "MetadataHelper.h" +#include "DataFormatsParameters/AggregatedRunInfo.h" #include #include #include #include -#include #include -#include -#include -#include -#include -#include "Framework/ASoAHelpers.h" // constants const float ctauxiPDG = 4.91; // from PDG @@ -49,611 +61,1214 @@ using namespace o2::framework; using namespace o2::framework::expressions; using std::array; -struct derivedCascadeAnalysis { - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; +using DauTracks = soa::Join; +using CascMCCandidates = soa::Join; - Configurable zVertexCut{"zVertexCut", 10, "Cut on PV position"}; +struct Derivedcascadeanalysis { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for QA histograms"}; - + ConfigurableAxis axisOccupancy{"axisOccupancy", {VARIABLE_WIDTH, 0.0f, 250.0f, 500.0f, 750.0f, 1000.0f, 1500.0f, 2000.0f, 3000.0f, 4500.0f, 6000.0f, 8000.0f, 10000.0f, 25000.0f}, "occupancy axis"}; + ConfigurableAxis axisOccupancyFt0{"axisOccupancyFt0", {VARIABLE_WIDTH, 0.0f, 2500.0f, 5000.0f, 7500.0f, 10000.0f, 15000.0f, 20000.0f, 30000.0f, 45000.0f, 60000.0f, 80000.0f, 100000.0f, 250000.0f}, "occupancy axis for the FT0 definition"}; + ConfigurableAxis axisNch{"axisNch", {500, 0.0f, +5000.0f}, "Number of charged particles in |y| < 0.5"}; ConfigurableAxis vertexZ{"vertexZ", {30, -15.0f, 15.0f}, ""}; - ConfigurableAxis axisXiMass{"axisXiMass", {200, 1.222f, 1.422f}, ""}; - ConfigurableAxis axisOmegaMass{"axisOmegaMass", {200, 1.572f, 1.772f}, ""}; + ConfigurableAxis axisMass{"axisMass", {200, 1.222f, 1.422f}, "range of invariant mass, in case of omega take 1.572f, 1.772f"}; + ConfigurableAxis axisIR{"axisIR", {510, -1, 50}, "Binning for the interaction rate (kHz)"}; Configurable isXi{"isXi", 1, "Apply cuts for Xi identification"}; - Configurable isMC{"isMC", false, "MC data are processed"}; - Configurable doBefSelCheck{"doBefSelCheck", false, "Fill mass histograms of all candidates before selections"}; - Configurable doPtDepCutStudy{"doPtDepCutStudy", false, "Fill histogram with a cutting paramer"}; - Configurable doGoodPVFT0EventCut{"doGoodPVFT0EventCut", true, "check for the PV position diffrence when estimated from tracks and FT0"}; - Configurable doITSTPCvertexEventCut{"doITSTPCvertexEventCut", true, "checks the presence of at least one ITS-TPC track"}; - Configurable doSameBunchPileUpEventCut{"doSameBunchPileUpEventCut", true, "removes events associated with the same \"found-by-T0\" bunch crossing"}; - Configurable doVertexTOFmatch{"doVertexTOFmatch", false, "Checks wherher at least one of vertex contributors is matched to TOF"}; - Configurable doVertexTRDmatch{"doVertexTRDmatch", false, "Checks wherher at least one of vertex contributors is matched to TRD"}; - Configurable doBefSelEventMultCorr{"doBefSelEventMultCorr", false, "Enable histogram of multiplicity correlation before cuts"}; - Configurable doTFeventCut{"doTFeventCut", false, "Enable TF event Cut"}; - Configurable doITSFrameBorderCut{"doITSFrameBorderCut", false, "Enable ITSFrame event cut"}; - Configurable doMultiplicityCorrCut{"doMultiplicityCorrCut", false, "Enable multiplicity vs centrality correlation cut"}; - - Configurable centMin{"centMin", 0, "Minimal accepted centrality"}; - Configurable centMax{"centMax", 100, "Maximal accepted centrality"}; - + Configurable useCentralityFT0M{"useCentralityFT0M", 0, "If true, use centFT0M"}; + Configurable useCentralityFT0A{"useCentralityFT0A", 0, "If true, use centFT0A"}; + Configurable useCentralityFT0Cvar1{"useCentralityFT0Cvar1", 0, "If true, use centFT0FT0Cvar1"}; + Configurable useTrackOccupancyDef{"useTrackOccupancyDef", true, "Use occupancy definition based on the tracks"}; + Configurable useFT0OccupancyDef{"useFT0OccupancyDef", false, "se occupancy definition based on the FT0 signals"}; Configurable minPt{"minPt", 0.0f, "minPt"}; - Configurable masswin{"masswin", 0.05, "Mass window limit"}; - Configurable lambdaMassWin{"lambdaMassWin", 0.005, "V0 Mass window limit"}; - Configurable rapCut{"rapCut", 0.5, "Rapidity acceptance"}; - Configurable etaDauCut{"etaDauCut", 0.8, "Pseudorapidity acceptance of the cascade daughters"}; - Configurable dcaBaryonToPV{"dcaBaryonToPV", 0.05, "DCA of baryon doughter track To PV"}; - Configurable dcaMesonToPV{"dcaMesonToPV", 0.1, "DCA of meson doughter track To PV"}; - Configurable dcaBachToPV{"dcaBachToPV", 0.04, "DCA Bach To PV"}; - Configurable casccospa{"casccospa", 0.97, "Casc CosPA"}; - Configurable v0cospa{"v0cospa", 0.97, "V0 CosPA"}; - Configurable dcacascdau{"dcacascdau", 1., "DCA Casc Daughters"}; - Configurable dcav0dau{"dcav0dau", 1.5, "DCA V0 Daughters"}; - Configurable dcaV0ToPV{"dcaV0ToPV", 0.06, "DCA V0 To PV"}; - Configurable minRadius{"minRadius", 1.4f, "minRadius"}; - Configurable maxRadius{"maxRadius", 100.0f, "maxRadius"}; - Configurable minV0Radius{"minV0Radius", 1.2f, "V0 transverse decay radius, minimum"}; - Configurable maxV0Radius{"maxV0Radius", 100.0f, "V0 transverse decay radius, maximum"}; - Configurable nsigmatpcPi{"nsigmatpcPi", 5, "N sigma TPC Pion"}; - Configurable nsigmatpcPr{"nsigmatpcPr", 5, "N sigma TPC Proton"}; - Configurable nsigmatpcKa{"nsigmatpcKa", 5, "N sigma TPC Kaon"}; - Configurable nsigmatofPr{"nsigmatofPr", 3, "N sigma TOF Proton"}; - Configurable nsigmatofPion{"nsigmatofPion", 3, "N sigma TOF for Pion from V0"}; - Configurable nsigmatofBachPion{"nsigmatofBachPion", 3, "N sigma TOF for bachelor Pion"}; - Configurable nsigmatofBachKaon{"nsigmatofBachKaon", 3, "N sigma TOF for bachelor Kaon"}; - Configurable bachBaryonCosPA{"bachBaryonCosPA", 0.9999, "Bachelor baryon CosPA"}; - Configurable bachBaryonDCAxyToPV{"bachBaryonDCAxyToPV", 0.08, "DCA bachelor baryon to PV"}; - Configurable mintpccrrows{"mintpccrrows", 50, "min N TPC crossed rows"}; - Configurable dooobrej{"dooobrej", 0, "OOB rejection: 0 no selection, 1 = ITS||TOF, 2 = TOF only for pT > ptthrtof"}; - Configurable ptthrtof{"ptthrtof", 2, "Pt threshold for applying only tof oob rejection"}; - Configurable proplifetime{"proplifetime", 3, "ctau/"}; - Configurable rejcomp{"rejcomp", 0.008, "Competing Cascade rejection"}; - - Configurable doPtDepCosPaCut{"doPtDepCosPaCut", false, "Enable pt dependent cos PA cut"}; - Configurable doPtDepCascRadiusCut{"doPtDepCascRadiusCut", false, "Enable pt dependent cascade radius cut"}; - Configurable doPtDepV0RadiusCut{"doPtDepV0RadiusCut", false, "Enable pt dependent V0 radius cut"}; - Configurable doPtDepV0CosPaCut{"doPtDepV0CosPaCut", false, "Enable pt dependent cos PA cut of the V0 daughter"}; - Configurable doPtDepDCAcascDauCut{"doPtDepDCAcascDauCut", false, "Enable pt dependent DCA cascade daughter cut"}; - Configurable doDCAdauToPVCut{"doDCAdauToPVCut", true, "Enable cut DCA daughter track to PV"}; - Configurable doCascadeCosPaCut{"doCascadeCosPaCut", true, "Enable cos PA cut"}; - Configurable doV0CosPaCut{"doV0CosPaCut", true, "Enable cos PA cut for the V0 daughter"}; - Configurable doDCACascadeDauCut{"doDCACascadeDauCut", true, "Enable cut DCA betweenn daughter tracks"}; - Configurable doDCAV0DauCut{"doDCAV0DauCut", true, "Enable cut DCA betweenn V0 daughter tracks"}; - Configurable doCascadeRadiusCut{"doCascadeRadiusCut", true, "Enable cut on the cascade radius"}; - Configurable doV0RadiusCut{"doV0RadiusCut", true, "Enable cut on the V0 radius"}; - Configurable doDCAV0ToPVCut{"doDCAV0ToPVCut", true, "Enable cut DCA of V0 to PV"}; - Configurable doNTPCSigmaCut{"doNTPCSigmaCut", false, "Enable cut N sigma TPC"}; - Configurable doBachelorBaryonCut{"doBachelorBaryonCut", true, "Enable Bachelor-Baryon cut "}; - Configurable doProperLifeTimeCut{"doProperLifeTimeCut", true, "Enable proper life-time cut "}; - Configurable doNTOFSigmaProtonCut{"doNTOFSigmaProtonCut", true, "Enable n sigma TOF PID cut for proton from V0"}; - Configurable doNTOFSigmaV0PionCut{"doNTOFSigmaV0PionCut", false, "Enable n sigma TOF PID cut for pion from V0"}; - Configurable doNTOFSigmaBachelorCut{"doNTOFSigmaBachelorCut", false, "Enable n sigma TOF PID cut for bachelor track"}; - - Configurable cosPApar0{"cosPApar0", 0.2, "const par for pt dep cosPA cut"}; - Configurable cosPApar1{"cosPApar1", -0.022, "linear par for pt dep cosPA cut"}; - - Configurable parCascRadius0{"parCascRadius0", 1.216159, "const par for pt dep radius cut"}; - Configurable parCascRadius1{"parCascRadius1", 0.064462, "linear par for pt dep radius cut"}; - - Configurable parV0Radius0{"parV0Radius0", 2.136381, "const par for pt dep V0 radius cut"}; - Configurable parV0Radius1{"parV0Radius1", 0.437074, "linear par for pt dep V0 radius cut"}; - - Configurable dcaCacsDauPar0{"dcaCacsDauPar0", 0.8, " par for pt dep DCA cascade daughter cut, p_T < 1 GeV/c"}; - Configurable dcaCacsDauPar1{"dcaCacsDauPar1", 0.5, " par for pt dep DCA cascade daughter cut, 1< p_T < 4 GeV/c"}; - Configurable dcaCacsDauPar2{"dcaCacsDauPar2", 0.2, " par for pt dep DCA cascade daughter cut, p_T > 4 GeV/c"}; + Configurable nPtBinsForNsigmaTPC{"nPtBinsForNsigmaTPC", 100, ""}; + Configurable irSource{"irSource", "T0VTX", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + struct : ConfigurableGroup { + std::string prefix = "qa"; + Configurable doFillNsigmaTPCHistPionBach{"doFillNsigmaTPCHistPionBach", false, ""}; + Configurable doFillNsigmaTPCHistKaonBach{"doFillNsigmaTPCHistKaonBach", false, ""}; + Configurable doFillNsigmaTPCHistProton{"doFillNsigmaTPCHistProton", false, ""}; + Configurable doFillNsigmaTPCHistV0Pion{"doFillNsigmaTPCHistV0Pion", false, ""}; + Configurable doBefSelCheck{"doBefSelCheck", false, "Fill mass histograms of all candidates before selections"}; + Configurable doPtDepCutStudy{"doPtDepCutStudy", false, "Fill histogram with a cutting paramer"}; + Configurable doBefSelEventMultCorr{"doBefSelEventMultCorr", false, "Enable histogram of multiplicity correlation before cuts"}; + Configurable doOccupancyCheck{"doOccupancyCheck", true, ""}; + Configurable doIRCheck{"doIRCheck", true, ""}; + Configurable doITSTPCmatchingCheck{"doITSTPCmatchingCheck", true, "fill histogram for ITS-TPC matching check"}; + } qaFlags; + + struct : ConfigurableGroup { + std::string prefix = "evSelectionRun3"; + Configurable doTFeventCut{"doTFeventCut", false, "Enable TF event Cut"}; + Configurable doITSFrameBorderCut{"doITSFrameBorderCut", false, "Enable ITSFrame event cut"}; + Configurable doGoodPVFT0EventCut{"doGoodPVFT0EventCut", true, "check for the PV position diffrence when estimated from tracks and FT0"}; + Configurable doITSTPCvertexEventCut{"doITSTPCvertexEventCut", true, "checks the presence of at least one ITS-TPC track"}; + Configurable doSameBunchPileUpEventCut{"doSameBunchPileUpEventCut", true, "removes events associated with the same \"found-by-T0\" bunch crossing"}; + Configurable doVertexTOFmatch{"doVertexTOFmatch", false, "Checks wherher at least one of vertex contributors is matched to TOF"}; + Configurable doVertexTRDmatch{"doVertexTRDmatch", false, "Checks wherher at least one of vertex contributors is matched to TRD"}; + Configurable doTimeRangeStandardCut{"doTimeRangeStandardCut", true, "It rejects a given collision if there are other events nearby in dtime +/- 2 μs, or mult above some threshold in -4..-2 μs"}; + Configurable doTimeRangeStrictCut{"doTimeRangeStrictCut", false, "It rejects a given collision if there are other events nearby in |dt|< 10 μs"}; + Configurable doNoCollInRofStrictCut{"doNoCollInRofStrictCut", false, "Enable an evevnt selection which rejects a collision if there are other events within the same ITS ROF"}; + Configurable doNoCollInRofStandardCut{"doNoCollInRofStandardCut", true, "Enable an evevnt selection which rejects a collision if there are other events within the same ITS ROF with mult above threshold"}; + Configurable doMultiplicityCorrCut{"doMultiplicityCorrCut", false, "Enable multiplicity vs centrality correlation cut"}; + Configurable doITSallLayersCut{"doITSallLayersCut", false, "Enable event selection which rejects collisions when ITS was rebooting."}; + Configurable minOccupancy{"minOccupancy", -1, "Minimal occupancy"}; + Configurable maxOccupancy{"maxOccupancy", -1, "Maximal occupancy"}; + Configurable minOccupancyFT0{"minOccupancyFT0", -1, "Minimal occupancy"}; + Configurable maxOccupancyFT0{"maxOccupancyFT0", -1, "Maximal occupancy"}; + } eventSelectionRun3Flags; + + struct : ConfigurableGroup { + std::string prefix = "evSelectionCommon"; + Configurable doTriggerSel8EventCut{"doTriggerSel8EventCut", true, "Standard MB event selection"}; + Configurable doTriggerTVXEventCut{"doTriggerTVXEventCut", false, "Minimal MB event selection, for MC"}; + Configurable doInel0{"doInel0", true, "Enable INEL > 0 selection"}; + Configurable zVertexCut{"zVertexCut", 10, "Cut on PV position"}; + Configurable centMin{"centMin", 0, "Minimal accepted centrality"}; + Configurable centMax{"centMax", 100, "Maximal accepted centrality"}; + Configurable doInel0MCGen{"doInel0MCGen", true, "Enable INEL > 0 selection for MC gen events"}; + Configurable applyZVtxSelOnMCPV{"applyZVtxSelOnMCPV", false, "Enable z vertex cut selection on generated events"}; + } eventSelectionCommonFlags; + + struct : ConfigurableGroup { + std::string prefix = "evSelectionRun2"; + Configurable doSel7{"doSel7", true, "require sel7 event selection (Run 2 only: event selection decision based on V0A & V0C)"}; + Configurable doINT7{"doINT7", true, "require INT7 trigger selection (Run 2 only)"}; + Configurable doIncompleteDAQCut{"doIncompleteDAQCut", true, "reject events with incomplete DAQ (Run 2 only)"}; + Configurable doConsistentSPDAndTrackVtx{"doConsistentSPDAndTrackVtx", true, "reject events with inconsistent in SPD and Track vertices (Run 2 only)"}; + Configurable doPileupFromSPDCut{"doPileupFromSPDCut", true, "reject events with pileup according to SPD vertexer (Run 2 only)"}; + Configurable doV0PFPileupCut{"doV0PFPileupCut", false, "reject events tagged as OOB pileup according to V0 past-future info (Run 2 only)"}; + Configurable doPileupInMultBinsCut{"doPileupInMultBinsCut", true, "reject events tagged as pileup according to multiplicity-differential pileup checks (Run 2 only)"}; + Configurable doPileupMVCut{"doPileupMVCut", true, "reject events tagged as pileup according to according to multi-vertexer (Run 2 only)"}; + Configurable doTPCPileupCut{"doTPCPileupCut", false, "reject events tagged as pileup according to pileup in TPC (Run 2 only)"}; + Configurable doNoV0MOnVsOffPileup{"doNoV0MOnVsOffPileup", false, "reject events tagged as OOB pileup according to online-vs-offline VOM correlation (Run 2 only)"}; + Configurable doNoSPDOnVsOffPileup{"doNoSPDOnVsOffPileup", false, "reject events tagged as pileup according to online-vs-offline SPD correlation (Run 2 only)"}; + Configurable doNoSPDClsVsTklBG{"doNoSPDClsVsTklBG", true, "reject events tagged as beam-gas and pileup according to cluster-vs-tracklet correlation (Run 2 only)"}; + + Configurable useSPDTrackletsCent{"useSPDTrackletsCent", false, "Use SPD tracklets for estimating centrality? If not, use V0M-based centrality (Run 2 only)"}; + } eventSelectionRun2Flags; + + struct : ConfigurableGroup { + std::string prefix = "candidateSelFlag"; + Configurable doPtDepCosPaCut{"doPtDepCosPaCut", false, "Enable pt dependent cos PA cut"}; + Configurable doPtDepCascRadiusCut{"doPtDepCascRadiusCut", false, "Enable pt dependent cascade radius cut"}; + Configurable doPtDepV0RadiusCut{"doPtDepV0RadiusCut", false, "Enable pt dependent V0 radius cut"}; + Configurable doPtDepV0CosPaCut{"doPtDepV0CosPaCut", false, "Enable pt dependent cos PA cut of the V0 daughter"}; + Configurable doPtDepDCAcascDauCut{"doPtDepDCAcascDauCut", false, "Enable pt dependent DCA cascade daughter cut"}; + Configurable doDCAbachToPVCut{"doDCAbachToPVCut", true, "Enable cut DCA daughter track to PV"}; + Configurable doDCAmesonToPVCut{"doDCAmesonToPVCut", true, "Enable cut DCA daughter track to PV"}; + Configurable doDCAbaryonToPVCut{"doDCAbaryonToPVCut", true, "Enable cut DCA daughter track to PV"}; + Configurable doCascadeCosPaCut{"doCascadeCosPaCut", true, "Enable cos PA cut"}; + Configurable doV0CosPaCut{"doV0CosPaCut", true, "Enable cos PA cut for the V0 daughter"}; + Configurable doDCACascadeDauCut{"doDCACascadeDauCut", true, "Enable cut DCA betweenn daughter tracks"}; + Configurable doDCAV0DauCut{"doDCAV0DauCut", true, "Enable cut DCA betweenn V0 daughter tracks"}; + Configurable doCascadeRadiusCut{"doCascadeRadiusCut", true, "Enable cut on the cascade radius"}; + Configurable doV0RadiusCut{"doV0RadiusCut", true, "Enable cut on the V0 radius"}; + Configurable doDCAV0ToPVCut{"doDCAV0ToPVCut", true, "Enable cut DCA of V0 to PV"}; + Configurable doNTPCSigmaCut{"doNTPCSigmaCut", false, "Enable cut N sigma TPC"}; + Configurable doBachelorBaryonCut{"doBachelorBaryonCut", true, "Enable Bachelor-Baryon cut "}; + Configurable doProperLifeTimeCut{"doProperLifeTimeCut", true, "Enable proper life-time cut "}; + Configurable doNTOFSigmaProtonCut{"doNTOFSigmaProtonCut", true, "Enable n sigma TOF PID cut for proton from V0"}; + Configurable doNTOFSigmaV0PionCut{"doNTOFSigmaV0PionCut", false, "Enable n sigma TOF PID cut for pion from V0"}; + Configurable doNTOFSigmaBachelorCut{"doNTOFSigmaBachelorCut", false, "Enable n sigma TOF PID cut for bachelor track"}; + Configurable dooobrej{"dooobrej", 0, "OOB rejection: 0 no selection, 1 = ITS||TOF, 2 = TOF only for pT > ptthrtof"}; + Configurable doAtLeastOneTrackAB{"doAtLeastOneTrackAB", false, "require that at least one of the daughter tracks is from Afterburner"}; + Configurable doBachelorITSTracking{"doBachelorITSTracking", false, "require that the bachelor track is from the ITS tracking"}; + Configurable doAllTracksMinITSClusters{"doAllTracksMinITSClusters", false, "require that all daughter tracks have minimal ITS hits"}; + } candidateSelectionFlags; + + struct : ConfigurableGroup { + std::string prefix = "candidateSelection"; + Configurable dcaBaryonToPV{"dcaBaryonToPV", 0.05, "DCA of baryon doughter track To PV"}; + Configurable dcaMesonToPV{"dcaMesonToPV", 0.1, "DCA of meson doughter track To PV"}; + Configurable dcaBachToPV{"dcaBachToPV", 0.04, "DCA Bach To PV"}; + Configurable casccospa{"casccospa", 0.97, "Casc CosPA"}; + Configurable v0cospa{"v0cospa", 0.97, "V0 CosPA"}; + Configurable dcacascdau{"dcacascdau", 1., "DCA Casc Daughters"}; + Configurable dcav0dau{"dcav0dau", 1.5, "DCA V0 Daughters"}; + Configurable dcaV0ToPV{"dcaV0ToPV", 0.06, "DCA V0 To PV"}; + Configurable minRadius{"minRadius", 1.4f, "minRadius"}; + Configurable maxRadius{"maxRadius", 100.0f, "maxRadius"}; + Configurable minV0Radius{"minV0Radius", 1.2f, "V0 transverse decay radius, minimum"}; + Configurable maxV0Radius{"maxV0Radius", 100.0f, "V0 transverse decay radius, maximum"}; + Configurable nsigmatpcPi{"nsigmatpcPi", 5, "N sigma TPC Pion"}; + Configurable nsigmatpcPr{"nsigmatpcPr", 5, "N sigma TPC Proton"}; + Configurable nsigmatpcKa{"nsigmatpcKa", 5, "N sigma TPC Kaon"}; + Configurable nsigmatofPr{"nsigmatofPr", 3, "N sigma TOF Proton"}; + Configurable nsigmatofPion{"nsigmatofPion", 3, "N sigma TOF for Pion from V0"}; + Configurable nsigmatofBachPion{"nsigmatofBachPion", 3, "N sigma TOF for bachelor Pion"}; + Configurable nsigmatofBachKaon{"nsigmatofBachKaon", 3, "N sigma TOF for bachelor Kaon"}; + Configurable bachBaryonCosPA{"bachBaryonCosPA", 0.9999, "Bachelor baryon CosPA"}; + Configurable bachBaryonDCAxyToPV{"bachBaryonDCAxyToPV", 0.08, "DCA bachelor baryon to PV"}; + Configurable mintpccrrows{"mintpccrrows", 70, "min N TPC crossed rows"}; + Configurable cosPApar0{"cosPApar0", 0.2, "const par for pt dep cosPA cut"}; + Configurable cosPApar1{"cosPApar1", -0.022, "linear par for pt dep cosPA cut"}; + Configurable parCascRadius0{"parCascRadius0", 1.216159, "const par for pt dep radius cut"}; + Configurable parCascRadius1{"parCascRadius1", 0.064462, "linear par for pt dep radius cut"}; + Configurable parV0Radius0{"parV0Radius0", 2.136381, "const par for pt dep V0 radius cut"}; + Configurable parV0Radius1{"parV0Radius1", 0.437074, "linear par for pt dep V0 radius cut"}; + Configurable dcaCacsDauPar0{"dcaCacsDauPar0", 0.8, " par for pt dep DCA cascade daughter cut, p_T < 1 GeV/c"}; + Configurable dcaCacsDauPar1{"dcaCacsDauPar1", 0.5, " par for pt dep DCA cascade daughter cut, 1< p_T < 4 GeV/c"}; + Configurable dcaCacsDauPar2{"dcaCacsDauPar2", 0.2, " par for pt dep DCA cascade daughter cut, p_T > 4 GeV/c"}; + Configurable lambdaMassWin{"lambdaMassWin", 0.005, "V0 Mass window limit"}; + Configurable proplifetime{"proplifetime", 3, "ctau/"}; + Configurable ptthrtof{"ptthrtof", 2, "Pt threshold for applying only tof oob rejection"}; + Configurable rejcomp{"rejcomp", 0.008, "Competing Cascade rejection"}; + Configurable masswin{"masswin", 0.05, "Mass window limit"}; + Configurable rapCut{"rapCut", 0.5, "Rapidity acceptance"}; + Configurable etaDauCut{"etaDauCut", 0.8, "Pseudorapidity acceptance of the cascade daughters"}; + Configurable minITSclusters{"minITSclusters", 3, "minimal number of ITS hits for the daughter tracks"}; + } candidateSelectionValues; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + ctpRateFetcher rateFetcher; Service pdgDB; + uint16_t selectionCheckMask; + double selectionCheck; + + static constexpr std::string_view kCentIndex[] = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}; + static constexpr float kCentralityIntervals[11] = {0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90.}; + static constexpr std::string_view kCharge[] = {"Positive", "Negative"}; + static constexpr std::string_view kSelectionNames[] = {"BachelorBaryonDCA", "DCAV0ToPV", "V0Radius", "CascadeRadius", "DCAV0Daughters", "DCACascDaughters", "V0pa", "CascPA", "DCABachelorToPV", "DCAMesonToPV", "DCABaryonToPV", "CascadeProperLifeTime"}; + + // For manual sliceBy + // Preslice> perMcCollision = aod::v0data::straMCCollisionId; + PresliceUnsorted> perMcCollision = aod::v0data::straMCCollisionId; + PresliceUnsorted> perMcCollisionRun2 = aod::v0data::straMCCollisionId; + void init(InitContext const&) { + if ((doprocessCascades || doprocessCascadesMCrec || doprocessCascadesMCforEff) && (doprocessCascadesRun2 || doprocessCascadesMCrecRun2 || doprocessCascadesMCforEffRun2)) { + LOGF(fatal, "Cannot enable Run2 and Run3 processes at the same time. Please choose one."); + } + + // setting CCDB service + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); + + selectionCheck = -1; + selectionCheckMask = 0; + if (!candidateSelectionFlags.doBachelorBaryonCut) + SETBIT(selectionCheckMask, 0); + if (!candidateSelectionFlags.doDCAV0ToPVCut) + SETBIT(selectionCheckMask, 1); + if (!candidateSelectionFlags.doV0RadiusCut) + SETBIT(selectionCheckMask, 2); + if (!candidateSelectionFlags.doCascadeRadiusCut) + SETBIT(selectionCheckMask, 3); + if (!candidateSelectionFlags.doDCAV0DauCut) + SETBIT(selectionCheckMask, 4); + if (!candidateSelectionFlags.doDCACascadeDauCut) + SETBIT(selectionCheckMask, 5); + if (!candidateSelectionFlags.doV0CosPaCut) + SETBIT(selectionCheckMask, 6); + if (!candidateSelectionFlags.doCascadeCosPaCut) + SETBIT(selectionCheckMask, 7); + if (!candidateSelectionFlags.doDCAbachToPVCut) + SETBIT(selectionCheckMask, 8); + if (!candidateSelectionFlags.doDCAmesonToPVCut) + SETBIT(selectionCheckMask, 9); + if (!candidateSelectionFlags.doDCAbaryonToPVCut) + SETBIT(selectionCheckMask, 10); + if (!candidateSelectionFlags.doProperLifeTimeCut) + SETBIT(selectionCheckMask, 11); + histos.add("hEventVertexZ", "hEventVertexZ", kTH1F, {vertexZ}); + histos.add("hEventMultFt0C", "", kTH1F, {{500, 0, 5000}}); histos.add("hEventCentrality", "hEventCentrality", kTH1F, {{101, 0, 101}}); - histos.add("hEventSelection", "hEventSelection", kTH1F, {{12, 0, 12}}); + + histos.add("hEventSelection", "hEventSelection", kTH1F, {{22, 0, 22}}); + // TODO adjust labels + TString eventSelLabelRun3[22] = {"all", "sel8", "TVX", "PV_{z}", "cent", "kNoSameBunchPileup", "kIsGoodZvtxFT0vsPV", "kIsVertexITSTPC", "kIsVertexTOFmatched", "kIsVertexTRDmatched", "kNoITSROFrameBorder", "kNoTimeFrameBorder", "MultCorrCut", "kNoCollInTimeRangeStrict", "kNoCollInTimeRangeStandard", "min Occup", "mxOccup", "kNoCollInRofStrict", "kNoCollInRofStandard", "kIsGoodITSLayersAll", "occupFt0", "-"}; + TString eventSelLabelRun2[22] = {"all", "sel8", "TVX", "PV_{z}", "cent", "sel7", "kINT7", "kNoIncompleteDAQ", "kNoInconsistentVtx", "kNoPileupFromSPD", "kNoV0PFPileup", "kNoPileupInMultBins", "kNoPileupMV", "kNoPileupTPC", "kNoV0MOnVsOfPileup", "kNoSPDOnVsOfPileup", "kNoSPDClsVsTklBG", "INEL0", "-", "-", "-", "-"}; + for (int i = 1; i <= histos.get(HIST("hEventSelection"))->GetNbinsX(); i++) { + if (doprocessCascades || doprocessCascadesMCrec || doprocessCascadesMCforEff) { + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(i, eventSelLabelRun3[i - 1]); + } else { + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(i, eventSelLabelRun2[i - 1]); + } + } + + histos.add("hOccupancyVsOccupFt0VsCentrality", "", kTH3F, {axisOccupancy, axisOccupancyFt0, {100, 0, 100}}); + + histos.add("hNCrossedRowsNegative", "", kTH1F, {{400, -200, 200}}); + histos.add("hNCrossedRowsPositive", "", kTH1F, {{400, -200, 200}}); + histos.add("hNCrossedRowsBachelor", "", kTH1F, {{400, -200, 200}}); histos.add("hEventNchCorrelationAfCuts", "hEventNchCorrelationAfCuts", kTH2F, {{5000, 0, 5000}, {5000, 0, 2500}}); histos.add("hEventPVcontributorsVsCentrality", "hEventPVcontributorsVsCentrality", kTH2F, {{100, 0, 100}, {5000, 0, 5000}}); histos.add("hEventGlobalTracksVsCentrality", "hEventGlobalTracksVsCentrality", kTH2F, {{100, 0, 100}, {2500, 0, 2500}}); - if (doBefSelEventMultCorr) { + if (qaFlags.doBefSelEventMultCorr) { histos.add("hEventNchCorrelationBefCuts", "hEventNchCorrelationBefCuts", kTH2F, {{5000, 0, 5000}, {2500, 0, 2500}}); histos.add("hEventPVcontributorsVsCentralityBefCuts", "hEventPVcontributorsVsCentralityBefCuts", kTH2F, {{100, 0, 100}, {5000, 0, 5000}}); histos.add("hEventGlobalTracksVsCentralityBefCuts", "hEventGlobalTracksVsCentralityBefCuts", kTH2F, {{100, 0, 100}, {2500, 0, 2500}}); } histos.add("hCandidate", "hCandidate", HistType::kTH1D, {{22, -0.5, 21.5}}); - histos.add("hCutValue", "hCutValue", HistType::kTH2D, {{22, -0.5, 21.5}, {300, 0, 3.01}}); + histos.add("hCutValue", "hCutValue", HistType::kTH2D, {{22, -0.5, 21.5}, {300, 0, 3.1}}); - histos.add("hNsigmaProton", "hNsigmaProton", HistType::kTH3D, {{175, -7, 7}, {100, 0, 10}, {100, 0, 100}}); - histos.add("hNsigmaPionPos", "hNsigmaPionPos", HistType::kTH3D, {{175, -7, 7}, {100, 0, 10}, {100, 0, 100}}); - histos.add("hNsigmaPionPosBach", "hNsigmaPionPosBach", HistType::kTH3D, {{175, -7, 7}, {100, 0, 10}, {100, 0, 100}}); - histos.add("hNsigmaProtonNeg", "hNsigmaProtonNeg", HistType::kTH3D, {{175, -7, 7}, {100, 0, 10}, {100, 0, 100}}); - histos.add("hNsigmaPionNeg", "hNsigmaPionNeg", HistType::kTH3D, {{175, -7, 7}, {100, 0, 10}, {100, 0, 100}}); - histos.add("hNsigmaPionNegBach", "hNsigmaPionNegBach", HistType::kTH3D, {{175, -7, 7}, {100, 0, 10}, {100, 0, 100}}); - histos.add("hNsigmaKaon", "hNsigmaKaon", HistType::kTH3D, {{175, -7, 7}, {100, 0, 10}, {100, 0, 100}}); + if (qaFlags.doFillNsigmaTPCHistProton) { + histos.add("hNsigmaProton", "hNsigmaProton", HistType::kTH3D, {{280, -7, 7}, {nPtBinsForNsigmaTPC, 0, 6}, {100, 0, 100}}); + histos.add("hNsigmaProtonNeg", "hNsigmaProtonNeg", HistType::kTH3D, {{280, -7, 7}, {nPtBinsForNsigmaTPC, 0, 6}, {100, 0, 100}}); + } + if (qaFlags.doFillNsigmaTPCHistV0Pion) { + histos.add("hNsigmaPionNeg", "hNsigmaPionNeg", HistType::kTH3D, {{280, -7, 7}, {nPtBinsForNsigmaTPC, 0, 2}, {100, 0, 100}}); + histos.add("hNsigmaPionPos", "hNsigmaPionPos", HistType::kTH3D, {{280, -7, 7}, {nPtBinsForNsigmaTPC, 0, 2}, {100, 0, 100}}); + } + if (qaFlags.doFillNsigmaTPCHistPionBach) { + histos.add("hNsigmaPionPosBach", "hNsigmaPionPosBach", HistType::kTH3D, {{280, -7, 7}, {nPtBinsForNsigmaTPC, 0, 2}, {100, 0, 100}}); + histos.add("hNsigmaPionNegBach", "hNsigmaPionNegBach", HistType::kTH3D, {{280, -7, 7}, {nPtBinsForNsigmaTPC, 0, 2}, {100, 0, 100}}); + } + if (qaFlags.doFillNsigmaTPCHistKaonBach) + histos.add("hNsigmaKaon", "hNsigmaKaon", HistType::kTH3D, {{280, -7, 7}, {nPtBinsForNsigmaTPC, 0, 6}, {100, 0, 100}}); - if (doNTOFSigmaProtonCut) + if (candidateSelectionFlags.doNTOFSigmaProtonCut) histos.add("hNsigmaTOFProton", "", HistType::kTH3D, {{70, -7, 7}, {100, 0, 10}, {100, 0, 100}}); - if (doNTOFSigmaV0PionCut) + if (candidateSelectionFlags.doNTOFSigmaV0PionCut) histos.add("hNsigmaTOFV0Pion", "", HistType::kTH3D, {{70, -7, 7}, {100, 0, 10}, {100, 0, 100}}); - if (doNTOFSigmaBachelorCut) { + if (candidateSelectionFlags.doNTOFSigmaBachelorCut) { if (isXi) histos.add("hNsigmaTOFBachelorPion", "", HistType::kTH3D, {{70, -7, 7}, {100, 0, 10}, {100, 0, 100}}); else histos.add("hNsigmaTOFBachelorKaon", "", HistType::kTH3D, {{70, -7, 7}, {100, 0, 10}, {100, 0, 100}}); } - TString CutLabel[22] = {"All", "MassWin", "y", "DCACascDau", "DCAV0Dau", "rCasc", "rCascMax", "rV0", "rV0Max", "LambdaMass", "Bach-baryon", "V0CosPA", "CompDecayMass", "DCADauToPV", "EtaDau", "CascCosPA", "DCAV0ToPV", "nSigmaTPCV0Dau", "NTPCrows", "OOBRej", "nSigmaTPCbachelor", "ctau"}; - for (Int_t i = 1; i <= histos.get(HIST("hCandidate"))->GetNbinsX(); i++) { - histos.get(HIST("hCandidate"))->GetXaxis()->SetBinLabel(i, CutLabel[i - 1]); - histos.get(HIST("hCutValue"))->GetXaxis()->SetBinLabel(i, CutLabel[i - 1]); + TString cutLabel[22] = {"All", "MassWin", "y", "DCACascDau", "DCAV0Dau", "rCasc", "rCascMax", "rV0", "rV0Max", "LambdaMass", "Bach-baryon", "V0CosPA", "CompDecayMass", "DCADauToPV", "EtaDau", "CascCosPA", "DCAV0ToPV", "nSigmaTPCV0Dau", "NTPCrows", "OOBRej", "nSigmaTPCbachelor", "ctau"}; + for (int i = 1; i <= histos.get(HIST("hCandidate"))->GetNbinsX(); i++) { + histos.get(HIST("hCandidate"))->GetXaxis()->SetBinLabel(i, cutLabel[i - 1]); + histos.get(HIST("hCutValue"))->GetXaxis()->SetBinLabel(i, cutLabel[i - 1]); } - histos.add("InvMassAfterSel/hNegativeCascade", "hNegativeCascade", HistType::kTH3F, {axisPt, axisXiMass, {101, 0, 101}}); - histos.add("InvMassAfterSel/hPositiveCascade", "hPositiveCascade", {HistType::kTH3F, {axisPt, axisXiMass, {101, 0, 101}}}); + histos.add("InvMassAfterSel/hNegativeCascade", "hNegativeCascade", HistType::kTH3F, {axisPt, axisMass, {101, 0, 101}}); + histos.add("InvMassAfterSel/hPositiveCascade", "hPositiveCascade", {HistType::kTH3F, {axisPt, axisMass, {101, 0, 101}}}); + + if (qaFlags.doOccupancyCheck) { + histos.add("InvMassAfterSelCent1/hNegativeCascade", "hNegativeCascade", HistType::kTH3F, {axisPt, axisMass, axisOccupancy}); + histos.add("InvMassAfterSelCent1/hPositiveCascade", "hPositiveCascade", HistType::kTH3F, {axisPt, axisMass, axisOccupancy}); + if (doprocessCascadesMCrec || doprocessCascadesMCrecRun2) { + histos.add("InvMassAfterSelCent1/hNegativeCascadeMCTruth", "hNegativeCascadeMCTruth", HistType::kTH3F, {axisPt, axisMass, axisOccupancy}); + histos.add("InvMassAfterSelCent1/hPositiveCascadeMCTruth", "hPositiveCascadeMCTruth", HistType::kTH3F, {axisPt, axisMass, axisOccupancy}); + } + if (!qaFlags.doIRCheck) { + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent2/"); + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent3/"); + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent4/"); + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent5/"); + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent6/"); + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent7/"); + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent8/"); + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent9/"); + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent10/"); + } + } - if (!isXi) { - histos.get(HIST("InvMassAfterSel/hNegativeCascade"))->GetYaxis()->Set(200, 1.572f, 1.772f); - histos.get(HIST("InvMassAfterSel/hPositiveCascade"))->GetYaxis()->Set(200, 1.572f, 1.772f); + if (qaFlags.doIRCheck) { + histos.add("InvMassAfterSelCent1/hNegativeCascadeIR", "hNegativeCascadeIR", HistType::kTH3F, {axisPt, axisMass, axisIR}); + histos.add("InvMassAfterSelCent1/hPositiveCascadeIR", "hPositiveCascadeIR", HistType::kTH3F, {axisPt, axisMass, axisIR}); + if (doprocessCascadesMCrec || doprocessCascadesMCrecRun2) { + histos.add("InvMassAfterSelCent1/hNegativeCascadeMCTruthIR", "hNegativeCascadeMCTruthIR", HistType::kTH3F, {axisPt, axisMass, axisIR}); + histos.add("InvMassAfterSelCent1/hPositiveCascadeMCTruthIR", "hPositiveCascadeMCTruthIR", HistType::kTH3F, {axisPt, axisMass, axisIR}); + } + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent2/"); + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent3/"); + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent4/"); + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent5/"); + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent6/"); + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent7/"); + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent8/"); + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent9/"); + histos.addClone("InvMassAfterSelCent1/", "InvMassAfterSelCent10/"); } - if (doBefSelCheck) + histos.add("hInteractionRate", "hInteractionRate", kTH1F, {axisIR}); + histos.add("hCentralityVsInteractionRate", "hCentralityVsInteractionRate", kTH2F, {{101, 0.0f, 101.0f}, axisIR}); + + if (qaFlags.doBefSelCheck) histos.addClone("InvMassAfterSel/", "InvMassBefSel/"); - if (isMC) + if (doprocessCascadesMCrec || doprocessCascadesMCrecRun2) histos.addClone("InvMassAfterSel/", "InvMassAfterSelMCrecTruth/"); - if (doPtDepCutStudy && !doProperLifeTimeCut) { - histos.add("PtDepCutStudy/hNegativeCascadeProperLifeTime", "hNegativeCascadeProperLifeTime", HistType::kTH3F, {axisPt, axisXiMass, {100, 0, 10}}); - histos.add("PtDepCutStudy/hPositiveCascadeProperLifeTime", "hPositiveCascadeProperLifeTime", {HistType::kTH3F, {axisPt, axisXiMass, {100, 0, 10}}}); - if (!isXi) { - histos.get(HIST("PtDepCutStudy/hNegativeCascadeProperLifeTime"))->GetYaxis()->Set(200, 1.572f, 1.772f); - histos.get(HIST("PtDepCutStudy/hPositiveCascadeProperLifeTime"))->GetYaxis()->Set(200, 1.572f, 1.772f); - } + if (qaFlags.doPtDepCutStudy && !candidateSelectionFlags.doProperLifeTimeCut) { + histos.add("PtDepCutStudy/hNegativeCascadeProperLifeTime", "hNegativeCascadeProperLifeTime", HistType::kTH3F, {axisPt, axisMass, {100, 0, 10}}); + histos.add("PtDepCutStudy/hPositiveCascadeProperLifeTime", "hPositiveCascadeProperLifeTime", {HistType::kTH3F, {axisPt, axisMass, {100, 0, 10}}}); } - if (doPtDepCutStudy && !doBachelorBaryonCut) { - histos.add("PtDepCutStudy/hNegativeBachelorBaryonDCA", "hNegativeBachelorBaryonDCA", HistType::kTH3F, {axisPt, axisXiMass, {40, 0, 1}}); - histos.add("PtDepCutStudy/hPositiveBachelorBaryonDCA", "hPositiveBachelorBaryonDCA", {HistType::kTH3F, {axisPt, axisXiMass, {40, 0, 1}}}); - if (!isXi) { - histos.get(HIST("PtDepCutStudy/hNegativeBachelorBaryonDCA"))->GetYaxis()->Set(200, 1.572f, 1.772f); - histos.get(HIST("PtDepCutStudy/hPositiveBachelorBaryonDCA"))->GetYaxis()->Set(200, 1.572f, 1.772f); - } + if (qaFlags.doPtDepCutStudy && !candidateSelectionFlags.doBachelorBaryonCut) { + histos.add("PtDepCutStudy/hNegativeBachelorBaryonDCA", "hNegativeBachelorBaryonDCA", HistType::kTH3F, {axisPt, axisMass, {40, 0, 1}}); + histos.add("PtDepCutStudy/hPositiveBachelorBaryonDCA", "hPositiveBachelorBaryonDCA", {HistType::kTH3F, {axisPt, axisMass, {40, 0, 1}}}); } - if (doPtDepCutStudy && !doDCAV0ToPVCut) { - histos.add("PtDepCutStudy/hNegativeDCAV0ToPV", "hNegativeDCAV0ToPV", HistType::kTH3F, {axisPt, axisXiMass, {40, 0, 1}}); - histos.add("PtDepCutStudy/hPositiveDCAV0ToPV", "hPositiveDCAV0ToPV", {HistType::kTH3F, {axisPt, axisXiMass, {40, 0, 1}}}); - if (!isXi) { - histos.get(HIST("PtDepCutStudy/hNegativeDCAV0ToPV"))->GetYaxis()->Set(200, 1.572f, 1.772f); - histos.get(HIST("PtDepCutStudy/hPositiveDCAV0ToPV"))->GetYaxis()->Set(200, 1.572f, 1.772f); - } + if (qaFlags.doPtDepCutStudy && !candidateSelectionFlags.doDCAV0ToPVCut) { + histos.add("PtDepCutStudy/hNegativeDCAV0ToPV", "hNegativeDCAV0ToPV", HistType::kTH3F, {axisPt, axisMass, {40, 0, 1}}); + histos.add("PtDepCutStudy/hPositiveDCAV0ToPV", "hPositiveDCAV0ToPV", {HistType::kTH3F, {axisPt, axisMass, {40, 0, 1}}}); } - if (doPtDepCutStudy && !doV0RadiusCut) { - histos.add("PtDepCutStudy/hNegativeV0Radius", "hNegativeV0Radius", HistType::kTH3F, {axisPt, axisXiMass, {20, 0, 10}}); - histos.add("PtDepCutStudy/hPositiveV0Radius", "hPositiveV0Radius", {HistType::kTH3F, {axisPt, axisXiMass, {20, 0, 10}}}); - if (!isXi) { - histos.get(HIST("PtDepCutStudy/hNegativeV0Radius"))->GetYaxis()->Set(200, 1.572f, 1.772f); - histos.get(HIST("PtDepCutStudy/hPositiveV0Radius"))->GetYaxis()->Set(200, 1.572f, 1.772f); - } + if (qaFlags.doPtDepCutStudy && !candidateSelectionFlags.doV0RadiusCut) { + histos.add("PtDepCutStudy/hNegativeV0Radius", "hNegativeV0Radius", HistType::kTH3F, {axisPt, axisMass, {20, 0, 10}}); + histos.add("PtDepCutStudy/hPositiveV0Radius", "hPositiveV0Radius", {HistType::kTH3F, {axisPt, axisMass, {20, 0, 10}}}); } - if (doPtDepCutStudy && !doCascadeRadiusCut) { - histos.add("PtDepCutStudy/hNegativeCascadeRadius", "hNegativeCascadeRadius", HistType::kTH3F, {axisPt, axisXiMass, {50, 0, 5}}); - histos.add("PtDepCutStudy/hPositiveCascadeRadius", "hPositiveCascadeRadius", {HistType::kTH3F, {axisPt, axisXiMass, {50, 0, 5}}}); - if (!isXi) { - histos.get(HIST("PtDepCutStudy/hNegativeCascadeRadius"))->GetYaxis()->Set(200, 1.572f, 1.772f); - histos.get(HIST("PtDepCutStudy/hPositiveCascadeRadius"))->GetYaxis()->Set(200, 1.572f, 1.772f); - } + if (qaFlags.doPtDepCutStudy && !candidateSelectionFlags.doCascadeRadiusCut) { + histos.add("PtDepCutStudy/hNegativeCascadeRadius", "hNegativeCascadeRadius", HistType::kTH3F, {axisPt, axisMass, {50, 0, 5}}); + histos.add("PtDepCutStudy/hPositiveCascadeRadius", "hPositiveCascadeRadius", {HistType::kTH3F, {axisPt, axisMass, {50, 0, 5}}}); } - if (doPtDepCutStudy && !doDCAV0DauCut) { - histos.add("PtDepCutStudy/hNegativeDCAV0Daughters", "hNegativeDCAV0Daughters", HistType::kTH3F, {axisPt, axisXiMass, {50, 0, 5}}); - histos.add("PtDepCutStudy/hPositiveDCAV0Daughters", "hPositiveDCAV0Daughters", {HistType::kTH3F, {axisPt, axisXiMass, {50, 0, 5}}}); - if (!isXi) { - histos.get(HIST("PtDepCutStudy/hNegativeDCAV0Daughters"))->GetYaxis()->Set(200, 1.572f, 1.772f); - histos.get(HIST("PtDepCutStudy/hPositiveDCAV0Daughters"))->GetYaxis()->Set(200, 1.572f, 1.772f); - } + if (qaFlags.doPtDepCutStudy && !candidateSelectionFlags.doDCAV0DauCut) { + histos.add("PtDepCutStudy/hNegativeDCAV0Daughters", "hNegativeDCAV0Daughters", HistType::kTH3F, {axisPt, axisMass, {50, 0, 5}}); + histos.add("PtDepCutStudy/hPositiveDCAV0Daughters", "hPositiveDCAV0Daughters", {HistType::kTH3F, {axisPt, axisMass, {50, 0, 5}}}); } - if (doPtDepCutStudy && !doDCACascadeDauCut) { - histos.add("PtDepCutStudy/hNegativeDCACascDaughters", "hNegativeDCACascDaughters", {HistType::kTH3F, {axisPt, axisXiMass, {20, 0, 1}}}); - histos.add("PtDepCutStudy/hPositiveDCACascDaughters", "hPositiveDCACascDaughters", {HistType::kTH3F, {axisPt, axisXiMass, {20, 0, 1}}}); - if (!isXi) { - histos.get(HIST("PtDepCutStudy/hPositiveDCACascDaughters"))->GetYaxis()->Set(200, 1.572f, 1.772f); - histos.get(HIST("PtDepCutStudy/hNegativeDCACascDaughters"))->GetYaxis()->Set(200, 1.572f, 1.772f); - } + if (qaFlags.doPtDepCutStudy && !candidateSelectionFlags.doDCACascadeDauCut) { + histos.add("PtDepCutStudy/hNegativeDCACascDaughters", "hNegativeDCACascDaughters", {HistType::kTH3F, {axisPt, axisMass, {20, 0, 1}}}); + histos.add("PtDepCutStudy/hPositiveDCACascDaughters", "hPositiveDCACascDaughters", {HistType::kTH3F, {axisPt, axisMass, {20, 0, 1}}}); } - if (doPtDepCutStudy && !doV0CosPaCut) { - histos.add("PtDepCutStudy/hNegativeV0pa", "hNegativeV0pa", HistType::kTH3F, {axisPt, axisXiMass, {40, 0, 0.4}}); - histos.add("PtDepCutStudy/hPositiveV0pa", "hPositiveV0pa", {HistType::kTH3F, {axisPt, axisXiMass, {40, 0, 0.4}}}); - if (!isXi) { - histos.get(HIST("PtDepCutStudy/hNegativeV0pa"))->GetYaxis()->Set(200, 1.572f, 1.772f); - histos.get(HIST("PtDepCutStudy/hPositiveV0pa"))->GetYaxis()->Set(200, 1.572f, 1.772f); - } + if (qaFlags.doPtDepCutStudy && !candidateSelectionFlags.doV0CosPaCut) { + histos.add("PtDepCutStudy/hNegativeV0pa", "hNegativeV0pa", HistType::kTH3F, {axisPt, axisMass, {40, 0, 0.4}}); + histos.add("PtDepCutStudy/hPositiveV0pa", "hPositiveV0pa", {HistType::kTH3F, {axisPt, axisMass, {40, 0, 0.4}}}); } - if (doPtDepCutStudy && !doDCAdauToPVCut) { - histos.add("PtDepCutStudy/hNegativeDCABachelorToPV", "hNegativeDCABachelorToPV", HistType::kTH3F, {axisPt, axisXiMass, {50, 0, 0.5}}); - histos.add("PtDepCutStudy/hNegativeDCABaryonToPV", "hNegativeDCABaryonToPV", HistType::kTH3F, {axisPt, axisXiMass, {50, 0, 0.5}}); - histos.add("PtDepCutStudy/hNegativeDCAMesonToPV", "hNegativeDCAMesonToPV", HistType::kTH3F, {axisPt, axisXiMass, {50, 0, 0.5}}); - histos.add("PtDepCutStudy/hPositiveDCABachelorToPV", "hPositiveDCABachelorToPV", {HistType::kTH3F, {axisPt, axisXiMass, {50, 0, 0.5}}}); - histos.add("PtDepCutStudy/hPositiveDCABaryonToPV", "hPositiveDCABaryonToPV", HistType::kTH3F, {axisPt, axisXiMass, {50, 0, 0.5}}); - histos.add("PtDepCutStudy/hPositiveDCAMesonToPV", "hPositiveDCAMesonToPV", HistType::kTH3F, {axisPt, axisXiMass, {50, 0, 0.5}}); - if (!isXi) { - histos.get(HIST("PtDepCutStudy/hNegativeDCABachelorToPV"))->GetYaxis()->Set(200, 1.572f, 1.772f); - histos.get(HIST("PtDepCutStudy/hNegativeDCABaryonToPV"))->GetYaxis()->Set(200, 1.572f, 1.772f); - histos.get(HIST("PtDepCutStudy/hNegativeDCAMesonToPV"))->GetYaxis()->Set(200, 1.572f, 1.772f); - histos.get(HIST("PtDepCutStudy/hPositiveDCABachelorToPV"))->GetYaxis()->Set(200, 1.572f, 1.772f); - histos.get(HIST("PtDepCutStudy/hPositiveDCABaryonToPV"))->GetYaxis()->Set(200, 1.572f, 1.772f); - histos.get(HIST("PtDepCutStudy/hPositiveDCAMesonToPV"))->GetYaxis()->Set(200, 1.572f, 1.772f); - } + if (qaFlags.doPtDepCutStudy && !candidateSelectionFlags.doDCAbachToPVCut) { + histos.add("PtDepCutStudy/hNegativeDCABachelorToPV", "hNegativeDCABachelorToPV", HistType::kTH3F, {axisPt, axisMass, {50, 0, 0.5}}); + histos.add("PtDepCutStudy/hPositiveDCABachelorToPV", "hPositiveDCABachelorToPV", {HistType::kTH3F, {axisPt, axisMass, {50, 0, 0.5}}}); + } + if (qaFlags.doPtDepCutStudy && !candidateSelectionFlags.doDCAmesonToPVCut) { + histos.add("PtDepCutStudy/hNegativeDCAMesonToPV", "hNegativeDCAMesonToPV", HistType::kTH3F, {axisPt, axisMass, {50, 0, 0.5}}); + histos.add("PtDepCutStudy/hPositiveDCAMesonToPV", "hPositiveDCAMesonToPV", HistType::kTH3F, {axisPt, axisMass, {50, 0, 0.5}}); + } + if (qaFlags.doPtDepCutStudy && !candidateSelectionFlags.doDCAbaryonToPVCut) { + histos.add("PtDepCutStudy/hNegativeDCABaryonToPV", "hNegativeDCABaryonToPV", HistType::kTH3F, {axisPt, axisMass, {50, 0, 0.5}}); + histos.add("PtDepCutStudy/hPositiveDCABaryonToPV", "hPositiveDCABaryonToPV", HistType::kTH3F, {axisPt, axisMass, {50, 0, 0.5}}); } - if (doPtDepCutStudy && !doCascadeCosPaCut) { - histos.add("PtDepCutStudy/hNegativeCascPA", "hNegativeCascPA", HistType::kTH3F, {axisPt, axisXiMass, {40, 0, 0.4}}); - histos.add("PtDepCutStudy/hPositiveCascPA", "hPositiveCascPA", {HistType::kTH3F, {axisPt, axisXiMass, {40, 0, 0.4}}}); - if (!isXi) { - histos.get(HIST("PtDepCutStudy/hNegativeCascPA"))->GetYaxis()->Set(200, 1.572f, 1.772f); - histos.get(HIST("PtDepCutStudy/hPositiveCascPA"))->GetYaxis()->Set(200, 1.572f, 1.772f); - } + if (qaFlags.doPtDepCutStudy && !candidateSelectionFlags.doCascadeCosPaCut) { + histos.add("PtDepCutStudy/hNegativeCascPA", "hNegativeCascPA", HistType::kTH3F, {axisPt, axisMass, {40, 0, 0.4}}); + histos.add("PtDepCutStudy/hPositiveCascPA", "hPositiveCascPA", {HistType::kTH3F, {axisPt, axisMass, {40, 0, 0.4}}}); + } + if (qaFlags.doITSTPCmatchingCheck) { + histos.add("histITSTPCmatchPosTrack", "", HistType::kTH3F, {axisPt, {101, 0, 101}, {3, 0, 3}}); + histos.add("histITSTPCmatchNegTrack", "", HistType::kTH3F, {axisPt, {101, 0, 101}, {3, 0, 3}}); + histos.add("histITSTPCmatchBachTrack", "", HistType::kTH3F, {axisPt, {101, 0, 101}, {3, 0, 3}}); } - if (isMC) { + if (doprocessCascadesMCrec || doprocessCascadesMCrecRun2) { histos.addClone("PtDepCutStudy/", "PtDepCutStudyMCTruth/"); - histos.add("hNegativeCascadePtForEfficiency", "hNegativeCascadePtForEfficiency", HistType::kTH3F, {axisPt, axisXiMass, {101, 0, 101}}); - histos.add("hPositiveCascadePtForEfficiency", "hPositiveCascadePtForEfficiency", {HistType::kTH3F, {axisPt, axisXiMass, {101, 0, 101}}}); - if (!isXi) { - histos.get(HIST("hNegativeCascadePtForEfficiency"))->GetYaxis()->Set(200, 1.572f, 1.772f); - histos.get(HIST("hPositiveCascadePtForEfficiency"))->GetYaxis()->Set(200, 1.572f, 1.772f); + histos.add("hNegativeCascadePtForEfficiency", "hNegativeCascadePtForEfficiency", HistType::kTH3F, {axisPt, axisMass, {101, 0, 101}}); + histos.add("hPositiveCascadePtForEfficiency", "hPositiveCascadePtForEfficiency", {HistType::kTH3F, {axisPt, axisMass, {101, 0, 101}}}); + histos.add("hNegativeCascadePtForEfficiencyVsNch", "hNegativeCascadePtForEfficiencyVsNch", HistType::kTH3F, {axisPt, axisMass, axisNch}); + histos.add("hPositiveCascadePtForEfficiencyVsNch", "hPositiveCascadePtForEfficiencyVsNch", {HistType::kTH3F, {axisPt, axisMass, axisNch}}); + if (qaFlags.doBefSelCheck) { + histos.add("hNegativeCascadePtForEfficiencyBefSel", "hNegativeCascadePtForEfficiencyBefSel", HistType::kTH3F, {axisPt, axisMass, {101, 0, 101}}); + histos.add("hPositiveCascadePtForEfficiencyBefSel", "hPositiveCascadePtForEfficiencyBefSel", {HistType::kTH3F, {axisPt, axisMass, {101, 0, 101}}}); + histos.add("hNegativeCascadePtForEfficiencyVsNchBefSel", "hNegativeCascadePtForEfficiencyVsNchBefSel", HistType::kTH3F, {axisPt, axisMass, axisNch}); + histos.add("hPositiveCascadePtForEfficiencyVsNchBefSel", "hPositiveCascadePtForEfficiencyVsNchBefSel", {HistType::kTH3F, {axisPt, axisMass, axisNch}}); + } + } + + if (doprocessCascadesMCforEff || doprocessCascadesMCforEffRun2) { + histos.add("hGenEvents", "", HistType::kTH2F, {{axisNch}, {4, 0, 4}}); + histos.add("hCentralityVsMultMC", "", kTH2F, {{101, 0.0f, 101.0f}, axisNch}); + histos.add("hRecMultVsMultMC", "", kTH2F, {axisNch, axisNch}); + histos.add("hGenMultMCFT0C", "", kTH1F, {{500, 0, 5000}}); + histos.add("hGenMCNParticlesEta10", "", kTH1F, {{500, 0, 5000}}); + histos.add("hCentralityVsIRGen", "", kTH2F, {{101, 0.0f, 101.0f}, axisIR}); + histos.add("hMultMCVsCentralityVsIRGen", "", kTH3F, {axisNch, {101, 0.0f, 101.0f}, axisIR}); + + histos.add("hCentralityVsNcoll_beforeEvSel", "", kTH2F, {{101, 0.0f, 101.0f}, {50, 0.f, 50.f}}); + histos.add("hCentralityVsNcoll_afterEvSel", "", kTH2F, {{101, 0.0f, 101.0f}, {50, 0.f, 50.f}}); + + if (isXi) { + histos.add("h2dGenXiMinusEta", "", kTH1F, {{30, -2, 2}}); + histos.add("h2dGenXiMinusEtaPosDaughter", "", kTH1F, {{30, -2, 2}}); + histos.add("h2dGenXiMinusEtaNegDaughter", "", kTH1F, {{30, -2, 2}}); + histos.add("h2dGenXiMinusEtaBach", "", kTH1F, {{30, -2, 2}}); + histos.add("h2dGenXiMinus", "h2dGenXiMinus", kTH2D, {{101, 0.0f, 101.0f}, axisPt}); + histos.add("h2dGenXiPlus", "h2dGenXiPlus", kTH2D, {{101, 0.0f, 101.0f}, axisPt}); + histos.add("h2dGenXiMinusVsNch", "h2dGenXiMinusVsNch", kTH2D, {axisNch, axisPt}); + histos.add("h2dGenXiPlusVsNch", "h2dGenXiPlusVsNch", kTH2D, {axisNch, axisPt}); + histos.add("h2dGenXiMinusVsCentOccupancy", "h2dGenXiMinusVsCentOccupancy", kTH3D, {axisPt, {101, 0.0f, 101.0f}, axisOccupancy}); + histos.add("h2dGenXiPlusVsCentOccupancy", "h2dGenXiPlusVsCentOccupancy", kTH3D, {axisPt, {101, 0.0f, 101.0f}, axisOccupancy}); + histos.add("h2dGenXiMinusVsNchVsOccupancy", "h2dGenXiMinusVsNchVsOccupancy", kTH3D, {axisPt, axisNch, axisOccupancy}); + histos.add("h2dGenXiPlusVsNchVsOccupancy", "h2dGenXiPlusVsNchVsOccupancy", kTH3D, {axisPt, axisNch, axisOccupancy}); + histos.add("h2dGenXiMinusVsMultMCVsCentrality", "h2dGenXiMinusVsMultMCVsCentrality", kTH3D, {axisNch, {101, 0.0f, 101.0f}, axisPt}); + histos.add("h2dGenXiPlusVsMultMCVsCentrality", "h2dGenXiPlusVsMultMCVsCentrality", kTH3D, {axisNch, {101, 0.0f, 101.0f}, axisPt}); + histos.add("h2dGenXiMinusVsCentIR", "h2dGenXiMinusVsCentIR", kTH3D, {axisPt, {101, 0.0f, 101.0f}, axisIR}); + histos.add("h2dGenXiPlusVsCentIR", "h2dGenXiPlusVsCentIR", kTH3D, {axisPt, {101, 0.0f, 101.0f}, axisIR}); + histos.add("h2dGenXiMinusVsMultMCVsIR", "h2dGenXiMinusVsMultMCVsIR", kTH3D, {axisNch, axisIR, axisPt}); + histos.add("h2dGenXiPlusVsMultMCVsIR", "h2dGenXiPlusVsMultMCVsIR", kTH3D, {axisNch, axisIR, axisPt}); + } else { + histos.add("h2dGenOmegaMinusEta", "", kTH1F, {{30, -2, 2}}); + histos.add("h2dGenOmegaMinusEtaPosDaughter", "", kTH1F, {{30, -2, 2}}); + histos.add("h2dGenOmegaMinusEtaNegDaughter", "", kTH1F, {{30, -2, 2}}); + histos.add("h2dGenOmegaMinusEtaBach", "", kTH1F, {{30, -2, 2}}); + histos.add("h2dGenOmegaMinus", "h2dGenOmegaMinus", kTH2D, {{101, 0.0f, 101.0f}, axisPt}); + histos.add("h2dGenOmegaPlus", "h2dGenOmegaPlus", kTH2D, {{101, 0.0f, 101.0f}, axisPt}); + histos.add("h2dGenOmegaMinusVsNch", "h2dGenOmegaMinusVsNch", kTH2D, {axisNch, axisPt}); + histos.add("h2dGenOmegaPlusVsNch", "h2dGenOmegaPlusVsNch", kTH2D, {axisNch, axisPt}); + histos.add("h2dGenOmegaMinusVsCentOccupancy", "h2dGenOmegaMinusVsCentOccupancy", kTH3D, {axisPt, {101, 0.0f, 101.0f}, axisOccupancy}); + histos.add("h2dGenOmegaPlusVsCentOccupancy", "h2dGenOmegaPlusVsCentOccupancy", kTH3D, {axisPt, {101, 0.0f, 101.0f}, axisOccupancy}); + histos.add("h2dGenOmegaMinusVsNchVsOccupancy", "h2dGenOmegaMinusVsNchVsOccupancy", kTH3D, {axisPt, axisNch, axisOccupancy}); + histos.add("h2dGenOmegaPlusVsNchVsOccupancy", "h2dGenOmegaPlusVsNchVsOccupancy", kTH3D, {axisPt, axisNch, axisOccupancy}); + histos.add("h2dGenOmegaMinusVsMultMCVsCentrality", "h2dGenOmegaMinusVsMultMCVsCentrality", kTH3D, {axisNch, {101, 0.0f, 101.0f}, axisPt}); + histos.add("h2dGenOmegaPlusVsMultMCVsCentrality", "h2dGenOmegaPlusVsMultMCVsCentrality", kTH3D, {axisNch, {101, 0.0f, 101.0f}, axisPt}); + histos.add("h2dGenOmegaMinusVsCentIR", "h2dGenOmegaMinusVsCentIR", kTH3D, {axisPt, {101, 0.0f, 101.0f}, axisIR}); + histos.add("h2dGenOmegaPlusVsCentIR", "h2dGenOmegaPlusVsCentIR", kTH3D, {axisPt, {101, 0.0f, 101.0f}, axisIR}); + histos.add("h2dGenOmegaMinusVsMultMCVsIR", "h2dGenOmegaMinusVsMultMCVsIR", kTH3D, {axisNch, axisIR, axisPt}); + histos.add("h2dGenOmegaPlusVsMultMCVsIR", "h2dGenOmegaPlusVsMultMCVsIR", kTH3D, {axisNch, axisIR, axisPt}); } } } + // Return slicing output + template + auto getGroupedCollisions(TCollisions const& collisions, int globalIndex) + { + if constexpr (run3) { // check if we are in Run 3 + return collisions.sliceBy(perMcCollision, globalIndex); + } else { // we are in Run2 + return collisions.sliceBy(perMcCollisionRun2, globalIndex); + } + } template - bool IsCosPAAccepted(TCascade casc, float x, float y, float z, bool ptdepcut, bool isCascPa) + bool isCosPAAccepted(TCascade casc, float x, float y, float z, bool ptdepcut, bool isCascPa) { if (ptdepcut) { double ptdepCut; if (isCascPa) - ptdepCut = cosPApar0 + cosPApar1 * casc.pt(); + ptdepCut = candidateSelectionValues.cosPApar0 + candidateSelectionValues.cosPApar1 * casc.pt(); else - ptdepCut = cosPApar0 + cosPApar1 * casc.pt(); + ptdepCut = candidateSelectionValues.cosPApar0 + candidateSelectionValues.cosPApar1 * casc.pt(); if (ptdepCut > 0.3 && casc.pt() < 0.5) ptdepCut = 0.3; if (ptdepCut < 0.012) ptdepCut = 0.012; if (isCascPa) - histos.fill(HIST("hCutValue"), 16, TMath::Cos(ptdepCut)); + histos.fill(HIST("hCutValue"), 15, std::cos(ptdepCut)); if (!isCascPa) - histos.fill(HIST("hCutValue"), 12, TMath::Cos(ptdepCut)); - if (isCascPa && casc.casccosPA(x, y, z) < TMath::Cos(ptdepCut)) + histos.fill(HIST("hCutValue"), 11, std::cos(ptdepCut)); + if (isCascPa && casc.casccosPA(x, y, z) < std::cos(ptdepCut)) return false; - if (!isCascPa && casc.v0cosPA(x, y, z) < TMath::Cos(ptdepCut)) + if (!isCascPa && casc.v0cosPA(x, y, z) < std::cos(ptdepCut)) return false; } else { - float cut = casccospa; - float cutV0 = v0cospa; + float cut = candidateSelectionValues.casccospa; + float cutV0 = candidateSelectionValues.v0cospa; if (isCascPa) - histos.fill(HIST("hCutValue"), 16, cut); + histos.fill(HIST("hCutValue"), 15, cut); if (!isCascPa) - histos.fill(HIST("hCutValue"), 12, cutV0); - if (isCascPa && casc.casccosPA(x, y, z) < casccospa) + histos.fill(HIST("hCutValue"), 11, cutV0); + if (isCascPa && casc.casccosPA(x, y, z) < candidateSelectionValues.casccospa) return false; - if (!isCascPa && casc.v0cosPA(x, y, z) < v0cospa) + if (!isCascPa && casc.v0cosPA(x, y, z) < candidateSelectionValues.v0cospa) return false; } return true; } + template - bool IsEventAccepted(TCollision coll, bool sel) + bool isEventAccepted(TCollision coll, bool fillHists) { - histos.fill(HIST("hEventSelection"), 0.5 /* all collisions */); - - if (doBefSelEventMultCorr) { - histos.fill(HIST("hEventNchCorrelationBefCuts"), coll.multNTracksPVeta1(), coll.multNTracksGlobal()); - histos.fill(HIST("hEventPVcontributorsVsCentralityBefCuts"), coll.centFT0C(), coll.multNTracksPVeta1()); - histos.fill(HIST("hEventGlobalTracksVsCentralityBefCuts"), coll.centFT0C(), coll.multNTracksGlobal()); + if (fillHists) + histos.fill(HIST("hEventSelection"), 0.5 /* all collisions */); + if (eventSelectionCommonFlags.doTriggerSel8EventCut && !coll.sel8()) { + return false; } + if (fillHists) + histos.fill(HIST("hEventSelection"), 1.5 /* collisions after sel8*/); - if (!sel) { + if (eventSelectionCommonFlags.doTriggerTVXEventCut && !coll.selection_bit(aod::evsel::kIsTriggerTVX)) { return false; } - histos.fill(HIST("hEventSelection"), 1.5 /* collisions after sel*/); - if (TMath::Abs(coll.posZ()) > zVertexCut) { + if (fillHists) + histos.fill(HIST("hEventSelection"), 2.5 /* collisions after TVX cut*/); + if (std::abs(coll.posZ()) > eventSelectionCommonFlags.zVertexCut) { return false; } + if (fillHists) + histos.fill(HIST("hEventSelection"), 3.5 /* collisions after sel pvz sel*/); + float centrality = -10; + double interactionRate = -10; + int occupancy = -2; + float occupancyFT0 = -2; + + if constexpr (requires { coll.centFT0C(); }) { + centrality = coll.centFT0C(); + if (useCentralityFT0M) + centrality = coll.centFT0M(); + if (useCentralityFT0A) + centrality = coll.centFV0A(); + if (useCentralityFT0Cvar1) + centrality = coll.centFT0CVariant1(); + + if (qaFlags.doBefSelEventMultCorr) { + histos.fill(HIST("hEventNchCorrelationBefCuts"), coll.multNTracksPVeta1(), coll.multNTracksGlobal()); + histos.fill(HIST("hEventPVcontributorsVsCentralityBefCuts"), centrality, coll.multNTracksPVeta1()); + histos.fill(HIST("hEventGlobalTracksVsCentralityBefCuts"), centrality, coll.multNTracksGlobal()); + } - histos.fill(HIST("hEventSelection"), 2.5 /* collisions after sel pvz sel*/); + if (centrality > eventSelectionCommonFlags.centMax || centrality < eventSelectionCommonFlags.centMin) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 4.5 /* collisions after centrality sel*/); - if (coll.centFT0C() > centMax || coll.centFT0C() < centMin) { - return false; - } + if (eventSelectionRun3Flags.doSameBunchPileUpEventCut && !coll.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 5.5 /* Not same Bunch pile up */); - histos.fill(HIST("hEventSelection"), 3.5 /* collisions after centrality sel*/); + if (eventSelectionRun3Flags.doGoodPVFT0EventCut && !coll.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 6.5 /* No large vertexZ difference from tracks and FT0*/); - if (doSameBunchPileUpEventCut && !coll.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { - return false; - } - histos.fill(HIST("hEventSelection"), 4.5 /* Not same Bunch pile up */); + if (eventSelectionRun3Flags.doITSTPCvertexEventCut && !coll.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 7.5 /* At least one ITS-TPC track in the event*/); - if (doGoodPVFT0EventCut && !coll.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { - return false; - } - histos.fill(HIST("hEventSelection"), 5.5 /* No large vertexZ difference from tracks and FT0*/); + if (eventSelectionRun3Flags.doVertexTOFmatch && !coll.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 8.5 /* At least one of vertex contributors is matched to TOF*/); - if (doITSTPCvertexEventCut && !coll.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { - return false; - } - histos.fill(HIST("hEventSelection"), 6.5 /* At least one ITS-TPC track in the event*/); + if (eventSelectionRun3Flags.doVertexTRDmatch && !coll.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 9.5 /* At least one of vertex contributors is matched to TRD*/); - if (doVertexTOFmatch && !coll.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { - return false; - } - histos.fill(HIST("hEventSelection"), 7.5 /* At least one of vertex contributors is matched to TOF*/); + if (eventSelectionRun3Flags.doITSFrameBorderCut && !coll.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 10.5 /* Not at ITS ROF border */); - if (doVertexTRDmatch && !coll.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { - return false; - } - histos.fill(HIST("hEventSelection"), 8.5 /* At least one of vertex contributors is matched to TRD*/); + if (eventSelectionRun3Flags.doTFeventCut && !coll.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 11.5 /* Not at TF border */); - if (doITSFrameBorderCut && !coll.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { - return false; - } - histos.fill(HIST("hEventSelection"), 9.5 /* Not at ITS ROF border */); + if (eventSelectionRun3Flags.doMultiplicityCorrCut) { + if (coll.multNTracksGlobal() < (1343.3 * std::exp(-0.0443259 * centrality) - 50) || coll.multNTracksGlobal() > (2098.9 * std::exp(-0.0332444 * centrality))) + return false; + if (coll.multNTracksPVeta1() < (3703 * std::exp(-0.0455483 * centrality) - 150) || coll.multNTracksPVeta1() > (4937.33 * std::exp(-0.0372668 * centrality) + 20)) + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 12.5 /* Remove outlyers */); - if (doTFeventCut && !coll.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { - return false; - } - histos.fill(HIST("hEventSelection"), 10.5 /* Not at TF border */); + if (eventSelectionRun3Flags.doTimeRangeStrictCut && !coll.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 13.5 /* Rejection of events too close in time, dtime +/- 10 μs */); + + if (eventSelectionRun3Flags.doTimeRangeStandardCut && !coll.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 14.5 /* No other collision within +/- 2 μs, or mult above some threshold in -4..-2 μs */); + + occupancy = coll.trackOccupancyInTimeRange(); + if (eventSelectionRun3Flags.minOccupancy > 0 && occupancy < eventSelectionRun3Flags.minOccupancy) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 15.5 /* Below min occupancy */); + if (eventSelectionRun3Flags.maxOccupancy > 0 && occupancy > eventSelectionRun3Flags.maxOccupancy) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 16.5 /* Above max occupancy */); + + if (eventSelectionRun3Flags.doNoCollInRofStrictCut && !coll.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 17.5 /*rejects a collision if there are other events within the same ITS ROF*/); + + if (eventSelectionRun3Flags.doNoCollInRofStandardCut && !coll.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 18.5 /*rejects a collision if there are other events within the same ITS ROF above mult threshold*/); + + if (eventSelectionRun3Flags.doITSallLayersCut && !coll.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 19.5 /*rejects collisions if ITS was in rebooting stage*/); + + occupancyFT0 = coll.ft0cOccupancyInTimeRange(); + if (eventSelectionRun3Flags.minOccupancyFT0 > -1 && occupancyFT0 < eventSelectionRun3Flags.minOccupancyFT0) { + return false; + } + if (eventSelectionRun3Flags.maxOccupancyFT0 > -1 && occupancyFT0 > eventSelectionRun3Flags.maxOccupancyFT0) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 20.5 /* Occupancy FT0 selection */); + + interactionRate = rateFetcher.fetch(ccdb.service, coll.timestamp(), coll.runNumber(), irSource) * 1.e-3; + } else { + centrality = eventSelectionRun2Flags.useSPDTrackletsCent ? coll.centRun2SPDTracklets() : coll.centRun2V0M(); - if (doMultiplicityCorrCut) { - if (coll.multNTracksGlobal() < (1343.3 * TMath::Exp(-0.0443259 * coll.centFT0C()) - 50) || coll.multNTracksGlobal() > (2098.9 * TMath::Exp(-0.0332444 * coll.centFT0C()))) + if (centrality > eventSelectionCommonFlags.centMax || centrality < eventSelectionCommonFlags.centMin) { return false; - if (coll.multNTracksPVeta1() < (3703 * TMath::Exp(-0.0455483 * coll.centFT0C()) - 150) || coll.multNTracksPVeta1() > (4937.33 * TMath::Exp(-0.0372668 * coll.centFT0C()) + 20)) + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 4.5 /* collisions after centrality sel*/); + + if (eventSelectionRun2Flags.doSel7 && !coll.sel7()) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 5.5 /* sel7 selection */); + + if (eventSelectionRun2Flags.doINT7 && !coll.alias_bit(kINT7)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 6.5 /* INT7-triggered collisions */); + if (eventSelectionRun2Flags.doIncompleteDAQCut && !coll.selection_bit(o2::aod::evsel::kNoIncompleteDAQ)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 7.5 /* Complete events according to DAQ flags */); + + if (eventSelectionRun2Flags.doConsistentSPDAndTrackVtx && !coll.selection_bit(o2::aod::evsel::kNoInconsistentVtx)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 8.5 /* No inconsistency in SPD and Track vertices */); + if (eventSelectionRun2Flags.doPileupFromSPDCut && !coll.selection_bit(o2::aod::evsel::kNoPileupFromSPD)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 9.5 /* No pileup according to SPD vertexer */); + if (eventSelectionRun2Flags.doV0PFPileupCut && !coll.selection_bit(o2::aod::evsel::kNoV0PFPileup)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 10.5 /* No out-of-bunch pileup according to V0 past-future info */); + + if (eventSelectionRun2Flags.doPileupInMultBinsCut && !coll.selection_bit(o2::aod::evsel::kNoPileupInMultBins)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 11.5 /* No pileup according to multiplicity-differential pileup checks */); + + if (eventSelectionRun2Flags.doPileupMVCut && !coll.selection_bit(o2::aod::evsel::kNoPileupMV)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 12.5 /* No pileup according to multi-vertexer */); + + if (eventSelectionRun2Flags.doTPCPileupCut && !coll.selection_bit(o2::aod::evsel::kNoPileupTPC)) { return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 13.5 /* No pileup in TPC */); + + if (eventSelectionRun2Flags.doNoV0MOnVsOffPileup && !coll.selection_bit(o2::aod::evsel::kNoV0MOnVsOfPileup)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 14.5 /* No out-of-bunch pileup according to online-vs-offline VOM correlation */); + + if (eventSelectionRun2Flags.doNoSPDOnVsOffPileup && !coll.selection_bit(o2::aod::evsel::kNoSPDOnVsOfPileup)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 15.5 /* No out-of-bunch pileup according to online-vs-offline SPD correlation */); + + if (eventSelectionRun2Flags.doNoSPDClsVsTklBG && !coll.selection_bit(o2::aod::evsel::kNoSPDClsVsTklBG)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 16.5 /* No beam-gas according to cluster-vs-tracklet correlation */); + } + if (eventSelectionCommonFlags.doInel0 && coll.multNTracksPVeta1() < 1) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 27.5 /* INEL > 0 selection */); + + if (fillHists) { + histos.fill(HIST("hInteractionRate"), interactionRate); + histos.fill(HIST("hCentralityVsInteractionRate"), centrality, interactionRate); + histos.fill(HIST("hOccupancyVsOccupFt0VsCentrality"), occupancy, occupancyFT0, centrality); + histos.fill(HIST("hEventCentrality"), centrality); + histos.fill(HIST("hEventVertexZ"), coll.posZ()); + histos.fill(HIST("hEventMultFt0C"), coll.multFT0C()); + histos.fill(HIST("hEventNchCorrelationAfCuts"), coll.multNTracksPVeta1(), coll.multNTracksGlobal()); + histos.fill(HIST("hEventPVcontributorsVsCentrality"), centrality, coll.multNTracksPVeta1()); + histos.fill(HIST("hEventGlobalTracksVsCentrality"), centrality, coll.multNTracksGlobal()); } - histos.fill(HIST("hEventSelection"), 11.5 /* Remove outlyers */); - histos.fill(HIST("hEventCentrality"), coll.centFT0C()); - histos.fill(HIST("hEventVertexZ"), coll.posZ()); - histos.fill(HIST("hEventNchCorrelationAfCuts"), coll.multNTracksPVeta1(), coll.multNTracksGlobal()); - histos.fill(HIST("hEventPVcontributorsVsCentrality"), coll.centFT0C(), coll.multNTracksPVeta1()); - histos.fill(HIST("hEventGlobalTracksVsCentrality"), coll.centFT0C(), coll.multNTracksGlobal()); return true; } template - bool IsCascadeCandidateAccepted(TCascade casc, int counter, float /*centrality*/) + bool isCascadeCandidateAccepted(TCascade casc, int counter, float /*centrality*/) { - float cut = masswin; + float cut = candidateSelectionValues.masswin; + histos.fill(HIST("hCutValue"), 1, cut); + cut = candidateSelectionValues.rapCut; histos.fill(HIST("hCutValue"), 2, cut); - cut = rapCut; - histos.fill(HIST("hCutValue"), 3, cut); if (isXi) { - if (TMath::Abs(casc.mXi() - pdgDB->Mass(3312)) > masswin) { + if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > candidateSelectionValues.masswin) { return false; } histos.fill(HIST("hCandidate"), ++counter); - if (TMath::Abs(casc.yXi()) > rapCut) + if (std::abs(casc.yXi()) > candidateSelectionValues.rapCut) return false; histos.fill(HIST("hCandidate"), ++counter); } else { - if (TMath::Abs(casc.mOmega() - pdgDB->Mass(3334)) > masswin) { + if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > candidateSelectionValues.masswin) { return false; } histos.fill(HIST("hCandidate"), ++counter); - if (TMath::Abs(casc.yOmega()) > rapCut) + if (std::abs(casc.yOmega()) > candidateSelectionValues.rapCut) return false; histos.fill(HIST("hCandidate"), ++counter); } - if (doDCACascadeDauCut) { - if (doPtDepDCAcascDauCut) { - float ptDepCut = dcaCacsDauPar0; + if (candidateSelectionFlags.doDCACascadeDauCut) { + if (candidateSelectionFlags.doPtDepDCAcascDauCut) { + float ptDepCut = candidateSelectionValues.dcaCacsDauPar0; if (casc.pt() > 1 && casc.pt() < 4) - ptDepCut = dcaCacsDauPar1; + ptDepCut = candidateSelectionValues.dcaCacsDauPar1; else if (casc.pt() > 4) - ptDepCut = dcaCacsDauPar2; - histos.fill(HIST("hCutValue"), 4, ptDepCut); + ptDepCut = candidateSelectionValues.dcaCacsDauPar2; + histos.fill(HIST("hCutValue"), 3, ptDepCut); if (casc.dcacascdaughters() > ptDepCut) return false; } else { - cut = dcacascdau; - histos.fill(HIST("hCutValue"), 4, cut); - if (casc.dcacascdaughters() > dcacascdau) + cut = candidateSelectionValues.dcacascdau; + histos.fill(HIST("hCutValue"), 3, cut); + if (casc.dcacascdaughters() > candidateSelectionValues.dcacascdau) return false; } histos.fill(HIST("hCandidate"), ++counter); - } else + } else { + if (qaFlags.doPtDepCutStudy) + selectionCheck = casc.dcacascdaughters(); ++counter; + } - if (doDCAV0DauCut) { - cut = dcav0dau; - histos.fill(HIST("hCutValue"), 5, cut); - if (casc.dcaV0daughters() > dcav0dau) + if (candidateSelectionFlags.doDCAV0DauCut) { + cut = candidateSelectionValues.dcav0dau; + histos.fill(HIST("hCutValue"), 4, cut); + if (casc.dcaV0daughters() > candidateSelectionValues.dcav0dau) return false; histos.fill(HIST("hCandidate"), ++counter); - } else + } else { + if (qaFlags.doPtDepCutStudy) + selectionCheck = casc.dcaV0daughters(); ++counter; + } - if (doCascadeRadiusCut) { - if (doPtDepCascRadiusCut) { - double ptdepminRadius = parCascRadius0 + parCascRadius1 * casc.pt(); - histos.fill(HIST("hCutValue"), 6, ptdepminRadius); + if (candidateSelectionFlags.doCascadeRadiusCut) { + if (candidateSelectionFlags.doPtDepCascRadiusCut) { + double ptdepminRadius = candidateSelectionValues.parCascRadius0 + candidateSelectionValues.parCascRadius1 * casc.pt(); + histos.fill(HIST("hCutValue"), 5, ptdepminRadius); if (casc.cascradius() < ptdepminRadius) return false; } else { - cut = minRadius; - histos.fill(HIST("hCutValue"), 6, cut); - if (casc.cascradius() < minRadius) + cut = candidateSelectionValues.minRadius; + histos.fill(HIST("hCutValue"), 5, cut); + if (casc.cascradius() < candidateSelectionValues.minRadius) return false; } histos.fill(HIST("hCandidate"), ++counter); - if (casc.cascradius() > maxRadius) + if (casc.cascradius() > candidateSelectionValues.maxRadius) return false; histos.fill(HIST("hCandidate"), ++counter); - } else + } else { + if (qaFlags.doPtDepCutStudy) + selectionCheck = casc.cascradius(); counter += 2; + } - if (doV0RadiusCut) { - if (doPtDepV0RadiusCut) { - float cut = parV0Radius0 + casc.pt() * parV0Radius1; - histos.fill(HIST("hCutValue"), 8, cut); + if (candidateSelectionFlags.doV0RadiusCut) { + if (candidateSelectionFlags.doPtDepV0RadiusCut) { + float cut = candidateSelectionValues.parV0Radius0 + casc.pt() * candidateSelectionValues.parV0Radius1; + histos.fill(HIST("hCutValue"), 7, cut); if (casc.v0radius() < cut) return false; } else { - cut = minV0Radius; - histos.fill(HIST("hCutValue"), 8, cut); - if (casc.v0radius() < minV0Radius) + cut = candidateSelectionValues.minV0Radius; + histos.fill(HIST("hCutValue"), 7, cut); + if (casc.v0radius() < candidateSelectionValues.minV0Radius) return false; } histos.fill(HIST("hCandidate"), ++counter); - if (casc.v0radius() > maxV0Radius) + if (casc.v0radius() > candidateSelectionValues.maxV0Radius) return false; histos.fill(HIST("hCandidate"), ++counter); - } else + } else { + if (qaFlags.doPtDepCutStudy) + selectionCheck = casc.v0radius(); counter += 2; + } - cut = lambdaMassWin; - histos.fill(HIST("hCutValue"), 10, cut); - if (TMath::Abs(casc.mLambda() - pdgDB->Mass(3122)) > lambdaMassWin) + cut = candidateSelectionValues.lambdaMassWin; + histos.fill(HIST("hCutValue"), 9, cut); + if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > candidateSelectionValues.lambdaMassWin) return false; histos.fill(HIST("hCandidate"), ++counter); - cut = bachBaryonDCAxyToPV; - histos.fill(HIST("hCutValue"), 11, cut); - if (doBachelorBaryonCut) { - if ((casc.bachBaryonCosPA() > bachBaryonCosPA || TMath::Abs(casc.bachBaryonDCAxyToPV()) < bachBaryonDCAxyToPV)) { // Bach-baryon selection if required + cut = candidateSelectionValues.bachBaryonDCAxyToPV; + histos.fill(HIST("hCutValue"), 10, cut); + if (candidateSelectionFlags.doBachelorBaryonCut) { + if ((casc.bachBaryonCosPA() > candidateSelectionValues.bachBaryonCosPA || std::abs(casc.bachBaryonDCAxyToPV()) < candidateSelectionValues.bachBaryonDCAxyToPV)) { // Bach-baryon selection if required return false; } histos.fill(HIST("hCandidate"), ++counter); - } else + } else { + if (qaFlags.doPtDepCutStudy) + selectionCheck = casc.bachBaryonDCAxyToPV(); ++counter; + } - if (doV0CosPaCut) { - if (!IsCosPAAccepted(casc, casc.x(), casc.y(), casc.z(), doPtDepV0CosPaCut, false)) + if (candidateSelectionFlags.doV0CosPaCut) { + if (!isCosPAAccepted(casc, casc.x(), casc.y(), casc.z(), candidateSelectionFlags.doPtDepV0CosPaCut, false)) return false; histos.fill(HIST("hCandidate"), ++counter); - } else + } else { + if (qaFlags.doPtDepCutStudy) + selectionCheck = std::acos(casc.v0cosPA(casc.x(), casc.y(), casc.z())); ++counter; + } - cut = rejcomp; - histos.fill(HIST("hCutValue"), 13, cut); + cut = candidateSelectionValues.rejcomp; + histos.fill(HIST("hCutValue"), 12, cut); if (isXi) { - if (TMath::Abs(casc.mOmega() - pdgDB->Mass(3334)) < rejcomp) + if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) < candidateSelectionValues.rejcomp) return false; histos.fill(HIST("hCandidate"), ++counter); } else { - if (TMath::Abs(casc.mXi() - pdgDB->Mass(3312)) < rejcomp) + if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) < candidateSelectionValues.rejcomp) return false; histos.fill(HIST("hCandidate"), ++counter); } - cut = dcaBachToPV; - histos.fill(HIST("hCutValue"), 14, cut); - cut = dcaMesonToPV; - histos.fill(HIST("hCutValue"), 14, cut); - cut = dcaBaryonToPV; - histos.fill(HIST("hCutValue"), 14, cut); - if (doDCAdauToPVCut) { - if (TMath::Abs(casc.dcabachtopv()) < dcaBachToPV) + cut = candidateSelectionValues.dcaBachToPV; + histos.fill(HIST("hCutValue"), 13, cut); + cut = candidateSelectionValues.dcaMesonToPV; + histos.fill(HIST("hCutValue"), 13, cut); + cut = candidateSelectionValues.dcaBaryonToPV; + histos.fill(HIST("hCutValue"), 13, cut); + if (candidateSelectionFlags.doDCAbachToPVCut || candidateSelectionFlags.doDCAmesonToPVCut || candidateSelectionFlags.doDCAbaryonToPVCut) { + if (candidateSelectionFlags.doDCAbachToPVCut && std::abs(casc.dcabachtopv()) < candidateSelectionValues.dcaBachToPV) return false; - if (casc.sign() > 0 && (TMath::Abs(casc.dcanegtopv()) < dcaBaryonToPV || TMath::Abs(casc.dcapostopv()) < dcaMesonToPV)) + if (casc.sign() > 0 && ((std::abs(casc.dcanegtopv()) < candidateSelectionValues.dcaBaryonToPV && candidateSelectionFlags.doDCAbaryonToPVCut) || (std::abs(casc.dcapostopv()) < candidateSelectionValues.dcaMesonToPV && candidateSelectionFlags.doDCAmesonToPVCut))) return false; - if (casc.sign() < 0 && (TMath::Abs(casc.dcapostopv()) < dcaBaryonToPV || TMath::Abs(casc.dcanegtopv()) < dcaMesonToPV)) + if (casc.sign() < 0 && ((std::abs(casc.dcapostopv()) < candidateSelectionValues.dcaBaryonToPV && candidateSelectionFlags.doDCAbaryonToPVCut) || (std::abs(casc.dcanegtopv()) < candidateSelectionValues.dcaMesonToPV && candidateSelectionFlags.doDCAmesonToPVCut))) return false; histos.fill(HIST("hCandidate"), ++counter); - } else + } else { + if (qaFlags.doPtDepCutStudy) { + if (!candidateSelectionFlags.doDCAbachToPVCut) + selectionCheck = std::abs(casc.dcabachtopv()); + if (!candidateSelectionFlags.doDCAbaryonToPVCut && casc.sign() > 0) + selectionCheck = std::abs(casc.dcanegtopv()); + if (!candidateSelectionFlags.doDCAbaryonToPVCut && casc.sign() < 0) + selectionCheck = std::abs(casc.dcapostopv()); + if (!candidateSelectionFlags.doDCAmesonToPVCut && casc.sign() > 0) + selectionCheck = std::abs(casc.dcapostopv()); + if (!candidateSelectionFlags.doDCAmesonToPVCut && casc.sign() < 0) + selectionCheck = std::abs(casc.dcanegtopv()); + } ++counter; + } return true; } - - void processCascades(soa::Join::iterator const& coll, soa::Join const& Cascades, soa::Join const&) + void fillHistOccupancyCheck(double pt, double mass, float occup, float centrality, bool isPos) + { + static_for<0, 9>([&](auto i) { + constexpr int In = i.value; + if (centrality < kCentralityIntervals[In + 1] && centrality > kCentralityIntervals[In]) { + if (isPos) + histos.fill(HIST("InvMassAfterSelCent") + HIST(kCentIndex[In]) + HIST("/hPositiveCascade"), pt, mass, occup); + else + histos.fill(HIST("InvMassAfterSelCent") + HIST(kCentIndex[In]) + HIST("/hNegativeCascade"), pt, mass, occup); + } + }); + } + void fillHistIRCheckData(double pt, double mass, double ir, float centrality, bool isPos) + { + static_for<0, 9>([&](auto i) { + constexpr int In = i.value; + if (centrality < kCentralityIntervals[In + 1] && centrality > kCentralityIntervals[In]) { + if (isPos) + histos.fill(HIST("InvMassAfterSelCent") + HIST(kCentIndex[In]) + HIST("/hPositiveCascadeIR"), pt, mass, ir); + else + histos.fill(HIST("InvMassAfterSelCent") + HIST(kCentIndex[In]) + HIST("/hNegativeCascadeIR"), pt, mass, ir); + } + }); + } + void fillHistIRCheckMC(double pt, double mass, double ir, float centrality, bool isPos) + { + static_for<0, 9>([&](auto i) { + constexpr int In = i.value; + if (centrality < kCentralityIntervals[In + 1] && centrality > kCentralityIntervals[In]) { + if (isPos) + histos.fill(HIST("InvMassAfterSelCent") + HIST(kCentIndex[In]) + HIST("/hPositiveCascadeMCTruthIR"), pt, mass, ir); + else + histos.fill(HIST("InvMassAfterSelCent") + HIST(kCentIndex[In]) + HIST("/hNegativeCascadeMCTruthIR"), pt, mass, ir); + } + }); + } + void fillHistPtDepSelectionStudy(double pt, double mass, double sel, uint64_t selectionCheckMask, bool isPos) + { + static_for<0, 11>([&](auto i) { + constexpr int In = i.value; + if (TESTBIT(selectionCheckMask, In)) { + if (isPos) + histos.fill(HIST("PtDepCutStudy/hPositive") + HIST(kSelectionNames[In]), pt, mass, sel); + else + histos.fill(HIST("PtDepCutStudy/hNegative") + HIST(kSelectionNames[In]), pt, mass, sel); + } + }); + } + void fillHistPtDepSelectionStudyMC(double pt, double mass, double sel, uint64_t selectionCheckMask, bool isPos) + { + static_for<0, 11>([&](auto i) { + constexpr int In = i.value; + if (TESTBIT(selectionCheckMask, In)) { + if (isPos) + histos.fill(HIST("PtDepCutStudyMCTruth/hPositive") + HIST(kSelectionNames[In]), pt, mass, sel); + else + histos.fill(HIST("PtDepCutStudyMCTruth/hNegative") + HIST(kSelectionNames[In]), pt, mass, sel); + } + }); + } + template + void analyseCascades(TCollision const& coll, TCascade const& Cascades) //(soa::Join::iterator const& coll, soa::Join const& Cascades, DauTracks const&)//(TCollision const& coll, TCascade const& Cascades) { - if (!IsEventAccepted(coll, coll.sel8())) + if (!isEventAccepted(coll, true)) return; + float centrality = -1; + float nChEta1 = -1; + float occupancy = -2; + + if constexpr (requires { coll.centFT0C(); }) { + nChEta1 = coll.multNTracksPVeta1(); + centrality = coll.centFT0C(); + if (useCentralityFT0M) + centrality = coll.centFT0M(); + if (useCentralityFT0A) + centrality = coll.centFV0A(); + if (useCentralityFT0Cvar1) + centrality = coll.centFT0CVariant1(); + occupancy = useTrackOccupancyDef ? coll.trackOccupancyInTimeRange() : coll.ft0cOccupancyInTimeRange(); + } else { + centrality = eventSelectionRun2Flags.useSPDTrackletsCent ? coll.centRun2SPDTracklets() : coll.centRun2V0M(); + } - for (auto& casc : Cascades) { + for (const auto& casc : Cascades) { int counter = -1; histos.fill(HIST("hCandidate"), ++counter); - double invmass; - if (isXi) - invmass = casc.mXi(); - else - invmass = casc.mOmega(); + double recoPt = casc.pt(); + + bool isNegative = false; + bool isPositive = false; + if (casc.sign() > 0) + isPositive = true; + if (casc.sign() < 0) + isNegative = true; + if (!isNegative && !isPositive) + continue; + + double invmass = -10; + invmass = isXi ? casc.mXi() : casc.mOmega(); // To have trace of how it was before selections - if (casc.sign() < 0 && doBefSelCheck) { - histos.fill(HIST("InvMassBefSel/hNegativeCascade"), casc.pt(), invmass, coll.centFT0C()); + if (qaFlags.doBefSelCheck) { + if (isPositive) + histos.fill(HIST("InvMassBefSel/hPositiveCascade"), recoPt, invmass, centrality); + if (isNegative) + histos.fill(HIST("InvMassBefSel/hNegativeCascade"), recoPt, invmass, centrality); } - if (casc.sign() > 0 && doBefSelCheck) { - histos.fill(HIST("InvMassBefSel/hPositiveCascade"), casc.pt(), invmass, coll.centFT0C()); + + bool isTrueMCCascade = false; + bool isTrueMCCascadeDecay = false; + bool isCorrectLambdaDecay = false; + float ptmc = -1; + + // MC part + if constexpr (requires { casc.has_cascMCCore(); }) { + if (!casc.has_cascMCCore()) + continue; + auto cascMC = casc.template cascMCCore_as>(); + ptmc = RecoDecay::sqrtSumOfSquares(cascMC.pxMC(), cascMC.pyMC()); + + if (cascMC.isPhysicalPrimary() && ((isXi && std::abs(cascMC.pdgCode()) == 3312) || (!isXi && std::abs(cascMC.pdgCode()) == 3334))) + isTrueMCCascade = true; + if (isTrueMCCascade && ((isPositive && cascMC.pdgCodePositive() == 211 && cascMC.pdgCodeNegative() == -2212) || (isNegative && cascMC.pdgCodePositive() == 2212 && cascMC.pdgCodeNegative() == -211))) + isCorrectLambdaDecay = true; + if (isTrueMCCascade && isCorrectLambdaDecay && ((isXi && std::abs(cascMC.pdgCodeBachelor()) == 211) || (!isXi && std::abs(cascMC.pdgCodeBachelor()) == 321))) + isTrueMCCascadeDecay = true; + + if (qaFlags.doBefSelCheck && isTrueMCCascade) { + if (isPositive) { + histos.fill(HIST("InvMassBefSel/hPositiveCascadePtForEfficiencyVsNchBefSel"), ptmc, invmass, nChEta1); + histos.fill(HIST("InvMassBefSel/hPositiveCascadePtForEfficiencyBefSel"), ptmc, invmass, centrality); + } + if (isNegative) { + histos.fill(HIST("InvMassBefSel/hNegativeCascadePtForEfficiencyVsNchBefSel"), ptmc, invmass, nChEta1); + histos.fill(HIST("InvMassBefSel/hNegativeCascadePtForEfficiencyBefSel"), ptmc, invmass, centrality); + } + } } - if (!IsCascadeCandidateAccepted(casc, counter, coll.centFT0C())) + if (!isCascadeCandidateAccepted(casc, counter, centrality)) continue; counter += 13; - auto negExtra = casc.negTrackExtra_as>(); - auto posExtra = casc.posTrackExtra_as>(); - auto bachExtra = casc.bachTrackExtra_as>(); + auto negExtra = casc.template negTrackExtra_as>(); + auto posExtra = casc.template posTrackExtra_as>(); + auto bachExtra = casc.template bachTrackExtra_as>(); auto poseta = RecoDecay::eta(std::array{casc.pxpos(), casc.pypos(), casc.pzpos()}); auto negeta = RecoDecay::eta(std::array{casc.pxneg(), casc.pyneg(), casc.pzneg()}); auto bacheta = RecoDecay::eta(std::array{casc.pxbach(), casc.pybach(), casc.pzbach()}); - float cut = etaDauCut; + + auto fullMomentumPosDaugh = std::sqrt(std::pow(casc.pxpos(), 2) + std::pow(casc.pypos(), 2) + std::pow(casc.pzpos(), 2)); + auto fullmomentumNegDaugh = std::sqrt(std::pow(casc.pxneg(), 2) + std::pow(casc.pyneg(), 2) + std::pow(casc.pzneg(), 2)); + auto fullmomentumBachelor = std::sqrt(std::pow(casc.pxbach(), 2) + std::pow(casc.pybach(), 2) + std::pow(casc.pzbach(), 2)); + + float cut = candidateSelectionValues.etaDauCut; histos.fill(HIST("hCutValue"), counter + 1, cut); - if (TMath::Abs(poseta) > etaDauCut || TMath::Abs(negeta) > etaDauCut || TMath::Abs(bacheta) > etaDauCut) + if (std::abs(poseta) > candidateSelectionValues.etaDauCut || std::abs(negeta) > candidateSelectionValues.etaDauCut || std::abs(bacheta) > candidateSelectionValues.etaDauCut) continue; histos.fill(HIST("hCandidate"), ++counter); - if (doCascadeCosPaCut) { - if (!IsCosPAAccepted(casc, coll.posX(), coll.posY(), coll.posZ(), doPtDepCosPaCut, true)) + if (candidateSelectionFlags.doCascadeCosPaCut) { + if (!isCosPAAccepted(casc, coll.posX(), coll.posY(), coll.posZ(), candidateSelectionFlags.doPtDepCosPaCut, true)) continue; histos.fill(HIST("hCandidate"), ++counter); - } else + } else { + if (qaFlags.doPtDepCutStudy) + selectionCheck = std::acos(casc.v0cosPA(coll.posX(), coll.posY(), coll.posZ())); ++counter; + } - cut = dcaV0ToPV; - histos.fill(HIST("hCutValue"), 17, cut); - if (doDCAV0ToPVCut) { - if (TMath::Abs(casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ())) < dcaV0ToPV) + cut = candidateSelectionValues.dcaV0ToPV; + histos.fill(HIST("hCutValue"), 16, cut); + if (candidateSelectionFlags.doDCAV0ToPVCut) { + if (std::abs(casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ())) < candidateSelectionValues.dcaV0ToPV) continue; histos.fill(HIST("hCandidate"), ++counter); - } else + } else { + if (qaFlags.doPtDepCutStudy) + selectionCheck = std::abs(casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ())); ++counter; + } - if (doNTPCSigmaCut) { - if (casc.sign() < 0) { - histos.fill(HIST("hNsigmaProton"), posExtra.tpcNSigmaPr(), TMath::Sqrt(TMath::Power(casc.pxpos(), 2) + TMath::Power(casc.pypos(), 2) + TMath::Power(casc.pzpos(), 2)), coll.centFT0C()); - histos.fill(HIST("hNsigmaPionNeg"), negExtra.tpcNSigmaPi(), TMath::Sqrt(TMath::Power(casc.pxneg(), 2) + TMath::Power(casc.pyneg(), 2) + TMath::Power(casc.pzneg(), 2)), coll.centFT0C()); - if (TMath::Abs(posExtra.tpcNSigmaPr()) > nsigmatpcPr || TMath::Abs(negExtra.tpcNSigmaPi()) > nsigmatpcPi) + if (isNegative) { + if (qaFlags.doFillNsigmaTPCHistProton) + histos.fill(HIST("hNsigmaProton"), posExtra.tpcNSigmaPr(), fullMomentumPosDaugh, centrality); + if (qaFlags.doFillNsigmaTPCHistV0Pion) + histos.fill(HIST("hNsigmaPionNeg"), negExtra.tpcNSigmaPi(), fullmomentumNegDaugh, centrality); + if (qaFlags.doFillNsigmaTPCHistPionBach && isXi) + histos.fill(HIST("hNsigmaPionNegBach"), bachExtra.tpcNSigmaPi(), fullmomentumBachelor, centrality); + if (qaFlags.doFillNsigmaTPCHistPionBach && !isXi) + histos.fill(HIST("hNsigmaKaon"), bachExtra.tpcNSigmaPi(), fullmomentumBachelor, centrality); + + } else { + if (qaFlags.doFillNsigmaTPCHistV0Pion) + histos.fill(HIST("hNsigmaPionPos"), posExtra.tpcNSigmaPi(), fullMomentumPosDaugh, centrality); + if (qaFlags.doFillNsigmaTPCHistProton) + histos.fill(HIST("hNsigmaProtonNeg"), negExtra.tpcNSigmaPr(), fullmomentumNegDaugh, centrality); + if (qaFlags.doFillNsigmaTPCHistPionBach && isXi) + histos.fill(HIST("hNsigmaPionPosBach"), bachExtra.tpcNSigmaPi(), fullmomentumBachelor, centrality); + if (qaFlags.doFillNsigmaTPCHistPionBach && !isXi) + histos.fill(HIST("hNsigmaKaon"), bachExtra.tpcNSigmaPi(), fullmomentumBachelor, centrality); + } + + if (isNegative) { + if (candidateSelectionFlags.doNTPCSigmaCut) { + if (std::abs(posExtra.tpcNSigmaPr()) > candidateSelectionValues.nsigmatpcPr || std::abs(negExtra.tpcNSigmaPi()) > candidateSelectionValues.nsigmatpcPi) continue; histos.fill(HIST("hCandidate"), ++counter); - } else if (casc.sign() > 0) { - histos.fill(HIST("hNsigmaPionPos"), posExtra.tpcNSigmaPi(), TMath::Sqrt(TMath::Power(casc.pxpos(), 2) + TMath::Power(casc.pypos(), 2) + TMath::Power(casc.pzpos(), 2)), coll.centFT0C()); - histos.fill(HIST("hNsigmaProtonNeg"), negExtra.tpcNSigmaPr(), TMath::Sqrt(TMath::Power(casc.pxneg(), 2) + TMath::Power(casc.pyneg(), 2) + TMath::Power(casc.pzneg(), 2)), coll.centFT0C()); - if (TMath::Abs(posExtra.tpcNSigmaPi()) > nsigmatpcPi || TMath::Abs(negExtra.tpcNSigmaPr()) > nsigmatpcPr) + } else { + ++counter; + } + } else { + if (candidateSelectionFlags.doNTPCSigmaCut) { + if (std::abs(posExtra.tpcNSigmaPi()) > candidateSelectionValues.nsigmatpcPi || std::abs(negExtra.tpcNSigmaPr()) > candidateSelectionValues.nsigmatpcPr) continue; histos.fill(HIST("hCandidate"), ++counter); + } else { + ++counter; } - } else - ++counter; + } - if (posExtra.tpcCrossedRows() < mintpccrrows || negExtra.tpcCrossedRows() < mintpccrrows || bachExtra.tpcCrossedRows() < mintpccrrows) + histos.fill(HIST("hNCrossedRowsBachelor"), bachExtra.tpcCrossedRows()); + histos.fill(HIST("hNCrossedRowsNegative"), negExtra.tpcCrossedRows()); + histos.fill(HIST("hNCrossedRowsPositive"), posExtra.tpcCrossedRows()); + + if (qaFlags.doITSTPCmatchingCheck) { + auto ptPosDaugh = std::sqrt(std::pow(casc.pxpos(), 2) + std::pow(casc.pypos(), 2)); + auto ptNegDaugh = std::sqrt(std::pow(casc.pxneg(), 2) + std::pow(casc.pyneg(), 2)); + auto ptBachelor = std::sqrt(std::pow(casc.pxbach(), 2) + std::pow(casc.pybach(), 2)); + + histos.fill(HIST("histITSTPCmatchPosTrack"), ptPosDaugh, centrality, 0.5); + histos.fill(HIST("histITSTPCmatchNegTrack"), ptNegDaugh, centrality, 0.5); + histos.fill(HIST("histITSTPCmatchBachTrack"), ptBachelor, centrality, 0.5); + if (candidateSelectionFlags.doAllTracksMinITSClusters) { + if (posExtra.hasITS() && posExtra.itsNCls() >= candidateSelectionValues.minITSclusters) + histos.fill(HIST("histITSTPCmatchPosTrack"), ptPosDaugh, centrality, 1.5); + if (negExtra.hasITS() && negExtra.itsNCls() >= candidateSelectionValues.minITSclusters) + histos.fill(HIST("histITSTPCmatchNegTrack"), ptNegDaugh, centrality, 1.5); + if (bachExtra.hasITS() && bachExtra.itsNCls() >= candidateSelectionValues.minITSclusters) + histos.fill(HIST("histITSTPCmatchBachTrack"), ptBachelor, centrality, 1.5); + if (posExtra.hasITS() && posExtra.itsNCls() >= candidateSelectionValues.minITSclusters && posExtra.hasTPC() && std::abs(posExtra.tpcCrossedRows()) >= candidateSelectionValues.mintpccrrows) + histos.fill(HIST("histITSTPCmatchPosTrack"), ptPosDaugh, centrality, 2.5); + if (negExtra.hasITS() && negExtra.itsNCls() >= candidateSelectionValues.minITSclusters && negExtra.hasTPC() && std::abs(negExtra.tpcCrossedRows()) >= candidateSelectionValues.mintpccrrows) + histos.fill(HIST("histITSTPCmatchNegTrack"), ptNegDaugh, centrality, 2.5); + if (bachExtra.hasITS() && bachExtra.itsNCls() >= candidateSelectionValues.minITSclusters && bachExtra.hasTPC() && std::abs(bachExtra.tpcCrossedRows()) >= candidateSelectionValues.mintpccrrows) + histos.fill(HIST("histITSTPCmatchBachTrack"), ptBachelor, centrality, 2.5); + } else { + if (posExtra.hasTPC() && std::abs(posExtra.tpcCrossedRows()) >= candidateSelectionValues.mintpccrrows) + histos.fill(HIST("histITSTPCmatchPosTrack"), ptPosDaugh, centrality, 2.5); + if (negExtra.hasTPC() && std::abs(negExtra.tpcCrossedRows()) >= candidateSelectionValues.mintpccrrows) + histos.fill(HIST("histITSTPCmatchNegTrack"), ptNegDaugh, centrality, 2.5); + if (bachExtra.hasTPC() && std::abs(bachExtra.tpcCrossedRows()) >= candidateSelectionValues.mintpccrrows) + histos.fill(HIST("histITSTPCmatchBachTrack"), ptBachelor, centrality, 2.5); + } + } + + if (std::abs(posExtra.tpcCrossedRows()) < candidateSelectionValues.mintpccrrows || std::abs(negExtra.tpcCrossedRows()) < candidateSelectionValues.mintpccrrows || std::abs(bachExtra.tpcCrossedRows()) < candidateSelectionValues.mintpccrrows) continue; histos.fill(HIST("hCandidate"), ++counter); bool kHasTOF = (posExtra.hasTOF() || negExtra.hasTOF() || bachExtra.hasTOF()); bool kHasITS = (posExtra.hasITS() || negExtra.hasITS() || bachExtra.hasITS()); - if (dooobrej == 1) { + if (candidateSelectionFlags.dooobrej == 1) { if (!kHasTOF && !kHasITS) continue; histos.fill(HIST("hCandidate"), ++counter); - } else if (dooobrej == 2) { - if (!kHasTOF && (casc.pt() > ptthrtof)) + } else if (candidateSelectionFlags.dooobrej == 2) { + if (!kHasTOF && (casc.pt() > candidateSelectionValues.ptthrtof)) continue; histos.fill(HIST("hCandidate"), ++counter); } else { @@ -664,429 +1279,356 @@ struct derivedCascadeAnalysis { float cascptotmom = std::hypot(casc.px(), casc.py(), casc.pz()); float ctau = -10; - cut = ctau; - histos.fill(HIST("hCutValue"), 22, cut); + cut = candidateSelectionValues.proplifetime; + histos.fill(HIST("hCutValue"), 21, cut); if (posExtra.hasTOF()) { - if (doNTOFSigmaProtonCut && casc.sign() < 0) { - histos.fill(HIST("hNsigmaTOFProton"), casc.tofNSigmaXiLaPr(), TMath::Sqrt(TMath::Power(casc.pxpos(), 2) + TMath::Power(casc.pypos(), 2) + TMath::Power(casc.pzpos(), 2)), coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaXiLaPr()) > nsigmatofPr) + + if (candidateSelectionFlags.doNTOFSigmaProtonCut && casc.sign() < 0) { + histos.fill(HIST("hNsigmaTOFProton"), casc.tofNSigmaXiLaPr(), fullMomentumPosDaugh, centrality); + if (std::abs(casc.tofNSigmaXiLaPr()) > candidateSelectionValues.nsigmatofPr && fullMomentumPosDaugh > 0.6) continue; } - if (doNTOFSigmaV0PionCut && casc.sign() > 0) { - histos.fill(HIST("hNsigmaTOFV0Pion"), casc.tofNSigmaXiLaPi(), TMath::Sqrt(TMath::Power(casc.pxpos(), 2) + TMath::Power(casc.pypos(), 2) + TMath::Power(casc.pzpos(), 2)), coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaXiLaPi()) > nsigmatofPion) + if (candidateSelectionFlags.doNTOFSigmaV0PionCut && casc.sign() > 0) { + histos.fill(HIST("hNsigmaTOFV0Pion"), casc.tofNSigmaXiLaPi(), fullMomentumPosDaugh, centrality); + if (std::abs(casc.tofNSigmaXiLaPi()) > candidateSelectionValues.nsigmatofPion) continue; } } if (negExtra.hasTOF()) { - if (doNTOFSigmaProtonCut && casc.sign() > 0) { - histos.fill(HIST("hNsigmaTOFProton"), casc.tofNSigmaXiLaPr(), TMath::Sqrt(TMath::Power(casc.pxneg(), 2) + TMath::Power(casc.pyneg(), 2) + TMath::Power(casc.pzneg(), 2)), coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaXiLaPr()) > nsigmatofPr) + + if (candidateSelectionFlags.doNTOFSigmaProtonCut && casc.sign() > 0) { + histos.fill(HIST("hNsigmaTOFProton"), casc.tofNSigmaXiLaPr(), fullmomentumNegDaugh, centrality); + if (std::abs(casc.tofNSigmaXiLaPr()) > candidateSelectionValues.nsigmatofPr && fullmomentumNegDaugh > 0.6) continue; } - if (doNTOFSigmaV0PionCut && casc.sign() < 0) { - histos.fill(HIST("hNsigmaTOFV0Pion"), casc.tofNSigmaXiLaPi(), TMath::Sqrt(TMath::Power(casc.pxneg(), 2) + TMath::Power(casc.pyneg(), 2) + TMath::Power(casc.pzneg(), 2)), coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaXiLaPi()) > nsigmatofPion) + if (candidateSelectionFlags.doNTOFSigmaV0PionCut && casc.sign() < 0) { + histos.fill(HIST("hNsigmaTOFV0Pion"), casc.tofNSigmaXiLaPi(), fullmomentumNegDaugh, centrality); + if (std::abs(casc.tofNSigmaXiLaPi()) > candidateSelectionValues.nsigmatofPion) continue; } } + if (candidateSelectionFlags.doAtLeastOneTrackAB) { + if (bachExtra.hasITSTracker() && negExtra.hasITSTracker() && posExtra.hasITSTracker()) + continue; + } + if (candidateSelectionFlags.doBachelorITSTracking) { + if (!bachExtra.hasITSTracker()) + continue; + } + if (candidateSelectionFlags.doAllTracksMinITSClusters) { + if (bachExtra.itsNCls() < candidateSelectionValues.minITSclusters || posExtra.itsNCls() < candidateSelectionValues.minITSclusters || negExtra.itsNCls() < candidateSelectionValues.minITSclusters) + continue; + } + if (isXi) { - if (casc.sign() < 0) - histos.fill(HIST("hNsigmaPionNegBach"), bachExtra.tpcNSigmaPi(), TMath::Sqrt(TMath::Power(casc.pxbach(), 2) + TMath::Power(casc.pybach(), 2) + TMath::Power(casc.pzbach(), 2)), coll.centFT0C()); - else - histos.fill(HIST("hNsigmaPionPosBach"), bachExtra.tpcNSigmaPi(), TMath::Sqrt(TMath::Power(casc.pxbach(), 2) + TMath::Power(casc.pybach(), 2) + TMath::Power(casc.pzbach(), 2)), coll.centFT0C()); - if (doNTPCSigmaCut) { - if (TMath::Abs(bachExtra.tpcNSigmaPi()) > nsigmatpcPi) + + if (candidateSelectionFlags.doNTPCSigmaCut) { + if (std::abs(bachExtra.tpcNSigmaPi()) > candidateSelectionValues.nsigmatpcPi) continue; histos.fill(HIST("hCandidate"), ++counter); - } else + } else { ++counter; + } - if (bachExtra.hasTOF() && doNTOFSigmaBachelorCut) { - histos.fill(HIST("hNsigmaTOFBachelorPion"), casc.tofNSigmaXiPi(), TMath::Sqrt(TMath::Power(casc.pxbach(), 2) + TMath::Power(casc.pybach(), 2) + TMath::Power(casc.pzbach(), 2)), coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaXiPi()) > nsigmatofBachPion) + if (bachExtra.hasTOF() && candidateSelectionFlags.doNTOFSigmaBachelorCut) { + histos.fill(HIST("hNsigmaTOFBachelorPion"), casc.tofNSigmaXiPi(), fullmomentumBachelor, centrality); + if (std::abs(casc.tofNSigmaXiPi()) > candidateSelectionValues.nsigmatofBachPion) continue; } - ctau = pdgDB->Mass(3312) * cascpos / ((cascptotmom + 1e-13) * ctauxiPDG); - if (doProperLifeTimeCut) { - if (ctau > proplifetime) + ctau = o2::constants::physics::MassXiMinus * cascpos / ((cascptotmom + 1e-13) * ctauxiPDG); + if (candidateSelectionFlags.doProperLifeTimeCut) { + if (ctau > candidateSelectionValues.proplifetime) continue; histos.fill(HIST("hCandidate"), ++counter); } else { + if (qaFlags.doPtDepCutStudy) + selectionCheck = ctau; ++counter; } } else { - histos.fill(HIST("hNsigmaKaon"), bachExtra.tpcNSigmaKa(), TMath::Sqrt(TMath::Power(casc.pxbach(), 2) + TMath::Power(casc.pybach(), 2) + TMath::Power(casc.pzbach(), 2)), coll.centFT0C()); - if (doNTPCSigmaCut) { - if (TMath::Abs(bachExtra.tpcNSigmaKa()) > nsigmatpcKa) + if (candidateSelectionFlags.doNTPCSigmaCut) { + if (std::abs(bachExtra.tpcNSigmaKa()) > candidateSelectionValues.nsigmatpcKa) continue; histos.fill(HIST("hCandidate"), ++counter); - } else + } else { ++counter; + } - if (bachExtra.hasTOF() && doNTOFSigmaBachelorCut) { - histos.fill(HIST("hNsigmaTOFBachelorKaon"), casc.tofNSigmaOmKa(), TMath::Sqrt(TMath::Power(casc.pxbach(), 2) + TMath::Power(casc.pybach(), 2) + TMath::Power(casc.pzbach(), 2)), coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaOmKa()) > nsigmatofBachKaon) + if (bachExtra.hasTOF() && candidateSelectionFlags.doNTOFSigmaBachelorCut) { + histos.fill(HIST("hNsigmaTOFBachelorKaon"), casc.tofNSigmaOmKa(), std::sqrt(std::pow(casc.pxbach(), 2) + std::pow(casc.pybach(), 2) + std::pow(casc.pzbach(), 2)), centrality); + if (std::abs(casc.tofNSigmaOmKa()) > candidateSelectionValues.nsigmatofBachKaon) continue; } - ctau = pdgDB->Mass(3334) * cascpos / ((cascptotmom + 1e-13) * ctauomegaPDG); - if (doProperLifeTimeCut) { - if (ctau > proplifetime) + ctau = o2::constants::physics::MassOmegaMinus * cascpos / ((cascptotmom + 1e-13) * ctauomegaPDG); + if (candidateSelectionFlags.doProperLifeTimeCut) { + if (ctau > candidateSelectionValues.proplifetime) continue; histos.fill(HIST("hCandidate"), ++counter); - } else + } else { + if (qaFlags.doPtDepCutStudy) + selectionCheck = ctau; ++counter; + } } - if (casc.sign() < 0) { - histos.fill(HIST("InvMassAfterSel/hNegativeCascade"), casc.pt(), invmass, coll.centFT0C()); - if (!doBachelorBaryonCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeBachelorBaryonDCA"), casc.pt(), invmass, casc.bachBaryonDCAxyToPV()); - if (!doDCAV0ToPVCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeDCAV0ToPV"), casc.pt(), invmass, TMath::Abs(casc.dcav0topv(casc.x(), casc.y(), casc.z()))); - if (!doV0RadiusCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeV0Radius"), casc.pt(), invmass, casc.v0radius()); - if (!doCascadeRadiusCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeCascadeRadius"), casc.pt(), invmass, casc.cascradius()); - if (!doDCAV0DauCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeDCAV0Daughters"), casc.pt(), invmass, casc.dcaV0daughters()); - if (!doDCACascadeDauCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeDCACascDaughters"), casc.pt(), invmass, casc.dcacascdaughters()); - if (!doV0CosPaCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeV0pa"), casc.pt(), invmass, TMath::ACos(casc.v0cosPA(casc.x(), casc.y(), casc.z()))); - if (!doCascadeCosPaCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeCascPA"), casc.pt(), invmass, TMath::ACos(casc.casccosPA(coll.posX(), coll.posY(), coll.posZ()))); - if (!doDCAdauToPVCut && doPtDepCutStudy) { - histos.fill(HIST("PtDepCutStudy/hNegativeDCABachelorToPV"), casc.pt(), invmass, casc.dcabachtopv()); - histos.fill(HIST("PtDepCutStudy/hNegativeDCAMesonToPV"), casc.pt(), invmass, casc.dcanegtopv()); - histos.fill(HIST("PtDepCutStudy/hNegativeDCABaryonToPV"), casc.pt(), invmass, casc.dcapostopv()); + if (qaFlags.doOccupancyCheck) { + fillHistOccupancyCheck(recoPt, invmass, occupancy, centrality, isPositive); + } + if (isPositive) { + histos.fill(HIST("InvMassAfterSel/hPositiveCascade"), recoPt, invmass, centrality); + if (isTrueMCCascadeDecay) { + histos.fill(HIST("hPositiveCascadePtForEfficiency"), ptmc, invmass, centrality); + histos.fill(HIST("hPositiveCascadePtForEfficiencyVsNch"), ptmc, invmass, nChEta1); } - if (!doProperLifeTimeCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeCascadeProperLifeTime"), casc.pt(), invmass, ctau); + if (isTrueMCCascadeDecay) + histos.fill(HIST("InvMassAfterSelMCrecTruth/hPositiveCascade"), ptmc, invmass, centrality); } else { - histos.fill(HIST("InvMassAfterSel/hPositiveCascade"), casc.pt(), invmass, coll.centFT0C()); - if (!doBachelorBaryonCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveBachelorBaryonDCA"), casc.pt(), invmass, casc.bachBaryonDCAxyToPV()); - if (!doDCAV0ToPVCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveDCAV0ToPV"), casc.pt(), invmass, TMath::Abs(casc.dcav0topv(casc.x(), casc.y(), casc.z()))); - if (!doV0RadiusCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveV0Radius"), casc.pt(), invmass, casc.v0radius()); - if (!doCascadeRadiusCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveCascadeRadius"), casc.pt(), invmass, casc.cascradius()); - if (!doDCAV0DauCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveDCAV0Daughters"), casc.pt(), invmass, casc.dcaV0daughters()); - if (!doDCACascadeDauCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveDCACascDaughters"), casc.pt(), invmass, casc.dcacascdaughters()); - if (!doV0CosPaCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveV0pa"), casc.pt(), invmass, TMath::ACos(casc.v0cosPA(casc.x(), casc.y(), casc.z()))); - if (!doCascadeCosPaCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveCascPA"), casc.pt(), invmass, TMath::ACos(casc.casccosPA(coll.posX(), coll.posY(), coll.posZ()))); - if (!doDCAdauToPVCut && doPtDepCutStudy) { - histos.fill(HIST("PtDepCutStudy/hPositiveDCABachelorToPV"), casc.pt(), invmass, casc.dcabachtopv()); - histos.fill(HIST("PtDepCutStudy/hPositiveDCAMesonToPV"), casc.pt(), invmass, casc.dcapostopv()); - histos.fill(HIST("PtDepCutStudy/hPositiveDCABaryonToPV"), casc.pt(), invmass, casc.dcanegtopv()); + histos.fill(HIST("InvMassAfterSel/hNegativeCascade"), recoPt, invmass, centrality); + if (isTrueMCCascadeDecay) { + histos.fill(HIST("hNegativeCascadePtForEfficiency"), ptmc, invmass, centrality); + histos.fill(HIST("hNegativeCascadePtForEfficiencyVsNch"), ptmc, invmass, nChEta1); } - if (!doProperLifeTimeCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveCascadeProperLifeTime"), casc.pt(), invmass, ctau); + if (isTrueMCCascadeDecay) + histos.fill(HIST("InvMassAfterSelMCrecTruth/hNegativeCascade"), ptmc, invmass, centrality); + } + + if (qaFlags.doIRCheck) { + double interactionRate = -2; + if constexpr (requires { coll.trackOccupancyInTimeRange(); }) { + interactionRate = rateFetcher.fetch(ccdb.service, coll.timestamp(), coll.runNumber(), irSource) * 1.e-3; + fillHistIRCheckData(recoPt, invmass, interactionRate, centrality, isPositive); + if (isTrueMCCascadeDecay) + fillHistIRCheckMC(ptmc, invmass, interactionRate, centrality, isPositive); + } + } + + if (qaFlags.doPtDepCutStudy && selectionCheck != -1) { + fillHistPtDepSelectionStudy(recoPt, invmass, selectionCheck, selectionCheckMask, isPositive); + if (isTrueMCCascade) + fillHistPtDepSelectionStudyMC(ptmc, invmass, selectionCheck, selectionCheckMask, isPositive); } } } - void processCascadesMCrec(soa::Join::iterator const& coll, soa::Join const& Cascades, soa::Join const&) + template + void analyseCascadesMCforEff(TMCCollisions const& mcCollisions, TCascMCs const& Cascades, TCollisions const& collisions) { - if (!IsEventAccepted(coll, coll.sel8())) - return; - for (auto& casc : Cascades) { + std::vector listBestCollisionIdx = fillGenEventHist(mcCollisions, collisions); - int counter = -1; - histos.fill(HIST("hCandidate"), ++counter); - - // To have trace of how it was before selections - if (casc.sign() < 0 && doBefSelCheck) { - if (isXi) - histos.fill(HIST("InvMassBefSel/hNegativeCascade"), casc.pt(), casc.mXi(), coll.centFT0C()); - else - histos.fill(HIST("InvMassBefSel/hNegativeCascade"), casc.pt(), casc.mOmega(), coll.centFT0C()); - } - if (casc.sign() > 0 && doBefSelCheck) { - if (isXi) - histos.fill(HIST("InvMassBefSel/hPositiveCascade"), casc.pt(), casc.mXi(), coll.centFT0C()); - else - histos.fill(HIST("InvMassBefSel/hPositiveCascade"), casc.pt(), casc.mOmega(), coll.centFT0C()); - } - - if (!IsCascadeCandidateAccepted(casc, counter, coll.centFT0C())) + for (auto const& cascMC : Cascades) { + if (!cascMC.has_straMCCollision()) continue; - counter += 13; - - auto negExtra = casc.negTrackExtra_as>(); - auto posExtra = casc.posTrackExtra_as>(); - auto bachExtra = casc.bachTrackExtra_as>(); - auto poseta = RecoDecay::eta(std::array{casc.pxpos(), casc.pypos(), casc.pzpos()}); - auto negeta = RecoDecay::eta(std::array{casc.pxneg(), casc.pyneg(), casc.pzneg()}); - auto bacheta = RecoDecay::eta(std::array{casc.pxbach(), casc.pybach(), casc.pzbach()}); - if (TMath::Abs(poseta) > etaDauCut || TMath::Abs(negeta) > etaDauCut || TMath::Abs(bacheta) > etaDauCut) + if (!cascMC.isPhysicalPrimary()) continue; - histos.fill(HIST("hCandidate"), ++counter); - if (doCascadeCosPaCut) { - if (!IsCosPAAccepted(casc, coll.posX(), coll.posY(), coll.posZ(), doPtDepCosPaCut, true)) - continue; - histos.fill(HIST("hCandidate"), ++counter); - } else - ++counter; - - if (doDCAV0ToPVCut) { - if (TMath::Abs(casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ())) < dcaV0ToPV) - continue; - histos.fill(HIST("hCandidate"), ++counter); - } else - ++counter; + float ptmc = RecoDecay::sqrtSumOfSquares(cascMC.pxMC(), cascMC.pyMC()); + float ymc = 1e3; + if (std::abs(cascMC.pdgCode()) == 3312) + ymc = RecoDecay::y(std::array{cascMC.pxMC(), cascMC.pyMC(), cascMC.pzMC()}, o2::constants::physics::MassXiMinus); + else if (std::abs(cascMC.pdgCode()) == 3334) + ymc = RecoDecay::y(std::array{cascMC.pxMC(), cascMC.pyMC(), cascMC.pzMC()}, o2::constants::physics::MassOmegaMinus); - if (doNTPCSigmaCut) { - if (casc.sign() < 0) { - histos.fill(HIST("hNsigmaProton"), posExtra.tpcNSigmaPr(), TMath::Sqrt(TMath::Power(casc.pxpos(), 2) + TMath::Power(casc.pypos(), 2) + TMath::Power(casc.pzpos(), 2)), coll.centFT0C()); - histos.fill(HIST("hNsigmaPionNeg"), negExtra.tpcNSigmaPi(), TMath::Sqrt(TMath::Power(casc.pxneg(), 2) + TMath::Power(casc.pyneg(), 2) + TMath::Power(casc.pzneg(), 2)), coll.centFT0C()); - if (TMath::Abs(posExtra.tpcNSigmaPr()) > nsigmatpcPr || TMath::Abs(negExtra.tpcNSigmaPi()) > nsigmatpcPi) - continue; - histos.fill(HIST("hCandidate"), ++counter); - } else if (casc.sign() > 0) { - histos.fill(HIST("hNsigmaProtonNeg"), negExtra.tpcNSigmaPr(), TMath::Sqrt(TMath::Power(casc.pxneg(), 2) + TMath::Power(casc.pyneg(), 2) + TMath::Power(casc.pzneg(), 2)), coll.centFT0C()); - histos.fill(HIST("hNsigmaPionPos"), posExtra.tpcNSigmaPi(), TMath::Sqrt(TMath::Power(casc.pxpos(), 2) + TMath::Power(casc.pypos(), 2) + TMath::Power(casc.pzpos(), 2)), coll.centFT0C()); - if (TMath::Abs(posExtra.tpcNSigmaPi()) > nsigmatpcPi || TMath::Abs(negExtra.tpcNSigmaPr()) > nsigmatpcPr) - continue; - histos.fill(HIST("hCandidate"), ++counter); - } - } else - ++counter; - - if (posExtra.tpcCrossedRows() < mintpccrrows || negExtra.tpcCrossedRows() < mintpccrrows || bachExtra.tpcCrossedRows() < mintpccrrows) + if (std::abs(ymc) > candidateSelectionValues.rapCut) continue; - histos.fill(HIST("hCandidate"), ++counter); - bool kHasTOF = (posExtra.hasTOF() || negExtra.hasTOF() || bachExtra.hasTOF()); - bool kHasITS = (posExtra.hasITS() || negExtra.hasITS() || bachExtra.hasITS()); - if (dooobrej == 1) { - if (!kHasTOF && !kHasITS) - continue; - histos.fill(HIST("hCandidate"), ++counter); - } else if (dooobrej == 2) { - if (!kHasTOF && (casc.pt() > ptthrtof)) - continue; - histos.fill(HIST("hCandidate"), ++counter); - } else { - ++counter; + auto mcCollision = cascMC.template straMCCollision_as>(); + if (eventSelectionCommonFlags.applyZVtxSelOnMCPV && std::abs(mcCollision.posZ()) > eventSelectionCommonFlags.zVertexCut) { + continue; } - double invmass; - float cascpos = std::hypot(casc.x() - coll.posX(), casc.y() - coll.posY(), casc.z() - coll.posZ()); - float cascptotmom = std::hypot(casc.px(), casc.py(), casc.pz()); - float ctau = -10; + if (eventSelectionCommonFlags.doInel0MCGen && mcCollision.multMCNParticlesEta10() < 1) { + continue; + } - if (posExtra.hasTOF()) { - if (doNTOFSigmaProtonCut && casc.sign() < 0) { - histos.fill(HIST("hNsigmaTOFProton"), casc.tofNSigmaXiLaPr(), TMath::Sqrt(TMath::Power(casc.pxpos(), 2) + TMath::Power(casc.pypos(), 2) + TMath::Power(casc.pzpos(), 2)), coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaXiLaPr()) > nsigmatofPr) - continue; - } - if (doNTOFSigmaV0PionCut && casc.sign() > 0) { - histos.fill(HIST("hNsigmaTOFV0Pion"), casc.tofNSigmaXiLaPi(), TMath::Sqrt(TMath::Power(casc.pxpos(), 2) + TMath::Power(casc.pypos(), 2) + TMath::Power(casc.pzpos(), 2)), coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaXiLaPi()) > nsigmatofPion) - continue; + float centrality = 100.5f; + float occupancy = -2; + float nChEta1 = -1; + double intRate = -1; + if (listBestCollisionIdx[mcCollision.globalIndex()] > -1) { + auto collision = collisions.iteratorAt(listBestCollisionIdx[mcCollision.globalIndex()]); + if constexpr (requires { collision.centFT0C(); }) { + intRate = rateFetcher.fetch(ccdb.service, collision.timestamp(), collision.runNumber(), irSource) * 1.e-3; + centrality = collision.centFT0C(); + if (useCentralityFT0M) + centrality = collision.centFT0M(); + if (useCentralityFT0A) + centrality = collision.centFV0A(); + if (useCentralityFT0Cvar1) + centrality = collision.centFT0CVariant1(); + if (useTrackOccupancyDef) + occupancy = collision.trackOccupancyInTimeRange(); + if (useFT0OccupancyDef) + occupancy = collision.ft0cOccupancyInTimeRange(); + } else { + centrality = eventSelectionRun2Flags.useSPDTrackletsCent ? collision.centRun2SPDTracklets() : collision.centRun2V0M(); } + nChEta1 = collision.multNTracksPVeta1(); } - if (negExtra.hasTOF()) { - if (doNTOFSigmaProtonCut && casc.sign() > 0) { - histos.fill(HIST("hNsigmaTOFProton"), casc.tofNSigmaXiLaPr(), TMath::Sqrt(TMath::Power(casc.pxneg(), 2) + TMath::Power(casc.pyneg(), 2) + TMath::Power(casc.pzneg(), 2)), coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaXiLaPr()) > nsigmatofPr) - continue; - } - if (doNTOFSigmaV0PionCut && casc.sign() < 0) { - histos.fill(HIST("hNsigmaTOFV0Pion"), casc.tofNSigmaXiLaPi(), TMath::Sqrt(TMath::Power(casc.pxneg(), 2) + TMath::Power(casc.pyneg(), 2) + TMath::Power(casc.pzneg(), 2)), coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaXiLaPi()) > nsigmatofPion) - continue; - } + if (cascMC.pdgCode() == 3312 && isXi) { + histos.fill(HIST("h2dGenXiMinus"), centrality, ptmc); + histos.fill(HIST("h2dGenXiMinusVsNch"), nChEta1, ptmc); + histos.fill(HIST("h2dGenXiMinusEta"), RecoDecay::eta(std::array{cascMC.pxMC(), cascMC.pyMC(), cascMC.pzMC()})); + histos.fill(HIST("h2dGenXiMinusEtaPosDaughter"), RecoDecay::eta(std::array{cascMC.pxPosMC(), cascMC.pyPosMC(), cascMC.pzPosMC()})); + histos.fill(HIST("h2dGenXiMinusEtaNegDaughter"), RecoDecay::eta(std::array{cascMC.pxNegMC(), cascMC.pyNegMC(), cascMC.pzNegMC()})); + histos.fill(HIST("h2dGenXiMinusEtaBach"), RecoDecay::eta(std::array{cascMC.pxBachMC(), cascMC.pyBachMC(), cascMC.pzBachMC()})); + histos.fill(HIST("h2dGenXiMinusVsMultMCVsCentrality"), mcCollision.multMCNParticlesEta05(), centrality, ptmc); + histos.fill(HIST("h2dGenXiMinusVsMultMCVsIR"), mcCollision.multMCNParticlesEta05(), intRate, ptmc); + histos.fill(HIST("h2dGenXiMinusVsCentOccupancy"), ptmc, centrality, occupancy); + histos.fill(HIST("h2dGenXiMinusVsCentIR"), ptmc, centrality, intRate); + histos.fill(HIST("h2dGenXiMinusVsNchVsOccupancy"), ptmc, nChEta1, occupancy); + } + if (cascMC.pdgCode() == -3312 && isXi) { + histos.fill(HIST("h2dGenXiPlus"), centrality, ptmc); + histos.fill(HIST("h2dGenXiPlusVsNch"), nChEta1, ptmc); + histos.fill(HIST("h2dGenXiPlusVsMultMCVsCentrality"), mcCollision.multMCNParticlesEta05(), centrality, ptmc); + histos.fill(HIST("h2dGenXiPlusVsMultMCVsIR"), mcCollision.multMCNParticlesEta05(), intRate, ptmc); + histos.fill(HIST("h2dGenXiPlusVsCentOccupancy"), ptmc, centrality, occupancy); + histos.fill(HIST("h2dGenXiPlusVsNchVsOccupancy"), ptmc, nChEta1, occupancy); + histos.fill(HIST("h2dGenXiPlusVsCentIR"), ptmc, centrality, intRate); } + if (cascMC.pdgCode() == 3334 && !isXi) { + histos.fill(HIST("h2dGenOmegaMinus"), centrality, ptmc); + histos.fill(HIST("h2dGenOmegaMinusVsNch"), nChEta1, ptmc); + histos.fill(HIST("h2dGenOmegaMinusEta"), RecoDecay::eta(std::array{cascMC.pxMC(), cascMC.pyMC(), cascMC.pzMC()})); + histos.fill(HIST("h2dGenOmegaMinusEtaPosDaughter"), RecoDecay::eta(std::array{cascMC.pxPosMC(), cascMC.pyPosMC(), cascMC.pzPosMC()})); + histos.fill(HIST("h2dGenOmegaMinusEtaNegDaughter"), RecoDecay::eta(std::array{cascMC.pxNegMC(), cascMC.pyNegMC(), cascMC.pzNegMC()})); + histos.fill(HIST("h2dGenOmegaMinusEtaBach"), RecoDecay::eta(std::array{cascMC.pxBachMC(), cascMC.pyBachMC(), cascMC.pzBachMC()})); + histos.fill(HIST("h2dGenOmegaMinusVsMultMCVsCentrality"), mcCollision.multMCNParticlesEta05(), centrality, ptmc); + histos.fill(HIST("h2dGenOmegaMinusVsMultMCVsIR"), mcCollision.multMCNParticlesEta05(), intRate, ptmc); + histos.fill(HIST("h2dGenOmegaMinusVsCentOccupancy"), ptmc, centrality, occupancy); + histos.fill(HIST("h2dGenOmegaMinusVsNchVsOccupancy"), ptmc, nChEta1, occupancy); + histos.fill(HIST("h2dGenOmegaMinusVsCentIR"), ptmc, centrality, intRate); + } + if (cascMC.pdgCode() == -3334 && !isXi) { + histos.fill(HIST("h2dGenOmegaPlus"), centrality, ptmc); + histos.fill(HIST("h2dGenOmegaPlusVsNch"), nChEta1, ptmc); + histos.fill(HIST("h2dGenOmegaPlusVsMultMCVsCentrality"), mcCollision.multMCNParticlesEta05(), centrality, ptmc); + histos.fill(HIST("h2dGenOmegaPlusVsMultMCVsIR"), mcCollision.multMCNParticlesEta05(), intRate, ptmc); + histos.fill(HIST("h2dGenOmegaPlusVsCentOccupancy"), ptmc, centrality, occupancy); + histos.fill(HIST("h2dGenOmegaPlusVsNchVsOccupancy"), ptmc, nChEta1, occupancy); + histos.fill(HIST("h2dGenOmegaPlusVsCentIR"), ptmc, centrality, intRate); + } + } + } + // ______________________________________________________ + // Simulated processing + // Fill event information (for event loss estimation) and return the index to the recoed collision associated to a given MC collision. + template + std::vector fillGenEventHist(TMCCollisions const& mcCollisions, TCollisions const& collisions) + { + std::vector listBestCollisionIdx(mcCollisions.size()); + for (auto const& mcCollision : mcCollisions) { + histos.fill(HIST("hGenEvents"), mcCollision.multMCNParticlesEta05(), 0.5 /* all gen. events*/); - if (isXi) { - if (casc.sign() < 0) - histos.fill(HIST("hNsigmaPionNegBach"), bachExtra.tpcNSigmaPi(), TMath::Sqrt(TMath::Power(casc.pxbach(), 2) + TMath::Power(casc.pybach(), 2) + TMath::Power(casc.pzbach(), 2)), coll.centFT0C()); - else - histos.fill(HIST("hNsigmaPionPosBach"), bachExtra.tpcNSigmaPi(), TMath::Sqrt(TMath::Power(casc.pxbach(), 2) + TMath::Power(casc.pybach(), 2) + TMath::Power(casc.pzbach(), 2)), coll.centFT0C()); - if (doNTPCSigmaCut) { - if (TMath::Abs(bachExtra.tpcNSigmaPi()) > nsigmatpcPi) - continue; - histos.fill(HIST("hCandidate"), ++counter); - } else - ++counter; + if (eventSelectionCommonFlags.applyZVtxSelOnMCPV && std::abs(mcCollision.posZ()) > eventSelectionCommonFlags.zVertexCut) { + continue; + } + histos.fill(HIST("hGenEvents"), mcCollision.multMCNParticlesEta05(), 1.5 /* gen. events with vertex cut*/); - if (bachExtra.hasTOF() && doNTOFSigmaBachelorCut) { - histos.fill(HIST("hNsigmaTOFBachelorPion"), casc.tofNSigmaXiPi(), TMath::Sqrt(TMath::Power(casc.pxbach(), 2) + TMath::Power(casc.pybach(), 2) + TMath::Power(casc.pzbach(), 2)), coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaXiPi()) > nsigmatofBachPion) - continue; + if (eventSelectionCommonFlags.doInel0MCGen && mcCollision.multMCNParticlesEta10() < 1) { + continue; + } + histos.fill(HIST("hGenEvents"), mcCollision.multMCNParticlesEta05(), 2.5 /* gen. events with INEL>0t*/); + + auto groupedCollisions = getGroupedCollisions(collisions, mcCollision.globalIndex()); + // Check if there is at least one of the reconstructed collisions associated to this MC collision + // If so, we consider it + bool atLeastOne = false; + int biggestNContribs = -1; + int bestCollisionIndex = -1; + float centrality = 100.5f; + int nCollisions = 0; + float nChEta05 = -1; + double intRate = -1; + for (auto const& collision : groupedCollisions) { + if (!isEventAccepted(collision, false)) { + continue; } - ctau = pdgDB->Mass(3312) * cascpos / ((cascptotmom + 1e-13) * ctauxiPDG); - if (doProperLifeTimeCut) { - if (ctau > proplifetime) - continue; - histos.fill(HIST("hCandidate"), ++counter); - } else { - ++counter; + if (biggestNContribs < collision.multPVTotalContributors()) { + biggestNContribs = collision.multPVTotalContributors(); + bestCollisionIndex = collision.globalIndex(); + if constexpr (requires { collision.centFT0C(); }) { + centrality = collision.centFT0C(); + intRate = rateFetcher.fetch(ccdb.service, collision.timestamp(), collision.runNumber(), irSource) * 1.e-3; + if (useCentralityFT0M) + centrality = collision.centFT0M(); + if (useCentralityFT0A) + centrality = collision.centFV0A(); + if (useCentralityFT0Cvar1) + centrality = collision.centFT0CVariant1(); + } else { + centrality = eventSelectionRun2Flags.useSPDTrackletsCent ? collision.centRun2SPDTracklets() : collision.centRun2V0M(); + } } + nCollisions++; - invmass = casc.mXi(); - } else { - histos.fill(HIST("hNsigmaKaon"), bachExtra.tpcNSigmaKa(), TMath::Sqrt(TMath::Power(casc.pxbach(), 2) + TMath::Power(casc.pybach(), 2) + TMath::Power(casc.pzbach(), 2)), coll.centFT0C()); - if (doNTPCSigmaCut) { - if (TMath::Abs(bachExtra.tpcNSigmaKa()) > nsigmatpcKa) - continue; - histos.fill(HIST("hCandidate"), ++counter); - } else - ++counter; + atLeastOne = true; + } + listBestCollisionIdx[mcCollision.globalIndex()] = bestCollisionIndex; - if (bachExtra.hasTOF() && doNTOFSigmaBachelorCut) { - histos.fill(HIST("hNsigmaTOFBachelorKaon"), casc.tofNSigmaOmKa(), TMath::Sqrt(TMath::Power(casc.pxbach(), 2) + TMath::Power(casc.pybach(), 2) + TMath::Power(casc.pzbach(), 2)), coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaOmKa()) > nsigmatofBachKaon) - continue; - } + histos.fill(HIST("hCentralityVsNcoll_beforeEvSel"), centrality, groupedCollisions.size() + 0.5); + histos.fill(HIST("hCentralityVsNcoll_afterEvSel"), centrality, nCollisions + 0.5); - ctau = pdgDB->Mass(3334) * cascpos / ((cascptotmom + 1e-13) * ctauomegaPDG); - if (doProperLifeTimeCut) { - if (ctau > proplifetime) - continue; - histos.fill(HIST("hCandidate"), ++counter); - } else - ++counter; - invmass = casc.mOmega(); - } - - if (casc.sign() < 0) { - histos.fill(HIST("InvMassAfterSel/hNegativeCascade"), casc.pt(), invmass, coll.centFT0C()); - if (!doBachelorBaryonCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeBachelorBaryonDCA"), casc.pt(), invmass, casc.bachBaryonDCAxyToPV()); - if (!doDCAV0ToPVCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeDCAV0ToPV"), casc.pt(), invmass, TMath::Abs(casc.dcav0topv(casc.x(), casc.y(), casc.z()))); - if (!doV0RadiusCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeV0Radius"), casc.pt(), invmass, casc.v0radius()); - if (!doCascadeRadiusCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeCascadeRadius"), casc.pt(), invmass, casc.cascradius()); - if (!doDCAV0DauCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeDCAV0Daughters"), casc.pt(), invmass, casc.dcaV0daughters()); - if (!doDCACascadeDauCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeDCACascDaughters"), casc.pt(), invmass, casc.dcacascdaughters()); - if (!doV0CosPaCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeV0pa"), casc.pt(), invmass, TMath::ACos(casc.v0cosPA(casc.x(), casc.y(), casc.z()))); - if (!doCascadeCosPaCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeCascPA"), casc.pt(), invmass, TMath::ACos(casc.casccosPA(coll.posX(), coll.posY(), coll.posZ()))); - if (!doDCAdauToPVCut && doPtDepCutStudy) { - histos.fill(HIST("PtDepCutStudy/hNegativeDCABachelorToPV"), casc.pt(), invmass, casc.dcabachtopv()); - histos.fill(HIST("PtDepCutStudy/hNegativeDCAMesonToPV"), casc.pt(), invmass, casc.dcanegtopv()); - histos.fill(HIST("PtDepCutStudy/hNegativeDCABaryonToPV"), casc.pt(), invmass, casc.dcapostopv()); - } - if (!doProperLifeTimeCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hNegativeCascadeProperLifeTime"), casc.pt(), invmass, ctau); - if (casc.isPhysicalPrimary()) { - if ((isXi && casc.pdgCode() == 3312) || (!isXi && casc.pdgCode() == 3334)) { - histos.fill(HIST("InvMassAfterSelMCrecTruth/hNegativeCascade"), casc.pt(), invmass, coll.centFT0C()); - if (!doBachelorBaryonCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hNegativeBachelorBaryonDCA"), casc.pt(), invmass, casc.bachBaryonDCAxyToPV()); - if (!doDCAV0ToPVCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hNegativeDCAV0ToPV"), casc.pt(), invmass, TMath::Abs(casc.dcav0topv(casc.x(), casc.y(), casc.z()))); - if (!doV0RadiusCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hNegativeV0Radius"), casc.pt(), invmass, casc.v0radius()); - if (!doCascadeRadiusCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hNegativeCascadeRadius"), casc.pt(), invmass, casc.cascradius()); - if (!doDCAV0DauCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hNegativeDCAV0Daughters"), casc.pt(), invmass, casc.dcaV0daughters()); - if (!doDCACascadeDauCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hNegativeDCACascDaughters"), casc.pt(), invmass, casc.dcacascdaughters()); - if (!doV0CosPaCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hNegativeV0pa"), casc.pt(), invmass, TMath::ACos(casc.v0cosPA(casc.x(), casc.y(), casc.z()))); - if (!doCascadeCosPaCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hNegativeCascPA"), casc.pt(), invmass, TMath::ACos(casc.casccosPA(coll.posX(), coll.posY(), coll.posZ()))); - if (!doDCAdauToPVCut && doPtDepCutStudy) { - histos.fill(HIST("PtDepCutStudyMCTruth/hNegativeDCABachelorToPV"), casc.pt(), invmass, casc.dcabachtopv()); - histos.fill(HIST("PtDepCutStudyMCTruth/hNegativeDCAMesonToPV"), casc.pt(), invmass, casc.dcanegtopv()); - histos.fill(HIST("PtDepCutStudyMCTruth/hNegativeDCABaryonToPV"), casc.pt(), invmass, casc.dcapostopv()); - } - if (!doProperLifeTimeCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hNegativeCascadeProperLifeTime"), casc.pt(), invmass, ctau); - if ((isXi && casc.pdgCodeV0() == 3122 && casc.pdgCodePositive() == 2212 && casc.pdgCodeNegative() == -211 && casc.pdgCodeBachelor() == -211) || (!isXi && casc.pdgCodeV0() == 3122 && casc.pdgCodePositive() == 2212 && casc.pdgCodeNegative() == -211 && casc.pdgCodeBachelor() == -321)) - histos.fill(HIST("hNegativeCascadePtForEfficiency"), casc.pt(), invmass, coll.centFT0C()); - } - } - } else { - histos.fill(HIST("InvMassAfterSel/hPositiveCascade"), casc.pt(), invmass, coll.centFT0C()); - if (!doBachelorBaryonCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveBachelorBaryonDCA"), casc.pt(), invmass, casc.bachBaryonDCAxyToPV()); - if (!doDCAV0ToPVCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveDCAV0ToPV"), casc.pt(), invmass, TMath::Abs(casc.dcav0topv(casc.x(), casc.y(), casc.z()))); - if (!doV0RadiusCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveV0Radius"), casc.pt(), invmass, casc.v0radius()); - if (!doCascadeRadiusCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveCascadeRadius"), casc.pt(), invmass, casc.cascradius()); - if (!doDCAV0DauCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveDCAV0Daughters"), casc.pt(), invmass, casc.dcaV0daughters()); - if (!doDCACascadeDauCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveDCACascDaughters"), casc.pt(), invmass, casc.dcacascdaughters()); - if (!doV0CosPaCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveV0pa"), casc.pt(), invmass, TMath::ACos(casc.v0cosPA(casc.x(), casc.y(), casc.z()))); - if (!doCascadeCosPaCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveCascPA"), casc.pt(), invmass, TMath::ACos(casc.casccosPA(coll.posX(), coll.posY(), coll.posZ()))); - if (!doDCAdauToPVCut && doPtDepCutStudy) { - histos.fill(HIST("PtDepCutStudy/hPositiveDCABachelorToPV"), casc.pt(), invmass, casc.dcabachtopv()); - histos.fill(HIST("PtDepCutStudy/hPositiveDCAMesonToPV"), casc.pt(), invmass, casc.dcapostopv()); - histos.fill(HIST("PtDepCutStudy/hPositiveDCABaryonToPV"), casc.pt(), invmass, casc.dcanegtopv()); - } - if (!doProperLifeTimeCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveCascadeProperLifeTime"), casc.pt(), invmass, ctau); - if (casc.isPhysicalPrimary()) { - if ((isXi && casc.pdgCode() == -3312) || (!isXi && casc.pdgCode() == -3334)) { - histos.fill(HIST("InvMassAfterSelMCrecTruth/hPositiveCascade"), casc.pt(), invmass, coll.centFT0C()); - if (!doBachelorBaryonCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hPositiveBachelorBaryonDCA"), casc.pt(), invmass, casc.bachBaryonDCAxyToPV()); - if (!doDCAV0ToPVCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hPositiveDCAV0ToPV"), casc.pt(), invmass, TMath::Abs(casc.dcav0topv(casc.x(), casc.y(), casc.z()))); - if (!doV0RadiusCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hPositiveV0Radius"), casc.pt(), invmass, casc.v0radius()); - if (!doCascadeRadiusCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hPositiveCascadeRadius"), casc.pt(), invmass, casc.cascradius()); - if (!doDCAV0DauCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hPositiveDCAV0Daughters"), casc.pt(), invmass, casc.dcaV0daughters()); - if (!doDCACascadeDauCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hPositiveDCACascDaughters"), casc.pt(), invmass, casc.dcacascdaughters()); - if (!doV0CosPaCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hPositiveV0pa"), casc.pt(), invmass, TMath::ACos(casc.v0cosPA(casc.x(), casc.y(), casc.z()))); - if (!doCascadeCosPaCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hPositiveCascPA"), casc.pt(), invmass, TMath::ACos(casc.casccosPA(coll.posX(), coll.posY(), coll.posZ()))); - if (!doDCAdauToPVCut && doPtDepCutStudy) { - histos.fill(HIST("PtDepCutStudyMCTruth/hPositiveDCABachelorToPV"), casc.pt(), invmass, casc.dcabachtopv()); - histos.fill(HIST("PtDepCutStudyMCTruth/hPositiveDCAMesonToPV"), casc.pt(), invmass, casc.dcapostopv()); - histos.fill(HIST("PtDepCutStudyMCTruth/hPositiveDCABaryonToPV"), casc.pt(), invmass, casc.dcanegtopv()); - } - if (!doProperLifeTimeCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudyMCTruth/hPositiveCascadeProperLifeTime"), casc.pt(), invmass, ctau); - if ((isXi && casc.pdgCodeV0() == -3122 && casc.pdgCodePositive() == 211 && casc.pdgCodeNegative() == -2212 && casc.pdgCodeBachelor() == 211) || (!isXi && casc.pdgCodeV0() == -3122 && casc.pdgCodePositive() == 211 && casc.pdgCodeNegative() == -2212 && casc.pdgCodeBachelor() == 321)) - histos.fill(HIST("hPositiveCascadePtForEfficiency"), casc.pt(), invmass, coll.centFT0C()); - } - } + histos.fill(HIST("hCentralityVsIRGen"), centrality, intRate); + histos.fill(HIST("hMultMCVsCentralityVsIRGen"), mcCollision.multMCNParticlesEta05(), centrality, intRate); + + histos.fill(HIST("hCentralityVsMultMC"), centrality, mcCollision.multMCNParticlesEta05()); + histos.fill(HIST("hRecMultVsMultMC"), nChEta05, mcCollision.multMCNParticlesEta05()); + + histos.fill(HIST("hGenMultMCFT0C"), mcCollision.multMCFT0C()); + histos.fill(HIST("hGenMCNParticlesEta10"), mcCollision.multMCNParticlesEta10()); + + if (atLeastOne) { + histos.fill(HIST("hGenEvents"), mcCollision.multMCNParticlesEta05(), 3.5 /* at least 1 rec. event*/); } } + return listBestCollisionIdx; + } + + void processCascades(soa::Join::iterator const& coll, soa::Join const& Cascades, DauTracks const&) + { + analyseCascades(coll, Cascades); + } + void processCascadesRun2(soa::Join::iterator const& coll, soa::Join const& Cascades, DauTracks const&) + { + analyseCascades(coll, Cascades); + } + + void processCascadesMCrec(soa::Join::iterator const& coll, CascMCCandidates const& Cascades, DauTracks const&, soa::Join const&) + { + analyseCascades(coll, Cascades); + } + void processCascadesMCrecRun2(soa::Join::iterator const& coll, CascMCCandidates const& Cascades, DauTracks const&, soa::Join const&) + { + analyseCascades(coll, Cascades); + } + + void processCascadesMCforEff(soa::Join const& mcCollisions, soa::Join const& Cascades, soa::Join const& collisions) + { + analyseCascadesMCforEff(mcCollisions, Cascades, collisions); + } + void processCascadesMCforEffRun2(soa::Join const& mcCollisions, soa::Join const& Cascades, soa::Join const& collisions) + { + analyseCascadesMCforEff(mcCollisions, Cascades, collisions); } - PROCESS_SWITCH(derivedCascadeAnalysis, processCascades, "cascade analysis, run3 data ", true); - PROCESS_SWITCH(derivedCascadeAnalysis, processCascadesMCrec, "cascade analysis, run3 rec MC", false); + PROCESS_SWITCH(Derivedcascadeanalysis, processCascades, "cascade analysis, run3 data ", true); + PROCESS_SWITCH(Derivedcascadeanalysis, processCascadesRun2, "cascade analysis, run2 data ", false); + PROCESS_SWITCH(Derivedcascadeanalysis, processCascadesMCrec, "cascade analysis, run3 rec MC", false); + PROCESS_SWITCH(Derivedcascadeanalysis, processCascadesMCrecRun2, "cascade analysis, run2 rec MC", false); + PROCESS_SWITCH(Derivedcascadeanalysis, processCascadesMCforEff, "cascade analysis, run3 rec MC", false); + PROCESS_SWITCH(Derivedcascadeanalysis, processCascadesMCforEffRun2, "cascade analysis, run2 rec MC", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/Strangeness/derivedlambdakzeroanalysis.cxx b/PWGLF/Tasks/Strangeness/derivedlambdakzeroanalysis.cxx index 1fea89cd342..55e618ac11a 100644 --- a/PWGLF/Tasks/Strangeness/derivedlambdakzeroanalysis.cxx +++ b/PWGLF/Tasks/Strangeness/derivedlambdakzeroanalysis.cxx @@ -9,6 +9,12 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // +/// \file derivedlambdakzeroanalysis.cxx +/// \brief V0s (K0s, Lambda and antiLambda) analysis task using derived data +/// +/// \author David Dobrigkeit Chinellato , Austrian Academy of Sciences & SMI +/// \author Romain Schotter , Austrian Academy of Sciences & SMI +// // V0 analysis task // ================ // @@ -26,22 +32,29 @@ #include #include #include +#include +#include +#include +#include #include #include #include #include #include -#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" #include "ReconstructionDataFormats/Track.h" +#include "CommonConstants/MathConstants.h" #include "CommonConstants/PhysicsConstants.h" #include "Common/Core/trackUtilities.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/DataModel/EventSelection.h" #include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessMLTables.h" #include "PWGLF/DataModel/LFStrangenessPIDTables.h" #include "Common/Core/TrackSelection.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -49,80 +62,211 @@ #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/PIDResponse.h" +#include "PWGUD/Core/SGSelector.h" +#include "Tools/ML/MlResponse.h" +#include "Tools/ML/model.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using std::array; -using dauTracks = soa::Join; -using v0Candidates = soa::Join; -using v0MCCandidates = soa::Join; +using namespace o2::aod::rctsel; + +using DauTracks = soa::Join; +using DauMCTracks = soa::Join; +using V0Candidates = soa::Join; +// using V0McCandidates = soa::Join; +using V0McCandidates = soa::Join; // simple checkers, but ensure 64 bit integers -#define bitset(var, nbit) ((var) |= (static_cast(1) << static_cast(nbit))) -#define bitcheck(var, nbit) ((var) & (static_cast(1) << static_cast(nbit))) +#define BITSET(var, nbit) ((var) |= (static_cast(1) << static_cast(nbit))) +#define BITCHECK(var, nbit) ((var) & (static_cast(1) << static_cast(nbit))) struct derivedlambdakzeroanalysis { HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + bool isRun3; + // master analysis switches Configurable analyseK0Short{"analyseK0Short", true, "process K0Short-like candidates"}; Configurable analyseLambda{"analyseLambda", true, "process Lambda-like candidates"}; Configurable analyseAntiLambda{"analyseAntiLambda", true, "process AntiLambda-like candidates"}; Configurable calculateFeeddownMatrix{"calculateFeeddownMatrix", true, "fill feeddown matrix if MC"}; - Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border"}; - Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border"}; - - // Selection criteria: acceptance - Configurable rapidityCut{"rapidityCut", 0.5, "rapidity"}; - Configurable daughterEtaCut{"daughterEtaCut", 0.8, "max eta for daughters"}; - - // Standard 5 topological criteria - Configurable v0cospa{"v0cospa", 0.97, "min V0 CosPA"}; - Configurable dcav0dau{"dcav0dau", 1.0, "max DCA V0 Daughters (cm)"}; - Configurable dcanegtopv{"dcanegtopv", .05, "min DCA Neg To PV (cm)"}; - Configurable dcapostopv{"dcapostopv", .05, "min DCA Pos To PV (cm)"}; - Configurable v0radius{"v0radius", 1.2, "minimum V0 radius (cm)"}; - Configurable v0radiusMax{"v0radiusMax", 1E5, "maximum V0 radius (cm)"}; - - // Additional selection on the AP plot (exclusive for K0Short) - // original equation: lArmPt*5>TMath::Abs(lArmAlpha) - Configurable armPodCut{"armPodCut", 5.0f, "pT * (cut) > |alpha|, AP cut. Negative: no cut"}; - - // Track quality - Configurable minTPCrows{"minTPCrows", 70, "minimum TPC crossed rows"}; - Configurable minITSclusters{"minITSclusters", -1, "minimum ITS clusters"}; - Configurable skipTPConly{"skipTPConly", false, "skip V0s comprised of at least one TPC only prong"}; - Configurable requirePosITSonly{"requirePosITSonly", false, "require that positive track is ITSonly (overrides TPC quality)"}; - Configurable requireNegITSonly{"requireNegITSonly", false, "require that negative track is ITSonly (overrides TPC quality)"}; - - // PID (TPC/TOF) - Configurable TpcPidNsigmaCut{"TpcPidNsigmaCut", 5, "TpcPidNsigmaCut"}; - Configurable TofPidNsigmaCutLaPr{"TofPidNsigmaCutLaPr", 1e+6, "TofPidNsigmaCutLaPr"}; - Configurable TofPidNsigmaCutLaPi{"TofPidNsigmaCutLaPi", 1e+6, "TofPidNsigmaCutLaPi"}; - Configurable TofPidNsigmaCutK0Pi{"TofPidNsigmaCutK0Pi", 1e+6, "TofPidNsigmaCutK0Pi"}; + + Configurable doPPAnalysis{"doPPAnalysis", false, "if in pp, set to true"}; + Configurable irSource{"irSource", "T0VTX", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + + struct : ConfigurableGroup { + Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; + Configurable requireTriggerTVX{"requireTriggerTVX", true, "require FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level"}; + Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border (Run 3 only)"}; + Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border (Run 3 only)"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "require events with at least one ITS-TPC track (Run 3 only)"}; + Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "require events with PV position along z consistent (within 1 cm) between PV reconstructed using tracks and PV using FT0 A-C time difference (Run 3 only)"}; + Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", false, "require events with at least one of vertex contributors matched to TOF (Run 3 only)"}; + Configurable requireIsVertexTRDmatched{"requireIsVertexTRDmatched", false, "require events with at least one of vertex contributors matched to TRD (Run 3 only)"}; + Configurable rejectSameBunchPileup{"rejectSameBunchPileup", true, "reject collisions in case of pileup with another collision in the same foundBC (Run 3 only)"}; + Configurable requireNoCollInTimeRangeStd{"requireNoCollInTimeRangeStd", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds (Run 3 only)"}; + Configurable requireNoCollInTimeRangeStrict{"requireNoCollInTimeRangeStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds (Run 3 only)"}; + Configurable requireNoCollInTimeRangeNarrow{"requireNoCollInTimeRangeNarrow", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds (Run 3 only)"}; + Configurable requireNoCollInROFStd{"requireNoCollInROFStd", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF with mult. above a certain threshold (Run 3 only)"}; + Configurable requireNoCollInROFStrict{"requireNoCollInROFStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF (Run 3 only)"}; + Configurable requireINEL0{"requireINEL0", true, "require INEL>0 event selection"}; + Configurable requireINEL1{"requireINEL1", false, "require INEL>1 event selection"}; + + Configurable maxZVtxPosition{"maxZVtxPosition", 10., "max Z vtx position"}; + + Configurable useEvtSelInDenomEff{"useEvtSelInDenomEff", false, "Consider event selections in the recoed <-> gen collision association for the denominator (or numerator) of the acc. x eff. (or signal loss)?"}; + Configurable applyZVtxSelOnMCPV{"applyZVtxSelOnMCPV", false, "Apply Z-vtx cut on the PV of the generated collision?"}; + Configurable useFT0CbasedOccupancy{"useFT0CbasedOccupancy", false, "Use sum of FT0-C amplitudes for estimating occupancy? (if not, use track-based definition)"}; + // fast check on occupancy + Configurable minOccupancy{"minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; + Configurable maxOccupancy{"maxOccupancy", -1, "maximum occupancy from neighbouring collisions"}; + // fast check on interaction rate + Configurable minIR{"minIR", -1, "minimum IR collisions"}; + Configurable maxIR{"maxIR", -1, "maximum IR collisions"}; + + // Run 2 specific event selections + Configurable requireSel7{"requireSel7", true, "require sel7 event selection (Run 2 only: event selection decision based on V0A & V0C)"}; + Configurable requireINT7{"requireINT7", true, "require INT7 trigger selection (Run 2 only)"}; + Configurable rejectIncompleteDAQ{"rejectIncompleteDAQ", true, "reject events with incomplete DAQ (Run 2 only)"}; + Configurable requireConsistentSPDAndTrackVtx{"requireConsistentSPDAndTrackVtx", true, "reject events with inconsistent in SPD and Track vertices (Run 2 only)"}; + Configurable rejectPileupFromSPD{"rejectPileupFromSPD", true, "reject events with pileup according to SPD vertexer (Run 2 only)"}; + Configurable rejectV0PFPileup{"rejectV0PFPileup", false, "reject events tagged as OOB pileup according to V0 past-future info (Run 2 only)"}; + Configurable rejectPileupInMultBins{"rejectPileupInMultBins", true, "reject events tagged as pileup according to multiplicity-differential pileup checks (Run 2 only)"}; + Configurable rejectPileupMV{"rejectPileupMV", true, "reject events tagged as pileup according to according to multi-vertexer (Run 2 only)"}; + Configurable rejectTPCPileup{"rejectTPCPileup", false, "reject events tagged as pileup according to pileup in TPC (Run 2 only)"}; + Configurable requireNoV0MOnVsOffPileup{"requireNoV0MOnVsOffPileup", false, "reject events tagged as OOB pileup according to online-vs-offline VOM correlation (Run 2 only)"}; + Configurable requireNoSPDOnVsOffPileup{"requireNoSPDOnVsOffPileup", false, "reject events tagged as pileup according to online-vs-offline SPD correlation (Run 2 only)"}; + Configurable requireNoSPDClsVsTklBG{"requireNoSPDClsVsTklBG", true, "reject events tagged as beam-gas and pileup according to cluster-vs-tracklet correlation (Run 2 only)"}; + + Configurable useSPDTrackletsCent{"useSPDTrackletsCent", false, "Use SPD tracklets for estimating centrality? If not, use V0M-based centrality (Run 2 only)"}; + } eventSelections; + + struct : ConfigurableGroup { + Configurable v0TypeSelection{"v0TypeSelection", 1, "select on a certain V0 type (leave negative if no selection desired)"}; + + // Selection criteria: acceptance + Configurable rapidityCut{"rapidityCut", 0.5, "rapidity"}; + Configurable daughterEtaCut{"daughterEtaCut", 0.8, "max eta for daughters"}; + + // Standard 5 topological criteria + Configurable v0cospa{"v0cospa", 0.97, "min V0 CosPA"}; + Configurable dcav0dau{"dcav0dau", 1.0, "max DCA V0 Daughters (cm)"}; + Configurable dcanegtopv{"dcanegtopv", .05, "min DCA Neg To PV (cm)"}; + Configurable dcapostopv{"dcapostopv", .05, "min DCA Pos To PV (cm)"}; + Configurable v0radius{"v0radius", 1.2, "minimum V0 radius (cm)"}; + Configurable v0radiusMax{"v0radiusMax", 1E5, "maximum V0 radius (cm)"}; + + // Additional selection on the AP plot (exclusive for K0Short) + // original equation: lArmPt*5>TMath::Abs(lArmAlpha) + Configurable armPodCut{"armPodCut", 5.0f, "pT * (cut) > |alpha|, AP cut. Negative: no cut"}; + + // Track quality + Configurable minTPCrows{"minTPCrows", 70, "minimum TPC crossed rows"}; + Configurable minITSclusters{"minITSclusters", -1, "minimum ITS clusters"}; + Configurable minTPCrowsOverFindableClusters{"minTPCrowsOverFindableClusters", -1, "minimum nbr of TPC crossed rows over findable clusters"}; + Configurable minTPCfoundOverFindableClusters{"minTPCfoundOverFindableClusters", -1, "minimum nbr of found over findable TPC clusters"}; + Configurable maxFractionTPCSharedClusters{"maxFractionTPCSharedClusters", 1e+09, "maximum fraction of TPC shared clusters"}; + Configurable maxITSchi2PerNcls{"maxITSchi2PerNcls", 1e+09, "maximum ITS chi2 per clusters"}; + Configurable maxTPCchi2PerNcls{"maxTPCchi2PerNcls", 1e+09, "maximum TPC chi2 per clusters"}; + Configurable skipTPConly{"skipTPConly", false, "skip V0s comprised of at least one TPC only prong"}; + Configurable requirePosITSonly{"requirePosITSonly", false, "require that positive track is ITSonly (overrides TPC quality)"}; + Configurable requireNegITSonly{"requireNegITSonly", false, "require that negative track is ITSonly (overrides TPC quality)"}; + Configurable rejectPosITSafterburner{"rejectPosITSafterburner", false, "reject positive track formed out of afterburner ITS tracks"}; + Configurable rejectNegITSafterburner{"rejectNegITSafterburner", false, "reject negative track formed out of afterburner ITS tracks"}; + Configurable requirePosITSafterburnerOnly{"requirePosITSafterburnerOnly", false, "require positive track formed out of afterburner ITS tracks"}; + Configurable requireNegITSafterburnerOnly{"requireNegITSafterburnerOnly", false, "require negative track formed out of afterburner ITS tracks"}; + + // PID (TPC/TOF) + Configurable tpcPidNsigmaCut{"tpcPidNsigmaCut", 5, "tpcPidNsigmaCut"}; + Configurable tofPidNsigmaCutLaPr{"tofPidNsigmaCutLaPr", 1e+6, "tofPidNsigmaCutLaPr"}; + Configurable tofPidNsigmaCutLaPi{"tofPidNsigmaCutLaPi", 1e+6, "tofPidNsigmaCutLaPi"}; + Configurable tofPidNsigmaCutK0Pi{"tofPidNsigmaCutK0Pi", 1e+6, "tofPidNsigmaCutK0Pi"}; + + // PID (TOF) + Configurable maxDeltaTimeProton{"maxDeltaTimeProton", 1e+9, "check maximum allowed time"}; + Configurable maxDeltaTimePion{"maxDeltaTimePion", 1e+9, "check maximum allowed time"}; + } v0Selections; Configurable doCompleteTopoQA{"doCompleteTopoQA", false, "do topological variable QA histograms"}; Configurable doTPCQA{"doTPCQA", false, "do TPC QA histograms"}; Configurable doTOFQA{"doTOFQA", false, "do TOF QA histograms"}; - Configurable doDetectPropQA{"doDetectPropQA", 0, "do Detector/ITS map QA: 0: no, 1: 4D, 2: 5D with mass"}; + Configurable doDetectPropQA{"doDetectPropQA", 0, "do Detector/ITS map QA: 0: no, 1: 4D, 2: 5D with mass; 3: plain in 3D"}; Configurable doPlainTopoQA{"doPlainTopoQA", true, "do simple 1D QA of candidates"}; Configurable qaMinPt{"qaMinPt", 0.0f, "minimum pT for QA plots"}; Configurable qaMaxPt{"qaMaxPt", 1000.0f, "maximum pT for QA plots"}; Configurable qaCentrality{"qaCentrality", false, "qa centrality flag: check base raw values"}; - // PID (TOF) - Configurable maxDeltaTimeProton{"maxDeltaTimeProton", 1e+9, "check maximum allowed time"}; - Configurable maxDeltaTimePion{"maxDeltaTimePion", 1e+9, "check maximum allowed time"}; - // for MC Configurable doMCAssociation{"doMCAssociation", true, "if MC, do MC association"}; + Configurable doTreatPiToMuon{"doTreatPiToMuon", false, "Take pi decay into muon into account in MC"}; Configurable doCollisionAssociationQA{"doCollisionAssociationQA", true, "check collision association"}; - static constexpr float defaultLifetimeCuts[1][2] = {{30., 20.}}; - Configurable> lifetimecut{"lifetimecut", {defaultLifetimeCuts[0], 2, {"lifetimecutLambda", "lifetimecutK0S"}}, "lifetimecut"}; + struct : ConfigurableGroup { + std::string prefix = "rctConfigurations"; // JSON group name + Configurable cfgRCTLabel{"cfgRCTLabel", "", "Which detector condition requirements? (CBT, CBT_hadronPID, CBT_electronPID, CBT_calo, CBT_muon, CBT_muon_glo)"}; + Configurable cfgCheckZDC{"cfgCheckZDC", false, "Include ZDC flags in the bit selection (for Pb-Pb only)"}; + Configurable cfgTreatLimitedAcceptanceAsBad{"cfgTreatLimitedAcceptanceAsBad", false, "reject all events where the detectors relevant for the specified Runlist are flagged as LimitedAcceptance"}; + } rctConfigurations; + + RCTFlagsChecker rctFlagsChecker{rctConfigurations.cfgRCTLabel.value}; + + // Machine learning evaluation for pre-selection and corresponding information generation + o2::ml::OnnxModel mlCustomModelK0Short; + o2::ml::OnnxModel mlCustomModelLambda; + o2::ml::OnnxModel mlCustomModelAntiLambda; + o2::ml::OnnxModel mlCustomModelGamma; + + struct : ConfigurableGroup { + std::string prefix = "mlConfigurations"; // JSON group name + // ML classifiers: master flags to control whether we should use custom ML classifiers or the scores in the derived data + Configurable useK0ShortScores{"useK0ShortScores", false, "use ML scores to select K0Short"}; + Configurable useLambdaScores{"useLambdaScores", false, "use ML scores to select Lambda"}; + Configurable useAntiLambdaScores{"useAntiLambdaScores", false, "use ML scores to select AntiLambda"}; + + Configurable calculateK0ShortScores{"calculateK0ShortScores", false, "calculate K0Short ML scores"}; + Configurable calculateLambdaScores{"calculateLambdaScores", false, "calculate Lambda ML scores"}; + Configurable calculateAntiLambdaScores{"calculateAntiLambdaScores", false, "calculate AntiLambda ML scores"}; + + // ML input for ML calculation + Configurable customModelPathCCDB{"customModelPathCCDB", "", "Custom ML Model path in CCDB"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB. Exceptions: > 0 for the specific timestamp, 0 gets the run dependent timestamp"}; + Configurable loadCustomModelsFromCCDB{"loadCustomModelsFromCCDB", false, "Flag to enable or disable the loading of custom models from CCDB"}; + Configurable enableOptimizations{"enableOptimizations", false, "Enables the ONNX extended model-optimization: sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED)"}; + + // Local paths for test purposes + Configurable localModelPathLambda{"localModelPathLambda", "Lambda_BDTModel.onnx", "(std::string) Path to the local .onnx file."}; + Configurable localModelPathAntiLambda{"localModelPathAntiLambda", "AntiLambda_BDTModel.onnx", "(std::string) Path to the local .onnx file."}; + Configurable localModelPathK0Short{"localModelPathK0Short", "KZeroShort_BDTModel.onnx", "(std::string) Path to the local .onnx file."}; + + // Thresholds for choosing to populate V0Cores tables with pre-selections + Configurable thresholdLambda{"thresholdLambda", -1.0f, "Threshold to keep Lambda candidates"}; + Configurable thresholdAntiLambda{"thresholdAntiLambda", -1.0f, "Threshold to keep AntiLambda candidates"}; + Configurable thresholdK0Short{"thresholdK0Short", -1.0f, "Threshold to keep K0Short candidates"}; + } mlConfigurations; + + // CCDB options + struct : ConfigurableGroup { + std::string prefix = "ccdbConfigurations"; // JSON group name + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable mVtxPath{"mVtxPath", "GLO/Calib/MeanVertex", "Path of the mean vertex file"}; + } ccdbConfigurations; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + ctpRateFetcher rateFetcher; + int mRunNumber; + std::map metadata; + + static constexpr float DefaultLifetimeCuts[1][2] = {{30., 20.}}; + Configurable> lifetimecut{"lifetimecut", {DefaultLifetimeCuts[0], 2, {"lifetimecutLambda", "lifetimecutK0S"}}, "lifetimecut"}; ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for analysis"}; ConfigurableAxis axisPtXi{"axisPtXi", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for feeddown from Xi"}; @@ -130,9 +274,13 @@ struct derivedlambdakzeroanalysis { ConfigurableAxis axisK0Mass{"axisK0Mass", {200, 0.4f, 0.6f}, ""}; ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.101f, 1.131f}, ""}; ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f}, "Centrality"}; + ConfigurableAxis axisNch{"axisNch", {500, 0.0f, +5000.0f}, "Number of charged particles"}; + ConfigurableAxis axisIRBinning{"axisIRBinning", {500, 0, 50}, "Binning for the interaction rate (kHz)"}; ConfigurableAxis axisRawCentrality{"axisRawCentrality", {VARIABLE_WIDTH, 0.000f, 52.320f, 75.400f, 95.719f, 115.364f, 135.211f, 155.791f, 177.504f, 200.686f, 225.641f, 252.645f, 281.906f, 313.850f, 348.302f, 385.732f, 426.307f, 470.146f, 517.555f, 568.899f, 624.177f, 684.021f, 748.734f, 818.078f, 892.577f, 973.087f, 1058.789f, 1150.915f, 1249.319f, 1354.279f, 1465.979f, 1584.790f, 1710.778f, 1844.863f, 1985.746f, 2134.643f, 2291.610f, 2456.943f, 2630.653f, 2813.959f, 3006.631f, 3207.229f, 3417.641f, 3637.318f, 3865.785f, 4104.997f, 4354.938f, 4615.786f, 4885.335f, 5166.555f, 5458.021f, 5762.584f, 6077.881f, 6406.834f, 6746.435f, 7097.958f, 7462.579f, 7839.165f, 8231.629f, 8635.640f, 9052.000f, 9484.268f, 9929.111f, 10389.350f, 10862.059f, 11352.185f, 11856.823f, 12380.371f, 12920.401f, 13476.971f, 14053.087f, 14646.190f, 15258.426f, 15890.617f, 16544.433f, 17218.024f, 17913.465f, 18631.374f, 19374.983f, 20136.700f, 20927.783f, 21746.796f, 22590.880f, 23465.734f, 24372.274f, 25314.351f, 26290.488f, 27300.899f, 28347.512f, 29436.133f, 30567.840f, 31746.818f, 32982.664f, 34276.329f, 35624.859f, 37042.588f, 38546.609f, 40139.742f, 41837.980f, 43679.429f, 45892.130f, 400000.000f}, "raw centrality signal"}; // for QA + ConfigurableAxis axisOccupancy{"axisOccupancy", {VARIABLE_WIDTH, 0.0f, 250.0f, 500.0f, 750.0f, 1000.0f, 1500.0f, 2000.0f, 3000.0f, 4500.0f, 6000.0f, 8000.0f, 10000.0f, 50000.0f}, "Occupancy"}; + // topological variable QA axes ConfigurableAxis axisDCAtoPV{"axisDCAtoPV", {20, 0.0f, 1.0f}, "DCA (cm)"}; ConfigurableAxis axisDCAdau{"axisDCAdau", {20, 0.0f, 2.0f}, "DCA (cm)"}; @@ -140,7 +288,29 @@ struct derivedlambdakzeroanalysis { ConfigurableAxis axisV0Radius{"axisV0Radius", {20, 0.0f, 60.0f}, "V0 2D radius (cm)"}; ConfigurableAxis axisNsigmaTPC{"axisNsigmaTPC", {200, -10.0f, 10.0f}, "N sigma TPC"}; ConfigurableAxis axisTPCsignal{"axisTPCsignal", {200, 0.0f, 200.0f}, "TPC signal"}; + ConfigurableAxis axisNsigmaTOF{"axisNsigmaTOF", {200, -10.0f, 10.0f}, "N sigma TOF"}; ConfigurableAxis axisTOFdeltaT{"axisTOFdeltaT", {200, -5000.0f, 5000.0f}, "TOF Delta T (ps)"}; + ConfigurableAxis axisPhi{"axisPhi", {18, 0.0f, constants::math::TwoPI}, "Azimuth angle (rad)"}; + ConfigurableAxis axisEta{"axisEta", {10, -1.0f, 1.0f}, "#eta"}; + ConfigurableAxis axisITSchi2{"axisITSchi2", {100, 0.0f, 100.0f}, "#chi^{2} per ITS clusters"}; + ConfigurableAxis axisTPCchi2{"axisTPCchi2", {100, 0.0f, 100.0f}, "#chi^{2} per TPC clusters"}; + ConfigurableAxis axisTPCrowsOverFindable{"axisTPCrowsOverFindable", {120, 0.0f, 1.2f}, "Fraction of TPC crossed rows over findable clusters"}; + ConfigurableAxis axisTPCfoundOverFindable{"axisTPCfoundOverFindable", {120, 0.0f, 1.2f}, "Fraction of TPC found over findable clusters"}; + ConfigurableAxis axisTPCsharedClusters{"axisTPCsharedClusters", {101, -0.005f, 1.005f}, "Fraction of TPC shared clusters"}; + + // UPC axes + ConfigurableAxis axisSelGap{"axisSelGap", {4, -1.5, 2.5}, "Gap side"}; + + // UPC selections + SGSelector sgSelector; + struct : ConfigurableGroup { + std::string prefix = "upcCuts"; // JSON group name + Configurable fv0Cut{"fv0Cut", 100., "FV0A threshold"}; + Configurable ft0Acut{"ft0Acut", 200., "FT0A threshold"}; + Configurable ft0Ccut{"ft0Ccut", 100., "FT0C threshold"}; + Configurable zdcCut{"zdcCut", 10., "ZDC threshold"}; + // Configurable gapSel{"gapSel", 2, "Gap selection"}; + } upcCuts; // AP plot axes ConfigurableAxis axisAPAlpha{"axisAPAlpha", {220, -1.1f, 1.1f}, "V0 AP alpha"}; @@ -149,15 +319,20 @@ struct derivedlambdakzeroanalysis { // Track quality axes ConfigurableAxis axisTPCrows{"axisTPCrows", {160, 0.0f, 160.0f}, "N TPC rows"}; ConfigurableAxis axisITSclus{"axisITSclus", {7, 0.0f, 7.0f}, "N ITS Clusters"}; - ConfigurableAxis axisITScluMap{"axisITSMap", {128, -0.5f, 127.5f}, "ITS Cluster map"}; + ConfigurableAxis axisITScluMap{"axisITScluMap", {128, -0.5f, 127.5f}, "ITS Cluster map"}; ConfigurableAxis axisDetMap{"axisDetMap", {16, -0.5f, 15.5f}, "Detector use map"}; - ConfigurableAxis axisITScluMapCoarse{"axisITScluMapCoarse", {13, -0.5f, 12.5f}, "ITS Coarse cluster map"}; - ConfigurableAxis axisDetMapCoarse{"axisDetMapCoarse", {4, -0.5f, 3.5f}, "Detector Coarse user map"}; + ConfigurableAxis axisITScluMapCoarse{"axisITScluMapCoarse", {16, -3.5f, 12.5f}, "ITS Coarse cluster map"}; + ConfigurableAxis axisDetMapCoarse{"axisDetMapCoarse", {5, -0.5f, 4.5f}, "Detector Coarse user map"}; // MC coll assoc QA axis ConfigurableAxis axisMonteCarloNch{"axisMonteCarloNch", {300, 0.0f, 3000.0f}, "N_{ch} MC"}; - enum selection : uint64_t { selCosPA = 0, + // For manual sliceBy + // Preslice> perMcCollision = aod::v0data::straMCCollisionId; + PresliceUnsorted> perMcCollision = aod::v0data::straMCCollisionId; + PresliceUnsorted> perMcCollisionRun2 = aod::v0data::straMCCollisionId; + + enum Selection : uint64_t { selCosPA = 0, selRadius, selRadiusMax, selDCANegToPV, @@ -221,82 +396,236 @@ struct derivedlambdakzeroanalysis { void init(InitContext const&) { - // initialise bit masks - maskTopological = (uint64_t(1) << selCosPA) | (uint64_t(1) << selRadius) | (uint64_t(1) << selDCANegToPV) | (uint64_t(1) << selDCAPosToPV) | (uint64_t(1) << selDCAV0Dau) | (uint64_t(1) << selRadiusMax); - maskTopoNoV0Radius = (uint64_t(1) << selCosPA) | (uint64_t(1) << selDCANegToPV) | (uint64_t(1) << selDCAPosToPV) | (uint64_t(1) << selDCAV0Dau) | (uint64_t(1) << selRadiusMax); - maskTopoNoDCANegToPV = (uint64_t(1) << selCosPA) | (uint64_t(1) << selRadius) | (uint64_t(1) << selDCAPosToPV) | (uint64_t(1) << selDCAV0Dau) | (uint64_t(1) << selRadiusMax); - maskTopoNoDCAPosToPV = (uint64_t(1) << selCosPA) | (uint64_t(1) << selRadius) | (uint64_t(1) << selDCANegToPV) | (uint64_t(1) << selDCAV0Dau) | (uint64_t(1) << selRadiusMax); - maskTopoNoCosPA = (uint64_t(1) << selRadius) | (uint64_t(1) << selDCANegToPV) | (uint64_t(1) << selDCAPosToPV) | (uint64_t(1) << selDCAV0Dau) | (uint64_t(1) << selRadiusMax); - maskTopoNoDCAV0Dau = (uint64_t(1) << selCosPA) | (uint64_t(1) << selRadius) | (uint64_t(1) << selDCANegToPV) | (uint64_t(1) << selDCAPosToPV) | (uint64_t(1) << selRadiusMax); + // Determine if we are dealing with Run3 or Run2 processing + if ((doprocessRealDataRun3 || doprocessMonteCarloRun3 || doprocessGeneratedRun3) && (doprocessRealDataRun2 || doprocessMonteCarloRun2 || doprocessGeneratedRun2)) { + LOGF(fatal, "Cannot enable Run2 and Run3 processes at the same time. Please choose one."); + } + if (doprocessRealDataRun3 || doprocessMonteCarloRun3 || doprocessGeneratedRun3) { + isRun3 = true; + } else { + isRun3 = false; + } + // setting CCDB service + ccdb->setURL(ccdbConfigurations.ccdbUrl); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); - maskK0ShortSpecific = (uint64_t(1) << selK0ShortRapidity) | (uint64_t(1) << selK0ShortCTau) | (uint64_t(1) << selK0ShortArmenteros) | (uint64_t(1) << selConsiderK0Short); - maskLambdaSpecific = (uint64_t(1) << selLambdaRapidity) | (uint64_t(1) << selLambdaCTau) | (uint64_t(1) << selConsiderLambda); - maskAntiLambdaSpecific = (uint64_t(1) << selLambdaRapidity) | (uint64_t(1) << selLambdaCTau) | (uint64_t(1) << selConsiderAntiLambda); + // initialise bit masks + // Mask with all topologic selections + maskTopological = 0; + BITSET(maskTopological, selCosPA); + BITSET(maskTopological, selRadius); + BITSET(maskTopological, selDCANegToPV); + BITSET(maskTopological, selDCAPosToPV); + BITSET(maskTopological, selDCAV0Dau); + BITSET(maskTopological, selRadiusMax); + // Mask with all topologic selections, except for V0 radius + maskTopoNoV0Radius = 0; + BITSET(maskTopoNoV0Radius, selCosPA); + BITSET(maskTopoNoV0Radius, selDCANegToPV); + BITSET(maskTopoNoV0Radius, selDCAPosToPV); + BITSET(maskTopoNoV0Radius, selDCAV0Dau); + BITSET(maskTopoNoV0Radius, selRadiusMax); + // Mask with all topologic selections, except for DCA neg. to PV + maskTopoNoDCANegToPV = 0; + BITSET(maskTopoNoDCANegToPV, selCosPA); + BITSET(maskTopoNoDCANegToPV, selRadius); + BITSET(maskTopoNoDCANegToPV, selDCAPosToPV); + BITSET(maskTopoNoDCANegToPV, selDCAV0Dau); + BITSET(maskTopoNoDCANegToPV, selRadiusMax); + // Mask with all topologic selections, except for DCA pos. to PV + maskTopoNoDCAPosToPV = 0; + BITSET(maskTopoNoDCAPosToPV, selCosPA); + BITSET(maskTopoNoDCAPosToPV, selRadius); + BITSET(maskTopoNoDCAPosToPV, selDCANegToPV); + BITSET(maskTopoNoDCAPosToPV, selDCAV0Dau); + BITSET(maskTopoNoDCAPosToPV, selRadiusMax); + // Mask with all topologic selections, except for cosPA + maskTopoNoCosPA = 0; + BITSET(maskTopoNoCosPA, selRadius); + BITSET(maskTopoNoCosPA, selDCANegToPV); + BITSET(maskTopoNoCosPA, selDCAPosToPV); + BITSET(maskTopoNoCosPA, selDCAV0Dau); + BITSET(maskTopoNoCosPA, selRadiusMax); + // Mask with all topologic selections, except for DCA between V0 dau + maskTopoNoDCAV0Dau = 0; + BITSET(maskTopoNoDCAV0Dau, selCosPA); + BITSET(maskTopoNoDCAV0Dau, selRadius); + BITSET(maskTopoNoDCAV0Dau, selDCANegToPV); + BITSET(maskTopoNoDCAV0Dau, selDCAPosToPV); + BITSET(maskTopoNoDCAV0Dau, selRadiusMax); + + // Mask for specifically selecting K0Short + maskK0ShortSpecific = 0; + BITSET(maskK0ShortSpecific, selK0ShortRapidity); + BITSET(maskK0ShortSpecific, selK0ShortCTau); + BITSET(maskK0ShortSpecific, selK0ShortArmenteros); + BITSET(maskK0ShortSpecific, selConsiderK0Short); + // Mask for specifically selecting Lambda + maskLambdaSpecific = 0; + BITSET(maskLambdaSpecific, selLambdaRapidity); + BITSET(maskLambdaSpecific, selLambdaCTau); + BITSET(maskLambdaSpecific, selConsiderLambda); + // Mask for specifically selecting AntiLambda + maskAntiLambdaSpecific = 0; + BITSET(maskAntiLambdaSpecific, selLambdaRapidity); + BITSET(maskAntiLambdaSpecific, selLambdaCTau); + BITSET(maskAntiLambdaSpecific, selConsiderAntiLambda); // ask for specific TPC/TOF PID selections maskTrackProperties = 0; - if (requirePosITSonly) { - maskTrackProperties = maskTrackProperties | (uint64_t(1) << selPosItsOnly) | (uint64_t(1) << selPosGoodITSTrack); + if (v0Selections.requirePosITSonly) { + BITSET(maskTrackProperties, selPosItsOnly); + BITSET(maskTrackProperties, selPosGoodITSTrack); } else { - maskTrackProperties = maskTrackProperties | (uint64_t(1) << selPosGoodTPCTrack) | (uint64_t(1) << selPosGoodITSTrack); + BITSET(maskTrackProperties, selPosGoodTPCTrack); + BITSET(maskTrackProperties, selPosGoodITSTrack); // TPC signal is available: ask for positive track PID - if (TpcPidNsigmaCut < 1e+5) { // safeguard for no cut - maskK0ShortSpecific = maskK0ShortSpecific | (uint64_t(1) << selTPCPIDPositivePion); - maskLambdaSpecific = maskLambdaSpecific | (uint64_t(1) << selTPCPIDPositiveProton); - maskAntiLambdaSpecific = maskAntiLambdaSpecific | (uint64_t(1) << selTPCPIDPositivePion); + if (v0Selections.tpcPidNsigmaCut < 1e+5) { // safeguard for no cut + BITSET(maskK0ShortSpecific, selTPCPIDPositivePion); + BITSET(maskLambdaSpecific, selTPCPIDPositiveProton); + BITSET(maskAntiLambdaSpecific, selTPCPIDPositivePion); } // TOF PID - if (TofPidNsigmaCutK0Pi < 1e+5) // safeguard for no cut - maskK0ShortSpecific = maskK0ShortSpecific | (uint64_t(1) << selTOFNSigmaPositivePionK0Short) | (uint64_t(1) << selTOFDeltaTPositivePionK0Short); - if (TofPidNsigmaCutLaPr < 1e+5) // safeguard for no cut - maskLambdaSpecific = maskLambdaSpecific | (uint64_t(1) << selTOFNSigmaPositiveProtonLambda) | (uint64_t(1) << selTOFDeltaTPositiveProtonLambda); - if (TofPidNsigmaCutLaPi < 1e+5) // safeguard for no cut - maskAntiLambdaSpecific = maskAntiLambdaSpecific | (uint64_t(1) << selTOFNSigmaPositivePionLambda) | (uint64_t(1) << selTOFDeltaTPositivePionLambda); + if (v0Selections.tofPidNsigmaCutK0Pi < 1e+5) { // safeguard for no cut + BITSET(maskK0ShortSpecific, selTOFNSigmaPositivePionK0Short); + BITSET(maskK0ShortSpecific, selTOFDeltaTPositivePionK0Short); + } + if (v0Selections.tofPidNsigmaCutLaPr < 1e+5) { // safeguard for no cut + BITSET(maskLambdaSpecific, selTOFNSigmaPositiveProtonLambda); + BITSET(maskLambdaSpecific, selTOFDeltaTPositiveProtonLambda); + } + if (v0Selections.tofPidNsigmaCutLaPi < 1e+5) { // safeguard for no cut + BITSET(maskAntiLambdaSpecific, selTOFNSigmaPositivePionLambda); + BITSET(maskAntiLambdaSpecific, selTOFDeltaTPositivePionLambda); + } } - if (requireNegITSonly) { - maskTrackProperties = maskTrackProperties | (uint64_t(1) << selNegItsOnly) | (uint64_t(1) << selNegGoodITSTrack); + if (v0Selections.requireNegITSonly) { + BITSET(maskTrackProperties, selNegItsOnly); + BITSET(maskTrackProperties, selNegGoodITSTrack); } else { - maskTrackProperties = maskTrackProperties | (uint64_t(1) << selNegGoodTPCTrack) | (uint64_t(1) << selNegGoodITSTrack); + BITSET(maskTrackProperties, selNegGoodTPCTrack); + BITSET(maskTrackProperties, selNegGoodITSTrack); // TPC signal is available: ask for negative track PID - if (TpcPidNsigmaCut < 1e+5) { // safeguard for no cut - maskK0ShortSpecific = maskK0ShortSpecific | (uint64_t(1) << selTPCPIDNegativePion); - maskLambdaSpecific = maskLambdaSpecific | (uint64_t(1) << selTPCPIDNegativePion); - maskAntiLambdaSpecific = maskAntiLambdaSpecific | (uint64_t(1) << selTPCPIDNegativeProton); + if (v0Selections.tpcPidNsigmaCut < 1e+5) { // safeguard for no cut + BITSET(maskK0ShortSpecific, selTPCPIDNegativePion); + BITSET(maskLambdaSpecific, selTPCPIDNegativePion); + BITSET(maskAntiLambdaSpecific, selTPCPIDNegativeProton); } // TOF PID - if (TofPidNsigmaCutK0Pi < 1e+5) // safeguard for no cut - maskK0ShortSpecific = maskK0ShortSpecific | (uint64_t(1) << selTOFNSigmaNegativePionK0Short) | (uint64_t(1) << selTOFDeltaTNegativePionK0Short); - if (TofPidNsigmaCutLaPr < 1e+5) // safeguard for no cut - maskLambdaSpecific = maskLambdaSpecific | (uint64_t(1) << selTOFNSigmaNegativePionLambda) | (uint64_t(1) << selTOFDeltaTNegativePionLambda); - if (TofPidNsigmaCutLaPi < 1e+5) // safeguard for no cut - maskAntiLambdaSpecific = maskAntiLambdaSpecific | (uint64_t(1) << selTOFNSigmaNegativeProtonLambda) | (uint64_t(1) << selTOFDeltaTNegativeProtonLambda); + if (v0Selections.tofPidNsigmaCutK0Pi < 1e+5) { // safeguard for no cut + BITSET(maskK0ShortSpecific, selTOFNSigmaNegativePionK0Short); + BITSET(maskK0ShortSpecific, selTOFDeltaTNegativePionK0Short); + } + if (v0Selections.tofPidNsigmaCutLaPi < 1e+5) { // safeguard for no cut + BITSET(maskLambdaSpecific, selTOFNSigmaNegativePionLambda); + BITSET(maskLambdaSpecific, selTOFDeltaTNegativePionLambda); + } + if (v0Selections.tofPidNsigmaCutLaPr < 1e+5) { // safeguard for no cut + BITSET(maskAntiLambdaSpecific, selTOFNSigmaNegativeProtonLambda); + BITSET(maskAntiLambdaSpecific, selTOFDeltaTNegativeProtonLambda); + } } - if (skipTPConly) { - maskK0ShortSpecific = maskK0ShortSpecific | (uint64_t(1) << selPosNotTPCOnly) | (uint64_t(1) << selNegNotTPCOnly); - maskLambdaSpecific = maskLambdaSpecific | (uint64_t(1) << selPosNotTPCOnly) | (uint64_t(1) << selNegNotTPCOnly); - maskAntiLambdaSpecific = maskAntiLambdaSpecific | (uint64_t(1) << selPosNotTPCOnly) | (uint64_t(1) << selNegNotTPCOnly); + if (v0Selections.skipTPConly) { + BITSET(maskK0ShortSpecific, selPosNotTPCOnly); + BITSET(maskLambdaSpecific, selPosNotTPCOnly); + BITSET(maskAntiLambdaSpecific, selPosNotTPCOnly); + + BITSET(maskK0ShortSpecific, selNegNotTPCOnly); + BITSET(maskLambdaSpecific, selNegNotTPCOnly); + BITSET(maskAntiLambdaSpecific, selNegNotTPCOnly); } // Primary particle selection, central to analysis - maskSelectionK0Short = maskTopological | maskTrackProperties | maskK0ShortSpecific | (uint64_t(1) << selPhysPrimK0Short); - maskSelectionLambda = maskTopological | maskTrackProperties | maskLambdaSpecific | (uint64_t(1) << selPhysPrimLambda); - maskSelectionAntiLambda = maskTopological | maskTrackProperties | maskAntiLambdaSpecific | (uint64_t(1) << selPhysPrimAntiLambda); + maskSelectionK0Short = maskTopological | maskTrackProperties | maskK0ShortSpecific | (static_cast(1) << selPhysPrimK0Short); + maskSelectionLambda = maskTopological | maskTrackProperties | maskLambdaSpecific | (static_cast(1) << selPhysPrimLambda); + maskSelectionAntiLambda = maskTopological | maskTrackProperties | maskAntiLambdaSpecific | (static_cast(1) << selPhysPrimAntiLambda); + + BITSET(maskSelectionK0Short, selPhysPrimK0Short); + BITSET(maskSelectionLambda, selPhysPrimLambda); + BITSET(maskSelectionAntiLambda, selPhysPrimAntiLambda); // No primary requirement for feeddown matrix secondaryMaskSelectionLambda = maskTopological | maskTrackProperties | maskLambdaSpecific; secondaryMaskSelectionAntiLambda = maskTopological | maskTrackProperties | maskAntiLambdaSpecific; + // Initialise the RCTFlagsChecker + rctFlagsChecker.init(rctConfigurations.cfgRCTLabel.value, rctConfigurations.cfgCheckZDC, rctConfigurations.cfgTreatLimitedAcceptanceAsBad); + // Event Counters - histos.add("hEventSelection", "hEventSelection", kTH1F, {{10, -0.5f, +9.5f}}); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(3, "posZ cut"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + histos.add("hEventSelection", "hEventSelection", kTH1F, {{21, -0.5f, +20.5f}}); + if (isRun3) { + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(3, "kIsTriggerTVX"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(6, "posZ cut"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(7, "kIsVertexITSTPC"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(8, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(9, "kIsVertexTOFmatched"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(10, "kIsVertexTRDmatched"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(11, "kNoSameBunchPileup"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(12, "kNoCollInTimeRangeStd"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(13, "kNoCollInTimeRangeStrict"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(14, "kNoCollInTimeRangeNarrow"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(15, "kNoCollInRofStd"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(16, "kNoCollInRofStrict"); + if (doPPAnalysis) { + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "INEL>0"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "INEL>1"); + } else { + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "Below min occup."); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "Above max occup."); + } + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(19, "Below min IR"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(20, "Above max IR"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(21, "RCT flags"); + } else { + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(3, "sel7 cut"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(4, "kINT7"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(5, "kIsTriggerTVX"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(6, "kNoIncompleteDAQ"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(7, "posZ cut"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(8, "kNoInconsistentVtx"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(9, "kNoPileupFromSPD"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(10, "kNoV0PFPileup"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(11, "kNoPileupInMultBins"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(12, "kNoPileupMV"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(13, "kNoPileupTPC"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(14, "kNoV0MOnVsOfPileup"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(15, "kNoSPDOnVsOfPileup"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(16, "kNoSPDClsVsTklBG"); + if (doPPAnalysis) { + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "INEL>0"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "INEL>1"); + } + } + + histos.add("hEventCentrality", "hEventCentrality", kTH1F, {{101, 0.0f, 101.0f}}); + histos.add("hCentralityVsNch", "hCentralityVsNch", kTH2F, {{101, 0.0f, 101.0f}, axisNch}); - histos.add("hEventCentrality", "hEventCentrality", kTH1F, {{100, 0.0f, +100.0f}}); - histos.add("hCentralityVsNch", "hCentralityVsNch", kTH2F, {axisCentrality, {500, 0.0f, +2000.0f}}); + histos.add("hEventPVz", "hEventPVz", kTH1F, {{100, -20.0f, +20.0f}}); + histos.add("hCentralityVsPVz", "hCentralityVsPVz", kTH2F, {{101, 0.0f, 101.0f}, {100, -20.0f, +20.0f}}); + if (doprocessGeneratedRun3 || doprocessGeneratedRun2) { + histos.add("hEventPVzMC", "hEventPVzMC", kTH1F, {{100, -20.0f, +20.0f}}); + histos.add("hCentralityVsPVzMC", "hCentralityVsPVzMC", kTH2F, {{101, 0.0f, 101.0f}, {100, -20.0f, +20.0f}}); + } + + histos.add("hEventOccupancy", "hEventOccupancy", kTH1F, {axisOccupancy}); + histos.add("hCentralityVsOccupancy", "hCentralityVsOccupancy", kTH2F, {{101, 0.0f, 101.0f}, axisOccupancy}); + + histos.add("hGapSide", "Gap side; Entries", kTH1F, {{5, -0.5, 4.5}}); + histos.add("hSelGapSide", "Selected gap side; Entries", kTH1F, {axisSelGap}); + histos.add("hEventCentralityVsSelGapSide", ";Centrality (%); Selected gap side", kTH2F, {{101, 0.0f, 101.0f}, axisSelGap}); + + histos.add("hInteractionRate", "hInteractionRate", kTH1F, {axisIRBinning}); + histos.add("hCentralityVsInteractionRate", "hCentralityVsInteractionRate", kTH2F, {{101, 0.0f, 101.0f}, axisIRBinning}); + + histos.add("hInteractionRateVsOccupancy", "hInteractionRateVsOccupancy", kTH2F, {axisIRBinning, axisOccupancy}); // for QA and test purposes auto hRawCentrality = histos.add("hRawCentrality", "hRawCentrality", kTH1F, {axisRawCentrality}); @@ -308,7 +637,14 @@ struct derivedlambdakzeroanalysis { // histograms versus mass if (analyseK0Short) { + histos.add("h2dNbrOfK0ShortVsCentrality", "h2dNbrOfK0ShortVsCentrality", kTH2F, {axisCentrality, {10, -0.5f, 9.5f}}); histos.add("h3dMassK0Short", "h3dMassK0Short", kTH3F, {axisCentrality, axisPt, axisK0Mass}); + // Non-UPC info + histos.add("h3dMassK0ShortHadronic", "h3dMassK0ShortHadronic", kTH3F, {axisCentrality, axisPt, axisK0Mass}); + // UPC info + histos.add("h3dMassK0ShortSGA", "h3dMassK0ShortSGA", kTH3F, {axisCentrality, axisPt, axisK0Mass}); + histos.add("h3dMassK0ShortSGC", "h3dMassK0ShortSGC", kTH3F, {axisCentrality, axisPt, axisK0Mass}); + histos.add("h3dMassK0ShortDG", "h3dMassK0ShortDG", kTH3F, {axisCentrality, axisPt, axisK0Mass}); if (doTPCQA) { histos.add("K0Short/h3dPosNsigmaTPC", "h3dPosNsigmaTPC", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); histos.add("K0Short/h3dNegNsigmaTPC", "h3dNegNsigmaTPC", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); @@ -324,10 +660,16 @@ struct derivedlambdakzeroanalysis { histos.add("K0Short/h3dNegTPCsignalVsTrackPt", "h3dNegTPCsignalVsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); } if (doTOFQA) { + histos.add("K0Short/h3dPosNsigmaTOF", "h3dPosNsigmaTOF", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); + histos.add("K0Short/h3dNegNsigmaTOF", "h3dNegNsigmaTOF", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); histos.add("K0Short/h3dPosTOFdeltaT", "h3dPosTOFdeltaT", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); histos.add("K0Short/h3dNegTOFdeltaT", "h3dNegTOFdeltaT", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); + histos.add("K0Short/h3dPosNsigmaTOFvsTrackPtot", "h3dPosNsigmaTOFvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); + histos.add("K0Short/h3dNegNsigmaTOFvsTrackPtot", "h3dNegNsigmaTOFvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); histos.add("K0Short/h3dPosTOFdeltaTvsTrackPtot", "h3dPosTOFdeltaTvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); histos.add("K0Short/h3dNegTOFdeltaTvsTrackPtot", "h3dNegTOFdeltaTvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); + histos.add("K0Short/h3dPosNsigmaTOFvsTrackPt", "h3dPosNsigmaTOFvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); + histos.add("K0Short/h3dNegNsigmaTOFvsTrackPt", "h3dNegNsigmaTOFvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); histos.add("K0Short/h3dPosTOFdeltaTvsTrackPt", "h3dPosTOFdeltaTvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); histos.add("K0Short/h3dNegTOFdeltaTvsTrackPt", "h3dNegTOFdeltaTvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); } @@ -345,9 +687,31 @@ struct derivedlambdakzeroanalysis { histos.add("K0Short/h5dPosDetectPropVsCentrality", "h5dPosDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse, axisK0Mass}); histos.add("K0Short/h5dNegDetectPropVsCentrality", "h5dNegDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse, axisK0Mass}); } + if (doDetectPropQA == 3) { + histos.add("K0Short/h3dITSchi2", "h3dMaxITSchi2", kTH3F, {axisCentrality, axisPtCoarse, axisITSchi2}); + histos.add("K0Short/h3dTPCchi2", "h3dMaxTPCchi2", kTH3F, {axisCentrality, axisPtCoarse, axisTPCchi2}); + histos.add("K0Short/h3dTPCFoundOverFindable", "h3dTPCFoundOverFindable", kTH3F, {axisCentrality, axisPtCoarse, axisTPCfoundOverFindable}); + histos.add("K0Short/h3dTPCrowsOverFindable", "h3dTPCrowsOverFindable", kTH3F, {axisCentrality, axisPtCoarse, axisTPCrowsOverFindable}); + histos.add("K0Short/h3dTPCsharedCls", "h3dTPCsharedCls", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsharedClusters}); + histos.add("K0Short/h3dPositiveITSchi2", "h3dPositiveITSchi2", kTH3F, {axisCentrality, axisPtCoarse, axisITSchi2}); + histos.add("K0Short/h3dNegativeITSchi2", "h3dNegativeITSchi2", kTH3F, {axisCentrality, axisPtCoarse, axisITSchi2}); + histos.add("K0Short/h3dPositiveTPCchi2", "h3dPositiveTPCchi2", kTH3F, {axisCentrality, axisPtCoarse, axisTPCchi2}); + histos.add("K0Short/h3dNegativeTPCchi2", "h3dNegativeTPCchi2", kTH3F, {axisCentrality, axisPtCoarse, axisTPCchi2}); + histos.add("K0Short/h3dPositiveITSclusters", "h3dPositiveITSclusters", kTH3F, {axisCentrality, axisPtCoarse, axisITSclus}); + histos.add("K0Short/h3dNegativeITSclusters", "h3dNegativeITSclusters", kTH3F, {axisCentrality, axisPtCoarse, axisITSclus}); + histos.add("K0Short/h3dPositiveTPCcrossedRows", "h3dPositiveTPCcrossedRows", kTH3F, {axisCentrality, axisPtCoarse, axisTPCrows}); + histos.add("K0Short/h3dNegativeTPCcrossedRows", "h3dNegativeTPCcrossedRows", kTH3F, {axisCentrality, axisPtCoarse, axisTPCrows}); + } } if (analyseLambda) { + histos.add("h2dNbrOfLambdaVsCentrality", "h2dNbrOfLambdaVsCentrality", kTH2F, {axisCentrality, {10, -0.5f, 9.5f}}); histos.add("h3dMassLambda", "h3dMassLambda", kTH3F, {axisCentrality, axisPt, axisLambdaMass}); + // Non-UPC info + histos.add("h3dMassLambdaHadronic", "h3dMassLambdaHadronic", kTH3F, {axisCentrality, axisPt, axisLambdaMass}); + // UPC info + histos.add("h3dMassLambdaSGA", "h3dMassLambdaSGA", kTH3F, {axisCentrality, axisPt, axisLambdaMass}); + histos.add("h3dMassLambdaSGC", "h3dMassLambdaSGC", kTH3F, {axisCentrality, axisPt, axisLambdaMass}); + histos.add("h3dMassLambdaDG", "h3dMassLambdaDG", kTH3F, {axisCentrality, axisPt, axisLambdaMass}); if (doTPCQA) { histos.add("Lambda/h3dPosNsigmaTPC", "h3dPosNsigmaTPC", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); histos.add("Lambda/h3dNegNsigmaTPC", "h3dNegNsigmaTPC", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); @@ -363,10 +727,16 @@ struct derivedlambdakzeroanalysis { histos.add("Lambda/h3dNegTPCsignalVsTrackPt", "h3dNegTPCsignalVsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); } if (doTOFQA) { + histos.add("Lambda/h3dPosNsigmaTOF", "h3dPosNsigmaTOF", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); + histos.add("Lambda/h3dNegNsigmaTOF", "h3dNegNsigmaTOF", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); histos.add("Lambda/h3dPosTOFdeltaT", "h3dPosTOFdeltaT", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); histos.add("Lambda/h3dNegTOFdeltaT", "h3dNegTOFdeltaT", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); + histos.add("Lambda/h3dPosNsigmaTOFvsTrackPtot", "h3dPosNsigmaTOFvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); + histos.add("Lambda/h3dNegNsigmaTOFvsTrackPtot", "h3dNegNsigmaTOFvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); histos.add("Lambda/h3dPosTOFdeltaTvsTrackPtot", "h3dPosTOFdeltaTvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); histos.add("Lambda/h3dNegTOFdeltaTvsTrackPtot", "h3dNegTOFdeltaTvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); + histos.add("Lambda/h3dPosNsigmaTOFvsTrackPt", "h3dPosNsigmaTOFvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); + histos.add("Lambda/h3dNegNsigmaTOFvsTrackPt", "h3dNegNsigmaTOFvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); histos.add("Lambda/h3dPosTOFdeltaTvsTrackPt", "h3dPosTOFdeltaTvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); histos.add("Lambda/h3dNegTOFdeltaTvsTrackPt", "h3dNegTOFdeltaTvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); } @@ -384,9 +754,31 @@ struct derivedlambdakzeroanalysis { histos.add("Lambda/h5dPosDetectPropVsCentrality", "h5dPosDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse, axisLambdaMass}); histos.add("Lambda/h5dNegDetectPropVsCentrality", "h5dNegDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse, axisLambdaMass}); } + if (doDetectPropQA == 3) { + histos.add("Lambda/h3dITSchi2", "h3dMaxITSchi2", kTH3F, {axisCentrality, axisPtCoarse, axisITSchi2}); + histos.add("Lambda/h3dTPCchi2", "h3dMaxTPCchi2", kTH3F, {axisCentrality, axisPtCoarse, axisTPCchi2}); + histos.add("Lambda/h3dTPCFoundOverFindable", "h3dTPCFoundOverFindable", kTH3F, {axisCentrality, axisPtCoarse, axisTPCfoundOverFindable}); + histos.add("Lambda/h3dTPCrowsOverFindable", "h3dTPCrowsOverFindable", kTH3F, {axisCentrality, axisPtCoarse, axisTPCrowsOverFindable}); + histos.add("Lambda/h3dTPCsharedCls", "h3dTPCsharedCls", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsharedClusters}); + histos.add("Lambda/h3dPositiveITSchi2", "h3dPositiveITSchi2", kTH3F, {axisCentrality, axisPtCoarse, axisITSchi2}); + histos.add("Lambda/h3dNegativeITSchi2", "h3dNegativeITSchi2", kTH3F, {axisCentrality, axisPtCoarse, axisITSchi2}); + histos.add("Lambda/h3dPositiveTPCchi2", "h3dPositiveTPCchi2", kTH3F, {axisCentrality, axisPtCoarse, axisTPCchi2}); + histos.add("Lambda/h3dNegativeTPCchi2", "h3dNegativeTPCchi2", kTH3F, {axisCentrality, axisPtCoarse, axisTPCchi2}); + histos.add("Lambda/h3dPositiveITSclusters", "h3dPositiveITSclusters", kTH3F, {axisCentrality, axisPtCoarse, axisITSclus}); + histos.add("Lambda/h3dNegativeITSclusters", "h3dNegativeITSclusters", kTH3F, {axisCentrality, axisPtCoarse, axisITSclus}); + histos.add("Lambda/h3dPositiveTPCcrossedRows", "h3dPositiveTPCcrossedRows", kTH3F, {axisCentrality, axisPtCoarse, axisTPCrows}); + histos.add("Lambda/h3dNegativeTPCcrossedRows", "h3dNegativeTPCcrossedRows", kTH3F, {axisCentrality, axisPtCoarse, axisTPCrows}); + } } if (analyseAntiLambda) { + histos.add("h2dNbrOfAntiLambdaVsCentrality", "h2dNbrOfAntiLambdaVsCentrality", kTH2F, {axisCentrality, {10, -0.5f, 9.5f}}); histos.add("h3dMassAntiLambda", "h3dMassAntiLambda", kTH3F, {axisCentrality, axisPt, axisLambdaMass}); + // Non-UPC info + histos.add("h3dMassAntiLambdaHadronic", "h3dMassAntiLambdaHadronic", kTH3F, {axisCentrality, axisPt, axisLambdaMass}); + // UPC info + histos.add("h3dMassAntiLambdaSGA", "h3dMassAntiLambdaSGA", kTH3F, {axisCentrality, axisPt, axisLambdaMass}); + histos.add("h3dMassAntiLambdaSGC", "h3dMassAntiLambdaSGC", kTH3F, {axisCentrality, axisPt, axisLambdaMass}); + histos.add("h3dMassAntiLambdaDG", "h3dMassAntiLambdaDG", kTH3F, {axisCentrality, axisPt, axisLambdaMass}); if (doTPCQA) { histos.add("AntiLambda/h3dPosNsigmaTPC", "h3dPosNsigmaTPC", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); histos.add("AntiLambda/h3dNegNsigmaTPC", "h3dNegNsigmaTPC", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); @@ -402,10 +794,16 @@ struct derivedlambdakzeroanalysis { histos.add("AntiLambda/h3dNegTPCsignalVsTrackPt", "h3dNegTPCsignalVsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); } if (doTOFQA) { + histos.add("AntiLambda/h3dPosNsigmaTOF", "h3dPosNsigmaTOF", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); + histos.add("AntiLambda/h3dNegNsigmaTOF", "h3dNegNsigmaTOF", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); histos.add("AntiLambda/h3dPosTOFdeltaT", "h3dPosTOFdeltaT", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); histos.add("AntiLambda/h3dNegTOFdeltaT", "h3dNegTOFdeltaT", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); + histos.add("AntiLambda/h3dPosNsigmaTOFvsTrackPtot", "h3dPosNsigmaTOFvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); + histos.add("AntiLambda/h3dNegNsigmaTOFvsTrackPtot", "h3dNegNsigmaTOFvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); histos.add("AntiLambda/h3dPosTOFdeltaTvsTrackPtot", "h3dPosTOFdeltaTvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); histos.add("AntiLambda/h3dNegTOFdeltaTvsTrackPtot", "h3dNegTOFdeltaTvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); + histos.add("AntiLambda/h3dPosNsigmaTOFvsTrackPt", "h3dPosNsigmaTOFvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); + histos.add("AntiLambda/h3dNegNsigmaTOFvsTrackPt", "h3dNegNsigmaTOFvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTOF}); histos.add("AntiLambda/h3dPosTOFdeltaTvsTrackPt", "h3dPosTOFdeltaTvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); histos.add("AntiLambda/h3dNegTOFdeltaTvsTrackPt", "h3dNegTOFdeltaTvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); } @@ -423,11 +821,26 @@ struct derivedlambdakzeroanalysis { histos.add("AntiLambda/h5dPosDetectPropVsCentrality", "h5dPosDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse, axisLambdaMass}); histos.add("AntiLambda/h5dNegDetectPropVsCentrality", "h5dNegDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse, axisLambdaMass}); } + if (doDetectPropQA == 3) { + histos.add("AntiLambda/h3dITSchi2", "h3dMaxITSchi2", kTH3F, {axisCentrality, axisPtCoarse, axisITSchi2}); + histos.add("AntiLambda/h3dTPCchi2", "h3dMaxTPCchi2", kTH3F, {axisCentrality, axisPtCoarse, axisTPCchi2}); + histos.add("AntiLambda/h3dTPCFoundOverFindable", "h3dTPCFoundOverFindable", kTH3F, {axisCentrality, axisPtCoarse, axisTPCfoundOverFindable}); + histos.add("AntiLambda/h3dTPCrowsOverFindable", "h3dTPCrowsOverFindable", kTH3F, {axisCentrality, axisPtCoarse, axisTPCrowsOverFindable}); + histos.add("AntiLambda/h3dTPCsharedCls", "h3dTPCsharedCls", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsharedClusters}); + histos.add("AntiLambda/h3dPositiveITSchi2", "h3dPositiveITSchi2", kTH3F, {axisCentrality, axisPtCoarse, axisITSchi2}); + histos.add("AntiLambda/h3dNegativeITSchi2", "h3dNegativeITSchi2", kTH3F, {axisCentrality, axisPtCoarse, axisITSchi2}); + histos.add("AntiLambda/h3dPositiveTPCchi2", "h3dPositiveTPCchi2", kTH3F, {axisCentrality, axisPtCoarse, axisTPCchi2}); + histos.add("AntiLambda/h3dNegativeTPCchi2", "h3dNegativeTPCchi2", kTH3F, {axisCentrality, axisPtCoarse, axisTPCchi2}); + histos.add("AntiLambda/h3dPositiveITSclusters", "h3dPositiveITSclusters", kTH3F, {axisCentrality, axisPtCoarse, axisITSclus}); + histos.add("AntiLambda/h3dNegativeITSclusters", "h3dNegativeITSclusters", kTH3F, {axisCentrality, axisPtCoarse, axisITSclus}); + histos.add("AntiLambda/h3dPositiveTPCcrossedRows", "h3dPositiveTPCcrossedRows", kTH3F, {axisCentrality, axisPtCoarse, axisTPCrows}); + histos.add("AntiLambda/h3dNegativeTPCcrossedRows", "h3dNegativeTPCcrossedRows", kTH3F, {axisCentrality, axisPtCoarse, axisTPCrows}); + } } - if (analyseLambda && calculateFeeddownMatrix && doprocessMonteCarlo) + if (analyseLambda && calculateFeeddownMatrix && (doprocessMonteCarloRun3 || doprocessMonteCarloRun2)) histos.add("h3dLambdaFeeddown", "h3dLambdaFeeddown", kTH3F, {axisCentrality, axisPt, axisPtXi}); - if (analyseAntiLambda && calculateFeeddownMatrix && doprocessMonteCarlo) + if (analyseAntiLambda && calculateFeeddownMatrix && (doprocessMonteCarloRun3 || doprocessMonteCarloRun2)) histos.add("h3dAntiLambdaFeeddown", "h3dAntiLambdaFeeddown", kTH3F, {axisCentrality, axisPt, axisPtXi}); // demo // fast @@ -442,6 +855,7 @@ struct derivedlambdakzeroanalysis { histos.add("K0Short/h4dDCADaughters", "h4dDCADaughters", kTHnF, {axisCentrality, axisPtCoarse, axisK0Mass, axisDCAdau}); histos.add("K0Short/h4dPointingAngle", "h4dPointingAngle", kTHnF, {axisCentrality, axisPtCoarse, axisK0Mass, axisPointingAngle}); histos.add("K0Short/h4dV0Radius", "h4dV0Radius", kTHnF, {axisCentrality, axisPtCoarse, axisK0Mass, axisV0Radius}); + histos.add("K0Short/h4dV0PhiVsEta", "h4dV0PhiVsEta", kTHnF, {axisPtCoarse, axisK0Mass, axisPhi, axisEta}); } if (analyseLambda) { histos.add("Lambda/h4dPosDCAToPV", "h4dPosDCAToPV", kTHnF, {axisCentrality, axisPtCoarse, axisLambdaMass, axisDCAtoPV}); @@ -449,6 +863,7 @@ struct derivedlambdakzeroanalysis { histos.add("Lambda/h4dDCADaughters", "h4dDCADaughters", kTHnF, {axisCentrality, axisPtCoarse, axisLambdaMass, axisDCAdau}); histos.add("Lambda/h4dPointingAngle", "h4dPointingAngle", kTHnF, {axisCentrality, axisPtCoarse, axisLambdaMass, axisPointingAngle}); histos.add("Lambda/h4dV0Radius", "h4dV0Radius", kTHnF, {axisCentrality, axisPtCoarse, axisLambdaMass, axisV0Radius}); + histos.add("Lambda/h4dV0PhiVsEta", "h4dV0PhiVsEta", kTHnF, {axisPtCoarse, axisK0Mass, axisPhi, axisEta}); } if (analyseAntiLambda) { histos.add("AntiLambda/h4dPosDCAToPV", "h4dPosDCAToPV", kTHnF, {axisCentrality, axisPtCoarse, axisLambdaMass, axisDCAtoPV}); @@ -456,6 +871,7 @@ struct derivedlambdakzeroanalysis { histos.add("AntiLambda/h4dDCADaughters", "h4dDCADaughters", kTHnF, {axisCentrality, axisPtCoarse, axisLambdaMass, axisDCAdau}); histos.add("AntiLambda/h4dPointingAngle", "h4dPointingAngle", kTHnF, {axisCentrality, axisPtCoarse, axisLambdaMass, axisPointingAngle}); histos.add("AntiLambda/h4dV0Radius", "h4dV0Radius", kTHnF, {axisCentrality, axisPtCoarse, axisLambdaMass, axisV0Radius}); + histos.add("AntiLambda/h4dV0PhiVsEta", "h4dV0PhiVsEta", kTHnF, {axisPtCoarse, axisK0Mass, axisPhi, axisEta}); } } @@ -502,7 +918,17 @@ struct derivedlambdakzeroanalysis { histos.add("GeneralQA/h2dArmenterosSelected", "h2dArmenterosSelected", kTH2F, {axisAPAlpha, axisAPQt}); // Creation of histograms: MC generated - if (doprocessBinnedGenerated) { + if ((doprocessGeneratedRun3 || doprocessGeneratedRun2)) { + histos.add("hGenEvents", "hGenEvents", kTH2F, {{axisNch}, {2, -0.5f, +1.5f}}); + histos.get(HIST("hGenEvents"))->GetYaxis()->SetBinLabel(1, "All gen. events"); + histos.get(HIST("hGenEvents"))->GetYaxis()->SetBinLabel(2, "Gen. with at least 1 rec. events"); + histos.add("hGenEventCentrality", "hGenEventCentrality", kTH1F, {{101, 0.0f, 101.0f}}); + + histos.add("hCentralityVsNcoll_beforeEvSel", "hCentralityVsNcoll_beforeEvSel", kTH2F, {axisCentrality, {50, -0.5f, 49.5f}}); + histos.add("hCentralityVsNcoll_afterEvSel", "hCentralityVsNcoll_afterEvSel", kTH2F, {axisCentrality, {50, -0.5f, 49.5f}}); + + histos.add("hCentralityVsMultMC", "hCentralityVsMultMC", kTH2F, {{101, 0.0f, 101.0f}, axisNch}); + histos.add("h2dGenK0Short", "h2dGenK0Short", kTH2D, {axisCentrality, axisPt}); histos.add("h2dGenLambda", "h2dGenLambda", kTH2D, {axisCentrality, axisPt}); histos.add("h2dGenAntiLambda", "h2dGenAntiLambda", kTH2D, {axisCentrality, axisPt}); @@ -510,115 +936,190 @@ struct derivedlambdakzeroanalysis { histos.add("h2dGenXiPlus", "h2dGenXiPlus", kTH2D, {axisCentrality, axisPt}); histos.add("h2dGenOmegaMinus", "h2dGenOmegaMinus", kTH2D, {axisCentrality, axisPt}); histos.add("h2dGenOmegaPlus", "h2dGenOmegaPlus", kTH2D, {axisCentrality, axisPt}); + + histos.add("h2dGenK0ShortVsMultMC_RecoedEvt", "h2dGenK0ShortVsMultMC_RecoedEvt", kTH2D, {axisNch, axisPt}); + histos.add("h2dGenLambdaVsMultMC_RecoedEvt", "h2dGenLambdaVsMultMC_RecoedEvt", kTH2D, {axisNch, axisPt}); + histos.add("h2dGenAntiLambdaVsMultMC_RecoedEvt", "h2dGenAntiLambdaVsMultMC_RecoedEvt", kTH2D, {axisNch, axisPt}); + histos.add("h2dGenXiMinusVsMultMC_RecoedEvt", "h2dGenXiMinusVsMultMC_RecoedEvt", kTH2D, {axisNch, axisPt}); + histos.add("h2dGenXiPlusVsMultMC_RecoedEvt", "h2dGenXiPlusVsMultMC_RecoedEvt", kTH2D, {axisNch, axisPt}); + histos.add("h2dGenOmegaMinusVsMultMC_RecoedEvt", "h2dGenOmegaMinusVsMultMC_RecoedEvt", kTH2D, {axisNch, axisPt}); + histos.add("h2dGenOmegaPlusVsMultMC_RecoedEvt", "h2dGenOmegaPlusVsMultMC_RecoedEvt", kTH2D, {axisNch, axisPt}); + + histos.add("h2dGenK0ShortVsMultMC", "h2dGenK0ShortVsMultMC", kTH2D, {axisNch, axisPt}); + histos.add("h2dGenLambdaVsMultMC", "h2dGenLambdaVsMultMC", kTH2D, {axisNch, axisPt}); + histos.add("h2dGenAntiLambdaVsMultMC", "h2dGenAntiLambdaVsMultMC", kTH2D, {axisNch, axisPt}); + histos.add("h2dGenXiMinusVsMultMC", "h2dGenXiMinusVsMultMC", kTH2D, {axisNch, axisPt}); + histos.add("h2dGenXiPlusVsMultMC", "h2dGenXiPlusVsMultMC", kTH2D, {axisNch, axisPt}); + histos.add("h2dGenOmegaMinusVsMultMC", "h2dGenOmegaMinusVsMultMC", kTH2D, {axisNch, axisPt}); + histos.add("h2dGenOmegaPlusVsMultMC", "h2dGenOmegaPlusVsMultMC", kTH2D, {axisNch, axisPt}); + } + if (doprocessBinnedGenerated) { + histos.add("h2dGeneratedK0Short", "h2dGeneratedK0Short", kTH2D, {axisCentrality, axisPt}); + histos.add("h2dGeneratedLambda", "h2dGeneratedLambda", kTH2D, {axisCentrality, axisPt}); + histos.add("h2dGeneratedAntiLambda", "h2dGeneratedAntiLambda", kTH2D, {axisCentrality, axisPt}); + histos.add("h2dGeneratedXiMinus", "h2dGeneratedXiMinus", kTH2D, {axisCentrality, axisPt}); + histos.add("h2dGeneratedXiPlus", "h2dGeneratedXiPlus", kTH2D, {axisCentrality, axisPt}); + histos.add("h2dGeneratedOmegaMinus", "h2dGeneratedOmegaMinus", kTH2D, {axisCentrality, axisPt}); + histos.add("h2dGeneratedOmegaPlus", "h2dGeneratedOmegaPlus", kTH2D, {axisCentrality, axisPt}); } // inspect histogram sizes, please histos.print(); } + // ______________________________________________________ + // Return slicing output + template + auto getGroupedCollisions(TCollisions const& collisions, int globalIndex) + { + if constexpr (run3) { // check if we are in Run 3 + return collisions.sliceBy(perMcCollision, globalIndex); + } else { // we are in Run2 + return collisions.sliceBy(perMcCollisionRun2, globalIndex); + } + } + + template + void initCCDB(TCollision collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + mRunNumber = collision.runNumber(); + + // machine learning initialization if requested + if (mlConfigurations.calculateK0ShortScores || + mlConfigurations.calculateLambdaScores || + mlConfigurations.calculateAntiLambdaScores) { + int64_t timeStampML = collision.timestamp(); + if (mlConfigurations.timestampCCDB.value != -1) + timeStampML = mlConfigurations.timestampCCDB.value; + loadMachines(timeStampML); + } + } + template uint64_t computeReconstructionBitmap(TV0 v0, TCollision collision, float rapidityLambda, float rapidityK0Short, float /*pT*/) // precalculate this information so that a check is one mask operation, not many { uint64_t bitMap = 0; // Base topological variables - if (v0.v0radius() > v0radius) - bitset(bitMap, selRadius); - if (v0.v0radius() < v0radiusMax) - bitset(bitMap, selRadiusMax); - if (TMath::Abs(v0.dcapostopv()) > dcapostopv) - bitset(bitMap, selDCAPosToPV); - if (TMath::Abs(v0.dcanegtopv()) > dcanegtopv) - bitset(bitMap, selDCANegToPV); - if (v0.v0cosPA() > v0cospa) - bitset(bitMap, selCosPA); - if (v0.dcaV0daughters() < dcav0dau) - bitset(bitMap, selDCAV0Dau); + if (v0.v0radius() > v0Selections.v0radius) + BITSET(bitMap, selRadius); + if (v0.v0radius() < v0Selections.v0radiusMax) + BITSET(bitMap, selRadiusMax); + if (std::abs(v0.dcapostopv()) > v0Selections.dcapostopv) + BITSET(bitMap, selDCAPosToPV); + if (std::abs(v0.dcanegtopv()) > v0Selections.dcanegtopv) + BITSET(bitMap, selDCANegToPV); + if (v0.v0cosPA() > v0Selections.v0cospa) + BITSET(bitMap, selCosPA); + if (v0.dcaV0daughters() < v0Selections.dcav0dau) + BITSET(bitMap, selDCAV0Dau); // rapidity - if (TMath::Abs(rapidityLambda) < rapidityCut) - bitset(bitMap, selLambdaRapidity); - if (TMath::Abs(rapidityK0Short) < rapidityCut) - bitset(bitMap, selK0ShortRapidity); + if (std::abs(rapidityLambda) < v0Selections.rapidityCut) + BITSET(bitMap, selLambdaRapidity); + if (std::abs(rapidityK0Short) < v0Selections.rapidityCut) + BITSET(bitMap, selK0ShortRapidity); - auto posTrackExtra = v0.template posTrackExtra_as(); - auto negTrackExtra = v0.template negTrackExtra_as(); + auto posTrackExtra = v0.template posTrackExtra_as(); + auto negTrackExtra = v0.template negTrackExtra_as(); // ITS quality flags - if (posTrackExtra.itsNCls() >= minITSclusters) - bitset(bitMap, selPosGoodITSTrack); - if (negTrackExtra.itsNCls() >= minITSclusters) - bitset(bitMap, selNegGoodITSTrack); + bool posIsFromAfterburner = posTrackExtra.hasITSAfterburner(); + bool negIsFromAfterburner = negTrackExtra.hasITSAfterburner(); + + // check minimum number of ITS clusters + maximum ITS chi2 per clusters + reject or select ITS afterburner tracks if requested + if (posTrackExtra.itsNCls() >= v0Selections.minITSclusters && // check minium ITS clusters + posTrackExtra.itsChi2NCl() < v0Selections.maxITSchi2PerNcls && // check maximum ITS chi2 per clusters + (!v0Selections.rejectPosITSafterburner || !posIsFromAfterburner) && // reject afterburner track or not + (!v0Selections.requirePosITSafterburnerOnly || posIsFromAfterburner)) // keep afterburner track or not + BITSET(bitMap, selPosGoodITSTrack); + if (negTrackExtra.itsNCls() >= v0Selections.minITSclusters && // check minium ITS clusters + negTrackExtra.itsChi2NCl() < v0Selections.maxITSchi2PerNcls && // check maximum ITS chi2 per clusters + (!v0Selections.rejectNegITSafterburner || !negIsFromAfterburner) && // reject afterburner track or not + (!v0Selections.requireNegITSafterburnerOnly || negIsFromAfterburner)) // select only afterburner track or not + BITSET(bitMap, selNegGoodITSTrack); // TPC quality flags - if (posTrackExtra.tpcCrossedRows() >= minTPCrows) - bitset(bitMap, selPosGoodTPCTrack); - if (negTrackExtra.tpcCrossedRows() >= minTPCrows) - bitset(bitMap, selNegGoodTPCTrack); + if (posTrackExtra.tpcCrossedRows() >= v0Selections.minTPCrows && // check minimum TPC crossed rows + posTrackExtra.tpcChi2NCl() < v0Selections.maxTPCchi2PerNcls && // check maximum TPC chi2 per clusters + posTrackExtra.tpcCrossedRowsOverFindableCls() >= v0Selections.minTPCrowsOverFindableClusters && // check minimum fraction of TPC rows over findable + posTrackExtra.tpcFoundOverFindableCls() >= v0Selections.minTPCfoundOverFindableClusters && // check minimum fraction of found over findable TPC clusters + posTrackExtra.tpcFractionSharedCls() < v0Selections.maxFractionTPCSharedClusters) // check the maximum fraction of allowed shared TPC clusters + BITSET(bitMap, selPosGoodTPCTrack); + if (negTrackExtra.tpcCrossedRows() >= v0Selections.minTPCrows && // check minimum TPC crossed rows + negTrackExtra.tpcChi2NCl() < v0Selections.maxTPCchi2PerNcls && // check maximum TPC chi2 per clusters + negTrackExtra.tpcCrossedRowsOverFindableCls() >= v0Selections.minTPCrowsOverFindableClusters && // check minimum fraction of TPC rows over findable + negTrackExtra.tpcFoundOverFindableCls() >= v0Selections.minTPCfoundOverFindableClusters && // check minimum fraction of found over findable TPC clusters + negTrackExtra.tpcFractionSharedCls() < v0Selections.maxFractionTPCSharedClusters) // check the maximum fraction of allowed shared TPC clusters + BITSET(bitMap, selNegGoodTPCTrack); // TPC PID - if (fabs(posTrackExtra.tpcNSigmaPi()) < TpcPidNsigmaCut) - bitset(bitMap, selTPCPIDPositivePion); - if (fabs(posTrackExtra.tpcNSigmaPr()) < TpcPidNsigmaCut) - bitset(bitMap, selTPCPIDPositiveProton); - if (fabs(negTrackExtra.tpcNSigmaPi()) < TpcPidNsigmaCut) - bitset(bitMap, selTPCPIDNegativePion); - if (fabs(negTrackExtra.tpcNSigmaPr()) < TpcPidNsigmaCut) - bitset(bitMap, selTPCPIDNegativeProton); + if (std::fabs(posTrackExtra.tpcNSigmaPi()) < v0Selections.tpcPidNsigmaCut) + BITSET(bitMap, selTPCPIDPositivePion); + if (std::fabs(posTrackExtra.tpcNSigmaPr()) < v0Selections.tpcPidNsigmaCut) + BITSET(bitMap, selTPCPIDPositiveProton); + if (std::fabs(negTrackExtra.tpcNSigmaPi()) < v0Selections.tpcPidNsigmaCut) + BITSET(bitMap, selTPCPIDNegativePion); + if (std::fabs(negTrackExtra.tpcNSigmaPr()) < v0Selections.tpcPidNsigmaCut) + BITSET(bitMap, selTPCPIDNegativeProton); // TOF PID in DeltaT // Positive track - if (fabs(v0.posTOFDeltaTLaPr()) < maxDeltaTimeProton) - bitset(bitMap, selTOFDeltaTPositiveProtonLambda); - if (fabs(v0.posTOFDeltaTLaPi()) < maxDeltaTimePion) - bitset(bitMap, selTOFDeltaTPositivePionLambda); - if (fabs(v0.posTOFDeltaTK0Pi()) < maxDeltaTimePion) - bitset(bitMap, selTOFDeltaTPositivePionK0Short); + if (std::fabs(v0.posTOFDeltaTLaPr()) < v0Selections.maxDeltaTimeProton) + BITSET(bitMap, selTOFDeltaTPositiveProtonLambda); + if (std::fabs(v0.posTOFDeltaTLaPi()) < v0Selections.maxDeltaTimePion) + BITSET(bitMap, selTOFDeltaTPositivePionLambda); + if (std::fabs(v0.posTOFDeltaTK0Pi()) < v0Selections.maxDeltaTimePion) + BITSET(bitMap, selTOFDeltaTPositivePionK0Short); // Negative track - if (fabs(v0.negTOFDeltaTLaPr()) < maxDeltaTimeProton) - bitset(bitMap, selTOFDeltaTNegativeProtonLambda); - if (fabs(v0.negTOFDeltaTLaPi()) < maxDeltaTimePion) - bitset(bitMap, selTOFDeltaTNegativePionLambda); - if (fabs(v0.negTOFDeltaTK0Pi()) < maxDeltaTimePion) - bitset(bitMap, selTOFDeltaTNegativePionK0Short); + if (std::fabs(v0.negTOFDeltaTLaPr()) < v0Selections.maxDeltaTimeProton) + BITSET(bitMap, selTOFDeltaTNegativeProtonLambda); + if (std::fabs(v0.negTOFDeltaTLaPi()) < v0Selections.maxDeltaTimePion) + BITSET(bitMap, selTOFDeltaTNegativePionLambda); + if (std::fabs(v0.negTOFDeltaTK0Pi()) < v0Selections.maxDeltaTimePion) + BITSET(bitMap, selTOFDeltaTNegativePionK0Short); // TOF PID in NSigma // Positive track - if (fabs(v0.tofNSigmaLaPr()) < TofPidNsigmaCutLaPr) - bitset(bitMap, selTOFNSigmaPositiveProtonLambda); - if (fabs(v0.tofNSigmaALaPi()) < TofPidNsigmaCutLaPi) - bitset(bitMap, selTOFNSigmaPositivePionLambda); - if (fabs(v0.tofNSigmaK0PiPlus()) < TofPidNsigmaCutK0Pi) - bitset(bitMap, selTOFNSigmaPositivePionK0Short); + if (std::fabs(v0.tofNSigmaLaPr()) < v0Selections.tofPidNsigmaCutLaPr) + BITSET(bitMap, selTOFNSigmaPositiveProtonLambda); + if (std::fabs(v0.tofNSigmaALaPi()) < v0Selections.tofPidNsigmaCutLaPi) + BITSET(bitMap, selTOFNSigmaPositivePionLambda); + if (std::fabs(v0.tofNSigmaK0PiPlus()) < v0Selections.tofPidNsigmaCutK0Pi) + BITSET(bitMap, selTOFNSigmaPositivePionK0Short); // Negative track - if (fabs(v0.tofNSigmaALaPr()) < TofPidNsigmaCutLaPr) - bitset(bitMap, selTOFNSigmaNegativeProtonLambda); - if (fabs(v0.tofNSigmaLaPi()) < TofPidNsigmaCutLaPi) - bitset(bitMap, selTOFNSigmaNegativePionLambda); - if (fabs(v0.tofNSigmaK0PiMinus()) < TofPidNsigmaCutK0Pi) - bitset(bitMap, selTOFNSigmaNegativePionK0Short); + if (std::fabs(v0.tofNSigmaALaPr()) < v0Selections.tofPidNsigmaCutLaPr) + BITSET(bitMap, selTOFNSigmaNegativeProtonLambda); + if (std::fabs(v0.tofNSigmaLaPi()) < v0Selections.tofPidNsigmaCutLaPi) + BITSET(bitMap, selTOFNSigmaNegativePionLambda); + if (std::fabs(v0.tofNSigmaK0PiMinus()) < v0Selections.tofPidNsigmaCutK0Pi) + BITSET(bitMap, selTOFNSigmaNegativePionK0Short); // ITS only tag if (posTrackExtra.tpcCrossedRows() < 1) - bitset(bitMap, selPosItsOnly); + BITSET(bitMap, selPosItsOnly); if (negTrackExtra.tpcCrossedRows() < 1) - bitset(bitMap, selNegItsOnly); + BITSET(bitMap, selNegItsOnly); // TPC only tag if (posTrackExtra.detectorMap() != o2::aod::track::TPC) - bitset(bitMap, selPosNotTPCOnly); + BITSET(bitMap, selPosNotTPCOnly); if (negTrackExtra.detectorMap() != o2::aod::track::TPC) - bitset(bitMap, selNegNotTPCOnly); + BITSET(bitMap, selNegNotTPCOnly); // proper lifetime if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < lifetimecut->get("lifetimecutLambda")) - bitset(bitMap, selLambdaCTau); + BITSET(bitMap, selLambdaCTau); if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < lifetimecut->get("lifetimecutK0S")) - bitset(bitMap, selK0ShortCTau); + BITSET(bitMap, selK0ShortCTau); // armenteros - if (v0.qtarm() * armPodCut > TMath::Abs(v0.alpha()) || armPodCut < 1e-4) - bitset(bitMap, selK0ShortArmenteros); + if (v0.qtarm() * v0Selections.armPodCut > std::abs(v0.alpha()) || v0Selections.armPodCut < 1e-4) + BITSET(bitMap, selK0ShortArmenteros); return bitMap; } @@ -628,22 +1129,25 @@ struct derivedlambdakzeroanalysis { // precalculate this information so that a check is one mask operation, not many { uint64_t bitMap = 0; - // check for specific particle species + bool isPositiveProton = v0.pdgCodePositive() == 2212; + bool isPositivePion = v0.pdgCodePositive() == 211 || (doTreatPiToMuon && v0.pdgCodePositive() == -13); + bool isNegativeProton = v0.pdgCodeNegative() == -2212; + bool isNegativePion = v0.pdgCodeNegative() == -211 || (doTreatPiToMuon && v0.pdgCodeNegative() == 13); - if (v0.pdgCode() == 310 && v0.pdgCodePositive() == 211 && v0.pdgCodeNegative() == -211) { - bitset(bitMap, selConsiderK0Short); + if (v0.pdgCode() == 310 && isPositivePion && isNegativePion) { + BITSET(bitMap, selConsiderK0Short); if (v0.isPhysicalPrimary()) - bitset(bitMap, selPhysPrimK0Short); + BITSET(bitMap, selPhysPrimK0Short); } - if (v0.pdgCode() == 3122 && v0.pdgCodePositive() == 2212 && v0.pdgCodeNegative() == -211) { - bitset(bitMap, selConsiderLambda); + if (v0.pdgCode() == 3122 && isPositiveProton && isNegativePion) { + BITSET(bitMap, selConsiderLambda); if (v0.isPhysicalPrimary()) - bitset(bitMap, selPhysPrimLambda); + BITSET(bitMap, selPhysPrimLambda); } - if (v0.pdgCode() == -3122 && v0.pdgCodePositive() == 211 && v0.pdgCodeNegative() == -2212) { - bitset(bitMap, selConsiderAntiLambda); + if (v0.pdgCode() == -3122 && isPositivePion && isNegativeProton) { + BITSET(bitMap, selConsiderAntiLambda); if (v0.isPhysicalPrimary()) - bitset(bitMap, selPhysPrimAntiLambda); + BITSET(bitMap, selPhysPrimAntiLambda); } return bitMap; } @@ -653,10 +1157,10 @@ struct derivedlambdakzeroanalysis { return (bitmap & mask) == mask; } - uint computeITSclusBitmap(uint8_t itsClusMap) + int computeITSclusBitmap(uint8_t itsClusMap, bool fromAfterburner) // Focus on the 12 dominant ITS cluster configurations { - uint bitMap = 0; + int bitMap = 0; if (verifyMask(itsClusMap, ((uint8_t(1) << 0) | (uint8_t(1) << 1) | (uint8_t(1) << 2) | (uint8_t(1) << 3) | (uint8_t(1) << 4) | (uint8_t(1) << 5) | (uint8_t(1) << 6)))) { // ITS : IB OB @@ -678,16 +1182,22 @@ struct derivedlambdakzeroanalysis { // ITS : L0 L1 L2 L3 L4 L5 L6 // ITS : x x x x bitMap = 9; + if (fromAfterburner) + bitMap = -3; } else if (verifyMask(itsClusMap, ((uint8_t(1) << 4) | (uint8_t(1) << 5) | (uint8_t(1) << 6)))) { // ITS : IB OB // ITS : L0 L1 L2 L3 L4 L5 L6 // ITS : x x x bitMap = 8; + if (fromAfterburner) + bitMap = -2; } else if (verifyMask(itsClusMap, ((uint8_t(1) << 5) | (uint8_t(1) << 6)))) { // ITS : IB OB // ITS : L0 L1 L2 L3 L4 L5 L6 // ITS : x x bitMap = 7; + if (fromAfterburner) + bitMap = -1; } else if (verifyMask(itsClusMap, ((uint8_t(1) << 0) | (uint8_t(1) << 1) | (uint8_t(1) << 2) | (uint8_t(1) << 3) | (uint8_t(1) << 4) | (uint8_t(1) << 5)))) { // ITS : IB OB // ITS : L0 L1 L2 L3 L4 L5 L6 @@ -728,6 +1238,7 @@ struct derivedlambdakzeroanalysis { uint computeDetBitmap(uint8_t detMap) // Focus on the 4 dominant track configurations : + // Others // ITS-TPC // ITS-TPC-TRD // ITS-TPC-TOF @@ -737,32 +1248,133 @@ struct derivedlambdakzeroanalysis { if (verifyMask(detMap, (o2::aod::track::ITS | o2::aod::track::TPC | o2::aod::track::TRD | o2::aod::track::TOF))) { // ITS-TPC-TRD-TOF - bitMap = 3; + bitMap = 4; } else if (verifyMask(detMap, (o2::aod::track::ITS | o2::aod::track::TPC | o2::aod::track::TOF))) { // ITS-TPC-TOF - bitMap = 2; + bitMap = 3; } else if (verifyMask(detMap, (o2::aod::track::ITS | o2::aod::track::TPC | o2::aod::track::TRD))) { // ITS-TPC-TRD - bitMap = 1; + bitMap = 2; } else if (verifyMask(detMap, (o2::aod::track::ITS | o2::aod::track::TPC))) { // ITS-TPC - bitMap = 0; + bitMap = 1; } return bitMap; } + // function to load models for ML-based classifiers + void loadMachines(int64_t timeStampML) + { + if (mlConfigurations.loadCustomModelsFromCCDB) { + ccdbApi.init(ccdbConfigurations.ccdbUrl); + LOG(info) << "Fetching models for timestamp: " << timeStampML; + + if (mlConfigurations.calculateLambdaScores) { + bool retrieveSuccessLambda = ccdbApi.retrieveBlob(mlConfigurations.customModelPathCCDB, ".", metadata, timeStampML, false, mlConfigurations.localModelPathLambda.value); + if (retrieveSuccessLambda) { + mlCustomModelLambda.initModel(mlConfigurations.localModelPathLambda.value, mlConfigurations.enableOptimizations.value); + } else { + LOG(fatal) << "Error encountered while fetching/loading the Lambda model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; + } + } + + if (mlConfigurations.calculateAntiLambdaScores) { + bool retrieveSuccessAntiLambda = ccdbApi.retrieveBlob(mlConfigurations.customModelPathCCDB, ".", metadata, timeStampML, false, mlConfigurations.localModelPathAntiLambda.value); + if (retrieveSuccessAntiLambda) { + mlCustomModelAntiLambda.initModel(mlConfigurations.localModelPathAntiLambda.value, mlConfigurations.enableOptimizations.value); + } else { + LOG(fatal) << "Error encountered while fetching/loading the AntiLambda model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; + } + } + + if (mlConfigurations.calculateK0ShortScores) { + bool retrieveSuccessKZeroShort = ccdbApi.retrieveBlob(mlConfigurations.customModelPathCCDB, ".", metadata, timeStampML, false, mlConfigurations.localModelPathK0Short.value); + if (retrieveSuccessKZeroShort) { + mlCustomModelK0Short.initModel(mlConfigurations.localModelPathK0Short.value, mlConfigurations.enableOptimizations.value); + } else { + LOG(fatal) << "Error encountered while fetching/loading the K0Short model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; + } + } + } else { + if (mlConfigurations.calculateLambdaScores) + mlCustomModelLambda.initModel(mlConfigurations.localModelPathLambda.value, mlConfigurations.enableOptimizations.value); + if (mlConfigurations.calculateAntiLambdaScores) + mlCustomModelAntiLambda.initModel(mlConfigurations.localModelPathAntiLambda.value, mlConfigurations.enableOptimizations.value); + if (mlConfigurations.calculateK0ShortScores) + mlCustomModelK0Short.initModel(mlConfigurations.localModelPathK0Short.value, mlConfigurations.enableOptimizations.value); + } + LOG(info) << "ML Models loaded."; + } + template - void analyseCandidate(TV0 v0, float pt, float centrality, uint64_t selMap) + void analyseCandidate(TV0 v0, float pt, float centrality, uint64_t selMap, uint8_t gapSide, int& nK0Shorts, int& nLambdas, int& nAntiLambdas) // precalculate this information so that a check is one mask operation, not many { - auto posTrackExtra = v0.template posTrackExtra_as(); - auto negTrackExtra = v0.template negTrackExtra_as(); + bool passK0ShortSelections = false; + bool passLambdaSelections = false; + bool passAntiLambdaSelections = false; + + // machine learning is on, go for calculation of thresholds + // FIXME THIS NEEDS ADJUSTING + std::vector inputFeatures{pt, 0.0f, 0.0f, v0.v0radius(), v0.v0cosPA(), v0.dcaV0daughters(), v0.dcapostopv(), v0.dcanegtopv()}; + + if (mlConfigurations.useK0ShortScores) { + float k0shortScore = -1; + if (mlConfigurations.calculateK0ShortScores) { + // evaluate machine-learning scores + float* k0shortProbability = mlCustomModelK0Short.evalModel(inputFeatures); + k0shortScore = k0shortProbability[1]; + } else { + k0shortScore = v0.k0ShortBDTScore(); + } + if (k0shortScore > mlConfigurations.thresholdK0Short.value) { + passK0ShortSelections = true; + } + } else { + passK0ShortSelections = verifyMask(selMap, maskSelectionK0Short); + } + if (mlConfigurations.useLambdaScores) { + float lambdaScore = -1; + if (mlConfigurations.calculateLambdaScores) { + // evaluate machine-learning scores + float* lambdaProbability = mlCustomModelLambda.evalModel(inputFeatures); + lambdaScore = lambdaProbability[1]; + } else { + lambdaScore = v0.lambdaBDTScore(); + } + if (lambdaScore > mlConfigurations.thresholdK0Short.value) { + passLambdaSelections = true; + } + } else { + passLambdaSelections = verifyMask(selMap, maskSelectionLambda); + } + if (mlConfigurations.useLambdaScores) { + float antiLambdaScore = -1; + if (mlConfigurations.calculateAntiLambdaScores) { + // evaluate machine-learning scores + float* antilambdaProbability = mlCustomModelAntiLambda.evalModel(inputFeatures); + antiLambdaScore = antilambdaProbability[1]; + } else { + antiLambdaScore = v0.antiLambdaBDTScore(); + } + if (antiLambdaScore > mlConfigurations.thresholdK0Short.value) { + passAntiLambdaSelections = true; + } + } else { + passAntiLambdaSelections = verifyMask(selMap, maskSelectionAntiLambda); + } + + auto posTrackExtra = v0.template posTrackExtra_as(); + auto negTrackExtra = v0.template negTrackExtra_as(); + + bool posIsFromAfterburner = posTrackExtra.itsChi2PerNcl() < 0; + bool negIsFromAfterburner = negTrackExtra.itsChi2PerNcl() < 0; uint posDetMap = computeDetBitmap(posTrackExtra.detectorMap()); - uint posITSclusMap = computeITSclusBitmap(posTrackExtra.itsClusterMap()); + int posITSclusMap = computeITSclusBitmap(posTrackExtra.itsClusterMap(), posIsFromAfterburner); uint negDetMap = computeDetBitmap(negTrackExtra.detectorMap()); - uint negITSclusMap = computeITSclusBitmap(negTrackExtra.itsClusterMap()); + int negITSclusMap = computeITSclusBitmap(negTrackExtra.itsClusterMap(), negIsFromAfterburner); // __________________________________________ // fill with no selection if plain QA requested @@ -770,7 +1382,7 @@ struct derivedlambdakzeroanalysis { histos.fill(HIST("hPosDCAToPV"), v0.dcapostopv()); histos.fill(HIST("hNegDCAToPV"), v0.dcanegtopv()); histos.fill(HIST("hDCADaughters"), v0.dcaV0daughters()); - histos.fill(HIST("hPointingAngle"), TMath::ACos(v0.v0cosPA())); + histos.fill(HIST("hPointingAngle"), std::acos(v0.v0cosPA())); histos.fill(HIST("hV0Radius"), v0.v0radius()); histos.fill(HIST("h2dPositiveITSvsTPCpts"), posTrackExtra.tpcCrossedRows(), posTrackExtra.itsNCls()); histos.fill(HIST("h2dNegativeITSvsTPCpts"), negTrackExtra.tpcCrossedRows(), negTrackExtra.itsNCls()); @@ -778,15 +1390,23 @@ struct derivedlambdakzeroanalysis { // __________________________________________ // main analysis - if (verifyMask(selMap, maskSelectionK0Short) && analyseK0Short) { + if (passK0ShortSelections && analyseK0Short) { histos.fill(HIST("GeneralQA/h2dArmenterosSelected"), v0.alpha(), v0.qtarm()); // cross-check histos.fill(HIST("h3dMassK0Short"), centrality, pt, v0.mK0Short()); + if (gapSide == 0) + histos.fill(HIST("h3dMassK0ShortSGA"), centrality, pt, v0.mK0Short()); + else if (gapSide == 1) + histos.fill(HIST("h3dMassK0ShortSGC"), centrality, pt, v0.mK0Short()); + else if (gapSide == 2) + histos.fill(HIST("h3dMassK0ShortDG"), centrality, pt, v0.mK0Short()); + else + histos.fill(HIST("h3dMassK0ShortHadronic"), centrality, pt, v0.mK0Short()); histos.fill(HIST("hMassK0Short"), v0.mK0Short()); if (doPlainTopoQA) { histos.fill(HIST("K0Short/hPosDCAToPV"), v0.dcapostopv()); histos.fill(HIST("K0Short/hNegDCAToPV"), v0.dcanegtopv()); histos.fill(HIST("K0Short/hDCADaughters"), v0.dcaV0daughters()); - histos.fill(HIST("K0Short/hPointingAngle"), TMath::ACos(v0.v0cosPA())); + histos.fill(HIST("K0Short/hPointingAngle"), std::acos(v0.v0cosPA())); histos.fill(HIST("K0Short/hV0Radius"), v0.v0radius()); histos.fill(HIST("K0Short/h2dPositiveITSvsTPCpts"), posTrackExtra.tpcCrossedRows(), posTrackExtra.itsNCls()); histos.fill(HIST("K0Short/h2dNegativeITSvsTPCpts"), negTrackExtra.tpcCrossedRows(), negTrackExtra.itsNCls()); @@ -801,36 +1421,66 @@ struct derivedlambdakzeroanalysis { histos.fill(HIST("K0Short/h5dPosDetectPropVsCentrality"), centrality, posTrackExtra.detectorMap(), posTrackExtra.itsClusterMap(), pt, v0.mK0Short()); histos.fill(HIST("K0Short/h5dNegDetectPropVsCentrality"), centrality, negTrackExtra.detectorMap(), negTrackExtra.itsClusterMap(), pt, v0.mK0Short()); } + if (doDetectPropQA == 3) { + histos.fill(HIST("K0Short/h3dITSchi2"), centrality, pt, std::max(posTrackExtra.itsChi2NCl(), negTrackExtra.itsChi2NCl())); + histos.fill(HIST("K0Short/h3dTPCchi2"), centrality, pt, std::max(posTrackExtra.tpcChi2NCl(), negTrackExtra.tpcChi2NCl())); + histos.fill(HIST("K0Short/h3dTPCFoundOverFindable"), centrality, pt, std::min(posTrackExtra.tpcFoundOverFindableCls(), negTrackExtra.tpcFoundOverFindableCls())); + histos.fill(HIST("K0Short/h3dTPCrowsOverFindable"), centrality, pt, std::min(posTrackExtra.tpcCrossedRowsOverFindableCls(), negTrackExtra.tpcCrossedRowsOverFindableCls())); + histos.fill(HIST("K0Short/h3dTPCsharedCls"), centrality, pt, std::max(posTrackExtra.tpcFractionSharedCls(), negTrackExtra.tpcFractionSharedCls())); + histos.fill(HIST("K0Short/h3dPositiveITSchi2"), centrality, pt, posTrackExtra.itsChi2NCl()); + histos.fill(HIST("K0Short/h3dNegativeITSchi2"), centrality, pt, negTrackExtra.itsChi2NCl()); + histos.fill(HIST("K0Short/h3dPositiveTPCchi2"), centrality, pt, posTrackExtra.tpcChi2NCl()); + histos.fill(HIST("K0Short/h3dNegativeTPCchi2"), centrality, pt, negTrackExtra.tpcChi2NCl()); + histos.fill(HIST("K0Short/h3dPositiveITSclusters"), centrality, pt, posTrackExtra.itsNCls()); + histos.fill(HIST("K0Short/h3dNegativeITSclusters"), centrality, pt, negTrackExtra.itsNCls()); + histos.fill(HIST("K0Short/h3dPositiveTPCcrossedRows"), centrality, pt, posTrackExtra.tpcCrossedRows()); + histos.fill(HIST("K0Short/h3dNegativeTPCcrossedRows"), centrality, pt, negTrackExtra.tpcCrossedRows()); + } if (doTPCQA) { histos.fill(HIST("K0Short/h3dPosNsigmaTPC"), centrality, pt, posTrackExtra.tpcNSigmaPi()); histos.fill(HIST("K0Short/h3dNegNsigmaTPC"), centrality, pt, negTrackExtra.tpcNSigmaPi()); histos.fill(HIST("K0Short/h3dPosTPCsignal"), centrality, pt, posTrackExtra.tpcSignal()); histos.fill(HIST("K0Short/h3dNegTPCsignal"), centrality, pt, negTrackExtra.tpcSignal()); - histos.fill(HIST("K0Short/h3dPosNsigmaTPCvsTrackPtot"), centrality, v0.positivept() * TMath::CosH(v0.positiveeta()), posTrackExtra.tpcNSigmaPi()); - histos.fill(HIST("K0Short/h3dNegNsigmaTPCvsTrackPtot"), centrality, v0.negativept() * TMath::CosH(v0.negativeeta()), negTrackExtra.tpcNSigmaPi()); - histos.fill(HIST("K0Short/h3dPosTPCsignalVsTrackPtot"), centrality, v0.positivept() * TMath::CosH(v0.positiveeta()), posTrackExtra.tpcSignal()); - histos.fill(HIST("K0Short/h3dNegTPCsignalVsTrackPtot"), centrality, v0.negativept() * TMath::CosH(v0.negativeeta()), negTrackExtra.tpcSignal()); + histos.fill(HIST("K0Short/h3dPosNsigmaTPCvsTrackPtot"), centrality, v0.pfracpos() * v0.p(), posTrackExtra.tpcNSigmaPi()); + histos.fill(HIST("K0Short/h3dNegNsigmaTPCvsTrackPtot"), centrality, v0.pfracneg() * v0.p(), negTrackExtra.tpcNSigmaPi()); + histos.fill(HIST("K0Short/h3dPosTPCsignalVsTrackPtot"), centrality, v0.pfracpos() * v0.p(), posTrackExtra.tpcSignal()); + histos.fill(HIST("K0Short/h3dNegTPCsignalVsTrackPtot"), centrality, v0.pfracneg() * v0.p(), negTrackExtra.tpcSignal()); histos.fill(HIST("K0Short/h3dPosNsigmaTPCvsTrackPt"), centrality, v0.positivept(), posTrackExtra.tpcNSigmaPi()); histos.fill(HIST("K0Short/h3dNegNsigmaTPCvsTrackPt"), centrality, v0.negativept(), negTrackExtra.tpcNSigmaPi()); histos.fill(HIST("K0Short/h3dPosTPCsignalVsTrackPt"), centrality, v0.positivept(), posTrackExtra.tpcSignal()); histos.fill(HIST("K0Short/h3dNegTPCsignalVsTrackPt"), centrality, v0.negativept(), negTrackExtra.tpcSignal()); } if (doTOFQA) { + histos.fill(HIST("K0Short/h3dPosNsigmaTOF"), centrality, pt, v0.tofNSigmaK0PiPlus()); + histos.fill(HIST("K0Short/h3dNegNsigmaTOF"), centrality, pt, v0.tofNSigmaK0PiMinus()); histos.fill(HIST("K0Short/h3dPosTOFdeltaT"), centrality, pt, v0.posTOFDeltaTK0Pi()); histos.fill(HIST("K0Short/h3dNegTOFdeltaT"), centrality, pt, v0.negTOFDeltaTK0Pi()); - histos.fill(HIST("K0Short/h3dPosTOFdeltaTvsTrackPtot"), centrality, v0.positivept() * TMath::CosH(v0.positiveeta()), v0.posTOFDeltaTK0Pi()); - histos.fill(HIST("K0Short/h3dNegTOFdeltaTvsTrackPtot"), centrality, v0.negativept() * TMath::CosH(v0.negativeeta()), v0.negTOFDeltaTK0Pi()); + histos.fill(HIST("K0Short/h3dPosNsigmaTOFvsTrackPtot"), centrality, v0.pfracpos() * v0.p(), v0.tofNSigmaK0PiPlus()); + histos.fill(HIST("K0Short/h3dNegNsigmaTOFvsTrackPtot"), centrality, v0.pfracneg() * v0.p(), v0.tofNSigmaK0PiMinus()); + histos.fill(HIST("K0Short/h3dPosTOFdeltaTvsTrackPtot"), centrality, v0.pfracpos() * v0.p(), v0.posTOFDeltaTK0Pi()); + histos.fill(HIST("K0Short/h3dNegTOFdeltaTvsTrackPtot"), centrality, v0.pfracneg() * v0.p(), v0.negTOFDeltaTK0Pi()); + histos.fill(HIST("K0Short/h3dPosNsigmaTOFvsTrackPt"), centrality, v0.positivept(), v0.tofNSigmaK0PiPlus()); + histos.fill(HIST("K0Short/h3dNegNsigmaTOFvsTrackPt"), centrality, v0.negativept(), v0.tofNSigmaK0PiMinus()); histos.fill(HIST("K0Short/h3dPosTOFdeltaTvsTrackPt"), centrality, v0.positivept(), v0.posTOFDeltaTK0Pi()); histos.fill(HIST("K0Short/h3dNegTOFdeltaTvsTrackPt"), centrality, v0.negativept(), v0.negTOFDeltaTK0Pi()); } + nK0Shorts++; } - if (verifyMask(selMap, maskSelectionLambda) && analyseLambda) { + if (passLambdaSelections && analyseLambda) { histos.fill(HIST("h3dMassLambda"), centrality, pt, v0.mLambda()); + if (gapSide == 0) + histos.fill(HIST("h3dMassLambdaSGA"), centrality, pt, v0.mLambda()); + else if (gapSide == 1) + histos.fill(HIST("h3dMassLambdaSGC"), centrality, pt, v0.mLambda()); + else if (gapSide == 2) + histos.fill(HIST("h3dMassLambdaDG"), centrality, pt, v0.mLambda()); + else + histos.fill(HIST("h3dMassLambdaHadronic"), centrality, pt, v0.mLambda()); if (doPlainTopoQA) { histos.fill(HIST("Lambda/hPosDCAToPV"), v0.dcapostopv()); histos.fill(HIST("Lambda/hNegDCAToPV"), v0.dcanegtopv()); histos.fill(HIST("Lambda/hDCADaughters"), v0.dcaV0daughters()); - histos.fill(HIST("Lambda/hPointingAngle"), TMath::ACos(v0.v0cosPA())); + histos.fill(HIST("Lambda/hPointingAngle"), std::acos(v0.v0cosPA())); histos.fill(HIST("Lambda/hV0Radius"), v0.v0radius()); histos.fill(HIST("Lambda/h2dPositiveITSvsTPCpts"), posTrackExtra.tpcCrossedRows(), posTrackExtra.itsNCls()); histos.fill(HIST("Lambda/h2dNegativeITSvsTPCpts"), negTrackExtra.tpcCrossedRows(), negTrackExtra.itsNCls()); @@ -845,36 +1495,66 @@ struct derivedlambdakzeroanalysis { histos.fill(HIST("Lambda/h5dPosDetectPropVsCentrality"), centrality, posTrackExtra.detectorMap(), posTrackExtra.itsClusterMap(), pt, v0.mLambda()); histos.fill(HIST("Lambda/h5dNegDetectPropVsCentrality"), centrality, negTrackExtra.detectorMap(), negTrackExtra.itsClusterMap(), pt, v0.mLambda()); } + if (doDetectPropQA == 3) { + histos.fill(HIST("Lambda/h3dITSchi2"), centrality, pt, std::max(posTrackExtra.itsChi2NCl(), negTrackExtra.itsChi2NCl())); + histos.fill(HIST("Lambda/h3dTPCchi2"), centrality, pt, std::max(posTrackExtra.tpcChi2NCl(), negTrackExtra.tpcChi2NCl())); + histos.fill(HIST("Lambda/h3dTPCFoundOverFindable"), centrality, pt, std::min(posTrackExtra.tpcFoundOverFindableCls(), negTrackExtra.tpcFoundOverFindableCls())); + histos.fill(HIST("Lambda/h3dTPCrowsOverFindable"), centrality, pt, std::min(posTrackExtra.tpcCrossedRowsOverFindableCls(), negTrackExtra.tpcCrossedRowsOverFindableCls())); + histos.fill(HIST("Lambda/h3dTPCsharedCls"), centrality, pt, std::max(posTrackExtra.tpcFractionSharedCls(), negTrackExtra.tpcFractionSharedCls())); + histos.fill(HIST("Lambda/h3dPositiveITSchi2"), centrality, pt, posTrackExtra.itsChi2NCl()); + histos.fill(HIST("Lambda/h3dNegativeITSchi2"), centrality, pt, negTrackExtra.itsChi2NCl()); + histos.fill(HIST("Lambda/h3dPositiveTPCchi2"), centrality, pt, posTrackExtra.tpcChi2NCl()); + histos.fill(HIST("Lambda/h3dNegativeTPCchi2"), centrality, pt, negTrackExtra.tpcChi2NCl()); + histos.fill(HIST("Lambda/h3dPositiveITSclusters"), centrality, pt, posTrackExtra.itsNCls()); + histos.fill(HIST("Lambda/h3dNegativeITSclusters"), centrality, pt, negTrackExtra.itsNCls()); + histos.fill(HIST("Lambda/h3dPositiveTPCcrossedRows"), centrality, pt, posTrackExtra.tpcCrossedRows()); + histos.fill(HIST("Lambda/h3dNegativeTPCcrossedRows"), centrality, pt, negTrackExtra.tpcCrossedRows()); + } if (doTPCQA) { histos.fill(HIST("Lambda/h3dPosNsigmaTPC"), centrality, pt, posTrackExtra.tpcNSigmaPr()); histos.fill(HIST("Lambda/h3dNegNsigmaTPC"), centrality, pt, negTrackExtra.tpcNSigmaPi()); histos.fill(HIST("Lambda/h3dPosTPCsignal"), centrality, pt, posTrackExtra.tpcSignal()); histos.fill(HIST("Lambda/h3dNegTPCsignal"), centrality, pt, negTrackExtra.tpcSignal()); - histos.fill(HIST("Lambda/h3dPosNsigmaTPCvsTrackPtot"), centrality, v0.positivept() * TMath::CosH(v0.positiveeta()), posTrackExtra.tpcNSigmaPr()); - histos.fill(HIST("Lambda/h3dNegNsigmaTPCvsTrackPtot"), centrality, v0.negativept() * TMath::CosH(v0.negativeeta()), negTrackExtra.tpcNSigmaPi()); - histos.fill(HIST("Lambda/h3dPosTPCsignalVsTrackPtot"), centrality, v0.positivept() * TMath::CosH(v0.positiveeta()), posTrackExtra.tpcSignal()); - histos.fill(HIST("Lambda/h3dNegTPCsignalVsTrackPtot"), centrality, v0.negativept() * TMath::CosH(v0.negativeeta()), negTrackExtra.tpcSignal()); + histos.fill(HIST("Lambda/h3dPosNsigmaTPCvsTrackPtot"), centrality, v0.pfracpos() * v0.p(), posTrackExtra.tpcNSigmaPr()); + histos.fill(HIST("Lambda/h3dNegNsigmaTPCvsTrackPtot"), centrality, v0.pfracneg() * v0.p(), negTrackExtra.tpcNSigmaPi()); + histos.fill(HIST("Lambda/h3dPosTPCsignalVsTrackPtot"), centrality, v0.pfracpos() * v0.p(), posTrackExtra.tpcSignal()); + histos.fill(HIST("Lambda/h3dNegTPCsignalVsTrackPtot"), centrality, v0.pfracneg() * v0.p(), negTrackExtra.tpcSignal()); histos.fill(HIST("Lambda/h3dPosNsigmaTPCvsTrackPt"), centrality, v0.positivept(), posTrackExtra.tpcNSigmaPr()); histos.fill(HIST("Lambda/h3dNegNsigmaTPCvsTrackPt"), centrality, v0.negativept(), negTrackExtra.tpcNSigmaPi()); histos.fill(HIST("Lambda/h3dPosTPCsignalVsTrackPt"), centrality, v0.positivept(), posTrackExtra.tpcSignal()); histos.fill(HIST("Lambda/h3dNegTPCsignalVsTrackPt"), centrality, v0.negativept(), negTrackExtra.tpcSignal()); } if (doTOFQA) { + histos.fill(HIST("Lambda/h3dPosNsigmaTOF"), centrality, pt, v0.tofNSigmaLaPr()); + histos.fill(HIST("Lambda/h3dNegNsigmaTOF"), centrality, pt, v0.tofNSigmaLaPi()); histos.fill(HIST("Lambda/h3dPosTOFdeltaT"), centrality, pt, v0.posTOFDeltaTLaPr()); histos.fill(HIST("Lambda/h3dNegTOFdeltaT"), centrality, pt, v0.negTOFDeltaTLaPi()); - histos.fill(HIST("Lambda/h3dPosTOFdeltaTvsTrackPtot"), centrality, v0.positivept() * TMath::CosH(v0.positiveeta()), v0.posTOFDeltaTLaPr()); - histos.fill(HIST("Lambda/h3dNegTOFdeltaTvsTrackPtot"), centrality, v0.negativept() * TMath::CosH(v0.negativeeta()), v0.negTOFDeltaTLaPi()); + histos.fill(HIST("Lambda/h3dPosNsigmaTOFvsTrackPtot"), centrality, v0.pfracpos() * v0.p(), v0.tofNSigmaLaPr()); + histos.fill(HIST("Lambda/h3dNegNsigmaTOFvsTrackPtot"), centrality, v0.pfracneg() * v0.p(), v0.tofNSigmaLaPi()); + histos.fill(HIST("Lambda/h3dPosTOFdeltaTvsTrackPtot"), centrality, v0.pfracpos() * v0.p(), v0.posTOFDeltaTLaPr()); + histos.fill(HIST("Lambda/h3dNegTOFdeltaTvsTrackPtot"), centrality, v0.pfracneg() * v0.p(), v0.negTOFDeltaTLaPi()); + histos.fill(HIST("Lambda/h3dPosNsigmaTOFvsTrackPt"), centrality, v0.positivept(), v0.tofNSigmaLaPr()); + histos.fill(HIST("Lambda/h3dNegNsigmaTOFvsTrackPt"), centrality, v0.negativept(), v0.tofNSigmaLaPi()); histos.fill(HIST("Lambda/h3dPosTOFdeltaTvsTrackPt"), centrality, v0.positivept(), v0.posTOFDeltaTLaPr()); histos.fill(HIST("Lambda/h3dNegTOFdeltaTvsTrackPt"), centrality, v0.negativept(), v0.negTOFDeltaTLaPi()); } + nLambdas++; } - if (verifyMask(selMap, maskSelectionAntiLambda) && analyseAntiLambda) { + if (passAntiLambdaSelections && analyseAntiLambda) { histos.fill(HIST("h3dMassAntiLambda"), centrality, pt, v0.mAntiLambda()); + if (gapSide == 0) + histos.fill(HIST("h3dMassAntiLambdaSGA"), centrality, pt, v0.mAntiLambda()); + else if (gapSide == 1) + histos.fill(HIST("h3dMassAntiLambdaSGC"), centrality, pt, v0.mAntiLambda()); + else if (gapSide == 2) + histos.fill(HIST("h3dMassAntiLambdaDG"), centrality, pt, v0.mAntiLambda()); + else + histos.fill(HIST("h3dMassAntiLambdaHadronic"), centrality, pt, v0.mAntiLambda()); if (doPlainTopoQA) { histos.fill(HIST("AntiLambda/hPosDCAToPV"), v0.dcapostopv()); histos.fill(HIST("AntiLambda/hNegDCAToPV"), v0.dcanegtopv()); histos.fill(HIST("AntiLambda/hDCADaughters"), v0.dcaV0daughters()); - histos.fill(HIST("AntiLambda/hPointingAngle"), TMath::ACos(v0.v0cosPA())); + histos.fill(HIST("AntiLambda/hPointingAngle"), std::acos(v0.v0cosPA())); histos.fill(HIST("AntiLambda/hV0Radius"), v0.v0radius()); histos.fill(HIST("AntiLambda/h2dPositiveITSvsTPCpts"), posTrackExtra.tpcCrossedRows(), posTrackExtra.itsNCls()); histos.fill(HIST("AntiLambda/h2dNegativeITSvsTPCpts"), negTrackExtra.tpcCrossedRows(), negTrackExtra.itsNCls()); @@ -889,28 +1569,50 @@ struct derivedlambdakzeroanalysis { histos.fill(HIST("AntiLambda/h5dPosDetectPropVsCentrality"), centrality, posTrackExtra.detectorMap(), posTrackExtra.itsClusterMap(), pt, v0.mAntiLambda()); histos.fill(HIST("AntiLambda/h5dNegDetectPropVsCentrality"), centrality, negTrackExtra.detectorMap(), negTrackExtra.itsClusterMap(), pt, v0.mAntiLambda()); } + if (doDetectPropQA == 3) { + histos.fill(HIST("AntiLambda/h3dITSchi2"), centrality, pt, std::max(posTrackExtra.itsChi2NCl(), negTrackExtra.itsChi2NCl())); + histos.fill(HIST("AntiLambda/h3dTPCchi2"), centrality, pt, std::max(posTrackExtra.tpcChi2NCl(), negTrackExtra.tpcChi2NCl())); + histos.fill(HIST("AntiLambda/h3dTPCFoundOverFindable"), centrality, pt, std::min(posTrackExtra.tpcFoundOverFindableCls(), negTrackExtra.tpcFoundOverFindableCls())); + histos.fill(HIST("AntiLambda/h3dTPCrowsOverFindable"), centrality, pt, std::min(posTrackExtra.tpcCrossedRowsOverFindableCls(), negTrackExtra.tpcCrossedRowsOverFindableCls())); + histos.fill(HIST("AntiLambda/h3dTPCsharedCls"), centrality, pt, std::max(posTrackExtra.tpcFractionSharedCls(), negTrackExtra.tpcFractionSharedCls())); + histos.fill(HIST("AntiLambda/h3dPositiveITSchi2"), centrality, pt, posTrackExtra.itsChi2NCl()); + histos.fill(HIST("AntiLambda/h3dNegativeITSchi2"), centrality, pt, negTrackExtra.itsChi2NCl()); + histos.fill(HIST("AntiLambda/h3dPositiveTPCchi2"), centrality, pt, posTrackExtra.tpcChi2NCl()); + histos.fill(HIST("AntiLambda/h3dNegativeTPCchi2"), centrality, pt, negTrackExtra.tpcChi2NCl()); + histos.fill(HIST("AntiLambda/h3dPositiveITSclusters"), centrality, pt, posTrackExtra.itsNCls()); + histos.fill(HIST("AntiLambda/h3dNegativeITSclusters"), centrality, pt, negTrackExtra.itsNCls()); + histos.fill(HIST("AntiLambda/h3dPositiveTPCcrossedRows"), centrality, pt, posTrackExtra.tpcCrossedRows()); + histos.fill(HIST("AntiLambda/h3dNegativeTPCcrossedRows"), centrality, pt, negTrackExtra.tpcCrossedRows()); + } if (doTPCQA) { histos.fill(HIST("AntiLambda/h3dPosNsigmaTPC"), centrality, pt, posTrackExtra.tpcNSigmaPi()); histos.fill(HIST("AntiLambda/h3dNegNsigmaTPC"), centrality, pt, negTrackExtra.tpcNSigmaPr()); histos.fill(HIST("AntiLambda/h3dPosTPCsignal"), centrality, pt, posTrackExtra.tpcSignal()); histos.fill(HIST("AntiLambda/h3dNegTPCsignal"), centrality, pt, negTrackExtra.tpcSignal()); - histos.fill(HIST("AntiLambda/h3dPosNsigmaTPCvsTrackPtot"), centrality, v0.positivept() * TMath::CosH(v0.positiveeta()), posTrackExtra.tpcNSigmaPi()); - histos.fill(HIST("AntiLambda/h3dNegNsigmaTPCvsTrackPtot"), centrality, v0.negativept() * TMath::CosH(v0.negativeeta()), negTrackExtra.tpcNSigmaPr()); - histos.fill(HIST("AntiLambda/h3dPosTPCsignalVsTrackPtot"), centrality, v0.positivept() * TMath::CosH(v0.positiveeta()), posTrackExtra.tpcSignal()); - histos.fill(HIST("AntiLambda/h3dNegTPCsignalVsTrackPtot"), centrality, v0.negativept() * TMath::CosH(v0.negativeeta()), negTrackExtra.tpcSignal()); + histos.fill(HIST("AntiLambda/h3dPosNsigmaTPCvsTrackPtot"), centrality, v0.pfracpos() * v0.p(), posTrackExtra.tpcNSigmaPi()); + histos.fill(HIST("AntiLambda/h3dNegNsigmaTPCvsTrackPtot"), centrality, v0.pfracneg() * v0.p(), negTrackExtra.tpcNSigmaPr()); + histos.fill(HIST("AntiLambda/h3dPosTPCsignalVsTrackPtot"), centrality, v0.pfracpos() * v0.p(), posTrackExtra.tpcSignal()); + histos.fill(HIST("AntiLambda/h3dNegTPCsignalVsTrackPtot"), centrality, v0.pfracneg() * v0.p(), negTrackExtra.tpcSignal()); histos.fill(HIST("AntiLambda/h3dPosNsigmaTPCvsTrackPt"), centrality, v0.positivept(), posTrackExtra.tpcNSigmaPi()); histos.fill(HIST("AntiLambda/h3dNegNsigmaTPCvsTrackPt"), centrality, v0.negativept(), negTrackExtra.tpcNSigmaPr()); histos.fill(HIST("AntiLambda/h3dPosTPCsignalVsTrackPt"), centrality, v0.positivept(), posTrackExtra.tpcSignal()); histos.fill(HIST("AntiLambda/h3dNegTPCsignalVsTrackPt"), centrality, v0.negativept(), negTrackExtra.tpcSignal()); } if (doTOFQA) { + histos.fill(HIST("AntiLambda/h3dPosNsigmaTOF"), centrality, pt, v0.tofNSigmaALaPi()); + histos.fill(HIST("AntiLambda/h3dNegNsigmaTOF"), centrality, pt, v0.tofNSigmaALaPr()); histos.fill(HIST("AntiLambda/h3dPosTOFdeltaT"), centrality, pt, v0.posTOFDeltaTLaPi()); histos.fill(HIST("AntiLambda/h3dNegTOFdeltaT"), centrality, pt, v0.negTOFDeltaTLaPr()); - histos.fill(HIST("AntiLambda/h3dPosTOFdeltaTvsTrackPtot"), centrality, v0.positivept() * TMath::CosH(v0.positiveeta()), v0.posTOFDeltaTLaPi()); - histos.fill(HIST("AntiLambda/h3dNegTOFdeltaTvsTrackPtot"), centrality, v0.negativept() * TMath::CosH(v0.negativeeta()), v0.negTOFDeltaTLaPr()); + histos.fill(HIST("AntiLambda/h3dPosNsigmaTOFvsTrackPtot"), centrality, v0.pfracpos() * v0.p(), v0.tofNSigmaALaPi()); + histos.fill(HIST("AntiLambda/h3dNegNsigmaTOFvsTrackPtot"), centrality, v0.pfracneg() * v0.p(), v0.tofNSigmaALaPr()); + histos.fill(HIST("AntiLambda/h3dPosTOFdeltaTvsTrackPtot"), centrality, v0.pfracpos() * v0.p(), v0.posTOFDeltaTLaPi()); + histos.fill(HIST("AntiLambda/h3dNegTOFdeltaTvsTrackPtot"), centrality, v0.pfracneg() * v0.p(), v0.negTOFDeltaTLaPr()); + histos.fill(HIST("AntiLambda/h3dPosNsigmaTOFvsTrackPt"), centrality, v0.positivept(), v0.tofNSigmaALaPi()); + histos.fill(HIST("AntiLambda/h3dNegNsigmaTOFvsTrackPt"), centrality, v0.negativept(), v0.tofNSigmaALaPr()); histos.fill(HIST("AntiLambda/h3dPosTOFdeltaTvsTrackPt"), centrality, v0.positivept(), v0.posTOFDeltaTLaPi()); histos.fill(HIST("AntiLambda/h3dNegTOFdeltaTvsTrackPt"), centrality, v0.negativept(), v0.negTOFDeltaTLaPr()); } + nAntiLambdas++; } // __________________________________________ @@ -920,38 +1622,47 @@ struct derivedlambdakzeroanalysis { if (verifyMask(selMap, maskTopoNoV0Radius | maskK0ShortSpecific)) histos.fill(HIST("K0Short/h4dV0Radius"), centrality, pt, v0.mK0Short(), v0.v0radius()); if (verifyMask(selMap, maskTopoNoDCAPosToPV | maskK0ShortSpecific)) - histos.fill(HIST("K0Short/h4dPosDCAToPV"), centrality, pt, v0.mK0Short(), TMath::Abs(v0.dcapostopv())); + histos.fill(HIST("K0Short/h4dPosDCAToPV"), centrality, pt, v0.mK0Short(), std::abs(v0.dcapostopv())); if (verifyMask(selMap, maskTopoNoDCANegToPV | maskK0ShortSpecific)) - histos.fill(HIST("K0Short/h4dNegDCAToPV"), centrality, pt, v0.mK0Short(), TMath::Abs(v0.dcanegtopv())); + histos.fill(HIST("K0Short/h4dNegDCAToPV"), centrality, pt, v0.mK0Short(), std::abs(v0.dcanegtopv())); if (verifyMask(selMap, maskTopoNoCosPA | maskK0ShortSpecific)) - histos.fill(HIST("K0Short/h4dPointingAngle"), centrality, pt, v0.mK0Short(), TMath::ACos(v0.v0cosPA())); + histos.fill(HIST("K0Short/h4dPointingAngle"), centrality, pt, v0.mK0Short(), std::acos(v0.v0cosPA())); if (verifyMask(selMap, maskTopoNoDCAV0Dau | maskK0ShortSpecific)) histos.fill(HIST("K0Short/h4dDCADaughters"), centrality, pt, v0.mK0Short(), v0.dcaV0daughters()); + + if (passK0ShortSelections) + histos.fill(HIST("K0Short/h4dV0PhiVsEta"), pt, v0.mK0Short(), v0.phi(), v0.eta()); } if (analyseLambda) { if (verifyMask(selMap, maskTopoNoV0Radius | maskLambdaSpecific)) histos.fill(HIST("Lambda/h4dV0Radius"), centrality, pt, v0.mLambda(), v0.v0radius()); if (verifyMask(selMap, maskTopoNoDCAPosToPV | maskLambdaSpecific)) - histos.fill(HIST("Lambda/h4dPosDCAToPV"), centrality, pt, v0.mLambda(), TMath::Abs(v0.dcapostopv())); + histos.fill(HIST("Lambda/h4dPosDCAToPV"), centrality, pt, v0.mLambda(), std::abs(v0.dcapostopv())); if (verifyMask(selMap, maskTopoNoDCANegToPV | maskLambdaSpecific)) - histos.fill(HIST("Lambda/h4dNegDCAToPV"), centrality, pt, v0.mLambda(), TMath::Abs(v0.dcanegtopv())); + histos.fill(HIST("Lambda/h4dNegDCAToPV"), centrality, pt, v0.mLambda(), std::abs(v0.dcanegtopv())); if (verifyMask(selMap, maskTopoNoCosPA | maskLambdaSpecific)) - histos.fill(HIST("Lambda/h4dPointingAngle"), centrality, pt, v0.mLambda(), TMath::ACos(v0.v0cosPA())); + histos.fill(HIST("Lambda/h4dPointingAngle"), centrality, pt, v0.mLambda(), std::acos(v0.v0cosPA())); if (verifyMask(selMap, maskTopoNoDCAV0Dau | maskLambdaSpecific)) histos.fill(HIST("Lambda/h4dDCADaughters"), centrality, pt, v0.mLambda(), v0.dcaV0daughters()); + + if (passLambdaSelections) + histos.fill(HIST("Lambda/h4dV0PhiVsEta"), pt, v0.mLambda(), v0.phi(), v0.eta()); } if (analyseAntiLambda) { if (verifyMask(selMap, maskTopoNoV0Radius | maskAntiLambdaSpecific)) histos.fill(HIST("AntiLambda/h4dV0Radius"), centrality, pt, v0.mAntiLambda(), v0.v0radius()); if (verifyMask(selMap, maskTopoNoDCAPosToPV | maskAntiLambdaSpecific)) - histos.fill(HIST("AntiLambda/h4dPosDCAToPV"), centrality, pt, v0.mAntiLambda(), TMath::Abs(v0.dcapostopv())); + histos.fill(HIST("AntiLambda/h4dPosDCAToPV"), centrality, pt, v0.mAntiLambda(), std::abs(v0.dcapostopv())); if (verifyMask(selMap, maskTopoNoDCANegToPV | maskAntiLambdaSpecific)) - histos.fill(HIST("AntiLambda/h4dNegDCAToPV"), centrality, pt, v0.mAntiLambda(), TMath::Abs(v0.dcanegtopv())); + histos.fill(HIST("AntiLambda/h4dNegDCAToPV"), centrality, pt, v0.mAntiLambda(), std::abs(v0.dcanegtopv())); if (verifyMask(selMap, maskTopoNoCosPA | maskAntiLambdaSpecific)) - histos.fill(HIST("AntiLambda/h4dPointingAngle"), centrality, pt, v0.mAntiLambda(), TMath::ACos(v0.v0cosPA())); + histos.fill(HIST("AntiLambda/h4dPointingAngle"), centrality, pt, v0.mAntiLambda(), std::acos(v0.v0cosPA())); if (verifyMask(selMap, maskTopoNoDCAV0Dau | maskAntiLambdaSpecific)) histos.fill(HIST("AntiLambda/h4dDCADaughters"), centrality, pt, v0.mAntiLambda(), v0.dcaV0daughters()); + + if (passAntiLambdaSelections) + histos.fill(HIST("AntiLambda/h4dV0PhiVsEta"), pt, v0.mAntiLambda(), v0.phi(), v0.eta()); } } // end systematics / qa } @@ -989,7 +1700,7 @@ struct derivedlambdakzeroanalysis { auto v0mother = v0.motherMCPart(); float rapidityXi = RecoDecay::y(std::array{v0mother.px(), v0mother.py(), v0mother.pz()}, o2::constants::physics::MassXiMinus); - if (fabs(rapidityXi) > 0.5f) + if (std::fabs(rapidityXi) > 0.5f) return; // not a valid mother rapidity (PDG selection is later) // __________________________________________ @@ -1003,113 +1714,536 @@ struct derivedlambdakzeroanalysis { } } + template + bool isEventAccepted(TCollision collision, bool fillHists) + // check whether the collision passes our collision selections + { + if (fillHists) + histos.fill(HIST("hEventSelection"), 0. /* all collisions */); + + if constexpr (requires { collision.centFT0C(); }) { // check if we are in Run 3 + if (eventSelections.requireSel8 && !collision.sel8()) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 1 /* sel8 collisions */); + + if (eventSelections.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 2 /* FT0 vertex (acceptable FT0C-FT0A time difference) collisions */); + + if (eventSelections.rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 3 /* Not at ITS ROF border */); + + if (eventSelections.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 4 /* Not at TF border */); + + if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 5 /* vertex-Z selected */); + + if (eventSelections.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 6 /* Contains at least one ITS-TPC track */); + + if (eventSelections.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 7 /* PV position consistency check */); + + if (eventSelections.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 8 /* PV with at least one contributor matched with TOF */); + + if (eventSelections.requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 9 /* PV with at least one contributor matched with TRD */); + + if (eventSelections.rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 10 /* Not at same bunch pile-up */); + + if (eventSelections.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 11 /* No other collision within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds*/); + + if (eventSelections.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 12 /* No other collision within +/- 10 microseconds */); + + if (eventSelections.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 13 /* No other collision within +/- 2 microseconds */); + + if (eventSelections.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 14 /* No other collision within the same ITS ROF with mult. above a certain threshold */); + + if (eventSelections.requireNoCollInROFStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 15 /* No other collision within the same ITS ROF */); + + if (doPPAnalysis) { // we are in pp + if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 16 /* INEL > 0 */); + + if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 17 /* INEL > 1 */); + + } else { // we are in Pb-Pb + float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 16 /* Below min occupancy */); + + if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 17 /* Above max occupancy */); + } + + // Fetch interaction rate only if required (in order to limit ccdb calls) + double interactionRate = (eventSelections.minIR >= 0 || eventSelections.maxIR >= 0) ? rateFetcher.fetch(ccdb.service, collision.timestamp(), collision.runNumber(), irSource) * 1.e-3 : -1; + if (eventSelections.minIR >= 0 && interactionRate < eventSelections.minIR) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 18 /* Below min IR */); + + if (eventSelections.maxIR >= 0 && interactionRate > eventSelections.maxIR) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 19 /* Above max IR */); + + if (!rctConfigurations.cfgRCTLabel.value.empty() && !rctFlagsChecker(collision)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 20 /* Pass CBT condition */); + + } else { // we are in Run 2 + if (eventSelections.requireSel8 && !collision.sel8()) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 1 /* sel8 collisions */); + + if (eventSelections.requireSel7 && !collision.sel7()) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 2 /* sel7 collisions */); + + if (eventSelections.requireINT7 && !collision.alias_bit(kINT7)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 3 /* INT7-triggered collisions */); + + if (eventSelections.requireTriggerTVX && !collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 4 /* FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level */); + + if (eventSelections.rejectIncompleteDAQ && !collision.selection_bit(o2::aod::evsel::kNoIncompleteDAQ)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 5 /* Complete events according to DAQ flags */); + + if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 6 /* vertex-Z selected */); + + if (eventSelections.requireConsistentSPDAndTrackVtx && !collision.selection_bit(o2::aod::evsel::kNoInconsistentVtx)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 7 /* No inconsistency in SPD and Track vertices */); + + if (eventSelections.rejectPileupFromSPD && !collision.selection_bit(o2::aod::evsel::kNoPileupFromSPD)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 8 /* No pileup according to SPD vertexer */); + + if (eventSelections.rejectV0PFPileup && !collision.selection_bit(o2::aod::evsel::kNoV0PFPileup)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 9 /* No out-of-bunch pileup according to V0 past-future info */); + + if (eventSelections.rejectPileupInMultBins && !collision.selection_bit(o2::aod::evsel::kNoPileupInMultBins)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 10 /* No pileup according to multiplicity-differential pileup checks */); + + if (eventSelections.rejectPileupMV && !collision.selection_bit(o2::aod::evsel::kNoPileupMV)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 11 /* No pileup according to multi-vertexer */); + + if (eventSelections.rejectTPCPileup && !collision.selection_bit(o2::aod::evsel::kNoPileupTPC)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 12 /* No pileup in TPC */); + + if (eventSelections.requireNoV0MOnVsOffPileup && !collision.selection_bit(o2::aod::evsel::kNoV0MOnVsOfPileup)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 13 /* No out-of-bunch pileup according to online-vs-offline VOM correlation */); + + if (eventSelections.requireNoSPDOnVsOffPileup && !collision.selection_bit(o2::aod::evsel::kNoSPDOnVsOfPileup)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 14 /* No out-of-bunch pileup according to online-vs-offline SPD correlation */); + + if (eventSelections.requireNoSPDClsVsTklBG && !collision.selection_bit(o2::aod::evsel::kNoSPDClsVsTklBG)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 15 /* No beam-gas according to cluster-vs-tracklet correlation */); + + if (doPPAnalysis) { // we are in pp + if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 16 /* INEL > 0 */); + + if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 17 /* INEL > 1 */); + } + } + + return true; + } + // ______________________________________________________ - // Real data processing - no MC subscription - void processRealData(soa::Join::iterator const& collision, v0Candidates const& fullV0s, dauTracks const&) + // Simulated processing + // Return the list of indices to the recoed collision associated to a given MC collision. + template + std::vector getListOfRecoCollIndices(TMCollisions const& mcCollisions, TCollisions const& collisions) { - histos.fill(HIST("hEventSelection"), 0. /* all collisions */); - if (!collision.sel8()) { - return; + std::vector listBestCollisionIdx(mcCollisions.size()); + for (auto const& mcCollision : mcCollisions) { + auto groupedCollisions = getGroupedCollisions(collisions, mcCollision.globalIndex()); + int biggestNContribs = -1; + int bestCollisionIndex = -1; + for (auto const& collision : groupedCollisions) { + // consider event selections in the recoed <-> gen collision association, for the denominator (or numerator) of the efficiency (or signal loss)? + if (eventSelections.useEvtSelInDenomEff) { + if (!isEventAccepted(collision, false)) { + continue; + } + } + + if constexpr (run3) { // check if we are in Run 3 + // Find the collision with the biggest nbr of PV contributors + // Follows what was done here: https://github.com/AliceO2Group/O2Physics/blob/master/Common/TableProducer/mcCollsExtra.cxx#L93 + if (biggestNContribs < collision.multPVTotalContributors()) { + biggestNContribs = collision.multPVTotalContributors(); + bestCollisionIndex = collision.globalIndex(); + } + } else { // we are in Run 2: there should be only one collision in groupedCollisions + bestCollisionIndex = collision.globalIndex(); + } + } + listBestCollisionIdx[mcCollision.globalIndex()] = bestCollisionIndex; } - histos.fill(HIST("hEventSelection"), 1 /* sel8 collisions */); + return listBestCollisionIdx; + } - if (std::abs(collision.posZ()) > 10.f) { - return; + // ______________________________________________________ + // Reconstructed data processing + // Fill reconstructed event information + // Return centrality, occupancy, interaction rate, gap side and selGapside via reference-passing in arguments + template + void fillReconstructedEventProperties(TCollision const& collision, float& centrality, float& collisionOccupancy, double& interactionRate, int& gapSide, int& selGapSide) + { + if constexpr (requires { collision.centFT0C(); }) { // check if we are in Run 3 + centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + // Fetch interaction rate only if required (in order to limit ccdb calls) + interactionRate = !irSource.value.empty() ? rateFetcher.fetch(ccdb.service, collision.timestamp(), collision.runNumber(), irSource) * 1.e-3 : -1; + + if (qaCentrality) { + auto hRawCentrality = histos.get(HIST("hRawCentrality")); + centrality = hRawCentrality->GetBinContent(hRawCentrality->FindBin(doPPAnalysis ? collision.multFT0A() + collision.multFT0C() : collision.multFT0C())); + } + + // gap side + gapSide = collision.gapSide(); + // -1 --> Hadronic + // 0 --> Single Gap - A side + // 1 --> Single Gap - C side + // 2 --> Double Gap - both A & C sides + selGapSide = sgSelector.trueGap(collision, upcCuts.fv0Cut, upcCuts.ft0Acut, upcCuts.ft0Ccut, upcCuts.zdcCut); + } else { // no, we are in Run 2 + centrality = eventSelections.useSPDTrackletsCent ? collision.centRun2SPDTracklets() : collision.centRun2V0M(); } - histos.fill(HIST("hEventSelection"), 2 /* vertex-Z selected */); - if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { - return; + histos.fill(HIST("hGapSide"), gapSide); + histos.fill(HIST("hSelGapSide"), selGapSide); + histos.fill(HIST("hEventCentralityVsSelGapSide"), centrality, selGapSide <= 2 ? selGapSide : -1); + + histos.fill(HIST("hEventCentrality"), centrality); + + histos.fill(HIST("hCentralityVsNch"), centrality, collision.multNTracksPVeta1()); + + histos.fill(HIST("hCentralityVsPVz"), centrality, collision.posZ()); + histos.fill(HIST("hEventPVz"), collision.posZ()); + + histos.fill(HIST("hEventOccupancy"), collisionOccupancy); + histos.fill(HIST("hCentralityVsOccupancy"), centrality, collisionOccupancy); + + histos.fill(HIST("hInteractionRate"), interactionRate); + histos.fill(HIST("hCentralityVsInteractionRate"), centrality, interactionRate); + + histos.fill(HIST("hInteractionRateVsOccupancy"), interactionRate, collisionOccupancy); + return; + } + + // ______________________________________________________ + // Simulated processing + // Fill generated event information (for event loss/splitting estimation) + template + void fillGeneratedEventProperties(TMCCollisions const& mcCollisions, TCollisions const& collisions) + { + std::vector listBestCollisionIdx(mcCollisions.size()); + for (auto const& mcCollision : mcCollisions) { + // Apply selections on MC collisions + if (eventSelections.applyZVtxSelOnMCPV && std::abs(mcCollision.posZ()) > eventSelections.maxZVtxPosition) { + continue; + } + if (doPPAnalysis) { // we are in pp + if (eventSelections.requireINEL0 && mcCollision.multMCNParticlesEta10() < 1) { + continue; + } + + if (eventSelections.requireINEL1 && mcCollision.multMCNParticlesEta10() < 2) { + continue; + } + } + + histos.fill(HIST("hGenEvents"), mcCollision.multMCNParticlesEta05(), 0 /* all gen. events*/); + + auto groupedCollisions = getGroupedCollisions(collisions, mcCollision.globalIndex()); + // Check if there is at least one of the reconstructed collisions associated to this MC collision + // If so, we consider it + bool atLeastOne = false; + int biggestNContribs = -1; + float centrality = 100.5f; + int nCollisions = 0; + for (auto const& collision : groupedCollisions) { + + if (!isEventAccepted(collision, false)) { + continue; + } + + if constexpr (run3) { // check if we are in Run 3 + if (biggestNContribs < collision.multPVTotalContributors()) { + biggestNContribs = collision.multPVTotalContributors(); + centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + } + } else { // we are in Run 2: there should be only one collision in groupedCollisions + centrality = eventSelections.useSPDTrackletsCent ? collision.centRun2SPDTracklets() : collision.centRun2V0M(); + } + nCollisions++; + + atLeastOne = true; + } + + histos.fill(HIST("hCentralityVsNcoll_beforeEvSel"), centrality, groupedCollisions.size()); + histos.fill(HIST("hCentralityVsNcoll_afterEvSel"), centrality, nCollisions); + + histos.fill(HIST("hCentralityVsMultMC"), centrality, mcCollision.multMCNParticlesEta05()); + histos.fill(HIST("hCentralityVsPVzMC"), centrality, mcCollision.posZ()); + histos.fill(HIST("hEventPVzMC"), mcCollision.posZ()); + + if (atLeastOne) { + histos.fill(HIST("hGenEvents"), mcCollision.multMCNParticlesEta05(), 1 /* at least 1 rec. event*/); + + histos.fill(HIST("hGenEventCentrality"), centrality); + } } - histos.fill(HIST("hEventSelection"), 3 /* Not at ITS ROF border */); + return; + } - if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { - return; + // ______________________________________________________ + // Real data processing - no MC subscription + template + void analyzeRecoedV0sInRealData(TCollision const& collision, TV0s const& fullV0s) + { + // Fire up CCDB + if ((mlConfigurations.useK0ShortScores && mlConfigurations.calculateK0ShortScores) || + (mlConfigurations.useLambdaScores && mlConfigurations.calculateLambdaScores) || + (mlConfigurations.useAntiLambdaScores && mlConfigurations.calculateAntiLambdaScores)) { + initCCDB(collision); } - histos.fill(HIST("hEventSelection"), 4 /* Not at TF border */); - float centrality = collision.centFT0C(); - if (qaCentrality) { - auto hRawCentrality = histos.get(HIST("hRawCentrality")); - centrality = hRawCentrality->GetBinContent(hRawCentrality->FindBin(collision.multFT0C())); + if (!isEventAccepted(collision, true)) { + return; } - histos.fill(HIST("hEventCentrality"), centrality); + float centrality = -1; + float collisionOccupancy = -2; // -1 already taken for the case where occupancy cannot be evaluated + double interactionRate = -1; + // gap side + int gapSide = -1; + int selGapSide = -1; // -1 --> Hadronic ; 0 --> Single Gap - A side ; 1 --> Single Gap - C side ; 2 --> Double Gap - both A & C sides + // Fill recoed event properties + fillReconstructedEventProperties(collision, centrality, collisionOccupancy, interactionRate, gapSide, selGapSide); - histos.fill(HIST("hCentralityVsNch"), centrality, collision.multNTracksPVeta1()); + histos.fill(HIST("hInteractionRateVsOccupancy"), interactionRate, collisionOccupancy); // __________________________________________ // perform main analysis - for (auto& v0 : fullV0s) { - if (std::abs(v0.negativeeta()) > daughterEtaCut || std::abs(v0.positiveeta()) > daughterEtaCut) + int nK0Shorts = 0; + int nLambdas = 0; + int nAntiLambdas = 0; + for (auto const& v0 : fullV0s) { + if (std::abs(v0.negativeeta()) > v0Selections.daughterEtaCut || std::abs(v0.positiveeta()) > v0Selections.daughterEtaCut) continue; // remove acceptance that's badly reproduced by MC / superfluous in future + if (v0.v0Type() != v0Selections.v0TypeSelection && v0Selections.v0TypeSelection > -1) + continue; // skip V0s that are not standard + // fill AP plot for all V0s histos.fill(HIST("GeneralQA/h2dArmenterosAll"), v0.alpha(), v0.qtarm()); uint64_t selMap = computeReconstructionBitmap(v0, collision, v0.yLambda(), v0.yK0Short(), v0.pt()); // consider for histograms for all species - selMap = selMap | (uint64_t(1) << selConsiderK0Short) | (uint64_t(1) << selConsiderLambda) | (uint64_t(1) << selConsiderAntiLambda); - selMap = selMap | (uint64_t(1) << selPhysPrimK0Short) | (uint64_t(1) << selPhysPrimLambda) | (uint64_t(1) << selPhysPrimAntiLambda); + BITSET(selMap, selConsiderK0Short); + BITSET(selMap, selConsiderLambda); + BITSET(selMap, selConsiderAntiLambda); + + BITSET(selMap, selPhysPrimK0Short); + BITSET(selMap, selPhysPrimLambda); + BITSET(selMap, selPhysPrimAntiLambda); - analyseCandidate(v0, v0.pt(), centrality, selMap); + analyseCandidate(v0, v0.pt(), centrality, selMap, selGapSide, nK0Shorts, nLambdas, nAntiLambdas); } // end v0 loop + + // fill the histograms with the number of reconstructed K0s/Lambda/antiLambda per collision + if (analyseK0Short) { + histos.fill(HIST("h2dNbrOfK0ShortVsCentrality"), centrality, nK0Shorts); + } + if (analyseLambda) { + histos.fill(HIST("h2dNbrOfLambdaVsCentrality"), centrality, nLambdas); + } + if (analyseAntiLambda) { + histos.fill(HIST("h2dNbrOfAntiLambdaVsCentrality"), centrality, nAntiLambdas); + } } // ______________________________________________________ // Simulated processing (subscribes to MC information too) - void processMonteCarlo(soa::Join::iterator const& collision, v0MCCandidates const& fullV0s, dauTracks const&, aod::MotherMCParts const&, soa::Join const& /*mccollisions*/) + template + void analyzeRecoedV0sInMonteCarlo(TCollision const& collision, TV0s const& fullV0s) { - histos.fill(HIST("hEventSelection"), 0. /* all collisions */); - if (!collision.sel8()) { - return; - } - histos.fill(HIST("hEventSelection"), 1 /* sel8 collisions */); - - if (std::abs(collision.posZ()) > 10.f) { - return; + // Fire up CCDB + if ((mlConfigurations.useK0ShortScores && mlConfigurations.calculateK0ShortScores) || + (mlConfigurations.useLambdaScores && mlConfigurations.calculateLambdaScores) || + (mlConfigurations.useAntiLambdaScores && mlConfigurations.calculateAntiLambdaScores)) { + initCCDB(collision); } - histos.fill(HIST("hEventSelection"), 2 /* vertex-Z selected */); - if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + if (!isEventAccepted(collision, true)) { return; } - histos.fill(HIST("hEventSelection"), 3 /* Not at ITS ROF border */); - - if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { - return; - } - histos.fill(HIST("hEventSelection"), 4 /* Not at TF border */); - - float centrality = collision.centFT0C(); - if (qaCentrality) { - auto hRawCentrality = histos.get(HIST("hRawCentrality")); - centrality = hRawCentrality->GetBinContent(hRawCentrality->FindBin(collision.multFT0C())); - } - histos.fill(HIST("hEventCentrality"), centrality); + float centrality = -1; + float collisionOccupancy = -2; // -1 already taken for the case where occupancy cannot be evaluated + double interactionRate = -1; + // gap side + int gapSide = -1; + int selGapSide = -1; // -1 --> Hadronic ; 0 --> Single Gap - A side ; 1 --> Single Gap - C side ; 2 --> Double Gap - both A & C sides + // Fill recoed event properties + fillReconstructedEventProperties(collision, centrality, collisionOccupancy, interactionRate, gapSide, selGapSide); - histos.fill(HIST("hCentralityVsNch"), centrality, collision.multNTracksPVeta1()); + histos.fill(HIST("hInteractionRateVsOccupancy"), interactionRate, collisionOccupancy); // __________________________________________ // perform main analysis - for (auto& v0 : fullV0s) { - if (std::abs(v0.negativeeta()) > daughterEtaCut || std::abs(v0.positiveeta()) > daughterEtaCut) + int nK0Shorts = 0; + int nLambdas = 0; + int nAntiLambdas = 0; + for (auto const& v0 : fullV0s) { + if (std::abs(v0.negativeeta()) > v0Selections.daughterEtaCut || std::abs(v0.positiveeta()) > v0Selections.daughterEtaCut) continue; // remove acceptance that's badly reproduced by MC / superfluous in future + if (v0.v0Type() != v0Selections.v0TypeSelection && v0Selections.v0TypeSelection > -1) + continue; // skip V0s that are not standard + + if (!v0.has_v0MCCore()) + continue; + + auto v0MC = v0.template v0MCCore_as>(); + // fill AP plot for all V0s histos.fill(HIST("GeneralQA/h2dArmenterosAll"), v0.alpha(), v0.qtarm()); - float ptmc = RecoDecay::sqrtSumOfSquares(v0.pxPosMC() + v0.pxNegMC(), v0.pyPosMC() + v0.pyNegMC()); + float ptmc = RecoDecay::sqrtSumOfSquares(v0MC.pxPosMC() + v0MC.pxNegMC(), v0MC.pyPosMC() + v0MC.pyNegMC()); float ymc = 1e-3; - if (v0.pdgCode() == 310) - ymc = RecoDecay::y(std::array{v0.pxPosMC() + v0.pxNegMC(), v0.pyPosMC() + v0.pyNegMC(), v0.pzPosMC() + v0.pzNegMC()}, o2::constants::physics::MassKaonNeutral); - else if (TMath::Abs(v0.pdgCode()) == 3122) - ymc = RecoDecay::y(std::array{v0.pxPosMC() + v0.pxNegMC(), v0.pyPosMC() + v0.pyNegMC(), v0.pzPosMC() + v0.pzNegMC()}, o2::constants::physics::MassLambda); + if (v0MC.pdgCode() == 310) + ymc = RecoDecay::y(std::array{v0MC.pxPosMC() + v0MC.pxNegMC(), v0MC.pyPosMC() + v0MC.pyNegMC(), v0MC.pzPosMC() + v0MC.pzNegMC()}, o2::constants::physics::MassKaonNeutral); + else if (std::abs(v0MC.pdgCode()) == 3122) + ymc = RecoDecay::y(std::array{v0MC.pxPosMC() + v0MC.pxNegMC(), v0MC.pyPosMC() + v0MC.pyNegMC(), v0MC.pzPosMC() + v0MC.pzNegMC()}, o2::constants::physics::MassLambda); uint64_t selMap = computeReconstructionBitmap(v0, collision, ymc, ymc, ptmc); - selMap = selMap | computeMCAssociation(v0); + selMap = selMap | computeMCAssociation(v0MC); // feeddown matrix always with association if (calculateFeeddownMatrix) @@ -1117,25 +2251,228 @@ struct derivedlambdakzeroanalysis { // consider only associated candidates if asked to do so, disregard association if (!doMCAssociation) { - selMap = selMap | (uint64_t(1) << selConsiderK0Short) | (uint64_t(1) << selConsiderLambda) | (uint64_t(1) << selConsiderAntiLambda); - selMap = selMap | (uint64_t(1) << selPhysPrimK0Short) | (uint64_t(1) << selPhysPrimLambda) | (uint64_t(1) << selPhysPrimAntiLambda); + BITSET(selMap, selConsiderK0Short); + BITSET(selMap, selConsiderLambda); + BITSET(selMap, selConsiderAntiLambda); + + BITSET(selMap, selPhysPrimK0Short); + BITSET(selMap, selPhysPrimLambda); + BITSET(selMap, selPhysPrimAntiLambda); } - analyseCandidate(v0, ptmc, centrality, selMap); + analyseCandidate(v0, ptmc, centrality, selMap, selGapSide, nK0Shorts, nLambdas, nAntiLambdas); if (doCollisionAssociationQA) { // check collision association explicitly bool correctCollision = false; int mcNch = -1; if (collision.has_straMCCollision()) { - auto mcCollision = collision.straMCCollision_as>(); + auto mcCollision = collision.template straMCCollision_as>(); mcNch = mcCollision.multMCNParticlesEta05(); - correctCollision = (v0.straMCCollisionId() == mcCollision.globalIndex()); + correctCollision = (v0MC.straMCCollisionId() == mcCollision.globalIndex()); } analyseCollisionAssociation(v0, ptmc, mcNch, correctCollision, selMap); } } // end v0 loop + + // fill the histograms with the number of reconstructed K0s/Lambda/antiLambda per collision + if (analyseK0Short) { + histos.fill(HIST("h2dNbrOfK0ShortVsCentrality"), centrality, nK0Shorts); + } + if (analyseLambda) { + histos.fill(HIST("h2dNbrOfLambdaVsCentrality"), centrality, nLambdas); + } + if (analyseAntiLambda) { + histos.fill(HIST("h2dNbrOfAntiLambdaVsCentrality"), centrality, nAntiLambdas); + } + } + + // ______________________________________________________ + // Simulated processing (subscribes to MC information too) + template + void analyzeGeneratedV0s(TMCCollisions const& mcCollisions, TV0MCs const& V0MCCores, TCascMCs const& CascMCCores, TCollisions const& collisions) + { + fillGeneratedEventProperties(mcCollisions, collisions); + std::vector listBestCollisionIdx = getListOfRecoCollIndices(mcCollisions, collisions); + for (auto const& v0MC : V0MCCores) { + if (!v0MC.has_straMCCollision()) + continue; + + if (!v0MC.isPhysicalPrimary()) + continue; + + float ptmc = v0MC.ptMC(); + float ymc = 1e3; + if (v0MC.pdgCode() == 310) + ymc = v0MC.rapidityMC(0); + else if (std::abs(v0MC.pdgCode()) == 3122) + ymc = v0MC.rapidityMC(1); + + if (std::abs(ymc) > v0Selections.rapidityCut) + continue; + + auto mcCollision = v0MC.template straMCCollision_as>(); + if (eventSelections.applyZVtxSelOnMCPV && std::abs(mcCollision.posZ()) > eventSelections.maxZVtxPosition) { + continue; + } + if (doPPAnalysis) { // we are in pp + if (eventSelections.requireINEL0 && mcCollision.multMCNParticlesEta10() < 1) { + continue; + } + + if (eventSelections.requireINEL1 && mcCollision.multMCNParticlesEta10() < 2) { + continue; + } + } + + float centrality = 100.5f; + if (listBestCollisionIdx[mcCollision.globalIndex()] > -1) { + auto collision = collisions.iteratorAt(listBestCollisionIdx[mcCollision.globalIndex()]); + if constexpr (requires { collision.centFT0C(); }) { // check if we are in Run 3 + centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + } else { // no, we are in Run 2 + centrality = eventSelections.useSPDTrackletsCent ? collision.centRun2SPDTracklets() : collision.centRun2V0M(); + } + + if (v0MC.pdgCode() == 310) { + histos.fill(HIST("h2dGenK0ShortVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCode() == 3122) { + histos.fill(HIST("h2dGenLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCode() == -3122) { + histos.fill(HIST("h2dGenAntiLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + + if (v0MC.pdgCode() == 310) { + histos.fill(HIST("h2dGenK0Short"), centrality, ptmc); + histos.fill(HIST("h2dGenK0ShortVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCode() == 3122) { + histos.fill(HIST("h2dGenLambda"), centrality, ptmc); + histos.fill(HIST("h2dGenLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCode() == -3122) { + histos.fill(HIST("h2dGenAntiLambda"), centrality, ptmc); + histos.fill(HIST("h2dGenAntiLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + + for (auto const& cascMC : CascMCCores) { + if (!cascMC.has_straMCCollision()) + continue; + + if (!cascMC.isPhysicalPrimary()) + continue; + + float ptmc = cascMC.ptMC(); + float ymc = 1e3; + if (std::abs(cascMC.pdgCode()) == 3312) + ymc = cascMC.rapidityMC(0); + else if (std::abs(cascMC.pdgCode()) == 3334) + ymc = cascMC.rapidityMC(2); + + if (std::abs(ymc) > v0Selections.rapidityCut) + continue; + + auto mcCollision = cascMC.template straMCCollision_as>(); + if (eventSelections.applyZVtxSelOnMCPV && std::abs(mcCollision.posZ()) > eventSelections.maxZVtxPosition) { + continue; + } + if (doPPAnalysis) { // we are in pp + if (eventSelections.requireINEL0 && mcCollision.multMCNParticlesEta10() < 1) { + continue; + } + + if (eventSelections.requireINEL1 && mcCollision.multMCNParticlesEta10() < 2) { + continue; + } + } + + float centrality = 100.5f; + if (listBestCollisionIdx[mcCollision.globalIndex()] > -1) { + auto collision = collisions.iteratorAt(listBestCollisionIdx[mcCollision.globalIndex()]); + if constexpr (requires { collision.centFT0C(); }) { // check if we are in Run 3 + centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + } else { // no, we are in Run 2 + centrality = eventSelections.useSPDTrackletsCent ? collision.centRun2SPDTracklets() : collision.centRun2V0M(); + } + + if (cascMC.pdgCode() == 3312) { + histos.fill(HIST("h2dGenXiMinusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == -3312) { + histos.fill(HIST("h2dGenXiPlusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == 3334) { + histos.fill(HIST("h2dGenOmegaMinusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == -3334) { + histos.fill(HIST("h2dGenOmegaPlusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + + if (cascMC.pdgCode() == 3312) { + histos.fill(HIST("h2dGenXiMinus"), centrality, ptmc); + histos.fill(HIST("h2dGenXiMinusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == -3312) { + histos.fill(HIST("h2dGenXiPlus"), centrality, ptmc); + histos.fill(HIST("h2dGenXiPlusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == 3334) { + histos.fill(HIST("h2dGenOmegaMinus"), centrality, ptmc); + histos.fill(HIST("h2dGenOmegaMinusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == -3334) { + histos.fill(HIST("h2dGenOmegaPlus"), centrality, ptmc); + histos.fill(HIST("h2dGenOmegaPlusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + } + + // ______________________________________________________ + // Real data processing in Run 3 - no MC subscription + void processRealDataRun3(soa::Join::iterator const& collision, V0Candidates const& fullV0s, DauTracks const&) + { + analyzeRecoedV0sInRealData(collision, fullV0s); + } + + // ______________________________________________________ + // Real data processing in Run 2 - no MC subscription + void processRealDataRun2(soa::Join::iterator const& collision, V0Candidates const& fullV0s, DauTracks const&) + { + analyzeRecoedV0sInRealData(collision, fullV0s); + } + + // ______________________________________________________ + // Simulated processing in Run 3 (subscribes to MC information too) + void processMonteCarloRun3(soa::Join::iterator const& collision, V0McCandidates const& fullV0s, DauTracks const&, aod::MotherMCParts const&, soa::Join const& /*mccollisions*/, soa::Join const&) + { + analyzeRecoedV0sInMonteCarlo(collision, fullV0s); + } + + // ______________________________________________________ + // Simulated processing in Run 2 (subscribes to MC information too) + void processMonteCarloRun2(soa::Join::iterator const& collision, V0McCandidates const& fullV0s, DauTracks const&, aod::MotherMCParts const&, soa::Join const& /*mccollisions*/, soa::Join const&) + { + analyzeRecoedV0sInMonteCarlo(collision, fullV0s); + } + + // ______________________________________________________ + // Simulated processing in Run 3 (subscribes to MC information too) + void processGeneratedRun3(soa::Join const& mcCollisions, soa::Join const& V0MCCores, soa::Join const& CascMCCores, soa::Join const& collisions) + { + analyzeGeneratedV0s(mcCollisions, V0MCCores, CascMCCores, collisions); + } + + // ______________________________________________________ + // Simulated processing in Run 2 (subscribes to MC information too) + void processGeneratedRun2(soa::Join const& mcCollisions, soa::Join const& V0MCCores, soa::Join const& CascMCCores, soa::Join const& collisions) + { + analyzeGeneratedV0s(mcCollisions, V0MCCores, CascMCCores, collisions); } // ______________________________________________________ @@ -1145,67 +2482,71 @@ struct derivedlambdakzeroanalysis { aod::GeXiMinus const& geXiMinus, aod::GeXiPlus const& geXiPlus, aod::GeOmegaMinus const& geOmegaMinus, aod::GeOmegaPlus const& geOmegaPlus) { - auto hK0Short = histos.get(HIST("h2dGenK0Short")); - auto hLambda = histos.get(HIST("h2dGenLambda")); - auto hAntiLambda = histos.get(HIST("h2dGenAntiLambda")); - auto hXiMinus = histos.get(HIST("h2dGenXiMinus")); - auto hXiPlus = histos.get(HIST("h2dGenXiPlus")); - auto hOmegaMinus = histos.get(HIST("h2dGenOmegaMinus")); - auto hOmegaPlus = histos.get(HIST("h2dGenOmegaPlus")); - for (auto& gVec : geK0Short) { - if (gVec.generatedK0Short().size() != hK0Short->GetNcells()) + auto hK0Short = histos.get(HIST("h2dGeneratedK0Short")); + auto hLambda = histos.get(HIST("h2dGeneratedLambda")); + auto hAntiLambda = histos.get(HIST("h2dGeneratedAntiLambda")); + auto hXiMinus = histos.get(HIST("h2dGeneratedXiMinus")); + auto hXiPlus = histos.get(HIST("h2dGeneratedXiPlus")); + auto hOmegaMinus = histos.get(HIST("h2dGeneratedOmegaMinus")); + auto hOmegaPlus = histos.get(HIST("h2dGeneratedOmegaPlus")); + for (auto const& gVec : geK0Short) { + if (static_cast(gVec.generatedK0Short().size()) != hK0Short->GetNcells()) LOGF(fatal, "K0Short: Number of elements in generated array and number of cells in receiving histogram differ: %i vs %i!", gVec.generatedK0Short().size(), hK0Short->GetNcells()); - for (uint64_t iv = 0; iv < hK0Short->GetNcells(); iv++) { + for (int iv = 0; iv < hK0Short->GetNcells(); iv++) { hK0Short->SetBinContent(iv, hK0Short->GetBinContent(iv) + gVec.generatedK0Short()[iv]); } } - for (auto& gVec : geLambda) { - if (gVec.generatedLambda().size() != hLambda->GetNcells()) + for (auto const& gVec : geLambda) { + if (static_cast(gVec.generatedLambda().size()) != hLambda->GetNcells()) LOGF(fatal, "Lambda: Number of elements in generated array and number of cells in receiving histogram differ: %i vs %i!", gVec.generatedLambda().size(), hLambda->GetNcells()); - for (uint64_t iv = 0; iv < hLambda->GetNcells(); iv++) { + for (int iv = 0; iv < hLambda->GetNcells(); iv++) { hLambda->SetBinContent(iv, hLambda->GetBinContent(iv) + gVec.generatedLambda()[iv]); } } - for (auto& gVec : geAntiLambda) { - if (gVec.generatedAntiLambda().size() != hAntiLambda->GetNcells()) + for (auto const& gVec : geAntiLambda) { + if (static_cast(gVec.generatedAntiLambda().size()) != hAntiLambda->GetNcells()) LOGF(fatal, "AntiLambda: Number of elements in generated array and number of cells in receiving histogram differ: %i vs %i!", gVec.generatedAntiLambda().size(), hAntiLambda->GetNcells()); - for (uint64_t iv = 0; iv < hAntiLambda->GetNcells(); iv++) { + for (int iv = 0; iv < hAntiLambda->GetNcells(); iv++) { hAntiLambda->SetBinContent(iv, hAntiLambda->GetBinContent(iv) + gVec.generatedAntiLambda()[iv]); } } - for (auto& gVec : geXiMinus) { - if (gVec.generatedXiMinus().size() != hXiMinus->GetNcells()) + for (auto const& gVec : geXiMinus) { + if (static_cast(gVec.generatedXiMinus().size()) != hXiMinus->GetNcells()) LOGF(fatal, "XiMinus: Number of elements in generated array and number of cells in receiving histogram differ: %i vs %i!", gVec.generatedXiMinus().size(), hXiMinus->GetNcells()); - for (uint64_t iv = 0; iv < hXiMinus->GetNcells(); iv++) { + for (int iv = 0; iv < hXiMinus->GetNcells(); iv++) { hXiMinus->SetBinContent(iv, hXiMinus->GetBinContent(iv) + gVec.generatedXiMinus()[iv]); } } - for (auto& gVec : geXiPlus) { - if (gVec.generatedXiPlus().size() != hXiPlus->GetNcells()) + for (auto const& gVec : geXiPlus) { + if (static_cast(gVec.generatedXiPlus().size()) != hXiPlus->GetNcells()) LOGF(fatal, "XiPlus: Number of elements in generated array and number of cells in receiving histogram differ: %i vs %i!", gVec.generatedXiPlus().size(), hXiPlus->GetNcells()); - for (uint64_t iv = 0; iv < hXiPlus->GetNcells(); iv++) { + for (int iv = 0; iv < hXiPlus->GetNcells(); iv++) { hXiPlus->SetBinContent(iv, hXiPlus->GetBinContent(iv) + gVec.generatedXiPlus()[iv]); } } - for (auto& gVec : geOmegaMinus) { - if (gVec.generatedOmegaMinus().size() != hOmegaMinus->GetNcells()) + for (auto const& gVec : geOmegaMinus) { + if (static_cast(gVec.generatedOmegaMinus().size()) != hOmegaMinus->GetNcells()) LOGF(fatal, "OmegaMinus: Number of elements in generated array and number of cells in receiving histogram differ: %i vs %i!", gVec.generatedOmegaMinus().size(), hOmegaMinus->GetNcells()); - for (uint64_t iv = 0; iv < hOmegaMinus->GetNcells(); iv++) { + for (int iv = 0; iv < hOmegaMinus->GetNcells(); iv++) { hOmegaMinus->SetBinContent(iv, hOmegaMinus->GetBinContent(iv) + gVec.generatedOmegaMinus()[iv]); } } - for (auto& gVec : geOmegaPlus) { - if (gVec.generatedOmegaPlus().size() != hOmegaPlus->GetNcells()) + for (auto const& gVec : geOmegaPlus) { + if (static_cast(gVec.generatedOmegaPlus().size()) != hOmegaPlus->GetNcells()) LOGF(fatal, "OmegaPlus: Number of elements in generated array and number of cells in receiving histogram differ: %i vs %i!", gVec.generatedOmegaPlus().size(), hOmegaPlus->GetNcells()); - for (uint64_t iv = 0; iv < hOmegaPlus->GetNcells(); iv++) { + for (int iv = 0; iv < hOmegaPlus->GetNcells(); iv++) { hOmegaPlus->SetBinContent(iv, hOmegaPlus->GetBinContent(iv) + gVec.generatedOmegaPlus()[iv]); } } } - PROCESS_SWITCH(derivedlambdakzeroanalysis, processRealData, "process as if real data", true); - PROCESS_SWITCH(derivedlambdakzeroanalysis, processMonteCarlo, "process as if MC", false); + PROCESS_SWITCH(derivedlambdakzeroanalysis, processRealDataRun3, "process as if real data in Run 3", true); + PROCESS_SWITCH(derivedlambdakzeroanalysis, processRealDataRun2, "process as if real data in Run 2", false); + PROCESS_SWITCH(derivedlambdakzeroanalysis, processMonteCarloRun3, "process as if MC in Run 3", false); + PROCESS_SWITCH(derivedlambdakzeroanalysis, processMonteCarloRun2, "process as if MC in Run 2", false); PROCESS_SWITCH(derivedlambdakzeroanalysis, processBinnedGenerated, "process MC generated", false); + PROCESS_SWITCH(derivedlambdakzeroanalysis, processGeneratedRun3, "process MC generated Run 3", false); + PROCESS_SWITCH(derivedlambdakzeroanalysis, processGeneratedRun2, "process MC generated Run 2", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Strangeness/derivedupcanalysis.cxx b/PWGLF/Tasks/Strangeness/derivedupcanalysis.cxx new file mode 100644 index 00000000000..af47c618d7a --- /dev/null +++ b/PWGLF/Tasks/Strangeness/derivedupcanalysis.cxx @@ -0,0 +1,2055 @@ +// Copyright 2019-2025 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 derivedupcanalysis.cxx +/// \brief Analysis of strangeness production in UPC collisions +/// \author Roman Nepeivoda (roman.nepeivoda@cern.ch) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "Framework/StaticFor.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGLF/Utils/strangenessMasks.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +using DauTracks = soa::Join; +using DauMCTracks = soa::Join; + +using V0Candidates = soa::Join; +using V0CandidatesMC = soa::Join; + +using CascadeCandidates = soa::Join; +using CascadeCandidatesMC = soa::Join; + +using CascMCCoresFull = soa::Join; + +using StraCollisonFull = soa::Join::iterator; +using StraCollisonFullMC = soa::Join::iterator; + +using StraCollisonsFullMC = soa::Join; + +using StraMCCollisionsFull = soa::Join; +using V0MCCoresFull = soa::Join; + +struct Derivedupcanalysis { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // master analysis switches + Configurable analyseK0Short{"analyseK0Short", true, "process K0Short-like candidates"}; + Configurable analyseLambda{"analyseLambda", true, "process Lambda-like candidates"}; + Configurable analyseAntiLambda{"analyseAntiLambda", true, "process AntiLambda-like candidates"}; + Configurable analyseXi{"analyseXi", true, "process Xi-like candidates"}; + Configurable analyseAntiXi{"analyseAntiXi", true, "process AntiXi-like candidates"}; + Configurable analyseOmega{"analyseOmega", true, "process Omega-like candidates"}; + Configurable analyseAntiOmega{"analyseAntiOmega", true, "process AntiOmega-like candidates"}; + + Configurable> generatorIds{"generatorIds", std::vector{-1}, "MC generatorIds to process"}; + + // Event selections + Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border"}; + Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border"}; + Configurable rejectSameBunchPileup{"rejectSameBunchPileup", true, "reject collisions in case of pileup with another collision in the same foundBC"}; + Configurable requireIsTriggerTVX{"requireIsTriggerTVX", false, "require coincidence in FT0A and FT0C"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "require events with at least one ITS-TPC track"}; + Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", false, "require events with PV position along z consistent (within 1 cm) between PV reconstructed using tracks and PV using FT0 A-C time difference"}; + Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", false, "require events with at least one of vertex contributors matched to TOF"}; + Configurable requireIsVertexTRDmatched{"requireIsVertexTRDmatched", false, "require events with at least one of vertex contributors matched to TRD"}; + Configurable requireNoCollInTimeRangeStd{"requireNoCollInTimeRangeStd", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds"}; + Configurable requireNoCollInTimeRangeNarrow{"requireNoCollInTimeRangeNarrow", true, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds"}; + Configurable studyUPConly{"studyUPConly", true, "is UPC-only analysis"}; + Configurable useUPCflag{"useUPCflag", false, "select UPC flagged events"}; + + Configurable verbose{"verbose", false, "additional printouts"}; + + // Acceptance selections + Configurable rapidityCut{"rapidityCut", 0.5, "rapidity"}; + Configurable daughterEtaCut{"daughterEtaCut", 0.8, "max eta for daughters"}; + + Configurable doDaughterDCA{"doDaughterDCA", true, "dcaXY cut for daughter tracks"}; + + // Standard V0 topological criteria + struct : ConfigurableGroup { + Configurable v0cospa{"v0cospa", 0.97, "min V0 CosPA"}; + Configurable dcav0dau{"dcav0dau", 1.5, "max DCA V0 Daughters (cm)"}; + Configurable dcanegtopv{"dcanegtopv", .05, "min DCA Neg To PV (cm)"}; + Configurable dcapostopv{"dcapostopv", .05, "min DCA Pos To PV (cm)"}; + Configurable v0radius{"v0radius", 1.2, "minimum V0 radius (cm)"}; + Configurable v0radiusMax{"v0radiusMax", 1E5, "maximum V0 radius (cm)"}; + // Additional selection on the AP plot (exclusive for K0Short) + // original equation: lArmPt*5>std::fabs(lArmAlpha) + Configurable armPodCut{"armPodCut", 5.0f, "pT * (cut) > |alpha|, AP cut. Negative: no cut"}; + Configurable v0TypeSelection{"v0TypeSelection", 1, "select on a certain V0 type (leave negative if no selection desired)"}; + } v0cuts; + static constexpr float kLifetimeCutsV0[1][2] = {{30., 20.}}; + Configurable> lifetimecutV0{"lifetimecutV0", {kLifetimeCutsV0[0], 2, {"lifetimecutLambda", "lifetimecutK0S"}}, "lifetimecutV0"}; + + // Standard cascade topological criteria + struct : ConfigurableGroup { + Configurable casccospa{"casccospa", 0.97, "Casc CosPA"}; + Configurable dcacascdau{"dcacascdau", 1.2, "DCA Casc Daughters"}; + Configurable cascradius{"cascradius", 0.6, "minimum cascade radius (cm)"}; + Configurable cascradiusMax{"cascradiusMax", 1E5, "maximum cascade radius (cm)"}; + Configurable bachbaryoncospa{"bachbaryoncospa", 2, "Bachelor baryon CosPA"}; + Configurable bachbaryondcaxytopv{"bachbaryondcaxytopv", -1, "DCA bachelor baryon to PV"}; + Configurable dcamesontopv{"dcamesontopv", 0.1, "DCA of meson doughter track To PV"}; + Configurable dcabaryontopv{"dcabaryontopv", 0.05, "DCA of baryon doughter track To PV"}; + Configurable dcabachtopv{"dcabachtopv", 0.04, "DCA Bach To PV"}; + Configurable dcav0topv{"dcav0topv", 0.06, "DCA V0 To PV"}; + // Cascade specific selections + Configurable masswin{"masswin", 0.05, "mass window limit"}; + Configurable lambdamasswin{"lambdamasswin", 0.005, "V0 Mass window limit"}; + Configurable rejcomp{"rejcomp", 0.008, "competing Cascade rejection"}; + } casccuts; + Configurable doBachelorBaryonCut{"doBachelorBaryonCut", false, "Enable Bachelor-Baryon cut "}; + static constexpr float kNCtauCutsCasc[1][2] = {{6., 6.}}; + Configurable> nCtauCutCasc{"nCtauCutCasc", {kNCtauCutsCasc[0], 2, {"lifetimecutXi", "lifetimecutOmega"}}, "nCtauCutCasc"}; + + // UPC selections + SGSelector sgSelector; + struct : ConfigurableGroup { + Configurable fv0a{"fv0a", 50., "FV0A threshold"}; + Configurable ft0a{"ft0a", 100., "FT0A threshold"}; + Configurable ft0c{"ft0c", 50., "FT0C threshold"}; + Configurable zdc{"zdc", 1., "ZDC threshold"}; + Configurable genGapSide{"genGapSide", 0, "0 -- A, 1 -- C, 2 -- double"}; + } upcCuts; + + // Track quality + struct : ConfigurableGroup { + Configurable minTPCrows{"minTPCrows", 70, "minimum TPC crossed rows"}; + Configurable minITSclusters{"minITSclusters", -1, "minimum ITS clusters"}; + Configurable skipTPConly{"skipTPConly", false, "skip V0s comprised of at least one TPC only prong"}; + Configurable requireBachITSonly{"requireBachITSonly", false, "require that bachelor track is ITSonly (overrides TPC quality)"}; + Configurable requirePosITSonly{"requirePosITSonly", false, "require that positive track is ITSonly (overrides TPC quality)"}; + Configurable requireNegITSonly{"requireNegITSonly", false, "require that negative track is ITSonly (overrides TPC quality)"}; + } TrackConfigurations; + + // PID (TPC/TOF) + struct : ConfigurableGroup { + Configurable tpcPidNsigmaCut{"tpcPidNsigmaCut", 1e+6, "tpcPidNsigmaCut"}; + Configurable tofPidNsigmaCutLaPr{"tofPidNsigmaCutLaPr", 1e+6, "tofPidNsigmaCutLaPr"}; + Configurable tofPidNsigmaCutLaPi{"tofPidNsigmaCutLaPi", 1e+6, "tofPidNsigmaCutLaPi"}; + Configurable tofPidNsigmaCutK0Pi{"tofPidNsigmaCutK0Pi", 1e+6, "tofPidNsigmaCutK0Pi"}; + + Configurable tofPidNsigmaCutXiPi{"tofPidNsigmaCutXiPi", 1e+6, "tofPidNsigmaCutXiPi"}; + Configurable tofPidNsigmaCutOmegaKaon{"tofPidNsigmaCutOmegaKaon", 1e+6, "tofPidNsigmaCutOmegaKaon"}; + + Configurable doTPCQA{"doTPCQA", false, "do TPC QA histograms"}; + Configurable doTOFQA{"doTOFQA", false, "do TOF QA histograms"}; + + // PID (TOF) + Configurable maxDeltaTimeProton{"maxDeltaTimeProton", 1e+9, "check maximum allowed time"}; + Configurable maxDeltaTimePion{"maxDeltaTimePion", 1e+9, "check maximum allowed time"}; + Configurable maxDeltaTimeKaon{"maxDeltaTimeKaon", 1e+9, "check maximum allowed time"}; + } PIDConfigurations; + + Configurable doKienmaticQA{"doKienmaticQA", true, "do Kinematic QA histograms"}; + Configurable doDetectPropQA{"doDetectPropQA", 0, "do Detector/ITS map QA: 0: no, 1: 4D, 2: 5D with mass"}; + Configurable doPlainTopoQA{"doPlainTopoQA", true, "do simple 1D QA of candidates"}; + + struct : ConfigurableGroup { + ConfigurableAxis axisFT0Aampl{"axisFT0Aampl", {100, 0.0f, 2000.0f}, "FT0Aamplitude"}; + ConfigurableAxis axisFT0Campl{"axisFT0Campl", {100, 0.0f, 2000.0f}, "FT0Camplitude"}; + ConfigurableAxis axisFV0Aampl{"axisFV0Aampl", {100, 0.0f, 2000.0f}, "FV0Aamplitude"}; + ConfigurableAxis axisFDDAampl{"axisFDDAampl", {100, 0.0f, 2000.0f}, "FDDAamplitude"}; + ConfigurableAxis axisFDDCampl{"axisFDDCampl", {100, 0.0f, 2000.0f}, "FDDCamplitude"}; + ConfigurableAxis axisZNAampl{"axisZNAampl", {100, 0.0f, 250.0f}, "ZNAamplitude"}; + ConfigurableAxis axisZNCampl{"axisZNCampl", {100, 0.0f, 250.0f}, "ZNCamplitude"}; + } axisDetectors; + + // for MC + Configurable doMCAssociation{"doMCAssociation", true, "if MC, do MC association"}; + Configurable doTreatPiToMuon{"doTreatPiToMuon", false, "Take pi decay into muon into account in MC"}; + Configurable calculateFeeddownMatrix{"calculateFeeddownMatrix", true, "fill feeddown matrix if MC"}; + ConfigurableAxis axisGeneratorIds{"axisGeneratorIds", {256, -0.5f, 255.5f}, "axis for generatorIds"}; + + // fast check on occupancy + Configurable minOccupancy{"minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; + Configurable maxOccupancy{"maxOccupancy", 1000, "maximum occupancy from neighbouring collisions"}; + + // z vertex cut + Configurable maxZVtxPosition{"maxZVtxPosition", 10.0f, "max Z vtx position"}; + + // Kinematic axes + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for v0 analysis"}; + ConfigurableAxis axisPtXi{"axisPtXi", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for cascade analysis"}; + ConfigurableAxis axisPtCoarse{"axisPtCoarse", {VARIABLE_WIDTH, 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 7.0f, 10.0f, 15.0f}, "pt axis for QA"}; + ConfigurableAxis axisEta{"axisEta", {100, -2.0f, 2.0f}, "#eta"}; + ConfigurableAxis axisRap{"axisRap", {100, -2.0f, 2.0f}, "y"}; + + // Invariant mass axes + ConfigurableAxis axisK0Mass{"axisK0Mass", {200, 0.4f, 0.6f}, ""}; + ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.101f, 1.131f}, ""}; + ConfigurableAxis axisXiMass{"axisXiMass", {200, 1.28f, 1.36f}, ""}; + ConfigurableAxis axisOmegaMass{"axisOmegaMass", {200, 1.59f, 1.75f}, ""}; + std::vector axisInvMass = {axisK0Mass, + axisLambdaMass, + axisLambdaMass, + axisXiMass, + axisXiMass, + axisOmegaMass, + axisOmegaMass}; + + ConfigurableAxis axisNTracksGlobal{"axisNTracksGlobal", {101, -1.5f, 99.5f}, "Number of global tracks"}; + ConfigurableAxis axisNTracksPVeta1{"axisNTracksPVeta1", {100, -0.5f, 99.5f}, "Number of PV contributors in |eta| < 1"}; + ConfigurableAxis axisNTracksPVeta05{"axisNTracksPVeta05", {100, -0.5f, 99.5f}, "Number of PV contributors in |eta| < 0.5"}; + ConfigurableAxis axisNAssocColl{"axisNAssocColl", {10, -0.5f, 9.5f}, "Number of assoc. rec. collisions"}; + ConfigurableAxis axisNTracksTotalExceptITSonly{"axisNTracksTotalExceptITSonly", {100, -0.5f, 99.5f}, "Number of ITS-TPC and TPC only tracks"}; + ConfigurableAxis axisNchInvMass{"axisNchInvMass", {201, -1.5f, 199.5f}, "Number of charged particles for kTHnSparseF"}; + + ConfigurableAxis axisFT0Cqa{"axisFT0Cqa", + {VARIABLE_WIDTH, -1.5, -0.5, 0., 0.01, 0.05, 0.1, 0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 105.5}, + "FT0C (%)"}; + + ConfigurableAxis axisFT0C{"axisFT0C", + {VARIABLE_WIDTH, 0., 0.01, 0.05, 0.1, 0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 105.5}, + "FT0C (%)"}; + + ConfigurableAxis axisOccupancy{"axisOccupancy", {VARIABLE_WIDTH, 0.0f, 250.0f, 500.0f, 750.0f, 1000.0f, 1500.0f, 2000.0f, 3000.0f, 4500.0f, 6000.0f, 8000.0f, 10000.0f, 50000.0f}, "Occupancy"}; + + // UPC axes + ConfigurableAxis axisSelGap{"axisSelGap", {4, -1.5, 2.5}, "Gap side"}; + + // AP plot axes + ConfigurableAxis axisAPAlpha{"axisAPAlpha", {220, -1.1f, 1.1f}, "V0 AP alpha"}; + ConfigurableAxis axisAPQt{"axisAPQt", {220, 0.0f, 0.5f}, "V0 AP alpha"}; + + // MC coll assoc QA axis + ConfigurableAxis axisMonteCarloNch{"axisMonteCarloNch", {300, 0.0f, 3000.0f}, "N_{ch} MC"}; + + // Track quality axes + ConfigurableAxis axisTPCrows{"axisTPCrows", {160, -0.5f, 159.5f}, "N TPC rows"}; + ConfigurableAxis axisITSclus{"axisITSclus", {7, -0.5f, 6.5f}, "N ITS Clusters"}; + ConfigurableAxis axisITScluMap{"axisITScluMap", {128, -0.5f, 127.5f}, "ITS Cluster map"}; + ConfigurableAxis axisDetMap{"axisDetMap", {16, -0.5f, 15.5f}, "Detector use map"}; + ConfigurableAxis axisITScluMapCoarse{"axisITScluMapCoarse", {16, -3.5f, 12.5f}, "ITS Coarse cluster map"}; + ConfigurableAxis axisDetMapCoarse{"axisDetMapCoarse", {5, -0.5f, 4.5f}, "Detector Coarse user map"}; + + // Topological variable QA axes + ConfigurableAxis axisDCAtoPV{"axisDCAtoPV", {80, -4.0f, 4.0f}, "DCA (cm)"}; + ConfigurableAxis axisDCAdau{"axisDCAdau", {24, 0.0f, 1.2f}, "DCA (cm)"}; + ConfigurableAxis axisPointingAngle{"axisPointingAngle", {100, 0.0f, 0.5f}, "pointing angle (rad)"}; + ConfigurableAxis axisV0Radius{"axisV0Radius", {60, 0.0f, 60.0f}, "V0 2D radius (cm)"}; + ConfigurableAxis axisNsigmaTPC{"axisNsigmaTPC", {200, -10.0f, 10.0f}, "N sigma TPC"}; + ConfigurableAxis axisTPCsignal{"axisTPCsignal", {200, 0.0f, 200.0f}, "TPC signal"}; + ConfigurableAxis axisTOFdeltaT{"axisTOFdeltaT", {200, -5000.0f, 5000.0f}, "TOF Delta T (ps)"}; + ConfigurableAxis axisNctau{"axisNctau", {100, 0.0f, 10.0f}, "n c x tau"}; + + static constexpr std::string_view kParticlenames[] = {"K0Short", "Lambda", "AntiLambda", "Xi", "AntiXi", "Omega", "AntiOmega"}; + + void setBits(std::bitset& mask, std::initializer_list selections) + { + for (const int& sel : selections) { + mask.set(sel); + } + } + + template + void addTopoHistograms(HistogramRegistry& histos) + { + const bool isCascade = (partID > 2.5) ? true : false; + if (isCascade) { + histos.add(Form("%s/hCascCosPA", kParticlenames[partID].data()), "hCascCosPA", kTH2F, {axisPtCoarse, {100, 0.9f, 1.0f}}); + histos.add(Form("%s/hDCACascDaughters", kParticlenames[partID].data()), "hDCACascDaughters", kTH2F, {axisPtCoarse, {44, 0.0f, 2.2f}}); + histos.add(Form("%s/hCascRadius", kParticlenames[partID].data()), "hCascRadius", kTH2D, {axisPtCoarse, {500, 0.0f, 50.0f}}); + histos.add(Form("%s/hMesonDCAToPV", kParticlenames[partID].data()), "hMesonDCAToPV", kTH2F, {axisPtCoarse, axisDCAtoPV}); + histos.add(Form("%s/hBaryonDCAToPV", kParticlenames[partID].data()), "hBaryonDCAToPV", kTH2F, {axisPtCoarse, axisDCAtoPV}); + histos.add(Form("%s/hBachDCAToPV", kParticlenames[partID].data()), "hBachDCAToPV", kTH2F, {axisPtCoarse, {200, -1.0f, 1.0f}}); + histos.add(Form("%s/hV0CosPA", kParticlenames[partID].data()), "hV0CosPA", kTH2F, {axisPtCoarse, {100, 0.9f, 1.0f}}); + histos.add(Form("%s/hV0Radius", kParticlenames[partID].data()), "hV0Radius", kTH2D, {axisPtCoarse, axisV0Radius}); + histos.add(Form("%s/hDCAV0Daughters", kParticlenames[partID].data()), "hDCAV0Daughters", kTH2F, {axisPtCoarse, axisDCAdau}); + histos.add(Form("%s/hDCAV0ToPV", kParticlenames[partID].data()), "hDCAV0ToPV", kTH2F, {axisPtCoarse, {44, 0.0f, 2.2f}}); + histos.add(Form("%s/hMassLambdaDau", kParticlenames[partID].data()), "hMassLambdaDau", kTH2F, {axisPtCoarse, axisLambdaMass}); + histos.add(Form("%s/hNctau", kParticlenames[partID].data()), "hNctau", kTH2F, {axisPtCoarse, axisNctau}); + if (doBachelorBaryonCut) { + histos.add(Form("%s/hBachBaryonCosPA", kParticlenames[partID].data()), "hBachBaryonCosPA", kTH2F, {axisPtCoarse, {100, 0.0f, 1.0f}}); + histos.add(Form("%s/hBachBaryonDCAxyToPV", kParticlenames[partID].data()), "hBachBaryonDCAxyToPV", kTH2F, {axisPtCoarse, {300, -3.0f, 3.0f}}); + } + } else { + histos.add(Form("%s/hPosDCAToPV", kParticlenames[partID].data()), "hPosDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add(Form("%s/hNegDCAToPV", kParticlenames[partID].data()), "hNegDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add(Form("%s/hDCADaughters", kParticlenames[partID].data()), "hDCADaughters", kTH1F, {axisDCAdau}); + histos.add(Form("%s/hPointingAngle", kParticlenames[partID].data()), "hPointingAngle", kTH1F, {axisPointingAngle}); + histos.add(Form("%s/hV0Radius", kParticlenames[partID].data()), "hV0Radius", kTH1F, {axisV0Radius}); + histos.add(Form("%s/h2dPositiveITSvsTPCpts", kParticlenames[partID].data()), "h2dPositiveITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add(Form("%s/h2dNegativeITSvsTPCpts", kParticlenames[partID].data()), "h2dNegativeITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + } + } + + template + void addTPCQAHistograms(HistogramRegistry& histos) + { + const bool isCascade = (partID > 2.5) ? true : false; + histos.add(Form("%s/h3dPosNsigmaTPC", kParticlenames[partID].data()), "h3dPosNsigmaTPC", kTH3F, {axisFT0C, axisPtCoarse, axisNsigmaTPC}); + histos.add(Form("%s/h3dNegNsigmaTPC", kParticlenames[partID].data()), "h3dNegNsigmaTPC", kTH3F, {axisFT0C, axisPtCoarse, axisNsigmaTPC}); + histos.add(Form("%s/h3dPosTPCsignal", kParticlenames[partID].data()), "h3dPosTPCsignal", kTH3F, {axisFT0C, axisPtCoarse, axisTPCsignal}); + histos.add(Form("%s/h3dNegTPCsignal", kParticlenames[partID].data()), "h3dNegTPCsignal", kTH3F, {axisFT0C, axisPtCoarse, axisTPCsignal}); + + histos.add(Form("%s/h3dPosNsigmaTPCvsTrackPtot", kParticlenames[partID].data()), "h3dPosNsigmaTPCvsTrackPtot", kTH3F, {axisFT0C, axisPtCoarse, axisNsigmaTPC}); + histos.add(Form("%s/h3dNegNsigmaTPCvsTrackPtot", kParticlenames[partID].data()), "h3dNegNsigmaTPCvsTrackPtot", kTH3F, {axisFT0C, axisPtCoarse, axisNsigmaTPC}); + + histos.add(Form("%s/h3dPosTPCsignalVsTrackPtot", kParticlenames[partID].data()), "h3dPosTPCsignalVsTrackPtot", kTH3F, {axisFT0C, axisPtCoarse, axisTPCsignal}); + histos.add(Form("%s/h3dNegTPCsignalVsTrackPtot", kParticlenames[partID].data()), "h3dNegTPCsignalVsTrackPtot", kTH3F, {axisFT0C, axisPtCoarse, axisTPCsignal}); + + histos.add(Form("%s/h3dPosNsigmaTPCvsTrackPt", kParticlenames[partID].data()), "h3dPosNsigmaTPCvsTrackPt", kTH3F, {axisFT0C, axisPtCoarse, axisNsigmaTPC}); + histos.add(Form("%s/h3dNegNsigmaTPCvsTrackPt", kParticlenames[partID].data()), "h3dNegNsigmaTPCvsTrackPt", kTH3F, {axisFT0C, axisPtCoarse, axisNsigmaTPC}); + + histos.add(Form("%s/h3dPosTPCsignalVsTrackPt", kParticlenames[partID].data()), "h3dPosTPCsignalVsTrackPt", kTH3F, {axisFT0C, axisPtCoarse, axisTPCsignal}); + histos.add(Form("%s/h3dNegTPCsignalVsTrackPt", kParticlenames[partID].data()), "h3dNegTPCsignalVsTrackPt", kTH3F, {axisFT0C, axisPtCoarse, axisTPCsignal}); + + if (isCascade) { + histos.add(Form("%s/h3dBachTPCsignal", kParticlenames[partID].data()), "h3dBachTPCsignal", kTH3F, {axisFT0C, axisPtCoarse, axisTPCsignal}); + histos.add(Form("%s/h3dBachNsigmaTPC", kParticlenames[partID].data()), "h3dBachNsigmaTPC", kTH3F, {axisFT0C, axisPtCoarse, axisNsigmaTPC}); + histos.add(Form("%s/h3dBachNsigmaTPCvsTrackPtot", kParticlenames[partID].data()), "h3dBachNsigmaTPCvsTrackPtot", kTH3F, {axisFT0C, axisPtCoarse, axisNsigmaTPC}); + histos.add(Form("%s/h3dBachTPCsignalVsTrackPtot", kParticlenames[partID].data()), "h3dBachTPCsignalVsTrackPtot", kTH3F, {axisFT0C, axisPtCoarse, axisTPCsignal}); + histos.add(Form("%s/h3dBachNsigmaTPCvsTrackPt", kParticlenames[partID].data()), "h3dBachNsigmaTPCvsTrackPt", kTH3F, {axisFT0C, axisPtCoarse, axisNsigmaTPC}); + histos.add(Form("%s/h3dBachTPCsignalVsTrackPt", kParticlenames[partID].data()), "h3dBachTPCsignalVsTrackPt", kTH3F, {axisFT0C, axisPtCoarse, axisTPCsignal}); + } + } + + template + void addTOFQAHistograms(HistogramRegistry& histos) + { + const bool isCascade = (partID > 2.5) ? true : false; + histos.add(Form("%s/h3dPosTOFdeltaT", kParticlenames[partID].data()), "h3dPosTOFdeltaT", kTH3F, {axisFT0C, axisPtCoarse, axisTOFdeltaT}); + histos.add(Form("%s/h3dNegTOFdeltaT", kParticlenames[partID].data()), "h3dNegTOFdeltaT", kTH3F, {axisFT0C, axisPtCoarse, axisTOFdeltaT}); + histos.add(Form("%s/h3dPosTOFdeltaTvsTrackPtot", kParticlenames[partID].data()), "h3dPosTOFdeltaTvsTrackPtot", kTH3F, {axisFT0C, axisPtCoarse, axisTOFdeltaT}); + histos.add(Form("%s/h3dNegTOFdeltaTvsTrackPtot", kParticlenames[partID].data()), "h3dNegTOFdeltaTvsTrackPtot", kTH3F, {axisFT0C, axisPtCoarse, axisTOFdeltaT}); + histos.add(Form("%s/h3dPosTOFdeltaTvsTrackPt", kParticlenames[partID].data()), "h3dPosTOFdeltaTvsTrackPt", kTH3F, {axisFT0C, axisPtCoarse, axisTOFdeltaT}); + histos.add(Form("%s/h3dNegTOFdeltaTvsTrackPt", kParticlenames[partID].data()), "h3dNegTOFdeltaTvsTrackPt", kTH3F, {axisFT0C, axisPtCoarse, axisTOFdeltaT}); + if (isCascade) { + histos.add(Form("%s/h3dBachTOFdeltaT", kParticlenames[partID].data()), "h3dBachTOFdeltaT", kTH3F, {axisFT0C, axisPtCoarse, axisTOFdeltaT}); + histos.add(Form("%s/h3dBachTOFdeltaTvsTrackPtot", kParticlenames[partID].data()), "h3dBachTOFdeltaTvsTrackPtot", kTH3F, {axisFT0C, axisPtCoarse, axisTOFdeltaT}); + histos.add(Form("%s/h3dBachTOFdeltaTvsTrackPt", kParticlenames[partID].data()), "h3dBachTOFdeltaTvsTrackPt", kTH3F, {axisFT0C, axisPtCoarse, axisTOFdeltaT}); + } + } + + template + void addKinematicQAHistograms(HistogramRegistry& histos) + { + const bool isCascade = (partID > 2.5) ? true : false; + histos.add(Form("%s/h3dPosEtaPt", kParticlenames[partID].data()), "h3dPosEtaPt", kTH3F, {axisPtCoarse, axisEta, axisSelGap}); + histos.add(Form("%s/h3dNegEtaPt", kParticlenames[partID].data()), "h3dNegEtaPt", kTH3F, {axisPtCoarse, axisEta, axisSelGap}); + histos.add(Form("%s/h3dRapPt", kParticlenames[partID].data()), "h3dRapPt", kTH3F, {axisPtCoarse, axisRap, axisSelGap}); + if (isCascade) { + histos.add(Form("%s/h3dBachEtaPt", kParticlenames[partID].data()), "h3dBachEtaPt", kTH3F, {axisPtCoarse, axisEta, axisSelGap}); + } + } + + template + void addDetectorPropHistograms(HistogramRegistry& histos) + { + const bool isCascade = (partID > 2.5) ? true : false; + if (doDetectPropQA == 1) { + if (isCascade) { + histos.add(Form("%s/h8dDetectPropVsCentrality", kParticlenames[partID].data()), "h8dDetectPropVsCentrality", kTHnSparseF, {axisFT0C, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisPtCoarse}); + } else { + histos.add(Form("%s/h6dDetectPropVsCentrality", kParticlenames[partID].data()), "h6dDetectPropVsCentrality", kTHnSparseF, {axisFT0C, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisPtCoarse}); + } + histos.add(Form("%s/h4dPosDetectPropVsCentrality", kParticlenames[partID].data()), "h4dPosDetectPropVsCentrality", kTHnSparseF, {axisFT0C, axisDetMap, axisITScluMap, axisPtCoarse}); + histos.add(Form("%s/h4dNegDetectPropVsCentrality", kParticlenames[partID].data()), "h4dNegDetectPropVsCentrality", kTHnSparseF, {axisFT0C, axisDetMap, axisITScluMap, axisPtCoarse}); + histos.add(Form("%s/h4dBachDetectPropVsCentrality", kParticlenames[partID].data()), "h4dBachDetectPropVsCentrality", kTHnSparseF, {axisFT0C, axisDetMap, axisITScluMap, axisPtCoarse}); + } + if (doDetectPropQA == 2) { + if (isCascade) { + histos.add(Form("%s/h9dDetectPropVsCentrality", kParticlenames[partID].data()), "h9dDetectPropVsCentrality", kTHnSparseF, {axisFT0C, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisPtCoarse, axisInvMass.at(partID)}); + } else { + histos.add(Form("%s/h7dDetectPropVsCentrality", kParticlenames[partID].data()), "h7dDetectPropVsCentrality", kTHnSparseF, {axisFT0C, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisPtCoarse, axisInvMass.at(partID)}); + } + histos.add(Form("%s/h5dPosDetectPropVsCentrality", kParticlenames[partID].data()), "h5dPosDetectPropVsCentrality", kTHnSparseF, {axisFT0C, axisDetMap, axisITScluMap, axisPtCoarse, axisInvMass.at(partID)}); + histos.add(Form("%s/h5dNegDetectPropVsCentrality", kParticlenames[partID].data()), "h5dNegDetectPropVsCentrality", kTHnSparseF, {axisFT0C, axisDetMap, axisITScluMap, axisPtCoarse, axisInvMass.at(partID)}); + histos.add(Form("%s/h5dBachDetectPropVsCentrality", kParticlenames[partID].data()), "h5dBachDetectPropVsCentrality", kTHnSparseF, {axisFT0C, axisDetMap, axisITScluMap, axisPtCoarse, axisInvMass.at(partID)}); + } + } + + template + void addHistograms(HistogramRegistry& histos) + { + histos.add(Form("%s/h7dMass", kParticlenames[partID].data()), "h7dMass", kTHnSparseF, {axisFT0C, axisPt, axisInvMass.at(partID), axisSelGap, axisNchInvMass, axisRap, axisEta}); + histos.add(Form("%s/h2dMass", kParticlenames[partID].data()), "h2dMass", kTH2F, {axisInvMass.at(partID), axisSelGap}); + if (doPlainTopoQA) { + addTopoHistograms(histos); + } + if (PIDConfigurations.doTPCQA) { + addTPCQAHistograms(histos); + } + if (PIDConfigurations.doTOFQA) { + addTOFQAHistograms(histos); + } + if (doKienmaticQA) { + addKinematicQAHistograms(histos); + } + addDetectorPropHistograms(histos); + } + + template + void fillHistogramsV0(TCand cand, TCollision coll, int gap) + { + float invMass = 0; + float centrality = coll.centFT0C(); + float pT = cand.pt(); + float rapidity = 1e6; + + float tpcNsigmaPos = 0; + float tpcNsigmaNeg = 0; + float tofDeltaTPos = 0; + float tofDeltaTNeg = 0; + + auto posTrackExtra = cand.template posTrackExtra_as(); + auto negTrackExtra = cand.template negTrackExtra_as(); + + bool posIsFromAfterburner = posTrackExtra.itsChi2PerNcl() < 0; + bool negIsFromAfterburner = negTrackExtra.itsChi2PerNcl() < 0; + + uint posDetMap = computeDetBitmap(posTrackExtra.detectorMap()); + int posITSclusMap = computeITSclusBitmap(posTrackExtra.itsClusterMap(), posIsFromAfterburner); + uint negDetMap = computeDetBitmap(negTrackExtra.detectorMap()); + int negITSclusMap = computeITSclusBitmap(negTrackExtra.itsClusterMap(), negIsFromAfterburner); + + if (partID == 0) { + histos.fill(HIST("generalQA/h2dArmenterosSelected"), cand.alpha(), cand.qtarm()); + invMass = cand.mK0Short(); + rapidity = cand.yK0Short(); + if (PIDConfigurations.doTOFQA) { + tofDeltaTPos = cand.posTOFDeltaTK0Pi(); + tofDeltaTNeg = cand.negTOFDeltaTK0Pi(); + } + if (PIDConfigurations.doTPCQA) { + tpcNsigmaPos = posTrackExtra.tpcNSigmaPi(); + tpcNsigmaNeg = negTrackExtra.tpcNSigmaPi(); + } + } else if (partID == 1) { + invMass = cand.mLambda(); + rapidity = cand.yLambda(); + if (PIDConfigurations.doTOFQA) { + tofDeltaTPos = cand.posTOFDeltaTLaPr(); + tofDeltaTNeg = cand.negTOFDeltaTLaPi(); + } + if (PIDConfigurations.doTPCQA) { + tpcNsigmaPos = posTrackExtra.tpcNSigmaPr(); + tpcNsigmaNeg = negTrackExtra.tpcNSigmaPi(); + } + } else if (partID == 2) { + invMass = cand.mAntiLambda(); + rapidity = cand.yLambda(); + if (PIDConfigurations.doTOFQA) { + tofDeltaTPos = cand.posTOFDeltaTLaPi(); + tofDeltaTNeg = cand.negTOFDeltaTLaPr(); + } + if (PIDConfigurations.doTPCQA) { + tpcNsigmaPos = posTrackExtra.tpcNSigmaPi(); + tpcNsigmaNeg = negTrackExtra.tpcNSigmaPr(); + } + } else { + LOG(fatal) << "Particle is unknown!"; + } + + histos.fill(HIST(kParticlenames[partID]) + HIST("/h2dMass"), invMass, gap); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h7dMass"), centrality, pT, invMass, gap, coll.multNTracksGlobal(), rapidity, cand.eta()); + if (doKienmaticQA) { + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosEtaPt"), pT, cand.positiveeta(), gap); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegEtaPt"), pT, cand.negativeeta(), gap); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dRapPt"), pT, rapidity, gap); + } + if (doPlainTopoQA) { + histos.fill(HIST(kParticlenames[partID]) + HIST("/hPosDCAToPV"), cand.dcapostopv()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/hNegDCAToPV"), cand.dcanegtopv()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/hDCADaughters"), cand.dcaV0daughters()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/hPointingAngle"), std::acos(cand.v0cosPA())); + histos.fill(HIST(kParticlenames[partID]) + HIST("/hV0Radius"), cand.v0radius()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h2dPositiveITSvsTPCpts"), posTrackExtra.tpcCrossedRows(), posTrackExtra.itsNCls()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h2dNegativeITSvsTPCpts"), negTrackExtra.tpcCrossedRows(), negTrackExtra.itsNCls()); + } + if (doDetectPropQA == 1) { + histos.fill(HIST(kParticlenames[partID]) + HIST("/h6dDetectPropVsCentrality"), centrality, posDetMap, posITSclusMap, negDetMap, negITSclusMap, pT); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h4dPosDetectPropVsCentrality"), centrality, posTrackExtra.detectorMap(), posTrackExtra.itsClusterMap(), pT); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h4dNegDetectPropVsCentrality"), centrality, negTrackExtra.detectorMap(), negTrackExtra.itsClusterMap(), pT); + } + if (doDetectPropQA == 2) { + histos.fill(HIST(kParticlenames[partID]) + HIST("/h7dPosDetectPropVsCentrality"), centrality, posDetMap, posITSclusMap, negDetMap, negITSclusMap, pT, invMass); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h5dPosDetectPropVsCentrality"), centrality, posTrackExtra.detectorMap(), posTrackExtra.itsClusterMap(), pT, invMass); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h5dNegDetectPropVsCentrality"), centrality, negTrackExtra.detectorMap(), negTrackExtra.itsClusterMap(), pT, invMass); + } + if (PIDConfigurations.doTPCQA) { + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTPCsignal"), centrality, pT, posTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTPCsignal"), centrality, pT, negTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTPCsignalVsTrackPtot"), centrality, cand.positivept() * std::cosh(cand.positiveeta()), posTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTPCsignalVsTrackPtot"), centrality, cand.negativept() * std::cosh(cand.negativeeta()), negTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTPCsignalVsTrackPt"), centrality, cand.positivept(), posTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTPCsignalVsTrackPt"), centrality, cand.negativept(), negTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosNsigmaTPCvsTrackPt"), centrality, cand.positivept(), posTrackExtra.tpcNSigmaPi()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegNsigmaTPCvsTrackPt"), centrality, cand.negativept(), negTrackExtra.tpcNSigmaPi()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosNsigmaTPCvsTrackPtot"), centrality, cand.positivept() * std::cosh(cand.positiveeta()), tpcNsigmaPos); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegNsigmaTPCvsTrackPtot"), centrality, cand.negativept() * std::cosh(cand.negativeeta()), tpcNsigmaNeg); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosNsigmaTPC"), centrality, pT, tpcNsigmaPos); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegNsigmaTPC"), centrality, pT, tpcNsigmaNeg); + } + if (PIDConfigurations.doTOFQA) { + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTOFdeltaTvsTrackPt"), centrality, cand.positivept(), tofDeltaTPos); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTOFdeltaTvsTrackPt"), centrality, cand.negativept(), tofDeltaTNeg); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTOFdeltaT"), centrality, pT, tofDeltaTPos); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTOFdeltaT"), centrality, pT, tofDeltaTNeg); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTOFdeltaTvsTrackPtot"), centrality, cand.positivept() * std::cosh(cand.positiveeta()), tofDeltaTPos); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTOFdeltaTvsTrackPtot"), centrality, cand.negativept() * std::cosh(cand.negativeeta()), tofDeltaTNeg); + } + } + + template + void fillHistogramsCasc(TCand cand, TCollision coll, int gap) + { + float invMass = 0; + float centrality = coll.centFT0C(); + float pT = cand.pt(); + float rapidity = 1e6; + + // Access daughter tracks + auto posTrackExtra = cand.template posTrackExtra_as(); + auto negTrackExtra = cand.template negTrackExtra_as(); + auto bachTrackExtra = cand.template bachTrackExtra_as(); + + bool posIsFromAfterburner = posTrackExtra.itsChi2PerNcl() < 0; + bool negIsFromAfterburner = negTrackExtra.itsChi2PerNcl() < 0; + bool bachIsFromAfterburner = bachTrackExtra.itsChi2PerNcl() < 0; + + uint posDetMap = computeDetBitmap(posTrackExtra.detectorMap()); + int posITSclusMap = computeITSclusBitmap(posTrackExtra.itsClusterMap(), posIsFromAfterburner); + uint negDetMap = computeDetBitmap(negTrackExtra.detectorMap()); + int negITSclusMap = computeITSclusBitmap(negTrackExtra.itsClusterMap(), negIsFromAfterburner); + uint bachDetMap = computeDetBitmap(bachTrackExtra.detectorMap()); + int bachITSclusMap = computeITSclusBitmap(bachTrackExtra.itsClusterMap(), bachIsFromAfterburner); + + // c x tau + float decayPos = std::hypot(cand.x() - coll.posX(), cand.y() - coll.posY(), cand.z() - coll.posZ()); + float totalMom = std::hypot(cand.px(), cand.py(), cand.pz()); + + float ctau = 0; + + float tpcNsigmaPos = 0; + float tpcNsigmaNeg = 0; + float tpcNsigmaBach = 0; + float tofDeltaTPos = 0; + float tofDeltaTNeg = 0; + float tofDeltaTBach = 0; + + if (partID == 3) { + invMass = cand.mXi(); + ctau = totalMom != 0 ? o2::constants::physics::MassXiMinus * decayPos / (totalMom * ctauxiPDG) : 1e6; + rapidity = cand.yXi(); + + if (PIDConfigurations.doTPCQA) { + tpcNsigmaPos = posTrackExtra.tpcNSigmaPr(); + tpcNsigmaNeg = negTrackExtra.tpcNSigmaPi(); + tpcNsigmaBach = bachTrackExtra.tpcNSigmaPi(); + } + if (PIDConfigurations.doTOFQA) { + tofDeltaTPos = cand.posTOFDeltaTXiPr(); + tofDeltaTNeg = cand.negTOFDeltaTXiPi(); + tofDeltaTBach = cand.bachTOFDeltaTXiPi(); + } + } else if (partID == 4) { + invMass = cand.mXi(); + ctau = totalMom != 0 ? o2::constants::physics::MassXiPlusBar * decayPos / (totalMom * ctauxiPDG) : 1e6; + rapidity = cand.yXi(); + + if (PIDConfigurations.doTPCQA) { + tpcNsigmaPos = posTrackExtra.tpcNSigmaPi(); + tpcNsigmaNeg = negTrackExtra.tpcNSigmaPr(); + tpcNsigmaBach = bachTrackExtra.tpcNSigmaPi(); + } + if (PIDConfigurations.doTOFQA) { + tofDeltaTPos = cand.posTOFDeltaTXiPi(); + tofDeltaTNeg = cand.negTOFDeltaTXiPr(); + tofDeltaTBach = cand.bachTOFDeltaTXiPi(); + } + + } else if (partID == 5) { + invMass = cand.mOmega(); + ctau = totalMom != 0 ? o2::constants::physics::MassOmegaMinus * decayPos / (totalMom * ctauomegaPDG) : 1e6; + rapidity = cand.yOmega(); + + if (PIDConfigurations.doTPCQA) { + tpcNsigmaPos = posTrackExtra.tpcNSigmaPr(); + tpcNsigmaNeg = negTrackExtra.tpcNSigmaPi(); + tpcNsigmaBach = bachTrackExtra.tpcNSigmaKa(); + } + if (PIDConfigurations.doTOFQA) { + tofDeltaTPos = cand.posTOFDeltaTOmPi(); + tofDeltaTNeg = cand.posTOFDeltaTOmPr(); + tofDeltaTBach = cand.bachTOFDeltaTOmKa(); + } + + } else if (partID == 6) { + invMass = cand.mOmega(); + ctau = totalMom != 0 ? o2::constants::physics::MassOmegaPlusBar * decayPos / (totalMom * ctauomegaPDG) : 1e6; + rapidity = cand.yOmega(); + + if (PIDConfigurations.doTPCQA) { + tpcNsigmaPos = posTrackExtra.tpcNSigmaPi(); + tpcNsigmaNeg = negTrackExtra.tpcNSigmaPr(); + tpcNsigmaBach = bachTrackExtra.tpcNSigmaKa(); + } + if (PIDConfigurations.doTOFQA) { + tofDeltaTPos = cand.posTOFDeltaTOmPr(); + tofDeltaTNeg = cand.posTOFDeltaTOmPi(); + tofDeltaTBach = cand.bachTOFDeltaTOmKa(); + } + } + histos.fill(HIST(kParticlenames[partID]) + HIST("/h2dMass"), invMass, gap); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h7dMass"), centrality, pT, invMass, gap, coll.multNTracksGlobal(), rapidity, cand.eta()); + if (doKienmaticQA) { + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosEtaPt"), pT, cand.positiveeta(), gap); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegEtaPt"), pT, cand.negativeeta(), gap); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dBachEtaPt"), pT, cand.bacheloreta(), gap); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dRapPt"), pT, rapidity, gap); + } + if (doPlainTopoQA) { + histos.fill(HIST(kParticlenames[partID]) + HIST("/hCascCosPA"), pT, cand.casccosPA(coll.posX(), coll.posY(), coll.posZ())); + histos.fill(HIST(kParticlenames[partID]) + HIST("/hDCACascDaughters"), pT, cand.dcacascdaughters()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/hCascRadius"), pT, cand.cascradius()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/hMesonDCAToPV"), pT, cand.dcanegtopv()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/hBaryonDCAToPV"), pT, cand.dcapostopv()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/hBachDCAToPV"), pT, cand.dcabachtopv()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/hV0CosPA"), pT, cand.v0cosPA(coll.posX(), coll.posY(), coll.posZ())); + histos.fill(HIST(kParticlenames[partID]) + HIST("/hV0Radius"), pT, cand.v0radius()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/hDCAV0Daughters"), pT, cand.dcaV0daughters()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/hDCAV0ToPV"), pT, std::fabs(cand.dcav0topv(coll.posX(), coll.posY(), coll.posZ()))); + histos.fill(HIST(kParticlenames[partID]) + HIST("/hMassLambdaDau"), pT, cand.mLambda()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/hNctau"), pT, ctau); + } + if (PIDConfigurations.doTPCQA) { + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosNsigmaTPC"), centrality, pT, tpcNsigmaPos); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegNsigmaTPC"), centrality, pT, tpcNsigmaNeg); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dBachNsigmaTPC"), centrality, pT, tpcNsigmaBach); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTPCsignal"), centrality, pT, posTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTPCsignal"), centrality, pT, negTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dBachTPCsignal"), centrality, pT, bachTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosNsigmaTPCvsTrackPtot"), centrality, cand.positivept() * std::cosh(cand.positiveeta()), tpcNsigmaPos); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegNsigmaTPCvsTrackPtot"), centrality, cand.negativept() * std::cosh(cand.negativeeta()), tpcNsigmaNeg); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dBachNsigmaTPCvsTrackPtot"), centrality, cand.bachelorpt() * std::cosh(cand.bacheloreta()), tpcNsigmaBach); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTPCsignalVsTrackPtot"), centrality, cand.positivept() * std::cosh(cand.positiveeta()), posTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTPCsignalVsTrackPtot"), centrality, cand.negativept() * std::cosh(cand.negativeeta()), negTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dBachTPCsignalVsTrackPtot"), centrality, cand.bachelorpt() * std::cosh(cand.bacheloreta()), bachTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosNsigmaTPCvsTrackPt"), centrality, cand.positivept(), tpcNsigmaPos); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegNsigmaTPCvsTrackPt"), centrality, cand.negativept(), tpcNsigmaNeg); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dBachNsigmaTPCvsTrackPt"), centrality, cand.bachelorpt(), tpcNsigmaBach); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTPCsignalVsTrackPt"), centrality, cand.positivept(), posTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTPCsignalVsTrackPt"), centrality, cand.negativept(), negTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dBachTPCsignalVsTrackPt"), centrality, cand.bachelorpt(), bachTrackExtra.tpcSignal()); + } + if (PIDConfigurations.doTOFQA) { + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTOFdeltaT"), centrality, pT, tofDeltaTPos); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTOFdeltaT"), centrality, pT, tofDeltaTNeg); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dBachTOFdeltaT"), centrality, pT, tofDeltaTBach); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTOFdeltaTvsTrackPtot"), centrality, cand.positivept() * std::cosh(cand.positiveeta()), tofDeltaTPos); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTOFdeltaTvsTrackPtot"), centrality, cand.negativept() * std::cosh(cand.negativeeta()), tofDeltaTNeg); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dBachTOFdeltaTvsTrackPtot"), centrality, cand.bachelorpt() * std::cosh(cand.bacheloreta()), tofDeltaTBach); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTOFdeltaTvsTrackPt"), centrality, cand.positivept(), tofDeltaTPos); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTOFdeltaTvsTrackPt"), centrality, cand.negativept(), tofDeltaTNeg); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dBachTOFdeltaTvsTrackPt"), centrality, cand.bachelorpt(), tofDeltaTBach); + } + if (doDetectPropQA == 1) { + histos.fill(HIST(kParticlenames[partID]) + HIST("/h8dDetectPropVsCentrality"), centrality, posDetMap, posITSclusMap, negDetMap, negITSclusMap, bachDetMap, bachITSclusMap, pT); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h4dPosDetectPropVsCentrality"), centrality, posTrackExtra.detectorMap(), posTrackExtra.itsClusterMap(), pT); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h4dNegDetectPropVsCentrality"), centrality, negTrackExtra.detectorMap(), negTrackExtra.itsClusterMap(), pT); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h4dBachDetectPropVsCentrality"), centrality, bachTrackExtra.detectorMap(), bachTrackExtra.itsClusterMap(), pT); + } + if (doDetectPropQA == 2) { + histos.fill(HIST(kParticlenames[partID]) + HIST("/h9dDetectPropVsCentrality"), centrality, posDetMap, posITSclusMap, negDetMap, negITSclusMap, bachDetMap, bachITSclusMap, pT, invMass); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h5dPosDetectPropVsCentrality"), centrality, posTrackExtra.detectorMap(), posTrackExtra.itsClusterMap(), pT, invMass); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h5dNegDetectPropVsCentrality"), centrality, negTrackExtra.detectorMap(), negTrackExtra.itsClusterMap(), pT, invMass); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h5dBachDetectPropVsCentrality"), centrality, bachTrackExtra.detectorMap(), bachTrackExtra.itsClusterMap(), pT, invMass); + } + } + + void init(InitContext const&) + { + if (doprocessV0s && doprocessCascades) { + LOG(fatal) << "Unable to analyze both v0s and cascades simultaneously. Please enable only one process at a time"; + } + + if ((doprocessV0sMC || doprocessCascadesMC || doprocessGenerated) && (doprocessV0s || doprocessCascades)) { + LOG(fatal) << "Cannot analyze both data and MC simultaneously. Please select one of them."; + } + + // initialise bit masks + setBits(maskTopologicalV0, {selV0CosPA, selDCANegToPV, selDCAPosToPV, selDCAV0Dau, selV0Radius, selV0RadiusMax}); + setBits(maskTopologicalCasc, {selCascCosPA, selDCACascDau, selCascRadius, selCascRadiusMax, selBachToPV, selMesonToPV, selBaryonToPV, + selDCAV0ToPV, selV0CosPA, selDCAV0Dau, selV0Radius, selV0RadiusMax, selLambdaMassWin}); + + if (doBachelorBaryonCut) + maskTopologicalCasc.set(selBachBaryon); + + setBits(maskKinematicV0, {selPosEta, selNegEta}); + setBits(maskKinematicCasc, {selPosEta, selNegEta, selBachEta}); + + if (doDaughterDCA) { + maskKinematicV0.set(selDauDCA); + maskKinematicCasc.set(selDauDCA); + } + + // Specific masks + setBits(maskK0ShortSpecific, {selK0ShortRapidity, selK0ShortCTau, selK0ShortArmenteros, selConsiderK0Short}); + setBits(maskLambdaSpecific, {selLambdaRapidity, selLambdaCTau, selConsiderLambda}); + setBits(maskAntiLambdaSpecific, {selLambdaRapidity, selLambdaCTau, selConsiderAntiLambda}); + setBits(maskXiSpecific, {selXiRapidity, selXiCTau, selRejCompXi, selMassWinXi, selConsiderXi}); + setBits(maskAntiXiSpecific, {selXiRapidity, selXiCTau, selRejCompXi, selMassWinXi, selConsiderAntiXi}); + setBits(maskOmegaSpecific, {selOmegaRapidity, selOmegaCTau, selRejCompOmega, selMassWinOmega, selConsiderOmega}); + setBits(maskAntiOmegaSpecific, {selOmegaRapidity, selOmegaCTau, selRejCompOmega, selMassWinOmega, selConsiderAntiOmega}); + + // ask for specific TPC/TOF PID selections + // positive track + if (TrackConfigurations.requirePosITSonly) { + setBits(maskTrackPropertiesV0, {selPosItsOnly, selPosGoodITSTrack}); + } else { + setBits(maskTrackPropertiesV0, {selPosGoodTPCTrack, selPosGoodITSTrack}); + // TPC signal is available: ask for positive track PID + if (PIDConfigurations.tpcPidNsigmaCut < 1e+5) { // safeguard for no cut + maskK0ShortSpecific.set(selTPCPIDPositivePion); + maskLambdaSpecific.set(selTPCPIDPositiveProton); + maskAntiLambdaSpecific.set(selTPCPIDPositivePion); + + maskXiSpecific.set(selTPCPIDPositiveProton); + maskAntiXiSpecific.set(selTPCPIDPositivePion); + maskOmegaSpecific.set(selTPCPIDPositiveProton); + maskAntiOmegaSpecific.set(selTPCPIDPositivePion); + } + // TOF PID + if (PIDConfigurations.tofPidNsigmaCutK0Pi < 1e+5) { // safeguard for no cut + setBits(maskK0ShortSpecific, {selTOFNSigmaPositivePionK0Short, selTOFDeltaTPositivePionK0Short}); + } + if (PIDConfigurations.tofPidNsigmaCutLaPr < 1e+5) { // safeguard for no cut + setBits(maskLambdaSpecific, {selTOFNSigmaPositiveProtonLambda, selTOFDeltaTPositiveProtonLambda}); + setBits(maskXiSpecific, {selTOFNSigmaPositiveProtonLambdaXi, selTOFDeltaTPositiveProtonLambdaXi}); + setBits(maskOmegaSpecific, {selTOFNSigmaPositiveProtonLambdaOmega, selTOFDeltaTPositiveProtonLambdaOmega}); + } + if (PIDConfigurations.tofPidNsigmaCutLaPi < 1e+5) { // safeguard for no cut + setBits(maskAntiLambdaSpecific, {selTOFNSigmaPositivePionLambda, selTOFDeltaTPositivePionLambda}); + setBits(maskAntiXiSpecific, {selTOFNSigmaPositivePionLambdaXi, selTOFDeltaTPositivePionLambdaXi}); + setBits(maskAntiOmegaSpecific, {selTOFNSigmaPositivePionLambdaOmega, selTOFDeltaTPositivePionLambdaOmega}); + } + } + // negative track + if (TrackConfigurations.requireNegITSonly) { + setBits(maskTrackPropertiesV0, {selNegItsOnly, selNegGoodITSTrack}); + } else { + setBits(maskTrackPropertiesV0, {selNegGoodTPCTrack, selNegGoodITSTrack}); + // TPC signal is available: ask for negative track PID + if (PIDConfigurations.tpcPidNsigmaCut < 1e+5) { // safeguard for no cut + maskK0ShortSpecific.set(selTPCPIDNegativePion); + maskLambdaSpecific.set(selTPCPIDNegativePion); + maskAntiLambdaSpecific.set(selTPCPIDNegativeProton); + + maskXiSpecific.set(selTPCPIDNegativePion); + maskAntiXiSpecific.set(selTPCPIDPositiveProton); + maskOmegaSpecific.set(selTPCPIDNegativePion); + maskAntiOmegaSpecific.set(selTPCPIDPositiveProton); + } + // TOF PID + if (PIDConfigurations.tofPidNsigmaCutK0Pi < 1e+5) { // safeguard for no cut + setBits(maskK0ShortSpecific, {selTOFNSigmaNegativePionK0Short, selTOFDeltaTNegativePionK0Short}); + } + if (PIDConfigurations.tofPidNsigmaCutLaPr < 1e+5) { // safeguard for no cut + setBits(maskAntiLambdaSpecific, {selTOFNSigmaNegativeProtonLambda, selTOFDeltaTNegativeProtonLambda}); + setBits(maskAntiXiSpecific, {selTOFNSigmaNegativeProtonLambdaXi, selTOFDeltaTNegativeProtonLambdaXi}); + setBits(maskAntiOmegaSpecific, {selTOFNSigmaNegativeProtonLambdaOmega, selTOFDeltaTNegativeProtonLambdaOmega}); + } + if (PIDConfigurations.tofPidNsigmaCutLaPi < 1e+5) { // safeguard for no cut + setBits(maskLambdaSpecific, {selTOFNSigmaNegativePionLambda, selTOFDeltaTNegativePionLambda}); + setBits(maskXiSpecific, {selTOFNSigmaNegativePionLambdaXi, selTOFDeltaTNegativePionLambdaXi}); + setBits(maskOmegaSpecific, {selTOFNSigmaNegativePionLambdaOmega, selTOFDeltaTNegativePionLambdaOmega}); + } + } + // bachelor track + maskTrackPropertiesCasc = maskTrackPropertiesV0; + if (TrackConfigurations.requireBachITSonly) { + setBits(maskTrackPropertiesCasc, {selBachItsOnly, selBachGoodITSTrack}); + } else { + setBits(maskTrackPropertiesCasc, {selBachGoodTPCTrack, selBachGoodITSTrack}); + // TPC signal is available: ask for positive track PID + if (PIDConfigurations.tpcPidNsigmaCut < 1e+5) { // safeguard for no cut + maskXiSpecific.set(selTPCPIDBachPion); + maskAntiXiSpecific.set(selTPCPIDBachPion); + maskOmegaSpecific.set(selTPCPIDBachKaon); + maskAntiOmegaSpecific.set(selTPCPIDBachKaon); + } + // TOF PID + if (PIDConfigurations.tofPidNsigmaCutXiPi < 1e+5) { // safeguard for no cut + setBits(maskXiSpecific, {selTOFNSigmaBachPionXi, selTOFDeltaTBachPionXi}); + setBits(maskAntiXiSpecific, {selTOFNSigmaBachPionXi, selTOFDeltaTBachPionXi}); + } + if (PIDConfigurations.tofPidNsigmaCutOmegaKaon < 1e+5) { // safeguard for no cut + setBits(maskOmegaSpecific, {selTOFNSigmaBachKaonOmega, selTOFDeltaTBachKaonOmega}); + setBits(maskAntiOmegaSpecific, {selTOFNSigmaBachKaonOmega, selTOFDeltaTBachKaonOmega}); + } + } + + if (TrackConfigurations.skipTPConly) { + setBits(maskK0ShortSpecific, {selPosNotTPCOnly, selNegNotTPCOnly}); + setBits(maskLambdaSpecific, {selPosNotTPCOnly, selNegNotTPCOnly}); + setBits(maskAntiLambdaSpecific, {selPosNotTPCOnly, selNegNotTPCOnly}); + setBits(maskXiSpecific, {selPosNotTPCOnly, selNegNotTPCOnly, selBachNotTPCOnly}); + setBits(maskOmegaSpecific, {selPosNotTPCOnly, selNegNotTPCOnly, selBachNotTPCOnly}); + setBits(maskAntiXiSpecific, {selPosNotTPCOnly, selNegNotTPCOnly, selBachNotTPCOnly}); + setBits(maskAntiOmegaSpecific, {selPosNotTPCOnly, selNegNotTPCOnly, selBachNotTPCOnly}); + } + + // Primary particle selection, central to analysis + maskSelectionK0Short = maskTopologicalV0 | maskKinematicV0 | maskTrackPropertiesV0 | maskK0ShortSpecific | (std::bitset(1) << selPhysPrimK0Short); + maskSelectionLambda = maskTopologicalV0 | maskKinematicV0 | maskTrackPropertiesV0 | maskLambdaSpecific | (std::bitset(1) << selPhysPrimLambda); + maskSelectionAntiLambda = maskTopologicalV0 | maskKinematicV0 | maskTrackPropertiesV0 | maskAntiLambdaSpecific | (std::bitset(1) << selPhysPrimAntiLambda); + maskSelectionXi = maskTopologicalCasc | maskKinematicCasc | maskTrackPropertiesCasc | maskXiSpecific | (std::bitset(1) << selPhysPrimXi); + maskSelectionAntiXi = maskTopologicalCasc | maskKinematicCasc | maskTrackPropertiesCasc | maskAntiXiSpecific | (std::bitset(1) << selPhysPrimAntiXi); + maskSelectionOmega = maskTopologicalCasc | maskKinematicCasc | maskTrackPropertiesCasc | maskOmegaSpecific | (std::bitset(1) << selPhysPrimOmega); + maskSelectionAntiOmega = maskTopologicalCasc | maskKinematicCasc | maskTrackPropertiesCasc | maskAntiOmegaSpecific | (std::bitset(1) << selPhysPrimAntiOmega); + + // No primary requirement for feeddown matrix + secondaryMaskSelectionLambda = maskTopologicalV0 | maskKinematicV0 | maskTrackPropertiesV0 | maskLambdaSpecific; + secondaryMaskSelectionAntiLambda = maskTopologicalV0 | maskKinematicV0 | maskTrackPropertiesV0 | maskAntiLambdaSpecific; + + // Event Counter + histos.add("eventQA/hEventSelection", "hEventSelection", kTH1F, {{16, -0.5f, +15.5f}}); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(2, "kIsTriggerTVX"); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(3, "posZ cut"); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(6, "kIsVertexITSTPC"); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(7, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(8, "kIsVertexTOFmatched"); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(9, "kIsVertexTRDmatched"); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(10, "kNoSameBunchPileup"); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(11, "kNoCollInTimeRangeStd"); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(12, "kNoCollInTimeRangeNarrow"); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(13, "Below min occup."); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(14, "Above max occup."); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(15, "isUPC"); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(16, "has UPC flag"); + + // Event QA + histos.add("eventQA/hCentrality", "hCentrality", kTH2F, {axisFT0Cqa, axisSelGap}); + histos.add("eventQA/hCentralityVsTracksPVeta1", "hCentralityVsTracksPVeta1", kTH3F, {axisFT0Cqa, axisNTracksPVeta1, axisSelGap}); + histos.add("eventQA/hCentralityVsTracksTotalExceptITSonly", "hCentralityVsTracksTotalExceptITSonly", kTH3F, {axisFT0Cqa, axisNTracksTotalExceptITSonly, axisSelGap}); + histos.add("eventQA/hOccupancy", "hOccupancy", kTH2F, {axisOccupancy, axisSelGap}); + histos.add("eventQA/hCentralityVsOccupancy", "hCentralityVsOccupancy", kTH3F, {axisFT0Cqa, axisOccupancy, axisSelGap}); + histos.add("eventQA/hTracksPVeta1VsTracksGlobal", "hTracksPVeta1VsTracksGlobal", kTH3F, {axisNTracksPVeta1, axisNTracksGlobal, axisSelGap}); + histos.add("eventQA/hCentralityVsTracksGlobal", "hCentralityVsTracksGlobal", kTH3F, {axisFT0Cqa, axisNTracksGlobal, axisSelGap}); + histos.add("eventQA/hGapSide", "Gap side; Entries", kTH1F, {{5, -0.5, 4.5}}); + histos.add("eventQA/hRawGapSide", "Raw Gap side; Entries", kTH1F, {{6, -1.5, 4.5}}); + histos.add("eventQA/hSelGapSide", "Selected gap side; Entries", kTH1F, {axisSelGap}); + histos.add("eventQA/hPosX", "Vertex position in x", kTH2F, {{100, -0.1, 0.1}, axisSelGap}); + histos.add("eventQA/hPosY", "Vertex position in y", kTH2F, {{100, -0.1, 0.1}, axisSelGap}); + histos.add("eventQA/hPosZ", "Vertex position in z", kTH2F, {{100, -20., 20.}, axisSelGap}); + histos.add("eventQA/hFT0", "hFT0", kTH3F, {axisDetectors.axisFT0Aampl, axisDetectors.axisFT0Campl, axisSelGap}); + histos.add("eventQA/hFDD", "hFDD", kTH3F, {axisDetectors.axisFDDAampl, axisDetectors.axisFDDCampl, axisSelGap}); + histos.add("eventQA/hZN", "hZN", kTH3F, {axisDetectors.axisZNAampl, axisDetectors.axisZNCampl, axisSelGap}); + + if (doprocessGenerated) { + histos.add("eventQA/mc/hEventSelectionMC", "hEventSelectionMC", kTH3F, {{3, -0.5, 2.5}, axisNTracksPVeta1, axisGeneratorIds}); + histos.get(HIST("eventQA/mc/hEventSelectionMC"))->GetXaxis()->SetBinLabel(1, "All collisions"); + histos.get(HIST("eventQA/mc/hEventSelectionMC"))->GetXaxis()->SetBinLabel(2, "posZ cut"); + histos.get(HIST("eventQA/mc/hEventSelectionMC"))->GetXaxis()->SetBinLabel(3, "rec. at least once"); + + histos.add("eventQA/mc/hTracksGlobalvsMCNParticlesEta10gen", "hTracksGlobalvsMCNParticlesEta10gen", kTH2F, {axisNTracksGlobal, axisNTracksPVeta1}); + histos.add("eventQA/mc/hTracksGlobalVsNcoll_beforeEvSel", "hTracksGlobalVsNcoll_beforeEvSel", kTH2F, {axisNTracksGlobal, axisNAssocColl}); + histos.add("eventQA/mc/hTracksGlobalVsNcoll_afterEvSel", "hTracksGlobalVsNcoll_afterEvSel", kTH2F, {axisNTracksGlobal, axisNAssocColl}); + histos.add("eventQA/mc/hTracksGlobalVsPVzMC", "hTracksGlobalVsPVzMC", kTH2F, {axisNTracksGlobal, {100, -20., 20.}}); + histos.add("eventQA/mc/hEventPVzMC", "hEventPVzMC", kTH1F, {{100, -20., 20.}}); + histos.add("eventQA/mc/hGenEventCentrality", "hGenEventCentrality", kTH1F, {axisFT0Cqa}); + } + + if (doprocessV0sMC || doprocessCascadesMC) { + // Event QA + histos.add("eventQA/mc/hFakeEvents", "hFakeEvents", {kTH1F, {{1, -0.5f, 0.5f}}}); + histos.add("eventQA/mc/hNTracksGlobalvsMCNParticlesEta10rec", "hNTracksGlobalvsMCNParticlesEta10rec", kTH2F, {axisNTracksGlobal, axisNTracksPVeta1}); + histos.add("eventQA/mc/hNTracksPVeta1vsMCNParticlesEta10rec", "hNTracksPVeta1vsMCNParticlesEta10rec", kTH2F, {axisNTracksPVeta1, axisNTracksPVeta1}); + histos.add("eventQA/mc/hNTracksGlobalvstotalMultMCParticles", "hNTracksGlobalvstotalMultMCParticles", kTH2F, {axisNTracksGlobal, axisNchInvMass}); + histos.add("eventQA/mc/hNTracksPVeta1vstotalMultMCParticles", "hNTracksPVeta1vstotalMultMCParticles", kTH2F, {axisNTracksPVeta1, axisNchInvMass}); + } + + if (doprocessV0sMC) { + if (analyseLambda && calculateFeeddownMatrix) + histos.add(Form("%s/h3dLambdaFeeddown", kParticlenames[1].data()), "h3dLambdaFeeddown", kTH3F, {axisNTracksGlobal, axisPt, axisPtXi}); + if (analyseAntiLambda && calculateFeeddownMatrix) + histos.add(Form("%s/h3dAntiLambdaFeeddown", kParticlenames[2].data()), "h3dAntiLambdaFeeddown", kTH3F, {axisNTracksGlobal, axisPt, axisPtXi}); + } + + if (doprocessGenerated) { + for (int partID = 0; partID <= 6; partID++) { + histos.add(Form("%s/mc/h7dGen", kParticlenames[partID].data()), "h7dGen", kTHnSparseF, {axisFT0Cqa, axisNchInvMass, axisNchInvMass, axisPt, axisSelGap, axisRap, axisGeneratorIds}); + } + } + + if (doprocessV0s || doprocessV0sMC) { + // For all candidates + if (doPlainTopoQA) { + histos.add("generalQA/hPt", "hPt", kTH1F, {axisPtCoarse}); + histos.add("generalQA/hPosDCAToPV", "hPosDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("generalQA/hNegDCAToPV", "hNegDCAToPV", kTH1F, {axisDCAtoPV}); + histos.add("generalQA/hDCADaughters", "hDCADaughters", kTH1F, {axisDCAdau}); + histos.add("generalQA/hPointingAngle", "hPointingAngle", kTH1F, {axisPointingAngle}); + histos.add("generalQA/hV0Radius", "hV0Radius", kTH1F, {axisV0Radius}); + histos.add("generalQA/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("generalQA/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("generalQA/h2dArmenterosAll", "h2dArmenterosAll", kTH2F, {axisAPAlpha, axisAPQt}); + histos.add("generalQA/h2dArmenterosSelected", "h2dArmenterosSelected", kTH2F, {axisAPAlpha, axisAPQt}); + } + + // K0s + if (analyseK0Short) { + addHistograms<0>(histos); + } + + // Lambda + if (analyseLambda) { + addHistograms<1>(histos); + } + + // Anti-Lambda + if (analyseAntiLambda) { + addHistograms<2>(histos); + } + } + + if (doprocessCascades || doprocessCascadesMC) { + // For all candidates + if (doPlainTopoQA) { + histos.add("generalQA/hPt", "hPt", kTH1F, {axisPtCoarse}); + histos.add("generalQA/hCascCosPA", "hCascCosPA", kTH2F, {axisPtCoarse, {100, 0.9f, 1.0f}}); + histos.add("generalQA/hDCACascDaughters", "hDCACascDaughters", kTH2F, {axisPtCoarse, {44, 0.0f, 2.2f}}); + histos.add("generalQA/hCascRadius", "hCascRadius", kTH2D, {axisPtCoarse, {500, 0.0f, 50.0f}}); + histos.add("generalQA/hMesonDCAToPV", "hMesonDCAToPV", kTH2F, {axisPtCoarse, axisDCAtoPV}); + histos.add("generalQA/hBaryonDCAToPV", "hBaryonDCAToPV", kTH2F, {axisPtCoarse, axisDCAtoPV}); + histos.add("generalQA/hBachDCAToPV", "hBachDCAToPV", kTH2F, {axisPtCoarse, {200, -1.0f, 1.0f}}); + histos.add("generalQA/hV0CosPA", "hV0CosPA", kTH2F, {axisPtCoarse, {100, 0.9f, 1.0f}}); + histos.add("generalQA/hV0Radius", "hV0Radius", kTH2D, {axisPtCoarse, axisV0Radius}); + histos.add("generalQA/hDCAV0Daughters", "hDCAV0Daughters", kTH2F, {axisPtCoarse, axisDCAdau}); + histos.add("generalQA/hDCAV0ToPV", "hDCAV0ToPV", kTH2F, {axisPtCoarse, {44, 0.0f, 2.2f}}); + histos.add("generalQA/hMassLambdaDau", "hMassLambdaDau", kTH2F, {axisPtCoarse, axisLambdaMass}); + histos.add("generalQA/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("generalQA/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("generalQA/h2dBachITSvsTPCpts", "h2dBachITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + } + + // Xi + if (analyseXi) { + addHistograms<3>(histos); + } + + // Anti-Xi + if (analyseAntiXi) { + addHistograms<4>(histos); + } + + // Omega + if (analyseOmega) { + addHistograms<5>(histos); + } + + // Anti-Omega + if (analyseAntiOmega) { + addHistograms<6>(histos); + } + } + + if (verbose) { + histos.print(); + } + } + + template + int getGapSide(TCollision const& collision, bool fillQA) + { + int selGapSide = sgSelector.trueGap(collision, upcCuts.fv0a, upcCuts.ft0a, upcCuts.ft0c, upcCuts.zdc); + if (fillQA) { + histos.fill(HIST("eventQA/hGapSide"), collision.gapSide()); + histos.fill(HIST("eventQA/hSelGapSide"), selGapSide); + histos.fill(HIST("eventQA/hFT0"), collision.totalFT0AmplitudeA(), collision.totalFT0AmplitudeC(), selGapSide); + histos.fill(HIST("eventQA/hFDD"), collision.totalFDDAmplitudeA(), collision.totalFDDAmplitudeC(), selGapSide); + histos.fill(HIST("eventQA/hZN"), collision.energyCommonZNA(), collision.energyCommonZNC(), selGapSide); + } + return selGapSide; + } + + template + void fillHistogramsQA(TCollision const& collision, int const& gap) + { + // QA histograms + float centrality = collision.centFT0C(); + histos.fill(HIST("eventQA/hCentrality"), centrality, gap); + histos.fill(HIST("eventQA/hCentralityVsTracksTotalExceptITSonly"), centrality, collision.multAllTracksTPCOnly() + collision.multAllTracksITSTPC(), gap); + histos.fill(HIST("eventQA/hCentralityVsTracksPVeta1"), centrality, collision.multNTracksPVeta1(), gap); + histos.fill(HIST("eventQA/hOccupancy"), collision.trackOccupancyInTimeRange(), gap); + histos.fill(HIST("eventQA/hCentralityVsOccupancy"), centrality, collision.trackOccupancyInTimeRange(), gap); + histos.fill(HIST("eventQA/hTracksPVeta1VsTracksGlobal"), collision.multNTracksPVeta1(), collision.multNTracksGlobal(), gap); + histos.fill(HIST("eventQA/hCentralityVsTracksGlobal"), centrality, collision.multNTracksGlobal(), gap); + histos.fill(HIST("eventQA/hPosX"), collision.posX(), gap); + histos.fill(HIST("eventQA/hPosY"), collision.posY(), gap); + histos.fill(HIST("eventQA/hPosZ"), collision.posZ(), gap); + } + + template + bool acceptEvent(TCollision const& collision, bool fillQA) + { + struct SelectionCheck { + bool selection; + bool condition; + float qaBin; + }; + + const std::array checks = {{ + {true, true, 0.0}, // All collisions + {requireIsTriggerTVX, collision.selection_bit(aod::evsel::kIsTriggerTVX), 1.0}, // Triggered by FT0M + {true, std::fabs(collision.posZ()) < maxZVtxPosition, 2.0}, // Vertex-Z selected + {rejectITSROFBorder, collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder), 3.0}, // Not at ITS ROF border + {rejectTFBorder, collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder), 4.0}, // Not at TF border + {requireIsVertexITSTPC, collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC), 5.0}, // At least one ITS-TPC track + {requireIsGoodZvtxFT0VsPV, collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV), 6.0}, // PV position consistency + {requireIsVertexTOFmatched, collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched), 7.0}, // PV with TOF match + {requireIsVertexTRDmatched, collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched), 8.0}, // PV with TRD match + {rejectSameBunchPileup, collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup), 9.0}, // No same-bunch pileup + {requireNoCollInTimeRangeStd, collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard), 10.0}, // No collision within +-10 µs + {requireNoCollInTimeRangeNarrow, collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow), 11.0}, // No collision within +-4 µs + {minOccupancy >= 0, collision.trackOccupancyInTimeRange() >= minOccupancy, 12.0}, // Above min occupancy + {maxOccupancy > 0, collision.trackOccupancyInTimeRange() < maxOccupancy, 13.0}, // Below max occupancy + }}; + + for (const auto& check : checks) { + if (check.selection && !check.condition) { + return false; + } + if (fillQA && check.selection) { + histos.fill(HIST("eventQA/hEventSelection"), check.qaBin); + } + } + + if (studyUPConly && !collision.isUPC()) { + return false; + } else if (collision.isUPC() && fillQA) { + histos.fill(HIST("eventQA/hEventSelection"), 14.0); // is UPC compatible + } + + // Additional check for UPC collision flag + if (useUPCflag && collision.flags() < 1) { + return false; + } + if (collision.flags() >= 1 && fillQA) { + histos.fill(HIST("eventQA/hEventSelection"), 15.0); // UPC event + } + + return true; + } + + bool verifyMask(std::bitset bitmap, std::bitset mask) + { + return (bitmap & mask) == mask; + } + + int computeITSclusBitmap(uint8_t itsClusMap, bool fromAfterburner) + { + int bitMap = 0; + + struct MaskBitmapPair { + uint8_t mask; + int bitmap; + int afterburnerBitmap; + }; + + constexpr MaskBitmapPair kConfigs[] = { + // L6 <-- L0 + {0x7F, 12, 12}, // 01111 111 (L0 to L6) + {0x7E, 11, 11}, // 01111 110 (L1 to L6) + {0x7C, 10, 10}, // 01111 100 (L2 to L6) + {0x78, 9, -3}, // 01111 000 (L3 to L6) + {0x70, 8, -2}, // 01110 000 (L4 to L6) + {0x60, 7, -1}, // 01100 000 (L5 to L6) + {0x3F, 6, 6}, // 00111 111 (L0 to L5) + {0x3E, 5, 5}, // 00111 110 (L1 to L5) + {0x3C, 4, 4}, // 00111 100 (L2 to L5) + {0x1F, 3, 3}, // 00011 111 (L0 to L4) + {0x1E, 2, 2}, // 00011 110 (L1 to L4) + {0x0F, 1, 1}, // 00001 111 (L0 to L3) + }; + + for (const auto& config : kConfigs) { + if (verifyMask(itsClusMap, config.mask)) { + bitMap = fromAfterburner ? config.afterburnerBitmap : config.bitmap; + break; + } + } + + return bitMap; + } + + uint computeDetBitmap(uint8_t detMap) + { + uint bitMap = 0; + + struct MaskBitmapPair { + uint8_t mask; + int bitmap; + }; + + constexpr MaskBitmapPair kConfigs[] = { + {o2::aod::track::ITS | o2::aod::track::TPC | o2::aod::track::TRD | o2::aod::track::TOF, 4}, // ITS-TPC-TRD-TOF + {o2::aod::track::ITS | o2::aod::track::TPC | o2::aod::track::TOF, 3}, // ITS-TPC-TOF + {o2::aod::track::ITS | o2::aod::track::TPC | o2::aod::track::TRD, 2}, // ITS-TPC-TRD + {o2::aod::track::ITS | o2::aod::track::TPC, 1} // ITS-TPC + }; + + for (const auto& config : kConfigs) { + if (verifyMask(detMap, config.mask)) { + bitMap = config.bitmap; + break; + } + } + + return bitMap; + } + + template + std::bitset computeBitmapCascade(TCasc const& casc, TCollision const& coll) + { + float rapidityXi = casc.yXi(); + float rapidityOmega = casc.yOmega(); + + // Access daughter tracks + auto posTrackExtra = casc.template posTrackExtra_as(); + auto negTrackExtra = casc.template negTrackExtra_as(); + auto bachTrackExtra = casc.template bachTrackExtra_as(); + + // c x tau + float decayPos = std::hypot(casc.x() - coll.posX(), casc.y() - coll.posY(), casc.z() - coll.posZ()); + float totalMom = std::hypot(casc.px(), casc.py(), casc.pz()); + float ctauXi = totalMom != 0 ? o2::constants::physics::MassXiMinus * decayPos / totalMom : 1e6; + float ctauOmega = totalMom != 0 ? o2::constants::physics::MassOmegaMinus * decayPos / totalMom : 1e6; + + std::bitset bitMap = 0; + + if (casc.casccosPA(coll.posX(), coll.posY(), coll.posZ()) > casccuts.casccospa) + bitMap.set(selCascCosPA); + if (casc.dcacascdaughters() < casccuts.dcacascdau) + bitMap.set(selDCACascDau); + if (casc.cascradius() > casccuts.cascradius) + bitMap.set(selCascRadius); + if (casc.cascradius() < casccuts.cascradiusMax) + bitMap.set(selCascRadiusMax); + if (doBachelorBaryonCut && (casc.bachBaryonCosPA() < casccuts.bachbaryoncospa) && (std::fabs(casc.bachBaryonDCAxyToPV()) > casccuts.bachbaryondcaxytopv)) + bitMap.set(selBachBaryon); + if (std::fabs(casc.dcabachtopv()) > casccuts.dcabachtopv) + bitMap.set(selBachToPV); + + if (casc.sign() > 0) { + if (std::fabs(casc.dcanegtopv()) > casccuts.dcabaryontopv) + bitMap.set(selBaryonToPV); + if (std::fabs(casc.dcapostopv()) > casccuts.dcamesontopv) + bitMap.set(selMesonToPV); + } else { // no sign == 0, in principle + if (std::fabs(casc.dcapostopv()) > casccuts.dcabaryontopv) + bitMap.set(selBaryonToPV); + if (std::fabs(casc.dcanegtopv()) > casccuts.dcamesontopv) + bitMap.set(selMesonToPV); + } + + if (std::fabs(casc.mXi() - o2::constants::physics::MassXiMinus) < casccuts.masswin) + bitMap.set(selMassWinXi); + if (std::fabs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) < casccuts.masswin) + bitMap.set(selMassWinOmega); + if (std::fabs(casc.mLambda() - o2::constants::physics::MassLambda0) < casccuts.lambdamasswin) + bitMap.set(selLambdaMassWin); + + if (std::fabs(casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ())) > casccuts.dcav0topv) + bitMap.set(selDCAV0ToPV); + if (casc.v0radius() > v0cuts.v0radius) + bitMap.set(selV0Radius); + if (casc.v0radius() < v0cuts.v0radiusMax) + bitMap.set(selV0RadiusMax); + if (casc.v0cosPA(coll.posX(), coll.posY(), coll.posZ()) > v0cuts.v0cospa) + bitMap.set(selV0CosPA); + if (casc.dcaV0daughters() < v0cuts.dcav0dau) + bitMap.set(selDCAV0Dau); + + // proper lifetime + if (ctauXi < nCtauCutCasc->get("lifetimecutXi") * ctauxiPDG) + bitMap.set(selXiCTau); + if (ctauOmega < nCtauCutCasc->get("lifetimecutOmega") * ctauomegaPDG) + bitMap.set(selOmegaCTau); + + auto poseta = RecoDecay::eta(std::array{casc.pxpos(), casc.pypos(), casc.pzpos()}); + auto negeta = RecoDecay::eta(std::array{casc.pxneg(), casc.pyneg(), casc.pzneg()}); + auto bacheta = RecoDecay::eta(std::array{casc.pxbach(), casc.pybach(), casc.pzbach()}); + + // kinematic + if (std::fabs(rapidityXi) < rapidityCut) + bitMap.set(selXiRapidity); + if (std::fabs(rapidityOmega) < rapidityCut) + bitMap.set(selOmegaRapidity); + if (std::fabs(poseta) < daughterEtaCut) + bitMap.set(selNegEta); + if (std::fabs(negeta) < daughterEtaCut) + bitMap.set(selPosEta); + if (std::fabs(bacheta) < daughterEtaCut) + bitMap.set(selBachEta); + + // DCA cuts + auto pospt = std::sqrt(std::pow(casc.pxpos(), 2) + std::pow(casc.pypos(), 2)); + auto negpt = std::sqrt(std::pow(casc.pxneg(), 2) + std::pow(casc.pyneg(), 2)); + auto bachpt = std::sqrt(std::pow(casc.pxbach(), 2) + std::pow(casc.pybach(), 2)); + + double posDcaXYLimit = 0.0105f + 0.035f / std::pow(pospt, 1.1f); + double negDcaXYLimit = 0.0105f + 0.035f / std::pow(negpt, 1.1f); + double bachDcaXYLimit = 0.0105f + 0.035f / std::pow(bachpt, 1.1f); + + // TODO: separate xy and z // + if ((std::abs(casc.dcapostopv()) > posDcaXYLimit) && + (std::abs(casc.dcanegtopv()) > negDcaXYLimit) && + (std::abs(casc.dcabachtopv()) > bachDcaXYLimit)) { + bitMap.set(selDauDCA); + } + + // ITS quality flags + if (posTrackExtra.itsNCls() >= TrackConfigurations.minITSclusters) + bitMap.set(selPosGoodITSTrack); + if (negTrackExtra.itsNCls() >= TrackConfigurations.minITSclusters) + bitMap.set(selNegGoodITSTrack); + if (bachTrackExtra.itsNCls() >= TrackConfigurations.minITSclusters) + bitMap.set(selBachGoodITSTrack); + + // TPC quality flags + if (posTrackExtra.tpcCrossedRows() >= TrackConfigurations.minTPCrows) + bitMap.set(selPosGoodTPCTrack); + if (negTrackExtra.tpcCrossedRows() >= TrackConfigurations.minTPCrows) + bitMap.set(selNegGoodTPCTrack); + if (bachTrackExtra.tpcCrossedRows() >= TrackConfigurations.minTPCrows) + bitMap.set(selBachGoodTPCTrack); + + // TPC PID + // positive track + if (std::fabs(posTrackExtra.tpcNSigmaPi()) < PIDConfigurations.tpcPidNsigmaCut) + bitMap.set(selTPCPIDPositivePion); + if (std::fabs(posTrackExtra.tpcNSigmaPr()) < PIDConfigurations.tpcPidNsigmaCut) + bitMap.set(selTPCPIDPositiveProton); + // negative track + if (std::fabs(negTrackExtra.tpcNSigmaPi()) < PIDConfigurations.tpcPidNsigmaCut) + bitMap.set(selTPCPIDNegativePion); + if (std::fabs(negTrackExtra.tpcNSigmaPr()) < PIDConfigurations.tpcPidNsigmaCut) + bitMap.set(selTPCPIDNegativeProton); + // bachelor track + if (std::fabs(bachTrackExtra.tpcNSigmaPi()) < PIDConfigurations.tpcPidNsigmaCut) + bitMap.set(selTPCPIDBachPion); + if (std::fabs(bachTrackExtra.tpcNSigmaKa()) < PIDConfigurations.tpcPidNsigmaCut) + bitMap.set(selTPCPIDBachKaon); + + // TOF PID in DeltaT + // positive track + if (std::fabs(casc.posTOFDeltaTXiPr()) < PIDConfigurations.maxDeltaTimeProton) + bitMap.set(selTOFDeltaTPositiveProtonLambdaXi); + if (std::fabs(casc.posTOFDeltaTXiPi()) < PIDConfigurations.maxDeltaTimePion) + bitMap.set(selTOFDeltaTPositivePionLambdaXi); + if (std::fabs(casc.posTOFDeltaTOmPr()) < PIDConfigurations.maxDeltaTimeProton) + bitMap.set(selTOFDeltaTPositiveProtonLambdaOmega); + if (std::fabs(casc.posTOFDeltaTOmPi()) < PIDConfigurations.maxDeltaTimePion) + bitMap.set(selTOFDeltaTPositivePionLambdaOmega); + // negative track + if (std::fabs(casc.negTOFDeltaTXiPr()) < PIDConfigurations.maxDeltaTimeProton) + bitMap.set(selTOFDeltaTNegativeProtonLambdaXi); + if (std::fabs(casc.negTOFDeltaTXiPi()) < PIDConfigurations.maxDeltaTimePion) + bitMap.set(selTOFDeltaTNegativePionLambdaXi); + if (std::fabs(casc.negTOFDeltaTOmPr()) < PIDConfigurations.maxDeltaTimeProton) + bitMap.set(selTOFDeltaTNegativeProtonLambdaOmega); + if (std::fabs(casc.negTOFDeltaTOmPi()) < PIDConfigurations.maxDeltaTimePion) + bitMap.set(selTOFDeltaTNegativePionLambdaOmega); + // bachelor track + if (std::fabs(casc.bachTOFDeltaTOmKa()) < PIDConfigurations.maxDeltaTimeKaon) + bitMap.set(selTOFDeltaTBachKaonOmega); + if (std::fabs(casc.bachTOFDeltaTXiPi()) < PIDConfigurations.maxDeltaTimePion) + bitMap.set(selTOFDeltaTBachPionXi); + + // TOF PID in NSigma + // meson track + if (std::fabs(casc.tofNSigmaXiLaPi()) < PIDConfigurations.tofPidNsigmaCutLaPi) { + bitMap.set(selTOFNSigmaPositivePionLambdaXi); + bitMap.set(selTOFNSigmaNegativePionLambdaXi); + } + if (std::fabs(casc.tofNSigmaOmLaPi()) < PIDConfigurations.tofPidNsigmaCutLaPi) { + bitMap.set(selTOFNSigmaPositivePionLambdaOmega); + bitMap.set(selTOFNSigmaNegativePionLambdaOmega); + } + // baryon track + if (std::fabs(casc.tofNSigmaXiLaPr()) < PIDConfigurations.tofPidNsigmaCutLaPr) { + bitMap.set(selTOFNSigmaNegativeProtonLambdaXi); + bitMap.set(selTOFNSigmaPositiveProtonLambdaXi); + } + if (std::fabs(casc.tofNSigmaOmLaPr()) < PIDConfigurations.tofPidNsigmaCutLaPr) { + bitMap.set(selTOFNSigmaNegativePionLambdaOmega); + bitMap.set(selTOFNSigmaPositivePionLambdaOmega); + } + // bachelor track + if (std::fabs(casc.tofNSigmaXiPi()) < PIDConfigurations.tofPidNsigmaCutXiPi) { + bitMap.set(selTOFNSigmaBachPionXi); + } + if (std::fabs(casc.tofNSigmaOmKa()) < PIDConfigurations.tofPidNsigmaCutOmegaKaon) { + bitMap.set(selTOFNSigmaBachKaonOmega); + } + + // ITS only tag + if (posTrackExtra.tpcCrossedRows() < 1) + bitMap.set(selPosItsOnly); + if (negTrackExtra.tpcCrossedRows() < 1) + bitMap.set(selNegItsOnly); + if (bachTrackExtra.tpcCrossedRows() < 1) + bitMap.set(selBachItsOnly); + + // rej. comp. + if (std::fabs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > casccuts.rejcomp) + bitMap.set(selRejCompXi); + if (std::fabs(casc.mXi() - o2::constants::physics::MassXiMinus) > casccuts.rejcomp) + bitMap.set(selRejCompOmega); + + // TPC only tag + if (posTrackExtra.detectorMap() != o2::aod::track::TPC) + bitMap.set(selPosNotTPCOnly); + if (negTrackExtra.detectorMap() != o2::aod::track::TPC) + bitMap.set(selNegNotTPCOnly); + if (bachTrackExtra.detectorMap() != o2::aod::track::TPC) + bitMap.set(selBachNotTPCOnly); + + return bitMap; + } + + template + std::bitset computeBitmapV0(TV0 const& v0, TCollision const& collision) + { + float rapidityLambda = v0.yLambda(); + float rapidityK0Short = v0.yK0Short(); + + std::bitset bitMap = 0; + + // base topological variables + if (v0.v0radius() > v0cuts.v0radius) + bitMap.set(selV0Radius); + if (v0.v0radius() < v0cuts.v0radiusMax) + bitMap.set(selV0RadiusMax); + if (std::fabs(v0.dcapostopv()) > v0cuts.dcapostopv) + bitMap.set(selDCAPosToPV); + if (std::fabs(v0.dcanegtopv()) > v0cuts.dcanegtopv) + bitMap.set(selDCANegToPV); + if (v0.v0cosPA() > v0cuts.v0cospa) + bitMap.set(selV0CosPA); + if (v0.dcaV0daughters() < v0cuts.dcav0dau) + bitMap.set(selDCAV0Dau); + + // kinematic + if (std::fabs(rapidityLambda) < rapidityCut) + bitMap.set(selLambdaRapidity); + if (std::fabs(rapidityK0Short) < rapidityCut) + bitMap.set(selK0ShortRapidity); + if (std::fabs(v0.negativeeta()) < daughterEtaCut) + bitMap.set(selNegEta); + if (std::fabs(v0.positiveeta()) < daughterEtaCut) + bitMap.set(selPosEta); + + auto posTrackExtra = v0.template posTrackExtra_as(); + auto negTrackExtra = v0.template negTrackExtra_as(); + + // DCA cuts + auto pospt = std::sqrt(std::pow(v0.pxpos(), 2) + std::pow(v0.pypos(), 2)); + auto negpt = std::sqrt(std::pow(v0.pxneg(), 2) + std::pow(v0.pyneg(), 2)); + + double posDcaXYLimit = 0.0105f + 0.035f / std::pow(pospt, 1.1f); + double negDcaXYLimit = 0.0105f + 0.035f / std::pow(negpt, 1.1f); + + // TODO: separate xy and z // + if ((std::abs(v0.dcapostopv()) > posDcaXYLimit) && + (std::abs(v0.dcanegtopv()) > negDcaXYLimit)) { + bitMap.set(selDauDCA); + } + + // ITS quality flags + if (posTrackExtra.itsNCls() >= TrackConfigurations.minITSclusters) + bitMap.set(selPosGoodITSTrack); + if (negTrackExtra.itsNCls() >= TrackConfigurations.minITSclusters) + bitMap.set(selNegGoodITSTrack); + + // TPC quality flags + if (posTrackExtra.tpcCrossedRows() >= TrackConfigurations.minTPCrows) + bitMap.set(selPosGoodTPCTrack); + if (negTrackExtra.tpcCrossedRows() >= TrackConfigurations.minTPCrows) + bitMap.set(selNegGoodTPCTrack); + + // TPC PID + if (std::fabs(posTrackExtra.tpcNSigmaPi()) < PIDConfigurations.tpcPidNsigmaCut) + bitMap.set(selTPCPIDPositivePion); + if (std::fabs(posTrackExtra.tpcNSigmaPr()) < PIDConfigurations.tpcPidNsigmaCut) + bitMap.set(selTPCPIDPositiveProton); + if (std::fabs(negTrackExtra.tpcNSigmaPi()) < PIDConfigurations.tpcPidNsigmaCut) + bitMap.set(selTPCPIDNegativePion); + if (std::fabs(negTrackExtra.tpcNSigmaPr()) < PIDConfigurations.tpcPidNsigmaCut) + bitMap.set(selTPCPIDNegativeProton); + + // TOF PID in DeltaT + // positive track + if (std::fabs(v0.posTOFDeltaTLaPr()) < PIDConfigurations.maxDeltaTimeProton) + bitMap.set(selTOFDeltaTPositiveProtonLambda); + if (std::fabs(v0.posTOFDeltaTLaPi()) < PIDConfigurations.maxDeltaTimePion) + bitMap.set(selTOFDeltaTPositivePionLambda); + if (std::fabs(v0.posTOFDeltaTK0Pi()) < PIDConfigurations.maxDeltaTimePion) + bitMap.set(selTOFDeltaTPositivePionK0Short); + // negative track + if (std::fabs(v0.negTOFDeltaTLaPr()) < PIDConfigurations.maxDeltaTimeProton) + bitMap.set(selTOFDeltaTNegativeProtonLambda); + if (std::fabs(v0.negTOFDeltaTLaPi()) < PIDConfigurations.maxDeltaTimePion) + bitMap.set(selTOFDeltaTNegativePionLambda); + if (std::fabs(v0.negTOFDeltaTK0Pi()) < PIDConfigurations.maxDeltaTimePion) + bitMap.set(selTOFDeltaTNegativePionK0Short); + + // TOF PID in NSigma + // positive track + if (std::fabs(v0.tofNSigmaLaPr()) < PIDConfigurations.tofPidNsigmaCutLaPr) + bitMap.set(selTOFNSigmaPositiveProtonLambda); + if (std::fabs(v0.tofNSigmaALaPi()) < PIDConfigurations.tofPidNsigmaCutLaPi) + bitMap.set(selTOFNSigmaPositivePionLambda); + if (std::fabs(v0.tofNSigmaK0PiPlus()) < PIDConfigurations.tofPidNsigmaCutK0Pi) + bitMap.set(selTOFNSigmaPositivePionK0Short); + // negative track + if (std::fabs(v0.tofNSigmaALaPr()) < PIDConfigurations.tofPidNsigmaCutLaPr) + bitMap.set(selTOFNSigmaNegativeProtonLambda); + if (std::fabs(v0.tofNSigmaLaPi()) < PIDConfigurations.tofPidNsigmaCutLaPi) + bitMap.set(selTOFNSigmaNegativePionLambda); + if (std::fabs(v0.tofNSigmaK0PiMinus()) < PIDConfigurations.tofPidNsigmaCutK0Pi) + bitMap.set(selTOFNSigmaNegativePionK0Short); + + // ITS only tag + if (posTrackExtra.tpcCrossedRows() < 1) + bitMap.set(selPosItsOnly); + if (negTrackExtra.tpcCrossedRows() < 1) + bitMap.set(selNegItsOnly); + + // TPC only tag + if (posTrackExtra.detectorMap() != o2::aod::track::TPC) + bitMap.set(selPosNotTPCOnly); + if (negTrackExtra.detectorMap() != o2::aod::track::TPC) + bitMap.set(selNegNotTPCOnly); + + // proper lifetime + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < lifetimecutV0->get("lifetimecutLambda")) + bitMap.set(selLambdaCTau); + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < lifetimecutV0->get("lifetimecutK0S")) + bitMap.set(selK0ShortCTau); + + // armenteros + if (v0.qtarm() * v0cuts.armPodCut > std::fabs(v0.alpha()) || v0cuts.armPodCut < 1e-4) + bitMap.set(selK0ShortArmenteros); + + return bitMap; + } + + template + void analyseCascCandidate(TCasc const& casc, TCollision const& coll, int const& gap, std::bitset const& selMap) + { + // Access daughter tracks + auto posTrackExtra = casc.template posTrackExtra_as(); + auto negTrackExtra = casc.template negTrackExtra_as(); + auto bachTrackExtra = casc.template bachTrackExtra_as(); + + if (doPlainTopoQA) { + histos.fill(HIST("generalQA/hPt"), casc.pt()); + histos.fill(HIST("generalQA/hCascCosPA"), casc.pt(), casc.casccosPA(coll.posX(), coll.posY(), coll.posZ())); + histos.fill(HIST("generalQA/hDCACascDaughters"), casc.pt(), casc.dcacascdaughters()); + histos.fill(HIST("generalQA/hCascRadius"), casc.pt(), casc.cascradius()); + histos.fill(HIST("generalQA/hMesonDCAToPV"), casc.pt(), casc.dcanegtopv()); + histos.fill(HIST("generalQA/hBaryonDCAToPV"), casc.pt(), casc.dcapostopv()); + histos.fill(HIST("generalQA/hBachDCAToPV"), casc.pt(), casc.dcabachtopv()); + histos.fill(HIST("generalQA/hV0CosPA"), casc.pt(), casc.v0cosPA(coll.posX(), coll.posY(), coll.posZ())); + histos.fill(HIST("generalQA/hV0Radius"), casc.pt(), casc.v0radius()); + histos.fill(HIST("generalQA/hDCAV0Daughters"), casc.pt(), casc.dcaV0daughters()); + histos.fill(HIST("generalQA/hDCAV0ToPV"), casc.pt(), std::fabs(casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ()))); + histos.fill(HIST("generalQA/hMassLambdaDau"), casc.pt(), casc.mLambda()); + histos.fill(HIST("generalQA/h2dPositiveITSvsTPCpts"), posTrackExtra.tpcCrossedRows(), posTrackExtra.itsNCls()); + histos.fill(HIST("generalQA/h2dNegativeITSvsTPCpts"), negTrackExtra.tpcCrossedRows(), negTrackExtra.itsNCls()); + histos.fill(HIST("generalQA/h2dBachITSvsTPCpts"), bachTrackExtra.tpcCrossedRows(), bachTrackExtra.itsNCls()); + } + + // Xi + if (verifyMask(selMap, maskSelectionXi) && analyseXi) { + fillHistogramsCasc<3>(casc, coll, gap); + } + + // Anti-Xi + if (verifyMask(selMap, maskSelectionAntiXi) && analyseAntiXi) { + fillHistogramsCasc<4>(casc, coll, gap); + } + + // Omega + if (verifyMask(selMap, maskSelectionOmega) && analyseOmega) { + fillHistogramsCasc<5>(casc, coll, gap); + } + + // Anti-Omega + if (verifyMask(selMap, maskSelectionAntiOmega) && analyseAntiOmega) { + fillHistogramsCasc<6>(casc, coll, gap); + } + } + + template + void computeV0MCAssociation(const TV0& v0, std::bitset& bitMap) + { + const int pdgPos = v0.pdgCodePositive(); + const int pdgNeg = v0.pdgCodeNegative(); + const int pdgV0 = v0.pdgCode(); + const bool isPhysPrim = v0.isPhysicalPrimary(); + + const bool isPositiveProton = (pdgPos == PDG_t::kProton); + const bool isPositivePion = (pdgPos == PDG_t::kPiPlus) || (doTreatPiToMuon && pdgPos == PDG_t::kMuonPlus); + const bool isNegativeProton = (pdgNeg == kProtonBar); + const bool isNegativePion = (pdgNeg == PDG_t::kPiMinus) || (doTreatPiToMuon && pdgNeg == PDG_t::kMuonMinus); + + switch (pdgV0) { + case PDG_t::kK0Short: // K0Short + if (isPositivePion && isNegativePion) { + bitMap.set(selConsiderK0Short); + if (isPhysPrim) + bitMap.set(selPhysPrimK0Short); + } + break; + case PDG_t::kLambda0: // Lambda + if (isPositiveProton && isNegativePion) { + bitMap.set(selConsiderLambda); + if (isPhysPrim) + bitMap.set(selPhysPrimLambda); + } + break; + case PDG_t::kLambda0Bar: // AntiLambda + if (isPositivePion && isNegativeProton) { + bitMap.set(selConsiderAntiLambda); + if (isPhysPrim) + bitMap.set(selPhysPrimAntiLambda); + } + break; + } + } + + template + void computeCascadeMCAssociation(const TCasc& casc, std::bitset& bitMap) + { + const int pdgPos = casc.pdgCodePositive(); + const int pdgNeg = casc.pdgCodeNegative(); + const int pdgBach = casc.pdgCodeBachelor(); + const int pdgCasc = casc.pdgCode(); + const bool isPhysPrim = casc.isPhysicalPrimary(); + + const bool isPositiveProton = (pdgPos == PDG_t::kProton); + + const bool isPositivePion = (pdgPos == PDG_t::kPiPlus); + const bool isBachelorPositivePion = (pdgBach == PDG_t::kPiPlus); + + const bool isNegativeProton = (pdgNeg == kProtonBar); + + const bool isNegativePion = (pdgNeg == PDG_t::kPiMinus); + const bool isBachelorNegativePion = (pdgBach == PDG_t::kPiMinus); + + const bool isBachelorPositiveKaon = (pdgBach == PDG_t::kKPlus); + const bool isBachelorNegativeKaon = (pdgBach == PDG_t::kKMinus); + + switch (pdgCasc) { + case PDG_t::kXiMinus: // Xi + if (isPositiveProton && isNegativePion && isBachelorNegativePion) { + bitMap.set(selConsiderXi); + if (isPhysPrim) + bitMap.set(selPhysPrimXi); + } + break; + case PDG_t::kXiPlusBar: // Anti-Xi + if (isNegativeProton && isPositivePion && isBachelorPositivePion) { + bitMap.set(selConsiderAntiXi); + if (isPhysPrim) + bitMap.set(selPhysPrimAntiXi); + } + break; + case PDG_t::kOmegaMinus: // Omega + if (isPositiveProton && isNegativePion && isBachelorNegativeKaon) { + bitMap.set(selConsiderOmega); + if (isPhysPrim) + bitMap.set(selPhysPrimOmega); + } + break; + case PDG_t::kOmegaPlusBar: // Anti-Omega + if (isNegativeProton && isPositivePion && isBachelorPositiveKaon) { + bitMap.set(selConsiderAntiOmega); + if (isPhysPrim) + bitMap.set(selPhysPrimAntiOmega); + } + break; + } + } + + template + void analyseV0Candidate(TV0 const& v0, TCollision const& coll, int const& gap, std::bitset const& selMap) + { + auto posTrackExtra = v0.template posTrackExtra_as(); + auto negTrackExtra = v0.template negTrackExtra_as(); + + // QA plots + if (doPlainTopoQA) { + histos.fill(HIST("generalQA/hPt"), v0.pt()); + histos.fill(HIST("generalQA/hPosDCAToPV"), v0.dcapostopv()); + histos.fill(HIST("generalQA/hNegDCAToPV"), v0.dcanegtopv()); + histos.fill(HIST("generalQA/hDCADaughters"), v0.dcaV0daughters()); + histos.fill(HIST("generalQA/hPointingAngle"), std::acos(v0.v0cosPA())); + histos.fill(HIST("generalQA/hV0Radius"), v0.v0radius()); + histos.fill(HIST("generalQA/h2dPositiveITSvsTPCpts"), posTrackExtra.tpcCrossedRows(), posTrackExtra.itsNCls()); + histos.fill(HIST("generalQA/h2dNegativeITSvsTPCpts"), negTrackExtra.tpcCrossedRows(), negTrackExtra.itsNCls()); + } + + histos.fill(HIST("generalQA/h2dArmenterosAll"), v0.alpha(), v0.qtarm()); + + // K0s + if (verifyMask(selMap, maskSelectionK0Short) && analyseK0Short) { + fillHistogramsV0<0>(v0, coll, gap); + } + + // Lambda + if (verifyMask(selMap, maskSelectionLambda) && analyseLambda) { + fillHistogramsV0<1>(v0, coll, gap); + } + + // Anti-Lambda + if (verifyMask(selMap, maskSelectionAntiLambda) && analyseAntiLambda) { + fillHistogramsV0<2>(v0, coll, gap); + } + } + + PresliceUnsorted perMcCollision = aod::v0data::straMCCollisionId; + + std::vector getListOfRecoCollIds(StraMCCollisionsFull const& mcCollisions, + StraCollisonsFullMC const& collisions) + { + std::vector listBestCollisionIds(mcCollisions.size(), -1); + + for (auto const& mcCollision : mcCollisions) { + if (std::find(generatorIds->begin(), generatorIds->end(), mcCollision.generatorsID()) == generatorIds->end()) { + continue; + } + auto groupedCollisions = collisions.sliceBy(perMcCollision, mcCollision.globalIndex()); + // Find the collision with the biggest nbr of PV contributors + // Follows what was done here: https://github.com/AliceO2Group/O2Physics/blob/master/Common/TableProducer/mcCollsExtra.cxx#L93 + int biggestNContribs = -1; + int bestCollisionIndex = -1; + for (auto const& collision : groupedCollisions) { + if (!acceptEvent(collision, false)) { + continue; + } + + int selGapSide = collision.isUPC() ? getGapSide(collision, false) : -1; + if (studyUPConly && (selGapSide < -0.5)) + continue; + + if (biggestNContribs < collision.multPVTotalContributors()) { + biggestNContribs = collision.multPVTotalContributors(); + bestCollisionIndex = collision.globalIndex(); + } + } + listBestCollisionIds[mcCollision.globalIndex()] = bestCollisionIndex; + } + + return listBestCollisionIds; + } + + void fillGenMCHistogramsQA(StraMCCollisionsFull const& mcCollisions, StraCollisonsFullMC const& collisions) + { + for (auto const& mcCollision : mcCollisions) { + // LOGF(info, "Generator ID is %i", mcCollision.generatorsID()); + if (std::find(generatorIds->begin(), generatorIds->end(), mcCollision.generatorsID()) == generatorIds->end()) { + continue; + } + + histos.fill(HIST("eventQA/mc/hEventSelectionMC"), 0.0, mcCollision.multMCNParticlesEta10(), mcCollision.generatorsID()); + + if (std::abs(mcCollision.posZ()) > maxZVtxPosition) + continue; + + histos.fill(HIST("eventQA/mc/hEventSelectionMC"), 1.0, mcCollision.multMCNParticlesEta10(), mcCollision.generatorsID()); + + // Group collisions by MC collision index + auto groupedCollisions = collisions.sliceBy(perMcCollision, mcCollision.globalIndex()); + + bool atLeastOne = false; + float centrality = -1.f; + int nCollisions = 0; + int biggestNContribs = -1; + int nTracksGlobal = -1; + + // Find the max contributors and count accepted collisions + for (auto const& collision : groupedCollisions) { + if (!acceptEvent(collision, false)) { + continue; + } + + int selGapSide = collision.isUPC() ? getGapSide(collision, false) : -1; + if (studyUPConly && (selGapSide < -0.5)) + continue; + + ++nCollisions; + atLeastOne = true; + + if (biggestNContribs < collision.multPVTotalContributors()) { + biggestNContribs = collision.multPVTotalContributors(); + centrality = collision.centFT0C(); + nTracksGlobal = collision.multNTracksGlobal(); + } + } + + // Fill histograms + histos.fill(HIST("eventQA/mc/hTracksGlobalVsNcoll_beforeEvSel"), nTracksGlobal, groupedCollisions.size()); + histos.fill(HIST("eventQA/mc/hTracksGlobalVsNcoll_afterEvSel"), nTracksGlobal, nCollisions); + histos.fill(HIST("eventQA/mc/hTracksGlobalvsMCNParticlesEta10gen"), nTracksGlobal, mcCollision.multMCNParticlesEta10()); + histos.fill(HIST("eventQA/mc/hTracksGlobalVsPVzMC"), nTracksGlobal, mcCollision.posZ()); + histos.fill(HIST("eventQA/mc/hEventPVzMC"), mcCollision.posZ()); + + if (atLeastOne) { + histos.fill(HIST("eventQA/mc/hEventSelectionMC"), 2.0, mcCollision.multMCNParticlesEta10(), mcCollision.generatorsID()); + histos.fill(HIST("eventQA/mc/hGenEventCentrality"), centrality); + } + } + } + + template + void fillFeeddownMatrix(TCollision const& collision, TV0 const& v0, std::bitset const& selMap) + { + if (!v0.has_motherMCPart()) { + return; + } + + auto v0mother = v0.motherMCPart(); + const float rapidityXi = RecoDecay::y(std::array{v0mother.px(), v0mother.py(), v0mother.pz()}, o2::constants::physics::MassXiMinus); + if (std::fabs(rapidityXi) > 0.5f) { + return; + } + + const float mult = collision.multNTracksGlobal(); + const float v0pt = v0.pt(); + const float motherPt = std::hypot(v0mother.px(), v0mother.py()); + + if (analyseLambda && verifyMask(selMap, secondaryMaskSelectionLambda) && + v0mother.pdgCode() == PDG_t::kXiMinus && v0mother.isPhysicalPrimary()) { + histos.fill(HIST("h3dLambdaFeeddown"), mult, v0pt, motherPt); + } + + if (analyseAntiLambda && verifyMask(selMap, secondaryMaskSelectionAntiLambda) && + v0mother.pdgCode() == PDG_t::kXiPlusBar && v0mother.isPhysicalPrimary()) { + histos.fill(HIST("h3dAntiLambdaFeeddown"), mult, v0pt, motherPt); + } + } + + void processV0s(StraCollisonFull const& collision, V0Candidates const& fullV0s, DauTracks const&) + { + if (!acceptEvent(collision, true)) { + return; + } // event is accepted + + histos.fill(HIST("eventQA/hRawGapSide"), collision.gapSide()); + + int selGapSide = collision.isUPC() ? getGapSide(collision, true) : -1; + if (studyUPConly && (selGapSide < -0.5)) + return; + + fillHistogramsQA(collision, selGapSide); + + for (const auto& v0 : fullV0s) { + if ((v0.v0Type() != v0cuts.v0TypeSelection) && (v0cuts.v0TypeSelection > 0)) + continue; // skip V0s that are not standard + + std::bitset selMap = computeBitmapV0(v0, collision); + + // consider all species for the candidate + setBits(selMap, {selConsiderK0Short, selConsiderLambda, selConsiderAntiLambda, + selPhysPrimK0Short, selPhysPrimLambda, selPhysPrimAntiLambda}); + + analyseV0Candidate(v0, collision, selGapSide, selMap); + } // end v0 loop + } + + void processV0sMC(StraCollisonFullMC const& collision, + V0CandidatesMC const& fullV0s, + DauTracks const&, + aod::MotherMCParts const&, + StraMCCollisionsFull const&, + V0MCCoresFull const&) + { + if (!collision.has_straMCCollision()) { + histos.fill(HIST("eventQA/mc/hFakeEvents"), 0); // no assoc. MC collisions + } else { + const auto& mcCollision = collision.straMCCollision_as(); + if (std::find(generatorIds->begin(), generatorIds->end(), mcCollision.generatorsID()) == generatorIds->end()) { + return; + } + } + + if (!acceptEvent(collision, true)) { + return; + } // event is accepted + + histos.fill(HIST("eventQA/hRawGapSide"), collision.gapSide()); + + int selGapSide = collision.isUPC() ? getGapSide(collision, true) : -1; + if (studyUPConly && (selGapSide < -0.5)) + return; + + fillHistogramsQA(collision, selGapSide); + + if (collision.has_straMCCollision()) { + const auto& mcCollision = collision.straMCCollision_as(); + histos.fill(HIST("eventQA/mc/hNTracksGlobalvsMCNParticlesEta10rec"), collision.multNTracksGlobal(), mcCollision.multMCNParticlesEta10()); + histos.fill(HIST("eventQA/mc/hNTracksPVeta1vsMCNParticlesEta10rec"), collision.multNTracksPVeta1(), mcCollision.multMCNParticlesEta10()); + histos.fill(HIST("eventQA/mc/hNTracksGlobalvstotalMultMCParticles"), collision.multNTracksGlobal(), mcCollision.totalMultMCParticles()); + histos.fill(HIST("eventQA/mc/hNTracksPVeta1vstotalMultMCParticles"), collision.multNTracksPVeta1(), mcCollision.totalMultMCParticles()); + } + + for (const auto& v0 : fullV0s) { + if ((v0.v0Type() != v0cuts.v0TypeSelection) && (v0cuts.v0TypeSelection > 0)) + continue; // skip V0s that are not standard + + std::bitset selMap = computeBitmapV0(v0, collision); + + if (doMCAssociation) { + if (v0.has_v0MCCore()) { + const auto& v0MC = v0.v0MCCore_as(); + computeV0MCAssociation(v0MC, selMap); + if (calculateFeeddownMatrix) { + fillFeeddownMatrix(collision, v0, selMap); + } + } + } else { + // consider all species for the candidate + setBits(selMap, {selConsiderK0Short, selConsiderLambda, selConsiderAntiLambda, + selPhysPrimK0Short, selPhysPrimLambda, selPhysPrimAntiLambda}); + } + + analyseV0Candidate(v0, collision, selGapSide, selMap); + } // end v0 loop + } + + void processCascades(StraCollisonFull const& collision, + CascadeCandidates const& fullCascades, + DauTracks const&) + { + if (!acceptEvent(collision, true)) { + return; + } // event is accepted + + histos.fill(HIST("eventQA/hRawGapSide"), collision.gapSide()); + + int selGapSide = collision.isUPC() ? getGapSide(collision, true) : -1; + if (studyUPConly && (selGapSide < -0.5)) + return; + + fillHistogramsQA(collision, selGapSide); + + for (const auto& casc : fullCascades) { + std::bitset selMap = computeBitmapCascade(casc, collision); + // the candidate may belong to any particle species + setBits(selMap, {selConsiderXi, selConsiderAntiXi, selConsiderOmega, selConsiderAntiOmega, + selPhysPrimXi, selPhysPrimAntiXi, selPhysPrimOmega, selPhysPrimAntiOmega}); + + analyseCascCandidate(casc, collision, selGapSide, selMap); + } // end casc loop + } + + void processCascadesMC(StraCollisonFullMC const& collision, + CascadeCandidatesMC const& fullCascades, + DauTracks const&, + aod::MotherMCParts const&, + StraMCCollisionsFull const&, + CascMCCoresFull const&) + { + if (!collision.has_straMCCollision()) { + histos.fill(HIST("eventQA/mc/hFakeEvents"), 0); // no assoc. MC collisions + } else { + const auto& mcCollision = collision.straMCCollision_as(); + if (std::find(generatorIds->begin(), generatorIds->end(), mcCollision.generatorsID()) == generatorIds->end()) { + return; + } + } + + if (!acceptEvent(collision, true)) { + return; + } // event is accepted + + histos.fill(HIST("eventQA/hRawGapSide"), collision.gapSide()); + + int selGapSide = collision.isUPC() ? getGapSide(collision, true) : -1; + if (studyUPConly && (selGapSide < -0.5)) + return; + + fillHistogramsQA(collision, selGapSide); + + if (collision.has_straMCCollision()) { + const auto& mcCollision = collision.straMCCollision_as(); + histos.fill(HIST("eventQA/mc/hNTracksGlobalvsMCNParticlesEta10rec"), collision.multNTracksGlobal(), mcCollision.multMCNParticlesEta10()); + histos.fill(HIST("eventQA/mc/hNTracksPVeta1vsMCNParticlesEta10rec"), collision.multNTracksPVeta1(), mcCollision.multMCNParticlesEta10()); + histos.fill(HIST("eventQA/mc/hNTracksGlobalvstotalMultMCParticles"), collision.multNTracksGlobal(), mcCollision.totalMultMCParticles()); + histos.fill(HIST("eventQA/mc/hNTracksPVeta1vstotalMultMCParticles"), collision.multNTracksPVeta1(), mcCollision.totalMultMCParticles()); + } + + for (const auto& casc : fullCascades) { + std::bitset selMap = computeBitmapCascade(casc, collision); + + if (doMCAssociation) { + if (casc.has_cascMCCore()) { + const auto& cascMC = casc.cascMCCore_as(); + computeCascadeMCAssociation(cascMC, selMap); + } + } else { + // the candidate may belong to any particle species + setBits(selMap, {selConsiderXi, selConsiderAntiXi, selConsiderOmega, selConsiderAntiOmega, + selPhysPrimXi, selPhysPrimAntiXi, selPhysPrimOmega, selPhysPrimAntiOmega}); + } + + analyseCascCandidate(casc, collision, selGapSide, selMap); + } // end casc loop + } + + void processGenerated(StraMCCollisionsFull const& mcCollisions, + V0MCCoresFull const& V0MCCores, + CascMCCoresFull const& CascMCCores, + StraCollisonsFullMC const& collisions) + { + fillGenMCHistogramsQA(mcCollisions, collisions); + std::vector listBestCollisionIds = getListOfRecoCollIds(mcCollisions, collisions); + // V0 start + for (auto const& v0MC : V0MCCores) { + // Consider only primaries + if (!v0MC.has_straMCCollision() || !v0MC.isPhysicalPrimary()) + continue; + + // Kinematics (|y| < rapidityCut) + float pTmc = v0MC.ptMC(); + float ymc = 1e3; + if (v0MC.pdgCode() == PDG_t::kK0Short) + ymc = v0MC.rapidityMC(0); + else if (std::abs(v0MC.pdgCode()) == PDG_t::kLambda0) + ymc = v0MC.rapidityMC(1); + if (std::abs(ymc) > rapidityCut) + continue; + + auto mcCollision = v0MC.straMCCollision_as(); // take gen. collision + + if (std::abs(mcCollision.posZ()) > maxZVtxPosition) + continue; + + // Collision is of the proccess of interest + if (std::find(generatorIds->begin(), generatorIds->end(), mcCollision.generatorsID()) == generatorIds->end()) { + continue; + } + + float centrality = -1.f; + int nTracksGlobal = -1; + + if (listBestCollisionIds[mcCollision.globalIndex()] > -1) { + auto collision = collisions.iteratorAt(listBestCollisionIds[mcCollision.globalIndex()]); + centrality = collision.centFT0C(); + nTracksGlobal = collision.multNTracksGlobal(); + } + + // Fill histograms + if (v0MC.pdgCode() == PDG_t::kK0Short) { + histos.fill(HIST(kParticlenames[0]) + HIST("/mc/h7dGen"), centrality, nTracksGlobal, mcCollision.multMCNParticlesEta10(), pTmc, static_cast(upcCuts.genGapSide), ymc, mcCollision.generatorsID()); + } + if (v0MC.pdgCode() == PDG_t::kLambda0) { + histos.fill(HIST(kParticlenames[1]) + HIST("/mc/h7dGen"), centrality, nTracksGlobal, mcCollision.multMCNParticlesEta10(), pTmc, static_cast(upcCuts.genGapSide), ymc, mcCollision.generatorsID()); + } + if (v0MC.pdgCode() == PDG_t::kLambda0Bar) { + histos.fill(HIST(kParticlenames[2]) + HIST("/mc/h7dGen"), centrality, nTracksGlobal, mcCollision.multMCNParticlesEta10(), pTmc, static_cast(upcCuts.genGapSide), ymc, mcCollision.generatorsID()); + } + } // V0 end + + // Cascade start + for (auto const& cascMC : CascMCCores) { + // Consider only primaries + if (!cascMC.has_straMCCollision() || !cascMC.isPhysicalPrimary()) + continue; + // Kinematics (|y| < rapidityCut) + float pTmc = cascMC.ptMC(); + float ymc = 1e3; + if (std::abs(cascMC.pdgCode()) == PDG_t::kXiMinus) + ymc = RecoDecay::y(std::array{cascMC.pxMC(), cascMC.pyMC(), cascMC.pzMC()}, o2::constants::physics::MassXiMinus); + else if (std::abs(cascMC.pdgCode()) == PDG_t::kOmegaMinus) + ymc = RecoDecay::y(std::array{cascMC.pxMC(), cascMC.pyMC(), cascMC.pzMC()}, o2::constants::physics::MassOmegaMinus); + if (std::abs(ymc) > rapidityCut) + continue; + + auto mcCollision = cascMC.straMCCollision_as(); // take gen. collision + if (std::abs(mcCollision.posZ()) > maxZVtxPosition) + continue; + + float centrality = -1.f; + int nTracksGlobal = -1; + + if (listBestCollisionIds[mcCollision.globalIndex()] > -1) { + auto collision = collisions.iteratorAt(listBestCollisionIds[mcCollision.globalIndex()]); + centrality = collision.centFT0C(); + nTracksGlobal = collision.multNTracksGlobal(); + } + + // Fill histograms + if (cascMC.pdgCode() == PDG_t::kXiMinus) { + histos.fill(HIST(kParticlenames[3]) + HIST("/mc/h7dGen"), centrality, nTracksGlobal, mcCollision.multMCNParticlesEta10(), pTmc, static_cast(upcCuts.genGapSide), ymc, mcCollision.generatorsID()); + } + if (cascMC.pdgCode() == PDG_t::kXiPlusBar) { + histos.fill(HIST(kParticlenames[4]) + HIST("/mc/h7dGen"), centrality, nTracksGlobal, mcCollision.multMCNParticlesEta10(), pTmc, static_cast(upcCuts.genGapSide), ymc, mcCollision.generatorsID()); + } + if (cascMC.pdgCode() == PDG_t::kOmegaMinus) { + histos.fill(HIST(kParticlenames[5]) + HIST("/mc/h7dGen"), centrality, nTracksGlobal, mcCollision.multMCNParticlesEta10(), pTmc, static_cast(upcCuts.genGapSide), ymc, mcCollision.generatorsID()); + } + if (cascMC.pdgCode() == PDG_t::kOmegaPlusBar) { + histos.fill(HIST(kParticlenames[6]) + HIST("/mc/h7dGen"), centrality, nTracksGlobal, mcCollision.multMCNParticlesEta10(), pTmc, static_cast(upcCuts.genGapSide), ymc, mcCollision.generatorsID()); + } + } // Cascade end + } + + PROCESS_SWITCH(Derivedupcanalysis, processV0s, "Process V0s", true); + PROCESS_SWITCH(Derivedupcanalysis, processV0sMC, "Process V0s MC", false); + PROCESS_SWITCH(Derivedupcanalysis, processCascades, "Process Cascades", false); + PROCESS_SWITCH(Derivedupcanalysis, processCascadesMC, "Process Cascades MC", false); + PROCESS_SWITCH(Derivedupcanalysis, processGenerated, "Process Generated Level", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx b/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx index 862ba224e6e..a58b485f114 100644 --- a/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx +++ b/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx @@ -8,7 +8,8 @@ // 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 hStrangeCorrelation.cxx /// \brief This task serves to do hadron-(strange hadron) correlation studies. /// The yield will be calculated using the two-particle correlation method. /// Trigger particle : Hadrons @@ -20,6 +21,8 @@ /// \author David Dobrigkeit Chinellato (david.dobrigkeit.chinellato@cern.ch) /// \author Zhongbao Yin (Zhong-Bao.Yin@cern.ch) +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -28,29 +31,39 @@ #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/PIDResponse.h" #include "Framework/ASoAHelpers.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Centrality.h" #include "Framework/StaticFor.h" #include "CCDB/BasicCCDBManager.h" +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" + using namespace o2; using namespace o2::constants::math; using namespace o2::framework; using namespace o2::framework::expressions; -// simple checkers -#define bitset(var, nbit) ((var) |= (1 << (nbit))) -#define bitcheck(var, nbit) ((var) & (1 << (nbit))) - -using TracksComplete = soa::Join; +using TracksComplete = soa::Join; using V0DatasWithoutTrackX = soa::Join; +using V0DatasWithoutTrackXMC = soa::Join; -struct correlateStrangeness { +struct HStrangeCorrelation { // for efficiency corrections if requested Service ccdb; + Service pdgDB; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + // event filtering + Configurable zorroMask{"zorroMask", "", "zorro trigger class to select on (empty: none)"}; + + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + Configurable doCorrelationHadron{"doCorrelationHadron", false, "do Hadron correlation"}; Configurable doCorrelationK0Short{"doCorrelationK0Short", true, "do K0Short correlation"}; Configurable doCorrelationLambda{"doCorrelationLambda", false, "do Lambda correlation"}; Configurable doCorrelationAntiLambda{"doCorrelationAntiLambda", false, "do AntiLambda correlation"}; @@ -59,29 +72,92 @@ struct correlateStrangeness { Configurable doCorrelationOmegaMinus{"doCorrelationOmegaMinus", false, "do OmegaMinus correlation"}; Configurable doCorrelationOmegaPlus{"doCorrelationOmegaPlus", false, "do OmegaPlus correlation"}; Configurable doCorrelationPion{"doCorrelationPion", false, "do Pion correlation"}; + Configurable doGenEventSelection{"doGenEventSelection", true, "use event selections when performing closure test for the gen events"}; + Configurable selectINELgtZERO{"selectINELgtZERO", true, "select INEL>0 events"}; Configurable zVertexCut{"zVertexCut", 10, "Cut on PV position"}; + Configurable requireAllGoodITSLayers{"requireAllGoodITSLayers", false, " require that in the event all ITS are good"}; Configurable skipUnderOverflowInTHn{"skipUnderOverflowInTHn", false, "skip under/overflow in THns"}; Configurable mixingParameter{"mixingParameter", 10, "how many events are mixed"}; Configurable doMCassociation{"doMCassociation", false, "fill everything only for MC associated"}; + Configurable doTriggPhysicalPrimary{"doTriggPhysicalPrimary", false, "require physical primary for trigger particles"}; + Configurable doAssocPhysicalPrimary{"doAssocPhysicalPrimary", false, "require physical primary for associated particles"}; + Configurable doLambdaPrimary{"doLambdaPrimary", false, "do primary selection for lambda"}; Configurable doAutocorrelationRejection{"doAutocorrelationRejection", true, "reject pairs where trigger Id is the same as daughter particle Id"}; + Configurable triggerBinToSelect{"triggerBinToSelect", 0, "trigger bin to select on if processSelectEventWithTrigger enabled"}; + Configurable triggerParticleCharge{"triggerParticleCharge", 0, "For checks, if 0 all charged tracks, if -1 only neg., if 1 only positive"}; + // Axes - configurable for smaller sizes ConfigurableAxis axisMult{"axisMult", {VARIABLE_WIDTH, 0.0f, 0.01f, 1.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 70.0f, 100.0f}, "Mixing bins - multiplicity"}; ConfigurableAxis axisVtxZ{"axisVtxZ", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - ConfigurableAxis axisPhi{"axisPhi", {72, 0, 2 * M_PI}, "#phi"}; + ConfigurableAxis axisPhi{"axisPhi", {72, 0, TwoPI}, "#phi"}; ConfigurableAxis axisEta{"axisEta", {80, -0.8, +0.8}, "#eta"}; ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {72, -PIHalf, PIHalf * 3}, "delta #varphi axis for histograms"}; ConfigurableAxis axisDeltaEta{"axisDeltaEta", {50, -1.6, 1.6}, "delta eta axis for histograms"}; ConfigurableAxis axisPtAssoc{"axisPtAssoc", {VARIABLE_WIDTH, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 10.0}, "pt associated axis for histograms"}; ConfigurableAxis axisPtTrigger{"axisPtTrigger", {VARIABLE_WIDTH, 0.0, 1.0, 2.0, 3.0, 100}, "pt associated axis for histograms"}; ConfigurableAxis axisPtQA{"axisPtQA", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for QA histograms"}; + ConfigurableAxis axisMultCount{"axisMultCount", {VARIABLE_WIDTH, 0, 200, 400, 600, 800, 1000, 1400, 1800, 2300, 2800, 3300, 4000, 5000, 6000}, "Mixing bins - multiplicity"}; + ConfigurableAxis axisMassNSigma{"axisMassNSigma", {40, -2, 2}, "Axis for mass Nsigma"}; + + // for topo var QA + struct : ConfigurableGroup { + Configurable maxPeakNSigma{"maxPeakNSigma", 5, "Peak region edge definition (in sigma)"}; + Configurable minBgNSigma{"minBgNSigma", 5, "Bg region edge closest to peak (in sigma)"}; + Configurable maxBgNSigma{"maxBgNSigma", 10, "Bg region edge furthest to peak (in sigma)"}; + } massWindowConfigurations; // allows for gap between peak and bg in case someone wants to // Implementation of on-the-spot efficiency correction Configurable applyEfficiencyCorrection{"applyEfficiencyCorrection", false, "apply efficiency correction"}; - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository to use"}; + Configurable applyEfficiencyForTrigger{"applyEfficiencyForTrigger", false, "apply efficiency correction for the trigger particle"}; + Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository to use"}; Configurable efficiencyCCDBPath{"efficiencyCCDBPath", "GLO/Config/GeometryAligned", "Path of the efficiency corrections"}; + // Configurables for doing subwagon systematics + // Group all settings necessary for systematics in a specific ConfigurableGroup + struct : ConfigurableGroup { + std::string prefix = "systematics"; + // --- Track quality variations (single track, both trigger and assoc daughters) + Configurable minTPCNCrossedRowsTrigger{"minTPCNCrossedRowsTrigger", 70, "Minimum TPC crossed rows (trigger)"}; + Configurable minTPCNCrossedRowsAssociated{"minTPCNCrossedRowsAssociated", 70, "Minimum TPC crossed rows (associated)"}; + Configurable triggerRequireITS{"triggerRequireITS", true, "require ITS signal in trigger tracks"}; + Configurable assocRequireITS{"assocRequireITS", true, "require ITS signal in associated primary tracks"}; + Configurable triggerMaxTPCSharedClusters{"triggerMaxTPCSharedClusters", 200, "maximum number of shared TPC clusters (inclusive)"}; + Configurable assocMaxTPCSharedClusters{"assocMaxTPCSharedClusters", 200, "maximum number of shared TPC clusters (inclusive) for assoc primary tracks"}; + Configurable triggerRequireL0{"triggerRequireL0", false, "require ITS L0 cluster for trigger"}; + Configurable assocRequireL0{"assocRequireL0", true, "require ITS L0 cluster for assoc primary track"}; + + // --- Trigger: DCA variation from basic formula: |DCAxy| < 0.004f + (0.013f / pt) + Configurable dcaXYconstant{"dcaXYconstant", 0.004, "[0] in |DCAxy| < [0]+[1]/pT"}; + Configurable dcaXYpTdep{"dcaXYpTdep", 0.013, "[1] in |DCAxy| < [0]+[1]/pT"}; + + Configurable dcaXYconstantAssoc{"dcaXYconstantAssoc", 0.004, "[0] in |DCAxy| < [0]+[1]/pT"}; + Configurable dcaXYpTdepAssoc{"dcaXYpTdepAssoc", 0.013, "[1] in |DCAxy| < [0]+[1]/pT"}; + + // --- Associated: topological variable variation (OK to vary all-at-once, at least for first study) + Configurable v0cospa{"v0cospa", 0.97, "V0 CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0) + Configurable dcaV0dau{"dcaV0dau", 1.0, "DCA V0 Daughters"}; + Configurable dcanegtopv{"dcanegtopv", 0.06, "DCA Neg To PV"}; + Configurable dcapostopv{"dcapostopv", 0.06, "DCA Pos To PV"}; + Configurable v0RadiusMin{"v0RadiusMin", 0.5, "v0radius"}; + Configurable v0RadiusMax{"v0RadiusMax", 200, "v0radius"}; + + // cascade selections + Configurable cascCospa{"cascCospa", 0.95, "cascCospa"}; + Configurable cascDcacascdau{"cascDcacascdau", 1.0, "cascDcacascdau"}; + Configurable cascDcabachtopv{"cascDcabachtopv", 0.1, "cascDcabachtopv"}; + Configurable cascRadius{"cascRadius", 0.5, "cascRadius"}; + Configurable cascV0masswindow{"cascV0masswindow", 0.01, "cascV0masswindow"}; + Configurable cascMindcav0topv{"cascMindcav0topv", 0.01, "cascMindcav0topv"}; + + // dE/dx for associated daughters + Configurable dEdxCompatibility{"dEdxCompatibility", 1, "0: loose, 1: normal, 2: tight. Defined in HStrangeCorrelationFilter"}; + + // (N.B.: sources that can be investigated in post are not listed!) + } systCuts; + // objects to use for efficiency corrections + TH2F* hEfficiencyTrigger; TH2F* hEfficiencyPion; TH2F* hEfficiencyK0Short; TH2F* hEfficiencyLambda; @@ -90,6 +166,7 @@ struct correlateStrangeness { TH2F* hEfficiencyXiPlus; TH2F* hEfficiencyOmegaMinus; TH2F* hEfficiencyOmegaPlus; + TH2F* hEfficiencyHadron; using BinningType = ColumnBinningPolicy; BinningType colBinning{{axisVtxZ, axisMult}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. @@ -98,29 +175,43 @@ struct correlateStrangeness { Preslice collisionSliceTracks = aod::triggerTracks::collisionId; Preslice collisionSliceV0s = aod::assocV0s::collisionId; Preslice collisionSliceCascades = aod::assocCascades::collisionId; - Preslice collisionSlicePions = aod::assocPions::collisionId; + // Preslice collisionSlicePions = aod::assocHadrons::collisionId; + Preslice collisionSliceHadrons = aod::assocHadrons::collisionId; + Preslice perCollision = aod::mcparticle::mcCollisionId; - static constexpr std::string_view v0names[] = {"K0Short", "Lambda", "AntiLambda"}; - static constexpr std::string_view cascadenames[] = {"XiMinus", "XiPlus", "OmegaMinus", "OmegaPlus"}; + static constexpr std::string_view kV0names[] = {"K0Short", "Lambda", "AntiLambda"}; + static constexpr std::string_view kCascadenames[] = {"XiMinus", "XiPlus", "OmegaMinus", "OmegaPlus"}; + static constexpr std::string_view kParticlenames[] = {"K0Short", "Lambda", "AntiLambda", "XiMinus", "XiPlus", "OmegaMinus", "OmegaPlus", "Pion", "Hadron"}; + static constexpr int kPdgCodes[] = {310, 3122, -3122, 3312, -3312, 3334, -3334, 211}; - uint8_t doCorrelation; + uint16_t doCorrelation; int mRunNumber; + int mRunNumberZorro; std::vector> axisRanges; /// Function to aid in calculating delta-phi /// \param phi1 first phi value /// \param phi2 second phi value - Double_t ComputeDeltaPhi(Double_t phi1, Double_t phi2) + double computeDeltaPhi(double phi1, double phi2) { - Double_t deltaPhi = phi1 - phi2; - if (deltaPhi < -TMath::Pi() / 2.) { - deltaPhi += 2. * TMath::Pi(); - } - if (deltaPhi > 3 * TMath::Pi() / 2.) { - deltaPhi -= 2. * TMath::Pi(); + double deltaPhi = phi1 - phi2; + double shiftedDeltaPhi = RecoDecay::constrainAngle(deltaPhi, -PIHalf); + return shiftedDeltaPhi; + } + + /// Function to load zorro + /// \param bc provided such that the run number + timestamp can be used + void initZorro(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumberZorro == bc.runNumber()) { + return; } - return deltaPhi; + + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), zorroMask.value); + zorro.populateHistRegistry(histos, bc.runNumber()); + + mRunNumberZorro = bc.runNumber(); } /// Function to load efficiencies to memory from CCDB @@ -130,34 +221,112 @@ struct correlateStrangeness { if (mRunNumber == bc.runNumber()) { return; } - LOG(info) << "Loading efficiencies from CCDB for run " << mRunNumber << "now..."; + mRunNumber = bc.runNumber(); + LOG(info) << "Loading efficiencies from CCDB for run " << mRunNumber << " now..."; auto timeStamp = bc.timestamp(); TList* listEfficiencies = ccdb->getForTimeStamp(efficiencyCCDBPath, timeStamp); + if (!listEfficiencies) { LOG(fatal) << "Problem getting TList object with efficiencies!"; } - hEfficiencyK0Short = (TH2F*)listEfficiencies->FindObject("hEfficiencyK0Short"); - hEfficiencyLambda = (TH2F*)listEfficiencies->FindObject("hEfficiencyLambda"); - hEfficiencyAntiLambda = (TH2F*)listEfficiencies->FindObject("hEfficiencyAntiLambda"); - hEfficiencyXiMinus = (TH2F*)listEfficiencies->FindObject("hEfficiencyXiMinus"); - hEfficiencyXiPlus = (TH2F*)listEfficiencies->FindObject("hEfficiencyXiPlus"); - hEfficiencyOmegaMinus = (TH2F*)listEfficiencies->FindObject("hEfficiencyOmegaMinus"); - hEfficiencyOmegaPlus = (TH2F*)listEfficiencies->FindObject("hEfficiencyOmegaPlus"); - + hEfficiencyTrigger = static_cast(listEfficiencies->FindObject("hEfficiencyTrigger")); + hEfficiencyK0Short = static_cast(listEfficiencies->FindObject("hEfficiencyK0Short")); + hEfficiencyLambda = static_cast(listEfficiencies->FindObject("hEfficiencyLambda")); + hEfficiencyAntiLambda = static_cast(listEfficiencies->FindObject("hEfficiencyAntiLambda")); + hEfficiencyXiMinus = static_cast(listEfficiencies->FindObject("hEfficiencyXiMinus")); + hEfficiencyXiPlus = static_cast(listEfficiencies->FindObject("hEfficiencyXiPlus")); + hEfficiencyOmegaMinus = static_cast(listEfficiencies->FindObject("hEfficiencyOmegaMinus")); + hEfficiencyOmegaPlus = static_cast(listEfficiencies->FindObject("hEfficiencyOmegaPlus")); + hEfficiencyHadron = static_cast(listEfficiencies->FindObject("hEfficiencyHadron")); + hEfficiencyPion = static_cast(listEfficiencies->FindObject("hEfficiencyPion")); LOG(info) << "Efficiencies now loaded for " << mRunNumber; } - + template + bool isValidTrigger(TTrack track) + { + if (track.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsTrigger) { + return false; // crossed rows + } + if (!track.hasITS() && systCuts.triggerRequireITS) { + return false; // skip, doesn't have ITS signal (skips lots of TPC-only!) + } + if (track.tpcNClsShared() > systCuts.triggerMaxTPCSharedClusters) { + return false; // skip, has shared clusters + } + if (!(TESTBIT(track.itsClusterMap(), 0)) && systCuts.triggerRequireL0) { + return false; // skip, doesn't have cluster in ITS L0 + } + // systematic variations: trigger DCAxy + if (std::abs(track.dcaXY()) > systCuts.dcaXYconstant + systCuts.dcaXYpTdep * std::abs(track.signed1Pt())) { + return false; + } + if (track.pt() > axisRanges[3][1] || track.pt() < axisRanges[3][0]) { + return false; + } + if (triggerParticleCharge > 0 && track.sign() < 0) { + return false; + } + if (triggerParticleCharge < 0 && track.sign() > 0) { + return false; + } + return true; + } + template + bool isValidAssocHadron(TTrack track) + { + if (track.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated) { + return false; // crossed rows + } + if (!track.hasITS() && systCuts.assocRequireITS) { + return false; // skip, doesn't have ITS signal (skips lots of TPC-only!) + } + if (track.tpcNClsShared() > systCuts.assocMaxTPCSharedClusters) { + return false; // skip, has shared clusters + } + if (!(TESTBIT(track.itsClusterMap(), 0)) && systCuts.assocRequireL0) { + return false; // skip, doesn't have cluster in ITS L0 + } + // systematic variations: trigger DCAxy + if (std::abs(track.dcaXY()) > systCuts.dcaXYconstantAssoc + systCuts.dcaXYpTdepAssoc * std::abs(track.signed1Pt())) { + return false; + } + if (track.pt() > axisRanges[2][1] || track.pt() < axisRanges[2][0]) { + return false; + } + return true; + } void fillCorrelationsV0(aod::TriggerTracks const& triggers, aod::AssocV0s const& assocs, bool mixing, float pvz, float mult) { - for (auto& triggerTrack : triggers) { + for (auto const& triggerTrack : triggers) { + if (doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + continue; auto trigg = triggerTrack.track_as(); - if (!mixing) - histos.fill(HIST("sameEvent/TriggerParticlesV0"), trigg.pt(), mult); - for (auto& assocCandidate : assocs) { + if (!isValidTrigger(trigg)) + continue; + + if (!mixing) { + float efficiency = 1.0f; + if (applyEfficiencyForTrigger) { + efficiency = hEfficiencyTrigger->Interpolate(trigg.pt(), trigg.eta()); + if (efficiency == 0) { // check for zero efficiency, do not apply if the case + efficiency = 1; + } + } + float weight = (applyEfficiencyForTrigger) ? 1. / efficiency : 1.0f; + histos.fill(HIST("sameEvent/TriggerParticlesV0"), trigg.pt(), mult, weight); + } + + for (auto const& assocCandidate : assocs) { auto assoc = assocCandidate.v0Core_as(); + //---] syst cuts [--- + if (assoc.v0radius() < systCuts.v0RadiusMin || assoc.v0radius() > systCuts.v0RadiusMax || + std::abs(assoc.dcapostopv()) < systCuts.dcapostopv || std::abs(assoc.dcanegtopv()) < systCuts.dcanegtopv || + assoc.v0cosPA() < systCuts.v0cospa || assoc.dcaV0daughters() > systCuts.dcaV0dau) + continue; + //---] removing autocorrelations [--- auto postrack = assoc.posTrack_as(); auto negtrack = assoc.negTrack_as(); @@ -172,7 +341,11 @@ struct correlateStrangeness { } } - float deltaphi = ComputeDeltaPhi(trigg.phi(), assoc.phi()); + //---] track quality check [--- + if (postrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated) + continue; + + float deltaphi = computeDeltaPhi(trigg.phi(), assoc.phi()); float deltaeta = trigg.eta() - assoc.eta(); float ptassoc = assoc.pt(); float pttrigger = trigg.pt(); @@ -184,45 +357,89 @@ struct correlateStrangeness { continue; if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) continue; - if (pttrigger < axisRanges[3][0] || pttrigger > axisRanges[3][1]) - continue; TH2F* hEfficiencyV0[3]; hEfficiencyV0[0] = hEfficiencyK0Short; hEfficiencyV0[1] = hEfficiencyLambda; hEfficiencyV0[2] = hEfficiencyAntiLambda; - static_for<0, 2>([&](auto i) { - constexpr int index = i.value; - if (bitcheck(doCorrelation, index)) { - float weight = applyEfficiencyCorrection ? 1. / hEfficiencyV0[index]->GetBinContent(hEfficiencyV0[index]->GetXaxis()->FindBin(ptassoc), hEfficiencyV0[index]->GetYaxis()->FindBin(assoc.eta())) : 1.0f; - if (assocCandidate.compatible(index) && (!doMCassociation || assocCandidate.mcTrue(index)) && !mixing && assocCandidate.invMassRegionCheck(index, 1)) - histos.fill(HIST("sameEvent/LeftBg/") + HIST(v0names[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index) && (!doMCassociation || assocCandidate.mcTrue(index)) && !mixing && assocCandidate.invMassRegionCheck(index, 2)) - histos.fill(HIST("sameEvent/Signal/") + HIST(v0names[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index) && (!doMCassociation || assocCandidate.mcTrue(index)) && !mixing && assocCandidate.invMassRegionCheck(index, 3)) - histos.fill(HIST("sameEvent/RightBg/") + HIST(v0names[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index) && (!doMCassociation || assocCandidate.mcTrue(index)) && mixing && assocCandidate.invMassRegionCheck(index, 1)) - histos.fill(HIST("mixedEvent/LeftBg/") + HIST(v0names[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index) && (!doMCassociation || assocCandidate.mcTrue(index)) && mixing && assocCandidate.invMassRegionCheck(index, 2)) - histos.fill(HIST("mixedEvent/Signal/") + HIST(v0names[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index) && (!doMCassociation || assocCandidate.mcTrue(index)) && mixing && assocCandidate.invMassRegionCheck(index, 3)) - histos.fill(HIST("mixedEvent/RightBg/") + HIST(v0names[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + constexpr int Index = i.value; + float efficiency = 1.0f; + if (applyEfficiencyCorrection) { + efficiency = hEfficiencyV0[Index]->Interpolate(ptassoc, assoc.eta()); + } + if (applyEfficiencyForTrigger) { + efficiency = efficiency * hEfficiencyTrigger->Interpolate(pttrigger, trigg.eta()); + } + if (efficiency == 0) { // check for zero efficiency, do not apply if the case + efficiency = 1; + } + + float weight = (applyEfficiencyCorrection || applyEfficiencyForTrigger) ? 1. / efficiency : 1.0f; + if (TESTBIT(doCorrelation, Index) && (!applyEfficiencyCorrection || efficiency != 0)) { + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) + histos.fill(HIST("sameEvent/LeftBg/") + HIST(kV0names[Index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) { + histos.fill(HIST("sameEvent/Signal/") + HIST(kV0names[Index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + if (std::abs(deltaphi) < 0.8) { + histos.fill(HIST("hITSClusters") + HIST(kV0names[Index]) + HIST("NegativeDaughterToward"), ptassoc, negtrack.itsNCls(), assoc.v0radius()); + histos.fill(HIST("hITSClusters") + HIST(kV0names[Index]) + HIST("PositiveDaughterToward"), ptassoc, postrack.itsNCls(), assoc.v0radius()); + } + if (std::abs(deltaphi) > 1 && std::abs(deltaphi) < 2) { + histos.fill(HIST("hITSClusters") + HIST(kV0names[Index]) + HIST("NegativeDaughterTransverse"), ptassoc, negtrack.itsNCls(), assoc.v0radius()); + histos.fill(HIST("hITSClusters") + HIST(kV0names[Index]) + HIST("PositiveDaughterTransverse"), ptassoc, postrack.itsNCls(), assoc.v0radius()); + } + } + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) + histos.fill(HIST("sameEvent/RightBg/") + HIST(kV0names[Index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) + histos.fill(HIST("mixedEvent/LeftBg/") + HIST(kV0names[Index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) + histos.fill(HIST("mixedEvent/Signal/") + HIST(kV0names[Index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) + histos.fill(HIST("mixedEvent/RightBg/") + HIST(kV0names[Index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); } }); } } } - void fillCorrelationsCascade(aod::TriggerTracks const& triggers, aod::AssocCascades const& assocs, bool mixing, float pvz, float mult) + void fillCorrelationsCascade(aod::TriggerTracks const& triggers, aod::AssocCascades const& assocs, bool mixing, float pvx, float pvy, float pvz, float mult) { - for (auto& triggerTrack : triggers) { + for (auto const& triggerTrack : triggers) { + if (doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + continue; auto trigg = triggerTrack.track_as(); - if (!mixing) - histos.fill(HIST("sameEvent/TriggerParticlesCascade"), trigg.pt(), mult); - for (auto& assocCandidate : assocs) { + if (!isValidTrigger(trigg)) + continue; + + if (!mixing) { + float efficiency = 1.0f; + if (applyEfficiencyForTrigger) { + efficiency = hEfficiencyTrigger->Interpolate(trigg.pt(), trigg.eta()); + if (efficiency == 0) { // check for zero efficiency, do not apply if the case + efficiency = 1; + } + } + float weight = (applyEfficiencyForTrigger) ? 1. / efficiency : 1.0f; + histos.fill(HIST("sameEvent/TriggerParticlesCascade"), trigg.pt(), mult, weight); + } + for (auto const& assocCandidate : assocs) { auto assoc = assocCandidate.cascData(); + //---] syst cuts [--- + if (std::abs(assoc.dcapostopv()) < systCuts.dcapostopv || + std::abs(assoc.dcanegtopv()) < systCuts.dcanegtopv || + assoc.dcabachtopv() < systCuts.cascDcabachtopv || + assoc.dcaV0daughters() > systCuts.dcaV0dau || + assoc.dcacascdaughters() > systCuts.cascDcacascdau || + assoc.v0cosPA(pvx, pvy, pvz) < systCuts.v0cospa || + assoc.casccosPA(pvx, pvy, pvz) < systCuts.cascCospa || + assoc.cascradius() < systCuts.cascRadius || + std::abs(assoc.dcav0topv(pvx, pvy, pvz)) < systCuts.cascMindcav0topv || + std::abs(assoc.mLambda() - o2::constants::physics::MassLambda0) > systCuts.cascV0masswindow) + continue; + //---] removing autocorrelations [--- auto postrack = assoc.posTrack_as(); auto negtrack = assoc.negTrack_as(); @@ -242,7 +459,11 @@ struct correlateStrangeness { } } - float deltaphi = ComputeDeltaPhi(trigg.phi(), assoc.phi()); + //---] track quality check [--- + if (postrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated || bachtrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated) + continue; + + float deltaphi = computeDeltaPhi(trigg.phi(), assoc.phi()); float deltaeta = trigg.eta() - assoc.eta(); float ptassoc = assoc.pt(); float pttrigger = trigg.pt(); @@ -254,8 +475,6 @@ struct correlateStrangeness { continue; if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) continue; - if (pttrigger < axisRanges[3][0] || pttrigger > axisRanges[3][1]) - continue; TH2F* hEfficiencyCascade[4]; hEfficiencyCascade[0] = hEfficiencyXiMinus; @@ -264,46 +483,81 @@ struct correlateStrangeness { hEfficiencyCascade[3] = hEfficiencyOmegaPlus; static_for<0, 3>([&](auto i) { - constexpr int index = i.value; - if (bitcheck(doCorrelation, index + 3)) { - float weight = applyEfficiencyCorrection ? 1. / hEfficiencyCascade[index]->GetBinContent(hEfficiencyCascade[index]->GetXaxis()->FindBin(ptassoc), hEfficiencyCascade[index]->GetYaxis()->FindBin(assoc.eta())) : 1.0f; - if (assocCandidate.compatible(index) && (!doMCassociation || assocCandidate.mcTrue(index)) && !mixing && assocCandidate.invMassRegionCheck(index, 1)) - histos.fill(HIST("sameEvent/LeftBg/") + HIST(cascadenames[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index) && (!doMCassociation || assocCandidate.mcTrue(index)) && !mixing && assocCandidate.invMassRegionCheck(index, 2)) - histos.fill(HIST("sameEvent/Signal/") + HIST(cascadenames[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index) && (!doMCassociation || assocCandidate.mcTrue(index)) && !mixing && assocCandidate.invMassRegionCheck(index, 3)) - histos.fill(HIST("sameEvent/RightBg/") + HIST(cascadenames[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index) && (!doMCassociation || assocCandidate.mcTrue(index)) && mixing && assocCandidate.invMassRegionCheck(index, 1)) - histos.fill(HIST("mixedEvent/LeftBg/") + HIST(cascadenames[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index) && (!doMCassociation || assocCandidate.mcTrue(index)) && mixing && assocCandidate.invMassRegionCheck(index, 2)) - histos.fill(HIST("mixedEvent/Signal/") + HIST(cascadenames[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index) && (!doMCassociation || assocCandidate.mcTrue(index)) && mixing && assocCandidate.invMassRegionCheck(index, 3)) - histos.fill(HIST("mixedEvent/RightBg/") + HIST(cascadenames[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + constexpr int Index = i.value; + float efficiency = 1.0f; + if (applyEfficiencyCorrection) { + efficiency = hEfficiencyCascade[Index]->Interpolate(ptassoc, assoc.eta()); + } + if (applyEfficiencyForTrigger) { + efficiency = efficiency * hEfficiencyTrigger->Interpolate(pttrigger, trigg.eta()); + } + if (efficiency == 0) { // check for zero efficiency, do not apply if the case + efficiency = 1; + } + float weight = (applyEfficiencyCorrection || applyEfficiencyForTrigger) ? 1. / efficiency : 1.0f; + if (TESTBIT(doCorrelation, Index + 3) && (!applyEfficiencyCorrection || efficiency != 0)) { + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) + histos.fill(HIST("sameEvent/LeftBg/") + HIST(kCascadenames[Index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) + histos.fill(HIST("sameEvent/Signal/") + HIST(kCascadenames[Index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) + histos.fill(HIST("sameEvent/RightBg/") + HIST(kCascadenames[Index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) + histos.fill(HIST("mixedEvent/LeftBg/") + HIST(kCascadenames[Index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) + histos.fill(HIST("mixedEvent/Signal/") + HIST(kCascadenames[Index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) + histos.fill(HIST("mixedEvent/RightBg/") + HIST(kCascadenames[Index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); } }); } } } - - void fillCorrelationsPion(aod::TriggerTracks const& triggers, aod::AssocPions const& assocs, bool mixing, float pvz, float mult) + template + void fillCorrelationsHadron(TTriggers const& triggers, THadrons const& assocs, bool mixing, float pvz, float mult) { - for (auto& triggerTrack : triggers) { - auto trigg = triggerTrack.track_as(); - if (!mixing) - histos.fill(HIST("sameEvent/TriggerParticlesPion"), trigg.pt(), mult); - for (auto& assocTrack : assocs) { - auto assoc = assocTrack.track_as(); + for (auto const& triggerTrack : triggers) { + if (doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + continue; + auto trigg = triggerTrack.template track_as(); + if (!isValidTrigger(trigg)) + continue; + + if (!mixing) { + float efficiency = 1.0f; + if (applyEfficiencyForTrigger) { + efficiency = hEfficiencyTrigger->Interpolate(trigg.pt(), trigg.eta()); + if (efficiency == 0) { // check for zero efficiency, do not apply if the case + efficiency = 1; + } + } + float weight = (applyEfficiencyForTrigger) ? 1. / efficiency : 1.0f; + if constexpr (requires { triggerTrack.extra(); }) + histos.fill(HIST("sameEvent/TriggerParticlesPion"), trigg.pt(), mult, weight); + else + histos.fill(HIST("sameEvent/TriggerParticlesHadron"), trigg.pt(), mult, weight); + } + for (auto const& assocTrack : assocs) { + auto assoc = assocTrack.template track_as(); //---] removing autocorrelations [--- if (doAutocorrelationRejection) { if (trigg.globalIndex() == assoc.globalIndex()) { - histos.fill(HIST("hNumberOfRejectedPairsPions"), 0.5); + if constexpr (requires { assocTrack.nSigmaTPCPi(); }) + histos.fill(HIST("hNumberOfRejectedPairsPion"), 0.5); + else + histos.fill(HIST("hNumberOfRejectedPairsHadron"), 0.5); continue; } } - - float deltaphi = ComputeDeltaPhi(trigg.phi(), assoc.phi()); + //---] track quality check [--- + if (!isValidAssocHadron(assoc)) + continue; + if (doAssocPhysicalPrimary && !assocTrack.mcPhysicalPrimary()) { + continue; + } + float deltaphi = computeDeltaPhi(trigg.phi(), assoc.phi()); float deltaeta = trigg.eta() - assoc.eta(); float ptassoc = assoc.pt(); float pttrigger = trigg.pt(); @@ -315,20 +569,45 @@ struct correlateStrangeness { continue; if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) continue; - if (pttrigger < axisRanges[3][0] || pttrigger > axisRanges[3][1]) - continue; - if (!mixing) - histos.fill(HIST("sameEvent/Pion"), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult); - else - histos.fill(HIST("mixedEvent/Pion"), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult); + float efficiency = 1; + if (applyEfficiencyCorrection) { + if constexpr (requires { assocTrack.nSigmaTPCPi(); }) { + efficiency = hEfficiencyPion->Interpolate(ptassoc, assoc.eta()); + } else { + efficiency = hEfficiencyHadron->Interpolate(ptassoc, assoc.eta()); + } + } + if (applyEfficiencyForTrigger) { + efficiency = efficiency * hEfficiencyTrigger->Interpolate(pttrigger, trigg.eta()); + } + if (efficiency == 0) { // check for zero efficiency, do not apply if the case + efficiency = 1; + } + float weight = (applyEfficiencyCorrection || applyEfficiencyForTrigger) ? 1. / efficiency : 1.0f; + + if (!mixing) { + if constexpr (requires { assocTrack.nSigmaTPCPi(); }) { + histos.fill(HIST("sameEvent/Signal/Pion"), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + } else { + histos.fill(HIST("sameEvent/Signal/Hadron"), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + } + } else { + if constexpr (requires { assocTrack.nSigmaTPCPi(); }) { + histos.fill(HIST("mixedEvent/Signal/Pion"), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + } else { + histos.fill(HIST("mixedEvent/Signal/Hadron"), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + } + } } } } void init(InitContext const&) { + zorroSummary.setObject(zorro.getZorroSummary()); mRunNumber = 0; + mRunNumberZorro = 0; hEfficiencyPion = 0x0; hEfficiencyK0Short = 0x0; hEfficiencyLambda = 0x0; @@ -338,24 +617,28 @@ struct correlateStrangeness { hEfficiencyOmegaMinus = 0x0; hEfficiencyOmegaPlus = 0x0; + hEfficiencyHadron = 0x0; + // set bitmap for convenience doCorrelation = 0; if (doCorrelationK0Short) - bitset(doCorrelation, 0); + SETBIT(doCorrelation, 0); if (doCorrelationLambda) - bitset(doCorrelation, 1); + SETBIT(doCorrelation, 1); if (doCorrelationAntiLambda) - bitset(doCorrelation, 2); + SETBIT(doCorrelation, 2); if (doCorrelationXiMinus) - bitset(doCorrelation, 3); + SETBIT(doCorrelation, 3); if (doCorrelationXiPlus) - bitset(doCorrelation, 4); + SETBIT(doCorrelation, 4); if (doCorrelationOmegaMinus) - bitset(doCorrelation, 5); + SETBIT(doCorrelation, 5); if (doCorrelationOmegaPlus) - bitset(doCorrelation, 6); + SETBIT(doCorrelation, 6); if (doCorrelationPion) - bitset(doCorrelation, 7); + SETBIT(doCorrelation, 7); + if (doCorrelationHadron) + SETBIT(doCorrelation, 8); // Store axis ranges to prevent spurious filling // axis status: @@ -372,6 +655,8 @@ struct correlateStrangeness { const AxisSpec preAxisPtTrigger{axisPtTrigger, "#it{p}_{T}^{trigger} (GeV/c)"}; const AxisSpec preAxisVtxZ{axisVtxZ, "vertex Z (cm)"}; const AxisSpec preAxisMult{axisMult, "mult percentile"}; + const AxisSpec axisPtLambda{axisPtAssoc, "#it{p}_{T}^{#Lambda} (GeV/c)"}; + const AxisSpec axisPtCascade{axisPtAssoc, "#it{p}_{T}^{Mother} (GeV/c)"}; // store the original axes in specific TH1Cs for completeness histos.add("axes/hDeltaPhiAxis", "", kTH1C, {preAxisDeltaPhi}); @@ -507,81 +792,20 @@ struct correlateStrangeness { const AxisSpec axisVtxZNDim{edgesVtxZ, "vertex Z (cm)"}; const AxisSpec axisMultNDim{edgesMult, "mult percentile"}; - if (bitcheck(doCorrelation, 0)) { - histos.add("h3dK0ShortSpectrum", "h3dK0ShortSpectrum", kTH3F, {axisPtQA, axisMult, {3, 0.5f, 3.5f}}); - histos.add("h3dK0ShortSpectrumY", "h3dK0ShortSpectrumY", kTH3F, {axisPtQA, axisMult, {3, 0.5f, 3.5f}}); - histos.add("hK0ShortEtaVsPtVsPhi", "hK0ShortEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hK0ShortEtaVsPtVsPhiBg", "hK0ShortEtaVsPtVsPhiBg", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("sameEvent/Signal/K0Short", "K0Short", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - } - if (bitcheck(doCorrelation, 1)) { - histos.add("h3dLambdaSpectrum", "h3dLambdaSpectrum", kTH3F, {axisPtQA, axisMult, {3, 0.5f, 3.5f}}); - histos.add("h3dLambdaSpectrumY", "h3dLambdaSpectrumY", kTH3F, {axisPtQA, axisMult, {3, 0.5f, 3.5f}}); - histos.add("hLambdaEtaVsPtVsPhi", "hLambdaEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hLambdaEtaVsPtVsPhiBg", "hLambdaEtaVsPtVsPhiBg", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("sameEvent/Signal/Lambda", "Lambda", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - } - if (bitcheck(doCorrelation, 2)) { - histos.add("h3dAntiLambdaSpectrum", "h3dAntiLambdaSpectrum", kTH3F, {axisPtQA, axisMult, {3, 0.5f, 3.5f}}); - histos.add("h3dAntiLambdaSpectrumY", "h3dAntiLambdaSpectrumY", kTH3F, {axisPtQA, axisMult, {3, 0.5f, 3.5f}}); - histos.add("hAntiLambdaEtaVsPtVsPhi", "hAntiLambdaEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hAntiLambdaEtaVsPtVsPhiBg", "hAntiLambdaEtaVsPtVsPhiBg", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("sameEvent/Signal/AntiLambda", "AntiLambda", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - } - if (bitcheck(doCorrelation, 3)) { - histos.add("h3dXiMinusSpectrum", "h3dXiMinusSpectrum", kTH3F, {axisPtQA, axisMult, {3, 0.5f, 3.5f}}); - histos.add("h3dXiMinusSpectrumY", "h3dXiMinusSpectrumY", kTH3F, {axisPtQA, axisMult, {3, 0.5f, 3.5f}}); - histos.add("hXiMinusEtaVsPtVsPhi", "hXiMinusEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hXiMinusEtaVsPtVsPhiBg", "hXiMinusEtaVsPtVsPhiBg", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("sameEvent/Signal/XiMinus", "XiMinus", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - } - if (bitcheck(doCorrelation, 4)) { - histos.add("h3dXiPlusSpectrum", "h3dXiPlusSpectrum", kTH3F, {axisPtQA, axisMult, {3, 0.5f, 3.5f}}); - histos.add("h3dXiPlusSpectrumY", "h3dXiPlusSpectrumY", kTH3F, {axisPtQA, axisMult, {3, 0.5f, 3.5f}}); - histos.add("hXiPlusEtaVsPtVsPhi", "hXiPlusEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hXiPlusEtaVsPtVsPhiBg", "hXiPlusEtaVsPtVsPhiBg", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("sameEvent/Signal/XiPlus", "XiPlus", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - } - if (bitcheck(doCorrelation, 5)) { - histos.add("h3dOmegaMinusSpectrum", "h3dOmegaMinusSpectrum", kTH3F, {axisPtQA, axisMult, {3, 0.5f, 3.5f}}); - histos.add("h3dOmegaMinusSpectrumY", "h3dOmegaMinusSpectrumY", kTH3F, {axisPtQA, axisMult, {3, 0.5f, 3.5f}}); - histos.add("hOmegaMinusEtaVsPtVsPhi", "hOmegaMinusEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hOmegaMinusEtaVsPtVsPhiBg", "hOmegaMinusEtaVsPtVsPhiBg", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("sameEvent/Signal/OmegaMinus", "OmegaMinus", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - } - if (bitcheck(doCorrelation, 6)) { - histos.add("h3dOmegaPlusSpectrum", "h3dOmegaPlusSpectrum", kTH3F, {axisPtQA, axisMult, {3, 0.5f, 3.5f}}); - histos.add("h3dOmegaPlusSpectrumY", "h3dOmegaPlusSpectrumY", kTH3F, {axisPtQA, axisMult, {3, 0.5f, 3.5f}}); - histos.add("hOmegaPlusEtaVsPtVsPhi", "hOmegaPlusEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hOmegaPlusEtaVsPtVsPhiBg", "hOmegaPlusEtaVsPtVsPhiBg", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("sameEvent/Signal/OmegaPlus", "OmegaPlus", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - } - if (bitcheck(doCorrelation, 7)) { - histos.add("sameEvent/Pion", "Pion", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - histos.add("hPionEtaVsPtVsPhi", "hPionEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); - } - LOGF(info, "Init THnFs done"); + // Some QA plots + histos.add("hGeneratedQAPtTrigger", "hGeneratedQAPtTrigger", kTH2F, {axisPtQA, {5, -0.5f, 4.5f}}); + histos.add("hGeneratedQAPtAssociatedK0", "hGeneratedQAPtAssociatedK0", kTH2F, {axisPtQA, {5, -0.5f, 4.5f}}); + histos.add("hClosureQAPtTrigger", "hClosureQAPtTrigger", kTH2F, {axisPtQA, {5, -0.5f, 4.5f}}); + histos.add("hClosureQAPtAssociatedK0", "hClosureQAPtAssociatedK0", kTH2F, {axisPtQA, {5, -0.5f, 4.5f}}); - if (doCorrelationK0Short || doCorrelationLambda || doCorrelationAntiLambda || doCorrelationXiMinus || doCorrelationXiPlus || doCorrelationOmegaMinus || doCorrelationOmegaPlus) { - histos.addClone("sameEvent/Signal/", "sameEvent/LeftBg/"); - histos.addClone("sameEvent/Signal/", "sameEvent/RightBg/"); - } + histos.add("hTriggerAllSelectedEtaVsPt", "hTriggerAllSelectedEtaVsPt", kTH3F, {axisPtQA, axisEta, axisMult}); - // mixed-event correlation functions - if (doprocessMixedEventHV0s || doprocessMixedEventHCascades || doprocessMixedEventHPions) { - histos.addClone("sameEvent/", "mixedEvent/"); - } - - // Some QA plots - histos.add("hTrackEtaVsPtVsPhi", "hTrackEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); + histos.add("hClosureTestEventCounter", "hClosureTestEventCounter", kTH1F, {{10, 0, 10}}); + histos.add("hNumberOfRejectedPairsHadron", "hNumberOfRejectedPairsHadron", kTH1F, {{1, 0, 1}}); histos.add("hNumberOfRejectedPairsV0", "hNumberOfRejectedPairsV0", kTH1F, {{1, 0, 1}}); histos.add("hNumberOfRejectedPairsCascades", "hNumberOfRejectedPairsCascades", kTH1F, {{1, 0, 1}}); - histos.add("hNumberOfRejectedPairsPions", "hNumberOfRejectedPairsPions", kTH1F, {{1, 0, 1}}); - - histos.add("sameEvent/TriggerParticlesV0", "TriggersV0", kTH2F, {axisPtQA, axisMult}); - histos.add("sameEvent/TriggerParticlesCascade", "TriggersCascade", kTH2F, {axisPtQA, axisMult}); - histos.add("sameEvent/TriggerParticlesPion", "TriggersPion", kTH2F, {axisPtQA, axisMult}); + histos.add("hNumberOfRejectedPairsPion", "hNumberOfRejectedPairsPion", kTH1F, {{1, 0, 1}}); // mixing QA histos.add("MixingQA/hSECollisionBins", ";bin;Entries", kTH1F, {{140, -0.5, 139.5}}); @@ -593,39 +817,93 @@ struct correlateStrangeness { histos.add("EventQA/hMixingQA", "mixing QA", kTH1F, {{2, -0.5, 1.5}}); histos.add("EventQA/hMult", "Multiplicity", kTH1F, {axisMult}); histos.add("EventQA/hPvz", ";pvz;Entries", kTH1F, {{30, -15, 15}}); + histos.add("EventQA/hMultFT0vsTPC", ";centFT0M;multNTracksPVeta1", kTH2F, {{100, 0, 100}, {300, 0, 300}}); + + // QA and THn Histograms + histos.add("hTriggerPtResolution", ";p_{T}^{reconstructed} (GeV/c); p_{T}^{generated} (GeV/c)", kTH2F, {axisPtQA, axisPtQA}); + histos.add("hTriggerPrimaryEtaVsPt", "hTriggerPrimaryEtaVsPt", kTH3F, {axisPtQA, axisEta, axisMult}); + histos.add("hTrackEtaVsPtVsPhi", "hTrackEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); + histos.add("hAssocTrackEtaVsPtVsPhi", "hAssocTrackEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); + histos.add("hTrackAttempt", "Attempt", kTH3F, {axisPtQA, axisEta, axisPhi}); + + bool hStrange = false; + for (int i = 0; i < 9; i++) { + if (TESTBIT(doCorrelation, i)) { + histos.add(fmt::format("h{}EtaVsPtVsPhi", kParticlenames[i]).c_str(), "", kTH3F, {axisPtQA, axisEta, axisPhi}); + histos.add(fmt::format("h3d{}Spectrum", kParticlenames[i]).c_str(), fmt::format("h3d{}Spectrum", kParticlenames[i]).c_str(), kTH3F, {axisPtQA, axisMult, axisMassNSigma}); + histos.add(fmt::format("h3d{}SpectrumY", kParticlenames[i]).c_str(), fmt::format("h3d{}SpectrumY", kParticlenames[i]).c_str(), kTH3F, {axisPtQA, axisMult, axisMassNSigma}); + histos.add(fmt::format("sameEvent/Signal/{}", kParticlenames[i]).c_str(), "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + if (i < 7) { + hStrange = true; + histos.add(fmt::format("h{}EtaVsPtVsPhiBg", kParticlenames[i]).c_str(), "", kTH3F, {axisPtQA, axisEta, axisPhi}); + histos.add(fmt::format("hITSClusters{}NegativeDaughterToward", kParticlenames[i]).c_str(), "", kTH3F, {axisPtAssoc, {8, -0.5, 7.5}, {20, 0, 10}}); + histos.add(fmt::format("hITSClusters{}PositiveDaughterToward", kParticlenames[i]).c_str(), "", kTH3F, {axisPtAssoc, {8, -0.5, 7.5}, {20, 0, 10}}); + histos.add(fmt::format("hITSClusters{}NegativeDaughterTransverse", kParticlenames[i]).c_str(), "", kTH3F, {axisPtAssoc, {8, -0.5, 7.5}, {20, 0, 10}}); + histos.add(fmt::format("hITSClusters{}PositiveDaughterTransverse", kParticlenames[i]).c_str(), "", kTH3F, {axisPtAssoc, {8, -0.5, 7.5}, {20, 0, 10}}); + } + } + } + + if (TESTBIT(doCorrelation, 8)) { + histos.add("hAsssocTrackEtaVsPtVsPhi", "", kTH3F, {axisPtQA, axisEta, axisPhi}); + histos.add("hAssocPrimaryEtaVsPt", "", kTH3F, {axisPtQA, axisEta, axisMultNDim}); + histos.add("hAssocHadronsAllSelectedEtaVsPt", "", kTH3F, {axisPtQA, axisEta, axisMultNDim}); + histos.add("hAssocPtResolution", ";p_{T}^{reconstructed} (GeV/c); p_{T}^{generated} (GeV/c)", kTH2F, {axisPtQA, axisPtQA}); + } + + if (hStrange) { + histos.addClone("sameEvent/Signal/", "sameEvent/LeftBg/"); + histos.addClone("sameEvent/Signal/", "sameEvent/RightBg/"); + } + + LOGF(info, "Init THnFs done"); + // mixed-event correlation functions + if (doprocessMixedEventHV0s || doprocessMixedEventHCascades || doprocessMixedEventHPions || doprocessMixedEventHHadrons) { + histos.addClone("sameEvent/", "mixedEvent/"); + } + if (doprocessSameEventHHadrons) + histos.add("sameEvent/TriggerParticlesHadron", "TriggersHadron", kTH2F, {axisPtQA, axisMult}); + if (doprocessSameEventHV0s) + histos.add("sameEvent/TriggerParticlesV0", "TriggersV0", kTH2F, {axisPtQA, axisMult}); + if (doprocessSameEventHCascades) + histos.add("sameEvent/TriggerParticlesCascade", "TriggersCascade", kTH2F, {axisPtQA, axisMult}); + if (doprocessSameEventHPions) + histos.add("sameEvent/TriggerParticlesPion", "TriggersPion", kTH2F, {axisPtQA, axisMult}); // MC generated plots if (doprocessMCGenerated) { - histos.add("Generated/hPion", "", kTH2F, {axisPtQA, axisEta}); - histos.add("Generated/hK0Short", "", kTH2F, {axisPtQA, axisEta}); - histos.add("Generated/hLambda", "", kTH2F, {axisPtQA, axisEta}); - histos.add("Generated/hAntiLambda", "", kTH2F, {axisPtQA, axisEta}); - histos.add("Generated/hXiMinus", "", kTH2F, {axisPtQA, axisEta}); - histos.add("Generated/hXiPlus", "", kTH2F, {axisPtQA, axisEta}); - histos.add("Generated/hOmegaMinus", "", kTH2F, {axisPtQA, axisEta}); - histos.add("Generated/hOmegaPlus", "", kTH2F, {axisPtQA, axisEta}); - + histos.add("Generated/hTrigger", "", kTH2F, {axisPtQA, axisEta}); + for (int i = 0; i < 8; i++) { + histos.add(fmt::format("Generated/h{}", kParticlenames[i]).c_str(), "", kTH2F, {axisPtQA, axisEta}); + } histos.addClone("Generated/", "GeneratedWithPV/"); // histograms within |y|<0.5, vs multiplicity - histos.add("GeneratedWithPV/hPion_MidYVsMult", "", kTH2F, {axisPtQA, axisMult}); - histos.add("GeneratedWithPV/hK0Short_MidYVsMult", "", kTH2F, {axisPtQA, axisMult}); - histos.add("GeneratedWithPV/hLambda_MidYVsMult", "", kTH2F, {axisPtQA, axisMult}); - histos.add("GeneratedWithPV/hAntiLambda_MidYVsMult", "", kTH2F, {axisPtQA, axisMult}); - histos.add("GeneratedWithPV/hXiMinus_MidYVsMult", "", kTH2F, {axisPtQA, axisMult}); - histos.add("GeneratedWithPV/hXiPlus_MidYVsMult", "", kTH2F, {axisPtQA, axisMult}); - histos.add("GeneratedWithPV/hOmegaMinus_MidYVsMult", "", kTH2F, {axisPtQA, axisMult}); - histos.add("GeneratedWithPV/hOmegaPlus_MidYVsMult", "", kTH2F, {axisPtQA, axisMult}); - - histos.add("GeneratedWithPV/hPion_MidYVsMult_TwoPVsOrMore", "", kTH2F, {axisPtQA, axisMult}); - histos.add("GeneratedWithPV/hK0Short_MidYVsMult_TwoPVsOrMore", "", kTH2F, {axisPtQA, axisMult}); - histos.add("GeneratedWithPV/hLambda_MidYVsMult_TwoPVsOrMore", "", kTH2F, {axisPtQA, axisMult}); - histos.add("GeneratedWithPV/hAntiLambda_MidYVsMult_TwoPVsOrMore", "", kTH2F, {axisPtQA, axisMult}); - histos.add("GeneratedWithPV/hXiMinus_MidYVsMult_TwoPVsOrMore", "", kTH2F, {axisPtQA, axisMult}); - histos.add("GeneratedWithPV/hXiPlus_MidYVsMult_TwoPVsOrMore", "", kTH2F, {axisPtQA, axisMult}); - histos.add("GeneratedWithPV/hOmegaMinus_MidYVsMult_TwoPVsOrMore", "", kTH2F, {axisPtQA, axisMult}); - histos.add("GeneratedWithPV/hOmegaPlus_MidYVsMult_TwoPVsOrMore", "", kTH2F, {axisPtQA, axisMult}); + for (int i = 0; i < 8; i++) { + histos.add(fmt::format("GeneratedWithPV/h{}_MidYVsMult", kParticlenames[i]).c_str(), "", kTH2F, {axisPtQA, axisMult}); + histos.add(fmt::format("GeneratedWithPV/h{}_MidYVsMult_TwoPVsOrMore", kParticlenames[i]).c_str(), "", kTH2F, {axisPtQA, axisMult}); + } + } + if (doprocessClosureTest) { + for (int i = 0; i < 8; i++) { + if (TESTBIT(doCorrelation, i)) + histos.add(fmt::format("ClosureTest/sameEvent/{}", kParticlenames[i]).c_str(), "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + if (TESTBIT(doCorrelation, i)) + histos.add(fmt::format("ClosureTest/h{}", kParticlenames[i]).c_str(), "", kTH3F, {axisPtQA, axisEta, axisPhi}); + } + histos.add("ClosureTest/hTrigger", "Trigger Tracks", kTH3F, {axisPtQA, axisEta, axisMult}); } + if (doprocessFeedDown) { + histos.add("hLambdaXiMinusFeeddownMatrix", "hLambdaXiMinusFeeddownMatrix", kTH2F, {axisPtLambda, axisPtCascade}); + histos.add("hLambdaXiZeroFeeddownMatrix", "hLambdaXiZeroFeeddownMatrix", kTH2F, {axisPtLambda, axisPtCascade}); + histos.add("hLambdaOmegaFeeddownMatrix", "hLambdaOmegaFeeddownMatrix", kTH2F, {axisPtLambda, axisPtCascade}); + histos.add("hAntiLambdaXiPlusFeeddownMatrix", "hAntiLambdaXiPlusFeeddownMatrix", kTH2F, {axisPtLambda, axisPtCascade}); + histos.add("hAntiLambdaXiZeroFeeddownMatrix", "hAntiLambdaXiZeroFeeddownMatrix", kTH2F, {axisPtLambda, axisPtCascade}); + histos.add("hAntiLambdaOmegaFeeddownMatrix", "hAntiLambdaOmegaFeeddownMatrix", kTH2F, {axisPtLambda, axisPtCascade}); + } + + // visual inspection of sizes + histos.print(); // initialize CCDB *only* if efficiency correction requested // skip if not requested, saves a bit of time @@ -637,19 +915,164 @@ struct correlateStrangeness { } } - void processSameEventHV0s(soa::Join::iterator const& collision, - aod::AssocV0s const& associatedV0s, aod::TriggerTracks const& triggerTracks, - V0DatasWithoutTrackX const&, aod::V0sLinked const&, TracksComplete const&) + // this function allows for all event selections to be done in a modular way + template + bool isCollisionSelected(TCollision const& collision) { // ________________________________________________ // Perform basic event selection if (!collision.sel8()) { + return false; + } + if (std::abs(collision.posZ()) > zVertexCut) { + return false; + } + if (collision.centFT0M() > axisRanges[5][1] || collision.centFT0M() < axisRanges[5][0]) { + return false; + } + if (!collision.isInelGt0() && selectINELgtZERO) { + return false; + } + if (!collision.selection_bit(aod::evsel::kIsGoodITSLayersAll) && requireAllGoodITSLayers) { + return false; + } + if (zorroMask.value != "") { + auto bc = collision.template bc_as(); + initZorro(bc); + bool zorroSelected = zorro.isSelected(collision.template bc_as().globalBC()); /// Just let Zorro do the accounting + if (!zorroSelected) { + return false; + } + } + return true; + } + + // if this process function is enabled, it will be such that only events with trigger particles within a given + // trigger pt bin are taken for the entire processing. This allows for the calculation of e.g. efficiencies + // within an event class that has a trigger (which may differ with respect to other cases, to be checked) + + // for map determining which trigger bins are present and which aren't + std::vector triggerPresenceMap; + + void processSelectEventWithTrigger(soa::Join const& collisions, + aod::TriggerTracks const& triggerTracks, TracksComplete const&, aod::BCsWithTimestamps const&) + { + // setup + triggerPresenceMap.clear(); + triggerPresenceMap.resize(collisions.size(), 0); + + for (auto const& collision : collisions) { + // ________________________________________________ + // Perform basic event selection + if (!isCollisionSelected(collision)) { + continue; + } + + // do not forget to re-group ... + auto slicedTriggerTracks = triggerTracks.sliceBy(collisionSliceTracks, collision.globalIndex()); + + for (auto const& triggerTrack : slicedTriggerTracks) { + auto track = triggerTrack.track_as(); + if (!isValidTrigger(track)) { + continue; + } + auto binNumber = histos.get(HIST("axes/hPtTriggerAxis"))->FindFixBin(track.pt()) - 1; + SETBIT(triggerPresenceMap[collision.globalIndex()], binNumber); + } + } + } + + void processSameEventHHadrons(soa::Join::iterator const& collision, + aod::AssocHadrons const& assocHadrons, aod::TriggerTracks const& triggerTracks, + TracksComplete const&, aod::BCsWithTimestamps const&) + { + // ________________________________________________ + // skip if desired trigger not found + if (triggerPresenceMap.size() > 0 && !TESTBIT(triggerPresenceMap[collision.globalIndex()], triggerBinToSelect)) { return; } - if (TMath::Abs(collision.posZ()) > zVertexCut) { + + if (applyEfficiencyCorrection) { + auto bc = collision.bc_as(); + initEfficiencyFromCCDB(bc); + } + + // ________________________________________________ + // Perform basic event selection + if (!isCollisionSelected(collision)) { return; } - if (collision.centFT0M() > axisRanges[5][1] || collision.centFT0M() < axisRanges[5][0]) { + // ________________________________________________ + if (!doprocessSameEventHCascades && !doprocessSameEventHV0s && !doprocessSameEventHPions) { + histos.fill(HIST("MixingQA/hSECollisionBins"), colBinning.getBin({collision.posZ(), collision.centFT0M()})); + histos.fill(HIST("EventQA/hMult"), collision.centFT0M()); + histos.fill(HIST("EventQA/hPvz"), collision.posZ()); + } + + // Do basic QA + for (auto const& hadron : assocHadrons) { + auto hadronTrack = hadron.track_as(); + histos.fill(HIST("hHadronEtaVsPtVsPhi"), hadronTrack.pt(), hadronTrack.eta(), hadronTrack.phi()); + } + if (!doprocessSameEventHCascades && !doprocessSameEventHV0s && !doprocessSameEventHPions) { + for (auto const& triggerTrack : triggerTracks) { + auto track = triggerTrack.track_as(); + if (!isValidTrigger(track)) + continue; + float efficiency = 1.0f; + if (applyEfficiencyCorrection) { + efficiency = hEfficiencyTrigger->Interpolate(track.pt(), track.eta()); + } + if (efficiency == 0) { // check for zero efficiency, do not apply if the case + efficiency = 1; + } + float weight = applyEfficiencyCorrection ? 1. / efficiency : 1.0f; + histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); + histos.fill(HIST("hTriggerPtResolution"), track.pt(), triggerTrack.mcOriginalPt()); + if (doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + continue; + histos.fill(HIST("hTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); + histos.fill(HIST("hTrackEtaVsPtVsPhi"), track.pt(), track.eta(), track.phi(), weight); + } + for (auto const& assocTrack : assocHadrons) { + auto assoc = assocTrack.track_as(); + if (!isValidAssocHadron(assoc)) + continue; + float efficiency = 1.0f; + if (applyEfficiencyCorrection) { + efficiency = hEfficiencyHadron->Interpolate(assoc.pt(), assoc.eta()); + } + if (efficiency == 0) { // check for zero efficiency, do not apply if the case + efficiency = 1; + } + float weight = applyEfficiencyCorrection ? 1. / efficiency : 1.0f; + histos.fill(HIST("hAssocHadronsAllSelectedEtaVsPt"), assoc.pt(), assoc.eta(), collision.centFT0M()); + histos.fill(HIST("hAssocPtResolution"), assoc.pt(), assocTrack.mcOriginalPt()); + if (doAssocPhysicalPrimary && !assocTrack.mcPhysicalPrimary()) + continue; + histos.fill(HIST("hAssocPrimaryEtaVsPt"), assoc.pt(), assoc.eta(), collision.centFT0M()); + histos.fill(HIST("hAsssocTrackEtaVsPtVsPhi"), assoc.pt(), assoc.eta(), assoc.phi(), weight); + } + } + + // ________________________________________________ + // Do hadron - hadron correlations + fillCorrelationsHadron(triggerTracks, assocHadrons, false, collision.posZ(), collision.centFT0M()); + } + + void processSameEventHV0s(soa::Join::iterator const& collision, + aod::AssocV0s const& associatedV0s, aod::TriggerTracks const& triggerTracks, + V0DatasWithoutTrackX const&, TracksComplete const&, aod::BCsWithTimestamps const&) + { + // ________________________________________________ + // skip if desired trigger not found + if (triggerPresenceMap.size() > 0 && !TESTBIT(triggerPresenceMap[collision.globalIndex()], triggerBinToSelect)) { + return; + } + + // ________________________________________________ + // Perform basic event selection + if (!isCollisionSelected(collision)) { return; } // ________________________________________________ @@ -657,8 +1080,14 @@ struct correlateStrangeness { histos.fill(HIST("MixingQA/hSECollisionBins"), colBinning.getBin({collision.posZ(), collision.centFT0M()})); histos.fill(HIST("EventQA/hMult"), collision.centFT0M()); histos.fill(HIST("EventQA/hPvz"), collision.posZ()); + histos.fill(HIST("EventQA/hMultFT0vsTPC"), collision.centFT0M(), collision.multNTracksPVeta1()); } // Do basic QA + + if (applyEfficiencyCorrection) { + auto bc = collision.bc_as(); + initEfficiencyFromCCDB(bc); + } TH2F* hEfficiencyV0[3]; hEfficiencyV0[0] = hEfficiencyK0Short; hEfficiencyV0[1] = hEfficiencyLambda; @@ -666,24 +1095,55 @@ struct correlateStrangeness { for (auto const& v0 : associatedV0s) { auto v0Data = v0.v0Core_as(); + + //---] track quality check [--- + auto postrack = v0Data.posTrack_as(); + auto negtrack = v0Data.negTrack_as(); + if (postrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated) + continue; + + //---] syst cuts [--- + if (v0Data.v0radius() < systCuts.v0RadiusMin || v0Data.v0radius() > systCuts.v0RadiusMax || + std::abs(v0Data.dcapostopv()) < systCuts.dcapostopv || std::abs(v0Data.dcanegtopv()) < systCuts.dcanegtopv || + v0Data.v0cosPA() < systCuts.v0cospa || v0Data.dcaV0daughters() > systCuts.dcaV0dau) + continue; + static_for<0, 2>([&](auto i) { - constexpr int index = i.value; - if (v0.compatible(index) && (!doMCassociation || v0.mcTrue(index)) && bitcheck(doCorrelation, index)) { - float weight = applyEfficiencyCorrection ? 1. / hEfficiencyV0[index]->GetBinContent(hEfficiencyV0[index]->GetXaxis()->FindBin(v0Data.pt()), hEfficiencyV0[index]->GetYaxis()->FindBin(v0Data.eta())) : 1.0f; - histos.fill(HIST("h3d") + HIST(v0names[index]) + HIST("Spectrum"), v0Data.pt(), collision.centFT0M(), v0.invMassRegion(index), weight); - if (std::abs(v0Data.rapidity(index)) < 0.5) { - histos.fill(HIST("h3d") + HIST(v0names[index]) + HIST("SpectrumY"), v0Data.pt(), collision.centFT0M(), v0.invMassRegion(index), weight); + constexpr int Index = i.value; + float efficiency = 1.0f; + if (applyEfficiencyCorrection) { + efficiency = hEfficiencyV0[Index]->Interpolate(v0Data.pt(), v0Data.eta()); + } + if (efficiency == 0) { // check for zero efficiency, do not apply if the case + efficiency = 1; + } + float weight = applyEfficiencyCorrection ? 1. / efficiency : 1.0f; + if (v0.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || v0.mcTrue(Index)) && (!doAssocPhysicalPrimary || v0.mcPhysicalPrimary()) && (!applyEfficiencyCorrection || efficiency != 0)) { + if (TESTBIT(doCorrelation, Index)) { + histos.fill(HIST("h3d") + HIST(kV0names[Index]) + HIST("Spectrum"), v0Data.pt(), collision.centFT0M(), v0.invMassNSigma(Index), weight); + if (std::abs(v0Data.rapidity(Index)) < 0.5) { + histos.fill(HIST("h3d") + HIST(kV0names[Index]) + HIST("SpectrumY"), v0Data.pt(), collision.centFT0M(), v0.invMassNSigma(Index), weight); + } + if ((-massWindowConfigurations.maxBgNSigma < v0.invMassNSigma(Index) && v0.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) || (+massWindowConfigurations.minBgNSigma < v0.invMassNSigma(Index) && v0.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma)) { + histos.fill(HIST("h") + HIST(kV0names[Index]) + HIST("EtaVsPtVsPhiBg"), v0Data.pt(), v0Data.eta(), v0Data.phi(), weight); + } + if (-massWindowConfigurations.maxPeakNSigma < v0.invMassNSigma(Index) && v0.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) { + histos.fill(HIST("h") + HIST(kV0names[Index]) + HIST("EtaVsPtVsPhi"), v0Data.pt(), v0Data.eta(), v0Data.phi(), weight); + } } - if (v0.invMassRegionCheck(index, 2)) - histos.fill(HIST("h") + HIST(v0names[index]) + HIST("EtaVsPtVsPhi"), v0Data.pt(), v0Data.eta(), v0Data.phi()); - if (v0.invMassRegionCheck(index, 1) || v0.invMassRegionCheck(index, 3)) - histos.fill(HIST("h") + HIST(v0names[index]) + HIST("EtaVsPtVsPhiBg"), v0Data.pt(), v0Data.eta(), v0Data.phi()); } }); } if (!doprocessSameEventHCascades) { for (auto const& triggerTrack : triggerTracks) { auto track = triggerTrack.track_as(); + if (!isValidTrigger(track)) + continue; + histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); + histos.fill(HIST("hTriggerPtResolution"), track.pt(), triggerTrack.mcOriginalPt()); + if (doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + continue; + histos.fill(HIST("hTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); histos.fill(HIST("hTrackEtaVsPtVsPhi"), track.pt(), track.eta(), track.phi()); } } @@ -693,19 +1153,19 @@ struct correlateStrangeness { fillCorrelationsV0(triggerTracks, associatedV0s, false, collision.posZ(), collision.centFT0M()); } - void processSameEventHCascades(soa::Join::iterator const& collision, + void processSameEventHCascades(soa::Join::iterator const& collision, aod::AssocV0s const&, aod::AssocCascades const& associatedCascades, aod::TriggerTracks const& triggerTracks, - V0DatasWithoutTrackX const&, aod::V0sLinked const&, aod::CascDatas const&, TracksComplete const&) + V0DatasWithoutTrackX const&, aod::CascDatas const&, TracksComplete const&, aod::BCsWithTimestamps const&) { // ________________________________________________ - // Perform basic event selection - if (!collision.sel8()) { - return; - } - if (TMath::Abs(collision.posZ()) > zVertexCut) { + // skip if desired trigger not found + if (triggerPresenceMap.size() > 0 && !TESTBIT(triggerPresenceMap[collision.globalIndex()], triggerBinToSelect)) { return; } - if (collision.centFT0M() > axisRanges[5][1] || collision.centFT0M() < axisRanges[5][0]) { + + // ________________________________________________ + // Perform basic event selection + if (!isCollisionSelected(collision)) { return; } // ________________________________________________ @@ -713,6 +1173,10 @@ struct correlateStrangeness { histos.fill(HIST("EventQA/hMult"), collision.centFT0M()); histos.fill(HIST("EventQA/hPvz"), collision.posZ()); // Do basic QA + if (applyEfficiencyCorrection) { + auto bc = collision.bc_as(); + initEfficiencyFromCCDB(bc); + } TH2F* hEfficiencyCascade[4]; hEfficiencyCascade[0] = hEfficiencyXiMinus; hEfficiencyCascade[1] = hEfficiencyXiPlus; @@ -721,43 +1185,87 @@ struct correlateStrangeness { for (auto const& casc : associatedCascades) { auto cascData = casc.cascData(); + + //---] syst cuts [--- + if (std::abs(cascData.dcapostopv()) < systCuts.dcapostopv || + std::abs(cascData.dcanegtopv()) < systCuts.dcanegtopv || + cascData.dcabachtopv() < systCuts.cascDcabachtopv || + cascData.dcaV0daughters() > systCuts.dcaV0dau || + cascData.dcacascdaughters() > systCuts.cascDcacascdau || + cascData.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < systCuts.v0cospa || + cascData.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < systCuts.cascCospa || + cascData.cascradius() < systCuts.cascRadius || + std::abs(cascData.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < systCuts.cascMindcav0topv || + std::abs(cascData.mLambda() - o2::constants::physics::MassLambda0) > systCuts.cascV0masswindow) + continue; + + //---] track quality check [--- + auto postrack = cascData.posTrack_as(); + auto negtrack = cascData.negTrack_as(); + auto bachtrack = cascData.bachelor_as(); + if (postrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated || bachtrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated) + continue; + static_for<0, 3>([&](auto i) { - constexpr int index = i.value; - float weight = applyEfficiencyCorrection ? 1. / hEfficiencyCascade[index]->GetBinContent(hEfficiencyCascade[index]->GetXaxis()->FindBin(cascData.pt()), hEfficiencyCascade[index]->GetYaxis()->FindBin(cascData.eta())) : 1.0f; - if (casc.compatible(index) && (!doMCassociation || casc.mcTrue(index)) && bitcheck(doCorrelation, index + 3)) { - histos.fill(HIST("h3d") + HIST(cascadenames[index]) + HIST("Spectrum"), cascData.pt(), collision.centFT0M(), casc.invMassRegion(index), weight); - if (std::abs(cascData.rapidity(index)) < 0.5) { - histos.fill(HIST("h3d") + HIST(cascadenames[index]) + HIST("SpectrumY"), cascData.pt(), collision.centFT0M(), casc.invMassRegion(index), weight); + constexpr int Index = i.value; + float efficiency = 1.0f; + if (applyEfficiencyCorrection) { + efficiency = hEfficiencyCascade[Index]->Interpolate(cascData.pt(), cascData.eta()); + } + if (efficiency == 0) { // check for zero efficiency, do not apply if the case + efficiency = 1; + } + float weight = applyEfficiencyCorrection ? 1. / efficiency : 1.0f; + if (casc.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || casc.mcTrue(Index)) && (!doAssocPhysicalPrimary || casc.mcPhysicalPrimary()) && (!applyEfficiencyCorrection || efficiency != 0)) { + if (TESTBIT(doCorrelation, Index + 3)) { + histos.fill(HIST("h3d") + HIST(kCascadenames[Index]) + HIST("Spectrum"), cascData.pt(), collision.centFT0M(), casc.invMassNSigma(Index), weight); + if (std::abs(cascData.rapidity(Index)) < 0.5) { + histos.fill(HIST("h3d") + HIST(kCascadenames[Index]) + HIST("SpectrumY"), cascData.pt(), collision.centFT0M(), casc.invMassNSigma(Index), weight); + } + if (-massWindowConfigurations.maxPeakNSigma < casc.invMassNSigma(Index) && casc.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) { + histos.fill(HIST("h") + HIST(kCascadenames[Index]) + HIST("EtaVsPtVsPhi"), cascData.pt(), cascData.eta(), cascData.phi(), weight); + } + if ((-massWindowConfigurations.maxBgNSigma < casc.invMassNSigma(Index) && casc.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) || (+massWindowConfigurations.minBgNSigma < casc.invMassNSigma(Index) && casc.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma)) { + histos.fill(HIST("h") + HIST(kCascadenames[Index]) + HIST("EtaVsPtVsPhiBg"), cascData.pt(), cascData.eta(), cascData.phi(), weight); + } } - if (casc.invMassRegionCheck(index, 2)) - histos.fill(HIST("h") + HIST(cascadenames[index]) + HIST("EtaVsPtVsPhi"), cascData.pt(), cascData.eta(), cascData.phi()); - if (casc.invMassRegionCheck(index, 1) || casc.invMassRegionCheck(index, 3)) - histos.fill(HIST("h") + HIST(cascadenames[index]) + HIST("EtaVsPtVsPhiBg"), cascData.pt(), cascData.eta(), cascData.phi()); } }); } for (auto const& triggerTrack : triggerTracks) { auto track = triggerTrack.track_as(); + if (!isValidTrigger(track)) + continue; + histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); + histos.fill(HIST("hTriggerPtResolution"), track.pt(), triggerTrack.mcOriginalPt()); + if (doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + continue; + histos.fill(HIST("hTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); histos.fill(HIST("hTrackEtaVsPtVsPhi"), track.pt(), track.eta(), track.phi()); } // ________________________________________________ // Do hadron - cascade correlations - fillCorrelationsCascade(triggerTracks, associatedCascades, false, collision.posZ(), collision.centFT0M()); + fillCorrelationsCascade(triggerTracks, associatedCascades, false, collision.posX(), collision.posY(), collision.posZ(), collision.centFT0M()); } - void processSameEventHPions(soa::Join::iterator const& collision, - aod::AssocPions const& associatedPions, aod::TriggerTracks const& triggerTracks, - TracksComplete const&) + void processSameEventHPions(soa::Join::iterator const& collision, + soa::Join const& associatedPions, soa::Join const& triggerTracks, + TracksComplete const&, aod::BCsWithTimestamps const&) { // ________________________________________________ - // Perform basic event selection - if (!collision.sel8()) { + // skip if desired trigger not found + if (triggerPresenceMap.size() > 0 && !TESTBIT(triggerPresenceMap[collision.globalIndex()], triggerBinToSelect)) { return; } - if (TMath::Abs(collision.posZ()) > zVertexCut) { - return; + + if (applyEfficiencyCorrection) { + auto bc = collision.bc_as(); + initEfficiencyFromCCDB(bc); } - if (collision.centFT0M() > axisRanges[5][1] || collision.centFT0M() < axisRanges[5][0]) { + + // ________________________________________________ + // Perform basic event selection + if (!isCollisionSelected(collision)) { return; } // ________________________________________________ @@ -774,25 +1282,85 @@ struct correlateStrangeness { if (!doprocessSameEventHCascades && !doprocessSameEventHV0s) { for (auto const& triggerTrack : triggerTracks) { auto track = triggerTrack.track_as(); + if (!isValidTrigger(track)) + continue; + histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); + histos.fill(HIST("hTriggerPtResolution"), track.pt(), triggerTrack.mcOriginalPt()); + if (doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + continue; + histos.fill(HIST("hTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); histos.fill(HIST("hTrackEtaVsPtVsPhi"), track.pt(), track.eta(), track.phi()); } } // ________________________________________________ // Do hadron - Pion correlations - fillCorrelationsPion(triggerTracks, associatedPions, false, collision.posZ(), collision.centFT0M()); + fillCorrelationsHadron(triggerTracks, associatedPions, false, collision.posZ(), collision.centFT0M()); } - void processMixedEventHV0s(soa::Join const& collisions, - aod::AssocV0s const& associatedV0s, aod::TriggerTracks const& triggerTracks, - V0DatasWithoutTrackX const&, aod::V0sLinked const&, TracksComplete const&) + + void processMixedEventHHadrons(soa::Join const& collisions, + aod::AssocHadrons const& assocHadrons, aod::TriggerTracks const& triggerTracks, + TracksComplete const&, aod::BCsWithTimestamps const&) { - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, mixingParameter, -1, collisions, collisions)) { + for (auto const& [collision1, collision2] : soa::selfCombinations(colBinning, mixingParameter, -1, collisions, collisions)) { + // ________________________________________________ + if (applyEfficiencyCorrection) { + auto bc = collision1.bc_as(); + initEfficiencyFromCCDB(bc); + } + // ________________________________________________ + // skip if desired trigger not found + if (triggerPresenceMap.size() > 0 && (!TESTBIT(triggerPresenceMap[collision1.globalIndex()], triggerBinToSelect) || !TESTBIT(triggerPresenceMap[collision2.globalIndex()], triggerBinToSelect))) { + return; + } + // ________________________________________________ // Perform basic event selection on both collisions - if (!collision1.sel8() || !collision2.sel8()) + if (!isCollisionSelected(collision1) || !isCollisionSelected(collision2)) { + continue; + } + if (collision1.centFT0M() > axisRanges[5][1] || collision1.centFT0M() < axisRanges[5][0]) + continue; + if (collision2.centFT0M() > axisRanges[5][1] || collision2.centFT0M() < axisRanges[5][0]) + continue; + + if (collision1.globalIndex() == collision2.globalIndex()) { + histos.fill(HIST("MixingQA/hMixingQA"), 0.0f); // same-collision pair counting + } + + histos.fill(HIST("MixingQA/hMEpvz1"), collision1.posZ()); + histos.fill(HIST("MixingQA/hMEpvz2"), collision2.posZ()); + histos.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), collision1.centFT0M()})); + // ________________________________________________ + // Do slicing + auto slicedTriggerTracks = triggerTracks.sliceBy(collisionSliceTracks, collision1.globalIndex()); + auto slicedAssocHadrons = assocHadrons.sliceBy(collisionSliceHadrons, collision2.globalIndex()); + // ________________________________________________ + // Do hadron - hadron correlations + fillCorrelationsHadron(slicedTriggerTracks, slicedAssocHadrons, true, collision1.posZ(), collision1.centFT0M()); + } + } + + void processMixedEventHV0s(soa::Join const& collisions, + aod::AssocV0s const& associatedV0s, aod::TriggerTracks const& triggerTracks, + V0DatasWithoutTrackX const&, TracksComplete const&, aod::BCsWithTimestamps const&) + { + for (auto const& [collision1, collision2] : soa::selfCombinations(colBinning, mixingParameter, -1, collisions, collisions)) { + // ________________________________________________ + if (applyEfficiencyCorrection) { + auto bc = collision1.bc_as(); + initEfficiencyFromCCDB(bc); + } + // ________________________________________________ + // skip if desired trigger not found + if (triggerPresenceMap.size() > 0 && (!TESTBIT(triggerPresenceMap[collision1.globalIndex()], triggerBinToSelect) || !TESTBIT(triggerPresenceMap[collision2.globalIndex()], triggerBinToSelect))) { continue; - if (TMath::Abs(collision1.posZ()) > zVertexCut || TMath::Abs(collision2.posZ()) > zVertexCut) + } + + // Perform basic event selection on both collisions + if (!isCollisionSelected(collision1) || !isCollisionSelected(collision2)) { continue; + } if (collision1.centFT0M() > axisRanges[5][1] || collision1.centFT0M() < axisRanges[5][0]) continue; if (collision2.centFT0M() > axisRanges[5][1] || collision2.centFT0M() < axisRanges[5][0]) @@ -815,17 +1383,26 @@ struct correlateStrangeness { fillCorrelationsV0(slicedTriggerTracks, slicedAssocV0s, true, collision1.posZ(), collision1.centFT0M()); } } - void processMixedEventHCascades(soa::Join const& collisions, + void processMixedEventHCascades(soa::Join const& collisions, aod::AssocV0s const&, aod::AssocCascades const& associatedCascades, aod::TriggerTracks const& triggerTracks, - V0DatasWithoutTrackX const&, aod::V0sLinked const&, aod::CascDatas const&, TracksComplete const&) + V0DatasWithoutTrackX const&, aod::CascDatas const&, TracksComplete const&, aod::BCsWithTimestamps const&) { - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, mixingParameter, -1, collisions, collisions)) { + for (auto const& [collision1, collision2] : soa::selfCombinations(colBinning, mixingParameter, -1, collisions, collisions)) { // ________________________________________________ - // Perform basic event selection on both collisions - if (!collision1.sel8() || !collision2.sel8()) + if (applyEfficiencyCorrection) { + auto bc = collision1.bc_as(); + initEfficiencyFromCCDB(bc); + } + // ________________________________________________ + // skip if desired trigger not found + if (triggerPresenceMap.size() > 0 && (!TESTBIT(triggerPresenceMap[collision1.globalIndex()], triggerBinToSelect) || !TESTBIT(triggerPresenceMap[collision2.globalIndex()], triggerBinToSelect))) { continue; - if (TMath::Abs(collision1.posZ()) > zVertexCut || TMath::Abs(collision2.posZ()) > zVertexCut) + } + + // Perform basic event selection on both collisions + if (!isCollisionSelected(collision1) || !isCollisionSelected(collision2)) { continue; + } if (collision1.centFT0M() > axisRanges[5][1] || collision1.centFT0M() < axisRanges[5][0]) continue; if (collision2.centFT0M() > axisRanges[5][1] || collision2.centFT0M() < axisRanges[5][0]) @@ -844,20 +1421,30 @@ struct correlateStrangeness { auto slicedAssocCascades = associatedCascades.sliceBy(collisionSliceCascades, collision2.globalIndex()); // ________________________________________________ // Do hadron - cascade correlations - fillCorrelationsCascade(slicedTriggerTracks, slicedAssocCascades, true, collision1.posZ(), collision1.centFT0M()); + fillCorrelationsCascade(slicedTriggerTracks, slicedAssocCascades, true, collision1.posX(), collision1.posY(), collision1.posZ(), collision1.centFT0M()); } } - void processMixedEventHPions(soa::Join const& collisions, - aod::AssocPions const& assocPions, aod::TriggerTracks const& triggerTracks, - TracksComplete const&) + void processMixedEventHPions(soa::Join const& collisions, + soa::Join const& assocPions, soa::Join const& triggerTracks, + TracksComplete const&, aod::BCsWithTimestamps const&) { - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, mixingParameter, -1, collisions, collisions)) { + for (auto const& [collision1, collision2] : soa::selfCombinations(colBinning, mixingParameter, -1, collisions, collisions)) { // ________________________________________________ - // Perform basic event selection on both collisions - if (!collision1.sel8() || !collision2.sel8()) + if (applyEfficiencyCorrection) { + auto bc = collision1.bc_as(); + initEfficiencyFromCCDB(bc); + } + // ________________________________________________ + // skip if desired trigger not found + if (triggerPresenceMap.size() > 0 && (!TESTBIT(triggerPresenceMap[collision1.globalIndex()], triggerBinToSelect) || !TESTBIT(triggerPresenceMap[collision2.globalIndex()], triggerBinToSelect))) { continue; - if (TMath::Abs(collision1.posZ()) > zVertexCut || TMath::Abs(collision2.posZ()) > zVertexCut) + } + + // ________________________________________________ + // Perform basic event selection on both collisions + if (!isCollisionSelected(collision1) || !isCollisionSelected(collision2)) { continue; + } if (collision1.centFT0M() > axisRanges[5][1] || collision1.centFT0M() < axisRanges[5][0]) continue; if (collision2.centFT0M() > axisRanges[5][1] || collision2.centFT0M() < axisRanges[5][0]) @@ -873,35 +1460,50 @@ struct correlateStrangeness { // ________________________________________________ // Do slicing auto slicedTriggerTracks = triggerTracks.sliceBy(collisionSliceTracks, collision1.globalIndex()); - auto slicedAssocPions = assocPions.sliceBy(collisionSlicePions, collision2.globalIndex()); + auto slicedAssocPions = assocPions.sliceBy(collisionSliceHadrons, collision2.globalIndex()); // ________________________________________________ // Do hadron - cascade correlations - fillCorrelationsPion(slicedTriggerTracks, slicedAssocPions, true, collision1.posZ(), collision1.centFT0M()); + fillCorrelationsHadron(slicedTriggerTracks, slicedAssocPions, true, collision1.posZ(), collision1.centFT0M()); } } - void processMCGenerated(aod::McCollision const&, soa::SmallGroups> const& collisions, aod::McParticles const& mcParticles) + + void processMCGenerated(aod::McCollision const& /*mcCollision*/, soa::SmallGroups> const& collisions, aod::McParticles const& mcParticles) { + histos.fill(HIST("hClosureTestEventCounter"), 2.5f); + for (auto const& mcParticle : mcParticles) { - if (!mcParticle.isPhysicalPrimary()) + double geta = mcParticle.eta(); + if (std::abs(geta) > 0.8f) { continue; - if (abs(mcParticle.pdgCode()) == 211) - histos.fill(HIST("Generated/hPion"), mcParticle.pt(), mcParticle.eta()); - if (abs(mcParticle.pdgCode()) == 310) - histos.fill(HIST("Generated/hK0Short"), mcParticle.pt(), mcParticle.eta()); - if (mcParticle.pdgCode() == 3122) - histos.fill(HIST("Generated/hLambda"), mcParticle.pt(), mcParticle.eta()); - if (mcParticle.pdgCode() == -3122) - histos.fill(HIST("Generated/hAntiLambda"), mcParticle.pt(), mcParticle.eta()); - if (mcParticle.pdgCode() == 3312) - histos.fill(HIST("Generated/hXiMinus"), mcParticle.pt(), mcParticle.eta()); - if (mcParticle.pdgCode() == -3312) - histos.fill(HIST("Generated/hXiPlus"), mcParticle.pt(), mcParticle.eta()); - if (mcParticle.pdgCode() == 3334) - histos.fill(HIST("Generated/hOmegaMinus"), mcParticle.pt(), mcParticle.eta()); - if (mcParticle.pdgCode() == -3334) - histos.fill(HIST("Generated/hOmegaPlus"), mcParticle.pt(), mcParticle.eta()); + } + double gpt = mcParticle.pt(); + if (std::abs(mcParticle.pdgCode()) == 211 || std::abs(mcParticle.pdgCode()) == 321 || std::abs(mcParticle.pdgCode()) == 2212 || std::abs(mcParticle.pdgCode()) == 11 || std::abs(mcParticle.pdgCode()) == 13) { + if (!doTriggPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + histos.fill(HIST("hGeneratedQAPtTrigger"), gpt, 0.0f); // step 1: before all selections + } + } + + if (!doAssocPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + if (mcParticle.pdgCode() == 310 && doCorrelationK0Short) { + histos.fill(HIST("hGeneratedQAPtAssociatedK0"), gpt, 0.0f); // step 1: before all selections + } + } } + for (auto const& mcParticle : mcParticles) { + if (!mcParticle.isPhysicalPrimary()) + continue; + static_for<0, 7>([&](auto i) { + constexpr int Index = i.value; + if (i == 0 || i == 7) { + if (std::abs(mcParticle.pdgCode()) == kPdgCodes[i]) + histos.fill(HIST("Generated/h") + HIST(kParticlenames[Index]), mcParticle.pt(), mcParticle.eta()); + } else { + if (mcParticle.pdgCode() == kPdgCodes[i]) + histos.fill(HIST("Generated/h") + HIST(kParticlenames[Index]), mcParticle.pt(), mcParticle.eta()); + } + }); + } if (collisions.size() < 1) return; @@ -910,12 +1512,18 @@ struct correlateStrangeness { int bestCollisionFT0Mpercentile = -1; float bestCollisionVtxZ = 0.0f; bool bestCollisionSel8 = false; - for (auto& collision : collisions) { + bool bestCollisionINELgtZERO = false; + uint32_t bestCollisionTriggerPresenceMap = 0; + + for (auto const& collision : collisions) { if (biggestNContribs < collision.numContrib()) { biggestNContribs = collision.numContrib(); bestCollisionFT0Mpercentile = collision.centFT0M(); bestCollisionSel8 = collision.sel8(); bestCollisionVtxZ = collision.posZ(); + bestCollisionINELgtZERO = collision.isInelGt0(); + if (triggerPresenceMap.size() > 0) + bestCollisionTriggerPresenceMap = triggerPresenceMap[collision.globalIndex()]; } } @@ -923,87 +1531,358 @@ struct correlateStrangeness { for (auto const& mcParticle : mcParticles) { if (!mcParticle.isPhysicalPrimary()) continue; - if (abs(mcParticle.y()) < 0.5) { - if (abs(mcParticle.pdgCode()) == 211) - histos.fill(HIST("GeneratedWithPV/hPion_MidYVsMult_TwoPVsOrMore"), mcParticle.pt(), bestCollisionFT0Mpercentile); - if (abs(mcParticle.pdgCode()) == 310) - histos.fill(HIST("GeneratedWithPV/hK0Short_MidYVsMult_TwoPVsOrMore"), mcParticle.pt(), bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == 3122) - histos.fill(HIST("GeneratedWithPV/hLambda_MidYVsMult_TwoPVsOrMore"), mcParticle.pt(), bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == -3122) - histos.fill(HIST("GeneratedWithPV/hAntiLambda_MidYVsMult_TwoPVsOrMore"), mcParticle.pt(), bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == 3312) - histos.fill(HIST("GeneratedWithPV/hXiMinus_MidYVsMult_TwoPVsOrMore"), mcParticle.pt(), bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == -3312) - histos.fill(HIST("GeneratedWithPV/hXiPlus_MidYVsMult_TwoPVsOrMore"), mcParticle.pt(), bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == 3334) - histos.fill(HIST("GeneratedWithPV/hOmegaMinus_MidYVsMult_TwoPVsOrMore"), mcParticle.pt(), bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == -3334) - histos.fill(HIST("GeneratedWithPV/hOmegaPlus_MidYVsMult_TwoPVsOrMore"), mcParticle.pt(), bestCollisionFT0Mpercentile); - } + if (std::abs(mcParticle.y()) > 0.5) + continue; + static_for<0, 7>([&](auto i) { + constexpr int Index = i.value; + if (i == 0 || i == 7) { + if (std::abs(mcParticle.pdgCode()) == kPdgCodes[i]) + histos.fill(HIST("GeneratedWithPV/h") + HIST(kParticlenames[Index]) + HIST("_MidYVsMult_TwoPVsOrMore"), mcParticle.pt(), bestCollisionFT0Mpercentile); + } else { + if (mcParticle.pdgCode() == kPdgCodes[i]) + histos.fill(HIST("GeneratedWithPV/h") + HIST(kParticlenames[Index]) + HIST("_MidYVsMult_TwoPVsOrMore"), mcParticle.pt(), bestCollisionFT0Mpercentile); + } + }); } } // do selections on best collision // WARNING: if 2 PV case large, this will not necessarily be fine! // caution advised! + + // ________________________________________________ + // skip if desired trigger not found + if (triggerPresenceMap.size() > 0 && !TESTBIT(bestCollisionTriggerPresenceMap, triggerBinToSelect)) { + return; + } if (!bestCollisionSel8) return; if (std::abs(bestCollisionVtxZ) > 10.0f) return; + if (!bestCollisionINELgtZERO) + return; + + histos.fill(HIST("hClosureTestEventCounter"), 3.5f); for (auto const& mcParticle : mcParticles) { - if (!mcParticle.isPhysicalPrimary()) + double geta = mcParticle.eta(); + if (std::abs(geta) > 0.8f) { + continue; + } + double gpt = mcParticle.pt(); + if (std::abs(mcParticle.pdgCode()) == 211 || std::abs(mcParticle.pdgCode()) == 321 || std::abs(mcParticle.pdgCode()) == 2212 || std::abs(mcParticle.pdgCode()) == 11 || std::abs(mcParticle.pdgCode()) == 13) { + if (!doTriggPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + histos.fill(HIST("hGeneratedQAPtTrigger"), gpt, 1.0f); // step 2: after event selection + } + } + + if (!doAssocPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + if (mcParticle.pdgCode() == 310 && doCorrelationK0Short) { + histos.fill(HIST("hGeneratedQAPtAssociatedK0"), gpt, 1.0f); // step 2: before all selections + } + } + } + + for (auto const& mcParticle : mcParticles) { + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + double geta = mcParticle.eta(); + double gpt = mcParticle.pt(); + if (std::abs(mcParticle.pdgCode()) == 211 || std::abs(mcParticle.pdgCode()) == 321 || std::abs(mcParticle.pdgCode()) == 2212 || std::abs(mcParticle.pdgCode()) == 11 || std::abs(mcParticle.pdgCode()) == 13) + histos.fill(HIST("GeneratedWithPV/hTrigger"), gpt, geta); + static_for<0, 7>([&](auto i) { + constexpr int Index = i.value; + if (i == 0 || i == 7) { + if (std::abs(mcParticle.pdgCode()) == kPdgCodes[i]) { + histos.fill(HIST("GeneratedWithPV/h") + HIST(kParticlenames[Index]), gpt, geta); + if (std::abs(mcParticle.y()) < 0.5) + histos.fill(HIST("GeneratedWithPV/h") + HIST(kParticlenames[Index]) + HIST("_MidYVsMult"), gpt, bestCollisionFT0Mpercentile); + } + + } else { + if (mcParticle.pdgCode() == kPdgCodes[i]) { + histos.fill(HIST("GeneratedWithPV/h") + HIST(kParticlenames[Index]), gpt, geta); + if (std::abs(mcParticle.y()) < 0.5) + histos.fill(HIST("GeneratedWithPV/h") + HIST(kParticlenames[Index]) + HIST("_MidYVsMult"), gpt, bestCollisionFT0Mpercentile); + } + } + }); + } + } + void processClosureTest(aod::McCollision const& /*mcCollision*/, soa::SmallGroups> const& recCollisions, aod::McParticles const& mcParticles) + { + + std::vector triggerIndices; + std::vector> associatedIndices; + std::vector piIndices; + std::vector k0ShortIndices; + std::vector lambdaIndices; + std::vector antiLambdaIndices; + std::vector xiMinusIndices; + std::vector xiPlusIndices; + std::vector omegaMinusIndices; + std::vector omegaPlusIndices; + + for (auto const& mcParticle : mcParticles) { + double geta = mcParticle.eta(); + if (std::abs(geta) > 0.8f) { + continue; + } + double gpt = mcParticle.pt(); + if (std::abs(mcParticle.pdgCode()) == 211 || std::abs(mcParticle.pdgCode()) == 321 || std::abs(mcParticle.pdgCode()) == 2212 || std::abs(mcParticle.pdgCode()) == 11 || std::abs(mcParticle.pdgCode()) == 13) { + if (!doTriggPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + histos.fill(HIST("hClosureQAPtTrigger"), gpt, 0.0f); // step 1: no event selection whatsoever + } + } + + if (!doAssocPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + if (mcParticle.pdgCode() == 310 && doCorrelationK0Short) { + histos.fill(HIST("hClosureQAPtAssociatedK0"), gpt, 0.0f); // step 1: no event selection whatsoever + } + } + } + + histos.fill(HIST("hClosureTestEventCounter"), 0.5f); + + int bestCollisionFT0Mpercentile = -1; + float bestCollisionVtxZ = 0.0f; + bool bestCollisionSel8 = false; + bool bestCollisionINELgtZERO = false; + int biggestNContribs = -1; + uint32_t bestCollisionTriggerPresenceMap = 0; + + for (auto const& recCollision : recCollisions) { + if (biggestNContribs < recCollision.numContrib()) { + biggestNContribs = recCollision.numContrib(); + bestCollisionFT0Mpercentile = recCollision.centFT0M(); + bestCollisionSel8 = recCollision.sel8(); + bestCollisionVtxZ = recCollision.posZ(); + bestCollisionINELgtZERO = recCollision.isInelGt0(); + if (triggerPresenceMap.size() > 0) + bestCollisionTriggerPresenceMap = triggerPresenceMap[recCollision.globalIndex()]; + } + } + // ________________________________________________ + // skip if desired trigger not found + if (triggerPresenceMap.size() > 0 && !TESTBIT(bestCollisionTriggerPresenceMap, triggerBinToSelect)) { + return; + } + + if (doGenEventSelection) { + if (!bestCollisionSel8) + return; + if (std::abs(bestCollisionVtxZ) > zVertexCut) + return; + if (!bestCollisionINELgtZERO) + return; + if (bestCollisionFT0Mpercentile > axisRanges[5][1] || bestCollisionFT0Mpercentile < axisRanges[5][0]) { + return; + } + } + + histos.fill(HIST("hClosureTestEventCounter"), 1.5f); + + for (auto const& mcParticle : mcParticles) { + double geta = mcParticle.eta(); + if (std::abs(geta) > 0.8f) { + continue; + } + double gpt = mcParticle.pt(); + if (std::abs(mcParticle.pdgCode()) == 211 || std::abs(mcParticle.pdgCode()) == 321 || std::abs(mcParticle.pdgCode()) == 2212 || std::abs(mcParticle.pdgCode()) == 11 || std::abs(mcParticle.pdgCode()) == 13) { + if (!doTriggPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + histos.fill(HIST("hClosureQAPtTrigger"), gpt, 1.0f); // step 2: after event selection + } + } + + if (!doAssocPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + if (mcParticle.pdgCode() == 310 && doCorrelationK0Short) { + histos.fill(HIST("hClosureQAPtAssociatedK0"), gpt, 1.0f); // step 2: after event selection + } + } + } + + int iteratorNum = -1; + for (auto const& mcParticle : mcParticles) { + iteratorNum = iteratorNum + 1; + double geta = mcParticle.eta(); + double gpt = mcParticle.pt(); + double gphi = mcParticle.phi(); + if (std::abs(geta) > 0.8f) { + continue; + } + if (std::abs(mcParticle.pdgCode()) == 211 || std::abs(mcParticle.pdgCode()) == 321 || std::abs(mcParticle.pdgCode()) == 2212 || std::abs(mcParticle.pdgCode()) == 11 || std::abs(mcParticle.pdgCode()) == 13) { + if (!doTriggPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + triggerIndices.emplace_back(iteratorNum); + histos.fill(HIST("ClosureTest/hTrigger"), gpt, geta, bestCollisionFT0Mpercentile); + } + } + if (!doAssocPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + if (std::abs(mcParticle.pdgCode()) == 211 && doCorrelationPion) { + piIndices.emplace_back(iteratorNum); + histos.fill(HIST("ClosureTest/hPion"), gpt, geta, gphi); + } + if (mcParticle.pdgCode() == 310 && doCorrelationK0Short) { + k0ShortIndices.emplace_back(iteratorNum); + histos.fill(HIST("ClosureTest/hK0Short"), gpt, geta, gphi); + } + if (mcParticle.pdgCode() == 3122 && doCorrelationLambda) { + lambdaIndices.emplace_back(iteratorNum); + histos.fill(HIST("ClosureTest/hLambda"), gpt, geta, gphi); + } + if (mcParticle.pdgCode() == -3122 && doCorrelationAntiLambda) { + antiLambdaIndices.emplace_back(iteratorNum); + histos.fill(HIST("ClosureTest/hAntiLambda"), gpt, geta, gphi); + } + if (mcParticle.pdgCode() == 3312 && doCorrelationXiMinus) { + xiMinusIndices.emplace_back(iteratorNum); + histos.fill(HIST("ClosureTest/hXiMinus"), gpt, geta, gphi); + } + if (mcParticle.pdgCode() == -3312 && doCorrelationXiPlus) { + xiPlusIndices.emplace_back(iteratorNum); + histos.fill(HIST("ClosureTest/hXiPlus"), gpt, geta, gphi); + } + if (mcParticle.pdgCode() == 3334 && doCorrelationOmegaMinus) { + omegaMinusIndices.emplace_back(iteratorNum); + histos.fill(HIST("ClosureTest/hOmegaMinus"), gpt, geta, gphi); + } + if (mcParticle.pdgCode() == -3334 && doCorrelationOmegaPlus) { + omegaPlusIndices.emplace_back(iteratorNum); + histos.fill(HIST("ClosureTest/hOmegaPlus"), gpt, geta, gphi); + } + } + } + + associatedIndices.emplace_back(k0ShortIndices); + associatedIndices.emplace_back(lambdaIndices); + associatedIndices.emplace_back(antiLambdaIndices); + associatedIndices.emplace_back(xiMinusIndices); + associatedIndices.emplace_back(xiPlusIndices); + associatedIndices.emplace_back(omegaMinusIndices); + associatedIndices.emplace_back(omegaPlusIndices); + associatedIndices.emplace_back(piIndices); + + for (std::size_t iTrigger = 0; iTrigger < triggerIndices.size(); iTrigger++) { + auto triggerParticle = mcParticles.iteratorAt(triggerIndices[iTrigger]); + // check range of trigger particle + if (triggerParticle.pt() > axisRanges[3][1] || triggerParticle.pt() < axisRanges[3][0]) { continue; - if (abs(mcParticle.pdgCode()) == 211) - histos.fill(HIST("GeneratedWithPV/hPion"), mcParticle.pt(), mcParticle.eta()); - if (abs(mcParticle.pdgCode()) == 310) - histos.fill(HIST("GeneratedWithPV/hK0Short"), mcParticle.pt(), mcParticle.eta()); - if (mcParticle.pdgCode() == 3122) - histos.fill(HIST("GeneratedWithPV/hLambda"), mcParticle.pt(), mcParticle.eta()); - if (mcParticle.pdgCode() == -3122) - histos.fill(HIST("GeneratedWithPV/hAntiLambda"), mcParticle.pt(), mcParticle.eta()); - if (mcParticle.pdgCode() == 3312) - histos.fill(HIST("GeneratedWithPV/hXiMinus"), mcParticle.pt(), mcParticle.eta()); - if (mcParticle.pdgCode() == -3312) - histos.fill(HIST("GeneratedWithPV/hXiPlus"), mcParticle.pt(), mcParticle.eta()); - if (mcParticle.pdgCode() == 3334) - histos.fill(HIST("GeneratedWithPV/hOmegaMinus"), mcParticle.pt(), mcParticle.eta()); - if (mcParticle.pdgCode() == -3334) - histos.fill(HIST("GeneratedWithPV/hOmegaPlus"), mcParticle.pt(), mcParticle.eta()); - - if (abs(mcParticle.y()) < 0.5) { - if (abs(mcParticle.pdgCode()) == 211) - histos.fill(HIST("GeneratedWithPV/hPion_MidYVsMult"), mcParticle.pt(), bestCollisionFT0Mpercentile); - if (abs(mcParticle.pdgCode()) == 310) - histos.fill(HIST("GeneratedWithPV/hK0Short_MidYVsMult"), mcParticle.pt(), bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == 3122) - histos.fill(HIST("GeneratedWithPV/hLambda_MidYVsMult"), mcParticle.pt(), bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == -3122) - histos.fill(HIST("GeneratedWithPV/hAntiLambda_MidYVsMult"), mcParticle.pt(), bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == 3312) - histos.fill(HIST("GeneratedWithPV/hXiMinus_MidYVsMult"), mcParticle.pt(), bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == -3312) - histos.fill(HIST("GeneratedWithPV/hXiPlus_MidYVsMult"), mcParticle.pt(), bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == 3334) - histos.fill(HIST("GeneratedWithPV/hOmegaMinus_MidYVsMult"), mcParticle.pt(), bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == -3334) - histos.fill(HIST("GeneratedWithPV/hOmegaPlus_MidYVsMult"), mcParticle.pt(), bestCollisionFT0Mpercentile); } + double getatrigger = triggerParticle.eta(); + double gphitrigger = triggerParticle.phi(); + double pttrigger = triggerParticle.pt(); + auto const& mother = triggerParticle.mothers_first_as(); + auto globalIndex = mother.globalIndex(); + static_for<0, 7>([&](auto i) { // associated loop + constexpr int Index = i.value; + for (std::size_t iassoc = 0; iassoc < associatedIndices[Index].size(); iassoc++) { + auto assocParticle = mcParticles.iteratorAt(associatedIndices[Index][iassoc]); + if (triggerIndices[iTrigger] != associatedIndices[Index][iassoc] && globalIndex != assocParticle.globalIndex()) { // avoid self + double getaassoc = assocParticle.eta(); + double gphiassoc = assocParticle.phi(); + double ptassoc = assocParticle.pt(); + double deltaphi = computeDeltaPhi(gphitrigger, gphiassoc); + double deltaeta = getatrigger - getaassoc; + + // skip if basic ranges not met + if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) + continue; + if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) + continue; + if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) + continue; + if (TESTBIT(doCorrelation, i)) + histos.fill(HIST("ClosureTest/sameEvent/") + HIST(kParticlenames[Index]), computeDeltaPhi(gphitrigger, gphiassoc), deltaeta, ptassoc, pttrigger, bestCollisionVtxZ, bestCollisionFT0Mpercentile); + } + } + }); } } - PROCESS_SWITCH(correlateStrangeness, processSameEventHV0s, "Process same events, h-V0s", true); - PROCESS_SWITCH(correlateStrangeness, processSameEventHCascades, "Process same events, h-Cascades", true); - PROCESS_SWITCH(correlateStrangeness, processSameEventHPions, "Process same events, h-Pion", true); - PROCESS_SWITCH(correlateStrangeness, processMixedEventHV0s, "Process mixed events, h-V0s", true); - PROCESS_SWITCH(correlateStrangeness, processMixedEventHCascades, "Process mixed events, h-Cascades", true); - PROCESS_SWITCH(correlateStrangeness, processMixedEventHPions, "Process mixed events, h-Pion", true); - PROCESS_SWITCH(correlateStrangeness, processMCGenerated, "Process MC generated", true); + void processFeedDown(soa::Join::iterator const& collision, aod::AssocV0s const& associatedV0s, aod::McParticles const&, V0DatasWithoutTrackXMC const&, TracksComplete const&, aod::BCsWithTimestamps const&) + { + + // ________________________________________________ + // Perform basic event selection + if (!isCollisionSelected(collision)) { + return; + } + + for (auto const& v0 : associatedV0s) { + auto v0Data = v0.v0Core_as(); + + //---] track quality check [--- + auto postrack = v0Data.posTrack_as(); + auto negtrack = v0Data.negTrack_as(); + if (postrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRowsAssociated) + continue; + + //---] syst cuts [--- + if (v0Data.v0radius() < systCuts.v0RadiusMin || v0Data.v0radius() > systCuts.v0RadiusMax || + std::abs(v0Data.dcapostopv()) < systCuts.dcapostopv || std::abs(v0Data.dcanegtopv()) < systCuts.dcanegtopv || + v0Data.v0cosPA() < systCuts.v0cospa || v0Data.dcaV0daughters() > systCuts.dcaV0dau) + continue; + + if (v0Data.has_mcParticle()) { + auto v0mcParticle = v0Data.mcParticle_as(); + int mcParticlePdg = v0mcParticle.pdgCode(); + if (mcParticlePdg == 3122 && !v0mcParticle.isPhysicalPrimary()) { + auto v0mothers = v0mcParticle.mothers_as(); + if (!v0mothers.empty()) { + auto& v0mcParticleMother = v0mothers.front(); // First mother + if (v0mcParticleMother.pdgCode() == 3312) // Xi Minus Mother Matched + { + histos.fill(HIST("hLambdaXiMinusFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt()); + } + if (v0mcParticleMother.pdgCode() == 3322) // Xi Zero Mother Matched + { + histos.fill(HIST("hLambdaXiZeroFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt()); + } + if (v0mcParticleMother.pdgCode() == 3334) // Omega Mother Matched + { + histos.fill(HIST("hLambdaOmegaFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt()); + } + } + } + if (mcParticlePdg == -3122 && !v0mcParticle.isPhysicalPrimary()) { + auto v0mothers = v0mcParticle.mothers_as(); + if (!v0mothers.empty()) { + auto& v0mcParticleMother = v0mothers.front(); // First mother + if (v0mcParticleMother.pdgCode() == -3312) // Xi Plus Mother Matched + { + histos.fill(HIST("hAntiLambdaXiPlusFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt()); + } + if (v0mcParticleMother.pdgCode() == -3322) // Anti Xi Zero Mother Matched + { + histos.fill(HIST("hAntiLambdaXiZeroFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt()); + } + if (v0mcParticleMother.pdgCode() == -3334) // Omega Mother Matched + { + histos.fill(HIST("hAntiLambdaOmegaFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt()); + } + } + } + } + } + } + PROCESS_SWITCH(HStrangeCorrelation, processSelectEventWithTrigger, "Select events with trigger only", true); + PROCESS_SWITCH(HStrangeCorrelation, processSameEventHV0s, "Process same events, h-V0s", true); + PROCESS_SWITCH(HStrangeCorrelation, processSameEventHCascades, "Process same events, h-Cascades", true); + PROCESS_SWITCH(HStrangeCorrelation, processSameEventHPions, "Process same events, h-Pion", true); + PROCESS_SWITCH(HStrangeCorrelation, processSameEventHHadrons, "Process same events, h-h", true); + + PROCESS_SWITCH(HStrangeCorrelation, processMixedEventHV0s, "Process mixed events, h-V0s", true); + PROCESS_SWITCH(HStrangeCorrelation, processMixedEventHCascades, "Process mixed events, h-Cascades", true); + PROCESS_SWITCH(HStrangeCorrelation, processMixedEventHPions, "Process mixed events, h-Pion", true); + PROCESS_SWITCH(HStrangeCorrelation, processMixedEventHHadrons, "Process mixed events, h-h", true); + + PROCESS_SWITCH(HStrangeCorrelation, processMCGenerated, "Process MC generated", false); + PROCESS_SWITCH(HStrangeCorrelation, processClosureTest, "Process Closure Test", false); + PROCESS_SWITCH(HStrangeCorrelation, processFeedDown, "process Feed Down", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/Strangeness/k0_mixed_events.cxx b/PWGLF/Tasks/Strangeness/k0_mixed_events.cxx index 708a0b3981b..5de8a32c122 100644 --- a/PWGLF/Tasks/Strangeness/k0_mixed_events.cxx +++ b/PWGLF/Tasks/Strangeness/k0_mixed_events.cxx @@ -9,30 +9,45 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // +/// \file k0_mixed_events.cxx /// \brief Femto3D pair mixing task /// \author Sofia Tomassini, Gleb Romanenko, Nicolò Jacazio /// \since 31 May 2023 -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include + #include #include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" #include "Framework/ASoA.h" -#include "MathUtils/Utils.h" #include "Framework/DataTypes.h" -#include "Common/DataModel/Multiplicity.h" #include "Framework/AnalysisDataModel.h" #include "Framework/Expressions.h" - #include "Framework/StaticFor.h" -#include "PWGCF/Femto3D/DataModel/singletrackselector.h" -#include -#include "TLorentzVector.h" -#include "TDatabasePDG.h" +#include "MathUtils/Utils.h" +#include "Common/DataModel/Multiplicity.h" + +#include "PWGCF/Femto3D/DataModel/singletrackselector.h" #include "PWGCF/Femto3D/Core/femto3dPairTask.h" +#include "Common/DataModel/Centrality.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "PWGLF/Utils/inelGt.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/PIDResponse.h" +#include "CCDB/BasicCCDBManager.h" +#include "DetectorsBase/Propagator.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" using namespace o2; using namespace o2::soa; @@ -40,11 +55,23 @@ using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; -using FilteredCollisions = aod::SingleCollSels; -using FilteredTracks = aod::SingleTrackSels; +using FilteredCollisions = soa::Filtered; +using FilteredTracks = soa::Filtered>; + +using RecoTracks = soa::Join; + +typedef std::shared_ptr trkType; +typedef std::shared_ptr trkTypeData; -typedef std::shared_ptr::iterator> trkType; -typedef std::shared_ptr::iterator> colType; +typedef std::shared_ptr colType; using MyFemtoPair = o2::aod::singletrackselector::FemtoPair; @@ -54,46 +81,53 @@ class ResoPair : public MyFemtoPair ResoPair() {} ResoPair(trkType const& first, trkType const& second) : MyFemtoPair(first, second) { - SetPair(first, second); - }; - ResoPair(trkType const& first, trkType const& second, const bool& isidentical) : MyFemtoPair(first, second, isidentical){}; - bool IsClosePair() const { return MyFemtoPair::IsClosePair(_deta, _dphi, _radius); } - void SetEtaDiff(const float deta) { _deta = deta; } - void SetPhiStarDiff(const float dphi) { _dphi = dphi; } - void SetPair(trkType const& first, trkType const& second) + setPair(first, second); + } + ResoPair(trkType const& first, trkType const& second, const bool& isidentical) : MyFemtoPair(first, second, isidentical) {} + bool isClosePair() const { return MyFemtoPair::IsClosePair(mDeltaEta, mDeltaPhi, mRadius); } + void setEtaDiff(const float deta) { mDeltaEta = deta; } + void setPhiStarDiff(const float dphi) { mDeltaPhi = dphi; } + void setRadius(const float r) { mRadius = r; } + void setPair(trkType const& first, trkType const& second) { MyFemtoPair::SetPair(first, second); lDecayDaughter1.SetPtEtaPhiM(first->pt(), first->eta(), first->phi(), particle_mass(GetPDG1())); lDecayDaughter2.SetPtEtaPhiM(second->pt(), second->eta(), second->phi(), particle_mass(GetPDG2())); lResonance = lDecayDaughter1 + lDecayDaughter2; } - float GetInvMass() const + void setPair(trkTypeData const& first, trkTypeData const& second) + { + // MyFemtoPair::SetPair(first, second); + lDecayDaughter1.SetPtEtaPhiM(first->pt(), first->eta(), first->phi(), particle_mass(GetPDG1())); + lDecayDaughter2.SetPtEtaPhiM(second->pt(), second->eta(), second->phi(), particle_mass(GetPDG2())); + lResonance = lDecayDaughter1 + lDecayDaughter2; + } + float getInvMass() const { // LOG(info) << "Mass = " << lResonance.M() << " 1 " << lDecayDaughter1.M() << " 2 " << lDecayDaughter2.M(); return lResonance.M(); } - float GetPt() const { return lResonance.Pt(); } - float GetRapidity() const { return lResonance.Rapidity(); } + float getPt() const { return lResonance.Pt(); } + float getRapidity() const { return lResonance.Rapidity(); } private: TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; - float _deta = 0.01; - float _dphi = 0.01; - float _radius = 1.2; + float mDeltaEta = 0.01; + float mDeltaPhi = 0.01; + float mRadius = 1.2; }; struct K0MixedEvents { - // using allinfo = soa::Join; // aod::pidTPCPr - /// Construct a registry object with direct declaration HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; - Configurable _min_P{"min_P", 0.0, "lower mometum limit"}; - Configurable _max_P{"max_P", 100.0, "upper mometum limit"}; + Configurable> multPercentileCut{"multPercentileCut", std::pair{-100.f, 1000.f}, "[min., max.] centrality range to keep events within"}; + Configurable> momentumCut{"momentumCut", std::pair{0.f, 100.f}, "[min., max.] momentum range to keep candidates within"}; + Configurable dcaxyCut{"dcaxyCut", -100.f, "dcaXY range to keep candidates within"}; + Configurable dcazCut{"dcazCut", -100.f, "dcaZ range to keep candidates within"}; + Configurable dcaxyExclusionCut{"dcaxyExclusionCut", 100.f, "dcaXY range to discard candidates within"}; + Configurable dcazExclusionCut{"dcazExclusionCut", 100.f, "dcaZ range to discard candidates within"}; + Configurable _eta{"eta", 100.0, "abs eta value limit"}; - Configurable _dcaXY{"dcaXY", 1000.0, "abs dcaXY value limit"}; - Configurable _dcaXYmin{"dcaXYmin", -0.1, "abs dcaXY min. value limit"}; - Configurable _dcaZ{"dcaZ", 1000.0, "abs dcaZ value limit"}; - Configurable _dcaZmin{"dcaZmin", -0.1, "abs dcaZ min. value limit"}; Configurable _tpcNClsFound{"minTpcNClsFound", 0, "minimum allowed number of TPC clasters"}; Configurable _tpcChi2NCl{"tpcChi2NCl", 100.0, "upper limit for chi2 value of a fit over TPC clasters"}; Configurable _tpcCrossedRowsOverFindableCls{"tpcCrossedRowsOverFindableCls", 0, "lower limit of TPC CrossedRows/FindableCls value"}; @@ -118,18 +152,34 @@ struct K0MixedEvents { Configurable _particlePDGtoReject{"particlePDGtoRejectFromSecond", 0, "applied only if the particles are non-identical and only to the second particle in the pair!!!"}; Configurable> _rejectWithinNsigmaTOF{"rejectWithinNsigmaTOF", std::vector{-0.0f, 0.0f}, "TOF rejection Nsigma range for the particle specified with PDG to be rejected"}; - Configurable _deta{"deta", 0.01, "minimum allowed defference in eta between two tracks in a pair"}; - Configurable _dphi{"dphi", 0.01, "minimum allowed defference in phi_star between two tracks in a pair"}; + Configurable _deta{"deta", 1, "minimum allowed defference in eta between two tracks in a pair"}; + Configurable _dphi{"dphi", 1, "minimum allowed defference in phi_star between two tracks in a pair"}; Configurable _radiusTPC{"radiusTPC", 1.2, "TPC radius to calculate phi_star for"}; Configurable doMixedEvent{"doMixedEvent", false, "Do the mixed event"}; Configurable _multbinwidth{"multbinwidth", 50, "width of multiplicity bins within which the mixing is done"}; Configurable _vertexbinwidth{"vertexbinwidth", 2, "width of vertexZ bins within which the mixing is done"}; + // Mag field + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + + // Event selections + Configurable sel8{"evSelsel8", 0, "Apply sel8 event selection"}; + Configurable isTriggerTVX{"evSelisTriggerTVX", 1, "Is Trigger TVX"}; + Configurable isNoTimeFrameBorder{"evSelisNoTimeFrameBorder", 1, "Is No Time Frame Border"}; + Configurable isNoITSROFrameBorder{"evSelisNoITSROFrameBorder", 1, "Is No ITS Readout Frame Border"}; + Configurable isVertexTOFmatched{"evSelisVertexTOFmatched", 0, "Is Vertex TOF matched"}; + Configurable isGoodZvtxFT0vsPV{"evSelisGoodZvtxFT0vsPV", 0, "isGoodZvtxFT0vsPV"}; + Configurable isNoSameBunchPileup{"isNoSameBunchPileup", 0, "isNoSameBunchPileup"}; + Configurable isInelGt0{"evSelisInelGt0", 0, "isInelGt0"}; + // Binnings - ConfigurableAxis CFkStarBinning{"CFkStarBinning", {500, 0.4, 0.6}, "k* binning of the CF (Nbins, lowlimit, uplimit)"}; + ConfigurableAxis invMassBinning{"invMassBinning", {500, 0.4, 0.6}, "k* binning of the CF (Nbins, lowlimit, uplimit)"}; ConfigurableAxis ptBinning{"ptBinning", {1000, 0.f, 10.f}, "pT binning (Nbins, lowlimit, uplimit)"}; ConfigurableAxis dcaXyBinning{"dcaXyBinning", {100, -1.f, 1.f}, "dcaXY binning (Nbins, lowlimit, uplimit)"}; + ConfigurableAxis multPercentileBinning{"multPercentileBinning", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 15.0, 20.0, 30.0, 40.0, 50.0, 70.0, 100.0}, "Binning in multiplicity percentile"}; bool IsIdentical; @@ -139,18 +189,16 @@ struct K0MixedEvents { std::pair> TPCcuts_2; std::pair> TOFcuts_2; - std::map> selectedtracks_1; - std::map> selectedtracks_2; - std::map, std::vector> mixbins; - std::unique_ptr Pair = std::make_unique(); - Filter pFilter = o2::aod::singletrackselector::p > _min_P&& o2::aod::singletrackselector::p < _max_P; + Filter pFilter = o2::aod::singletrackselector::p > momentumCut.value.first&& o2::aod::singletrackselector::p < momentumCut.value.second; Filter etaFilter = nabs(o2::aod::singletrackselector::eta) < _eta; Filter tpcTrkFilter = o2::aod::singletrackselector::tpcNClsFound >= _tpcNClsFound && o2::aod::singletrackselector::tpcNClsShared <= (uint8_t)_tpcNClsShared; - Filter itsNClsFilter = o2::aod::singletrackselector::itsNCls >= (uint8_t)_itsNCls; + + // Filter itsNClsFilter = o2::aod::singletrackselector::itsNCls >= (uint8_t)_itsNCls; Filter vertexFilter = nabs(o2::aod::singletrackselector::posZ) < _vertexZ; + Filter multPercentileFilter = o2::aod::singletrackselector::multPerc > multPercentileCut.value.first&& o2::aod::singletrackselector::multPerc < multPercentileCut.value.second; const char* pdgToSymbol(const int pdg) { @@ -169,141 +217,343 @@ struct K0MixedEvents { void init(o2::framework::InitContext&) { + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + IsIdentical = (_sign_1 * _particlePDG_1 == _sign_2 * _particlePDG_2); LOG(info) << "IsIdentical=" << IsIdentical << "; sign1=" << _sign_1 << "; Pdg1=" << _particlePDG_1 << "; total1=" << _sign_1 * _particlePDG_1 << " -- Pdg2=" << _particlePDG_2 << "; sign2=" << _sign_2 << "; total2=" << _sign_2 * _particlePDG_2; Pair->SetIdentical(IsIdentical); Pair->SetPDG1(_particlePDG_1); Pair->SetPDG2(_particlePDG_2); - Pair->SetEtaDiff(1); + Pair->setEtaDiff(_deta); + Pair->setPhiStarDiff(_dphi); + Pair->setRadius(_radiusTPC); TPCcuts_1 = std::make_pair(_particlePDG_1, _tpcNSigma_1); TOFcuts_1 = std::make_pair(_particlePDG_1, _tofNSigma_1); TPCcuts_2 = std::make_pair(_particlePDG_2, _tpcNSigma_2); TOFcuts_2 = std::make_pair(_particlePDG_2, _tofNSigma_2); - const AxisSpec invMassAxis{CFkStarBinning, "Inv. mass (GeV/c^{2})"}; + const AxisSpec invMassAxis{invMassBinning, "Inv. mass (GeV/c^{2})"}; const AxisSpec ptAxis{ptBinning, "#it{p}_{T} (GeV/c)"}; const AxisSpec dcaXyAxis{dcaXyBinning, "DCA_{xy} (cm)"}; + const AxisSpec dcaZAxis{dcaXyBinning, "DCA_{z} (cm)"}; + const AxisSpec multPercentileAxis{multPercentileBinning, "Mult. Perc."}; + + registry.add("hNEvents", "hNEvents", {HistType::kTH1D, {{14, 0.f, 14.f}}}); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(1, "all"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(2, "sel8"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(3, "TVX"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(4, "zvertex"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(5, "TFBorder"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(6, "ITSROFBorder"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(7, "isTOFVertexMatched"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(8, "isGoodZvtxFT0vsPV"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(9, "isNoSameBunchPileup"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(10, "InelGT0"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(11, Form("collision.centFT0M() < %f", multPercentileCut.value.second)); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(12, Form("collision.centFT0M() > %f", multPercentileCut.value.first)); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(13, "Applied selection"); registry.add("Trks", "Trks", kTH1D, {{2, 0.5, 2.5, "Tracks"}}); - registry.add("VTXc", "VTXc", kTH1F, {{100, -20., 20., "vtx"}}); - registry.add("VTX", "VTX", kTH1F, {{100, -20., 20., "vtx"}}); - registry.add("SEcand", "SEcand", kTH1F, {{2, 0.5, 2.5}}); - registry.add("SE", "SE", kTH1F, {invMassAxis}); - registry.add("ME", "ME", kTH1F, {invMassAxis}); - registry.add("SEvsPt", "SEvsPt", kTH2D, {invMassAxis, ptAxis}); - registry.add("MEvsPt", "MEvsPt", kTH2D, {invMassAxis, ptAxis}); - registry.add("eta", Form("eta_%i", (int)_particlePDG_1), kTH2F, {ptAxis, {100, -10., 10., "#eta"}}); - registry.add("p_first", Form("p_%i", (int)_particlePDG_1), kTH1F, {ptAxis}); - registry.add("dcaXY_first", Form("dca_%i", (int)_particlePDG_1), kTH2F, {ptAxis, dcaXyAxis}); - registry.add("nsigmaTOF_first", Form("nsigmaTOF_%i", (int)_particlePDG_1), kTH2F, {ptAxis, {100, -10., 10., Form("N#sigma_{TOF}(%s))", pdgToSymbol(_particlePDG_1))}}); - registry.add("nsigmaTPC_first", Form("nsigmaTPC_%i", (int)_particlePDG_1), kTH2F, {ptAxis, {100, -10., 10., Form("N#sigma_{TPC}(%s))", pdgToSymbol(_particlePDG_1))}}); - registry.add("rapidity_first", Form("rapidity_%i", (int)_particlePDG_1), kTH2F, {ptAxis, {100, -10., 10., Form("y(%s)", pdgToSymbol(_particlePDG_1))}}); + registry.add("VTXc", "VTXc", kTH1D, {{100, -20., 20., "vtx"}}); + registry.add("VTX", "VTX", kTH1D, {{100, -20., 20., "vtx"}}); + registry.add("multPerc", "multPerc", kTH1D, {multPercentileAxis}); + + registry.add("SEcand", "SEcand", kTH1D, {{2, 0.5, 2.5}}); + registry.add("SE", "SE", kTH1D, {invMassAxis}); + registry.add("ME", "ME", kTH1D, {invMassAxis}); + registry.add("SEvsPt", "SEvsPt", kTH3F, {invMassAxis, ptAxis, multPercentileAxis}); + if (doMixedEvent) { + registry.add("MEvsPt", "MEvsPt", kTH3F, {invMassAxis, ptAxis, multPercentileAxis}); + } + registry.add("eta_first", Form("eta_%i", _particlePDG_1.value), kTH2F, {ptAxis, {100, -10., 10., "#eta"}}); + registry.add("p_first", Form("p_%i", _particlePDG_1.value), kTH1D, {ptAxis}); + registry.add("dcaXY_first", Form("dcaXY_%i", _particlePDG_1.value), kTH2F, {ptAxis, dcaXyAxis}); + registry.add("dcaZ_first", Form("dcaZ_%i", _particlePDG_1.value), kTH2F, {ptAxis, dcaZAxis}); + registry.add("nsigmaTOF_first", Form("nsigmaTOF_%i", _particlePDG_1.value), kTH2F, {ptAxis, {100, -10., 10., Form("N#sigma_{TOF}(%s))", pdgToSymbol(_particlePDG_1))}}); + registry.add("nsigmaTPC_first", Form("nsigmaTPC_%i", _particlePDG_1.value), kTH2F, {ptAxis, {100, -10., 10., Form("N#sigma_{TPC}(%s))", pdgToSymbol(_particlePDG_1))}}); + registry.add("rapidity_first", Form("rapidity_%i", _particlePDG_1.value), kTH2F, {ptAxis, {100, -10., 10., Form("y(%s)", pdgToSymbol(_particlePDG_1))}}); if (!IsIdentical) { - registry.add("p_second", Form("p_%i", (int)_particlePDG_2), kTH1F, {ptAxis}); - registry.add("dcaXY_second", Form("dca_%i", (int)_particlePDG_2), kTH2F, {ptAxis, dcaXyAxis}); - registry.add("nsigmaTOF_second", Form("nsigmaTOF_%i", (int)_particlePDG_2), kTH2F, {ptAxis, {100, -10., 10., Form("N#sigma_{TOF}(%s))", pdgToSymbol(_particlePDG_2))}}); - registry.add("nsigmaTPC_second", Form("nsigmaTPC_%i", (int)_particlePDG_2), kTH2F, {ptAxis, {100, -10., 10., Form("N#sigma_{TPC}(%s))", pdgToSymbol(_particlePDG_2))}}); - registry.add("rapidity_second", Form("rapidity_%i", (int)_particlePDG_2), kTH2F, {ptAxis, {100, -10., 10., Form("y(%s)", pdgToSymbol(_particlePDG_2))}}); + registry.add("p_second", Form("p_%i", _particlePDG_2.value), kTH1D, {ptAxis}); + registry.add("dcaXY_second", Form("dcaXY_%i", _particlePDG_2.value), kTH2F, {ptAxis, dcaXyAxis}); + registry.add("dcaZ_second", Form("dcaZ_%i", _particlePDG_1.value), kTH2F, {ptAxis, dcaZAxis}); + registry.add("nsigmaTOF_second", Form("nsigmaTOF_%i", _particlePDG_2.value), kTH2F, {ptAxis, {100, -10., 10., Form("N#sigma_{TOF}(%s))", pdgToSymbol(_particlePDG_2))}}); + registry.add("nsigmaTPC_second", Form("nsigmaTPC_%i", _particlePDG_2.value), kTH2F, {ptAxis, {100, -10., 10., Form("N#sigma_{TPC}(%s))", pdgToSymbol(_particlePDG_2))}}); + registry.add("rapidity_second", Form("rapidity_%i", _particlePDG_2.value), kTH2F, {ptAxis, {100, -10., 10., Form("y(%s)", pdgToSymbol(_particlePDG_2))}}); } + + if (!doprocessMC) { + return; + } + registry.add("MC/multPerc", "multPerc", kTH1D, {multPercentileAxis}); + registry.add("MC/multPercWMcCol", "multPercWMcCol", kTH1D, {multPercentileAxis}); + registry.add("MC/generatedInRecoEvs", "generatedInRecoEvs", kTH2D, {ptAxis, multPercentileAxis}); + registry.add("MC/SE", "SE", kTH1D, {invMassAxis}); + registry.add("MC/SEvsPt", "SEvsPt", kTH3F, {invMassAxis, ptAxis, multPercentileAxis}); + registry.addClone("MC/", "MCCent/"); + registry.add("MCCent/generatedInGenEvs", "generatedInGenEvs", kTH2D, {ptAxis, multPercentileAxis}); + } + + int mRunNumber = 0; + float d_bz = 0.f; + Service ccdb; + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) // inspired by PWGLF/TableProducer/lambdakzerobuilder.cxx + { + if (mRunNumber == bc.runNumber()) { + return; + } + d_bz = 0.f; + + auto run3grp_timestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + o2::parameters::GRPMagField* grpmag = 0x0; + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + // Fetch magnetic field from ccdb for current collision + d_bz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + // Fetch magnetic field from ccdb for current collision + d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + } + mRunNumber = bc.runNumber(); + d_bz = 0.1 * d_bz; } template - void mixTracks(Type const& tracks) + void mixTracks(Type const& tracks, const float centrality) { // template for identical particles from the same collision - for (long unsigned int ii = 0; ii < tracks.size(); ii++) { // nested loop for all the combinations - for (long unsigned int iii = ii + 1; iii < tracks.size(); iii++) { + LOG(debug) << "Mixing tracks of the same event"; + for (uint32_t trk1 = 0; trk1 < tracks.size(); trk1++) { // nested loop for all the combinations + for (uint32_t trk2 = trk1 + 1; trk2 < tracks.size(); trk2++) { - Pair->SetPair(tracks[ii], tracks[iii]); + Pair->setPair(tracks[trk1], tracks[trk2]); registry.fill(HIST("SEcand"), 1.f); - if (!Pair->IsClosePair()) { - continue; - } - if (std::abs(Pair->GetRapidity()) > 0.5f) { + // if (!Pair->isClosePair()) { + // continue; + // } + if (std::abs(Pair->getRapidity()) > 0.5f) { continue; } registry.fill(HIST("SEcand"), 2.f); - registry.fill(HIST("SE"), Pair->GetInvMass()); // close pair rejection and fillig the SE histo - registry.fill(HIST("SEvsPt"), Pair->GetInvMass(), Pair->GetPt()); // close pair rejection and fillig the SE histo + registry.fill(HIST("SE"), Pair->getInvMass()); // close pair rejection and fillig the SE histo + registry.fill(HIST("SEvsPt"), Pair->getInvMass(), Pair->getPt(), centrality); // close pair rejection and fillig the SE histo } } } template - void mixTracks(Type const& tracks1, Type const& tracks2) + void mixTracks(Type const& tracks1, Type const& tracks2, const float centrality) { - for (auto ii : tracks1) { - for (auto iii : tracks2) { + LOG(debug) << "Mixing tracks of two different events"; + for (auto trk1 : tracks1) { + for (auto trk2 : tracks2) { - Pair->SetPair(ii, iii); + Pair->setPair(trk1, trk2); if constexpr (isSameEvent) { registry.fill(HIST("SEcand"), 1.f); } - if (!Pair->IsClosePair()) { - continue; - } - if (std::abs(Pair->GetRapidity()) > 0.5f) { + // if (!Pair->isClosePair()) { + // continue; + // } + if (std::abs(Pair->getRapidity()) > 0.5f) { continue; } if constexpr (isSameEvent) { registry.fill(HIST("SEcand"), 2.f); - registry.fill(HIST("SE"), Pair->GetInvMass()); - registry.fill(HIST("SEvsPt"), Pair->GetInvMass(), Pair->GetPt()); + registry.fill(HIST("SE"), Pair->getInvMass()); + registry.fill(HIST("SEvsPt"), Pair->getInvMass(), Pair->getPt(), centrality); } else { - registry.fill(HIST("ME"), Pair->GetInvMass()); - registry.fill(HIST("MEvsPt"), Pair->GetInvMass(), Pair->GetPt()); + registry.fill(HIST("ME"), Pair->getInvMass()); + registry.fill(HIST("MEvsPt"), Pair->getInvMass(), Pair->getPt(), centrality); } } } } - void process(soa::Filtered const& collisions, soa::Filtered const& tracks) + template + bool isTrackSelected(TrkType const& track) { - if (_particlePDG_1 == 0 || _particlePDG_2 == 0) + if (track.itsChi2NCl() > 36.f) + return false; + if (track.itsChi2NCl() < 0.f) + return false; + if (track.tpcChi2NCl() < 0.f) + return false; + if (track.tpcChi2NCl() > 4.f) + return false; + if (track.itsNCls() < _itsNCls) { + return false; + } + if (track.itsChi2NCl() > _itsChi2NCl) { + return false; + } + if (track.tpcChi2NCl() > _tpcChi2NCl) { + return false; + } + if (track.tpcCrossedRowsOverFindableCls() < _tpcCrossedRowsOverFindableCls) { + return false; + } + if (std::abs(track.dcaXY()) > dcaxyCut) { + return false; + } + if (std::abs(track.dcaXY()) < dcaxyExclusionCut) { + return false; + } + if (std::abs(track.dcaZ()) > dcazCut) { + return false; + } + if (std::abs(track.dcaZ()) < dcazExclusionCut) { + return false; + } + if (track.p() < momentumCut.value.first) { + return false; + } + if (track.p() > momentumCut.value.second) { + return false; + } + if (std::abs(track.eta()) >= _eta) { + return false; + } + if (track.tpcNClsFound() < _tpcNClsFound) { + return false; + } + if (track.tpcNClsShared() > _tpcNClsShared) { + return false; + } + + return true; + } + + // Event selection + template + bool acceptEvent(TCollision const& collision, bool fill = true) + { + if (fill) { + registry.fill(HIST("hNEvents"), 0.5); + } + if (sel8 && !collision.sel8()) { + return false; + } + if (fill) { + registry.fill(HIST("hNEvents"), 1.5); + } + if (isTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + if (fill) { + registry.fill(HIST("hNEvents"), 2.5); + } + if (TMath::Abs(collision.posZ()) > _vertexZ) { + return false; + } + if (fill) { + registry.fill(HIST("hNEvents"), 3.5); + } + if (isNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (fill) { + registry.fill(HIST("hNEvents"), 4.5); + } + if (isNoITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if (fill) { + registry.fill(HIST("hNEvents"), 5.5); + } + if (isVertexTOFmatched && !collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (fill) { + registry.fill(HIST("hNEvents"), 6.5); + } + if (isGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (fill) { + registry.fill(HIST("hNEvents"), 7.5); + } + if (isNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (fill) { + registry.fill(HIST("hNEvents"), 8.5); + } + if (isInelGt0 && !collision.isInelGt0()) { + return false; + } + if (fill) { + registry.fill(HIST("hNEvents"), 9.5); + } + if (collision.centFT0M() > multPercentileCut.value.second) + return false; + if (fill) { + registry.fill(HIST("hNEvents"), 10.5); + } + if (collision.centFT0M() < multPercentileCut.value.first) + return false; + if (fill) { + registry.fill(HIST("hNEvents"), 11.5); + } + if (fill) { + registry.fill(HIST("hNEvents"), 12.5); + } + return true; + } + + void processDerived(FilteredTracks const& tracks, FilteredCollisions const& collisions) + { + LOG(debug) << "Processing " << collisions.size() << " collisions and " << tracks.size() << " tracks"; + std::map> selectedtracks_1; + std::map> selectedtracks_2; + std::map, std::vector> mixbins; + if (_particlePDG_1 == 0 || _particlePDG_2 == 0) { LOGF(fatal, "One of passed PDG is 0!!!"); + } registry.fill(HIST("Trks"), 2.f, tracks.size()); - for (auto c : collisions) { - registry.fill(HIST("VTXc"), c.posZ()); + for (const auto& collision : collisions) { + LOG(debug) << "Collision index " << collision.globalIndex(); + registry.fill(HIST("VTXc"), collision.posZ()); + registry.fill(HIST("multPerc"), collision.multPerc()); } for (auto track : tracks) { - if (track.itsChi2NCl() > _itsChi2NCl) { - continue; - } - if (track.tpcChi2NCl() > _tpcChi2NCl) { - continue; - } - if (track.tpcCrossedRowsOverFindableCls() < _tpcCrossedRowsOverFindableCls) { - continue; - } - if (track.dcaXY() < _dcaXYmin || track.dcaXY() > _dcaXY) { - continue; - } - if (track.dcaZ() < _dcaZmin || track.dcaZ() > _dcaZ) { + LOG(debug) << "Track index " << track.singleCollSelId(); + if (!isTrackSelected(track)) { continue; } - registry.fill(HIST("Trks"), 1); - registry.fill(HIST("VTX"), track.singleCollSel().posZ()); - if (abs(track.singleCollSel().posZ()) > _vertexZ) + const auto& col = track.singleCollSel_as(); + if (std::abs(col.posZ()) > _vertexZ) continue; - registry.fill(HIST("eta"), track.pt(), track.eta()); - if (abs(track.rapidity(particle_mass(_particlePDG_1))) > _maxy) { + if (col.multPerc() > multPercentileCut.value.second || col.multPerc() < multPercentileCut.value.first) continue; - } + registry.fill(HIST("VTX"), col.posZ()); + registry.fill(HIST("eta_first"), track.pt(), track.eta()); registry.fill(HIST("rapidity_first"), track.pt(), track.rapidity(particle_mass(_particlePDG_1))); if ((track.sign() == _sign_1) && - (track.p() < _PIDtrshld_1 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_1) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_1))) { // filling the map: eventID <-> selected particles1 + (track.p() < _PIDtrshld_1 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_1) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_1))) { // filling the map: eventID <-> selected particles1 selectedtracks_1[track.singleCollSelId()].push_back(std::make_shared(track)); registry.fill(HIST("p_first"), track.p()); registry.fill(HIST("dcaXY_first"), track.pt(), track.dcaXY()); + registry.fill(HIST("dcaZ_first"), track.pt(), track.dcaZ()); switch (_particlePDG_1) { case 211: registry.fill(HIST("nsigmaTOF_first"), track.p(), track.tofNSigmaPi()); @@ -326,15 +576,16 @@ struct K0MixedEvents { } } - if (IsIdentical) + if (IsIdentical) { continue; - else if ((track.sign() == _sign_2) && - (_particlePDGtoReject != 0 || !TOFselection(track, std::make_pair(_particlePDGtoReject, _rejectWithinNsigmaTOF))) && - (track.p() < _PIDtrshld_2 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_2) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_2))) { // filling the map: eventID <-> selected particles2 if (see condition above ^) + } else if ((track.sign() == _sign_2) && + (_particlePDGtoReject != 0 || !o2::aod::singletrackselector::TOFselection(track, std::make_pair(_particlePDGtoReject, _rejectWithinNsigmaTOF))) && + (track.p() < _PIDtrshld_2 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_2) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_2))) { // filling the map: eventID <-> selected particles2 if (see condition above ^) selectedtracks_2[track.singleCollSelId()].push_back(std::make_shared(track)); registry.fill(HIST("p_second"), track.p()); registry.fill(HIST("dcaXY_second"), track.pt(), track.dcaXY()); + registry.fill(HIST("dcaZ_second"), track.pt(), track.dcaZ()); switch (_particlePDG_2) { case 211: registry.fill(HIST("nsigmaTOF_second"), track.p(), track.tofNSigmaPi()); @@ -375,52 +626,52 @@ struct K0MixedEvents { for (auto i = mixbins.begin(); i != mixbins.end(); i++) { // iterating over all vertex&mult bins - for (long unsigned int indx1 = 0; indx1 < (i->second).size(); indx1++) { // loop over all the events in each vertex&mult bin + for (uint32_t indx1 = 0; indx1 < (i->second).size(); indx1++) { // loop over all the events in each vertex&mult bin auto col1 = (i->second)[indx1]; Pair->SetMagField1(col1->magField()); Pair->SetMagField2(col1->magField()); - mixTracks(selectedtracks_1[col1->index()]); // mixing SE identical + mixTracks(selectedtracks_1[col1->index()], col1->multPerc()); // mixing SE identical if (!doMixedEvent) { continue; } - for (long unsigned int indx2 = indx1 + 1; indx2 < (i->second).size(); indx2++) { // nested loop for all the combinations of collisions in a chosen mult/vertex bin + for (uint32_t indx2 = indx1 + 1; indx2 < (i->second).size(); indx2++) { // nested loop for all the combinations of collisions in a chosen mult/vertex bin auto col2 = (i->second)[indx2]; Pair->SetMagField2(col2->magField()); - mixTracks(selectedtracks_1[col1->index()], selectedtracks_1[col2->index()]); // mixing ME identical + mixTracks(selectedtracks_1[col1->index()], selectedtracks_1[col2->index()], col1->multPerc()); // mixing ME identical } } } - } //====================================== end of mixing identical ====================================== - - else { //====================================== mixing non-identical ====================================== + //====================================== end of mixing identical ====================================== + } else { + //====================================== mixing non-identical ====================================== for (auto i = mixbins.begin(); i != mixbins.end(); i++) { // iterating over all vertex&mult bins - for (long unsigned int indx1 = 0; indx1 < (i->second).size(); indx1++) { // loop over all the events in each vertex&mult bin + for (uint32_t indx1 = 0; indx1 < (i->second).size(); indx1++) { // loop over all the events in each vertex&mult bin auto col1 = (i->second)[indx1]; Pair->SetMagField1(col1->magField()); Pair->SetMagField2(col1->magField()); - mixTracks(selectedtracks_1[col1->index()], selectedtracks_2[col1->index()]); // mixing SE non-identical + mixTracks(selectedtracks_1[col1->index()], selectedtracks_2[col1->index()], col1->multPerc()); // mixing SE non-identical if (!doMixedEvent) { continue; } - for (long unsigned int indx2 = indx1 + 1; indx2 < (i->second).size(); indx2++) { // nested loop for all the combinations of collisions in a chosen mult/vertex bin + for (uint32_t indx2 = indx1 + 1; indx2 < (i->second).size(); indx2++) { // nested loop for all the combinations of collisions in a chosen mult/vertex bin auto col2 = (i->second)[indx2]; Pair->SetMagField2(col2->magField()); - mixTracks(selectedtracks_1[col1->index()], selectedtracks_2[col2->index()]); // mixing ME non-identical + mixTracks(selectedtracks_1[col1->index()], selectedtracks_2[col2->index()], col1->multPerc()); // mixing ME non-identical } } } @@ -442,9 +693,341 @@ struct K0MixedEvents { (i->second).clear(); mixbins.clear(); } + PROCESS_SWITCH(K0MixedEvents, processDerived, "process derived", true); + + using RecoCollisions = soa::Join; + + void processData(RecoTracks const& tracks, RecoCollisions const& collisions, BCsWithTimestamps const& bcs) + { + initCCDB(bcs.iteratorAt(0)); + LOG(debug) << "Processing " << collisions.size() << " collisions and " << tracks.size() << " tracks"; + std::map> selectedtracks_1; + std::map> selectedtracks_2; + std::map, std::vector>> mixbins; + if (_particlePDG_1 == 0 || _particlePDG_2 == 0) { + LOGF(fatal, "One of passed PDG is 0!!!"); + } + + registry.fill(HIST("Trks"), 2.f, tracks.size()); + for (auto collision : collisions) { + if (!acceptEvent(collision)) + continue; + LOG(debug) << "Collision index " << collision.globalIndex(); + registry.fill(HIST("VTXc"), collision.posZ()); + registry.fill(HIST("multPerc"), collision.centFT0M()); + } + + for (auto track : tracks) { + if (!isTrackSelected(track)) { + continue; + } + // if (!track.isGlobalTrackWoDCA()) { + // continue; + // } + if (track.trackType() != aod::track::Track) { + continue; + } + if (track.tofChi2() >= 10.f) { + continue; + } + if (!track.has_collision()) { + continue; + } + registry.fill(HIST("Trks"), 1); + const auto& col = track.collision_as(); + if (!acceptEvent(col, false)) + continue; + if (std::abs(col.posZ()) > _vertexZ) + continue; + if (col.centFT0M() > multPercentileCut.value.second || col.centFT0M() < multPercentileCut.value.first) + continue; + registry.fill(HIST("VTX"), col.posZ()); + registry.fill(HIST("eta_first"), track.pt(), track.eta()); + registry.fill(HIST("rapidity_first"), track.pt(), track.rapidity(particle_mass(_particlePDG_1))); + + if ((track.sign() == _sign_1) && + (track.p() < _PIDtrshld_1 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_1) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_1))) { // filling the map: eventID <-> selected particles1 + selectedtracks_1[track.collisionId()].push_back(std::make_shared(track)); + + registry.fill(HIST("p_first"), track.p()); + registry.fill(HIST("dcaXY_first"), track.pt(), track.dcaXY()); + registry.fill(HIST("dcaZ_first"), track.pt(), track.dcaZ()); + switch (_particlePDG_1) { + case 211: + registry.fill(HIST("nsigmaTOF_first"), track.p(), track.tofNSigmaPi()); + registry.fill(HIST("nsigmaTPC_first"), track.p(), track.tpcNSigmaPi()); + break; + case 321: + registry.fill(HIST("nsigmaTOF_first"), track.p(), track.tofNSigmaKa()); + registry.fill(HIST("nsigmaTPC_first"), track.p(), track.tpcNSigmaKa()); + break; + case 2212: + registry.fill(HIST("nsigmaTOF_first"), track.p(), track.tofNSigmaPr()); + registry.fill(HIST("nsigmaTPC_first"), track.p(), track.tpcNSigmaPr()); + break; + case 1000010020: + registry.fill(HIST("nsigmaTOF_first"), track.p(), track.tofNSigmaDe()); + registry.fill(HIST("nsigmaTPC_first"), track.p(), track.tpcNSigmaDe()); + break; + default: + LOG(fatal) << "PDG code 1: " << _particlePDG_1 << " is not supported!!!"; + } + } + + if (IsIdentical) { + continue; + } else if ((track.sign() == _sign_2) && + (_particlePDGtoReject != 0 || !o2::aod::singletrackselector::TOFselection(track, std::make_pair(_particlePDGtoReject, _rejectWithinNsigmaTOF))) && + (track.p() < _PIDtrshld_2 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_2) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_2))) { // filling the map: eventID <-> selected particles2 if (see condition above ^) + selectedtracks_2[track.collisionId()].push_back(std::make_shared(track)); + + registry.fill(HIST("p_second"), track.p()); + registry.fill(HIST("dcaXY_second"), track.pt(), track.dcaXY()); + registry.fill(HIST("dcaZ_second"), track.pt(), track.dcaZ()); + switch (_particlePDG_2) { + case 211: + registry.fill(HIST("nsigmaTOF_second"), track.p(), track.tofNSigmaPi()); + registry.fill(HIST("nsigmaTPC_second"), track.p(), track.tpcNSigmaPi()); + break; + case 321: + registry.fill(HIST("nsigmaTOF_second"), track.p(), track.tofNSigmaKa()); + registry.fill(HIST("nsigmaTPC_second"), track.p(), track.tpcNSigmaKa()); + break; + case 2212: + registry.fill(HIST("nsigmaTOF_second"), track.p(), track.tofNSigmaPr()); + registry.fill(HIST("nsigmaTPC_second"), track.p(), track.tpcNSigmaPr()); + break; + case 1000010020: + registry.fill(HIST("nsigmaTOF_second"), track.p(), track.tofNSigmaDe()); + registry.fill(HIST("nsigmaTPC_second"), track.p(), track.tpcNSigmaDe()); + break; + default: + LOG(fatal) << "PDG code 2: " << _particlePDG_2 << " is not supported!!!"; + } + } + } + + for (auto collision : collisions) { + if (selectedtracks_1.find(collision.globalIndex()) == selectedtracks_1.end()) { + if (IsIdentical) + continue; + else if (selectedtracks_2.find(collision.globalIndex()) == selectedtracks_2.end()) + continue; + } + + mixbins[std::pair{round(collision.posZ() / _vertexbinwidth), floor(collision.multNTracksPVeta1() / _multbinwidth)}].push_back(std::make_shared(collision)); + } + + //====================================== mixing starts here ====================================== + + if (IsIdentical) { //====================================== mixing identical ====================================== + + for (auto i = mixbins.begin(); i != mixbins.end(); i++) { // iterating over all vertex&mult bins + + for (uint32_t indx1 = 0; indx1 < (i->second).size(); indx1++) { // loop over all the events in each vertex&mult bin + + auto col1 = (i->second)[indx1]; + + Pair->SetMagField1(d_bz); + Pair->SetMagField2(d_bz); + + mixTracks(selectedtracks_1[col1->index()], col1->centFT0M()); // mixing SE identical + if (!doMixedEvent) { + continue; + } + + for (uint32_t indx2 = indx1 + 1; indx2 < (i->second).size(); indx2++) { // nested loop for all the combinations of collisions in a chosen mult/vertex bin + + auto col2 = (i->second)[indx2]; + + Pair->SetMagField2(d_bz); + mixTracks(selectedtracks_1[col1->index()], selectedtracks_1[col2->index()], col1->centFT0M()); // mixing ME identical + } + } + } + + //====================================== end of mixing identical ====================================== + } else { + //====================================== mixing non-identical ====================================== + + for (auto i = mixbins.begin(); i != mixbins.end(); i++) { // iterating over all vertex&mult bins + + for (uint32_t indx1 = 0; indx1 < (i->second).size(); indx1++) { // loop over all the events in each vertex&mult bin + + auto col1 = (i->second)[indx1]; + + Pair->SetMagField1(d_bz); + Pair->SetMagField2(d_bz); + + mixTracks(selectedtracks_1[col1->index()], selectedtracks_2[col1->index()], col1->centFT0M()); // mixing SE non-identical + if (!doMixedEvent) { + continue; + } + + for (uint32_t indx2 = indx1 + 1; indx2 < (i->second).size(); indx2++) { // nested loop for all the combinations of collisions in a chosen mult/vertex bin + + auto col2 = (i->second)[indx2]; + + Pair->SetMagField2(d_bz); + mixTracks(selectedtracks_1[col1->index()], selectedtracks_2[col2->index()], col1->centFT0M()); // mixing ME non-identical + } + } + } + + } //====================================== end of mixing non-identical ====================================== + + // clearing up + for (auto i = selectedtracks_1.begin(); i != selectedtracks_1.end(); i++) + (i->second).clear(); + selectedtracks_1.clear(); + + if (!IsIdentical) { + for (auto i = selectedtracks_2.begin(); i != selectedtracks_2.end(); i++) + (i->second).clear(); + selectedtracks_2.clear(); + } + + for (auto i = mixbins.begin(); i != mixbins.end(); i++) + (i->second).clear(); + mixbins.clear(); + } + PROCESS_SWITCH(K0MixedEvents, processData, "process data", false); + + using RecoMCCollisions = soa::Join; + using RecoMCTracks = soa::Join; + using GenMCCollisions = soa::Join; + + Service pdgDB; + Preslice perMCCol = aod::mcparticle::mcCollisionId; + Preslice perCollision = aod::track::collisionId; + SliceCache cache; + void processMC(RecoMCCollisions const& collisions, + RecoMCTracks const& tracks, + GenMCCollisions const& mcCollisions, + aod::McParticles const& mcParticles) + { + // Loop on reconstructed tracks + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; + std::vector> trkPool1; + std::vector> trkPool2; + // Loop on reconstructed collisions + for (const auto& col : collisions) { + if (!col.sel8()) { + continue; + } + if (std::abs(col.posZ()) > _vertexZ) { + continue; + } + // Loop on tracks + const auto& tracksInCollision = tracks.sliceByCached(aod::track::collisionId, col.globalIndex(), cache); + for (const auto& trk : tracksInCollision) { + if (!trk.has_mcParticle()) { + continue; + } + if (!isTrackSelected(trk)) { + continue; + } + // if (!trk.isGlobalTrackWoDCA()) { + // continue; + // } + if (trk.trackType() != aod::track::Track) { + continue; + } + if (trk.tofChi2() >= 10.f) { + continue; + } + const auto& part = trk.mcParticle(); + switch (part.pdgCode()) { + case 211: + trkPool1.push_back(std::make_shared(trk)); + break; + case -211: + trkPool2.push_back(std::make_shared(trk)); + break; + default: + continue; + } + } + + for (uint32_t trk1 = 0; trk1 < trkPool1.size(); trk1++) { // nested loop for all the combinations + lDecayDaughter1.SetPtEtaPhiM(trkPool1[trk1]->pt(), trkPool1[trk1]->eta(), trkPool1[trk1]->phi(), particle_mass(_particlePDG_1)); + for (uint32_t trk2 = 0; trk2 < trkPool2.size(); trk2++) { + lDecayDaughter2.SetPtEtaPhiM(trkPool2[trk2]->pt(), trkPool2[trk2]->eta(), trkPool2[trk2]->phi(), particle_mass(_particlePDG_2)); + // if (!Pair->isClosePair()) { + // continue; + // } + lResonance = lDecayDaughter1 + lDecayDaughter2; + if (std::abs(lResonance.Rapidity()) > 0.5f) { + continue; + } + registry.fill(HIST("MC/SE"), lResonance.M()); // close pair rejection and fillig the SE histo + registry.fill(HIST("MC/SEvsPt"), lResonance.M(), lResonance.Pt(), col.centFT0M()); // close pair rejection and fillig the SE histo + if (col.has_mcCollision()) { + registry.fill(HIST("MCCent/SE"), lResonance.M()); // close pair rejection and fillig the SE histo + registry.fill(HIST("MCCent/SEvsPt"), lResonance.M(), lResonance.Pt(), col.mcCollision_as().centFT0M()); // close pair rejection and fillig the SE histo + } + } + } + trkPool1.clear(); + trkPool2.clear(); + + registry.fill(HIST("MC/multPerc"), col.centFT0M()); + if (!col.has_mcCollision()) { + continue; + } + const auto& mcCollision = col.mcCollision_as(); + registry.fill(HIST("MC/multPercWMcCol"), col.centFT0M()); + registry.fill(HIST("MCCent/multPercWMcCol"), mcCollision.centFT0M()); + + // Loop on particles + const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); + for (const auto& mcParticle : particlesInCollision) { + switch (mcParticle.pdgCode()) { + case 310: + break; + default: + continue; + } + if (mcParticle.pdgCode() != 310) { + LOG(fatal) << "Fatal in PDG"; + } + if (std::abs(mcParticle.y()) > 0.5) { + continue; + } + registry.fill(HIST("MC/generatedInRecoEvs"), mcParticle.pt(), col.centFT0M()); + registry.fill(HIST("MCCent/generatedInRecoEvs"), mcParticle.pt(), mcCollision.centFT0M()); + } + } + + // Loop on generated collisions + for (const auto& mcCollision : mcCollisions) { + if (std::abs(mcCollision.posZ()) > _vertexZ) { + continue; + } + const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); + if (!o2::pwglf::isINELgt0mc(particlesInCollision, pdgDB)) { + continue; + } + registry.fill(HIST("MCCent/multPerc"), mcCollision.centFT0M()); + for (const auto& mcParticle : particlesInCollision) { + switch (mcParticle.pdgCode()) { + case 310: + break; + default: + continue; + } + if (mcParticle.pdgCode() != 310) { + LOG(fatal) << "Fatal in PDG"; + } + if (std::abs(mcParticle.y()) > 0.5) { + continue; + } + registry.fill(HIST("MCCent/generatedInGenEvs"), mcParticle.pt(), mcCollision.centFT0M()); + } + } + } + + PROCESS_SWITCH(K0MixedEvents, processMC, "process mc", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/Strangeness/kinkAnalysis.cxx b/PWGLF/Tasks/Strangeness/kinkAnalysis.cxx deleted file mode 100644 index 6c0853baaec..00000000000 --- a/PWGLF/Tasks/Strangeness/kinkAnalysis.cxx +++ /dev/null @@ -1,951 +0,0 @@ -// 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 kinkAnalysis: Analysis task for kink topology, to be converted later in a table producer for common usage by other tasks -/// \author everyone - -#include -#include - -#include "Math/Vector4D.h" -#include "Common/Core/CollisionAssociation.h" -#include "Framework/runDataProcessing.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/AnalysisTask.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/AnalysisDataModel.h" -#include "Common/Core/trackUtilities.h" -#include "Framework/DataTypes.h" -#include "DCAFitter/DCAFitterN.h" -#include "CCDB/BasicCCDBManager.h" -#include "Common/Core/RecoDecay.h" -#include "CommonConstants/LHCConstants.h" - -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/PIDResponse.h" - -#include "DataFormatsParameters/GRPMagField.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsBase/Propagator.h" -#include "Common/DataModel/EventSelection.h" -#include "PWGLF/DataModel/LFParticleIdentification.h" -#include "DetectorsVertexing/SVertexer.h" -#include "DetectorsVertexing/SVertexerParams.h" -#include "TPCReconstruction/TPCFastTransformHelperO2.h" -#include "DataFormatsTPC/VDriftCorrFact.h" -#include "DataFormatsCalibration/MeanVertexObject.h" - -#include "ReconstructionDataFormats/Track.h" - -using namespace std; - -using namespace o2; -using namespace vertexing; - -using namespace o2::dataformats; -using namespace o2::aod; - -using namespace o2::framework; -using namespace o2::framework::expressions; -using VBracket = o2::math_utils::Bracket; - -static constexpr int POS = 0, NEG = 1; - -namespace kink -{ -constexpr std::array LayerRadii{2.33959f, 3.14076f, 3.91924f, 19.6213f, 24.5597f, 34.388f, 39.3329f}; -} - -struct KinkCandidates { - int chargeMother; - int globalIndexMother; - int globalIndexDaughter; - int mcParticleIdxMother; - int mcParticleIdxDaughter; - float prx, pry, prz; - float decayvtxX, decayvtxY, decayvtxZ; - float mthinnerpx, mthinnerpy, mthinnerpz; - float mthouterpx, mthouterpy, mthouterpz; - float dghtpx, dghtpy, dghtpz; - unsigned int flags = 0u; -}; - -struct kinkAnalysis { - - HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - Service ccdb; - - enum strParticleAdDecay { SigmaMinus, - SigmaPlusToPi, - SigmaPlusToProton, - Kaon, - Pion, - Xi, - OmegaToL, - OmegaToXi, - Hypertriton }; - - Configurable cfgCutEta{"cfgCutEta", 0.8f, "Eta range for tracks"}; - Configurable cfgBz{"cfgBz", -999, "bz field, -999 is automatic"}; - Configurable cfgGRPpath{"cfgGRPpath", "GLO/GRP/GRP", "Path of the grp file"}; - Configurable cfgGRPmagPath{"cfgGRPmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable cfgCCDBurl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable cfgLUTpath{"cfgLUTpath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; - Configurable cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrLUT), "Type of material correction"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; - Configurable dcaKinkDtopv{"dcaKinkDtopv", .2, "DCA kink daughter To PV"}; - Configurable mVtxPath{"mVtxPath", "GLO/Calib/MeanVertex", "Path of the mean vertex file"}; - Configurable cfgMotherCharge{"cfgMotherCharge", -1, "mother charge"}; - Configurable cfgDaughterCharge{"cfgDaughterCharge", -1, "mother charge"}; - Configurable cfgParticleSpec{"cfgParticleSpec", SigmaPlusToProton, "particle species"}; - Configurable cfgLowerHistLimit{"cfgLowerHistLimit", 1.1, "lower limit for inv mass histo"}; - Configurable cfgUpperHistLimit{"cfgUpperHistLimit", 1.4, "upper limit for inv mass histo"}; - Configurable cfgNsigmaTPCdaughter{"cfgNsigmaTPCdaughter", 3, "nSigma TPC for the daughter track"}; - Configurable qTupper{"qTupper", 0.195, "upper qT cut"}; - Configurable qTlower{"qTLower", 0.150, "upper qT cut"}; - Configurable kinkAngle{"kinkAngle", 0.5, "mother-daughter angle cutoff"}; - Configurable zDiff{"zDiff", 20., "mother-daughter z diff"}; - Configurable phiDiff{"phiDiff", 100., "mother-daughter phi diff"}; - Configurable cfgIsMC{"cfgIsMC", true, "data or MC"}; - Configurable cfgMassCheck{"cfgMassCheck", false, "check if the reconstructed neutral mass is within 0.1 of the PDG mass"}; - - o2::base::MatLayerCylSet* lut = nullptr; - o2::dataformats::MeanVertexObject* mVtx = nullptr; - o2::vertexing::DCAFitterN<2> ft2; - - std::vector mKinkCandidates; - - int mRunNumber; - float mBz; - - float etaS = 0; - float phiS = 0; - float etaP = 0; - float phiP = 0; - - std::array sigmaPDC = {0, 0, 0}; - std::array pionPDC = {0, 0, 0}; - std::array sigmaPin = {0, 0, 0}; - - float pionPabsDC = 0; - float sigmaPabsDC = 0; - float sigmaPt = 0.; - - float costheta; - float theta; - float qT; - - float pionE = 0; - double neutronE = 0; - float sigmaE = 0; - float neutronPabs = 0; - float neutronM = 0; - float mass; - float radToDeg = 180. / M_PI; - int particlePdgCode; - - o2::track::TrackParCov SigmaTr; - o2::track::TrackParCov SigmaTr2; - o2::track::TrackParCov PionTr; - - float mMother, mChargedDaughter, mNeutralDaughter; - - using CompleteTracks = soa::Join; - using CompleteCollisions = soa::Join; - - struct TrackCand { - int Idxtr; - int mcParticleIdx = -1; - VBracket vBracket{}; - }; - - float angleCutFunction(int particleName, float x) - { - - float mSigmaMinus = 1.197449, mSigmaPlus = 1.189449, mKaon = 0.493677, mPion = 0.13957018, mXi = 1.321, mOmega = 1.67245, mHypertriton = 2.99131; - float par1 = mSigmaMinus; /// Default value is for SigmaMinus - float par2 = 0.8; - float par3 = M_PI; - switch (particleName) { - case SigmaPlusToPi: - par1 = mSigmaPlus; - par2 = 0.8; - break; - - case SigmaPlusToProton: - par1 = mSigmaPlus; - par2 = 0.2; - break; - - case Xi: - par1 = mXi; - par2 = 0.68; - break; - - case OmegaToL: - par1 = mOmega; - par2 = 0.68; - break; - - case OmegaToXi: - par1 = mOmega; - par2 = 0.68; - break; - - case Kaon: - par1 = mKaon; - par2 = 0.9127037; - break; - - case Pion: - par1 = mPion; - par2 = 0.2731374; - break; - - case Hypertriton: - par1 = mHypertriton; - par2 = 0.07; - break; - } - - if ((particleName == SigmaMinus) || (particleName == SigmaPlusToPi) || (particleName == SigmaPlusToProton) || (particleName == Xi) || (particleName == OmegaToXi) || (particleName == OmegaToL) || (particleName == Hypertriton)) - return par1 * (par2 / (sqrt((x * x) * (1 - (par2 * par2)) - ((par1 * par1) * (par2 * par2))))) * (180. / par3) + 1; - - return ((atan(par1 * par2 * (1.0 / (sqrt((x * x) * (1.0 - (par1 * par1)) - (par1 * par1) * (par2 * par2)))))) * 180.) / par3; - } - - void init(InitContext const&) - { - ccdb->setURL(cfgCCDBurl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - - int anParticleName = cfgParticleSpec; - if (cfgIsMC) { - switch (anParticleName) { - case SigmaPlusToPi: - if (cfgMotherCharge == 1) - particlePdgCode = 3222; - else - particlePdgCode = -3222; - break; - - case SigmaPlusToProton: - if (cfgMotherCharge == 1) - particlePdgCode = 3222; - else - particlePdgCode = -3222; - break; - - case Xi: - if (cfgMotherCharge == -1) - particlePdgCode = 3312; - else - particlePdgCode = -3312; - break; - - case OmegaToL: - if (cfgMotherCharge == -1) - particlePdgCode = 3334; - else - particlePdgCode = -3334; - break; - - case OmegaToXi: - if (cfgMotherCharge == -1) - particlePdgCode = 3334; - else - particlePdgCode = -3334; - break; - - case SigmaMinus: - if (cfgMotherCharge == -1) - particlePdgCode = 3112; - else - particlePdgCode = -3112; - break; - - case Hypertriton: - if (cfgMotherCharge == -1) - particlePdgCode = 1010010030; - else - particlePdgCode = -1010010030; - break; - - default: - particlePdgCode = 3112; - } - } - - mRunNumber = 0; - mBz = 0.f; - - // define axes you want to use - const AxisSpec axisEta{30, -1.5, +1.5, "#eta"}; - const AxisSpec axisqT{1000, 0.0, 1.0, "q_{T}"}; - const AxisSpec axisRmother{500, 0.0, 50.0, "#it{R}_{mother} (cm)"}; - const AxisSpec axisDCAdaugh{1000, 0.0, 10.0, "#it{DCA}_{daughter} (cm)"}; - - const AxisSpec axisSigmaMass{1000, 1.1, 1.4, "#it{M}_{inv} (Gev/#it{c^{2}})"}; - const AxisSpec hypAxisMass{100, 2.9, 3.6, "#it{M}_{inv} (Gev/#it{c^{2}})"}; - const AxisSpec axisPtHyp{100, 0., 15, "#it{p}_{T} (GeV/#it{c})"}; - - const AxisSpec axisdtime{10000, 0, 50, "#delta t"}; - const AxisSpec axisPt{500, 0., 50., "#it{p}_{T} (GeV/#it{c})"}; - const AxisSpec axisdphi{360, 0, 360, "#delta phi"}; - const AxisSpec axisdz{400, -20., 20, "#delta z"}; - const AxisSpec axisPdgCodes{8001, -4000.5, 4000.5, "mother pdg codes"}; - - // create histograms - histos.add("etaHistogram", "etaHistogram", kTH1F, {axisEta}); - histos.add("hqT", "hqT", kTH1F, {axisqT}); - histos.add("hRecVtxZData", "collision z position", HistType::kTH1F, {{200, -20., +20., "z position (cm)"}}); - histos.add("hVtxZData", "collision z position", HistType::kTH1F, {{200, -20., +20., "z position (cm)"}}); - histos.add("hCollId", "collision id", HistType::kTH1F, {{1000, 0., 100000., "collision id"}}); - histos.add("hRadiusMth", "hRadiusMth", kTH1F, {axisRmother}); - histos.add("hMassMinusPt", "hMassMinusPt", kTH2F, {axisSigmaMass, axisPt}); - histos.add("hMassPlusPt", "hMassPlusPt", kTH2F, {axisSigmaMass, axisPt}); - histos.add("hBackgroundPosNegPt", "hBackgroundPosNegPt", kTH2F, {axisSigmaMass, axisPt}); - histos.add("hBackgroundNegPosPt", "hBackgroundNegPosPt", kTH2F, {axisSigmaMass, axisPt}); - histos.add("hDCAdaughterToPV", "hDCAdaughterToPV", kTH1F, {axisDCAdaugh}); - histos.add("hDCAMotherToPV", "hDCAMotherToPV", kTH1F, {axisDCAdaugh}); - histos.add("hdeltatime", "hdeltatime", kTH1F, {axisdtime}); - histos.add("hdelt_tthresh", "hdelt_tthresh", kTH2F, {axisdtime, axisdtime}); - histos.add("hdeltaphi", "hdeltaphi", kTH1F, {axisdphi}); - histos.add("hdeltaz", "hdeltaz", kTH1F, {axisdz}); - histos.add("generatedPt", "generatedPt", kTH1F, {axisPt}); - histos.add("hPtMinusRecMcTrth", "hPtMinusRecMcTrth", kTH2F, {axisSigmaMass, axisPt}); - histos.add("hPtPlusRecMcTrth", "hPtPlusRecMcTrth", kTH2F, {axisSigmaMass, axisPt}); - histos.add("hcodes", "hcodes", kTH2F, {axisPdgCodes, axisPdgCodes}); - histos.add("hptMtrue", "hptMtrue", kTH2F, {axisPt, axisPt}); - histos.add("hptMDtrue", "hptMDtrue", kTH2F, {axisPt, axisPt}); - histos.add("hptMDelse", "hptMDelse", kTH2F, {axisPt, axisPt}); - histos.add("hPtMinusRecMcTrthM", "hPtMinusRecMcTrthM", kTH2F, {axisSigmaMass, axisPt}); - histos.add("hPtMinusRecMcTrthelse", "hPtMinusRecMcTrthelse", kTH2F, {axisSigmaMass, axisPt}); - - histos.add("hHypMass", "hHypMass", kTH1F, {hypAxisMass}); - histos.add("hHypMassMC", "hHypMassMC", kTH1F, {hypAxisMass}); - histos.add("hHypMassPt", "hHypMassPt", kTH2F, {hypAxisMass, axisPtHyp}); - - histos.add("hNSigmaTrVsPt", "hNSigmaTrVsPt", kTH2F, {axisPtHyp, {100, -5, 5, "nSigmaTPC"}}); - histos.add("hpRes", "hpRes", kTH2F, {axisPtHyp, {100, -0.5, 0.5, "p_{T} Res"}}); - histos.add("hDCAdaughterMC", "hDCAdaughterMC", kTH1F, {axisDCAdaugh}); - histos.add("tpcClusterTriton", "tpcClusterTriton", kTH1F, {{100, 0, 300, "TPC clusters"}}); - - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(cfgLUTpath)); - ft2.setMaxChi2(5); - ft2.setUseAbsDCA(true); - - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - ft2.setMatCorrType(matCorr); - } - - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - - // In case override, don't proceed, please - no CCDB access required - if (cfgBz > -990) { - mBz = cfgBz; - ft2.setBz(mBz); - o2::parameters::GRPMagField grpmag; - if (fabs(mBz) > 1e-5) { - grpmag.setL3Current(30000.f / (mBz / 5.0f)); - } - o2::base::Propagator::initFieldFromGRP(&grpmag); - mVtx = ccdb->getForTimeStamp(mVtxPath, bc.timestamp()); - mRunNumber = bc.runNumber(); - return; - } - - auto run3grp_timestamp = bc.timestamp(); - o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(cfgGRPpath, run3grp_timestamp); - o2::parameters::GRPMagField* grpmag = 0x0; - if (grpo) { - o2::base::Propagator::initFieldFromGRP(grpo); - // Fetch magnetic field from ccdb for current collision - mBz = grpo->getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << mBz << " kZG"; - } else { - grpmag = ccdb->getForTimeStamp(cfgGRPmagPath, run3grp_timestamp); - if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " << cfgGRPmagPath << " of object GRPMagField and " << cfgGRPpath << " of object GRPObject for timestamp " << run3grp_timestamp; - } - o2::base::Propagator::initFieldFromGRP(grpmag); - // Fetch magnetic field from ccdb for current collision - mBz = std::lround(5.f * grpmag->getL3Current() / 30000.f); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << mBz << " kZG"; - } - mVtx = ccdb->getForTimeStamp(mVtxPath, bc.timestamp()); - mRunNumber = bc.runNumber(); - - ft2.setBz(mBz); - - o2::base::Propagator::Instance()->setMatLUT(lut); - } - - std::array, 4> makeTracksPool(CompleteCollisions const& collisions, CompleteTracks const& tracks, o2::aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const&) - { - mKinkCandidates.clear(); - std::unordered_map> tmap; - TrackCand trForpool; - - std::array, 4> pools; // pools of positive and negative seeds sorted in min VtxID - std::vector selected(tracks.size(), 0u); - std::vector globalBCvector; - - int index{0}; - for (const auto& track : tracks) { - if (track.has_collision()) { - if (track.collision_as().has_bc()) { - globalBCvector.push_back(track.collision_as().bc_as().globalBC()); - } - } else { - for (const auto& ambTrack : ambiTracks) { - if (ambTrack.trackId() == track.globalIndex()) { - if (!ambTrack.has_bc() || ambTrack.bc_as().size() == 0) { - globalBCvector.push_back(-1); - break; - } - globalBCvector.push_back(ambTrack.bc_as().begin().globalBC()); - break; - } - } - } - - if (std::abs(track.eta()) < 0.8) { - if (track.hasITS() && !track.hasTPC() && !track.hasTOF() && track.itsNCls() < 6 && track.itsNClsInnerBarrel() == 3 && track.itsChi2NCl() < 4) { - selected[index] = 1; - } else if (track.hasITS() && track.hasTPC() && track.itsNClsInnerBarrel() == 0 && track.itsNCls() < 4 && track.tpcNClsCrossedRows() >= 70 && track.itsChi2NCl() < 36.f && track.tpcChi2NCl() < 4.f && track.tpcNClsCrossedRows() > 0.8 * track.tpcNClsFindable()) { - selected[index] = 2; - } - } - index++; - } - - constexpr auto bOffsetMax = 241; // 6 mus (ITS) - - for (const auto& collision : collisions) { - if (!collision.sel8()) - continue; - if (std::abs(collision.posZ()) > 10.) - continue; - - const float collTime = collision.collisionTime(); - const float collTimeRes2 = collision.collisionTimeRes() * collision.collisionTimeRes(); - uint64_t collBC = collision.bc_as().globalBC(); - const auto collIdx = collision.globalIndex(); - - histos.fill(HIST("hVtxZData"), collision.posZ()); - index = -1; - for (const auto& track : tracks) { - index++; - if (!selected[index] || !track.has_collision()) - continue; - const int64_t bcOffset = (int64_t)globalBCvector[track.filteredIndex()] - (int64_t)collBC; - if (std::abs(bcOffset) > bOffsetMax) { - continue; - } - - float trackTime{0.}; - float trackTimeRes{0.}; - if (track.isPVContributor()) { - trackTime = track.collision_as().collisionTime(); // if PV contributor, we assume the time to be the one of the collision - trackTimeRes = constants::lhc::LHCBunchSpacingNS; // 1 BC - } else { - trackTime = track.trackTime(); - trackTimeRes = track.trackTimeRes(); - } - - const float deltaTime = trackTime - collTime + bcOffset * constants::lhc::LHCBunchSpacingNS; - float sigmaTimeRes2 = collTimeRes2 + trackTimeRes * trackTimeRes; - - float thresholdTime = 0.; - if (track.isPVContributor()) { - thresholdTime = trackTimeRes; - } else if (TESTBIT(track.flags(), o2::aod::track::TrackTimeResIsRange)) { - thresholdTime = std::sqrt(sigmaTimeRes2); // + timeMargin; - } else { - // thresholdTime = nSigmaForTimeCompat * std::sqrt(sigmaTimeRes2); // + timeMargin; - thresholdTime = 4. * std::sqrt(sigmaTimeRes2); // + timeMargin; - } - - histos.fill(HIST("hdeltatime"), deltaTime); - histos.fill(HIST("hdelt_tthresh"), deltaTime, thresholdTime); - - if (std::abs(deltaTime) < thresholdTime) { - - const auto& tref = tmap.find(track.globalIndex()); - if (tref != tmap.end()) { - pools[tref->second.second][tref->second.first].vBracket.setMax(static_cast(collIdx)); // this track was already processed with other vertex, account the latter - continue; - } - } - - int poolIndex = (selected[index] - 1) * 2 + (track.sign() < 0); /// first the two mothers then the two daughters (mom pos 0, mom neg 1, dau pos 2, dau neg 3) - trForpool.Idxtr = track.globalIndex(); - trForpool.vBracket = {static_cast(collIdx), static_cast(collIdx)}; - pools[poolIndex].emplace_back(trForpool); - if (std::abs(deltaTime) < thresholdTime) { // track attached to >1 vertex, remember that it was already processed - tmap[track.globalIndex()] = {pools[poolIndex].size() - 1, poolIndex}; - } - - } // track Mother loop - } // collision loop - - return pools; - } - - void calculateInvMass(CompleteCollisions const& collisions, CompleteTracks const& tracks, o2::aod::AmbiguousTracks const& /*ambiTracks*/, aod::BCsWithTimestamps const& /*bcWtmp*/, gsl::span> trackPoolM, gsl::span> trackPoolD, int chargeM, int chargeD, int particleName, const aod::McParticles* partTable = nullptr) - { - - int ntrInner = chargeM < 0 ? trackPoolM[NEG].size() : trackPoolM[POS].size(); - int ntrOuter = chargeD < 0 ? trackPoolD[NEG].size() : trackPoolD[POS].size(); - - const int poolCh1 = chargeM < 0 ? 1 : 0; - const int poolCh2 = chargeD < 0 ? 1 : 0; - int motherPdg = 999; - float mcMotherPt = 0; - int daughterPdg = 777; - - switch (particleName) { - case SigmaMinus: - mMother = 1.197449; - mChargedDaughter = 0.13957039; - mNeutralDaughter = 0.9395654205; - break; - - case SigmaPlusToPi: - mMother = 1.18937; - mChargedDaughter = 0.13957039; - mNeutralDaughter = 0.9395654205; - break; - - case SigmaPlusToProton: - mMother = 1.18937; - mChargedDaughter = 0.93827208816; - mNeutralDaughter = 0.1349768; - break; - - case Kaon: - mMother = 0.493677; - mChargedDaughter = 0.1056583755; - mNeutralDaughter = 0.; - break; - - case Xi: - mMother = 1.32171; - mChargedDaughter = 0.13957039; - mNeutralDaughter = 1.115683; - break; - - case OmegaToL: - mMother = 1.67245; - mChargedDaughter = 0.493677; - mNeutralDaughter = 1.115683; - break; - - case OmegaToXi: - mMother = 1.67245; - mChargedDaughter = 0.13957039; - mNeutralDaughter = 1.31486; - break; - - case Hypertriton: - mMother = 2.99131; - mChargedDaughter = 2.808921; - mNeutralDaughter = 0.1349766; - break; - } - - o2::dataformats::VertexBase primaryVertex; - - std::array, 2> mVtxSecondTrack{}; // 1st pos. and neg. track of the pools for each vertex - - for (int i = 0; i < 2; i++) { - mVtxSecondTrack[i].clear(); - mVtxSecondTrack[i].resize(collisions.size(), -1); - } - - for (int pn = 0; pn < 2; pn++) { - auto& vtxFirstT = mVtxSecondTrack[pn]; - const auto& tracksPool = trackPoolD[pn]; - for (unsigned i = 0; i < tracksPool.size(); i++) { - const auto& t = tracksPool[i]; - for (int j{t.vBracket.getMin()}; j <= t.vBracket.getMax(); ++j) { - if (vtxFirstT[j] == -1) { - vtxFirstT[j] = i; - } - } - } - } - - for (int itp = 0; itp < ntrInner; itp++) { // HERE change neg->pos to get the other charge!!! - auto& seedM = trackPoolM[poolCh1][itp]; - int firstD = mVtxSecondTrack[poolCh2][seedM.vBracket.getMin()]; - if (firstD < 0) { - LOG(debug) << "No partner is found for pos.track " << itp << " out of " << ntrInner; - continue; - } - - const auto& trackM = tracks.iteratorAt(seedM.Idxtr); - if ((seedM.mcParticleIdx != -1) && partTable) { - auto mcParticle = partTable->rawIteratorAt(seedM.mcParticleIdx); - motherPdg = mcParticle.pdgCode(); - mcMotherPt = mcParticle.pt(); - } - - if (trackM.has_collision()) { - auto const& collision = trackM.collision_as(); - primaryVertex.setPos({collision.posX(), collision.posY(), collision.posZ()}); - primaryVertex.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); - histos.fill(HIST("hRecVtxZData"), primaryVertex.getZ()); - } else { - primaryVertex.setPos({mVtx->getX(), mVtx->getY(), mVtx->getZ()}); - histos.fill(HIST("hRecVtxZData"), primaryVertex.getZ()); - } - - SigmaTr = getTrackParCov(trackM); - o2::base::Propagator::Instance()->PropagateToXBxByBz(SigmaTr, kink::LayerRadii[trackM.itsNCls() - 1]); - - SigmaTr2 = getTrackParCov(trackM); - - gpu::gpustd::array dcaInfoM; - o2::base::Propagator::Instance()->propagateToDCABxByBz({primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, SigmaTr2, 2.f, static_cast(cfgMaterialCorrection.value), &dcaInfoM); - auto motherdcaXY = abs(dcaInfoM[0]); - histos.fill(HIST("hDCAMotherToPV"), motherdcaXY); - - if (motherdcaXY > 0.03) - continue; - - for (int itn = firstD; itn < ntrOuter; itn++) { - auto& seedD = trackPoolD[poolCh2][itn]; - if (seedD.vBracket.isOutside(seedM.vBracket)) { - LOG(debug) << "Brackets do not match"; - continue; - } - - const auto& trackDgh = tracks.iteratorAt(static_cast(seedD.Idxtr)); - - if ((seedD.mcParticleIdx != -1) && partTable) { - auto mcParticle = partTable->rawIteratorAt(seedD.mcParticleIdx); - daughterPdg = mcParticle.pdgCode(); - } - - bool isDaughter = false; - - if (cfgIsMC && (particleName == Hypertriton)) { - int tritPDG = 1000010030; - if (abs(daughterPdg) == tritPDG) - isDaughter = true; - } - - PionTr = getTrackParCov(trackDgh); - - SigmaTr2.getPxPyPzGlo(sigmaPin); - - if ((particleName == SigmaMinus) || (particleName == SigmaPlusToPi) || (particleName == Xi) || (particleName == OmegaToXi)) { - if (trackDgh.tpcNSigmaPi() > cfgNsigmaTPCdaughter) - continue; - } - if (particleName == SigmaPlusToProton) { - if (trackDgh.tpcNSigmaPr() > cfgNsigmaTPCdaughter) - continue; - } - if (particleName == OmegaToL) { - if (trackDgh.tpcNSigmaKa() > cfgNsigmaTPCdaughter) - continue; - } - if (particleName == Hypertriton) { - if (trackDgh.tpcNSigmaTr() > cfgNsigmaTPCdaughter) - continue; - } - - gpu::gpustd::array dcaInfo; - o2::base::Propagator::Instance()->propagateToDCABxByBz({primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, PionTr, 2.f, static_cast(cfgMaterialCorrection.value), &dcaInfo); - auto kinkdcaXY = abs(dcaInfo[0]); - histos.fill(HIST("hDCAdaughterToPV"), kinkdcaXY); - - if (kinkdcaXY < dcaKinkDtopv) - continue; - - // check how much the tracks are close in space - if ((cfgIsMC) && (motherPdg == particlePdgCode)) { - histos.fill(HIST("hdeltaphi"), (SigmaTr.getPhi() - PionTr.getPhi()) * radToDeg); - histos.fill(HIST("hdeltaz"), SigmaTr.getZ() - PionTr.getZ()); - } - - if (std::abs(SigmaTr.getZ() - PionTr.getZ()) > zDiff) - continue; - if ((std::abs(SigmaTr.getPhi() - PionTr.getPhi()) * radToDeg) > phiDiff) - continue; - - { - try { - ft2.process(PionTr, SigmaTr); - ft2.propagateTracksToVertex(); - if (ft2.isPropagateTracksToVertexDone() == true) { - auto SigmaTrDCA = ft2.getTrack(1); - auto PionTrDCA = ft2.getTrack(0); - SigmaTrDCA.getPxPyPzGlo(sigmaPDC); - sigmaPabsDC = SigmaTrDCA.getP(); - sigmaPt = SigmaTr.getPt(); - etaS = SigmaTr.getEta(); - phiS = SigmaTr.getPhi(); - - PionTrDCA.getPxPyPzGlo(pionPDC); - pionPabsDC = PionTrDCA.getP(); - etaP = PionTr.getEta(); - phiP = PionTr.getPhi(); - - pionE = 0; - neutronE = 0; - - if (ft2.getChi2AtPCACandidate() < 0) - continue; - std::array R = ft2.getPCACandidatePos(); - - pionE = sqrt(mChargedDaughter * mChargedDaughter + pionPabsDC * pionPabsDC); - - costheta = (sigmaPDC[0] * pionPDC[0] + sigmaPDC[1] * pionPDC[1] + sigmaPDC[2] * pionPDC[2]) / (sigmaPabsDC * pionPabsDC); - theta = std::acos(costheta); - - qT = pionPabsDC * std::sin(theta); - - histos.fill(HIST("hqT"), qT); - - sigmaE = sqrt(mMother * mMother + sigmaPabsDC * sigmaPabsDC); - neutronPabs = sqrt(pow((sigmaPDC[2] - pionPDC[2]), 2) + pow((sigmaPDC[1] - pionPDC[1]), 2) + pow((sigmaPDC[0] - pionPDC[0]), 2)); - neutronM = sqrt((sigmaE - pionE) * (sigmaE - pionE) - neutronPabs * neutronPabs); - - if (cfgMassCheck) { - if (abs(neutronM - mNeutralDaughter) / mNeutralDaughter > 0.1) - continue; - } - - if ((particleName == SigmaMinus) || (particleName == SigmaPlusToPi)) { - if ((theta * radToDeg > (angleCutFunction(particleName, sigmaPabsDC))) && (sigmaPabsDC > 1.6)) - continue; - } - if (particleName == SigmaPlusToProton) { - if ((theta * radToDeg > (angleCutFunction(particleName, sigmaPabsDC))) && (sigmaPabsDC > 0.3)) - continue; - } - if (particleName == Kaon) { - Double_t maxDecAngKmu = angleCutFunction(particleName, sigmaPabsDC); - Double_t maxDecAngpimu = angleCutFunction(Pion, sigmaPabsDC); - - if ((theta * radToDeg < maxDecAngpimu * 1.2)) - continue; - if ((theta * radToDeg > maxDecAngKmu * .98) && (sigmaPabsDC > 1.2)) - continue; - } - if (particleName == Xi) { - if (sigmaPabsDC < 2.) - if (theta * radToDeg < 2.5) - continue; - if (sigmaPabsDC > 1.2) - if (theta * radToDeg > angleCutFunction(particleName, sigmaPabsDC)) - continue; - } - if ((particleName == OmegaToL) || (particleName == OmegaToXi)) { - if (sigmaPabsDC < 5.5) - if (theta * radToDeg < 4.) - continue; - if (sigmaPabsDC > 0.6) - if (theta * radToDeg > angleCutFunction(particleName, sigmaPabsDC)) - continue; - } - - if (particleName == Hypertriton) { - // if (sigmaPabsDC < 2.5) - // if (theta * radToDeg < 2.5) - // continue; - if (sigmaPabsDC > 0.6) - if (theta * radToDeg > angleCutFunction(particleName, sigmaPabsDC)) - continue; - } - - if (!cfgIsMC) - if (sigmaPt < 1.6) - continue; - - if (particleName != Hypertriton) { - if (theta * radToDeg < 0.5) - continue; - } else if (theta * radToDeg < 0.2) { - continue; - } - - if ((qT < qTlower) || (qT > qTupper)) - continue; - - if (sqrt(R[0] * R[0] + R[1] * R[1]) < 18.) - continue; - - if (chargeM == chargeD) - mKinkCandidates.emplace_back(KinkCandidates{chargeM, seedM.Idxtr, seedD.Idxtr, seedM.mcParticleIdx, seedD.mcParticleIdx, primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ(), R[0], R[1], R[2], sigmaPin[0], sigmaPin[1], sigmaPin[2], sigmaPDC[0], sigmaPDC[1], sigmaPDC[2], pionPDC[0], pionPDC[1], pionPDC[2]}); - - neutronE = sqrt(mNeutralDaughter * mNeutralDaughter + pow((sigmaPDC[2] - pionPDC[2]), 2) + pow((sigmaPDC[1] - pionPDC[1]), 2) + pow((sigmaPDC[0] - pionPDC[0]), 2)); - - mass = sqrt((neutronE + pionE) * (neutronE + pionE) - sigmaPabsDC * sigmaPabsDC); - - if (isDaughter) - histos.fill(HIST("hDCAdaughterMC"), kinkdcaXY); - - if (particleName == Hypertriton) { - if (trackDgh.tpcNSigmaTr() > 4 || trackDgh.tpcNSigmaTr() < -2) - continue; - - histos.fill(HIST("tpcClusterTriton"), trackDgh.tpcNClsFound()); - if (trackDgh.tpcNClsFound() < 90) - continue; - } - - if (particleName == Hypertriton) { - histos.fill(HIST("hHypMass"), mass); - histos.fill(HIST("hHypMassPt"), mass, sigmaPt); - - histos.fill(HIST("hNSigmaTrVsPt"), sigmaPt, trackDgh.tpcNSigmaTr()); - if (isDaughter) - histos.fill(HIST("hHypMassMC"), mass); - } - - if (((chargeM == -1) && (chargeD == -1)) || ((chargeM == 1) && (chargeD == 1))) { - if (cfgIsMC) { - histos.fill(HIST("hcodes"), motherPdg, daughterPdg); - } - } - - if ((chargeM == -1) && (chargeD == -1)) { - if (cfgIsMC) { - if ((motherPdg == particlePdgCode || motherPdg == -3222) && (daughterPdg == -211)) { - histos.fill(HIST("hPtMinusRecMcTrth"), mass, sigmaPt); - histos.fill(HIST("hptMDtrue"), sigmaPt, PionTr.getPt()); - } else if ((motherPdg == particlePdgCode || motherPdg == -3222) && (daughterPdg != -211)) { - histos.fill(HIST("hptMtrue"), sigmaPt, PionTr.getPt()); - histos.fill(HIST("hPtMinusRecMcTrthM"), mass, sigmaPt); - } else if (motherPdg == -1010010030 && daughterPdg == -1000010030) { - histos.fill(HIST("hpRes"), sigmaPt, (mcMotherPt - sigmaPt) / mcMotherPt); - } else { - histos.fill(HIST("hptMDelse"), sigmaPt, PionTr.getPt()); - histos.fill(HIST("hPtMinusRecMcTrthelse"), mass, sigmaPt); - } - } - histos.fill(HIST("hMassMinusPt"), mass, sigmaPt); - } - if ((chargeM == 1) && (chargeD == 1)) { - if (cfgIsMC) { - if (motherPdg == particlePdgCode) - histos.fill(HIST("hPtPlusRecMcTrth"), mass, sigmaPt); - if (motherPdg == 1010010030 && daughterPdg == 1000010030) - histos.fill(HIST("hpRes"), sigmaPt, (mcMotherPt - sigmaPt) / mcMotherPt); - } - histos.fill(HIST("hMassPlusPt"), mass, sigmaPt); - } - - if ((chargeM == -1) && (chargeD == 1)) { - histos.fill(HIST("hBackgroundNegPosPt"), mass, sigmaPt); - } - if ((chargeM == 1) && (chargeD == -1)) { - histos.fill(HIST("hBackgroundPosNegPt"), mass, sigmaPt); - } - } // true - } catch (std::runtime_error& e) { - continue; - } - //} //dca fitter option - - } // try - - } // inner track loop - } // outer track loop - } - - void processReco(CompleteCollisions const& collisions, CompleteTracks const& tracks, o2::aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcWtmp) - { - auto firstcollision = collisions.begin(); - auto bc1 = firstcollision.bc_as(); - initCCDB(bc1); - - auto trackPools = makeTracksPool(collisions, tracks, ambiTracks, bcWtmp); - - LOG(info) << "Collected for mother " << trackPools[POS].size() << " positive and " << trackPools[NEG].size() << " negative seeds"; - - LOG(info) << "Collected for daughter " << trackPools[2 + POS].size() << " positive and " << trackPools[2 + NEG].size() << " negative seeds"; - - gsl::span> trackPoolsMth{trackPools.data(), 2}; - gsl::span> trackPoolsDhgt{trackPools.data() + 2, 2}; - - calculateInvMass(collisions, tracks, ambiTracks, bcWtmp, trackPoolsMth, trackPoolsDhgt, cfgMotherCharge, cfgDaughterCharge, cfgParticleSpec); - calculateInvMass(collisions, tracks, ambiTracks, bcWtmp, trackPoolsMth, trackPoolsDhgt, -1, +1, cfgParticleSpec); - calculateInvMass(collisions, tracks, ambiTracks, bcWtmp, trackPoolsMth, trackPoolsDhgt, +1, -1, cfgParticleSpec); - - } // process - - PROCESS_SWITCH(kinkAnalysis, processReco, "process reconstructed information", true); - - void processSim(CompleteCollisions const& collisions, CompleteTracks const& tracks, o2::aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcWtmp, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC) - { - auto firstcollision = collisions.begin(); - auto bc1 = firstcollision.bc_as(); - initCCDB(bc1); - - for (const auto& mcParticle : particlesMC) { - if (mcParticle.pdgCode() != particlePdgCode) - continue; - histos.fill(HIST("generatedPt"), mcParticle.pt()); - } - - auto trackPools = makeTracksPool(collisions, tracks, ambiTracks, bcWtmp); - - for (auto& pool : trackPools) { - for (auto& track : pool) { - auto label = trackLabelsMC.iteratorAt(track.Idxtr); - if (label.mcParticleId() < -1 || label.mcParticleId() >= particlesMC.size()) { - continue; - } - track.mcParticleIdx = label.mcParticleId(); - } - } - - LOG(info) << "Collected for mother " << trackPools[POS].size() << " positive and " << trackPools[NEG].size() << " negative seeds"; - - LOG(info) << "Collected for daughter " << trackPools[2 + POS].size() << " positive and " << trackPools[2 + NEG].size() << " negative seeds"; - - gsl::span> trackPoolsMth{trackPools.data(), 2}; - gsl::span> trackPoolsDhgt{trackPools.data() + 2, 2}; - - calculateInvMass(collisions, tracks, ambiTracks, bcWtmp, trackPoolsMth, trackPoolsDhgt, cfgMotherCharge, cfgDaughterCharge, cfgParticleSpec, &particlesMC); - - // for (auto& candidates : mKinkCandidates) { - - // } - - calculateInvMass(collisions, tracks, ambiTracks, bcWtmp, trackPoolsMth, trackPoolsDhgt, -1, +1, cfgParticleSpec, &particlesMC); - calculateInvMass(collisions, tracks, ambiTracks, bcWtmp, trackPoolsMth, trackPoolsDhgt, +1, -1, cfgParticleSpec, &particlesMC); - } // process - - PROCESS_SWITCH(kinkAnalysis, processSim, "process sim information", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGLF/Tasks/Strangeness/lambdaJetpolarization.cxx b/PWGLF/Tasks/Strangeness/lambdaJetpolarization.cxx new file mode 100644 index 00000000000..5cf681104ea --- /dev/null +++ b/PWGLF/Tasks/Strangeness/lambdaJetpolarization.cxx @@ -0,0 +1,335 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// + +/// \author Youpeng Su (yousu@cern.ch) +#include +#include +#include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Common/DataModel/EventSelection.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Common/DataModel/PIDResponse.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include +#include +#include +#include "PWGLF/DataModel/lambdaJetpolarization.h" +using std::cout; +using std::endl; +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct LfMyV0s { + HistogramRegistry registry{"registry"}; + void init(InitContext const&) + { + const AxisSpec axisPx{100, -10, 10, "#px (GeV/c)"}; + const AxisSpec axisPy{100, -10, 10, "#py (GeV/c)"}; + const AxisSpec axisPz{100, -10, 10, "#pz (GeV/c)"}; + const AxisSpec axisPT{200, 0, 50, "#p_{T} (GeV/c)"}; + const AxisSpec axisPhi{100, -3.14, 3.14, "#Phi"}; + const AxisSpec axisMass{100, 0, 2, "Mass(GeV/c^{2})"}; + + registry.add("hMassLambda", "hMassLambda", {HistType::kTH1F, {{200, 0.9f, 1.2f}}}); + registry.add("V0pTInLab", "V0pTInLab", kTH1F, {axisPT}); + registry.add("hMassVsPtLambda", "hMassVsPtLambda", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {200, 1.016f, 1.216f}}}); + registry.add("hMassVsPtAntiLambda", "hMassVsPtAntiLambda", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {200, 1.016f, 1.216f}}}); + + registry.add("V0pxInLab", "V0pxInLab", kTH1F, {axisPx}); + registry.add("V0pyInLab", "V0pyInLab", kTH1F, {axisPy}); + registry.add("V0pzInLab", "V0pzInLab", kTH1F, {axisPz}); + + registry.add("V0pxInRest_frame", "V0pxInRest_frame", kTH1F, {axisPx}); + registry.add("V0pyInRest_frame", "V0pyInRest_frame", kTH1F, {axisPy}); + registry.add("V0pzInRest_frame", "V0pzInRest_frame", kTH1F, {axisPz}); + + registry.add("JetpxInLab", "JetpxInLab", kTH1F, {axisPx}); + registry.add("JetpyInLab", "JetpyInLab", kTH1F, {axisPy}); + registry.add("JetpzInLab", "JetpzInLab", kTH1F, {axisPz}); + registry.add("JetpTInLab", "JetpTInLab", kTH1F, {axisPT}); + + registry.add("LeadingJetpx", "LeadingJetpx", kTH1F, {axisPx}); + registry.add("LeadingJetpy", "LeadingJetpy", kTH1F, {axisPy}); + registry.add("LeadingJetpz", "LeadingJetpz", kTH1F, {axisPz}); + registry.add("LeadingJetpT", "LeadingJetpT", kTH1F, {axisPT}); + + registry.add("V0protonpxInLab", "V0protonpxInLab", kTH1F, {axisPx}); + registry.add("V0protonpyInLab", "V0protonpyInLab", kTH1F, {axisPy}); + registry.add("V0protonpzInLab", "V0protonpzInLab", kTH1F, {axisPz}); + registry.add("V0protonphiInLab", "V0protonphiInLab", kTH1F, {axisPhi}); + + registry.add("V0protonpxInRest_frame", "V0protonpxInRest_frame", kTH1F, {axisPx}); + registry.add("V0protonpyInRest_frame", "V0protonpyInRest_frame", kTH1F, {axisPy}); + registry.add("V0protonpzInRest_frame", "V0protonpzInRest_frame", kTH1F, {axisPz}); + registry.add("V0protonMassInRest_frame", "V0protonMassInRest_frame", kTH1F, {axisMass}); + registry.add("V0protonphiInRest_frame", "V0protonphiInRest_frame", kTH1F, {axisPhi}); + + registry.add("V0protonpxInJetV0frame", "V0protonpxInJetV0frame", kTH1F, {axisPx}); + registry.add("V0protonpyInJetV0frame", "V0protonpyInJetV0frame", kTH1F, {axisPy}); + registry.add("V0protonpzInJetV0frame", "V0protonpzInJetV0frame", kTH1F, {axisPz}); + registry.add("V0protonphiInJetV0frame", "V0protonphiInJetV0frame", kTH1F, {axisPhi}); + registry.add("V0antiprotonphiInJetV0frame", "V0antiprotonphiInJetV0frame", kTH1F, {axisPhi}); + + registry.add("V0LambdapxInJetV0frame", "V0LambdapxInJetV0frame", kTH1F, {axisPx}); + registry.add("V0LambdapyInJetV0frame", "V0LambdapyInJetV0frame", kTH1F, {axisPy}); + registry.add("V0LambdapzInJetV0frame", "V0LambdapzInJetV0frame", kTH1F, {axisPz}); + + registry.add("hLambdamassandSinPhi", "hLambdamassandSinPhi", kTH2F, {{200, 0.9, 1.2}, {200, -1, 1}}); + registry.add("hAntiLambdamassandSinPhi", "hAntiLambdamassandSinPhi", kTH2F, {{200, 0.9, 1.2}, {200, -1, 1}}); + registry.add("profile", "Invariant Mass vs sin(phi)", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registry.add("profileAntiV0", "Invariant Mass vs sin(phi)", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registry.add("hLambdaPhiandSinPhi", "hLambdaPhiandSinPhi", kTH2F, {{200, -TMath::Pi() / 2, TMath::Pi() / 2}, {200, -1, 1}}); + registry.add("hAntiLambdaPhiandSinPhi", "hAntiLambdaPhiandSinPhi", kTH2F, {{200, -TMath::Pi() / 2, TMath::Pi() / 2}, {200, -1, 1}}); + + registry.add("V0LambdaprotonPhi", "V0LambdaprotonPhi", {HistType::kTH1F, {{200, -TMath::Pi() / 2, TMath::Pi() / 2}}}); + registry.add("V0AntiLambdaprotonPhi", "V0AntiLambdaprotonPhi", {HistType::kTH1F, {{200, -TMath::Pi() / 2, TMath::Pi() / 2}}}); + } + double massPr = o2::constants::physics::MassProton; + double massLambda = o2::constants::physics::MassLambda; + + TMatrixD LorentzTransInV0frame(double ELambda, double Lambdapx, double Lambdapy, double Lambdapz) + { + double PLambda = sqrt(Lambdapx * Lambdapx + Lambdapy * Lambdapy + Lambdapz * Lambdapz); + double LambdaMass = sqrt(ELambda * ELambda - PLambda * PLambda); + double Alpha = 1 / (LambdaMass * (ELambda + LambdaMass)); + TMatrixD matrixLabToLambda(4, 4); + matrixLabToLambda(0, 0) = ELambda / LambdaMass; + matrixLabToLambda(0, 1) = -Lambdapx / LambdaMass; + matrixLabToLambda(0, 2) = -Lambdapy / LambdaMass; + matrixLabToLambda(0, 3) = -Lambdapz / LambdaMass; + matrixLabToLambda(1, 0) = -Lambdapx / LambdaMass; + matrixLabToLambda(1, 1) = 1 + Alpha * Lambdapx * Lambdapx; + matrixLabToLambda(1, 2) = Alpha * Lambdapx * Lambdapy; + matrixLabToLambda(1, 3) = Alpha * Lambdapx * Lambdapz; + matrixLabToLambda(2, 0) = -Lambdapy / LambdaMass; + matrixLabToLambda(2, 1) = Alpha * Lambdapy * Lambdapx; + matrixLabToLambda(2, 2) = 1 + Alpha * Lambdapy * Lambdapy; + matrixLabToLambda(2, 3) = Alpha * Lambdapy * Lambdapz; + matrixLabToLambda(3, 0) = -Lambdapz / LambdaMass; + matrixLabToLambda(3, 1) = Alpha * Lambdapz * Lambdapx; + matrixLabToLambda(3, 2) = Alpha * Lambdapz * Lambdapy; + matrixLabToLambda(3, 3) = 1 + Alpha * Lambdapz * Lambdapz; + return matrixLabToLambda; + } + TMatrixD MyTMatrixTranslationToJet(double Jetpx, double Jetpy, double Jetpz, double Lambdapx, double Lambdapy, double Lambdapz) + { + TVector3 UnitX(1.0, 0.0, 0.0); + TVector3 UnitY(0.0, 1.0, 0.0); + TVector3 UnitZ(0.0, 0.0, 1.0); + TVector3 JetP(Jetpx, Jetpy, Jetpz); + TVector3 V0LambdaP(Lambdapx, Lambdapy, Lambdapz); + TVector3 vortex_y = (JetP.Cross(V0LambdaP)); + + TVector3 z_hat = JetP.Unit(); + TVector3 y_hat = vortex_y.Unit(); + TVector3 x_hat1 = y_hat.Cross(z_hat); + TVector3 x_hat = x_hat1.Unit(); + + TMatrixD matrixLabToJet(4, 4); + matrixLabToJet(0, 0) = 1; + matrixLabToJet(0, 1) = 0.0; + matrixLabToJet(0, 2) = 0.0; + matrixLabToJet(0, 3) = 0.0; + matrixLabToJet(1, 0) = 0.0; + matrixLabToJet(1, 1) = x_hat.X(); + matrixLabToJet(1, 2) = x_hat.Y(); + matrixLabToJet(1, 3) = x_hat.Z(); + matrixLabToJet(2, 0) = 0.0; + matrixLabToJet(2, 1) = y_hat.X(); + matrixLabToJet(2, 2) = y_hat.Y(); + matrixLabToJet(2, 3) = y_hat.Z(); + matrixLabToJet(3, 0) = 0.0; + matrixLabToJet(3, 1) = z_hat.X(); + matrixLabToJet(3, 2) = z_hat.Y(); + matrixLabToJet(3, 3) = z_hat.Z(); + return matrixLabToJet; + } + // aod::MyCollision const& collision + void processJetV0Analysis(aod::MyTable const& myv0s, aod::MyTableJet const& myJets) + { + for (auto& candidate : myv0s) { + registry.fill(HIST("hMassLambda"), candidate.v0Lambdamass()); + registry.fill(HIST("V0pTInLab"), candidate.v0pt()); + registry.fill(HIST("hMassVsPtLambda"), candidate.v0pt(), candidate.v0Lambdamass()); + registry.fill(HIST("V0pxInLab"), candidate.v0px()); + registry.fill(HIST("V0pyInLab"), candidate.v0py()); + registry.fill(HIST("V0pzInLab"), candidate.v0pz()); + registry.fill(HIST("V0protonpxInLab"), candidate.v0protonpx()); + registry.fill(HIST("V0protonpyInLab"), candidate.v0protonpy()); + registry.fill(HIST("V0protonpzInLab"), candidate.v0protonpz()); + double protonsinPhiInLab = candidate.v0protonpy() / sqrt(candidate.v0protonpx() * candidate.v0protonpx() + candidate.v0protonpy() * candidate.v0protonpy()); + registry.fill(HIST("V0protonphiInLab"), protonsinPhiInLab); + double PLambda = sqrt(candidate.v0px() * candidate.v0px() + candidate.v0py() * candidate.v0py() + candidate.v0pz() * candidate.v0pz()); + double ELambda = sqrt(candidate.v0Lambdamass() * candidate.v0Lambdamass() + PLambda * PLambda); + TMatrixD pLabV0(4, 1); + pLabV0(0, 0) = ELambda; + pLabV0(1, 0) = candidate.v0px(); + pLabV0(2, 0) = candidate.v0py(); + pLabV0(3, 0) = candidate.v0pz(); + TMatrixD V0InV0(4, 1); + V0InV0 = LorentzTransInV0frame(ELambda, candidate.v0px(), candidate.v0py(), candidate.v0pz()) * pLabV0; + registry.fill(HIST("V0pxInRest_frame"), V0InV0(1, 0)); + registry.fill(HIST("V0pyInRest_frame"), V0InV0(2, 0)); + registry.fill(HIST("V0pzInRest_frame"), V0InV0(3, 0)); + } + for (auto& candidate : myv0s) { + double PLambda = sqrt(candidate.v0px() * candidate.v0px() + candidate.v0py() * candidate.v0py() + candidate.v0pz() * candidate.v0pz()); + double ELambda = sqrt(candidate.v0Lambdamass() * candidate.v0Lambdamass() + PLambda * PLambda); + TMatrixD pLabproton(4, 1); + double protonE = sqrt(massPr * massPr + candidate.v0protonpx() * candidate.v0protonpx() + candidate.v0protonpy() * candidate.v0protonpy() + candidate.v0protonpz() * candidate.v0protonpz()); + pLabproton(0, 0) = protonE; + pLabproton(1, 0) = candidate.v0protonpx(); + pLabproton(2, 0) = candidate.v0protonpy(); + pLabproton(3, 0) = candidate.v0protonpz(); + TMatrixD protonInV0(4, 1); + protonInV0 = LorentzTransInV0frame(ELambda, candidate.v0px(), candidate.v0py(), candidate.v0pz()) * pLabproton; + double protonMassInV0 = sqrt(protonInV0(0, 0) * protonInV0(0, 0) - protonInV0(1, 0) * protonInV0(1, 0) - protonInV0(2, 0) * protonInV0(2, 0) - protonInV0(3, 0) * protonInV0(3, 0)); + registry.fill(HIST("V0protonMassInRest_frame"), protonMassInV0); + registry.fill(HIST("V0protonpxInRest_frame"), protonInV0(1, 0)); + registry.fill(HIST("V0protonpyInRest_frame"), protonInV0(2, 0)); + registry.fill(HIST("V0protonpzInRest_frame"), protonInV0(3, 0)); + double protonsinPhiInV0frame = protonInV0(2, 0) / sqrt(protonInV0(1, 0) * protonInV0(1, 0) + protonInV0(2, 0) * protonInV0(2, 0)); + registry.fill(HIST("V0protonphiInRest_frame"), protonsinPhiInV0frame); + } + + for (auto& Jet : myJets) { + registry.fill(HIST("JetpxInLab"), Jet.jetpx()); + registry.fill(HIST("JetpyInLab"), Jet.jetpy()); + registry.fill(HIST("JetpzInLab"), Jet.jetpz()); + registry.fill(HIST("JetpTInLab"), Jet.jetpt()); + } + } + PROCESS_SWITCH(LfMyV0s, processJetV0Analysis, "processJetV0Analysis", true); + void processLeadingJetV0Analysis(aod::MyTable const& myv0s, aod::MyTableLeadingJet const& myleadingJets) + { + for (auto& LeadingJet : myleadingJets) { + int V0Numbers = 0; + double protonsinPhiInJetV0frame = 0; + for (auto& candidate : myv0s) { + if (candidate.mycollisionv0() == LeadingJet.mycollisionleadingjet()) { + V0Numbers = V0Numbers + 1; + double PLambda = sqrt(candidate.v0px() * candidate.v0px() + candidate.v0py() * candidate.v0py() + candidate.v0pz() * candidate.v0pz()); + double ELambda = sqrt(candidate.v0Lambdamass() * candidate.v0Lambdamass() + PLambda * PLambda); + double protonE = sqrt(massPr * massPr + candidate.v0protonpx() * candidate.v0protonpx() + candidate.v0protonpy() * candidate.v0protonpy() + candidate.v0protonpz() * candidate.v0protonpz()); + + TMatrixD pLabV0(4, 1); + pLabV0(0, 0) = ELambda; + pLabV0(1, 0) = candidate.v0px(); + pLabV0(2, 0) = candidate.v0py(); + pLabV0(3, 0) = candidate.v0pz(); + + TMatrixD lambdaInJet(4, 1); + lambdaInJet = MyTMatrixTranslationToJet(LeadingJet.leadingjetpx(), LeadingJet.leadingjetpy(), LeadingJet.leadingjetpz(), candidate.v0px(), candidate.v0py(), candidate.v0pz()) * pLabV0; + + TMatrixD lambdaInJetV0(4, 1); + lambdaInJetV0 = LorentzTransInV0frame(ELambda, lambdaInJet(1, 0), lambdaInJet(2, 0), lambdaInJet(3, 0)) * MyTMatrixTranslationToJet(LeadingJet.leadingjetpx(), LeadingJet.leadingjetpy(), LeadingJet.leadingjetpz(), candidate.v0px(), candidate.v0py(), candidate.v0pz()) * pLabV0; + registry.fill(HIST("V0LambdapxInJetV0frame"), lambdaInJetV0(1, 0)); + registry.fill(HIST("V0LambdapyInJetV0frame"), lambdaInJetV0(2, 0)); + registry.fill(HIST("V0LambdapzInJetV0frame"), lambdaInJetV0(3, 0)); + + TMatrixD pLabproton(4, 1); + pLabproton(0, 0) = protonE; + pLabproton(1, 0) = candidate.v0protonpx(); + pLabproton(2, 0) = candidate.v0protonpy(); + pLabproton(3, 0) = candidate.v0protonpz(); + TMatrixD protonInJetV0(4, 1); + protonInJetV0 = LorentzTransInV0frame(ELambda, lambdaInJet(1, 0), lambdaInJet(2, 0), lambdaInJet(3, 0)) * MyTMatrixTranslationToJet(LeadingJet.leadingjetpx(), LeadingJet.leadingjetpy(), LeadingJet.leadingjetpz(), candidate.v0px(), candidate.v0py(), candidate.v0pz()) * pLabproton; + registry.fill(HIST("V0protonpxInJetV0frame"), protonInJetV0(1, 0)); + registry.fill(HIST("V0protonpyInJetV0frame"), protonInJetV0(2, 0)); + registry.fill(HIST("V0protonpzInJetV0frame"), protonInJetV0(3, 0)); + protonsinPhiInJetV0frame = protonsinPhiInJetV0frame + protonInJetV0(2, 0) / sqrt(protonInJetV0(1, 0) * protonInJetV0(1, 0) + protonInJetV0(2, 0) * protonInJetV0(2, 0)); + } + } + for (auto& candidate : myv0s) { + if (candidate.mycollisionv0() == LeadingJet.mycollisionleadingjet()) { + registry.fill(HIST("V0protonphiInJetV0frame"), protonsinPhiInJetV0frame / V0Numbers); + registry.fill(HIST("hLambdamassandSinPhi"), candidate.v0Lambdamass(), protonsinPhiInJetV0frame / V0Numbers); + registry.fill(HIST("hLambdaPhiandSinPhi"), TMath::ASin(protonsinPhiInJetV0frame / V0Numbers), protonsinPhiInJetV0frame / V0Numbers); + registry.fill(HIST("V0LambdaprotonPhi"), TMath::ASin(protonsinPhiInJetV0frame / V0Numbers)); + registry.fill(HIST("profile"), candidate.v0Lambdamass(), protonsinPhiInJetV0frame / V0Numbers); + } + } + } + for (auto& LeadingJet : myleadingJets) { + registry.fill(HIST("LeadingJetpx"), LeadingJet.leadingjetpx()); + registry.fill(HIST("LeadingJetpy"), LeadingJet.leadingjetpy()); + registry.fill(HIST("LeadingJetpz"), LeadingJet.leadingjetpz()); + registry.fill(HIST("LeadingJetpT"), LeadingJet.leadingjetpt()); + } + } + PROCESS_SWITCH(LfMyV0s, processLeadingJetV0Analysis, "processLeadingJetV0Analysis", true); + + void processLeadingJetAntiV0Analysis(aod::MyTableAnti const& myv0s, aod::MyTableLeadingJet const& myleadingJets) + { + for (auto& LeadingJet : myleadingJets) { + int V0Numbers = 0; + double protonsinPhiInJetV0frame = 0; + for (auto& candidate : myv0s) { + if (candidate.mycollisionv0() == LeadingJet.mycollisionleadingjet()) { + V0Numbers = V0Numbers + 1; + double PLambda = sqrt(candidate.v0px() * candidate.v0px() + candidate.v0py() * candidate.v0py() + candidate.v0pz() * candidate.v0pz()); + double ELambda = sqrt(candidate.v0Lambdamass() * candidate.v0Lambdamass() + PLambda * PLambda); + double protonE = sqrt(massPr * massPr + candidate.v0protonpx() * candidate.v0protonpx() + candidate.v0protonpy() * candidate.v0protonpy() + candidate.v0protonpz() * candidate.v0protonpz()); + + TMatrixD pLabV0(4, 1); + pLabV0(0, 0) = ELambda; + pLabV0(1, 0) = candidate.v0px(); + pLabV0(2, 0) = candidate.v0py(); + pLabV0(3, 0) = candidate.v0pz(); + + TMatrixD lambdaInJet(4, 1); + lambdaInJet = MyTMatrixTranslationToJet(LeadingJet.leadingjetpx(), LeadingJet.leadingjetpy(), LeadingJet.leadingjetpz(), candidate.v0px(), candidate.v0py(), candidate.v0pz()) * pLabV0; + + TMatrixD lambdaInJetV0(4, 1); + lambdaInJetV0 = LorentzTransInV0frame(ELambda, lambdaInJet(1, 0), lambdaInJet(2, 0), lambdaInJet(3, 0)) * MyTMatrixTranslationToJet(LeadingJet.leadingjetpx(), LeadingJet.leadingjetpy(), LeadingJet.leadingjetpz(), candidate.v0px(), candidate.v0py(), candidate.v0pz()) * pLabV0; + + TMatrixD pLabproton(4, 1); + pLabproton(0, 0) = protonE; + pLabproton(1, 0) = candidate.v0protonpx(); + pLabproton(2, 0) = candidate.v0protonpy(); + pLabproton(3, 0) = candidate.v0protonpz(); + TMatrixD protonInJetV0(4, 1); + protonInJetV0 = LorentzTransInV0frame(ELambda, lambdaInJet(1, 0), lambdaInJet(2, 0), lambdaInJet(3, 0)) * MyTMatrixTranslationToJet(LeadingJet.leadingjetpx(), LeadingJet.leadingjetpy(), LeadingJet.leadingjetpz(), candidate.v0px(), candidate.v0py(), candidate.v0pz()) * pLabproton; + protonsinPhiInJetV0frame = protonsinPhiInJetV0frame + protonInJetV0(2, 0) / sqrt(protonInJetV0(1, 0) * protonInJetV0(1, 0) + protonInJetV0(2, 0) * protonInJetV0(2, 0)); + } + } + for (auto& candidate : myv0s) { + if (candidate.mycollisionv0() == LeadingJet.mycollisionleadingjet()) { + registry.fill(HIST("V0antiprotonphiInJetV0frame"), protonsinPhiInJetV0frame / V0Numbers); + registry.fill(HIST("hAntiLambdamassandSinPhi"), candidate.v0Lambdamass(), protonsinPhiInJetV0frame / V0Numbers); + registry.fill(HIST("hAntiLambdaPhiandSinPhi"), TMath::ASin(protonsinPhiInJetV0frame / V0Numbers), protonsinPhiInJetV0frame / V0Numbers); + registry.fill(HIST("V0AntiLambdaprotonPhi"), TMath::ASin(protonsinPhiInJetV0frame / V0Numbers)); + registry.fill(HIST("profileAntiV0"), candidate.v0Lambdamass(), protonsinPhiInJetV0frame / V0Numbers); + } + } + } + for (auto& candidate : myv0s) { + registry.fill(HIST("hMassVsPtAntiLambda"), candidate.v0pt(), candidate.v0Lambdamass()); + } + } + PROCESS_SWITCH(LfMyV0s, processLeadingJetAntiV0Analysis, "processLeadingJetAntiV0Analysis", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGLF/Tasks/Strangeness/lambdak0sflattenicity.cxx b/PWGLF/Tasks/Strangeness/lambdak0sflattenicity.cxx new file mode 100755 index 00000000000..4114d614b90 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/lambdak0sflattenicity.cxx @@ -0,0 +1,2012 @@ +// 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. +/// +/// Making modifications to the Strangeness Tutorial code +/// The code is still in development mode +/// Flattenicity part of the code is adopted from +/// https://github.com/AliceO2Group/O2Physics/blob/master/PWGMM/Mult/Tasks/flatenicityFV0.cxx +/// \file lambdak0sflattenicity.cxx +/// \brief V0 task for production of strange hadrons as a function of flattenicity +/// \author Suraj Prasad (suraj.prasad@cern.ch) + +#include +#include +#include +#include +#include +#include + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "Framework/O2DatabasePDGPlugin.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/PIDResponse.h" + +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/inelGt.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct Lambdak0sflattenicity { + // Histograms are defined with HistogramRegistry + Service pdg; + HistogramRegistry rEventSelection{"eventSelection", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; + HistogramRegistry rKzeroShort{ + "kzeroShort", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; + HistogramRegistry rLambda{ + "lambda", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; + HistogramRegistry rAntiLambda{ + "antilambda", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; + HistogramRegistry rXi{ + "Xi", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; + HistogramRegistry rCommonHist{ + "commonhists", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; + HistogramRegistry rFlattenicity{ + "flattenicity", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; + + static constexpr std::string_view kHEst[8] = { + "eGlobaltrack", "eFV0", "e1flatencityFV0", "eFT0", + "e1flatencityFT0", "eFV0FT0C", "e1flatencityFV0FT0C", "ePtTrig"}; + static constexpr std::string_view kTEst[8] = { + "GlobalTrk", "FV0", "1-flatencity_FV0", "FT0", + "1-flatencityFT0", "FV0_FT0C", "1-flatencity_FV0_FT0C", "PtTrig"}; + static constexpr std::string_view kHPtEst[8] = { + "ptVsGlobaltrack", "ptVsFV0", + "ptVs1flatencityFV0", "ptVsFT0", + "ptVs1flatencityFT0", "ptVsFV0FT0C", + "ptVs1flatencityFV0FT0C", "pTVsPtTrig"}; + + // Configurable for histograms + Configurable nBinsVz{"nBinsVz", 100, "N bins in Vz"}; + Configurable nBinsK0sMass{"nBinsK0sMass", 400, "N bins in K0sMass"}; + Configurable nBinsLambdaMass{"nBinsLambdaMass", 400, + "N bins in LambdaMass"}; + Configurable nBinsXiMass{"nBinsXiMass", 400, "N bins in XiMass"}; + + Configurable kK0sEPshiftfromMass{"kK0sEPshiftfromMass", 0.1, "distance of K0s Inv mass histogram start and end points from PDG mass"}; + Configurable kLambdaEPshiftfromMass{"kLambdaEPshiftfromMass", 0.05, "distance of Lambda Inv mass histogram start and end points from PDG mass"}; + Configurable kXiEPshiftfromMass{"kXiEPshiftfromMass", 0.05, "distance of Xi Inv mass histogram start and end points from PDG mass"}; + + Configurable nBinspT{"nBinspT", 250, "N bins in pT"}; + Configurable nBinsFlattenicity{"nBinsFlattenicity", 100, "N bins in Flattenicity"}; + + // Configurable for event selection + + Configurable applyEvSel{"applyEvSel", true, + "Apply event selection to Data and MCRec"}; + Configurable issel8{"issel8", true, + "Accept events that pass sel8 selection"}; + Configurable cutzvertex{"cutzvertex", 10.0f, + "Accepted z-vertex range (cm)"}; + Configurable isINELgt0{"isINELgt0", true, "is INEL gt 0"}; + Configurable isNoTimeFrameBorder{"isNoTimeFrameBorder", true, + "cut branch crossing at the beginning/end of TF"}; + Configurable isNoITSROFrameBorder{"isNoITSROFrameBorder", true, + "cut branch crossing at the beginning/end of ITS ROF"}; + Configurable isVertexITSTPC{"isVertexITSTPC", false, + "Is Vertex ITSTPC"}; + Configurable isNoSameBunchPileup{"isNoSameBunchPileup", false, + "Is No Same Bunch Pileup"}; + Configurable isGoodZvtxFT0vsPV{"isGoodZvtxFT0vsPV", false, + "Is Good Zvtx FT0 vs PV"}; + Configurable isTriggerTVX{"isTriggerTVX", true, + "coincidence of a signal in FT0A and FT0C"}; + + // Configurables for Flattenicity + Configurable flattenicityQA{"flattenicityQA", true, "Store Flattenicity QA plots"}; + Configurable applyCalibCh{"applyCalibCh", false, "equalize FV0"}; + Configurable applyCalibVtx{"applyCalibVtx", false, + "equalize FV0 vs vtx"}; + Configurable applyNorm{"applyNorm", false, "normalization to eta"}; + Configurable isflattenicitywithFV0{"isflattenicitywithFV0", true, + "Calculate Flattenicity with FV0"}; + Configurable isflattenicitywithFT0{"isflattenicitywithFT0", true, + "Calculate Flattenicity with FT0"}; + Configurable isflattenicitywithFV0FT0C{"isflattenicitywithFV0FT0C", true, + "Calculate Flattenicity with FV0+FT0C"}; + + Configurable flattenicityforanalysis{"flattenicityforanalysis", 0, + "Which Flattenicity to be used for analysis, 0 for FV0, 1 for FT0, 2 for FV0+FT0C"}; + Configurable flattenicityforLossCorrRec{"flattenicityforLossCorrRec", true, + "Flattenicity from Rec Tracks are used for Signal and Event loss calculations"}; + // Common Configurable parameters for V0 selection + Configurable v0settingDCAv0dau{"v0settingDCAv0dau", 1, + "DCA V0 Daughters"}; + Configurable v0settingDCApostopv{"v0settingDCApostopv", 0.06, + "DCA Pos To PV"}; + Configurable v0settingDCAnegtopv{"v0settingDCAnegtopv", 0.06, + "DCA Neg To PV"}; + Configurable v0settingDCAbactopv{"v0settingDCAbactopv", 0.06, + "DCA Bchelor To PV"}; + Configurable v0settingRapidity{"v0settingRapidity", 0.5, + "V0 rapidity cut"}; + + // Configurable parameters for V0 selection for KOs + Configurable v0settingCosPAK0s{"v0settingCosPAK0s", 0.97, + "V0 CosPA for K0s"}; + Configurable v0settingRadiusK0s{"v0settingRadiusK0s", 0.5, + "v0radius for K0s"}; + Configurable v0settingcTauK0s{"v0settingcTauK0s", 20, + "v0ctau for K0s"}; + Configurable v0settingMassRejectionK0s{"v0settingMassRejectionK0s", 0.005, + "Competing Mass Rejection cut for K0s"}; + Configurable v0settingArmePodoK0s{"v0settingArmePodoK0s", 0.2, + "Armenteros-Podolanski cut for K0s"}; + + // Configurable parameters for V0 selection for Lambda + Configurable v0settingCosPALambda{"v0settingCosPALambda", 0.995, + "V0 CosPA for Lambda"}; + Configurable v0settingRadiusLambda{"v0settingRadiusLambda", 0.5, + "v0radius for Lambda"}; + Configurable v0settingcTauLambda{"v0settingcTauLambda", 30, + "v0ctau for Lambda"}; + Configurable v0settingMassRejectionLambda{"v0settingMassRejectionLambda", 0.01, + "Competing Mass Rejection cut for Lambda"}; + + // Configurable parameters for PID selection + Configurable nSigmaTPCPion{"nSigmaTPCPion", 5, "nSigmaTPCPion"}; + Configurable nSigmaTPCProton{"nSigmaTPCProton", 5, "nSigmaTPCProton"}; + Configurable nSigmaTPCKaon{"nSigmaTPCKaon", 5, "nSigmaTPCKaon"}; + + // Configurable v0daughter_etacut{"V0DaughterEtaCut", 0.8, + // "V0DaughterEtaCut"}; + // Configurable v0etacut{"v0etacut", 0.8, "v0etacut"}; + + // acceptance cuts for Flattenicity correlation + Configurable cfgTrkEtaCut{"cfgTrkEtaCut", 0.8f, + "Eta range for tracks"}; + Configurable cfgTrkLowPtCut{"cfgTrkLowPtCut", 0.0f, "Minimum pT"}; + + // Additional Cut configurables for Cascades + Configurable nTPCcrossedRows{"nTPCcrossedRows", 52, "Number of TPC crossed pad raws"}; + Configurable cascsettingDCAv0toPV{"cascsettingDCAv0toPV", 0.03, "DCA V0 To PV"}; + Configurable cascsettingDCAv0bach{"cascsettingDCAv0bach", 0.25, "DCA V0 To bachelor"}; + Configurable cascsettingDCAxybaryonbach{"cascsettingDCAxybaryonbach", 0.02, "DCA Baryon To bachelor"}; + Configurable cascsettingCosPAcascPV{"cascsettingCosPAcascPV", 0.9947, "CosThetap for Cascade to PV"}; + Configurable cascsettingCosPAv0PV{"cascsettingCosPAv0PV", 0.9876, "CosThetap for V0 to PV"}; + Configurable cascsettingv0radius{"cascsettingv0radius", 0.55, "V0 decay radius for cadcades in cm"}; + Configurable cascsettingcascradius{"cascsettingcascradius", 1.01, "Cascade decay radius for cadcades in cm"}; + Configurable cascsettingRapidity{"cascsettingRapidity", 0.5, "Cascade rapidity cut"}; + Configurable cascsettingMassRejectionLambdaXi{"cascsettingMassRejectionLambdaXi", 0.0116, "Casc Mass Rejection cut of Lambda for Xi"}; + Configurable cascsettingMassRejectioOmegaXi{"cascsettingMassRejectioOmegaXi", -1, "Casc Mass Rejection cut of Omega for Xi"}; + Configurable cascsettingproplifetime{"cascsettingproplifetime", 4.6, "Scale for lifetime cut on ctau Xi"}; + + int nbin = 1; + + void init(InitContext const&) + { + // Axes + AxisSpec k0sMassAxis = {nBinsK0sMass, 0.49f - kK0sEPshiftfromMass, 0.49f + kK0sEPshiftfromMass, + "#it{M}_{#pi^{+}#pi^{-}} [GeV/#it{c}^{2}]"}; + AxisSpec lambdaMassAxis = {nBinsLambdaMass, 1.115f - kLambdaEPshiftfromMass, 1.115f + kLambdaEPshiftfromMass, + "#it{M}_{p#pi^{-}} [GeV/#it{c}^{2}]"}; + AxisSpec antilambdaMassAxis = {nBinsLambdaMass, 1.115f - kLambdaEPshiftfromMass, 1.115f + kLambdaEPshiftfromMass, + "#it{M}_{#pi^{+}#bar{p}} [GeV/#it{c}^{2}]"}; + AxisSpec xiMassAxis = {nBinsXiMass, 1.32f - kXiEPshiftfromMass, 1.32f + kXiEPshiftfromMass, + "#it{M}_{#Lambda#pi} [GeV/#it{c}^{2}]"}; + AxisSpec vertexZAxis = {nBinsVz, -15., 15., "vrtx_{Z} [cm]"}; + AxisSpec ptAxis = {nBinspT, 0.0f, 25.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec flatAxis = {nBinsFlattenicity, 0.0f, 1.0f, "1-#rho_{ch}"}; + + int nBinsEst[8] = {100, 500, 102, 500, 102, 500, 102, 150}; + float lowEdgeEst[8] = {-0.5, -0.5, -0.01, -0.5, -0.01, -0.5, -0.01, .0}; + float upEdgeEst[8] = {99.5, 49999.5, 1.01, 499.5, 1.01, 499.5, 1.01, 150.0}; + + // Histograms + // Event selection + rEventSelection.add("hVertexZ", "hVertexZ", + {HistType::kTH1D, {vertexZAxis}}); + rEventSelection.add("hEventsSelected", "hEventsSelected", + {HistType::kTH1D, {{12, 0, 12}}}); + + rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "all"); + if (issel8) { + rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "sel8"); + } + + rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "zvertex"); + + if (isNoTimeFrameBorder) { + rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "TFBorder"); + } + if (isNoITSROFrameBorder) { + rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "ITSROFBorder"); + } + if (isVertexITSTPC) { + rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "VertexITSTPC"); + } + if (isNoSameBunchPileup) { + rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "SameBunchPileup"); + } + if (isGoodZvtxFT0vsPV) { + rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "isGoodZvtxFT0vsPV"); + } + if (isTriggerTVX) { + rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "TVX"); + } + if (isINELgt0) { + rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "INEL>0"); + } + + rEventSelection.add("hFlattenicityDistribution", "hFlattenicityDistribution", + {HistType::kTH1D, {flatAxis}}); + if (doprocessRecMCLambdaK0s || doprocessRecMCRun3Cascade) { + rEventSelection.add("hFlattenicityDistributionMCGen_Rec", "hFlattenicityDistributionMCGen_Rec", + {HistType::kTH1D, {flatAxis}}); + rEventSelection.add("hFlattenicity_Corr_Gen_vs_Rec", "hFlattenicity_Corr_Gen_vs_Rec", + {HistType::kTH2D, {flatAxis, flatAxis}}); + } + + if (doprocessDataRun3LambdaK0s || doprocessRecMCLambdaK0s) { + // K0s reconstruction + // Mass + rKzeroShort.add("hMassK0s", "hMassK0s", {HistType::kTH1D, {k0sMassAxis}}); + rKzeroShort.add("hMassK0sSelected", "hMassK0sSelected", + {HistType::kTH1D, {k0sMassAxis}}); + + // K0s topological/PID cuts + rKzeroShort.add("hrapidityK0s", "hrapidityK0s", + {HistType::kTH1D, {{40, -2.0f, 2.0f, "y"}}}); + rKzeroShort.add("hctauK0s", "hctauK0s", + {HistType::kTH1D, {{40, 0.0f, 40.0f, "c#tau (cm)"}}}); + rKzeroShort.add( + "h2DdecayRadiusK0s", "h2DdecayRadiusK0s", + {HistType::kTH1D, {{100, 0.0f, 1.0f, "Decay Radius (cm)"}}}); + rKzeroShort.add("hDCAV0DaughtersK0s", "hDCAV0DaughtersK0s", + {HistType::kTH1D, {{55, 0.0f, 2.2f, "DCA Daughters"}}}); + rKzeroShort.add("hV0CosPAK0s", "hV0CosPAK0s", + {HistType::kTH1D, {{100, 0.95f, 1.f, "CosPA"}}}); + rKzeroShort.add("hNSigmaPosPionFromK0s", "hNSigmaPosPionFromK0s", + {HistType::kTH2D, {{100, -5.f, 5.f}, {ptAxis}}}); + rKzeroShort.add("hNSigmaNegPionFromK0s", "hNSigmaNegPionFromK0s", + {HistType::kTH2D, {{100, -5.f, 5.f}, {ptAxis}}}); + rKzeroShort.add("hMassK0spT", "hMassK0spT", + {HistType::kTH2D, {{k0sMassAxis}, {ptAxis}}}); + rKzeroShort.add("hMassK0spTFlat", "hMassK0spTFlat", + {HistType::kTH3D, {{k0sMassAxis}, {ptAxis}, {flatAxis}}}); + rKzeroShort.add("hArmPodoAlphavsQTK0sAfterCut", "hArmPodoAlphavsQTK0sAfterCut", + {HistType::kTH2D, {{200, -1, 1, "#alpha"}, {70, 0, 0.35, "Q_{T}"}}}); + + if (doprocessRecMCLambdaK0s) { + rKzeroShort.add("Generated_MCRecoCollCheck_INEL_K0Short", "Generated_MCRecoCollCheck_INEL_K0Short", + {HistType::kTH2D, {{ptAxis}, {flatAxis}}}); + } + + // Lambda reconstruction Mass + rLambda.add("hMassLambda", "hMassLambda", + {HistType::kTH1D, {lambdaMassAxis}}); + rLambda.add("hMassLambdaSelected", "hMassLambdaSelected", + {HistType::kTH1D, {lambdaMassAxis}}); + + // Lambda topological/PID cuts + rLambda.add("hDCAV0DaughtersLambda", "hDCAV0DaughtersLambda", + {HistType::kTH1D, {{55, 0.0f, 2.2f, "DCA Daughters"}}}); + rLambda.add("hV0CosPALambda", "hV0CosPALambda", + {HistType::kTH1D, {{100, 0.95f, 1.f, "CosPA"}}}); + rLambda.add("hNSigmaPosPionFromLambda", "hNSigmaPosPionFromLambda", + {HistType::kTH2D, {{100, -5.f, 5.f}, {ptAxis}}}); + rLambda.add("hNSigmaNegPionFromLambda", "hNSigmaNegPionFromLambda", + {HistType::kTH2D, {{100, -5.f, 5.f}, {ptAxis}}}); + rLambda.add("hrapidityLambda", "hrapidityLambda", + {HistType::kTH1D, {{40, -2.0f, 2.0f, "y"}}}); + rLambda.add("hctauLambda", "hctauLambda", + {HistType::kTH1D, {{40, 0.0f, 40.0f, "c#tau (cm)"}}}); + rLambda.add("h2DdecayRadiusLambda", "h2DdecayRadiusLambda", + {HistType::kTH1D, {{100, 0.0f, 1.0f, "c#tau (cm)"}}}); + rLambda.add("hMassLambdapT", "hMassLambdapT", + {HistType::kTH2D, {{lambdaMassAxis}, {ptAxis}}}); + rLambda.add("hMassLambdapTFlat", "hMassLambdapTFlat", + {HistType::kTH3D, {{lambdaMassAxis}, {ptAxis}, {flatAxis}}}); + if (doprocessRecMCLambdaK0s) { + rLambda.add("Generated_MCRecoCollCheck_INEL_Lambda", "Generated_MCRecoCollCheck_INEL_Lambda", + {HistType::kTH2D, {{ptAxis}, {flatAxis}}}); + } + + // AntiLambda reconstruction + // Mass + rAntiLambda.add("hMassAntiLambda", "hMassAntiLambda", + {HistType::kTH1D, {antilambdaMassAxis}}); + rAntiLambda.add("hMassAntiLambdaSelected", "hMassAntiLambdaSelected", + {HistType::kTH1D, {antilambdaMassAxis}}); + + // AntiLambda topological/PID cuts + rAntiLambda.add("hDCAV0DaughtersAntiLambda", "hDCAV0DaughtersAntiLambda", + {HistType::kTH1D, {{55, 0.0f, 2.2f, "DCA Daughters"}}}); + rAntiLambda.add("hV0CosPAAntiLambda", "hV0CosPAAntiLambda", + {HistType::kTH1D, {{100, 0.95f, 1.f, "CosPA"}}}); + rAntiLambda.add("hNSigmaPosPionFromAntiLambda", + "hNSigmaPosPionFromAntiLambda", + {HistType::kTH2D, {{100, -5.f, 5.f}, {ptAxis}}}); + rAntiLambda.add("hNSigmaNegPionFromAntiLambda", + "hNSigmaNegPionFromAntiLambda", + {HistType::kTH2D, {{100, -5.f, 5.f}, {ptAxis}}}); + rAntiLambda.add("hrapidityAntiLambda", "hrapidityAntiLambda", + {HistType::kTH1D, {{40, -2.0f, 2.0f, "y"}}}); + rAntiLambda.add("hctauAntiLambda", "hctauAntiLambda", + {HistType::kTH1D, {{40, 0.0f, 40.0f, "c#tau (cm)"}}}); + rAntiLambda.add("h2DdecayRadiusAntiLambda", "h2DdecayRadiusAntiLambda", + {HistType::kTH1D, {{100, 0.0f, 1.0f, "c#tau (cm)"}}}); + rAntiLambda.add("hMassAntiLambdapT", "hMassAntiLambdapT", + {HistType::kTH2D, {{antilambdaMassAxis}, {ptAxis}}}); + rAntiLambda.add("hMassAntiLambdapTFlat", "hMassAntiLambdapTFlat", + {HistType::kTH3D, {{antilambdaMassAxis}, {ptAxis}, {flatAxis}}}); + if (doprocessRecMCLambdaK0s) { + rAntiLambda.add("Generated_MCRecoCollCheck_INEL_AntiLambda", "Generated_MCRecoCollCheck_INEL_AntiLambda", + {HistType::kTH2D, {{ptAxis}, {flatAxis}}}); + } + + rCommonHist.add("hArmPodoAlphavsQT", "hArmPodoAlphavsQT", + {HistType::kTH2D, {{200, -1, 1, "#alpha"}, {70, 0, 0.35, "Q_{T}"}}}); + } + + if (doprocessRecMCRun3Cascade || doprocessDataRun3Cascade) { + rXi.add("hMassXi", "hMassXi", {HistType::kTH1D, {xiMassAxis}}); + rXi.add("hMassXiSelected", "hMassXiSelected", + {HistType::kTH1D, {xiMassAxis}}); + + // Xi topological/PID cuts + rXi.add("hrapidityXi", "hrapidityXi", + {HistType::kTH1D, {{40, -2.0f, 2.0f, "y"}}}); + rXi.add("hctauXi", "hctauXi", + {HistType::kTH1D, {{40, 0.0f, 40.0f, "c#tau (cm)"}}}); + rXi.add( + "h2DdecayRadiusXi", "h2DdecayRadiusXi", + {HistType::kTH1D, {{100, 0.0f, 1.0f, "Decay Radius (cm)"}}}); + rXi.add("hDCAV0DaughtersXi", "hDCAV0DaughtersXi", + {HistType::kTH1D, {{55, 0.0f, 2.2f, "DCA Daughters"}}}); + rXi.add("hV0CosPAXi", "hV0CosPAXi", + {HistType::kTH1D, {{100, 0.95f, 1.f, "CosPA"}}}); + rXi.add("hNSigmaPosPionFromXi", "hNSigmaPosPionFromXi", + {HistType::kTH2D, {{100, -5.f, 5.f}, {ptAxis}}}); + rXi.add("hNSigmaNegPionFromXi", "hNSigmaNegPionFromXi", + {HistType::kTH2D, {{100, -5.f, 5.f}, {ptAxis}}}); + rXi.add("hMassXipT", "hMassXipT", + {HistType::kTH2D, {{xiMassAxis}, {ptAxis}}}); + rXi.add("hMassXipTFlat", "hMassXipTFlat", + {HistType::kTH3D, {{xiMassAxis}, {ptAxis}, {flatAxis}}}); + if (doprocessRecMCRun3Cascade) { + rXi.add("Generated_MCRecoCollCheck_INEL_Xi", "Generated_MCRecoCollCheck_INEL_Xi", + {HistType::kTH2D, {{ptAxis}, {flatAxis}}}); + } + } + if (doprocessGenMC) { + + rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin, "Applied selection"); + + rEventSelection.add("hVertexZGen", "hVertexZGen", + {HistType::kTH1D, {vertexZAxis}}); + + rEventSelection.add("hFlattenicityDistributionMCGen", "hFlattenicityDistributionMCGen", + {HistType::kTH1D, {flatAxis}}); + + rEventSelection.add("hFlattenicityDistributionRecMCGen", "hFlattenicityDistributionRecMCGen", + {HistType::kTH1D, {flatAxis}}); + + rEventSelection.add("hFlat_RecoColl_MC", "hFlat_RecoColl_MC", {HistType::kTH1D, {flatAxis}}); + rEventSelection.add("hFlat_RecoColl_MC_INELgt0", "hFlat_RecoColl_MC_INELgt0", {HistType::kTH1D, {flatAxis}}); + rEventSelection.add("hFlat_GenRecoColl_MC", "hFlat_GenRecoColl_MC", {HistType::kTH1D, {flatAxis}}); + rEventSelection.add("hFlat_GenRecoColl_MC_INELgt0", "hFlat_GenRecoColl_MC_INELgt0", {HistType::kTH1D, {flatAxis}}); + rEventSelection.add("hFlat_GenColl_MC", "hFlat_GenColl_MC", {HistType::kTH1D, {flatAxis}}); + rEventSelection.add("hFlat_GenColl_MC_INELgt0", "hFlat_GenColl_MC_INELgt0", {HistType::kTH1D, {flatAxis}}); + rEventSelection.add("hNEventsMCGen", "hNEventsMCGen", {HistType::kTH1D, {{4, 0.f, 4.f}}}); + rEventSelection.get(HIST("hNEventsMCGen"))->GetXaxis()->SetBinLabel(1, "all"); + rEventSelection.get(HIST("hNEventsMCGen"))->GetXaxis()->SetBinLabel(2, "zvertex_true"); + rEventSelection.get(HIST("hNEventsMCGen"))->GetXaxis()->SetBinLabel(3, "INELgt0_true"); + rEventSelection.add("hNEventsMCGenReco", "hNEventsMCGenReco", {HistType::kTH1D, {{2, 0.f, 2.f}}}); + rEventSelection.get(HIST("hNEventsMCGenReco"))->GetXaxis()->SetBinLabel(1, "INEL"); + rEventSelection.get(HIST("hNEventsMCGenReco"))->GetXaxis()->SetBinLabel(2, "INELgt0"); + rEventSelection.add("hNEventsMCReco", "hNEventsMCReco", {HistType::kTH1D, {{4, 0.f, 4.f}}}); + rEventSelection.get(HIST("hNEventsMCReco"))->GetXaxis()->SetBinLabel(1, "all"); + rEventSelection.get(HIST("hNEventsMCReco"))->GetXaxis()->SetBinLabel(2, "pass ev sel"); + rEventSelection.get(HIST("hNEventsMCReco"))->GetXaxis()->SetBinLabel(3, "INELgt0"); + rEventSelection.get(HIST("hNEventsMCReco"))->GetXaxis()->SetBinLabel(4, "check"); + rEventSelection.add("hTrueFV0amplvsFlat", "TrueFV0MvsFlat", HistType::kTH2D, + {{500, -0.5, +499.5, "True Nch in FV0 region"}, flatAxis}); + + rKzeroShort.add("pGen_MCGenRecoColl_INEL_K0Short", "pGen_MCGenRecoColl_INEL_K0Short", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rKzeroShort.add("Generated_MCRecoColl_INEL_K0Short", "Generated_MCRecoColl_INEL_K0Short", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rKzeroShort.add("pGen_MCGenColl_INEL_K0Short", "pGen_MCGenColl_INEL_K0Short", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rKzeroShort.add("pGen_MCGenRecoColl_INELgt0_K0Short", "pGen_MCGenRecoColl_INELgt0_K0Short", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rKzeroShort.add("Generated_MCRecoColl_INELgt0_K0Short", "Generated_MCRecoColl_INELgt0_K0Short", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rKzeroShort.add("Generated_MCRecoCollCheck_INELgt0_K0Short", "Generated_MCRecoCollCheck_INELgt0_K0Short", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rKzeroShort.add("pGen_MCGenColl_INELgt0_K0Short", "pGen_MCGenColl_INELgt0_K0Short", + {HistType::kTH2D, {ptAxis, flatAxis}}); + + rLambda.add("pGen_MCGenRecoColl_INEL_Lambda", "pGen_MCGenRecoColl_INEL_Lambda", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rLambda.add("Generated_MCRecoColl_INEL_Lambda", "Generated_MCRecoColl_INEL_Lambda", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rLambda.add("pGen_MCGenColl_INEL_Lambda", "pGen_MCGenColl_INEL_Lambda", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rLambda.add("pGen_MCGenRecoColl_INELgt0_Lambda", "pGen_MCGenRecoColl_INELgt0_Lambda", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rLambda.add("Generated_MCRecoColl_INELgt0_Lambda", "Generated_MCRecoColl_INELgt0_Lambda", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rLambda.add("Generated_MCRecoCollCheck_INELgt0_Lambda", "Generated_MCRecoCollCheck_INELgt0_Lambda", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rLambda.add("pGen_MCGenColl_INELgt0_Lambda", "pGen_MCGenColl_INELgt0_Lambda", + {HistType::kTH2D, {ptAxis, flatAxis}}); + + rAntiLambda.add("pGen_MCGenRecoColl_INEL_AntiLambda", "pGen_MCGenRecoColl_INEL_AntiLambda", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rAntiLambda.add("Generated_MCRecoColl_INEL_AntiLambda", "Generated_MCRecoColl_INEL_AntiLambda", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rAntiLambda.add("pGen_MCGenColl_INEL_AntiLambda", "pGen_MCGenColl_INEL_AntiLambda", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rAntiLambda.add("pGen_MCGenRecoColl_INELgt0_AntiLambda", "pGen_MCGenRecoColl_INELgt0_AntiLambda", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rAntiLambda.add("Generated_MCRecoColl_INELgt0_AntiLambda", "Generated_MCRecoColl_INELgt0_AntiLambda", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rAntiLambda.add("Generated_MCRecoCollCheck_INELgt0_AntiLambda", "Generated_MCRecoCollCheck_INELgt0_AntiLambda", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rAntiLambda.add("pGen_MCGenColl_INELgt0_AntiLambda", "pGen_MCGenColl_INELgt0_AntiLambda", + {HistType::kTH2D, {ptAxis, flatAxis}}); + + rXi.add("pGen_MCGenRecoColl_INEL_Xi", "pGen_MCGenRecoColl_INEL_Xi", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rXi.add("Generated_MCRecoColl_INEL_Xi", "Generated_MCRecoColl_INEL_Xi", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rXi.add("pGen_MCGenColl_INEL_Xi", "pGen_MCGenColl_INEL_Xi", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rXi.add("pGen_MCGenRecoColl_INELgt0_Xi", "pGen_MCGenRecoColl_INELgt0_Xi", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rXi.add("Generated_MCRecoColl_INELgt0_Xi", "Generated_MCRecoColl_INELgt0_Xi", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rXi.add("Generated_MCRecoCollCheck_INELgt0_Xi", "Generated_MCRecoCollCheck_INELgt0_Xi", + {HistType::kTH2D, {ptAxis, flatAxis}}); + rXi.add("pGen_MCGenColl_INELgt0_Xi", "pGen_MCGenColl_INELgt0_Xi", + {HistType::kTH2D, {ptAxis, flatAxis}}); + } + + if (flattenicityQA) { + rFlattenicity.add("hEv", "Ev", HistType::kTH1D, + {{6, -0.5, 5.5, "index activated detector"}}); + rFlattenicity.add("hFV0amplRing1to4", "FV01to4", HistType::kTH1D, + {{4000, -0.5, +49999.5, "FV0 amplitude"}}); + rFlattenicity.add("hFT0Aampl", "FTAampl", HistType::kTH1D, + {{50000, -0.5, +199999.5, "FT0A amplitude"}}); + rFlattenicity.add("hFT0Campl", "FTCampl", HistType::kTH1D, + {{10000, -0.5, +4999.5, "FT0C amplitude"}}); + rFlattenicity.add("hFT0C", "FT0C", HistType::kTH1D, + {{50000, -0.5, 199999.5, "FT0C amplitudes"}}); + rFlattenicity.add("hFT0A", "FT0A", HistType::kTH1D, + {{2000, -0.5, 1999.5, "FT0A amplitudes"}}); + rFlattenicity.add("hFV0amplvsFlat", "FV0MvsFlat", HistType::kTH2D, + {{4000, -0.5, +49999.5, "FV0 amplitude"}, flatAxis}); + + // estimators + for (int iEe = 0; iEe < 8; ++iEe) { + rFlattenicity.add( + kHEst[iEe].data(), "", HistType::kTH2D, + {{nBinsEst[iEe], lowEdgeEst[iEe], upEdgeEst[iEe], kTEst[iEe].data()}, + {100, -0.5, +99.5, "Global track"}}); + } + + // vs pT + for (int iEe = 0; iEe < 8; ++iEe) { + rFlattenicity.add( + kHPtEst[iEe].data(), "", HistType::kTProfile, + {{nBinsEst[iEe], lowEdgeEst[iEe], upEdgeEst[iEe], kTEst[iEe].data()}}); + } + + rFlattenicity.add("fMultFv0", "FV0 amp", HistType::kTH1D, + {{5000, -0.5, +199999.5, "FV0 amplitude"}}); + rFlattenicity.add( + "hAmpV0VsCh", "", HistType::kTH2D, + {{48, -0.5, 47.5, "channel"}, {500, -0.5, +19999.5, "FV0 amplitude"}}); + rFlattenicity.add( + "hAmpV0VsChBeforeCalibration", "", HistType::kTH2D, + {{48, -0.5, 47.5, "channel"}, {500, -0.5, +19999.5, "FV0 amplitude"}}); + + rFlattenicity.add( + "hAmpT0AVsChBeforeCalibration", "", HistType::kTH2D, + {{24, -0.5, 23.5, "channel"}, {600, -0.5, +5999.5, "FT0A amplitude"}}); + rFlattenicity.add( + "hAmpT0CVsChBeforeCalibration", "", HistType::kTH2D, + {{28, -0.5, 27.5, "channel"}, {600, -0.5, +5999.5, "FT0C amplitude"}}); + + rFlattenicity.add( + "hAmpT0AVsCh", "", HistType::kTH2D, + {{24, -0.5, 23.5, "channel"}, {600, -0.5, +5999.5, "FT0A amplitude"}}); + rFlattenicity.add( + "hAmpT0CVsCh", "", HistType::kTH2D, + {{28, -0.5, 27.5, "channel"}, {600, -0.5, +5999.5, "FT0C amplitude"}}); + + rFlattenicity.add("hFlatFT0CvsFlatFT0A", "", HistType::kTH2D, + {{20, -0.01, +1.01, "flatenicity (FT0C)"}, + {20, -0.01, +1.01, "flatenicity (FT0A)"}}); + rFlattenicity.add( + "fEtaPhiFv0", "eta vs phi", HistType::kTH2D, + {{8, 0.0, constants::math::TwoPI, "#phi (rad)"}, {5, 2.2, 5.1, "#eta"}}); + + rFlattenicity.add("hAmpV0vsVtxBeforeCalibration", "", HistType::kTH2D, + {{30, -15.0, +15.0, "Trk mult"}, + {1000, -0.5, +39999.5, "FV0 amplitude"}}); + rFlattenicity.add( + "hAmpT0AvsVtxBeforeCalibration", "", HistType::kTH2D, + {{30, -15.0, +15.0, "Vtx_z"}, {600, -0.5, +5999.5, "FT0A amplitude"}}); + rFlattenicity.add( + "hAmpT0CvsVtxBeforeCalibration", "", HistType::kTH2D, + {{30, -15.0, +15.0, "Vtx_z"}, {600, -0.5, +5999.5, "FT0C amplitude"}}); + + rFlattenicity.add("hAmpV0vsVtx", "", HistType::kTH2D, + {{30, -15.0, +15.0, "Trk mult"}, + {1000, -0.5, +39999.5, "FV0 amplitude"}}); + rFlattenicity.add( + "hAmpT0AvsVtx", "", HistType::kTH2D, + {{30, -15.0, +15.0, "Vtx_z"}, {600, -0.5, +5999.5, "FT0A amplitude"}}); + rFlattenicity.add( + "hAmpT0CvsVtx", "", HistType::kTH2D, + {{30, -15.0, +15.0, "Vtx_z"}, {600, -0.5, +5999.5, "FT0C amplitude"}}); + } + + if ((doprocessDataRun3LambdaK0s || doprocessRecMCLambdaK0s) && (doprocessDataRun3Cascade || doprocessRecMCRun3Cascade)) { + LOGF(fatal, "Can not run both LambdaK0s and Cascade process functions simulatenously. Try one at a time."); + } + + if ((doprocessDataRun3LambdaK0s || doprocessDataRun3Cascade) && doprocessGenMC) { + LOGF(fatal, "Can not run MCGen and Data process functions together. Try one of these at a time"); + } + } + + int getT0ASector(int iCh) + { + int iSecT0a = -1; + for (int iSec = 0; iSec < 24; ++iSec) { + if (iCh >= 4 * iSec && iCh <= 3 + 4 * iSec) { + iSecT0a = iSec; + break; + } + } + return iSecT0a; + } + + int getT0CSector(int iCh) + { + int iSecT0c = -1; + for (int iSec = 0; iSec < 28; ++iSec) { + if (iCh >= 4 * iSec && iCh <= 3 + 4 * iSec) { + iSecT0c = iSec; + break; + } + } + return iSecT0c; + } + + int getFV0Ring(int iCh) + { + int iRing = -1; + if (iCh < 8) { + iRing = 0; + } else if (iCh >= 8 && iCh < 16) { + iRing = 1; + } else if (iCh >= 16 && iCh < 24) { + iRing = 2; + } else if (iCh >= 24 && iCh < 32) { + iRing = 3; + } else { + iRing = 4; + } + return iRing; + } + + int getFV0IndexPhi(int iCh) + { + int iRing = -1; + + if (iCh >= 0 && iCh < 8) { + if (iCh < 4) { + iRing = iCh; + } else { + if (iCh == 7) { + iRing = 4; + } else if (iCh == 6) { + iRing = 5; + } else if (iCh == 5) { + iRing = 6; + } else if (iCh == 4) { + iRing = 7; + } + } + } else if (iCh >= 8 && iCh < 16) { + if (iCh < 12) { + iRing = iCh; + } else { + if (iCh == 15) { + iRing = 12; + } else if (iCh == 14) { + iRing = 13; + } else if (iCh == 13) { + iRing = 14; + } else if (iCh == 12) { + iRing = 15; + } + } + } else if (iCh >= 16 && iCh < 24) { + if (iCh < 20) { + iRing = iCh; + } else { + if (iCh == 23) { + iRing = 20; + } else if (iCh == 22) { + iRing = 21; + } else if (iCh == 21) { + iRing = 22; + } else if (iCh == 20) { + iRing = 23; + } + } + } else if (iCh >= 24 && iCh < 32) { + if (iCh < 28) { + iRing = iCh; + } else { + if (iCh == 31) { + iRing = 28; + } else if (iCh == 30) { + iRing = 29; + } else if (iCh == 29) { + iRing = 30; + } else if (iCh == 28) { + iRing = 31; + } + } + } else if (iCh == 32) { + iRing = 32; + } else if (iCh == 40) { + iRing = 33; + } else if (iCh == 33) { + iRing = 34; + } else if (iCh == 41) { + iRing = 35; + } else if (iCh == 34) { + iRing = 36; + } else if (iCh == 42) { + iRing = 37; + } else if (iCh == 35) { + iRing = 38; + } else if (iCh == 43) { + iRing = 39; + } else if (iCh == 47) { + iRing = 40; + } else if (iCh == 39) { + iRing = 41; + } else if (iCh == 46) { + iRing = 42; + } else if (iCh == 38) { + iRing = 43; + } else if (iCh == 45) { + iRing = 44; + } else if (iCh == 37) { + iRing = 45; + } else if (iCh == 44) { + iRing = 46; + } else if (iCh == 36) { + iRing = 47; + } + return iRing; + } + + float getFlatenicity(std::span signals) + { + int entries = signals.size(); + float flat = 9999; + float mRho = 0; + for (int iCell = 0; iCell < entries; ++iCell) { + mRho += 1.0 * signals[iCell]; + } + // average activity per cell + mRho /= (1.0 * entries); + // get sigma + float sRhoTmp = 0; + for (int iCell = 0; iCell < entries; ++iCell) { + sRhoTmp += std::pow(1.0 * signals[iCell] - mRho, 2); + } + sRhoTmp /= (1.0 * entries * entries); + float sRho = std::sqrt(sRhoTmp); + if (mRho > 0) { + flat = sRho / mRho; + } + return flat; + } + float pdgmassK0s = 0.497614; + float pdgmassLambda = 1.115683; + float pdgmassXi = 1.3217; + float pdgmassOmega = 1.67243; + // V0A signal and flatenicity calculation + static constexpr float kCalib[48] = { + 1.01697, 1.122, 1.03854, 1.108, 1.11634, 1.14971, 1.19321, + 1.06866, 0.954675, 0.952695, 0.969853, 0.957557, 0.989784, 1.01549, + 1.02182, 0.976005, 1.01865, 1.06871, 1.06264, 1.02969, 1.07378, + 1.06622, 1.15057, 1.0433, 0.83654, 0.847178, 0.890027, 0.920814, + 0.888271, 1.04662, 0.8869, 0.856348, 0.863181, 0.906312, 0.902166, + 1.00122, 1.03303, 0.887866, 0.892437, 0.906278, 0.884976, 0.864251, + 0.917221, 1.10618, 1.04028, 0.893184, 0.915734, 0.892676}; + // calibration T0C + static constexpr float kCalibT0C[28] = { + 0.949829, 1.05408, 1.00681, 1.00724, 0.990663, 0.973571, 0.9855, + 1.03726, 1.02526, 1.00467, 0.983008, 0.979349, 0.952352, 0.985775, + 1.013, 1.01721, 0.993948, 0.996421, 0.971871, 1.02921, 0.989641, + 1.01885, 1.01259, 0.929502, 1.03969, 1.02496, 1.01385, 1.01711}; + // calibration T0A + static constexpr float kCalibT0A[24] = { + 0.86041, 1.10607, 1.17724, 0.756397, 1.14954, 1.0879, + 0.829438, 1.09014, 1.16515, 0.730077, 1.06722, 0.906344, + 0.824167, 1.14716, 1.20692, 0.755034, 1.11734, 1.00556, + 0.790522, 1.09138, 1.16225, 0.692458, 1.12428, 1.01127}; + // calibration factor MFT vs vtx + static constexpr float kBiningVtxt[30] = { + -14.5, -13.5, -12.5, -11.5, -10.5, -9.5, -8.5, -7.5, -6.5, -5.5, + -4.5, -3.5, -2.5, -1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, + 5.5, 6.5, 7.5, 8.5, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5}; + + // calibration factor FV0 vs vtx + static constexpr float kCalibFV0vtx[30] = { + 0.907962, 0.934607, 0.938929, 0.950987, 0.950817, 0.966362, + 0.968509, 0.972741, 0.982412, 0.984872, 0.994543, 0.996003, + 0.99435, 1.00266, 0.998245, 1.00584, 1.01078, 1.01003, + 1.00726, 1.00872, 1.01726, 1.02015, 1.0193, 1.01106, + 1.02229, 1.02104, 1.03435, 1.00822, 1.01921, 1.01736}; + // calibration FT0A vs vtx + static constexpr float kCalibFT0Avtx[30] = { + 0.924334, 0.950988, 0.959604, 0.965607, 0.970016, 0.979057, + 0.978384, 0.982005, 0.992825, 0.990048, 0.998588, 0.997338, + 1.00102, 1.00385, 0.99492, 1.01083, 1.00703, 1.00494, + 1.00063, 1.0013, 1.00777, 1.01238, 1.01179, 1.00577, + 1.01028, 1.017, 1.02975, 1.0085, 1.00856, 1.01662}; + // calibration FT0C vs vtx + static constexpr float kCalibFT0Cvtx[30] = { + 1.02096, 1.01245, 1.02148, 1.03605, 1.03561, 1.03667, + 1.04229, 1.0327, 1.03674, 1.02764, 1.01828, 1.02331, + 1.01864, 1.015, 1.01197, 1.00615, 0.996845, 0.993051, + 0.985635, 0.982883, 0.981914, 0.964635, 0.967812, 0.95475, + 0.956687, 0.932816, 0.92773, 0.914892, 0.891724, 0.872382}; + + static constexpr int kNeta5 = 2; // FT0C + FT0A + static constexpr float kWeigthsEta5[kNeta5] = {0.0490638, 0.010958415}; + static constexpr float kDeltaEeta5[kNeta5] = {1.1, 1.2}; + + static constexpr int kNeta6 = 2; // FT0C + FV0 + static constexpr float kWeigthsEta6[kNeta6] = {0.0490638, 0.00353962}; + static constexpr float kDeltaEeta6[kNeta6] = {1.1, 2.9}; + + static constexpr int kInnerFV0 = 32; + static constexpr float kMaxEtaFV0 = 5.1; + static constexpr float kMinEtaFV0 = 2.2; + static constexpr float kDetaFV0 = (kMaxEtaFV0 - kMinEtaFV0) / 5.0; + + static constexpr int kNCells = 48; // 48 sectors in FV0 + std::array rhoLattice; + std::array rhoLatticeFV0AMC; + std::array ampchannel; + std::array ampchannelBefore; + static constexpr int kNCellsT0A = 24; + std::array rhoLatticeT0A; + static constexpr int kNCellsT0C = 28; + std::array rhoLatticeT0C; + + std::array estimator; + + template + bool isEventSelected(TCollision const& collision) + { + float nbinev = 0.5; + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + + if (issel8 && !collision.sel8()) { + return false; + } + if (issel8) { + nbinev++; + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } + + if (std::abs(collision.posZ()) > cutzvertex) { + return false; + } + + nbinev++; + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + + if (isNoTimeFrameBorder && + !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (isNoTimeFrameBorder) { + nbinev++; + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } + + if (isNoITSROFrameBorder && + !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if (isNoITSROFrameBorder) { + nbinev++; + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } + if (isVertexITSTPC && + !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (isVertexITSTPC) { + nbinev++; + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } + + if (isNoSameBunchPileup && + !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (isNoSameBunchPileup) { + nbinev++; + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } + + if (isGoodZvtxFT0vsPV && + !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (isGoodZvtxFT0vsPV) { + nbinev++; + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } + if (isTriggerTVX && + !collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + return false; + } + if (isTriggerTVX) { + nbinev++; + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } + + if (isINELgt0 && (collision.isInelGt0() == false)) { + return false; + } + if (isINELgt0) { + nbinev++; + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } + + return true; + } + + // ============== Flattenicity estimation begins ===================== // + template + float estimateFlattenicity(TCollision const& collision, Tracks const& tracks) + { + const int nDetVtx = 3; + TGraph* gVtx[nDetVtx]; + const char* nameDet[nDetVtx] = {"AmpV0", "AmpT0A", "AmpT0C"}; + + float ampl5[kNeta5] = {0, 0}; + float ampl6[kNeta6] = {0, 0}; + + for (int i_d = 0; i_d < nDetVtx; ++i_d) { + gVtx[i_d] = 0; + gVtx[i_d] = new TGraph(); + } + for (int i_v = 0; i_v < 30; ++i_v) { + gVtx[0]->SetPoint(i_v, kBiningVtxt[i_v], kCalibFV0vtx[i_v]); + } + for (int i_v = 0; i_v < 30; ++i_v) { + gVtx[1]->SetPoint(i_v, kBiningVtxt[i_v], kCalibFT0Avtx[i_v]); + } + for (int i_v = 0; i_v < 30; ++i_v) { + gVtx[2]->SetPoint(i_v, kBiningVtxt[i_v], kCalibFT0Cvtx[i_v]); + } + + for (int i_d = 0; i_d < nDetVtx; ++i_d) { + gVtx[i_d]->SetName(Form("g%s", nameDet[i_d])); + } + auto vtxZ = collision.posZ(); + + float sumAmpFV0 = 0; + float sumAmpFV01to4Ch = 0; + + ampchannel.fill(0.0); + ampchannelBefore.fill(0.0); + rhoLattice.fill(0); + + if ((isflattenicitywithFV0 || isflattenicitywithFV0FT0C) && + collision.has_foundFV0()) { + + auto fv0 = collision.foundFV0(); + for (std::size_t ich = 0; ich < fv0.amplitude().size(); ich++) { + float phiv0 = -999.0; + float etav0 = -999.0; + int channelv0 = fv0.channel()[ich]; + float amplCh = fv0.amplitude()[ich]; + int ringindex = getFV0Ring(channelv0); + int channelv0phi = getFV0IndexPhi(channelv0); + etav0 = kMaxEtaFV0 - (kDetaFV0 / 2.0) * (2.0 * ringindex + 1); + if (channelv0 < kInnerFV0) { + phiv0 = (2.0 * (channelv0phi - 8 * ringindex) + 1) * constants::math::PI / (8.0); + } else { + phiv0 = ((2.0 * channelv0phi) + 1 - 64.0) * constants::math::TwoPI / (32.0); + } + ampchannelBefore[channelv0phi] = amplCh; + if (applyCalibCh) { + amplCh *= kCalib[channelv0phi]; + } + sumAmpFV0 += amplCh; + + if (channelv0 >= 8) { // exclude the 1st ch, eta 2.2,4.52 + sumAmpFV01to4Ch += amplCh; + } + if (flattenicityQA) { + rFlattenicity.fill(HIST("fEtaPhiFv0"), phiv0, etav0, amplCh); + } + ampchannel[channelv0phi] = amplCh; + if (channelv0 < kInnerFV0) { + rhoLattice[channelv0phi] = amplCh; + } else { + rhoLattice[channelv0phi] = amplCh / 2.0; // two channels per bin + } + } + + if (flattenicityQA) { + rFlattenicity.fill(HIST("hAmpV0vsVtxBeforeCalibration"), vtxZ, sumAmpFV0); + } + if (applyCalibVtx) { + sumAmpFV0 *= gVtx[0]->Eval(vtxZ); + sumAmpFV01to4Ch *= gVtx[0]->Eval(vtxZ); + } + if (flattenicityQA) { + rFlattenicity.fill(HIST("hAmpV0vsVtx"), vtxZ, sumAmpFV0); + } + } + + float flattenicityfv0 = 9999; + if (isflattenicitywithFV0 || isflattenicitywithFV0FT0C) { + flattenicityfv0 = getFlatenicity({rhoLattice.data(), rhoLattice.size()}); + } + + // global tracks + float ptT = 0.; + int multGlob = 0; + for (const auto& track : tracks) { + if (!track.isGlobalTrack()) { + continue; + } + if (track.pt() > ptT) { + ptT = track.pt(); + } + multGlob++; + } + + // FT0 + float sumAmpFT0A = 0.f; + float sumAmpFT0C = 0.f; + + rhoLatticeT0A.fill(0); + rhoLatticeT0C.fill(0); + + if ((isflattenicitywithFT0 || isflattenicitywithFV0FT0C) && + collision.has_foundFT0()) { + auto ft0 = collision.foundFT0(); + if (isflattenicitywithFT0) { + for (std::size_t i_a = 0; i_a < ft0.amplitudeA().size(); i_a++) { + float amplitude = ft0.amplitudeA()[i_a]; + uint8_t channel = ft0.channelA()[i_a]; + int sector = getT0ASector(channel); + if (sector >= 0 && sector < 24) { + rhoLatticeT0A[sector] += amplitude; + if (flattenicityQA) { + rFlattenicity.fill(HIST("hAmpT0AVsChBeforeCalibration"), sector, + amplitude); + } + if (applyCalibCh) { + amplitude *= kCalibT0A[sector]; + } + if (flattenicityQA) { + rFlattenicity.fill(HIST("hAmpT0AVsCh"), sector, amplitude); + } + } + sumAmpFT0A += amplitude; + if (flattenicityQA) { + rFlattenicity.fill(HIST("hFT0A"), amplitude); + } + } + } + + for (std::size_t i_c = 0; i_c < ft0.amplitudeC().size(); i_c++) { + float amplitude = ft0.amplitudeC()[i_c]; + sumAmpFT0C += amplitude; + uint8_t channel = ft0.channelC()[i_c]; + int sector = getT0CSector(channel); + if (sector >= 0 && sector < 28) { + rhoLatticeT0C[sector] += amplitude; + if (flattenicityQA) { + rFlattenicity.fill(HIST("hAmpT0CVsChBeforeCalibration"), sector, + amplitude); + } + if (applyCalibCh) { + amplitude *= kCalibT0C[sector]; + } + if (flattenicityQA) { + rFlattenicity.fill(HIST("hAmpT0CVsCh"), sector, amplitude); + } + } + if (flattenicityQA) { + rFlattenicity.fill(HIST("hFT0C"), amplitude); + } + } + if (flattenicityQA) { + rFlattenicity.fill(HIST("hAmpT0AvsVtxBeforeCalibration"), vtxZ, + sumAmpFT0A); + rFlattenicity.fill(HIST("hAmpT0CvsVtxBeforeCalibration"), vtxZ, + sumAmpFT0C); + } + if (applyCalibVtx) { + sumAmpFT0A *= gVtx[1]->Eval(vtxZ); + sumAmpFT0C *= gVtx[2]->Eval(vtxZ); + } + if (flattenicityQA) { + rFlattenicity.fill(HIST("hAmpT0AvsVtx"), vtxZ, sumAmpFT0A); + rFlattenicity.fill(HIST("hAmpT0CvsVtx"), vtxZ, sumAmpFT0C); + } + } + float flatenicityT0a = 9999; + if (isflattenicitywithFT0) { + flatenicityT0a = + getFlatenicity({rhoLatticeT0A.data(), rhoLatticeT0A.size()}); + } + float flatenicityT0c = 9999; + if (isflattenicitywithFT0 || isflattenicitywithFV0FT0C) { + flatenicityT0c = + getFlatenicity({rhoLatticeT0C.data(), rhoLatticeT0C.size()}); + } + + bool isOKEstimator5 = false; + bool isOKEstimator6 = false; + float combinedEstimator5 = 0; + float combinedEstimator6 = 0; + + for (int iEe = 0; iEe < 8; ++iEe) { + estimator[iEe] = 0; + } + + if (collision.has_foundFV0() && collision.has_foundFT0()) { + float allWeights = 0; + // option 5 + ampl5[0] = sumAmpFT0C; + ampl5[1] = sumAmpFT0A; + if (sumAmpFT0C > 0 && sumAmpFT0A > 0) { + isOKEstimator5 = true; + } + if (isOKEstimator5) { + if (applyNorm) { + allWeights = 0; + for (int i5 = 0; i5 < kNeta5; ++i5) { + combinedEstimator5 += + ampl5[i5] * kWeigthsEta5[i5] / kDeltaEeta5[i5]; + allWeights += kWeigthsEta5[i5]; + } + combinedEstimator5 /= allWeights; + } else { + for (int i5 = 0; i5 < kNeta5; ++i5) { + combinedEstimator5 += ampl5[i5] * kWeigthsEta5[i5]; + } + } + } + // option 6: FT0C + FV0 + ampl6[0] = sumAmpFT0C; + ampl6[1] = sumAmpFV0; + if (sumAmpFT0C > 0 && sumAmpFV0 > 0) { + isOKEstimator6 = true; + } + if (isOKEstimator6) { + if (applyNorm) { + allWeights = 0; + for (int i6 = 0; i6 < kNeta6; ++i6) { + combinedEstimator6 += + ampl6[i6] * kWeigthsEta6[i6] / kDeltaEeta6[i6]; + allWeights += kWeigthsEta6[i6]; + } + combinedEstimator6 /= allWeights; + } else { + for (int i6 = 0; i6 < kNeta6; ++i6) { + combinedEstimator6 += ampl6[i6] * kWeigthsEta6[i6]; + } + } + } + if (flattenicityQA) { + rFlattenicity.fill(HIST("hFT0Aampl"), sumAmpFT0A); + rFlattenicity.fill(HIST("hFT0Campl"), sumAmpFT0C); + rFlattenicity.fill(HIST("hFV0amplRing1to4"), sumAmpFV01to4Ch); + rFlattenicity.fill(HIST("hEv"), 4); + } + estimator[0] = multGlob; + estimator[1] = sumAmpFV0; + estimator[2] = 1.0 - flattenicityfv0; + estimator[3] = combinedEstimator5; + float flatenicityFT0 = (flatenicityT0a + flatenicityT0c) / 2.0; + estimator[4] = 1.0 - flatenicityFT0; + estimator[5] = combinedEstimator6; + float flatenicityFT0v0 = 0.5 * flattenicityfv0 + 0.5 * flatenicityT0c; + estimator[6] = 1.0 - flatenicityFT0v0; + estimator[7] = ptT; + if (flattenicityQA) { + rFlattenicity.fill(HIST(kHEst[0]), estimator[0], estimator[0]); + rFlattenicity.fill(HIST(kHEst[1]), estimator[1], estimator[0]); + rFlattenicity.fill(HIST(kHEst[2]), estimator[2], estimator[0]); + rFlattenicity.fill(HIST(kHEst[3]), estimator[3], estimator[0]); + rFlattenicity.fill(HIST(kHEst[4]), estimator[4], estimator[0]); + rFlattenicity.fill(HIST(kHEst[5]), estimator[5], estimator[0]); + rFlattenicity.fill(HIST(kHEst[6]), estimator[6], estimator[0]); + rFlattenicity.fill(HIST(kHEst[7]), estimator[7], estimator[0]); + + // plot pt vs estimators + for (const auto& track : tracks) { + if (!track.isGlobalTrack()) { + continue; + } + float pt = track.pt(); + rFlattenicity.fill(HIST(kHPtEst[0]), estimator[0], pt); + rFlattenicity.fill(HIST(kHPtEst[1]), estimator[1], pt); + rFlattenicity.fill(HIST(kHPtEst[2]), estimator[2], pt); + rFlattenicity.fill(HIST(kHPtEst[3]), estimator[3], pt); + rFlattenicity.fill(HIST(kHPtEst[4]), estimator[4], pt); + rFlattenicity.fill(HIST(kHPtEst[5]), estimator[5], pt); + rFlattenicity.fill(HIST(kHPtEst[6]), estimator[6], pt); + rFlattenicity.fill(HIST(kHPtEst[7]), estimator[7], pt); + } + + if (isflattenicitywithFV0) { + for (int iCh = 0; iCh < 48; ++iCh) { + rFlattenicity.fill(HIST("hAmpV0VsCh"), iCh, ampchannel[iCh]); + rFlattenicity.fill(HIST("hAmpV0VsChBeforeCalibration"), iCh, + ampchannelBefore[iCh]); + } + } + + rFlattenicity.fill(HIST("fMultFv0"), sumAmpFV0); + rFlattenicity.fill(HIST("hFlatFT0CvsFlatFT0A"), flatenicityT0c, + flatenicityT0a); + } + } + float finalflattenicity = estimator[2]; + rFlattenicity.fill(HIST("hFV0amplvsFlat"), sumAmpFV0, estimator[2]); + + if (flattenicityforanalysis == 1) { + finalflattenicity = estimator[4]; + } + if (flattenicityforanalysis == 2) { + finalflattenicity = estimator[6]; + } + return finalflattenicity; + } + + template + float estimateFlattenicityFV0MC(McParticles const& mcParticles) + { + rhoLatticeFV0AMC.fill(0); + float flattenicity = -1; + float etamin, etamax, minphi, maxphi, dphi; + int isegment = 0, nsectors; + int multFV0 = 0; + + for (const auto& mcParticle : mcParticles) { + if (!(mcParticle.isPhysicalPrimary() && mcParticle.pt() > 0)) { + continue; + } + + auto pdgParticle = pdg->GetParticle(mcParticle.pdgCode()); + if (!(pdgParticle && pdgParticle->Charge() > 0.01)) { + continue; + } + + float etap = mcParticle.eta(); + float phip = mcParticle.phi(); + isegment = 0; + + for (int ieta = 0; ieta < 5; ieta++) { + etamax = kMaxEtaFV0 - ieta * kDetaFV0; + if (ieta == 0) { + etamax = kMaxEtaFV0; + } + etamin = kMaxEtaFV0 - (ieta + 1) * kDetaFV0; + if (ieta == 4) { + etamin = kMinEtaFV0; + } + nsectors = 8; + if (ieta == 4) { + nsectors = 16; + } + for (int iphi = 0; iphi < nsectors; iphi++) { + minphi = iphi * constants::math::TwoPI / nsectors; + maxphi = (iphi + 1) * constants::math::TwoPI / nsectors; + dphi = std::abs(maxphi - minphi); + if (etap >= etamin && etap < etamax && phip >= minphi && phip < maxphi) { + rhoLatticeFV0AMC[isegment] += 1.0 / std::abs(dphi * kDetaFV0); + multFV0++; + } + isegment++; + } + } + } + + flattenicity = + 1.0 - getFlatenicity({rhoLatticeFV0AMC.data(), rhoLatticeFV0AMC.size()}); + rEventSelection.fill(HIST("hTrueFV0amplvsFlat"), multFV0, estimator[2]); + return flattenicity; + } + // ====================== Flattenicity estimation ends ===================== + + // Filters on V0s + // Cannot filter on dynamic columns, so we cut on DCA to PV and DCA between + // daughters only + Filter preFilterV0 = (nabs(aod::v0data::dcapostopv) > v0settingDCApostopv && + nabs(aod::v0data::dcanegtopv) > v0settingDCAnegtopv && + aod::v0data::dcaV0daughters < v0settingDCAv0dau); + + Filter trackFilter = + (nabs(aod::track::eta) < cfgTrkEtaCut && aod::track::pt > cfgTrkLowPtCut); + + using TrackCandidates = soa::Filtered< + soa::Join>; + + void processDataRun3LambdaK0s( + soa::Join::iterator const& collision, + soa::Filtered const& V0s, TrackCandidates const& tracks, + soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0s*/) + { + if (applyEvSel && + !(isEventSelected(collision))) { // Checking if the event passes the + // selection criteria + return; + } + + auto vtxZ = collision.posZ(); + auto vtxY = collision.posY(); + auto vtxX = collision.posX(); + + float flattenicity = estimateFlattenicity(collision, tracks); + + rEventSelection.fill(HIST("hVertexZ"), vtxZ); + rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + + for (const auto& v0 : V0s) { + const auto& posDaughterTrack = v0.posTrack_as(); + const auto& negDaughterTrack = v0.negTrack_as(); + + if (std::abs(posDaughterTrack.eta()) > cfgTrkEtaCut || + std::abs(negDaughterTrack.eta()) > cfgTrkEtaCut || + negDaughterTrack.pt() < cfgTrkLowPtCut || + posDaughterTrack.pt() < cfgTrkLowPtCut) { + continue; + } + float massK0s = v0.mK0Short(); + float massLambda = v0.mLambda(); + float massAntiLambda = v0.mAntiLambda(); + + rKzeroShort.fill(HIST("hMassK0s"), massK0s); + rLambda.fill(HIST("hMassLambda"), massLambda); + rAntiLambda.fill(HIST("hMassAntiLambda"), massAntiLambda); + + float decayvtxX = v0.x(); + float decayvtxY = v0.y(); + float decayvtxZ = v0.z(); + + float decaylength = std::sqrt(std::pow(decayvtxX - vtxX, 2) + + std::pow(decayvtxY - vtxY, 2) + + std::pow(decayvtxZ - vtxZ, 2)); + float v0p = std::sqrt(v0.pt() * v0.pt() + v0.pz() * v0.pz()); + + float ctauK0s = decaylength * massK0s / v0p; + float ctauLambda = decaylength * massLambda / v0p; + float ctauAntiLambda = decaylength * massAntiLambda / v0p; + + float alpha = v0.alpha(); + float qtarm = v0.qtarm(); + + // Cut on dynamic columns for K0s + rCommonHist.fill(HIST("hArmPodoAlphavsQT"), alpha, qtarm); + + if (v0.v0cosPA() >= v0settingCosPAK0s && + v0.v0radius() >= v0settingRadiusK0s && + std::abs(posDaughterTrack.tpcNSigmaPi()) <= nSigmaTPCPion && + std::abs(negDaughterTrack.tpcNSigmaPi()) <= nSigmaTPCPion && + ctauK0s < v0settingcTauK0s && + std::abs(v0.rapidity(0)) <= v0settingRapidity && + std::abs(massLambda - pdgmassLambda) > v0settingMassRejectionK0s && + std::abs(massAntiLambda - pdgmassLambda) > + v0settingMassRejectionK0s && + qtarm > v0settingArmePodoK0s * std::abs(alpha)) { + + rKzeroShort.fill(HIST("hMassK0sSelected"), massK0s); + rKzeroShort.fill(HIST("hDCAV0DaughtersK0s"), v0.dcaV0daughters()); + rKzeroShort.fill(HIST("hV0CosPAK0s"), v0.v0cosPA()); + rKzeroShort.fill(HIST("hrapidityK0s"), v0.rapidity(0)); + rKzeroShort.fill(HIST("hctauK0s"), ctauK0s); + rKzeroShort.fill(HIST("h2DdecayRadiusK0s"), v0.v0radius()); + rKzeroShort.fill(HIST("hMassK0spT"), massK0s, v0.pt()); + rKzeroShort.fill(HIST("hMassK0spTFlat"), massK0s, v0.pt(), flattenicity); + rKzeroShort.fill(HIST("hArmPodoAlphavsQTK0sAfterCut"), alpha, qtarm); + + // Filling the PID of the V0 daughters in the region of the K0s peak + if (0.45 < massK0s && massK0s < 0.55) { + rKzeroShort.fill(HIST("hNSigmaPosPionFromK0s"), + posDaughterTrack.tpcNSigmaPi(), + posDaughterTrack.tpcInnerParam()); + rKzeroShort.fill(HIST("hNSigmaNegPionFromK0s"), + negDaughterTrack.tpcNSigmaPi(), + negDaughterTrack.tpcInnerParam()); + } + } + + // Cut on dynamic columns for Lambda + if (v0.v0cosPA() >= v0settingCosPALambda && + v0.v0radius() >= v0settingRadiusLambda && + std::abs(posDaughterTrack.tpcNSigmaPr()) <= nSigmaTPCProton && + std::abs(negDaughterTrack.tpcNSigmaPi()) <= nSigmaTPCPion && + ctauLambda < v0settingcTauLambda && + std::abs(v0.rapidity(1)) <= v0settingRapidity && + std::abs(massK0s - pdgmassK0s) > v0settingMassRejectionLambda) { + + rLambda.fill(HIST("hMassLambdaSelected"), massLambda); + rLambda.fill(HIST("hDCAV0DaughtersLambda"), v0.dcaV0daughters()); + rLambda.fill(HIST("hV0CosPALambda"), v0.v0cosPA()); + rLambda.fill(HIST("hrapidityLambda"), v0.rapidity(1)); + rLambda.fill(HIST("hctauLambda"), ctauLambda); + rLambda.fill(HIST("h2DdecayRadiusLambda"), v0.v0radius()); + rLambda.fill(HIST("hMassLambdapT"), massLambda, v0.pt()); + rLambda.fill(HIST("hMassLambdapTFlat"), massLambda, v0.pt(), flattenicity); + + // Filling the PID of the V0 daughters in the region of the Lambda peak + if (1.015 < massLambda && massLambda < 1.215) { + rLambda.fill(HIST("hNSigmaPosPionFromLambda"), + posDaughterTrack.tpcNSigmaPr(), + posDaughterTrack.tpcInnerParam()); + rLambda.fill(HIST("hNSigmaNegPionFromLambda"), + negDaughterTrack.tpcNSigmaPi(), + negDaughterTrack.tpcInnerParam()); + } + } + + // Cut on dynamic columns for AntiLambda + if (v0.v0cosPA() >= v0settingCosPALambda && + v0.v0radius() >= v0settingRadiusLambda && + std::abs(posDaughterTrack.tpcNSigmaPi()) <= nSigmaTPCPion && + std::abs(negDaughterTrack.tpcNSigmaPr()) <= nSigmaTPCProton && + ctauAntiLambda < v0settingcTauLambda && + std::abs(v0.rapidity(2)) <= v0settingRapidity && + std::abs(massK0s - pdgmassK0s) > v0settingMassRejectionLambda) { + + rAntiLambda.fill(HIST("hMassAntiLambdaSelected"), massAntiLambda); + rAntiLambda.fill(HIST("hDCAV0DaughtersAntiLambda"), + v0.dcaV0daughters()); + rAntiLambda.fill(HIST("hV0CosPAAntiLambda"), v0.v0cosPA()); + rAntiLambda.fill(HIST("hrapidityAntiLambda"), v0.rapidity(2)); + rAntiLambda.fill(HIST("hctauAntiLambda"), ctauAntiLambda); + rAntiLambda.fill(HIST("h2DdecayRadiusAntiLambda"), v0.v0radius()); + rAntiLambda.fill(HIST("hMassAntiLambdapT"), massAntiLambda, v0.pt()); + + rAntiLambda.fill(HIST("hMassAntiLambdapTFlat"), massAntiLambda, v0.pt(), flattenicity); + // Filling the PID of the V0 daughters in the region of the AntiLambda + // peak + if (1.015 < massAntiLambda && massAntiLambda < 1.215) { + rAntiLambda.fill(HIST("hNSigmaPosPionFromAntiLambda"), + posDaughterTrack.tpcNSigmaPi(), + posDaughterTrack.tpcInnerParam()); + rAntiLambda.fill(HIST("hNSigmaNegPionFromAntiLambda"), + negDaughterTrack.tpcNSigmaPr(), + negDaughterTrack.tpcInnerParam()); + } + } + } + } + + using TrackCandidatesMC = + soa::Filtered>; + + Preslice>> perCol = aod::track::collisionId; + Preslice perMCCol = aod::mcparticle::mcCollisionId; + SliceCache cache1; + + void processRecMCLambdaK0s( + soa::Join const& collisions, + soa::Filtered> const& V0s, aod::McCollisions const&, TrackCandidatesMC const& tracks, + soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0s*/, aod::McParticles const& mcParticles) + { + for (const auto& collision : collisions) { + if (applyEvSel && + !(isEventSelected(collision))) { // Checking if the event passes the + // selection criteria + continue; + } + + auto vtxZ = collision.posZ(); + auto vtxY = collision.posY(); + auto vtxX = collision.posX(); + + float flattenicity = estimateFlattenicity(collision, tracks); + + rEventSelection.fill(HIST("hVertexZ"), vtxZ); + rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + + auto v0sThisCollision = V0s.sliceBy(perCol, collision.globalIndex()); + const auto& mcCollision = collision.mcCollision_as(); + + for (const auto& v0 : v0sThisCollision) { + + const auto& posDaughterTrack = v0.posTrack_as(); + const auto& negDaughterTrack = v0.negTrack_as(); + + if (std::abs(posDaughterTrack.eta()) > cfgTrkEtaCut || + std::abs(negDaughterTrack.eta()) > cfgTrkEtaCut || + negDaughterTrack.pt() < cfgTrkLowPtCut || + posDaughterTrack.pt() < cfgTrkLowPtCut) { + continue; + } + + if (!v0.has_mcParticle()) { + continue; + } + + float massK0s = v0.mK0Short(); + float massLambda = v0.mLambda(); + float massAntiLambda = v0.mAntiLambda(); + + rKzeroShort.fill(HIST("hMassK0s"), massK0s); + rLambda.fill(HIST("hMassLambda"), massLambda); + rAntiLambda.fill(HIST("hMassAntiLambda"), massAntiLambda); + + float decayvtxX = v0.x(); + float decayvtxY = v0.y(); + float decayvtxZ = v0.z(); + + float decaylength = std::sqrt(std::pow(decayvtxX - vtxX, 2) + + std::pow(decayvtxY - vtxY, 2) + + std::pow(decayvtxZ - vtxZ, 2)); + float v0p = std::sqrt(v0.pt() * v0.pt() + v0.pz() * v0.pz()); + + float ctauK0s = decaylength * massK0s / v0p; + float ctauLambda = decaylength * massLambda / v0p; + float ctauAntiLambda = decaylength * massAntiLambda / v0p; + + float alpha = v0.alpha(); + float qtarm = v0.qtarm(); + rCommonHist.fill(HIST("hArmPodoAlphavsQT"), alpha, qtarm); + + auto v0mcParticle = v0.mcParticle(); + // Cut on dynamic columns for K0s + + if (v0mcParticle.pdgCode() == PDG_t::kK0Short && v0.v0cosPA() >= v0settingCosPAK0s && + v0.v0radius() >= v0settingRadiusK0s && + std::abs(posDaughterTrack.tpcNSigmaPi()) <= nSigmaTPCPion && + std::abs(negDaughterTrack.tpcNSigmaPi()) <= nSigmaTPCPion && + ctauK0s < v0settingcTauK0s && + std::abs(v0.rapidity(0)) <= v0settingRapidity && + std::abs(massLambda - pdgmassLambda) > v0settingMassRejectionK0s && + std::abs(massAntiLambda - pdgmassLambda) > + v0settingMassRejectionK0s && + qtarm > v0settingArmePodoK0s * std::abs(alpha)) { + + rKzeroShort.fill(HIST("hMassK0sSelected"), massK0s); + rKzeroShort.fill(HIST("hDCAV0DaughtersK0s"), v0.dcaV0daughters()); + rKzeroShort.fill(HIST("hV0CosPAK0s"), v0.v0cosPA()); + rKzeroShort.fill(HIST("hrapidityK0s"), v0.rapidity(0)); + rKzeroShort.fill(HIST("hctauK0s"), ctauK0s); + rKzeroShort.fill(HIST("h2DdecayRadiusK0s"), v0.v0radius()); + rKzeroShort.fill(HIST("hMassK0spT"), massK0s, v0.pt()); + rKzeroShort.fill(HIST("hMassK0spTFlat"), massK0s, v0.pt(), flattenicity); + rKzeroShort.fill(HIST("hArmPodoAlphavsQTK0sAfterCut"), alpha, qtarm); + + // Filling the PID of the V0 daughters in the region of the K0s peak + if (0.45 < massK0s && massK0s < 0.55) { + rKzeroShort.fill(HIST("hNSigmaPosPionFromK0s"), + posDaughterTrack.tpcNSigmaPi(), + posDaughterTrack.tpcInnerParam()); + rKzeroShort.fill(HIST("hNSigmaNegPionFromK0s"), + negDaughterTrack.tpcNSigmaPi(), + negDaughterTrack.tpcInnerParam()); + } + } + + // Cut on dynamic columns for Lambda + if (v0mcParticle.pdgCode() == PDG_t::kLambda0 && + v0.v0cosPA() >= v0settingCosPALambda && + v0.v0radius() >= v0settingRadiusLambda && + std::abs(posDaughterTrack.tpcNSigmaPr()) <= nSigmaTPCProton && + std::abs(negDaughterTrack.tpcNSigmaPi()) <= nSigmaTPCPion && + ctauLambda < v0settingcTauLambda && + std::abs(v0.rapidity(1)) <= v0settingRapidity && + std::abs(massK0s - pdgmassK0s) > v0settingMassRejectionLambda) { + + rLambda.fill(HIST("hMassLambdaSelected"), massLambda); + rLambda.fill(HIST("hDCAV0DaughtersLambda"), v0.dcaV0daughters()); + rLambda.fill(HIST("hV0CosPALambda"), v0.v0cosPA()); + rLambda.fill(HIST("hrapidityLambda"), v0.rapidity(1)); + rLambda.fill(HIST("hctauLambda"), ctauLambda); + rLambda.fill(HIST("h2DdecayRadiusLambda"), v0.v0radius()); + rLambda.fill(HIST("hMassLambdapT"), massLambda, v0.pt()); + rLambda.fill(HIST("hMassLambdapTFlat"), massLambda, v0.pt(), flattenicity); + + // Filling the PID of the V0 daughters in the region of the Lambda peak + if (1.015 < massLambda && massLambda < 1.215) { + rLambda.fill(HIST("hNSigmaPosPionFromLambda"), + posDaughterTrack.tpcNSigmaPr(), + posDaughterTrack.tpcInnerParam()); + rLambda.fill(HIST("hNSigmaNegPionFromLambda"), + negDaughterTrack.tpcNSigmaPi(), + negDaughterTrack.tpcInnerParam()); + } + } + + // Cut on dynamic columns for AntiLambda + if (v0mcParticle.pdgCode() == PDG_t::kLambda0Bar && + v0.v0cosPA() >= v0settingCosPALambda && + v0.v0radius() >= v0settingRadiusLambda && + std::abs(posDaughterTrack.tpcNSigmaPi()) <= nSigmaTPCPion && + std::abs(negDaughterTrack.tpcNSigmaPr()) <= nSigmaTPCProton && + ctauAntiLambda < v0settingcTauLambda && + std::abs(v0.rapidity(2)) <= v0settingRapidity && + std::abs(massK0s - pdgmassK0s) > v0settingMassRejectionLambda) { + + rAntiLambda.fill(HIST("hMassAntiLambdaSelected"), massAntiLambda); + rAntiLambda.fill(HIST("hDCAV0DaughtersAntiLambda"), + v0.dcaV0daughters()); + rAntiLambda.fill(HIST("hV0CosPAAntiLambda"), v0.v0cosPA()); + rAntiLambda.fill(HIST("hrapidityAntiLambda"), v0.rapidity(2)); + rAntiLambda.fill(HIST("hctauAntiLambda"), ctauAntiLambda); + rAntiLambda.fill(HIST("h2DdecayRadiusAntiLambda"), v0.v0radius()); + rAntiLambda.fill(HIST("hMassAntiLambdapT"), massAntiLambda, v0.pt()); + rAntiLambda.fill(HIST("hMassAntiLambdapTFlat"), massAntiLambda, v0.pt(), flattenicity); + + // Filling the PID of the V0 daughters in the region of the AntiLambda + // peak + if (1.015 < massAntiLambda && massAntiLambda < 1.215) { + rAntiLambda.fill(HIST("hNSigmaPosPionFromAntiLambda"), + posDaughterTrack.tpcNSigmaPi(), + posDaughterTrack.tpcInnerParam()); + rAntiLambda.fill(HIST("hNSigmaNegPionFromAntiLambda"), + negDaughterTrack.tpcNSigmaPr(), + negDaughterTrack.tpcInnerParam()); + } + } + } + + const auto particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache1); + float flattenicityMCGen = estimateFlattenicityFV0MC(particlesInCollision); + rEventSelection.fill(HIST("hFlattenicityDistributionMCGen_Rec"), flattenicityMCGen); + rEventSelection.fill(HIST("hFlattenicity_Corr_Gen_vs_Rec"), flattenicityMCGen, flattenicity); + + for (const auto& mcParticle : particlesInCollision) { + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + + if (std::abs(mcParticle.y()) > 0.5f) { + continue; + } + + if (mcParticle.pdgCode() == PDG_t::kK0Short) { + rKzeroShort.fill(HIST("Generated_MCRecoCollCheck_INEL_K0Short"), mcParticle.pt(), flattenicity); // K0s + } + if (mcParticle.pdgCode() == PDG_t::kLambda0) { + rLambda.fill(HIST("Generated_MCRecoCollCheck_INEL_Lambda"), mcParticle.pt(), flattenicity); // Lambda + } + if (mcParticle.pdgCode() == PDG_t::kLambda0Bar) { + rAntiLambda.fill(HIST("Generated_MCRecoCollCheck_INEL_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + } + } + } + } + + // Filter posZFilterMC = (nabs(o2::aod::mccollision::posZ) < cutzvertex); + void processGenMC( + o2::aod::McCollision const& mcCollision, const soa::SmallGroups>& collisions, TrackCandidatesMC const& tracks, aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0s*/, o2::aod::McParticles const& mcParticles) + { + + float flattenicity; + if (flattenicityforLossCorrRec) { + float flattenicityRec = 999.0; + for (const auto& collision : collisions) { + flattenicityRec = estimateFlattenicity(collision, tracks); + // printf("FoundFlattenicity, Gen=%f, Rec=%f \n", flattenicity, flattenicityRec); + } + rEventSelection.fill(HIST("hFlattenicityDistributionRecMCGen"), flattenicityRec); + flattenicity = flattenicityRec; + } else { + float flattenicityGen = estimateFlattenicityFV0MC(mcParticles); + rEventSelection.fill(HIST("hFlattenicityDistributionMCGen"), flattenicityGen); + flattenicity = flattenicityGen; + } + + //==================================== + //===== Event Loss Denominator ======= + //==================================== + + rEventSelection.fill(HIST("hNEventsMCGen"), 0.5); + + if (std::abs(mcCollision.posZ()) > cutzvertex) { + return; + } + rEventSelection.fill(HIST("hNEventsMCGen"), 1.5); + rEventSelection.fill(HIST("hFlat_GenColl_MC"), flattenicity); + + bool isINELgt0true = false; + + if (pwglf::isINELgtNmc(mcParticles, 0, pdg)) { + isINELgt0true = true; + rEventSelection.fill(HIST("hNEventsMCGen"), 2.5); + rEventSelection.fill(HIST("hFlat_GenColl_MC_INELgt0"), flattenicity); + } + + //===================================== + //===== Signal Loss Denominator ======= + //===================================== + + for (const auto& mcParticle : mcParticles) { + + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + if (std::abs(mcParticle.y()) > 0.5f) { + continue; + } + + if (mcParticle.pdgCode() == PDG_t::kK0Short) { + rKzeroShort.fill(HIST("pGen_MCGenColl_INEL_K0Short"), mcParticle.pt(), flattenicity); // K0s + if (isINELgt0true) { + rKzeroShort.fill(HIST("pGen_MCGenColl_INELgt0_K0Short"), mcParticle.pt(), flattenicity); // K0s + } + } + if (mcParticle.pdgCode() == PDG_t::kLambda0) { + rLambda.fill(HIST("pGen_MCGenColl_INEL_Lambda"), mcParticle.pt(), flattenicity); // Lambda + if (isINELgt0true) { + rLambda.fill(HIST("pGen_MCGenColl_INELgt0_Lambda"), mcParticle.pt(), flattenicity); // Lambda + } + } + if (mcParticle.pdgCode() == PDG_t::kLambda0Bar) { + rAntiLambda.fill(HIST("pGen_MCGenColl_INEL_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + if (isINELgt0true) { + rAntiLambda.fill(HIST("pGen_MCGenColl_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + } + } + if (std::abs(mcParticle.pdgCode()) == PDG_t::kXiPlusBar) { + rXi.fill(HIST("pGen_MCGenColl_INEL_Xi"), mcParticle.pt(), flattenicity); // Xi + if (isINELgt0true) { + rXi.fill(HIST("pGen_MCGenColl_INELgt0_Xi"), mcParticle.pt(), flattenicity); // Xi + } + } + } + + int recoCollIndexINEL = 0; + int recoCollIndexINELgt0 = 0; + for (const auto& collision : collisions) { // loop on reconstructed collisions + + //===================================== + //====== Event Split Numerator ======== + //===================================== + + rEventSelection.fill(HIST("hNEventsMCReco"), 0.5); + if (applyEvSel && !isEventSelected(collision)) { + continue; + } + rEventSelection.fill(HIST("hEventsSelected"), nbin - 0.5); + rEventSelection.fill(HIST("hNEventsMCReco"), 1.5); + rEventSelection.fill(HIST("hFlat_RecoColl_MC"), flattenicity); + + recoCollIndexINEL++; + + if (collision.isInelGt0() && isINELgt0true) { + rEventSelection.fill(HIST("hNEventsMCReco"), 2.5); + rEventSelection.fill(HIST("hFlat_RecoColl_MC_INELgt0"), flattenicity); + + recoCollIndexINELgt0++; + } + + //===================================== + //======== Sgn Split Numerator ======== + //===================================== + + for (const auto& mcParticle : mcParticles) { + + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + + if (std::abs(mcParticle.y()) > 0.5f) { + continue; + } + + if (mcParticle.pdgCode() == PDG_t::kK0Short) { + rKzeroShort.fill(HIST("Generated_MCRecoColl_INEL_K0Short"), mcParticle.pt(), flattenicity); // K0s + if (recoCollIndexINELgt0 > 0) { + rKzeroShort.fill(HIST("Generated_MCRecoColl_INELgt0_K0Short"), mcParticle.pt(), flattenicity); // K0s + } + } + if (mcParticle.pdgCode() == PDG_t::kLambda0) { + rLambda.fill(HIST("Generated_MCRecoColl_INEL_Lambda"), mcParticle.pt(), flattenicity); // Lambda + if (recoCollIndexINELgt0 > 0) { + rLambda.fill(HIST("Generated_MCRecoColl_INELgt0_Lambda"), mcParticle.pt(), flattenicity); // Lambda + } + } + if (mcParticle.pdgCode() == PDG_t::kLambda0Bar) { + rAntiLambda.fill(HIST("Generated_MCRecoColl_INEL_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + if (recoCollIndexINELgt0 > 0) { + rAntiLambda.fill(HIST("Generated_MCRecoColl_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + } + } + if (std::abs(mcParticle.pdgCode()) == PDG_t::kXiPlusBar) { + rXi.fill(HIST("Generated_MCRecoColl_INEL_Xi"), mcParticle.pt(), flattenicity); // Xi + if (recoCollIndexINELgt0 > 0) { + rXi.fill(HIST("Generated_MCRecoColl_INELgt0_Xi"), mcParticle.pt(), flattenicity); // Xi + } + } + } + } + + // From now on keep only mc collisions with at least one reconstructed collision (INEL) + if (recoCollIndexINEL < 1) { + return; + } + + //===================================== + //====== Event Loss Numerator ========= + //===================================== + + rEventSelection.fill(HIST("hNEventsMCGenReco"), 0.5); + rEventSelection.fill(HIST("hFlat_GenRecoColl_MC"), flattenicity); + + if (recoCollIndexINELgt0 > 0) { + rEventSelection.fill(HIST("hNEventsMCGenReco"), 1.5); + rEventSelection.fill(HIST("hFlat_GenRecoColl_MC_INELgt0"), flattenicity); + } + + //===================================== + //===== Signal Loss Numerator ========= + //===================================== + + for (const auto& mcParticle : mcParticles) { + + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + + if (std::abs(mcParticle.y()) > 0.5f) { + continue; + } + + if (mcParticle.pdgCode() == PDG_t::kK0Short) { + rKzeroShort.fill(HIST("pGen_MCGenRecoColl_INEL_K0Short"), mcParticle.pt(), flattenicity); // K0s + if (recoCollIndexINELgt0 > 0) { + rKzeroShort.fill(HIST("pGen_MCGenRecoColl_INELgt0_K0Short"), mcParticle.pt(), flattenicity); // K0s + } + } + if (mcParticle.pdgCode() == PDG_t::kLambda0) { + rLambda.fill(HIST("pGen_MCGenRecoColl_INEL_Lambda"), mcParticle.pt(), flattenicity); // Lambda + if (recoCollIndexINELgt0 > 0) { + rLambda.fill(HIST("pGen_MCGenRecoColl_INELgt0_Lambda"), mcParticle.pt(), flattenicity); // Lambda + } + } + if (mcParticle.pdgCode() == PDG_t::kLambda0Bar) { + rAntiLambda.fill(HIST("pGen_MCGenRecoColl_INEL_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + if (recoCollIndexINELgt0 > 0) { + rAntiLambda.fill(HIST("pGen_MCGenRecoColl_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + } + } + if (std::abs(mcParticle.pdgCode()) == PDG_t::kXiPlusBar) { + rXi.fill(HIST("pGen_MCGenRecoColl_INEL_Xi"), mcParticle.pt(), flattenicity); // Xi + if (recoCollIndexINELgt0 > 0) { + rXi.fill(HIST("pGen_MCGenRecoColl_INELgt0_Xi"), mcParticle.pt(), flattenicity); // Xi + } + } + } + } + TRandom2* fRand = new TRandom2(); + // Cascade Analysis Starts here + using DauTracks = soa::Join; + using LabeledCascades = soa::Join; + // float ctauxiPDG = 4.91; // from PDG + // float ctauomegaPDG = 2.461; // from PDG + + void processDataRun3Cascade(soa::Join::iterator const& collision, + aod::CascDataExt const& Cascades, + aod::V0Datas const&, DauTracks const& tracks, + soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0s*/) + { + if (applyEvSel && + !(isEventSelected(collision))) { // Checking if the event passes the + // selection criteria + return; + } + + auto vtxZ = collision.posZ(); + auto vtxY = collision.posY(); + auto vtxX = collision.posX(); + + float flattenicity = estimateFlattenicity(collision, tracks); + + rEventSelection.fill(HIST("hVertexZ"), vtxZ); + rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + + for (const auto& casc : Cascades) { + + auto posDaughterTrack = casc.posTrack_as(); + auto negDaughterTrack = casc.negTrack_as(); + auto bacDaughterTrack = casc.bachelor_as(); + + float cascPos = std::hypot(casc.x() - vtxX, casc.y() - vtxY, casc.z() - vtxZ); + float cascTotMom = std::hypot(casc.px(), casc.py(), casc.pz()); + float ctauXi = pdgmassXi * cascPos / (cascTotMom + 1e-13); + // float ctauOmega =pdgmassOmega * cascPos / (cascTotMom + 1e-13); + float dcav0pv = casc.dcav0topv(vtxX, vtxY, vtxZ); + float cosPAcasc = casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()); + float cosPAv0 = casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); + float massXi = casc.mXi(); + rXi.fill(HIST("hMassXi"), massXi); + // Cascade + if (posDaughterTrack.tpcNSigmaPi() < nSigmaTPCPion && negDaughterTrack.tpcNSigmaPi() < nSigmaTPCPion && bacDaughterTrack.tpcNSigmaPi() < nSigmaTPCPion && + posDaughterTrack.tpcNSigmaKa() < nSigmaTPCKaon && negDaughterTrack.tpcNSigmaKa() < nSigmaTPCKaon && bacDaughterTrack.tpcNSigmaKa() < nSigmaTPCKaon && + posDaughterTrack.tpcNSigmaPr() < nSigmaTPCProton && negDaughterTrack.tpcNSigmaPr() < nSigmaTPCProton && bacDaughterTrack.tpcNSigmaPr() < nSigmaTPCProton && + posDaughterTrack.tpcNClsCrossedRows() > nTPCcrossedRows && negDaughterTrack.tpcNClsCrossedRows() > nTPCcrossedRows && bacDaughterTrack.tpcNClsCrossedRows() > nTPCcrossedRows && + std::abs(posDaughterTrack.eta()) < cfgTrkEtaCut && std::abs(negDaughterTrack.eta()) < cfgTrkEtaCut && std::abs(bacDaughterTrack.eta()) < cfgTrkEtaCut && + casc.dcapostopv() > v0settingDCApostopv && casc.dcanegtopv() > v0settingDCAnegtopv && casc.dcabachtopv() > v0settingDCAbactopv && casc.dcaV0daughters() < v0settingDCAv0dau && dcav0pv > cascsettingDCAv0toPV && + casc.dcacascdaughters() < cascsettingDCAv0bach && casc.bachBaryonDCAxyToPV() < cascsettingDCAxybaryonbach && cosPAcasc > cascsettingCosPAcascPV && cosPAv0 > cascsettingCosPAv0PV && + casc.cascradius() > cascsettingcascradius && casc.v0radius() > cascsettingv0radius && + std::abs(casc.yXi()) < cascsettingRapidity && ctauXi < 4.91 * cascsettingproplifetime && + std::abs(casc.mLambda() - pdgmassLambda) < cascsettingMassRejectionLambdaXi && std::abs(casc.mOmega() - pdgmassOmega) > cascsettingMassRejectioOmegaXi) { + + rXi.fill(HIST("hMassXiSelected"), massXi); + rXi.fill(HIST("hDCAV0DaughtersXi"), casc.dcaV0daughters()); + rXi.fill(HIST("hV0CosPAXi"), cosPAv0); + rXi.fill(HIST("hrapidityXi"), casc.rapidity(1)); + rXi.fill(HIST("hctauXi"), ctauXi); + rXi.fill(HIST("h2DdecayRadiusXi"), casc.v0radius()); + rXi.fill(HIST("hMassXipT"), massXi, casc.pt()); + rXi.fill(HIST("hMassXipTFlat"), massXi, casc.pt(), flattenicity); + } + } + } + Preslice> perColCasc = aod::track::collisionId; + SliceCache cacheCasc; + + void processRecMCRun3Cascade(soa::Join const& collisions, + soa::Join const& Cascades, + aod::V0Datas const&, soa::Join const& tracks, + soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0s*/, aod::McCollisions const&, aod::McParticles const& mcParticles) + { + for (const auto& collision : collisions) { + if (applyEvSel && + !(isEventSelected(collision))) { // Checking if the event passes the + // selection criteria + return; + } + + auto vtxZ = collision.posZ(); + auto vtxY = collision.posY(); + auto vtxX = collision.posX(); + + float flattenicity = estimateFlattenicity(collision, tracks); + + rEventSelection.fill(HIST("hVertexZ"), vtxZ); + rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + + auto cascsThisCollision = Cascades.sliceBy(perColCasc, collision.globalIndex()); + const auto& mcCollision = collision.mcCollision_as(); + + for (const auto& casc : cascsThisCollision) { + + auto posDaughterTrack = casc.posTrack_as(); + auto negDaughterTrack = casc.negTrack_as(); + auto bacDaughterTrack = casc.bachelor_as(); + + float cascPos = std::hypot(casc.x() - vtxX, casc.y() - vtxY, casc.z() - vtxZ); + float cascTotMom = std::hypot(casc.px(), casc.py(), casc.pz()); + float ctauXi = pdgmassXi * cascPos / (cascTotMom + 1e-13); + // float ctauOmega =pdgmassOmega * cascPos / (cascTotMom + 1e-13); + float dcav0pv = casc.dcav0topv(vtxX, vtxY, vtxZ); + float cosPAcasc = casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()); + float cosPAv0 = casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); + float massXi = casc.mXi(); + rXi.fill(HIST("hMassXi"), massXi); + // Cascade + if (posDaughterTrack.tpcNSigmaPi() < nSigmaTPCPion && negDaughterTrack.tpcNSigmaPi() < nSigmaTPCPion && bacDaughterTrack.tpcNSigmaPi() < nSigmaTPCPion && + posDaughterTrack.tpcNSigmaKa() < nSigmaTPCKaon && negDaughterTrack.tpcNSigmaKa() < nSigmaTPCKaon && bacDaughterTrack.tpcNSigmaKa() < nSigmaTPCKaon && + posDaughterTrack.tpcNSigmaPr() < nSigmaTPCProton && negDaughterTrack.tpcNSigmaPr() < nSigmaTPCProton && bacDaughterTrack.tpcNSigmaPr() < nSigmaTPCProton && + posDaughterTrack.tpcNClsCrossedRows() > nTPCcrossedRows && negDaughterTrack.tpcNClsCrossedRows() > nTPCcrossedRows && bacDaughterTrack.tpcNClsCrossedRows() > nTPCcrossedRows && + std::abs(posDaughterTrack.eta()) < cfgTrkEtaCut && std::abs(negDaughterTrack.eta()) < cfgTrkEtaCut && std::abs(bacDaughterTrack.eta()) < cfgTrkEtaCut && + casc.dcapostopv() > v0settingDCApostopv && casc.dcanegtopv() > v0settingDCAnegtopv && casc.dcabachtopv() > v0settingDCAbactopv && casc.dcaV0daughters() < v0settingDCAv0dau && dcav0pv > cascsettingDCAv0toPV && + casc.dcacascdaughters() < cascsettingDCAv0bach && casc.bachBaryonDCAxyToPV() < cascsettingDCAxybaryonbach && cosPAcasc > cascsettingCosPAcascPV && cosPAv0 > cascsettingCosPAv0PV && + casc.cascradius() > cascsettingcascradius && casc.v0radius() > cascsettingv0radius && + std::abs(casc.yXi()) < cascsettingRapidity && ctauXi < 4.91 * cascsettingproplifetime && + std::abs(casc.mLambda() - pdgmassLambda) < cascsettingMassRejectionLambdaXi && std::abs(casc.mOmega() - pdgmassOmega) > cascsettingMassRejectioOmegaXi) { + + rXi.fill(HIST("hMassXiSelected"), massXi); + rXi.fill(HIST("hDCAV0DaughtersXi"), casc.dcaV0daughters()); + rXi.fill(HIST("hV0CosPAXi"), cosPAv0); + rXi.fill(HIST("hrapidityXi"), casc.rapidity(1)); + rXi.fill(HIST("hctauXi"), ctauXi); + rXi.fill(HIST("h2DdecayRadiusXi"), casc.v0radius()); + rXi.fill(HIST("hMassXipT"), massXi, casc.pt()); + rXi.fill(HIST("hMassXipTFlat"), massXi, casc.pt(), flattenicity); + } + } + const auto particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cacheCasc); + float flattenicityMCGen = estimateFlattenicityFV0MC(particlesInCollision); + rEventSelection.fill(HIST("hFlattenicityDistributionMCGen_Rec"), flattenicityMCGen); + rEventSelection.fill(HIST("hFlattenicity_Corr_Gen_vs_Rec"), flattenicityMCGen, flattenicity); + + for (const auto& mcParticle : particlesInCollision) { + if (mcParticle.isPhysicalPrimary() && std::abs(mcParticle.y()) < 0.5f && std::abs(mcParticle.pdgCode()) == PDG_t::kXiPlusBar) { + rXi.fill(HIST("Generated_MCRecoCollCheck_INEL_Xi"), mcParticle.pt(), flattenicity); // K0s + } + } + } + } + + PROCESS_SWITCH(Lambdak0sflattenicity, processDataRun3LambdaK0s, "Process Run 3 Data LambdaK0s", false); + PROCESS_SWITCH(Lambdak0sflattenicity, processRecMCLambdaK0s, "Process Run 3 MC reconstructed LambdaK0s", false); + PROCESS_SWITCH(Lambdak0sflattenicity, processGenMC, "Process Run 3 MC generated", false); + PROCESS_SWITCH(Lambdak0sflattenicity, processDataRun3Cascade, "Process Run 3 Data Cascade", true); + PROCESS_SWITCH(Lambdak0sflattenicity, processRecMCRun3Cascade, "Process Run 3 mc Rec Cascade", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Strangeness/lambdalambda.cxx b/PWGLF/Tasks/Strangeness/lambdalambda.cxx new file mode 100644 index 00000000000..bf8579f105d --- /dev/null +++ b/PWGLF/Tasks/Strangeness/lambdalambda.cxx @@ -0,0 +1,554 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author Junlee Kim (jikim1290@gmail.com) + +#include +#include +#include +#include +#include +#include + +#include "TLorentzVector.h" +#include "TRandom3.h" +#include "TF1.h" +#include "TVector3.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/StaticFor.h" + +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" + +#include "CommonConstants/PhysicsConstants.h" + +#include "ReconstructionDataFormats/Track.h" + +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" + +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" + +#include "PWGLF/DataModel/LFStrangenessTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; + +struct lambdalambda { + using EventCandidates = soa::Join; + using TrackCandidates = soa::Join; + using V0TrackCandidate = aod::V0Datas; + + HistogramRegistry histos{ + "histos", + {}, + OutputObjHandlingPolicy::AnalysisObject}; + + struct : ConfigurableGroup { + Configurable cfgURL{"cfgURL", + "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; + Configurable nolaterthan{"ccdb-no-later-than", + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), + "Latest acceptable timestamp of creation for the object"}; + } cfgCcdbParam; + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + + Configurable cfgCentSel{"cfgCentSel", 100., "Centrality selection"}; + Configurable cfgCentEst{"cfgCentEst", 1, "Centrality estimator, 1: FT0C, 2: FT0M"}; + + Configurable cfgEvtSel{"cfgEvtSel", true, "event selection flag"}; + Configurable cfgPVSel{"cfgPVSel", false, "Additional PV selection flag for syst"}; + Configurable cfgPV{"cfgPV", 8.0, "Additional PV selection range for syst"}; + Configurable cfgAddEvtSelPileup{"cfgAddEvtSelPileup", false, "flag for additional pileup selection"}; + Configurable cfgMaxOccupancy{"cfgMaxOccupancy", 999999, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable cfgMinOccupancy{"cfgMinOccupancy", 0, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + + Configurable cfgv0radiusMin{"cfgv0radiusMin", 1.2, "minimum decay radius"}; + Configurable cfgDCAPosToPVMin{"cfgDCAPosToPVMin", 0.05, "minimum DCA to PV for positive track"}; + Configurable cfgDCANegToPVMin{"cfgDCANegToPVMin", 0.2, "minimum DCA to PV for negative track"}; + Configurable cfgv0CosPA{"cfgv0CosPA", 0.995, "minimum v0 cosine"}; + Configurable cfgDCAV0Dau{"cfgDCAV0Dau", 1.0, "maximum DCA between daughters"}; + + Configurable cfgV0PtMin{"cfgV0PtMin", 0, "minimum pT for lambda"}; + Configurable cfgV0EtaMin{"cfgV0EtaMin", -0.5, "maximum rapidity"}; + Configurable cfgV0EtaMax{"cfgV0EtaMax", 0.5, "maximum rapidity"}; + Configurable cfgV0LifeTime{"cfgV0LifeTime", 30., "maximum lambda lifetime"}; + + Configurable cfgQAv0{"cfgQAv0", false, "QA plot"}; + + Configurable cfgDaughTPCnclsMin{"cfgDaughTPCnclsMin", 70, "minimum fired crossed rows"}; + Configurable cfgDaughPIDCutsTPCPr{"cfgDaughPIDCutsTPCPr", 5, "proton nsigma for TPC"}; + Configurable cfgDaughPIDCutsTPCPi{"cfgDaughPIDCutsTPCPi", 5, "pion nsigma for TPC"}; + Configurable cfgDaughEtaMin{"cfgDaughEtaMin", -0.8, "minimum daughter eta"}; + Configurable cfgDaughEtaMax{"cfgDaughEtaMax", 0.8, "maximum daughter eta"}; + Configurable cfgDaughPrPt{"cfgDaughPrPt", 0.5, "minimum daughter proton pt"}; + Configurable cfgDaughPiPt{"cfgDaughPiPt", 0.5, "minimum daughter pion pt"}; + + Configurable cfgHypMassWindow{"cfgHypMassWindow", 0.02, "single lambda mass selection"}; + Configurable cfgV0V0RapMax{"cfgV0V0RapMax", 0.5, "rapidity selection for V0V0"}; + + Configurable cfgV0V0Sel{"cfgV0V0Sel", false, "application of V0V0 selections"}; + + Configurable cfgV0V0RadiusMin{"cfgV0V0RadiusMin", 1.0, "maximum radius of v0v0"}; + Configurable cfgV0V0CPAMin{"cfgV0V0CPAMin", 0.6, "minimum CPA of v0v0"}; + Configurable cfgV0V0DistanceMin{"cfgV0V0DistanceMin", 1, "minimum distance of v0v0"}; + Configurable cfgV0V0DCAMin{"cfgV0V0DCAMin", 1.0, "maximum DCA of v0v0 R"}; + + Configurable cfgV0V0RadiusMax{"cfgV0V0RadiusMax", 1.0, "maximum radius of v0v0"}; + Configurable cfgV0V0CPAMax{"cfgV0V0CPAMax", 0.6, "maximum CPA of v0v0"}; + Configurable cfgV0V0DistanceMax{"cfgV0V0DistanceMax", 1, "maximum distance of v0v0"}; + Configurable cfgV0V0DCAMax{"cfgV0V0DCAMax", 1.0, "maximum DCA of v0v0 R"}; + + Configurable cfgEffCor{"cfgEffCor", false, "flag to apply efficiency correction"}; + Configurable cfgEffCorPath{"cfgEffCorPath", "", "path for pseudo efficiency correction"}; + + Configurable cfgRotBkg{"cfgRotBkg", true, "flag to construct rotational backgrounds"}; + Configurable cfgNRotBkg{"cfgNRotBkg", 10, "the number of rotational backgrounds"}; + Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 10, "Number of mixed events per event"}; + + ConfigurableAxis massAxis{"massAxis", {110, 2.22, 2.33}, "Invariant mass axis"}; + ConfigurableAxis ptAxis{"ptAxis", {VARIABLE_WIDTH, 0.2, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.5, 8.0, 10.0, 100.0}, "Transverse momentum bins"}; + ConfigurableAxis centAxis{"centAxis", {VARIABLE_WIDTH, 0, 10, 20, 50, 100}, "Centrality interval"}; + ConfigurableAxis vertexAxis{"vertexAxis", {10, -10, 10}, "vertex axis for mixing"}; + + ConfigurableAxis RadiusAxis{"RadiusAxis", {100, 0, 5}, "radius of v0v0"}; + ConfigurableAxis CPAAxis{"CPAAxis", {102, -1.02, 1.02}, "CPA of v0v0"}; + ConfigurableAxis DistanceAxis{"DistanceAxis", {100, 0, 10}, "distance of v0v0"}; + ConfigurableAxis DCAAxis{"DCAAxis", {100, 0, 2}, "DCA of v0v0R"}; + + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + + float centrality; + TProfile2D* EffMap = nullptr; + + TRandom* rn = new TRandom(); + + bool IsTriggered; + bool IsSelected; + + void init(o2::framework::InitContext&) + { + AxisSpec centQaAxis = {80, 0.0, 80.0}; + AxisSpec PVzQaAxis = {300, -15.0, 15.0}; + AxisSpec combAxis = {3, -0.5, 2.5}; + + histos.add("hEventstat", "", {HistType::kTH1F, {{4, 0, 4}}}); + + histos.add("Radius_V0V0_full", "", {HistType::kTHnSparseF, {massAxis, ptAxis, RadiusAxis, combAxis}}); + histos.add("CPA_V0V0_full", "", {HistType::kTHnSparseF, {massAxis, ptAxis, CPAAxis, combAxis}}); + histos.add("Distance_V0V0_full", "", {HistType::kTHnSparseF, {massAxis, ptAxis, DistanceAxis, combAxis}}); + histos.add("DCA_V0V0_full", "", {HistType::kTHnSparseF, {massAxis, ptAxis, DCAAxis, combAxis}}); + + histos.add("Radius_V0V0_sel", "", {HistType::kTHnSparseF, {massAxis, ptAxis, RadiusAxis, combAxis}}); + histos.add("CPA_V0V0_sel", "", {HistType::kTHnSparseF, {massAxis, ptAxis, CPAAxis, combAxis}}); + histos.add("Distance_V0V0_sel", "", {HistType::kTHnSparseF, {massAxis, ptAxis, DistanceAxis, combAxis}}); + histos.add("DCA_V0V0_sel", "", {HistType::kTHnSparseF, {massAxis, ptAxis, DCAAxis, combAxis}}); + + histos.add("h_InvMass_same", "", {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis, combAxis}}); + histos.add("h_InvMass_mixed", "", {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis, combAxis}}); + histos.add("h_InvMass_rot", "", {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis, combAxis}}); + + histos.add("h_InvMass_same_sel", "", {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis, combAxis}}); + histos.add("h_InvMass_mixed_sel", "", {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis, combAxis}}); + histos.add("h_InvMass_rot_sel", "", {HistType::kTHnSparseF, {massAxis, ptAxis, centAxis, combAxis}}); + + if (cfgQAv0) { + histos.add("QA/CentDist", "", {HistType::kTH1F, {centQaAxis}}); + histos.add("QA/PVzDist", "", {HistType::kTH1F, {PVzQaAxis}}); + } + + fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultPVCutLow->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05); + fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultPVCutHigh->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05); + + ccdb->setURL(cfgCcdbParam.cfgURL); + ccdbApi.init("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + } + + double massLambda = o2::constants::physics::MassLambda; + ROOT::Math::PxPyPzMVector RecoV01, RecoV02, RecoV0V0; + ROOT::Math::PxPyPzMVector RecoV02Rot, RecoV0V0Rot; + + template + bool eventSelected(TCollision collision) + { + if (!collision.sel8()) { + return 0; + } + + if (cfgCentSel < centrality) { + return 0; + } + /* + auto multNTracksPV = collision.multNTracksPV(); + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) { + return 0; + } + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) { + return 0; + } + */ + if (!collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return 0; + } + if (!collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return 0; + } + if (cfgPVSel && std::abs(collision.posZ()) > cfgPV) { + return 0; + } + if (cfgAddEvtSelPileup && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return 0; + } + if (collision.trackOccupancyInTimeRange() > cfgMaxOccupancy || collision.trackOccupancyInTimeRange() < cfgMinOccupancy) { + return 0; + } + + return 1; + } // event selection + + template + bool SelectionV0(TCollision const& collision, V0 const& candidate) + { + if (candidate.v0radius() < cfgv0radiusMin) + return false; + if (std::abs(candidate.dcapostopv()) < cfgDCAPosToPVMin) + return false; + if (std::abs(candidate.dcanegtopv()) < cfgDCANegToPVMin) + return false; + if (candidate.v0cosPA() < cfgv0CosPA) + return false; + if (std::abs(candidate.dcaV0daughters()) > cfgDCAV0Dau) + return false; + if (candidate.pt() < cfgV0PtMin) + return false; + if (candidate.yLambda() < cfgV0EtaMin) + return false; + if (candidate.yLambda() > cfgV0EtaMax) + return false; + if (candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massLambda > cfgV0LifeTime) + return false; + + return true; + } + + template + bool isSelectedV0Daughter(T const& track, int pid) // pid 0: proton, pid 1: pion + { + if (track.tpcNClsFound() < cfgDaughTPCnclsMin) + return false; + if (pid == 0 && std::abs(track.tpcNSigmaPr()) > cfgDaughPIDCutsTPCPr) + return false; + if (pid == 1 && std::abs(track.tpcNSigmaPi()) > cfgDaughPIDCutsTPCPi) + return false; + if (track.eta() > cfgDaughEtaMax) + return false; + if (track.eta() < cfgDaughEtaMin) + return false; + if (pid == 0 && track.pt() < cfgDaughPrPt) + return false; + if (pid == 1 && track.pt() < cfgDaughPiPt) + return false; + + return true; + } + + template + bool isSelectedV0V0(V01 const& v01, V02 const& v02) + { + if (getDCAofV0V0(v01, v02) > cfgV0V0DCAMax) + return false; + if (getDCAofV0V0(v01, v02) < cfgV0V0DCAMin) + return false; + if (getCPA(v01, v02) > cfgV0V0CPAMax) + return false; + if (getCPA(v01, v02) < cfgV0V0CPAMin) + return false; + if (getDistance(v01, v02) > cfgV0V0DistanceMax) + return false; + if (getDistance(v01, v02) < cfgV0V0DistanceMin) + return false; + if (getRadius(v01, v02) > cfgV0V0RadiusMax) + return false; + if (getRadius(v01, v02) < cfgV0V0RadiusMin) + return false; + + return true; + } + + template + float getDCAofV0V0(V01 const& v01, V02 const& v02) + { + ROOT::Math::XYZVector v01pos, v02pos, v01mom, v02mom; + v01pos.SetXYZ(v01.x(), v01.y(), v01.z()); + v02pos.SetXYZ(v02.x(), v02.y(), v02.z()); + v01mom.SetXYZ(v01.px(), v01.py(), v01.pz()); + v02mom.SetXYZ(v02.px(), v02.py(), v02.pz()); + + ROOT::Math::XYZVector posdiff = v02pos - v01pos; + ROOT::Math::XYZVector cross = v01mom.Cross(v02mom); + ROOT::Math::XYZVector dcaVec = (posdiff.Dot(cross) / cross.Mag2()) * cross; + return std::sqrt(dcaVec.Mag2()); + } + + template + float getCPA(V01 const& v01, V02 const& v02) + { + ROOT::Math::XYZVector v01mom, v02mom; + v01mom.SetXYZ(v01.px() / v01.p(), v01.py() / v01.p(), v01.pz() / v01.p()); + v02mom.SetXYZ(v02.px() / v02.p(), v02.py() / v02.p(), v02.pz() / v02.p()); + return v01mom.Dot(v02mom); + } + + template + float getDistance(V01 const& v01, V02 const& v02) + { + ROOT::Math::XYZVector v01pos, v02pos; + v01pos.SetXYZ(v01.x(), v01.y(), v01.z()); + v02pos.SetXYZ(v02.x(), v02.y(), v02.z()); + ROOT::Math::XYZVector posdiff = v02pos - v01pos; + return std::sqrt(posdiff.Mag2()); + } + + template + float getRadius(V01 const& v01, V02 const& v02) + { + ROOT::Math::XYZVector v01pos, v02pos, v01mom, v02mom; + v01pos.SetXYZ(v01.x(), v01.y(), v01.z()); + v02pos.SetXYZ(v02.x(), v02.y(), v02.z()); + v01mom.SetXYZ(v01.px() / v01.p(), v01.py() / v01.p(), v01.pz() / v01.p()); + v02mom.SetXYZ(v02.px() / v02.p(), v02.py() / v02.p(), v02.pz() / v02.p()); + ROOT::Math::XYZVector posdiff = v02pos - v01pos; + + float d = 1. - TMath::Power(v01mom.Dot(v02mom), 2); + if (d < 1e-5) + return 999; + float t = posdiff.Dot(v01mom - v01mom.Dot(v02mom) * v02mom) / d; + float s = -posdiff.Dot(v02mom - v01mom.Dot(v02mom) * v01mom) / d; + ROOT::Math::XYZVector dca = v01pos + v02pos + t * v01mom + s * v02mom; + dca /= 2.; + return std::sqrt(dca.Mag2()); + } + + template + void FillHistograms(C1 const& c1, C2 const& c2, V01 const& V01s, V02 const& V02s) + { + IsTriggered = false; + IsSelected = false; + + for (auto& v01 : V01s) { + auto postrack_v01 = v01.template posTrack_as(); + auto negtrack_v01 = v01.template negTrack_as(); + + int LambdaTag = 0; + int aLambdaTag = 0; + int V01Tag = -2; + + if (isSelectedV0Daughter(postrack_v01, 0) && isSelectedV0Daughter(negtrack_v01, 1)) { + LambdaTag = 1; + V01Tag = 0; + } + if (isSelectedV0Daughter(negtrack_v01, 0) && isSelectedV0Daughter(postrack_v01, 1)) { + aLambdaTag = 1; + V01Tag = 1; + } + + if (LambdaTag == aLambdaTag) + continue; + + if (!SelectionV0(c1, v01)) + continue; + + if (LambdaTag) { + if (std::abs(massLambda - v01.mLambda()) > cfgHypMassWindow) + continue; + RecoV01 = ROOT::Math::PxPyPzMVector(v01.px(), v01.py(), v01.pz(), v01.mLambda()); + } else if (aLambdaTag) { + if (std::abs(massLambda - v01.mAntiLambda()) > cfgHypMassWindow) + continue; + RecoV01 = ROOT::Math::PxPyPzMVector(v01.px(), v01.py(), v01.pz(), v01.mAntiLambda()); + } + + for (auto& v02 : V02s) { + if (v01.v0Id() <= v02.v0Id() && doprocessDataSame) + continue; + auto postrack_v02 = v02.template posTrack_as(); + auto negtrack_v02 = v02.template negTrack_as(); + + LambdaTag = 0; + aLambdaTag = 0; + int V02Tag = -2; + + if (isSelectedV0Daughter(postrack_v02, 0) && isSelectedV0Daughter(negtrack_v02, 1)) { + LambdaTag = 1; + V02Tag = 0; + } + if (isSelectedV0Daughter(negtrack_v02, 0) && isSelectedV0Daughter(postrack_v02, 1)) { + aLambdaTag = 1; + V02Tag = 1; + } + + if (LambdaTag == aLambdaTag) + continue; + + if (!SelectionV0(c2, v02)) + continue; + + if (doprocessDataSame) { + if (postrack_v01.globalIndex() == postrack_v02.globalIndex() || postrack_v01.globalIndex() == negtrack_v02.globalIndex() || negtrack_v01.globalIndex() == postrack_v02.globalIndex() || negtrack_v01.globalIndex() == negtrack_v02.globalIndex()) + continue; // no shared decay products + } + + if (LambdaTag) { + if (std::abs(massLambda - v02.mLambda()) > cfgHypMassWindow) + continue; + RecoV02 = ROOT::Math::PxPyPzMVector(v02.px(), v02.py(), v02.pz(), v02.mLambda()); + } else if (aLambdaTag) { + if (std::abs(massLambda - v02.mAntiLambda()) > cfgHypMassWindow) + continue; + RecoV02 = ROOT::Math::PxPyPzMVector(v02.px(), v02.py(), v02.pz(), v02.mAntiLambda()); + } + + RecoV0V0 = RecoV01 + RecoV02; + + if (std::abs(RecoV0V0.Rapidity()) > cfgV0V0RapMax) + continue; + IsTriggered = true; + + histos.fill(HIST("Radius_V0V0_full"), RecoV0V0.M(), RecoV0V0.Pt(), getRadius(v01, v02), V01Tag + V02Tag); + histos.fill(HIST("CPA_V0V0_full"), RecoV0V0.M(), RecoV0V0.Pt(), getCPA(v01, v02), V01Tag + V02Tag); + histos.fill(HIST("Distance_V0V0_full"), RecoV0V0.M(), RecoV0V0.Pt(), getDistance(v01, v02), V01Tag + V02Tag); + histos.fill(HIST("DCA_V0V0_full"), RecoV0V0.M(), RecoV0V0.Pt(), getDCAofV0V0(v01, v02), V01Tag + V02Tag); + + if (isSelectedV0V0(v01, v02)) { + histos.fill(HIST("Radius_V0V0_sel"), RecoV0V0.M(), RecoV0V0.Pt(), getRadius(v01, v02), V01Tag + V02Tag); + histos.fill(HIST("CPA_V0V0_sel"), RecoV0V0.M(), RecoV0V0.Pt(), getCPA(v01, v02), V01Tag + V02Tag); + histos.fill(HIST("Distance_V0V0_sel"), RecoV0V0.M(), RecoV0V0.Pt(), getDistance(v01, v02), V01Tag + V02Tag); + histos.fill(HIST("DCA_V0V0_sel"), RecoV0V0.M(), RecoV0V0.Pt(), getDCAofV0V0(v01, v02), V01Tag + V02Tag); + IsSelected = true; + } + + if (doprocessDataSame) { + histos.fill(HIST("h_InvMass_same"), RecoV0V0.M(), RecoV0V0.Pt(), centrality, V01Tag + V02Tag); + if (cfgV0V0Sel && isSelectedV0V0(v01, v02)) { + histos.fill(HIST("h_InvMass_same_sel"), RecoV0V0.M(), RecoV0V0.Pt(), centrality, V01Tag + V02Tag); + if (cfgRotBkg) { + for (int nr = 0; nr < cfgNRotBkg; nr++) { + auto RanPhi = rn->Uniform(o2::constants::math::PI * 5.0 / 6.0, o2::constants::math::PI * 7.0 / 6.0); + RanPhi += RecoV02.Phi(); + RecoV02Rot = ROOT::Math::PxPyPzMVector(RecoV02.Pt() * std::cos(RanPhi), RecoV02.Pt() * std::sin(RanPhi), RecoV02.Pz(), RecoV02.M()); + RecoV0V0Rot = RecoV01 + RecoV02Rot; + histos.fill(HIST("h_InvMass_rot"), RecoV0V0Rot.M(), RecoV0V0Rot.Pt(), centrality, V01Tag + V02Tag); + } + } + } + } + if (doprocessDataMixed) { + histos.fill(HIST("h_InvMass_mixed"), RecoV0V0.M(), RecoV0V0.Pt(), centrality, V01Tag + V02Tag); + if (cfgV0V0Sel && isSelectedV0V0(v01, v02)) { + histos.fill(HIST("h_InvMass_mixed_sel"), RecoV0V0.M(), RecoV0V0.Pt(), centrality, V01Tag + V02Tag); + } + } + } + } + } + + void processDataSame(EventCandidates::iterator const& collision, + TrackCandidates const& /*tracks*/, aod::V0Datas const& V0s, + aod::BCsWithTimestamps const&) + { + if (cfgCentEst == 1) { + centrality = collision.centFT0C(); + } else if (cfgCentEst == 2) { + centrality = collision.centFT0M(); + } + histos.fill(HIST("hEventstat"), 0.5); + if (!eventSelected(collision) && cfgEvtSel) { + return; + } + histos.fill(HIST("hEventstat"), 1.5); + + histos.fill(HIST("QA/CentDist"), centrality, 1.0); + histos.fill(HIST("QA/PVzDist"), collision.posZ(), 1.0); + + if (cfgEffCor) { + auto bc = collision.bc_as(); + EffMap = ccdb->getForTimeStamp(cfgEffCorPath.value, bc.timestamp()); + } + FillHistograms(collision, collision, V0s, V0s); + + if (IsTriggered) + histos.fill(HIST("hEventstat"), 2.5); + if (IsSelected) + histos.fill(HIST("hEventstat"), 3.5); + } + PROCESS_SWITCH(lambdalambda, processDataSame, "Process Event for same data", true); + + SliceCache cache; + using BinningTypeVertexContributor = ColumnBinningPolicy; + + void processDataMixed(EventCandidates const& collisions, + TrackCandidates const& /*tracks*/, aod::V0Datas const& V0s) + { + auto tracksTuple = std::make_tuple(V0s); + BinningTypeVertexContributor binningOnPositions{{vertexAxis, centAxis}, true}; + SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; + for (auto& [c1, tracks1, c2, tracks2] : pair) { + if (cfgCentEst == 1) { + centrality = c1.centFT0C(); + } else if (cfgCentEst == 2) { + centrality = c1.centFT0M(); + } + if (!eventSelected(c1)) + continue; + if (!eventSelected(c2)) + continue; + if (c1.bcId() == c2.bcId()) + continue; + + FillHistograms(c1, c2, tracks1, tracks2); + } + } + PROCESS_SWITCH(lambdalambda, processDataMixed, "Process Event for mixed data", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"lf-lambdalambda"})}; +} diff --git a/PWGLF/Tasks/Strangeness/lambdapolarization.cxx b/PWGLF/Tasks/Strangeness/lambdapolarization.cxx new file mode 100644 index 00000000000..38e17ba338a --- /dev/null +++ b/PWGLF/Tasks/Strangeness/lambdapolarization.cxx @@ -0,0 +1,1049 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author Junlee Kim (jikim1290@gmail.com) + +#include +#include +#include +#include +#include +#include + +#include "TLorentzVector.h" +#include "TRandom3.h" +#include "TF1.h" +#include "TVector2.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/StaticFor.h" + +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/PIDResponseITS.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" + +#include "CommonConstants/PhysicsConstants.h" + +#include "ReconstructionDataFormats/Track.h" + +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" + +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" + +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; + +struct lambdapolarization { + // using EventCandidates = soa::Filtered>; + using EventCandidates = soa::Join; + using TrackCandidates = soa::Join; + using V0TrackCandidate = aod::V0Datas; + + HistogramRegistry histos{ + "histos", + {}, + OutputObjHandlingPolicy::AnalysisObject}; + + struct : ConfigurableGroup { + Configurable cfgURL{"cfgURL", + "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; + Configurable nolaterthan{"ccdb-no-later-than", + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), + "Latest acceptable timestamp of creation for the object"}; + } cfgCcdbParam; + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + + Configurable cfgCentSel{"cfgCentSel", 80., "Centrality selection"}; + Configurable cfgCentEst{"cfgCentEst", 1, "Centrality estimator, 1: FT0C, 2: FT0M"}; + + Configurable cfgPVSel{"cfgPVSel", false, "Additional PV selection flag for syst"}; + Configurable cfgPV{"cfgPV", 8.0, "Additional PV selection range for syst"}; + Configurable cfgAddEvtSelPileup{"cfgAddEvtSelPileup", false, "flag for additional pileup selection"}; + Configurable cfgMaxOccupancy{"cfgMaxOccupancy", 999999, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable cfgMinOccupancy{"cfgMinOccupancy", 0, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + + Configurable cfgv0radiusMin{"cfgv0radiusMin", 1.2, "minimum decay radius"}; + Configurable cfgDCAPrToPVMin{"cfgDCAPrToPVMin", 0.05, "minimum DCA to PV for proton track"}; + Configurable cfgDCAPiToPVMin{"cfgDCAPiToPVMin", 0.1, "minimum DCA to PV for pion track"}; + Configurable cfgv0CosPA{"cfgv0CosPA", 0.995, "minimum v0 cosine"}; + Configurable cfgDCAV0Dau{"cfgDCAV0Dau", 1.0, "maximum DCA between daughters"}; + + Configurable cfgV0PtMin{"cfgV0PtMin", 0, "minimum pT for lambda"}; + Configurable cfgV0EtaMin{"cfgV0EtaMin", -0.5, "maximum rapidity"}; + Configurable cfgV0EtaMax{"cfgV0EtaMax", 0.5, "maximum rapidity"}; + Configurable cfgV0LifeTime{"cfgV0LifeTime", 30., "maximum lambda lifetime"}; + + Configurable cfgQAv0{"cfgQAv0", false, "QA plot"}; + + Configurable cfgDaughTPCnclsMin{"cfgDaughTPCnclsMin", 70, "minimum fired crossed rows"}; + Configurable cfgDaughPIDCutsTPCPr{"cfgDaughPIDCutsTPCPr", 5, "proton nsigma for TPC"}; + Configurable cfgDaughPIDCutsTPCPi{"cfgDaughPIDCutsTPCPi", 5, "pion nsigma for TPC"}; + Configurable cfgDaughEtaMin{"cfgDaughEtaMin", -0.8, "minimum daughter eta"}; + Configurable cfgDaughEtaMax{"cfgDaughEtaMax", 0.8, "maximum daughter eta"}; + Configurable cfgDaughPrPt{"cfgDaughPrPt", 0.5, "minimum daughter proton pt"}; + Configurable cfgDaughPiPt{"cfgDaughPiPt", 0.5, "minimum daughter pion pt"}; + + Configurable cfgnMods{"cfgnMods", 1, "The number of modulations of interest starting from 2"}; + Configurable cfgNQvec{"cfgNQvec", 7, "The number of total Qvectors for looping over the task"}; + + Configurable cfgQvecDetName{"cfgQvecDetName", "FT0C", "The name of detector to be analyzed"}; + Configurable cfgQvecRefAName{"cfgQvecRefAName", "TPCpos", "The name of detector for reference A"}; + Configurable cfgQvecRefBName{"cfgQvecRefBName", "TPCneg", "The name of detector for reference B"}; + + Configurable cfgPhiDepStudy{"cfgPhiDepStudy", false, "cfg for phi dependent study"}; + Configurable cfgUSESP{"cfgUSESP", false, "cfg for sp"}; + Configurable cfgPhiDepSig{"cfgPhiDepSig", 0.2, "cfg for significance on phi dependent study"}; + + Configurable cfgShiftCorr{"cfgShiftCorr", false, "additional shift correction"}; + Configurable cfgShiftCorrDef{"cfgShiftCorrDef", false, "additional shift correction definition"}; + Configurable cfgShiftPath{"cfgShiftPath", "Users/j/junlee/Qvector/QvecCalib/Shift", "Path for Shift"}; + + Configurable cfgEffCor{"cfgEffCor", false, "flag to apply efficiency correction"}; + Configurable cfgEffCorPath{"cfgEffCorPath", "", "path for pseudo efficiency correction"}; + + Configurable cfgAccCor{"cfgAccCor", false, "flag to apply acceptance correction"}; + Configurable cfgAccCorPath{"cfgAccCorPath", "", "path for pseudo acceptance correction"}; + + Configurable cfgCalcCum{"cfgCalcCum", false, "flag to calculate cumulants of cossin"}; + Configurable cfgCalcCum1{"cfgCalcCum1", false, "flag to calculate cumulants of coscos"}; + + Configurable cfgRapidityDep{"cfgRapidityDep", false, "flag for rapidity dependent study"}; + Configurable cfgAccAzimuth{"cfgAccAzimuth", false, "flag for azimuth closure study"}; + + ConfigurableAxis massAxis{"massAxis", {30, 1.1, 1.13}, "Invariant mass axis"}; + ConfigurableAxis ptAxis{"ptAxis", {VARIABLE_WIDTH, 0.2, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.5, 8.0, 10.0, 100.0}, "Transverse momentum bins"}; + ConfigurableAxis centAxis{"centAxis", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 100}, "Centrality interval"}; + ConfigurableAxis cosAxis{"cosAxis", {110, -1.05, 1.05}, "Cosine axis"}; + ConfigurableAxis RapAxis{"RapAxis", {10, -0.5, 0.5}, "Rapidity axis"}; + ConfigurableAxis qqAxis{"qqAxis", {100, -0.1, 0.1}, "qq axis"}; + + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + + int DetId; + int RefAId; + int RefBId; + + int QvecDetInd; + int QvecRefAInd; + int QvecRefBInd; + + float centrality; + + double angle; + double psi; + double relphi; + + int currentRunNumber = -999; + int lastRunNumber = -999; + std::vector shiftprofile{}; + TProfile2D* EffMap = nullptr; + TProfile2D* AccMap = nullptr; + + std::string fullCCDBShiftCorrPath; + + double GetPhiInRange(double phi) + { + double result = phi; + while (result < 0) { + result = result + 2. * TMath::Pi() / 2; + } + while (result > 2. * TMath::Pi() / 2) { + result = result - 2. * TMath::Pi() / 2; + } + return result; + } + + template + int GetDetId(const T& name) + { + if (name.value == "FT0C") { + return 0; + } else if (name.value == "FT0A") { + return 1; + } else if (name.value == "FT0M") { + return 2; + } else if (name.value == "FV0A") { + return 3; + } else if (name.value == "TPCpos") { + return 4; + } else if (name.value == "TPCneg") { + return 5; + } else if (name.value == "TPCall") { + return 6; + } else { + return 0; + } + } + + void init(o2::framework::InitContext&) + { + AxisSpec centQaAxis = {80, 0.0, 80.0}; + AxisSpec PVzQaAxis = {300, -15.0, 15.0}; + AxisSpec epAxis = {6, 0.0, 2.0 * constants::math::PI}; + AxisSpec epQaAxis = {100, -1.0 * constants::math::PI, constants::math::PI}; + + AxisSpec pidAxis = {100, -10, 10}; + + AxisSpec shiftAxis = {10, 0, 10, "shift"}; + AxisSpec basisAxis = {20, 0, 20, "basis"}; + + for (auto i = 2; i < cfgnMods + 2; i++) { + histos.add(Form("psi%d/h_lambda_cos", i), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis, epAxis}}); + histos.add(Form("psi%d/h_alambda_cos", i), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis, epAxis}}); + histos.add(Form("psi%d/h_lambda_cos2", i), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis, epAxis}}); + histos.add(Form("psi%d/h_alambda_cos2", i), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis, epAxis}}); + + if (cfgRapidityDep) { + histos.add(Form("psi%d/h_lambda_cos2_rap", i), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis, RapAxis}}); + histos.add(Form("psi%d/h_alambda_cos2_rap", i), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis, RapAxis}}); + } + + histos.add(Form("psi%d/h_lambda_cossin", i), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add(Form("psi%d/h_alambda_cossin", i), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + + if (cfgAccAzimuth) { + histos.add(Form("psi%d/h_lambda_coscos", i), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add(Form("psi%d/h_alambda_coscos", i), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + } + + histos.add(Form("psi%d/h_lambda_vncos", i), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add(Form("psi%d/h_lambda_vnsin", i), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add(Form("psi%d/h_alambda_vncos", i), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add(Form("psi%d/h_alambda_vnsin", i), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + } + histos.add("QA/ptspec_l", "", {HistType::kTH3F, {massAxis, ptAxis, centAxis}}); + histos.add("QA/ptspec_al", "", {HistType::kTH3F, {massAxis, ptAxis, centAxis}}); + histos.add("QA/ptspecCor_l", "", {HistType::kTH3F, {massAxis, ptAxis, centAxis}}); + histos.add("QA/ptspecCor_al", "", {HistType::kTH3F, {massAxis, ptAxis, centAxis}}); + + if (cfgCalcCum) { + histos.add("psi2/QA/cosTheta_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosPsi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosPhi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + + histos.add("psi2/QA/sinPsi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/sinPhi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + + histos.add("psi2/QA/cosTheta_cosPhi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosTheta_cosPsi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + + histos.add("psi2/QA/cosTheta_sinPhi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosTheta_sinPsi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + + histos.add("psi2/QA/cosPhi_sinPsi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/sinPhi_cosPsi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + + histos.add("psi2/QA/cosTheta_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosPsi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosPhi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + + histos.add("psi2/QA/sinPsi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/sinPhi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + + histos.add("psi2/QA/cosTheta_cosPhi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosTheta_cosPsi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + + histos.add("psi2/QA/cosTheta_sinPhi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosTheta_sinPsi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + + histos.add("psi2/QA/cosPhi_sinPsi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/sinPhi_cosPsi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + } + + if (cfgCalcCum1) { + histos.add("psi2/QA/cosTheta_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosPsi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosPhi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + + histos.add("psi2/QA/cosPhi_cosPsi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosTheta_cosPhi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosTheta_cosPsi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + + histos.add("psi2/QA/sinPhi_sinPsi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosTheta_sinPhi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosTheta_sinPsi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + + histos.add("psi2/QA/sinPsi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/sinPhi_l", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + + histos.add("psi2/QA/cosTheta_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosPsi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosPhi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + + histos.add("psi2/QA/cosPhi_cosPsi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosTheta_cosPhi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosTheta_cosPsi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + + histos.add("psi2/QA/sinPhi_sinPsi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosTheta_sinPhi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/cosTheta_sinPsi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + + histos.add("psi2/QA/sinPsi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + histos.add("psi2/QA/sinPhi_al", "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis}}); + } + + if (cfgQAv0) { + histos.add("QA/CentDist", "", {HistType::kTH1F, {centQaAxis}}); + histos.add("QA/PVzDist", "", {HistType::kTH1F, {PVzQaAxis}}); + + histos.add("QA/nsigma_tpc_pt_ppr", "", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA/nsigma_tpc_pt_ppi", "", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA/nsigma_tpc_pt_mpr", "", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA/nsigma_tpc_pt_mpi", "", {HistType::kTH2F, {ptAxis, pidAxis}}); + + for (auto i = 2; i < cfgnMods + 2; i++) { + histos.add(Form("psi%d/QA/EP_Det", i), "", {HistType::kTH2F, {centQaAxis, epQaAxis}}); + histos.add(Form("psi%d/QA/EP_RefA", i), "", {HistType::kTH2F, {centQaAxis, epQaAxis}}); + histos.add(Form("psi%d/QA/EP_RefB", i), "", {HistType::kTH2F, {centQaAxis, epQaAxis}}); + + histos.add(Form("psi%d/QA/qqAxis_Det_RefA_xx", i), "", {HistType::kTH2F, {centQaAxis, qqAxis}}); + histos.add(Form("psi%d/QA/qqAxis_Det_RefB_xx", i), "", {HistType::kTH2F, {centQaAxis, qqAxis}}); + histos.add(Form("psi%d/QA/qqAxis_RefA_RefB_xx", i), "", {HistType::kTH2F, {centQaAxis, qqAxis}}); + + histos.add(Form("psi%d/QA/qqAxis_Det_RefA_yy", i), "", {HistType::kTH2F, {centQaAxis, qqAxis}}); + histos.add(Form("psi%d/QA/qqAxis_Det_RefB_yy", i), "", {HistType::kTH2F, {centQaAxis, qqAxis}}); + histos.add(Form("psi%d/QA/qqAxis_RefA_RefB_yy", i), "", {HistType::kTH2F, {centQaAxis, qqAxis}}); + + histos.add(Form("psi%d/QA/EPRes_Det_RefA", i), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); + histos.add(Form("psi%d/QA/EPRes_Det_RefB", i), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); + histos.add(Form("psi%d/QA/EPRes_RefA_RefB", i), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); + + histos.add(Form("psi%d/QA/EP_FT0C_shifted", i), "", {HistType::kTH2F, {centQaAxis, epQaAxis}}); + histos.add(Form("psi%d/QA/EP_FT0A_shifted", i), "", {HistType::kTH2F, {centQaAxis, epQaAxis}}); + histos.add(Form("psi%d/QA/EP_FV0A_shifted", i), "", {HistType::kTH2F, {centQaAxis, epQaAxis}}); + + histos.add(Form("psi%d/QA/EPRes_FT0C_FT0A_shifted", i), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); + histos.add(Form("psi%d/QA/EPRes_FT0C_FV0A_shifted", i), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); + histos.add(Form("psi%d/QA/EPRes_FT0A_FV0A_shifted", i), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); + } + } + + if (doprocessMC_ITSTPC) { + histos.add("hImpactParameter", "Impact parameter", kTH1F, {{200, 0.0f, 20.0f}}); + histos.add("hEventPlaneAngle", "hEventPlaneAngle", kTH1F, {{200, -2.0f * TMath::Pi(), 2.0f * TMath::Pi()}}); + histos.add("hEventPlaneAngleRec", "hEventPlaneAngleRec", kTH1F, {{200, -2.0f * TMath::Pi(), 2.0f * TMath::Pi()}}); + histos.add("hNchVsImpactParameter", "hNchVsImpactParameter", kTH2F, {{200, 0.0f, 20.0f}, {500, -0.5f, 5000.5f}}); + histos.add("hSparseMCGenWeight", "hSparseMCGenWeight", HistType::kTHnSparseF, {centAxis, {36, 0.0f, TMath::Pi()}, {50, 0.0f, 1}, ptAxis, {8, -0.8, 0.8}}); + histos.add("hSparseMCRecWeight", "hSparseMCRecWeight", HistType::kTHnSparseF, {centAxis, {36, 0.0f, TMath::Pi()}, {50, 0.0f, 1}, ptAxis, {8, -0.8, 0.8}}); + histos.add("hSparseMCRecAllTrackWeight", "hSparseMCRecAllTrackWeight", HistType::kTHnSparseF, {centAxis, {36, 0.0, TMath::Pi()}, {50, 0.0f, 1}, ptAxis, {8, -0.8, 0.8}}); + } + + if (cfgShiftCorrDef) { + for (auto i = 2; i < cfgnMods + 2; i++) { + histos.add(Form("psi%d/ShiftFIT", i), "", kTProfile3D, {centQaAxis, basisAxis, shiftAxis}); + } + } + + DetId = GetDetId(cfgQvecDetName); + RefAId = GetDetId(cfgQvecRefAName); + RefBId = GetDetId(cfgQvecRefBName); + + if (DetId == RefAId || DetId == RefBId || RefAId == RefBId) { + LOGF(info, "Wrong detector configuration \n The FT0C will be used to get Q-Vector \n The TPCpos and TPCneg will be used as reference systems"); + DetId = 0; + RefAId = 4; + RefBId = 5; + } + + fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultPVCutLow->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05); + fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultPVCutHigh->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05); + + ccdb->setURL(cfgCcdbParam.cfgURL); + ccdbApi.init("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + } + + double massLambda = o2::constants::physics::MassLambda; + double massPr = o2::constants::physics::MassProton; + double massPi = o2::constants::physics::MassPionCharged; + + ROOT::Math::PxPyPzMVector ProtonVec, PionVec, LambdaVec, ProtonBoostedVec, PionBoostedVec; + + template + bool eventSelected(TCollision collision) + { + if (!collision.sel8()) { + return 0; + } + + if (cfgCentSel < centrality) { + return 0; + } + /* + auto multNTracksPV = collision.multNTracksPV(); + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) { + return 0; + } + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) { + return 0; + } + */ + if (!collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return 0; + } + if (!collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return 0; + } + if (cfgPVSel && std::abs(collision.posZ()) > cfgPV) { + return 0; + } + if (cfgAddEvtSelPileup && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return 0; + } + if (collision.trackOccupancyInTimeRange() > cfgMaxOccupancy || collision.trackOccupancyInTimeRange() < cfgMinOccupancy) { + return 0; + } + + return 1; + } // event selection + + template + bool SelectionV0(TCollision const& collision, V0 const& candidate, int LambdaTag) + { + if (candidate.v0radius() < cfgv0radiusMin) + return false; + if (LambdaTag) { + if (std::abs(candidate.dcapostopv()) < cfgDCAPrToPVMin) + return false; + if (std::abs(candidate.dcanegtopv()) < cfgDCAPiToPVMin) + return false; + } else if (!LambdaTag) { + if (std::abs(candidate.dcapostopv()) < cfgDCAPiToPVMin) + return false; + if (std::abs(candidate.dcanegtopv()) < cfgDCAPrToPVMin) + return false; + } + if (candidate.v0cosPA() < cfgv0CosPA) + return false; + if (std::abs(candidate.dcaV0daughters()) > cfgDCAV0Dau) + return false; + if (candidate.pt() < cfgV0PtMin) + return false; + if (candidate.yLambda() < cfgV0EtaMin) + return false; + if (candidate.yLambda() > cfgV0EtaMax) + return false; + if (candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massLambda > cfgV0LifeTime) + return false; + + return true; + } + + template + bool isSelectedV0Daughter(T const& track, int pid) // pid 0: proton, pid 1: pion + { + if (track.tpcNClsFound() < cfgDaughTPCnclsMin) + return false; + if (pid == 0 && std::abs(track.tpcNSigmaPr()) > cfgDaughPIDCutsTPCPr) + return false; + if (pid == 1 && std::abs(track.tpcNSigmaPi()) > cfgDaughPIDCutsTPCPi) + return false; + if (track.eta() > cfgDaughEtaMax) + return false; + if (track.eta() < cfgDaughEtaMin) + return false; + if (pid == 0 && track.pt() < cfgDaughPrPt) + return false; + if (pid == 1 && track.pt() < cfgDaughPiPt) + return false; + + return true; + } + + template + void FillShiftCorrection(TCollision const& collision, int nmode) + { + QvecDetInd = DetId * 4 + 3 + (nmode - 2) * cfgNQvec * 4; + QvecRefAInd = RefAId * 4 + 3 + (nmode - 2) * cfgNQvec * 4; + QvecRefBInd = RefBId * 4 + 3 + (nmode - 2) * cfgNQvec * 4; + for (int ishift = 1; ishift <= 10; ishift++) { + if (nmode == 2) { + histos.fill(HIST("psi2/ShiftFIT"), centrality, 0.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) / static_cast(nmode))); + histos.fill(HIST("psi2/ShiftFIT"), centrality, 1.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) / static_cast(nmode))); + + histos.fill(HIST("psi2/ShiftFIT"), centrality, 2.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecRefAInd], collision.qvecRe()[QvecRefAInd]) / static_cast(nmode))); + histos.fill(HIST("psi2/ShiftFIT"), centrality, 3.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecRefAInd], collision.qvecRe()[QvecRefAInd]) / static_cast(nmode))); + + histos.fill(HIST("psi2/ShiftFIT"), centrality, 4.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecRefBInd], collision.qvecRe()[QvecRefBInd]) / static_cast(nmode))); + histos.fill(HIST("psi2/ShiftFIT"), centrality, 5.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecRefBInd], collision.qvecRe()[QvecRefBInd]) / static_cast(nmode))); + } else if (nmode == 3) { + histos.fill(HIST("psi3/ShiftFIT"), centrality, 0.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) / static_cast(nmode))); + histos.fill(HIST("psi3/ShiftFIT"), centrality, 1.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) / static_cast(nmode))); + + histos.fill(HIST("psi3/ShiftFIT"), centrality, 2.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecRefAInd], collision.qvecRe()[QvecRefAInd]) / static_cast(nmode))); + histos.fill(HIST("psi3/ShiftFIT"), centrality, 3.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecRefAInd], collision.qvecRe()[QvecRefAInd]) / static_cast(nmode))); + + histos.fill(HIST("psi3/ShiftFIT"), centrality, 4.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecRefBInd], collision.qvecRe()[QvecRefBInd]) / static_cast(nmode))); + histos.fill(HIST("psi3/ShiftFIT"), centrality, 5.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecRefBInd], collision.qvecRe()[QvecRefBInd]) / static_cast(nmode))); + } else if (nmode == 4) { + histos.fill(HIST("psi4/ShiftFIT"), centrality, 0.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) / static_cast(nmode))); + histos.fill(HIST("psi4/ShiftFIT"), centrality, 1.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) / static_cast(nmode))); + + histos.fill(HIST("psi4/ShiftFIT"), centrality, 2.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecRefAInd], collision.qvecRe()[QvecRefAInd]) / static_cast(nmode))); + histos.fill(HIST("psi4/ShiftFIT"), centrality, 3.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecRefAInd], collision.qvecRe()[QvecRefAInd]) / static_cast(nmode))); + + histos.fill(HIST("psi4/ShiftFIT"), centrality, 4.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecRefBInd], collision.qvecRe()[QvecRefBInd]) / static_cast(nmode))); + histos.fill(HIST("psi4/ShiftFIT"), centrality, 5.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(collision.qvecIm()[QvecRefBInd], collision.qvecRe()[QvecRefBInd]) / static_cast(nmode))); + } + } + } + + template + void FillEPQA(TCollision const& collision, int nmode) + { + QvecDetInd = DetId * 4 + 3 + (nmode - 2) * cfgNQvec * 4; + QvecRefAInd = RefAId * 4 + 3 + (nmode - 2) * cfgNQvec * 4; + QvecRefBInd = RefBId * 4 + 3 + (nmode - 2) * cfgNQvec * 4; + + if (collision.qvecAmp()[DetId] < 1e-5 || collision.qvecAmp()[RefAId] < 1e-5 || collision.qvecAmp()[RefBId] < 1e-5) + return; + + if (nmode == 2) { + histos.fill(HIST("psi2/QA/EP_Det"), centrality, TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) / static_cast(nmode)); + histos.fill(HIST("psi2/QA/EP_RefA"), centrality, TMath::ATan2(collision.qvecIm()[QvecRefAInd], collision.qvecRe()[QvecRefAInd]) / static_cast(nmode)); + histos.fill(HIST("psi2/QA/EP_RefB"), centrality, TMath::ATan2(collision.qvecIm()[QvecRefBInd], collision.qvecRe()[QvecRefBInd]) / static_cast(nmode)); + + histos.fill(HIST("psi2/QA/qqAxis_Det_RefA_xx"), centrality, collision.qvecRe()[QvecDetInd] * collision.qvecRe()[QvecRefAInd]); + histos.fill(HIST("psi2/QA/qqAxis_Det_RefB_xx"), centrality, collision.qvecRe()[QvecDetInd] * collision.qvecRe()[QvecRefBInd]); + histos.fill(HIST("psi2/QA/qqAxis_RefA_RefB_xx"), centrality, collision.qvecRe()[QvecRefAInd] * collision.qvecRe()[QvecRefBInd]); + + histos.fill(HIST("psi2/QA/qqAxis_Det_RefA_yy"), centrality, collision.qvecIm()[QvecDetInd] * collision.qvecIm()[QvecRefAInd]); + histos.fill(HIST("psi2/QA/qqAxis_Det_RefB_yy"), centrality, collision.qvecIm()[QvecDetInd] * collision.qvecIm()[QvecRefBInd]); + histos.fill(HIST("psi2/QA/qqAxis_RefA_RefB_yy"), centrality, collision.qvecIm()[QvecRefAInd] * collision.qvecIm()[QvecRefBInd]); + + histos.fill(HIST("psi2/QA/EPRes_Det_RefA"), centrality, TMath::Cos(TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) - TMath::ATan2(collision.qvecIm()[QvecRefAInd], collision.qvecRe()[QvecRefAInd]))); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB"), centrality, TMath::Cos(TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) - TMath::ATan2(collision.qvecIm()[QvecRefBInd], collision.qvecRe()[QvecRefBInd]))); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB"), centrality, TMath::Cos(TMath::ATan2(collision.qvecIm()[QvecRefAInd], collision.qvecRe()[QvecRefAInd]) - TMath::ATan2(collision.qvecIm()[QvecRefBInd], collision.qvecRe()[QvecRefBInd]))); + } else if (nmode == 3) { + histos.fill(HIST("psi3/QA/EP_Det"), centrality, TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) / static_cast(nmode)); + histos.fill(HIST("psi3/QA/EP_RefA"), centrality, TMath::ATan2(collision.qvecIm()[QvecRefAInd], collision.qvecRe()[QvecRefAInd]) / static_cast(nmode)); + histos.fill(HIST("psi3/QA/EP_RefB"), centrality, TMath::ATan2(collision.qvecIm()[QvecRefBInd], collision.qvecRe()[QvecRefBInd]) / static_cast(nmode)); + + histos.fill(HIST("psi3/QA/qqAxis_Det_RefA_xx"), centrality, collision.qvecRe()[QvecDetInd] * collision.qvecRe()[QvecRefAInd]); + histos.fill(HIST("psi3/QA/qqAxis_Det_RefB_xx"), centrality, collision.qvecRe()[QvecDetInd] * collision.qvecRe()[QvecRefBInd]); + histos.fill(HIST("psi3/QA/qqAxis_RefA_RefB_xx"), centrality, collision.qvecRe()[QvecRefAInd] * collision.qvecRe()[QvecRefBInd]); + + histos.fill(HIST("psi3/QA/qqAxis_Det_RefA_yy"), centrality, collision.qvecIm()[QvecDetInd] * collision.qvecIm()[QvecRefAInd]); + histos.fill(HIST("psi3/QA/qqAxis_Det_RefB_yy"), centrality, collision.qvecIm()[QvecDetInd] * collision.qvecIm()[QvecRefBInd]); + histos.fill(HIST("psi3/QA/qqAxis_RefA_RefB_yy"), centrality, collision.qvecIm()[QvecRefAInd] * collision.qvecIm()[QvecRefBInd]); + + histos.fill(HIST("psi3/QA/EPRes_Det_RefA"), centrality, TMath::Cos(TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) - TMath::ATan2(collision.qvecIm()[QvecRefAInd], collision.qvecRe()[QvecRefAInd]))); + histos.fill(HIST("psi3/QA/EPRes_Det_RefB"), centrality, TMath::Cos(TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) - TMath::ATan2(collision.qvecIm()[QvecRefBInd], collision.qvecRe()[QvecRefBInd]))); + histos.fill(HIST("psi3/QA/EPRes_RefA_RefB"), centrality, TMath::Cos(TMath::ATan2(collision.qvecIm()[QvecRefAInd], collision.qvecRe()[QvecRefAInd]) - TMath::ATan2(collision.qvecIm()[QvecRefBInd], collision.qvecRe()[QvecRefBInd]))); + } else if (nmode == 4) { + histos.fill(HIST("psi4/QA/EP_Det"), centrality, TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) / static_cast(nmode)); + histos.fill(HIST("psi4/QA/EP_RefA"), centrality, TMath::ATan2(collision.qvecIm()[QvecRefAInd], collision.qvecRe()[QvecRefAInd]) / static_cast(nmode)); + histos.fill(HIST("psi4/QA/EP_RefB"), centrality, TMath::ATan2(collision.qvecIm()[QvecRefBInd], collision.qvecRe()[QvecRefBInd]) / static_cast(nmode)); + + histos.fill(HIST("psi4/QA/qqAxis_Det_RefA_xx"), centrality, collision.qvecRe()[QvecDetInd] * collision.qvecRe()[QvecRefAInd]); + histos.fill(HIST("psi4/QA/qqAxis_Det_RefB_xx"), centrality, collision.qvecRe()[QvecDetInd] * collision.qvecRe()[QvecRefBInd]); + histos.fill(HIST("psi4/QA/qqAxis_RefA_RefB_xx"), centrality, collision.qvecRe()[QvecRefAInd] * collision.qvecRe()[QvecRefBInd]); + + histos.fill(HIST("psi4/QA/qqAxis_Det_RefA_yy"), centrality, collision.qvecIm()[QvecDetInd] * collision.qvecIm()[QvecRefAInd]); + histos.fill(HIST("psi4/QA/qqAxis_Det_RefB_yy"), centrality, collision.qvecIm()[QvecDetInd] * collision.qvecIm()[QvecRefBInd]); + histos.fill(HIST("psi4/QA/qqAxis_RefA_RefB_yy"), centrality, collision.qvecIm()[QvecRefAInd] * collision.qvecIm()[QvecRefBInd]); + + histos.fill(HIST("psi4/QA/EPRes_Det_RefA"), centrality, TMath::Cos(TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) - TMath::ATan2(collision.qvecIm()[QvecRefAInd], collision.qvecRe()[QvecRefAInd]))); + histos.fill(HIST("psi4/QA/EPRes_Det_RefB"), centrality, TMath::Cos(TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) - TMath::ATan2(collision.qvecIm()[QvecRefBInd], collision.qvecRe()[QvecRefBInd]))); + histos.fill(HIST("psi4/QA/EPRes_RefA_RefB"), centrality, TMath::Cos(TMath::ATan2(collision.qvecIm()[QvecRefAInd], collision.qvecRe()[QvecRefAInd]) - TMath::ATan2(collision.qvecIm()[QvecRefBInd], collision.qvecRe()[QvecRefBInd]))); + } + + if (cfgShiftCorr) { + auto deltapsiFT0C = 0.0; + auto deltapsiFT0A = 0.0; + auto deltapsiFV0A = 0.0; + + auto psidefFT0C = TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) / static_cast(nmode); + auto psidefFT0A = TMath::ATan2(collision.qvecIm()[QvecRefAInd], collision.qvecRe()[QvecRefAInd]) / static_cast(nmode); + auto psidefFV0A = TMath::ATan2(collision.qvecIm()[QvecRefBInd], collision.qvecRe()[QvecRefBInd]) / static_cast(nmode); + for (int ishift = 1; ishift <= 10; ishift++) { + auto coeffshiftxFT0C = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(centrality, 0.5, ishift - 0.5)); + auto coeffshiftyFT0C = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(centrality, 1.5, ishift - 0.5)); + auto coeffshiftxFT0A = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(centrality, 2.5, ishift - 0.5)); + auto coeffshiftyFT0A = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(centrality, 3.5, ishift - 0.5)); + auto coeffshiftxFV0A = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(centrality, 4.5, ishift - 0.5)); + auto coeffshiftyFV0A = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(centrality, 5.5, ishift - 0.5)); + + deltapsiFT0C += ((1 / (1.0 * ishift)) * (-coeffshiftxFT0C * TMath::Cos(ishift * static_cast(nmode) * psidefFT0C) + coeffshiftyFT0C * TMath::Sin(ishift * static_cast(nmode) * psidefFT0C))); + deltapsiFT0A += ((1 / (1.0 * ishift)) * (-coeffshiftxFT0A * TMath::Cos(ishift * static_cast(nmode) * psidefFT0A) + coeffshiftyFT0A * TMath::Sin(ishift * static_cast(nmode) * psidefFT0A))); + deltapsiFV0A += ((1 / (1.0 * ishift)) * (-coeffshiftxFV0A * TMath::Cos(ishift * static_cast(nmode) * psidefFV0A) + coeffshiftyFV0A * TMath::Sin(ishift * static_cast(nmode) * psidefFV0A))); + } + if (nmode == 2) { + histos.fill(HIST("psi2/QA/EP_FT0C_shifted"), centrality, psidefFT0C + deltapsiFT0C); + histos.fill(HIST("psi2/QA/EP_FT0A_shifted"), centrality, psidefFT0A + deltapsiFT0A); + histos.fill(HIST("psi2/QA/EP_FV0A_shifted"), centrality, psidefFV0A + deltapsiFV0A); + + histos.fill(HIST("psi2/QA/EPRes_FT0C_FT0A_shifted"), centrality, TMath::Cos(static_cast(nmode) * (psidefFT0C + deltapsiFT0C - psidefFT0A - deltapsiFT0A))); + histos.fill(HIST("psi2/QA/EPRes_FT0C_FV0A_shifted"), centrality, TMath::Cos(static_cast(nmode) * (psidefFT0C + deltapsiFT0C - psidefFV0A - deltapsiFV0A))); + histos.fill(HIST("psi2/QA/EPRes_FT0A_FV0A_shifted"), centrality, TMath::Cos(static_cast(nmode) * (psidefFT0A + deltapsiFT0A - psidefFV0A - deltapsiFV0A))); + } else if (nmode == 3) { + histos.fill(HIST("psi3/QA/EP_FT0C_shifted"), centrality, psidefFT0C + deltapsiFT0C); + histos.fill(HIST("psi3/QA/EP_FT0A_shifted"), centrality, psidefFT0A + deltapsiFT0A); + histos.fill(HIST("psi3/QA/EP_FV0A_shifted"), centrality, psidefFV0A + deltapsiFV0A); + + histos.fill(HIST("psi3/QA/EPRes_FT0C_FT0A_shifted"), centrality, TMath::Cos(static_cast(nmode) * (psidefFT0C + deltapsiFT0C - psidefFT0A - deltapsiFT0A))); + histos.fill(HIST("psi3/QA/EPRes_FT0C_FV0A_shifted"), centrality, TMath::Cos(static_cast(nmode) * (psidefFT0C + deltapsiFT0C - psidefFV0A - deltapsiFV0A))); + histos.fill(HIST("psi3/QA/EPRes_FT0A_FV0A_shifted"), centrality, TMath::Cos(static_cast(nmode) * (psidefFT0A + deltapsiFT0A - psidefFV0A - deltapsiFV0A))); + } else if (nmode == 4) { + histos.fill(HIST("psi4/QA/EP_FT0C_shifted"), centrality, psidefFT0C + deltapsiFT0C); + histos.fill(HIST("psi4/QA/EP_FT0A_shifted"), centrality, psidefFT0A + deltapsiFT0A); + histos.fill(HIST("psi4/QA/EP_FV0A_shifted"), centrality, psidefFV0A + deltapsiFV0A); + + histos.fill(HIST("psi4/QA/EPRes_FT0C_FT0A_shifted"), centrality, TMath::Cos(static_cast(nmode) * (psidefFT0C + deltapsiFT0C - psidefFT0A - deltapsiFT0A))); + histos.fill(HIST("psi4/QA/EPRes_FT0C_FV0A_shifted"), centrality, TMath::Cos(static_cast(nmode) * (psidefFT0C + deltapsiFT0C - psidefFV0A - deltapsiFV0A))); + histos.fill(HIST("psi4/QA/EPRes_FT0A_FV0A_shifted"), centrality, TMath::Cos(static_cast(nmode) * (psidefFT0A + deltapsiFT0A - psidefFV0A - deltapsiFV0A))); + } + } + } + + template + void FillHistograms(TCollision const& collision, V0 const& V0s, int nmode) + { + QvecDetInd = DetId * 4 + 3 + (nmode - 2) * cfgNQvec * 4; + QvecRefAInd = RefAId * 4 + 3 + (nmode - 2) * cfgNQvec * 4; + QvecRefBInd = RefBId * 4 + 3 + (nmode - 2) * cfgNQvec * 4; + + for (auto& v0 : V0s) { + auto postrack = v0.template posTrack_as(); + auto negtrack = v0.template negTrack_as(); + + double nTPCSigmaPosPr = postrack.tpcNSigmaPr(); + double nTPCSigmaNegPi = negtrack.tpcNSigmaPi(); + + double nTPCSigmaNegPr = negtrack.tpcNSigmaPr(); + double nTPCSigmaPosPi = postrack.tpcNSigmaPi(); + + if (cfgQAv0 && nmode == 2) { + histos.fill(HIST("QA/nsigma_tpc_pt_ppr"), postrack.pt(), nTPCSigmaPosPr); + histos.fill(HIST("QA/nsigma_tpc_pt_ppi"), postrack.pt(), nTPCSigmaPosPi); + + histos.fill(HIST("QA/nsigma_tpc_pt_mpr"), negtrack.pt(), nTPCSigmaNegPr); + histos.fill(HIST("QA/nsigma_tpc_pt_mpi"), negtrack.pt(), nTPCSigmaNegPi); + } + + int LambdaTag = 0; + int aLambdaTag = 0; + + if (isSelectedV0Daughter(postrack, 0) && isSelectedV0Daughter(negtrack, 1)) { + LambdaTag = 1; + } + if (isSelectedV0Daughter(negtrack, 0) && isSelectedV0Daughter(postrack, 1)) { + aLambdaTag = 1; + } + + if (LambdaTag == aLambdaTag) + continue; + + if (!SelectionV0(collision, v0, LambdaTag)) + continue; + + if (LambdaTag) { + ProtonVec = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), massPr); + PionVec = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), massPi); + } + if (aLambdaTag) { + ProtonVec = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), massPr); + PionVec = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), massPi); + } + LambdaVec = ProtonVec + PionVec; + LambdaVec.SetM(massLambda); + + ROOT::Math::Boost boost{LambdaVec.BoostToCM()}; + ProtonBoostedVec = boost(ProtonVec); + + angle = ProtonBoostedVec.Pz() / ProtonBoostedVec.P(); + psi = TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) / static_cast(nmode); + relphi = TVector2::Phi_0_2pi(static_cast(nmode) * (LambdaVec.Phi() - psi)); + + if (cfgShiftCorr) { + auto deltapsiFT0C = 0.0; + auto deltapsiFT0A = 0.0; + auto deltapsiFV0A = 0.0; + + auto psidefFT0C = TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) / static_cast(nmode); + auto psidefFT0A = TMath::ATan2(collision.qvecIm()[QvecRefAInd], collision.qvecRe()[QvecRefAInd]) / static_cast(nmode); + auto psidefFV0A = TMath::ATan2(collision.qvecIm()[QvecRefBInd], collision.qvecRe()[QvecRefBInd]) / static_cast(nmode); + for (int ishift = 1; ishift <= 10; ishift++) { + auto coeffshiftxFT0C = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(centrality, 0.5, ishift - 0.5)); + auto coeffshiftyFT0C = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(centrality, 1.5, ishift - 0.5)); + auto coeffshiftxFT0A = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(centrality, 2.5, ishift - 0.5)); + auto coeffshiftyFT0A = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(centrality, 3.5, ishift - 0.5)); + auto coeffshiftxFV0A = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(centrality, 4.5, ishift - 0.5)); + auto coeffshiftyFV0A = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(centrality, 5.5, ishift - 0.5)); + + deltapsiFT0C += ((1 / (1.0 * ishift)) * (-coeffshiftxFT0C * TMath::Cos(ishift * static_cast(nmode) * psidefFT0C) + coeffshiftyFT0C * TMath::Sin(ishift * static_cast(nmode) * psidefFT0C))); + deltapsiFT0A += ((1 / (1.0 * ishift)) * (-coeffshiftxFT0A * TMath::Cos(ishift * static_cast(nmode) * psidefFT0A) + coeffshiftyFT0A * TMath::Sin(ishift * static_cast(nmode) * psidefFT0A))); + deltapsiFV0A += ((1 / (1.0 * ishift)) * (-coeffshiftxFV0A * TMath::Cos(ishift * static_cast(nmode) * psidefFV0A) + coeffshiftyFV0A * TMath::Sin(ishift * static_cast(nmode) * psidefFV0A))); + } + psi += deltapsiFT0C; + relphi = TVector2::Phi_0_2pi(static_cast(nmode) * (LambdaVec.Phi() - psidefFT0C - deltapsiFT0C)); + } + + if (cfgPhiDepStudy && cfgPhiDepSig * std::abs(TMath::Sin(relphi)) > gRandom->Uniform(0, 1)) { + continue; + } + + if (LambdaTag) { + histos.fill(HIST("QA/ptspec_l"), v0.mLambda(), v0.pt(), centrality); + if (cfgEffCor) { + histos.fill(HIST("QA/ptspecCor_l"), v0.mLambda(), v0.pt(), centrality, + 1.0 / EffMap->GetBinContent(EffMap->GetXaxis()->FindBin(v0.pt()), EffMap->GetYaxis()->FindBin(centrality))); + } + } + if (aLambdaTag) { + histos.fill(HIST("QA/ptspec_al"), v0.mAntiLambda(), v0.pt(), centrality); + if (cfgEffCor) { + histos.fill(HIST("QA/ptspecCor_al"), v0.mAntiLambda(), v0.pt(), centrality, + 1.0 / EffMap->GetBinContent(EffMap->GetXaxis()->FindBin(v0.pt()), EffMap->GetYaxis()->FindBin(centrality))); + } + } + double weight = 1.0; + weight *= cfgEffCor ? 1.0 / EffMap->GetBinContent(EffMap->GetXaxis()->FindBin(v0.pt()), EffMap->GetYaxis()->FindBin(centrality)) : 1.; + weight *= cfgAccCor ? 1.0 / AccMap->GetBinContent(AccMap->GetXaxis()->FindBin(v0.pt()), AccMap->GetYaxis()->FindBin(v0.yLambda())) : 1.; + + double qvecMag = 1.0; + if (cfgUSESP) + qvecMag *= TMath::Sqrt(TMath::Power(collision.qvecIm()[3 + (nmode - 2) * 28], 2) + TMath::Power(collision.qvecRe()[3 + (nmode - 2) * 28], 2)); + + if (nmode == 2) { //////////// + if (LambdaTag) { + histos.fill(HIST("psi2/h_lambda_cos"), v0.mLambda(), v0.pt(), angle * weight, centrality, relphi); + histos.fill(HIST("psi2/h_lambda_cos2"), v0.mLambda(), v0.pt(), angle * angle, centrality, relphi); + histos.fill(HIST("psi2/h_lambda_cossin"), v0.mLambda(), v0.pt(), angle * TMath::Sin(relphi) * weight, centrality); + histos.fill(HIST("psi2/h_lambda_vncos"), v0.mLambda(), v0.pt(), qvecMag * TMath::Cos(relphi) * weight, centrality); + histos.fill(HIST("psi2/h_lambda_vnsin"), v0.mLambda(), v0.pt(), TMath::Sin(relphi), centrality); + + if (cfgRapidityDep) { + histos.fill(HIST("psi2/h_lambda_cos2_rap"), v0.mLambda(), v0.pt(), angle * angle, centrality, v0.yLambda(), weight); + } + + if (cfgAccAzimuth) { + histos.fill(HIST("psi2/h_lambda_coscos"), v0.mLambda(), v0.pt(), angle * TMath::Cos(relphi), centrality, weight); + } + + if (cfgCalcCum) { + histos.fill(HIST("psi2/QA/cosTheta_l"), v0.mLambda(), v0.pt(), angle, centrality); + histos.fill(HIST("psi2/QA/cosPsi_l"), v0.mLambda(), v0.pt(), TMath::Cos(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosPhi_l"), v0.mLambda(), v0.pt(), TMath::Cos(v0.phi() * 2.0), centrality); + + histos.fill(HIST("psi2/QA/sinPsi_l"), v0.mLambda(), v0.pt(), TMath::Sin(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/sinPhi_l"), v0.mLambda(), v0.pt(), TMath::Sin(v0.phi() * 2.0), centrality); + + histos.fill(HIST("psi2/QA/cosTheta_cosPhi_l"), v0.mLambda(), v0.pt(), angle * TMath::Cos(v0.phi() * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_cosPsi_l"), v0.mLambda(), v0.pt(), angle * TMath::Cos(psi * 2.0), centrality); + + histos.fill(HIST("psi2/QA/cosTheta_sinPhi_l"), v0.mLambda(), v0.pt(), angle * TMath::Sin(v0.phi() * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_sinPsi_l"), v0.mLambda(), v0.pt(), angle * TMath::Sin(psi * 2.0), centrality); + + histos.fill(HIST("psi2/QA/cosPhi_sinPsi_l"), v0.mLambda(), v0.pt(), TMath::Cos(v0.phi() * 2.0) * TMath::Sin(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/sinPhi_cosPsi_l"), v0.mLambda(), v0.pt(), TMath::Sin(v0.phi() * 2.0) * TMath::Cos(psi * 2.0), centrality); + } + if (cfgCalcCum1) { + histos.fill(HIST("psi2/QA/cosTheta_l"), v0.mLambda(), v0.pt(), angle, centrality); + histos.fill(HIST("psi2/QA/cosPsi_l"), v0.mLambda(), v0.pt(), TMath::Cos(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosPhi_l"), v0.mLambda(), v0.pt(), TMath::Cos(v0.phi() * 2.0), centrality); + + histos.fill(HIST("psi2/QA/cosPhi_cosPsi_l"), v0.mLambda(), v0.pt(), TMath::Cos(v0.phi() * 2.0) * TMath::Cos(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_cosPhi_l"), v0.mLambda(), v0.pt(), angle * TMath::Cos(v0.phi() * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_cosPsi_l"), v0.mLambda(), v0.pt(), angle * TMath::Cos(psi * 2.0), centrality); + + histos.fill(HIST("psi2/QA/sinPhi_sinPsi_l"), v0.mLambda(), v0.pt(), TMath::Sin(v0.phi() * 2.0) * TMath::Sin(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_sinPhi_l"), v0.mLambda(), v0.pt(), angle * TMath::Sin(v0.phi() * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_sinPsi_l"), v0.mLambda(), v0.pt(), angle * TMath::Sin(psi * 2.0), centrality); + + histos.fill(HIST("psi2/QA/sinPsi_l"), v0.mLambda(), v0.pt(), TMath::Sin(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/sinPhi_l"), v0.mLambda(), v0.pt(), TMath::Sin(v0.phi() * 2.0), centrality); + } + } + if (aLambdaTag) { + histos.fill(HIST("psi2/h_alambda_cos"), v0.mAntiLambda(), v0.pt(), angle * weight, centrality, relphi); + histos.fill(HIST("psi2/h_alambda_cos2"), v0.mAntiLambda(), v0.pt(), angle * angle, centrality, relphi); + histos.fill(HIST("psi2/h_alambda_cossin"), v0.mAntiLambda(), v0.pt(), angle * TMath::Sin(relphi) * weight, centrality); + histos.fill(HIST("psi2/h_alambda_vncos"), v0.mAntiLambda(), v0.pt(), qvecMag * TMath::Cos(relphi) * weight, centrality); + histos.fill(HIST("psi2/h_alambda_vnsin"), v0.mAntiLambda(), v0.pt(), TMath::Sin(relphi), centrality); + + if (cfgRapidityDep) { + histos.fill(HIST("psi2/h_alambda_cos2_rap"), v0.mAntiLambda(), v0.pt(), angle * angle, centrality, v0.yLambda(), weight); + } + + if (cfgAccAzimuth) { + histos.fill(HIST("psi2/h_alambda_coscos"), v0.mAntiLambda(), v0.pt(), angle * TMath::Cos(relphi), centrality, weight); + } + + if (cfgCalcCum) { + histos.fill(HIST("psi2/QA/cosTheta_al"), v0.mAntiLambda(), v0.pt(), angle, centrality); + histos.fill(HIST("psi2/QA/cosPsi_al"), v0.mAntiLambda(), v0.pt(), TMath::Cos(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosPhi_al"), v0.mAntiLambda(), v0.pt(), TMath::Cos(v0.phi() * 2.0), centrality); + + histos.fill(HIST("psi2/QA/sinPsi_al"), v0.mAntiLambda(), v0.pt(), TMath::Sin(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/sinPhi_al"), v0.mAntiLambda(), v0.pt(), TMath::Sin(v0.phi() * 2.0), centrality); + + histos.fill(HIST("psi2/QA/cosTheta_cosPhi_al"), v0.mAntiLambda(), v0.pt(), angle * TMath::Cos(v0.phi() * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_cosPsi_al"), v0.mAntiLambda(), v0.pt(), angle * TMath::Cos(psi * 2.0), centrality); + + histos.fill(HIST("psi2/QA/cosTheta_sinPhi_al"), v0.mAntiLambda(), v0.pt(), angle * TMath::Sin(v0.phi() * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_sinPsi_al"), v0.mAntiLambda(), v0.pt(), angle * TMath::Sin(psi * 2.0), centrality); + + histos.fill(HIST("psi2/QA/cosPhi_sinPsi_al"), v0.mAntiLambda(), v0.pt(), TMath::Cos(v0.phi() * 2.0) * TMath::Sin(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/sinPhi_cosPsi_al"), v0.mAntiLambda(), v0.pt(), TMath::Sin(v0.phi() * 2.0) * TMath::Cos(psi * 2.0), centrality); + } + if (cfgCalcCum1) { + histos.fill(HIST("psi2/QA/cosTheta_al"), v0.mAntiLambda(), v0.pt(), angle, centrality); + histos.fill(HIST("psi2/QA/cosPsi_al"), v0.mAntiLambda(), v0.pt(), TMath::Cos(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosPhi_al"), v0.mAntiLambda(), v0.pt(), TMath::Cos(v0.phi() * 2.0), centrality); + + histos.fill(HIST("psi2/QA/cosPhi_cosPsi_al"), v0.mAntiLambda(), v0.pt(), TMath::Cos(v0.phi() * 2.0) * TMath::Cos(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_cosPhi_al"), v0.mAntiLambda(), v0.pt(), angle * TMath::Cos(v0.phi() * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_cosPsi_al"), v0.mAntiLambda(), v0.pt(), angle * TMath::Cos(psi * 2.0), centrality); + + histos.fill(HIST("psi2/QA/sinPhi_sinPsi_al"), v0.mAntiLambda(), v0.pt(), TMath::Sin(v0.phi() * 2.0) * TMath::Sin(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_sinPhi_al"), v0.mAntiLambda(), v0.pt(), angle * TMath::Sin(v0.phi() * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_sinPsi_al"), v0.mAntiLambda(), v0.pt(), angle * TMath::Sin(psi * 2.0), centrality); + + histos.fill(HIST("psi2/QA/sinPsi_al"), v0.mAntiLambda(), v0.pt(), TMath::Sin(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/sinPhi_al"), v0.mAntiLambda(), v0.pt(), TMath::Sin(v0.phi() * 2.0), centrality); + } + } + } else if (nmode == 3) { + if (LambdaTag) { + histos.fill(HIST("psi3/h_lambda_cos"), v0.mLambda(), v0.pt(), angle * weight, centrality, relphi); + histos.fill(HIST("psi3/h_lambda_cos2"), v0.mLambda(), v0.pt(), angle * angle, centrality, relphi); + histos.fill(HIST("psi3/h_lambda_cossin"), v0.mLambda(), v0.pt(), angle * TMath::Sin(relphi) * weight, centrality); + histos.fill(HIST("psi3/h_lambda_vncos"), v0.mLambda(), v0.pt(), qvecMag * TMath::Cos(relphi) * weight, centrality); + histos.fill(HIST("psi3/h_lambda_vnsin"), v0.mLambda(), v0.pt(), TMath::Sin(relphi), centrality); + + if (cfgRapidityDep) { + histos.fill(HIST("psi3/h_lambda_cos2_rap"), v0.mLambda(), v0.pt(), angle * angle, centrality, v0.yLambda(), weight); + } + + if (cfgAccAzimuth) { + histos.fill(HIST("psi3/h_lambda_coscos"), v0.mLambda(), v0.pt(), angle * TMath::Cos(relphi), centrality, weight); + } + } + if (aLambdaTag) { + histos.fill(HIST("psi3/h_alambda_cos"), v0.mAntiLambda(), v0.pt(), angle * weight, centrality, relphi); + histos.fill(HIST("psi3/h_alambda_cos2"), v0.mAntiLambda(), v0.pt(), angle * angle, centrality, relphi, weight); + histos.fill(HIST("psi3/h_alambda_cossin"), v0.mAntiLambda(), v0.pt(), angle * TMath::Sin(relphi) * weight, centrality); + histos.fill(HIST("psi3/h_alambda_vncos"), v0.mAntiLambda(), v0.pt(), qvecMag * TMath::Cos(relphi) * weight, centrality); + histos.fill(HIST("psi3/h_alambda_vnsin"), v0.mAntiLambda(), v0.pt(), TMath::Sin(relphi), centrality); + + if (cfgRapidityDep) { + histos.fill(HIST("psi3/h_alambda_cos2_rap"), v0.mAntiLambda(), v0.pt(), angle * angle, centrality, v0.yLambda(), weight); + } + + if (cfgAccAzimuth) { + histos.fill(HIST("psi3/h_alambda_coscos"), v0.mAntiLambda(), v0.pt(), angle * TMath::Cos(relphi), centrality, weight); + } + } + } else if (nmode == 4) { + if (LambdaTag) { + histos.fill(HIST("psi4/h_lambda_cos"), v0.mLambda(), v0.pt(), angle * weight, centrality, relphi); + histos.fill(HIST("psi4/h_lambda_cos2"), v0.mLambda(), v0.pt(), angle * angle, centrality, relphi); + histos.fill(HIST("psi4/h_lambda_cossin"), v0.mLambda(), v0.pt(), angle * TMath::Sin(relphi) * weight, centrality); + histos.fill(HIST("psi4/h_lambda_vncos"), v0.mLambda(), v0.pt(), qvecMag * TMath::Cos(relphi) * weight, centrality); + histos.fill(HIST("psi4/h_lambda_vnsin"), v0.mLambda(), v0.pt(), TMath::Sin(relphi), centrality); + + if (cfgRapidityDep) { + histos.fill(HIST("psi4/h_lambda_cos2_rap"), v0.mLambda(), v0.pt(), angle * angle, centrality, v0.yLambda(), weight); + } + + if (cfgAccAzimuth) { + histos.fill(HIST("psi4/h_lambda_coscos"), v0.mLambda(), v0.pt(), angle * TMath::Cos(relphi), centrality, weight); + } + } + if (aLambdaTag) { + histos.fill(HIST("psi4/h_alambda_cos"), v0.mAntiLambda(), v0.pt(), angle * weight, centrality, relphi); + histos.fill(HIST("psi4/h_alambda_cos2"), v0.mAntiLambda(), v0.pt(), angle * angle, centrality, relphi); + histos.fill(HIST("psi4/h_alambda_cossin"), v0.mAntiLambda(), v0.pt(), angle * TMath::Sin(relphi) * weight, centrality); + histos.fill(HIST("psi4/h_alambda_vncos"), v0.mAntiLambda(), v0.pt(), qvecMag * TMath::Cos(relphi) * weight, centrality); + histos.fill(HIST("psi4/h_alambda_vnsin"), v0.mAntiLambda(), v0.pt(), TMath::Sin(relphi), centrality); + + if (cfgRapidityDep) { + histos.fill(HIST("psi4/h_alambda_cos2_rap"), v0.mAntiLambda(), v0.pt(), angle * angle, centrality, v0.yLambda(), weight); + } + + if (cfgAccAzimuth) { + histos.fill(HIST("psi4/h_alambda_coscos"), v0.mAntiLambda(), v0.pt(), angle * TMath::Cos(relphi), centrality, weight); + } + } + } ////////// FIXME: not possible to get histograms using nmode + } + } + + void processData(EventCandidates::iterator const& collision, + TrackCandidates const& /*tracks*/, aod::V0Datas const& V0s, + aod::BCsWithTimestamps const&) + { + if (cfgCentEst == 1) { + centrality = collision.centFT0C(); + } else if (cfgCentEst == 2) { + centrality = collision.centFT0M(); + } + if (!eventSelected(collision)) { + return; + } + histos.fill(HIST("QA/CentDist"), centrality, 1.0); + histos.fill(HIST("QA/PVzDist"), collision.posZ(), 1.0); + + if (cfgShiftCorr) { + auto bc = collision.bc_as(); + currentRunNumber = bc.runNumber(); + if (currentRunNumber != lastRunNumber) { + shiftprofile.clear(); + for (int i = 2; i < cfgnMods + 2; i++) { + fullCCDBShiftCorrPath = cfgShiftPath; + fullCCDBShiftCorrPath += "/v"; + fullCCDBShiftCorrPath += std::to_string(i); + auto objshift = ccdb->getForTimeStamp(fullCCDBShiftCorrPath, bc.timestamp()); + shiftprofile.push_back(objshift); + } + lastRunNumber = currentRunNumber; + } + } + auto bc = collision.bc_as(); + if (cfgEffCor) { + EffMap = ccdb->getForTimeStamp(cfgEffCorPath.value, bc.timestamp()); + } + if (cfgAccCor) { + AccMap = ccdb->getForTimeStamp(cfgAccCorPath.value, bc.timestamp()); + } + for (int i = 2; i < cfgnMods + 2; i++) { + if (cfgShiftCorrDef) { + FillShiftCorrection(collision, i); + } + if (cfgQAv0) { + FillEPQA(collision, i); + } + FillHistograms(collision, V0s, i); + } // FIXME: need to fill different histograms for different harmonic + } + PROCESS_SWITCH(lambdapolarization, processData, "Process Event for data", true); + + using recoTracks = soa::Join; + void processMC_ITSTPC(aod::McCollision const& mcCollision, soa::Join const& mcParticles, recoTracks const&) + { + float imp = mcCollision.impactParameter(); + float evPhi = mcCollision.eventPlaneAngle() / 2.0; + float centclass = -999; + if (imp >= 0 && imp < 3.49) { + centclass = 2.5; + } + if (imp >= 3.49 && imp < 4.93) { + centclass = 7.5; + } + if (imp >= 4.93 && imp < 6.98) { + centclass = 15.0; + } + if (imp >= 6.98 && imp < 8.55) { + centclass = 25.0; + } + if (imp >= 8.55 && imp < 9.87) { + centclass = 35.0; + } + if (imp >= 9.87 && imp < 11) { + centclass = 45.0; + } + if (imp >= 11 && imp < 12.1) { + centclass = 55.0; + } + if (imp >= 12.1 && imp < 13.1) { + centclass = 65.0; + } + if (imp >= 13.1 && imp < 14) { + centclass = 75.0; + } + // if (evPhi < 0) + // evPhi += 2. * TMath::Pi(); + + int nCh = 0; + + if (centclass > 0 && centclass < 80) { + // event within range + histos.fill(HIST("hImpactParameter"), imp); + histos.fill(HIST("hEventPlaneAngle"), evPhi); + for (auto const& mcParticle : mcParticles) { + + float deltaPhi = mcParticle.phi() - mcCollision.eventPlaneAngle(); + // focus on bulk: e, mu, pi, k, p + int pdgCode = TMath::Abs(mcParticle.pdgCode()); + if (pdgCode != 3122) + continue; + if (!mcParticle.isPhysicalPrimary()) + continue; + if (TMath::Abs(mcParticle.eta()) > 0.8) // main acceptance + continue; + histos.fill(HIST("hSparseMCGenWeight"), centclass, GetPhiInRange(deltaPhi), TMath::Power(TMath::Cos(2.0 * GetPhiInRange(deltaPhi)), 2.0), mcParticle.pt(), mcParticle.eta()); + nCh++; + bool validGlobal = false; + bool validAny = false; + if (mcParticle.has_tracks()) { + auto const& tracks = mcParticle.tracks_as(); + for (auto const& track : tracks) { + if (track.hasTPC() && track.hasITS()) { + validGlobal = true; + } + if (track.hasTPC() || track.hasITS()) { + validAny = true; + } + } + } + // if valid global, fill + if (validGlobal) { + histos.fill(HIST("hSparseMCRecWeight"), centclass, GetPhiInRange(deltaPhi), TMath::Power(TMath::Cos(2.0 * GetPhiInRange(deltaPhi)), 2.0), mcParticle.pt(), mcParticle.eta()); + } + if (validAny) { + histos.fill(HIST("hSparseMCRecAllTrackWeight"), centclass, GetPhiInRange(deltaPhi), TMath::Power(TMath::Cos(2.0 * GetPhiInRange(deltaPhi)), 2.0), mcParticle.pt(), mcParticle.eta()); + histos.fill(HIST("hEventPlaneAngleRec"), GetPhiInRange(deltaPhi)); + } + // if any track present, fill + } + } + histos.fill(HIST("hNchVsImpactParameter"), imp, nCh); + } + PROCESS_SWITCH(lambdapolarization, processMC_ITSTPC, "Process MC for ITSTPC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"lf-lambdapolarization"})}; +} diff --git a/PWGLF/Tasks/Strangeness/lambdapolsp.cxx b/PWGLF/Tasks/Strangeness/lambdapolsp.cxx new file mode 100644 index 00000000000..3aab9460e44 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/lambdapolsp.cxx @@ -0,0 +1,1227 @@ +// 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. +// Lambda polarisation task +// prottay.das@cern.ch + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Common/Core/RecoDecay.h" + +#include "TRandom3.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" +#include "TF1.h" + +#include "PWGLF/DataModel/SPCalibrationTables.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/TrackSelection.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "CCDB/BasicCCDBManager.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "Common/DataModel/FT0Corrected.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +using dauTracks = soa::Join; +using v0Candidates = soa::Join; + +struct lambdapolsp { + + int mRunNumber; + Service ccdb; + Service pdg; + + // fill output + Configurable additionalEvSel{"additionalEvSel", false, "additionalEvSel"}; + Configurable additionalEvSel2{"additionalEvSel2", false, "additionalEvSel2"}; + Configurable additionalEvSel3{"additionalEvSel3", false, "additionalEvSel3"}; + Configurable additionalEvSel4{"additionalEvSel4", false, "additionalEvSel4"}; + Configurable globalpt{"globalpt", true, "select tracks based on pt global vs tpc"}; + Configurable cqvas{"cqvas", false, "change q vectors after shift correction"}; + Configurable useprofile{"useprofile", 3, "flag to select profile vs Sparse"}; + Configurable QxyNbins{"QxyNbins", 100, "Number of bins in QxQy histograms"}; + Configurable lbinQxy{"lbinQxy", -5.0, "lower bin value in QxQy histograms"}; + Configurable hbinQxy{"hbinQxy", 5.0, "higher bin value in QxQy histograms"}; + Configurable cfgMaxOccupancy{"cfgMaxOccupancy", 1000, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable cfgMinOccupancy{"cfgMinOccupancy", 0, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable sys{"sys", 1, "flag to select systematic source"}; + Configurable dosystematic{"dosystematic", false, "flag to perform systematic study"}; + Configurable needetaaxis{"needetaaxis", false, "flag to use last axis"}; + // events + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutCentralityMax{"cfgCutCentralityMax", 50.0f, "Accepted maximum Centrality"}; + Configurable cfgCutCentralityMin{"cfgCutCentralityMin", 30.0f, "Accepted minimum Centrality"}; + // proton track cut + Configurable cfgCutPT{"cfgCutPT", 0.15, "PT cut on daughter track"}; + Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; + Configurable cfgCutDCAxy{"cfgCutDCAxy", 0.1f, "DCAxy range for tracks"}; + Configurable cfgCutDCAz{"cfgCutDCAz", 0.1f, "DCAz range for tracks"}; + Configurable cfgITScluster{"cfgITScluster", 5, "Number of ITS cluster"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; + Configurable isPVContributor{"isPVContributor", true, "is PV contributor"}; + Configurable checkwithpub{"checkwithpub", true, "checking results with published"}; + + // Configs for V0 + Configurable ConfV0PtMin{"ConfV0PtMin", 0.f, "Minimum transverse momentum of V0"}; + Configurable ConfV0Rap{"ConfV0Rap", 0.8f, "Rapidity range of V0"}; + Configurable ConfV0DCADaughMax{"ConfV0DCADaughMax", 0.2f, "Maximum DCA between the V0 daughters"}; + Configurable ConfV0CPAMin{"ConfV0CPAMin", 0.9998f, "Minimum CPA of V0"}; + Configurable ConfV0TranRadV0Min{"ConfV0TranRadV0Min", 1.5f, "Minimum transverse radius"}; + Configurable ConfV0TranRadV0Max{"ConfV0TranRadV0Max", 100.f, "Maximum transverse radius"}; + Configurable cMaxV0DCA{"cMaxV0DCA", 1.2, "Maximum V0 DCA to PV"}; + Configurable cMinV0DCAPr{"cMinV0DCAPr", 0.05, "Minimum V0 daughters DCA to PV for Pr"}; + Configurable cMinV0DCAPi{"cMinV0DCAPi", 0.05, "Minimum V0 daughters DCA to PV for Pi"}; + Configurable cMaxV0LifeTime{"cMaxV0LifeTime", 20, "Maximum V0 life time"}; + + // config for V0 daughters + Configurable ConfDaughEta{"ConfDaughEta", 0.8f, "V0 Daugh sel: max eta"}; + Configurable cfgDaughPrPt{"cfgDaughPrPt", 0.4, "minimum daughter proton pt"}; + Configurable cfgDaughPiPt{"cfgDaughPiPt", 0.2, "minimum daughter pion pt"}; + Configurable ConfDaughTPCnclsMin{"ConfDaughTPCnclsMin", 50.f, "V0 Daugh sel: Min. nCls TPC"}; + Configurable ConfDaughPIDCuts{"ConfDaughPIDCuts", 3, "PID selections for Lambda daughters"}; + Configurable usesubdet{"usesubdet", false, "use subdet"}; + Configurable useAccCorr{"useAccCorr", false, "use acceptance correction"}; + Configurable ConfAccPathL{"ConfAccPathL", "Users/p/prottay/My/Object/From379780/Fulldata/NewPbPbpass4_28032025/acccorrL", "Path to acceptance correction for Lambda"}; + Configurable ConfAccPathAL{"ConfAccPathAL", "Users/p/prottay/My/Object/From379780/Fulldata/NewPbPbpass4_28032025/acccorrAL", "Path to acceptance correction for AntiLambda"}; + + Configurable CentNbins{"CentNbins", 16, "Number of bins in cent histograms"}; + Configurable lbinCent{"lbinCent", 0.0, "lower bin value in cent histograms"}; + Configurable hbinCent{"hbinCent", 80.0, "higher bin value in cent histograms"}; + Configurable SANbins{"SANbins", 20, "Number of bins in costhetastar"}; + Configurable lbinSA{"lbinSA", -1.0, "lower bin value in costhetastar histograms"}; + Configurable hbinSA{"hbinSA", 1.0, "higher bin value in costhetastar histograms"}; + Configurable PolNbins{"PolNbins", 20, "Number of bins in polarisation"}; + Configurable lbinPol{"lbinPol", -1.0, "lower bin value in #phi-#psi histograms"}; + Configurable hbinPol{"hbinPol", 1.0, "higher bin value in #phi-#psi histograms"}; + Configurable IMNbins{"IMNbins", 100, "Number of bins in invariant mass"}; + Configurable lbinIM{"lbinIM", 1.0, "lower bin value in IM histograms"}; + Configurable hbinIM{"hbinIM", 1.2, "higher bin value in IM histograms"}; + Configurable resNbins{"resNbins", 50, "Number of bins in reso"}; + Configurable lbinres{"lbinres", 0.0, "lower bin value in reso histograms"}; + Configurable hbinres{"hbinres", 10.0, "higher bin value in reso histograms"}; + Configurable spNbins{"spNbins", 2000, "Number of bins in sp"}; + Configurable lbinsp{"lbinsp", -1.0, "lower bin value in sp histograms"}; + Configurable hbinsp{"hbinsp", 1.0, "higher bin value in sp histograms"}; + + ConfigurableAxis configcentAxis{"configcentAxis", {VARIABLE_WIDTH, 0.0, 10.0, 40.0, 80.0}, "Cent V0M"}; + ConfigurableAxis configthnAxispT{"configthnAxisPt", {VARIABLE_WIDTH, 0.2, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.5, 8.0, 10.0, 100.0}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis configetaAxis{"configetaAxis", {VARIABLE_WIDTH, -0.8, -0.4, -0.2, 0, 0.2, 0.4, 0.8}, "Eta"}; + ConfigurableAxis configthnAxisPol{"configthnAxisPol", {VARIABLE_WIDTH, -1.0, -0.6, -0.2, 0, 0.2, 0.4, 0.8}, "Pol"}; + ConfigurableAxis configbinAxis{"configbinAxis", {VARIABLE_WIDTH, -0.8, -0.4, -0.2, 0, 0.2, 0.4, 0.8}, "BA"}; + // ConfigurableAxis configphiAxis{"configphiAxis", {VARIABLE_WIDTH, 0.0, 0.2, 0.4, 0.8, 1.0, 2.0, 2.5, 3.0, 4.0, 5.0, 5.5, 6.28}, "PhiAxis"}; + + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + AxisSpec thnAxisres{resNbins, lbinres, hbinres, "Reso"}; + AxisSpec thnAxisInvMass{IMNbins, lbinIM, hbinIM, "#it{M} (GeV/#it{c}^{2})"}; + AxisSpec thnAxisCosThetaStar{SANbins, lbinSA, hbinSA, "SA"}; + AxisSpec centAxis = {CentNbins, lbinCent, hbinCent, "V0M (%)"}; + AxisSpec spAxis = {spNbins, lbinsp, hbinsp, "Sp"}; + AxisSpec qxZDCAxis = {QxyNbins, lbinQxy, hbinQxy, "Qx"}; + + std::vector runaxes = {thnAxisInvMass, configthnAxispT, configthnAxisPol, configcentAxis}; + if (needetaaxis) + runaxes.insert(runaxes.end(), {configbinAxis}); + + if (checkwithpub) { + if (useprofile == 2) { + histos.add("hpuxQxpvscentpteta", "hpuxQxpvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuyQypvscentpteta", "hpuyQypvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuxQxtvscentpteta", "hpuxQxtvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuyQytvscentpteta", "hpuyQytvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuxyQxytvscentpteta", "hpuxyQxytvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuxyQxypvscentpteta", "hpuxyQxypvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpoddv1vscentpteta", "hpoddv1vscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpevenv1vscentpteta", "hpevenv1vscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpv21", "hpv21", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpv22", "hpv22", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpv23", "hpv23", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpx2Tx1Ax1Cvscentpteta", "hpx2Tx1Ax1Cvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpx2Ty1Ay1Cvscentpteta", "hpx2Ty1Ay1Cvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpy2Tx1Ay1Cvscentpteta", "hpy2Tx1Ay1Cvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpy2Ty1Ax1Cvscentpteta", "hpy2Ty1Ax1Cvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpx1Ax1Cvscentpteta", "hpx1Ax1Cvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpy1Ay1Cvscentpteta", "hpy1Ay1Cvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpx1Avscentpteta", "hpx1Avscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpx1Cvscentpteta", "hpx1Cvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpy1Avscentpteta", "hpy1Avscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpy1Cvscentpteta", "hpy1Cvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + + histos.add("hpx2Tx1Avscentpteta", "hpx2Tx1Avscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpx2Tx1Cvscentpteta", "hpx2Tx1Cvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpx2Ty1Avscentpteta", "hpx2Ty1Avscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpx2Ty1Cvscentpteta", "hpx2Ty1Cvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpy2Tx1Avscentpteta", "hpy2Tx1Avscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpy2Ty1Cvscentpteta", "hpy2Ty1Cvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpy2Ty1Avscentpteta", "hpy2Ty1Avscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpy2Tx1Cvscentpteta", "hpy2Tx1Cvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpx1Ay1Cvscentpteta", "hpx1Ay1Cvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpy1Ax1Cvscentpteta", "hpy1Ax1Cvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpx2Tvscentpteta", "hpx2Tvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpy2Tvscentpteta", "hpy2Tvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + + histos.add("hpuxvscentpteta", "hpuxvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuyvscentpteta", "hpuyvscentpteta", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + /* + histos.add("hpuxvscentptetaneg", "hpuxvscentptetaneg", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuyvscentptetaneg", "hpuyvscentptetaneg", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + + histos.add("hpuxQxpvscentptetaneg", "hpuxQxpvscentptetaneg", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuyQypvscentptetaneg", "hpuyQypvscentptetaneg", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuxQxtvscentptetaneg", "hpuxQxtvscentptetaneg", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuyQytvscentptetaneg", "hpuyQytvscentptetaneg", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuxyQxytvscentptetaneg", "hpuxyQxytvscentptetaneg", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuxyQxypvscentptetaneg", "hpuxyQxypvscentptetaneg", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpoddv1vscentptetaneg", "hpoddv1vscentptetaneg", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpevenv1vscentptetaneg", "hpevenv1vscentptetaneg", HistType::kTHnSparseF, {centAxis, configthnAxispT, configetaAxis, spAxis}, true); + */ + + histos.add("hpQxtQxpvscent", "hpQxtQxpvscent", HistType::kTHnSparseF, {centAxis, spAxis}, true); + histos.add("hpQytQypvscent", "hpQytQypvscent", HistType::kTHnSparseF, {centAxis, spAxis}, true); + histos.add("hpQxytpvscent", "hpQxytpvscent", HistType::kTHnSparseF, {centAxis, spAxis}, true); + histos.add("hpQxtQypvscent", "hpQxtQypvscent", HistType::kTHnSparseF, {centAxis, spAxis}, true); + histos.add("hpQxpQytvscent", "hpQxpQytvscent", HistType::kTHnSparseF, {centAxis, spAxis}, true); + + histos.add("hpQxpvscent", "hpQxpvscent", HistType::kTHnSparseF, {centAxis, spAxis}, true); + histos.add("hpQxtvscent", "hpQxtvscent", HistType::kTHnSparseF, {centAxis, spAxis}, true); + histos.add("hpQypvscent", "hpQypvscent", HistType::kTHnSparseF, {centAxis, spAxis}, true); + histos.add("hpQytvscent", "hpQytvscent", HistType::kTHnSparseF, {centAxis, spAxis}, true); + } else { + histos.add("hpuxQxpvscentpteta", "hpuxQxpvscentpteta", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuyQypvscentpteta", "hpuyQypvscentpteta", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuxQxtvscentpteta", "hpuxQxtvscentpteta", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuyQytvscentpteta", "hpuyQytvscentpteta", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuxyQxytvscentpteta", "hpuxyQxytvscentpteta", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuxyQxypvscentpteta", "hpuxyQxypvscentpteta", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpoddv1vscentpteta", "hpoddv1vscentpteta", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpevenv1vscentpteta", "hpevenv1vscentpteta", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + + histos.add("hpuxvscentpteta", "hpuxvscentpteta", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuyvscentpteta", "hpuyvscentpteta", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + /*histos.add("hpuxvscentptetaneg", "hpuxvscentptetaneg", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuyvscentptetaneg", "hpuyvscentptetaneg", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + + histos.add("hpuxQxpvscentptetaneg", "hpuxQxpvscentptetaneg", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuyQypvscentptetaneg", "hpuyQypvscentptetaneg", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuxQxtvscentptetaneg", "hpuxQxtvscentptetaneg", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuyQytvscentptetaneg", "hpuyQytvscentptetaneg", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuxyQxytvscentptetaneg", "hpuxyQxytvscentptetaneg", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuxyQxypvscentptetaneg", "hpuxyQxypvscentptetaneg", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpoddv1vscentptetaneg", "hpoddv1vscentptetaneg", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpevenv1vscentptetaneg", "hpevenv1vscentptetaneg", HistType::kTHnSparseF, {configcentAxis, configthnAxispT, configetaAxis, spAxis}, true);*/ + + histos.add("hpQxtQxpvscent", "hpQxtQxpvscent", HistType::kTHnSparseF, {configcentAxis, spAxis}, true); + histos.add("hpQytQypvscent", "hpQytQypvscent", HistType::kTHnSparseF, {configcentAxis, spAxis}, true); + histos.add("hpQxytpvscent", "hpQxytpvscent", HistType::kTHnSparseF, {configcentAxis, spAxis}, true); + histos.add("hpQxtQypvscent", "hpQxtQypvscent", HistType::kTHnSparseF, {configcentAxis, spAxis}, true); + histos.add("hpQxpQytvscent", "hpQxpQytvscent", HistType::kTHnSparseF, {configcentAxis, spAxis}, true); + + histos.add("hpQxpvscent", "hpQxpvscent", HistType::kTHnSparseF, {configcentAxis, spAxis}, true); + histos.add("hpQxtvscent", "hpQxtvscent", HistType::kTHnSparseF, {configcentAxis, spAxis}, true); + histos.add("hpQypvscent", "hpQypvscent", HistType::kTHnSparseF, {configcentAxis, spAxis}, true); + histos.add("hpQytvscent", "hpQytvscent", HistType::kTHnSparseF, {configcentAxis, spAxis}, true); + } + } + + histos.add("hCentrality", "Centrality distribution", kTH1F, {{centAxis}}); + // histos.add("hpsiApsiC", "hpsiApsiC", kTHnSparseF, {psiACAxis, psiACAxis}); + // histos.add("hpsiApsiC", "hpsiApsiC", kTH2F, {psiACAxis, psiACAxis}); + // histos.add("hphiminuspsiA", "hphiminuspisA", kTH1F, {{50, 0, 6.28}}, true); + // histos.add("hphiminuspsiC", "hphiminuspisC", kTH1F, {{50, 0, 6.28}}, true); + // histos.add("hCentrality0", "Centrality distribution0", kTH1F, {{centAxis}}); + // histos.add("hCentrality1", "Centrality distribution1", kTH1F, {{centAxis}}); + // histos.add("hCentrality2", "Centrality distribution2", kTH1F, {{centAxis}}); + // histos.add("hCentrality3", "Centrality distribution3", kTH1F, {{centAxis}}); + + if (!checkwithpub) { + // histos.add("hVtxZ", "Vertex distribution in Z;Z (cm)", kTH1F, {{20, -10.0, 10.0}}); + histos.add("hpRes", "hpRes", HistType::kTHnSparseF, {configcentAxis, thnAxisres}); + histos.add("hpResSin", "hpResSin", HistType::kTHnSparseF, {configcentAxis, thnAxisres}); + /*histos.add("hpCosPsiA", "hpCosPsiA", HistType::kTHnSparseF, {configcentAxis, thnAxisres}); + histos.add("hpCosPsiC", "hpCosPsiC", HistType::kTHnSparseF, {configcentAxis, thnAxisres}); + histos.add("hpSinPsiA", "hpSinPsiA", HistType::kTHnSparseF, {configcentAxis, thnAxisres}); + histos.add("hpSinPsiC", "hpSinPsiC", HistType::kTHnSparseF, {configcentAxis, thnAxisres});*/ + /*histos.add("hcentQxZDCA", "hcentQxZDCA", kTH2F, {{centAxis}, {qxZDCAxis}}); + histos.add("hcentQyZDCA", "hcentQyZDCA", kTH2F, {{centAxis}, {qxZDCAxis}}); + histos.add("hcentQxZDCC", "hcentQxZDCC", kTH2F, {{centAxis}, {qxZDCAxis}}); + histos.add("hcentQyZDCC", "hcentQyZDCC", kTH2F, {{centAxis}, {qxZDCAxis}});*/ + + if (usesubdet) { + histos.add("hSparseLambdaCosPsiA", "hSparseLambdaCosPsiA", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseLambdaSinPsiA", "hSparseLambdaSinPsiA", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseLambdaCosPsiC", "hSparseLambdaCosPsiC", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseLambdaSinPsiC", "hSparseLambdaSinPsiC", HistType::kTHnSparseF, runaxes, true); + } + histos.add("hSparseLambdaCosPsi", "hSparseLambdaCosPsi", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseLambdaSinPsi", "hSparseLambdaSinPsi", HistType::kTHnSparseF, runaxes, true); + if (usesubdet) { + histos.add("hSparseAntiLambdaCosPsiA", "hSparseAntiLambdaCosPsiA", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseAntiLambdaSinPsiA", "hSparseAntiLambdaSinPsiA", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseAntiLambdaCosPsiC", "hSparseAntiLambdaCosPsiC", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseAntiLambdaSinPsiC", "hSparseAntiLambdaSinPsiC", HistType::kTHnSparseF, runaxes, true); + } + histos.add("hSparseAntiLambdaCosPsi", "hSparseAntiLambdaCosPsi", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseAntiLambdaSinPsi", "hSparseAntiLambdaSinPsi", HistType::kTHnSparseF, runaxes, true); + + histos.add("hSparseLambdaPol", "hSparseLambdaPol", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseLambdaPolwgt", "hSparseLambdaPolwgt", HistType::kTHnSparseF, runaxes, true); + if (usesubdet) { + histos.add("hSparseLambdaPolA", "hSparseLambdaPolA", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseLambdaPolC", "hSparseLambdaPolC", HistType::kTHnSparseF, runaxes, true); + } + histos.add("hSparseAntiLambdaPol", "hSparseAntiLambdaPol", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseAntiLambdaPolwgt", "hSparseAntiLambdaPolwgt", HistType::kTHnSparseF, runaxes, true); + if (usesubdet) { + histos.add("hSparseAntiLambdaPolA", "hSparseAntiLambdaPolA", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseAntiLambdaPolC", "hSparseAntiLambdaPolC", HistType::kTHnSparseF, runaxes, true); + } + histos.add("hSparseLambda_corr1a", "hSparseLambda_corr1a", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseLambda_corr1b", "hSparseLambda_corr1b", HistType::kTHnSparseF, runaxes, true); + // histos.add("hSparseLambda_corr1c", "hSparseLambda_corr1c", HistType::kTHnSparseF, {thnAxisInvMass, configthnAxispT, configphiAxis, configcentAxis, configbinAxis}, true); + histos.add("hSparseAntiLambda_corr1a", "hSparseAntiLambda_corr1a", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseAntiLambda_corr1b", "hSparseAntiLambda_corr1b", HistType::kTHnSparseF, runaxes, true); + // histos.add("hSparseAntiLambda_corr1c", "hSparseAntiLambda_corr1c", HistType::kTHnSparseF, {thnAxisInvMass, configthnAxispT, configphiAxis, configcentAxis, configbinAxis}, true); + + histos.add("hSparseLambda_corr2a", "hSparseLambda_corr2a", HistType::kTHnSparseF, runaxes, true); + // histos.add("hSparseLambda_corr2b", "hSparseLambda_corr2b", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseAntiLambda_corr2a", "hSparseAntiLambda_corr2a", HistType::kTHnSparseF, runaxes, true); + // histos.add("hSparseAntiLambda_corr2b", "hSparseAntiLambda_corr2b", HistType::kTHnSparseF, runaxes, true); + } + } + + template + bool selectionTrack(const T& candidate) + { + if (!(candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsFound() > cfgTPCcluster && candidate.itsNClsInnerBarrel() >= 1)) { + return false; + } + return true; + } + + template + bool SelectionV0(Collision const& collision, V0 const& candidate) + { + if (TMath::Abs(candidate.dcav0topv()) > cMaxV0DCA) { + return false; + } + const float pT = candidate.pt(); + const float tranRad = candidate.v0radius(); + const float dcaDaughv0 = TMath::Abs(candidate.dcaV0daughters()); + const float cpav0 = candidate.v0cosPA(); + + float CtauLambda = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massLambda; + // float lowmasscutlambda = cMinLambdaMass; + // float highmasscutlambda = cMaxLambdaMass; + + if (pT < ConfV0PtMin) { + return false; + } + if (dcaDaughv0 > ConfV0DCADaughMax) { + return false; + } + if (cpav0 < ConfV0CPAMin) { + return false; + } + if (tranRad < ConfV0TranRadV0Min) { + return false; + } + if (tranRad > ConfV0TranRadV0Max) { + return false; + } + if (TMath::Abs(CtauLambda) > cMaxV0LifeTime) { + return false; + } + if (TMath::Abs(candidate.yLambda()) > ConfV0Rap) { + return false; + } + return true; + } + template + bool isSelectedV0Daughter(V0 const& candidate, T const& track, int pid) + { + // const auto eta = track.eta(); + // const auto pt = track.pt(); + const auto tpcNClsF = track.tpcNClsFound(); + if (track.tpcNClsCrossedRows() < 70) { + return false; + } + /*if (TMath::Abs(eta) > ConfDaughEta) { + return false; + }*/ + if (tpcNClsF < ConfDaughTPCnclsMin) { + return false; + } + if (track.tpcCrossedRowsOverFindableCls() < 0.8) { + return false; + } + + if (pid == 0 && TMath::Abs(track.tpcNSigmaPr()) > ConfDaughPIDCuts) { + return false; + } + if (pid == 1 && TMath::Abs(track.tpcNSigmaPi()) > ConfDaughPIDCuts) { + return false; + } + if (pid == 0 && (candidate.positivept() < cfgDaughPrPt || candidate.negativept() < cfgDaughPiPt)) { + return false; // doesn´t pass lambda pT sels + } + if (pid == 1 && (candidate.positivept() < cfgDaughPiPt || candidate.negativept() < cfgDaughPrPt)) { + return false; // doesn´t pass antilambda pT sels + } + if (std::abs(candidate.positiveeta()) > ConfDaughEta || std::abs(candidate.negativeeta()) > ConfDaughEta) { + return false; + } + + if (pid == 0 && (TMath::Abs(candidate.dcapostopv()) < cMinV0DCAPr || TMath::Abs(candidate.dcanegtopv()) < cMinV0DCAPi)) { + return false; + } + if (pid == 1 && (TMath::Abs(candidate.dcapostopv()) < cMinV0DCAPi || TMath::Abs(candidate.dcanegtopv()) < cMinV0DCAPr)) { + return false; + } + + return true; + } + + template + bool isCompatible(TV0 const& v0, int pid /*0: lambda, 1: antilambda*/) + { + // checks if this V0 is compatible with the requested hypothesis + + // de-ref track extras + auto posTrackExtra = v0.template posTrackExtra_as(); + auto negTrackExtra = v0.template negTrackExtra_as(); + + // check for desired kinematics + if (pid == 0 && (v0.positivept() < cfgDaughPrPt || v0.negativept() < cfgDaughPiPt)) { + return false; // doesn´t pass lambda pT sels + } + if (pid == 1 && (v0.positivept() < cfgDaughPiPt || v0.negativept() < cfgDaughPrPt)) { + return false; // doesn´t pass antilambda pT sels + } + if (std::abs(v0.positiveeta()) > ConfDaughEta || std::abs(v0.negativeeta()) > ConfDaughEta) { + return false; + } + + // check TPC tracking properties + if (posTrackExtra.tpcNClsCrossedRows() < 70 || negTrackExtra.tpcNClsCrossedRows() < 70) { + return false; + } + if (posTrackExtra.tpcNClsFound() < ConfDaughTPCnclsMin || negTrackExtra.tpcNClsFound() < ConfDaughTPCnclsMin) { + return false; + } + if (posTrackExtra.tpcCrossedRowsOverFindableCls() < 0.8 || negTrackExtra.tpcCrossedRowsOverFindableCls() < 0.8) { + return false; + } + + // check TPC PID + if (pid == 0 && ((std::abs(posTrackExtra.tpcNSigmaPr()) > ConfDaughPIDCuts) || (std::abs(negTrackExtra.tpcNSigmaPi()) > ConfDaughPIDCuts))) { + return false; + } + if (pid == 1 && ((std::abs(posTrackExtra.tpcNSigmaPi()) > ConfDaughPIDCuts) || (std::abs(negTrackExtra.tpcNSigmaPr()) > ConfDaughPIDCuts))) { + return false; + } + + if (pid == 0 && (TMath::Abs(v0.dcapostopv()) < cMinV0DCAPr || TMath::Abs(v0.dcanegtopv()) < cMinV0DCAPi)) { + return false; + } + if (pid == 1 && (TMath::Abs(v0.dcapostopv()) < cMinV0DCAPi || TMath::Abs(v0.dcanegtopv()) < cMinV0DCAPr)) { + return false; + } + + // if we made it this far, it's good + return true; + } + + double GetPhiInRange(double phi) + { + double result = RecoDecay::constrainAngle(phi); + + /* + double result = phi; + while (result < 0) { + // result = result + 2. * TMath::Pi(); + result = result + 2. * o2::constants::math::PI; + } + while (result > 2. * TMath::Pi()) { + // result = result - 2. * TMath::Pi(); + result = result - 2. * o2::constants::math::PI; + }*/ + return result; + } + + bool shouldReject(bool LambdaTag, bool aLambdaTag, + const ROOT::Math::PxPyPzMVector& Lambdadummy, + const ROOT::Math::PxPyPzMVector& AntiLambdadummy) + { + const double minMass = 1.105; + const double maxMass = 1.125; + return (LambdaTag && aLambdaTag && + (Lambdadummy.M() > minMass && Lambdadummy.M() < maxMass) && + (AntiLambdadummy.M() > minMass && AntiLambdadummy.M() < maxMass)); + } + + void fillHistograms(bool tag1, bool tag2, const ROOT::Math::PxPyPzMVector& particle, + const ROOT::Math::PxPyPzMVector& daughter, + double psiZDCC, double psiZDCA, double psiZDC, double centrality, + double candmass, double candpt, float desbinvalue, double acvalue) + { + + ROOT::Math::Boost boost{particle.BoostToCM()}; + auto fourVecDauCM = boost(daughter); + auto phiangle = TMath::ATan2(fourVecDauCM.Py(), fourVecDauCM.Px()); + auto phiminuspsiC = GetPhiInRange(phiangle - psiZDCC); + auto phiminuspsiA = GetPhiInRange(phiangle - psiZDCA); + auto phiminuspsi = GetPhiInRange(phiangle - psiZDC); + auto cosThetaStar = fourVecDauCM.Pz() / fourVecDauCM.P(); + auto sinThetaStar = TMath::Sqrt(1 - (cosThetaStar * cosThetaStar)); + auto PolC = TMath::Sin(phiminuspsiC); + auto PolA = TMath::Sin(phiminuspsiA); + auto Pol = TMath::Sin(phiminuspsi); + + auto sinPhiStar = TMath::Sin(GetPhiInRange(phiangle)); + auto cosPhiStar = TMath::Cos(GetPhiInRange(phiangle)); + // auto sinThetaStarcosphiphiStar = sinThetaStar * TMath::Cos(2 * GetPhiInRange(particle.Phi() - phiangle)); + // auto phiphiStar = GetPhiInRange(particle.Phi() - phiangle); + + acvalue = (4 / 3.14) * acvalue; + // PolC = PolC / acvalue; + // PolA = PolA / acvalue; + // Pol = Pol / acvalue; + auto Polwgt = Pol / acvalue; + + // Fill histograms using constructed names + if (tag2) { + if (needetaaxis) { + if (usesubdet) { + histos.fill(HIST("hSparseAntiLambdaCosPsiA"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCA))), centrality, desbinvalue); + histos.fill(HIST("hSparseAntiLambdaCosPsiC"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCC))), centrality, desbinvalue); + histos.fill(HIST("hSparseAntiLambdaSinPsiA"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCA))), centrality, desbinvalue); + histos.fill(HIST("hSparseAntiLambdaSinPsiC"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCC))), centrality, desbinvalue); + } + histos.fill(HIST("hSparseAntiLambdaCosPsi"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDC))), centrality, desbinvalue); + histos.fill(HIST("hSparseAntiLambdaSinPsi"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDC))), centrality, desbinvalue); + if (usesubdet) { + histos.fill(HIST("hSparseAntiLambdaPolA"), candmass, candpt, PolA, centrality, desbinvalue); + histos.fill(HIST("hSparseAntiLambdaPolC"), candmass, candpt, PolC, centrality, desbinvalue); + } + histos.fill(HIST("hSparseAntiLambdaPol"), candmass, candpt, Pol, centrality, desbinvalue); + histos.fill(HIST("hSparseAntiLambdaPolwgt"), candmass, candpt, Polwgt, centrality, desbinvalue); + histos.fill(HIST("hSparseAntiLambda_corr1a"), candmass, candpt, sinPhiStar, centrality, desbinvalue); + histos.fill(HIST("hSparseAntiLambda_corr1b"), candmass, candpt, cosPhiStar, centrality, desbinvalue); + // histos.fill(HIST("hSparseAntiLambda_corr1c"), candmass, candpt, phiphiStar, centrality, desbinvalue); + histos.fill(HIST("hSparseAntiLambda_corr2a"), candmass, candpt, sinThetaStar, centrality, desbinvalue); + // histos.fill(HIST("hSparseAntiLambda_corr2b"), candmass, candpt, sinThetaStarcosphiphiStar, centrality, desbinvalue); + } else { + if (usesubdet) { + histos.fill(HIST("hSparseAntiLambdaCosPsiA"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCA))), centrality); + histos.fill(HIST("hSparseAntiLambdaCosPsiC"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCC))), centrality); + histos.fill(HIST("hSparseAntiLambdaSinPsiA"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCA))), centrality); + histos.fill(HIST("hSparseAntiLambdaSinPsiC"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCC))), centrality); + } + histos.fill(HIST("hSparseAntiLambdaCosPsi"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDC))), centrality); + histos.fill(HIST("hSparseAntiLambdaSinPsi"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDC))), centrality); + if (usesubdet) { + histos.fill(HIST("hSparseAntiLambdaPolA"), candmass, candpt, PolA, centrality); + histos.fill(HIST("hSparseAntiLambdaPolC"), candmass, candpt, PolC, centrality); + } + histos.fill(HIST("hSparseAntiLambdaPol"), candmass, candpt, Pol, centrality); + histos.fill(HIST("hSparseAntiLambdaPolwgt"), candmass, candpt, Polwgt, centrality); + histos.fill(HIST("hSparseAntiLambda_corr1a"), candmass, candpt, sinPhiStar, centrality); + histos.fill(HIST("hSparseAntiLambda_corr1b"), candmass, candpt, cosPhiStar, centrality); + // histos.fill(HIST("hSparseAntiLambda_corr1c"), candmass, candpt, phiphiStar, centrality); + histos.fill(HIST("hSparseAntiLambda_corr2a"), candmass, candpt, sinThetaStar, centrality); + // histos.fill(HIST("hSparseAntiLambda_corr2b"), candmass, candpt, sinThetaStarcosphiphiStar, centrality); + } + } + if (tag1) { + if (needetaaxis) { + if (usesubdet) { + histos.fill(HIST("hSparseLambdaCosPsiA"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCA))), centrality, desbinvalue); + histos.fill(HIST("hSparseLambdaCosPsiC"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCC))), centrality, desbinvalue); + histos.fill(HIST("hSparseLambdaSinPsiA"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCA))), centrality, desbinvalue); + histos.fill(HIST("hSparseLambdaSinPsiC"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCC))), centrality, desbinvalue); + } + histos.fill(HIST("hSparseLambdaCosPsi"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDC))), centrality, desbinvalue); + histos.fill(HIST("hSparseLambdaSinPsi"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDC))), centrality, desbinvalue); + if (usesubdet) { + histos.fill(HIST("hSparseLambdaPolA"), candmass, candpt, PolA, centrality, desbinvalue); + histos.fill(HIST("hSparseLambdaPolC"), candmass, candpt, PolC, centrality, desbinvalue); + } + histos.fill(HIST("hSparseLambdaPol"), candmass, candpt, Pol, centrality, desbinvalue); + histos.fill(HIST("hSparseLambdaPolwgt"), candmass, candpt, Polwgt, centrality, desbinvalue); + histos.fill(HIST("hSparseLambda_corr1a"), candmass, candpt, sinPhiStar, centrality, desbinvalue); + histos.fill(HIST("hSparseLambda_corr1b"), candmass, candpt, cosPhiStar, centrality, desbinvalue); + // histos.fill(HIST("hSparseLambda_corr1c"), candmass, candpt, phiphiStar, centrality, desbinvalue); + histos.fill(HIST("hSparseLambda_corr2a"), candmass, candpt, sinThetaStar, centrality, desbinvalue); + // histos.fill(HIST("hSparseLambda_corr2b"), candmass, candpt, sinThetaStarcosphiphiStar, centrality, desbinvalue); + } else { + if (usesubdet) { + histos.fill(HIST("hSparseLambdaCosPsiA"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCA))), centrality); + histos.fill(HIST("hSparseLambdaCosPsiC"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCC))), centrality); + histos.fill(HIST("hSparseLambdaSinPsiA"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCA))), centrality); + histos.fill(HIST("hSparseLambdaSinPsiC"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCC))), centrality); + } + histos.fill(HIST("hSparseLambdaCosPsi"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDC))), centrality); + histos.fill(HIST("hSparseLambdaSinPsi"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDC))), centrality); + if (usesubdet) { + histos.fill(HIST("hSparseLambdaPolA"), candmass, candpt, PolA, centrality); + histos.fill(HIST("hSparseLambdaPolC"), candmass, candpt, PolC, centrality); + } + histos.fill(HIST("hSparseLambdaPol"), candmass, candpt, Pol, centrality); + histos.fill(HIST("hSparseLambdaPolwgt"), candmass, candpt, Polwgt, centrality); + histos.fill(HIST("hSparseLambda_corr1a"), candmass, candpt, sinPhiStar, centrality); + histos.fill(HIST("hSparseLambda_corr1b"), candmass, candpt, cosPhiStar, centrality); + // histos.fill(HIST("hSparseLambda_corr1c"), candmass, candpt, phiphiStar, centrality); + histos.fill(HIST("hSparseLambda_corr2a"), candmass, candpt, sinThetaStar, centrality); + // histos.fill(HIST("hSparseLambda_corr2b"), candmass, candpt, sinThetaStarcosphiphiStar, centrality); + } + } + } + + ROOT::Math::PxPyPzMVector Lambda, AntiLambda, Lambdadummy, AntiLambdadummy, Proton, Pion, AntiProton, AntiPion, fourVecDauCM; + ROOT::Math::XYZVector threeVecDauCM, threeVecDauCMXY; + double phiangle = 0.0; + // double angleLambda=0.0; + // double angleAntiLambda=0.0; + double massLambda = o2::constants::physics::MassLambda; + double massPr = o2::constants::physics::MassProton; + double massPi = o2::constants::physics::MassPionCharged; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter centralityFilter = (nabs(aod::cent::centFT0C) < cfgCutCentralityMax && nabs(aod::cent::centFT0C) > cfgCutCentralityMin); + Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPT); + Filter dcaCutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); + + using EventCandidates = soa::Filtered>; + using AllTrackCandidates = soa::Filtered>; + using ResoV0s = aod::V0Datas; + + TProfile2D* accprofileL; + TProfile2D* accprofileAL; + // int currentRunNumber = -999; + // int lastRunNumber = -999; + + using BCsRun3 = soa::Join; + + void processData(EventCandidates::iterator const& collision, AllTrackCandidates const& tracks, ResoV0s const& V0s, BCsRun3 const&) + { + + if (!collision.sel8()) { + return; + } + auto centrality = collision.centFT0C(); + // histos.fill(HIST("hCentrality0"), centrality); + if (!collision.triggereventsp()) { + return; + } + // histos.fill(HIST("hCentrality1"), centrality); + + if (additionalEvSel && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + // histos.fill(HIST("hCentrality2"), centrality); + // if (additionalEvSel2 && (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + if (additionalEvSel2 && (collision.trackOccupancyInTimeRange() > cfgMaxOccupancy || collision.trackOccupancyInTimeRange() < cfgMinOccupancy)) { + return; + } + // histos.fill(HIST("hCentrality3"), centrality); + if (additionalEvSel3 && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + return; + } + + if (additionalEvSel4 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return; + } + + // currentRunNumber = collision.foundBC_as().runNumber(); + auto bc = collision.foundBC_as(); + + auto qxZDCA = collision.qxZDCA(); + auto qxZDCC = collision.qxZDCC(); + auto qyZDCA = collision.qyZDCA(); + auto qyZDCC = collision.qyZDCC(); + auto psiZDCC = collision.psiZDCC(); + auto psiZDCA = collision.psiZDCA(); + + double modqxZDCA; + double modqyZDCA; + double modqxZDCC; + double modqyZDCC; + + if (cqvas) { + modqxZDCA = TMath::Sqrt((qxZDCA * qxZDCA) + (qyZDCA * qyZDCA)) * TMath::Cos(psiZDCA); + modqyZDCA = TMath::Sqrt((qxZDCA * qxZDCA) + (qyZDCA * qyZDCA)) * TMath::Sin(psiZDCA); + modqxZDCC = TMath::Sqrt((qxZDCC * qxZDCC) + (qyZDCC * qyZDCC)) * TMath::Cos(psiZDCC); + modqyZDCC = TMath::Sqrt((qxZDCC * qxZDCC) + (qyZDCC * qyZDCC)) * TMath::Sin(psiZDCC); + } else { + modqxZDCA = qxZDCA; + modqyZDCA = qyZDCA; + modqxZDCC = qxZDCC; + modqyZDCC = qyZDCC; + } + + auto psiZDC = TMath::ATan2((modqyZDCC - modqyZDCA), (modqxZDCC - modqxZDCA)); // full event plane + /*if (useonlypsis) { + psiZDC = psiZDCC - psiZDCA; + }*/ + + histos.fill(HIST("hCentrality"), centrality); + if (!checkwithpub) { + // histos.fill(HIST("hVtxZ"), collision.posZ()); + histos.fill(HIST("hpRes"), centrality, (TMath::Cos(GetPhiInRange(psiZDCA - psiZDCC)))); + histos.fill(HIST("hpResSin"), centrality, (TMath::Sin(GetPhiInRange(psiZDCA - psiZDCC)))); + /*histos.fill(HIST("hpCosPsiA"), centrality, (TMath::Cos(GetPhiInRange(psiZDCA)))); + histos.fill(HIST("hpCosPsiC"), centrality, (TMath::Cos(GetPhiInRange(psiZDCC)))); + histos.fill(HIST("hpSinPsiA"), centrality, (TMath::Sin(GetPhiInRange(psiZDCA)))); + histos.fill(HIST("hpSinPsiC"), centrality, (TMath::Sin(GetPhiInRange(psiZDCC))));*/ + /*histos.fill(HIST("hcentQxZDCA"), centrality, qxZDCA); + histos.fill(HIST("hcentQyZDCA"), centrality, qyZDCA); + histos.fill(HIST("hcentQxZDCC"), centrality, qxZDCC); + histos.fill(HIST("hcentQyZDCC"), centrality, qyZDCC);*/ + } + + ///////////checking v1//////////////////////////////// + if (checkwithpub) { + + auto QxtQxp = modqxZDCA * modqxZDCC; + auto QytQyp = modqyZDCA * modqyZDCC; + auto Qxytp = QxtQxp + QytQyp; + auto QxpQyt = modqxZDCA * modqyZDCC; + auto QxtQyp = modqxZDCC * modqyZDCA; + + histos.fill(HIST("hpQxtQxpvscent"), centrality, QxtQxp); + histos.fill(HIST("hpQytQypvscent"), centrality, QytQyp); + histos.fill(HIST("hpQxytpvscent"), centrality, Qxytp); + histos.fill(HIST("hpQxpQytvscent"), centrality, QxpQyt); + histos.fill(HIST("hpQxtQypvscent"), centrality, QxtQyp); + + histos.fill(HIST("hpQxpvscent"), centrality, modqxZDCA); + histos.fill(HIST("hpQxtvscent"), centrality, modqxZDCC); + histos.fill(HIST("hpQypvscent"), centrality, modqyZDCA); + histos.fill(HIST("hpQytvscent"), centrality, modqyZDCC); + + for (const auto& track : tracks) { + if (!selectionTrack(track)) { + continue; + } + + float sign = track.sign(); + if (sign == 0.0) // removing neutral particles + continue; + + auto ux = TMath::Cos(GetPhiInRange(track.phi())); + auto uy = TMath::Sin(GetPhiInRange(track.phi())); + // auto py=track.py(); + + auto uxQxp = ux * modqxZDCA; + auto uyQyp = uy * modqyZDCA; + auto uxyQxyp = uxQxp + uyQyp; + auto uxQxt = ux * modqxZDCC; + auto uyQyt = uy * modqyZDCC; + auto uxyQxyt = uxQxt + uyQyt; + auto oddv1 = ux * (modqxZDCA - modqxZDCC) + uy * (modqyZDCA - modqyZDCC); + auto evenv1 = ux * (modqxZDCA + modqxZDCC) + uy * (modqyZDCA + modqyZDCC); + auto v21 = TMath::Cos(2 * (GetPhiInRange(track.phi()) - psiZDCA - psiZDCC)); + auto v22 = TMath::Cos(2 * (GetPhiInRange(track.phi()) + psiZDCA - psiZDCC)); + auto v23 = TMath::Cos(2 * (GetPhiInRange(track.phi()) - psiZDC)); + + auto x2Tx1Ax1C = TMath::Cos(2 * GetPhiInRange(track.phi())) * modqxZDCA * modqxZDCC; + auto x2Ty1Ay1C = TMath::Cos(2 * GetPhiInRange(track.phi())) * modqyZDCA * modqyZDCC; + auto y2Tx1Ay1C = TMath::Sin(2 * GetPhiInRange(track.phi())) * modqxZDCA * modqyZDCC; + auto y2Ty1Ax1C = TMath::Sin(2 * GetPhiInRange(track.phi())) * modqyZDCA * modqxZDCC; + auto x1Ax1C = modqxZDCA * modqxZDCC; + auto y1Ay1C = modqyZDCA * modqyZDCC; + auto x1Ay1C = modqxZDCA * modqyZDCC; + auto x1Cy1A = modqxZDCC * modqyZDCA; + + // detector acceptance corrections to match v2{ZDC} + auto x1A = modqxZDCA; + auto x1C = modqxZDCC; + auto y1A = modqyZDCA; + auto y1C = modqyZDCC; + auto x2T = TMath::Cos(2 * GetPhiInRange(track.phi())); + auto y2T = TMath::Sin(2 * GetPhiInRange(track.phi())); + auto x2Tx1A = TMath::Cos(2 * GetPhiInRange(track.phi())) * modqxZDCA; + auto x2Tx1C = TMath::Cos(2 * GetPhiInRange(track.phi())) * modqxZDCC; + auto x2Ty1A = TMath::Cos(2 * GetPhiInRange(track.phi())) * modqyZDCA; + auto x2Ty1C = TMath::Cos(2 * GetPhiInRange(track.phi())) * modqyZDCC; + auto y2Tx1A = TMath::Sin(2 * GetPhiInRange(track.phi())) * modqxZDCA; + auto y2Tx1C = TMath::Sin(2 * GetPhiInRange(track.phi())) * modqxZDCC; + auto y2Ty1A = TMath::Sin(2 * GetPhiInRange(track.phi())) * modqyZDCA; + auto y2Ty1C = TMath::Sin(2 * GetPhiInRange(track.phi())) * modqyZDCC; + + if (globalpt) { + // if (sign > 0) { + histos.fill(HIST("hpuxQxpvscentpteta"), centrality, track.pt(), track.eta(), uxQxp); + histos.fill(HIST("hpuyQypvscentpteta"), centrality, track.pt(), track.eta(), uyQyp); + histos.fill(HIST("hpuxQxtvscentpteta"), centrality, track.pt(), track.eta(), uxQxt); + histos.fill(HIST("hpuyQytvscentpteta"), centrality, track.pt(), track.eta(), uyQyt); + + histos.fill(HIST("hpuxvscentpteta"), centrality, track.pt(), track.eta(), ux); + histos.fill(HIST("hpuyvscentpteta"), centrality, track.pt(), track.eta(), uy); + + histos.fill(HIST("hpuxyQxytvscentpteta"), centrality, track.pt(), track.eta(), uxyQxyt); + histos.fill(HIST("hpuxyQxypvscentpteta"), centrality, track.pt(), track.eta(), uxyQxyp); + histos.fill(HIST("hpoddv1vscentpteta"), centrality, track.pt(), track.eta(), oddv1); + histos.fill(HIST("hpevenv1vscentpteta"), centrality, track.pt(), track.eta(), evenv1); + + histos.fill(HIST("hpv21"), centrality, track.pt(), track.eta(), v21); + histos.fill(HIST("hpv22"), centrality, track.pt(), track.eta(), v22); + histos.fill(HIST("hpv23"), centrality, track.pt(), track.eta(), v23); + + histos.fill(HIST("hpx2Tx1Ax1Cvscentpteta"), centrality, track.pt(), track.eta(), x2Tx1Ax1C); + histos.fill(HIST("hpx2Ty1Ay1Cvscentpteta"), centrality, track.pt(), track.eta(), x2Ty1Ay1C); + histos.fill(HIST("hpy2Tx1Ay1Cvscentpteta"), centrality, track.pt(), track.eta(), y2Tx1Ay1C); + histos.fill(HIST("hpy2Ty1Ax1Cvscentpteta"), centrality, track.pt(), track.eta(), y2Ty1Ax1C); + histos.fill(HIST("hpx2Tvscentpteta"), centrality, track.pt(), track.eta(), x2T); + histos.fill(HIST("hpy2Tvscentpteta"), centrality, track.pt(), track.eta(), y2T); + histos.fill(HIST("hpx2Tx1Avscentpteta"), centrality, track.pt(), track.eta(), x2Tx1A); + histos.fill(HIST("hpx2Tx1Cvscentpteta"), centrality, track.pt(), track.eta(), x2Tx1C); + histos.fill(HIST("hpx2Ty1Avscentpteta"), centrality, track.pt(), track.eta(), x2Ty1A); + histos.fill(HIST("hpx2Ty1Cvscentpteta"), centrality, track.pt(), track.eta(), x2Ty1C); + histos.fill(HIST("hpy2Tx1Avscentpteta"), centrality, track.pt(), track.eta(), y2Tx1A); + histos.fill(HIST("hpy2Ty1Cvscentpteta"), centrality, track.pt(), track.eta(), y2Ty1C); + histos.fill(HIST("hpy2Ty1Avscentpteta"), centrality, track.pt(), track.eta(), y2Ty1A); + histos.fill(HIST("hpy2Tx1Cvscentpteta"), centrality, track.pt(), track.eta(), y2Tx1C); + histos.fill(HIST("hpx1Ax1Cvscentpteta"), centrality, track.pt(), track.eta(), x1Ax1C); + histos.fill(HIST("hpy1Ay1Cvscentpteta"), centrality, track.pt(), track.eta(), y1Ay1C); + histos.fill(HIST("hpx1Ay1Cvscentpteta"), centrality, track.pt(), track.eta(), x1Ay1C); + histos.fill(HIST("hpy1Ax1Cvscentpteta"), centrality, track.pt(), track.eta(), x1Cy1A); + histos.fill(HIST("hpx1Avscentpteta"), centrality, track.pt(), track.eta(), x1A); + histos.fill(HIST("hpx1Cvscentpteta"), centrality, track.pt(), track.eta(), x1C); + histos.fill(HIST("hpy1Avscentpteta"), centrality, track.pt(), track.eta(), y1A); + histos.fill(HIST("hpy1Cvscentpteta"), centrality, track.pt(), track.eta(), y1C); + + /*} else { + histos.fill(HIST("hpuxQxpvscentptetaneg"), centrality, track.pt(), track.eta(), uxQxp); + histos.fill(HIST("hpuyQypvscentptetaneg"), centrality, track.pt(), track.eta(), uyQyp); + histos.fill(HIST("hpuxQxtvscentptetaneg"), centrality, track.pt(), track.eta(), uxQxt); + histos.fill(HIST("hpuyQytvscentptetaneg"), centrality, track.pt(), track.eta(), uyQyt); + + histos.fill(HIST("hpuxvscentptetaneg"), centrality, track.pt(), track.eta(), ux); + histos.fill(HIST("hpuyvscentptetaneg"), centrality, track.pt(), track.eta(), uy); + + histos.fill(HIST("hpuxyQxytvscentptetaneg"), centrality, track.pt(), track.eta(), uxyQxyt); + histos.fill(HIST("hpuxyQxypvscentptetaneg"), centrality, track.pt(), track.eta(), uxyQxyp); + histos.fill(HIST("hpoddv1vscentptetaneg"), centrality, track.pt(), track.eta(), oddv1); + histos.fill(HIST("hpevenv1vscentptetaneg"), centrality, track.pt(), track.eta(), evenv1); + }*/ + } else { + histos.fill(HIST("hpuxQxpvscentpteta"), centrality, track.tpcInnerParam(), track.eta(), uxQxp); + histos.fill(HIST("hpuyQypvscentpteta"), centrality, track.tpcInnerParam(), track.eta(), uyQyp); + histos.fill(HIST("hpuxQxtvscentpteta"), centrality, track.tpcInnerParam(), track.eta(), uxQxt); + histos.fill(HIST("hpuyQytvscentpteta"), centrality, track.tpcInnerParam(), track.eta(), uyQyt); + + histos.fill(HIST("hpuxvscentpteta"), centrality, track.pt(), track.eta(), ux); + histos.fill(HIST("hpuyvscentpteta"), centrality, track.pt(), track.eta(), uy); + + histos.fill(HIST("hpuxyQxytvscentpteta"), centrality, track.tpcInnerParam(), track.eta(), uxyQxyt); + histos.fill(HIST("hpuxyQxypvscentpteta"), centrality, track.tpcInnerParam(), track.eta(), uxyQxyp); + histos.fill(HIST("hpoddv1vscentpteta"), centrality, track.pt(), track.eta(), oddv1); + histos.fill(HIST("hpevenv1vscentpteta"), centrality, track.pt(), track.eta(), evenv1); + } + } + } else { + for (const auto& v0 : V0s) { + + auto postrack = v0.template posTrack_as(); + auto negtrack = v0.template negTrack_as(); + + int LambdaTag = 0; + int aLambdaTag = 0; + + const auto signpos = postrack.sign(); + const auto signneg = negtrack.sign(); + + if (signpos < 0 || signneg > 0) { + continue; + } + + if (isSelectedV0Daughter(v0, postrack, 0) && isSelectedV0Daughter(v0, negtrack, 1)) { + LambdaTag = 1; + } + if (isSelectedV0Daughter(v0, negtrack, 0) && isSelectedV0Daughter(v0, postrack, 1)) { + aLambdaTag = 1; + } + + if (!LambdaTag && !aLambdaTag) + continue; + + if (!SelectionV0(collision, v0)) { + continue; + } + + if (LambdaTag) { + Proton = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), massPr); + AntiPion = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), massPi); + Lambdadummy = Proton + AntiPion; + // angleLambda = calculateAngleBetweenLorentzVectors(Proton, AntiPion); + } + if (aLambdaTag) { + AntiProton = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), massPr); + Pion = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), massPi); + AntiLambdadummy = AntiProton + Pion; + // angleAntiLambda = calculateAngleBetweenLorentzVectors(AntiProton, Pion); + } + + if (shouldReject(LambdaTag, aLambdaTag, Lambdadummy, AntiLambdadummy)) { + continue; + } + + if (TMath::Abs(v0.eta()) > 0.8) + continue; + + int taga = LambdaTag; + int tagb = aLambdaTag; + + // if (useAccCorr && (currentRunNumber != lastRunNumber)) { + if (useAccCorr) { + accprofileL = ccdb->getForTimeStamp(ConfAccPathL.value, bc.timestamp()); + accprofileAL = ccdb->getForTimeStamp(ConfAccPathAL.value, bc.timestamp()); + } + + float desbinvalue = 0.0; + if (dosystematic) { + //////////////////////////////////////////////////// + float LTsys = TMath::Abs(v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massLambda); + float CPAsys = v0.v0cosPA(); + float DCADaughsys = TMath::Abs(v0.dcaV0daughters()); + float DCApossys = TMath::Abs(v0.dcapostopv()); + float DCAnegsys = TMath::Abs(v0.dcanegtopv()); + float sysvar = -999.9; + double syst[10]; + if (sys == 1) { + double temp[10] = {26, 27, 28, 29, 30, 31, 32, 33, 34, 35}; + std::copy(std::begin(temp), std::end(temp), std::begin(syst)); + sysvar = LTsys; + } + if (sys == 2) { + double temp[10] = {0.992, 0.993, 0.9935, 0.994, 0.9945, 0.995, 0.9955, 0.996, 0.9965, 0.997}; + std::copy(std::begin(temp), std::end(temp), std::begin(syst)); + sysvar = CPAsys; + } + if (sys == 3) { + double temp[10] = {0.8, 0.85, 0.9, 0.95, 1.0, 1.05, 1.1, 1.15, 1.2, 1.25}; + std::copy(std::begin(temp), std::end(temp), std::begin(syst)); + sysvar = DCADaughsys; + } + if (sys == 4) { + double temp[10] = {0.05, 0.07, 0.1, 0.15, 0.18, 0.2, 0.22, 0.25, 0.28, 0.3}; + std::copy(std::begin(temp), std::end(temp), std::begin(syst)); + sysvar = DCApossys; + } + if (sys == 5) { + double temp[10] = {0.05, 0.07, 0.1, 0.15, 0.18, 0.2, 0.22, 0.25, 0.28, 0.3}; + std::copy(std::begin(temp), std::end(temp), std::begin(syst)); + sysvar = DCAnegsys; + } + + for (int i = 0; i < 10; i++) { + if (sys == 1 || sys == 3) { + if (sysvar < syst[i]) + desbinvalue = i + 0.5; + else + continue; + } + if (sys == 2 || sys == 4 || sys == 5) { + if (sysvar > syst[i]) + desbinvalue = i + 0.5; + else + continue; + } + + /////////////////////////////////////////////////// + if (LambdaTag) { + Lambda = Proton + AntiPion; + tagb = 0; + int binx = accprofileL->GetXaxis()->FindBin(v0.eta()); + int biny = accprofileL->GetYaxis()->FindBin(v0.pt()); + double acvalue = accprofileL->GetBinContent(binx, biny); + fillHistograms(taga, tagb, Lambda, Proton, psiZDCC, psiZDCA, psiZDC, centrality, v0.mLambda(), v0.pt(), desbinvalue, acvalue); + } + + tagb = aLambdaTag; + if (aLambdaTag) { + AntiLambda = AntiProton + Pion; + taga = 0; + int binx = accprofileAL->GetXaxis()->FindBin(v0.eta()); + int biny = accprofileAL->GetYaxis()->FindBin(v0.pt()); + double acvalue = accprofileAL->GetBinContent(binx, biny); + fillHistograms(taga, tagb, AntiLambda, AntiProton, psiZDCC, psiZDCA, psiZDC, centrality, v0.mAntiLambda(), v0.pt(), desbinvalue, acvalue); + } + } + } else { + if (LambdaTag) { + Lambda = Proton + AntiPion; + tagb = 0; + int binx = accprofileL->GetXaxis()->FindBin(v0.eta()); + int biny = accprofileL->GetYaxis()->FindBin(v0.pt()); + double acvalue = accprofileL->GetBinContent(binx, biny); + fillHistograms(taga, tagb, Lambda, Proton, psiZDCC, psiZDCA, psiZDC, centrality, v0.mLambda(), v0.pt(), v0.eta(), acvalue); + } + + tagb = aLambdaTag; + if (aLambdaTag) { + AntiLambda = AntiProton + Pion; + taga = 0; + int binx = accprofileAL->GetXaxis()->FindBin(v0.eta()); + int biny = accprofileAL->GetYaxis()->FindBin(v0.pt()); + double acvalue = accprofileAL->GetBinContent(binx, biny); + fillHistograms(taga, tagb, AntiLambda, AntiProton, psiZDCC, psiZDCA, psiZDC, centrality, v0.mAntiLambda(), v0.pt(), v0.eta(), acvalue); + } + } + } + } + // lastRunNumber = currentRunNumber; + } + PROCESS_SWITCH(lambdapolsp, processData, "Process data", true); + + // process function for derived data - mimics the functionality of the original data + void processDerivedData(soa::Join::iterator const& collision, v0Candidates const& V0s, dauTracks const&, BCsRun3 const&) + { + //___________________________________________________________________________________________________ + // event selection + if (!collision.sel8()) { + return; + } + auto centrality = collision.centFT0C(); + if (!collision.triggereventsp()) { // provided by StraZDCSP + return; + } + + if (additionalEvSel && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + // histos.fill(HIST("hCentrality2"), centrality); + // if (additionalEvSel2 && (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + if (additionalEvSel2 && (collision.trackOccupancyInTimeRange() > cfgMaxOccupancy || collision.trackOccupancyInTimeRange() < cfgMinOccupancy)) { + return; + } + // histos.fill(HIST("hCentrality3"), centrality); + if (additionalEvSel3 && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + return; + } + + if (additionalEvSel4 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return; + } + + /*currentRunNumber = collision.foundBC_as().runNumber(); + auto bc = collision.foundBC_as(); + + if (useAccCorr && (currentRunNumber != lastRunNumber)) { + accprofileL = ccdb->getForTimeStamp(ConfAccPathL.value, bc.timestamp()); + accprofileAL = ccdb->getForTimeStamp(ConfAccPathAL.value, bc.timestamp()); + } + */ + //___________________________________________________________________________________________________ + // retrieve further info provided by StraZDCSP + auto qxZDCA = collision.qxZDCA(); + auto qxZDCC = collision.qxZDCC(); + auto qyZDCA = collision.qyZDCA(); + auto qyZDCC = collision.qyZDCC(); + auto psiZDCC = collision.psiZDCC(); + auto psiZDCA = collision.psiZDCA(); + double modqxZDCA; + double modqyZDCA; + double modqxZDCC; + double modqyZDCC; + + if (cqvas) { + modqxZDCA = TMath::Sqrt((qxZDCA * qxZDCA) + (qyZDCA * qyZDCA)) * TMath::Cos(psiZDCA); + modqyZDCA = TMath::Sqrt((qxZDCA * qxZDCA) + (qyZDCA * qyZDCA)) * TMath::Sin(psiZDCA); + modqxZDCC = TMath::Sqrt((qxZDCC * qxZDCC) + (qyZDCC * qyZDCC)) * TMath::Cos(psiZDCC); + modqyZDCC = TMath::Sqrt((qxZDCC * qxZDCC) + (qyZDCC * qyZDCC)) * TMath::Sin(psiZDCC); + } else { + modqxZDCA = qxZDCA; + modqyZDCA = qyZDCA; + modqxZDCC = qxZDCC; + modqyZDCC = qyZDCC; + } + + auto psiZDC = TMath::ATan2((modqyZDCC - modqyZDCA), (modqxZDCC - modqxZDCA)); // full event plane + + // fill histograms + histos.fill(HIST("hCentrality"), centrality); + if (!checkwithpub) { + // histos.fill(HIST("hVtxZ"), collision.posZ()); + histos.fill(HIST("hpRes"), centrality, (TMath::Cos(GetPhiInRange(psiZDCA - psiZDCC)))); + histos.fill(HIST("hpResSin"), centrality, (TMath::Sin(GetPhiInRange(psiZDCA - psiZDCC)))); + /*histos.fill(HIST("hpCosPsiA"), centrality, (TMath::Cos(GetPhiInRange(psiZDCA)))); + histos.fill(HIST("hpCosPsiC"), centrality, (TMath::Cos(GetPhiInRange(psiZDCC)))); + histos.fill(HIST("hpSinPsiA"), centrality, (TMath::Sin(GetPhiInRange(psiZDCA)))); + histos.fill(HIST("hpSinPsiC"), centrality, (TMath::Sin(GetPhiInRange(psiZDCC))));*/ + } + + //___________________________________________________________________________________________________ + // loop over V0s as necessary + for (const auto& v0 : V0s) { + bool LambdaTag = isCompatible(v0, 0); + bool aLambdaTag = isCompatible(v0, 1); + + if (!LambdaTag && !aLambdaTag) + continue; + + if (!SelectionV0(collision, v0)) { + continue; + } + + if (LambdaTag) { + Proton = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), massPr); + AntiPion = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), massPi); + Lambdadummy = Proton + AntiPion; + // angleLambda = calculateAngleBetweenLorentzVectors(Proton, AntiPion); + } + if (aLambdaTag) { + AntiProton = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), massPr); + Pion = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), massPi); + AntiLambdadummy = AntiProton + Pion; + // angleAntiLambda = calculateAngleBetweenLorentzVectors(AntiProton, Pion); + } + + if (shouldReject(LambdaTag, aLambdaTag, Lambdadummy, AntiLambdadummy)) { + continue; + } + + if (TMath::Abs(v0.eta()) > 0.8) + continue; + + int taga = LambdaTag; + int tagb = aLambdaTag; + + float desbinvalue = 0.0; + if (dosystematic) { + //////////////////////////////////////////////////// + float LTsys = TMath::Abs(v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massLambda); + float CPAsys = v0.v0cosPA(); + float DCADaughsys = TMath::Abs(v0.dcaV0daughters()); + float DCApossys = TMath::Abs(v0.dcapostopv()); + float DCAnegsys = TMath::Abs(v0.dcanegtopv()); + float sysvar = -999.9; + double syst[10]; + if (sys == 1) { + double temp[10] = {26, 27, 28, 29, 30, 31, 32, 33, 34, 35}; + std::copy(std::begin(temp), std::end(temp), std::begin(syst)); + sysvar = LTsys; + } + if (sys == 2) { + double temp[10] = {0.992, 0.993, 0.9935, 0.994, 0.9945, 0.995, 0.9955, 0.996, 0.9965, 0.997}; + std::copy(std::begin(temp), std::end(temp), std::begin(syst)); + sysvar = CPAsys; + } + if (sys == 3) { + double temp[10] = {0.8, 0.85, 0.9, 0.95, 1.0, 1.05, 1.1, 1.15, 1.2, 1.25}; + std::copy(std::begin(temp), std::end(temp), std::begin(syst)); + sysvar = DCADaughsys; + } + if (sys == 4) { + double temp[10] = {0.05, 0.07, 0.1, 0.15, 0.18, 0.2, 0.22, 0.25, 0.28, 0.3}; + std::copy(std::begin(temp), std::end(temp), std::begin(syst)); + sysvar = DCApossys; + } + if (sys == 5) { + double temp[10] = {0.05, 0.07, 0.1, 0.15, 0.18, 0.2, 0.22, 0.25, 0.28, 0.3}; + std::copy(std::begin(temp), std::end(temp), std::begin(syst)); + sysvar = DCAnegsys; + } + + for (int i = 0; i < 10; i++) { + if (sys == 1 || sys == 3) { + if (sysvar < syst[i]) + desbinvalue = i + 0.5; + else + continue; + } + if (sys == 2 || sys == 4 || sys == 5) { + if (sysvar > syst[i]) + desbinvalue = i + 0.5; + else + continue; + } + + /////////////////////////////////////////////////// + if (LambdaTag) { + Lambda = Proton + AntiPion; + tagb = 0; + double acvalue = 1.0; + fillHistograms(taga, tagb, Lambda, Proton, psiZDCC, psiZDCA, psiZDC, centrality, v0.mLambda(), v0.pt(), desbinvalue, acvalue); + } + + tagb = aLambdaTag; + if (aLambdaTag) { + AntiLambda = AntiProton + Pion; + taga = 0; + double acvalue = 1.0; + fillHistograms(taga, tagb, AntiLambda, AntiProton, psiZDCC, psiZDCA, psiZDC, centrality, v0.mAntiLambda(), v0.pt(), desbinvalue, acvalue); + } + } + } else { + if (LambdaTag) { + Lambda = Proton + AntiPion; + tagb = 0; + double acvalue = 1.0; + fillHistograms(taga, tagb, Lambda, Proton, psiZDCC, psiZDCA, psiZDC, centrality, v0.mLambda(), v0.pt(), v0.eta(), acvalue); + } + + tagb = aLambdaTag; + if (aLambdaTag) { + AntiLambda = AntiProton + Pion; + taga = 0; + double acvalue = 1.0; + fillHistograms(taga, tagb, AntiLambda, AntiProton, psiZDCC, psiZDCA, psiZDC, centrality, v0.mAntiLambda(), v0.pt(), v0.eta(), acvalue); + } + } + } + // lastRunNumber = currentRunNumber; + } + PROCESS_SWITCH(lambdapolsp, processDerivedData, "Process derived data", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"lambdapolsp"})}; +} diff --git a/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx b/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx index d9b0fc15dd8..b658981c5c4 100644 --- a/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx +++ b/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx @@ -9,11 +9,19 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include +#include +#include +#include + +#include "Math/Vector4D.h" + #include "CCDB/BasicCCDBManager.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" #include "DataFormatsParameters/GRPMagField.h" @@ -21,6 +29,8 @@ #include "DataFormatsTPC/BetheBlochAleph.h" #include "DCAFitter/DCAFitterN.h" #include "DetectorsBase/Propagator.h" +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ASoA.h" @@ -37,11 +47,38 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +namespace +{ struct NPCascCandidate { - int globalIndex; + int64_t mcParticleId; + int64_t trackGlobID; + int64_t trackITSID; + int64_t collisionID; + float matchingChi2; + float deltaPt; + float itsClusSize; + bool hasReassociatedCluster; + bool isGoodMatch; + bool isGoodCascade; + int pdgCodeMom; + int pdgCodeITStrack; + bool isFromBeauty; + bool isFromCharm; + uint16_t pvContributors; + uint8_t cascPVContribs; + float pvTimeResolution; + float pvX; + float pvY; + float pvZ; float cascPt; float cascEta; float cascPhi; + float protonPt; + float protonEta; + float pionPt; + float pionEta; + float bachPt; + float bachEta; float cascDCAxy; float cascDCAz; float protonDCAxy; @@ -62,42 +99,46 @@ struct NPCascCandidate { int cascNClusITS; int protonNClusITS; int pionNClusITS; - int bachKaonNClusITS; - int bachPionNClusITS; + int bachNClusITS; int protonNClusTPC; int pionNClusTPC; - int bachKaonNClusTPC; - int bachPionNClusTPC; + int bachNClusTPC; float protonTPCNSigma; float pionTPCNSigma; float bachKaonTPCNSigma; float bachPionTPCNSigma; bool protonHasTOF; bool pionHasTOF; - bool bachKaonHasTOF; - bool bachPionHasTOF; + bool bachHasTOF; float protonTOFNSigma; float pionTOFNSigma; float bachKaonTOFNSigma; float bachPionTOFNSigma; + bool sel8; + float multFT0C; + float multFT0A; }; -struct motherDCA { - float DCAxy; - float DCAz; -}; - -struct daughtersDCA { - float bachDCAxy; - float bachDCAz; - float protonDCAxy; - float protonDCAz; - float pionDCAxy; - float pionDCAz; -}; - -namespace +std::array isFromHF(auto& particle) { + bool fromBeauty = false; + bool fromCharm = false; + if (particle.has_mothers()) { + auto mom = particle.template mothers_as()[0]; + int pdgCodeMom = mom.pdgCode(); + fromBeauty = std::abs(pdgCodeMom) / 5000 == 1 || std::abs(pdgCodeMom) / 500 == 1 || std::abs(pdgCodeMom) == 5; + fromCharm = std::abs(pdgCodeMom) / 4000 == 1 || std::abs(pdgCodeMom) / 400 == 1 || std::abs(pdgCodeMom) == 4; + while (mom.has_mothers()) { + const auto grandma = mom.template mothers_as()[0]; + int pdgCodeGrandma = std::abs(grandma.pdgCode()); + fromBeauty = fromBeauty || (pdgCodeGrandma / 5000 == 1 || pdgCodeGrandma / 500 == 1 || pdgCodeGrandma == 5); + fromCharm = fromCharm || (pdgCodeGrandma / 4000 == 1 || pdgCodeGrandma / 400 == 1 || pdgCodeGrandma == 4); + mom = grandma; + } + } + return {fromBeauty, fromCharm}; +} + static constexpr int nParticles{4}; static constexpr int nCutsPID{2}; static const std::vector matterOrNot{"Matter", "Antimatter"}; @@ -109,17 +150,9 @@ static constexpr float cutsPID[nParticles][nCutsPID]{ {-4.f, +4.f}, /*Pr*/ {-4.f, +4.f}, /*Pi*/ }; -std::shared_ptr h2TPCsignal[nParticles]; -std::shared_ptr h2TPCnSigma[nParticles]; - -std::shared_ptr invMassBCOmega; -std::shared_ptr invMassACOmega; -std::shared_ptr invMassBCXi; -std::shared_ptr invMassACXi; -std::shared_ptr invMassBCV0; -std::shared_ptr invMassACV0; -std::vector candidates; +std::vector gCandidates; +std::vector gCandidatesNT; } // namespace @@ -127,525 +160,214 @@ struct NonPromptCascadeTask { Produces NPCTable; Produces NPCTableMC; + Produces NPCTableNT; + Produces NPCTableMCNT; + Produces NPCTableGen; using TracksExtData = soa::Join; using TracksExtMC = soa::Join; - using CollisionCandidatesRun3 = soa::Join::iterator; + using CollisionCandidatesRun3 = soa::Join; + using CollisionCandidatesRun3MC = soa::Join; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable propToDCA{"propToDCA", true, "create tracks version propagated to PCA"}; - Configurable useAbsDCA{"useAbsDCA", true, "Minimise abs. distance rather than chi2"}; - Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; - Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; - Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; - Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations if chi2/chi2old > this"}; + Configurable cfgPropToPCA{"cfgPropToPCA", true, "create tracks version propagated to PCA"}; + Configurable cfgUseAbsDCA{"cfgUseAbsDCA", true, "Minimise abs. distance rather than chi2"}; + Configurable cfgMaxR{"cfgMaxR", 200., "reject PCA's above this radius"}; + Configurable cfgMaxDZIni{"cfgMaxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; + Configurable cfgMinParamChange{"cfgMinParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; + Configurable cfgMinRelChi2Change{"cfgMinRelChi2Change", 0.9, "stop iterations if chi2/chi2old > this"}; Configurable cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrLUT), "Type of material correction"}; Configurable cfgGRPmagPath{"cfgGRPmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable cfgGRPpath{"cfgGRPpath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable cfgSelectOnlyOmegas{"cfgSelectOnlyOmegas", false, "Toggle to select only Omegas"}; - Configurable cfgCutNclusTPC{"cfgCutNclusTPC", 70, "Minimum number of TPC clusters"}; + Configurable cfgCutNclusTPC{"cfgCutNclusTPC", 70, "Minimum number of TPC clusters"}; + Configurable cfgMinCosPA{"cfgMinCosPA", -1.f, "Minimum cosine of pointing angle"}; Configurable> cfgCutsPID{"particlesCutsPID", {cutsPID[0], nParticles, nCutsPID, particlesNames, cutsNames}, "Nuclei PID selections"}; + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", true, "Skimmed dataset processing"}; - Service ccdb; + Zorro mZorro; + OutputObj mZorroSummary{"ZorroSummary"}; + + Service mCCDB; int mRunNumber = 0; - float bz = 0.f; - - HistogramRegistry registry{ - "registry", - { - {"h_dca_Omega", "DCA;DCA (cm)", {HistType::kTH1D, {{200, 0., .5}}}}, - {"h_dcaxy_Omega", "DCA xy;DCA_{xy} (cm)", {HistType::kTH1D, {{200, -.5, .5}}}}, - {"h_dcaz_Omega", "DCA z;DCA_{z} (cm)", {HistType::kTH1D, {{200, -.5, .5}}}}, - {"h_bachdcaxyM_Omega", "Bachelor DCA xy;DCA_{xy} (cm)", {HistType::kTH1D, {{200, -1., 1.}}}}, - {"h_bachdcaxyAM_Omega", "Bachelor DCA xy;DCA_{xy} (cm)", {HistType::kTH1D, {{200, -1., 1.}}}}, - {"h_bachdcazM_Omega", "Bachelor DCA z;DCA_{z} (cm)", {HistType::kTH1D, {{200, -1., 1.}}}}, - {"h_bachdcazAM_Omega", "Bachelor DCA z;DCA_{z} (cm)", {HistType::kTH1D, {{200, -1., 1.}}}}, - {"h_dcavspt_Omega", "DCA vs p_{T};DCA (cm);p_{T} (GeV/#it{c})", {HistType::kTH2D, {{100, -0.1, 0.1}, {50, 0., 10.}}}}, - {"h_bachdcavspt_Omega", "Bachelor DCA vs p_{T};DCA (cm);p_{T} (GeV/#it{c})", {HistType::kTH2D, {{200, -1., 1.}, {50, 0., 10.}}}}, - {"h_bachdcavsr_Omega", "Bachelor DCA vs R (cm);DCA (cm);R (cm)", {HistType::kTH2D, {{200, -1., 1.}, {50, 0., 30.}}}}, - {"h_ntrackdcavspt_Omega", "N track DCA vs p_{T};DCA (cm);p_{T} (GeV/#it{c})", {HistType::kTH2D, {{200, -1., 1.}, {50, 0., 10.}}}}, - {"h_ptrackdcavspt_Omega", "P track DCA vs p_{T};DCA (cm);p_{T} (GeV/#it{c})", {HistType::kTH2D, {{200, -1., 1.}, {50, 0., 10.}}}}, - {"h_dcavsr_Omega", "DCA vs R;DCA (cm);R (cm)", {HistType::kTH2D, {{200, -.5, .5}, {200, 0., 5.}}}}, - {"h_massvspt_Omega", "Mass vs p_{T};Mass (GeV/#it{c}^2);p_{T} (GeV/#it{c})", {HistType::kTH2D, {{125, 1.650, 1.700}, {50, 0., 10.}}}}, - {"h_buildermassvspt_Omega", "Mass (from builder) vs p_{T};Mass (GeV/#it{c}^2);p_{T} (GeV/#it{c})", {HistType::kTH2D, {{125, 1.650, 1.700}, {50, 0., 10.}}}}, - {"h_massvsmass_Omega", "Mass vs mass;Mass (GeV/#it{c}^{2});Mass (GeV/#it{c}^{2})", {HistType::kTH2D, {{125, 1.650, 1.700}, {125, 1.650, 1.700}}}}, - {"h_bachelorsign_Omega", "Bachelor sign;Sign;Counts", {HistType::kTH1D, {{6, -3., 3.}}}}, - - {"h_dca_Xi", "DCA;DCA (cm)", {HistType::kTH1D, {{200, 0., .5}}}}, - {"h_dcaxy_Xi", "DCA xy;DCA_{xy} (cm)", {HistType::kTH1D, {{200, -.5, .5}}}}, - {"h_dcaz_Xi", "DCA z;DCA_{z} (cm)", {HistType::kTH1D, {{200, -.5, .5}}}}, - {"h_bachdcaxyM_Xi", "Bachelor DCA xy;DCA_{xy} (cm)", {HistType::kTH1D, {{200, -1., 1.}}}}, - {"h_bachdcaxyAM_Xi", "Bachelor DCA xy;DCA_{xy} (cm)", {HistType::kTH1D, {{200, -1., 1.}}}}, - {"h_bachdcazM_Xi", "Bachelor DCA z;DCA_{z} (cm)", {HistType::kTH1D, {{200, -1., 1.}}}}, - {"h_bachdcazAM_Xi", "Bachelor DCA z;DCA_{z} (cm)", {HistType::kTH1D, {{200, -1., 1.}}}}, - {"h_dcavspt_Xi", "DCA vs p_{T};DCA (cm);p_{T} (GeV/#it{c})", {HistType::kTH2D, {{100, -0.1, 0.1}, {50, 0., 10.}}}}, - {"h_bachdcavspt_Xi", "Bachelor DCA vs p_{T};DCA (cm);p_{T} (GeV/#it{c})", {HistType::kTH2D, {{200, -1., 1.}, {50, 0., 10.}}}}, - {"h_bachdcavsr_Xi", "Bachelor DCA vs R (cm);DCA (cm);R (cm)", {HistType::kTH2D, {{200, -1., 1.}, {50, 0., 30.}}}}, - {"h_ntrackdcavspt_Xi", "N track DCA vs p_{T};DCA (cm);p_{T} (GeV/#it{c})", {HistType::kTH2D, {{200, -1., 1.}, {50, 0., 10.}}}}, - {"h_ptrackdcavspt_Xi", "P track DCA vs p_{T};DCA (cm);p_{T} (GeV/#it{c})", {HistType::kTH2D, {{200, -1., 1.}, {50, 0., 10.}}}}, - {"h_dcavsr_Xi", "DCA vs R;DCA (cm);R (cm)", {HistType::kTH2D, {{200, -.5, .5}, {200, 0., 5.}}}}, - {"h_massvspt_Xi", "Mass vs p_{T};Mass (GeV/#it{c}^2);p_{T} (GeV/#it{c})", {HistType::kTH2D, {{125, 1.296, 1.346}, {50, 0., 10.}}}}, - {"h_buildermassvspt_Xi", "Mass (from builder) vs p_{T};Mass (GeV/#it{c}^2);p_{T} (GeV/#it{c})", {HistType::kTH2D, {{125, 1.296, 1.346}, {50, 0., 10.}}}}, - {"h_massvsmass_Xi", "Mass vs mass;Mass (GeV/#it{c}^{2});Mass (GeV/#it{c}^{2})", {HistType::kTH2D, {{125, 1.296, 1.346}, {125, 1.296, 1.346}}}}, - {"h_bachelorsign_Xi", "Bachelor sign;Sign;Counts", {HistType::kTH1D, {{6, -3., 3.}}}}, - - {"h_massvspt_V0", "Mass vs p_{T};Mass (GeV/#it{c}^2);p_{T} (GeV/#it{c})", {HistType::kTH2D, {{125, 1.090, 1.140}, {50, 0., 10.}}}}, - - }}; + float mBz = 0.f; + o2::vertexing::DCAFitterN<2> mDCAFitter; + + HistogramRegistry mRegistry; void initCCDB(aod::BCsWithTimestamps::iterator const& bc) { - if (mRunNumber != bc.runNumber()) { - mRunNumber = bc.runNumber(); - auto timestamp = bc.timestamp(); - - if (o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(cfgGRPpath, timestamp)) { - o2::base::Propagator::initFieldFromGRP(grpo); - bz = grpo->getNominalL3Field(); - } else if (o2::parameters::GRPMagField* grpmag = ccdb->getForTimeStamp(cfgGRPmagPath, timestamp)) { - o2::base::Propagator::initFieldFromGRP(grpmag); - bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); - LOG(debug) << "bz = " << bz; - } else { - LOG(fatal) << "Got nullptr from CCDB for path " << cfgGRPmagPath << " of object GRPMagField and " << cfgGRPpath << " of object GRPObject for timestamp " << timestamp; - } + if (mRunNumber == bc.runNumber()) { + return; } - return; - } + mRunNumber = bc.runNumber(); - void init(InitContext const&) - { - ccdb->setURL(ccdbUrl); - ccdb->setFatalWhenNull(false); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); + if (o2::parameters::GRPMagField* grpmag = mCCDB->getForRun(cfgGRPmagPath, mRunNumber)) { + o2::base::Propagator::initFieldFromGRP(grpmag); + mBz = static_cast(grpmag->getNominalL3Field()); + } + mDCAFitter.setBz(mBz); if (static_cast(cfgMaterialCorrection.value) == o2::base::Propagator::MatCorrType::USEMatCorrLUT) { - auto* lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get("GLO/Param/MatLUT")); + auto* lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(mCCDB->getForRun("GLO/Param/MatLUT", mRunNumber)); o2::base::Propagator::Instance(true)->setMatLUT(lut); } + } + + void init(InitContext const&) + { + mZorroSummary.setObject(mZorro.getZorroSummary()); + mCCDB->setURL(ccdbUrl); + mCCDB->setFatalWhenNull(true); + mCCDB->setCaching(true); + mCCDB->setLocalObjectValidityChecking(); + + mDCAFitter.setPropagateToPCA(cfgPropToPCA); + mDCAFitter.setMaxR(cfgMaxR); + mDCAFitter.setMaxDZIni(cfgMaxDZIni); + mDCAFitter.setMinParamChange(cfgMinParamChange); + mDCAFitter.setMinRelChi2Change(cfgMinRelChi2Change); + mDCAFitter.setUseAbsDCA(cfgUseAbsDCA); std::vector ptBinning = {0.4, 0.8, 1.2, 1.6, 2.0, 2.4, 2.8, 3.2, 3.6, 4.0, 4.4, 4.8, 5.2, 5.6, 6.0}; AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; - auto cutsOmega{std::get>(registry.add("h_PIDcutsOmega", ";;Invariant mass (GeV/#it{c}^{2})", HistType::kTH2D, {{6, -0.5, 5.5}, {125, 1.650, 1.700}}))}; - cutsOmega->GetXaxis()->SetBinLabel(1, "Tot #Omega"); - cutsOmega->GetXaxis()->SetBinLabel(2, "hasTof"); - cutsOmega->GetXaxis()->SetBinLabel(3, "nClusTPC"); - cutsOmega->GetXaxis()->SetBinLabel(4, "nSigmaTPCbach"); - cutsOmega->GetXaxis()->SetBinLabel(5, "nSigmaTPCprotontrack"); - cutsOmega->GetXaxis()->SetBinLabel(6, "nSigmaTPCpiontrack"); - - auto cutsXi{std::get>(registry.add("h_PIDcutsXi", ";;Invariant mass (GeV/#it{c}^{2})", HistType::kTH2D, {{6, -0.5, 5.5}, {125, 1.296, 1.346}}))}; - cutsXi->GetXaxis()->SetBinLabel(1, "Tot #Xi"); - cutsXi->GetXaxis()->SetBinLabel(2, "hasTof"); - cutsXi->GetXaxis()->SetBinLabel(3, "nClusTPC"); - cutsXi->GetXaxis()->SetBinLabel(4, "nSigmaTPCbach"); - cutsXi->GetXaxis()->SetBinLabel(5, "nSigmaTPCprotontrack"); - cutsXi->GetXaxis()->SetBinLabel(6, "nSigmaTPCpiontrack"); - - invMassBCOmega = registry.add("h_invariantmass_beforeCuts_Omega", "Invariant Mass (GeV/#it{c}^{2})", HistType::kTH1D, {{125, 1.650, 1.700, "Invariant Mass (GeV/#it{c}^{2})"}}); - invMassACOmega = registry.add("h_invariantmass_afterCuts_Omega", "Invariant Mass (GeV/#it{c}^{2})", HistType::kTH1D, {{125, 1.650, 1.700, "Invariant Mass (GeV/#it{c}^{2})"}}); - invMassBCXi = registry.add("h_invariantmass_beforeCuts_Xi", "Invariant Mass (GeV/#it{c}^{2})", HistType::kTH1D, {{125, 1.296, 1.346, "Invariant Mass (GeV/#it{c}^{2})"}}); - invMassACXi = registry.add("h_invariantmass_afterCuts_Xi", "Invariant Mass (GeV/#it{c}^{2})", HistType::kTH1D, {{125, 1.296, 1.346, "Invariant Mass (GeV/#it{c}^{2})"}}); - invMassBCV0 = registry.add("h_invariantmass_beforeCuts_V0", "Invariant Mass (GeV/#it{c}^{2})", HistType::kTH1D, {{125, 1.090, 1.140, "Invariant Mass (GeV/#it{c}^{2})"}}); - invMassACV0 = registry.add("h_invariantmass_afterCuts_V0", "Invariant Mass (GeV/#it{c}^{2})", HistType::kTH1D, {{125, 1.090, 1.140, "Invariant Mass (GeV/#it{c}^{2})"}}); - } + std::array cutsNames{"# candidates", "hasTOF", "nClusTPC", "nSigmaTPCbach", "nSigmaTPCprotontrack", "nSigmaTPCpiontrack", "cosPA"}; + auto cutsOmega{std::get>(mRegistry.add("h_PIDcutsOmega", ";;Invariant mass (GeV/#it{c}^{2})", HistType::kTH2D, {{cutsNames.size(), -0.5, -0.5 + cutsNames.size()}, {125, 1.650, 1.700}}))}; + auto cutsXi{std::get>(mRegistry.add("h_PIDcutsXi", ";;Invariant mass (GeV/#it{c}^{2})", HistType::kTH2D, {{6, -0.5, 5.5}, {125, 1.296, 1.346}}))}; - template - void fillCascadeDCA(T const track, PR const& protonTrack, PI const& pionTrack, o2::dataformats::VertexBase primaryVertex, bool isOmega, motherDCA& mDCA) - { - const auto matCorr = static_cast(cfgMaterialCorrection.value); - auto trackCovTrk = getTrackParCov(track); - o2::dataformats::DCA impactParameterTrk; - - if (o2::base::Propagator::Instance()->propagateToDCA(primaryVertex, trackCovTrk, bz, 2.f, matCorr, &impactParameterTrk)) { - if (protonTrack.hasTPC() && pionTrack.hasTPC()) { - if (isOmega) { - registry.fill(HIST("h_dca_Omega"), TMath::Sqrt(impactParameterTrk.getR2())); - registry.fill(HIST("h_dcaxy_Omega"), impactParameterTrk.getY()); - registry.fill(HIST("h_dcaz_Omega"), impactParameterTrk.getZ()); - registry.fill(HIST("h_dcavspt_Omega"), impactParameterTrk.getY(), track.pt()); - registry.fill(HIST("h_dcavsr_Omega"), impactParameterTrk.getY(), std::hypot(track.x(), track.y())); - } - } - - if (protonTrack.hasTPC() && pionTrack.hasTPC()) { - registry.fill(HIST("h_dca_Xi"), TMath::Sqrt(impactParameterTrk.getR2())); - registry.fill(HIST("h_dcaxy_Xi"), impactParameterTrk.getY()); - registry.fill(HIST("h_dcaz_Xi"), impactParameterTrk.getZ()); - registry.fill(HIST("h_dcavspt_Xi"), impactParameterTrk.getY(), track.pt()); - registry.fill(HIST("h_dcavsr_Xi"), impactParameterTrk.getY(), std::hypot(track.x(), track.y())); - } + for (size_t iBin{0}; iBin < cutsNames.size(); ++iBin) { + cutsOmega->GetYaxis()->SetBinLabel(iBin + 1, cutsNames[iBin].c_str()); + cutsXi->GetYaxis()->SetBinLabel(iBin + 1, cutsNames[iBin].c_str()); } - mDCA.DCAxy = impactParameterTrk.getY(); - mDCA.DCAz = impactParameterTrk.getZ(); } - template - void fillDauDCA(TC const& trackedCascade, B const& bachelor, PR const& protonTrack, PI const& pionTrack, o2::dataformats::VertexBase primaryVertex, bool isOmega, daughtersDCA& dDCA) + void zorroAccounting(const auto& collisions) { - const auto matCorr = static_cast(cfgMaterialCorrection.value); - - auto trackCovBach = getTrackParCov(bachelor); - o2::dataformats::DCA impactParameterBach; - if (o2::base::Propagator::Instance()->propagateToDCA(primaryVertex, trackCovBach, bz, 2.f, matCorr, &impactParameterBach)) { - if (isOmega) { - if (bachelor.sign() < 0) { - registry.fill(HIST("h_bachdcaxyM_Omega"), impactParameterBach.getY()); - registry.fill(HIST("h_bachdcazM_Omega"), impactParameterBach.getZ()); - } else if (bachelor.sign() > 0) { - registry.fill(HIST("h_bachdcaxyAM_Omega"), impactParameterBach.getY()); - registry.fill(HIST("h_bachdcazAM_Omega"), impactParameterBach.getZ()); + if (cfgSkimmedProcessing) { + int runNumber{-1}; + for (const auto& coll : collisions) { + auto bc = coll.template bc_as(); + if (runNumber != bc.runNumber()) { + mZorro.initCCDB(mCCDB.service, bc.runNumber(), bc.timestamp(), "fTrackedOmega"); + mZorro.populateHistRegistry(mRegistry, bc.runNumber()); + runNumber = bc.runNumber(); } - registry.fill(HIST("h_bachdcavspt_Omega"), impactParameterBach.getY(), bachelor.pt()); - registry.fill(HIST("h_bachdcavsr_Omega"), impactParameterBach.getY(), std::hypot(trackedCascade.decayX(), trackedCascade.decayY())); - registry.fill(HIST("h_bachelorsign_Omega"), bachelor.sign()); - } - if (bachelor.sign() < 0) { - registry.fill(HIST("h_bachdcaxyM_Xi"), impactParameterBach.getY()); - registry.fill(HIST("h_bachdcazM_Xi"), impactParameterBach.getZ()); - } else if (bachelor.sign() > 0) { - registry.fill(HIST("h_bachdcaxyAM_Xi"), impactParameterBach.getY()); - registry.fill(HIST("h_bachdcazAM_Xi"), impactParameterBach.getZ()); - } - registry.fill(HIST("h_bachdcavspt_Xi"), impactParameterBach.getY(), bachelor.pt()); - registry.fill(HIST("h_bachdcavsr_Xi"), impactParameterBach.getY(), std::hypot(trackedCascade.decayX(), trackedCascade.decayY())); - registry.fill(HIST("h_bachelorsign_Xi"), bachelor.sign()); - } - - auto trackCovNtrack = getTrackParCov(pionTrack); - o2::dataformats::DCA impactParameterPiontrack; - if (o2::base::Propagator::Instance()->propagateToDCA(primaryVertex, trackCovNtrack, bz, 2.f, matCorr, &impactParameterPiontrack)) { - if (isOmega) { - registry.fill(HIST("h_ntrackdcavspt_Omega"), impactParameterPiontrack.getY(), pionTrack.pt()); + mZorro.isSelected(bc.globalBC()); /// Just let Zorro do the accounting } - registry.fill(HIST("h_ntrackdcavspt_Xi"), impactParameterPiontrack.getY(), pionTrack.pt()); } - - auto trackCovPtrack = getTrackParCov(protonTrack); - o2::dataformats::DCA impactParameterProtontrack; - if (o2::base::Propagator::Instance()->propagateToDCA(primaryVertex, trackCovPtrack, bz, 2.f, matCorr, &impactParameterProtontrack)) { - if (isOmega) { - registry.fill(HIST("h_ptrackdcavspt_Omega"), impactParameterProtontrack.getY(), protonTrack.pt()); - } - registry.fill(HIST("h_ptrackdcavspt_Xi"), impactParameterProtontrack.getY(), protonTrack.pt()); - } - - dDCA.bachDCAxy = impactParameterBach.getY(); - dDCA.bachDCAz = impactParameterBach.getZ(); - dDCA.protonDCAxy = impactParameterProtontrack.getY(); - dDCA.protonDCAz = impactParameterProtontrack.getZ(); - dDCA.pionDCAxy = impactParameterPiontrack.getY(); - dDCA.pionDCAz = impactParameterPiontrack.getZ(); } - void processTrackedCascadesMC(CollisionCandidatesRun3 const& collision, - aod::AssignedTrackedCascades const& trackedCascades, aod::Cascades const& /*cascades*/, - aod::V0s const& /*v0s*/, TracksExtMC const& /*tracks*/, - aod::McParticles const& mcParticles, aod::BCsWithTimestamps const&) + template + void fillCandidatesVector(CollisionType const&, auto const& cascades, auto& candidates) { - candidates.clear(); - bool isOmega{false}; - - auto bc = collision.bc_as(); - initCCDB(bc); - - const auto primaryVertex = getPrimaryVertex(collision); - o2::vertexing::DCAFitterN<2> df2; - df2.setBz(bz); - df2.setPropagateToPCA(propToDCA); - df2.setMaxR(maxR); - df2.setMaxDZIni(maxDZIni); - df2.setMinParamChange(minParamChange); - df2.setMinRelChi2Change(minRelChi2Change); - df2.setUseAbsDCA(useAbsDCA); + const auto& getCascade = [](auto const& candidate) { + if constexpr (requires { candidate.cascade(); }) { + return candidate.cascade(); + } else { + return candidate; + } + }; - std::vector mcParticleId; + candidates.clear(); + for (const auto& candidate : cascades) { - for (const auto& trackedCascade : trackedCascades) { + auto collision = candidate.template collision_as(); + auto bc = collision.template bc_as(); + initCCDB(bc); - isOmega = false; + const auto primaryVertex = getPrimaryVertex(collision); - const auto& track = trackedCascade.track_as(); - const auto& casc = trackedCascade.cascade(); - const auto& bachelor = casc.bachelor_as(); + const auto& casc = getCascade(candidate); + const auto& bachelor = casc.template bachelor_as(); const auto& v0 = casc.v0(); - const auto& ptrack = v0.posTrack_as(); - const auto& ntrack = v0.negTrack_as(); + const auto& ptrack = v0.template posTrack_as(); + const auto& ntrack = v0.template negTrack_as(); const auto& protonTrack = bachelor.sign() > 0 ? ntrack : ptrack; const auto& pionTrack = bachelor.sign() > 0 ? ptrack : ntrack; - std::array, 2> momenta; - std::array masses; - - // track propagation - o2::track::TrackParCov trackParCovV0; - o2::track::TrackPar trackParV0; - o2::track::TrackPar trackParBachelor; - - float cascCpa = -1; - float v0Cpa = -1; - - std::array v0Pos = {-999., -999., -999.}; - - if (df2.process(getTrackParCov(pionTrack), getTrackParCov(protonTrack))) { - trackParCovV0 = df2.createParentTrackParCov(0); // V0 track retrieved from p and pi daughters - v0Pos = {trackParCovV0.getX(), trackParCovV0.getY(), trackParCovV0.getZ()}; - if (df2.process(trackParCovV0, getTrackParCov(bachelor))) { - trackParV0 = df2.getTrackParamAtPCA(0); - trackParBachelor = df2.getTrackParamAtPCA(1); - trackParV0.getPxPyPzGlo(momenta[0]); // getting the V0 momentum - trackParBachelor.getPxPyPzGlo(momenta[1]); // getting the bachelor momentum - std::array pVec; - df2.createParentTrackParCov().getPxPyPzGlo(pVec); - std::array pvPos = {primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}; - cascCpa = RecoDecay::cpa(pvPos, df2.getPCACandidate(), pVec); - v0Cpa = RecoDecay::cpa(pvPos, df2.getPCACandidate(), momenta[0]); - } else { - continue; - } - } else { - continue; - } - - // Omega - masses = {o2::constants::physics::MassLambda0, o2::constants::physics::MassKPlus}; - const auto massOmega = RecoDecay::m(momenta, masses); + // first bit for the strange track, second for pos v0, third for neg v0, fourth for bachelor + uint8_t cascPVContribs = 0; + cascPVContribs |= ptrack.isPVContributor() << 1; + cascPVContribs |= ntrack.isPVContributor() << 2; + cascPVContribs |= bachelor.isPVContributor() << 3; - // Xi - masses = {o2::constants::physics::MassLambda0, o2::constants::physics::MassPiPlus}; - const auto massXi = RecoDecay::m(momenta, masses); + mRegistry.fill(HIST("h_PIDcutsXi"), 0, 1.322); + mRegistry.fill(HIST("h_PIDcutsOmega"), 0, 1.675); - // Lambda - masses = {o2::constants::physics::MassProton, o2::constants::physics::MassPiMinus}; - momenta[0] = {protonTrack.px(), protonTrack.py(), protonTrack.pz()}; - momenta[1] = {pionTrack.px(), pionTrack.py(), pionTrack.pz()}; - const auto v0mass = RecoDecay::m(momenta, masses); + mRegistry.fill(HIST("h_PIDcutsXi"), 1, 1.322); + mRegistry.fill(HIST("h_PIDcutsOmega"), 1, 1.675); - ////Omega hypohesis -> rejecting Xi - if (TMath::Abs(massXi - constants::physics::MassXiMinus) > 0.005) { - isOmega = true; - invMassBCOmega->Fill(massOmega); - } - - invMassBCXi->Fill(massXi); - invMassBCV0->Fill(v0mass); - - registry.fill(HIST("h_PIDcutsOmega"), 0, massOmega); - registry.fill(HIST("h_PIDcutsXi"), 0, massXi); - - int bachKaonNClusTPC = -1; - int bachPionNClusTPC = -1; - int bachKaonNClusITS = -1; - int bachPionNClusITS = -1; - if (isOmega) { - bachKaonNClusTPC = bachelor.tpcNClsFound(); - bachKaonNClusITS = bachelor.itsNCls(); - } - bachPionNClusTPC = bachelor.tpcNClsFound(); /// by default cascade = Xi - bachPionNClusITS = bachelor.itsNCls(); /// by default cascade = Xi - - bool bachKaonHasTOF = 0; - bool bachPionHasTOF = 0; - if (isOmega) { - bachKaonHasTOF = bachelor.hasTOF(); - } - bachPionHasTOF = bachelor.hasTOF(); - - // if (!bachelor.hasTOF() && !ptrack.hasTOF() && !ntrack.hasTOF()) { - // LOG(debug) << "no TOF: " << bachelor.hasTOF() << "/" << ptrack.hasTOF() << "/" << ntrack.hasTOF(); - // continue; - // } - - registry.fill(HIST("h_PIDcutsOmega"), 1, massOmega); - registry.fill(HIST("h_PIDcutsXi"), 1, massXi); - - if (protonTrack.tpcNClsFound() < cfgCutNclusTPC || pionTrack.tpcNClsFound() < cfgCutNclusTPC) { - LOG(debug) << "no tpcNClsFound: " << bachelor.tpcNClsFound() << "/" << protonTrack.tpcNClsFound() << "/" << pionTrack.tpcNClsFound(); + if (protonTrack.tpcNClsFound() < cfgCutNclusTPC || pionTrack.tpcNClsFound() < cfgCutNclusTPC || bachelor.tpcNClsFound() < cfgCutNclusTPC) { continue; } - - registry.fill(HIST("h_PIDcutsOmega"), 2, massOmega); - registry.fill(HIST("h_PIDcutsXi"), 2, massXi); + mRegistry.fill(HIST("h_PIDcutsXi"), 2, 1.322); + mRegistry.fill(HIST("h_PIDcutsOmega"), 2, 1.675); // QA PID float nSigmaTPC[nParticles]{bachelor.tpcNSigmaKa(), bachelor.tpcNSigmaPi(), protonTrack.tpcNSigmaPr(), pionTrack.tpcNSigmaPi()}; - if (isOmega) { - if (bachelor.hasTPC()) { - LOG(debug) << "TPCSignal bachelor " << bachelor.sign() << "/" << bachelor.tpcInnerParam() << "/" << bachelor.tpcSignal(); - if (nSigmaTPC[0] < cfgCutsPID->get(0u, 0u) || nSigmaTPC[0] > cfgCutsPID->get(0u, 1u)) { - continue; - } - } - registry.fill(HIST("h_PIDcutsOmega"), 3, massOmega); + bool isBachelorSurvived = false; + if (nSigmaTPC[0] > cfgCutsPID->get(0u, 0u) && nSigmaTPC[0] < cfgCutsPID->get(0u, 1u)) { + mRegistry.fill(HIST("h_PIDcutsOmega"), 3, 1.675); + isBachelorSurvived = true; } - if (bachelor.hasTPC()) { - LOG(debug) << "TPCSignal bachelor " << bachelor.sign() << "/" << bachelor.tpcInnerParam() << "/" << bachelor.tpcSignal(); - if (nSigmaTPC[1] < cfgCutsPID->get(1u, 0u) || nSigmaTPC[1] > cfgCutsPID->get(1u, 1u)) { - continue; - } + if (!cfgSelectOnlyOmegas && nSigmaTPC[1] > cfgCutsPID->get(1u, 0u) && nSigmaTPC[1] < cfgCutsPID->get(1u, 1u)) { + mRegistry.fill(HIST("h_PIDcutsXi"), 3, 1.322); + isBachelorSurvived = true; } - registry.fill(HIST("h_PIDcutsXi"), 3, massXi); - LOG(debug) << "TPCSignal protonTrack " << protonTrack.sign() << "/" << protonTrack.tpcInnerParam() << "/" << protonTrack.tpcSignal(); - if (nSigmaTPC[2] < cfgCutsPID->get(2u, 0u) || nSigmaTPC[2] > cfgCutsPID->get(2u, 1u)) { + if (!isBachelorSurvived) { continue; } - registry.fill(HIST("h_PIDcutsOmega"), 4, massOmega); - registry.fill(HIST("h_PIDcutsXi"), 4, massXi); - - LOG(debug) << "TPCSignal ntrack " << pionTrack.sign() << "/" << pionTrack.tpcInnerParam() << "/" << pionTrack.tpcSignal(); - if (nSigmaTPC[3] < cfgCutsPID->get(3u, 0u) || nSigmaTPC[3] > cfgCutsPID->get(3u, 1u)) { + if (nSigmaTPC[2] < cfgCutsPID->get(2u, 0u) || nSigmaTPC[2] > cfgCutsPID->get(2u, 1u)) { continue; } - registry.fill(HIST("h_PIDcutsXi"), 5, massXi); - - if (isOmega) { - registry.fill(HIST("h_PIDcutsOmega"), 5, massOmega); - invMassACOmega->Fill(massOmega); - registry.fill(HIST("h_massvspt_Omega"), massOmega, track.pt()); - } - - registry.fill(HIST("h_PIDcutsXi"), 5, massXi); - - invMassACXi->Fill(massXi); - registry.fill(HIST("h_massvspt_Xi"), massXi, track.pt()); - - invMassACV0->Fill(v0mass); - registry.fill(HIST("h_massvspt_V0"), v0mass, track.pt()); - - motherDCA mDCA; - fillCascadeDCA(track, protonTrack, pionTrack, primaryVertex, isOmega, mDCA); - - LOGF(debug, "protonTrack (id: %d, pdg: %d) has mother %d", protonTrack.mcParticleId(), - protonTrack.mcParticle().pdgCode(), protonTrack.mcParticle().has_mothers() ? protonTrack.mcParticle().mothersIds()[0] : -1); - LOGF(debug, "pionTrack (id: %d, pdg: %d) has mother %d", pionTrack.mcParticleId(), - pionTrack.mcParticle().pdgCode(), pionTrack.mcParticle().has_mothers() ? pionTrack.mcParticle().mothersIds()[0] : -1); - - LOG(debug) << "bachelor with PDG code: " << bachelor.mcParticle().pdgCode() << ". Charge: " << bachelor.sign(); - if (ptrack.mcParticle().has_mothers() && pionTrack.mcParticle().has_mothers() && - protonTrack.mcParticle().mothersIds()[0] == pionTrack.mcParticle().mothersIds()[0]) { - const auto v0part = protonTrack.mcParticle().mothers_as()[0]; - LOG(debug) << "v0 with PDG code: " << v0part.pdgCode(); - } - daughtersDCA dDCA; - fillDauDCA(trackedCascade, bachelor, protonTrack, pionTrack, primaryVertex, isOmega, dDCA); - - candidates.emplace_back(NPCascCandidate{static_cast(track.globalIndex()), - track.pt(), track.eta(), track.phi(), - mDCA.DCAxy, mDCA.DCAz, dDCA.protonDCAxy, dDCA.protonDCAz, dDCA.pionDCAxy, dDCA.pionDCAz, dDCA.bachDCAxy, dDCA.bachDCAz, - cascCpa, v0Cpa, - massXi, massOmega, v0mass, - std::hypot(trackedCascade.decayX(), trackedCascade.decayY()), std::hypot(v0Pos[0], v0Pos[1]), std::hypot(trackedCascade.decayX(), trackedCascade.decayY(), trackedCascade.decayZ()), std::hypot(v0Pos[0], v0Pos[1], v0Pos[2]), - track.itsNCls(), protonTrack.itsNCls(), pionTrack.itsNCls(), bachKaonNClusITS, bachPionNClusITS, protonTrack.tpcNClsFound(), pionTrack.tpcNClsFound(), bachKaonNClusTPC, bachPionNClusTPC, - protonTrack.tpcNSigmaPr(), pionTrack.tpcNSigmaPi(), bachelor.tpcNSigmaKa(), bachelor.tpcNSigmaPi(), - protonTrack.hasTOF(), pionTrack.hasTOF(), bachKaonHasTOF, bachPionHasTOF, - protonTrack.tofNSigmaPr(), pionTrack.tofNSigmaPi(), bachelor.tofNSigmaKa(), bachelor.tofNSigmaPi()}); - - if (track.mcParticleId() < -1 || track.mcParticleId() >= mcParticles.size()) { - mcParticleId.push_back(-1); - } else { - mcParticleId.push_back(track.mcParticleId()); - } - } // end loop over tracked cascades + mRegistry.fill(HIST("h_PIDcutsOmega"), 4, 1.675); + mRegistry.fill(HIST("h_PIDcutsXi"), 4, 1.322); - for (size_t i = 0; i < candidates.size(); ++i) { - if (mcParticleId[i] < 0) { + if (nSigmaTPC[3] < cfgCutsPID->get(3u, 0u) || nSigmaTPC[3] > cfgCutsPID->get(3u, 1u)) { continue; } - auto particle = mcParticles.iteratorAt(mcParticleId[i]); - auto& c = candidates[i]; - - NPCTableMC(c.cascPt, c.cascEta, c.cascPhi, - c.cascDCAxy, c.cascDCAz, c.protonDCAxy, c.protonDCAz, c.pionDCAxy, c.pionDCAz, c.bachDCAxy, c.bachDCAz, - c.casccosPA, c.v0cosPA, - c.massXi, c.massOmega, c.massV0, - c.cascRadius, c.v0radius, c.cascLength, c.v0length, - c.cascNClusITS, c.protonNClusITS, c.pionNClusITS, c.bachKaonNClusITS, c.bachPionNClusITS, c.protonNClusTPC, c.pionNClusTPC, c.bachKaonNClusTPC, c.bachPionNClusTPC, - c.protonTPCNSigma, c.pionTPCNSigma, c.bachKaonTPCNSigma, c.bachPionTPCNSigma, - c.protonHasTOF, c.pionHasTOF, c.bachKaonHasTOF, c.bachPionHasTOF, - c.protonTOFNSigma, c.pionTOFNSigma, c.bachKaonTOFNSigma, c.bachPionTOFNSigma, - particle.pt(), particle.eta(), particle.phi(), particle.pdgCode()); - } - } - PROCESS_SWITCH(NonPromptCascadeTask, processTrackedCascadesMC, "process cascades from strangeness tracking: MC analysis", true); - - void processTrackedCascadesData(CollisionCandidatesRun3 const& collision, - aod::AssignedTrackedCascades const& trackedCascades, aod::Cascades const& /*cascades*/, - aod::V0s const& /*v0s*/, TracksExtData const& /*tracks*/, - aod::BCsWithTimestamps const&) - { - candidates.clear(); - bool isOmega{false}; - auto bc = collision.bc_as(); - initCCDB(bc); + mRegistry.fill(HIST("h_PIDcutsOmega"), 5, 1.675); + mRegistry.fill(HIST("h_PIDcutsXi"), 5, 1.322); - const auto primaryVertex = getPrimaryVertex(collision); - - o2::vertexing::DCAFitterN<2> df2; - df2.setBz(bz); - df2.setPropagateToPCA(propToDCA); - df2.setMaxR(maxR); - df2.setMaxDZIni(maxDZIni); - df2.setMinParamChange(minParamChange); - df2.setMinRelChi2Change(minRelChi2Change); - df2.setUseAbsDCA(useAbsDCA); - - for (const auto& trackedCascade : trackedCascades) { - - isOmega = false; - - const auto& track = trackedCascade.track_as(); - const auto& casc = trackedCascade.cascade(); - const auto& bachelor = casc.bachelor_as(); - const auto& v0 = casc.v0(); - const auto& ptrack = v0.posTrack_as(); - const auto& ntrack = v0.negTrack_as(); - const auto& protonTrack = bachelor.sign() > 0 ? ntrack : ptrack; - const auto& pionTrack = bachelor.sign() > 0 ? ptrack : ntrack; + auto protonTrkParCov = getTrackParCov(protonTrack); + auto pionTrkParCov = getTrackParCov(pionTrack); + auto bachTrkParCov = getTrackParCov(bachelor); std::array, 2> momenta; - std::array masses; - - // track propagation - o2::track::TrackParCov trackParCovV0; - o2::track::TrackPar trackParV0; - o2::track::TrackPar trackParBachelor; - - float cascCpa = -1; - float v0Cpa = -1; - - std::array v0Pos = {-999., -999., -999.}; - - if (df2.process(getTrackParCov(pionTrack), getTrackParCov(protonTrack))) { - trackParCovV0 = df2.createParentTrackParCov(0); // V0 track retrieved from p and pi daughters - v0Pos = {trackParCovV0.getX(), trackParCovV0.getY(), trackParCovV0.getZ()}; - if (df2.process(trackParCovV0, getTrackParCov(bachelor))) { - trackParV0 = df2.getTrackParamAtPCA(0); - trackParBachelor = df2.getTrackParamAtPCA(1); - trackParV0.getPxPyPzGlo(momenta[0]); // getting the V0 momentum - trackParBachelor.getPxPyPzGlo(momenta[1]); // getting the bachelor momentum - std::array pVec; - df2.createParentTrackParCov().getPxPyPzGlo(pVec); + std::array cascadeMomentum; + o2::math_utils::SVector cascadePos, v0Pos; + + float cascCpa = -1, v0Cpa = -1; + if (mDCAFitter.process(pionTrkParCov, protonTrkParCov)) { + auto trackParCovV0 = mDCAFitter.createParentTrackParCov(0); // V0 track retrieved from p and pi daughters + v0Pos = mDCAFitter.getPCACandidate(); + if (mDCAFitter.process(trackParCovV0, bachTrkParCov)) { + mDCAFitter.getTrackParamAtPCA(0).getPxPyPzGlo(momenta[0]); + mDCAFitter.getTrackParamAtPCA(1).getPxPyPzGlo(momenta[1]); + mDCAFitter.createParentTrackParCov().getPxPyPzGlo(cascadeMomentum); std::array pvPos = {primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}; - cascCpa = RecoDecay::cpa(pvPos, df2.getPCACandidate(), pVec); - v0Cpa = RecoDecay::cpa(pvPos, df2.getPCACandidate(), momenta[0]); + cascadePos = mDCAFitter.getPCACandidate(); + cascCpa = RecoDecay::cpa(pvPos, mDCAFitter.getPCACandidate(), cascadeMomentum); + v0Cpa = RecoDecay::cpa(pvPos, v0Pos, momenta[0]); } else { continue; } } else { continue; } + ROOT::Math::LorentzVector> cascadeLvector; + cascadeLvector.SetPxPyPzE(cascadeMomentum[0], cascadeMomentum[1], cascadeMomentum[2], std::hypot(cascadeMomentum[0], cascadeMomentum[1], cascadeMomentum[2])); /// 0 mass, used only for the momentum // Omega - masses = {o2::constants::physics::MassLambda0, o2::constants::physics::MassKPlus}; + std::array masses{o2::constants::physics::MassLambda0, o2::constants::physics::MassKPlus}; const auto massOmega = RecoDecay::m(momenta, masses); // Xi @@ -658,138 +380,213 @@ struct NonPromptCascadeTask { momenta[1] = {pionTrack.px(), pionTrack.py(), pionTrack.pz()}; const auto v0mass = RecoDecay::m(momenta, masses); - ////Omega hypohesis -> rejecting Xi - if (TMath::Abs(massXi - constants::physics::MassXiMinus) > 0.005) { - isOmega = true; - invMassBCOmega->Fill(massOmega); - } - - invMassBCXi->Fill(massXi); - invMassBCV0->Fill(v0mass); - - registry.fill(HIST("h_PIDcutsXi"), 0, massXi); - registry.fill(HIST("h_PIDcutsOmega"), 0, massOmega); - - int bachKaonNClusTPC = -1; - int bachPionNClusTPC = -1; - int bachKaonNClusITS = -1; - int bachPionNClusITS = -1; - if (isOmega) { - bachKaonNClusTPC = bachelor.tpcNClsFound(); - bachKaonNClusITS = bachelor.itsNCls(); - } - bachPionNClusTPC = bachelor.tpcNClsFound(); /// by default cascade = Xi - bachPionNClusITS = bachelor.itsNCls(); /// by default cascade = Xi - - bool bachKaonHasTOF = 0; - bool bachPionHasTOF = 0; - if (isOmega) { - bachKaonHasTOF = bachelor.hasTOF(); - } - bachPionHasTOF = bachelor.hasTOF(); - - // if (!bachelor.hasTOF() && !ptrack.hasTOF() && !ntrack.hasTOF() ) { - // LOG(debug)<< "no TOF: "< rejecting Xi, we don't do it in the MC as we can identify the particle with the MC truth + bool isOmega{std::abs(massXi - constants::physics::MassXiMinus) > 0.005}; + if (cfgSelectOnlyOmegas && !isOmega) { continue; } - registry.fill(HIST("h_PIDcutsXi"), 2, massXi); - registry.fill(HIST("h_PIDcutsOmega"), 2, massOmega); - // QA PID - float nSigmaTPC[nParticles]{bachelor.tpcNSigmaKa(), bachelor.tpcNSigmaPi(), protonTrack.tpcNSigmaPr(), pionTrack.tpcNSigmaPi()}; - - bool isBachelorSurvived = false; - if (isOmega) { - if (bachelor.hasTPC()) { - LOG(debug) << "TPCSignal bachelor " << bachelor.sign() << "/" << bachelor.tpcInnerParam() << "/" << bachelor.tpcSignal(); - if (nSigmaTPC[0] > cfgCutsPID->get(0u, 0u) && nSigmaTPC[0] < cfgCutsPID->get(0u, 1u)) { - registry.fill(HIST("h_PIDcutsOmega"), 3, massOmega); - isBachelorSurvived = true; + std::array fromHF{false, false}; + bool isGoodMatch{false}, isGoodCascade{false}; + int itsTrackPDG{0}, pdgCodeMom{0}; + int64_t mcParticleID{-1}; + + if constexpr (TrackType::template contains()) { + if (protonTrack.mcParticle().has_mothers() && pionTrack.mcParticle().has_mothers() && bachelor.mcParticle().has_mothers()) { + if (protonTrack.mcParticle().mothersIds()[0] == pionTrack.mcParticle().mothersIds()[0]) { + const auto v0part = protonTrack.mcParticle().template mothers_first_as(); + if (std::abs(v0part.pdgCode()) == 3122 && v0part.has_mothers()) { + const auto motherV0 = v0part.template mothers_as()[0]; + if (v0part.mothersIds()[0] == bachelor.mcParticle().mothersIds()[0]) { + if (std::abs(motherV0.pdgCode()) == 3312 || std::abs(motherV0.pdgCode()) == 3334) { + isGoodCascade = true; + isOmega = (std::abs(motherV0.pdgCode()) == 3334); + fromHF = isFromHF(motherV0); + mcParticleID = v0part.mothersIds()[0]; + } + } + } } } } - if (bachelor.hasTPC()) { - LOG(debug) << "TPCSignal bachelor " << bachelor.sign() << "/" << bachelor.tpcInnerParam() << "/" << bachelor.tpcSignal(); - if (nSigmaTPC[1] > cfgCutsPID->get(1u, 0u) && nSigmaTPC[1] < cfgCutsPID->get(1u, 1u)) { - registry.fill(HIST("h_PIDcutsXi"), 3, massXi); - isBachelorSurvived = true; - } - } - - if (!isBachelorSurvived) { - continue; - } - - LOG(debug) << "TPCSignal protonTrack " << protonTrack.sign() << "/" << protonTrack.tpcInnerParam() << "/" << protonTrack.tpcSignal(); - if (nSigmaTPC[2] < cfgCutsPID->get(2u, 0u) || nSigmaTPC[2] > cfgCutsPID->get(2u, 1u)) { + if (cascCpa < cfgMinCosPA) { continue; } - if (isOmega) { - registry.fill(HIST("h_PIDcutsOmega"), 4, massOmega); + mRegistry.fill(HIST("h_PIDcutsOmega"), 6, massOmega); + } + mRegistry.fill(HIST("h_PIDcutsXi"), 6, massXi); + + const auto matCorr = static_cast(cfgMaterialCorrection.value); + o2::dataformats::DCA motherDCA{-999.f, -999.f}, protonDCA{-999.f, -999.f}, pionDCA{-999.f, -999.f}, bachDCA{-999.f, -999.f}; + o2::base::Propagator::Instance()->propagateToDCA(primaryVertex, protonTrkParCov, mBz, 2.f, matCorr, &protonDCA); + o2::base::Propagator::Instance()->propagateToDCA(primaryVertex, pionTrkParCov, mBz, 2.f, matCorr, &pionDCA); + o2::base::Propagator::Instance()->propagateToDCA(primaryVertex, bachTrkParCov, mBz, 2.f, matCorr, &bachDCA); + + float deltaPtITSCascade{-1.e10f}, cascITSclsSize{-1.e10f}, matchingChi2{-1.e10f}; + bool hasReassociatedClusters{false}; + int trackedCascGlobalIndex{-1}, itsTrackGlobalIndex{-1}, cascITSclusters{-1}; + if constexpr (requires { candidate.track(); }) { + const auto& track = candidate.template track_as(); + cascPVContribs |= track.isPVContributor() << 0; + const auto& ITStrack = candidate.template itsTrack_as(); + auto trackTrkParCov = getTrackParCov(track); + o2::base::Propagator::Instance()->propagateToDCA(primaryVertex, trackTrkParCov, mBz, 2.f, matCorr, &motherDCA); + hasReassociatedClusters = (track.itsNCls() != ITStrack.itsNCls()); + cascadeLvector.SetCoordinates(track.pt(), track.eta(), track.phi(), 0); + deltaPtITSCascade = std::hypot(cascadeMomentum[0], cascadeMomentum[1]) - ITStrack.pt(); + trackedCascGlobalIndex = track.globalIndex(); + itsTrackGlobalIndex = ITStrack.globalIndex(); + cascITSclusters = track.itsNCls(); + cascITSclsSize = candidate.itsClsSize(); + matchingChi2 = candidate.matchingChi2(); + cascadePos = {candidate.decayX(), candidate.decayY(), candidate.decayZ()}; + if constexpr (TrackType::template contains()) { + isGoodMatch = ((mcParticleID == ITStrack.mcParticleId())) ? true : false; + + if (isGoodMatch) { + pdgCodeMom = track.mcParticle().has_mothers() ? track.mcParticle().template mothers_as()[0].pdgCode() : 0; + } + itsTrackPDG = ITStrack.has_mcParticle() ? ITStrack.mcParticle().pdgCode() : 0; + } } - registry.fill(HIST("h_PIDcutsXi"), 4, massXi); + // bool mysel8 = collision.sel8(); + float mc = collision.multFT0C(); + float ma = collision.multFT0A(); + candidates.emplace_back(NPCascCandidate{mcParticleID, trackedCascGlobalIndex, itsTrackGlobalIndex, candidate.collisionId(), matchingChi2, deltaPtITSCascade, cascITSclsSize, hasReassociatedClusters, isGoodMatch, isGoodCascade, pdgCodeMom, itsTrackPDG, fromHF[0], fromHF[1], + collision.numContrib(), cascPVContribs, collision.collisionTimeRes(), primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ(), + cascadeLvector.pt(), cascadeLvector.eta(), cascadeLvector.phi(), + protonTrack.pt(), protonTrack.eta(), pionTrack.pt(), pionTrack.eta(), bachelor.pt(), bachelor.eta(), + motherDCA.getY(), motherDCA.getZ(), protonDCA.getY(), protonDCA.getZ(), pionDCA.getY(), pionDCA.getZ(), bachDCA.getY(), bachDCA.getZ(), + cascCpa, v0Cpa, massXi, massOmega, v0mass, + static_cast(std::hypot(cascadePos[0], cascadePos[1])), static_cast(std::hypot(v0Pos[0], v0Pos[1])), static_cast(std::hypot(cascadePos[0], cascadePos[1], cascadePos[2])), static_cast(std::hypot(v0Pos[0], v0Pos[1], v0Pos[2])), + cascITSclusters, protonTrack.itsNCls(), pionTrack.itsNCls(), bachelor.itsNCls(), protonTrack.tpcNClsFound(), pionTrack.tpcNClsFound(), bachelor.tpcNClsFound(), + protonTrack.tpcNSigmaPr(), pionTrack.tpcNSigmaPi(), bachelor.tpcNSigmaKa(), bachelor.tpcNSigmaPi(), + protonTrack.hasTOF(), pionTrack.hasTOF(), bachelor.hasTOF(), + protonTrack.tofNSigmaPr(), pionTrack.tofNSigmaPi(), bachelor.tofNSigmaKa(), bachelor.tofNSigmaPi(), collision.sel8(), mc, ma}); + } + } - LOG(debug) << "TPCSignal ntrack " << pionTrack.sign() << "/" << pionTrack.tpcInnerParam() << "/" << pionTrack.tpcSignal(); - if (nSigmaTPC[3] < cfgCutsPID->get(3u, 0u) || nSigmaTPC[3] > cfgCutsPID->get(3u, 1u)) { + template + void fillDataTable(auto const& candidates) + { + for (const auto& c : candidates) { + getDataTable()(c.matchingChi2, c.deltaPt, c.itsClusSize, c.hasReassociatedCluster, + c.pvContributors, c.cascPVContribs, c.pvTimeResolution, c.pvX, c.pvY, c.pvZ, + c.cascPt, c.cascEta, c.cascPhi, + c.protonPt, c.protonEta, c.pionPt, c.pionEta, c.bachPt, c.bachEta, + c.cascDCAxy, c.cascDCAz, c.protonDCAxy, c.protonDCAz, c.pionDCAxy, c.pionDCAz, c.bachDCAxy, c.bachDCAz, + c.casccosPA, c.v0cosPA, + c.massXi, c.massOmega, c.massV0, + c.cascRadius, c.v0radius, c.cascLength, c.v0length, + c.cascNClusITS, c.protonNClusITS, c.pionNClusITS, c.bachNClusITS, c.protonNClusTPC, c.pionNClusTPC, c.bachNClusTPC, + c.protonTPCNSigma, c.pionTPCNSigma, c.bachKaonTPCNSigma, c.bachPionTPCNSigma, + c.protonHasTOF, c.pionHasTOF, c.bachHasTOF, + c.protonTOFNSigma, c.pionTOFNSigma, c.bachKaonTOFNSigma, c.bachPionTOFNSigma, c.sel8, c.multFT0C, c.multFT0A); + } + } + + template + void fillMCtable(auto const& mcParticles, auto const& collisions, auto const& candidates) + { + for (size_t i = 0; i < candidates.size(); ++i) { + auto& c = candidates[i]; + if (c.mcParticleId < 0) { continue; } + auto particle = mcParticles.iteratorAt(c.mcParticleId); + auto mcCollision = particle.template mcCollision_as(); + auto recCollision = collisions.iteratorAt(c.collisionID); + + getMCtable()(c.matchingChi2, c.deltaPt, c.itsClusSize, c.hasReassociatedCluster, c.isGoodMatch, c.isGoodCascade, c.pdgCodeMom, c.pdgCodeITStrack, c.isFromBeauty, c.isFromCharm, + c.pvContributors, c.cascPVContribs, c.pvTimeResolution, c.pvX, c.pvY, c.pvZ, c.cascPt, c.cascEta, c.cascPhi, + c.protonPt, c.protonEta, c.pionPt, c.pionEta, c.bachPt, c.bachEta, + c.cascDCAxy, c.cascDCAz, c.protonDCAxy, c.protonDCAz, c.pionDCAxy, c.pionDCAz, c.bachDCAxy, c.bachDCAz, + c.casccosPA, c.v0cosPA, c.massXi, c.massOmega, c.massV0, c.cascRadius, c.v0radius, c.cascLength, c.v0length, + c.cascNClusITS, c.protonNClusITS, c.pionNClusITS, c.bachNClusITS, c.protonNClusTPC, c.pionNClusTPC, c.bachNClusTPC, c.protonTPCNSigma, + c.pionTPCNSigma, c.bachKaonTPCNSigma, c.bachPionTPCNSigma, c.protonHasTOF, c.pionHasTOF, c.bachHasTOF, + c.protonTOFNSigma, c.pionTOFNSigma, c.bachKaonTOFNSigma, c.bachPionTOFNSigma, c.sel8, c.multFT0C, c.multFT0A, + particle.pt(), particle.eta(), particle.phi(), particle.pdgCode(), mcCollision.posX() - particle.vx(), mcCollision.posY() - particle.vy(), + mcCollision.posZ() - particle.vz(), mcCollision.globalIndex() == recCollision.mcCollisionId()); + } + } - if (isOmega) { - registry.fill(HIST("h_PIDcutsOmega"), 5, massOmega); - invMassACOmega->Fill(massOmega); - registry.fill(HIST("h_massvspt_Omega"), massOmega, track.pt()); - } + template + auto& getMCtable() + { + if constexpr (std::is_same_v) { + return NPCTableMCNT; + } else { + return NPCTableMC; + } + } - registry.fill(HIST("h_PIDcutsXi"), 5, massXi); + template + auto& getDataTable() + { + if constexpr (std::is_same_v) { + return NPCTableNT; + } else { + return NPCTable; + } + } - invMassACXi->Fill(massXi); - registry.fill(HIST("h_massvspt_Xi"), massXi, track.pt()); + void processTrackedCascadesMC(CollisionCandidatesRun3MC const& collisions, + aod::AssignedTrackedCascades const& trackedCascades, aod::Cascades const& /*cascades*/, + aod::V0s const& /*v0s*/, TracksExtMC const& /*tracks*/, + aod::McParticles const& mcParticles, aod::McCollisions const&, aod::BCsWithTimestamps const&) + { + fillCandidatesVector(collisions, trackedCascades, gCandidates); + fillMCtable(mcParticles, collisions, gCandidates); + } + PROCESS_SWITCH(NonPromptCascadeTask, processTrackedCascadesMC, "process cascades from strangeness tracking: MC analysis", true); - invMassACV0->Fill(v0mass); - registry.fill(HIST("h_massvspt_V0"), v0mass, track.pt()); + void processCascadesMC(CollisionCandidatesRun3MC const& collisions, aod::Cascades const& cascades, + aod::V0s const& /*v0s*/, TracksExtMC const& /*tracks*/, + aod::McParticles const& mcParticles, aod::McCollisions const&, aod::BCsWithTimestamps const&) + { + fillCandidatesVector(collisions, cascades, gCandidatesNT); + fillMCtable(mcParticles, collisions, gCandidatesNT); + } + PROCESS_SWITCH(NonPromptCascadeTask, processCascadesMC, "process cascades: MC analysis", false); - motherDCA mDCA; - fillCascadeDCA(track, protonTrack, pionTrack, primaryVertex, isOmega, mDCA); - daughtersDCA dDCA; - fillDauDCA(trackedCascade, bachelor, protonTrack, pionTrack, primaryVertex, isOmega, dDCA); + void processGenParticles(aod::McParticles const& mcParticles, aod::McCollisions const&) + { + for (const auto& p : mcParticles) { + auto absCode = std::abs(p.pdgCode()); + if (absCode != 3312 && absCode != 3334) { + continue; + } + auto fromHF = isFromHF(p); + int pdgCodeMom = p.has_mothers() ? p.template mothers_as()[0].pdgCode() : 0; + auto mcCollision = p.template mcCollision_as(); - candidates.emplace_back(NPCascCandidate{static_cast(track.globalIndex()), - track.pt(), track.eta(), track.phi(), - mDCA.DCAxy, mDCA.DCAz, dDCA.protonDCAxy, dDCA.protonDCAz, dDCA.pionDCAxy, dDCA.pionDCAz, dDCA.bachDCAxy, dDCA.bachDCAz, - cascCpa, v0Cpa, - massXi, massOmega, v0mass, - std::hypot(trackedCascade.decayX(), trackedCascade.decayY()), std::hypot(v0Pos[0], v0Pos[1]), std::hypot(trackedCascade.decayX(), trackedCascade.decayY(), trackedCascade.decayZ()), std::hypot(v0Pos[0], v0Pos[1], v0Pos[2]), - track.itsNCls(), protonTrack.itsNCls(), pionTrack.itsNCls(), bachKaonNClusITS, bachPionNClusITS, protonTrack.tpcNClsFound(), pionTrack.tpcNClsFound(), bachKaonNClusTPC, bachPionNClusTPC, - protonTrack.tpcNSigmaPr(), pionTrack.tpcNSigmaPi(), bachelor.tpcNSigmaKa(), bachelor.tpcNSigmaPi(), - protonTrack.hasTOF(), pionTrack.hasTOF(), bachKaonHasTOF, bachPionHasTOF, - protonTrack.tofNSigmaPr(), pionTrack.tofNSigmaPi(), bachelor.tofNSigmaKa(), bachelor.tofNSigmaPi()}); - - } // end loop over tracked cascades - - for (auto& c : candidates) { - - NPCTable(c.cascPt, c.cascEta, c.cascPhi, - c.cascDCAxy, c.cascDCAz, c.protonDCAxy, c.protonDCAz, c.pionDCAxy, c.pionDCAz, c.bachDCAxy, c.bachDCAz, - c.casccosPA, c.v0cosPA, - c.massXi, c.massOmega, c.massV0, - c.cascRadius, c.v0radius, c.cascLength, c.v0length, - c.cascNClusITS, c.protonNClusITS, c.pionNClusITS, c.bachKaonNClusITS, c.bachPionNClusITS, c.protonNClusTPC, c.pionNClusTPC, c.bachKaonNClusTPC, c.bachPionNClusTPC, - c.protonTPCNSigma, c.pionTPCNSigma, c.bachKaonTPCNSigma, c.bachPionTPCNSigma, - c.protonHasTOF, c.pionHasTOF, c.bachKaonHasTOF, c.bachPionHasTOF, - c.protonTOFNSigma, c.pionTOFNSigma, c.bachKaonTOFNSigma, c.bachPionTOFNSigma); + NPCTableGen(p.pt(), p.eta(), p.phi(), p.pdgCode(), pdgCodeMom, mcCollision.posX() - p.vx(), mcCollision.posY() - p.vy(), mcCollision.posZ() - p.vz(), fromHF[0], fromHF[1]); } } + PROCESS_SWITCH(NonPromptCascadeTask, processGenParticles, "process gen cascades: MC analysis", false); + + void processTrackedCascadesData(CollisionCandidatesRun3 const& collisions, + aod::AssignedTrackedCascades const& trackedCascades, aod::Cascades const& /*cascades*/, + aod::V0s const& /*v0s*/, TracksExtData const& /*tracks*/, + aod::BCsWithTimestamps const&) + { + zorroAccounting(collisions); + fillCandidatesVector(collisions, trackedCascades, gCandidates); + fillDataTable(gCandidates); + } PROCESS_SWITCH(NonPromptCascadeTask, processTrackedCascadesData, "process cascades from strangeness tracking: Data analysis", false); + + void processCascadesData(CollisionCandidatesRun3 const& collisions, aod::Cascades const& cascades, + aod::V0s const& /*v0s*/, TracksExtData const& /*tracks*/, + aod::BCsWithTimestamps const&) + { + zorroAccounting(collisions); + fillCandidatesVector(collisions, cascades, gCandidatesNT); + fillDataTable(gCandidatesNT); + } + PROCESS_SWITCH(NonPromptCascadeTask, processCascadesData, "process cascades: Data analysis", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Strangeness/phik0shortanalysis.cxx b/PWGLF/Tasks/Strangeness/phik0shortanalysis.cxx new file mode 100644 index 00000000000..bf04c3c0e37 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/phik0shortanalysis.cxx @@ -0,0 +1,2197 @@ +// 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 phik0shortanalysis.cxx +/// \brief Analysis task for the Phi and K0S rapidity correlations analysis +/// \author Stefano Cannito (stefano.cannito@cern.ch) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Common/DataModel/EventSelection.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Common/DataModel/PIDResponse.h" +#include "Framework/ASoAHelpers.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "PWGLF/Utils/inelGt.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "CCDB/BasicCCDBManager.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct Phik0shortanalysis { + // Histograms are defined with HistogramRegistry + HistogramRegistry dataEventHist{"dataEventHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry mcEventHist{"mcEventHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry dataPhiHist{"dataPhiHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry mcPhiHist{"mcPhiHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry closureMCPhiHist{"closureMCPhiHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry dataK0SHist{"dataK0SHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry mcK0SHist{"mcK0SHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry dataPhiK0SHist{"dataPhiK0SHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry mcPhiK0SHist{"mcPhiK0SHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry closureMCPhiK0SHist{"closureMCPhiK0SHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry dataPionHist{"dataPionHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry mcPionHist{"mcPionHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry dataPhiPionHist{"dataPhiPionHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry mcPhiPionHist{"mcPhiPionHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry closureMCPhiPionHist{"closureMCPhiPionHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Configurable for event selection + Configurable cutZVertex{"cutZVertex", 10.0f, "Accepted z-vertex range (cm)"}; + + // Configurable on multiplicity bins + Configurable> binsMult{"binsMult", {0.0, 1.0, 5.0, 10.0, 15.0, 20.0, 30.0, 40.0, 50.0, 70.0, 100.0}, "Multiplicity bin limits"}; + + // Configurables for track selection (not necessarily common for trigger and the two associated particles) + struct : ConfigurableGroup { + Configurable cfgCutCharge{"cfgCutCharge", 0.0f, "Cut on charge"}; + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", false, "Primary track selection"}; + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; + Configurable cfgPVContributor{"cfgPVContributor", true, "PV contributor track selection"}; + Configurable cMinKaonPtcut{"cMinKaonPtcut", 0.15f, "Track minimum pt cut"}; + Configurable etaMax{"etaMax", 0.8f, "eta max"}; + Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 2.0f, "Track DCAz cut to PV Maximum"}; + Configurable cMaxDCArToPV1Phi{"cMaxDCArToPV1Phi", 0.004f, "Track DCAr cut to PV config 1 for Phi"}; + Configurable cMaxDCArToPV2Phi{"cMaxDCArToPV2Phi", 0.013f, "Track DCAr cut to PV config 2 for Phi"}; + Configurable cMaxDCArToPV3Phi{"cMaxDCArToPV3Phi", 1.0f, "Track DCAr cut to PV config 3 for Phi"}; + Configurable cMaxDCArToPV1Pion{"cMaxDCArToPV1Pion", 0.004f, "Track DCAr cut to PV config 1 for Pions"}; + Configurable cMaxDCArToPV2Pion{"cMaxDCArToPV2Pion", 0.013f, "Track DCAr cut to PV config 2 for Pions"}; + Configurable cMaxDCArToPV3Pion{"cMaxDCArToPV3Pion", 1.0f, "Track DCAr cut to PV config 3 for Pions"}; + + Configurable cfgIsDCAzParameterized{"cfgIsDCAzParameterized", false, "IsDCAzParameterized"}; + Configurable cMaxDCAzToPV1Pion{"cMaxDCAzToPV1Pion", 0.004f, "Track DCAz cut to PV config 1 for Pion"}; + Configurable cMaxDCAzToPV2Pion{"cMaxDCAzToPV2Pion", 0.013f, "Track DCAz cut to PV config 2 for Pion"}; + Configurable cMaxDCAzToPV3Pion{"cMaxDCAzToPV3Pion", 1.0f, "Track DCAz cut to PV config 3 for Pion"}; + + Configurable isNoTOF{"isNoTOF", false, "isNoTOF"}; + Configurable nSigmaCutTPCKa{"nSigmaCutTPCKa", 3.0f, "Value of the TPC Nsigma cut for Kaons"}; + Configurable nSigmaCutCombinedKa{"nSigmaCutCombinedKa", 3.0f, "Value of the TOF Nsigma cut for Kaons"}; + + Configurable nSigmaCutTPCPion{"nSigmaCutTPCPion", 4.0f, "Value of the TPC Nsigma cut for Pions"}; + Configurable cMinPionPtcut{"cMinPionPtcut", 0.3f, "Track minimum pt cut"}; + Configurable minTPCnClsFound{"minTPCnClsFound", 70, "min number of found TPC clusters"}; + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 80, "min number of TPC crossed rows"}; + Configurable maxChi2TPC{"maxChi2TPC", 4.0f, "max chi2 per cluster TPC"}; + Configurable minITSnCls{"minITSnCls", 4, "min number of ITS clusters"}; + Configurable maxChi2ITS{"maxChi2ITS", 36.0f, "max chi2 per cluster ITS"}; + } trackConfigs; + + // Configurables on phi pT bins + Configurable> binspTPhi{"binspTPhi", {0.4, 0.8, 1.4, 2.0, 2.8, 4.0, 6.0, 10.0}, "pT bin limits for Phi"}; + Configurable minPhiPt{"minPhiPt", 0.4f, "Minimum pT for Phi"}; + Configurable maxPhiPt{"maxPhiPt", 10.0f, "Maximum pT for Phi"}; + + // Configurables on phi mass + Configurable nBinsMPhi{"nBinsMPhi", 13, "N bins in cfgmassPhiaxis"}; + Configurable lowMPhi{"lowMPhi", 1.0095f, "Upper limits on Phi mass for signal extraction"}; + Configurable upMPhi{"upMPhi", 1.029f, "Upper limits on Phi mass for signal extraction"}; + + // Configurables for V0 selection + struct : ConfigurableGroup { + Configurable v0SettingCosPA{"v0SettingCosPA", 0.98f, "V0 CosPA"}; + Configurable v0SettingRadius{"v0SettingRadius", 0.5f, "v0radius"}; + Configurable v0SettingDCAV0Dau{"v0SettingDCAV0Dau", 1.0f, "DCA V0 Daughters"}; + Configurable v0SettingDCAPosToPV{"v0SettingDCAPosToPV", 0.1f, "DCA Pos To PV"}; + Configurable v0SettingDCANegToPV{"v0SettingDCANegToPV", 0.1f, "DCA Neg To PV"}; + Configurable v0SettingMinPt{"v0SettingMinPt", 0.1f, "V0 min pt"}; + + Configurable cfgisV0ForData{"cfgisV0ForData", true, "isV0ForData"}; + + Configurable cfgFurtherV0Selection{"cfgFurtherV0Selection", false, "Further V0 selection"}; + Configurable ctauK0s{"ctauK0s", 20.0f, "C tau K0s(cm)"}; + Configurable paramArmenterosCut{"paramArmenterosCut", 0.2f, "parameter Armenteros Cut"}; + Configurable v0rejK0s{"v0rejK0s", 0.005f, "V0 rej K0s"}; + } v0Configs; + + // Configurables on K0S mass + Configurable lowMK0S{"lowMK0S", 0.48f, "Lower limit on K0Short mass"}; + Configurable upMK0S{"upMK0S", 0.52f, "Upper limit on K0Short mass"}; + + // Configurable on K0S pT bins + Configurable> binspTK0S{"binspTK0S", {0.1, 0.5, 0.8, 1.2, 1.6, 2.0, 2.5, 3.0, 4.0, 6.0}, "pT bin limits for K0S"}; + + // Configurable on pion pT bins + Configurable> binspTPi{"binspTPi", {0.3, 0.4, 0.5, 0.6, 0.8, 1.0, 1.2, 1.5, 2.0, 3.0}, "pT bin limits for pions"}; + + // Configurables for delta y selection + Configurable nBinsY{"nBinsY", 80, "Number of bins in y axis"}; + Configurable nBinsDeltaY{"nBinsDeltaY", 24, "Number of bins in deltay axis"}; + Configurable cfgYAcceptance{"cfgYAcceptance", 0.5f, "Rapidity acceptance"}; + Configurable cfgYAcceptanceSmear{"cfgYAcceptanceSmear", 0.8f, "Rapidity acceptance for smearing matrix study"}; + Configurable cfgFCutOnDeltaY{"cfgFCutOnDeltaY", 0.5f, "First upper bound on Deltay selection"}; + Configurable cfgSCutOnDeltaY{"cfgSCutOnDeltaY", 0.1f, "Second upper bound on Deltay selection"}; + Configurable> cfgDeltaYAcceptanceBins{"cfgDeltaYAcceptanceBins", {1.0f, 0.8f, 0.6f, 0.5f, 0.3f, 0.2f}, "Rapidity acceptance bins"}; + + // Configurable for RecMC + Configurable cfgiskNoITSROFrameBorder{"cfgiskNoITSROFrameBorder", false, "kNoITSROFrameBorder request on RecMC collisions"}; + + // Configurables for MC closure + Configurable cfgisRecMCWPDGForClosure1{"cfgisRecMCWPDGForClosure1", false, "RecoMC with PDG Codes for Closure only for Associated particles"}; + Configurable cfgisRecMCWPDGForClosure2{"cfgisRecMCWPDGForClosure2", false, "RecoMC with PDG Codes for Closure"}; + Configurable cfgisGenMCForClosure{"cfgisGenMCForClosure", false, "GenMC for Closure"}; + + // Configurables to choose the filling method + Configurable fillMethodMultipleWeights{"fillMethodMultipleWeights", true, "Fill method Multiple Weights"}; + Configurable fillMethodSingleWeight{"fillMethodSingleWeight", false, "Fill method Single Weight"}; + + // Configurable for CCDB + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository to use"}; + Configurable ccdbPurityPath{"ccdbPurityPath", "Users/s/scannito/PhiPuritiesData", "Correction path to file"}; + + // Constants + double massKa = o2::constants::physics::MassKPlus; + double massPi = o2::constants::physics::MassPiPlus; + double massK0S = o2::constants::physics::MassK0Short; + double massLambda = o2::constants::physics::MassLambda0; + + // 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); + + // Defining filters on V0s (cannot filter on dynamic columns) + Filter preFilterV0 = (nabs(aod::v0data::dcapostopv) > v0Configs.v0SettingDCAPosToPV && nabs(aod::v0data::dcanegtopv) > v0Configs.v0SettingDCANegToPV && aod::v0data::dcaV0daughters < v0Configs.v0SettingDCAV0Dau); + + // Defining the type of the collisions for data and MC + using SelCollisions = soa::Join; + using SimCollisions = soa::Join; + using MCCollisions = soa::Join; + + // Defining the type of the V0s + using FullV0s = soa::Filtered; + using FullMCV0s = soa::Join; + + // Defining the type of the tracks for data and MC + using FullTracks = soa::Join; + using FullMCTracks = soa::Join; + + using V0DauTracks = soa::Join; + using V0DauMCTracks = soa::Join; + + // Defining the binning policy for mixed event + using BinningTypeVertexContributor = ColumnBinningPolicy; + + SliceCache cache; + + Partition posTracks = aod::track::signed1Pt > trackConfigs.cfgCutCharge; + Partition negTracks = aod::track::signed1Pt < trackConfigs.cfgCutCharge; + + Partition posMCTracks = aod::track::signed1Pt > trackConfigs.cfgCutCharge; + Partition negMCTracks = aod::track::signed1Pt < trackConfigs.cfgCutCharge; + + // Necessary to flag INEL>0 events in GenMC + Service pdgDB; + + // Necessary to get the CCDB for phi purities + Service ccdb; + + // Set of functions for phi purity + std::vector> phiPurityFunctions = std::vector>(binsMult->size(), std::vector(binspTPhi->size(), nullptr)); + + void init(InitContext&) + { + // Axes + AxisSpec massK0SAxis = {200, 0.45f, 0.55f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec massPhiAxis = {200, 0.9f, 1.2f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec sigmassPhiAxis = {nBinsMPhi, lowMPhi, upMPhi, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec vertexZAxis = {100, -15.f, 15.f, "vrtx_{Z} [cm]"}; + AxisSpec yAxis = {nBinsY, -cfgYAcceptanceSmear, cfgYAcceptanceSmear, "#it{y}"}; + AxisSpec deltayAxis = {nBinsDeltaY, -1.2f, 1.2f, "#Delta#it{y}"}; + AxisSpec multAxis = {120, 0.0f, 120.0f, "centFT0M"}; + AxisSpec binnedmultAxis{(std::vector)binsMult, "centFT0M"}; + AxisSpec binnedpTPhiAxis{(std::vector)binspTPhi, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptK0SAxis = {60, 0.0f, 6.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec binnedptK0SAxis{(std::vector)binspTK0S, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptPiAxis = {30, 0.0f, 3.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec binnedptPiAxis{(std::vector)binspTPi, "#it{p}_{T} (GeV/#it{c})"}; + + // Histograms + // Number of events per selection + dataEventHist.add("hEventSelection", "hEventSelection", kTH1F, {{6, -0.5f, 5.5f}}); + dataEventHist.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + dataEventHist.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + dataEventHist.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(3, "posZ cut"); + dataEventHist.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(4, "INEL>0 cut"); + dataEventHist.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(5, "With at least a #phi cand"); + dataEventHist.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(6, "With at least a #phi"); + + // Event information + dataEventHist.add("hVertexZ", "hVertexZ", kTH1F, {vertexZAxis}); + dataEventHist.add("hMultiplicityPercent", "Multiplicity Percentile", kTH1F, {multAxis}); + dataEventHist.add("hMultiplicityPercentWithPhi", "Multiplicity Percentile in Events with a Phi Candidate", kTH1F, {multAxis}); + + // Number of MC events per selection for Rec and Gen + mcEventHist.add("hRecMCEventSelection", "hRecMCEventSelection", kTH1F, {{9, -0.5f, 8.5f}}); + mcEventHist.get(HIST("hRecMCEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + mcEventHist.get(HIST("hRecMCEventSelection"))->GetXaxis()->SetBinLabel(2, "kIsTriggerTVX"); + mcEventHist.get(HIST("hRecMCEventSelection"))->GetXaxis()->SetBinLabel(3, "kNoTimeFrameBorder"); + mcEventHist.get(HIST("hRecMCEventSelection"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + mcEventHist.get(HIST("hRecMCEventSelection"))->GetXaxis()->SetBinLabel(5, "posZ cut"); + mcEventHist.get(HIST("hRecMCEventSelection"))->GetXaxis()->SetBinLabel(6, "INEL>0 cut"); + mcEventHist.get(HIST("hRecMCEventSelection"))->GetXaxis()->SetBinLabel(7, "With at least a gen coll"); + mcEventHist.get(HIST("hRecMCEventSelection"))->GetXaxis()->SetBinLabel(8, "With at least a #phi cand"); + mcEventHist.get(HIST("hRecMCEventSelection"))->GetXaxis()->SetBinLabel(9, "With at least a #phi"); + + mcEventHist.add("hGenMCEventSelection", "hGenMCEventSelection", kTH1F, {{5, -0.5f, 4.5f}}); + mcEventHist.get(HIST("hGenMCEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + mcEventHist.get(HIST("hGenMCEventSelection"))->GetXaxis()->SetBinLabel(2, "posZ cut"); + mcEventHist.get(HIST("hGenMCEventSelection"))->GetXaxis()->SetBinLabel(3, "INEL>0 cut"); + mcEventHist.get(HIST("hGenMCEventSelection"))->GetXaxis()->SetBinLabel(4, "With at least a #phi"); + mcEventHist.get(HIST("hGenMCEventSelection"))->GetXaxis()->SetBinLabel(5, "With at least a reco coll"); + + // MC Event information for Rec and Gen + mcEventHist.add("hRecMCVertexZ", "hRecMCVertexZ", kTH1F, {vertexZAxis}); + mcEventHist.add("hRecMCMultiplicityPercent", "RecMC Multiplicity Percentile", kTH1F, {multAxis}); + mcEventHist.add("hRecMCGenMultiplicityPercent", "RecMC Gen Multiplicity Percentile", kTH1F, {binnedmultAxis}); + mcEventHist.add("hRecMCGenMultiplicityPercentWithPhi", "RecMC Gen Multiplicity Percentile in Events with a Phi Candidate", kTH1F, {binnedmultAxis}); + + mcEventHist.add("hGenMCVertexZ", "hGenMCVertexZ", kTH1F, {vertexZAxis}); + mcEventHist.add("hGenMCMultiplicityPercent", "GenMC Multiplicity Percentile", kTH1F, {binnedmultAxis}); + + // Phi topological/PID cuts + dataPhiHist.add("h2DauTracksPhiDCAxyPreCutData", "Dcaxy distribution vs pt before DCAxy cut", kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{xy} (cm)"}}); + dataPhiHist.add("h2DauTracksPhiDCAzPreCutData", "Dcaz distribution vs pt before DCAxy cut", kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{z} (cm)"}}); + dataPhiHist.add("h2DauTracksPhiDCAxyPostCutData", "Dcaxy distribution vs pt after DCAxy cut", kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{xy} (cm)"}}); + dataPhiHist.add("h2DauTracksPhiDCAzPostCutData", "Dcaz distribution vs pt after DCAxy cut", kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{z} (cm)"}}); + + dataPhiHist.add("hEta", "Eta distribution", kTH1F, {{200, -1.0f, 1.0f}}); + dataPhiHist.add("hNsigmaKaonTPC", "NsigmaKaon TPC distribution", kTH2F, {{100, 0.0, 5.0, "#it{p} (GeV/#it{c})"}, {100, -10.0f, 10.0f}}); + dataPhiHist.add("hNsigmaKaonTOF", "NsigmaKaon TOF distribution", kTH2F, {{100, 0.0, 5.0, "#it{p} (GeV/#it{c})"}, {100, -10.0f, 10.0f}}); + + // Phi invariant mass for computing purities and normalisation + dataPhiHist.add("h3PhipurData", "Invariant mass of Phi for Purity (no K0S/Pi) in Data", kTH3F, {binnedmultAxis, binnedpTPhiAxis, massPhiAxis}); + + dataPhiHist.add("h4PhipurK0SData", "Invariant mass of Phi for Purity (K0S) in Data", kTHnSparseF, {{static_cast(cfgDeltaYAcceptanceBins->size()), -0.5f, static_cast(cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedpTPhiAxis, massPhiAxis}); + dataPhiHist.get(HIST("h4PhipurK0SData"))->GetAxis(0)->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + dataPhiHist.get(HIST("h4PhipurK0SData"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", cfgDeltaYAcceptanceBins->at(i))); + } + + dataPhiHist.add("h4PhipurPiData", "Invariant mass of Phi for Purity (Pi) in Data", kTHnSparseF, {{static_cast(cfgDeltaYAcceptanceBins->size()), -0.5f, static_cast(cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedpTPhiAxis, massPhiAxis}); + dataPhiHist.get(HIST("h4PhipurPiData"))->GetAxis(0)->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + dataPhiHist.get(HIST("h4PhipurPiData"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", cfgDeltaYAcceptanceBins->at(i))); + } + + // DCA plots for phi daughters in MCReco + mcPhiHist.add("h2DauTracksPhiDCAxyPreCutMCReco", "Dcaxy distribution vs pt before DCAxy cut", kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{xy} (cm)"}}); + mcPhiHist.add("h2DauTracksPhiDCAzPreCutMCReco", "Dcaz distribution vs pt before DCAxy cut", kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{z} (cm)"}}); + mcPhiHist.add("h2DauTracksPhiDCAxyPostCutMCReco", "Dcaxy distribution vs pt after DCAxy cut", kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{xy} (cm)"}}); + mcPhiHist.add("h2DauTracksPhiDCAzPostCutMCReco", "Dcaz distribution vs pt after DCAxy cut", kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{z} (cm)"}}); + + // MCPhi invariant mass for computing purities + closureMCPhiHist.add("h3PhipurMCClosure", "Invariant mass of Phi for Purity (no K0S/Pi)", kTH3F, {binnedmultAxis, binnedpTPhiAxis, massPhiAxis}); + + closureMCPhiHist.add("h4PhipurK0SMCClosure", "Invariant mass of Phi for Purity (K0S) in MCClosure", kTHnSparseF, {{static_cast(cfgDeltaYAcceptanceBins->size()), -0.5f, static_cast(cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedpTPhiAxis, massPhiAxis}); + closureMCPhiHist.get(HIST("h4PhipurK0SMCClosure"))->GetAxis(0)->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + closureMCPhiHist.get(HIST("h4PhipurK0SMCClosure"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", cfgDeltaYAcceptanceBins->at(i))); + } + + closureMCPhiHist.add("h4PhipurPiMCClosure", "Invariant mass of Phi for Purity (Pi) in MCClosure", kTHnSparseF, {{static_cast(cfgDeltaYAcceptanceBins->size()), -0.5f, static_cast(cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedpTPhiAxis, massPhiAxis}); + closureMCPhiHist.get(HIST("h4PhipurPiMCClosure"))->GetAxis(0)->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + closureMCPhiHist.get(HIST("h4PhipurPiMCClosure"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", cfgDeltaYAcceptanceBins->at(i))); + } + + // K0S topological/PID cuts + dataK0SHist.add("hDCAV0Daughters", "hDCAV0Daughters", kTH1F, {{55, 0.0f, 2.2f}}); + dataK0SHist.add("hV0CosPA", "hV0CosPA", kTH1F, {{100, 0.95f, 1.f}}); + dataK0SHist.add("hNSigmaPosPionFromK0S", "hNSigmaPosPionFromK0Short", kTH2F, {{100, 0.0, 5.0, "#it{p} (GeV/#it{c})"}, {100, -10.0f, 10.0f}}); + dataK0SHist.add("hNSigmaNegPionFromK0S", "hNSigmaNegPionFromK0Short", kTH2F, {{100, 0.0, 5.0, "#it{p} (GeV/#it{c})"}, {100, -10.0f, 10.0f}}); + + // 2D mass of Phi and K0S for Data + dataPhiK0SHist.add("h5PhiK0SData", "2D Invariant mass of Phi and K0Short for Data", kTHnSparseF, {{static_cast(cfgDeltaYAcceptanceBins->size()), -0.5f, static_cast(cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedptK0SAxis, massK0SAxis, sigmassPhiAxis}); + dataPhiK0SHist.get(HIST("h5PhiK0SData"))->GetAxis(0)->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + dataPhiK0SHist.get(HIST("h5PhiK0SData"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", cfgDeltaYAcceptanceBins->at(i))); + } + + // 1D mass of K0S for Data + dataPhiK0SHist.add("h3PhiK0SSEIncNew", "Invariant mass of K0Short for Same Event Inclusive", kTH3F, {binnedmultAxis, binnedptK0SAxis, massK0SAxis}); + dataPhiK0SHist.add("h3PhiK0SSEFCutNew", "Invariant mass of K0Short for Same Event Deltay < FirstCut", kTH3F, {binnedmultAxis, binnedptK0SAxis, massK0SAxis}); + dataPhiK0SHist.add("h3PhiK0SSESCutNew", "Invariant mass of K0Short for Same Event Deltay < SecondCut", kTH3F, {binnedmultAxis, binnedptK0SAxis, massK0SAxis}); + + // K0S rapidity in Data + dataK0SHist.add("h3K0SRapidityData", "K0Short rapidity for Data", kTH3F, {binnedmultAxis, binnedptK0SAxis, yAxis}); + + // RecMC K0S coupled to Phi + mcPhiK0SHist.add("h4PhiK0SMCReco", "K0S coupled to Phi in MCReco", kTHnSparseF, {{static_cast(cfgDeltaYAcceptanceBins->size()), -0.5f, static_cast(cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedptK0SAxis, massK0SAxis}); + mcPhiK0SHist.get(HIST("h4PhiK0SMCReco"))->GetAxis(0)->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + mcPhiK0SHist.get(HIST("h4PhiK0SMCReco"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", cfgDeltaYAcceptanceBins->at(i))); + } + + // GenMC K0S coupled to Phi + mcPhiK0SHist.add("h3PhiK0SMCGen", "K0S coupled toPhi in MCGen", kTH3F, {{static_cast(cfgDeltaYAcceptanceBins->size()), -0.5f, static_cast(cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedptK0SAxis}); + mcPhiK0SHist.get(HIST("h3PhiK0SMCGen"))->GetXaxis()->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + mcPhiK0SHist.get(HIST("h3PhiK0SMCGen"))->GetXaxis()->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", cfgDeltaYAcceptanceBins->at(i))); + } + + mcPhiK0SHist.add("h3PhiK0SMCGenAssocReco", "K0S coupled toPhi in MCGen Associated MCReco Collision", kTH3F, {{static_cast(cfgDeltaYAcceptanceBins->size()), -0.5f, static_cast(cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedptK0SAxis}); + mcPhiK0SHist.get(HIST("h3PhiK0SMCGenAssocReco"))->GetXaxis()->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + mcPhiK0SHist.get(HIST("h3PhiK0SMCGenAssocReco"))->GetXaxis()->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", cfgDeltaYAcceptanceBins->at(i))); + } + + // 2D mass of Phi and K0S for Closure Test + closureMCPhiK0SHist.add("h5PhiK0SMCClosure", "2D Invariant mass of Phi and K0Short for MC Closure Test", kTHnSparseF, {{static_cast(cfgDeltaYAcceptanceBins->size()), -0.5f, static_cast(cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedptK0SAxis, massK0SAxis, sigmassPhiAxis}); + closureMCPhiK0SHist.get(HIST("h5PhiK0SMCClosure"))->GetAxis(0)->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + closureMCPhiK0SHist.get(HIST("h5PhiK0SMCClosure"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", cfgDeltaYAcceptanceBins->at(i))); + } + + // 1D mass of K0S for Closure Test + closureMCPhiK0SHist.add("h3ClosureMCPhiK0SSEIncNew", "Invariant mass of K0Short for Inclusive for Closure Test", kTH3F, {binnedmultAxis, binnedptK0SAxis, massK0SAxis}); + closureMCPhiK0SHist.add("h3ClosureMCPhiK0SSEFCutNew", "Invariant mass of K0Short for Deltay < FirstCut for Closure Test", kTH3F, {binnedmultAxis, binnedptK0SAxis, massK0SAxis}); + closureMCPhiK0SHist.add("h3ClosureMCPhiK0SSESCutNew", "Invariant mass of K0Short for Deltay < SecondCut for Closure Test", kTH3F, {binnedmultAxis, binnedptK0SAxis, massK0SAxis}); + + // Phi mass vs Pion NSigma dE/dx for Data + dataPhiPionHist.add("h6PhiPiData", "Phi Invariant mass vs Pion nSigma TPC/TOF for Data", kTHnSparseF, {{static_cast(cfgDeltaYAcceptanceBins->size()), -0.5f, static_cast(cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedptPiAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}, sigmassPhiAxis}); + dataPhiPionHist.get(HIST("h6PhiPiData"))->GetAxis(0)->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + dataPhiPionHist.get(HIST("h6PhiPiData"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", cfgDeltaYAcceptanceBins->at(i))); + } + + // Pion NSigma dE/dx for Data + dataPhiPionHist.add("h4PhiPiSEIncNew", "Pion nSigma TPC/TOF for Same Event Inclusive", kTHnSparseF, {binnedmultAxis, binnedptPiAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}}); + dataPhiPionHist.add("h4PhiPiSEFCutNew", "Pion nSigma TPC/TOF for Same Event Deltay < FirstCut", kTHnSparseF, {binnedmultAxis, binnedptPiAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}}); + dataPhiPionHist.add("h4PhiPiSESCutNew", "Pion nSigma TPC/TOF for Same Event Deltay < SecondCut", kTHnSparseF, {binnedmultAxis, binnedptPiAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}}); + + // Pion rapidity in Data + dataPionHist.add("h3PiRapidityData", "Pion rapidity for Data", kTH3F, {binnedmultAxis, binnedptPiAxis, yAxis}); + + // DCA plots for pions in Data + dataPionHist.add("h2TracksPiDCAxyPreCutData", "Dcaxy distribution vs pt before DCAxy cut", kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{xy} (cm)"}}); + dataPionHist.add("h2TracksPiDCAzPreCutData", "Dcaz distribution vs pt before DCAxy cut", kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{z} (cm)"}}); + dataPionHist.add("h2TracksPiDCAxyPostCutData", "Dcaxy distribution vs pt after DCAxy cut", kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{xy} (cm)"}}); + dataPionHist.add("h2TracksPiDCAzPostCutData", "Dcaz distribution vs pt after DCAxy cut", kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{z} (cm)"}}); + + // DCA plots for pions in MCReco + mcPionHist.add("h2TracksPiDCAxyPreCutMCReco", "Dcaxy distribution vs pt before DCAxy cut", kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{xy} (cm)"}}); + mcPionHist.add("h2TracksPiDCAzPreCutMCReco", "Dcaz distribution vs pt before DCAxy cut", kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{z} (cm)"}}); + mcPionHist.add("h2TracksPiDCAxyPostCutMCReco", "Dcaxy distribution vs pt after DCAxy cut", kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{xy} (cm)"}}); + mcPionHist.add("h2TracksPiDCAzPostCutMCReco", "Dcaz distribution vs pt after DCAxy cut", kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{z} (cm)"}}); + + // DCA plots for pions in MCReco distinguishing Primaries, Secondaries from Weak Decay and Secondaries from Material + mcPionHist.add("h3RecMCDCAxyPrimPi", "Dcaxy distribution vs pt for Primary Pions", kTH2F, {binnedptPiAxis, {2000, -0.05, 0.05, "DCA_{xy} (cm)"}}); + mcPionHist.add("h3RecMCDCAxySecWeakDecayPi", "Dcaz distribution vs pt for Secondary Pions from Weak Decay", kTH2F, {binnedptPiAxis, {2000, -0.05, 0.05, "DCA_{xy} (cm)"}}); + mcPionHist.add("h3RecMCDCAxySecMaterialPi", "Dcaxy distribution vs pt for Secondary Pions from Material", kTH2F, {binnedptPiAxis, {2000, -0.05, 0.05, "DCA_{xy} (cm)"}}); + + // RecMC Pion coupled to Phi with TPC + mcPhiPionHist.add("h4PhiPiTPCMCReco", "Pion coupled to Phi in MCReco (TPC)", kTHnSparseF, {{static_cast(cfgDeltaYAcceptanceBins->size()), -0.5f, static_cast(cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedptPiAxis, {100, -10.0f, 10.0f}}); + mcPhiPionHist.get(HIST("h4PhiPiTPCMCReco"))->GetAxis(0)->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + mcPhiPionHist.get(HIST("h4PhiPiTPCMCReco"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", cfgDeltaYAcceptanceBins->at(i))); + } + + // RecMC Pion coupled to Phi with TPC and TOF + mcPhiPionHist.add("h5PhiPiTPCTOFMCReco", "Pion coupled to Phi in MCReco (TPC and TOF)", kTHnSparseF, {{static_cast(cfgDeltaYAcceptanceBins->size()), -0.5f, static_cast(cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedptPiAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}}); + mcPhiPionHist.get(HIST("h5PhiPiTPCTOFMCReco"))->GetAxis(0)->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + mcPhiPionHist.get(HIST("h5PhiPiTPCTOFMCReco"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", cfgDeltaYAcceptanceBins->at(i))); + } + + mcPhiPionHist.add("h3PhiPiMCGen", "Pion coupled to Phi in MCGen", kTH3F, {{static_cast(cfgDeltaYAcceptanceBins->size()), -0.5f, static_cast(cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedptPiAxis}); + mcPhiPionHist.get(HIST("h3PhiPiMCGen"))->GetXaxis()->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + mcPhiPionHist.get(HIST("h3PhiPiMCGen"))->GetXaxis()->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", cfgDeltaYAcceptanceBins->at(i))); + } + + mcPhiPionHist.add("h3PhiPiMCGenAssocReco", "Pion coupled to Phi in MCGen Associated Reco Collision", kTH3F, {{static_cast(cfgDeltaYAcceptanceBins->size()), -0.5f, static_cast(cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedptPiAxis}); + mcPhiPionHist.get(HIST("h3PhiPiMCGenAssocReco"))->GetXaxis()->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + mcPhiPionHist.get(HIST("h3PhiPiMCGenAssocReco"))->GetXaxis()->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", cfgDeltaYAcceptanceBins->at(i))); + } + + // Phi mass vs Pion NSigma dE/dx for Closure Test + closureMCPhiPionHist.add("h6PhiPiMCClosure", "Phi Invariant mass vs Pion nSigma TPC/TOF for MC Closure Test", kTHnSparseF, {{static_cast(cfgDeltaYAcceptanceBins->size()), -0.5f, static_cast(cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedptPiAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}, sigmassPhiAxis}); + closureMCPhiPionHist.get(HIST("h6PhiPiMCClosure"))->GetAxis(0)->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + closureMCPhiPionHist.get(HIST("h6PhiPiMCClosure"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", cfgDeltaYAcceptanceBins->at(i))); + } + + // Phi mass vs Pion NSigma dE/dx for Closure Test + closureMCPhiPionHist.add("h4ClosureMCPhiPiSEIncNew", "Pion nSigma TPC/TOF for Inclusive for Closure Test", kTHnSparseF, {binnedmultAxis, binnedptPiAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}}); + closureMCPhiPionHist.add("h4ClosureMCPhiPiSEFCutNew", "Pion nSigma TPC/TOF for Deltay < FirstCut for Closure Test", kTHnSparseF, {binnedmultAxis, binnedptPiAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}}); + closureMCPhiPionHist.add("h4ClosureMCPhiPiSESCutNew", "Pion nSigma TPC/TOF for Deltay < SecondCut for Closure Test", kTHnSparseF, {binnedmultAxis, binnedptPiAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}}); + + // MCPhi invariant mass for computing efficiencies and MCnormalisation + mcPhiHist.add("h2PhieffInvMass", "Invariant mass of Phi for Efficiency (no K0S/Pi)", kTH2F, {binnedmultAxis, massPhiAxis}); + + mcPhiHist.add("h3PhieffK0SInvMassInc", "Invariant mass of Phi for Efficiency (K0S) Inclusive", kTH3F, {binnedmultAxis, binnedptK0SAxis, massPhiAxis}); + mcPhiHist.add("h3PhieffK0SInvMassFCut", "Invariant mass of Phi for Efficiency (K0S) Deltay < FirstCut", kTH3F, {binnedmultAxis, binnedptK0SAxis, massPhiAxis}); + mcPhiHist.add("h3PhieffK0SInvMassSCut", "Invariant mass of Phi for Efficiency (K0S) Deltay < SecondCut", kTH3F, {binnedmultAxis, binnedptK0SAxis, massPhiAxis}); + + mcPhiHist.add("h3PhieffPiInvMassInc", "Invariant mass of Phi for Efficiency (Pi) Inclusive", kTH3F, {binnedmultAxis, binnedptPiAxis, massPhiAxis}); + mcPhiHist.add("h3PhieffPiInvMassFCut", "Invariant mass of Phi for Efficiency (Pi) Deltay < FirstCut", kTH3F, {binnedmultAxis, binnedptPiAxis, massPhiAxis}); + mcPhiHist.add("h3PhieffPiInvMassSCut", "Invariant mass of Phi for Efficiency (Pi) Deltay < SecondCut", kTH3F, {binnedmultAxis, binnedptPiAxis, massPhiAxis}); + + // GenMC Phi and Phi coupled to K0S and Pion + mcPhiHist.add("h1PhiGenMC", "Phi for GenMC", kTH1F, {binnedmultAxis}); + mcPhiHist.add("h1PhiGenMCAssocReco", "Phi for GenMC Associated Reco Collision", kTH1F, {binnedmultAxis}); + + mcPhiHist.add("h2PhieffK0SGenMCInc", "Phi coupled to K0Short for GenMC Inclusive", kTH2F, {binnedmultAxis, binnedptK0SAxis}); + mcPhiHist.add("h2PhieffK0SGenMCFCut", "Phi coupled to K0Short for GenMC Deltay < FirstCut", kTH2F, {binnedmultAxis, binnedptK0SAxis}); + mcPhiHist.add("h2PhieffK0SGenMCSCut", "Phi coupled to K0Short for GenMC Deltay < SecondCut", kTH2F, {binnedmultAxis, binnedptK0SAxis}); + + mcPhiHist.add("h2PhieffK0SGenMCIncAssocReco", "Phi coupled to K0Short for GenMC Inclusive Associated Reco Collision", kTH2F, {binnedmultAxis, binnedptK0SAxis}); + mcPhiHist.add("h2PhieffK0SGenMCFCutAssocReco", "Phi coupled to K0Short for GenMC Deltay < FirstCut Associated Reco Collision", kTH2F, {binnedmultAxis, binnedptK0SAxis}); + mcPhiHist.add("h2PhieffK0SGenMCSCutAssocReco", "Phi coupled to K0Short for GenMC Deltay < SecondCut Associated Reco Collision", kTH2F, {binnedmultAxis, binnedptK0SAxis}); + + mcPhiHist.add("h2PhieffPiGenMCInc", "Phi coupled to Pion for GenMC Inclusive", kTH2F, {binnedmultAxis, binnedptPiAxis}); + mcPhiHist.add("h2PhieffPiGenMCFCut", "Phi coupled to Pion for GenMC Deltay < FirstCut", kTH2F, {binnedmultAxis, binnedptPiAxis}); + mcPhiHist.add("h2PhieffPiGenMCSCut", "Phi coupled to Pion for GenMC Deltay < SecondCut", kTH2F, {binnedmultAxis, binnedptPiAxis}); + + mcPhiHist.add("h2PhieffPiGenMCIncAssocReco", "Phi coupled to Pion for GenMC Inclusive Associated Reco Collision", kTH2F, {binnedmultAxis, binnedptPiAxis}); + mcPhiHist.add("h2PhieffPiGenMCFCutAssocReco", "Phi coupled to Pion for GenMC Deltay < FirstCut Associated Reco Collision", kTH2F, {binnedmultAxis, binnedptPiAxis}); + mcPhiHist.add("h2PhieffPiGenMCSCutAssocReco", "Phi coupled to Pion for GenMC Deltay < SecondCut Associated Reco Collision", kTH2F, {binnedmultAxis, binnedptPiAxis}); + + // Rapidity smearing matrix for Phi + mcPhiHist.add("h3PhiRapiditySmearing", "Rapidity Smearing Matrix for Phi", kTH3F, {binnedmultAxis, yAxis, yAxis}); + + // MCK0S invariant mass and GenMC K0S for computing efficiencies + mcK0SHist.add("h3K0SMCReco", "K0S for MCReco", kTH3F, {binnedmultAxis, binnedptK0SAxis, massK0SAxis}); + + mcK0SHist.add("h2K0SMCGen", "K0S for MCGen", kTH2F, {binnedmultAxis, binnedptK0SAxis}); + mcK0SHist.add("h2K0SMCGenAssocReco", "K0S for MCGen Associated Reco Collision", kTH2F, {binnedmultAxis, binnedptK0SAxis}); + + // Rapidity smearing matrix for K0S and rapidity in GenMC + mcK0SHist.add("h4K0SRapiditySmearing", "Rapidity Smearing Matrix for K0Short", kTHnSparseF, {binnedmultAxis, binnedptK0SAxis, yAxis, yAxis}); + + mcK0SHist.add("h3K0SRapidityGenMC", "Rapidity for K0Short for GenMC", kTH3F, {binnedmultAxis, binnedptK0SAxis, yAxis}); + + // MCPion invariant mass and GenMC Pion for computing efficiencies + mcPionHist.add("h3PiTPCMCReco", "Pion for MCReco (TPC)", kTH3F, {binnedmultAxis, binnedptPiAxis, {100, -10.0f, 10.0f}}); + mcPionHist.add("h4PiTPCTOFMCReco", "Pion for MCReco (TPC and TOF)", kTHnSparseF, {binnedmultAxis, binnedptPiAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}}); + + mcPionHist.add("h2PiMCGen", "Pion for GenMC", kTH2F, {binnedmultAxis, binnedptPiAxis}); + mcPionHist.add("h2PiMCGenAssocReco", "Pion for GenMC Associated Reco Collision", kTH2F, {binnedmultAxis, binnedptPiAxis}); + + // Rapidity smearing matrix for Pion and rapidity in GenMC + mcPionHist.add("h4PiRapiditySmearing", "Rapidity Smearing Matrix for Pion", kTHnSparseF, {binnedmultAxis, binnedptPiAxis, yAxis, yAxis}); + + mcPionHist.add("h3PiRapidityGenMC", "Rapidity for Pion for GenMC", kTH3F, {binnedmultAxis, binnedptPiAxis, yAxis}); + + // Initialize CCDB only if purity is requested in the task + if (fillMethodSingleWeight) { + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + getPhiPurityFunctionsFromCCDB(); + } + } + + // Event selection and QA filling + template + bool acceptEventQA(const T& collision, bool QA) + { + if constexpr (!isMC) { // data event + if (QA) + dataEventHist.fill(HIST("hEventSelection"), 0); // all collisions + if (!collision.sel8()) + return false; + if (QA) + dataEventHist.fill(HIST("hEventSelection"), 1); // sel8 collisions + if (std::abs(collision.posZ()) >= cutZVertex) + return false; + if (QA) { + dataEventHist.fill(HIST("hEventSelection"), 2); // vertex-Z selected + dataEventHist.fill(HIST("hVertexZ"), collision.posZ()); + } + if (!collision.isInelGt0()) + return false; + if (QA) + dataEventHist.fill(HIST("hEventSelection"), 3); // INEL>0 collisions + return true; + } else { // RecMC event + if (QA) + mcEventHist.fill(HIST("hRecMCEventSelection"), 0); // all collisions + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX)) + return false; + if (QA) + mcEventHist.fill(HIST("hRecMCEventSelection"), 1); // kIsTriggerTVX collisions + if (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + return false; + if (QA) + mcEventHist.fill(HIST("hRecMCEventSelection"), 2); // kNoTimeFrameBorder collisions + if (cfgiskNoITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) + return false; + if (QA) + mcEventHist.fill(HIST("hRecMCEventSelection"), 3); // kNoITSROFrameBorder collisions (by default not requested by the selection) + if (std::abs(collision.posZ()) > cutZVertex) + return false; + if (QA) { + mcEventHist.fill(HIST("hRecMCEventSelection"), 4); // vertex-Z selected + mcEventHist.fill(HIST("hRecMCVertexZ"), collision.posZ()); + } + if (!collision.isInelGt0()) + return false; + if (QA) + mcEventHist.fill(HIST("hRecMCEventSelection"), 5); // INEL>0 collisions + return true; + } + } + + // Single track selection for strangeness sector + template + bool selectionTrackStrangeness(const T& track) + { + if (!track.hasTPC()) + return false; + if (track.tpcNClsFound() < trackConfigs.minTPCnClsFound) + return false; + if (track.tpcNClsCrossedRows() < trackConfigs.minNCrossedRowsTPC) + return false; + if (track.tpcChi2NCl() > trackConfigs.maxChi2TPC) + return false; + + if (std::abs(track.eta()) > trackConfigs.etaMax) + return false; + return true; + } + + // V0 selection + template + bool selectionV0(const T1& v0, const T2& daughter1, const T2& daughter2) + { + if (!selectionTrackStrangeness(daughter1) || !selectionTrackStrangeness(daughter2)) + return false; + + if (v0.v0cosPA() < v0Configs.v0SettingCosPA) + return false; + if (v0.v0radius() < v0Configs.v0SettingRadius) + return false; + if (v0.pt() < v0Configs.v0SettingMinPt) + return false; + + if (v0Configs.cfgisV0ForData) { + if (std::abs(daughter1.tpcNSigmaPi()) > trackConfigs.nSigmaCutTPCPion) + return false; + if (std::abs(daughter2.tpcNSigmaPi()) > trackConfigs.nSigmaCutTPCPion) + return false; + } + return true; + } + + // Further V0 selection + template + bool furtherSelectionV0(const T1& v0, const T2& collision) + { + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massK0S > v0Configs.ctauK0s) + return false; + if (v0.qtarm() < (v0Configs.paramArmenterosCut * std::abs(v0.alpha()))) + return false; + if (std::abs(v0.mLambda() - massLambda) < v0Configs.v0rejK0s) + return false; + return true; + } + + // Topological track selection + template + bool selectionTrackResonance(const T& track, bool isQA) + { + if (trackConfigs.cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (trackConfigs.cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (trackConfigs.cfgPVContributor && !track.isPVContributor()) + return false; + + if (track.tpcNClsFound() < trackConfigs.minTPCnClsFound) + return false; + + if (track.pt() < trackConfigs.cMinKaonPtcut) + return false; + if (std::abs(track.eta()) > trackConfigs.etaMax) + return false; + + if (isQA) { + if constexpr (!isMC) { + dataPhiHist.fill(HIST("h2DauTracksPhiDCAxyPreCutData"), track.pt(), track.dcaXY()); + dataPhiHist.fill(HIST("h2DauTracksPhiDCAzPreCutData"), track.pt(), track.dcaZ()); + } else { + mcPhiHist.fill(HIST("h2DauTracksPhiDCAxyPreCutMCReco"), track.pt(), track.dcaXY()); + mcPhiHist.fill(HIST("h2DauTracksPhiDCAzPreCutMCReco"), track.pt(), track.dcaZ()); + } + } + if (std::abs(track.dcaXY()) > trackConfigs.cMaxDCArToPV1Phi + (trackConfigs.cMaxDCArToPV2Phi / std::pow(track.pt(), trackConfigs.cMaxDCArToPV3Phi))) + return false; + if (isQA) { + if constexpr (!isMC) { + dataPhiHist.fill(HIST("h2DauTracksPhiDCAxyPostCutData"), track.pt(), track.dcaXY()); + dataPhiHist.fill(HIST("h2DauTracksPhiDCAzPostCutData"), track.pt(), track.dcaZ()); + } else { + mcPhiHist.fill(HIST("h2DauTracksPhiDCAxyPostCutMCReco"), track.pt(), track.dcaXY()); + mcPhiHist.fill(HIST("h2DauTracksPhiDCAzPostCutMCReco"), track.pt(), track.dcaZ()); + } + } + if (std::abs(track.dcaZ()) > trackConfigs.cMaxDCAzToPVcut) + return false; + return true; + } + + // PIDKaon track selection + template + bool selectionPIDKaon(const T& track) + { + if (!trackConfigs.isNoTOF && track.hasTOF() && (std::pow(track.tofNSigmaKa(), 2) + std::pow(track.tpcNSigmaKa(), 2)) < std::pow(trackConfigs.nSigmaCutCombinedKa, 2)) + return true; + if (!trackConfigs.isNoTOF && !track.hasTOF() && std::abs(track.tpcNSigmaKa()) < trackConfigs.nSigmaCutTPCKa) + return true; + if (trackConfigs.isNoTOF && std::abs(track.tpcNSigmaKa()) < trackConfigs.nSigmaCutTPCKa) + return true; + return false; + } + + template + bool selectionPIDKaonpTdependent(const T& track) + { + if (track.pt() < 0.5 && std::abs(track.tpcNSigmaKa()) < trackConfigs.nSigmaCutTPCKa) + return true; + if (track.pt() >= 0.5 && track.hasTOF() && (std::pow(track.tofNSigmaKa(), 2) + std::pow(track.tpcNSigmaKa(), 2)) < std::pow(trackConfigs.nSigmaCutCombinedKa, 2)) + return true; + return false; + } + + // Reconstruct the Phi + template + ROOT::Math::PxPyPzMVector recMother(const T1& track1, const T2& track2, float masscand1, float masscand2) + { + ROOT::Math::PxPyPzMVector daughter1(track1.px(), track1.py(), track1.pz(), masscand1); // set the daughter1 4-momentum + ROOT::Math::PxPyPzMVector daughter2(track2.px(), track2.py(), track2.pz(), masscand2); // set the daughter2 4-momentum + ROOT::Math::PxPyPzMVector mother = daughter1 + daughter2; // calculate the mother 4-momentum + + return mother; + } + + // Topological selection for pions + template + bool selectionPion(const T& track, bool isQA) + { + if (!track.hasITS()) + return false; + if (track.itsNCls() < trackConfigs.minITSnCls) + return false; + if (track.itsChi2NCl() > trackConfigs.maxChi2ITS) + return false; + + if (!track.hasTPC()) + return false; + if (track.tpcNClsFound() < trackConfigs.minTPCnClsFound) + return false; + if (track.tpcNClsCrossedRows() < trackConfigs.minNCrossedRowsTPC) + return false; + if (track.tpcChi2NCl() > trackConfigs.maxChi2TPC) + return false; + + if (track.pt() < trackConfigs.cMinPionPtcut) + return false; + if (std::abs(track.eta()) > trackConfigs.etaMax) + return false; + + if constexpr (isTOFChecked) { + if (track.pt() >= 0.5 && !track.hasTOF()) + return false; + } + + if (isQA) { + if constexpr (!isMC) { + dataPionHist.fill(HIST("h2TracksPiDCAxyPreCutData"), track.pt(), track.dcaXY()); + dataPionHist.fill(HIST("h2TracksPiDCAzPreCutData"), track.pt(), track.dcaZ()); + } else { + mcPionHist.fill(HIST("h2TracksPiDCAxyPreCutMCReco"), track.pt(), track.dcaXY()); + mcPionHist.fill(HIST("h2TracksPiDCAzPreCutMCReco"), track.pt(), track.dcaZ()); + } + } + if (std::abs(track.dcaXY()) > trackConfigs.cMaxDCArToPV1Pion + (trackConfigs.cMaxDCArToPV2Pion / std::pow(track.pt(), trackConfigs.cMaxDCArToPV3Pion))) + return false; + if (isQA) { + if constexpr (!isMC) { + dataPionHist.fill(HIST("h2TracksPiDCAxyPostCutData"), track.pt(), track.dcaXY()); + dataPionHist.fill(HIST("h2TracksPiDCAzPostCutData"), track.pt(), track.dcaZ()); + } else { + mcPionHist.fill(HIST("h2TracksPiDCAxyPostCutMCReco"), track.pt(), track.dcaXY()); + mcPionHist.fill(HIST("h2TracksPiDCAzPostCutMCReco"), track.pt(), track.dcaZ()); + } + } + if (trackConfigs.cfgIsDCAzParameterized) { + if (std::abs(track.dcaZ()) > trackConfigs.cMaxDCAzToPV1Pion + (trackConfigs.cMaxDCAzToPV2Pion / std::pow(track.pt(), trackConfigs.cMaxDCAzToPV3Pion))) + return false; + } else { + if (std::abs(track.dcaZ()) > trackConfigs.cMaxDCAzToPVcut) + return false; + } + return true; + } + + // Get phi-meson purity functions from CCDB + void getPhiPurityFunctionsFromCCDB() + { + TList* listPhiPurityFunctions = ccdb->get(ccdbPurityPath); + if (!listPhiPurityFunctions) + LOG(fatal) << "Problem getting TList object with phi purity functions!"; + + for (size_t multIdx = 0; multIdx < binsMult->size() - 1; multIdx++) { + for (size_t ptIdx = 0; ptIdx < binspTPhi->size() - 1; ptIdx++) { + phiPurityFunctions[multIdx][ptIdx] = static_cast(listPhiPurityFunctions->FindObject(Form("funcFitPhiPur_%zu_%zu", multIdx, ptIdx))); + } + } + } + + // Get the phi purity choosing the correct purity function according to the multiplicity and pt of the phi + double getPhiPurity(float multiplicity, const ROOT::Math::PxPyPzMVector& Phi) + { + // Check if multiplicity is out of range + if (multiplicity < binsMult->front() || multiplicity >= binsMult->back()) { + LOG(info) << "Multiplicity out of range: " << multiplicity; + return 0; + } + + // Find the multiplicity bin using upper_bound which finds the first element strictly greater than 'multiplicity' + // Subtract 1 to get the correct bin index + auto multIt = std::upper_bound(binsMult->begin(), binsMult->end(), multiplicity); + int multIdx = std::distance(binsMult->begin(), multIt) - 1; + + // Check if pT is out of range + if (Phi.Pt() < binspTPhi->front() || Phi.Pt() >= binspTPhi->back()) { + LOG(info) << "pT out of range: " << Phi.Pt(); + return 0; + } + + // Find the pT bin using upper_bound + // The logic is the same as for multiplicity + auto pTIt = std::upper_bound(binspTPhi->begin(), binspTPhi->end(), Phi.Pt()); + int pTIdx = std::distance(binspTPhi->begin(), pTIt) - 1; + + return phiPurityFunctions[multIdx][pTIdx]->Eval(Phi.M()); + } + + // Fill 2D invariant mass histogram for V0 and Phi + template + void fillInvMass2D(const T& V0, const std::vector& listPhi, float multiplicity, const std::vector& weights) + { + for (const auto& Phi : listPhi) { + if constexpr (!isMC) { // same event + dataPhiK0SHist.fill(HIST("h5PhiK0SData"), 0, multiplicity, V0.pt(), V0.mK0Short(), Phi.M(), weights.at(0)); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(V0.yK0Short() - Phi.Rapidity()) > cfgDeltaYAcceptanceBins->at(i)) + continue; + dataPhiK0SHist.fill(HIST("h5PhiK0SData"), i + 1, multiplicity, V0.pt(), V0.mK0Short(), Phi.M(), weights.at(i + 1)); + } + } else { // MC event + closureMCPhiK0SHist.fill(HIST("h5PhiK0SMCClosure"), 0, multiplicity, V0.pt(), V0.mK0Short(), Phi.M(), weights.at(0)); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(V0.yK0Short() - Phi.Rapidity()) > cfgDeltaYAcceptanceBins->at(i)) + continue; + closureMCPhiK0SHist.fill(HIST("h5PhiK0SMCClosure"), i + 1, multiplicity, V0.pt(), V0.mK0Short(), Phi.M(), weights.at(i + 1)); + } + } + } + } + + // Fill Phi invariant mass vs Pion nSigmaTPC/TOF histogram + template + void fillInvMassNSigma(const T& Pi, const std::vector& listPhi, float multiplicity, const std::vector& weights) + { + float nSigmaTOFPi = (Pi.hasTOF() ? Pi.tofNSigmaPi() : -999); + + for (const auto& Phi : listPhi) { + if constexpr (!isMC) { // same event + dataPhiPionHist.fill(HIST("h6PhiPiData"), 0, multiplicity, Pi.pt(), Pi.tpcNSigmaPi(), nSigmaTOFPi, Phi.M(), weights.at(0)); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(Pi.rapidity(massPi) - Phi.Rapidity()) > cfgDeltaYAcceptanceBins->at(i)) + continue; + dataPhiPionHist.fill(HIST("h6PhiPiData"), i + 1, multiplicity, Pi.pt(), Pi.tpcNSigmaPi(), nSigmaTOFPi, Phi.M(), weights.at(i + 1)); + } + } else { // MC event + closureMCPhiPionHist.fill(HIST("h6PhiPiMCClosure"), 0, multiplicity, Pi.pt(), Pi.tpcNSigmaPi(), nSigmaTOFPi, Phi.M(), weights.at(0)); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(Pi.rapidity(massPi) - Phi.Rapidity()) > cfgDeltaYAcceptanceBins->at(i)) + continue; + closureMCPhiPionHist.fill(HIST("h6PhiPiMCClosure"), i + 1, multiplicity, Pi.pt(), Pi.tpcNSigmaPi(), nSigmaTOFPi, Phi.M(), weights.at(i + 1)); + } + } + } + } + + // Fill invariant mass histogram for V0 + template + void fillInvMass(const T& V0, float multiplicity, const std::vector& weights) + { + if constexpr (!isMC) { // same event + dataPhiK0SHist.fill(HIST("h3PhiK0SSEIncNew"), multiplicity, V0.pt(), V0.mK0Short(), weights.at(0)); + dataPhiK0SHist.fill(HIST("h3PhiK0SSEFCutNew"), multiplicity, V0.pt(), V0.mK0Short(), weights.at(1)); + dataPhiK0SHist.fill(HIST("h3PhiK0SSESCutNew"), multiplicity, V0.pt(), V0.mK0Short(), weights.at(2)); + } else { // MC event + closureMCPhiK0SHist.fill(HIST("h3ClosureMCPhiK0SSEIncNew"), multiplicity, V0.pt(), V0.mK0Short(), weights.at(0)); + closureMCPhiK0SHist.fill(HIST("h3ClosureMCPhiK0SSEFCutNew"), multiplicity, V0.pt(), V0.mK0Short(), weights.at(1)); + closureMCPhiK0SHist.fill(HIST("h3ClosureMCPhiK0SSESCutNew"), multiplicity, V0.pt(), V0.mK0Short(), weights.at(2)); + } + } + + // Fill nSigmaTPC/TOF histogram for Pion + template + void fillNSigma(const T& Pi, float multiplicity, const std::vector& weights) + { + float nSigmaTOFPi = (Pi.hasTOF() ? Pi.tofNSigmaPi() : -999); + + if constexpr (!isMC) { // same event + dataPhiPionHist.fill(HIST("h4PhiPiSEIncNew"), multiplicity, Pi.pt(), Pi.tpcNSigmaPi(), nSigmaTOFPi, weights.at(0)); + dataPhiPionHist.fill(HIST("h4PhiPiSEFCutNew"), multiplicity, Pi.pt(), Pi.tpcNSigmaPi(), nSigmaTOFPi, weights.at(1)); + dataPhiPionHist.fill(HIST("h4PhiPiSESCutNew"), multiplicity, Pi.pt(), Pi.tpcNSigmaPi(), nSigmaTOFPi, weights.at(2)); + } else { // MC event + closureMCPhiPionHist.fill(HIST("h4ClosureMCPhiPiSEIncNew"), multiplicity, Pi.pt(), Pi.tpcNSigmaPi(), nSigmaTOFPi, weights.at(0)); + closureMCPhiPionHist.fill(HIST("h4ClosureMCPhiPiSEFCutNew"), multiplicity, Pi.pt(), Pi.tpcNSigmaPi(), nSigmaTOFPi, weights.at(1)); + closureMCPhiPionHist.fill(HIST("h4ClosureMCPhiPiSESCutNew"), multiplicity, Pi.pt(), Pi.tpcNSigmaPi(), nSigmaTOFPi, weights.at(2)); + } + } + + void processQAPurity(SelCollisions::iterator const& collision, FullTracks const& fullTracks, FullV0s const& V0s, V0DauTracks const&) + { + // Check if the event selection is passed + if (!acceptEventQA(collision, true)) + return; + + float multiplicity = collision.centFT0M(); + dataEventHist.fill(HIST("hMultiplicityPercent"), multiplicity); + + // Defining positive and negative tracks for phi reconstruction + auto posThisColl = posTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negThisColl = negTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + bool isCountedPhi = false; + bool isFilledhV0 = false; + + double weight{1.0}; + + // Loop over all positive tracks + for (const auto& track1 : posThisColl) { + if (!selectionTrackResonance(track1, true) || !selectionPIDKaonpTdependent(track1)) + continue; // topological and PID selection + + dataPhiHist.fill(HIST("hEta"), track1.eta()); + dataPhiHist.fill(HIST("hNsigmaKaonTPC"), track1.tpcInnerParam(), track1.tpcNSigmaKa()); + dataPhiHist.fill(HIST("hNsigmaKaonTOF"), track1.tpcInnerParam(), track1.tofNSigmaKa()); + + auto track1ID = track1.globalIndex(); + + // Loop over all negative tracks + for (const auto& track2 : negThisColl) { + if (!selectionTrackResonance(track2, true) || !selectionPIDKaonpTdependent(track2)) + continue; // topological and PID selection + + auto track2ID = track2.globalIndex(); + if (track2ID == track1ID) + continue; // condition to avoid double counting of pair + + ROOT::Math::PxPyPzMVector recPhi = recMother(track1, track2, massKa, massKa); + if (recPhi.Pt() < minPhiPt || recPhi.Pt() > maxPhiPt) + continue; + if (std::abs(recPhi.Rapidity()) > cfgYAcceptance) + continue; + + if (!isCountedPhi) { + dataEventHist.fill(HIST("hEventSelection"), 4); // at least a Phi candidate in the event + dataEventHist.fill(HIST("hMultiplicityPercentWithPhi"), multiplicity); + isCountedPhi = true; + } + + if (fillMethodSingleWeight) + weight *= (1 - getPhiPurity(multiplicity, recPhi)); + + dataPhiHist.fill(HIST("h3PhipurData"), multiplicity, recPhi.Pt(), recPhi.M()); + + std::vector countsK0S(cfgDeltaYAcceptanceBins->size() + 1, 0); + + // V0 already reconstructed by the builder + for (const auto& v0 : V0s) { + const auto& posDaughterTrack = v0.posTrack_as(); + const auto& negDaughterTrack = v0.negTrack_as(); + + // Cut on V0 dynamic columns + if (!selectionV0(v0, posDaughterTrack, negDaughterTrack)) + continue; + if (v0Configs.cfgFurtherV0Selection && !furtherSelectionV0(v0, collision)) + continue; + + if (!isFilledhV0) { + dataK0SHist.fill(HIST("hDCAV0Daughters"), v0.dcaV0daughters()); + dataK0SHist.fill(HIST("hV0CosPA"), v0.v0cosPA()); + + // Filling the PID of the V0 daughters in the region of the K0 peak + if (lowMK0S < v0.mK0Short() && v0.mK0Short() < upMK0S) { + dataK0SHist.fill(HIST("hNSigmaPosPionFromK0S"), posDaughterTrack.tpcInnerParam(), posDaughterTrack.tpcNSigmaPi()); + dataK0SHist.fill(HIST("hNSigmaNegPionFromK0S"), negDaughterTrack.tpcInnerParam(), negDaughterTrack.tpcNSigmaPi()); + } + } + + if (std::abs(v0.yK0Short()) > cfgYAcceptance) + continue; + + countsK0S.at(0)++; + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(v0.yK0Short() - recPhi.Rapidity()) > cfgDeltaYAcceptanceBins->at(i)) + continue; + countsK0S.at(i + 1)++; + } + } + + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size() + 1; i++) { + if (countsK0S.at(i) > 0) + dataPhiHist.fill(HIST("h4PhipurK0SData"), i, multiplicity, recPhi.Pt(), recPhi.M()); + } + + isFilledhV0 = true; + + std::vector countsPi(cfgDeltaYAcceptanceBins->size(), 0); + + // Loop over all primary pion candidates + for (const auto& track : fullTracks) { + if (!selectionPion(track, false)) + continue; + + if (std::abs(track.rapidity(massPi)) > cfgYAcceptance) + continue; + + countsPi.at(0)++; + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(track.rapidity(massPi) - recPhi.Rapidity()) > cfgDeltaYAcceptanceBins->at(i)) + continue; + countsPi.at(i + 1)++; + } + } + + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size() + 1; i++) { + if (countsPi.at(i) > 0) + dataPhiHist.fill(HIST("h4PhipurPiData"), i, multiplicity, recPhi.Pt(), recPhi.M()); + } + } + } + + weight = 1 - weight; + dataEventHist.fill(HIST("hEventSelection"), 5, weight); // at least a Phi in the event + } + + PROCESS_SWITCH(Phik0shortanalysis, processQAPurity, "Process for QA and Phi Purities", true); + + void processSEPhiK0S(soa::Filtered::iterator const& collision, FullTracks const&, FullV0s const& V0s, V0DauTracks const&) + { + if (!collision.isInelGt0()) + return; + + float multiplicity = collision.centFT0M(); + dataEventHist.fill(HIST("hMultiplicityPercent"), multiplicity); + + // Defining positive and negative tracks for phi reconstruction + auto posThisColl = posTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negThisColl = negTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + // V0 already reconstructed by the builder + for (const auto& v0 : V0s) { + const auto& posDaughterTrack = v0.posTrack_as(); + const auto& negDaughterTrack = v0.negTrack_as(); + + // Cut on V0 dynamic columns + if (!selectionV0(v0, posDaughterTrack, negDaughterTrack)) + continue; + if (v0Configs.cfgFurtherV0Selection && !furtherSelectionV0(v0, collision)) + continue; + + dataK0SHist.fill(HIST("h3K0SRapidityData"), multiplicity, v0.pt(), v0.yK0Short()); + + if (std::abs(v0.yK0Short()) > cfgYAcceptance) + continue; + + std::vector listrecPhi; + std::vector counts(cfgDeltaYAcceptanceBins->size() + 1, 0); + std::vector weights(cfgDeltaYAcceptanceBins->size() + 1, 1); + + // Phi reconstruction + // Loop over positive tracks + for (const auto& track1 : posThisColl) { + if (!selectionTrackResonance(track1, false) || !selectionPIDKaonpTdependent(track1)) + continue; // topological and PID selection + + auto track1ID = track1.globalIndex(); + + // Loop over all negative tracks + for (const auto& track2 : negThisColl) { + if (!selectionTrackResonance(track2, false) || !selectionPIDKaonpTdependent(track2)) + continue; // topological and PID selection + + auto track2ID = track2.globalIndex(); + if (track2ID == track1ID) + continue; // condition to avoid double counting of pair + + ROOT::Math::PxPyPzMVector recPhi = recMother(track1, track2, massKa, massKa); + if (recPhi.Pt() < minPhiPt || recPhi.Pt() > maxPhiPt) + continue; + if (recPhi.M() < lowMPhi || recPhi.M() > upMPhi) + continue; + if (std::abs(recPhi.Rapidity()) > cfgYAcceptance) + continue; + + double phiPurity{}; + if (fillMethodSingleWeight) + phiPurity = getPhiPurity(multiplicity, recPhi); + + if (fillMethodMultipleWeights) + listrecPhi.push_back(recPhi); + + counts.at(0)++; + weights.at(0) *= (1 - phiPurity); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(v0.yK0Short() - recPhi.Rapidity()) > cfgDeltaYAcceptanceBins->at(i)) + continue; + counts.at(i + 1)++; + weights.at(i + 1) *= (1 - phiPurity); + } + } + } + + if (fillMethodMultipleWeights) { + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size() + 1; i++) { + weights.at(i) = (counts.at(i) > 0 ? 1. / static_cast(counts.at(i)) : 0); + } + fillInvMass2D(v0, listrecPhi, multiplicity, weights); + } else if (fillMethodSingleWeight) { + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size() + 1; i++) { + weights.at(i) = (counts.at(i) > 0 ? 1 - weights.at(i) : 0); + } + fillInvMass(v0, multiplicity, weights); + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processSEPhiK0S, "Process Same Event for Phi-K0S Analysis", false); + + void processSEPhiPion(soa::Filtered::iterator const& collision, FullTracks const& fullTracks) + { + if (!collision.isInelGt0()) + return; + + float multiplicity = collision.centFT0M(); + dataEventHist.fill(HIST("hMultiplicityPercent"), multiplicity); + + // Defining positive and negative tracks for phi reconstruction + auto posThisColl = posTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negThisColl = negTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + // Loop over all primary pion candidates + for (const auto& track : fullTracks) { + + // Pion selection + if (!selectionPion(track, true)) + continue; + + dataPionHist.fill(HIST("h3PiRapidityData"), multiplicity, track.pt(), track.rapidity(massPi)); + + if (std::abs(track.rapidity(massPi)) > cfgYAcceptance) + continue; + + std::vector listrecPhi; + std::vector counts(cfgDeltaYAcceptanceBins->size() + 1, 0); + std::vector weights(cfgDeltaYAcceptanceBins->size() + 1, 1); + + // Phi reconstruction + // Loop over positive tracks + for (const auto& track1 : posThisColl) { // loop over all selected tracks + if (!selectionTrackResonance(track1, false) || !selectionPIDKaonpTdependent(track1)) + continue; // topological and PID selection + + auto track1ID = track1.globalIndex(); + + // Loop over all negative tracks + for (const auto& track2 : negThisColl) { + if (!selectionTrackResonance(track2, false) || !selectionPIDKaonpTdependent(track2)) + continue; // topological and PID selection + + auto track2ID = track2.globalIndex(); + if (track2ID == track1ID) + continue; // condition to avoid double counting of pair + + ROOT::Math::PxPyPzMVector recPhi = recMother(track1, track2, massKa, massKa); + if (recPhi.Pt() < minPhiPt || recPhi.Pt() > maxPhiPt) + continue; + if (recPhi.M() < lowMPhi || recPhi.M() > upMPhi) + continue; + if (std::abs(recPhi.Rapidity()) > cfgYAcceptance) + continue; + + double phiPurity{}; + if (fillMethodSingleWeight) + phiPurity = getPhiPurity(multiplicity, recPhi); + + if (fillMethodMultipleWeights) + listrecPhi.push_back(recPhi); + + counts.at(0)++; + weights.at(0) *= (1 - phiPurity); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(track.rapidity(massPi) - recPhi.Rapidity()) > cfgDeltaYAcceptanceBins->at(i)) + continue; + counts.at(i + 1)++; + weights.at(i + 1) *= (1 - phiPurity); + } + } + } + + if (fillMethodMultipleWeights) { + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size() + 1; i++) { + weights.at(i) = (counts.at(i) > 0 ? 1. / static_cast(counts.at(i)) : 0); + } + fillInvMassNSigma(track, listrecPhi, multiplicity, weights); + } else if (fillMethodSingleWeight) { + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size() + 1; i++) { + weights.at(i) = (counts.at(i) > 0 ? 1 - weights.at(i) : 0); + } + fillNSigma(track, multiplicity, weights); + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processSEPhiPion, "Process Same Event for Phi-Pion Analysis", false); + + void processRecMCPhiQA(SimCollisions::iterator const& collision, FullMCTracks const& fullMCTracks, FullMCV0s const& V0s, V0DauMCTracks const&, MCCollisions const&, aod::McParticles const&) + { + if (!acceptEventQA(collision, true)) + return; + + float multiplicity = collision.centFT0M(); + mcEventHist.fill(HIST("hRecMCMultiplicityPercent"), multiplicity); + + if (!collision.has_mcCollision()) + return; + mcEventHist.fill(HIST("hRecMCEventSelection"), 6); // with at least a gen collision + + const auto& mcCollision = collision.mcCollision_as(); + float genmultiplicity = mcCollision.centFT0M(); + mcEventHist.fill(HIST("hRecMCGenMultiplicityPercent"), genmultiplicity); + + // Defining positive and negative tracks for phi reconstruction + auto posThisColl = posMCTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negThisColl = negMCTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + bool isCountedPhi = false; + + // Loop over all positive tracks + for (const auto& track1 : posThisColl) { + if (!selectionTrackResonance(track1, false) || !selectionPIDKaonpTdependent(track1)) + continue; // topological and PID selection + + auto track1ID = track1.globalIndex(); + + if (!track1.has_mcParticle()) + continue; + auto mcTrack1 = track1.mcParticle_as(); + if (mcTrack1.pdgCode() != PDG_t::kKPlus || !mcTrack1.isPhysicalPrimary()) + continue; + + // Loop over all negative tracks + for (const auto& track2 : negThisColl) { + if (!selectionTrackResonance(track2, false) || !selectionPIDKaonpTdependent(track2)) + continue; // topological and PID selection + + auto track2ID = track2.globalIndex(); + if (track2ID == track1ID) + continue; // condition to avoid double counting of pair + + if (!track2.has_mcParticle()) + continue; + auto mcTrack2 = track2.mcParticle_as(); + if (mcTrack2.pdgCode() != PDG_t::kKMinus || !mcTrack2.isPhysicalPrimary()) + continue; + + bool isMCMotherPhi = false; + auto mcMotherPhi = mcTrack1.mothers_as()[0]; + for (const auto& MotherOfmcTrack1 : mcTrack1.mothers_as()) { + for (const auto& MotherOfmcTrack2 : mcTrack2.mothers_as()) { + if (MotherOfmcTrack1 == MotherOfmcTrack2 && MotherOfmcTrack1.pdgCode() == o2::constants::physics::Pdg::kPhi) { + mcMotherPhi = MotherOfmcTrack1; + isMCMotherPhi = true; + } + } + } + + if (!isMCMotherPhi) + continue; + + ROOT::Math::PxPyPzMVector recPhi = recMother(track1, track2, massKa, massKa); + if (recPhi.Pt() < minPhiPt || recPhi.Pt() > maxPhiPt) + continue; + + mcPhiHist.fill(HIST("h3PhiRapiditySmearing"), genmultiplicity, recPhi.Rapidity(), mcMotherPhi.y()); + + if (std::abs(recPhi.Rapidity()) > cfgYAcceptance) + continue; + + if (!isCountedPhi) { + mcEventHist.fill(HIST("hRecMCEventSelection"), 7); // at least a Phi in the event + isCountedPhi = true; + } + + mcPhiHist.fill(HIST("h2PhieffInvMass"), genmultiplicity, recPhi.M()); + + std::array isCountedK0S{false, false, false}; + + // V0 already reconstructed by the builder + for (const auto& v0 : V0s) { + if (!v0.has_mcParticle()) { + continue; + } + + auto v0mcparticle = v0.mcParticle(); + if (v0mcparticle.pdgCode() != PDG_t::kK0Short || !v0mcparticle.isPhysicalPrimary()) + continue; + + const auto& posDaughterTrack = v0.posTrack_as(); + const auto& negDaughterTrack = v0.negTrack_as(); + + // Cut on V0 dynamic columns + if (!selectionV0(v0, posDaughterTrack, negDaughterTrack)) + continue; + if (v0Configs.cfgFurtherV0Selection && !furtherSelectionV0(v0, collision)) + continue; + + if (std::abs(v0.yK0Short()) > cfgYAcceptance) + continue; + if (!isCountedK0S.at(0)) { + mcPhiHist.fill(HIST("h3PhieffK0SInvMassInc"), genmultiplicity, v0.pt(), recPhi.M()); + isCountedK0S.at(0) = true; + } + if (std::abs(v0.yK0Short() - recPhi.Rapidity()) > cfgFCutOnDeltaY) + continue; + if (!isCountedK0S.at(1)) { + mcPhiHist.fill(HIST("h3PhieffK0SInvMassFCut"), genmultiplicity, v0.pt(), recPhi.M()); + isCountedK0S.at(1) = true; + } + if (std::abs(v0.yK0Short() - recPhi.Rapidity()) > cfgSCutOnDeltaY) + continue; + if (!isCountedK0S.at(2)) { + mcPhiHist.fill(HIST("h3PhieffK0SInvMassSCut"), genmultiplicity, v0.pt(), recPhi.M()); + isCountedK0S.at(2) = true; + } + } + + std::array isCountedPi{false, false, false}; + + // Loop over all primary pion candidates + for (const auto& track : fullMCTracks) { + if (!track.has_mcParticle()) + continue; + + auto mcTrack = track.mcParticle_as(); + if (std::abs(mcTrack.pdgCode()) != PDG_t::kPiPlus || !mcTrack.isPhysicalPrimary()) + continue; + + if (!selectionPion(track, false)) + continue; + + if (std::abs(track.rapidity(massPi)) > cfgYAcceptance) + continue; + if (!isCountedPi.at(0)) { + mcPhiHist.fill(HIST("h3PhieffPiInvMassInc"), genmultiplicity, track.pt(), recPhi.M()); + isCountedPi.at(0) = true; + } + if (std::abs(track.rapidity(massPi) - recPhi.Rapidity()) > cfgFCutOnDeltaY) + continue; + if (!isCountedPi.at(1)) { + mcPhiHist.fill(HIST("h3PhieffPiInvMassFCut"), genmultiplicity, track.pt(), recPhi.M()); + isCountedPi.at(1) = true; + } + if (std::abs(track.rapidity(massPi) - recPhi.Rapidity()) > cfgSCutOnDeltaY) + continue; + if (!isCountedPi.at(2)) { + mcPhiHist.fill(HIST("h3PhieffPiInvMassSCut"), genmultiplicity, track.pt(), recPhi.M()); + isCountedPi.at(2) = true; + } + } + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processRecMCPhiQA, "Process for ReCMCQA and Phi in RecMC", false); + + void processRecMCPhiK0S(SimCollisions const& collisions, FullMCV0s const& V0s, V0DauMCTracks const&, MCCollisions const&, aod::McParticles const& mcParticles) + { + for (const auto& collision : collisions) { + if (!acceptEventQA(collision, false)) + continue; + + if (!collision.has_mcCollision()) + continue; + + const auto& mcCollision = collision.mcCollision_as(); + float genmultiplicity = mcCollision.centFT0M(); + + // Defining V0s in the collision + auto v0sThisColl = V0s.sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + // Defining McParticles in the collision + auto mcParticlesThisColl = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); + + // V0 already reconstructed by the builder + for (const auto& v0 : v0sThisColl) { + if (!v0.has_mcParticle()) + continue; + + auto v0mcparticle = v0.mcParticle(); + if (v0mcparticle.pdgCode() != PDG_t::kK0Short || !v0mcparticle.isPhysicalPrimary()) + continue; + + const auto& posDaughterTrack = v0.posTrack_as(); + const auto& negDaughterTrack = v0.negTrack_as(); + + if (!selectionV0(v0, posDaughterTrack, negDaughterTrack)) + continue; + if (v0Configs.cfgFurtherV0Selection && !furtherSelectionV0(v0, collision)) + continue; + + mcK0SHist.fill(HIST("h4K0SRapiditySmearing"), genmultiplicity, v0.pt(), v0.yK0Short(), v0mcparticle.y()); + + if (std::abs(v0mcparticle.y()) > cfgYAcceptance) + continue; + + mcK0SHist.fill(HIST("h3K0SMCReco"), genmultiplicity, v0mcparticle.pt(), v0.mK0Short()); + + std::vector counts(cfgDeltaYAcceptanceBins->size() + 1, 0); + + for (const auto& mcParticle : mcParticlesThisColl) { + if (mcParticle.pdgCode() != o2::constants::physics::Pdg::kPhi) + continue; + if (mcParticle.pt() < minPhiPt || mcParticle.pt() > maxPhiPt) + continue; + if (std::abs(mcParticle.y()) > cfgYAcceptance) + continue; + + counts.at(0)++; + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(v0mcparticle.y() - mcParticle.y()) > cfgDeltaYAcceptanceBins->at(i)) + continue; + counts.at(i + 1)++; + } + } + + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size() + 1; i++) { + if (counts.at(i) > 0) + mcPhiK0SHist.fill(HIST("h4PhiK0SMCReco"), i, genmultiplicity, v0mcparticle.pt(), v0.mK0Short()); + } + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processRecMCPhiK0S, "Process RecMC for Phi-K0S Analysis", false); + + void processRecMCPhiPion(SimCollisions const& collisions, FullMCTracks const& fullMCTracks, MCCollisions const&, aod::McParticles const& mcParticles) + { + for (const auto& collision : collisions) { + if (!acceptEventQA(collision, false)) + continue; + + if (!collision.has_mcCollision()) + continue; + + const auto& mcCollision = collision.mcCollision_as(); + float genmultiplicity = mcCollision.centFT0M(); + + // Defining tracks in the collision + auto mcTracksThisColl = fullMCTracks.sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + // Defining McParticles in the collision + auto mcParticlesThisColl = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); + + // Loop over all primary pion candidates + for (const auto& track : mcTracksThisColl) { + // Pion selection + if (!selectionPion(track, false)) + continue; + + if (!track.has_mcParticle()) + continue; + + auto mcTrack = track.mcParticle_as(); + if (std::abs(mcTrack.pdgCode()) != PDG_t::kPiPlus) + continue; + + if (std::abs(mcTrack.y()) > cfgYAcceptance) + continue; + + // Primary pion selection + if (mcTrack.isPhysicalPrimary()) { + mcPionHist.fill(HIST("h3RecMCDCAxyPrimPi"), track.pt(), track.dcaXY()); + } else { + if (mcTrack.getProcess() == 4) { // Selection of secondary pions from weak decay + mcPionHist.fill(HIST("h3RecMCDCAxySecWeakDecayPi"), track.pt(), track.dcaXY()); + } else { // Selection of secondary pions from material interactions + mcPionHist.fill(HIST("h3RecMCDCAxySecMaterialPi"), track.pt(), track.dcaXY()); + } + continue; + } + + mcPionHist.fill(HIST("h4PiRapiditySmearing"), genmultiplicity, track.pt(), track.rapidity(massPi), mcTrack.y()); + + mcPionHist.fill(HIST("h3PiTPCMCReco"), genmultiplicity, mcTrack.pt(), track.tpcNSigmaPi()); + + std::vector countsTPC(cfgDeltaYAcceptanceBins->size() + 1, 0); + + for (const auto& mcParticle : mcParticlesThisColl) { + if (mcParticle.pdgCode() != o2::constants::physics::Pdg::kPhi) + continue; + if (mcParticle.pt() < minPhiPt || mcParticle.pt() > maxPhiPt) + continue; + if (std::abs(mcParticle.y()) > cfgYAcceptance) + continue; + + countsTPC.at(0)++; + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(mcTrack.y() - mcParticle.y()) > cfgDeltaYAcceptanceBins->at(i)) + continue; + countsTPC.at(i + 1)++; + } + } + + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size() + 1; i++) { + if (countsTPC.at(i) > 0) + mcPhiPionHist.fill(HIST("h4PhiPiTPCMCReco"), i, genmultiplicity, mcTrack.pt(), track.tpcNSigmaPi()); + } + + if (track.pt() >= 0.5 && !track.hasTOF()) + continue; + + mcPionHist.fill(HIST("h4PiTPCTOFMCReco"), genmultiplicity, mcTrack.pt(), track.tpcNSigmaPi(), track.tofNSigmaPi()); + + std::vector countsTPCTOF(cfgDeltaYAcceptanceBins->size() + 1, 0); + + for (const auto& mcParticle : mcParticlesThisColl) { + if (mcParticle.pdgCode() != o2::constants::physics::Pdg::kPhi) + continue; + if (mcParticle.pt() < minPhiPt || mcParticle.pt() > maxPhiPt) + continue; + if (std::abs(mcParticle.y()) > cfgYAcceptance) + continue; + + countsTPCTOF.at(0)++; + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(mcTrack.y() - mcParticle.y()) > cfgDeltaYAcceptanceBins->at(i)) + continue; + countsTPCTOF.at(i + 1)++; + } + } + + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size() + 1; i++) { + if (countsTPCTOF.at(i) > 0) + mcPhiPionHist.fill(HIST("h5PhiPiTPCTOFMCReco"), i, genmultiplicity, mcTrack.pt(), track.tpcNSigmaPi(), track.tofNSigmaPi()); + } + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processRecMCPhiPion, "Process RecMC for Phi-Pion Analysis", false); + + void processRecMCClosurePhiQA(SimCollisions::iterator const& collision, FullMCTracks const& fullMCTracks, FullMCV0s const& V0s, V0DauMCTracks const&, MCCollisions const&, aod::McParticles const&) + { + if (!acceptEventQA(collision, true)) + return; + + if (!collision.has_mcCollision()) + return; + mcEventHist.fill(HIST("hRecMCEventSelection"), 6); // with at least a gen collision + + const auto& mcCollision = collision.mcCollision_as(); + float genmultiplicity = mcCollision.centFT0M(); + mcEventHist.fill(HIST("hRecMCGenMultiplicityPercent"), genmultiplicity); + + // Defining positive and negative tracks for phi reconstruction + auto posThisColl = posMCTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negThisColl = negMCTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + bool isCountedPhi = false; + + double weight{1.0}; + + // Loop over all positive tracks + for (const auto& track1 : posThisColl) { + if (!selectionTrackResonance(track1, true) || !selectionPIDKaonpTdependent(track1)) + continue; // topological and PID selection + + auto track1ID = track1.globalIndex(); + + // Loop over all negative tracks + for (const auto& track2 : negThisColl) { + if (!selectionTrackResonance(track2, true) || !selectionPIDKaonpTdependent(track2)) + continue; // topological and PID selection + + auto track2ID = track2.globalIndex(); + if (track2ID == track1ID) + continue; // condition to avoid double counting of pair + + ROOT::Math::PxPyPzMVector recPhi = recMother(track1, track2, massKa, massKa); + if (recPhi.Pt() < minPhiPt || recPhi.Pt() > maxPhiPt) + continue; + if (std::abs(recPhi.Rapidity()) > cfgYAcceptance) + continue; + + if (!isCountedPhi) { + mcEventHist.fill(HIST("hRecMCEventSelection"), 7); // at least a Phi candidate in the event + mcEventHist.fill(HIST("hRecMCGenMultiplicityPercentWithPhi"), genmultiplicity); + isCountedPhi = true; + } + + if (fillMethodSingleWeight) + weight *= (1 - getPhiPurity(genmultiplicity, recPhi)); + + closureMCPhiHist.fill(HIST("h3PhipurMCClosure"), genmultiplicity, recPhi.Pt(), recPhi.M()); + + std::vector countsK0S(cfgDeltaYAcceptanceBins->size() + 1, 0); + + // V0 already reconstructed by the builder + for (const auto& v0 : V0s) { + if (cfgisRecMCWPDGForClosure1) { + if (!v0.has_mcParticle()) + continue; + auto v0mcparticle = v0.mcParticle(); + if (v0mcparticle.pdgCode() != PDG_t::kK0Short || !v0mcparticle.isPhysicalPrimary()) + continue; + } + + const auto& posDaughterTrack = v0.posTrack_as(); + const auto& negDaughterTrack = v0.negTrack_as(); + + if (!selectionV0(v0, posDaughterTrack, negDaughterTrack)) + continue; + if (v0Configs.cfgFurtherV0Selection && !furtherSelectionV0(v0, collision)) + continue; + + if (std::abs(v0.yK0Short()) > cfgYAcceptance) + continue; + + countsK0S.at(0)++; + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(v0.yK0Short() - recPhi.Rapidity()) > cfgDeltaYAcceptanceBins->at(i)) + continue; + countsK0S.at(i + 1)++; + } + } + + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size() + 1; i++) { + if (countsK0S.at(i) > 0) + closureMCPhiHist.fill(HIST("h4PhipurK0SInvMass"), i, genmultiplicity, recPhi.Pt(), recPhi.M()); + } + + std::vector countsPi(cfgDeltaYAcceptanceBins->size() + 1, 0); + + // Loop over all primary pion candidates + for (const auto& track : fullMCTracks) { + if (cfgisRecMCWPDGForClosure1) { + if (!track.has_mcParticle()) + continue; + auto mcTrack = track.mcParticle_as(); + if (std::abs(mcTrack.pdgCode()) != PDG_t::kPiPlus || !mcTrack.isPhysicalPrimary()) + continue; + } + + if (!selectionPion(track, false)) + continue; + + if (std::abs(track.rapidity(massPi)) > cfgYAcceptance) + continue; + + countsPi.at(0)++; + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(track.rapidity(massPi) - recPhi.Rapidity()) > cfgDeltaYAcceptanceBins->at(i)) + continue; + countsPi.at(i + 1)++; + } + } + + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size() + 1; i++) { + if (countsPi.at(i) > 0) + closureMCPhiHist.fill(HIST("h4PhipurPiInvMass"), i, genmultiplicity, recPhi.Pt(), recPhi.M()); + } + } + } + + weight = 1 - weight; + mcEventHist.fill(HIST("hRecMCEventSelection"), 8, weight); // at least a Phi in the event + } + + PROCESS_SWITCH(Phik0shortanalysis, processRecMCClosurePhiQA, "Process for ReCMCQA and Phi in RecMCClosure", false); + + void processRecMCClosurePhiK0S(SimCollisions::iterator const& collision, FullMCTracks const&, FullMCV0s const& V0s, V0DauMCTracks const&, MCCollisions const&, aod::McParticles const&) + { + if (!acceptEventQA(collision, false)) + return; + + if (!collision.has_mcCollision()) + return; + + const auto& mcCollision = collision.mcCollision_as(); + float genmultiplicity = mcCollision.centFT0M(); + + // Defining positive and negative tracks for phi reconstruction + auto posThisColl = posMCTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negThisColl = negMCTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + // V0 already reconstructed by the builder + for (const auto& v0 : V0s) { + if (cfgisRecMCWPDGForClosure1) { + if (!v0.has_mcParticle()) + continue; + auto v0mcparticle = v0.mcParticle(); + if (v0mcparticle.pdgCode() != PDG_t::kK0Short || !v0mcparticle.isPhysicalPrimary()) + continue; + } + + const auto& posDaughterTrack = v0.posTrack_as(); + const auto& negDaughterTrack = v0.negTrack_as(); + + if (!selectionV0(v0, posDaughterTrack, negDaughterTrack)) + continue; + if (v0Configs.cfgFurtherV0Selection && !furtherSelectionV0(v0, collision)) + continue; + + if (std::abs(v0.yK0Short()) > cfgYAcceptance) + continue; + + std::vector listrecPhi; + std::vector counts(cfgDeltaYAcceptanceBins->size() + 1, 0); + std::vector weights(cfgDeltaYAcceptanceBins->size() + 1, 1); + + // Phi reconstruction + for (const auto& track1 : posThisColl) { // loop over all selected tracks + if (!selectionTrackResonance(track1, false) || !selectionPIDKaonpTdependent(track1)) + continue; // topological and PID selection + + auto track1ID = track1.globalIndex(); + + for (const auto& track2 : negThisColl) { + if (!selectionTrackResonance(track2, false) || !selectionPIDKaonpTdependent(track2)) + continue; // topological and PID selection + + auto track2ID = track2.globalIndex(); + if (track2ID == track1ID) + continue; // condition to avoid double counting of pair + + if (cfgisRecMCWPDGForClosure2) { + if (!track1.has_mcParticle()) + continue; + auto mcTrack1 = track1.mcParticle_as(); + if (mcTrack1.pdgCode() != PDG_t::kKPlus || !mcTrack1.isPhysicalPrimary()) + continue; + + if (!track2.has_mcParticle()) + continue; + auto mcTrack2 = track2.mcParticle_as(); + if (mcTrack2.pdgCode() != PDG_t::kKMinus || !mcTrack2.isPhysicalPrimary()) + continue; + + bool isMCMotherPhi = false; + for (const auto& motherOfMcTrack1 : mcTrack1.mothers_as()) { + for (const auto& motherOfMcTrack2 : mcTrack2.mothers_as()) { + if (motherOfMcTrack1.pdgCode() != motherOfMcTrack2.pdgCode()) + continue; + if (motherOfMcTrack1.globalIndex() != motherOfMcTrack2.globalIndex()) + continue; + if (motherOfMcTrack1.pdgCode() != o2::constants::physics::Pdg::kPhi) + continue; + isMCMotherPhi = true; + } + } + if (!isMCMotherPhi) + continue; + } + + ROOT::Math::PxPyPzMVector recPhi = recMother(track1, track2, massKa, massKa); + if (recPhi.Pt() < minPhiPt || recPhi.Pt() > maxPhiPt) + continue; + if (recPhi.M() < lowMPhi || recPhi.M() > upMPhi) + continue; + if (std::abs(recPhi.Rapidity()) > cfgYAcceptance) + continue; + + double phiPurity{}; + if (fillMethodSingleWeight) + phiPurity = getPhiPurity(genmultiplicity, recPhi); + + if (fillMethodMultipleWeights) + listrecPhi.push_back(recPhi); + + counts.at(0)++; + weights.at(0) *= (1 - phiPurity); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(v0.yK0Short() - recPhi.Rapidity()) > cfgDeltaYAcceptanceBins->at(i)) + continue; + counts.at(i + 1)++; + weights.at(i + 1) *= (1 - phiPurity); + } + } + } + + if (fillMethodMultipleWeights) { + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size() + 1; i++) { + weights.at(i) = (counts.at(i) > 0 ? 1. / static_cast(counts.at(i)) : 0); + } + fillInvMass2D(v0, listrecPhi, genmultiplicity, weights); + } else if (fillMethodSingleWeight) { + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size() + 1; i++) { + weights.at(i) = (counts.at(i) > 0 ? 1 - weights.at(i) : 0); + } + fillInvMass(v0, genmultiplicity, weights); + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processRecMCClosurePhiK0S, "Process RecMC for MCClosure Phi-K0S Analysis", false); + + void processRecMCClosurePhiPion(SimCollisions::iterator const& collision, FullMCTracks const& fullMCTracks, MCCollisions const&, aod::McParticles const&) + { + if (!acceptEventQA(collision, false)) + return; + + if (!collision.has_mcCollision()) + return; + + const auto& mcCollision = collision.mcCollision_as(); + float genmultiplicity = mcCollision.centFT0M(); + + // Defining positive and negative tracks for phi reconstruction + auto posThisColl = posMCTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negThisColl = negMCTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + // Loop over all primary pion candidates + for (const auto& track : fullMCTracks) { + if (cfgisRecMCWPDGForClosure1) { + if (!track.has_mcParticle()) + continue; + auto mcTrack = track.mcParticle_as(); + if (std::abs(mcTrack.pdgCode()) != PDG_t::kPiPlus || !mcTrack.isPhysicalPrimary()) + continue; + } + + // Pion selection + if (!selectionPion(track, true)) + continue; + + if (std::abs(track.rapidity(massPi)) > cfgYAcceptance) + continue; + + std::vector listrecPhi; + std::vector counts(cfgDeltaYAcceptanceBins->size() + 1, 0); + std::vector weights(cfgDeltaYAcceptanceBins->size() + 1, 1); + + // Phi reconstruction + for (const auto& track1 : posThisColl) { // loop over all selected tracks + if (!selectionTrackResonance(track1, false) || !selectionPIDKaonpTdependent(track1)) + continue; // topological and PID selection + + auto track1ID = track1.globalIndex(); + + for (const auto& track2 : negThisColl) { + if (!selectionTrackResonance(track2, false) || !selectionPIDKaonpTdependent(track2)) + continue; // topological and PID selection + + auto track2ID = track2.globalIndex(); + if (track2ID == track1ID) + continue; // condition to avoid double counting of pair + + if (cfgisRecMCWPDGForClosure2) { + if (!track1.has_mcParticle()) + continue; + auto mcTrack1 = track1.mcParticle_as(); + if (mcTrack1.pdgCode() != PDG_t::kKPlus || !mcTrack1.isPhysicalPrimary()) + continue; + + if (!track2.has_mcParticle()) + continue; + auto mcTrack2 = track2.mcParticle_as(); + if (mcTrack2.pdgCode() != PDG_t::kKMinus || !mcTrack2.isPhysicalPrimary()) + continue; + + bool isMCMotherPhi = false; + for (const auto& motherOfMcTrack1 : mcTrack1.mothers_as()) { + for (const auto& motherOfMcTrack2 : mcTrack2.mothers_as()) { + if (motherOfMcTrack1.pdgCode() != motherOfMcTrack2.pdgCode()) + continue; + if (motherOfMcTrack1.globalIndex() != motherOfMcTrack2.globalIndex()) + continue; + if (motherOfMcTrack1.pdgCode() != o2::constants::physics::Pdg::kPhi) + continue; + isMCMotherPhi = true; + } + } + if (!isMCMotherPhi) + continue; + } + + ROOT::Math::PxPyPzMVector recPhi = recMother(track1, track2, massKa, massKa); + if (recPhi.Pt() < minPhiPt || recPhi.Pt() > maxPhiPt) + continue; + if (recPhi.M() < lowMPhi || recPhi.M() > upMPhi) + continue; + if (std::abs(recPhi.Rapidity()) > cfgYAcceptance) + continue; + + double phiPurity{}; + if (fillMethodSingleWeight) + phiPurity = getPhiPurity(genmultiplicity, recPhi); + + if (fillMethodMultipleWeights) + listrecPhi.push_back(recPhi); + + counts.at(0)++; + weights.at(0) *= (1 - phiPurity); + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(track.rapidity(massPi) - recPhi.Rapidity()) > cfgDeltaYAcceptanceBins->at(i)) + continue; + counts.at(i + 1)++; + weights.at(i + 1) *= (1 - phiPurity); + } + } + } + + if (fillMethodMultipleWeights) { + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size() + 1; i++) { + weights.at(i) = (counts.at(i) > 0 ? 1. / static_cast(counts.at(i)) : 0); + } + fillInvMassNSigma(track, listrecPhi, genmultiplicity, weights); + } else if (fillMethodSingleWeight) { + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size() + 1; i++) { + weights.at(i) = (counts.at(i) > 0 ? 1 - weights.at(i) : 0); + } + fillNSigma(track, genmultiplicity, weights); + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processRecMCClosurePhiPion, "Process RecMC for MCClosure Phi-Pion Analysis", false); + + void processGenMCPhiQA(MCCollisions::iterator const& mcCollision, soa::SmallGroups const& collisions, aod::McParticles const& mcParticles) + { + mcEventHist.fill(HIST("hGenMCEventSelection"), 0); // all collisions + if (std::abs(mcCollision.posZ()) > cutZVertex) + return; + mcEventHist.fill(HIST("hGenMCEventSelection"), 1); // vertex-Z selected + mcEventHist.fill(HIST("hGenMCVertexZ"), mcCollision.posZ()); + if (!pwglf::isINELgtNmc(mcParticles, 0, pdgDB)) + return; + mcEventHist.fill(HIST("hGenMCEventSelection"), 2); // INEL>0 collisions + + bool isAssocColl = false; + for (const auto& collision : collisions) { + if (acceptEventQA(collision, false)) { + isAssocColl = true; + break; + } + } + + float genmultiplicity = mcCollision.centFT0M(); + mcEventHist.fill(HIST("hGenMCMultiplicityPercent"), genmultiplicity); + + bool isCountedPhi = false; + + for (const auto& mcParticle1 : mcParticles) { + if (mcParticle1.pdgCode() != o2::constants::physics::Pdg::kPhi) + continue; + auto kDaughters = mcParticle1.daughters_as(); + if (kDaughters.size() != 2) + continue; + bool isPosKaon = false, isNegKaon = false; + for (const auto& kDaughter : kDaughters) { + if (kDaughter.pdgCode() == PDG_t::kKPlus) + isPosKaon = true; + if (kDaughter.pdgCode() == PDG_t::kKMinus) + isNegKaon = true; + } + if (!isPosKaon || !isNegKaon) + continue; + if (std::abs(mcParticle1.y()) > cfgYAcceptance) + continue; + + if (!isCountedPhi) { + mcEventHist.fill(HIST("hGenMCEventSelection"), 3); // at least a Phi in the event + if (isAssocColl) + mcEventHist.fill(HIST("hGenMCEventSelection"), 4); // with at least a reco collision + isCountedPhi = true; + } + + mcPhiHist.fill(HIST("h1PhiGenMC"), genmultiplicity); + if (isAssocColl) + mcPhiHist.fill(HIST("h1PhiGenMCAssocReco"), genmultiplicity); + + std::array isCountedK0S = {false, false, false}; + + for (const auto& mcParticle2 : mcParticles) { + if (mcParticle2.pdgCode() != PDG_t::kK0Short) + continue; + if (!mcParticle2.isPhysicalPrimary()) + continue; + + if (std::abs(mcParticle2.y()) > cfgYAcceptance) + continue; + if (!isCountedK0S.at(0)) { + mcPhiHist.fill(HIST("h2PhieffK0SGenMCInc"), genmultiplicity, mcParticle2.pt()); + if (isAssocColl) + mcPhiHist.fill(HIST("h2PhieffK0SGenMCFCutAssocReco"), genmultiplicity, mcParticle2.pt()); + isCountedK0S.at(0) = true; + } + if (std::abs(mcParticle1.y() - mcParticle2.y()) > cfgFCutOnDeltaY) + continue; + if (!isCountedK0S.at(1)) { + mcPhiHist.fill(HIST("h2PhieffK0SGenMCFCut"), genmultiplicity, mcParticle2.pt()); + if (isAssocColl) + mcPhiHist.fill(HIST("h2PhieffK0SGenMCFCutAssocReco"), genmultiplicity, mcParticle2.pt()); + isCountedK0S.at(1) = true; + } + if (std::abs(mcParticle1.y() - mcParticle2.y()) > cfgSCutOnDeltaY) + continue; + if (!isCountedK0S.at(2)) { + mcPhiHist.fill(HIST("h2PhieffK0SGenMCSCut"), genmultiplicity, mcParticle2.pt()); + if (isAssocColl) + mcPhiHist.fill(HIST("h2PhieffK0SGenMCSCutAssocReco"), genmultiplicity, mcParticle2.pt()); + isCountedK0S.at(2) = true; + } + } + + std::array isCountedPi = {false, false, false}; + + for (const auto& mcParticle2 : mcParticles) { + if (std::abs(mcParticle2.pdgCode()) != PDG_t::kPiPlus) + continue; + if (!mcParticle2.isPhysicalPrimary()) + continue; + + if (std::abs(mcParticle2.y()) > cfgYAcceptance) + continue; + if (!isCountedPi.at(0)) { + mcPhiHist.fill(HIST("h2PhieffPiGenMCInc"), genmultiplicity, mcParticle2.pt()); + if (isAssocColl) + mcPhiHist.fill(HIST("h2PhieffPiGenMCIncAssocReco"), genmultiplicity, mcParticle2.pt()); + isCountedPi.at(0) = true; + } + if (std::abs(mcParticle1.y() - mcParticle2.y()) > cfgFCutOnDeltaY) + continue; + if (!isCountedPi.at(1)) { + mcPhiHist.fill(HIST("h2PhieffPiGenMCFCut"), genmultiplicity, mcParticle2.pt()); + if (isAssocColl) + mcPhiHist.fill(HIST("h2PhieffPiGenMCFCutAssocReco"), genmultiplicity, mcParticle2.pt()); + isCountedPi.at(1) = true; + } + if (std::abs(mcParticle1.y() - mcParticle2.y()) > cfgSCutOnDeltaY) + continue; + if (!isCountedPi.at(2)) { + mcPhiHist.fill(HIST("h2PhieffPiGenMCSCut"), genmultiplicity, mcParticle2.pt()); + if (isAssocColl) + mcPhiHist.fill(HIST("h2PhieffPiGenMCSCutAssocReco"), genmultiplicity, mcParticle2.pt()); + isCountedPi.at(2) = true; + } + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processGenMCPhiQA, "Process for ReCMCQA and Phi in RecMC", false); + + void processGenMCPhiK0S(MCCollisions::iterator const& mcCollision, soa::SmallGroups const& collisions, aod::McParticles const& mcParticles) + { + if (std::abs(mcCollision.posZ()) > cutZVertex) + return; + if (!pwglf::isINELgtNmc(mcParticles, 0, pdgDB)) + return; + + bool isAssocColl = false; + for (const auto& collision : collisions) { + if (acceptEventQA(collision, false)) { + isAssocColl = true; + break; + } + } + + float genmultiplicity = mcCollision.centFT0M(); + mcEventHist.fill(HIST("hGenMCMultiplicityPercent"), genmultiplicity); + + for (const auto& mcParticle1 : mcParticles) { + if (mcParticle1.pdgCode() != PDG_t::kK0Short) + continue; + if (!mcParticle1.isPhysicalPrimary() || mcParticle1.pt() < v0Configs.v0SettingMinPt) + continue; + + mcK0SHist.fill(HIST("h3K0SRapidityGenMC"), genmultiplicity, mcParticle1.pt(), mcParticle1.y()); + + if (std::abs(mcParticle1.y()) > cfgYAcceptance) + continue; + + mcK0SHist.fill(HIST("h2K0SMCGen"), genmultiplicity, mcParticle1.pt()); + if (isAssocColl) + mcK0SHist.fill(HIST("h2K0SMCGenAssocReco"), genmultiplicity, mcParticle1.pt()); + + std::vector counts(cfgDeltaYAcceptanceBins->size() + 1, 0); + + for (const auto& mcParticle2 : mcParticles) { + if (mcParticle2.pdgCode() != o2::constants::physics::Pdg::kPhi) + continue; + if (cfgisGenMCForClosure) { + auto kDaughters = mcParticle2.daughters_as(); + if (kDaughters.size() != 2) + continue; + bool isPosKaon = false, isNegKaon = false; + for (const auto& kDaughter : kDaughters) { + if (kDaughter.pdgCode() == PDG_t::kKPlus) + isPosKaon = true; + if (kDaughter.pdgCode() == PDG_t::kKMinus) + isNegKaon = true; + } + if (!isPosKaon || !isNegKaon) + continue; + } + if (mcParticle2.pt() < minPhiPt || mcParticle2.pt() > maxPhiPt) + continue; + if (std::abs(mcParticle2.y()) > cfgYAcceptance) + continue; + + counts.at(0)++; + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(mcParticle1.y() - mcParticle2.y()) > cfgDeltaYAcceptanceBins->at(i)) + continue; + counts.at(i + 1)++; + } + } + + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size() + 1; i++) { + if (counts.at(i) > 0) { + mcPhiK0SHist.fill(HIST("h3PhiK0SMCGen"), i, genmultiplicity, mcParticle1.pt()); + if (isAssocColl) + mcPhiK0SHist.fill(HIST("h3PhiK0SMCGenAssocReco"), i, genmultiplicity, mcParticle1.pt()); + } + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processGenMCPhiK0S, "Process GenMC for Phi-K0S Analysis", false); + + void processGenMCPhiPion(MCCollisions::iterator const& mcCollision, soa::SmallGroups const& collisions, aod::McParticles const& mcParticles) + { + if (std::abs(mcCollision.posZ()) > cutZVertex) + return; + if (!pwglf::isINELgtNmc(mcParticles, 0, pdgDB)) + return; + + bool isAssocColl = false; + for (const auto& collision : collisions) { + if (acceptEventQA(collision, false)) { + isAssocColl = true; + break; + } + } + + float genmultiplicity = mcCollision.centFT0M(); + mcEventHist.fill(HIST("hGenMCMultiplicityPercent"), genmultiplicity); + + for (const auto& mcParticle1 : mcParticles) { + if (std::abs(mcParticle1.pdgCode()) != PDG_t::kPiPlus) + continue; + if (!mcParticle1.isPhysicalPrimary() || mcParticle1.pt() < trackConfigs.cMinPionPtcut) + continue; + + mcPionHist.fill(HIST("h3PiRapidityGenMC"), genmultiplicity, mcParticle1.pt(), mcParticle1.y()); + + if (std::abs(mcParticle1.y()) > cfgYAcceptance) + continue; + + mcPionHist.fill(HIST("h2PiMCGen"), genmultiplicity, mcParticle1.pt()); + if (isAssocColl) + mcPionHist.fill(HIST("h2PiMCGenAssocReco"), genmultiplicity, mcParticle1.pt()); + + std::vector counts(cfgDeltaYAcceptanceBins->size() + 1, 0); + + for (const auto& mcParticle2 : mcParticles) { + if (mcParticle2.pdgCode() != o2::constants::physics::Pdg::kPhi) + continue; + if (cfgisGenMCForClosure) { + auto kDaughters = mcParticle2.daughters_as(); + if (kDaughters.size() != 2) + continue; + bool isPosKaon = false, isNegKaon = false; + for (const auto& kDaughter : kDaughters) { + if (kDaughter.pdgCode() == PDG_t::kKPlus) + isPosKaon = true; + if (kDaughter.pdgCode() == PDG_t::kKMinus) + isNegKaon = true; + } + if (!isPosKaon || !isNegKaon) + continue; + } + if (mcParticle2.pt() < minPhiPt || mcParticle2.pt() > maxPhiPt) + continue; + if (std::abs(mcParticle2.y()) > cfgYAcceptance) + continue; + + counts.at(0)++; + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(mcParticle1.y() - mcParticle2.y()) > cfgDeltaYAcceptanceBins->at(i)) + continue; + counts.at(i + 1)++; + } + } + + for (size_t i = 0; i < cfgDeltaYAcceptanceBins->size() + 1; i++) { + if (counts.at(i) > 0) { + mcPhiPionHist.fill(HIST("h3PhiPiMCGen"), i, genmultiplicity, mcParticle1.pt()); + if (isAssocColl) + mcPhiPionHist.fill(HIST("h3PhiPiMCGenAssocReco"), i, genmultiplicity, mcParticle1.pt()); + } + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processGenMCPhiPion, "Process GenMC for Phi-Pion Analysis", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Strangeness/sigmaanalysis.cxx b/PWGLF/Tasks/Strangeness/sigmaanalysis.cxx index e99dc031c8b..f2e04920d50 100644 --- a/PWGLF/Tasks/Strangeness/sigmaanalysis.cxx +++ b/PWGLF/Tasks/Strangeness/sigmaanalysis.cxx @@ -9,14 +9,21 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // -// This is a task that employs the standard V0 tables and attempts to combine -// two V0s into a Sigma0 -> Lambda + gamma candidate. +// This is a task that reads sigma0 tables (from sigma0builder) to perform analysis. +// *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* +// Sigma0 analysis task +// *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* +// +// Comments, questions, complaints, suggestions? +// Please write to: +// gianni.shigeru.setoue.liveraro@cern.ch +// #include #include #include #include - +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -25,15 +32,16 @@ #include "ReconstructionDataFormats/Track.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "PWGLF/DataModel/LFStrangenessPIDTables.h" -#include "PWGLF/DataModel/LFStrangenessMLTables.h" -#include "PWGLF/DataModel/LFSigmaTables.h" #include "Common/Core/TrackSelection.h" #include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/PIDResponse.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessMLTables.h" +#include "PWGLF/DataModel/LFSigmaTables.h" #include "CCDB/BasicCCDBManager.h" #include #include @@ -45,262 +53,1094 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; + using std::array; -using std::cout; -using std::endl; -using dauTracks = soa::Join; +using V0MCSigmas = soa::Join; +using V0Sigmas = soa::Join; struct sigmaanalysis { + Service ccdb; + ctpRateFetcher rateFetcher; HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - // master analysis switches - // Configurable fSaveTTree{"fSaveTTree", false, "Save TTree with Sigma0 candidates info for ML-based analysis"}; - // Configurable analyseSigma{"analyseSigma", false, "process Sigma-like candidates"}; - // Configurable analyseAntiSigma{"analyseAntiSigma", false, "process AntiSigma-like candidates"}; - // Base selection criteria - - // Selection criteria: acceptance - Configurable rapidityCut{"rapidityCut", 0.5, "rapidity"}; - Configurable daughterEtaCut{"daughterEtaCut", 0.8, "max eta for daughters"}; - - // Photon standard criteria: - Configurable minPhotonRadius{"minPhotonRadius", 5.0, "minimum photon conversion radius (cm)"}; - Configurable maxPhotonRadius{"maxPhotonRadius", 180, "maximum photon conversion radius (cm)"}; - Configurable minPhotonPt{"minPhotonPt", 0.02, "minimum photon pT (GeV/c)"}; - Configurable minPhotonEta{"minPhotonEta", 0.9, "minimum photon eta"}; - Configurable maxPhotonMass{"maxPhotonMass", 0.1, "Maximum photon mass (GeV/c^{2})"}; - Configurable maxPhotonqt{"maxPhotonqt", 0.06, "Maximum photon qt value (AP plot) (GeV/c)"}; - Configurable Photonalpha{"Photonalpha", 0.95, "Max photon alpha absolute value (AP plot)"}; - - // PID (TPC) - Configurable TpcPidNsigmaCut{"TpcPidNsigmaCut", 4, "TpcPidNsigmaCut"}; - Configurable allowTPConly{"allowTPConly", false, "Accept V0s that are TPC-only"}; - - // Track quality - Configurable minTPCrows{"minTPCrows", 70, "minimum TPC crossed rows"}; - - // Lambda: - Configurable lambdaWindow{"lambdaWindow", 0.01, "Accept +/- this wrt Lambda mass (GeV/c^{2})"}; - Configurable v0cospa{"v0cospa", 0.97, "min V0 CosPA"}; - Configurable dcav0dau{"dcav0dau", 1.0, "max DCA V0 Daughters (cm)"}; - Configurable dcanegtopv{"dcanegtopv", .05, "min DCA Neg To PV (cm)"}; - Configurable dcapostopv{"dcapostopv", .05, "min DCA Pos To PV (cm)"}; - Configurable v0radius{"v0radius", 1.2, "minimum V0 radius (cm)"}; + // Interaction rate selection: + // Event selection + Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; + Configurable fGetIR{"fGetIR", false, "Flag to retrieve the IR info."}; + Configurable irSource{"irSource", "T0VTX", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + Configurable minIR{"minIR", -1, "Min Interaction Rate (kHz). Leave -1 if no selection desired."}; + Configurable maxIR{"maxIR", -1, "Max Interaction Rate (kHz). Leave -1 if no selection desired."}; + + struct : ConfigurableGroup { + Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; + Configurable requireTriggerTVX{"requireTriggerTVX", true, "require FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level"}; + Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border"}; + Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", true, "require events with at least one ITS-TPC track"}; + Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "require events with PV position along z consistent (within 1 cm) between PV reconstructed using tracks and PV using FT0 A-C time difference"}; + Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", false, "require events with at least one of vertex contributors matched to TOF"}; + Configurable requireIsVertexTRDmatched{"requireIsVertexTRDmatched", false, "require events with at least one of vertex contributors matched to TRD"}; + Configurable rejectSameBunchPileup{"rejectSameBunchPileup", false, "reject collisions in case of pileup with another collision in the same foundBC"}; + Configurable requireNoCollInTimeRangeStd{"requireNoCollInTimeRangeStd", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds"}; + Configurable requireNoCollInTimeRangeStrict{"requireNoCollInTimeRangeStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds"}; + Configurable requireNoCollInTimeRangeNarrow{"requireNoCollInTimeRangeNarrow", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds"}; + Configurable requireNoCollInTimeRangeVzDep{"requireNoCollInTimeRangeVzDep", false, "reject collisions corrupted by the cannibalism, with other collisions with pvZ of drifting TPC tracks from past/future collisions within 2.5 cm the current pvZ"}; + Configurable requireNoCollInROFStd{"requireNoCollInROFStd", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF with mult. above a certain threshold"}; + Configurable requireNoCollInROFStrict{"requireNoCollInROFStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF"}; + Configurable requireINEL0{"requireINEL0", false, "require INEL>0 event selection"}; + Configurable requireINEL1{"requireINEL1", false, "require INEL>1 event selection"}; + Configurable maxZVtxPosition{"maxZVtxPosition", 10., "max Z vtx position"}; + Configurable useFT0CbasedOccupancy{"useFT0CbasedOccupancy", false, "Use sum of FT0-C amplitudes for estimating occupancy? (if not, use track-based definition)"}; + // fast check on occupancy + Configurable minOccupancy{"minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; + Configurable maxOccupancy{"maxOccupancy", -1, "maximum occupancy from neighbouring collisions"}; + } eventSelections; + + // Analysis strategy: + Configurable fUseMLSel{"fUseMLSel", false, "Flag to use ML selection. If False, the standard selection is applied."}; + Configurable fProcessMonteCarlo{"fProcessMonteCarlo", false, "Flag to process MC data."}; + Configurable fselLambdaTPCPID{"fselLambdaTPCPID", true, "Flag to select lambda-like candidates using TPC NSigma."}; + Configurable fselLambdaTOFPID{"fselLambdaTOFPID", false, "Flag to select lambda-like candidates using TOF NSigma."}; + Configurable doMCAssociation{"doMCAssociation", false, "Flag to process only signal candidates. Use only with processMonteCarlo!"}; + Configurable doPhotonLambdaSelQA{"doPhotonLambdaSelQA", false, "Flag to fill photon and lambda QA histos!"}; + + // For ML Selection + Configurable Gamma_MLThreshold{"Gamma_MLThreshold", 0.1, "Decision Threshold value to select gammas"}; + Configurable Lambda_MLThreshold{"Lambda_MLThreshold", 0.1, "Decision Threshold value to select lambdas"}; + Configurable AntiLambda_MLThreshold{"AntiLambda_MLThreshold", 0.1, "Decision Threshold value to select antilambdas"}; + + // For Standard Selection: + //// Lambda standard criteria:: + Configurable LambdaMinDCANegToPv{"LambdaMinDCANegToPv", .05, "min DCA Neg To PV (cm)"}; + Configurable LambdaMinDCAPosToPv{"LambdaMinDCAPosToPv", .05, "min DCA Pos To PV (cm)"}; + Configurable ALambdaMinDCANegToPv{"ALambdaMinDCANegToPv", .05, "min DCA Neg To PV (cm)"}; + Configurable ALambdaMinDCAPosToPv{"ALambdaMinDCAPosToPv", .05, "min DCA Pos To PV (cm)"}; + Configurable LambdaMaxDCAV0Dau{"LambdaMaxDCAV0Dau", 2.5, "Max DCA V0 Daughters (cm)"}; + Configurable LambdaMinv0radius{"LambdaMinv0radius", 0.0, "Min V0 radius (cm)"}; + Configurable LambdaMaxv0radius{"LambdaMaxv0radius", 40, "Max V0 radius (cm)"}; + Configurable LambdaMinQt{"LambdaMinQt", 0.01, "Min lambda qt value (AP plot) (GeV/c)"}; + Configurable LambdaMaxQt{"LambdaMaxQt", 0.17, "Max lambda qt value (AP plot) (GeV/c)"}; + Configurable LambdaMinAlpha{"LambdaMinAlpha", 0.25, "Min lambda alpha absolute value (AP plot)"}; + Configurable LambdaMaxAlpha{"LambdaMaxAlpha", 1.0, "Max lambda alpha absolute value (AP plot)"}; + Configurable LambdaMinv0cospa{"LambdaMinv0cospa", 0.95, "Min V0 CosPA"}; + Configurable LambdaMaxLifeTime{"LambdaMaxLifeTime", 30, "Max lifetime"}; + Configurable LambdaWindow{"LambdaWindow", 0.015, "Mass window around expected (in GeV/c2)"}; + Configurable LambdaMaxRap{"LambdaMaxRap", 0.8, "Max lambda rapidity"}; + Configurable LambdaMaxDauEta{"LambdaMaxDauEta", 0.8, "Max pseudorapidity of daughter tracks"}; + Configurable LambdaMaxTPCNSigmas{"LambdaMaxTPCNSigmas", 1e+9, "Max TPC NSigmas for daughters"}; + Configurable LambdaPrMaxTOFNSigmas{"LambdaPrMaxTOFNSigmas", 1e+9, "Max TOF NSigmas for daughters"}; + Configurable LambdaPiMaxTOFNSigmas{"LambdaPiMaxTOFNSigmas", 1e+9, "Max TOF NSigmas for daughters"}; + Configurable LambdaMinTPCCrossedRows{"LambdaMinTPCCrossedRows", 50, "Min daughter TPC Crossed Rows"}; + Configurable LambdaMinITSclusters{"LambdaMinITSclusters", 1, "minimum ITS clusters"}; + Configurable LambdaRejectPosITSafterburner{"LambdaRejectPosITSafterburner", false, "reject positive track formed out of afterburner ITS tracks"}; + Configurable LambdaRejectNegITSafterburner{"LambdaRejectNegITSafterburner", false, "reject negative track formed out of afterburner ITS tracks"}; + + //// Photon standard criteria: + Configurable Photonv0TypeSel{"Photonv0TypeSel", 7, "select on a certain V0 type (leave negative if no selection desired)"}; + Configurable PhotonDauMinPt{"PhotonDauMinPt", 0.0, "Min daughter pT (GeV/c)"}; + Configurable PhotonMinDCADauToPv{"PhotonMinDCADauToPv", 0.0, "Min DCA daughter To PV (cm)"}; + Configurable PhotonMaxDCAV0Dau{"PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; + Configurable PhotonMinTPCCrossedRows{"PhotonMinTPCCrossedRows", 30, "Min daughter TPC Crossed Rows"}; + Configurable PhotonMinTPCNSigmas{"PhotonMinTPCNSigmas", -7, "Min TPC NSigmas for daughters"}; + Configurable PhotonMaxTPCNSigmas{"PhotonMaxTPCNSigmas", 7, "Max TPC NSigmas for daughters"}; + Configurable PiMaxTPCNSigmas{"PiMaxTPCNSigmas", 1, "Max TPC NSigmas for pi rejection"}; + Configurable piMaxpT{"piMaxpT", 3.5, "Max pT for pi rejection"}; + Configurable PhotonMinPt{"PhotonMinPt", 0.0, "Min photon pT (GeV/c)"}; + Configurable PhotonMaxPt{"PhotonMaxPt", 50.0, "Max photon pT (GeV/c)"}; + Configurable PhotonMaxRap{"PhotonMaxRap", 0.5, "Max photon rapidity"}; + Configurable PhotonMinRadius{"PhotonMinRadius", 3.0, "Min photon conversion radius (cm)"}; + Configurable PhotonMaxRadius{"PhotonMaxRadius", 115, "Max photon conversion radius (cm)"}; + Configurable PhotonMaxZ{"PhotonMaxZ", 240, "Max photon conversion point z value (cm)"}; + Configurable PhotonMaxQt{"PhotonMaxQt", 0.05, "Max photon qt value (AP plot) (GeV/c)"}; + Configurable PhotonMaxAlpha{"PhotonMaxAlpha", 0.95, "Max photon alpha absolute value (AP plot)"}; + Configurable PhotonMinV0cospa{"PhotonMinV0cospa", 0.80, "Min V0 CosPA"}; + Configurable PhotonMaxMass{"PhotonMaxMass", 0.10, "Max photon mass (GeV/c^{2})"}; + Configurable PhotonPsiPairMax{"PhotonPsiPairMax", 1e+9, "maximum psi angle of the track pair"}; + Configurable PhotonMaxDauEta{"PhotonMaxDauEta", 0.8, "Max pseudorapidity of daughter tracks"}; + Configurable PhotonLineCutZ0{"PhotonLineCutZ0", 7.0, "The offset for the linecute used in the Z vs R plot"}; + Configurable PhotonPhiMin1{"PhotonPhiMin1", -1, "Phi min value for photons, region 1 (leave negative if no selection desired)"}; + Configurable PhotonPhiMax1{"PhotonPhiMax1", -1, "Phi max value for photons, region 1 (leave negative if no selection desired)"}; + Configurable PhotonPhiMin2{"PhotonPhiMin2", -1, "Phi max value for photons, region 2 (leave negative if no selection desired)"}; + Configurable PhotonPhiMax2{"PhotonPhiMax2", -1, "Phi min value for photons, region 2 (leave negative if no selection desired)"}; + + Configurable SigmaMaxRap{"SigmaMaxRap", 0.5, "Max sigma0 rapidity"}; // Axis // base properties - ConfigurableAxis vertexZ{"vertexZ", {30, -15.0f, 15.0f}, ""}; + ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Centrality"}; ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "p_{T} (GeV/c)"}; - ConfigurableAxis axisRadius{"axisRadius", {200, 0.0f, 100.0f}, "V0 radius (cm)"}; + ConfigurableAxis axisInvPt{"axisInvPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 2.0, 5.0, 10.0, 20.0, 50.0}, ""}; + ConfigurableAxis axisDeltaPt{"axisDeltaPt", {400, -50.0, 50.0}, ""}; + ConfigurableAxis axisRapidity{"axisRapidity", {100, -2.0f, 2.0f}, "Rapidity"}; + ConfigurableAxis axisIRBinning{"axisIRBinning", {5000, 0, 1500}, "Binning for the interaction rate (kHz)"}; // Invariant Mass - ConfigurableAxis axisSigmaMass{"axisSigmaMass", {200, 1.16f, 1.23f}, "M_{#Sigma^{0}} (GeV/c^{2})"}; - ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.08f, 1.16f}, "M_{#Lambda} (GeV/c^{2})"}; - ConfigurableAxis axisPhotonMass{"axisPhotonMass", {200, -0.1f, 0.1f}, "M_{#Gamma}"}; + ConfigurableAxis axisSigmaMass{"axisSigmaMass", {1000, 1.10f, 1.30f}, "M_{#Sigma^{0}} (GeV/c^{2})"}; + ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.05f, 1.151f}, "M_{#Lambda} (GeV/c^{2})"}; + ConfigurableAxis axisPhotonMass{"axisPhotonMass", {600, -0.1f, 0.5f}, "M_{#Gamma}"}; // AP plot axes ConfigurableAxis axisAPAlpha{"axisAPAlpha", {220, -1.1f, 1.1f}, "V0 AP alpha"}; ConfigurableAxis axisAPQt{"axisAPQt", {220, 0.0f, 0.5f}, "V0 AP alpha"}; + // Track quality, PID and other axes + ConfigurableAxis axisTPCrows{"axisTPCrows", {160, 0.0f, 160.0f}, "N TPC rows"}; + ConfigurableAxis axisNCls{"axisNCls", {8, -0.5, 7.5}, "NCls"}; + ConfigurableAxis axisChi2PerNcl{"axisChi2PerNcl", {80, -40, 40}, "Chi2 Per Ncl"}; + ConfigurableAxis axisTPCNSigma{"axisTPCNSigma", {120, -30, 30}, "TPC NSigma"}; + ConfigurableAxis axisTOFNSigma{"axisTOFNSigma", {120, -30, 30}, "TOF NSigma"}; + ConfigurableAxis axisLifetime{"axisLifetime", {200, 0, 200}, "Chi2 Per Ncl"}; + + // topological variable QA axes + ConfigurableAxis axisRadius{"axisRadius", {240, 0.0f, 120.0f}, "V0 radius (cm)"}; + ConfigurableAxis axisDCAtoPV{"axisDCAtoPV", {500, 0.0f, 50.0f}, "DCA (cm)"}; + ConfigurableAxis axisDCAdau{"axisDCAdau", {50, 0.0f, 5.0f}, "DCA (cm)"}; + ConfigurableAxis axisCosPA{"axisCosPA", {200, 0.5f, 1.0f}, "Cosine of pointing angle"}; + ConfigurableAxis axisPsiPair{"axisPsiPair", {500, -5.0f, 5.0f}, "Psipair for photons"}; + ConfigurableAxis axisCandSel{"axisCandSel", {32, 0.5f, +32.5f}, "Candidate Selection"}; + // ML ConfigurableAxis MLProb{"MLOutput", {100, 0.0f, 1.0f}, ""}; - + int nSigmaCandidates = 0; void init(InitContext const&) { - // Event counter - histos.add("hEventVertexZ", "hEventVertexZ", kTH1F, {vertexZ}); - histos.add("hEventVertexZMC", "hEventVertexZMC", kTH1F, {vertexZ}); - - // Number of reconstructed sigma per collision as QA - histos.add("hNSigmaCandidates", "hNSigmaCandidates", kTH1F, {{100, -0.5f, 99.5f}}); - histos.add("hNSigmaCandidatesMC", "hNSigmaCandidatesMC", kTH1F, {{100, -0.5f, 99.5f}}); - - // V0 Radius - histos.add("h2dLambdaRadiusVsPt", "hLambdaRadiusVsPt", {HistType::kTH2F, {axisPt, axisRadius}}); - histos.add("h2dPhotonRadiusVsPt", "hPhotonRadiusVsPt", {HistType::kTH2F, {axisPt, axisRadius}}); - histos.add("h2dLambdaRadiusVsPtMC", "hLambdaRadiusVsPtMC", {HistType::kTH2F, {axisPt, axisRadius}}); - histos.add("h2dPhotonRadiusVsPtMC", "hPhotonRadiusVsPtMC", {HistType::kTH2F, {axisPt, axisRadius}}); - - // Invariant Mass - histos.add("h2dSigmaMassVsPt", "hSigmaMassVsPt", {HistType::kTH2F, {axisPt, axisSigmaMass}}); - histos.add("h2dLambdaMassVsPt", "hLambdaMassVsPt", {HistType::kTH2F, {axisPt, axisLambdaMass}}); - histos.add("h2dPhotonMassVsPt", "hPhotonMassVsPt", {HistType::kTH2F, {axisPt, axisPhotonMass}}); - histos.add("h2dSigmaMassVsPtMC", "hSigmaMassVsPtMC", {HistType::kTH2F, {axisPt, axisSigmaMass}}); - histos.add("h2dLambdaMassVsPtMC", "hLambdaMassVsPtMC", {HistType::kTH2F, {axisPt, axisLambdaMass}}); - histos.add("h2dPhotonMassVsPtMC", "hPhotonMassVsPtMC", {HistType::kTH2F, {axisPt, axisPhotonMass}}); - - // Exploratory Analysis with MC: - /// Armenteros-Polanski plot: - histos.add("h2dMCArmenterosPolanski", "h2dMCArmenterosPolanski", {HistType::kTH2F, {axisAPAlpha, axisAPQt}}); - - /// Lambda - histos.add("hMCLambdaCosPA", "hMCLambdaCosPA", kTH1F, {{100, 0.9f, 1.0f}}); - histos.add("hMCLambdaDCA_V0Dau", "hMCLambdaDCA_V0Dau", kTH1F, {{100, 0.0f, 3.0f}}); - histos.add("hMCLambdaDCA_V0Pos", "hMCLambdaDCA_V0Pos", kTH1F, {{100, 0.0f, 2.0f}}); - histos.add("hMCLambdaDCA_V0Neg", "hMCLambdaDCA_V0Neg", kTH1F, {{100, 0.0f, 2.0f}}); - histos.add("hMCLambda_V0Radius", "hMCLambda_V0Radius", kTH1F, {{100, 0.0f, 40.0f}}); - - /// Photon: - histos.add("hMCPhoton_ConversionRadius", "hMCPhoton_ConversionRadius", kTH1F, {{100, 0.0f, 150.0f}}); - histos.add("hMCPhotonCosPA", "hMCPhotonCosPA", kTH1F, {{100, 0.9f, 1.0f}}); - histos.add("hMCPhotonDCA_V0Dau", "hMCPhotonDCA_V0Dau", kTH1F, {{100, 0.0f, 5.0}}); - histos.add("hMCPhotonDCA_V0Pos", "hMCPhotonDCA_V0Pos", kTH1F, {{100, 0.0f, 5.0f}}); - histos.add("hMCPhotonDCA_V0Neg", "hMCPhotonDCA_V0Neg", kTH1F, {{100, 0.0f, 5.0f}}); - - // ML Analysis - histos.add("hMLOutputLambda", "hMLOutputLambda", kTH1F, {MLProb}); - histos.add("hMLOutputGamma", "hMLOutputGamma", kTH1F, {MLProb}); - - if (doprocessCounterQA) { - histos.add("hGammaIndices", "hGammaIndices", {HistType::kTH1F, {{4000, 0.0f, 400000.0f}}}); - histos.add("hCollIndices", "hCollIndices", {HistType::kTH1F, {{4000, 0.0f, 4000.0f}}}); - histos.add("h2dIndices", "h2dIndices", {HistType::kTH2F, {{4000, 0.0f, 40000.0f}, {4000, 0.0f, 400000.0f}}}); + // setting CCDB service + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); + + // Event Counters + histos.add("hEventSelection", "hEventSelection", kTH1F, {{20, -0.5f, +18.5f}}); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(3, "kIsTriggerTVX"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(6, "posZ cut"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(7, "kIsVertexITSTPC"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(8, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(9, "kIsVertexTOFmatched"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(10, "kIsVertexTRDmatched"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(11, "kNoSameBunchPileup"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(12, "kNoCollInTimeRangeStd"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(13, "kNoCollInTimeRangeStrict"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(14, "kNoCollInTimeRangeNarrow"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(15, "kNoCollInRofStd"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(16, "kNoCollInRofStrict"); + if (doPPAnalysis) { + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "INEL>0"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "INEL>1"); + } else { + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "Below min occup."); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "Above max occup."); } - } - // Helper struct to pass v0 information - struct { - float mass; - float pT; - } sigmaCandidate; + // All candidates received + histos.add("GeneralQA/hInteractionRate", "hInteractionRate", kTH1F, {axisIRBinning}); + histos.add("GeneralQA/hInteractionRatePerColl", "hInteractionRatePerColl", kTH1F, {axisIRBinning}); + histos.add("GeneralQA/hCentralityVsInteractionRate", "hCentralityVsInteractionRate", kTH2F, {axisCentrality, axisIRBinning}); + histos.add("GeneralQA/hCentralityVsInteractionRatePerColl", "hCentralityVsInteractionRatePerColl", kTH2F, {axisCentrality, axisIRBinning}); + histos.add("GeneralQA/h2dArmenterosBeforeSel", "h2dArmenterosBeforeSel", {HistType::kTH2F, {axisAPAlpha, axisAPQt}}); + histos.add("GeneralQA/h2dArmenterosAfterSel", "h2dArmenterosAfterSel", {HistType::kTH2F, {axisAPAlpha, axisAPQt}}); + histos.add("GeneralQA/hMassSigma0BeforeSel", "hMassSigma0BeforeSel", kTH1F, {axisSigmaMass}); + + // Candidates Counters + histos.add("GeneralQA/hCandidateAnalysisSelection", "hCandidateAnalysisSelection", kTH1F, {axisCandSel}); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(1, "No Sel"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(2, "Photon V0Type"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(3, "Photon DauPt"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(4, "Photon DCAToPV"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(5, "Photon DCADau"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(6, "Photon TPCCrossedRows"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(7, "Photon TPCNSigmaEl"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(8, "Photon TPCNSigmaPi"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(9, "Photon Pt"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(10, "Photon Y/Eta"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(11, "Photon Radius"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(12, "Photon RZ line"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(13, "Photon QT"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(14, "Photon Alpha"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(15, "Photon CosPA"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(16, "Photon PsiPair"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(17, "Photon Phi"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(18, "Photon Mass"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(19, "Lambda Radius"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(20, "Lambda DCADau"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(21, "Lambda QT"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(22, "Lambda Alpha"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(23, "Lambda CosPA"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(24, "Lambda Y/Eta"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(25, "Lambda TPCCrossedRows"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(26, "Lambda ITSNCls"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(27, "Lambda Lifetime"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(28, "Lambda/ALambda PID"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(29, "Lambda/ALambda DCAToPV"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(30, "Lambda/ALambda Mass"); + histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(31, "Sigma Y"); + + // Photon Selection QA histos + histos.add("GeneralQA/hPhotonV0Type", "hPhotonV0Type", kTH1F, {{8, 0.5f, 8.5f}}); + histos.add("GeneralQA/hPhotonNegpT", "hPhotonNegpT", kTH1F, {axisPt}); + histos.add("GeneralQA/hPhotonPospT", "hPhotonPospT", kTH1F, {axisPt}); + histos.add("GeneralQA/hPhotonDCANegToPV", "hPhotonDCANegToPV", kTH1F, {axisDCAtoPV}); + histos.add("GeneralQA/hPhotonDCAPosToPV", "hPhotonDCAPosToPV", kTH1F, {axisDCAtoPV}); + histos.add("GeneralQA/hPhotonDCADau", "hPhotonDCADau", kTH1F, {axisDCAdau}); + histos.add("GeneralQA/hPhotonPosTPCCR", "hPhotonPosTPCCR", kTH1F, {axisTPCrows}); + histos.add("GeneralQA/hPhotonNegTPCCR", "hPhotonNegTPCCR", kTH1F, {axisTPCrows}); + histos.add("GeneralQA/h2dPhotonPosTPCNSigmaEl", "h2dPhotonPosTPCNSigmaEl", {HistType::kTH2F, {axisPt, {30, -15.0f, 15.0f}}}); + histos.add("GeneralQA/h2dPhotonNegTPCNSigmaEl", "h2dPhotonNegTPCNSigmaEl", {HistType::kTH2F, {axisPt, {30, -15.0f, 15.0f}}}); + histos.add("GeneralQA/h2dPhotonPosTPCNSigmaPi", "h2dPhotonPosTPCNSigmaPi", {HistType::kTH2F, {axisPt, {30, -15.0f, 15.0f}}}); + histos.add("GeneralQA/h2dPhotonNegTPCNSigmaPi", "h2dPhotonNegTPCNSigmaPi", {HistType::kTH2F, {axisPt, {30, -15.0f, 15.0f}}}); + histos.add("GeneralQA/hPhotonpT", "hPhotonpT", kTH1F, {axisPt}); + histos.add("GeneralQA/hPhotonY", "hPhotonY", kTH1F, {axisRapidity}); + histos.add("GeneralQA/hPhotonPosEta", "hPhotonPosEta", kTH1F, {axisRapidity}); + histos.add("GeneralQA/hPhotonNegEta", "hPhotonNegEta", kTH1F, {axisRapidity}); + histos.add("GeneralQA/hPhotonRadius", "hPhotonRadius", kTH1F, {axisRadius}); + histos.add("GeneralQA/hPhotonZ", "hPhotonZ", kTH1F, {{240, 0.0f, 120.0f}}); + histos.add("GeneralQA/h2dRZCut", "h2dRZCut", {HistType::kTH2F, {{240, -120.0f, 120.0f}, axisRadius}}); + histos.add("GeneralQA/h2dRZPlane", "h2dRZPlane", {HistType::kTH2F, {{240, -120.0f, 120.0f}, axisRadius}}); + histos.add("GeneralQA/h2dPhotonArmenteros", "h2dPhotonArmenteros", {HistType::kTH2F, {axisAPAlpha, axisAPQt}}); + histos.add("GeneralQA/hPhotonCosPA", "hPhotonCosPA", kTH1F, {axisCosPA}); + histos.add("GeneralQA/hPhotonPsiPair", "hPhotonPsiPair", kTH1F, {axisPsiPair}); + histos.add("GeneralQA/hPhotonPhi", "hPhotonPhi", kTH1F, {{200, 0, 2 * o2::constants::math::PI}}); + histos.add("GeneralQA/h3dPhotonMass", "h3dPhotonMass", kTH3F, {axisCentrality, axisPt, axisPhotonMass}); + + // Lambda Selection QA histos + histos.add("GeneralQA/hLambdaRadius", "hLambdaRadius", kTH1F, {axisRadius}); + histos.add("GeneralQA/hLambdaDCADau", "hLambdaDCADau", kTH1F, {axisDCAdau}); + histos.add("GeneralQA/h2dLambdaArmenteros", "h2dLambdaArmenteros", {HistType::kTH2F, {axisAPAlpha, axisAPQt}}); + histos.add("GeneralQA/hLambdaCosPA", "hLambdaCosPA", kTH1F, {axisCosPA}); + histos.add("GeneralQA/hLambdaY", "hLambdaY", kTH1F, {axisRapidity}); + histos.add("GeneralQA/hLambdaPosEta", "hLambdaPosEta", kTH1F, {axisRapidity}); + histos.add("GeneralQA/hLambdaNegEta", "hLambdaNegEta", kTH1F, {axisRapidity}); + histos.add("GeneralQA/hLambdaPosTPCCR", "hLambdaPosTPCCR", kTH1F, {axisTPCrows}); + histos.add("GeneralQA/hLambdaNegTPCCR", "hLambdaNegTPCCR", kTH1F, {axisTPCrows}); + histos.add("GeneralQA/hLambdaPosITSCls", "hLambdaPosITSCls", kTH1F, {axisNCls}); + histos.add("GeneralQA/hLambdaNegITSCls", "hLambdaNegITSCls", kTH1F, {axisNCls}); + histos.add("GeneralQA/hLambdaPosChi2PerNc", "hLambdaPosChi2PerNc", kTH1F, {axisChi2PerNcl}); + histos.add("GeneralQA/hLambdaNegChi2PerNc", "hLambdaNegChi2PerNc", kTH1F, {axisChi2PerNcl}); + histos.add("GeneralQA/hLambdaLifeTime", "hLambdaLifeTime", kTH1F, {axisLifetime}); + + histos.add("GeneralQA/h2dTPCvsTOFNSigma_LambdaPr", "h2dTPCvsTOFNSigma_LambdaPr", {HistType::kTH2F, {axisTPCNSigma, axisTOFNSigma}}); + histos.add("GeneralQA/h2dTPCvsTOFNSigma_LambdaPi", "h2dTPCvsTOFNSigma_LambdaPi", {HistType::kTH2F, {axisTPCNSigma, axisTOFNSigma}}); + histos.add("GeneralQA/hLambdaDCANegToPV", "hLambdaDCANegToPV", kTH1F, {axisDCAtoPV}); + histos.add("GeneralQA/hLambdaDCAPosToPV", "hLambdaDCAPosToPV", kTH1F, {axisDCAtoPV}); + histos.add("GeneralQA/h3dLambdaMass", "h3dLambdaMass", kTH3F, {axisCentrality, axisPt, axisLambdaMass}); + histos.add("GeneralQA/h2dTPCvsTOFNSigma_ALambdaPr", "h2dTPCvsTOFNSigma_ALambdaPr", {HistType::kTH2F, {axisTPCNSigma, axisTOFNSigma}}); + histos.add("GeneralQA/h2dTPCvsTOFNSigma_ALambdaPi", "h2dTPCvsTOFNSigma_ALambdaPi", {HistType::kTH2F, {axisTPCNSigma, axisTOFNSigma}}); + histos.add("GeneralQA/hALambdaDCANegToPV", "hALambdaDCANegToPV", kTH1F, {axisDCAtoPV}); + histos.add("GeneralQA/hALambdaDCAPosToPV", "hALambdaDCAPosToPV", kTH1F, {axisDCAtoPV}); + histos.add("GeneralQA/h3dAntiLambdaMass", "h3dAntiLambdaMass", kTH3F, {axisCentrality, axisPt, axisLambdaMass}); + + histos.add("GeneralQA/hPhotonMassSelected", "hPhotonMassSelected", kTH1F, {axisPhotonMass}); + histos.add("GeneralQA/hLambdaMassSelected", "hLambdaMassSelected", kTH1F, {axisLambdaMass}); + histos.add("GeneralQA/hAntiLambdaMassSelected", "hAntiLambdaMassSelected", kTH1F, {axisLambdaMass}); + + histos.add("GeneralQA/hSigmaY", "hSigmaY", kTH1F, {axisRapidity}); + histos.add("GeneralQA/hSigmaOPAngle", "hSigmaOPAngle", kTH1F, {{140, 0.0f, +7.0f}}); + + // Specific sigma0 QA + histos.add("SigmaSelQA/h2dPhotonV0Type", "h2dPhotonV0Type", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dPhotonMass", "h2dPhotonMass", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dPhotonDaupT", "h2dPhotonDaupT", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dPhotonDCADauToPV", "h2dPhotonDCADauToPV", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dPhotonDCADau", "h2dPhotonDCADau", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dPhotonDauTPCCR", "h2dPhotonDauTPCCR", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dPhotonTPCNSigmaEl", "h2dPhotonTPCNSigmaEl", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dPhotonpT", "h2dPhotonpT", {HistType::kTH2F, {axisPt, axisSigmaMass}}); // + histos.add("SigmaSelQA/h2dPhotonY", "h2dPhotonY", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dPhotonRadius", "h2dPhotonRadius", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dRZCut", "h2dRZCut", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dPhotonArmenteros", "h2dPhotonArmenteros", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dPhotonCosPA", "h2dPhotonCosPA", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dPhotonPsiPair", "h2dPhotonPsiPair", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dLambdaRadius", "h2dLambdaRadius", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dLambdaDCADau", "h2dLambdaDCADau", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dLambdaArmenteros", "h2dLambdaArmenteros", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dLambdaCosPA", "h2dLambdaCosPA", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dLambdaY", "h2dLambdaY", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dLambdaDauTPCCR", "h2dLambdaDauTPCCR", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dLambdaDauITSCls", "h2dLambdaDauITSCls", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dLambdaLifeTime", "h2dLambdaLifeTime", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dTPCvsTOFNSigma_Lambda", "h2dTPCvsTOFNSigma_Lambda", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dLambdaDCADauToPV", "h2dLambdaDCADauToPV", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dLambdaMass", "h2dLambdaMass", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dTPCvsTOFNSigma_ALambda", "h2dTPCvsTOFNSigma_ALambda", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dALambdaDCADauToPV", "h2dALambdaDCADauToPV", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dAntiLambdaMass", "h2dAntiLambdaMass", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + histos.add("SigmaSelQA/h2dSigmaY", "h2dSigmaY", {HistType::kTH2F, {axisPt, axisSigmaMass}}); + + // Specific photon QA + histos.add("PhotonSelQA/h2dPhotonBaseline", "h2dPhotonBaseline", {HistType::kTH2F, {axisPt, axisPhotonMass}}); + histos.add("PhotonSelQA/h2dPhotonV0Type", "h2dPhotonV0Type", {HistType::kTH2F, {axisPt, axisPhotonMass}}); + histos.add("PhotonSelQA/h2dPhotonMass", "h2dPhotonMass", {HistType::kTH2F, {axisPt, axisPhotonMass}}); + histos.add("PhotonSelQA/h2dPhotonDaupT", "h2dPhotonDaupT", {HistType::kTH2F, {axisPt, axisPhotonMass}}); + histos.add("PhotonSelQA/h2dPhotonDCADauToPV", "h2dPhotonDCADauToPV", {HistType::kTH2F, {axisPt, axisPhotonMass}}); + histos.add("PhotonSelQA/h2dPhotonDCADau", "h2dPhotonDCADau", {HistType::kTH2F, {axisPt, axisPhotonMass}}); + histos.add("PhotonSelQA/h2dPhotonDauTPCCR", "h2dPhotonDauTPCCR", {HistType::kTH2F, {axisPt, axisPhotonMass}}); + histos.add("PhotonSelQA/h2dPhotonTPCNSigmaEl", "h2dPhotonTPCNSigmaEl", {HistType::kTH2F, {axisPt, axisPhotonMass}}); + histos.add("PhotonSelQA/h2dPhotonpT", "h2dPhotonpT", {HistType::kTH2F, {axisPt, axisPhotonMass}}); // + histos.add("PhotonSelQA/h2dPhotonY", "h2dPhotonY", {HistType::kTH2F, {axisPt, axisPhotonMass}}); + histos.add("PhotonSelQA/h2dPhotonRadius", "h2dPhotonRadius", {HistType::kTH2F, {axisPt, axisPhotonMass}}); + histos.add("PhotonSelQA/h2dRZCut", "h2dRZCut", {HistType::kTH2F, {axisPt, axisPhotonMass}}); + histos.add("PhotonSelQA/h2dPhotonArmenteros", "h2dPhotonArmenteros", {HistType::kTH2F, {axisPt, axisPhotonMass}}); + histos.add("PhotonSelQA/h2dPhotonCosPA", "h2dPhotonCosPA", {HistType::kTH2F, {axisPt, axisPhotonMass}}); + histos.add("PhotonSelQA/h2dPhotonPsiPair", "h2dPhotonPsiPair", {HistType::kTH2F, {axisPt, axisPhotonMass}}); + histos.add("PhotonSelQA/h2dPhotonPhi", "h2dPhotonPhi", {HistType::kTH2F, {axisPt, axisPhotonMass}}); + + // Specific Lambda/ALambda QA + histos.add("LambdaSelQA/h2dLambdaBaseline", "h2dLambdaBaseline", {HistType::kTH2F, {axisPt, axisLambdaMass}}); + histos.add("LambdaSelQA/h2dLambdaRadius", "h2dLambdaRadius", {HistType::kTH2F, {axisPt, axisLambdaMass}}); + histos.add("LambdaSelQA/h2dLambdaDCADau", "h2dLambdaDCADau", {HistType::kTH2F, {axisPt, axisLambdaMass}}); + histos.add("LambdaSelQA/h2dLambdaArmenteros", "h2dLambdaArmenteros", {HistType::kTH2F, {axisPt, axisLambdaMass}}); + histos.add("LambdaSelQA/h2dLambdaCosPA", "h2dLambdaCosPA", {HistType::kTH2F, {axisPt, axisLambdaMass}}); + histos.add("LambdaSelQA/h2dLambdaY", "h2dLambdaY", {HistType::kTH2F, {axisPt, axisLambdaMass}}); + histos.add("LambdaSelQA/h2dLambdaDauTPCCR", "h2dLambdaDauTPCCR", {HistType::kTH2F, {axisPt, axisLambdaMass}}); + histos.add("LambdaSelQA/h2dLambdaDauITSCls", "h2dLambdaDauITSCls", {HistType::kTH2F, {axisPt, axisLambdaMass}}); + histos.add("LambdaSelQA/h2dLambdaLifeTime", "h2dLambdaLifeTime", {HistType::kTH2F, {axisPt, axisLambdaMass}}); + histos.add("LambdaSelQA/h2dTPCvsTOFNSigma_Lambda", "h2dTPCvsTOFNSigma_Lambda", {HistType::kTH2F, {axisPt, axisLambdaMass}}); + histos.add("LambdaSelQA/h2dLambdaDCADauToPV", "h2dLambdaDCADauToPV", {HistType::kTH2F, {axisPt, axisLambdaMass}}); + histos.add("LambdaSelQA/h2dLambdaMass", "h2dLambdaMass", {HistType::kTH2F, {axisPt, axisLambdaMass}}); + + // For Signal Extraction - // Process sigma candidate and store properties in object - template - bool processSigmaCandidate(TCollision const&, TV0Object const& lambda, TV0Object const& gamma) + // Sigma0 + histos.add("Sigma0/h3dMassSigma0", "h3dMassSigma0", kTH3F, {axisCentrality, axisPt, axisSigmaMass}); + histos.add("Sigma0/h3dPhotonRadiusVsMassSigma0", "h3dPhotonRadiusVsMassSigma0", kTH3F, {axisCentrality, axisRadius, axisSigmaMass}); + histos.add("Sigma0/hMassSigma0", "hMassSigma0", kTH1F, {axisSigmaMass}); + histos.add("Sigma0/hPtSigma0", "hPtSigma0", kTH1F, {axisPt}); + histos.add("Sigma0/hRapiditySigma0", "hRapiditySigma0", kTH1F, {axisRapidity}); + + // AntiSigma0 + histos.add("AntiSigma0/h3dMassAntiSigma0", "h3dMassAntiSigma0", kTH3F, {axisCentrality, axisPt, axisSigmaMass}); + histos.add("AntiSigma0/h3dPhotonRadiusVsMassAntiSigma0", "h3dPhotonRadiusVsMassAntiSigma0", kTH3F, {axisCentrality, axisRadius, axisSigmaMass}); + histos.add("AntiSigma0/hMassAntiSigma0", "hMassAntiSigma0", kTH1F, {axisSigmaMass}); + histos.add("AntiSigma0/hPtAntiSigma0", "hPtAntiSigma0", kTH1F, {axisPt}); + histos.add("AntiSigma0/hRapidityAntiSigma0", "hRapidityAntiSigma0", kTH1F, {axisRapidity}); + + if (fProcessMonteCarlo) { + + // Kinematic + histos.add("MC/h3dMassSigma0", "h3dMassSigma0", kTH3F, {axisCentrality, axisPt, axisSigmaMass}); + histos.add("MC/h3dMassAntiSigma0", "h3dMassSigma0", kTH3F, {axisCentrality, axisPt, axisSigmaMass}); + histos.add("MC/h3dMassAllSigma0sBeforesel", "h3dMassAllSigma0sBeforesel", kTH3F, {axisCentrality, axisPt, axisSigmaMass}); + histos.add("MC/h2dArmenterosBeforeSel", "h2dArmenterosBeforeSel", {HistType::kTH2F, {axisAPAlpha, axisAPQt}}); + histos.add("MC/h2dArmenterosAfterSel", "h2dArmenterosAfterSel", {HistType::kTH2F, {axisAPAlpha, axisAPQt}}); + + // Sigma0 QA + histos.add("MC/hMassSigma0BeforeSel", "hMassSigma0BeforeSel", kTH1F, {axisSigmaMass}); + histos.add("MC/hPtSigma0BeforeSel", "hPtSigma0BeforeSel", kTH1F, {axisPt}); + histos.add("MC/hMassSigma0", "hMassSigma0", kTH1F, {axisSigmaMass}); + histos.add("MC/hPtSigma0", "hPtSigma0", kTH1F, {axisPt}); + histos.add("MC/hMassAntiSigma0", "hMassAntiSigma0", kTH1F, {axisSigmaMass}); + histos.add("MC/hPtAntiSigma0", "hPtAntiSigma0", kTH1F, {axisPt}); + + // For background decomposition + histos.add("MC/h2dPtVsMassSigma_SignalBkg", "h2dPtVsMassSigma_SignalBkg", kTH2D, {axisPt, axisSigmaMass}); + histos.add("MC/h2dPtVsMassSigma_SignalOnly", "h2dPtVsMassSigma_SignalOnly", kTH2D, {axisPt, axisSigmaMass}); + histos.add("MC/h2dPtVsMassSigma_TrueDaughters", "h2dPtVsMassSigma_TrueDaughters", kTH2D, {axisPt, axisSigmaMass}); + histos.add("MC/h2dPtVsMassSigma_TrueGammaFakeLambda", "h2dPtVsMassSigma_TrueGammaFakeLambda", kTH2D, {axisPt, axisSigmaMass}); + histos.add("MC/h2dPtVsMassSigma_FakeGammaTrueLambda", "h2dPtVsMassSigma_FakeGammaTrueLambda", kTH2D, {axisPt, axisSigmaMass}); + histos.add("MC/h2dPtVsMassSigma_FakeDaughters", "h2dPtVsMassSigma_FakeDaughters", kTH2D, {axisPt, axisSigmaMass}); + histos.add("MC/h2dTrueDaughtersMatrix", "h2dTrueDaughtersMatrix", kTHnSparseD, {{10001, -5000.5f, +5000.5f}, {10001, -5000.5f, +5000.5f}}); + + // For new selection studies: + //// Opening angle between daughters + histos.add("MC/h2dPtVsOPAngle_SignalOnly", "h2dPtVsOPAngle_SignalOnly", kTH2D, {axisPt, {140, 0.0f, +7.0f}}); + histos.add("MC/h2dPtVsOPAngle_TrueDaughters", "h2dPtVsOPAngle_TrueDaughters", kTH2D, {axisPt, {140, 0.0f, +7.0f}}); + histos.add("MC/h2dPtVsMassSigma_AfterOPAngleSel", "h2dPtVsMassSigma_AfterOPAngleSel", kTH2D, {axisPt, axisSigmaMass}); + + // For efficiency/Purity studies + // Before any selection + histos.add("MC/hPtTrueLambda_BeforeSel", "hPtTrueLambda_BeforeSel", kTH1F, {axisPt}); // Signal only + histos.add("MC/hPtTrueAntiLambda_BeforeSel", "hPtTrueAntiLambda_BeforeSel", kTH1F, {axisPt}); // Signal only + histos.add("MC/hPtTrueGamma_BeforeSel", "hPtTrueGamma_BeforeSel", kTH1F, {axisPt}); // Signal only + histos.add("MC/hPtTrueSigma_BeforeSel", "hPtTrueSigma_BeforeSel", kTH1F, {axisPt}); // Signal only + histos.add("MC/hPtTrueAntiSigma_BeforeSel", "hPtTrueAntiSigma_BeforeSel", kTH1F, {axisPt}); // Signal only + histos.add("MC/hPtLambdaCand_BeforeSel", "hPtLambdaCand_BeforeSel", kTH1F, {axisPt}); // Bkg + Signal + histos.add("MC/hPtGammaCand_BeforeSel", "hPtGammaCand_BeforeSel", kTH1F, {axisPt}); // Bkg + Signal + histos.add("MC/hPtSigmaCand_BeforeSel", "hPtGammaCand_BeforeSel", kTH1F, {axisPt}); // Bkg + Signal + + // After analysis selections + histos.add("MC/hPtTrueLambda_AfterSel", "hPtTrueLambda_AfterSel", kTH1F, {axisPt}); // Signal only + histos.add("MC/hPtTrueAntiLambda_AfterSel", "hPtTrueAntiLambda_AfterSel", kTH1F, {axisPt}); // Signal only + histos.add("MC/hPtTrueGamma_AfterSel", "hPtTrueGamma_AfterSel", kTH1F, {axisPt}); // Signal only + histos.add("MC/hPtTrueSigma_AfterSel", "hPtTrueSigma_AfterSel", kTH1F, {axisPt}); // Signal only + + histos.add("MC/hPtLambdaCand_AfterSel", "hPtLambdaCand_AfterSel", kTH1F, {axisPt}); + histos.add("MC/hPtGammaCand_AfterSel", "hPtGammaCand_AfterSel", kTH1F, {axisPt}); + histos.add("MC/hPtSigmaCand_AfterSel", "hPtSigmaCand_AfterSel", kTH1F, {axisPt}); + + // TPC vs TOF N Sigmas distributions + histos.add("MC/h3dTPCvsTOFNSigma_LambdaPr", "h3dTPCvsTOFNSigma_LambdaPr", kTH3F, {axisTPCNSigma, axisTOFNSigma, axisPt}); + histos.add("MC/h3dTPCvsTOFNSigma_LambdaPi", "h3dTPCvsTOFNSigma_LambdaPi", kTH3F, {axisTPCNSigma, axisTOFNSigma, axisPt}); + histos.add("MC/h3dTPCvsTOFNSigma_TrueLambdaPr", "h3dTPCvsTOFNSigma_TrueLambdaPr", kTH3F, {axisTPCNSigma, axisTOFNSigma, axisPt}); + histos.add("MC/h3dTPCvsTOFNSigma_TrueLambdaPi", "h3dTPCvsTOFNSigma_TrueLambdaPi", kTH3F, {axisTPCNSigma, axisTOFNSigma, axisPt}); + histos.add("MC/h3dTPCvsTOFNSigma_TrueALambdaPr", "h3dTPCvsTOFNSigma_TrueALambdaPr", kTH3F, {axisTPCNSigma, axisTOFNSigma, axisPt}); + histos.add("MC/h3dTPCvsTOFNSigma_TrueALambdaPi", "h3dTPCvsTOFNSigma_TrueALambdaPi", kTH3F, {axisTPCNSigma, axisTOFNSigma, axisPt}); + + // QA of PID selections: + //// TPC PID + histos.add("MC/hPtTrueLambda_passedTPCPID", "hPtTrueLambda_passedTPCPID", kTH1F, {axisPt}); + histos.add("MC/hPtLambdaCandidates_passedTPCPID", "hPtLambdaCandidates_passedTPCPID", kTH1F, {axisPt}); + + //// TOF PID + histos.add("MC/hPtTrueLambda_passedTOFPID", "hPtTrueLambda_passedTOFPID", kTH1F, {axisPt}); + histos.add("MC/hPtLambdaCandidates_passedTOFPID", "hPtLambdaCandidates_passedTOFPID", kTH1F, {axisPt}); + + //// TPC+TOF PID + histos.add("MC/hPtTrueLambda_passedTPCTOFPID", "hPtTrueLambda_passedTPCTOFPID", kTH1F, {axisPt}); + histos.add("MC/hPtLambdaCandidates_passedTPCTOFPID", "hPtLambdaCandidates_passedTPCTOFPID", kTH1F, {axisPt}); + + // 1/pT Resolution: + histos.add("MC/h2dLambdaPtResolution", "h2dLambdaPtResolution", kTH2D, {axisInvPt, axisDeltaPt}); + histos.add("MC/h2dAntiLambdaPtResolution", "h2dAntiLambdaPtResolution", kTH2D, {axisInvPt, axisDeltaPt}); + histos.add("MC/h2dGammaPtResolution", "h2dGammaPtResolution", kTH2D, {axisInvPt, axisDeltaPt}); + histos.add("MC/h2dSigma0PtResolution", "h2dSigma0PtResolution", kTH2D, {axisInvPt, axisDeltaPt}); + histos.add("MC/h2dAntiSigma0PtResolution", "h2dAntiSigma0PtResolution", kTH2D, {axisInvPt, axisDeltaPt}); + histos.add("MC/h3dLambdaPtResoVsTPCCR", "h3dLambdaPtResoVsTPCCR", kTH3F, {axisInvPt, axisDeltaPt, {320, -160.0f, 160.0f}}); + histos.add("MC/h3dAntiLambdaPtResoVsTPCCR", "h3dAntiLambdaPtResoVsTPCCR", kTH3F, {axisInvPt, axisDeltaPt, {320, -160.0f, 160.0f}}); + histos.add("MC/h3dGammaPtResoVsTPCCR", "h3dGammaPtResoVsTPCCR", kTH3F, {axisInvPt, axisDeltaPt, {320, -160.0f, 160.0f}}); + + // pTMC info: + histos.add("MC/h2dSigmaMCPtVsLambdaMCPt", "h2dSigmaMCPtVsLambdaMCPt", kTH2D, {axisPt, axisPt}); + histos.add("MC/h2dSigmaMCPtVsGammaMCPt", "h2dSigmaMCPtVsGammaMCPt", kTH2D, {axisPt, axisPt}); + } + } + + template + bool IsEventAccepted(TCollision collision) + // check whether the collision passes our collision selections { - // FIXME: this should be at the single particle level, preferably partitions - if (!allowTPConly && (lambda.v0Type() > 1 || gamma.v0Type() > 1)) + histos.fill(HIST("hEventSelection"), 0. /* all collisions */); + if (eventSelections.requireSel8 && !collision.sel8()) { return false; - - // Gamma selection criteria: - if (gamma.mGamma() > maxPhotonMass) + } + histos.fill(HIST("hEventSelection"), 1 /* sel8 collisions */); + if (eventSelections.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { return false; - if (gamma.v0radius() < minPhotonRadius) + } + histos.fill(HIST("hEventSelection"), 2 /* FT0 vertex (acceptable FT0C-FT0A time difference) collisions */); + if (eventSelections.rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { return false; - if (gamma.v0radius() > maxPhotonRadius) + } + histos.fill(HIST("hEventSelection"), 3 /* Not at ITS ROF border */); + if (eventSelections.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { return false; - if (gamma.pt() < minPhotonPt) + } + histos.fill(HIST("hEventSelection"), 4 /* Not at TF border */); + if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { return false; - if (gamma.qtarm() > maxPhotonqt) + } + histos.fill(HIST("hEventSelection"), 5 /* vertex-Z selected */); + if (eventSelections.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { return false; - if (TMath::Abs(gamma.alpha()) > Photonalpha) + } + histos.fill(HIST("hEventSelection"), 6 /* Contains at least one ITS-TPC track */); + if (eventSelections.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { return false; - - // Lambda selection criteria: - if (TMath::Abs(lambda.mLambda() - 1.115683) > lambdaWindow) + } + histos.fill(HIST("hEventSelection"), 7 /* PV position consistency check */); + if (eventSelections.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { return false; - if (lambda.v0radius() < v0radius) + } + histos.fill(HIST("hEventSelection"), 8 /* PV with at least one contributor matched with TOF */); + if (eventSelections.requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { return false; - if (lambda.v0cosPA() < v0cospa) + } + histos.fill(HIST("hEventSelection"), 9 /* PV with at least one contributor matched with TRD */); + if (eventSelections.rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { return false; - if (lambda.dcapostopv() < dcapostopv) + } + histos.fill(HIST("hEventSelection"), 10 /* Not at same bunch pile-up */); + if (eventSelections.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { return false; - if (lambda.dcanegtopv() < dcanegtopv) + } + histos.fill(HIST("hEventSelection"), 11 /* No other collision within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds*/); + if (eventSelections.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { return false; - if (lambda.dcaV0daughters() > dcav0dau) + } + histos.fill(HIST("hEventSelection"), 12 /* No other collision within +/- 10 microseconds */); + if (eventSelections.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { return false; - - std::array pVecPhotons{gamma.px(), gamma.py(), gamma.pz()}; - std::array pVecLambda{lambda.px(), lambda.py(), lambda.pz()}; - auto arrMom = std::array{pVecPhotons, pVecLambda}; - sigmaCandidate.mass = RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassLambda0}); - sigmaCandidate.pT = RecoDecay::pt(array{gamma.px() + lambda.px(), gamma.py() + lambda.py()}); + } + histos.fill(HIST("hEventSelection"), 13 /* No other collision within +/- 2 microseconds */); + if (eventSelections.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + histos.fill(HIST("hEventSelection"), 14 /* No other collision within the same ITS ROF with mult. above a certain threshold */); + if (eventSelections.requireNoCollInROFStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } + histos.fill(HIST("hEventSelection"), 15 /* No other collision within the same ITS ROF */); + if (doPPAnalysis) { // we are in pp + if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) { + return false; + } + histos.fill(HIST("hEventSelection"), 16 /* INEL > 0 */); + if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { + return false; + } + histos.fill(HIST("hEventSelection"), 17 /* INEL > 1 */); + } else { // we are in Pb-Pb + float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) { + return false; + } + histos.fill(HIST("hEventSelection"), 16 /* Below min occupancy */); + if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { + return false; + } + histos.fill(HIST("hEventSelection"), 17 /* Above max occupancy */); + } return true; } - // This process function cross-checks index correctness - void processCounterQA(soa::Join const& v0s) + // Apply selections in sigma candidates + template + bool processSigmaCandidate(TV0Object const& cand, bool isLambdalike) { - for (auto& gamma : v0s) { - histos.fill(HIST("hGammaIndices"), gamma.globalIndex()); - histos.fill(HIST("hCollIndices"), gamma.straCollisionId()); - histos.fill(HIST("h2dIndices"), gamma.straCollisionId(), gamma.globalIndex()); + if (fUseMLSel) { + if ((cand.gammaBDTScore() == -1) || (cand.lambdaBDTScore() == -1) || (cand.antilambdaBDTScore() == -1)) { + LOGF(fatal, "ML Score is not available! Please, enable gamma and lambda selection with ML in sigmabuilder!"); + } + // Gamma selection: + if (cand.gammaBDTScore() <= Gamma_MLThreshold) + return false; + + // Lambda selection: + if (cand.lambdaBDTScore() <= Lambda_MLThreshold) + return false; + + // AntiLambda selection: + if (cand.antilambdaBDTScore() <= AntiLambda_MLThreshold) + return false; + } else { + + bool isMCTrueLambda = false; + bool isMCTruePhoton = false; + if constexpr (requires { cand.lambdaCandPDGCode(); cand.photonCandPDGCode(); }) { + if (cand.photonCandPDGCode() == 22) + isMCTruePhoton = true; + if (cand.lambdaCandPDGCode() == 3122) + isMCTrueLambda = true; + } + + // Photon Selections + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 1.); + histos.fill(HIST("GeneralQA/hPhotonV0Type"), cand.photonV0Type()); + if ((isMCTruePhoton || doPhotonLambdaSelQA) && (TMath::Abs(cand.photonMass()) <= PhotonMaxMass)) + histos.fill(HIST("PhotonSelQA/h2dPhotonBaseline"), cand.photonPt(), cand.photonMass()); + if (cand.photonV0Type() != Photonv0TypeSel && Photonv0TypeSel > -1) + return false; + histos.fill(HIST("SigmaSelQA/h2dPhotonV0Type"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTruePhoton || doPhotonLambdaSelQA) && (TMath::Abs(cand.photonMass()) <= PhotonMaxMass)) + histos.fill(HIST("PhotonSelQA/h2dPhotonV0Type"), cand.photonPt(), cand.photonMass()); + + // histos.fill(HIST("GeneralQA/h3dPhotonMass"), cand.sigmaCentrality(), cand.photonPt(), cand.photonMass()); + // histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 2.); + // if (TMath::Abs(cand.photonMass()) > PhotonMaxMass) + // return false; + // histos.fill(HIST("SigmaSelQA/h2dPhotonMass"), cand.sigmapT(), cand.sigmaMass()); + // if (isMCTruePhoton || doPhotonLambdaSelQA) histos.fill(HIST("PhotonSelQA/h2dPhotonMass"), cand.photonPt(), cand.photonMass()); + + histos.fill(HIST("GeneralQA/hPhotonNegpT"), cand.photonNegPt()); + histos.fill(HIST("GeneralQA/hPhotonPospT"), cand.photonPosPt()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 2.); + if ((cand.photonPosPt() < PhotonDauMinPt) || (cand.photonNegPt() < PhotonDauMinPt)) + return false; + histos.fill(HIST("SigmaSelQA/h2dPhotonDaupT"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTruePhoton || doPhotonLambdaSelQA) && (TMath::Abs(cand.photonMass()) <= PhotonMaxMass)) + histos.fill(HIST("PhotonSelQA/h2dPhotonDaupT"), cand.photonPt(), cand.photonMass()); + histos.fill(HIST("GeneralQA/hPhotonDCANegToPV"), cand.photonDCANegPV()); + histos.fill(HIST("GeneralQA/hPhotonDCAPosToPV"), cand.photonDCAPosPV()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 3.); + if ((TMath::Abs(cand.photonDCAPosPV()) < PhotonMinDCADauToPv) || (TMath::Abs(cand.photonDCANegPV()) < PhotonMinDCADauToPv)) + return false; + histos.fill(HIST("SigmaSelQA/h2dPhotonDCADauToPV"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTruePhoton || doPhotonLambdaSelQA) && (TMath::Abs(cand.photonMass()) <= PhotonMaxMass)) + histos.fill(HIST("PhotonSelQA/h2dPhotonDCADauToPV"), cand.photonPt(), cand.photonMass()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 4.); + histos.fill(HIST("GeneralQA/hPhotonDCADau"), cand.photonDCADau()); + if (TMath::Abs(cand.photonDCADau()) > PhotonMaxDCAV0Dau) + return false; + histos.fill(HIST("SigmaSelQA/h2dPhotonDCADau"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTruePhoton || doPhotonLambdaSelQA) && (TMath::Abs(cand.photonMass()) <= PhotonMaxMass)) + histos.fill(HIST("PhotonSelQA/h2dPhotonDCADau"), cand.photonPt(), cand.photonMass()); + histos.fill(HIST("GeneralQA/hPhotonPosTPCCR"), cand.photonPosTPCCrossedRows()); + histos.fill(HIST("GeneralQA/hPhotonNegTPCCR"), cand.photonNegTPCCrossedRows()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 5.); + if ((cand.photonPosTPCCrossedRows() < PhotonMinTPCCrossedRows) || (cand.photonNegTPCCrossedRows() < PhotonMinTPCCrossedRows)) + return false; + histos.fill(HIST("SigmaSelQA/h2dPhotonDauTPCCR"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTruePhoton || doPhotonLambdaSelQA) && (TMath::Abs(cand.photonMass()) <= PhotonMaxMass)) + histos.fill(HIST("PhotonSelQA/h2dPhotonDauTPCCR"), cand.photonPt(), cand.photonMass()); + histos.fill(HIST("GeneralQA/h2dPhotonPosTPCNSigmaEl"), cand.photonPosPt(), cand.photonPosTPCNSigmaEl()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 6.); + if (((cand.photonPosTPCNSigmaEl() < PhotonMinTPCNSigmas) || (cand.photonPosTPCNSigmaEl() > PhotonMaxTPCNSigmas))) + return false; + histos.fill(HIST("GeneralQA/h2dPhotonNegTPCNSigmaEl"), cand.photonNegPt(), cand.photonNegTPCNSigmaEl()); + if (((cand.photonNegTPCNSigmaEl() < PhotonMinTPCNSigmas) || (cand.photonNegTPCNSigmaEl() > PhotonMaxTPCNSigmas))) + return false; + histos.fill(HIST("SigmaSelQA/h2dPhotonTPCNSigmaEl"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTruePhoton || doPhotonLambdaSelQA) && (TMath::Abs(cand.photonMass()) <= PhotonMaxMass)) + histos.fill(HIST("PhotonSelQA/h2dPhotonTPCNSigmaEl"), cand.photonPt(), cand.photonMass()); + histos.fill(HIST("GeneralQA/h2dPhotonPosTPCNSigmaPi"), cand.photonPosPt(), cand.photonPosTPCNSigmaPi()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 7.); + if (((TMath::Abs(cand.photonPosTPCNSigmaPi()) < PiMaxTPCNSigmas) && cand.photonPosPt() <= piMaxpT)) + return false; + histos.fill(HIST("GeneralQA/h2dPhotonNegTPCNSigmaPi"), cand.photonNegPt(), cand.photonNegTPCNSigmaPi()); + if (((TMath::Abs(cand.photonNegTPCNSigmaPi()) < PiMaxTPCNSigmas) && cand.photonNegPt() <= piMaxpT)) + return false; + histos.fill(HIST("GeneralQA/hPhotonpT"), cand.photonPt()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 8.); + if ((cand.photonPt() < PhotonMinPt) || (cand.photonPt() > PhotonMaxPt)) + return false; + histos.fill(HIST("SigmaSelQA/h2dPhotonpT"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTruePhoton || doPhotonLambdaSelQA) && (TMath::Abs(cand.photonMass()) <= PhotonMaxMass)) + histos.fill(HIST("PhotonSelQA/h2dPhotonpT"), cand.photonPt(), cand.photonMass()); + histos.fill(HIST("GeneralQA/hPhotonY"), cand.photonY()); + histos.fill(HIST("GeneralQA/hPhotonPosEta"), cand.photonPosEta()); + histos.fill(HIST("GeneralQA/hPhotonNegEta"), cand.photonNegEta()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 9.); + if ((TMath::Abs(cand.photonY()) > PhotonMaxRap) || (TMath::Abs(cand.photonPosEta()) > PhotonMaxDauEta) || (TMath::Abs(cand.photonNegEta()) > PhotonMaxDauEta)) + return false; + histos.fill(HIST("SigmaSelQA/h2dPhotonY"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTruePhoton || doPhotonLambdaSelQA) && (TMath::Abs(cand.photonMass()) <= PhotonMaxMass)) + histos.fill(HIST("PhotonSelQA/h2dPhotonY"), cand.photonPt(), cand.photonMass()); + histos.fill(HIST("GeneralQA/hPhotonRadius"), cand.photonRadius()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 10.); + if ((cand.photonRadius() < PhotonMinRadius) || (cand.photonRadius() > PhotonMaxRadius)) + return false; + float photonRZLineCut = TMath::Abs(cand.photonZconv()) * TMath::Tan(2 * TMath::ATan(TMath::Exp(-PhotonMaxDauEta))) - PhotonLineCutZ0; + histos.fill(HIST("SigmaSelQA/h2dPhotonRadius"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTruePhoton || doPhotonLambdaSelQA) && (TMath::Abs(cand.photonMass()) <= PhotonMaxMass)) + histos.fill(HIST("PhotonSelQA/h2dPhotonRadius"), cand.photonPt(), cand.photonMass()); + histos.fill(HIST("GeneralQA/hPhotonZ"), cand.photonZconv()); + histos.fill(HIST("GeneralQA/h2dRZCut"), cand.photonRadius(), photonRZLineCut); + histos.fill(HIST("GeneralQA/h2dRZPlane"), cand.photonZconv(), cand.photonRadius()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 11.); + if ((TMath::Abs(cand.photonRadius()) < photonRZLineCut) || (TMath::Abs(cand.photonZconv()) > PhotonMaxZ)) + return false; + histos.fill(HIST("SigmaSelQA/h2dRZCut"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTruePhoton || doPhotonLambdaSelQA) && (TMath::Abs(cand.photonMass()) <= PhotonMaxMass)) + histos.fill(HIST("PhotonSelQA/h2dRZCut"), cand.photonPt(), cand.photonMass()); + histos.fill(HIST("GeneralQA/h2dPhotonArmenteros"), cand.photonAlpha(), cand.photonQt()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 12.); + if (cand.photonQt() > PhotonMaxQt) + return false; + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 13.); + if (TMath::Abs(cand.photonAlpha()) > PhotonMaxAlpha) + return false; + histos.fill(HIST("SigmaSelQA/h2dPhotonArmenteros"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTruePhoton || doPhotonLambdaSelQA) && (TMath::Abs(cand.photonMass()) <= PhotonMaxMass)) + histos.fill(HIST("PhotonSelQA/h2dPhotonArmenteros"), cand.photonPt(), cand.photonMass()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 14.); + histos.fill(HIST("GeneralQA/hPhotonCosPA"), cand.photonCosPA()); + if (cand.photonCosPA() < PhotonMinV0cospa) + return false; + histos.fill(HIST("SigmaSelQA/h2dPhotonCosPA"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTruePhoton || doPhotonLambdaSelQA) && (TMath::Abs(cand.photonMass()) <= PhotonMaxMass)) + histos.fill(HIST("PhotonSelQA/h2dPhotonCosPA"), cand.photonPt(), cand.photonMass()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 15.); + histos.fill(HIST("GeneralQA/hPhotonPsiPair"), cand.photonPsiPair()); + if (TMath::Abs(cand.photonPsiPair()) > PhotonPsiPairMax) + return false; + histos.fill(HIST("SigmaSelQA/h2dPhotonPsiPair"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTruePhoton || doPhotonLambdaSelQA) && (TMath::Abs(cand.photonMass()) <= PhotonMaxMass)) + histos.fill(HIST("PhotonSelQA/h2dPhotonPsiPair"), cand.photonPt(), cand.photonMass()); + + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 16.); + histos.fill(HIST("GeneralQA/hPhotonPhi"), cand.photonPhi()); + if (((cand.photonPhi() < PhotonPhiMin1) || ((cand.photonPhi() > PhotonPhiMax1) && (cand.photonPhi() < PhotonPhiMin2)) || ((cand.photonPhi() > PhotonPhiMax2) && (PhotonPhiMax2 != -1)))) + return false; + if ((isMCTruePhoton || doPhotonLambdaSelQA) && (TMath::Abs(cand.photonMass()) <= PhotonMaxMass)) + histos.fill(HIST("PhotonSelQA/h2dPhotonPhi"), cand.photonPt(), cand.photonMass()); + histos.fill(HIST("GeneralQA/h3dPhotonMass"), cand.sigmaCentrality(), cand.photonPt(), cand.photonMass()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 17.); + if (TMath::Abs(cand.photonMass()) > PhotonMaxMass) + return false; + histos.fill(HIST("SigmaSelQA/h2dPhotonMass"), cand.sigmapT(), cand.sigmaMass()); + if (isMCTruePhoton || doPhotonLambdaSelQA) + histos.fill(HIST("PhotonSelQA/h2dPhotonMass"), cand.photonPt(), cand.photonMass()); + + // #### + // Lambda selections + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 18.); + histos.fill(HIST("GeneralQA/hLambdaRadius"), cand.lambdaRadius()); + if ((isMCTrueLambda || doPhotonLambdaSelQA) && (TMath::Abs(cand.lambdaMass() - o2::constants::physics::MassLambda0) < LambdaWindow)) + histos.fill(HIST("LambdaSelQA/h2dLambdaBaseline"), cand.lambdaPt(), cand.lambdaMass()); + if ((cand.lambdaRadius() < LambdaMinv0radius) || (cand.lambdaRadius() > LambdaMaxv0radius)) + return false; + histos.fill(HIST("SigmaSelQA/h2dLambdaRadius"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTrueLambda || doPhotonLambdaSelQA) && (TMath::Abs(cand.lambdaMass() - o2::constants::physics::MassLambda0) < LambdaWindow)) + histos.fill(HIST("LambdaSelQA/h2dLambdaRadius"), cand.lambdaPt(), cand.lambdaMass()); + histos.fill(HIST("GeneralQA/hLambdaDCADau"), cand.lambdaDCADau()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 19.); + if (TMath::Abs(cand.lambdaDCADau()) > LambdaMaxDCAV0Dau) + return false; + histos.fill(HIST("SigmaSelQA/h2dLambdaDCADau"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTrueLambda || doPhotonLambdaSelQA) && (TMath::Abs(cand.lambdaMass() - o2::constants::physics::MassLambda0) < LambdaWindow)) + histos.fill(HIST("LambdaSelQA/h2dLambdaDCADau"), cand.lambdaPt(), cand.lambdaMass()); + histos.fill(HIST("GeneralQA/h2dLambdaArmenteros"), cand.lambdaAlpha(), cand.lambdaQt()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 20.); + if ((cand.lambdaQt() < LambdaMinQt) || (cand.lambdaQt() > LambdaMaxQt)) + return false; + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 21.); + if ((TMath::Abs(cand.lambdaAlpha()) < LambdaMinAlpha) || (TMath::Abs(cand.lambdaAlpha()) > LambdaMaxAlpha)) + return false; + histos.fill(HIST("SigmaSelQA/h2dLambdaArmenteros"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTrueLambda || doPhotonLambdaSelQA) && (TMath::Abs(cand.lambdaMass() - o2::constants::physics::MassLambda0) < LambdaWindow)) + histos.fill(HIST("LambdaSelQA/h2dLambdaArmenteros"), cand.lambdaPt(), cand.lambdaMass()); + histos.fill(HIST("GeneralQA/hLambdaCosPA"), cand.lambdaCosPA()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 22.); + if (cand.lambdaCosPA() < LambdaMinv0cospa) + return false; + histos.fill(HIST("SigmaSelQA/h2dLambdaCosPA"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTrueLambda || doPhotonLambdaSelQA) && (TMath::Abs(cand.lambdaMass() - o2::constants::physics::MassLambda0) < LambdaWindow)) + histos.fill(HIST("LambdaSelQA/h2dLambdaCosPA"), cand.lambdaPt(), cand.lambdaMass()); + histos.fill(HIST("GeneralQA/hLambdaY"), cand.lambdaY()); + histos.fill(HIST("GeneralQA/hLambdaPosEta"), cand.lambdaPosEta()); + histos.fill(HIST("GeneralQA/hLambdaNegEta"), cand.lambdaNegEta()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 23.); + if ((TMath::Abs(cand.lambdaY()) > LambdaMaxRap) || (TMath::Abs(cand.lambdaPosEta()) > LambdaMaxDauEta) || (TMath::Abs(cand.lambdaNegEta()) > LambdaMaxDauEta)) + return false; + histos.fill(HIST("SigmaSelQA/h2dLambdaY"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTrueLambda || doPhotonLambdaSelQA) && (TMath::Abs(cand.lambdaMass() - o2::constants::physics::MassLambda0) < LambdaWindow)) + histos.fill(HIST("LambdaSelQA/h2dLambdaY"), cand.lambdaPt(), cand.lambdaMass()); + histos.fill(HIST("GeneralQA/hLambdaPosTPCCR"), cand.lambdaPosTPCCrossedRows()); + histos.fill(HIST("GeneralQA/hLambdaNegTPCCR"), cand.lambdaNegTPCCrossedRows()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 24.); + if ((cand.lambdaPosTPCCrossedRows() < LambdaMinTPCCrossedRows) || (cand.lambdaNegTPCCrossedRows() < LambdaMinTPCCrossedRows)) + return false; + histos.fill(HIST("SigmaSelQA/h2dLambdaDauTPCCR"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTrueLambda || doPhotonLambdaSelQA) && (TMath::Abs(cand.lambdaMass() - o2::constants::physics::MassLambda0) < LambdaWindow)) + histos.fill(HIST("LambdaSelQA/h2dLambdaDauTPCCR"), cand.lambdaPt(), cand.lambdaMass()); + histos.fill(HIST("GeneralQA/hLambdaPosITSCls"), cand.lambdaPosITSCls()); + histos.fill(HIST("GeneralQA/hLambdaNegITSCls"), cand.lambdaNegITSCls()); + histos.fill(HIST("GeneralQA/hLambdaPosChi2PerNc"), cand.lambdaPosChi2PerNcl()); + histos.fill(HIST("GeneralQA/hLambdaNegChi2PerNc"), cand.lambdaNegChi2PerNcl()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 25.); + // check minimum number of ITS clusters + reject ITS afterburner tracks if requested + bool posIsFromAfterburner = cand.lambdaPosChi2PerNcl() < 0; + bool negIsFromAfterburner = cand.lambdaNegChi2PerNcl() < 0; + if (cand.lambdaPosITSCls() < LambdaMinITSclusters && (!LambdaRejectPosITSafterburner || posIsFromAfterburner)) + return false; + if (cand.lambdaNegITSCls() < LambdaMinITSclusters && (!LambdaRejectNegITSafterburner || negIsFromAfterburner)) + return false; + histos.fill(HIST("SigmaSelQA/h2dLambdaDauITSCls"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTrueLambda || doPhotonLambdaSelQA) && (TMath::Abs(cand.lambdaMass() - o2::constants::physics::MassLambda0) < LambdaWindow)) + histos.fill(HIST("LambdaSelQA/h2dLambdaDauITSCls"), cand.lambdaPt(), cand.lambdaMass()); + histos.fill(HIST("GeneralQA/hLambdaLifeTime"), cand.lambdaLifeTime()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 26.); + if (cand.lambdaLifeTime() > LambdaMaxLifeTime) + return false; + histos.fill(HIST("SigmaSelQA/h2dLambdaLifeTime"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTrueLambda || doPhotonLambdaSelQA) && (TMath::Abs(cand.lambdaMass() - o2::constants::physics::MassLambda0) < LambdaWindow)) + histos.fill(HIST("LambdaSelQA/h2dLambdaLifeTime"), cand.lambdaPt(), cand.lambdaMass()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 27.); + // Separating lambda and antilambda selections: + if (isLambdalike) { // Lambda selection + histos.fill(HIST("GeneralQA/h2dTPCvsTOFNSigma_LambdaPr"), cand.lambdaPosPrTPCNSigma(), cand.lambdaPrTOFNSigma()); + histos.fill(HIST("GeneralQA/h2dTPCvsTOFNSigma_LambdaPi"), cand.lambdaNegPiTPCNSigma(), cand.lambdaPiTOFNSigma()); + + // TPC Selection + if (fselLambdaTPCPID && (TMath::Abs(cand.lambdaPosPrTPCNSigma()) > LambdaMaxTPCNSigmas)) + return false; + if (fselLambdaTPCPID && (TMath::Abs(cand.lambdaNegPiTPCNSigma()) > LambdaMaxTPCNSigmas)) + return false; + + // TOF Selection + if (fselLambdaTOFPID && (TMath::Abs(cand.lambdaPrTOFNSigma()) > LambdaPrMaxTOFNSigmas)) + return false; + if (fselLambdaTOFPID && (TMath::Abs(cand.lambdaPiTOFNSigma()) > LambdaPiMaxTOFNSigmas)) + return false; + + histos.fill(HIST("SigmaSelQA/h2dTPCvsTOFNSigma_Lambda"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTrueLambda || doPhotonLambdaSelQA) && (TMath::Abs(cand.lambdaMass() - o2::constants::physics::MassLambda0) < LambdaWindow)) + histos.fill(HIST("LambdaSelQA/h2dTPCvsTOFNSigma_Lambda"), cand.lambdaPt(), cand.lambdaMass()); + // DCA Selection + histos.fill(HIST("GeneralQA/hLambdaDCANegToPV"), cand.lambdaDCANegPV()); + histos.fill(HIST("GeneralQA/hLambdaDCAPosToPV"), cand.lambdaDCAPosPV()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 28.); + if ((TMath::Abs(cand.lambdaDCAPosPV()) < LambdaMinDCAPosToPv) || (TMath::Abs(cand.lambdaDCANegPV()) < LambdaMinDCANegToPv)) + return false; + histos.fill(HIST("SigmaSelQA/h2dLambdaDCADauToPV"), cand.sigmapT(), cand.sigmaMass()); + if ((isMCTrueLambda || doPhotonLambdaSelQA) && (TMath::Abs(cand.lambdaMass() - o2::constants::physics::MassLambda0) < LambdaWindow)) + histos.fill(HIST("LambdaSelQA/h2dLambdaDCADauToPV"), cand.lambdaPt(), cand.lambdaMass()); + + // Mass Selection + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 29.); + histos.fill(HIST("GeneralQA/h3dLambdaMass"), cand.sigmaCentrality(), cand.lambdaPt(), cand.lambdaMass()); + if (TMath::Abs(cand.lambdaMass() - o2::constants::physics::MassLambda0) > LambdaWindow) + return false; + histos.fill(HIST("SigmaSelQA/h2dLambdaMass"), cand.sigmapT(), cand.sigmaMass()); + if (isMCTrueLambda || doPhotonLambdaSelQA) + histos.fill(HIST("LambdaSelQA/h2dLambdaMass"), cand.lambdaPt(), cand.lambdaMass()); + + } else { // AntiLambda selection + histos.fill(HIST("GeneralQA/h2dTPCvsTOFNSigma_ALambdaPr"), cand.lambdaNegPrTPCNSigma(), cand.aLambdaPrTOFNSigma()); + histos.fill(HIST("GeneralQA/h2dTPCvsTOFNSigma_ALambdaPi"), cand.lambdaPosPiTPCNSigma(), cand.aLambdaPiTOFNSigma()); + + // TPC Selection + if (fselLambdaTPCPID && (TMath::Abs(cand.lambdaPosPiTPCNSigma()) > LambdaMaxTPCNSigmas)) + return false; + if (fselLambdaTPCPID && (TMath::Abs(cand.lambdaNegPrTPCNSigma()) > LambdaMaxTPCNSigmas)) + return false; + + // TOF Selection + if (fselLambdaTOFPID && (TMath::Abs(cand.aLambdaPrTOFNSigma()) > LambdaPrMaxTOFNSigmas)) + return false; + if (fselLambdaTOFPID && (TMath::Abs(cand.aLambdaPiTOFNSigma()) > LambdaPiMaxTOFNSigmas)) + return false; + + histos.fill(HIST("SigmaSelQA/h2dTPCvsTOFNSigma_ALambda"), cand.sigmapT(), cand.sigmaMass()); + // DCA Selection + histos.fill(HIST("GeneralQA/hALambdaDCANegToPV"), cand.lambdaDCANegPV()); + histos.fill(HIST("GeneralQA/hALambdaDCAPosToPV"), cand.lambdaDCAPosPV()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 28.); + if ((TMath::Abs(cand.lambdaDCAPosPV()) < ALambdaMinDCAPosToPv) || (TMath::Abs(cand.lambdaDCANegPV()) < ALambdaMinDCANegToPv)) + return false; + + histos.fill(HIST("SigmaSelQA/h2dALambdaDCADauToPV"), cand.sigmapT(), cand.sigmaMass()); + // Mass Selection + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 29.); + histos.fill(HIST("GeneralQA/h3dAntiLambdaMass"), cand.sigmaCentrality(), cand.lambdaPt(), cand.antilambdaMass()); + if (TMath::Abs(cand.antilambdaMass() - o2::constants::physics::MassLambda0) > LambdaWindow) + return false; + histos.fill(HIST("SigmaSelQA/h2dAntiLambdaMass"), cand.sigmapT(), cand.sigmaMass()); + } + + // Sigma0 selection + histos.fill(HIST("GeneralQA/hSigmaY"), cand.sigmaRapidity()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 30.); + if (TMath::Abs(cand.sigmaRapidity()) > SigmaMaxRap) + return false; + histos.fill(HIST("SigmaSelQA/h2dSigmaY"), cand.sigmapT(), cand.sigmaMass()); + histos.fill(HIST("GeneralQA/hSigmaOPAngle"), cand.sigmaOPAngle()); + histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 31.); } + return true; } - void processMonteCarlo(aod::StraCollision const& coll, soa::Join const& v0s) + void processMonteCarlo(V0MCSigmas const& sigmas) { - int SigmaCounter = 0; - - histos.fill(HIST("hEventVertexZMC"), coll.posZ()); + for (auto& sigma : sigmas) { // selecting Sigma0-like candidates + if (doMCAssociation && !(sigma.isSigma() || sigma.isAntiSigma())) { + continue; + } + if (fGetIR) { + double interactionRate = rateFetcher.fetch(ccdb.service, sigma.sigmaTimestamp(), sigma.sigmaRunNumber(), irSource) * 1.e-3; + histos.fill(HIST("GeneralQA/hInteractionRate"), interactionRate); + histos.fill(HIST("GeneralQA/hCentralityVsInteractionRate"), sigma.sigmaCentrality(), interactionRate); + if ((maxIR != -1) && (minIR != -1) && ((interactionRate <= minIR) || (interactionRate >= maxIR))) { + continue; + } + } - for (auto& gamma : v0s) { // selecting photons from Sigma0 + // Filling histos before analysis selection + histos.fill(HIST("MC/h2dSigmaMCPtVsLambdaMCPt"), sigma.sigmaMCPt(), sigma.lambdaMCPt()); + histos.fill(HIST("MC/h2dSigmaMCPtVsGammaMCPt"), sigma.sigmaMCPt(), sigma.photonMCPt()); + histos.fill(HIST("MC/h3dMassAllSigma0sBeforesel"), sigma.sigmaCentrality(), sigma.sigmapT(), sigma.sigmaMass()); + histos.fill(HIST("MC/h2dArmenterosBeforeSel"), sigma.photonAlpha(), sigma.photonQt()); + histos.fill(HIST("MC/h2dArmenterosBeforeSel"), sigma.lambdaAlpha(), sigma.lambdaQt()); + histos.fill(HIST("MC/hMassSigma0BeforeSel"), sigma.sigmaMass()); + histos.fill(HIST("MC/hPtSigma0BeforeSel"), sigma.sigmapT()); + histos.fill(HIST("MC/hPtGammaCand_BeforeSel"), sigma.photonPt()); + histos.fill(HIST("MC/hPtLambdaCand_BeforeSel"), sigma.lambdaPt()); + histos.fill(HIST("MC/hPtSigmaCand_BeforeSel"), sigma.sigmapT()); - if ((gamma.pdgCode() != 22 || gamma.pdgCodeMother() != 3212) && (gamma.pdgCode() != -22 || gamma.pdgCodeMother() != -3212)) - continue; + if (sigma.photonCandPDGCode() == 22) { + histos.fill(HIST("MC/hPtTrueGamma_BeforeSel"), sigma.photonPt()); + if (sigma.photonMCPt() > 0) { + histos.fill(HIST("MC/h3dGammaPtResoVsTPCCR"), 1.f / sigma.lambdaMCPt(), 1.f / sigma.lambdaPt() - 1.f / sigma.lambdaMCPt(), -1 * sigma.photonNegTPCCrossedRows()); // 1/pT resolution + histos.fill(HIST("MC/h3dGammaPtResoVsTPCCR"), 1.f / sigma.lambdaMCPt(), 1.f / sigma.lambdaPt() - 1.f / sigma.lambdaMCPt(), sigma.photonPosTPCCrossedRows()); // 1/pT resolution + histos.fill(HIST("MC/h2dGammaPtResolution"), 1.f / sigma.photonMCPt(), 1.f / sigma.photonPt() - 1.f / sigma.photonMCPt()); // pT resolution + } + } + if (sigma.lambdaCandPDGCode() == 3122) { + histos.fill(HIST("MC/hPtTrueLambda_BeforeSel"), sigma.lambdaPt()); + if (sigma.lambdaMCPt() > 0) { + histos.fill(HIST("MC/h2dLambdaPtResolution"), 1.f / sigma.lambdaMCPt(), 1.f / sigma.lambdaPt() - 1.f / sigma.lambdaMCPt()); // 1/pT resolution + histos.fill(HIST("MC/h3dLambdaPtResoVsTPCCR"), 1.f / sigma.lambdaMCPt(), 1.f / sigma.lambdaPt() - 1.f / sigma.lambdaMCPt(), -1 * sigma.lambdaNegTPCCrossedRows()); // 1/pT resolution + histos.fill(HIST("MC/h3dLambdaPtResoVsTPCCR"), 1.f / sigma.lambdaMCPt(), 1.f / sigma.lambdaPt() - 1.f / sigma.lambdaMCPt(), sigma.lambdaPosTPCCrossedRows()); // 1/pT resolution + } + } + if (sigma.lambdaCandPDGCode() == -3122) { + if (sigma.lambdaMCPt() > 0) { + histos.fill(HIST("MC/h2dAntiLambdaPtResolution"), 1.f / sigma.lambdaMCPt(), 1.f / sigma.lambdaPt() - 1.f / sigma.lambdaMCPt()); // pT resolution + histos.fill(HIST("MC/h3dAntiLambdaPtResoVsTPCCR"), 1.f / sigma.lambdaMCPt(), 1.f / sigma.lambdaPt() - 1.f / sigma.lambdaMCPt(), -1 * sigma.lambdaNegTPCCrossedRows()); // 1/pT resolution + histos.fill(HIST("MC/h3dAntiLambdaPtResoVsTPCCR"), 1.f / sigma.lambdaMCPt(), 1.f / sigma.lambdaPt() - 1.f / sigma.lambdaMCPt(), sigma.lambdaPosTPCCrossedRows()); // 1/pT resolution + } + histos.fill(HIST("MC/hPtTrueAntiLambda_BeforeSel"), sigma.lambdaPt()); + } + if (sigma.isSigma()) { + histos.fill(HIST("MC/hPtTrueSigma_BeforeSel"), sigma.sigmapT()); + if (sigma.sigmaMCPt() > 0) + histos.fill(HIST("MC/h2dSigma0PtResolution"), 1.f / sigma.sigmaMCPt(), 1.f / sigma.sigmapT() - 1.f / sigma.sigmaMCPt()); // pT resolution + } + if (sigma.isAntiSigma()) { + histos.fill(HIST("MC/hPtTrueAntiSigma_BeforeSel"), sigma.sigmapT()); + if (sigma.sigmaMCPt() > 0) + histos.fill(HIST("MC/h2dAntiSigma0PtResolution"), 1.f / sigma.sigmaMCPt(), 1.f / sigma.sigmapT() - 1.f / sigma.sigmaMCPt()); // pT resolution + } - for (auto& lambda : v0s) { // selecting lambdas from Sigma0 - if ((lambda.pdgCode() != 3122 || lambda.pdgCodeMother() != 3212) && (lambda.pdgCode() != -3122 || lambda.pdgCodeMother() != -3212)) + if (sigma.lambdaAlpha() > 0) { // Lambda Analysis + if (!processSigmaCandidate(sigma, true)) continue; - if (gamma.motherMCPartId() != lambda.motherMCPartId()) - continue; // selecting pair from exactly the same mother - - // Exploratory Analysis histograms: - - // Lambda - histos.fill(HIST("hMCLambdaCosPA"), lambda.v0cosPA()); - histos.fill(HIST("hMCLambdaDCA_V0Dau"), TMath::Abs(lambda.dcaV0daughters())); - histos.fill(HIST("hMCLambdaDCA_V0Pos"), TMath::Abs(lambda.dcapostopv())); - histos.fill(HIST("hMCLambdaDCA_V0Neg"), TMath::Abs(lambda.dcanegtopv())); - histos.fill(HIST("hMCLambda_V0Radius"), lambda.v0radius()); - - // Photon - histos.fill(HIST("hMCPhoton_ConversionRadius"), gamma.v0radius()); - histos.fill(HIST("hMCPhotonCosPA"), gamma.v0cosPA()); - histos.fill(HIST("hMCPhotonDCA_V0Dau"), TMath::Abs(gamma.dcaV0daughters())); - histos.fill(HIST("hMCPhotonDCA_V0Pos"), TMath::Abs(gamma.dcapostopv())); - histos.fill(HIST("hMCPhotonDCA_V0Neg"), TMath::Abs(gamma.dcanegtopv())); - - // Armenteros-Polanski plot: - histos.fill(HIST("h2dMCArmenterosPolanski"), gamma.alpha(), gamma.qtarm()); - histos.fill(HIST("h2dMCArmenterosPolanski"), lambda.alpha(), lambda.qtarm()); - - if (!processSigmaCandidate(coll, lambda, gamma)) + + // For Lambda PID Studies + histos.fill(HIST("MC/hPtLambdaCand_AfterSel"), sigma.lambdaPt()); + histos.fill(HIST("MC/h3dTPCvsTOFNSigma_LambdaPr"), sigma.lambdaPosPrTPCNSigma(), sigma.lambdaPrTOFNSigma(), sigma.lambdaPt()); + histos.fill(HIST("MC/h3dTPCvsTOFNSigma_LambdaPi"), sigma.lambdaNegPiTPCNSigma(), sigma.lambdaPiTOFNSigma(), sigma.lambdaPt()); + + if (sigma.lambdaCandPDGCode() == 3122) { + histos.fill(HIST("MC/hPtTrueLambda_AfterSel"), sigma.lambdaPt()); + histos.fill(HIST("MC/h3dTPCvsTOFNSigma_TrueLambdaPr"), sigma.lambdaPosPrTPCNSigma(), sigma.lambdaPrTOFNSigma(), sigma.lambdaPt()); + histos.fill(HIST("MC/h3dTPCvsTOFNSigma_TrueLambdaPi"), sigma.lambdaNegPiTPCNSigma(), sigma.lambdaPiTOFNSigma(), sigma.lambdaPt()); + } + histos.fill(HIST("GeneralQA/hLambdaMassSelected"), sigma.lambdaMass()); + histos.fill(HIST("Sigma0/hMassSigma0"), sigma.sigmaMass()); + histos.fill(HIST("Sigma0/hPtSigma0"), sigma.sigmapT()); + histos.fill(HIST("Sigma0/hRapiditySigma0"), sigma.sigmaRapidity()); + histos.fill(HIST("Sigma0/h3dMassSigma0"), sigma.sigmaCentrality(), sigma.sigmapT(), sigma.sigmaMass()); + histos.fill(HIST("Sigma0/h3dPhotonRadiusVsMassSigma0"), sigma.sigmaCentrality(), sigma.photonRadius(), sigma.sigmaMass()); + + if (sigma.isSigma()) { // Signal study + histos.fill(HIST("MC/h2dArmenterosAfterSel"), sigma.photonAlpha(), sigma.photonQt()); + histos.fill(HIST("MC/h2dArmenterosAfterSel"), sigma.lambdaAlpha(), sigma.lambdaQt()); + histos.fill(HIST("MC/hMassSigma0"), sigma.sigmaMass()); + histos.fill(HIST("MC/hPtSigma0"), sigma.sigmapT()); + histos.fill(HIST("MC/h3dMassSigma0"), sigma.sigmaCentrality(), sigma.sigmapT(), sigma.sigmaMass()); + histos.fill(HIST("MC/h2dPtVsMassSigma_SignalOnly"), sigma.sigmapT(), sigma.sigmaMass()); + histos.fill(HIST("MC/hPtTrueSigma_AfterSel"), sigma.sigmapT()); + } + } else { // AntiLambda Analysis + if (!processSigmaCandidate(sigma, false)) continue; - SigmaCounter++; - histos.fill(HIST("h2dLambdaRadiusVsPtMC"), sigmaCandidate.pT, lambda.v0radius()); - histos.fill(HIST("h2dPhotonRadiusVsPtMC"), sigmaCandidate.pT, gamma.v0radius()); + if (sigma.lambdaCandPDGCode() == -3122) { + histos.fill(HIST("MC/hPtTrueAntiLambda_AfterSel"), sigma.lambdaPt()); + histos.fill(HIST("MC/h3dTPCvsTOFNSigma_TrueALambdaPr"), sigma.lambdaNegPrTPCNSigma(), sigma.aLambdaPrTOFNSigma(), sigma.lambdaPt()); + histos.fill(HIST("MC/h3dTPCvsTOFNSigma_TrueALambdaPi"), sigma.lambdaPosPiTPCNSigma(), sigma.aLambdaPiTOFNSigma(), sigma.lambdaPt()); + } + histos.fill(HIST("GeneralQA/hAntiLambdaMassSelected"), sigma.antilambdaMass()); + histos.fill(HIST("AntiSigma0/hMassAntiSigma0"), sigma.sigmaMass()); + histos.fill(HIST("AntiSigma0/hPtAntiSigma0"), sigma.sigmapT()); + histos.fill(HIST("AntiSigma0/hRapidityAntiSigma0"), sigma.sigmaRapidity()); + histos.fill(HIST("AntiSigma0/h3dMassAntiSigma0"), sigma.sigmaCentrality(), sigma.sigmapT(), sigma.sigmaMass()); + histos.fill(HIST("AntiSigma0/h3dPhotonRadiusVsMassAntiSigma0"), sigma.sigmaCentrality(), sigma.photonRadius(), sigma.sigmaMass()); + if (sigma.isAntiSigma()) { // Signal study + histos.fill(HIST("MC/h2dArmenterosAfterSel"), sigma.photonAlpha(), sigma.photonQt()); + histos.fill(HIST("MC/h2dArmenterosAfterSel"), sigma.lambdaAlpha(), sigma.lambdaQt()); + histos.fill(HIST("MC/hMassAntiSigma0"), sigma.sigmaMass()); + histos.fill(HIST("MC/hPtAntiSigma0"), sigma.sigmapT()); + histos.fill(HIST("MC/h3dMassAntiSigma0"), sigma.sigmaCentrality(), sigma.sigmapT(), sigma.sigmaMass()); + histos.fill(HIST("MC/h2dPtVsMassSigma_SignalOnly"), sigma.sigmapT(), sigma.sigmaMass()); + histos.fill(HIST("MC/hPtTrueSigma_AfterSel"), sigma.sigmapT()); + } + } + + // Fill histos after selection, please + histos.fill(HIST("MC/hPtGammaCand_AfterSel"), sigma.photonPt()); + histos.fill(HIST("GeneralQA/hPhotonMassSelected"), sigma.photonMass()); + histos.fill(HIST("MC/hPtSigmaCand_AfterSel"), sigma.sigmapT()); + + if (sigma.photonCandPDGCode() == 22) { + histos.fill(HIST("MC/hPtTrueGamma_AfterSel"), sigma.photonPt()); + } - // Inv Mass - histos.fill(HIST("h2dLambdaMassVsPtMC"), sigmaCandidate.pT, lambda.mLambda()); - histos.fill(HIST("h2dPhotonMassVsPtMC"), sigmaCandidate.pT, gamma.mGamma()); - histos.fill(HIST("h2dSigmaMassVsPtMC"), sigmaCandidate.pT, sigmaCandidate.mass); + // For background studies: + histos.fill(HIST("MC/h2dPtVsMassSigma_SignalBkg"), sigma.sigmapT(), sigma.sigmaMass()); + // Real Gamma x Real Lambda - but not from the same sigma0/antisigma0! + if ((sigma.photonCandPDGCode() == 22) && ((sigma.lambdaCandPDGCode() == 3122) || (sigma.lambdaCandPDGCode() == -3122)) && !(sigma.isSigma()) && !(sigma.isAntiSigma())) { + histos.fill(HIST("MC/h2dPtVsMassSigma_TrueDaughters"), sigma.sigmapT(), sigma.sigmaMass()); + histos.fill(HIST("MC/h2dTrueDaughtersMatrix"), sigma.lambdaCandPDGCodeMother(), sigma.photonCandPDGCodeMother()); + histos.fill(HIST("MC/h2dPtVsOPAngle_TrueDaughters"), sigma.sigmapT(), sigma.sigmaOPAngle()); } + // Real Gamma x fake Lambda + if ((sigma.photonCandPDGCode() == 22) && (sigma.lambdaCandPDGCode() != 3122) && (sigma.lambdaCandPDGCode() != -3122)) + histos.fill(HIST("MC/h2dPtVsMassSigma_TrueGammaFakeLambda"), sigma.sigmapT(), sigma.sigmaMass()); + + // Fake Gamma x Real Lambda + if ((sigma.photonCandPDGCode() != 22) && ((sigma.lambdaCandPDGCode() == 3122) || (sigma.lambdaCandPDGCode() == -3122))) + histos.fill(HIST("MC/h2dPtVsMassSigma_FakeGammaTrueLambda"), sigma.sigmapT(), sigma.sigmaMass()); + + // Fake Gamma x Fake Lambda + if ((sigma.photonCandPDGCode() != 22) && (sigma.lambdaCandPDGCode() != 3122) && (sigma.lambdaCandPDGCode() != -3122)) + histos.fill(HIST("MC/h2dPtVsMassSigma_FakeDaughters"), sigma.sigmapT(), sigma.sigmaMass()); } - histos.fill(HIST("hNSigmaCandidatesMC"), SigmaCounter); } - void processRealData(aod::StraCollision const& coll, soa::Join const& v0s) + void processRealData(V0Sigmas const& sigmas) { - int SigmaCounter = 0; + for (auto& sigma : sigmas) { // selecting Sigma0-like candidates + if (fGetIR) { + double interactionRate = rateFetcher.fetch(ccdb.service, sigma.sigmaTimestamp(), sigma.sigmaRunNumber(), irSource) * 1.e-3; + histos.fill(HIST("GeneralQA/hInteractionRate"), interactionRate); + histos.fill(HIST("GeneralQA/hCentralityVsInteractionRate"), sigma.sigmaCentrality(), interactionRate); + if ((maxIR != -1) && (minIR != -1) && ((interactionRate <= minIR) || (interactionRate >= maxIR))) { + continue; + } + } + histos.fill(HIST("GeneralQA/h2dArmenterosBeforeSel"), sigma.photonAlpha(), sigma.photonQt()); + histos.fill(HIST("GeneralQA/h2dArmenterosBeforeSel"), sigma.lambdaAlpha(), sigma.lambdaQt()); + histos.fill(HIST("GeneralQA/hMassSigma0BeforeSel"), sigma.sigmaMass()); - histos.fill(HIST("hEventVertexZ"), coll.posZ()); + nSigmaCandidates++; + if (nSigmaCandidates % 100000 == 0) { + LOG(info) << "Sigma0-like Candidates processed: " << nSigmaCandidates; + } - for (auto& gamma : v0s) { // selecting photons from Sigma0 - for (auto& lambda : v0s) { // selecting lambdas from Sigma0 - if (!processSigmaCandidate(coll, lambda, gamma)) + if (sigma.lambdaAlpha() > 0) { + // Perform analysis selection for sigma0 + if (!processSigmaCandidate(sigma, true)) continue; - SigmaCounter++; - histos.fill(HIST("h2dLambdaRadiusVsPt"), sigmaCandidate.pT, lambda.v0radius()); - histos.fill(HIST("h2dPhotonRadiusVsPt"), sigmaCandidate.pT, gamma.v0radius()); + histos.fill(HIST("GeneralQA/h2dArmenterosAfterSel"), sigma.photonAlpha(), sigma.photonQt()); + histos.fill(HIST("GeneralQA/h2dArmenterosAfterSel"), sigma.lambdaAlpha(), sigma.lambdaQt()); + histos.fill(HIST("GeneralQA/hLambdaMassSelected"), sigma.lambdaMass()); + histos.fill(HIST("Sigma0/hMassSigma0"), sigma.sigmaMass()); + histos.fill(HIST("Sigma0/hPtSigma0"), sigma.sigmapT()); + histos.fill(HIST("Sigma0/hRapiditySigma0"), sigma.sigmaRapidity()); + histos.fill(HIST("Sigma0/h3dMassSigma0"), sigma.sigmaCentrality(), sigma.sigmapT(), sigma.sigmaMass()); + histos.fill(HIST("Sigma0/h3dPhotonRadiusVsMassSigma0"), sigma.sigmaCentrality(), sigma.photonRadius(), sigma.sigmaMass()); - // Inv Mass - histos.fill(HIST("h2dLambdaMassVsPt"), sigmaCandidate.pT, lambda.mLambda()); - histos.fill(HIST("h2dPhotonMassVsPt"), sigmaCandidate.pT, gamma.mGamma()); - histos.fill(HIST("h2dSigmaMassVsPt"), sigmaCandidate.pT, sigmaCandidate.mass); + } else { - histos.fill(HIST("hMLOutputLambda"), lambda.lambdaBDTScore()); - histos.fill(HIST("hMLOutputGamma"), gamma.gammaBDTScore()); + // Perform analysis selection for antisigma0 + if (!processSigmaCandidate(sigma, false)) + continue; + + histos.fill(HIST("GeneralQA/h2dArmenterosAfterSel"), sigma.photonAlpha(), sigma.photonQt()); + histos.fill(HIST("GeneralQA/h2dArmenterosAfterSel"), sigma.lambdaAlpha(), sigma.lambdaQt()); + histos.fill(HIST("GeneralQA/hAntiLambdaMassSelected"), sigma.antilambdaMass()); + histos.fill(HIST("AntiSigma0/hMassAntiSigma0"), sigma.sigmaMass()); + histos.fill(HIST("AntiSigma0/hPtAntiSigma0"), sigma.sigmapT()); + histos.fill(HIST("AntiSigma0/hRapidityAntiSigma0"), sigma.sigmaRapidity()); + histos.fill(HIST("AntiSigma0/h3dMassAntiSigma0"), sigma.sigmaCentrality(), sigma.sigmapT(), sigma.sigmaMass()); + histos.fill(HIST("AntiSigma0/h3dPhotonRadiusVsMassAntiSigma0"), sigma.sigmaCentrality(), sigma.photonRadius(), sigma.sigmaMass()); + } + histos.fill(HIST("GeneralQA/hPhotonMassSelected"), sigma.photonMass()); + } + } + + void processCollisions(soa::Join const& collisions) + { + for (const auto& coll : collisions) { + if (!IsEventAccepted(coll)) { + continue; } + double interactionRate = rateFetcher.fetch(ccdb.service, coll.timestamp(), coll.runNumber(), irSource) * 1.e-3; + histos.fill(HIST("GeneralQA/hInteractionRatePerColl"), interactionRate); + histos.fill(HIST("GeneralQA/hCentralityVsInteractionRatePerColl"), coll.centFT0C(), interactionRate); } - histos.fill(HIST("hNSigmaCandidates"), SigmaCounter); } - PROCESS_SWITCH(sigmaanalysis, processCounterQA, "Check standard counter correctness", true); - PROCESS_SWITCH(sigmaanalysis, processMonteCarlo, "Do Monte-Carlo-based analysis", true); + // PROCESS_SWITCH(sigmaanalysis, processCounterQA, "Check standard counter correctness", true); + PROCESS_SWITCH(sigmaanalysis, processMonteCarlo, "Do Monte-Carlo-based analysis", false); PROCESS_SWITCH(sigmaanalysis, processRealData, "Do real data analysis", true); + PROCESS_SWITCH(sigmaanalysis, processCollisions, "Process collisions to retrieve IR info", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Strangeness/sigmaminustask.cxx b/PWGLF/Tasks/Strangeness/sigmaminustask.cxx new file mode 100644 index 00000000000..8b309476913 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/sigmaminustask.cxx @@ -0,0 +1,77 @@ +// 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 sigmaminustask.cxx +/// \brief Example of a simple task for the analysis of the Sigma-minus +/// \author Francesco Mazzaschi + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Common/DataModel/EventSelection.h" +#include "PWGLF/DataModel/LFKinkDecayTables.h" +#include "Common/DataModel/PIDResponse.h" +#include "ReconstructionDataFormats/PID.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using TracksFull = soa::Join; +using CollisionsFull = soa::Join; + +struct sigmaminustask { + // Histograms are defined with HistogramRegistry + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rSigmaMinus{"sigmaminus", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Configurable for event selection + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable cutNSigmaPi{"cutNSigmaPi", 4, "NSigmaTPCPion"}; + + void init(InitContext const&) + { + // Axes + const AxisSpec ptAxis{50, -10, 10, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec nSigmaPiAxis{100, -5, 5, "n#sigma_{#pi}"}; + const AxisSpec sigmaMassAxis{100, 1.1, 1.4, "m (GeV/#it{c}^{2})"}; + const AxisSpec vertexZAxis{100, -15., 15., "vrtx_{Z} [cm]"}; + + // Event selection + rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); + + // Sigma-minus reconstruction + rSigmaMinus.add("h2MassSigmaMinusPt", "h2MassSigmaMinusPt", {HistType::kTH2F, {ptAxis, sigmaMassAxis}}); + rSigmaMinus.add("h2NSigmaPiPt", "h2NSigmaPiPt", {HistType::kTH2F, {ptAxis, nSigmaPiAxis}}); + } + + void process(soa::Join::iterator const& collision, + aod::KinkCands const& KinkCands, TracksFull const&) + { + if (std::abs(collision.posZ()) > cutzvertex || !collision.sel8()) { + return; + } + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + for (const auto& kinkCand : KinkCands) { + auto dauTrack = kinkCand.trackDaug_as(); + if (abs(dauTrack.tpcNSigmaPi()) > cutNSigmaPi) { + continue; + } + rSigmaMinus.fill(HIST("h2MassSigmaMinusPt"), kinkCand.mothSign() * kinkCand.ptMoth(), kinkCand.mSigmaMinus()); + rSigmaMinus.fill(HIST("h2NSigmaPiPt"), kinkCand.mothSign() * kinkCand.ptMoth(), dauTrack.tpcNSigmaPi()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Strangeness/strangenessInJets.cxx b/PWGLF/Tasks/Strangeness/strangenessInJets.cxx new file mode 100644 index 00000000000..f5878bb17ad --- /dev/null +++ b/PWGLF/Tasks/Strangeness/strangenessInJets.cxx @@ -0,0 +1,2093 @@ +// 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 strangenessInJets.cxx +/// +/// \brief task for analysis of strangeness in jets +/// \author Alberto Caliva (alberto.caliva@cern.ch), Francesca Ercolessi (francesca.ercolessi@cern.ch), Nicolò Jacazio (nicolo.jacazio@cern.ch) +/// \since May 22, 2024 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include "PWGJE/Core/JetBkgSubUtils.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/Jet.h" + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" + +using namespace std; +using namespace o2; +using namespace o2::soa; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; +using namespace o2::constants::math; +using std::array; + +using SelCollisions = soa::Join; +using SimCollisions = soa::Join; +using StrHadronDaughterTracks = soa::Join; +using MCTracks = soa::Join; + +struct StrangenessInJets { + + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + HistogramRegistry registryData{"registryData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryMC{"registryMC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryQC{"registryQC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Global Parameters + Configurable particleOfInterest{"particleOfInterest", 0, "0=v0, 1=cascade, 2=pions, 3=k+-, 4=proton"}; + Configurable minJetPt{"minJetPt", 10.0, "Minimum pt of the jet"}; + Configurable rJet{"rJet", 0.3, "Jet resolution parameter R"}; + Configurable zVtx{"zVtx", 10.0, "Maximum zVertex"}; + Configurable deltaEtaEdge{"deltaEtaEdge", 0.05, "eta gap from the edge"}; + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; + + // Axis parameters + struct : ConfigurableGroup { + ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0}, "Binning of the pT axis"}; + + ConfigurableAxis binsDca{"binsDca", {VARIABLE_WIDTH, -3.0, -2.95, -2.9, -2.85, -2.8, -2.75, -2.7, -2.65, -2.6, -2.55, -2.5, -2.45, -2.4, -2.35, -2.3, -2.25, -2.2, -2.15, -2.1, -2.05, -2.0, -1.975, -1.95, -1.925, -1.9, -1.875, -1.85, -1.825, -1.8, -1.775, -1.75, -1.725, -1.7, -1.675, -1.65, -1.625, -1.6, -1.575, -1.55, -1.525, -1.5, -1.475, -1.45, -1.425, -1.4, -1.375, -1.35, -1.325, -1.3, -1.275, -1.25, -1.225, -1.2, -1.175, -1.15, -1.125, -1.1, -1.075, -1.05, -1.025, -1.0, -0.99, -0.98, -0.97, -0.96, -0.95, -0.94, -0.93, -0.92, -0.91, -0.9, -0.89, -0.88, -0.87, -0.86, -0.85, -0.84, -0.83, -0.82, -0.81, -0.8, -0.79, -0.78, -0.77, -0.76, -0.75, -0.74, -0.73, -0.72, -0.71, -0.7, -0.69, -0.68, -0.67, -0.66, -0.65, -0.64, -0.63, -0.62, -0.61, -0.6, -0.59, -0.58, -0.57, -0.56, -0.55, -0.54, -0.53, -0.52, -0.51, -0.5, -0.49, -0.48, -0.47, -0.46, -0.45, -0.44, -0.43, -0.42, -0.41, -0.4, -0.396, -0.392, -0.388, -0.384, -0.38, -0.376, -0.372, -0.368, -0.364, -0.36, -0.356, -0.352, -0.348, -0.344, -0.34, -0.336, -0.332, -0.328, -0.324, -0.32, -0.316, -0.312, -0.308, -0.304, -0.3, -0.296, -0.292, -0.288, -0.284, -0.28, -0.276, -0.272, -0.268, -0.264, -0.26, -0.256, -0.252, -0.248, -0.244, -0.24, -0.236, -0.232, -0.228, -0.224, -0.22, -0.216, -0.212, -0.208, -0.204, -0.2, -0.198, -0.196, -0.194, -0.192, -0.19, -0.188, -0.186, -0.184, -0.182, -0.18, -0.178, -0.176, -0.174, -0.172, -0.17, -0.168, -0.166, -0.164, -0.162, -0.16, -0.158, -0.156, -0.154, -0.152, -0.15, -0.148, -0.146, -0.144, -0.142, -0.14, -0.138, -0.136, -0.134, -0.132, -0.13, -0.128, -0.126, -0.124, -0.122, -0.12, -0.118, -0.116, -0.114, -0.112, -0.11, -0.108, -0.106, -0.104, -0.102, -0.1, -0.099, -0.098, -0.097, -0.096, -0.095, -0.094, -0.093, -0.092, -0.091, -0.09, -0.089, -0.088, -0.087, -0.086, -0.085, -0.084, -0.083, -0.082, -0.081, -0.08, -0.079, -0.078, -0.077, -0.076, -0.075, -0.074, -0.073, -0.072, -0.071, -0.07, -0.069, -0.068, -0.067, -0.066, -0.065, -0.064, -0.063, -0.062, -0.061, -0.06, -0.059, -0.058, -0.057, -0.056, -0.055, -0.054, -0.053, -0.052, -0.051, -0.05, -0.049, -0.048, -0.047, -0.046, -0.045, -0.044, -0.043, -0.042, -0.041, -0.04, -0.039, -0.038, -0.037, -0.036, -0.035, -0.034, -0.033, -0.032, -0.031, -0.03, -0.029, -0.028, -0.027, -0.026, -0.025, -0.024, -0.023, -0.022, -0.021, -0.02, -0.019, -0.018, -0.017, -0.016, -0.015, -0.014, -0.013, -0.012, -0.011, -0.01, -0.009, -0.008, -0.007, -0.006, -0.005, -0.004, -0.003, -0.002, -0.001, -0.0, 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, 0.01, 0.011, 0.012, 0.013, 0.014, 0.015, 0.016, 0.017, 0.018, 0.019, 0.02, 0.021, 0.022, 0.023, 0.024, 0.025, 0.026, 0.027, 0.028, 0.029, 0.03, 0.031, 0.032, 0.033, 0.034, 0.035, 0.036, 0.037, 0.038, 0.039, 0.04, 0.041, 0.042, 0.043, 0.044, 0.045, 0.046, 0.047, 0.048, 0.049, 0.05, 0.051, 0.052, 0.053, 0.054, 0.055, 0.056, 0.057, 0.058, 0.059, 0.06, 0.061, 0.062, 0.063, 0.064, 0.065, 0.066, 0.067, 0.068, 0.069, 0.07, 0.071, 0.072, 0.073, 0.074, 0.075, 0.076, 0.077, 0.078, 0.079, 0.08, 0.081, 0.082, 0.083, 0.084, 0.085, 0.086, 0.087, 0.088, 0.089, 0.09, 0.091, 0.092, 0.093, 0.094, 0.095, 0.096, 0.097, 0.098, 0.099, 0.1, 0.102, 0.104, 0.106, 0.108, 0.11, 0.112, 0.114, 0.116, 0.118, 0.12, 0.122, 0.124, 0.126, 0.128, 0.13, 0.132, 0.134, 0.136, 0.138, 0.14, 0.142, 0.144, 0.146, 0.148, 0.15, 0.152, 0.154, 0.156, 0.158, 0.16, 0.162, 0.164, 0.166, 0.168, 0.17, 0.172, 0.174, 0.176, 0.178, 0.18, 0.182, 0.184, 0.186, 0.188, 0.19, 0.192, 0.194, 0.196, 0.198, 0.2, 0.204, 0.208, 0.212, 0.216, 0.22, 0.224, 0.228, 0.232, 0.236, 0.24, 0.244, 0.248, 0.252, 0.256, 0.26, 0.264, 0.268, 0.272, 0.276, 0.28, 0.284, 0.288, 0.292, 0.296, 0.3, 0.304, 0.308, 0.312, 0.316, 0.32, 0.324, 0.328, 0.332, 0.336, 0.34, 0.344, 0.348, 0.352, 0.356, 0.36, 0.364, 0.368, 0.372, 0.376, 0.38, 0.384, 0.388, 0.392, 0.396, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.7, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.8, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.9, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.0, 1.025, 1.05, 1.075, 1.1, 1.125, 1.15, 1.175, 1.2, 1.225, 1.25, 1.275, 1.3, 1.325, 1.35, 1.375, 1.4, 1.425, 1.45, 1.475, 1.5, 1.525, 1.55, 1.575, 1.6, 1.625, 1.65, 1.675, 1.7, 1.725, 1.75, 1.775, 1.8, 1.825, 1.85, 1.875, 1.9, 1.925, 1.95, 1.975, 2.0, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3.0}, "Binning of DCA xy and z axis"}; + + } binsOptions; + + // Track Parameters + Configurable minITSnCls{"minITSnCls", 4.0f, "min number of ITS clusters"}; + Configurable minTPCnClsFound{"minTPCnClsFound", 80.0f, "min number of found TPC clusters"}; + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 80.0f, "min number of TPC crossed rows"}; + Configurable minTpcNcrossedRowsOverFindable{"minTpcNcrossedRowsOverFindable", 0.8, "crossed rows/findable"}; + Configurable maxChi2TPC{"maxChi2TPC", 4.0f, "max chi2 per cluster TPC"}; + Configurable maxChi2ITS{"maxChi2ITS", 36.0f, "max chi2 per cluster ITS"}; + Configurable etaMin{"etaMin", -0.8f, "eta min"}; + Configurable etaMax{"etaMax", +0.8f, "eta max"}; + Configurable ptMinV0Proton{"ptMinV0Proton", 0.3f, "pt min of proton from V0"}; + Configurable ptMaxV0Proton{"ptMaxV0Proton", 10.0f, "pt max of proton from V0"}; + Configurable ptMinV0Pion{"ptMinV0Pion", 0.1f, "pt min of pion from V0"}; + Configurable ptMaxV0Pion{"ptMaxV0Pion", 1.5f, "pt max of pion from V0"}; + Configurable ptMinK0Pion{"ptMinK0Pion", 0.3f, "pt min of pion from K0"}; + Configurable ptMaxK0Pion{"ptMaxK0Pion", 10.0f, "pt max of pion from K0"}; + Configurable nsigmaTPCmin{"nsigmaTPCmin", -3.0f, "Minimum nsigma TPC"}; + Configurable nsigmaTPCmax{"nsigmaTPCmax", +3.0f, "Maximum nsigma TPC"}; + Configurable nsigmaTOFmin{"nsigmaTOFmin", -3.0f, "Minimum nsigma TOF"}; + Configurable nsigmaTOFmax{"nsigmaTOFmax", +3.0f, "Maximum nsigma TOF"}; + Configurable nsigmaTOFminPionMC{"nsigmaTOFminPionMC", -6.0f, "Minimum nsigma TOF for pion in MC"}; + Configurable nsigmaTOFmaxPionMC{"nsigmaTOFmaxPionMC", +6.0f, "Maximum nsigma TOF for pion in MC"}; + Configurable dcaxyMax{"dcaxyMax", 0.1f, "Maximum DCAxy to primary vertex"}; + Configurable dcazMax{"dcazMax", 0.1f, "Maximum DCAz to primary vertex"}; + Configurable requireITS{"requireITS", false, "require ITS hit"}; + Configurable requireTOF{"requireTOF", false, "require TOF hit"}; + + // V0 Parameters + Configurable minimumV0Radius{"minimumV0Radius", 0.5f, "Minimum V0 Radius"}; + Configurable maximumV0Radius{"maximumV0Radius", 40.0f, "Maximum V0 Radius"}; + Configurable dcanegtoPVmin{"dcanegtoPVmin", 0.1f, "Minimum DCA Neg To PV"}; + Configurable dcapostoPVmin{"dcapostoPVmin", 0.1f, "Minimum DCA Pos To PV"}; + Configurable v0cospaMin{"v0cospaMin", 0.99f, "Minimum V0 CosPA"}; + Configurable dcaV0DaughtersMax{"dcaV0DaughtersMax", 0.5f, "Maximum DCA Daughters"}; + + // Cascade Parameters + Configurable minimumCascRadius{"minimumCascRadius", 0.1f, "Minimum Cascade Radius"}; + Configurable maximumCascRadius{"maximumCascRadius", 40.0f, "Maximum Cascade Radius"}; + Configurable casccospaMin{"casccospaMin", 0.99f, "Minimum Cascade CosPA"}; + Configurable dcabachtopvMin{"dcabachtopvMin", 0.1f, "Minimum DCA bachelor to PV"}; + Configurable dcaV0topvMin{"dcaV0topvMin", 0.1f, "Minimum DCA V0 to PV"}; + Configurable dcaCascDaughtersMax{"dcaCascDaughtersMax", 0.5f, "Maximum DCA Daughters"}; + + // Re-weighting + Configurable applyReweighting{"applyReweighting", true, "apply reweighting"}; + Configurable urlToCcdb{"urlToCcdb", "http://alice-ccdb.cern.ch", "url of the personal ccdb"}; + Configurable pathToFile{"pathToFile", "", "path to file with reweighting"}; + Configurable histoNameWeightPiplusJet{"histoNameWeightPiplusJet", "", "reweighting histogram: Pi Plus in jet"}; + Configurable histoNameWeightPiplusUe{"histoNameWeightPiplusUe", "", "reweighting histogram: Pi Plus in ue"}; + Configurable histoNameWeightPiminusJet{"histoNameWeightPiminusJet", "", "reweighting histogram: Pi Minus in jet"}; + Configurable histoNameWeightPiminusUe{"histoNameWeightPiminusUe", "", "reweighting histogram: Pi Minus in ue"}; + Configurable histoNameWeightK0Jet{"histoNameWeightK0Jet", "", "reweighting histogram: K0 in jet"}; + Configurable histoNameWeightK0Ue{"histoNameWeightK0Ue", "", "reweighting histogram: K0 in ue"}; + Configurable histoNameWeightLambdaJet{"histoNameWeightLambdaJet", "", "reweighting histogram: lambda in jet"}; + Configurable histoNameWeightLambdaUe{"histoNameWeightLambdaUe", "", "reweighting histogram: lambda in ue"}; + Configurable histoNameWeightAntilambdaJet{"histoNameWeightAntilambdaJet", "", "reweighting histogram: antilambda in jet"}; + Configurable histoNameWeightAntilambdaUe{"histoNameWeightAntilambdaUe", "", "reweighting histogram: antilambda in ue"}; + Configurable histoNameWeightsXiInJet{"histoNameWeightsXiInJet", "", "reweighting histogram: xi in jet"}; + Configurable histoNameWeightsXiInUe{"histoNameWeightsXiInUe", "", "reweighting histogram: xi in ue"}; + Configurable histoNameWeightsAntiXiInJet{"histoNameWeightsAntiXiInJet", "", "reweighting histogram: antixi in jet"}; + Configurable histoNameWeightsAntiXiInUe{"histoNameWeightsAntiXiInUe", "", "reweighting histogram: antixi in ue"}; + + // Two-dimensional weights + TH2F* twodWeightsPiplusJet = nullptr; + TH2F* twodWeightsPiplusUe = nullptr; + TH2F* twodWeightsPiminusJet = nullptr; + TH2F* twodWeightsPiminusUe = nullptr; + TH2F* twodWeightsK0Jet; + TH2F* twodWeightsK0Ue; + TH2F* twodWeightsLambdaJet; + TH2F* twodWeightsLambdaUe; + TH2F* twodWeightsAntilambdaJet; + TH2F* twodWeightsAntilambdaUe; + TH1F* weightsXiInJet; + TH1F* weightsXiInUe; + TH1F* weightsAntiXiInJet; + TH1F* weightsAntiXiInUe; + + // List of Particles + enum Option { KZeroLambda, + CascadePart, + ChargedPions, + ChargedKaon, + ProtonAntiproton }; + + // Jet background subtraction + JetBkgSubUtils backgroundSub; + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (cfgSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), "fOmega"); + } + } + + void init(InitContext const&) + { + if (cfgSkimmedProcessing) { + zorroSummary.setObject(zorro.getZorroSummary()); + } + + ccdb->setURL(urlToCcdb.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + ccdb->setFatalWhenNull(false); + + if (applyReweighting) { + getReweightingHistograms(ccdb); + } else { + twodWeightsK0Jet = nullptr; + twodWeightsK0Ue = nullptr; + twodWeightsLambdaJet = nullptr; + twodWeightsLambdaUe = nullptr; + twodWeightsAntilambdaJet = nullptr; + twodWeightsAntilambdaUe = nullptr; + weightsXiInJet = nullptr; + weightsXiInUe = nullptr; + weightsAntiXiInJet = nullptr; + weightsAntiXiInUe = nullptr; + } + + // Event Counters + if (doprocessData) { + registryData.add("number_of_events_data", "number of events in data", HistType::kTH1D, {{20, 0, 20, "Event Cuts"}}); + registryData.add("number_of_events_vsmultiplicity", "number of events in data vs multiplicity", HistType::kTH1D, {{101, 0, 101, "Multiplicity percentile"}}); + } + + if (doprocessMCefficiency) { + registryMC.add("number_of_events_mc", "number of events in mc", HistType::kTH1D, {{10, 0, 10, "Event Cuts"}}); + } + + // QC Histograms + registryQC.add("deltaEtadeltaPhiJet", "deltaEtadeltaPhiJet", HistType::kTH2F, {{200, -0.5, 0.5, "#Delta#eta"}, {200, 0, o2::constants::math::PIHalf, "#Delta#phi"}}); + registryQC.add("deltaEtadeltaPhi_ue", "deltaEtadeltaPhi_ue", HistType::kTH2F, {{200, -0.5, 0.5, "#Delta#eta"}, {200, 0, o2::constants::math::PIHalf, "#Delta#phi"}}); + registryQC.add("NchJetPlusUE", "NchJetPlusUE", HistType::kTH1F, {{100, 0, 100, "#it{N}_{ch}"}}); + registryQC.add("NchJet", "NchJet", HistType::kTH1F, {{100, 0, 100, "#it{N}_{ch}"}}); + registryQC.add("NchUE", "NchUE", HistType::kTH1F, {{100, 0, 100, "#it{N}_{ch}"}}); + registryQC.add("sumPtJetPlusUE", "sumPtJetPlusUE", HistType::kTH1F, {{500, 0, 50, "#it{p}_{T} (GeV/#it{c})"}}); + registryQC.add("sumPtJet", "sumPtJet", HistType::kTH1F, {{500, 0, 50, "#it{p}_{T} (GeV/#it{c})"}}); + registryQC.add("sumPtUE", "sumPtUE", HistType::kTH1F, {{500, 0, 50, "#it{p}_{T} (GeV/#it{c})"}}); + registryQC.add("nJets_found", "nJets_found", HistType::kTH1F, {{10, 0, 10, "#it{n}_{Jet}"}}); + registryQC.add("nJets_selected", "nJets_selected", HistType::kTH1F, {{10, 0, 10, "#it{n}_{Jet}"}}); + registryQC.add("dcaxy_vs_pt", "dcaxy_vs_pt", HistType::kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{xy} (cm)"}}); + registryQC.add("dcaz_vs_pt", "dcaz_vs_pt", HistType::kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {2000, -0.05, 0.05, "DCA_{z} (cm)"}}); + registryQC.add("jet_jet_overlaps", "jet_jet_overlaps", HistType::kTH2F, {{20, 0.0, 20.0, "#it{n}_{jet}"}, {200, 0.0, 200.0, "#it{n}_{overlaps}"}}); + registryQC.add("jet_ue_overlaps", "jet_ue_overlaps", HistType::kTH2F, {{20, 0.0, 20.0, "#it{n}_{jet}"}, {200, 0.0, 200.0, "#it{n}_{overlaps}"}}); + registryQC.add("ue_ue_overlaps", "ue_ue_overlaps", HistType::kTH2F, {{20, 0.0, 20.0, "#it{n}_{jet}"}, {200, 0.0, 200.0, "#it{n}_{overlaps}"}}); + registryQC.add("tot_overlaps", "tot_overlaps", HistType::kTH2F, {{20, 0.0, 20.0, "#it{n}_{jet}"}, {200, 0.0, 200.0, "#it{n}_{overlaps}"}}); + registryQC.add("survivedK0", "survivedK0", HistType::kTH1F, {{20, 0, 20, "step"}}); + + // Multiplicity Binning + std::vector multBinning = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}; + AxisSpec multAxis = {multBinning, "FT0C percentile"}; + const AxisSpec etaAxis{18, -0.9, 0.9, "#eta"}; + const AxisSpec ptAxisPi{binsOptions.binsPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec ptAxis{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec nsigmaTOFAxis{200, -10, 10, "n#sigma_{TOF}"}; + const AxisSpec nsigmaTPCAxis{200, -10, 10, "n#sigma_{TPC}"}; + const AxisSpec dcaAxis{binsOptions.binsDca, "DCA_{xy} (cm)"}; + const AxisSpec invMassK0sAxis{200, 0.44, 0.56, "m_{#pi#pi} (GeV/#it{c}^{2})"}; + const AxisSpec invMassLambdaAxis{200, 1.09, 1.14, "m_{p#pi} (GeV/#it{c}^{2})"}; + const AxisSpec invMassXiAxis{200, 1.28, 1.36, "m_{p#pi#pi} (GeV/#it{c}^{2})"}; + const AxisSpec invMassOmegaAxis{200, 1.63, 1.71, "m_{p#piK} (GeV/#it{c}^{2})"}; + + // Histograms for pions (data) + if (doprocessData || doprocessK0s) { + switch (particleOfInterest) { + case KZeroLambda: + // Histograms for lambda (data) + registryData.add("Lambda_in_jet", "Lambda_in_jet", HistType::kTH3F, {multBinning, ptAxis, invMassLambdaAxis}); + registryData.add("AntiLambda_in_jet", "AntiLambda_in_jet", HistType::kTH3F, {multBinning, ptAxis, invMassLambdaAxis}); + registryData.add("Lambda_in_ue", "Lambda_in_ue", HistType::kTH3F, {multBinning, ptAxis, invMassLambdaAxis}); + registryData.add("AntiLambda_in_ue", "AntiLambda_in_ue", HistType::kTH3F, {multBinning, ptAxis, invMassLambdaAxis}); + // Histograms for K0s (data) + registryData.add("K0s_in_jet", "K0s_in_jet", HistType::kTH3F, {multBinning, ptAxis, invMassK0sAxis}); + registryData.add("K0s_in_ue", "K0s_in_ue", HistType::kTH3F, {multBinning, ptAxis, invMassK0sAxis}); + break; + case CascadePart: + // Histograms for xi (data) + registryData.add("XiPos_in_jet", "XiPos_in_jet", HistType::kTH3F, {multBinning, ptAxis, invMassXiAxis}); + registryData.add("XiPos_in_ue", "XiPos_in_ue", HistType::kTH3F, {multBinning, ptAxis, invMassXiAxis}); + registryData.add("XiNeg_in_jet", "XiNeg_in_jet", HistType::kTH3F, {multBinning, ptAxis, invMassXiAxis}); + registryData.add("XiNeg_in_ue", "XiNeg_in_ue", HistType::kTH3F, {multBinning, ptAxis, invMassXiAxis}); + // Histograms for omega (data) + registryData.add("OmegaPos_in_jet", "OmegaPos_in_jet", HistType::kTH3F, {multBinning, ptAxis, invMassOmegaAxis}); + registryData.add("OmegaPos_in_ue", "OmegaPos_in_ue", HistType::kTH3F, {multBinning, ptAxis, invMassOmegaAxis}); + registryData.add("OmegaNeg_in_jet", "OmegaNeg_in_jet", HistType::kTH3F, {multBinning, ptAxis, invMassOmegaAxis}); + registryData.add("OmegaNeg_in_ue", "OmegaNeg_in_ue", HistType::kTH3F, {multBinning, ptAxis, invMassOmegaAxis}); + break; + case ChargedPions: + registryData.add("piplus_tpc_in_jet", "piplus_tpc_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTPCAxis}); + registryData.add("piplus_tof_in_jet", "piplus_tof_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTOFAxis}); + registryData.add("piplus_tpc_in_ue", "piplus_tpc_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTPCAxis}); + registryData.add("piplus_tof_in_ue", "piplus_tof_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTOFAxis}); + registryData.add("piminus_tpc_in_jet", "piminus_tpc_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTPCAxis}); + registryData.add("piminus_tof_in_jet", "piminus_tof_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTOFAxis}); + registryData.add("piminus_tpc_in_ue", "piminus_tpc_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTPCAxis}); + registryData.add("piminus_tof_in_ue", "piminus_tof_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTOFAxis}); + registryData.add("piplus_dcaxy_in_jet", "piplus_dcaxy_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, dcaAxis}); + registryData.add("piplus_dcaxy_in_ue", "piplus_dcaxy_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, dcaAxis}); + registryData.add("piminus_dcaxy_in_jet", "piminus_dcaxy_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, dcaAxis}); + registryData.add("piminus_dcaxy_in_ue", "piminus_dcaxy_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, dcaAxis}); + break; + case ChargedKaon: // Here we keep the name but just change the title to avoid rewriting everything + registryData.add("piplus_tpc_in_jet", "kaplus_tpc_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTPCAxis}); + registryData.add("piplus_tof_in_jet", "kaplus_tof_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTOFAxis}); + registryData.add("piplus_tpc_in_ue", "kaplus_tpc_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTPCAxis}); + registryData.add("piplus_tof_in_ue", "kaplus_tof_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTOFAxis}); + registryData.add("piminus_tpc_in_jet", "kaminus_tpc_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTPCAxis}); + registryData.add("piminus_tof_in_jet", "kaminus_tof_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTOFAxis}); + registryData.add("piminus_tpc_in_ue", "kaminus_tpc_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTPCAxis}); + registryData.add("piminus_tof_in_ue", "kaminus_tof_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTOFAxis}); + registryData.add("piplus_dcaxy_in_jet", "kaplus_dcaxy_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, dcaAxis}); + registryData.add("piplus_dcaxy_in_ue", "kaplus_dcaxy_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, dcaAxis}); + registryData.add("piminus_dcaxy_in_jet", "kaminus_dcaxy_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, dcaAxis}); + registryData.add("piminus_dcaxy_in_ue", "kaminus_dcaxy_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, dcaAxis}); + break; + case ProtonAntiproton: // Here we keep the name but just change the title to avoid rewriting everything + registryData.add("piplus_tpc_in_jet", "prplus_tpc_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTPCAxis}); + registryData.add("piplus_tof_in_jet", "prplus_tof_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTOFAxis}); + registryData.add("piplus_tpc_in_ue", "prplus_tpc_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTPCAxis}); + registryData.add("piplus_tof_in_ue", "prplus_tof_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTOFAxis}); + registryData.add("piminus_tpc_in_jet", "prminus_tpc_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTPCAxis}); + registryData.add("piminus_tof_in_jet", "prminus_tof_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTOFAxis}); + registryData.add("piminus_tpc_in_ue", "prminus_tpc_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTPCAxis}); + registryData.add("piminus_tof_in_ue", "prminus_tof_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, nsigmaTOFAxis}); + registryData.add("piplus_dcaxy_in_jet", "prplus_dcaxy_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, dcaAxis}); + registryData.add("piplus_dcaxy_in_ue", "prplus_dcaxy_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, dcaAxis}); + registryData.add("piminus_dcaxy_in_jet", "prminus_dcaxy_in_jet", HistType::kTH3F, {multBinning, ptAxisPi, dcaAxis}); + registryData.add("piminus_dcaxy_in_ue", "prminus_dcaxy_in_ue", HistType::kTH3F, {multBinning, ptAxisPi, dcaAxis}); + break; + default: + LOG(fatal) << "Cannot interpret particle " << particleOfInterest; + break; + } + } + + // Histograms for efficiency (generated) + if (doprocessMCefficiency) { + registryMC.add("K0s_generated_jet", "K0s_generated_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("K0s_generated_ue", "K0s_generated_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("Lambda_generated_jet", "Lambda_generated_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("Lambda_generated_ue", "Lambda_generated_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("AntiLambda_generated_jet", "AntiLambda_generated_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("AntiLambda_generated_ue", "AntiLambda_generated_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("XiPos_generated", "XiPos_generated", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("XiNeg_generated", "XiNeg_generated", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaPos_generated", "OmegaPos_generated", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaNeg_generated", "OmegaNeg_generated", HistType::kTH2F, {multBinning, ptAxis}); + + // Histograms for efficiency (reconstructed) + registryMC.add("K0s_reconstructed_jet", "K0s_reconstructed_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("K0s_reconstructed_ue", "K0s_reconstructed_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("Lambda_reconstructed_jet", "Lambda_reconstructed_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("Lambda_reconstructed_ue", "Lambda_reconstructed_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("AntiLambda_reconstructed_jet", "AntiLambda_reconstructed_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("AntiLambda_reconstructed_ue", "AntiLambda_reconstructed_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("XiPos_reconstructed", "XiPos_reconstructed", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("XiNeg_reconstructed", "XiNeg_reconstructed", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaPos_reconstructed", "OmegaPos_reconstructed", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaNeg_reconstructed", "OmegaNeg_reconstructed", HistType::kTH2F, {multBinning, ptAxis}); + + // Histograms for secondary hadrons + registryMC.add("K0s_reconstructed_incl", "K0s_reconstructed_incl", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("Lambda_reconstructed_incl", "Lambda_reconstructed_incl", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("AntiLambda_reconstructed_incl", "AntiLambda_reconstructed_incl", HistType::kTH2F, {multBinning, ptAxis}); + + // Histograms for secondary lambda in jet and UE + registryMC.add("Secondary_Lambda_InJet", "Secondary_Lambda_InJet", HistType::kTH1F, {ptAxis}); + registryMC.add("Secondary_Lambda_InUe", "Secondary_Lambda_InUe", HistType::kTH1F, {ptAxis}); + registryMC.add("Secondary_AntiLambda_InJet", "Secondary_AntiLambda_InJet", HistType::kTH1F, {ptAxis}); + registryMC.add("Secondary_AntiLambda_InUe", "Secondary_AntiLambda_InUe", HistType::kTH1F, {ptAxis}); + + // Histograms for 2d reweighting (pion) + registryMC.add("mc_pi_plus_eta_pt/jet", "", HistType::kTH2F, {ptAxisPi, etaAxis}); + registryMC.addClone("mc_pi_plus_eta_pt/jet", "mc_pi_plus_eta_pt/ue"); + registryMC.addClone("mc_pi_plus_eta_pt/jet", "mc_pi_plus_eta_pt/pythia"); + + registryMC.addClone("mc_pi_plus_eta_pt/", "mc_pi_minus_eta_pt/"); + + registryMC.addClone("mc_pi_plus_eta_pt/", "mc_ka_plus_eta_pt/"); + registryMC.addClone("mc_pi_minus_eta_pt/", "mc_ka_minus_eta_pt/"); + + registryMC.addClone("mc_pi_plus_eta_pt/", "mc_pr_plus_eta_pt/"); + registryMC.addClone("mc_pi_minus_eta_pt/", "mc_pr_minus_eta_pt/"); + + // Histograms for 2d reweighting (K0s) + registryMC.add("K0s_eta_pt_jet", "K0s_eta_pt_jet", HistType::kTH2F, {ptAxis, etaAxis}); + registryMC.add("K0s_eta_pt_ue", "K0s_eta_pt_ue", HistType::kTH2F, {ptAxis, etaAxis}); + registryMC.add("K0s_eta_pt_pythia", "K0s_eta_pt_pythia", HistType::kTH2F, {ptAxis, etaAxis}); + + // Histograms for 2d reweighting (Lambda) + registryMC.add("Lambda_eta_pt_jet", "Lambda_eta_pt_jet", HistType::kTH2F, {ptAxis, etaAxis}); + registryMC.add("Lambda_eta_pt_ue", "Lambda_eta_pt_ue", HistType::kTH2F, {ptAxis, etaAxis}); + registryMC.add("Lambda_eta_pt_pythia", "Lambda_eta_pt_pythia", HistType::kTH2F, {ptAxis, etaAxis}); + registryMC.add("AntiLambda_eta_pt_jet", "AntiLambda_eta_pt_jet", HistType::kTH2F, {ptAxis, etaAxis}); + registryMC.add("AntiLambda_eta_pt_ue", "AntiLambda_eta_pt_ue", HistType::kTH2F, {ptAxis, etaAxis}); + registryMC.add("AntiLambda_eta_pt_pythia", "AntiLambda_eta_pt_pythia", HistType::kTH2F, {ptAxis, etaAxis}); + + // Histograms for 2d reweighting (Xi) + registryMC.add("Xi_eta_pt_jet", "Xi_eta_pt_jet", HistType::kTH2F, {ptAxis, etaAxis}); + registryMC.add("Xi_eta_pt_ue", "Xi_eta_pt_ue", HistType::kTH2F, {ptAxis, etaAxis}); + registryMC.add("Xi_eta_pt_pythia", "Xi_eta_pt_pythia", HistType::kTH2F, {ptAxis, etaAxis}); + registryMC.add("AntiXi_eta_pt_jet", "AntiXi_eta_pt_jet", HistType::kTH2F, {ptAxis, etaAxis}); + registryMC.add("AntiXi_eta_pt_ue", "AntiXi_eta_pt_ue", HistType::kTH2F, {ptAxis, etaAxis}); + registryMC.add("AntiXi_eta_pt_pythia", "AntiXi_eta_pt_pythia", HistType::kTH2F, {ptAxis, etaAxis}); + + // Histograms for 2d reweighting (Omega) + registryMC.add("Omega_eta_pt_jet", "Omega_eta_pt_jet", HistType::kTH2F, {ptAxis, etaAxis}); + registryMC.add("Omega_eta_pt_ue", "Omega_eta_pt_ue", HistType::kTH2F, {ptAxis, etaAxis}); + registryMC.add("Omega_eta_pt_pythia", "Omega_eta_pt_pythia", HistType::kTH2F, {ptAxis, etaAxis}); + registryMC.add("AntiOmega_eta_pt_jet", "AntiOmega_eta_pt_jet", HistType::kTH2F, {ptAxis, etaAxis}); + registryMC.add("AntiOmega_eta_pt_ue", "AntiOmega_eta_pt_ue", HistType::kTH2F, {ptAxis, etaAxis}); + registryMC.add("AntiOmega_eta_pt_pythia", "AntiOmega_eta_pt_pythia", HistType::kTH2F, {ptAxis, etaAxis}); + + // Histograms for efficiency (pions) + registryMC.add("mc_pi_plus/in_jet/gen", "", HistType::kTH2F, {multBinning, ptAxisPi}); + registryMC.addClone("mc_pi_plus/in_jet/gen", "mc_pi_plus/in_jet/rec_tpc"); + registryMC.addClone("mc_pi_plus/in_jet/gen", "mc_pi_plus/in_jet/rec_tof"); + registryMC.addClone("mc_pi_plus/in_jet/", "mc_pi_plus/in_ue/"); + + registryMC.addClone("mc_pi_plus/", "mc_pi_minus/"); + + // Histograms for efficiency (kaons) + registryMC.addClone("mc_pi_plus/", "mc_ka_plus/"); + registryMC.addClone("mc_pi_minus/", "mc_ka_minus/"); + + // Histograms for efficiency (protons) + registryMC.addClone("mc_pi_plus/", "mc_pr_plus/"); + registryMC.addClone("mc_pi_minus/", "mc_pr_minus/"); + + // MC Templates + registryMC.add("pi_plus_dcaxy/prm", "", HistType::kTH3F, {multBinning, ptAxisPi, dcaAxis}); + registryMC.addClone("pi_plus_dcaxy/prm", "pi_plus_dcaxy/sec"); + + registryMC.addClone("pi_plus_dcaxy/", "pi_minus_dcaxy/"); + + registryMC.addClone("pi_plus_dcaxy/", "kaplus_dcaxy/"); + registryMC.addClone("pi_minus_dcaxy/", "kaminus_dcaxy/"); + + registryMC.addClone("pi_plus_dcaxy/", "prplus_dcaxy/"); + registryMC.addClone("pi_minus_dcaxy/", "prminus_dcaxy/"); + } + } + + void getPerpendicularAxis(TVector3 p, TVector3& u, double sign) + { + // initialization + double ux(0), uy(0), uz(0); + + // components of vector p + double px = p.X(); + double py = p.Y(); + double pz = p.Z(); + + // protection 1 + if (px == 0 && py != 0) { + uy = -(pz * pz) / py; + ux = sign * std::sqrt(py * py - (pz * pz * pz * pz) / (py * py)); + uz = pz; + u.SetXYZ(ux, uy, uz); + return; + } + + // protection 2 + if (py == 0 && px != 0) { + ux = -(pz * pz) / px; + uy = sign * std::sqrt(px * px - (pz * pz * pz * pz) / (px * px)); + uz = pz; + u.SetXYZ(ux, uy, uz); + return; + } + + // equation parameters + double a = px * px + py * py; + double b = 2.0 * px * pz * pz; + double c = pz * pz * pz * pz - py * py * py * py - px * px * py * py; + double delta = b * b - 4.0 * a * c; + + // protection agains delta<0 + if (delta < 0) { + return; + } + + // solutions + ux = (-b + sign * std::sqrt(delta)) / (2.0 * a); + uy = (-pz * pz - px * ux) / py; + uz = pz; + u.SetXYZ(ux, uy, uz); + return; + } + + double getDeltaPhi(double a1, double a2) + { + double deltaPhi(0); + double phi1 = TVector2::Phi_0_2pi(a1); + double phi2 = TVector2::Phi_0_2pi(a2); + double diff = std::fabs(phi1 - phi2); + + if (diff <= PI) + deltaPhi = diff; + if (diff > PI) + deltaPhi = TwoPI - diff; + + return deltaPhi; + } + + // ITS hit + template + bool hasITSHit(const TrackIts& track, int layer) + { + int ibit = layer - 1; + return (track.itsClusterMap() & (1 << ibit)); + } + + // Single-Track Selection for Particles inside Jets + template + bool passedTrackSelectionForJetReconstruction(const JetTrack& track) + { + const int minTpcCr = 70; + const double minCrFindable = 0.8; + const double maxChi2Tpc = 4.0; + const double maxChi2Its = 36.0; + const double maxPseudorapidity = 0.8; + const double minPtTrack = 0.1; + const double dcaxyMaxTrackPar0 = 0.0105; + const double dcaxyMaxTrackPar1 = 0.035; + const double dcaxyMaxTrackPar2 = 1.1; + const double dcazMaxTrack = 2.0; + + if (!track.hasITS()) + return false; + if ((!hasITSHit(track, 1)) && (!hasITSHit(track, 2)) && (!hasITSHit(track, 3))) + return false; + if (!track.hasTPC()) + return false; + if (track.tpcNClsCrossedRows() < minTpcCr) + return false; + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < minCrFindable) + return false; + if (track.tpcChi2NCl() > maxChi2Tpc) + return false; + if (track.itsChi2NCl() > maxChi2Its) + return false; + if (track.eta() < -maxPseudorapidity || track.eta() > maxPseudorapidity) + return false; + if (track.pt() < minPtTrack) + return false; + if (std::fabs(track.dcaXY()) > (dcaxyMaxTrackPar0 + dcaxyMaxTrackPar1 / std::pow(track.pt(), dcaxyMaxTrackPar2))) + return false; + if (std::fabs(track.dcaZ()) > dcazMaxTrack) + return false; + return true; + } + + template + bool passedTrackSelectionForPions(const pionTrack& track) + { + if (!track.hasITS()) + return false; + if (track.itsNCls() < minITSnCls) + return false; + if (!track.hasTPC()) + return false; + if (track.tpcNClsFound() < minTPCnClsFound) + return false; + if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < minTpcNcrossedRowsOverFindable) + return false; + if (track.tpcChi2NCl() > maxChi2TPC) + return false; + if (track.itsChi2NCl() > maxChi2ITS) + return false; + if (track.eta() < etaMin || track.eta() > etaMax) + return false; + if (std::fabs(track.dcaZ()) > dcazMax) + return false; + return true; + } + + // Lambda Selections + template + bool passedLambdaSelection(const Lambda& v0, const TrackPos& ptrack, const TrackNeg& ntrack) + { + // Single-Track Selections + if (!passedSingleTrackSelection(ptrack)) + return false; + if (!passedSingleTrackSelection(ntrack)) + return false; + + // Momentum of Lambda Daughters + TVector3 proton(v0.pxpos(), v0.pypos(), v0.pzpos()); + TVector3 pion(v0.pxneg(), v0.pyneg(), v0.pzneg()); + + if (proton.Pt() < ptMinV0Proton) + return false; + if (proton.Pt() > ptMaxV0Proton) + return false; + if (pion.Pt() < ptMinV0Pion) + return false; + if (pion.Pt() > ptMaxV0Pion) + return false; + + // V0 Selections + if (v0.v0cosPA() < v0cospaMin) + return false; + if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) + return false; + if (std::fabs(v0.dcaV0daughters()) > dcaV0DaughtersMax) + return false; + if (std::fabs(v0.dcapostopv()) < dcapostoPVmin) + return false; + if (std::fabs(v0.dcanegtopv()) < dcanegtoPVmin) + return false; + + // PID Selections (TPC) + if (ptrack.tpcNSigmaPr() < nsigmaTPCmin || ptrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + if (ntrack.tpcNSigmaPi() < nsigmaTPCmin || ntrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + + // PID Selections (TOF) + if (requireTOF) { + if (ptrack.tofNSigmaPr() < nsigmaTOFmin || ptrack.tofNSigmaPr() > nsigmaTOFmax) + return false; + if (ntrack.tofNSigmaPi() < nsigmaTOFmin || ntrack.tofNSigmaPi() > nsigmaTOFmax) + return false; + } + return true; + } + + // AntiLambda Selections + template + bool passedAntiLambdaSelection(const AntiLambda& v0, const TrackPos& ptrack, const TrackNeg& ntrack) + { + // Single-Track Selections + if (!passedSingleTrackSelection(ptrack)) + return false; + if (!passedSingleTrackSelection(ntrack)) + return false; + + // Momentum AntiLambda Daughters + TVector3 pion(v0.pxpos(), v0.pypos(), v0.pzpos()); + TVector3 proton(v0.pxneg(), v0.pyneg(), v0.pzneg()); + + if (proton.Pt() < ptMinV0Proton) + return false; + if (proton.Pt() > ptMaxV0Proton) + return false; + if (pion.Pt() < ptMinV0Pion) + return false; + if (pion.Pt() > ptMaxV0Pion) + return false; + + // V0 Selections + if (v0.v0cosPA() < v0cospaMin) + return false; + if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) + return false; + if (std::fabs(v0.dcaV0daughters()) > dcaV0DaughtersMax) + return false; + if (std::fabs(v0.dcapostopv()) < dcapostoPVmin) + return false; + if (std::fabs(v0.dcanegtopv()) < dcanegtoPVmin) + return false; + + // PID Selections (TPC) + if (ptrack.tpcNSigmaPi() < nsigmaTPCmin || ptrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + if (ntrack.tpcNSigmaPr() < nsigmaTPCmin || ntrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + + // PID Selections (TOF) + if (requireTOF) { + if (ptrack.tofNSigmaPi() < nsigmaTOFmin || ptrack.tofNSigmaPi() > nsigmaTOFmax) + return false; + if (ntrack.tofNSigmaPr() < nsigmaTOFmin || ntrack.tofNSigmaPr() > nsigmaTOFmax) + return false; + } + return true; + } + + // K0s Selections + template + bool passedK0ShortSelection(const K0short& v0, const TrackPos& ptrack, const TrackNeg& ntrack) + { + // Single-Track Selections + if (!passedSingleTrackSelection(ptrack)) + return false; + if (!passedSingleTrackSelection(ntrack)) + return false; + + // Momentum K0s Daughters + TVector3 pionPos(v0.pxpos(), v0.pypos(), v0.pzpos()); + TVector3 pionNeg(v0.pxneg(), v0.pyneg(), v0.pzneg()); + + if (pionPos.Pt() < ptMinK0Pion) + return false; + if (pionPos.Pt() > ptMaxK0Pion) + return false; + if (pionNeg.Pt() < ptMinK0Pion) + return false; + if (pionNeg.Pt() > ptMaxK0Pion) + return false; + + // V0 Selections + if (v0.v0cosPA() < v0cospaMin) + return false; + if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) + return false; + if (std::fabs(v0.dcaV0daughters()) > dcaV0DaughtersMax) + return false; + if (std::fabs(v0.dcapostopv()) < dcapostoPVmin) + return false; + if (std::fabs(v0.dcanegtopv()) < dcanegtoPVmin) + return false; + + // PID Selections (TPC) + if (ptrack.tpcNSigmaPi() < nsigmaTPCmin || ptrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + if (ntrack.tpcNSigmaPi() < nsigmaTPCmin || ntrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + + // PID Selections (TOF) + if (requireTOF) { + if (ptrack.tofNSigmaPi() < nsigmaTOFmin || ptrack.tofNSigmaPi() > nsigmaTOFmax) + return false; + if (ntrack.tofNSigmaPi() < nsigmaTOFmin || ntrack.tofNSigmaPi() > nsigmaTOFmax) + return false; + } + return true; + } + + // Xi Selections + template + bool passedXiSelection(const Xi& casc, const TrackPos& ptrack, const TrackNeg& ntrack, const TrackBac& btrack, const Coll& coll) + { + if (!passedSingleTrackSelection(ptrack)) + return false; + if (!passedSingleTrackSelection(ntrack)) + return false; + if (!passedSingleTrackSelection(btrack)) + return false; + + // Xi+ Selection (Xi+ -> antiL + pi+) + if (btrack.sign() > 0) { + if (ntrack.pt() < ptMinV0Proton) + return false; + if (ntrack.pt() > ptMaxV0Proton) + return false; + if (ptrack.pt() < ptMinV0Pion) + return false; + if (ptrack.pt() > ptMaxV0Pion) + return false; + + // PID Selections (TPC) + if (ntrack.tpcNSigmaPr() < nsigmaTPCmin || ntrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + if (ptrack.tpcNSigmaPi() < nsigmaTPCmin || ptrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + + // PID Selections (TOF) + if (requireTOF) { + if (ntrack.tofNSigmaPr() < nsigmaTOFmin || ntrack.tofNSigmaPr() > nsigmaTOFmax) + return false; + if (ptrack.tofNSigmaPi() < nsigmaTOFmin || ptrack.tofNSigmaPi() > nsigmaTOFmax) + return false; + } + } + + // Xi- Selection (Xi- -> L + pi-) + if (btrack.sign() < 0) { + if (ptrack.pt() < ptMinV0Proton) + return false; + if (ptrack.pt() > ptMaxV0Proton) + return false; + if (ntrack.pt() < ptMinV0Pion) + return false; + if (ntrack.pt() > ptMaxV0Pion) + return false; + + // PID Selections (TPC) + if (ptrack.tpcNSigmaPr() < nsigmaTPCmin || ptrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + if (ntrack.tpcNSigmaPi() < nsigmaTPCmin || ntrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + + // PID Selections (TOF) + if (requireTOF) { + if (ptrack.tofNSigmaPr() < nsigmaTOFmin || ptrack.tofNSigmaPr() > nsigmaTOFmax) + return false; + if (ntrack.tofNSigmaPi() < nsigmaTOFmin || ntrack.tofNSigmaPi() > nsigmaTOFmax) + return false; + } + } + + // V0 Selections + if (casc.v0cosPA(coll.posX(), coll.posY(), coll.posZ()) < v0cospaMin) + return false; + if (casc.v0radius() < minimumV0Radius || casc.v0radius() > maximumV0Radius) + return false; + if (std::fabs(casc.dcaV0daughters()) > dcaV0DaughtersMax) + return false; + if (std::fabs(casc.dcapostopv()) < dcapostoPVmin) + return false; + if (std::fabs(casc.dcanegtopv()) < dcanegtoPVmin) + return false; + + // Cascade Selections + if (casc.cascradius() < minimumCascRadius || casc.cascradius() > maximumCascRadius) + return false; + if (casc.casccosPA(coll.posX(), coll.posY(), coll.posZ()) < casccospaMin) + return false; + if (std::fabs(casc.dcabachtopv()) < dcabachtopvMin) + return false; + if (std::fabs(casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ())) < dcaV0topvMin) + return false; + if (std::fabs(casc.dcacascdaughters()) > dcaCascDaughtersMax) + return false; + + // PID Selection on bachelor + if (btrack.tpcNSigmaPi() < nsigmaTPCmin || btrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + + // PID Selections (TOF) + if (requireTOF) { + if (btrack.tofNSigmaPi() < nsigmaTOFmin || btrack.tofNSigmaPi() > nsigmaTOFmax) + return false; + } + return true; + } + + // Omega Selections + template + bool passedOmegaSelection(const Omega& casc, const TrackPos& ptrack, const TrackNeg& ntrack, const TrackBac& btrack, const Coll& coll) + { + if (!passedSingleTrackSelection(ptrack)) + return false; + if (!passedSingleTrackSelection(ntrack)) + return false; + if (!passedSingleTrackSelection(btrack)) + return false; + + // Omega+ Selection (Omega+ -> antiL + K+) + if (btrack.sign() > 0) { + if (ntrack.pt() < ptMinV0Proton) + return false; + if (ntrack.pt() > ptMaxV0Proton) + return false; + if (ptrack.pt() < ptMinV0Pion) + return false; + if (ptrack.pt() > ptMaxV0Pion) + return false; + + // PID Selections (TPC) + if (ntrack.tpcNSigmaPr() < nsigmaTPCmin || ntrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + if (ptrack.tpcNSigmaPi() < nsigmaTPCmin || ptrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + + // PID Selections (TOF) + if (requireTOF) { + if (ntrack.tofNSigmaPr() < nsigmaTOFmin || ntrack.tofNSigmaPr() > nsigmaTOFmax) + return false; + if (ptrack.tofNSigmaPi() < nsigmaTOFmin || ptrack.tofNSigmaPi() > nsigmaTOFmax) + return false; + } + } + + // Omega- Selection (Omega- -> L + K-) + if (btrack.sign() < 0) { + if (ptrack.pt() < ptMinV0Proton) + return false; + if (ptrack.pt() > ptMaxV0Proton) + return false; + if (ntrack.pt() < ptMinV0Pion) + return false; + if (ntrack.pt() > ptMaxV0Pion) + return false; + + // PID Selections (TPC) + if (ptrack.tpcNSigmaPr() < nsigmaTPCmin || ptrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + if (ntrack.tpcNSigmaPi() < nsigmaTPCmin || ntrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + + // PID Selections (TOF) + if (requireTOF) { + if (ptrack.tofNSigmaPr() < nsigmaTOFmin || ptrack.tofNSigmaPr() > nsigmaTOFmax) + return false; + if (ntrack.tofNSigmaPi() < nsigmaTOFmin || ntrack.tofNSigmaPi() > nsigmaTOFmax) + return false; + } + } + + // V0 Selections + if (casc.v0cosPA(coll.posX(), coll.posY(), coll.posZ()) < v0cospaMin) + return false; + if (casc.v0radius() < minimumV0Radius || casc.v0radius() > maximumV0Radius) + return false; + if (std::fabs(casc.dcaV0daughters()) > dcaV0DaughtersMax) + return false; + if (std::fabs(casc.dcapostopv()) < dcapostoPVmin) + return false; + if (std::fabs(casc.dcanegtopv()) < dcanegtoPVmin) + return false; + + // Cascade Selections + if (casc.cascradius() < minimumCascRadius || casc.cascradius() > maximumCascRadius) + return false; + if (casc.casccosPA(coll.posX(), coll.posY(), coll.posZ()) < casccospaMin) + return false; + if (std::fabs(casc.dcabachtopv()) < dcabachtopvMin) + return false; + if (std::fabs(casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ())) < dcaV0topvMin) + return false; + if (std::fabs(casc.dcacascdaughters()) > dcaCascDaughtersMax) + return false; + + // PID Selection on bachelor + if (btrack.tpcNSigmaKa() < nsigmaTPCmin || btrack.tpcNSigmaKa() > nsigmaTPCmax) + return false; + + // PID Selections (TOF) + if (requireTOF) { + if (btrack.tofNSigmaKa() < nsigmaTOFmin || btrack.tofNSigmaKa() > nsigmaTOFmax) + return false; + } + return true; + } + + // Single-Track Selection + template + bool passedSingleTrackSelection(const Track& track) + { + if (requireITS && (!track.hasITS())) + return false; + if (requireITS && track.itsNCls() < minITSnCls) + return false; + if (!track.hasTPC()) + return false; + if (track.tpcNClsFound() < minTPCnClsFound) + return false; + if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < minTpcNcrossedRowsOverFindable) + return false; + if (track.tpcChi2NCl() > maxChi2TPC) + return false; + if (track.eta() < etaMin || track.eta() > etaMax) + return false; + if (requireTOF && (!track.hasTOF())) + return false; + return true; + } + + // Pion Selection + template + bool isHighPurityPion(const pionTrack& track, const float nsigmaTPC, const float nsigmaTOF) + { + double nsigmaPi = 2.0; + double pThreshold = 0.6; + if (track.p() < pThreshold && std::fabs(nsigmaTPC) < nsigmaPi) + return true; + if (track.p() > pThreshold && std::fabs(nsigmaTPC) < nsigmaPi && std::fabs(nsigmaTOF) < nsigmaPi) + return true; + return false; + } + + double getCorrectedPt(double ptRec) + { + // to be developed + return ptRec; + } + + void getReweightingHistograms(o2::framework::Service const& ccdbObj) + { + auto getWeightHistoObj = [&](Configurable name, TH2F*& histo) { + if (name.value == "") { + LOG(info) << "Getting weight histogram for " << name.name << " from " << name.value; + histo = ccdbObj->get(name); + } + }; + + getWeightHistoObj(histoNameWeightPiplusJet, twodWeightsPiplusJet); + getWeightHistoObj(histoNameWeightPiplusUe, twodWeightsPiplusUe); + getWeightHistoObj(histoNameWeightPiminusJet, twodWeightsPiminusJet); + getWeightHistoObj(histoNameWeightPiminusUe, twodWeightsPiminusUe); + + TList* l = ccdbObj->get(pathToFile.value.c_str()); + if (!l) { + LOG(error) << "Could not open the file " << pathToFile.value; + return; + } + l->ls(); + + auto get2DWeightHisto = [&](Configurable name, TH2F*& histo) { + LOG(info) << "Looking for 2D weight histogram '" << name.value << "' for " << name.name; + if (name.value == "") { + LOG(info) << " -> Skipping"; + return; + } + histo = static_cast(l->FindObject(name.value.c_str())); + if (!histo) { + LOG(error) << "Could not open histogram '" << name.value << "'"; + return; + } + LOG(info) << "Opened histogram " << histo->ClassName() << " " << histo->GetName(); + }; + + get2DWeightHisto(histoNameWeightK0Jet, twodWeightsK0Jet); + get2DWeightHisto(histoNameWeightK0Ue, twodWeightsK0Ue); + get2DWeightHisto(histoNameWeightLambdaJet, twodWeightsLambdaJet); + get2DWeightHisto(histoNameWeightLambdaUe, twodWeightsLambdaUe); + get2DWeightHisto(histoNameWeightAntilambdaJet, twodWeightsAntilambdaJet); + get2DWeightHisto(histoNameWeightAntilambdaUe, twodWeightsAntilambdaUe); + + auto get1DWeightHisto = [&](Configurable name, TH1F*& histo) { + LOG(info) << "Looking for 1D weight histogram '" << name.value << "' for " << name.name; + if (name.value == "") { + LOG(info) << " -> Skipping"; + return; + } + histo = static_cast(l->FindObject(name.value.c_str())); + if (!histo) { + LOG(error) << "Could not open histogram '" << name.value << "'"; + return; + } + LOG(info) << "Opened histogram " << histo->ClassName() << " " << histo->GetName(); + }; + + // Secondary Lambda + get1DWeightHisto(histoNameWeightsXiInJet, weightsXiInJet); + get1DWeightHisto(histoNameWeightsXiInUe, weightsXiInUe); + get1DWeightHisto(histoNameWeightsAntiXiInJet, weightsAntiXiInJet); + get1DWeightHisto(histoNameWeightsAntiXiInUe, weightsAntiXiInUe); + } + + void processData(SelCollisions::iterator const& collision, + aod::V0Datas const& fullV0s, + aod::CascDataExt const& Cascades, + StrHadronDaughterTracks const& tracks) + { + // event counter: before event selection + registryData.fill(HIST("number_of_events_data"), 0.5); + + auto bc = collision.template bc_as(); + initCCDB(bc); + + if (cfgSkimmedProcessing && !zorro.isSelected(collision.template bc_as().globalBC())) { + return; + } + + // event selection + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + return; + + // event counter: after event selection + registryData.fill(HIST("number_of_events_data"), 1.5); + + // loop over reconstructed tracks + std::vector fjParticles; + for (auto const& track : tracks) { + + if (!passedTrackSelectionForJetReconstruction(track)) + continue; + + // 4-momentum representation of a particle + fastjet::PseudoJet fourMomentum(track.px(), track.py(), track.pz(), track.energy(MassPionCharged)); + fjParticles.emplace_back(fourMomentum); + } + + // reject empty events + if (fjParticles.size() < 1) + return; + registryData.fill(HIST("number_of_events_data"), 2.5); + + // cluster particles using the anti-kt algorithm + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); + fastjet::ClusterSequenceArea cs(fjParticles, jetDef, areaDef); + std::vector jets = fastjet::sorted_by_pt(cs.inclusive_jets()); + auto [rhoPerp, rhoMPerp] = backgroundSub.estimateRhoPerpCone(fjParticles, jets); + + // jet selection + bool isAtLeastOneJetSelected = false; + std::vector selectedJet; + std::vector ue1; + std::vector ue2; + + for (auto& jet : jets) { // o2-linter: disable=const-ref-in-for-loop (required by backgroundSub) + + // jet must be fully contained in the acceptance + if ((std::fabs(jet.eta()) + rJet) > (etaMax - deltaEtaEdge)) + continue; + + // jet pt must be larger than threshold + fastjet::PseudoJet jetMinusBkg = backgroundSub.doRhoAreaSub(jet, rhoPerp, rhoMPerp); + if (getCorrectedPt(jetMinusBkg.pt()) < minJetPt) + continue; + isAtLeastOneJetSelected = true; + + // perpendicular cone + // double coneRadius = std::sqrt(jet.area() / PI); + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + TVector3 ueAxis1(0, 0, 0); + TVector3 ueAxis2(0, 0, 0); + getPerpendicularAxis(jetAxis, ueAxis1, +1); + getPerpendicularAxis(jetAxis, ueAxis2, -1); + + selectedJet.emplace_back(jetAxis); + ue1.emplace_back(ueAxis1); + ue2.emplace_back(ueAxis2); + } + if (!isAtLeastOneJetSelected) + return; + registryData.fill(HIST("number_of_events_data"), 3.5); + + // Event multiplicity + const float multiplicity = collision.centFT0M(); + + registryData.fill(HIST("number_of_events_vsmultiplicity"), multiplicity); + + for (int i = 0; i < static_cast(selectedJet.size()); i++) { + + // KZeroLambda + if (particleOfInterest == Option::KZeroLambda) { + for (const auto& v0 : fullV0s) { + + const auto& pos = v0.posTrack_as(); + const auto& neg = v0.negTrack_as(); + TVector3 v0dir(v0.px(), v0.py(), v0.pz()); + + float deltaEtaJet = v0dir.Eta() - selectedJet[i].Eta(); + float deltaPhiJet = getDeltaPhi(v0dir.Phi(), selectedJet[i].Phi()); + float deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + float deltaEtaUe1 = v0dir.Eta() - ue1[i].Eta(); + float deltaPhiUe1 = getDeltaPhi(v0dir.Phi(), ue1[i].Phi()); + float deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + float deltaEtaUe2 = v0dir.Eta() - ue2[i].Eta(); + float deltaPhiUe2 = getDeltaPhi(v0dir.Phi(), ue2[i].Phi()); + float deltaRue2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + // K0s + if (passedK0ShortSelection(v0, pos, neg)) { + if (deltaRjet < rJet) { + registryData.fill(HIST("K0s_in_jet"), multiplicity, v0.pt(), v0.mK0Short()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryData.fill(HIST("K0s_in_ue"), multiplicity, v0.pt(), v0.mK0Short()); + } + } + // Lambda + if (passedLambdaSelection(v0, pos, neg)) { + if (deltaRjet < rJet) { + registryData.fill(HIST("Lambda_in_jet"), multiplicity, v0.pt(), v0.mLambda()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryData.fill(HIST("Lambda_in_ue"), multiplicity, v0.pt(), v0.mLambda()); + } + } + // AntiLambda + if (passedAntiLambdaSelection(v0, pos, neg)) { + if (deltaRjet < rJet) { + registryData.fill(HIST("AntiLambda_in_jet"), multiplicity, v0.pt(), v0.mAntiLambda()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryData.fill(HIST("AntiLambda_in_ue"), multiplicity, v0.pt(), v0.mAntiLambda()); + } + } + } + } + + // Cascades + if (particleOfInterest == Option::CascadePart) { + for (const auto& casc : Cascades) { + + auto bach = casc.bachelor_as(); + auto pos = casc.posTrack_as(); + auto neg = casc.negTrack_as(); + + TVector3 cascadeDir(casc.px(), casc.py(), casc.pz()); + float deltaEtaJet = cascadeDir.Eta() - selectedJet[i].Eta(); + float deltaPhiJet = getDeltaPhi(cascadeDir.Phi(), selectedJet[i].Phi()); + float deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + float deltaEtaUe1 = cascadeDir.Eta() - ue1[i].Eta(); + float deltaPhiUe1 = getDeltaPhi(cascadeDir.Phi(), ue1[i].Phi()); + float deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + float deltaEtaUe2 = cascadeDir.Eta() - ue2[i].Eta(); + float deltaPhiUe2 = getDeltaPhi(cascadeDir.Phi(), ue2[i].Phi()); + float deltaRue2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + // Xi+ + if (passedXiSelection(casc, pos, neg, bach, collision) && + bach.sign() > 0) { + if (deltaRjet < rJet) { + registryData.fill(HIST("XiPos_in_jet"), multiplicity, casc.pt(), casc.mXi()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryData.fill(HIST("XiPos_in_ue"), multiplicity, casc.pt(), casc.mXi()); + } + } + // Xi- + if (passedXiSelection(casc, pos, neg, bach, collision) && + bach.sign() < 0) { + if (deltaRjet < rJet) { + registryData.fill(HIST("XiNeg_in_jet"), multiplicity, casc.pt(), casc.mXi()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryData.fill(HIST("XiNeg_in_ue"), multiplicity, casc.pt(), casc.mXi()); + } + } + // Omega+ + if (passedOmegaSelection(casc, pos, neg, bach, collision) && + bach.sign() > 0) { + if (deltaRjet < rJet) { + registryData.fill(HIST("OmegaPos_in_jet"), multiplicity, casc.pt(), casc.mOmega()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryData.fill(HIST("OmegaPos_in_ue"), multiplicity, casc.pt(), casc.mOmega()); + } + } + // Omega- + if (passedOmegaSelection(casc, pos, neg, bach, collision) && + bach.sign() < 0) { + if (deltaRjet < rJet) { + registryData.fill(HIST("OmegaNeg_in_jet"), multiplicity, casc.pt(), casc.mOmega()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryData.fill(HIST("OmegaNeg_in_ue"), multiplicity, casc.pt(), casc.mOmega()); + } + } + } + } + + // Pions + if (particleOfInterest == Option::ChargedPions) { + for (const auto& track : tracks) { + + if (!passedTrackSelectionForPions(track)) + continue; + + TVector3 trackDir(track.px(), track.py(), track.pz()); + const float deltaEtaJet = trackDir.Eta() - selectedJet[i].Eta(); + const float deltaPhiJet = getDeltaPhi(trackDir.Phi(), selectedJet[i].Phi()); + const float deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + const float deltaEtaUe1 = trackDir.Eta() - ue1[i].Eta(); + const float deltaPhiUe1 = getDeltaPhi(trackDir.Phi(), ue1[i].Phi()); + const float deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + const float deltaEtaUe2 = trackDir.Eta() - ue2[i].Eta(); + const float deltaPhiUe2 = getDeltaPhi(trackDir.Phi(), ue2[i].Phi()); + const float deltaRue2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + float nsigmaTPC = 999.f; + float nsigmaTOF = 999.f; + switch (particleOfInterest) { + case Option::ChargedPions: + nsigmaTPC = track.tpcNSigmaPi(); + nsigmaTOF = track.tofNSigmaPi(); + break; + case Option::ChargedKaon: + nsigmaTPC = track.tpcNSigmaKa(); + nsigmaTOF = track.tofNSigmaKa(); + break; + case Option::ProtonAntiproton: + nsigmaTPC = track.tpcNSigmaPr(); + nsigmaTOF = track.tofNSigmaPr(); + break; + } + + bool isInJet = false; + bool isInUe = false; + if (deltaRjet < rJet) + isInJet = true; + if (deltaRue1 < rJet || deltaRue2 < rJet) + isInUe = true; + + if (isHighPurityPion(track, nsigmaTPC, nsigmaTOF)) { + if (track.sign() > 0) { + if (isInJet) + registryData.fill(HIST("piplus_dcaxy_in_jet"), multiplicity, track.pt(), track.dcaXY()); + if (isInUe) + registryData.fill(HIST("piplus_dcaxy_in_ue"), multiplicity, track.pt(), track.dcaXY()); + } else { + if (isInJet) + registryData.fill(HIST("piminus_dcaxy_in_jet"), multiplicity, track.pt(), track.dcaXY()); + if (isInUe) + registryData.fill(HIST("piminus_dcaxy_in_ue"), multiplicity, track.pt(), track.dcaXY()); + } + } + + // DCAxy Selection + if (std::fabs(track.dcaXY()) > dcaxyMax) + continue; + + // TPC + switch (track.sign()) { + case 1: + if (isInJet) { + registryData.fill(HIST("piplus_tpc_in_jet"), multiplicity, track.pt(), nsigmaTPC); + } + if (isInUe) { + registryData.fill(HIST("piplus_tpc_in_ue"), multiplicity, track.pt(), nsigmaTPC); + } + break; + case -1: + if (isInJet) { + registryData.fill(HIST("piminus_tpc_in_jet"), multiplicity, track.pt(), nsigmaTPC); + } + if (isInUe) { + registryData.fill(HIST("piminus_tpc_in_ue"), multiplicity, track.pt(), nsigmaTPC); + } + break; + default: + LOG(fatal) << "Error in the charge"; + } + if (nsigmaTPC < nsigmaTPCmin || nsigmaTPC > nsigmaTPCmax) + continue; + if (!track.hasTOF()) + continue; + + // TOF + switch (track.sign()) { + case 1: + if (isInJet) { + registryData.fill(HIST("piplus_tof_in_jet"), multiplicity, track.pt(), nsigmaTOF); + } + if (isInUe) { + registryData.fill(HIST("piplus_tof_in_ue"), multiplicity, track.pt(), nsigmaTOF); + } + break; + case -1: + if (isInJet) { + registryData.fill(HIST("piminus_tof_in_jet"), multiplicity, track.pt(), nsigmaTOF); + } + if (isInUe) { + registryData.fill(HIST("piminus_tof_in_ue"), multiplicity, track.pt(), nsigmaTOF); + } + break; + default: + LOG(fatal) << "Error in the charge"; + } + } + } + } + } + PROCESS_SWITCH(StrangenessInJets, processData, "Process data", true); + + void processK0s(SelCollisions::iterator const& collision, aod::V0Datas const& fullV0s, StrHadronDaughterTracks const&) + { + registryData.fill(HIST("number_of_events_data"), 10.5); + if (!collision.sel8()) + return; + registryData.fill(HIST("number_of_events_data"), 11.5); + if (std::fabs(collision.posZ()) > zVtx) + return; + registryData.fill(HIST("number_of_events_data"), 12.5); + + for (const auto& v0 : fullV0s) { + const auto& ptrack = v0.posTrack_as(); + const auto& ntrack = v0.negTrack_as(); + + registryQC.fill(HIST("survivedK0"), 0.5); + + // Single-Track Selections + if (!passedSingleTrackSelection(ptrack)) + continue; + registryQC.fill(HIST("survivedK0"), 1.5); + + if (!passedSingleTrackSelection(ntrack)) + continue; + registryQC.fill(HIST("survivedK0"), 2.5); + + // Momentum K0s Daughters + TVector3 pionPos(v0.pxpos(), v0.pypos(), v0.pzpos()); + TVector3 pionNeg(v0.pxneg(), v0.pyneg(), v0.pzneg()); + + if (pionPos.Pt() < ptMinK0Pion) + continue; + registryQC.fill(HIST("survivedK0"), 3.5); + + if (pionPos.Pt() > ptMaxK0Pion) + continue; + registryQC.fill(HIST("survivedK0"), 4.5); + + if (pionNeg.Pt() < ptMinK0Pion) + continue; + registryQC.fill(HIST("survivedK0"), 5.5); + + if (pionNeg.Pt() > ptMaxK0Pion) + continue; + registryQC.fill(HIST("survivedK0"), 6.5); + + // V0 Selections + if (v0.v0cosPA() < v0cospaMin) + continue; + registryQC.fill(HIST("survivedK0"), 7.5); + + if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) + continue; + registryQC.fill(HIST("survivedK0"), 8.5); + + if (std::fabs(v0.dcaV0daughters()) > dcaV0DaughtersMax) + continue; + registryQC.fill(HIST("survivedK0"), 9.5); + + if (std::fabs(v0.dcapostopv()) < dcapostoPVmin) + continue; + registryQC.fill(HIST("survivedK0"), 10.5); + + if (std::fabs(v0.dcanegtopv()) < dcanegtoPVmin) + continue; + registryQC.fill(HIST("survivedK0"), 11.5); + + // PID Selections (TPC) + if (ptrack.tpcNSigmaPi() < nsigmaTPCmin || ptrack.tpcNSigmaPi() > nsigmaTPCmax) + continue; + registryQC.fill(HIST("survivedK0"), 12.5); + + if (ntrack.tpcNSigmaPi() < nsigmaTPCmin || ntrack.tpcNSigmaPi() > nsigmaTPCmax) + continue; + registryQC.fill(HIST("survivedK0"), 13.5); + + // PID Selections (TOF) + if (requireTOF) { + if (ptrack.tofNSigmaPi() < nsigmaTOFmin || ptrack.tofNSigmaPi() > nsigmaTOFmax) + continue; + registryQC.fill(HIST("survivedK0"), 14.5); + + if (ntrack.tofNSigmaPi() < nsigmaTOFmin || ntrack.tofNSigmaPi() > nsigmaTOFmax) + continue; + registryQC.fill(HIST("survivedK0"), 15.5); + } + } + + for (const auto& v0 : fullV0s) { + const auto& ptrack = v0.posTrack_as(); + const auto& ntrack = v0.negTrack_as(); + if (!passedK0ShortSelection(v0, ptrack, ntrack)) + continue; + registryQC.fill(HIST("survivedK0"), 16.5); + } + } + PROCESS_SWITCH(StrangenessInJets, processK0s, "Process K0s", false); + + Preslice perCollisionV0 = o2::aod::v0data::collisionId; + Preslice perCollisionCasc = o2::aod::cascade::collisionId; + Preslice perMCCollision = o2::aod::mcparticle::mcCollisionId; + Preslice perCollisionTrk = o2::aod::track::collisionId; + + void processMCefficiency(SimCollisions const& collisions, MCTracks const& mcTracks, aod::V0Datas const& fullV0s, aod::CascDataExt const& Cascades, const aod::McParticles& mcParticles) + { + for (const auto& collision : collisions) { + registryMC.fill(HIST("number_of_events_mc"), 0.5); + if (!collision.sel8()) + continue; + + registryMC.fill(HIST("number_of_events_mc"), 1.5); + if (std::fabs(collision.posZ()) > zVtx) + continue; + + registryMC.fill(HIST("number_of_events_mc"), 2.5); + float multiplicity = collision.centFT0M(); + + auto v0sPerColl = fullV0s.sliceBy(perCollisionV0, collision.globalIndex()); + auto cascPerColl = Cascades.sliceBy(perCollisionCasc, collision.globalIndex()); + auto mcParticlesPerColl = mcParticles.sliceBy(perMCCollision, collision.globalIndex()); + auto tracksPerColl = mcTracks.sliceBy(perCollisionTrk, collision.globalIndex()); + + for (const auto& v0 : v0sPerColl) { + + const auto& pos = v0.posTrack_as(); + const auto& neg = v0.negTrack_as(); + if (!pos.has_mcParticle()) + continue; + if (!neg.has_mcParticle()) + continue; + + auto posParticle = pos.mcParticle_as(); + auto negParticle = neg.mcParticle_as(); + if (!posParticle.has_mothers()) + continue; + if (!negParticle.has_mothers()) + continue; + + int pdgParent(0); + bool isPhysPrim = false; + for (const auto& particleMotherOfNeg : negParticle.mothers_as()) { + for (const auto& particleMotherOfPos : posParticle.mothers_as()) { + if (particleMotherOfNeg == particleMotherOfPos) { + pdgParent = particleMotherOfNeg.pdgCode(); + isPhysPrim = particleMotherOfNeg.isPhysicalPrimary(); + } + } + } + if (pdgParent == 0) + continue; + + // Generated Momentum of V0 + TVector3 momentumPos(posParticle.px(), posParticle.py(), posParticle.pz()); + TVector3 momentumNeg(negParticle.px(), negParticle.py(), negParticle.pz()); + TVector3 momentumV0 = momentumPos + momentumNeg; + + // Feed-down for lambda + if (passedLambdaSelection(v0, pos, neg) && pdgParent == kLambda0) { + if (!isPhysPrim) { + double wSecLambdaInJet(1.0); + double wSecLambdaInUe(1.0); + int idMother = posParticle.mothersIds()[0]; + const auto& mother = mcParticles.iteratorAt(idMother); + int idGrandMother = mother.mothersIds()[0]; + const auto& grandMother = mcParticles.iteratorAt(idGrandMother); + switch (grandMother.pdgCode()) { + case kXiMinus: + case kXiPlusBar: + // case 3322: + // case -3322: + if (weightsXiInJet) { + int ibinXiInJet = weightsXiInJet->GetXaxis()->FindBin(grandMother.pt()); + wSecLambdaInJet = weightsXiInJet->GetBinContent(ibinXiInJet); + } + if (weightsXiInUe) { + int ibinXiInUe = weightsXiInUe->GetXaxis()->FindBin(grandMother.pt()); + wSecLambdaInUe = weightsXiInUe->GetBinContent(ibinXiInUe); + } + break; + default: + break; + } + registryMC.fill(HIST("Secondary_Lambda_InJet"), v0.pt(), wSecLambdaInJet); + registryMC.fill(HIST("Secondary_Lambda_InUe"), v0.pt(), wSecLambdaInUe); + } + } + + // Feed-down for antilambda + if (passedAntiLambdaSelection(v0, pos, neg) && pdgParent == kLambda0Bar) { + if (!isPhysPrim) { + double wSecAntiLambdaInJet(1.0); + double wSecAntiLambdaInUe(1.0); + int idMother = posParticle.mothersIds()[0]; + const auto& mother = mcParticles.iteratorAt(idMother); + int idGrandMother = mother.mothersIds()[0]; + const auto& grandMother = mcParticles.iteratorAt(idGrandMother); + switch (grandMother.pdgCode()) { + case kXiMinus: + case kXiPlusBar: + // case 3322: + // case -3322: + if (weightsAntiXiInJet) { + int ibinAntiXiInJet = weightsAntiXiInJet->GetXaxis()->FindBin(grandMother.pt()); + wSecAntiLambdaInJet = weightsAntiXiInJet->GetBinContent(ibinAntiXiInJet); + } + if (weightsAntiXiInUe) { + int ibinAntiXiInUe = weightsAntiXiInUe->GetXaxis()->FindBin(grandMother.pt()); + wSecAntiLambdaInUe = weightsAntiXiInUe->GetBinContent(ibinAntiXiInUe); + } + break; + default: + break; + } + registryMC.fill(HIST("Secondary_AntiLambda_InJet"), v0.pt(), wSecAntiLambdaInJet); + registryMC.fill(HIST("Secondary_AntiLambda_InUe"), v0.pt(), wSecAntiLambdaInUe); + } + } + + if (passedK0ShortSelection(v0, pos, neg) && pdgParent == kK0Short) { + registryMC.fill(HIST("K0s_reconstructed_incl"), multiplicity, v0.pt()); + } + if (passedLambdaSelection(v0, pos, neg) && pdgParent == kLambda0) { + registryMC.fill(HIST("Lambda_reconstructed_incl"), multiplicity, v0.pt()); + } + if (passedAntiLambdaSelection(v0, pos, neg) && pdgParent == kLambda0Bar) { + registryMC.fill(HIST("AntiLambda_reconstructed_incl"), multiplicity, v0.pt()); + } + if (!isPhysPrim) + continue; + + double wK0jet(1.0), wK0Ue(1.0), wLambdaJet(1.0), wLambdaUe(1.0), wAntilambdaJet(1.0), wAntilambdaUe(1.0); + if (applyReweighting) { + int ix = twodWeightsK0Jet->GetXaxis()->FindBin(momentumV0.Pt()); + int iy = twodWeightsK0Jet->GetYaxis()->FindBin(momentumV0.Eta()); + wK0jet = twodWeightsK0Jet->GetBinContent(ix, iy); + wK0Ue = twodWeightsK0Ue->GetBinContent(ix, iy); + wLambdaJet = twodWeightsLambdaJet->GetBinContent(ix, iy); + wLambdaUe = twodWeightsLambdaUe->GetBinContent(ix, iy); + wAntilambdaJet = twodWeightsAntilambdaJet->GetBinContent(ix, iy); + wAntilambdaUe = twodWeightsAntilambdaUe->GetBinContent(ix, iy); + + // protections + if (ix == 0 || ix > twodWeightsK0Jet->GetNbinsX()) { + wK0jet = 1.0; + wK0Ue = 1.0; + wLambdaJet = 1.0; + wLambdaUe = 1.0; + wAntilambdaJet = 1.0; + wAntilambdaUe = 1.0; + } + if (iy == 0 || iy > twodWeightsK0Jet->GetNbinsY()) { + wK0jet = 1.0; + wK0Ue = 1.0; + wLambdaJet = 1.0; + wLambdaUe = 1.0; + wAntilambdaJet = 1.0; + wAntilambdaUe = 1.0; + } + } + + if (passedK0ShortSelection(v0, pos, neg) && pdgParent == kK0Short) { + registryMC.fill(HIST("K0s_reconstructed_jet"), multiplicity, v0.pt(), wK0jet); + registryMC.fill(HIST("K0s_reconstructed_ue"), multiplicity, v0.pt(), wK0Ue); + } + if (passedLambdaSelection(v0, pos, neg) && pdgParent == kLambda0) { + registryMC.fill(HIST("Lambda_reconstructed_jet"), multiplicity, v0.pt(), wLambdaJet); + registryMC.fill(HIST("Lambda_reconstructed_ue"), multiplicity, v0.pt(), wLambdaUe); + } + if (passedAntiLambdaSelection(v0, pos, neg) && pdgParent == kLambda0Bar) { + registryMC.fill(HIST("AntiLambda_reconstructed_jet"), multiplicity, v0.pt(), wAntilambdaJet); + registryMC.fill(HIST("AntiLambda_reconstructed_ue"), multiplicity, v0.pt(), wAntilambdaUe); + } + } + + // Cascades + for (const auto& casc : cascPerColl) { + auto bach = casc.template bachelor_as(); + auto neg = casc.template negTrack_as(); + auto pos = casc.template posTrack_as(); + + if (!bach.has_mcParticle()) + continue; + if (!pos.has_mcParticle()) + continue; + if (!neg.has_mcParticle()) + continue; + + auto posParticle = pos.mcParticle_as(); + auto negParticle = neg.mcParticle_as(); + auto bachParticle = bach.mcParticle_as(); + if (!posParticle.has_mothers()) + continue; + if (!negParticle.has_mothers()) + continue; + if (!bachParticle.has_mothers()) + continue; + + int pdgParent(0); + for (const auto& particleMotherOfNeg : negParticle.mothers_as()) { + for (const auto& particleMotherOfPos : posParticle.mothers_as()) { + for (const auto& particleMotherOfBach : bachParticle.mothers_as()) { + if (particleMotherOfNeg != particleMotherOfPos) + continue; + if (std::abs(particleMotherOfNeg.pdgCode()) != kLambda0) + continue; + if (!particleMotherOfBach.isPhysicalPrimary()) + continue; + + pdgParent = particleMotherOfBach.pdgCode(); + } + } + } + if (pdgParent == 0) + continue; + + // Xi+ + if (passedXiSelection(casc, pos, neg, bach, collision) && pdgParent == kXiPlusBar) { + registryMC.fill(HIST("XiPos_reconstructed"), multiplicity, casc.pt()); + } + // Xi- + if (passedXiSelection(casc, pos, neg, bach, collision) && pdgParent == kXiMinus) { + registryMC.fill(HIST("XiNeg_reconstructed"), multiplicity, casc.pt()); + } + // Omega+ + if (passedOmegaSelection(casc, pos, neg, bach, collision) && pdgParent == kOmegaPlusBar) { + registryMC.fill(HIST("OmegaPos_reconstructed"), multiplicity, casc.pt()); + } + // Omega- + if (passedOmegaSelection(casc, pos, neg, bach, collision) && pdgParent == kOmegaMinus) { + registryMC.fill(HIST("OmegaNeg_reconstructed"), multiplicity, casc.pt()); + } + } + + // Reconstructed Tracks + for (const auto& track : tracksPerColl) { + + // Get MC Particle + if (!track.has_mcParticle()) + continue; + // Track Selection + if (!passedTrackSelectionForPions(track)) + continue; + + const auto particle = track.mcParticle(); + switch (std::abs(particle.pdgCode())) { + case kPiPlus: + if (particle.isPhysicalPrimary()) { + if (track.sign() > 0) + registryMC.fill(HIST("pi_plus_dcaxy/prm"), multiplicity, track.pt(), track.dcaXY()); + else + registryMC.fill(HIST("pi_minus_dcaxy/prm"), multiplicity, track.pt(), track.dcaXY()); + } else { + if (track.sign() > 0) + registryMC.fill(HIST("pi_plus_dcaxy/sec"), multiplicity, track.pt(), track.dcaXY()); + else + registryMC.fill(HIST("pi_minus_dcaxy/sec"), multiplicity, track.pt(), track.dcaXY()); + } + break; + case kKPlus: + if (particle.isPhysicalPrimary()) { + if (track.sign() > 0) + registryMC.fill(HIST("ka_plus_dcaxy/prm"), multiplicity, track.pt(), track.dcaXY()); + else + registryMC.fill(HIST("ka_minus_dcaxy/prm"), multiplicity, track.pt(), track.dcaXY()); + } else { + if (track.sign() > 0) + registryMC.fill(HIST("ka_plus_dcaxy/sec"), multiplicity, track.pt(), track.dcaXY()); + else + registryMC.fill(HIST("ka_minus_dcaxy/sec"), multiplicity, track.pt(), track.dcaXY()); + } + break; + case kProton: + if (particle.isPhysicalPrimary()) { + if (track.sign() > 0) + registryMC.fill(HIST("pr_plus_dcaxy/prm"), multiplicity, track.pt(), track.dcaXY()); + else + registryMC.fill(HIST("pr_minus_dcaxy/prm"), multiplicity, track.pt(), track.dcaXY()); + } else { + if (track.sign() > 0) + registryMC.fill(HIST("pr_plus_dcaxy/sec"), multiplicity, track.pt(), track.dcaXY()); + else + registryMC.fill(HIST("pr_minus_dcaxy/sec"), multiplicity, track.pt(), track.dcaXY()); + } + break; + default: + continue; + } + + if (std::fabs(track.dcaXY()) > dcaxyMax) + continue; + + if (track.tpcNSigmaPi() < nsigmaTPCmin || track.tpcNSigmaPi() > nsigmaTPCmax) + continue; + + if (!particle.isPhysicalPrimary()) + continue; + + double wPiplusJet(1.0), wPiplusUe(1.0); + double wPiminusJet(1.0), wPiminusUe(1.0); + if (applyReweighting) { + auto getWeight = [&](TH2F* histo) { + if (!histo) + return 1.0; + const int bx = histo->GetXaxis()->FindBin(track.pt()); + if (bx <= 0 || bx > histo->GetNbinsX()) { + return 1.0; + } + const int by = histo->GetYaxis()->FindBin(track.eta()); + if (by <= 0 || by > histo->GetNbinsX()) { + return 1.0; + } + return histo->GetBinContent(bx, by); + }; + wPiplusJet = getWeight(twodWeightsPiplusJet); + wPiplusUe = getWeight(twodWeightsPiplusUe); + wPiminusJet = getWeight(twodWeightsPiminusJet); + wPiminusUe = getWeight(twodWeightsPiminusUe); + } + + if (track.sign() > 0) { + registryMC.fill(HIST("mc_pi_plus/in_jet/rec_tpc"), multiplicity, track.pt(), wPiplusJet); + registryMC.fill(HIST("mc_pi_plus/in_ue/rec_tpc"), multiplicity, track.pt(), wPiplusUe); + } else { + registryMC.fill(HIST("pi_minus_rec_in_jet_tpc"), multiplicity, track.pt(), wPiminusJet); + registryMC.fill(HIST("pi_minus_rec_in_ue_tpc"), multiplicity, track.pt(), wPiminusUe); + } + + if (!track.hasTOF()) + continue; + if (track.tofNSigmaPi() < nsigmaTOFminPionMC || track.tofNSigmaPi() > nsigmaTOFmaxPionMC) + continue; + + if (track.sign() > 0) { + registryMC.fill(HIST("mc_pi_plus/in_jet/rec_tof"), multiplicity, track.pt(), wPiplusJet); + registryMC.fill(HIST("mc_pi_plus/in_ue/rec_tof"), multiplicity, track.pt(), wPiplusUe); + } else { + registryMC.fill(HIST("pi_minus_rec_in_jet_tof"), multiplicity, track.pt(), wPiminusJet); + registryMC.fill(HIST("pi_minus_rec_in_ue_tof"), multiplicity, track.pt(), wPiminusUe); + } + } + + for (const auto& mcParticle : mcParticlesPerColl) { + + if (mcParticle.eta() < etaMin || mcParticle.eta() > etaMax) + continue; + if (!mcParticle.isPhysicalPrimary()) + continue; + + double wPiplusJet(1.0), wPiplusUe(1.0); + double wPiminusJet(1.0), wPiminusUe(1.0); + double wKaplusJet(1.0), wKaplusUe(1.0); + double wKaminusJet(1.0), wKaminusUe(1.0); + double wPrplusJet(1.0), wPrplusUe(1.0); + double wPrminusJet(1.0), wPrminusUe(1.0); + double wK0jet(1.0), wK0Ue(1.0), wLambdaJet(1.0), wLambdaUe(1.0), wAntilambdaJet(1.0), wAntilambdaUe(1.0); + if (applyReweighting) { + auto getWeight = [&](TH2F* histo) { + if (!histo) { + return 1.0; + } + const int bx = histo->GetXaxis()->FindBin(mcParticle.pt()); + if (bx <= 0 || bx > histo->GetNbinsX()) { + return 1.0; + } + const int by = histo->GetYaxis()->FindBin(mcParticle.eta()); + if (by <= 0 || by > histo->GetNbinsX()) { + return 1.0; + } + return histo->GetBinContent(bx, by); + }; + wPiplusJet = getWeight(twodWeightsPiplusJet); + wPiplusUe = getWeight(twodWeightsPiplusUe); + wPiminusJet = getWeight(twodWeightsPiminusJet); + wPiminusUe = getWeight(twodWeightsPiminusUe); + + int ix = twodWeightsK0Jet->GetXaxis()->FindBin(mcParticle.pt()); + int iy = twodWeightsK0Jet->GetYaxis()->FindBin(mcParticle.eta()); + wK0jet = twodWeightsK0Jet->GetBinContent(ix, iy); + wK0Ue = twodWeightsK0Ue->GetBinContent(ix, iy); + wLambdaJet = twodWeightsLambdaJet->GetBinContent(ix, iy); + wLambdaUe = twodWeightsLambdaUe->GetBinContent(ix, iy); + wAntilambdaJet = twodWeightsAntilambdaJet->GetBinContent(ix, iy); + wAntilambdaUe = twodWeightsAntilambdaUe->GetBinContent(ix, iy); + + // protections + if (ix == 0 || ix > twodWeightsK0Jet->GetNbinsX()) { + wK0jet = 1.0; + wK0Ue = 1.0; + wLambdaJet = 1.0; + wLambdaUe = 1.0; + wAntilambdaJet = 1.0; + wAntilambdaUe = 1.0; + } + if (iy == 0 || iy > twodWeightsK0Jet->GetNbinsY()) { + wK0jet = 1.0; + wK0Ue = 1.0; + wLambdaJet = 1.0; + wLambdaUe = 1.0; + wAntilambdaJet = 1.0; + wAntilambdaUe = 1.0; + } + } + + switch (mcParticle.pdgCode()) { + case kPiPlus: // Pi+ + registryMC.fill(HIST("mc_pi_plus/in_jet/gen"), multiplicity, mcParticle.pt(), wPiplusJet); + registryMC.fill(HIST("mc_pi_plus/in_ue/gen"), multiplicity, mcParticle.pt(), wPiplusUe); + registryMC.fill(HIST("pi_plus_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); + break; + case kPiMinus: // Pi- + registryMC.fill(HIST("mc_pi_minus/in_jet/gen"), multiplicity, mcParticle.pt(), wPiminusJet); + registryMC.fill(HIST("mc_pi_minus/in_ue/gen"), multiplicity, mcParticle.pt(), wPiminusUe); + registryMC.fill(HIST("pi_minus_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); + break; + case kKPlus: // Ka+ + registryMC.fill(HIST("mc_ka_plus/in_jet/gen"), multiplicity, mcParticle.pt(), wKaplusJet); + registryMC.fill(HIST("mc_ka_plus/in_ue/gen"), multiplicity, mcParticle.pt(), wKaplusUe); + registryMC.fill(HIST("ka_plus_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); + break; + case kKMinus: // Ka- + registryMC.fill(HIST("mc_ka_minus/in_jet/gen"), multiplicity, mcParticle.pt(), wKaminusJet); + registryMC.fill(HIST("mc_ka_minus/in_ue/gen"), multiplicity, mcParticle.pt(), wKaminusUe); + registryMC.fill(HIST("ka_minus_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); + break; + case kProton: // Pr+ + registryMC.fill(HIST("mc_pr_plus/in_jet/gen"), multiplicity, mcParticle.pt(), wPrplusJet); + registryMC.fill(HIST("mc_pr_plus/in_ue/gen"), multiplicity, mcParticle.pt(), wPrplusUe); + registryMC.fill(HIST("pr_plus_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); + break; + case kProtonBar: // Pr- + registryMC.fill(HIST("mc_pr_minus/in_jet/gen"), multiplicity, mcParticle.pt(), wPrminusJet); + registryMC.fill(HIST("mc_pr_minus/in_ue/gen"), multiplicity, mcParticle.pt(), wPrminusUe); + registryMC.fill(HIST("pr_minus_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); + break; + case kK0Short: // K0s + registryMC.fill(HIST("K0s_generated_jet"), multiplicity, mcParticle.pt(), wK0jet); + registryMC.fill(HIST("K0s_generated_ue"), multiplicity, mcParticle.pt(), wK0Ue); + registryMC.fill(HIST("K0s_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); + break; + case kLambda0: // Lambda + registryMC.fill(HIST("Lambda_generated_jet"), multiplicity, mcParticle.pt(), wLambdaJet); + registryMC.fill(HIST("Lambda_generated_ue"), multiplicity, mcParticle.pt(), wLambdaUe); + registryMC.fill(HIST("Lambda_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); + break; + case kLambda0Bar: // AntiLambda + registryMC.fill(HIST("AntiLambda_generated_jet"), multiplicity, mcParticle.pt(), wAntilambdaJet); + registryMC.fill(HIST("AntiLambda_generated_ue"), multiplicity, mcParticle.pt(), wAntilambdaUe); + registryMC.fill(HIST("AntiLambda_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); + break; + case kXiPlusBar: // Xi Pos + registryMC.fill(HIST("XiPos_generated"), multiplicity, mcParticle.pt()); + registryMC.fill(HIST("Xi_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); + break; + case kXiMinus: // Xi Neg + registryMC.fill(HIST("XiNeg_generated"), multiplicity, mcParticle.pt()); + registryMC.fill(HIST("AntiXi_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); + break; + case kOmegaPlusBar: // Omega Pos + registryMC.fill(HIST("OmegaPos_generated"), multiplicity, mcParticle.pt()); + registryMC.fill(HIST("Omega_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); + break; + case kOmegaMinus: // Omega Neg + registryMC.fill(HIST("OmegaNeg_generated"), multiplicity, mcParticle.pt()); + registryMC.fill(HIST("AntiOmega_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); + break; + } + } + } + } + PROCESS_SWITCH(StrangenessInJets, processMCefficiency, "Process MC Efficiency", false); + + void processGen(o2::aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + for (const auto& mccollision : mcCollisions) { + + // Selection on z_{vertex} + if (std::fabs(mccollision.posZ()) > zVtx) + continue; + + // MC Particles per Collision + auto mcParticlesPerColl = mcParticles.sliceBy(perMCCollision, mccollision.globalIndex()); + + // loop over generated MC particles + std::vector fjParticles; + for (const auto& particle : mcParticlesPerColl) { + + if (!particle.isPhysicalPrimary()) + continue; + if (std::fabs(particle.eta()) > etaMax) + continue; + double ptMinPart = 0.1; + if (particle.pt() < ptMinPart) + continue; + + // 4-momentum representation of a particle + double energy = std::sqrt(particle.p() * particle.p() + MassPionCharged * MassPionCharged); + fastjet::PseudoJet fourMomentum(particle.px(), particle.py(), particle.pz(), energy); + fjParticles.emplace_back(fourMomentum); + } + // reject empty events + if (fjParticles.size() < 1) + continue; + + // cluster particles using the anti-kt algorithm + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); + fastjet::ClusterSequenceArea cs(fjParticles, jetDef, areaDef); + std::vector jets = fastjet::sorted_by_pt(cs.inclusive_jets()); + auto [rhoPerp, rhoMPerp] = backgroundSub.estimateRhoPerpCone(fjParticles, jets); + + // jet selection + bool isAtLeastOneJetSelected = false; + std::vector selectedJet; + std::vector ue1; + std::vector ue2; + + for (auto& jet : jets) { // o2-linter: disable=const-ref-in-for-loop (required by backgroundSub) + + // jet must be fully contained in the acceptance + if ((std::fabs(jet.eta()) + rJet) > (etaMax - deltaEtaEdge)) + continue; + + // jet pt must be larger than threshold + fastjet::PseudoJet jetMinusBkg = backgroundSub.doRhoAreaSub(jet, rhoPerp, rhoMPerp); + if (getCorrectedPt(jetMinusBkg.pt()) < minJetPt) + continue; + isAtLeastOneJetSelected = true; + + // perpendicular cone + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + TVector3 ueAxis1(0, 0, 0); + TVector3 ueAxis2(0, 0, 0); + getPerpendicularAxis(jetAxis, ueAxis1, +1); + getPerpendicularAxis(jetAxis, ueAxis2, -1); + selectedJet.emplace_back(jetAxis); + ue1.emplace_back(ueAxis1); + ue2.emplace_back(ueAxis2); + } + if (!isAtLeastOneJetSelected) + continue; + + // loop over selected jets / UE + for (int i = 0; i < static_cast(selectedJet.size()); i++) { + for (const auto& particle : mcParticlesPerColl) { + + if (!particle.isPhysicalPrimary()) + continue; + if (std::fabs(particle.eta()) > etaMax) + continue; + double ptMinPart = 0.1; + if (particle.pt() < ptMinPart) + continue; + + TVector3 particleDir(particle.px(), particle.py(), particle.pz()); + float deltaEtaJet = particleDir.Eta() - selectedJet[i].Eta(); + float deltaPhiJet = getDeltaPhi(particleDir.Phi(), selectedJet[i].Phi()); + float deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + float deltaEtaUe1 = particleDir.Eta() - ue1[i].Eta(); + float deltaPhiUe1 = getDeltaPhi(particleDir.Phi(), ue1[i].Phi()); + float deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + float deltaEtaUe2 = particleDir.Eta() - ue2[i].Eta(); + float deltaPhiUe2 = getDeltaPhi(particleDir.Phi(), ue2[i].Phi()); + float deltaRue2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + // In jet + if (deltaRjet < rJet) { + switch (particle.pdgCode()) { + case kPiPlus: + registryMC.fill(HIST("pi_plus_eta_pt_jet"), particle.pt(), particle.eta()); + break; + case kPiMinus: + registryMC.fill(HIST("pi_minus_eta_pt_jet"), particle.pt(), particle.eta()); + break; + case kK0Short: + registryMC.fill(HIST("K0s_eta_pt_jet"), particle.pt(), particle.eta()); + break; + case kLambda0: + registryMC.fill(HIST("Lambda_eta_pt_jet"), particle.pt(), particle.eta()); + break; + case kLambda0Bar: + registryMC.fill(HIST("AntiLambda_eta_pt_jet"), particle.pt(), particle.eta()); + break; + case kXiMinus: + registryMC.fill(HIST("Xi_eta_pt_jet"), particle.pt(), particle.eta()); + break; + case kXiPlusBar: + registryMC.fill(HIST("AntiXi_eta_pt_jet"), particle.pt(), particle.eta()); + break; + case kOmegaMinus: + registryMC.fill(HIST("Omega_eta_pt_jet"), particle.pt(), particle.eta()); + break; + case kOmegaPlusBar: + registryMC.fill(HIST("AntiOmega_eta_pt_jet"), particle.pt(), particle.eta()); + break; + default: + continue; + } + } + + if (deltaRue1 < rJet || deltaRue2 < rJet) { + switch (particle.pdgCode()) { + case kPiPlus: + registryMC.fill(HIST("pi_plus_eta_pt_ue"), particle.pt(), particle.eta()); + break; + case kPiMinus: + registryMC.fill(HIST("pi_minus_eta_pt_ue"), particle.pt(), particle.eta()); + break; + case kK0Short: + registryMC.fill(HIST("K0s_eta_pt_ue"), particle.pt(), particle.eta()); + break; + case kLambda0: + registryMC.fill(HIST("Lambda_eta_pt_ue"), particle.pt(), particle.eta()); + break; + case kLambda0Bar: + registryMC.fill(HIST("AntiLambda_eta_pt_ue"), particle.pt(), particle.eta()); + break; + case kXiMinus: + registryMC.fill(HIST("Xi_eta_pt_ue"), particle.pt(), particle.eta()); + break; + case kXiPlusBar: + registryMC.fill(HIST("AntiXi_eta_pt_ue"), particle.pt(), particle.eta()); + break; + case kOmegaMinus: + registryMC.fill(HIST("Omega_eta_pt_ue"), particle.pt(), particle.eta()); + break; + case kOmegaPlusBar: + registryMC.fill(HIST("AntiOmega_eta_pt_ue"), particle.pt(), particle.eta()); + break; + default: + continue; + } + } + } + } + } + } + PROCESS_SWITCH(StrangenessInJets, processGen, "Process generated MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Strangeness/taskLambdaSpinCorr.cxx b/PWGLF/Tasks/Strangeness/taskLambdaSpinCorr.cxx new file mode 100644 index 00000000000..091593281e9 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/taskLambdaSpinCorr.cxx @@ -0,0 +1,397 @@ +// 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 taskLambdaSpinCorr.cxx +/// \brief Analysis task for Lambda spin spin correlation +/// +/// \author prottay.das@cern.ch + +#include +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "Math/GenVector/Boost.h" + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/TrackSelection.h" +#include "Framework/ASoAHelpers.h" +#include "ReconstructionDataFormats/Track.h" +#include "CCDB/BasicCCDBManager.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "Common/DataModel/FT0Corrected.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +struct LfTaskLambdaSpinCorr { + + Service ccdb; + + // fill output + Configurable additionalEvSel{"additionalEvSel", false, "additionalEvSel"}; + Configurable additionalEvSel3{"additionalEvSel3", false, "additionalEvSel3"}; + + // events + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutCentralityMax{"cfgCutCentralityMax", 50.0f, "Accepted maximum Centrality"}; + Configurable cfgCutCentralityMin{"cfgCutCentralityMin", 30.0f, "Accepted minimum Centrality"}; + + // Configs for V0 + Configurable confV0PtMin{"confV0PtMin", 0.f, "Minimum transverse momentum of V0"}; + Configurable confV0Rap{"confV0Rap", 0.8f, "Rapidity range of V0"}; + Configurable confV0DCADaughMax{"confV0DCADaughMax", 0.2f, "Maximum DCA between the V0 daughters"}; + Configurable confV0CPAMin{"confV0CPAMin", 0.9998f, "Minimum CPA of V0"}; + Configurable confV0TranRadV0Min{"confV0TranRadV0Min", 1.5f, "Minimum transverse radius"}; + Configurable confV0TranRadV0Max{"confV0TranRadV0Max", 100.f, "Maximum transverse radius"}; + Configurable cMaxV0DCA{"cMaxV0DCA", 1.2, "Maximum V0 DCA to PV"}; + Configurable cMinV0DCAPr{"cMinV0DCAPr", 0.05, "Minimum V0 daughters DCA to PV for Pr"}; + Configurable cMinV0DCAPi{"cMinV0DCAPi", 0.05, "Minimum V0 daughters DCA to PV for Pi"}; + Configurable cMaxV0LifeTime{"cMaxV0LifeTime", 20, "Maximum V0 life time"}; + + // config for V0 daughters + Configurable confDaughEta{"confDaughEta", 0.8f, "V0 Daugh sel: max eta"}; + Configurable cfgDaughPrPt{"cfgDaughPrPt", 0.4, "minimum daughter proton pt"}; + Configurable cfgDaughPiPt{"cfgDaughPiPt", 0.2, "minimum daughter pion pt"}; + Configurable confDaughTPCnclsMin{"confDaughTPCnclsMin", 50.f, "V0 Daugh sel: Min. nCls TPC"}; + Configurable confDaughDCAMin{"confDaughDCAMin", 0.08f, "V0 Daugh sel: Max. DCA Daugh to PV (cm)"}; + Configurable confDaughPIDCuts{"confDaughPIDCuts", 3, "PID selections for Lambda daughters"}; + + Configurable iMNbins{"iMNbins", 100, "Number of bins in invariant mass"}; + Configurable lbinIM{"lbinIM", 1.0, "lower bin value in IM histograms"}; + Configurable hbinIM{"hbinIM", 1.2, "higher bin value in IM histograms"}; + + ConfigurableAxis configcentAxis{"configcentAxis", {VARIABLE_WIDTH, 0.0, 10.0, 40.0, 80.0}, "Cent V0M"}; + ConfigurableAxis configthnAxisPt{"configthnAxisPt", {VARIABLE_WIDTH, 0.2, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.5, 8.0, 10.0, 100.0}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis configthnAxisPol{"configthnAxisPol", {VARIABLE_WIDTH, -1.0, -0.6, -0.2, 0, 0.2, 0.4, 0.8}, "Pol"}; + + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + AxisSpec thnAxisInvMass{iMNbins, lbinIM, hbinIM, "#it{M} (GeV/#it{c}^{2})"}; + + histos.add("hCentrality", "Centrality distribution", kTH1F, {{configcentAxis}}); + + histos.add("hSparseLambdaLambda", "hSparseLambdaLambda", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, configthnAxisPt, configthnAxisPt}, true); + histos.add("hSparseLambdaAntiLambda", "hSparseLambdaAntiLambda", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, configthnAxisPt, configthnAxisPt}, true); + histos.add("hSparseAntiLambdaAntiLambda", "hSparseAntiLambdaAntiLambda", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, configthnAxisPt, configthnAxisPt}, true); + } + + template + bool selectionV0(Collision const& collision, V0 const& candidate) + { + if (std::abs(candidate.dcav0topv()) > cMaxV0DCA) { + return false; + } + const float pT = candidate.pt(); + const float tranRad = candidate.v0radius(); + const float dcaDaughv0 = std::abs(candidate.dcaV0daughters()); + const float cpav0 = candidate.v0cosPA(); + + float ctauLambda = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * (o2::constants::physics::MassLambda); + + if (pT < confV0PtMin) { + return false; + } + if (dcaDaughv0 > confV0DCADaughMax) { + return false; + } + if (cpav0 < confV0CPAMin) { + return false; + } + if (tranRad < confV0TranRadV0Min) { + return false; + } + if (tranRad > confV0TranRadV0Max) { + return false; + } + if (std::abs(ctauLambda) > cMaxV0LifeTime) { + return false; + } + if (std::abs(candidate.yLambda()) > confV0Rap) { + return false; + } + return true; + } + template + bool isSelectedV0Daughter(V0 const& candidate, T const& track, int pid) + { + const auto tpcNClsF = track.tpcNClsFound(); + const auto ncr = 70; + const auto ncrfc = 0.8; + + if (track.tpcNClsCrossedRows() < ncr) { + return false; + } + if (tpcNClsF < confDaughTPCnclsMin) { + return false; + } + if (track.tpcCrossedRowsOverFindableCls() < ncrfc) { + return false; + } + + if (pid == 0 && std::abs(track.tpcNSigmaPr()) > confDaughPIDCuts) { + return false; + } + if (pid == 1 && std::abs(track.tpcNSigmaPi()) > confDaughPIDCuts) { + return false; + } + if (pid == 0 && (candidate.positivept() < cfgDaughPrPt || candidate.negativept() < cfgDaughPiPt)) { + return false; + } + if (pid == 1 && (candidate.positivept() < cfgDaughPiPt || candidate.negativept() < cfgDaughPrPt)) { + return false; + } + if (std::abs(candidate.positiveeta()) > confDaughEta || std::abs(candidate.negativeeta()) > confDaughEta) { + return false; + } + + if (pid == 0 && (std::abs(candidate.dcapostopv()) < cMinV0DCAPr || std::abs(candidate.dcanegtopv()) < cMinV0DCAPi)) { + return false; + } + if (pid == 1 && (std::abs(candidate.dcapostopv()) < cMinV0DCAPi || std::abs(candidate.dcanegtopv()) < cMinV0DCAPr)) { + return false; + } + + return true; + } + + bool shouldReject(bool lambdaTag, bool aLambdaTag, + const ROOT::Math::PxPyPzMVector& Lambdadummy, + const ROOT::Math::PxPyPzMVector& AntiLambdadummy) + { + const double minMass = 1.105; + const double maxMass = 1.125; + return (lambdaTag && aLambdaTag && + (Lambdadummy.M() > minMass && Lambdadummy.M() < maxMass) && + (AntiLambdadummy.M() > minMass && AntiLambdadummy.M() < maxMass)); + } + + void fillHistograms(bool tag1, bool tag2, bool tag3, bool tag4, const ROOT::Math::PxPyPzMVector& particlepair, + const ROOT::Math::PxPyPzMVector& particle1, const ROOT::Math::PxPyPzMVector& particle2, + const ROOT::Math::PxPyPzMVector& daughpart1, const ROOT::Math::PxPyPzMVector& daughpart2, + double centrality) + { + + ROOT::Math::Boost boostPairToCM{particlepair.BoostToCM()}; // boosting vector for pair CM + // Boosting both Lambdas to Lambda-Lambda pair rest frame + auto lambda1CM = boostPairToCM(particle1); + auto lambda2CM = boostPairToCM(particle2); + + // Step 2: Boost Each Lambda to its Own Rest Frame + ROOT::Math::Boost boostLambda1ToCM{lambda1CM.BoostToCM()}; + ROOT::Math::Boost boostLambda2ToCM{lambda2CM.BoostToCM()}; + + // Also boost the daughter protons to the same frame + auto proton1pairCM = boostPairToCM(daughpart1); // proton1 to pair CM + auto proton2pairCM = boostPairToCM(daughpart2); // proton2 to pair CM + + // Boost protons into their respective Lambda rest frames + auto proton1LambdaRF = boostLambda1ToCM(proton1pairCM); + auto proton2LambdaRF = boostLambda2ToCM(proton2pairCM); + + // Method2 + ROOT::Math::XYZVector quantizationAxis = lambda1CM.Vect().Unit(); // Unit vector along Lambda1's direction in pair rest frame + double cosTheta1 = proton1LambdaRF.Vect().Unit().Dot(quantizationAxis); + double cosTheta2 = proton2LambdaRF.Vect().Unit().Dot(-quantizationAxis); // Opposite for Lambda2 + + double theta1 = std::acos(cosTheta1); // angle in radians + double theta2 = std::acos(cosTheta2); // angle in radians + // Step 2: Compute sin(theta1) and sin(theta2) + // double sinTheta1 = std::sqrt(1 - cosTheta1 * cosTheta1); + // double sinTheta2 = std::sqrt(1 - cosTheta2 * cosTheta2); + + // Step 3: Calculate cos(theta1 - theta2) using the trigonometric identity + // double cosThetaDiff = cosTheta1 * cosTheta2 + sinTheta1 * sinTheta2; + double cosThetaDiff = std::cos(theta1 - theta2); + + if (tag1 && tag3) + histos.fill(HIST("hSparseLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, centrality, particle1.Pt(), particle2.Pt()); + if (tag1 && tag4) + histos.fill(HIST("hSparseLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, centrality, particle1.Pt(), particle2.Pt()); + if (tag2 && tag4) + histos.fill(HIST("hSparseAntiLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, centrality, particle1.Pt(), particle2.Pt()); + } + + std::tuple getLambdaTags(const auto& v0, const auto& collision) + { + auto postrack = v0.template posTrack_as(); + auto negtrack = v0.template negTrack_as(); + + int lambdaTag = 0; + int aLambdaTag = 0; + + const auto signpos = postrack.sign(); + const auto signneg = negtrack.sign(); + + if (signpos < 0 || signneg > 0) { + return {0, 0, false}; // Invalid candidate + } + + if (isSelectedV0Daughter(v0, postrack, 0) && isSelectedV0Daughter(v0, negtrack, 1)) { + lambdaTag = 1; + } + if (isSelectedV0Daughter(v0, negtrack, 0) && isSelectedV0Daughter(v0, postrack, 1)) { + aLambdaTag = 1; + } + + if (!lambdaTag && !aLambdaTag) { + return {0, 0, false}; // No valid tags + } + + if (!selectionV0(collision, v0)) { + return {0, 0, false}; // Fails selection + } + + const auto netav = 0.8; + if (std::abs(v0.eta()) > netav) { + return {0, 0, false}; // Fails selection + } + + return {lambdaTag, aLambdaTag, true}; // Valid candidate + } + + ROOT::Math::PxPyPzMVector lambda, antiLambda, lambdadummy, antiLambdadummy, proton, pion, antiProton, antiPion, fourVecDauCM; + ROOT::Math::PxPyPzMVector lambda2, antiLambda2, lambdadummy2, antiLambdadummy2, proton2, pion2, antiProton2, antiPion2; + ROOT::Math::PxPyPzMVector lambdaLambdapair, lambdaAntiLambdapair, antiLambdaAntiLambdapair; + ROOT::Math::XYZVector threeVecDauCM, threeVecDauCMXY; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter centralityFilter = (nabs(aod::cent::centFT0C) < cfgCutCentralityMax && nabs(aod::cent::centFT0C) > cfgCutCentralityMin); + + // using EventCandidates = soa::Filtered>; + using EventCandidates = soa::Filtered>; + using AllTrackCandidates = soa::Join; + using ResoV0s = aod::V0Datas; + + void processData(EventCandidates::iterator const& collision, AllTrackCandidates const& /*tracks*/, ResoV0s const& V0s, aod::BCs const&) + { + + if (!collision.sel8()) { + return; + } + auto centrality = collision.centFT0C(); + + if (additionalEvSel && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + + if (additionalEvSel3 && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + return; + } + + histos.fill(HIST("hCentrality"), centrality); + + for (const auto& v0 : V0s) { + + auto [lambdaTag, aLambdaTag, isValid] = getLambdaTags(v0, collision); + if (!isValid) + continue; + + if (lambdaTag) { + proton = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), o2::constants::physics::MassProton); + antiPion = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), o2::constants::physics::MassPionCharged); + lambdadummy = proton + antiPion; + } + if (aLambdaTag) { + antiProton = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), o2::constants::physics::MassProton); + pion = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), o2::constants::physics::MassPionCharged); + antiLambdadummy = antiProton + pion; + } + + if (shouldReject(lambdaTag, aLambdaTag, lambdadummy, antiLambdadummy)) { + continue; + } + + int taga = lambdaTag; + int tagb = aLambdaTag; + + // 2nd loop for combination of lambda lambda + for (const auto& v02 : V0s) { + + if (v0.v0Id() >= v02.v0Id()) + continue; + + auto [lambdaTag2, aLambdaTag2, isValid2] = getLambdaTags(v02, collision); + if (!isValid2) + continue; + + if (lambdaTag2) { + proton2 = ROOT::Math::PxPyPzMVector(v02.pxpos(), v02.pypos(), v02.pzpos(), o2::constants::physics::MassProton); + antiPion2 = ROOT::Math::PxPyPzMVector(v02.pxneg(), v02.pyneg(), v02.pzneg(), o2::constants::physics::MassPionCharged); + lambdadummy2 = proton2 + antiPion2; + } + if (aLambdaTag2) { + antiProton2 = ROOT::Math::PxPyPzMVector(v02.pxneg(), v02.pyneg(), v02.pzneg(), o2::constants::physics::MassProton); + pion2 = ROOT::Math::PxPyPzMVector(v02.pxpos(), v02.pypos(), v02.pzpos(), o2::constants::physics::MassPionCharged); + antiLambdadummy2 = antiProton2 + pion2; + } + + if (shouldReject(lambdaTag2, aLambdaTag2, lambdadummy2, antiLambdadummy2)) { + continue; + } + + int taga2 = lambdaTag2; + int tagb2 = aLambdaTag2; + + if (lambdaTag && lambdaTag2) { + lambdaLambdapair = lambdadummy + lambdadummy2; + tagb = 0; + tagb2 = 0; + // fillHistograms(taga, tagb, taga2, tagb2, LambdaLambdapair, Lambdadummy, Lambdadummy2, Proton, Proton2, centrality, LambdaLambdapair.M(), LambdaLambdapair.Pt()); + fillHistograms(taga, tagb, taga2, tagb2, lambdaLambdapair, lambdadummy, lambdadummy2, proton, proton2, centrality); + } + + tagb2 = aLambdaTag2; + + if (lambdaTag && aLambdaTag2) { + lambdaAntiLambdapair = lambdadummy + antiLambdadummy2; + tagb = 0; + taga2 = 0; + // fillHistograms(taga, tagb, taga2, tagb2, LambdaAntiLambdapair, Lambdadummy, AntiLambdadummy2, Proton, AntiProton2, centrality, LambdaAntiLambdapair.M(), LambdaAntiLambdapair.Pt()); + fillHistograms(taga, tagb, taga2, tagb2, lambdaAntiLambdapair, lambdadummy, antiLambdadummy2, proton, antiProton2, centrality); + } + + tagb = aLambdaTag; + taga2 = lambdaTag2; + + if (aLambdaTag && aLambdaTag2) { + antiLambdaAntiLambdapair = antiLambdadummy + antiLambdadummy2; + taga = 0; + taga2 = 0; + // fillHistograms(taga, tagb, taga2, tagb2, AntiLambdaAntiLambdapair, AntiLambdadummy, AntiLambdadummy2, AntiProton, AntiProton2, centrality, AntiLambdaAntiLambdapair.M(), AntiLambdaAntiLambdapair.Pt()); + fillHistograms(taga, tagb, taga2, tagb2, antiLambdaAntiLambdapair, antiLambdadummy, antiLambdadummy2, antiProton, antiProton2, centrality); + } + } + } + } + PROCESS_SWITCH(LfTaskLambdaSpinCorr, processData, "Process data", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // return WorkflowSpec{ + // adaptAnalysisTask(cfgc, TaskName{"LambdaSpinCorrelation"})}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Strangeness/v0postprocessing.cxx b/PWGLF/Tasks/Strangeness/v0postprocessing.cxx index 50ceab1ed5b..4f6ab094f46 100644 --- a/PWGLF/Tasks/Strangeness/v0postprocessing.cxx +++ b/PWGLF/Tasks/Strangeness/v0postprocessing.cxx @@ -26,11 +26,10 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -using DauTracks = soa::Join; - struct v0postprocessing { Configurable radius{"radius", 0.5, "Radius"}; + Configurable maxradius{"maxradius", 100000, "Radius"}; Configurable dcanegtopv{"dcanegtopv", 0.05, "DCA Neg To PV"}; Configurable dcapostopv{"dcapostopv", 0.05, "DCA Pos To PV"}; Configurable cospaK0s{"cospaK0s", 0.97, "K0s CosPA"}; @@ -43,17 +42,73 @@ struct v0postprocessing { Configurable v0rejLambda{"v0rejLambda", 0.01, "V0 rej K0s"}; Configurable ntpcsigma{"ntpcsigma", 5, "N sigma TPC"}; Configurable etadau{"etadau", 0.8, "Eta Daughters"}; + Configurable minITShits{"minITShits", 2, "min ITS hits"}; + Configurable min_TPC_nClusters{"min_TPC_nClusters", 80, "min_TPC_nClusters"}; + Configurable max_tpcSharedCls{"max_tpcSharedCls", 100, "max_tpcSharedCls"}; + Configurable max_chi2_ITS{"max_chi2_ITS", 36, "max_chi2_ITS"}; + Configurable max_chi2_TPC{"max_chi2_TPC", 4, "max_chi2_TPC"}; Configurable isMC{"isMC", 1, "isMC"}; + Configurable evSel{"evSel", 1, "evSel"}; + Configurable hasTOF2Leg{"hasTOF2Leg", 0, "hasTOF2Leg"}; + Configurable hasTOF1Leg{"hasTOF1Leg", 0, "hasTOF1Leg"}; + Configurable paramArmenterosCut{"paramArmenterosCut", 0.2, "parameter Armenteros Cut"}; + Configurable doArmenterosCut{"doArmenterosCut", 1, "do Armenteros Cut"}; + Configurable doQA{"doQA", 1, "fill QA histograms"}; HistogramRegistry registry{"registry"}; void init(InitContext const&) { + registry.add("hV0Cuts", ";Sel", {HistType::kTH1D, {{22, 0., 22.}}}); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(1, "all"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(2, "Event selection"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(3, "Radius"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(4, "Eta Daughters"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(5, "Dau DCA to PV"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(6, "DCA Daughters"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(7, "min ITS hits"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(8, "has TOF 1 Leg"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(9, "has TOF 2 Legs"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(10, "TPC NCl"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(11, "TPC Cls Shared"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(12, "ITS Chi2"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(13, "TPC Chi2"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(14, "cosPA K0s"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(15, "cosPA Lambda"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(16, "rapidity"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(17, "ctau K0s"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(18, "ctau Lambda"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(19, "v0 rej K0s"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(20, "v0 rej Lambda"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(21, "TPC nsigma Dau"); + registry.get(HIST("hV0Cuts"))->GetXaxis()->SetBinLabel(22, "Armenteros-Podolansky"); + + registry.get(HIST("hV0Cuts"))->SetBinContent(1, 1); + registry.get(HIST("hV0Cuts"))->SetBinContent(2, evSel); + registry.get(HIST("hV0Cuts"))->SetBinContent(3, radius); + registry.get(HIST("hV0Cuts"))->SetBinContent(4, etadau); + registry.get(HIST("hV0Cuts"))->SetBinContent(5, dcanegtopv); + registry.get(HIST("hV0Cuts"))->SetBinContent(6, dcav0dau); + registry.get(HIST("hV0Cuts"))->SetBinContent(7, minITShits); + registry.get(HIST("hV0Cuts"))->SetBinContent(8, hasTOF1Leg); + registry.get(HIST("hV0Cuts"))->SetBinContent(9, hasTOF2Leg); + registry.get(HIST("hV0Cuts"))->SetBinContent(10, min_TPC_nClusters); + registry.get(HIST("hV0Cuts"))->SetBinContent(11, max_tpcSharedCls); + registry.get(HIST("hV0Cuts"))->SetBinContent(12, max_chi2_ITS); + registry.get(HIST("hV0Cuts"))->SetBinContent(13, max_chi2_TPC); + registry.get(HIST("hV0Cuts"))->SetBinContent(14, cospaK0s); + registry.get(HIST("hV0Cuts"))->SetBinContent(15, cospaLambda); + registry.get(HIST("hV0Cuts"))->SetBinContent(16, rap); + registry.get(HIST("hV0Cuts"))->SetBinContent(17, ctauK0s); + registry.get(HIST("hV0Cuts"))->SetBinContent(18, ctauLambda); + registry.get(HIST("hV0Cuts"))->SetBinContent(19, v0rejK0s); + registry.get(HIST("hV0Cuts"))->SetBinContent(20, v0rejLambda); + registry.get(HIST("hV0Cuts"))->SetBinContent(21, ntpcsigma); + registry.get(HIST("hV0Cuts"))->SetBinContent(22, paramArmenterosCut * doArmenterosCut); registry.add("hMassK0Short", ";M_{#pi^{+}#pi^{-}} [GeV/c^{2}]", {HistType::kTH1F, {{200, 0.4f, 0.6f}}}); registry.add("hMassVsPtK0Short", ";p_{T} [GeV/c];M_{#pi^{+}#pi^{-}} [GeV/c^{2}]", {HistType::kTH2F, {{250, 0.0f, 25.0f}, {200, 0.4f, 0.6f}}}); registry.add("hMassVsPtK0ShortVsCentFT0M", ";p_{T} [GeV/c]; CentFT0M; M_{#pi^{+}#pi^{-}} [GeV/c^{2}]", {HistType::kTH3F, {{250, 0.0f, 25.0f}, {100, 0.f, 100.f}, {200, 0.4f, 0.6f}}}); - registry.add("hMassVsPtK0ShortVsCentFV0A", ";p_{T} [GeV/c]; CentFT0M; M_{#pi^{+}#pi^{-}} [GeV/c^{2}]", {HistType::kTH3F, {{250, 0.0f, 25.0f}, {100, 0.f, 100.f}, {200, 0.4f, 0.6f}}}); registry.add("hMassLambda", "hMassLambda", {HistType::kTH1F, {{200, 1.016f, 1.216f}}}); registry.add("hMassVsPtLambda", "hMassVsPtLambda", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {200, 1.016f, 1.216f}}}); registry.add("hMassVsPtLambdaVsCentFT0M", ";p_{T} [GeV/c]; CentFT0M; M_{#pi^{+}#pi^{-}} [GeV/c^{2}]", {HistType::kTH3F, {{250, 0.0f, 25.0f}, {100, 0.f, 100.f}, {200, 1.016f, 1.216f}}}); @@ -63,163 +118,400 @@ struct v0postprocessing { if (isMC) { registry.add("hMassK0Short_MC", ";M_{#pi^{+}#pi^{-}} [GeV/c^{2}]", {HistType::kTH1F, {{200, 0.4f, 0.6f}}}); - registry.add("hMassVsPtK0Short_MC", ";p_{T} [GeV/c];M_{#pi^{+}#pi^{-}} [GeV/c^{2}]", {HistType::kTH2F, {{250, 0.0f, 25.0f}, {200, 0.4f, 0.6f}}}); + registry.add("hMassVsPtK0ShortVsCentFT0M_MC", ";p_{T} [GeV/c];M_{#pi^{+}#pi^{-}} [GeV/c^{2}]", {HistType::kTH3F, {{250, 0.0f, 25.0f}, {100, 0.f, 100.f}, {200, 0.4f, 0.6f}}}); registry.add("hMassLambda_MC", "hMassLambda", {HistType::kTH1F, {{200, 1.016f, 1.216f}}}); - registry.add("hMassVsPtLambda_MC", "hMassVsPtLambda", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {200, 1.016f, 1.216f}}}); + registry.add("hMassVsPtLambdaVsCentFT0M_MC", ";p_{T} [GeV/c];M_{p^{+}#pi^{-}} [GeV/c^{2}]", {HistType::kTH3F, {{250, 0.0f, 25.0f}, {100, 0.f, 100.f}, {200, 1.016f, 1.216f}}}); registry.add("hMassAntiLambda_MC", "hMassAntiLambda", {HistType::kTH1F, {{200, 1.016f, 1.216f}}}); - registry.add("hMassVsPtAntiLambda_MC", "hMassVsPtAntiLambda", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {200, 1.016f, 1.216f}}}); + registry.add("hMassVsPtLambdaVsMotherPt_DoubleCharged_MC", ";p_{T} [GeV/c] (V0);p_{T}^{gen} [GeV/c] (Xi);M_{p^{-}#pi^{+}} [GeV/c^{2}]", {HistType::kTH3F, {{250, 0.0f, 25.0f}, {250, 0.0f, 25.0f}, {200, 1.016f, 1.216f}}}); + registry.add("hMassVsPtLambdaVsMotherPt_MCRatio_MC", ";p_{T} [GeV/c] (V0);p_{T}^{gen} [GeV/c] (Xi);M_{p^{-}#pi^{+}} [GeV/c^{2}]", {HistType::kTH3F, {{250, 0.0f, 25.0f}, {250, 0.0f, 25.0f}, {200, 1.016f, 1.216f}}}); + registry.add("hMassVsPtAntiLambdaVsCentFT0M_MC", ";p_{T} [GeV/c];M_{p^{-}#pi^{+}} [GeV/c^{2}]", {HistType::kTH3F, {{250, 0.0f, 25.0f}, {100, 0.f, 100.f}, {200, 1.016f, 1.216f}}}); + registry.add("hMassVsPtAntiLambdaVsMotherPt_DoubleCharged_MC", ";p_{T} [GeV/c] (V0);p_{T}^{gen} [GeV/c] (Xi);M_{p^{-}#pi^{+}} [GeV/c^{2}]", {HistType::kTH3F, {{250, 0.0f, 25.0f}, {250, 0.0f, 25.0f}, {200, 1.016f, 1.216f}}}); + registry.add("hMassVsPtAntiLambdaVsMotherPt_MCRatio_MC", ";p_{T} [GeV/c] (V0);p_{T}^{gen} [GeV/c] (Xi);M_{p^{-}#pi^{+}} [GeV/c^{2}]", {HistType::kTH3F, {{250, 0.0f, 25.0f}, {250, 0.0f, 25.0f}, {200, 1.016f, 1.216f}}}); } - // QA - registry.add("hK0sV0Radius", "hK0sV0Radius", {HistType::kTH1D, {{200, 0.0f, 40.0f}}}); - registry.add("hK0sCosPA", "hK0sCosPA", {HistType::kTH1F, {{100, 0.9f, 1.0f}}}); - registry.add("hK0sV0DCANegToPV", "hK0sV0DCANegToPV", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}); - registry.add("hK0sV0DCAPosToPV", "hK0sV0DCAPosToPV", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}); - registry.add("hK0sV0DCAV0Daughters", "hK0sV0DCAV0Daughters", {HistType::kTH1F, {{55, 0.0f, 2.20f}}}); - registry.add("hK0sCtau", "hK0sCtau", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); - registry.add("hK0sEtaDau", "hK0sEtaDau", {HistType::kTH1F, {{100, -1.0f, 1.0f}}}); - registry.add("hK0sRap", "hK0sRap", {HistType::kTH1F, {{100, -1.0f, 1.0f}}}); - registry.add("hK0sTPCNSigmaPosPi", "hK0sTPCNSigmaPosPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); - registry.add("hK0sTPCNSigmaNegPi", "hK0sTPCNSigmaNegPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); - - /* registry.add("hLambdaV0Radius", "hLambdaV0Radius", {HistType::kTH1D, {{200, 0.0f, 40.0f}}}); - registry.add("hLambdaCosPA", "hLambdaCosPA", {HistType::kTH1F, {{100, 0.9f, 1.0f}}}); - registry.add("hLambdaV0DCANegToPV", "hLambdaV0DCANegToPV", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}); - registry.add("hLambdaV0DCAPosToPV", "hLambdaV0DCAPosToPV", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}); - registry.add("hLambdaV0DCAV0Daughters", "hLambdaV0DCAV0Daughters", {HistType::kTH1F, {{55, 0.0f, 2.20f}}}); - registry.add("hLambdaCtau", "hLambdaCtau", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); - registry.add("hLambdaEtaDau", "hLambdaEtaDau", {HistType::kTH1F, {{100, -1.0f, 1.0f}}}); - registry.add("hLambdaRap", "hLambdaRap", {HistType::kTH1F, {{100, -1.0f, 1.0f}}}); - registry.add("hLambdaTPCNSigmaPosPi", "hLambdaTPCNSigmaPosPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); - registry.add("hLambdaTPCNSigmaNegPi", "hLambdaTPCNSigmaNegPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); - registry.add("hLambdaTPCNSigmaNegPr", "hLambdaTPCNSigmaNegPr", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); - registry.add("hLambdaTPCNSigmaPosPr", "hLambdaTPCNSigmaPosPr", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); - - registry.add("hAntiLambdaV0Radius", "hAntiLambdaV0Radius", {HistType::kTH1D, {{200, 0.0f, 40.0f}}}); - registry.add("hAntiLambdaCosPA", "hAntiLambdaCosPA", {HistType::kTH1F, {{100, 0.9f, 1.0f}}}); - registry.add("hAntiLambdaV0DCANegToPV", "hAntiLambdaV0DCANegToPV", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}); - registry.add("hAntiLambdaV0DCAPosToPV", "hAntiLambdaV0DCAPosToPV", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}); - registry.add("hAntiLambdaV0DCAV0Daughters", "hAntiLambdaV0DCAV0Daughters", {HistType::kTH1F, {{55, 0.0f, 2.20f}}}); - registry.add("hAntiLambdaCtau", "hAntiLambdaCtau", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); - registry.add("hAntiLambdaEtaDau", "hAntiLambdaEtaDau", {HistType::kTH1F, {{100, -1.0f, 1.0f}}}); - registry.add("hAntiLambdaRap", "hAntiLambdaRap", {HistType::kTH1F, {{100, -1.0f, 1.0f}}}); - registry.add("hAntiLambdaTPCNSigmaPosPi", "hAntiLambdaTPCNSigmaPosPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); - registry.add("hAntiLambdaTPCNSigmaNegPi", "hAntiLambdaTPCNSigmaNegPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); - registry.add("hAntiLambdaTPCNSigmaNegPr", "hAntiLambdaTPCNSigmaNegPr", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); - registry.add("hAntiLambdaTPCNSigmaPosPr", "hAntiLambdaTPCNSigmaPosPr", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); - - registry.add("TPCNSigmaPosPr", "TPCNSigmaPosPr", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); - registry.add("TPCNSigmaNegPr", "TPCNSigmaNegPr", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); - registry.add("TOFNSigmaPosPi", "TOFNSigmaPosPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); - registry.add("TOFNSigmaNegPi", "TOFNSigmaNegPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); - registry.add("TOFNSigmaPosPr", "TOFNSigmaPosPr", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); - registry.add("TOFNSigmaNegPr", "TOFNSigmaNegPr", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); */ + if (doQA) { + registry.add("QA/hK0sSelection", ";Sel", {HistType::kTH1D, {{22, 0., 22.}}}); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(1, "all"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(2, "Event selection"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(3, "Radius"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(4, "Eta Daughters"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(5, "Dau DCA to PV"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(6, "DCA Daughters"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(7, "min ITS hits"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(8, "has TOF 1 Leg"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(9, "has TOF 2 Legs"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(10, "TPC NCl"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(11, "TPC Cls Shared"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(12, "ITS Chi2"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(13, "TPC Chi2"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(14, "cosPA"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(15, "rapidity"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(16, "ctau"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(17, "v0 rej"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(18, "TPC nsigma Neg Dau"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(19, "TPC nsigma Pos Dau"); + registry.get(HIST("QA/hK0sSelection"))->GetXaxis()->SetBinLabel(20, "Armenteros-Podolansky"); + + // common + registry.add("QA/hV0_EvFlag", "hV0_EvFlag", {HistType::kTH1D, {{2, 0.0f, 2.0f}}}); + registry.add("QA/hV0_Radius", "hV0_Radius", {HistType::kTH1D, {{1000, 0.0f, 100.0f}}}); + registry.add("QA/hV0_DCADauToPV", "hV0_DCADauToPV", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}); + registry.add("QA/hV0_DCADaughters", "hV0_DCADaughters", {HistType::kTH1F, {{200, 0.0f, 2.0f}}}); + registry.add("QA/hV0_EtaDau", "hV0_EtaDau", {HistType::kTH1F, {{100, -1.0f, 1.0f}}}); + registry.add("QA/hV0_ITShits", "hV0_ITShits", {HistType::kTH1F, {{10, .0f, 10.0f}}}); + registry.add("QA/hV0_TPCNCls", "hV0_TPCNCls", {HistType::kTH1F, {{200, .0f, 200.0f}}}); + registry.add("QA/hV0_TPCNClsShared", "hV0_TPCNClsShared", {HistType::kTH1F, {{150, .0f, 1.5f}}}); + registry.add("QA/hV0_ITSChi2", "hV0_ITSChi2", {HistType::kTH1F, {{10, .0f, 10.0f}}}); + registry.add("QA/hV0_TPCChi2", "hV0_TPCChi2", {HistType::kTH1F, {{100, .0f, 100.0f}}}); + // K0s + registry.add("QA/hK0s_ArmenterosPodolanski", "QA/hK0s_ArmenterosPodolanski", {HistType::kTH2F, {{1000, -1.0f, 1.0f, "#alpha"}, {1000, 0.0f, 0.30f, "#it{Q}_{T}"}}}); + registry.add("QA/hK0s_Rap", "hK0s_Rap", {HistType::kTH1F, {{100, -1.0f, 1.0f}}}); + registry.add("QA/hK0s_CosPA", "hK0s_CosPA", {HistType::kTH1F, {{100, 0.95f, 1.0f}}}); + registry.add("QA/hK0s_Ctau", "hK0s_Ctau", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); + registry.add("QA/hK0s_TPCNSigmaPosPi", "hK0s_TPCNSigmaPosPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); + registry.add("QA/hK0s_TPCNSigmaNegPi", "hK0s_TPCNSigmaNegPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); + // Lambda + registry.add("QA/hLambda_ArmenterosPodolanski", "QA/hLambda_ArmenterosPodolanski", {HistType::kTH2F, {{1000, -1.0f, 1.0f, "#alpha"}, {1000, 0.0f, 0.30f, "#it{Q}_{T}"}}}); + registry.add("QA/hLambda_Rap", "hLambda_Rap", {HistType::kTH1F, {{100, -1.0f, 1.0f}}}); + registry.add("QA/hLambda_CosPA", "hLambda_CosPA", {HistType::kTH1F, {{100, 0.95f, 1.0f}}}); + registry.add("QA/hLambda_Ctau", "hLambda_Ctau", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); + registry.add("QA/hLambda_TPCNSigmaPosPi", "hLambda_TPCNSigmaPosPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); + registry.add("QA/hLambda_TPCNSigmaNegPi", "hLambda_TPCNSigmaNegPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); + // AntiLambda + registry.add("QA/hAntiLambda_ArmenterosPodolanski", "QA/hAntiLambda_ArmenterosPodolanski", {HistType::kTH2F, {{1000, -1.0f, 1.0f, "#alpha"}, {1000, 0.0f, 0.30f, "#it{Q}_{T}"}}}); + registry.add("QA/hAntiLambda_Rap", "hAntiLambda_Rap", {HistType::kTH1F, {{100, -1.0f, 1.0f}}}); + registry.add("QA/hAntiLambda_CosPA", "hAntiLambda_CosPA", {HistType::kTH1F, {{100, 0.95f, 1.0f}}}); + registry.add("QA/hAntiLambda_Ctau", "hAntiLambda_Ctau", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); + registry.add("QA/hAntiLambda_TPCNSigmaPosPi", "hAntiLambda_TPCNSigmaPosPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); + registry.add("QA/hAntiLambda_TPCNSigmaNegPi", "hAntiLambda_TPCNSigmaNegPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); + + // common + registry.add("QA/hV0_Sel_EvFlag", "hV0_Sel_EvFlag", {HistType::kTH1D, {{2, 0.0f, 2.0f}}}); + registry.add("QA/hV0_Sel_Radius", "hV0_Sel_Radius", {HistType::kTH1D, {{1000, 0.0f, 100.0f}}}); + registry.add("QA/hV0_Sel_DCADauToPV", "hV0_Sel_DCADauToPV", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}); + registry.add("QA/hV0_Sel_DCADaughters", "hV0_Sel_DCADaughters", {HistType::kTH1F, {{200, 0.0f, 2.0f}}}); + registry.add("QA/hV0_Sel_EtaDau", "hV0_Sel_EtaDau", {HistType::kTH1F, {{100, -1.0f, 1.0f}}}); + registry.add("QA/hV0_Sel_ITShits", "hV0_Sel_ITShits", {HistType::kTH1F, {{10, .0f, 10.0f}}}); + registry.add("QA/hV0_Sel_TPCNCls", "hV0_Sel_TPCNCls", {HistType::kTH1F, {{200, .0f, 200.0f}}}); + registry.add("QA/hV0_Sel_TPCNClsShared", "hV0_Sel_TPCNClsShared", {HistType::kTH1F, {{150, .0f, 1.5f}}}); + registry.add("QA/hV0_Sel_ITSChi2", "hV0_Sel_ITSChi2", {HistType::kTH1F, {{10, .0f, 10.0f}}}); + registry.add("QA/hV0_Sel_TPCChi2", "hV0_Sel_TPCChi2", {HistType::kTH1F, {{100, .0f, 100.0f}}}); + // K0s + registry.add("QA/hK0s_Sel_ArmenterosPodolanski", "QA/hK0s_ArmenterosPodolanski", {HistType::kTH2F, {{1000, -1.0f, 1.0f, "#alpha"}, {1000, 0.0f, 0.30f, "#it{Q}_{T}"}}}); + registry.add("QA/hK0s_Sel_Rap", "hK0s_Sel_Rap", {HistType::kTH1F, {{100, -1.0f, 1.0f}}}); + registry.add("QA/hK0s_Sel_CosPA", "hK0s_Sel_CosPA", {HistType::kTH1F, {{100, 0.95f, 1.0f}}}); + registry.add("QA/hK0s_Sel_Ctau", "hK0s_Sel_Ctau", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); + registry.add("QA/hK0s_Sel_TPCNSigmaPosPi", "hK0s_Sel_TPCNSigmaPosPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); + registry.add("QA/hK0s_Sel_TPCNSigmaNegPi", "hK0s_Sel_TPCNSigmaNegPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); + // Lambda + registry.add("QA/hLambda_Sel_ArmenterosPodolanski", "QA/hLambda_Sel_ArmenterosPodolanski", {HistType::kTH2F, {{1000, -1.0f, 1.0f, "#alpha"}, {1000, 0.0f, 0.30f, "#it{Q}_{T}"}}}); + registry.add("QA/hLambda_Sel_Rap", "hLambda_Sel_Rap", {HistType::kTH1F, {{100, -1.0f, 1.0f}}}); + registry.add("QA/hLambda_Sel_CosPA", "hLambda_Sel_CosPA", {HistType::kTH1F, {{100, 0.95f, 1.0f}}}); + registry.add("QA/hLambda_Sel_Ctau", "hLambda_Sel_Ctau", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); + registry.add("QA/hLambda_Sel_TPCNSigmaPosPr", "hLambda_Sel_TPCNSigmaPosPr", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); + registry.add("QA/hLambda_Sel_TPCNSigmaNegPi", "hLambda_Sel_TPCNSigmaNegPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); + // AntiLambda + registry.add("QA/hAntiLambda_Sel_ArmenterosPodolanski", "QA/hAntiLambda_Sel_ArmenterosPodolanski", {HistType::kTH2F, {{1000, -1.0f, 1.0f, "#alpha"}, {1000, 0.0f, 0.30f, "#it{Q}_{T}"}}}); + registry.add("QA/hAntiLambda_Sel_Rap", "hAntiLambda_Sel_Rap", {HistType::kTH1F, {{100, -1.0f, 1.0f}}}); + registry.add("QA/hAntiLambda_Sel_CosPA", "hAntiLambda_Sel_CosPA", {HistType::kTH1F, {{100, 0.95f, 1.0f}}}); + registry.add("QA/hAntiLambda_Sel_Ctau", "hAntiLambda_Sel_Ctau", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); + registry.add("QA/hAntiLambda_Sel_TPCNSigmaPosPi", "hAntiLambda_Sel_TPCNSigmaPosPi", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); + registry.add("QA/hAntiLambda_Sel_TPCNSigmaNegPr", "hAntiLambda_Sel_TPCNSigmaNegPr", {HistType::kTH1F, {{100, -10.0f, 10.0f}}}); + } + } + + // V0 selection + template + bool QAK0s(TV0Type const& candidate) + { + if (candidate.v0cospa() <= cospaK0s) + return false; + registry.fill(HIST("QA/hK0sSelection"), 13.5); + + if (candidate.rapk0short() >= rap) + return false; + registry.fill(HIST("QA/hK0sSelection"), 14.5); + + if (candidate.ctauk0short() >= ctauK0s) + return false; + registry.fill(HIST("QA/hK0sSelection"), 15.5); + + if (std::abs(candidate.masslambda() - o2::constants::physics::MassLambda0) <= v0rejK0s) + return false; + registry.fill(HIST("QA/hK0sSelection"), 16.5); + + if (std::abs(candidate.ntpcsigmanegpi()) > ntpcsigma) + return false; + registry.fill(HIST("QA/hK0sSelection"), 17.5); + + if (std::abs(candidate.ntpcsigmapospi()) > ntpcsigma) + return false; + registry.fill(HIST("QA/hK0sSelection"), 18.5); + + if (doArmenterosCut && candidate.qtarm() < (paramArmenterosCut * std::abs(candidate.alpha()))) + return false; + registry.fill(HIST("QA/hK0sSelection"), 19.5); + + return true; + } + + // V0 selection + template + bool AcceptV0(TV0Type const& candidate) + { + if (evSel && candidate.evflag() < 1) + return false; + registry.fill(HIST("QA/hK0sSelection"), 1.5); + + if (candidate.v0radius() < radius && candidate.v0radius() > maxradius) + return false; + registry.fill(HIST("QA/hK0sSelection"), 2.5); + + if (std::abs(candidate.v0poseta()) > etadau) + return false; + if (std::abs(candidate.v0negeta()) > etadau) + return false; + registry.fill(HIST("QA/hK0sSelection"), 3.5); + + if (std::abs(candidate.v0dcanegtopv()) < dcanegtopv) + return false; + if (std::abs(candidate.v0dcapostopv()) < dcapostopv) + return false; + registry.fill(HIST("QA/hK0sSelection"), 4.5); + + if (candidate.v0dcav0daughters() > dcav0dau) + return false; + registry.fill(HIST("QA/hK0sSelection"), 5.5); + + if (candidate.v0positshits() < minITShits) + return false; + if (candidate.v0negitshits() < minITShits) + return false; + registry.fill(HIST("QA/hK0sSelection"), 6.5); + + if (hasTOF1Leg && !candidate.poshastof() && !candidate.neghastof()) + return false; + registry.fill(HIST("QA/hK0sSelection"), 7.5); + + if (hasTOF2Leg && (!candidate.poshastof() || !candidate.neghastof())) + return false; + registry.fill(HIST("QA/hK0sSelection"), 8.5); + + if (candidate.v0postpcCrossedRows() < min_TPC_nClusters) + return false; + if (candidate.v0negtpcCrossedRows() < min_TPC_nClusters) + return false; + registry.fill(HIST("QA/hK0sSelection"), 9.5); + + if (candidate.v0postpcNClsShared() > max_tpcSharedCls) + return false; + if (candidate.v0negtpcNClsShared() > max_tpcSharedCls) + return false; + registry.fill(HIST("QA/hK0sSelection"), 10.5); + + if (candidate.v0positsChi2NCl() > max_chi2_ITS) + return false; + if (candidate.v0negitsChi2NCl() > max_chi2_ITS) + return false; + registry.fill(HIST("QA/hK0sSelection"), 11.5); + + if (candidate.v0postpcChi2NCl() > max_chi2_TPC) + return false; + if (candidate.v0negtpcChi2NCl() > max_chi2_TPC) + return false; + registry.fill(HIST("QA/hK0sSelection"), 12.5); + + return true; } void process(aod::MyV0Candidates const& myv0s) { for (auto& candidate : myv0s) { - // common selections - if (candidate.v0radius() < radius) - continue; - if (TMath::Abs(candidate.v0poseta()) > etadau) - continue; - if (TMath::Abs(candidate.v0negeta()) > etadau) - continue; - if (TMath::Abs(candidate.v0dcanegtopv()) < dcanegtopv) - continue; - if (TMath::Abs(candidate.v0dcapostopv()) < dcapostopv) - continue; - if (candidate.v0dcav0daughters() > dcav0dau) - continue; - if (TMath::Abs(candidate.ntpcsigmanegpi()) > ntpcsigma) - continue; - if (TMath::Abs(candidate.ntpcsigmapospi()) > ntpcsigma) + if (doQA) { + registry.fill(HIST("QA/hK0sSelection"), 0.5); + registry.fill(HIST("QA/hV0_EvFlag"), candidate.evflag()); + registry.fill(HIST("QA/hV0_Radius"), candidate.v0radius()); + registry.fill(HIST("QA/hV0_DCADauToPV"), candidate.v0dcanegtopv()); + registry.fill(HIST("QA/hV0_DCADaughters"), candidate.v0dcav0daughters()); + registry.fill(HIST("QA/hV0_EtaDau"), candidate.v0poseta()); + registry.fill(HIST("QA/hV0_EtaDau"), candidate.v0negeta()); + registry.fill(HIST("QA/hV0_ITShits"), candidate.v0negitshits()); + registry.fill(HIST("QA/hV0_TPCNCls"), candidate.v0postpcCrossedRows()); + registry.fill(HIST("QA/hV0_TPCNCls"), candidate.v0negtpcCrossedRows()); + registry.fill(HIST("QA/hV0_TPCNClsShared"), candidate.v0postpcNClsShared()); + registry.fill(HIST("QA/hV0_TPCNClsShared"), candidate.v0negtpcNClsShared()); + registry.fill(HIST("QA/hV0_ITSChi2"), candidate.v0positsChi2NCl()); + registry.fill(HIST("QA/hV0_ITSChi2"), candidate.v0negitsChi2NCl()); + registry.fill(HIST("QA/hV0_TPCChi2"), candidate.v0postpcChi2NCl()); + registry.fill(HIST("QA/hV0_TPCChi2"), candidate.v0negtpcChi2NCl()); + registry.fill(HIST("QA/hK0s_ArmenterosPodolanski"), candidate.alpha(), candidate.qtarm()); + registry.fill(HIST("QA/hK0s_CosPA"), candidate.v0cospa()); + registry.fill(HIST("QA/hK0s_Rap"), candidate.rapk0short()); + registry.fill(HIST("QA/hK0s_Ctau"), candidate.ctauk0short()); + registry.fill(HIST("QA/hK0s_TPCNSigmaPosPi"), candidate.ntpcsigmapospi()); + registry.fill(HIST("QA/hK0s_TPCNSigmaNegPi"), candidate.ntpcsigmanegpi()); + registry.fill(HIST("QA/hLambda_ArmenterosPodolanski"), candidate.alpha(), candidate.qtarm()); + registry.fill(HIST("QA/hLambda_CosPA"), candidate.v0cospa()); + registry.fill(HIST("QA/hLambda_Rap"), candidate.rapk0short()); + registry.fill(HIST("QA/hLambda_Ctau"), candidate.ctauk0short()); + registry.fill(HIST("QA/hLambda_TPCNSigmaPosPi"), candidate.ntpcsigmapospi()); + registry.fill(HIST("QA/hLambda_TPCNSigmaNegPi"), candidate.ntpcsigmanegpi()); + registry.fill(HIST("QA/hAntiLambda_ArmenterosPodolanski"), candidate.alpha(), candidate.qtarm()); + registry.fill(HIST("QA/hAntiLambda_CosPA"), candidate.v0cospa()); + registry.fill(HIST("QA/hAntiLambda_Rap"), candidate.rapk0short()); + registry.fill(HIST("QA/hAntiLambda_Ctau"), candidate.ctauk0short()); + registry.fill(HIST("QA/hAntiLambda_TPCNSigmaPosPi"), candidate.ntpcsigmapospi()); + registry.fill(HIST("QA/hAntiLambda_TPCNSigmaNegPi"), candidate.ntpcsigmanegpi()); + } + + // Apply common V0 selection + if (!AcceptV0(candidate)) { continue; + } + + QAK0s(candidate); + + if (doQA) { + registry.fill(HIST("QA/hV0_Sel_EvFlag"), candidate.evflag()); + registry.fill(HIST("QA/hV0_Sel_Radius"), candidate.v0radius()); + registry.fill(HIST("QA/hV0_Sel_DCADauToPV"), candidate.v0dcanegtopv()); + registry.fill(HIST("QA/hV0_Sel_DCADaughters"), candidate.v0dcav0daughters()); + registry.fill(HIST("QA/hV0_Sel_EtaDau"), candidate.v0poseta()); + registry.fill(HIST("QA/hV0_Sel_EtaDau"), candidate.v0negeta()); + registry.fill(HIST("QA/hV0_Sel_ITShits"), candidate.v0negitshits()); + registry.fill(HIST("QA/hV0_Sel_ITShits"), candidate.v0positshits()); + registry.fill(HIST("QA/hV0_Sel_TPCNCls"), candidate.v0postpcCrossedRows()); + registry.fill(HIST("QA/hV0_Sel_TPCNCls"), candidate.v0negtpcCrossedRows()); + registry.fill(HIST("QA/hV0_Sel_TPCNClsShared"), candidate.v0postpcNClsShared()); + registry.fill(HIST("QA/hV0_Sel_TPCNClsShared"), candidate.v0negtpcNClsShared()); + registry.fill(HIST("QA/hV0_Sel_ITSChi2"), candidate.v0positsChi2NCl()); + registry.fill(HIST("QA/hV0_Sel_ITSChi2"), candidate.v0negitsChi2NCl()); + registry.fill(HIST("QA/hV0_Sel_TPCChi2"), candidate.v0postpcChi2NCl()); + registry.fill(HIST("QA/hV0_Sel_TPCChi2"), candidate.v0negtpcChi2NCl()); + } + + ////////////////////////////////// + //////////// K0Short ///////////// + ////////////////////////////////// - // K0Short analysis if (candidate.v0cospa() > cospaK0s && - TMath::Abs(candidate.rapk0short()) < rap && + std::abs(candidate.rapk0short()) < rap && candidate.ctauk0short() < ctauK0s && - TMath::Abs(candidate.massk0short() - o2::constants::physics::MassK0Short) < 0.075 && - TMath::Abs(candidate.masslambda() - o2::constants::physics::MassLambda0) > v0rejK0s) { + std::abs(candidate.massk0short() - o2::constants::physics::MassK0Short) < 0.075 && + std::abs(candidate.masslambda() - o2::constants::physics::MassLambda0) > v0rejK0s && + std::abs(candidate.ntpcsigmanegpi()) <= ntpcsigma && + std::abs(candidate.ntpcsigmapospi()) <= ntpcsigma && + (doArmenterosCut && candidate.qtarm() > (paramArmenterosCut * std::abs(candidate.alpha())))) { registry.fill(HIST("hMassK0Short"), candidate.massk0short()); registry.fill(HIST("hMassVsPtK0Short"), candidate.v0pt(), candidate.massk0short()); registry.fill(HIST("hMassVsPtK0ShortVsCentFT0M"), candidate.v0pt(), candidate.multft0m(), candidate.massk0short()); - registry.fill(HIST("hMassVsPtK0ShortVsCentFV0A"), candidate.v0pt(), candidate.multfv0a(), candidate.massk0short()); - - // QA - if (!isMC) { - registry.fill(HIST("hK0sV0Radius"), candidate.v0radius()); - registry.fill(HIST("hK0sCosPA"), candidate.v0cospa()); - registry.fill(HIST("hK0sV0DCANegToPV"), candidate.v0dcanegtopv()); - registry.fill(HIST("hK0sV0DCAPosToPV"), candidate.v0dcapostopv()); - registry.fill(HIST("hK0sV0DCAV0Daughters"), candidate.v0dcav0daughters()); - registry.fill(HIST("hK0sCtau"), candidate.ctauk0short()); - registry.fill(HIST("hK0sEtaDau"), candidate.v0poseta()); - registry.fill(HIST("hK0sRap"), candidate.rapk0short()); - registry.fill(HIST("hK0sTPCNSigmaPosPi"), candidate.ntpcsigmapospi()); - registry.fill(HIST("hK0sTPCNSigmaNegPi"), candidate.ntpcsigmanegpi()); + + if (isMC && + candidate.pdgcode() == 310 && + candidate.isdauk0short() && + candidate.isphysprimary() == 1) { + + registry.fill(HIST("hMassK0Short_MC"), candidate.massk0short()); + registry.fill(HIST("hMassVsPtK0ShortVsCentFT0M_MC"), candidate.v0pt(), candidate.multft0m(), candidate.massk0short()); + } + + if (doQA) { + registry.fill(HIST("QA/hK0s_Sel_ArmenterosPodolanski"), candidate.alpha(), candidate.qtarm()); + registry.fill(HIST("QA/hK0s_Sel_Rap"), candidate.rapk0short()); + registry.fill(HIST("QA/hK0s_Sel_CosPA"), candidate.v0cospa()); + registry.fill(HIST("QA/hK0s_Sel_Ctau"), candidate.ctauk0short()); + registry.fill(HIST("QA/hK0s_Sel_TPCNSigmaPosPi"), candidate.ntpcsigmapospi()); + registry.fill(HIST("QA/hK0s_Sel_TPCNSigmaNegPi"), candidate.ntpcsigmanegpi()); } } - // Lambda analysis - /* if (candidate.v0cospa() > cospaLambda && - TMath::Abs(candidate.raplambda()) < rap && - candidate.ctaulambda() < ctauK0s && - TMath::Abs(candidate.masslambda() - o2::constants::physics::MassLambda0) < 0.075 && - TMath::Abs(candidate.massk0short() - o2::constants::physics::MassK0Short) > v0rejLambda) { - - registry.fill(HIST("hMassLambda"), candidate.masslambda()); - registry.fill(HIST("hMassVsPtLambda"), candidate.v0pt(), candidate.masslambda()); - registry.fill(HIST("hMassVsPtLambdaVsCentFT0M"), candidate.v0pt(), candidate.multft0m(), candidate.masslambda()); - registry.fill(HIST("hMassVsPtLambdaVsCentFV0A"), candidate.v0pt(), candidate.multfv0a(), candidate.masslambda()); - - // QA - if (!isMC) { - registry.fill(HIST("hLambdaV0Radius"), candidate.v0radius()); - registry.fill(HIST("hLambdaCosPA"), candidate.v0cospa()); - registry.fill(HIST("hLambdaV0DCANegToPV"), candidate.v0dcanegtopv()); - registry.fill(HIST("hLambdaV0DCAPosToPV"), candidate.v0dcapostopv()); - registry.fill(HIST("hLambdaV0DCAV0Daughters"), candidate.v0dcav0daughters()); - registry.fill(HIST("hLambdaCtau"), candidate.ctaulambda()); - registry.fill(HIST("hLambdaEtaDau"), candidate.v0poseta()); - registry.fill(HIST("hLambdaRap"), candidate.raplambda()); - registry.fill(HIST("hLambdaTPCNSigmaPosPi"), candidate.ntpcsigmapospi()); - registry.fill(HIST("hLambdaTPCNSigmaPosPr"), candidate.ntpcsigmapospr()); - registry.fill(HIST("hLambdaTPCNSigmaNegPi"), candidate.ntpcsigmanegpi()); - registry.fill(HIST("hLambdaTPCNSigmaNegPr"), candidate.ntpcsigmanegpr()); - } - } - */ - if (isMC) { - - if (candidate.isphysprimary() == 0) - continue; - - // K0Short analysis - if (candidate.v0cospa() > cospaK0s && - TMath::Abs(candidate.rapk0short()) < rap && - candidate.ctauk0short() < ctauK0s && - TMath::Abs(candidate.massk0short() - o2::constants::physics::MassK0Short) < 0.075 && - TMath::Abs(candidate.masslambda() - o2::constants::physics::MassLambda0) > v0rejK0s && - (candidate.pdgcode() == 310)) { + ////////////////////////////////// + ////// Lambda / AntiLambda /////// + ////////////////////////////////// - registry.fill(HIST("hMassK0Short_MC"), candidate.massk0short()); - registry.fill(HIST("hMassVsPtK0Short_MC"), candidate.v0pt(), candidate.massk0short()); - - registry.fill(HIST("hK0sV0Radius"), candidate.v0radius()); - registry.fill(HIST("hK0sCosPA"), candidate.v0cospa()); - registry.fill(HIST("hK0sV0DCANegToPV"), candidate.v0dcanegtopv()); - registry.fill(HIST("hK0sV0DCAPosToPV"), candidate.v0dcapostopv()); - registry.fill(HIST("hK0sV0DCAV0Daughters"), candidate.v0dcav0daughters()); - registry.fill(HIST("hK0sCtau"), candidate.ctauk0short()); - registry.fill(HIST("hK0sEtaDau"), candidate.v0poseta()); - registry.fill(HIST("hK0sRap"), candidate.rapk0short()); - registry.fill(HIST("hK0sTPCNSigmaPosPi"), candidate.ntpcsigmapospi()); - registry.fill(HIST("hK0sTPCNSigmaNegPi"), candidate.ntpcsigmanegpi()); + if (candidate.v0cospa() > cospaLambda && + std::abs(candidate.raplambda()) < rap && + std::abs(candidate.massk0short() - o2::constants::physics::MassK0Short) > v0rejLambda) { + + ////////////////////////////////// + ///////////// Lambda ///////////// + ////////////////////////////////// + + if (std::abs(candidate.ntpcsigmanegpi()) <= ntpcsigma && + std::abs(candidate.ntpcsigmapospr()) <= ntpcsigma && + candidate.ctaulambda() < ctauLambda && + std::abs(candidate.masslambda() - o2::constants::physics::MassLambda0) < 0.075) { + + registry.fill(HIST("hMassLambda"), candidate.masslambda()); + registry.fill(HIST("hMassVsPtLambda"), candidate.v0pt(), candidate.masslambda()); + registry.fill(HIST("hMassVsPtLambdaVsCentFT0M"), candidate.v0pt(), candidate.multft0m(), candidate.masslambda()); + + if (isMC) { + + if (candidate.pdgcode() == 3122 && candidate.isdaulambda()) { + + if (candidate.isphysprimary() == 1) { + registry.fill(HIST("hMassLambda_MC"), candidate.masslambda()); + registry.fill(HIST("hMassVsPtLambdaVsCentFT0M_MC"), candidate.v0pt(), candidate.multft0m(), candidate.masslambda()); + } + + if (candidate.pdgcodemother() == 3312) { + registry.fill(HIST("hMassVsPtLambdaVsMotherPt_DoubleCharged_MC"), candidate.v0pt(), candidate.v0motherpt(), candidate.masslambda()); + } + if (candidate.pdgcodemother() == 3312 || candidate.pdgcodemother() == 3322) { + registry.fill(HIST("hMassVsPtLambdaVsMotherPt_MCRatio_MC"), candidate.v0pt(), candidate.v0motherpt(), candidate.masslambda()); + } + } + } + + if (doQA) { + registry.fill(HIST("QA/hLambda_Sel_ArmenterosPodolanski"), candidate.alpha(), candidate.qtarm()); + registry.fill(HIST("QA/hLambda_Sel_Rap"), candidate.rapk0short()); + registry.fill(HIST("QA/hLambda_Sel_CosPA"), candidate.v0cospa()); + registry.fill(HIST("QA/hLambda_Sel_Ctau"), candidate.ctauk0short()); + registry.fill(HIST("QA/hLambda_Sel_TPCNSigmaPosPr"), candidate.ntpcsigmapospr()); + registry.fill(HIST("QA/hLambda_Sel_TPCNSigmaNegPi"), candidate.ntpcsigmanegpi()); + } + } + + ////////////////////////////////// + /////////// AntiLambda /////////// + ////////////////////////////////// + + if (std::abs(candidate.ntpcsigmanegpr()) <= ntpcsigma && + std::abs(candidate.ntpcsigmapospi()) <= ntpcsigma && + candidate.ctauantilambda() < ctauLambda && + std::abs(candidate.massantilambda() - o2::constants::physics::MassLambda0) < 0.075) { + + registry.fill(HIST("hMassAntiLambda"), candidate.massantilambda()); + registry.fill(HIST("hMassVsPtAntiLambda"), candidate.v0pt(), candidate.massantilambda()); + registry.fill(HIST("hMassVsPtAntiLambdaVsCentFT0M"), candidate.v0pt(), candidate.multft0m(), candidate.massantilambda()); + + if (candidate.pdgcode() == -3122 && candidate.isdauantilambda()) { + + if (candidate.isphysprimary() == 1) { + registry.fill(HIST("hMassAntiLambda_MC"), candidate.massantilambda()); + registry.fill(HIST("hMassVsPtAntiLambdaVsCentFT0M_MC"), candidate.v0pt(), candidate.v0motherpt(), candidate.massantilambda()); + } + + if (candidate.pdgcodemother() == -3312) { + registry.fill(HIST("hMassVsPtAntiLambdaVsMotherPt_DoubleCharged_MC"), candidate.v0pt(), candidate.v0motherpt(), candidate.massantilambda()); + } + if (candidate.pdgcodemother() == -3312 || candidate.pdgcodemother() == -3322) { + registry.fill(HIST("hMassVsPtAntiLambdaVsMotherPt_MCRatio_MC"), candidate.v0pt(), candidate.v0motherpt(), candidate.massantilambda()); + } + } + + if (doQA) { + registry.fill(HIST("QA/hAntiLambda_Sel_ArmenterosPodolanski"), candidate.alpha(), candidate.qtarm()); + registry.fill(HIST("QA/hAntiLambda_Sel_Rap"), candidate.rapk0short()); + registry.fill(HIST("QA/hAntiLambda_Sel_CosPA"), candidate.v0cospa()); + registry.fill(HIST("QA/hAntiLambda_Sel_Ctau"), candidate.ctauk0short()); + registry.fill(HIST("QA/hAntiLambda_Sel_TPCNSigmaPosPi"), candidate.ntpcsigmapospi()); + registry.fill(HIST("QA/hAntiLambda_Sel_TPCNSigmaNegPr"), candidate.ntpcsigmanegpr()); + } } } } diff --git a/PWGLF/Tasks/Strangeness/v0ptinvmassplots.cxx b/PWGLF/Tasks/Strangeness/v0ptinvmassplots.cxx new file mode 100644 index 00000000000..b5f014ffaba --- /dev/null +++ b/PWGLF/Tasks/Strangeness/v0ptinvmassplots.cxx @@ -0,0 +1,580 @@ +// 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 v0ptinvmassplots.cxx +/// \brief V0 task for production of invariant mass plots for Pt Spectrum Analysis +/// \author Nikolaos Karatzenis (nikolaos.karatzenis@cern.ch) +/// \author Roman Lietava (roman.lietava@cern.ch) + +/*Description +This task creates up to 30 histograms that are filled with the V0 invariant mass under the K0, Lambda and Antilambda mass assumption +for different pt ranges (constituting bins). The values are inserted as configurable strings for convinience. +Also feed-down matrices for the Lambda and Anti-Lambda are produced. +This analysis includes three processes, one for Real Data and two for MC at the Generated and Reconstructed level*/ + +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Common/DataModel/EventSelection.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Common/DataModel/PIDResponse.h" +#include "CommonUtils/StringUtils.h" +#include "CommonConstants/PhysicsConstants.h" +#include "TPDGCode.h" + +// namespace to be used for pt plots and bins +namespace pthistos +{ +std::vector> kaonPt; +static std::vector kaonPtBins; +std::vector> lambdaPt; +static std::vector lambdaPtBins; +std::vector> antilambdaPt; +static std::vector antilambdaPtBins; +} // namespace pthistos +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +struct V0PtInvMassPlots { + // Histogram Registries + HistogramRegistry rPtAnalysis{"PtAnalysis", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rKaonshMassPlotsPerPtBin{"KaonshMassPlotsPerPtBin", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rLambdaMassPlotsPerPtBin{"LambdaMassPlotsPerPtBin", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rAntilambdaMassPlotsPerPtBin{"AntilambdaMassPlotsPerPtBin", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rFeeddownMatrices{"FeeddownMatrices", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Configurable for histograms + Configurable nBins{"nBins", 100, "N bins in all histos"}; + Configurable nBinsArmenteros{"nBinsArmenteros", 500, "N bins in Armenteros histos"}; + Configurable nmaxHistograms{"nmaxHistograms", 20, "N Pt Histograms"}; + + // Configurables for Cuts + Configurable cutZVertex{"cutZVertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable nSigmaTPCPion{"nSigmaTPCPion", 4, "nSigmaTPCPion"}; + Configurable nSigmaTPCProton{"nSigmaTPCProton", 4, "nSigmaTPCProton"}; + Configurable compv0masscut{"compv0masscut", 0.01, "CompetitiveV0masscut (GeV)"}; + Configurable etadau{"etadau", 0.8, "Eta Daughters"}; + Configurable rapidityCut{"rapidityCut", 0.5, "V0 Rapidity Window GenMC"}; + + // Configurable Kaonsh Topological Cuts (best cuts determined by v0topologicalcuts task) + Configurable kaonshSettingdcav0dau{"kaonshSettingdcav0dau", 0.3, "DCA V0 Daughters"}; + Configurable kaonshSettingdcapostopv{"kaonshSettingdcapostopv", 0.05, "DCA Pos To PV"}; + Configurable kaonshSettingdcanegtopv{"kaonshSettingdcanegtopv", 0.05, "DCA Neg To PV"}; + Configurable kaonshSettingcosPA{"kaonshSettingcosPA", 0.98, "V0 CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0 + Configurable kaonshSettingradius{"kaonshSettingradius", 0.50, "v0radius"}; + + // Configurable Lambda Topological Cuts (best cuts determined by v0topologicalcuts task) + Configurable lambdaSettingdcav0dau{"lambdaSettingdcav0dau", 0.3, "DCA V0 Daughters"}; + Configurable lambdaSettingdcapostopv{"lambdaSettingdcapostopv", 0.05, "DCA Pos To PV"}; + Configurable lambdaSettingdcanegtopv{"lambdaSettingdcanegtopv", 0.09, "DCA Neg To PV"}; + Configurable lambdaSettingcosPA{"lambdaSettingcosPA", 0.98, "V0 CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0 + Configurable lambdaSettingradius{"lambdaSettingradius", 0.50, "v0radius"}; + + // Configurable Antilambda Topological Cuts (best cuts determined by v0topologicalcuts task) + Configurable antilambdaSettingdcav0dau{"antilambdaSettingdcav0dau", 0.3, "DCA V0 Daughters"}; + Configurable antilambdaSettingdcapostopv{"antilambdaSettingdcapostopv", 0.09, "DCA Pos To PV"}; + Configurable antilambdaSettingdcanegtopv{"antilambdaSettingdcanegtopv", 0.05, "DCA Neg To PV"}; + Configurable antilambdaSettingcosPA{"antilambdaSettingcosPA", 0.98, "V0 CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0 + Configurable antilambdaSettingradius{"antilambdaSettingradius", 0.50, "v0radius"}; + + // Configurables for Specific V0s analysis + Configurable kzeroAnalysis{"kzeroAnalysis", true, "Enable Kzerosh Pt Analysis"}; + Configurable lambdaAnalysis{"lambdaAnalysis", true, "Enable Lambda Pt Analysis"}; + Configurable antiLambdaAnalysis{"antiLambdaAnalysis", true, "Enable Antilambda Pt Analysis"}; + + // Configurable string for Different Pt Bins + Configurable kzeroSettingPtBinsString{"kzeroSettingPtBinsString", {"0.0,0.15,0.3,0.45,0.6,0.75,0.9,1.05,1.2,1.35,1.5,1.65,1.8,1.95,2.1,2.25,2.4,2.55,2.7,2.85,3.0"}, "Kzero Pt Bin Values"}; + Configurable lambdaSettingPtBinsString{"lambdaSettingPtBinsString", {"0.0,0.15,0.3,0.45,0.6,0.75,0.9,1.05,1.2,1.35,1.5,1.65,1.8,1.95,2.1,2.25,2.4,2.55,2.7,2.85,3.0"}, "Lambda Pt Bin Values"}; + Configurable antilambdaSettingPtBinsString{"antilambdaSettingPtBinsString", {"0.0,0.15,0.3,0.45,0.6,0.75,0.9,1.05,1.2,1.35,1.5,1.65,1.8,1.95,2.1,2.25,2.4,2.55,2.7,2.85,3.0"}, "Antilambda Pt Bin Values"}; + + void init(InitContext const&) + { + pthistos::kaonPt.resize(nmaxHistograms); // number of Kaon Pt histograms to expect + pthistos::lambdaPt.resize(nmaxHistograms); // number of Lambda histograms to expect + pthistos::antilambdaPt.resize(nmaxHistograms); // number of Antilambda histograms to expect + // tokenise strings into individual values + pthistos::kaonPtBins = o2::utils::Str::tokenize(kzeroSettingPtBinsString, ','); + pthistos::lambdaPtBins = o2::utils::Str::tokenize(lambdaSettingPtBinsString, ','); + pthistos::antilambdaPtBins = o2::utils::Str::tokenize(antilambdaSettingPtBinsString, ','); + + // initialize and convert tokenized strings into vector of doubles for AxisSpec + std::vector kaonptedgevalues(nmaxHistograms + 1); + std::vector lambdaptedgevalues(nmaxHistograms + 1); + std::vector antilambdaPtedgevalues(nmaxHistograms + 1); + for (int i = 0; i < nmaxHistograms + 1; i++) { + kaonptedgevalues[i] = std::stod(pthistos::kaonPtBins[i]); + lambdaptedgevalues[i] = std::stod(pthistos::lambdaPtBins[i]); + antilambdaPtedgevalues[i] = std::stod(pthistos::antilambdaPtBins[i]); + } + + // Axes + AxisSpec k0ShortMassAxis = {nBins, 0.45f, 0.55f, "#it{M} #pi^{+}#pi^{-} [GeV/#it{c}^{2}]"}; + AxisSpec lambdaMassAxis = {nBins, 1.085f, 1.145f, "#it{M} p^{+}#pi^{-} [GeV/#it{c}^{2}]"}; + AxisSpec antiLambdaMassAxis = {nBins, 1.085f, 1.145f, "#it{M} p^{-}#pi^{+} [GeV/#it{c}^{2}]"}; + AxisSpec k0ShortPtAxis = {kaonptedgevalues, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec lambdaPtAxis = {lambdaptedgevalues, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec antilambdaPtAxis = {antilambdaPtedgevalues, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec armenterosQtAxis = {nBinsArmenteros, 0.0f, 0.3f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec armenterosasymAxis = {nBinsArmenteros, -1.f, 1.f, "#ait{p}^{+}_{||}-it{p}^{-}_{||}/it{p}^{+}_{||}+it{p}^{-}_{||}"}; + AxisSpec vertexZAxis = {nBins, -11.0f, 11.0f, "vrtx_{Z} [cm]"}; + + std::vector kaonhistvalue(nmaxHistograms + 1); + std::vector lambdahistvalue(nmaxHistograms + 1); + std::vector antilambdahistvalue(nmaxHistograms + 1); + // K0short Histogram Pt Bin Edges + for (int i = 0; i < nmaxHistograms + 1; i++) { // Histos won't accept "." character so converting it to "_" + std::string kaonptbin = pthistos::kaonPtBins[i]; // getting the value of the bin edge + size_t pos = kaonptbin.find("."); // finding the "." character + kaonptbin[pos] = '_'; // changing the "." character of thestring-value to a "_" + kaonhistvalue[i] = kaonptbin; // filling bin edges list + } + // Lambda Histograms Pt Bin Edges (same as K0s above) + for (int i = 0; i < nmaxHistograms + 1; i++) { + std::string lambdaptbin = pthistos::lambdaPtBins[i]; + size_t pos = lambdaptbin.find("."); + lambdaptbin[pos] = '_'; + lambdahistvalue[i] = lambdaptbin; + } + // AntiLambda Histograms Pt Bin Edges (same as K0s above) + for (int i = 0; i < nmaxHistograms + 1; i++) { + std::string antilambdaPtbin = pthistos::antilambdaPtBins[i]; + size_t pos = antilambdaPtbin.find("."); + antilambdaPtbin[pos] = '_'; + antilambdahistvalue[i] = antilambdaPtbin; + } + + rPtAnalysis.add("hVertexZ", "hVertexZ", {HistType::kTH1F, {vertexZAxis}}); + rPtAnalysis.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); + rPtAnalysis.add("hArmenterosPodolanskiPlot", "hArmenterosPodolanskiPlot", {HistType::kTH2F, {{armenterosasymAxis}, {armenterosQtAxis}}}); + rPtAnalysis.add("hV0EtaDaughters", "hV0EtaDaughters", {HistType::kTH1F, {{nBins, -1.2f, 1.2f}}}); + rPtAnalysis.add("V0Rapidity", "V0Rapidity", {HistType::kTH1F, {{nBins, -10.0f, 10.0f}}}); + + // Generated Pt Spectrums For Feeddown + rPtAnalysis.add("GenParticleRapidity", "GenParticleRapidity", {HistType::kTH1F, {{nBins, -10.0f, 10.0f}}}); + rPtAnalysis.add("hXiMinusGeneratedPtSpectrum", "hXiMinusGeneratedPtSpectrum", {HistType::kTH1F, {lambdaPtAxis}}); + rPtAnalysis.add("hXiZeroGeneratedPtSpectrum", "hXiZeroGeneratedPtSpectrum", {HistType::kTH1F, {lambdaPtAxis}}); + rPtAnalysis.add("hOmegaGeneratedPtSpectrum", "hOmegaGeneratedPtSpectrum", {HistType::kTH1F, {lambdaPtAxis}}); + rPtAnalysis.add("hXiPlusGeneratedPtSpectrum", "hXiPlusGeneratedPtSpectrum", {HistType::kTH1F, {antilambdaPtAxis}}); + rPtAnalysis.add("hAntiXiZeroGeneratedPtSpectrum", "hAntiXiZeroGeneratedPtSpectrum", {HistType::kTH1F, {antilambdaPtAxis}}); + rPtAnalysis.add("hAntiOmegaGeneratedPtSpectrum", "hAntiOmegaGeneratedPtSpectrum", {HistType::kTH1F, {antilambdaPtAxis}}); + rPtAnalysis.add("hPhiGeneratedPtSpectrum", "hPhiGeneratedPtSpectrum", {HistType::kTH1F, {k0ShortPtAxis}}); + + // Adding Kzerosh Histograms to registry + if (kzeroAnalysis == true) { + rPtAnalysis.add("hK0ShGeneratedPtSpectrum", "hK0ShGeneratedPtSpectrum", {HistType::kTH1F, {k0ShortPtAxis}}); + rPtAnalysis.add("hK0ShortReconstructedPtSpectrum", "hK0ShortReconstructedPtSpectrum", {HistType::kTH1F, {k0ShortPtAxis}}); + rPtAnalysis.add("hMassK0ShortAll", "hMassK0ShortAll", {HistType::kTH1F, {k0ShortMassAxis}}); + rPtAnalysis.add("hK0ShortPtSpectrumBeforeCuts", "hK0ShortPtSpectrumBeforeCuts", {HistType::kTH1F, {k0ShortPtAxis}}); + rPtAnalysis.add("hMassK0ShortAllAfterCuts", "hMassK0ShortAllAfterCuts", {HistType::kTH1F, {k0ShortMassAxis}}); + rPtAnalysis.add("hNSigmaPosPiFromK0s", "hNSigmaPosPiFromK0s", {HistType::kTH2F, {{100, -5.f, 5.f}, {k0ShortPtAxis}}}); + rPtAnalysis.add("hNSigmaNegPiFromK0s", "hNSigmaNegPiFromK0s", {HistType::kTH2F, {{100, -5.f, 5.f}, {k0ShortPtAxis}}}); + rPtAnalysis.add("hK0shEtaDaughters", "hK0shEtaDaughters", {HistType::kTH1F, {{nBins, -1.2f, 1.2f}}}); + rPtAnalysis.add("hArmenterosPodolanskiPlotK0Short", "hArmenterosPodolanskiPlotK0Short", {HistType::kTH2F, {{armenterosasymAxis}, {armenterosQtAxis}}}); + rPtAnalysis.add("hK0shNegDaughterPt", "hK0shNegDaughterPt", {HistType::kTH1F, {k0ShortPtAxis}}); + rPtAnalysis.add("hK0shPosDaughterPt", "hK0shPosDaughterPt", {HistType::kTH1F, {k0ShortPtAxis}}); + + for (int i = 0; i < nmaxHistograms; i++) { + pthistos::kaonPt[i] = rKaonshMassPlotsPerPtBin.add(fmt::format("hPt_from_{0}_to_{1}", kaonhistvalue[i], kaonhistvalue[i + 1]).c_str(), fmt::format("hPt_from_{0}_to_{1}", kaonhistvalue[i], kaonhistvalue[i + 1]).c_str(), {HistType::kTH1D, {{k0ShortMassAxis}}}); + } + } + // Adding Lambda Histograms + if (lambdaAnalysis == true) { + // same method as in Kzerosh above + rPtAnalysis.add("hLambdaGeneratedPtSpectrum", "hLambdaGeneratedPtSpectrum", {HistType::kTH1F, {lambdaPtAxis}}); + rPtAnalysis.add("hLambdaReconstructedPtSpectrum", "hLambdaReconstructedPtSpectrum", {HistType::kTH1F, {lambdaPtAxis}}); + rPtAnalysis.add("hMassLambdaAll", "hMassLambdaAll", {HistType::kTH1F, {lambdaMassAxis}}); + rPtAnalysis.add("hLambdaPtSpectrumBeforeCuts", "hLambdaPtSpectrumBeforeCuts", {HistType::kTH1F, {lambdaPtAxis}}); + rPtAnalysis.add("hMassLambdaAllAfterCuts", "hMassLambdaAllAfterCuts", {HistType::kTH1F, {lambdaMassAxis}}); + rPtAnalysis.add("hNSigmaPosProtonFromLambda", "hNSigmaPosProtonFromLambda", {HistType::kTH2F, {{100, -5.f, 5.f}, {lambdaPtAxis}}}); + rPtAnalysis.add("hNSigmaNegPionFromLambda", "hNSigmaNegPionFromLambda", {HistType::kTH2F, {{100, -5.f, 5.f}, {lambdaPtAxis}}}); + rPtAnalysis.add("hLambdaEtaDaughters", "hLambdaEtaDaughters", {HistType::kTH1F, {{nBins, -1.2f, 1.2f}}}); + rPtAnalysis.add("hArmenterosPodolanskiPlotLambda", "hArmenterosPodolanskiPlotLambda", {HistType::kTH2F, {{armenterosasymAxis}, {armenterosQtAxis}}}); + rPtAnalysis.add("hLambdaNegDaughterPt", "hLambdaNegDaughterPt", {HistType::kTH1F, {lambdaPtAxis}}); + rPtAnalysis.add("hLambdaPosDaughterPt", "hLambdaPosDaughterPt", {HistType::kTH1F, {lambdaPtAxis}}); + for (int i = 0; i < nmaxHistograms; i++) { + pthistos::lambdaPt[i] = rLambdaMassPlotsPerPtBin.add(fmt::format("hPt_from_{0}_to_{1}", lambdahistvalue[i], lambdahistvalue[i + 1]).c_str(), fmt::format("hPt_from_{0}_to_{1}", lambdahistvalue[i], lambdahistvalue[i + 1]).c_str(), {HistType::kTH1D, {{lambdaMassAxis}}}); + } + // lambdafeeddown matrices + rFeeddownMatrices.add("hLambdaXiMinusFeeddownMatrix", "hLambdaXiMinusFeeddownMatrix", {HistType::kTH2F, {{lambdaPtAxis}, {lambdaPtAxis}}}); + rFeeddownMatrices.add("hLambdaXiZeroFeeddownMatrix", "hLambdaXiZeroFeeddownMatrix", {HistType::kTH2F, {{lambdaPtAxis}, {lambdaPtAxis}}}); + rFeeddownMatrices.add("hLambdaOmegaFeeddownMatrix", "hLambdaOmegaFeeddownMatrix", {HistType::kTH2F, {{lambdaPtAxis}, {lambdaPtAxis}}}); + } + // Adding Antilambda Histograms + if (antiLambdaAnalysis == true) { + // same method as in Lambda and Kzerosh above + rPtAnalysis.add("hAntilambdaGeneratedPtSpectrum", "hAntilambdaGeneratedPtSpectrum", {HistType::kTH1F, {{antilambdaPtAxis}}}); + rPtAnalysis.add("hAntilambdaReconstructedPtSpectrum", "hAntilambdaReconstructedPtSpectrum", {HistType::kTH1F, {antilambdaPtAxis}}); + rPtAnalysis.add("hMassAntilambdaAll", "hMassAntilambdaAll", {HistType::kTH1F, {antiLambdaMassAxis}}); + rPtAnalysis.add("hantilambdaPtSpectrumBeforeCuts", "hantilambdaPtSpectrumBeforeCuts", {HistType::kTH1F, {antilambdaPtAxis}}); + rPtAnalysis.add("hMassAntilambdaAllAfterCuts", "hMassAntilambdaAllAfterCuts", {HistType::kTH1F, {antiLambdaMassAxis}}); + rPtAnalysis.add("hNSigmaNegProtonFromAntilambda", "hNSigmaNegProtonFromAntilambda", {HistType::kTH2F, {{100, -5.f, 5.f}, {antilambdaPtAxis}}}); + rPtAnalysis.add("hNSigmaPosPionFromAntilambda", "hNSigmaPosPionFromAntilambda", {HistType::kTH2F, {{100, -5.f, 5.f}, {antilambdaPtAxis}}}); + rPtAnalysis.add("hAntiLambdaEtaDaughters", "hAntiLambdaEtaDaughters", {HistType::kTH1F, {{nBins, -1.2f, 1.2f}}}); + rPtAnalysis.add("hArmenterosPodolanskiPlotAntiLambda", "hArmenterosPodolanskiPlotAntiLambda", {HistType::kTH2F, {{armenterosasymAxis}, {armenterosQtAxis}}}); + rPtAnalysis.add("hAntiLambdaNegDaughterPt", "hAntiLambdaNegDaughterPt", {HistType::kTH1F, {antilambdaPtAxis}}); + rPtAnalysis.add("hAntiLambdaPosDaughterPt", "hAntiLambdaPosDaughterPt", {HistType::kTH1F, {antilambdaPtAxis}}); + for (int i = 0; i < nmaxHistograms; i++) { + pthistos::antilambdaPt[i] = rAntilambdaMassPlotsPerPtBin.add(fmt::format("hPt_from_{0}_to_{1}", antilambdahistvalue[i], antilambdahistvalue[i + 1]).c_str(), fmt::format("hPt_from_{0}_to_{1}", antilambdahistvalue[i], antilambdahistvalue[i + 1]).c_str(), {HistType::kTH1D, {{antiLambdaMassAxis}}}); + } + // antilambdafeeddown matrices + rFeeddownMatrices.add("hAntiLambdaXiPlusFeeddownMatrix", "hAntiLambdaXiPlusFeeddownMatrix", {HistType::kTH2F, {{antilambdaPtAxis}, {antilambdaPtAxis}}}); + rFeeddownMatrices.add("hAntiLambdaAntiXiZeroFeeddownMatrix", "hAntiLambdaAntiXiZeroFeeddownMatrix", {HistType::kTH2F, {{antilambdaPtAxis}, {antilambdaPtAxis}}}); + rFeeddownMatrices.add("hAntiLambdaAntiOmegaFeeddownMatrix", "hAntiLambdaAntiOmegaPlusFeeddownMatrix", {HistType::kTH2F, {{antilambdaPtAxis}, {antilambdaPtAxis}}}); + } + } + + // Defining filters for events (event selection) + // Processed events will be already fulfilling the event selection requirements + Filter eventFilter = (o2::aod::evsel::sel8 == true); + Filter posZFilterMC = (nabs(o2::aod::mccollision::posZ) < cutZVertex); + Filter posZFilter = (nabs(o2::aod::collision::posZ) < cutZVertex); + + // Defining the type of the daughter tracks + using DaughterTracks = soa::Join; + + // This is the Process for the MC Generated Data + void genMCProcess(soa::Filtered::iterator const&, + const soa::SmallGroups>&, + aod::McParticles const& mcParticles) + { + for (const auto& mcParticle : mcParticles) { + if (std::abs(mcParticle.y()) < rapidityCut) { + if (mcParticle.isPhysicalPrimary()) { + rPtAnalysis.fill(HIST("GenParticleRapidity"), mcParticle.y()); + if (mcParticle.pdgCode() == kK0Short) // kzero matched + { + rPtAnalysis.fill(HIST("hK0ShGeneratedPtSpectrum"), mcParticle.pt()); + } + if (mcParticle.pdgCode() == kLambda0) // lambda matched + { + rPtAnalysis.fill(HIST("hLambdaGeneratedPtSpectrum"), mcParticle.pt()); + } + if (mcParticle.pdgCode() == kLambda0Bar) // antilambda matched + { + rPtAnalysis.fill(HIST("hAntilambdaGeneratedPtSpectrum"), mcParticle.pt()); + } + if (mcParticle.pdgCode() == kXiMinus) // Xi Minus matched + { + rPtAnalysis.fill(HIST("hXiMinusGeneratedPtSpectrum"), mcParticle.pt()); + } + if (mcParticle.pdgCode() == kXi0) // Xi Zero matched + { + rPtAnalysis.fill(HIST("hXiZeroGeneratedPtSpectrum"), mcParticle.pt()); + } + if (mcParticle.pdgCode() == kOmegaMinus) // Omega matched + { + rPtAnalysis.fill(HIST("hOmegaGeneratedPtSpectrum"), mcParticle.pt()); + } + if (mcParticle.pdgCode() == kXiPlusBar) // Xi Plus matched + { + rPtAnalysis.fill(HIST("hXiPlusGeneratedPtSpectrum"), mcParticle.pt()); + } + if (mcParticle.pdgCode() == -kXi0) // Anti-Xi Zero matched + { + rPtAnalysis.fill(HIST("hAntiXiZeroGeneratedPtSpectrum"), mcParticle.pt()); + } + if (mcParticle.pdgCode() == kOmegaPlusBar) // Anti-Omega matched + { + rPtAnalysis.fill(HIST("hAntiOmegaGeneratedPtSpectrum"), mcParticle.pt()); + } + if (mcParticle.pdgCode() == kPhi) // Anti-Omega matched + { + rPtAnalysis.fill(HIST("hPhiGeneratedPtSpectrum"), mcParticle.pt()); + } + } + } + } + } + // This is the Process for the MC reconstructed Data + void recMCProcess(soa::Filtered>::iterator const& collision, + soa::Join const& V0s, + DaughterTracks const&, // no need to define a variable for tracks, if we don't access them directly + aod::McParticles const&) + { + // PDG mass values for Competitive V0 Cut old: const auto& mK0shPDG = 0.497611; + double mK0shPDG = o2::constants::physics::MassK0Short; + double mLambdaPDG = o2::constants::physics::MassLambda0; + + // tokenise strings into individual values + pthistos::kaonPtBins = o2::utils::Str::tokenize(kzeroSettingPtBinsString, ','); + pthistos::lambdaPtBins = o2::utils::Str::tokenize(lambdaSettingPtBinsString, ','); + pthistos::antilambdaPtBins = o2::utils::Str::tokenize(antilambdaSettingPtBinsString, ','); + + // initialize and convert tokenized strings into vector of doubles for Pt Bin Edges + std::vector kaonptedgevalues(nmaxHistograms + 1); + std::vector lambdaptedgevalues(nmaxHistograms + 1); + std::vector antilambdaPtedgevalues(nmaxHistograms + 1); + + for (int i = 0; i < nmaxHistograms + 1; i++) { + kaonptedgevalues[i] = std::stod(pthistos::kaonPtBins[i]); + lambdaptedgevalues[i] = std::stod(pthistos::lambdaPtBins[i]); + antilambdaPtedgevalues[i] = std::stod(pthistos::antilambdaPtBins[i]); + } + rPtAnalysis.fill(HIST("hVertexZ"), collision.posZ()); + for (const auto& v0 : V0s) { + rPtAnalysis.fill(HIST("hVertexZRec"), collision.posZ()); + // Checking that the V0 is a true K0s/Lambdas/Antilambdas and then filling the parameter histograms and the invariant mass plots for different cuts (which are taken from namespace) + if (v0.has_mcParticle()) { + auto v0mcParticle = v0.mcParticle(); + if (std::abs(v0mcParticle.y()) < rapidityCut) { + rPtAnalysis.fill(HIST("V0Rapidity"), v0.y()); + if (std::abs(v0.posTrack_as().eta()) < etadau && std::abs(v0.negTrack_as().eta()) < etadau) { // daughters pseudorapidityCut cut + rPtAnalysis.fill(HIST("hV0EtaDaughters"), v0.negTrack_as().eta()); + rPtAnalysis.fill(HIST("hV0EtaDaughters"), v0.posTrack_as().eta()); + if (kzeroAnalysis == true) { + if (v0mcParticle.pdgCode() == kK0Short) { // kzero matched + rPtAnalysis.fill(HIST("hMassK0ShortAll"), v0.mK0Short()); + rPtAnalysis.fill(HIST("hK0ShortPtSpectrumBeforeCuts"), v0.pt()); + if (std::abs(v0.mLambda() - mLambdaPDG) > compv0masscut && std::abs(v0.mAntiLambda() - mLambdaPDG) > compv0masscut) { // Kzero competitive v0 mass cut (cut out Lambdas and Anti-Lambdas) + // Implementing best kzero topological cuts + if (v0.v0cosPA() > kaonshSettingcosPA && v0.dcaV0daughters() < kaonshSettingdcav0dau && v0.v0radius() > kaonshSettingradius && std::abs(v0.dcapostopv()) > kaonshSettingdcapostopv && std::abs(v0.dcanegtopv()) > kaonshSettingdcanegtopv) { + rPtAnalysis.fill(HIST("hMassK0ShortAllAfterCuts"), v0.mK0Short()); + rPtAnalysis.fill(HIST("hK0ShortReconstructedPtSpectrum"), v0.pt()); + rPtAnalysis.fill(HIST("hK0shEtaDaughters"), v0.negTrack_as().eta()); + rPtAnalysis.fill(HIST("hK0shEtaDaughters"), v0.posTrack_as().eta()); + rPtAnalysis.fill(HIST("hK0shNegDaughterPt"), v0.negTrack_as().pt()); // Neg Daughter Pt + rPtAnalysis.fill(HIST("hK0shPosDaughterPt"), v0.posTrack_as().pt()); // Pos Daughter Pt + if (v0mcParticle.isPhysicalPrimary()) { + for (int i = 0; i < nmaxHistograms; i++) { + if (kaonptedgevalues[i] <= v0.pt() && v0.pt() < kaonptedgevalues[i + 1]) { // finding v0s with pt within the range of our bin edges + pthistos::kaonPt[i]->Fill(v0.mK0Short()); // filling the k0s namespace histograms + } + } + } + } + } + } + } + // lambda analysis + if (lambdaAnalysis == true) { + if (v0mcParticle.pdgCode() == kLambda0) { // lambda matched + rPtAnalysis.fill(HIST("hMassLambdaAll"), v0.mLambda()); + rPtAnalysis.fill(HIST("hLambdaPtSpectrumBeforeCuts"), v0.pt()); + if (std::abs(v0.mK0Short() - mK0shPDG) > compv0masscut) { // lambda competitive v0 mass cut (cut out Kaons) + // Implementing best lambda cuts + if (v0.v0cosPA() > lambdaSettingcosPA && v0.dcaV0daughters() < lambdaSettingdcav0dau && v0.v0radius() > lambdaSettingradius && std::abs(v0.dcapostopv()) > lambdaSettingdcapostopv && std::abs(v0.dcanegtopv()) > lambdaSettingdcanegtopv) { + rPtAnalysis.fill(HIST("hMassLambdaAllAfterCuts"), v0.mLambda()); + rPtAnalysis.fill(HIST("hLambdaReconstructedPtSpectrum"), v0.pt()); + rPtAnalysis.fill(HIST("hLambdaEtaDaughters"), v0.negTrack_as().eta()); + rPtAnalysis.fill(HIST("hLambdaEtaDaughters"), v0.posTrack_as().eta()); + rPtAnalysis.fill(HIST("hLambdaNegDaughterPt"), v0.negTrack_as().pt()); // Neg Daughter Pt + rPtAnalysis.fill(HIST("hLambdaPosDaughterPt"), v0.posTrack_as().pt()); // Pos Daughter Pt + if (v0mcParticle.isPhysicalPrimary()) { + for (int i = 0; i < nmaxHistograms; i++) { + if (lambdaptedgevalues[i] <= v0.pt() && v0.pt() < lambdaptedgevalues[i + 1]) { + pthistos::lambdaPt[i]->Fill(v0.mLambda()); + } + } + } + if (!v0mcParticle.isPhysicalPrimary()) { + auto v0mothers = v0mcParticle.mothers_as(); // Get mothers + if (!v0mothers.empty()) { + auto& v0mcParticleMother = v0mothers.front(); // First mother + if (v0mcParticleMother.pdgCode() == kXiMinus) // Xi Minus Mother Matched + { + rFeeddownMatrices.fill(HIST("hLambdaXiMinusFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt()); + } + if (v0mcParticleMother.pdgCode() == kXi0) // Xi Zero Mother Matched + { + rFeeddownMatrices.fill(HIST("hLambdaXiZeroFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt()); + } + if (v0mcParticleMother.pdgCode() == kOmegaMinus) // Omega Mother Matched + { + rFeeddownMatrices.fill(HIST("hLambdaOmegaFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt()); + } + } + } + } + } + } + } + // antilambda analysis + if (antiLambdaAnalysis == true) { + if (v0mcParticle.pdgCode() == kLambda0Bar) { // antilambda matched + rPtAnalysis.fill(HIST("hMassAntilambdaAll"), v0.mAntiLambda()); + rPtAnalysis.fill(HIST("hantilambdaPtSpectrumBeforeCuts"), v0.pt()); + if (std::abs(v0.mK0Short() - mK0shPDG) > compv0masscut) { // antilambda competitive v0 mass cut (cut out Kaons) + // Implementing best antilambda cuts + if (v0.v0cosPA() > antilambdaSettingcosPA && v0.dcaV0daughters() < antilambdaSettingdcav0dau && v0.v0radius() > antilambdaSettingradius && std::abs(v0.dcapostopv()) > antilambdaSettingdcapostopv && std::abs(v0.dcanegtopv()) > antilambdaSettingdcanegtopv) { + rPtAnalysis.fill(HIST("hMassAntilambdaAllAfterCuts"), v0.mAntiLambda()); + rPtAnalysis.fill(HIST("hAntilambdaReconstructedPtSpectrum"), v0.pt()); + rPtAnalysis.fill(HIST("hAntiLambdaEtaDaughters"), v0.negTrack_as().eta()); + rPtAnalysis.fill(HIST("hAntiLambdaEtaDaughters"), v0.posTrack_as().eta()); + rPtAnalysis.fill(HIST("hAntiLambdaNegDaughterPt"), v0.negTrack_as().pt()); // Neg Daughter Pt + rPtAnalysis.fill(HIST("hAntiLambdaPosDaughterPt"), v0.posTrack_as().pt()); // Pos Daughter Pt + if (v0mcParticle.isPhysicalPrimary()) { + for (int i = 0; i < nmaxHistograms; i++) { + if (antilambdaPtedgevalues[i] <= v0.pt() && v0.pt() < antilambdaPtedgevalues[i + 1]) { + pthistos::antilambdaPt[i]->Fill(v0.mAntiLambda()); + } + } + } + if (!v0mcParticle.isPhysicalPrimary()) { + auto v0mothers = v0mcParticle.mothers_as(); // Get mothers + if (!v0mothers.empty()) { + auto& v0mcParticleMother = v0mothers.front(); // First mother + if (v0mcParticleMother.pdgCode() == kXiPlusBar) // Xi Plus Mother Matched + { + rFeeddownMatrices.fill(HIST("hAntiLambdaXiPlusFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt()); + } + if (v0mcParticleMother.pdgCode() == -kXi0) // Anti-Xi Zero Mother Matched + { + rFeeddownMatrices.fill(HIST("hAntiLambdaAntiXiZeroFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt()); + } + if (v0mcParticleMother.pdgCode() == kOmegaPlusBar) // Anti-Omega (minus) Mother Matched + { + rFeeddownMatrices.fill(HIST("hAntiLambdaAntiOmegaFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt()); + } + } + } + } + } + } + } + } + } + } + } + } + // This is the process for Real Data + void dataProcess(soa::Filtered>::iterator const& collision, + aod::V0Datas const& V0s, + DaughterTracks const&) + { + double mK0shPDG = o2::constants::physics::MassK0Short; + double mLambdaPDG = o2::constants::physics::MassLambda0; + + // tokenise strings into individual values + pthistos::kaonPtBins = o2::utils::Str::tokenize(kzeroSettingPtBinsString, ','); + pthistos::lambdaPtBins = o2::utils::Str::tokenize(lambdaSettingPtBinsString, ','); + pthistos::antilambdaPtBins = o2::utils::Str::tokenize(antilambdaSettingPtBinsString, ','); + + // initialize and convert tokenized strings into vector of doubles for pt bin edges + std::vector kaonptedgevalues(nmaxHistograms + 1); + std::vector lambdaptedgevalues(nmaxHistograms + 1); + std::vector antilambdaPtedgevalues(nmaxHistograms + 1); + for (int i = 0; i < nmaxHistograms + 1; i++) { + kaonptedgevalues[i] = std::stod(pthistos::kaonPtBins[i]); + lambdaptedgevalues[i] = std::stod(pthistos::lambdaPtBins[i]); + antilambdaPtedgevalues[i] = std::stod(pthistos::antilambdaPtBins[i]); + } + rPtAnalysis.fill(HIST("hVertexZ"), collision.posZ()); + for (const auto& v0 : V0s) { + const auto& posDaughterTrack = v0.posTrack_as(); + const auto& negDaughterTrack = v0.negTrack_as(); + // Armenteros-Podolandski Plot Values + double pv0 = std::sqrt((v0.px() * v0.px()) + (v0.py() * v0.py()) + (v0.pz() * v0.pz())); + double pposdauparallelv0 = ((v0.posTrack_as().px() * v0.px()) + (v0.posTrack_as().py() * v0.py()) + (v0.posTrack_as().pz() * v0.pz())) / pv0; + double qValue = std::sqrt(((v0.posTrack_as().px() * v0.posTrack_as().px()) + (v0.posTrack_as().py() * v0.posTrack_as().py()) + (v0.posTrack_as().pz() * v0.posTrack_as().pz())) - (pposdauparallelv0 * pposdauparallelv0)); + double plpos = (v0.posTrack_as().px() * v0.px() / pv0) + (v0.posTrack_as().py() * v0.py() / pv0) + (v0.posTrack_as().pz() * v0.pz() / pv0); + double plneg = (v0.negTrack_as().px() * v0.px() / pv0) + (v0.negTrack_as().py() * v0.py() / pv0) + (v0.negTrack_as().pz() * v0.pz() / pv0); + double aValue = (plpos - plneg) / (plpos + plneg); + rPtAnalysis.fill(HIST("hArmenterosPodolanskiPlot"), aValue, qValue); + rPtAnalysis.fill(HIST("hVertexZRec"), collision.posZ()); + if (std::abs(v0.y()) < rapidityCut) { + rPtAnalysis.fill(HIST("V0Rapidity"), v0.y()); + if (std::abs(v0.posTrack_as().eta()) < etadau && std::abs(v0.negTrack_as().eta()) < etadau) { // daughters pseudorapidityCut cut + rPtAnalysis.fill(HIST("hV0EtaDaughters"), v0.negTrack_as().eta()); + rPtAnalysis.fill(HIST("hV0EtaDaughters"), v0.posTrack_as().eta()); + // kzero analysis + if (kzeroAnalysis == true) { + // Filling the five Kzero invariant mass plots for different cuts (which are taken from namespace), for full explanation see the first kzero cut filling in the MC process + rPtAnalysis.fill(HIST("hMassK0ShortAll"), v0.mK0Short()); + if (std::abs(v0.mLambda() - mLambdaPDG) > compv0masscut && std::abs(v0.mAntiLambda() - mLambdaPDG) > compv0masscut) { // antilambda competitive v0 mass cut (cut out Lambdas and Anti-Lambdas) + // Implementing best kzero cuts + if (std::abs(posDaughterTrack.tpcNSigmaPi()) < nSigmaTPCPion && std::abs(negDaughterTrack.tpcNSigmaPi()) < nSigmaTPCPion) { // TPC PID on daughter pions + rPtAnalysis.fill(HIST("hNSigmaPosPiFromK0s"), posDaughterTrack.tpcNSigmaPi(), posDaughterTrack.tpcInnerParam()); + rPtAnalysis.fill(HIST("hNSigmaNegPiFromK0s"), negDaughterTrack.tpcNSigmaPi(), negDaughterTrack.tpcInnerParam()); + if (v0.v0cosPA() > kaonshSettingcosPA && v0.dcaV0daughters() < kaonshSettingdcav0dau && v0.v0radius() > kaonshSettingradius && std::abs(v0.dcapostopv()) > kaonshSettingdcapostopv && std::abs(v0.dcanegtopv()) > kaonshSettingdcanegtopv) { + rPtAnalysis.fill(HIST("hMassK0ShortAllAfterCuts"), v0.mK0Short()); + rPtAnalysis.fill(HIST("hK0shEtaDaughters"), v0.negTrack_as().eta()); + rPtAnalysis.fill(HIST("hK0shEtaDaughters"), v0.posTrack_as().eta()); + rPtAnalysis.fill(HIST("hArmenterosPodolanskiPlotK0Short"), aValue, qValue); + rPtAnalysis.fill(HIST("hK0shNegDaughterPt"), v0.negTrack_as().pt()); // Neg Daughter Pt + rPtAnalysis.fill(HIST("hK0shPosDaughterPt"), v0.posTrack_as().pt()); // Pos Daughter Pt + for (int i = 0; i < nmaxHistograms; i++) { + if (kaonptedgevalues[i] <= v0.pt() && v0.pt() < kaonptedgevalues[i + 1]) { + pthistos::kaonPt[i]->Fill(v0.mK0Short()); + } + } + } + } + } + } + // lambda analysis + if (lambdaAnalysis == true) { + // Filling the five lambda invariant mass plots for different cuts (which are taken from namespace), for full explanation see the first kzero cut filling in the MC process + rPtAnalysis.fill(HIST("hMassLambdaAll"), v0.mLambda()); + if (std::abs(v0.mK0Short() - mK0shPDG) > compv0masscut) { // lambda competitive v0 mass cut (cut out Kaons) + if (std::abs(posDaughterTrack.tpcNSigmaPr()) < nSigmaTPCProton && std::abs(negDaughterTrack.tpcNSigmaPi()) < nSigmaTPCPion) { // TPC PID on daughter pion and proton for Lambda + rPtAnalysis.fill(HIST("hNSigmaPosProtonFromLambda"), posDaughterTrack.tpcNSigmaPr(), posDaughterTrack.tpcInnerParam()); + rPtAnalysis.fill(HIST("hNSigmaNegPionFromLambda"), negDaughterTrack.tpcNSigmaPi(), negDaughterTrack.tpcInnerParam()); + // Implementing best lambda cuts + if (v0.v0cosPA() > lambdaSettingcosPA && v0.dcaV0daughters() < lambdaSettingdcav0dau && v0.v0radius() > lambdaSettingradius && std::abs(v0.dcapostopv()) > lambdaSettingdcapostopv && std::abs(v0.dcanegtopv()) > lambdaSettingdcanegtopv) { + rPtAnalysis.fill(HIST("hMassLambdaAllAfterCuts"), v0.mLambda()); + rPtAnalysis.fill(HIST("hLambdaEtaDaughters"), v0.negTrack_as().eta()); + rPtAnalysis.fill(HIST("hLambdaEtaDaughters"), v0.posTrack_as().eta()); + rPtAnalysis.fill(HIST("hArmenterosPodolanskiPlotLambda"), aValue, qValue); + rPtAnalysis.fill(HIST("hLambdaNegDaughterPt"), v0.negTrack_as().pt()); // Neg Daughter Pt + rPtAnalysis.fill(HIST("hLambdaPosDaughterPt"), v0.posTrack_as().pt()); // Pos Daughter Pt + for (int i = 0; i < nmaxHistograms; i++) { + if (lambdaptedgevalues[i] <= v0.pt() && v0.pt() < lambdaptedgevalues[i + 1]) { + pthistos::lambdaPt[i]->Fill(v0.mLambda()); + } + } + } + } + } + } + // anti-lambda analysis + if (antiLambdaAnalysis == true) { + // Filling the five Antilambda invariant mass plots for different cuts (which are taken from namespace), for full explanation see the first kzero cut filling in the MC process + rPtAnalysis.fill(HIST("hMassAntilambdaAll"), v0.mAntiLambda()); + if (std::abs(v0.mK0Short() - mK0shPDG) > compv0masscut) { // antilambda competitive v0 mass cut (cut out Kaons) + if (std::abs(negDaughterTrack.tpcNSigmaPr()) < nSigmaTPCProton && std::abs(posDaughterTrack.tpcNSigmaPi()) < nSigmaTPCPion) { // TPC PID on daughter pion and proton for AntiLambda + rPtAnalysis.fill(HIST("hNSigmaPosPionFromAntilambda"), posDaughterTrack.tpcNSigmaPi(), posDaughterTrack.tpcInnerParam()); + rPtAnalysis.fill(HIST("hNSigmaNegProtonFromAntilambda"), negDaughterTrack.tpcNSigmaPr(), negDaughterTrack.tpcInnerParam()); + // implementing best antilambda cuts + if (v0.v0cosPA() > antilambdaSettingcosPA && v0.dcaV0daughters() < antilambdaSettingdcav0dau && v0.v0radius() > antilambdaSettingradius && std::abs(v0.dcapostopv()) > antilambdaSettingdcapostopv && std::abs(v0.dcanegtopv()) > antilambdaSettingdcanegtopv) { + rPtAnalysis.fill(HIST("hMassAntilambdaAllAfterCuts"), v0.mAntiLambda()); + rPtAnalysis.fill(HIST("hAntiLambdaEtaDaughters"), v0.negTrack_as().eta()); + rPtAnalysis.fill(HIST("hAntiLambdaEtaDaughters"), v0.posTrack_as().eta()); + rPtAnalysis.fill(HIST("hArmenterosPodolanskiPlotAntiLambda"), aValue, qValue); + rPtAnalysis.fill(HIST("hAntiLambdaNegDaughterPt"), v0.negTrack_as().pt()); // Neg Daughter Pt + rPtAnalysis.fill(HIST("hAntiLambdaPosDaughterPt"), v0.posTrack_as().pt()); // Pos Daughter Pt + for (int i = 0; i < nmaxHistograms; i++) { + if (lambdaptedgevalues[i] <= v0.pt() && v0.pt() < lambdaptedgevalues[i + 1]) { + pthistos::antilambdaPt[i]->Fill(v0.mAntiLambda()); + } + } + } + } + } + } + } + } + } + } + PROCESS_SWITCH(V0PtInvMassPlots, genMCProcess, "Process Run 3 MC Generated", false); + PROCESS_SWITCH(V0PtInvMassPlots, recMCProcess, "Process Run 3 MC Reconstructed", false); + PROCESS_SWITCH(V0PtInvMassPlots, dataProcess, "Process Run 3 Data,", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Strangeness/v0topologicalcuts.cxx b/PWGLF/Tasks/Strangeness/v0topologicalcuts.cxx new file mode 100644 index 00000000000..fd351646bee --- /dev/null +++ b/PWGLF/Tasks/Strangeness/v0topologicalcuts.cxx @@ -0,0 +1,685 @@ +// 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 v0topologicalcuts.cxx +/// \brief V0 task for production of invariant mass plots for Optimised Topological Cuts Analysis +/// \author Nikolaos Karatzenis (nikolaos.karatzenis@cern.ch) +/// \author Roman Lietava (roman.lietava@cern.ch) + +/*Description +This task creates <=20 histograms (for each of the 5 different V0 topological cuts, namely cosPointingAngle, +DCA[between]V0daughters, v0radius,DCA-positive[daughter]to-primary-vertex and DCA-negative[daughter]to-primary-vertex) +that are filled with the V0 invariant mass under the K0, Lambda and Antilambda mass assumption +(so 20cutsx5parametersx3particles=300 mass invariant plots).It also produces plots of the topological parameters themselves. +The cuts are passed as configurable strings for convenience. +This analysis includes two processes, one for Real Data and one for MC Data switchable at the end of the code, only run one at a time*/ + +#include +#include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Common/DataModel/EventSelection.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Common/DataModel/PIDResponse.h" +#include "CommonUtils/StringUtils.h" + +// namespaces to be used for the plot names and topological cuts that will be given by a configurable string +namespace cuthistoskzerosh +{ +std::shared_ptr cosPACut[20]; +static std::vector cosPAcuts; +std::shared_ptr dcaCut[20]; +static std::vector dcacuts; +std::shared_ptr v0radiusCut[20]; +static std::vector v0radiuscuts; +std::shared_ptr dcapostopCut[20]; +static std::vector dcapostopvcuts; +std::shared_ptr dcanegtopCut[20]; +static std::vector dcanegtopvcuts; +} // namespace cuthistoskzerosh +namespace cuthistoslambda +{ +std::shared_ptr cosPACut[20]; +static std::vector cosPAcuts; +std::shared_ptr dcaCut[20]; +static std::vector dcacuts; +std::shared_ptr v0radiusCut[20]; +static std::vector v0radiuscuts; +std::shared_ptr dcapostopCut[20]; +static std::vector dcapostopvcuts; +std::shared_ptr dcanegtopCut[20]; +static std::vector dcanegtopvcuts; +} // namespace cuthistoslambda +namespace cuthistosantilambda +{ +std::shared_ptr cosPACut[20]; +static std::vector cosPAcuts; +std::shared_ptr dcaCut[20]; +static std::vector dcacuts; +std::shared_ptr v0radiusCut[20]; +static std::vector v0radiuscuts; +std::shared_ptr dcapostopCut[20]; +static std::vector dcapostopvcuts; +std::shared_ptr dcanegtopCut[20]; +static std::vector dcanegtopvcuts; +} // namespace cuthistosantilambda +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct v0topologicalcuts { + // Histogram Registry includes different V0 Parameteres for all V0s and individual MC-V0s with MC-matching + HistogramRegistry rV0ParametersMCV0match{"V0ParametersMCV0Match", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rV0ParametersMCK0Smatch{"V0ParametersMCK0SMatch", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rV0ParametersMCLambdamatch{"V0ParametersMCLambdaMatch", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rV0ParametersMCAntiLambdamatch{"V0ParametersMCAntiLambdaMatch", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rV0ParametersData{"rV0ParametersData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + // kzero cut Histogram Registry with MC-matching, each will include 20 histograms for 20 different cuts + HistogramRegistry rKzeroShortCosPACut{"KzeroShortCosPACuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rKzeroShortDCACut{"KzeroShortDCACuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rKzeroShortV0radiusCut{"KzeroShortV0radiusCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rKzeroShortDCApostopCut{"KzeroShortDCApostopvCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rKzeroShortDCAnegtopCut{"KzeroShortDCAnegtopvCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + // lambdas cut histograms with MC-matching (same as in Kzeros above) + HistogramRegistry rLambdaCosPACut{"LambdaCosPACuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rLambdaDCACut{"LambdaDCACuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rLambdaV0radiusCut{"LambdaV0radiusCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rLambdaDCApostopCut{"LambdaDCApostopvCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rLambdaDCAnegtopCut{"LambdaDCAnegtopvCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + // antilambdas cut histograms with MC-matching (same as in Lambdas an Kzeros above) + HistogramRegistry rAntiLambdaCosPACut{"AntiLambdaCosPACuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rAntiLambdaDCACut{"AntiLambdaDCACuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rAntiLambdaV0radiusCut{"AntiLambdaV0radiusCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rAntiLambdaDCApostopCut{"AntiLambdaDCApostopvCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rAntiLambdaDCAnegtopCut{"AntiLambdaDCAnegtopvCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Configurable for histograms + Configurable nBins{"nBins", 100, "N bins in all histos"}; + + // Configurables for Cuts + Configurable cutZVertex{"cutZVertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable nSigmaTPCPion{"nSigmaTPCPion", 4, "nSigmaTPCPion"}; + Configurable nSigmaTPCProton{"nSigmaTPCProton", 4, "nSigmaTPCProton"}; + Configurable compv0masscut{"compv0masscut", 0.01, "CompetitiveV0masscut (GeV)"}; + Configurable etadau{"etadau", 0.8, "Eta Daughters"}; + + // Configurable strings for Kzero cuts + Configurable kzeroshSettingCosPAcutsString{"kzeroshSettingCosPAcutsString", {"0_98,0_981,0_982,0_983,0_984,0_985,0_986,0_987,0_988,0_989,0_99,0_991,0_992,0_993,0_994,0_995,0_996,0_997,0_998,0_999"}, "Kzero cosPA Cut Values"}; + Configurable kzeroshSettingDCAcutsString{"kzeroshSettingDCAcutsString", {"0_3,0_285,0_27,0_255,0_24,0_225,0_21,0_195,0_18,0_165,0_15,0_135,0_12,0_105,0_09,0_075,0_06,0_045,0_03,0_015"}, "Kzero DCA Cut Values"}; + Configurable kzeroshSettingV0radiusString{"kzeroshSettingV0radiusString", {"0_5,0_51,0_52,0_53,0_54,0_55,0_56,0_57,0_58,0_59,0_6,0_61,0_62,0_63,0_64,0_65,0_66,0_67,0_68,0_69"}, "Kzero V0Radius Cut Values"}; + Configurable kzeroshSettingDCApostopvString{"kzeroshSettingDCApostopvString", {"0_0,0_01,0_02,0_03,0_04,0_05,0_06,0_07,0_08,0_09,0_1,0_11,0_12,0_13,0_14,0_15,0_16,0_17,0_18,0_19"}, "Kzero DCA Pos to PV Cut Values"}; + Configurable kzeroshSettingDCAnegtopvString{"kzeroshSettingDCAnegtopvString", {"0_0,0_01,0_02,0_03,0_04,0_05,0_06,0_07,0_08,0_09,0_1,0_11,0_12,0_13,0_14,0_15,0_16,0_17,0_18,0_19"}, "KzeroDCA Neg to PV Cut Values"}; + + // Configurable strings for Lambdacuts + Configurable lambdaSettingCosPAcutsString{"lambdaSettingCosPAcutsString", {"0_98,0_981,0_982,0_983,0_984,0_985,0_986,0_987,0_988,0_989,0_99,0_991,0_992,0_993,0_994"}, "Lambda cosPA Cut Values"}; + Configurable lambdaSettingDCAcutsString{"lambdaSettingDCAcutsString", {"0_3,0_285,0_27,0_255,0_24,0_225,0_21,0_195,0_18,0_165,0_15,0_135,0_12,0_105,0_09,0_075,0_06,0_045,0_03,0_015"}, "Lambda DCA Cut Values"}; + Configurable lambdaSettingV0radiusString{"lambdaSettingV0radiusString", {"0_5,0_51,0_52,0_53,0_54,0_55,0_56,0_57,0_58,0_59,0_6,0_61,0_62,0_63,0_64,0_65,0_66,0_67,0_68,0_69"}, "Lambda V0Radius Cut Values"}; + Configurable lambdaSettingDCApostopvString{"lambdaSettingDCApostopvString", {"0_0,0_01,0_02,0_03,0_04,0_05,0_06,0_07,0_08,0_09,0_1,0_11,0_12,0_13,0_14,0_15,0_16,0_17,0_18,0_19"}, "Lambda DCA Pos to PV Cut Values"}; + Configurable lambdaSettingDCAnegtopvString{"lambdaSettingDCAnegtopvString", {"0_0,0_01,0_02,0_03,0_04,0_05,0_06,0_07,0_08,0_09,0_1,0_11,0_12,0_13,0_14,0_15,0_16,0_17,0_18,0_19"}, "Lambda DCA Neg to PV Cut Values"}; + + // Configurable strings for AntiLambdacuts + Configurable antilambdaSettingCosPAcutsString{"antilambdaSettingCosPAcutsString", {"0_98,0_981,0_982,0_983,0_984,0_985,0_986,0_987,0_988,0_989,0_99,0_991,0_992,0_993,0_994,0_995,0_996,0_997,0_998,0_999"}, "Antilambda cosPA Cut Values"}; + Configurable antilambdaSettingDCAcutsString{"antilambdaSettingDCAcutsString", {"0_3,0_285,0_27,0_255,0_24,0_225,0_21,0_195,0_18,0_165,0_15,0_135,0_12,0_105,0_09,0_075,0_06,0_045,0_03,0_015"}, "Antilambda DCA Cut Values"}; + Configurable antilambdaSettingV0radiusString{"antilambdaSettingV0radiusString", {"0_5,0_51,0_52,0_53,0_54,0_55,0_56,0_57,0_58,0_59,0_6,0_61,0_62,0_63,0_64,0_65,0_66,0_67,0_68,0_69"}, "Antilambda V0Radius Cut Values"}; + Configurable antilambdaSettingDCApostopvString{"antilambdaSettingDCApostopvString", {"0_0,0_01,0_02,0_03,0_04,0_05,0_06,0_07,0_08,0_09,0_1,0_11,0_12,0_13,0_14,0_15,0_16,0_17,0_18,0_19"}, "Antilambda DCA Pos to PV Cut Values"}; + Configurable antilambdaSettingDCAnegtopvString{"antilambdaSettingDCAnegtopvString", {"0_0,0_01,0_02,0_03,0_04,0_05,0_06,0_07,0_08,0_09,0_1,0_11,0_12,0_13,0_14,0_15,0_16,0_17,0_18,0_19"}, "Antilambda DCA Neg to PV Cut Values"}; + + void init(InitContext const&) + { + // kzero filling namespace with configurable strings + + // Setting strings from configurable strings in order to manipulate them + // getting the cut values for the names of the plots for the five topological cuts + cuthistoskzerosh::cosPAcuts = o2::utils::Str::tokenize(kzeroshSettingCosPAcutsString, ','); + cuthistoskzerosh::dcacuts = o2::utils::Str::tokenize(kzeroshSettingDCAcutsString, ','); + cuthistoskzerosh::v0radiuscuts = o2::utils::Str::tokenize(kzeroshSettingV0radiusString, ','); + cuthistoskzerosh::dcapostopvcuts = o2::utils::Str::tokenize(kzeroshSettingDCApostopvString, ','); + cuthistoskzerosh::dcanegtopvcuts = o2::utils::Str::tokenize(kzeroshSettingDCAnegtopvString, ','); + + // lambda filling namespace with configurable strings (same as in Kzeros above) + cuthistoslambda::cosPAcuts = o2::utils::Str::tokenize(lambdaSettingCosPAcutsString, ','); + cuthistoslambda::dcacuts = o2::utils::Str::tokenize(lambdaSettingDCAcutsString, ','); + cuthistoslambda::v0radiuscuts = o2::utils::Str::tokenize(lambdaSettingV0radiusString, ','); + cuthistoslambda::dcapostopvcuts = o2::utils::Str::tokenize(lambdaSettingDCApostopvString, ','); + cuthistoslambda::dcanegtopvcuts = o2::utils::Str::tokenize(lambdaSettingDCAnegtopvString, ','); + + // antilambda filling namespace with configurable strings (same as in Lambdas and Kzeros above) + cuthistosantilambda::cosPAcuts = o2::utils::Str::tokenize(antilambdaSettingCosPAcutsString, ','); + cuthistosantilambda::dcacuts = o2::utils::Str::tokenize(antilambdaSettingDCAcutsString, ','); + cuthistosantilambda::v0radiuscuts = o2::utils::Str::tokenize(antilambdaSettingV0radiusString, ','); + cuthistosantilambda::dcapostopvcuts = o2::utils::Str::tokenize(antilambdaSettingDCApostopvString, ','); + cuthistosantilambda::dcanegtopvcuts = o2::utils::Str::tokenize(antilambdaSettingDCAnegtopvString, ','); + + // Axes for the three invariant mass plots + AxisSpec k0ShortMassAxis = {nBins, 0.45f, 0.55f, "#it{M} #pi^{+}#pi^{-} [GeV/#it{c}^{2}]"}; + AxisSpec lambdaMassAxis = {nBins, 1.085f, 1.145f, "#it{M} p^{+}#pi^{-} [GeV/#it{c}^{2}]"}; + AxisSpec antiLambdaMassAxis = {nBins, 1.085f, 1.145f, "#it{M} p^{-}#pi^{+} [GeV/#it{c}^{2}]"}; + AxisSpec ptAxis = {nBins, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec vertexZAxis = {nBins, -15., 15., "vrtx_{Z} [cm]"}; + + // adding the invariant mass histograms to their Registries using the namespace for kzeros, lambdas and antilambdas + for (uint32_t i = 0; i < cuthistoskzerosh::cosPAcuts.size(); i++) { + cuthistoskzerosh::cosPACut[i] = rKzeroShortCosPACut.add(fmt::format("hKzerocosPACut_{}", cuthistoskzerosh::cosPAcuts[i]).data(), fmt::format("hKzerocosPACut_{}", cuthistoskzerosh::cosPAcuts[i]).data(), {HistType::kTH1D, {{k0ShortMassAxis}}}); + } + for (uint32_t i = 0; i < cuthistoskzerosh::dcacuts.size(); i++) { + cuthistoskzerosh::dcaCut[i] = rKzeroShortDCACut.add(fmt::format("hKzerodcaCut_{}", cuthistoskzerosh::dcacuts[i]).data(), fmt::format("hKzerodcaCut_{}", cuthistoskzerosh::dcacuts[i]).data(), {HistType::kTH1D, {{k0ShortMassAxis}}}); + } + for (uint32_t i = 0; i < cuthistoskzerosh::v0radiuscuts.size(); i++) { + cuthistoskzerosh::v0radiusCut[i] = rKzeroShortV0radiusCut.add(fmt::format("hKzerov0radiusCut_{}", cuthistoskzerosh::v0radiuscuts[i]).data(), fmt::format("hKzerov0radiusCut_{}", cuthistoskzerosh::v0radiuscuts[i]).data(), {HistType::kTH1D, {{k0ShortMassAxis}}}); + } + for (uint32_t i = 0; i < cuthistoskzerosh::dcapostopvcuts.size(); i++) { + cuthistoskzerosh::dcapostopCut[i] = rKzeroShortDCApostopCut.add(fmt::format("hKzerodcapostopCut_{}", cuthistoskzerosh::dcapostopvcuts[i]).data(), fmt::format("hKzerodcapostopCut_{}", cuthistoskzerosh::dcapostopvcuts[i]).data(), {HistType::kTH1D, {{k0ShortMassAxis}}}); + } + for (uint32_t i = 0; i < cuthistoskzerosh::dcanegtopvcuts.size(); i++) { + cuthistoskzerosh::dcanegtopCut[i] = rKzeroShortDCAnegtopCut.add(fmt::format("hKzerodcanegtopCut_{}", cuthistoskzerosh::dcanegtopvcuts[i]).data(), fmt::format("hKzerodcanegtopCut_{}", cuthistoskzerosh::dcanegtopvcuts[i]).data(), {HistType::kTH1D, {{k0ShortMassAxis}}}); + } + for (uint32_t i = 0; i < cuthistoslambda::cosPAcuts.size(); i++) { + cuthistoslambda::cosPACut[i] = rLambdaCosPACut.add(fmt::format("hLambdacosPACut_{}", cuthistoslambda::cosPAcuts[i]).data(), fmt::format("hLambdacosPACut_{}", cuthistoslambda::cosPAcuts[i]).data(), {HistType::kTH1D, {{lambdaMassAxis}}}); + } + for (uint32_t i = 0; i < cuthistoslambda::dcacuts.size(); i++) { + cuthistoslambda::dcaCut[i] = rLambdaDCACut.add(fmt::format("hLambdadcaCut_{}", cuthistoslambda::dcacuts[i]).data(), fmt::format("hLambdadcaCut_{}", cuthistoslambda::dcacuts[i]).data(), {HistType::kTH1D, {{lambdaMassAxis}}}); + } + for (uint32_t i = 0; i < cuthistoslambda::v0radiuscuts.size(); i++) { + cuthistoslambda::v0radiusCut[i] = rLambdaV0radiusCut.add(fmt::format("hLambdav0radiusCut_{}", cuthistoslambda::v0radiuscuts[i]).data(), fmt::format("hLambdav0radiusCut_{}", cuthistoslambda::v0radiuscuts[i]).data(), {HistType::kTH1D, {{lambdaMassAxis}}}); + } + for (uint32_t i = 0; i < cuthistoslambda::dcapostopvcuts.size(); i++) { + cuthistoslambda::dcapostopCut[i] = rLambdaDCApostopCut.add(fmt::format("hLambdadcapostopCut_{}", cuthistoslambda::dcapostopvcuts[i]).data(), fmt::format("hLambdadcapostopCut_{}", cuthistoslambda::dcapostopvcuts[i]).data(), {HistType::kTH1D, {{lambdaMassAxis}}}); + } + for (uint32_t i = 0; i < cuthistoslambda::dcanegtopvcuts.size(); i++) { + cuthistoslambda::dcanegtopCut[i] = rLambdaDCAnegtopCut.add(fmt::format("hLambdadcanegtopCut_{}", cuthistoslambda::dcanegtopvcuts[i]).data(), fmt::format("hLambdadcanegtopCut_{}", cuthistoslambda::dcanegtopvcuts[i]).data(), {HistType::kTH1D, {{lambdaMassAxis}}}); + } + + for (uint32_t i = 0; i < cuthistosantilambda::cosPAcuts.size(); i++) { + cuthistosantilambda::cosPACut[i] = rAntiLambdaCosPACut.add(fmt::format("hAntiLambdacosPACut_{}", cuthistosantilambda::cosPAcuts[i]).data(), fmt::format("hAntiLambdacosPACut_{}", cuthistosantilambda::cosPAcuts[i]).data(), {HistType::kTH1D, {{antiLambdaMassAxis}}}); + } + for (uint32_t i = 0; i < cuthistosantilambda::dcacuts.size(); i++) { + cuthistosantilambda::dcaCut[i] = rAntiLambdaDCACut.add(fmt::format("hAntiLambdadcaCut_{}", cuthistosantilambda::dcacuts[i]).data(), fmt::format("hAntiLambdadcaCut_{}", cuthistosantilambda::dcacuts[i]).data(), {HistType::kTH1D, {{antiLambdaMassAxis}}}); + } + for (uint32_t i = 0; i < cuthistosantilambda::v0radiuscuts.size(); i++) { + cuthistosantilambda::v0radiusCut[i] = rAntiLambdaV0radiusCut.add(fmt::format("hAntiLambdav0radiusCut_{}", cuthistosantilambda::v0radiuscuts[i]).data(), fmt::format("hAntiLambdav0radiusCut_{}", cuthistosantilambda::v0radiuscuts[i]).data(), {HistType::kTH1D, {{antiLambdaMassAxis}}}); + } + for (uint32_t i = 0; i < cuthistosantilambda::dcapostopvcuts.size(); i++) { + cuthistosantilambda::dcapostopCut[i] = rAntiLambdaDCApostopCut.add(fmt::format("hAntiLambdadcapostopCut_{}", cuthistosantilambda::dcapostopvcuts[i]).data(), fmt::format("hAntiLambdadcapostopCut_{}", cuthistosantilambda::dcapostopvcuts[i]).data(), {HistType::kTH1D, {{antiLambdaMassAxis}}}); + } + for (uint32_t i = 0; i < cuthistosantilambda::dcanegtopvcuts.size(); i++) { + cuthistosantilambda::dcanegtopCut[i] = rAntiLambdaDCAnegtopCut.add(fmt::format("hAntiLambdadcanegtopCut_{}", cuthistosantilambda::dcanegtopvcuts[i]).data(), fmt::format("hAntiLambdadcanegtopCut_{}", cuthistosantilambda::dcanegtopvcuts[i]).data(), {HistType::kTH1D, {{antiLambdaMassAxis}}}); + } + + // K0s topological cut histograms added and MC-matched + rV0ParametersMCV0match.add("hDCAV0Daughters_V0_Match", "hDCAV0Daughters_No_Match", {HistType::kTH1F, {{nBins, 0.0f, 1.2f}}}); + rV0ParametersMCV0match.add("hV0CosPA_V0_Match", "hV0CosPA_No_Match", {HistType::kTH1F, {{nBins, 0.95f, 1.f}}}); + rV0ParametersMCV0match.add("hV0Radius_V0_Match", "hV0Radius_No_Match", {HistType::kTH1F, {{nBins, 0.0f, 5.0f}}}); + rV0ParametersMCV0match.add("hV0Radius_V0_Match_Full", "hV0Radius_No_Match_Full", {HistType::kTH1F, {{nBins, 0.0f, 40.0f}}}); + rV0ParametersMCV0match.add("hDCAPostoPV_V0_Match", "hDCAPostoPV_No_Match", {HistType::kTH1F, {{nBins, 0.0f, 2.0f}}}); + rV0ParametersMCV0match.add("hDCANegtoPV_V0_Match", "hDCANegtoPV_No_Match", {HistType::kTH1F, {{nBins, 0.0f, 2.0f}}}); + rV0ParametersMCV0match.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); + + // kzero match + rV0ParametersMCK0Smatch.add("hDCAV0Daughters_KzeroMC_Match", "hDCAV0Daughters_KzeroMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 1.2f}}}); + rV0ParametersMCK0Smatch.add("hV0CosPA_KzeroMC_Match", "hV0CosPA_KzeroMC_Match", {HistType::kTH1F, {{nBins, 0.95f, 1.f}}}); + rV0ParametersMCK0Smatch.add("hV0Radius_KzeroMC_Match", "hV0Radius_KzeroMC_Match", {HistType::kTH1F, {{nBins, 0.2f, 5.0f}}}); + rV0ParametersMCK0Smatch.add("hDCAPostoPV_KzeroMC_Match", "hDCAPostoPV_KzeroMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 2.0f}}}); + rV0ParametersMCK0Smatch.add("hDCANegtoPV_KzeroMC_Match", "hDCANegtoPV_KzeroMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 2.0f}}}); + + // lambda match + rV0ParametersMCLambdamatch.add("hDCAV0Daughters_LambdaMC_Match", "hDCAV0Daughters_LambdaMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 1.2f}}}); + rV0ParametersMCLambdamatch.add("hV0CosPA_LambdaMC_Match", "hV0CosPA_LambdaMC_Match", {HistType::kTH1F, {{nBins, 0.95f, 1.f}}}); + rV0ParametersMCLambdamatch.add("hV0Radius_LambdaMC_Match", "hV0Radius_LambdaMC_Match", {HistType::kTH1F, {{nBins, 0.2f, 5.0f}}}); + rV0ParametersMCLambdamatch.add("hDCAPostoPV_LambdaMC_Match", "hDCAPostoPV_LambdaMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 2.0f}}}); + rV0ParametersMCLambdamatch.add("hDCANegtoPV_LambdaMC_Match", "hDCANegtoPV_LambdaMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 2.0f}}}); + + // antilambda match + rV0ParametersMCAntiLambdamatch.add("hDCAV0Daughters_AntiLambdaMC_Match", "hDCAV0Daughters_AntiLambdaMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 1.2f}}}); + rV0ParametersMCAntiLambdamatch.add("hV0CosPA_AntiLambdaMC_Match", "hV0CosPA_AntiLambdaMC_Match", {HistType::kTH1F, {{nBins, 0.95f, 1.f}}}); + rV0ParametersMCAntiLambdamatch.add("hV0Radius_AntiLambdaMC_Match", "hV0Radius_AntiLambdaMC_Match", {HistType::kTH1F, {{nBins, 0.2f, 5.0f}}}); + rV0ParametersMCAntiLambdamatch.add("hDCAPostoPV_AntiLambdaMC_Match", "hDCAPostoPV_AntiLambdaMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 2.0f}}}); + rV0ParametersMCAntiLambdamatch.add("hDCANegtoPV_AntiLambdaMC_Match", "hDCANegtoPV_AntiLambdaMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 2.0f}}}); + + // V0s Data + rV0ParametersData.add("hDCAV0Daughters_V0Data", "hDCAV0Daughters_V0Data", {HistType::kTH1F, {{nBins, 0.0f, 1.2f}}}); + rV0ParametersData.add("hV0CosPA_V0Data", "hV0CosPA_V0Data", {HistType::kTH1F, {{nBins, 0.95f, 1.f}}}); + rV0ParametersData.add("hV0Radius_V0Data", "hV0Radius_V0Data", {HistType::kTH1F, {{nBins, 0.2f, 5.0f}}}); + rV0ParametersData.add("hV0Radius_Full_V0Data", "hV0Radius_Full_V0Data", {HistType::kTH1F, {{nBins, 0.2f, 40.0f}}}); + rV0ParametersData.add("hDCAPostoPV_V0Data", "hDCAPostoPV_V0Data", {HistType::kTH1F, {{nBins, 0.0f, 2.0f}}}); + rV0ParametersData.add("hDCANegtoPV_V0Data", "hDCANegtoPV_V0Data", {HistType::kTH1F, {{nBins, 0.0f, 2.0f}}}); + rV0ParametersData.add("hMassK0ShortNoCuts_V0Data", "hMassK0ShortNoCuts_V0Data", {HistType::kTH1F, {{k0ShortMassAxis}}}); + rV0ParametersData.add("hMassLambdaNoCuts_V0Data", "hMassLambdaNoCuts_V0Data", {HistType::kTH1F, {{lambdaMassAxis}}}); + rV0ParametersData.add("hMassAntilambdaNoCuts_V0Data", "hMassAntilambdaNoCuts_V0Data", {HistType::kTH1F, {{antiLambdaMassAxis}}}); + rV0ParametersData.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); + // K0short Data + rV0ParametersData.add("hMassK0ShortAfterEtaCut", "hMassK0ShortAfterEtaCut", {HistType::kTH1F, {k0ShortMassAxis}}); + rV0ParametersData.add("hMassK0ShortAfterCompmassCut", "hMassK0ShortAfterCompmassCut", {HistType::kTH1F, {k0ShortMassAxis}}); + rV0ParametersData.add("hMassK0ShortAfterAllCuts", "hMassK0ShortAfterAllCuts", {HistType::kTH1F, {k0ShortMassAxis}}); + rV0ParametersData.add("hNSigmaPosPiFromK0s", "hNSigmaPosPiFromK0s", {HistType::kTH2F, {{100, -5.f, 5.f}, {ptAxis}}}); + rV0ParametersData.add("hNSigmaNegPiFromK0s", "hNSigmaNegPiFromK0s", {HistType::kTH2F, {{100, -5.f, 5.f}, {ptAxis}}}); + rV0ParametersData.add("hK0shEtaPosDau", "hK0shEtaPosDau", {HistType::kTH1F, {{nBins, -1.2f, 1.2f}}}); + rV0ParametersData.add("hK0shEtaNegDau", "hK0shEtaNegDau", {HistType::kTH1F, {{nBins, -1.2f, 1.2f}}}); + rV0ParametersData.add("hK0shEtaPosDauAfterCut", "hK0shEtaPosDauAfterCut", {HistType::kTH1F, {{nBins, -1.2f, 1.2f}}}); + rV0ParametersData.add("hK0shEtaNegDauAfterCut", "hK0shEtaNegDauAfterCut", {HistType::kTH1F, {{nBins, -1.2f, 1.2f}}}); + + // Lambda Data + rV0ParametersData.add("hMassLambdaAfterEtaCut", "hMassLambdaAfterEtaCut", {HistType::kTH1F, {lambdaMassAxis}}); + rV0ParametersData.add("hMassLambdaAfterCompmassCut", "hMassLambdaAfterCompmassCut", {HistType::kTH1F, {lambdaMassAxis}}); + rV0ParametersData.add("hMassLambdaAfterAllCuts", "hMassLambdaAfterAllCuts", {HistType::kTH1F, {lambdaMassAxis}}); + rV0ParametersData.add("hNSigmaPosProtonFromLambda", "hNSigmaPosProtonFromLambda", {HistType::kTH2F, {{100, -5.f, 5.f}, {ptAxis}}}); + rV0ParametersData.add("hNSigmaNegPionFromLambda", "hNSigmaNegPionFromLambda", {HistType::kTH2F, {{100, -5.f, 5.f}, {ptAxis}}}); + // Antilambda Data + rV0ParametersData.add("hMassAntiLambdaAfterEtaCut", "hMassAntiLambdaAfterEtaCut", {HistType::kTH1F, {antiLambdaMassAxis}}); + rV0ParametersData.add("hMassAntiLambdaAfterCompmassCut", "hMassAntiLambdaAfterCompmassCut", {HistType::kTH1F, {antiLambdaMassAxis}}); + rV0ParametersData.add("hMassAntiLambdaAfterAllCuts", "hMassAntiLambdaAfterAllCuts", {HistType::kTH1F, {antiLambdaMassAxis}}); + rV0ParametersData.add("hNSigmaNegProtonFromAntilambda", "hNSigmaNegProtonFromAntilambda", {HistType::kTH2F, {{100, -5.f, 5.f}, {ptAxis}}}); + rV0ParametersData.add("hNSigmaPosPionFromAntilambda", "hNSigmaPosPionFromAntilambda", {HistType::kTH2F, {{100, -5.f, 5.f}, {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 posZFilterMC = (nabs(o2::aod::mccollision::posZ) < cutZVertex); + Filter posZFilter = (nabs(o2::aod::collision::posZ) < cutZVertex); + + // Defining the type of the daughter tracks + using DaughterTracks = soa::Join; + + // This is the Process for the MC reconstructed Data + void recMCProcess(soa::Filtered>::iterator const& collision, + soa::Join const& V0s, + DaughterTracks const&, // no need to define a variable for tracks, if we don't access them directly + aod::McParticles const&) + { + const auto& mLambdaPDG = 1.115683; + const auto& mK0shPDG = 0.497611; + for (const auto& v0 : V0s) { + if (std::abs(v0.posTrack_as().eta()) < etadau && std::abs(v0.negTrack_as().eta()) < etadau) { // daughters pseudorapidity cut + // filling histograms with V0 values + rV0ParametersMCV0match.fill(HIST("hDCAV0Daughters_V0_Match"), v0.dcaV0daughters()); + rV0ParametersMCV0match.fill(HIST("hV0CosPA_V0_Match"), v0.v0cosPA()); + rV0ParametersMCV0match.fill(HIST("hV0Radius_V0_Match"), v0.v0radius()); + rV0ParametersMCV0match.fill(HIST("hV0Radius_V0_Match_Full"), v0.v0radius()); + rV0ParametersMCV0match.fill(HIST("hDCAPostoPV_V0_Match"), v0.dcapostopv()); + rV0ParametersMCV0match.fill(HIST("hDCANegtoPV_V0_Match"), v0.dcanegtopv()); + rV0ParametersMCV0match.fill(HIST("hVertexZRec"), collision.posZ()); + + // Checking that the V0 is a true K0s/Lambdas/Antilambdas and then filling the parameter histograms and the invariant mass plots for different cuts (which are taken from namespace) + if (v0.has_mcParticle()) { + auto v0mcParticle = v0.mcParticle(); + if (v0mcParticle.pdgCode() == 310) { // kzero matched + if (std::abs(v0.mLambda() - mLambdaPDG) > compv0masscut && std::abs(v0.mAntiLambda() - mLambdaPDG) > compv0masscut) { // Kzero competitive v0 mass cut (cut out Lambdas and Anti-Lambdas) + rV0ParametersMCK0Smatch.fill(HIST("hDCAV0Daughters_KzeroMC_Match"), v0.dcaV0daughters()); + rV0ParametersMCK0Smatch.fill(HIST("hV0CosPA_KzeroMC_Match"), v0.v0cosPA()); + rV0ParametersMCK0Smatch.fill(HIST("hV0Radius_KzeroMC_Match"), v0.v0radius()); + rV0ParametersMCK0Smatch.fill(HIST("hDCAPostoPV_KzeroMC_Match"), std::abs(v0.dcapostopv())); + rV0ParametersMCK0Smatch.fill(HIST("hDCANegtoPV_KzeroMC_Match"), std::abs(v0.dcanegtopv())); + + for (uint32_t j = 0; j < cuthistoskzerosh::cosPAcuts.size(); j++) { + std::string cosPAcut = cuthistoskzerosh::cosPAcuts[j]; // Get the current cut value from the namespace + size_t pos = cosPAcut.find("_"); // find the "_" which needs to change to a "." for it to be a number + cosPAcut[pos] = '.'; // change the "_" into an "." + const float cosPAcutvalue = std::stod(cosPAcut); // make the string into a float value + if (v0.v0cosPA() > cosPAcutvalue) { // enforce the cut value + cuthistoskzerosh::cosPACut[j]->Fill(v0.mK0Short()); // fill the corresponding histo from the namespace with the invariant mass (of a Kzero here) + } + } + for (uint32_t j = 0; j < cuthistoskzerosh::dcacuts.size(); j++) { + std::string dcacut = cuthistoskzerosh::dcacuts[j]; + size_t pos = dcacut.find("_"); + dcacut[pos] = '.'; + const float dcacutvalue = std::stod(dcacut); + if (v0.dcaV0daughters() < dcacutvalue) { + cuthistoskzerosh::dcaCut[j]->Fill(v0.mK0Short()); + } + } + for (uint32_t j = 0; j < cuthistoskzerosh::v0radiuscuts.size(); j++) { + std::string v0radiuscut = cuthistoskzerosh::v0radiuscuts[j]; + size_t pos = v0radiuscut.find("_"); + v0radiuscut[pos] = '.'; + const float v0radiuscutvalue = std::stod(v0radiuscut); + if (v0.v0radius() > v0radiuscutvalue) { + cuthistoskzerosh::v0radiusCut[j]->Fill(v0.mK0Short()); + } + } + for (uint32_t j = 0; j < cuthistoskzerosh::dcapostopvcuts.size(); j++) { + std::string dcapostopcut = cuthistoskzerosh::dcapostopvcuts[j]; + size_t pos = dcapostopcut.find("_"); + dcapostopcut[pos] = '.'; + const float dcapostopcutvalue = std::stod(dcapostopcut); + if (std::abs(v0.dcapostopv()) > dcapostopcutvalue) { + cuthistoskzerosh::dcapostopCut[j]->Fill(v0.mK0Short()); + } + } + for (uint32_t j = 0; j < cuthistoskzerosh::dcanegtopvcuts.size(); j++) { + std::string dcanegtopcut = cuthistoskzerosh::dcanegtopvcuts[j]; + size_t pos = dcanegtopcut.find("_"); + dcanegtopcut[pos] = '.'; + const float dcanegtopcutvalue = std::stod(dcanegtopcut); + if (std::abs(v0.dcanegtopv()) > dcanegtopcutvalue) { + cuthistoskzerosh::dcanegtopCut[j]->Fill(v0.mK0Short()); + } + } + } + } + if (v0mcParticle.pdgCode() == 3122) { // lambda matched + if (std::abs(v0.mK0Short() - mK0shPDG) > compv0masscut) { // antilambda competitive v0 mass cut (cut out Kaons) + rV0ParametersMCLambdamatch.fill(HIST("hDCAV0Daughters_LambdaMC_Match"), v0.dcaV0daughters()); + rV0ParametersMCLambdamatch.fill(HIST("hV0CosPA_LambdaMC_Match"), v0.v0cosPA()); + rV0ParametersMCLambdamatch.fill(HIST("hV0Radius_LambdaMC_Match"), v0.v0radius()); + rV0ParametersMCLambdamatch.fill(HIST("hDCAPostoPV_LambdaMC_Match"), std::abs(v0.dcapostopv())); + rV0ParametersMCLambdamatch.fill(HIST("hDCANegtoPV_LambdaMC_Match"), std::abs(v0.dcanegtopv())); + + // for explanation look at the first Kzero plot above + for (uint32_t j = 0; j < cuthistoslambda::cosPAcuts.size(); j++) { + std::string cosPAcutlambda = cuthistoslambda::cosPAcuts[j]; + size_t pos = cosPAcutlambda.find("_"); + cosPAcutlambda[pos] = '.'; + const float cosPAcutlambdavalue = std::stod(cosPAcutlambda); + if (v0.v0cosPA() > cosPAcutlambdavalue) { + cuthistoslambda::cosPACut[j]->Fill(v0.mLambda()); + } + } + for (uint32_t j = 0; j < cuthistoslambda::dcacuts.size(); j++) { + std::string dcacutlambda = cuthistoslambda::dcacuts[j]; + size_t pos = dcacutlambda.find("_"); + dcacutlambda[pos] = '.'; + const float dcacutlambdavalue = std::stod(dcacutlambda); + if (v0.dcaV0daughters() < dcacutlambdavalue) { + cuthistoslambda::dcaCut[j]->Fill(v0.mLambda()); + } + } + for (uint32_t j = 0; j < cuthistoslambda::v0radiuscuts.size(); j++) { + std::string v0radiuscutlambda = cuthistoslambda::v0radiuscuts[j]; + size_t pos = v0radiuscutlambda.find("_"); + v0radiuscutlambda[pos] = '.'; + const float v0radiuscutlambdavalue = std::stod(v0radiuscutlambda); + if (v0.v0radius() > v0radiuscutlambdavalue) { + cuthistoslambda::v0radiusCut[j]->Fill(v0.mLambda()); + } + } + for (uint32_t j = 0; j < cuthistoslambda::dcapostopvcuts.size(); j++) { + std::string dcapostopcutlambda = cuthistoslambda::dcapostopvcuts[j]; + size_t pos = dcapostopcutlambda.find("_"); + dcapostopcutlambda[pos] = '.'; + const float dcapostopcutlambdavalue = std::stod(dcapostopcutlambda); + if (std::abs(v0.dcapostopv()) > dcapostopcutlambdavalue) { + cuthistoslambda::dcapostopCut[j]->Fill(v0.mLambda()); + } + } + for (uint32_t j = 0; j < cuthistoslambda::dcanegtopvcuts.size(); j++) { + std::string dcanegtopcutlambda = cuthistoslambda::dcanegtopvcuts[j]; + size_t pos = dcanegtopcutlambda.find("_"); + dcanegtopcutlambda[pos] = '.'; + const float dcanegtopcutlambdavalue = std::stod(dcanegtopcutlambda); + if (std::abs(v0.dcanegtopv()) > dcanegtopcutlambdavalue) { + cuthistoslambda::dcanegtopCut[j]->Fill(v0.mLambda()); + } + } + } + } + if (v0mcParticle.pdgCode() == -3122) { // antilambda matched + if (std::abs(v0.mK0Short() - mK0shPDG) > compv0masscut) { // antilambda competitive v0 mass cut (cut out Kaons) + rV0ParametersMCAntiLambdamatch.fill(HIST("hDCAV0Daughters_AntiLambdaMC_Match"), v0.dcaV0daughters()); + rV0ParametersMCAntiLambdamatch.fill(HIST("hV0CosPA_AntiLambdaMC_Match"), v0.v0cosPA()); + rV0ParametersMCAntiLambdamatch.fill(HIST("hV0Radius_AntiLambdaMC_Match"), v0.v0radius()); + rV0ParametersMCAntiLambdamatch.fill(HIST("hDCAPostoPV_AntiLambdaMC_Match"), std::abs(v0.dcapostopv())); + rV0ParametersMCAntiLambdamatch.fill(HIST("hDCANegtoPV_AntiLambdaMC_Match"), std::abs(v0.dcanegtopv())); + // for explanation look at the first Kzero plot above + for (uint32_t j = 0; j < cuthistosantilambda::cosPAcuts.size(); j++) { + std::string cosPAcutantilambda = cuthistosantilambda::cosPAcuts[j]; + size_t pos = cosPAcutantilambda.find("_"); + cosPAcutantilambda[pos] = '.'; + const float cosPAcutantilambdavalue = std::stod(cosPAcutantilambda); + if (v0.v0cosPA() > cosPAcutantilambdavalue) { + cuthistosantilambda::cosPACut[j]->Fill(v0.mAntiLambda()); + } + } + for (uint32_t j = 0; j < cuthistosantilambda::dcacuts.size(); j++) { + std::string dcacutantilambda = cuthistosantilambda::dcacuts[j]; + size_t pos = dcacutantilambda.find("_"); + dcacutantilambda[pos] = '.'; + const float dcacutantilambdavalue = std::stod(dcacutantilambda); + if (v0.dcaV0daughters() < dcacutantilambdavalue) { + cuthistosantilambda::dcaCut[j]->Fill(v0.mAntiLambda()); + } + } + for (uint32_t j = 0; j < cuthistosantilambda::v0radiuscuts.size(); j++) { + std::string v0radiusantilambda = cuthistosantilambda::v0radiuscuts[j]; + size_t pos = v0radiusantilambda.find("_"); + v0radiusantilambda[pos] = '.'; + const float v0radiuscutantilambdavalue = std::stod(v0radiusantilambda); + if (v0.v0radius() > v0radiuscutantilambdavalue) { + cuthistosantilambda::v0radiusCut[j]->Fill(v0.mAntiLambda()); + } + } + for (uint32_t j = 0; j < cuthistosantilambda::dcapostopvcuts.size(); j++) { + std::string dcapostopantilambda = cuthistosantilambda::dcapostopvcuts[j]; + size_t pos = dcapostopantilambda.find("_"); + dcapostopantilambda[pos] = '.'; + const float dcapostopcutantilambdavalue = std::stod(dcapostopantilambda); + if (std::abs(v0.dcapostopv()) > dcapostopcutantilambdavalue) { + cuthistosantilambda::dcapostopCut[j]->Fill(v0.mAntiLambda()); + } + } + for (uint32_t j = 0; j < cuthistosantilambda::dcanegtopvcuts.size(); j++) { + std::string dcanegtopantilambda = cuthistosantilambda::dcanegtopvcuts[j]; + size_t pos = dcanegtopantilambda.find("_"); + dcanegtopantilambda[pos] = '.'; + const float dcanegtopcutantilambdavalue = std::stod(dcanegtopantilambda); + if (std::abs(v0.dcanegtopv()) > dcanegtopcutantilambdavalue) { + cuthistosantilambda::dcanegtopCut[j]->Fill(v0.mAntiLambda()); + } + } + } + } + } + } + } + } + // This is the process for Real Data + void dataProcess(soa::Filtered>::iterator const& collision, + aod::V0Datas const& V0s, + DaughterTracks const&) + { + // filling histograms with the different V0 parameters + const auto& mLambdaPDG = 1.115683; + const auto& mK0shPDG = 0.497611; + for (const auto& v0 : V0s) { + const auto& posDaughterTrack = v0.posTrack_as(); + const auto& negDaughterTrack = v0.negTrack_as(); + rV0ParametersData.fill(HIST("hMassK0ShortNoCuts_V0Data"), v0.mK0Short()); + rV0ParametersData.fill(HIST("hMassLambdaNoCuts_V0Data"), v0.mLambda()); + rV0ParametersData.fill(HIST("hMassAntilambdaNoCuts_V0Data"), v0.mAntiLambda()); + rV0ParametersData.fill(HIST("hDCAV0Daughters_V0Data"), v0.dcaV0daughters()); + rV0ParametersData.fill(HIST("hV0CosPA_V0Data"), v0.v0cosPA()); + rV0ParametersData.fill(HIST("hV0Radius_V0Data"), v0.v0radius()); + rV0ParametersData.fill(HIST("hV0Radius_Full_V0Data"), v0.v0radius()); + rV0ParametersData.fill(HIST("hDCAPostoPV_V0Data"), std::abs(v0.dcapostopv())); + rV0ParametersData.fill(HIST("hDCANegtoPV_V0Data"), std::abs(v0.dcanegtopv())); + rV0ParametersData.fill(HIST("hVertexZRec"), collision.posZ()); + rV0ParametersData.fill(HIST("hK0shEtaPosDau"), v0.posTrack_as().eta()); + rV0ParametersData.fill(HIST("hK0shEtaNegDau"), v0.negTrack_as().eta()); + + if (std::abs(v0.posTrack_as().eta()) < etadau && std::abs(v0.negTrack_as().eta()) < etadau) { // daughters pseudorapidity cut + rV0ParametersData.fill(HIST("hMassK0ShortAfterEtaCut"), v0.mK0Short()); + rV0ParametersData.fill(HIST("hMassLambdaAfterEtaCut"), v0.mLambda()); + rV0ParametersData.fill(HIST("hMassAntiLambdaAfterEtaCut"), v0.mAntiLambda()); + rV0ParametersData.fill(HIST("hK0shEtaPosDauAfterCut"), v0.posTrack_as().eta()); + rV0ParametersData.fill(HIST("hK0shEtaNegDauAfterCut"), v0.negTrack_as().eta()); + if (std::abs(v0.mLambda() - mLambdaPDG) > compv0masscut && std::abs(v0.mAntiLambda() - mLambdaPDG) > compv0masscut) { // antilambda competitive v0 mass cut (cut out Lambdas and Anti-Lambdas) + rV0ParametersData.fill(HIST("hMassK0ShortAfterCompmassCut"), v0.mK0Short()); + if (std::abs(posDaughterTrack.tpcNSigmaPi()) < nSigmaTPCPion && std::abs(negDaughterTrack.tpcNSigmaPi()) < nSigmaTPCPion) { // TPC PID on daughter pions + rV0ParametersData.fill(HIST("hMassK0ShortAfterAllCuts"), v0.mK0Short()); + rV0ParametersData.fill(HIST("hNSigmaPosPiFromK0s"), posDaughterTrack.tpcNSigmaPi(), posDaughterTrack.tpcInnerParam()); + rV0ParametersData.fill(HIST("hNSigmaNegPiFromK0s"), negDaughterTrack.tpcNSigmaPi(), negDaughterTrack.tpcInnerParam()); + // Filling the five Kzero invariant mass plots for different cuts (which are taken from namespace), for full explanation see the first kzero cut filling in the MC process + for (uint32_t j = 0; j < cuthistoskzerosh::cosPAcuts.size(); j++) { + std::string cosPAcut = cuthistoskzerosh::cosPAcuts[j]; + size_t pos = cosPAcut.find("_"); + cosPAcut[pos] = '.'; + const float cosPAcutvalue = std::stod(cosPAcut); + if (v0.v0cosPA() > cosPAcutvalue) { + cuthistoskzerosh::cosPACut[j]->Fill(v0.mK0Short()); + } + } + for (uint32_t j = 0; j < cuthistoskzerosh::dcacuts.size(); j++) { + std::string dcacut = cuthistoskzerosh::dcacuts[j]; + size_t pos = dcacut.find("_"); + dcacut[pos] = '.'; + const float dcacutvalue = std::stod(dcacut); + if (v0.dcaV0daughters() < dcacutvalue) { + cuthistoskzerosh::dcaCut[j]->Fill(v0.mK0Short()); + } + } + for (uint32_t j = 0; j < cuthistoskzerosh::v0radiuscuts.size(); j++) { + std::string v0radiuscut = cuthistoskzerosh::v0radiuscuts[j]; + size_t pos = v0radiuscut.find("_"); + v0radiuscut[pos] = '.'; + const float v0radiuscutvalue = std::stod(v0radiuscut); + if (v0.v0radius() > v0radiuscutvalue) { + cuthistoskzerosh::v0radiusCut[j]->Fill(v0.mK0Short()); + } + } + for (uint32_t j = 0; j < cuthistoskzerosh::dcapostopvcuts.size(); j++) { + std::string dcapostopcut = cuthistoskzerosh::dcapostopvcuts[j]; + size_t pos = dcapostopcut.find("_"); + dcapostopcut[pos] = '.'; + const float dcapostopcutvalue = std::stod(dcapostopcut); + if (std::abs(v0.dcapostopv()) > dcapostopcutvalue) { + cuthistoskzerosh::dcapostopCut[j]->Fill(v0.mK0Short()); + } + } + for (uint32_t j = 0; j < cuthistoskzerosh::dcanegtopvcuts.size(); j++) { + std::string dcanegtopcut = cuthistoskzerosh::dcanegtopvcuts[j]; + size_t pos = dcanegtopcut.find("_"); + dcanegtopcut[pos] = '.'; + const float dcanegtopcutvalue = std::stod(dcanegtopcut); + if (std::abs(v0.dcanegtopv()) > dcanegtopcutvalue) { + cuthistoskzerosh::dcanegtopCut[j]->Fill(v0.mK0Short()); + } + } + } + } + if (std::abs(v0.mK0Short() - mK0shPDG) > compv0masscut) { // lambda competitive v0 mass cut (cut out Kaons) + rV0ParametersData.fill(HIST("hMassLambdaAfterCompmassCut"), v0.mLambda()); + rV0ParametersData.fill(HIST("hMassAntiLambdaAfterCompmassCut"), v0.mAntiLambda()); + if (std::abs(posDaughterTrack.tpcNSigmaPr()) < nSigmaTPCProton && std::abs(negDaughterTrack.tpcNSigmaPi()) < nSigmaTPCPion) { // TPC PID on daughter pion and proton for Lambda + rV0ParametersData.fill(HIST("hMassLambdaAfterAllCuts"), v0.mLambda()); + rV0ParametersData.fill(HIST("hNSigmaPosProtonFromLambda"), posDaughterTrack.tpcNSigmaPr(), posDaughterTrack.tpcInnerParam()); + rV0ParametersData.fill(HIST("hNSigmaNegPionFromLambda"), negDaughterTrack.tpcNSigmaPi(), negDaughterTrack.tpcInnerParam()); + // Filling the five Lambda invariant mass plots for different cuts (which are taken from namespace), same as with Kzeros above,for full explanation see the first kzero cut filling in the MC process + for (uint32_t j = 0; j < cuthistoslambda::cosPAcuts.size(); j++) { + std::string cosPAcutlambda = cuthistoslambda::cosPAcuts[j]; + size_t pos = cosPAcutlambda.find("_"); + cosPAcutlambda[pos] = '.'; + const float cosPAcutlambdavalue = std::stod(cosPAcutlambda); + if (v0.v0cosPA() > cosPAcutlambdavalue) { + cuthistoslambda::cosPACut[j]->Fill(v0.mLambda()); + } + } + for (uint32_t j = 0; j < cuthistoslambda::dcacuts.size(); j++) { + std::string dcacutlambda = cuthistoslambda::dcacuts[j]; + size_t pos = dcacutlambda.find("_"); + dcacutlambda[pos] = '.'; + const float dcacutlambdavalue = std::stod(dcacutlambda); + if (v0.dcaV0daughters() < dcacutlambdavalue) { + cuthistoslambda::dcaCut[j]->Fill(v0.mLambda()); + } + } + for (uint32_t j = 0; j < cuthistoslambda::v0radiuscuts.size(); j++) { + std::string v0radiuscutlambda = cuthistoslambda::v0radiuscuts[j]; + size_t pos = v0radiuscutlambda.find("_"); + v0radiuscutlambda[pos] = '.'; + const float v0radiuscutlambdavalue = std::stod(v0radiuscutlambda); + if (v0.v0radius() > v0radiuscutlambdavalue) { + cuthistoslambda::v0radiusCut[j]->Fill(v0.mLambda()); + } + } + for (uint32_t j = 0; j < cuthistoslambda::dcanegtopvcuts.size(); j++) { + std::string dcapostopcutlambda = cuthistoslambda::dcapostopvcuts[j]; + size_t pos = dcapostopcutlambda.find("_"); + dcapostopcutlambda[pos] = '.'; + const float dcapostopcutlambdavalue = std::stod(dcapostopcutlambda); + if (std::abs(v0.dcapostopv()) > dcapostopcutlambdavalue) { + cuthistoslambda::dcapostopCut[j]->Fill(v0.mLambda()); + } + } + for (uint32_t j = 0; j < cuthistoslambda::dcanegtopvcuts.size(); j++) { + std::string dcanegtopcutlambda = cuthistoslambda::dcanegtopvcuts[j]; + size_t pos = dcanegtopcutlambda.find("_"); + dcanegtopcutlambda[pos] = '.'; + const float dcanegtopcutlambdavalue = std::stod(dcanegtopcutlambda); + if (std::abs(v0.dcanegtopv()) > dcanegtopcutlambdavalue) { + cuthistoslambda::dcanegtopCut[j]->Fill(v0.mLambda()); + } + } + } + // Filling the five Anti-Lambda invariant mass plots for different cuts (which are taken from namespace), same as with Kzeros and Lambdas above,for full explanation see the first kzero cut filling in the MC process + if (std::abs(negDaughterTrack.tpcNSigmaPr()) < nSigmaTPCProton && std::abs(posDaughterTrack.tpcNSigmaPi()) < nSigmaTPCPion) { // TPC PID on daughter pion and proton for AntiLambda + rV0ParametersData.fill(HIST("hMassAntiLambdaAfterAllCuts"), v0.mAntiLambda()); + rV0ParametersData.fill(HIST("hNSigmaPosPionFromAntilambda"), posDaughterTrack.tpcNSigmaPi(), posDaughterTrack.tpcInnerParam()); + rV0ParametersData.fill(HIST("hNSigmaNegProtonFromAntilambda"), negDaughterTrack.tpcNSigmaPr(), negDaughterTrack.tpcInnerParam()); + for (uint32_t j = 0; j < cuthistosantilambda::cosPAcuts.size(); j++) { + std::string cosPAcutantilambda = cuthistosantilambda::cosPAcuts[j]; + size_t pos = cosPAcutantilambda.find("_"); + cosPAcutantilambda[pos] = '.'; + const float cosPAcutantilambdavalue = std::stod(cosPAcutantilambda); + if (v0.v0cosPA() > cosPAcutantilambdavalue) { + cuthistosantilambda::cosPACut[j]->Fill(v0.mAntiLambda()); + } + } + for (uint32_t j = 0; j < cuthistosantilambda::dcacuts.size(); j++) { + std::string dcacutantilambda = cuthistosantilambda::dcacuts[j]; + size_t pos = dcacutantilambda.find("_"); + dcacutantilambda[pos] = '.'; + const float dcacutantilambdavalue = std::stod(dcacutantilambda); + if (v0.dcaV0daughters() < dcacutantilambdavalue) { + cuthistosantilambda::dcaCut[j]->Fill(v0.mAntiLambda()); + } + } + for (uint32_t j = 0; j < cuthistosantilambda::v0radiuscuts.size(); j++) { + std::string v0radiusantilambda = cuthistosantilambda::v0radiuscuts[j]; + size_t pos = v0radiusantilambda.find("_"); + v0radiusantilambda[pos] = '.'; + const float v0radiuscutantilambdavalue = std::stod(v0radiusantilambda); + if (v0.v0radius() > v0radiuscutantilambdavalue) { + cuthistosantilambda::v0radiusCut[j]->Fill(v0.mAntiLambda()); + } + } + for (uint32_t j = 0; j < cuthistosantilambda::dcapostopvcuts.size(); j++) { + std::string dcapostopantilambda = cuthistosantilambda::dcapostopvcuts[j]; + size_t pos = dcapostopantilambda.find("_"); + dcapostopantilambda[pos] = '.'; + const float dcapostopcutantilambdavalue = std::stod(dcapostopantilambda); + if (std::abs(v0.dcapostopv()) > dcapostopcutantilambdavalue) { + cuthistosantilambda::dcapostopCut[j]->Fill(v0.mAntiLambda()); + } + } + for (uint32_t j = 0; j < cuthistosantilambda::dcanegtopvcuts.size(); j++) { + std::string dcanegtopantilambda = cuthistosantilambda::dcanegtopvcuts[j]; + size_t pos = dcanegtopantilambda.find("_"); + dcanegtopantilambda[pos] = '.'; + const float dcanegtopcutantilambdavalue = std::stod(dcanegtopantilambda); + if (std::abs(v0.dcanegtopv()) > dcanegtopcutantilambdavalue) { + cuthistosantilambda::dcanegtopCut[j]->Fill(v0.mAntiLambda()); + } + } + } + } + } + } + } + PROCESS_SWITCH(v0topologicalcuts, recMCProcess, "Process Run 3 MC:Reconstructed", true); + PROCESS_SWITCH(v0topologicalcuts, dataProcess, "Process Run 3 Data,", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Strangeness/vzero_cascade_absorption.cxx b/PWGLF/Tasks/Strangeness/vzero_cascade_absorption.cxx index 8080130f637..6ca2e43ba69 100644 --- a/PWGLF/Tasks/Strangeness/vzero_cascade_absorption.cxx +++ b/PWGLF/Tasks/Strangeness/vzero_cascade_absorption.cxx @@ -30,15 +30,16 @@ #include "Common/Core/TrackSelection.h" #include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" #include "Common/DataModel/PIDResponse.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::constants::physics; using std::array; using SelectedCollisions = soa::Join; + using SimCollisions = soa::Join; using FullTracks = soa::Join; @@ -73,90 +74,77 @@ struct vzero_cascade_absorption { // Configurable Parameters Configurable minTPCnClsFound{"minTPCnClsFound", 80.0f, "min number of found TPC clusters"}; - Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 80.0f, "min number of found TPC crossed rows"}; + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 80.0f, "min number of TPC crossed rows"}; Configurable maxChi2TPC{"maxChi2TPC", 4.0f, "max chi2 per cluster TPC"}; - Configurable etaMin{"etaMin", -0.5f, "etaMin"}; - Configurable etaMax{"etaMax", +0.5f, "etaMax"}; + Configurable etaMin{"etaMin", -0.5f, "eta min"}; + Configurable etaMax{"etaMax", +0.5f, "eta max"}; Configurable pMin_k0postrack{"pMin_k0postrack", 0.3f, "Min Momentum K0 pos track"}; Configurable pMax_k0postrack{"pMax_k0postrack", 5.0f, "Max Momentum K0 pos track"}; Configurable pMin_k0negtrack{"pMin_k0negtrack", 0.3f, "Min Momentum K0 neg track"}; Configurable pMax_k0negtrack{"pMax_k0negtrack", 5.0f, "Max Momentum K0 neg track"}; - Configurable pMin_Lambda_proton{"pMin_Lambda_proton", 0.3f, "Min Momentum proton from Lambda"}; - Configurable pMax_Lambda_proton{"pMax_Lambda_proton", 5.0f, "Max Momentum proton from Lambda"}; - Configurable pMin_Lambda_pion{"pMin_Lambda_pion", 0.2f, "Min Momentum pion from Lambda"}; - Configurable pMax_Lambda_pion{"pMax_Lambda_pion", 1.0f, "Max Momentum pion from Lambda"}; - Configurable requirehitsITS{"requirehitsITS", true, "require ITS hits for daughters"}; - Configurable> hit_requirement_before_target{"hit_requirement_before_target", {0, 0, 0, 1, 1, 1, 1}, "ITS Hits before target"}; - Configurable> hit_requirement_after_target{"hit_requirement_after_target", {0, 0, 0, 0, 0, 1, 1}, "ITS Hits after target"}; - Configurable useTOF{"useTOF", true, "use TOF for PID"}; + Configurable pMin_Lambda_proton{"pMin_Lambda_proton", 0.3f, "Min Momentum proton from (Anti)Lambda"}; + Configurable pMax_Lambda_proton{"pMax_Lambda_proton", 5.0f, "Max Momentum proton from (Anti)Lambda"}; + Configurable pMin_Lambda_pion{"pMin_Lambda_pion", 0.2f, "Min Momentum pion from (Anti)Lambda"}; + Configurable pMax_Lambda_pion{"pMax_Lambda_pion", 1.2f, "Max Momentum pion from (Anti)Lambda"}; Configurable nsigmaTPCmin{"nsigmaTPCmin", -3.0f, "Minimum nsigma TPC"}; Configurable nsigmaTPCmax{"nsigmaTPCmax", +3.0f, "Maximum nsigma TPC"}; Configurable nsigmaTOFmin{"nsigmaTOFmin", -3.0f, "Minimum nsigma TOF"}; Configurable nsigmaTOFmax{"nsigmaTOFmax", +3.0f, "Maximum nsigma TOF"}; Configurable minimumV0Radius{"minimumV0Radius", 0.5f, "Minimum V0 Radius"}; Configurable maximumV0Radius{"maximumV0Radius", 40.0f, "Maximum V0 Radius"}; - Configurable minimumCascRadius{"minimumCascRadius", 0.5f, "Minimum Cascade Radius"}; - Configurable maximumCascRadius{"maximumCascRadius", 40.0f, "Maximum Cascade Radius"}; Configurable dcanegtoPVmin{"dcanegtoPVmin", 0.1f, "Minimum DCA Neg To PV"}; Configurable dcapostoPVmin{"dcapostoPVmin", 0.1f, "Minimum DCA Pos To PV"}; - Configurable dcaBachelorToPVmin{"dcaBachelorToPVmin", 0.1f, "Minimum DCA bachelor To PV"}; - Configurable dcaV0ToPVmin{"dcaV0ToPVmin", 0.1f, "Minimum DCA V0 To PV for cascades"}; Configurable v0cospaMin{"v0cospaMin", 0.99f, "Minimum V0 CosPA"}; - Configurable casccospaMin{"casccospaMin", 0.99f, "Minimum Cascade CosPA"}; Configurable dcaV0DaughtersMax{"dcaV0DaughtersMax", 0.5f, "Maximum DCA Daughters"}; - Configurable dcaCascDaughtersMax{"dcaCascDaughtersMax", 0.5f, "Maximum DCA Cascade Daughters"}; Configurable Rmin_beforeAbs{"Rmin_beforeAbs", 10.0f, "Rmin before target"}; Configurable Rmax_beforeAbs{"Rmax_beforeAbs", 15.0f, "Rmax before target"}; Configurable Rmin_afterAbs{"Rmin_afterAbs", 26.0f, "Rmin after target"}; Configurable Rmax_afterAbs{"Rmax_afterAbs", 31.0f, "Rmax after target"}; + Configurable useTOF{"useTOF", true, "use TOF for PID"}; + Configurable requirehitsITS{"requirehitsITS", true, "require ITS hits for daughters"}; + Configurable> hit_req_before_target{"hit_req_before_target", {0, 0, 0, 1, 1, 1, 1}, "ITS Hits before target"}; + Configurable> hit_req_after_target{"hit_req_after_target", {0, 0, 0, 0, 0, 1, 1}, "ITS Hits after target"}; void init(InitContext const&) { - // Histograms - registryQC.add("event_counter_data", "event counter data", HistType::kTH1F, {{5, 0, 5, "number of events"}}); - registryQC.add("event_counter_mc", "event counter mc", HistType::kTH1F, {{5, 0, 5, "number of events"}}); + // QC Histograms (event counters) + registryQC.add("event_counter_data", "event counter data", HistType::kTH1F, {{5, 0, 5, "number of events data"}}); + registryQC.add("event_counter_mc", "event counter mc", HistType::kTH1F, {{5, 0, 5, "number of events mc"}}); // K0 short - registryData.add("K0_before_target_data", "K0 before target data", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {240, 0.44, 0.56, "m (GeV/c^{2})"}}); - registryData.add("K0_after_target_data", "K0 after target data", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {240, 0.44, 0.56, "m (GeV/c^{2})"}}); - registryMC.add("K0_before_target_mc", "K0 before target mc", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {240, 0.44, 0.56, "m (GeV/c^{2})"}}); - registryMC.add("K0_after_target_mc", "K0 after target mc", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {240, 0.44, 0.56, "m (GeV/c^{2})"}}); - - // Lambda and Antilambda - registryData.add("Lambda_before_target_data", "Lambda before target data", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {200, 1.09, 1.14, "m (GeV/c^{2})"}}); - registryData.add("Lambda_after_target_data", "Lambda after target data", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {200, 1.09, 1.14, "m (GeV/c^{2})"}}); - registryData.add("AntiLambda_before_target_data", "AntiLambda before target data", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {200, 1.09, 1.14, "m (GeV/c^{2})"}}); - registryData.add("AntiLambda_after_target_data", "AntiLambda after target data", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {200, 1.09, 1.14, "m (GeV/c^{2})"}}); - registryMC.add("Lambda_before_target_mc", "Lambda before target mc", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {200, 1.09, 1.14, "m (GeV/c^{2})"}}); - registryMC.add("Lambda_after_target_mc", "Lambda after target mc", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {200, 1.09, 1.14, "m (GeV/c^{2})"}}); - registryMC.add("AntiLambda_before_target_mc", "AntiLambda before target mc", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {200, 1.09, 1.14, "m (GeV/c^{2})"}}); - registryMC.add("AntiLambda_after_target_mc", "AntiLambda after target mc", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {200, 1.09, 1.14, "m (GeV/c^{2})"}}); + registryData.add("K0_before_target_data", "K0 before target data", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {240, 0.44, 0.56, "m (GeV/c^{2})"}}); + registryData.add("K0_after_target_data", "K0 after target data", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {240, 0.44, 0.56, "m (GeV/c^{2})"}}); + registryMC.add("K0_before_target_mc", "K0 before target mc", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {240, 0.44, 0.56, "m (GeV/c^{2})"}}); + registryMC.add("K0_after_target_mc", "K0 after target mc", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {240, 0.44, 0.56, "m (GeV/c^{2})"}}); + + // Lambda + registryData.add("Lambda_before_target_data", "Lambda before target data", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {200, 1.09, 1.14, "m (GeV/c^{2})"}}); + registryData.add("Lambda_after_target_data", "Lambda after target data", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {200, 1.09, 1.14, "m (GeV/c^{2})"}}); + registryMC.add("Lambda_before_target_mc", "Lambda before target mc", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {200, 1.09, 1.14, "m (GeV/c^{2})"}}); + registryMC.add("Lambda_after_target_mc", "Lambda after target mc", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {200, 1.09, 1.14, "m (GeV/c^{2})"}}); + + // Antilambda + registryData.add("AntiLambda_before_target_data", "AntiLambda before target data", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {200, 1.09, 1.14, "m (GeV/c^{2})"}}); + registryData.add("AntiLambda_after_target_data", "AntiLambda after target data", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {200, 1.09, 1.14, "m (GeV/c^{2})"}}); + registryMC.add("AntiLambda_before_target_mc", "AntiLambda before target mc", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {200, 1.09, 1.14, "m (GeV/c^{2})"}}); + registryMC.add("AntiLambda_after_target_mc", "AntiLambda after target mc", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {200, 1.09, 1.14, "m (GeV/c^{2})"}}); // Generated Distributions - registryMC.add("Lambda_before_target_mc_gen", "Lambda before target mc gen", HistType::kTH1F, {{200, 0.0, 10.0, "p (GeV/c)"}}); - registryMC.add("Lambda_after_target_mc_gen", "Lambda after target mc gen", HistType::kTH1F, {{200, 0.0, 10.0, "p (GeV/c)"}}); - registryMC.add("AntiLambda_before_target_mc_gen", "AntiLambda before target mc gen", HistType::kTH1F, {{200, 0.0, 10.0, "p (GeV/c)"}}); - registryMC.add("AntiLambda_after_target_mc_gen", "AntiLambda after target mc gen", HistType::kTH1F, {{200, 0.0, 10.0, "p (GeV/c)"}}); + registryMC.add("Lambda_before_target_mc_gen", "Lambda before target mc gen", HistType::kTH1F, {{100, 0.0, 10.0, "p (GeV/c)"}}); + registryMC.add("Lambda_after_target_mc_gen", "Lambda after target mc gen", HistType::kTH1F, {{100, 0.0, 10.0, "p (GeV/c)"}}); + registryMC.add("AntiLambda_before_target_mc_gen", "AntiLambda before target mc gen", HistType::kTH1F, {{100, 0.0, 10.0, "p (GeV/c)"}}); + registryMC.add("AntiLambda_after_target_mc_gen", "AntiLambda after target mc gen", HistType::kTH1F, {{100, 0.0, 10.0, "p (GeV/c)"}}); // Resolution - registryMC.add("K0_Rresolution_before_target", "K0 Rresolution before target", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {500, -5, 5, "#Delta R (cm)"}}); - registryMC.add("K0_Rresolution_after_target", "K0 Rresolution after target", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {500, -5, 5, "#Delta R (cm)"}}); - registryMC.add("Lambda_Rresolution_before_target", "Lambda Rresolution before target", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {500, -5, 5, "#Delta R (cm)"}}); - registryMC.add("Lambda_Rresolution_after_target", "Lambda Rresolution after target", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {500, -5, 5, "#Delta R (cm)"}}); - registryMC.add("AntiLambda_Rresolution_before_target", "AntiLambda Rresolution before target", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {500, -5, 5, "#Delta R (cm)"}}); - registryMC.add("AntiLambda_Rresolution_after_target", "AntiLambda Rresolution after target", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {500, -5, 5, "#Delta R (cm)"}}); - - /* - registryData.add("Csi_before_target", "Csi_before_target", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {200, 1.305, 1.34, "m (GeV/c)"}}); - registryData.add("Csi_after_target", "Csi_after_target", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {200, 1.305, 1.34, "m (GeV/c)"}}); - registryData.add("AntiCsi_before_target", "AntiCsi_before_target", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {200, 1.3, 1.35, "m (GeV/c)"}}); - registryData.add("AntiCsi_after_target", "AntiCsi_after_target", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {200, 1.3, 1.35, "m (GeV/c)"}}); - registryData.add("Omega_before_target", "Omega_before_target", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {200, 1.6, 1.75, "m (GeV/c)"}}); - registryData.add("Omega_after_target", "Omega_after_target", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {200, 1.6, 1.75, "m (GeV/c)"}}); - registryData.add("AntiOmega_before_target", "AntiOmega_before_target", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {200, 1.6, 1.75, "m (GeV/c)"}}); - registryData.add("AntiOmega_after_target", "AntiOmega_after_target", HistType::kTH2F, {{200, 0.0, 10.0, "p (GeV/c)"}, {200, 1.6, 1.75, "m (GeV/c)"}});*/ + registryMC.add("K0_Rresolution_before_target", "K0 Rresolution before target", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {200, -5, 5, "#Delta R (cm)"}}); + registryMC.add("K0_Rresolution_after_target", "K0 Rresolution after target", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {200, -5, 5, "#Delta R (cm)"}}); + registryMC.add("Lambda_Rresolution_before_target", "Lambda Rresolution before target", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {200, -5, 5, "#Delta R (cm)"}}); + registryMC.add("Lambda_Rresolution_after_target", "Lambda Rresolution after target", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {200, -5, 5, "#Delta R (cm)"}}); + registryMC.add("AntiLambda_Rresolution_before_target", "AntiLambda Rresolution before target", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {200, -5, 5, "#Delta R (cm)"}}); + registryMC.add("AntiLambda_Rresolution_after_target", "AntiLambda Rresolution after target", HistType::kTH2F, {{100, 0.0, 10.0, "p (GeV/c)"}, {200, -5, 5, "#Delta R (cm)"}}); } + // Hits on ITS Layer bool hasHitOnITSlayer(uint8_t itsClsmap, int layer) { unsigned char test_bit = 1 << layer; @@ -164,8 +152,8 @@ struct vzero_cascade_absorption { } // Single-Track Selection - template - bool passedSingleTrackSelection(const T1& track, const C&) + template + bool passedSingleTrackSelection(const T1& track) { // Single-Track Selections if (requirehitsITS && (!track.hasITS())) @@ -186,14 +174,13 @@ struct vzero_cascade_absorption { } // K0s Selections - template - bool passedK0Selection(const T1& v0, const T2& ntrack, const T2& ptrack, - const C& collision) + template + bool passedK0Selection(const V& v0, const T1& ntrack, const T2& ptrack, const C& /*collision*/) { // Single-Track Selections - if (!passedSingleTrackSelection(ptrack, collision)) + if (!passedSingleTrackSelection(ptrack)) return false; - if (!passedSingleTrackSelection(ntrack, collision)) + if (!passedSingleTrackSelection(ntrack)) return false; // Momentum K0 Daughters @@ -236,14 +223,13 @@ struct vzero_cascade_absorption { } // Lambda Selections - template - bool passedLambdaSelection(const T1& v0, const T2& ntrack, const T2& ptrack, - const C& collision) + template + bool passedLambdaSelection(const V& v0, const T1& ntrack, const T2& ptrack, const C& /*collision*/) { // Single-Track Selections - if (!passedSingleTrackSelection(ptrack, collision)) + if (!passedSingleTrackSelection(ptrack)) return false; - if (!passedSingleTrackSelection(ntrack, collision)) + if (!passedSingleTrackSelection(ntrack)) return false; // Momentum Lambda Daughters @@ -286,14 +272,13 @@ struct vzero_cascade_absorption { } // AntiLambda Selections - template - bool passedAntiLambdaSelection(const T1& v0, const T2& ntrack, const T2& ptrack, - const C& collision) + template + bool passedAntiLambdaSelection(const V& v0, const T1& ntrack, const T2& ptrack, const C& /*collision*/) { // Single-Track Selections - if (!passedSingleTrackSelection(ptrack, collision)) + if (!passedSingleTrackSelection(ptrack)) return false; - if (!passedSingleTrackSelection(ntrack, collision)) + if (!passedSingleTrackSelection(ntrack)) return false; // Momentum Lambda Daughters @@ -355,8 +340,9 @@ struct vzero_cascade_absorption { // Event Counter (after cut on z_vtx) registryQC.fill(HIST("event_counter_data"), 2.5); - auto hit_ITS_before_target = static_cast>(hit_requirement_before_target); - auto hit_ITS_after_target = static_cast>(hit_requirement_after_target); + // Hits in ITS Layers + auto hit_ITS_before_target = static_cast>(hit_req_before_target); + auto hit_ITS_after_target = static_cast>(hit_req_after_target); // Loop over Reconstructed V0s for (auto& v0 : fullV0s) { @@ -424,15 +410,15 @@ struct vzero_cascade_absorption { if (v0.v0radius() > Rmin_afterAbs && v0.v0radius() < Rmax_afterAbs) registryData.fill(HIST("AntiLambda_after_target_data"), v0.p(), v0.mAntiLambda()); } - } // end loop on V0s - } // end processData + } + } PROCESS_SWITCH(vzero_cascade_absorption, processData, "Process data", true); Preslice perCollision = o2::aod::v0data::collisionId; Preslice perMCCollision = o2::aod::mcparticle::mcCollisionId; // Process MC Rec - void processMCrec(SimCollisions const& collisions, MCTracks const&, aod::V0Datas const& fullV0s, aod::McCollisions const&, const aod::McParticles&) + void processMCrec(SimCollisions const& collisions, MCTracks const& /*mcTracks*/, aod::V0Datas const& fullV0s, aod::McCollisions const& /*mcCollisions*/, const aod::McParticles& /*mcParticles*/) { for (const auto& collision : collisions) { @@ -469,8 +455,8 @@ struct vzero_cascade_absorption { if (!negTrack.passedTPCRefit()) continue; - auto hit_ITS_before_target = static_cast>(hit_requirement_before_target); - auto hit_ITS_after_target = static_cast>(hit_requirement_after_target); + auto hit_ITS_before_target = static_cast>(hit_req_before_target); + auto hit_ITS_after_target = static_cast>(hit_req_after_target); // ITS Requirement bool satisfyITSreq = true; @@ -502,6 +488,7 @@ struct vzero_cascade_absorption { continue; } + // Identification based on PDG bool isK0s = false; bool isLambda = false; bool isAntiLambda = false; @@ -510,7 +497,6 @@ struct vzero_cascade_absorption { for (auto& particleMotherOfPos : posParticle.mothers_as()) { if (particleMotherOfNeg == particleMotherOfPos && particleMotherOfNeg.pdgCode() == 310) isK0s = true; - if (particleMotherOfNeg == particleMotherOfPos && particleMotherOfNeg.pdgCode() == +3122) isLambda = true; if (particleMotherOfNeg == particleMotherOfPos && particleMotherOfNeg.pdgCode() == -3122) @@ -570,10 +556,9 @@ struct vzero_cascade_absorption { registryMC.fill(HIST("AntiLambda_Rresolution_after_target"), v0.p(), deltaR); } } - - } // end loop on V0s + } } - } // end processMC + } void processMCgen(o2::aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) { diff --git a/PWGLF/Utils/CMakeLists.txt b/PWGLF/Utils/CMakeLists.txt new file mode 100644 index 00000000000..51048b896a5 --- /dev/null +++ b/PWGLF/Utils/CMakeLists.txt @@ -0,0 +1,18 @@ +# 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_library(v0SelectionGroup + SOURCES v0SelectionGroup.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore) + +o2physics_target_root_dictionary(v0SelectionGroup + HEADERS v0SelectionGroup.h + LINKDEF v0SelectionGroupLinkDef.h) \ No newline at end of file diff --git a/PWGLF/Utils/collisionCuts.h b/PWGLF/Utils/collisionCuts.h index 29a5d9f429f..399454e9368 100644 --- a/PWGLF/Utils/collisionCuts.h +++ b/PWGLF/Utils/collisionCuts.h @@ -20,12 +20,12 @@ #ifndef PWGLF_UTILS_COLLISIONCUTS_H_ #define PWGLF_UTILS_COLLISIONCUTS_H_ +#include + #include "Framework/HistogramRegistry.h" #include "Framework/Logger.h" #include "Common/DataModel/EventSelection.h" -using namespace o2::framework; - namespace o2::analysis { @@ -34,59 +34,127 @@ class CollisonCuts public: virtual ~CollisonCuts() = default; + enum EvtSel { + kAllEvent = 0, + kFlagZvertex, + kFlagTrigerTVX, + kFlagTimeFrameBorder, + kFlagITSROFrameBorder, + kFlagSel8, + kFlagVertexITSTPC, + kFlagBunchPileup, + kFlagZvtxFT0vsPV, + kFlagOccupancy, + kNoCollInTimeRangeStandard, + kNoCollInTimeRangeNarrow, + kAllpassed + }; + + inline int binLabel(int index) + { + return index + 1; + } + /// \brief Pass the selection criteria to the class /// \param zvtxMax Maximal value of the z-vertex /// \param checkTrigger whether or not to check for the trigger alias - /// \param trig Requested trigger alias /// \param checkOffline whether or not to check for offline selection criteria - void setCuts(float zvtxMax, bool checkTrigger, int trig, bool checkOffline, bool checkRun3) + void setCuts(float zvtxMax, bool checkTrigger, bool checkOffline, bool checkRun3, bool triggerTVXsel = false, int trackOccupancyInTimeRangeMax = -1, int trackOccupancyInTimeRangeMin = -1) { mCutsSet = true; mZvtxMax = zvtxMax; mCheckTrigger = checkTrigger; - mTrigger = trig; mCheckOffline = checkOffline; + mTriggerTVXselection = triggerTVXsel; mCheckIsRun3 = checkRun3; mApplyTFBorderCut = false; - mApplyITSTPCmatching = false; + mApplyITSTPCvertex = false; mApplyZvertexTimedifference = false; mApplyPileupRejection = false; mApplyNoITSROBorderCut = false; + mApplyCollInTimeRangeNarrow = false; + mApplyCollInTimeRangeStandard = false; + mtrackOccupancyInTimeRangeMax = trackOccupancyInTimeRangeMax; + mtrackOccupancyInTimeRangeMin = trackOccupancyInTimeRangeMin; + mApplyRun2AliEventCuts = true; + mApplyRun2INELgtZERO = false; } /// Initializes histograms for the task /// \param registry Histogram registry to be passed - void init(HistogramRegistry* registry) + void init(o2::framework::HistogramRegistry* registry) { if (!mCutsSet) { LOGF(error, "Event selection not set - quitting!"); } + for (int i = 0; i < kNaliases; i++) { + bitList.push_back(1 << i); // BIT(i) + } mHistogramRegistry = registry; - mHistogramRegistry->add("Event/posZ", "; vtx_{z} (cm); Entries", kTH1F, {{250, -12.5, 12.5}}); + mHistogramRegistry->add("Event/posZ", "; vtx_{z} (cm); Entries", o2::framework::kTH1F, {{250, -12.5, 12.5}}); // z-vertex histogram after event selections + mHistogramRegistry->add("Event/posZ_noCut", "; vtx_{z} (cm); Entries", o2::framework::kTH1F, {{250, -12.5, 12.5}}); // z-vertex histogram before all selections if (mCheckIsRun3) { - mHistogramRegistry->add("Event/CentFV0A", "; vCentV0A; Entries", kTH1F, {{110, 0, 110}}); - mHistogramRegistry->add("Event/CentFT0M", "; vCentT0M; Entries", kTH1F, {{110, 0, 110}}); - mHistogramRegistry->add("Event/CentFT0C", "; vCentT0C; Entries", kTH1F, {{110, 0, 110}}); - mHistogramRegistry->add("Event/CentFT0A", "; vCentT0A; Entries", kTH1F, {{110, 0, 110}}); + mHistogramRegistry->add("Event/CentFT0M", "; vCentT0M; Entries", o2::framework::kTH1F, {{110, 0, 110}}); + mHistogramRegistry->add("Event/CentFT0C", "; vCentT0C; Entries", o2::framework::kTH1F, {{110, 0, 110}}); + mHistogramRegistry->add("Event/CentFT0A", "; vCentT0A; Entries", o2::framework::kTH1F, {{110, 0, 110}}); + mHistogramRegistry->add("Event/posZ_ITSOnly", "; vtx_{z} (cm); Entries", o2::framework::kTH1F, {{250, -12.5, 12.5}}); + mHistogramRegistry->add("Event/posZ_ITSTPC", "; vtx_{z} (cm); Entries", o2::framework::kTH1F, {{250, -12.5, 12.5}}); + mHistogramRegistry->add("Event/trackOccupancyInTimeRange_noCut", "; Occupancy; Entries", o2::framework::kTH1F, {{500, 0., 20000.}}); } else { - mHistogramRegistry->add("Event/CentRun2V0M", "; vCentV0M; Entries", kTH1F, {{110, 0, 110}}); + mHistogramRegistry->add("Event/CentRun2V0M", "; vCentV0M; Entries", o2::framework::kTH1F, {{110, 0, 110}}); } + mHistogramRegistry->add("CollCutCounts", "; ; Entries", o2::framework::kTH1F, {{kAllpassed + 1, 0, kAllpassed + 1}}); + mHistogramRegistry->get(HIST("CollCutCounts"))->GetXaxis()->SetBinLabel(binLabel(EvtSel::kAllEvent), "all"); + mHistogramRegistry->get(HIST("CollCutCounts"))->GetXaxis()->SetBinLabel(binLabel(EvtSel::kFlagZvertex), "Zvtx"); + mHistogramRegistry->get(HIST("CollCutCounts"))->GetXaxis()->SetBinLabel(binLabel(EvtSel::kFlagTrigerTVX), "IsTriggerTVX"); + mHistogramRegistry->get(HIST("CollCutCounts"))->GetXaxis()->SetBinLabel(binLabel(EvtSel::kFlagTimeFrameBorder), "NoTimeFrameBorder"); + mHistogramRegistry->get(HIST("CollCutCounts"))->GetXaxis()->SetBinLabel(binLabel(EvtSel::kFlagITSROFrameBorder), "NoITSROFrameBorder"); + mHistogramRegistry->get(HIST("CollCutCounts"))->GetXaxis()->SetBinLabel(binLabel(EvtSel::kFlagSel8), "sel8"); + mHistogramRegistry->get(HIST("CollCutCounts"))->GetXaxis()->SetBinLabel(binLabel(EvtSel::kFlagVertexITSTPC), "IsVertexITSTPC"); + mHistogramRegistry->get(HIST("CollCutCounts"))->GetXaxis()->SetBinLabel(binLabel(EvtSel::kFlagBunchPileup), "NoSameBunchPileup"); + mHistogramRegistry->get(HIST("CollCutCounts"))->GetXaxis()->SetBinLabel(binLabel(EvtSel::kFlagZvtxFT0vsPV), "IsGoodZvtxFT0vsPV"); + mHistogramRegistry->get(HIST("CollCutCounts"))->GetXaxis()->SetBinLabel(binLabel(EvtSel::kFlagOccupancy), "LowOccupancy"); + mHistogramRegistry->get(HIST("CollCutCounts"))->GetXaxis()->SetBinLabel(binLabel(EvtSel::kNoCollInTimeRangeStandard), "NoCollInTimeRangeStandard"); + mHistogramRegistry->get(HIST("CollCutCounts"))->GetXaxis()->SetBinLabel(binLabel(EvtSel::kNoCollInTimeRangeNarrow), "NoCollInTimeRangeNarrow"); + mHistogramRegistry->get(HIST("CollCutCounts"))->GetXaxis()->SetBinLabel(binLabel(EvtSel::kAllpassed), "Allpassed"); } /// Print some debug information void printCuts() { - LOGF(info, "Debug information for Collison Cuts \n Max. z-vertex: %f \n Check trigger: %d \n Trigger: %d \n Check offline: %d \n", mZvtxMax, mCheckTrigger, mTrigger, mCheckOffline); + LOGF(info, "Debug information for Collison Cuts"); + LOGF(info, "Max. z-vertex: %f", mZvtxMax); + LOGF(info, "Check trigger: %d", mCheckTrigger); + LOGF(info, "Check offline: %d", mCheckOffline); + LOGF(info, "Check Run3: %d", mCheckIsRun3); + if (mCheckIsRun3) { + LOGF(info, "Trigger TVX selection: %d", mTriggerTVXselection); + LOGF(info, "Apply time frame border cut: %d", mApplyTFBorderCut); + LOGF(info, "Apply ITS-TPC vertex: %d", mApplyITSTPCvertex); + LOGF(info, "Apply NoCollInTimeRangeNarrow: %d", mApplyCollInTimeRangeNarrow); + LOGF(info, "Apply Z-vertex time difference: %d", mApplyZvertexTimedifference); + LOGF(info, "Apply Pileup rejection: %d", mApplyPileupRejection); + LOGF(info, "Apply NoITSRO frame border cut: %d", mApplyNoITSROBorderCut); + LOGF(info, "Track occupancy in time range max: %d", mtrackOccupancyInTimeRangeMax); + LOGF(info, "Track occupancy in time range min: %d", mtrackOccupancyInTimeRangeMin); + LOGF(info, "Apply NoCollInTimeRangeStandard: %d", mApplyCollInTimeRangeStandard); + } else { + LOGF(info, "Apply Run2 AliEventCuts: %d", mApplyRun2AliEventCuts); + LOGF(info, "Apply Run2 INELgtZERO: %d", mApplyRun2INELgtZERO); + } } - /// Scan the trigger alias of the event - void setInitialTriggerScan(bool checkTrigger) { mInitialTriggerScan = checkTrigger; } + /// Set MB selection + void setTriggerTVX(bool triggerTVXsel) { mTriggerTVXselection = triggerTVXsel; } /// Set the time frame border cut void setApplyTFBorderCut(bool applyTFBorderCut) { mApplyTFBorderCut = applyTFBorderCut; } /// Set the ITS-TPC matching cut - void setApplyITSTPCmatching(bool applyITSTPCmatching) { mApplyITSTPCmatching = applyITSTPCmatching; } + void setApplyITSTPCvertex(bool applyITSTPCvertex) { mApplyITSTPCvertex = applyITSTPCvertex; } + + /// Set the NoCollInTimeRangeNarrow cut + void setApplyCollInTimeRangeNarrow(bool applyCollInTimeRangeNarrow) { mApplyCollInTimeRangeNarrow = applyCollInTimeRangeNarrow; } /// Set the Z-vertex time difference cut void setApplyZvertexTimedifference(bool applyZvertexTimedifference) { mApplyZvertexTimedifference = applyZvertexTimedifference; } @@ -97,6 +165,21 @@ class CollisonCuts /// Set the NoITSRO frame border cut void setApplyNoITSROBorderCut(bool applyNoITSROBorderCut) { mApplyNoITSROBorderCut = applyNoITSROBorderCut; } + /// Set the track occupancy in time range cut + void setTrackOccupancyInTimeRange(int trackOccupancyInTimeRangeMax, int trackOccupancyInTimeRangeMin) + { + mtrackOccupancyInTimeRangeMax = trackOccupancyInTimeRangeMax; + mtrackOccupancyInTimeRangeMin = trackOccupancyInTimeRangeMin; + } + /// Set the NoCollInTimeRangeStandard cut + void setApplyCollInTimeRangeStandard(bool applyCollInTimeRangeStandard) { mApplyCollInTimeRangeStandard = applyCollInTimeRangeStandard; } + + /// Set the Run2 AliEventCuts cut + void setApplyRun2AliEventCuts(bool applyRun2AliEventCuts) { mApplyRun2AliEventCuts = applyRun2AliEventCuts; } + + /// Set the Run2 INELgtZERO cut + void setApplyRun2INELgtZERO(bool applyRun2INELgtZERO) { mApplyRun2INELgtZERO = applyRun2INELgtZERO; } + /// Check whether the collisions fulfills the specified selections /// \tparam T type of the collision /// \param col Collision @@ -104,54 +187,97 @@ class CollisonCuts template bool isSelected(T const& col) { + mHistogramRegistry->fill(HIST("Event/posZ_noCut"), col.posZ()); + if (mCheckIsRun3) { + mHistogramRegistry->fill(HIST("Event/trackOccupancyInTimeRange_noCut"), col.trackOccupancyInTimeRange()); + } + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kAllEvent); if (std::abs(col.posZ()) > mZvtxMax) { LOGF(debug, "Vertex out of range"); return false; } + if (mInitialColBitScan) { + for (const auto& bit : bitList) { + if (col.selection_bit(bit)) { + LOGF(info, "Trigger %d fired", bit); + } + } + mInitialColBitScan = false; + } + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagZvertex); if (mCheckIsRun3) { // Run3 case - if (mCheckOffline && !col.sel8()) { - LOGF(debug, "Offline selection failed (Run3)"); + if (!col.selection_bit(aod::evsel::kIsTriggerTVX) && mTriggerTVXselection) { + LOGF(debug, "Offline selection TVX failed (Run3)"); return false; } + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagTrigerTVX); if (!col.selection_bit(aod::evsel::kNoTimeFrameBorder) && mApplyTFBorderCut) { LOGF(debug, "Time frame border cut failed"); return false; } - if (!col.selection_bit(o2::aod::evsel::kIsVertexITSTPC) && mApplyITSTPCmatching) { + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagTimeFrameBorder); + if (!col.selection_bit(aod::evsel::kNoITSROFrameBorder) && mApplyNoITSROBorderCut) { + LOGF(debug, "NoITSRO frame border cut failed"); + return false; + } + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagITSROFrameBorder); + if (!col.sel8() && mCheckOffline) { + LOGF(debug, "Offline selection failed (Run3)"); + return false; + } + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagSel8); + if (!col.selection_bit(o2::aod::evsel::kIsVertexITSTPC) && mApplyITSTPCvertex) { LOGF(debug, "ITS-TPC matching cut failed"); return false; } + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagVertexITSTPC); + if (!col.selection_bit(o2::aod::evsel::kNoSameBunchPileup) && mApplyPileupRejection) { + LOGF(debug, "Pileup rejection failed"); + return false; + } + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagBunchPileup); + if (!col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow) && mApplyCollInTimeRangeNarrow) { + LOGF(debug, "NoCollInTimeRangeNarrow selection failed"); + return false; + } + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kNoCollInTimeRangeNarrow); if (!col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV) && mApplyZvertexTimedifference) { LOGF(debug, "Z-vertex time difference cut failed"); return false; } - if (!col.selection_bit(o2::aod::evsel::kNoSameBunchPileup) && mApplyPileupRejection) { - LOGF(debug, "Pileup rejection failed"); + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagZvtxFT0vsPV); + if (mtrackOccupancyInTimeRangeMax > 0 && col.trackOccupancyInTimeRange() > mtrackOccupancyInTimeRangeMax) { + LOGF(debug, "trackOccupancyInTimeRange selection failed"); return false; } - if (!col.selection_bit(aod::evsel::kNoITSROFrameBorder) && mApplyNoITSROBorderCut) { - LOGF(debug, "NoITSRO frame border cut failed"); + if (mtrackOccupancyInTimeRangeMin > 0 && col.trackOccupancyInTimeRange() < mtrackOccupancyInTimeRangeMin) { + LOGF(debug, "trackOccupancyInTimeRange selection failed"); return false; } + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagOccupancy); + if ((!col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) && mApplyCollInTimeRangeStandard) { + LOGF(debug, "NoCollInTimeRangeStandard selection failed"); + return false; + } + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kNoCollInTimeRangeStandard); } else { // Run2 case if (mCheckOffline && !col.sel7()) { LOGF(debug, "Offline selection failed (sel7)"); return false; } - } - if (mCheckTrigger && !col.alias_bit(mTrigger)) { - LOGF(debug, "Trigger selection failed"); - if (mInitialTriggerScan) { // Print out the trigger bits - LOGF(debug, "Trigger scan initialized"); - for (int i = 0; i < kNaliases; i++) { - if (col.alias_bit(i)) { - LOGF(debug, "Trigger %d fired", i); - } - } - mInitialTriggerScan = false; + auto bc = col.template bc_as(); + if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kAliEventCutsAccepted)) && !mApplyRun2AliEventCuts) { + LOGF(debug, "Offline selection failed (AliEventCuts)"); + return false; } - return false; + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagSel8); + if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kINELgtZERO)) && !mApplyRun2INELgtZERO) { + LOGF(debug, "INELgtZERO selection failed"); + return false; + } + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kAllpassed); } + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kAllpassed); return true; } @@ -163,7 +289,11 @@ class CollisonCuts { if (mHistogramRegistry) { mHistogramRegistry->fill(HIST("Event/posZ"), col.posZ()); - mHistogramRegistry->fill(HIST("Event/CentFV0A"), col.centFV0A()); + if (!col.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + mHistogramRegistry->fill(HIST("Event/posZ_ITSOnly"), col.posZ()); + } else { + mHistogramRegistry->fill(HIST("Event/posZ_ITSTPC"), col.posZ()); + } mHistogramRegistry->fill(HIST("Event/CentFT0M"), col.centFT0M()); mHistogramRegistry->fill(HIST("Event/CentFT0C"), col.centFT0C()); mHistogramRegistry->fill(HIST("Event/CentFT0A"), col.centFT0A()); @@ -183,19 +313,27 @@ class CollisonCuts } private: - HistogramRegistry* mHistogramRegistry = nullptr; ///< For QA output - bool mCutsSet = false; ///< Protection against running without cuts - bool mCheckTrigger = false; ///< Check for trigger - bool mCheckOffline = false; ///< Check for offline criteria (might change) - bool mCheckIsRun3 = false; ///< Check if running on Pilot Beam - bool mInitialTriggerScan = false; ///< Check trigger when the event is first selected - bool mApplyTFBorderCut = false; ///< Apply time frame border cut - bool mApplyITSTPCmatching = false; ///< selects collisions with at least one ITS-TPC track - bool mApplyZvertexTimedifference = false; ///< removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference. - bool mApplyPileupRejection = false; ///< Pileup rejection - bool mApplyNoITSROBorderCut = false; ///< Apply NoITSRO frame border cut - int mTrigger = kINT7; ///< Trigger to check for - float mZvtxMax = 999.f; ///< Maximal deviation from nominal z-vertex (cm) + using BCsWithRun2Info = soa::Join; + o2::framework::HistogramRegistry* mHistogramRegistry = nullptr; ///< For QA output + std::vector bitList; + bool mCutsSet = false; ///< Protection against running without cuts + bool mInitialColBitScan = true; ///< Scan for collision bit + bool mCheckTrigger = false; ///< Check for trigger + bool mTriggerTVXselection = false; ///< Check for trigger TVX selection + bool mCheckOffline = false; ///< Check for offline criteria (might change) + bool mCheckIsRun3 = false; ///< Check if running on Pilot Beam + bool mApplyTFBorderCut = false; ///< Apply time frame border cut + bool mApplyITSTPCvertex = false; ///< Apply at least one ITS-TPC track for vertexing + bool mApplyCollInTimeRangeNarrow = false; ///< Apply NoCollInTimeRangeNarrow selection + bool mApplyZvertexTimedifference = false; ///< removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference. + bool mApplyPileupRejection = false; ///< Pileup rejection + bool mApplyNoITSROBorderCut = false; ///< Apply NoITSRO frame border cut + bool mApplyCollInTimeRangeStandard = false; ///< Apply NoCollInTimeRangeStandard selection + bool mApplyRun2AliEventCuts = true; ///< Apply Run2 AliEventCuts + bool mApplyRun2INELgtZERO = false; ///< Apply Run2 INELgtZERO selection + float mZvtxMax = 999.f; ///< Maximal deviation from nominal z-vertex (cm) + int mtrackOccupancyInTimeRangeMax = -1; ///< Maximum trackOccupancyInTimeRange cut (-1 no cut) + int mtrackOccupancyInTimeRangeMin = -1; ///< Minimum trackOccupancyInTimeRange cut (-1 no cut) }; } // namespace o2::analysis diff --git a/PWGLF/Utils/inelGt.h b/PWGLF/Utils/inelGt.h new file mode 100644 index 00000000000..2ed513a902c --- /dev/null +++ b/PWGLF/Utils/inelGt.h @@ -0,0 +1,173 @@ +// 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 inelGt.h +/// \since 07/05/2024 +/// \brief Utilities for counting charged particles in |eta| region and define the INEL > N selection in the MC at the generated level +/// Based on cascqaanalysis.cxx +/// + +#ifndef PWGLF_UTILS_INELGT_H_ +#define PWGLF_UTILS_INELGT_H_ + +#include + +namespace o2 +{ +namespace pwglf +{ + +struct EtaCharge { + float eta; + int charge; +}; + +// Struct for counting charged particles in |eta| region +template +bool isINELgtNmc(TMcParticles particles, int nChToSatisfySelection, pdgDatabase pdgDB) +{ + // INEL > N (at least N+1 charged particles in |eta| < 1.0) + EtaCharge etaCharge; + std::vector ParticlesEtaAndCharge(particles.size()); + unsigned int nParticles = 0; + for (const auto& particle : particles) { + if (particle.isPhysicalPrimary() == 0) { + continue; // consider only primaries + } + etaCharge = {999, 0}; // refresh init. for safety + TParticlePDG* p = pdgDB->GetParticle(particle.pdgCode()); + if (!p) { + switch (std::to_string(particle.pdgCode()).length()) { + case 10: // nuclei + { + etaCharge = {particle.eta(), static_cast(particle.pdgCode() / 10000 % 1000)}; + ParticlesEtaAndCharge[nParticles++] = etaCharge; + break; + } + default: + break; + } + } else { + etaCharge = {particle.eta(), static_cast(p->Charge())}; + ParticlesEtaAndCharge[nParticles++] = etaCharge; + } + } + + ParticlesEtaAndCharge.resize(nParticles); + + auto etaChargeConditionFunc = [](EtaCharge elem) { + return ((TMath::Abs(elem.eta) < 1.0) && (TMath::Abs(elem.charge) > 0.001)); + }; + + if (std::count_if(ParticlesEtaAndCharge.begin(), ParticlesEtaAndCharge.end(), etaChargeConditionFunc) > nChToSatisfySelection) { + return true; + } else { + return false; + } +} + +template +bool isINELgt0mc(TMcParticles particles, pdgDatabase pdgDB) +{ + return isINELgtNmc(particles, 0, pdgDB); +} + +template +bool isINELgt1mc(TMcParticles particles, pdgDatabase pdgDB) +{ + return isINELgtNmc(particles, 1, pdgDB); +} + +template +struct ParticleCounter { + bool mSelectPrimaries = true; + pdgDatabase* mPdgDatabase; + + float countMultInAcceptance(const aod::McParticles& mcParticles, const float etamin, const float etamax) + { + // static_assert(etamin < etamax, "etamin must be smaller than etamax"); + float counter = 0; + for (const auto& particle : mcParticles) { + + // primary + if (mSelectPrimaries && !particle.isPhysicalPrimary()) { + continue; + } + + // has pdg + TParticlePDG* p = mPdgDatabase->get()->GetParticle(particle.pdgCode()); + if (!p) { + continue; + } + // is charged + if (abs(p->Charge()) == 0) { + continue; + } + // in acceptance + if (particle.eta() > etamin && particle.eta() < etamax) { + counter++; + } + } + return counter; + } + + float countEnergyInAcceptance(const aod::McParticles& mcParticles, const float etamin, const float etamax, const bool requireNeutral = false) + { + // static_assert(etamin < etamax, "etamin must be smaller than etamax"); + float counter = 0.f; + for (const auto& particle : mcParticles) { + + // primary + if (mSelectPrimaries && !particle.isPhysicalPrimary()) { + continue; + } + // has pdg + TParticlePDG* p = mPdgDatabase->get()->GetParticle(particle.pdgCode()); + if (!p) { + continue; + } + // is neutral + if (requireNeutral) { + if (std::abs(p->Charge()) > 1e-3) + continue; + } else { + if (std::abs(p->Charge()) <= 1e-3) + continue; + } + // in acceptance + if (particle.eta() > etamin && particle.eta() < etamax) { + counter += particle.e(); + } + } + return counter; + } + + float countFT0A(const aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, 3.5f, 4.9f); } + float countFT0C(const aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, -3.3f, -2.1f); } + float countFV0A(const aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, 2.2f, 5.1f); } + float countV0A(const aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, 2.8f, 5.1f); } + float countV0C(const aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, -3.7f, -1.7f); } + float countFDDA(const aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, 4.9f, 6.3f); } + float countFDDC(const aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, -7.f, -4.9f); } + + float countZNA(const aod::McParticles& mcParticles) { return countEnergyInAcceptance(mcParticles, 8.8f, 100.f, true); } + float countZNC(const aod::McParticles& mcParticles) { return countEnergyInAcceptance(mcParticles, -100.f, -8.8f, true); } + + float countITSIB(const aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, -2.f, 2.f); } + float countEta05(const aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, -0.5f, 0.5f); } + float countEta08(const aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, -0.8f, 0.8f); } +}; + +} // namespace pwglf +} // namespace o2 + +#endif // PWGLF_UTILS_INELGT_H_ diff --git a/PWGLF/Utils/mcParticle.h b/PWGLF/Utils/mcParticle.h new file mode 100644 index 00000000000..e85d98ca5f0 --- /dev/null +++ b/PWGLF/Utils/mcParticle.h @@ -0,0 +1,335 @@ +// 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 mcParticle.h +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \author Francesca Ercolessi francesca.ercolessi@cern.ch +/// \since 31/05/2024 +/// \brief Utilities to handle the MC information +/// + +#ifndef PWGLF_UTILS_MCPARTICLE_H_ +#define PWGLF_UTILS_MCPARTICLE_H_ + +#include +#include + +#include "ReconstructionDataFormats/PID.h" + +namespace o2 +{ +namespace pwglf +{ + +/// @brief Extended the indices of the PID class with additional particles +class PIDExtended +{ + public: + typedef int16_t ID; + + static constexpr ID Electron = 0; + static constexpr ID Muon = 1; + static constexpr ID Pion = 2; + static constexpr ID Kaon = 3; + static constexpr ID Proton = 4; + static constexpr ID Deuteron = 5; + static constexpr ID Triton = 6; + static constexpr ID Helium3 = 7; + static constexpr ID Alpha = 8; + static constexpr ID PI0 = 9; + static constexpr ID Photon = 10; + static constexpr ID K0 = 11; + static constexpr ID Lambda = 12; + static constexpr ID HyperTriton = 13; + static constexpr ID Hyperhydrog4 = 14; + static constexpr ID XiMinus = 15; + static constexpr ID OmegaMinus = 16; + static constexpr ID HyperHelium4 = 17; + static constexpr ID HyperHelium5 = 18; + + static_assert(Electron == o2::track::PID::Electron, "PID::Electron mismatch"); + static_assert(Muon == o2::track::PID::Muon, "PID::Muon mismatch"); + static_assert(Pion == o2::track::PID::Pion, "PID::Pion mismatch"); + static_assert(Kaon == o2::track::PID::Kaon, "PID::Kaon mismatch"); + static_assert(Proton == o2::track::PID::Proton, "PID::Proton mismatch"); + static_assert(Deuteron == o2::track::PID::Deuteron, "PID::Deuteron mismatch"); + static_assert(Triton == o2::track::PID::Triton, "PID::Triton mismatch"); + static_assert(Helium3 == o2::track::PID::Helium3, "PID::Helium3 mismatch"); + static_assert(Alpha == o2::track::PID::Alpha, "PID::Alpha mismatch"); + static_assert(PI0 == o2::track::PID::PI0, "PID::PI0 mismatch"); + static_assert(Photon == o2::track::PID::Photon, "PID::Photon mismatch"); + static_assert(K0 == o2::track::PID::K0, "PID::K0 mismatch"); + static_assert(Lambda == o2::track::PID::Lambda, "PID::Lambda mismatch"); + static_assert(HyperTriton == o2::track::PID::HyperTriton, "PID::HyperTriton mismatch"); + static_assert(Hyperhydrog4 == o2::track::PID::Hyperhydrog4, "PID::Hyperhydrog4 mismatch"); + static_assert(XiMinus == o2::track::PID::XiMinus, "PID::XiMinus mismatch"); + static_assert(OmegaMinus == o2::track::PID::OmegaMinus, "PID::OmegaMinus mismatch"); + // static_assert(HyperHelium4 == o2::track::PID::HyperHelium4, "PID::HyperHelium4 mismatch"); + // static_assert(HyperHelium5 == o2::track::PID::HyperHelium5, "PID::HyperHelium5 mismatch"); + + static constexpr ID PIDCountsUntilAl = 9; // Number of indices defined in PID.h equivalent to o2::track::PID::NIDs + // static_assert(PIDCountsUntilAl == o2::track::PID::NIDs, "PID::NIDs mismatch"); + + static constexpr ID PIDCounts = 19; // Number of indices defined in PID.h + // static_assert(PIDCounts == o2::track::PID::NIDsTot, "PID::NIDsTot mismatch"); + // Define an array of IDs + static constexpr std::array mIDsUntilAl = {Electron, Muon, Pion, Kaon, Proton, Deuteron, Triton, Helium3, Alpha}; + static constexpr std::array mIDs = {Electron, Muon, Pion, Kaon, Proton, Deuteron, Triton, Helium3, Alpha, PI0, Photon, K0, Lambda, HyperTriton, Hyperhydrog4, XiMinus, OmegaMinus, HyperHelium4, HyperHelium5}; + + // Define the antiparticles + static constexpr ID Positron = PIDCounts; + static constexpr ID MuonPlus = PIDCounts + 1; + static constexpr ID PionMinus = PIDCounts + 2; + static constexpr ID KaonMinus = PIDCounts + 3; + static constexpr ID AntiProton = PIDCounts + 4; + static constexpr ID AntiDeuteron = PIDCounts + 5; + static constexpr ID AntiTriton = PIDCounts + 6; + static constexpr ID AntiHelium3 = PIDCounts + 7; + static constexpr ID AntiAlpha = PIDCounts + 8; + static constexpr ID AntiLambda = PIDCounts + 9; + static constexpr ID AntiHyperTriton = PIDCounts + 10; + static constexpr ID AntiHyperhydrog4 = PIDCounts + 11; + static constexpr ID XiPlus = PIDCounts + 12; + static constexpr ID OmegaPlus = PIDCounts + 13; + static constexpr ID AntiHyperHelium4 = PIDCounts + 14; + static constexpr ID AntiHyperHelium5 = PIDCounts + 15; + + static constexpr ID Neutron = PIDCounts + 16; + static constexpr ID AntiNeutron = PIDCounts + 17; + static constexpr ID Phi = PIDCounts + 18; + static constexpr ID BZero = PIDCounts + 19; + static constexpr ID BPlus = PIDCounts + 20; + static constexpr ID BS = PIDCounts + 21; + static constexpr ID D0 = PIDCounts + 22; + static constexpr ID DPlus = PIDCounts + 23; + static constexpr ID DS = PIDCounts + 24; + static constexpr ID DStar = PIDCounts + 25; + static constexpr ID ChiC1 = PIDCounts + 26; + static constexpr ID JPsi = PIDCounts + 27; + static constexpr ID LambdaB0 = PIDCounts + 28; + static constexpr ID LambdaCPlus = PIDCounts + 29; + static constexpr ID OmegaC0 = PIDCounts + 30; + static constexpr ID SigmaC0 = PIDCounts + 31; + static constexpr ID SigmaCPlusPlus = PIDCounts + 32; + static constexpr ID X3872 = PIDCounts + 33; + static constexpr ID Xi0 = PIDCounts + 34; + static constexpr ID XiB0 = PIDCounts + 35; + static constexpr ID XiCCPlusPlus = PIDCounts + 36; + static constexpr ID XiCPlus = PIDCounts + 37; + static constexpr ID XiC0 = PIDCounts + 38; + static constexpr ID NIDsTot = PIDCounts + 39; + + static constexpr const char* sNames[NIDsTot + 1] = { + o2::track::pid_constants::sNames[Electron], // Electron + o2::track::pid_constants::sNames[Muon], // Muon + o2::track::pid_constants::sNames[Pion], // Pion + o2::track::pid_constants::sNames[Kaon], // Kaon + o2::track::pid_constants::sNames[Proton], // Proton + o2::track::pid_constants::sNames[Deuteron], // Deuteron + o2::track::pid_constants::sNames[Triton], // Triton + o2::track::pid_constants::sNames[Helium3], // Helium3 + o2::track::pid_constants::sNames[Alpha], // Alpha + o2::track::pid_constants::sNames[PI0], // PI0 + o2::track::pid_constants::sNames[Photon], // Photon + o2::track::pid_constants::sNames[K0], // K0 + o2::track::pid_constants::sNames[Lambda], // Lambda + o2::track::pid_constants::sNames[HyperTriton], // HyperTriton + o2::track::pid_constants::sNames[Hyperhydrog4], // Hyperhydrog4 + o2::track::pid_constants::sNames[XiMinus], // XiMinus + o2::track::pid_constants::sNames[OmegaMinus], // OmegaMinus + "HyperHelium4", // HyperHelium4 + "HyperHelium5", // HyperHelium5 + "Positron", // Positron + "MuonPlus", // MuonPlus + "PionMinus", // PionMinus + "KaonMinus", // KaonMinus + "AntiProton", // AntiProton + "AntiDeuteron", // AntiDeuteron + "AntiTriton", // AntiTriton + "AntiHelium3", // AntiHelium3 + "AntiAlpha", // AntiAlpha + "AntiLambda", // AntiLambda + "AntiHyperTriton", // AntiHyperTriton + "AntiHyperhydrog4", // AntiHyperhydrog4 + "XiPlus", // XiPlus + "OmegaPlus", // OmegaPlus + "AntiHyperHelium4", // AntiHyperHelium4 + "AntiHyperHelium5", // AntiHyperHelium5 + "Neutron", // Neutron + "AntiNeutron", // AntiNeutron + "Phi", // Phi + "BZero", // BZero + "BPlus", // BPlus + "BS", // BS + "D0", // D0 + "DPlus", // DPlus + "DS", // DS + "DStar", // DStar + "ChiC1", // ChiC1 + "JPsi", // JPsi + "LambdaB0", // LambdaB0 + "LambdaCPlus", // LambdaCPlus + "OmegaC0", // OmegaC0 + "SigmaC0", // SigmaC0 + "SigmaCPlusPlus", // SigmaCPlusPlus + "X3872", // X3872 + "Xi0", // Xi0 + "XiB0", // XiB0 + "XiCCPlusPlus", // XiCCPlusPlus + "XiCPlus", // XiCPlus + "XiC0", // XiC0 + nullptr}; + + static std::vector arrayNames() + { + std::vector names; + for (int i = 0; i < NIDsTot; i++) { + names.push_back(sNames[i]); + } + return names; + } + + static const char* getName(ID id) { return sNames[id]; } + + /// \brief Convert PDG code to PID index + template + static ID pdgToId(const TrackType& particle) + { + switch (particle.pdgCode()) { + case 11: + return Electron; + case -11: + return Positron; + case 13: + return Muon; + case -13: + return MuonPlus; + case 211: + return Pion; + case -211: + return PionMinus; + case 321: + return Kaon; + case -321: + return KaonMinus; + case 2212: + return Proton; + case -2212: + return AntiProton; + case 2112: + return Neutron; + case -2112: + return AntiNeutron; + case o2::constants::physics::Pdg::kDeuteron: + return Deuteron; + case -o2::constants::physics::Pdg::kDeuteron: + return AntiDeuteron; + case o2::constants::physics::Pdg::kTriton: + return Triton; + case -o2::constants::physics::Pdg::kTriton: + return AntiTriton; + case o2::constants::physics::Pdg::kHelium3: + return Helium3; + case -o2::constants::physics::Pdg::kHelium3: + return AntiHelium3; + case o2::constants::physics::Pdg::kAlpha: + return Alpha; + case -o2::constants::physics::Pdg::kAlpha: + return AntiAlpha; + case o2::constants::physics::Pdg::kHyperHelium4: + return HyperHelium4; + case -o2::constants::physics::Pdg::kHyperHelium4: + return AntiHyperHelium4; + case o2::constants::physics::Pdg::kHyperHelium5: + return HyperHelium5; + case -o2::constants::physics::Pdg::kHyperHelium5: + return AntiHyperHelium5; + case 111: + return PI0; + case 22: + return Photon; + case 130: + return K0; + case 3122: + return Lambda; + case -3122: + return AntiLambda; + case o2::constants::physics::Pdg::kHyperTriton: + return HyperTriton; + case -o2::constants::physics::Pdg::kHyperTriton: + return AntiHyperTriton; + case o2::constants::physics::Pdg::kHyperHydrogen4: + return Hyperhydrog4; + case -o2::constants::physics::Pdg::kHyperHydrogen4: + return AntiHyperhydrog4; + case 3312: + return XiMinus; + case -3312: + return XiPlus; + case 3334: + return OmegaMinus; + case -3334: + return OmegaPlus; + case o2::constants::physics::Pdg::kPhi: + return Phi; + case o2::constants::physics::Pdg::kB0: + return BZero; + case o2::constants::physics::Pdg::kBPlus: + return BPlus; + case o2::constants::physics::Pdg::kBS: + return BS; + case o2::constants::physics::Pdg::kD0: + return D0; + case o2::constants::physics::Pdg::kDPlus: + return DPlus; + case o2::constants::physics::Pdg::kDS: + return DS; + case o2::constants::physics::Pdg::kDStar: + return DStar; + case o2::constants::physics::Pdg::kChiC1: + return ChiC1; + case o2::constants::physics::Pdg::kJPsi: + return JPsi; + case o2::constants::physics::Pdg::kLambdaB0: + return LambdaB0; + case o2::constants::physics::Pdg::kLambdaCPlus: + return LambdaCPlus; + case o2::constants::physics::Pdg::kOmegaC0: + return OmegaC0; + case o2::constants::physics::Pdg::kSigmaC0: + return SigmaC0; + case o2::constants::physics::Pdg::kSigmaCPlusPlus: + return SigmaCPlusPlus; + case o2::constants::physics::Pdg::kX3872: + return X3872; + case o2::constants::physics::Pdg::kXi0: + return Xi0; + case o2::constants::physics::Pdg::kXiB0: + return XiB0; + case o2::constants::physics::Pdg::kXiCCPlusPlus: + return XiCCPlusPlus; + case o2::constants::physics::Pdg::kXiCPlus: + return XiCPlus; + case o2::constants::physics::Pdg::kXiC0: + return XiC0; + default: + LOG(debug) << "Cannot identify particle with PDG code " << particle.pdgCode(); + break; + } + return -1; + } +}; + +} // namespace pwglf +} // namespace o2 + +#endif // PWGLF_UTILS_MCPARTICLE_H_ diff --git a/PWGLF/Utils/rsnOutput.h b/PWGLF/Utils/rsnOutput.h index 73694b4931c..e9ccc1c3ddb 100644 --- a/PWGLF/Utils/rsnOutput.h +++ b/PWGLF/Utils/rsnOutput.h @@ -9,8 +9,9 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. /// +/// \file rsnOutput.h +/// \brief Resonance output class. /// \author Veronika Barbasova (veronika.barbasova@cern.ch) -/// \since April 3, 2024 #ifndef PWGLF_UTILS_RSNOUTPUT_H_ #define PWGLF_UTILS_RSNOUTPUT_H_ @@ -22,8 +23,6 @@ #include "Framework/HistogramRegistry.h" #include "Framework/Logger.h" -using namespace o2::framework; - namespace o2::analysis { namespace rsn @@ -47,6 +46,7 @@ enum class PairType { likemm, unliketrue, unlikegen, + unlikegenold, mixingpm, mixingpp, mixingmm, @@ -58,40 +58,70 @@ enum class PairAxisType { im, pt, mu, + ce, ns1, ns2, + eta, y, vz, mum, + cem, vzm, unknown }; -namespace PariAxis + +enum class MixingType { + ce, + mu, + none +}; + +MixingType mixingTypeName(std::string name) +{ + if (name == "ce") + return MixingType::ce; + else if (name == "mu") + return MixingType::mu; + + return MixingType::none; +} + +enum class SystematicsAxisType { + ncl, + unknown +}; +namespace pair_axis { -std::vector names{"im", "pt", "mu", "ns1", "ns2", "y", "vz", "mum", "vzm"}; +std::vector names{"im", "pt", "mu", "ce", "ns1", "ns2", "eta", "y", "vz", "mum", "cem", "vzm"}; } + +namespace systematic_axis +{ +std::vector names{"ncl"}; +} + class Output { public: virtual ~Output() = default; - virtual void init(std::vector const& sparseAxes, std::vector const& allAxes, bool /*produceTrue*/ = false, bool /*eventMixing*/ = false, bool /*produceLikesign*/ = false, HistogramRegistry* registry = nullptr) + virtual void init(std::vector const& sparseAxes, std::vector const& allAxes, std::vector const& sysAxes, std::vector const& allAxes_sys, bool /*produceTrue*/ = false, MixingType /*eventMixing*/ = MixingType::none, bool /*produceLikesign*/ = false, o2::framework::HistogramRegistry* registry = nullptr) { mHistogramRegistry = registry; if (mHistogramRegistry == nullptr) - mHistogramRegistry = new HistogramRegistry("registry"); + mHistogramRegistry = new o2::framework::HistogramRegistry("registry"); // check if all axes are added in correct order for (int i = 0; i < static_cast(PairAxisType::unknown); i++) { auto aname = *std::move(allAxes[i].name); LOGF(debug, "Check axis '%s' %d", aname.c_str(), i); - if (aname.compare(PariAxis::names[static_cast(i)])) { - LOGF(fatal, "rsn::Output::Error: Order in allAxes is not correct !!! Expected axis '%s' and has '%s'.", aname.c_str(), PariAxis::names[static_cast(i)]); + if (aname.compare(pair_axis::names[static_cast(i)])) { + LOGF(fatal, "rsn::Output::Error: Order in allAxes is not correct !!! Expected axis '%s' and has '%s'.", aname.c_str(), pair_axis::names[static_cast(i)]); } } PairAxisType currentType; - for (auto& c : sparseAxes) { + for (const auto& c : sparseAxes) { currentType = type(c); if (currentType >= PairAxisType::unknown) { LOGF(warning, "Found unknown axis (rsn::PairAxisType = %d)!!! Skipping ...", static_cast(currentType)); @@ -107,19 +137,57 @@ class Output mFillPoint = new double[mCurrentAxisTypes.size()]; LOGF(info, "Number of axis added: %d", mCurrentAxes.size()); - mPairHisto = new HistogramConfigSpec(HistType::kTHnSparseF, mCurrentAxes); - }; + mPairHisto = new o2::framework::HistogramConfigSpec(o2::framework::HistType::kTHnSparseF, mCurrentAxes); + + // check if all systematic axes are added in correct order + for (int i = 0; i < static_cast(SystematicsAxisType::unknown); i++) { + auto aname = *std::move(allAxes_sys[i].name); + LOGF(debug, "Check axis '%s' %d", aname.c_str(), i); + if (aname.compare(systematic_axis::names[static_cast(i)])) { + LOGF(fatal, "rsn::Output::Error: Order in allAxes_sys is not correct !!! Expected axis '%s' and has '%s'.", aname.c_str(), systematic_axis::names[static_cast(i)]); + } + } + + SystematicsAxisType currentTypeSys; + for (const auto& c : sysAxes) { + currentTypeSys = typeSys(c); + if (currentTypeSys >= SystematicsAxisType::unknown) { + LOGF(warning, "Found unknown axis (rsn::SystematicsAxisType = %d)!!! Skipping ...", static_cast(currentTypeSys)); + continue; + } + LOGF(info, "Adding axis '%s' to systematic histogram", c.c_str()); + mCurrentAxesSys.push_back(allAxes_sys[static_cast(currentTypeSys)]); + mCurrentAxisTypesSys.push_back(currentTypeSys); + } + + if (mFillPointSys != nullptr) + delete mFillPointSys; + mFillPointSys = new double[mCurrentAxisTypesSys.size()]; + + LOGF(info, "Number of systematic axis added: %d", mCurrentAxesSys.size()); + mPairHistoSys = new o2::framework::HistogramConfigSpec(o2::framework::HistType::kTHnSparseF, mCurrentAxesSys); + } template void fillSparse(const T& h, double* point) { int i = 0; - for (auto& at : mCurrentAxisTypes) { + for (const auto& at : mCurrentAxisTypes) { mFillPoint[i++] = point[static_cast(at)]; } mHistogramRegistry->get(h)->Fill(mFillPoint); } + template + void fillSparseSys(const T& h, double* point) + { + int i = 0; + for (const auto& at : mCurrentAxisTypesSys) { + mFillPointSys[i++] = point[static_cast(at)]; + } + mHistogramRegistry->get(h)->Fill(mFillPointSys); + } + virtual void fill(EventType /*t*/, double* /*point*/) { LOGF(warning, "Abstract method : 'virtual void rsn::Output::fill(EventType t, double* point)' !!! Please implement it first."); @@ -139,51 +207,70 @@ class Output virtual void fillLikemm(double* point) = 0; virtual void fillUnliketrue(double* point) = 0; virtual void fillUnlikegen(double* point) = 0; + virtual void fillUnlikegenOld(double* point) = 0; virtual void fillMixingpm(double* point) = 0; virtual void fillMixingpp(double* point) = 0; virtual void fillMixingmm(double* point) = 0; virtual void fillMixingmp(double* point) = 0; + virtual void fillSystematics(double* point) = 0; PairAxisType type(std::string name) { - auto it = std::find(PariAxis::names.begin(), PariAxis::names.end(), name); - if (it == PariAxis::names.end()) { + auto it = std::find(pair_axis::names.begin(), pair_axis::names.end(), name); + if (it == pair_axis::names.end()) { return PairAxisType::unknown; } - return static_cast(std::distance(PariAxis::names.begin(), it)); + return static_cast(std::distance(pair_axis::names.begin(), it)); + } + + SystematicsAxisType typeSys(std::string name) + { + auto it = std::find(systematic_axis::names.begin(), systematic_axis::names.end(), name); + if (it == systematic_axis::names.end()) { + return SystematicsAxisType::unknown; + } + return static_cast(std::distance(systematic_axis::names.begin(), it)); } std::string name(PairAxisType type) { - return PariAxis::names[(static_cast(type))]; + return pair_axis::names[(static_cast(type))]; + } + + std::string nameSys(SystematicsAxisType type) + { + return systematic_axis::names[(static_cast(type))]; } - AxisSpec axis(std::vector const& allAxes, PairAxisType type) + o2::framework::AxisSpec axis(std::vector const& allAxes, PairAxisType type) { - const AxisSpec unknownAxis = {1, 0., 1., "unknown axis", "unknown"}; + const o2::framework::AxisSpec unknownAxis = {1, 0., 1., "unknown axis", "unknown"}; if (type == PairAxisType::unknown) return unknownAxis; return allAxes[static_cast(type)]; } protected: - HistogramRegistry* mHistogramRegistry = nullptr; - HistogramConfigSpec* mPairHisto = nullptr; - std::vector mCurrentAxes; + o2::framework::HistogramRegistry* mHistogramRegistry = nullptr; + o2::framework::HistogramConfigSpec* mPairHisto = nullptr; + o2::framework::HistogramConfigSpec* mPairHistoSys = nullptr; + std::vector mCurrentAxes; std::vector mCurrentAxisTypes; + std::vector mCurrentAxesSys; + std::vector mCurrentAxisTypesSys; double* mFillPoint = nullptr; + double* mFillPointSys = nullptr; }; class OutputSparse : public Output { public: - virtual void init(std::vector const& sparseAxes, std::vector const& allAxes, bool produceTrue = false, bool eventMixing = false, bool produceLikesign = false, HistogramRegistry* registry = nullptr) + virtual void init(std::vector const& sparseAxes, std::vector const& allAxes, std::vector const& sysAxes, std::vector const& allAxes_sys, bool produceTrue = false, MixingType eventMixing = MixingType::none, bool produceLikesign = false, o2::framework::HistogramRegistry* registry = nullptr) { - Output::init(sparseAxes, allAxes, produceTrue, eventMixing, produceLikesign, registry); - mHistogramRegistry->add("hVz", "; V_{z} (cm); Entries", kTH1F, {{40, -20., 20.}}); + Output::init(sparseAxes, allAxes, sysAxes, allAxes_sys, produceTrue, eventMixing, produceLikesign, registry); mHistogramRegistry->add("unlikepm", "Unlike pm", *mPairHisto); - mHistogramRegistry->add("unlikemp", "Unlike mp", *mPairHisto); + // mHistogramRegistry->add("unlikemp", "Unlike mp", *mPairHisto); if (produceLikesign) { mHistogramRegistry->add("likepp", "Like PP", *mPairHisto); mHistogramRegistry->add("likemm", "Like MM", *mPairHisto); @@ -191,8 +278,9 @@ class OutputSparse : public Output if (produceTrue) { mHistogramRegistry->add("unliketrue", "Unlike True", *mPairHisto); mHistogramRegistry->add("unlikegen", "Unlike Gen", *mPairHisto); + mHistogramRegistry->add("unlikegenold", "Unlike Gen Old", *mPairHisto); } - if (eventMixing) { + if (eventMixing != MixingType::none) { mHistogramRegistry->add("mixingpm", "Event Mixing pm", *mPairHisto); if (produceLikesign) { mHistogramRegistry->add("mixingpp", "Event Mixing pp", *mPairHisto); @@ -200,6 +288,8 @@ class OutputSparse : public Output } mHistogramRegistry->add("mixingmp", "Event Mixing mp", *mPairHisto); } + + mHistogramRegistry->add("Mapping/systematics", "Systematics mapping", *mPairHistoSys); } virtual void @@ -235,6 +325,9 @@ class OutputSparse : public Output case PairType::unlikegen: fillUnlikegen(point); break; + case PairType::unlikegenold: + fillUnlikegenOld(point); + break; case PairType::mixingpm: fillMixingpm(point); break; @@ -279,6 +372,10 @@ class OutputSparse : public Output { fillSparse(HIST("unlikegen"), point); } + virtual void fillUnlikegenOld(double* point) + { + fillSparse(HIST("unlikegenold"), point); + } virtual void fillMixingpm(double* point) { fillSparse(HIST("mixingpm"), point); @@ -295,6 +392,10 @@ class OutputSparse : public Output { fillSparse(HIST("mixingmp"), point); } + virtual void fillSystematics(double* point) + { + fillSparse(HIST("Mapping/systematics"), point); + } }; } // namespace rsn } // namespace o2::analysis diff --git a/PWGLF/Utils/strangenessBuilderHelper.h b/PWGLF/Utils/strangenessBuilderHelper.h new file mode 100644 index 00000000000..ed92bf4f0b1 --- /dev/null +++ b/PWGLF/Utils/strangenessBuilderHelper.h @@ -0,0 +1,1294 @@ +// 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. + +#ifndef PWGLF_UTILS_STRANGENESSBUILDERHELPER_H_ +#define PWGLF_UTILS_STRANGENESSBUILDERHELPER_H_ + +#include +#include +#include +#include "DCAFitter/DCAFitterN.h" +#include "Framework/AnalysisDataModel.h" +#include "ReconstructionDataFormats/Track.h" +#include "DetectorsBase/GeometryManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/trackUtilities.h" +#include "Tools/KFparticle/KFUtilities.h" + +#ifndef HomogeneousField +#define HomogeneousField +#endif + +/// includes KFParticle +#include "KFParticle.h" +#include "KFPTrack.h" +#include "KFPVertex.h" +#include "KFParticleBase.h" +#include "KFVertex.h" + +namespace o2 +{ +namespace pwglf +{ +//__________________________________________ +// V0 group: abstraction to deal with duplicates +// in an intuitive manner +struct V0group { + std::vector V0Ids; // index list to original aod::V0s + std::vector collisionIds; // coll indices + int posTrackId; + int negTrackId; + uint8_t v0Type; +}; + +//_______________________________________________________________________ +template +std::vector sort_indices_posTrack(const std::vector& v) +{ + std::vector idx(v.size()); + std::iota(idx.begin(), idx.end(), 0); + std::stable_sort(idx.begin(), idx.end(), + [&v](std::size_t i1, std::size_t i2) { return v[i1].posTrackId < v[i2].posTrackId; }); + return idx; +} + +//_______________________________________________________________________ +template +std::vector sort_indices_negTrack(const std::vector& v) +{ + std::vector idx(v.size()); + std::iota(idx.begin(), idx.end(), 0); + std::stable_sort(idx.begin(), idx.end(), + [&v](std::size_t i1, std::size_t i2) { return v[i1].negTrackId < v[i2].negTrackId; }); + return idx; +} + +//_______________________________________________________________________ +// this function deals with the fact that V0s provided in AO2Ds may +// be duplicated in several collisions and groups them into entries +// of type pwglf::V0group, each entry having the same neg/pos tracks +// but an array of compatible collisions. The original V0 indices +// are preserved in the resulting structure to allow for easy referencing +// back afterwards. Algorithmically, full N^2 loops and/or multiple +// find calls are avoided via sorting. +template +std::vector groupDuplicates(const T& V0s) +{ + std::vector v0table; + if (V0s.size() == 0) { + return v0table; + } + V0group thisV0; + thisV0.V0Ids.push_back(-1); // create one single element + thisV0.collisionIds.push_back(-1); // create one single element + for (auto const& V0 : V0s) { + thisV0.V0Ids[0] = V0.globalIndex(); + thisV0.collisionIds[0] = V0.collisionId(); + thisV0.posTrackId = V0.posTrackId(); + thisV0.negTrackId = V0.negTrackId(); + thisV0.v0Type = V0.v0Type(); + v0table.push_back(thisV0); + } + + // sort tracks according to positive track index to avoid excessive N^2 searches + auto posTrackSort = sort_indices_posTrack(v0table); + + // create a proper list of V0s including duplicates: collisionIds is now a vector + int atPosTrackId = v0table[posTrackSort[0]].posTrackId; + std::vector v0tableFixedPositive; // small list with fixed positive id + std::vector v0tableGrouped; // final list with proper grouping + for (size_t iV0 = 0; iV0 < posTrackSort.size(); iV0++) { + if (atPosTrackId != v0table[posTrackSort[iV0]].posTrackId) { + // switched pos track id. Process chunk of V0s + auto negTrackSort = sort_indices_negTrack(v0tableFixedPositive); + thisV0.collisionIds.clear(); + thisV0.V0Ids.clear(); + thisV0.negTrackId = v0tableFixedPositive[negTrackSort[0]].negTrackId; + for (size_t iPV0 = 0; iPV0 < v0tableFixedPositive.size(); iPV0++) { + if (thisV0.negTrackId != v0tableFixedPositive[negTrackSort[iPV0]].negTrackId) { + v0tableGrouped.push_back(thisV0); + thisV0.collisionIds.clear(); // clean collision Ids + thisV0.V0Ids.clear(); // clean aod::V0s Ids + } + thisV0.V0Ids.push_back(v0tableFixedPositive[negTrackSort[iPV0]].V0Ids[0]); + thisV0.collisionIds.push_back(v0tableFixedPositive[negTrackSort[iPV0]].collisionIds[0]); + thisV0.posTrackId = v0tableFixedPositive[negTrackSort[iPV0]].posTrackId; + thisV0.negTrackId = v0tableFixedPositive[negTrackSort[iPV0]].negTrackId; + thisV0.v0Type = v0tableFixedPositive[negTrackSort[iPV0]].v0Type; + } + v0tableGrouped.push_back(thisV0); // publish last + v0tableFixedPositive.clear(); + atPosTrackId = v0table[posTrackSort[iV0]].posTrackId; // move to the next pos index + } + v0tableFixedPositive.push_back(v0table[posTrackSort[iV0]]); + } + v0tableGrouped.push_back(thisV0); // publish last + + LOGF(info, "Duplicate V0s grouped. aod::V0s counted: %i, unique index pairs: %i", V0s.size(), v0tableGrouped.size()); + return v0tableGrouped; +} + +//__________________________________________ +// V0 information storage +struct v0candidate { + // indexing + int collisionId = -1; + int negativeTrack = -1; + int positiveTrack = -1; + + // daughter properties + std::array positiveMomentum = {0.0f, 0.0f, 0.0f}; + std::array negativeMomentum = {0.0f, 0.0f, 0.0f}; + std::array positivePosition = {0.0f, 0.0f, 0.0f}; + std::array negativePosition = {0.0f, 0.0f, 0.0f}; + float positiveTrackX = 0.0f; + float negativeTrackX = 0.0f; + float positiveDCAxy = 0.0f; + float negativeDCAxy = 0.0f; + + // V0 properties + std::array momentum = {0.0f, 0.0f, 0.0f}; // necessary for KF + std::array position = {0.0f, 0.0f, 0.0f}; + float daughterDCA = 1000.0f; + float pointingAngle = 1.0f; + float dcaToPV = 0.0f; + + // calculated masses for convenience + float massGamma; + float massK0Short; + float massLambda; + float massAntiLambda; + + // stored for decay chains + float positionCovariance[6]; + float momentumCovariance[6]; +}; + +//__________________________________________ +// Cascade information storage +struct cascadeCandidate { + // indexing + int collisionId = -1; + int v0Id = -1; + int negativeTrack = -1; + int positiveTrack = -1; + int bachelorTrack = -1; + + // daughter properties + std::array positiveMomentum = {0.0f, 0.0f, 0.0f}; + std::array negativeMomentum = {0.0f, 0.0f, 0.0f}; + std::array bachelorMomentum = {0.0f, 0.0f, 0.0f}; + std::array positivePosition = {0.0f, 0.0f, 0.0f}; + std::array negativePosition = {0.0f, 0.0f, 0.0f}; + std::array bachelorPosition = {0.0f, 0.0f, 0.0f}; + float positiveDCAxy = 0.0f; + float negativeDCAxy = 0.0f; + float bachelorDCAxy = 0.0f; + float positiveTrackX = 0.0f; + float negativeTrackX = 0.0f; + float bachelorTrackX = 0.0f; + + // cascade properties + int charge = -1; // default: []Minus + float cascadeDaughterDCA = 1000.0f; + float v0DaughterDCA = 1000.0f; + + float pointingAngle = 0.0f; + float cascadeDCAxy = 0.0f; + float cascadeDCAz = 0.0f; + std::array v0Position = {0.0f, 0.0f, 0.0f}; + std::array v0Momentum = {0.0f, 0.0f, 0.0f}; + std::array cascadePosition = {0.0f, 0.0f, 0.0f}; + std::array cascadeMomentum = {0.0f, 0.0f, 0.0f}; + + float bachBaryonCosPA = 0.0f; + float bachBaryonDCAxyToPV = 1e+3; + float massXi = 0.0f; + float massOmega = 0.0f; + + // KF-specific variables + float kfV0Chi2 = 0.0f; + float kfCascadeChi2 = 0.0f; + float kfMLambda = 0.0f; + float kfTrackCovarianceV0[21]; + float kfTrackCovariancePos[21]; + float kfTrackCovarianceNeg[21]; + + // stored for decay chains + float covariance[21]; +}; + +//__________________________________________ +// builder helper class +class strangenessBuilderHelper +{ + public: + strangenessBuilderHelper() + { + // standards hardcoded in builder ... + // ...but can be changed easily since fitter is public + fitter.setPropagateToPCA(true); + fitter.setMaxR(200.); + fitter.setMinParamChange(1e-3); + fitter.setMinRelChi2Change(0.9); + fitter.setMaxDZIni(1e9); + fitter.setMaxDXYIni(4.0f); + fitter.setMaxChi2(1e9); + fitter.setUseAbsDCA(true); + fitter.setWeightedFinalPCA(false); + + v0selections.minCrossedRows = -1; + v0selections.dcanegtopv = -1.0f; + v0selections.dcapostopv = -1.0f; + v0selections.v0cospa = -2; + v0selections.dcav0dau = 1e+6; + v0selections.v0radius = 0.0f; + v0selections.maxDaughterEta = 2.0; + + // LUT has to be loaded later + lut = nullptr; + fitter.setMatCorrType(o2::base::Propagator::MatCorrType::USEMatCorrLUT); + + // mag field has to be set later + fitter.setBz(-999.9f); // will NOT make sense if not changed + }; + + //_______________________________________________________________________ + // standard build V0 function. Populates ::v0 object + // ::v0 will be initialized to defaults if build fails + template + bool buildV0Candidate(int collisionIndex, + float pvX, float pvY, float pvZ, + TTrack const& positiveTrack, + TTrack const& negativeTrack, + TTrackParametrization& positiveTrackParam, + TTrackParametrization& negativeTrackParam, + bool useCollinearFit = false, + bool calculateCovariance = false, + bool acceptTPCOnly = false) + { + if constexpr (useSelections) { + // verify track quality + if (positiveTrack.tpcNClsCrossedRows() < v0selections.minCrossedRows) { + v0 = {}; + return false; + } + if (negativeTrack.tpcNClsCrossedRows() < v0selections.minCrossedRows) { + v0 = {}; + return false; + } + // verify eta + if (std::fabs(positiveTrack.eta()) > v0selections.maxDaughterEta) { + v0 = {}; + return false; + } + if (std::fabs(negativeTrack.eta()) > v0selections.maxDaughterEta) { + v0 = {}; + return false; + } + if (!acceptTPCOnly && !positiveTrack.hasITS()) { + v0 = {}; + return false; + } + if (!acceptTPCOnly && !negativeTrack.hasITS()) { + v0 = {}; + return false; + } + } + + // Calculate DCA with respect to the collision associated to the V0 + gpu::gpustd::array dcaInfo; + + // do DCA to PV on copies instead of originals + auto positiveTrackParamCopy = positiveTrackParam; + auto negativeTrackParamCopy = negativeTrackParam; + + o2::base::Propagator::Instance()->propagateToDCABxByBz({pvX, pvY, pvZ}, positiveTrackParamCopy, 2.f, fitter.getMatCorrType(), &dcaInfo); + v0.positiveDCAxy = dcaInfo[0]; + + if constexpr (useSelections) { + if (std::fabs(v0.positiveDCAxy) < v0selections.dcanegtopv) { + v0 = {}; + return false; + } + } + + o2::base::Propagator::Instance()->propagateToDCABxByBz({pvX, pvY, pvZ}, negativeTrackParamCopy, 2.f, fitter.getMatCorrType(), &dcaInfo); + v0.negativeDCAxy = dcaInfo[0]; + + if constexpr (useSelections) { + if (std::fabs(v0.negativeDCAxy) < v0selections.dcanegtopv) { + v0 = {}; + return false; + } + } + + // Perform DCA fit + int nCand = 0; + fitter.setCollinear(useCollinearFit); + try { + nCand = fitter.process(positiveTrackParam, negativeTrackParam); + } catch (...) { + v0 = {}; + return false; + } + if (nCand == 0) { + v0 = {}; + return false; + } + fitter.setCollinear(false); // proper cleaning: when exiting this loop, always reset to not collinear + + v0.positiveTrackX = fitter.getTrack(0).getX(); + v0.negativeTrackX = fitter.getTrack(1).getX(); + positiveTrackParam = fitter.getTrack(0); + negativeTrackParam = fitter.getTrack(1); + positiveTrackParam.getPxPyPzGlo(v0.positiveMomentum); + negativeTrackParam.getPxPyPzGlo(v0.negativeMomentum); + positiveTrackParam.getXYZGlo(v0.positivePosition); + negativeTrackParam.getXYZGlo(v0.negativePosition); + for (int i = 0; i < 3; i++) { + // avoids misuse if mixed with KF particle use + v0.momentum[i] = v0.positiveMomentum[i] + v0.negativeMomentum[i]; + } + + // get decay vertex coordinates + const auto& vtx = fitter.getPCACandidate(); + for (int i = 0; i < 3; i++) { + v0.position[i] = vtx[i]; + } + + if constexpr (useSelections) { + if (std::hypot(v0.position[0], v0.position[1]) < v0selections.v0radius) { + v0 = {}; + return false; + } + } + + v0.daughterDCA = TMath::Sqrt(fitter.getChi2AtPCACandidate()); + + if constexpr (useSelections) { + if (v0.daughterDCA > v0selections.dcav0dau) { + v0 = {}; + return false; + } + } + + double cosPA = RecoDecay::cpa( + std::array{pvX, pvY, pvZ}, + std::array{v0.position[0], v0.position[1], v0.position[2]}, + std::array{v0.positiveMomentum[0] + v0.negativeMomentum[0], v0.positiveMomentum[1] + v0.negativeMomentum[1], v0.positiveMomentum[2] + v0.negativeMomentum[2]}); + if constexpr (useSelections) { + if (cosPA < v0selections.v0cospa) { + v0 = {}; + return false; + } + } + + v0.pointingAngle = TMath::ACos(cosPA); + v0.dcaToPV = CalculateDCAStraightToPV( + v0.position[0], v0.position[1], v0.position[2], + v0.positiveMomentum[0] + v0.negativeMomentum[0], + v0.positiveMomentum[1] + v0.negativeMomentum[1], + v0.positiveMomentum[2] + v0.negativeMomentum[2], + pvX, pvY, pvZ); + + // Calculate masses + v0.massGamma = RecoDecay::m(std::array{ + std::array{v0.positiveMomentum[0], v0.positiveMomentum[1], v0.positiveMomentum[2]}, + std::array{v0.negativeMomentum[0], v0.negativeMomentum[1], v0.negativeMomentum[2]}}, + std::array{o2::constants::physics::MassElectron, o2::constants::physics::MassElectron}); + v0.massK0Short = RecoDecay::m(std::array{ + std::array{v0.positiveMomentum[0], v0.positiveMomentum[1], v0.positiveMomentum[2]}, + std::array{v0.negativeMomentum[0], v0.negativeMomentum[1], v0.negativeMomentum[2]}}, + std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged}); + v0.massLambda = RecoDecay::m(std::array{ + std::array{v0.positiveMomentum[0], v0.positiveMomentum[1], v0.positiveMomentum[2]}, + std::array{v0.negativeMomentum[0], v0.negativeMomentum[1], v0.negativeMomentum[2]}}, + std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); + v0.massAntiLambda = RecoDecay::m(std::array{ + std::array{v0.positiveMomentum[0], v0.positiveMomentum[1], v0.positiveMomentum[2]}, + std::array{v0.negativeMomentum[0], v0.negativeMomentum[1], v0.negativeMomentum[2]}}, + std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton}); + + // calculate covariance if requested + if (calculateCovariance) { + // Calculate position covariance matrix + auto covVtxV = fitter.calcPCACovMatrix(0); + // std::array positionCovariance; + v0.positionCovariance[0] = covVtxV(0, 0); + v0.positionCovariance[1] = covVtxV(1, 0); + v0.positionCovariance[2] = covVtxV(1, 1); + v0.positionCovariance[3] = covVtxV(2, 0); + v0.positionCovariance[4] = covVtxV(2, 1); + v0.positionCovariance[5] = covVtxV(2, 2); + std::array covTpositive = {0.}; + std::array covTnegative = {0.}; + positiveTrackParam.getCovXYZPxPyPzGlo(covTpositive); + negativeTrackParam.getCovXYZPxPyPzGlo(covTnegative); + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 6; i++) { + v0.momentumCovariance[i] = covTpositive[MomInd[i]] + covTnegative[MomInd[i]]; + } + } + + // set collision Id correctly + v0.collisionId = collisionIndex; + + // information validated, V0 built successfully. Signal OK + return true; + } + + //_______________________________________________________________________ + // build V0 with KF function. Populates ::v0 object + // ::v0 will be initialized to defaults if build fails + template + bool buildV0CandidateWithKF(TCollision const& collision, + TTrack const& positiveTrack, + TTrack const& negativeTrack, + TTrackParametrization& positiveTrackParam, + TTrackParametrization& negativeTrackParam, + int kfConstructMethod = 2, // the typical used + float kfConstrainedMassValue = 0.0f, // negative: no constraint + bool kfConstrainToPrimaryVertex = true) + { + int collisionIndex = collision.globalIndex(); + float pvX = collision.posX(); + float pvY = collision.posY(); + float pvZ = collision.posZ(); + + // verify track quality + if (positiveTrack.tpcNClsCrossedRows() < v0selections.minCrossedRows) { + v0 = {}; + return false; + } + if (negativeTrack.tpcNClsCrossedRows() < v0selections.minCrossedRows) { + v0 = {}; + return false; + } + + // verify eta + if (std::fabs(positiveTrack.eta()) > v0selections.maxDaughterEta) { + v0 = {}; + return false; + } + if (std::fabs(negativeTrack.eta()) > v0selections.maxDaughterEta) { + v0 = {}; + return false; + } + + // Calculate DCA with respect to the collision associated to the V0 + gpu::gpustd::array dcaInfo; + + // do DCA to PV on copies instead of originals + auto positiveTrackParamCopy = positiveTrackParam; + auto negativeTrackParamCopy = negativeTrackParam; + + o2::base::Propagator::Instance()->propagateToDCABxByBz({pvX, pvY, pvZ}, positiveTrackParamCopy, 2.f, fitter.getMatCorrType(), &dcaInfo); + v0.positiveDCAxy = dcaInfo[0]; + + if (std::fabs(v0.positiveDCAxy) < v0selections.dcanegtopv) { + v0 = {}; + return false; + } + + o2::base::Propagator::Instance()->propagateToDCABxByBz({pvX, pvY, pvZ}, negativeTrackParamCopy, 2.f, fitter.getMatCorrType(), &dcaInfo); + v0.negativeDCAxy = dcaInfo[0]; + + if (std::fabs(v0.negativeDCAxy) < v0selections.dcanegtopv) { + v0 = {}; + return false; + } + + //__________________________________________ + //*>~<* do V0 with KF + // create KFParticle objects from trackParCovs + KFParticle kfpPos = createKFParticleFromTrackParCov(positiveTrackParam, positiveTrackParam.getCharge(), o2::constants::physics::MassElectron); + KFParticle kfpNeg = createKFParticleFromTrackParCov(negativeTrackParam, negativeTrackParam.getCharge(), o2::constants::physics::MassElectron); + + KFParticle kfpPos_DecayVtx = kfpPos; + KFParticle kfpNeg_DecayVtx = kfpNeg; + const KFParticle* V0Daughters[2] = {&kfpPos, &kfpNeg}; + + // construct V0 + KFParticle KFV0; + KFV0.SetConstructMethod(kfConstructMethod); + try { + KFV0.Construct(V0Daughters, 2); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to construct cascade V0 from daughter tracks: " << e.what(); + v0 = {}; + return false; + } + + if (kfConstrainedMassValue > -1e-4) { + // photon constraint: this one's got no mass + KFV0.SetNonlinearMassConstraint(kfConstrainedMassValue); + } + + // V0 constructed, now recovering TrackParCov for dca fitter minimization (with material correction) + KFV0.TransportToDecayVertex(); + o2::track::TrackParCov v0TrackParCov = getTrackParCovFromKFP(KFV0, o2::track::PID::Lambda, 0); + v0TrackParCov.setAbsCharge(0); // to be sure + + // estimate momentum of daughters (since KFParticle does not allow us to retrieve it directly...) + float xyz_decay[3] = {KFV0.GetX(), KFV0.GetY(), KFV0.GetZ()}; + kfpPos_DecayVtx.TransportToPoint(xyz_decay); + kfpNeg_DecayVtx.TransportToPoint(xyz_decay); + + v0.positiveMomentum = {kfpPos_DecayVtx.GetPx(), kfpPos_DecayVtx.GetPy(), kfpPos_DecayVtx.GetPz()}; + v0.negativeMomentum = {kfpNeg_DecayVtx.GetPx(), kfpNeg_DecayVtx.GetPy(), kfpNeg_DecayVtx.GetPz()}; + + v0.daughterDCA = std::hypot( + kfpPos_DecayVtx.GetX() - kfpNeg_DecayVtx.GetX(), + kfpPos_DecayVtx.GetY() - kfpNeg_DecayVtx.GetY(), + kfpPos_DecayVtx.GetZ() - kfpNeg_DecayVtx.GetZ()); + + if (v0.daughterDCA > v0selections.dcav0dau) { + v0 = {}; + return false; + } + + // check radius + for (int i = 0; i < 3; i++) { + v0.position[i] = xyz_decay[i]; + } + if (std::hypot(v0.position[0], v0.position[1]) < v0selections.v0radius) { + v0 = {}; + return false; + } + + KFPVertex kfpVertex = createKFPVertexFromCollision(collision); + KFParticle KFPV(kfpVertex); + + // deal with pointing angle + float cosPA = cpaFromKF(KFV0, KFPV); + if (cosPA < v0selections.v0cospa) { + v0 = {}; + return false; + } + v0.pointingAngle = TMath::ACos(cosPA); + + v0.dcaToPV = CalculateDCAStraightToPV( + v0.position[0], v0.position[1], v0.position[2], + v0.momentum[0], v0.momentum[1], v0.momentum[2], + pvX, pvY, pvZ); + + // apply topological constraint to PV if requested + // might adjust px py pz + KFParticle KFV0_PV = KFV0; + if (kfConstrainToPrimaryVertex) { + KFV0_PV.SetProductionVertex(KFPV); + } + v0.momentum = {KFV0_PV.GetPx(), KFV0_PV.GetPy(), KFV0_PV.GetPz()}; + + // set collision Id correctly + v0.collisionId = collisionIndex; + + // Calculate masses + v0.massGamma = RecoDecay::m(std::array{ + std::array{v0.positiveMomentum[0], v0.positiveMomentum[1], v0.positiveMomentum[2]}, + std::array{v0.negativeMomentum[0], v0.negativeMomentum[1], v0.negativeMomentum[2]}}, + std::array{o2::constants::physics::MassElectron, o2::constants::physics::MassElectron}); + v0.massK0Short = RecoDecay::m(std::array{ + std::array{v0.positiveMomentum[0], v0.positiveMomentum[1], v0.positiveMomentum[2]}, + std::array{v0.negativeMomentum[0], v0.negativeMomentum[1], v0.negativeMomentum[2]}}, + std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged}); + v0.massLambda = RecoDecay::m(std::array{ + std::array{v0.positiveMomentum[0], v0.positiveMomentum[1], v0.positiveMomentum[2]}, + std::array{v0.negativeMomentum[0], v0.negativeMomentum[1], v0.negativeMomentum[2]}}, + std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); + v0.massAntiLambda = RecoDecay::m(std::array{ + std::array{v0.positiveMomentum[0], v0.positiveMomentum[1], v0.positiveMomentum[2]}, + std::array{v0.negativeMomentum[0], v0.negativeMomentum[1], v0.negativeMomentum[2]}}, + std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton}); + + // information validated, V0 built successfully. Signal OK + return true; + } + + //_______________________________________________________________________ + // build Cascade from three tracks, including V0 building. + // Populates ::cascade object. + // ::cascade will be initialized to defaults if build fails + // cascade builder creating a cascade from plain tracks + template + bool buildCascadeCandidate(int collisionIndex, + float pvX, float pvY, float pvZ, + TTrack const& positiveTrack, + TTrack const& negativeTrack, + TTrack const& bachelorTrack, + bool calculateBachelorBaryonVariables = false, + bool useCascadeMomentumAtPV = false, + bool processCovariances = false) + { + // no special treatment of positive and negative tracks when building V0s for cascades + auto posTrackPar = getTrackParCov(positiveTrack); + auto negTrackPar = getTrackParCov(negativeTrack); + + if (!buildV0Candidate(collisionIndex, pvX, pvY, pvZ, positiveTrack, negativeTrack, posTrackPar, negTrackPar, false, processCovariances, false)) { + return false; + } + if (!buildCascadeCandidate(collisionIndex, pvX, pvY, pvZ, v0, positiveTrack, negativeTrack, bachelorTrack, calculateBachelorBaryonVariables, useCascadeMomentumAtPV, processCovariances)) { + return false; + } + return true; + } + + //_______________________________________________________________________ + // cascade builder using pre-fabricated information, thus not calling + // the DCAfitter again for the V0 contained in the cascade + // If building from scratch, prefer previous version! + // Populates ::cascade object. + // ::cascade will be initialized to defaults if build fails + // cascade builder creating a cascade from plain tracks + template + bool buildCascadeCandidate(int collisionIndex, + float pvX, float pvY, float pvZ, + v0candidate const& v0input, + TTrack const& positiveTrack, + TTrack const& negativeTrack, + TTrack const& bachelorTrack, + bool calculateBachelorBaryonVariables = false, + bool useCascadeMomentumAtPV = false, + bool processCovariances = false) + { + // verify track quality + if (positiveTrack.tpcNClsCrossedRows() < cascadeselections.minCrossedRows) { + cascade = {}; + return false; + } + if (negativeTrack.tpcNClsCrossedRows() < cascadeselections.minCrossedRows) { + cascade = {}; + return false; + } + if (bachelorTrack.tpcNClsCrossedRows() < cascadeselections.minCrossedRows) { + cascade = {}; + return false; + } + + // verify eta + if (std::fabs(positiveTrack.eta()) > cascadeselections.maxDaughterEta) { + cascade = {}; + return false; + } + if (std::fabs(negativeTrack.eta()) > cascadeselections.maxDaughterEta) { + cascade = {}; + return false; + } + if (std::fabs(bachelorTrack.eta()) > cascadeselections.maxDaughterEta) { + cascade = {}; + return false; + } + + // verify lambda mass + if (bachelorTrack.sign() < 0 && std::fabs(v0input.massLambda - 1.116) > cascadeselections.lambdaMassWindow) { + cascade = {}; + return false; + } + if (bachelorTrack.sign() > 0 && std::fabs(v0input.massAntiLambda - 1.116) > cascadeselections.lambdaMassWindow) { + cascade = {}; + return false; + } + + if (calculateBachelorBaryonVariables) { + // Calculates properties of the V0 comprised of bachelor and baryon in the cascade + // baryon: distinguished via bachelor charge + if (bachelorTrack.sign() < 0) { + processBachBaryonVariables(pvX, pvY, pvZ, bachelorTrack, positiveTrack); + } else { + processBachBaryonVariables(pvX, pvY, pvZ, bachelorTrack, negativeTrack); + } + } + + // Overall cascade charge + cascade.charge = bachelorTrack.signed1Pt() > 0 ? +1 : -1; + + // bachelor DCA track to PV + // Calculate DCA with respect to the collision associated to the V0, not individual tracks + gpu::gpustd::array dcaInfo; + + auto bachTrackPar = getTrackPar(bachelorTrack); + o2::base::Propagator::Instance()->propagateToDCABxByBz({pvX, pvY, pvZ}, bachTrackPar, 2.f, fitter.getMatCorrType(), &dcaInfo); + cascade.bachelorDCAxy = dcaInfo[0]; + + if (std::fabs(cascade.bachelorDCAxy) < cascadeselections.dcabachtopv) { + cascade = {}; + return false; + } + + // Do actual minimization + auto lBachelorTrack = getTrackParCov(bachelorTrack); + + // Set up covariance matrices (should in fact be optional) + std::array covV = {0.}; + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 6; i++) { + covV[MomInd[i]] = v0input.momentumCovariance[i]; + covV[i] = v0input.positionCovariance[i]; + } + auto lV0Track = o2::track::TrackParCov( + {v0input.position[0], v0input.position[1], v0input.position[2]}, + {v0input.positiveMomentum[0] + v0input.negativeMomentum[0], v0input.positiveMomentum[1] + v0input.negativeMomentum[1], v0input.positiveMomentum[2] + v0input.negativeMomentum[2]}, + covV, 0, true); + lV0Track.setAbsCharge(0); + lV0Track.setPID(o2::track::PID::Lambda); + + //---/---/---/ + // Move close to minima + int nCand = 0; + try { + nCand = fitter.process(lV0Track, lBachelorTrack); + } catch (...) { + cascade = {}; + return false; + } + if (nCand == 0) { + cascade = {}; + return false; + } + + lV0Track = fitter.getTrack(0); + lBachelorTrack = fitter.getTrack(1); + + // DCA between cascade daughters + cascade.cascadeDaughterDCA = TMath::Sqrt(fitter.getChi2AtPCACandidate()); + if (cascade.cascadeDaughterDCA > cascadeselections.dcacascdau) { + cascade = {}; + return false; + } + + lBachelorTrack.getPxPyPzGlo(cascade.bachelorMomentum); + // get decay vertex coordinates + const auto& vtx = fitter.getPCACandidate(); + for (int i = 0; i < 3; i++) { + cascade.cascadePosition[i] = vtx[i]; + } + if (std::hypot(cascade.cascadePosition[0], cascade.cascadePosition[1]) < cascadeselections.cascradius) { + cascade = {}; + return false; + } + + double cosPA = RecoDecay::cpa( + std::array{pvX, pvY, pvZ}, + std::array{cascade.cascadePosition[0], cascade.cascadePosition[1], cascade.cascadePosition[2]}, + std::array{v0input.positiveMomentum[0] + v0input.negativeMomentum[0] + cascade.bachelorMomentum[0], + v0input.positiveMomentum[1] + v0input.negativeMomentum[1] + cascade.bachelorMomentum[1], + v0input.positiveMomentum[2] + v0input.negativeMomentum[2] + cascade.bachelorMomentum[2]}); + if (cosPA < cascadeselections.casccospa) { + cascade = {}; + return false; + } + cascade.pointingAngle = TMath::ACos(cosPA); + + // Calculate DCAxy of the cascade (with bending) + auto lCascadeTrack = fitter.createParentTrackParCov(); + lCascadeTrack.setAbsCharge(cascade.charge); // to be sure + lCascadeTrack.setPID(o2::track::PID::XiMinus); // FIXME: not OK for omegas + dcaInfo[0] = 999; + dcaInfo[1] = 999; + + o2::base::Propagator::Instance()->propagateToDCABxByBz({pvX, pvY, pvZ}, lCascadeTrack, 2.f, fitter.getMatCorrType(), &dcaInfo); + cascade.cascadeDCAxy = dcaInfo[0]; + cascade.cascadeDCAz = dcaInfo[1]; + + // Calculate masses a priori + cascade.massXi = RecoDecay::m(std::array{std::array{cascade.bachelorMomentum[0], cascade.bachelorMomentum[1], cascade.bachelorMomentum[2]}, + std::array{v0input.positiveMomentum[0] + v0input.negativeMomentum[0], v0input.positiveMomentum[1] + v0input.negativeMomentum[1], v0input.positiveMomentum[2] + v0input.negativeMomentum[2]}}, + std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassLambda}); + cascade.massOmega = RecoDecay::m(std::array{std::array{cascade.bachelorMomentum[0], cascade.bachelorMomentum[1], cascade.bachelorMomentum[2]}, + std::array{v0input.positiveMomentum[0] + v0input.negativeMomentum[0], v0input.positiveMomentum[1] + v0input.negativeMomentum[1], v0input.positiveMomentum[2] + v0input.negativeMomentum[2]}}, + std::array{o2::constants::physics::MassKaonCharged, o2::constants::physics::MassLambda}); + + // Populate information + // cascadecandidate.v0Id = v0index.globalIndex(); + cascade.collisionId = collisionIndex; + cascade.positiveTrack = positiveTrack.globalIndex(); + cascade.negativeTrack = negativeTrack.globalIndex(); + cascade.bachelorTrack = bachelorTrack.globalIndex(); + cascade.positiveTrackX = v0input.positiveTrackX; + cascade.negativeTrackX = v0input.negativeTrackX; + cascade.bachelorTrackX = lBachelorTrack.getX(); // from this minimization + cascade.v0Position[0] = v0input.position[0]; + cascade.v0Position[1] = v0input.position[1]; + cascade.v0Position[2] = v0input.position[2]; + cascade.v0Momentum[0] = v0input.positiveMomentum[0] + v0input.negativeMomentum[0]; + cascade.v0Momentum[1] = v0input.positiveMomentum[1] + v0input.negativeMomentum[1]; + cascade.v0Momentum[2] = v0input.positiveMomentum[2] + v0input.negativeMomentum[2]; + cascade.positiveMomentum[0] = v0input.positiveMomentum[0]; + cascade.positiveMomentum[1] = v0input.positiveMomentum[1]; + cascade.positiveMomentum[2] = v0input.positiveMomentum[2]; + cascade.negativeMomentum[0] = v0input.negativeMomentum[0]; + cascade.negativeMomentum[1] = v0input.negativeMomentum[1]; + cascade.negativeMomentum[2] = v0input.negativeMomentum[2]; + cascade.v0DaughterDCA = v0input.daughterDCA; + cascade.positiveDCAxy = v0input.positiveDCAxy; + cascade.negativeDCAxy = v0input.negativeDCAxy; + + if (useCascadeMomentumAtPV) { + lCascadeTrack.getPxPyPzGlo(cascade.cascadeMomentum); + } else { + cascade.cascadeMomentum[0] = cascade.bachelorMomentum[0] + v0input.positiveMomentum[0] + v0input.negativeMomentum[0]; + cascade.cascadeMomentum[1] = cascade.bachelorMomentum[1] + v0input.positiveMomentum[1] + v0input.negativeMomentum[1]; + cascade.cascadeMomentum[2] = cascade.bachelorMomentum[2] + v0input.positiveMomentum[2] + v0input.negativeMomentum[2]; + } + + if (processCovariances) { + // Calculate position covariance matrix + auto covVtxV = fitter.calcPCACovMatrix(0); + // std::array positionCovariance; + float positionCovariance[6]; + positionCovariance[0] = covVtxV(0, 0); + positionCovariance[1] = covVtxV(1, 0); + positionCovariance[2] = covVtxV(1, 1); + positionCovariance[3] = covVtxV(2, 0); + positionCovariance[4] = covVtxV(2, 1); + positionCovariance[5] = covVtxV(2, 2); + // store momentum covariance matrix + std::array covTv0 = {0.}; + std::array covTbachelor = {0.}; + // std::array momentumCovariance; + lV0Track.getCovXYZPxPyPzGlo(covTv0); + lBachelorTrack.getCovXYZPxPyPzGlo(covTbachelor); + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 21; i++) { + cascade.covariance[i] = 0.0f; + } + for (int i = 0; i < 6; i++) { + cascade.covariance[i] = positionCovariance[i]; + cascade.covariance[MomInd[i]] = covTv0[MomInd[i]] + covTbachelor[MomInd[i]]; + } + } + + // Final outcome is YES if I got here! + return true; + } + + //_______________________________________________________________________ + // build KF Cascade from three tracks, including V0 building. + // Populates ::cascade object. + // ::cascade will be initialized to defaults if build fails + // cascade builder creating a cascade from plain tracks + template + bool buildCascadeCandidateWithKF(int collisionIndex, + float pvX, float pvY, float pvZ, + TTrack const& positiveTrack, + TTrack const& negativeTrack, + TTrack const& bachelorTrack, + bool calculateBachelorBaryonVariables = false, + int kfConstructMethod = 2, + bool kfTuneForOmega = false, + bool kfUseV0MassConstraint = true, + bool kfUseCascadeMassConstraint = false, + bool kfDoDCAFitterPreMinimV0 = false, + bool kfDoDCAFitterPreMinimCasc = false) + { + //*>~<*>~<*>~<*>~<*>~<*>~<*>~<*>~<*>~<* + // KF particle based rebuilding + // dispenses prior V0 generation, uses constrained (re-)fit based on bachelor charge + //*>~<*>~<*>~<*>~<*>~<*>~<*>~<*>~<*>~<* + + if (positiveTrack.tpcNClsCrossedRows() < cascadeselections.minCrossedRows) { + cascade = {}; + return false; + } + if (negativeTrack.tpcNClsCrossedRows() < cascadeselections.minCrossedRows) { + cascade = {}; + return false; + } + if (bachelorTrack.tpcNClsCrossedRows() < cascadeselections.minCrossedRows) { + cascade = {}; + return false; + } + + // verify eta + if (std::fabs(positiveTrack.eta()) > cascadeselections.maxDaughterEta) { + cascade = {}; + return false; + } + if (std::fabs(negativeTrack.eta()) > cascadeselections.maxDaughterEta) { + cascade = {}; + return false; + } + if (std::fabs(bachelorTrack.eta()) > cascadeselections.maxDaughterEta) { + cascade = {}; + return false; + } + + if (calculateBachelorBaryonVariables) { + // Calculates properties of the V0 comprised of bachelor and baryon in the cascade + // baryon: distinguished via bachelor charge + if (bachelorTrack.sign() < 0) { + processBachBaryonVariables(pvX, pvY, pvZ, bachelorTrack, positiveTrack); + } else { + processBachBaryonVariables(pvX, pvY, pvZ, bachelorTrack, negativeTrack); + } + } + + // Overall cascade charge + cascade.charge = bachelorTrack.signed1Pt() > 0 ? +1 : -1; + + // bachelor DCA track to PV + // Calculate DCA with respect to the collision associated to the V0, not individual tracks + gpu::gpustd::array dcaInfo; + + auto bachTrackPar = getTrackPar(bachelorTrack); + o2::base::Propagator::Instance()->propagateToDCABxByBz({pvX, pvY, pvZ}, bachTrackPar, 2.f, fitter.getMatCorrType(), &dcaInfo); + cascade.bachelorDCAxy = dcaInfo[0]; + o2::track::TrackParCov posTrackParCovForDCA = getTrackParCov(positiveTrack); + o2::base::Propagator::Instance()->propagateToDCABxByBz({pvX, pvY, pvZ}, posTrackParCovForDCA, 2.f, fitter.getMatCorrType(), &dcaInfo); + cascade.positiveDCAxy = dcaInfo[0]; + o2::track::TrackParCov negTrackParCovForDCA = getTrackParCov(negativeTrack); + o2::base::Propagator::Instance()->propagateToDCABxByBz({pvX, pvY, pvZ}, negTrackParCovForDCA, 2.f, fitter.getMatCorrType(), &dcaInfo); + cascade.negativeDCAxy = dcaInfo[0]; + + if (std::fabs(cascade.bachelorDCAxy) < cascadeselections.dcabachtopv) { + cascade = {}; + return false; + } + + o2::track::TrackParCov lBachelorTrack = getTrackParCov(bachelorTrack); + o2::track::TrackParCov posTrackParCov = getTrackParCov(positiveTrack); + o2::track::TrackParCov negTrackParCov = getTrackParCov(negativeTrack); + + float massPosTrack, massNegTrack; + if (cascade.charge < 0) { + massPosTrack = o2::constants::physics::MassProton; + massNegTrack = o2::constants::physics::MassPionCharged; + } else { + massPosTrack = o2::constants::physics::MassPionCharged; + massNegTrack = o2::constants::physics::MassProton; + } + + //__________________________________________ + //*>~<* step 1 : V0 with dca fitter, uses material corrections implicitly + // This is optional - move close to minima and therefore take material + if (kfDoDCAFitterPreMinimV0) { + int nCand = 0; + try { + nCand = fitter.process(posTrackParCov, negTrackParCov); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call!"; + cascade = {}; + return false; + } + if (nCand == 0) { + cascade = {}; + return false; + } + // save classical DCA daughters + cascade.v0DaughterDCA = TMath::Sqrt(fitter.getChi2AtPCACandidate()); + + // re-acquire from DCA fitter + posTrackParCov = fitter.getTrack(0); + negTrackParCov = fitter.getTrack(1); + } + + //__________________________________________ + //*>~<* step 2 : V0 with KF + // create KFParticle objects from trackParCovs + KFParticle kfpPos = createKFParticleFromTrackParCov(posTrackParCov, posTrackParCov.getCharge(), massPosTrack); + KFParticle kfpNeg = createKFParticleFromTrackParCov(negTrackParCov, negTrackParCov.getCharge(), massNegTrack); + const KFParticle* V0Daughters[2] = {&kfpPos, &kfpNeg}; + + // construct V0 + KFParticle KFV0; + KFV0.SetConstructMethod(kfConstructMethod); + try { + KFV0.Construct(V0Daughters, 2); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to construct cascade V0 from daughter tracks: " << e.what(); + cascade = {}; + return false; + } + + if (kfUseV0MassConstraint) { + KFV0.SetNonlinearMassConstraint(o2::constants::physics::MassLambda); + } + + // V0 constructed, now recovering TrackParCov for dca fitter minimization (with material correction) + KFV0.TransportToDecayVertex(); + o2::track::TrackParCov v0TrackParCov = getTrackParCovFromKFP(KFV0, o2::track::PID::Lambda, 0); + v0TrackParCov.setAbsCharge(0); // to be sure + + //__________________________________________ + //*>~<* step 3 : Cascade with dca fitter (with material corrections) + if (kfDoDCAFitterPreMinimCasc) { + int nCandCascade = 0; + try { + nCandCascade = fitter.process(v0TrackParCov, lBachelorTrack); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call!"; + cascade = {}; + return false; + } + if (nCandCascade == 0) { + cascade = {}; + return false; + } + + v0TrackParCov = fitter.getTrack(0); + lBachelorTrack = fitter.getTrack(1); + } + + //__________________________________________ + //*>~<* step 4 : Cascade with KF particle (potentially mass-constrained if asked) + float massBachelorPion = o2::constants::physics::MassPionCharged; + float massBachelorKaon = o2::constants::physics::MassKaonCharged; + + KFParticle kfpV0 = createKFParticleFromTrackParCov(v0TrackParCov, 0, o2::constants::physics::MassLambda); + KFParticle kfpBachPion = createKFParticleFromTrackParCov(lBachelorTrack, cascade.charge, massBachelorPion); + KFParticle kfpBachKaon = createKFParticleFromTrackParCov(lBachelorTrack, cascade.charge, massBachelorKaon); + const KFParticle* XiDaugthers[2] = {&kfpBachPion, &kfpV0}; + const KFParticle* OmegaDaugthers[2] = {&kfpBachKaon, &kfpV0}; + + // construct mother + KFParticle KFXi, KFOmega; + KFXi.SetConstructMethod(kfConstructMethod); + KFOmega.SetConstructMethod(kfConstructMethod); + try { + KFXi.Construct(XiDaugthers, 2); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to construct xi from V0 and bachelor track: " << e.what(); + cascade = {}; + return false; + } + try { + KFOmega.Construct(OmegaDaugthers, 2); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to construct omega from V0 and bachelor track: " << e.what(); + cascade = {}; + return false; + } + if (kfUseCascadeMassConstraint) { + // set mass constraint if requested + // WARNING: this is only adequate for decay chains, i.e. XiC -> Xi or OmegaC -> Omega + KFXi.SetNonlinearMassConstraint(o2::constants::physics::MassXiMinus); + KFOmega.SetNonlinearMassConstraint(o2::constants::physics::MassOmegaMinus); + } + KFXi.TransportToDecayVertex(); + KFOmega.TransportToDecayVertex(); + + // get DCA of daughters at vertex + cascade.cascadeDaughterDCA = kfpBachPion.GetDistanceFromParticle(kfpV0); + if (cascade.cascadeDaughterDCA > cascadeselections.dcacascdau) { + cascade = {}; + return false; + } + + //__________________________________________ + //*>~<* step 5 : propagate cascade to primary vertex with material corrections if asked + + o2::track::TrackParCov lCascadeTrack; + if (!kfTuneForOmega) { + lCascadeTrack = getTrackParCovFromKFP(KFXi, o2::track::PID::XiMinus, cascade.charge); + } else { + lCascadeTrack = getTrackParCovFromKFP(KFOmega, o2::track::PID::OmegaMinus, cascade.charge); + } + dcaInfo[0] = 999; + dcaInfo[1] = 999; + o2::base::Propagator::Instance()->propagateToDCABxByBz({pvX, pvY, pvZ}, lCascadeTrack, 2.f, fitter.getMatCorrType(), &dcaInfo); + cascade.cascadeDCAxy = dcaInfo[0]; + cascade.cascadeDCAz = dcaInfo[1]; + + //__________________________________________ + //*>~<* step 6 : acquire all parameters for analysis + + // basic indices + cascade.collisionId = collisionIndex; + cascade.v0Id = -1; + cascade.positiveTrack = positiveTrack.globalIndex(); + cascade.negativeTrack = negativeTrack.globalIndex(); + cascade.bachelorTrack = bachelorTrack.globalIndex(); + + // KF chi2 + cascade.kfV0Chi2 = KFV0.GetChi2(); + cascade.kfCascadeChi2 = KFXi.GetChi2(); + if (kfTuneForOmega) + cascade.kfCascadeChi2 = KFOmega.GetChi2(); + + // Daughter momentum not KF-updated FIXME --> but DCA fitter updated if pre-minimisation is used + lBachelorTrack.getPxPyPzGlo(cascade.bachelorMomentum); + posTrackParCov.getPxPyPzGlo(cascade.positiveMomentum); + negTrackParCov.getPxPyPzGlo(cascade.negativeMomentum); + + // Daughter track position at vertex not KF-updated FIXME --> but DCA fitter updated if pre-minimisation is used + posTrackParCov.getXYZGlo(cascade.positivePosition); + negTrackParCov.getXYZGlo(cascade.negativePosition); + + // mother position information from KF + cascade.v0Position[0] = KFV0.GetX(); + cascade.v0Position[1] = KFV0.GetY(); + cascade.v0Position[2] = KFV0.GetZ(); + + // mother momentumm information from KF + cascade.v0Momentum[0] = KFV0.GetPx(); + cascade.v0Momentum[1] = KFV0.GetPy(); + cascade.v0Momentum[2] = KFV0.GetPz(); + + // Mother position + momentum is KF updated + if (!kfTuneForOmega) { + cascade.cascadePosition[0] = KFXi.GetX(); + cascade.cascadePosition[1] = KFXi.GetY(); + cascade.cascadePosition[2] = KFXi.GetZ(); + cascade.cascadeMomentum[0] = KFXi.GetPx(); + cascade.cascadeMomentum[1] = KFXi.GetPy(); + cascade.cascadeMomentum[2] = KFXi.GetPz(); + } else { + cascade.cascadePosition[0] = KFOmega.GetX(); + cascade.cascadePosition[1] = KFOmega.GetY(); + cascade.cascadePosition[2] = KFOmega.GetZ(); + cascade.cascadeMomentum[0] = KFOmega.GetPx(); + cascade.cascadeMomentum[1] = KFOmega.GetPy(); + cascade.cascadeMomentum[2] = KFOmega.GetPz(); + } + if (std::hypot(cascade.cascadePosition[0], cascade.cascadePosition[1]) < cascadeselections.cascradius) { + cascade = {}; + return false; + } + + // KF-aware cosPA + double cosPA = RecoDecay::cpa( + std::array{pvX, pvY, pvZ}, + std::array{cascade.cascadePosition[0], cascade.cascadePosition[1], cascade.cascadePosition[2]}, + std::array{cascade.cascadeMomentum[0], cascade.cascadeMomentum[1], cascade.cascadeMomentum[2]}); + if (cosPA < cascadeselections.casccospa) { + cascade = {}; + return false; + } + cascade.pointingAngle = TMath::ACos(cosPA); + + // Calculate masses a priori + float MLambda, SigmaLambda, MXi, SigmaXi, MOmega, SigmaOmega; + KFV0.GetMass(MLambda, SigmaLambda); + KFXi.GetMass(MXi, SigmaXi); + KFOmega.GetMass(MOmega, SigmaOmega); + cascade.kfMLambda = MLambda; + cascade.massXi = MXi; + cascade.massOmega = MOmega; + + // KF Cascade covariance matrix + o2::gpu::gpustd::array covCascKF; + for (int i = 0; i < 21; i++) { // get covariance matrix elements (lower triangle) + covCascKF[i] = KFXi.GetCovariance(i); + cascade.covariance[i] = covCascKF[i]; + } + + // KF V0 covariance matrix + o2::gpu::gpustd::array covV0KF; + for (int i = 0; i < 21; i++) { // get covariance matrix elements (lower triangle) + covV0KF[i] = KFV0.GetCovariance(i); + cascade.kfTrackCovarianceV0[i] = covV0KF[i]; + } + + // V0 daughter covariance matrices + std::array cvPosKF, cvNegKF; + posTrackParCov.getCovXYZPxPyPzGlo(cvPosKF); + negTrackParCov.getCovXYZPxPyPzGlo(cvNegKF); + for (int i = 0; i < 21; i++) { + cascade.kfTrackCovariancePos[i] = cvPosKF[i]; + cascade.kfTrackCovarianceNeg[i] = cvNegKF[i]; + } + + return true; + } + + o2::base::MatLayerCylSet* lut; // material LUT for DCA fitter + o2::vertexing::DCAFitterN<2> fitter; // 2-prong o2 dca fitter + + v0candidate v0; // storage for V0 candidate properties + cascadeCandidate cascade; // storage for cascade candidate properties + + // v0 candidate criteria + struct { + int minCrossedRows; + float dcanegtopv; + float dcapostopv; + double v0cospa; + float dcav0dau; + float v0radius; + float maxDaughterEta; + } v0selections; + + // cascade candidate criteria + struct { + int minCrossedRows; + float dcabachtopv; + float cascradius; + float casccospa; + float dcacascdau; + float lambdaMassWindow; + float maxDaughterEta; + } cascadeselections; + + private: + // internal helper to calculate DCA (3D) of a straight line to a given PV analytically + float CalculateDCAStraightToPV(float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) + { + return std::sqrt((std::pow((pvY - Y) * Pz - (pvZ - Z) * Py, 2) + std::pow((pvX - X) * Pz - (pvZ - Z) * Px, 2) + std::pow((pvX - X) * Py - (pvY - Y) * Px, 2)) / (Px * Px + Py * Py + Pz * Pz)); + } + + template + void processBachBaryonVariables(float pvX, float pvY, float pvZ, TTrack const& track1, TTrack const& track2) + { + cascade.bachBaryonCosPA = 0; // would ordinarily accept all + cascade.bachBaryonDCAxyToPV = 1e+3; // would ordinarily accept all + + // create tracks from table rows + o2::track::TrackParCov tr1 = getTrackParCov(track1); + o2::track::TrackParCov tr2 = getTrackParCov(track2); + + //---/---/---/ + // Move close to minima + int nCand = 0; + try { + nCand = fitter.process(tr1, tr2); + } catch (...) { + return; + } + if (nCand == 0) + return; // variables are such that candidate is accepted (not obvious...) + + // Calculate DCAxy of the cascade (with bending) + o2::track::TrackPar wrongV0 = fitter.createParentTrackPar(); + wrongV0.setAbsCharge(0); // charge zero + gpu::gpustd::array dcaInfo; + dcaInfo[0] = 999; + dcaInfo[1] = 999; + + // bachelor-baryon DCAxy to PV + o2::base::Propagator::Instance()->propagateToDCABxByBz({pvX, pvY, pvZ}, wrongV0, 2.f, fitter.getMatCorrType(), &dcaInfo); + cascade.bachBaryonDCAxyToPV = dcaInfo[0]; + + const auto& vtx = fitter.getPCACandidate(); + if (!fitter.isPropagateTracksToVertexDone()) + return; + + std::array tr1p; + std::array tr2p; + + fitter.getTrack(1).getPxPyPzGlo(tr1p); + fitter.getTrack(2).getPxPyPzGlo(tr2p); + + // bachelor-baryon CosPA + cascade.bachBaryonCosPA = RecoDecay::cpa( + std::array{pvX, pvY, pvZ}, + std::array{vtx[0], vtx[1], vtx[2]}, + std::array{tr1p[0] + tr2p[0], tr1p[1] + tr2p[1], tr1p[2] + tr2p[2]}); + + // Potentially also to be considered: bachelor-baryon DCA (between the two tracks) + // to be added here as complementary information in the future + } +}; + +} // namespace pwglf +} // namespace o2 + +#endif // PWGLF_UTILS_STRANGENESSBUILDERHELPER_H_ diff --git a/PWGLF/Utils/strangenessMasks.h b/PWGLF/Utils/strangenessMasks.h new file mode 100644 index 00000000000..ef224c8e5fa --- /dev/null +++ b/PWGLF/Utils/strangenessMasks.h @@ -0,0 +1,156 @@ +// 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 strangenessMasks.h +/// \brief Defines selection criteria and bit masks for identifying v0 and cascade particles +/// \author Roman Nepeivoda (roman.nepeivoda@cern.ch) + +#ifndef PWGLF_UTILS_STRANGENESSMASKS_H_ +#define PWGLF_UTILS_STRANGENESSMASKS_H_ + +enum SelectionsCombined : int { selV0CosPA = 0, + selV0Radius, + selV0RadiusMax, + selDCANegToPV, + selDCAPosToPV, + selDCAV0Dau, + selK0ShortRapidity, + selLambdaRapidity, + selTPCPIDPositivePion, + selTPCPIDNegativePion, + selTPCPIDPositiveProton, + selTPCPIDNegativeProton, + selTOFDeltaTPositiveProtonLambda, + selTOFDeltaTPositivePionLambda, + selTOFDeltaTPositivePionK0Short, + selTOFDeltaTNegativeProtonLambda, + selTOFDeltaTNegativePionLambda, + selTOFDeltaTNegativePionK0Short, + selTOFNSigmaPositiveProtonLambda, // Nsigma + selTOFNSigmaPositivePionLambda, // Nsigma + selTOFNSigmaPositivePionK0Short, // Nsigma + selTOFNSigmaNegativeProtonLambda, // Nsigma + selTOFNSigmaNegativePionLambda, // Nsigma + selTOFNSigmaNegativePionK0Short, // Nsigma + selK0ShortCTau, + selLambdaCTau, + selK0ShortArmenteros, + selPosGoodTPCTrack, // at least min # TPC rows + selNegGoodTPCTrack, // at least min # TPC rows + selPosGoodITSTrack, // at least min # ITS clusters + selNegGoodITSTrack, // at least min # ITS clusters + selPosItsOnly, + selNegItsOnly, + selPosNotTPCOnly, + selNegNotTPCOnly, + selConsiderK0Short, // for mc tagging + selConsiderLambda, // for mc tagging + selConsiderAntiLambda, // for mc tagging + selPhysPrimK0Short, // for mc tagging + selPhysPrimLambda, // for mc tagging + selPhysPrimAntiLambda, // for mc tagging + selPosEta, + selNegEta, + selDauDCA, + // cascade selections + selCascCosPA, + selMassWinXi, + selMassWinOmega, + selDCACascDau, + selDCAV0ToPV, + selCascRadius, + selCascRadiusMax, + selBachBaryon, + selRejCompXi, + selRejCompOmega, + selBachToPV, + selMesonToPV, + selBaryonToPV, + selXiRapidity, + selXiCTau, + selConsiderXi, + selConsiderAntiXi, + selPhysPrimXi, + selPhysPrimAntiXi, + selOmegaRapidity, + selOmegaCTau, + selConsiderOmega, + selConsiderAntiOmega, + selPhysPrimOmega, + selPhysPrimAntiOmega, + selBachItsOnly, + selBachNotTPCOnly, + selBachGoodTPCTrack, + selBachGoodITSTrack, + selTPCPIDBachPion, + selTPCPIDBachKaon, + selTOFNSigmaBachPionXi, + selTOFNSigmaBachKaonOmega, + selTOFNSigmaPositiveProtonLambdaXi, + selTOFNSigmaPositiveProtonLambdaOmega, + selTOFNSigmaPositivePionLambdaXi, + selTOFNSigmaPositivePionLambdaOmega, + selTOFNSigmaNegativePionLambdaXi, + selTOFNSigmaNegativePionLambdaOmega, + selTOFNSigmaNegativeProtonLambdaXi, + selTOFNSigmaNegativeProtonLambdaOmega, + selTOFDeltaTPositiveProtonLambdaXi, + selTOFDeltaTPositiveProtonLambdaOmega, + selTOFDeltaTPositivePionLambdaXi, + selTOFDeltaTPositivePionLambdaOmega, + selTOFDeltaTNegativeProtonLambdaXi, + selTOFDeltaTNegativeProtonLambdaOmega, + selTOFDeltaTNegativePionLambdaXi, + selTOFDeltaTNegativePionLambdaOmega, + selTOFDeltaTBachPionXi, + selTOFDeltaTBachKaonOmega, + selBachEta, + selLambdaMassWin, + selCount, +}; + +static constexpr int kSelNum = static_cast(SelectionsCombined::selCount); + +// constants +const float ctauxiPDG = 4.91; // from PDG +const float ctauomegaPDG = 2.461; // from PDG + +// bit masks +std::bitset maskTopologicalV0; +std::bitset maskTopologicalCasc; + +std::bitset maskKinematicV0; +std::bitset maskKinematicCasc; + +std::bitset maskTrackPropertiesV0; +std::bitset maskTrackPropertiesCasc; + +std::bitset maskK0ShortSpecific; +std::bitset maskLambdaSpecific; +std::bitset maskAntiLambdaSpecific; +std::bitset maskXiSpecific; +std::bitset maskAntiXiSpecific; +std::bitset maskOmegaSpecific; +std::bitset maskAntiOmegaSpecific; + +std::bitset maskSelectionK0Short; +std::bitset maskSelectionLambda; +std::bitset maskSelectionAntiLambda; + +std::bitset secondaryMaskSelectionLambda; +std::bitset secondaryMaskSelectionAntiLambda; + +std::bitset maskSelectionXi; +std::bitset maskSelectionAntiXi; +std::bitset maskSelectionOmega; +std::bitset maskSelectionAntiOmega; + +#endif // PWGLF_UTILS_STRANGENESSMASKS_H_ diff --git a/PWGLF/Utils/svPoolCreator.h b/PWGLF/Utils/svPoolCreator.h new file mode 100644 index 00000000000..2414eb7e19b --- /dev/null +++ b/PWGLF/Utils/svPoolCreator.h @@ -0,0 +1,271 @@ +// 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. + +#ifndef PWGLF_UTILS_SVPOOLCREATOR_H_ +#define PWGLF_UTILS_SVPOOLCREATOR_H_ + +#include +#include +#include +#include +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Common/Core/trackUtilities.h" +#include "DCAFitter/DCAFitterN.h" +#include "Framework/AnalysisDataModel.h" + +using namespace o2; +using namespace o2::constants; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; +using CollBracket = o2::math_utils::Bracket; + +constexpr uint64_t bOffsetMax = 241; // track compatibility can never go beyond 6 mus (ITS) + +struct TrackCand { + int Idxtr; + CollBracket collBracket{}; +}; + +struct SVCand { + int tr0Idx; + int tr1Idx; + CollBracket collBracket{}; +}; + +class svPoolCreator +{ + public: + svPoolCreator() = default; + svPoolCreator(int track0Pdg, int track1Pdg) + : track0Pdg(track0Pdg), track1Pdg(track1Pdg) + { + } + + void setPDGs(int track0Pdg, int track1Pdg) + { + this->track0Pdg = track0Pdg; + this->track1Pdg = track1Pdg; + } + + void clearPools() + { + for (auto& pool : trackCandPool) { + pool.clear(); + } + tmap.clear(); + svCandPool.clear(); + bc2Coll.clear(); + } + + void setTimeMargin(float timeMargin) { timeMarginNS = timeMargin; } + void setFitter(const o2::vertexing::DCAFitterN<2>& fitter) { this->fitter = fitter; } + void setSkipAmbiTracks() { skipAmbiTracks = true; } + o2::vertexing::DCAFitterN<2>* getFitter() { return &fitter; } + std::array, 4> getTrackCandPool() { return trackCandPool; } + + template + void fillBC2Coll(const C& collisions, aod::BCsWithTimestamps const&) + { + for (unsigned i = 0; i < collisions.size(); i++) { + auto collision = collisions.rawIteratorAt(i); + if (!collision.has_bc()) { + continue; + } + bc2Coll[collision.template bc_as().globalBC()] = i; + } + } + + template + void appendTrackCand(const T& trackCand, const C& collisions, int pdgHypo, o2::aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const&) + { + if (pdgHypo != track0Pdg && pdgHypo != track1Pdg) { + LOG(debug) << "Wrong pdg hypothesis"; + return; + } + bool isDau0 = pdgHypo == track0Pdg; + constexpr uint64_t BcInvalid = -1; + uint64_t globalBC = BcInvalid; + if (trackCand.has_collision()) { + if (trackCand.template collision_as().has_bc()) { + globalBC = trackCand.template collision_as().template bc_as().globalBC(); + } + } else if (!skipAmbiTracks) { + for (const auto& ambTrack : ambiTracks) { + if (ambTrack.trackId() != trackCand.globalIndex()) { + continue; + } + if (!ambTrack.has_bc() || ambTrack.bc_as().size() == 0) { + globalBC = BcInvalid; + break; + } + globalBC = ambTrack.bc_as().begin().globalBC(); + break; + } + } else { + globalBC = BcInvalid; + } + + if (globalBC == BcInvalid) { + return; + } + + uint64_t firstBC = globalBC < bOffsetMax ? 0 : globalBC - bOffsetMax; + uint64_t lastBC = globalBC + bOffsetMax; + int firstCollIdx = -1; + while (firstBC < lastBC) { + if (bc2Coll.find(firstBC) != bc2Coll.end()) { + firstCollIdx = bc2Coll[firstBC]; + break; + } + firstBC++; + } + // now loop over all the collisions to make the pool + for (int i = firstCollIdx; i < collisions.size(); i++) { + const auto& collision = collisions.rawIteratorAt(i); + float collTime = collision.collisionTime(); + float collTimeRes2 = collision.collisionTimeRes() * collision.collisionTimeRes(); + uint64_t collBC = collision.template bc_as().globalBC(); + int collIdx = collision.globalIndex(); + int64_t bcOffset = globalBC - static_cast(collBC); + if (static_cast(std::abs(bcOffset)) > bOffsetMax) { + if (bcOffset < 0) { + break; + } else if (bcOffset > 0) { + continue; + } + } + + float trackTime{0.}; + float trackTimeRes{0.}; + if (trackCand.isPVContributor()) { + trackTime = trackCand.template collision_as().collisionTime(); // if PV contributor, we assume the time to be the one of the collision + trackTimeRes = constants::lhc::LHCBunchSpacingNS; // 1 BC + } else { + trackTime = trackCand.trackTime(); + trackTimeRes = trackCand.trackTimeRes(); + } + + const float deltaTime = trackTime - collTime + bcOffset * constants::lhc::LHCBunchSpacingNS; + float sigmaTimeRes2 = collTimeRes2 + trackTimeRes * trackTimeRes; + + float thresholdTime = 0.; + if (trackCand.isPVContributor()) { + thresholdTime = trackTimeRes; + } else if (TESTBIT(trackCand.flags(), o2::aod::track::TrackTimeResIsRange)) { + thresholdTime = std::sqrt(sigmaTimeRes2); + thresholdTime += timeMarginNS; + + } else { + thresholdTime = 4. * std::sqrt(sigmaTimeRes2); + thresholdTime += timeMarginNS; + } + // LOG(info) << "Threshold time: " << thresholdTime << " isPVContributor: " << trackCand.isPVContributor() << " time margin: " << timeMarginNS; + if (std::abs(deltaTime) > thresholdTime) { + continue; + } + + const auto& tref = tmap.find(trackCand.globalIndex()); + if (tref != tmap.end()) { + LOG(debug) << "Track: " << trackCand.globalIndex() << " already processed with other vertex"; + trackCandPool[tref->second.second][tref->second.first].collBracket.setMax(static_cast(collIdx)); // this track was already processed with other vertex, account the latter + continue; + } + + int poolIndex = (1 - isDau0) * 2 + (trackCand.sign() < 0); + trForpool.Idxtr = trackCand.globalIndex(); + trForpool.collBracket = {static_cast(collIdx), static_cast(collIdx)}; + // LOG(info) << "Adding track to pool: " << trForpool.Idxtr << " with bracket: " << trForpool.collBracket.getMin() << " " << trForpool.collBracket.getMax() << " and pool index: " << poolIndex; + trackCandPool[poolIndex].emplace_back(trForpool); + tmap[trackCand.globalIndex()] = {trackCandPool[poolIndex].size() - 1, poolIndex}; + } + + // is Sorting Needed ? TBD + } + template + std::vector& getSVCandPool(const C& collisions, bool combineLikeSign = false) + { + gsl::span> track0Pool{trackCandPool.data(), 2}; + gsl::span> track1Pool{trackCandPool.data() + 2, 2}; + std::array, 2> mVtxTrack0{}; // 1st pos. and neg. track of the kink pool for each vertex + + for (int i = 0; i < 2; i++) { + mVtxTrack0[i].clear(); + mVtxTrack0[i].resize(collisions.size(), -1); + } + + for (int pn = 0; pn < 2; pn++) { + auto& vtxFirstT = mVtxTrack0[pn]; + const auto& signTrack0Pool = track0Pool[pn]; + for (unsigned i = 0; i < signTrack0Pool.size(); i++) { + const auto& track0Seed = signTrack0Pool[i]; + LOG(debug) << "Processsing track0 with index: " << track0Seed.Idxtr << " min bracket: " << track0Seed.collBracket.getMin() << " max bracket: " << track0Seed.collBracket.getMax(); + for (int j{track0Seed.collBracket.getMin()}; j <= track0Seed.collBracket.getMax(); ++j) { + if (vtxFirstT[j] == -1) { + vtxFirstT[j] = i; + } + } + } + int track1sign = combineLikeSign ? pn : 1 - pn; + auto& signTrack1 = track1Pool[track1sign]; + for (unsigned itp = 0; itp < signTrack1.size(); itp++) { + auto& track1Seed = signTrack1[itp]; + LOG(debug) << "Processing track1 with index: " << track1Seed.Idxtr << " min bracket: " << track1Seed.collBracket.getMin() << " max bracket: " << track1Seed.collBracket.getMax(); + int firsOverlapIdx = -1; + for (int j{track1Seed.collBracket.getMin()}; j <= track1Seed.collBracket.getMax(); ++j) { + LOG(debug) << "Checking vtxFirstT at position " << j << " with value " << vtxFirstT[j]; + if (vtxFirstT[j] != -1) { + firsOverlapIdx = vtxFirstT[j]; + break; + } + } + if (firsOverlapIdx < 0) { + continue; + } + for (unsigned itn = firsOverlapIdx; itn < signTrack0Pool.size(); itn++) { + auto& track0Seed = signTrack0Pool[itn]; + + if (track0Seed.collBracket.getMin() > track1Seed.collBracket.getMax()) { + break; + } + + if (track0Seed.collBracket.isOutside(track1Seed.collBracket)) { + LOG(debug) << "Brackets do not match"; + continue; + } + auto overlapBracket = track0Seed.collBracket.getOverlap(track1Seed.collBracket); + + svCandPool.emplace_back(SVCand{track0Seed.Idxtr, track1Seed.Idxtr, overlapBracket}); + } + } + } + return svCandPool; + } + + template + bool fitSV(unsigned int idxDau0, unsigned int idxDau1, T& trackTable); + + private: + o2::vertexing::DCAFitterN<2> fitter; + int track0Pdg; + int track1Pdg; + float timeMarginNS = 600.; + bool skipAmbiTracks = false; + std::unordered_map> tmap; + std::unordered_map bc2Coll; + + std::array, 4> trackCandPool; // Sorting: dau0 pos, dau0 neg, dau1 pos, dau1 neg + std::vector svCandPool; // index of the two tracks in the track table + TrackCand trForpool; +}; + +#endif // PWGLF_UTILS_SVPOOLCREATOR_H_ diff --git a/PWGLF/Utils/v0SelectionBits.h b/PWGLF/Utils/v0SelectionBits.h new file mode 100644 index 00000000000..dd4b48d5a0b --- /dev/null +++ b/PWGLF/Utils/v0SelectionBits.h @@ -0,0 +1,62 @@ +// 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. + +#ifndef PWGLF_UTILS_V0SELECTIONBITS_H_ +#define PWGLF_UTILS_V0SELECTIONBITS_H_ + +namespace v0data +{ +// provides simple switches +enum selection : uint64_t { selCosPA = 0, + selRadius, + selRadiusMax, + selDCANegToPV, + selDCAPosToPV, + selDCAV0Dau, + selK0ShortRapidity, + selLambdaRapidity, + selTPCPIDPositivePion, + selTPCPIDNegativePion, + selTPCPIDPositiveProton, + selTPCPIDNegativeProton, + selTOFDeltaTPositiveProtonLambda, + selTOFDeltaTPositivePionLambda, + selTOFDeltaTPositivePionK0Short, + selTOFDeltaTNegativeProtonLambda, + selTOFDeltaTNegativePionLambda, + selTOFDeltaTNegativePionK0Short, + selTOFNSigmaPositiveProtonLambda, // Nsigma + selTOFNSigmaPositivePionLambda, // Nsigma + selTOFNSigmaPositivePionK0Short, // Nsigma + selTOFNSigmaNegativeProtonLambda, // Nsigma + selTOFNSigmaNegativePionLambda, // Nsigma + selTOFNSigmaNegativePionK0Short, // Nsigma + selK0ShortCTau, + selLambdaCTau, + selK0ShortArmenteros, + selPosGoodTPCTrack, // at least min # TPC rows + selNegGoodTPCTrack, // at least min # TPC rows + selPosGoodITSTrack, // at least min # ITS clusters + selNegGoodITSTrack, // at least min # ITS clusters + selPosItsOnly, + selNegItsOnly, + selPosNotTPCOnly, + selNegNotTPCOnly, + selConsiderK0Short, // for mc tagging + selConsiderLambda, // for mc tagging + selConsiderAntiLambda, // for mc tagging + selPhysPrimK0Short, // for mc tagging + selPhysPrimLambda, // for mc tagging + selPhysPrimAntiLambda, // for mc tagging +}; +} // namespace v0data + +#endif // PWGLF_UTILS_V0SELECTIONBITS_H_ diff --git a/PWGLF/Utils/v0SelectionGroup.cxx b/PWGLF/Utils/v0SelectionGroup.cxx new file mode 100644 index 00000000000..6ceffa27482 --- /dev/null +++ b/PWGLF/Utils/v0SelectionGroup.cxx @@ -0,0 +1,107 @@ +// 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. + +// see header for a more detailed description. + +#include "v0SelectionGroup.h" + +// simple checkers, but ensure 64 bit integers +#define bitset(var, nbit) ((var) |= (static_cast(1) << static_cast(nbit))) +#define bitcheck(var, nbit) ((var) & (static_cast(1) << static_cast(nbit))) + +// trivial 64-bit mask checker +bool v0SelectionGroup::verifyMask(uint64_t bitmap, uint64_t mask) const +{ + return (bitmap & mask) == mask; +} + +// provides standard masks given current event selection criteria. +void v0SelectionGroup::provideMasks(uint64_t& maskTopological, uint64_t& maskTrackProperties, uint64_t& maskK0ShortSpecific, uint64_t& maskLambdaSpecific, uint64_t& maskAntiLambdaSpecific) const +{ + maskTopological = (uint64_t(1) << v0data::selCosPA) | (uint64_t(1) << v0data::selRadius) | (uint64_t(1) << v0data::selDCANegToPV) | (uint64_t(1) << v0data::selDCAPosToPV) | (uint64_t(1) << v0data::selDCAV0Dau) | (uint64_t(1) << v0data::selRadiusMax); + maskK0ShortSpecific = (uint64_t(1) << v0data::selK0ShortRapidity) | (uint64_t(1) << v0data::selK0ShortCTau) | (uint64_t(1) << v0data::selK0ShortArmenteros) | (uint64_t(1) << v0data::selConsiderK0Short); + maskLambdaSpecific = (uint64_t(1) << v0data::selLambdaRapidity) | (uint64_t(1) << v0data::selLambdaCTau) | (uint64_t(1) << v0data::selConsiderLambda); + maskAntiLambdaSpecific = (uint64_t(1) << v0data::selLambdaRapidity) | (uint64_t(1) << v0data::selLambdaCTau) | (uint64_t(1) << v0data::selConsiderAntiLambda); + + // ask for specific TPC/TOF PID v0data::selections + maskTrackProperties = 0; + if (requirePosITSonly) { + maskTrackProperties = maskTrackProperties | (uint64_t(1) << v0data::selPosItsOnly) | (uint64_t(1) << v0data::selPosGoodITSTrack); + } else { + maskTrackProperties = maskTrackProperties | (uint64_t(1) << v0data::selPosGoodTPCTrack) | (uint64_t(1) << v0data::selPosGoodITSTrack); + // TPC signal is available: ask for positive track PID + if (TpcPidNsigmaCut < 1e+5) { // safeguard for no cut + maskK0ShortSpecific = maskK0ShortSpecific | (uint64_t(1) << v0data::selTPCPIDPositivePion); + maskLambdaSpecific = maskLambdaSpecific | (uint64_t(1) << v0data::selTPCPIDPositiveProton); + maskAntiLambdaSpecific = maskAntiLambdaSpecific | (uint64_t(1) << v0data::selTPCPIDPositivePion); + } + // TOF PID + if (TofPidNsigmaCutK0Pi < 1e+5) // safeguard for no cut + maskK0ShortSpecific = maskK0ShortSpecific | (uint64_t(1) << v0data::selTOFNSigmaPositivePionK0Short) | (uint64_t(1) << v0data::selTOFDeltaTPositivePionK0Short); + if (TofPidNsigmaCutLaPr < 1e+5) // safeguard for no cut + maskLambdaSpecific = maskLambdaSpecific | (uint64_t(1) << v0data::selTOFNSigmaPositiveProtonLambda) | (uint64_t(1) << v0data::selTOFDeltaTPositiveProtonLambda); + if (TofPidNsigmaCutLaPi < 1e+5) // safeguard for no cut + maskAntiLambdaSpecific = maskAntiLambdaSpecific | (uint64_t(1) << v0data::selTOFNSigmaPositivePionLambda) | (uint64_t(1) << v0data::selTOFDeltaTPositivePionLambda); + } + if (requireNegITSonly) { + maskTrackProperties = maskTrackProperties | (uint64_t(1) << v0data::selNegItsOnly) | (uint64_t(1) << v0data::selNegGoodITSTrack); + } else { + maskTrackProperties = maskTrackProperties | (uint64_t(1) << v0data::selNegGoodTPCTrack) | (uint64_t(1) << v0data::selNegGoodITSTrack); + // TPC signal is available: ask for negative track PID + if (TpcPidNsigmaCut < 1e+5) { // safeguard for no cut + maskK0ShortSpecific = maskK0ShortSpecific | (uint64_t(1) << v0data::selTPCPIDNegativePion); + maskLambdaSpecific = maskLambdaSpecific | (uint64_t(1) << v0data::selTPCPIDNegativePion); + maskAntiLambdaSpecific = maskAntiLambdaSpecific | (uint64_t(1) << v0data::selTPCPIDNegativeProton); + } + // TOF PID + if (TofPidNsigmaCutK0Pi < 1e+5) // safeguard for no cut + maskK0ShortSpecific = maskK0ShortSpecific | (uint64_t(1) << v0data::selTOFNSigmaNegativePionK0Short) | (uint64_t(1) << v0data::selTOFDeltaTNegativePionK0Short); + if (TofPidNsigmaCutLaPr < 1e+5) // safeguard for no cut + maskLambdaSpecific = maskLambdaSpecific | (uint64_t(1) << v0data::selTOFNSigmaNegativePionLambda) | (uint64_t(1) << v0data::selTOFDeltaTNegativePionLambda); + if (TofPidNsigmaCutLaPi < 1e+5) // safeguard for no cut + maskAntiLambdaSpecific = maskAntiLambdaSpecific | (uint64_t(1) << v0data::selTOFNSigmaNegativeProtonLambda) | (uint64_t(1) << v0data::selTOFDeltaTNegativeProtonLambda); + } + + if (skipTPConly) { + maskK0ShortSpecific = maskK0ShortSpecific | (uint64_t(1) << v0data::selPosNotTPCOnly) | (uint64_t(1) << v0data::selNegNotTPCOnly); + maskLambdaSpecific = maskLambdaSpecific | (uint64_t(1) << v0data::selPosNotTPCOnly) | (uint64_t(1) << v0data::selNegNotTPCOnly); + maskAntiLambdaSpecific = maskAntiLambdaSpecific | (uint64_t(1) << v0data::selPosNotTPCOnly) | (uint64_t(1) << v0data::selNegNotTPCOnly); + } +} + +void v0SelectionGroup::PrintSelections() const +{ + LOGF(info, "+++ Phase space selections ++++++++++++++++++++++++"); + LOGF(info, "Rapidity cut ...........................: %.2f", rapidityCut); + LOGF(info, "Eta (daughters) cut ....................: %.2f", daughterEtaCut); + LOGF(info, "+++ Topological selections ++++++++++++++++++++++++"); + LOGF(info, "V0 cosine of PA ........................: %.2f", v0cospa); + LOGF(info, "DCA V0 daughters .......................: %.2f", dcav0dau); + LOGF(info, "Neg track DCA to PV ....................: %.2f", dcanegtopv); + LOGF(info, "Pos track DCA to PV ....................: %.2f", dcapostopv); + LOGF(info, "Minimum radius .........................: %.2f", v0radius); + LOGF(info, "Maximum radius .........................: %.2f", v0radiusMax); + LOGF(info, "+++ Track quality selections ++++++++++++++++++++++"); + LOGF(info, "Minimum TPC rows .......................: %i", minTPCrows); + LOGF(info, "Minimum ITS clusters ...................: %i", minITSclusters); + LOGF(info, "Skip TPC only ..........................: %s", skipTPConly ? "true" : "false"); + LOGF(info, "Require positive ITS only ..............: %s", requirePosITSonly ? "true" : "false"); + LOGF(info, "Require negative ITS only ..............: %s", requireNegITSonly ? "true" : "false"); + LOGF(info, "+++ Particle identification selections ++++++++++++"); + LOGF(info, "TPC PID Nsigma .........................: %.2f", TpcPidNsigmaCut); + LOGF(info, "TOF PID Nsigma LaPr ....................: %.2f", TofPidNsigmaCutLaPr); + LOGF(info, "TOF PID Nsigma LaPi ....................: %.2f", TofPidNsigmaCutLaPi); + LOGF(info, "TOF PID Nsigma K0Pi ....................: %.2f", TofPidNsigmaCutK0Pi); + LOGF(info, "+++ Misc selections ++++++++++++++++++++++++++++++"); + LOGF(info, "K0Short lifetime cut ...................: %.2f", lifetimeCutK0Short); + LOGF(info, "Lambda lifetime cut ....................: %.2f", lifetimeCutLambda); + LOGF(info, "Armenteros podolanski parameter ........: %.2f", armPodCut); +} diff --git a/PWGLF/Utils/v0SelectionGroup.h b/PWGLF/Utils/v0SelectionGroup.h new file mode 100644 index 00000000000..a353a86c742 --- /dev/null +++ b/PWGLF/Utils/v0SelectionGroup.h @@ -0,0 +1,105 @@ +// 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. + +#ifndef PWGLF_UTILS_V0SELECTIONGROUP_H_ +#define PWGLF_UTILS_V0SELECTIONGROUP_H_ + +#include +#include +#include +#include "v0SelectionBits.h" +#include "Framework/Logger.h" +#include "CommonConstants/PhysicsConstants.h" + +class v0SelectionGroup +{ + public: + v0SelectionGroup() + : rapidityCut{0.5f}, daughterEtaCut{0.8f}, v0cospa{0.97f}, dcav0dau{1.0f}, dcanegtopv{0.05f}, dcapostopv{0.05f}, v0radius{1.2f}, v0radiusMax{1e+5}, minTPCrows{70}, minITSclusters{-1}, skipTPConly{false}, requirePosITSonly{false}, requireNegITSonly{false}, TpcPidNsigmaCut{5.0f}, TofPidNsigmaCutLaPr{1e+6}, TofPidNsigmaCutLaPi{1e+6}, TofPidNsigmaCutK0Pi{1e+6}, maxDeltaTimeProton{1e+9}, maxDeltaTimePion{1e+9}, lifetimeCutK0Short{20.0f}, lifetimeCutLambda{20.0f}, armPodCut{5.0f} + { + // constructor + } + + void provideMasks(uint64_t& maskTopological, uint64_t& maskTrackProperties, uint64_t& maskK0ShortSpecific, uint64_t& maskLambdaSpecific, uint64_t& maskAntiLambdaSpecific) const; + bool verifyMask(uint64_t bitmap, uint64_t mask) const; + + float getRapidityCut() const { return rapidityCut; } + float getDaughterEtaCut() const { return daughterEtaCut; } + + float getv0cospa() const { return v0cospa; } + float getdcav0dau() const { return dcav0dau; } + float getdcanegtopv() const { return dcanegtopv; } + float getdcapostopv() const { return dcapostopv; } + float getv0radius() const { return v0radius; } + float getv0radiusMax() const { return v0radiusMax; } + + int getminTPCrows() const { return minTPCrows; } + int getminITSclusters() const { return minITSclusters; } + bool getskipTPConly() const { return skipTPConly; } + bool getrequirePosITSonly() const { return requirePosITSonly; } + bool getrequireNegITSonly() const { return requireNegITSonly; } + + float getTpcPidNsigmaCut() const { return TpcPidNsigmaCut; } + float getTofPidNsigmaCutLaPr() const { return TofPidNsigmaCutLaPr; } + float getTofPidNsigmaCutLaPi() const { return TofPidNsigmaCutLaPi; } + float getTofPidNsigmaCutK0Pi() const { return TofPidNsigmaCutK0Pi; } + + float getmaxDeltaTimeProton() const { return maxDeltaTimeProton; } + float getmaxDeltaTimePion() const { return maxDeltaTimePion; } + + float getlifetimeCutK0Short() const { return lifetimeCutK0Short; } + float getlifetimeCutLambda() const { return lifetimeCutLambda; } + + float getarmPodCut() const { return armPodCut; } + + // Helper to print out selections + void PrintSelections() const; + + private: + // Phase space + float rapidityCut; + float daughterEtaCut; + // Topology + float v0cospa; + float dcav0dau; + float dcanegtopv; + float dcapostopv; + float v0radius; + float v0radiusMax; + + // Track quality + int minTPCrows; + int minITSclusters; + bool skipTPConly; + bool requirePosITSonly; + bool requireNegITSonly; + + // PID + float TpcPidNsigmaCut; + float TofPidNsigmaCutLaPr; + float TofPidNsigmaCutLaPi; + float TofPidNsigmaCutK0Pi; + + // PID precursor (compatibility only); + float maxDeltaTimeProton; + float maxDeltaTimePion; + + // Lifetime + float lifetimeCutK0Short; + float lifetimeCutLambda; + + // Armenteros + float armPodCut; + + ClassDefNV(v0SelectionGroup, 1); +}; + +#endif // PWGLF_UTILS_V0SELECTIONGROUP_H_ diff --git a/PWGLF/Utils/v0SelectionGroupLinkDef.h b/PWGLF/Utils/v0SelectionGroupLinkDef.h new file mode 100644 index 00000000000..3c81add2fc2 --- /dev/null +++ b/PWGLF/Utils/v0SelectionGroupLinkDef.h @@ -0,0 +1,25 @@ +// 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. + +#ifndef PWGLF_UTILS_V0SELECTIONGROUPLINKDEF_H_ +#define PWGLF_UTILS_V0SELECTIONGROUPLINKDEF_H_ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; +#pragma link C++ nestedclasses; +#pragma link C++ class v0SelectionGroup + ; +#pragma link C++ class std::vector < int> + ; +#pragma link C++ class std::vector < float> + ; +#pragma link C++ class std::vector < double> + ; +#pragma link C++ class std::vector < bool> + ; + +#endif // PWGLF_UTILS_V0SELECTIONGROUPLINKDEF_H_ diff --git a/PWGLF/Utils/v0SelectionTools.h b/PWGLF/Utils/v0SelectionTools.h new file mode 100644 index 00000000000..c88e43eaace --- /dev/null +++ b/PWGLF/Utils/v0SelectionTools.h @@ -0,0 +1,131 @@ +// 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. + +#ifndef PWGLF_UTILS_V0SELECTIONTOOLS_H_ +#define PWGLF_UTILS_V0SELECTIONTOOLS_H_ + +#include "v0SelectionBits.h" +#include "v0SelectionGroup.h" + +// simple checkers, but ensure 64 bit integers +#define bitset(var, nbit) ((var) |= (static_cast(1) << static_cast(nbit))) +#define bitcheck(var, nbit) ((var) & (static_cast(1) << static_cast(nbit))) + +namespace v0data +{ + +// utility method to calculate a selection map for the V0s +template +uint64_t computeReconstructionBitmap(TV0 v0, TTrack posTrackExtra, TTrack negTrackExtra, TCollision collision, float rapidityLambda, float rapidityK0Short, const v0SelectionGroup& v0sels) +// precalculate this information so that a check is one mask operation, not many +{ + uint64_t bitMap = 0; + // Base topological variables + if (v0.v0radius() > v0sels.getv0radius()) + bitset(bitMap, v0data::selRadius); + if (v0.v0radius() < v0sels.getv0radiusMax()) + bitset(bitMap, v0data::selRadiusMax); + if (TMath::Abs(v0.dcapostopv()) > v0sels.getdcapostopv()) + bitset(bitMap, v0data::selDCAPosToPV); + if (TMath::Abs(v0.dcanegtopv()) > v0sels.getdcanegtopv()) + bitset(bitMap, v0data::selDCANegToPV); + if (v0.v0cosPA() > v0sels.getv0cospa()) + bitset(bitMap, v0data::selCosPA); + if (v0.dcaV0daughters() < v0sels.getdcav0dau()) + bitset(bitMap, v0data::selDCAV0Dau); + + // rapidity + if (TMath::Abs(rapidityLambda) < v0sels.getRapidityCut()) + bitset(bitMap, v0data::selLambdaRapidity); + if (TMath::Abs(rapidityK0Short) < v0sels.getRapidityCut()) + bitset(bitMap, v0data::selK0ShortRapidity); + + // ITS quality flags + if (posTrackExtra.itsNCls() >= v0sels.getminITSclusters()) + bitset(bitMap, v0data::selPosGoodITSTrack); + if (negTrackExtra.itsNCls() >= v0sels.getminITSclusters()) + bitset(bitMap, v0data::selNegGoodITSTrack); + + // TPC quality flags + if (posTrackExtra.tpcCrossedRows() >= v0sels.getminTPCrows()) + bitset(bitMap, v0data::selPosGoodTPCTrack); + if (negTrackExtra.tpcCrossedRows() >= v0sels.getminTPCrows()) + bitset(bitMap, v0data::selNegGoodTPCTrack); + + // TPC PID + if (fabs(posTrackExtra.tpcNSigmaPi()) < v0sels.getTpcPidNsigmaCut()) + bitset(bitMap, v0data::selTPCPIDPositivePion); + if (fabs(posTrackExtra.tpcNSigmaPr()) < v0sels.getTpcPidNsigmaCut()) + bitset(bitMap, v0data::selTPCPIDPositiveProton); + if (fabs(negTrackExtra.tpcNSigmaPi()) < v0sels.getTpcPidNsigmaCut()) + bitset(bitMap, v0data::selTPCPIDNegativePion); + if (fabs(negTrackExtra.tpcNSigmaPr()) < v0sels.getTpcPidNsigmaCut()) + bitset(bitMap, v0data::selTPCPIDNegativeProton); + + // TOF PID in DeltaT (deprecated, kept for compatibility) + // Positive track + if (fabs(v0.posTOFDeltaTLaPr()) < v0sels.getmaxDeltaTimeProton()) + bitset(bitMap, v0data::selTOFDeltaTPositiveProtonLambda); + if (fabs(v0.posTOFDeltaTLaPi()) < v0sels.getmaxDeltaTimePion()) + bitset(bitMap, v0data::selTOFDeltaTPositivePionLambda); + if (fabs(v0.posTOFDeltaTK0Pi()) < v0sels.getmaxDeltaTimePion()) + bitset(bitMap, v0data::selTOFDeltaTPositivePionK0Short); + // Negative track + if (fabs(v0.negTOFDeltaTLaPr()) < v0sels.getmaxDeltaTimeProton()) + bitset(bitMap, v0data::selTOFDeltaTNegativeProtonLambda); + if (fabs(v0.negTOFDeltaTLaPi()) < v0sels.getmaxDeltaTimePion()) + bitset(bitMap, v0data::selTOFDeltaTNegativePionLambda); + if (fabs(v0.negTOFDeltaTK0Pi()) < v0sels.getmaxDeltaTimePion()) + bitset(bitMap, v0data::selTOFDeltaTNegativePionK0Short); + + // TOF PID in NSigma + // Positive track + if (fabs(v0.tofNSigmaLaPr()) < v0sels.getTofPidNsigmaCutLaPr()) + bitset(bitMap, v0data::selTOFNSigmaPositiveProtonLambda); + if (fabs(v0.tofNSigmaALaPi()) < v0sels.getTofPidNsigmaCutLaPi()) + bitset(bitMap, v0data::selTOFNSigmaPositivePionLambda); + if (fabs(v0.tofNSigmaK0PiPlus()) < v0sels.getTofPidNsigmaCutK0Pi()) + bitset(bitMap, v0data::selTOFNSigmaPositivePionK0Short); + // Negative track + if (fabs(v0.tofNSigmaALaPr()) < v0sels.getTofPidNsigmaCutLaPr()) + bitset(bitMap, v0data::selTOFNSigmaNegativeProtonLambda); + if (fabs(v0.tofNSigmaLaPi()) < v0sels.getTofPidNsigmaCutLaPi()) + bitset(bitMap, v0data::selTOFNSigmaNegativePionLambda); + if (fabs(v0.tofNSigmaK0PiMinus()) < v0sels.getTofPidNsigmaCutK0Pi()) + bitset(bitMap, v0data::selTOFNSigmaNegativePionK0Short); + + // ITS only tag + if (posTrackExtra.tpcCrossedRows() < 1) + bitset(bitMap, v0data::selPosItsOnly); + if (negTrackExtra.tpcCrossedRows() < 1) + bitset(bitMap, v0data::selNegItsOnly); + + // TPC only tag + if (posTrackExtra.detectorMap() != o2::aod::track::TPC) + bitset(bitMap, v0data::selPosNotTPCOnly); + if (negTrackExtra.detectorMap() != o2::aod::track::TPC) + bitset(bitMap, v0data::selNegNotTPCOnly); + + // proper lifetime + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < v0sels.getlifetimeCutLambda()) + bitset(bitMap, v0data::selLambdaCTau); + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < v0sels.getlifetimeCutK0Short()) + bitset(bitMap, v0data::selK0ShortCTau); + + // armenteros + if (v0.qtarm() * v0sels.getarmPodCut() > TMath::Abs(v0.alpha()) || v0sels.getarmPodCut() < 1e-4) + bitset(bitMap, v0data::selK0ShortArmenteros); + + return bitMap; +} +} // namespace v0data + +#endif // PWGLF_UTILS_V0SELECTIONTOOLS_H_ diff --git a/PWGMM/Lumi/Tasks/lumiStability.cxx b/PWGMM/Lumi/Tasks/lumiStability.cxx index edfb91ef6c3..5938ec42cdd 100644 --- a/PWGMM/Lumi/Tasks/lumiStability.cxx +++ b/PWGMM/Lumi/Tasks/lumiStability.cxx @@ -8,65 +8,221 @@ // 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 lumiStability.cxx +/// \brief Analysis over BCs to study the luminosity stability along time. /// -/// \brief This task is an empty skeleton that fills a simple eta histogram. -/// it is meant to be a blank page for further developments. -/// \author everyone +/// \author Josue Martinez Garcia, josuem@cern.ch + +#include +#include +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/TrackSelectionTables.h" #include "Framework/ASoAHelpers.h" #include "DataFormatsFDD/Digit.h" +#include "DataFormatsFT0/Digit.h" +#include "DataFormatsFV0/Digit.h" #include "Framework/ASoA.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonDataFormat/BunchFilling.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsParameters/GRPECSObject.h" using namespace o2; using namespace o2::framework; -using BCsWithTimestamps = soa::Join; -int nBCsPerOrbit = 3564; +using BCsWithTimestamps = soa::Join; -struct lumiStabilityTask { +struct LumiStabilityTask { // Histogram registry: an object to hold your histograms HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + // Declare configurables + Configurable myMaxDeltaBCFDD{"myMaxDeltaBCFDD", 5, {"My BC cut"}}; + Configurable myMaxDeltaBCFT0{"myMaxDeltaBCFT0", 5, {"My BC cut"}}; + Configurable myMaxDeltaBCFV0{"myMaxDeltaBCFV0", 5, {"My BC cut"}}; + Configurable nOrbitsConf{"nOrbitsConf", 972'288'000, "number of orbits"}; + Configurable nOrbitsPerTF{"nOrbitsPerTF", 128, "number of orbits per time frame"}; + Configurable minOrbitConf{"minOrbitConf", 0, "minimum orbit"}; + Configurable is2022Data{"is2022Data", true, "To 2022 data"}; + Configurable minEmpty{"minEmpty", 5, "number of BCs empty for leading BC"}; + + Service ccdb; + int nBCsPerOrbit = 3564; + int lastRunNumber = -1; + int nOrbits = nOrbitsConf; + double minOrbit = minOrbitConf; + int64_t bcSOR = 0; // global bc of the start of the first orbit, setting 0 by default for unanchored MC + int64_t tsSOR; + int64_t tsEOR; + int64_t nBCsPerTF = nOrbitsPerTF * nBCsPerOrbit; // duration of TF in bcs, should be 128*3564 or 32*3564, setting 128 orbits by default sfor unanchored MC + std::bitset beamPatternA; + std::bitset beamPatternC; + std::bitset bcPatternA; + std::bitset bcPatternC; + std::bitset bcPatternB; + std::bitset bcPatternE; + void init(InitContext const&) { - const AxisSpec axisFDDTriggger{nBCsPerOrbit, -0.5f, nBCsPerOrbit - 0.5f}; - const AxisSpec axisFT0Triggger{nBCsPerOrbit, -0.5f, nBCsPerOrbit - 0.5f}; - const AxisSpec axisFV0Triggger{nBCsPerOrbit, -0.5f, nBCsPerOrbit - 0.5f}; - + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + const AxisSpec axisCounts{6, -0.5, 5.5}; + const AxisSpec axisV0Counts{5, -0.5, 4.5}; + const AxisSpec axisTrigger{nBCsPerOrbit, -0.5f, nBCsPerOrbit - 0.5f}; + const AxisSpec axisPos{1000, -1, 1}; + const AxisSpec axisPosZ{1000, -25, 25}; + const AxisSpec axisNumContrib{1001, -0.5, 1000}; + const AxisSpec axisCollisionTime{1000, -50, 50}; + const AxisSpec axisTime{1000, -10, 40}; + const AxisSpec axisTimeFDD{1000, -20, 100}; + const AxisSpec axisCountsTime{2, -0.5, 1.5}; + const AxisSpec axisOrbits{static_cast(nOrbits / nOrbitsPerTF), 0., static_cast(nOrbits), ""}; + const AxisSpec axisTimeRate{int(double(43200) / (nOrbitsPerTF * 89e-6)), 0., 43200, ""}; // t in seconds. Histo for 12 hrs. Each bin contain one time frame (128/32 orbits for Run2/3). + + histos.add("hBcA", "BC pattern A; BC ; It is present", kTH1F, {axisTrigger}); + histos.add("hBcC", "BC pattern C; BC ; It is present", kTH1F, {axisTrigger}); + histos.add("hBcB", "BC pattern B; BC ; It is present", kTH1F, {axisTrigger}); + histos.add("hBcBL", "BC pattern B - Leading BC; BC ; It is present", kTH1F, {axisTrigger}); + histos.add("hBcE", "BC pattern Empty; BC ; It is present", kTH1F, {axisTrigger}); + histos.add("hvertexX", "Pos X vertex trigger; Pos x; Count ", kTH1F, {axisPos}); + histos.add("hvertexXvsTime", "Pos X vertex vs Collision Time; vertex X (cm) ; time (ns)", {HistType::kTH2F, {{axisPos}, {axisCollisionTime}}}); + histos.add("hvertexY", "Pos Y vertex trigger; Pos y; Count ", kTH1F, {axisPos}); + histos.add("hvertexZ", "Pos Z vertex trigger; Pos z; Count ", kTH1F, {axisPosZ}); + histos.add("hnumContrib", "Num of contributors; Num of contributors; Count ", kTH1I, {axisNumContrib}); + histos.add("hcollisinTime", "Collision Time; ns; Count ", kTH1F, {axisCollisionTime}); + histos.add("hOrbitFDDVertexCoinc", "", kTH1F, {axisOrbits}); + histos.add("hOrbitFDDVertex", "", kTH1F, {axisOrbits}); + histos.add("hOrbitFT0vertex", "", kTH1F, {axisOrbits}); + histos.add("hOrbitFV0Central", "", kTH1F, {axisOrbits}); + histos.add("tsValues", "", kTH1D, {{2, -0.5, 1.5}}); + // time 32.766 is dummy time // histo about triggers - histos.add("FDD/bcVertexTrigger", "vertex trigger per BC (FDD);BC in FDD; counts", kTH1F, {axisFDDTriggger}); - histos.add("FDD/bcVertexTriggerCoincidence", "vertex trigger per BC (FDD) with coincidences;BC in FDD; counts", kTH1F, {axisFDDTriggger}); - histos.add("FDD/bcSCentralTrigger", "scentral trigger per BC (FDD);BC in FDD; counts", kTH1F, {axisFDDTriggger}); - histos.add("FDD/bcSCentralTriggerCoincidence", "scentral trigger per BC (FDD) with coincidences;BC in FDD; counts", kTH1F, {axisFDDTriggger}); - histos.add("FDD/bcVSCTrigger", "vertex and scentral trigger per BC (FDD);BC in FDD; counts", kTH1F, {axisFDDTriggger}); - histos.add("FDD/bcVSCTriggerCoincidence", "vertex and scentral trigger per BC (FDD) with coincidences;BC in FDD; counts", kTH1F, {axisFDDTriggger}); - histos.add("FDD/bcCentralTrigger", "central trigger per BC (FDD);BC in FDD; counts", kTH1F, {axisFDDTriggger}); - histos.add("FDD/bcCentralTriggerCoincidence", "central trigger per BC (FDD) with coincidences;BC in FDD; counts", kTH1F, {axisFDDTriggger}); - histos.add("FDD/bcVCTrigger", "vertex and central trigger per BC (FDD);BC in FDD; counts", kTH1F, {axisFDDTriggger}); - histos.add("FDD/bcVCTriggerCoincidence", "vertex and central trigger per BC (FDD) with coincidences;BC in FDD; counts", kTH1F, {axisFDDTriggger}); - - histos.add("FT0/bcVertexTrigger", "vertex trigger per BC (FT0);BC in FT0; counts", kTH1F, {axisFT0Triggger}); - histos.add("FT0/bcSCentralTrigger", "Scentral trigger per BC (FT0);BC in FT0; counts", kTH1F, {axisFT0Triggger}); - histos.add("FT0/bcVSCTrigger", "vertex and Scentral trigger per BC (FT0);BC in FT0; counts", kTH1F, {axisFT0Triggger}); - histos.add("FT0/bcCentralTrigger", "central trigger per BC (FT0);BC in FT0; counts", kTH1F, {axisFT0Triggger}); - histos.add("FT0/bcVCTrigger", "vertex and central trigger per BC (FT0);BC in FT0; counts", kTH1F, {axisFT0Triggger}); - histos.add("FT0/bcSCentralCentralTrigger", "Scentral and central trigger per BC (FT0);BC in FT0; counts", kTH1F, {axisFT0Triggger}); - - histos.add("FV0/bcOutTrigger", "Out trigger per BC (FV0);BC in V0; counts", kTH1F, {axisFV0Triggger}); - histos.add("FV0/bcInTrigger", "In trigger per BC (FV0);BC in V0; counts", kTH1F, {axisFV0Triggger}); - histos.add("FV0/bcSCenTrigger", "SCen trigger per BC (FV0);BC in V0; counts", kTH1F, {axisFV0Triggger}); - histos.add("FV0/bcCenTrigger", "Out trigger per BC (FV0);BC in V0; counts", kTH1F, {axisFV0Triggger}); - histos.add("FV0/bcSCenCenTrigger", "SCen and Cen trigger per BC (FV0);BC in V0; counts", kTH1F, {axisFV0Triggger}); + histos.add("FDD/hCounts", "0 FDDCount - 1 FDDVertexCount - 2 FDDPPVertexCount - 3 FDDCoincidencesVertexCount - 4 FDDPPCoincidencesVertexCount - 5 FDDPPBotSidesCount; Number; counts", kTH1F, {axisCounts}); + histos.add("FDD/bcVertexTrigger", "vertex trigger per BC (FDD);BC in FDD; counts", kTH1F, {axisTrigger}); + histos.add("FDD/bcVertexTriggerPP", "vertex trigger per BC (FDD);BC in FDD; counts", kTH1F, {axisTrigger}); + histos.add("FDD/bcVertexTriggerCoincidence", "vertex trigger per BC (FDD) with coincidences;BC in FDD; counts", kTH1F, {axisTrigger}); + histos.add("FDD/bcVertexTriggerCoincidencePP", "vertex trigger per BC (FDD) with coincidences and Past Protection;BC in FDD; counts", kTH1F, {axisTrigger}); + histos.add("FDD/bcVertexTriggerBothSidesCoincidencePP", "vertex per BC (FDD) with coincidences, at least one side trigger and Past Protection;BC in FDD; counts", kTH1F, {axisTrigger}); + histos.add("FDD/bcSCentralTrigger", "scentral trigger per BC (FDD);BC in FDD; counts", kTH1F, {axisTrigger}); + histos.add("FDD/bcSCentralTriggerCoincidence", "scentral trigger per BC (FDD) with coincidences;BC in FDD; counts", kTH1F, {axisTrigger}); + histos.add("FDD/bcVSCTrigger", "vertex and scentral trigger per BC (FDD);BC in FDD; counts", kTH1F, {axisTrigger}); + histos.add("FDD/bcVSCTriggerCoincidence", "vertex and scentral trigger per BC (FDD) with coincidences;BC in FDD; counts", kTH1F, {axisTrigger}); + histos.add("FDD/bcCentralTrigger", "central trigger per BC (FDD);BC in FDD; counts", kTH1F, {axisTrigger}); + histos.add("FDD/bcCentralTriggerCoincidence", "central trigger per BC (FDD) with coincidences;BC in FDD; counts", kTH1F, {axisTrigger}); + histos.add("FDD/bcVCTrigger", "vertex and central trigger per BC (FDD);BC in FDD; counts", kTH1F, {axisTrigger}); + histos.add("FDD/bcVCTriggerCoincidence", "vertex and central trigger per BC (FDD) with coincidences;BC in FDD; counts", kTH1F, {axisTrigger}); + histos.add("FDD/hBcAVertex", "BC pattern A in FDD; BC in FDD ; It is present", kTH1F, {axisTrigger}); + histos.add("FDD/hBcCVertex", "BC pattern C in FDD; BC in FDD ; It is present", kTH1F, {axisTrigger}); + histos.add("FDD/hBcBVertex", "BC pattern B in FDD; BC in FDD ; It is present", kTH1F, {axisTrigger}); + histos.add("FDD/hBcBVertexL", "BC pattern B in FDD - Leading BC; BC in FDD ; It is present", kTH1F, {axisTrigger}); + histos.add("FDD/hBcEVertex", "BC pattern Empty in FDD; BC in FDD ; It is present", kTH1F, {axisTrigger}); + histos.add("FDD/timeACbcBVertex", "time bcB ; A (ns); C (ns)", {HistType::kTH2F, {{300, -15, 15}, {300, -15, 15}}}); + histos.add("FDD/timeACbcAVertex", "time bcA ; A (ns); C (ns)", {HistType::kTH2F, {{300, -15, 15}, {300, -15, 15}}}); + histos.add("FDD/timeACbcCVertex", "time bcC ; A (ns); C (ns)", {HistType::kTH2F, {{300, -15, 15}, {300, -15, 15}}}); + histos.add("FDD/timeACbcEVertex", "time bcE ; A (ns); C (ns)", {HistType::kTH2F, {{300, -15, 15}, {300, -15, 15}}}); + histos.add("FDD/hBcA", "BC pattern A in FDD; BC in FDD ; It is present", kTH1F, {axisTrigger}); + histos.add("FDD/hBcC", "BC pattern C in FDD; BC in FDD ; It is present", kTH1F, {axisTrigger}); + histos.add("FDD/hBcB", "BC pattern B in FDD; BC in FDD ; It is present", kTH1F, {axisTrigger}); + histos.add("FDD/hBcBL", "BC pattern B in FDD - Leading BC; BC in FDD ; It is present", kTH1F, {axisTrigger}); + histos.add("FDD/hBcE", "BC pattern Empty in FDD; BC in FDD ; It is present", kTH1F, {axisTrigger}); + histos.add("FDD/timeACbcB", "time bcB ; A (ns); C (ns)", {HistType::kTH2F, {{300, -15, 15}, {300, -15, 15}}}); + histos.add("FDD/timeACbcA", "time bcA ; A (ns); C (ns)", {HistType::kTH2F, {{300, -15, 15}, {300, -15, 15}}}); + histos.add("FDD/timeACbcC", "time bcC ; A (ns); C (ns)", {HistType::kTH2F, {{300, -15, 15}, {300, -15, 15}}}); + histos.add("FDD/timeACbcE", "time bcE ; A (ns); C (ns)", {HistType::kTH2F, {{300, -15, 15}, {300, -15, 15}}}); + histos.add("FDD/hTimeAVertex", "FDD time A; ns ; count", kTH1F, {axisTimeFDD}); + histos.add("FDD/hTimeCVertex", "FDD time C; ns ; count", kTH1F, {axisTimeFDD}); + histos.add("FDD/hTimeACoinc", "FDD time A; ns ; count", kTH1F, {axisTimeFDD}); + histos.add("FDD/hTimeCCoinc", "FDD time C; ns ; count", kTH1F, {axisTimeFDD}); + histos.add("FDD/hCountsTimeA2022", "0 Dummy Time - 1 Valid Time ; Kind of Time; counts", kTH1F, {axisCounts}); + histos.add("FDD/hCountsTimeC2022", "0 Dummy Time - 1 Valid Time ; Kind of Time; counts", kTH1F, {axisCounts}); + histos.add("FDD/hCountsTime2022", "0 Dummy Time - 1 Valid Time ; Kind of Time; counts", kTH1F, {axisCounts}); + histos.add("FDD/hValidTimeAvsBC2022", "Valid Time A vs BC id;BC in FT0;valid time counts", kTH1F, {axisTrigger}); + histos.add("FDD/hInvTimeAvsBC2022", "Invalid Time A vs BC id;BC in FT0;invalid time counts", kTH1F, {axisTrigger}); + histos.add("FDD/hValidTimeCvsBC2022", "Valid Time C vs BC id;BC in FT0;valid time counts", kTH1F, {axisTrigger}); + histos.add("FDD/hInvTimeCvsBC2022", "Invalid Time C vs BC id;BC in FT0;invalid time counts", kTH1F, {axisTrigger}); + histos.add("FDD/hValidTimevsBC2022", "Valid Time vs BC id;BC in FT0;valid time counts", kTH1F, {axisTrigger}); + histos.add("FDD/hInvTimevsBC2022", "Invalid Time vs BC id;BC in FT0;invalid time counts", kTH1F, {axisTrigger}); + histos.add("FDD/hCountsTimeA", "0 Dummy Time - 1 Valid Time ; Kind of Time; counts", kTH1F, {axisCounts}); + histos.add("FDD/hCountsTimeC", "0 Dummy Time - 1 Valid Time ; Kind of Time; counts", kTH1F, {axisCounts}); + histos.add("FDD/hCountsTime", "0 Dummy Time - 1 Valid Time ; Kind of Time; counts", kTH1F, {axisCounts}); + histos.add("FDD/hValidTimeAvsBC", "Valid Time A vs BC id;BC in FT0;valid time counts", kTH1F, {axisTrigger}); + histos.add("FDD/hInvTimeAvsBC", "Invalid Time A vs BC id;BC in FT0;invalid time counts", kTH1F, {axisTrigger}); + histos.add("FDD/hValidTimeCvsBC", "Valid Time C vs BC id;BC in FT0;valid time counts", kTH1F, {axisTrigger}); + histos.add("FDD/hInvTimeCvsBC", "Invalid Time C vs BC id;BC in FT0;invalid time counts", kTH1F, {axisTrigger}); + histos.add("FDD/hValidTimevsBC", "Valid Time vs BC id;BC in FT0;valid time counts", kTH1F, {axisTrigger}); + histos.add("FDD/hInvTimevsBC", "Invalid Time vs BC id;BC in FT0;invalid time counts", kTH1F, {axisTrigger}); + histos.add("FDD/hTimeForRate", "Counts by time in FDD;t (in seconds) in FDD; counts", kTH1F, {axisTimeRate}); + histos.add("FDD/hTimeForRateLeadingBC", "Counts by time in FDD;t (in seconds) in FDD; counts", kTH1F, {axisTimeRate}); + + histos.add("FT0/hCounts", "0 FT0Count - 1 FT0VertexCount - 2 FT0PPVertexCount - 3 FT0PPBothSidesCount; Number; counts", kTH1F, {axisCounts}); + histos.add("FT0/bcVertexTrigger", "vertex trigger per BC (FT0);BC in FT0; counts", kTH1F, {axisTrigger}); + histos.add("FT0/bcVertexTriggerPP", "vertex trigger per BC (FT0) with Past Protection;BC in FT0; counts", kTH1F, {axisTrigger}); + histos.add("FT0/bcVertexTriggerBothSidesPP", "vertex per BC (FDD) with coincidences, at least one side trigger and Past Protection;BC in FDD; counts", kTH1F, {axisTrigger}); + histos.add("FT0/bcSCentralTrigger", "Scentral trigger per BC (FT0);BC in FT0; counts", kTH1F, {axisTrigger}); + histos.add("FT0/bcVSCTrigger", "vertex and Scentral trigger per BC (FT0);BC in FT0; counts", kTH1F, {axisTrigger}); + histos.add("FT0/bcCentralTrigger", "central trigger per BC (FT0);BC in FT0; counts", kTH1F, {axisTrigger}); + histos.add("FT0/bcVCTrigger", "vertex and central trigger per BC (FT0);BC in FT0; counts", kTH1F, {axisTrigger}); + histos.add("FT0/hBcA", "BC pattern A in FT0; BC in FT0 ; It is present", kTH1F, {axisTrigger}); + histos.add("FT0/hBcC", "BC pattern C in FT0; BC in FT0 ; It is present", kTH1F, {axisTrigger}); + histos.add("FT0/hBcB", "BC pattern B in FT0; BC in FT0 ; It is present", kTH1F, {axisTrigger}); + histos.add("FT0/hBcBL", "BC pattern B in FT0 - Leading BC; BC in FT0 ; It is present", kTH1F, {axisTrigger}); + histos.add("FT0/hBcE", "BC pattern Empty in FT0; BC in FT0 ; It is present", kTH1F, {axisTrigger}); + histos.add("FT0/timeACbcB", "time bcB ; A (ns); C (ns)", {HistType::kTH2F, {{300, -15, 15}, {300, -15, 15}}}); + histos.add("FT0/timeACbcA", "time bcA ; A (ns); C (ns)", {HistType::kTH2F, {{300, -15, 15}, {300, -15, 15}}}); + histos.add("FT0/timeACbcC", "time bcC ; A (ns); C (ns)", {HistType::kTH2F, {{300, -15, 15}, {300, -15, 15}}}); + histos.add("FT0/timeACbcE", "time bcE ; A (ns); C (ns)", {HistType::kTH2F, {{300, -15, 15}, {300, -15, 15}}}); + histos.add("FT0/hTimeA", "FT0 time A; ns ; count", kTH1F, {axisTime}); + histos.add("FT0/hTimeC", "FT0 time C; ns ; count", kTH1F, {axisTime}); + histos.add("FT0/hCountsTimeA", "0 Dummy Time - 1 Valid Time ; Kind of Time; counts", kTH1F, {axisCounts}); + histos.add("FT0/hCountsTimeC", "0 Dummy Time - 1 Valid Time ; Kind of Time; counts", kTH1F, {axisCounts}); + histos.add("FT0/hCountsTime", "0 Dummy Time - 1 Valid Time ; Kind of Time; counts", kTH1F, {axisCounts}); + histos.add("FT0/hValidTimeAvsBC", "Valid Time A vs BC id;BC in FT0;valid time counts", kTH1F, {axisTrigger}); + histos.add("FT0/hInvTimeAvsBC", "Invalid Time A vs BC id;BC in FT0;invalid time counts", kTH1F, {axisTrigger}); + histos.add("FT0/hValidTimeCvsBC", "Valid Time C vs BC id;BC in FT0;valid time counts", kTH1F, {axisTrigger}); + histos.add("FT0/hInvTimeCvsBC", "Invalid Time C vs BC id;BC in FT0;invalid time counts", kTH1F, {axisTrigger}); + histos.add("FT0/hValidTimevsBC", "Valid Time vs BC id;BC in FT0;valid time counts", kTH1F, {axisTrigger}); + histos.add("FT0/hInvTimevsBC", "Invalid Time vs BC id;BC in FT0;invalid time counts", kTH1F, {axisTrigger}); + histos.add("FT0/hTimeForRate", "Counts by time in FT0;t (in seconds) in FT0; counts", kTH1F, {axisTimeRate}); + histos.add("FT0/hTimeForRateLeadingBC", "Counts by time in FT0;t (in seconds) in FT0; counts", kTH1F, {axisTimeRate}); + + histos.add("FV0/hCounts", "0 CountCentralFV0 - 1 CountPFPCentralFV0 - 2 CountPFPOutInFV0 - 3 CountPPCentralFV0 - 4 CountPPOutInFV0; Number; counts", kTH1F, {axisV0Counts}); + histos.add("FV0/bcOutTrigger", "Out trigger per BC (FV0);BC in V0; counts", kTH1F, {axisTrigger}); + histos.add("FV0/bcInTrigger", "In trigger per BC (FV0);BC in V0; counts", kTH1F, {axisTrigger}); + histos.add("FV0/bcSCenTrigger", "SCen trigger per BC (FV0);BC in V0; counts", kTH1F, {axisTrigger}); + histos.add("FV0/bcCenTrigger", "Central trigger per BC (FV0);BC in V0; counts", kTH1F, {axisTrigger}); + histos.add("FV0/bcCenTriggerPFPCentral", "Central trigger per BC (FV0) with PFP in central trigger;BC in V0; counts", kTH1F, {axisTrigger}); + histos.add("FV0/bcCenTriggerPPCentral", "Central trigger per BC (FV0) with PP in central trigger;BC in V0; counts", kTH1F, {axisTrigger}); + histos.add("FV0/bcCenTriggerPFPOutIn", "Central trigger per BC (FV0) with PFP in Out and In trigger;BC in V0; counts", kTH1F, {axisTrigger}); + histos.add("FV0/bcCenTriggerPPOutIn", "Central trigger per BC (FV0) with PP in Out and In trigger;BC in V0; counts", kTH1F, {axisTrigger}); + histos.add("FV0/hBcA", "BC pattern A in FV0; BC in FV0 ; It is present", kTH1F, {axisTrigger}); + histos.add("FV0/hBcC", "BC pattern C in FV0; BC in FV0 ; It is present", kTH1F, {axisTrigger}); + histos.add("FV0/hBcB", "BC pattern B in FV0; BC in FV0 ; It is present", kTH1F, {axisTrigger}); + histos.add("FV0/hBcE", "BC pattern Empty in FV0; BC in FV0 ; It is present", kTH1F, {axisTrigger}); + histos.add("FV0/timeAbcB", "time bcB ; A (ns)", kTH1F, {{300, -15, 15}}); + histos.add("FV0/timeAbcA", "time bcA ; A (ns)", kTH1F, {{300, -15, 15}}); + histos.add("FV0/timeAbcC", "time bcC ; A (ns)", kTH1F, {{300, -15, 15}}); + histos.add("FV0/timeAbcE", "time bcE ; A (ns)", kTH1F, {{300, -15, 15}}); } bool checkAnyCoincidence(const std::vector& channels) { - std::map channelPairs = {{0, 4}, {1, 5}, {2, 6}, {4, 7}}; - for (const auto& pair : channelPairs) { + constexpr std::pair kPair0 = {0, 4}; + constexpr std::pair kPair1 = {1, 5}; + constexpr std::pair kPair2 = {2, 6}; + constexpr std::pair kPair3 = {3, 7}; + constexpr std::array, 4> kChannelPairs = {kPair0, kPair1, kPair2, kPair3}; + // std::map kChannelPairs = {{0, 4}, {1, 5}, {2, 6}, {3, 7}}; + for (const auto& pair : kChannelPairs) { if (std::find(channels.begin(), channels.end(), pair.first) != channels.end() && std::find(channels.begin(), channels.end(), pair.second) != channels.end()) { return true; @@ -75,31 +231,128 @@ struct lumiStabilityTask { return false; } - void processFDDFT0(aod::FT0s const& ft0s, aod::FDDs const& fdds, aod::BCsWithTimestamps const&) + void processMain(aod::FDDs const& fdds, aod::FT0s const& ft0s, aod::FV0As const& fv0s, aod::BCsWithTimestamps const& bcs) { + int executionCounter = 0; + int nbin = o2::constants::lhc::LHCMaxBunches; + uint32_t nOrbitsPerTF = 0; // 128 in 2022, 32 in 2023 + if (is2022Data) { + nOrbitsPerTF = 128; // 128 in 2022, 32 in 2023 + } else { + nOrbitsPerTF = 32; // 128 in 2022, 32 in 2023 + } + int runNumber = bcs.iteratorAt(0).runNumber(); + if (runNumber != lastRunNumber && executionCounter < 1) { + tsSOR = 0; + tsEOR = 1; + lastRunNumber = runNumber; // do it only once + executionCounter++; + + if (runNumber >= 500000) { // access CCDB for data or anchored MC only + int64_t ts = bcs.iteratorAt(0).timestamp(); + + // access colliding and beam-gas bc patterns + auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", ts); + beamPatternA = grplhcif->getBunchFilling().getBeamPattern(0); + beamPatternC = grplhcif->getBunchFilling().getBeamPattern(1); + bcPatternA = beamPatternA & ~beamPatternC; + bcPatternC = ~beamPatternA & beamPatternC; + bcPatternB = beamPatternA & beamPatternC; + bcPatternE = ~beamPatternA & ~beamPatternC; + + for (int i = 0; i < nBCsPerOrbit; i++) { + if (bcPatternA[i]) { + histos.fill(HIST("hBcA"), i); + } + if (bcPatternC[i]) { + histos.fill(HIST("hBcC"), i); + } + if (bcPatternB[i]) { + histos.fill(HIST("hBcB"), i); + bool isLeadBC = true; + for (int jbit = i - minEmpty; jbit < i; jbit++) { + int kbit = jbit; + if (kbit < 0) + kbit += nbin; + if (bcPatternB[kbit]) { + isLeadBC = false; + break; + } + } + if (isLeadBC) + histos.fill(HIST("hBcBL"), i); + } + if (bcPatternE[i]) { + histos.fill(HIST("hBcE"), i); + } + } + + EventSelectionParams* par = ccdb->getForTimeStamp("EventSelection/EventSelectionParams", ts); + // access orbit-reset timestamp + auto ctpx = ccdb->getForTimeStamp>("CTP/Calib/OrbitReset", ts); + int64_t tsOrbitReset = (*ctpx)[0]; // us + // access TF duration, start-of-run and end-of-run timestamps from ECS GRP + std::map metadata; + metadata["runNumber"] = Form("%d", runNumber); + auto grpecs = ccdb->getSpecific("GLO/Config/GRPECS", ts, metadata); + nOrbitsPerTF = grpecs->getNHBFPerTF(); // assuming 1 orbit = 1 HBF; nOrbitsPerTF=128 in 2022, 32 in 2023 + tsSOR = grpecs->getTimeStart(); // ms + tsEOR = grpecs->getTimeEnd(); // ms + // calculate SOR and EOR orbits + int64_t orbitSOR = (tsSOR * 1000 - tsOrbitReset) / o2::constants::lhc::LHCOrbitMUS; + int64_t orbitEOR = (tsEOR * 1000 - tsOrbitReset) / o2::constants::lhc::LHCOrbitMUS; + // adjust to the nearest TF edge + orbitSOR = orbitSOR / nOrbitsPerTF * nOrbitsPerTF + par->fTimeFrameOrbitShift; + orbitEOR = orbitEOR / nOrbitsPerTF * nOrbitsPerTF + par->fTimeFrameOrbitShift; + // set nOrbits and minOrbit used for orbit-axis binning + nOrbits = orbitEOR - orbitSOR; + minOrbit = orbitSOR; + // first bc of the first orbit (should coincide with TF start) + bcSOR = orbitSOR * o2::constants::lhc::LHCMaxBunches; + // duration of TF in bcs + nBCsPerTF = nOrbitsPerTF * o2::constants::lhc::LHCMaxBunches; + LOGP(info, "tsOrbitReset={} us, SOR = {} ms, EOR = {} ms, orbitSOR = {}, nBCsPerTF = {}", tsOrbitReset, tsSOR, tsEOR, orbitSOR, nBCsPerTF); + + auto hTsValues = histos.get(HIST("tsValues")); + hTsValues->GetXaxis()->SetBinLabel(1, "tsSOR"); + hTsValues->GetXaxis()->SetBinLabel(2, "tsEOR"); + hTsValues->SetBinContent(1, tsSOR / 1000); // seconds + hTsValues->SetBinContent(2, tsEOR / 1000); // seconds + } + + // create orbit-axis histograms on the fly with binning based on info from GRP if GRP is available + // otherwise default minOrbit and nOrbits will be used + // const AxisSpec axisOrbits{static_cast(nOrbits / nOrbitsPerTF), 0., static_cast(nOrbits), ""}; + // histos.add("hOrbitFDDVertexCoinc", "", kTH1F, {axisOrbits}); + // histos.add("hOrbitFDDVertex", "", kTH1F, {axisOrbits}); + // histos.add("hOrbitFT0vertex", "", kTH1F, {axisOrbits}); + // histos.add("hOrbitFV0Central", "", kTH1F, {axisOrbits}); + } + for (auto const& fdd : fdds) { auto bc = fdd.bc_as(); - if (bc.timestamp() == false) { + if (bc.timestamp() == 0) { continue; } - Long64_t globalBC = bc.globalBC(); + int64_t globalBC = bc.globalBC(); int localBC = globalBC % nBCsPerOrbit; + uint64_t orbit = globalBC / nBCsPerOrbit; std::bitset<8> fddTriggers = fdd.triggerMask(); bool vertex = fddTriggers[o2::fdd::Triggers::bitVertex]; bool scentral = fddTriggers[o2::fdd::Triggers::bitSCen]; bool central = fddTriggers[o2::fdd::Triggers::bitCen]; - auto SideA = fdd.chargeA(); - auto SideC = fdd.chargeC(); + auto sideA = fdd.chargeA(); + auto sideC = fdd.chargeC(); std::vector channelA; std::vector channelC; for (auto i = 0; i < 8; i++) { - if (SideA[i] > 0) { + if (sideA[i] > 0) { channelA.push_back(i); } - if (SideC[i] > 0) { + if (sideC[i] > 0) { channelC.push_back(i); } } @@ -107,11 +360,223 @@ struct lumiStabilityTask { bool isCoinA = checkAnyCoincidence(channelA); bool isCoinC = checkAnyCoincidence(channelC); + histos.fill(HIST("FDD/hCounts"), 0); if (vertex) { histos.fill(HIST("FDD/bcVertexTrigger"), localBC); + histos.fill(HIST("FDD/hCounts"), 1); + histos.fill(HIST("hOrbitFDDVertex"), orbit - minOrbit); + + if (bcPatternB[localBC]) { + histos.fill(HIST("FDD/hTimeForRate"), (bc.timestamp() - tsSOR) * 1.e-3); // Converting ms into seconds + bool isLeadBC = true; + for (int jbit = localBC - minEmpty; jbit < localBC; jbit++) { + int kbit = jbit; + if (kbit < 0) + kbit += nbin; + if (bcPatternB[kbit]) { + isLeadBC = false; + break; + } + } + if (isLeadBC) + histos.fill(HIST("FDD/hTimeForRateLeadingBC"), (bc.timestamp() - tsSOR) * 1.e-3); + } + + int deltaIndex = 0; // backward move counts + int deltaBC = 0; // current difference wrt globalBC + bool pastActivityFDDVertex = false; + while (deltaBC < myMaxDeltaBCFDD) { + deltaIndex++; + if (fdd.globalIndex() - deltaIndex < 0) { + break; + } + const auto& fddPast = fdds.iteratorAt(fdd.globalIndex() - deltaIndex); + auto bcPast = fddPast.bc_as(); + deltaBC = globalBC - bcPast.globalBC(); + + if (deltaBC < myMaxDeltaBCFDD) { + std::bitset<8> fddTriggersPast = fddPast.triggerMask(); + bool vertexPast = fddTriggersPast[o2::fdd::Triggers::bitVertex]; + pastActivityFDDVertex |= (vertexPast); + } + } + deltaIndex = 0; + deltaBC = 0; + + if (pastActivityFDDVertex == false) { + histos.fill(HIST("FDD/hCounts"), 2); + histos.fill(HIST("FDD/bcVertexTriggerPP"), localBC); + if (bcPatternA[localBC]) { + histos.fill(HIST("FDD/timeACbcAVertex"), fdd.timeA(), fdd.timeC()); + histos.fill(HIST("FDD/hBcAVertex"), localBC); + } + if (bcPatternC[localBC]) { + histos.fill(HIST("FDD/timeACbcCVertex"), fdd.timeA(), fdd.timeC()); + histos.fill(HIST("FDD/hBcCVertex"), localBC); + } + if (bcPatternB[localBC]) { + histos.fill(HIST("FDD/timeACbcBVertex"), fdd.timeA(), fdd.timeC()); + histos.fill(HIST("FDD/hBcBVertex"), localBC); + bool isLeadBC = true; + for (int jbit = localBC - minEmpty; jbit < localBC; jbit++) { + int kbit = jbit; + if (kbit < 0) + kbit += nbin; + if (bcPatternB[kbit]) { + isLeadBC = false; + break; + } + } + if (isLeadBC) + histos.fill(HIST("FDD/hBcBVertexL"), localBC); + histos.fill(HIST("FDD/hTimeAVertex"), fdd.timeA()); + histos.fill(HIST("FDD/hTimeCVertex"), fdd.timeC()); + if (is2022Data) { + if (fdd.timeA() > 30) { + histos.fill(HIST("FDD/hCountsTimeA2022"), 0); + histos.fill(HIST("FDD/hInvTimeAvsBC2022"), localBC); + } else { + histos.fill(HIST("FDD/hCountsTimeA2022"), 1); + histos.fill(HIST("FDD/hValidTimeAvsBC2022"), localBC); + } + + if (fdd.timeC() > 30) { + histos.fill(HIST("FDD/hCountsTimeC2022"), 0); + histos.fill(HIST("FDD/hInvTimeCvsBC2022"), localBC); + } else { + histos.fill(HIST("FDD/hCountsTimeC2022"), 1); + histos.fill(HIST("FDD/hValidTimeCvsBC2022"), localBC); + } + + if (fdd.timeA() > 30 || fdd.timeC() > 30) { + histos.fill(HIST("FDD/hCountsTime2022"), 0); + histos.fill(HIST("FDD/hInvTimevsBC2022"), localBC); + } + if (fdd.timeA() < 30 && fdd.timeC() < 30) { + histos.fill(HIST("FDD/hCountsTime2022"), 1); + histos.fill(HIST("FDD/hValidTimevsBC2022"), localBC); + } + } + } + if (bcPatternE[localBC]) { + histos.fill(HIST("FDD/timeACbcEVertex"), fdd.timeA(), fdd.timeC()); + histos.fill(HIST("FDD/hBcEVertex"), localBC); + } + } + if (isCoinA && isCoinC) { histos.fill(HIST("FDD/bcVertexTriggerCoincidence"), localBC); - } + histos.fill(HIST("FDD/hCounts"), 3); + histos.fill(HIST("hOrbitFDDVertexCoinc"), orbit - minOrbit); + + if (bcPatternA[localBC]) { + histos.fill(HIST("FDD/timeACbcA"), fdd.timeA(), fdd.timeC()); + histos.fill(HIST("FDD/hBcA"), localBC); + } + if (bcPatternC[localBC]) { + histos.fill(HIST("FDD/timeACbcC"), fdd.timeA(), fdd.timeC()); + histos.fill(HIST("FDD/hBcC"), localBC); + } + if (bcPatternB[localBC]) { + histos.fill(HIST("FDD/timeACbcB"), fdd.timeA(), fdd.timeC()); + histos.fill(HIST("FDD/hBcB"), localBC); + bool isLeadBC = true; + for (int jbit = localBC - minEmpty; jbit < localBC; jbit++) { + int kbit = jbit; + if (kbit < 0) + kbit += nbin; + if (bcPatternB[kbit]) { + isLeadBC = false; + break; + } + } + if (isLeadBC) + histos.fill(HIST("FDD/hBcBL"), localBC); + histos.fill(HIST("FDD/hTimeACoinc"), fdd.timeA()); + histos.fill(HIST("FDD/hTimeCCoinc"), fdd.timeC()); + if (!is2022Data) { + if (fdd.timeA() > 30) { + histos.fill(HIST("FDD/hCountsTimeA"), 0); + histos.fill(HIST("FDD/hInvTimeAvsBC"), localBC); + } else { + histos.fill(HIST("FDD/hCountsTimeA"), 1); + histos.fill(HIST("FDD/hValidTimeAvsBC"), localBC); + } + + if (fdd.timeC() > 30) { + histos.fill(HIST("FDD/hCountsTimeC"), 0); + histos.fill(HIST("FDD/hInvTimeCvsBC"), localBC); + } else { + histos.fill(HIST("FDD/hCountsTimeC"), 1); + histos.fill(HIST("FDD/hValidTimeCvsBC"), localBC); + } + + if (fdd.timeA() > 30 || fdd.timeC() > 30) { + histos.fill(HIST("FDD/hCountsTime"), 0); + histos.fill(HIST("FDD/hInvTimevsBC"), localBC); + } + if (fdd.timeA() < 30 && fdd.timeC() < 30) { + histos.fill(HIST("FDD/hCountsTime"), 1); + histos.fill(HIST("FDD/hValidTimevsBC"), localBC); + } + } + } + if (bcPatternE[localBC]) { + histos.fill(HIST("FDD/timeACbcE"), fdd.timeA(), fdd.timeC()); + histos.fill(HIST("FDD/hBcE"), localBC); + } + + int deltaIndex = 0; // backward move counts + int deltaBC = 0; // current difference wrt globalBC + bool pastActivityFDDVertexCoincidences = false; + bool pastActivityFDDTriggerACoincidenceA = false; + bool pastActivityFDDTriggerCCoincidenceC = false; + while (deltaBC < myMaxDeltaBCFDD) { + deltaIndex++; + if (fdd.globalIndex() - deltaIndex < 0) { + break; + } + const auto& fddPast = fdds.iteratorAt(fdd.globalIndex() - deltaIndex); + auto bcPast = fddPast.bc_as(); + deltaBC = globalBC - bcPast.globalBC(); + + if (deltaBC < myMaxDeltaBCFDD) { + std::bitset<8> fddTriggersPast = fddPast.triggerMask(); + bool vertexPast = fddTriggersPast[o2::fdd::Triggers::bitVertex]; + bool triggerAPast = fddTriggersPast[o2::fdd::Triggers::bitA]; + bool triggerCPast = fddTriggersPast[o2::fdd::Triggers::bitC]; + auto sideAPast = fddPast.chargeA(); + auto sideCPast = fddPast.chargeC(); + std::vector channelAPast; + std::vector channelCPast; + for (auto i = 0; i < 8; i++) { + if (sideAPast[i] > 0) { + channelAPast.push_back(i); + } + if (sideCPast[i] > 0) { + channelCPast.push_back(i); + } + } + + bool isCoinAPast = checkAnyCoincidence(channelAPast); + bool isCoinCPast = checkAnyCoincidence(channelCPast); + pastActivityFDDVertexCoincidences |= (vertexPast & isCoinAPast & isCoinCPast); + pastActivityFDDTriggerACoincidenceA |= (triggerAPast & isCoinAPast); + pastActivityFDDTriggerCCoincidenceC |= (triggerCPast & isCoinCPast); + } + } + deltaIndex = 0; + deltaBC = 0; + + if (pastActivityFDDVertexCoincidences == false) { + histos.fill(HIST("FDD/hCounts"), 4); + histos.fill(HIST("FDD/bcVertexTriggerCoincidencePP"), localBC); + } + if (pastActivityFDDTriggerACoincidenceA == false || pastActivityFDDTriggerCCoincidenceC == false) { + histos.fill(HIST("FDD/hCounts"), 5); + histos.fill(HIST("FDD/bcVertexTriggerBothSidesCoincidencePP"), localBC); + } + } // coincidences } // vertex true if (scentral) { @@ -141,26 +606,125 @@ struct lumiStabilityTask { histos.fill(HIST("FDD/bcVCTriggerCoincidence"), localBC); } } // vertex and scentral true - } // loop over FDD events + } // loop over FDD events for (auto const& ft0 : ft0s) { auto bc = ft0.bc_as(); - if (bc.timestamp() == false) { + if (bc.timestamp() == 0) { continue; } - Long64_t globalBC = bc.globalBC(); + int64_t globalBC = bc.globalBC(); int localBC = globalBC % nBCsPerOrbit; + uint64_t orbit = globalBC / nBCsPerOrbit; std::bitset<8> fT0Triggers = ft0.triggerMask(); - bool vertex = fT0Triggers[o2::fdd::Triggers::bitVertex]; + bool vertex = fT0Triggers[o2::ft0::Triggers::bitVertex]; + bool sCentral = fT0Triggers[o2::ft0::Triggers::bitSCen]; + bool central = fT0Triggers[o2::ft0::Triggers::bitCen]; + histos.fill(HIST("FT0/hCounts"), 0); if (vertex) { histos.fill(HIST("FT0/bcVertexTrigger"), localBC); - } // vertex true + histos.fill(HIST("hOrbitFT0vertex"), orbit - minOrbit); + + if (bcPatternA[localBC]) { + histos.fill(HIST("FT0/timeACbcA"), ft0.timeA(), ft0.timeC()); + histos.fill(HIST("FT0/hBcA"), localBC); + } + if (bcPatternC[localBC]) { + histos.fill(HIST("FT0/timeACbcC"), ft0.timeA(), ft0.timeC()); + histos.fill(HIST("FT0/hBcC"), localBC); + } + if (bcPatternB[localBC]) { + histos.fill(HIST("FT0/timeACbcB"), ft0.timeA(), ft0.timeC()); + histos.fill(HIST("FT0/hBcB"), localBC); + histos.fill(HIST("FT0/hTimeForRate"), (bc.timestamp() - tsSOR) * 1.e-3); // Converting ms into seconds + bool isLeadBC = true; + for (int jbit = localBC - minEmpty; jbit < localBC; jbit++) { + int kbit = jbit; + if (kbit < 0) + kbit += nbin; + if (bcPatternB[kbit]) { + isLeadBC = false; + break; + } + } + if (isLeadBC) { + histos.fill(HIST("FT0/hTimeForRateLeadingBC"), (bc.timestamp() - tsSOR) * 1.e-3); // Converting ms into seconds + histos.fill(HIST("FT0/hBcBL"), localBC); + } + histos.fill(HIST("FT0/hTimeA"), ft0.timeA()); + histos.fill(HIST("FT0/hTimeC"), ft0.timeC()); + + if (ft0.timeA() > 30) { + histos.fill(HIST("FT0/hCountsTimeA"), 0); + histos.fill(HIST("FT0/hInvTimeAvsBC"), localBC); + } else { + histos.fill(HIST("FT0/hCountsTimeA"), 1); + histos.fill(HIST("FT0/hValidTimeAvsBC"), localBC); + } + + if (ft0.timeC() > 30) { + histos.fill(HIST("FT0/hCountsTimeC"), 0); + histos.fill(HIST("FT0/hInvTimeCvsBC"), localBC); + } else { + histos.fill(HIST("FT0/hCountsTimeC"), 1); + histos.fill(HIST("FT0/hValidTimeCvsBC"), localBC); + } + + if (ft0.timeA() > 30 || ft0.timeC() > 30) { + histos.fill(HIST("FT0/hCountsTime"), 0); + histos.fill(HIST("FT0/hInvTimevsBC"), localBC); + } + if (ft0.timeA() < 30 && ft0.timeC() < 30) { + histos.fill(HIST("FT0/hCountsTime"), 1); + histos.fill(HIST("FT0/hValidTimevsBC"), localBC); + } + } + if (bcPatternE[localBC]) { + histos.fill(HIST("FT0/timeACbcE"), ft0.timeA(), ft0.timeC()); + histos.fill(HIST("FT0/hBcE"), localBC); + } + + int deltaIndex = 0; // backward move counts + int deltaBC = 0; // current difference wrt globalBC + bool pastActivityFT0Vertex = false; + bool pastActivityFT0TriggerA = false; + bool pastActivityFT0TriggerC = false; + while (deltaBC < myMaxDeltaBCFT0) { + deltaIndex++; + if (ft0.globalIndex() - deltaIndex < 0) { + break; + } + const auto& ft0Past = ft0s.iteratorAt(ft0.globalIndex() - deltaIndex); + auto bcPast = ft0Past.bc_as(); + deltaBC = globalBC - bcPast.globalBC(); + + if (deltaBC < myMaxDeltaBCFT0) { + std::bitset<8> fT0TriggersPast = ft0Past.triggerMask(); + bool vertexPast = fT0TriggersPast[o2::ft0::Triggers::bitVertex]; + bool triggerAPast = fT0TriggersPast[o2::ft0::Triggers::bitA]; + bool triggerCPast = fT0TriggersPast[o2::ft0::Triggers::bitC]; + + pastActivityFT0Vertex |= vertexPast; + pastActivityFT0TriggerA |= triggerAPast; + pastActivityFT0TriggerC |= triggerCPast; + } + } + deltaIndex = 0; + deltaBC = 0; - bool sCentral = fT0Triggers[o2::fdd::Triggers::bitSCen]; - bool central = fT0Triggers[o2::fdd::Triggers::bitCen]; + histos.fill(HIST("FT0/hCounts"), 1); + if (pastActivityFT0Vertex == false) { + histos.fill(HIST("FT0/hCounts"), 2); + histos.fill(HIST("FT0/bcVertexTriggerPP"), localBC); + } + if (pastActivityFT0TriggerA == false || pastActivityFT0TriggerC == false) { + histos.fill(HIST("FT0/hCounts"), 3); + histos.fill(HIST("FT0/bcVertexTriggerBothSidesPP"), localBC); + } + } // vertex true if (sCentral) { histos.fill(HIST("FT0/bcSCentralTrigger"), localBC); @@ -179,26 +743,22 @@ struct lumiStabilityTask { } } } // loop over FT0 events - } // end processFDDFT0 - PROCESS_SWITCH(lumiStabilityTask, processFDDFT0, "Process FDD and FT0 to lumi stability analysis", true); - - void processV0(aod::FV0As const& fv0s, aod::BCsWithTimestamps const&) - { for (auto const& fv0 : fv0s) { auto bc = fv0.bc_as(); - if (bc.timestamp() == false) { + if (bc.timestamp() == 0) { continue; } - Long64_t globalBC = bc.globalBC(); + int64_t globalBC = bc.globalBC(); int localBC = globalBC % nBCsPerOrbit; + uint64_t orbit = globalBC / nBCsPerOrbit; std::bitset<8> fv0Triggers = fv0.triggerMask(); - bool aOut = fv0Triggers[o2::fdd::Triggers::bitAOut]; - bool aIn = fv0Triggers[o2::fdd::Triggers::bitAIn]; - bool aSCen = fv0Triggers[o2::fdd::Triggers::bitTrgNchan]; - bool aCen = fv0Triggers[o2::fdd::Triggers::bitTrgCharge]; + bool aOut = fv0Triggers[o2::fv0::Triggers::bitAOut]; + bool aIn = fv0Triggers[o2::fv0::Triggers::bitAIn]; + bool aSCen = fv0Triggers[o2::fv0::Triggers::bitTrgNchan]; + bool aCen = fv0Triggers[o2::fv0::Triggers::bitTrgCharge]; if (aOut) { histos.fill(HIST("FV0/bcOutTrigger"), localBC); @@ -213,19 +773,119 @@ struct lumiStabilityTask { } if (aCen) { + histos.fill(HIST("hOrbitFV0Central"), orbit - minOrbit); histos.fill(HIST("FV0/bcCenTrigger"), localBC); - if (aSCen) { - histos.fill(HIST("FV0/bcSCenCenTrigger"), localBC); + + if (bcPatternA[localBC]) { + histos.fill(HIST("FV0/timeAbcA"), fv0.time()); + histos.fill(HIST("FV0/hBcA"), localBC); + } + if (bcPatternC[localBC]) { + histos.fill(HIST("FV0/timeAbcC"), fv0.time()); + histos.fill(HIST("FV0/hBcC"), localBC); + } + if (bcPatternB[localBC]) { + histos.fill(HIST("FV0/timeAbcB"), fv0.time()); + histos.fill(HIST("FV0/hBcB"), localBC); + } + if (bcPatternE[localBC]) { + histos.fill(HIST("FV0/timeAbcE"), fv0.time()); + histos.fill(HIST("FV0/hBcE"), localBC); + } + + int deltaIndex = 0; // backward move counts + int deltaBC = 0; // current difference wrt globalBC + bool pastActivityFV0Cen = false; + bool pastActivityFV0TriggerOut = false; + bool pastActivityFV0TriggerIn = false; + while (deltaBC < myMaxDeltaBCFV0) { + deltaIndex++; + if (fv0.globalIndex() - deltaIndex < 0) { + break; + } + const auto& fv0Past = fv0s.iteratorAt(fv0.globalIndex() - deltaIndex); + auto bcPast = fv0Past.bc_as(); + deltaBC = globalBC - bcPast.globalBC(); + + if (deltaBC < myMaxDeltaBCFV0) { + std::bitset<8> fv0Triggers = fv0Past.triggerMask(); + bool centralPast = fv0Triggers[o2::fv0::Triggers::bitTrgCharge]; + bool triggerOutPast = fv0Triggers[o2::fv0::Triggers::bitAOut]; + bool triggerInPast = fv0Triggers[o2::fv0::Triggers::bitAIn]; + + pastActivityFV0Cen |= centralPast; + pastActivityFV0TriggerOut |= triggerOutPast; + pastActivityFV0TriggerIn |= triggerInPast; + } + } + deltaIndex = 0; + deltaBC = 0; + + bool futureActivityFV0Cen = false; + bool futureActivityFV0TriggerOut = false; + bool futureActivityFV0TriggerIn = false; + while (deltaBC < myMaxDeltaBCFV0) { + deltaIndex++; + if (fv0.globalIndex() + deltaIndex >= fv0s.size()) { + break; + } + const auto& fv0Future = fv0s.iteratorAt(fv0.globalIndex() + deltaIndex); + deltaBC = fv0Future.bcId() - fv0.bcId(); + + if (deltaBC < myMaxDeltaBCFV0) { + std::bitset<8> fv0Triggers = fv0Future.triggerMask(); + bool centralFuture = fv0Triggers[o2::fv0::Triggers::bitTrgCharge]; + bool triggerOutFuture = fv0Triggers[o2::fv0::Triggers::bitAOut]; + bool triggerInFuture = fv0Triggers[o2::fv0::Triggers::bitAIn]; + + futureActivityFV0Cen |= centralFuture; + futureActivityFV0TriggerOut |= triggerOutFuture; + futureActivityFV0TriggerIn |= triggerInFuture; + } + } + + histos.fill(HIST("FV0/hCounts"), 0); + if ((pastActivityFV0TriggerOut || futureActivityFV0TriggerOut) == true || (pastActivityFV0TriggerIn || futureActivityFV0TriggerIn) == true) { + histos.fill(HIST("FV0/hCounts"), 2); + } else { + histos.fill(HIST("FV0/bcCenTriggerPFPOutIn"), localBC); + } + if (pastActivityFV0TriggerOut == true || pastActivityFV0TriggerIn == true) { + histos.fill(HIST("FV0/hCounts"), 4); + } else { + histos.fill(HIST("FV0/bcCenTriggerPPOutIn"), localBC); + } + if (pastActivityFV0Cen == true || futureActivityFV0Cen == true) { + histos.fill(HIST("FV0/hCounts"), 1); + } else { + histos.fill(HIST("FV0/bcCenTriggerPFPCentral"), localBC); + } + if (pastActivityFV0Cen == true) { + histos.fill(HIST("FV0/hCounts"), 3); + } else { + histos.fill(HIST("FV0/bcCenTriggerPPCentral"), localBC); } } } // loop over V0 events - } // end processV0 + } // end processMain + + PROCESS_SWITCH(LumiStabilityTask, processMain, "Process FDD and FT0 to lumi stability analysis", true); + + void processCollisions(aod::Collision const& collision) + { + histos.fill(HIST("hvertexX"), collision.posX()); + histos.fill(HIST("hvertexY"), collision.posY()); + histos.fill(HIST("hvertexZ"), collision.posZ()); + histos.fill(HIST("hnumContrib"), collision.numContrib()); + histos.fill(HIST("hcollisinTime"), collision.collisionTime()); + histos.fill(HIST("hvertexXvsTime"), collision.posX(), collision.collisionTime()); + } - PROCESS_SWITCH(lumiStabilityTask, processV0, "Process V0 to lumi stability analysis", true); + PROCESS_SWITCH(LumiStabilityTask, processCollisions, "Process collision to get vertex position", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGMM/Mult/Core/include/Functions.h b/PWGMM/Mult/Core/include/Functions.h index 4cd59894184..00d1ef0ee2a 100644 --- a/PWGMM/Mult/Core/include/Functions.h +++ b/PWGMM/Mult/Core/include/Functions.h @@ -11,31 +11,191 @@ #ifndef PWGMM_MULT_CORE_INCLUDE_FUNCTIONS_H_ #define PWGMM_MULT_CORE_INCLUDE_FUNCTIONS_H_ -#include "Common/DataModel/Centrality.h" namespace pwgmm::mult { -using namespace o2; +template +concept has_hepmc_xs = requires(MCC::iterator const& mcc) { + mcc.xsectGen(); +}; -// helper function to determine if collision/mccollison type contains centrality -template -static constexpr bool hasSimCent() +template +concept has_hepmc_pid = requires(MCC::iterator const& mcc) { + mcc.processId(); +}; + +template +concept has_hepmc_pdf = requires(MCC::iterator const& mcc) { + mcc.pdfId1(); + mcc.pdfId2(); +}; + +template +concept has_hepmc_hi = requires(MCC::iterator const& mcc) { + mcc.ncollHard(); + mcc.ncoll(); +}; + +template +concept has_FT0C = requires(C::iterator const& c) { + c.centFT0C(); +}; + +template +concept iterator_with_FT0C = requires(IC const& c) { + c.centFT0C(); +}; + +template +concept has_centFT0CVariant1 = requires(C::iterator const& c) { + c.centFT0CVariant1(); +}; + +template +concept iterator_with_centFT0CVariant1 = requires(IC const& c) { + c.centFT0CVariant1(); +}; + +template +concept has_FT0M = requires(C::iterator const& c) { + c.centFT0M(); +}; + +template +concept iterator_with_FT0M = requires(IC const& c) { + c.centFT0M(); +}; + +template +concept has_centNGlobal = requires(C::iterator const& c) { + c.centNGlobal(); +}; + +template +concept iterator_with_centNGlobal = requires(IC const& c) { + c.centNGlobal(); +}; + +template +concept has_centMFT = requires(C::iterator const& c) { + c.centMFT(); +}; + +template +concept iterator_with_centMFT = requires(IC const& c) { + c.centMFT(); +}; + +template +concept has_genFT0C = requires(C::iterator const& c) { + c.gencentFT0C(); +}; + +template +concept has_genFT0M = requires(C::iterator const& c) { + c.gencentFT0M(); +}; + +template +concept iterator_with_genFT0C = requires(C const& c) { + c.gencentFT0C(); +}; + +template +concept iterator_with_genFT0M = requires(C const& c) { + c.gencentFT0M(); +}; + +template +concept has_reco_cent = has_FT0C || has_centFT0CVariant1 || has_FT0M || has_centNGlobal || has_centMFT; + +template +concept has_gen_cent = has_genFT0C && has_genFT0M; + +template +concept has_Centrality = requires(MCC::iterator const& mcc) { + mcc.centrality(); +}; + +template +concept iterator_with_Centrality = requires(MCC const& mcc) { + mcc.centrality(); +}; + +template + requires(!(iterator_with_FT0C || iterator_with_centFT0CVariant1 || iterator_with_FT0M || iterator_with_centNGlobal || iterator_with_centMFT)) +static float getRecoCent(C const&) +{ + return -1; +} + +template +static float getRecoCent(C const& collision) +{ + return collision.centFT0C(); +} + +template +static float getRecoCent(C const& collision) +{ + return collision.centFT0CVariant1(); +} + +template +static float getRecoCent(C const& collision) +{ + return collision.centFT0M(); +} + +template +static float getRecoCent(C const& collision) +{ + return collision.centNGlobal(); +} + +template +static float getRecoCent(C const& collision) +{ + return collision.centMFT(); +} + +template + requires(!iterator_with_genFT0C) +static float getGenCentFT0C(MCC const&) +{ + return -1; +} + +template + requires(!iterator_with_genFT0M) +static float getGenCentFT0M(MCC const&) +{ + return -1; +} + +template +static float getGenCentFT0C(MCC const& mccollision) +{ + return mccollision.gencentFT0C(); +} + +template +static float getGenCentFT0M(MCC const& mccollision) +{ + return mccollision.gencentFT0M(); +} + +template + requires(!iterator_with_Centrality) +static float getSimCent(MCC const&) { - if constexpr (!soa::is_soa_join_v) { - return false; - } else { - return T::template contains(); - } + return -1; } -template -static constexpr bool hasRecoCent() +template +static float getSimCent(MCC const& mccollision) { - if constexpr (!soa::is_soa_join_v) { - return false; - } else { - return T::template contains() || T::template contains(); - } + return mccollision.centrality(); } } // namespace pwgmm::mult diff --git a/PWGMM/Mult/Core/include/Histograms.h b/PWGMM/Mult/Core/include/Histograms.h index d7155280ca0..2b41c9ecefe 100644 --- a/PWGMM/Mult/Core/include/Histograms.h +++ b/PWGMM/Mult/Core/include/Histograms.h @@ -12,6 +12,7 @@ #ifndef PWGMM_MULT_CORE_INCLUDE_HISTOGRAMS_H_ #define PWGMM_MULT_CORE_INCLUDE_HISTOGRAMS_H_ #include "TPDGCode.h" +#include #include namespace pwgmm::mult @@ -45,6 +46,9 @@ static constexpr std::string_view SplitMult = "Events/SplitMult"; static constexpr std::string_view EventChi2 = "Events/Control/Chi2"; // collisions chi2 distribution static constexpr std::string_view EventTimeRes = "Events/Control/TimeResolution"; // collisions time resolution distribution +static constexpr std::string_view NpvcZvtx = "Events/NpvcZvtx"; // N PV contributors vs vtx Z for selected collisions +static constexpr std::string_view NpvcZvxtGen = "Events/NpvcZvtxGen"; // -- simulated collisions + static constexpr std::string_view MCVertex = "MCEvents/Vertex"; // MC vertex position static constexpr std::string_view RecoVertex = "Events/Vertex"; // Reco vertex position static constexpr std::string_view MCCorrelates = "MCEvents/Properties/Correlates"; // Correlation of generated multiplicity and other event properties diff --git a/PWGMM/Mult/DataModel/CMakeLists.txt b/PWGMM/Mult/DataModel/CMakeLists.txt index 14fe4e618af..42f51846fda 100644 --- a/PWGMM/Mult/DataModel/CMakeLists.txt +++ b/PWGMM/Mult/DataModel/CMakeLists.txt @@ -10,4 +10,4 @@ # or submit itself to any jurisdiction. o2physics_add_header_only_library(MultDataModel - HEADERS ReducedTables.h) + HEADERS ReducedTables.h Gencentralities.h) diff --git a/PWGMM/Mult/DataModel/Gencentralities.h b/PWGMM/Mult/DataModel/Gencentralities.h new file mode 100644 index 00000000000..112072fa2c8 --- /dev/null +++ b/PWGMM/Mult/DataModel/Gencentralities.h @@ -0,0 +1,27 @@ +// 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. + +#ifndef PWGMM_MULT_DATAMODEL_GENCENTRALITIES_H_ +#define PWGMM_MULT_DATAMODEL_GENCENTRALITIES_H_ + +#include "Framework/AnalysisDataModel.h" +namespace o2::aod +{ +namespace gencents +{ +DECLARE_SOA_COLUMN(GenCentFT0C, gencentFT0C, float); +DECLARE_SOA_COLUMN(GenCentFT0M, gencentFT0M, float); +} // namespace gencents +DECLARE_SOA_TABLE(GenCents, "AOD", "GENCENT", + gencents::GenCentFT0C, + gencents::GenCentFT0M); +} // namespace o2::aod +#endif // PWGMM_MULT_DATAMODEL_GENCENTRALITIES_H_ diff --git a/PWGMM/Mult/DataModel/ReducedTables.h b/PWGMM/Mult/DataModel/ReducedTables.h index ed740b2fb91..fbdd68b89db 100644 --- a/PWGMM/Mult/DataModel/ReducedTables.h +++ b/PWGMM/Mult/DataModel/ReducedTables.h @@ -11,6 +11,8 @@ #ifndef PWGMM_MULT_DATAMODEL_REDUCEDTABLES_H_ #define PWGMM_MULT_DATAMODEL_REDUCEDTABLES_H_ +#include + #include "Framework/AnalysisDataModel.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Centrality.h" @@ -23,18 +25,14 @@ namespace o2::aod bc::RunNumber // Reduced BCs as a root index -DECLARE_SOA_TABLE(RBCs, "AOD", "RBC", - BCcols, - soa::Marker<1>); -DECLARE_SOA_TABLE(StoredRBCs, "AOD1", "RBC", - BCcols, - soa::Marker<2>); +DECLARE_SOA_TABLE_STAGED(RBCs, "RBC", + BCcols); namespace rcol { DECLARE_SOA_INDEX_COLUMN(RBC, rbc); DECLARE_SOA_COLUMN(MapEtaPhi, mapetaphi, std::vector); -} +} // namespace rcol #define Ccols o2::soa::Index<>, \ rcol::RBCId, \ @@ -61,19 +59,11 @@ DECLARE_SOA_COLUMN(MapEtaPhi, mapetaphi, std::vector); cent::CentNTPV // Reduced Collisions -DECLARE_SOA_TABLE(RCollisions, "AOD", "RCOLLISION", - Ccols, - soa::Marker<1>) -DECLARE_SOA_TABLE(StoredRCollisions, "AOD1", "RCOLLISION", - Ccols, - soa::Marker<2>) +DECLARE_SOA_TABLE_STAGED(RCollisions, "RCOLLISION", + Ccols) -DECLARE_SOA_TABLE(RCents, "AOD", "RCENTS", - CCcols, - soa::Marker<1>) -DECLARE_SOA_TABLE(StoredRCents, "AOD1", "RCENTS", - CCcols, - soa::Marker<2>) +DECLARE_SOA_TABLE_STAGED(RCents, "RCENTS", + CCcols) // Reduced tracks (is this needed?) namespace rtrack @@ -91,12 +81,8 @@ DECLARE_SOA_COLUMN(Weight, weight, float); track::DcaXY, \ track::DcaZ -DECLARE_SOA_TABLE(RTracks, "AOD", "RTRACK", - Tcols, - soa::Marker<1>) -DECLARE_SOA_TABLE(StoredRTracks, "AOD1", "RTRACK", - Tcols, - soa::Marker<2>) +DECLARE_SOA_TABLE_STAGED(RTracks, "RTRACK", + Tcols) #define TFcols o2::soa::Index<>, \ rtrack::RCollisionId, \ @@ -108,12 +94,8 @@ DECLARE_SOA_TABLE(StoredRTracks, "AOD1", "RTRACK", fwdtrack::FwdDcaX, \ fwdtrack::FwdDcaY -DECLARE_SOA_TABLE(RFTracks, "AOD", "RFTRACK", - TFcols, - soa::Marker<1>) -DECLARE_SOA_TABLE(StoredRFTracks, "AOD1", "RFTRACK", - TFcols, - soa::Marker<2>) +DECLARE_SOA_TABLE_STAGED(RFTracks, "RFTRACK", + TFcols) // Reduced MC collisions namespace rmccol @@ -132,12 +114,8 @@ DECLARE_SOA_COLUMN(Weight, weight, float); mult::MultMCNParticlesEta05, \ mult::MultMCNParticlesEta10 -DECLARE_SOA_TABLE(RMCCollisions, "AOD", "RMCCOLLISION", - MCCcols, - soa::Marker<1>) -DECLARE_SOA_TABLE(StoredRMCCollisions, "AOD1", "RMCCOLLISION", - MCCcols, - soa::Marker<2>) +DECLARE_SOA_TABLE_STAGED(RMCCollisions, "RMCCOLLISION", + MCCcols) // Extra MC tables namespace rhepmc @@ -159,12 +137,8 @@ DECLARE_SOA_INDEX_COLUMN(RMCCollision, rmccollison); hepmcpdfinfo::Pdf1, \ hepmcpdfinfo::Pdf2 -DECLARE_SOA_TABLE(RHepMCinfos, "AOD", "RHEPMCINFO", - HMCcols, - soa::Marker<1>); -DECLARE_SOA_TABLE(StoredRHepMCinfos, "AOD1", "RHEPMCINFO", - HMCcols, - soa::Marker<2>); +DECLARE_SOA_TABLE_STAGED(RHepMCinfos, "RHEPMCINFO", + HMCcols); #define HMCHIcols rhepmc::RMCCollisionId, \ hepmcheavyion::NcollHard, \ @@ -176,12 +150,8 @@ DECLARE_SOA_TABLE(StoredRHepMCinfos, "AOD1", "RHEPMCINFO", hepmcheavyion::SigmaInelNN, \ hepmcheavyion::Centrality -DECLARE_SOA_TABLE(RHepMCHIs, "AOD", "RHEPMCHI", - HMCHIcols, - soa::Marker<1>); -DECLARE_SOA_TABLE(StoredRHepMCHIs, "AOD1", "RHEPMCHI", - HMCHIcols, - soa::Marker<2>); +DECLARE_SOA_TABLE_STAGED(RHepMCHIs, "RHEPMCHI", + HMCHIcols); namespace rparticle { @@ -202,12 +172,8 @@ DECLARE_SOA_INDEX_COLUMN(RMCCollision, rmccollision); mcparticle::E, \ mcparticle::Weight -DECLARE_SOA_TABLE(RMCParticles, "AOD", "RMCPARTICLE", - RMCPcols, - soa::Marker<1>) -DECLARE_SOA_TABLE(StoredRMCParticles, "AOD1", "RMCPARTICLE", - RMCPcols, - soa::Marker<2>) +DECLARE_SOA_TABLE_STAGED(RMCParticles, "RMCPARTICLE", + RMCPcols) // label tables namespace rlabels @@ -215,15 +181,11 @@ namespace rlabels DECLARE_SOA_INDEX_COLUMN(RMCCollision, rmccollision); DECLARE_SOA_INDEX_COLUMN(RMCParticle, rmcparticle); } // namespace rlabels -DECLARE_SOA_TABLE(RMCTrackLabels, "AOD", "RMCTRKLABEL", - rlabels::RMCParticleId, soa::Marker<1>) -DECLARE_SOA_TABLE(StoredRMCTrackLabels, "AOD1", "RMCTRKLABEL", - rlabels::RMCParticleId, soa::Marker<2>) +DECLARE_SOA_TABLE_STAGED(RMCTrackLabels, "RMCTRKLABEL", + rlabels::RMCParticleId) -DECLARE_SOA_TABLE(RMCColLabels, "AOD", "RMCCOLLABEL", - rlabels::RMCCollisionId, soa::Marker<1>) -DECLARE_SOA_TABLE(StoredRMCColLabels, "AOD1", "RMCCOLLABEL", - rlabels::RMCCollisionId, soa::Marker<2>) +DECLARE_SOA_TABLE_STAGED(RMCColLabels, "RMCCOLLABEL", + rlabels::RMCCollisionId) namespace features { diff --git a/PWGMM/Mult/TableProducer/CMakeLists.txt b/PWGMM/Mult/TableProducer/CMakeLists.txt index f37c5f106ef..9b1ddb5e997 100644 --- a/PWGMM/Mult/TableProducer/CMakeLists.txt +++ b/PWGMM/Mult/TableProducer/CMakeLists.txt @@ -28,3 +28,8 @@ o2physics_add_dpl_workflow(track-propagation SOURCES trackPropagation.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsCommonDataFormats COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(percentiles + SOURCES percentiles.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGMM/Mult/TableProducer/percentiles.cxx b/PWGMM/Mult/TableProducer/percentiles.cxx new file mode 100644 index 00000000000..c11fca858f8 --- /dev/null +++ b/PWGMM/Mult/TableProducer/percentiles.cxx @@ -0,0 +1,236 @@ +// 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. +#include "Selections.h" + +#include +#include +#include +#include +#include "Common/DataModel/Centrality.h" +#include +#include +#include +#include + +#include "Gencentralities.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using namespace pwgmm::mult; + +constexpr float FT0Alo = -3.3; +constexpr float FT0Ahi = -2.1; +constexpr float FT0Clo = 3.5; +constexpr float FT0Chi = 4.9; + +struct Binner { + Service pdg; + Produces gencents; + HistogramRegistry h{"histograms", {}}; + + using Particles = soa::Filtered; + Preslice perMcCol = aod::mcparticle::mcCollisionId; + Preslice perCol = aod::track::collisionId; + + ConfigurableAxis multBinning{"multBinning", {302, -1.5, 300.5}, ""}; + ConfigurableAxis centBinning{"centBinning", {VARIABLE_WIDTH, 0, 1, 5, 10, 15, 20, 30, 40, 50, 70, 100}, ""}; + + // The objects are uploaded with https://alimonitor.cern.ch/ccdb/upload.jsp + Service ccdb; + Configurable path{"ccdb-path", "Users/a/aalkin/gencentralities", "base path to the ccdb object"}; + Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + bool isChargedParticle(int code) const + { + static auto p = pdg->GetParticle(code); + if (p == nullptr) { + return 0; + } + return std::abs(p->Charge()) >= 3.; + } + + template + static inline bool isCollisionSelectedMC(C const& collision) + { + return collision.selection_bit(aod::evsel::kIsTriggerTVX) && + collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && + collision.selection_bit(aod::evsel::kIsVertexITSTPC) && + collision.selection_bit(aod::evsel::kIsVertexTOFmatched); + } + + template + static inline bool isCollisionSelected(C const& collision) + { + return collision.selection_bit(aod::evsel::kIsTriggerTVX) && + collision.selection_bit(aod::evsel::kNoTimeFrameBorder) && + collision.selection_bit(aod::evsel::kNoITSROFrameBorder) && + collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && + collision.selection_bit(aod::evsel::kIsVertexITSTPC) && + collision.selection_bit(aod::evsel::kIsVertexTOFmatched); + } + + TH1F* multFT0C = nullptr; + TH1F* multFT0M = nullptr; + + void init(InitContext const&) + { + AxisSpec MultAxis = {multBinning}; + h.add({"hFT0M", "; N_{part} in FT0M acc", {HistType::kTH1F, {MultAxis}}}); + h.add({"hFT0C", "; N_{part} in FT0C acc", {HistType::kTH1F, {MultAxis}}}); + if (dobin) { + ccdb->setURL(url.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + } + if (docalibrateAdvanced) { + centBinning.value.insert(centBinning.value.begin() + 1, {-2}); + AxisSpec ExtraCentAxis = {centBinning}; + h.add({"hCorrelate", " ; N_{part}^{FT0M}; N_{part}^{FT0C}; N_{trk}^{#eta = 0}", {HistType::kTHnSparseF, {MultAxis, MultAxis, MultAxis, ExtraCentAxis}}}); + } + if (dogetData) { + AxisSpec CentAxis = {centBinning}; + h.add({"hTrkAt0vsFT0M", " ; N_{trk}^{#eta = 0}; FT0M percentile", {HistType::kTH2F, {MultAxis, CentAxis}}}); + } + } + + Filter primaries = ncheckbit(aod::mcparticle::flags, (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary); + Partition pFT0M = ((aod::mcparticle::eta > FT0Alo) && (aod::mcparticle::eta < FT0Ahi)) || ((aod::mcparticle::eta > FT0Clo) && (aod::mcparticle::eta < FT0Chi)); + Partition pFT0C = (aod::mcparticle::eta > FT0Clo) && (aod::mcparticle::eta < FT0Chi); + + void calibrate(aod::McCollisions const& mccollisions, Particles const&) + { + for (auto& mcc : mccollisions) { + auto pcFT0M = pFT0M.sliceBy(perMcCol, mcc.globalIndex()); + auto pcFT0C = pFT0C.sliceBy(perMcCol, mcc.globalIndex()); + int nFT0M = 0; + int nFT0C = 0; + for (auto& p : pcFT0M) { + if (isChargedParticle(p.pdgCode())) { + ++nFT0M; + } + } + h.fill(HIST("hFT0M"), nFT0M); + for (auto& p : pcFT0C) { + if (isChargedParticle(p.pdgCode())) { + ++nFT0C; + } + } + h.fill(HIST("hFT0C"), nFT0C); + } + } + + PROCESS_SWITCH(Binner, calibrate, "Create binnings", true); + + using ExColsMCFT0M = soa::Join; + using ExColsCentFT0M = soa::Join; + using Trks = soa::Join; + // require a mix of ITS+TPC and ITS-only tracks (filters on the same table are automatically combined with &&) + Filter fTrackSelectionITS = ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) && + ncheckbit(aod::track::trackCutFlag, trackSelectionITS); + Filter fTrackSelectionTPC = ifnode(ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC), + ncheckbit(aod::track::trackCutFlag, trackSelectionTPC), true); + Filter fTrackSelectionDCA = nabs(aod::track::dcaZ) <= 0.2f && ncheckbit(aod::track::trackCutFlag, trackSelectionDCAXYonly); + Filter fTracksEta = nabs(aod::track::eta) < 0.5f; + + void calibrateAdvanced(aod::McCollision const& mcc, + soa::SmallGroups const& collisions, + Particles const&, + soa::Filtered const& tracks) + { + auto pcFT0M = pFT0M.sliceBy(perMcCol, mcc.globalIndex()); + auto pcFT0C = pFT0C.sliceBy(perMcCol, mcc.globalIndex()); + int nFT0M = 0; + int nFT0C = 0; + int nTrkAt0 = 0; + for (auto& p : pcFT0M) { + if (isChargedParticle(p.pdgCode())) { + ++nFT0M; + } + } + h.fill(HIST("hFT0M"), nFT0M); + for (auto& p : pcFT0C) { + if (isChargedParticle(p.pdgCode())) { + ++nFT0C; + } + } + h.fill(HIST("hFT0C"), nFT0C); + + bool selected = false; + float cent = 1.e3; + for (auto& c : collisions) { + if (isCollisionSelectedMC(c)) { + selected = true; + auto sample = tracks.sliceBy(perCol, c.globalIndex()); + nTrkAt0 += sample.size(); + if (c.centFT0M() < cent) { + cent = c.centFT0M(); + } + } + } + if (!selected) { + nTrkAt0 = -1; + cent = -1; + } + h.fill(HIST("hCorrelate"), nFT0M, nFT0C, nTrkAt0, cent); + } + + PROCESS_SWITCH(Binner, calibrateAdvanced, "Create binning matched to dN/deta", false); + + void getData(ExColsCentFT0M::iterator const& collision, + soa::Filtered const& tracks) + { + if (isCollisionSelected(collision)) { + h.fill(HIST("hTrkAt0vsFT0M"), tracks.size(), collision.centFT0M()); + } + } + + PROCESS_SWITCH(Binner, getData, "Get data distribution to match to", false); + + void bin(aod::BCsWithTimestamps const& bcs, aod::McCollisions const& mccollisions, Particles const&) + { + auto bc = bcs.begin(); + multFT0M = ccdb->getForTimeStamp(path.value + "/hFT0M", bc.timestamp()); + multFT0C = ccdb->getForTimeStamp(path.value + "/hFT0C", bc.timestamp()); + if (multFT0C == nullptr && multFT0M == nullptr) { + LOGP(fatal, "Unable to get the distributions from CCDB"); + } + for (auto& mcc : mccollisions) { + auto pcFT0M = pFT0M.sliceBy(perMcCol, mcc.globalIndex()); + auto pcFT0C = pFT0C.sliceBy(perMcCol, mcc.globalIndex()); + int nFT0M = 0; + int nFT0C = 0; + for (auto& p : pcFT0M) { + if (isChargedParticle(p.pdgCode())) { + ++nFT0M; + } + } + h.fill(HIST("hFT0M"), nFT0M); + for (auto& p : pcFT0C) { + if (isChargedParticle(p.pdgCode())) { + ++nFT0C; + } + } + h.fill(HIST("hFT0C"), nFT0C); + float percentileFT0M = 100.f * multFT0M->Integral(multFT0M->FindFixBin(nFT0C), multFT0M->FindLastBinAbove()); + float percentileFT0C = 100.f * multFT0C->Integral(multFT0C->FindFixBin(nFT0C), multFT0C->FindLastBinAbove()); + gencents(percentileFT0C, percentileFT0M); + } + } + + PROCESS_SWITCH(Binner, bin, "Bin collisions", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return {adaptAnalysisTask(cfgc)}; +} diff --git a/PWGMM/Mult/TableProducer/reducer.cxx b/PWGMM/Mult/TableProducer/reducer.cxx index 5eda9070ca8..de9d516703b 100644 --- a/PWGMM/Mult/TableProducer/reducer.cxx +++ b/PWGMM/Mult/TableProducer/reducer.cxx @@ -47,10 +47,17 @@ struct Reducer { Configurable> etaBins{"eta", {-1.5, -0.5, 0.5, 1.5}, "eta binning"}; Configurable> phiBins{"phi", {0., PI / 2., PI, 3. * PI / 2., 2. * PI}, "phi binning"}; + Configurable useEvSel{"useEvSel", true, "use event selection"}; + Configurable checkTF{"checkTF", false, "check TF border"}; + Configurable checkITSROF{"checkITSROF", false, "check ITS readout frame border"}; + Configurable checkFT0PVcoincidence{"checkFT0PVcoincidence", true, "Check coincidence between FT0 and PV"}; + Configurable rejectITSonly{"rejectITSonly", true, "Reject ITS-only vertex"}; + Preslice cperBC = aod::collision::bcId; Preslice mccperBC = aod::mccollision::bcId; Preslice perMCc = aod::mcparticle::mcCollisionId; Preslice perC = aod::track::collisionId; + PresliceUnsorted> cperMCc = aod::mccollisionlabel::mcCollisionId; std::random_device rd; std::mt19937 randomgen; @@ -81,6 +88,16 @@ struct Reducer { 1. / (x * TMath::Beta(x, (1. + params->get((int)0, 5) * params->get((int)0, 5)))) * TMath::Power((params->get((int)0, 4) * params->get((int)0, 4)) / ((1. + params->get((int)0, 5) * params->get((int)0, 5)) + (params->get((int)0, 4) * params->get((int)0, 4))), x) * TMath::Power((1. + params->get((int)0, 5) * params->get((int)0, 5)) / ((1. + params->get((int)0, 5) * params->get((int)0, 5)) + (params->get((int)0, 4) * params->get((int)0, 4))), (1. + params->get((int)0, 5) * params->get((int)0, 5)))); } + template + inline bool isCollisionSelected(C const& collision) + { + return collision.selection_bit(aod::evsel::kIsTriggerTVX) && + (!checkTF || collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) && + (!checkITSROF || collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) && + (!checkFT0PVcoincidence || collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) && + (!rejectITSonly || collision.selection_bit(aod::evsel::kIsVertexITSTPC)); + } + void init(InitContext const&) { randomgen.seed(rd()); @@ -192,6 +209,19 @@ struct Reducer { ++i; continue; } + if (useEvSel) { + bool pass = false; + for (auto& c : collisions) { + if (isCollisionSelected(c)) { + pass = true; + break; + } + } + if (!pass) { + ++i; + continue; + } + } rmcc(bcId, weights[i], mcc.posX(), mcc.posY(), mcc.posZ(), mcc.impactParameter(), mcc.multMCFT0A(), mcc.multMCFT0C(), mcc.multMCNParticlesEta05(), mcc.multMCNParticlesEta10()); if constexpr (requires {mcc.processId(); mcc.pdf1(); }) { rhepmci(rmcc.lastIndex(), mcc.xsectGen(), mcc.ptHard(), mcc.nMPI(), mcc.processId(), mcc.id1(), mcc.id2(), mcc.pdfId1(), mcc.pdfId2(), mcc.x1(), mcc.x2(), mcc.scalePdf(), mcc.pdf1(), mcc.pdf2()); @@ -201,18 +231,18 @@ struct Reducer { usedLabels.push_back(rmcc.lastIndex()); ++i; } - i = 0; // check Reco events for (auto& c : collisions) { // discard fake events if (!c.has_mcCollision()) { - ++i; continue; } // discard events for which MC event was discarded auto pos = std::find(usedMCCs.begin(), usedMCCs.end(), c.mcCollisionId()); if (pos == usedMCCs.end()) { - ++i; + continue; + } + if (useEvSel && !isCollisionSelected(c)) { continue; } std::fill(binned.begin(), binned.end(), 0); @@ -225,7 +255,6 @@ struct Reducer { } rc(bcId, c.posX(), c.posY(), c.posZ(), c.collisionTimeRes(), c.multFT0A(), c.multFT0C(), c.multFDDA(), c.multFDDC(), c.multZNA(), c.multZNC(), c.multNTracksPV(), c.multNTracksPVeta1(), c.multNTracksPVetaHalf(), binned); rmcl(usedLabels[std::distance(usedMCCs.begin(), pos)]); - ++i; } } }; diff --git a/PWGMM/Mult/TableProducer/trackPropagation.cxx b/PWGMM/Mult/TableProducer/trackPropagation.cxx index 314bc59a2b2..a1dffe08dbf 100644 --- a/PWGMM/Mult/TableProducer/trackPropagation.cxx +++ b/PWGMM/Mult/TableProducer/trackPropagation.cxx @@ -89,12 +89,24 @@ struct AmbiguousTrackPropagation { ccdb->setLocalObjectValidityChecking(); if (produceHistos) { - registry.add({"DeltaZ", " ; #Delta#it{z}", {HistType::kTH1F, {{201, -10.1, 10.1}}}}); - registry.add({"TracksDCAXY", " ; DCA_{XY} (cm)", {HistType::kTH1F, {DCAxyAxis}}}); - registry.add({"ReassignedDCAXY", " ; DCA_{XY} (cm)", {HistType::kTH1F, {DCAxyAxis}}}); - registry.add({"TracksOrigDCAXY", " ; DCA_{XY} (wrt orig coll) (cm)", {HistType::kTH1F, {DCAxyAxis}}}); - registry.add({"TracksAmbDegree", " ; N_{coll}^{comp}", {HistType::kTH1D, {{41, -0.5, 40.5}}}}); - registry.add({"TrackIsAmb", " ; isAmbiguous", {HistType::kTH1D, {{2, -0.5, 1.5}}}}); + if (doprocessMFT || doprocessMFTReassoc) { + registry.add({"DeltaZ", " ; #Delta#it{z}", {HistType::kTH1F, {{201, -10.1, 10.1}}}}); + registry.add({"TracksDCAXY", " ; DCA_{XY} (cm)", {HistType::kTH1F, {DCAxyAxis}}}); + registry.add({"ReassignedDCAXY", " ; DCA_{XY} (cm)", {HistType::kTH1F, {DCAxyAxis}}}); + registry.add({"TracksOrigDCAXY", " ; DCA_{XY} (wrt orig coll) (cm)", {HistType::kTH1F, {DCAxyAxis}}}); + registry.add({"TracksAmbDegree", " ; N_{coll}^{comp}", {HistType::kTH1D, {{41, -0.5, 40.5}}}}); + registry.add({"TrackIsAmb", " ; isAmbiguous", {HistType::kTH1D, {{2, -0.5, 1.5}}}}); + } + if (doprocessCentral) { + registry.add({"PropagationFailures", "", {HistType::kTH1F, {{5, 0.5, 5.5}}}}); + auto h = registry.get(HIST("PropagationFailures")); + auto* x = h->GetXaxis(); + x->SetBinLabel(1, "Total"); + x->SetBinLabel(2, "Propagated"); + x->SetBinLabel(3, "Failed 1"); + x->SetBinLabel(4, "Failed 2"); + x->SetBinLabel(5, "Failed 3+"); + } } } @@ -164,16 +176,39 @@ struct AmbiguousTrackPropagation { if (ids.empty() || (ids.size() == 1 && bestCol == ids[0])) { continue; } + if (produceHistos) { + registry.fill(HIST("PropagationFailures"), 1); + } auto compatibleColls = track.compatibleColl(); + int failures = 0; for (auto& collision : compatibleColls) { - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPar, 2.f, matCorr, &dcaInfo); - if ((std::abs(dcaInfo[0]) < std::abs(bestDCA[0])) && (std::abs(dcaInfo[1]) < std::abs(bestDCA[1]))) { + auto propagated = o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPar, 2.f, matCorr, &dcaInfo); + if (!propagated) { + ++failures; + } + if (propagated && ((std::abs(dcaInfo[0]) < std::abs(bestDCA[0])) && (std::abs(dcaInfo[1]) < std::abs(bestDCA[1])))) { bestCol = collision.globalIndex(); bestDCA[0] = dcaInfo[0]; bestDCA[1] = dcaInfo[1]; bestTrackPar = trackPar; } } + if (produceHistos) { + switch (failures) { + case 0: + registry.fill(HIST("PropagationFailures"), 2); + break; + case 1: + registry.fill(HIST("PropagationFailures"), 3); + break; + case 2: + registry.fill(HIST("PropagationFailures"), 4); + break; + default: + registry.fill(HIST("PropagationFailures"), 5); + break; + } + } } tracksReassignedCore(bestCol, track.globalIndex(), bestDCA[0], bestDCA[1]); if (produceExtra) { diff --git a/PWGMM/Mult/Tasks/CMakeLists.txt b/PWGMM/Mult/Tasks/CMakeLists.txt index 4828a7ea434..2c56cc8fc96 100644 --- a/PWGMM/Mult/Tasks/CMakeLists.txt +++ b/PWGMM/Mult/Tasks/CMakeLists.txt @@ -34,6 +34,11 @@ o2physics_add_dpl_workflow(dndeta-mft PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(dndeta-mft-pbpb + SOURCES dndetaMFTPbPb.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(flatenicity-fv0 SOURCES flatenicityFV0.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore diff --git a/PWGMM/Mult/Tasks/dndeta-hi.cxx b/PWGMM/Mult/Tasks/dndeta-hi.cxx index e670da92d4d..7ac1bc49bb5 100644 --- a/PWGMM/Mult/Tasks/dndeta-hi.cxx +++ b/PWGMM/Mult/Tasks/dndeta-hi.cxx @@ -154,10 +154,6 @@ AxisSpec PtVarAxis = {kPtVarend - 1, +kPtVarbegin + 0.5, +kPtVarend - 0.5, "", " AxisSpec EvtClassAxis = {kECend - 1, +kECbegin + 0.5, +kECend - 0.5, "", "event class"}; AxisSpec TrigClassAxis = {kTrigend - 1, +kTrigbegin + 0.5, +kTrigend - 0.5, "", "trigger class"}; AxisSpec ParticleTypeAxis = {kParTypeend - 1, +kParTypebegin + 0.5, +kParTypeend - 0.5, "", "Particle type"}; -std::vector centBinningPbPb = {0, 1, 2, 3, 4, 5, 10, 20, 30, 40, 50, 60, 70, 80, 100}; -std::vector centBinning = {0., 0.01, 0.1, 1.0, 5.0, 10., 15, 20., 25, 30., 35., 40., 45., 50., 70., 100.0}; -AxisSpec CentAxis = {centBinning, "", "centrality"}; -AxisSpec CentAxisPbPb = {centBinningPbPb, "", "centrality"}; AxisSpec SpeciesAxis = {kSpeciesend - 1, +kSpeciesbegin + 0.5, +kSpeciesend - 0.5, "", "species class"}; AxisSpec MassAxis = {600, 0.3f, 1.3f, "Mass (GeV/c^{2})", "Inv. Mass (GeV/c^{2})"}; AxisSpec SignAxis = {kSignend - 1, +kSignbegin + 0.5, +kSignend - 0.5, "", "sign"}; @@ -199,6 +195,7 @@ struct MultiplicityCounter { Configurable v0radius{"v0radius", 0.5, "Radius"}; Configurable etadau{"etadau", 4, "Eta Daughters"}; Configurable rapidity{"v0rapidity", 0.5, "V0 rapidity"}; + ConfigurableAxis centBinning{"centrality", {VARIABLE_WIDTH, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 24, 26, 28, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100}, ""}; // Configurable mftanalysis{"mftanalysis", false, "mft analysis switch"}; Configurable zvtxcut{"zvtxcut", false, "z vtx cut < 10cm"}; @@ -212,6 +209,9 @@ struct MultiplicityCounter { std::vector usedTracksIds; void init(InitContext&) { + + AxisSpec CentAxis = {centBinning, "", "centrality"}; + AxisSpec CentAxisPbPb = {centBinning, "", "centrality"}; registry.add({"hetaresponse", ";etaresponse", {HistType::kTH2D, {{80, -4, 4}, {80, -4, 4}}}}); registry.add({"hft0multiplicity", ";multiplicity", {HistType::kTH1D, {{10000, 0, 100000}}}}); registry.add({"hcentrality", IsPbPb ? " ; centrality_FT0C (%) " : "; centrality_FT0M", {HistType::kTH1F, {{10000, 0, 100}}}}); @@ -226,6 +226,7 @@ struct MultiplicityCounter { registry.add({"hgendndeta", "evntclass; zvtex, eta", {HistType::kTHnSparseD, {EvtClassAxis, ZAxis, EtaAxis, IsPbPb ? CentAxisPbPb : CentAxis, ParticleTypeAxis, PtVarAxis, phibin}}}); registry.add({"hgenzvtx", "evntclass; zvtex", {HistType::kTHnSparseD, {EvtClassAxis, ZAxis, IsPbPb ? CentAxisPbPb : CentAxis}}}); registry.add({"hv0mass", "etaaxis; invmass", {HistType::kTHnSparseD, {IsPbPb ? CentAxisPbPb : CentAxis, SpeciesAxis, V0EtaAxis, MassAxis}}}); + registry.add({"hv0k0s", "invmass", {HistType::kTH1D, {{100, 0.4, 0.6}}}}); registry.add({"recetaINELg0Sel8recz10", ";etaresponse", {HistType::kTH2D, {EtaAxis, ZAxis}}}); registry.add({"genetaINELg0Sel8recz10", ";etaresponse", {HistType::kTH2D, {EtaAxis, ZAxis}}}); @@ -325,6 +326,8 @@ struct MultiplicityCounter { auto pertracks = tSample3->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto Ntrk = 0; + // if (collision.selection_bit(aod::evsel::kIsTriggerTVX) && collision.selection_bit(aod::evsel::kNoTimeFrameBorder) && collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + // if (collision.selection_bit(aod::evsel::kIsTriggerTVX)) { if (collision.sel8()) { btrigc[kSel8] = true; registry.fill(HIST("Selection"), 2.); @@ -345,7 +348,7 @@ struct MultiplicityCounter { if (btrigc[kSel8]) btrigc[kSel8g0] = true; } - if (btrigc[kSel8]) + if (btrigc[kSel8g0]) registry.fill(HIST("reczINELg0Sel8"), z); auto cent = -1.f; @@ -540,6 +543,8 @@ struct MultiplicityCounter { Bool_1d btrigc(kTrigend, false); auto z = collision.posZ(); + // if (collision.selection_bit(aod::evsel::kIsTriggerTVX) && collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + // if (collision.selection_bit(aod::evsel::kIsTriggerTVX)) { if (collision.sel8()) { btrigc[kSel8] = true; registry.fill(HIST("Selection"), 2.); @@ -755,11 +760,12 @@ struct MultiplicityCounter { } } PROCESS_SWITCH(MultiplicityCounter, processGen, "Process generator-level info", false); - + Preslice perCollisionV0 = o2::aod::v0data::collisionId; void processV0Counting( MyCollisionsCent const& collisions, aod::V0Datas const& fullV0s, - FiTracks const& /*tracks*/) + FiTracks const& /*tracks*/, + DaughterTracks const& /*Dautrks*/) { for (auto& collision : collisions) { if (!collision.sel8()) @@ -775,8 +781,27 @@ struct MultiplicityCounter { cent = collision.centFT0M(); } - for (auto& v0 : fullV0s) { + auto v0s_per_coll = fullV0s.sliceBy(perCollisionV0, collision.globalIndex()); + for (auto& v0 : v0s_per_coll) { + + auto pTrack = v0.template posTrack_as(); + auto nTrack = v0.template negTrack_as(); if (std::abs(z) < 10) { + if (v0.v0radius() > v0radius) + continue; + if (v0.dcapostopv() > dcapostopv) + continue; + if (v0.dcanegtopv() > dcanegtopv) + continue; + if (v0.v0cosPA() < v0cospa) + continue; + if (fabs(pTrack.eta()) > 0.9) + continue; + if (fabs(nTrack.eta()) > 0.9) + continue; + + if (fabs(v0.eta()) < 0.5) + registry.fill(HIST("hv0k0s"), v0.mK0Short()); registry.fill(HIST("hv0mass"), cent, Double_t(kK0short), v0.eta(), Double_t(v0.mK0Short())); registry.fill(HIST("hv0mass"), cent, Double_t(kLambda), v0.eta(), Double_t(v0.mLambda())); registry.fill(HIST("hv0mass"), cent, Double_t(kAntilambda), v0.eta(), Double_t(v0.mAntiLambda())); diff --git a/PWGMM/Mult/Tasks/dndeta-mft.cxx b/PWGMM/Mult/Tasks/dndeta-mft.cxx index b0164b73580..7d52a606226 100644 --- a/PWGMM/Mult/Tasks/dndeta-mft.cxx +++ b/PWGMM/Mult/Tasks/dndeta-mft.cxx @@ -83,7 +83,7 @@ struct PseudorapidityDensityMFT { "maxZDiff", 1.0f, "max allowed Z difference for reconstruced collisions (cm)"}; - Configurable usePhiCut{"usePhiCut", true, "use azimuthal angle cut"}; + Configurable usePhiCut{"usePhiCut", false, "use azimuthal angle cut"}; Configurable cfgPhiCut{"cfgPhiCut", 0.1f, "Cut on azimuthal angle of MFT tracks"}; diff --git a/PWGMM/Mult/Tasks/dndeta.cxx b/PWGMM/Mult/Tasks/dndeta.cxx index cf23c3f43fb..220bdbdebb8 100644 --- a/PWGMM/Mult/Tasks/dndeta.cxx +++ b/PWGMM/Mult/Tasks/dndeta.cxx @@ -21,6 +21,7 @@ #include #include +#include "Gencentralities.h" #include "Index.h" #include "bestCollisionTable.h" @@ -49,28 +50,39 @@ struct MultiplicityCounter { Configurable estimatorEta{"estimatorEta", 1.0, "eta range for INEL>0 sample definition"}; Configurable dcaZ{"dcaZ", 0.2f, "Custom DCA Z cut (ignored if negative)"}; - ConfigurableAxis multBinning{"multBinning", {301, -0.5, 300.5}, ""}; - ConfigurableAxis centBinning{"centBinning", {VARIABLE_WIDTH, 0, 10, 20, 30, 40, 50, 60, 70, 80, 100}, ""}; + ConfigurableAxis multBinning{"multBinning", {301, -0.5, 300.5}, "Multiplicity axis binning"}; + ConfigurableAxis centBinning{"centBinning", {VARIABLE_WIDTH, 0, 10, 20, 30, 40, 50, 60, 70, 80, 100}, "Centrality axis binning"}; + ConfigurableAxis occuBinning{"occuBinning", {VARIABLE_WIDTH, 0, 500, 1000, 2000, 5000, 10000}, "Occupancy axis binning"}; // Pb-Pb default - Configurable fillResponse{"fillResponse", true, "Fill respons matrix"}; + Configurable fillResponse{"fillResponse", true, "Fill response matrix"}; Configurable useProcId{"use-process-id", true, "Use process ID from generator"}; Configurable addFT0{"addFT0", false, "add FT0 estimators"}; Configurable addFDD{"addFDD", false, "add FDD estimators"}; - Configurable useEvSel{"useEvSel", true, "use event selection"}; - Configurable checkTF{"checkTF", true, "check TF border"}; - Configurable checkITSROF{"checkITSROF", true, "check ITS readout frame border"}; - Configurable checkFT0PVcoincidence{"checkFT0PVcoincidence", true, "Check coincidence between FT0 and PV"}; - Configurable rejectITSonly{"rejectITSonly", false, "Reject ITS-only vertex"}; + Configurable useEvSel{"useEvSel", true, "Use event selection"}; + Configurable excludeTFborder{"excludeTFborder", true, "Exclude TF border"}; + Configurable excludeITSROFborder{"excludeITSROFborder", true, "Exclude ITS RO frame border"}; + Configurable requireFT0PVcoincidence{"requireFT0PVcoincidence", true, "Require coincidence between FT0 and PV"}; + Configurable rejectITSonly{"rejectITSonly", true, "Reject ITS-only vertex"}; + Configurable requireVtxTOFMatched{"checkTOFMatch", true, "Consider only vertex with TOF match"}; template inline bool isCollisionSelected(C const& collision) { return collision.selection_bit(aod::evsel::kIsTriggerTVX) && - (!checkTF || collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) && - (!checkITSROF || collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) && - (!checkFT0PVcoincidence || collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) && - (!rejectITSonly || collision.selection_bit(aod::evsel::kIsVertexITSTPC)); + (!excludeTFborder || collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) && + (!excludeITSROFborder || collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) && + (!requireFT0PVcoincidence || collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) && + (!rejectITSonly || collision.selection_bit(aod::evsel::kIsVertexITSTPC)) && + (!requireVtxTOFMatched || collision.selection_bit(aod::evsel::kIsVertexTOFmatched)); + } + + template + inline bool isBCSelected(B const& bc) + { + return bc.selection_bit(aod::evsel::kIsTriggerTVX) && + (!excludeTFborder || bc.selection_bit(aod::evsel::kNoTimeFrameBorder)) && + (!excludeITSROFborder || bc.selection_bit(aod::evsel::kNoITSROFrameBorder)); } HistogramRegistry commonRegistry{ @@ -100,10 +112,12 @@ struct MultiplicityCounter { std::vector usedTracksIdsDF; std::vector usedTracksIdsDFMC; std::vector usedTracksIdsDFMCEff; + void init(InitContext&) { AxisSpec MultAxis = {multBinning}; AxisSpec CentAxis = {centBinning, "centrality"}; + AxisSpec OccuAxis = {occuBinning, "occupancy"}; { auto hstat = commonRegistry.get(HIST(BCSelection)); auto* x = hstat->GetXaxis(); @@ -113,17 +127,17 @@ struct MultiplicityCounter { } if (doprocessEventStat) { - inclusiveRegistry.add({EventChi2.data(), " ; #chi^2", {HistType::kTH1F, {{101, -0.1, 10.1}}}}); - inclusiveRegistry.add({EventTimeRes.data(), " ; t (ms)", {HistType::kTH1F, {{1001, -0.1, 100.1}}}}); + inclusiveRegistry.add({EventChi2.data(), " ; #chi^2", {HistType::kTH2F, {{101, -0.1, 10.1}, OccuAxis}}}); + inclusiveRegistry.add({EventTimeRes.data(), " ; t (ms)", {HistType::kTH2F, {{1001, -0.1, 100.1}, OccuAxis}}}); } if (doprocessEventStatCentralityFT0C || doprocessEventStatCentralityFT0M) { - binnedRegistry.add({EventChi2.data(), " ; #chi^2; centrality", {HistType::kTH2F, {{101, -0.1, 10.1}, CentAxis}}}); - binnedRegistry.add({EventTimeRes.data(), " ; t (ms); centrality", {HistType::kTH2F, {{1001, -0.1, 100.1}, CentAxis}}}); + binnedRegistry.add({EventChi2.data(), " ; #chi^2; centrality", {HistType::kTHnSparseF, {{101, -0.1, 10.1}, CentAxis, OccuAxis}}}); + binnedRegistry.add({EventTimeRes.data(), " ; t (ms); centrality", {HistType::kTHnSparseF, {{1001, -0.1, 100.1}, CentAxis, OccuAxis}}}); } if (doprocessCountingAmbiguous || doprocessCounting) { - inclusiveRegistry.add({EventSelection.data(), ";status;events", {HistType::kTH1F, {{static_cast(EvSelBins::kRejected), 0.5, static_cast(EvSelBins::kRejected) + 0.5}}}}); - auto hstat = inclusiveRegistry.get(HIST(EventSelection)); + inclusiveRegistry.add({EventSelection.data(), ";status;occupancy;events", {HistType::kTH2F, {{static_cast(EvSelBins::kRejected), 0.5, static_cast(EvSelBins::kRejected) + 0.5}, OccuAxis}}}); + auto hstat = inclusiveRegistry.get(HIST(EventSelection)); auto* x = hstat->GetXaxis(); x->SetBinLabel(static_cast(EvSelBins::kAll), EvSelBinLabels[static_cast(EvSelBins::kAll)].data()); x->SetBinLabel(static_cast(EvSelBins::kSelected), EvSelBinLabels[static_cast(EvSelBins::kSelected)].data()); @@ -131,51 +145,57 @@ struct MultiplicityCounter { x->SetBinLabel(static_cast(EvSelBins::kSelectedPVgt0), EvSelBinLabels[static_cast(EvSelBins::kSelectedPVgt0)].data()); x->SetBinLabel(static_cast(EvSelBins::kRejected), EvSelBinLabels[static_cast(EvSelBins::kRejected)].data()); - inclusiveRegistry.add({NtrkZvtx.data(), "; N_{trk}; Z_{vtx} (cm); events", {HistType::kTH2F, {MultAxis, ZAxis}}}); - inclusiveRegistry.add({EtaZvtx.data(), "; #eta; Z_{vtx} (cm); tracks", {HistType::kTH2F, {EtaAxis, ZAxis}}}); - inclusiveRegistry.add({EtaZvtx_gt0.data(), "; #eta; Z_{vtx} (cm); tracks", {HistType::kTH2F, {EtaAxis, ZAxis}}}); - inclusiveRegistry.add({EtaZvtx_PVgt0.data(), "; #eta; Z_{vtx} (cm); tracks", {HistType::kTH2F, {EtaAxis, ZAxis}}}); - inclusiveRegistry.add({PhiEta.data(), "; #varphi; #eta; tracks", {HistType::kTH2F, {PhiAxis, EtaAxis}}}); - inclusiveRegistry.add({PtEta.data(), " ; p_{T} (GeV/c); #eta", {HistType::kTH2F, {PtAxis, EtaAxis}}}); - inclusiveRegistry.add({DCAXYPt.data(), " ; p_{T} (GeV/c) ; DCA_{XY} (cm)", {HistType::kTH2F, {PtAxis, DCAAxis}}}); - inclusiveRegistry.add({DCAZPt.data(), " ; p_{T} (GeV/c) ; DCA_{Z} (cm)", {HistType::kTH2F, {PtAxis, DCAAxis}}}); + inclusiveRegistry.add({NtrkZvtx.data(), "; N_{trk}; Z_{vtx} (cm);occupancy; events", {HistType::kTHnSparseF, {MultAxis, ZAxis, OccuAxis}}}); + inclusiveRegistry.add({NpvcZvtx.data(), "; N_{PVc}; Z_{vtx} (cm);occupancy; events", {HistType::kTHnSparseF, {MultAxis, ZAxis, OccuAxis}}}); + inclusiveRegistry.add({EtaZvtx.data(), "; #eta; Z_{vtx} (cm);occupancy; tracks", {HistType::kTHnSparseF, {EtaAxis, ZAxis, OccuAxis}}}); + inclusiveRegistry.add({EtaZvtx_gt0.data(), "; #eta; Z_{vtx} (cm);occupancy; tracks", {HistType::kTHnSparseF, {EtaAxis, ZAxis, OccuAxis}}}); + inclusiveRegistry.add({EtaZvtx_PVgt0.data(), "; #eta; Z_{vtx} (cm);occupancy; tracks", {HistType::kTHnSparseF, {EtaAxis, ZAxis, OccuAxis}}}); + inclusiveRegistry.add({PhiEta.data(), "; #varphi; #eta;occupancy; tracks", {HistType::kTHnSparseF, {PhiAxis, EtaAxis, OccuAxis}}}); + inclusiveRegistry.add({PtEta.data(), " ; p_{T} (GeV/c);occupancy; #eta", {HistType::kTHnSparseF, {PtAxis, EtaAxis, OccuAxis}}}); + inclusiveRegistry.add({DCAXYPt.data(), " ; p_{T} (GeV/c) ; DCA_{XY} (cm);occupancy", {HistType::kTHnSparseF, {PtAxis, DCAAxis, OccuAxis}}}); + inclusiveRegistry.add({DCAZPt.data(), " ; p_{T} (GeV/c) ; DCA_{Z} (cm);occupancy", {HistType::kTHnSparseF, {PtAxis, DCAAxis, OccuAxis}}}); if (doprocessCountingAmbiguous) { - inclusiveRegistry.add({ReassignedDCAXYPt.data(), " ; p_{T} (GeV/c) ; DCA_{XY} (cm)", {HistType::kTH2F, {PtAxis, DCAAxis}}}); - inclusiveRegistry.add({ReassignedDCAZPt.data(), " ; p_{T} (GeV/c) ; DCA_{Z} (cm)", {HistType::kTH2F, {PtAxis, DCAAxis}}}); - inclusiveRegistry.add({ExtraDCAXYPt.data(), " ; p_{T} (GeV/c) ; DCA_{XY} (cm)", {HistType::kTH2F, {PtAxis, DCAAxis}}}); - inclusiveRegistry.add({ExtraDCAZPt.data(), " ; p_{T} (GeV/c) ; DCA_{Z} (cm)", {HistType::kTH2F, {PtAxis, DCAAxis}}}); - inclusiveRegistry.add({ExtraEtaZvtx.data(), "; #eta; Z_{vtx} (cm); tracks", {HistType::kTH2F, {EtaAxis, ZAxis}}}); - inclusiveRegistry.add({ExtraPhiEta.data(), "; #varphi; #eta; tracks", {HistType::kTH2F, {PhiAxis, EtaAxis}}}); - inclusiveRegistry.add({ReassignedEtaZvtx.data(), "; #eta; Z_{vtx} (cm); tracks", {HistType::kTH2F, {EtaAxis, ZAxis}}}); - inclusiveRegistry.add({ReassignedPhiEta.data(), "; #varphi; #eta; tracks", {HistType::kTH2F, {PhiAxis, EtaAxis}}}); - inclusiveRegistry.add({ReassignedZvtxCorr.data(), "; Z_{vtx}^{orig} (cm); Z_{vtx}^{re} (cm)", {HistType::kTH2F, {ZAxis, ZAxis}}}); + inclusiveRegistry.add({ReassignedDCAXYPt.data(), " ; p_{T} (GeV/c) ; DCA_{XY} (cm);occupancy", {HistType::kTHnSparseF, {PtAxis, DCAAxis, OccuAxis}}}); + inclusiveRegistry.add({ReassignedDCAZPt.data(), " ; p_{T} (GeV/c) ; DCA_{Z} (cm);occupancy", {HistType::kTHnSparseF, {PtAxis, DCAAxis, OccuAxis}}}); + inclusiveRegistry.add({ExtraDCAXYPt.data(), " ; p_{T} (GeV/c) ; DCA_{XY} (cm);occupancy", {HistType::kTHnSparseF, {PtAxis, DCAAxis, OccuAxis}}}); + inclusiveRegistry.add({ExtraDCAZPt.data(), " ; p_{T} (GeV/c) ; DCA_{Z} (cm);occupancy", {HistType::kTHnSparseF, {PtAxis, DCAAxis, OccuAxis}}}); + inclusiveRegistry.add({ExtraEtaZvtx.data(), "; #eta; Z_{vtx} (cm);occupancy; tracks", {HistType::kTHnSparseF, {EtaAxis, ZAxis, OccuAxis}}}); + inclusiveRegistry.add({ExtraPhiEta.data(), "; #varphi; #eta;occupancy; tracks", {HistType::kTHnSparseF, {PhiAxis, EtaAxis, OccuAxis}}}); + inclusiveRegistry.add({ReassignedEtaZvtx.data(), "; #eta; Z_{vtx} (cm);occupancy; tracks", {HistType::kTHnSparseF, {EtaAxis, ZAxis, OccuAxis}}}); + inclusiveRegistry.add({ReassignedPhiEta.data(), "; #varphi; #eta;occupancy; tracks", {HistType::kTHnSparseF, {PhiAxis, EtaAxis, OccuAxis}}}); + inclusiveRegistry.add({ReassignedZvtxCorr.data(), "; Z_{vtx}^{orig} (cm); Z_{vtx}^{re} (cm);occupancy", {HistType::kTHnSparseF, {ZAxis, ZAxis, OccuAxis}}}); } } if (doprocessCountingAmbiguousCentralityFT0C || doprocessCountingAmbiguousCentralityFT0M || doprocessCountingCentralityFT0C || doprocessCountingCentralityFT0M) { - binnedRegistry.add({EventSelection.data(), ";status;centrality;events", {HistType::kTH2F, {{3, 0.5, 3.5}, CentAxis}}}); - auto hstat = binnedRegistry.get(HIST(EventSelection)); - auto* x = hstat->GetXaxis(); - x->SetBinLabel(1, EvSelBinLabels[static_cast(EvSelBins::kAll)].data()); - x->SetBinLabel(2, EvSelBinLabels[static_cast(EvSelBins::kSelected)].data()); - x->SetBinLabel(3, EvSelBinLabels[static_cast(EvSelBins::kRejected)].data()); - - binnedRegistry.add({NtrkZvtx.data(), "; N_{trk}; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {MultAxis, ZAxis, CentAxis}}}); - binnedRegistry.add({EtaZvtx.data(), "; #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {EtaAxis, ZAxis, CentAxis}}}); - binnedRegistry.add({PhiEta.data(), "; #varphi; #eta; centrality", {HistType::kTHnSparseF, {PhiAxis, EtaAxis, CentAxis}}}); - binnedRegistry.add({PtEta.data(), " ; p_{T} (GeV/c); #eta; centrality", {HistType::kTHnSparseF, {PtAxis, EtaAxis, CentAxis}}}); - binnedRegistry.add({DCAXYPt.data(), " ; p_{T} (GeV/c) ; DCA_{XY} (cm); centrality", {HistType::kTHnSparseF, {PtAxis, DCAAxis, CentAxis}}}); - binnedRegistry.add({DCAZPt.data(), " ; p_{T} (GeV/c) ; DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {PtAxis, DCAAxis, CentAxis}}}); + binnedRegistry.add({EventSelection.data(), ";status;centrality;occupancy;events", {HistType::kTHnSparseF, {{static_cast(EvSelBins::kRejected), 0.5, static_cast(EvSelBins::kRejected) + 0.5}, CentAxis, OccuAxis}}}); + auto hstat = binnedRegistry.get(HIST(EventSelection)); + auto* x = hstat->GetAxis(0); + x->SetBinLabel(static_cast(EvSelBins::kAll), EvSelBinLabels[static_cast(EvSelBins::kAll)].data()); + x->SetBinLabel(static_cast(EvSelBins::kSelected), EvSelBinLabels[static_cast(EvSelBins::kSelected)].data()); + x->SetBinLabel(static_cast(EvSelBins::kSelectedgt0), EvSelBinLabels[static_cast(EvSelBins::kSelectedgt0)].data()); + x->SetBinLabel(static_cast(EvSelBins::kSelectedPVgt0), EvSelBinLabels[static_cast(EvSelBins::kSelectedPVgt0)].data()); + x->SetBinLabel(static_cast(EvSelBins::kRejected), EvSelBinLabels[static_cast(EvSelBins::kRejected)].data()); + + binnedRegistry.add({NtrkZvtx.data(), "; N_{trk}; Z_{vtx} (cm); centrality;occupancy", {HistType::kTHnSparseF, {MultAxis, ZAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({NpvcZvtx.data(), "; N_{PVc}; Z_{vtx} (cm); centrality;occupancy", {HistType::kTHnSparseF, {MultAxis, ZAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({EtaZvtx.data(), "; #eta; Z_{vtx} (cm); centrality;occupancy", {HistType::kTHnSparseF, {EtaAxis, ZAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({EtaZvtx_gt0.data(), "; #eta; Z_{vtx} (cm); centrality;occupancy", {HistType::kTHnSparseF, {EtaAxis, ZAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({EtaZvtx_PVgt0.data(), "; #eta; Z_{vtx} (cm); centrality;occupancy", {HistType::kTHnSparseF, {EtaAxis, ZAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({PhiEta.data(), "; #varphi; #eta; centrality;occupancy", {HistType::kTHnSparseF, {PhiAxis, EtaAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({PtEta.data(), " ; p_{T} (GeV/c); #eta; centrality;occupancy", {HistType::kTHnSparseF, {PtAxis, EtaAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({DCAXYPt.data(), " ; p_{T} (GeV/c) ; DCA_{XY} (cm); centrality;occupancy", {HistType::kTHnSparseF, {PtAxis, DCAAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({DCAZPt.data(), " ; p_{T} (GeV/c) ; DCA_{Z} (cm); centrality;occupancy", {HistType::kTHnSparseF, {PtAxis, DCAAxis, CentAxis, OccuAxis}}}); if (doprocessCountingAmbiguousCentralityFT0C || doprocessCountingAmbiguousCentralityFT0M) { - binnedRegistry.add({ReassignedDCAXYPt.data(), " ; p_{T} (GeV/c) ; DCA_{XY} (cm); centrality", {HistType::kTHnSparseF, {PtAxis, DCAAxis, CentAxis}}}); - binnedRegistry.add({ReassignedDCAZPt.data(), " ; p_{T} (GeV/c) ; DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {PtAxis, DCAAxis, CentAxis}}}); - binnedRegistry.add({ExtraDCAXYPt.data(), " ; p_{T} (GeV/c) ; DCA_{XY} (cm); centrality", {HistType::kTHnSparseF, {PtAxis, DCAAxis, CentAxis}}}); - binnedRegistry.add({ExtraDCAZPt.data(), " ; p_{T} (GeV/c) ; DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {PtAxis, DCAAxis, CentAxis}}}); - binnedRegistry.add({ExtraEtaZvtx.data(), "; #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {EtaAxis, ZAxis, CentAxis}}}); - binnedRegistry.add({ExtraPhiEta.data(), "; #varphi; #eta; centrality", {HistType::kTHnSparseF, {PhiAxis, EtaAxis, CentAxis}}}); - binnedRegistry.add({ReassignedEtaZvtx.data(), "; #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {EtaAxis, ZAxis, CentAxis}}}); - binnedRegistry.add({ReassignedPhiEta.data(), "; #varphi; #eta; centrality", {HistType::kTHnSparseF, {PhiAxis, EtaAxis, CentAxis}}}); - binnedRegistry.add({ReassignedZvtxCorr.data(), "; Z_{vtx}^{orig} (cm); Z_{vtx}^{re} (cm); centrality", {HistType::kTHnSparseF, {ZAxis, ZAxis, CentAxis}}}); + binnedRegistry.add({ReassignedDCAXYPt.data(), " ; p_{T} (GeV/c) ; DCA_{XY} (cm); centrality;occupancy", {HistType::kTHnSparseF, {PtAxis, DCAAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({ReassignedDCAZPt.data(), " ; p_{T} (GeV/c) ; DCA_{Z} (cm); centrality;occupancy", {HistType::kTHnSparseF, {PtAxis, DCAAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({ExtraDCAXYPt.data(), " ; p_{T} (GeV/c) ; DCA_{XY} (cm); centrality;occupancy", {HistType::kTHnSparseF, {PtAxis, DCAAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({ExtraDCAZPt.data(), " ; p_{T} (GeV/c) ; DCA_{Z} (cm); centrality;occupancy", {HistType::kTHnSparseF, {PtAxis, DCAAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({ExtraEtaZvtx.data(), "; #eta; Z_{vtx} (cm); centrality;occupancy", {HistType::kTHnSparseF, {EtaAxis, ZAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({ExtraPhiEta.data(), "; #varphi; #eta; centrality;occupancy", {HistType::kTHnSparseF, {PhiAxis, EtaAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({ReassignedEtaZvtx.data(), "; #eta; Z_{vtx} (cm); centrality;occupancy", {HistType::kTHnSparseF, {EtaAxis, ZAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({ReassignedPhiEta.data(), "; #varphi; #eta; centrality;occupancy", {HistType::kTHnSparseF, {PhiAxis, EtaAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({ReassignedZvtxCorr.data(), "; Z_{vtx}^{orig} (cm); Z_{vtx}^{re} (cm); centrality;occupancy", {HistType::kTHnSparseF, {ZAxis, ZAxis, CentAxis, OccuAxis}}}); } } @@ -186,35 +206,43 @@ struct MultiplicityCounter { effLabels += " ; process ID"; effAxes.push_back(ProcAxis); } - inclusiveRegistry.add({NtrkZvtxGen.data(), "; N_{trk}; Z_{vtx} (cm); events", {HistType::kTH2F, {MultAxis, ZAxis}}}); + inclusiveRegistry.add({NtrkZvtxGen.data(), "; N_{trk}; Z_{vtx} (cm); occupancy; events", {HistType::kTHnSparseF, {MultAxis, ZAxis, OccuAxis}}}); inclusiveRegistry.add({NtrkZvtxGen_t.data(), effLabels.c_str(), {HistType::kTHnSparseF, effAxes}}); - inclusiveRegistry.add({EtaZvtxGen.data(), "; #eta; Z_{vtx} (cm); tracks", {HistType::kTH2F, {EtaAxis, ZAxis}}}); + inclusiveRegistry.add({NpvcZvxtGen.data(), "; N_{PVc}; Z_{vtx} (cm); occupancy; events", {HistType::kTHnSparseF, {MultAxis, ZAxis, OccuAxis}}}); + inclusiveRegistry.add({EtaZvtxGen.data(), "; #eta; Z_{vtx} (cm); occupancy; tracks", {HistType::kTHnSparseF, {EtaAxis, ZAxis, OccuAxis}}}); inclusiveRegistry.add({EtaZvtxGen_t.data(), "; #eta; Z_{vtx} (cm); tracks", {HistType::kTH2F, {EtaAxis, ZAxis}}}); inclusiveRegistry.add({EtaZvtxGen_gt0.data(), "; #eta; Z_{vtx} (cm); tracks", {HistType::kTH2F, {EtaAxis, ZAxis}}}); inclusiveRegistry.add({EtaZvtxGen_PVgt0.data(), "; #eta; Z_{vtx} (cm); tracks", {HistType::kTH2F, {EtaAxis, ZAxis}}}); inclusiveRegistry.add({EtaZvtxGen_gt0t.data(), "; #eta; Z_{vtx} (cm); tracks", {HistType::kTH2F, {EtaAxis, ZAxis}}}); inclusiveRegistry.add({PtEtaGen.data(), " ; p_{T} (GeV/c) ; #eta", {HistType::kTH2F, {PtAxis, EtaAxis}}}); + inclusiveRegistry.add({PhiEtaGen.data(), "; #varphi; #eta; tracks", {HistType::kTHnSparseF, {PhiAxis, EtaAxis}}}); - inclusiveRegistry.add({PhiEtaGen.data(), "; #varphi; #eta; tracks", {HistType::kTH2F, {PhiAxis, EtaAxis}}}); - - inclusiveRegistry.add({Efficiency.data(), "; status; events", {HistType::kTH1F, {{static_cast(EvEffBins::kSelectedPVgt0), 0.5, static_cast(EvEffBins::kSelectedPVgt0) + 0.5}}}}); - inclusiveRegistry.add({NotFoundZvtx.data(), " ; Z_{vtx} (cm)", {HistType::kTH1F, {ZAxis}}}); + inclusiveRegistry.add({Efficiency.data(), "; status; occupancy; events", {HistType::kTH2F, {{static_cast(EvEffBins::kSelectedPVgt0), 0.5, static_cast(EvEffBins::kSelectedPVgt0) + 0.5}, OccuAxis}}}); + inclusiveRegistry.add({NotFoundZvtx.data(), " ; Z_{vtx} (cm) ", {HistType::kTH1F, {ZAxis}}}); if (fillResponse) { inclusiveRegistry.add({EfficiencyMult.data(), effLabels.c_str(), {HistType::kTHnSparseF, effAxes}}); inclusiveRegistry.add({SplitMult.data(), " ; N_{gen} ; Z_{vtx} (cm)", {HistType::kTH2F, {MultAxis, ZAxis}}}); - if (addFT0 && !addFDD) { - inclusiveRegistry.add({Response.data(), " ; N_{rec}; N_{PV cont}; N_{gen}; N_{FT0A}; N_{FT0C}; Z_{vtx} (cm)", {HistType::kTHnSparseF, {MultAxis, MultAxis, MultAxis, FT0AAxis, FT0CAxis, ZAxis}}}); - } else if (addFDD && !addFT0) { - inclusiveRegistry.add({Response.data(), " ; N_{rec}; N_{PV cont}; N_{gen}; N_{FDA}; N_{FDC}; Z_{vtx} (cm)", {HistType::kTHnSparseF, {MultAxis, MultAxis, MultAxis, FDAAxis, FDCAxis, ZAxis}}}); - } else if (addFT0 && addFDD) { - inclusiveRegistry.add({Response.data(), " ; N_{rec}; N_{PV cont}; N_{gen}; N_{FT0A}; N_{FT0C}; N_{FDA}; N_{FDC}; Z_{vtx} (cm)", {HistType::kTHnSparseF, {MultAxis, MultAxis, MultAxis, FT0AAxis, FT0CAxis, FDAAxis, FDCAxis, ZAxis}}}); - } else { - inclusiveRegistry.add({Response.data(), " ; N_{rec}; N_{PV cont}; N_{gen}; Z_{vtx} (cm)", {HistType::kTHnSparseF, {MultAxis, MultAxis, MultAxis, ZAxis}}}); + + std::string reLabels{" ; N_{rec}; N_{PV cont}; N_{gen}"}; + std::vector reAxes{MultAxis, MultAxis, MultAxis}; + if (addFT0) { + reLabels += " ; N_{FT0A}; N_{FT0C}"; + reAxes.push_back(FT0AAxis); + reAxes.push_back(FT0CAxis); + } + if (addFDD) { + reLabels += " ; N_{FDA}; N_{FDC}"; + reAxes.push_back(FDAAxis); + reAxes.push_back(FDCAxis); } + reLabels += " ; Z_{vtx} (cm); occupancy"; + reAxes.push_back(ZAxis); + reAxes.push_back(OccuAxis); + inclusiveRegistry.add({Response.data(), reLabels.c_str(), {HistType::kTHnSparseF, reAxes}}); } - auto heff = inclusiveRegistry.get(HIST(Efficiency)); + auto heff = inclusiveRegistry.get(HIST(Efficiency)); auto* x = heff->GetXaxis(); x->SetBinLabel(static_cast(EvEffBins::kGen), EvEffBinLabels[static_cast(EvEffBins::kGen)].data()); x->SetBinLabel(static_cast(EvEffBins::kGengt0), EvEffBinLabels[static_cast(EvEffBins::kGengt0)].data()); @@ -224,37 +252,54 @@ struct MultiplicityCounter { x->SetBinLabel(static_cast(EvEffBins::kSelectedPVgt0), EvEffBinLabels[static_cast(EvEffBins::kSelectedPVgt0)].data()); } - if (doprocessGenAmbiguousFT0C || doprocessGenAmbiguousFT0M || doprocessGenAmbiguousFT0Chi || doprocessGenAmbiguousFT0Mhi || - doprocessGenFT0C || doprocessGenFT0M || doprocessGenFT0Chi || doprocessGenFT0Mhi) { - binnedRegistry.add({NtrkZvtxGen.data(), "; N_{trk}; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {MultAxis, ZAxis, CentAxis}}}); - binnedRegistry.add({NtrkZvtxGen_t.data(), "; N_{part}; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {MultAxis, ZAxis, CentAxis}}}); - binnedRegistry.add({EtaZvtxGen.data(), "; #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {EtaAxis, ZAxis, CentAxis}}}); + if (doprocessGenAmbiguousFT0C || doprocessGenAmbiguousFT0M || doprocessGenAmbiguousFT0Cplus || doprocessGenAmbiguousFT0Mplus || doprocessGenAmbiguousFT0Chi || doprocessGenAmbiguousFT0Mhi || + doprocessGenFT0C || doprocessGenFT0M || doprocessGenFT0Cplus || doprocessGenFT0Mplus || doprocessGenFT0Chi || doprocessGenFT0Mhi || doprocessGenAmbiguousExFT0C || doprocessGenAmbiguousExFT0M || + doprocessGenExFT0C || doprocessGenExFT0M) { + std::string effLabels{" ; N_{gen}; Z_{vtx} (cm); centrality"}; + std::vector effAxes{MultAxis, ZAxis, CentAxis}; + if ((doprocessGenAmbiguousExFT0C || doprocessGenAmbiguousExFT0M || doprocessGenExFT0C || doprocessGenExFT0M) && useProcId) { + effLabels += " ; process ID"; + effAxes.push_back(ProcAxis); + } + binnedRegistry.add({NtrkZvtxGen.data(), "; N_{trk}; Z_{vtx} (cm); centrality; occupance", {HistType::kTHnSparseF, {MultAxis, ZAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({NtrkZvtxGen_t.data(), effLabels.c_str(), {HistType::kTHnSparseF, effAxes}}); + binnedRegistry.add({NpvcZvxtGen.data(), "; N_{PVc}; Z_{vtx} (cm); centrality; occupancy", {HistType::kTHnSparseF, {MultAxis, ZAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({EtaZvtxGen.data(), "; #eta; Z_{vtx} (cm); centrality; occupancy", {HistType::kTHnSparseF, {EtaAxis, ZAxis, CentAxis, OccuAxis}}}); binnedRegistry.add({EtaZvtxGen_t.data(), "; #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {EtaAxis, ZAxis, CentAxis}}}); binnedRegistry.add({EtaZvtxGen_gt0.data(), "; #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {EtaAxis, ZAxis, CentAxis}}}); binnedRegistry.add({EtaZvtxGen_PVgt0.data(), "; #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {EtaAxis, ZAxis, CentAxis}}}); binnedRegistry.add({EtaZvtxGen_gt0t.data(), "; #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {EtaAxis, ZAxis, CentAxis}}}); binnedRegistry.add({PtEtaGen.data(), " ; p_{T} (GeV/c) ; #eta; centrality", {HistType::kTHnSparseF, {PtAxis, EtaAxis, CentAxis}}}); - binnedRegistry.add({PhiEtaGen.data(), "; #varphi; #eta; tracks", {HistType::kTHnSparseF, {PhiAxis, EtaAxis, CentAxis}}}); - binnedRegistry.add({Efficiency.data(), "; status; centrality; events", {HistType::kTH2F, {{static_cast(EvEffBins::kSelectedPVgt0), 0.5, static_cast(EvEffBins::kSelectedPVgt0) + 0.5}, CentAxis}}}); + + binnedRegistry.add({Efficiency.data(), "; status; centrality; occupancy; events", {HistType::kTHnSparseF, {{static_cast(EvEffBins::kSelectedPVgt0), 0.5, static_cast(EvEffBins::kSelectedPVgt0) + 0.5}, CentAxis, OccuAxis}}}); binnedRegistry.add({NotFoundZvtx.data(), " ; Z_{vtx} (cm); centrality; events", {HistType::kTH2F, {ZAxis, CentAxis}}}); if (fillResponse) { - binnedRegistry.add({EfficiencyMult.data(), " ; N_{gen}; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {MultAxis, ZAxis, CentAxis}}}); + binnedRegistry.add({EfficiencyMult.data(), effLabels.c_str(), {HistType::kTHnSparseF, effAxes}}); binnedRegistry.add({SplitMult.data(), " ; N_{gen} ; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {MultAxis, ZAxis, CentAxis}}}); - if (addFT0 && !addFDD) { - binnedRegistry.add({Response.data(), " ; N_{rec}; N_{PV cont}; N_{gen}; N_{FT0A}; N_{FT0C}; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {MultAxis, MultAxis, MultAxis, FT0AAxis, FT0CAxis, ZAxis, CentAxis}}}); - } else if (addFDD && !addFT0) { - binnedRegistry.add({Response.data(), " ; N_{rec}; N_{PV cont}; N_{gen}; N_{FDA}; N_{FDC}; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {MultAxis, MultAxis, MultAxis, FDAAxis, FDCAxis, ZAxis, CentAxis}}}); - } else if (addFT0 && addFDD) { - binnedRegistry.add({Response.data(), " ; N_{rec}; N_{PV cont}; N_{gen}; N_{FT0A}; N_{FT0C}; N_{FDA}; N_{FDC}; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {MultAxis, MultAxis, MultAxis, FT0AAxis, FT0CAxis, FDAAxis, FDCAxis, ZAxis, CentAxis}}}); - } else { - binnedRegistry.add({Response.data(), " ; N_{rec}; N_{PV cont}; N_{gen}; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {MultAxis, MultAxis, ZAxis, CentAxis}}}); + + std::string reLabels{" ; N_{rec}; N_{PV cont}; N_{gen}"}; + std::vector reAxes{MultAxis, MultAxis, MultAxis}; + if (addFT0) { + reLabels += " ; N_{FT0A}; N_{FT0C}"; + reAxes.push_back(FT0AAxis); + reAxes.push_back(FT0CAxis); + } + if (addFDD) { + reLabels += " ; N_{FDA}; N_{FDC}"; + reAxes.push_back(FDAAxis); + reAxes.push_back(FDCAxis); } + reLabels += " ; Z_{vtx} (cm); centrality; occupancy"; + reAxes.push_back(ZAxis); + reAxes.push_back(CentAxis); + reAxes.push_back(OccuAxis); + binnedRegistry.add({Response.data(), reLabels.c_str(), {HistType::kTHnSparseF, reAxes}}); } - auto heff = binnedRegistry.get(HIST(Efficiency)); - auto* x = heff->GetXaxis(); + auto heff = binnedRegistry.get(HIST(Efficiency)); + auto* x = heff->GetAxis(0); x->SetBinLabel(static_cast(EvEffBins::kGen), EvEffBinLabels[static_cast(EvEffBins::kGen)].data()); x->SetBinLabel(static_cast(EvEffBins::kGengt0), EvEffBinLabels[static_cast(EvEffBins::kGengt0)].data()); x->SetBinLabel(static_cast(EvEffBins::kRec), EvEffBinLabels[static_cast(EvEffBins::kRec)].data()); @@ -264,57 +309,57 @@ struct MultiplicityCounter { } if (doprocessTrackEfficiencyAmbiguous || doprocessTrackEfficiency) { - inclusiveRegistry.add({PtGen.data(), " ; p_{T} (GeV/c)", {HistType::kTH1F, {PtAxisEff}}}); - inclusiveRegistry.add({PtGenNoEtaCut.data(), " ; p_{T} (GeV/c)", {HistType::kTH1F, {PtAxisEff}}}); - inclusiveRegistry.add({PtEfficiency.data(), " ; p_{T} (GeV/c)", {HistType::kTH1F, {PtAxisEff}}}); - inclusiveRegistry.add({PtEfficiencyNoEtaCut.data(), " ; p_{T} (GeV/c)", {HistType::kTH1F, {PtAxisEff}}}); - inclusiveRegistry.add({PtEfficiencyFakes.data(), " ; p_{T} (GeV/c)", {HistType::kTH1F, {PtAxisEff}}}); + inclusiveRegistry.add({PtGen.data(), " ; p_{T} (GeV/c); occupancy", {HistType::kTH2F, {PtAxisEff, OccuAxis}}}); + inclusiveRegistry.add({PtGenNoEtaCut.data(), " ; p_{T} (GeV/c); occupancy", {HistType::kTH2F, {PtAxisEff, OccuAxis}}}); + inclusiveRegistry.add({PtEfficiency.data(), " ; p_{T} (GeV/c); occupancy", {HistType::kTH2F, {PtAxisEff, OccuAxis}}}); + inclusiveRegistry.add({PtEfficiencyNoEtaCut.data(), " ; p_{T} (GeV/c); occupancy", {HistType::kTH2F, {PtAxisEff, OccuAxis}}}); + inclusiveRegistry.add({PtEfficiencyFakes.data(), " ; p_{T} (GeV/c); occupancy", {HistType::kTH2F, {PtAxisEff, OccuAxis}}}); for (auto i = 0u; i < speciesIds.size(); ++i) { - inclusiveRegistry.add({fmt::format(PtGenF.data(), species[i]).c_str(), " ; p_{T} (GeV/c)", {HistType::kTH1F, {PtAxisEff}}}); - inclusiveRegistry.add({fmt::format(PtEfficiencyF.data(), species[i]).c_str(), " ; p_{T} (GeV/c)", {HistType::kTH1F, {PtAxisEff}}}); + inclusiveRegistry.add({fmt::format(PtGenF.data(), species[i]).c_str(), " ; p_{T} (GeV/c); occupancy", {HistType::kTH2F, {PtAxisEff, OccuAxis}}}); + inclusiveRegistry.add({fmt::format(PtEfficiencyF.data(), species[i]).c_str(), " ; p_{T} (GeV/c); occupancy", {HistType::kTH2F, {PtAxisEff, OccuAxis}}}); } } if (doprocessTrackEfficiencyAmbiguousCentralityFT0M || doprocessTrackEfficiencyCentralityFT0M || doprocessTrackEfficiencyAmbiguousCentralityFT0C || doprocessTrackEfficiencyCentralityFT0C) { - binnedRegistry.add({PtGen.data(), " ; p_{T} (GeV/c); centrality", {HistType::kTH2F, {PtAxisEff, CentAxis}}}); - binnedRegistry.add({PtGenNoEtaCut.data(), " ; p_{T} (GeV/c); centrality", {HistType::kTH2F, {PtAxisEff, CentAxis}}}); - binnedRegistry.add({PtEfficiency.data(), " ; p_{T} (GeV/c); centrality", {HistType::kTH2F, {PtAxisEff, CentAxis}}}); - binnedRegistry.add({PtEfficiencyNoEtaCut.data(), " ; p_{T} (GeV/c); centrality", {HistType::kTH2F, {PtAxisEff, CentAxis}}}); - binnedRegistry.add({PtEfficiencyFakes.data(), " ; p_{T} (GeV/c); centrality", {HistType::kTH2F, {PtAxisEff, CentAxis}}}); + binnedRegistry.add({PtGen.data(), " ; p_{T} (GeV/c); centrality; occupancy", {HistType::kTHnSparseF, {PtAxisEff, CentAxis, OccuAxis}}}); + binnedRegistry.add({PtGenNoEtaCut.data(), " ; p_{T} (GeV/c); centrality; occupancy", {HistType::kTHnSparseF, {PtAxisEff, CentAxis, OccuAxis}}}); + binnedRegistry.add({PtEfficiency.data(), " ; p_{T} (GeV/c); centrality; occupancy", {HistType::kTHnSparseF, {PtAxisEff, CentAxis, OccuAxis}}}); + binnedRegistry.add({PtEfficiencyNoEtaCut.data(), " ; p_{T} (GeV/c); centrality; occupancy", {HistType::kTHnSparseF, {PtAxisEff, CentAxis, OccuAxis}}}); + binnedRegistry.add({PtEfficiencyFakes.data(), " ; p_{T} (GeV/c); centrality; occupancy", {HistType::kTHnSparseF, {PtAxisEff, CentAxis, OccuAxis}}}); for (auto i = 0u; i < speciesIds.size(); ++i) { - binnedRegistry.add({fmt::format(PtGenF.data(), species[i]).c_str(), " ; p_{T} (GeV/c); centrality", {HistType::kTH2F, {PtAxisEff, CentAxis}}}); - binnedRegistry.add({fmt::format(PtEfficiencyF.data(), species[i]).c_str(), " ; p_{T} (GeV/c); centrality", {HistType::kTH2F, {PtAxisEff, CentAxis}}}); + binnedRegistry.add({fmt::format(PtGenF.data(), species[i]).c_str(), " ; p_{T} (GeV/c); centrality; occupancy", {HistType::kTHnSparseF, {PtAxisEff, CentAxis, OccuAxis}}}); + binnedRegistry.add({fmt::format(PtEfficiencyF.data(), species[i]).c_str(), " ; p_{T} (GeV/c); centrality; occupancy", {HistType::kTHnSparseF, {PtAxisEff, CentAxis, OccuAxis}}}); } } if (doprocessTrackEfficiencyIndexed) { - inclusiveRegistry.add({PhiEtaGenDuplicates.data(), "; #varphi; #eta; tracks", {HistType::kTH2F, {PhiAxis, EtaAxis}}}); - inclusiveRegistry.add({PhiEtaDuplicates.data(), "; #varphi; #eta; tracks", {HistType::kTH2F, {PhiAxis, EtaAxis}}}); - inclusiveRegistry.add({PtGenIdx.data(), " ; p_{T} (GeV/c)", {HistType::kTH1F, {PtAxisEff}}}); - inclusiveRegistry.add({PtGenIdxNoEtaCut.data(), " ; p_{T} (GeV/c)", {HistType::kTH1F, {PtAxisEff}}}); - inclusiveRegistry.add({PtEfficiencyIdx.data(), " ; p_{T} (GeV/c)", {HistType::kTH1F, {PtAxisEff}}}); - inclusiveRegistry.add({PtEfficiencyIdxNoEtaCut.data(), " ; p_{T} (GeV/c)", {HistType::kTH1F, {PtAxisEff}}}); - inclusiveRegistry.add({PtEfficiencySecondariesIdx.data(), " ; p_{T} (GeV/c)", {HistType::kTH1F, {PtAxisEff}}}); - inclusiveRegistry.add({PtEfficiencySecondariesIdxNoEtaCut.data(), " ; p_{T} (GeV/c)", {HistType::kTH1F, {PtAxisEff}}}); - inclusiveRegistry.add({Mask.data(), " ; bit", {HistType::kTH1F, {{17, -0.5, 16.5}}}}); - inclusiveRegistry.add({ITSlayers.data(), " ; layer", {HistType::kTH1F, {{8, 0.5, 8.5}}}}); + inclusiveRegistry.add({PhiEtaGenDuplicates.data(), "; #varphi; #eta; occupancy; tracks", {HistType::kTHnSparseF, {PhiAxis, EtaAxis, OccuAxis}}}); + inclusiveRegistry.add({PhiEtaDuplicates.data(), "; #varphi; #eta; occupancy; tracks", {HistType::kTHnSparseF, {PhiAxis, EtaAxis, OccuAxis}}}); + inclusiveRegistry.add({PtGenIdx.data(), " ; p_{T} (GeV/c); occupancy", {HistType::kTH2F, {PtAxisEff, OccuAxis}}}); + inclusiveRegistry.add({PtGenIdxNoEtaCut.data(), " ; p_{T} (GeV/c); occupancy", {HistType::kTH2F, {PtAxisEff, OccuAxis}}}); + inclusiveRegistry.add({PtEfficiencyIdx.data(), " ; p_{T} (GeV/c); occupancy", {HistType::kTH2F, {PtAxisEff, OccuAxis}}}); + inclusiveRegistry.add({PtEfficiencyIdxNoEtaCut.data(), " ; p_{T} (GeV/c); occupancy", {HistType::kTH2F, {PtAxisEff, OccuAxis}}}); + inclusiveRegistry.add({PtEfficiencySecondariesIdx.data(), " ; p_{T} (GeV/c); occupancy", {HistType::kTH2F, {PtAxisEff, OccuAxis}}}); + inclusiveRegistry.add({PtEfficiencySecondariesIdxNoEtaCut.data(), " ; p_{T} (GeV/c); occupancy", {HistType::kTH2F, {PtAxisEff, OccuAxis}}}); + inclusiveRegistry.add({Mask.data(), " ; bit; occupancy", {HistType::kTH2F, {{17, -0.5, 16.5}, OccuAxis}}}); + inclusiveRegistry.add({ITSlayers.data(), " ; layer; occupancy", {HistType::kTH2F, {{8, 0.5, 8.5}, OccuAxis}}}); for (auto i = 0u; i < speciesIds.size(); ++i) { - inclusiveRegistry.add({fmt::format(PtGenIdxF.data(), species[i]).c_str(), " ; p_{T} (GeV/c)", {HistType::kTH1F, {PtAxisEff}}}); - inclusiveRegistry.add({fmt::format(PtEfficiencyIdxF.data(), species[i]).c_str(), " ; p_{T} (GeV/c)", {HistType::kTH1F, {PtAxisEff}}}); + inclusiveRegistry.add({fmt::format(PtGenIdxF.data(), species[i]).c_str(), " ; p_{T} (GeV/c); occupancy", {HistType::kTH2F, {PtAxisEff, OccuAxis}}}); + inclusiveRegistry.add({fmt::format(PtEfficiencyIdxF.data(), species[i]).c_str(), " ; p_{T} (GeV/c); occupancy", {HistType::kTH2F, {PtAxisEff, OccuAxis}}}); } } if (doprocessTrackEfficiencyIndexedCentralityFT0M || doprocessTrackEfficiencyIndexedCentralityFT0C) { - binnedRegistry.add({PhiEtaGenDuplicates.data(), "; #varphi; #eta; centrality; tracks", {HistType::kTH3F, {PhiAxis, EtaAxis, CentAxis}}}); - binnedRegistry.add({PhiEtaDuplicates.data(), "; #varphi; #eta; centrality; tracks", {HistType::kTH3F, {PhiAxis, EtaAxis, CentAxis}}}); - binnedRegistry.add({PtGenIdx.data(), " ; p_{T} (GeV/c); centrality", {HistType::kTH2F, {PtAxisEff, CentAxis}}}); - binnedRegistry.add({PtGenIdxNoEtaCut.data(), " ; p_{T} (GeV/c); centrality", {HistType::kTH2F, {PtAxisEff, CentAxis}}}); - binnedRegistry.add({PtEfficiencyIdx.data(), " ; p_{T} (GeV/c); centrality", {HistType::kTH2F, {PtAxisEff, CentAxis}}}); - binnedRegistry.add({PtEfficiencyIdxNoEtaCut.data(), " ; p_{T} (GeV/c); centrality", {HistType::kTH2F, {PtAxisEff, CentAxis}}}); - binnedRegistry.add({PtEfficiencySecondariesIdx.data(), " ; p_{T} (GeV/c); centrality", {HistType::kTH2F, {PtAxisEff, CentAxis}}}); - binnedRegistry.add({PtEfficiencySecondariesIdxNoEtaCut.data(), " ; p_{T} (GeV/c); centrality", {HistType::kTH2F, {PtAxisEff, CentAxis}}}); - binnedRegistry.add({Mask.data(), " ; bit; centrality", {HistType::kTH2F, {{17, -0.5, 16.5}, CentAxis}}}); - binnedRegistry.add({ITSlayers.data(), " ; layer; centrality", {HistType::kTH2F, {{8, 0.5, 8.5}, CentAxis}}}); + binnedRegistry.add({PhiEtaGenDuplicates.data(), "; #varphi; #eta; centrality; occupancy; tracks", {HistType::kTHnSparseF, {PhiAxis, EtaAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({PhiEtaDuplicates.data(), "; #varphi; #eta; centrality; occupancy; tracks", {HistType::kTHnSparseF, {PhiAxis, EtaAxis, CentAxis, OccuAxis}}}); + binnedRegistry.add({PtGenIdx.data(), " ; p_{T} (GeV/c); centrality; occupancy", {HistType::kTHnSparseF, {PtAxisEff, CentAxis, OccuAxis}}}); + binnedRegistry.add({PtGenIdxNoEtaCut.data(), " ; p_{T} (GeV/c); centrality; occupancy", {HistType::kTHnSparseF, {PtAxisEff, CentAxis, OccuAxis}}}); + binnedRegistry.add({PtEfficiencyIdx.data(), " ; p_{T} (GeV/c); centrality; occupancy", {HistType::kTHnSparseF, {PtAxisEff, CentAxis, OccuAxis}}}); + binnedRegistry.add({PtEfficiencyIdxNoEtaCut.data(), " ; p_{T} (GeV/c); centrality; occupancy", {HistType::kTHnSparseF, {PtAxisEff, CentAxis, OccuAxis}}}); + binnedRegistry.add({PtEfficiencySecondariesIdx.data(), " ; p_{T} (GeV/c); centrality; occupancy", {HistType::kTHnSparseF, {PtAxisEff, CentAxis, OccuAxis}}}); + binnedRegistry.add({PtEfficiencySecondariesIdxNoEtaCut.data(), " ; p_{T} (GeV/c); centrality; occupancy", {HistType::kTHnSparseF, {PtAxisEff, CentAxis, OccuAxis}}}); + binnedRegistry.add({Mask.data(), " ; bit; centrality; occupancy", {HistType::kTHnSparseF, {{17, -0.5, 16.5}, CentAxis, OccuAxis}}}); + binnedRegistry.add({ITSlayers.data(), " ; layer; centrality; occupancy", {HistType::kTHnSparseF, {{8, 0.5, 8.5}, CentAxis, OccuAxis}}}); for (auto i = 0u; i < speciesIds.size(); ++i) { - binnedRegistry.add({fmt::format(PtGenIdxF.data(), species[i]).c_str(), " ; p_{T} (GeV/c); centrality", {HistType::kTH2F, {PtAxisEff, CentAxis}}}); - binnedRegistry.add({fmt::format(PtEfficiencyIdxF.data(), species[i]).c_str(), " ; p_{T} (GeV/c); centrality", {HistType::kTH2F, {PtAxisEff, CentAxis}}}); + binnedRegistry.add({fmt::format(PtGenIdxF.data(), species[i]).c_str(), " ; p_{T} (GeV/c); centrality; occupancy", {HistType::kTHnSparseF, {PtAxisEff, CentAxis, OccuAxis}}}); + binnedRegistry.add({fmt::format(PtEfficiencyIdxF.data(), species[i]).c_str(), " ; p_{T} (GeV/c); centrality; occupancy", {HistType::kTHnSparseF, {PtAxisEff, CentAxis, OccuAxis}}}); } } } @@ -323,42 +368,37 @@ struct MultiplicityCounter { template void processEventStatGeneral(FullBCs const& bcs, C const& collisions) { - std::vector::iterator> cols; + std::vector colids; for (auto& bc : bcs) { - if (!useEvSel || (bc.selection_bit(aod::evsel::kNoITSROFrameBorder) && - bc.selection_bit(aod::evsel::kIsBBT0A) && - bc.selection_bit(aod::evsel::kIsBBT0C)) != 0) { + if (!useEvSel || isBCSelected(bc)) { commonRegistry.fill(HIST(BCSelection), 1.); - cols.clear(); + colids.clear(); for (auto& collision : collisions) { if (collision.has_foundBC()) { if (collision.foundBCId() == bc.globalIndex()) { - cols.emplace_back(collision); + colids.push_back(collision.globalIndex()); } } else if (collision.bcId() == bc.globalIndex()) { - cols.emplace_back(collision); + colids.push_back(collision.globalIndex()); } } - LOGP(debug, "BC {} has {} collisions", bc.globalBC(), cols.size()); - if (!cols.empty()) { + LOGP(debug, "BC {} has {} collisions", bc.globalBC(), colids.size()); + if (!colids.empty()) { commonRegistry.fill(HIST(BCSelection), 2.); - if (cols.size() > 1) { + if (colids.size() > 1) { commonRegistry.fill(HIST(BCSelection), 3.); } } - for (auto& col : cols) { - if constexpr (hasRecoCent()) { - float c = -1; - if constexpr (C::template contains()) { - c = col.centFT0C(); - } else if constexpr (C::template contains()) { - c = col.centFT0M(); - } - binnedRegistry.fill(HIST(EventChi2), col.chi2(), c); - binnedRegistry.fill(HIST(EventTimeRes), col.collisionTimeRes(), c); + auto col = collisions.begin(); + for (auto& colid : colids) { + col.moveByIndex(colid - col.globalIndex()); + float c = getRecoCent(c); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(EventChi2), col.chi2(), c, col.trackOccupancyInTimeRange()); + binnedRegistry.fill(HIST(EventTimeRes), col.collisionTimeRes(), c, col.trackOccupancyInTimeRange()); } else { - inclusiveRegistry.fill(HIST(EventChi2), col.chi2()); - inclusiveRegistry.fill(HIST(EventTimeRes), col.collisionTimeRes()); + inclusiveRegistry.fill(HIST(EventChi2), col.chi2(), col.trackOccupancyInTimeRange()); + inclusiveRegistry.fill(HIST(EventTimeRes), col.collisionTimeRes(), col.trackOccupancyInTimeRange()); } } } @@ -422,7 +462,7 @@ struct MultiplicityCounter { Partition pvContribTracksIUEta1 = (nabs(aod::track::eta) < 1.0f) && ((aod::track::flags & (uint32_t)o2::aod::track::PVContributor) == (uint32_t)o2::aod::track::PVContributor); template - int countTracks(T const& tracks, float z, float c) + int countTracks(T const& tracks, float z, float c, float o) { auto Ntrks = 0; for (auto& track : tracks) { @@ -430,18 +470,18 @@ struct MultiplicityCounter { ++Ntrks; } if constexpr (fillHistos) { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(EtaZvtx), track.eta(), z, c); - binnedRegistry.fill(HIST(PhiEta), track.phi(), track.eta(), c); - binnedRegistry.fill(HIST(PtEta), track.pt(), track.eta(), c); - binnedRegistry.fill(HIST(DCAXYPt), track.pt(), track.dcaXY(), c); - binnedRegistry.fill(HIST(DCAZPt), track.pt(), track.dcaZ(), c); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(EtaZvtx), track.eta(), z, c, o); + binnedRegistry.fill(HIST(PhiEta), track.phi(), track.eta(), c, o); + binnedRegistry.fill(HIST(PtEta), track.pt(), track.eta(), c, o); + binnedRegistry.fill(HIST(DCAXYPt), track.pt(), track.dcaXY(), c, o); + binnedRegistry.fill(HIST(DCAZPt), track.pt(), track.dcaZ(), c, o); } else { - inclusiveRegistry.fill(HIST(EtaZvtx), track.eta(), z); - inclusiveRegistry.fill(HIST(PhiEta), track.phi(), track.eta()); - inclusiveRegistry.fill(HIST(PtEta), track.pt(), track.eta()); - inclusiveRegistry.fill(HIST(DCAXYPt), track.pt(), track.dcaXY()); - inclusiveRegistry.fill(HIST(DCAZPt), track.pt(), track.dcaZ()); + inclusiveRegistry.fill(HIST(EtaZvtx), track.eta(), z, o); + inclusiveRegistry.fill(HIST(PhiEta), track.phi(), track.eta(), o); + inclusiveRegistry.fill(HIST(PtEta), track.pt(), track.eta(), o); + inclusiveRegistry.fill(HIST(DCAXYPt), track.pt(), track.dcaXY(), o); + inclusiveRegistry.fill(HIST(DCAZPt), track.pt(), track.dcaZ(), o); } } } @@ -453,23 +493,19 @@ struct MultiplicityCounter { typename C::iterator const& collision, FiTracks const& tracks) { - float c = -1; - if constexpr (hasRecoCent()) { - if constexpr (C::template contains()) { - c = collision.centFT0C(); - } else if (C::template contains()) { - c = collision.centFT0M(); - } - binnedRegistry.fill(HIST(EventSelection), 1., c); + float c = getRecoCent(collision); + float o = collision.trackOccupancyInTimeRange(); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kAll), c, o); } else { - inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kAll)); + inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kAll), o); } if (!useEvSel || isCollisionSelected(collision)) { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(EventSelection), 2., c); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelected), c, o); } else { - inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelected)); + inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelected), o); } auto z = collision.posZ(); usedTracksIds.clear(); @@ -477,39 +513,57 @@ struct MultiplicityCounter { auto groupPVContrib = pvContribTracksIUEta1->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto INELgt0PV = groupPVContrib.size() > 0; - auto Ntrks = countTracks(tracks, z, c); - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(NtrkZvtx), Ntrks, z, c); + auto Ntrks = countTracks(tracks, z, c, o); + if constexpr (has_reco_cent) { + if (Ntrks > 0 || INELgt0PV) { + if (INELgt0PV) { + binnedRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelectedPVgt0), c, o); + } + if (Ntrks > 0) { + binnedRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelectedgt0), c, o); + } + for (auto& track : tracks) { + if (Ntrks > 0) { + binnedRegistry.fill(HIST(EtaZvtx_gt0), track.eta(), z, c, o); + } + if (INELgt0PV) { + binnedRegistry.fill(HIST(EtaZvtx_PVgt0), track.eta(), z, c, o); + } + } + } + binnedRegistry.fill(HIST(NtrkZvtx), Ntrks, z, c, o); + binnedRegistry.fill(HIST(NpvcZvtx), groupPVContrib.size(), z, c, o); } else { if (Ntrks > 0 || INELgt0PV) { if (INELgt0PV) { - inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelectedPVgt0)); + inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelectedPVgt0), o); } if (Ntrks > 0) { - inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelectedgt0)); + inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelectedgt0), o); } for (auto& track : tracks) { if (Ntrks > 0) { - inclusiveRegistry.fill(HIST(EtaZvtx_gt0), track.eta(), z); + inclusiveRegistry.fill(HIST(EtaZvtx_gt0), track.eta(), z, o); } if (INELgt0PV) { - inclusiveRegistry.fill(HIST(EtaZvtx_PVgt0), track.eta(), z); + inclusiveRegistry.fill(HIST(EtaZvtx_PVgt0), track.eta(), z, o); } } } - inclusiveRegistry.fill(HIST(NtrkZvtx), Ntrks, z); + inclusiveRegistry.fill(HIST(NtrkZvtx), Ntrks, z, o); + inclusiveRegistry.fill(HIST(NpvcZvtx), groupPVContrib.size(), z, o); } } else { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(EventSelection), 3., c); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kRejected), c, o); } else { - inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kRejected)); + inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kRejected), o); } } } template - int countTracksAmbiguous(T const& tracks, AT const& atracks, float z, float c) + int countTracksAmbiguous(T const& tracks, AT const& atracks, float z, float c, float o) { auto Ntrks = 0; for (auto& track : atracks) { @@ -531,49 +585,49 @@ struct MultiplicityCounter { ++Ntrks; } if (fillHistos) { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(EtaZvtx), otrack.eta(), z, c); - binnedRegistry.fill(HIST(PhiEta), otrack.phi(), otrack.eta(), c); - binnedRegistry.fill(HIST(PtEta), otrack.pt(), otrack.eta(), c); - binnedRegistry.fill(HIST(DCAXYPt), otrack.pt(), track.bestDCAXY(), c); - binnedRegistry.fill(HIST(DCAZPt), otrack.pt(), track.bestDCAZ(), c); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(EtaZvtx), otrack.eta(), z, c, o); + binnedRegistry.fill(HIST(PhiEta), otrack.phi(), otrack.eta(), c, o); + binnedRegistry.fill(HIST(PtEta), otrack.pt(), otrack.eta(), c, o); + binnedRegistry.fill(HIST(DCAXYPt), otrack.pt(), track.bestDCAXY(), c, o); + binnedRegistry.fill(HIST(DCAZPt), otrack.pt(), track.bestDCAZ(), c, o); } else { - inclusiveRegistry.fill(HIST(EtaZvtx), otrack.eta(), z); - inclusiveRegistry.fill(HIST(PhiEta), otrack.phi(), otrack.eta()); - inclusiveRegistry.fill(HIST(PtEta), otrack.pt(), otrack.eta()); - inclusiveRegistry.fill(HIST(DCAXYPt), otrack.pt(), track.bestDCAXY()); - inclusiveRegistry.fill(HIST(DCAZPt), otrack.pt(), track.bestDCAZ()); + inclusiveRegistry.fill(HIST(EtaZvtx), otrack.eta(), z, o); + inclusiveRegistry.fill(HIST(PhiEta), otrack.phi(), otrack.eta(), o); + inclusiveRegistry.fill(HIST(PtEta), otrack.pt(), otrack.eta(), o); + inclusiveRegistry.fill(HIST(DCAXYPt), otrack.pt(), track.bestDCAXY(), o); + inclusiveRegistry.fill(HIST(DCAZPt), otrack.pt(), track.bestDCAZ(), o); } } if (otrack.has_collision() && otrack.collisionId() != track.bestCollisionId()) { usedTracksIdsDF.emplace_back(track.trackId()); if constexpr (fillHistos) { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(ReassignedEtaZvtx), otrack.eta(), z, c); - binnedRegistry.fill(HIST(ReassignedPhiEta), otrack.phi(), otrack.eta(), c); - binnedRegistry.fill(HIST(ReassignedZvtxCorr), otrack.template collision_as().posZ(), z, c); - binnedRegistry.fill(HIST(ReassignedDCAXYPt), otrack.pt(), track.bestDCAXY(), c); - binnedRegistry.fill(HIST(ReassignedDCAZPt), otrack.pt(), track.bestDCAZ(), c); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(ReassignedEtaZvtx), otrack.eta(), z, c, o); + binnedRegistry.fill(HIST(ReassignedPhiEta), otrack.phi(), otrack.eta(), c, o); + binnedRegistry.fill(HIST(ReassignedZvtxCorr), otrack.template collision_as().posZ(), z, c, o); + binnedRegistry.fill(HIST(ReassignedDCAXYPt), otrack.pt(), track.bestDCAXY(), c, o); + binnedRegistry.fill(HIST(ReassignedDCAZPt), otrack.pt(), track.bestDCAZ(), c, o); } else { - inclusiveRegistry.fill(HIST(ReassignedEtaZvtx), otrack.eta(), z); - inclusiveRegistry.fill(HIST(ReassignedPhiEta), otrack.phi(), otrack.eta()); - inclusiveRegistry.fill(HIST(ReassignedZvtxCorr), otrack.template collision_as().posZ(), z); - inclusiveRegistry.fill(HIST(ReassignedDCAXYPt), otrack.pt(), track.bestDCAXY()); - inclusiveRegistry.fill(HIST(ReassignedDCAZPt), otrack.pt(), track.bestDCAZ()); + inclusiveRegistry.fill(HIST(ReassignedEtaZvtx), otrack.eta(), z, o); + inclusiveRegistry.fill(HIST(ReassignedPhiEta), otrack.phi(), otrack.eta(), o); + inclusiveRegistry.fill(HIST(ReassignedZvtxCorr), otrack.template collision_as().posZ(), z, o); + inclusiveRegistry.fill(HIST(ReassignedDCAXYPt), otrack.pt(), track.bestDCAXY(), o); + inclusiveRegistry.fill(HIST(ReassignedDCAZPt), otrack.pt(), track.bestDCAZ(), o); } } } else if (!otrack.has_collision()) { if constexpr (fillHistos) { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(ExtraEtaZvtx), otrack.eta(), z, c); - binnedRegistry.fill(HIST(ExtraPhiEta), otrack.phi(), otrack.eta(), c); - binnedRegistry.fill(HIST(ExtraDCAXYPt), otrack.pt(), track.bestDCAXY(), c); - binnedRegistry.fill(HIST(ExtraDCAZPt), otrack.pt(), track.bestDCAZ(), c); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(ExtraEtaZvtx), otrack.eta(), z, c, o); + binnedRegistry.fill(HIST(ExtraPhiEta), otrack.phi(), otrack.eta(), c, o); + binnedRegistry.fill(HIST(ExtraDCAXYPt), otrack.pt(), track.bestDCAXY(), c, o); + binnedRegistry.fill(HIST(ExtraDCAZPt), otrack.pt(), track.bestDCAZ(), c, o); } else { - inclusiveRegistry.fill(HIST(ExtraEtaZvtx), otrack.eta(), z); - inclusiveRegistry.fill(HIST(ExtraPhiEta), otrack.phi(), otrack.eta()); - inclusiveRegistry.fill(HIST(ExtraDCAXYPt), otrack.pt(), track.bestDCAXY()); - inclusiveRegistry.fill(HIST(ExtraDCAZPt), otrack.pt(), track.bestDCAZ()); + inclusiveRegistry.fill(HIST(ExtraEtaZvtx), otrack.eta(), z, o); + inclusiveRegistry.fill(HIST(ExtraPhiEta), otrack.phi(), otrack.eta(), o); + inclusiveRegistry.fill(HIST(ExtraDCAXYPt), otrack.pt(), track.bestDCAXY(), o); + inclusiveRegistry.fill(HIST(ExtraDCAZPt), otrack.pt(), track.bestDCAZ(), o); } } } @@ -590,18 +644,18 @@ struct MultiplicityCounter { ++Ntrks; } if constexpr (fillHistos) { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(EtaZvtx), track.eta(), z, c); - binnedRegistry.fill(HIST(PhiEta), track.phi(), track.eta(), c); - binnedRegistry.fill(HIST(PtEta), track.pt(), track.eta(), c); - binnedRegistry.fill(HIST(DCAXYPt), track.pt(), track.dcaXY(), c); - binnedRegistry.fill(HIST(DCAZPt), track.pt(), track.dcaZ(), c); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(EtaZvtx), track.eta(), z, c, o); + binnedRegistry.fill(HIST(PhiEta), track.phi(), track.eta(), c, o); + binnedRegistry.fill(HIST(PtEta), track.pt(), track.eta(), c, o); + binnedRegistry.fill(HIST(DCAXYPt), track.pt(), track.dcaXY(), c, o); + binnedRegistry.fill(HIST(DCAZPt), track.pt(), track.dcaZ(), c, o); } else { - inclusiveRegistry.fill(HIST(EtaZvtx), track.eta(), z); - inclusiveRegistry.fill(HIST(PhiEta), track.phi(), track.eta()); - inclusiveRegistry.fill(HIST(PtEta), track.pt(), track.eta()); - inclusiveRegistry.fill(HIST(DCAXYPt), track.pt(), track.dcaXY()); - inclusiveRegistry.fill(HIST(DCAZPt), track.pt(), track.dcaZ()); + inclusiveRegistry.fill(HIST(EtaZvtx), track.eta(), z, o); + inclusiveRegistry.fill(HIST(PhiEta), track.phi(), track.eta(), o); + inclusiveRegistry.fill(HIST(PtEta), track.pt(), track.eta(), o); + inclusiveRegistry.fill(HIST(DCAXYPt), track.pt(), track.dcaXY(), o); + inclusiveRegistry.fill(HIST(DCAZPt), track.pt(), track.dcaZ(), o); } } } @@ -614,23 +668,19 @@ struct MultiplicityCounter { FiTracks const& tracks, soa::SmallGroups const& atracks) { - float c = -1; - if constexpr (hasRecoCent()) { - if constexpr (C::template contains()) { - c = collision.centFT0C(); - } else if (C::template contains()) { - c = collision.centFT0M(); - } - binnedRegistry.fill(HIST(EventSelection), 1., c); + float c = getRecoCent(collision); + float o = collision.trackOccupancyInTimeRange(); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kAll), c, o); } else { - inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kAll)); + inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kAll), o); } if (!useEvSel || isCollisionSelected(collision)) { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(EventSelection), 2., c); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelected), c, o); } else { - inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelected)); + inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelected), o); } auto z = collision.posZ(); usedTracksIds.clear(); @@ -638,23 +688,54 @@ struct MultiplicityCounter { auto groupPVContrib = pvContribTracksIUEta1->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto INELgt0PV = groupPVContrib.size() > 0; - auto Ntrks = countTracksAmbiguous(tracks, atracks, z, c); - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(NtrkZvtx), Ntrks, z, c); + auto Ntrks = countTracksAmbiguous(tracks, atracks, z, c, o); + if constexpr (has_reco_cent) { + if (Ntrks > 0 || INELgt0PV) { + if (INELgt0PV) { + binnedRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelectedPVgt0), c, o); + } + if (Ntrks > 0) { + binnedRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelectedgt0), c, o); + } + for (auto& track : atracks) { + if (Ntrks > 0) { + binnedRegistry.fill(HIST(EtaZvtx_gt0), track.track_as().eta(), z, c, o); + } + if (INELgt0PV) { + binnedRegistry.fill(HIST(EtaZvtx_PVgt0), track.track_as().eta(), z, c, o); + } + } + for (auto& track : tracks) { + if (std::find(usedTracksIds.begin(), usedTracksIds.end(), track.globalIndex()) != usedTracksIds.end()) { + continue; + } + if (std::find(usedTracksIdsDF.begin(), usedTracksIdsDF.end(), track.globalIndex()) != usedTracksIdsDF.end()) { + continue; + } + if (Ntrks > 0) { + binnedRegistry.fill(HIST(EtaZvtx_gt0), track.eta(), z, c, o); + } + if (INELgt0PV) { + binnedRegistry.fill(HIST(EtaZvtx_PVgt0), track.eta(), z, c, o); + } + } + } + binnedRegistry.fill(HIST(NtrkZvtx), Ntrks, z, c, o); + binnedRegistry.fill(HIST(NpvcZvtx), groupPVContrib.size(), z, c, o); } else { if (Ntrks > 0 || INELgt0PV) { if (INELgt0PV) { - inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelectedPVgt0)); + inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelectedPVgt0), o); } if (Ntrks > 0) { - inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelectedgt0)); + inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelectedgt0), o); } for (auto& track : atracks) { if (Ntrks > 0) { - inclusiveRegistry.fill(HIST(EtaZvtx_gt0), track.track_as().eta(), z); + inclusiveRegistry.fill(HIST(EtaZvtx_gt0), track.track_as().eta(), z, o); } if (INELgt0PV) { - inclusiveRegistry.fill(HIST(EtaZvtx_PVgt0), track.track_as().eta(), z); + inclusiveRegistry.fill(HIST(EtaZvtx_PVgt0), track.track_as().eta(), z, o); } } for (auto& track : tracks) { @@ -665,20 +746,21 @@ struct MultiplicityCounter { continue; } if (Ntrks > 0) { - inclusiveRegistry.fill(HIST(EtaZvtx_gt0), track.eta(), z); + inclusiveRegistry.fill(HIST(EtaZvtx_gt0), track.eta(), z, o); } if (INELgt0PV) { - inclusiveRegistry.fill(HIST(EtaZvtx_PVgt0), track.eta(), z); + inclusiveRegistry.fill(HIST(EtaZvtx_PVgt0), track.eta(), z, o); } } } - inclusiveRegistry.fill(HIST(NtrkZvtx), Ntrks, z); + inclusiveRegistry.fill(HIST(NtrkZvtx), Ntrks, z, o); + inclusiveRegistry.fill(HIST(NpvcZvtx), groupPVContrib.size(), z, o); } } else { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(EventSelection), 3., c); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kRejected), c, o); } else { - inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kRejected)); + inclusiveRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kRejected), o); } } } @@ -770,53 +852,46 @@ struct MultiplicityCounter { if (!collision.has_mcCollision()) { return; } - float c_rec = -1; - float c_gen = -1; - if constexpr (hasRecoCent()) { - if constexpr (C::template contains()) { - c_rec = collision.centFT0C(); - } else if (C::template contains()) { - c_rec = collision.centFT0M(); - } - } + float c_rec = getRecoCent(collision); + float o = collision.trackOccupancyInTimeRange(); auto mcCollision = collision.mcCollision(); - if constexpr (hasSimCent()) { - c_gen = mcCollision.centrality(); - } else if constexpr (hasRecoCent()) { + float c_gen = getSimCent(mcCollision); + if (c_gen < 0 && c_rec >= 0) { c_gen = c_rec; } + auto sample = particles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); for (auto& particle : sample) { if (!isChargedParticle(particle.pdgCode())) { continue; } - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(PtGenIdxNoEtaCut), particle.pt(), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(PtGenIdxNoEtaCut), particle.pt(), c_gen, o); if (std::abs(particle.eta()) < estimatorEta) { - binnedRegistry.fill(HIST(PtGenIdx), particle.pt(), c_gen); + binnedRegistry.fill(HIST(PtGenIdx), particle.pt(), c_gen, o); if (particle.pdgCode() == speciesIds[0]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtGenIdxSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtGenIdxSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[1]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtGenIdxSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtGenIdxSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[2]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtGenIdxSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtGenIdxSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[3]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtGenIdxSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtGenIdxSuff), particle.pt(), c_gen, o); } } } else { - inclusiveRegistry.fill(HIST(PtGenIdxNoEtaCut), particle.pt()); + inclusiveRegistry.fill(HIST(PtGenIdxNoEtaCut), particle.pt(), o); if (std::abs(particle.eta()) < estimatorEta) { - inclusiveRegistry.fill(HIST(PtGenIdx), particle.pt()); + inclusiveRegistry.fill(HIST(PtGenIdx), particle.pt(), o); if (particle.pdgCode() == speciesIds[0]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtGenIdxSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtGenIdxSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[1]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtGenIdxSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtGenIdxSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[2]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtGenIdxSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtGenIdxSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[3]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtGenIdxSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtGenIdxSuff), particle.pt(), o); } } } @@ -828,106 +903,106 @@ struct MultiplicityCounter { auto relatedTracks = particle.template filtered_tracks_as(); for (auto const& track : relatedTracks) { ++counter; - if constexpr (hasRecoCent()) { + if constexpr (has_reco_cent) { if (!countedNoEtaCut) { - binnedRegistry.fill(HIST(PtEfficiencyIdxNoEtaCut), particle.pt(), c_gen); + binnedRegistry.fill(HIST(PtEfficiencyIdxNoEtaCut), particle.pt(), c_gen, o); countedNoEtaCut = true; } if (std::abs(track.eta()) < estimatorEta) { if (!counted) { - binnedRegistry.fill(HIST(PtEfficiencyIdx), particle.pt(), c_gen); + binnedRegistry.fill(HIST(PtEfficiencyIdx), particle.pt(), c_gen, o); if (particle.pdgCode() == speciesIds[0]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtEffIdxSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtEffIdxSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[1]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtEffIdxSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtEffIdxSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[2]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtEffIdxSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtEffIdxSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[3]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtEffIdxSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtEffIdxSuff), particle.pt(), c_gen, o); } counted = true; } } if (counter > 1) { - binnedRegistry.fill(HIST(PtEfficiencySecondariesIdxNoEtaCut), particle.pt(), c_gen); + binnedRegistry.fill(HIST(PtEfficiencySecondariesIdxNoEtaCut), particle.pt(), c_gen, o); if (std::abs(track.eta()) < estimatorEta) { - binnedRegistry.fill(HIST(PtEfficiencySecondariesIdx), particle.pt(), c_gen); + binnedRegistry.fill(HIST(PtEfficiencySecondariesIdx), particle.pt(), c_gen, o); } } } else { if (!countedNoEtaCut) { - inclusiveRegistry.fill(HIST(PtEfficiencyIdxNoEtaCut), particle.pt()); + inclusiveRegistry.fill(HIST(PtEfficiencyIdxNoEtaCut), particle.pt(), o); countedNoEtaCut = true; } if (std::abs(track.eta()) < estimatorEta) { if (!counted) { - inclusiveRegistry.fill(HIST(PtEfficiencyIdx), particle.pt()); + inclusiveRegistry.fill(HIST(PtEfficiencyIdx), particle.pt(), o); if (particle.pdgCode() == speciesIds[0]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtEffIdxSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtEffIdxSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[1]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtEffIdxSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtEffIdxSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[2]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtEffIdxSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtEffIdxSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[3]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtEffIdxSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtEffIdxSuff), particle.pt(), o); } counted = true; } } if (counter > 1) { - inclusiveRegistry.fill(HIST(PtEfficiencySecondariesIdxNoEtaCut), particle.pt()); + inclusiveRegistry.fill(HIST(PtEfficiencySecondariesIdxNoEtaCut), particle.pt(), o); if (std::abs(track.eta()) < estimatorEta) { - inclusiveRegistry.fill(HIST(PtEfficiencySecondariesIdx), particle.pt()); + inclusiveRegistry.fill(HIST(PtEfficiencySecondariesIdx), particle.pt(), o); } } } } - if constexpr (hasRecoCent()) { + if constexpr (has_reco_cent) { for (auto const& track : relatedTracks) { for (auto layer = 0; layer < 7; ++layer) { if (track.itsClusterMap() & (uint8_t(1) << layer)) { - binnedRegistry.fill(HIST(ITSlayers), layer + 1, c_gen); + binnedRegistry.fill(HIST(ITSlayers), layer + 1, c_gen, o); } } auto hasbit = false; for (auto bit = 0; bit < 16; ++bit) { if (track.mcMask() & (uint8_t(1) << bit)) { - binnedRegistry.fill(HIST(Mask), bit, c_gen); + binnedRegistry.fill(HIST(Mask), bit, c_gen, o); hasbit = true; } } if (!hasbit) { - binnedRegistry.fill(HIST(Mask), 16, c_gen); + binnedRegistry.fill(HIST(Mask), 16, c_gen, o); } } if (relatedTracks.size() > 1) { - binnedRegistry.fill(HIST(PhiEtaGenDuplicates), particle.phi(), particle.eta(), c_gen); + binnedRegistry.fill(HIST(PhiEtaGenDuplicates), particle.phi(), particle.eta(), c_gen, o); for (auto const& track : relatedTracks) { - binnedRegistry.fill(HIST(PhiEtaDuplicates), track.phi(), track.eta(), c_gen); + binnedRegistry.fill(HIST(PhiEtaDuplicates), track.phi(), track.eta(), c_gen, o); } } } else { for (auto const& track : relatedTracks) { for (auto layer = 0; layer < 7; ++layer) { if (track.itsClusterMap() & (uint8_t(1) << layer)) { - inclusiveRegistry.fill(HIST(ITSlayers), layer + 1); + inclusiveRegistry.fill(HIST(ITSlayers), layer + 1, o); } } auto hasbit = false; for (auto bit = 0; bit < 16; ++bit) { if (track.mcMask() & (uint8_t(1) << bit)) { - inclusiveRegistry.fill(HIST(Mask), bit); + inclusiveRegistry.fill(HIST(Mask), bit, o); hasbit = true; } } if (!hasbit) { - inclusiveRegistry.fill(HIST(Mask), 16); + inclusiveRegistry.fill(HIST(Mask), 16, o); } } if (relatedTracks.size() > 1) { - inclusiveRegistry.fill(HIST(PhiEtaGenDuplicates), particle.phi(), particle.eta()); + inclusiveRegistry.fill(HIST(PhiEtaGenDuplicates), particle.phi(), particle.eta(), o); for (auto const& track : relatedTracks) { - inclusiveRegistry.fill(HIST(PhiEtaDuplicates), track.phi(), track.eta()); + inclusiveRegistry.fill(HIST(PhiEtaDuplicates), track.phi(), track.eta(), o); } } } @@ -978,19 +1053,11 @@ struct MultiplicityCounter { if (!collision.has_mcCollision()) { return; } - float c_rec = -1; - float c_gen = -1; - if constexpr (hasRecoCent()) { - if constexpr (C::template contains()) { - c_rec = collision.centFT0C(); - } else if (C::template contains()) { - c_rec = collision.centFT0M(); - } - } + float c_rec = getRecoCent(collision); + float o = collision.trackOccupancyInTimeRange(); auto mcCollision = collision.mcCollision(); - if constexpr (hasSimCent()) { - c_gen = mcCollision.centrality(); - } else if constexpr (hasRecoCent()) { + float c_gen = getSimCent(mcCollision); + if (c_gen < 0 && c_rec >= 0) { c_gen = c_rec; } @@ -1005,41 +1072,41 @@ struct MultiplicityCounter { } if (otrack.has_mcParticle()) { auto particle = otrack.mcParticle_as(); - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(PtEfficiencyNoEtaCut), particle.pt(), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(PtEfficiencyNoEtaCut), particle.pt(), c_gen, o); } else { - inclusiveRegistry.fill(HIST(PtEfficiencyNoEtaCut), particle.pt()); + inclusiveRegistry.fill(HIST(PtEfficiencyNoEtaCut), particle.pt(), o); } if (std::abs(otrack.eta()) < estimatorEta) { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(PtEfficiency), particle.pt(), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(PtEfficiency), particle.pt(), c_gen, o); if (particle.pdgCode() == speciesIds[0]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtEffSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtEffSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[1]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtEffSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtEffSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[2]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtEffSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtEffSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[3]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtEffSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtEffSuff), particle.pt(), c_gen, o); } } else { - inclusiveRegistry.fill(HIST(PtEfficiency), particle.pt()); + inclusiveRegistry.fill(HIST(PtEfficiency), particle.pt(), o); if (particle.pdgCode() == speciesIds[0]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtEffSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtEffSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[1]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtEffSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtEffSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[2]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtEffSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtEffSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[3]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtEffSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtEffSuff), particle.pt(), o); } } } } else { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(PtEfficiencyFakes), otrack.pt(), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(PtEfficiencyFakes), otrack.pt(), c_gen, o); } else { - inclusiveRegistry.fill(HIST(PtEfficiencyFakes), otrack.pt()); + inclusiveRegistry.fill(HIST(PtEfficiencyFakes), otrack.pt(), o); } } } @@ -1052,41 +1119,41 @@ struct MultiplicityCounter { } if (track.has_mcParticle()) { auto particle = track.template mcParticle_as(); - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(PtEfficiencyNoEtaCut), particle.pt(), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(PtEfficiencyNoEtaCut), particle.pt(), c_gen, o); } else { - inclusiveRegistry.fill(HIST(PtEfficiencyNoEtaCut), particle.pt()); + inclusiveRegistry.fill(HIST(PtEfficiencyNoEtaCut), particle.pt(), o); } if (std::abs(track.eta()) < estimatorEta) { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(PtEfficiency), particle.pt(), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(PtEfficiency), particle.pt(), c_gen, o); if (particle.pdgCode() == speciesIds[0]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtEffSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtEffSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[1]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtEffSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtEffSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[2]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtEffSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtEffSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[3]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtEffSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtEffSuff), particle.pt(), c_gen, o); } } else { - inclusiveRegistry.fill(HIST(PtEfficiency), particle.pt()); + inclusiveRegistry.fill(HIST(PtEfficiency), particle.pt(), o); if (particle.pdgCode() == speciesIds[0]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtEffSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtEffSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[1]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtEffSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtEffSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[2]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtEffSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtEffSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[3]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtEffSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtEffSuff), particle.pt(), o); } } } } else { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(PtEfficiencyFakes), track.pt(), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(PtEfficiencyFakes), track.pt(), c_gen, o); } else { - inclusiveRegistry.fill(HIST(PtEfficiencyFakes), track.pt()); + inclusiveRegistry.fill(HIST(PtEfficiencyFakes), track.pt(), o); } } } @@ -1095,32 +1162,32 @@ struct MultiplicityCounter { if (!isChargedParticle(particle.pdgCode())) { continue; } - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(PtGenNoEtaCut), particle.pt(), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(PtGenNoEtaCut), particle.pt(), c_gen, o); if (std::abs(particle.eta()) < estimatorEta) { - binnedRegistry.fill(HIST(PtGen), particle.pt(), c_gen); + binnedRegistry.fill(HIST(PtGen), particle.pt(), c_gen, o); if (particle.pdgCode() == speciesIds[0]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtGenSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtGenSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[1]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtGenSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtGenSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[2]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtGenSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtGenSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[3]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtGenSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtGenSuff), particle.pt(), c_gen, o); } } } else { inclusiveRegistry.fill(HIST(PtGenNoEtaCut), particle.pt()); if (std::abs(particle.eta()) < estimatorEta) { - inclusiveRegistry.fill(HIST(PtGen), particle.pt()); + inclusiveRegistry.fill(HIST(PtGen), particle.pt(), o); if (particle.pdgCode() == speciesIds[0]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtGenSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtGenSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[1]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtGenSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtGenSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[2]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtGenSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtGenSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[3]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtGenSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtGenSuff), particle.pt(), o); } } } @@ -1139,19 +1206,11 @@ struct MultiplicityCounter { if (!collision.has_mcCollision()) { return; } - float c_rec = -1; - float c_gen = -1; - if constexpr (hasRecoCent()) { - if constexpr (C::template contains()) { - c_rec = collision.centFT0C(); - } else if (C::template contains()) { - c_rec = collision.centFT0M(); - } - } + float c_rec = getRecoCent(collision); + float o = collision.trackOccupancyInTimeRange(); auto mcCollision = collision.mcCollision(); - if constexpr (hasSimCent()) { - c_gen = mcCollision.centrality(); - } else if constexpr (hasRecoCent()) { + float c_gen = getSimCent(mcCollision); + if (c_gen < 0 && c_rec >= 0) { c_gen = c_rec; } @@ -1161,40 +1220,40 @@ struct MultiplicityCounter { for (auto const& track : tracks) { if (track.has_mcParticle()) { auto particle = track.template mcParticle_as(); - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(PtEfficiencyNoEtaCut), particle.pt(), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(PtEfficiencyNoEtaCut), particle.pt(), c_gen, o); if (std::abs(track.eta()) < estimatorEta) { - binnedRegistry.fill(HIST(PtEfficiency), particle.pt(), c_gen); + binnedRegistry.fill(HIST(PtEfficiency), particle.pt(), c_gen, o); if (particle.pdgCode() == speciesIds[0]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtEffSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtEffSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[1]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtEffSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtEffSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[2]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtEffSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtEffSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[3]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtEffSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtEffSuff), particle.pt(), c_gen, o); } } } else { - inclusiveRegistry.fill(HIST(PtEfficiencyNoEtaCut), particle.pt()); + inclusiveRegistry.fill(HIST(PtEfficiencyNoEtaCut), particle.pt(), o); if (std::abs(track.eta()) < estimatorEta) { - inclusiveRegistry.fill(HIST(PtEfficiency), particle.pt()); + inclusiveRegistry.fill(HIST(PtEfficiency), particle.pt(), o); if (particle.pdgCode() == speciesIds[0]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtEffSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtEffSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[1]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtEffSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtEffSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[2]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtEffSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtEffSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[3]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtEffSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtEffSuff), particle.pt(), o); } } } } else { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(PtEfficiencyFakes), track.pt(), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(PtEfficiencyFakes), track.pt(), c_gen, o); } else { - inclusiveRegistry.fill(HIST(PtEfficiencyFakes), track.pt()); + inclusiveRegistry.fill(HIST(PtEfficiencyFakes), track.pt(), o); } } } @@ -1203,32 +1262,32 @@ struct MultiplicityCounter { if (!isChargedParticle(particle.pdgCode())) { continue; } - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(PtGenNoEtaCut), particle.pt(), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(PtGenNoEtaCut), particle.pt(), c_gen, o); if (std::abs(particle.eta()) < estimatorEta) { - binnedRegistry.fill(HIST(PtGen), particle.pt(), c_gen); + binnedRegistry.fill(HIST(PtGen), particle.pt(), c_gen, o); if (particle.pdgCode() == speciesIds[0]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtGenSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtGenSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[1]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtGenSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtGenSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[2]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtGenSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtGenSuff), particle.pt(), c_gen, o); } else if (particle.pdgCode() == speciesIds[3]) { - binnedRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtGenSuff), particle.pt(), c_gen); + binnedRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtGenSuff), particle.pt(), c_gen, o); } } } else { - inclusiveRegistry.fill(HIST(PtGenNoEtaCut), particle.pt()); + inclusiveRegistry.fill(HIST(PtGenNoEtaCut), particle.pt(), o); if (std::abs(particle.eta()) < estimatorEta) { - inclusiveRegistry.fill(HIST(PtGen), particle.pt()); + inclusiveRegistry.fill(HIST(PtGen), particle.pt(), o); if (particle.pdgCode() == speciesIds[0]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtGenSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[0]) + HIST(PtGenSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[1]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtGenSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[1]) + HIST(PtGenSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[2]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtGenSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[2]) + HIST(PtGenSuff), particle.pt(), o); } else if (particle.pdgCode() == speciesIds[3]) { - inclusiveRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtGenSuff), particle.pt()); + inclusiveRegistry.fill(HIST(prefix) + HIST(species[3]) + HIST(PtGenSuff), particle.pt(), o); } } } @@ -1398,6 +1457,15 @@ struct MultiplicityCounter { return nCharged; } + std::vector NrecPerCol; + std::vector c_recPerCol; + std::vector OccuPerCol; + std::vector NPVPerCol; + std::vector NFT0APerCol; + std::vector NFT0CPerCol; + std::vector NFDDAPerCol; + std::vector NFDDCPerCol; + template void processGenGeneralAmbiguous( typename MC::iterator const& mcCollision, @@ -1405,158 +1473,184 @@ struct MultiplicityCounter { Particles const& particles, FiTracks const& tracks, FiReTracks const& atracks) { float c_gen = -1; - // add generated centrality estimation - if constexpr (hasSimCent()) { - c_gen = mcCollision.centrality(); + if constexpr (has_Centrality) { + c_gen = getSimCent(mcCollision); + } else { + if constexpr (has_FT0C) { + c_gen = getGenCentFT0C(mcCollision); + } else if (has_FT0M) { + c_gen = getGenCentFT0M(mcCollision); + } } + NrecPerCol.clear(); + c_recPerCol.clear(); + OccuPerCol.clear(); + NPVPerCol.clear(); + NFT0APerCol.clear(); + NFT0CPerCol.clear(); + NFDDAPerCol.clear(); + NFDDCPerCol.clear(); + bool atLeastOne = false; bool atLeastOne_gt0 = false; bool atLeastOne_PVgt0 = false; auto moreThanOne = 0; LOGP(debug, "MC col {} has {} reco cols", mcCollision.globalIndex(), collisions.size()); - std::vector NrecPerCol; - std::vector c_recPerCol; - std::vector NPVPerCol; - std::vector NFT0APerCol; - std::vector NFT0CPerCol; - std::vector NFDDAPerCol; - std::vector NFDDCPerCol; + if constexpr (has_reco_cent) { + float min_c_rec = 2e2; + for (auto& collision : collisions) { + if (!useEvSel || isCollisionSelected(collision)) { + float c = getRecoCent(collision); + if (c < min_c_rec) { + min_c_rec = c; + } + } + } + if constexpr (!has_Centrality) { + if (c_gen < 0) { + c_gen = min_c_rec; // if there is no generator centrality info, fall back to reco (from the largest reco collision) + } + } + } + float o_max = -1; + for (auto& collision : collisions) { + if (!useEvSel || isCollisionSelected(collision)) { + auto o = collision.trackOccupancyInTimeRange(); + if (o > o_max) { + o_max = o; + } + } + } for (auto& collision : collisions) { usedTracksIds.clear(); - float c_rec = -1; - if constexpr (hasRecoCent()) { - if constexpr (C::template contains()) { - c_rec = collision.centFT0C(); - } else if (C::template contains()) { - c_rec = collision.centFT0M(); - } - c_recPerCol.emplace_back(c_rec); - binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kRec), c_gen); + float c_rec = getRecoCent(collision); + float o = collision.trackOccupancyInTimeRange(); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kRec), c_gen, o); } else { - inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kRec)); + inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kRec), o); } if (!useEvSel || isCollisionSelected(collision)) { + c_recPerCol.emplace_back(c_rec); + OccuPerCol.emplace_back(o); auto z = collision.posZ(); ++moreThanOne; - if constexpr (hasRecoCent() && !hasSimCent()) { - if (!atLeastOne) { - c_gen = c_rec; // if there is no generator centrality info, fall back to reco (from the first reco collision) - } - } atLeastOne = true; auto groupPVcontrib = pvContribTracksIUEta1->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); if (groupPVcontrib.size() > 0) { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelectedPVgt0), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelectedPVgt0), c_gen, o); } else { - inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelectedPVgt0)); + inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelectedPVgt0), o); } atLeastOne_PVgt0 = true; } auto perCollisionASample = atracks.sliceBy(perColU, collision.globalIndex()); auto perCollisionSample = tracks.sliceBy(perCol, collision.globalIndex()); - auto Nrec = countTracksAmbiguous(perCollisionSample, perCollisionASample, z, c_rec); + auto Nrec = countTracksAmbiguous(perCollisionSample, perCollisionASample, z, c_rec, o); NrecPerCol.emplace_back(Nrec); - NPVPerCol.emplace_back(collision.numContrib()); + NPVPerCol.emplace_back(groupPVcontrib.size()); fillFIT(collision, NFT0APerCol, NFT0CPerCol, NFDDAPerCol, NFDDCPerCol); - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelected), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelected), c_gen, o); } else { - inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelected)); + inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelected), o); } if (Nrec > 0) { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelectedgt0), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelectedgt0), c_gen, o); } else { - inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelectedgt0)); + inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelectedgt0), o); } atLeastOne_gt0 = true; } - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(NtrkZvtxGen), Nrec, collision.posZ(), c_rec); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(NtrkZvtxGen), Nrec, collision.posZ(), c_rec, o); + binnedRegistry.fill(HIST(NpvcZvxtGen), groupPVcontrib.size(), collision.posZ(), c_rec, o); } else { inclusiveRegistry.fill(HIST(NtrkZvtxGen), Nrec, collision.posZ()); + inclusiveRegistry.fill(HIST(NpvcZvxtGen), groupPVcontrib.size(), collision.posZ(), o); } } } auto nCharged = countParticles(particles); - if constexpr (hasRecoCent()) { + if constexpr (has_reco_cent) { binnedRegistry.fill(HIST(NtrkZvtxGen_t), nCharged, mcCollision.posZ(), c_gen); - binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kGen), c_gen); + binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kGen), c_gen, o_max); } else { - if constexpr (soa::is_soa_join_v) { - if constexpr (MC::template contains()) { - if (useProcId) { - inclusiveRegistry.fill(HIST(NtrkZvtxGen_t), nCharged, mcCollision.posZ(), mcCollision.processId()); - } else { - inclusiveRegistry.fill(HIST(NtrkZvtxGen_t), nCharged, mcCollision.posZ()); - } + inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kGen), o_max); + if (useProcId) { + if constexpr (has_hepmc_pid) { + inclusiveRegistry.fill(HIST(NtrkZvtxGen_t), nCharged, mcCollision.posZ(), mcCollision.processId()); } else { - inclusiveRegistry.fill(HIST(NtrkZvtxGen_t), nCharged, mcCollision.posZ()); + LOGP(fatal, "useProcId = true, but MC collision does not have HepMC info"); } } else { inclusiveRegistry.fill(HIST(NtrkZvtxGen_t), nCharged, mcCollision.posZ()); } - inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kGen)); } if (nCharged > 0) { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kGengt0), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kGengt0), c_gen, o_max); } else { - inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kGengt0)); + inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kGengt0), o_max); } } if (fillResponse) { for (auto i = 0U; i < NrecPerCol.size(); ++i) { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ(), c_recPerCol[i]); + if constexpr (has_reco_cent) { + if (useProcId) { + if constexpr (has_hepmc_pid) { + binnedRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ(), c_recPerCol[i], mcCollision.processId()); + } else { + LOGP(fatal, "useProcId = true, but MC collision does not have HepMC info"); + } + } else { + binnedRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ(), c_recPerCol[i]); + } if (addFT0 && !addFDD) { - binnedRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFT0APerCol[i], NFT0CPerCol[i], mcCollision.posZ(), c_recPerCol[i]); + binnedRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFT0APerCol[i], NFT0CPerCol[i], mcCollision.posZ(), c_recPerCol[i], OccuPerCol[i]); } else if (addFDD && !addFT0) { - binnedRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFDDAPerCol[i], NFDDCPerCol[i], mcCollision.posZ(), c_recPerCol[i]); + binnedRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFDDAPerCol[i], NFDDCPerCol[i], mcCollision.posZ(), c_recPerCol[i], OccuPerCol[i]); } else if (addFT0 && addFDD) { - binnedRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFT0APerCol[i], NFT0CPerCol[i], NFDDAPerCol[i], NFDDCPerCol[i], mcCollision.posZ(), c_recPerCol[i]); + binnedRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFT0APerCol[i], NFT0CPerCol[i], NFDDAPerCol[i], NFDDCPerCol[i], mcCollision.posZ(), c_recPerCol[i], OccuPerCol[i]); } else { - binnedRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, mcCollision.posZ(), c_recPerCol[i]); + binnedRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, mcCollision.posZ(), c_recPerCol[i], OccuPerCol[i]); } } else { - if constexpr (soa::is_soa_join_v) { - if constexpr (MC::template contains()) { - if (useProcId) { - inclusiveRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ(), mcCollision.processId()); - } else { - inclusiveRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ()); - } + if (useProcId) { + if constexpr (has_hepmc_pid) { + inclusiveRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ(), mcCollision.processId()); } else { - inclusiveRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ()); + LOGP(fatal, "useProcId = true, but MC collision does not have HepMC info"); } } else { inclusiveRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ()); } if (addFT0 && !addFDD) { - inclusiveRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFT0APerCol[i], NFT0CPerCol[i], mcCollision.posZ()); + inclusiveRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFT0APerCol[i], NFT0CPerCol[i], mcCollision.posZ(), OccuPerCol[i]); } else if (addFDD && !addFT0) { - inclusiveRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFDDAPerCol[i], NFDDCPerCol[i], mcCollision.posZ()); + inclusiveRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFDDAPerCol[i], NFDDCPerCol[i], mcCollision.posZ(), OccuPerCol[i]); } else if (addFT0 && addFDD) { - inclusiveRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFT0APerCol[i], NFT0CPerCol[i], NFDDAPerCol[i], NFDDCPerCol[i], mcCollision.posZ()); + inclusiveRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFT0APerCol[i], NFT0CPerCol[i], NFDDAPerCol[i], NFDDCPerCol[i], mcCollision.posZ(), OccuPerCol[i]); } else { - inclusiveRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, mcCollision.posZ()); + inclusiveRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, mcCollision.posZ(), OccuPerCol[i]); } } } if (moreThanOne > 1) { - if constexpr (hasRecoCent()) { + if constexpr (has_reco_cent) { binnedRegistry.fill(HIST(SplitMult), nCharged, mcCollision.posZ(), c_gen); } else { inclusiveRegistry.fill(HIST(SplitMult), nCharged, mcCollision.posZ()); @@ -1565,7 +1659,7 @@ struct MultiplicityCounter { } if (collisions.size() == 0) { - if constexpr (hasRecoCent()) { + if constexpr (has_reco_cent) { binnedRegistry.fill(HIST(NotFoundZvtx), mcCollision.posZ(), c_gen); } else { inclusiveRegistry.fill(HIST(NotFoundZvtx), mcCollision.posZ()); @@ -1573,7 +1667,7 @@ struct MultiplicityCounter { } auto zmc = mcCollision.posZ(); - fillParticleHistos()>(particles, zmc, nCharged, c_gen, atLeastOne, atLeastOne_gt0, atLeastOne_PVgt0); + fillParticleHistos>(particles, zmc, nCharged, c_gen, atLeastOne, atLeastOne_gt0, atLeastOne_PVgt0); } template @@ -1583,9 +1677,14 @@ struct MultiplicityCounter { Particles const& particles, FiTracks const& tracks) { float c_gen = -1; - // add generated centrality estimation - if constexpr (hasSimCent()) { - c_gen = mcCollision.centrality(); + if constexpr (has_Centrality) { + c_gen = getSimCent(mcCollision); + } else { + if constexpr (has_FT0C) { + c_gen = getGenCentFT0C(mcCollision); + } else if (has_FT0M) { + c_gen = getGenCentFT0M(mcCollision); + } } bool atLeastOne = false; @@ -1594,146 +1693,166 @@ struct MultiplicityCounter { auto moreThanOne = 0; LOGP(debug, "MC col {} has {} reco cols", mcCollision.globalIndex(), collisions.size()); - std::vector NrecPerCol; - std::vector c_recPerCol; - std::vector NPVPerCol; - std::vector NFT0APerCol; - std::vector NFT0CPerCol; - std::vector NFDDAPerCol; - std::vector NFDDCPerCol; + NrecPerCol.clear(); + c_recPerCol.clear(); + OccuPerCol.clear(); + NPVPerCol.clear(); + NFT0APerCol.clear(); + NFT0CPerCol.clear(); + NFDDAPerCol.clear(); + NFDDCPerCol.clear(); + + if constexpr (has_reco_cent) { + float min_c_rec = 2e2; + for (auto& collision : collisions) { + if (!useEvSel || isCollisionSelected(collision)) { + float c = getRecoCent(collision); + if (c < min_c_rec) { + min_c_rec = c; + } + } + } + if constexpr (!has_Centrality) { + if (c_gen < 0) { + c_gen = min_c_rec; // if there is no generator centrality info, fall back to reco (from the largest reco collision) + } + } + } + float o_max = -1; + for (auto& collision : collisions) { + if (!useEvSel || isCollisionSelected(collision)) { + auto o = collision.trackOccupancyInTimeRange(); + if (o > o_max) { + o_max = o; + } + } + } for (auto& collision : collisions) { usedTracksIds.clear(); - float c_rec = -1; - if constexpr (hasRecoCent()) { - if constexpr (C::template contains()) { - c_rec = collision.centFT0C(); - } else if (C::template contains()) { - c_rec = collision.centFT0M(); - } - c_recPerCol.emplace_back(c_rec); - binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kRec), c_gen); + float c_rec = getRecoCent(collision); + float o = collision.trackOccupancyInTimeRange(); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kRec), c_gen, o); } else { - inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kRec)); + inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kRec), o); } if (!useEvSel || isCollisionSelected(collision)) { + c_recPerCol.emplace_back(c_rec); auto z = collision.posZ(); ++moreThanOne; - if constexpr (hasRecoCent() && !hasSimCent()) { - if (!atLeastOne) { - c_gen = c_rec; // if there is no generator centrality info, fall back to reco (from the first reco collision) - } - } atLeastOne = true; auto groupPVcontrib = pvContribTracksIUEta1->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); if (groupPVcontrib.size() > 0) { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelectedPVgt0), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelectedPVgt0), c_gen, o); } else { - inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelectedPVgt0)); + inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelectedPVgt0), o); } atLeastOne_PVgt0 = true; } auto perCollisionSample = tracks.sliceBy(perCol, collision.globalIndex()); - auto Nrec = countTracks(perCollisionSample, z, c_rec); + auto Nrec = countTracks(perCollisionSample, z, c_rec, o); NrecPerCol.emplace_back(Nrec); - NPVPerCol.emplace_back(collision.numContrib()); + NPVPerCol.emplace_back(groupPVcontrib.size()); fillFIT(collision, NFT0APerCol, NFT0CPerCol, NFDDAPerCol, NFDDCPerCol); - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelected), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelected), c_gen, o); } else { - inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelected)); + inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelected), o); } if (Nrec > 0) { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelectedgt0), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelectedgt0), c_gen, o); } else { - inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelectedgt0)); + inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kSelectedgt0), o); } atLeastOne_gt0 = true; } - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(NtrkZvtxGen), Nrec, collision.posZ(), c_rec); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(NtrkZvtxGen), Nrec, collision.posZ(), c_rec, o); + binnedRegistry.fill(HIST(NpvcZvxtGen), groupPVcontrib.size(), collision.posZ(), c_rec, o); } else { - inclusiveRegistry.fill(HIST(NtrkZvtxGen), Nrec, collision.posZ()); + inclusiveRegistry.fill(HIST(NtrkZvtxGen), Nrec, collision.posZ(), o); + inclusiveRegistry.fill(HIST(NpvcZvxtGen), groupPVcontrib.size(), collision.posZ(), o); } } } auto nCharged = countParticles(particles); - if constexpr (hasRecoCent()) { + if constexpr (has_reco_cent) { binnedRegistry.fill(HIST(NtrkZvtxGen_t), nCharged, mcCollision.posZ(), c_gen); - binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kGen), c_gen); + binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kGen), c_gen, o_max); } else { - if constexpr (soa::is_soa_join_v) { - if constexpr (MC::template contains()) { - if (useProcId) { - inclusiveRegistry.fill(HIST(NtrkZvtxGen_t), nCharged, mcCollision.posZ(), mcCollision.processId()); - } else { - inclusiveRegistry.fill(HIST(NtrkZvtxGen_t), nCharged, mcCollision.posZ()); - } + inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kGen), o_max); + if (useProcId) { + if constexpr (has_hepmc_pid) { + inclusiveRegistry.fill(HIST(NtrkZvtxGen_t), nCharged, mcCollision.posZ(), mcCollision.processId()); } else { - inclusiveRegistry.fill(HIST(NtrkZvtxGen_t), nCharged, mcCollision.posZ()); + LOGP(fatal, "useProcId = true, but MC collision does not have HepMC info"); } } else { inclusiveRegistry.fill(HIST(NtrkZvtxGen_t), nCharged, mcCollision.posZ()); } - inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kGen)); } if (nCharged > 0) { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kGengt0), c_gen); + if constexpr (has_reco_cent) { + binnedRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kGengt0), c_gen, o_max); } else { - inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kGengt0)); + inclusiveRegistry.fill(HIST(Efficiency), static_cast(EvEffBins::kGengt0), o_max); } } if (fillResponse) { for (auto i = 0U; i < NrecPerCol.size(); ++i) { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ(), c_recPerCol[i]); + if constexpr (has_reco_cent) { + if (useProcId) { + if constexpr (has_hepmc_pid) { + binnedRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ(), c_recPerCol[i], mcCollision.processId()); + } else { + LOGP(fatal, "useProcId = true, but MC collision does not have HepMC info"); + } + } else { + binnedRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ(), c_recPerCol[i]); + } if (addFT0 && !addFDD) { - binnedRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFT0APerCol[i], NFT0CPerCol[i], mcCollision.posZ(), c_recPerCol[i]); + binnedRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFT0APerCol[i], NFT0CPerCol[i], mcCollision.posZ(), c_recPerCol[i], OccuPerCol[i]); } else if (addFDD && !addFT0) { - binnedRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFDDAPerCol[i], NFDDCPerCol[i], mcCollision.posZ(), c_recPerCol[i]); + binnedRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFDDAPerCol[i], NFDDCPerCol[i], mcCollision.posZ(), c_recPerCol[i], OccuPerCol[i]); } else if (addFT0 && addFDD) { - binnedRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFT0APerCol[i], NFT0CPerCol[i], NFDDAPerCol[i], NFDDCPerCol[i], mcCollision.posZ(), c_recPerCol[i]); + binnedRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFT0APerCol[i], NFT0CPerCol[i], NFDDAPerCol[i], NFDDCPerCol[i], mcCollision.posZ(), c_recPerCol[i], OccuPerCol[i]); } else { - binnedRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, mcCollision.posZ(), c_recPerCol[i]); + binnedRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, mcCollision.posZ(), c_recPerCol[i], OccuPerCol[i]); } } else { - if constexpr (soa::is_soa_join_v) { - if constexpr (MC::template contains()) { - if (useProcId) { - inclusiveRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ(), mcCollision.processId()); - } else { - inclusiveRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ()); - } + if (useProcId) { + if constexpr (has_hepmc_pid) { + inclusiveRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ(), mcCollision.processId()); } else { - inclusiveRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ()); + LOGP(fatal, "useProcId = true, but MC collision does not have HepMC info"); } } else { inclusiveRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ()); } if (addFT0 && !addFDD) { - inclusiveRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFT0APerCol[i], NFT0CPerCol[i], mcCollision.posZ()); + inclusiveRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFT0APerCol[i], NFT0CPerCol[i], mcCollision.posZ(), OccuPerCol[i]); } else if (addFDD && !addFT0) { - inclusiveRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFDDAPerCol[i], NFDDCPerCol[i], mcCollision.posZ()); + inclusiveRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFDDAPerCol[i], NFDDCPerCol[i], mcCollision.posZ(), OccuPerCol[i]); } else if (addFT0 && addFDD) { - inclusiveRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFT0APerCol[i], NFT0CPerCol[i], NFDDAPerCol[i], NFDDCPerCol[i], mcCollision.posZ()); + inclusiveRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, NFT0APerCol[i], NFT0CPerCol[i], NFDDAPerCol[i], NFDDCPerCol[i], mcCollision.posZ(), OccuPerCol[i]); } else { - inclusiveRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, mcCollision.posZ()); + inclusiveRegistry.fill(HIST(Response), NrecPerCol[i], NPVPerCol[i], nCharged, mcCollision.posZ(), OccuPerCol[i]); } } } if (moreThanOne > 1) { - if constexpr (hasRecoCent()) { + if constexpr (has_reco_cent) { binnedRegistry.fill(HIST(SplitMult), nCharged, mcCollision.posZ(), c_gen); } else { inclusiveRegistry.fill(HIST(SplitMult), nCharged, mcCollision.posZ()); @@ -1742,14 +1861,14 @@ struct MultiplicityCounter { } if (collisions.size() == 0) { - if constexpr (hasRecoCent()) { + if constexpr (has_reco_cent) { binnedRegistry.fill(HIST(NotFoundZvtx), mcCollision.posZ(), c_gen); } else { inclusiveRegistry.fill(HIST(NotFoundZvtx), mcCollision.posZ()); } } auto zmc = mcCollision.posZ(); - fillParticleHistos()>(particles, zmc, nCharged, c_gen, atLeastOne, atLeastOne_gt0, atLeastOne_PVgt0); + fillParticleHistos>(particles, zmc, nCharged, c_gen, atLeastOne, atLeastOne_gt0, atLeastOne_PVgt0); } using MC = aod::McCollisions; // soa::Join; @@ -1814,6 +1933,46 @@ struct MultiplicityCounter { PROCESS_SWITCH(MultiplicityCounter, processGenFT0C, "Process generator-level info (FT0C centrality) w/o ambiguous", false); + void processGenAmbiguousFT0Cplus( + soa::Join::iterator const& mcCollision, + o2::soa::SmallGroups> const& collisions, + Particles const& particles, FiTracks const& tracks, FiReTracks const& atracks, aod::FT0s const&, aod::FDDs const&) + { + processGenGeneralAmbiguous, ExColsCentFT0C>(mcCollision, collisions, particles, tracks, atracks); + } + + PROCESS_SWITCH(MultiplicityCounter, processGenAmbiguousFT0Cplus, "Process generator-level info (FT0C centrality + gen level)", false); + + void processGenFT0Cplus( + soa::Join::iterator const& mcCollision, + o2::soa::SmallGroups> const& collisions, + Particles const& particles, FiTracks const& tracks, aod::FT0s const&, aod::FDDs const&) + { + processGenGeneral, ExColsCentFT0C>(mcCollision, collisions, particles, tracks); + } + + PROCESS_SWITCH(MultiplicityCounter, processGenFT0Cplus, "Process generator-level info (FT0C centrality + gen level) w/o ambiguous", false); + + void processGenAmbiguousExFT0C( + MCex::iterator const& mcCollision, + o2::soa::SmallGroups> const& collisions, + Particles const& particles, FiTracks const& tracks, FiReTracks const& atracks, aod::FT0s const&, aod::FDDs const&) + { + processGenGeneralAmbiguous(mcCollision, collisions, particles, tracks, atracks); + } + + PROCESS_SWITCH(MultiplicityCounter, processGenAmbiguousExFT0C, "Process generator-level info (FT0C centrality)", false); + + void processGenExFT0C( + MCex::iterator const& mcCollision, + o2::soa::SmallGroups> const& collisions, + Particles const& particles, FiTracks const& tracks, aod::FT0s const&, aod::FDDs const&) + { + processGenGeneral(mcCollision, collisions, particles, tracks); + } + + PROCESS_SWITCH(MultiplicityCounter, processGenExFT0C, "Process generator-level info (FT0C centrality) w/o ambiguous", false); + void processGenAmbiguousFT0M( MC::iterator const& mcCollision, o2::soa::SmallGroups> const& collisions, @@ -1834,6 +1993,46 @@ struct MultiplicityCounter { PROCESS_SWITCH(MultiplicityCounter, processGenFT0M, "Process generator-level info (FT0M centrality) w/o ambiguous", false); + void processGenAmbiguousFT0Mplus( + soa::Join::iterator const& mcCollision, + o2::soa::SmallGroups> const& collisions, + Particles const& particles, FiTracks const& tracks, FiReTracks const& atracks, aod::FT0s const&, aod::FDDs const&) + { + processGenGeneralAmbiguous, ExColsCentFT0M>(mcCollision, collisions, particles, tracks, atracks); + } + + PROCESS_SWITCH(MultiplicityCounter, processGenAmbiguousFT0Mplus, "Process generator-level info (FT0M centrality + gen level)", false); + + void processGenFT0Mplus( + soa::Join::iterator const& mcCollision, + o2::soa::SmallGroups> const& collisions, + Particles const& particles, FiTracks const& tracks, aod::FT0s const&, aod::FDDs const&) + { + processGenGeneral, ExColsCentFT0M>(mcCollision, collisions, particles, tracks); + } + + PROCESS_SWITCH(MultiplicityCounter, processGenFT0Mplus, "Process generator-level info (FT0M centrality + gen level) w/o ambiguous", false); + + void processGenAmbiguousExFT0M( + MCex::iterator const& mcCollision, + o2::soa::SmallGroups> const& collisions, + Particles const& particles, FiTracks const& tracks, FiReTracks const& atracks, aod::FT0s const&, aod::FDDs const&) + { + processGenGeneralAmbiguous(mcCollision, collisions, particles, tracks, atracks); + } + + PROCESS_SWITCH(MultiplicityCounter, processGenAmbiguousExFT0M, "Process generator-level info (FT0M centrality)", false); + + void processGenExFT0M( + MCex::iterator const& mcCollision, + o2::soa::SmallGroups> const& collisions, + Particles const& particles, FiTracks const& tracks, aod::FT0s const&, aod::FDDs const&) + { + processGenGeneral(mcCollision, collisions, particles, tracks); + } + + PROCESS_SWITCH(MultiplicityCounter, processGenExFT0M, "Process generator-level info (FT0M centrality) w/o ambiguous", false); + using MChi = soa::Join; void processGenAmbiguousFT0Chi( diff --git a/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx b/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx new file mode 100644 index 00000000000..13ae6acbc83 --- /dev/null +++ b/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx @@ -0,0 +1,2153 @@ +// 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 dndetaMFTPbPb.cxx +/// \brief Task for calculating dNdeta in Pb-Pb collisions using MFT detector +/// \author Gyula Bencedi, gyula.bencedi@cern.ch +/// \since Nov 2024 + +#include +#include +#include +#include +#include +#include + +#include "CCDB/BasicCCDBManager.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RuntimeError.h" +#include "Framework/runDataProcessing.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "CommonConstants/MathConstants.h" + +#include "MathUtils/Utils.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "TPDGCode.h" + +#include "Functions.h" +#include "Index.h" +#include "bestCollisionTable.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::track; +using namespace o2::aod::fwdtrack; +using namespace o2::constants::physics; +using namespace o2::constants::math; +using namespace pwgmm::mult; + +AxisSpec ptAxis = {1001, -0.005, 10.005}; +AxisSpec multAxis = {701, -0.5, 700.5, "N_{trk}"}; +AxisSpec zAxis = {60, -30., 30.}; +AxisSpec deltaZAxis = {61, -6.1, 6.1}; +AxisSpec dcaxyAxis = {500, -1, 50}; +AxisSpec phiAxis = {629, 0, TwoPI, "Rad", "#phi"}; +AxisSpec etaAxis = {20, -4., -2.}; +AxisSpec centAxis{100, 0, 100, "centrality"}; + +struct DndetaMFTPbPb { + SliceCache cache; + + enum OccupancyEst { TrkITS = 1, + Ft0C }; + + HistogramRegistry registry{ + "registry", + {}, + OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry qaregistry{ + "qaregistry", + {}, + OutputObjHandlingPolicy::AnalysisObject, + false, + true}; + + struct : ConfigurableGroup { + Configurable usephiCut{"usephiCut", false, "use azimuthal angle cut"}; + Configurable phiCut{"phiCut", 0.1f, + "Cut on azimuthal angle of MFT tracks"}; + Configurable minPhi{"minPhi", 0.f, ""}; + Configurable maxPhi{"maxPhi", 6.2832, ""}; + Configurable minEta{"minEta", -3.6f, ""}; + Configurable maxEta{"maxEta", -2.5f, ""}; + Configurable minNclusterMft{"minNclusterMft", 5, + "minimum number of MFT clusters"}; + Configurable minPt{"minPt", 0., "minimum pT of the MFT tracks"}; + Configurable requireCA{ + "requireCA", false, "Use Cellular Automaton track-finding algorithm"}; + Configurable maxDCAxy{"maxDCAxy", 2.0f, "Cut on dcaXY"}; + } trackCuts; + + struct : ConfigurableGroup { + Configurable maxZvtx{"maxZvtx", 10.0f, "Cut on z-vtx"}; + Configurable useZDiffCut{"useZDiffCut", false, + "use Zvtx reco-mc diff. cut"}; + Configurable maxZvtxDiff{ + "maxZvtxDiff", 1.0f, + "max allowed Z vtx difference for reconstruced collisions (cm)"}; + Configurable requireNoCollInTimeRangeStd{ + "requireNoCollInTimeRangeStd", false, + "reject collisions corrupted by the cannibalism, with other collisions " + "within +/- 10 microseconds"}; + Configurable requireNoCollInTimeRangeNarrow{ + "requireNoCollInTimeRangeNarrow", false, + "reject collisions corrupted by the cannibalism, with other collisions " + "within +/- 10 microseconds"}; + Configurable occupancyEstimator{ + "occupancyEstimator", 1, + "Occupancy estimator: 1 = trackOccupancyInTimeRange, 2 = " + "ft0cOccupancyInTimeRange"}; + Configurable minOccupancy{ + "minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; + Configurable maxOccupancy{ + "maxOccupancy", -1, "maximum occupancy from neighbouring collisions"}; + Configurable minIR{"minIR", -1, "minimum IR (kHz) collisions"}; + Configurable maxIR{"maxIR", -1, "maximum IR (kHz) collisions"}; + } eventCuts; + + ConfigurableAxis occupancyBins{"occupancyBins", + {VARIABLE_WIDTH, 0.0f, 250.0f, 500.0f, 750.0f, + 1000.0f, 1500.0f, 2000.0f, 3000.0f, 4500.0f, + 6000.0f, 8000.0f, 10000.0f, 50000.0f}, + "Occupancy"}; + ConfigurableAxis centralityBins{ + "centralityBins", + {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}, + "Centrality"}; + ConfigurableAxis irBins{"irBins", {500, 0, 50}, "Interaction rate (kHz)"}; + + Service pdg; + + Service ccdb; + Configurable ccdbNoLaterThan{ + "ccdbNoLaterThan", + std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(), + "latest acceptable timestamp of creation for the object"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", + "url of the ccdb repository"}; + ctpRateFetcher rateFetcher; + + /// @brief init function, definition of histograms + void init(InitContext&) + { + ccdb->setURL(ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(ccdbNoLaterThan.value); + ccdb->setFatalWhenNull(false); + + if (static_cast(doprocessDataInclusive) + + static_cast(doprocessDatawBestTracksInclusive) > + 1) { + LOGP(fatal, + "Either processDataInclusive OR " + "processDatawBestTracksInclusive should be enabled!"); + } + if ((static_cast(doprocessDataCentFT0C) + + static_cast(doprocessDatawBestTracksCentFT0C) > + 1) || + (static_cast(doprocessDataCentFT0CVariant1) + + static_cast(doprocessDatawBestTracksCentFT0CVariant1) > + 1) || + (static_cast(doprocessDataCentFT0M) + + static_cast(doprocessDatawBestTracksCentFT0M) > + 1) || + (static_cast(doprocessDataCentNGlobal) + + static_cast(doprocessDatawBestTracksCentNGlobal) > + 1) || + (static_cast(doprocessDataCentMFT) + + static_cast(doprocessDatawBestTracksCentMFT) > + 1)) { + LOGP(fatal, + "Either processDataCent[ESTIMATOR] OR " + "processDatawBestTracksCent[ESTIMATOR] should " + "be enabled!"); + } + if (static_cast(doprocessMCInclusive) + + static_cast(doprocessMCwBestTracksInclusive) > + 1) { + LOGP(fatal, + "Either processMCInclusive OR processMCwBestTracksInclusive " + "should be enabled!"); + } + if ((static_cast(doprocessMCCentFT0C) + + static_cast(doprocessMCwBestTracksCentFT0C) > + 1) || + (static_cast(doprocessMCCentFT0CVariant1) + + static_cast(doprocessMCwBestTracksCentFT0CVariant1) > + 1) || + (static_cast(doprocessMCCentFT0M) + + static_cast(doprocessMCwBestTracksCentFT0M) > + 1) || + (static_cast(doprocessMCCentNGlobal) + + static_cast(doprocessMCwBestTracksCentNGlobal) > + 1) || + (static_cast(doprocessMCCentMFT) + + static_cast(doprocessMCwBestTracksCentMFT) > + 1)) { + LOGP(fatal, + "Either processMCCent[ESTIMATOR] OR " + "processMCwBestTracksCent[ESTIMATOR] should " + "be enabled!"); + } + + auto hev = registry.add("hEvtSel", "hEvtSel", HistType::kTH1F, + {{12, -0.5f, +11.5f}}); + hev->GetXaxis()->SetBinLabel(1, "All collisions"); + hev->GetXaxis()->SetBinLabel(2, "Ev. sel."); + hev->GetXaxis()->SetBinLabel(3, "kIsGoodZvtxFT0vsPV"); + hev->GetXaxis()->SetBinLabel(4, "NoSameBunchPileup"); + hev->GetXaxis()->SetBinLabel(5, "Z-vtx cut"); + hev->GetXaxis()->SetBinLabel(6, "kNoCollInTimeRangeStd"); + hev->GetXaxis()->SetBinLabel(7, "kNoCollInTimeRangeNarrow"); + hev->GetXaxis()->SetBinLabel(8, "Below min occup."); + hev->GetXaxis()->SetBinLabel(9, "Above max occup."); + hev->GetXaxis()->SetBinLabel(10, "Below min IR (kHz)"); + hev->GetXaxis()->SetBinLabel(11, "Above max IR (kHz)"); + + auto hBcSel = registry.add("hBcSel", "hBcSel", HistType::kTH1F, + {{3, -0.5f, +2.5f}}); + hBcSel->GetXaxis()->SetBinLabel(1, "Good BCs"); + hBcSel->GetXaxis()->SetBinLabel(2, "BCs with collisions"); + hBcSel->GetXaxis()->SetBinLabel(3, "BCs with pile-up/splitting"); + + AxisSpec centralityAxis = {centralityBins, "Centrality", "centralityAxis"}; + AxisSpec occupancyAxis = {occupancyBins, "Occupancy", "occupancyAxis"}; + + if (doprocessDataInclusive || doprocessDatawBestTracksInclusive || + doprocessMCInclusive || doprocessMCwBestTracksInclusive) { + registry.add({"Events/Selection", + ";status;occupancy", + {HistType::kTH2F, {{2, 0.5, 2.5}, occupancyAxis}}}); + auto hstat = registry.get(HIST("Events/Selection")); + auto* x = hstat->GetXaxis(); + x->SetBinLabel(1, "All"); + x->SetBinLabel(2, "Selected"); + + qaregistry.add("hOccIRate", "hOccIRate", HistType::kTH2F, + {occupancyAxis, irBins}); + + registry.add({"Events/NtrkZvtx", + "; N_{trk}; Z_{vtx} (cm); occupancy", + {HistType::kTHnSparseF, {multAxis, zAxis, occupancyAxis}}}); + registry.add({"Tracks/EtaZvtx", + "; #eta; Z_{vtx} (cm); occupancy", + {HistType::kTHnSparseF, {etaAxis, zAxis, occupancyAxis}}}); + registry.add( + {"Tracks/PhiEta", + "; #varphi; #eta; occupancy", + {HistType::kTHnSparseF, {phiAxis, etaAxis, occupancyAxis}}}); + + qaregistry.add( + {"Tracks/Chi2Eta", + "; #chi^{2}; #it{#eta}; occupancy", + {HistType::kTHnSparseF, {{600, 0, 20}, etaAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/Chi2", + "; #chi^{2};", + {HistType::kTH2F, {{600, 0, 20}, occupancyAxis}}}); + qaregistry.add( + {"Tracks/NclustersEta", + "; nClusters; #eta; occupancy", + {HistType::kTHnSparseF, {{7, 4, 10}, etaAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/NchSel", + "; N_{ch}; occupancy", + {HistType::kTH2F, {multAxis, occupancyAxis}}}); + + if (doprocessDatawBestTracksInclusive) { + registry.add( + {"Events/NtrkZvtxBest", + "; N_{trk}; Z_{vtx} (cm); occupancy", + {HistType::kTHnSparseF, {multAxis, zAxis, occupancyAxis}}}); + registry.add( + {"Tracks/EtaZvtxBest", + "; #eta; Z_{vtx} (cm); occupancy", + {HistType::kTHnSparseF, {etaAxis, zAxis, occupancyAxis}}}); + registry.add( + {"Tracks/PhiEtaBest", + "; #varphi; #eta; occupancy", + {HistType::kTHnSparseF, {phiAxis, etaAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/NclustersEtaBest", + "; nClusters; #eta; occupancy", + {HistType::kTHnSparseF, {{7, 4, 10}, etaAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/DCAXYPt", + "; p_{T} (GeV/c) ; DCA_{XY} (cm); occupancy", + {HistType::kTHnSparseF, {ptAxis, dcaxyAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/DCAXY", + "; DCA_{XY} (cm); occupancy", + {HistType::kTH2F, {dcaxyAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/ReTracksEtaZvtx", + "; #eta; #it{z}_{vtx} (cm); occupancy", + {HistType::kTHnSparseF, {etaAxis, zAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/ReTracksPhiEta", + "; #varphi; #eta; occupancy", + {HistType::kTHnSparseF, {phiAxis, etaAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/TrackAmbDegree", + "; N_{coll}^{comp}; occupancy", + {HistType::kTH2F, {{51, -0.5, 50.5}, occupancyAxis}}}); + } + } + + if (doprocessDataCentFT0C || doprocessDatawBestTracksCentFT0C || + doprocessMCCentFT0C || doprocessMCwBestTracksCentFT0C || + doprocessDataCentFT0CVariant1 || + doprocessDatawBestTracksCentFT0CVariant1 || + doprocessMCCentFT0CVariant1 || doprocessMCwBestTracksCentFT0CVariant1 || + doprocessDataCentFT0M || doprocessDatawBestTracksCentFT0M || + doprocessMCCentFT0M || doprocessMCwBestTracksCentFT0M || + doprocessDataCentNGlobal || doprocessDatawBestTracksCentNGlobal || + doprocessMCCentNGlobal || doprocessMCwBestTracksCentNGlobal || + doprocessDataCentMFT || doprocessDatawBestTracksCentMFT || + doprocessMCCentMFT || doprocessMCwBestTracksCentMFT) { + registry.add({"Events/Centrality/Selection", + ";status;centrality;occupancy", + {HistType::kTHnSparseF, + {{2, 0.5, 2.5}, centralityAxis, occupancyAxis}}}); + auto hstat = registry.get(HIST("Events/Centrality/Selection")); + hstat->GetAxis(0)->SetBinLabel(1, "All"); + hstat->GetAxis(0)->SetBinLabel(2, "Selected"); + + qaregistry.add("hCentOccIRate", "hCentOccIRate", HistType::kTHnSparseF, + {centralityAxis, occupancyAxis, irBins}); + + qaregistry.add({"Events/Centrality/hCent", + "; centrality; occupancy", + {HistType::kTH2F, {centAxis, occupancyAxis}}, + true}); + qaregistry.add( + {"Events/Centrality/hZvtxCent", + "; Z_{vtx} (cm); centrality; occupancy", + {HistType::kTHnSparseF, {zAxis, centralityAxis, occupancyAxis}}}); + registry.add({"Events/Centrality/NtrkZvtx", + "; N_{trk}; Z_{vtx} (cm); centrality; occupancy", + {HistType::kTHnSparseF, + {multAxis, zAxis, centralityAxis, occupancyAxis}}}); + registry.add({"Tracks/Centrality/EtaZvtx", + "; #eta; Z_{vtx} (cm); centrality; occupancy", + {HistType::kTHnSparseF, + {etaAxis, zAxis, centralityAxis, occupancyAxis}}}); + registry.add({"Tracks/Centrality/PhiEta", + "; #varphi; #eta; centrality; occupancy", + {HistType::kTHnSparseF, + {phiAxis, etaAxis, centralityAxis, occupancyAxis}}}); + + qaregistry.add( + {"Tracks/Centrality/NchSel", + "; N_{ch}; centrality; occupancy", + {HistType::kTHnSparseF, {multAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/Centrality/Chi2Eta", + "; #chi^{2}; #it{#eta}; centrality; occupancy", + {HistType::kTHnSparseF, + {{600, 0, 20}, etaAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/Centrality/Chi2", + "; #chi^{2}; centrality; occupancy", + {HistType::kTHnSparseF, + {{600, 0, 20}, centralityAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/Centrality/NclustersEta", + "; nClusters; #eta; centrality; occupancy", + {HistType::kTHnSparseF, + {{7, 4, 10}, etaAxis, centralityAxis, occupancyAxis}}}); + + if (doprocessDatawBestTracksCentFT0C || + doprocessDatawBestTracksCentFT0CVariant1 || + doprocessDatawBestTracksCentFT0M || + doprocessDatawBestTracksCentNGlobal || + doprocessDatawBestTracksCentMFT) { + registry.add({"Events/Centrality/NtrkZvtxBest", + "; N_{trk}; Z_{vtx} (cm); centrality; occupancy", + {HistType::kTHnSparseF, + {multAxis, zAxis, centralityAxis, occupancyAxis}}}); + registry.add({"Tracks/Centrality/EtaZvtxBest", + "; #eta; Z_{vtx} (cm); centrality; occupancy", + {HistType::kTHnSparseF, + {etaAxis, zAxis, centralityAxis, occupancyAxis}}}); + registry.add({"Tracks/Centrality/PhiEtaBest", + "; #varphi; #eta; centrality; occupancy", + {HistType::kTHnSparseF, + {phiAxis, etaAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/Centrality/NclustersEtaBest", + "; nClusters; #eta; centrality; occupancy", + {HistType::kTHnSparseF, + {{7, 4, 10}, etaAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/Centrality/TrackAmbDegree", + "; N_{coll}^{comp}; centrality; occupancy", + {HistType::kTHnSparseF, + {{51, -0.5, 50.5}, centralityAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/Centrality/DCAXY", + "; DCA_{XY} (cm); centrality; occupancy", + {HistType::kTHnSparseF, + {dcaxyAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/Centrality/DCAXYPt", + "; p_{T} (GeV/c) ; DCA_{XY} (cm); centrality; occupancy", + {HistType::kTHnSparseF, + {ptAxis, dcaxyAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/Centrality/ReTracksEtaZvtx", + "; #eta; #it{z}_{vtx} (cm); occupancy", + {HistType::kTHnSparseF, + {etaAxis, zAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/Centrality/ReTracksPhiEta", + "; #varphi; #eta; occupancy", + {HistType::kTHnSparseF, + {phiAxis, etaAxis, centralityAxis, occupancyAxis}}}); + } + } + + if (doprocessMCInclusive || doprocessMCwBestTracksInclusive) { + registry.add({"Events/EvtEffGen", + ";status;occupancy", + {HistType::kTH2F, {{3, 0.5, 3.5}, occupancyAxis}}}); + auto heff = registry.get(HIST("Events/EvtEffGen")); + auto* h = heff->GetXaxis(); + h->SetBinLabel(1, "All reconstructed"); + h->SetBinLabel(2, "Selected reconstructed"); + h->SetBinLabel(3, "All generated"); + + registry.add({"Events/NtrkZvtxGen_t", + "; N_{trk}; Z_{vtx} (cm);", + {HistType::kTH2F, {multAxis, zAxis}}}); + registry.add({"Events/NtrkZvtxGen", + "; N_{trk}; Z_{vtx} (cm); occupancy", + {HistType::kTHnSparseF, {multAxis, zAxis, occupancyAxis}}}); + registry.add({"Tracks/EtaZvtxGen", + "; #eta; Z_{vtx} (cm); occupancy", + {HistType::kTHnSparseF, {etaAxis, zAxis, occupancyAxis}}}); + registry.add( + {"Tracks/PhiEtaGen", + "; #varphi; #eta;", + {HistType::kTHnSparseF, {phiAxis, etaAxis, occupancyAxis}}}); + registry.add({"Tracks/EtaZvtxGen_t", + "; #eta; Z_{vtx} (cm);", + {HistType::kTH2F, {etaAxis, zAxis}}}); + registry.add({"Tracks/PhiEtaGen_t", + "; #varphi; #eta;", + {HistType::kTH2F, {phiAxis, etaAxis}}}); + qaregistry.add({"Events/NotFoundEventZvtx", + "; #it{z}_{vtx} (cm)", + {HistType::kTH1F, {zAxis}}}); + qaregistry.add({"Events/ZvtxDiff", + "; Z_{rec} - Z_{gen} (cm)", + {HistType::kTH1F, {deltaZAxis}}}); + qaregistry.add({"Events/SplitMult", + "; N_{gen}; #it{z}_{vtx} (cm)", + {HistType::kTH2F, {multAxis, zAxis}}}); + } + + if (doprocessMCCentFT0C || doprocessMCwBestTracksCentFT0C || + doprocessMCCentFT0CVariant1 || doprocessMCwBestTracksCentFT0CVariant1 || + doprocessMCCentFT0M || doprocessMCwBestTracksCentFT0M || + doprocessMCCentNGlobal || doprocessMCwBestTracksCentNGlobal || + doprocessMCCentMFT || doprocessMCwBestTracksCentMFT) { + registry.add({"Events/Centrality/EvtEffGen", + ";status;centrality;occupancy", + {HistType::kTHnSparseF, + {{3, 0.5, 3.5}, centralityAxis, occupancyAxis}}}); + auto heff = registry.get(HIST("Events/Centrality/EvtEffGen")); + heff->GetAxis(0)->SetBinLabel(1, "All reconstructed"); + heff->GetAxis(0)->SetBinLabel(2, "Selected reconstructed"); + heff->GetAxis(0)->SetBinLabel(3, "All generated"); + + registry.add( + {"Events/Centrality/NtrkZvtxGen_t", + "; N_{trk}; Z_{vtx} (cm); centrality", + {HistType::kTHnSparseF, {multAxis, zAxis, centralityAxis}}}); + registry.add({"Events/Centrality/NtrkZvtxGen", + "; N_{trk}; Z_{vtx} (cm); centrality; occupancy", + {HistType::kTHnSparseF, + {multAxis, zAxis, centralityAxis, occupancyAxis}}}); + registry.add({"Events/Centrality/hRecCent", + "; centrality; occupancy", + {HistType::kTH2F, {centralityAxis, occupancyAxis}}}); + registry.add( + {"Events/Centrality/hRecZvtxCent", + "; Z_{vtx} (cm); centrality; occupancy", + {HistType::kTHnSparseF, {zAxis, centralityAxis, occupancyAxis}}}); + registry.add({"Tracks/Centrality/EtaZvtxGen", + "; #eta; Z_{vtx} (cm); centrality; occupancy", + {HistType::kTHnSparseF, + {etaAxis, zAxis, centralityAxis, occupancyAxis}}}); + registry.add({"Tracks/Centrality/PhiEtaGen", + "; #varphi; #eta; centrality; occupancy", + {HistType::kTHnSparseF, + {phiAxis, etaAxis, centralityAxis, occupancyAxis}}}); + registry.add({"Tracks/Centrality/EtaZvtxGen_t", + "; #eta; Z_{vtx} (cm); centrality", + {HistType::kTHnSparseF, {etaAxis, zAxis, centralityAxis}}}); + registry.add( + {"Tracks/Centrality/PhiEtaGen_t", + "; #varphi; #eta; centrality", + {HistType::kTHnSparseF, {phiAxis, etaAxis, centralityAxis}}}); + qaregistry.add({"Events/Centrality/NotFoundEventZvtx", + "; #it{z}_{vtx} (cm); centrality", + {HistType::kTH2F, {zAxis, centralityAxis}}}); + qaregistry.add({"Events/Centrality/ZvtxDiff", + "; Z_{rec} - Z_{gen} (cm); centrality", + {HistType::kTH2F, {deltaZAxis, centralityAxis}}}); + qaregistry.add( + {"Events/Centrality/SplitMult", + "; N_{gen}; #it{z}_{vtx} (cm); centrality", + {HistType::kTHnSparseF, {multAxis, zAxis, centralityAxis}}}); + } + + if (doprocessTrkEffIdxInlusive) { + qaregistry.add({"Tracks/hPtEtaEffGen", + "; p_{T} (GeV/c); #eta; occupancy", + {HistType::kTHnSparseF, + {ptAxis, etaAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/hPtEtaEffPrim", + "; p_{T} (GeV/c); #eta; occupancy", + {HistType::kTHnSparseF, + {ptAxis, etaAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/hPtEtaEffSec", + "; p_{T} (GeV/c); #eta; occupancy", + {HistType::kTHnSparseF, + {ptAxis, etaAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/hPtEtaEffGenDupl", + "; p_{T} (GeV/c); #eta; occupancy", + {HistType::kTHnSparseF, + {ptAxis, etaAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/hPtEtaEffDupl", + "; p_{T} (GeV/c); #eta; occupancy", + {HistType::kTHnSparseF, + {ptAxis, etaAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/NmftTrkPerPart", + "; #it{N}_{mft tracks per particle}; occupancy", + {HistType::kTH2F, {multAxis, occupancyAxis}}}); + } + + if (doprocessTrkEffIdxCentFT0C) { + qaregistry.add( + {"Tracks/Centrality/hPtEtaEffGen", + "; p_{T} (GeV/c); #eta; centrality; " + "occupancy", + {HistType::kTHnSparseF, + {ptAxis, etaAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/Centrality/hPtEtaEffPrim", + "; p_{T} (GeV/c); #eta; centrality; " + "occupancy", + {HistType::kTHnSparseF, + {ptAxis, etaAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/Centrality/hPtEtaEffSec", + "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); centrality; " + "occupancy", + {HistType::kTHnSparseF, + {ptAxis, etaAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/Centrality/hPtEtaEffGenDupl", + "; p_{T} (GeV/c); #eta; centrality; " + "occupancy", + {HistType::kTHnSparseF, + {ptAxis, etaAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/Centrality/hPtEtaEffDupl", + "; p_{T} (GeV/c); #eta; centrality; " + "occupancy", + {HistType::kTHnSparseF, + {ptAxis, etaAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/Centrality/NmftTrkPerPart", + "; #it{N}_{mft tracks per particle}; centrality; occupancy", + {HistType::kTHnSparseF, {multAxis, centralityAxis, occupancyAxis}}}); + } + + if (doprocessTrkEffBestInclusive) { + qaregistry.add({"Tracks/hPtPhiEtaZvtxEffBestGen", + "; p_{T} (GeV/c); #varphi; #eta; Z_{vtx} (cm); occupancy", + {HistType::kTHnSparseF, + {ptAxis, phiAxis, etaAxis, zAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/hPtPhiEtaZvtxEffBestRec", + "; p_{T} (GeV/c); #varphi; #eta; Z_{vtx} (cm); occupancy", + {HistType::kTHnSparseF, + {ptAxis, phiAxis, etaAxis, zAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/hPtEffBestFakeRec", + " ; p_{T} (GeV/c); occupancy", + {HistType::kTH2F, {ptAxis, occupancyAxis}}}); + } + + if (doprocessTrkEffBestCentFT0C) { + qaregistry.add( + {"Tracks/Centrality/hPtPhiEtaZvtxEffBestGen", + "; p_{T} (GeV/c); #varphi; #eta; Z_{vtx} (cm); centrality; " + "occupancy", + {HistType::kTHnSparseF, + {ptAxis, phiAxis, etaAxis, zAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/Centrality/hPtPhiEtaZvtxEffBestRec", + "; p_{T} (GeV/c); #varphi; #eta; Z_{vtx} (cm); centrality; " + "occupancy", + {HistType::kTHnSparseF, + {ptAxis, phiAxis, etaAxis, zAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/Centrality/hPtEffBestFakeRec", + "; p_{T} (GeV/c); centrality; occupancy", + {HistType::kTHnSparseF, {ptAxis, centralityAxis, occupancyAxis}}}); + } + + if (doprocessMcQAInclusive) { + qaregistry.add({"Events/hRecPerGenColls", + "; #it{N}_{reco collisions} / #it{N}_{gen collisions};", + {HistType::kTH2F, {{200, 0., 2.}, occupancyAxis}}}); + qaregistry.add({"Tracks/hNmftTrks", + "; #it{N}_{mft tracks};", + {HistType::kTH2F, {{200, -0.5, 200.}, occupancyAxis}}}); + qaregistry.add({"Tracks/hFracAmbiguousMftTrks", + "; #it{N}_{ambiguous tracks} / #it{N}_{tracks};", + {HistType::kTH2F, {{100, 0., 1.}, occupancyAxis}}}); + } + + if (doprocessMcQACentFT0C) { + qaregistry.add( + {"Events/Centrality/hRecPerGenColls", + "; #it{N}_{reco collisions} / #it{N}_{gen collisions}; centrality", + {HistType::kTHnSparseF, + {{200, 0., 2.}, centralityAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/Centrality/hNmftTrks", + "; #it{N}_{mft tracks}; centrality", + {HistType::kTHnSparseF, + {{200, -0.5, 200.}, centralityAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/Centrality/hFracAmbiguousMftTrks", + "; #it{N}_{ambiguous tracks} / #it{N}_{tracks}; centrality", + {HistType::kTHnSparseF, + {{100, 0., 1.}, centralityAxis, occupancyAxis}}}); + } + + if (doprocessCheckAmbiguousMftTracksInclusive) { + qaregistry.add({"Tracks/hMftTracksAmbDegree", + " ; N_{coll}^{comp}; occupancy", + {HistType::kTH2F, {{41, -0.5, 40.5}, occupancyAxis}}}); + qaregistry.add({"Tracks/hAmbTrackType", + " ; Ambiguous track type; occupancy", + {HistType::kTH2F, {{5, -0.5, 4.5}, occupancyAxis}}}); + qaregistry.add({"Tracks/histAmbZvtx", + "#it{z}_{vtx} of collisions associated to a " + "track;#it{z}_{vtx} (cm);", + {HistType::kTH1F, {zAxis}}}); + } + + if (doprocessCheckAmbiguousMftTracksCentFT0C) { + qaregistry.add({"Tracks/Centrality/hMftTracksAmbDegree", + " ; N_{coll}^{comp}; occupancy", + {HistType::kTHnSparseF, + {{41, -0.5, 40.5}, centralityAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/Centrality/hAmbTrackType", + " ; Ambiguous track type; occupancy", + {HistType::kTHnSparseF, + {{5, -0.5, 4.5}, centralityAxis, occupancyAxis}}}); + } + + if (doprocessEfficiencyInclusive) { + qaregistry.add({"Tracks/hEffRec", + "; p_{T} (GeV/c); #varphi; #eta; Z_{vtx} (cm); occupancy", + {HistType::kTHnSparseF, + {ptAxis, phiAxis, etaAxis, zAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/hEffFake", + "; p_{T} (GeV/c); #varphi; #eta; Z_{vtx} (cm); occupancy", + {HistType::kTHnSparseF, + {ptAxis, phiAxis, etaAxis, zAxis, occupancyAxis}}}); + } + + if (doprocessEfficiencyCentFT0C) { + qaregistry.add({"Tracks/Centrality/hEffRec", + "; p_{T} (GeV/c); #varphi; #eta; Z_{vtx} (cm); centrality; occupancy", + {HistType::kTHnSparseF, + {ptAxis, phiAxis, etaAxis, zAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/Centrality/hEffFake", + "; p_{T} (GeV/c); #varphi; #eta; Z_{vtx} (cm); centrality; occupancy", + {HistType::kTHnSparseF, + {ptAxis, phiAxis, etaAxis, zAxis, centralityAxis, occupancyAxis}}}); + } + } + + /// Filters - tracks + Filter filtTrkEta = (aod::fwdtrack::eta < trackCuts.maxEta) && + (aod::fwdtrack::eta > trackCuts.minEta); + Filter filtATrackID = (aod::fwdtrack::bestCollisionId >= 0); + Filter filtATrackDCA = (nabs(aod::fwdtrack::bestDCAXY) < trackCuts.maxDCAxy); + + /// Filters - mc particles + Filter primaries = (aod::mcparticle::flags & + (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary) == + (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary; + + /// Joined tables + using FullBCs = soa::Join; + using CollBCs = soa::Join; + using Colls = soa::Join; + using Coll = Colls::iterator; + using CollsCentFT0C = soa::Join; + using CollsCentFT0CVariant1 = + soa::Join; + using CollsCentFT0M = soa::Join; + using CollsCentNGlobal = + soa::Join; + using CollsCentMFT = soa::Join; + using CollCentFT0C = CollsCentFT0C::iterator; + using CollsGenCentFT0C = soa::Join; + using CollGenCent = CollsGenCentFT0C::iterator; + using MFTTracksLabeled = soa::Join; + using MftTracksWColls = soa::Join; + + /// Filtered tables + using FiltMftTracks = soa::Filtered; + using FiltMcMftTracks = soa::Filtered; + using FiltBestTracks = soa::Filtered; + using FiltParticles = soa::Filtered; + + bool isIRSelected(CollBCs::iterator const& bc, bool fillHis = false) + { + double ir = (eventCuts.minIR >= 0 || eventCuts.maxIR >= 0) + ? rateFetcher.fetch(ccdb.service, bc.timestamp(), + bc.runNumber(), "ZNC hadronic") * + 1.e-3 + : -1; + if (eventCuts.minIR >= 0 && ir < eventCuts.minIR) { + return false; + } + if (fillHis) { + registry.fill(HIST("hEvtSel"), 9); + } + if (eventCuts.maxIR >= 0 && ir > eventCuts.maxIR) { + return false; + } + if (fillHis) { + registry.fill(HIST("hEvtSel"), 10); + } + return true; + } + + template + bool isTrackSelected(const T& track) + { + if (track.eta() < trackCuts.minEta || track.eta() > trackCuts.maxEta) + return false; + if (trackCuts.requireCA && !track.isCA()) + return false; + if (track.nClusters() < trackCuts.minNclusterMft) + return false; + if (track.pt() < trackCuts.minPt) + return false; + if (trackCuts.usephiCut) { + float phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + if (phi < trackCuts.minPhi || trackCuts.maxPhi < phi) { + return false; + } + if ((phi < trackCuts.phiCut) || + ((phi > PI - trackCuts.phiCut) && (phi < PI + trackCuts.phiCut)) || + (phi > TwoPI - trackCuts.phiCut) || + ((phi > ((PIHalf - 0.1) * PI) - trackCuts.phiCut) && + (phi < ((PIHalf - 0.1) * PI) + trackCuts.phiCut))) + return false; + } + return true; + } + + template + int countTracks(T const& tracks, float z, float c, float occ) + { + auto nTrk = 0; + if (tracks.size() > 0) { + for (auto const& track : tracks) { + if (fillHis) { + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/Chi2Eta"), track.chi2(), + track.eta(), c, occ); + qaregistry.fill(HIST("Tracks/Centrality/Chi2"), track.chi2(), c, + occ); + qaregistry.fill(HIST("Tracks/Centrality/NclustersEta"), + track.nClusters(), track.eta(), c, occ); + } else { + qaregistry.fill(HIST("Tracks/Chi2Eta"), track.chi2(), track.eta(), + occ); + qaregistry.fill(HIST("Tracks/Chi2"), track.chi2(), occ); + qaregistry.fill(HIST("Tracks/NclustersEta"), track.nClusters(), + track.eta(), occ); + } + } + if (!isTrackSelected(track)) { + continue; + } + if (fillHis) { + float phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + if (phi < 0.f || TwoPI < phi) { + continue; + } + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/EtaZvtx"), track.eta(), z, c, + occ); + registry.fill(HIST("Tracks/Centrality/PhiEta"), phi, track.eta(), c, + occ); + } else { + registry.fill(HIST("Tracks/EtaZvtx"), track.eta(), z, occ); + registry.fill(HIST("Tracks/PhiEta"), phi, track.eta(), occ); + } + } + ++nTrk; + } + } + if (fillHis) { + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/NchSel"), nTrk, c, occ); + } else { + qaregistry.fill(HIST("Tracks/NchSel"), nTrk, occ); + } + } + return nTrk; + } + + template + int countBestTracks(T const& /*tracks*/, B const& besttracks, float z, + float c, float occ) + { + auto nATrk = 0; + if (besttracks.size() > 0) { + for (auto const& atrack : besttracks) { + auto itrack = atrack.template mfttrack_as(); + if (!isTrackSelected(itrack)) { + continue; + } + if (fillHis) { + float phi = itrack.phi(); + o2::math_utils::bringTo02Pi(phi); + if (phi < 0.f || TwoPI < phi) { + continue; + } + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/EtaZvtxBest"), itrack.eta(), + z, c, occ); + registry.fill(HIST("Tracks/Centrality/PhiEtaBest"), phi, + itrack.eta(), c, occ); + qaregistry.fill(HIST("Tracks/Centrality/DCAXYPt"), itrack.pt(), + atrack.bestDCAXY(), c, occ); + qaregistry.fill(HIST("Tracks/Centrality/DCAXY"), atrack.bestDCAXY(), + c, occ); + qaregistry.fill(HIST("Tracks/Centrality/NclustersEtaBest"), + itrack.nClusters(), itrack.eta(), c, occ); + if (itrack.collisionId() != atrack.bestCollisionId()) { + qaregistry.fill(HIST("Tracks/Centrality/ReTracksEtaZvtx"), + itrack.eta(), z, c, occ); + qaregistry.fill(HIST("Tracks/Centrality/ReTracksPhiEta"), phi, + itrack.eta(), c, occ); + } + qaregistry.fill(HIST("Tracks/Centrality/TrackAmbDegree"), + atrack.ambDegree(), c, occ); + } else { + registry.fill(HIST("Tracks/EtaZvtxBest"), itrack.eta(), z, occ); + registry.fill(HIST("Tracks/PhiEtaBest"), phi, itrack.eta(), occ); + qaregistry.fill(HIST("Tracks/DCAXYPt"), itrack.pt(), + atrack.bestDCAXY(), occ); + qaregistry.fill(HIST("Tracks/DCAXY"), atrack.bestDCAXY(), occ); + qaregistry.fill(HIST("Tracks/NclustersEtaBest"), itrack.nClusters(), + itrack.eta(), occ); + if (itrack.collisionId() != atrack.bestCollisionId()) { + qaregistry.fill(HIST("Tracks/ReTracksEtaZvtx"), itrack.eta(), z, + occ); + qaregistry.fill(HIST("Tracks/ReTracksPhiEta"), phi, itrack.eta(), + occ); + } + qaregistry.fill(HIST("Tracks/TrackAmbDegree"), atrack.ambDegree(), + occ); + } + } + ++nATrk; + } + } + return nATrk; + } + + template + int countPart(P const& particles) + { + auto nCharged = 0; + for (auto const& particle : particles) { + if (!isChrgParticle(particle.pdgCode())) { + continue; + } + nCharged++; + } + return nCharged; + } + + template + float getOccupancy(C const& collision, uint occEstimator) + { + switch (occEstimator) { + case OccupancyEst::TrkITS: + return collision.trackOccupancyInTimeRange(); + case OccupancyEst::Ft0C: + return collision.ft0cOccupancyInTimeRange(); + default: + LOG(fatal) << "No valid occupancy estimator "; + break; + } + return -1.f; + } + + template + bool isGoodEvent(C const& collision) + { + if constexpr (fillHis) { + registry.fill(HIST("hEvtSel"), 0); + } + if (!collision.sel8()) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("hEvtSel"), 1); + } + if (!collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("hEvtSel"), 2); + } + if (!collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("hEvtSel"), 3); + } + if (std::abs(collision.posZ()) >= eventCuts.maxZvtx) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("hEvtSel"), 4); + } + if (eventCuts.requireNoCollInTimeRangeStd && + !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("hEvtSel"), 5); + } + if (eventCuts.requireNoCollInTimeRangeNarrow && + !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("hEvtSel"), 6); + } + if (eventCuts.minOccupancy >= 0 && + getOccupancy(collision, eventCuts.occupancyEstimator) < + eventCuts.minOccupancy) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("hEvtSel"), 7); + } + if (eventCuts.maxOccupancy >= 0 && + getOccupancy(collision, eventCuts.occupancyEstimator) > + eventCuts.maxOccupancy) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("hEvtSel"), 8); + } + return true; + } + + /// @brief Selection of charged particles + /// @return true: charged; false: not charged + bool isChrgParticle(int code) + { + auto p = pdg->GetParticle(code); + auto charge = 0.; + if (p != nullptr) { + charge = p->Charge(); + } + return std::abs(charge) >= 3.; + } + + template + void fillHistMC(P const& particles, float c, float occ, float zvtx, + bool const gtZeroColl) + { + for (auto const& particle : particles) { + if (!isChrgParticle(particle.pdgCode())) { + continue; + } + + float phi = particle.phi(); + o2::math_utils::bringTo02Pi(phi); + if (phi < 0.f || TwoPI < phi) { + continue; + } + if constexpr (isCent) { + registry.fill(HIST("Tracks/Centrality/EtaZvtxGen_t"), particle.eta(), + zvtx, c); + registry.fill(HIST("Tracks/Centrality/PhiEtaGen_t"), phi, + particle.eta(), c); + } else { + registry.fill(HIST("Tracks/EtaZvtxGen_t"), particle.eta(), zvtx); + registry.fill(HIST("Tracks/PhiEtaGen_t"), phi, particle.eta()); + } + + if (gtZeroColl) { + float phi = particle.phi(); + o2::math_utils::bringTo02Pi(phi); + if (phi < 0.f || TwoPI < phi) { + continue; + } + if constexpr (isCent) { + registry.fill(HIST("Tracks/Centrality/EtaZvtxGen"), particle.eta(), + zvtx, c, occ); + registry.fill(HIST("Tracks/Centrality/PhiEtaGen"), phi, + particle.eta(), c, occ); + } else { + registry.fill(HIST("Tracks/EtaZvtxGen"), particle.eta(), zvtx, occ); + registry.fill(HIST("Tracks/PhiEtaGen"), phi, particle.eta(), occ); + } + } + } + } + + /// @brief process function for general event statistics + void processTagging(FullBCs const& bcs, CollsCentFT0C const& collisions) + { + std::vector::iterator> cols; + for (auto const& bc : bcs) { + if ((bc.selection_bit(aod::evsel::kIsBBT0A) && + bc.selection_bit(aod::evsel::kIsBBT0C)) != 0) { + registry.fill(HIST("hBcSel"), 0); + cols.clear(); + for (auto const& collision : collisions) { + if (collision.has_foundBC()) { + if (collision.foundBCId() == bc.globalIndex()) { + cols.emplace_back(collision); + } + } else if (collision.bcId() == bc.globalIndex()) { + cols.emplace_back(collision); + } + } + LOGP(debug, "BC {} has {} collisions", bc.globalBC(), cols.size()); + if (!cols.empty()) { + registry.fill(HIST("hBcSel"), 1); + if (cols.size() > 1) { + registry.fill(HIST("hBcSel"), 2); + } + } + } + } + } + + PROCESS_SWITCH(DndetaMFTPbPb, processTagging, "Collect event sample stats", + true); + + /// @brief process function for counting tracks + template + void processData(typename C::iterator const& collision, + FiltMftTracks const& tracks, CollBCs const& /*bcs*/) + { + auto occ = getOccupancy(collision, eventCuts.occupancyEstimator); + float c = getRecoCent(collision); + auto bc = collision.template foundBC_as(); + double ir = rateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), + "ZNC hadronic") * + 1.e-3; + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/Selection"), 1., c, occ); + } else { + registry.fill(HIST("Events/Selection"), 1., occ); + } + + if (!isGoodEvent(collision)) { + return; + } + if (!isIRSelected(bc, true)) { + return; + } + + auto z = collision.posZ(); + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/Selection"), 2., c, occ); + qaregistry.fill(HIST("Events/Centrality/hZvtxCent"), z, c, occ); + qaregistry.fill(HIST("Events/Centrality/hCent"), c, occ); + qaregistry.fill(HIST("hCentOccIRate"), c, occ, ir); + + } else { + qaregistry.fill(HIST("hOccIRate"), occ, ir); + registry.fill(HIST("Events/Selection"), 2., occ); + } + + auto nTrk = countTracks(tracks, z, c, occ); + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/NtrkZvtx"), nTrk, z, c, occ); + } else { + registry.fill(HIST("Events/NtrkZvtx"), nTrk, z, occ); + } + } + + /// @brief process function for counting tracks (based on BestCollisionsFwd + /// table) + template + void processDatawBestTracks( + typename C::iterator const& collision, FiltMftTracks const& tracks, + soa::SmallGroups const& besttracks, + CollBCs const& /*bcs*/) + { + auto occ = getOccupancy(collision, eventCuts.occupancyEstimator); + float c = getRecoCent(collision); + auto bc = collision.template foundBC_as(); + double ir = rateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), + "ZNC hadronic") * + 1.e-3; + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/Selection"), 1., c, occ); + } else { + registry.fill(HIST("Events/Selection"), 1., occ); + } + + if (!isGoodEvent(collision)) { + return; + } + if (!isIRSelected(bc, true)) { + return; + } + + auto z = collision.posZ(); + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/Selection"), 2., c, occ); + qaregistry.fill(HIST("hCentOccIRate"), c, occ, ir); + } else { + registry.fill(HIST("Events/Selection"), 2., occ); + qaregistry.fill(HIST("hOccIRate"), occ, ir); + } + + auto nBestTrks = countBestTracks(tracks, besttracks, z, c, occ); + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/NtrkZvtxBest"), nBestTrks, z, c, + occ); + } else { + registry.fill(HIST("Events/NtrkZvtxBest"), nBestTrks, z, occ); + } + } + + void processDataInclusive(Colls::iterator const& collision, + FiltMftTracks const& tracks, CollBCs const& bcs) + { + processData(collision, tracks, bcs); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processDataInclusive, + "Count tracks (inclusive)", false); + + void processDataCentFT0C(CollsCentFT0C::iterator const& collision, + FiltMftTracks const& tracks, CollBCs const& bcs) + { + processData(collision, tracks, bcs); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processDataCentFT0C, + "Count tracks in FT0C centrality bins", false); + + void + processDataCentFT0CVariant1(CollsCentFT0CVariant1::iterator const& collision, + FiltMftTracks const& tracks, CollBCs const& bcs) + { + processData(collision, tracks, bcs); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processDataCentFT0CVariant1, + "Count tracks in FT0CVariant1 centrality bins", false); + + void processDataCentFT0M(CollsCentFT0M::iterator const& collision, + FiltMftTracks const& tracks, CollBCs const& bcs) + { + processData(collision, tracks, bcs); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processDataCentFT0M, + "Count tracks in FT0M centrality bins", false); + + void processDataCentNGlobal(CollsCentNGlobal::iterator const& collision, + FiltMftTracks const& tracks, CollBCs const& bcs) + { + processData(collision, tracks, bcs); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processDataCentNGlobal, + "Count tracks in NGlobal centrality bins", false); + + void processDataCentMFT(CollsCentMFT::iterator const& collision, + FiltMftTracks const& tracks, CollBCs const& bcs) + { + processData(collision, tracks, bcs); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processDataCentMFT, + "Count tracks in MFT centrality bins", false); + + void processDatawBestTracksInclusive( + Colls::iterator const& collision, FiltMftTracks const& tracks, + soa::SmallGroups const& besttracks, + CollBCs const& bcs) + { + processDatawBestTracks(collision, tracks, besttracks, bcs); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processDatawBestTracksInclusive, + "Count tracks based on BestCollisionsFwd table (inclusive)", + false); + + void processDatawBestTracksCentFT0C( + CollsCentFT0C::iterator const& collision, FiltMftTracks const& tracks, + soa::SmallGroups const& besttracks, + CollBCs const& bcs) + { + processDatawBestTracks(collision, tracks, besttracks, bcs); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processDatawBestTracksCentFT0C, + "Count tracks in FT0C centrality bins based on BestCollisionsFwd table", + false); + + void processDatawBestTracksCentFT0CVariant1( + CollsCentFT0CVariant1::iterator const& collision, + FiltMftTracks const& tracks, + soa::SmallGroups const& besttracks, + CollBCs const& bcs) + { + processDatawBestTracks(collision, tracks, besttracks, + bcs); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processDatawBestTracksCentFT0CVariant1, + "Count tracks in FT0CVariant1 centrality bins based on " + "BestCollisionsFwd table", + false); + + void processDatawBestTracksCentFT0M( + CollsCentFT0M::iterator const& collision, FiltMftTracks const& tracks, + soa::SmallGroups const& besttracks, + CollBCs const& bcs) + { + processDatawBestTracks(collision, tracks, besttracks, bcs); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processDatawBestTracksCentFT0M, + "Count tracks in FT0M centrality bins based on BestCollisionsFwd table", + false); + + void processDatawBestTracksCentNGlobal( + CollsCentNGlobal::iterator const& collision, FiltMftTracks const& tracks, + soa::SmallGroups const& besttracks, + CollBCs const& bcs) + { + processDatawBestTracks(collision, tracks, besttracks, + bcs); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processDatawBestTracksCentNGlobal, + "Count tracks in NGlobal centrality bins based on " + "BestCollisionsFwd table", + false); + + void processDatawBestTracksCentMFT( + CollsCentMFT::iterator const& collision, FiltMftTracks const& tracks, + soa::SmallGroups const& besttracks, + CollBCs const& bcs) + { + processDatawBestTracks(collision, tracks, besttracks, bcs); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processDatawBestTracksCentMFT, + "Count tracks in MFT centrality bins based on BestCollisionsFwd table", + false); + + Preslice perCol = o2::aod::fwdtrack::collisionId; + PresliceUnsorted recColPerMcCol = + aod::mccollisionlabel::mcCollisionId; + Partition mcSample = nabs(aod::mcparticle::eta) < 1.0f; + + /// @brief process template function to run on MC gen + template + void processMC( + typename MC::iterator const& mcCollision, + soa::SmallGroups> const& collisions, + FiltParticles const& particles, FiltMcMftTracks const& tracks) + { + bool gtZeroColl = false; + int gtOneColl = 0; + + float cgen = -1; + if constexpr (has_reco_cent) { + float crec_min = 105.f; + for (const auto& collision : collisions) { + if (isGoodEvent(collision)) { + float c = getRecoCent(collision); + if (c < crec_min) { + crec_min = c; + } + } + } + if (cgen < 0) + cgen = crec_min; + } + + float occgen = -1.; + for (const auto& collision : collisions) { + if (isGoodEvent(collision)) { + float o = getOccupancy(collision, eventCuts.occupancyEstimator); + if (o > occgen) { + occgen = o; + } + } + } + + for (auto const& collision : collisions) { + float occrec = getOccupancy(collision, eventCuts.occupancyEstimator); + float crec = getRecoCent(collision); + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/EvtEffGen"), 1., crec, occrec); + } else { + registry.fill(HIST("Events/EvtEffGen"), 1., occrec); + } + + if (isGoodEvent(collision)) { + gtZeroColl = true; + ++gtOneColl; + auto z = collision.posZ(); + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/EvtEffGen"), 2., crec, occrec); + registry.fill(HIST("Events/Centrality/hRecCent"), crec, occrec); + registry.fill(HIST("Events/Centrality/hRecZvtxCent"), z, crec, + occrec); + } else { + registry.fill(HIST("Events/EvtEffGen"), 2., occrec); + } + + auto perColSample = tracks.sliceBy(perCol, collision.globalIndex()); + auto nTrkRec = countTracks(perColSample, z, crec, occrec); + + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Events/Centrality/ZvtxDiff"), + collision.posZ() - mcCollision.posZ(), crec); + } else { + qaregistry.fill(HIST("Events/ZvtxDiff"), + collision.posZ() - mcCollision.posZ()); + } + + if (eventCuts.useZDiffCut) { + if (std::abs(collision.posZ() - mcCollision.posZ()) > + eventCuts.maxZvtxDiff) { + continue; + } + } + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/NtrkZvtxGen"), nTrkRec, + collision.posZ(), crec, occrec); + } else { + registry.fill(HIST("Events/NtrkZvtxGen"), nTrkRec, collision.posZ(), + occrec); + } + } + } + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/EvtEffGen"), 3., cgen, occgen); + } else { + registry.fill(HIST("Events/EvtEffGen"), 3., occgen); + } + + auto perCollMCsample = mcSample->sliceByCached( + aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); + auto nchrg = countPart(perCollMCsample); + auto zvtxMC = mcCollision.posZ(); + + if (gtOneColl > 1) { + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Events/Centrality/SplitMult"), nchrg, zvtxMC, cgen); + } else { + qaregistry.fill(HIST("Events/SplitMult"), nchrg, zvtxMC); + } + } + + auto nCharged = countPart(particles); + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/NtrkZvtxGen_t"), nCharged, zvtxMC, + cgen); + } else { + registry.fill(HIST("Events/NtrkZvtxGen_t"), nCharged, zvtxMC); + } + + fillHistMC>(particles, cgen, occgen, zvtxMC, gtZeroColl); + + if (collisions.size() == 0) { + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Events/Centrality/NotFoundEventZvtx"), + mcCollision.posZ(), cgen); + } else { + qaregistry.fill(HIST("Events/NotFoundEventZvtx"), mcCollision.posZ()); + } + } + } + + void processMCInclusive( + aod::McCollisions::iterator const& mccollision, + soa::SmallGroups> const& collisions, + FiltParticles const& particles, FiltMcMftTracks const& tracks) + { + processMC(mccollision, collisions, particles, + tracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processMCInclusive, + "Count MC particles (inclusive)", false); + + void processMCCentFT0C( + aod::McCollisions::iterator const& mccollision, + soa::SmallGroups> const& collisions, + FiltParticles const& particles, FiltMcMftTracks const& tracks) + { + processMC(mccollision, collisions, + particles, tracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processMCCentFT0C, + "Count MC particles in FT0C centrality bins", false); + + void processMCCentFT0CVariant1( + aod::McCollisions::iterator const& mccollision, + soa::SmallGroups> const& collisions, + FiltParticles const& particles, FiltMcMftTracks const& tracks) + { + processMC(mccollision, collisions, + particles, tracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processMCCentFT0CVariant1, + "Count MC particles in FT0CVariant1 centrality bins", false); + + void processMCCentFT0M( + aod::McCollisions::iterator const& mccollision, + soa::SmallGroups> const& collisions, + FiltParticles const& particles, FiltMcMftTracks const& tracks) + { + processMC(mccollision, collisions, + particles, tracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processMCCentFT0M, + "Count MC particles in FT0M centrality bins", false); + + void processMCCentNGlobal( + aod::McCollisions::iterator const& mccollision, + soa::SmallGroups> const& collisions, + FiltParticles const& particles, FiltMcMftTracks const& tracks) + { + processMC(mccollision, collisions, + particles, tracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processMCCentNGlobal, + "Count MC particles in NGlobal centrality bins", false); + + void processMCCentMFT( + aod::McCollisions::iterator const& mccollision, + soa::SmallGroups> const& collisions, + FiltParticles const& particles, FiltMcMftTracks const& tracks) + { + processMC(mccollision, collisions, + particles, tracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processMCCentMFT, + "Count MC particles in MFT centrality bins", false); + + PresliceUnsorted perColU = + aod::fwdtrack::bestCollisionId; + + /// @brief process template function to run on MC truth using + /// aod::BestCollisionsFwd tracks + template + void processMCwBestTracks( + typename MC::iterator const& mcCollision, + soa::SmallGroups> const& collisions, + FiltParticles const& particles, FiltMcMftTracks const& tracks, + FiltBestTracks const& besttracks) + { + bool gtZeroColl = false; + float cgen = -1; + if constexpr (has_reco_cent) { + float crec_min = 105.f; + for (const auto& collision : collisions) { + if (isGoodEvent(collision)) { + float c = getRecoCent(collision); + if (c < crec_min) { + crec_min = c; + } + } + } + if (cgen < 0) + cgen = crec_min; + } + + float occgen = -1.; + for (const auto& collision : collisions) { + if (isGoodEvent(collision)) { + float o = getOccupancy(collision, eventCuts.occupancyEstimator); + if (o > occgen) { + occgen = o; + } + } + } + + for (auto const& collision : collisions) { + auto occrec = getOccupancy(collision, eventCuts.occupancyEstimator); + float crec = getRecoCent(collision); + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/EvtEffGen"), 1., crec, occrec); + } else { + registry.fill(HIST("Events/EvtEffGen"), 1., occrec); + } + + if (isGoodEvent(collision)) { + gtZeroColl = true; + auto z = collision.posZ(); + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/EvtEffGen"), 2., crec, occrec); + } else { + registry.fill(HIST("Events/EvtEffGen"), 2., occrec); + } + + auto perCollisionSample = + tracks.sliceBy(perCol, collision.globalIndex()); + auto perCollisionASample = + besttracks.sliceBy(perColU, collision.globalIndex()); + auto nTrkRec = countBestTracks( + perCollisionSample, perCollisionASample, z, crec, + collision.trackOccupancyInTimeRange()); + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/NtrkZvtxGen"), nTrkRec, z, + crec, occrec); + } else { + registry.fill(HIST("Events/NtrkZvtxGen"), nTrkRec, z, occrec); + } + } + } + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/EvtEffGen"), 3., cgen, occgen); + } else { + registry.fill(HIST("Events/EvtEffGen"), 3., occgen); + } + + auto zvtxMC = mcCollision.posZ(); + auto nCharged = countPart(particles); + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/NtrkZvtxGen_t"), nCharged, zvtxMC, + cgen); + } else { + registry.fill(HIST("Events/NtrkZvtxGen_t"), nCharged, zvtxMC); + } + + fillHistMC>(particles, cgen, occgen, zvtxMC, gtZeroColl); + + if (collisions.size() == 0) { + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Events/Centrality/NotFoundEventZvtx"), + mcCollision.posZ(), cgen); + } else { + qaregistry.fill(HIST("Events/NotFoundEventZvtx"), mcCollision.posZ()); + } + } + } + + void processMCwBestTracksInclusive( + aod::McCollisions::iterator const& mccollision, + soa::SmallGroups> const& collisions, + FiltParticles const& particles, FiltMcMftTracks const& tracks, + FiltBestTracks const& besttracks) + { + processMCwBestTracks( + mccollision, collisions, particles, tracks, besttracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processMCwBestTracksInclusive, + "Count MC particles using aod::BestCollisionsFwd (inclusive)", + false); + + void processMCwBestTracksCentFT0C( + aod::McCollisions::iterator const& mccollision, + soa::SmallGroups> const& collisions, + FiltParticles const& particles, FiltMcMftTracks const& tracks, + FiltBestTracks const& besttracks) + { + processMCwBestTracks( + mccollision, collisions, particles, tracks, besttracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processMCwBestTracksCentFT0C, + "Count MC particles in FT0C centrality bins using aod::BestCollisionsFwd", + false); + + void processMCwBestTracksCentFT0CVariant1( + aod::McCollisions::iterator const& mccollision, + soa::SmallGroups> const& collisions, + FiltParticles const& particles, FiltMcMftTracks const& tracks, + FiltBestTracks const& besttracks) + { + processMCwBestTracks( + mccollision, collisions, particles, tracks, besttracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processMCwBestTracksCentFT0CVariant1, + "Count MC particles in FT0CVariant1 centrality bins using " + "aod::BestCollisionsFwd", + false); + + void processMCwBestTracksCentFT0M( + aod::McCollisions::iterator const& mccollision, + soa::SmallGroups> const& collisions, + FiltParticles const& particles, FiltMcMftTracks const& tracks, + FiltBestTracks const& besttracks) + { + processMCwBestTracks( + mccollision, collisions, particles, tracks, besttracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processMCwBestTracksCentFT0M, + "Count MC particles in FT0M centrality bins using aod::BestCollisionsFwd", + false); + + void processMCwBestTracksCentNGlobal( + aod::McCollisions::iterator const& mccollision, + soa::SmallGroups> const& collisions, + FiltParticles const& particles, FiltMcMftTracks const& tracks, + FiltBestTracks const& besttracks) + { + processMCwBestTracks( + mccollision, collisions, particles, tracks, besttracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processMCwBestTracksCentNGlobal, + "Count MC particles in NGlobal centrality bins using " + "aod::BestCollisionsFwd", + false); + + void processMCwBestTracksCentMFT( + aod::McCollisions::iterator const& mccollision, + soa::SmallGroups> const& collisions, + FiltParticles const& particles, FiltMcMftTracks const& tracks, + FiltBestTracks const& besttracks) + { + processMCwBestTracks( + mccollision, collisions, particles, tracks, besttracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processMCwBestTracksCentMFT, + "Count MC particles in MFT centrality bins using aod::BestCollisionsFwd", + false); + + using ParticlesI = soa::Join; + Partition primariesI = + ((aod::mcparticle::flags & + (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary) == + (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary); + + /// @brief process template function to calculate tracking efficiency (indexed + /// as particle-to-MFT-tracks) + template + void processTrkEffIdx( + typename soa::Join const& collisions, + MC const& /*mccollisions*/, ParticlesI const& /*particles*/, + MFTTracksLabeled const& tracks) + { + for (auto const& collision : collisions) { + if (!isGoodEvent(collision)) { + continue; + } + if (!collision.has_mcCollision()) { + continue; + } + + float crec = getRecoCent(collision); + auto occrec = getOccupancy(collision, eventCuts.occupancyEstimator); + auto mcCollision = collision.mcCollision(); + + auto partsPerCol = primariesI->sliceByCached( + aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); + partsPerCol.bindExternalIndices(&tracks); + + for (auto const& particle : partsPerCol) { + if (!isChrgParticle(particle.pdgCode())) { + continue; + } + + // MC gen + if constexpr (has_reco_cent) { + if (particle.eta() > trackCuts.minEta && particle.eta() < trackCuts.maxEta) { + if (std::abs(mcCollision.posZ()) < eventCuts.maxZvtx) { + qaregistry.fill(HIST("Tracks/Centrality/hPtEtaEffGen"), particle.pt(), particle.eta(), crec, occrec); + } + } + } else { + if (particle.eta() > trackCuts.minEta && particle.eta() < trackCuts.maxEta) { + if (std::abs(mcCollision.posZ()) < eventCuts.maxZvtx) { + qaregistry.fill(HIST("Tracks/hPtEtaEffGen"), particle.pt(), particle.eta(), occrec); + } + } + } + // MC rec + if (particle.has_mfttracks()) { + auto iscounted = false; + auto ncnt = 0; + auto relatedTracks = particle.template mfttracks_as(); + for (auto const& track : relatedTracks) { + ++ncnt; + if constexpr (has_reco_cent) { + if (track.eta() > trackCuts.minEta && track.eta() < trackCuts.maxEta) { + if (!iscounted) { // primaries + if (std::abs(mcCollision.posZ()) < eventCuts.maxZvtx) { + qaregistry.fill(HIST("Tracks/Centrality/hPtEtaEffPrim"), particle.pt(), particle.eta(), crec, occrec); + } + iscounted = true; + } + } + if (ncnt > 1) { // secondaries + if (track.eta() > trackCuts.minEta && track.eta() < trackCuts.maxEta) { + qaregistry.fill(HIST("Tracks/Centrality/hPtEtaEffSec"), particle.pt(), particle.eta(), crec, occrec); + } + } + } else { + if (track.eta() > trackCuts.minEta && track.eta() < trackCuts.maxEta) { + if (!iscounted) { // primaries + if (std::abs(mcCollision.posZ()) < eventCuts.maxZvtx) { + qaregistry.fill(HIST("Tracks/hPtEtaEffPrim"), particle.pt(), particle.eta(), occrec); + } + iscounted = true; + } + } + if (ncnt > 1) { // secondaries + if (track.eta() > trackCuts.minEta && track.eta() < trackCuts.maxEta) { + qaregistry.fill(HIST("Tracks/hPtEtaEffSec"), particle.pt(), particle.eta(), occrec); + } + } + } + } + + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/NmftTrkPerPart"), ncnt, crec, occrec); + } else { + qaregistry.fill(HIST("Tracks/NmftTrkPerPart"), ncnt, occrec); + } + + if (relatedTracks.size() > 1) { // duplicates + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/hPtEtaEffGenDupl"), particle.pt(), particle.eta(), crec, occrec); + for (auto const& track : relatedTracks) { + qaregistry.fill(HIST("Tracks/Centrality/hPtEtaEffDupl"), track.pt(), track.eta(), crec, occrec); + } + } else { + qaregistry.fill(HIST("Tracks/hPtEtaEffGenDupl"), particle.pt(), particle.eta(), occrec); + for (auto const& track : relatedTracks) { + qaregistry.fill(HIST("Tracks/hPtEtaEffDupl"), track.pt(), track.eta(), occrec); + } + } + } + } + } + } + } + + void processTrkEffIdxInlusive( + soa::Join const& collisions, + aod::McCollisions const& mccollisions, ParticlesI const& particles, + MFTTracksLabeled const& tracks) + { + processTrkEffIdx(collisions, mccollisions, + particles, tracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processTrkEffIdxInlusive, + "Process tracking efficiency (inclusive, indexed)", false); + + void processTrkEffIdxCentFT0C( + soa::Join const& collisions, + aod::McCollisions const& mccollisions, ParticlesI const& particles, + MFTTracksLabeled const& tracks) + { + processTrkEffIdx(collisions, mccollisions, + particles, tracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processTrkEffIdxCentFT0C, + "Process tracking efficiency (in FT0C centrality bins, indexed)", false); + + /// @brief process function to calculate tracking efficiency (indexed) based + /// on BestCollisionsFwd in FT0C bins + template + void processTrkEffBest( + typename soa::Join::iterator const& collision, + MC const& /*mccollisions*/, FiltParticles const& particles, + FiltMcMftTracks const& /*tracks*/, + soa::SmallGroups const& besttracks) + { + if (!isGoodEvent(collision)) { + return; + } + if (!collision.has_mcCollision()) { + return; + } + + float crec = getRecoCent(collision); + auto occrec = getOccupancy(collision, eventCuts.occupancyEstimator); + auto mcCollision = collision.mcCollision(); + auto partsPerCol = particles.sliceByCached( + aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); + + for (auto const& particle : partsPerCol) { + if (!isChrgParticle(particle.pdgCode())) { + continue; + } + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/hPtPhiEtaZvtxEffBestGen"), + particle.pt(), particle.phi(), particle.eta(), + mcCollision.posZ(), crec, occrec); + } else { + qaregistry.fill(HIST("Tracks/hPtPhiEtaZvtxEffBestGen"), particle.pt(), + particle.phi(), particle.eta(), mcCollision.posZ(), + occrec); + } + } + + for (auto const& track : besttracks) { + auto itrack = track.mfttrack_as(); + if (!isTrackSelected(itrack)) { + continue; + } + if (itrack.has_mcParticle()) { + auto particle = itrack.mcParticle_as(); + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/hPtPhiEtaZvtxEffBestRec"), + particle.pt(), itrack.phi(), itrack.eta(), + mcCollision.posZ(), crec, occrec); + } else { + qaregistry.fill(HIST("Tracks/hPtPhiEtaZvtxEffBestRec"), particle.pt(), + itrack.phi(), itrack.eta(), mcCollision.posZ(), + occrec); + } + } else { + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/hPtEffBestFakeRec"), + itrack.pt(), crec, occrec); + } else { + qaregistry.fill(HIST("Tracks/hPtEffBestFakeRec"), itrack.pt(), + occrec); + } + } + } + } + + void processTrkEffBestInclusive( + soa::Join::iterator const& collision, + aod::McCollisions const& mccollisions, FiltParticles const& particles, + FiltMcMftTracks const& tracks, + soa::SmallGroups const& besttracks) + { + processTrkEffBest(collision, mccollisions, + particles, tracks, besttracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processTrkEffBestInclusive, + "Process tracking efficiency (inclusive, based on BestCollisionsFwd)", + false); + + void processTrkEffBestCentFT0C( + soa::Join::iterator const& collision, + aod::McCollisions const& mccollisions, FiltParticles const& particles, + FiltMcMftTracks const& tracks, + soa::SmallGroups const& besttracks) + { + processTrkEffBest( + collision, mccollisions, particles, tracks, besttracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processTrkEffBestCentFT0C, + "Process tracking efficiency (in FT0 centrality bins, based " + "on BestCollisionsFwd)", + false); + + Preslice filtMcTrkperCol = o2::aod::fwdtrack::collisionId; + + /// @brief process function to calculate MC efficiency and fraction of fake + /// tracks + template + void processEfficiency( + typename soa::Join const& collisions, + MC const& /*mccollisions*/, FiltParticles const& /*particles*/, + FiltMcMftTracks const& tracks) + { + for (auto const& collision : collisions) { + if (!isGoodEvent(collision)) { + continue; + } + + float crec = getRecoCent(collision); + auto occrec = getOccupancy(collision, eventCuts.occupancyEstimator); + auto mcCollision = collision.mcCollision(); + auto perColTrks = + tracks.sliceBy(filtMcTrkperCol, collision.globalIndex()); + + for (auto const& track : perColTrks) { + if (!isTrackSelected(track)) { + continue; + } + if (track.has_mcParticle()) { + auto particle = track.template mcParticle_as(); + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/hEffRec"), particle.pt(), + particle.phi(), particle.eta(), mcCollision.posZ(), + crec, occrec); + } else { + qaregistry.fill(HIST("Tracks/hEffRec"), particle.pt(), + particle.phi(), particle.eta(), mcCollision.posZ(), + crec, occrec); + } + } else { + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/hEffFake"), track.pt(), + track.phi(), track.eta(), mcCollision.posZ(), crec, + occrec); + } else { + qaregistry.fill(HIST("Tracks/hEffFake"), track.pt(), track.phi(), + track.eta(), mcCollision.posZ(), crec, occrec); + } + } + } + } + } + + void processEfficiencyInclusive( + soa::Join const& collisions, + aod::McCollisions const& mccollisions, FiltParticles const& particles, + FiltMcMftTracks const& tracks) + { + processEfficiency(collisions, mccollisions, + particles, tracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processEfficiencyInclusive, + "Process efficiencies (inclusive)", false); + + void processEfficiencyCentFT0C( + soa::Join const& collisions, + aod::McCollisions const& mccollisions, FiltParticles const& particles, + FiltMcMftTracks const& tracks) + { + processEfficiency( + collisions, mccollisions, particles, tracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processEfficiencyCentFT0C, + "Process efficiencies in FT0C centrality bins", false); + + /// @brief process function to check ambiguous tracks + template + void processCheckAmbiguousMftTracks(typename C::iterator const& collision, + allC const& allcollisions, + MftTracksWColls const& tracks) + { + auto occ = getOccupancy(collision, eventCuts.occupancyEstimator); + float c = getRecoCent(collision); + + bool ambTrk = false; + int typeAmbTrk = 0; + for (auto const& track : tracks) { + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/hMftTracksAmbDegree"), + track.compatibleCollIds().size(), c, occ); + } else { + qaregistry.fill(HIST("Tracks/hMftTracksAmbDegree"), + track.compatibleCollIds().size(), occ); + } + if (track.compatibleCollIds().size() > 0) { + if (track.compatibleCollIds().size() == 1) { + if (track.collisionId() != track.compatibleCollIds()[0]) { + ambTrk = true; + typeAmbTrk = 2; + } else { + typeAmbTrk = 1; + } + } else { + ambTrk = true; + typeAmbTrk = 3; + + for (const auto& collIdx : track.compatibleCollIds()) { + auto ambColl = allcollisions.rawIteratorAt(collIdx); + qaregistry.fill(HIST("Tracks/histAmbZvtx"), ambColl.posZ()); + } + } + } + } + + if (ambTrk) { + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/hAmbTrackType"), typeAmbTrk, c, + occ); + } else { + qaregistry.fill(HIST("Tracks/hAmbTrackType"), typeAmbTrk, occ); + } + } else { + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/hAmbTrackType"), typeAmbTrk, c, + occ); + } else { + qaregistry.fill(HIST("Tracks/hAmbTrackType"), typeAmbTrk, occ); + } + } + } + + void processCheckAmbiguousMftTracksInclusive(Colls::iterator const& collision, + Colls const& allcollisions, + MftTracksWColls const& track) + { + processCheckAmbiguousMftTracks(collision, allcollisions, + track); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processCheckAmbiguousMftTracksInclusive, + "Process checks for Ambiguous MFT tracks (inclusive)", false); + + void processCheckAmbiguousMftTracksCentFT0C( + CollsCentFT0C::iterator const& collision, + CollsCentFT0C const& allcollisions, MftTracksWColls const& track) + { + processCheckAmbiguousMftTracks( + collision, allcollisions, track); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processCheckAmbiguousMftTracksCentFT0C, + "Process checks for Ambiguous MFT tracks (in FT0C centrality bins)", + false); + + Preslice filtTrkperCol = o2::aod::fwdtrack::collisionId; + + /// @brief process template function for MC QA checks + template + void + processMcQA(typename soa::Join const& collisions, + MFTTracksLabeled const& tracks, + aod::AmbiguousMFTTracks const& atracks, + aod::McCollisions const& mcCollisions, + FiltParticles const& /*particles*/) + { + for (const auto& collision : collisions) { + float crec = getRecoCent(collision); + auto occrec = getOccupancy(collision, eventCuts.occupancyEstimator); + + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Events/Centrality/hRecPerGenColls"), + static_cast(collisions.size()) / + mcCollisions.size(), + crec, occrec); + } else { + qaregistry.fill(HIST("Events/hRecPerGenColls"), + static_cast(collisions.size()) / + mcCollisions.size(), + occrec); + } + + if (!isGoodEvent(collision)) { + return; + } + + auto trkPerColl = tracks.sliceBy(filtTrkperCol, collision.globalIndex()); + uint ntracks{0u}, nAtracks{0u}; + for (const auto& track : trkPerColl) { + ntracks++; + for (const auto& atrack : atracks) { + if (atrack.mfttrackId() == track.globalIndex()) { + nAtracks++; + break; + } + } + } + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/hNmftTrks"), ntracks, crec, + occrec); + qaregistry.fill(HIST("Tracks/Centrality/hFracAmbiguousMftTrks"), + static_cast(nAtracks) / ntracks, crec, occrec); + } else { + qaregistry.fill(HIST("Tracks/hNmftTrks"), ntracks, occrec); + qaregistry.fill(HIST("Tracks/hFracAmbiguousMftTrks"), + static_cast(nAtracks) / ntracks, occrec); + } + } + } + + void processMcQAInclusive( + soa::Join const& collisions, + MFTTracksLabeled const& tracks, aod::AmbiguousMFTTracks const& atracks, + aod::McCollisions const& mcCollisions, FiltParticles const& particles) + { + processMcQA(collisions, tracks, atracks, mcCollisions, particles); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processMcQAInclusive, + "Process MC QA checks (inclusive)", false); + + void processMcQACentFT0C( + soa::Join const& collisions, + MFTTracksLabeled const& tracks, aod::AmbiguousMFTTracks const& atracks, + aod::McCollisions const& mcCollisions, FiltParticles const& particles) + { + processMcQA(collisions, tracks, atracks, mcCollisions, + particles); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processMcQACentFT0C, + "Process MC QA checks (in FT0 centrality bins)", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGMM/Mult/Tasks/heavy-ion-mult.cxx b/PWGMM/Mult/Tasks/heavy-ion-mult.cxx index 7017d046a2c..bb12521502d 100644 --- a/PWGMM/Mult/Tasks/heavy-ion-mult.cxx +++ b/PWGMM/Mult/Tasks/heavy-ion-mult.cxx @@ -23,6 +23,7 @@ #include #include #include +#include #include "bestCollisionTable.h" #include "CCDB/BasicCCDBManager.h" @@ -42,6 +43,9 @@ #include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/GlobalTrackID.h" #include "ReconstructionDataFormats/Track.h" +#include "Index.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" using namespace o2; using namespace o2::framework; @@ -49,17 +53,44 @@ using namespace o2::framework::expressions; using namespace o2::aod::track; using namespace o2::aod::evsel; -using CollisionDataTable = soa::Join; -using CollisionDataTableCorrelation = soa::Join; -using CollisionDataTableCentFT0C = soa::Join; +using CollisionDataTable = soa::Join; using TrackDataTable = soa::Join; using FilTrackDataTable = soa::Filtered; using CollisionMCTrueTable = aod::McCollisions; using TrackMCTrueTable = aod::McParticles; -using CollisionMCRecTable = soa::SmallGroups>; -using CollisionMCRecTableCentFT0C = soa::SmallGroups>; +using CollisionMCRecTable = soa::SmallGroups>; using TrackMCRecTable = soa::Join; using FilTrackMCRecTable = soa::Filtered; +using v0trackcandidates = soa::Join; + +enum { + kTrackTypebegin = 0, + kGlobalplusITS = 1, + kGlobalonly, + kITSonly, + kTrackTypeend +}; + +enum { + kGenpTbegin = 0, + kNoGenpTVar = 1, + kGenpTup, + kGenpTdown, + kGenpTend +}; + +enum { + kSpeciesbegin = 0, + kSpPion = 1, + kSpKaon, + kSpProton, + kSpOther, + kSpStrangeDecay, + kBkg, + kSpNotPrimary, + kSpAll, + kSpeciesend +}; static constexpr TrackSelectionFlags::flagtype trackSelectionITS = TrackSelectionFlags::kITSNCls | TrackSelectionFlags::kITSChi2NDF | @@ -73,14 +104,18 @@ static constexpr TrackSelectionFlags::flagtype trackSelectionDCA = static constexpr TrackSelectionFlags::flagtype trackSelectionDCAXYonly = TrackSelectionFlags::kDCAxy; -AxisSpec axisEvent{5, -0.5, 4.5, "#Event"}; -AxisSpec axisVtxZ{40, -20, 20, "Vertex Z"}; -AxisSpec axisDCA = {601, -3.01, 3.01}; -AxisSpec axisEta{40, -2, 2, "#eta"}; -AxisSpec axisPhi{629, 0, 2 * M_PI, "#phi"}; -AxisSpec axisPhi2{{0, M_PI / 2, M_PI, M_PI * 3. / 2, 2 * M_PI}, "#phi"}; -AxisSpec axisMCEvent_ambiguity{10, -0.5, 9.5, "reco collisions per true collision"}; +AxisSpec axisEvent{12, 0.5, 12.5, "#Event", "EventAxis"}; +AxisSpec axisVtxZ{40, -20, 20, "Vertex Z", "VzAxis"}; +AxisSpec axisEta{40, -2, 2, "#eta", "EtaAxis"}; +AxisSpec axisPhi{{0, M_PI / 4, M_PI / 2, M_PI * 3. / 4, M_PI, M_PI * 5. / 4, M_PI * 3. / 2, M_PI * 7. / 4, 2 * M_PI}, "#phi", "PhiAxis"}; +AxisSpec axisPhi2{629, 0, 2 * M_PI, "#phi"}; AxisSpec axisCent{100, 0, 100, "#Cent"}; +AxisSpec AxisTrackType = {kTrackTypeend - 1, +kTrackTypebegin + 0.5, +kTrackTypeend - 0.5, "", "TrackTypeAxis"}; +AxisSpec AxisGenpTVary = {kGenpTend - 1, +kGenpTbegin + 0.5, +kGenpTend - 0.5, "", "GenpTVaryAxis"}; +AxisSpec AxisSpecies = {kSpeciesend - 1, +kSpeciesbegin + 0.5, +kSpeciesend - 0.5, "", "SpeciesAxis"}; +AxisSpec AxisMassK0s = {200, 0.4, 0.6, "K0sMass", "K0sMass"}; +AxisSpec AxisMassLambda = {200, 1.07, 1.17, "Lambda/AntiLamda Mass", "Lambda/AntiLamda Mass"}; +AxisSpec axisTracks{9, 0.5, 9.5, "#tracks", "TrackAxis"}; struct HeavyIonMultiplicity { @@ -91,25 +126,51 @@ struct HeavyIonMultiplicity { Configurable etaRange{"eta-range", 1.0f, "Eta range to consider"}; Configurable VtxRange{"vertex-range", 10.0f, "Vertex Z range to consider"}; Configurable dcaZ{"dcaZ", 0.2f, "Custom DCA Z cut (ignored if negative)"}; + Configurable v0radiusCut{"v0radiusCut", 1.2f, "RadiusCut"}; + Configurable dcapostopvCut{"dcapostopvCut", 0.05f, "dcapostopvCut"}; + Configurable dcanegtopvCut{"dcanegtopvCut", 0.05f, "dcanegtopvCut"}; + Configurable v0cospaCut{"v0cospaCut", 0.995f, "v0cospaCut"}; + Configurable dcav0daughtercut{"dcav0daughtercut", 1.0f, "dcav0daughtercut"}; + Configurable minTPCnClsCut{"minTPCnClsCut", 50.0f, "minTPCnClsCut"}; + Configurable NSigmaTPCcut{"NSigmaTPCcut", 5.0f, "NSigmaTPCcut"}; ConfigurableAxis multHistBin{"MultDistBinning", {501, -0.5, 500.5}, ""}; ConfigurableAxis PVHistBin{"PVDistBinning", {501, -0.5, 500.5}, ""}; - ConfigurableAxis FV0multHistBin{"FV0MultDistBinning", {501, -0.5, 500.5}, ""}; - ConfigurableAxis FT0multHistBin{"FT0MultDistBinning", {501, -0.5, 500.5}, ""}; + ConfigurableAxis FV0AmultHistBin{"FV0AMultDistBinning", {501, -0.5, 500.5}, ""}; ConfigurableAxis FT0AmultHistBin{"FT0AMultDistBinning", {501, -0.5, 500.5}, ""}; ConfigurableAxis FT0CmultHistBin{"FT0CMultDistBinning", {501, -0.5, 500.5}, ""}; - ConfigurableAxis pTHistBin{"pTHistBin", {VARIABLE_WIDTH, 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, ""}; + ConfigurableAxis pTHistBin{"pTHistBin", {200, 0., 20.}, ""}; ConfigurableAxis CentralityBinning{"CentralityBinning", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}, ""}; + ConfigurableAxis OccupancyBin{"OccupancyBin", {VARIABLE_WIDTH, 0, 500, 1000, 2000, 5000, 10000}, ""}; + + Configurable IsApplySameBunchPileup{"IsApplySameBunchPileup", true, "Enable SameBunchPileup cut"}; + Configurable IsApplyGoodZvtxFT0vsPV{"IsApplyGoodZvtxFT0vsPV", true, "Enable GoodZvtxFT0vsPV cut"}; + Configurable IsApplyVertexITSTPC{"IsApplyVertexITSTPC", true, "Enable VertexITSTPC cut"}; + Configurable IsApplyVertexTOFmatched{"IsApplyVertexTOFmatched", true, "Enable VertexTOFmatched cut"}; + Configurable IsApplyVertexTRDmatched{"IsApplyVertexTRDmatched", true, "Enable VertexTRDmatched cut"}; + Configurable IsApplyExtraCorrCut{"IsApplyExtraCorrCut", false, "Enable extra NPVtracks vs FTOC correlation cut"}; + Configurable IsApplyExtraPhiCut{"IsApplyExtraPhiCut", false, "Enable extra phi cut"}; + Configurable NPVtracksCut{"NPVtracksCut", 1.0f, "Apply extra NPVtracks cut"}; + Configurable FT0CCut{"FT0CCut", 1.0f, "Apply extra FT0C cut"}; + Configurable IsApplyNoCollInTimeRangeStandard{"IsApplyNoCollInTimeRangeStandard", true, "Enable NoCollInTimeRangeStandard cut"}; + Configurable IsApplyNoCollInRofStandard{"IsApplyNoCollInRofStandard", true, "Enable NoCollInRofStandard cut"}; + Configurable IsApplyNoHighMultCollInPrevRof{"IsApplyNoHighMultCollInPrevRof", true, "Enable NoHighMultCollInPrevRof cut"}; + Configurable IsApplyFT0CbasedOccupancy{"IsApplyFT0CbasedOccupancy", true, "Enable FT0CbasedOccupancy cut"}; + Configurable IsApplyCentFT0C{"IsApplyCentFT0C", false, "Centrality based on FT0C"}; + Configurable IsApplyCentFT0CVariant1{"IsApplyCentFT0CVariant1", false, "Centrality based on FT0C variant1"}; + Configurable IsApplyCentFT0M{"IsApplyCentFT0M", false, "Centrality based on FT0A + FT0C"}; + Configurable IsApplyCentNGlobal{"IsApplyCentNGlobal", false, "Centrality based on global tracks"}; + Configurable IsApplyCentMFT{"IsApplyCentMFT", false, "Centrality based on MFT tracks"}; void init(InitContext const&) { - AxisSpec axisMult = {multHistBin}; - AxisSpec axisPV = {PVHistBin}; - AxisSpec axisFV0Mult = {FV0multHistBin}; - AxisSpec axisFT0Mult = {FT0multHistBin}; - AxisSpec axisFT0AMult = {FT0AmultHistBin}; - AxisSpec axisFT0CMult = {FT0CmultHistBin}; - AxisSpec CentAxis = {CentralityBinning, "Centrality"}; - AxisSpec axisPT = {pTHistBin}; + AxisSpec axisMult = {multHistBin, "Mult", "MultAxis"}; + AxisSpec axisPV = {PVHistBin, "PV", "PVAxis"}; + AxisSpec axisFV0AMult = {FV0AmultHistBin, "fv0a", "FV0AMultAxis"}; + AxisSpec axisFT0AMult = {FT0AmultHistBin, "ft0a", "FT0AMultAxis"}; + AxisSpec axisFT0CMult = {FT0CmultHistBin, "ft0c", "FT0CMultAxis"}; + AxisSpec CentAxis = {CentralityBinning, "Centrality", "CentralityAxis"}; + AxisSpec axisPT = {pTHistBin, "pT", "pTAxis"}; + AxisSpec axisOccupancy = {OccupancyBin, "occupancy", "OccupancyAxis"}; histos.add("EventHist", "EventHist", kTH1D, {axisEvent}, false); histos.add("VtxZHist", "VtxZHist", kTH1D, {axisVtxZ}, false); @@ -118,80 +179,190 @@ struct HeavyIonMultiplicity { auto* x = hstat->GetXaxis(); x->SetBinLabel(1, "All events"); x->SetBinLabel(2, "sel8"); - x->SetBinLabel(3, "kNoITSROFrameBorder"); - x->SetBinLabel(4, "kNoTimeFrameBorder"); - x->SetBinLabel(5, "|VtxZ|<10"); + x->SetBinLabel(3, "kNoSameBunchPileup"); // reject collisions in case of pileup with another collision in the same foundBC + x->SetBinLabel(4, "kIsGoodZvtxFT0vsPV"); // small difference between z-vertex from PV and from FT0 + x->SetBinLabel(5, "kIsVertexITSTPC"); // at least one ITS-TPC track (reject vertices built from ITS-only tracks) + x->SetBinLabel(6, "kIsVertexTOFmatched"); // at least one of vertex contributors is matched to TOF + x->SetBinLabel(7, "kIsVertexTRDmatched"); // at least one of vertex contributors is matched to TRD + x->SetBinLabel(8, "Centrality"); + x->SetBinLabel(9, "ApplyExtraCorrCut"); + x->SetBinLabel(10, "ApplyNoCollInTimeRangeStandard"); + x->SetBinLabel(11, "ApplyNoCollInRofStandard"); + x->SetBinLabel(12, "ApplyNoHighMultCollInPrevRof"); if (doprocessData) { - histos.add("MultHist", "MultHist", kTH1D, {axisMult}, true); - histos.add("EtaHist", "EtaHist", kTH1D, {axisEta}, true); - histos.add("PhiHist", "PhiHist", kTH1D, {axisPhi}, true); - histos.add("EtaVsVtxZHist", "EtaVsVtxZHist", kTH2D, {axisEta, axisVtxZ}, false); - histos.add("PhiVsEtaHist", "PhiVsEtaHist", kTH2D, {axisPhi, axisEta}, false); - histos.add("DCAXYHist", "DCAXYHist", kTH1D, {axisDCA}, false); - histos.add("DCAZHist", "DCAZHist", kTH1D, {axisDCA}, false); - histos.add("pTHist", "pTHist", kTH1D, {axisPT}, true); - } - - if (doprocessMC) { - histos.add("MCEventHist_ambiguity", "MCEventHist_ambiguity", kTH1D, {axisMCEvent_ambiguity}, false); - histos.add("MCRecEtaHist", "MCRecEtaHist", kTH1D, {axisEta}, true); - histos.add("MCRecPhiHist", "MCRecPhiHist", kTH1D, {axisPhi}, true); - histos.add("MCRecPhiVsEtaHist", "MCRecPhiVsEtaHist", kTH2D, {axisPhi, axisEta}, false); - histos.add("EtaVsVtxZMCRecHist", "EtaVsVtxZMCRecHist", kTH2D, {axisEta, axisVtxZ}, true); - histos.add("DCAXYMCRecHist", "DCAXYMCRecHist", kTH1D, {axisDCA}, false); - histos.add("DCAZMCRecHist", "DCAZMCRecHist", kTH1D, {axisDCA}, false); - histos.add("pTMCRecHist", "pTMCRecHist", kTH1D, {axisPT}, true); - histos.add("MCRecMultHist", "MCRecMultHist", kTH1D, {axisMult}, true); - - histos.add("MCGenEtaHist", "MCGenEtaHist", kTH1D, {axisEta}, true); - histos.add("MCGenPhiHist", "MCGenPhiHist", kTH1D, {axisPhi}, true); - histos.add("MCGenPhiVsEtaHist", "MCGenPhiVsEtaHist", kTH2D, {axisPhi, axisEta}, false); - histos.add("EtaVsVtxZMCGenHist", "EtaVsVtxZMCGenHist", kTH2D, {axisEta, axisVtxZ}, true); - histos.add("MCGenMultHist", "MCGenMultHist", kTH1D, {axisMult}, true); - histos.add("MCGenVsRecMultHist", "MCGenVsRecMultHist", kTH2D, {axisMult, axisMult}, true); - histos.add("pTMCGenHist", "pTMCGenHist", kTH1D, {axisPT}, true); - histos.add("VtxZGenHist", "VtxZGenHist", kTH1D, {axisVtxZ}, false); - - histos.add("MCGenEtaHistAll", "MCGenEtaHistAll", kTH1D, {axisEta}, true); - histos.add("MCGenPhiHistAll", "MCGenPhiHistAll", kTH1D, {axisPhi}, true); - histos.add("MCGenPhiVsEtaHistAll", "MCGenPhiVsEtaHistAll", kTH2D, {axisPhi, axisEta}, false); - histos.add("EtaVsVtxZMCGenHistAll", "EtaVsVtxZMCGenHistAll", kTH2D, {axisEta, axisVtxZ}, true); - histos.add("MCGenMultHistAll", "MCGenMultHistAll", kTH1D, {axisMult}, true); - } - - if (doprocessDataCentFT0C) { histos.add("CentPercentileHist", "CentPercentileHist", kTH1D, {axisCent}, false); - histos.add("CentHistInsideTrackloop", "CentHistInsideTrackloop", kTH1D, {axisCent}, false); - histos.add("hdatamult", "hdatamult", kTHnSparseF, {axisVtxZ, axisMult, CentAxis}, false); - histos.add("hdatadndeta", "hdatadndeta", kTHnSparseF, {axisVtxZ, CentAxis, axisEta, axisPhi2}, false); - histos.add("hdatazvtxcent", "hdatazvtxcent", kTH2D, {axisVtxZ, CentAxis}, false); + histos.add("hdatamult", "hdatamult", kTHnSparseD, {axisVtxZ, axisMult, CentAxis}, false); + histos.add("hdatadndeta", "hdatadndeta", kTHnSparseD, {axisVtxZ, CentAxis, axisOccupancy, axisEta, axisPhi, AxisTrackType}, false); + histos.add("hdatazvtxcent", "hdatazvtxcent", kTH3D, {axisVtxZ, CentAxis, axisOccupancy}, false); + histos.add("PhiVsEtaHist", "PhiVsEtaHist", kTH2D, {axisPhi2, axisEta}, false); } - if (doprocessMCCentFT0C) { + if (doprocessMonteCarlo || doprocessMCpTefficiency || doprocessMCcheckFakeTracks || doprocessMCfillspecies) { histos.add("CentPercentileMCRecHist", "CentPercentileMCRecHist", kTH1D, {axisCent}, false); - histos.add("hmczvtxcent", "hmczvtxcent", kTH2D, {axisVtxZ, CentAxis}, false); - histos.add("hrecdndeta_pion", "hrecdndeta_pion", kTHnSparseF, {axisVtxZ, axisEta, axisPhi2, CentAxis, axisPT}, false); - histos.add("hrecdndeta_kaon", "hrecdndeta_kaon", kTHnSparseF, {axisVtxZ, axisEta, axisPhi2, CentAxis, axisPT}, false); - histos.add("hrecdndeta_proton", "hrecdndeta_proton", kTHnSparseF, {axisVtxZ, axisEta, axisPhi2, CentAxis, axisPT}, false); - histos.add("hrecdndeta_other", "hrecdndeta_other", kTHnSparseF, {axisVtxZ, axisEta, axisPhi2, CentAxis, axisPT}, false); - histos.add("hrecdndeta_bkg", "hrecdndeta_bkg", kTHnSparseF, {axisVtxZ, axisEta, axisPhi2, CentAxis, axisPT}, false); - histos.add("hrecdndeta_NotPrimary", "hrecdndeta_NotPrimary", kTHnSparseF, {axisVtxZ, axisEta, axisPhi2, CentAxis, axisPT}, false); - histos.add("hgendndeta_pion", "hgendndeta_pion", kTHnSparseF, {axisVtxZ, axisEta, axisPhi2, CentAxis, axisPT}, false); - histos.add("hgendndeta_kaon", "hgendndeta_kaon", kTHnSparseF, {axisVtxZ, axisEta, axisPhi2, CentAxis, axisPT}, false); - histos.add("hgendndeta_proton", "hgendndeta_proton", kTHnSparseF, {axisVtxZ, axisEta, axisPhi2, CentAxis, axisPT}, false); - histos.add("hgendndeta_other", "hgendndeta_other", kTHnSparseF, {axisVtxZ, axisEta, axisPhi2, CentAxis, axisPT}, false); + histos.add("hmczvtxcent", "hmczvtxcent", kTH3D, {axisVtxZ, CentAxis, axisOccupancy}, false); + } + + if (doprocessMonteCarlo) { + histos.add("MCrecPhiVsEtaHist", "MCrecPhiVsEtaHist", kTH2D, {axisPhi2, axisEta}, false); + histos.add("hmcrecdndeta", "hmcrecdndeta", kTHnSparseD, {axisVtxZ, CentAxis, axisOccupancy, axisEta, axisPhi}, false); + histos.add("hmcgendndeta", "hmcgendndeta", kTHnSparseD, {axisVtxZ, CentAxis, axisEta, axisPhi, AxisGenpTVary}, false); + } + + if (doprocessMCfillspecies) { + histos.add("FillMCrecSpecies", "FillMCrecSpecies", kTHnSparseD, {CentAxis, axisOccupancy, axisEta, AxisSpecies}, false); + histos.add("FillMCgenSpecies", "FillMCgenSpecies", kTHnSparseD, {CentAxis, axisEta, AxisSpecies}, false); + } + + if (doprocessMCpTefficiency) { + histos.add("hmcrecdndpt", "hmcrecdndpt", kTHnSparseD, {CentAxis, axisPT}, false); + histos.add("hmcgendndpt", "hmcgendndpt", kTHnSparseD, {CentAxis, axisPT, AxisGenpTVary}, false); + } + + if (doprocessMCcheckFakeTracks) { + histos.add("hTracksCount", "hTracksCount", kTHnSparseD, {CentAxis, axisTracks}, false); + auto htrack = histos.get(HIST("hTracksCount")); + auto* x2 = htrack->GetAxis(1); + x2->SetBinLabel(1, "All tracks"); + x2->SetBinLabel(2, "Non-fake tracks"); + for (int i = 0; i < 7; i++) { + x2->SetBinLabel(i + 3, Form("layer %d", i)); + } } if (doprocessCorrelation) { - histos.add("GlobalMult_vs_FT0A", "GlobalMult_vs_FT0A", kTH2F, {axisFT0AMult, axisMult}, true); - histos.add("GlobalMult_vs_FT0C", "GlobalMult_vs_FT0C", kTH2F, {axisFT0CMult, axisMult}, true); - histos.add("GlobalMult_vs_FT0", "GlobalMult_vs_FT0", kTH2F, {axisFT0Mult, axisMult}, true); - histos.add("GlobalMult_vs_FV0", "GlobalMult_vs_FV0", kTH2F, {axisFV0Mult, axisMult}, true); - histos.add("GlobalMult_vs_NumPVContributor", "GlobalMult_vs_NumPVContributor", kTH2F, {axisPV, axisMult}, true); + histos.add("GlobalMult_vs_FT0A", "GlobalMult_vs_FT0A", kTH2F, {axisMult, axisFT0AMult}, true); + histos.add("GlobalMult_vs_FT0C", "GlobalMult_vs_FT0C", kTH2F, {axisMult, axisFT0CMult}, true); + histos.add("NPVtracks_vs_FT0C", "NPVtracks_vs_FT0C", kTH2F, {axisPV, axisFT0CMult}, true); + histos.add("GlobalMult_vs_FV0A", "GlobalMult_vs_FV0A", kTH2F, {axisMult, axisFV0AMult}, true); + histos.add("NPVtracks_vs_GlobalMult", "NPVtracks_vs_GlobalMult", kTH2F, {axisPV, axisMult}, true); + } + + if (doprocessStrangeYield) { + histos.add("hzvtxcent", "hzvtxcent", kTH2D, {axisVtxZ, CentAxis}, false); + histos.add("K0sCentEtaMass", "K0sCentEtaMass", kTH3D, {CentAxis, axisEta, AxisMassK0s}, false); + histos.add("LambdaCentEtaMass", "LambdaCentEtaMass", kTH3D, {CentAxis, axisEta, AxisMassLambda}, false); + histos.add("AntiLambdaCentEtaMass", "AntiLambdaCentEtaMass", kTH3D, {CentAxis, axisEta, AxisMassLambda}, false); } } + template + bool IsTrackSelected(CheckTrack const& track) + { + if (std::abs(track.eta()) >= etaRange) { + return false; + } + if (IsApplyExtraPhiCut && ((track.phi() > 3.07666 && track.phi() < 3.12661) || track.phi() <= 0.03 || track.phi() >= 6.253)) { + return false; + } + return true; + } + template + bool IsGenTrackSelected(CheckGenTrack const& track) + { + if (!track.isPhysicalPrimary()) { + return false; + } + if (!track.producedByGenerator()) { + return false; + } + auto pdgTrack = pdg->GetParticle(track.pdgCode()); + if (pdgTrack == nullptr) { + return false; + } + if (std::abs(pdgTrack->Charge()) < 3) { + return false; + } + if (std::abs(track.eta()) >= etaRange) { + return false; + } + if (IsApplyExtraPhiCut && ((track.phi() > 3.07666 && track.phi() < 3.12661) || track.phi() <= 0.03 || track.phi() >= 6.253)) { + return false; + } + return true; + } + template + bool IsEventSelected(CheckCol const& col) + { + histos.fill(HIST("EventHist"), 1); + + if (!col.sel8()) { + return false; + } + histos.fill(HIST("EventHist"), 2); + + if (IsApplySameBunchPileup && !col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + histos.fill(HIST("EventHist"), 3); + + if (IsApplyGoodZvtxFT0vsPV && !col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + histos.fill(HIST("EventHist"), 4); + + if (IsApplyVertexITSTPC && !col.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + histos.fill(HIST("EventHist"), 5); + + if (IsApplyVertexTOFmatched && !col.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return false; + } + histos.fill(HIST("EventHist"), 6); + + if (IsApplyVertexTRDmatched && !col.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + return false; + } + histos.fill(HIST("EventHist"), 7); + + if (col.centFT0C() < 0. || col.centFT0C() > 100.) { + return false; + } + histos.fill(HIST("EventHist"), 8); + + if (IsApplyExtraCorrCut && col.multNTracksPV() > NPVtracksCut && col.multFT0C() < (10 * col.multNTracksPV() - FT0CCut)) { + return false; + } + histos.fill(HIST("EventHist"), 9); + + if (IsApplyNoCollInTimeRangeStandard && !col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + histos.fill(HIST("EventHist"), 10); + + if (IsApplyNoCollInRofStandard && !col.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + histos.fill(HIST("EventHist"), 11); + + if (IsApplyNoHighMultCollInPrevRof && !col.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + return false; + } + histos.fill(HIST("EventHist"), 12); + return true; + } + template + float SelectColCentrality(CheckColCent const& col) + { + auto cent = -1; + if (IsApplyCentFT0C) { + cent = col.centFT0C(); + } + if (IsApplyCentFT0CVariant1) { + cent = col.centFT0CVariant1(); + } + if (IsApplyCentFT0M) { + cent = col.centFT0M(); + } + if (IsApplyCentNGlobal) { + cent = col.centNGlobal(); + } + if (IsApplyCentMFT) { + cent = col.centMFT(); + } + return cent; + } expressions::Filter trackSelectionProperMixed = ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) && ncheckbit(aod::track::trackCutFlag, trackSelectionITS) && ifnode(ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC), @@ -201,292 +372,304 @@ struct HeavyIonMultiplicity { void processData(CollisionDataTable::iterator const& collision, FilTrackDataTable const& tracks) { + if (!IsEventSelected(collision)) { + return; + } + histos.fill(HIST("VtxZHist"), collision.posZ()); + histos.fill(HIST("CentPercentileHist"), SelectColCentrality(collision)); + auto OccupancyValue = IsApplyFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + histos.fill(HIST("hdatazvtxcent"), collision.posZ(), SelectColCentrality(collision), OccupancyValue); + auto NchTracks = 0; - histos.fill(HIST("EventHist"), 0); - if (collision.sel8()) { - histos.fill(HIST("EventHist"), 1); - if (collision.selection_bit(kNoITSROFrameBorder)) { - histos.fill(HIST("EventHist"), 2); - if (collision.selection_bit(kNoTimeFrameBorder)) { - histos.fill(HIST("EventHist"), 3); - if (std::abs(collision.posZ()) < VtxRange) { - histos.fill(HIST("EventHist"), 4); - histos.fill(HIST("VtxZHist"), collision.posZ()); - for (auto& track : tracks) { - if (std::abs(track.eta()) < etaRange) { - NchTracks++; - histos.fill(HIST("EtaHist"), track.eta()); - histos.fill(HIST("PhiHist"), track.phi()); - histos.fill(HIST("PhiVsEtaHist"), track.phi(), track.eta()); - histos.fill(HIST("EtaVsVtxZHist"), track.eta(), collision.posZ()); - histos.fill(HIST("DCAXYHist"), track.dcaXY()); - histos.fill(HIST("DCAZHist"), track.dcaZ()); - histos.fill(HIST("pTHist"), track.pt()); - } - } - histos.fill(HIST("MultHist"), NchTracks); - } - } + for (auto& track : tracks) { + if (!IsTrackSelected(track)) { + continue; + } + histos.fill(HIST("PhiVsEtaHist"), track.phi(), track.eta()); + NchTracks++; + histos.fill(HIST("hdatadndeta"), collision.posZ(), SelectColCentrality(collision), OccupancyValue, track.eta(), track.phi(), kGlobalplusITS); + if (track.hasTPC()) { + histos.fill(HIST("hdatadndeta"), collision.posZ(), SelectColCentrality(collision), OccupancyValue, track.eta(), track.phi(), kGlobalonly); + } else { + histos.fill(HIST("hdatadndeta"), collision.posZ(), SelectColCentrality(collision), OccupancyValue, track.eta(), track.phi(), kITSonly); } } + histos.fill(HIST("hdatamult"), collision.posZ(), NchTracks, SelectColCentrality(collision)); } + PROCESS_SWITCH(HeavyIonMultiplicity, processData, "process data CentFT0C", false); - PROCESS_SWITCH(HeavyIonMultiplicity, processData, "process data", false); - - void processMC(CollisionMCTrueTable::iterator const& TrueCollision, CollisionMCRecTable const& RecCollisions, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + void processCorrelation(CollisionDataTable::iterator const& collision, FilTrackDataTable const& tracks) { - histos.fill(HIST("MCEventHist_ambiguity"), RecCollisions.size()); - if (RecCollisions.size() == 0 || RecCollisions.size() > 1) { + if (!IsEventSelected(collision)) { + return; + } + if (std::abs(collision.posZ()) >= VtxRange) { return; } + histos.fill(HIST("VtxZHist"), collision.posZ()); - auto NchRecTracks = 0; - auto NchGenTracks = 0; - for (auto& RecCollision : RecCollisions) { - histos.fill(HIST("EventHist"), 0); - if (RecCollision.sel8()) { - histos.fill(HIST("EventHist"), 1); - if (RecCollision.selection_bit(kNoITSROFrameBorder)) { - histos.fill(HIST("EventHist"), 2); - if (RecCollision.selection_bit(kNoTimeFrameBorder)) { - histos.fill(HIST("EventHist"), 3); - if (std::abs(RecCollision.posZ()) < VtxRange) { - histos.fill(HIST("EventHist"), 4); - histos.fill(HIST("VtxZHist"), RecCollision.posZ()); - - auto Rectrackspart = RecTracks.sliceBy(perCollision, RecCollision.globalIndex()); - for (auto& Rectrack : Rectrackspart) { - if (std::abs(Rectrack.eta()) < etaRange) { - NchRecTracks++; - histos.fill(HIST("MCRecEtaHist"), Rectrack.eta()); - histos.fill(HIST("MCRecPhiHist"), Rectrack.phi()); - histos.fill(HIST("MCRecPhiVsEtaHist"), Rectrack.phi(), Rectrack.eta()); - histos.fill(HIST("EtaVsVtxZMCRecHist"), Rectrack.eta(), RecCollision.posZ()); - histos.fill(HIST("DCAXYMCRecHist"), Rectrack.dcaXY()); - histos.fill(HIST("DCAZMCRecHist"), Rectrack.dcaZ()); - histos.fill(HIST("pTMCRecHist"), Rectrack.pt()); - } - } - - for (auto& particle : GenParticles) { - if (!particle.isPhysicalPrimary()) { - continue; - } - if (!particle.producedByGenerator()) { - continue; - } - auto pdgParticle = pdg->GetParticle(particle.pdgCode()); - if (pdgParticle == nullptr) { - continue; - } - if (std::abs(pdgParticle->Charge()) >= 3) { - if (std::abs(particle.eta()) < etaRange) { - NchGenTracks++; - histos.fill(HIST("MCGenEtaHist"), particle.eta()); - histos.fill(HIST("MCGenPhiHist"), particle.phi()); - histos.fill(HIST("MCGenPhiVsEtaHist"), particle.phi(), particle.eta()); - histos.fill(HIST("EtaVsVtxZMCGenHist"), particle.eta(), RecCollision.posZ()); - histos.fill(HIST("pTMCGenHist"), particle.pt()); - } - } - } - - histos.fill(HIST("MCRecMultHist"), NchRecTracks); - histos.fill(HIST("MCGenMultHist"), NchGenTracks); - histos.fill(HIST("MCGenVsRecMultHist"), NchRecTracks, NchGenTracks); - } - } - } + auto NchTracks = 0; + for (auto& track : tracks) { + if (std::abs(track.eta()) >= etaRange) { + continue; } + NchTracks++; } + histos.fill(HIST("GlobalMult_vs_FT0A"), NchTracks, collision.multFT0A()); + histos.fill(HIST("GlobalMult_vs_FT0C"), NchTracks, collision.multFT0C()); + histos.fill(HIST("NPVtracks_vs_FT0C"), collision.multNTracksPV(), collision.multFT0C()); + histos.fill(HIST("GlobalMult_vs_FV0A"), NchTracks, collision.multFV0A()); + histos.fill(HIST("NPVtracks_vs_GlobalMult"), collision.multNTracksPV(), NchTracks); + } + PROCESS_SWITCH(HeavyIonMultiplicity, processCorrelation, "do correlation study in data", false); - auto NchGenTracksAll = 0; - for (auto& particle : GenParticles) { - if (!particle.isPhysicalPrimary()) { + void processMonteCarlo(CollisionMCTrueTable::iterator const&, CollisionMCRecTable const& RecCollisions, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + { + for (auto& RecCollision : RecCollisions) { + if (!IsEventSelected(RecCollision)) { continue; } - if (!particle.producedByGenerator()) { + histos.fill(HIST("VtxZHist"), RecCollision.posZ()); + histos.fill(HIST("CentPercentileMCRecHist"), SelectColCentrality(RecCollision)); + auto OccupancyValue = IsApplyFT0CbasedOccupancy ? RecCollision.ft0cOccupancyInTimeRange() : RecCollision.trackOccupancyInTimeRange(); + histos.fill(HIST("hmczvtxcent"), RecCollision.posZ(), SelectColCentrality(RecCollision), OccupancyValue); + + auto Rectrackspart = RecTracks.sliceBy(perCollision, RecCollision.globalIndex()); + for (auto& Rectrack : Rectrackspart) { + if (!IsTrackSelected(Rectrack)) { + continue; + } + histos.fill(HIST("MCrecPhiVsEtaHist"), Rectrack.phi(), Rectrack.eta()); + histos.fill(HIST("hmcrecdndeta"), RecCollision.posZ(), SelectColCentrality(RecCollision), OccupancyValue, Rectrack.eta(), Rectrack.phi()); + } // track (mcrec) loop + + for (auto& particle : GenParticles) { + if (!IsGenTrackSelected(particle)) { + continue; + } + histos.fill(HIST("hmcgendndeta"), RecCollision.posZ(), SelectColCentrality(RecCollision), particle.eta(), particle.phi(), kNoGenpTVar); + if (particle.pt() < 0.1) { + histos.fill(HIST("hmcgendndeta"), RecCollision.posZ(), SelectColCentrality(RecCollision), particle.eta(), particle.phi(), kGenpTup, -10.0 * particle.pt() + 2); + histos.fill(HIST("hmcgendndeta"), RecCollision.posZ(), SelectColCentrality(RecCollision), particle.eta(), particle.phi(), kGenpTdown, 5.0 * particle.pt() + 0.5); + } else { + histos.fill(HIST("hmcgendndeta"), RecCollision.posZ(), SelectColCentrality(RecCollision), particle.eta(), particle.phi(), kGenpTup); + histos.fill(HIST("hmcgendndeta"), RecCollision.posZ(), SelectColCentrality(RecCollision), particle.eta(), particle.phi(), kGenpTdown); + } + } // track (mcgen) loop + } // collision loop + } + PROCESS_SWITCH(HeavyIonMultiplicity, processMonteCarlo, "process MC CentFT0C", false); + + void processMCpTefficiency(CollisionMCTrueTable::iterator const&, CollisionMCRecTable const& RecCollisions, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + { + for (auto& RecCollision : RecCollisions) { + if (!IsEventSelected(RecCollision)) { continue; } - auto pdgParticle = pdg->GetParticle(particle.pdgCode()); - if (pdgParticle == nullptr) { + if (std::abs(RecCollision.posZ()) >= VtxRange) { continue; } - if (std::abs(pdgParticle->Charge()) >= 3) { - if (std::abs(TrueCollision.posZ()) < VtxRange) { - histos.fill(HIST("VtxZGenHist"), TrueCollision.posZ()); - if (std::abs(particle.eta()) < etaRange) { - NchGenTracksAll++; - histos.fill(HIST("MCGenEtaHistAll"), particle.eta()); - histos.fill(HIST("MCGenPhiHistAll"), particle.phi()); - histos.fill(HIST("MCGenPhiVsEtaHistAll"), particle.phi(), particle.eta()); - histos.fill(HIST("EtaVsVtxZMCGenHistAll"), particle.eta(), TrueCollision.posZ()); + histos.fill(HIST("VtxZHist"), RecCollision.posZ()); + histos.fill(HIST("CentPercentileMCRecHist"), SelectColCentrality(RecCollision)); + auto OccupancyValue = IsApplyFT0CbasedOccupancy ? RecCollision.ft0cOccupancyInTimeRange() : RecCollision.trackOccupancyInTimeRange(); + histos.fill(HIST("hmczvtxcent"), RecCollision.posZ(), SelectColCentrality(RecCollision), OccupancyValue); + + auto Rectrackspart = RecTracks.sliceBy(perCollision, RecCollision.globalIndex()); + for (auto& Rectrack : Rectrackspart) { + if (std::abs(Rectrack.eta()) >= etaRange) { + continue; + } + if (Rectrack.has_mcParticle()) { + auto mcpart = Rectrack.mcParticle(); + if (mcpart.isPhysicalPrimary()) { + histos.fill(HIST("hmcrecdndpt"), SelectColCentrality(RecCollision), mcpart.pt()); } } } - } - histos.fill(HIST("MCGenMultHistAll"), NchGenTracksAll); - } - - PROCESS_SWITCH(HeavyIonMultiplicity, processMC, "process MC", false); - void processDataCentFT0C(CollisionDataTableCentFT0C::iterator const& collision, FilTrackDataTable const& tracks) - { - float cent = -1; - auto NchTracks = 0; - constexpr auto hasCentrality = CollisionDataTableCentFT0C::template contains(); - histos.fill(HIST("EventHist"), 0); - if (collision.sel8()) { - histos.fill(HIST("EventHist"), 1); - if (collision.selection_bit(kNoITSROFrameBorder)) { - histos.fill(HIST("EventHist"), 2); - if (collision.selection_bit(kNoTimeFrameBorder)) { - histos.fill(HIST("EventHist"), 3); - if constexpr (hasCentrality) { - cent = collision.centFT0C(); - if (cent < 0.0 || cent > 100.0) { - return; - } - histos.fill(HIST("EventHist"), 4); - histos.fill(HIST("VtxZHist"), collision.posZ()); - histos.fill(HIST("CentPercentileHist"), cent); - histos.fill(HIST("hdatazvtxcent"), collision.posZ(), cent); - for (auto& track : tracks) { - if (std::abs(track.eta()) < etaRange) { - NchTracks++; - histos.fill(HIST("CentHistInsideTrackloop"), cent); - histos.fill(HIST("hdatadndeta"), collision.posZ(), cent, track.eta(), track.phi()); - } - } - histos.fill(HIST("hdatamult"), collision.posZ(), NchTracks, cent); - } + for (auto& particle : GenParticles) { + if (!IsGenTrackSelected(particle)) { + continue; + } + histos.fill(HIST("hmcgendndpt"), SelectColCentrality(RecCollision), particle.pt(), kNoGenpTVar); + if (particle.pt() < 0.1) { + histos.fill(HIST("hmcgendndpt"), SelectColCentrality(RecCollision), particle.pt(), kGenpTup, -10.0 * particle.pt() + 2); + histos.fill(HIST("hmcgendndpt"), SelectColCentrality(RecCollision), particle.pt(), kGenpTdown, 5.0 * particle.pt() + 0.5); + } else { + histos.fill(HIST("hmcgendndpt"), SelectColCentrality(RecCollision), particle.pt(), kGenpTup); + histos.fill(HIST("hmcgendndpt"), SelectColCentrality(RecCollision), particle.pt(), kGenpTdown); } } } } + PROCESS_SWITCH(HeavyIonMultiplicity, processMCpTefficiency, "process MC pTefficiency", false); - PROCESS_SWITCH(HeavyIonMultiplicity, processDataCentFT0C, "process data CentFT0C", false); - - void processMCCentFT0C(CollisionMCTrueTable::iterator const& /*TrueCollision*/, CollisionMCRecTableCentFT0C const& RecCollisions, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + void processMCcheckFakeTracks(CollisionMCTrueTable::iterator const&, CollisionMCRecTable const& RecCollisions, FilTrackMCRecTable const& RecTracks) { - if (RecCollisions.size() == 0 || RecCollisions.size() > 1) { - return; - } - - float cent = -1; - constexpr auto hasCentrality = CollisionMCRecTableCentFT0C::template contains(); - for (auto& RecCollision : RecCollisions) { - histos.fill(HIST("EventHist"), 0); - if (RecCollision.sel8()) { - histos.fill(HIST("EventHist"), 1); - if (RecCollision.selection_bit(kNoITSROFrameBorder)) { - histos.fill(HIST("EventHist"), 2); - if (RecCollision.selection_bit(kNoTimeFrameBorder)) { - histos.fill(HIST("EventHist"), 3); - if constexpr (hasCentrality) { - cent = RecCollision.centFT0C(); - if (cent < 0.0 || cent > 100.0) { - continue; - } - histos.fill(HIST("EventHist"), 4); - histos.fill(HIST("VtxZHist"), RecCollision.posZ()); - histos.fill(HIST("CentPercentileMCRecHist"), cent); - histos.fill(HIST("hmczvtxcent"), RecCollision.posZ(), cent); - - auto Rectrackspart = RecTracks.sliceBy(perCollision, RecCollision.globalIndex()); - for (auto& Rectrack : Rectrackspart) { - if (std::abs(Rectrack.eta()) > etaRange) { - continue; - } - if (Rectrack.has_mcParticle()) { - auto mcpart = Rectrack.mcParticle(); - if (std::abs(mcpart.eta()) > etaRange) { - continue; - } - if (mcpart.isPhysicalPrimary()) { - if (std::abs(mcpart.pdgCode()) == 211) { - histos.fill(HIST("hrecdndeta_pion"), RecCollision.posZ(), mcpart.eta(), mcpart.phi(), cent, mcpart.pt()); - } else if (std::abs(mcpart.pdgCode()) == 321) { - histos.fill(HIST("hrecdndeta_kaon"), RecCollision.posZ(), mcpart.eta(), mcpart.phi(), cent, mcpart.pt()); - } else if (std::abs(mcpart.pdgCode()) == 2212) { - histos.fill(HIST("hrecdndeta_proton"), RecCollision.posZ(), mcpart.eta(), mcpart.phi(), cent, mcpart.pt()); - } else { - histos.fill(HIST("hrecdndeta_other"), RecCollision.posZ(), mcpart.eta(), mcpart.phi(), cent, mcpart.pt()); - } - } else { - histos.fill(HIST("hrecdndeta_NotPrimary"), RecCollision.posZ(), mcpart.eta(), mcpart.phi(), cent, mcpart.pt()); - } - } else { - histos.fill(HIST("hrecdndeta_bkg"), RecCollision.posZ(), Rectrack.eta(), Rectrack.phi(), cent, Rectrack.pt()); - } - } - - for (auto& particle : GenParticles) { - if (!particle.isPhysicalPrimary()) { - continue; - } - if (!particle.producedByGenerator()) { - continue; - } - auto pdgParticle = pdg->GetParticle(particle.pdgCode()); - if (pdgParticle == nullptr) { - continue; - } - if (std::abs(pdgParticle->Charge()) >= 3) { - if (std::abs(particle.eta()) > etaRange) { - continue; - } - if (std::abs(particle.pdgCode()) == 211) { - histos.fill(HIST("hgendndeta_pion"), RecCollision.posZ(), particle.eta(), particle.phi(), cent, particle.pt()); - } else if (std::abs(particle.pdgCode()) == 321) { - histos.fill(HIST("hgendndeta_kaon"), RecCollision.posZ(), particle.eta(), particle.phi(), cent, particle.pt()); - } else if (std::abs(particle.pdgCode()) == 2212) { - histos.fill(HIST("hgendndeta_proton"), RecCollision.posZ(), particle.eta(), particle.phi(), cent, particle.pt()); - } else { - histos.fill(HIST("hgendndeta_other"), RecCollision.posZ(), particle.eta(), particle.phi(), cent, particle.pt()); - } - } - } - } + if (!IsEventSelected(RecCollision)) { + continue; + } + if (std::abs(RecCollision.posZ()) >= VtxRange) { + continue; + } + histos.fill(HIST("VtxZHist"), RecCollision.posZ()); + histos.fill(HIST("CentPercentileMCRecHist"), SelectColCentrality(RecCollision)); + auto OccupancyValue = IsApplyFT0CbasedOccupancy ? RecCollision.ft0cOccupancyInTimeRange() : RecCollision.trackOccupancyInTimeRange(); + histos.fill(HIST("hmczvtxcent"), RecCollision.posZ(), SelectColCentrality(RecCollision), OccupancyValue); + + auto Rectrackspart = RecTracks.sliceBy(perCollision, RecCollision.globalIndex()); + for (auto& Rectrack : Rectrackspart) { + if (std::abs(Rectrack.eta()) >= etaRange) { + continue; + } + if (!Rectrack.hasTPC()) { + continue; + } + histos.fill(HIST("hTracksCount"), SelectColCentrality(RecCollision), 1); + bool IsFakeITStracks = false; + for (int i = 0; i < 7; i++) { + if (Rectrack.mcMask() & 1 << i) { + IsFakeITStracks = true; + histos.fill(HIST("hTracksCount"), SelectColCentrality(RecCollision), i + 3); + break; } } + if (IsFakeITStracks) { + continue; + } + histos.fill(HIST("hTracksCount"), SelectColCentrality(RecCollision), 2); } } } + PROCESS_SWITCH(HeavyIonMultiplicity, processMCcheckFakeTracks, "Check Fake tracks", false); - PROCESS_SWITCH(HeavyIonMultiplicity, processMCCentFT0C, "process MC CentFT0C", false); - - void processCorrelation(CollisionDataTableCorrelation::iterator const& collision, FilTrackDataTable const& tracks) + void processMCfillspecies(CollisionMCTrueTable::iterator const&, CollisionMCRecTable const& RecCollisions, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) { - auto NchTracks = 0; - histos.fill(HIST("EventHist"), 0); - if (collision.sel8()) { - histos.fill(HIST("EventHist"), 1); - if (collision.selection_bit(kNoITSROFrameBorder)) { - histos.fill(HIST("EventHist"), 2); - if (collision.selection_bit(kNoTimeFrameBorder)) { - histos.fill(HIST("EventHist"), 3); - if (std::abs(collision.posZ()) < VtxRange) { - histos.fill(HIST("EventHist"), 4); - histos.fill(HIST("VtxZHist"), collision.posZ()); - for (auto& track : tracks) { - if (std::abs(track.eta()) < etaRange) { - NchTracks++; - } + for (auto& RecCollision : RecCollisions) { + if (!IsEventSelected(RecCollision)) { + continue; + } + if (std::abs(RecCollision.posZ()) >= VtxRange) { + continue; + } + histos.fill(HIST("VtxZHist"), RecCollision.posZ()); + histos.fill(HIST("CentPercentileMCRecHist"), SelectColCentrality(RecCollision)); + auto OccupancyValue = IsApplyFT0CbasedOccupancy ? RecCollision.ft0cOccupancyInTimeRange() : RecCollision.trackOccupancyInTimeRange(); + histos.fill(HIST("hmczvtxcent"), RecCollision.posZ(), SelectColCentrality(RecCollision), OccupancyValue); + + auto Rectrackspart = RecTracks.sliceBy(perCollision, RecCollision.globalIndex()); + std::vector mclabels; + for (auto& Rectrack : Rectrackspart) { + if (!IsTrackSelected(Rectrack)) { + continue; + } + histos.fill(HIST("FillMCrecSpecies"), SelectColCentrality(RecCollision), OccupancyValue, Rectrack.eta(), Double_t(kSpAll)); + if (Rectrack.has_mcParticle()) { + Int_t pid = kBkg; + auto mcpart = Rectrack.template mcParticle_as(); + if (mcpart.isPhysicalPrimary()) { + switch (std::abs(mcpart.pdgCode())) { + case 211: + pid = kSpPion; + break; + case 321: + pid = kSpKaon; + break; + case 2212: + pid = kSpProton; + break; + default: + pid = kSpOther; + break; + } + } else { + pid = kSpNotPrimary; + } + if (mcpart.has_mothers()) { + auto mcpartMother = mcpart.template mothers_as().front(); + if (mcpartMother.pdgCode() == 310 || std::abs(mcpartMother.pdgCode()) == 3122) { + pid = kSpStrangeDecay; } - histos.fill(HIST("GlobalMult_vs_FT0A"), collision.multFT0A(), NchTracks); - histos.fill(HIST("GlobalMult_vs_FT0C"), collision.multFT0C(), NchTracks); - histos.fill(HIST("GlobalMult_vs_FT0"), collision.multFT0A() + collision.multFT0C(), NchTracks); - histos.fill(HIST("GlobalMult_vs_FV0"), collision.multFV0A(), NchTracks); - histos.fill(HIST("GlobalMult_vs_NumPVContributor"), collision.numContrib(), NchTracks); } + if (find(mclabels.begin(), mclabels.end(), Rectrack.mcParticleId()) != mclabels.end()) { + pid = kBkg; + } + mclabels.push_back(Rectrack.mcParticleId()); + histos.fill(HIST("FillMCrecSpecies"), SelectColCentrality(RecCollision), OccupancyValue, Rectrack.eta(), Double_t(pid)); + } else { + histos.fill(HIST("FillMCrecSpecies"), SelectColCentrality(RecCollision), OccupancyValue, Rectrack.eta(), Double_t(kBkg)); + } + } // rec track loop + + for (auto& particle : GenParticles) { + if (!IsGenTrackSelected(particle)) { + continue; } + histos.fill(HIST("FillMCgenSpecies"), SelectColCentrality(RecCollision), particle.eta(), Double_t(kSpAll)); + Int_t pid = 0; + switch (std::abs(particle.pdgCode())) { + case 211: + pid = kSpPion; + break; + case 321: + pid = kSpKaon; + break; + case 2212: + pid = kSpProton; + break; + default: + pid = kSpOther; + break; + } + histos.fill(HIST("FillMCgenSpecies"), SelectColCentrality(RecCollision), particle.eta(), Double_t(pid)); + } // gen track loop + } // collision loop + } + PROCESS_SWITCH(HeavyIonMultiplicity, processMCfillspecies, "Fill particle species in MC", false); + + void processStrangeYield(CollisionDataTable::iterator const& collision, v0trackcandidates const&, aod::V0Datas const& v0data) + { + if (!IsEventSelected(collision)) { + return; + } + if (std::abs(collision.posZ()) >= VtxRange) { + return; + } + histos.fill(HIST("hzvtxcent"), collision.posZ(), SelectColCentrality(collision)); + for (auto& v0track : v0data) { + auto v0pTrack = v0track.template posTrack_as(); + auto v0nTrack = v0track.template negTrack_as(); + if (std::abs(v0pTrack.eta()) > 0.9 || std::abs(v0nTrack.eta()) > 0.9) { + continue; + } + if (v0pTrack.tpcNClsFound() < minTPCnClsCut) { + continue; + } + if (v0nTrack.tpcNClsFound() < minTPCnClsCut) { + continue; + } + if (std::abs(v0pTrack.tpcNSigmaPi()) > NSigmaTPCcut) { + continue; } + if (std::abs(v0nTrack.tpcNSigmaPi()) > NSigmaTPCcut) { + continue; + } + if (std::abs(v0pTrack.tpcNSigmaPr()) > NSigmaTPCcut) { + continue; + } + if (std::abs(v0nTrack.tpcNSigmaPr()) > NSigmaTPCcut) { + continue; + } + if (std::abs(v0track.dcapostopv()) < dcapostopvCut || std::abs(v0track.dcanegtopv()) < dcanegtopvCut || v0track.v0radius() < v0radiusCut || v0track.v0cosPA() < v0cospaCut || std::abs(v0track.dcaV0daughters()) > dcav0daughtercut) { + continue; + } + histos.fill(HIST("K0sCentEtaMass"), SelectColCentrality(collision), v0track.eta(), v0track.mK0Short()); + histos.fill(HIST("LambdaCentEtaMass"), SelectColCentrality(collision), v0track.eta(), v0track.mLambda()); + histos.fill(HIST("AntiLambdaCentEtaMass"), SelectColCentrality(collision), v0track.eta(), v0track.mAntiLambda()); } } - - PROCESS_SWITCH(HeavyIonMultiplicity, processCorrelation, "do correlation between FT0/FV0 Mult vs GlobalMult", false); + PROCESS_SWITCH(HeavyIonMultiplicity, processStrangeYield, "Strange particle yield", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGMM/UE/Tasks/CMakeLists.txt b/PWGMM/UE/Tasks/CMakeLists.txt index 9f3cce1bf4d..f9ee32c6e10 100644 --- a/PWGMM/UE/Tasks/CMakeLists.txt +++ b/PWGMM/UE/Tasks/CMakeLists.txt @@ -17,4 +17,9 @@ o2physics_add_dpl_workflow(ue-charged o2physics_add_dpl_workflow(ue-zdc-analysis SOURCES ue-zdc-analysys.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(dedx-analysis + SOURCES dedxAnalysis.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) \ No newline at end of file diff --git a/PWGMM/UE/Tasks/dedxAnalysis.cxx b/PWGMM/UE/Tasks/dedxAnalysis.cxx new file mode 100644 index 00000000000..5bf47f2021b --- /dev/null +++ b/PWGMM/UE/Tasks/dedxAnalysis.cxx @@ -0,0 +1,596 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \author Paola Vargas Torres (paola.vargas.torres@cern.ch) +/// \since January 8, 2025 +/// \file dedxAnalysis.cxx +/// \brief Analysis to do PID + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/TrackSelectionDefaults.h" + +using namespace o2; +using namespace o2::framework; +using namespace constants::physics; + +using PIDTracks = soa::Join< + aod::Tracks, aod::TracksExtra, aod::TrackSelectionExtension, aod::TracksDCA, aod::TrackSelection, + aod::pidTOFFullPi, aod::pidTOFFullPr, aod::pidTOFFullEl, aod::pidTOFbeta>; + +using SelectedCollisions = soa::Join; + +struct DedxAnalysis { + + // dE/dx for all charged particles + HistogramRegistry registryDeDx{ + "registryDeDx", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; + + // Configurable Parameters + // Tracks cuts + Configurable minTPCnClsFound{"minTPCnClsFound", 70.0f, + "min number of found TPC clusters"}; + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 70.0f, "min number of found TPC crossed rows"}; + Configurable maxChi2TPC{"maxChi2TPC", 4.0f, + "max chi2 per cluster TPC"}; + Configurable maxChi2ITS{"maxChi2ITS", 36.0f, + "max chi2 per cluster ITS"}; + Configurable etaMin{"etaMin", -0.8f, "etaMin"}; + Configurable etaMax{"etaMax", +0.8f, "etaMax"}; + Configurable minNCrossedRowsOverFindableClustersTPC{"minNCrossedRowsOverFindableClustersTPC", 0.8f, "Additional cut on the minimum value of the ratio between crossed rows and findable clusters in the TPC"}; + Configurable maxDCAz{"maxDCAz", 2.f, "maxDCAz"}; + // v0 cuts + Configurable v0cospaMin{"v0cospaMin", 0.998f, "Minimum V0 CosPA"}; + Configurable minimumV0Radius{"minimumV0Radius", 0.5f, + "Minimum V0 Radius"}; + Configurable maximumV0Radius{"maximumV0Radius", 100.0f, + "Maximum V0 Radius"}; + Configurable dcaV0DaughtersMax{"dcaV0DaughtersMax", 0.5f, + "Maximum DCA Daughters"}; + Configurable nsigmaTOFmax{"nsigmaTOFmax", 3.0f, "Maximum nsigma TOF"}; + Configurable minMassK0s{"minMassK0s", 0.4f, "Minimum Mass K0s"}; + Configurable maxMassK0s{"maxMassK0s", 0.6f, "Maximum Mass K0s"}; + Configurable minMassLambda{"minMassLambda", 1.1f, + "Minimum Mass Lambda"}; + Configurable maxMassLambda{"maxMassLambda", 1.2f, + "Maximum Mass Lambda"}; + Configurable minMassGamma{"minMassGamma", 0.000922f, + "Minimum Mass Gamma"}; + Configurable maxMassGamma{"maxMassGamma", 0.002022f, + "Maximum Mass Gamma"}; + Configurable calibrationMode{"calibrationMode", false, "calibration mode"}; + // Histograms names + static constexpr std::string_view kDedxvsMomentumPos[4] = {"dEdx_vs_Momentum_all_Pos", "dEdx_vs_Momentum_Pi_v0_Pos", "dEdx_vs_Momentum_Pr_v0_Pos", "dEdx_vs_Momentum_El_v0_Pos"}; + static constexpr std::string_view kDedxvsMomentumNeg[4] = {"dEdx_vs_Momentum_all_Neg", "dEdx_vs_Momentum_Pi_v0_Neg", "dEdx_vs_Momentum_Pr_v0_Neg", "dEdx_vs_Momentum_El_v0_Neg"}; + static constexpr double EtaCut[9] = {-0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8}; + Configurable> calibrationFactorNeg{"calibrationFactorNeg", {50.4011, 50.4764, 50.186, 49.2955, 48.8222, 49.4273, 49.9292, 50.0556}, "negative calibration factors"}; + Configurable> calibrationFactorPos{"calibrationFactorPos", {50.5157, 50.6359, 50.3198, 49.3345, 48.9197, 49.4931, 50.0188, 50.1406}, "positive calibration factors"}; + ConfigurableAxis binP{"binP", {VARIABLE_WIDTH, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 18.0, 20.0}, ""}; + + TrackSelection myTrackSelection() + { + TrackSelection selectedTracks; + selectedTracks.SetPtRange(0.1f, 1e10f); + selectedTracks.SetEtaRange(etaMin, etaMax); + selectedTracks.SetRequireITSRefit(true); + selectedTracks.SetRequireTPCRefit(true); + selectedTracks.SetMinNCrossedRowsTPC(minNCrossedRowsTPC); + selectedTracks.SetMinNCrossedRowsOverFindableClustersTPC(minNCrossedRowsOverFindableClustersTPC); + selectedTracks.SetMaxChi2PerClusterTPC(maxChi2TPC); + selectedTracks.SetRequireHitsInITSLayers(1, {0, 1}); + selectedTracks.SetMaxChi2PerClusterITS(maxChi2ITS); + selectedTracks.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f / std::pow(pt, 1.1f); }); + selectedTracks.SetMaxDcaZ(maxDCAz); + + return selectedTracks; + } + + TrackSelection mySelectionPrim; + + void init(InitContext const&) + { + AxisSpec dedxAxis{100, 0.0, 100.0, "dE/dx MIP (a. u.)"}; + AxisSpec etaAxis{8, -0.8, 0.8, "#eta"}; + AxisSpec pAxis = {binP, "#it{p}/Z (GeV/c)"}; + if (calibrationMode) { + // MIP for pions + registryDeDx.add( + "hdEdx_vs_eta_Neg_Pi", "dE/dx", HistType::kTH2F, + {{etaAxis}, {dedxAxis}}); + registryDeDx.add( + "hdEdx_vs_eta_Pos_Pi", "dE/dx", HistType::kTH2F, + {{etaAxis}, {dedxAxis}}); + // MIP for electrons + registryDeDx.add( + "hdEdx_vs_eta_vs_p_Neg_El", "dE/dx", HistType::kTH3F, + {{etaAxis}, {dedxAxis}, {pAxis}}); + registryDeDx.add( + "hdEdx_vs_eta_vs_p_Pos_El", "dE/dx", HistType::kTH3F, + {{etaAxis}, {dedxAxis}, {pAxis}}); + // Pions from TOF + registryDeDx.add( + "hdEdx_vs_eta_vs_p_Neg_TOF", "dE/dx", HistType::kTH3F, + {{etaAxis}, {dedxAxis}, {pAxis}}); + registryDeDx.add( + "hdEdx_vs_eta_vs_p_Pos_TOF", "dE/dx", HistType::kTH3F, + {{etaAxis}, {dedxAxis}, {pAxis}}); + + } else { + // MIP for pions + registryDeDx.add( + "hdEdx_vs_eta_Neg_calibrated_Pi", "dE/dx", HistType::kTH2F, + {{etaAxis}, {dedxAxis}}); + + registryDeDx.add( + "hdEdx_vs_eta_Pos_calibrated_Pi", "dE/dx", HistType::kTH2F, + {{etaAxis}, {dedxAxis}}); + + // MIP for electrons + registryDeDx.add( + "hdEdx_vs_eta_vs_p_Neg_calibrated_El", "dE/dx", HistType::kTH3F, + {{etaAxis}, {dedxAxis}, {pAxis}}); + + registryDeDx.add( + "hdEdx_vs_eta_vs_p_Pos_calibrated_El", "dE/dx", HistType::kTH3F, + {{etaAxis}, {dedxAxis}, {pAxis}}); + + // Pions from TOF + registryDeDx.add( + "hdEdx_vs_eta_vs_p_Neg_calibrated_TOF", "dE/dx", HistType::kTH3F, + {{etaAxis}, {dedxAxis}, {pAxis}}); + + registryDeDx.add( + "hdEdx_vs_eta_vs_p_Pos_calibrated_TOF", "dE/dx", HistType::kTH3F, + {{etaAxis}, {dedxAxis}, {pAxis}}); + + // De/Dx for ch and v0 particles + for (int i = 0; i < 4; ++i) { + registryDeDx.add(kDedxvsMomentumPos[i].data(), "dE/dx", HistType::kTH3F, + {{pAxis}, {dedxAxis}, {etaAxis}}); + registryDeDx.add(kDedxvsMomentumNeg[i].data(), "dE/dx", HistType::kTH3F, + {{pAxis}, {dedxAxis}, {etaAxis}}); + } + } + + registryDeDx.add( + "hdEdx_vs_phi", "dE/dx", HistType::kTH2F, + {{100, 0.0, 6.4, "#phi"}, {dedxAxis}}); + + registryDeDx.add( + "hbeta_vs_p_Neg", "beta", HistType::kTH2F, + {{pAxis}, {100, 0.0, 1.1, "#beta"}}); + + registryDeDx.add( + "hbeta_vs_p_Pos", "beta", HistType::kTH2F, + {{pAxis}, {100, 0.0, 1.1, "#beta"}}); + // Event Counter + registryDeDx.add("histRecVtxZData", "collision z position", HistType::kTH1F, {{100, -20.0, +20.0, "z_{vtx} (cm)"}}); + + mySelectionPrim = myTrackSelection(); + } + + // Single-Track Selection + template + bool passedSingleTrackSelection(const T1& track, const C& /*collision*/) + { + // Single-Track Selections + if (!track.hasTPC()) + return false; + if (track.tpcNClsFound() < minTPCnClsFound) + return false; + if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + if (track.tpcChi2NCl() > maxChi2TPC) + return false; + if (track.eta() < etaMin || track.eta() > etaMax) + return false; + + return true; + } + + // General V0 Selections + template + bool passedV0Selection(const T1& v0, const C& /*collision*/) + { + if (v0.v0cosPA() < v0cospaMin) + return false; + if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) + return false; + + return true; + } + + // K0s Selections + template + bool passedK0Selection(const T1& v0, const T2& ntrack, const T2& ptrack, + const C& collision) + { + // Single-Track Selections + if (!passedSingleTrackSelection(ptrack, collision)) + return false; + if (!passedSingleTrackSelection(ntrack, collision)) + return false; + + if (ptrack.tpcInnerParam() > 0.6) { + if (!ptrack.hasTOF()) + return false; + if (std::abs(ptrack.tofNSigmaPi()) > nsigmaTOFmax) + return false; + } + + if (ntrack.tpcInnerParam() > 0.6) { + if (!ntrack.hasTOF()) + return false; + if (std::abs(ntrack.tofNSigmaPi()) > nsigmaTOFmax) + return false; + } + + // Invariant-Mass Selection + if (v0.mK0Short() < minMassK0s || v0.mK0Short() > maxMassK0s) + return false; + + return true; + } + + // Lambda Selections + template + bool passedLambdaSelection(const T1& v0, const T2& ntrack, const T2& ptrack, + const C& collision) + { + // Single-Track Selections + if (!passedSingleTrackSelection(ptrack, collision)) + return false; + if (!passedSingleTrackSelection(ntrack, collision)) + return false; + + if (ptrack.tpcInnerParam() > 0.6) { + if (!ptrack.hasTOF()) + return false; + if (std::abs(ptrack.tofNSigmaPr()) > nsigmaTOFmax) + return false; + } + + if (ntrack.tpcInnerParam() > 0.6) { + if (!ntrack.hasTOF()) + return false; + if (std::abs(ntrack.tofNSigmaPi()) > nsigmaTOFmax) + return false; + } + + // Invariant-Mass Selection + if (v0.mLambda() < minMassLambda || v0.mLambda() > maxMassLambda) + return false; + + return true; + } + + // AntiLambda Selections + template + bool passedAntiLambdaSelection(const T1& v0, const T2& ntrack, + const T2& ptrack, const C& collision) + { + + // Single-Track Selections + if (!passedSingleTrackSelection(ptrack, collision)) + return false; + if (!passedSingleTrackSelection(ntrack, collision)) + return false; + + if (ptrack.tpcInnerParam() > 0.6) { + if (!ptrack.hasTOF()) + return false; + if (std::abs(ptrack.tofNSigmaPi()) > nsigmaTOFmax) + return false; + } + + if (ntrack.tpcInnerParam() > 0.6) { + if (!ntrack.hasTOF()) + return false; + if (std::abs(ntrack.tofNSigmaPr()) > nsigmaTOFmax) + return false; + } + + // Invariant-Mass Selection + if (v0.mAntiLambda() < minMassLambda || v0.mAntiLambda() > maxMassLambda) + return false; + + return true; + } + + // Gamma Selections + template + bool passedGammaSelection(const T1& v0, const T2& ntrack, const T2& ptrack, + const C& collision) + { + // Single-Track Selections + if (!passedSingleTrackSelection(ptrack, collision)) + return false; + if (!passedSingleTrackSelection(ntrack, collision)) + return false; + + if (ptrack.tpcInnerParam() > 0.6) { + if (!ptrack.hasTOF()) + return false; + if (std::abs(ptrack.tofNSigmaEl()) > nsigmaTOFmax) + return false; + } + + if (ntrack.tpcInnerParam() > 0.6) { + if (!ntrack.hasTOF()) + return false; + if (std::abs(ntrack.tofNSigmaEl()) > nsigmaTOFmax) + return false; + } + + // Invariant-Mass Selection + if (v0.mGamma() < minMassGamma || v0.mGamma() > maxMassGamma) + return false; + + return true; + } + + // Process Data + void process(SelectedCollisions::iterator const& collision, + aod::V0Datas const& fullV0s, PIDTracks const& tracks) + { + // Event Selection + if (!collision.sel8()) + return; + + // Event Counter + registryDeDx.fill(HIST("histRecVtxZData"), collision.posZ()); + + // Centrality + float centrality = collision.centFT0C(); + if (centrality < 0.0 || centrality > 100.0) + centrality = 1.0; + + // Kaons + for (const auto& trk : tracks) { + + // track Selection + if (!passedSingleTrackSelection(trk, collision)) + continue; + + if (!mySelectionPrim.IsSelected(trk)) + continue; + + float signedP = trk.sign() * trk.tpcInnerParam(); + + // MIP calibration for pions + if (trk.tpcInnerParam() >= 0.35 && trk.tpcInnerParam() <= 0.45) { + if (calibrationMode) { + if (signedP < 0) { + registryDeDx.fill(HIST("hdEdx_vs_eta_Neg_Pi"), trk.eta(), trk.tpcSignal()); + } else { + registryDeDx.fill(HIST("hdEdx_vs_eta_Pos_Pi"), trk.eta(), trk.tpcSignal()); + } + + } else { + for (int i = 0; i < 8; ++i) { + if (trk.eta() > EtaCut[i] && trk.eta() < EtaCut[i + 1]) { + if (signedP < 0) { + registryDeDx.fill(HIST("hdEdx_vs_eta_Neg_calibrated_Pi"), trk.eta(), trk.tpcSignal() * 50 / calibrationFactorNeg->at(i)); + } else { + registryDeDx.fill(HIST("hdEdx_vs_eta_Pos_calibrated_Pi"), trk.eta(), trk.tpcSignal() * 50 / calibrationFactorPos->at(i)); + } + } + } + } + } + // Beta from TOF + if (signedP < 0) { + registryDeDx.fill(HIST("hbeta_vs_p_Neg"), std::abs(signedP), trk.beta()); + } else { + registryDeDx.fill(HIST("hbeta_vs_p_Pos"), signedP, trk.beta()); + } + // Electrons from TOF + if (std::abs(trk.beta() - 1) < 0.1) { // beta cut + if (calibrationMode) { + if (signedP < 0) { + registryDeDx.fill(HIST("hdEdx_vs_eta_vs_p_Neg_El"), trk.eta(), trk.tpcSignal(), std::abs(signedP)); + } else { + registryDeDx.fill(HIST("hdEdx_vs_eta_vs_p_Pos_El"), trk.eta(), trk.tpcSignal(), signedP); + } + } else { + for (int i = 0; i < 8; ++i) { + if (trk.eta() > EtaCut[i] && trk.eta() < EtaCut[i + 1]) { + if (signedP < 0) { + registryDeDx.fill(HIST("hdEdx_vs_eta_vs_p_Neg_calibrated_El"), trk.eta(), trk.tpcSignal() * 50 / calibrationFactorNeg->at(i), std::abs(signedP)); + } else { + registryDeDx.fill(HIST("hdEdx_vs_eta_vs_p_Pos_calibrated_El"), trk.eta(), trk.tpcSignal() * 50 / calibrationFactorPos->at(i), signedP); + } + } + } + } + } + // pions from TOF + if (trk.beta() > 1. && trk.beta() < 1.05) { // beta cut + if (calibrationMode) { + if (signedP < 0) { + registryDeDx.fill(HIST("hdEdx_vs_eta_vs_p_Neg_TOF"), trk.eta(), trk.tpcSignal(), std::abs(signedP)); + } else { + registryDeDx.fill(HIST("hdEdx_vs_eta_vs_p_Pos_TOF"), trk.eta(), trk.tpcSignal(), signedP); + } + } else { + for (int i = 0; i < 8; ++i) { + if (trk.eta() > EtaCut[i] && trk.eta() < EtaCut[i + 1]) { + if (signedP < 0) { + registryDeDx.fill(HIST("hdEdx_vs_eta_vs_p_Neg_calibrated_TOF"), trk.eta(), trk.tpcSignal() * 50 / calibrationFactorNeg->at(i), std::abs(signedP)); + } else { + registryDeDx.fill(HIST("hdEdx_vs_eta_vs_p_Pos_calibrated_TOF"), trk.eta(), trk.tpcSignal() * 50 / calibrationFactorPos->at(i), signedP); + } + } + } + } + } + + registryDeDx.fill(HIST("hdEdx_vs_phi"), trk.phi(), trk.tpcSignal()); + + if (!calibrationMode) { + for (int i = 0; i < 8; ++i) { + if (trk.eta() > EtaCut[i] && trk.eta() < EtaCut[i + 1]) { + if (signedP > 0) { + registryDeDx.fill(HIST(kDedxvsMomentumPos[0]), signedP, trk.tpcSignal() * 50 / calibrationFactorPos->at(i), trk.eta()); + } else { + registryDeDx.fill(HIST(kDedxvsMomentumNeg[0]), std::abs(signedP), trk.tpcSignal() * 50 / calibrationFactorNeg->at(i), trk.eta()); + } + } + } + } + } + + // Loop over Reconstructed V0s + if (!calibrationMode) { + for (const auto& v0 : fullV0s) { + + // Standard V0 Selections + if (!passedV0Selection(v0, collision)) { + continue; + } + + if (v0.dcaV0daughters() > dcaV0DaughtersMax) { + continue; + } + + // Positive and Negative Tracks + const auto& posTrack = v0.posTrack_as(); + const auto& negTrack = v0.negTrack_as(); + + if (!posTrack.passedTPCRefit()) + continue; + if (!negTrack.passedTPCRefit()) + continue; + + float signedPpos = posTrack.sign() * posTrack.tpcInnerParam(); + float signedPneg = negTrack.sign() * negTrack.tpcInnerParam(); + + float pxPos = posTrack.px(); + float pyPos = posTrack.py(); + float pzPos = posTrack.pz(); + + float pxNeg = negTrack.px(); + float pyNeg = negTrack.py(); + float pzNeg = negTrack.pz(); + + const float gammaMass = 2 * MassElectron; // GeV/c^2 + + // K0s Selection + if (passedK0Selection(v0, negTrack, posTrack, collision)) { + float ePosPi = posTrack.energy(MassPionCharged); + float eNegPi = negTrack.energy(MassPionCharged); + + float invMass = std::sqrt((eNegPi + ePosPi) * (eNegPi + ePosPi) - ((pxNeg + pxPos) * (pxNeg + pxPos) + (pyNeg + pyPos) * (pyNeg + pyPos) + (pzNeg + pzPos) * (pzNeg + pzPos))); + + if (std::abs(invMass - MassK0Short) > 0.01) { + continue; + } + + for (int i = 0; i < 8; ++i) { + if (negTrack.eta() > EtaCut[i] && negTrack.eta() < EtaCut[i + 1]) { + registryDeDx.fill(HIST(kDedxvsMomentumNeg[1]), std::abs(signedPneg), negTrack.tpcSignal() * 50 / calibrationFactorNeg->at(i), negTrack.eta()); + } + if (posTrack.eta() > EtaCut[i] && posTrack.eta() < EtaCut[i + 1]) { + registryDeDx.fill(HIST(kDedxvsMomentumPos[1]), signedPpos, posTrack.tpcSignal() * 50 / calibrationFactorPos->at(i), posTrack.eta()); + } + } + } + + // Lambda Selection + if (passedLambdaSelection(v0, negTrack, posTrack, collision)) { + + float ePosPr = posTrack.energy(MassProton); + float eNegPi = negTrack.energy(MassPionCharged); + + float invMass = std::sqrt((eNegPi + ePosPr) * (eNegPi + ePosPr) - ((pxNeg + pxPos) * (pxNeg + pxPos) + (pyNeg + pyPos) * (pyNeg + pyPos) + (pzNeg + pzPos) * (pzNeg + pzPos))); + + if (std::abs(invMass - MassLambda) > 0.01) { + continue; + } + + for (int i = 0; i < 8; ++i) { + if (negTrack.eta() > EtaCut[i] && negTrack.eta() < EtaCut[i + 1]) { + registryDeDx.fill(HIST(kDedxvsMomentumNeg[1]), std::abs(signedPneg), negTrack.tpcSignal() * 50 / calibrationFactorNeg->at(i), negTrack.eta()); + } + if (posTrack.eta() > EtaCut[i] && posTrack.eta() < EtaCut[i + 1]) { + registryDeDx.fill(HIST(kDedxvsMomentumPos[2]), signedPpos, posTrack.tpcSignal() * 50 / calibrationFactorPos->at(i), posTrack.eta()); + } + } + } + + // AntiLambda Selection + if (passedAntiLambdaSelection(v0, negTrack, posTrack, collision)) { + + float ePosPi = posTrack.energy(MassPionCharged); + float eNegPr = negTrack.energy(MassProton); + + float invMass = std::sqrt((eNegPr + ePosPi) * (eNegPr + ePosPi) - ((pxNeg + pxPos) * (pxNeg + pxPos) + (pyNeg + pyPos) * (pyNeg + pyPos) + (pzNeg + pzPos) * (pzNeg + pzPos))); + + if (std::abs(invMass - MassLambda) > 0.01) { + continue; + } + + for (int i = 0; i < 8; ++i) { + if (negTrack.eta() > EtaCut[i] && negTrack.eta() < EtaCut[i + 1]) { + registryDeDx.fill(HIST(kDedxvsMomentumNeg[2]), std::abs(signedPneg), negTrack.tpcSignal() * 50 / calibrationFactorNeg->at(i), negTrack.eta()); + } + if (posTrack.eta() > EtaCut[i] && posTrack.eta() < EtaCut[i + 1]) { + registryDeDx.fill(HIST(kDedxvsMomentumPos[1]), signedPpos, posTrack.tpcSignal() * 50 / calibrationFactorPos->at(i), posTrack.eta()); + } + } + } + + // Gamma Selection + if (passedGammaSelection(v0, negTrack, posTrack, collision)) { + + float ePosEl = posTrack.energy(MassElectron); + float eNegEl = negTrack.energy(MassElectron); + + float invMass = std::sqrt((eNegEl + ePosEl) * (eNegEl + ePosEl) - ((pxNeg + pxPos) * (pxNeg + pxPos) + (pyNeg + pyPos) * (pyNeg + pyPos) + (pzNeg + pzPos) * (pzNeg + pzPos))); + + if (std::abs(invMass - gammaMass) > 0.0015) { + continue; + } + + for (int i = 0; i < 8; ++i) { + if (negTrack.eta() > EtaCut[i] && negTrack.eta() < EtaCut[i + 1]) { + registryDeDx.fill(HIST(kDedxvsMomentumNeg[3]), std::abs(signedPneg), negTrack.tpcSignal() * 50 / calibrationFactorNeg->at(i), negTrack.eta()); + } + if (posTrack.eta() > EtaCut[i] && posTrack.eta() < EtaCut[i + 1]) { + registryDeDx.fill(HIST(kDedxvsMomentumPos[3]), signedPpos, posTrack.tpcSignal() * 50 / calibrationFactorPos->at(i), posTrack.eta()); + } + } + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGMM/UE/Tasks/dedx_analysys.cxx b/PWGMM/UE/Tasks/dedx_analysys.cxx new file mode 100644 index 00000000000..13c8b32b20e --- /dev/null +++ b/PWGMM/UE/Tasks/dedx_analysys.cxx @@ -0,0 +1,566 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \author Paola Vargas +/// \since January 8, 2025 + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "ReconstructionDataFormats/Track.h" + +using namespace o2; +using namespace o2::framework; + +using PIDTracks = soa::Join< + aod::Tracks, aod::TracksExtra, aod::TracksDCA, aod::pidTOFbeta, + aod::pidTOFmass, aod::TrackSelection, aod::TrackSelectionExtension, + aod::pidTPCFullPi, aod::pidTPCFullKa, aod::pidTPCFullPr, aod::pidTPCFullDe, + aod::pidTPCFullTr, aod::pidTPCFullHe, aod::pidTOFFullPi, aod::pidTOFFullKa, + aod::pidTOFFullPr, aod::pidTOFFullDe, aod::pidTOFFullTr, aod::pidTOFFullHe, aod::pidTOFFullEl>; + +using SelectedCollisions = soa::Join; + +struct dedx_analysys { + + // dE/dx for all charged particles + HistogramRegistry registryDeDx{ + "registryDeDx", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; + + // Corrections + // constexpr double Correc[8]{54.3344, 55.1277, 56.0811, 56.7974, 56.9533, 56.4622, 55.8873, 55.1449}; + // constexpr double Correc[9]{-0.8, -0.6, -0.4, -0.2, 0., 0.2, 0.4, 0.6, 0.8}; + + // Configurable Parameters + Configurable minTPCnClsFound{"minTPCnClsFound", 70.0f, + "min number of found TPC clusters"}; + Configurable minNCrossedRowsTPC{ + "minNCrossedRowsTPC", 70.0f, "min number of found TPC crossed rows"}; + Configurable minNClsTPCdEdx{ + "minNClsTPCdEdx", 50.0f, "min number of TPC clusters for PID"}; + Configurable maxChi2TPC{"maxChi2TPC", 4.0f, + "max chi2 per cluster TPC"}; + Configurable maxChi2ITS{"maxChi2ITS", 36.0f, + "max chi2 per cluster ITS"}; + Configurable etaMin{"etaMin", -0.8f, "etaMin"}; + Configurable etaMax{"etaMax", +0.8f, "etaMax"}; + Configurable v0cospaMin{"v0cospaMin", 0.998f, "Minimum V0 CosPA"}; + Configurable minimumV0Radius{"minimumV0Radius", 0.5f, + "Minimum V0 Radius"}; + Configurable maximumV0Radius{"maximumV0Radius", 100.0f, + "Maximum V0 Radius"}; + Configurable dcaV0DaughtersMax{"dcaV0DaughtersMax", 0.5f, + "Maximum DCA Daughters"}; + Configurable nsigmaTOFmax{"nsigmaTOFmax", 3.0f, "Maximum nsigma TOF"}; + Configurable minMassK0s{"minMassK0s", 0.4f, "Minimum Mass K0s"}; + Configurable maxMassK0s{"maxMassK0s", 0.6f, "Maximum Mass K0s"}; + Configurable minMassLambda{"minMassLambda", 1.1f, + "Minimum Mass Lambda"}; + Configurable maxMassLambda{"maxMassLambda", 1.2f, + "Maximum Mass Lambda"}; + Configurable minMassGamma{"minMassGamma", 0.000922f, + "Minimum Mass Gamma"}; + Configurable maxMassGamma{"maxMassGamma", 0.002022f, + "Maximum Mass Gamma"}; + Configurable minReqClusterITS{ + "minReqClusterITS", 4.0f, "min number of clusters required in ITS"}; + Configurable maxDCAxy{"maxDCAxy", 0.1f, "maxDCAxy"}; + Configurable maxDCAz{"maxDCAz", 0.1f, "maxDCAz"}; + Configurable eventSelection{"eventSelection", true, "event selection"}; + // Histograms names + static constexpr std::string_view Armenteros[5] = {"Armenteros", "Armenteros_K0S", "Armenteros_Lambda", "Armenteros_AntiLambda", "Armenteros_Gamma"}; + static constexpr std::string_view Qt_vs_alpha[5] = {"Qt_vs_alpha", "Qt_vs_alpha_K0S", "Qt_vs_alpha_Lambda", "Qt_vs_alpha_AntiLambda", "Qt_vs_alpha_Gamma"}; + static constexpr std::string_view dEdx_vs_Momentum[5] = {"dEdx_vs_Momentum_all", "dEdx_vs_Momentum_02", "dEdx_vs_Momentum_0204", "dEdx_vs_Momentum_0406", "dEdx_vs_Momentum_0608"}; + static constexpr std::string_view dEdx_vs_Momentum_neg[4] = {"dEdx_vs_Momentum_02neg", "dEdx_vs_Momentum_0204neg", "dEdx_vs_Momentum_0406neg", "dEdx_vs_Momentum_0608neg"}; + static constexpr std::string_view dEdx_vs_Momentum_pos[4] = {"dEdx_vs_Momentum_02pos", "dEdx_vs_Momentum_0204pos", "dEdx_vs_Momentum_0406pos", "dEdx_vs_Momentum_0608pos"}; + static constexpr std::string_view dEdx_vs_Momentum_v0[3] = {"dEdx_vs_Momentum_Pi_v0", "dEdx_vs_Momentum_Pr_v0", "dEdx_vs_Momentum_El_v0"}; + static constexpr std::string_view hInvMass[4] = {"InvMass_K0S", "InvMass_Lambda", "InvMass_AntiLambda", "InvMass_Gamma"}; + static constexpr double EtaCut[9] = {-0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8}; + static constexpr double Correction[8] = {54.3344, 55.1277, 56.0811, 56.7974, 56.9533, 56.4622, 55.8873, 55.1449}; + + void init(InitContext const&) + { + + // MIP for pions + registryDeDx.add( + "dEdxMIP_vs_eta", "dE/dx", HistType::kTH2F, + {{100, -0.8, 0.8, "#eta"}, {100, 0.0, 600.0, "dE/dx MIP (a. u.)"}}); + + registryDeDx.add( + "dEdxMIP_vs_phi", "dE/dx", HistType::kTH2F, + {{100, 0.0, 6.4, "#phi"}, {100, 0.0, 600.0, "dE/dx MIP (a. u.)"}}); + + registryDeDx.add( + "dEdxMIP_vs_eta_AfterCorr", "dE/dx", HistType::kTH2F, + {{100, -0.8, 0.8, "#eta"}, {100, 0.0, 600.0, "dE/dx MIP (a. u.)"}}); + + //////////////////////////////// + registryDeDx.add(hInvMass[0].data(), "mass", HistType::kTH1F, + {{100, 400, 600, "m (MeV/c)"}}); + registryDeDx.add(hInvMass[1].data(), "mass", HistType::kTH1F, + {{100, 1.08, 1.25, "m (GeV/c)"}}); + registryDeDx.add(hInvMass[2].data(), "mass", HistType::kTH1F, + {{100, 1.08, 1.25, "m (GeV/c)"}}); + registryDeDx.add(hInvMass[3].data(), "mass", HistType::kTH1F, + {{100, 0, 2, "m (MeV/c)"}}); + // Armenteros plot and De/Dx for eta cut inclusive + for (int i = 0; i < 5; ++i) { + registryDeDx.add(Armenteros[i].data(), Qt_vs_alpha[i].data(), HistType::kTH2F, + {{100, -1., 1., "#alpha (a. u.)"}, {100, 0.0, 0.3, "q_T (GeV/c)"}}); + registryDeDx.add(dEdx_vs_Momentum[i].data(), "dE/dx", HistType::kTH2F, + {{100, -20.0, 20.0, "#it{p}/Z (GeV/c)"}, {100, 0.0, 600.0, "dE/dx (a. u.)"}}); + } + // De/Dx for eta cut negative and positive + for (int i = 0; i < 4; ++i) { + + registryDeDx.add(dEdx_vs_Momentum_neg[i].data(), "dE/dx", HistType::kTH2F, + {{100, -20.0, 20.0, "#it{p}/Z (GeV/c)"}, {100, 0.0, 600.0, "dE/dx (a. u.)"}}); + + registryDeDx.add(dEdx_vs_Momentum_pos[i].data(), "dE/dx", HistType::kTH2F, + {{100, -20.0, 20.0, "#it{p}/Z (GeV/c)"}, {100, 0.0, 600.0, "dE/dx (a. u.)"}}); + } + + // De/Dx for v0 particles + for (int i = 0; i < 3; ++i) { + + registryDeDx.add(dEdx_vs_Momentum_v0[i].data(), "dE/dx", HistType::kTH2F, + {{100, -20.0, 20.0, "#it{p}/Z (GeV/c)"}, {100, 0.0, 600.0, "dE/dx (a. u.)"}}); + } + + // Event Counter + registryDeDx.add("histRecVtxZData", "collision z position", HistType::kTH1F, {{100, -20.0, +20.0, "z_{vtx} (cm)"}}); + } + + // Single-Track Selection + template + bool passedSingleTrackSelection(const T1& track, const C& /*collision*/) + { + // Single-Track Selections + if (!track.hasTPC()) + return false; + if (track.tpcNClsFound() < minTPCnClsFound) + return false; + if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + if (track.tpcChi2NCl() > maxChi2TPC) + return false; + if (track.eta() < etaMin || track.eta() > etaMax) + return false; + + return true; + } + + // General V0 Selections + template + bool passedV0Selection(const T1& v0, const C& /*collision*/) + { + if (v0.v0cosPA() < v0cospaMin) + return false; + if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) + return false; + + return true; + } + + // K0s Selections + template + bool passedK0Selection(const T1& v0, const T2& ntrack, const T2& ptrack, + const C& collision) + { + // Single-Track Selections + if (!passedSingleTrackSelection(ptrack, collision)) + return false; + if (!passedSingleTrackSelection(ntrack, collision)) + return false; + + if (ptrack.tpcInnerParam() > 0.6) { + if (!ptrack.hasTOF()) + return false; + if (TMath::Abs(ptrack.tofNSigmaPi()) > nsigmaTOFmax) + return false; + } + + if (ntrack.tpcInnerParam() > 0.6) { + if (!ntrack.hasTOF()) + return false; + if (TMath::Abs(ntrack.tofNSigmaPi()) > nsigmaTOFmax) + return false; + } + + // Invariant-Mass Selection + if (v0.mK0Short() < minMassK0s || v0.mK0Short() > maxMassK0s) + return false; + + return true; + } + + // Lambda Selections + template + bool passedLambdaSelection(const T1& v0, const T2& ntrack, const T2& ptrack, + const C& collision) + { + // Single-Track Selections + if (!passedSingleTrackSelection(ptrack, collision)) + return false; + if (!passedSingleTrackSelection(ntrack, collision)) + return false; + + if (ptrack.tpcInnerParam() > 0.6) { + if (!ptrack.hasTOF()) + return false; + if (TMath::Abs(ptrack.tofNSigmaPr()) > nsigmaTOFmax) + return false; + } + + if (ntrack.tpcInnerParam() > 0.6) { + if (!ntrack.hasTOF()) + return false; + if (TMath::Abs(ntrack.tofNSigmaPi()) > nsigmaTOFmax) + return false; + } + + // Invariant-Mass Selection + if (v0.mLambda() < minMassLambda || v0.mLambda() > maxMassLambda) + return false; + + return true; + } + + // AntiLambda Selections + template + bool passedAntiLambdaSelection(const T1& v0, const T2& ntrack, + const T2& ptrack, const C& collision) + { + + // Single-Track Selections + if (!passedSingleTrackSelection(ptrack, collision)) + return false; + if (!passedSingleTrackSelection(ntrack, collision)) + return false; + + if (ptrack.tpcInnerParam() > 0.6) { + if (!ptrack.hasTOF()) + return false; + if (TMath::Abs(ptrack.tofNSigmaPi()) > nsigmaTOFmax) + return false; + } + + if (ntrack.tpcInnerParam() > 0.6) { + if (!ntrack.hasTOF()) + return false; + if (TMath::Abs(ntrack.tofNSigmaPr()) > nsigmaTOFmax) + return false; + } + + // Invariant-Mass Selection + if (v0.mAntiLambda() < minMassLambda || v0.mAntiLambda() > maxMassLambda) + return false; + + return true; + } + + // Gamma Selections + template + bool passedGammaSelection(const T1& v0, const T2& ntrack, const T2& ptrack, + const C& collision) + { + // Single-Track Selections + if (!passedSingleTrackSelection(ptrack, collision)) + return false; + if (!passedSingleTrackSelection(ntrack, collision)) + return false; + + if (ptrack.tpcInnerParam() > 0.6) { + if (!ptrack.hasTOF()) + return false; + if (TMath::Abs(ptrack.tofNSigmaEl()) > nsigmaTOFmax) + return false; + } + + if (ntrack.tpcInnerParam() > 0.6) { + if (!ntrack.hasTOF()) + return false; + if (TMath::Abs(ntrack.tofNSigmaEl()) > nsigmaTOFmax) + return false; + } + + // Invariant-Mass Selection + if (v0.mGamma() < minMassGamma || v0.mGamma() > maxMassGamma) + return false; + + return true; + } + + // Process Data + void process(SelectedCollisions::iterator const& collision, + aod::V0Datas const& fullV0s, PIDTracks const& tracks) + { + // Event Selection + if (!collision.sel8()) + return; + + // Event Counter + registryDeDx.fill(HIST("histRecVtxZData"), collision.posZ()); + + // Centrality + float centrality = collision.centFT0C(); + if (centrality < 0.0 || centrality > 100.0) + centrality = 1.0; + + // Kaons + for (auto& trk : tracks) { + + if (!passedSingleTrackSelection(trk, collision)) + continue; + if (!trk.passedTPCRefit()) + continue; + float signedP = trk.sign() * trk.tpcInnerParam(); + + // DeDx all particles + registryDeDx.fill(HIST(dEdx_vs_Momentum[0]), signedP, trk.tpcSignal()); + + //////////////////////////////// + + // MIP for pions + + // TODO: 0.25 TO 0.35 + // range 0.2 to 0.6 + // float pion_m = 0.139; //GeV + if (trk.tpcInnerParam() >= 0.25 && trk.tpcInnerParam() <= 0.35) { + registryDeDx.fill(HIST("dEdxMIP_vs_eta"), trk.eta(), trk.tpcSignal()); + registryDeDx.fill(HIST("dEdxMIP_vs_phi"), trk.phi(), trk.tpcSignal()); + // After calibration + + for (int i = 0; i < 8; ++i) { + if (trk.eta() > EtaCut[i] && trk.eta() < EtaCut[i + 1]) { + registryDeDx.fill(HIST("dEdxMIP_vs_eta_AfterCorr"), trk.eta(), trk.tpcSignal() * 50 / Correction[i]); + } + } + } + + // After calibration + for (int i = 0; i < 8; ++i) { + if (trk.eta() > EtaCut[i] && trk.eta() < EtaCut[i + 1]) { + if (i == 0) { + registryDeDx.fill(HIST(dEdx_vs_Momentum_neg[0]), signedP, trk.tpcSignal() * 50 / Correction[i]); + registryDeDx.fill(HIST(dEdx_vs_Momentum[4]), signedP, trk.tpcSignal() * 50 / Correction[i]); + } else if (i == 1) { + registryDeDx.fill(HIST(dEdx_vs_Momentum_neg[1]), signedP, trk.tpcSignal() * 50 / Correction[i]); + registryDeDx.fill(HIST(dEdx_vs_Momentum[3]), signedP, trk.tpcSignal() * 50 / Correction[i]); + } else if (i == 2) { + registryDeDx.fill(HIST(dEdx_vs_Momentum_neg[2]), signedP, trk.tpcSignal() * 50 / Correction[i]); + registryDeDx.fill(HIST(dEdx_vs_Momentum[2]), signedP, trk.tpcSignal() * 50 / Correction[i]); + } else if (i == 3) { + registryDeDx.fill(HIST(dEdx_vs_Momentum_neg[3]), signedP, trk.tpcSignal() * 50 / Correction[i]); + registryDeDx.fill(HIST(dEdx_vs_Momentum[1]), signedP, trk.tpcSignal() * 50 / Correction[i]); + } else if (i == 4) { + registryDeDx.fill(HIST(dEdx_vs_Momentum_pos[0]), signedP, trk.tpcSignal() * 50 / Correction[i]); + registryDeDx.fill(HIST(dEdx_vs_Momentum[1]), signedP, trk.tpcSignal() * 50 / Correction[i]); + } else if (i == 5) { + registryDeDx.fill(HIST(dEdx_vs_Momentum_pos[1]), signedP, trk.tpcSignal() * 50 / Correction[i]); + registryDeDx.fill(HIST(dEdx_vs_Momentum[2]), signedP, trk.tpcSignal() * 50 / Correction[i]); + } else if (i == 6) { + registryDeDx.fill(HIST(dEdx_vs_Momentum_pos[2]), signedP, trk.tpcSignal() * 50 / Correction[i]); + registryDeDx.fill(HIST(dEdx_vs_Momentum[3]), signedP, trk.tpcSignal() * 50 / Correction[i]); + } else if (i == 7) { + registryDeDx.fill(HIST(dEdx_vs_Momentum_pos[3]), signedP, trk.tpcSignal() * 50 / Correction[i]); + registryDeDx.fill(HIST(dEdx_vs_Momentum[4]), signedP, trk.tpcSignal() * 50 / Correction[i]); + } + } + } + } + + // Loop over Reconstructed V0s + for (auto& v0 : fullV0s) { + + // Standard V0 Selections + if (!passedV0Selection(v0, collision)) { + continue; + } + + if (v0.dcaV0daughters() > dcaV0DaughtersMax) { + continue; + } + + // Positive and Negative Tracks + const auto& posTrack = v0.posTrack_as(); + const auto& negTrack = v0.negTrack_as(); + + if (!posTrack.passedTPCRefit()) + continue; + if (!negTrack.passedTPCRefit()) + continue; + + float signedPpos = posTrack.sign() * posTrack.tpcInnerParam(); + float signedPneg = negTrack.sign() * negTrack.tpcInnerParam(); + + float px_v0 = v0.px(); + float py_v0 = v0.py(); + float pz_v0 = v0.pz(); + float p_v0 = sqrt(px_v0 * px_v0 + py_v0 * py_v0 + pz_v0 * pz_v0); + + float px_pos = posTrack.px(); + float py_pos = posTrack.py(); + float pz_pos = posTrack.pz(); + + float px_neg = negTrack.px(); + float py_neg = negTrack.py(); + float pz_neg = negTrack.pz(); + + const float protonMass = 0.938; // GeV/c^2 + const float piMass = 0.13957; // GeV/c^2 + const float K0SMass = 493.677; // MeV/c^2 + const float LambdaMass = 1.115; // GeV/c^2 + const float GammaMass = 1.022; // MeV/c^2 + const float eMass = 0.511; // MeV/c^2 + + // float E_pos_man = std::sqrt(px_pos * px_pos + py_pos * py_pos + pz_pos * pz_pos + piMass * piMass); + + //-------------------Armenteros plots-------- + + float pl_pos = (px_pos * px_v0 + py_pos * py_v0 + pz_pos * pz_v0) / p_v0; + float pl_neg = (px_neg * px_v0 + py_neg * py_v0 + pz_neg * pz_v0) / p_v0; + + float alpha = (pl_pos - pl_neg) / (pl_pos + pl_neg); + float p_pos = sqrt(px_pos * px_pos + py_pos * py_pos + pz_pos * pz_pos); + float qt = sqrt(p_pos * p_pos - pl_pos * pl_pos); + + registryDeDx.fill(HIST(Armenteros[0]), alpha, qt); + + //------------------------------------------- + + // K0s Selection + if (passedK0Selection(v0, negTrack, posTrack, collision)) { + float E_pos_pi = posTrack.energy(piMass); + float E_neg_pi = negTrack.energy(piMass); + + float InvMass = sqrt((E_neg_pi + E_pos_pi) * (E_neg_pi + E_pos_pi) - ((px_neg + px_pos) * (px_neg + px_pos) + (py_neg + py_pos) * (py_neg + py_pos) + (pz_neg + pz_pos) * (pz_neg + pz_pos))); + + if (TMath::Abs(InvMass * 1000 - K0SMass) > 10) { + continue; + } + + registryDeDx.fill(HIST(hInvMass[0]), InvMass * 1000); + registryDeDx.fill(HIST(Armenteros[1]), alpha, qt); + + for (int i = 0; i < 8; ++i) { + if (negTrack.eta() > EtaCut[i] && negTrack.eta() < EtaCut[i + 1]) { + + registryDeDx.fill(HIST(dEdx_vs_Momentum_v0[0]), signedPneg, negTrack.tpcSignal() * 50 / Correction[i]); + } + if (posTrack.eta() > EtaCut[i] && posTrack.eta() < EtaCut[i + 1]) { + + registryDeDx.fill(HIST(dEdx_vs_Momentum_v0[0]), signedPpos, posTrack.tpcSignal() * 50 / Correction[i]); + } + } + } + + // Lambda Selection + if (passedLambdaSelection(v0, negTrack, posTrack, collision)) { + float E_pos_p = posTrack.energy(protonMass); + float E_neg_pi = negTrack.energy(piMass); + + float InvMass = sqrt((E_neg_pi + E_pos_p) * (E_neg_pi + E_pos_p) - ((px_neg + px_pos) * (px_neg + px_pos) + (py_neg + py_pos) * (py_neg + py_pos) + (pz_neg + pz_pos) * (pz_neg + pz_pos))); + + if (TMath::Abs(InvMass - LambdaMass) > 0.01) { + continue; + } + + registryDeDx.fill(HIST(hInvMass[1]), InvMass); + registryDeDx.fill(HIST(Armenteros[2]), alpha, qt); + + for (int i = 0; i < 8; ++i) { + if (negTrack.eta() > EtaCut[i] && negTrack.eta() < EtaCut[i + 1]) { + + registryDeDx.fill(HIST(dEdx_vs_Momentum_v0[0]), signedPneg, negTrack.tpcSignal() * 50 / Correction[i]); + } + if (posTrack.eta() > EtaCut[i] && posTrack.eta() < EtaCut[i + 1]) { + + registryDeDx.fill(HIST(dEdx_vs_Momentum_v0[1]), signedPpos, posTrack.tpcSignal() * 50 / Correction[i]); + } + } + } + + // AntiLambda Selection + if (passedAntiLambdaSelection(v0, negTrack, posTrack, collision)) { + + float E_pos_pi = posTrack.energy(piMass); + float E_neg_p = negTrack.energy(protonMass); + + float InvMass = sqrt((E_neg_p + E_pos_pi) * (E_neg_p + E_pos_pi) - ((px_neg + px_pos) * (px_neg + px_pos) + (py_neg + py_pos) * (py_neg + py_pos) + (pz_neg + pz_pos) * (pz_neg + pz_pos))); + + if (TMath::Abs(InvMass - LambdaMass) > 0.01) { + continue; + } + + registryDeDx.fill(HIST(hInvMass[2]), InvMass); + registryDeDx.fill(HIST(Armenteros[3]), alpha, qt); + + for (int i = 0; i < 8; ++i) { + if (negTrack.eta() > EtaCut[i] && negTrack.eta() < EtaCut[i + 1]) { + + registryDeDx.fill(HIST(dEdx_vs_Momentum_v0[1]), signedPneg, negTrack.tpcSignal() * 50 / Correction[i]); + } + if (posTrack.eta() > EtaCut[i] && posTrack.eta() < EtaCut[i + 1]) { + + registryDeDx.fill(HIST(dEdx_vs_Momentum_v0[0]), signedPpos, posTrack.tpcSignal() * 50 / Correction[i]); + } + } + } + + // Gamma Selection + if (passedGammaSelection(v0, negTrack, posTrack, collision)) { + + float E_pos_e = posTrack.energy(eMass); + float E_neg_e = negTrack.energy(eMass); + + float InvMass = sqrt((E_neg_e + E_pos_e) * (E_neg_e + E_pos_e) - ((px_neg + px_pos) * (px_neg + px_pos) + (py_neg + py_pos) * (py_neg + py_pos) + (pz_neg + pz_pos) * (pz_neg + pz_pos))); + + if (TMath::Abs(InvMass - GammaMass) > 10) { + continue; + } + + registryDeDx.fill(HIST(hInvMass[3]), InvMass); + registryDeDx.fill(HIST(Armenteros[4]), alpha, qt); + + for (int i = 0; i < 8; ++i) { + if (negTrack.eta() > EtaCut[i] && negTrack.eta() < EtaCut[i + 1]) { + + registryDeDx.fill(HIST(dEdx_vs_Momentum_v0[2]), signedPneg, negTrack.tpcSignal() * 50 / Correction[i]); + } + if (posTrack.eta() > EtaCut[i] && posTrack.eta() < EtaCut[i + 1]) { + + registryDeDx.fill(HIST(dEdx_vs_Momentum_v0[2]), signedPpos, posTrack.tpcSignal() * 50 / Correction[i]); + } + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGMM/UE/Tasks/ue-zdc-analysys.cxx b/PWGMM/UE/Tasks/ue-zdc-analysys.cxx index c5b6566e44e..ec5294f7248 100644 --- a/PWGMM/UE/Tasks/ue-zdc-analysys.cxx +++ b/PWGMM/UE/Tasks/ue-zdc-analysys.cxx @@ -122,6 +122,9 @@ struct ZDCAnalysis { registry.add("ZPAvstdccoll", "ZPAvstdccoll", {HistType::kTH2F, {{{nBinsTDC, -13.5, 11.45}, {nBinsAmp, -0.5, MaxZP}}}}); registry.add("ZEM1vstdccoll", "ZEM1vstdccoll", {HistType::kTH2F, {{{nBinsTDC, -13.5, 11.45}, {nBinsAmp, -0.5, MaxZEM}}}}); registry.add("ZEM2vstdccoll", "ZEM2vstdccoll", {HistType::kTH2F, {{{nBinsTDC, -13.5, 11.45}, {nBinsAmp, -0.5, MaxZEM}}}}); + registry.add("debunch", "ZN sum vs. ZN diff.", {HistType::kTH2F, {{{240, -12., 12.}, {240, -12., 12.}}}}); + registry.add("centroidZNA", "ZNA centroid", {HistType::kTH2F, {{{350, -1.75, 1.75}, {350, -1.75, 1.75}}}}); + registry.add("centroidZNC", "ZNC centroid", {HistType::kTH2F, {{{350, -1.75, 1.75}, {350, -1.75, 1.75}}}}); } if (doprocessZdcCorrela) { // Check if the process function for ZDCCollCorrela is enabled registry.add("ZNvsFV0Acorrel", "ZNvsFV0Acorrel", {HistType::kTH2F, {{{nBinsFit, 0., MaxMultFV0}, {nBinsAmp, -0.5, 2. * MaxZN}}}}); @@ -132,17 +135,24 @@ struct ZDCAnalysis { void processZdcAuto(aod::Zdc const& zdc) { - registry.get(HIST("ZNApmc"))->Fill(zdc.amplitudeZNA()); - registry.get(HIST("ZNCpmc"))->Fill(zdc.amplitudeZNC()); - registry.get(HIST("ZPApmc"))->Fill(zdc.amplitudeZPA()); - registry.get(HIST("ZPCpmc"))->Fill(zdc.amplitudeZPC()); - registry.get(HIST("ZEM1"))->Fill(zdc.amplitudeZEM1()); - registry.get(HIST("ZEM2"))->Fill(zdc.amplitudeZEM2()); - registry.get(HIST("ZNvsZEM"))->Fill(zdc.amplitudeZEM1() + zdc.amplitudeZEM2(), zdc.amplitudeZNA() + zdc.amplitudeZNC()); - registry.get(HIST("ZNAvsZNC"))->Fill(zdc.amplitudeZNC(), zdc.amplitudeZNA()); - registry.get(HIST("ZPAvsZPC"))->Fill(zdc.amplitudeZPC(), zdc.amplitudeZPA()); - registry.get(HIST("ZNAvsZPA"))->Fill(zdc.amplitudeZPA(), zdc.amplitudeZNA()); - registry.get(HIST("ZNCvsZPC"))->Fill(zdc.amplitudeZPC(), zdc.amplitudeZNC()); + auto aZNA = zdc.amplitudeZNA(); + auto aZNC = zdc.amplitudeZNC(); + auto aZPA = zdc.amplitudeZPA(); + auto aZPC = zdc.amplitudeZPC(); + auto aZEM1 = zdc.amplitudeZEM1(); + auto aZEM2 = zdc.amplitudeZEM2(); + // + registry.get(HIST("ZNApmc"))->Fill(aZNA); + registry.get(HIST("ZNCpmc"))->Fill(aZNC); + registry.get(HIST("ZPApmc"))->Fill(aZPA); + registry.get(HIST("ZPCpmc"))->Fill(aZPC); + registry.get(HIST("ZEM1"))->Fill(aZEM1); + registry.get(HIST("ZEM2"))->Fill(aZEM2); + registry.get(HIST("ZNvsZEM"))->Fill(aZEM1 + aZEM2, aZNA + aZNC); + registry.get(HIST("ZNAvsZNC"))->Fill(aZNC, aZNA); + registry.get(HIST("ZPAvsZPC"))->Fill(aZPC, aZPA); + registry.get(HIST("ZNAvsZPA"))->Fill(aZPA, aZNA); + registry.get(HIST("ZNCvsZPC"))->Fill(aZPC, aZNC); // float sumZNC = (zdc.energySectorZNC())[0] + (zdc.energySectorZNC())[1] + (zdc.energySectorZNC())[2] + (zdc.energySectorZNC())[3]; float sumZNA = (zdc.energySectorZNA())[0] + (zdc.energySectorZNA())[1] + (zdc.energySectorZNA())[2] + (zdc.energySectorZNA())[3]; @@ -153,12 +163,12 @@ struct ZDCAnalysis { registry.get(HIST("ZPCcvsZPCsum"))->Fill(sumZPC, zdc.energyCommonZPC()); registry.get(HIST("ZPAcvsZPAsum"))->Fill(sumZPA, zdc.energyCommonZPA()); // - registry.get(HIST("ZNCvstdc"))->Fill(zdc.timeZNC(), zdc.amplitudeZNC()); - registry.get(HIST("ZNAvstdc"))->Fill(zdc.timeZNA(), zdc.amplitudeZNA()); - registry.get(HIST("ZPCvstdc"))->Fill(zdc.timeZPC(), zdc.amplitudeZPC()); - registry.get(HIST("ZPAvstdc"))->Fill(zdc.timeZPA(), zdc.amplitudeZPA()); - registry.get(HIST("ZEM1vstdc"))->Fill(zdc.timeZEM1(), zdc.amplitudeZEM1()); - registry.get(HIST("ZEM2vstdc"))->Fill(zdc.timeZEM2(), zdc.amplitudeZEM2()); + registry.get(HIST("ZNCvstdc"))->Fill(zdc.timeZNC(), aZNC); + registry.get(HIST("ZNAvstdc"))->Fill(zdc.timeZNA(), aZNA); + registry.get(HIST("ZPCvstdc"))->Fill(zdc.timeZPC(), aZPC); + registry.get(HIST("ZPAvstdc"))->Fill(zdc.timeZPA(), aZPA); + registry.get(HIST("ZEM1vstdc"))->Fill(zdc.timeZEM1(), aZEM1); + registry.get(HIST("ZEM2vstdc"))->Fill(zdc.timeZEM2(), aZEM2); } /// name, description, function pointer, default value /// note that it has to be declared after the function, so that the pointer is known @@ -171,17 +181,24 @@ struct ZDCAnalysis { for (const auto& bc : bcs) { if (bc.has_zdc()) { - registry.get(HIST("ZNAbc"))->Fill(bc.zdc().amplitudeZNA()); - registry.get(HIST("ZNCbc"))->Fill(bc.zdc().amplitudeZNC()); - registry.get(HIST("ZPAbc"))->Fill(bc.zdc().amplitudeZPA()); - registry.get(HIST("ZPCbc"))->Fill(bc.zdc().amplitudeZPC()); - registry.get(HIST("ZEM1bc"))->Fill(bc.zdc().amplitudeZEM1()); - registry.get(HIST("ZEM2bc"))->Fill(bc.zdc().amplitudeZEM2()); - registry.get(HIST("ZNvsZEMbc"))->Fill(bc.zdc().amplitudeZEM1() + bc.zdc().amplitudeZEM2(), bc.zdc().amplitudeZNA() + bc.zdc().amplitudeZNC()); - registry.get(HIST("ZNAvsZNCbc"))->Fill(bc.zdc().amplitudeZNC(), bc.zdc().amplitudeZNA()); - registry.get(HIST("ZPAvsZPCbc"))->Fill(bc.zdc().amplitudeZPC(), bc.zdc().amplitudeZPA()); - registry.get(HIST("ZNAvsZPAbc"))->Fill(bc.zdc().amplitudeZPA(), bc.zdc().amplitudeZNA()); - registry.get(HIST("ZNCvsZPCbc"))->Fill(bc.zdc().amplitudeZPC(), bc.zdc().amplitudeZNC()); + auto aZNA = bc.zdc().amplitudeZNA(); + auto aZNC = bc.zdc().amplitudeZNC(); + auto aZPA = bc.zdc().amplitudeZPA(); + auto aZPC = bc.zdc().amplitudeZPC(); + auto aZEM1 = bc.zdc().amplitudeZEM1(); + auto aZEM2 = bc.zdc().amplitudeZEM2(); + + registry.get(HIST("ZNAbc"))->Fill(aZNA); + registry.get(HIST("ZNCbc"))->Fill(aZNC); + registry.get(HIST("ZPAbc"))->Fill(aZPA); + registry.get(HIST("ZPCbc"))->Fill(aZPC); + registry.get(HIST("ZEM1bc"))->Fill(aZEM1); + registry.get(HIST("ZEM2bc"))->Fill(aZEM2); + registry.get(HIST("ZNvsZEMbc"))->Fill(aZEM1 + aZEM2, aZNA + aZNC); + registry.get(HIST("ZNAvsZNCbc"))->Fill(aZNC, aZNA); + registry.get(HIST("ZPAvsZPCbc"))->Fill(aZPC, aZPA); + registry.get(HIST("ZNAvsZPAbc"))->Fill(aZPA, aZNA); + registry.get(HIST("ZNCvsZPCbc"))->Fill(aZPC, aZNC); } } } @@ -197,46 +214,106 @@ struct ZDCAnalysis { const auto& foundBC = collision.foundBC_as(); if (foundBC.has_zdc()) { const auto& zdcread = foundBC.zdc(); + // + auto aZNA = zdcread.amplitudeZNA(); + auto aZNC = zdcread.amplitudeZNC(); + auto aZPA = zdcread.amplitudeZPA(); + auto aZPC = zdcread.amplitudeZPC(); + auto aZEM1 = zdcread.amplitudeZEM1(); + auto aZEM2 = zdcread.amplitudeZEM2(); + auto tZNA = zdcread.timeZNA(); + auto tZNC = zdcread.timeZNC(); + auto tZPA = zdcread.timeZPA(); + auto tZPC = zdcread.timeZPC(); + // if (TDCcut) { - if ((zdcread.timeZNA() >= tdcZNmincut) && (zdcread.timeZNA() <= tdcZNmaxcut)) - registry.get(HIST("ZNAcoll"))->Fill(zdcread.amplitudeZNA()); - if ((zdcread.timeZNC() >= tdcZNmincut) && (zdcread.timeZNC() <= tdcZNmaxcut)) - registry.get(HIST("ZNCcoll"))->Fill(zdcread.amplitudeZNC()); - if ((zdcread.timeZPA() >= tdcZPmincut) && (zdcread.timeZPA() <= tdcZPmaxcut)) - registry.get(HIST("ZPAcoll"))->Fill(zdcread.amplitudeZPA()); - if ((zdcread.timeZPC() >= tdcZPmincut) && (zdcread.timeZPC() <= tdcZPmaxcut)) - registry.get(HIST("ZPCcoll"))->Fill(zdcread.amplitudeZPC()); - if (((zdcread.timeZNC() >= tdcZNmincut) && (zdcread.timeZNC() <= tdcZNmaxcut)) && ((zdcread.timeZNA() >= tdcZNmincut) && (zdcread.timeZNA() <= tdcZNmaxcut))) - registry.get(HIST("ZNvsZEMcoll"))->Fill(zdcread.amplitudeZEM1() + zdcread.amplitudeZEM2(), zdcread.amplitudeZNA() + zdcread.amplitudeZNC()); - if (((zdcread.timeZNC() >= tdcZNmincut) && (zdcread.timeZNC() <= tdcZNmaxcut)) && ((zdcread.timeZNA() >= tdcZNmincut) && (zdcread.timeZNA() <= tdcZNmaxcut))) - registry.get(HIST("ZNAvsZNCcoll"))->Fill(zdcread.amplitudeZNC(), zdcread.amplitudeZNA()); - if (((zdcread.timeZPC() >= tdcZPmincut) && (zdcread.timeZPC() <= tdcZPmaxcut)) && ((zdcread.timeZPA() >= tdcZPmincut) && (zdcread.timeZPA() <= tdcZPmaxcut))) - registry.get(HIST("ZPAvsZPCcoll"))->Fill(zdcread.amplitudeZPC(), zdcread.amplitudeZPA()); - if ((zdcread.timeZNA() >= tdcZNmincut) && (zdcread.timeZNA() <= tdcZNmaxcut)) - registry.get(HIST("ZNAvsZPAcoll"))->Fill(zdcread.amplitudeZPA(), zdcread.amplitudeZNA()); - if ((zdcread.timeZNC() >= tdcZNmincut) && (zdcread.timeZNC() <= tdcZNmaxcut)) - registry.get(HIST("ZNCvsZPCcoll"))->Fill(zdcread.amplitudeZPC(), zdcread.amplitudeZNC()); + if ((tZNA >= tdcZNmincut) && (tZNA <= tdcZNmaxcut)) + registry.get(HIST("ZNAcoll"))->Fill(aZNA); + if ((tZNC >= tdcZNmincut) && (tZNC <= tdcZNmaxcut)) + registry.get(HIST("ZNCcoll"))->Fill(aZNC); + if ((tZPA >= tdcZPmincut) && (tZPA <= tdcZPmaxcut)) + registry.get(HIST("ZPAcoll"))->Fill(aZPA); + if ((tZPC >= tdcZPmincut) && (tZPC <= tdcZPmaxcut)) + registry.get(HIST("ZPCcoll"))->Fill(aZPC); + if (((tZNC >= tdcZNmincut) && (tZNC <= tdcZNmaxcut)) && ((tZNA >= tdcZNmincut) && (tZNA <= tdcZNmaxcut))) + registry.get(HIST("ZNvsZEMcoll"))->Fill(aZEM1 + aZEM2, aZNA + aZNC); + if (((tZNC >= tdcZNmincut) && (tZNC <= tdcZNmaxcut)) && ((tZNA >= tdcZNmincut) && (tZNA <= tdcZNmaxcut))) + registry.get(HIST("ZNAvsZNCcoll"))->Fill(aZNC, aZNA); + if (((tZPC >= tdcZPmincut) && (tZPC <= tdcZPmaxcut)) && ((tZPA >= tdcZPmincut) && (tZPA <= tdcZPmaxcut))) + registry.get(HIST("ZPAvsZPCcoll"))->Fill(aZPC, aZPA); + if ((tZNA >= tdcZNmincut) && (tZNA <= tdcZNmaxcut)) + registry.get(HIST("ZNAvsZPAcoll"))->Fill(aZPA, aZNA); + if ((tZNC >= tdcZNmincut) && (tZNC <= tdcZNmaxcut)) + registry.get(HIST("ZNCvsZPCcoll"))->Fill(aZPC, aZNC); // } else { - registry.get(HIST("ZNAcoll"))->Fill(zdcread.amplitudeZNA()); - registry.get(HIST("ZNCcoll"))->Fill(zdcread.amplitudeZNC()); - registry.get(HIST("ZPAcoll"))->Fill(zdcread.amplitudeZPA()); - registry.get(HIST("ZPCcoll"))->Fill(zdcread.amplitudeZPC()); - registry.get(HIST("ZNvsZEMcoll"))->Fill(zdcread.amplitudeZEM1() + zdcread.amplitudeZEM2(), zdcread.amplitudeZNA() + zdcread.amplitudeZNC()); - registry.get(HIST("ZNAvsZNCcoll"))->Fill(zdcread.amplitudeZNC(), zdcread.amplitudeZNA()); - registry.get(HIST("ZPAvsZPCcoll"))->Fill(zdcread.amplitudeZPC(), zdcread.amplitudeZPA()); - registry.get(HIST("ZNAvsZPAcoll"))->Fill(zdcread.amplitudeZPA(), zdcread.amplitudeZNA()); - registry.get(HIST("ZNCvsZPCcoll"))->Fill(zdcread.amplitudeZPC(), zdcread.amplitudeZNC()); + registry.get(HIST("ZNAcoll"))->Fill(aZNA); + registry.get(HIST("ZNCcoll"))->Fill(aZNC); + registry.get(HIST("ZPAcoll"))->Fill(aZPA); + registry.get(HIST("ZPCcoll"))->Fill(aZPC); + registry.get(HIST("ZNvsZEMcoll"))->Fill(aZEM1 + aZEM2, aZNA + aZNC); + registry.get(HIST("ZNAvsZNCcoll"))->Fill(aZNC, aZNA); + registry.get(HIST("ZPAvsZPCcoll"))->Fill(aZPC, aZPA); + registry.get(HIST("ZNAvsZPAcoll"))->Fill(aZPA, aZNA); + registry.get(HIST("ZNCvsZPCcoll"))->Fill(aZPC, aZNC); + } + registry.get(HIST("ZEM1coll"))->Fill(aZEM1); + registry.get(HIST("ZEM2coll"))->Fill(aZEM2); + // + registry.get(HIST("ZNCvstdccoll"))->Fill(tZNC, aZNC); + registry.get(HIST("ZNAvstdccoll"))->Fill(tZNA, aZNA); + registry.get(HIST("ZPCvstdccoll"))->Fill(tZPC, aZPC); + registry.get(HIST("ZPAvstdccoll"))->Fill(tZPA, aZPA); + registry.get(HIST("ZEM1vstdccoll"))->Fill(zdcread.timeZEM1(), aZEM1); + registry.get(HIST("ZEM2vstdccoll"))->Fill(zdcread.timeZEM2(), aZEM2); + // + registry.get(HIST("debunch"))->Fill(tZNA - tZNC, tZNA + tZNC); + // + // Calculating centroid over ZNA and ZNC + // const float beamEne = 5.36/2.; + const float x[4] = {-1.75, 1.75, -1.75, 1.75}; + const float y[4] = {-1.75, -1.75, 1.75, 1.75}; + const float alpha = 0.395; + double numXZNC = 0., numYZNC = 0., denZNC = 0.; + double numXZNA = 0., numYZNA = 0., denZNA = 0.; + double centrZNC[2] = {0., 0}, centrZNA[2] = {0., 0.}; + // + auto zncTower = zdcread.energySectorZNC(); + auto znaTower = zdcread.energySectorZNA(); + auto zncC = zdcread.energyCommonZNC(); + auto znaC = zdcread.energyCommonZNA(); + // + for (int i = 0; i < 4; i++) { + if (zncTower[i] > 0.) { + float wZNC = std::pow(zncTower[i], alpha); + numXZNC += x[i] * wZNC; + numYZNC += y[i] * wZNC; + denZNC += wZNC; + } + if (znaTower[i] > 0.) { + float wZNA = std::pow(znaTower[i], alpha); + numXZNA += x[i] * wZNA; + numYZNA += y[i] * wZNA; + denZNA += wZNA; + } + } + // + if (denZNC != 0) { + centrZNC[0] = numXZNC / denZNC; + centrZNC[1] = numYZNC / denZNC; + } else { + centrZNC[0] = centrZNC[1] = 999.; + } + // + if (denZNA != 0) { + centrZNA[0] = -numXZNA / denZNA; + centrZNA[1] = numYZNA / denZNA; + } else { + centrZNA[0] = centrZNA[1] = 999.; } - registry.get(HIST("ZEM1coll"))->Fill(zdcread.amplitudeZEM1()); - registry.get(HIST("ZEM2coll"))->Fill(zdcread.amplitudeZEM2()); // - registry.get(HIST("ZNCvstdccoll"))->Fill(zdcread.timeZNC(), zdcread.amplitudeZNC()); - registry.get(HIST("ZNAvstdccoll"))->Fill(zdcread.timeZNA(), zdcread.amplitudeZNA()); - registry.get(HIST("ZPCvstdccoll"))->Fill(zdcread.timeZPC(), zdcread.amplitudeZPC()); - registry.get(HIST("ZPAvstdccoll"))->Fill(zdcread.timeZPA(), zdcread.amplitudeZPA()); - registry.get(HIST("ZEM1vstdccoll"))->Fill(zdcread.timeZEM1(), zdcread.amplitudeZEM1()); - registry.get(HIST("ZEM2vstdccoll"))->Fill(zdcread.timeZEM2(), zdcread.amplitudeZEM2()); + registry.get(HIST("centroidZNA"))->Fill(centrZNA[0], centrZNA[1], znaC); + registry.get(HIST("centroidZNC"))->Fill(centrZNC[0], centrZNC[1], zncC); } } } @@ -253,8 +330,8 @@ struct ZDCAnalysis { const auto& foundBC = coll.foundBC_as(); // FT0 - float multT0A = 0; - float multT0C = 0; + float multT0A = 0.; + float multT0C = 0.; if (foundBC.has_ft0()) { for (auto amplitude : foundBC.ft0().amplitudeA()) { multT0A += amplitude; @@ -278,10 +355,11 @@ struct ZDCAnalysis { float multFDA = 0; float multFDC = 0; if (foundBC.has_fdd()) { - for (auto amplitude : foundBC.fdd().chargeA()) { + auto const& fdd = foundBC.fdd(); + for (auto const& amplitude : fdd.chargeA()) { multFDA += amplitude; } - for (auto amplitude : foundBC.fdd().chargeC()) { + for (auto const& amplitude : fdd.chargeC()) { multFDC += amplitude; } } else { @@ -290,9 +368,11 @@ struct ZDCAnalysis { if (foundBC.has_zdc()) { const auto& zdcread = foundBC.zdc(); - registry.get(HIST("ZNvsFV0Acorrel"))->Fill(multV0A / 100., zdcread.amplitudeZNA() + zdcread.amplitudeZNC()); - registry.get(HIST("ZNvsFT0correl"))->Fill((multT0A + multT0C) / 100., zdcread.amplitudeZNC() + zdcread.amplitudeZNA()); - registry.get(HIST("ZNvsFDDcorrel"))->Fill(multFDC + multFDA, zdcread.amplitudeZNC() + zdcread.amplitudeZNA()); + auto aZNA = zdcread.amplitudeZNA(); + auto aZNC = zdcread.amplitudeZNC(); + registry.get(HIST("ZNvsFV0Acorrel"))->Fill(multV0A / 100., aZNA + aZNC); + registry.get(HIST("ZNvsFT0correl"))->Fill((multT0A + multT0C) / 100., aZNC + aZNA); + registry.get(HIST("ZNvsFDDcorrel"))->Fill(multFDC + multFDA, aZNC + aZNA); } } PROCESS_SWITCH(ZDCAnalysis, processZdcCorrela, "Processing ZDC vs. mult. w. collision association", true); diff --git a/PWGMM/UE/Tasks/uecharged.cxx b/PWGMM/UE/Tasks/uecharged.cxx index 0e2b7a00166..9cfaeb96022 100644 --- a/PWGMM/UE/Tasks/uecharged.cxx +++ b/PWGMM/UE/Tasks/uecharged.cxx @@ -8,9 +8,9 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \author Antonio Ortiz (antonio.ortiz.velasquez@cern.ch) +/// \author Antonio Ortiz (antonio.ortiz@nucleares.unam.mx) /// \since November 2021 -/// \last update: October 2022 +/// \last update: July 2024 #include #include @@ -28,6 +28,7 @@ #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/TrackSelectionTables.h" #include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" #include "TDatabasePDG.h" #include @@ -35,7 +36,7 @@ #include #include -// TODO: implement 50% stat for MC closure vs 50% for testing +// TODO: implement 50% stat for MC closure vs 50% for testing, add flag for weak decays using namespace o2; using namespace o2::framework; @@ -43,14 +44,57 @@ using namespace o2::framework::expressions; struct ueCharged { - TrackSelection myTrackSelection(); + TrackSelection myTrackSelectionPrim() + { + TrackSelection selectedTracks; + selectedTracks.SetPtRange(0.1f, 1e10f); + selectedTracks.SetEtaRange(-0.8f, 0.8f); + selectedTracks.SetRequireITSRefit(true); + selectedTracks.SetRequireTPCRefit(true); + // selectedTracks.SetRequireGoldenChi2(true); + selectedTracks.SetMinNCrossedRowsTPC(70); + selectedTracks.SetMinNCrossedRowsOverFindableClustersTPC(0.8f); + selectedTracks.SetMaxChi2PerClusterTPC(4.f); + selectedTracks.SetRequireHitsInITSLayers(1, {0, 1}); // one hit in any SPD layer + selectedTracks.SetMaxChi2PerClusterITS(36.f); + selectedTracks.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f / pow(pt, 1.1f); }); + selectedTracks.SetMaxDcaZ(2.f); + return selectedTracks; + } + TrackSelection myTrackSelectionOpenDCA() + { + TrackSelection selectedTracks; + selectedTracks.SetPtRange(0.1f, 1e10f); + selectedTracks.SetEtaRange(-0.8f, 0.8f); + selectedTracks.SetRequireITSRefit(true); + selectedTracks.SetRequireTPCRefit(true); + // selectedTracks.SetRequireGoldenChi2(true); + selectedTracks.SetMinNCrossedRowsTPC(70); + selectedTracks.SetMinNCrossedRowsOverFindableClustersTPC(0.8f); + selectedTracks.SetMaxChi2PerClusterTPC(4.f); + selectedTracks.SetRequireHitsInITSLayers(1, {0, 1}); // one hit in any SPD layer + selectedTracks.SetMaxChi2PerClusterITS(36.f); + // selectedTracks.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f / pow(pt, 1.1f); }); + selectedTracks.SetMaxDcaZ(2.f); + return selectedTracks; + } + + TrackSelection mySelectionPrim; + TrackSelection mySelectionOpenDCA; Service pdg; float DeltaPhi(float phia, float phib, float rangeMin, float rangeMax); + // Configurable for event selection Configurable isRun3{"isRun3", true, "is Run3 dataset"}; + Configurable piluprejection{"piluprejection", true, "Pileup rejection"}; + Configurable goodzvertex{"goodzvertex", true, "removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference."}; + Configurable sel8{"sel8", true, "Apply the sel8 event selection"}; + Configurable removeITSROFBorder{"removeITSROFBorder", false, "Remove ITS Read-Out Frame border and only apply kIsTriggerTVX & kNoTimeFrameBorder (recommended for MC)"}; + Configurable manuallyApplysel8{"manuallyApplysel8", false, "Apply manually the event selection criteria considered in sel8, ie. kIsTriggerTVX & kNoTimeFrameBorder & kNoITSROFrameBorder"}; + // acceptance cuts Configurable cfgTrkEtaCut{"cfgTrkEtaCut", 0.8f, "Eta range for tracks"}; - Configurable cfgTrkLowPtCut{"cfgTrkLowPtCut", 0.5f, "Minimum constituent pT"}; + Configurable cfgTrkLowPtCut{"cfgTrkLowPtCut", 0.15f, "Minimum constituent pT"}; HistogramRegistry ue; static constexpr std::string_view pNumDenMeasuredPS[3] = {"pNumDenMeasuredPS_NS", "pNumDenMeasuredPS_AS", "pNumDenMeasuredPS_TS"}; @@ -81,6 +125,7 @@ struct ueCharged { OutputObj f_Eff{"fpara"}; void init(InitContext const&); + template void processMeasMC(const C& collision, const T& tracks, const P& particles); @@ -88,7 +133,7 @@ struct ueCharged { void processMeas(const C& collision, const T& tracks); template - void processTrue(const C& collision, const P& particles); + void processTrue(const C& mcCollision, const P& particles); Filter trackFilter = (nabs(aod::track::eta) < cfgTrkEtaCut) && (aod::track::pt > cfgTrkLowPtCut); @@ -147,16 +192,16 @@ float ueCharged::DeltaPhi(float phia, float phib, void ueCharged::init(InitContext const&) { + mySelectionPrim = myTrackSelectionPrim(); + mySelectionOpenDCA = myTrackSelectionOpenDCA(); + ConfigurableAxis ptBinningt{"ptBinningt", {0, 0.15, 0.50, 1.00, 1.50, 2.00, 2.50, 3.00, 3.50, 4.00, 4.50, 5.00, 6.00, 7.00, 8.00, 9.00, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0, 25.0, 30.0, 40.0, 50.0}, "pTtrig bin limits"}; AxisSpec ptAxist = {ptBinningt, "#it{p}_{T}^{trig} (GeV/#it{c})"}; - ConfigurableAxis ptBinning{"ptBinning", {0, 0.0, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0, 25.0, 30.0, 40.0, 50.0}, "pTassoc bin limits"}; + ConfigurableAxis ptBinning{"ptBinning", {0, 0.0, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0, 25.0, 30.0, 40.0, 50.0}, "pTassoc bin limits"}; AxisSpec ptAxis = {ptBinning, "#it{p}_{T}^{assoc} (GeV/#it{c})"}; - f_Eff.setObject(new TF1("fpara", - "(x<0.9)*((-6.67648e-02)+x*(1.78170e+00)+x*x*(-1.12962e+00))+" - "(x>=0.9&&x<4.5)*((5.48165e-01)+(1.35818e-01)*x+(-4.87156e-02)*x*x+(5.97039e-03)*x*x*x)+(x>=4.5)*(6.90314e-01)", - 0.15, 50.0)); + f_Eff.setObject(new TF1("fpara", "(x<0.3)*((0.283781)+x*(3.0492)+x*x*(-6.17018)) + (x>=0.3&&x<1.8)*((0.597121)+(0.200737)*x+(-0.11255)*x*x+(0.0242807)*x*x*x) + (x>=1.8&&x<14.)*((0.729892)+(0.0018516)*x+(0.000257896)*x*x+(-2.05202e-05)*x*x*x) + (x>=14)*(0.749313)", 0., 1e5)); if (doprocessMC) { ue.add("hPtOut", "pT all rec; pT; Nch", HistType::kTH1D, {ptAxis}); @@ -194,7 +239,7 @@ void ueCharged::init(InitContext const&) ue.add("phiEta", ";#eta;#varphi", HistType::kTH2F, {{50, -2.5, 2.5}, {200, 0., 2 * M_PI, " "}}); ue.add("hvtxZ", "vtxZ", HistType::kTH1F, {{40, -20.0, 20.0, " "}}); - ue.add("hCounter", "Counter; sel; Nev", HistType::kTH1D, {{3, 0, 3, " "}}); + ue.add("hCounter", "Counter; sel; Nev", HistType::kTH1D, {{7, 0, 7, " "}}); ue.add("hPtLeadingRecPS", "rec pTleading after physics selection", HistType::kTH1D, {ptAxist}); ue.add("hPtLeadingMeasured", "measured pTleading after physics selection", HistType::kTH1D, {ptAxist}); @@ -233,7 +278,6 @@ void ueCharged::processMC(CollisionTableMCTrue::iterator const& mcCollision, Col } } processTrue(mcCollision, particles); - // processTrue(collisions, particles); } void ueCharged::processDataMC(CollisionTableMCData::iterator const& collision, TrackTableMCData const& tracks, ParticleTableMC const& particles, aod::McCollisions const& /*mcCollisions*/) @@ -246,7 +290,7 @@ void ueCharged::processData(CollisionTableData::iterator const& collision, Track } template -void ueCharged::processTrue(const C& collision, const P& particles) +void ueCharged::processTrue(const C& mcCollision, const P& particles) { int multTrue = 0; int multTrueINEL = 0; @@ -271,11 +315,12 @@ void ueCharged::processTrue(const C& collision, const P& particles) ue.fill(HIST("hPtInPrimGen"), particle.pt()); } ue.fill(HIST("hmultTrueGen"), multTrue); - ue.fill(HIST("hvtxZmc"), collision.posZ()); - if (std::abs(collision.posZ()) > 10.f && multTrueINEL <= 0) { + if (std::abs(mcCollision.posZ()) > 10.f && multTrueINEL <= 0) { return; } + ue.fill(HIST("hvtxZmc"), mcCollision.posZ()); + double flPtTrue = 0; // leading pT double flPhiTrue = 0; int flIndexTrue = 0; @@ -372,15 +417,6 @@ void ueCharged::processTrue(const C& collision, const P& particles) ue.fill(HIST(pNumDenTrueAll[2]), flPtTrue, ue_true[2]); ue.fill(HIST(pSumPtTrueAll[2]), flPtTrue, ue_true[5]); - ue.fill(HIST(pNumDenTrue[0]), flPtTrue, ue_true[0]); - ue.fill(HIST(pSumPtTrue[0]), flPtTrue, ue_true[3]); - - ue.fill(HIST(pNumDenTrue[1]), flPtTrue, ue_true[1]); - ue.fill(HIST(pSumPtTrue[1]), flPtTrue, ue_true[4]); - - ue.fill(HIST(pNumDenTrue[2]), flPtTrue, ue_true[2]); - ue.fill(HIST(pSumPtTrue[2]), flPtTrue, ue_true[5]); - ptArrayTrue.clear(); phiArrayTrue.clear(); indexArrayTrue.clear(); @@ -391,37 +427,39 @@ void ueCharged::processMeas(const C& collision, const T& tracks) ue.fill(HIST("hCounter"), 0); - bool isAcceptedEvent = false; - if (isRun3 ? collision.sel8() : collision.sel7()) { - if ((isRun3 || doprocessMC) ? true : collision.alias_bit(kINT7)) { - isAcceptedEvent = true; - } + if (sel8 && !collision.sel8()) { + return; } - // only PS - if (!isAcceptedEvent) { + + if (removeITSROFBorder && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder))) { + return; + } + + if (manuallyApplysel8 && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { return; } ue.fill(HIST("hCounter"), 1); - ue.fill(HIST("hStat"), collision.size()); - auto vtxZ = collision.posZ(); + if (piluprejection && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return; + } - isAcceptedEvent = false; - if (std::abs(collision.posZ()) < 10.f) { - if (isRun3 ? collision.sel8() : collision.sel7()) { - if ((isRun3 || doprocessMC) ? true : collision.alias_bit(kINT7)) { - isAcceptedEvent = true; - } - } + ue.fill(HIST("hCounter"), 2); + if (goodzvertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; } + ue.fill(HIST("hCounter"), 3); + + ue.fill(HIST("hStat"), collision.size()); + auto vtxZ = collision.posZ(); // + vtx - if (!isAcceptedEvent) { + if ((std::abs(collision.posZ()) >= 10.f)) { return; } - ue.fill(HIST("hCounter"), 2); + ue.fill(HIST("hCounter"), 4); ue.fill(HIST("hvtxZ"), vtxZ); @@ -432,7 +470,7 @@ void ueCharged::processMeas(const C& collision, const T& tracks) int flIndex = 0; int multRec = 0; for (auto& track : tracks) { - if (!track.isGlobalTrack()) { + if (!mySelectionPrim.IsSelected(track)) { continue; } @@ -467,11 +505,11 @@ void ueCharged::processMeas(const C& collision, const T& tracks) for (auto& track : tracks) { - if (myTrackSelection().IsSelected(track)) { // TODO: set cuts w/o DCA cut + if (mySelectionOpenDCA.IsSelected(track)) { ue.fill(HIST("hPTVsDCAData"), track.pt(), track.dcaXY()); } - if (track.isGlobalTrack()) { + if (mySelectionPrim.IsSelected(track)) { // applying the efficiency twice for the misrec of leading particle if (f_Eff->Eval(track.pt()) > gRandom->Uniform(0, 1)) { ptArray.push_back(track.pt()); @@ -596,19 +634,6 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part ue.fill(HIST("hCounter"), 0); - bool isAcceptedEvent = false; - if (isRun3 ? collision.sel8() : collision.sel7()) { - if ((isRun3 || doprocessMC) ? true : collision.alias_bit(kINT7)) { - isAcceptedEvent = true; - } - } - // only PS - if (!isAcceptedEvent) { - return; - } - - ue.fill(HIST("hCounter"), 1); - ue.fill(HIST("hStat"), collision.size()); auto vtxZ = collision.posZ(); @@ -632,7 +657,6 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part if (particle.pt() < cfgTrkLowPtCut) { continue; } - // ue.fill(HIST("hPtInPrim"), particle.pt()); if (flPtTrue < particle.pt()) { flPtTrue = particle.pt(); @@ -694,37 +718,60 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part ue_true.push_back(sumptm_toptrue[i_reg]); } - // add flags for Vtx, PS, ev sel - - ue.fill(HIST(pNumDenTruePS[0]), flPtTrue, ue_true[0]); - ue.fill(HIST(pSumPtTruePS[0]), flPtTrue, ue_true[3]); + ue.fill(HIST(pNumDenTrue[0]), flPtTrue, ue_true[0]); + ue.fill(HIST(pSumPtTrue[0]), flPtTrue, ue_true[3]); - ue.fill(HIST(pNumDenTruePS[1]), flPtTrue, ue_true[1]); - ue.fill(HIST(pSumPtTruePS[1]), flPtTrue, ue_true[4]); + ue.fill(HIST(pNumDenTrue[1]), flPtTrue, ue_true[1]); + ue.fill(HIST(pSumPtTrue[1]), flPtTrue, ue_true[4]); - ue.fill(HIST(pNumDenTruePS[2]), flPtTrue, ue_true[2]); - ue.fill(HIST(pSumPtTruePS[2]), flPtTrue, ue_true[5]); + ue.fill(HIST(pNumDenTrue[2]), flPtTrue, ue_true[2]); + ue.fill(HIST(pSumPtTrue[2]), flPtTrue, ue_true[5]); ptArrayTrue.clear(); phiArrayTrue.clear(); indexArrayTrue.clear(); - isAcceptedEvent = false; - if (std::abs(collision.posZ()) < 10.f) { - if (isRun3 ? collision.sel8() : collision.sel7()) { - if ((isRun3 || doprocessMC) ? true : collision.alias_bit(kINT7)) { - isAcceptedEvent = true; - } - } + if (sel8 && !collision.sel8()) { + return; } - // + vtx - if (!isAcceptedEvent) { + if (removeITSROFBorder && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder))) { return; } + if (manuallyApplysel8 && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + return; + } + + ue.fill(HIST("hCounter"), 1); + + if (piluprejection && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return; + } ue.fill(HIST("hCounter"), 2); + if (goodzvertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; + } + ue.fill(HIST("hCounter"), 3); + + // only PS + if ((std::abs(collision.posZ()) >= 10.f)) { + return; + } + ue.fill(HIST("hCounter"), 4); + + ue.fill(HIST(pNumDenTruePS[0]), flPtTrue, ue_true[0]); + ue.fill(HIST(pSumPtTruePS[0]), flPtTrue, ue_true[3]); + + ue.fill(HIST(pNumDenTruePS[1]), flPtTrue, ue_true[1]); + ue.fill(HIST(pSumPtTruePS[1]), flPtTrue, ue_true[4]); + + ue.fill(HIST(pNumDenTruePS[2]), flPtTrue, ue_true[2]); + ue.fill(HIST(pSumPtTruePS[2]), flPtTrue, ue_true[5]); + + // ue.fill(HIST("hCounter"), 2); + ue.fill(HIST("hvtxZ"), vtxZ); // loop over MC true particles int multTrue = 0; @@ -753,7 +800,7 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part int flIndex = 0; int multRec = 0; for (auto& track : tracks) { - if (!track.isGlobalTrack()) { + if (!mySelectionPrim.IsSelected(track)) { continue; } @@ -785,36 +832,36 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part for (auto& track : tracks) { - if (myTrackSelection().IsSelected(track)) { // TODO: set cuts w/o DCA cut + if (mySelectionOpenDCA.IsSelected(track)) { // TODO: set cuts w/o DCA cut ue.fill(HIST("hPTVsDCAData"), track.pt(), track.dcaXY()); } if constexpr (IS_MC) { if (track.has_mcParticle()) { - if (track.isGlobalTrack()) { + if (mySelectionPrim.IsSelected(track)) { ue.fill(HIST("hPtOut"), track.pt()); } - if (myTrackSelection().IsSelected(track)) { + if (mySelectionOpenDCA.IsSelected(track)) { ue.fill(HIST("hPtDCAall"), track.pt(), track.dcaXY()); } const auto& particle = track.template mcParticle_as(); if (particle.isPhysicalPrimary()) { - if (track.isGlobalTrack()) { + if (mySelectionPrim.IsSelected(track)) { // ue.fill(HIST("hPtOutPrim"), track.pt()); ue.fill(HIST("hPtOutPrim"), particle.pt()); } - if (myTrackSelection().IsSelected(track)) { + if (mySelectionOpenDCA.IsSelected(track)) { ue.fill(HIST("hPtDCAPrimary"), track.pt(), track.dcaXY()); } // LOGP(info, "this track has MC particle {}", 1); } else { - if (track.isGlobalTrack()) { + if (mySelectionPrim.IsSelected(track)) { ue.fill(HIST("hPtOutSec"), track.pt()); } - if (myTrackSelection().IsSelected(track)) { - if (particle.getGenStatusCode() >= 0) { // i guess these are decays + if (mySelectionOpenDCA.IsSelected(track)) { + if (particle.producedByGenerator()) { // i guess these are from decays ue.fill(HIST("hPtDCAWeak"), track.pt(), track.dcaXY()); - } else { // i guess these are from material + } else { //// i guess these are from material ue.fill(HIST("hPtDCAMat"), track.pt(), track.dcaXY()); } } @@ -822,7 +869,7 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part } } - if (track.isGlobalTrack()) { + if (mySelectionPrim.IsSelected(track)) { // applying the efficiency twice for the misrec of leading particle if (f_Eff->Eval(track.pt()) > gRandom->Uniform(0, 1)) { ptArray.push_back(track.pt()); @@ -940,20 +987,3 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part phiArray.clear(); indexArray.clear(); } -TrackSelection ueCharged::myTrackSelection() -{ - TrackSelection selectedTracks; - selectedTracks.SetPtRange(0.1f, 1e10f); - selectedTracks.SetEtaRange(-0.8f, 0.8f); - selectedTracks.SetRequireITSRefit(true); - selectedTracks.SetRequireTPCRefit(true); - selectedTracks.SetRequireGoldenChi2(false); - selectedTracks.SetMinNCrossedRowsTPC(70); - selectedTracks.SetMinNCrossedRowsOverFindableClustersTPC(0.8f); - selectedTracks.SetMaxChi2PerClusterTPC(4.f); - selectedTracks.SetRequireHitsInITSLayers(1, {0, 1}); // one hit in any SPD layer - selectedTracks.SetMaxChi2PerClusterITS(36.f); - selectedTracks.SetMaxDcaXY(10.f); - selectedTracks.SetMaxDcaZ(10.f); - return selectedTracks; -} diff --git a/PWGUD/AQC/udQCmidRap.cxx b/PWGUD/AQC/udQCmidRap.cxx index 38e1b96384a..e7178cfa042 100644 --- a/PWGUD/AQC/udQCmidRap.cxx +++ b/PWGUD/AQC/udQCmidRap.cxx @@ -44,6 +44,7 @@ struct UDQCmid { Configurable DGCuts{"DGCuts", {}, "DG event cuts"}; // Configurable withAmbTrackAnalysis{"ambiguousTracks", false, "with ambiguous tracks analysis"}; // Configurable withAmbFwdTrackAnalysis{"ambiguousFwdTracks", false, "with ambiguous forward tracks analysis"}; + // Configurable doCleanFITBC{"doCleanFITBC", false, "Require cleanFIT in compatible BCs"}; // structures to hold information about the possible BCs the ambiguous tracks/FwdTracks belong to o2::dataformats::bcRanges abcrs = o2::dataformats::bcRanges("ambiguous_tracks"); @@ -89,15 +90,17 @@ struct UDQCmid { registry.add("DG/dEdxTPC", "DG: TPC signal versus signed track momentum; Signed track momentum [GeV/c]; TPC signal; Tracks", {HistType::kTH2F, {{120, -6., 6.}, {1000, 0., 1000.}}}); registry.add("DG/dEdxTOF", "DG: TOF signal versus signed track momentum; Signed track momentum [GeV/c]; TOF signal; Tracks", {HistType::kTH2F, {{1000, 0., 10.}, {1000, 0., 10.}}}); - registry.add("DG/hMassAll", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{2000, 0., 20.}}}); - registry.add("DG/hMassFIT", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{2000, 0., 20.}}}); + registry.add("DG/hMassAll", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{1000, 0., 10.}}}); + registry.add("DG/hMassFIT", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{1000, 0., 10.}}}); - registry.add("DG/hMassZDC", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{2000, 0., 20.}}}); - registry.add("DG/hMassTOF", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{2000, 0., 20.}}}); - registry.add("DG/hMassFWD", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{2000, 0., 20.}}}); - registry.add("DG/hMassGlobalTrk", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{2000, 0., 20.}}}); - registry.add("DG/hMassAmbigous", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{2000, 0., 20.}}}); - registry.add("DG/hMassAmbigousFWD", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{2000, 0., 20.}}}); + registry.add("DG/hMassZDC", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{1000, 0., 10.}}}); + registry.add("DG/hMassTOF", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{1000, 0., 10.}}}); + registry.add("DG/hMassFWD", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{1000, 0., 10.}}}); + registry.add("DG/hMassGlobalTrk", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{1000, 0., 10.}}}); + registry.add("DG/hMassITSTrk", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{1000, 0., 10.}}}); + + registry.add("DG/hMassAmbigous", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{1000, 0., 10.}}}); + registry.add("DG/hMassAmbigousFWD", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{1000, 0., 10.}}}); registry.add("DG/etaphi", "DG: Eta versus Phi; eta ; #phi ", {HistType::kTH2F, {{80, -2., 2.}, {120, 0., 6.28}}}); registry.add("DG/etaphi1", "DG: Eta versus Phi; eta ; #phi ", {HistType::kTH2F, {{80, -2., 2.}, {120, 0., 6.28}}}); @@ -107,22 +110,25 @@ struct UDQCmid { registry.add("DG/etaphi5", "DG: Eta versus Phi; eta ; #phi ", {HistType::kTH2F, {{80, -2., 2.}, {120, 0., 6.28}}}); registry.add("DG/etaphi6", "DG: Eta versus Phi; eta ; #phi ", {HistType::kTH2F, {{80, -2., 2.}, {120, 0., 6.28}}}); registry.add("DG/etaphi7", "DG: Eta versus Phi; eta ; #phi ", {HistType::kTH2F, {{80, -2., 2.}, {120, 0., 6.28}}}); + registry.add("DG/etaphi8", "DG: Eta versus Phi; eta ; #phi ", {HistType::kTH2F, {{80, -2., 2.}, {120, 0., 6.28}}}); registry.add("DG/IVMptSys2PVtrk", "DG: Invariant mass versus p_{T, system}; Invarian mass [GeV/c^2]; p_{T, system} [GeV/c]; DG collisions 2 PV tracks", {HistType::kTH2F, {{2000, 0., 20.}, {2000, 0., 20.0}}}); registry.add("DG/IVMptSys2PVtrk1", "DG: Invariant mass versus p_{T, system}; Invarian mass [GeV/c^2]; p_{T, system} [GeV/c]; DG collisions 2 PV tracks", {HistType::kTH2F, {{2000, 0., 20.}, {2000, 0., 20.0}}}); registry.add("DG/IVMptSys2PVtrk2", "DG: Invariant mass versus p_{T, system}; Invarian mass [GeV/c^2]; p_{T, system} [GeV/c]; DG collisions 2 PV tracks", {HistType::kTH2F, {{2000, 0., 20.}, {2000, 0., 20.0}}}); registry.add("DG/IVMptSys2PVtrk3", "DG: Invariant mass versus p_{T, system}; Invarian mass [GeV/c^2]; p_{T, system} [GeV/c]; DG collisions 2 PV tracks", {HistType::kTH2F, {{2000, 0., 20.}, {2000, 0., 20.0}}}); - registry.add("DG/IVMptSys2PVtrk4", "DG: Invariant mass versus p_{T, system}; Invarian mass [GeV/c^2]; p_{T, system} [GeV/c]; DG collisions 2 PV tracks", {HistType::kTH2F, {{2000, 0., 20.}, {2000, 0., 20.0}}}); registry.add("DG/IVMptSys2PVtrk5", "DG: Invariant mass versus p_{T, system}; Invarian mass [GeV/c^2]; p_{T, system} [GeV/c]; DG collisions 2 PV tracks", {HistType::kTH2F, {{2000, 0., 20.}, {2000, 0., 20.0}}}); registry.add("DG/IVMptSys2PVtrk6", "DG: Invariant mass versus p_{T, system}; Invarian mass [GeV/c^2]; p_{T, system} [GeV/c]; DG collisions 2 PV tracks", {HistType::kTH2F, {{2000, 0., 20.}, {2000, 0., 20.0}}}); registry.add("DG/IVMptSys2PVtrk7", "DG: Invariant mass versus p_{T, system}; Invarian mass [GeV/c^2]; p_{T, system} [GeV/c]; DG collisions 2 PV tracks", {HistType::kTH2F, {{2000, 0., 20.}, {2000, 0., 20.0}}}); + registry.add("DG/IVMptSys2PVtrk8", "DG: Invariant mass versus p_{T, system}; Invarian mass [GeV/c^2]; p_{T, system} [GeV/c]; DG collisions 2 PV tracks", {HistType::kTH2F, {{2000, 0., 20.}, {2000, 0., 20.0}}}); } if (context.mOptions.get("processFewProng")) { registry.add("fpStat", "#fpStat", {HistType::kTH1F, {{2, 0.5, 2.5}}}); registry.add("allPVC", "#allPVC", {HistType::kTH1F, {{200, 0.5, 200.5}}}); registry.add("fpPVC", "#fpPVC", {HistType::kTH1F, {{200, 0.5, 200.5}}}); + registry.add("fpPVC1", "#fpPVC1", {HistType::kTH1F, {{200, 0.5, 200.5}}}); + registry.add("fpPVC2", "#fpPVC2", {HistType::kTH1F, {{200, 0.5, 200.5}}}); } } @@ -149,10 +155,10 @@ struct UDQCmid { registry.get(HIST("collisions/globalTracks"))->Fill(goodTracks.size()); // 12. net charge and invariant mass - // bool goodetas = true; - // bool goodpts = true; + // bool goodetas = false; + // bool goodpts = false; bool ispipiCand = false; - // auto netCharge = 0; + auto netCharge = 0; auto lvtmp = TLorentzVector(); auto ivm = TLorentzVector(); if (isDGcandidate) { @@ -177,13 +183,13 @@ struct UDQCmid { // define Lorentz vector to create invariant mass lvtmp.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), mass2Use); LOGF(debug, "mass %f track pt %f/%f eta %f/%f", mass2Use, track.pt(), lvtmp.Perp(), track.eta(), lvtmp.Eta()); - /* if (track.pt() <= diffCuts.minPt() || track.pt() >= diffCuts.maxPt()) { - goodpts = false; - } - if (track.eta() <= diffCuts.minEta() || track.eta() >= diffCuts.maxEta()) { - goodetas = false; - }*/ - // netCharge += track.sign(); + if (track.pt() <= diffCuts.minPt() || track.pt() >= diffCuts.maxPt()) { + continue; + } + if (track.eta() <= diffCuts.minEta() || track.eta() >= diffCuts.maxEta()) { + continue; + } + netCharge += track.sign(); ivm += lvtmp; } @@ -213,7 +219,8 @@ struct UDQCmid { if (ispipiCand) { registry.get(HIST("DG/IVMptSys2PVtrk"))->Fill(ivm.M(), ivm.Pt()); registry.get(HIST("DG/etaphi"))->Fill(ivm.Eta(), ivm.Phi()); - registry.get(HIST("DG/hMassAll"))->Fill(ivm.M()); + if (netCharge == 0) + registry.get(HIST("DG/hMassAll"))->Fill(ivm.M()); } } // coll } // dgcand @@ -286,30 +293,36 @@ struct UDQCmid { break; } } + /* if (doCleanFITBC) { + for (auto const& bc : bcSlice) { + if (!udhelpers::cleanFIT(bc, diffCuts.maxFITtime(), diffCuts.FITAmpLimits())) { + isDGcandidate = false; + break; + } + } + }*/ registry.get(HIST("collisions/Stat"))->Fill(1., isDGcandidate * 1.); // Invariant mass with 2 PV contributors and all contributors if (isDGcandidate) { - if (collision.numContrib() == 2) { - if (ispipiCand) { - registry.get(HIST("DG/IVMptSys2PVtrk1"))->Fill(ivm.M(), ivm.Pt()); - registry.get(HIST("DG/etaphi1"))->Fill(ivm.Eta(), ivm.Phi()); - if (ivm.Pt() < 0.2) { - registry.get(HIST("DG/hMassFIT"))->Fill(ivm.M()); - } + if (ispipiCand) { + registry.get(HIST("DG/IVMptSys2PVtrk1"))->Fill(ivm.M(), ivm.Pt()); + registry.get(HIST("DG/etaphi1"))->Fill(ivm.Eta(), ivm.Phi()); + if ((ivm.Pt() < 0.2) && (netCharge == 0)) { + registry.get(HIST("DG/hMassFIT"))->Fill(ivm.M()); } + } - for (auto const& track : tracks) { - if (track.isPVContributor()) { - registry.get(HIST("DG/etapt"))->Fill(track.eta(), track.pt(), 1.); - LOGF(debug, "dEdx TPC %f TOF %i %f", track.tpcSignal(), track.hasTOF(), track.hasTOF() ? track.tofSignal() : 0.); - registry.get(HIST("DG/dEdxTPC"))->Fill(track.tpcInnerParam() / track.sign(), track.tpcSignal()); - - if (track.hasTOF()) { - registry.get(HIST("DG/dEdxTOF"))->Fill(track.p() / track.sign(), track.beta()); - } // fill TOF - } // pv contributor - } + for (auto const& track : tracks) { + if (track.isPVContributor()) { + registry.get(HIST("DG/etapt"))->Fill(track.eta(), track.pt(), 1.); + LOGF(debug, "dEdx TPC %f TOF %i %f", track.tpcSignal(), track.hasTOF(), track.hasTOF() ? track.tofSignal() : 0.); + registry.get(HIST("DG/dEdxTPC"))->Fill(track.tpcInnerParam() / track.sign(), track.tpcSignal()); + + if (track.hasTOF()) { + registry.get(HIST("DG/dEdxTOF"))->Fill(track.p() / track.sign(), track.beta()); + } // fill TOF + } // pv contributor } } // Inavariant mass after FIT @@ -328,7 +341,7 @@ struct UDQCmid { if (ispipiCand) { registry.get(HIST("DG/IVMptSys2PVtrk2"))->Fill(ivm.M(), ivm.Pt()); registry.get(HIST("DG/etaphi2"))->Fill(ivm.Eta(), ivm.Phi()); - if (ivm.Pt() < 0.2) { + if ((ivm.Pt() < 0.2) && (netCharge == 0)) { registry.get(HIST("DG/hMassZDC"))->Fill(ivm.M()); } } @@ -342,37 +355,51 @@ struct UDQCmid { if (ispipiCand) { registry.get(HIST("DG/IVMptSys2PVtrk3"))->Fill(ivm.M(), ivm.Pt()); registry.get(HIST("DG/etaphi3"))->Fill(ivm.Eta(), ivm.Phi()); - if (ivm.Pt() < 0.2) { + if ((ivm.Pt() < 0.2) && (netCharge == 0)) { registry.get(HIST("DG/hMassFWD"))->Fill(ivm.M()); } } } - // 4. Check for global tracks which are no vtx tracks + // 4. Check for global tracks bool globalAndVtx = isDGcandidate; - bool vtxAndGlobal = isDGcandidate; for (auto const& track : tracks) { - if (track.isGlobalTrack() && !track.isPVContributor()) { + if (track.isGlobalTrack() && track.isPVContributor()) { globalAndVtx = false; } - if (track.isPVContributor() && !track.isGlobalTrack()) { - vtxAndGlobal = false; - } } registry.get(HIST("collisions/Stat"))->Fill(4., globalAndVtx * 1.); - registry.get(HIST("collisions/Stat"))->Fill(5., vtxAndGlobal * 1.); if (globalAndVtx) { if (ispipiCand) { registry.get(HIST("DG/IVMptSys2PVtrk4"))->Fill(ivm.M(), ivm.Pt()); registry.get(HIST("DG/etaphi4"))->Fill(ivm.Eta(), ivm.Phi()); - if (ivm.Pt() < 0.2) { + if ((ivm.Pt() < 0.2) && (netCharge == 0)) { registry.get(HIST("DG/hMassGlobalTrk"))->Fill(ivm.M()); } } } - // 5. check a given bc for possible ambiguous Tracks + // 5. Check for ITS only tracks + bool ITSOnlytrks = isDGcandidate; + for (auto const& track : tracks) { + if (track.hasITS() && track.isPVContributor() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) { + ITSOnlytrks = false; + } + } + registry.get(HIST("collisions/Stat"))->Fill(5., ITSOnlytrks * 1.); + + if (ITSOnlytrks) { + if (ispipiCand) { + registry.get(HIST("DG/IVMptSys2PVtrk5"))->Fill(ivm.M(), ivm.Pt()); + registry.get(HIST("DG/etaphi5"))->Fill(ivm.Eta(), ivm.Phi()); + if ((ivm.Pt() < 0.2) && (netCharge == 0)) { + registry.get(HIST("DG/hMassITSTrk"))->Fill(ivm.M()); + } + } + } + + // 6. check a given bc for possible ambiguous Tracks auto noAmbTracks = isDGcandidate; for (auto const& bc : bcSlice) { if (abcrs.isInRange(bc.globalIndex())) { @@ -385,15 +412,15 @@ struct UDQCmid { if (noAmbTracks) { if (ispipiCand) { - registry.get(HIST("DG/IVMptSys2PVtrk5"))->Fill(ivm.M(), ivm.Pt()); - registry.get(HIST("DG/etaphi5"))->Fill(ivm.Eta(), ivm.Phi()); - if (ivm.Pt() < 0.2) { + registry.get(HIST("DG/IVMptSys2PVtrk6"))->Fill(ivm.M(), ivm.Pt()); + registry.get(HIST("DG/etaphi6"))->Fill(ivm.Eta(), ivm.Phi()); + if ((ivm.Pt() < 0.2) && (netCharge == 0)) { registry.get(HIST("DG/hMassAmbigous"))->Fill(ivm.M()); } } } - // 6. check a given bc for possible ambiguous FwdTracks + // 7. check a given bc for possible ambiguous FwdTracks auto noAmbFwdTracks = isDGcandidate; for (auto const& bc : bcSlice) { if (afbcrs.isInRange(bc.globalIndex())) { @@ -406,23 +433,23 @@ struct UDQCmid { if (noAmbFwdTracks) { if (ispipiCand) { - registry.get(HIST("DG/IVMptSys2PVtrk6"))->Fill(ivm.M(), ivm.Pt()); - registry.get(HIST("DG/etaphi6"))->Fill(ivm.Eta(), ivm.Phi()); - if (ivm.Pt() < 0.2) { + registry.get(HIST("DG/IVMptSys2PVtrk7"))->Fill(ivm.M(), ivm.Pt()); + registry.get(HIST("DG/etaphi7"))->Fill(ivm.Eta(), ivm.Phi()); + if ((ivm.Pt() < 0.2) && (netCharge == 0)) { registry.get(HIST("DG/hMassAmbigousFWD"))->Fill(ivm.M()); } } } - // 7. fraction of PV tracks with TOF hit + // 8. fraction of PV tracks with TOF hit isDGcandidate &= (rgtrwTOF >= diffCuts.minRgtrwTOF()); registry.get(HIST("collisions/Stat"))->Fill(8., isDGcandidate * 1.); if (isDGcandidate) { if (ispipiCand) { - registry.get(HIST("DG/IVMptSys2PVtrk7"))->Fill(ivm.M(), ivm.Pt()); - registry.get(HIST("DG/etaphi7"))->Fill(ivm.Eta(), ivm.Phi()); - if (ivm.Pt() < 0.2) { + registry.get(HIST("DG/IVMptSys2PVtrk8"))->Fill(ivm.M(), ivm.Pt()); + registry.get(HIST("DG/etaphi8"))->Fill(ivm.Eta(), ivm.Phi()); + if ((ivm.Pt() < 0.2) && (netCharge == 0)) { registry.get(HIST("DG/hMassTOF"))->Fill(ivm.M()); } } @@ -447,7 +474,24 @@ struct UDQCmid { // update #PV contributors in collisions with empty FT0 registry.get(HIST("fpPVC"))->Fill(collision.numContrib(), 1.); - } + + if (udhelpers::cleanFV0(bc, diffCuts.maxFITtime(), 0.)) { + // only collisions with empty FV0 and FT0 arrive here + registry.get(HIST("fpStat"))->Fill(3., 1.); + + // update #PV contributors in collisions with empty FT0 && FV0 + registry.get(HIST("fpPVC1"))->Fill(collision.numContrib(), 1.); + + if (udhelpers::cleanFDD(bc, diffCuts.maxFITtime(), 0., 0.)) { + // only collisions with empty FV0 arrive here + registry.get(HIST("fpStat"))->Fill(4., 1.); + + // update #PV contributors in collisions with empty FT0 && FV0&& FDCC + registry.get(HIST("fpPVC2"))->Fill(collision.numContrib(), 1.); + } // fdd + } // fvo + + } // ft0 } PROCESS_SWITCH(UDQCmid, processFewProng, "Process FewProng", true); }; diff --git a/PWGUD/Core/CMakeLists.txt b/PWGUD/Core/CMakeLists.txt index d5ef6f9a085..7686edd8eea 100644 --- a/PWGUD/Core/CMakeLists.txt +++ b/PWGUD/Core/CMakeLists.txt @@ -56,3 +56,11 @@ o2physics_add_library(UPCCutparHolder o2physics_target_root_dictionary(UPCCutparHolder HEADERS UPCCutparHolder.h LINKDEF UPCCutparHolderLinkDef.h) + +o2physics_add_library(decayTree + SOURCES decayTree.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore ROOT::EG RapidJSON::RapidJSON) + +o2physics_target_root_dictionary(decayTree + HEADERS decayTree.h + LINKDEF decayTreeLinkDef.h) diff --git a/PWGUD/Core/DGCutparHolder.h b/PWGUD/Core/DGCutparHolder.h index 2877ea0aade..8312d72ac32 100644 --- a/PWGUD/Core/DGCutparHolder.h +++ b/PWGUD/Core/DGCutparHolder.h @@ -39,7 +39,7 @@ class DGCutparHolder bool TOR = true, float maxFITtime = 4, std::vector FITAmpLimits = {0., 0., 0., 0., 0.}, - std::vector collisionSel = {0, 0, 0, 0, 0}) : mNDtcoll{ndtcoll}, mMinNBCs{nMinBCs}, mWithFwdTracks{withFwdTracks}, mGlobalTracksOnly{globalTracksOnly}, mITSOnlyTracks{ITSonlyTracks}, mMinRgtrwTOF{minrgtrwTOF}, mMinNTracks{MinNTracks}, mMaxNTracks{MaxNTracks}, mNetCharges{NetCharges}, mPidHypo{pidHypo}, mMinVertexPosz{MinPosz}, mMaxVertexPosz{MaxPosz}, mMinPt{minPt}, mMaxPt{maxPt}, mMinEta{minEta}, mMaxEta{maxEta}, mMinIVM{minIVM}, mMaxIVM{maxIVM}, mMaxNSigmaTPC{maxNSigmaTPC}, mMaxNSigmaTOF{maxNSigmaTOF}, mTVX{TVX}, mTSC{TSC}, mTCE{TCE}, mTOR{TOR}, mMaxFITtime{maxFITtime}, mFITAmpLimits{FITAmpLimits}, mCollisionSel{collisionSel} + std::vector collisionSel = {1, 1, 1, 0, 1, 0, 0}) : mNDtcoll{ndtcoll}, mMinNBCs{nMinBCs}, mWithFwdTracks{withFwdTracks}, mGlobalTracksOnly{globalTracksOnly}, mITSOnlyTracks{ITSonlyTracks}, mMinRgtrwTOF{minrgtrwTOF}, mMinNTracks{MinNTracks}, mMaxNTracks{MaxNTracks}, mNetCharges{NetCharges}, mPidHypo{pidHypo}, mMinVertexPosz{MinPosz}, mMaxVertexPosz{MaxPosz}, mMinPt{minPt}, mMaxPt{maxPt}, mMinEta{minEta}, mMaxEta{maxEta}, mMinIVM{minIVM}, mMaxIVM{maxIVM}, mMaxNSigmaTPC{maxNSigmaTPC}, mMaxNSigmaTOF{maxNSigmaTOF}, mTVX{TVX}, mTSC{TSC}, mTCE{TCE}, mTOR{TOR}, mMaxFITtime{maxFITtime}, mFITAmpLimits{FITAmpLimits}, mCollisionSel{collisionSel} { } @@ -145,6 +145,13 @@ class DGCutparHolder std::vector mFITAmpLimits; // collision selections to consider from event selection task + // 0: time frame border + // 1: same bunch pile-up + // 2: ITS ROF frame boarder + // 3: ZvtxFT0 vs PV + // 4: Vertex ITS-TPC + // 5: Vertex TRD matched + // 6: Vertex TOF matched std::vector mCollisionSel; ClassDefNV(DGCutparHolder, 1); diff --git a/PWGUD/Core/DGPIDSelector.cxx b/PWGUD/Core/DGPIDSelector.cxx index 5d37ef6c8de..04dab87ef7a 100644 --- a/PWGUD/Core/DGPIDSelector.cxx +++ b/PWGUD/Core/DGPIDSelector.cxx @@ -8,7 +8,8 @@ // 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. - +#include +#include #include "CommonConstants/PhysicsConstants.h" #include "DGPIDSelector.h" @@ -143,7 +144,7 @@ void DGAnaparHolder::Print() LOGF(info, " max alpha: %f", mMaxAlpha); LOGF(info, " min system pT: %f", mMinptsys); LOGF(info, " max system pT: %f", mMaxptsys); - LOGF(info, " nCombine: %d", mNCombine); + LOGF(info, " nCombine: %zu", mNCombine); LOGF(info, " unlike charges"); for (auto ch : mUnlikeCharges) { LOGF(info, " %i", ch); @@ -160,6 +161,108 @@ void DGAnaparHolder::Print() } // ----------------------------------------------------------------------------- +// setter +void DGAnaparHolder::SetNTracks(int min, int max) +{ + mMinNTracks = min; + mMaxNTracks = max; +} + +void DGAnaparHolder::SetMinRgtrwTOF(float rgtrwTOF) +{ + mMinRgtrwTOF = rgtrwTOF; +} + +void DGAnaparHolder::SetmaxDCA(float maxxy, float maxz) +{ + mMaxDCAxy = maxxy; + mMaxDCAz = maxz; +} + +void DGAnaparHolder::SetdBC(int min, int max) +{ + mdBCMin = min; + mdBCMax = max; +} + +void DGAnaparHolder::SetFITvetoes(std::vector vetoes) +{ + + if (vetoes.size() == 5) { + mFITvetoes = vetoes; + } else { + LOGF(info, "Wrong number of vetoes. Vetoes are not set!"); + } +} + +void DGAnaparHolder::SetITSOnlyTracks(bool itsOnly) +{ + mITSOnlyTracks = itsOnly; +} + +void DGAnaparHolder::SetNClTPC(int min, int max) +{ + mMinNClTPC = min; + mMaxNClTPC = max; +} + +void DGAnaparHolder::SetChi2NClTPC(float min, float max) +{ + mMinChi2NClTPC = min; + mMaxChi2NClTPC = max; +} + +void DGAnaparHolder::Setpt(float min, float max) +{ + mMinpt = min; + mMaxpt = max; +} + +void DGAnaparHolder::Seteta(float min, float max) +{ + mMineta = min; + mMaxeta = max; +} + +void DGAnaparHolder::SetAlpha(float min, float max) +{ + mMinAlpha = min; + mMaxAlpha = max; +} + +void DGAnaparHolder::Setptsys(float min, float max) +{ + mMinptsys = min; + mMaxptsys = max; +} + +void DGAnaparHolder::SetnCombine(std::size_t nComb) +{ + mNCombine = nComb; +} + +void DGAnaparHolder::SetnetCharges(std::vector charges) +{ + mNetCharges = charges; +} + +void DGAnaparHolder::SetunlikeCharges(std::vector charges) +{ + mUnlikeCharges = charges; +} + +void DGAnaparHolder::SetlikeCharges(std::vector charges) +{ + mLikeCharges = charges; +} + +void DGAnaparHolder::SetPIDs(std::vector pids) +{ + mDGPIDs = pids; +} + +// ----------------------------------------------------------------------------- +// getter DGPIDCuts DGAnaparHolder::PIDCuts() { return DGPIDCuts(mDGPIDCutValues); @@ -197,7 +300,7 @@ void DGAnaparHolder::makeUniquePermutations() auto hash = hasher(std::string(hashstr)); if (std::find(hashes.begin(), hashes.end(), hash) == hashes.end()) { hashes.push_back(hash); - for (auto ii = 0; ii < mNCombine; ii++) { + for (std::size_t ii = 0; ii < mNCombine; ii++) { muniquePerms.push_back(perm[ii]); } } @@ -420,7 +523,7 @@ std::vector> DGPIDSelector::combinations(int nPool) for (auto comb : combs) { for (auto ii = 0u; ii < numUniquePerms; ii++) { std::vector cope(mAnaPars.nCombine(), 0); - for (auto jj = 0; jj < mAnaPars.nCombine(); jj++) { + for (std::size_t jj = 0; jj < mAnaPars.nCombine(); jj++) { auto ind = ii * mAnaPars.nCombine() + jj; cope[uniquePerms[ind]] = comb[jj]; } diff --git a/PWGUD/Core/DGPIDSelector.h b/PWGUD/Core/DGPIDSelector.h index 3daa9c8596a..c130c2094ce 100644 --- a/PWGUD/Core/DGPIDSelector.h +++ b/PWGUD/Core/DGPIDSelector.h @@ -115,7 +115,7 @@ struct DGAnaparHolder { float mineta = -2.0, float maxeta = 2.0, float minalpha = 0.0, float maxalpha = 3.2, float minptsys = 0.0, float maxptsys = 100.0, - int nCombine = 2, + std::size_t nCombine = 2, std::vector netCharges = {0}, std::vector unlikeCharges = {0}, std::vector likeCharges = {-2, 2}, @@ -139,6 +139,25 @@ struct DGAnaparHolder { // helper void Print(); + // setter + void SetNTracks(int, int); + void SetMinRgtrwTOF(float); + void SetmaxDCA(float, float); + void SetdBC(int, int); + void SetFITvetoes(std::vector); + void SetITSOnlyTracks(bool); + void SetNClTPC(int, int); + void SetChi2NClTPC(float, float); + void Setpt(float, float); + void Seteta(float, float); + void SetAlpha(float, float); + void Setptsys(float, float); + void SetnCombine(std::size_t); + void SetnetCharges(std::vector); + void SetunlikeCharges(std::vector); + void SetlikeCharges(std::vector); + void SetPIDs(std::vector); + // getter int minNTracks() const { return mMinNTracks; } int maxNTracks() const { return mMaxNTracks; } @@ -161,7 +180,7 @@ struct DGAnaparHolder { float maxAlpha() const { return mMaxAlpha; } float minptsys() const { return mMinptsys; } float maxptsys() const { return mMaxptsys; } - int nCombine() const { return mNCombine; } + std::size_t nCombine() const { return mNCombine; } std::vector netCharges() const { return mNetCharges; } std::vector unlikeCharges() const { return mUnlikeCharges; } std::vector likeCharges() const { return mLikeCharges; } @@ -197,7 +216,7 @@ struct DGAnaparHolder { float mMaxAlpha; float mMinptsys; float mMaxptsys; - int mNCombine; + std::size_t mNCombine; std::vector mNetCharges; // all PV tracks std::vector mUnlikeCharges; // selected PV tracks std::vector mLikeCharges; // selected PV tracks diff --git a/PWGUD/Core/DGSelector.h b/PWGUD/Core/DGSelector.h index 0c40747f6e0..c9349da9247 100644 --- a/PWGUD/Core/DGSelector.h +++ b/PWGUD/Core/DGSelector.h @@ -179,10 +179,18 @@ class DGSelector if (sels[3] && !udhelpers::cutIsGoodZvtxFT0vsPV(collision)) { return 16; } - // is ITS-TPC track + // at least one PV track with TPC hit if (sels[4] && !udhelpers::cutIsVertexITSTPC(collision)) { return 17; } + // at least one PV track with TRD hit + if (sels[5] && !udhelpers::cutIsVertexTRDmatched(collision)) { + return 18; + } + // at least one PV track with TOF hit + if (sels[6] && !udhelpers::cutIsVertexTOFmatched(collision)) { + return 19; + } // if we arrive here then the event is good! return 0; diff --git a/PWGUD/Core/SGSelector.h b/PWGUD/Core/SGSelector.h index 3b1d9c0d182..4845818f244 100644 --- a/PWGUD/Core/SGSelector.h +++ b/PWGUD/Core/SGSelector.h @@ -32,7 +32,7 @@ class SGSelector SGSelector() : fPDG(TDatabasePDG::Instance()) {} template - int Print(SGCutParHolder diffCuts, CC& collision, BCs& bcRange, TCs& tracks, FWs& fwdtracks) + int Print(SGCutParHolder /*diffCuts*/, CC& collision, BCs& /*bcRange*/, TCs& /*tracks*/, FWs& /*fwdtracks*/) { LOGF(info, "Size of array %i", collision.size()); return 1; @@ -93,7 +93,7 @@ class SGSelector } } if (newdgabc != newdgcbc) { - if (ampc / diffCuts.FITAmpLimits()[2] > ampa / diffCuts.FITAmpLimits()[2]) + if (ampc / diffCuts.FITAmpLimits()[2] > ampa / diffCuts.FITAmpLimits()[1]) newdgabc = newdgcbc; } newbc = newdgabc; @@ -119,19 +119,29 @@ class SGSelector float fit_cut[3] = {fv0, ft0a, ft0c}; int gap = collision.gapSide(); int true_gap = gap; + float FV0A, FT0A, FT0C, ZNA, ZNC; + FV0A = collision.totalFV0AmplitudeA(); + FT0A = collision.totalFT0AmplitudeA(); + FT0C = collision.totalFT0AmplitudeC(); + ZNA = collision.energyCommonZNA(); + ZNC = collision.energyCommonZNC(); if (gap == 0) { - if (collision.totalFV0AmplitudeA() > fit_cut[0] || collision.totalFT0AmplitudeA() > fit_cut[1] || collision.energyCommonZNA() > zdc_cut) + if (FV0A > fit_cut[0] || FT0A > fit_cut[1] || ZNA > zdc_cut) true_gap = -1; } else if (gap == 1) { - if (collision.totalFT0AmplitudeC() > fit_cut[2] || collision.energyCommonZNC() > zdc_cut) + if (FT0C > fit_cut[2] || ZNC > zdc_cut) true_gap = -1; } else if (gap == 2) { - if ((collision.totalFV0AmplitudeA() > fit_cut[0] || collision.totalFT0AmplitudeA() > fit_cut[1] || collision.energyCommonZNA() > zdc_cut) && (collision.totalFT0AmplitudeC() > fit_cut[2] || collision.energyCommonZNC() > zdc_cut)) + if ((FV0A > fit_cut[0] || FT0A > fit_cut[1] || ZNA > zdc_cut) && (FT0C > fit_cut[2] || ZNC > zdc_cut)) true_gap = -1; - else if (collision.totalFV0AmplitudeA() > fit_cut[0] || collision.totalFT0AmplitudeA() > fit_cut[1] || collision.energyCommonZNA() > zdc_cut) + else if ((FV0A > fit_cut[0] || FT0A > fit_cut[1] || ZNA > zdc_cut) && (FT0C <= fit_cut[2] && ZNC <= zdc_cut)) true_gap = 1; - else if (collision.totalFT0AmplitudeC() > fit_cut[2] || collision.energyCommonZNC() > zdc_cut) + else if ((FV0A <= fit_cut[0] && FT0A <= fit_cut[1] && ZNA <= zdc_cut) && (FT0C > fit_cut[2] || ZNC > zdc_cut)) true_gap = 0; + else if (FV0A <= fit_cut[0] && FT0A <= fit_cut[1] && ZNA <= zdc_cut && FT0C <= fit_cut[2] && ZNC <= zdc_cut) + true_gap = 2; + else + std::cout << "Something wrong with DG" << std::endl; } return true_gap; } diff --git a/PWGUD/Core/SGTrackSelector.h b/PWGUD/Core/SGTrackSelector.h new file mode 100644 index 00000000000..1b68ab0ddba --- /dev/null +++ b/PWGUD/Core/SGTrackSelector.h @@ -0,0 +1,165 @@ +// 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. +// +// \Single Gap Event Analyzer +// \author Sasha Bylinkin, alexander.bylinkin@gmail.com +// \since April 2023 + +#ifndef PWGUD_CORE_SGTRACKSELECTOR_H_ +#define PWGUD_CORE_SGTRACKSELECTOR_H_ + +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "iostream" +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/SGSelector.h" +#include +#include "TVector3.h" +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +template +int trackselector(const T& track, const std::vector& params) +{ + // Ensure the params vector contains all the necessary parameters + + if (params.size() < 8) { + throw std::runtime_error("Insufficient parameters provided"); + } + TVector3 a; + a.SetXYZ(track.px(), track.py(), track.pz()); + if (params[0] == 1 && !track.isPVContributor()) + return 0; + if (std::abs(track.dcaZ()) > params[1]) + return 0; + if (!params[2]) { + if (std::abs(track.dcaXY()) > .0105 + .035 / pow(a.Pt(), 1.1)) + return 0; + } else { + if (std::abs(track.dcaXY()) > params[2]) + return 0; + } + if (track.tpcChi2NCl() > params[3]) + return 0; + if (track.tpcNClsFindable() < params[4]) + return 0; + if (track.itsChi2NCl() > params[5]) + return 0; + if (std::abs(a.Eta()) > params[6]) + return 0; + if (a.Pt() < params[7]) + return 0; + return 1; +} +template +int trackpid(const T& track, bool use_tof) +{ + int pid = 0; + float pi, ka, pr; + float tpi, tka, tpr; + pi = std::abs(track.tpcNSigmaPi()); + ka = std::abs(track.tpcNSigmaKa()); + pr = std::abs(track.tpcNSigmaPr()); + if (pi < 1. && pi < ka && pi < pr) + pid = 1; + else if (ka < 1. && ka < pi && ka < pr) + pid = 2; + else if (pr < 1. && pr < pi && pr < ka) + pid = 3; + if (use_tof && track.tofChi2() > -1) { + tpi = std::abs(track.tofNSigmaPi()); + tka = std::abs(track.tofNSigmaKa()); + tpr = std::abs(track.tofNSigmaPr()); + if (std::sqrt(pi * pi + tpi * tpi) < 2 && std::sqrt(pi * pi + tpi * tpi) < std::sqrt(ka * ka + tka * tka) && std::sqrt(pi * pi + tpi * tpi) < std::sqrt(pr * pr + tpr * tpr)) + pid = 1; + else if (std::sqrt(ka * ka + tka * tka) < 2 && std::sqrt(pi * pi + tpi * tpi) > std::sqrt(ka * ka + tka * tka) && std::sqrt(ka * ka + tka * tka) < std::sqrt(pr * pr + tpr * tpr)) + pid = 2; + else if (std::sqrt(pr * pr + tpr * tpr) < 2 && std::sqrt(pr * pr + tpr * tpr) < std::sqrt(ka * ka + tka * tka) && std::sqrt(pi * pi + tpi * tpi) > std::sqrt(pr * pr + tpr * tpr)) + pid = 3; + } + return pid; +} +template +bool selectionPIDKaon(const T& candidate, bool use_tof, float nsigmatpc_cut, float nsigmatof_cut) +{ + if (use_tof && candidate.hasTOF() && (candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa()) < nsigmatof_cut) { + return true; + } + if (use_tof && !candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < nsigmatpc_cut) { + return true; + } + if (!use_tof && std::abs(candidate.tpcNSigmaKa()) < nsigmatpc_cut) { + return true; + } + return false; +} +template +bool selectionPIDPion(const T& candidate, bool use_tof, float nsigmatpc_cut, float nsigmatof_cut) +{ + if (use_tof && candidate.hasTOF() && (candidate.tofNSigmaPi() * candidate.tofNSigmaPi() + candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi()) < nsigmatof_cut) { + return true; + } + if (use_tof && !candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < nsigmatpc_cut) { + return true; + } + if (!use_tof && std::abs(candidate.tpcNSigmaPi()) < nsigmatpc_cut) { + return true; + } + return false; +} +template +bool selectionPIDElec(const T& candidate, bool use_tof, float nsigmatpc_cut, float nsigmatof_cut) +{ + if (use_tof && candidate.hasTOF() && (candidate.tofNSigmaEl() * candidate.tofNSigmaEl() + candidate.tpcNSigmaEl() * candidate.tpcNSigmaEl()) < nsigmatof_cut) { + return true; + } + if (use_tof && !candidate.hasTOF() && std::abs(candidate.tpcNSigmaEl()) < nsigmatpc_cut) { + return true; + } + if (!use_tof && std::abs(candidate.tpcNSigmaEl()) < nsigmatpc_cut) { + return true; + } + return false; +} +template +bool selectionPIDProton(const T& candidate, bool use_tof, float nsigmatpc_cut, float nsigmatof_cut) +{ + if (use_tof && candidate.hasTOF() && (candidate.tofNSigmaPr() * candidate.tofNSigmaPr() + candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr()) < nsigmatof_cut) { + return true; + } + if (use_tof && !candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmatpc_cut) { + return true; + } + if (!use_tof && std::abs(candidate.tpcNSigmaPr()) < nsigmatpc_cut) { + return true; + } + return false; +} +template +bool selectionPIDMuon(const T& candidate, bool use_tof, float nsigmatpc_cut, float nsigmatof_cut) +{ + if (use_tof && candidate.hasTOF() && (candidate.tofNSigmaMu() * candidate.tofNSigmaMu() + candidate.tpcNSigmaMu() * candidate.tpcNSigmaMu()) < nsigmatof_cut) { + return true; + } + if (use_tof && !candidate.hasTOF() && std::abs(candidate.tpcNSigmaMu()) < nsigmatpc_cut) { + return true; + } + if (!use_tof && std::abs(candidate.tpcNSigmaMu()) < nsigmatpc_cut) { + return true; + } + return false; +} +#endif // PWGUD_CORE_SGTRACKSELECTOR_H_ diff --git a/PWGUD/Core/UDHelpers.h b/PWGUD/Core/UDHelpers.h index 787cf3673e4..4b692f7c5c1 100644 --- a/PWGUD/Core/UDHelpers.h +++ b/PWGUD/Core/UDHelpers.h @@ -18,6 +18,7 @@ #include #include + #include "TLorentzVector.h" #include "Framework/Logger.h" #include "DataFormatsFT0/Digit.h" @@ -42,7 +43,7 @@ template ::type* = nullptr, typenam int8_t netCharge(TCs tracks) { int8_t nch = 0; - for (auto track : tracks) { + for (const auto& track : tracks) { if (track.isPVContributor()) { nch += track.sign(); } @@ -55,7 +56,7 @@ template ::type* = nullptr, typena int8_t netCharge(TCs tracks) { int8_t nch = 0; - for (auto track : tracks) { + for (const auto& track : tracks) { nch += track.sign(); } return nch; @@ -67,7 +68,7 @@ template ::type* = nullptr, typenam float rPVtrwTOF(TCs tracks, int nPVTracks) { float rpvrwTOF = 0.; - for (auto& track : tracks) { + for (const auto& track : tracks) { if (track.isPVContributor() && track.hasTOF()) { rpvrwTOF += 1.; } @@ -83,7 +84,7 @@ template ::type* = nullptr, typena float rPVtrwTOF(TCs tracks, int nPVTracks) { float rpvrwTOF = 0.; - for (auto& track : tracks) { + for (const auto& track : tracks) { if (track.hasTOF()) { rpvrwTOF += 1.; } @@ -101,29 +102,31 @@ float rPVtrwTOF(TCs tracks, int nPVTracks) // true BC. // template -T compatibleBCs(uint64_t meanBC, int deltaBC, T const& bcs); +T compatibleBCs(uint64_t const& meanBC, int const& deltaBC, T const& bcs); -template -T compatibleBCs(I& bcIter, uint64_t meanBC, int deltaBC, T const& bcs); +template +T compatibleBCs(B const& bc, uint64_t const& meanBC, int const& deltaBC, T const& bcs); // In this variant of compatibleBCs the bcIter is ideally placed within // [minBC, maxBC], but it does not need to be. The range is given by meanBC +- delatBC. -template -T compatibleBCs(I& bcIter, uint64_t meanBC, int deltaBC, T const& bcs) +template +T compatibleBCs(B const& bc, uint64_t const& meanBC, int const& deltaBC, T const& bcs) { + // get BCs iterator + auto bcIter = bcs.iteratorAt(bc.globalIndex()); + // range of BCs to consider - uint64_t minBC = (uint64_t)deltaBC < meanBC ? meanBC - (uint64_t)deltaBC : 0; - uint64_t maxBC = meanBC + (uint64_t)deltaBC; - LOGF(debug, " minBC %d maxBC %d bcIterator %d (%d)", minBC, maxBC, bcIter.globalBC(), bcIter.globalIndex()); + uint64_t minBC = static_cast(deltaBC) < meanBC ? meanBC - static_cast(deltaBC) : 0; + uint64_t maxBC = meanBC + static_cast(deltaBC); + LOGF(debug, " minBC %d maxBC %d bcIterator %d (%d) #BCs %d", minBC, maxBC, bcIter.globalBC(), bcIter.globalIndex(), bcs.size()); // check [min,max]BC to overlap with [bcs.iteratorAt([0,bcs.size() - 1]) if (maxBC < bcs.iteratorAt(0).globalBC() || minBC > bcs.iteratorAt(bcs.size() - 1).globalBC()) { LOGF(debug, " No overlap of [%d, %d] and [%d, %d]", minBC, maxBC, bcs.iteratorAt(0).globalBC(), bcs.iteratorAt(bcs.size() - 1).globalBC()); - return T{{bcs.asArrowTable()->Slice(0, 0)}, (uint64_t)0}; + return T{{bcs.asArrowTable()->Slice(0, 0)}, static_cast(0)}; } // find slice of BCs table with BC in [minBC, maxBC] - int moveCount = 0; int64_t minBCId = bcIter.globalIndex(); int64_t maxBCId = bcIter.globalIndex(); @@ -131,14 +134,12 @@ T compatibleBCs(I& bcIter, uint64_t meanBC, int deltaBC, T const& bcs) if (bcIter.globalBC() < minBC) { while (bcIter != bcs.end() && bcIter.globalBC() < minBC) { ++bcIter; - ++moveCount; minBCId = bcIter.globalIndex(); } } else { while (bcIter.globalIndex() > 0 && bcIter.globalBC() >= minBC) { minBCId = bcIter.globalIndex(); --bcIter; - --moveCount; } } @@ -147,26 +148,19 @@ T compatibleBCs(I& bcIter, uint64_t meanBC, int deltaBC, T const& bcs) while (bcIter != bcs.end() && bcIter.globalBC() <= maxBC) { maxBCId = bcIter.globalIndex(); ++bcIter; - ++moveCount; } - } else { while (bcIter.globalIndex() > 0 && bcIter.globalBC() > maxBC) { --bcIter; - --moveCount; maxBCId = bcIter.globalIndex(); } } - LOGF(debug, " BC range: %d - %d", minBCId, maxBCId); - - // reset bcIter - bcIter.moveByIndex(-moveCount); // create bc slice - T slice{{bcs.asArrowTable()->Slice(minBCId, maxBCId - minBCId + 1)}, (uint64_t)minBCId}; - bcs.copyIndexBindings(slice); - LOGF(debug, " size of slice %d", slice.size()); - return slice; + T bcslice{{bcs.asArrowTable()->Slice(minBCId, maxBCId - minBCId + 1)}, static_cast(minBCId)}; + bcs.copyIndexBindings(bcslice); + LOGF(debug, " size of slice %d", bcslice.size()); + return bcslice; } // In this variant of compatibleBCs the range of compatible BCs is calculated from the @@ -178,7 +172,7 @@ T compatibleBCs(C const& collision, int ndt, T const& bcs, int nMinBCs = 7) // return if collisions has no associated BC if (!collision.has_foundBC() || ndt < 0) { - return T{{bcs.asArrowTable()->Slice(0, 0)}, (uint64_t)0}; + return T{{bcs.asArrowTable()->Slice(0, 0)}, static_cast(0)}; } // get associated BC @@ -200,10 +194,10 @@ T compatibleBCs(C const& collision, int ndt, T const& bcs, int nMinBCs = 7) // In this variant of compatibleBCs the range of compatible BCs is defined by meanBC +- deltaBC. template -T compatibleBCs(uint64_t meanBC, int deltaBC, T const& bcs) +T compatibleBCs(uint64_t const& meanBC, int const& deltaBC, T const& bcs) { // find BC with globalBC ~ meanBC - uint64_t ind = (uint64_t)(bcs.size() / 2); + uint64_t ind = static_cast(bcs.size() / 2); auto bcIter = bcs.iteratorAt(ind); return compatibleBCs(bcIter, meanBC, deltaBC, bcs); @@ -212,14 +206,14 @@ T compatibleBCs(uint64_t meanBC, int deltaBC, T const& bcs) // ----------------------------------------------------------------------------- // Same as above but for collisions with MC information template -T MCcompatibleBCs(F const& collision, int ndt, T const& bcs, int nMinBCs = 7) +T MCcompatibleBCs(F const& collision, int const& ndt, T const& bcs, int const& nMinBCs = 7) { LOGF(debug, "Collision time / resolution [ns]: %f / %f", collision.collisionTime(), collision.collisionTimeRes()); // return if collisions has no associated BC if (!collision.has_foundBC()) { - LOGF(info, "Collision %i - no BC found!", collision.globalIndex()); - return T{{bcs.asArrowTable()->Slice(0, 0)}, (uint64_t)0}; + LOGF(debug, "Collision %i - no BC found!", collision.globalIndex()); + return T{{bcs.asArrowTable()->Slice(0, 0)}, static_cast(0)}; } // get associated BC @@ -252,19 +246,19 @@ bool hasGoodPID(DGCutparHolder diffCuts, TC track) track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()); - if (TMath::Abs(track.tpcNSigmaEl()) < diffCuts.maxNSigmaTPC()) { + if (std::abs(track.tpcNSigmaEl()) < diffCuts.maxNSigmaTPC()) { return true; } - if (TMath::Abs(track.tpcNSigmaMu()) < diffCuts.maxNSigmaTPC()) { + if (std::abs(track.tpcNSigmaMu()) < diffCuts.maxNSigmaTPC()) { return true; } - if (TMath::Abs(track.tpcNSigmaPi()) < diffCuts.maxNSigmaTPC()) { + if (std::abs(track.tpcNSigmaPi()) < diffCuts.maxNSigmaTPC()) { return true; } - if (TMath::Abs(track.tpcNSigmaKa()) < diffCuts.maxNSigmaTPC()) { + if (std::abs(track.tpcNSigmaKa()) < diffCuts.maxNSigmaTPC()) { return true; } - if (TMath::Abs(track.tpcNSigmaPr()) < diffCuts.maxNSigmaTPC()) { + if (std::abs(track.tpcNSigmaPr()) < diffCuts.maxNSigmaTPC()) { return true; } @@ -275,19 +269,19 @@ bool hasGoodPID(DGCutparHolder diffCuts, TC track) track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()); - if (TMath::Abs(track.tofNSigmaEl()) < diffCuts.maxNSigmaTOF()) { + if (std::abs(track.tofNSigmaEl()) < diffCuts.maxNSigmaTOF()) { return true; } - if (TMath::Abs(track.tofNSigmaMu()) < diffCuts.maxNSigmaTOF()) { + if (std::abs(track.tofNSigmaMu()) < diffCuts.maxNSigmaTOF()) { return true; } - if (TMath::Abs(track.tofNSigmaPi()) < diffCuts.maxNSigmaTOF()) { + if (std::abs(track.tofNSigmaPi()) < diffCuts.maxNSigmaTOF()) { return true; } - if (TMath::Abs(track.tofNSigmaKa()) < diffCuts.maxNSigmaTOF()) { + if (std::abs(track.tofNSigmaKa()) < diffCuts.maxNSigmaTOF()) { return true; } - if (TMath::Abs(track.tofNSigmaPr()) < diffCuts.maxNSigmaTOF()) { + if (std::abs(track.tofNSigmaPr()) < diffCuts.maxNSigmaTOF()) { return true; } } @@ -589,7 +583,7 @@ bool cutIsGoodZvtxFT0vsPV(T const& coll) template bool cutIsVertexITSTPC(T const& coll) -// Selects collisions with at least one ITS-TPC track, and thus rejects vertices built from ITS-only tracks. +// Selects collisions with at least one ITS-TPC PV track, and thus rejects vertices built from ITS-only tracks. // Has an effect only on the pp data, in Pb-Pb ITS-only vertices are already rejected by default. // Return true when event is good. { @@ -598,6 +592,26 @@ bool cutIsVertexITSTPC(T const& coll) // ----------------------------------------------------------------------------- +template +bool cutIsVertexTRDmatched(T const& coll) +// Selects collisions with at least one TRD PV track. +// Return true when event is good. +{ + return coll.selection_bit(o2::aod::evsel::kIsVertexTRDmatched); +} + +// ----------------------------------------------------------------------------- + +template +bool cutIsVertexTOFmatched(T const& coll) +// Selects collisions with at least one TOF PV track. +// Return true when event is good. +{ + return coll.selection_bit(o2::aod::evsel::kIsVertexTOFmatched); +} + +// ----------------------------------------------------------------------------- + template bool goodCollision(T const& coll, DGCutparHolder const& diffCuts) // Return true if collision is accepted according to user-chosen rules from event selection task @@ -605,15 +619,19 @@ bool goodCollision(T const& coll, DGCutparHolder const& diffCuts) bool accepted = true; std::vector sels = diffCuts.collisionSel(); if (sels[0]) - accepted = cutNoTimeFrameBorder(coll); + accepted = accepted && cutNoTimeFrameBorder(coll); if (sels[1]) - accepted = cutNoSameBunchPileup(coll); + accepted = accepted && cutNoSameBunchPileup(coll); if (sels[2]) - accepted = cutNoITSROFrameBorder(coll); + accepted = accepted && cutNoITSROFrameBorder(coll); if (sels[3]) - accepted = cutIsGoodZvtxFT0vsPV(coll); + accepted = accepted && cutIsGoodZvtxFT0vsPV(coll); if (sels[4]) - accepted = cutIsVertexITSTPC(coll); + accepted = accepted && cutIsVertexITSTPC(coll); + if (sels[5]) + accepted = accepted && cutIsVertexTRDmatched(coll); + if (sels[6]) + accepted = accepted && cutIsVertexTOFmatched(coll); return accepted; } @@ -627,6 +645,9 @@ void fillBGBBFlags(upchelpers::FITInfo& info, uint64_t const& minbc, BCR const& // 0 <= bit <= 31 auto bit = bc.globalBC() - minbc; + if (bit < 0 || bit > 31) + continue; + if (!bc.selection_bit(o2::aod::evsel::kNoBGT0A)) SETBIT(info.BGFT0Apf, bit); if (!bc.selection_bit(o2::aod::evsel::kNoBGT0C)) @@ -652,52 +673,42 @@ void fillBGBBFlags(upchelpers::FITInfo& info, uint64_t const& minbc, BCR const& // ----------------------------------------------------------------------------- // extract FIT information -template -void getFITinfo(upchelpers::FITInfo& info, uint64_t const& bcnum, B const& bcs, aod::FT0s const& ft0s, aod::FV0As const& fv0as, aod::FDDs const& fdds) -{ - // find bc with globalBC = bcnum - Partition selbc = aod::bc::globalBC == bcnum; - selbc.bindTable(bcs); - - // if BC exists then update FIT information for this BC - if (selbc.size() > 0) { - auto bc = selbc.begin(); - - // FV0A - if (bc.has_foundFV0()) { - auto fv0 = fv0as.iteratorAt(bc.foundFV0Id()); - info.timeFV0A = fv0.time(); - info.ampFV0A = FV0AmplitudeA(fv0); - info.triggerMaskFV0A = fv0.triggerMask(); - } +template +void getFITinfo(upchelpers::FITInfo& info, BC& bc, BCS const& bcs, aod::FT0s const& ft0s, aod::FV0As const& fv0as, aod::FDDs const& fdds) +{ + // FV0A + if (bc.has_foundFV0()) { + auto fv0 = fv0as.iteratorAt(bc.foundFV0Id()); + info.timeFV0A = fv0.time(); + info.ampFV0A = FV0AmplitudeA(fv0); + info.triggerMaskFV0A = fv0.triggerMask(); + } - // FT0 - if (bc.has_foundFT0()) { - auto ft0 = ft0s.iteratorAt(bc.foundFT0Id()); - info.timeFT0A = ft0.timeA(); - info.timeFT0C = ft0.timeC(); - info.ampFT0A = FT0AmplitudeA(ft0); - info.ampFT0C = FT0AmplitudeC(ft0); - info.triggerMaskFT0 = ft0.triggerMask(); - } + // FT0 + if (bc.has_foundFT0()) { + auto ft0 = ft0s.iteratorAt(bc.foundFT0Id()); + info.timeFT0A = ft0.timeA(); + info.timeFT0C = ft0.timeC(); + info.ampFT0A = FT0AmplitudeA(ft0); + info.ampFT0C = FT0AmplitudeC(ft0); + info.triggerMaskFT0 = ft0.triggerMask(); + } - // FDD - if (bc.has_foundFDD()) { - auto fdd = fdds.iteratorAt(bc.foundFDDId()); - info.timeFDDA = fdd.timeA(); - info.timeFDDC = fdd.timeC(); - info.ampFDDA = FDDAmplitudeA(fdd); - info.ampFDDC = FDDAmplitudeC(fdd); - info.triggerMaskFDD = fdd.triggerMask(); - } + // FDD + if (bc.has_foundFDD()) { + auto fdd = fdds.iteratorAt(bc.foundFDDId()); + info.timeFDDA = fdd.timeA(); + info.timeFDDC = fdd.timeC(); + info.ampFDDA = FDDAmplitudeA(fdd); + info.ampFDDC = FDDAmplitudeC(fdd); + info.triggerMaskFDD = fdd.triggerMask(); } // fill BG and BB flags - auto minbc = bcnum - 16; - auto maxbc = bcnum + 15; - Partition bcrange = aod::bc::globalBC >= minbc && aod::bc::globalBC <= maxbc; - bcrange.bindTable(bcs); - fillBGBBFlags(info, minbc, bcrange); + auto bcnum = bc.globalBC(); + auto bcrange = compatibleBCs(bc, bcnum, 16, bcs); + LOGF(debug, "size of bcrange %d", bcrange.size()); + fillBGBBFlags(info, bcnum - 16, bcrange); } // ----------------------------------------------------------------------------- @@ -719,7 +730,7 @@ bool cleanCalo(T const& bc, aod::Calos& calos, std::vector& /*lims*/, Sli // ----------------------------------------------------------------------------- // check if all tracks come from same MCCollision template -int64_t sameMCCollision(T tracks, aod::McCollisions mccols, aod::McParticles mcparts) +int64_t sameMCCollision(T tracks, aod::McCollisions, aod::McParticles) { int64_t colID = -1; for (auto const& track : tracks) { @@ -731,14 +742,14 @@ int64_t sameMCCollision(T tracks, aod::McCollisions mccols, aod::McParticles mcp colID = mccol.globalIndex(); } else { if (colID != mccol.globalIndex()) { - return (int64_t)-1; + return static_cast(-1); } } } else { - return (int64_t)-1; + return static_cast(-1); } } else { - return (int64_t)-1; + return static_cast(-1); } } @@ -751,7 +762,7 @@ int64_t sameMCCollision(T tracks, aod::McCollisions mccols, aod::McParticles mcp template bool isPythiaCDE(T MCparts) { - for (auto mcpart : MCparts) { + for (const auto& mcpart : MCparts) { if (mcpart.pdgCode() == 9900110) { return true; } @@ -770,7 +781,7 @@ bool isSTARLightJPsimumu(T MCparts) } else { if (MCparts.iteratorAt(0).pdgCode() != 443013) return false; - if (abs(MCparts.iteratorAt(1).pdgCode()) != 13) + if (std::abs(MCparts.iteratorAt(1).pdgCode()) != 13) return false; if (MCparts.iteratorAt(2).pdgCode() != -MCparts.iteratorAt(1).pdgCode()) return false; @@ -778,35 +789,48 @@ bool isSTARLightJPsimumu(T MCparts) return true; } +// ----------------------------------------------------------------------------- +// PbPb di electron production +// [15, 11, 13], [15, 11, 13] +template +bool isUpcgen(T MCparts) +{ + if (MCparts.size() < 4) { + return false; + } else { + auto pid1 = std::abs(MCparts.iteratorAt(0).pdgCode()); + auto pid2 = std::abs(MCparts.iteratorAt(1).pdgCode()); + if (pid1 != 11 && pid1 != 13 && pid1 != 15) + return false; + if (pid2 != 11 && pid2 != 13 && pid2 != 15) + return false; + } + return true; +} + // ----------------------------------------------------------------------------- // In pp events produced with GRANIITTI the stack starts with -// 22212/22212/99/22212/2212/99/90 +// 22212/22212/22212/2212/[211,321,]/[211,321,] template bool isGraniittiCDE(T MCparts) { - for (auto MCpart : MCparts) { - LOGF(debug, " MCpart.pdgCode() %d", MCpart.pdgCode()); - } - LOGF(debug, ""); + // for (auto MCpart : MCparts) { + // LOGF(info, " MCpart.pdgCode() %d", MCpart.pdgCode()); + // } + // LOGF(debug, ""); - if (MCparts.size() < 7) { + if (MCparts.size() < 6) { return false; } else { if (MCparts.iteratorAt(0).pdgCode() != 2212) return false; if (MCparts.iteratorAt(1).pdgCode() != 2212) return false; - if (MCparts.iteratorAt(2).pdgCode() != 99) + if (MCparts.iteratorAt(2).pdgCode() != 2212) return false; if (MCparts.iteratorAt(3).pdgCode() != 2212) return false; - if (MCparts.iteratorAt(4).pdgCode() != 2212) - return false; - if (MCparts.iteratorAt(5).pdgCode() != 99) - return false; - if (MCparts.iteratorAt(6).pdgCode() != 90) - return false; } return true; @@ -833,6 +857,11 @@ int isOfInterest(T MCparts) return 3; } + // Upcgen + if (isUpcgen(MCparts)) { + return 4; + } + return 0; } diff --git a/PWGUD/Core/UPCJpsiCentralBarrelCorrHelper.h b/PWGUD/Core/UPCJpsiCentralBarrelCorrHelper.h index 54b6ec1b276..0857d6bab1d 100644 --- a/PWGUD/Core/UPCJpsiCentralBarrelCorrHelper.h +++ b/PWGUD/Core/UPCJpsiCentralBarrelCorrHelper.h @@ -16,22 +16,24 @@ #ifndef PWGUD_CORE_UPCJPSICENTRALBARRELCORRHELPER_H_ #define PWGUD_CORE_UPCJPSICENTRALBARRELCORRHELPER_H_ +#include #include #include "CommonConstants/MathConstants.h" +#include "random" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using namespace std; -enum ParticleType { +/*enum ParticleType { P_ELECTRON = 0, P_MUON = 1, P_PROTON = 2 -}; +};*/ -template -int testPIDhypo(T trackPID) +/*template +int testPIDhypoTPC(T trackPID) { float nSigmaTPC[3]; nSigmaTPC[P_ELECTRON] = std::abs(trackPID.tpcNSigmaEl()); @@ -46,6 +48,33 @@ int testPIDhypo(T trackPID) } } +template +int testPIDhypo(T trackPID) +{ + float nSigmaTPC[3]; + nSigmaTPC[P_ELECTRON] = std::abs(trackPID.tpcNSigmaEl()); + nSigmaTPC[P_MUON] = std::abs(trackPID.tpcNSigmaMu()); + nSigmaTPC[P_PROTON] = std::abs(trackPID.tpcNSigmaPr()); + int enumChoiceTPC = std::distance(std::begin(nSigmaTPC), + std::min_element(std::begin(nSigmaTPC), std::end(nSigmaTPC))); + + float nSigmaTOF[3]; + nSigmaTOF[P_ELECTRON] = std::abs(trackPID.tofNSigmaEl()); + nSigmaTOF[P_MUON] = std::abs(trackPID.tofNSigmaMu()); + nSigmaTOF[P_PROTON] = std::abs(trackPID.tofNSigmaPr()); + int enumChoiceTOF = std::distance(std::begin(nSigmaTOF), + std::min_element(std::begin(nSigmaTOF), std::end(nSigmaTOF))); + if (trackPID.hasTPC() || trackPID.hasTOF()) { + if (trackPID.hasTOF()) { + return enumChoiceTOF; + } else { + return enumChoiceTPC; + } + } else { + return -1; + } +}*/ + float* correlation(TLorentzVector* lv1, TLorentzVector* lv2, TLorentzVector* lv) { TLorentzVector pa(1., 0., 0, 1); // projectile @@ -190,4 +219,19 @@ double DeltaPhi(TLorentzVector lv1, TLorentzVector lv2) return dp; } +double DeltaPhiRandom(TLorentzVector lv1, TLorentzVector lv2) +{ + std::vector indices = {0, 1}; + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); + std::shuffle(indices.begin(), indices.end(), std::default_random_engine(seed)); + std::array arrayLorentz = {lv1, lv2}; + TLorentzVector lv_sum = arrayLorentz[indices[0]] + arrayLorentz[indices[1]]; + TLorentzVector lv_diff = arrayLorentz[indices[0]] - arrayLorentz[indices[1]]; + ; + + double dp = lv_sum.DeltaPhi(lv_diff); + + return dp; +} + #endif // PWGUD_CORE_UPCJPSICENTRALBARRELCORRHELPER_H_ diff --git a/PWGUD/Core/UPCTauCentralBarrelHelperRL.h b/PWGUD/Core/UPCTauCentralBarrelHelperRL.h index d205d69aeb9..55a13a0e9c5 100644 --- a/PWGUD/Core/UPCTauCentralBarrelHelperRL.h +++ b/PWGUD/Core/UPCTauCentralBarrelHelperRL.h @@ -19,16 +19,28 @@ #include #include -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - enum MyParticle { P_ELECTRON = 0, P_MUON = 1, P_PION = 2, P_KAON = 3, - P_PROTON = 4 + P_PROTON = 4, + P_ENUM_COUNTER = 5 +}; + +enum MyTauChannel { + CH_EE = 0, + CH_MUMU = 1, + CH_EMU = 2, + CH_PIPI = 3, + CH_EPI = 4, + CH_MUPI = 5, + CH_FOURPI = 6, + CH_ETHREEPI = 7, + CH_MUTHREEPI = 8, + CH_SIXPI = 9, + CH_EMUPI = 10, + CH_ENUM_COUNTER = 11 }; void printLargeMessage(std::string info) @@ -43,8 +55,14 @@ void printMediumMessage(std::string info) LOGF(info, "+++++++++++++ %s +++++++++++++", info); } +void printDebugMessage(std::string info) +// Helper to printf info message to terminal +{ + LOGF(debug, "X!X!X!X!X!X!X!X!X %s X!X!X!X!X!X!X!X!X", info); +} + template -int testPIDhypothesis(T trackPIDinfo, float nSigmaShift = 0., bool isMC = false) +int testPIDhypothesis(T trackPIDinfo, float maxNsigmaTPC = 5.0, float maxNsigmaTOF = 5.0, bool useTOF = true, bool useTOFsigmaAfterTPC = true, float nSigmaShift = 0., bool isMC = false) // Choose, which particle it is according to PID { float nSigmaTPC[5]; @@ -70,34 +88,51 @@ int testPIDhypothesis(T trackPIDinfo, float nSigmaShift = 0., bool isMC = false) int enumChoiceTOF = std::distance(std::begin(nSigmaTOF), std::min_element(std::begin(nSigmaTOF), std::end(nSigmaTOF))); - if (trackPIDinfo.hasTPC() || trackPIDinfo.hasTOF()) { - if (trackPIDinfo.hasTOF()) { - return enumChoiceTOF; + if (trackPIDinfo.hasTPC()) { + if (trackPIDinfo.hasTOF() && useTOF) { + if (nSigmaTOF[enumChoiceTOF] < maxNsigmaTOF) { + return enumChoiceTOF; + } else { + printDebugMessage(Form("testPIDhypothesis cut - the lowest nSigmaTOF is higher than %f", maxNsigmaTPC)); + return -1; + } + } else if (trackPIDinfo.hasTOF() && useTOFsigmaAfterTPC) { + if (nSigmaTPC[enumChoiceTPC] < maxNsigmaTPC && nSigmaTOF[enumChoiceTPC] < maxNsigmaTOF) { + return enumChoiceTPC; + } else { + printDebugMessage(Form("testPIDhypothesis cut - the lowest nSigmaTPC is higher than %f or the lowest nSigmaTOF is higher than %f", maxNsigmaTPC, maxNsigmaTOF)); + return -1; + } } else { - return enumChoiceTPC; + if (nSigmaTPC[enumChoiceTPC] < maxNsigmaTPC) { + return enumChoiceTPC; + } else { + printDebugMessage(Form("testPIDhypothesis cut - the lowest nSigmaTPC is higher than %f", maxNsigmaTPC)); + return -1; + } } } else { - LOGF(debug, "testPIDhypothesis failed - track did not leave information in TPC or TOF"); + printDebugMessage("testPIDhypothesis failed - track did not leave information in TPC"); return -1; } } template -int trackPDG(T trackPIDinfo) +int trackPDG(T trackPIDinfo, float maxNsigmaTPC = 5.0, float maxNsigmaTOF = 5.0, bool useTOF = true, bool useTOFsigmaAfterTPC = true, float nSigmaShift = 0., bool isMC = false) // using testPIDhypothesis, reads enumMyParticle and return pdg value { - if (testPIDhypothesis(trackPIDinfo) == P_ELECTRON) { + if (testPIDhypothesis(trackPIDinfo, maxNsigmaTPC, maxNsigmaTOF, useTOF, useTOFsigmaAfterTPC, nSigmaShift, isMC) == P_ELECTRON) { return 11; - } else if (testPIDhypothesis(trackPIDinfo) == P_MUON) { + } else if (testPIDhypothesis(trackPIDinfo, maxNsigmaTPC, maxNsigmaTOF, useTOF, useTOFsigmaAfterTPC, nSigmaShift, isMC) == P_MUON) { return 13; - } else if (testPIDhypothesis(trackPIDinfo) == P_PION) { + } else if (testPIDhypothesis(trackPIDinfo, maxNsigmaTPC, maxNsigmaTOF, useTOF, useTOFsigmaAfterTPC, nSigmaShift, isMC) == P_PION) { return 211; - } else if (testPIDhypothesis(trackPIDinfo) == P_KAON) { + } else if (testPIDhypothesis(trackPIDinfo, maxNsigmaTPC, maxNsigmaTOF, useTOF, useTOFsigmaAfterTPC, nSigmaShift, isMC) == P_KAON) { return 321; - } else if (testPIDhypothesis(trackPIDinfo) == P_PROTON) { + } else if (testPIDhypothesis(trackPIDinfo, maxNsigmaTPC, maxNsigmaTOF, useTOF, useTOFsigmaAfterTPC, nSigmaShift, isMC) == P_PROTON) { return 2212; } else { - printMediumMessage("Something is wrong with track PDG selector"); + printDebugMessage("Something is wrong with track PDG selector"); return -1.; } } @@ -116,11 +151,17 @@ int enumMyParticle(int valuePDG) } else if (std::abs(valuePDG) == 2212) { return P_PROTON; } else { - printMediumMessage("PDG value not found in enumMyParticle. Returning -1."); + printDebugMessage("PDG value not found in enumMyParticle. Returning -1."); return -1.; } } +float pt(float px, float py) +// Just a simple function to return pt +{ + return std::sqrt(px * px + py * py); +} + float momentum(float px, float py, float pz) // Just a simple function to return momentum { @@ -165,16 +206,50 @@ float rapidity(float mass, float px, float py, float pz) return 0.5 * std::log((energy(mass, px, py, pz) + pz) / (energy(mass, px, py, pz) - pz)); } -double calculateAcoplanarity(double phi_trk1, double phi_trk2) +double calculateAcoplanarity(double phiTrk1, double phiTrk2) // Function to calculate acoplanarity of two tracks based on phi of both tracks, which is in interval (0,2*pi) { - double aco = std::abs(phi_trk1 - phi_trk2); + double aco = std::abs(phiTrk1 - phiTrk2); if (aco <= o2::constants::math::PI) return aco; else return (o2::constants::math::TwoPI - aco); } +double calculateCollinearity(double etaTrk1, double etaTrk2, double phiTrk1, double phiTrk2) +// Function to calculate deltaR(trk1,trk2) = sqrt(deltaEta^2+deltaPhi^2) +{ + double deltaEta = etaTrk1 - etaTrk2; + double deltaPhi = phiTrk1 - phiTrk2; + return std::sqrt(deltaEta * deltaEta + deltaPhi * deltaPhi); +} + +template +int countPhysicalPrimary(Ps particles) +// Function to loop over particles associated to a mcCollision and return total of physical primary particles +{ + int nTotal = 0; + for (const auto& particle : particles) { + if (!particle.isPhysicalPrimary()) + continue; + nTotal++; + } + return nTotal; +} + +template +int countParticlesWithoutMother(Ps particles) +// Function to loop over particles associated to a mcCollision and return total of particles without mothers (hopely alternative to isPhysicalPrimary) +{ + int nTotal = 0; + for (const auto& particle : particles) { + if (particle.has_mothers()) + continue; + nTotal++; + } + return nTotal; +} + template float getAvgITSClSize(T const& track) { diff --git a/PWGUD/Core/decayTree.cxx b/PWGUD/Core/decayTree.cxx new file mode 100644 index 00000000000..026c77af706 --- /dev/null +++ b/PWGUD/Core/decayTree.cxx @@ -0,0 +1,1220 @@ +// 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. + +#include +#include +#include +#include +#include + +#include "rapidjson/document.h" +#include "rapidjson/filereadstream.h" +#include "decayTree.h" + +using namespace rapidjson; + +// ----------------------------------------------------------------------------- +// pidSelector holds an array of pidcut +// pidcut +// double[8] +// 0: pid to apply +// 1: detector: 1 - TPC, 2 - TOF +// 2: cut type: +// 1: pt and nSigma within limits +// -1: nSigma out of limits within pt range +// 2: pt and detector signal within limits +// -2: detector signal out of limits within pt range +// 3: How to apply cut: +// 0: not active +// 1: if information available +// 2: return false if information not available +// 4: pT min +// 5: pT max +// 6: signal/nSigma min +// 7: signal/nSigma max +// pidSelector +pidSelector::pidSelector(std::vector>& pidcuts) +{ + fpidCuts = pidcuts; +} + +void pidSelector::clear() +{ + fpidCuts.clear(); +} + +int pidSelector::pid2ind(int pid) +{ + switch (std::abs(pid)) { + case 11: // electron + return 0; + case 211: // pion + return 1; + case 13: // muon + return 2; + case 321: // kaon + return 3; + case 2212: // proton + return 4; + default: // unknown + return -1.; + } +}; + +void pidSelector::Print() +{ + LOGF(info, " PID cuts"); + for (const auto& cut : fpidCuts) { + LOGF(info, " [ %.0f %.0f %.0f %.0f %.0f %.2f %.2f %.2f ]", cut[0], cut[1], cut[2], cut[3], cut[4], cut[5], cut[6], cut[7]); + } +} + +// ----------------------------------------------------------------------------- +// angleCut +angleCut::angleCut(std::pair rnames, double angleMin, double angleMax) +{ + fRnames = rnames; + fAngleMin = angleMin; + fAngleMax = angleMax; +} + +void angleCut::Print() +{ + LOGF(info, " %s ^ %s: %f : %f", fRnames.first, fRnames.second, fAngleMin, fAngleMax); +} + +// ----------------------------------------------------------------------------- +// Resonance +resonance::resonance() +{ + init(); +} + +// reset to default values +void resonance::init() +{ + // initialisations + fisFinal = false; + fCounter = -1; + fName = ""; + fStatus = 0; + fPID = 0; + fPIDfun = 0; + fdetectorHits = std::vector{-1, -1, -1, -1}; + fParents.clear(); + fDaughters.clear(); + + // initialize mass, pT, eta range + setMassRange(0., 100.); + setPtRange(0., 100.); + setEtaRange(-10., 10.); + setNcltpcRange(0, 200); + setChi2ncltpcRange(0., 100.); + setDCAxyzMax(100., 100.); + + // histogram axes + fnmassBins = 350; + fmassHistMin = 0.0; + fmassHistMax = 3.5; + fnmomBins = 300; + fmomHistMin = 0.0; + fmomHistMax = 3.0; + + // invariant mass + fIVM = TLorentzVector(0., 0., 0., 0.); + fCharge = 0; + + // pid cuts + fpidSelector.clear(); + fangleCuts.clear(); +} + +void resonance::reset() +{ + fStatus = 0; +} + +// check mass, pt, eta range and charge +void resonance::updateStatus() +{ + // IVM has to be computed + if (fStatus == 0) { + return; + } + + // check mass, pt, and eta range + fStatus = 2; + if (fIVM.M() < fmassMin || fIVM.M() > fmassMax) { + return; + } + if (fIVM.Perp() < fptMin || fIVM.Perp() > fptMax) { + return; + } + if (fIVM.Eta() < fetaMin || fIVM.Eta() > fetaMax) { + return; + } + + // good candidate + fStatus = 3; +} + +void resonance::Print() +{ + if (fisFinal) { + // final + LOGF(info, " %s : %d", fName, fPID); + LOGF(info, " status: %d", fStatus); + LOGF(info, " final: %d", fCounter); + LOGF(info, " nCluster TPC: %d : %d", fncltpcMin, fncltpcMax); + LOGF(info, " chi2 per cluster TPC: %f : %f", fchi2ncltpcMin, fchi2ncltpcMax); + LOGF(info, " maximum dca_XY : %f", fdcaxyMax); + LOGF(info, " maximum dca_Z: %f", fdcazMax); + LOGF(info, " parents"); + for (const auto& parent : fParents) { + LOGF(info, " %s", parent); + } + } else { + // resonance + LOGF(info, " %s", fName); + LOGF(info, " status: %d", fStatus); + LOGF(info, " parents"); + for (const auto& parent : fParents) { + LOGF(info, " %s", parent); + } + LOGF(info, " daughters"); + for (const auto& daugh : fDaughters) { + LOGF(info, " %s", daugh); + } + } + LOGF(info, " mass range: %f : %f", fmassMin, fmassMax); + LOGF(info, " pt range: %f : %f", fptMin, fptMax); + LOGF(info, " eta range: %f : %f", fetaMin, fetaMax); + if (fisFinal) { + fpidSelector.Print(); + } else { + LOGF(info, " Angle cuts"); + for (const auto& anglecut : fangleCuts) { + anglecut->Print(); + } + } + + if (fStatus > 0) { + LOGF(info, " charge: %d", fCharge); + LOGF(info, " mass: %f", fIVM.M()); + LOGF(info, " E: %f", fIVM.E()); + LOGF(info, " pT: %f", fIVM.Perp()); + LOGF(info, " eta: %f", fIVM.Eta()); + } + LOGF(info, ""); +} + +// ----------------------------------------------------------------------------- +// decayTree +decayTree::decayTree() +{ + fPDG = TDatabasePDG::Instance(); +} + +bool decayTree::init(std::string const& parFile, o2::framework::HistogramRegistry& registry) +{ + // initialisation of constants + fccs = {"ULS", "LS"}; + fdets = {"TPC", "TOF"}; + fparts = {"el", "pi", "mu", "ka", "pr"}; + + // open the decayTree file + FILE* fjson = fopen(parFile.c_str(), "r"); + if (!fjson) { + LOGF(error, "Could not open parameter file %s", parFile); + return false; + } + + // create streamer + char readBuffer[65536]; + FileReadStream jsonStream(fjson, readBuffer, sizeof(readBuffer)); + + // parse the json file + Document jsonDocument; + jsonDocument.ParseStream(jsonStream); + + // is it a proper json document? + if (jsonDocument.HasParseError()) { + LOGF(error, "Check the parameter file! There is a problem with the format!"); + return false; + } + + // check for decayTree + const char* itemName = "decayTree"; + if (!jsonDocument.HasMember(itemName)) { + LOGF(error, "Check the parameter file! Item %s is missing!", itemName); + return false; + } + const Value& decTree = jsonDocument[itemName]; + + // finals and resonance parameters + std::string name; + int pid; + int pidfun; + std::vector daughters; + std::vector charges; + std::vector> vcuts; + std::vector vanglecuts; + + itemName = "finals"; + if (!decTree.HasMember(itemName)) { + LOGF(info, "No %s defined!", itemName); + return false; + } + if (!decTree[itemName].IsArray()) { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + return false; + } + + // loop over finals + fnFinals = 0; + auto fins = decTree[itemName].GetArray(); + for (const auto& fin : fins) { + if (!fin.IsObject()) { + LOGF(error, "Check the parameter file! %s must be objects!", itemName); + return false; + } + + // create new finals (resonance) + resonance* newRes = new resonance(); + newRes->setisFinal(); + + // check for name + itemName = "name"; + if (fin.HasMember(itemName)) { + if (fin[itemName].IsString()) { + name = fin[itemName].GetString(); + newRes->setName(name); + } else { + LOGF(error, "Check the parameter file! %s must be a string!", itemName); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Finals must have a %s!", itemName); + delete newRes; + return false; + } + + // check for pid + itemName = "pid"; + if (fin.HasMember(itemName)) { + pid = fin[itemName].GetInt(); + newRes->setPID(pid); + } else { + LOGF(error, "Check the parameter file! Finals must have a %s!", itemName); + delete newRes; + return false; + } + + // check for ptrange + itemName = "ptrange"; + if (fin.HasMember(itemName)) { + if (fin[itemName].IsArray()) { + auto lims = fin[itemName].GetArray(); + if (lims.Size() == 2) { + newRes->setPtRange(lims[0].GetFloat(), lims[1].GetFloat()); + } else { + LOGF(error, "Check the parameter file! %s must have two elements!", itemName); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + delete newRes; + return false; + } + } + + // check for etarange + itemName = "etarange"; + if (fin.HasMember(itemName)) { + if (fin[itemName].IsArray()) { + auto lims = fin[itemName].GetArray(); + if (lims.Size() == 2) { + newRes->setEtaRange(lims[0].GetFloat(), lims[1].GetFloat()); + } else { + LOGF(error, "Check the parameter file! %s must have two elements!", itemName); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + delete newRes; + return false; + } + } + + // check for detectorhits + // 0: ITS + // 1: TPC + // 2: TRD + // 3: TOF + itemName = "detectorhits"; + if (fin.HasMember(itemName)) { + if (fin[itemName].IsArray()) { + auto hits = fin[itemName].GetArray(); + if (hits.Size() == 4) { + newRes->setDetectorHits(hits[0].GetInt(), hits[1].GetInt(), hits[2].GetInt(), hits[3].GetInt()); + } else { + LOGF(error, "Check the parameter file! %s must have four elements!", itemName); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + delete newRes; + return false; + } + } + + // check for ncltpcrange + itemName = "ncltpcrange"; + if (fin.HasMember(itemName)) { + if (fin[itemName].IsArray()) { + auto lims = fin[itemName].GetArray(); + if (lims.Size() == 2) { + newRes->setNcltpcRange(lims[0].GetFloat(), lims[1].GetFloat()); + } else { + LOGF(error, "Check the parameter file! %s must have two elements!", itemName); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + delete newRes; + return false; + } + } + + // check for chi2ncltpcrange + itemName = "chi2ncltpcrange"; + if (fin.HasMember(itemName)) { + if (fin[itemName].IsArray()) { + auto lims = fin[itemName].GetArray(); + if (lims.Size() == 2) { + newRes->setChi2ncltpcRange(lims[0].GetFloat(), lims[1].GetFloat()); + } else { + LOGF(error, "Check the parameter file! %s must have two elements!", itemName); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + delete newRes; + return false; + } + } + + // check for dcaxyzmax + itemName = "dcaxyzmax"; + if (fin.HasMember(itemName)) { + if (fin[itemName].IsArray()) { + auto lims = fin[itemName].GetArray(); + if (lims.Size() == 2) { + newRes->setDCAxyzMax(lims[0].GetFloat(), lims[1].GetFloat()); + } else { + LOGF(error, "Check the parameter file! %s must have two elements!", itemName); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + delete newRes; + return false; + } + } + + // pid cuts + vcuts.clear(); + itemName = "pidcuts"; + if (fin.HasMember(itemName)) { + if (fin[itemName].IsArray()) { + auto pidcuts = fin[itemName].GetArray(); + for (const auto& pidcut : pidcuts) { + if (pidcut.HasMember("pidcut")) { + if (pidcut["pidcut"].IsArray()) { + auto vals = pidcut["pidcut"].GetArray(); + if (vals.Size() == 8) { + std::vector vs; + for (const auto& val : vals) { + vs.push_back(val.GetFloat()); + } + vcuts.push_back(vs); + } else { + LOGF(error, "Check the parameter file! A pidcut has %d members", vals.Size()); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Item pidcuts['pidcut'] must be an array!"); + delete newRes; + return false; + } + } + } + auto pidsel = pidSelector(vcuts); + newRes->setPIDSelector(pidsel); + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + delete newRes; + return false; + } + } + + // check for massaxis + itemName = "massaxis"; + if (fin.HasMember(itemName)) { + if (fin[itemName].IsArray()) { + auto max = fin[itemName].GetArray(); + if (max.Size() == 3) { + newRes->setMassHistAxis(max[0].GetInt(), max[1].GetFloat(), max[2].GetFloat()); + } else { + LOGF(error, "Check the parameter file! %s must have three elements!", itemName); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + delete newRes; + return false; + } + } + + // check for momaxis + itemName = "momaxis"; + if (fin.HasMember(itemName)) { + if (fin[itemName].IsArray()) { + auto momax = fin[itemName].GetArray(); + if (momax.Size() == 3) { + newRes->setMomHistAxis(momax[0].GetInt(), momax[1].GetFloat(), momax[2].GetFloat()); + } else { + LOGF(error, "Check the parameter file! %s must have three elements!", itemName); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + delete newRes; + return false; + } + } + + // update fResonances + fnFinals++; + newRes->setCounter(fnFinals - 1); + fResonances.push_back(newRes); + } + + itemName = "ulsstates"; + if (decTree.HasMember(itemName)) { + LOGF(info, "No %s defined!", itemName); + if (!decTree[itemName].IsArray()) { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + return false; + } + auto ulsstates = decTree[itemName].GetArray(); + for (const auto& obj : ulsstates) { + if (obj.IsArray()) { + auto ulsstate = obj.GetArray(); + if (static_cast(ulsstate.Size()) != fnFinals) { + LOGF(error, "%s with wrong number of elements!", itemName); + return false; + } + charges.clear(); + for (const auto& ch : ulsstate) { + charges.push_back(ch.GetInt()); + } + LOGF(info, "adding charge state %d", chargeState(charges)); + fULSstates.push_back(chargeState(charges)); + } else { + LOGF(error, "Check the parameter file! Elements of item %s must be arrays!", itemName); + return false; + } + } + } + + itemName = "lsstates"; + if (decTree.HasMember(itemName)) { + LOGF(info, "No %s defined!", itemName); + if (!decTree[itemName].IsArray()) { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + return false; + } + auto lsstates = decTree[itemName].GetArray(); + for (const auto& obj : lsstates) { + if (obj.IsArray()) { + auto lsstate = obj.GetArray(); + if (static_cast(lsstate.Size()) != fnFinals) { + LOGF(error, "%s with wrong number of elements!", itemName); + return false; + } + charges.clear(); + for (const auto& ch : lsstate) { + charges.push_back(ch.GetInt()); + } + fLSstates.push_back(chargeState(charges)); + } else { + LOGF(error, "Check the parameter file! Elements of item %s must be arrays!", itemName); + return false; + } + } + } + + // update permutations + permutations(fnFinals, fPermutations); + + itemName = "resonances"; + if (!decTree.HasMember(itemName)) { + LOGF(info, "No resonances defined!"); + } else { + if (!decTree[itemName].IsArray()) { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + return false; + } + + // loop over resonances + auto ress = decTree[itemName].GetArray(); + for (const auto& res : ress) { + if (!res.IsObject()) { + LOGF(error, "Check the parameter file! %s must be objects!", itemName); + return false; + } + + // create new resonance + resonance* newRes = new resonance(); + + // check for name + itemName = "name"; + if (res.HasMember(itemName)) { + if (res[itemName].IsString()) { + name = res[itemName].GetString(); + newRes->setName(name); + } else { + LOGF(error, "Check the parameter file! %s must be a string!", itemName); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Resonances must have a name!"); + delete newRes; + return false; + } + + // check for daughters + itemName = "daughters"; + if (res.HasMember(itemName)) { + if (res[itemName].IsArray()) { + auto daughs = res[itemName].GetArray(); + if (daughs.Size() >= 2) { + daughters.clear(); + for (const auto& daugh : daughs) { + daughters.push_back(daugh.GetString()); + } + newRes->setDaughters(daughters); + } else { + LOGF(error, "Check the parameter file! %s must have at least two elements!", itemName); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Resonances must have daughters!"); + delete newRes; + return false; + } + + // check for massrange + itemName = "massrange"; + if (res.HasMember(itemName)) { + if (res[itemName].IsArray()) { + auto lims = res[itemName].GetArray(); + if (lims.Size() != 2) { + LOGF(error, "Check the parameter file! %s must have two elements!", itemName); + delete newRes; + return false; + } + newRes->setMassRange(lims[0].GetFloat(), lims[1].GetFloat()); + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + delete newRes; + return false; + } + } + + // check for ptrange + itemName = "ptrange"; + if (res.HasMember(itemName)) { + if (res[itemName].IsArray()) { + auto lims = res[itemName].GetArray(); + if (lims.Size() == 2) { + newRes->setPtRange(lims[0].GetFloat(), lims[1].GetFloat()); + } else { + LOGF(error, "Check the parameter file! %s must have two elements!", itemName); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + delete newRes; + return false; + } + } + + // check for etarange + itemName = "etarange"; + if (res.HasMember(itemName)) { + if (res[itemName].IsArray()) { + auto lims = res[itemName].GetArray(); + if (lims.Size() == 2) { + newRes->setEtaRange(lims[0].GetFloat(), lims[1].GetFloat()); + } else { + LOGF(error, "Check the parameter file! %s must have two elements!", itemName); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + delete newRes; + return false; + } + } + + // check for pidfun + itemName = "pidfun"; + if (res.HasMember(itemName)) { + pidfun = res[itemName].GetInt(); + newRes->setPIDFun(pidfun); + } + + // angle cuts + vanglecuts.clear(); + itemName = "anglecuts"; + if (res.HasMember(itemName)) { + if (res[itemName].IsArray()) { + auto anglecuts = res[itemName].GetArray(); + for (const auto& anglecut : anglecuts) { + if (anglecut.HasMember("pair")) { + if (anglecut["pair"].IsArray()) { + auto daughters = anglecut["pair"].GetArray(); + if (daughters.Size() == 2) { + std::pair pair{daughters[0].GetString(), daughters[1].GetString()}; + if (anglecut.HasMember("anglerange")) { + if (anglecut["anglerange"].IsArray()) { + auto arange = anglecut["anglerange"].GetArray(); + if (arange.Size() == 2) { + vanglecuts.push_back(new angleCut(pair, arange[0].GetFloat(), arange[1].GetFloat())); + } else { + LOGF(error, "Check the parameter file! An anglecut['anglerange'] has %d members", arange.Size()); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Item anglerange must be an array!"); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! An anglecut must have an anglerange!"); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! A anglecut['pair'] has %d members", daughters.Size()); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Item anglecut must be an array!"); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! An anglecut must have a pair!"); + delete newRes; + return false; + } + } + newRes->setAngleCuts(vanglecuts); + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + delete newRes; + return false; + } + } + + // check for massaxis + itemName = "massaxis"; + if (res.HasMember(itemName)) { + if (res[itemName].IsArray()) { + auto max = res[itemName].GetArray(); + if (max.Size() == 3) { + newRes->setMassHistAxis(max[0].GetInt(), max[1].GetFloat(), max[2].GetFloat()); + } else { + LOGF(error, "Check the parameter file! %s must have three elements!", itemName); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + delete newRes; + return false; + } + } + + // check for momaxis + itemName = "momaxis"; + if (res.HasMember(itemName)) { + if (res[itemName].IsArray()) { + auto momax = res[itemName].GetArray(); + if (momax.Size() == 3) { + newRes->setMomHistAxis(momax[0].GetInt(), momax[1].GetFloat(), momax[2].GetFloat()); + } else { + LOGF(error, "Check the parameter file! %s must have three elements!", itemName); + delete newRes; + return false; + } + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + delete newRes; + return false; + } + } + + // use the items to create a new resonance + fResonances.push_back(newRes); + } + } + + // update the parents information + updateParents(); + + // check for eventCuts + // set default values + fnTracksMin = fnFinals; + fnTracksMax = fnFinals; + frgtwtofMin = 0.0; + fdBCMin = 0; + fdBCMax = 0; + fFITvetos = {0, 1, 1, 0, 0}; + + itemName = "eventCuts"; + if (!jsonDocument.HasMember(itemName)) { + return true; + } + const Value& evset = jsonDocument[itemName]; + + // check for ntrackrange + itemName = "ntrackrange"; + if (evset.HasMember(itemName)) { + if (evset[itemName].IsArray()) { + auto lims = evset[itemName].GetArray(); + if (lims.Size() == 2) { + fnTracksMin = lims[0].GetFloat(); + fnTracksMax = lims[1].GetFloat(); + } else { + LOGF(error, "Check the parameter file! %s must have two elements!", itemName); + return false; + } + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + return false; + } + } + + // check for rgtwtofmin + itemName = "rgtrwtofmin"; + if (evset.HasMember(itemName)) { + frgtwtofMin = evset[itemName].GetFloat(); + } + + // check for dBCrange + itemName = "dBCrange"; + if (evset.HasMember(itemName)) { + if (evset[itemName].IsArray()) { + auto lims = evset[itemName].GetArray(); + if (lims.Size() == 2) { + fdBCMin = lims[0].GetInt(); + fdBCMax = lims[1].GetInt(); + } else { + LOGF(error, "Check the parameter file! %s must have two elements!", itemName); + return false; + } + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + return false; + } + } + + // check for FITvetos + itemName = "FITvetos"; + if (evset.HasMember(itemName)) { + if (evset[itemName].IsArray()) { + auto vetoes = evset[itemName].GetArray(); + if (vetoes.Size() == 5) { + fFITvetos.clear(); + for (auto i = 0; i < 5; i++) { + fFITvetos.push_back(vetoes[i].GetInt()); + } + } else { + LOGF(error, "Check the parameter file! %s must have five elements!", itemName); + return false; + } + } else { + LOGF(error, "Check the parameter file! Item %s must be an array!", itemName); + return false; + } + } + + // clean up + fclose(fjson); + + // create the histograms + createHistograms(registry); + + return true; +} + +void decayTree::updateParents() +{ + // reset parents + for (const auto& res : fResonances) { + res->clearParents(); + } + + for (const auto& res : fResonances) { + for (const auto& daughName : res->getDaughters()) { + auto daugh = getResonance(daughName); + daugh->addParent(res->name()); + } + } +} + +void decayTree::reset() +{ + fStatus = 0; + fChargeState = -1; + for (const auto& res : fResonances) { + res->reset(); + } +} + +// decayTree status +// 0: unset +// 1: not accepted +// 2: ULS accepted +// 3: LS accepted +void decayTree::updateStatus() +{ + bool isULS = true; + bool isLS = true; + fStatus = 1; + for (const auto& res : fResonances) { + if (res->status() < 3) { + return; + } + + // check the charge state + updateChargeState(); + if (std::find(fULSstates.begin(), fULSstates.end(), fChargeState) == fULSstates.end()) { + isULS = false; + } + if (std::find(fLSstates.begin(), fLSstates.end(), fChargeState) == fLSstates.end()) { + isLS = false; + } + } + if (isULS) { + fStatus = 2; + } else if (isLS) { + fStatus = 3; + } +} + +void decayTree::Print() +{ + LOGF(info, "eventCuts"); + LOGF(info, " ntrkRange: %d : %d", fnTracksMin, fnTracksMax); + LOGF(info, " dBCRange: %d : %d", fdBCMin, fdBCMax); + LOGF(info, " FITVetoes: [ %d %d %d %d %d ]", fFITvetos[0], fFITvetos[1], fFITvetos[2], fFITvetos[3], fFITvetos[4]); + LOGF(info, " ULS states"); + for (const auto& chstat : fULSstates) { + LOGF(info, " %d", chstat); + } + LOGF(info, " LS states"); + for (const auto& chstat : fLSstates) { + LOGF(info, " %d", chstat); + } + LOGF(info, ""); + LOGF(info, "decayTree"); + LOGF(info, " nResonances: %d", fResonances.size()); + LOGF(info, " nFinals: %d", fnFinals); + LOGF(info, " Resonances"); + for (const auto& res : fResonances) { + res->Print(); + } +} + +resonance* decayTree::getResonance(std::string name) +{ + for (const auto& res : fResonances) { + if (res->name() == name) { + return res; + } + } + LOGF(error, "A resonance %s does not exists!", name); + return new resonance(); // is needed to satisfy return type +} + +resonance* decayTree::getFinal(int counter) +{ + for (const auto& res : fResonances) { + if (res->counter() == counter) { + return res; + } + } + LOGF(error, "The final %d does not exists!", counter); + return new resonance(); // is needed to satisfy return type +} + +std::vector decayTree::getFinals(resonance* res) +{ + std::vector resFinals; + + for (const auto& d1Name : res->getDaughters()) { + auto d1 = getResonance(d1Name); + if (d1->isFinal()) { + resFinals.push_back(d1); + } else { + for (const auto& d2Name : d1->getDaughters()) { + auto d2 = getResonance(d2Name); + for (const auto& d3 : getFinals(d2)) { + resFinals.push_back(d3); + } + } + } + } + return resFinals; +} + +// apply anglecuts +void decayTree::checkAngles() +{ + // loop over resonances + for (const auto& res : fResonances) { + auto anglecuts = res->getAngleCuts(); + // loop over angle cuts + for (const auto& anglecut : anglecuts) { + auto rnames = anglecut->rNames(); + auto anglerange = anglecut->angleRange(); + + // compute angle between two resonances + auto lv1 = getResonance(rnames.first)->IVM(); + auto lv2 = getResonance(rnames.second)->IVM(); + auto ang = lv1.Angle(lv2.Vect()); + + // apply cut + if (ang < anglerange.first || ang > anglerange.second) { + res->setStatus(2); + break; + } + } + } +} + +// compute charge state +int decayTree::chargeState(std::vector chs) +{ + int chargeState = -1; + if (static_cast(chs.size()) == fnFinals) { + // loop over elements of chargestate + chargeState = 0; + for (auto ind = 0; ind < fnFinals; ind++) { + chargeState += (chs[ind] > 0) * std::pow(2, ind); + } + } + return chargeState; +} +void decayTree::updateChargeState() +{ + fChargeState = 0; + + // loop over all finals + for (auto ind = 0; ind < fnFinals; ind++) { + fChargeState += (getFinal(ind)->charge() > 0) * std::pow(2, ind); + } +} + +std::size_t decayTree::combHash(std::vector& comb) +{ + // comb contains indices to tracks + // the combination hash is created from a string which is comprised of a sorted list of track indices + + // sort comb + std::map m_unsorted; + for (size_t cnt = 0; cnt < comb.size(); cnt++) { + m_unsorted.insert(std::pair(comb[cnt], cnt)); + } + std::vector v_sorted(comb.size()); + partial_sort_copy(begin(comb), end(comb), begin(v_sorted), end(v_sorted)); + + // create the hash + std::hash hasher; + std::string hashstr{""}; + for (size_t cnt = 0; cnt < comb.size(); cnt++) { + hashstr += std::to_string(v_sorted[cnt]); + } + + return hasher(hashstr); +} + +// find all permutations of n0 elements +void decayTree::permutations(std::vector& ref, int n0, int np, std::vector>& perms) +{ + // create local reference + auto ref2u = ref; + + // loop over np-1 rotations of last np elements of ref + for (auto ii = 0; ii < np; ii++) { + + // create a new permutation + // copy first n0-np elements from ref + // then rotate last np elements of ref + std::vector perm(n0, 0); + for (auto ii = 0; ii < n0 - np; ii++) { + perm[ii] = ref2u[ii]; + } + for (auto ii = n0 - np + 1; ii < n0; ii++) { + perm[ii - 1] = ref2u[ii]; + } + perm[n0 - 1] = ref2u[n0 - np]; + + // add new permutation to the list of permuutations + if (ii < (np - 1)) { + perms.push_back(perm); + } + + // if np>2 then do permutation of next level + // use the new combination as reference + if (np > 2) { + auto newnp = np - 1; + permutations(perm, n0, newnp, perms); + } + + // update reference + ref2u = perm; + } +} + +// find all permutations of n0 elements +int decayTree::permutations(int n0, std::vector>& perms) +{ + // initialize with first trivial combination + perms.clear(); + if (n0 == 0) { + return 0; + } + + std::vector ref(n0, 0); + for (auto ii = 0; ii < n0; ii++) { + ref[ii] = ii; + } + perms.push_back(ref); + + // iterate recursively + permutations(ref, n0, n0, perms); + + return perms.size(); +} + +void decayTree::combinations(int n0, std::vector& pool, int np, std::vector& inds, int n, + std::vector>& combs) +{ + // loop over pool + for (auto ii = 0; ii < n0 - n; ii++) { + + inds[n] = pool[ii]; + + // if all inds are defined then print them out + // else get next inds + if (np == 1) { + + std::vector comb(n + 1, 0); + for (uint ii = 0; ii < inds.size(); ii++) { + comb[ii] = inds[ii]; + } + combs.push_back(comb); + + } else { + + auto n0new = n0 - ii; + std::vector newpool(n0new, 0); + for (auto kk = 0; kk < n0new; kk++) { + newpool[kk] = pool[kk + ii + 1]; + } + + auto npnew = np - 1; + auto nnew = n + 1; + combinations(n0new, newpool, npnew, inds, nnew, combs); + } + } +} + +// find all possible selections of np out of n0 +int decayTree::combinations(int n0, int np, std::vector>& combs) +{ + // initialisations + combs.clear(); + if (n0 < np) { + return 0; + } + + std::vector pool(n0, 0); + for (auto ii = 0; ii < n0; ii++) { + pool[ii] = ii; + } + std::vector inds(np, 0); + + // iterate recursively + combinations(n0, pool, np, inds, 0, combs); + + return combs.size(); +} + +std::vector> decayTree::combinations(int nPool) +{ + // all selections of fnFinals items from nPool elements + std::vector> combs; + combinations(nPool, fnFinals, combs); + + // permute the combinations + std::vector> copes; + for (const auto& comb : combs) { + for (const auto& perm : fPermutations) { + std::vector cope(fnFinals, 0); + for (auto jj = 0; jj < fnFinals; jj++) { + cope[perm[jj]] = comb[jj]; + } + copes.push_back(cope); + } + } + + return copes; +} + +// ----------------------------------------------------------------------------- diff --git a/PWGUD/Core/decayTree.h b/PWGUD/Core/decayTree.h new file mode 100644 index 00000000000..3dd4f53578b --- /dev/null +++ b/PWGUD/Core/decayTree.h @@ -0,0 +1,999 @@ +// 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. + +#ifndef PWGUD_CORE_DECAYTREE_H_ +#define PWGUD_CORE_DECAYTREE_H_ + +#include +#include +#include +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/Logger.h" +#include "TLorentzVector.h" +#include "TDatabasePDG.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// ----------------------------------------------------------------------------- +class pidSelector +{ + public: + // constructor/destructor + pidSelector() {} + explicit pidSelector(std::vector>& pidcuts); + ~pidSelector() {} + + // setter + void clear(); + + // getters + void Print(); + + // templated functions + template + double getTPCnSigma(TTs track, int pid) + { + auto hypo = pid2ind(pid); + switch (hypo) { + case 0: + return track.tpcNSigmaEl(); + case 1: + return track.tpcNSigmaPi(); + case 2: + return track.tpcNSigmaMu(); + case 3: + return track.tpcNSigmaKa(); + case 4: + return track.tpcNSigmaPr(); + default: + return 0.; + } + }; + + template + double getTOFnSigma(TTs track, int pid) + { + auto hypo = pid2ind(pid); + switch (hypo) { + case 0: + return track.tofNSigmaEl(); + case 1: + return track.tofNSigmaPi(); + case 2: + return track.tofNSigmaMu(); + case 3: + return track.tofNSigmaKa(); + case 4: + return track.tofNSigmaPr(); + default: + return 0.; + } + }; + + template + bool goodTrack(TTs track) + { + // loop over pidcuts + for (const auto& pidcut : fpidCuts) { + + float mom = 0.; + float detValue = 0.; + if (pidcut[1] == 1) { + // TPC + if (track.hasTPC()) { + mom = track.tpcInnerParam(); + if (mom < pidcut[4] || mom > pidcut[5]) { + // not in relevant momentum range + continue; + } + if (std::abs(pidcut[2]) == 1) { + // nSigma + detValue = getTPCnSigma(track, pidcut[0]); + } else { + // signal + detValue = track.tpcSignal(); + } + } else { + if (pidcut[3] == 2) { + // TPC is required + return false; + } else { + continue; + } + } + } else { + // TOF + if (track.hasTOF()) { + mom = track.tofExpMom(); + if (mom < pidcut[4] || mom > pidcut[5]) { + // not in relevant momentum range + continue; + } + if (std::abs(pidcut[2]) == 1) { + // nSigma + detValue = getTOFnSigma(track, pidcut[0]); + } else { + // signal + detValue = track.tofSignal(); + } + } else { + if (pidcut[3] == 2) { + // TOF is required + return false; + } else { + continue; + } + } + } + + // inclusive / exclusive + if (pidcut[2] > 0 && (detValue < pidcut[6] || detValue > pidcut[7])) { + return false; + } else if (pidcut[2] < 0 && (detValue > pidcut[6] && detValue < pidcut[7])) { + return false; + } + } + + // the track is good if we arrive here + return true; + } + + private: + std::vector> fpidCuts; + int pid2ind(int pid); + + // ClassDefNV(pidSelector, 1); +}; + +// ----------------------------------------------------------------------------- +class angleCut +{ + public: + // constructor/destructor + angleCut() {} + explicit angleCut(std::pair rNames, double angleMin, double angleMax); + ~angleCut() {} + + std::pair rNames() { return fRnames; } + std::pair angleRange() { return std::pair{fAngleMin, fAngleMax}; } + + void Print(); + + private: + std::pair fRnames; + double fAngleMin; + double fAngleMax; + + // ClassDefNV(angleCut, 1); +}; + +// ----------------------------------------------------------------------------- +class reconstructedParticle +{ + public: + // constructor/destructor + reconstructedParticle() {} + explicit reconstructedParticle(std::string name, TLorentzVector ivm, std::vector& comb) + { + fName = name; + fIVM = ivm; + fComb = comb; + }; + ~reconstructedParticle() {} + + std::string name() { return fName; } + TLorentzVector lv() { return fIVM; } + std::vector comb() { return fComb; } + + private: + std::string fName; + TLorentzVector fIVM; + std::vector fComb; +}; + +using recResType = std::vector>; + +class reconstructedEvent +{ + public: + // constructor/destructor + reconstructedEvent() {} + explicit reconstructedEvent(recResType recs, int chargeState, std::vector& comb) + { + fRecs = recs; + fComb = comb; + fChargeState = chargeState; + }; + ~reconstructedEvent() {} + + recResType recResonances() { return fRecs; } + std::vector comb() { return fComb; } + + private: + recResType fRecs; + std::vector fComb; + int fChargeState; +}; + +using decayTreeResType = std::map; + +// ----------------------------------------------------------------------------- +class resonance +{ + public: + // constructor/destructor + resonance(); + ~resonance() {} + + // setters + void init(); + void reset(); + + void setisFinal() { fisFinal = true; } + void setCounter(int counter) { fCounter = counter; } + void setName(std::string name) { fName = name; } + void setStatus(int status) { fStatus = status; } + void setPID(int pid) { fPID = pid; } + void setPIDFun(int pidfun) { fPIDfun = pidfun; } + void setDetectorHits(int its, int tpc, int trd, int tof) + { + fdetectorHits = std::vector{its, tpc, trd, tof}; + } + void clearParents() { fParents.clear(); } + void addParent(std::string parent) { fParents.push_back(parent); } + void setDaughters(std::vector& daughters) { fDaughters = daughters; } + void setIVM(TLorentzVector ivm) + { + fIVM = ivm; + fStatus = 1; + } + void setCharge(int charge) { fCharge = charge; } + + // selections + void setMassRange(double mmin, double mmax) + { + fmassMin = mmin; + fmassMax = mmax; + } + void setPtRange(double ptmin, double ptmax) + { + fptMin = ptmin; + fptMax = ptmax; + } + void setEtaRange(double etamin, double etamax) + { + fetaMin = etamin; + fetaMax = etamax; + } + void setNcltpcRange(int ncltpcmin, int ncltpcmax) + { + fncltpcMin = ncltpcmin; + fncltpcMax = ncltpcmax; + } + void setChi2ncltpcRange(double chi2ncltpcmin, double chi2ncltpcmax) + { + fchi2ncltpcMin = chi2ncltpcmin; + fchi2ncltpcMax = chi2ncltpcmax; + } + void setDCAxyzMax(double dcaxymax, double dcazmax) + { + fdcaxyMax = dcaxymax; + fdcazMax = dcazmax; + } + void setPIDSelector(pidSelector pidcuts) { fpidSelector = pidcuts; } + void setAngleCuts(std::vector anglecuts) { fangleCuts = anglecuts; } + + // histograms + void setMassHistAxis(int nbins, double binmin, double binmax) + { + fnmassBins = nbins; + fmassHistMin = binmin; + fmassHistMax = binmax; + } + void setMomHistAxis(int nbins, double binmin, double binmax) + { + fnmomBins = nbins; + fmomHistMin = binmin; + fmomHistMax = binmax; + } + void updateStatus(); + + // getters + bool isFinal() { return fisFinal; } + int counter() { return fCounter; } + std::string name() { return fName; } + int status() { return fStatus; } + int pid() { return fPID; } + int pidFun() { return fPIDfun; } + std::vector detectorHits() { return fdetectorHits; } + std::vector getParents() { return fParents; } + std::vector getDaughters() { return fDaughters; } + double massMin() { return fmassMin; } + double massMax() { return fmassMax; } + double ptMin() { return fptMin; } + double ptMax() { return fptMax; } + double etaMin() { return fetaMin; } + double etaMax() { return fetaMax; } + TLorentzVector IVM() { return fIVM; } + int charge() { return fCharge; } + pidSelector getPIDSelector() { return fpidSelector; } + std::vector getAngleCuts() { return fangleCuts; } + + // histograms + int nmassBins() { return fnmassBins; } + std::vector massHistRange() { return std::vector({fmassHistMin, fmassHistMax}); } + int nmomBins() { return fnmomBins; } + std::vector momHistRange() { return std::vector({fmomHistMin, fmomHistMax}); } + + void Print(); + + // templated functions + // resonance status + // 0: unset + // 1: IVM calculated + // 2: not accepted + // 3: accepted + template + void updateStatus(TTs const& track) + { + // IVM has to be computed + if (fStatus == 0) { + return; + } + + // check mass, pt, eta range and charge + updateStatus(); + + // check detector hits, track cuts + if (fStatus >= 3) { + // detector hits + if (fdetectorHits[0] >= 0) { + if ((fdetectorHits[0] == 0 && track.hasITS()) || (fdetectorHits[0] > 0 && !track.hasITS())) { + fStatus = 2; + } + } + if (fdetectorHits[1] >= 0) { + if ((fdetectorHits[1] == 0 && track.hasTPC()) || (fdetectorHits[1] > 0 && !track.hasTPC())) { + fStatus = 2; + } + } + if (fdetectorHits[2] >= 0) { + if ((fdetectorHits[2] == 0 && track.hasTRD()) || (fdetectorHits[2] > 0 && !track.hasTRD())) { + fStatus = 2; + } + } + if (fdetectorHits[3] >= 0) { + if ((fdetectorHits[3] == 0 && track.hasTOF()) || (fdetectorHits[3] > 0 && !track.hasTOF())) { + fStatus = 2; + } + } + // PID cuts + if (!fpidSelector.goodTrack(track)) { + fStatus = 2; + } + // nclTPC + auto nclTPC = track.tpcNClsFindable() - track.tpcNClsFindableMinusFound(); + if (nclTPC < fncltpcMin || nclTPC > fncltpcMax) { + fStatus = 2; + } + // chi2nclTPC + if (track.tpcChi2NCl() < fchi2ncltpcMin || track.tpcChi2NCl() > fchi2ncltpcMax) { + fStatus = 2; + } + // dcaxyz + auto lim = fdcaxyMax + std::pow(0.0350 / track.pt(), 1.1); + if (std::abs(track.dcaXY()) > lim || std::abs(track.dcaZ()) > fdcazMax) { + fStatus = 2; + } + } + } + + private: + bool fisFinal; + int fCounter; + + // resonance name + std::string fName; + int fStatus; + + // nominal pid + int fPID; + int fPIDfun; + std::vector fdetectorHits; + + // name of parents and daughters + std::vector fParents; + std::vector fDaughters; + void updateParents(); + + // mass, pT, , eta range + double fmassMin; + double fmassMax; + double fptMin; + double fptMax; + double fetaMin; + double fetaMax; + int fncltpcMin; + int fncltpcMax; + double fchi2ncltpcMin; + double fchi2ncltpcMax; + double fdcaxyMax; + double fdcazMax; + + // histogram axes + int fnmassBins; + double fmassHistMax; + double fmassHistMin; + int fnmomBins; + double fmomHistMax; + double fmomHistMin; + + // invariant mass + TLorentzVector fIVM; + int fCharge; + + // pidcuts, anglecuts + pidSelector fpidSelector; + std::vector fangleCuts; + + // ClassDefNV(resonance, 1); +}; + +// ----------------------------------------------------------------------------- +class decayTree +{ + public: + // constructor/destructor + decayTree(); + ~decayTree() {} + + // setters + // read decay tree from json file + bool init(std::string const& filename, HistogramRegistry& registry); + + // reset status of all resonances to 0 + void reset(); + void updateStatus(); + + // getters + int nFinals() { return fnFinals; } + std::vector getResonances() { return fResonances; } + resonance* getResonance(std::string name); + resonance* getFinal(int counter); + std::vector getFinals(resonance* res); + std::vector ntrackRange() { return std::vector{fnTracksMin, fnTracksMax}; } + double rgtrTOFMin() { return frgtwtofMin; } + std::vector dBCRange() { return std::vector{fdBCMin, fdBCMax}; } + std::vector FITvetos() { return fFITvetos; } + + void Print(); + + template + decayTreeResType processTree(TTs const& tracks, bool withFill = true) + { + recResType ULSresults; + recResType LSresults; + + // return if nFinals > tracks.size() + if (fnFinals > tracks.size()) { + LOGF(info, "Number of tracks (%d) is smaller than the number of finals (%d)", tracks.size(), fnFinals); + return decayTreeResType{{"ULS", ULSresults}, {"LS", LSresults}}; + } + + // create all possible track combinations including permutations + auto combs = combinations(tracks.size()); + + // a vector to keep track of successful combinations + std::vector goodCombs; + + // loop over possible combinations + LOGF(debug, "New event"); + for (auto& comb : combs) { + std::string scomb(""); + for (const auto& i : comb) { + scomb.append(" ").append(std::to_string(i)); + } + LOGF(debug, " combination:%s", scomb); + + // has an equivalent combination been accepted already? + auto newHash = combHash(comb); + if (std::find(goodCombs.begin(), goodCombs.end(), newHash) != goodCombs.end()) { + LOGF(debug, " Equivalent combination is already accepted!"); + continue; + } + + // loop over resonances and compute + reset(); + for (auto res : fResonances) { + computeResonance(res, tracks, comb); + } + + // check angles between daughters of all resonances + checkAngles(); + + // check status of all resonances + updateStatus(); + if (fStatus >= 2) { + goodCombs.push_back(newHash); + std::map recResonances; + for (const auto& res : fResonances) { + recResonances.insert({res->name(), reconstructedParticle(res->name(), res->IVM(), comb)}); + } + + if (fStatus == 2) { + ULSresults.push_back(recResonances); + } else { + LSresults.push_back(recResonances); + } + } + } + auto results = decayTreeResType{{"ULS", ULSresults}, {"LS", LSresults}}; + if (withFill) { + fillHistograms(results, tracks); + } + return results; + } + +#define getHist(type, name) std::get>(fhistPointers[name]) + template + void fillHistograms(decayTreeResType results, TTs const& tracks) + { + // fill the histograms + std::string base; + std::string hname; + + // results["ULS"] contains the ULS results + // results["LS"] contains the LS results + for (const auto& cc : fccs) { + // result is a std::vector> + for (auto result : results[cc]) { + + // loop over the reconstructed particles + // rec.first: name of the reconstructed particle + // rec.second: reconstructed particle + for (auto rec : result) { + auto lv = rec.second.lv(); + base = cc; + base.append("/").append(rec.first).append("/"); + + hname = base + "mpt"; + getHist(TH2, hname)->Fill(lv.M(), lv.Perp(), 1.); + hname = base + "meta"; + getHist(TH2, hname)->Fill(lv.M(), lv.Eta(), 1.); + hname = base + "pteta"; + getHist(TH2, hname)->Fill(lv.Perp(), lv.Eta(), 1.); + + // M vs daughters + auto res = getResonance(rec.first); + auto daughs = res->getDaughters(); + auto ndaughs = daughs.size(); + for (auto i = 0; i < static_cast(ndaughs); i++) { + auto d1 = getResonance(daughs[i]); + + // M vs pT daughter + hname = base; + hname.append("MvspT_").append(rec.first).append(d1->name()); + getHist(TH2, hname)->Fill(lv.M(), result[d1->name()].lv().Perp(), 1.); + + // M vs eta daughter + hname = base; + hname.append("Mvseta_").append(rec.first).append(d1->name()); + getHist(TH2, hname)->Fill(lv.M(), result[d1->name()].lv().Eta(), 1.); + + if (d1->isFinal()) { + auto tr = tracks.begin() + result[d1->name()].comb()[d1->counter()]; + + // M vs dca + hname = base; + hname.append("MvsdcaXY_").append(rec.first).append(d1->name()); + getHist(TH2, hname)->Fill(lv.M(), tr.dcaXY(), 1.); + hname = base; + hname.append("MvsdcaZ_").append(rec.first).append(d1->name()); + getHist(TH2, hname)->Fill(lv.M(), tr.dcaZ(), 1.); + + // M vs chi2 track + hname = base; + hname.append("Mvschi2_").append(rec.first).append(d1->name()); + getHist(TH2, hname)->Fill(lv.M(), tr.tpcChi2NCl(), 1.); + + // M vs nCl track + hname = base; + hname.append("MvsnCl_").append(rec.first).append(d1->name()); + getHist(TH2, hname)->Fill(lv.M(), tr.tpcNClsFindable() - tr.tpcNClsFindableMinusFound(), 1.); + + // M versus detector hits + hname = base; + hname.append("MvsdetHits_").append(rec.first).append(d1->name()); + auto ind = tr.hasITS() + tr.hasTPC() * 2 + tr.hasTRD() * 4 + tr.hasTOF() * 8; + getHist(TH2, hname)->Fill(lv.M(), ind, 1.); + } else { + // M vs Mi + hname = base; + hname.append("MvsM_").append(rec.first).append(d1->name()); + getHist(TH2, hname)->Fill(lv.M(), result[d1->name()].lv().M(), 1.); + } + } + + // daughters vs daughters + for (auto i = 0; i < static_cast(ndaughs - 1); i++) { + auto d1 = getResonance(daughs[i]); + auto ivm1 = result[daughs[i]].lv(); + for (auto j = i + 1; j < static_cast(ndaughs); j++) { + auto d2 = getResonance(daughs[j]); + auto ivm2 = result[daughs[j]].lv(); + + // M1 vs M2 + hname = base; + hname.append("MvsM_").append(d1->name()).append(d2->name()); + getHist(TH2, hname)->Fill(ivm1.M(), ivm2.M(), 1.); + + // angle(d1, d2) + auto ang = ivm1.Angle(ivm2.Vect()); + hname = base; + hname.append("angle_").append(d1->name()).append(d2->name()); + getHist(TH1, hname)->Fill(ang, 1.); + + // M vs angle(d1, d2) + hname = base; + hname.append("Mvsangle_").append(d1->name()).append(d2->name()); + getHist(TH2, hname)->Fill(lv.M(), ang, 1.); + + // both daughters are finals + if (d1->isFinal() && d2->isFinal()) { + auto tr1 = tracks.begin() + result[d1->name()].comb()[d1->counter()]; + auto tr2 = tracks.begin() + result[d2->name()].comb()[d2->counter()]; + + // TPC signal vs TPC signal + hname = base; + hname.append("TPCsignal_").append(d1->name()).append(d2->name()); + getHist(TH2, hname)->Fill(tr1.tpcSignal(), tr2.tpcSignal(), 1.); + } + } + } + + // finals specific histograms + if (res->isFinal()) { + auto tr = tracks.begin() + rec.second.comb()[res->counter()]; + + // dca XYZ + hname = base; + hname.append("dcaXY"); + getHist(TH1, hname)->Fill(tr.dcaXY(), 1.); + hname = base; + hname.append("dcaZ"); + getHist(TH1, hname)->Fill(tr.dcaZ(), 1.); + + // TPC + hname = base; + hname.append("nS").append(fparts[0]).append(fdets[0]); + getHist(TH2, hname)->Fill(tr.tpcInnerParam(), tr.tpcNSigmaEl(), 1.); + hname = base; + hname.append("nS").append(fparts[1]).append(fdets[0]); + getHist(TH2, hname)->Fill(tr.tpcInnerParam(), tr.tpcNSigmaPi(), 1.); + hname = base; + hname.append("nS").append(fparts[2]).append(fdets[0]); + getHist(TH2, hname)->Fill(tr.tpcInnerParam(), tr.tpcNSigmaMu(), 1.); + hname = base; + hname.append("nS").append(fparts[3]).append(fdets[0]); + getHist(TH2, hname)->Fill(tr.tpcInnerParam(), tr.tpcNSigmaKa(), 1.); + hname = base; + hname.append("nS").append(fparts[4]).append(fdets[0]); + getHist(TH2, hname)->Fill(tr.tpcInnerParam(), tr.tpcNSigmaPr(), 1.); + + // TOF + if (tr.hasTOF()) { + hname = base; + hname.append("nS").append(fparts[0]).append(fdets[1]); + getHist(TH2, hname)->Fill(tr.tofExpMom(), tr.tofNSigmaEl(), 1.); + hname = base; + hname.append("nS").append(fparts[1]).append(fdets[1]); + getHist(TH2, hname)->Fill(tr.tofExpMom(), tr.tofNSigmaPi(), 1.); + hname = base; + hname.append("nS").append(fparts[2]).append(fdets[1]); + getHist(TH2, hname)->Fill(tr.tofExpMom(), tr.tofNSigmaMu(), 1.); + hname = base; + hname.append("nS").append(fparts[3]).append(fdets[1]); + getHist(TH2, hname)->Fill(tr.tofExpMom(), tr.tofNSigmaKa(), 1.); + hname = base; + hname.append("nS").append(fparts[4]).append(fdets[1]); + getHist(TH2, hname)->Fill(tr.tofExpMom(), tr.tofNSigmaPr(), 1.); + } + + // detector hits + hname = base; + hname.append("detectorHits"); + if (tr.hasITS()) { + getHist(TH1, hname)->Fill(1, 1.); + } + if (tr.hasTPC()) { + getHist(TH1, hname)->Fill(2, 1.); + } + if (tr.hasTRD()) { + getHist(TH1, hname)->Fill(3, 1.); + } + if (tr.hasTOF()) { + getHist(TH1, hname)->Fill(4, 1.); + } + } + } + } + } + } + + private: + // decayTree status + // 0: unset + // 1: not accepted + // 2: ULS accepted + // 3: LS accepted + int fStatus; + TDatabasePDG* fPDG; + + // event requierements + int fnTracksMin; + int fnTracksMax; + double frgtwtofMin; + int fdBCMin; + int fdBCMax; + std::vector fFITvetos; + std::vector fULSstates; + std::vector fLSstates; + + // vectors of Resonances + std::vector fResonances; + int fChargeState; + + // number of finals + int fnFinals; + std::vector> fPermutations; + + // histogram registry + std::vector fccs; + std::vector fdets; + std::vector fparts; + std::map fhistPointers; + + // generate parent information for all resonances + void updateParents(); + + // helper functions to compute combinations and permutations + // combination: selection of n out of N + // permutation: order of n selected items + // create all permutations of all combinations + std::size_t combHash(std::vector& comb); + void permutations(std::vector& ref, int n0, int np, std::vector>& perms); + int permutations(int n0, std::vector>& perms); + void combinations(int n0, std::vector& pool, int np, std::vector& inds, int n, + std::vector>& combs); + int combinations(int n0, int np, std::vector>& combs); + std::vector> combinations(int nPool); + + // check all angle requirements + void checkAngles(); + + // compute the charge state + int chargeState(std::vector chs); + void updateChargeState(); + + // templated functions + template + void computeResonance(resonance* res, TTs const& tracks, std::vector& comb) + { + // if status > 0 then return + if (res->status() > 0) { + return; + } + + // initialisations + TLorentzVector ivm{0., 0., 0., 0.}; + int charge = 0; + + // is this a final state or a resonance + if (res->isFinal()) { + // is a final + auto pdgparticle = fPDG->GetParticle(res->pid()); + auto track = (tracks.begin() + comb[res->counter()]); + ivm.SetXYZM(track.px(), track.py(), track.pz(), pdgparticle->Mass()); + res->setIVM(ivm); + res->setCharge(track.sign()); + res->setStatus(1); + + // apply cuts + res->updateStatus(track); + + } else { + // is a resonance + // loop over daughters + for (const auto& daughName : res->getDaughters()) { + auto daugh = getResonance(daughName); + computeResonance(daugh, tracks, comb); + ivm += daugh->IVM(); + charge += daugh->charge(); + } + res->setIVM(ivm); + res->setCharge(charge); + res->setStatus(1); + + // apply cuts + res->updateStatus(); + } + } + + // create histograms + void createHistograms(HistogramRegistry& registry) + { + // definitions + auto etax = AxisSpec(100, -1.5, 1.5); + auto nSax = AxisSpec(300, -15.0, 15.0); + auto chi2ax = AxisSpec(100, 0.0, 5.0); + auto nClax = AxisSpec(170, 0.0, 170.0); + auto angax = AxisSpec(315, 0.0, 3.15); + auto dcaxyax = AxisSpec(400, -0.2, 0.2); + auto dcazax = AxisSpec(600, -0.3, 0.3); + auto sTPCax = AxisSpec(1000, 0., 1000.); + + std::string base; + std::string hname; + std::string annot; + fhistPointers.clear(); + for (const auto& res : getResonances()) { + auto max = AxisSpec(res->nmassBins(), res->massHistRange()[0], res->massHistRange()[1]); + auto momax = AxisSpec(res->nmomBins(), res->momHistRange()[0], res->momHistRange()[1]); + + // M-pT, M-eta, pT-eta + for (const auto& cc : fccs) { + base = cc; + base.append("/").append(res->name()).append("/"); + hname = base + "mpt"; + annot = "M versus pT; M (" + res->name() + ") GeV/c^{2}; pT (" + res->name() + ") GeV/c"; + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH2F, {max, momax}})}); + hname = base + "meta"; + annot = "M versus eta; M (" + res->name() + ") GeV/c^{2}; eta (" + res->name() + ")"; + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH2F, {max, etax}})}); + hname = base + "pteta"; + annot = "pT versus eta; pT (" + res->name() + ") GeV/c; eta (" + res->name() + ")"; + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH2F, {momax, etax}})}); + + // M versus daughters + auto daughs = res->getDaughters(); + auto ndaughs = daughs.size(); + for (auto i = 0; i < static_cast(ndaughs); i++) { + auto d1 = getResonance(daughs[i]); + + // M vs pT daughter + hname = base; + hname.append("MvspT_").append(res->name()).append(d1->name()); + annot = "M versus pT; M (" + res->name() + ") GeV/c^{2}; pT (" + d1->name() + ") GeV/c"; + auto momax1 = AxisSpec(d1->nmomBins(), d1->momHistRange()[0], d1->momHistRange()[1]); + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH2F, {max, momax1}})}); + + // M vs eta daughter + hname = base; + hname.append("Mvseta_").append(res->name()).append(d1->name()); + annot = "M versus eta; M (" + res->name() + ") GeV/c^{2}; eta (" + d1->name() + ")"; + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH2F, {max, etax}})}); + + if (d1->isFinal()) { + // M vs dcaXYZ + hname = base; + hname.append("MvsdcaXY_").append(res->name()).append(d1->name()); + annot = "M versus dcaXY; M (" + res->name() + ") GeV/c^{2}; dca_{XY} (" + d1->name() + ") #mu m"; + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH2F, {max, dcaxyax}})}); + hname = base; + hname.append("MvsdcaZ_").append(res->name()).append(d1->name()); + annot = "M versus dcaZ; M (" + res->name() + ") GeV/c^{2}; dca_{Z} (" + d1->name() + ") #mu m"; + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH2F, {max, dcazax}})}); + + // M vs chi2 track + hname = base; + hname.append("Mvschi2_").append(res->name()).append(d1->name()); + annot = "M versus chi2; M (" + res->name() + ") GeV/c^{2}; chi2 (" + d1->name() + ")"; + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH2F, {max, chi2ax}})}); + + // M vs nCl track + hname = base; + hname.append("MvsnCl_").append(res->name()).append(d1->name()); + annot = "M versus nCl; M (" + res->name() + ") GeV/c^{2}; nCl (" + d1->name() + ")"; + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH2F, {max, nClax}})}); + + // M versus detector hits + hname = base; + hname.append("MvsdetHits_").append(res->name()).append(d1->name()); + annot = "M versus detector hits; M (" + res->name() + ") GeV/c^{2}; ITS + 2*TPC + 4*TRD + 8*TOF (" + d1->name() + ")"; + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH2F, {max, {16, -0.5, 15.5}}})}); + } else { + // M vs Mi + hname = base; + hname.append("MvsM_").append(res->name()).append(d1->name()); + annot = "M versus M; M (" + res->name() + ") GeV/c^{2}; M (" + d1->name() + ") GeV/c^{2}"; + auto max1 = AxisSpec(res->nmassBins(), d1->massHistRange()[0], d1->massHistRange()[1]); + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH2F, {max, max1}})}); + } + } + + // daughters vs daughters + for (auto i = 0; i < static_cast(ndaughs - 1); i++) { + auto d1 = getResonance(daughs[i]); + auto max1 = AxisSpec(d1->nmassBins(), d1->massHistRange()[0], d1->massHistRange()[1]); + for (auto j = i + 1; j < static_cast(ndaughs); j++) { + auto d2 = getResonance(daughs[j]); + auto max2 = AxisSpec(d2->nmassBins(), d2->massHistRange()[0], d2->massHistRange()[1]); + + // M1 vs M2 + hname = base; + hname.append("MvsM_").append(d1->name()).append(d2->name()); + annot = std::string("M versus M; M (").append(d1->name()).append(") GeV/c^{2}; M (").append(d2->name()).append(") GeV/c^{2}"); + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH2F, {max1, max2}})}); + + // angle(d1, d2) + hname = base; + hname.append("angle_").append(d1->name()).append(d2->name()); + annot = std::string("angle; Angle (").append(d1->name()).append(", ").append(d2->name()).append(")"); + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH1F, {angax}})}); + + // M vs angle(d1, d2) + hname = base; + hname.append("Mvsangle_").append(d1->name()).append(d2->name()); + annot = std::string("M versus angle; M (").append(res->name()).append(") GeV/c^{2}; Angle (").append(d1->name()).append(", ").append(d2->name()).append(")"); + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH2F, {max, angax}})}); + + // both daughters are finals + if (d1->isFinal() && d2->isFinal()) { + hname = base; + hname.append("TPCsignal_").append(d1->name()).append(d2->name()); + annot = std::string("TPC signal of both tracks; TPCsignal (").append(d1->name()).append("); TPCsignal (").append(d2->name()).append(")"); + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH2F, {sTPCax, sTPCax}})}); + } + } + } + + // for finals only + if (res->isFinal()) { + // dca + hname = base; + hname.append("dcaXY"); + annot = std::string("dcaXY; dca_{XY}(").append(res->name()).append(")"); + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH1F, {dcaxyax}})}); + hname = base; + hname.append("dcaZ"); + annot = std::string("dcaZ; dca_{Z}(").append(res->name()).append(")"); + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH1F, {dcazax}})}); + + // nSIgma[TPC, TOF] vs pT + for (const auto& det : fdets) { + for (const auto& part : fparts) { + hname = base; + hname.append("nS").append(part).append(det); + annot = std::string("nSigma_").append(det).append(" versus p; p (").append(res->name()).append(") GeV/c; nSigma_{").append(det).append(", ").append(part).append("} (").append(res->name()).append(")"); + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH2F, {momax, nSax}})}); + } + } + + // detector hits + hname = base; + hname.append("detectorHits"); + annot = std::string("detectorHits; Detector(").append(res->name()).append(")"); + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {HistType::kTH1F, {{4, 0.5, 4.5}}})}); + } + } + } + } + + // ClassDefNV(decayTree, 1); +}; + +#endif // PWGUD_CORE_DECAYTREE_H_ diff --git a/PWGUD/Core/decayTreeLinkDef.h b/PWGUD/Core/decayTreeLinkDef.h new file mode 100644 index 00000000000..92d99ccf1bc --- /dev/null +++ b/PWGUD/Core/decayTreeLinkDef.h @@ -0,0 +1,19 @@ +// 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. +#ifndef PWGUD_CORE_DECAYTREELINKDEF_H_ +#define PWGUD_CORE_DECAYTREELINKDEF_H_ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; +#pragma link C++ class decayTree + ; + +#endif // PWGUD_CORE_DECAYTREELINKDEF_H_ diff --git a/PWGUD/DataModel/SGTables.h b/PWGUD/DataModel/SGTables.h new file mode 100644 index 00000000000..bf9ef68da96 --- /dev/null +++ b/PWGUD/DataModel/SGTables.h @@ -0,0 +1,67 @@ +// 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. + +#ifndef PWGUD_DATAMODEL_SGTABLES_H_ +#define PWGUD_DATAMODEL_SGTABLES_H_ + +#include +#include +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/DataTypes.h" +#include "MathUtils/Utils.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" + +namespace o2::aod +{ +namespace sgevent +{ +DECLARE_SOA_COLUMN(Run, run, int32_t); +DECLARE_SOA_COLUMN(Flag, flag, int); +DECLARE_SOA_COLUMN(GS, gs, int); +DECLARE_SOA_COLUMN(ZNA, zna, float); +DECLARE_SOA_COLUMN(ZNC, znc, float); +DECLARE_SOA_COLUMN(Ntr, ntr, int); +DECLARE_SOA_COLUMN(Occ, occ, int); +DECLARE_SOA_COLUMN(Ir, ir, float); +} // namespace sgevent +DECLARE_SOA_TABLE(SGEvents, "AOD", "SGEVENT", // o2::soa::Index<>, + sgevent::Run, sgevent::Flag, sgevent::GS, sgevent::ZNA, sgevent::ZNC, sgevent::Ntr, sgevent::Occ, sgevent::Ir); +// sgevent::Run, sgevent::Flag); +using SGEvent = SGEvents::iterator; +namespace sgtrack +{ +DECLARE_SOA_INDEX_COLUMN(SGEvent, sgEvent); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Sign, sign, float); +DECLARE_SOA_COLUMN(TPCpi, tpcpi, float); +DECLARE_SOA_COLUMN(TPCka, tpcka, float); +DECLARE_SOA_COLUMN(TPCpr, tpcpr, float); +DECLARE_SOA_COLUMN(TPCel, tpcel, float); +DECLARE_SOA_COLUMN(TOFpi, tofpi, float); +DECLARE_SOA_COLUMN(TOFka, tofka, float); +DECLARE_SOA_COLUMN(TOFpr, tofpr, float); +DECLARE_SOA_COLUMN(TOFel, tofel, float); +DECLARE_SOA_COLUMN(TPCmu, tpcmu, float); +DECLARE_SOA_COLUMN(TOFmu, tofmu, float); +DECLARE_SOA_COLUMN(TPCde, tpcde, float); +DECLARE_SOA_COLUMN(TOFde, tofde, float); +} // namespace sgtrack +DECLARE_SOA_TABLE(SGTracks, "AOD", "SGTRACK", + o2::soa::Index<>, sgtrack::SGEventId, + sgtrack::Pt, sgtrack::Eta, sgtrack::Phi, sgtrack::Sign, sgtrack::TPCpi, sgtrack::TPCka, sgtrack::TPCpr, sgtrack::TPCel, sgtrack::TOFpi, sgtrack::TOFka, sgtrack::TOFpr, sgtrack::TOFel, sgtrack::TPCmu, sgtrack::TOFmu, sgtrack::TPCde, sgtrack::TOFde); +using SGTrack = SGTracks::iterator; +} // namespace o2::aod + +#endif // PWGUD_DATAMODEL_SGTABLES_H_ diff --git a/PWGUD/DataModel/UDIndex.h b/PWGUD/DataModel/UDIndex.h new file mode 100644 index 00000000000..5fdfb0596e6 --- /dev/null +++ b/PWGUD/DataModel/UDIndex.h @@ -0,0 +1,33 @@ +// 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 UDIndex.h +/// \author Roman Lavička +/// \since 2025-04-15 +/// \brief A table to store indices for association of MC truth to MC reco +/// + +#ifndef PWGUD_DATAMODEL_UDINDEX_H_ +#define PWGUD_DATAMODEL_UDINDEX_H_ + +#include "Framework/AnalysisDataModel.h" +namespace o2::aod +{ +namespace udidx +{ +DECLARE_SOA_ARRAY_INDEX_COLUMN(UDTrack, udtracks); +DECLARE_SOA_ARRAY_INDEX_COLUMN(UDCollision, udcollisions); +} // namespace udidx +DECLARE_SOA_TABLE(UDMcParticlesToUDTracks, "AOD", "UDP2UDT", udidx::UDTrackIds); +DECLARE_SOA_TABLE(UDMcCollisionsToUDCollisions, "AOD", "UDMCC2UDC", udidx::UDCollisionIds); +} // namespace o2::aod +#endif // PWGUD_DATAMODEL_UDINDEX_H_ diff --git a/PWGUD/DataModel/UDTables.h b/PWGUD/DataModel/UDTables.h index 8a21797d91c..b84f6cd26e7 100644 --- a/PWGUD/DataModel/UDTables.h +++ b/PWGUD/DataModel/UDTables.h @@ -29,7 +29,7 @@ namespace udmccollision DECLARE_SOA_COLUMN(GlobalBC, globalBC, uint64_t); //! } // namespace udmccollision -DECLARE_SOA_TABLE(UDMcCollisions, "AOD", "UDMCCOLLISIONS", +DECLARE_SOA_TABLE(UDMcCollisions, "AOD", "UDMCCOLLISION", o2::soa::Index<>, udmccollision::GlobalBC, mccollision::GeneratorsID, @@ -53,7 +53,7 @@ DECLARE_SOA_COLUMN(Pz, pz, float); //! DECLARE_SOA_COLUMN(E, e, float); //! } // namespace udmcparticle -DECLARE_SOA_TABLE_FULL(UDMcParticles, "UDMcParticles", "AOD", "UDMCPARTICLES", //! +DECLARE_SOA_TABLE_FULL(UDMcParticles, "UDMcParticles", "AOD", "UDMCPARTICLE", //! o2::soa::Index<>, udmcparticle::UDMcCollisionId, mcparticle::PdgCode, mcparticle::StatusCode, @@ -86,16 +86,31 @@ DECLARE_SOA_COLUMN(TotalFT0AmplitudeC, totalFT0AmplitudeC, float); //! sum of am DECLARE_SOA_COLUMN(TimeFT0A, timeFT0A, float); //! FT0A average time DECLARE_SOA_COLUMN(TimeFT0C, timeFT0C, float); //! FT0C average time DECLARE_SOA_COLUMN(TriggerMaskFT0, triggerMaskFT0, uint8_t); //! FT0 trigger mask +DECLARE_SOA_COLUMN(ChFT0A, chFT0A, uint8_t); //! number of FT0A active channels +DECLARE_SOA_COLUMN(ChFT0C, chFT0C, uint8_t); //! number of FT0C active channels // FDD information DECLARE_SOA_COLUMN(TotalFDDAmplitudeA, totalFDDAmplitudeA, float); //! sum of amplitudes on A side of FDD DECLARE_SOA_COLUMN(TotalFDDAmplitudeC, totalFDDAmplitudeC, float); //! sum of amplitudes on C side of FDD DECLARE_SOA_COLUMN(TimeFDDA, timeFDDA, float); //! FDDA average time DECLARE_SOA_COLUMN(TimeFDDC, timeFDDC, float); //! FDDC average time DECLARE_SOA_COLUMN(TriggerMaskFDD, triggerMaskFDD, uint8_t); //! FDD trigger mask +DECLARE_SOA_COLUMN(ChFDDA, chFDDA, uint8_t); //! number of FDDA active channels +DECLARE_SOA_COLUMN(ChFDDC, chFDDC, uint8_t); //! number of FDDC active channels // FV0A information DECLARE_SOA_COLUMN(TotalFV0AmplitudeA, totalFV0AmplitudeA, float); //! sum of amplitudes on A side of FDD DECLARE_SOA_COLUMN(TimeFV0A, timeFV0A, float); //! FV0A average time DECLARE_SOA_COLUMN(TriggerMaskFV0A, triggerMaskFV0A, uint8_t); //! FV0 trigger mask +DECLARE_SOA_COLUMN(ChFV0A, chFV0A, uint8_t); //! number of FV0A active channels +DECLARE_SOA_COLUMN(OccupancyInTime, occupancyInTime, int); +DECLARE_SOA_COLUMN(HadronicRate, hadronicRate, double); +DECLARE_SOA_COLUMN(Trs, trs, int); +DECLARE_SOA_COLUMN(Trofs, trofs, int); +DECLARE_SOA_COLUMN(Hmpr, hmpr, int); +DECLARE_SOA_COLUMN(TFb, tfb, int); +DECLARE_SOA_COLUMN(ITSROFb, itsROFb, int); +DECLARE_SOA_COLUMN(Sbp, sbp, int); +DECLARE_SOA_COLUMN(ZvtxFT0vPV, zVtxFT0vPV, int); +DECLARE_SOA_COLUMN(VtxITSTPC, vtxITSTPC, int); // Gap Side Information DECLARE_SOA_COLUMN(GapSide, gapSide, uint8_t); // 0 for side A, 1 for side C, 2 for both sides (or use an enum for better readability) // FIT selection flags @@ -151,7 +166,7 @@ DECLARE_SOA_INDEX_COLUMN(UDMcCollision, udMcCollision); } // namespace udcollision -DECLARE_SOA_TABLE(UDCollisions, "AOD", "UDCOLLISION", +DECLARE_SOA_TABLE(UDCollisions_000, "AOD", "UDCOLLISION", o2::soa::Index<>, udcollision::GlobalBC, udcollision::RunNumber, @@ -161,6 +176,18 @@ DECLARE_SOA_TABLE(UDCollisions, "AOD", "UDCOLLISION", collision::NumContrib, udcollision::NetCharge, udcollision::RgtrwTOF); +// Version with UPC Reco Flag +DECLARE_SOA_TABLE_VERSIONED(UDCollisions_001, "AOD", "UDCOLLISION", 1, + o2::soa::Index<>, + udcollision::GlobalBC, + udcollision::RunNumber, + collision::PosX, + collision::PosY, + collision::PosZ, + collision::Flags, + collision::NumContrib, + udcollision::NetCharge, + udcollision::RgtrwTOF); DECLARE_SOA_TABLE(SGCollisions, "AOD", "SGCOLLISION", udcollision::GapSide); @@ -186,6 +213,42 @@ DECLARE_SOA_TABLE(UDCollisionsSels, "AOD", "UDCOLLISIONSEL", udcollision::BBFV0A, udcollision::BGFV0A, udcollision::BBFDDA, udcollision::BBFDDC, udcollision::BGFDDA, udcollision::BGFDDC); +DECLARE_SOA_TABLE(UDCollisionSelExtras_000, "AOD", "UDCOLSELEXTRA", + udcollision::ChFT0A, //! number of active channels in FT0A + udcollision::ChFT0C, //! number of active channels in FT0C + udcollision::ChFDDA, //! number of active channels in FDDA + udcollision::ChFDDC, //! number of active channels in FDDC + udcollision::ChFV0A); //! number of active channels in FV0A + +DECLARE_SOA_TABLE_VERSIONED(UDCollisionSelExtras_001, "AOD", "UDCOLSELEXTRA", 1, + udcollision::ChFT0A, //! number of active channels in FT0A + udcollision::ChFT0C, //! number of active channels in FT0C + udcollision::ChFDDA, //! number of active channels in FDDA + udcollision::ChFDDC, //! number of active channels in FDDC + udcollision::ChFV0A, //! number of active channels in FV0A + udcollision::OccupancyInTime, //! Occupancy + udcollision::HadronicRate, //! Interaction Rate + udcollision::Trs, //! kNoCollInTimeRangeStandard + udcollision::Trofs, //! kNoCollInRofStandard + udcollision::Hmpr); //! kNoHighMultCollInPrevRof + +DECLARE_SOA_TABLE_VERSIONED(UDCollisionSelExtras_002, "AOD", "UDCOLSELEXTRA", 2, + udcollision::ChFT0A, //! number of active channels in FT0A + udcollision::ChFT0C, //! number of active channels in FT0C + udcollision::ChFDDA, //! number of active channels in FDDA + udcollision::ChFDDC, //! number of active channels in FDDC + udcollision::ChFV0A, //! number of active channels in FV0A + udcollision::OccupancyInTime, //! Occupancy + udcollision::HadronicRate, //! Interaction Rate + udcollision::Trs, //! kNoCollInTimeRangeStandard + udcollision::Trofs, //! kNoCollInRofStandard + udcollision::Hmpr, //! kNoHighMultCollInPrevRof + udcollision::TFb, //! kNoTimeFrameBorder + udcollision::ITSROFb, //! kNoITSROFrameBorder + udcollision::Sbp, //! kNoSameBunchPileup + udcollision::ZvtxFT0vPV, //! kIsGoodZvtxFT0vsPV + udcollision::VtxITSTPC); //! kIsVertexITSTPC + // central barrel-specific selections DECLARE_SOA_TABLE(UDCollisionsSelsCent, "AOD", "UDCOLSELCNT", udcollision::DBcTOR, @@ -208,11 +271,15 @@ DECLARE_SOA_TABLE(UDCollsLabels, "AOD", "UDCOLLSLABEL", DECLARE_SOA_TABLE(UDMcCollsLabels, "AOD", "UDMCCOLLSLABEL", udcollision::UDMcCollisionId); +using UDCollisions = UDCollisions_001; +using UDCollisionSelExtras = UDCollisionSelExtras_002; + using UDCollision = UDCollisions::iterator; using SGCollision = SGCollisions::iterator; using UDCollisionsSel = UDCollisionsSels::iterator; using UDCollisionsSelCent = UDCollisionsSelsCent::iterator; using UDCollisionsSelFwd = UDCollisionsSelsFwd::iterator; +using UDCollisionSelExtra = UDCollisionSelExtras::iterator; using UDCollsLabel = UDCollsLabels::iterator; using UDMcCollsLabel = UDMcCollsLabels::iterator; @@ -264,6 +331,10 @@ DECLARE_SOA_TABLE(UDTracksPID, "AOD", "UDTRACKPID", pidtofbeta::Beta, pidtofbeta::BetaError, pidtof::TOFNSigmaEl, pidtof::TOFNSigmaMu, pidtof::TOFNSigmaPi, pidtof::TOFNSigmaKa, pidtof::TOFNSigmaPr); +DECLARE_SOA_TABLE(UDTracksPIDExtra, "AOD", "UDTRACKPIDEXTRA", + pidtpc::TPCNSigmaDe, pidtpc::TPCNSigmaTr, pidtpc::TPCNSigmaHe, pidtpc::TPCNSigmaAl, + pidtof::TOFNSigmaDe, pidtof::TOFNSigmaTr, pidtof::TOFNSigmaHe, pidtof::TOFNSigmaAl); + DECLARE_SOA_TABLE(UDTracksExtra, "AOD", "UDTRACKEXTRA", track::TPCInnerParam, track::ITSClusterSizes, @@ -355,8 +426,25 @@ DECLARE_SOA_TABLE(UDFwdTracks, "AOD", "UDFWDTRACK", udfwdtrack::TrackTime, udfwdtrack::TrackTimeRes); +namespace udfwdmatchindex +{ +DECLARE_SOA_INDEX_COLUMN(UDCollision, udCollision); //! +DECLARE_SOA_COLUMN(GlobalIndex, globalIndex, int64_t); //! Index of the track in the global track table +DECLARE_SOA_COLUMN(MCHTrackId, mchTrackId, int64_t); //! Id of original MCH track used for matching +DECLARE_SOA_COLUMN(MFTTrackId, mftTrackId, int64_t); //! Id of original MFT track used for matching +} // namespace udfwdmatchindex + +// Details about FWD indices +DECLARE_SOA_TABLE(UDFwdIndices, "AOD", "UDFWDINDEX", + o2::soa::Index<>, + udfwdmatchindex::UDCollisionId, + udfwdmatchindex::GlobalIndex, + udfwdmatchindex::MCHTrackId, + udfwdmatchindex::MFTTrackId); + // Muon track quality details -DECLARE_SOA_TABLE(UDFwdTracksExtra, "AOD", "UDFWDTRACKEXTRA", +// Version with only MCH-MID tracks +DECLARE_SOA_TABLE(UDFwdTracksExtra_000, "AOD", "UDFWDTRACKEXTRA", fwdtrack::NClusters, fwdtrack::PDca, fwdtrack::RAtAbsorberEnd, @@ -366,7 +454,23 @@ DECLARE_SOA_TABLE(UDFwdTracksExtra, "AOD", "UDFWDTRACKEXTRA", fwdtrack::MIDBitMap, fwdtrack::MIDBoards); +// Version with global tracks +DECLARE_SOA_TABLE_VERSIONED(UDFwdTracksExtra_001, "AOD", "UDFWDTRACKEXTRA", 1, + fwdtrack::TrackType, + fwdtrack::NClusters, + fwdtrack::PDca, + fwdtrack::RAtAbsorberEnd, + fwdtrack::Chi2, + fwdtrack::Chi2MatchMCHMID, + fwdtrack::Chi2MatchMCHMFT, + fwdtrack::MCHBitMap, + fwdtrack::MIDBitMap, + fwdtrack::MIDBoards); + +using UDFwdTracksExtra = UDFwdTracksExtra_001; + using UDFwdTrack = UDFwdTracks::iterator; +using UDFwdIndex = UDFwdIndices::iterator; using UDFwdTrackExtra = UDFwdTracksExtra::iterator; DECLARE_SOA_TABLE(UDFwdTracksProp, "AOD", "UDFWDTRACKPROP", diff --git a/PWGUD/TableProducer/CMakeLists.txt b/PWGUD/TableProducer/CMakeLists.txt index 2406868718c..16dd0773aed 100644 --- a/PWGUD/TableProducer/CMakeLists.txt +++ b/PWGUD/TableProducer/CMakeLists.txt @@ -9,14 +9,16 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +add_subdirectory(Converters) + o2physics_add_dpl_workflow(dgcand-producer SOURCES DGCandProducer.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGCutparHolder + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGCutparHolder O2Physics::EventFilteringUtils O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(sgcand-producer SOURCES SGCandProducer.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::SGCutParHolder + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::SGCutParHolder O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(dgbccand-producer @@ -29,7 +31,22 @@ o2physics_add_dpl_workflow(upccand-producer PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::UPCCutparHolder COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(tau-event-table-producer + SOURCES tauEventTableProducer.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(fwdtrack-propagation - SOURCES fwdTrackPropagation.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::GlobalTracking - COMPONENT_NAME Analysis) + SOURCES fwdTrackPropagation.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::GlobalTracking + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(udmcparticles-to-udtracks + SOURCES udMcParticles2udTracks.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(udmccollisions-to-udcollisions + SOURCES udMcCollisions2udCollisions.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGUD/TableProducer/Converters/CMakeLists.txt b/PWGUD/TableProducer/Converters/CMakeLists.txt new file mode 100644 index 00000000000..8230278b45c --- /dev/null +++ b/PWGUD/TableProducer/Converters/CMakeLists.txt @@ -0,0 +1,31 @@ +# 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(fwd-tracks-extra-converter + SOURCES UDFwdTracksExtraConverter.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + + +o2physics_add_dpl_workflow(collisions-converter + SOURCES UDCollisionsConverter.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(collisionselextras-converter + SOURCES UDCollisionSelExtrasConverter.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(collisionselextras-converter-v002 + SOURCES UDCollisionSelExtrasV002Converter.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGUD/TableProducer/Converters/UDCollisionSelExtrasConverter.cxx b/PWGUD/TableProducer/Converters/UDCollisionSelExtrasConverter.cxx new file mode 100644 index 00000000000..1fa1882e7d5 --- /dev/null +++ b/PWGUD/TableProducer/Converters/UDCollisionSelExtrasConverter.cxx @@ -0,0 +1,59 @@ +// 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 UDCollisionSelExtrasConverter.cxx +/// \brief Converts UDCollisionSelExtras table from version 000 to 001 + +/// This task allows for the conversion of the UDCollisionSelExtras table from the version 000, +/// to include occupancy and interaction rate +/// to the version 001, that includes it + +/// executable name o2-analysis-ud-collisionselectras-converter + +/// \author Sasha Bylinkin + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGUD/DataModel/UDTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts UDCollisions for version 000 to 001 +struct UDCollisionSelExtrasConverter { + Produces udCollisionSelExtras_001; + + void process(o2::aod::UDCollisionSelExtras_000 const& collisions) + { + + for (const auto& collision : collisions) { + + udCollisionSelExtras_001(collision.chFT0A(), + collision.chFT0C(), + collision.chFDDA(), + collision.chFDDC(), + collision.chFV0A(), + 0, // dummy occupancy + 0.0f, // dummy rate + 0, // dummy trs + 0, // dummy trofs + 0); // dummy hmpr + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGUD/TableProducer/Converters/UDCollisionSelExtrasV002Converter.cxx b/PWGUD/TableProducer/Converters/UDCollisionSelExtrasV002Converter.cxx new file mode 100644 index 00000000000..b10b467ec4d --- /dev/null +++ b/PWGUD/TableProducer/Converters/UDCollisionSelExtrasV002Converter.cxx @@ -0,0 +1,98 @@ +// 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 UDCollisionSelExtrasV002Converter.cxx +/// \brief Converts UDCollisionSelExtras table from version 000 to 002 and 001 to 002 +/// \author Roman Lavicka + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGUD/DataModel/UDTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts UDCollisions for version 000 to 002 and 001 to 002 +struct UDCollisionSelExtrasV002Converter { + Produces udCollisionSelExtras_002; + + void init(InitContext const&) + { + if (!doprocessV000ToV002 && !doprocessV001ToV002) { + LOGF(fatal, "Neither processV000ToV002 nor processV001ToV002 is enabled. Please choose one!"); + } + if (doprocessV000ToV002 && doprocessV001ToV002) { + LOGF(fatal, "Both processV000ToV002 and processV001ToV002 are enabled. Please choose only one!"); + } + } + + void processV000ToV002(o2::aod::UDCollisionSelExtras_000 const& collisions) + { + + for (const auto& collision : collisions) { + + udCollisionSelExtras_002(collision.chFT0A(), + collision.chFT0C(), + collision.chFDDA(), + collision.chFDDC(), + collision.chFV0A(), + 0, // dummy occupancy + 0.0f, // dummy rate + 0, // dummy trs + 0, // dummy trofs + 0, // dummy hmpr + 0, // dummy tfb + 0, // dummy itsROFb + 0, // dummy sbp + 0, // dummy zVtxFT0vPV + 0); // dummy vtxITSTPC + } + } + PROCESS_SWITCH(UDCollisionSelExtrasV002Converter, processV000ToV002, "process v000-to-v002 conversion", false); + + void processV001ToV002(o2::aod::UDCollisionSelExtras_001 const& collisions) + { + + for (const auto& collision : collisions) { + + udCollisionSelExtras_002(collision.chFT0A(), + collision.chFT0C(), + collision.chFDDA(), + collision.chFDDC(), + collision.chFV0A(), + collision.occupancyInTime(), + collision.hadronicRate(), + collision.trs(), + collision.trofs(), + collision.hmpr(), + 0, // dummy tfb + 0, // dummy itsROFb + 0, // dummy sbp + 0, // dummy zVtxFT0vPV + 0); // dummy vtxITSTPC + } + } + PROCESS_SWITCH(UDCollisionSelExtrasV002Converter, processV001ToV002, "process v001-to-v002 conversion", true); +}; + +/// Spawn the extended table for UDCollisionSelExtras002 to avoid the call to the internal spawner and a consequent circular dependency +// struct UDCollisionSelExtrasSpawner { +// Spawns udCollisionSelExtras_002; +// }; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + // adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGUD/TableProducer/Converters/UDCollisionsConverter.cxx b/PWGUD/TableProducer/Converters/UDCollisionsConverter.cxx new file mode 100644 index 00000000000..8be7bce717b --- /dev/null +++ b/PWGUD/TableProducer/Converters/UDCollisionsConverter.cxx @@ -0,0 +1,58 @@ +// 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 UDCollisionsConverter.cxx +/// \brief Converts UDCollisions table from version 000 to 001 + +/// This task allows for the conversion of the UDCollisions table from the version 000, +/// that is before the introduction of Flags for UPC reconstruction +/// to the version 001, that includes it + +/// executable name o2-analysis-ud-collisions-converter + +/// \author Sasha Bylinkin + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGUD/DataModel/UDTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts UDCollisions for version 000 to 001 +struct UDCollisionsConverter { + Produces udCollisions_001; + + void process(o2::aod::UDCollisions_000 const& collisions) + { + + for (const auto& collision : collisions) { + + udCollisions_001(collision.globalBC(), + collision.runNumber(), + collision.posX(), + collision.posY(), + collision.posZ(), + 0.0f, // dummy UPC reco flag, not available in version 000 + collision.numContrib(), + collision.netCharge(), + collision.rgtrwTOF()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGUD/TableProducer/Converters/UDFwdTracksExtraConverter.cxx b/PWGUD/TableProducer/Converters/UDFwdTracksExtraConverter.cxx new file mode 100644 index 00000000000..f9b1f2d0d22 --- /dev/null +++ b/PWGUD/TableProducer/Converters/UDFwdTracksExtraConverter.cxx @@ -0,0 +1,68 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file UDFwdTracksExtraConverter.cxx +/// \brief Converts UDFwdTracksExtra table from version 000 to 001 + +/// This task allows for the conversion of the UDFwdTracksExtra table from the version 000, +/// that is before the introduction of global tracks (and so contains only MCH-MID and +/// MCH only tracks), to the version 001, that includes global tracks +/// Global tracks introduced here: https://github.com/AliceO2Group/O2Physics/commit/72f673611ddcd7c39978787dbed9f77e6e7c3d6a) + +/// executable name o2-analysis-ud-fwd-tracks-extra-converter + +/// \author Andrea Giovanni Riffero + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGUD/DataModel/UDTables.h" + +using namespace o2; +using namespace o2::framework; + +// Converts UDFwdTracksExtra for version 000 to 001 +// v_000 only MID-MCH and MCH only tracks +// v_001 global tracks +struct UDFwdTracksExtraConverter { + Produces udFwdTracksExtra_001; + + void process(o2::aod::UDFwdTracksExtra_000 const& tracks) + { + int trkType = 3; // trackType of MCH-MID tracks is 3 + + for (const auto& track : tracks) { + + if (track.chi2MatchMCHMID() > 0) + trkType = 3; // trackType of MCH-MID tracks is 3 + if (track.chi2MatchMCHMID() < 0) + trkType = 4; // trackType of MCH only tracks is 4 + + udFwdTracksExtra_001(trkType, + track.nClusters(), + track.pDca(), + track.rAtAbsorberEnd(), + track.chi2(), + track.chi2MatchMCHMID(), + 0.0f, // dummy mchmftChi2, not available in version 000 + track.mchBitMap(), + track.midBitMap(), + track.midBoards()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGUD/TableProducer/DGBCCandProducer.cxx b/PWGUD/TableProducer/DGBCCandProducer.cxx index d765be9afc6..97b60c42c9e 100644 --- a/PWGUD/TableProducer/DGBCCandProducer.cxx +++ b/PWGUD/TableProducer/DGBCCandProducer.cxx @@ -17,6 +17,7 @@ #include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" +#include "ReconstructionDataFormats/Vertex.h" #include "PWGUD/DataModel/UDTables.h" #include "PWGUD/Core/UDHelpers.h" #include "PWGUD/Core/UPCHelpers.h" @@ -279,11 +280,11 @@ struct DGBCCandProducer { // update UDTables template - void updateUDTables(bool onlyPV, int64_t colID, uint64_t bcnum, int rnum, float vx, float vy, float vz, + void updateUDTables(bool onlyPV, int64_t colID, uint64_t bcnum, int rnum, float vx, float vy, float vz, int flag, uint16_t const& ntrks, int8_t const& ncharge, float const& rtrwTOF, TTracks const& tracks, upchelpers::FITInfo const& fitInfo) { - outputCollisions(bcnum, rnum, vx, vy, vz, ntrks, ncharge, rtrwTOF); + outputCollisions(bcnum, rnum, vx, vy, vz, flag, ntrks, ncharge, rtrwTOF); outputCollisionsSels(fitInfo.ampFT0A, fitInfo.ampFT0C, fitInfo.timeFT0A, fitInfo.timeFT0C, fitInfo.triggerMaskFT0, fitInfo.ampFDDA, fitInfo.ampFDDC, fitInfo.timeFDDA, fitInfo.timeFDDC, @@ -380,11 +381,10 @@ struct DGBCCandProducer { // fill FITInfo auto bcnum = tibc.bcnum(); upchelpers::FITInfo fitInfo{}; - udhelpers::getFITinfo(fitInfo, bcnum, bcs, ft0s, fv0as, fdds); // check if DG event // distinguish between cases with and without associated BC - // 1. candidate has associated BC and associated collision -> vertex position: col.[posX(), posY(), posZ()] + // 1. candidate has associated BC and associated collision -> position: col.[posX(), posY(), posZ()] // 2. candidate has associated BC but no associated collision -> [-2., 2., -2.] // 3. candidate has no associated BC -> [-3., 3., -3.] int isDG = -1; @@ -395,6 +395,7 @@ struct DGBCCandProducer { // get associated bc auto bc = tibc.bc_as(); + udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); // is there an associated collision? Partition colSlize = aod::evsel::foundBCId == bc.globalIndex(); @@ -415,8 +416,11 @@ struct DGBCCandProducer { registry.get(HIST("table/candCase"))->Fill(1, 1.); rtrwTOF = udhelpers::rPVtrwTOF(colTracks, col.numContrib()); nCharge = udhelpers::netCharge(colTracks); - - updateUDTables(false, col.globalIndex(), bc.globalBC(), bc.runNumber(), col.posX(), col.posY(), col.posZ(), + int upc_flag = 0; + ushort flags = col.flags(); + if (flags & dataformats::Vertex>::Flags::UPCMode) + upc_flag = 1; + updateUDTables(false, col.globalIndex(), bc.globalBC(), bc.runNumber(), col.posX(), col.posY(), col.posZ(), upc_flag, col.numContrib(), nCharge, rtrwTOF, colTracks, fitInfo); } } else { @@ -448,7 +452,7 @@ struct DGBCCandProducer { rtrwTOF = udhelpers::rPVtrwTOF(tracksArray, tracksArray.size()); nCharge = udhelpers::netCharge(tracksArray); - updateUDTables(false, -1, bc.globalBC(), bc.runNumber(), -2., 2., -2, + updateUDTables(false, -1, bc.globalBC(), bc.runNumber(), -2., 2., -2, 0, tracksArray.size(), nCharge, rtrwTOF, tracksArray, fitInfo); } } @@ -494,7 +498,7 @@ struct DGBCCandProducer { rtrwTOF = udhelpers::rPVtrwTOF(tracksArray, tracksArray.size()); nCharge = udhelpers::netCharge(tracksArray); - updateUDTables(false, -1, bcnum, tibc.runNumber(), -3., 3., -3, + updateUDTables(false, -1, bcnum, tibc.runNumber(), -3., 3., -3, 0, tracksArray.size(), nCharge, rtrwTOF, tracksArray, fitInfo); } } @@ -611,8 +615,12 @@ struct DGBCCandProducer { auto rtrwTOF = udhelpers::rPVtrwTOF(colTracks, col.numContrib()); auto nCharge = udhelpers::netCharge(colTracks); - udhelpers::getFITinfo(fitInfo, bcnum, bcs, ft0s, fv0as, fdds); - updateUDTables(false, col.globalIndex(), bcnum, bc.runNumber(), col.posX(), col.posY(), col.posZ(), + udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); + int upc_flag = 0; + ushort flags = col.flags(); + if (flags & dataformats::Vertex>::Flags::UPCMode) + upc_flag = 1; + updateUDTables(false, col.globalIndex(), bcnum, bc.runNumber(), col.posX(), col.posY(), col.posZ(), upc_flag, col.numContrib(), nCharge, rtrwTOF, colTracks, fitInfo); // fill UDZdcs if (bc.has_zdc()) { @@ -661,7 +669,7 @@ struct DGBCCandProducer { auto rtrwTOF = udhelpers::rPVtrwTOF(tracksArray, tracksArray.size()); auto nCharge = udhelpers::netCharge(tracksArray); - udhelpers::getFITinfo(fitInfo, bcnum, bcs, ft0s, fv0as, fdds); + udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); // distinguish different cases if (bc.globalBC() == bcnum) { @@ -681,7 +689,11 @@ struct DGBCCandProducer { } int64_t colID = withCollision ? col.globalIndex() : -1; - updateUDTables(false, colID, bcnum, tibc.runNumber(), vpos[0], vpos[1], vpos[2], + int upc_flag = 0; + ushort flags = col.flags(); + if (flags & dataformats::Vertex>::Flags::UPCMode) + upc_flag = 1; + updateUDTables(false, colID, bcnum, tibc.runNumber(), vpos[0], vpos[1], vpos[2], upc_flag, tracksArray.size(), nCharge, rtrwTOF, tracksArray, fitInfo); // fill UDZdcs if (bc.globalBC() == bcnum) { diff --git a/PWGUD/TableProducer/DGCandProducer.cxx b/PWGUD/TableProducer/DGCandProducer.cxx index 744505c3704..54c353d3d9a 100644 --- a/PWGUD/TableProducer/DGCandProducer.cxx +++ b/PWGUD/TableProducer/DGCandProducer.cxx @@ -12,8 +12,17 @@ // \brief Saves relevant information of DG candidates // \author Paul Buehler, paul.buehler@oeaw.ac.at +#include +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "ReconstructionDataFormats/Vertex.h" +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" +#include "CCDB/BasicCCDBManager.h" +#include "Common/CCDB/ctpRateFetcher.h" #include "PWGUD/DataModel/UDTables.h" #include "PWGUD/Core/UPCHelpers.h" #include "PWGUD/Core/DGSelector.h" @@ -22,20 +31,13 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -struct DGCandProducer { - // get a DGCutparHolder - DGCutparHolder diffCuts = DGCutparHolder(); - Configurable DGCuts{"DGCuts", {}, "DG event cuts"}; - Configurable saveAllTracks{"saveAllTracks", true, "save only PV contributors or all tracks associated to a collision"}; - Configurable rejectAtTFBoundary{"rejectAtTFBoundary", false, "reject collisions at a TF boundary"}; - Configurable fillFIThistos{"fillFIThistos", false, "fill the histograms with the FIT amplitudes"}; - - // DG selector - DGSelector dgSelector; +#define getHist(type, name) std::get>(histPointers[name]) +struct DGCandProducer { // data tables Produces outputCollisions; Produces outputCollisionsSels; + Produces outputCollisionSelExtras; Produces outputCollsLabels; Produces outputZdcs; Produces outputZdcsReduced; @@ -49,10 +51,33 @@ struct DGCandProducer { Produces outputFwdTracksExtra; Produces outputTracksLabel; + // get a DGCutparHolder + DGCutparHolder diffCuts = DGCutparHolder(); + Configurable DGCuts{"DGCuts", {}, "DG event cuts"}; + + // DG selector + DGSelector dgSelector; + + // configurables + Configurable saveAllTracks{"saveAllTracks", true, "save only PV contributors or all tracks associated to a collision"}; + Configurable> generatorIds{"generatorIds", std::vector{-1}, "MC generatorIds to process"}; + + // zorro object + int mRunNumber; + Service ccdb; + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + Configurable cfgCCDBurl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable cfgZorroCCDBpath{"cfgZorroCCDBpath", "/Users/m/mpuccio/EventFiltering/OTS/", "path to the zorro ccdb objects"}; + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; + Configurable triggerName{"triggerName", "fUDiff,fUDdiffSmall,fUDiffLarge", "Name of the software trigger"}; + + // ctpRateFetcher + ctpRateFetcher mRateFetcher; + // initialize histogram registry - HistogramRegistry registry{ - "registry", - {}}; + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + std::map histPointers; // data inputs using CCs = soa::Join; @@ -65,6 +90,9 @@ struct DGCandProducer { aod::pidTOFFullEl, aod::pidTOFFullMu, aod::pidTOFFullPi, aod::pidTOFFullKa, aod::pidTOFFullPr>; using FWs = aod::FwdTracks; + using MCCCs = soa::Join; + using MCCC = MCCCs::iterator; + // function to update UDFwdTracks, UDFwdTracksExtra template void updateUDFwdTrackTables(TFwdTrack const& fwdtrack, uint64_t const& bcnum) @@ -72,11 +100,13 @@ struct DGCandProducer { outputFwdTracks(outputCollisions.lastIndex(), fwdtrack.px(), fwdtrack.py(), fwdtrack.pz(), fwdtrack.sign(), bcnum, fwdtrack.trackTime(), fwdtrack.trackTimeRes()); - outputFwdTracksExtra(fwdtrack.nClusters(), + outputFwdTracksExtra(fwdtrack.trackType(), + fwdtrack.nClusters(), fwdtrack.pDca(), fwdtrack.rAtAbsorberEnd(), fwdtrack.chi2(), fwdtrack.chi2MatchMCHMID(), + fwdtrack.chi2MatchMCHMFT(), fwdtrack.mchBitMap(), fwdtrack.midBitMap(), fwdtrack.midBoards()); @@ -132,126 +162,157 @@ struct DGCandProducer { outputTracksLabel(track.globalIndex()); } + void createHistograms(std::string histdir) + { + const int nXbinsInStatH = 26; + std::string labels[nXbinsInStatH] = { + "all", "hasBC", "zorro", "accepted", "FITveto", "MID trk", "global not PV trk", "not global PV trk", + "ITS-only PV trk", "TOF PV trk fraction", "n PV trks", "PID", "pt", "eta", "net charge", + "inv mass", "evsel TF border", "evsel no pile-up", "evsel ITSROF", "evsel z-vtx", "evsel ITSTPC vtx", + "evsel TRD vtx", "evsel TOF vtx", "", "", ""}; + + std::string hname = histdir + "/Stat"; + histPointers.insert({hname, registry.add(hname.c_str(), "Cut statistics, Collisions", {HistType::kTH1F, {{nXbinsInStatH, -0.5, static_cast(nXbinsInStatH - 0.5)}}})}); + getHist(TH1, hname)->SetNdivisions(nXbinsInStatH, "X"); + for (int iXbin(1); iXbin < nXbinsInStatH + 1; iXbin++) { + getHist(TH1, hname)->GetXaxis()->ChangeLabel(iXbin, 45, 0.03, 33, -1, -1, labels[iXbin - 1]); + } + + hname = histdir + "/pt1Vspt2"; + histPointers.insert({hname, registry.add(hname.c_str(), "2 prong events, p_{T} versus p_{T}", {HistType::kTH2F, {{100, -3., 3.}, {100, -3., 3.0}}})}); + hname = histdir + "/TPCsignal1"; + histPointers.insert({hname, registry.add(hname.c_str(), "2 prong events, TPC signal versus p_{T} of particle 1", {HistType::kTH2F, {{200, -3., 3.}, {200, 0., 100.0}}})}); + hname = histdir + "/TPCsignal2"; + histPointers.insert({hname, registry.add(hname.c_str(), "2 prong events, TPC signal versus p_{T} of particle 2", {HistType::kTH2F, {{200, -3., 3.}, {200, 0., 100.0}}})}); + hname = histdir + "/sig1VsSig2TPC"; + histPointers.insert({hname, registry.add(hname.c_str(), "2 prong events, TPC signal versus TPC signal", {HistType::kTH2F, {{100, 0., 100.}, {100, 0., 100.}}})}); + + // FIT amplitudes + // 0: unconditional + // 1: TOR 5: no TOR + // 2: TVX 6: no TVX + // 3: TSC 7: no TSC + // 4: TCE 8: no TCE + // 9: IsBBXXX 10: !IsBBXXX + // 11: kNoBGXXX 12: !kNoBGXXX + const int nXbinsFITH = 201; + hname = histdir + "/fv0"; + histPointers.insert({hname, registry.add(hname.c_str(), "FV0 amplitudes", {HistType::kTH2F, {{nXbinsFITH, -0.5, nXbinsFITH - 0.5}, {13, -0.5, 12.5}}})}); + hname = histdir + "/ft0A"; + histPointers.insert({hname, registry.add(hname.c_str(), "FT0A amplitudes", {HistType::kTH2F, {{nXbinsFITH, -0.5, nXbinsFITH - 0.5}, {13, -0.5, 12.5}}})}); + hname = histdir + "/ft0C"; + histPointers.insert({hname, registry.add(hname.c_str(), "FT0C amplitudes", {HistType::kTH2F, {{nXbinsFITH, -0.5, nXbinsFITH - 0.5}, {13, -0.5, 12.5}}})}); + hname = histdir + "/fddA"; + histPointers.insert({hname, registry.add(hname.c_str(), "FDDA amplitudes", {HistType::kTH2F, {{nXbinsFITH, -0.5, nXbinsFITH - 0.5}, {13, -0.5, 12.5}}})}); + hname = histdir + "/fddC"; + histPointers.insert({hname, registry.add(hname.c_str(), "FDDC amplitudes", {HistType::kTH2F, {{nXbinsFITH, -0.5, nXbinsFITH - 0.5}, {13, -0.5, 12.5}}})}); + } + template - void fillFIThistograms(TBC const& bc) + void fillFIThistograms(TBC const& bc, std::string histdir) { + LOGF(debug, ""); std::array triggers{{true, !udhelpers::cleanFIT(bc, diffCuts.maxFITtime(), diffCuts.FITAmpLimits()), udhelpers::TVX(bc), udhelpers::TSC(bc), udhelpers::TCE(bc)}}; + LOGF(debug, "triggers %d %d %d %d %d", triggers[0], triggers[1], triggers[2], triggers[3], triggers[4]); if (bc.has_foundFV0()) { auto fv0 = bc.foundFV0(); auto ampA = udhelpers::FV0AmplitudeA(fv0); - registry.get(HIST("reco/fv0"))->Fill(ampA, 0); - registry.get(HIST("reco/fv0"))->Fill(ampA, triggers[1] ? 1 : 5); - registry.get(HIST("reco/fv0"))->Fill(ampA, triggers[2] ? 2 : 6); - registry.get(HIST("reco/fv0"))->Fill(ampA, triggers[3] ? 3 : 7); - registry.get(HIST("reco/fv0"))->Fill(ampA, triggers[4] ? 4 : 8); - registry.get(HIST("reco/fv0"))->Fill(ampA, bc.selection_bit(o2::aod::evsel::kIsBBV0A) ? 9 : 10); - registry.get(HIST("reco/fv0"))->Fill(ampA, bc.selection_bit(o2::aod::evsel::kNoBGV0A) ? 11 : 12); + getHist(TH2, histdir + "/fv0")->Fill(ampA, 0); + getHist(TH2, histdir + "/fv0")->Fill(ampA, triggers[1] ? 1 : 5); + getHist(TH2, histdir + "/fv0")->Fill(ampA, triggers[2] ? 2 : 6); + getHist(TH2, histdir + "/fv0")->Fill(ampA, triggers[3] ? 3 : 7); + getHist(TH2, histdir + "/fv0")->Fill(ampA, triggers[4] ? 4 : 8); + getHist(TH2, histdir + "/fv0")->Fill(ampA, bc.selection_bit(o2::aod::evsel::kIsBBV0A) ? 9 : 10); + getHist(TH2, histdir + "/fv0")->Fill(ampA, bc.selection_bit(o2::aod::evsel::kNoBGV0A) ? 11 : 12); } if (bc.has_foundFT0()) { auto ft0 = bc.foundFT0(); auto ampA = udhelpers::FT0AmplitudeA(ft0); auto ampC = udhelpers::FT0AmplitudeC(ft0); - registry.get(HIST("reco/ft0A"))->Fill(ampA, 0); - registry.get(HIST("reco/ft0C"))->Fill(ampC, 0); - registry.get(HIST("reco/ft0A"))->Fill(ampA, triggers[1] ? 1 : 5); - registry.get(HIST("reco/ft0C"))->Fill(ampC, triggers[1] ? 1 : 5); - registry.get(HIST("reco/ft0A"))->Fill(ampA, triggers[2] ? 2 : 6); - registry.get(HIST("reco/ft0C"))->Fill(ampC, triggers[2] ? 2 : 6); - registry.get(HIST("reco/ft0A"))->Fill(ampA, triggers[3] ? 3 : 7); - registry.get(HIST("reco/ft0C"))->Fill(ampC, triggers[3] ? 3 : 7); - registry.get(HIST("reco/ft0A"))->Fill(ampA, triggers[4] ? 4 : 8); - registry.get(HIST("reco/ft0C"))->Fill(ampC, triggers[4] ? 4 : 8); - registry.get(HIST("reco/ft0A"))->Fill(ampA, bc.selection_bit(o2::aod::evsel::kIsBBT0A) ? 9 : 10); - registry.get(HIST("reco/ft0C"))->Fill(ampC, bc.selection_bit(o2::aod::evsel::kIsBBT0C) ? 9 : 10); - registry.get(HIST("reco/ft0A"))->Fill(ampA, bc.selection_bit(o2::aod::evsel::kNoBGT0A) ? 11 : 12); - registry.get(HIST("reco/ft0C"))->Fill(ampC, bc.selection_bit(o2::aod::evsel::kNoBGT0C) ? 11 : 12); + getHist(TH2, histdir + "/ft0A")->Fill(ampA, 0); + getHist(TH2, histdir + "/ft0C")->Fill(ampC, 0); + getHist(TH2, histdir + "/ft0A")->Fill(ampA, triggers[1] ? 1 : 5); + getHist(TH2, histdir + "/ft0C")->Fill(ampC, triggers[1] ? 1 : 5); + getHist(TH2, histdir + "/ft0A")->Fill(ampA, triggers[2] ? 2 : 6); + getHist(TH2, histdir + "/ft0C")->Fill(ampC, triggers[2] ? 2 : 6); + getHist(TH2, histdir + "/ft0A")->Fill(ampA, triggers[3] ? 3 : 7); + getHist(TH2, histdir + "/ft0C")->Fill(ampC, triggers[3] ? 3 : 7); + getHist(TH2, histdir + "/ft0A")->Fill(ampA, triggers[4] ? 4 : 8); + getHist(TH2, histdir + "/ft0C")->Fill(ampC, triggers[4] ? 4 : 8); + getHist(TH2, histdir + "/ft0A")->Fill(ampA, bc.selection_bit(o2::aod::evsel::kIsBBT0A) ? 9 : 10); + getHist(TH2, histdir + "/ft0C")->Fill(ampC, bc.selection_bit(o2::aod::evsel::kIsBBT0C) ? 9 : 10); + getHist(TH2, histdir + "/ft0A")->Fill(ampA, bc.selection_bit(o2::aod::evsel::kNoBGT0A) ? 11 : 12); + getHist(TH2, histdir + "/ft0C")->Fill(ampC, bc.selection_bit(o2::aod::evsel::kNoBGT0C) ? 11 : 12); } if (bc.has_foundFDD()) { auto fdd = bc.foundFDD(); auto ampA = udhelpers::FDDAmplitudeA(fdd); auto ampC = udhelpers::FDDAmplitudeC(fdd); - registry.get(HIST("reco/fddA"))->Fill(ampA, 0); - registry.get(HIST("reco/fddC"))->Fill(ampC, 0); - registry.get(HIST("reco/fddA"))->Fill(ampA, triggers[1] ? 1 : 5); - registry.get(HIST("reco/fddC"))->Fill(ampC, triggers[1] ? 1 : 5); - registry.get(HIST("reco/fddA"))->Fill(ampA, triggers[2] ? 2 : 6); - registry.get(HIST("reco/fddC"))->Fill(ampC, triggers[2] ? 2 : 6); - registry.get(HIST("reco/fddA"))->Fill(ampA, triggers[3] ? 3 : 7); - registry.get(HIST("reco/fddC"))->Fill(ampC, triggers[3] ? 3 : 7); - registry.get(HIST("reco/fddA"))->Fill(ampA, triggers[4] ? 4 : 8); - registry.get(HIST("reco/fddC"))->Fill(ampC, triggers[4] ? 4 : 8); - registry.get(HIST("reco/fddA"))->Fill(ampA, bc.selection_bit(o2::aod::evsel::kIsBBFDA) ? 9 : 10); - registry.get(HIST("reco/fddC"))->Fill(ampC, bc.selection_bit(o2::aod::evsel::kIsBBFDC) ? 9 : 10); - registry.get(HIST("reco/fddA"))->Fill(ampA, bc.selection_bit(o2::aod::evsel::kNoBGFDA) ? 11 : 12); - registry.get(HIST("reco/fddC"))->Fill(ampC, bc.selection_bit(o2::aod::evsel::kNoBGFDC) ? 11 : 12); - } - } - - void init(InitContext&) - { - LOGF(debug, " beginning of init reached"); - - diffCuts = (DGCutparHolder)DGCuts; - - const int nXbinsInStatH = 25; - - // add histograms for the different process functions - registry.add("reco/Stat", "Cut statistics;; Collisions", {HistType::kTH1F, {{nXbinsInStatH, -0.5, static_cast(nXbinsInStatH - 0.5)}}}); - registry.add("reco/pt1Vspt2", "2 prong events, p_{T} versus p_{T}", {HistType::kTH2F, {{100, -3., 3.}, {100, -3., 3.0}}}); - registry.add("reco/TPCsignal1", "2 prong events, TPC signal versus p_{T} of particle 1", {HistType::kTH2F, {{200, -3., 3.}, {200, 0., 100.0}}}); - registry.add("reco/TPCsignal2", "2 prong events, TPC signal versus p_{T} of particle 2", {HistType::kTH2F, {{200, -3., 3.}, {200, 0., 100.0}}}); - registry.add("reco/sig1VsSig2TPC", "2 prong events, TPC signal versus TPC signal", {HistType::kTH2F, {{100, 0., 100.}, {100, 0., 100.}}}); - - // FIT amplitudes - // 0: unconditional - // 1: TOR 5: no TOR - // 2: TVX 6: no TVX - // 3: TSC 7: no TSC - // 4: TCE 8: no TCE - // 9: IsBBXXX 10: !IsBBXXX - // 11: kNoBGXXX 12: !kNoBGXXX - registry.add("reco/fv0", "FV0 amplitudes", {HistType::kTH2F, {{20001, -0.5, 20000.5}, {13, -0.5, 12.5}}}); - registry.add("reco/ft0A", "FT0A amplitudes", {HistType::kTH2F, {{20001, -0.5, 20000.5}, {13, -0.5, 12.5}}}); - registry.add("reco/ft0C", "FT0C amplitudes", {HistType::kTH2F, {{20001, -0.5, 20000.5}, {13, -0.5, 12.5}}}); - registry.add("reco/fddA", "FDDA amplitudes", {HistType::kTH2F, {{20001, -0.5, 20000.5}, {13, -0.5, 12.5}}}); - registry.add("reco/fddC", "FDDC amplitudes", {HistType::kTH2F, {{20001, -0.5, 20000.5}, {13, -0.5, 12.5}}}); - - std::string labels[nXbinsInStatH] = {"all", "hasBC", "selected", "FITveto", "MID trk", "global PV trk", "not global PB trk", - "ITS-only PV trk", "TOF PV trk fraction", "n PV trks", "PID", "pt", "eta", "net charge", - "inv mass", "TF border", "no pile-up", "ITSROF", "z-vtx", "ITSTPC vtx", "", "", "", "", ""}; - - registry.get(HIST("reco/Stat"))->SetNdivisions(nXbinsInStatH, "X"); - for (int iXbin(1); iXbin < nXbinsInStatH + 1; iXbin++) { - registry.get(HIST("reco/Stat"))->GetXaxis()->ChangeLabel(iXbin, 45, 0.03, 33, -1, -1, labels[iXbin - 1]); + getHist(TH2, histdir + "/fddA")->Fill(ampA, 0); + getHist(TH2, histdir + "/fddC")->Fill(ampC, 0); + getHist(TH2, histdir + "/fddA")->Fill(ampA, triggers[1] ? 1 : 5); + getHist(TH2, histdir + "/fddC")->Fill(ampC, triggers[1] ? 1 : 5); + getHist(TH2, histdir + "/fddA")->Fill(ampA, triggers[2] ? 2 : 6); + getHist(TH2, histdir + "/fddC")->Fill(ampC, triggers[2] ? 2 : 6); + getHist(TH2, histdir + "/fddA")->Fill(ampA, triggers[3] ? 3 : 7); + getHist(TH2, histdir + "/fddC")->Fill(ampC, triggers[3] ? 3 : 7); + getHist(TH2, histdir + "/fddA")->Fill(ampA, triggers[4] ? 4 : 8); + getHist(TH2, histdir + "/fddC")->Fill(ampC, triggers[4] ? 4 : 8); + getHist(TH2, histdir + "/fddA")->Fill(ampA, bc.selection_bit(o2::aod::evsel::kIsBBFDA) ? 9 : 10); + getHist(TH2, histdir + "/fddC")->Fill(ampC, bc.selection_bit(o2::aod::evsel::kIsBBFDC) ? 9 : 10); + getHist(TH2, histdir + "/fddA")->Fill(ampA, bc.selection_bit(o2::aod::evsel::kNoBGFDA) ? 11 : 12); + getHist(TH2, histdir + "/fddC")->Fill(ampC, bc.selection_bit(o2::aod::evsel::kNoBGFDC) ? 11 : 12); } - - LOGF(debug, " end of init reached"); } - // process function for real data - void process(CC const& collision, BCs const& bcs, TCs& tracks, FWs& fwdtracks, - aod::Zdcs& /*zdcs*/, aod::FV0As& fv0as, aod::FT0s& ft0s, aod::FDDs& fdds) + template + void processReco(std::string histdir, TCol const& collision, BCs const& bcs, + TCs const& tracks, FWs const& fwdtracks, + aod::FV0As const& fv0as, aod::FT0s const& ft0s, aod::FDDs const& fdds) { LOGF(debug, " collision %d", collision.globalIndex()); - registry.get(HIST("reco/Stat"))->Fill(0., 1.); - - // reject collisions at TF boundaries - if (rejectAtTFBoundary && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { - return; - } - registry.get(HIST("reco/Stat"))->Fill(1., 1.); + getHist(TH1, histdir + "/Stat")->Fill(0., 1.); // nominal BC if (!collision.has_foundBC()) { return; } - registry.get(HIST("reco/Stat"))->Fill(2., 1.); - auto bc = collision.foundBC_as(); + getHist(TH1, histdir + "/Stat")->Fill(1., 1.); + auto bc = collision.template foundBC_as(); LOGF(debug, " BC id %d", bc.globalBC()); + const uint64_t ts = bc.timestamp(); + const int runnumber = bc.runNumber(); + int trs = collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) ? 1 : 0; + int trofs = collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard) ? 1 : 0; + int hmpr = collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof) ? 1 : 0; + int tfb = collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) ? 1 : 0; + int itsROFb = collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder) ? 1 : 0; + int sbp = collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup) ? 1 : 0; + int zVtxFT0vPv = collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV) ? 1 : 0; + int vtxITSTPC = collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC) ? 1 : 0; + double ir = 0.; + if (bc.has_zdc()) { + ir = mRateFetcher.fetch(ccdb.service, ts, runnumber, "ZNC hadronic") * 1.e-3; + } + uint8_t chFT0A = 0; + uint8_t chFT0C = 0; + uint8_t chFDDA = 0; + uint8_t chFDDC = 0; + uint8_t chFV0A = 0; + int occ = collision.trackOccupancyInTimeRange(); + + if (cfgSkimmedProcessing) { + // update ccdb setting for zorro + if (mRunNumber != bc.runNumber()) { + mRunNumber = bc.runNumber(); + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), triggerName.value); + zorro.populateHistRegistry(registry, bc.runNumber()); + } + } // fill FIT histograms - fillFIThistograms(bc); + fillFIThistograms(bc, histdir); // obtain slice of compatible BCs auto bcRange = udhelpers::compatibleBCs(collision, diffCuts.NDtcoll(), bcs, diffCuts.minNBCs()); @@ -261,18 +322,28 @@ struct DGCandProducer { auto isDGEvent = dgSelector.IsSelected(diffCuts, collision, bcRange, tracks, fwdtracks); // save DG candidates - registry.get(HIST("reco/Stat"))->Fill(isDGEvent + 3, 1.); + getHist(TH1, histdir + "/Stat")->Fill(isDGEvent + 3, 1.); if (isDGEvent == 0) { LOGF(debug, " Data: good collision!"); + if (cfgSkimmedProcessing) { + // let zorro do the accounting + auto zorroDecision = zorro.isSelected(bc.globalBC()); + LOGF(info, " zorroDecision %d", zorroDecision); + if (zorroDecision) { + getHist(TH1, histdir + "/Stat")->Fill(2, 1.); + } + } + // fill FITInfo upchelpers::FITInfo fitInfo{}; - udhelpers::getFITinfo(fitInfo, bc.globalBC(), bcs, ft0s, fv0as, fdds); + udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); // update DG candidates tables auto rtrwTOF = udhelpers::rPVtrwTOF(tracks, collision.numContrib()); + int upc_flag = (collision.flags() & dataformats::Vertex>::Flags::UPCMode) ? 1 : 0; outputCollisions(bc.globalBC(), bc.runNumber(), - collision.posX(), collision.posY(), collision.posZ(), + collision.posX(), collision.posY(), collision.posZ(), upc_flag, collision.numContrib(), udhelpers::netCharge(tracks), rtrwTOF); outputCollisionsSels(fitInfo.ampFT0A, fitInfo.ampFT0C, fitInfo.timeFT0A, fitInfo.timeFT0C, @@ -283,17 +354,18 @@ struct DGCandProducer { fitInfo.BBFT0Apf, fitInfo.BBFT0Cpf, fitInfo.BGFT0Apf, fitInfo.BGFT0Cpf, fitInfo.BBFV0Apf, fitInfo.BGFV0Apf, fitInfo.BBFDDApf, fitInfo.BBFDDCpf, fitInfo.BGFDDApf, fitInfo.BGFDDCpf); + outputCollisionSelExtras(chFT0A, chFT0C, chFDDA, chFDDC, chFV0A, occ, ir, trs, trofs, hmpr, tfb, itsROFb, sbp, zVtxFT0vPv, vtxITSTPC); outputCollsLabels(collision.globalIndex()); // update DGTracks tables - for (auto& track : tracks) { + for (const auto& track : tracks) { if (saveAllTracks || track.isPVContributor()) { updateUDTrackTables(outputCollisions.lastIndex(), track, bc.globalBC()); } } // update DGFwdTracks tables - for (auto& fwdtrack : fwdtracks) { + for (const auto& fwdtrack : fwdtracks) { updateUDFwdTrackTables(fwdtrack, bc.globalBC()); } @@ -320,7 +392,7 @@ struct DGCandProducer { auto cnt = 0; float pt1 = 0., pt2 = 0.; float signalTPC1 = 0., signalTPC2 = 0.; - for (auto tr : tracks) { + for (const auto& tr : tracks) { if (tr.isPVContributor()) { cnt++; switch (cnt) { @@ -336,13 +408,61 @@ struct DGCandProducer { cnt, tr.isGlobalTrack(), tr.pt(), tr.itsNCls(), tr.tpcNClsCrossedRows(), tr.hasTRD(), tr.hasTOF()); } } - registry.get(HIST("reco/pt1Vspt2"))->Fill(pt1, pt2); - registry.get(HIST("reco/TPCsignal1"))->Fill(pt1, signalTPC1); - registry.get(HIST("reco/TPCsignal2"))->Fill(pt2, signalTPC2); - registry.get(HIST("reco/sig1VsSig2TPC"))->Fill(signalTPC1, signalTPC2); + getHist(TH2, histdir + "/pt1Vspt2")->Fill(pt1, pt2); + getHist(TH2, histdir + "/TPCsignal1")->Fill(pt1, signalTPC1); + getHist(TH2, histdir + "/TPCsignal2")->Fill(pt2, signalTPC2); + getHist(TH2, histdir + "/sig1VsSig2TPC")->Fill(signalTPC1, signalTPC2); } } } + + void init(InitContext& context) + { + // initialize zorro + mRunNumber = -1; + zorroSummary.setObject(zorro.getZorroSummary()); + zorro.setBaseCCDBPath(cfgZorroCCDBpath.value); + ccdb->setURL(cfgCCDBurl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + // DGCuts + diffCuts = (DGCutparHolder)DGCuts; + + // add histograms for the different process functions + histPointers.clear(); + if (context.mOptions.get("processData")) { + createHistograms("reco"); + } + if (context.mOptions.get("processMcData")) { + createHistograms("MCreco"); + } + } + + // process function for reconstructed data + void processData(CC const& collision, BCs const& bcs, TCs const& tracks, FWs const& fwdtracks, + aod::Zdcs const& /*zdcs*/, aod::FV0As const& fv0as, aod::FT0s const& ft0s, aod::FDDs const& fdds) + { + processReco(std::string("reco"), collision, bcs, tracks, fwdtracks, fv0as, ft0s, fdds); + } + PROCESS_SWITCH(DGCandProducer, processData, "Produce UD table with data", true); + + // process function for reconstructed MC data + void processMcData(MCCC const& collision, aod::McCollisions const& /*mccollisions*/, BCs const& bcs, + TCs const& tracks, FWs const& fwdtracks, aod::Zdcs const& /*zdcs*/, aod::FV0As const& fv0as, + aod::FT0s const& ft0s, aod::FDDs const& fdds) + { + // select specific processes with the GeneratorID + auto mccol = collision.mcCollision(); + LOGF(debug, "GeneratorId %d (%d)", mccol.getGeneratorId(), generatorIds->size()); + + if (std::find(generatorIds->begin(), generatorIds->end(), mccol.getGeneratorId()) != generatorIds->end()) { + LOGF(debug, "Event with good generatorId"); + processReco(std::string("MCreco"), collision, bcs, tracks, fwdtracks, fv0as, ft0s, fdds); + } + } + PROCESS_SWITCH(DGCandProducer, processMcData, "Produce UD tables with MC data", false); }; struct McDGCandProducer { @@ -352,6 +472,10 @@ struct McDGCandProducer { Produces outputMcCollsLabels; Produces outputMcTrackLabels; + // save all McTruth, even if the collisions is not reconstructed + Configurable> generatorIds{"generatorIds", std::vector{-1}, "MC generatorIds to process"}; + Configurable saveAllMcCollisions{"saveAllMcCollisions", true, "save all McCollisions"}; + using CCs = soa::Join; using BCs = soa::Join; using TCs = soa::Join; @@ -371,8 +495,10 @@ struct McDGCandProducer { template void updateUDMcCollisions(TMcCollision const& mccol) { + LOGF(debug, ""); // save mccol - outputMcCollisions(mccol.bcId(), + auto bc = mccol.template bc_as(); + outputMcCollisions(bc.globalBC(), mccol.generatorsID(), mccol.posX(), mccol.posY(), @@ -385,6 +511,8 @@ struct McDGCandProducer { template void updateUDMcParticle(TMcParticle const& McPart, int64_t McCollisionId, std::map& mcPartIsSaved) { + LOGF(debug, " McCollisionId %d", McCollisionId); + // save McPart // mother and daughter indices are set to -1 // ATTENTION: this can be improved to also include mother and daughter indices @@ -411,38 +539,75 @@ struct McDGCandProducer { template void updateUDMcParticles(TMcParticles const& McParts, int64_t McCollisionId, std::map& mcPartIsSaved) { + LOGF(debug, " number of McParticles %d", McParts.size()); + LOGF(debug, " McCollisionId %d", McCollisionId); + + /* + LOGF(info, "PStack"); + for (auto const& part : McParts) { + LOGF(info, "P - Id %d PID %d", part.globalIndex(), part.pdgCode()); + for (auto const& mother : part.template mothers_as()) { + LOGF(info, " M - Id %d PID %d", mother.globalIndex(), mother.pdgCode()); + } + for (auto const& daughter : part.template daughters_as()) { + LOGF(info, " D - Id %d PID %d", daughter.globalIndex(), daughter.pdgCode()); + } + } + LOGF(info, ""); + */ + // save McParts // new mother and daughter ids std::vector newmids; int32_t newdids[2] = {-1, -1}; int64_t newval = -1; + // Determine the particle indices within the UDMcParticles table + // before filling the table + // This is needed to be able to assign the new daughter indices + std::map oldnew; + auto lastId = outputMcParticles.lastIndex(); + for (const auto& mcpart : McParts) { + auto oldId = mcpart.globalIndex(); + if (mcPartIsSaved.find(oldId) != mcPartIsSaved.end()) { + oldnew[oldId] = mcPartIsSaved[oldId]; + } else { + lastId++; + oldnew[oldId] = lastId; + } + } + // all particles of the McCollision are saved - for (auto mcpart : McParts) { + for (const auto& mcpart : McParts) { + LOGF(debug, " p (%d) %d", mcpart.pdgCode(), mcpart.globalIndex()); if (mcPartIsSaved.find(mcpart.globalIndex()) == mcPartIsSaved.end()) { - // correct mother and daughter IDs + // mothers newmids.clear(); auto oldmids = mcpart.mothersIds(); - for (uint ii = 0; ii < oldmids.size(); ii++) { - if (mcPartIsSaved.find(oldmids[ii]) != mcPartIsSaved.end()) { - newval = mcPartIsSaved[oldmids[ii]]; - LOGF(debug, " mid %i / %i", oldmids[ii], newval); + for (const auto& oldmid : oldmids) { + auto m = McParts.rawIteratorAt(oldmid); + LOGF(debug, " m %d", m.globalIndex()); + if (mcPartIsSaved.find(oldmid) != mcPartIsSaved.end()) { + newval = mcPartIsSaved[oldmid]; } else { newval = -1; } + LOGF(debug, " mid o %i n %i", oldmid, newval); newmids.push_back(newval); } + + // daughters auto olddids = mcpart.daughtersIds(); for (uint ii = 0; ii < olddids.size(); ii++) { - if (mcPartIsSaved.find(olddids[ii]) != mcPartIsSaved.end()) { - newval = mcPartIsSaved[olddids[ii]]; - LOGF(debug, " did %i / %i", olddids[ii], newval); + if (oldnew.find(olddids[ii]) != oldnew.end()) { + newval = oldnew[olddids[ii]]; } else { newval = -1; } + LOGF(debug, " did o %i n %i", olddids[ii], newval); newdids[ii] = newval; } - LOGF(debug, " ms %i ds %i", oldmids.size(), olddids.size()); + LOGF(debug, " ms %i ds %i", oldmids.size(), olddids.size()); // update UDMcParticles outputMcParticles(McCollisionId, @@ -457,6 +622,7 @@ struct McDGCandProducer { mcpart.pz(), mcpart.e()); mcPartIsSaved[mcpart.globalIndex()] = outputMcParticles.lastIndex(); + LOGF(debug, " mcpart %d -> udmcpart %d", mcpart.globalIndex(), mcPartIsSaved[mcpart.globalIndex()]); } } } @@ -487,7 +653,7 @@ struct McDGCandProducer { void updateUDMcTrackLabels(TTrack const& udtracks, std::map& mcPartIsSaved) { // loop over all tracks - for (auto udtrack : udtracks) { + for (const auto& udtrack : udtracks) { // udtrack (UDTCs) -> track (TCs) -> mcTrack (McParticles) -> udMcTrack (UDMcParticles) auto trackId = udtrack.trackId(); if (trackId >= 0) { @@ -508,30 +674,10 @@ struct McDGCandProducer { } } - void init(InitContext& context) - { - // add histograms for the different process functions - if (context.mOptions.get("processMC")) { - registry.add("mcTruth/collisions", "Number of associated collisions", {HistType::kTH1F, {{11, -0.5, 10.5}}}); - registry.add("mcTruth/collType", "Collision type", {HistType::kTH1F, {{5, -0.5, 4.5}}}); - registry.add("mcTruth/IVMpt", "Invariant mass versus p_{T}", {HistType::kTH2F, {{150, 0.0, 3.0}, {150, 0.0, 3.0}}}); - } - } - - // process function for MC data - // save the MC truth of all events of interest and of the DG events - void processMC(aod::McCollisions const& mccols, aod::McParticles const& mcparts, - UDCCs const& dgcands, UDTCs const& udtracks, - CCs const& /*collisions*/, BCs const& /*bcs*/, TCs const& /*tracks*/) + // updating McTruth data and links to reconstructed data + void procWithDgCand(aod::McCollisions const& mccols, aod::McParticles const& mcparts, + UDCCs const& dgcands, UDTCs const& udtracks) { - LOGF(info, "Number of McCollisions %d", mccols.size()); - LOGF(info, "Number of DG candidates %d", dgcands.size()); - LOGF(info, "Number of UD tracks %d", udtracks.size()); - if (dgcands.size() <= 0) { - LOGF(info, "No DG candidates to save!"); - return; - } - // use a hash table to keep track of the McCollisions which have been added to the UDMcCollision table // {McCollisionId : udMcCollisionId} // similar for the McParticles which have been added to the UDMcParticle table @@ -541,36 +687,42 @@ struct McDGCandProducer { // loop over McCollisions and UDCCs simultaneously auto mccol = mccols.iteratorAt(0); - auto dgcand = dgcands.iteratorAt(0); + auto mcOfInterest = std::find(generatorIds->begin(), generatorIds->end(), mccol.getGeneratorId()) != generatorIds->end(); auto lastmccol = mccols.iteratorAt(mccols.size() - 1); + auto mccolAtEnd = false; + + auto dgcand = dgcands.iteratorAt(0); auto lastdgcand = dgcands.iteratorAt(dgcands.size() - 1); + auto dgcandAtEnd = false; // advance dgcand and mccol until both are AtEnd int64_t mccolId = mccol.globalIndex(); int64_t mcdgId = -1; - auto dgcandAtEnd = dgcand == lastdgcand; - auto mccolAtEnd = mccol == lastmccol; + int64_t colId = -1; + bool goon = true; while (goon) { - // check if dgcand has an associated McCollision - if (!dgcand.has_collision()) { - mcdgId = -1; - } else { + // check if dgcand has an associated Collision and McCollision + if (dgcand.has_collision()) { auto dgcandCol = dgcand.collision_as(); - if (!dgcandCol.has_mcCollision()) { - mcdgId = -1; - } else { + colId = dgcandCol.globalIndex(); + if (dgcandCol.has_mcCollision()) { mcdgId = dgcandCol.mcCollision().globalIndex(); + } else { + mcdgId = -1; } + } else { + colId = -1; + mcdgId = -1; } - LOGF(info, "\nStart of loop mcdgId %d mccolId %d", mcdgId, mccolId); + LOGF(debug, ""); + LOGF(debug, "dgcand %d mcdgId %d colId %d mccolId %d - UDMcCollsLabels %d UDMcCollisions %d", dgcand.globalIndex(), mcdgId, colId, mccolId, outputMcCollsLabels.lastIndex(), outputMcCollisions.lastIndex()); // two cases to consider - // 1. the event to process is a dgcand. In this case the Mc tables as well as the McLabel tables are updated - // 2. the event to process is an event of interest. In this case only the Mc tables are updated + // 1. mcdgId <= mccolId: the event to process is a dgcand. In this case the Mc tables as well as the McLabel tables are updated + // 2. mccolId < mcdgId: the event to process is an MC event of interest without reconstructed dgcand. In this case only the Mc tables are updated if ((!dgcandAtEnd && !mccolAtEnd && (mcdgId <= mccolId)) || mccolAtEnd) { // this is case 1. - LOGF(info, "Doing case 1 with mcdgId %d", mcdgId); // update UDMcCollisions and UDMcColsLabels (for each UDCollision -> UDMcCollisions) // update UDMcParticles and UDMcTrackLabels (for each UDTrack -> UDMcParticles) @@ -579,16 +731,19 @@ struct McDGCandProducer { // If the dgcand has an associated McCollision then the McCollision and all associated // McParticles are saved - if (mcdgId >= 0) { + // but only consider generated events of interest + if (mcdgId >= 0 && mcOfInterest) { + if (mcColIsSaved.find(mcdgId) == mcColIsSaved.end()) { - LOGF(info, " Saving McCollision %d", mcdgId); // update UDMcCollisions + LOGF(debug, " writing mcCollision %d to UDMcCollisions", mcdgId); auto dgcandMcCol = dgcand.collision_as().mcCollision(); updateUDMcCollisions(dgcandMcCol); mcColIsSaved[mcdgId] = outputMcCollisions.lastIndex(); } // update UDMcColsLabels (for each UDCollision -> UDMcCollisions) + LOGF(debug, " writing %d to outputMcCollsLabels", mcColIsSaved[mcdgId]); outputMcCollsLabels(mcColIsSaved[mcdgId]); // update UDMcParticles @@ -601,19 +756,24 @@ struct McDGCandProducer { } else { // If the dgcand has no associated McCollision then only the McParticles which are associated // with the tracks of the dgcand are saved - LOGF(info, " Saving McCollision %d", -1); // update UDMcColsLabels (for each UDCollision -> UDMcCollisions) + LOGF(debug, " writing %d to UDMcCollsLabels", -1); outputMcCollsLabels(-1); // update UDMcParticles and UDMcTrackLabels (for each UDTrack -> UDMcParticles) // loop over tracks of dgcand - for (auto dgtrack : dgTracks) { + for (const auto& dgtrack : dgTracks) { if (dgtrack.has_track()) { auto track = dgtrack.track_as(); if (track.has_mcParticle()) { auto mcPart = track.mcParticle(); - updateUDMcParticle(mcPart, -1, mcPartIsSaved); + auto mcCol = mcPart.mcCollision(); + if (mcColIsSaved.find(mcCol.globalIndex()) == mcColIsSaved.end()) { + updateUDMcCollisions(mcCol); + mcColIsSaved[mcCol.globalIndex()] = outputMcCollisions.lastIndex(); + } + updateUDMcParticle(mcPart, mcColIsSaved[mcCol.globalIndex()], mcPartIsSaved); updateUDMcTrackLabel(dgtrack, mcPartIsSaved); } else { outputMcTrackLabels(-1, track.mcMask()); @@ -631,12 +791,13 @@ struct McDGCandProducer { } } else { // this is case 2. - LOGF(info, "Doing case 2"); // update UDMcCollisions and UDMcParticles - if (mcColIsSaved.find(mccolId) == mcColIsSaved.end()) { - LOGF(info, " Saving McCollision %d", mccolId); + // but only consider generated events of interest + if (mcOfInterest && mcColIsSaved.find(mccolId) == mcColIsSaved.end()) { + // update UDMcCollisions + LOGF(debug, " writing mcCollision %d to UDMcCollisions", mccolId); updateUDMcCollisions(mccol); mcColIsSaved[mccolId] = outputMcCollisions.lastIndex(); @@ -648,17 +809,81 @@ struct McDGCandProducer { // advance mccol if (mccol != lastmccol) { mccol++; + mcOfInterest = std::find(generatorIds->begin(), generatorIds->end(), mccol.getGeneratorId()) != generatorIds->end(); mccolId = mccol.globalIndex(); } else { mccolAtEnd = true; } } - + LOGF(info, " UDMcCollsLabels %d (of %d) UDMcCollisions %d", outputMcCollsLabels.lastIndex(), dgcands.size() - 1, outputMcCollisions.lastIndex()); goon = !dgcandAtEnd || !mccolAtEnd; - LOGF(info, "End of loop mcdgId %d mccolId %d", mcdgId, mccolId); } } - PROCESS_SWITCH(McDGCandProducer, processMC, "Produce MC tables", false); + + // updating McTruth data only + void procWithoutDgCand(aod::McCollisions const& mccols, aod::McParticles const& mcparts) + { + // use a hash table to keep track of the McCollisions which have been added to the UDMcCollision table + // {McCollisionId : udMcCollisionId} + // similar for the McParticles which have been added to the UDMcParticle table + // {McParticleId : udMcParticleId} + std::map mcColIsSaved; + std::map mcPartIsSaved; + + // loop over McCollisions + for (auto const& mccol : mccols) { + // only consider generated events of interest + if (std::find(generatorIds->begin(), generatorIds->end(), mccol.getGeneratorId()) == generatorIds->end()) + continue; + + int64_t mccolId = mccol.globalIndex(); + // update UDMcCollisions and UDMcParticles + if (mcColIsSaved.find(mccolId) == mcColIsSaved.end()) { + + // update UDMcCollisions + LOGF(debug, " writing mcCollision %d to UDMcCollisions", mccolId); + updateUDMcCollisions(mccol); + mcColIsSaved[mccolId] = outputMcCollisions.lastIndex(); + + // update UDMcParticles + auto mcPartsSlice = mcparts.sliceBy(mcPartsPerMcCollision, mccolId); + updateUDMcParticles(mcPartsSlice, mcColIsSaved[mccolId], mcPartIsSaved); + } + } + } + + void init(InitContext& context) + { + // add histograms for the different process functions + if (context.mOptions.get("processMCTruth")) { + LOGF(info, "Preparing histograms for processMCTruth."); + registry.add("mcTruth/collisions", "Number of associated collisions", {HistType::kTH1F, {{11, -0.5, 10.5}}}); + registry.add("mcTruth/collType", "Collision type", {HistType::kTH1F, {{5, -0.5, 4.5}}}); + registry.add("mcTruth/IVMpt", "Invariant mass versus p_{T}", {HistType::kTH2F, {{150, 0.0, 3.0}, {150, 0.0, 3.0}}}); + } + } + + // process function for MC data + // save the MC truth of all events of interest and of the DG events + void processMCTruth(aod::McCollisions const& mccols, aod::McParticles const& mcparts, + UDCCs const& dgcands, UDTCs const& udtracks, + CCs const& /*collisions*/, BCs const& /*bcs*/, TCs const& /*tracks*/) + { + LOGF(info, "Number of McCollisions %d", mccols.size()); + LOGF(info, "Number of DG candidates %d", dgcands.size()); + LOGF(info, "Number of UD tracks %d", udtracks.size()); + + if (mccols.size() > 0) { + if (dgcands.size() > 0) { + procWithDgCand(mccols, mcparts, dgcands, udtracks); + } else { + if (saveAllMcCollisions) { + procWithoutDgCand(mccols, mcparts); + } + } + } + } + PROCESS_SWITCH(McDGCandProducer, processMCTruth, "Produce MC tables", false); void processDummy(aod::Collisions const& /*collisions*/) { diff --git a/PWGUD/TableProducer/SGCandProducer.cxx b/PWGUD/TableProducer/SGCandProducer.cxx index ae90f2f8892..bc42a71016b 100644 --- a/PWGUD/TableProducer/SGCandProducer.cxx +++ b/PWGUD/TableProducer/SGCandProducer.cxx @@ -10,15 +10,25 @@ // or submit itself to any jurisdiction. #include +#include +#include +#include +#include "CCDB/BasicCCDBManager.h" #include "Framework/ASoA.h" #include "Framework/AnalysisDataModel.h" -#include "Common/CCDB/EventSelectionParams.h" -#include "Common/DataModel/EventSelection.h" +#include "ReconstructionDataFormats/Vertex.h" #include "CommonConstants/LHCConstants.h" #include "DataFormatsFIT/Triggers.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" -#include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/DataModel/EventSelection.h" #include "PWGUD/DataModel/UDTables.h" #include "PWGUD/Core/UPCHelpers.h" #include "PWGUD/Core/SGSelector.h" @@ -26,11 +36,32 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::dataformats; + +#define getHist(type, name) std::get>(histPointers[name]) struct SGCandProducer { + Service ccdb; + // data inputs + using CCs = soa::Join; + using CC = CCs::iterator; + using BCs = soa::Join; + using BC = BCs::iterator; + using TCs = soa::Join; + using FWs = aod::FwdTracks; + + using MCCCs = soa::Join; + using MCCC = MCCCs::iterator; + // get an SGCutparHolder SGCutParHolder sameCuts = SGCutParHolder(); // SGCutparHolder Configurable SGCuts{"SGCuts", {}, "SG event cuts"}; + Configurable verboseInfo{"verboseInfo", false, "Print general info to terminal; default it false."}; Configurable saveAllTracks{"saveAllTracks", true, "save only PV contributors or all tracks associated to a collision"}; Configurable savenonPVCITSOnlyTracks{"savenonPVCITSOnlyTracks", false, "save non PV contributors with ITS only information"}; Configurable rejectAtTFBoundary{"rejectAtTFBoundary", true, "reject collisions at a TF boundary"}; @@ -38,20 +69,28 @@ struct SGCandProducer { Configurable noSameBunchPileUp{"noSameBunchPileUp", true, "reject SameBunchPileUp"}; Configurable IsGoodVertex{"IsGoodVertex", false, "Select FT0 PV vertex matching"}; Configurable ITSTPCVertex{"ITSTPCVertex", true, "reject ITS-only vertex"}; // if one wants to look at Single Gap pp events + Configurable> generatorIds{"generatorIds", std::vector{-1}, "MC generatorIds to process"}; + + // Configurables to decide which tables are filled + Configurable fillTrackTables{"fillTrackTables", true, "Fill track tables"}; + Configurable fillFwdTrackTables{"fillFwdTrackTables", true, "Fill forward track tables"}; // SG selector SGSelector sgSelector; + ctpRateFetcher mRateFetcher; // data tables Produces outputSGCollisions; Produces outputCollisions; Produces outputCollisionsSels; + Produces outputCollisionSelExtras; Produces outputCollsLabels; Produces outputZdcs; - Produces udZdcsReduced; + Produces udZdcsReduced; Produces outputTracks; Produces outputTracksCov; Produces outputTracksDCA; Produces outputTracksPID; + Produces outputTracksPIDExtra; Produces outputTracksExtra; Produces outputTracksFlag; Produces outputFwdTracks; @@ -62,17 +101,7 @@ struct SGCandProducer { HistogramRegistry registry{ "registry", {}}; - - // data inputs - using CCs = soa::Join; - using CC = CCs::iterator; - using BCs = soa::Join; - using BC = BCs::iterator; - using TCs = soa::Join; - using FWs = aod::FwdTracks; + std::map histPointers; // function to update UDFwdTracks, UDFwdTracksExtra template @@ -81,11 +110,13 @@ struct SGCandProducer { outputFwdTracks(outputCollisions.lastIndex(), fwdtrack.px(), fwdtrack.py(), fwdtrack.pz(), fwdtrack.sign(), bcnum, fwdtrack.trackTime(), fwdtrack.trackTimeRes()); - outputFwdTracksExtra(fwdtrack.nClusters(), + outputFwdTracksExtra(fwdtrack.trackType(), + fwdtrack.nClusters(), fwdtrack.pDca(), fwdtrack.rAtAbsorberEnd(), fwdtrack.chi2(), fwdtrack.chi2MatchMCHMID(), + fwdtrack.chi2MatchMCHMFT(), fwdtrack.mchBitMap(), fwdtrack.midBitMap(), fwdtrack.midBoards()); @@ -119,6 +150,14 @@ struct SGCandProducer { track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()); + outputTracksPIDExtra(track.tpcNSigmaDe(), + track.tpcNSigmaTr(), + track.tpcNSigmaHe(), + track.tpcNSigmaAl(), + track.tofNSigmaDe(), + track.tofNSigmaTr(), + track.tofNSigmaHe(), + track.tofNSigmaAl()); outputTracksExtra(track.tpcInnerParam(), track.itsClusterSizes(), track.tpcNClsFindable(), @@ -141,49 +180,60 @@ struct SGCandProducer { outputTracksLabel(track.globalIndex()); } - void init(InitContext&) - { - sameCuts = (SGCutParHolder)SGCuts; - registry.add("reco/Stat", "Cut statistics; Selection criterion; Collisions", {HistType::kTH1F, {{14, -0.5, 13.5}}}); - } - - // process function for real data - void process(CC const& collision, BCs const& bcs, TCs& tracks, FWs& fwdtracks, - aod::Zdcs& zdcs, aod::FT0s& ft0s, aod::FV0As& fv0as, aod::FDDs& fdds) + // function to process reconstructed data + template + void processReco(std::string histdir, TCol const& collision, BCs const& bcs, + TCs const& tracks, FWs const& fwdtracks, + aod::FV0As const& fv0as, aod::FT0s const& ft0s, aod::FDDs const& fdds) { - LOGF(debug, " collision %d", collision.globalIndex()); - registry.get(HIST("reco/Stat"))->Fill(0., 1.); + if (verboseInfo) + LOGF(debug, " collision %d", collision.globalIndex()); + getHist(TH1, histdir + "/Stat")->Fill(0., 1.); // reject collisions at TF boundaries if (rejectAtTFBoundary && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { return; } + getHist(TH1, histdir + "/Stat")->Fill(1., 1.); // reject collisions at ITS RO TF boundaries if (noITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { return; } - // registry.get(HIST("reco/Stat"))->Fill(1., 1.); + getHist(TH1, histdir + "/Stat")->Fill(2., 1.); // reject Same Bunch PileUp if (noSameBunchPileUp && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { return; } - // registry.get(HIST("reco/Stat"))->Fill(1., 1.); + getHist(TH1, histdir + "/Stat")->Fill(3., 1.); // check vertex matching to FT0 if (IsGoodVertex && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { return; } - // registry.get(HIST("reco/Stat"))->Fill(1., 1.); + getHist(TH1, histdir + "/Stat")->Fill(4., 1.); // reject ITS Only vertices if (ITSTPCVertex && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) { return; } - // registry.get(HIST("reco/Stat"))->Fill(1., 1.); - // registry.get(HIST("reco/Stat"))->Fill(1., 1.); + getHist(TH1, histdir + "/Stat")->Fill(5., 1.); // nominal BC if (!collision.has_foundBC()) { return; } - registry.get(HIST("reco/Stat"))->Fill(2., 1.); - auto bc = collision.foundBC_as(); + getHist(TH1, histdir + "/Stat")->Fill(6., 1.); + int trs = collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) ? 1 : 0; + int trofs = collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard) ? 1 : 0; + int hmpr = collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof) ? 1 : 0; + int tfb = collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) ? 1 : 0; + int itsROFb = collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder) ? 1 : 0; + int sbp = collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup) ? 1 : 0; + int zVtxFT0vPv = collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV) ? 1 : 0; + int vtxITSTPC = collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC) ? 1 : 0; + auto bc = collision.template foundBC_as(); + double ir = 0.; + const uint64_t ts = bc.timestamp(); + const int runnumber = bc.runNumber(); + if (bc.has_zdc()) { + ir = mRateFetcher.fetch(ccdb.service, ts, runnumber, "ZNC hadronic") * 1.e-3; + } auto newbc = bc; // obtain slice of compatible BCs @@ -191,25 +241,35 @@ struct SGCandProducer { auto isSGEvent = sgSelector.IsSelected(sameCuts, collision, bcRange, bc); // auto isSGEvent = sgSelector.IsSelected(sameCuts, collision, bcRange, tracks); int issgevent = isSGEvent.value; - if (isSGEvent.bc) { + if (isSGEvent.bc && issgevent < 2) { newbc = *(isSGEvent.bc); } else { - LOGF(info, "No Newbc %i", bc.globalBC()); + if (verboseInfo) + LOGF(info, "No Newbc %i", bc.globalBC()); } - registry.get(HIST("reco/Stat"))->Fill(issgevent + 3, 1.); + getHist(TH1, histdir + "/Stat")->Fill(issgevent + 8, 1.); if (issgevent <= 2) { - // LOGF(info, "Current BC: %i, %i, %i", bc.globalBC(), newbc.globalBC(), issgevent); + if (verboseInfo) + LOGF(info, "Current BC: %i, %i, %i", bc.globalBC(), newbc.globalBC(), issgevent); if (sameCuts.minRgtrwTOF()) { if (udhelpers::rPVtrwTOF(tracks, collision.numContrib()) < sameCuts.minRgtrwTOF()) return; } upchelpers::FITInfo fitInfo{}; - udhelpers::getFITinfo(fitInfo, newbc.globalBC(), bcs, ft0s, fv0as, fdds); + uint8_t chFT0A = 0; + uint8_t chFT0C = 0; + uint8_t chFDDA = 0; + uint8_t chFDDC = 0; + uint8_t chFV0A = 0; + int occ = collision.trackOccupancyInTimeRange(); + udhelpers::getFITinfo(fitInfo, newbc, bcs, ft0s, fv0as, fdds); + int upc_flag = (collision.flags() & dataformats::Vertex>::Flags::UPCMode) ? 1 : 0; // update SG candidates tables outputCollisions(bc.globalBC(), bc.runNumber(), - collision.posX(), collision.posY(), collision.posZ(), + collision.posX(), collision.posY(), collision.posZ(), upc_flag, collision.numContrib(), udhelpers::netCharge(tracks), 1.); // rtrwTOF); //omit the calculation to speed up the things while skimming + outputSGCollisions(issgevent); outputCollisionsSels(fitInfo.ampFT0A, fitInfo.ampFT0C, fitInfo.timeFT0A, fitInfo.timeFT0C, fitInfo.triggerMaskFT0, @@ -219,6 +279,7 @@ struct SGCandProducer { fitInfo.BBFT0Apf, fitInfo.BBFT0Cpf, fitInfo.BGFT0Apf, fitInfo.BGFT0Cpf, fitInfo.BBFV0Apf, fitInfo.BGFV0Apf, fitInfo.BBFDDApf, fitInfo.BBFDDCpf, fitInfo.BGFDDApf, fitInfo.BGFDDCpf); + outputCollisionSelExtras(chFT0A, chFT0C, chFDDA, chFDDC, chFV0A, occ, ir, trs, trofs, hmpr, tfb, itsROFb, sbp, zVtxFT0vPv, vtxITSTPC); outputCollsLabels(collision.globalIndex()); if (newbc.has_zdc()) { auto zdc = newbc.zdc(); @@ -227,32 +288,490 @@ struct SGCandProducer { udZdcsReduced(outputCollisions.lastIndex(), -999, -999, -999, -999); } // update SGTracks tables - for (auto& track : tracks) { - if (track.pt() > sameCuts.minPt() && track.eta() > sameCuts.minEta() && track.eta() < sameCuts.maxEta()) { - if (track.isPVContributor()) { - updateUDTrackTables(outputCollisions.lastIndex(), track, bc.globalBC()); - } else if (saveAllTracks) { - if (track.itsClusterSizes() && track.itsChi2NCl() > 0 && ((track.tpcNClsFindable() == 0 && savenonPVCITSOnlyTracks) || track.tpcNClsFindable() > 50)) + if (fillTrackTables) { + for (auto& track : tracks) { + if (track.pt() > sameCuts.minPt() && track.eta() > sameCuts.minEta() && track.eta() < sameCuts.maxEta()) { + if (track.isPVContributor()) { updateUDTrackTables(outputCollisions.lastIndex(), track, bc.globalBC()); - // if (track.isPVContributor()) updateUDTrackTables(outputCollisions.lastIndex(), track, bc.globalBC()); + } else if (saveAllTracks) { + if (track.itsClusterSizes() && track.itsChi2NCl() > 0 && ((track.tpcNClsFindable() == 0 && savenonPVCITSOnlyTracks) || track.tpcNClsFindable() > 50)) + updateUDTrackTables(outputCollisions.lastIndex(), track, bc.globalBC()); + // if (track.isPVContributor()) updateUDTrackTables(outputCollisions.lastIndex(), track, bc.globalBC()); + } } } } // update SGFwdTracks tables - if (sameCuts.withFwdTracks()) { - for (auto& fwdtrack : fwdtracks) { - if (!sgSelector.FwdTrkSelector(fwdtrack)) - updateUDFwdTrackTables(fwdtrack, bc.globalBC()); + if (fillFwdTrackTables) { + if (sameCuts.withFwdTracks()) { + for (auto& fwdtrack : fwdtracks) { + if (!sgSelector.FwdTrkSelector(fwdtrack)) + updateUDFwdTrackTables(fwdtrack, bc.globalBC()); + } } } } } + + void init(InitContext& context) + { + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); + sameCuts = (SGCutParHolder)SGCuts; + + // add histograms for the different process functions + histPointers.clear(); + if (context.mOptions.get("processData")) { + histPointers.insert({"reco/Stat", registry.add("reco/Stat", "Cut statistics; Selection criterion; Collisions", {HistType::kTH1F, {{14, -0.5, 13.5}}})}); + } + if (context.mOptions.get("processMcData")) { + histPointers.insert({"MCreco/Stat", registry.add("MCreco/Stat", "Cut statistics; Selection criterion; Collisions", {HistType::kTH1F, {{14, -0.5, 13.5}}})}); + } + } + + // process function for reconstructed data + void processData(CC const& collision, BCs const& bcs, TCs const& tracks, FWs const& fwdtracks, + aod::Zdcs const& /*zdcs*/, aod::FV0As const& fv0as, aod::FT0s const& ft0s, aod::FDDs const& fdds) + { + processReco(std::string("reco"), collision, bcs, tracks, fwdtracks, fv0as, ft0s, fdds); + } + PROCESS_SWITCH(SGCandProducer, processData, "Produce UD table with data", true); + + // process function for reconstructed MC data + void processMcData(MCCC const& collision, aod::McCollisions const& /*mccollisions*/, BCs const& bcs, + TCs const& tracks, FWs const& fwdtracks, aod::Zdcs const& /*zdcs*/, aod::FV0As const& fv0as, + aod::FT0s const& ft0s, aod::FDDs const& fdds) + { + // select specific processes with the GeneratorID + if (!collision.has_mcCollision()) + return; + auto mccol = collision.mcCollision(); + if (verboseInfo) + LOGF(info, "GeneratorId %d (%d)", mccol.getGeneratorId(), generatorIds->size()); + + if (std::find(generatorIds->begin(), generatorIds->end(), mccol.getGeneratorId()) != generatorIds->end()) { + if (verboseInfo) + LOGF(info, "Event with good generatorId"); + processReco(std::string("MCreco"), collision, bcs, tracks, fwdtracks, fv0as, ft0s, fdds); + } + } + PROCESS_SWITCH(SGCandProducer, processMcData, "Produce UD tables with MC data", false); +}; + +struct McSGCandProducer { + // MC tables + Configurable verboseInfoMC{"verboseInfoMC", false, "Print general info to terminal; default it false."}; + Produces outputMcCollisions; + Produces outputMcParticles; + Produces outputMcCollsLabels; + Produces outputMcTrackLabels; + + // save all McTruth, even if the collisions is not reconstructed + Configurable> generatorIds{"generatorIds", std::vector{-1}, "MC generatorIds to process"}; + Configurable saveAllMcCollisions{"saveAllMcCollisions", true, "save all McCollisions"}; + + using CCs = soa::Join; + using BCs = soa::Join; + using TCs = soa::Join; + using UDCCs = soa::Join; + using UDTCs = soa::Join; + + // prepare slices + SliceCache cache; + PresliceUnsorted mcPartsPerMcCollision = aod::mcparticle::mcCollisionId; + Preslice udtracksPerUDCollision = aod::udtrack::udCollisionId; + + // initialize histogram registry + HistogramRegistry registry{ + "registry", + {}}; + + template + void updateUDMcCollisions(TMcCollision const& mccol, uint64_t globBC) + { + // save mccol + outputMcCollisions(globBC, + mccol.generatorsID(), + mccol.posX(), + mccol.posY(), + mccol.posZ(), + mccol.t(), + mccol.weight(), + mccol.impactParameter()); + } + + template + void updateUDMcParticle(TMcParticle const& McPart, int64_t McCollisionId, std::map& mcPartIsSaved) + { + // save McPart + // mother and daughter indices are set to -1 + // ATTENTION: this can be improved to also include mother and daughter indices + std::vector newmids; + int32_t newdids[2] = {-1, -1}; + + // update UDMcParticles + if (mcPartIsSaved.find(McPart.globalIndex()) == mcPartIsSaved.end()) { + outputMcParticles(McCollisionId, + McPart.pdgCode(), + McPart.statusCode(), + McPart.flags(), + newmids, + newdids, + McPart.weight(), + McPart.px(), + McPart.py(), + McPart.pz(), + McPart.e()); + mcPartIsSaved[McPart.globalIndex()] = outputMcParticles.lastIndex(); + } + } + + template + void updateUDMcParticles(TMcParticles const& McParts, int64_t McCollisionId, std::map& mcPartIsSaved) + { + // save McParts + // new mother and daughter ids + std::vector newmids; + int32_t newdids[2] = {-1, -1}; + int64_t newval = -1; + + // Determine the particle indices within the UDMcParticles table + // before filling the table + // This is needed to be able to assign the new daughter indices + std::map oldnew; + auto lastId = outputMcParticles.lastIndex(); + for (auto mcpart : McParts) { + auto oldId = mcpart.globalIndex(); + if (mcPartIsSaved.find(oldId) != mcPartIsSaved.end()) { + oldnew[oldId] = mcPartIsSaved[oldId]; + } else { + lastId++; + oldnew[oldId] = lastId; + } + } + + // all particles of the McCollision are saved + for (auto mcpart : McParts) { + if (mcPartIsSaved.find(mcpart.globalIndex()) == mcPartIsSaved.end()) { + // mothers + newmids.clear(); + auto oldmids = mcpart.mothersIds(); + for (auto oldmid : oldmids) { + auto m = McParts.rawIteratorAt(oldmid); + if (verboseInfoMC) + LOGF(debug, " m %d", m.globalIndex()); + if (mcPartIsSaved.find(oldmid) != mcPartIsSaved.end()) { + newval = mcPartIsSaved[oldmid]; + } else { + newval = -1; + } + newmids.push_back(newval); + } + // daughters + auto olddids = mcpart.daughtersIds(); + for (uint ii = 0; ii < olddids.size(); ii++) { + if (oldnew.find(olddids[ii]) != oldnew.end()) { + newval = oldnew[olddids[ii]]; + } else { + newval = -1; + } + newdids[ii] = newval; + } + if (verboseInfoMC) + LOGF(debug, " ms %i ds %i", oldmids.size(), olddids.size()); + + // update UDMcParticles + outputMcParticles(McCollisionId, + mcpart.pdgCode(), + mcpart.statusCode(), + mcpart.flags(), + newmids, + newdids, + mcpart.weight(), + mcpart.px(), + mcpart.py(), + mcpart.pz(), + mcpart.e()); + mcPartIsSaved[mcpart.globalIndex()] = outputMcParticles.lastIndex(); + } + } + } + + template + void updateUDMcTrackLabel(TTrack const& udtrack, std::map& mcPartIsSaved) + { + // udtrack (UDTCs) -> track (TCs) -> mcTrack (McParticles) -> udMcTrack (UDMcParticles) + auto trackId = udtrack.trackId(); + if (trackId >= 0) { + auto track = udtrack.template track_as(); + auto mcTrackId = track.mcParticleId(); + if (mcTrackId >= 0) { + if (mcPartIsSaved.find(mcTrackId) != mcPartIsSaved.end()) { + outputMcTrackLabels(mcPartIsSaved[mcTrackId], track.mcMask()); + } else { + outputMcTrackLabels(-1, track.mcMask()); + } + } else { + outputMcTrackLabels(-1, track.mcMask()); + } + } else { + outputMcTrackLabels(-1, -1); + } + } + + template + void updateUDMcTrackLabels(TTrack const& udtracks, std::map& mcPartIsSaved) + { + // loop over all tracks + for (auto udtrack : udtracks) { + // udtrack (UDTCs) -> track (TCs) -> mcTrack (McParticles) -> udMcTrack (UDMcParticles) + auto trackId = udtrack.trackId(); + if (trackId >= 0) { + auto track = udtrack.template track_as(); + auto mcTrackId = track.mcParticleId(); + if (mcTrackId >= 0) { + if (mcPartIsSaved.find(mcTrackId) != mcPartIsSaved.end()) { + outputMcTrackLabels(mcPartIsSaved[mcTrackId], track.mcMask()); + } else { + outputMcTrackLabels(-1, track.mcMask()); + } + } else { + outputMcTrackLabels(-1, track.mcMask()); + } + } else { + outputMcTrackLabels(-1, -1); + } + } + } + + // updating McTruth data and links to reconstructed data + void procWithSgCand(aod::McCollisions const& mccols, aod::McParticles const& mcparts, + UDCCs const& sgcands, UDTCs const& udtracks) + { + // use a hash table to keep track of the McCollisions which have been added to the UDMcCollision table + // {McCollisionId : udMcCollisionId} + // similar for the McParticles which have been added to the UDMcParticle table + // {McParticleId : udMcParticleId} + std::map mcColIsSaved; + std::map mcPartIsSaved; + + // loop over McCollisions and UDCCs simultaneously + auto mccol = mccols.iteratorAt(0); + auto mcOfInterest = std::find(generatorIds->begin(), generatorIds->end(), mccol.getGeneratorId()) != generatorIds->end(); + auto lastmccol = mccols.iteratorAt(mccols.size() - 1); + auto mccolAtEnd = false; + + auto sgcand = sgcands.iteratorAt(0); + auto lastsgcand = sgcands.iteratorAt(sgcands.size() - 1); + auto sgcandAtEnd = false; + + // advance dgcand and mccol until both are AtEnd + int64_t mccolId = mccol.globalIndex(); + int64_t mcsgId = -1; + bool goon = true; + while (goon) { + auto globBC = mccol.bc_as().globalBC(); + // check if dgcand has an associated McCollision + if (sgcand.has_collision()) { + auto sgcandCol = sgcand.collision_as(); + // colId = sgcandCol.globalIndex(); + if (sgcandCol.has_mcCollision()) { + mcsgId = sgcandCol.mcCollision().globalIndex(); + } else { + mcsgId = -1; + } + } else { + mcsgId = -1; + } + if (verboseInfoMC) + LOGF(info, "\nStart of loop mcsgId %d mccolId %d", mcsgId, mccolId); + + // two cases to consider + // 1. mcdgId <= mccolId: the event to process is a dgcand. In this case the Mc tables as well as the McLabel tables are updated + // 2. mccolId < mcdgId: the event to process is an MC event of interest without reconstructed dgcand. In this case only the Mc tables are updated + if ((!sgcandAtEnd && !mccolAtEnd && (mcsgId <= mccolId)) || mccolAtEnd) { + // this is case 1. + if (verboseInfoMC) + LOGF(info, "Doing case 1 with mcsgId %d", mcsgId); + + // update UDMcCollisions and UDMcColsLabels (for each UDCollision -> UDMcCollisions) + // update UDMcParticles and UDMcTrackLabels (for each UDTrack -> UDMcParticles) + // get dgcand tracks + auto sgTracks = udtracks.sliceByCached(aod::udtrack::udCollisionId, sgcand.globalIndex(), cache); + + // If the sgcand has an associated McCollision then the McCollision and all associated + // McParticles are saved + // but only consider generated events of interest + if (mcsgId >= 0 && mcOfInterest) { + if (mcColIsSaved.find(mcsgId) == mcColIsSaved.end()) { + if (verboseInfoMC) + LOGF(info, " Saving McCollision %d", mcsgId); + // update UDMcCollisions + auto sgcandMcCol = sgcand.collision_as().mcCollision(); + updateUDMcCollisions(sgcandMcCol, globBC); + mcColIsSaved[mcsgId] = outputMcCollisions.lastIndex(); + } + + // update UDMcColsLabels (for each UDCollision -> UDMcCollisions) + outputMcCollsLabels(mcColIsSaved[mcsgId]); + + // update UDMcParticles + auto mcPartsSlice = mcparts.sliceBy(mcPartsPerMcCollision, mcsgId); + updateUDMcParticles(mcPartsSlice, mcColIsSaved[mcsgId], mcPartIsSaved); + + // update UDMcTrackLabels (for each UDTrack -> UDMcParticles) + updateUDMcTrackLabels(sgTracks, mcPartIsSaved); + + } else { + // If the sgcand has no associated McCollision then only the McParticles which are associated + // with the tracks of the sgcand are saved + if (verboseInfoMC) + LOGF(info, " Saving McCollision %d", -1); + + // update UDMcColsLabels (for each UDCollision -> UDMcCollisions) + outputMcCollsLabels(-1); + + // update UDMcParticles and UDMcTrackLabels (for each UDTrack -> UDMcParticles) + // loop over tracks of dgcand + for (auto sgtrack : sgTracks) { + if (sgtrack.has_track()) { + auto track = sgtrack.track_as(); + if (track.has_mcParticle()) { + auto mcPart = track.mcParticle(); + auto mcCol = mcPart.mcCollision(); + if (mcColIsSaved.find(mcCol.globalIndex()) == mcColIsSaved.end()) { + updateUDMcCollisions(mcCol, globBC); + mcColIsSaved[mcCol.globalIndex()] = outputMcCollisions.lastIndex(); + } + updateUDMcParticle(mcPart, mcColIsSaved[mcCol.globalIndex()], mcPartIsSaved); + updateUDMcTrackLabel(sgtrack, mcPartIsSaved); + } else { + outputMcTrackLabels(-1, track.mcMask()); + } + } else { + outputMcTrackLabels(-1, -1); + } + } + } + // advance sgcand + if (sgcand != lastsgcand) { + sgcand++; + } else { + sgcandAtEnd = true; + } + } else { + // this is case 2. + if (verboseInfoMC) + LOGF(info, "Doing case 2"); + + // update UDMcCollisions and UDMcParticles + // but only consider generated events of interest + if (mcOfInterest && mcColIsSaved.find(mccolId) == mcColIsSaved.end()) { + if (verboseInfoMC) + LOGF(info, " Saving McCollision %d", mccolId); + // update UDMcCollisions + updateUDMcCollisions(mccol, globBC); + mcColIsSaved[mccolId] = outputMcCollisions.lastIndex(); + + // update UDMcParticles + auto mcPartsSlice = mcparts.sliceBy(mcPartsPerMcCollision, mccolId); + updateUDMcParticles(mcPartsSlice, mcColIsSaved[mccolId], mcPartIsSaved); + } + + // advance mccol + if (mccol != lastmccol) { + mccol++; + mcOfInterest = std::find(generatorIds->begin(), generatorIds->end(), mccol.getGeneratorId()) != generatorIds->end(); + mccolId = mccol.globalIndex(); + } else { + mccolAtEnd = true; + } + } + + goon = !sgcandAtEnd || !mccolAtEnd; + if (verboseInfoMC) + LOGF(info, "End of loop mcsgId %d mccolId %d", mcsgId, mccolId); + } + } + + // updating McTruth data only + void procWithoutSgCand(aod::McCollisions const& mccols, aod::McParticles const& mcparts) + { + // use a hash table to keep track of the McCollisions which have been added to the UDMcCollision table + // {McCollisionId : udMcCollisionId} + // similar for the McParticles which have been added to the UDMcParticle table + // {McParticleId : udMcParticleId} + std::map mcColIsSaved; + std::map mcPartIsSaved; + + // loop over McCollisions + for (auto const& mccol : mccols) { + int64_t mccolId = mccol.globalIndex(); + uint64_t globBC = mccol.bc_as().globalBC(); + + // update UDMcCollisions and UDMcParticles + if (mcColIsSaved.find(mccolId) == mcColIsSaved.end()) { + if (verboseInfoMC) + LOGF(info, " Saving McCollision %d", mccolId); + + // update UDMcCollisions + updateUDMcCollisions(mccol, globBC); + mcColIsSaved[mccolId] = outputMcCollisions.lastIndex(); + + // update UDMcParticles + auto mcPartsSlice = mcparts.sliceBy(mcPartsPerMcCollision, mccolId); + updateUDMcParticles(mcPartsSlice, mcColIsSaved[mccolId], mcPartIsSaved); + } + } + } + + void init(InitContext& context) + { + // add histograms for the different process functions + if (context.mOptions.get("processMC")) { + registry.add("mcTruth/collisions", "Number of associated collisions", {HistType::kTH1F, {{11, -0.5, 10.5}}}); + registry.add("mcTruth/collType", "Collision type", {HistType::kTH1F, {{5, -0.5, 4.5}}}); + registry.add("mcTruth/IVMpt", "Invariant mass versus p_{T}", {HistType::kTH2F, {{150, 0.0, 3.0}, {150, 0.0, 3.0}}}); + } + } + + // process function for MC data + // save the MC truth of all events of interest and of the DG events + void processMC(aod::McCollisions const& mccols, aod::McParticles const& mcparts, + UDCCs const& sgcands, UDTCs const& udtracks, + CCs const& /*collisions*/, BCs const& /*bcs*/, TCs const& /*tracks*/) + { + if (verboseInfoMC) { + LOGF(info, "Number of McCollisions %d", mccols.size()); + LOGF(info, "Number of SG candidates %d", sgcands.size()); + LOGF(info, "Number of UD tracks %d", udtracks.size()); + } + if (mccols.size() > 0) { + if (sgcands.size() > 0) { + procWithSgCand(mccols, mcparts, sgcands, udtracks); + } else { + if (saveAllMcCollisions) { + procWithoutSgCand(mccols, mcparts); + } + } + } + } + PROCESS_SWITCH(McSGCandProducer, processMC, "Produce MC tables", false); + + void processDummy(aod::Collisions const& /*collisions*/) + { + // do nothing + if (verboseInfoMC) + LOGF(info, "Running dummy process function!"); + } + PROCESS_SWITCH(McSGCandProducer, processDummy, "Dummy function", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow{ - adaptAnalysisTask(cfgc, TaskName{"sgcandproducer"})}; - + adaptAnalysisTask(cfgc, TaskName{"sgcandproducer"}), + adaptAnalysisTask(cfgc, TaskName{"mcsgcandproducer"})}; return workflow; } diff --git a/PWGUD/TableProducer/UPCCandidateProducer.cxx b/PWGUD/TableProducer/UPCCandidateProducer.cxx index b65d44f9d2f..e7f029ae91d 100644 --- a/PWGUD/TableProducer/UPCCandidateProducer.cxx +++ b/PWGUD/TableProducer/UPCCandidateProducer.cxx @@ -8,7 +8,17 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. - +/// \author Nazar Burmasov, nazar.burmasov@cern.ch +/// \author Diana Krupova, diana.krupova@cern.ch +/// \since 04.06.2024 + +#include +#include +#include +#include +#include +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -19,6 +29,7 @@ #include "PWGUD/Core/UPCCutparHolder.h" #include "PWGUD/Core/UPCHelpers.h" #include "PWGUD/DataModel/UDTables.h" +#include "DataFormatsITSMFT/ROFRecord.h" using namespace o2::framework; using namespace o2::framework::expressions; @@ -34,6 +45,7 @@ struct UpcCandProducer { Produces udFwdTracks; Produces udFwdTracksExtra; + Produces udFwdIndices; Produces udFwdTrkClusters; Produces udFwdTrackLabels; @@ -48,6 +60,7 @@ struct UpcCandProducer { Produces eventCandidatesSels; Produces eventCandidatesSelsCent; Produces eventCandidatesSelsFwd; + Produces eventCandidatesSelExtras; Produces udZdcsReduced; @@ -68,7 +81,7 @@ struct UpcCandProducer { Configurable fFilterTVX{"filterTVX", -1, "Filter candidates by FT0 TVX"}; Configurable fFilterFV0{"filterFV0", -1, "Filter candidates by FV0A"}; - Configurable fBCWindowFITAmps{"bcWindowFITAmps", 20, "BC range for T0A/V0A amplitudes array [-range, +(range-1)]"}; + Configurable fBCWindowFITAmps{"bcWindowFITAmps", 20, "BC range for T0A/V0A amplitudes array [-range, +(range-1)]"}; Configurable fBcWindowMCH{"bcWindowMCH", 20, "Time window for MCH-MID to MCH-only matching for Muon candidates"}; Configurable fBcWindowITSTPC{"bcWindowITSTPC", 20, "Time window for TOF/ITS-TPC to ITS-TPC matching for Central candidates"}; @@ -82,10 +95,16 @@ struct UpcCandProducer { Configurable fSearchITSTPC{"searchITSTPC", 0, "Search for ITS-TPC tracks near candidates"}; Configurable fSearchRangeITSTPC{"searchRangeITSTPC", 50, "BC range for ITS-TPC tracks search wrt TOF tracks"}; + Configurable fMinEtaMFT{"minEtaMFT", -3.6, "Minimum eta for MFT tracks"}; + Configurable fMaxEtaMFT{"maxEtaMFT", -2.5, "Maximum eta for MFT tracks"}; + + Configurable fRequireNoTimeFrameBorder{"requireNoTimeFrameBorder", true, "Require kNoTimeFrameBorder selection bit"}; + Configurable fRequireNoITSROFrameBorder{"requireNoITSROFrameBorder", true, "Require kNoITSROFrameBorder selection bit"}; + // QA histograms HistogramRegistry histRegistry{"HistRegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; - using BCsWithBcSels = o2::soa::Join; + using BCsWithBcSels = o2::soa::Join; using ForwardTracks = o2::soa::Join; @@ -108,6 +127,9 @@ struct UpcCandProducer { histRegistry.get(HIST("hCountersTrg"))->GetXaxis()->SetBinLabel(1, "TCE"); histRegistry.get(HIST("hCountersTrg"))->GetXaxis()->SetBinLabel(2, "ZNA"); histRegistry.get(HIST("hCountersTrg"))->GetXaxis()->SetBinLabel(3, "ZNC"); + histRegistry.get(HIST("hCountersTrg"))->GetXaxis()->SetBinLabel(4, "TCE_ROF"); + histRegistry.get(HIST("hCountersTrg"))->GetXaxis()->SetBinLabel(5, "TCE_TF"); + histRegistry.get(HIST("hCountersTrg"))->GetXaxis()->SetBinLabel(6, "TCE_ROF_TF"); const AxisSpec axisBcDist{201, 0.5, 200.5, ""}; histRegistry.add("hDistToITSTPC", "", kTH1F, {axisBcDist}); @@ -157,7 +179,6 @@ struct UpcCandProducer { histRegistry.fill(HIST("MuonsSelCounter"), upchelpers::kFwdSelpDCA, 1); if (fwdSelectors[upchelpers::kFwdSelChi2]) histRegistry.fill(HIST("MuonsSelCounter"), upchelpers::kFwdSelChi2, 1); - bool pass = fwdSelectors[upchelpers::kFwdSelPt] && fwdSelectors[upchelpers::kFwdSelEta] && fwdSelectors[upchelpers::kFwdSelRabs] && @@ -364,9 +385,14 @@ struct UpcCandProducer { trTime = (static_cast(globalBC) - static_cast(closestBcMCH)) * o2::constants::lhc::LHCBunchSpacingNS; // track time relative to MCH-MID track mchmidChi2 = -999.; // no MID match } + double mchmftChi2 = track.chi2MatchMCHMFT(); + int64_t globalIndex = track.globalIndex(); + int64_t mchIndex = track.matchMCHTrackId(); + int64_t mftIndex = track.matchMFTTrackId(); udFwdTracks(candID, track.px(), track.py(), track.pz(), track.sign(), globalBC, trTime, track.trackTimeRes()); - udFwdTracksExtra(track.nClusters(), track.pDca(), track.rAtAbsorberEnd(), track.chi2(), mchmidChi2, + udFwdTracksExtra(track.trackType(), track.nClusters(), track.pDca(), track.rAtAbsorberEnd(), track.chi2(), mchmidChi2, mchmftChi2, track.mchBitMap(), track.midBitMap(), track.midBoards()); + udFwdIndices(candID, globalIndex, mchIndex, mftIndex); // fill MC labels and masks if needed if (fDoMC) { const auto& label = mcTrackLabels->iteratorAt(trackID); @@ -387,12 +413,14 @@ struct UpcCandProducer { for (const auto& cls : fwdTrkCls) { clustersPerTrack[cls.fwdtrackId()].push_back(cls.globalIndex()); } + int newId = 0; for (auto trackId : trackIds) { const auto& clusters = clustersPerTrack.at(trackId); for (auto clsId : clusters) { const auto& clsInfo = fwdTrkCls.iteratorAt(clsId); - udFwdTrkClusters(trackId, clsInfo.x(), clsInfo.y(), clsInfo.z(), clsInfo.clInfo()); + udFwdTrkClusters(newId, clsInfo.x(), clsInfo.y(), clsInfo.z(), clsInfo.clInfo()); } + newId++; } } @@ -456,10 +484,11 @@ struct UpcCandProducer { return hasNoFT0; } + template void processFITInfo(upchelpers::FITInfo& fitInfo, uint64_t midbc, std::vector>& v, - BCsWithBcSels const& bcs, + TBCs const& bcs, o2::aod::FT0s const& /*ft0s*/, o2::aod::FDDs const& /*fdds*/, o2::aod::FV0As const& /*fv0as*/) @@ -668,6 +697,46 @@ struct UpcCandProducer { } } + template + void collectForwardGlobalTracks(std::vector& bcsMatchedTrIds, + int typeFilter, + TBCs const& /*bcs*/, + o2::aod::Collisions const& /*collisions*/, + ForwardTracks const& fwdTracks, + o2::aod::AmbiguousFwdTracks const& /*ambFwdTracks*/, + std::unordered_map& ambFwdTrBCs) + { + for (const auto& trk : fwdTracks) { + if (trk.trackType() != typeFilter) + continue; + if (!applyFwdCuts(trk)) + continue; + int64_t trkId = trk.globalIndex(); + int32_t nContrib = -1; + uint64_t trackBC = 0; + auto ambIter = ambFwdTrBCs.find(trkId); + if (ambIter == ambFwdTrBCs.end()) { + const auto& col = trk.collision(); + nContrib = col.numContrib(); + trackBC = col.bc_as().globalBC(); + const auto& bc = col.bc_as(); + if (fRequireNoTimeFrameBorder && !bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + continue; // skip this track if the kNoTimeFrameBorder bit is required but not set + } + if (fRequireNoITSROFrameBorder && !bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + continue; // skip this track if the kNoITSROFrameBorder bit is required but not set + } + } else { + trackBC = ambIter->second; + } + int64_t tint = TMath::FloorNint(trk.trackTime() / o2::constants::lhc::LHCBunchSpacingNS + static_cast(fMuonTrackTShift)); + uint64_t bc = trackBC + tint; + if (nContrib > upcCuts.getMaxNContrib()) + continue; + addTrack(bcsMatchedTrIds, bc, trkId); + } + } + int32_t searchTracks(uint64_t midbc, uint64_t range, uint32_t tracksToFind, std::vector& tracks, std::vector& v, @@ -710,9 +779,10 @@ struct UpcCandProducer { return 0; // found exactly tracksToFind tracks in [midbc - range, midbc + range] } + template void createCandidatesCentral(BarrelTracks const& barrelTracks, o2::aod::AmbiguousTracks const& ambBarrelTracks, - o2::aod::BCs const& bcs, + TBCs const& bcs, o2::aod::Collisions const& collisions, o2::aod::FT0s const& ft0s, o2::aod::FDDs const& /*fdds*/, @@ -727,7 +797,7 @@ struct UpcCandProducer { // trackID -> index in amb. track table std::unordered_map ambBarrelTrBCs; if (upcCuts.getAmbigSwitch() != 1) - collectAmbTrackBCs<0, o2::aod::BCs>(ambBarrelTrBCs, ambBarrelTracks); + collectAmbTrackBCs<0, BCsWithBcSels>(ambBarrelTrBCs, ambBarrelTracks); collectBarrelTracks(bcsMatchedTrIdsTOF, 0, @@ -748,7 +818,7 @@ struct UpcCandProducer { std::map mapGlobalBcWithTVX{}; std::map mapGlobalBcWithTSC{}; for (const auto& ft0 : ft0s) { - uint64_t globalBC = ft0.bc_as().globalBC(); + uint64_t globalBC = ft0.bc_as().globalBC(); int32_t globalIndex = ft0.globalIndex(); if (!(std::abs(ft0.timeA()) > 2.f && std::abs(ft0.timeC()) > 2.f)) mapGlobalBcWithTOR[globalBC] = globalIndex; @@ -769,7 +839,7 @@ struct UpcCandProducer { for (const auto& fv0a : fv0as) { if (std::abs(fv0a.time()) > 15.f) continue; - uint64_t globalBC = fv0a.bc_as().globalBC(); + uint64_t globalBC = fv0a.bc_as().globalBC(); mapGlobalBcWithV0A[globalBC] = fv0a.globalIndex(); } @@ -781,7 +851,7 @@ struct UpcCandProducer { histRegistry.get(HIST("hCountersTrg"))->Fill("ZNA", 1); if (!(std::abs(zdc.timeZNC()) > 2.f)) histRegistry.get(HIST("hCountersTrg"))->Fill("ZNC", 1); - auto globalBC = zdc.bc_as().globalBC(); + auto globalBC = zdc.bc_as().globalBC(); mapGlobalBcWithZdc[globalBC] = zdc.globalIndex(); } @@ -860,7 +930,7 @@ struct UpcCandProducer { for (auto& pair : bcsMatchedTrIdsTOF) { auto globalBC = pair.first; auto& barrelTrackIDs = pair.second; - int32_t nTOFs = barrelTrackIDs.size(); + uint32_t nTOFs = barrelTrackIDs.size(); if (nTOFs > fNBarProngs) // too many tracks continue; auto closestBcITSTPC = std::numeric_limits::max(); @@ -874,7 +944,7 @@ struct UpcCandProducer { if (std::abs(distClosestBcITSTPC) > fBcWindowITSTPC) continue; auto& itstpcTracks = itClosestBcITSTPC->second; - int32_t nITSTPCs = itstpcTracks.size(); + uint32_t nITSTPCs = itstpcTracks.size(); if ((nTOFs + nITSTPCs) != fNBarProngs) continue; barrelTrackIDs.insert(barrelTrackIDs.end(), itstpcTracks.begin(), itstpcTracks.end()); @@ -906,8 +976,12 @@ struct UpcCandProducer { } RgtrwTOF = RgtrwTOF / static_cast(numContrib); // store used tracks + int upc_flag = 0; + // TODO: introduce better check on association of collision and reconstruction mode + if (bcs.iteratorAt(0).flags() == o2::itsmft::ROFRecord::VtxUPCMode) + upc_flag = 1; fillBarrelTracks(barrelTracks, barrelTrackIDs, candID, globalBC, closestBcITSTPC, mcBarrelTrackLabels, ambBarrelTrBCs); - eventCandidates(globalBC, runNumber, dummyX, dummyY, dummyZ, numContrib, netCharge, RgtrwTOF); + eventCandidates(globalBC, runNumber, dummyX, dummyY, dummyZ, upc_flag, numContrib, netCharge, RgtrwTOF); eventCandidatesSels(fitInfo.ampFT0A, fitInfo.ampFT0C, fitInfo.timeFT0A, fitInfo.timeFT0C, fitInfo.triggerMaskFT0, fitInfo.ampFDDA, fitInfo.ampFDDC, fitInfo.timeFDDA, fitInfo.timeFDDC, fitInfo.triggerMaskFDD, fitInfo.ampFV0A, fitInfo.timeFV0A, fitInfo.triggerMaskFV0A, @@ -925,7 +999,7 @@ struct UpcCandProducer { for (auto& pair : bcsMatchedTrIdsITSTPC) { auto globalBC = pair.first; auto& barrelTrackIDs = pair.second; - int32_t nThisITSTPCs = barrelTrackIDs.size(); + uint32_t nThisITSTPCs = barrelTrackIDs.size(); if (nThisITSTPCs > fNBarProngs || nThisITSTPCs == 0) // too many tracks / already matched to TOF continue; auto closestBcITSTPC = std::numeric_limits::max(); @@ -939,7 +1013,7 @@ struct UpcCandProducer { if (std::abs(distClosestBcITSTPC) > fBcWindowITSTPC) continue; auto& itstpcTracks = itClosestBcITSTPC->second; - int32_t nITSTPCs = itstpcTracks.size(); + uint32_t nITSTPCs = itstpcTracks.size(); if ((nThisITSTPCs + nITSTPCs) != fNBarProngs) continue; barrelTrackIDs.insert(barrelTrackIDs.end(), itstpcTracks.begin(), itstpcTracks.end()); @@ -971,8 +1045,12 @@ struct UpcCandProducer { } RgtrwTOF = RgtrwTOF / static_cast(numContrib); // store used tracks + int upc_flag = 0; + // TODO: introduce better check on association of collision and reconstruction mode + if (bcs.iteratorAt(0).flags() == o2::itsmft::ROFRecord::VtxUPCMode) + upc_flag = 1; fillBarrelTracks(barrelTracks, barrelTrackIDs, candID, globalBC, closestBcITSTPC, mcBarrelTrackLabels, ambBarrelTrBCs); - eventCandidates(globalBC, runNumber, dummyX, dummyY, dummyZ, numContrib, netCharge, RgtrwTOF); + eventCandidates(globalBC, runNumber, dummyX, dummyY, dummyZ, upc_flag, numContrib, netCharge, RgtrwTOF); eventCandidatesSels(fitInfo.ampFT0A, fitInfo.ampFT0C, fitInfo.timeFT0A, fitInfo.timeFT0C, fitInfo.triggerMaskFT0, fitInfo.ampFDDA, fitInfo.ampFDDC, fitInfo.timeFDDA, fitInfo.timeFDDC, fitInfo.triggerMaskFDD, fitInfo.ampFV0A, fitInfo.timeFV0A, fitInfo.triggerMaskFV0A, @@ -992,12 +1070,13 @@ struct UpcCandProducer { bcsMatchedTrIdsTOF.clear(); } + template void createCandidatesSemiFwd(BarrelTracks const& barrelTracks, o2::aod::AmbiguousTracks const& ambBarrelTracks, ForwardTracks const& fwdTracks, - o2::aod::FwdTrkCls const& fwdTrkClusters, + o2::aod::FwdTrkCls const& /*fwdTrkClusters*/, o2::aod::AmbiguousFwdTracks const& ambFwdTracks, - BCsWithBcSels const& bcs, + TBCs const& bcs, o2::aod::Collisions const& collisions, o2::aod::FT0s const& ft0s, o2::aod::FDDs const& fdds, @@ -1147,9 +1226,13 @@ struct UpcCandProducer { } RgtrwTOF = RgtrwTOF / static_cast(numContrib); // store used tracks + int upc_flag = 0; + // TODO: introduce better check on association of collision and reconstruction mode + if (bcs.iteratorAt(0).flags() == o2::itsmft::ROFRecord::VtxUPCMode) + upc_flag = 1; fillFwdTracks(fwdTracks, fwdTrackIDs, candID, bc, bc, mcFwdTrackLabels); fillBarrelTracks(barrelTracks, barrelTrackIDs, candID, bc, bc, mcBarrelTrackLabels, ambBarrelTrBCs); - eventCandidates(bc, runNumber, dummyX, dummyY, dummyZ, numContrib, netCharge, RgtrwTOF); + eventCandidates(bc, runNumber, dummyX, dummyY, dummyZ, upc_flag, numContrib, netCharge, RgtrwTOF); eventCandidatesSels(fitInfo.ampFT0A, fitInfo.ampFT0C, fitInfo.timeFT0A, fitInfo.timeFT0C, fitInfo.triggerMaskFT0, fitInfo.ampFDDA, fitInfo.ampFDDC, fitInfo.timeFDDA, fitInfo.timeFDDC, fitInfo.triggerMaskFDD, fitInfo.ampFV0A, fitInfo.timeFV0A, fitInfo.triggerMaskFV0A, @@ -1171,7 +1254,7 @@ struct UpcCandProducer { const std::map& mapBCs, std::vector& amps, std::vector& relBCs, - int64_t gbc) + uint64_t gbc) { auto s = gbc - fBCWindowFITAmps; auto e = gbc + (fBCWindowFITAmps - 1); @@ -1197,13 +1280,14 @@ struct UpcCandProducer { } } + template void createCandidatesFwd(ForwardTracks const& fwdTracks, o2::aod::FwdTrkCls const& fwdTrkClusters, o2::aod::AmbiguousFwdTracks const& ambFwdTracks, - o2::aod::BCs const& bcs, + TBCs const& bcs, o2::aod::Collisions const& collisions, o2::aod::FT0s const& ft0s, - o2::aod::FDDs const& /*fdds*/, + o2::aod::FDDs const& fdds, o2::aod::FV0As const& fv0as, o2::aod::Zdcs const& zdcs, const o2::aod::McFwdTrackLabels* mcFwdTrackLabels) @@ -1214,7 +1298,7 @@ struct UpcCandProducer { // trackID -> index in amb. track table std::unordered_map ambFwdTrBCs; - collectAmbTrackBCs<1, o2::aod::BCs>(ambFwdTrBCs, ambFwdTracks); + collectAmbTrackBCs<1, BCsWithBcSels>(ambFwdTrBCs, ambFwdTracks); collectForwardTracks(bcsMatchedTrIdsMID, o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack, @@ -1241,7 +1325,7 @@ struct UpcCandProducer { } if (std::abs(ft0.timeA()) > 2.f) continue; - uint64_t globalBC = ft0.bc_as().globalBC(); + uint64_t globalBC = ft0.bc_as().globalBC(); mapGlobalBcWithT0A[globalBC] = ft0.globalIndex(); } @@ -1251,7 +1335,7 @@ struct UpcCandProducer { continue; if (std::abs(fv0a.time()) > 15.f) continue; - uint64_t globalBC = fv0a.bc_as().globalBC(); + uint64_t globalBC = fv0a.bc_as().globalBC(); mapGlobalBcWithV0A[globalBC] = fv0a.globalIndex(); } @@ -1263,14 +1347,33 @@ struct UpcCandProducer { histRegistry.get(HIST("hCountersTrg"))->Fill("ZNA", 1); if (!(std::abs(zdc.timeZNC()) > 2.f)) histRegistry.get(HIST("hCountersTrg"))->Fill("ZNC", 1); - auto globalBC = zdc.bc_as().globalBC(); + auto globalBC = zdc.bc_as().globalBC(); mapGlobalBcWithZdc[globalBC] = zdc.globalIndex(); } + std::map mapGlobalBcWithFDD{}; + uint8_t twoLayersA = 0; + uint8_t twoLayersC = 0; + for (const auto& fdd : fdds) { + // get signal coincidence + for (int i = 0; i < 4; i++) { + if (fdd.chargeA()[i + 4] > 0 && fdd.chargeA()[i] > 0) + twoLayersA++; + if (fdd.chargeC()[i + 4] > 0 && fdd.chargeC()[i] > 0) + twoLayersC++; + } + // if no signal, continue + if ((twoLayersA == 0) && (twoLayersC == 0)) + continue; + uint64_t globalBC = fdd.bc_as().globalBC(); + mapGlobalBcWithFDD[globalBC] = fdd.globalIndex(); + } + auto nFT0s = mapGlobalBcWithT0A.size(); auto nFV0As = mapGlobalBcWithV0A.size(); auto nZdcs = mapGlobalBcWithZdc.size(); auto nBcsWithMCH = bcsMatchedTrIdsMCH.size(); + auto nFDDs = mapGlobalBcWithFDD.size(); // todo: calculate position of UD collision? float dummyX = 0.; @@ -1283,10 +1386,11 @@ struct UpcCandProducer { // storing n-prong matches int32_t candID = 0; - for (auto& pair : bcsMatchedTrIdsMID) { + + for (auto& pair : bcsMatchedTrIdsMID) { // candidates without MFT auto globalBC = static_cast(pair.first); const auto& fwdTrackIDs = pair.second; // only MID-matched tracks at the moment - int32_t nMIDs = fwdTrackIDs.size(); + uint32_t nMIDs = fwdTrackIDs.size(); if (nMIDs > fNFwdProngs) // too many tracks continue; std::vector trkCandIDs{}; @@ -1301,7 +1405,7 @@ struct UpcCandProducer { if (std::abs(distClosestBcMCH) > fBcWindowMCH) continue; auto& mchTracks = itClosestBcMCH->second; - int32_t nMCHs = mchTracks.size(); + uint32_t nMCHs = mchTracks.size(); if ((nMCHs + nMIDs) != fNFwdProngs) continue; trkCandIDs.insert(trkCandIDs.end(), fwdTrackIDs.begin(), fwdTrackIDs.end()); @@ -1318,6 +1422,8 @@ struct UpcCandProducer { std::vector amplitudesV0A{}; std::vector relBCsT0A{}; std::vector relBCsV0A{}; + uint8_t chFT0A = 0; + uint8_t chFT0C = 0; if (nFT0s > 0) { uint64_t closestBcT0A = findClosestBC(globalBC, mapGlobalBcWithT0A); int64_t distClosestBcT0A = globalBC - static_cast(closestBcT0A); @@ -1332,8 +1438,11 @@ struct UpcCandProducer { const auto& t0AmpsC = ft0.amplitudeC(); fitInfo.ampFT0A = std::accumulate(t0AmpsA.begin(), t0AmpsA.end(), 0.f); fitInfo.ampFT0C = std::accumulate(t0AmpsC.begin(), t0AmpsC.end(), 0.f); + chFT0A = ft0.amplitudeA().size(); + chFT0C = ft0.amplitudeC().size(); fillAmplitudes(ft0s, mapGlobalBcWithT0A, amplitudesT0A, relBCsT0A, globalBC); } + uint8_t chFV0A = 0; if (nFV0As > 0) { uint64_t closestBcV0A = findClosestBC(globalBC, mapGlobalBcWithV0A); int64_t distClosestBcV0A = globalBC - static_cast(closestBcV0A); @@ -1345,8 +1454,32 @@ struct UpcCandProducer { fitInfo.timeFV0A = fv0a.time(); const auto& v0Amps = fv0a.amplitude(); fitInfo.ampFV0A = std::accumulate(v0Amps.begin(), v0Amps.end(), 0.f); + chFV0A = fv0a.amplitude().size(); fillAmplitudes(fv0as, mapGlobalBcWithV0A, amplitudesV0A, relBCsV0A, globalBC); } + uint8_t chFDDA = 0; + uint8_t chFDDC = 0; + if (nFDDs > 0) { + uint64_t closestBcFDD = findClosestBC(globalBC, mapGlobalBcWithFDD); + auto fddId = mapGlobalBcWithFDD.at(closestBcFDD); + auto fdd = fdds.iteratorAt(fddId); + fitInfo.timeFDDA = fdd.timeA(); + fitInfo.timeFDDC = fdd.timeC(); + fitInfo.ampFDDA = 0; + for (int i = 0; i < 8; i++) + fitInfo.ampFDDA += fdd.chargeA()[i]; + fitInfo.ampFDDC = 0; + for (int i = 0; i < 8; i++) + fitInfo.ampFDDC += fdd.chargeC()[i]; + fitInfo.triggerMaskFDD = fdd.triggerMask(); + // get signal coincidence + for (int i = 0; i < 4; i++) { + if (fdd.chargeA()[i + 4] > 0 && fdd.chargeA()[i] > 0) + chFDDA++; + if (fdd.chargeC()[i + 4] > 0 && fdd.chargeC()[i] > 0) + chFDDC++; + } + } if (nZdcs > 0) { auto itZDC = mapGlobalBcWithZdc.find(globalBC); if (itZDC != mapGlobalBcWithZdc.end()) { @@ -1367,14 +1500,19 @@ struct UpcCandProducer { selTrackIds.push_back(id); } // store used tracks + int upc_flag = 0; + // TODO: introduce better check on association of collision and reconstruction mode + if (bcs.iteratorAt(0).flags() == o2::itsmft::ROFRecord::VtxUPCMode) + upc_flag = 1; fillFwdTracks(fwdTracks, trkCandIDs, candID, globalBC, closestBcMCH, mcFwdTrackLabels); - eventCandidates(globalBC, runNumber, dummyX, dummyY, dummyZ, numContrib, netCharge, RgtrwTOF); + eventCandidates(globalBC, runNumber, dummyX, dummyY, dummyZ, upc_flag, numContrib, netCharge, RgtrwTOF); eventCandidatesSels(fitInfo.ampFT0A, fitInfo.ampFT0C, fitInfo.timeFT0A, fitInfo.timeFT0C, fitInfo.triggerMaskFT0, fitInfo.ampFDDA, fitInfo.ampFDDC, fitInfo.timeFDDA, fitInfo.timeFDDC, fitInfo.triggerMaskFDD, fitInfo.ampFV0A, fitInfo.timeFV0A, fitInfo.triggerMaskFV0A, fitInfo.BBFT0Apf, fitInfo.BBFT0Cpf, fitInfo.BGFT0Apf, fitInfo.BGFT0Cpf, fitInfo.BBFV0Apf, fitInfo.BGFV0Apf, fitInfo.BBFDDApf, fitInfo.BBFDDCpf, fitInfo.BGFDDApf, fitInfo.BGFDDCpf); + eventCandidatesSelExtras(chFT0A, chFT0C, chFDDA, chFDDC, chFV0A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); eventCandidatesSelsFwd(fitInfo.distClosestBcV0A, fitInfo.distClosestBcT0A, amplitudesT0A, @@ -1393,6 +1531,322 @@ struct UpcCandProducer { bcsMatchedTrIdsMCH.clear(); mapGlobalBcWithT0A.clear(); mapGlobalBcWithV0A.clear(); + mapGlobalBcWithFDD.clear(); + } + + template + void createCandidatesFwdGlobal(ForwardTracks const& fwdTracks, + o2::aod::FwdTrkCls const& /*fwdTrkClusters*/, + o2::aod::AmbiguousFwdTracks const& ambFwdTracks, + TBCs const& bcs, + o2::aod::Collisions const& collisions, + o2::aod::FT0s const& ft0s, + o2::aod::FDDs const& fdds, + o2::aod::FV0As const& fv0as, + o2::aod::Zdcs const& zdcs, + const o2::aod::McFwdTrackLabels* mcFwdTrackLabels) + { + // pairs of global BCs and vectors of matched track IDs: + std::vector bcsMatchedTrIdsMID; + std::vector bcsMatchedTrIdsMCH; + std::vector bcsMatchedTrIdsGlobal; + + // trackID -> index in amb. track table + std::unordered_map ambFwdTrBCs; + collectAmbTrackBCs<1, BCsWithBcSels>(ambFwdTrBCs, ambFwdTracks); + + collectForwardTracks(bcsMatchedTrIdsMID, + o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack, + bcs, collisions, + fwdTracks, ambFwdTracks, ambFwdTrBCs); + + collectForwardTracks(bcsMatchedTrIdsMCH, + o2::aod::fwdtrack::ForwardTrackTypeEnum::MCHStandaloneTrack, + bcs, collisions, + fwdTracks, ambFwdTracks, ambFwdTrBCs); + + collectForwardGlobalTracks(bcsMatchedTrIdsGlobal, + o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack, + bcs, collisions, + fwdTracks, ambFwdTracks, ambFwdTrBCs); + + std::sort(bcsMatchedTrIdsMID.begin(), bcsMatchedTrIdsMID.end(), + [](const auto& left, const auto& right) { return left.first < right.first; }); + + std::sort(bcsMatchedTrIdsMCH.begin(), bcsMatchedTrIdsMCH.end(), + [](const auto& left, const auto& right) { return left.first < right.first; }); + + std::sort(bcsMatchedTrIdsGlobal.begin(), bcsMatchedTrIdsGlobal.end(), + [](const auto& left, const auto& right) { return left.first < right.first; }); + + std::map mapGlobalBcWithT0A{}; + for (const auto& ft0 : ft0s) { + if (!TESTBIT(ft0.triggerMask(), o2::fit::Triggers::bitVertex)) + continue; + if (TESTBIT(ft0.triggerMask(), o2::fit::Triggers::bitCen)) { // TVX & TCE + histRegistry.get(HIST("hCountersTrg"))->Fill("TCE", 1); + if (ft0.bc_as().selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { // TVX & TCE without ROF borders + histRegistry.get(HIST("hCountersTrg"))->Fill("TCE_ROF", 1); + } + if (ft0.bc_as().selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { // TVX & TCE without TF borders + histRegistry.get(HIST("hCountersTrg"))->Fill("TCE_TF", 1); + } + if (ft0.bc_as().selection_bit(o2::aod::evsel::kNoITSROFrameBorder) && + ft0.bc_as().selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { // TVX & TCE without ROF and TF borders + histRegistry.get(HIST("hCountersTrg"))->Fill("TCE_ROF_TF", 1); + } + } + if (std::abs(ft0.timeA()) > 2.f) + continue; + uint64_t globalBC = ft0.bc_as().globalBC(); + mapGlobalBcWithT0A[globalBC] = ft0.globalIndex(); + } + + std::map mapGlobalBcWithV0A{}; + for (const auto& fv0a : fv0as) { + if (!TESTBIT(fv0a.triggerMask(), o2::fit::Triggers::bitA)) + continue; + if (std::abs(fv0a.time()) > 15.f) + continue; + uint64_t globalBC = fv0a.bc_as().globalBC(); + mapGlobalBcWithV0A[globalBC] = fv0a.globalIndex(); + } + + std::map mapGlobalBcWithZdc{}; + for (const auto& zdc : zdcs) { + if (std::abs(zdc.timeZNA()) > 2.f && std::abs(zdc.timeZNC()) > 2.f) + continue; + if (!(std::abs(zdc.timeZNA()) > 2.f)) + histRegistry.get(HIST("hCountersTrg"))->Fill("ZNA", 1); + if (!(std::abs(zdc.timeZNC()) > 2.f)) + histRegistry.get(HIST("hCountersTrg"))->Fill("ZNC", 1); + auto globalBC = zdc.bc_as().globalBC(); + mapGlobalBcWithZdc[globalBC] = zdc.globalIndex(); + } + + std::map mapGlobalBcWithFDD{}; + uint8_t twoLayersA = 0; + uint8_t twoLayersC = 0; + for (const auto& fdd : fdds) { + // get signal coincidence + for (int i = 0; i < 4; i++) { + if (fdd.chargeA()[i + 4] > 0 && fdd.chargeA()[i] > 0) + twoLayersA++; + if (fdd.chargeC()[i + 4] > 0 && fdd.chargeC()[i] > 0) + twoLayersC++; + } + // if no signal, continue + if ((twoLayersA == 0) && (twoLayersC == 0)) + continue; + uint64_t globalBC = fdd.bc_as().globalBC(); + mapGlobalBcWithFDD[globalBC] = fdd.globalIndex(); + } + + auto nFT0s = mapGlobalBcWithT0A.size(); + auto nFV0As = mapGlobalBcWithV0A.size(); + auto nZdcs = mapGlobalBcWithZdc.size(); + auto nFDDs = mapGlobalBcWithFDD.size(); + + // todo: calculate position of UD collision? + float dummyX = 0.; + float dummyY = 0.; + float dummyZ = 0.; + + int32_t runNumber = bcs.iteratorAt(0).runNumber(); + + std::vector selTrackIdsGlobal{}; + + int32_t candID = 0; + + for (auto& pair : bcsMatchedTrIdsGlobal) { + auto globalBC = static_cast(pair.first); + const auto& fwdTrackIDs = pair.second; // Forward tracks (Global with MFT) + if (fwdTrackIDs.size() != 2) { // ensure we have two MFT tracks + continue; + } + + // find the corresponding MCH-MID tracks + auto midIt = std::find_if(bcsMatchedTrIdsMID.begin(), bcsMatchedTrIdsMID.end(), + [globalBC](const auto& midPair) { + return midPair.first == static_cast(globalBC); + }); + const auto* midTrackIDs = (midIt != bcsMatchedTrIdsMID.end()) ? &midIt->second : nullptr; + + // ensure MCH-MID tracks are available + if (!midTrackIDs || midTrackIDs->size() != 2) { + continue; + } + + std::vector trkCandIDs; + + // retrieve global track eta and apply the logic + bool firstInAcceptance = false, secondInAcceptance = false; + + const auto& trk1 = fwdTracks.iteratorAt(fwdTrackIDs[0]); + const auto& trk2 = fwdTracks.iteratorAt(fwdTrackIDs[1]); + + if (trk1.eta() > fMinEtaMFT && trk1.eta() < fMaxEtaMFT) { + firstInAcceptance = true; + } + if (trk2.eta() > fMinEtaMFT && trk2.eta() < fMaxEtaMFT) { + secondInAcceptance = true; + } + + // handle the four cases + if (!firstInAcceptance && !secondInAcceptance) { + // Case 1: Both outside MFT acceptance + trkCandIDs.insert(trkCandIDs.end(), midTrackIDs->begin(), midTrackIDs->end()); + } else if (firstInAcceptance && !secondInAcceptance) { + // Case 2: First inside, second outside + trkCandIDs.push_back(fwdTrackIDs[0]); // Keep first global + trkCandIDs.push_back((*midTrackIDs)[1]); // Replace second with MCH-MID + } else if (!firstInAcceptance && secondInAcceptance) { + // Case 3: First outside, second inside + trkCandIDs.push_back((*midTrackIDs)[0]); // Replace first with MCH-MID + trkCandIDs.push_back(fwdTrackIDs[1]); // Keep second global + } else { + // Case 4: Both inside MFT acceptance + trkCandIDs.insert(trkCandIDs.end(), fwdTrackIDs.begin(), fwdTrackIDs.end()); + } + + uint64_t closestBcMCH = 0; + upchelpers::FITInfo fitInfo{}; + fitInfo.timeFT0A = -999.f; + fitInfo.timeFT0C = -999.f; + fitInfo.timeFV0A = -999.f; + fitInfo.ampFT0A = 0.f; + fitInfo.ampFT0C = 0.f; + fitInfo.ampFV0A = 0.f; + std::vector amplitudesT0A{}; + std::vector amplitudesV0A{}; + std::vector relBCsT0A{}; + std::vector relBCsV0A{}; + uint8_t chFT0A = 0; + uint8_t chFT0C = 0; + int trs = 0; + int trofs = 0; + int hmpr = 0; + int tfb = 0; + int itsROFb = 0; + int sbp = 0; + int zVtxFT0vPv = 0; + int vtxITSTPC = 0; + if (nFT0s > 0) { + uint64_t closestBcT0A = findClosestBC(globalBC, mapGlobalBcWithT0A); + int64_t distClosestBcT0A = globalBC - static_cast(closestBcT0A); + if (std::abs(distClosestBcT0A) <= fFilterFT0) + continue; + fitInfo.distClosestBcT0A = distClosestBcT0A; + auto ft0Id = mapGlobalBcWithT0A.at(closestBcT0A); + auto ft0 = ft0s.iteratorAt(ft0Id); + fitInfo.timeFT0A = ft0.timeA(); + fitInfo.timeFT0C = ft0.timeC(); + const auto& t0AmpsA = ft0.amplitudeA(); + const auto& t0AmpsC = ft0.amplitudeC(); + fitInfo.ampFT0A = std::accumulate(t0AmpsA.begin(), t0AmpsA.end(), 0.f); + fitInfo.ampFT0C = std::accumulate(t0AmpsC.begin(), t0AmpsC.end(), 0.f); + chFT0A = ft0.amplitudeA().size(); + chFT0C = ft0.amplitudeC().size(); + // get selection flags per BC + trs = ft0.bc_as().selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) ? 1 : 0; + trofs = ft0.bc_as().selection_bit(o2::aod::evsel::kNoCollInRofStandard) ? 1 : 0; + hmpr = ft0.bc_as().selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof) ? 1 : 0; + tfb = ft0.bc_as().selection_bit(o2::aod::evsel::kNoTimeFrameBorder) ? 1 : 0; + itsROFb = ft0.bc_as().selection_bit(o2::aod::evsel::kNoITSROFrameBorder) ? 1 : 0; + sbp = ft0.bc_as().selection_bit(o2::aod::evsel::kNoSameBunchPileup) ? 1 : 0; + zVtxFT0vPv = ft0.bc_as().selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV) ? 1 : 0; + vtxITSTPC = ft0.bc_as().selection_bit(o2::aod::evsel::kIsVertexITSTPC) ? 1 : 0; + fillAmplitudes(ft0s, mapGlobalBcWithT0A, amplitudesT0A, relBCsT0A, globalBC); + } + uint8_t chFV0A = 0; + if (nFV0As > 0) { + uint64_t closestBcV0A = findClosestBC(globalBC, mapGlobalBcWithV0A); + int64_t distClosestBcV0A = globalBC - static_cast(closestBcV0A); + if (std::abs(distClosestBcV0A) <= fFilterFV0) + continue; + fitInfo.distClosestBcV0A = distClosestBcV0A; + auto fv0aId = mapGlobalBcWithV0A.at(closestBcV0A); + auto fv0a = fv0as.iteratorAt(fv0aId); + fitInfo.timeFV0A = fv0a.time(); + const auto& v0Amps = fv0a.amplitude(); + fitInfo.ampFV0A = std::accumulate(v0Amps.begin(), v0Amps.end(), 0.f); + chFV0A = fv0a.amplitude().size(); + fillAmplitudes(fv0as, mapGlobalBcWithV0A, amplitudesV0A, relBCsV0A, globalBC); + } + uint8_t chFDDA = 0; + uint8_t chFDDC = 0; + if (nFDDs > 0) { + uint64_t closestBcFDD = findClosestBC(globalBC, mapGlobalBcWithFDD); + auto fddId = mapGlobalBcWithFDD.at(closestBcFDD); + auto fdd = fdds.iteratorAt(fddId); + fitInfo.timeFDDA = fdd.timeA(); + fitInfo.timeFDDC = fdd.timeC(); + fitInfo.ampFDDA = 0; + for (int i = 0; i < 8; i++) + fitInfo.ampFDDA += fdd.chargeA()[i]; + fitInfo.ampFDDC = 0; + for (int i = 0; i < 8; i++) + fitInfo.ampFDDC += fdd.chargeC()[i]; + fitInfo.triggerMaskFDD = fdd.triggerMask(); + // get signal coincidence + for (int i = 0; i < 4; i++) { + if (fdd.chargeA()[i + 4] > 0 && fdd.chargeA()[i] > 0) + chFDDA++; + if (fdd.chargeC()[i + 4] > 0 && fdd.chargeC()[i] > 0) + chFDDC++; + } + } + if (nZdcs > 0) { + auto itZDC = mapGlobalBcWithZdc.find(globalBC); + if (itZDC != mapGlobalBcWithZdc.end()) { + const auto& zdc = zdcs.iteratorAt(itZDC->second); + float timeZNA = zdc.timeZNA(); + float timeZNC = zdc.timeZNC(); + float eComZNA = zdc.energyCommonZNA(); + float eComZNC = zdc.energyCommonZNC(); + udZdcsReduced(candID, timeZNA, timeZNC, eComZNA, eComZNC); + } + } + uint16_t numContrib = fNFwdProngs; + int8_t netCharge = 0; + float RgtrwTOF = 0.; + for (auto id : trkCandIDs) { + auto tr = fwdTracks.iteratorAt(id); + netCharge += tr.sign(); + selTrackIdsGlobal.push_back(id); + } + // store used tracks + int upc_flag = 0; + // TODO: introduce better check on association of collision and reconstruction mode + if (bcs.iteratorAt(0).flags() == o2::itsmft::ROFRecord::VtxUPCMode) + upc_flag = 1; + fillFwdTracks(fwdTracks, trkCandIDs, candID, globalBC, closestBcMCH, mcFwdTrackLabels); + eventCandidates(globalBC, runNumber, dummyX, dummyY, dummyZ, upc_flag, numContrib, netCharge, RgtrwTOF); + eventCandidatesSels(fitInfo.ampFT0A, fitInfo.ampFT0C, fitInfo.timeFT0A, fitInfo.timeFT0C, fitInfo.triggerMaskFT0, + fitInfo.ampFDDA, fitInfo.ampFDDC, fitInfo.timeFDDA, fitInfo.timeFDDC, fitInfo.triggerMaskFDD, + fitInfo.ampFV0A, fitInfo.timeFV0A, fitInfo.triggerMaskFV0A, + fitInfo.BBFT0Apf, fitInfo.BBFT0Cpf, fitInfo.BGFT0Apf, fitInfo.BGFT0Cpf, + fitInfo.BBFV0Apf, fitInfo.BGFV0Apf, + fitInfo.BBFDDApf, fitInfo.BBFDDCpf, fitInfo.BGFDDApf, fitInfo.BGFDDCpf); + eventCandidatesSelExtras(chFT0A, chFT0C, chFDDA, chFDDC, chFV0A, 0, 0, trs, trofs, hmpr, tfb, itsROFb, sbp, zVtxFT0vPv, vtxITSTPC); + eventCandidatesSelsFwd(fitInfo.distClosestBcV0A, + fitInfo.distClosestBcT0A, + amplitudesT0A, + relBCsT0A, + amplitudesV0A, + relBCsV0A); + candID++; + trkCandIDs.clear(); + } + + selTrackIdsGlobal.clear(); + ambFwdTrBCs.clear(); + bcsMatchedTrIdsMID.clear(); + bcsMatchedTrIdsMCH.clear(); + bcsMatchedTrIdsGlobal.clear(); + mapGlobalBcWithT0A.clear(); + mapGlobalBcWithV0A.clear(); + mapGlobalBcWithFDD.clear(); } // data processors @@ -1423,7 +1877,7 @@ struct UpcCandProducer { // create candidates for central region void processCentral(BarrelTracks const& barrelTracks, o2::aod::AmbiguousTracks const& ambBarrelTracks, - o2::aod::BCs const& bcs, + BCsWithBcSels const& bcs, o2::aod::Collisions const& collisions, o2::aod::FT0s const& ft0s, o2::aod::FDDs const& fdds, @@ -1469,7 +1923,7 @@ struct UpcCandProducer { // create candidates for central region void processCentralMC(BarrelTracks const& barrelTracks, o2::aod::AmbiguousTracks const& ambBarrelTracks, - o2::aod::BCs const& bcs, + BCsWithBcSels const& bcs, o2::aod::Collisions const& collisions, o2::aod::FT0s const& ft0s, o2::aod::FDDs const& fdds, @@ -1492,7 +1946,7 @@ struct UpcCandProducer { void processForward(ForwardTracks const& fwdTracks, o2::aod::FwdTrkCls const& fwdTrkClusters, o2::aod::AmbiguousFwdTracks const& ambFwdTracks, - o2::aod::BCs const& bcs, + BCsWithBcSels const& bcs, o2::aod::Collisions const& collisions, o2::aod::FT0s const& ft0s, o2::aod::FDDs const& fdds, @@ -1509,7 +1963,7 @@ struct UpcCandProducer { void processForwardMC(ForwardTracks const& fwdTracks, o2::aod::FwdTrkCls const& fwdTrkClusters, o2::aod::AmbiguousFwdTracks const& ambFwdTracks, - o2::aod::BCs const& bcs, + BCsWithBcSels const& bcs, o2::aod::Collisions const& collisions, o2::aod::FT0s const& ft0s, o2::aod::FDDs const& fdds, @@ -1527,12 +1981,54 @@ struct UpcCandProducer { fNewPartIDs.clear(); } + // create candidates for forward region including MFT + // forward: n fwd tracks + void processForwardGlobal(ForwardTracks const& fwdTracks, + o2::aod::FwdTrkCls const& fwdTrkClusters, + o2::aod::AmbiguousFwdTracks const& ambFwdTracks, + BCsWithBcSels const& bcs, + o2::aod::Collisions const& collisions, + o2::aod::FT0s const& ft0s, + o2::aod::FDDs const& fdds, + o2::aod::FV0As const& fv0as, + o2::aod::Zdcs const& zdcs) + { + fDoMC = false; + createCandidatesFwdGlobal(fwdTracks, fwdTrkClusters, ambFwdTracks, + bcs, collisions, + ft0s, fdds, fv0as, zdcs, + (o2::aod::McFwdTrackLabels*)nullptr); + } + + void processForwardGlobalMC(ForwardTracks const& fwdTracks, + o2::aod::FwdTrkCls const& fwdTrkClusters, + o2::aod::AmbiguousFwdTracks const& ambFwdTracks, + BCsWithBcSels const& bcs, + o2::aod::Collisions const& collisions, + o2::aod::FT0s const& ft0s, + o2::aod::FDDs const& fdds, + o2::aod::FV0As const& fv0as, + o2::aod::Zdcs const& zdcs, + o2::aod::McCollisions const& mcCollisions, o2::aod::McParticles const& mcParticles, + o2::aod::McFwdTrackLabels const& mcFwdTrackLabels) + { + fDoMC = true; + skimMCInfo(mcCollisions, mcParticles, bcs); + createCandidatesFwdGlobal(fwdTracks, fwdTrkClusters, ambFwdTracks, + bcs, collisions, + ft0s, fdds, fv0as, zdcs, + &mcFwdTrackLabels); + fNewPartIDs.clear(); + } + PROCESS_SWITCH(UpcCandProducer, processSemiFwd, "Produce candidates in semiforward/forward region", false); PROCESS_SWITCH(UpcCandProducer, processCentral, "Produce candidates in central region", false); PROCESS_SWITCH(UpcCandProducer, processSemiFwdMC, "Produce candidates in semiforward/forward region with MC information", false); PROCESS_SWITCH(UpcCandProducer, processCentralMC, "Produce candidates in central region with MC information", false); - PROCESS_SWITCH(UpcCandProducer, processForward, "Produce caniddates in forward region", false); - PROCESS_SWITCH(UpcCandProducer, processForwardMC, "Produce caniddates in forward region with MC information", false); + PROCESS_SWITCH(UpcCandProducer, processForward, "Produce candidates in forward region", false); + PROCESS_SWITCH(UpcCandProducer, processForwardGlobal, "Produce candidates in forward region with MFT", true); + PROCESS_SWITCH(UpcCandProducer, processForwardMC, "Produce candidates in forward region with MC information", false); + PROCESS_SWITCH(UpcCandProducer, processForwardGlobalMC, "Produce candidates in forward region with MFT and MC information", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGUD/TableProducer/fwdTrackPropagation.cxx b/PWGUD/TableProducer/fwdTrackPropagation.cxx index 4064b9df538..cc6ba621690 100644 --- a/PWGUD/TableProducer/fwdTrackPropagation.cxx +++ b/PWGUD/TableProducer/fwdTrackPropagation.cxx @@ -8,6 +8,9 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \author Nazar Burmasov, nazar.burmasov@cern.ch +/// \author Diana Krupova, diana.krupova@cern.ch +/// \since 04.06.2024 #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" @@ -15,6 +18,8 @@ #include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" +#include "TGeoGlobalMagField.h" +#include "Field/MagneticField.h" #include "DetectorsBase/Propagator.h" #include "GlobalTracking/MatchGlobalFwd.h" #include "MCHTracking/TrackExtrap.h" @@ -60,20 +65,31 @@ struct FwdTrackPropagation { muon.cPhiPhi(), muon.cTglX(), muon.cTglY(), muon.cTglPhi(), muon.cTglTgl(), muon.c1PtX(), muon.c1PtY(), muon.c1PtPhi(), muon.c1PtTgl(), muon.c1Pt21Pt2()}; SMatrix55 tcovs(v1.begin(), v1.end()); - o2::track::TrackParCovFwd fwdtrack{muon.z(), tpars, tcovs, chi2}; o2::dataformats::GlobalFwdTrack propmuon; - o2::dataformats::GlobalFwdTrack track; - track.setParameters(tpars); - track.setZ(fwdtrack.getZ()); - track.setCovariances(tcovs); - auto mchTrack = fMatching.FwdtoMCH(track); - o2::mch::TrackExtrap::extrapToVertex(mchTrack, vtx[0], vtx[1], vtx[2], vtxCov[0], vtxCov[1]); - auto proptrack = fMatching.MCHtoFwd(mchTrack); - propmuon.setParameters(proptrack.getParameters()); - propmuon.setZ(proptrack.getZ()); - propmuon.setCovariances(proptrack.getCovariances()); + if (static_cast(muon.trackType()) > 2) { + o2::dataformats::GlobalFwdTrack track; + track.setParameters(tpars); + track.setZ(fwdtrack.getZ()); + track.setCovariances(tcovs); + auto mchTrack = fMatching.FwdtoMCH(track); + o2::mch::TrackExtrap::extrapToVertex(mchTrack, vtx[0], vtx[1], vtx[2], vtxCov[0], vtxCov[1]); + auto proptrack = fMatching.MCHtoFwd(mchTrack); + propmuon.setParameters(proptrack.getParameters()); + propmuon.setZ(proptrack.getZ()); + propmuon.setCovariances(proptrack.getCovariances()); + } else if (static_cast(muon.trackType()) < 2) { + double centerMFT[3] = {0, 0, -61.4}; + o2::field::MagneticField* field = static_cast(TGeoGlobalMagField::Instance()->GetField()); + auto Bz = field->getBz(centerMFT); // Get field at centre of MFT + auto geoMan = o2::base::GeometryManager::meanMaterialBudget(muon.x(), muon.y(), muon.z(), vtx[0], vtx[1], vtx[2]); + auto x2x0 = static_cast(geoMan.meanX2X0); + fwdtrack.propagateToVtxhelixWithMCS(vtx[2], {vtx[0], vtx[1]}, {vtxCov[0], vtxCov[1]}, Bz, x2x0); + propmuon.setParameters(fwdtrack.getParameters()); + propmuon.setZ(fwdtrack.getZ()); + propmuon.setCovariances(fwdtrack.getCovariances()); + } return propmuon; } @@ -83,9 +99,9 @@ struct FwdTrackPropagation { if (run != fRun) { fRun = run; - std::map metadata, headers; - headers = fCCDBApi.retrieveHeaders(Form("RCT/Info/RunInformation/%i", run), metadata, -1); - int64_t ts = std::atol(headers["SOR"].c_str()); + std::map metadata; + auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(fCCDBApi, run); + auto ts = soreor.first; auto grpmag = fCCDBApi.retrieveFromTFileAny("GLO/Config/GRPMagField", metadata, ts); o2::base::Propagator::initFieldFromGRP(grpmag); if (!o2::base::GeometryManager::isGeometryLoaded()) @@ -126,16 +142,16 @@ struct FwdTrackPropagation { float sigPhi = TMath::Sqrt(cov(2, 2)); float sigTgl = TMath::Sqrt(cov(3, 3)); float sig1Pt = TMath::Sqrt(cov(4, 4)); - auto rhoXY = static_cast(128. * cov(0, 1) / (sigX * sigY)); - auto rhoPhiX = static_cast(128. * cov(0, 2) / (sigPhi * sigX)); - auto rhoPhiY = static_cast(128. * cov(1, 2) / (sigPhi * sigY)); - auto rhoTglX = static_cast(128. * cov(0, 3) / (sigTgl * sigX)); - auto rhoTglY = static_cast(128. * cov(1, 3) / (sigTgl * sigY)); - auto rhoTglPhi = static_cast(128. * cov(2, 3) / (sigTgl * sigPhi)); - auto rho1PtX = static_cast(128. * cov(0, 4) / (sig1Pt * sigX)); - auto rho1PtY = static_cast(128. * cov(1, 4) / (sig1Pt * sigY)); - auto rho1PtPhi = static_cast(128. * cov(2, 4) / (sig1Pt * sigPhi)); - auto rho1PtTgl = static_cast(128. * cov(3, 4) / (sig1Pt * sigTgl)); + auto rhoXY = static_cast(128. * cov(0, 1) / (sigX * sigY)); + auto rhoPhiX = static_cast(128. * cov(0, 2) / (sigPhi * sigX)); + auto rhoPhiY = static_cast(128. * cov(1, 2) / (sigPhi * sigY)); + auto rhoTglX = static_cast(128. * cov(0, 3) / (sigTgl * sigX)); + auto rhoTglY = static_cast(128. * cov(1, 3) / (sigTgl * sigY)); + auto rhoTglPhi = static_cast(128. * cov(2, 3) / (sigTgl * sigPhi)); + auto rho1PtX = static_cast(128. * cov(0, 4) / (sig1Pt * sigX)); + auto rho1PtY = static_cast(128. * cov(1, 4) / (sig1Pt * sigY)); + auto rho1PtPhi = static_cast(128. * cov(2, 4) / (sig1Pt * sigPhi)); + auto rho1PtTgl = static_cast(128. * cov(3, 4) / (sig1Pt * sigTgl)); propFwdTracksCov(sigX, sigY, sigTgl, sigPhi, sig1Pt, rhoXY, rhoPhiX, rhoPhiY, rhoTglX, rhoTglY, rhoTglPhi, rho1PtX, rho1PtY, diff --git a/PWGUD/TableProducer/tauEventTableProducer.cxx b/PWGUD/TableProducer/tauEventTableProducer.cxx new file mode 100644 index 00000000000..035cd4de860 --- /dev/null +++ b/PWGUD/TableProducer/tauEventTableProducer.cxx @@ -0,0 +1,501 @@ +// 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 tauEventTableProducer.cxx +/// \brief Produces derived table from UD tables +/// +/// \author Roman Lavicka , Austrian Academy of Sciences & SMI +/// \since 09.04.2025 +// + +// C++ headers +#include +#include +#include +#include +#include + +// O2 headers +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +// O2Physics headers +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/DataModel/UDIndex.h" // for UDMcParticles2UDTracks table +#include "PWGUD/Core/SGSelector.h" + +// ROOT headers +#include "TLorentzVector.h" +#include "TPDGCode.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +namespace o2::aod +{ +namespace tau_tree +{ +// event info +DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); +DECLARE_SOA_COLUMN(Bc, bc, int); +DECLARE_SOA_COLUMN(TotalTracks, totalTracks, int); +DECLARE_SOA_COLUMN(NumContrib, numContrib, int); +DECLARE_SOA_COLUMN(GlobalNonPVtracks, globalNonPVtracks, int); +DECLARE_SOA_COLUMN(PosX, posX, float); +DECLARE_SOA_COLUMN(PosY, posY, float); +DECLARE_SOA_COLUMN(PosZ, posZ, float); +DECLARE_SOA_COLUMN(RecoMode, recoMode, int); +DECLARE_SOA_COLUMN(OccupancyInTime, occupancyInTime, int); +DECLARE_SOA_COLUMN(HadronicRate, hadronicRate, double); +DECLARE_SOA_COLUMN(Trs, trs, int); +DECLARE_SOA_COLUMN(Trofs, trofs, int); +DECLARE_SOA_COLUMN(Hmpr, hmpr, int); +DECLARE_SOA_COLUMN(Tfb, tfb, int); +DECLARE_SOA_COLUMN(ItsRofb, itsRofb, int); +DECLARE_SOA_COLUMN(Sbp, sbp, int); +DECLARE_SOA_COLUMN(ZvtxFT0vsPv, zvtxFT0vsPv, int); +DECLARE_SOA_COLUMN(VtxITSTPC, vtxITSTPC, int); +// FIT info +DECLARE_SOA_COLUMN(TotalFT0AmplitudeA, totalFT0AmplitudeA, float); +DECLARE_SOA_COLUMN(TotalFT0AmplitudeC, totalFT0AmplitudeC, float); +DECLARE_SOA_COLUMN(TotalFV0AmplitudeA, totalFV0AmplitudeA, float); +DECLARE_SOA_COLUMN(EnergyCommonZNA, energyCommonZNA, float); +DECLARE_SOA_COLUMN(EnergyCommonZNC, energyCommonZNC, float); +DECLARE_SOA_COLUMN(TimeFT0A, timeFT0A, float); +DECLARE_SOA_COLUMN(TimeFT0C, timeFT0C, float); +DECLARE_SOA_COLUMN(TimeFV0A, timeFV0A, float); +DECLARE_SOA_COLUMN(TimeZNA, timeZNA, float); +DECLARE_SOA_COLUMN(TimeZNC, timeZNC, float); +// tracks +DECLARE_SOA_COLUMN(TrkPx, trkPx, float[2]); +DECLARE_SOA_COLUMN(TrkPy, trkPy, float[2]); +DECLARE_SOA_COLUMN(TrkPz, trkPz, float[2]); +DECLARE_SOA_COLUMN(TrkSign, trkSign, int[2]); +DECLARE_SOA_COLUMN(TrkDCAxy, trkDCAxy, float[2]); +DECLARE_SOA_COLUMN(TrkDCAz, trkDCAz, float[2]); +DECLARE_SOA_COLUMN(TrkTimeRes, trkTimeRes, float[2]); +DECLARE_SOA_COLUMN(Trk1ITSclusterSizes, trk1ITSclusterSizes, uint32_t); +DECLARE_SOA_COLUMN(Trk2ITSclusterSizes, trk2ITSclusterSizes, uint32_t); +DECLARE_SOA_COLUMN(TrkTPCsignal, trkTPCsignal, float[2]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaEl, trkTPCnSigmaEl, float[2]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaMu, trkTPCnSigmaMu, float[2]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaPi, trkTPCnSigmaPi, float[2]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaKa, trkTPCnSigmaKa, float[2]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaPr, trkTPCnSigmaPr, float[2]); +DECLARE_SOA_COLUMN(TrkTPCinnerParam, trkTPCinnerParam, float[2]); +DECLARE_SOA_COLUMN(TrkTOFsignal, trkTOFsignal, float[2]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaEl, trkTOFnSigmaEl, float[2]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaMu, trkTOFnSigmaMu, float[2]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaPi, trkTOFnSigmaPi, float[2]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaKa, trkTOFnSigmaKa, float[2]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaPr, trkTOFnSigmaPr, float[2]); +DECLARE_SOA_COLUMN(TrkTOFexpMom, trkTOFexpMom, float[2]); + +} // namespace tau_tree +DECLARE_SOA_TABLE(TauTwoTracks, "AOD", "TAUTWOTRACK", + tau_tree::RunNumber, tau_tree::Bc, tau_tree::TotalTracks, tau_tree::NumContrib, tau_tree::GlobalNonPVtracks, tau_tree::PosX, tau_tree::PosY, tau_tree::PosZ, + tau_tree::RecoMode, tau_tree::OccupancyInTime, tau_tree::HadronicRate, + tau_tree::Trs, tau_tree::Trofs, tau_tree::Hmpr, tau_tree::Tfb, tau_tree::ItsRofb, tau_tree::Sbp, tau_tree::ZvtxFT0vsPv, tau_tree::VtxITSTPC, + tau_tree::TotalFT0AmplitudeA, tau_tree::TotalFT0AmplitudeC, tau_tree::TotalFV0AmplitudeA, tau_tree::EnergyCommonZNA, tau_tree::EnergyCommonZNC, + tau_tree::TimeFT0A, tau_tree::TimeFT0C, tau_tree::TimeFV0A, tau_tree::TimeZNA, tau_tree::TimeZNC, + tau_tree::TrkPx, tau_tree::TrkPy, tau_tree::TrkPz, tau_tree::TrkSign, tau_tree::TrkDCAxy, tau_tree::TrkDCAz, tau_tree::TrkTimeRes, + tau_tree::Trk1ITSclusterSizes, tau_tree::Trk2ITSclusterSizes, + tau_tree::TrkTPCsignal, tau_tree::TrkTPCnSigmaEl, tau_tree::TrkTPCnSigmaMu, tau_tree::TrkTPCnSigmaPi, tau_tree::TrkTPCnSigmaKa, tau_tree::TrkTPCnSigmaPr, tau_tree::TrkTPCinnerParam, + tau_tree::TrkTOFsignal, tau_tree::TrkTOFnSigmaEl, tau_tree::TrkTOFnSigmaMu, tau_tree::TrkTOFnSigmaPi, tau_tree::TrkTOFnSigmaKa, tau_tree::TrkTOFnSigmaPr, tau_tree::TrkTOFexpMom); + +} // namespace o2::aod + +struct TauEventTableProducer { + Produces tauTwoTracks; + + // Global varialbes + Service pdg; + SGSelector sgSelector; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // declare configurables + Configurable verboseInfo{"verboseInfo", false, {"Print general info to terminal; default it false."}}; + + struct : ConfigurableGroup { + Configurable whichGapSide{"whichGapSide", 2, {"0 for side A, 1 for side C, 2 for both sides"}}; + Configurable useTrueGap{"useTrueGap", true, {"Calculate gapSide for a given FV0/FT0/ZDC thresholds"}}; + Configurable cutNumContribs{"cutNumContribs", 2, {"How many contributors event has"}}; + Configurable useNumContribs{"useNumContribs", false, {"Use coll.numContribs as event cut"}}; + Configurable cutRecoFlag{"cutRecoFlag", 1, {"0 = std mode, 1 = upc mode"}}; + Configurable useRecoFlag{"useRecoFlag", false, {"Use coll.flags as event cut"}}; + Configurable cutTrueGapSideFV0{"cutTrueGapSideFV0", 180000, "FV0A threshold for SG selector"}; + Configurable cutTrueGapSideFT0A{"cutTrueGapSideFT0A", 150., "FT0A threshold for SG selector"}; + Configurable cutTrueGapSideFT0C{"cutTrueGapSideFT0C", 50., "FT0C threshold for SG selector"}; + Configurable cutTrueGapSideZDC{"cutTrueGapSideZDC", 10000., "ZDC threshold for SG selector. 0 is <1n, 4.2 is <2n, 6.7 is <3n, 9.5 is <4n, 12.5 is <5n"}; + Configurable cutFITtime{"cutFITtime", 40., "Maximum FIT time allowed. Default is 40ns"}; + Configurable cutEvOccupancy{"cutEvOccupancy", 100000., "Maximum allowed occupancy"}; + Configurable cutEvTrs{"cutEvTrs", false, {"Event selection bit kNoCollInTimeRangeStandard"}}; + Configurable cutEvTrofs{"cutEvTrofs", false, {"Event selection bit kNoCollInRofStandard"}}; + Configurable cutEvHmpr{"cutEvHmpr", false, {"Event selection bit kNoHighMultCollInPrevRof"}}; + } cutSample; + + struct : ConfigurableGroup { + Configurable applyGlobalTrackSelection{"applyGlobalTrackSelection", false, {"Applies cut on here defined global tracks"}}; + Configurable cutMinPt{"cutMinPt", 0.1f, {"Global track cut"}}; + Configurable cutMaxPt{"cutMaxPt", 1e10f, {"Global track cut"}}; + Configurable cutMinEta{"cutMinEta", -0.8f, {"Global track cut"}}; + Configurable cutMaxEta{"cutMaxEta", 0.8f, {"Global track cut"}}; + Configurable cutMaxDCAz{"cutMaxDCAz", 2.f, {"Global track cut"}}; + Configurable cutMaxDCAxy{"cutMaxDCAxy", 1e10f, {"Global track cut"}}; + Configurable applyPtDependentDCAxy{"applyPtDependentDCAxy", false, {"Global track cut"}}; + Configurable cutHasITS{"cutHasITS", true, {"Global track cut"}}; + Configurable cutMinITSnCls{"cutMinITSnCls", 1, {"Global track cut"}}; + Configurable cutMaxITSchi2{"cutMaxITSchi2", 36.f, {"Global track cut"}}; + Configurable cutITShitsRule{"cutITShitsRule", 0, {"Global track cut"}}; + Configurable cutHasTPC{"cutHasTPC", true, {"Global track cut"}}; + Configurable cutMinTPCnCls{"cutMinTPCnCls", 1, {"Global track cut"}}; + Configurable cutMinTPCnClsXrows{"cutMinTPCnClsXrows", 70, {"Global track cut"}}; + Configurable cutMinTPCnClsXrowsOverNcls{"cutMinTPCnClsXrowsOverNcls", 0.8f, {"Global track cut"}}; + Configurable cutMaxTPCchi2{"cutMaxTPCchi2", 4.f, {"Global track cut"}}; + Configurable cutGoodITSTPCmatching{"cutGoodITSTPCmatching", true, {"Global track cut"}}; + Configurable cutMaxTOFchi2{"cutMaxTOFchi2", 3.f, {"Global track cut"}}; + } cutGlobalTrack; + + struct : ConfigurableGroup { + Configurable preselUseTrackPID{"preselUseTrackPID", true, {"Apply weak PID check on tracks."}}; + Configurable preselNgoodPVtracs{"preselNgoodPVtracs", 2, {"How many good PV tracks to select."}}; + Configurable preselMinElectronNsigmaEl{"preselMinElectronNsigmaEl", 4.0, {"Good el candidate hypo in. Upper n sigma cut on el hypo of selected electron. What is more goes away."}}; + Configurable preselMaxElectronNsigmaEl{"preselMaxElectronNsigmaEl", -2.0, {"Good el candidate hypo in. Lower n sigma cut on el hypo of selected electron. What is less goes away."}}; + Configurable preselElectronHasTOF{"preselElectronHasTOF", true, {"Electron candidated is required to hit TOF."}}; + Configurable preselMinPionNsigmaEl{"preselMinPionNsigmaEl", 5.0, {"Good pi candidate hypo in. Upper n sigma cut on pi hypo of selected electron. What is more goes away."}}; + Configurable preselMaxPionNsigmaEl{"preselMaxPionNsigmaEl", -5.0, {"Good pi candidate hypo in. Lower n sigma cut on pi hypo of selected electron. What is less goes away."}}; + Configurable preselMinMuonNsigmaEl{"preselMinMuonNsigmaEl", 5.0, {"Good pi candidate hypo in. Upper n sigma cut on pi hypo of selected electron. What is more goes away."}}; + Configurable preselMaxMuonNsigmaEl{"preselMaxMuonNsigmaEl", -5.0, {"Good pi candidate hypo in. Lower n sigma cut on pi hypo of selected electron. What is less goes away."}}; + Configurable preselMupionHasTOF{"preselMupionHasTOF", true, {"Mupion candidate is required to hit TOF."}}; + } cutPreselect; + + using FullUDTracks = soa::Join; + using FullSGUDCollisions = soa::Join; + using FullSGUDCollision = FullSGUDCollisions::iterator; + using FullMCUDTracks = soa::Join; + using FullMCSGUDCollisions = soa::Join; + using FullMCSGUDCollision = FullMCSGUDCollisions::iterator; + using UDMcParticlesWithUDTracks = soa::Join; + using UDMcCollisionsWithUDCollisions = soa::Join; + using UDMcCollisionsWithUDCollision = UDMcCollisionsWithUDCollisions::iterator; + + // init + void init(InitContext&) + { + if (verboseInfo) + printMediumMessage("INIT METHOD"); + + mySetITShitsRule(cutGlobalTrack.cutITShitsRule); + + } // end init + + template + bool isGoodFITtime(C const& coll, float maxFITtime) + { + + // FTOA + if ((std::abs(coll.timeFT0A()) > maxFITtime) && coll.timeFT0A() > -998.) + return false; + + // FTOC + if ((std::abs(coll.timeFT0C()) > maxFITtime) && coll.timeFT0C() > -998.) + return false; + + return true; + } + + template + bool isGoodROFtime(C const& coll) + { + + // Occupancy + if (coll.occupancyInTime() > cutSample.cutEvOccupancy) + return false; + + // kNoCollInTimeRangeStandard + if (cutSample.cutEvTrs && !coll.trs()) + return false; + + // kNoCollInRofStandard + if (cutSample.cutEvTrofs && !coll.trofs()) + return false; + + // kNoHighMultCollInPrevRof + if (cutSample.cutEvHmpr && !coll.hmpr()) + return false; + + return true; + } + + std::vector>> cutMyRequiredITSHits{}; + + void mySetRequireHitsInITSLayers(int8_t minNRequiredHits, std::set requiredLayers) + { + // layer 0 corresponds to the the innermost ITS layer + cutMyRequiredITSHits.push_back(std::make_pair(minNRequiredHits, requiredLayers)); + } + + void mySetITShitsRule(int matching) + { + switch (matching) { + case 0: // Run3ITSibAny + mySetRequireHitsInITSLayers(1, {0, 1, 2}); + break; + case 1: // Run3ITSibTwo + mySetRequireHitsInITSLayers(2, {0, 1, 2}); + break; + case 2: // Run3ITSallAny + mySetRequireHitsInITSLayers(1, {0, 1, 2, 3, 4, 5, 6}); + break; + case 3: // Run3ITSall7Layers + mySetRequireHitsInITSLayers(7, {0, 1, 2, 3, 4, 5, 6}); + break; + default: + LOG(fatal) << "You chose wrong ITS matching"; + break; + } + } + + bool isFulfillsITSHitRequirementsReinstatement(uint8_t itsClusterMap) const + { + constexpr uint8_t kBit = 1; + for (const auto& kITSrequirement : cutMyRequiredITSHits) { + auto hits = std::count_if(kITSrequirement.second.begin(), kITSrequirement.second.end(), [&](auto&& requiredLayer) { return itsClusterMap & (kBit << requiredLayer); }); + if ((kITSrequirement.first == -1) && (hits > 0)) { + return false; // no hits were required in specified layers + } else if (hits < kITSrequirement.first) { + return false; // not enough hits found in specified layers + } + } + return true; + } + + template + bool isGlobalTrackReinstatement(T const& track) + { + // kInAcceptance copy + if (track.pt() < cutGlobalTrack.cutMinPt || track.pt() > cutGlobalTrack.cutMaxPt) + return false; + if (eta(track.px(), track.py(), track.pz()) < cutGlobalTrack.cutMinEta || eta(track.px(), track.py(), track.pz()) > cutGlobalTrack.cutMaxEta) + return false; + // kPrimaryTracks + // GoldenChi2 cut is only for Run 2 + if (std::abs(track.dcaZ()) > cutGlobalTrack.cutMaxDCAz) + return false; + if (cutGlobalTrack.applyPtDependentDCAxy) { + float maxDCA = 0.0182f + 0.0350f / std::pow(track.pt(), 1.01f); + if (std::abs(track.dcaXY()) > maxDCA) + return false; + } else { + if (std::abs(track.dcaXY()) > cutGlobalTrack.cutMaxDCAxy) + return false; + } + // kQualityTrack + // TrackType is always 1 as per definition of processed Run3 AO2Ds + // ITS + if (cutGlobalTrack.cutHasITS && !track.hasITS()) + return false; // ITS refit + if (track.itsNCls() < cutGlobalTrack.cutMinITSnCls) + return false; + if (track.itsChi2NCl() > cutGlobalTrack.cutMaxITSchi2) + return false; + if (!isFulfillsITSHitRequirementsReinstatement(track.itsClusterMap())) + return false; + // TPC + if (cutGlobalTrack.cutHasTPC && !track.hasTPC()) + return false; // TPC refit + if ((track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) < cutGlobalTrack.cutMinTPCnCls) + return false; // tpcNClsFound() + if (track.tpcNClsCrossedRows() < cutGlobalTrack.cutMinTPCnClsXrows) + return false; + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < cutGlobalTrack.cutMinTPCnClsXrowsOverNcls) + return false; + if (track.tpcChi2NCl() > cutGlobalTrack.cutMaxTPCchi2) + return false; // TPC chi2 + if (cutGlobalTrack.cutGoodITSTPCmatching) { + if (track.itsChi2NCl() < 0.) + return false; // TPC chi2 + } + // TOF + if (track.hasTOF()) { + if (track.tpcChi2NCl() > cutGlobalTrack.cutMaxTOFchi2) + return false; // TOF chi2 + } + + return true; + } + + template + bool isElectronCandidate(T const& electronCandidate) + // Loose criterium to find electron-like particle + // Requiring TOF to avoid double-counting pions/electrons and for better timing + { + if (electronCandidate.tpcNSigmaEl() < cutPreselect.preselMaxElectronNsigmaEl || electronCandidate.tpcNSigmaEl() > cutPreselect.preselMinElectronNsigmaEl) + return false; + if (cutPreselect.preselElectronHasTOF && !electronCandidate.hasTOF()) + return false; + return true; + } + + template + bool isMuPionCandidate(T const& muPionCandidate) + // Loose criterium to find muon/pion-like particle + // Requiring TOF for better timing + { + if (muPionCandidate.tpcNSigmaMu() < cutPreselect.preselMaxMuonNsigmaEl || muPionCandidate.tpcNSigmaMu() > cutPreselect.preselMinMuonNsigmaEl) + return false; + if (muPionCandidate.tpcNSigmaPi() < cutPreselect.preselMaxPionNsigmaEl || muPionCandidate.tpcNSigmaPi() > cutPreselect.preselMinPionNsigmaEl) + return false; + if (cutPreselect.preselMupionHasTOF && !muPionCandidate.hasTOF()) + return false; + return true; + } + + void processDataSG(FullSGUDCollision const& collision, + FullUDTracks const& tracks) + { + + int gapSide = collision.gapSide(); + int trueGapSide = sgSelector.trueGap(collision, cutSample.cutTrueGapSideFV0, cutSample.cutTrueGapSideFT0A, cutSample.cutTrueGapSideFT0C, cutSample.cutTrueGapSideZDC); + + if (cutSample.useTrueGap) + gapSide = trueGapSide; + + if (!isGoodROFtime(collision)) + return; + + if (gapSide != cutSample.whichGapSide) + return; + + if (!isGoodFITtime(collision, cutSample.cutFITtime)) + return; + + if (cutSample.useNumContribs && (collision.numContrib() != cutSample.cutNumContribs)) + return; + + if (cutSample.useRecoFlag && (collision.flags() != cutSample.cutRecoFlag)) + return; + + int countTracksPerCollision = 0; + int countGoodNonPVtracks = 0; + int countGoodPVtracks = 0; + std::vector vecTrkIdx; + // Loop over tracks with selections + for (const auto& track : tracks) { + countTracksPerCollision++; + if (!isGlobalTrackReinstatement(track)) + continue; + if (!track.isPVContributor()) { + countGoodNonPVtracks++; + continue; + } + countGoodPVtracks++; + vecTrkIdx.push_back(track.index()); + } // Loop over tracks with selections + + // Apply weak condition on track PID + int countPVGTel = 0; + int countPVGTmupi = 0; + if (countGoodPVtracks == 2) { + for (const auto& vecMember : vecTrkIdx) { + const auto& thisTrk = tracks.iteratorAt(vecMember); + if (isElectronCandidate(thisTrk)) { + countPVGTel++; + continue; + } + if (isMuPionCandidate(thisTrk)) { + countPVGTmupi++; + } + } + } + + if (cutPreselect.preselUseTrackPID ? ((countPVGTel == 2 && countPVGTmupi == 0) || (countPVGTel == 1 && countPVGTmupi == 1)) : countGoodPVtracks == cutPreselect.preselNgoodPVtracs) { + const auto& trk1 = tracks.iteratorAt(vecTrkIdx[0]); + const auto& trk2 = tracks.iteratorAt(vecTrkIdx[1]); + + float px[2] = {trk1.px(), trk2.px()}; + float py[2] = {trk1.py(), trk2.py()}; + float pz[2] = {trk1.pz(), trk2.pz()}; + int sign[2] = {trk1.sign(), trk2.sign()}; + float dcaxy[2] = {trk1.dcaXY(), trk2.dcaXY()}; + float dcaz[2] = {trk1.dcaZ(), trk2.dcaZ()}; + float trkTimeRes[2] = {trk1.trackTimeRes(), trk2.trackTimeRes()}; + uint32_t itsClusterSizesTrk1 = trk1.itsClusterSizes(); + uint32_t itsClusterSizesTrk2 = trk2.itsClusterSizes(); + float tpcSignal[2] = {trk1.tpcSignal(), trk2.tpcSignal()}; + float tpcEl[2] = {trk1.tpcNSigmaEl(), trk2.tpcNSigmaEl()}; + float tpcMu[2] = {trk1.tpcNSigmaMu(), trk2.tpcNSigmaMu()}; + float tpcPi[2] = {trk1.tpcNSigmaPi(), trk2.tpcNSigmaPi()}; + float tpcKa[2] = {trk1.tpcNSigmaKa(), trk2.tpcNSigmaKa()}; + float tpcPr[2] = {trk1.tpcNSigmaPr(), trk2.tpcNSigmaPr()}; + float tpcIP[2] = {trk1.tpcInnerParam(), trk2.tpcInnerParam()}; + float tofSignal[2] = {trk1.tofSignal(), trk2.tofSignal()}; + float tofEl[2] = {trk1.tofNSigmaEl(), trk2.tofNSigmaEl()}; + float tofMu[2] = {trk1.tofNSigmaMu(), trk2.tofNSigmaMu()}; + float tofPi[2] = {trk1.tofNSigmaPi(), trk2.tofNSigmaPi()}; + float tofKa[2] = {trk1.tofNSigmaKa(), trk2.tofNSigmaKa()}; + float tofPr[2] = {trk1.tofNSigmaPr(), trk2.tofNSigmaPr()}; + float tofEP[2] = {trk1.tofExpMom(), trk2.tofExpMom()}; + // float infoZDC[4] = {-999., -999., -999., -999.}; + // if constexpr (requires { collision.udZdcsReduced(); }) { + // infoZDC[0] = collision.energyCommonZNA(); + // infoZDC[1] = collision.energyCommonZNC(); + // infoZDC[2] = collision.timeZNA(); + // infoZDC[3] = collision.timeZNC(); + // } + float infoZDC[4] = {collision.energyCommonZNA(), collision.energyCommonZNC(), collision.timeZNA(), collision.timeZNC()}; + + tauTwoTracks(collision.runNumber(), collision.globalBC(), countTracksPerCollision, collision.numContrib(), countGoodNonPVtracks, collision.posX(), collision.posY(), collision.posZ(), + collision.flags(), collision.occupancyInTime(), collision.hadronicRate(), collision.trs(), collision.trofs(), collision.hmpr(), + collision.tfb(), collision.itsROFb(), collision.sbp(), collision.zVtxFT0vPV(), collision.vtxITSTPC(), + collision.totalFT0AmplitudeA(), collision.totalFT0AmplitudeC(), collision.totalFV0AmplitudeA(), infoZDC[0], infoZDC[1], + collision.timeFT0A(), collision.timeFT0C(), collision.timeFV0A(), infoZDC[2], infoZDC[3], + px, py, pz, sign, dcaxy, dcaz, trkTimeRes, + itsClusterSizesTrk1, itsClusterSizesTrk2, + tpcSignal, tpcEl, tpcMu, tpcPi, tpcKa, tpcPr, tpcIP, + tofSignal, tofEl, tofMu, tofPi, tofKa, tofPr, tofEP); + } + } + PROCESS_SWITCH(TauEventTableProducer, processDataSG, "Iterate UD tables with measured data created by SG-Candidate-Producer.", false); + + void processMonteCarlo(UDMcCollisionsWithUDCollision const& mccollision, + FullMCSGUDCollisions const&, + FullUDTracks const&, + UDMcParticlesWithUDTracks const&) + { + LOGF(info, "mccollision idx %i", mccollision.globalIndex()); + if (mccollision.has_udcollisions()) { + auto const& collFromMcColl = mccollision.udcollisions_as(); + LOGF(info, "collision size %i ", collFromMcColl.size()); + } + } + PROCESS_SWITCH(TauEventTableProducer, processMonteCarlo, "Iterate UD tables with simulated data created by SG-Candidate-Producer.", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/TableProducer/udMcCollisions2udCollisions.cxx b/PWGUD/TableProducer/udMcCollisions2udCollisions.cxx new file mode 100644 index 00000000000..cea35fb70ea --- /dev/null +++ b/PWGUD/TableProducer/udMcCollisions2udCollisions.cxx @@ -0,0 +1,75 @@ +// 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 udMcCollisions2udCollisions.cxx +/// \author Roman Lavička +/// \since 2025-04-15 +/// \brief A task to create a reverse index from UDMcCollisions to UDCollisions +/// + +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/DataModel/UDIndex.h" + +using namespace o2; +using namespace o2::framework; + +struct UDMcCollisions2UDCollisions { + using LabeledCollisions = soa::Join; + Produces udmcc2udc; + + std::vector collisionIds; + + void init(InitContext&) + { + } + + void process(aod::UDMcCollisions const& mcCollisions) + { + if (doprocessIndexingCentral || doprocessIndexingCentralFast) { + udmcc2udc.reserve(mcCollisions.size()); + } + } + + void processIndexingCentralFast(aod::UDMcCollisions const& mcCollisions, LabeledCollisions const& collisions) + { + // faster version, but will use more memory due to pre-allocation + std::vector> mccoll2coll(mcCollisions.size()); + for (const auto& collision : collisions) { + if (collision.has_udMcCollision()) + mccoll2coll[collision.udMcCollisionId()].push_back(collision.globalIndex()); + } + for (const auto& mcCollision : mcCollisions) { + udmcc2udc(mccoll2coll[mcCollision.globalIndex()]); + } + } + PROCESS_SWITCH(UDMcCollisions2UDCollisions, processIndexingCentralFast, "Create reverse index from mccollisions to collision: more memory use but potentially faster", true); + + void processIndexingCentral(aod::UDMcCollisions const&, soa::SmallGroups const& collisions) + { + collisionIds.clear(); + for (const auto& collision : collisions) { + collisionIds.push_back(collision.globalIndex()); + } + udmcc2udc(collisionIds); + } + PROCESS_SWITCH(UDMcCollisions2UDCollisions, processIndexingCentral, "Create reverse index from mccollisions to collision", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/TableProducer/udMcParticles2udTracks.cxx b/PWGUD/TableProducer/udMcParticles2udTracks.cxx new file mode 100644 index 00000000000..4a876a72fb3 --- /dev/null +++ b/PWGUD/TableProducer/udMcParticles2udTracks.cxx @@ -0,0 +1,75 @@ +// 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 udMcParticles2udTracks.cxx +/// \author Roman Lavička +/// \since 2025-04-15 +/// \brief A task to create a reverse index from UDMcParticles to UDTracks +/// + +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/DataModel/UDIndex.h" + +using namespace o2; +using namespace o2::framework; + +struct UDMcParticlesToUDTracks { + using LabeledTracks = soa::Join; + Produces udp2udt; + + std::vector trackIds; + + void init(InitContext&) + { + } + + void process(aod::UDMcParticles const& particles) + { + if (doprocessIndexingCentral || doprocessIndexingCentralFast) { + udp2udt.reserve(particles.size()); + } + } + + void processIndexingCentralFast(aod::UDMcParticles const& mcParticles, LabeledTracks const& tracks) + { + // faster version, but will use more memory due to pre-allocation + std::vector> part2track(mcParticles.size()); + for (const auto& track : tracks) { + if (track.has_udMcParticle()) + part2track[track.udMcParticleId()].push_back(track.globalIndex()); + } + for (const auto& mcParticle : mcParticles) { + udp2udt(part2track[mcParticle.globalIndex()]); + } + } + PROCESS_SWITCH(UDMcParticlesToUDTracks, processIndexingCentralFast, "Create reverse index from particles to tracks: more memory use but potentially faster", true); + + void processIndexingCentral(aod::UDMcParticles const&, soa::SmallGroups const& tracks) + { + trackIds.clear(); + for (const auto& track : tracks) { + trackIds.push_back(track.globalIndex()); + } + udp2udt(trackIds); + } + PROCESS_SWITCH(UDMcParticlesToUDTracks, processIndexingCentral, "Create reverse index from particles to tracks", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/CMakeLists.txt b/PWGUD/Tasks/CMakeLists.txt index e482df61f7e..2f78f0629b4 100644 --- a/PWGUD/Tasks/CMakeLists.txt +++ b/PWGUD/Tasks/CMakeLists.txt @@ -19,11 +19,51 @@ o2physics_add_dpl_workflow(sg-spectra PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(sg-pid-spectra-table + SOURCES sgPIDSpectraTable.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(sg-pid-analyzer + SOURCES sgPIDAnalyzer.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(sg-pid-spectra + SOURCES sgPIDSpectra.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(sg-incl-jpsi + SOURCES sgInclJpsi.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(sg-excl-omega + SOURCES sgExclOmega.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(sg-excl-universe + SOURCES sgExcUniverse.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(sg-fourpi SOURCES sgFourPiAnalyzer.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(sg-sixpi + SOURCES sgSixPiAnalyzer.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(sg-twopi + SOURCES sgTwoPiAnalyzer.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(sg-d0 SOURCES sgD0Analyzer.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase @@ -83,8 +123,9 @@ o2physics_add_dpl_workflow(tautau13topo SOURCES upcTauTau13topo.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(upc-tau-rl - SOURCES upcTauCentralBarrelRL.cxx + SOURCES upcTauRl.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsBase O2::DetectorsCommonDataFormats COMPONENT_NAME Analysis) @@ -92,3 +133,118 @@ o2physics_add_dpl_workflow(polarisation-rho SOURCES polarisationRho.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(upc-jpsi-corr + SOURCES upcJpsiCorr.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(exclusive-phi + SOURCES exclusivePhi.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(upc-photonuclear-jmg + SOURCES upcPhotonuclearAnalysisJMG.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsBase O2::DetectorsCommonDataFormats + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(exclusive-two-protons + SOURCES exclusiveTwoProtons.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(exclusive-two-protons-sg + SOURCES exclusiveTwoProtonsSG.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(exclusive-phi-leptons + SOURCES exclusivePhiLeptons.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(exclusive-phi-leptons-trees + SOURCES exclusivePhiLeptonsTrees.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(exclusive-pentaquark + SOURCES exclusivePentaquark.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(inclusive-phikstar-sd + SOURCES sginclusivePhiKstarSD.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(sg-exclusive-phi + SOURCES sgExclusivePhi.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(sg-exclusive-phi-its + SOURCES sgExclusivePhiITSselections.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(upc-pion-analysis + SOURCES upcPionAnalysis.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(fwd-muons-upc + SOURCES FwdMuonsUPC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(upc-event-itsrof-counter + SOURCES upcEventITSROFcounter.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(upc-rho-analysis + SOURCES upcRhoAnalysis.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(upc-rho-prime-analysis + SOURCES upcRhoPrimeAnalysis.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(event-by-event + SOURCES eventByevent.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(exclusive-rho-to-four-pi + SOURCES exclusiveRhoTo4Pi.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(upc-quarkonia-central-barrel + SOURCES upcQuarkoniaCentralBarrel.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(test-mc-std-tabs-rl + SOURCES testMCstdTabsRL.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsBase O2::DetectorsCommonDataFormats + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(decaytree-analyzer + SOURCES decayTreeAnalyzer.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::UDGoodRunSelector O2Physics::decayTree + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-cumulants-upc + SOURCES flowCumulantsUpc.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-correlations-upc + SOURCES flowCorrelationsUpc.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::PWGCFCore + COMPONENT_NAME Analysis) diff --git a/PWGUD/Tasks/FwdMuonsUPC.cxx b/PWGUD/Tasks/FwdMuonsUPC.cxx new file mode 100644 index 00000000000..b35a2d8167c --- /dev/null +++ b/PWGUD/Tasks/FwdMuonsUPC.cxx @@ -0,0 +1,975 @@ +// 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 FwdMuonsUPC.cxx +/// \brief perform some selections on fwd events and saves the results + +/// executable name o2-analysis-ud-fwd-muon-upc + +/// \author Andrea Giovanni Riffero + +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "PWGUD/DataModel/UDTables.h" + +#include "TLorentzVector.h" +#include "TSystem.h" +#include "TMath.h" +#include "TRandom3.h" + +// table for saving tree with info on data +namespace dimu +{ +// dimuon +DECLARE_SOA_COLUMN(RunNumber, runNumber, int); +DECLARE_SOA_COLUMN(M, m, float); +DECLARE_SOA_COLUMN(Energy, energy, float); +DECLARE_SOA_COLUMN(Px, px, float); +DECLARE_SOA_COLUMN(Py, py, float); +DECLARE_SOA_COLUMN(Pz, pz, float); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Rap, rap, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(PhiAv, phiAv, float); +DECLARE_SOA_COLUMN(PhiCh, phiCh, float); +// tracks positive (p) and negative (n) +DECLARE_SOA_COLUMN(EnergyP, energyP, float); +DECLARE_SOA_COLUMN(Pxp, pxp, float); +DECLARE_SOA_COLUMN(Pyp, pyp, float); +DECLARE_SOA_COLUMN(Pzp, pzp, float); +DECLARE_SOA_COLUMN(Ptp, ptp, float); +DECLARE_SOA_COLUMN(Etap, etap, float); +DECLARE_SOA_COLUMN(Phip, phip, float); +DECLARE_SOA_COLUMN(EnergyN, energyN, float); +DECLARE_SOA_COLUMN(Pxn, pxn, float); +DECLARE_SOA_COLUMN(Pyn, pyn, float); +DECLARE_SOA_COLUMN(Pzn, pzn, float); +DECLARE_SOA_COLUMN(Ptn, ptn, float); +DECLARE_SOA_COLUMN(Etan, etan, float); +DECLARE_SOA_COLUMN(Phin, phin, float); +// zn +DECLARE_SOA_COLUMN(Tzna, tzna, float); +DECLARE_SOA_COLUMN(Ezna, ezna, float); +DECLARE_SOA_COLUMN(Tznc, tznc, float); +DECLARE_SOA_COLUMN(Eznc, eznc, float); +DECLARE_SOA_COLUMN(Nclass, nclass, int); +} // namespace dimu + +namespace o2::aod +{ +DECLARE_SOA_TABLE(DiMu, "AOD", "DIMU", + dimu::RunNumber, + dimu::M, dimu::Energy, dimu::Px, dimu::Py, dimu::Pz, dimu::Pt, dimu::Rap, dimu::Phi, + dimu::PhiAv, dimu::PhiCh, + dimu::EnergyP, dimu::Pxp, dimu::Pyp, dimu::Pzp, dimu::Ptp, dimu::Etap, dimu::Phip, + dimu::EnergyN, dimu::Pxn, dimu::Pyn, dimu::Pzn, dimu::Ptn, dimu::Etan, dimu::Phin, + dimu::Tzna, dimu::Ezna, dimu::Tznc, dimu::Eznc, dimu::Nclass); +} // namespace o2::aod + +// for saving tree with info on gen MC +namespace gendimu +{ +// dimuon +DECLARE_SOA_COLUMN(M, m, float); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Rap, rap, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(PhiAv, phiAv, float); +DECLARE_SOA_COLUMN(PhiCh, phiCh, float); +// tracks positive (p) and negative (n) +DECLARE_SOA_COLUMN(Ptp, ptp, float); +DECLARE_SOA_COLUMN(Etap, etap, float); +DECLARE_SOA_COLUMN(Phip, phip, float); +DECLARE_SOA_COLUMN(Ptn, ptn, float); +DECLARE_SOA_COLUMN(Etan, etan, float); +DECLARE_SOA_COLUMN(Phin, phin, float); +} // namespace gendimu + +namespace o2::aod +{ +DECLARE_SOA_TABLE(GenDimu, "AOD", "GENDIMU", + gendimu::M, gendimu::Pt, gendimu::Rap, gendimu::Phi, + gendimu::PhiAv, gendimu::PhiCh, + gendimu::Ptp, gendimu::Etap, gendimu::Phip, + gendimu::Ptn, gendimu::Etan, gendimu::Phin); +} // namespace o2::aod + +// for saving tree with info on reco MC +namespace recodimu +{ +// dimuon +DECLARE_SOA_COLUMN(RunNumber, runNumber, int); +DECLARE_SOA_COLUMN(M, m, float); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Rap, rap, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(PhiAv, phiAv, float); +DECLARE_SOA_COLUMN(PhiCh, phiCh, float); +// tracks positive (p) and negative (n) +DECLARE_SOA_COLUMN(Ptp, ptp, float); +DECLARE_SOA_COLUMN(Etap, etap, float); +DECLARE_SOA_COLUMN(Phip, phip, float); +DECLARE_SOA_COLUMN(Ptn, ptn, float); +DECLARE_SOA_COLUMN(Etan, etan, float); +DECLARE_SOA_COLUMN(Phin, phin, float); +// gen info dimuon +DECLARE_SOA_COLUMN(GenPt, genPt, float); +DECLARE_SOA_COLUMN(GenRap, genRap, float); +DECLARE_SOA_COLUMN(GenPhi, genPhi, float); +// gen info trks +DECLARE_SOA_COLUMN(GenPtp, genPtp, float); +DECLARE_SOA_COLUMN(GenEtap, genEtap, float); +DECLARE_SOA_COLUMN(GenPhip, genPhip, float); +DECLARE_SOA_COLUMN(GenPtn, genPtn, float); +DECLARE_SOA_COLUMN(GenEtan, genEtan, float); +DECLARE_SOA_COLUMN(GenPhin, genPhin, float); +} // namespace recodimu + +namespace o2::aod +{ +DECLARE_SOA_TABLE(RecoDimu, "AOD", "RECODIMU", + recodimu::RunNumber, + recodimu::M, recodimu::Pt, recodimu::Rap, recodimu::Phi, + recodimu::PhiAv, recodimu::PhiCh, + recodimu::Ptp, recodimu::Etap, recodimu::Phip, + recodimu::Ptn, recodimu::Etan, recodimu::Phin, + recodimu::GenPt, recodimu::GenRap, recodimu::GenPhi, + recodimu::GenPtp, recodimu::GenEtap, recodimu::GenPhip, + recodimu::GenPtn, recodimu::GenEtan, recodimu::GenPhin); +} // namespace o2::aod + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// constants used in the track selection +const float kRAbsMin = 17.6; +const float kRAbsMid = 26.5; +const float kRAbsMax = 89.5; +const float kPDca1 = 200.; +const float kPDca2 = 200.; +const float kEtaMin = -4.0; +const float kEtaMax = -2.5; +const float kPtMin = 0.; + +struct FwdMuonsUPC { + + // a pdg object + Service pdg; + + using CandidatesFwd = soa::Join; + using ForwardTracks = soa::Join; + using CompleteFwdTracks = soa::Join; + + Produces dimuSel; + Produces dimuGen; + Produces dimuReco; + + // defining histograms using histogram registry: different histos for the different process functions + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry reg0n0n{"reg0n0n", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry regXn0n{"regXn0n", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry regXnXn{"regXnXn", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry mcGenRegistry{"mcGenRegistry", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry mcRecoRegistry{"mcRecoRegistry", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // CONFIGURABLES + static constexpr double Pi = o2::constants::math::PI; + // pT of muon pairs + Configurable nBinsPt{"nBinsPt", 250, "N bins in pT histo"}; + Configurable lowPt{"lowPt", 0., "lower limit in pT histo"}; + Configurable highPt{"highPt", 2, "upper limit in pT histo"}; + // mass of muon pairs + Configurable nBinsMass{"nBinsMass", 500, "N bins in mass histo"}; + Configurable lowMass{"lowMass", 0., "lower limit in mass histo"}; + Configurable highMass{"highMass", 10., "upper limit in mass histo"}; + // eta of muon pairs + Configurable nBinsEta{"nBinsEta", 600, "N bins in eta histo"}; + Configurable lowEta{"lowEta", -10., "lower limit in eta histo"}; + Configurable highEta{"highEta", -2., "upper limit in eta histo"}; + // rapidity of muon pairs + Configurable nBinsRapidity{"nBinsRapidity", 250, "N bins in rapidity histo"}; + Configurable lowRapidity{"lowRapidity", -4.5, "lower limit in rapidity histo"}; + Configurable highRapidity{"highRapidity", -2., "upper limit in rapidity histo"}; + // phi of muon pairs + Configurable nBinsPhi{"nBinsPhi", 600, "N bins in phi histo"}; + Configurable lowPhi{"lowPhi", -Pi, "lower limit in phi histo"}; + Configurable highPhi{"highPhi", Pi, "upper limit in phi histo"}; + // pT of single muons + Configurable nBinsPtSingle{"nBinsPtSingle", 500, "N bins in pT histo single muon"}; + Configurable lowPtSingle{"lowPtSingle", 0., "lower limit in pT histo single muon"}; + Configurable highPtSingle{"highPtSingle", 2., "upper limit in pT histo single muon"}; + // eta of single muons + Configurable nBinsEtaSingle{"nBinsEtaSingle", 250, "N bins in eta histo single muon"}; + Configurable lowEtaSingle{"lowEtaSingle", -4.5, "lower limit in eta histo single muon"}; + Configurable highEtaSingle{"highEtaSingle", -2., "upper limit in eta histo single muon"}; + // phi of single muons + Configurable nBinsPhiSingle{"nBinsPhiSingle", 600, "N bins in phi histo single muon"}; + Configurable lowPhiSingle{"lowPhiSingle", -Pi, "lower limit in phi histo single muon"}; + Configurable highPhiSingle{"highPhiSingle", Pi, "upper limit in phi histo single muon"}; + // ZDC + Configurable nBinsZDCen{"nBinsZDCen", 200, "N bins in ZN energy"}; + Configurable lowEnZN{"lowEnZN", -50., "lower limit in ZN energy histo"}; + Configurable highEnZN{"highEnZN", 250., "upper limit in ZN energy histo"}; + + void init(InitContext&) + { + // binning of pT axis fr fit + std::vector ptFitBinning = { + 0.00, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.10, + 0.11, 0.12, 0.13, 0.14, 0.15, 0.175, 0.20, 0.25, 0.30, 0.40, 0.50, + 0.60, 0.70, 0.80, 0.90, 1.00, 1.20, 1.40, 1.60, 1.80, 2.00, 2.50, + 3.00, 3.50}; + + // axis + const AxisSpec axisPt{nBinsPt, lowPt, highPt, "#it{p}_{T} GeV/#it{c}"}; + const AxisSpec axisPtFit = {ptFitBinning, "#it{p}_{T} (GeV/c)"}; + const AxisSpec axisMass{nBinsMass, lowMass, highMass, "m_{#mu#mu} GeV/#it{c}^{2}"}; + const AxisSpec axisEta{nBinsEta, lowEta, highEta, "#eta"}; + const AxisSpec axisRapidity{nBinsRapidity, lowRapidity, highRapidity, "Rapidity"}; + const AxisSpec axisPhi{nBinsPhi, lowPhi, highPhi, "#varphi"}; + const AxisSpec axisPtSingle{nBinsPtSingle, lowPtSingle, highPtSingle, "#it{p}_{T}_{ trk} GeV/#it{c}"}; + const AxisSpec axisTimeZN{200, -10, 10, "ZDC time (ns)"}; + const AxisSpec axisEnergyZNA{nBinsZDCen, lowEnZN, highEnZN, "ZNA energy (TeV)"}; + const AxisSpec axisEnergyZNC{nBinsZDCen, lowEnZN, highEnZN, "ZNC energy (TeV)"}; + const AxisSpec axisEtaSingle{nBinsEtaSingle, lowEtaSingle, highEtaSingle, "#eta_{trk}"}; + const AxisSpec axisPhiSingle{nBinsPhiSingle, lowPhiSingle, highPhiSingle, "#varphi_{trk}"}; + + // histos + // data and reco MC + registry.add("hMass", "Invariant mass of muon pairs;;#counts", kTH1D, {axisMass}); + registry.add("hPt", "Transverse momentum of muon pairs;;#counts", kTH1D, {axisPt}); + registry.add("hPtFit", "Transverse momentum of muon pairs;;#counts", kTH1D, {axisPtFit}); + registry.add("hEta", "Pseudorapidty of muon pairs;;#counts", kTH1D, {axisEta}); + registry.add("hRapidity", "Rapidty of muon pairs;;#counts", kTH1D, {axisRapidity}); + registry.add("hPhi", "#varphi of muon pairs;;#counts", kTH1D, {axisPhi}); + registry.add("hCharge", "Charge;;;#counts", kTH1D, {{5, -2.5, 2.5}}); + registry.add("hContrib", "hContrib;;#counts", kTH1D, {{6, -0.5, 5.5}}); + registry.add("hEvSign", "Sum of the charges of all the tracks in each event;;#counts", kTH1D, {{5, -2.5, 2.5}}); + registry.add("hPtTrkPos", "Pt of positive muons;;#counts", kTH1D, {axisPtSingle}); + registry.add("hPtTrkNeg", "Pt of negative muons;;#counts", kTH1D, {axisPtSingle}); + registry.add("hEtaTrkPos", "#eta of positive muons;;#counts", kTH1D, {axisEtaSingle}); + registry.add("hEtaTrkNeg", "#eta of negative muons;;#counts", kTH1D, {axisEtaSingle}); + registry.add("hPhiTrkPos", "#varphi of positive muons;;#counts", kTH1D, {axisPhiSingle}); + registry.add("hPhiTrkNeg", "#varphi of negative muons;;#counts", kTH1D, {axisPhiSingle}); + registry.add("hSameSign", "hSameSign;;#counts", kTH1D, {{6, -0.5, 5.5}}); + registry.add("hPhiCharge", "#phi #it{charge}", kTH1D, {axisPhi}); + registry.add("hPhiAverage", "#phi #it{average}", kTH1D, {axisPhi}); + + // data + registry.add("hTimeZNA", "ZNA Times;;#counts", kTH1D, {axisTimeZN}); + registry.add("hTimeZNC", "ZNC Times;;#counts", kTH1D, {axisTimeZN}); + registry.add("hEnergyZN", "ZNA vs ZNC energy", kTH2D, {axisEnergyZNA, axisEnergyZNC}); + + reg0n0n.add("hMass", "Invariant mass of muon pairs - 0n0n;;#counts", kTH1D, {axisMass}); + reg0n0n.add("hPt", "Transverse momentum of muon pairs - 0n0n;;#counts", kTH1D, {axisPt}); + reg0n0n.add("hEta", "Pseudorapidty of muon pairs - 0n0n;;#counts", kTH1D, {axisEta}); + reg0n0n.add("hRapidity", "Rapidty of muon pairs - 0n0n;;#counts", kTH1D, {axisRapidity}); + reg0n0n.add("hPtFit", "Transverse momentum of muon pairs - 0n0n;;#counts", kTH1D, {axisPtFit}); + + regXn0n.add("hMass", "Invariant mass of muon pairs - Xn0n;;#counts", kTH1D, {axisMass}); + regXn0n.add("hPt", "Transverse momentum of muon pairs - Xn0n;;#counts", kTH1D, {axisPt}); + regXn0n.add("hEta", "Pseudorapidty of muon pairs - Xn0n;;#counts", kTH1D, {axisEta}); + regXn0n.add("hRapidity", "Rapidty of muon pairs - Xn0n;;#counts", kTH1D, {axisRapidity}); + regXn0n.add("hPtFit", "Transverse momentum of muon pairs - Xn0n;;#counts", kTH1D, {axisPtFit}); + + regXnXn.add("hMass", "Invariant mass of muon pairs - XnXn;;#counts", kTH1D, {axisMass}); + regXnXn.add("hPt", "Transverse momentum of muon pairs - XnXn;;#counts", kTH1D, {axisPt}); + regXnXn.add("hEta", "Pseudorapidty of muon pairs - XnXn;;#counts", kTH1D, {axisEta}); + regXnXn.add("hRapidity", "Rapidty of muon pairs - XnXn;;#counts", kTH1D, {axisRapidity}); + regXnXn.add("hPtFit", "Transverse momentum of muon pairs - XnXn;;#counts", kTH1D, {axisPtFit}); + + // gen MC + mcGenRegistry.add("hMass", "Invariant mass of muon pairs;;#counts", kTH1D, {axisMass}); + mcGenRegistry.add("hPt", "Transverse momentum of muon pairs;;#counts", kTH1D, {axisPt}); + mcGenRegistry.add("hEta", "Pseudorapidty of muon pairs;;#counts", kTH1D, {axisEta}); + mcGenRegistry.add("hRapidity", "Rapidty of muon pairs;;#counts", kTH1D, {axisRapidity}); + mcGenRegistry.add("hPhi", "#varphi of muon pairs;;#counts", kTH1D, {axisPhi}); + mcGenRegistry.add("hPtTrkPos", "Pt of positive muons;;#counts", kTH1D, {axisPtSingle}); + mcGenRegistry.add("hPtTrkNeg", "Pt of negative muons;;#counts", kTH1D, {axisPtSingle}); + mcGenRegistry.add("hEtaTrkPos", "#eta of positive muons;;#counts", kTH1D, {axisEtaSingle}); + mcGenRegistry.add("hEtaTrkNeg", "#eta of negative muons;;#counts", kTH1D, {axisEtaSingle}); + mcGenRegistry.add("hPhiTrkPos", "#varphi of positive muons;;#counts", kTH1D, {axisPhiSingle}); + mcGenRegistry.add("hPhiTrkNeg", "#varphi of negative muons;;#counts", kTH1D, {axisPhiSingle}); + mcGenRegistry.add("hPhiCharge", "#phi #it{charge}", kTH1D, {axisPhi}); + mcGenRegistry.add("hPhiAverage", "#phi #it{average}", kTH1D, {axisPhi}); + + // reco MC + mcRecoRegistry.add("hMass", "Invariant mass of muon pairs;;#counts", kTH1D, {axisMass}); + mcRecoRegistry.add("hPt", "Transverse momentum of muon pairs;;#counts", kTH1D, {axisPt}); + mcRecoRegistry.add("hPtFit", "Transverse momentum of muon pairs;;#counts", kTH1D, {axisPtFit}); + mcRecoRegistry.add("hEta", "Pseudorapidty of muon pairs;;#counts", kTH1D, {axisEta}); + mcRecoRegistry.add("hRapidity", "Rapidty of muon pairs;;#counts", kTH1D, {axisRapidity}); + mcRecoRegistry.add("hPhi", "#varphi of muon pairs;;#counts", kTH1D, {axisPhi}); + mcRecoRegistry.add("hCharge", "Charge;;;#counts", kTH1D, {{5, -2.5, 2.5}}); + mcRecoRegistry.add("hContrib", "hContrib;;#counts", kTH1D, {{6, -0.5, 5.5}}); + mcRecoRegistry.add("hEvSign", "Sum of the charges of all the tracks in each event;;#counts", kTH1D, {{5, -2.5, 2.5}}); + mcRecoRegistry.add("hPtTrkPos", "Pt of positive muons;;#counts", kTH1D, {axisPtSingle}); + mcRecoRegistry.add("hPtTrkNeg", "Pt of negative muons;;#counts", kTH1D, {axisPtSingle}); + mcRecoRegistry.add("hEtaTrkPos", "#eta of positive muons;;#counts", kTH1D, {axisEtaSingle}); + mcRecoRegistry.add("hEtaTrkNeg", "#eta of negative muons;;#counts", kTH1D, {axisEtaSingle}); + mcRecoRegistry.add("hPhiTrkPos", "#varphi of positive muons;;#counts", kTH1D, {axisPhiSingle}); + mcRecoRegistry.add("hPhiTrkNeg", "#varphi of negative muons;;#counts", kTH1D, {axisPhiSingle}); + mcRecoRegistry.add("hSameSign", "hSameSign;;#counts", kTH1D, {{6, -0.5, 5.5}}); + mcRecoRegistry.add("hPhiCharge", "#phi #it{charge}", kTH1D, {axisPhi}); + mcRecoRegistry.add("hPhiAverage", "#phi #it{average}", kTH1D, {axisPhi}); + + // corr gen-reco + mcRecoRegistry.add("hPtcorr", "gen pT vs reco pT", kTH2D, {axisPt, axisPt}); + mcRecoRegistry.add("hRapcorr", "gen rapidity vs reco rapidity", kTH2D, {axisRapidity, axisRapidity}); + mcRecoRegistry.add("hPhicorr", "gen #phi vs reco #phi", kTH2D, {axisPhi, axisPhi}); + } + + // FUNCTIONS + + // retrieve particle mass (GeV/c^2) from TDatabasePDG + float particleMass(int pid) + { + auto mass = pdg->Mass(pid); + return mass; + } + + // template function that fills a map with the collision id of each udcollision as key + // and a vector with the tracks + // map == (key, element) == (udCollisionId, vector of trks) + template + void collectCandIDs(std::unordered_map>& tracksPerCand, TTracks& tracks) + { + for (const auto& tr : tracks) { + int32_t candId = tr.udCollisionId(); + if (candId < 0) { + continue; + } + tracksPerCand[candId].push_back(tr.globalIndex()); + } + } + + // template function that fills a map with the collision id of each udmccollision as key + // and a vector with the tracks + // map == (key, element) == (udMcCollisionId, vector of mc particles) + template + void collectMcCandIDs(std::unordered_map>& tracksPerCand, TTracks& tracks) + { + for (const auto& tr : tracks) { + int32_t candId = tr.udMcCollisionId(); + if (candId < 0) { + continue; + } + tracksPerCand[candId].push_back(tr.globalIndex()); + } + } + + // template function that fills a map with the collision id of each udcollision as key + // and a vector with the tracks and corresponding geneated particles + // map == (key, element) == (udCollisionId, vector(track1, mcPart1, track2, mcPart2)) + template + void collectRecoCandID(std::unordered_map>& tracksPerCand, TTracks& tracks) + { + for (const auto& tr : tracks) { + int32_t candId = tr.udCollisionId(); + if (candId < 0) + continue; + + if (!tr.has_udMcParticle()) { + // LOGF(debug,"tr does not have mc part"); + continue; + } + // retrieve mc particle from the reco track + auto mcPart = tr.udMcParticle(); + + tracksPerCand[candId].push_back(tr.globalIndex()); + tracksPerCand[candId].push_back(mcPart.globalIndex()); + } + } + + // struct used to store the ZDC info in a map + struct ZDCinfo { + float timeA; + float timeC; + float enA; + float enC; + int32_t id; + }; + + // function that fills a map with the collision id of each udcollision as key + // and a ZDCinfo struct with the ZDC information + void collectCandZDCInfo(std::unordered_map& zdcPerCand, o2::aod::UDZdcsReduced const& ZDCs) + { + + for (const auto& zdc : ZDCs) { + int32_t candId = zdc.udCollisionId(); + if (candId < 0) { + continue; + } + + zdcPerCand[candId].timeA = zdc.timeZNA(); + zdcPerCand[candId].timeC = zdc.timeZNC(); + zdcPerCand[candId].enA = zdc.energyCommonZNA(); + zdcPerCand[candId].enC = zdc.energyCommonZNC(); + + // take care of the infinity + if (std::isinf(zdcPerCand[candId].timeA)) + zdcPerCand[candId].timeA = -999; + if (std::isinf(zdcPerCand[candId].timeC)) + zdcPerCand[candId].timeC = -999; + if (std::isinf(zdcPerCand[candId].enA)) + zdcPerCand[candId].enA = -999; + if (std::isinf(zdcPerCand[candId].enC)) + zdcPerCand[candId].enC = -999; + } + } + + // function to select muon tracks + template + bool isMuonSelected(const TTracks& fwdTrack) + { + float rAbs = fwdTrack.rAtAbsorberEnd(); + float pDca = fwdTrack.pDca(); + TLorentzVector p; + auto mMu = particleMass(13); + p.SetXYZM(fwdTrack.px(), fwdTrack.py(), fwdTrack.pz(), mMu); + float eta = p.Eta(); + float pt = p.Pt(); + float pDcaMax = rAbs < kRAbsMid ? kPDca1 : kPDca2; + + if (eta < kEtaMin || eta > kEtaMax) + return false; + if (pt < kPtMin) + return false; + if (rAbs < kRAbsMin || rAbs > kRAbsMax) + return false; + if (pDca > pDcaMax) + return false; + return true; + } + + // function to compute phi for azimuth anisotropy + void computePhiAnis(TLorentzVector p1, TLorentzVector p2, int sign1, float& phiAverage, float& phiCharge) + { + + TLorentzVector tSum, tDiffAv, tDiffCh; + tSum = p1 + p2; + if (sign1 > 0) { + tDiffCh = p1 - p2; + if (gRandom->Rndm() > 0.5) + tDiffAv = p1 - p2; + else + tDiffAv = p2 - p1; + } else { + tDiffCh = p2 - p1; + if (gRandom->Rndm() > 0.5) + tDiffAv = p2 - p1; + else + tDiffAv = p1 - p2; + } + + // average + phiAverage = tSum.DeltaPhi(tDiffAv); + // charge + phiCharge = tSum.DeltaPhi(tDiffCh); + } + + // function that processes the candidates: + // it applies V0 selection, trk selection, kine selection, and fills the histograms + // it also divides the data in neutron classes + // used for real data + void processCand(CandidatesFwd::iterator const& cand, + ForwardTracks::iterator const& tr1, ForwardTracks::iterator const& tr2, + ZDCinfo const& zdc) + { + // V0 selection + const auto& ampsV0A = cand.amplitudesV0A(); + const auto& ampsRelBCsV0A = cand.ampRelBCsV0A(); + for (unsigned int i = 0; i < ampsV0A.size(); ++i) { + if (std::abs(ampsRelBCsV0A[i]) <= 1) { + if (ampsV0A[i] > 100.) + return; + } + } + + // select opposite charge events only + if (cand.netCharge() != 0) { + registry.fill(HIST("hSameSign"), cand.numContrib()); + return; + } + + // track selection + if (!isMuonSelected(*tr1)) + return; + if (!isMuonSelected(*tr2)) + return; + + // MCH-MID match selection + int nMIDs = 0; + if (tr1.chi2MatchMCHMID() > 0) + nMIDs++; + if (tr2.chi2MatchMCHMID() > 0) + nMIDs++; + if (nMIDs != 2) + return; + + // form Lorentz vectors + TLorentzVector p1, p2; + auto mMu = particleMass(13); + p1.SetXYZM(tr1.px(), tr1.py(), tr1.pz(), mMu); + p2.SetXYZM(tr2.px(), tr2.py(), tr2.pz(), mMu); + TLorentzVector p = p1 + p2; + + // cut on pair kinematics + // select mass + if (p.M() < lowMass) + return; + if (p.M() > highMass) + return; + // select pt + if (p.Pt() < lowPt) + return; + if (p.Pt() > highPt) + return; + // select rapidity + if (p.Rapidity() < lowRapidity) + return; + if (p.Rapidity() > highRapidity) + return; + + // compute phi for azimuth anisotropy + float phiAverage = 0; + float phiCharge = 0; + computePhiAnis(p1, p2, tr1.sign(), phiAverage, phiCharge); + + // zdc info + if (std::abs(zdc.timeA) < 10) + registry.fill(HIST("hTimeZNA"), zdc.timeA); + if (std::abs(zdc.timeC) < 10) + registry.fill(HIST("hTimeZNC"), zdc.timeC); + registry.fill(HIST("hEnergyZN"), zdc.enA, zdc.enC); + + // divide the events in neutron classes + bool neutronA = false; + bool neutronC = false; + int znClass = -1; + + if (std::abs(zdc.timeA) < 2) + neutronA = true; + if (std::abs(zdc.timeC) < 2) + neutronC = true; + + if (std::isinf(zdc.timeC)) + neutronC = false; + if (std::isinf(zdc.timeA)) + neutronA = false; + + // fill the histos in neutron classes and assign neutron class label + // 0n0n + if (neutronC == false && neutronA == false) { + znClass = 1; + reg0n0n.fill(HIST("hMass"), p.M()); + reg0n0n.fill(HIST("hPt"), p.Pt()); + reg0n0n.fill(HIST("hPtFit"), p.Pt()); + reg0n0n.fill(HIST("hEta"), p.Eta()); + reg0n0n.fill(HIST("hRapidity"), p.Rapidity()); + } else if (neutronA ^ neutronC) { // Xn0n + 0nXn + if (neutronA) + znClass = 2; + else if (neutronC) + znClass = 3; + regXn0n.fill(HIST("hMass"), p.M()); + regXn0n.fill(HIST("hPt"), p.Pt()); + regXn0n.fill(HIST("hPtFit"), p.Pt()); + regXn0n.fill(HIST("hEta"), p.Eta()); + regXn0n.fill(HIST("hRapidity"), p.Rapidity()); + } else if (neutronA && neutronC) { // XnXn + znClass = 4; + regXnXn.fill(HIST("hMass"), p.M()); + regXnXn.fill(HIST("hPt"), p.Pt()); + regXnXn.fill(HIST("hPtFit"), p.Pt()); + regXnXn.fill(HIST("hEta"), p.Eta()); + regXnXn.fill(HIST("hRapidity"), p.Rapidity()); + } + + // fill the histos without looking at neutron emission + registry.fill(HIST("hContrib"), cand.numContrib()); + registry.fill(HIST("hPtTrkPos"), p1.Pt()); + registry.fill(HIST("hPtTrkNeg"), p2.Pt()); + registry.fill(HIST("hEtaTrkPos"), p1.Eta()); + registry.fill(HIST("hEtaTrkNeg"), p2.Eta()); + registry.fill(HIST("hPhiTrkPos"), p1.Phi()); + registry.fill(HIST("hPhiTrkNeg"), p2.Phi()); + registry.fill(HIST("hEvSign"), cand.netCharge()); + registry.fill(HIST("hMass"), p.M()); + registry.fill(HIST("hPt"), p.Pt()); + registry.fill(HIST("hPtFit"), p.Pt()); + registry.fill(HIST("hEta"), p.Eta()); + registry.fill(HIST("hRapidity"), p.Rapidity()); + registry.fill(HIST("hPhi"), p.Phi()); + registry.fill(HIST("hCharge"), tr1.sign()); + registry.fill(HIST("hCharge"), tr2.sign()); + registry.fill(HIST("hPhiAverage"), phiAverage); + registry.fill(HIST("hPhiCharge"), phiCharge); + + // store the event to save it into a tree + if (tr1.sign() > 0) { + dimuSel(cand.runNumber(), + p.M(), p.E(), p.Px(), p.Py(), p.Pz(), p.Pt(), p.Rapidity(), p.Phi(), + phiAverage, phiCharge, + p1.E(), p1.Px(), p1.Py(), p1.Pz(), p1.Pt(), p1.PseudoRapidity(), p1.Phi(), + p2.E(), p2.Px(), p2.Py(), p2.Pz(), p2.Pt(), p2.PseudoRapidity(), p2.Phi(), + zdc.timeA, zdc.enA, zdc.timeC, zdc.enC, znClass); + } else { + dimuSel(cand.runNumber(), + p.M(), p.E(), p.Px(), p.Py(), p.Pz(), p.Pt(), p.Rapidity(), p.Phi(), + phiAverage, phiCharge, + p2.E(), p2.Px(), p2.Py(), p2.Pz(), p2.Pt(), p2.PseudoRapidity(), p2.Phi(), + p1.E(), p1.Px(), p1.Py(), p1.Pz(), p1.Pt(), p1.PseudoRapidity(), p1.Phi(), + zdc.timeA, zdc.enA, zdc.timeC, zdc.enC, znClass); + } + } + + // function that processes the MC gen candidates: + // it applies some kinematics cut and fills the histograms + void processMcGenCand(aod::UDMcCollisions::iterator const& /*mcCand*/, + aod::UDMcParticles::iterator const& McPart1, aod::UDMcParticles::iterator const& McPart2) + { + + // check that all pairs are mu+mu- + if (std::abs(McPart1.pdgCode()) != 13 && std::abs(McPart2.pdgCode()) != 13) + LOGF(debug, "PDG codes: %d | %d", McPart1.pdgCode(), McPart2.pdgCode()); + + // create Lorentz vectors + TLorentzVector p1, p2; + auto mMu = particleMass(13); + p1.SetXYZM(McPart1.px(), McPart1.py(), McPart1.pz(), mMu); + p2.SetXYZM(McPart2.px(), McPart2.py(), McPart2.pz(), mMu); + TLorentzVector p = p1 + p2; + + // cut on pair kinematics + // select mass + if (p.M() < lowMass) + return; + if (p.M() > highMass) + return; + // select pt + if (p.Pt() < lowPt) + return; + if (p.Pt() > highPt) + return; + // select rapidity + if (p.Rapidity() < lowRapidity) + return; + if (p.Rapidity() > highRapidity) + return; + + // compute phi for azimuth anisotropy + float phiAverage = 0; + float phiCharge = 0; + computePhiAnis(p1, p2, -McPart1.pdgCode(), phiAverage, phiCharge); + + // fill the histos + mcGenRegistry.fill(HIST("hPtTrkPos"), p1.Pt()); + mcGenRegistry.fill(HIST("hPtTrkNeg"), p2.Pt()); + mcGenRegistry.fill(HIST("hEtaTrkPos"), p1.Eta()); + mcGenRegistry.fill(HIST("hEtaTrkNeg"), p2.Eta()); + mcGenRegistry.fill(HIST("hPhiTrkPos"), p1.Phi()); + mcGenRegistry.fill(HIST("hPhiTrkNeg"), p2.Phi()); + mcGenRegistry.fill(HIST("hMass"), p.M()); + mcGenRegistry.fill(HIST("hPt"), p.Pt()); + mcGenRegistry.fill(HIST("hEta"), p.Eta()); + mcGenRegistry.fill(HIST("hRapidity"), p.Rapidity()); + mcGenRegistry.fill(HIST("hPhi"), p.Phi()); + mcGenRegistry.fill(HIST("hPhiAverage"), phiAverage); + mcGenRegistry.fill(HIST("hPhiCharge"), phiCharge); + + // store the event to save it into a tree + if (McPart1.pdgCode() < 0) { + dimuGen(p.M(), p.Pt(), p.Rapidity(), p.Phi(), + phiAverage, phiCharge, + p1.Pt(), p1.PseudoRapidity(), p1.Phi(), + p2.Pt(), p2.PseudoRapidity(), p2.Phi()); + } else { + dimuGen(p.M(), p.Pt(), p.Rapidity(), p.Phi(), + phiAverage, phiCharge, + p2.Pt(), p2.PseudoRapidity(), p2.Phi(), + p1.Pt(), p1.PseudoRapidity(), p1.Phi()); + } + } + + // function that processes MC reco candidates + // it applies V0 selection, trk selection, kine selection, and fills the histograms + void processMcRecoCand(CandidatesFwd::iterator const& cand, + CompleteFwdTracks::iterator const& tr1, aod::UDMcParticles::iterator const& McPart1, + CompleteFwdTracks::iterator const& tr2, aod::UDMcParticles::iterator const& McPart2) + { + + // check that all pairs are mu+mu- + if (std::abs(McPart1.pdgCode()) != 13 && std::abs(McPart2.pdgCode()) != 13) + LOGF(debug, "PDG codes: %d | %d", McPart1.pdgCode(), McPart2.pdgCode()); + + // V0 selection + const auto& ampsV0A = cand.amplitudesV0A(); + const auto& ampsRelBCsV0A = cand.ampRelBCsV0A(); + for (unsigned int i = 0; i < ampsV0A.size(); ++i) { + if (std::abs(ampsRelBCsV0A[i]) <= 1) { + if (ampsV0A[i] > 100.) + return; + } + } + + // select opposite charge events only + if (cand.netCharge() != 0) { + registry.fill(HIST("hSameSign"), cand.numContrib()); + return; + } + + // track selection + if (!isMuonSelected(*tr1)) + return; + if (!isMuonSelected(*tr2)) + return; + + // MCH-MID match selection + int nMIDs = 0; + if (tr1.chi2MatchMCHMID() > 0) + nMIDs++; + if (tr2.chi2MatchMCHMID() > 0) + nMIDs++; + if (nMIDs != 2) + return; + + // form Lorentz vectors + TLorentzVector p1, p2; + auto mMu = particleMass(13); + p1.SetXYZM(tr1.px(), tr1.py(), tr1.pz(), mMu); + p2.SetXYZM(tr2.px(), tr2.py(), tr2.pz(), mMu); + TLorentzVector p = p1 + p2; + + // cut on pair kinematics (reco candidates) + // select mass + if (p.M() < lowMass) + return; + if (p.M() > highMass) + return; + // select pt + if (p.Pt() < lowPt) + return; + if (p.Pt() > highPt) + return; + // select rapidity + if (p.Rapidity() < lowRapidity) + return; + if (p.Rapidity() > highRapidity) + return; + + // compute phi for azimuth anisotropy + float phiAverage = 0; + float phiCharge = 0; + computePhiAnis(p1, p2, tr1.sign(), phiAverage, phiCharge); + + // gen particle + TLorentzVector p1Mc, p2Mc; + p1Mc.SetXYZM(McPart1.px(), McPart1.py(), McPart1.pz(), mMu); + p2Mc.SetXYZM(McPart2.px(), McPart2.py(), McPart2.pz(), mMu); + TLorentzVector pMc = p1Mc + p2Mc; + + // compute gen phi for azimuth anisotropy + float phiGenAverage = 0; + float phiGenCharge = 0; + computePhiAnis(p1, p2, -McPart1.pdgCode(), phiGenAverage, phiGenCharge); + + // print info in case of problems + if (tr1.sign() * McPart1.pdgCode() > 0 || tr2.sign() * McPart2.pdgCode() > 0) { + LOGF(debug, "Problem: "); + LOGF(debug, "real: %d | %d", (int)tr1.sign(), (int)tr2.sign()); + LOGF(debug, "mc : %i | %i", (int)McPart1.pdgCode(), (int)McPart2.pdgCode()); + LOGF(debug, "contrib: %d", (int)cand.numContrib()); + } + + // fill the histos + // reco info + mcRecoRegistry.fill(HIST("hContrib"), cand.numContrib()); + mcRecoRegistry.fill(HIST("hPtTrkPos"), p1.Pt()); + mcRecoRegistry.fill(HIST("hPtTrkNeg"), p2.Pt()); + mcRecoRegistry.fill(HIST("hEtaTrkPos"), p1.Eta()); + mcRecoRegistry.fill(HIST("hEtaTrkNeg"), p2.Eta()); + mcRecoRegistry.fill(HIST("hPhiTrkPos"), p1.Phi()); + mcRecoRegistry.fill(HIST("hPhiTrkNeg"), p2.Phi()); + mcRecoRegistry.fill(HIST("hEvSign"), cand.netCharge()); + mcRecoRegistry.fill(HIST("hMass"), p.M()); + mcRecoRegistry.fill(HIST("hPt"), p.Pt()); + mcRecoRegistry.fill(HIST("hPtFit"), p.Pt()); + mcRecoRegistry.fill(HIST("hEta"), p.Eta()); + mcRecoRegistry.fill(HIST("hRapidity"), p.Rapidity()); + mcRecoRegistry.fill(HIST("hPhi"), p.Phi()); + mcRecoRegistry.fill(HIST("hCharge"), tr1.sign()); + mcRecoRegistry.fill(HIST("hCharge"), tr2.sign()); + mcRecoRegistry.fill(HIST("hPhiAverage"), phiAverage); + mcRecoRegistry.fill(HIST("hPhiCharge"), phiCharge); + + // gen info (of reco events) + mcGenRegistry.fill(HIST("hPtTrkPos"), p1Mc.Pt()); + mcGenRegistry.fill(HIST("hPtTrkNeg"), p2Mc.Pt()); + mcGenRegistry.fill(HIST("hEtaTrkPos"), p1Mc.Eta()); + mcGenRegistry.fill(HIST("hEtaTrkNeg"), p2Mc.Eta()); + mcGenRegistry.fill(HIST("hPhiTrkPos"), p1Mc.Phi()); + mcGenRegistry.fill(HIST("hPhiTrkNeg"), p2Mc.Phi()); + mcGenRegistry.fill(HIST("hMass"), pMc.M()); + mcGenRegistry.fill(HIST("hPt"), pMc.Pt()); + mcGenRegistry.fill(HIST("hEta"), pMc.Eta()); + mcGenRegistry.fill(HIST("hRapidity"), pMc.Rapidity()); + mcGenRegistry.fill(HIST("hPhi"), pMc.Phi()); + mcGenRegistry.fill(HIST("hPhiAverage"), phiGenAverage); + mcGenRegistry.fill(HIST("hPhiCharge"), phiGenCharge); + + // reco-gen correlations + mcRecoRegistry.fill(HIST("hPtcorr"), p.Pt(), pMc.Pt()); + mcRecoRegistry.fill(HIST("hRapcorr"), p.Rapidity(), pMc.Rapidity()); + mcRecoRegistry.fill(HIST("hPhicorr"), p.Phi(), pMc.Phi()); + + // store the event to save it into a tree + if (tr1.sign() > 0) { + dimuReco(cand.runNumber(), + p.M(), p.Pt(), p.Rapidity(), p.Phi(), + phiAverage, phiCharge, + p1.Pt(), p1.PseudoRapidity(), p1.Phi(), + p2.Pt(), p2.PseudoRapidity(), p2.Phi(), + // gen info + pMc.Pt(), pMc.Rapidity(), pMc.Phi(), + p1Mc.Pt(), p1Mc.PseudoRapidity(), p1Mc.Phi(), + p2Mc.Pt(), p2Mc.PseudoRapidity(), p2Mc.Phi()); + } else { + dimuReco(cand.runNumber(), + p.M(), p.Pt(), p.Rapidity(), p.Phi(), + phiAverage, phiCharge, + p2.Pt(), p2.PseudoRapidity(), p2.Phi(), + p1.Pt(), p1.PseudoRapidity(), p1.Phi(), + // gen info + pMc.Pt(), pMc.Rapidity(), pMc.Phi(), + p2Mc.Pt(), p2Mc.PseudoRapidity(), p2Mc.Phi(), + p1Mc.Pt(), p1Mc.PseudoRapidity(), p1Mc.Phi()); + } + } + + // PROCESS FUNCTION + void processData(CandidatesFwd const& eventCandidates, + o2::aod::UDZdcsReduced const& ZDCs, + ForwardTracks const& fwdTracks) + { + + // map with the tracks + std::unordered_map> tracksPerCand; + collectCandIDs(tracksPerCand, fwdTracks); + + // map with the ZDC info + std::unordered_map zdcPerCand; + collectCandZDCInfo(zdcPerCand, ZDCs); + + // loop over the candidates + for (const auto& item : tracksPerCand) { + int32_t trId1 = item.second[0]; + int32_t trId2 = item.second[1]; + int32_t candID = item.first; + auto cand = eventCandidates.iteratorAt(candID); + auto tr1 = fwdTracks.iteratorAt(trId1); + auto tr2 = fwdTracks.iteratorAt(trId2); + + ZDCinfo zdc; + + if (zdcPerCand.count(candID) != 0) { + zdc = zdcPerCand.at(candID); + } else { + zdc.timeA = -999; + zdc.timeC = -999; + zdc.enA = -999; + zdc.enC = -999; + } + + processCand(cand, tr1, tr2, zdc); + } + } + + PROCESS_SWITCH(FwdMuonsUPC, processData, "", true); + + // process MC Truth + void processMcGen(aod::UDMcCollisions const& mccollisions, aod::UDMcParticles const& McParts) + { + + // map with the tracks + std::unordered_map> tracksPerCand; + collectMcCandIDs(tracksPerCand, McParts); + + // loop over the candidates + for (const auto& item : tracksPerCand) { + int32_t trId1 = item.second[0]; + int32_t trId2 = item.second[1]; + int32_t candID = item.first; + auto cand = mccollisions.iteratorAt(candID); + auto tr1 = McParts.iteratorAt(trId1); + auto tr2 = McParts.iteratorAt(trId2); + + processMcGenCand(cand, tr1, tr2); + } + } + PROCESS_SWITCH(FwdMuonsUPC, processMcGen, "", false); + + // process reco MC (gen info included) + void processMcReco(CandidatesFwd const& eventCandidates, + CompleteFwdTracks const& fwdTracks, + aod::UDMcCollisions const&, + aod::UDMcParticles const& McParts) + { + std::unordered_map> tracksPerCandAll; + collectRecoCandID(tracksPerCandAll, fwdTracks); + + // loop over the candidates + for (const auto& item : tracksPerCandAll) { + if (item.second.size() != 4) { + LOGF(debug, "number track (reco + gen) = %d", item.second.size()); + continue; + } + + // get the reco candidate + auto cand = eventCandidates.iteratorAt(item.first); + + // get reco tracks and corresponding gen particles + auto tr1 = fwdTracks.iteratorAt(item.second[0]); + auto trMc1 = McParts.iteratorAt(item.second[1]); + auto tr2 = fwdTracks.iteratorAt(item.second[2]); + auto trMc2 = McParts.iteratorAt(item.second[3]); + + // check that the method used here gets the the MC particles + // as the one used by Nazar + auto nzTrMc1 = McParts.iteratorAt(tr1.udMcParticleId()); + auto nzTrMc2 = McParts.iteratorAt(tr2.udMcParticleId()); + + if (nzTrMc1 != trMc1) + LOGF(debug, "diff wrt Nazar!"); + if (nzTrMc2 != trMc2) + LOGF(debug, "diff wrt Nazar!"); + + processMcRecoCand(cand, tr1, trMc1, tr2, trMc2); + } + } + PROCESS_SWITCH(FwdMuonsUPC, processMcReco, "", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGUD/Tasks/SGTrackSelector.h b/PWGUD/Tasks/SGTrackSelector.h deleted file mode 100644 index d0c2cb551b8..00000000000 --- a/PWGUD/Tasks/SGTrackSelector.h +++ /dev/null @@ -1,83 +0,0 @@ -// 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. -// -// \Single Gap Event Analyzer -// \author Sasha Bylinkin, alexander.bylinkin@gmail.com -// \since April 2023 - -#ifndef PWGUD_TASKS_SGTRACKSELECTOR_H_ -#define PWGUD_TASKS_SGTRACKSELECTOR_H_ - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "iostream" -#include "PWGUD/DataModel/UDTables.h" -#include "PWGUD/Core/SGSelector.h" -//#include "Common/DataModel/PIDResponse.h" -//#include "PWGUD/Core/RLhelper.h" -#include -#include "TLorentzVector.h" -using namespace std; -using namespace o2; -using namespace o2::aod; -using namespace o2::framework; -using namespace o2::framework::expressions; -#define mpion 0.1396 -#define mkaon 0.4937 -#define mproton 0.9383 -template -int trackselector(const T& track) -{ - TLorentzVector a; - a.SetXYZM(track.px(), track.py(), track.pz(), mpion); - if (std::abs(track.dcaZ()) > 2.) - return 0; - if (std::abs(track.dcaXY()) > .0105 + .035 / pow(a.Pt(), 1.1)) - return 0; - if (track.tpcChi2NCl() > 4) - return 0; - if (track.tpcNClsFindable() < 70) - return 0; - if (track.itsChi2NCl() > 36) - return 0; - return 1; -} -template -int trackpid(const T& track, bool use_tof) -{ - int pid = 0; - float pi, ka, pr; - float tpi, tka, tpr; - pi = std::abs(track.tpcNSigmaPi()); - ka = std::abs(track.tpcNSigmaKa()); - pr = std::abs(track.tpcNSigmaPr()); - if (pi < 1. && pi < ka && pi < pr) - pid = 1; - else if (ka < 1. && ka < pi && ka < pr) - pid = 2; - else if (pr < 1. && pr < pi && pr < ka) - pid = 3; - if (use_tof && track.tofChi2() > -1) { - tpi = std::abs(track.tofNSigmaPi()); - tka = std::abs(track.tofNSigmaKa()); - tpr = std::abs(track.tofNSigmaPr()); - if (std::sqrt(pi * pi + tpi * tpi) < 2 && std::sqrt(pi * pi + tpi * tpi) < std::sqrt(ka * ka + tka * tka) && std::sqrt(pi * pi + tpi * tpi) < std::sqrt(pr * pr + tpr * tpr)) - pid = 1; - else if (std::sqrt(ka * ka + tka * tka) < 2 && std::sqrt(pi * pi + tpi * tpi) > std::sqrt(ka * ka + tka * tka) && std::sqrt(ka * ka + tka * tka) < std::sqrt(pr * pr + tpr * tpr)) - pid = 2; - else if (std::sqrt(pr * pr + tpr * tpr) < 2 && std::sqrt(pr * pr + tpr * tpr) < std::sqrt(ka * ka + tka * tka) && std::sqrt(pi * pi + tpi * tpi) > std::sqrt(pr * pr + tpr * tpr)) - pid = 3; - } - return pid; -} - -#endif // PWGUD_TASKS_SGTRACKSELECTOR_H_ diff --git a/PWGUD/Tasks/decayTreeAnalyzer.cxx b/PWGUD/Tasks/decayTreeAnalyzer.cxx new file mode 100644 index 00000000000..c725a2ca72a --- /dev/null +++ b/PWGUD/Tasks/decayTreeAnalyzer.cxx @@ -0,0 +1,143 @@ +// 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 Analyses UD tables (DGCandidates, DGTracks) of DG candidates produced with DGCandProducer +// \author Paul Buehler, paul.buehler@oeaw.ac.at +// \since 01.03.2024 + +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "CommonConstants/LHCConstants.h" +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/UDHelpers.h" +#include "PWGUD/Core/UDGoodRunSelector.h" +#include "PWGUD/Core/decayTree.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct decayTreeAnalyzer { + + // ccdb + Service ccdb; + int lastRun = -1; // last run number (needed to access ccdb only if run!=lastRun) + std::bitset bcPatternB; // bc pattern of colliding bunches + + // goodRun selector + Configurable goodRunsFile{"goodRunsFile", {}, "json with list of good runs"}; + UDGoodRunSelector grsel = UDGoodRunSelector(); + + // decay tree object + Configurable parsFile{"parsFile", {}, "json with parameters"}; + decayTree decTree = decayTree(); + + // initialize histogram registry + HistogramRegistry registry{ + "registry", + {}}; + + void init(InitContext&) + { + // goodRun selector + grsel.init(goodRunsFile); + grsel.Print(); + + // decay tree object + decTree.init(parsFile, registry); + decTree.Print(); + } + + using UDCollisionsFull = soa::Join; + using UDCollisionFull = UDCollisionsFull::iterator; + using UDTracksFull = soa::Join; + + // PV contributors + Filter PVContributorFilter = aod::udtrack::isPVContributor == true; + using PVTracks = soa::Filtered; + + void process(UDCollisionFull const& dgcand, UDTracksFull const& dgtracks, PVTracks const& PVContributors) + { + + // accept only selected run numbers + int run = dgcand.runNumber(); + if (!grsel.isGoodRun(run)) { + return; + } + + // extract bc pattern from CCDB for data or anchored MC only + if (run != lastRun && run >= 500000) { + LOGF(info, "Updating bcPattern %d ...", run); + auto tss = ccdb->getRunDuration(run); + auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", tss.first); + bcPatternB = grplhcif->getBunchFilling().getBCPattern(); + lastRun = run; + } + + // is BB bunch? + auto bcnum = dgcand.globalBC(); + if (run >= 500000 && bcPatternB[bcnum % o2::constants::lhc::LHCMaxBunches] == 0) { + LOGF(debug, "bcnum[1] %d is not a BB BC", bcnum % o2::constants::lhc::LHCMaxBunches); + return; + } + + // check FIT information + auto bitMin = decTree.dBCRange()[0] + 16; + auto bitMax = decTree.dBCRange()[1] + 16; + for (auto bit = bitMin; bit <= bitMax; bit++) { + if (decTree.FITvetos()[0] && TESTBIT(dgcand.bbFV0Apf(), bit)) + return; + if (decTree.FITvetos()[1] && TESTBIT(dgcand.bbFT0Apf(), bit)) + return; + if (decTree.FITvetos()[2] && TESTBIT(dgcand.bbFT0Cpf(), bit)) + return; + if (decTree.FITvetos()[3] && TESTBIT(dgcand.bbFDDApf(), bit)) + return; + if (decTree.FITvetos()[4] && TESTBIT(dgcand.bbFDDCpf(), bit)) + return; + } + + // check number of PV contributors + if (dgcand.numContrib() != PVContributors.size()) { + LOGF(info, "Missmatch of PVContributors %d != %d", dgcand.numContrib(), PVContributors.size()); + } + auto nTrackRange = decTree.ntrackRange(); + if (dgcand.numContrib() < nTrackRange[0] || dgcand.numContrib() > nTrackRange[1]) { + LOGF(debug, "Rejected 1: %d not in range [%d, %d].", dgcand.numContrib(), nTrackRange[0], nTrackRange[1]); + return; + } + + // skip events with out-of-range rgtrwTOF + auto rtrwTOF = udhelpers::rPVtrwTOF(dgtracks, PVContributors.size()); + auto minRgtrwTOF = decTree.rgtrTOFMin(); + if (rtrwTOF < minRgtrwTOF) { + LOGF(debug, "Rejected 3: %f below threshold of %f.", rtrwTOF, minRgtrwTOF); + return; + } + + // compute the decay tree + LOGF(debug, "BC %d", dgcand.globalBC()); + decayTreeResType results = decTree.processTree(PVContributors); + // decTree.fillHistograms(results, PVContributors); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"decaytree-analyzer"}), + }; +} diff --git a/PWGUD/Tasks/dgCandAnalyzer.cxx b/PWGUD/Tasks/dgCandAnalyzer.cxx index d0966dc794d..93c62c567d5 100644 --- a/PWGUD/Tasks/dgCandAnalyzer.cxx +++ b/PWGUD/Tasks/dgCandAnalyzer.cxx @@ -14,6 +14,8 @@ // \since 06.06.2022 #include +#include + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -217,7 +219,11 @@ struct DGCandAnalyzer { } } - void processReco(UDCollisionFull const& dgcand, UDTracksFull const& dgtracks) + // PV contributors + Filter PVContributorFilter = aod::udtrack::isPVContributor == true; + using PVTracks = soa::Filtered; + + void processReco(UDCollisionFull const& dgcand, UDTracksFull const& dgtracks, PVTracks const& PVContributors) { // count collisions registry.fill(HIST("stat/candCaseAll"), 0., 1.); @@ -273,8 +279,6 @@ struct DGCandAnalyzer { registry.fill(HIST("FIT/FDDCAmplitude"), dgcand.totalFDDAmplitudeC(), 1.); // skip events with too few/many tracks - Partition PVContributors = aod::udtrack::isPVContributor == true; - PVContributors.bindTable(dgtracks); if (dgcand.numContrib() != PVContributors.size()) { LOGF(info, "Missmatch of PVContributors %d != %d", dgcand.numContrib(), PVContributors.size()); } diff --git a/PWGUD/Tasks/diffMCDataScanner.cxx b/PWGUD/Tasks/diffMCDataScanner.cxx index 05a3e497e17..8ad8d7ae853 100644 --- a/PWGUD/Tasks/diffMCDataScanner.cxx +++ b/PWGUD/Tasks/diffMCDataScanner.cxx @@ -102,9 +102,21 @@ struct collisionsInfo { using MFs = aod::MFTTracks; using FWs = aod::FwdTracks; - void process(CC const& collision, BCs const& bct0s, - TCs& tracks, /* MFs& mfttracks,*/ FWs& fwdtracks, aod::FT0s& /*ft0s*/, aod::FV0As& /*fv0as*/, aod::FDDs& /*fdds*/, - aod::McCollisions& /*McCols*/, aod::McParticles& /*McParts*/) + // filter for global tracks + Filter globalTrackFilter = requireGlobalTrackInFilter(); + using globalTracks = soa::Filtered; + + void process(CC const& collision, + BCs const& bct0s, + TCs& tracks, + /* MFs& mfttracks,*/ + FWs& fwdtracks, + globalTracks& goodTracks, + aod::FT0s& /*ft0s*/, + aod::FV0As& /*fv0as*/, + aod::FDDs& /*fdds*/, + aod::McCollisions& /*McCols*/, + aod::McParticles& /*McParts*/) { // obtain slice of compatible BCs @@ -123,8 +135,6 @@ struct collisionsInfo { } // global tracks - Partition goodTracks = requireGlobalTrackInFilter(); - goodTracks.bindTable(tracks); int cntGlobal = goodTracks.size(); // count tracks diff --git a/PWGUD/Tasks/diffMCQA.cxx b/PWGUD/Tasks/diffMCQA.cxx index 4d199892762..19bf3016a97 100644 --- a/PWGUD/Tasks/diffMCQA.cxx +++ b/PWGUD/Tasks/diffMCQA.cxx @@ -239,12 +239,26 @@ struct DiffMCQA { PROCESS_SWITCH(DiffMCQA, processMCTruth, "Process MC truth", true); // ............................................................................................................... - void processMain(CC const& collision, BCs const& bct0s, - TCs const& tracks, FWs const& fwdtracks, ATs const& /*ambtracks*/, AFTs const& /*ambfwdtracks*/, - aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0as*/, aod::FDDs const& /*fdds*/, - aod::Zdcs& zdcs, aod::Calos& calos, - aod::V0s const& v0s, aod::Cascades const& cascades, - aod::McCollisions const& /*McCols*/, aod::McParticles const& McParts) + // filter for global tracks + Filter globalTrackFilter = requireGlobalTrackInFilter(); + using globalTracks = soa::Filtered; + + void processMain(CC const& collision, + BCs const& bct0s, + TCs const& tracks, + FWs const& fwdtracks, + globalTracks const& goodTracks, + ATs const& /*ambtracks*/, + AFTs const& /*ambfwdtracks*/, + aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0as*/, + aod::FDDs const& /*fdds*/, + aod::Zdcs& zdcs, + aod::Calos& calos, + aod::V0s const& v0s, + aod::Cascades const& cascades, + aod::McCollisions const& /*McCols*/, + aod::McParticles const& McParts) { bool isDGcandidate = true; @@ -263,10 +277,6 @@ struct DiffMCQA { registry.get(HIST("all/mcCols"))->Fill(0., 1.); } - // global tracks - Partition goodTracks = requireGlobalTrackInFilter(); - goodTracks.bindTable(tracks); - // update collision histograms if (isPythiaDiff) { registry.get(HIST("MBRDiff/Stat"))->Fill(0., 1.); diff --git a/PWGUD/Tasks/diffQA.cxx b/PWGUD/Tasks/diffQA.cxx index f219bc4eccb..a1e9ec34185 100644 --- a/PWGUD/Tasks/diffQA.cxx +++ b/PWGUD/Tasks/diffQA.cxx @@ -218,11 +218,24 @@ struct DiffQA { } // ............................................................................................................... - void processMain(CC const& collision, BCs const& bct0s, - TCs const& tracks, FWs const& fwdtracks, ATs const& /*ambtracks*/, AFTs const& /*ambfwdtracks*/, - aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0as*/, aod::FDDs const& /*fdds*/, - aod::Zdcs& zdcs, aod::Calos& calos, - aod::V0s const& v0s, aod::Cascades const& cascades) + // filter for global tracks + Filter globalTrackFilter = requireGlobalTrackInFilter(); + using globalTracks = soa::Filtered; + + void processMain(CC const& collision, + BCs const& bct0s, + TCs const& tracks, + FWs const& fwdtracks, + globalTracks const& goodTracks, + ATs const& /*ambtracks*/, + AFTs const& /*ambfwdtracks*/, + aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0as*/, + aod::FDDs const& /*fdds*/, + aod::Zdcs& zdcs, + aod::Calos& calos, + aod::V0s const& v0s, + aod::Cascades const& cascades) { LOGF(debug, " Collision %d", collision.globalIndex()); LOGF(debug, " Start %i", abcrs.size()); @@ -239,8 +252,6 @@ struct DiffQA { // vertex tracks registry.get(HIST("collisions/PVTracks"))->Fill(collision.numContrib()); // global tracks - Partition goodTracks = requireGlobalTrackInFilter(); - goodTracks.bindTable(tracks); registry.get(HIST("collisions/globalTracks"))->Fill(goodTracks.size()); // loop over all tracks diff --git a/PWGUD/Tasks/eventByevent.cxx b/PWGUD/Tasks/eventByevent.cxx new file mode 100644 index 00000000000..3df594af546 --- /dev/null +++ b/PWGUD/Tasks/eventByevent.cxx @@ -0,0 +1,302 @@ +// 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. +// + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "iostream" +#include "PWGUD/DataModel/UDTables.h" +#include +#include +#include "TLorentzVector.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" + +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// \brief Event by event study of pions +/// \author Amrit Gautam +/// \author Anisa Khatun +/// \date 20.07.2024 + +namespace o2::aod +{ +namespace tree +{ +// DECLARE_SOA_COLUMN(GAPSIDE, gapside, int); +// DECLARE_SOA_COLUMN(FT0AAMP, ft0Aamp, float); // namespace udzdc +// DECLARE_SOA_COLUMN(FT0CAMP, ft0Camp, float); +// DECLARE_SOA_COLUMN(FDDAAMP, fddAamp, float); +// DECLARE_SOA_COLUMN(FDDCAMP, fddCamp, float); +// DECLARE_SOA_COLUMN(FV0AAMP, fv0Aamp, float); +// ZDC tables +DECLARE_SOA_COLUMN(ZAENERGY, zaenergy, float); // namespace udzdc +DECLARE_SOA_COLUMN(ZCENERGY, zcenergy, float); +// track tables +// DECLARE_SOA_COLUMN(TRACKID, TrackId,std::vector); +DECLARE_SOA_COLUMN(SIGMAPI, sigmapi, std::vector); +DECLARE_SOA_COLUMN(SIGMAK, sigmak, std::vector); +DECLARE_SOA_COLUMN(SIGMAEL, sigmael, std::vector); +DECLARE_SOA_COLUMN(SIGMAPR, sigmapr, std::vector); +// DECLARE_SOA_COLUMN(SIGMAPI2, sigmapi2,float); +// DECLARE_SOA_COLUMN(SIGMAK2, sigmak2,float); +// DECLARE_SOA_COLUMN(SIGMAEL2, sigmael2,float); +// DECLARE_SOA_COLUMN(SIGMAPI3, sigmapi3,float); +// DECLARE_SOA_COLUMN(SIGMAK3, sigmak3,float); +// DECLARE_SOA_COLUMN(SIGMAEL3, sigmael3,float); +// DECLARE_SOA_COLUMN(SIGMAPI4, sigmapi4,float); +// DECLARE_SOA_COLUMN(SIGMAK4, sigmak4,float); +// DECLARE_SOA_COLUMN(SIGMAEL4, sigmael4,float); +DECLARE_SOA_COLUMN(PT, Pt, float); +DECLARE_SOA_COLUMN(RAP, rap, float); +DECLARE_SOA_COLUMN(PHI, Phi, float); +DECLARE_SOA_COLUMN(TOTSIGN, totsign, int); +DECLARE_SOA_COLUMN(MASS, mass, float); +DECLARE_SOA_COLUMN(NPVTRACK, npvtrack, int); +DECLARE_SOA_COLUMN(PTS, Pts, std::vector); +DECLARE_SOA_COLUMN(ETAS, etas, std::vector); +DECLARE_SOA_COLUMN(PHIS, Phis, std::vector); +DECLARE_SOA_COLUMN(SIGNS, Signs, std::vector); +// DECLARE_SOA_COLUMN(RAWTRACKS, rawtracks, int); +// DECLARE_SOA_COLUMN(PTRACKS, ptracks, int); + +// DECLARE_SOA_COLUMN(NTPCCLS, ntpccls,int); +} // namespace tree + +DECLARE_SOA_TABLE(TREE, "AOD", "Tree", //! ZDC information + // tree::GAPSIDE, + // tree::FT0AAMP, + // tree::FT0CAMP, + // tree::FDDAAMP, + // tree::FDDCAMP, + // tree::FV0AAMP, + tree::ZAENERGY, + tree::ZCENERGY, + tree::PT, + tree::RAP, + tree::PHI, + tree::MASS, + tree::TOTSIGN, + tree::NPVTRACK, + tree::SIGMAPI, + // tree::SIGMAPI2, + // tree::SIGMAPI3, + // tree::SIGMAPI4, + tree::SIGMAK, + // tree::SIGMAK2, + // tree::SIGMAK3, + // tree::SIGMAK4, + tree::SIGMAEL, + // tree::SIGMAEL2, + // tree::SIGMAEL3, + // tree::SIGMAEL4, + tree::SIGMAPR, + tree::PTS, + tree::ETAS, + tree::PHIS, + tree::SIGNS + // tree::RAWTRACKS, + // tree::PTRACKS +); + +} // namespace o2::aod + +struct EventByEvent { + SGSelector sgSelector; + Produces tree; + + Configurable FV0_cut{"FV0", 100., "FV0A threshold"}; + Configurable FT0A_cut{"FT0A", 200., "FT0A threshold"}; + Configurable FT0C_cut{"FT0C", 100., "FT0C threshold"}; + Configurable FDDA_cut{"FDDA", 10000., "FDDA threshold"}; + Configurable FDDC_cut{"FDDC", 10000., "FDDC threshold"}; + Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; + Configurable gap_Side{"gap", 2, "gap selection"}; + + // Collision selection + Configurable collcontrib_cut{"collcontrib_cut", 10, "no. of PV contributor per collsion"}; + Configurable Zvtx_cut{"Zvtx_cut", 15, "z-vertex selection"}; + + // Track Selections + Configurable PV_cut{"PV_cut", 1.0, "Use Only PV tracks"}; + Configurable dcaZ_cut{"dcaZ_cut", 2.0, "dcaZ cut"}; + Configurable dcaXY_cut{"dcaXY_cut", 0.0, "dcaXY cut (0 for Pt-function)"}; + Configurable tpcChi2_cut{"tpcChi2_cut", 4, "Max tpcChi2NCl"}; + Configurable tpcNClsFindable_cut{"tpcNClsFindable_cut", 70, "Min tpcNClsFindable"}; + Configurable itsChi2_cut{"itsChi2_cut", 36, "Max itsChi2NCl"}; + Configurable eta_cut{"eta_cut", 0.9, "Track Pseudorapidity"}; + Configurable pt_cut{"pt_cut", 0.1, "Track Pt"}; + Configurable TPC_cluster{"TPC_cluster", 50, "No.of TPC cluster"}; + + // Kinmatic cuts + Configurable PID_cut{"PID_cut", 5, "TPC PID"}; + Configurable Rap_cut{"Rap_cut", 0.9, "Track rapidity"}; + Configurable Mass_Max{"Mass_Max", 10, "Invariant Mass range high"}; + Configurable Mass_Min{"Mass_Min", 0, "Invariant Mass range low"}; + Configurable Pt_coherent{"Pt_coherent", 0.15, "Coherent selection"}; + + // defining histograms using histogram registry + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //----------------------------------------------------------------------------------------------------------------------- + void init(o2::framework::InitContext&) + { + + registry.add("GapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + registry.add("TrueGapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + + auto hSelectionCounter = registry.add("hSelectionCounter", "hSelectionCounter;;NEvents", HistType::kTH1I, {{20, 0., 20.}}); + + TString SelectionCuts[18] = {"NoSelection", "gapside", "goodtracks", "truegap", "ncollcontrib ", "zvtx", "2collcontrib", "2goodtrk", "TPCPID", "Rap_cut", "unlikesign", "mass_cut", "coherent", "incoherent", "likesign", "mass_cut", "coherent", "incoherent"}; + // now we can set BinLabel in histogram Registry + + for (int i = 0; i < 18; i++) { + hSelectionCounter->GetXaxis()->SetBinLabel(i + 1, SelectionCuts[i].Data()); + } + + // tracks + registry.add("hTracks", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hTracksPions", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("h4TracksPions", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hdEdx", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {100, 0.0, 200.0}}); + registry.add("hdEdxPion", "p_{#pi} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {100, 0.0, 200.0}}); + + // using Angular Correlation method + } + + using udtracks = soa::Join; + using udtracksfull = soa::Join; + using UDCollisionsFull = soa::Join; + //__________________________________________________________________________ + // Main process + void process(UDCollisionsFull::iterator const& collision, udtracksfull const& tracks) + { + registry.fill(HIST("hSelectionCounter"), 0); + // LOGF(info, " BC ID %d",collision.gapSide()); + int gapSide = collision.gapSide(); + if (gapSide < 0 || gapSide > 2) + return; + + registry.fill(HIST("hSelectionCounter"), 1); + + float FIT_cut[5] = {FV0_cut, FT0A_cut, FT0C_cut, FDDA_cut, FDDC_cut}; + int truegapSide = sgSelector.trueGap(collision, FIT_cut[0], FIT_cut[1], FIT_cut[2], ZDC_cut); + std::vector parameters = {PV_cut, dcaZ_cut, dcaXY_cut, tpcChi2_cut, tpcNClsFindable_cut, itsChi2_cut, eta_cut, pt_cut}; + registry.fill(HIST("hSelectionCounter"), 2); + + registry.fill(HIST("GapSide"), gapSide); + registry.fill(HIST("TrueGapSide"), truegapSide); + gapSide = truegapSide; + + registry.fill(HIST("hSelectionCounter"), 3); + //_____________________________________ + // Create pions and apply TPC Pion PID + std::vector allTracks; + std::vector onlyPionTracks; + std::vector onlyPionSigma; + std::vector rawPionTracks; + std::vector trackpt; + std::vector tracketa; + std::vector trackphi; + std::vector tracksign; + std::vector pitpcpid; + std::vector ktpcpid; + std::vector eltpcpid; + std::vector prtpcpid; + + TLorentzVector p; + + if (gapSide == gap_Side) { + + // registry.fill(HIST("hTracks"), tracks.size()); + + if (collision.numContrib() > collcontrib_cut) + return; + + registry.fill(HIST("hSelectionCounter"), 4); + if ((collision.posZ() < -(Zvtx_cut)) || (collision.posZ() > Zvtx_cut)) + return; + registry.fill(HIST("hSelectionCounter"), 5); + + for (auto t : tracks) { + + if (!trackselector(t, parameters)) + continue; + + double dEdx = t.tpcSignal(); + + registry.fill(HIST("hdEdx"), t.tpcInnerParam() / t.sign(), dEdx); + TLorentzVector a; + a.SetXYZM(t.px(), t.py(), t.pz(), o2::constants::physics::MassPionCharged); + allTracks.push_back(a); + auto nSigmaPi = t.tpcNSigmaPi(); + + if (fabs(nSigmaPi) < PID_cut) { + onlyPionTracks.push_back(a); + onlyPionSigma.push_back(nSigmaPi); + rawPionTracks.push_back(t); + registry.fill(HIST("hdEdxPion"), t.tpcInnerParam() / t.sign(), dEdx); + } + } + registry.fill(HIST("hTracksPions"), onlyPionTracks.size()); + + //_____________________________________ + if (collision.numContrib() >= 2) { + // Four pions analysis + registry.fill(HIST("hSelectionCounter"), 6); + if ((rawPionTracks.size() >= 2) && (allTracks.size() >= 2)) { + + for (auto pion : onlyPionTracks) { + p += pion; + } + + registry.fill(HIST("h4TracksPions"), onlyPionTracks.size()); + registry.fill(HIST("hSelectionCounter"), 7); + + for (auto rtrk : rawPionTracks) { + + TLorentzVector itrk; + itrk.SetXYZM(rtrk.px(), rtrk.py(), rtrk.pz(), o2::constants::physics::MassPionCharged); + trackpt.push_back(itrk.Pt()); + tracketa.push_back(itrk.Eta()); + trackphi.push_back(itrk.Phi()); + tracksign.push_back(rtrk.sign()); + pitpcpid.push_back(rtrk.tpcNSigmaPi()); + ktpcpid.push_back(rtrk.tpcNSigmaKa()); + eltpcpid.push_back(rtrk.tpcNSigmaEl()); + prtpcpid.push_back(rtrk.tpcNSigmaPr()); + } + + int sign = 0; + TLorentzVector piplus, piminus; + for (auto rawPion : rawPionTracks) { + sign += rawPion.sign(); + } + + registry.fill(HIST("hTracks"), collision.numContrib()); + + tree(collision.energyCommonZNA(), collision.energyCommonZNC(), p.Pt(), p.Y(), p.Phi(), p.M(), sign, collision.numContrib(), pitpcpid, ktpcpid, eltpcpid, prtpcpid, trackpt, tracketa, trackphi, tracksign); + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/exclusivePentaquark.cxx b/PWGUD/Tasks/exclusivePentaquark.cxx new file mode 100644 index 00000000000..95da9600f67 --- /dev/null +++ b/PWGUD/Tasks/exclusivePentaquark.cxx @@ -0,0 +1,324 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "iostream" +#include "PWGUD/DataModel/UDTables.h" +#include +#include "TLorentzVector.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGUD/Core/SGSelector.h" +using std::array; +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// \brief Exclusive proton+Jpsi task +/// \author Simone Ragoni, Creighton +/// \date 29/4/2024 + +struct ExclusivePentaquark { + SGSelector sgSelector; + Configurable FV0_cut{"FV0", 100., "FV0A threshold"}; + Configurable FT0A_cut{"FT0A", 200., "FT0A threshold"}; + Configurable FT0C_cut{"FT0C", 100., "FT0C threshold"}; + Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; + Configurable gap_Side{"gap", 2, "gap selection"}; + + // defining histograms using histogram registry + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //----------------------------------------------------------------------------------------------------------------------- + void init(o2::framework::InitContext&) + { + registry.add("GapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + registry.add("TrueGapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + registry.add("posx", "Vertex position in x", kTH1F, {{100, -0.5, 0.5}}); + registry.add("posy", "Vertex position in y", kTH1F, {{100, -0.5, 0.5}}); + registry.add("posz", "Vertex position in z", kTH1F, {{1000, -100., 100.}}); + registry.add("hITSCluster", "N_{cluster}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hChi2ITSTrkSegment", "N_{cluster}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hTPCCluster", "N_{cluster}", kTH1F, {{200, -0.5, 199.5}}); + registry.add("hdEdx", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdx2", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdx3", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdSigmaElectron", "p vs dE/dx sigma electron", kTH2F, {{100, 0.0, 3.0}, {1000, -500.0, 500.0}}); + registry.add("hdSigmaProton", "p vs dE/dx sigma proton", kTH2F, {{100, 0.0, 3.0}, {1000, -500.0, 500.0}}); + registry.add("hdSigmaProton2", "p vs dE/dx sigma proton", kTH2F, {{100, 0.0, 3.0}, {1000, -500.0, 500.0}}); + registry.add("hdSigmaProton3", "p vs dE/dx sigma proton", kTH2F, {{100, 0.0, 3.0}, {1000, -500.0, 500.0}}); + registry.add("hNsigEvsKa1", "NSigma(t1) vs NSigma (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); + registry.add("hNsigEvsKa2", "NSigma(t1) vs NSigma (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); + registry.add("hMomentum", "p_{#ka};#it{p_{trk}}, GeV/c;", kTH1F, {{100, 0., 3.}}); + registry.add("hClusterSizeAllTracks", "ClusterSizeAllTracks;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeProtonsTPC", "ClusterSizeProtonsTPC;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeProtonsTOF", "ClusterSizeProtonsTOF;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hEta1", "#eta_{#ka};#it{#eta_{trk}}, GeV/c;", kTH1F, {{100, -2., 2.}}); + registry.add("hPtLikeSignProton", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("hMassLikeSignProton", "Raw Inv.M;#it{m_{pp}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("hMassPtLikeSignProton", "Raw Inv.M;#it{m_{PP}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{1000, 0., 10.}, {400, 0., 4.}}); + + auto hSelectionCounter = registry.add("hSelectionCounter", "hSelectionCounter;;NEvents", HistType::kTH1I, {{10, 0., 10.}}); + + TString SelectionCuts[9] = {"NoSelection", "GAPcondition", "PVtracks", "Good TPC-ITS track", "TPC/TOF PID track", "End trk loop", "Exactly 2p", "Like-sign ev", "Unlike-sign ev"}; + // now we can set BinLabel in histogram Registry + + for (int i = 0; i < 9; i++) { + hSelectionCounter->GetXaxis()->SetBinLabel(i + 1, SelectionCuts[i].Data()); + } + + // Unlike sign pp + registry.add("PP/hRapidity", "Rapidity;#it{y_{pp}};", kTH1F, {{100, -2., 2.}}); + registry.add("PP/hPtProtonVsProton", "Pt1 vs Pt2;p_{T};p_{T};", kTH2F, {{100, 0., 3.}, {100, 0., 3.}}); + registry.add("PP/hMassPtUnlikeSignProton", "Raw Inv.M;#it{m_{pp}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("PP/hMassUnlike", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hUnlikePt", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PP/hCoherentMass", "Raw Inv.M;#it{m_{pp}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + } + + using udtracks = soa::Join; + using udtracksfull = soa::Join; + using UDCollisionsFull = soa::Join; + //__________________________________________________________________________ + // Main process + void process(UDCollisionsFull::iterator const& collision, udtracksfull const& tracks) + { + registry.fill(HIST("hSelectionCounter"), 0); + int gapSide = collision.gapSide(); + if (gapSide < 0 || gapSide > 2) + return; + + registry.fill(HIST("posx"), collision.posX()); + registry.fill(HIST("posy"), collision.posY()); + registry.fill(HIST("posz"), collision.posZ()); + int truegapSide = sgSelector.trueGap(collision, FV0_cut, FT0A_cut, FT0C_cut, ZDC_cut); + registry.fill(HIST("GapSide"), gapSide); + registry.fill(HIST("TrueGapSide"), truegapSide); + gapSide = truegapSide; + // if (gapSide != gap_Side) { + // return; + // } + + TLorentzVector resonance; // lorentz vectors of tracks and the mother + + // =================================== + // Task for p+Jpsi pairs with PID + // =================================== + std::vector onlyLeptonTracks; + std::vector onlyProtonTracks; + std::vector onlyProtonTracksTOF; + std::vector onlyProtonSigma; + std::vector onlyProtonSigmaTOF; + std::vector rawLeptonTracks; + std::vector rawProtonTracks; + std::vector rawProtonTracksTOF; + + for (auto trk : tracks) { + if (!trk.isPVContributor()) { + continue; + } + registry.fill(HIST("hSelectionCounter"), 2); + + int NFindable = trk.tpcNClsFindable(); + int NMinusFound = trk.tpcNClsFindableMinusFound(); + int NCluster = NFindable - NMinusFound; + registry.fill(HIST("hTPCCluster"), NCluster); + registry.fill(HIST("hChi2ITSTrkSegment"), trk.itsChi2NCl()); + if (NCluster < 70) { + continue; + } + if (trk.itsNCls() < 7) { + continue; + } + if (trk.pt() < 0.1) { + continue; + } + if (!(std::abs(trk.dcaZ()) < 2.)) { + continue; + } + double dcaLimit = 0.0105 + 0.035 / pow(trk.pt(), 1.1); + if (!(std::abs(trk.dcaXY()) < dcaLimit)) { + continue; + } + registry.fill(HIST("hSelectionCounter"), 3); + registry.fill(HIST("hITSCluster"), trk.itsNCls()); + + int clusterSize[7]; + double averageClusterSize = 0.; + for (int i = 0; i < 7; i++) { // info stored in 4 bits + clusterSize[i] = (((1 << 4) - 1) & (trk.itsClusterSizes() >> 4 * i)); + averageClusterSize += static_cast(clusterSize[i]); + } + averageClusterSize /= 7.; + registry.fill(HIST("hClusterSizeAllTracks"), averageClusterSize); + + double momentum = TMath::Sqrt(trk.px() * trk.px() + trk.py() * trk.py() + trk.pz() * trk.pz()); + double dEdx = trk.tpcSignal(); + registry.fill(HIST("hdEdx"), momentum, dEdx); + + TLorentzVector electron; + electron.SetXYZM(trk.px(), trk.py(), trk.pz(), o2::constants::physics::MassElectron); + TLorentzVector muon; + muon.SetXYZM(trk.px(), trk.py(), trk.pz(), o2::constants::physics::MassMuon); + TLorentzVector proton; + proton.SetXYZM(trk.px(), trk.py(), trk.pz(), o2::constants::physics::MassProton); + TLorentzVector protonbar; + protonbar.SetXYZM(trk.px(), trk.py(), trk.pz(), o2::constants::physics::MassProtonBar); + auto nSigmaPr = trk.tpcNSigmaPr(); + auto nSigmaPrTOF = trk.tofNSigmaPr(); + auto nSigmaElTOF = trk.tofNSigmaEl(); + auto nSigmaMuTOF = trk.tofNSigmaMu(); + + if (trk.hasTOF()) { + registry.fill(HIST("hdSigmaProton"), momentum, nSigmaPrTOF); + } + if (fabs(nSigmaPr) < 2.) { + registry.fill(HIST("hdEdx2"), momentum, dEdx); + registry.fill(HIST("hdSigmaProton2"), momentum, nSigmaPr); + registry.fill(HIST("hMomentum"), momentum); + if (trk.hasTOF() && fabs(nSigmaPrTOF) < 2.) { + registry.fill(HIST("hdSigmaProton3"), momentum, nSigmaPrTOF); + registry.fill(HIST("hClusterSizeProtonsTOF"), averageClusterSize); + onlyProtonTracksTOF.push_back(proton); + onlyProtonSigmaTOF.push_back(nSigmaPrTOF); + rawProtonTracksTOF.push_back(trk); + } else if (!trk.hasTOF()) { + onlyProtonTracks.push_back(proton); + onlyProtonSigma.push_back(nSigmaPr); + rawProtonTracks.push_back(trk); + } + registry.fill(HIST("hSelectionCounter"), 4); + registry.fill(HIST("hClusterSizeProtonsTPC"), averageClusterSize); + } + + if (trk.hasTOF() && (fabs(nSigmaElTOF) < 2. || fabs(nSigmaMuTOF) < 2.) && trk.pt() > 0.5) { + if (fabs(trk.tpcNSigmaEl()) < fabs(trk.tpcNSigmaMu())) { + onlyLeptonTracks.push_back(electron); + } else { + onlyLeptonTracks.push_back(muon); + } + rawLeptonTracks.push_back(trk); + registry.fill(HIST("hdEdx3"), momentum, dEdx); + registry.fill(HIST("hdSigmaElectron"), momentum, nSigmaElTOF); + } + + } // trk loop + + registry.fill(HIST("hSelectionCounter"), 5); + + if (onlyLeptonTracks.size() == 2) { + int signSum = rawLeptonTracks[0].sign() + rawLeptonTracks[1].sign(); + TLorentzVector resonance; + resonance += onlyLeptonTracks[0]; + resonance += onlyLeptonTracks[1]; + if (signSum == 0) { + registry.fill(HIST("hMassPtLikeSignProton"), resonance.M(), resonance.Pt()); + registry.fill(HIST("hSelectionCounter"), 7); + registry.fill(HIST("hPtLikeSignProton"), resonance.Pt()); + registry.fill(HIST("hMassLikeSignProton"), resonance.M()); + } + + TLorentzVector pentaquark; + pentaquark += resonance; + if (onlyProtonTracksTOF.size() == 1) { + pentaquark += onlyProtonTracksTOF[0]; + if (resonance.M() > 3. && resonance.M() < 3.13) { + registry.fill(HIST("PP/hMassPtUnlikeSignProton"), pentaquark.M(), pentaquark.Pt()); + registry.fill(HIST("hSelectionCounter"), 8); + registry.fill(HIST("PP/hUnlikePt"), pentaquark.Pt()); + registry.fill(HIST("PP/hMassUnlike"), pentaquark.M()); + registry.fill(HIST("PP/hRapidity"), pentaquark.Rapidity()); + if (pentaquark.Pt() < 0.3) { + registry.fill(HIST("PP/hCoherentMass"), pentaquark.M()); + } + } + } + } + + // if ((onlyProtonTracksTOF.size() > 0) && (onlyProtonTracks.size() + onlyProtonTracksTOF.size()) == 2) { + // registry.fill(HIST("hSelectionCounter"), 6); + + // int signSum = -999.; + // double sigmaTotal = -999.; + // if (onlyProtonTracksTOF.size() == 1) { + + // if (!(fabs(onlyProtonTracks[0].Eta()) < 0.8 && fabs(onlyProtonTracksTOF[0].Eta()) < 0.8)) { + // return; + // } + // registry.fill(HIST("hEta1"), onlyProtonTracks[0].Eta()); + // registry.fill(HIST("hEta1"), onlyProtonTracksTOF[0].Eta()); + // resonance += onlyProtonTracks[0]; + // resonance += onlyProtonTracksTOF[0]; + // sigmaTotal = 0; + // sigmaTotal = onlyProtonSigma[0] * onlyProtonSigma[0] + onlyProtonSigmaTOF[0] * onlyProtonSigmaTOF[0]; + // ; + // registry.fill(HIST("hNsigEvsKa1"), onlyProtonSigma[0], onlyProtonSigmaTOF[0]); + // signSum = rawProtonTracks[0].sign() + rawProtonTracksTOF[0].sign(); + // if (signSum == 0) { + // registry.fill(HIST("PP/hPtProtonVsProton"), onlyProtonTracks[0].Pt(), onlyProtonTracksTOF[0].Pt()); + // } + + // } else if (onlyProtonTracksTOF.size() == 2) { + + // if (!(fabs(onlyProtonTracksTOF[0].Eta()) < 0.8 && fabs(onlyProtonTracksTOF[1].Eta()) < 0.8)) { + // return; + // } + // registry.fill(HIST("hEta1"), onlyProtonTracksTOF[0].Eta()); + // registry.fill(HIST("hEta1"), onlyProtonTracksTOF[1].Eta()); + // resonance += onlyProtonTracksTOF[0]; + // resonance += onlyProtonTracksTOF[1]; + // sigmaTotal = 0; + // sigmaTotal = onlyProtonSigmaTOF[0] * onlyProtonSigmaTOF[0] + onlyProtonSigmaTOF[1] * onlyProtonSigmaTOF[1]; + // ; + // registry.fill(HIST("hNsigEvsKa1"), onlyProtonSigmaTOF[0], onlyProtonSigmaTOF[1]); + // signSum = rawProtonTracksTOF[0].sign() + rawProtonTracksTOF[1].sign(); + // if (signSum == 0) { + // registry.fill(HIST("PP/hPtProtonVsProton"), onlyProtonTracksTOF[0].Pt(), onlyProtonTracksTOF[1].Pt()); + // } + // } + + // if (sigmaTotal > 16.) { + // return; + // } + // if (onlyProtonTracksTOF.size() == 1) { + // registry.fill(HIST("hNsigEvsKa2"), onlyProtonSigma[0], onlyProtonSigmaTOF[0]); + // } else if (onlyProtonTracksTOF.size() == 2) { + // registry.fill(HIST("hNsigEvsKa2"), onlyProtonSigmaTOF[0], onlyProtonSigmaTOF[1]); + // } + + // if (signSum != 0) { + // registry.fill(HIST("hMassPtLikeSignProton"), resonance.M(), resonance.Pt()); + // registry.fill(HIST("hSelectionCounter"), 7); + // registry.fill(HIST("hPtLikeSignProton"), resonance.Pt()); + // registry.fill(HIST("hMassLikeSignProton"), resonance.M()); + // } else { + // registry.fill(HIST("PP/hMassPtUnlikeSignProton"), resonance.M(), resonance.Pt()); + // registry.fill(HIST("hSelectionCounter"), 8); + // registry.fill(HIST("PP/hUnlikePt"), resonance.Pt()); + // registry.fill(HIST("PP/hMassUnlike"), resonance.M()); + // registry.fill(HIST("PP/hRapidity"), resonance.Rapidity()); + // if (resonance.Pt() < 0.15) { + // registry.fill(HIST("PP/hCoherentMass"), resonance.M()); + // } + // } + // } + + } // end of process + +}; // end of struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/exclusivePhi.cxx b/PWGUD/Tasks/exclusivePhi.cxx index dcfbe750592..8f764f2bfff 100644 --- a/PWGUD/Tasks/exclusivePhi.cxx +++ b/PWGUD/Tasks/exclusivePhi.cxx @@ -8,6 +8,8 @@ // 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. +// +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -16,16 +18,13 @@ #include #include "TLorentzVector.h" #include "Common/DataModel/PIDResponse.h" -#include "PWGUD/Core/SGSelector.h" + using std::array; using namespace std; using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; -#define mpion 0.1396 // mass of pion -#define mkaon 0.493696 // mass of kaon -// #define mmuon 0.1057 // mass of muon /// \brief Exclusive phi without PID /// \author Simone Ragoni, Creighton @@ -33,9 +32,6 @@ using namespace o2::framework::expressions; /// \date 14/2/2024 struct ExclusivePhi { - SGSelector sgSelector; - Configurable FV0_cut{"FV0", 100., "FV0A threshold"}; - Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; // defining histograms using histogram registry HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -104,34 +100,56 @@ struct ExclusivePhi { //----------------------------------------------------------------------------------------------------------------------- void init(o2::framework::InitContext&) { - registry.add("GapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); - registry.add("TrueGapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + auto hSelectionCounter = registry.add("hSelectionCounter", "hSelectionCounter;;NEvents", HistType::kTH1I, {{12, 0., 12.}}); + TString SelectionCuts[12] = {"NoSelection", "Trackloop", "PVtracks", "|nsigmaka|<3", "|nsigmapi|>3", "|nsigmael|>3", "|nsigmamu|>3", "two tracks", "Phi-peak", "pt<0.2 GeV/c", "pt>0.2 GeV/c"}; + + for (int i = 0; i < 12; i++) { + hSelectionCounter->GetXaxis()->SetBinLabel(i + 1, SelectionCuts[i].Data()); + } + + registry.add("posx", "Vertex position in x", kTH1F, {{100, -0.5, 0.5}}); + registry.add("posy", "Vertex position in y", kTH1F, {{100, -0.5, 0.5}}); + registry.add("posz", "Vertex position in z", kTH1F, {{1000, -100., 100.}}); registry.add("hTracks", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hTracksITSonly", "N_{tracks ITS only}", kTH1F, {{100, -0.5, 99.5}}); registry.add("hITSCluster", "N_{cluster}", kTH1F, {{100, -0.5, 99.5}}); registry.add("hChi2ITSTrkSegment", "N_{cluster}", kTH1F, {{100, -0.5, 99.5}}); registry.add("hTPCCluster", "N_{cluster}", kTH1F, {{200, -0.5, 199.5}}); registry.add("hTracksKaons", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); registry.add("hdEdx", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); registry.add("hdEdxKaon", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon1", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); registry.add("hdEdxKaon2", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); registry.add("hdEdxKaon3", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); - registry.add("hNsigEvsKa1", "NSigmaKa(t1) vs NSigmaKa (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); - registry.add("hNsigEvsKa2", "NSigmaKa(t1) vs NSigmaKa (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); + registry.add("hdEdxKaon4", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon5", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon6", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon7", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon8", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon9", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + + registry.add("hNsigEvsKa1", "NSigmaKa(t1) vs NSigmaKa (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, 0., 1000.}, {100, 0., 1000}}); + registry.add("hNsigEvsKa2", "NSigmaKa(t1) vs NSigmaKa (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, 0., 1000.}, {100, 0., 1000}}); registry.add("hMomentum", "p_{#ka};#it{p_{trk}}, GeV/c;", kTH1F, {{100, 0., 3.}}); + registry.add("hClusterSizeAllTracks", "ClusterSizeAllTracks;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeMomentumCut", "ClusterSizeMomentumCut;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeOnlyIdentifiedKaons", "ClusterSizeOnlyIdentifiedKaons;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeOnlyITS", "ClusterSizeOnlyITS;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); registry.add("hEta1", "#eta_{#ka};#it{#eta_{trk}}, GeV/c;", kTH1F, {{100, -2., 2.}}); registry.add("hEta2", "#eta_{#ka};#it{#eta_{trk}}, GeV/c;", kTH1F, {{100, -2., 2.}}); registry.add("hPtPhi", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("hRapidityPhi", "Rapidity;#it{y_{KK}};", kTH1F, {{100, -2., 2.}}); registry.add("hMassPhi", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); - registry.add("hMassPtPhi", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("hMassPhiIncoherent", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); - auto hSelectionCounter = registry.add("hSelectionCounter", "hSelectionCounter;;NEvents", HistType::kTH1I, {{10, 0., 10.}}); + registry.add("hMassPtPhi", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); - TString SelectionCuts[9] = {"NoSelection", "GAPcondition", "PVtracks", "TPCcrossrow", "|nsigmaka|<2", "doublegap", "two tracks", "Phi-peak", "pt<0.2 GeV/c"}; - // now we can set BinLabel in histogram Registry + auto hSelectionCounter2 = registry.add("hSelectionCounter2", "hSelectionCounter;;NEvents", HistType::kTH1I, {{12, 0., 12.}}); + TString SelectionCuts2[12] = {"NoSelection", "Trackloop", "PVtracks", "|nTPCCluster|<50", " track pt<0.180 GeV/c", "Kaon Band", "ITSCluster<6", "two tracks", "Phi-peak", "pt<0.2 GeV/c", "pt>0.2 GeV/c"}; - for (int i = 0; i < 9; i++) { - hSelectionCounter->GetXaxis()->SetBinLabel(i + 1, SelectionCuts[i].Data()); + for (int i = 0; i < 12; i++) { + hSelectionCounter2->GetXaxis()->SetBinLabel(i + 1, SelectionCuts2[i].Data()); } registry.add("hMassPhiWithoutPID", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); @@ -149,6 +167,14 @@ struct ExclusivePhi { registry.add("PHI/hMassPhiWithoutPIDPionHypothesis", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1D, {{400, 0., 4.}}); registry.add("PHI/hPtPhiWithoutPIDPionHypothesis", "Pt;#it{p_{t}}, GeV/c;", kTH1D, {{500, 0., 5.}}); + // DIfferent phi topologies, 2 identified kaons, 1 identified kaon + 1 ITS track with correct selections and 4 ITS clusters + registry.add("KaonBandPHI/hMassPtPhiIdentifiedKaons", "Raw Inv.M;#it{m_{KK}} (GeV/c^{2});Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("KaonBandPHI/hMassPhiIdentifiedKaons", "Raw Inv.M;#it{M_{KK}} (GeV/c^{2});", kTH1F, {{400, 0., 4.}}); + registry.add("KaonBandPHI/hPtPhiIdentifiedKaons", "Pt;#it{p_{t}} (GeV/c);", kTH1F, {{400, 0., 4.}}); + registry.add("KaonBandPHI/hMassPtPhiIdentifiedKaonAndITSkaon", "Raw Inv.M;#it{m_{KK}} (GeV/c^{2});Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("KaonBandPHI/hMassPhiIdentifiedKaonAndITSkaon", "Raw Inv.M;#it{m_{KK}} (GeV/c^{2});", kTH1F, {{400, 0., 4.}}); + registry.add("KaonBandPHI/hPtPhiIdentifiedKaonAndITSkaon", "Pt;#it{p_{t}} (GeV/c);", kTH1F, {{400, 0., 4.}}); + registry.add("PHI/hMassLike", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{400, 0., 4.}}); registry.add("PHI/hMassUnlike", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{400, 0., 4.}}); registry.add("PHI/hlikePt", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); @@ -179,7 +205,6 @@ struct ExclusivePhi { registry.add("PHIHIGH/hInCoherentMassLike1", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); // Low Mass region - registry.add("PHILOW/hPtPhiWithoutPID2", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); registry.add("PHILOW/hMassVsPt2", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); registry.add("PHILOW/hRapidityPhiWithoutPID2", "Rapidity;#it{y_{KK}};", kTH1F, {{100, -2., 2.}}); @@ -201,26 +226,17 @@ struct ExclusivePhi { } using udtracks = soa::Join; - using udtracksfull = soa::Join; - using UDCollisionsFull = soa::Join; + using udtracksfull = soa::Join; + // using UDCollisions = soa::Join; //__________________________________________________________________________ - // Main process - void process(UDCollisions::iterator const&, udtracksfull const& tracks) - // void process(UDCollisionsFull::iterator const& collision, udtracksfull const& tracks) + // Main process + void process(UDCollisions::iterator const& collision, udtracksfull const& tracks) { registry.fill(HIST("hSelectionCounter"), 0); - /*int gapSide = collision.gapSide(); - if (gapSide < 0 || gapSide > 2) - return;*/ - // if (collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)){ - // if (collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { - registry.fill(HIST("hSelectionCounter"), 1); - - /* int truegapSide = sgSelector.trueGap(collision, FV0_cut, ZDC_cut); - registry.fill(HIST("GapSide"), gapSide); - registry.fill(HIST("TrueGapSide"), truegapSide); - gapSide = truegapSide;*/ + registry.fill(HIST("posx"), collision.posX()); + registry.fill(HIST("posy"), collision.posY()); + registry.fill(HIST("posz"), collision.posZ()); TLorentzVector phi, phiWithoutPID, phiWithKaonPID, phiWrongMomentaWithoutPID, phiWithoutPIDPionHypothesis; // lorentz vectors of tracks and the mother @@ -239,6 +255,7 @@ struct ExclusivePhi { std::vector rawKaonTracks; for (auto trk : tracks) { + registry.fill(HIST("hSelectionCounter"), 1); if (!trk.isPVContributor()) { continue; } @@ -247,61 +264,79 @@ struct ExclusivePhi { int NFindable = trk.tpcNClsFindable(); int NMinusFound = trk.tpcNClsFindableMinusFound(); int NCluster = NFindable - NMinusFound; + + if (NCluster < 50) { + continue; + } registry.fill(HIST("hTPCCluster"), NCluster); registry.fill(HIST("hITSCluster"), trk.itsNCls()); registry.fill(HIST("hChi2ITSTrkSegment"), trk.itsChi2NCl()); - registry.fill(HIST("hSelectionCounter"), 3); - - double momentum = TMath::Sqrt(trk.px() * trk.px() + trk.py() * trk.py() + trk.pz() * trk.pz()); double dEdx = trk.tpcSignal(); - registry.fill(HIST("hdEdx"), momentum, dEdx); - - /* if(trk.pt() > 0.180){ - continue; - }*/ + registry.fill(HIST("hdEdx"), trk.tpcInnerParam() / trk.sign(), dEdx); TLorentzVector kaon; - kaon.SetXYZM(trk.px(), trk.py(), trk.pz(), o2::constants::physics::MassKaonCharged); - auto nSigmaKa = trk.tpcNSigmaKa(); - - if (fabs(nSigmaKa) < 2.) { - onlyKaonTracks.push_back(kaon); - onlyKaonSigma.push_back(nSigmaKa); - rawKaonTracks.push_back(trk); - registry.fill(HIST("hdEdxKaon"), momentum, dEdx); - registry.fill(HIST("hSelectionCounter"), 4); - } + kaon.SetXYZM(trk.px(), trk.py(), trk.pz(), o2::constants::physics::MassElectron); + // auto nSigmaKa = trk.tpcNSigmaKa(); + auto nSigmaEl = trk.tpcNSigmaEl(); + // auto nSigmaPi = trk.tpcNSigmaPi(); + // auto nSigmaMu = trk.tpcNSigmaMu(); + + // if((nSigmaKa * nSigmaKa + nSigmaKa * nSigmaKa) > 9.) continue; + /*if (fabs(nSigmaKa) > 3.) + continue;*/ + registry.fill(HIST("hSelectionCounter"), 3); + registry.fill(HIST("hdEdxKaon1"), trk.tpcInnerParam() / trk.sign(), dEdx); + // if((nSigmaEl * nSigmaEl + nSigmaEl * nSigmaEl) < 9.) continue; + // if (fabs(nSigmaPi) < 3.)continue; + registry.fill(HIST("hSelectionCounter"), 4); + registry.fill(HIST("hdEdxKaon2"), trk.tpcInnerParam() / trk.sign(), dEdx); + // if((nSigmaPi * nSigmaPi + nSigmaPi * nSigmaPi) < 9.) continue; + if (fabs(nSigmaEl) < 3.) + continue; + registry.fill(HIST("hSelectionCounter"), 5); + registry.fill(HIST("hdEdxKaon3"), trk.tpcInnerParam() / trk.sign(), dEdx); + // if((nSigmaMu * nSigmaMu + nSigmaMu * nSigmaMu) < 9.) continue; + // if (fabs(nSigmaMu) < 3.) + // continue; + registry.fill(HIST("hSelectionCounter"), 6); + registry.fill(HIST("hdEdxKaon4"), trk.tpcInnerParam() / trk.sign(), dEdx); - } // trk loop + onlyKaonTracks.push_back(kaon); + onlyKaonSigma.push_back(nSigmaEl); + rawKaonTracks.push_back(trk); - // registry.fill(HIST("hTracksKaons"), rawKaonTracks.size()); + } // trk loop - // Creating phis using Kaon PID - // if (gapSide == 2) { - registry.fill(HIST("hSelectionCounter"), 5); if (onlyKaonTracks.size() == 2) { - registry.fill(HIST("hSelectionCounter"), 6); + registry.fill(HIST("hSelectionCounter"), 7); for (auto kaon : onlyKaonTracks) { phi += kaon; } - registry.fill(HIST("hNsigEvsKa1"), rawKaonTracks[0].tpcNSigmaKa(), rawKaonTracks[1].tpcNSigmaKa()); + registry.fill(HIST("hdEdxKaon"), rawKaonTracks[0].tpcInnerParam() / rawKaonTracks[0].sign(), rawKaonTracks[1].tpcSignal()); + registry.fill(HIST("hNsigEvsKa1"), rawKaonTracks[0].tpcSignal(), rawKaonTracks[1].tpcSignal()); registry.fill(HIST("hMassPtPhi"), phi.M(), phi.Pt()); - // if(rawKaonTracks[0].sign() != rawKaonTracks[1].sign()){ - if ((phi.M() > 0.98) && (phi.M() < 1.06)) { - registry.fill(HIST("hSelectionCounter"), 7); - registry.fill(HIST("hPtPhi"), phi.Pt()); - } - if (phi.Pt() < 0.2) { - registry.fill(HIST("hMassPhi"), phi.M()); - registry.fill(HIST("hSelectionCounter"), 8); - } + registry.fill(HIST("hRapidityPhi"), phi.Rapidity()); + + if (rawKaonTracks[0].sign() != rawKaonTracks[1].sign()) { + if ((phi.M() > 0.98) && (phi.M() < 1.05)) { + registry.fill(HIST("hSelectionCounter"), 8); + registry.fill(HIST("hPtPhi"), phi.Pt()); - // } + if (phi.Pt() < 0.2) { + registry.fill(HIST("hMassPhi"), phi.M()); + registry.fill(HIST("hSelectionCounter"), 9); + } + + if (phi.Pt() > 0.2) { + registry.fill(HIST("hMassPhiIncoherent"), phi.M()); + registry.fill(HIST("hSelectionCounter"), 10); + } + } + } } - // } // double gap // =================================== // Task for phi WITHOUT PID @@ -317,30 +352,34 @@ struct ExclusivePhi { //_____________________________________ // Create kaons WITHOUT PID std::vector onlyTwoTracks; + std::vector onlyKaonBandPID; + std::vector onlyITS; std::vector allTracksAreKaons; std::vector allTracksArePions; std::vector allTracksAreKaonsWrongMomentum; + std::vector allTracksAreKaonsBandPID; + std::vector allTracksAreITSonlyAndFourITSclusters; int counter = 0; for (auto t : tracks) { + registry.fill(HIST("hSelectionCounter2"), 0); if (!t.isPVContributor()) { continue; } - + registry.fill(HIST("hSelectionCounter2"), 1); registry.fill(HIST("hTracks"), t.size()); - /* if(t.itsNCls() < 4) { - continue; - }*/ - double momentum = TMath::Sqrt(t.px() * t.px() + t.py() * t.py() + t.pz() * t.pz()); double dEdx = t.tpcSignal(); - registry.fill(HIST("hMomentum"), momentum); - - /* if ((!t.hasITS()) && (t.hasTPC()) && (t.hasTOF())) { - continue; - } // not working*/ + int clusterSize[7]; + double averageClusterSize = 0.; + for (int i = 0; i < 7; i++) { // info stored in 4 bits + clusterSize[i] = (((1 << 4) - 1) & (t.itsClusterSizes() >> 4 * i)); + averageClusterSize += static_cast(clusterSize[i]); + } + averageClusterSize /= 7.; + registry.fill(HIST("hClusterSizeAllTracks"), averageClusterSize); int NFindable = t.tpcNClsFindable(); int NMinusFound = t.tpcNClsFindableMinusFound(); @@ -350,26 +389,27 @@ struct ExclusivePhi { if (NCluster > 50) { continue; } + registry.fill(HIST("hSelectionCounter2"), 3); + registry.fill(HIST("hdEdxKaon5"), t.tpcInnerParam() / t.sign(), dEdx); - registry.fill(HIST("hdEdxKaon2"), momentum, dEdx); if (t.pt() > 0.180) { continue; } - registry.fill(HIST("hdEdxKaon3"), momentum, dEdx); + registry.fill(HIST("hSelectionCounter2"), 4); + registry.fill(HIST("hMomentum"), momentum); + registry.fill(HIST("hdEdxKaon6"), t.tpcInnerParam() / t.sign(), dEdx); + registry.fill(HIST("hClusterSizeMomentumCut"), averageClusterSize); onlyTwoTracks.push_back(t); TLorentzVector a; a.SetXYZM(t.px(), t.py(), t.pz(), o2::constants::physics::MassKaonCharged); TLorentzVector b; - b.SetXYZM(t.px(), t.py(), t.pz(), o2::constants::physics::MassPionCharged); + b.SetXYZM(t.px(), t.py(), t.pz(), o2::constants::physics::MassElectron); TLorentzVector a2; a2.SetXYZM(-1. * t.px(), -1. * t.py(), -1. * t.pz(), o2::constants::physics::MassKaonCharged); - if (-0.6 > a.Eta() || a.Eta() > 0.6) - continue; - allTracksAreKaons.push_back(a); allTracksArePions.push_back(b); @@ -379,41 +419,41 @@ struct ExclusivePhi { allTracksAreKaonsWrongMomentum.push_back(a2); } counter += 1; + + bool kaonBand = false; + if ((momentum > 0.180) && (momentum < 0.220) && (dEdx > 300)) { + kaonBand = true; + } else if ((momentum > 0.220) && (momentum < 0.300) && (dEdx > 180)) { + kaonBand = true; + } else if ((momentum > 0.300) && (momentum < 0.500) && (dEdx > 110)) { + kaonBand = true; + } + + if (kaonBand == true) { + registry.fill(HIST("hSelectionCounter2"), 5); + allTracksAreKaonsBandPID.push_back(a); + onlyKaonBandPID.push_back(t); + registry.fill(HIST("hdEdxKaon7"), t.tpcInnerParam() / t.sign(), dEdx); + registry.fill(HIST("hClusterSizeOnlyIdentifiedKaons"), averageClusterSize); + } + + if (NFindable < 1 && t.itsNCls() < 7) { + // if((NCluster==0) && (t.itsNCls() == 4)){ + allTracksAreITSonlyAndFourITSclusters.push_back(a); + onlyITS.push_back(t); + registry.fill(HIST("hdEdxKaon8"), t.tpcInnerParam() / t.sign(), dEdx); + registry.fill(HIST("hSelectionCounter2"), 6); + } + } // track loop //_____________________________________ // Creating phis and saving all the information // in the case that there are ONLY 2 PV - /* int hasITS[2] = {-1, -1}; - int hasTPC[2] = {-1, -1}; - int hasTOF[2] = {-1, -1}; - bool goodFirstTrack = false; - bool goodSecondTrack = false; - bool goodEvent = false; - if (onlyTwoTracks.size() == 2) { - hasITS[0] = onlyTwoTracks[0].hasITS(); - hasTPC[0] = onlyTwoTracks[0].hasTPC(); - hasTOF[0] = onlyTwoTracks[0].hasTOF(); - hasITS[1] = onlyTwoTracks[1].hasITS(); - hasTPC[1] = onlyTwoTracks[1].hasTPC(); - hasTOF[1] = onlyTwoTracks[1].hasTOF(); - if ((hasITS[0]) && (hasTPC[0]) && (!hasTOF[0])) { - goodFirstTrack = true; - } - - if ((hasITS[1]) && (hasTPC[1]) && (!hasTOF[1])) { - goodSecondTrack = true; - } - - if (goodFirstTrack || goodSecondTrack) { - goodEvent = true; - } - - }*/ - // if (gapSide == 2) { + // if ((collision.posZ() < -10) || (collision.posZ() > 10)) { if (allTracksAreKaons.size() == 2) { - + registry.fill(HIST("hSelectionCounter2"), 7); for (auto kaon : allTracksAreKaons) { phiWithoutPID += kaon; } @@ -427,24 +467,10 @@ struct ExclusivePhi { phiWithoutPIDPionHypothesis += pion; } - // TLorentzVector kaons[2], kaonsLikeSign[2], phiLikeSignWithoutPID; - registry.fill(HIST("hNsigEvsKa2"), onlyTwoTracks[0].tpcNSigmaKa(), onlyTwoTracks[1].tpcNSigmaKa()); + registry.fill(HIST("hNsigEvsKa2"), onlyTwoTracks[0].tpcSignal(), onlyTwoTracks[1].tpcSignal()); registry.fill(HIST("hEta1"), allTracksAreKaons[0].Eta()); registry.fill(HIST("hEta2"), allTracksAreKaons[1].Eta()); - /* if (-0.6 > allTracksAreKaons[0].Eta() || allTracksAreKaons[0].Eta() > 0.6) - return; - if (-0.6 > allTracksAreKaons[1].Eta() || allTracksAreKaons[1].Eta() > 0.6) - return;*/ - - // kaons[0].SetXYZM(onlyTwoTracks[0].px(), onlyTwoTracks[0].py(), onlyTwoTracks[0].pz(), o2::constants::physics::MassKaonCharged); - // kaons[1].SetXYZM(onlyTwoTracks[1].px(), onlyTwoTracks[1].py(), onlyTwoTracks[1].pz(), o2::constants::physics::MassKaonCharged); - - // phiWithoutPID += kaons[0]; - // phiWithoutPID += kaons[1]; - /*phiLikeSignWithoutPID += kaonsLikeSign[0]; - phiLikeSignWithoutPID += kaonsLikeSign[1];*/ - auto costhetaPhi = CosThetaHelicityFrame(allTracksAreKaons[0], allTracksAreKaons[1], phiWithoutPID); auto phiPhi = 1. * TMath::Pi() + PhiHelicityFrame(allTracksAreKaons[0], allTracksAreKaons[1], phiWithoutPID); @@ -454,46 +480,49 @@ struct ExclusivePhi { registry.fill(HIST("hMassPhiWrongMomentumWithoutPID"), phiWrongMomentaWithoutPID.M()); // Phi peak region - // if ((phiWithoutPID.Rapidity()>-0.6)&&(phiWithoutPID.Rapidity()<0.6)){ - // if ((phiWithoutPID.M() > 0.98) && (phiWithoutPID.M() < 1.06)) { - registry.fill(HIST("PHI/hPtPhiWithoutPID"), phiWithoutPID.Pt()); - registry.fill(HIST("PHI/hMassVsPt"), phiWithoutPID.M(), phiWithoutPID.Pt()); - registry.fill(HIST("PHI/hRapidityPhiWithoutPID"), phiWithoutPID.Rapidity()); - registry.fill(HIST("PHI/hPtKaonVsKaon"), allTracksAreKaons[0].Pt(), allTracksAreKaons[1].Pt()); - - registry.fill(HIST("PHI/hPtPhiWithoutPIDPionHypothesis"), phiWithoutPIDPionHypothesis.Pt()); - registry.fill(HIST("PHI/hMassPhiWithoutPIDPionHypothesis"), phiWithoutPIDPionHypothesis.M()); - - // unlike-sign - if (onlyTwoTracks[0].sign() != onlyTwoTracks[1].sign()) { - registry.fill(HIST("PHI/hCosThetaPhiWithoutPID"), costhetaPhi); - registry.fill(HIST("PHI/hPhiPhiWithoutPID"), phiPhi); - registry.fill(HIST("PHI/hCostheta_Phi"), phiPhi, costhetaPhi); - registry.fill(HIST("PHI/hUnlikePt"), phiWithoutPID.Pt()); - registry.fill(HIST("PHI/hMassUnlike"), phiWithoutPID.M()); - if (phiWithoutPID.Pt() < 0.2) { - registry.fill(HIST("PHI/hCoherentPhiWithoutPID"), phiWithoutPID.M()); - } - if (phiWithoutPID.Pt() > 0.2) { - registry.fill(HIST("PHI/hInCoherentPhiWithoutPID"), phiWithoutPID.M()); - } - } - //}//Rapidity - // Likesign quantities - if (onlyTwoTracks[0].sign() == onlyTwoTracks[1].sign()) { - registry.fill(HIST("PHI/hMassLike"), phiWithoutPID.M()); - registry.fill(HIST("PHI/hlikePt"), phiWithoutPID.Pt()); + if ((phiWithoutPID.M() > 0.98) && (phiWithoutPID.M() < 1.05)) { + registry.fill(HIST("PHI/hPtPhiWithoutPID"), phiWithoutPID.Pt()); + registry.fill(HIST("PHI/hMassVsPt"), phiWithoutPID.M(), phiWithoutPID.Pt()); + registry.fill(HIST("PHI/hRapidityPhiWithoutPID"), phiWithoutPID.Rapidity()); + registry.fill(HIST("PHI/hPtKaonVsKaon"), allTracksAreKaons[0].Pt(), allTracksAreKaons[1].Pt()); - if (phiWithoutPID.Pt() < 0.2) { - registry.fill(HIST("PHI/hCoherentMassLike"), phiWithoutPID.M()); + registry.fill(HIST("PHI/hPtPhiWithoutPIDPionHypothesis"), phiWithoutPIDPionHypothesis.Pt()); + registry.fill(HIST("PHI/hMassPhiWithoutPIDPionHypothesis"), phiWithoutPIDPionHypothesis.M()); + + // unlike-sign + if (onlyTwoTracks[0].sign() != onlyTwoTracks[1].sign()) { + registry.fill(HIST("hSelectionCounter2"), 8); + registry.fill(HIST("PHI/hCosThetaPhiWithoutPID"), costhetaPhi); + registry.fill(HIST("PHI/hPhiPhiWithoutPID"), phiPhi); + registry.fill(HIST("PHI/hCostheta_Phi"), phiPhi, costhetaPhi); + registry.fill(HIST("PHI/hUnlikePt"), phiWithoutPID.Pt()); + registry.fill(HIST("PHI/hMassUnlike"), phiWithoutPID.M()); + if (phiWithoutPID.Pt() < 0.2) { + registry.fill(HIST("hSelectionCounter2"), 9); + registry.fill(HIST("PHI/hCoherentPhiWithoutPID"), phiWithoutPID.M()); + } + if (phiWithoutPID.Pt() > 0.2) { + registry.fill(HIST("hSelectionCounter2"), 10); + registry.fill(HIST("PHI/hInCoherentPhiWithoutPID"), phiWithoutPID.M()); + } } - if (phiWithoutPID.Pt() > 0.2) { - registry.fill(HIST("PHI/hInCoherentMassLike"), phiWithoutPID.M()); + + // Likesign quantities + if (onlyTwoTracks[0].sign() == onlyTwoTracks[1].sign()) { + registry.fill(HIST("PHI/hMassLike"), phiWithoutPID.M()); + registry.fill(HIST("PHI/hlikePt"), phiWithoutPID.Pt()); + + if (phiWithoutPID.Pt() < 0.2) { + registry.fill(HIST("PHI/hCoherentMassLike"), phiWithoutPID.M()); + } + if (phiWithoutPID.Pt() > 0.2) { + registry.fill(HIST("PHI/hInCoherentMassLike"), phiWithoutPID.M()); + } } - } + } // Mass cut // Side band above phi mass region - if (phiWithoutPID.M() > 1.06) { + if (phiWithoutPID.M() > 1.05) { registry.fill(HIST("PHIHIGH/hPtPhiWithoutPID1"), phiWithoutPID.Pt()); registry.fill(HIST("PHIHIGH/hMassVsPt1"), phiWithoutPID.M(), phiWithoutPID.Pt()); @@ -536,7 +565,6 @@ struct ExclusivePhi { // Side band below phi mass region if (phiWithoutPID.M() < 0.98) { - registry.fill(HIST("PHILOW/hPtPhiWithoutPID2"), phiWithoutPID.Pt()); registry.fill(HIST("PHILOW/hMassVsPt2"), phiWithoutPID.M(), phiWithoutPID.Pt()); registry.fill(HIST("PHILOW/hRapidityPhiWithoutPID2"), phiWithoutPID.Rapidity()); @@ -574,10 +602,53 @@ struct ExclusivePhi { } } } // end of two tracks only loop + // } // vertex cut + + if (allTracksAreKaonsBandPID.size() == 2) { + + TLorentzVector reallyPhi; + for (auto kaon : allTracksAreKaonsBandPID) { + reallyPhi += kaon; + } + + registry.fill(HIST("KaonBandPHI/hMassPtPhiIdentifiedKaons"), reallyPhi.M(), reallyPhi.Pt()); + if (reallyPhi.Pt() < 0.2) { + registry.fill(HIST("KanonBandPHI/hMassPhiIdentifiedKaons"), reallyPhi.M()); + } + registry.fill(HIST("KaonBandPHI/hPtPhiIdentifiedKaons"), reallyPhi.Pt()); + } + + if (allTracksAreKaonsBandPID.size() == 1) { + + double momentum = TMath::Sqrt(onlyKaonBandPID[0].px() * onlyKaonBandPID[0].px() + onlyKaonBandPID[0].py() * onlyKaonBandPID[0].py() + onlyKaonBandPID[0].pz() * onlyKaonBandPID[0].pz()); + double dEdx = onlyKaonBandPID[0].tpcSignal(); + registry.fill(HIST("hdEdxKaon9"), momentum, dEdx); - // } // double gap - // } - } // end of process + // auto ksize = allTracksAreITSonlyAndFourITSclusters.size(); + registry.fill(HIST("hTracksITSonly"), allTracksAreITSonlyAndFourITSclusters.size()); + + for (std::size_t kaon = 0; kaon < allTracksAreITSonlyAndFourITSclusters.size(); kaon++) { + + int clusterSize[7]; + double averageClusterSize = 0.; + for (int i = 0; i < 7; i++) { // info stored in 4 bits + clusterSize[i] = (((1 << 4) - 1) & (onlyITS[kaon].itsClusterSizes() >> 4 * i)); + averageClusterSize += static_cast(clusterSize[i]); + } + averageClusterSize /= 7.; + registry.fill(HIST("hClusterSizeOnlyITS"), averageClusterSize); + + TLorentzVector reallyPhi; + reallyPhi += allTracksAreKaonsBandPID[0]; + reallyPhi += allTracksAreITSonlyAndFourITSclusters[kaon]; + registry.fill(HIST("KaonBandPHI/hMassPtPhiIdentifiedKaonAndITSkaon"), reallyPhi.M(), reallyPhi.Pt()); + registry.fill(HIST("KaonBandPHI/hPtPhiIdentifiedKaonAndITSkaon"), reallyPhi.Pt()); + if (reallyPhi.Pt() < 0.2) { + registry.fill(HIST("KaonBandPHI/hMassPhiIdentifiedKaonAndITSkaon"), reallyPhi.M()); + } + } + } // Kaon Band + } // end of process }; // end of struct diff --git a/PWGUD/Tasks/exclusivePhiLeptons.cxx b/PWGUD/Tasks/exclusivePhiLeptons.cxx new file mode 100644 index 00000000000..ea7e92f61dd --- /dev/null +++ b/PWGUD/Tasks/exclusivePhiLeptons.cxx @@ -0,0 +1,423 @@ +// 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. +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "iostream" +#include "PWGUD/DataModel/UDTables.h" +#include +#include "TLorentzVector.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGUD/Core/SGSelector.h" +using std::array; +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// \brief Exclusive phi->ee task +/// \author Simone Ragoni, Creighton +/// \date 5/5/2024 + +struct ExclusivePhiLeptons { + SGSelector sgSelector; + Configurable FV0_cut{"FV0", 100., "FV0A threshold"}; + Configurable FT0A_cut{"FT0A", 200., "FT0A threshold"}; + Configurable FT0C_cut{"FT0C", 100., "FT0C threshold"}; + Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; + Configurable gap_Side{"gap", 2, "gap selection"}; + Configurable pid2d_cut{"PID2D", 2., "PID cut in 2D"}; + Configurable pid_cut{"PID", 2., "PID cut in 1D"}; + Configurable electronsInTOF{"eTOF", 2, "electrons in TOF"}; + // defining histograms using histogram registry + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //----------------------------------------------------------------------------------------------------------------------- + void init(o2::framework::InitContext&) + { + registry.add("GapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + registry.add("TrueGapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + registry.add("posx", "Vertex position in x", kTH1F, {{100, -0.5, 0.5}}); + registry.add("posy", "Vertex position in y", kTH1F, {{100, -0.5, 0.5}}); + registry.add("posz", "Vertex position in z", kTH1F, {{1000, -100., 100.}}); + registry.add("hITSCluster", "N_{cluster}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hChi2ITSTrkSegment", "N_{cluster}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hTPCCluster", "N_{cluster}", kTH1F, {{200, -0.5, 199.5}}); + registry.add("hdEdx", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdx2", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdSigmaElectron", "p vs dE/dx sigma electron", kTH2F, {{100, 0.0, 3.0}, {1000, -500.0, 500.0}}); + registry.add("hdSigmaElectron2", "p vs dE/dx sigma electron", kTH2F, {{100, 0.0, 3.0}, {1000, -500.0, 500.0}}); + registry.add("hdSigmaElectron3", "p vs dE/dx sigma electron", kTH2F, {{100, 0.0, 3.0}, {1000, -500.0, 500.0}}); + registry.add("hNsigEvsKa1", "NSigma(t1) vs NSigma (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); + registry.add("hNsigEvsKa2", "NSigma(t1) vs NSigma (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); + registry.add("hMomentum", "p_{#ka};#it{p_{trk}}, GeV/c;", kTH1F, {{100, 0., 3.}}); + registry.add("hClusterSizeAllTracks", "ClusterSizeAllTracks;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeElectronsTPC", "ClusterSizeElectronsTPC;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeElectronsTOF", "ClusterSizeElectronsTOF;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hEta1", "#eta_{#ka};#it{#eta_{trk}}, GeV/c;", kTH1F, {{100, -2., 2.}}); + registry.add("hPtLikeSignElectron", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("hMassLikeSignElectron", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("hMassPtLikeSignElectron", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{1000, 0., 10.}, {400, 0., 4.}}); + + auto hSelectionCounter = registry.add("hSelectionCounter", "hSelectionCounter;;NEvents", HistType::kTH1I, {{10, 0., 10.}}); + + TString SelectionCuts[9] = {"NoSelection", "GAPcondition", "PVtracks", "Good TPC-ITS track", "TPC/TOF PID track", "End trk loop", "Exactly 2p", "Like-sign ev", "Unlike-sign ev"}; + // now we can set BinLabel in histogram Registry + + for (int i = 0; i < 9; i++) { + hSelectionCounter->GetXaxis()->SetBinLabel(i + 1, SelectionCuts[i].Data()); + } + + // Unlike sign pp + registry.add("PP/hRapidity", "Rapidity;#it{y_{ee}};", kTH1F, {{100, -2., 2.}}); + registry.add("PP/hPtElectronVsElectron", "Pt1 vs Pt2;p_{T};p_{T};", kTH2F, {{100, 0., 3.}, {100, 0., 3.}}); + registry.add("PP/hMassPtUnlikeSignElectron", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("PP/hMassUnlike", "m_{ee} [GeV/#it{c}^{2}]", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hUnlikePt", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PP/hUnlikePt2", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PP/hUnlikePt3", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PP/hUnlikePt4", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PP/hUnlikePt5", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PP/hUnlikePt6", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PP/hCoherentMass", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hCoherentMass2", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hCoherentMass3", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hCoherentMass4", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hCoherentMass5", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hCoherentMass6", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hIncoherentMass", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hIncoherentMass2", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hIncoherentMass3", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hIncoherentMass4", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hIncoherentMass5", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hIncoherentMass6", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hAngle", "Angular distrib helicity frame;#theta;", kTH1F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("PP/hAngle2", "Angular distrib helicity frame;#theta;", kTH1F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("PP/hAngle3", "Angular distrib helicity frame;#theta;", kTH1F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("PP/hAngle4", "Angular distrib helicity frame;#theta;", kTH1F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("PP/hAngle5", "Angular distrib helicity frame;#theta;", kTH1F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("PP/hAngle6", "Angular distrib helicity frame;#theta;", kTH1F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + } + + using udtracks = soa::Join; + using udtracksfull = soa::Join; + using UDCollisionsFull = soa::Join; + //__________________________________________________________________________ + // Main process + void process(UDCollisionsFull::iterator const& collision, udtracksfull const& tracks) + { + registry.fill(HIST("hSelectionCounter"), 0); + int gapSide = collision.gapSide(); + if (gapSide < 0 || gapSide > 2) + return; + + registry.fill(HIST("posx"), collision.posX()); + registry.fill(HIST("posy"), collision.posY()); + registry.fill(HIST("posz"), collision.posZ()); + int truegapSide = sgSelector.trueGap(collision, FV0_cut, FT0A_cut, FT0C_cut, ZDC_cut); + registry.fill(HIST("GapSide"), gapSide); + registry.fill(HIST("TrueGapSide"), truegapSide); + gapSide = truegapSide; + if (gapSide != gap_Side) { + return; + } + TLorentzVector resonance; // lorentz vectors of tracks and the mother + + // =================================== + // Task for p+pbar pairs with PID + // =================================== + std::vector onlyElectronTracks; + std::vector onlyElectronTracksTOF; + std::vector onlyElectronSigma; + std::vector onlyElectronSigmaTOF; + std::vector rawElectronTracks; + std::vector rawElectronTracksTOF; + + int counterPV = 0; + for (auto trk : tracks) { + if (!trk.isPVContributor()) { + continue; + } + counterPV += 1; + registry.fill(HIST("hSelectionCounter"), 2); + + int NFindable = trk.tpcNClsFindable(); + int NMinusFound = trk.tpcNClsFindableMinusFound(); + int NCluster = NFindable - NMinusFound; + registry.fill(HIST("hTPCCluster"), NCluster); + registry.fill(HIST("hChi2ITSTrkSegment"), trk.itsChi2NCl()); + if (NCluster < 70) { + continue; + } + if (trk.itsNCls() < 7) { + continue; + } + if (trk.pt() < 0.300) { + continue; + } + if (!(std::abs(trk.dcaZ()) < 2.)) { + continue; + } + double dcaLimit = 0.0105 + 0.035 / pow(trk.pt(), 1.1); + if (!(std::abs(trk.dcaXY()) < dcaLimit)) { + continue; + } + registry.fill(HIST("hSelectionCounter"), 3); + registry.fill(HIST("hITSCluster"), trk.itsNCls()); + + int clusterSize[7]; + double averageClusterSize = 0.; + for (int i = 0; i < 7; i++) { // info stored in 4 bits + clusterSize[i] = (((1 << 4) - 1) & (trk.itsClusterSizes() >> 4 * i)); + averageClusterSize += static_cast(clusterSize[i]); + } + averageClusterSize /= 7.; + registry.fill(HIST("hClusterSizeAllTracks"), averageClusterSize); + + double momentum = TMath::Sqrt(trk.px() * trk.px() + trk.py() * trk.py() + trk.pz() * trk.pz()); + double dEdx = trk.tpcSignal(); + registry.fill(HIST("hdEdx"), momentum, dEdx); + + TLorentzVector electron; + electron.SetXYZM(trk.px(), trk.py(), trk.pz(), o2::constants::physics::MassElectron); + auto nSigmaEl = trk.tpcNSigmaEl(); + auto nSigmaElTOF = trk.tofNSigmaEl(); + + if (trk.hasTOF()) { + registry.fill(HIST("hdSigmaElectron"), momentum, nSigmaElTOF); + } + if (fabs(nSigmaEl) < pid_cut) { + registry.fill(HIST("hdEdx2"), momentum, dEdx); + registry.fill(HIST("hdSigmaElectron2"), momentum, nSigmaEl); + registry.fill(HIST("hMomentum"), momentum); + if (trk.hasTOF() && fabs(nSigmaElTOF) < pid_cut) { + registry.fill(HIST("hdSigmaElectron3"), momentum, nSigmaElTOF); + registry.fill(HIST("hClusterSizeElectronsTOF"), averageClusterSize); + onlyElectronTracksTOF.push_back(electron); + onlyElectronSigmaTOF.push_back(nSigmaElTOF); + rawElectronTracksTOF.push_back(trk); + } else if (!trk.hasTOF()) { + onlyElectronTracks.push_back(electron); + onlyElectronSigma.push_back(nSigmaEl); + rawElectronTracks.push_back(trk); + } + registry.fill(HIST("hSelectionCounter"), 4); + registry.fill(HIST("hClusterSizeElectronsTPC"), averageClusterSize); + } + + } // trk loop + + if (counterPV != 2) { + return; + } + registry.fill(HIST("hSelectionCounter"), 5); + if ((onlyElectronTracksTOF.size() >= electronsInTOF) && (onlyElectronTracks.size() + onlyElectronTracksTOF.size()) == 2) { + registry.fill(HIST("hSelectionCounter"), 6); + + int signSum = -999.; + double sigmaTotal = -999.; + TVector3 momentum[2]; + int restrictedMomenta = -1; + // two electrons in the TPC + if (onlyElectronTracksTOF.size() == 0) { + + if (!(fabs(onlyElectronTracks[0].Eta()) < 0.8 && fabs(onlyElectronTracks[1].Eta()) < 0.8)) { + return; + } + if (!(onlyElectronTracks[0].P() < 0.8 && onlyElectronTracks[0].P() > 0.3 && onlyElectronTracks[1].P() < 0.8 && onlyElectronTracks[1].P() > 0.3)) { + return; + } + if (!(onlyElectronTracks[0].P() < 0.6 && onlyElectronTracks[0].P() > 0.4 && onlyElectronTracks[1].P() < 0.6 && onlyElectronTracks[1].P() > 0.4)) { + restrictedMomenta = 1; + } + momentum[0] = onlyElectronTracks[0].Vect(); + momentum[1] = onlyElectronTracks[1].Vect(); + registry.fill(HIST("hEta1"), onlyElectronTracks[0].Eta()); + registry.fill(HIST("hEta1"), onlyElectronTracks[1].Eta()); + resonance += onlyElectronTracks[0]; + resonance += onlyElectronTracks[1]; + sigmaTotal = 0; + sigmaTotal = onlyElectronSigma[0] * onlyElectronSigma[0] + onlyElectronSigma[1] * onlyElectronSigma[1]; + ; + registry.fill(HIST("hNsigEvsKa1"), onlyElectronSigma[0], onlyElectronSigma[1]); + signSum = rawElectronTracks[0].sign() + rawElectronTracks[1].sign(); + if (signSum == 0) { + registry.fill(HIST("PP/hPtElectronVsElectron"), onlyElectronTracks[0].Pt(), onlyElectronTracks[1].Pt()); + } + + } else if (onlyElectronTracksTOF.size() == 1) { + + if (!(fabs(onlyElectronTracks[0].Eta()) < 0.8 && fabs(onlyElectronTracksTOF[0].Eta()) < 0.8)) { + return; + } + if (!(onlyElectronTracks[0].P() < 0.8 && onlyElectronTracks[0].P() > 0.3 && onlyElectronTracksTOF[0].P() < 0.8 && onlyElectronTracksTOF[0].P() > 0.3)) { + return; + } + if (!(onlyElectronTracks[0].P() < 0.6 && onlyElectronTracks[0].P() > 0.4 && onlyElectronTracksTOF[0].P() < 0.6 && onlyElectronTracksTOF[0].P() > 0.4)) { + restrictedMomenta = 1; + } + momentum[0] = onlyElectronTracks[0].Vect(); + momentum[1] = onlyElectronTracksTOF[0].Vect(); + registry.fill(HIST("hEta1"), onlyElectronTracks[0].Eta()); + registry.fill(HIST("hEta1"), onlyElectronTracksTOF[0].Eta()); + resonance += onlyElectronTracks[0]; + resonance += onlyElectronTracksTOF[0]; + sigmaTotal = 0; + sigmaTotal = onlyElectronSigma[0] * onlyElectronSigma[0] + onlyElectronSigmaTOF[0] * onlyElectronSigmaTOF[0]; + ; + registry.fill(HIST("hNsigEvsKa1"), onlyElectronSigma[0], onlyElectronSigmaTOF[0]); + signSum = rawElectronTracks[0].sign() + rawElectronTracksTOF[0].sign(); + if (signSum == 0) { + registry.fill(HIST("PP/hPtElectronVsElectron"), onlyElectronTracks[0].Pt(), onlyElectronTracksTOF[0].Pt()); + } + + } else if (onlyElectronTracksTOF.size() == 2) { + + if (!(fabs(onlyElectronTracksTOF[0].Eta()) < 0.8 && fabs(onlyElectronTracksTOF[1].Eta()) < 0.8)) { + return; + } + if (!(onlyElectronTracksTOF[0].P() < 0.8 && onlyElectronTracksTOF[0].P() > 0.3 && onlyElectronTracksTOF[1].P() < 0.8 && onlyElectronTracksTOF[1].P() > 0.3)) { + return; + } + if (!(onlyElectronTracksTOF[0].P() < 0.6 && onlyElectronTracksTOF[0].P() > 0.4 && onlyElectronTracksTOF[1].P() < 0.6 && onlyElectronTracksTOF[1].P() > 0.4)) { + restrictedMomenta = 1; + } + momentum[0] = onlyElectronTracksTOF[0].Vect(); + momentum[1] = onlyElectronTracksTOF[1].Vect(); + registry.fill(HIST("hEta1"), onlyElectronTracksTOF[0].Eta()); + registry.fill(HIST("hEta1"), onlyElectronTracksTOF[1].Eta()); + resonance += onlyElectronTracksTOF[0]; + resonance += onlyElectronTracksTOF[1]; + sigmaTotal = 0; + sigmaTotal = onlyElectronSigmaTOF[0] * onlyElectronSigmaTOF[0] + onlyElectronSigmaTOF[1] * onlyElectronSigmaTOF[1]; + ; + registry.fill(HIST("hNsigEvsKa1"), onlyElectronSigmaTOF[0], onlyElectronSigmaTOF[1]); + signSum = rawElectronTracksTOF[0].sign() + rawElectronTracksTOF[1].sign(); + if (signSum == 0) { + registry.fill(HIST("PP/hPtElectronVsElectron"), onlyElectronTracksTOF[0].Pt(), onlyElectronTracksTOF[1].Pt()); + } + } + + if (sigmaTotal > pid2d_cut * pid2d_cut) { + return; + } + if (onlyElectronTracksTOF.size() == 1) { + registry.fill(HIST("hNsigEvsKa2"), onlyElectronSigma[0], onlyElectronSigmaTOF[0]); + } else if (onlyElectronTracksTOF.size() == 2) { + registry.fill(HIST("hNsigEvsKa2"), onlyElectronSigmaTOF[0], onlyElectronSigmaTOF[1]); + } + + auto angleBetweenMomenta = momentum[0].Angle(momentum[1]); + if (signSum == 0) { + registry.fill(HIST("PP/hAngle"), angleBetweenMomenta); + } + + // if (fabs(angleBetweenMomenta - TMath::Pi()) > TMath::Pi() / 18.) { + // return; + // } + + if (signSum != 0) { + registry.fill(HIST("hMassPtLikeSignElectron"), resonance.M(), resonance.Pt()); + registry.fill(HIST("hSelectionCounter"), 7); + registry.fill(HIST("hPtLikeSignElectron"), resonance.Pt()); + registry.fill(HIST("hMassLikeSignElectron"), resonance.M()); + } else { + registry.fill(HIST("PP/hMassPtUnlikeSignElectron"), resonance.M(), resonance.Pt()); + registry.fill(HIST("hSelectionCounter"), 8); + if (fabs(angleBetweenMomenta - TMath::Pi()) < TMath::Pi() / 18.) { + registry.fill(HIST("PP/hAngle2"), angleBetweenMomenta); + if (resonance.M() > 1.02 && resonance.M() < 1.06) { + registry.fill(HIST("PP/hUnlikePt"), resonance.Pt()); + } + registry.fill(HIST("PP/hMassUnlike"), resonance.M()); + registry.fill(HIST("PP/hRapidity"), resonance.Rapidity()); + if (resonance.Pt() > 0.1) { + registry.fill(HIST("PP/hIncoherentMass"), resonance.M()); + } else { + registry.fill(HIST("PP/hCoherentMass"), resonance.M()); + } + } + if (fabs(angleBetweenMomenta - TMath::Pi()) < TMath::Pi() / 90.) { + // two degs + registry.fill(HIST("PP/hAngle3"), angleBetweenMomenta); + if (resonance.M() > 1.02 && resonance.M() < 1.06) { + registry.fill(HIST("PP/hUnlikePt3"), resonance.Pt()); + } + if (resonance.Pt() > 0.1) { + registry.fill(HIST("PP/hIncoherentMass3"), resonance.M()); + } else { + registry.fill(HIST("PP/hCoherentMass3"), resonance.M()); + } + } + if (fabs(angleBetweenMomenta - TMath::Pi()) < TMath::Pi() / 180.) { + // one deg + registry.fill(HIST("PP/hAngle4"), angleBetweenMomenta); + if (resonance.M() > 1.02 && resonance.M() < 1.06) { + registry.fill(HIST("PP/hUnlikePt4"), resonance.Pt()); + } + if (resonance.Pt() > 0.1) { + registry.fill(HIST("PP/hIncoherentMass4"), resonance.M()); + } else { + registry.fill(HIST("PP/hCoherentMass4"), resonance.M()); + } + } + if (fabs(angleBetweenMomenta - TMath::Pi()) < TMath::Pi() / 180.) { + // one deg + if (resonance.M() > 1.02 && resonance.M() < 1.06) { + registry.fill(HIST("PP/hUnlikePt4"), resonance.Pt()); + } + if (resonance.Pt() > 0.1) { + registry.fill(HIST("PP/hIncoherentMass4"), resonance.M()); + } else { + registry.fill(HIST("PP/hCoherentMass4"), resonance.M()); + } + } + if (fabs(angleBetweenMomenta - TMath::Pi()) < TMath::Pi() / 18. && restrictedMomenta == 1) { + // ten degs + registry.fill(HIST("PP/hAngle5"), angleBetweenMomenta); + if (resonance.M() > 1.02 && resonance.M() < 1.06) { + registry.fill(HIST("PP/hUnlikePt5"), resonance.Pt()); + } + if (resonance.Pt() > 0.1) { + registry.fill(HIST("PP/hIncoherentMass5"), resonance.M()); + } else { + registry.fill(HIST("PP/hCoherentMass5"), resonance.M()); + } + } + if (fabs(angleBetweenMomenta - TMath::Pi()) < TMath::Pi() / 90. && restrictedMomenta == 1) { + // two degs + registry.fill(HIST("PP/hAngle6"), angleBetweenMomenta); + if (resonance.M() > 1.02 && resonance.M() < 1.06) { + registry.fill(HIST("PP/hUnlikePt6"), resonance.Pt()); + } + if (resonance.Pt() > 0.1) { + registry.fill(HIST("PP/hIncoherentMass6"), resonance.M()); + } else { + registry.fill(HIST("PP/hCoherentMass6"), resonance.M()); + } + } + if (resonance.M() > 1.02 && resonance.M() < 1.06) { + registry.fill(HIST("PP/hUnlikePt2"), resonance.Pt()); + } + } + } + + } // end of process + +}; // end of struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/exclusivePhiLeptonsTrees.cxx b/PWGUD/Tasks/exclusivePhiLeptonsTrees.cxx new file mode 100644 index 00000000000..e1ef9b8f3b4 --- /dev/null +++ b/PWGUD/Tasks/exclusivePhiLeptonsTrees.cxx @@ -0,0 +1,310 @@ +// 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. +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "iostream" +#include "PWGUD/DataModel/UDTables.h" +#include +#include "TLorentzVector.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGUD/Core/SGSelector.h" +using std::array; +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// \brief Exclusive phi->ee tree producer, for ML applications, DG-based +/// \author Simone Ragoni, Creighton +/// \date 11/11/2024 + +namespace o2::aod +{ +namespace tree +{ +// track tables +DECLARE_SOA_COLUMN(PX1, px1, float); +DECLARE_SOA_COLUMN(PY1, py1, float); +DECLARE_SOA_COLUMN(PZ1, pz1, float); +DECLARE_SOA_COLUMN(PE1, pE1, float); +DECLARE_SOA_COLUMN(PX2, px2, float); +DECLARE_SOA_COLUMN(PY2, py2, float); +DECLARE_SOA_COLUMN(PZ2, pz2, float); +DECLARE_SOA_COLUMN(PE2, pE2, float); +DECLARE_SOA_COLUMN(NCOUNTERPV, nCounterPV, int); +DECLARE_SOA_COLUMN(NELECTRONSTOF, nElectronsTOF, int); +} // namespace tree + +DECLARE_SOA_TABLE(TREE, "AOD", "Tree", tree::PX1, tree::PY1, tree::PZ1, tree::PE1, tree::PX2, tree::PY2, tree::PZ2, tree::PE2, tree::NCOUNTERPV, tree::NELECTRONSTOF); +} // namespace o2::aod + +struct ExclusivePhiLeptonsTrees { + Produces tree; + Configurable gap_Side{"gap", 2, "gap selection"}; + Configurable pid2d_cut{"PID2D", 2., "PID cut in 2D"}; + Configurable pid_cut{"PID", 2., "PID cut in 1D"}; + Configurable electronsInTOF{"eTOF", 2, "electrons in TOF"}; + // defining histograms using histogram registry + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //----------------------------------------------------------------------------------------------------------------------- + void init(o2::framework::InitContext&) + { + registry.add("posx", "Vertex position in x", kTH1F, {{100, -0.5, 0.5}}); + registry.add("posy", "Vertex position in y", kTH1F, {{100, -0.5, 0.5}}); + registry.add("posz", "Vertex position in z", kTH1F, {{1000, -100., 100.}}); + registry.add("hITSCluster", "N_{cluster}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hChi2ITSTrkSegment", "N_{cluster}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hTPCCluster", "N_{cluster}", kTH1F, {{200, -0.5, 199.5}}); + registry.add("hdEdx", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdx2", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdSigmaElectron", "p vs dE/dx sigma electron", kTH2F, {{100, 0.0, 3.0}, {1000, -500.0, 500.0}}); + registry.add("hdSigmaElectron2", "p vs dE/dx sigma electron", kTH2F, {{100, 0.0, 3.0}, {1000, -500.0, 500.0}}); + registry.add("hdSigmaElectron3", "p vs dE/dx sigma electron", kTH2F, {{100, 0.0, 3.0}, {1000, -500.0, 500.0}}); + registry.add("hNsigEvsKa1", "NSigma(t1) vs NSigma (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); + registry.add("hNsigEvsKa2", "NSigma(t1) vs NSigma (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); + registry.add("hMomentum", "p_{#ka};#it{p_{trk}}, GeV/c;", kTH1F, {{100, 0., 3.}}); + registry.add("hEta1", "#eta_{#ka};#it{#eta_{trk}}, GeV/c;", kTH1F, {{100, -2., 2.}}); + registry.add("hPtLikeSignElectron", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("hMassLikeSignElectron", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("hMassPtLikeSignElectron", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{1000, 0., 10.}, {400, 0., 4.}}); + + auto hSelectionCounter = registry.add("hSelectionCounter", "hSelectionCounter;;NEvents", HistType::kTH1I, {{10, 0., 10.}}); + + TString SelectionCuts[9] = {"NoSelection", "GAPcondition", "PVtracks", "Good TPC-ITS track", "TPC/TOF PID track", "End trk loop", "Exactly 2e", "Like-sign ev", "Unlike-sign ev"}; + // now we can set BinLabel in histogram Registry + + for (int i = 0; i < 9; i++) { + hSelectionCounter->GetXaxis()->SetBinLabel(i + 1, SelectionCuts[i].Data()); + } + + // Unlike sign pp + registry.add("ee/hRapidity", "Rapidity;#it{y_{ee}};", kTH1F, {{100, -2., 2.}}); + registry.add("ee/hPtElectronVsElectron", "Pt1 vs Pt2;p_{T};p_{T};", kTH2F, {{100, 0., 3.}, {100, 0., 3.}}); + registry.add("ee/hMassPtUnlikeSignElectron", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("ee/hMassUnlike", "m_{ee} [GeV/#it{c}^{2}]", kTH1F, {{1000, 0., 10.}}); + registry.add("ee/hUnlikePt", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("ee/hCoherentMass", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("ee/hIncoherentMass", "Raw Inv.M;#it{m_{ee}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + } + + using udtracks = soa::Join; + using udtracksfull = soa::Join; + // using UDCollisions = soa::Join; + //__________________________________________________________________________ + // Main process + void process(UDCollisions::iterator const& collision, udtracksfull const& tracks) + { + registry.fill(HIST("hSelectionCounter"), 0); + registry.fill(HIST("posx"), collision.posX()); + registry.fill(HIST("posy"), collision.posY()); + registry.fill(HIST("posz"), collision.posZ()); + TLorentzVector resonance; // lorentz vectors of tracks and the mother + // =================================== + // Task for ee pairs with PID + // Topology: + // - 2 TOF ee + // - 1 TOF e + 1 TPC e + // =================================== + std::vector onlyElectronTracks; + std::vector onlyElectronTracksTOF; + std::vector onlyElectronSigma; + std::vector onlyElectronSigmaTOF; + std::vector rawElectronTracks; + std::vector rawElectronTracksTOF; + + // ------------------------------------------- + // TO BE SAVED: + // - counterPV + // - electronsTOF (0,1,2) = 2 - electronsTPC + // - (px,py,pz,E)1 + // - (px,py,pz,E)2 + int counterPV = 0; + for (auto trk : tracks) { + // ---------------------------------------- + // SELECTIONS: + // - PV track + // - at least 70 TPC clusters + // - at least 6 ITS clusters + // - 0.3 < pT < 0.65 GeV from STARlight + // - DCAxy, DCAz + // - Nsigma^2 < 2^2 + // - |track eta| < 0.8 + if (!trk.isPVContributor()) { + continue; + } + counterPV += 1; + registry.fill(HIST("hSelectionCounter"), 2); + + int NFindable = trk.tpcNClsFindable(); + int NMinusFound = trk.tpcNClsFindableMinusFound(); + int NCluster = NFindable - NMinusFound; + registry.fill(HIST("hTPCCluster"), NCluster); + registry.fill(HIST("hChi2ITSTrkSegment"), trk.itsChi2NCl()); + if (NCluster < 70) { + continue; + } + if (trk.itsNCls() < 6) { + continue; + } + if (trk.pt() < 0.300) { + continue; + } + if (trk.pt() > 0.650) { + continue; + } + if (!(std::abs(trk.dcaZ()) < 2.)) { + continue; + } + double dcaLimit = 0.0105 + 0.035 / pow(trk.pt(), 1.1); + if (!(std::abs(trk.dcaXY()) < dcaLimit)) { + continue; + } + registry.fill(HIST("hSelectionCounter"), 3); + registry.fill(HIST("hITSCluster"), trk.itsNCls()); + + double momentum = TMath::Sqrt(trk.px() * trk.px() + trk.py() * trk.py() + trk.pz() * trk.pz()); + double dEdx = trk.tpcSignal(); + registry.fill(HIST("hdEdx"), momentum, dEdx); + + TLorentzVector electron; + electron.SetXYZM(trk.px(), trk.py(), trk.pz(), o2::constants::physics::MassElectron); + if (fabs(electron.Eta()) > 0.8) { + return; + } + auto nSigmaEl = trk.tpcNSigmaEl(); + auto nSigmaElTOF = trk.tofNSigmaEl(); + + if (trk.hasTOF()) { + registry.fill(HIST("hdSigmaElectron"), momentum, nSigmaElTOF); + } + if (fabs(nSigmaEl) < pid_cut) { + registry.fill(HIST("hdEdx2"), momentum, dEdx); + registry.fill(HIST("hdSigmaElectron2"), momentum, nSigmaEl); + registry.fill(HIST("hMomentum"), momentum); + if (trk.hasTOF() && fabs(nSigmaElTOF) < pid_cut) { + registry.fill(HIST("hdSigmaElectron3"), momentum, nSigmaElTOF); + onlyElectronTracksTOF.push_back(electron); + onlyElectronSigmaTOF.push_back(nSigmaElTOF); + rawElectronTracksTOF.push_back(trk); + } else if (!trk.hasTOF()) { + onlyElectronTracks.push_back(electron); + onlyElectronSigma.push_back(nSigmaEl); + rawElectronTracks.push_back(trk); + } + registry.fill(HIST("hSelectionCounter"), 4); + } + + } // trk loop + + registry.fill(HIST("hSelectionCounter"), 5); + if ((onlyElectronTracksTOF.size() >= electronsInTOF) && (onlyElectronTracks.size() + onlyElectronTracksTOF.size()) == 2) { + registry.fill(HIST("hSelectionCounter"), 6); + + int signSum = -999.; + double sigmaTotal = -999.; + TLorentzVector a, b; + // two electrons in the TPC + if (onlyElectronTracksTOF.size() == 0) { + + registry.fill(HIST("hEta1"), onlyElectronTracks[0].Eta()); + registry.fill(HIST("hEta1"), onlyElectronTracks[1].Eta()); + resonance += onlyElectronTracks[0]; + resonance += onlyElectronTracks[1]; + a += onlyElectronTracks[0]; + b += onlyElectronTracks[1]; + sigmaTotal = 0; + sigmaTotal = onlyElectronSigma[0] * onlyElectronSigma[0] + onlyElectronSigma[1] * onlyElectronSigma[1]; + ; + registry.fill(HIST("hNsigEvsKa1"), onlyElectronSigma[0], onlyElectronSigma[1]); + signSum = rawElectronTracks[0].sign() + rawElectronTracks[1].sign(); + if (signSum == 0) { + registry.fill(HIST("ee/hPtElectronVsElectron"), onlyElectronTracks[0].Pt(), onlyElectronTracks[1].Pt()); + } + + } else if (onlyElectronTracksTOF.size() == 1) { + + registry.fill(HIST("hEta1"), onlyElectronTracks[0].Eta()); + registry.fill(HIST("hEta1"), onlyElectronTracksTOF[0].Eta()); + resonance += onlyElectronTracks[0]; + resonance += onlyElectronTracksTOF[0]; + a += onlyElectronTracks[0]; + b += onlyElectronTracksTOF[0]; + sigmaTotal = 0; + sigmaTotal = onlyElectronSigma[0] * onlyElectronSigma[0] + onlyElectronSigmaTOF[0] * onlyElectronSigmaTOF[0]; + ; + registry.fill(HIST("hNsigEvsKa1"), onlyElectronSigma[0], onlyElectronSigmaTOF[0]); + signSum = rawElectronTracks[0].sign() + rawElectronTracksTOF[0].sign(); + if (signSum == 0) { + registry.fill(HIST("ee/hPtElectronVsElectron"), onlyElectronTracks[0].Pt(), onlyElectronTracksTOF[0].Pt()); + } + + } else if (onlyElectronTracksTOF.size() == 2) { + + registry.fill(HIST("hEta1"), onlyElectronTracksTOF[0].Eta()); + registry.fill(HIST("hEta1"), onlyElectronTracksTOF[1].Eta()); + resonance += onlyElectronTracksTOF[0]; + resonance += onlyElectronTracksTOF[1]; + a += onlyElectronTracksTOF[0]; + b += onlyElectronTracksTOF[1]; + sigmaTotal = 0; + sigmaTotal = onlyElectronSigmaTOF[0] * onlyElectronSigmaTOF[0] + onlyElectronSigmaTOF[1] * onlyElectronSigmaTOF[1]; + ; + registry.fill(HIST("hNsigEvsKa1"), onlyElectronSigmaTOF[0], onlyElectronSigmaTOF[1]); + signSum = rawElectronTracksTOF[0].sign() + rawElectronTracksTOF[1].sign(); + if (signSum == 0) { + registry.fill(HIST("ee/hPtElectronVsElectron"), onlyElectronTracksTOF[0].Pt(), onlyElectronTracksTOF[1].Pt()); + } + } + + if (sigmaTotal > pid2d_cut * pid2d_cut) { + return; + } + if (onlyElectronTracksTOF.size() == 1) { + registry.fill(HIST("hNsigEvsKa2"), onlyElectronSigma[0], onlyElectronSigmaTOF[0]); + } else if (onlyElectronTracksTOF.size() == 2) { + registry.fill(HIST("hNsigEvsKa2"), onlyElectronSigmaTOF[0], onlyElectronSigmaTOF[1]); + } + + if (signSum != 0) { + registry.fill(HIST("hMassPtLikeSignElectron"), resonance.M(), resonance.Pt()); + registry.fill(HIST("hSelectionCounter"), 7); + registry.fill(HIST("hPtLikeSignElectron"), resonance.Pt()); + registry.fill(HIST("hMassLikeSignElectron"), resonance.M()); + } else { + registry.fill(HIST("ee/hMassPtUnlikeSignElectron"), resonance.M(), resonance.Pt()); + registry.fill(HIST("hSelectionCounter"), 8); + registry.fill(HIST("ee/hMassUnlike"), resonance.M()); + registry.fill(HIST("ee/hRapidity"), resonance.Rapidity()); + if (resonance.Pt() > 0.1) { + registry.fill(HIST("ee/hIncoherentMass"), resonance.M()); + } else { + registry.fill(HIST("ee/hCoherentMass"), resonance.M()); + } + if (resonance.M() > 1.01 && resonance.M() < 1.03) { + registry.fill(HIST("ee/hUnlikePt"), resonance.Pt()); + } + } + // Filling tree, make to be consistent with the declared tables + tree(a.Px(), a.Py(), a.Pz(), a.E(), b.Px(), b.Py(), b.Pz(), b.E(), counterPV, onlyElectronTracksTOF.size()); + } + } // end of process + +}; // end of struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/exclusiveRhoTo4Pi.cxx b/PWGUD/Tasks/exclusiveRhoTo4Pi.cxx new file mode 100644 index 00000000000..57509889089 --- /dev/null +++ b/PWGUD/Tasks/exclusiveRhoTo4Pi.cxx @@ -0,0 +1,1738 @@ +// 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 exclusiveRhoTo4Pi.cxx +/// \brief Task for analyzing exclusive rho decays to 4 pions +/// \author Anantha Padmanabhan M Nair + +#include +#include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/UDHelpers.h" +#include "PWGUD/Core/SGTrackSelector.h" +#include "Common/DataModel/PIDResponse.h" +#include +#include "TLorentzVector.h" +#include +#include "Math/Vector4D.h" +#include "Math/Vector3D.h" +#include "Math/GenVector/Boost.h" +#include "CommonConstants/PhysicsConstants.h" +#include "TPDGCode.h" + +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace o2::aod +{ +namespace branch +{ + +// vertex Position +DECLARE_SOA_COLUMN(PosX, posX, double); +DECLARE_SOA_COLUMN(PosY, posY, double); +DECLARE_SOA_COLUMN(PosZ, posZ, double); + +// FIT signals +DECLARE_SOA_COLUMN(Fv0signal, fv0signal, double); +DECLARE_SOA_COLUMN(Ft0asignal, ft0asignal, double); +DECLARE_SOA_COLUMN(Ft0csignal, ft0csignal, double); +DECLARE_SOA_COLUMN(Fddasignal, fddasignal, double); +DECLARE_SOA_COLUMN(Fddcsignal, fddcsignal, double); + +// FIT times +DECLARE_SOA_COLUMN(TimeFv0, timeFv0, double); +DECLARE_SOA_COLUMN(TimeFt0a, timeFt0a, double); +DECLARE_SOA_COLUMN(TimeFt0c, timeFt0c, double); +DECLARE_SOA_COLUMN(TimeFdda, timeFdda, double); +DECLARE_SOA_COLUMN(TimeFddc, timeFddc, double); + +// ZDC times +DECLARE_SOA_COLUMN(TimeZna, timeZna, double); +DECLARE_SOA_COLUMN(TimeZnc, timeZnc, double); + +// DCA +DECLARE_SOA_COLUMN(Dcaxy1, dcaxy1, double); +DECLARE_SOA_COLUMN(Dcaxy2, dcaxy2, double); +DECLARE_SOA_COLUMN(Dcaxy3, dcaxy3, double); +DECLARE_SOA_COLUMN(Dcaxy4, dcaxy4, double); + +DECLARE_SOA_COLUMN(Dcaz1, dcaz1, double); +DECLARE_SOA_COLUMN(Dcaz2, dcaz2, double); +DECLARE_SOA_COLUMN(Dcaz3, dcaz3, double); +DECLARE_SOA_COLUMN(Dcaz4, dcaz4, double); + +// TPC nSigmaPi +DECLARE_SOA_COLUMN(TpcNsigmaPi1, tpcNsigmaPi1, double); +DECLARE_SOA_COLUMN(TpcNsigmaPi2, tpcNsigmaPi2, double); +DECLARE_SOA_COLUMN(TpcNsigmaPi3, tpcNsigmaPi3, double); +DECLARE_SOA_COLUMN(TpcNsigmaPi4, tpcNsigmaPi4, double); + +// TPC nSigmaKa +DECLARE_SOA_COLUMN(TpcNsigmaKa1, tpcNsigmaKa1, double); +DECLARE_SOA_COLUMN(TpcNsigmaKa2, tpcNsigmaKa2, double); +DECLARE_SOA_COLUMN(TpcNsigmaKa3, tpcNsigmaKa3, double); +DECLARE_SOA_COLUMN(TpcNsigmaKa4, tpcNsigmaKa4, double); + +// TPC nSigmaPr +DECLARE_SOA_COLUMN(TpcNsigmaPr1, tpcNsigmaPr1, double); +DECLARE_SOA_COLUMN(TpcNsigmaPr2, tpcNsigmaPr2, double); +DECLARE_SOA_COLUMN(TpcNsigmaPr3, tpcNsigmaPr3, double); +DECLARE_SOA_COLUMN(TpcNsigmaPr4, tpcNsigmaPr4, double); + +// TPC nSigmaEl +DECLARE_SOA_COLUMN(TpcNsigmaEl1, tpcNsigmaEl1, double); +DECLARE_SOA_COLUMN(TpcNsigmaEl2, tpcNsigmaEl2, double); +DECLARE_SOA_COLUMN(TpcNsigmaEl3, tpcNsigmaEl3, double); +DECLARE_SOA_COLUMN(TpcNsigmaEl4, tpcNsigmaEl4, double); + +// TPC nSigmaMu +DECLARE_SOA_COLUMN(TpcNsigmaMu1, tpcNsigmaMu1, double); +DECLARE_SOA_COLUMN(TpcNsigmaMu2, tpcNsigmaMu2, double); +DECLARE_SOA_COLUMN(TpcNsigmaMu3, tpcNsigmaMu3, double); +DECLARE_SOA_COLUMN(TpcNsigmaMu4, tpcNsigmaMu4, double); + +// TPC Chi2 +DECLARE_SOA_COLUMN(TpcChi21, tpcChi21, double); +DECLARE_SOA_COLUMN(TpcChi22, tpcChi22, double); +DECLARE_SOA_COLUMN(TpcChi23, tpcChi23, double); +DECLARE_SOA_COLUMN(TpcChi24, tpcChi24, double); + +// TPC NClsFindable +DECLARE_SOA_COLUMN(TpcNClsFindable1, tpcNClsFindable1, double); +DECLARE_SOA_COLUMN(TpcNClsFindable2, tpcNClsFindable2, double); +DECLARE_SOA_COLUMN(TpcNClsFindable3, tpcNClsFindable3, double); +DECLARE_SOA_COLUMN(TpcNClsFindable4, tpcNClsFindable4, double); + +// ITS Chi2 +DECLARE_SOA_COLUMN(ItsChi21, itsChi21, double); +DECLARE_SOA_COLUMN(ItsChi22, itsChi22, double); +DECLARE_SOA_COLUMN(ItsChi23, itsChi23, double); +DECLARE_SOA_COLUMN(ItsChi24, itsChi24, double); + +// PionPt +DECLARE_SOA_COLUMN(PionPt1, pionPt1, double); +DECLARE_SOA_COLUMN(PionPt2, pionPt2, double); +DECLARE_SOA_COLUMN(PionPt3, pionPt3, double); +DECLARE_SOA_COLUMN(PionPt4, pionPt4, double); + +// Pion Eta +DECLARE_SOA_COLUMN(PionEta1, pionEta1, double); +DECLARE_SOA_COLUMN(PionEta2, pionEta2, double); +DECLARE_SOA_COLUMN(PionEta3, pionEta3, double); +DECLARE_SOA_COLUMN(PionEta4, pionEta4, double); + +// Pion Phi +DECLARE_SOA_COLUMN(PionPhi1, pionPhi1, double); +DECLARE_SOA_COLUMN(PionPhi2, pionPhi2, double); +DECLARE_SOA_COLUMN(PionPhi3, pionPhi3, double); +DECLARE_SOA_COLUMN(PionPhi4, pionPhi4, double); + +// Pion Rapidity +DECLARE_SOA_COLUMN(PionRapidity1, pionRapidity1, double); +DECLARE_SOA_COLUMN(PionRapidity2, pionRapidity2, double); +DECLARE_SOA_COLUMN(PionRapidity3, pionRapidity3, double); +DECLARE_SOA_COLUMN(PionRapidity4, pionRapidity4, double); + +DECLARE_SOA_COLUMN(FourPionPt, fourPionPt, double); +DECLARE_SOA_COLUMN(FourPionEta, fourPionEta, double); +DECLARE_SOA_COLUMN(FourPionPhi, fourPionPhi, double); +DECLARE_SOA_COLUMN(FourPionRapidity, fourPionRapidity, double); + +DECLARE_SOA_COLUMN(FourPionMass, fourPionMass, double); +DECLARE_SOA_COLUMN(FourPionPhiPair1, fourPionPhiPair1, double); +DECLARE_SOA_COLUMN(FourPionPhiPair2, fourPionPhiPair2, double); +DECLARE_SOA_COLUMN(FourPionCosThetaPair1, fourPionCosThetaPair1, double); +DECLARE_SOA_COLUMN(FourPionCosThetaPair2, fourPionCosThetaPair2, double); +} // namespace branch + +DECLARE_SOA_TABLE(SignalData, "AOD", "signalData", + branch::PosX, + branch::PosY, + branch::PosZ, + + branch::Fv0signal, + branch::Ft0asignal, + branch::Ft0csignal, + branch::Fddasignal, + branch::Fddcsignal, + + branch::TimeFv0, + branch::TimeFt0a, + branch::TimeFt0c, + branch::TimeFdda, + branch::TimeFddc, + branch::TimeZna, + branch::TimeZnc, + + branch::Dcaxy1, + branch::Dcaxy2, + branch::Dcaxy3, + branch::Dcaxy4, + + branch::Dcaz1, + branch::Dcaz2, + branch::Dcaz3, + branch::Dcaz4, + + branch::TpcNsigmaPi1, + branch::TpcNsigmaPi2, + branch::TpcNsigmaPi3, + branch::TpcNsigmaPi4, + + branch::TpcNsigmaKa1, + branch::TpcNsigmaKa2, + branch::TpcNsigmaKa3, + branch::TpcNsigmaKa4, + + branch::TpcNsigmaPr1, + branch::TpcNsigmaPr2, + branch::TpcNsigmaPr3, + branch::TpcNsigmaPr4, + + branch::TpcNsigmaEl1, + branch::TpcNsigmaEl2, + branch::TpcNsigmaEl3, + branch::TpcNsigmaEl4, + + branch::TpcNsigmaMu1, + branch::TpcNsigmaMu2, + branch::TpcNsigmaMu3, + branch::TpcNsigmaMu4, + + branch::TpcChi21, + branch::TpcChi22, + branch::TpcChi23, + branch::TpcChi24, + + branch::TpcNClsFindable1, + branch::TpcNClsFindable2, + branch::TpcNClsFindable3, + branch::TpcNClsFindable4, + + branch::ItsChi21, + branch::ItsChi22, + branch::ItsChi23, + branch::ItsChi24, + + branch::PionPt1, + branch::PionPt2, + branch::PionPt3, + branch::PionPt4, + + branch::PionEta1, + branch::PionEta2, + branch::PionEta3, + branch::PionEta4, + + branch::PionPhi1, + branch::PionPhi2, + branch::PionPhi3, + branch::PionPhi4, + + branch::PionRapidity1, + branch::PionRapidity2, + branch::PionRapidity3, + branch::PionRapidity4, + + branch::FourPionPt, + branch::FourPionEta, + branch::FourPionPhi, + branch::FourPionRapidity, + branch::FourPionMass, + branch::FourPionPhiPair1, + branch::FourPionPhiPair2, + branch::FourPionCosThetaPair1, + branch::FourPionCosThetaPair2); + +DECLARE_SOA_TABLE(BkgroundData, "AOD", "bkgroundData", + + branch::PosX, + branch::PosY, + branch::PosZ, + + branch::Fv0signal, + branch::Ft0asignal, + branch::Ft0csignal, + branch::Fddasignal, + branch::Fddcsignal, + + branch::TimeFv0, + branch::TimeFt0a, + branch::TimeFt0c, + branch::TimeFdda, + branch::TimeFddc, + branch::TimeZna, + branch::TimeZnc, + + branch::Dcaxy1, + branch::Dcaxy2, + branch::Dcaxy3, + branch::Dcaxy4, + + branch::Dcaz1, + branch::Dcaz2, + branch::Dcaz3, + branch::Dcaz4, + + branch::TpcNsigmaPi1, + branch::TpcNsigmaPi2, + branch::TpcNsigmaPi3, + branch::TpcNsigmaPi4, + + branch::TpcNsigmaKa1, + branch::TpcNsigmaKa2, + branch::TpcNsigmaKa3, + branch::TpcNsigmaKa4, + + branch::TpcNsigmaPr1, + branch::TpcNsigmaPr2, + branch::TpcNsigmaPr3, + branch::TpcNsigmaPr4, + + branch::TpcNsigmaEl1, + branch::TpcNsigmaEl2, + branch::TpcNsigmaEl3, + branch::TpcNsigmaEl4, + + branch::TpcNsigmaMu1, + branch::TpcNsigmaMu2, + branch::TpcNsigmaMu3, + branch::TpcNsigmaMu4, + + branch::TpcChi21, + branch::TpcChi22, + branch::TpcChi23, + branch::TpcChi24, + + branch::TpcNClsFindable1, + branch::TpcNClsFindable2, + branch::TpcNClsFindable3, + branch::TpcNClsFindable4, + + branch::ItsChi21, + branch::ItsChi22, + branch::ItsChi23, + branch::ItsChi24, + + branch::PionPt1, + branch::PionPt2, + branch::PionPt3, + branch::PionPt4, + + branch::PionEta1, + branch::PionEta2, + branch::PionEta3, + branch::PionEta4, + + branch::PionPhi1, + branch::PionPhi2, + branch::PionPhi3, + branch::PionPhi4, + + branch::PionRapidity1, + branch::PionRapidity2, + branch::PionRapidity3, + branch::PionRapidity4, + + branch::FourPionPt, + branch::FourPionEta, + branch::FourPionPhi, + branch::FourPionRapidity, + branch::FourPionMass); + +DECLARE_SOA_TABLE(MCgen, "AOD", "MCgen", + branch::PionPt1, + branch::PionPt2, + branch::PionPt3, + branch::PionPt4, + + branch::PionEta1, + branch::PionEta2, + branch::PionEta3, + branch::PionEta4, + + branch::PionPhi1, + branch::PionPhi2, + branch::PionPhi3, + branch::PionPhi4, + + branch::PionRapidity1, + branch::PionRapidity2, + branch::PionRapidity3, + branch::PionRapidity4, + + branch::FourPionPt, + branch::FourPionEta, + branch::FourPionPhi, + branch::FourPionRapidity, + branch::FourPionMass, + branch::FourPionPhiPair1, + branch::FourPionPhiPair2, + branch::FourPionCosThetaPair1, + branch::FourPionCosThetaPair2); + +DECLARE_SOA_TABLE(SignalMCreco, "AOD", "SignalMCreco", + branch::PosX, + branch::PosY, + branch::PosZ, + + branch::Fv0signal, + branch::Ft0asignal, + branch::Ft0csignal, + branch::Fddasignal, + branch::Fddcsignal, + + branch::TimeFv0, + branch::TimeFt0a, + branch::TimeFt0c, + branch::TimeFdda, + branch::TimeFddc, + branch::TimeZna, + branch::TimeZnc, + + branch::Dcaxy1, + branch::Dcaxy2, + branch::Dcaxy3, + branch::Dcaxy4, + + branch::Dcaz1, + branch::Dcaz2, + branch::Dcaz3, + branch::Dcaz4, + + branch::TpcNsigmaPi1, + branch::TpcNsigmaPi2, + branch::TpcNsigmaPi3, + branch::TpcNsigmaPi4, + + branch::TpcNsigmaKa1, + branch::TpcNsigmaKa2, + branch::TpcNsigmaKa3, + branch::TpcNsigmaKa4, + + branch::TpcNsigmaPr1, + branch::TpcNsigmaPr2, + branch::TpcNsigmaPr3, + branch::TpcNsigmaPr4, + + branch::TpcNsigmaEl1, + branch::TpcNsigmaEl2, + branch::TpcNsigmaEl3, + branch::TpcNsigmaEl4, + + branch::TpcNsigmaMu1, + branch::TpcNsigmaMu2, + branch::TpcNsigmaMu3, + branch::TpcNsigmaMu4, + + branch::TpcChi21, + branch::TpcChi22, + branch::TpcChi23, + branch::TpcChi24, + + branch::TpcNClsFindable1, + branch::TpcNClsFindable2, + branch::TpcNClsFindable3, + branch::TpcNClsFindable4, + + branch::ItsChi21, + branch::ItsChi22, + branch::ItsChi23, + branch::ItsChi24, + + branch::PionPt1, + branch::PionPt2, + branch::PionPt3, + branch::PionPt4, + + branch::PionEta1, + branch::PionEta2, + branch::PionEta3, + branch::PionEta4, + + branch::PionPhi1, + branch::PionPhi2, + branch::PionPhi3, + branch::PionPhi4, + + branch::PionRapidity1, + branch::PionRapidity2, + branch::PionRapidity3, + branch::PionRapidity4, + + branch::FourPionPt, + branch::FourPionEta, + branch::FourPionPhi, + branch::FourPionRapidity, + branch::FourPionMass, + branch::FourPionPhiPair1, + branch::FourPionPhiPair2, + branch::FourPionCosThetaPair1, + branch::FourPionCosThetaPair2); +} // namespace o2::aod + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +struct ExclusiveRhoTo4Pi { + SGSelector sgSelector; + int rhoPrime = 30113; + uint16_t numPVContrib = 4; + Produces sigFromData; + Produces bkgFromData; + Produces generatedMC; + Produces sigFromMC; + + HistogramRegistry histosData{"histosData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry histosMCgen{"histosMCgen", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry histosMCreco{"histosMCreco", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry histosFastData{"histosFastData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry histosFastMCreco{"histosFastMCreco", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Configurable fv0Cut{"fv0Cut", 50., "FV0A threshold"}; + Configurable ft0aCut{"ft0aCut", 150., "FT0A threshold"}; + Configurable ft0cCut{"ft0cCut", 50., "FT0C threshold"}; + Configurable zdcCut{"zdcCut", 1., "ZDC threshold"}; + + Configurable pvCut{"pvCut", 1.0, "Use Only PV tracks"}; + Configurable dcaZcut{"dcaZcut", 2, "dcaZ cut"}; + Configurable dcaXYcut{"dcaXYcut", 0, "dcaXY cut"}; + Configurable tpcChi2Cut{"tpcChi2Cut", 4, "Max tpcChi2NCl"}; + Configurable tpcNClsFindableCut{"tpcNClsFindableCut", 70, "Min tpcNClsFindable"}; + Configurable itsChi2Cut{"itsChi2Cut", 36, "Max itsChi2NCl"}; + Configurable etaCut{"etaCut", 0.9, "Track Pseudorapidity"}; + Configurable pTcut{"pTcut", 0.15, "Track Pt"}; + + Configurable nSigmaTPCcut{"nSigmaTPCcut", 3, "TPC cut"}; + Configurable nSigmaTOFcut{"nSigmaTOFcut", 3, "TOF cut"}; + + Configurable nBinsPt{"nBinsPt", 1000, "Number of bins for pT"}; + Configurable nBinsInvariantMass{"nBinsInvariantMass", 1000, "Number of bins for Invariant Mass"}; + Configurable invariantMassMin{"invariantMassMin", 0.8, "Minimum Invariant Mass"}; + Configurable invariantMassMax{"invariantMassMax", 2.5, "Maximum Invariant Mass"}; + Configurable nBinsRapidity{"nBinsRapidity", 1000, "Number of bins for Rapidity"}; + Configurable nBinsPhi{"nBinsPhi", 360, "Number of bins for Phi"}; + Configurable nBinsCosTheta{"nBinsCosTheta", 360, "Number of bins for cos Theta"}; + //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + // Begin of Init Function----------------------------------------------------------------------------------------------------------------------------------------------------- + void init(InitContext const&) + { + + histosData.add("GapSide", "Gap Side; Events", kTH1F, {{4, -1.5, 2.5}}); + histosData.add("TrueGapSide", "Gap Side; Events", kTH1F, {{4, -1.5, 2.5}}); + histosData.add("EventCounts", "Total Events; Events", kTH1F, {{10, 0, 10}}); + + histosData.add("vertexZ", "Vertex Z; Vertex Z [cm]; Counts", kTH1F, {{1000, -20, 20}}); + histosData.add("dcaXY", "dcaXY; dcaXY [cm]; Counts", kTH1F, {{10000, -5, 5}}); + histosData.add("dcaZ", "dcaZ; dcaZ [cm]; Counts", kTH1F, {{10000, -10, 10}}); + histosData.add("tpcChi2NCl", "TPC Chi2/NCl; Chi2/NCl; Counts", kTH1F, {{200, 0, 200}}); + histosData.add("itsChi2NCl", "ITS Chi2/NCl; Chi2/NCl; Counts", kTH1F, {{200, 0, 200}}); + histosData.add("tpcNClsFindable", "TPC N Cls Findable; N Cls Findable; Counts", kTH1F, {{200, 0, 200}}); + + // TPC nSigma + histosData.add("tpcNSigmaPi_WOTS", "TPC nSigma Pion without track selection; Events", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosData.add("tpcNSigmaPi_WTS", "TPC nSigma Pion with track selection; Events", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosData.add("tpcNSigmaPi_WTS_PID_Pi", "TPC nSigma Pion with track selection and PID Selection of Pi; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + + // TPC nSigma of other particles with selected pion tracks + histosData.add("tpcNSigmaKa_WTS_PID_Pi", "TPC nSigma Kaon with track selection and PID Selection of Pion; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosData.add("tpcNSigmaPr_WTS_PID_Pi", "TPC nSigma Proton with track selection and PID Selection of Pion; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosData.add("tpcNSigmaEl_WTS_PID_Pi", "TPC nSigma Electron with track selection and PID Selection of Pion; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosData.add("tpcNSigmaMu_WTS_PID_Pi", "TPC nSigma Muon with track selection and PID Selection of Pion; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + + // TOF nSigma + histosData.add("tofNSigmaPi_WTS", "TOF nSigma Pion with track selection; Events", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosData.add("tofNSigmaPi_WOTS", "TOF nSigma Pion without track selection; Events", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosData.add("tofNSigmaPi_WTS_PID_Pi", "TOF nSigma Pion with track selection and PID Selection of Pi; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + + // TOF nSigma of other particles with selected pion tracks + histosData.add("tofNSigmaKa_WTS_PID_Pi", "TOF nSigma Kaon with track selection and PID Selection of Pion; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosData.add("tofNSigmaPr_WTS_PID_Pi", "TOF nSigma Proton with track selection and PID Selection of Pion; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosData.add("tofNSigmaEl_WTS_PID_Pi", "TOF nSigma Electron with track selection and PID Selection of Pion; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosData.add("tofNSigmaMu_WTS_PID_Pi", "TOF nSigma Muon with track selection and PID Selection of Pion; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + + // Track Transverse Momentum + histosData.add("pT_track_WOTS", "pT without track selection; pT [GeV/c]; Counts", kTH1F, {{nBinsPt, 0, 2}}); + histosData.add("pT_track_WTS", "pT with track selection; pT [GeV/c]; Counts", kTH1F, {{nBinsPt, 0, 2}}); + histosData.add("pT_track_WTS_PID_Pi", "pT with track selection and PID selection of Pi; pT [GeV/c]; Events", kTH1F, {{nBinsPt, 0, 2}}); + histosData.add("pT_track_WTS_PID_Pi_contributed", "pT with track selection and PID selection of Pi which are contributed to selected event; pT [GeV/c]; Events", kTH1F, {{nBinsPt, 0, 2}}); + + // Track Rapidity + histosData.add("rapidity_track_WOTS", "Rapidity without track selection; y; Counts", kTH1F, {{nBinsRapidity, -2.5, 2.5}}); + histosData.add("rapidity_track_WTS", "Rapidity with track selection; y; Counts", kTH1F, {{nBinsRapidity, -2.5, 2.5}}); + histosData.add("rapidity_track_WTS_PID_Pi", "Rapidity with track selection and PID selection of Pi; y; Events", kTH1F, {{nBinsRapidity, -2.5, 2.5}}); + histosData.add("rapidity_track_WTS_PID_Pi_contributed", "Rapidity with track selection and PID selection of Pi which are contributed to selected event; y; Events", kTH1F, {{nBinsRapidity, -2.5, 2.5}}); + + // Zero charge Event Transverse Momentum + histosData.add("pT_event_0charge_WTS_PID_Pi", "Event pT in 0 Charge Events With Track Selection and PID Selection of Pi; pT [GeV/c]; Events", kTH1F, {{nBinsPt, 0, 2}}); + + // Non Zero charge Event Transverse Momentum + histosData.add("pT_event_non0charge_WTS_PID_Pi", "Event pT in Non 0 Charge Events With Track Selection and PID Selection of Pi; pT [GeV/c]; Events", kTH1F, {{nBinsPt, 0, 2}}); + + // Rapidity of 0 charge Events + histosData.add("rapidity_event_0charge_WTS_PID_Pi_domainA", "Rapidity of Events With Track Selection and PID Selection of Pi for p_{T} < 0.15 GeV/c; y; Events", kTH1F, {{1000, -2.5, 2.5}}); + histosData.add("rapidity_event_0charge_WTS_PID_Pi_domainB", "Rapidity of Events With Track Selection and PID Selection of Pi for 0.15< p_{T} < 0.80 GeV/c; y; Events", kTH1F, {{1000, -2.5, 2.5}}); + histosData.add("rapidity_event_0charge_WTS_PID_Pi_domainC", "Rapidity of Events With Track Selection and PID Selection of Pi for p_{T} > 0.80 GeV/c; y; Events", kTH1F, {{1000, -2.5, 2.5}}); + + // Rapidity of non 0 charge Events + histosData.add("rapidity_event_non0charge_WTS_PID_Pi_domainA", "Rapidity of Events With Track Selection and PID Selection of Pi for p_{T} < 0.15 GeV/c; y; Events", kTH1F, {{nBinsRapidity, -2.5, 2.5}}); + histosData.add("rapidity_event_non0charge_WTS_PID_Pi_domainB", "Rapidity of Events With Track Selection and PID Selection of Pi for 0.15< p_{T} < 0.80 GeV/c$; y; Events", kTH1F, {{nBinsRapidity, -2.5, 2.5}}); + histosData.add("rapidity_event_non0charge_WTS_PID_Pi_domainC", "Rapidity of Events With Track Selection and PID Selection of Pi for p_{T} > 0.80 GeV/c; y; Events", kTH1F, {{nBinsRapidity, -2.5, 2.5}}); + + // Pair Invariant Mass + histosData.add("invMass_pair_1", "Invariant Mass Distribution of 2 pions 1 ; m(#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{5000, 0, 5}}); + histosData.add("invMass_pair_2", "Invariant Mass Distribution of 2 pions 2 ; m(#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{5000, 0, 5}}); + histosData.add("invMass_pair_3", "Invariant Mass Distribution of 2 pions 3 ; m(#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{5000, 0, 5}}); + histosData.add("invMass_pair_4", "Invariant Mass Distribution of 2 pions 4 ; m(#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{5000, 0, 5}}); + + // Invariant Mass of 0 charge events + histosData.add("invMass_event_0charge_WTS_PID_Pi_domainA", "Invariant Mass Distribution of 0 charge Events with PID Selection of Pi for p_{T} < 0.15 GeV/c; m(#pi^{+}#pi^{-}#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{nBinsInvariantMass, invariantMassMin, invariantMassMax}}); // pT < 0.15GeV + histosData.add("invMass_event_0charge_WTS_PID_Pi_domainB", "Invariant Mass Distribution of 0 charge Events with PID Selection of Pi for 0.15< p_{T} < 0.80 GeV/c; m(#pi^{+}#pi^{-}#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{nBinsInvariantMass, invariantMassMin, invariantMassMax}}); // 0.15GeV < pT < 0.8GeV + histosData.add("invMass_event_0charge_WTS_PID_Pi_domainC", "Invariant Mass Distribution of 0 charge Events with PID Selection of Pi for p_{T} > 0.80 GeV/c; m(#pi^{+}#pi^{-}#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{nBinsInvariantMass, invariantMassMin, invariantMassMax}}); // 0.8GeV < pT + + // Invariant mass of non 0 charge events + histosData.add("invMass_event_non0charge_WTS_PID_Pi_domainA", "Invariant Mass Distribution of non 0 charge Events with PID Selection of Pi for p_{T} < 0.15 GeV/c; m(#pi^{+}#pi^{-}#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{nBinsInvariantMass, invariantMassMin, invariantMassMax}}); // pT < 0.15GeV + histosData.add("invMass_event_non0charge_WTS_PID_Pi_domainB", "Invariant Mass Distribution of non 0 charge Events with PID Selection of Pi for 0.15< p_{T} < 0.80 GeV/c; m(#pi^{+}#pi^{-}#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{nBinsInvariantMass, invariantMassMin, invariantMassMax}}); // 0.15GeV < pT < 0.8GeV + histosData.add("invMass_event_non0charge_WTS_PID_Pi_domainC", "Invariant Mass Distribution of non 0 charge Events with PID Selection of Pi for p_{T} > 0.80 GeV/c; m(#pi^{+}#pi^{-}#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{nBinsInvariantMass, invariantMassMin, invariantMassMax}}); // 0.8GeV < pT + + // tpc signal + histosData.add("tpcSignal", "TPC dEdx vs p; p [GeV/c]; dEdx [a.u.]", kTH2F, {{500, 0, 10}, {5000, 0.0, 5000.0}}); + histosData.add("tpcSignal_Pi", "TPC dEdx vs p for pions; p [GeV/c]; dEdx [a.u.]", kTH2F, {{500, 0, 10}, {5000, 0.0, 5000.0}}); + + // tof beta + histosData.add("tofBeta", "TOF beta vs p; p [GeV/c]; #beta", kTH2F, {{500, 0, 10}, {500, 0.0, 1.0}}); + histosData.add("tofBeta_Pi", "TOF beta vs p for pions; p [GeV/c]; #beta", kTH2F, {{500, 0, 10}, {500, 0.0, 1.0}}); + + // Other signals + histosData.add("FT0A", "T0A amplitude", kTH1F, {{2000, 0.0, 500.0}}); + histosData.add("FT0C", "T0C amplitude", kTH1F, {{2000, 0.0, 500.0}}); + histosData.add("ZDC_A", "ZDC amplitude", kTH1F, {{1000, 0.0, 15}}); + histosData.add("ZDC_C", "ZDC amplitude", kTH1F, {{1000, 0.0, 15}}); + histosData.add("V0A", "V0A amplitude", kTH1F, {{1000, 0.0, 100}}); + + // Collin Soper Theta and Phi + histosData.add("CS_phi_pair_1", "#phi Distribution; #phi; Events", kTH1F, {{nBinsPhi, -3.2, 3.2}}); + histosData.add("CS_phi_pair_2", "#phi Distribution; #phi; Events", kTH1F, {{nBinsPhi, -3.2, 3.2}}); + histosData.add("CS_costheta_pair_1", "#theta Distribution;cos(#theta); Counts", kTH1F, {{nBinsCosTheta, -1, 1}}); + histosData.add("CS_costheta_pair_2", "#theta Distribution;cos(#theta); Counts", kTH1F, {{nBinsCosTheta, -1, 1}}); + histosData.add("phi_cosTheta_pair_1", "Phi vs cosTheta; #phi; cos(#theta)", kTH2F, {{nBinsPhi, -3.2, 3.2}, {nBinsCosTheta, -1, 1}}); + histosData.add("phi_cosTheta_pair_2", "Phi vs cosTheta; #phi; cos(#theta)", kTH2F, {{nBinsPhi, -3.2, 3.2}, {nBinsCosTheta, -1, 1}}); + + // MC Gen Stuff + + // counts + histosMCgen.add("rhoPrimeCounts", "Total Rho prime Events; Events", kTH1F, {{10, 0, 10}}); + + // Track Stuff + histosMCgen.add("pion_pT", "Generated pT; pT [GeV/c]; Events", kTH1F, {{nBinsPt, 0, 10}}); + histosMCgen.add("pion_eta", "Generated Pseudorapidity; #eta; Events", kTH1F, {{1000, -2.5, 2.5}}); + histosMCgen.add("pion_rapidity", "Generated Rapidity; y; Events", kTH1F, {{nBinsRapidity, -2.5, 2.5}}); + + // Pair Invariant Mass + histosMCgen.add("twoPion_invMass_pair_1", "Invariant Mass Distribution of 2 pions 1 ; m(#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{5000, 0, 5}}); + histosMCgen.add("twoPion_invMass_pair_2", "Invariant Mass Distribution of 2 pions 2 ; m(#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{5000, 0, 5}}); + histosMCgen.add("twoPion_invMass_pair_3", "Invariant Mass Distribution of 2 pions 3 ; m(#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{5000, 0, 5}}); + histosMCgen.add("twoPion_invMass_pair_4", "Invariant Mass Distribution of 2 pions 4 ; m(#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{5000, 0, 5}}); + + // Generated Transverse Momentum, Rapidty and Invariant Mass + histosMCgen.add("rhoPrime_pT", "Generated pT; pT [GeV/c]; Events", kTH1F, {{nBinsPt, 0, 2}}); + histosMCgen.add("rhoPrime_eta", "Generated pT; pT [GeV/c]; Events", kTH1F, {{nBinsPt, 0, 2}}); + histosMCgen.add("rhoPrime_rapidity", "Generated pT; pT [GeV/c]; Events", kTH1F, {{nBinsPt, 0, 2}}); + histosMCgen.add("rhoPrime_invmass", "Generated pT; pT [GeV/c]; Events", kTH1F, {{nBinsPt, 0, 2}}); + + histosMCgen.add("fourPion_pT", "Generated pT; pT [GeV/c]; Events", kTH1F, {{nBinsPt, 0, 2}}); + histosMCgen.add("fourPion_eta", "Generated Pseudorapidity; #eta; Events", kTH1F, {{1000, -2.5, 2.5}}); + histosMCgen.add("fourPion_rapidity", "Generated Rapidity; y; Events", kTH1F, {{nBinsRapidity, -2.5, 2.5}}); + histosMCgen.add("fourPion_invmass", "Invariant Mass of 4-Pions; m(4-pion); Events", kTH1F, {{nBinsInvariantMass, invariantMassMin, invariantMassMax}}); + + // Collin Soper Theta and Phi + histosMCgen.add("fourPion_phi_pair_1", "#phi Distribution; #phi; Events", kTH1F, {{nBinsPhi, -3.2, 3.2}}); + histosMCgen.add("fourPion_phi_pair_2", "#phi Distribution; #phi; Events", kTH1F, {{nBinsPhi, -3.2, 3.2}}); + histosMCgen.add("fourPion_costheta_pair_1", "#theta Distribution;cos(#theta); Events", kTH1F, {{nBinsCosTheta, -1, 1}}); + histosMCgen.add("fourPion_costheta_pair_2", "#theta Distribution;cos(#theta); Events", kTH1F, {{nBinsCosTheta, -1, 1}}); + histosMCgen.add("phi_cosTheta_pair_1", "Phi vs cosTheta; #phi; cos(#theta)", kTH2F, {{nBinsPhi, -3.2, 3.2}, {nBinsCosTheta, -1, 1}}); + histosMCgen.add("phi_cosTheta_pair_2", "Phi vs cosTheta; #phi; cos(#theta)", kTH2F, {{nBinsPhi, -3.2, 3.2}, {nBinsCosTheta, -1, 1}}); + + // MC Reco Stuff + + histosMCreco.add("vertexZ", "Vertex Z; Vertex Z [cm]; Counts", kTH1F, {{1000, -20, 20}}); + histosMCreco.add("dcaXY", "dcaXY; dcaXY [cm]; Counts", kTH1F, {{10000, -5, 5}}); + histosMCreco.add("dcaZ", "dcaZ; dcaZ [cm]; Counts", kTH1F, {{10000, -10, 10}}); + histosMCreco.add("tpcChi2NCl", "TPC Chi2/NCl; Chi2/NCl; Counts", kTH1F, {{200, 0, 200}}); + histosMCreco.add("itsChi2NCl", "ITS Chi2/NCl; Chi2/NCl; Counts", kTH1F, {{200, 0, 200}}); + histosMCreco.add("tpcNClsFindable", "TPC N Cls Findable; N Cls Findable; Counts", kTH1F, {{200, 0, 200}}); + + histosMCreco.add("GapSide", "Gap Side; Events", kTH1F, {{4, -1.5, 2.5}}); + histosMCreco.add("TrueGapSide", "Gap Side; Events", kTH1F, {{4, -1.5, 2.5}}); + histosMCreco.add("EventCounts", "Total Events; Events", kTH1F, {{10, 0, 10}}); + + // TPC nSigma + histosMCreco.add("tpcNSigmaPi_WOTS", "TPC nSigma Pion without track selection; Events", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosMCreco.add("tpcNSigmaPi_WTS", "TPC nSigma Pion with track selection; Events", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosMCreco.add("tpcNSigmaPi_WTS_PID_Pi", "TPC nSigma Pion with track selection and PID Selection of Pi; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + + // TPC nSigma of other particles with selected pion tracks + histosMCreco.add("tpcNSigmaKa_WTS_PID_Pi", "TPC nSigma Kaon with track selection and PID Selection of Pion; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosMCreco.add("tpcNSigmaPr_WTS_PID_Pi", "TPC nSigma Proton with track selection and PID Selection of Pion; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosMCreco.add("tpcNSigmaEl_WTS_PID_Pi", "TPC nSigma Electron with track selection and PID Selection of Pion; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosMCreco.add("tpcNSigmaMu_WTS_PID_Pi", "TPC nSigma Muon with track selection and PID Selection of Pion; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + + // TOF nSigma + histosMCreco.add("tofNSigmaPi_WTS", "TOF nSigma Pion with track selection; Events", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosMCreco.add("tofNSigmaPi_WOTS", "TOF nSigma Pion without track selection; Events", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosMCreco.add("tofNSigmaPi_WTS_PID_Pi", "TOF nSigma Pion with track selection and PID Selection of Pi; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + + // TOF nSigma of other particles with selected pion tracks + histosMCreco.add("tofNSigmaKa_WTS_PID_Pi", "TOF nSigma Kaon with track selection and PID Selection of Pion; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosMCreco.add("tofNSigmaPr_WTS_PID_Pi", "TOF nSigma Proton with track selection and PID Selection of Pion; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosMCreco.add("tofNSigmaEl_WTS_PID_Pi", "TOF nSigma Electron with track selection and PID Selection of Pion; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + histosMCreco.add("tofNSigmaMu_WTS_PID_Pi", "TOF nSigma Muon with track selection and PID Selection of Pion; Entries", kTH2F, {{1000, -15, 15}, {nBinsPt, 0, 10}}); + + // Track Transverse Momentum + histosMCreco.add("pT_track_WOTS", "pT without track selection; pT [GeV/c]; Counts", kTH1F, {{nBinsPt, 0, 2}}); + histosMCreco.add("pT_track_WTS", "pT with track selection; pT [GeV/c]; Counts", kTH1F, {{nBinsPt, 0, 2}}); + histosMCreco.add("pT_track_WTS_PID_Pi", "pT with track selection and PID selection of Pi; pT [GeV/c]; Events", kTH1F, {{nBinsPt, 0, 2}}); + histosMCreco.add("pT_track_WTS_PID_Pi_contributed", "pT with track selection and PID selection of Pi which are contributed to selected event; pT [GeV/c]; Events", kTH1F, {{nBinsPt, 0, 2}}); + + // Track Rapidity + histosMCreco.add("rapidity_track_WOTS", "Rapidity without track selection; y; Counts", kTH1F, {{nBinsRapidity, -2.5, 2.5}}); + histosMCreco.add("rapidity_track_WTS", "Rapidity with track selection; y; Counts", kTH1F, {{nBinsRapidity, -2.5, 2.5}}); + histosMCreco.add("rapidity_track_WTS_PID_Pi", "Rapidity with track selection and PID selection of Pi; y; Events", kTH1F, {{nBinsRapidity, -2.5, 2.5}}); + histosMCreco.add("rapidity_track_WTS_PID_Pi_contributed", "Rapidity with track selection and PID selection of Pi which are contributed to selected event; y; Events", kTH1F, {{nBinsRapidity, -2.5, 2.5}}); + + // Zero charge Event Transverse Momentum + histosMCreco.add("pT_event_0charge_WTS_PID_Pi", "Event pT in 0 Charge Events With Track Selection and PID Selection of Pi; pT [GeV/c]; Events", kTH1F, {{nBinsPt, 0, 2}}); + + // Non Zero charge Event Transverse Momentum + histosMCreco.add("pT_event_non0charge_WTS_PID_Pi", "Event pT in Non 0 Charge Events With Track Selection and PID Selection of Pi; pT [GeV/c]; Events", kTH1F, {{nBinsPt, 0, 2}}); + + // Rapidity of 0 charge Events + histosMCreco.add("rapidity_event_0charge_WTS_PID_Pi_domainA", "Rapidity of Events With Track Selection and PID Selection of Pi for p_{T} < 0.15 GeV/c; y; Events", kTH1F, {{1000, -2.5, 2.5}}); + histosMCreco.add("rapidity_event_0charge_WTS_PID_Pi_domainB", "Rapidity of Events With Track Selection and PID Selection of Pi for 0.15< p_{T} < 0.80 GeV/c; y; Events", kTH1F, {{1000, -2.5, 2.5}}); + histosMCreco.add("rapidity_event_0charge_WTS_PID_Pi_domainC", "Rapidity of Events With Track Selection and PID Selection of Pi for p_{T} > 0.80 GeV/c; y; Events", kTH1F, {{1000, -2.5, 2.5}}); + + // Rapidity of non 0 charge Events + histosMCreco.add("rapidity_event_non0charge_WTS_PID_Pi_domainA", "Rapidity of Events With Track Selection and PID Selection of Pi for p_{T} < 0.15 GeV/c; y; Events", kTH1F, {{nBinsRapidity, -2.5, 2.5}}); + histosMCreco.add("rapidity_event_non0charge_WTS_PID_Pi_domainB", "Rapidity of Events With Track Selection and PID Selection of Pi for 0.15< p_{T} < 0.80 GeV/c$; y; Events", kTH1F, {{nBinsRapidity, -2.5, 2.5}}); + histosMCreco.add("rapidity_event_non0charge_WTS_PID_Pi_domainC", "Rapidity of Events With Track Selection and PID Selection of Pi for p_{T} > 0.80 GeV/c; y; Events", kTH1F, {{nBinsRapidity, -2.5, 2.5}}); + + // Pair Invariant Mass + histosMCreco.add("invMass_pair_1", "Invariant Mass Distribution of 2 pions 1 ; m(#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{5000, 0, 5}}); + histosMCreco.add("invMass_pair_2", "Invariant Mass Distribution of 2 pions 2 ; m(#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{5000, 0, 5}}); + histosMCreco.add("invMass_pair_3", "Invariant Mass Distribution of 2 pions 3 ; m(#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{5000, 0, 5}}); + histosMCreco.add("invMass_pair_4", "Invariant Mass Distribution of 2 pions 4 ; m(#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{5000, 0, 5}}); + + // Invariant Mass of 0 charge events + histosMCreco.add("invMass_event_0charge_WTS_PID_Pi_domainA", "Invariant Mass Distribution of 0 charge Events with PID Selection of Pi for p_{T} < 0.15 GeV/c; m(#pi^{+}#pi^{-}#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{nBinsInvariantMass, invariantMassMin, invariantMassMax}}); // pT < 0.15GeV + histosMCreco.add("invMass_event_0charge_WTS_PID_Pi_domainB", "Invariant Mass Distribution of 0 charge Events with PID Selection of Pi for 0.15< p_{T} < 0.80 GeV/c; m(#pi^{+}#pi^{-}#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{nBinsInvariantMass, invariantMassMin, invariantMassMax}}); // 0.15GeV < pT < 0.8GeV + histosMCreco.add("invMass_event_0charge_WTS_PID_Pi_domainC", "Invariant Mass Distribution of 0 charge Events with PID Selection of Pi for p_{T} > 0.80 GeV/c; m(#pi^{+}#pi^{-}#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{nBinsInvariantMass, invariantMassMin, invariantMassMax}}); // 0.8GeV < pT + + // Invariant mass of non 0 charge events + histosMCreco.add("invMass_event_non0charge_WTS_PID_Pi_domainA", "Invariant Mass Distribution of non 0 charge Events with PID Selection of Pi for p_{T} < 0.15 GeV/c; m(#pi^{+}#pi^{-}#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{nBinsInvariantMass, invariantMassMin, invariantMassMax}}); // pT < 0.15GeV + histosMCreco.add("invMass_event_non0charge_WTS_PID_Pi_domainB", "Invariant Mass Distribution of non 0 charge Events with PID Selection of Pi for 0.15< p_{T} < 0.80 GeV/c; m(#pi^{+}#pi^{-}#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{nBinsInvariantMass, invariantMassMin, invariantMassMax}}); // 0.15GeV < pT < 0.8GeV + histosMCreco.add("invMass_event_non0charge_WTS_PID_Pi_domainC", "Invariant Mass Distribution of non 0 charge Events with PID Selection of Pi for p_{T} > 0.80 GeV/c; m(#pi^{+}#pi^{-}#pi^{+}#pi^{-}) [GeV/c]", kTH1F, {{nBinsInvariantMass, invariantMassMin, invariantMassMax}}); // 0.8GeV < pT + + // tpc signal + histosMCreco.add("tpcSignal", "TPC dEdx vs p; p [GeV/c]; dEdx [a.u.]", kTH2F, {{500, 0, 10}, {5000, 0.0, 5000.0}}); + histosMCreco.add("tpcSignal_Pi", "TPC dEdx vs p for pions; p [GeV/c]; dEdx [a.u.]", kTH2F, {{500, 0, 10}, {5000, 0.0, 5000.0}}); + + // tof beta + histosMCreco.add("tofBeta", "TOF beta vs p; p [GeV/c]; #beta", kTH2F, {{500, 0, 10}, {500, 0.0, 1.0}}); + histosMCreco.add("tofBeta_Pi", "TOF beta vs p for pions; p [GeV/c]; #beta", kTH2F, {{500, 0, 10}, {500, 0.0, 1.0}}); + + // Other signals + histosMCreco.add("FT0A", "T0A amplitude", kTH1F, {{2000, 0.0, 500.0}}); + histosMCreco.add("FT0C", "T0C amplitude", kTH1F, {{2000, 0.0, 500.0}}); + histosMCreco.add("ZDC_A", "ZDC amplitude", kTH1F, {{1000, 0.0, 15}}); + histosMCreco.add("ZDC_C", "ZDC amplitude", kTH1F, {{1000, 0.0, 15}}); + histosMCreco.add("V0A", "V0A amplitude", kTH1F, {{1000, 0.0, 100}}); + + // Collin Soper Theta and Phi + histosMCreco.add("CS_phi_pair_1", "#phi Distribution; #phi; Events", kTH1F, {{nBinsPhi, -3.2, 3.2}}); + histosMCreco.add("CS_phi_pair_2", "#phi Distribution; #phi; Events", kTH1F, {{nBinsPhi, -3.2, 3.2}}); + histosMCreco.add("CS_costheta_pair_1", "#theta Distribution;cos(#theta); Counts", kTH1F, {{nBinsCosTheta, -1, 1}}); + histosMCreco.add("CS_costheta_pair_2", "#theta Distribution;cos(#theta); Counts", kTH1F, {{nBinsCosTheta, -1, 1}}); + histosMCreco.add("phi_cosTheta_pair_1", "Phi vs cosTheta; #phi; cos(#theta)", kTH2F, {{nBinsPhi, -3.2, 3.2}, {nBinsCosTheta, -1, 1}}); + histosMCreco.add("phi_cosTheta_pair_2", "Phi vs cosTheta; #phi; cos(#theta)", kTH2F, {{nBinsPhi, -3.2, 3.2}, {nBinsCosTheta, -1, 1}}); + + // Fast Data Stuff + histosFastData.add("4PionMassWithCut", "", kTH1F, {{nBinsInvariantMass, invariantMassMin, invariantMassMax}}); + histosFastData.add("4PionMassFull", "", kTH1F, {{nBinsInvariantMass, invariantMassMin, invariantMassMax}}); + histosFastData.add("4PionPt", "", kTH1F, {{nBinsPt, 0, 10}}); + histosFastData.add("4PionRapidity", "", kTH1F, {{nBinsRapidity, -1, 1}}); + + // Fast MC reco Stuff + histosFastMCreco.add("4PionMassWithCut", "", kTH1F, {{nBinsInvariantMass, invariantMassMin, invariantMassMax}}); + histosFastMCreco.add("4PionMassFull", "", kTH1F, {{nBinsInvariantMass, invariantMassMin, invariantMassMax}}); + histosFastMCreco.add("4PionPt", "", kTH1F, {{nBinsPt, 0, 10}}); + histosFastMCreco.add("4PionRapidity", "", kTH1F, {{nBinsRapidity, -1, 1}}); + + } // End of init function + //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + // Calculate the Collins-Soper Frame---------------------------------------------------------------------------------------------------------------------------- + double cosThetaCollinsSoperFrame(ROOT::Math::PtEtaPhiMVector pair1, ROOT::Math::PtEtaPhiMVector pair2, ROOT::Math::PtEtaPhiMVector fourpion) + { + double halfSqrtSnn = 2680.; + double massOfLead208 = 193.6823; + double momentumBeam = std::sqrt(halfSqrtSnn * halfSqrtSnn * 208 * 208 - massOfLead208 * massOfLead208); + + TLorentzVector pProjCM(0., 0., -momentumBeam, halfSqrtSnn * 208); // projectile + TLorentzVector pTargCM(0., 0., momentumBeam, halfSqrtSnn * 208); // target + + // TVector3 beta = (-1. / fourpion.E()) * fourpion.Vect(); + ROOT::Math::PtEtaPhiMVector v1 = pair1; + ROOT::Math::PtEtaPhiMVector v2 = pair2; + ROOT::Math::PtEtaPhiMVector v12 = fourpion; + + // Boost to center of mass frame + ROOT::Math::Boost boostv12{v12.BoostToCM()}; + ROOT::Math::XYZVectorF v1CM{(boostv12(v1).Vect()).Unit()}; + ROOT::Math::XYZVectorF v2CM{(boostv12(v2).Vect()).Unit()}; + ROOT::Math::XYZVectorF beam1CM{(boostv12(pProjCM).Vect()).Unit()}; + ROOT::Math::XYZVectorF beam2CM{(boostv12(pTargCM).Vect()).Unit()}; + + // Axes + ROOT::Math::XYZVectorF zaxisCS{((beam1CM.Unit() - beam2CM.Unit()).Unit())}; + + double cosThetaCS = zaxisCS.Dot((v1CM)); + return cosThetaCS; + } // End of cosThetaCollinsSoperFrame function------------------------------------------------------------------------------------------------------------------------ + + // Calculate Phi in Collins-Soper Frame------------------------------------------------------------------------------------------------------------------------ + double phiCollinsSoperFrame(ROOT::Math::PtEtaPhiMVector pair1, ROOT::Math::PtEtaPhiMVector pair2, ROOT::Math::PtEtaPhiMVector fourpion) + { + // Half of the energy per pair of the colliding nucleons. + double halfSqrtSnn = 2680.; + double massOfLead208 = 193.6823; + double momentumBeam = std::sqrt(halfSqrtSnn * halfSqrtSnn * 208 * 208 - massOfLead208 * massOfLead208); + + TLorentzVector pProjCM(0., 0., -momentumBeam, halfSqrtSnn * 208); // projectile + TLorentzVector pTargCM(0., 0., momentumBeam, halfSqrtSnn * 208); // target + ROOT::Math::PtEtaPhiMVector v1 = pair1; + ROOT::Math::PtEtaPhiMVector v2 = pair2; + ROOT::Math::PtEtaPhiMVector v12 = fourpion; + // Boost to center of mass frame + ROOT::Math::Boost boostv12{v12.BoostToCM()}; + ROOT::Math::XYZVectorF v1CM{(boostv12(v1).Vect()).Unit()}; + ROOT::Math::XYZVectorF v2CM{(boostv12(v2).Vect()).Unit()}; + ROOT::Math::XYZVectorF beam1CM{(boostv12(pProjCM).Vect()).Unit()}; + ROOT::Math::XYZVectorF beam2CM{(boostv12(pTargCM).Vect()).Unit()}; + // Axes + ROOT::Math::XYZVectorF zaxisCS{((beam1CM.Unit() - beam2CM.Unit()).Unit())}; + ROOT::Math::XYZVectorF yaxisCS{(beam1CM.Cross(beam2CM)).Unit()}; + ROOT::Math::XYZVectorF xaxisCS{(yaxisCS.Cross(zaxisCS)).Unit()}; + + double phi = std::atan2(yaxisCS.Dot(v1CM), xaxisCS.Dot(v1CM)); + return phi; + } // End of phiCollinsSoperFrame function------------------------------------------------------------------------------------------------------------------------ + + //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + using UDtracksfull = soa::Join; + using UDCollisionsFull = soa::Join; // + using UDCollisionFull = UDCollisionsFull::iterator; + //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + // Begin of Process function-------------------------------------------------------------------------------------------------------------------------------------------------- + void processData(UDCollisionFull const& collision, UDtracksfull const& tracks) + { + + if (std::abs(collision.posZ()) > 10) { + return; + } + + int gapSide = collision.gapSide(); + std::vector parameters = {pvCut, dcaZcut, dcaXYcut, tpcChi2Cut, tpcNClsFindableCut, itsChi2Cut, etaCut, pTcut}; + int truegapSide = sgSelector.trueGap(collision, fv0Cut, ft0aCut, ft0cCut, zdcCut); + histosData.fill(HIST("GapSide"), gapSide); + histosData.fill(HIST("TrueGapSide"), truegapSide); + histosData.fill(HIST("EventCounts"), 1); + gapSide = truegapSide; + + if ((gapSide != 2)) { + return; + } + + histosData.fill(HIST("vertexZ"), collision.posZ()); + histosData.fill(HIST("V0A"), collision.totalFV0AmplitudeA()); + histosData.fill(HIST("FT0A"), collision.totalFT0AmplitudeA()); + histosData.fill(HIST("FT0C"), collision.totalFT0AmplitudeC()); + histosData.fill(HIST("ZDC_A"), collision.energyCommonZNA()); + histosData.fill(HIST("ZDC_C"), collision.energyCommonZNC()); + + if (collision.numContrib() != 4) { + return; + } + + std::vector WOTS_tracks; + std::vector WTS_tracks; + std::vector WTS_PID_Pi_tracks; + std::vector Pi_plus_tracks; + std::vector Pi_minus_tracks; + + for (const auto& t0 : tracks) { + + WOTS_tracks.push_back(t0); + + if (trackselector(t0, parameters)) { + WTS_tracks.push_back(t0); + + if (selectionPIDPion(t0, true, nSigmaTPCcut, nSigmaTOFcut)) { + WTS_PID_Pi_tracks.push_back(t0); + if (t0.sign() == 1) { + Pi_plus_tracks.push_back(t0); + } + if (t0.sign() == -1) { + Pi_minus_tracks.push_back(t0); + } + } // End of Selection PID Pion + + } // End of track selections + + } // End of loop over tracks + + int numTracksWOTS = static_cast(WOTS_tracks.size()); + int numTracksWTS = static_cast(WTS_tracks.size()); + int numTracksWTSandPIDpi = static_cast(WTS_PID_Pi_tracks.size()); + int numPiPlusTracks = static_cast(Pi_plus_tracks.size()); + int numPionMinusTRacks = static_cast(Pi_minus_tracks.size()); + + TLorentzVector tempWOTS; + for (int i = 0; i < numTracksWOTS; i++) { + tempWOTS.SetXYZM(WOTS_tracks[i].px(), WOTS_tracks[i].py(), WOTS_tracks[i].pz(), o2::constants::physics::MassPionCharged); + histosData.fill(HIST("tpcNSigmaPi_WOTS"), WOTS_tracks[i].tpcNSigmaPi(), std::sqrt(WOTS_tracks[i].px() * WOTS_tracks[i].px() + WOTS_tracks[i].py() * WOTS_tracks[i].py())); + histosData.fill(HIST("tofNSigmaPi_WOTS"), WOTS_tracks[i].tofNSigmaPi(), std::sqrt(WOTS_tracks[i].px() * WOTS_tracks[i].px() + WOTS_tracks[i].py() * WOTS_tracks[i].py())); + histosData.fill(HIST("pT_track_WOTS"), std::sqrt(WOTS_tracks[i].px() * WOTS_tracks[i].px() + WOTS_tracks[i].py() * WOTS_tracks[i].py())); + histosData.fill(HIST("rapidity_track_WOTS"), tempWOTS.Rapidity()); + } // End of loop over tracks without selection + + TLorentzVector tempWTS; + for (int i = 0; i < numTracksWTS; i++) { + tempWTS.SetXYZM(WTS_tracks[i].px(), WTS_tracks[i].py(), WTS_tracks[i].pz(), o2::constants::physics::MassPionCharged); + histosData.fill(HIST("tpcSignal"), std::sqrt(WTS_tracks[i].px() * WTS_tracks[i].px() + WTS_tracks[i].py() * WTS_tracks[i].py() + WTS_tracks[i].pz() * WTS_tracks[i].pz()), WTS_tracks[i].tpcSignal()); + histosData.fill(HIST("tofBeta"), std::sqrt(WTS_tracks[i].px() * WTS_tracks[i].px() + WTS_tracks[i].py() * WTS_tracks[i].py() + WTS_tracks[i].pz() * WTS_tracks[i].pz()), WTS_tracks[i].beta()); + histosData.fill(HIST("tpcNSigmaPi_WTS"), WTS_tracks[i].tpcNSigmaPi(), std::sqrt(WTS_tracks[i].px() * WTS_tracks[i].px() + WTS_tracks[i].py() * WTS_tracks[i].py())); + histosData.fill(HIST("tofNSigmaPi_WTS"), WTS_tracks[i].tofNSigmaPi(), std::sqrt(WTS_tracks[i].px() * WTS_tracks[i].px() + WTS_tracks[i].py() * WTS_tracks[i].py())); + histosData.fill(HIST("pT_track_WTS"), std::sqrt(WTS_tracks[i].px() * WTS_tracks[i].px() + WTS_tracks[i].py() * WTS_tracks[i].py())); + histosData.fill(HIST("rapidity_track_WTS"), tempWTS.Rapidity()); + + histosData.fill(HIST("itsChi2NCl"), WTS_tracks[i].itsChi2NCl()); + histosData.fill(HIST("tpcChi2NCl"), WTS_tracks[i].tpcChi2NCl()); + histosData.fill(HIST("tpcNClsFindable"), WTS_tracks[i].tpcNClsFindable()); + histosData.fill(HIST("dcaXY"), WTS_tracks[i].dcaXY()); + histosData.fill(HIST("dcaZ"), WTS_tracks[i].dcaZ()); + + } // End of loop over tracks with selection only + + TLorentzVector tempWTSPIDPi; + for (int i = 0; i < numTracksWTSandPIDpi; i++) { + + tempWTSPIDPi.SetXYZM(WTS_PID_Pi_tracks[i].px(), WTS_PID_Pi_tracks[i].py(), WTS_PID_Pi_tracks[i].pz(), o2::constants::physics::MassPionCharged); + + histosData.fill(HIST("tpcSignal_Pi"), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py() + WTS_PID_Pi_tracks[i].pz() * WTS_PID_Pi_tracks[i].pz()), WTS_PID_Pi_tracks[i].tpcSignal()); + histosData.fill(HIST("tofBeta_Pi"), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py() + WTS_PID_Pi_tracks[i].pz() * WTS_PID_Pi_tracks[i].pz()), WTS_PID_Pi_tracks[i].beta()); + + histosData.fill(HIST("tpcNSigmaPi_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tpcNSigmaPi(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosData.fill(HIST("tpcNSigmaKa_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tpcNSigmaKa(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosData.fill(HIST("tpcNSigmaPr_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tpcNSigmaPr(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosData.fill(HIST("tpcNSigmaEl_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tpcNSigmaEl(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosData.fill(HIST("tpcNSigmaMu_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tpcNSigmaMu(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + + histosData.fill(HIST("tofNSigmaPi_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tofNSigmaPi(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosData.fill(HIST("tofNSigmaKa_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tofNSigmaKa(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosData.fill(HIST("tofNSigmaPr_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tofNSigmaPr(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosData.fill(HIST("tofNSigmaEl_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tofNSigmaEl(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosData.fill(HIST("tofNSigmaMu_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tofNSigmaMu(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + + histosData.fill(HIST("pT_track_WTS_PID_Pi"), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosData.fill(HIST("rapidity_track_WTS_PID_Pi"), tempWTSPIDPi.Rapidity()); + } // End of loop over tracks with selection and PID selection of Pions + + if (numTracksWTSandPIDpi != 4) { + return; + } + + // Selecting Events with net charge = 0 + if (numPionMinusTRacks == 2 && numPiPlusTracks == 2) { + + TLorentzVector p1, p2, p3, p4, p1234; + ROOT::Math::PtEtaPhiMVector k1, k2, k3, k4, k1234, k13, k14, k23, k24; + + p1.SetXYZM(Pi_plus_tracks[0].px(), Pi_plus_tracks[0].py(), Pi_plus_tracks[0].pz(), o2::constants::physics::MassPionCharged); + p2.SetXYZM(Pi_plus_tracks[1].px(), Pi_plus_tracks[1].py(), Pi_plus_tracks[1].pz(), o2::constants::physics::MassPionCharged); + p3.SetXYZM(Pi_minus_tracks[0].px(), Pi_minus_tracks[0].py(), Pi_minus_tracks[0].pz(), o2::constants::physics::MassPionCharged); + p4.SetXYZM(Pi_minus_tracks[1].px(), Pi_minus_tracks[1].py(), Pi_minus_tracks[1].pz(), o2::constants::physics::MassPionCharged); + + histosData.fill(HIST("pT_track_WTS_PID_Pi_contributed"), p1.Pt()); + histosData.fill(HIST("pT_track_WTS_PID_Pi_contributed"), p2.Pt()); + histosData.fill(HIST("pT_track_WTS_PID_Pi_contributed"), p3.Pt()); + histosData.fill(HIST("pT_track_WTS_PID_Pi_contributed"), p4.Pt()); + + histosData.fill(HIST("rapidity_track_WTS_PID_Pi_contributed"), p1.Rapidity()); + histosData.fill(HIST("rapidity_track_WTS_PID_Pi_contributed"), p2.Rapidity()); + histosData.fill(HIST("rapidity_track_WTS_PID_Pi_contributed"), p3.Rapidity()); + histosData.fill(HIST("rapidity_track_WTS_PID_Pi_contributed"), p4.Rapidity()); + + k1.SetCoordinates(p1.Pt(), p1.Eta(), p1.Phi(), o2::constants::physics::MassPionCharged); + k2.SetCoordinates(p2.Pt(), p2.Eta(), p2.Phi(), o2::constants::physics::MassPionCharged); + k3.SetCoordinates(p3.Pt(), p3.Eta(), p3.Phi(), o2::constants::physics::MassPionCharged); + k4.SetCoordinates(p4.Pt(), p4.Eta(), p4.Phi(), o2::constants::physics::MassPionCharged); + + p1234 = p1 + p2 + p3 + p4; + k1234 = k1 + k2 + k3 + k4; + + k13 = k1 + k3; + k14 = k1 + k4; + k23 = k2 + k3; + k24 = k2 + k4; + + double fourPiPhiPair1 = phiCollinsSoperFrame(k13, k24, k1234); + double fourPiPhiPair2 = phiCollinsSoperFrame(k14, k23, k1234); + double fourPiCosThetaPair1 = cosThetaCollinsSoperFrame(k13, k24, k1234); + double fourPiCosThetaPair2 = cosThetaCollinsSoperFrame(k14, k23, k1234); + + sigFromData( + collision.posX(), collision.posY(), collision.posZ(), + collision.totalFV0AmplitudeA(), collision.totalFT0AmplitudeA(), collision.totalFT0AmplitudeC(), collision.totalFDDAmplitudeA(), collision.totalFDDAmplitudeC(), + collision.timeFV0A(), collision.timeFT0A(), collision.timeFT0C(), collision.timeFDDA(), collision.timeFDDC(), collision.timeZNA(), collision.timeZNC(), + Pi_plus_tracks[0].dcaXY(), Pi_plus_tracks[1].dcaXY(), Pi_minus_tracks[0].dcaXY(), Pi_minus_tracks[1].dcaXY(), + + Pi_plus_tracks[0].dcaZ(), Pi_plus_tracks[1].dcaZ(), Pi_minus_tracks[0].dcaZ(), Pi_minus_tracks[1].dcaZ(), + + Pi_plus_tracks[0].tpcNSigmaPi(), Pi_plus_tracks[1].tpcNSigmaPi(), Pi_minus_tracks[0].tpcNSigmaPi(), Pi_minus_tracks[1].tpcNSigmaPi(), + + Pi_plus_tracks[0].tpcNSigmaKa(), Pi_plus_tracks[1].tpcNSigmaKa(), Pi_minus_tracks[0].tpcNSigmaKa(), Pi_minus_tracks[1].tpcNSigmaKa(), + + Pi_plus_tracks[0].tpcNSigmaPr(), Pi_plus_tracks[1].tpcNSigmaPr(), Pi_minus_tracks[0].tpcNSigmaPr(), Pi_minus_tracks[1].tpcNSigmaPr(), + + Pi_plus_tracks[0].tpcNSigmaEl(), Pi_plus_tracks[1].tpcNSigmaEl(), Pi_minus_tracks[0].tpcNSigmaEl(), Pi_minus_tracks[1].tpcNSigmaEl(), + + Pi_plus_tracks[0].tpcNSigmaMu(), Pi_plus_tracks[1].tpcNSigmaMu(), Pi_minus_tracks[0].tpcNSigmaMu(), Pi_minus_tracks[1].tpcNSigmaMu(), + + Pi_plus_tracks[0].tpcChi2NCl(), Pi_plus_tracks[1].tpcChi2NCl(), Pi_minus_tracks[0].tpcChi2NCl(), Pi_minus_tracks[1].tpcChi2NCl(), + + Pi_plus_tracks[0].tpcNClsFindable(), Pi_plus_tracks[1].tpcNClsFindable(), Pi_minus_tracks[0].tpcNClsFindable(), Pi_minus_tracks[1].tpcNClsFindable(), + + Pi_plus_tracks[0].itsChi2NCl(), Pi_plus_tracks[1].itsChi2NCl(), Pi_minus_tracks[0].itsChi2NCl(), Pi_minus_tracks[1].itsChi2NCl(), + + p1.Pt(), p2.Pt(), p3.Pt(), p4.Pt(), + p1.Eta(), p2.Eta(), p3.Eta(), p4.Eta(), + p1.Phi(), p2.Phi(), p3.Phi(), p4.Phi(), + p1.Rapidity(), p2.Rapidity(), p3.Rapidity(), p4.Rapidity(), + p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), + fourPiPhiPair1, fourPiPhiPair2, fourPiCosThetaPair1, fourPiCosThetaPair2); + + if (std::fabs(p1234.Rapidity()) < 0.5) { + histosData.fill(HIST("pT_event_0charge_WTS_PID_Pi"), p1234.Pt()); + if (p1234.Pt() < 0.15) { + histosData.fill(HIST("rapidity_event_0charge_WTS_PID_Pi_domainA"), p1234.Rapidity()); + histosData.fill(HIST("invMass_event_0charge_WTS_PID_Pi_domainA"), p1234.M()); + + histosData.fill(HIST("invMass_pair_1"), (p1 + p3).M()); + histosData.fill(HIST("invMass_pair_2"), (p1 + p4).M()); + histosData.fill(HIST("invMass_pair_3"), (p2 + p3).M()); + histosData.fill(HIST("invMass_pair_4"), (p2 + p4).M()); + + histosData.fill(HIST("CS_phi_pair_1"), fourPiPhiPair1); + histosData.fill(HIST("CS_phi_pair_2"), fourPiPhiPair2); + histosData.fill(HIST("CS_costheta_pair_1"), fourPiCosThetaPair1); + histosData.fill(HIST("CS_costheta_pair_2"), fourPiCosThetaPair2); + + histosData.fill(HIST("phi_cosTheta_pair_1"), fourPiPhiPair1, fourPiCosThetaPair1); + histosData.fill(HIST("phi_cosTheta_pair_2"), fourPiPhiPair2, fourPiCosThetaPair2); + } + if (p1234.Pt() > 0.15 && p1234.Pt() < 0.80) { + histosData.fill(HIST("rapidity_event_0charge_WTS_PID_Pi_domainB"), p1234.Rapidity()); + histosData.fill(HIST("invMass_event_0charge_WTS_PID_Pi_domainB"), p1234.M()); + } + if (p1234.Pt() > 0.80) { + histosData.fill(HIST("rapidity_event_0charge_WTS_PID_Pi_domainC"), p1234.Rapidity()); + histosData.fill(HIST("invMass_event_0charge_WTS_PID_Pi_domainC"), p1234.M()); + } + } // End of Rapidity range selection + + } // End of Analysis for 0 charge events + + // Selecting Events with net charge != 0 for estimation of background + if (numPionMinusTRacks != 2 && numPiPlusTracks != 2) { + + TLorentzVector p1, p2, p3, p4, p1234; + TLorentzVector tempVec; + p1.SetXYZM(WTS_PID_Pi_tracks[0].px(), WTS_PID_Pi_tracks[0].py(), WTS_PID_Pi_tracks[0].pz(), o2::constants::physics::MassPionCharged); + p2.SetXYZM(WTS_PID_Pi_tracks[1].px(), WTS_PID_Pi_tracks[1].py(), WTS_PID_Pi_tracks[1].pz(), o2::constants::physics::MassPionCharged); + p3.SetXYZM(WTS_PID_Pi_tracks[2].px(), WTS_PID_Pi_tracks[2].py(), WTS_PID_Pi_tracks[2].pz(), o2::constants::physics::MassPionCharged); + p4.SetXYZM(WTS_PID_Pi_tracks[3].px(), WTS_PID_Pi_tracks[3].py(), WTS_PID_Pi_tracks[3].pz(), o2::constants::physics::MassPionCharged); + + p1234 = p1 + p2 + p3 + p4; + + bkgFromData( + collision.posX(), collision.posY(), collision.posZ(), + collision.totalFV0AmplitudeA(), collision.totalFT0AmplitudeA(), collision.totalFT0AmplitudeC(), collision.totalFDDAmplitudeA(), collision.totalFDDAmplitudeC(), + collision.timeFV0A(), collision.timeFT0A(), collision.timeFT0C(), collision.timeFDDA(), collision.timeFDDC(), + collision.timeZNA(), collision.timeZNC(), + WTS_PID_Pi_tracks[0].dcaXY(), WTS_PID_Pi_tracks[1].dcaXY(), WTS_PID_Pi_tracks[0].dcaXY(), WTS_PID_Pi_tracks[1].dcaXY(), + WTS_PID_Pi_tracks[0].dcaZ(), WTS_PID_Pi_tracks[1].dcaZ(), WTS_PID_Pi_tracks[0].dcaZ(), WTS_PID_Pi_tracks[1].dcaZ(), + WTS_PID_Pi_tracks[0].tpcNSigmaPi(), WTS_PID_Pi_tracks[1].tpcNSigmaPi(), WTS_PID_Pi_tracks[0].tpcNSigmaPi(), WTS_PID_Pi_tracks[1].tpcNSigmaPi(), + WTS_PID_Pi_tracks[0].tpcNSigmaKa(), WTS_PID_Pi_tracks[1].tpcNSigmaKa(), WTS_PID_Pi_tracks[0].tpcNSigmaKa(), WTS_PID_Pi_tracks[1].tpcNSigmaKa(), + WTS_PID_Pi_tracks[0].tpcNSigmaPr(), WTS_PID_Pi_tracks[1].tpcNSigmaPr(), WTS_PID_Pi_tracks[0].tpcNSigmaPr(), WTS_PID_Pi_tracks[1].tpcNSigmaPr(), + WTS_PID_Pi_tracks[0].tpcNSigmaEl(), WTS_PID_Pi_tracks[1].tpcNSigmaEl(), WTS_PID_Pi_tracks[0].tpcNSigmaEl(), WTS_PID_Pi_tracks[1].tpcNSigmaEl(), + WTS_PID_Pi_tracks[0].tpcNSigmaMu(), WTS_PID_Pi_tracks[1].tpcNSigmaMu(), WTS_PID_Pi_tracks[0].tpcNSigmaMu(), WTS_PID_Pi_tracks[1].tpcNSigmaMu(), + WTS_PID_Pi_tracks[0].itsChi2NCl(), WTS_PID_Pi_tracks[1].itsChi2NCl(), WTS_PID_Pi_tracks[0].itsChi2NCl(), WTS_PID_Pi_tracks[1].itsChi2NCl(), + WTS_PID_Pi_tracks[0].tpcChi2NCl(), WTS_PID_Pi_tracks[1].tpcChi2NCl(), WTS_PID_Pi_tracks[0].tpcChi2NCl(), WTS_PID_Pi_tracks[1].tpcChi2NCl(), + WTS_PID_Pi_tracks[0].tpcNClsFindable(), WTS_PID_Pi_tracks[1].tpcNClsFindable(), WTS_PID_Pi_tracks[0].tpcNClsFindable(), WTS_PID_Pi_tracks[1].tpcNClsFindable(), + p1.Pt(), p2.Pt(), p3.Pt(), p4.Pt(), + p1.Eta(), p2.Eta(), p3.Eta(), p4.Eta(), + p1.Phi(), p2.Phi(), p3.Phi(), p4.Phi(), + p1.Rapidity(), p2.Rapidity(), p3.Rapidity(), p4.Rapidity(), + p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M()); + + if (std::fabs(p1234.Rapidity()) < 0.5) { + histosData.fill(HIST("pT_event_non0charge_WTS_PID_Pi"), p1234.Pt()); + + if (p1234.Pt() < 0.15) { + histosData.fill(HIST("rapidity_event_non0charge_WTS_PID_Pi_domainA"), p1234.Rapidity()); + histosData.fill(HIST("invMass_event_non0charge_WTS_PID_Pi_domainA"), p1234.M()); + } + if (p1234.Pt() > 0.15 && p1234.Pt() < 0.80) { + histosData.fill(HIST("rapidity_event_non0charge_WTS_PID_Pi_domainB"), p1234.Rapidity()); + histosData.fill(HIST("invMass_event_non0charge_WTS_PID_Pi_domainB"), p1234.M()); + } + if (p1234.Pt() > 0.80) { + histosData.fill(HIST("rapidity_event_non0charge_WTS_PID_Pi_domainC"), p1234.Rapidity()); + histosData.fill(HIST("invMass_event_non0charge_WTS_PID_Pi_domainC"), p1234.M()); + } + } // End of Rapidity range selection + + } // End of Analysis for non 0 charge events + + } // End of 4 Pion Analysis Process function for Data + PROCESS_SWITCH(ExclusiveRhoTo4Pi, processData, "The Process for 4 Pion Analysis from data", true); + //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + Filter collCuts = (nabs(o2::aod::collision::posZ) < 10.0f) && (o2::aod::collision::numContrib == numPVContrib); + Filter fitCuts = (o2::aod::udcollision::totalFT0AmplitudeA < ft0aCut) && (o2::aod::udcollision::totalFT0AmplitudeC < ft0cCut) && (o2::aod::udcollision::totalFV0AmplitudeA < fv0Cut); + Filter zdcCuts = (o2::aod::udzdc::energyCommonZNA < zdcCut) && (o2::aod::udzdc::energyCommonZNC < zdcCut); + Filter trackCuts = (o2::aod::track::tpcChi2NCl < tpcChi2Cut) && (o2::aod::track::tpcNClsFindable > tpcNClsFindableCut) && (o2::aod::track::itsChi2NCl < itsChi2Cut) && (nabs(o2::aod::track::eta) < etaCut) && (o2::aod::track::pt > pTcut) && (nabs(o2::aod::track::dcaZ) < dcaZcut) && (nabs(o2::aod::track::dcaXY) < dcaXYcut); + Filter udtrackCuts = (o2::aod::udtrack::isPVContributor == true); + Filter pidCuts = (nabs(o2::aod::pidtpc::tpcNSigmaPi) < nSigmaTPCcut); + using FilteredTracks = soa::Filtered>; + using FilteredCollisions = soa::Filtered>; + using FilteredCollisionsFull = FilteredCollisions::iterator; + + // // Begin of FAST Process function-------------------------------------------------------------------------------------------------------------------------------------------------- + void processDataFast(FilteredCollisionsFull const& collision, FilteredTracks const& tracks) + { + + if (tracks.size() != 4) { + return; + } + + std::vector pionPlusTracks; + std::vector pionMinusTracks; + + for (const auto& track : tracks) { + if ((!selectionPIDPion(track, true, nSigmaTPCcut, nSigmaTOFcut))) { + continue; + } + if (track.sign() == 1) { + pionPlusTracks.push_back(track); + } + if (track.sign() == -1) { + pionMinusTracks.push_back(track); + } + } // end of loop over tracks + + if ((pionPlusTracks.size() + pionMinusTracks.size()) != 4) { + return; + } + + if (pionPlusTracks.size() == 2 || pionMinusTracks.size() == 2) { + + TLorentzVector p1, p2, p3, p4, p1234; + ROOT::Math::PtEtaPhiMVector k1, k2, k3, k4, k1234, k13, k14, k23, k24; + + p1.SetXYZM(pionPlusTracks[0].px(), pionPlusTracks[0].py(), pionPlusTracks[0].pz(), o2::constants::physics::MassPionCharged); + p2.SetXYZM(pionPlusTracks[1].px(), pionPlusTracks[1].py(), pionPlusTracks[1].pz(), o2::constants::physics::MassPionCharged); + p3.SetXYZM(pionMinusTracks[0].px(), pionMinusTracks[0].py(), pionMinusTracks[0].pz(), o2::constants::physics::MassPionCharged); + p4.SetXYZM(pionMinusTracks[1].px(), pionMinusTracks[1].py(), pionMinusTracks[1].pz(), o2::constants::physics::MassPionCharged); + + k1.SetCoordinates(p1.Pt(), p1.Eta(), p1.Phi(), o2::constants::physics::MassPionCharged); + k2.SetCoordinates(p2.Pt(), p2.Eta(), p2.Phi(), o2::constants::physics::MassPionCharged); + k3.SetCoordinates(p3.Pt(), p3.Eta(), p3.Phi(), o2::constants::physics::MassPionCharged); + k4.SetCoordinates(p4.Pt(), p4.Eta(), p4.Phi(), o2::constants::physics::MassPionCharged); + + p1234 = p1 + p2 + p3 + p4; + k1234 = k1 + k2 + k3 + k4; + + k13 = k1 + k3; + k14 = k1 + k4; + k23 = k2 + k3; + k24 = k2 + k4; + + double fourPiPhiPair1 = phiCollinsSoperFrame(k13, k24, k1234); + double fourPiPhiPair2 = phiCollinsSoperFrame(k14, k23, k1234); + double fourPiCosThetaPair1 = cosThetaCollinsSoperFrame(k13, k24, k1234); + double fourPiCosThetaPair2 = cosThetaCollinsSoperFrame(k14, k23, k1234); + + sigFromData( + collision.posX(), collision.posY(), collision.posZ(), + collision.totalFV0AmplitudeA(), collision.totalFT0AmplitudeA(), collision.totalFT0AmplitudeC(), collision.totalFDDAmplitudeA(), collision.totalFDDAmplitudeC(), + collision.timeFV0A(), collision.timeFT0A(), collision.timeFT0C(), collision.timeFDDA(), collision.timeFDDC(), + collision.timeZNA(), collision.timeZNC(), + pionPlusTracks[0].dcaXY(), pionPlusTracks[1].dcaXY(), pionMinusTracks[0].dcaXY(), pionMinusTracks[1].dcaXY(), + pionPlusTracks[0].dcaZ(), pionPlusTracks[1].dcaZ(), pionMinusTracks[0].dcaZ(), pionMinusTracks[1].dcaZ(), + pionPlusTracks[0].tpcNSigmaPi(), pionPlusTracks[1].tpcNSigmaPi(), pionMinusTracks[0].tpcNSigmaPi(), pionMinusTracks[1].tpcNSigmaPi(), + pionPlusTracks[0].tpcNSigmaKa(), pionPlusTracks[1].tpcNSigmaKa(), pionMinusTracks[0].tpcNSigmaKa(), pionMinusTracks[1].tpcNSigmaKa(), + pionPlusTracks[0].tpcNSigmaPr(), pionPlusTracks[1].tpcNSigmaPr(), pionMinusTracks[0].tpcNSigmaPr(), pionMinusTracks[1].tpcNSigmaPr(), + pionPlusTracks[0].tpcNSigmaEl(), pionPlusTracks[1].tpcNSigmaEl(), pionMinusTracks[0].tpcNSigmaEl(), pionMinusTracks[1].tpcNSigmaEl(), + pionPlusTracks[0].tpcNSigmaMu(), pionPlusTracks[1].tpcNSigmaMu(), pionMinusTracks[0].tpcNSigmaMu(), pionMinusTracks[1].tpcNSigmaMu(), + pionPlusTracks[0].tpcChi2NCl(), pionPlusTracks[1].tpcChi2NCl(), pionMinusTracks[0].tpcChi2NCl(), pionMinusTracks[1].tpcChi2NCl(), + pionPlusTracks[0].tpcNClsFindable(), pionPlusTracks[1].tpcNClsFindable(), pionMinusTracks[0].tpcNClsFindable(), pionMinusTracks[1].tpcNClsFindable(), + pionPlusTracks[0].itsChi2NCl(), pionPlusTracks[1].itsChi2NCl(), pionMinusTracks[0].itsChi2NCl(), pionMinusTracks[1].itsChi2NCl(), + p1.Pt(), p2.Pt(), p3.Pt(), p4.Pt(), + p1.Eta(), p2.Eta(), p3.Eta(), p4.Eta(), + p1.Phi(), p2.Phi(), p3.Phi(), p4.Phi(), + p1.Rapidity(), p2.Rapidity(), p3.Rapidity(), p4.Rapidity(), + p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), + fourPiPhiPair1, fourPiPhiPair2, fourPiCosThetaPair1, fourPiCosThetaPair2); + + histosFastData.fill(HIST("4PionPt"), p1234.Pt()); + histosFastData.fill(HIST("4PionRapidity"), p1234.Rapidity()); + histosFastData.fill(HIST("4PionMassFull"), p1234.M()); + + if ((p1234.Pt() < 0.15) && (std::abs(p1234.Rapidity()) < 0.5)) { + histosFastData.fill(HIST("4PionMassWithCut"), p1234.M()); + } + } // End 0 charge event + + if (pionPlusTracks.size() != 2 && pionMinusTracks.size() != 2) { + std::vector allTracks; + int piPlussize = static_cast(pionPlusTracks.size()); + int piMinussize = static_cast(pionMinusTracks.size()); + + for (int i = 0; i < piPlussize; i++) { + allTracks.push_back(pionPlusTracks[i]); + } + for (int i = 0; i < piMinussize; i++) { + allTracks.push_back(pionMinusTracks[i]); + } + + TLorentzVector p1, p2, p3, p4, p1234; + + p1.SetXYZM(allTracks[0].px(), allTracks[0].py(), allTracks[0].pz(), o2::constants::physics::MassPionCharged); + p2.SetXYZM(allTracks[1].px(), allTracks[1].py(), allTracks[1].pz(), o2::constants::physics::MassPionCharged); + p3.SetXYZM(allTracks[2].px(), allTracks[2].py(), allTracks[2].pz(), o2::constants::physics::MassPionCharged); + p4.SetXYZM(allTracks[3].px(), allTracks[3].py(), allTracks[3].pz(), o2::constants::physics::MassPionCharged); + + p1234 = p1 + p2 + p3 + p4; + + bkgFromData( + collision.posX(), collision.posY(), collision.posZ(), + collision.totalFV0AmplitudeA(), collision.totalFT0AmplitudeA(), collision.totalFT0AmplitudeC(), collision.totalFDDAmplitudeA(), collision.totalFDDAmplitudeC(), + collision.timeFV0A(), collision.timeFT0A(), collision.timeFT0C(), collision.timeFDDA(), collision.timeFDDC(), collision.timeZNA(), collision.timeZNC(), + allTracks[0].dcaXY(), allTracks[1].dcaXY(), allTracks[2].dcaXY(), allTracks[3].dcaXY(), + + allTracks[0].dcaZ(), allTracks[1].dcaZ(), allTracks[2].dcaZ(), allTracks[3].dcaZ(), + + allTracks[0].tpcNSigmaPi(), allTracks[1].tpcNSigmaPi(), allTracks[2].tpcNSigmaPi(), allTracks[3].tpcNSigmaPi(), + + allTracks[0].tpcNSigmaKa(), allTracks[1].tpcNSigmaKa(), allTracks[2].tpcNSigmaKa(), allTracks[3].tpcNSigmaKa(), + + allTracks[0].tpcNSigmaPr(), allTracks[1].tpcNSigmaPr(), allTracks[2].tpcNSigmaPr(), allTracks[3].tpcNSigmaPr(), + + allTracks[0].tpcNSigmaEl(), allTracks[1].tpcNSigmaEl(), allTracks[2].tpcNSigmaEl(), allTracks[3].tpcNSigmaEl(), + + allTracks[0].tpcNSigmaMu(), allTracks[1].tpcNSigmaMu(), allTracks[2].tpcNSigmaMu(), allTracks[3].tpcNSigmaMu(), + + allTracks[0].tpcChi2NCl(), allTracks[1].tpcChi2NCl(), allTracks[2].tpcChi2NCl(), allTracks[3].tpcChi2NCl(), + + allTracks[0].tpcNClsFindable(), allTracks[1].tpcNClsFindable(), allTracks[2].tpcNClsFindable(), allTracks[3].tpcNClsFindable(), + + allTracks[0].itsChi2NCl(), allTracks[1].itsChi2NCl(), allTracks[2].itsChi2NCl(), allTracks[3].itsChi2NCl(), + + p1.Pt(), p2.Pt(), p3.Pt(), p4.Pt(), + p1.Eta(), p2.Eta(), p3.Eta(), p4.Eta(), + p1.Phi(), p2.Phi(), p3.Phi(), p4.Phi(), + p1.Rapidity(), p2.Rapidity(), p3.Rapidity(), p4.Rapidity(), + p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M()); + + } // end of non 0 charge event + + } // End of 4 Pion Analysis Process function for Fast Data + PROCESS_SWITCH(ExclusiveRhoTo4Pi, processDataFast, "The Process for 4 Pion Analysis from data fast", true); + // //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + // Begin of MC Generation function----------------------------------------------------------------------------------------------------------------------------------------------- + void processMCgen(aod::UDMcCollisions::iterator const&, aod::UDMcParticles const& mcParts) + { + std::vector piPlusvectors; + std::vector piMinusvectors; + TLorentzVector daughterVector; + TVector3 particleVector; + + for (const auto& particle : mcParts) { + + if ((particle.pdgCode() != rhoPrime) || (particle.daughters_as().size() != 4)) { + continue; + } + + particleVector.SetXYZ(particle.px(), particle.py(), particle.pz()); + histosMCgen.fill(HIST("rhoPrimeCounts"), 1); + histosMCgen.fill(HIST("rhoPrime_pT"), particleVector.Pt()); + histosMCgen.fill(HIST("rhoPrime_eta"), particleVector.Eta()); + + for (const auto& daughter : particle.daughters_as()) { + daughterVector.SetXYZM(daughter.px(), daughter.py(), daughter.pz(), o2::constants::physics::MassPionCharged); + if (daughter.pdgCode() == PDG_t::kPiPlus) { + piPlusvectors.push_back(daughterVector); + } + if (daughter.pdgCode() == PDG_t::kPiMinus) { + piMinusvectors.push_back(daughterVector); + } + } // End of loop over daughters + + } // End of loop over MC particles + + if (piPlusvectors.size() != 2 || piMinusvectors.size() != 2) { + return; + } + + TLorentzVector p1234 = piPlusvectors[0] + piPlusvectors[1] + piMinusvectors[0] + piMinusvectors[1]; + + histosMCgen.fill(HIST("pion_pT"), piPlusvectors[0].Pt()); + histosMCgen.fill(HIST("pion_pT"), piPlusvectors[1].Pt()); + histosMCgen.fill(HIST("pion_pT"), piMinusvectors[0].Pt()); + histosMCgen.fill(HIST("pion_pT"), piMinusvectors[1].Pt()); + + histosMCgen.fill(HIST("pion_eta"), piPlusvectors[0].Eta()); + histosMCgen.fill(HIST("pion_eta"), piPlusvectors[1].Eta()); + histosMCgen.fill(HIST("pion_eta"), piMinusvectors[0].Eta()); + histosMCgen.fill(HIST("pion_eta"), piMinusvectors[1].Eta()); + + histosMCgen.fill(HIST("pion_rapidity"), piPlusvectors[0].Rapidity()); + histosMCgen.fill(HIST("pion_rapidity"), piPlusvectors[1].Rapidity()); + histosMCgen.fill(HIST("pion_rapidity"), piMinusvectors[0].Rapidity()); + histosMCgen.fill(HIST("pion_rapidity"), piMinusvectors[1].Rapidity()); + + histosMCgen.fill(HIST("fourPion_pT"), p1234.Pt()); + histosMCgen.fill(HIST("fourPion_eta"), p1234.Eta()); + histosMCgen.fill(HIST("fourPion_rapidity"), p1234.Rapidity()); + histosMCgen.fill(HIST("fourPion_invmass"), p1234.M()); + + histosMCgen.fill(HIST("twoPion_invMass_pair_1"), (piPlusvectors[0] + piMinusvectors[0]).M()); + histosMCgen.fill(HIST("twoPion_invMass_pair_2"), (piPlusvectors[0] + piMinusvectors[1]).M()); + histosMCgen.fill(HIST("twoPion_invMass_pair_3"), (piPlusvectors[1] + piMinusvectors[0]).M()); + histosMCgen.fill(HIST("twoPion_invMass_pair_4"), (piPlusvectors[1] + piMinusvectors[1]).M()); + + ROOT::Math::PtEtaPhiMVector k1, k2, k3, k4, k1234, k13, k14, k23, k24; + + k1.SetCoordinates(piPlusvectors[0].Pt(), piPlusvectors[0].Eta(), piPlusvectors[0].Phi(), o2::constants::physics::MassPionCharged); + k2.SetCoordinates(piPlusvectors[1].Pt(), piPlusvectors[1].Eta(), piPlusvectors[1].Phi(), o2::constants::physics::MassPionCharged); + k3.SetCoordinates(piMinusvectors[0].Pt(), piMinusvectors[0].Eta(), piMinusvectors[0].Phi(), o2::constants::physics::MassPionCharged); + k4.SetCoordinates(piMinusvectors[1].Pt(), piMinusvectors[1].Eta(), piMinusvectors[1].Phi(), o2::constants::physics::MassPionCharged); + + k1234 = k1 + k2 + k3 + k4; + + k13 = k1 + k3; + k14 = k1 + k4; + k23 = k2 + k3; + k24 = k2 + k4; + + auto phiPair1 = phiCollinsSoperFrame(k13, k24, k1234); + auto phiPair2 = phiCollinsSoperFrame(k14, k23, k1234); + auto cosThetaPair1 = cosThetaCollinsSoperFrame(k13, k24, k1234); + auto cosThetaPair2 = cosThetaCollinsSoperFrame(k14, k23, k1234); + + generatedMC( + piPlusvectors[0].Pt(), piPlusvectors[1].Pt(), piMinusvectors[0].Pt(), piMinusvectors[1].Pt(), + piPlusvectors[0].Eta(), piPlusvectors[1].Eta(), piMinusvectors[0].Eta(), piMinusvectors[1].Eta(), + piPlusvectors[0].Phi(), piPlusvectors[1].Phi(), piMinusvectors[0].Phi(), piMinusvectors[1].Phi(), + piPlusvectors[0].Rapidity(), piPlusvectors[1].Rapidity(), piMinusvectors[0].Rapidity(), piMinusvectors[1].Rapidity(), + p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), + phiPair1, phiPair2, cosThetaPair1, cosThetaPair2); + + histosMCgen.fill(HIST("fourPion_phi_pair_1"), phiPair1); + histosMCgen.fill(HIST("fourPion_phi_pair_2"), phiPair2); + histosMCgen.fill(HIST("fourPion_costheta_pair_1"), cosThetaPair1); + histosMCgen.fill(HIST("fourPion_costheta_pair_2"), cosThetaPair2); + histosMCgen.fill(HIST("phi_cosTheta_pair_1"), phiPair1, cosThetaPair1); + histosMCgen.fill(HIST("phi_cosTheta_pair_2"), phiPair2, cosThetaPair2); + + } // End of 4 Pion MC Generation Process function + PROCESS_SWITCH(ExclusiveRhoTo4Pi, processMCgen, "The Process for 4 Pion Analysis from MC Generation", false); + + using CollisionStuff = soa::Join; + using CollisionTotal = CollisionStuff::iterator; + using TrackStuff = soa::Join; + + void processMCrec(CollisionTotal const& collision, TrackStuff const& tracks) + { + + if (std::abs(collision.posZ()) > 10) { + return; + } + + if (!collision.has_udMcCollision()) { + return; + } + + int gapSide = collision.gapSide(); + std::vector parameters = {pvCut, dcaZcut, dcaXYcut, tpcChi2Cut, tpcNClsFindableCut, itsChi2Cut, etaCut, pTcut}; + int truegapSide = sgSelector.trueGap(collision, fv0Cut, ft0aCut, ft0cCut, zdcCut); + histosMCreco.fill(HIST("GapSide"), gapSide); + histosMCreco.fill(HIST("TrueGapSide"), truegapSide); + histosMCreco.fill(HIST("EventCounts"), 1); + gapSide = truegapSide; + + if ((gapSide != 2)) { + return; + } + + histosMCreco.fill(HIST("vertexZ"), collision.posZ()); + histosMCreco.fill(HIST("V0A"), collision.totalFV0AmplitudeA()); + histosMCreco.fill(HIST("FT0A"), collision.totalFT0AmplitudeA()); + histosMCreco.fill(HIST("FT0C"), collision.totalFT0AmplitudeC()); + histosMCreco.fill(HIST("ZDC_A"), collision.energyCommonZNA()); + histosMCreco.fill(HIST("ZDC_C"), collision.energyCommonZNC()); + + if (collision.numContrib() != 4) { + return; + } + + std::vector WOTS_tracks; + std::vector WTS_tracks; + std::vector WTS_PID_Pi_tracks; + std::vector Pi_plus_tracks; + std::vector Pi_minus_tracks; + + for (const auto& t0 : tracks) { + + WOTS_tracks.push_back(t0); + + if (trackselector(t0, parameters) && t0.has_udMcParticle()) { + WTS_tracks.push_back(t0); + + if (selectionPIDPion(t0, true, nSigmaTPCcut, nSigmaTOFcut)) { + WTS_PID_Pi_tracks.push_back(t0); + if (t0.sign() == 1) { + Pi_plus_tracks.push_back(t0); + } + if (t0.sign() == -1) { + Pi_minus_tracks.push_back(t0); + } + } // End of Selection PID Pion + + } // End of track selections + + } // End of loop over tracks + + int numTracksWOTS = static_cast(WOTS_tracks.size()); + int numTracksWTS = static_cast(WTS_tracks.size()); + int numTracksWTSandPIDpi = static_cast(WTS_PID_Pi_tracks.size()); + int numPiPlusTracks = static_cast(Pi_plus_tracks.size()); + int numPionMinusTRacks = static_cast(Pi_minus_tracks.size()); + + TLorentzVector tempWOTS; + for (int i = 0; i < numTracksWOTS; i++) { + tempWOTS.SetXYZM(WOTS_tracks[i].px(), WOTS_tracks[i].py(), WOTS_tracks[i].pz(), o2::constants::physics::MassPionCharged); + histosMCreco.fill(HIST("tpcNSigmaPi_WOTS"), WOTS_tracks[i].tpcNSigmaPi(), std::sqrt(WOTS_tracks[i].px() * WOTS_tracks[i].px() + WOTS_tracks[i].py() * WOTS_tracks[i].py())); + histosMCreco.fill(HIST("tofNSigmaPi_WOTS"), WOTS_tracks[i].tofNSigmaPi(), std::sqrt(WOTS_tracks[i].px() * WOTS_tracks[i].px() + WOTS_tracks[i].py() * WOTS_tracks[i].py())); + histosMCreco.fill(HIST("pT_track_WOTS"), std::sqrt(WOTS_tracks[i].px() * WOTS_tracks[i].px() + WOTS_tracks[i].py() * WOTS_tracks[i].py())); + histosMCreco.fill(HIST("rapidity_track_WOTS"), tempWOTS.Rapidity()); + + } // End of loop over tracks without selection + + TLorentzVector tempWTS; + for (int i = 0; i < numTracksWTS; i++) { + tempWTS.SetXYZM(WTS_tracks[i].px(), WTS_tracks[i].py(), WTS_tracks[i].pz(), o2::constants::physics::MassPionCharged); + histosMCreco.fill(HIST("tpcSignal"), std::sqrt(WTS_tracks[i].px() * WTS_tracks[i].px() + WTS_tracks[i].py() * WTS_tracks[i].py() + WTS_tracks[i].pz() * WTS_tracks[i].pz()), WTS_tracks[i].tpcSignal()); + histosMCreco.fill(HIST("tofBeta"), std::sqrt(WTS_tracks[i].px() * WTS_tracks[i].px() + WTS_tracks[i].py() * WTS_tracks[i].py() + WTS_tracks[i].pz() * WTS_tracks[i].pz()), WTS_tracks[i].beta()); + histosMCreco.fill(HIST("tpcNSigmaPi_WTS"), WTS_tracks[i].tpcNSigmaPi(), std::sqrt(WTS_tracks[i].px() * WTS_tracks[i].px() + WTS_tracks[i].py() * WTS_tracks[i].py())); + histosMCreco.fill(HIST("tofNSigmaPi_WTS"), WTS_tracks[i].tofNSigmaPi(), std::sqrt(WTS_tracks[i].px() * WTS_tracks[i].px() + WTS_tracks[i].py() * WTS_tracks[i].py())); + histosMCreco.fill(HIST("pT_track_WTS"), std::sqrt(WTS_tracks[i].px() * WTS_tracks[i].px() + WTS_tracks[i].py() * WTS_tracks[i].py())); + histosMCreco.fill(HIST("rapidity_track_WTS"), tempWTS.Rapidity()); + + histosMCreco.fill(HIST("itsChi2NCl"), WTS_tracks[i].itsChi2NCl()); + histosMCreco.fill(HIST("tpcChi2NCl"), WTS_tracks[i].tpcChi2NCl()); + histosMCreco.fill(HIST("tpcNClsFindable"), WTS_tracks[i].tpcNClsFindable()); + histosMCreco.fill(HIST("dcaXY"), WTS_tracks[i].dcaXY()); + histosMCreco.fill(HIST("dcaZ"), WTS_tracks[i].dcaZ()); + } // End of loop over tracks with selection only + + TLorentzVector tempWTSPIDPi; + for (int i = 0; i < numTracksWTSandPIDpi; i++) { + + tempWTSPIDPi.SetXYZM(WTS_PID_Pi_tracks[i].px(), WTS_PID_Pi_tracks[i].py(), WTS_PID_Pi_tracks[i].pz(), o2::constants::physics::MassPionCharged); + + histosMCreco.fill(HIST("tpcSignal_Pi"), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py() + WTS_PID_Pi_tracks[i].pz() * WTS_PID_Pi_tracks[i].pz()), WTS_PID_Pi_tracks[i].tpcSignal()); + histosMCreco.fill(HIST("tofBeta_Pi"), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py() + WTS_PID_Pi_tracks[i].pz() * WTS_PID_Pi_tracks[i].pz()), WTS_PID_Pi_tracks[i].beta()); + + histosMCreco.fill(HIST("tpcNSigmaPi_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tpcNSigmaPi(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosMCreco.fill(HIST("tpcNSigmaKa_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tpcNSigmaKa(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosMCreco.fill(HIST("tpcNSigmaPr_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tpcNSigmaPr(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosMCreco.fill(HIST("tpcNSigmaEl_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tpcNSigmaEl(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosMCreco.fill(HIST("tpcNSigmaMu_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tpcNSigmaMu(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + + histosMCreco.fill(HIST("tofNSigmaPi_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tofNSigmaPi(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosMCreco.fill(HIST("tofNSigmaKa_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tofNSigmaKa(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosMCreco.fill(HIST("tofNSigmaPr_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tofNSigmaPr(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosMCreco.fill(HIST("tofNSigmaEl_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tofNSigmaEl(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosMCreco.fill(HIST("tofNSigmaMu_WTS_PID_Pi"), WTS_PID_Pi_tracks[i].tofNSigmaMu(), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + + histosMCreco.fill(HIST("pT_track_WTS_PID_Pi"), std::sqrt(WTS_PID_Pi_tracks[i].px() * WTS_PID_Pi_tracks[i].px() + WTS_PID_Pi_tracks[i].py() * WTS_PID_Pi_tracks[i].py())); + histosMCreco.fill(HIST("rapidity_track_WTS_PID_Pi"), tempWTSPIDPi.Rapidity()); + } // End of loop over tracks with selection and PID selection of Pions + + if (numTracksWTSandPIDpi != 4) { + return; + } + + // Selecting Events with net charge = 0 + if (numPionMinusTRacks == 2 && numPiPlusTracks == 2) { + + TLorentzVector p1, p2, p3, p4, p1234; + ROOT::Math::PtEtaPhiMVector k1, k2, k3, k4, k1234, k13, k14, k23, k24; + + p1.SetXYZM(Pi_plus_tracks[0].px(), Pi_plus_tracks[0].py(), Pi_plus_tracks[0].pz(), o2::constants::physics::MassPionCharged); + p2.SetXYZM(Pi_plus_tracks[1].px(), Pi_plus_tracks[1].py(), Pi_plus_tracks[1].pz(), o2::constants::physics::MassPionCharged); + p3.SetXYZM(Pi_minus_tracks[0].px(), Pi_minus_tracks[0].py(), Pi_minus_tracks[0].pz(), o2::constants::physics::MassPionCharged); + p4.SetXYZM(Pi_minus_tracks[1].px(), Pi_minus_tracks[1].py(), Pi_minus_tracks[1].pz(), o2::constants::physics::MassPionCharged); + + histosMCreco.fill(HIST("pT_track_WTS_PID_Pi_contributed"), p1.Pt()); + histosMCreco.fill(HIST("pT_track_WTS_PID_Pi_contributed"), p2.Pt()); + histosMCreco.fill(HIST("pT_track_WTS_PID_Pi_contributed"), p3.Pt()); + histosMCreco.fill(HIST("pT_track_WTS_PID_Pi_contributed"), p4.Pt()); + + histosMCreco.fill(HIST("rapidity_track_WTS_PID_Pi_contributed"), p1.Rapidity()); + histosMCreco.fill(HIST("rapidity_track_WTS_PID_Pi_contributed"), p2.Rapidity()); + histosMCreco.fill(HIST("rapidity_track_WTS_PID_Pi_contributed"), p3.Rapidity()); + histosMCreco.fill(HIST("rapidity_track_WTS_PID_Pi_contributed"), p4.Rapidity()); + + k1.SetCoordinates(p1.Pt(), p1.Eta(), p1.Phi(), o2::constants::physics::MassPionCharged); + k2.SetCoordinates(p2.Pt(), p2.Eta(), p2.Phi(), o2::constants::physics::MassPionCharged); + k3.SetCoordinates(p3.Pt(), p3.Eta(), p3.Phi(), o2::constants::physics::MassPionCharged); + k4.SetCoordinates(p4.Pt(), p4.Eta(), p4.Phi(), o2::constants::physics::MassPionCharged); + + p1234 = p1 + p2 + p3 + p4; + k1234 = k1 + k2 + k3 + k4; + + k13 = k1 + k3; + k14 = k1 + k4; + k23 = k2 + k3; + k24 = k2 + k4; + + double phiPair1 = phiCollinsSoperFrame(k13, k24, k1234); + double phiPair2 = phiCollinsSoperFrame(k14, k23, k1234); + double cosThetaPair1 = cosThetaCollinsSoperFrame(k13, k24, k1234); + double cosThetaPair2 = cosThetaCollinsSoperFrame(k14, k23, k1234); + + sigFromMC( + collision.posX(), collision.posY(), collision.posZ(), + collision.totalFV0AmplitudeA(), collision.totalFT0AmplitudeA(), collision.totalFT0AmplitudeC(), collision.totalFDDAmplitudeA(), collision.totalFDDAmplitudeC(), + collision.timeFV0A(), collision.timeFT0A(), collision.timeFT0C(), collision.timeFDDA(), collision.timeFDDC(), + collision.timeZNA(), collision.timeZNC(), + Pi_plus_tracks[0].dcaXY(), Pi_plus_tracks[1].dcaXY(), Pi_minus_tracks[0].dcaXY(), Pi_minus_tracks[1].dcaXY(), + Pi_plus_tracks[0].dcaZ(), Pi_plus_tracks[1].dcaZ(), Pi_minus_tracks[0].dcaZ(), Pi_minus_tracks[1].dcaZ(), + Pi_plus_tracks[0].tpcNSigmaPi(), Pi_plus_tracks[1].tpcNSigmaPi(), Pi_minus_tracks[0].tpcNSigmaPi(), Pi_minus_tracks[1].tpcNSigmaPi(), + Pi_plus_tracks[0].tpcNSigmaKa(), Pi_plus_tracks[1].tpcNSigmaKa(), Pi_minus_tracks[0].tpcNSigmaKa(), Pi_minus_tracks[1].tpcNSigmaKa(), + Pi_plus_tracks[0].tpcNSigmaPr(), Pi_plus_tracks[1].tpcNSigmaPr(), Pi_minus_tracks[0].tpcNSigmaPr(), Pi_minus_tracks[1].tpcNSigmaPr(), + Pi_plus_tracks[0].tpcNSigmaEl(), Pi_plus_tracks[1].tpcNSigmaEl(), Pi_minus_tracks[0].tpcNSigmaEl(), Pi_minus_tracks[1].tpcNSigmaEl(), + Pi_plus_tracks[0].tpcNSigmaMu(), Pi_plus_tracks[1].tpcNSigmaMu(), Pi_minus_tracks[0].tpcNSigmaMu(), Pi_minus_tracks[1].tpcNSigmaMu(), + Pi_plus_tracks[0].tpcChi2NCl(), Pi_plus_tracks[1].tpcChi2NCl(), Pi_minus_tracks[0].tpcChi2NCl(), Pi_minus_tracks[1].tpcChi2NCl(), + Pi_plus_tracks[0].tpcNClsFindable(), Pi_plus_tracks[1].tpcNClsFindable(), Pi_minus_tracks[0].tpcNClsFindable(), Pi_minus_tracks[1].tpcNClsFindable(), + Pi_plus_tracks[0].itsChi2NCl(), Pi_plus_tracks[1].itsChi2NCl(), Pi_minus_tracks[0].itsChi2NCl(), Pi_minus_tracks[1].itsChi2NCl(), + p1.Pt(), p2.Pt(), p3.Pt(), p4.Pt(), + p1.Eta(), p2.Eta(), p3.Eta(), p4.Eta(), + p1.Phi(), p2.Phi(), p3.Phi(), p4.Phi(), + p1.Rapidity(), p2.Rapidity(), p3.Rapidity(), p4.Rapidity(), + p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), + phiPair1, phiPair2, cosThetaPair1, cosThetaPair2); + + if (std::fabs(p1234.Rapidity()) < 0.5) { + histosMCreco.fill(HIST("pT_event_0charge_WTS_PID_Pi"), p1234.Pt()); + if (p1234.Pt() < 0.15) { + histosMCreco.fill(HIST("rapidity_event_0charge_WTS_PID_Pi_domainA"), p1234.Rapidity()); + histosMCreco.fill(HIST("invMass_event_0charge_WTS_PID_Pi_domainA"), p1234.M()); + + histosMCreco.fill(HIST("invMass_pair_1"), (p1 + p3).M()); + histosMCreco.fill(HIST("invMass_pair_2"), (p1 + p4).M()); + histosMCreco.fill(HIST("invMass_pair_3"), (p2 + p3).M()); + histosMCreco.fill(HIST("invMass_pair_4"), (p2 + p4).M()); + + histosMCreco.fill(HIST("CS_phi_pair_1"), phiPair1); + histosMCreco.fill(HIST("CS_phi_pair_2"), phiPair2); + histosMCreco.fill(HIST("CS_costheta_pair_1"), cosThetaPair1); + histosMCreco.fill(HIST("CS_costheta_pair_2"), cosThetaPair2); + histosMCreco.fill(HIST("phi_cosTheta_pair_1"), phiPair1, cosThetaPair1); + histosMCreco.fill(HIST("phi_cosTheta_pair_2"), phiPair2, cosThetaPair2); + } + if (p1234.Pt() > 0.15 && p1234.Pt() < 0.80) { + histosMCreco.fill(HIST("rapidity_event_0charge_WTS_PID_Pi_domainB"), p1234.Rapidity()); + histosMCreco.fill(HIST("invMass_event_0charge_WTS_PID_Pi_domainB"), p1234.M()); + } + if (p1234.Pt() > 0.80) { + histosMCreco.fill(HIST("rapidity_event_0charge_WTS_PID_Pi_domainC"), p1234.Rapidity()); + histosMCreco.fill(HIST("invMass_event_0charge_WTS_PID_Pi_domainC"), p1234.M()); + } + } // End of Rapidity range selection + + } // End of Analysis for 0 charge events + + // Selecting Events with net charge != 0 for estimation of background + if (numPionMinusTRacks != 2 && numPiPlusTracks != 2) { + + TLorentzVector p1, p2, p3, p4, p1234; + p1.SetXYZM(WTS_PID_Pi_tracks[0].px(), WTS_PID_Pi_tracks[0].py(), WTS_PID_Pi_tracks[0].pz(), o2::constants::physics::MassPionCharged); + p2.SetXYZM(WTS_PID_Pi_tracks[1].px(), WTS_PID_Pi_tracks[1].py(), WTS_PID_Pi_tracks[1].pz(), o2::constants::physics::MassPionCharged); + p3.SetXYZM(WTS_PID_Pi_tracks[2].px(), WTS_PID_Pi_tracks[2].py(), WTS_PID_Pi_tracks[2].pz(), o2::constants::physics::MassPionCharged); + p4.SetXYZM(WTS_PID_Pi_tracks[3].px(), WTS_PID_Pi_tracks[3].py(), WTS_PID_Pi_tracks[3].pz(), o2::constants::physics::MassPionCharged); + + p1234 = p1 + p2 + p3 + p4; + + if (std::fabs(p1234.Rapidity()) < 0.5) { + histosMCreco.fill(HIST("pT_event_non0charge_WTS_PID_Pi"), p1234.Pt()); + + if (p1234.Pt() < 0.15) { + histosMCreco.fill(HIST("rapidity_event_non0charge_WTS_PID_Pi_domainA"), p1234.Rapidity()); + histosMCreco.fill(HIST("invMass_event_non0charge_WTS_PID_Pi_domainA"), p1234.M()); + } + if (p1234.Pt() > 0.15 && p1234.Pt() < 0.80) { + histosMCreco.fill(HIST("rapidity_event_non0charge_WTS_PID_Pi_domainB"), p1234.Rapidity()); + histosMCreco.fill(HIST("invMass_event_non0charge_WTS_PID_Pi_domainB"), p1234.M()); + } + if (p1234.Pt() > 0.80) { + histosMCreco.fill(HIST("rapidity_event_non0charge_WTS_PID_Pi_domainC"), p1234.Rapidity()); + histosMCreco.fill(HIST("invMass_event_non0charge_WTS_PID_Pi_domainC"), p1234.M()); + } + } // End of Rapidity range selection + + } // End of Analysis for non 0 charge events + + } // End of 4 Pion Analysis Process function for MC Reconstruction + PROCESS_SWITCH(ExclusiveRhoTo4Pi, processMCrec, "The Process for 4 Pion Analysis from MC Reconstruction", false); + + using FilteredTrackStuff = soa::Filtered>; + using FilteredCollisionStuff = soa::Filtered>; + using FilteredCollisionTotal = FilteredCollisionStuff::iterator; + + void processMCrecFast(FilteredCollisionTotal const& collision, FilteredTrackStuff const& tracks) + { + + if ((tracks.size() != 4) || (!collision.has_udMcCollision())) { + return; + } + + std::vector pionPlusTracks; + std::vector pionMinusTracks; + + for (const auto& track : tracks) { + if ((!selectionPIDPion(track, true, nSigmaTPCcut, nSigmaTOFcut)) || (!track.has_udMcParticle())) { + continue; + } + if (track.sign() == 1) { + pionPlusTracks.push_back(track); + } + if (track.sign() == -1) { + pionMinusTracks.push_back(track); + } + } // end of loop over tracks + + if ((pionPlusTracks.size() + pionMinusTracks.size()) != 4) { + return; + } + + if (pionPlusTracks.size() == 2 || pionMinusTracks.size() == 2) { + + TLorentzVector p1, p2, p3, p4, p1234; + ROOT::Math::PtEtaPhiMVector k1, k2, k3, k4, k1234, k13, k14, k23, k24; + + p1.SetXYZM(pionPlusTracks[0].px(), pionPlusTracks[0].py(), pionPlusTracks[0].pz(), o2::constants::physics::MassPionCharged); + p2.SetXYZM(pionPlusTracks[1].px(), pionPlusTracks[1].py(), pionPlusTracks[1].pz(), o2::constants::physics::MassPionCharged); + p3.SetXYZM(pionMinusTracks[0].px(), pionMinusTracks[0].py(), pionMinusTracks[0].pz(), o2::constants::physics::MassPionCharged); + p4.SetXYZM(pionMinusTracks[1].px(), pionMinusTracks[1].py(), pionMinusTracks[1].pz(), o2::constants::physics::MassPionCharged); + + k1.SetCoordinates(p1.Pt(), p1.Eta(), p1.Phi(), o2::constants::physics::MassPionCharged); + k2.SetCoordinates(p2.Pt(), p2.Eta(), p2.Phi(), o2::constants::physics::MassPionCharged); + k3.SetCoordinates(p3.Pt(), p3.Eta(), p3.Phi(), o2::constants::physics::MassPionCharged); + k4.SetCoordinates(p4.Pt(), p4.Eta(), p4.Phi(), o2::constants::physics::MassPionCharged); + + p1234 = p1 + p2 + p3 + p4; + k1234 = k1 + k2 + k3 + k4; + + k13 = k1 + k3; + k14 = k1 + k4; + k23 = k2 + k3; + k24 = k2 + k4; + + double fourPiPhiPair1 = phiCollinsSoperFrame(k13, k24, k1234); + double fourPiPhiPair2 = phiCollinsSoperFrame(k14, k23, k1234); + double fourPiCosThetaPair1 = cosThetaCollinsSoperFrame(k13, k24, k1234); + double fourPiCosThetaPair2 = cosThetaCollinsSoperFrame(k14, k23, k1234); + + sigFromMC( + collision.posX(), collision.posY(), collision.posZ(), + collision.totalFV0AmplitudeA(), collision.totalFT0AmplitudeA(), collision.totalFT0AmplitudeC(), collision.totalFDDAmplitudeA(), collision.totalFDDAmplitudeC(), + collision.timeFV0A(), collision.timeFT0A(), collision.timeFT0C(), collision.timeFDDA(), collision.timeFDDC(), collision.timeZNA(), collision.timeZNC(), + pionPlusTracks[0].dcaXY(), pionPlusTracks[1].dcaXY(), pionMinusTracks[0].dcaXY(), pionMinusTracks[1].dcaXY(), + + pionPlusTracks[0].dcaZ(), pionPlusTracks[1].dcaZ(), pionMinusTracks[0].dcaZ(), pionMinusTracks[1].dcaZ(), + + pionPlusTracks[0].tpcNSigmaPi(), pionPlusTracks[1].tpcNSigmaPi(), pionMinusTracks[0].tpcNSigmaPi(), pionMinusTracks[1].tpcNSigmaPi(), + + pionPlusTracks[0].tpcNSigmaKa(), pionPlusTracks[1].tpcNSigmaKa(), pionMinusTracks[0].tpcNSigmaKa(), pionMinusTracks[1].tpcNSigmaKa(), + + pionPlusTracks[0].tpcNSigmaPr(), pionPlusTracks[1].tpcNSigmaPr(), pionMinusTracks[0].tpcNSigmaPr(), pionMinusTracks[1].tpcNSigmaPr(), + + pionPlusTracks[0].tpcNSigmaEl(), pionPlusTracks[1].tpcNSigmaEl(), pionMinusTracks[0].tpcNSigmaEl(), pionMinusTracks[1].tpcNSigmaEl(), + + pionPlusTracks[0].tpcNSigmaMu(), pionPlusTracks[1].tpcNSigmaMu(), pionMinusTracks[0].tpcNSigmaMu(), pionMinusTracks[1].tpcNSigmaMu(), + + pionPlusTracks[0].tpcChi2NCl(), pionPlusTracks[1].tpcChi2NCl(), pionMinusTracks[0].tpcChi2NCl(), pionMinusTracks[1].tpcChi2NCl(), + pionPlusTracks[0].tpcNClsFindable(), pionPlusTracks[1].tpcNClsFindable(), pionMinusTracks[0].tpcNClsFindable(), pionMinusTracks[1].tpcNClsFindable(), + pionPlusTracks[0].itsChi2NCl(), pionPlusTracks[1].itsChi2NCl(), pionMinusTracks[0].itsChi2NCl(), pionMinusTracks[1].itsChi2NCl(), + p1.Pt(), p2.Pt(), p3.Pt(), p4.Pt(), + p1.Eta(), p2.Eta(), p3.Eta(), p4.Eta(), + p1.Phi(), p2.Phi(), p3.Phi(), p4.Phi(), + p1.Rapidity(), p2.Rapidity(), p3.Rapidity(), p4.Rapidity(), + p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), + fourPiPhiPair1, fourPiPhiPair2, fourPiCosThetaPair1, fourPiCosThetaPair2); + + histosFastMCreco.fill(HIST("4PionPt"), p1234.Pt()); + histosFastMCreco.fill(HIST("4PionRapidity"), p1234.Rapidity()); + histosFastMCreco.fill(HIST("4PionMassFull"), p1234.M()); + + if ((p1234.Pt() < 0.15) && (std::abs(p1234.Rapidity()) < 0.5)) { + histosFastMCreco.fill(HIST("4PionMassWithCut"), p1234.M()); + } + } // End 0 charge event + } // End of 4 Pion Analysis Process function for Fast MC Reconstruction + + PROCESS_SWITCH(ExclusiveRhoTo4Pi, processMCrecFast, "The Process for 4 Pion Analysis from Fast MC Reconstruction", false); + +}; // End of Struct exclusiveRhoTo4Pi +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/exclusiveTwoProtons.cxx b/PWGUD/Tasks/exclusiveTwoProtons.cxx new file mode 100644 index 00000000000..72032b06906 --- /dev/null +++ b/PWGUD/Tasks/exclusiveTwoProtons.cxx @@ -0,0 +1,453 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "iostream" +#include "PWGUD/DataModel/UDTables.h" +#include +#include "TLorentzVector.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGUD/Core/SGSelector.h" +using std::array; +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// \brief Exclusive proton+proton task +/// \author Simone Ragoni, Creighton +/// \date 29/4/2024 + +struct ExclusiveTwoProtons { + SGSelector sgSelector; + Configurable FV0_cut{"FV0", 100., "FV0A threshold"}; + Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; + // defining histograms using histogram registry + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + //_____________________________________________________________________________ + Double_t CosThetaHelicityFrame(TLorentzVector posDaughter, TLorentzVector negDaughter, TLorentzVector mother) + { + + Double_t HalfSqrtSnn = 2680.; + Double_t MassOfLead208 = 193.6823; + Double_t MomentumBeam = TMath::Sqrt(HalfSqrtSnn * HalfSqrtSnn * 208 * 208 - MassOfLead208 * MassOfLead208); + + TLorentzVector pProjCM(0., 0., -MomentumBeam, HalfSqrtSnn * 208); // projectile + TLorentzVector pTargCM(0., 0., MomentumBeam, HalfSqrtSnn * 208); // target + + TVector3 beta = (-1. / mother.E()) * mother.Vect(); + TLorentzVector pPi1Dipion = posDaughter; + TLorentzVector pPi2Dipion = negDaughter; + TLorentzVector pProjDipion = pProjCM; + TLorentzVector pTargDipion = pTargCM; + + pPi1Dipion.Boost(beta); + pPi2Dipion.Boost(beta); + pProjDipion.Boost(beta); + pTargDipion.Boost(beta); + + TVector3 zaxis = (mother.Vect()).Unit(); + + Double_t CosThetaHE = zaxis.Dot((pPi1Dipion.Vect()).Unit()); + return CosThetaHE; + } + //------------------------------------------------------------------------------------------------------ + Double_t PhiHelicityFrame(TLorentzVector posDaughter, TLorentzVector negDaughter, TLorentzVector mother) + { + + // Half of the energy per pair of the colliding nucleons. + Double_t HalfSqrtSnn = 2680.; + Double_t MassOfLead208 = 193.6823; + Double_t MomentumBeam = TMath::Sqrt(HalfSqrtSnn * HalfSqrtSnn * 208 * 208 - MassOfLead208 * MassOfLead208); + + TLorentzVector pProjCM(0., 0., -MomentumBeam, HalfSqrtSnn * 208); // projectile + TLorentzVector pTargCM(0., 0., MomentumBeam, HalfSqrtSnn * 208); // target + + // Translate the dimuon parameters in the dimuon rest frame + TVector3 beta = (-1. / mother.E()) * mother.Vect(); + TLorentzVector pMu1Dimu = posDaughter; + TLorentzVector pMu2Dimu = negDaughter; + TLorentzVector pProjDimu = pProjCM; + TLorentzVector pTargDimu = pTargCM; + pMu1Dimu.Boost(beta); + pMu2Dimu.Boost(beta); + pProjDimu.Boost(beta); + pTargDimu.Boost(beta); + + // Axes + TVector3 zaxis = (mother.Vect()).Unit(); + TVector3 yaxis = ((pProjDimu.Vect()).Cross(pTargDimu.Vect())).Unit(); + TVector3 xaxis = (yaxis.Cross(zaxis)).Unit(); + // + // --- Calculation of the azimuthal angle (Helicity) + // + Double_t phi = TMath::ATan2((pMu1Dimu.Vect()).Dot(yaxis), (pMu1Dimu.Vect()).Dot(xaxis)); + return phi; + } + //----------------------------------------------------------------------------------------------------------------------- + void init(o2::framework::InitContext&) + { + registry.add("hITSCluster", "N_{cluster}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hChi2ITSTrkSegment", "N_{cluster}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hTPCCluster", "N_{cluster}", kTH1F, {{200, -0.5, 199.5}}); + registry.add("hdEdx", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdx2", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdSigmaProton", "p vs dE/dx sigma proton", kTH2F, {{100, 0.0, 3.0}, {1000, -500.0, 500.0}}); + registry.add("hdSigmaProton2", "p vs dE/dx sigma proton", kTH2F, {{100, 0.0, 3.0}, {1000, -500.0, 500.0}}); + registry.add("hdSigmaProton3", "p vs dE/dx sigma proton", kTH2F, {{100, 0.0, 3.0}, {1000, -500.0, 500.0}}); + registry.add("hNsigEvsKa1", "NSigma(t1) vs NSigma (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); + registry.add("hNsigEvsKa2", "NSigma(t1) vs NSigma (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); + registry.add("hNsigEvsKa3", "NSigma(t1) vs NSigma (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); + registry.add("hMomentum", "p_{#ka};#it{p_{trk}}, GeV/c;", kTH1F, {{100, 0., 3.}}); + registry.add("hClusterSizeAllTracks", "ClusterSizeAllTracks;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeProtonsTPC", "ClusterSizeProtonsTPC;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeProtonsTOF", "ClusterSizeProtonsTOF;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hEta1", "#eta_{#ka};#it{#eta_{trk}}, GeV/c;", kTH1F, {{100, -2., 2.}}); + registry.add("hPtLikeSignProton", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("hMassLikeSignProton", "Raw Inv.M;#it{m_{pp}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("hMassPtLikeSignProton", "Raw Inv.M;#it{m_{PP}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{1000, 0., 10.}, {400, 0., 4.}}); + + auto hSelectionCounter = registry.add("hSelectionCounter", "hSelectionCounter;;NEvents", HistType::kTH1I, {{10, 0., 10.}}); + + TString SelectionCuts[9] = {"NoSelection", "GAPcondition", "PVtracks", "Good TPC-ITS track", "TPC/TOF PID track", "End trk loop", "Exactly 2p", "Like-sign ev", "Unlike-sign ev"}; + // now we can set BinLabel in histogram Registry + + for (int i = 0; i < 9; i++) { + hSelectionCounter->GetXaxis()->SetBinLabel(i + 1, SelectionCuts[i].Data()); + } + + // Unlike sign pp + registry.add("PP/hRapidity", "Rapidity;#it{y_{pp}};", kTH1F, {{100, -2., 2.}}); + registry.add("PP/hPtProtonVsProton", "Pt1 vs Pt2;p_{T};p_{T};", kTH2F, {{100, 0., 3.}, {100, 0., 3.}}); + registry.add("PP/hMassPtUnlikeSignProton", "Raw Inv.M;#it{m_{pp}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("PP/hMassUnlike", "#it{m_{pp}} [GeV/#it{c}^{2}]", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hMassHighPt0150", "#it{m_{pp}} [GeV/#it{c}^{2}]", kTH1F, {{2000, 0., 20.}}); + registry.add("PP/hMassHighPt0200", "#it{m_{pp}} [GeV/#it{c}^{2}]", kTH1F, {{2000, 0., 20.}}); + registry.add("PP/hMassHighPt0300", "#it{m_{pp}} [GeV/#it{c}^{2}]", kTH1F, {{2000, 0., 20.}}); + registry.add("PP/hMassHighPt0500", "#it{m_{pp}} [GeV/#it{c}^{2}]", kTH1F, {{2000, 0., 20.}}); + registry.add("PP/hMassHighPt1000", "#it{m_{pp}} [GeV/#it{c}^{2}]", kTH1F, {{2000, 0., 20.}}); + registry.add("PP/hUnlikePt", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PP/hCoherentMass", "Raw Inv.M;#it{m_{pp}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hCoherentMassWithoutDCAcuts", "Raw Inv.M;#it{m_{pp}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hCoherentMassWithoutDCAxycut", "Raw Inv.M;#it{m_{pp}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hCoherentMassWithoutDCAzcut", "Raw Inv.M;#it{m_{pp}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hUnlikePtLowBand", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PP/hUnlikePtLowBand24to275", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PP/hUnlikePtLowBand275to300", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PP/hUnlikePtHighBand", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PP/hUnlikePtJpsi", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + + registry.add("PP/hAngularDstribLab", "Angular distrib in the lab system;#it{#varphi};#it{Cos#Theta};", kTH2F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}, {100, -2, 2}}); + registry.add("PP/hCosThetaLab", "Angular distrib in the lab system;#it{Cos#Theta};", kTH1F, {{100, -2, 2}}); + registry.add("PP/hAngularDistribHelicity", "Angular distrib helicity frame;#it{#varphi};#it{Cos#Theta};", kTH2F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}, {100, -2, 2}}); + registry.add("PP/hCosThetaHelicity", "Angular distrib helicity frame;#it{Cos#Theta};", kTH1F, {{100, -2, 2}}); + registry.add("PP/hPhiHelicity", "Angular distrib helicity frame;#it{#varphi};", kTH1F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + } + + using udtracks = soa::Join; + // using udtracksfull = soa::Join; + using udtracksfull = soa::Join; + //__________________________________________________________________________ + // Main process + void process(UDCollisions::iterator const& /*collision*/, udtracksfull const& tracks) + // void process(UDCollisionsFull::iterator const& collision, udtracksfull const& tracks) + { + registry.fill(HIST("hSelectionCounter"), 0); + TLorentzVector resonance; // lorentz vectors of tracks and the mother + + // =================================== + // Task for p+pbar pairs with PID + // =================================== + std::vector onlyProtonTracks; + std::vector onlyProtonTracksTOF; + std::vector onlyProtonSigma; + std::vector onlyProtonSigmaTOF; + std::vector rawProtonTracks; + std::vector rawProtonTracksTOF; + + for (auto trk : tracks) { + if (!trk.isPVContributor()) { + continue; + } + registry.fill(HIST("hSelectionCounter"), 2); + + int NFindable = trk.tpcNClsFindable(); + int NMinusFound = trk.tpcNClsFindableMinusFound(); + int NCluster = NFindable - NMinusFound; + registry.fill(HIST("hTPCCluster"), NCluster); + registry.fill(HIST("hChi2ITSTrkSegment"), trk.itsChi2NCl()); + if (NCluster < 70) { + continue; + } + if (trk.itsNCls() < 7) { + continue; + } + if (!(std::abs(trk.dcaZ()) < 2.)) { + continue; + } + double dcaLimit = 0.0105 + 0.035 / pow(trk.pt(), 1.1); + if (!(std::abs(trk.dcaXY()) < dcaLimit)) { + continue; + } + registry.fill(HIST("hSelectionCounter"), 3); + registry.fill(HIST("hITSCluster"), trk.itsNCls()); + + int clusterSize[7]; + double averageClusterSize = 0.; + for (int i = 0; i < 7; i++) { // info stored in 4 bits + clusterSize[i] = (((1 << 4) - 1) & (trk.itsClusterSizes() >> 4 * i)); + averageClusterSize += static_cast(clusterSize[i]); + } + averageClusterSize /= 7.; + registry.fill(HIST("hClusterSizeAllTracks"), averageClusterSize); + + double momentum = TMath::Sqrt(trk.px() * trk.px() + trk.py() * trk.py() + trk.pz() * trk.pz()); + double dEdx = trk.tpcSignal(); + registry.fill(HIST("hdEdx"), momentum, dEdx); + + TLorentzVector proton; + proton.SetXYZM(trk.px(), trk.py(), trk.pz(), o2::constants::physics::MassProton); + TLorentzVector protonbar; + protonbar.SetXYZM(trk.px(), trk.py(), trk.pz(), o2::constants::physics::MassProtonBar); + auto nSigmaPr = trk.tpcNSigmaPr(); + auto nSigmaPrTOF = trk.tofNSigmaPr(); + + if (trk.hasTOF()) { + registry.fill(HIST("hdSigmaProton"), momentum, nSigmaPrTOF); + } + if (fabs(nSigmaPr) < 4.) { + registry.fill(HIST("hdEdx2"), momentum, dEdx); + registry.fill(HIST("hdSigmaProton2"), momentum, nSigmaPr); + registry.fill(HIST("hMomentum"), momentum); + if (trk.hasTOF() && fabs(nSigmaPrTOF) < 4.) { + registry.fill(HIST("hdSigmaProton3"), momentum, nSigmaPrTOF); + registry.fill(HIST("hClusterSizeProtonsTOF"), averageClusterSize); + onlyProtonTracksTOF.push_back(proton); + onlyProtonSigmaTOF.push_back(nSigmaPrTOF); + rawProtonTracksTOF.push_back(trk); + } else if (!trk.hasTOF()) { + onlyProtonTracks.push_back(proton); + onlyProtonSigma.push_back(nSigmaPr); + rawProtonTracks.push_back(trk); + } + registry.fill(HIST("hSelectionCounter"), 4); + registry.fill(HIST("hClusterSizeProtonsTPC"), averageClusterSize); + } + + } // trk loop + + registry.fill(HIST("hSelectionCounter"), 5); + if ((onlyProtonTracksTOF.size() > 0) && (onlyProtonTracks.size() + onlyProtonTracksTOF.size()) == 2) { + registry.fill(HIST("hSelectionCounter"), 6); + + int signSum = -999.; + double sigmaTotal = -999.; + TLorentzVector a, b; + int positiveFlag = -1; + // double dcaZ[2] = {-99., -99.}; + // double dcaXY[2] = {-99., -99.}; + int dcaZbool = -1; + int dcaXYbool = -1; + if (onlyProtonTracksTOF.size() == 1) { + + if (!(fabs(onlyProtonTracks[0].Eta()) < 0.8 && fabs(onlyProtonTracksTOF[0].Eta()) < 0.8)) { + return; + } + registry.fill(HIST("hEta1"), onlyProtonTracks[0].Eta()); + registry.fill(HIST("hEta1"), onlyProtonTracksTOF[0].Eta()); + resonance += onlyProtonTracks[0]; + resonance += onlyProtonTracksTOF[0]; + a = onlyProtonTracks[0]; + b = onlyProtonTracksTOF[0]; + sigmaTotal = 0; + sigmaTotal = onlyProtonSigma[0] * onlyProtonSigma[0] + onlyProtonSigmaTOF[0] * onlyProtonSigmaTOF[0]; + ; + registry.fill(HIST("hNsigEvsKa1"), onlyProtonSigma[0], onlyProtonSigmaTOF[0]); + signSum = rawProtonTracks[0].sign() + rawProtonTracksTOF[0].sign(); + if (signSum == 0) { + registry.fill(HIST("PP/hPtProtonVsProton"), onlyProtonTracks[0].Pt(), onlyProtonTracksTOF[0].Pt()); + if (rawProtonTracks[0].sign() == 1) { + positiveFlag = 1; + } else { + positiveFlag = 2; + } + } + + // // DCA checks + // dcaZ[0] = rawProtonTracks[0].dcaZ(); + // dcaZ[1] = rawProtonTracksTOF[0].dcaZ(); + // dcaXY[0] = rawProtonTracks[0].dcaXY(); + // dcaXY[1] = rawProtonTracksTOF[0].dcaXY(); + // if (std::abs(dcaZ[0]) < 2. && std::abs(dcaZ[1]) < 2.) { + // dcaZbool = 1; + // } else { + // dcaZbool = 0; + // } + // double dcaLimit[2] = {-99., -99.}; + // dcaLimit[0] = 0.0105 + 0.035 / pow(a.Pt(), 1.1); + // dcaLimit[1] = 0.0105 + 0.035 / pow(b.Pt(), 1.1); + // if (std::abs(dcaXY[0]) < dcaLimit[0] && std::abs(dcaXY[1]) < dcaLimit[1]) { + // dcaXYbool = 1; + // } else { + // dcaXYbool = 0; + // } + } else if (onlyProtonTracksTOF.size() == 2) { + + if (!(fabs(onlyProtonTracksTOF[0].Eta()) < 0.8 && fabs(onlyProtonTracksTOF[1].Eta()) < 0.8)) { + return; + } + registry.fill(HIST("hEta1"), onlyProtonTracksTOF[0].Eta()); + registry.fill(HIST("hEta1"), onlyProtonTracksTOF[1].Eta()); + resonance += onlyProtonTracksTOF[0]; + resonance += onlyProtonTracksTOF[1]; + a = onlyProtonTracksTOF[0]; + b = onlyProtonTracksTOF[1]; + sigmaTotal = 0; + sigmaTotal = onlyProtonSigmaTOF[0] * onlyProtonSigmaTOF[0] + onlyProtonSigmaTOF[1] * onlyProtonSigmaTOF[1]; + ; + registry.fill(HIST("hNsigEvsKa1"), onlyProtonSigmaTOF[0], onlyProtonSigmaTOF[1]); + signSum = rawProtonTracksTOF[0].sign() + rawProtonTracksTOF[1].sign(); + if (signSum == 0) { + registry.fill(HIST("PP/hPtProtonVsProton"), onlyProtonTracksTOF[0].Pt(), onlyProtonTracksTOF[1].Pt()); + if (rawProtonTracksTOF[0].sign() == 1) { + positiveFlag = 1; + } else { + positiveFlag = 2; + } + } + + // // DCA checks + // dcaZ[0] = rawProtonTracksTOF[0].dcaZ(); + // dcaZ[1] = rawProtonTracksTOF[1].dcaZ(); + // dcaXY[0] = rawProtonTracksTOF[0].dcaXY(); + // dcaXY[1] = rawProtonTracksTOF[1].dcaXY(); + // if (std::abs(dcaZ[0]) < 2. && std::abs(dcaZ[1]) < 2.) { + // dcaZbool = 1; + // } else { + // dcaZbool = 0; + // } + // double dcaLimit[2] = {-99., -99.}; + // dcaLimit[0] = 0.0105 + 0.035 / pow(a.Pt(), 1.1); + // dcaLimit[1] = 0.0105 + 0.035 / pow(b.Pt(), 1.1); + // if (std::abs(dcaXY[0]) < dcaLimit[0] && std::abs(dcaXY[1]) < dcaLimit[1]) { + // dcaXYbool = 1; + // } else { + // dcaXYbool = 0; + // } + } + + if (sigmaTotal > 16.) { + return; + } + if (onlyProtonTracksTOF.size() == 1) { + registry.fill(HIST("hNsigEvsKa2"), onlyProtonSigma[0], onlyProtonSigmaTOF[0]); + } else if (onlyProtonTracksTOF.size() == 2) { + registry.fill(HIST("hNsigEvsKa2"), onlyProtonSigmaTOF[0], onlyProtonSigmaTOF[1]); + } + + if (signSum != 0) { + registry.fill(HIST("hMassPtLikeSignProton"), resonance.M(), resonance.Pt()); + registry.fill(HIST("hSelectionCounter"), 7); + registry.fill(HIST("hPtLikeSignProton"), resonance.Pt()); + registry.fill(HIST("hMassLikeSignProton"), resonance.M()); + } else { + registry.fill(HIST("PP/hMassPtUnlikeSignProton"), resonance.M(), resonance.Pt()); + registry.fill(HIST("hSelectionCounter"), 8); + registry.fill(HIST("PP/hUnlikePt"), resonance.Pt()); + registry.fill(HIST("PP/hMassUnlike"), resonance.M()); + registry.fill(HIST("PP/hRapidity"), resonance.Rapidity()); + if (resonance.Pt() < 0.15) { + // registry.fill(HIST("PP/hCoherentMassWithoutDCAcuts"), resonance.M()); + // if (dcaZbool == 1) { + // registry.fill(HIST("PP/hCoherentMassWithoutDCAxycut"), resonance.M()); + // } + // if (dcaXYbool == 1) { + // registry.fill(HIST("PP/hCoherentMassWithoutDCAzcut"), resonance.M()); + // } + // } + // if (resonance.Pt() < 0.15 && dcaZbool == 1 && dcaXYbool == 1) { + registry.fill(HIST("PP/hCoherentMass"), resonance.M()); + if (resonance.M() < 3.0) { + registry.fill(HIST("PP/hAngularDstribLab"), a.Phi() + TMath::Pi(), a.CosTheta()); + registry.fill(HIST("PP/hAngularDstribLab"), b.Phi() + TMath::Pi(), b.CosTheta()); + registry.fill(HIST("PP/hCosThetaLab"), a.CosTheta()); + registry.fill(HIST("PP/hCosThetaLab"), b.CosTheta()); + } + double costhetaHel = -999.; + double phiHel = -999.; + if (positiveFlag == 1 && (resonance.M() > 2.4 && resonance.M() < 3.)) { + costhetaHel = CosThetaHelicityFrame(a, b, resonance); + phiHel = 1. * TMath::Pi() + PhiHelicityFrame(a, b, resonance); + registry.fill(HIST("PP/hAngularDistribHelicity"), phiHel, costhetaHel); + registry.fill(HIST("PP/hCosThetaHelicity"), costhetaHel); + registry.fill(HIST("PP/hPhiHelicity"), phiHel); + } else if (positiveFlag == 2 && (resonance.M() > 2.4 && resonance.M() < 3.)) { + costhetaHel = CosThetaHelicityFrame(b, a, resonance); + phiHel = 1. * TMath::Pi() + PhiHelicityFrame(b, a, resonance); + registry.fill(HIST("PP/hAngularDistribHelicity"), phiHel, costhetaHel); + registry.fill(HIST("PP/hCosThetaHelicity"), costhetaHel); + registry.fill(HIST("PP/hPhiHelicity"), phiHel); + } + } + // outside the hard pT cut, but with opposite charges + dcaZbool = 1; + dcaXYbool = 1; + if (dcaZbool == 1 && dcaXYbool == 1) { + if (resonance.M() > 2.4 && resonance.M() < 2.75) { + registry.fill(HIST("PP/hUnlikePtLowBand24to275"), resonance.Pt()); + registry.fill(HIST("PP/hUnlikePtLowBand"), resonance.Pt()); + } else if (resonance.M() > 2.75 && resonance.M() < 3.) { + registry.fill(HIST("PP/hUnlikePtLowBand275to300"), resonance.Pt()); + registry.fill(HIST("PP/hUnlikePtLowBand"), resonance.Pt()); + } else if (resonance.M() > 3.0 && resonance.M() < 3.15) { + registry.fill(HIST("PP/hUnlikePtJpsi"), resonance.Pt()); + } else if (resonance.M() > 3.15 && resonance.M() < 3.4) { + registry.fill(HIST("PP/hUnlikePtHighBand"), resonance.Pt()); + } + + // high mass states + if (resonance.M() > 4.) { + if (onlyProtonTracksTOF.size() == 1) { + registry.fill(HIST("hNsigEvsKa3"), onlyProtonSigma[0], onlyProtonSigmaTOF[0]); + } else if (onlyProtonTracksTOF.size() == 2) { + registry.fill(HIST("hNsigEvsKa3"), onlyProtonSigmaTOF[0], onlyProtonSigmaTOF[1]); + } + if (resonance.Pt() < 0.15) { + registry.fill(HIST("PP/hMassHighPt0150"), resonance.M()); + } + if (resonance.Pt() < 0.20) { + registry.fill(HIST("PP/hMassHighPt0200"), resonance.M()); + } + if (resonance.Pt() < 0.30) { + registry.fill(HIST("PP/hMassHighPt0300"), resonance.M()); + } + if (resonance.Pt() < 0.50) { + registry.fill(HIST("PP/hMassHighPt0500"), resonance.M()); + } + if (resonance.Pt() < 1.00) { + registry.fill(HIST("PP/hMassHighPt1000"), resonance.M()); + } + } + } + } + } + + } // end of process + +}; // end of struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/exclusiveTwoProtonsSG.cxx b/PWGUD/Tasks/exclusiveTwoProtonsSG.cxx new file mode 100644 index 00000000000..0e0aa7c83dd --- /dev/null +++ b/PWGUD/Tasks/exclusiveTwoProtonsSG.cxx @@ -0,0 +1,479 @@ +// 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. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "iostream" +#include "PWGUD/DataModel/UDTables.h" +#include +#include "TLorentzVector.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGUD/Core/SGSelector.h" +using std::array; +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// \brief Exclusive proton+proton task +/// \author Simone Ragoni, Creighton +/// \date 29/4/2024 + +struct ExclusiveTwoProtonsSG { + SGSelector sgSelector; + Configurable FV0_cut{"FV0", 100., "FV0A threshold"}; + Configurable FT0A_cut{"FT0A", 200., "FT0A threshold"}; + Configurable FT0C_cut{"FT0C", 100., "FT0C threshold"}; + Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; + Configurable gap_Side{"gap", 2, "gap selection"}; + // defining histograms using histogram registry + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + //_____________________________________________________________________________ + Double_t CosThetaHelicityFrame(TLorentzVector posDaughter, TLorentzVector negDaughter, TLorentzVector mother) + { + + Double_t HalfSqrtSnn = 2680.; + Double_t MassOfLead208 = 193.6823; + Double_t MomentumBeam = TMath::Sqrt(HalfSqrtSnn * HalfSqrtSnn * 208 * 208 - MassOfLead208 * MassOfLead208); + + TLorentzVector pProjCM(0., 0., -MomentumBeam, HalfSqrtSnn * 208); // projectile + TLorentzVector pTargCM(0., 0., MomentumBeam, HalfSqrtSnn * 208); // target + + TVector3 beta = (-1. / mother.E()) * mother.Vect(); + TLorentzVector pPi1Dipion = posDaughter; + TLorentzVector pPi2Dipion = negDaughter; + TLorentzVector pProjDipion = pProjCM; + TLorentzVector pTargDipion = pTargCM; + + pPi1Dipion.Boost(beta); + pPi2Dipion.Boost(beta); + pProjDipion.Boost(beta); + pTargDipion.Boost(beta); + + TVector3 zaxis = (mother.Vect()).Unit(); + + Double_t CosThetaHE = zaxis.Dot((pPi1Dipion.Vect()).Unit()); + return CosThetaHE; + } + //------------------------------------------------------------------------------------------------------ + Double_t PhiHelicityFrame(TLorentzVector posDaughter, TLorentzVector negDaughter, TLorentzVector mother) + { + + // Half of the energy per pair of the colliding nucleons. + Double_t HalfSqrtSnn = 2680.; + Double_t MassOfLead208 = 193.6823; + Double_t MomentumBeam = TMath::Sqrt(HalfSqrtSnn * HalfSqrtSnn * 208 * 208 - MassOfLead208 * MassOfLead208); + + TLorentzVector pProjCM(0., 0., -MomentumBeam, HalfSqrtSnn * 208); // projectile + TLorentzVector pTargCM(0., 0., MomentumBeam, HalfSqrtSnn * 208); // target + + // Translate the dimuon parameters in the dimuon rest frame + TVector3 beta = (-1. / mother.E()) * mother.Vect(); + TLorentzVector pMu1Dimu = posDaughter; + TLorentzVector pMu2Dimu = negDaughter; + TLorentzVector pProjDimu = pProjCM; + TLorentzVector pTargDimu = pTargCM; + pMu1Dimu.Boost(beta); + pMu2Dimu.Boost(beta); + pProjDimu.Boost(beta); + pTargDimu.Boost(beta); + + // Axes + TVector3 zaxis = (mother.Vect()).Unit(); + TVector3 yaxis = ((pProjDimu.Vect()).Cross(pTargDimu.Vect())).Unit(); + TVector3 xaxis = (yaxis.Cross(zaxis)).Unit(); + // + // --- Calculation of the azimuthal angle (Helicity) + // + Double_t phi = TMath::ATan2((pMu1Dimu.Vect()).Dot(yaxis), (pMu1Dimu.Vect()).Dot(xaxis)); + return phi; + } + //----------------------------------------------------------------------------------------------------------------------- + void init(o2::framework::InitContext&) + { + registry.add("GapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + registry.add("TrueGapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + registry.add("posx", "Vertex position in x", kTH1F, {{100, -0.5, 0.5}}); + registry.add("posy", "Vertex position in y", kTH1F, {{100, -0.5, 0.5}}); + registry.add("posz", "Vertex position in z", kTH1F, {{1000, -100., 100.}}); + registry.add("hITSCluster", "N_{cluster}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hChi2ITSTrkSegment", "N_{cluster}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hTPCCluster", "N_{cluster}", kTH1F, {{200, -0.5, 199.5}}); + registry.add("hdEdx", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdx2", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdSigmaProton", "p vs dE/dx sigma proton", kTH2F, {{100, 0.0, 3.0}, {1000, -500.0, 500.0}}); + registry.add("hdSigmaProton2", "p vs dE/dx sigma proton", kTH2F, {{100, 0.0, 3.0}, {1000, -500.0, 500.0}}); + registry.add("hdSigmaProton3", "p vs dE/dx sigma proton", kTH2F, {{100, 0.0, 3.0}, {1000, -500.0, 500.0}}); + registry.add("hNsigEvsKa1", "NSigma(t1) vs NSigma (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); + registry.add("hNsigEvsKa2", "NSigma(t1) vs NSigma (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); + registry.add("hNsigEvsKa3", "NSigma(t1) vs NSigma (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); + registry.add("hMomentum", "p_{#ka};#it{p_{trk}}, GeV/c;", kTH1F, {{100, 0., 3.}}); + registry.add("hClusterSizeAllTracks", "ClusterSizeAllTracks;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeProtonsTPC", "ClusterSizeProtonsTPC;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeProtonsTOF", "ClusterSizeProtonsTOF;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hEta1", "#eta_{#ka};#it{#eta_{trk}}, GeV/c;", kTH1F, {{100, -2., 2.}}); + registry.add("hPtLikeSignProton", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("hMassLikeSignProton", "Raw Inv.M;#it{m_{pp}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("hMassPtLikeSignProton", "Raw Inv.M;#it{m_{PP}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{1000, 0., 10.}, {400, 0., 4.}}); + + auto hSelectionCounter = registry.add("hSelectionCounter", "hSelectionCounter;;NEvents", HistType::kTH1I, {{10, 0., 10.}}); + + TString SelectionCuts[9] = {"NoSelection", "GAPcondition", "PVtracks", "Good TPC-ITS track", "TPC/TOF PID track", "End trk loop", "Exactly 2p", "Like-sign ev", "Unlike-sign ev"}; + // now we can set BinLabel in histogram Registry + + for (int i = 0; i < 9; i++) { + hSelectionCounter->GetXaxis()->SetBinLabel(i + 1, SelectionCuts[i].Data()); + } + + // Unlike sign pp + registry.add("PP/hRapidity", "Rapidity;#it{y_{pp}};", kTH1F, {{100, -2., 2.}}); + registry.add("PP/hPtProtonVsProton", "Pt1 vs Pt2;p_{T};p_{T};", kTH2F, {{100, 0., 3.}, {100, 0., 3.}}); + registry.add("PP/hMassPtUnlikeSignProton", "Raw Inv.M;#it{m_{pp}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("PP/hMassUnlike", "#it{m_{pp}} [GeV/#it{c}^{2}]", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hMassHighPt0150", "#it{m_{pp}} [GeV/#it{c}^{2}]", kTH1F, {{2000, 0., 20.}}); + registry.add("PP/hMassHighPt0200", "#it{m_{pp}} [GeV/#it{c}^{2}]", kTH1F, {{2000, 0., 20.}}); + registry.add("PP/hMassHighPt0300", "#it{m_{pp}} [GeV/#it{c}^{2}]", kTH1F, {{2000, 0., 20.}}); + registry.add("PP/hMassHighPt0500", "#it{m_{pp}} [GeV/#it{c}^{2}]", kTH1F, {{2000, 0., 20.}}); + registry.add("PP/hMassHighPt1000", "#it{m_{pp}} [GeV/#it{c}^{2}]", kTH1F, {{2000, 0., 20.}}); + registry.add("PP/hUnlikePt", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PP/hCoherentMass", "Raw Inv.M;#it{m_{pp}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hCoherentMassWithoutDCAcuts", "Raw Inv.M;#it{m_{pp}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hCoherentMassWithoutDCAxycut", "Raw Inv.M;#it{m_{pp}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hCoherentMassWithoutDCAzcut", "Raw Inv.M;#it{m_{pp}}, GeV/c^{2};", kTH1F, {{1000, 0., 10.}}); + registry.add("PP/hUnlikePtLowBand", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PP/hUnlikePtLowBand24to275", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PP/hUnlikePtLowBand275to300", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PP/hUnlikePtHighBand", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PP/hUnlikePtJpsi", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + + registry.add("PP/hAngularDstribLab", "Angular distrib in the lab system;#it{#varphi};#it{Cos#Theta};", kTH2F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}, {100, -2, 2}}); + registry.add("PP/hCosThetaLab", "Angular distrib in the lab system;#it{Cos#Theta};", kTH1F, {{100, -2, 2}}); + registry.add("PP/hAngularDistribHelicity", "Angular distrib helicity frame;#it{#varphi};#it{Cos#Theta};", kTH2F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}, {100, -2, 2}}); + registry.add("PP/hCosThetaHelicity", "Angular distrib helicity frame;#it{Cos#Theta};", kTH1F, {{100, -2, 2}}); + registry.add("PP/hPhiHelicity", "Angular distrib helicity frame;#it{#varphi};", kTH1F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + } + + using udtracks = soa::Join; + using udtracksfull = soa::Join; + using UDCollisionsFull = soa::Join; + //__________________________________________________________________________ + // Main process + void process(UDCollisionsFull::iterator const& collision, udtracksfull const& tracks) + { + registry.fill(HIST("hSelectionCounter"), 0); + int gapSide = collision.gapSide(); + if (gapSide < 0 || gapSide > 2) + return; + + registry.fill(HIST("posx"), collision.posX()); + registry.fill(HIST("posy"), collision.posY()); + registry.fill(HIST("posz"), collision.posZ()); + int truegapSide = sgSelector.trueGap(collision, FV0_cut, FT0A_cut, FT0C_cut, ZDC_cut); + registry.fill(HIST("GapSide"), gapSide); + registry.fill(HIST("TrueGapSide"), truegapSide); + gapSide = truegapSide; + if (gapSide != gap_Side) { + return; + } + TLorentzVector resonance; // lorentz vectors of tracks and the mother + + // =================================== + // Task for p+pbar pairs with PID + // =================================== + std::vector onlyProtonTracks; + std::vector onlyProtonTracksTOF; + std::vector onlyProtonSigma; + std::vector onlyProtonSigmaTOF; + std::vector rawProtonTracks; + std::vector rawProtonTracksTOF; + + for (auto trk : tracks) { + if (!trk.isPVContributor()) { + continue; + } + registry.fill(HIST("hSelectionCounter"), 2); + + int NFindable = trk.tpcNClsFindable(); + int NMinusFound = trk.tpcNClsFindableMinusFound(); + int NCluster = NFindable - NMinusFound; + registry.fill(HIST("hTPCCluster"), NCluster); + registry.fill(HIST("hChi2ITSTrkSegment"), trk.itsChi2NCl()); + if (NCluster < 70) { + continue; + } + if (trk.itsNCls() < 7) { + continue; + } + if (trk.pt() < 0.7) { + continue; + } + if (!(std::abs(trk.dcaZ()) < 2.)) { + continue; + } + double dcaLimit = 0.0105 + 0.035 / pow(trk.pt(), 1.1); + if (!(std::abs(trk.dcaXY()) < dcaLimit)) { + continue; + } + + registry.fill(HIST("hSelectionCounter"), 3); + registry.fill(HIST("hITSCluster"), trk.itsNCls()); + + int clusterSize[7]; + double averageClusterSize = 0.; + for (int i = 0; i < 7; i++) { // info stored in 4 bits + clusterSize[i] = (((1 << 4) - 1) & (trk.itsClusterSizes() >> 4 * i)); + averageClusterSize += static_cast(clusterSize[i]); + } + averageClusterSize /= 7.; + registry.fill(HIST("hClusterSizeAllTracks"), averageClusterSize); + + double momentum = TMath::Sqrt(trk.px() * trk.px() + trk.py() * trk.py() + trk.pz() * trk.pz()); + double dEdx = trk.tpcSignal(); + registry.fill(HIST("hdEdx"), momentum, dEdx); + + TLorentzVector proton; + proton.SetXYZM(trk.px(), trk.py(), trk.pz(), o2::constants::physics::MassProton); + TLorentzVector protonbar; + protonbar.SetXYZM(trk.px(), trk.py(), trk.pz(), o2::constants::physics::MassProtonBar); + auto nSigmaPr = trk.tpcNSigmaPr(); + auto nSigmaPrTOF = trk.tofNSigmaPr(); + + if (trk.hasTOF()) { + registry.fill(HIST("hdSigmaProton"), momentum, nSigmaPrTOF); + } + if (fabs(nSigmaPr) < 4.) { + registry.fill(HIST("hdEdx2"), momentum, dEdx); + registry.fill(HIST("hdSigmaProton2"), momentum, nSigmaPr); + registry.fill(HIST("hMomentum"), momentum); + if (trk.hasTOF() && fabs(nSigmaPrTOF) < 4.) { + registry.fill(HIST("hdSigmaProton3"), momentum, nSigmaPrTOF); + registry.fill(HIST("hClusterSizeProtonsTOF"), averageClusterSize); + onlyProtonTracksTOF.push_back(proton); + onlyProtonSigmaTOF.push_back(nSigmaPrTOF); + rawProtonTracksTOF.push_back(trk); + } else if (!trk.hasTOF()) { + onlyProtonTracks.push_back(proton); + onlyProtonSigma.push_back(nSigmaPr); + rawProtonTracks.push_back(trk); + } + registry.fill(HIST("hSelectionCounter"), 4); + registry.fill(HIST("hClusterSizeProtonsTPC"), averageClusterSize); + } + + } // trk loop + + registry.fill(HIST("hSelectionCounter"), 5); + if ((onlyProtonTracksTOF.size() > 0) && (onlyProtonTracks.size() + onlyProtonTracksTOF.size()) == 2) { + registry.fill(HIST("hSelectionCounter"), 6); + + int signSum = -999.; + double sigmaTotal = -999.; + TLorentzVector a, b; + int positiveFlag = -1; + // double dcaZ[2] = {-99., -99.}; + // double dcaXY[2] = {-99., -99.}; + // int dcaZbool = -1; + // int dcaXYbool = -1; + int dcaZbool = 1; + int dcaXYbool = 1; + if (onlyProtonTracksTOF.size() == 1) { + + if (!(fabs(onlyProtonTracks[0].Eta()) < 0.8 && fabs(onlyProtonTracksTOF[0].Eta()) < 0.8)) { + return; + } + registry.fill(HIST("hEta1"), onlyProtonTracks[0].Eta()); + registry.fill(HIST("hEta1"), onlyProtonTracksTOF[0].Eta()); + resonance += onlyProtonTracks[0]; + resonance += onlyProtonTracksTOF[0]; + a = onlyProtonTracks[0]; + b = onlyProtonTracksTOF[0]; + sigmaTotal = 0; + sigmaTotal = onlyProtonSigma[0] * onlyProtonSigma[0] + onlyProtonSigmaTOF[0] * onlyProtonSigmaTOF[0]; + ; + registry.fill(HIST("hNsigEvsKa1"), onlyProtonSigma[0], onlyProtonSigmaTOF[0]); + signSum = rawProtonTracks[0].sign() + rawProtonTracksTOF[0].sign(); + if (signSum == 0) { + registry.fill(HIST("PP/hPtProtonVsProton"), onlyProtonTracks[0].Pt(), onlyProtonTracksTOF[0].Pt()); + if (rawProtonTracks[0].sign() == 1) { + positiveFlag = 1; + } else { + positiveFlag = 2; + } + } + + // // DCA checks + // dcaZ[0] = rawProtonTracks[0].dcaZ(); + // dcaZ[1] = rawProtonTracksTOF[0].dcaZ(); + // dcaXY[0] = rawProtonTracks[0].dcaXY(); + // dcaXY[1] = rawProtonTracksTOF[0].dcaXY(); + // if (std::abs(dcaZ[0]) < 2. && std::abs(dcaZ[1]) < 2.) { + // dcaZbool = 1; + // } else { + // dcaZbool = 0; + // } + // double dcaLimit[2] = {-99., -99.}; + // dcaLimit[0] = 0.0105 + 0.035 / pow(a.Pt(), 1.1); + // dcaLimit[1] = 0.0105 + 0.035 / pow(b.Pt(), 1.1); + // if (std::abs(dcaXY[0]) < dcaLimit[0] && std::abs(dcaXY[1]) < dcaLimit[1]) { + // dcaXYbool = 1; + // } else { + // dcaXYbool = 0; + // } + + } else if (onlyProtonTracksTOF.size() == 2) { + + if (!(fabs(onlyProtonTracksTOF[0].Eta()) < 0.8 && fabs(onlyProtonTracksTOF[1].Eta()) < 0.8)) { + return; + } + registry.fill(HIST("hEta1"), onlyProtonTracksTOF[0].Eta()); + registry.fill(HIST("hEta1"), onlyProtonTracksTOF[1].Eta()); + resonance += onlyProtonTracksTOF[0]; + resonance += onlyProtonTracksTOF[1]; + a = onlyProtonTracksTOF[0]; + b = onlyProtonTracksTOF[1]; + sigmaTotal = 0; + sigmaTotal = onlyProtonSigmaTOF[0] * onlyProtonSigmaTOF[0] + onlyProtonSigmaTOF[1] * onlyProtonSigmaTOF[1]; + ; + registry.fill(HIST("hNsigEvsKa1"), onlyProtonSigmaTOF[0], onlyProtonSigmaTOF[1]); + signSum = rawProtonTracksTOF[0].sign() + rawProtonTracksTOF[1].sign(); + if (signSum == 0) { + registry.fill(HIST("PP/hPtProtonVsProton"), onlyProtonTracksTOF[0].Pt(), onlyProtonTracksTOF[1].Pt()); + if (rawProtonTracksTOF[0].sign() == 1) { + positiveFlag = 1; + } else { + positiveFlag = 2; + } + } + + // // DCA checks + // dcaZ[0] = rawProtonTracksTOF[0].dcaZ(); + // dcaZ[1] = rawProtonTracksTOF[1].dcaZ(); + // dcaXY[0] = rawProtonTracksTOF[0].dcaXY(); + // dcaXY[1] = rawProtonTracksTOF[1].dcaXY(); + // if (std::abs(dcaZ[0]) < 2. && std::abs(dcaZ[1]) < 2.) { + // dcaZbool = 1; + // } else { + // dcaZbool = 0; + // } + // double dcaLimit[2] = {-99., -99.}; + // dcaLimit[0] = 0.0105 + 0.035 / pow(a.Pt(), 1.1); + // dcaLimit[1] = 0.0105 + 0.035 / pow(b.Pt(), 1.1); + // if (std::abs(dcaXY[0]) < dcaLimit[0] && std::abs(dcaXY[1]) < dcaLimit[1]) { + // dcaXYbool = 1; + // } else { + // dcaXYbool = 0; + // } + } + + if (sigmaTotal > 16.) { + return; + } + if (onlyProtonTracksTOF.size() == 1) { + registry.fill(HIST("hNsigEvsKa2"), onlyProtonSigma[0], onlyProtonSigmaTOF[0]); + } else if (onlyProtonTracksTOF.size() == 2) { + registry.fill(HIST("hNsigEvsKa2"), onlyProtonSigmaTOF[0], onlyProtonSigmaTOF[1]); + } + + if (signSum != 0) { + registry.fill(HIST("hMassPtLikeSignProton"), resonance.M(), resonance.Pt()); + registry.fill(HIST("hSelectionCounter"), 7); + registry.fill(HIST("hPtLikeSignProton"), resonance.Pt()); + registry.fill(HIST("hMassLikeSignProton"), resonance.M()); + } else { + registry.fill(HIST("PP/hMassPtUnlikeSignProton"), resonance.M(), resonance.Pt()); + registry.fill(HIST("hSelectionCounter"), 8); + registry.fill(HIST("PP/hUnlikePt"), resonance.Pt()); + registry.fill(HIST("PP/hMassUnlike"), resonance.M()); + registry.fill(HIST("PP/hRapidity"), resonance.Rapidity()); + if (resonance.Pt() < 0.15) { + registry.fill(HIST("PP/hCoherentMassWithoutDCAcuts"), resonance.M()); + if (dcaZbool == 1) { + registry.fill(HIST("PP/hCoherentMassWithoutDCAxycut"), resonance.M()); + } + if (dcaXYbool == 1) { + registry.fill(HIST("PP/hCoherentMassWithoutDCAzcut"), resonance.M()); + } + } + if (resonance.Pt() < 0.15 && dcaZbool == 1 && dcaXYbool == 1) { + registry.fill(HIST("PP/hCoherentMass"), resonance.M()); + if (resonance.M() < 3.0) { + registry.fill(HIST("PP/hAngularDstribLab"), a.Phi() + TMath::Pi(), a.CosTheta()); + registry.fill(HIST("PP/hAngularDstribLab"), b.Phi() + TMath::Pi(), b.CosTheta()); + registry.fill(HIST("PP/hCosThetaLab"), a.CosTheta()); + registry.fill(HIST("PP/hCosThetaLab"), b.CosTheta()); + } + double costhetaHel = -999.; + double phiHel = -999.; + if (positiveFlag == 1 && (resonance.M() > 2.4 && resonance.M() < 3.)) { + costhetaHel = CosThetaHelicityFrame(a, b, resonance); + phiHel = 1. * TMath::Pi() + PhiHelicityFrame(a, b, resonance); + registry.fill(HIST("PP/hAngularDistribHelicity"), phiHel, costhetaHel); + registry.fill(HIST("PP/hCosThetaHelicity"), costhetaHel); + registry.fill(HIST("PP/hPhiHelicity"), phiHel); + } else if (positiveFlag == 2 && (resonance.M() > 2.4 && resonance.M() < 3.)) { + costhetaHel = CosThetaHelicityFrame(b, a, resonance); + phiHel = 1. * TMath::Pi() + PhiHelicityFrame(b, a, resonance); + registry.fill(HIST("PP/hAngularDistribHelicity"), phiHel, costhetaHel); + registry.fill(HIST("PP/hCosThetaHelicity"), costhetaHel); + registry.fill(HIST("PP/hPhiHelicity"), phiHel); + } + } + // outside the hard pT cut, but with opposite charges + if (dcaZbool == 1 && dcaXYbool == 1) { + if (resonance.M() > 2.4 && resonance.M() < 2.75) { + registry.fill(HIST("PP/hUnlikePtLowBand24to275"), resonance.Pt()); + registry.fill(HIST("PP/hUnlikePtLowBand"), resonance.Pt()); + } else if (resonance.M() > 2.75 && resonance.M() < 3.) { + registry.fill(HIST("PP/hUnlikePtLowBand275to300"), resonance.Pt()); + registry.fill(HIST("PP/hUnlikePtLowBand"), resonance.Pt()); + } else if (resonance.M() > 3.0 && resonance.M() < 3.15) { + registry.fill(HIST("PP/hUnlikePtJpsi"), resonance.Pt()); + } else if (resonance.M() > 3.15 && resonance.M() < 3.4) { + registry.fill(HIST("PP/hUnlikePtHighBand"), resonance.Pt()); + } + + // high mass states + if (resonance.M() > 4.) { + if (onlyProtonTracksTOF.size() == 1) { + registry.fill(HIST("hNsigEvsKa3"), onlyProtonSigma[0], onlyProtonSigmaTOF[0]); + } else if (onlyProtonTracksTOF.size() == 2) { + registry.fill(HIST("hNsigEvsKa3"), onlyProtonSigmaTOF[0], onlyProtonSigmaTOF[1]); + } + if (resonance.Pt() < 0.15) { + registry.fill(HIST("PP/hMassHighPt0150"), resonance.M()); + } + if (resonance.Pt() < 0.20) { + registry.fill(HIST("PP/hMassHighPt0200"), resonance.M()); + } + if (resonance.Pt() < 0.30) { + registry.fill(HIST("PP/hMassHighPt0300"), resonance.M()); + } + if (resonance.Pt() < 0.50) { + registry.fill(HIST("PP/hMassHighPt0500"), resonance.M()); + } + if (resonance.Pt() < 1.00) { + registry.fill(HIST("PP/hMassHighPt1000"), resonance.M()); + } + } + } + } + } + + } // end of process + +}; // end of struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/flowCorrelationsUpc.cxx b/PWGUD/Tasks/flowCorrelationsUpc.cxx new file mode 100644 index 00000000000..7b00062f453 --- /dev/null +++ b/PWGUD/Tasks/flowCorrelationsUpc.cxx @@ -0,0 +1,271 @@ +// 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 flowCorrelationsUpc.cxx +/// \brief Provides a sparse with usefull two particle correlation info +/// \author Mingrui Zhao (mingrui.zhao@cern.ch, mingrui.zhao@mail.labz0.org) +/// copied from Thor Jensen (thor.kjaersgaard.jensen@cern.ch) and Debojit Sarkar (debojit.sarkar@cern.ch) + +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/ASoA.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "CommonConstants/MathConstants.h" +#include "CCDB/BasicCCDBManager.h" +#include "Common/Core/RecoDecay.h" + +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/SGSelector.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "PWGCF/DataModel/CorrelationsDerived.h" +#include "PWGCF/Core/CorrelationContainer.h" +#include "PWGCF/Core/PairCuts.h" + +namespace o2::aod +{ +namespace flowcorrupc +{ +DECLARE_SOA_COLUMN(Multiplicity, multiplicity, int); +} +DECLARE_SOA_TABLE(Multiplicity, "AOD", "MULTIPLICITY", + flowcorrupc::Multiplicity); + +} // namespace o2::aod + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// define the filtered collisions and tracks +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct CalcNchUpc { + O2_DEFINE_CONFIGURABLE(cfgZVtxCut, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgPtCutMin, float, 0.2f, "minimum accepted track pT") + O2_DEFINE_CONFIGURABLE(cfgPtCutMax, float, 10.0f, "maximum accepted track pT") + O2_DEFINE_CONFIGURABLE(cfgEtaCut, float, 0.8f, "Eta cut") + O2_DEFINE_CONFIGURABLE(cfgMinMixEventNum, int, 5, "Minimum number of events to mix") + + // Filter trackFilter = (nabs(aod::track::eta) < cfgEtaCut) && (aod::track::pt > cfgPtCutMin) && (aod::track::pt < cfgPtCutMax) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)); + + using UdTracks = soa::Join; + using UdTracksFull = soa::Join; + using UDCollisionsFull = soa::Join; + + Produces multiplicityNch; + + HistogramRegistry registry{"registry"}; + + void init(InitContext&) + { + AxisSpec axisNch = {100, 0, 100}; + AxisSpec axisVrtx = {10, -10, 10}; + + registry.add("Ncharge", "N_{charge}", {HistType::kTH1D, {axisNch}}); + registry.add("zVtx_all", "zVtx_all", {HistType::kTH1D, {axisVrtx}}); + } + + void process(UDCollisionsFull::iterator const& collision, UdTracksFull const& tracks) + { + multiplicityNch(tracks.size()); + registry.fill(HIST("Ncharge"), tracks.size()); + registry.fill(HIST("zVtx_all"), collision.posZ()); + } +}; + +struct FlowCorrelationsUpc { + O2_DEFINE_CONFIGURABLE(cfgZVtxCut, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgPtCutMin, float, 0.2f, "minimum accepted track pT") + O2_DEFINE_CONFIGURABLE(cfgPtCutMax, float, 10.0f, "maximum accepted track pT") + O2_DEFINE_CONFIGURABLE(cfgEtaCut, float, 0.8f, "Eta cut") + O2_DEFINE_CONFIGURABLE(cfgMinMixEventNum, int, 5, "Minimum number of events to mix") + O2_DEFINE_CONFIGURABLE(cfgMinMult, int, 0, "Minimum multiplicity for collision") + O2_DEFINE_CONFIGURABLE(cfgMaxMult, int, 10, "Maximum multiplicity for collision") + + ConfigurableAxis axisVertex{"axisVertex", {10, -10, 10}, "vertex axis for histograms"}; + ConfigurableAxis axisEta{"axisEta", {40, -1., 1.}, "eta axis for histograms"}; + ConfigurableAxis axisPhi{"axisPhi", {72, 0.0, constants::math::TwoPI}, "phi axis for histograms"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 10.0}, "pt axis for histograms"}; + ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {72, -PIHalf, PIHalf * 3}, "delta phi axis for histograms"}; + ConfigurableAxis axisDeltaEta{"axisDeltaEta", {40, -2, 2}, "delta eta axis for histograms"}; + ConfigurableAxis axisPtTrigger{"axisPtTrigger", {VARIABLE_WIDTH, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 10.0}, "pt trigger axis for histograms"}; + ConfigurableAxis axisPtAssoc{"axisPtAssoc", {VARIABLE_WIDTH, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 10.0}, "pt associated axis for histograms"}; + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 15, 20, 25, 30, 35, 40, 50, 60, 80, 100}, "multiplicity / centrality axis for histograms"}; + ConfigurableAxis vtxMix{"vtxMix", {VARIABLE_WIDTH, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "vertex axis for mixed event histograms"}; + ConfigurableAxis multMix{"multMix", {VARIABLE_WIDTH, 0, 5, 10, 15, 20, 25, 30, 35, 40, 50, 60, 80, 100}, "multiplicity / centrality axis for mixed event histograms"}; + + ConfigurableAxis axisVertexEfficiency{"axisVertexEfficiency", {10, -10, 10}, "vertex axis for efficiency histograms"}; + ConfigurableAxis axisEtaEfficiency{"axisEtaEfficiency", {20, -1.0, 1.0}, "eta axis for efficiency histograms"}; + ConfigurableAxis axisPtEfficiency{"axisPtEfficiency", {VARIABLE_WIDTH, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0}, "pt axis for efficiency histograms"}; + + // Added UPC Cuts + SGSelector sgSelector; + Configurable cfgCutFV0{"cfgCutFV0", 50., "FV0A threshold"}; + Configurable cfgCutFT0A{"cfgCutFT0A", 150., "FT0A threshold"}; + Configurable cfgCutFT0C{"cfgCutFT0C", 50., "FT0C threshold"}; + Configurable cfgCutZDC{"cfgCutZDC", 10., "ZDC threshold"}; + Configurable cfgGapSideSelection{"cfgGapSideSelection", 2, "gap selection"}; + + // make the filters and cuts. + // Filter collisionFilter = (nabs(aod::collision::posZ) < cfgZVtxCut) && (aod::flowcorrupc::multiplicity) > cfgMinMult && (aod::flowcorrupc::multiplicity) < cfgMaxMult && (aod::evsel::sel8) == true; + // Filter trackFilter = (nabs(aod::track::eta) < cfgEtaCut) && (aod::track::pt > cfgPtCutMin) && (aod::track::pt < cfgPtCutMax) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)); + + using UdTracks = soa::Join; + using UdTracksFull = soa::Join; + using UDCollisionsFull = soa::Join; + + // Define the outputs + OutputObj same{Form("sameEvent_%i_%i", static_cast(cfgMinMult), static_cast(cfgMaxMult))}; + OutputObj mixed{Form("mixedEvent_%i_%i", static_cast(cfgMinMult), static_cast(cfgMaxMult))}; + + HistogramRegistry registry{"registry"}; + + void init(InitContext&) + { + LOGF(info, "Starting init"); + // Make histograms to check the distributions after cuts + registry.add("deltaEta_deltaPhi_same", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEta}}); // check to see the delta eta and delta phi distribution + registry.add("deltaEta_deltaPhi_mixed", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEta}}); + registry.add("Phi", "Phi", {HistType::kTH1D, {axisPhi}}); + registry.add("Eta", "Eta", {HistType::kTH1D, {axisEta}}); + registry.add("pT", "pT", {HistType::kTH1D, {axisPtTrigger}}); + registry.add("Nch", "N_{ch}", {HistType::kTH1D, {axisMultiplicity}}); + registry.add("zVtx", "zVtx", {HistType::kTH1D, {axisVertex}}); + + registry.add("Trig_hist", "", {HistType::kTHnSparseF, {{axisMultiplicity, axisVertex, axisPtTrigger}}}); + + registry.add("eventcount", "bin", {HistType::kTH1F, {{3, 0, 3, "bin"}}}); // histogram to see how many events are in the same and mixed event + + std::vector corrAxis = {{axisMultiplicity, "Nch"}, + {axisVertex, "z-vtx (cm)"}, + {axisPtTrigger, "p_{T} (GeV/c)"}, + {axisPtAssoc, "p_{T} (GeV/c)"}, + {axisDeltaPhi, "#Delta#varphi (rad)"}, + {axisDeltaEta, "#Delta#eta"}}; + std::vector effAxis = { + {axisVertexEfficiency, "z-vtx (cm)"}, + {axisPtEfficiency, "p_{T} (GeV/c)"}, + {axisEtaEfficiency, "#eta"}, + }; + std::vector userAxis; + + same.setObject(new CorrelationContainer(Form("sameEvent_%i_%i", static_cast(cfgMinMult), static_cast(cfgMaxMult)), Form("sameEvent_%i_%i", static_cast(cfgMinMult), static_cast(cfgMaxMult)), corrAxis, effAxis, userAxis)); + mixed.setObject(new CorrelationContainer(Form("mixedEvent_%i_%i", static_cast(cfgMinMult), static_cast(cfgMaxMult)), Form("mixedEvent_%i_%i", static_cast(cfgMinMult), static_cast(cfgMaxMult)), corrAxis, effAxis, userAxis)); + } + enum EventType { + SameEvent = 1, + MixedEvent = 3 + }; + + // fill multiple histograms + template + void fillYield(TCollision collision, TTracks tracks) // function to fill the yield and etaphi histograms. + { + registry.fill(HIST("Nch"), tracks.size()); + registry.fill(HIST("zVtx"), collision.posZ()); + + for (auto const& track1 : tracks) { + auto momentum1 = std::array{track1.px(), track1.py(), track1.pz()}; + registry.fill(HIST("Phi"), RecoDecay::phi(momentum1)); + registry.fill(HIST("Eta"), RecoDecay::eta(momentum1)); + registry.fill(HIST("pT"), track1.pt()); + } + } + + template + void fillCorrelations(TTracks tracks1, TTracks tracks2, float posZ, int system, float Nch) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms + { + // loop over all tracks + for (auto const& track1 : tracks1) { + + if (system == SameEvent) { + registry.fill(HIST("Trig_hist"), Nch, posZ, track1.pt()); + } + + for (auto const& track2 : tracks2) { + + if (track1.pt() <= track2.pt()) + continue; // skip if the trigger pt is less than the associate p + + auto momentum1 = std::array{track1.px(), track1.py(), track1.pz()}; + auto momentum2 = std::array{track2.px(), track2.py(), track2.pz()}; + double phi1 = RecoDecay::phi(momentum1); + double phi2 = RecoDecay::phi(momentum2); + float deltaPhi = RecoDecay::constrainAngle(phi1 - phi2, -PIHalf); + float deltaEta = RecoDecay::eta(momentum1) - RecoDecay::eta(momentum2); + + // fill the right sparse and histograms + if (system == SameEvent) { + same->getPairHist()->Fill(step, Nch, posZ, track1.pt(), track2.pt(), deltaPhi, deltaEta); + registry.fill(HIST("deltaEta_deltaPhi_same"), deltaPhi, deltaEta); + } else if (system == MixedEvent) { + mixed->getPairHist()->Fill(step, Nch, posZ, track1.pt(), track2.pt(), deltaPhi, deltaEta); + registry.fill(HIST("deltaEta_deltaPhi_mixed"), deltaPhi, deltaEta); + } + } + } + } + + void processSame(UDCollisionsFull::iterator const& collision, UdTracksFull const& tracks) + { + int gapSide = collision.gapSide(); + if (gapSide < 0 || gapSide > 2) { + return; + } + + int trueGapSide = sgSelector.trueGap(collision, cfgCutFV0, cfgCutFT0A, cfgCutFT0C, cfgCutZDC); + gapSide = trueGapSide; + if (gapSide == cfgGapSideSelection) { + return; + } + + registry.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin + fillYield(collision, tracks); + fillCorrelations(tracks, tracks, collision.posZ(), SameEvent, tracks.size()); // fill the SE histogram and Sparse + } + PROCESS_SWITCH(FlowCorrelationsUpc, processSame, "Process same event", true); + + // event mixing + + SliceCache cache; + using MixedBinning = ColumnBinningPolicy; + + // the process for filling the mixed events + void processMixed(UDCollisionsFull const& collisions, UdTracksFull const& tracks) + { + MixedBinning binningOnVtxAndMult{{vtxMix, multMix}, true}; // true is for 'ignore overflows' (true by default) + auto tracksTuple = std::make_tuple(tracks); + SameKindPair pairs{binningOnVtxAndMult, cfgMinMixEventNum, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + + for (auto const& [collision1, tracks1, collision2, tracks2] : pairs) { + registry.fill(HIST("eventcount"), MixedEvent); // fill the mixed event in the 3 bin + fillCorrelations(tracks1, tracks2, collision1.posZ(), MixedEvent, tracks1.size()); + } + } + PROCESS_SWITCH(FlowCorrelationsUpc, processMixed, "Process mixed events", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGUD/Tasks/flowCumulantsUpc.cxx b/PWGUD/Tasks/flowCumulantsUpc.cxx new file mode 100644 index 00000000000..155a398cd44 --- /dev/null +++ b/PWGUD/Tasks/flowCumulantsUpc.cxx @@ -0,0 +1,885 @@ +// 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 flowCumulantsUpc.cxx +/// \author Mingrui Zhao (mingrui.zhao@mail.labz0.org, mingrui.zhao@cern.ch) +/// \since Mar/2025 +/// \brief jira: , task to measure flow observables with cumulant method + +#include +#include +#include +#include +#include +#include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/HistogramRegistry.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/CCDB/ctpRateFetcher.h" + +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/SGSelector.h" +#include "TVector3.h" + +#include "GFWPowerArray.h" +#include "GFW.h" +#include "GFWCumulant.h" +#include "GFWWeights.h" +#include "FlowContainer.h" +#include "TList.h" +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct FlowCumulantsUpc { + + O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCentEstimator, int, 0, "0:FT0C; 1:FT0CVariant1; 2:FT0M; 3:FT0A") + O2_DEFINE_CONFIGURABLE(cfgCentFT0CMin, float, 0.0f, "Minimum centrality (FT0C) to cut events in filter") + O2_DEFINE_CONFIGURABLE(cfgCentFT0CMax, float, 100.0f, "Maximum centrality (FT0C) to cut events in filter") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMin, float, 0.2f, "Minimal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMax, float, 10.0f, "Maximal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtRefMin, float, 0.2f, "Minimal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtRefMax, float, 3.0f, "Maximal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for all tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 10.0f, "Maximal pT for all tracks") + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5f, "max chi2 per TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutTPCclu, float, 70.0f, "minimum TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutITSclu, float, 5.0f, "minimum ITS clusters") + O2_DEFINE_CONFIGURABLE(cfgCutDCAz, float, 2.0f, "max DCA to vertex z") + O2_DEFINE_CONFIGURABLE(cfgCutDCAxyppPass3Enabled, bool, false, "switch of ppPass3 DCAxy pt dependent cut") + O2_DEFINE_CONFIGURABLE(cfgCutDCAzPtDepEnabled, bool, false, "switch of DCAz pt dependent cut") + O2_DEFINE_CONFIGURABLE(cfgTrkSelSwitch, bool, false, "switch for self-defined track selection") + O2_DEFINE_CONFIGURABLE(cfgUseAdditionalEventCut, bool, false, "Use additional event cut on mult correlations") + O2_DEFINE_CONFIGURABLE(cfgUseTentativeEventCounter, bool, false, "After sel8(), count events regardless of real event selection") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoSameBunchPileup, bool, false, "rejects collisions which are associated with the same found-by-T0 bunch crossing") + O2_DEFINE_CONFIGURABLE(cfgEvSelkIsGoodZvtxFT0vsPV, bool, false, "removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference, use this cut at low multiplicities with caution") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoCollInTimeRangeStandard, bool, false, "no collisions in specified time range") + O2_DEFINE_CONFIGURABLE(cfgEvSelkIsGoodITSLayersAll, bool, true, "cut time intervals with dead ITS staves") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoCollInRofStandard, bool, false, "no other collisions in this Readout Frame with per-collision multiplicity above threshold") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoHighMultCollInPrevRof, bool, false, "veto an event if FT0C amplitude in previous ITS ROF is above threshold") + O2_DEFINE_CONFIGURABLE(cfgEvSelMultCorrelation, bool, true, "Multiplicity correlation cut") + O2_DEFINE_CONFIGURABLE(cfgEvSelV0AT0ACut, bool, true, "V0A T0A 5 sigma cut") + O2_DEFINE_CONFIGURABLE(cfgGetInteractionRate, bool, false, "Get interaction rate from CCDB") + O2_DEFINE_CONFIGURABLE(cfgUseInteractionRateCut, bool, false, "Use events with low interaction rate") + O2_DEFINE_CONFIGURABLE(cfgCutMaxIR, float, 50.0f, "maximum interaction rate (kHz)") + O2_DEFINE_CONFIGURABLE(cfgCutMinIR, float, 0.0f, "minimum interaction rate (kHz)") + O2_DEFINE_CONFIGURABLE(cfgUseNch, bool, false, "Use Nch for flow observables") + O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 30, "Number of subsamples") + O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeights, bool, false, "Fill and output NUA weights") + O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeightsRefPt, bool, false, "NUA weights are filled in ref pt bins") + O2_DEFINE_CONFIGURABLE(cfgEfficiency, std::string, "", "CCDB path to efficiency object") + O2_DEFINE_CONFIGURABLE(cfgAcceptance, std::string, "", "CCDB path to acceptance object") + O2_DEFINE_CONFIGURABLE(cfgAcceptanceList, std::string, "", "CCDB path to acceptance lsit object") + O2_DEFINE_CONFIGURABLE(cfgAcceptanceListEnabled, bool, false, "switch of acceptance list") + O2_DEFINE_CONFIGURABLE(cfgEvSelOccupancy, bool, true, "Occupancy cut") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyHigh, int, 500, "High cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyLow, int, 0, "Low cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgUseSmallMemory, bool, false, "Use small memory mode") + Configurable> cfgUserDefineGFWCorr{"cfgUserDefineGFWCorr", std::vector{"refN02 {2} refP02 {-2}", "refN12 {2} refP12 {-2}"}, "User defined GFW CorrelatorConfig"}; + Configurable> cfgUserDefineGFWName{"cfgUserDefineGFWName", std::vector{"Ch02Gap22", "Ch12Gap22"}, "User defined GFW Name"}; + Configurable> cfgRunRemoveList{"cfgRunRemoveList", std::vector{-1}, "excluded run numbers"}; + + ConfigurableAxis axisPtHist{"axisPtHist", {100, 0., 10.}, "pt axis for histograms"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.2, 2.4, 2.6, 2.8, 3, 3.5, 4, 5, 6, 8, 10}, "pt axis for histograms"}; + ConfigurableAxis axisIndependent{"axisIndependent", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}, "X axis for histograms"}; + ConfigurableAxis axisNch{"axisNch", {4000, 0, 4000}, "N_{ch}"}; + ConfigurableAxis axisDCAz{"axisDCAz", {200, -2, 2}, "DCA_{z} (cm)"}; + ConfigurableAxis axisDCAxy{"axisDCAxy", {200, -1, 1}, "DCA_{xy} (cm)"}; + + // Added UPC Cuts + SGSelector sgSelector; + Configurable cfgCutFV0{"cfgCutFV0", 50., "FV0A threshold"}; + Configurable cfgCutFT0A{"cfgCutFT0A", 150., "FT0A threshold"}; + Configurable cfgCutFT0C{"cfgCutFT0C", 50., "FT0C threshold"}; + Configurable cfgCutZDC{"cfgCutZDC", 10., "ZDC threshold"}; + Configurable cfgGapSideSelection{"cfgGapSideSelection", 2, "gap selection"}; + + // Filter collisionFilter = (nabs(aod::collision::posZ) < cfgCutVertex) && (aod::cent::centFT0C > cfgCentFT0CMin) && (aod::cent::centFT0C < cfgCentFT0CMax); + // Filter trackFilter = ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtMin) && (aod::track::pt < cfgCutPtMax) && (aod::track::tpcChi2NCl < cfgCutChi2prTPCcls) && (nabs(aod::track::dcaZ) < cfgCutDCAz); + + // Corrections + TH1D* mEfficiency = nullptr; + GFWWeights* mAcceptance = nullptr; + TObjArray* mAcceptanceList = nullptr; + bool correctionsLoaded = false; + + // Connect to ccdb + Service ccdb; + Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + // Define output + OutputObj fFC{FlowContainer("FlowContainer")}; + OutputObj fWeights{GFWWeights("weights")}; + HistogramRegistry registry{"registry"}; + + // define global variables + GFW* fGFW = new GFW(); + std::vector corrconfigs; + TAxis* fPtAxis; + TRandom3* fRndm = new TRandom3(0); + enum CentEstimators { + kCentFT0C = 0, + kCentFT0CVariant1, + kCentFT0M, + kCentFV0A, + // Count the total number of enum + kCount_CentEstimators + }; + int mRunNumber{-1}; + uint64_t mSOR{0}; + double mMinSeconds{-1.}; + std::unordered_map gHadronicRate; + ctpRateFetcher mRateFetcher; + TH2* gCurrentHadronicRate; + + // using AodCollisions = soa::Filtered>; + // using AodTracks = soa::Filtered>; + // + using UdTracks = soa::Join; + using UdTracksFull = soa::Join; + using UDCollisionsFull = soa::Join; + + // Track selection + TrackSelection myTrackSel; + TF1* fPhiCutLow = nullptr; + TF1* fPhiCutHigh = nullptr; + // Additional Event selection cuts - Copy from flowGenericFramework.cxx + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + TF1* fMultCutLow = nullptr; + TF1* fMultCutHigh = nullptr; + TF1* fMultMultPVCut = nullptr; + TF1* fT0AV0AMean = nullptr; + TF1* fT0AV0ASigma = nullptr; + + void init(InitContext const&) + { + const AxisSpec axisVertex{40, -20, 20, "Vtxz (cm)"}; + const AxisSpec axisPhi{60, 0.0, constants::math::TwoPI, "#varphi"}; + const AxisSpec axisEta{40, -1., 1., "#eta"}; + const AxisSpec axisCentForQA{100, 0, 100, "centrality (%)"}; + const AxisSpec axisT0C{70, 0, 70000, "N_{ch} (T0C)"}; + const AxisSpec axisT0A{200, 0, 200000, "N_{ch} (T0A)"}; + + ccdb->setURL(ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setCreatedNotAfter(ccdbNoLaterThan.value); + + // Add some output objects to the histogram registry + // Event QA + registry.add("hEventCount", "Number of Event;; Count", {HistType::kTH1D, {{5, 0, 5}}}); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(1, "Filtered event"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(2, "after sel8"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(3, "after supicious Runs removal"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(4, "after additional event cut"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(5, "after correction loads"); + registry.add("hEventCountSpecific", "Number of Event;; Count", {HistType::kTH1D, {{10, 0, 10}}}); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(1, "after sel8"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(2, "kNoSameBunchPileup"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(3, "kIsGoodZvtxFT0vsPV"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(4, "kNoCollInTimeRangeStandard"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(5, "kIsGoodITSLayersAll"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(6, "kNoCollInRofStandard"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(7, "kNoHighMultCollInPrevRof"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(8, "occupancy"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(9, "MultCorrelation"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(10, "cfgEvSelV0AT0ACut"); + if (cfgUseTentativeEventCounter) { + registry.add("hEventCountTentative", "Number of Event;; Count", {HistType::kTH1D, {{10, 0, 10}}}); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(1, "after sel8"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(2, "kNoSameBunchPileup"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(3, "kIsGoodZvtxFT0vsPV"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(4, "kNoCollInTimeRangeStandard"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(5, "kIsGoodITSLayersAll"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(6, "kNoCollInRofStandard"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(7, "kNoHighMultCollInPrevRof"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(8, "occupancy"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(9, "MultCorrelation"); + registry.get(HIST("hEventCountTentative"))->GetXaxis()->SetBinLabel(10, "cfgEvSelV0AT0ACut"); + } + registry.add("hVtxZ", "Vexter Z distribution", {HistType::kTH1D, {axisVertex}}); + registry.add("hMult", "Multiplicity distribution", {HistType::kTH1D, {{3000, 0.5, 3000.5}}}); + std::string hCentTitle = "Centrality distribution, Estimator " + std::to_string(cfgCentEstimator); + registry.add("hCent", hCentTitle.c_str(), {HistType::kTH1D, {{90, 0, 90}}}); + if (!cfgUseSmallMemory) { + registry.add("BeforeSel8_globalTracks_centT0C", "before sel8;Centrality T0C;mulplicity global tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + registry.add("BeforeCut_globalTracks_centT0C", "before cut;Centrality T0C;mulplicity global tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + registry.add("BeforeCut_PVTracks_centT0C", "before cut;Centrality T0C;mulplicity PV tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + registry.add("BeforeCut_globalTracks_PVTracks", "before cut;mulplicity PV tracks;mulplicity global tracks", {HistType::kTH2D, {axisNch, axisNch}}); + registry.add("BeforeCut_globalTracks_multT0A", "before cut;mulplicity T0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + registry.add("BeforeCut_globalTracks_multV0A", "before cut;mulplicity V0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + registry.add("BeforeCut_multV0A_multT0A", "before cut;mulplicity T0A;mulplicity V0A", {HistType::kTH2D, {axisT0A, axisT0A}}); + registry.add("BeforeCut_multT0C_centT0C", "before cut;Centrality T0C;mulplicity T0C", {HistType::kTH2D, {axisCentForQA, axisT0C}}); + registry.add("globalTracks_centT0C", "after cut;Centrality T0C;mulplicity global tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + registry.add("PVTracks_centT0C", "after cut;Centrality T0C;mulplicity PV tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + registry.add("globalTracks_PVTracks", "after cut;mulplicity PV tracks;mulplicity global tracks", {HistType::kTH2D, {axisNch, axisNch}}); + registry.add("globalTracks_multT0A", "after cut;mulplicity T0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + registry.add("globalTracks_multV0A", "after cut;mulplicity V0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + registry.add("multV0A_multT0A", "after cut;mulplicity T0A;mulplicity V0A", {HistType::kTH2D, {axisT0A, axisT0A}}); + registry.add("multT0C_centT0C", "after cut;Centrality T0C;mulplicity T0C", {HistType::kTH2D, {axisCentForQA, axisT0C}}); + registry.add("centFT0CVar_centFT0C", "after cut;Centrality T0C;Centrality T0C Var", {HistType::kTH2D, {axisCentForQA, axisCentForQA}}); + registry.add("centFT0M_centFT0C", "after cut;Centrality T0C;Centrality T0M", {HistType::kTH2D, {axisCentForQA, axisCentForQA}}); + registry.add("centFV0A_centFT0C", "after cut;Centrality T0C;Centrality V0A", {HistType::kTH2D, {axisCentForQA, axisCentForQA}}); + } + // Track QA + registry.add("hPhi", "#phi distribution", {HistType::kTH1D, {axisPhi}}); + registry.add("hPhiWeighted", "corrected #phi distribution", {HistType::kTH1D, {axisPhi}}); + registry.add("hEta", "#eta distribution", {HistType::kTH1D, {axisEta}}); + registry.add("hPt", "p_{T} distribution before cut", {HistType::kTH1D, {axisPtHist}}); + registry.add("hPtRef", "p_{T} distribution after cut", {HistType::kTH1D, {axisPtHist}}); + registry.add("hChi2prTPCcls", "#chi^{2}/cluster for the TPC track segment", {HistType::kTH1D, {{100, 0., 5.}}}); + registry.add("hChi2prITScls", "#chi^{2}/cluster for the ITS track", {HistType::kTH1D, {{100, 0., 50.}}}); + registry.add("hnTPCClu", "Number of found TPC clusters", {HistType::kTH1D, {{100, 40, 180}}}); + registry.add("hnITSClu", "Number of found ITS clusters", {HistType::kTH1D, {{100, 0, 20}}}); + registry.add("hnTPCCrossedRow", "Number of crossed TPC Rows", {HistType::kTH1D, {{100, 40, 180}}}); + registry.add("hDCAz", "DCAz after cuts; DCAz (cm); Pt", {HistType::kTH2D, {{200, -0.5, 0.5}, {200, 0, 5}}}); + registry.add("hDCAxy", "DCAxy after cuts; DCAxy (cm); Pt", {HistType::kTH2D, {{200, -0.5, 0.5}, {200, 0, 5}}}); + registry.add("hTrackCorrection2d", "Correlation table for number of tracks table; uncorrected track; corrected track", {HistType::kTH2D, {axisNch, axisNch}}); + + o2::framework::AxisSpec axis = axisPt; + int nPtBins = axis.binEdges.size() - 1; + double* ptBins = &(axis.binEdges)[0]; + fPtAxis = new TAxis(nPtBins, ptBins); + + if (cfgOutputNUAWeights) { + fWeights->setPtBins(nPtBins, ptBins); + fWeights->init(true, false); + } + + // add in FlowContainer to Get boostrap sample automatically + TObjArray* oba = new TObjArray(); + oba->Add(new TNamed("ChGap22", "ChGap22")); + oba->Add(new TNamed("ChFull22", "ChFull22")); + oba->Add(new TNamed("ChFull32", "ChFull32")); + oba->Add(new TNamed("ChFull42", "ChFull42")); + oba->Add(new TNamed("ChFull24", "ChFull24")); + oba->Add(new TNamed("ChFull26", "ChFull26")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("ChFull22_pt_%i", i + 1), "ChFull22_pTDiff")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("ChFull24_pt_%i", i + 1), "ChFull24_pTDiff")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("ChFull26_pt_%i", i + 1), "ChFull26_pTDiff")); + oba->Add(new TNamed("Ch04Gap22", "Ch04Gap22")); + oba->Add(new TNamed("Ch06Gap22", "Ch06Gap22")); + oba->Add(new TNamed("Ch08Gap22", "Ch08Gap22")); + oba->Add(new TNamed("Ch10Gap22", "Ch10Gap22")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ch10Gap22_pt_%i", i + 1), "Ch10Gap22_pTDiff")); + oba->Add(new TNamed("Ch12Gap22", "Ch12Gap22")); + oba->Add(new TNamed("Ch04Gap32", "Ch04Gap32")); + oba->Add(new TNamed("Ch06Gap32", "Ch06Gap32")); + oba->Add(new TNamed("Ch08Gap32", "Ch08Gap32")); + oba->Add(new TNamed("Ch10Gap32", "Ch10Gap32")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ch10Gap32_pt_%i", i + 1), "Ch10Gap32_pTDiff")); + oba->Add(new TNamed("Ch12Gap32", "Ch12Gap32")); + oba->Add(new TNamed("Ch04Gap42", "Ch04Gap42")); + oba->Add(new TNamed("Ch06Gap42", "Ch06Gap42")); + oba->Add(new TNamed("Ch08Gap42", "Ch08Gap42")); + oba->Add(new TNamed("Ch10Gap42", "Ch10Gap42")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ch10Gap42_pt_%i", i + 1), "Ch10Gap42_pTDiff")); + oba->Add(new TNamed("Ch12Gap42", "Ch12Gap42")); + oba->Add(new TNamed("ChFull422", "ChFull422")); + oba->Add(new TNamed("Ch04GapA422", "Ch04GapA422")); + oba->Add(new TNamed("Ch04GapB422", "Ch04GapB422")); + oba->Add(new TNamed("Ch10GapA422", "Ch10GapA422")); + oba->Add(new TNamed("Ch10GapB422", "Ch10GapB422")); + oba->Add(new TNamed("ChFull3232", "ChFull3232")); + oba->Add(new TNamed("ChFull4242", "ChFull4242")); + oba->Add(new TNamed("Ch04Gap3232", "Ch04Gap3232")); + oba->Add(new TNamed("Ch04Gap4242", "Ch04Gap4242")); + oba->Add(new TNamed("Ch04Gap24", "Ch04Gap24")); + oba->Add(new TNamed("Ch10Gap3232", "Ch10Gap3232")); + oba->Add(new TNamed("Ch10Gap4242", "Ch10Gap4242")); + oba->Add(new TNamed("Ch10Gap24", "Ch10Gap24")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) + oba->Add(new TNamed(Form("Ch10Gap24_pt_%i", i + 1), "Ch10Gap24_pTDiff")); + std::vector userDefineGFWCorr = cfgUserDefineGFWCorr; + std::vector userDefineGFWName = cfgUserDefineGFWName; + if (!userDefineGFWCorr.empty() && !userDefineGFWName.empty()) { + for (uint i = 0; i < userDefineGFWName.size(); i++) { + oba->Add(new TNamed(userDefineGFWName.at(i).c_str(), userDefineGFWName.at(i).c_str())); + } + } + fFC->SetName("FlowContainer"); + fFC->SetXAxis(fPtAxis); + fFC->Initialize(oba, axisIndependent, cfgNbootstrap); + delete oba; + + // eta region + fGFW->AddRegion("full", -0.8, 0.8, 1, 1); + fGFW->AddRegion("refN00", -0.8, 0., 1, 1); // gap0 negative region + fGFW->AddRegion("refP00", 0., 0.8, 1, 1); // gap0 positve region + fGFW->AddRegion("refN02", -0.8, -0.1, 1, 1); // gap2 negative region + fGFW->AddRegion("refP02", 0.1, 0.8, 1, 1); // gap2 positve region + fGFW->AddRegion("refN04", -0.8, -0.2, 1, 1); // gap4 negative region + fGFW->AddRegion("refP04", 0.2, 0.8, 1, 1); // gap4 positve region + fGFW->AddRegion("refN06", -0.8, -0.3, 1, 1); // gap6 negative region + fGFW->AddRegion("refP06", 0.3, 0.8, 1, 1); // gap6 positve region + fGFW->AddRegion("refN08", -0.8, -0.4, 1, 1); + fGFW->AddRegion("refP08", 0.4, 0.8, 1, 1); + fGFW->AddRegion("refN10", -0.8, -0.5, 1, 1); + fGFW->AddRegion("refP10", 0.5, 0.8, 1, 1); + fGFW->AddRegion("refN12", -0.8, -0.6, 1, 1); + fGFW->AddRegion("refP12", 0.6, 0.8, 1, 1); + fGFW->AddRegion("refN14", -0.8, -0.7, 1, 1); + fGFW->AddRegion("refP14", 0.7, 0.8, 1, 1); + fGFW->AddRegion("refN", -0.8, -0.4, 1, 1); + fGFW->AddRegion("refP", 0.4, 0.8, 1, 1); + fGFW->AddRegion("refM", -0.4, 0.4, 1, 1); + fGFW->AddRegion("poiN", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poifull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("olN", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olfull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 4); + + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {3 -3}", "ChFull32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {4 -4}", "ChFull42", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 2 -2 -2}", "ChFull24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 2 2 -2 -2 -2}", "ChFull26", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {2} refP04 {-2}", "Ch04Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN06 {2} refP06 {-2}", "Ch06Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {2} refP08 {-2}", "Ch08Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {2} refP10 {-2}", "Ch10Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN12 {2} refP12 {-2}", "Ch12Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {3} refP04 {-3}", "Ch04Gap32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN06 {3} refP06 {-3}", "Ch06Gap32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {3} refP08 {-3}", "Ch08Gap32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {3} refP10 {-3}", "Ch10Gap32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN12 {3} refP12 {-3}", "Ch12Gap32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {4} refP04 {-4}", "Ch04Gap42", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN06 {4} refP06 {-4}", "Ch06Gap42", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN08 {4} refP08 {-4}", "Ch08Gap42", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {4} refP10 {-4}", "Ch10Gap42", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN12 {4} refP12 {-4}", "Ch12Gap42", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN {2} refP {-2}", "ChGap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poifull full | olfull {2 -2}", "ChFull22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poifull full | olfull {2 2 -2 -2}", "ChFull24", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poifull full | olfull {2 2 2 -2 -2 -2}", "ChFull26", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiN10 refN10 | olN10 {2} refP10 {-2}", "Ch10Gap22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiN10 refN10 | olN10 {3} refP10 {-3}", "Ch10Gap32", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiN10 refN10 | olN10 {4} refP10 {-4}", "Ch10Gap42", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {4 -2 -2}", "ChFull422", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {-2 -2} refP04 {4}", "Ch04GapA422", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {4} refP04 {-2 -2}", "Ch04GapB422", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {-2 -2} refP10 {4}", "Ch10GapA422", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {4} refP10 {-2 -2}", "Ch10GapB422", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {3 2 -3 -2}", "ChFull3232", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {4 2 -4 -2}", "ChFull4242", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {3 2} refP04 {-3 -2}", "Ch04Gap3232", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {4 2} refP04 {-4 -2}", "Ch04Gap4242", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN04 {2 2} refP04 {-2 -2}", "Ch04Gap24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {3 2} refP10 {-3 -2}", "Ch10Gap3232", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {4 2} refP10 {-4 -2}", "Ch10Gap4242", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {2 2} refP10 {-2 -2}", "Ch10Gap24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiN10 refN10 | olN10 {2 2} refP10 {-2 -2}", "Ch10Gap24", kTRUE)); + if (!userDefineGFWCorr.empty() && !userDefineGFWName.empty()) { + LOGF(info, "User adding GFW CorrelatorConfig:"); + // attentaion: here we follow the index of cfgUserDefineGFWCorr + for (uint i = 0; i < userDefineGFWCorr.size(); i++) { + if (i >= userDefineGFWName.size()) { + LOGF(fatal, "The names you provided are more than configurations. userDefineGFWName.size(): %d > userDefineGFWCorr.size(): %d", userDefineGFWName.size(), userDefineGFWCorr.size()); + break; + } + LOGF(info, "%d: %s %s", i, userDefineGFWCorr.at(i).c_str(), userDefineGFWName.at(i).c_str()); + corrconfigs.push_back(fGFW->GetCorrelatorConfig(userDefineGFWCorr.at(i).c_str(), userDefineGFWName.at(i).c_str(), kFALSE)); + } + } + fGFW->CreateRegions(); + + if (cfgUseAdditionalEventCut) { + fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x - 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); + fMultPVCutLow->SetParameters(3257.29, -121.848, 1.98492, -0.0172128, 6.47528e-05, 154.756, -1.86072, -0.0274713, 0.000633499, -3.37757e-06); + fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x + 3.5*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); + fMultPVCutHigh->SetParameters(3257.29, -121.848, 1.98492, -0.0172128, 6.47528e-05, 154.756, -1.86072, -0.0274713, 0.000633499, -3.37757e-06); + + fMultCutLow = new TF1("fMultCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultCutLow->SetParameters(1654.46, -47.2379, 0.449833, -0.0014125, 150.773, -3.67334, 0.0530503, -0.000614061, 3.15956e-06); + fMultCutHigh = new TF1("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 3.*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); + fMultCutHigh->SetParameters(1654.46, -47.2379, 0.449833, -0.0014125, 150.773, -3.67334, 0.0530503, -0.000614061, 3.15956e-06); + + fT0AV0AMean = new TF1("fT0AV0AMean", "[0]+[1]*x", 0, 200000); + fT0AV0AMean->SetParameters(-1601.0581, 9.417652e-01); + fT0AV0ASigma = new TF1("fT0AV0ASigma", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 200000); + fT0AV0ASigma->SetParameters(463.4144, 6.796509e-02, -9.097136e-07, 7.971088e-12, -2.600581e-17); + } + + myTrackSel = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::Default); + myTrackSel.SetMinNClustersTPC(cfgCutTPCclu); + myTrackSel.SetMinNClustersITS(cfgCutITSclu); + if (cfgCutDCAxyppPass3Enabled) + myTrackSel.SetMaxDcaXYPtDep([](float pt) { return 0.004f + 0.013f / pt; }); // Tuned on the LHC22f anchored MC LHC23d1d on primary pions. 7 Sigmas of the resolution + } + + template + void fillProfile(const GFW::CorrConfig& corrconf, const ConstStr& tarName, const double& cent) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) { + return; + } + if (!corrconf.pTDif) { + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) { + registry.fill(tarName, cent, val, dnx); + } + return; + } + return; + } + + void fillFC(const GFW::CorrConfig& corrconf, const double& cent, const double& rndm) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (!corrconf.pTDif) { + if (dnx == 0) { + return; + } + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) { + fFC->FillProfile(corrconf.Head.c_str(), cent, val, dnx, rndm); + } + return; + } + for (auto i = 1; i <= fPtAxis->GetNbins(); i++) { + dnx = fGFW->Calculate(corrconf, i - 1, kTRUE).real(); + if (dnx == 0) { + continue; + } + val = fGFW->Calculate(corrconf, i - 1, kFALSE).real() / dnx; + if (std::fabs(val) < 1) { + fFC->FillProfile(Form("%s_pt_%i", corrconf.Head.c_str(), i), cent, val, dnx, rndm); + } + } + return; + } + + void loadCorrections(uint64_t timestamp, int runNumber) + { + if (correctionsLoaded) { + return; + } + if (!cfgAcceptanceListEnabled && cfgAcceptance.value.empty() == false) { + mAcceptance = ccdb->getForTimeStamp(cfgAcceptance, timestamp); + if (mAcceptance) { + LOGF(info, "Loaded acceptance weights from %s (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance); + } else { + LOGF(warning, "Could not load acceptance weights from %s (%p)", cfgAcceptance.value.c_str(), (void*)mAcceptance); + } + } + if (cfgAcceptanceListEnabled && cfgAcceptanceList.value.empty() == false) { + mAcceptanceList = ccdb->getForTimeStamp(cfgAcceptanceList, timestamp); + if (mAcceptanceList == nullptr) { + LOGF(fatal, "Could not load acceptance weights list from %s", cfgAcceptanceList.value.c_str()); + } + LOGF(info, "Loaded acceptance weights list from %s (%p)", cfgAcceptanceList.value.c_str(), (void*)mAcceptanceList); + + mAcceptance = static_cast(mAcceptanceList->FindObject(Form("%d", runNumber))); + if (mAcceptance == nullptr) { + LOGF(fatal, "Could not find acceptance weights for run %d in acceptance list", runNumber); + } + LOGF(info, "Loaded acceptance weights (%p) for run %d from list (%p)", (void*)mAcceptance, runNumber, (void*)mAcceptanceList); + } + if (cfgEfficiency.value.empty() == false) { + mEfficiency = ccdb->getForTimeStamp(cfgEfficiency, timestamp); + if (mEfficiency == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgEfficiency.value.c_str()); + } + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgEfficiency.value.c_str(), (void*)mEfficiency); + } + correctionsLoaded = true; + } + + bool setCurrentParticleWeights(float& weight_nue, float& weight_nua, float phi, float eta, float pt, float vtxz) + { + float eff = 1.; + if (mEfficiency) + eff = mEfficiency->GetBinContent(mEfficiency->FindBin(pt)); + else + eff = 1.0; + if (eff == 0) + return false; + weight_nue = 1. / eff; + + if (mAcceptance) + weight_nua = mAcceptance->getNUA(phi, eta, vtxz); + else + weight_nua = 1; + return true; + } + + template + bool eventSelected(TCollision collision, const int multTrk, const float centrality) + { + registry.fill(HIST("hEventCountSpecific"), 0.5); + if (cfgEvSelkNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + // rejects collisions which are associated with the same "found-by-T0" bunch crossing + // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof + return 0; + } + if (cfgEvSelkNoSameBunchPileup) { + registry.fill(HIST("hEventCountSpecific"), 1.5); + } + if (cfgEvSelkIsGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference + // use this cut at low multiplicities with caution + return 0; + } + if (cfgEvSelkIsGoodZvtxFT0vsPV) { + registry.fill(HIST("hEventCountSpecific"), 2.5); + } + if (cfgEvSelkNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // no collisions in specified time range + return 0; + } + if (cfgEvSelkNoCollInTimeRangeStandard) { + registry.fill(HIST("hEventCountSpecific"), 3.5); + } + if (cfgEvSelkIsGoodITSLayersAll && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + // from Jan 9 2025 AOT meeting + // cut time intervals with dead ITS staves + return 0; + } + if (cfgEvSelkIsGoodITSLayersAll) { + registry.fill(HIST("hEventCountSpecific"), 4.5); + } + if (cfgEvSelkNoCollInRofStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + // no other collisions in this Readout Frame with per-collision multiplicity above threshold + return 0; + } + if (cfgEvSelkNoCollInRofStandard) { + registry.fill(HIST("hEventCountSpecific"), 5.5); + } + if (cfgEvSelkNoHighMultCollInPrevRof && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + // veto an event if FT0C amplitude in previous ITS ROF is above threshold + return 0; + } + if (cfgEvSelkNoHighMultCollInPrevRof) { + registry.fill(HIST("hEventCountSpecific"), 6.5); + } + auto multNTracksPV = collision.multNTracksPV(); + auto occupancy = collision.trackOccupancyInTimeRange(); + if (cfgEvSelOccupancy && (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh)) { + return 0; + } + if (cfgEvSelOccupancy) { + registry.fill(HIST("hEventCountSpecific"), 7.5); + } + + if (cfgEvSelMultCorrelation) { + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) + return 0; + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) + return 0; + if (multTrk < fMultCutLow->Eval(centrality)) + return 0; + if (multTrk > fMultCutHigh->Eval(centrality)) + return 0; + } + if (cfgEvSelMultCorrelation) { + registry.fill(HIST("hEventCountSpecific"), 8.5); + } + + // V0A T0A 5 sigma cut + if (cfgEvSelV0AT0ACut && (std::fabs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > 5 * fT0AV0ASigma->Eval(collision.multFT0A()))) { + return 0; + } + if (cfgEvSelV0AT0ACut) { + registry.fill(HIST("hEventCountSpecific"), 9.5); + } + + return 1; + } + + template + void eventCounterQA(TCollision collision, const int multTrk, const float centrality) + { + registry.fill(HIST("hEventCountTentative"), 0.5); + // Regradless of the event selection, fill the event counter histograms + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + registry.fill(HIST("hEventCountTentative"), 1.5); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + registry.fill(HIST("hEventCountTentative"), 2.5); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + registry.fill(HIST("hEventCountTentative"), 3.5); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + registry.fill(HIST("hEventCountTentative"), 4.5); + } + if (collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + registry.fill(HIST("hEventCountTentative"), 5.5); + } + if (collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + registry.fill(HIST("hEventCountTentative"), 6.5); + } + auto multNTracksPV = collision.multNTracksPV(); + auto occupancy = collision.trackOccupancyInTimeRange(); + if (!(occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh)) { + registry.fill(HIST("hEventCountTentative"), 7.5); + } + if (!((multNTracksPV < fMultPVCutLow->Eval(centrality)) || (multNTracksPV > fMultPVCutHigh->Eval(centrality)) || (multTrk < fMultCutLow->Eval(centrality)) || (multTrk > fMultCutHigh->Eval(centrality)))) { + registry.fill(HIST("hEventCountTentative"), 8.5); + } + if (!(std::fabs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > 5 * fT0AV0ASigma->Eval(collision.multFT0A()))) { + registry.fill(HIST("hEventCountTentative"), 9.5); + } + } + + template + bool trackSelected(TTrack track) + { + // UPC selection + if (!track.isPVContributor()) { + return false; + } + if (!(std::fabs(track.dcaZ()) < 2.)) { + return false; + } + double dcaLimit = 0.0105 + 0.035 / std::pow(track.pt(), 1.1); + if (!(std::fabs(track.dcaXY()) < dcaLimit)) { + return false; + } + return true; + + // if (cfgCutDCAzPtDepEnabled && (std::fabs(track.dcaZ()) > (0.004f + 0.013f / track.pt()))) + // return false; + + // if (cfgTrkSelSwitch) { + // return myTrackSel.IsSelected(track); + // } else { + // return ((track.tpcNClsFound() >= cfgCutTPCclu) && (track.itsNCls() >= cfgCutITSclu)); + // } + } + + void initHadronicRate(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + if (gHadronicRate.find(mRunNumber) == gHadronicRate.end()) { + auto runDuration = ccdb->getRunDuration(mRunNumber); + mSOR = runDuration.first; + mMinSeconds = std::floor(mSOR * 1.e-3); /// round tsSOR to the highest integer lower than tsSOR + double maxSec = std::ceil(runDuration.second * 1.e-3); /// round tsEOR to the lowest integer higher than tsEOR + const AxisSpec axisSeconds{static_cast((maxSec - mMinSeconds) / 20.f), 0, maxSec - mMinSeconds, "Seconds since SOR"}; + gHadronicRate[mRunNumber] = registry.add(Form("HadronicRate/%i", mRunNumber), ";Time since SOR (s);Hadronic rate (kHz)", kTH2D, {axisSeconds, {510, 0., 51.}}).get(); + } + gCurrentHadronicRate = gHadronicRate[mRunNumber]; + } + + // void process(AodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, AodTracks const& tracks) + void process(UDCollisionsFull::iterator const& collision, UdTracksFull const& tracks) + { + + // Runnumber loading test + // accept only selected run numbers + // int run = collision.runNumber(); + + // extract bc pattern from CCDB for data or anchored MC only + // if (run != lastRun && run >= 500000) { + // LOGF(info, "Updating bcPattern %d ...", run); + // auto tss = ccdb->getRunDuration(run); + // auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", tss.first); + // bcPatternB = grplhcif->getBunchFilling().getBCPattern(); + // lastRun = run; + // LOGF(info, "done!"); + // } + + // auto bcnum = collision.globalBC(); + + registry.fill(HIST("hEventCount"), 0.5); + int gapSide = collision.gapSide(); + if (gapSide < 0 || gapSide > 2) { + return; + } + + int trueGapSide = sgSelector.trueGap(collision, cfgCutFV0, cfgCutFT0A, cfgCutFT0C, cfgCutZDC); + gapSide = trueGapSide; + if (gapSide == cfgGapSideSelection) { + return; + } + + // if (!cfgUseSmallMemory && tracks.size() >= 1) { + // registry.fill(HIST("BeforeSel8_globalTracks_centT0C"), collision.centFT0C(), tracks.size()); + // } + // if (!collision.sel8()) + // return; + // if (tracks.size() < 1) + // return; + registry.fill(HIST("hEventCount"), 1.5); + // auto bc = collision.bc_as(); + // int currentRunNumber = bc.runNumber(); + // for (const auto& ExcludedRun : cfgRunRemoveList.value) { + // if (currentRunNumber == ExcludedRun) { + // return; + // } + // } + // registry.fill(HIST("hEventCount"), 2.5); + // if (!cfgUseSmallMemory) { + // registry.fill(HIST("BeforeCut_globalTracks_centT0C"), collision.centFT0C(), tracks.size()); + // registry.fill(HIST("BeforeCut_PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV()); + // registry.fill(HIST("BeforeCut_globalTracks_PVTracks"), collision.multNTracksPV(), tracks.size()); + // registry.fill(HIST("BeforeCut_globalTracks_multT0A"), collision.multFT0A(), tracks.size()); + // registry.fill(HIST("BeforeCut_globalTracks_multV0A"), collision.multFV0A(), tracks.size()); + // registry.fill(HIST("BeforeCut_multV0A_multT0A"), collision.multFT0A(), collision.multFV0A()); + // registry.fill(HIST("BeforeCut_multT0C_centT0C"), collision.centFT0C(), collision.multFT0C()); + // } + float cent = 100; + // switch (cfgCentEstimator) { + // case kCentFT0C: + // cent = collision.centFT0C(); + // break; + // case kCentFT0CVariant1: + // cent = collision.centFT0CVariant1(); + // break; + // case kCentFT0M: + // cent = collision.centFT0M(); + // break; + // case kCentFV0A: + // cent = collision.centFV0A(); + // break; + // default: + // cent = collision.centFT0C(); + // } + // if (cfgUseTentativeEventCounter) + // eventCounterQA(collision, tracks.size(), cent); + // if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), cent)) + // return; + // registry.fill(HIST("hEventCount"), 3.5); + float lRandom = fRndm->Rndm(); + float vtxz = collision.posZ(); + registry.fill(HIST("hVtxZ"), vtxz); + registry.fill(HIST("hMult"), tracks.size()); + registry.fill(HIST("hCent"), cent); + fGFW->Clear(); + // if (cfgGetInteractionRate) { + // initHadronicRate(bc); + // double hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), mRunNumber, "ZNC hadronic") * 1.e-3; // + // double seconds = bc.timestamp() * 1.e-3 - mMinSeconds; + // if (cfgUseInteractionRateCut && (hadronicRate < cfgCutMinIR || hadronicRate > cfgCutMaxIR)) // cut on hadronic rate + // return; + // gCurrentHadronicRate->Fill(seconds, hadronicRate); + // } + // loadCorrections(bc.timestamp(), currentRunNumber); + // registry.fill(HIST("hEventCount"), 4.5); + + // // fill event QA + // if (!cfgUseSmallMemory) { + // registry.fill(HIST("globalTracks_centT0C"), collision.centFT0C(), tracks.size()); + // registry.fill(HIST("PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV()); + // registry.fill(HIST("globalTracks_PVTracks"), collision.multNTracksPV(), tracks.size()); + // registry.fill(HIST("globalTracks_multT0A"), collision.multFT0A(), tracks.size()); + // registry.fill(HIST("globalTracks_multV0A"), collision.multFV0A(), tracks.size()); + // registry.fill(HIST("multV0A_multT0A"), collision.multFT0A(), collision.multFV0A()); + // registry.fill(HIST("multT0C_centT0C"), collision.centFT0C(), collision.multFT0C()); + // registry.fill(HIST("centFT0CVar_centFT0C"), collision.centFT0C(), collision.centFT0CVariant1()); + // registry.fill(HIST("centFT0M_centFT0C"), collision.centFT0C(), collision.centFT0M()); + // registry.fill(HIST("centFV0A_centFT0C"), collision.centFT0C(), collision.centFV0A()); + // } + + // // track weights + float weff = 1, wacc = 1; + double nTracksCorrected = 0; + float independent = cent; + if (cfgUseNch) { + independent = static_cast(tracks.size()); + } + + for (const auto& track : tracks) { + if (!trackSelected(track)) + continue; + auto momentum = std::array{track.px(), track.py(), track.pz()}; + double pt = RecoDecay::pt(momentum); + double phi = RecoDecay::phi(momentum); + double eta = RecoDecay::eta(momentum); + bool withinPtPOI = (cfgCutPtPOIMin < pt) && (pt < cfgCutPtPOIMax); // within POI pT range + bool withinPtRef = (cfgCutPtRefMin < pt) && (pt < cfgCutPtRefMax); // within RF pT range + if (cfgOutputNUAWeights) { + if (cfgOutputNUAWeightsRefPt) { + if (withinPtRef) { + fWeights->fill(phi, eta, vtxz, pt, cent, 0); + } + } else { + fWeights->fill(phi, eta, vtxz, pt, cent, 0); + } + } + if (!setCurrentParticleWeights(weff, wacc, phi, eta, pt, vtxz)) { + continue; + } + registry.fill(HIST("hPt"), track.pt()); + if (withinPtRef) { + registry.fill(HIST("hPhi"), phi); + registry.fill(HIST("hPhiWeighted"), phi, wacc); + registry.fill(HIST("hEta"), eta); + registry.fill(HIST("hPtRef"), pt); + // registry.fill(HIST("hChi2prTPCcls"), track.tpcChi2NCl()); + // registry.fill(HIST("hChi2prITScls"), track.itsChi2NCl()); + // registry.fill(HIST("hnTPCClu"), track.tpcNClsFound()); + // registry.fill(HIST("hnITSClu"), track.itsNCls()); + // registry.fill(HIST("hnTPCCrossedRow"), track.tpcNClsCrossedRows()); + registry.fill(HIST("hDCAz"), track.dcaZ(), track.pt()); + registry.fill(HIST("hDCAxy"), track.dcaXY(), track.pt()); + nTracksCorrected += weff; + } + if (withinPtRef) { + fGFW->Fill(eta, fPtAxis->FindBin(pt) - 1, phi, wacc * weff, 1); + } + if (withinPtPOI) { + fGFW->Fill(eta, fPtAxis->FindBin(pt) - 1, phi, wacc * weff, 2); + } + if (withinPtPOI && withinPtRef) { + fGFW->Fill(eta, fPtAxis->FindBin(pt) - 1, phi, wacc * weff, 4); + } + } + registry.fill(HIST("hTrackCorrection2d"), tracks.size(), nTracksCorrected); + + // Filling Flow Container + for (uint l_ind = 0; l_ind < corrconfigs.size(); l_ind++) { + fillFC(corrconfigs.at(l_ind), independent, lRandom); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/sgD0Analyzer.cxx b/PWGUD/Tasks/sgD0Analyzer.cxx index 797fa8d72e9..b5c35b9deec 100644 --- a/PWGUD/Tasks/sgD0Analyzer.cxx +++ b/PWGUD/Tasks/sgD0Analyzer.cxx @@ -16,10 +16,12 @@ #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "iostream" #include "PWGUD/DataModel/UDTables.h" #include "PWGUD/Core/SGSelector.h" #include "Common/DataModel/PIDResponse.h" +#include "PWGUD/Core/SGTrackSelector.h" #include #include "TLorentzVector.h" using namespace std; @@ -27,48 +29,73 @@ using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; -#define mpion 0.1396 -#define mkaon 0.4937 -#define mproton 0.9383 struct SGD0Analyzer { SGSelector sgSelector; + Service pdg; Configurable FV0_cut{"FV0", 100., "FV0A threshold"}; Configurable FT0A_cut{"FT0A", 100., "FT0A threshold"}; Configurable FT0C_cut{"FT0C", 50., "FT0C threshold"}; Configurable FDDA_cut{"FDDA", 10000., "FDDA threshold"}; Configurable FDDC_cut{"FDDC", 10000., "FDDC threshold"}; Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; + // Track Selections + Configurable PV_cut{"PV_cut", 0.0, "Use Only PV tracks"}; + Configurable dcaZ_cut{"dcaZ_cut", 2.0, "dcaZ cut"}; + Configurable dcaXY_cut{"dcaXY_cut", 2.0, "dcaXY cut (0 for Pt-function)"}; + Configurable tpcChi2_cut{"tpcChi2_cut", 4, "Max tpcChi2NCl"}; + Configurable tpcNClsFindable_cut{"tpcNClsFindable_cut", 70, "Min tpcNClsFindable"}; + Configurable itsChi2_cut{"itsChi2_cut", 36, "Max itsChi2NCl"}; + Configurable eta_cut{"eta_cut", 0.9, "Track Pseudorapidity"}; + Configurable pt_cut{"pt_cut", 0.1, "Track Pt"}; + // D0 Specific Cuts + Configurable Ntr_min{"Ntr_min", 2., "Minimum Number of Tracks"}; + Configurable Ntr_max{"Ntr_max", 50., "Maximum Number of Tracks"}; HistogramRegistry registry{ "registry", { {"GapSide", "Gap Side; Entries", {HistType::kTH1F, {{4, -1.5, 2.5}}}}, {"TrueGapSide", "Gap Side; Entries", {HistType::kTH1F, {{4, -1.5, 2.5}}}}, - {"os_KPi_pT", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, - {"os_KPi_eTa", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, - {"os_KPi_invm", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, - {"ss_KPi_pT", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, - {"ss_KPi_eTa", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, - {"ss_KPi_invm", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, - {"os_KPi_pT_1", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, - {"os_KPi_eTa_1", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, - {"os_KPi_invm_1", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, - {"ss_KPi_pT_1", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, - {"ss_KPi_eTa_1", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, - {"ss_KPi_invm_1", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, - {"os_KPi_pT_0", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, - {"os_KPi_eTa_0", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, - {"os_KPi_invm_0", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, - {"ss_KPi_pT_0", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, - {"ss_KPi_eTa_0", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, - {"ss_KPi_invm_0", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, - {"os_KPi_pT_2", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, - {"os_KPi_eTa_2", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, - {"os_KPi_invm_2", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, - {"ss_KPi_pT_2", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, - {"ss_KPi_eTa_2", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, - {"ss_KPi_invm_2", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, - }}; + {"os_KPi_pT", "K#pi pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_KPi_eTa", "K#pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"os_KPi_invm", "K#pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_KPi_pT", "K#pi pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_KPi_eTa", "K#pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"ss_KPi_invm", "K#pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_KPi_pT_1", "K#pi pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_KPi_eTa_1", "K#pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"os_KPi_invm_1", "K#pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_KPi_pT_1", "K#pi pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_KPi_eTa_1", "K#pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"ss_KPi_invm_1", "K#pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_KPi_pT_0", "K#pi pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_KPi_eTa_0", "K#pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"os_KPi_invm_0", "K#pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_KPi_pT_0", "K#pi pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_KPi_eTa_0", "K#pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"ss_KPi_invm_0", "K#pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_KPi_pT_2", "K#pi pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_KPi_eTa_2", "K#pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"os_KPi_invm_2", "K#pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_KPi_pT_2", "K#pi pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_KPi_eTa_2", "K#pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"ss_KPi_invm_2", "K#pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_Ntr_KPi_invm_0", "N tracks vs K#pi Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {750, .7, 2.2}}}}, + {"os_Ntr_KPi_invm_1", "N tracks vs K#pi Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {750, .7, 2.2}}}}, + {"os_Ntr_KPi_invm_2", "N tracks vs K#pi Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {750, .7, 2.2}}}}, + {"D0_FT0A", "FIT Amplitude", {HistType::kTH1F, {{500, 0, 1000}}}}, + {"D0_FT0C", "FIT Amplitude", {HistType::kTH1F, {{500, 0, 1000}}}}, + {"D0_FV0A", "FIT Amplitude", {HistType::kTH1F, {{500, 0, 1000}}}}, + {"D0_FDDA", "FIT Amplitude", {HistType::kTH1F, {{500, 0, 1000}}}}, + {"D0_FDDC", "FIT Amplitude", {HistType::kTH1F, {{500, 0, 1000}}}}, + {"D0_ZNA", "ZDC Energy", {HistType::kTH1F, {{500, 0, 200}}}}, + {"D0_ZNC", "ZDC Energy", {HistType::kTH1F, {{500, 0, 200}}}}, + {"D0_Ntr_0", "Tracks", {HistType::kTH1F, {{100, 0.5, 100.5}}}}, + {"D0_Ntr_1", "Tracks", {HistType::kTH1F, {{100, 0.5, 100.5}}}}, + {"D0_Ntr_2", "Tracks", {HistType::kTH1F, {{100, 0.5, 100.5}}}}, + {"D0_NtrPV_0", "Tracks", {HistType::kTH1F, {{50, 0.5, 50.5}}}}, + {"D0_NtrPV_1", "Tracks", {HistType::kTH1F, {{50, 0.5, 50.5}}}}, + {"D0_NtrPV_2", "Tracks", {HistType::kTH1F, {{50, 0.5, 50.5}}}}}}; using udtracks = soa::Join; using udtracksfull = soa::Join; using UDCollisionsFull = soa::Join; // @@ -87,14 +114,24 @@ struct SGD0Analyzer { // int truegapSide = sgSelector.trueGap(collision); // int truegapSide = sgSelector.trueGap(collision, FV0_cut, ZDC_cut); float FIT_cut[5] = {FV0_cut, FT0A_cut, FT0C_cut, FDDA_cut, FDDC_cut}; + std::vector parameters = {PV_cut, dcaZ_cut, dcaXY_cut, tpcChi2_cut, tpcNClsFindable_cut, itsChi2_cut, eta_cut, pt_cut}; // int truegapSide = sgSelector.trueGap(collision, *FIT_cut, ZDC_cut); - int truegapSide = sgSelector.trueGap(collision, FIT_cut[0], FIT_cut[1], FIT_cut[3], ZDC_cut); + int truegapSide = sgSelector.trueGap(collision, FIT_cut[0], FIT_cut[1], FIT_cut[2], ZDC_cut); registry.fill(HIST("GapSide"), gapSide); registry.fill(HIST("TrueGapSide"), truegapSide); gapSide = truegapSide; + int pvtracks = 0; + for (auto& t0 : tracks) { + if (trackselector(t0, parameters) && t0.isPVContributor()) + pvtracks++; + } // Look for D0 and D0bar + if (tracks.size() < Ntr_min || tracks.size() > Ntr_max) + return; for (auto& [t0, t1] : combinations(tracks, tracks)) { // PID cut - t0=K, t1=pi + if (!trackselector(t0, parameters) || !trackselector(t1, parameters)) + continue; if (std::abs(t0.tpcNSigmaKa()) < 3 && std::abs(t1.tpcNSigmaPi()) < 3 && std::abs(t0.tofNSigmaKa()) < 3 && std::abs(t1.tofNSigmaPi()) < 3) { // Apply pion hypothesis and create pairs v0.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassKaonCharged); @@ -109,16 +146,38 @@ struct SGD0Analyzer { registry.fill(HIST("os_KPi_pT_0"), v01.Pt()); registry.fill(HIST("os_KPi_eTa_0"), v01.Eta()); registry.fill(HIST("os_KPi_invm_0"), v01.M()); + registry.fill(HIST("os_Ntr_KPi_invm_0"), tracks.size(), v01.M()); + if (v01.M() > 1.8 && v01.M() < 1.9) { + registry.fill(HIST("D0_Ntr_0"), tracks.size()); + registry.fill(HIST("D0_NtrPV_0"), pvtracks); + } } if (gapSide == 1) { registry.fill(HIST("os_KPi_pT_1"), v01.Pt()); registry.fill(HIST("os_KPi_eTa_1"), v01.Eta()); registry.fill(HIST("os_KPi_invm_1"), v01.M()); + registry.fill(HIST("os_Ntr_KPi_invm_1"), tracks.size(), v01.M()); + if (v01.M() > 1.8 && v01.M() < 1.9) { + registry.fill(HIST("D0_Ntr_1"), tracks.size()); + registry.fill(HIST("D0_NtrPV_1"), pvtracks); + } } if (gapSide == 2) { registry.fill(HIST("os_KPi_pT_2"), v01.Pt()); registry.fill(HIST("os_KPi_eTa_2"), v01.Eta()); registry.fill(HIST("os_KPi_invm_2"), v01.M()); + registry.fill(HIST("os_Ntr_KPi_invm_2"), tracks.size(), v01.M()); + if (v01.M() > 1.8 && v01.M() < 1.9) { + registry.fill(HIST("D0_Ntr_2"), tracks.size()); + registry.fill(HIST("D0_NtrPV_2"), pvtracks); + registry.fill(HIST("D0_FT0A"), collision.totalFT0AmplitudeA()); + registry.fill(HIST("D0_FT0C"), collision.totalFT0AmplitudeC()); + registry.fill(HIST("D0_FV0A"), collision.totalFV0AmplitudeA()); + registry.fill(HIST("D0_FDDA"), collision.totalFDDAmplitudeA()); + registry.fill(HIST("D0_FDDC"), collision.totalFDDAmplitudeC()); + registry.fill(HIST("D0_ZNA"), collision.energyCommonZNA()); + registry.fill(HIST("D0_ZNC"), collision.energyCommonZNC()); + } } } else if (t0.sign() == t1.sign()) { registry.fill(HIST("ss_KPi_pT"), v01.Pt()); @@ -154,16 +213,38 @@ struct SGD0Analyzer { registry.fill(HIST("os_KPi_pT_0"), v01.Pt()); registry.fill(HIST("os_KPi_eTa_0"), v01.Eta()); registry.fill(HIST("os_KPi_invm_0"), v01.M()); + registry.fill(HIST("os_Ntr_KPi_invm_0"), tracks.size(), v01.M()); + if (v01.M() > 1.8 && v01.M() < 1.9) { + registry.fill(HIST("D0_Ntr_0"), tracks.size()); + registry.fill(HIST("D0_NtrPV_0"), pvtracks); + } } if (gapSide == 1) { registry.fill(HIST("os_KPi_pT_1"), v01.Pt()); registry.fill(HIST("os_KPi_eTa_1"), v01.Eta()); registry.fill(HIST("os_KPi_invm_1"), v01.M()); + registry.fill(HIST("os_Ntr_KPi_invm_1"), tracks.size(), v01.M()); + if (v01.M() > 1.8 && v01.M() < 1.9) { + registry.fill(HIST("D0_Ntr_1"), tracks.size()); + registry.fill(HIST("D0_NtrPV_1"), pvtracks); + } } if (gapSide == 2) { registry.fill(HIST("os_KPi_pT_2"), v01.Pt()); registry.fill(HIST("os_KPi_eTa_2"), v01.Eta()); registry.fill(HIST("os_KPi_invm_2"), v01.M()); + registry.fill(HIST("os_Ntr_KPi_invm_2"), tracks.size(), v01.M()); + if (v01.M() > 1.8 && v01.M() < 1.9) { + registry.fill(HIST("D0_Ntr_2"), tracks.size()); + registry.fill(HIST("D0_NtrPV_2"), pvtracks); + registry.fill(HIST("D0_FT0A"), collision.totalFT0AmplitudeA()); + registry.fill(HIST("D0_FT0C"), collision.totalFT0AmplitudeC()); + registry.fill(HIST("D0_FV0A"), collision.totalFV0AmplitudeA()); + registry.fill(HIST("D0_FDDA"), collision.totalFDDAmplitudeA()); + registry.fill(HIST("D0_FDDC"), collision.totalFDDAmplitudeC()); + registry.fill(HIST("D0_ZNA"), collision.energyCommonZNA()); + registry.fill(HIST("D0_ZNC"), collision.energyCommonZNC()); + } } } else if (t0.sign() == t1.sign()) { registry.fill(HIST("ss_KPi_pT"), v01.Pt()); diff --git a/PWGUD/Tasks/sgExcUniverse.cxx b/PWGUD/Tasks/sgExcUniverse.cxx new file mode 100644 index 00000000000..f7dd3691c25 --- /dev/null +++ b/PWGUD/Tasks/sgExcUniverse.cxx @@ -0,0 +1,172 @@ +// 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. +// +// \Single Gap Event Analyzer +// \author Sasha Bylinkin, alexander.bylinkin@gmail.com +// \since April 2023 + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" + +#include "TVector3.h" +#include "TTree.h" +#include "TFile.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/UDHelpers.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace excl_fs +{ +DECLARE_SOA_COLUMN(GS, gs, int); +DECLARE_SOA_COLUMN(PV, pv, int); +DECLARE_SOA_COLUMN(ZA, za, int); +DECLARE_SOA_COLUMN(ZC, zc, int); +DECLARE_SOA_COLUMN(SIGN, sign, std::vector); +DECLARE_SOA_COLUMN(PX, px, std::vector); +DECLARE_SOA_COLUMN(PY, py, std::vector); +DECLARE_SOA_COLUMN(PZ, pz, std::vector); +DECLARE_SOA_COLUMN(ISELEC, iselec, std::vector); +DECLARE_SOA_COLUMN(ISMUON, ismuon, std::vector); +DECLARE_SOA_COLUMN(ISPION, ispion, std::vector); +DECLARE_SOA_COLUMN(ISKAON, iskaon, std::vector); +DECLARE_SOA_COLUMN(ISPROTON, isproton, std::vector); +} // namespace excl_fs +namespace o2::aod +{ +DECLARE_SOA_TABLE(Excl_fs, "AOD", "EXCL_FS", + excl_fs::GS, excl_fs::PV, excl_fs::ZA, excl_fs::ZC, excl_fs::SIGN, excl_fs::PX, excl_fs::PY, excl_fs::PZ, excl_fs::ISELEC, excl_fs::ISMUON, excl_fs::ISPION, excl_fs::ISKAON, excl_fs::ISPROTON); +} +struct SGExcUniverse { + Produces excl_fs; + SGSelector sgSelector; + + // configurables + Configurable FV0_cut{"FV0", 100., "FV0A threshold"}; + Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; + Configurable FT0A_cut{"FT0A", 100., "FT0A threshold"}; + Configurable FT0C_cut{"FT0C", 50., "FT0C threshold"}; + Configurable FDDA_cut{"FDDA", 10000., "FDDA threshold"}; + Configurable FDDC_cut{"FDDC", 10000., "FDDC threshold"}; + // Track Selections + Configurable PV_cut{"PV_cut", 1.0, "Use Only PV tracks"}; + Configurable dcaZ_cut{"dcaZ_cut", 2.0, "dcaZ cut"}; + Configurable dcaXY_cut{"dcaXY_cut", 0.0, "dcaXY cut (0 for Pt-function)"}; + Configurable tpcChi2_cut{"tpcChi2_cut", 4, "Max tpcChi2NCl"}; + Configurable tpcNClsFindable_cut{"tpcNClsFindable_cut", 70, "Min tpcNClsFindable"}; + Configurable itsChi2_cut{"itsChi2_cut", 36, "Max itsChi2NCl"}; + Configurable eta_cut{"eta_cut", 0.9, "Track Pseudorapidity"}; + Configurable pt_cut{"pt_cut", 0.1, "Track Pt"}; + // PID Selections + Configurable nsigmatpc_cut{"nsigmatpc", 3.0, "nsigma tpc cut"}; + Configurable nsigmatof_cut{"nsigmatof", 9.0, "nsigma tof cut"}; + Configurable use_tof{"Use_TOF", true, "TOF PID"}; + // initialize histogram registry + HistogramRegistry registry{ + "registry", + {}}; + + void init(InitContext&) + { + // Collision histograms + registry.add("collisions/GapSide", "Gap Side: A, C, A+C", {HistType::kTH1F, {{3, -0.5, 2.5}}}); + registry.add("collisions/TrueGapSide", "Gap Side: A, C, A+C", {HistType::kTH1F, {{4, -1.5, 2.5}}}); + } + + // define data types + using UDCollisionsFull = soa::Join; // UDCollisions + using UDCollisionFull = UDCollisionsFull::iterator; + using UDTracksFull = soa::Join; + + void process(UDCollisionFull const& coll, UDTracksFull const& tracks) + { + // fill collision histograms + registry.get(HIST("collisions/GapSide"))->Fill(coll.gapSide(), 1.); + // int truegapSide = sgSelector.trueGap(dgcand, FV0_cut, ZDC_cut); + float FIT_cut[5] = {FV0_cut, FT0A_cut, FT0C_cut, FDDA_cut, FDDC_cut}; + int truegapSide = sgSelector.trueGap(coll, FIT_cut[0], FIT_cut[1], FIT_cut[2], ZDC_cut); + int gs = truegapSide; + registry.get(HIST("collisions/TrueGapSide"))->Fill(truegapSide, 1.); + // select PV contributors + float zna = -1; + float znc = -1; + int an = 0; + int cn = 0; + if (coll.energyCommonZNC() > 0) + znc = coll.energyCommonZNC(); + if (coll.energyCommonZNA() > 0) + zna = coll.energyCommonZNA(); + if (zna > 0 && zna < 4) + an = 1; + else if (zna > 4 && zna < 6.8) + an = 2; + else if (zna > 6.8 && zna < 10) + an = 3; + if (znc > 0 && znc < 4) + cn = 1; + else if (znc > 4 && znc < 6.8) + cn = 2; + else if (znc > 6.8 && znc < 10) + cn = 3; + + std::vector parameters = {PV_cut, dcaZ_cut, dcaXY_cut, tpcChi2_cut, tpcNClsFindable_cut, itsChi2_cut, eta_cut, pt_cut}; + // check rho0 signals + int goodTracks = 0; + std::vector px; + std::vector py; + std::vector pz; + std::vector sign; + std::vector ispion; + std::vector isproton; + std::vector iskaon; + std::vector ismuon; + std::vector iselec; + for (auto t : tracks) { + TLorentzVector a; + if (trackselector(t, parameters)) { + px.push_back(t.px()); + py.push_back(t.py()); + pz.push_back(t.pz()); + sign.push_back(t.sign()); + int hypothesis; + hypothesis = selectionPIDElec(t, use_tof, nsigmatpc_cut, nsigmatof_cut); + iselec.push_back(hypothesis); + hypothesis = selectionPIDMuon(t, use_tof, nsigmatpc_cut, nsigmatof_cut); + ismuon.push_back(hypothesis); + hypothesis = selectionPIDPion(t, use_tof, nsigmatpc_cut, nsigmatof_cut); + ispion.push_back(hypothesis); + hypothesis = selectionPIDKaon(t, use_tof, nsigmatpc_cut, nsigmatof_cut); + iskaon.push_back(hypothesis); + hypothesis = selectionPIDProton(t, use_tof, nsigmatpc_cut, nsigmatof_cut); + isproton.push_back(hypothesis); + goodTracks++; + } + } + // Fill Tables here + if (goodTracks == 2) { + excl_fs(gs, 2, an, cn, sign, px, py, pz, iselec, ismuon, ispion, iskaon, isproton); + } else if (goodTracks == 4) { + excl_fs(gs, 4, an, cn, sign, px, py, pz, iselec, ismuon, ispion, iskaon, isproton); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"sgexcuniverse"}), + }; +} diff --git a/PWGUD/Tasks/sgExclOmega.cxx b/PWGUD/Tasks/sgExclOmega.cxx new file mode 100644 index 00000000000..3e24048e621 --- /dev/null +++ b/PWGUD/Tasks/sgExclOmega.cxx @@ -0,0 +1,189 @@ +// 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. +// +// \Single Gap Event Analyzer +// \author Sasha Bylinkin, alexander.bylinkin@gmail.com +// \since April 2023 + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "iostream" +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/SGSelector.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGUD/Core/SGTrackSelector.h" +#include +#include "TLorentzVector.h" +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +struct SGExclOmega { + SGSelector sgSelector; + Service pdg; + Configurable FV0_cut{"FV0", 100., "FV0A threshold"}; + Configurable FT0A_cut{"FT0A", 100., "FT0A threshold"}; + Configurable FT0C_cut{"FT0C", 50., "FT0C threshold"}; + Configurable FDDA_cut{"FDDA", 10000., "FDDA threshold"}; + Configurable FDDC_cut{"FDDC", 10000., "FDDC threshold"}; + Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; + // Track Selections + Configurable PV_cut{"PV_cut", 1.0, "Use Only PV tracks"}; + Configurable dcaZ_cut{"dcaZ_cut", 2.0, "dcaZ cut"}; + Configurable dcaXY_cut{"dcaXY_cut", 2.0, "dcaXY cut (0 for Pt-function)"}; + Configurable tpcChi2_cut{"tpcChi2_cut", 4, "Max tpcChi2NCl"}; + Configurable tpcNClsFindable_cut{"tpcNClsFindable_cut", 70, "Min tpcNClsFindable"}; + Configurable itsChi2_cut{"itsChi2_cut", 36, "Max itsChi2NCl"}; + Configurable eta_cut{"eta_cut", 0.9, "Track Pseudorapidity"}; + Configurable pt_cut{"pt_cut", 0.1, "Track Pt"}; + // D0 Specific Cuts + Configurable nsigmatpc_cut{"nsigmatpc", 3.0, "nsigma tpc cut"}; + Configurable nsigmatof_cut{"nsigmatof", 9.0, "nsigma tof cut"}; + Configurable use_tof{"Use_TOF", true, "TOF PID"}; + HistogramRegistry registry{ + "registry", + { + + {"GapSide", "Gap Side; Entries", {HistType::kTH1F, {{4, -1.5, 2.5}}}}, + {"TrueGapSide", "Gap Side; Entries", {HistType::kTH1F, {{4, -1.5, 2.5}}}}, + {"os_O_pT", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_O_eTa", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"os_O_invm", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_O_pT", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_O_eTa", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"ss_O_invm", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"pi0_invm", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_O_pt_invm", " Nt vs Mass", {HistType::kTH2F, {{500, 0, 10.}, {500, 0, 2.5}}}}, + {"os_O_pT_pid", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_O_eTa_pid", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"os_O_invm_pid", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_O_pT_pid", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_O_eTa_pid", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"ss_O_invm_pid", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_O_pt_invm_pid", "pt vs Mass", {HistType::kTH2F, {{500, 0, 10.}, {500, 0, 2.5}}}}, + {"pi0_invm_pid", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_O_pT_pid_pi0", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_O_eTa_pid_pi0", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"os_O_invm_pid_pi0", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_O_pT_pid_pi0", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_O_eTa_pid_pi0", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"ss_O_invm_pid_pi0", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_O_pt_invm_pid_pi0", "pt vs Mass", {HistType::kTH2F, {{500, 0, 10.}, {500, 0, 2.5}}}}, + }}; + using udtracks = soa::Join; + using udtracksfull = soa::Join; + using UDCollisionsFull = soa::Join; // + using UDCollisionFull = UDCollisionsFull::iterator; + + void process(UDCollisionFull const& collision, udtracksfull const& tracks) + { + TLorentzVector a; + int gapSide = collision.gapSide(); + if (gapSide < 0 || gapSide > 2) + return; + // Single gap either side + TLorentzVector v0; + TLorentzVector v1; + TLorentzVector v2; + TLorentzVector v3; + TLorentzVector v4; + TLorentzVector v5; + TLorentzVector v01; + std::vector els, pis; + TLorentzVector v00; + // int truegapSide = sgSelector.trueGap(collision); + // int truegapSide = sgSelector.trueGap(collision, FV0_cut, ZDC_cut); + float FIT_cut[5] = {FV0_cut, FT0A_cut, FT0C_cut, FDDA_cut, FDDC_cut}; + std::vector parameters = {PV_cut, dcaZ_cut, dcaXY_cut, tpcChi2_cut, tpcNClsFindable_cut, itsChi2_cut, eta_cut, pt_cut}; + // int truegapSide = sgSelector.trueGap(collision, *FIT_cut, ZDC_cut); + int truegapSide = sgSelector.trueGap(collision, FIT_cut[0], FIT_cut[1], FIT_cut[2], ZDC_cut); + registry.fill(HIST("GapSide"), gapSide); + registry.fill(HIST("TrueGapSide"), truegapSide); + gapSide = truegapSide; + // if (gapSide!=2) return; + int pvtracks = 0; + int esign = 0; + int nElec = 0; + for (auto& t0 : tracks) { + if (trackselector(t0, parameters) && t0.isPVContributor()) { + pvtracks++; + if (selectionPIDElec(t0, use_tof, nsigmatpc_cut, nsigmatof_cut)) { + nElec++; + esign += t0.sign(); + a.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassElectron); + els.push_back(a); + } else { + a.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassPionCharged); + pis.push_back(a); + } + } + } + // Look for D0 and D0bar + // if (pvtracks != 6) return; + if (nElec != 4 || esign != 0 || pvtracks < 6) + return; + // Apply pion hypothesis and create pairs + v00 = els[0] + els[1] + els[2] + els[3]; + for (auto& [t0, t1] : combinations(tracks, tracks)) { + if (selectionPIDElec(t0, use_tof, nsigmatpc_cut, nsigmatof_cut) || selectionPIDElec(t1, use_tof, nsigmatpc_cut, nsigmatof_cut)) + continue; + v0.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassPionCharged); + v1.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassPionCharged); + v01 = v0 + v1 + v00; + // Opposite sign pairs + if (t0.sign() != t1.sign()) { + registry.fill(HIST("os_O_pT"), v01.Pt()); + registry.fill(HIST("os_O_eTa"), v01.Eta()); + registry.fill(HIST("os_O_invm"), v01.M()); + registry.fill(HIST("os_O_pt_invm"), v01.Pt(), v01.M()); + registry.fill(HIST("pi0_invm"), v00.M()); + } else { + registry.fill(HIST("ss_O_pT"), v01.Pt()); + registry.fill(HIST("ss_O_eTa"), v01.Eta()); + registry.fill(HIST("ss_O_invm"), v01.M()); + } + if (selectionPIDPion(t0, use_tof, nsigmatpc_cut, nsigmatof_cut) && selectionPIDPion(t1, use_tof, nsigmatpc_cut, nsigmatof_cut)) { + if (t0.sign() != t1.sign()) { + registry.fill(HIST("os_O_pT_pid"), v01.Pt()); + registry.fill(HIST("os_O_eTa_pid"), v01.Eta()); + registry.fill(HIST("os_O_invm_pid"), v01.M()); + registry.fill(HIST("os_O_pt_invm_pid"), v01.Pt(), v01.M()); + } else { + registry.fill(HIST("ss_O_pT_pid_pi0"), v01.Pt()); + registry.fill(HIST("ss_O_eTa_pid_pi0"), v01.Eta()); + registry.fill(HIST("ss_O_invm_pid_pi0"), v01.M()); + } + + if (abs(v00.M() - o2::constants::physics::MassPionNeutral) < 0.1) { + if (t0.sign() != t1.sign()) { + registry.fill(HIST("os_O_pT_pid_pi0"), v01.Pt()); + registry.fill(HIST("os_O_eTa_pid_pi0"), v01.Eta()); + registry.fill(HIST("os_O_invm_pid_pi0"), v01.M()); + registry.fill(HIST("os_O_pt_invm_pid_pi0"), v01.Pt(), v01.M()); + } else { + registry.fill(HIST("ss_O_pT_pid_pi0"), v01.Pt()); + registry.fill(HIST("ss_O_eTa_pid_pi0"), v01.Eta()); + registry.fill(HIST("ss_O_invm_pid_pi0"), v01.M()); + } + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/sgExclusivePhi.cxx b/PWGUD/Tasks/sgExclusivePhi.cxx new file mode 100644 index 00000000000..679d1677593 --- /dev/null +++ b/PWGUD/Tasks/sgExclusivePhi.cxx @@ -0,0 +1,743 @@ +// 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. +// +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "iostream" +#include "PWGUD/DataModel/UDTables.h" +#include +#include "TLorentzVector.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGUD/Core/SGSelector.h" + +using std::array; +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// \brief Exclusive phi without PID +/// \author Simone Ragoni, Creighton +/// \author Anisa Khatun, Kansas University +/// \date 14/2/2024 + +struct sgExclusivePhi { + SGSelector sgSelector; + Configurable FV0_cut{"FV0", 100., "FV0A threshold"}; + Configurable FT0A_cut{"FT0A", 200., "FT0A threshold"}; + Configurable FT0C_cut{"FT0C", 100., "FT0C threshold"}; + Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; + Configurable gap_Side{"gap", 2, "gap selection"}; + // defining histograms using histogram registry + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //_____________________________________________________________________________ + Double_t CosThetaHelicityFrame(TLorentzVector pionPositive, + TLorentzVector pionNegative, + TLorentzVector possibleRhoZero) + { + + Double_t HalfSqrtSnn = 2680.; + Double_t MassOfLead208 = 193.6823; + Double_t MomentumBeam = TMath::Sqrt(HalfSqrtSnn * HalfSqrtSnn * 208 * 208 - MassOfLead208 * MassOfLead208); + + TLorentzVector pProjCM(0., 0., -MomentumBeam, HalfSqrtSnn * 208); // projectile + TLorentzVector pTargCM(0., 0., MomentumBeam, HalfSqrtSnn * 208); // target + + TVector3 beta = (-1. / possibleRhoZero.E()) * possibleRhoZero.Vect(); + TLorentzVector pPi1Dipion = pionPositive; + TLorentzVector pPi2Dipion = pionNegative; + TLorentzVector pProjDipion = pProjCM; + TLorentzVector pTargDipion = pTargCM; + + pPi1Dipion.Boost(beta); + pPi2Dipion.Boost(beta); + pProjDipion.Boost(beta); + pTargDipion.Boost(beta); + + TVector3 zaxis = (possibleRhoZero.Vect()).Unit(); + + Double_t CosThetaHE = zaxis.Dot((pPi1Dipion.Vect()).Unit()); + return CosThetaHE; + } + //------------------------------------------------------------------------------------------------------ + Double_t PhiHelicityFrame(TLorentzVector muonPositive, TLorentzVector muonNegative, TLorentzVector possibleJPsi) + { + + // Half of the energy per pair of the colliding nucleons. + Double_t HalfSqrtSnn = 2680.; + Double_t MassOfLead208 = 193.6823; + Double_t MomentumBeam = TMath::Sqrt(HalfSqrtSnn * HalfSqrtSnn * 208 * 208 - MassOfLead208 * MassOfLead208); + + TLorentzVector pProjCM(0., 0., -MomentumBeam, HalfSqrtSnn * 208); // projectile + TLorentzVector pTargCM(0., 0., MomentumBeam, HalfSqrtSnn * 208); // target + + // Translate the dimuon parameters in the dimuon rest frame + TVector3 beta = (-1. / possibleJPsi.E()) * possibleJPsi.Vect(); + TLorentzVector pMu1Dimu = muonPositive; + TLorentzVector pMu2Dimu = muonNegative; + TLorentzVector pProjDimu = pProjCM; + TLorentzVector pTargDimu = pTargCM; + pMu1Dimu.Boost(beta); + pMu2Dimu.Boost(beta); + pProjDimu.Boost(beta); + pTargDimu.Boost(beta); + + // Axes + TVector3 zaxis = (possibleJPsi.Vect()).Unit(); + TVector3 yaxis = ((pProjDimu.Vect()).Cross(pTargDimu.Vect())).Unit(); + TVector3 xaxis = (yaxis.Cross(zaxis)).Unit(); + // + // --- Calculation of the azimuthal angle (Helicity) + // + Double_t phi = TMath::ATan2((pMu1Dimu.Vect()).Dot(yaxis), (pMu1Dimu.Vect()).Dot(xaxis)); + return phi; + } + //----------------------------------------------------------------------------------------------------------------------- + void init(o2::framework::InitContext&) + { + auto hSelectionCounter = registry.add("hSelectionCounter", "hSelectionCounter;;NEvents", HistType::kTH1I, {{12, 0., 12.}}); + TString SelectionCuts[12] = {"NoSelection", "Trackloop", "PVtracks", "|nsigmaka|<3", "|nsigmapi|>3", "|nsigmael|>3", "|nsigmamu|>3", "two tracks", "Phi-peak", "pt<0.2 GeV/c", "pt>0.2 GeV/c"}; + + for (int i = 0; i < 12; i++) { + hSelectionCounter->GetXaxis()->SetBinLabel(i + 1, SelectionCuts[i].Data()); + } + + registry.add("GapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + registry.add("TrueGapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + + registry.add("posx", "Vertex position in x", kTH1F, {{100, -0.5, 0.5}}); + registry.add("posy", "Vertex position in y", kTH1F, {{100, -0.5, 0.5}}); + registry.add("posz", "Vertex position in z", kTH1F, {{1000, -100., 100.}}); + + registry.add("hTracks", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hTracksITSonly", "N_{tracks ITS only}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hITSCluster", "N_{cluster}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hChi2ITSTrkSegment", "N_{cluster}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hTPCCluster", "N_{cluster}", kTH1F, {{200, -0.5, 199.5}}); + registry.add("hTracksKaons", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hdEdx", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon1", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon2", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon3", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon4", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon5", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon6", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon7", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon8", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon9", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + + registry.add("hNsigEvsKa1", "NSigmaKa(t1) vs NSigmaKa (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, 0., 1000.}, {100, 0., 1000}}); + registry.add("hNsigEvsKa2", "NSigmaKa(t1) vs NSigmaKa (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, 0., 1000.}, {100, 0., 1000}}); + registry.add("hMomentum", "p_{#ka};#it{p_{trk}}, GeV/c;", kTH1F, {{100, 0., 3.}}); + registry.add("hClusterSizeAllTracks", "ClusterSizeAllTracks;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeMomentumCut", "ClusterSizeMomentumCut;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeOnlyIdentifiedKaons", "ClusterSizeOnlyIdentifiedKaons;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeOnlyIdentifiedKaons2", "ClusterSizeOnlyIdentifiedKaons;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeOnlyITS", "ClusterSizeOnlyITS;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeOnlyITS2", "ClusterSizeOnlyITS;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeOnlyITS3", "ClusterSizeOnlyITS;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hEta1", "#eta_{#ka};#it{#eta_{trk}}, GeV/c;", kTH1F, {{100, -2., 2.}}); + registry.add("hEta2", "#eta_{#ka};#it{#eta_{trk}}, GeV/c;", kTH1F, {{100, -2., 2.}}); + registry.add("hPtPhi", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("hRapidityPhi", "Rapidity;#it{y_{KK}};", kTH1F, {{100, -2., 2.}}); + registry.add("hMassPhi", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + registry.add("hMassPhiIncoherent", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + + registry.add("hMassPtPhi", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + + auto hSelectionCounter2 = registry.add("hSelectionCounter2", "hSelectionCounter;;NEvents", HistType::kTH1I, {{12, 0., 12.}}); + TString SelectionCuts2[12] = {"NoSelection", "Trackloop", "PVtracks", "|nTPCCluster|<50", " track pt<0.180 GeV/c", "Kaon Band", "ITSCluster<6", "two tracks", "Phi-peak", "pt<0.2 GeV/c", "pt>0.2 GeV/c"}; + + for (int i = 0; i < 12; i++) { + hSelectionCounter2->GetXaxis()->SetBinLabel(i + 1, SelectionCuts2[i].Data()); + } + + registry.add("hMassPhiWithoutPID", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + registry.add("hMassPtPhiWithoutPID", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("hMassPhiWrongMomentumWithoutPID", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1D, {{400, 0., 4.}}); + + // Phi peak region + registry.add("PHI/hPtPhiWithoutPID", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PHI/hMassVsPt", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("PHI/hRapidityPhiWithoutPID", "Rapidity;#it{y_{KK}};", kTH1F, {{100, -2., 2.}}); + registry.add("PHI/hCosThetaPhiWithoutPID", "CosTheta;cos(#theta);", kTH1F, {{100, -2., 2.}}); + registry.add("PHI/hPhiPhiWithoutPID", "Phi;#varphi;", kTH1F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("PHI/hPtKaonVsKaon", "Pt1 vs Pt2;p_{T};p_{T};", kTH2F, {{100, 0., 3.}, {100, 0., 3.}}); + registry.add("PHI/hCostheta_Phi", "Phi vs Costheta;#it{#phi};#it{Cos#Theta};", kTH2F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}, {100, -2, 2}}); + registry.add("PHI/hMassPhiWithoutPIDPionHypothesis", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1D, {{400, 0., 4.}}); + registry.add("PHI/hPtPhiWithoutPIDPionHypothesis", "Pt;#it{p_{t}}, GeV/c;", kTH1D, {{500, 0., 5.}}); + + // DIfferent phi topologies, 2 identified kaons, 1 identified kaon + 1 ITS track with correct selections and 4 ITS clusters + registry.add("KaonBandPHI/hMassPtPhiIdentifiedKaons", "Raw Inv.M;#it{m_{KK}} (GeV/c^{2});Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("KaonBandPHI/hMassPhiIdentifiedKaons", "Raw Inv.M;#it{M_{KK}} (GeV/c^{2});", kTH1F, {{400, 0., 4.}}); + registry.add("KaonBandPHI/hPtPhiIdentifiedKaons", "Pt;#it{p_{t}} (GeV/c);", kTH1F, {{400, 0., 4.}}); + registry.add("KaonBandPHI/hMassPtPhiIdentifiedKaonAndITSkaon", "Raw Inv.M;#it{m_{KK}} (GeV/c^{2});Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("KaonBandPHI/hMassPtPhiIdentifiedKaonAndITSkaon2", "Raw Inv.M;#it{m_{KK}} (GeV/c^{2});Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("KaonBandPHI/hMassPtPhiIdentifiedKaonAndITSkaon3", "Raw Inv.M;#it{m_{KK}} (GeV/c^{2});Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("KaonBandPHI/hMassPhiIdentifiedKaonAndITSkaon", "Raw Inv.M;#it{m_{KK}} (GeV/c^{2});", kTH1F, {{400, 0., 4.}}); + registry.add("KaonBandPHI/hMassPhiIdentifiedKaonAndITSkaon2", "Raw Inv.M;#it{m_{KK}} (GeV/c^{2});", kTH1F, {{400, 0., 4.}}); + registry.add("KaonBandPHI/hMassPhiIdentifiedKaonAndITSkaon3", "Raw Inv.M;#it{m_{KK}} (GeV/c^{2});", kTH1F, {{400, 0., 4.}}); + registry.add("KaonBandPHI/hPtPhiIdentifiedKaonAndITSkaon", "Pt;#it{p_{t}} (GeV/c);", kTH1F, {{400, 0., 4.}}); + registry.add("KaonBandPHI/hPtPhiIdentifiedKaonAndITSkaon2", "Pt;#it{p_{t}} (GeV/c);", kTH1F, {{400, 0., 4.}}); + registry.add("KaonBandPHI/hPtPhiIdentifiedKaonAndITSkaon3", "Pt;#it{p_{t}} (GeV/c);", kTH1F, {{400, 0., 4.}}); + + registry.add("PHI/hMassLike", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{400, 0., 4.}}); + registry.add("PHI/hMassUnlike", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{400, 0., 4.}}); + registry.add("PHI/hlikePt", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PHI/hUnlikePt", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PHI/hCoherentPhiWithoutPID", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + registry.add("PHI/hInCoherentPhiWithoutPID", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + registry.add("PHI/hCoherentMassLike", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + registry.add("PHI/hInCoherentMassLike", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + + // High Mass region + registry.add("PHIHIGH/hPtPhiWithoutPID1", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PHIHIGH/hMassVsPt1", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("PHIHIGH/hRapidityPhiWithoutPID1", "Rapidity;#it{y_{KK}};", kTH1F, {{100, -2., 2.}}); + registry.add("PHIHIGH/hCosThetaPhiWithoutPID1", "CosTheta;cos(#theta);", kTH1F, {{100, -2., 2.}}); + registry.add("PHIHIGH/hPhiPhiWithoutPID1", "Phi;#varphi;", kTH1F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("PHIHIGH/hPtKaonVsKaon1", "Pt1 vs Pt2;p_{T};p_{T};", kTH2F, {{100, 0., 3.}, {100, 0., 3.}}); + registry.add("PHIHIGH/hCostheta_Phi1", "Phi vs Costheta;#it{#phi};#it{Cos#Theta};", kTH2F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}, {100, -2, 2}}); + registry.add("PHIHIGH/hMassPhiWithoutPIDPionHypothesis1", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1D, {{400, 0., 4.}}); + registry.add("PHIHIGH/hPtPhiWithoutPIDPionHypothesis1", "Pt;#it{p_{t}}, GeV/c;", kTH1D, {{500, 0., 5.}}); + + registry.add("PHIHIGH/hMassLike1", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{400, 0., 4.}}); + registry.add("PHIHIGH/hMassUnlike1", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{400, 0., 4.}}); + registry.add("PHIHIGH/hlikePt1", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{400, 0., 4.}}); + registry.add("PHIHIGH/hUnlikePt1", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{400, 0., 4.}}); + registry.add("PHIHIGH/hCoherentPhiWithoutPID1", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + registry.add("PHIHIGH/hInCoherentPhiWithoutPID1", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + registry.add("PHIHIGH/hCoherentMassLike1", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + registry.add("PHIHIGH/hInCoherentMassLike1", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + + // Low Mass region + registry.add("PHILOW/hPtPhiWithoutPID2", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PHILOW/hMassVsPt2", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("PHILOW/hRapidityPhiWithoutPID2", "Rapidity;#it{y_{KK}};", kTH1F, {{100, -2., 2.}}); + registry.add("PHILOW/hCosThetaPhiWithoutPID2", "CosTheta;cos(#theta);", kTH1F, {{100, -2., 2.}}); + registry.add("PHILOW/hPhiPhiWithoutPID2", "Phi;#varphi;", kTH1F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("PHILOW/hPtKaonVsKaon2", "Pt1 vs Pt2;p_{T};p_{T};", kTH2F, {{100, 0., 3.}, {100, 0., 3.}}); + registry.add("PHILOW/hCostheta_Phi2", "Phi vs Costheta;#it{#phi};#it{Cos#Theta};", kTH2F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}, {100, -2, 2}}); + registry.add("PHILOW/hMassPhiWithoutPIDPionHypothesis2", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1D, {{400, 0., 4.}}); + registry.add("PHILOW/hPtPhiWithoutPIDPionHypothesis2", "Pt;#it{p_{t}}, GeV/c;", kTH1D, {{500, 0., 5.}}); + + registry.add("PHILOW/hMassLike2", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{400, 0., 4.}}); + registry.add("PHILOW/hMassUnlike2", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{400, 0., 4.}}); + registry.add("PHILOW/hlikePt2", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{400, 0., 4.}}); + registry.add("PHILOW/hUnlikePt2", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{400, 0., 4.}}); + registry.add("PHILOW/hCoherentPhiWithoutPID2", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + registry.add("PHILOW/hInCoherentPhiWithoutPID2", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + registry.add("PHILOW/hCoherentMassLike2", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + registry.add("PHILOW/hInCoherentMassLike2", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + } + + using udtracks = soa::Join; + using udtracksfull = soa::Join; + using UDCollisionsFull = soa::Join; + //__________________________________________________________________________ + // Main process + void process(UDCollisionsFull::iterator const& collision, udtracksfull const& tracks) + { + registry.fill(HIST("hSelectionCounter"), 0); + + int gapSide = collision.gapSide(); + if (gapSide < 0 || gapSide > 2) + return; + + registry.fill(HIST("posx"), collision.posX()); + registry.fill(HIST("posy"), collision.posY()); + registry.fill(HIST("posz"), collision.posZ()); + int truegapSide = sgSelector.trueGap(collision, FV0_cut, FT0A_cut, FT0C_cut, ZDC_cut); + registry.fill(HIST("GapSide"), gapSide); + registry.fill(HIST("TrueGapSide"), truegapSide); + gapSide = truegapSide; + + if (gapSide == gap_Side) { + TLorentzVector phi, phiWithoutPID, phiWithKaonPID, phiWrongMomentaWithoutPID, phiWithoutPIDPionHypothesis; // lorentz vectors of tracks and the mother + + // =================================== + // Task for phi WITH PID FROM TPC + // =================================== + // Here the tracks are allowed to have + // at most 30 TPC clusters + // TPC PID is then possible, although + // not truly reliable + // NB: from MC simulations coherent + // phi SHOULD NOT leave clusters + // in the TPC at all + std::vector onlyKaonTracks; + std::vector onlyKaonSigma; + std::vector rawKaonTracks; + + for (auto trk : tracks) { + registry.fill(HIST("hSelectionCounter"), 1); + if (!trk.isPVContributor()) { + continue; + } + if (!(std::abs(trk.dcaZ()) < 2.)) { + continue; + } + double dcaLimit = 0.0105 + 0.035 / pow(trk.pt(), 1.1); + if (!(std::abs(trk.dcaXY()) < dcaLimit)) { + continue; + } + registry.fill(HIST("hSelectionCounter"), 2); + + int NFindable = trk.tpcNClsFindable(); + int NMinusFound = trk.tpcNClsFindableMinusFound(); + int NCluster = NFindable - NMinusFound; + registry.fill(HIST("hTPCCluster"), NCluster); + registry.fill(HIST("hITSCluster"), trk.itsNCls()); + registry.fill(HIST("hChi2ITSTrkSegment"), trk.itsChi2NCl()); + + double dEdx = trk.tpcSignal(); + registry.fill(HIST("hdEdx"), trk.tpcInnerParam() / trk.sign(), dEdx); + + TLorentzVector kaon; + kaon.SetXYZM(trk.px(), trk.py(), trk.pz(), o2::constants::physics::MassKaonCharged); + auto nSigmaKa = trk.tpcNSigmaKa(); + auto nSigmaEl = trk.tpcNSigmaEl(); + auto nSigmaPi = trk.tpcNSigmaPi(); + auto nSigmaMu = trk.tpcNSigmaMu(); + + // if((nSigmaKa * nSigmaKa + nSigmaKa * nSigmaKa) > 9.) continue; + if (fabs(nSigmaKa) > 3.) + continue; + registry.fill(HIST("hSelectionCounter"), 3); + registry.fill(HIST("hdEdxKaon1"), trk.tpcInnerParam() / trk.sign(), dEdx); + // if((nSigmaEl * nSigmaEl + nSigmaEl * nSigmaEl) < 9.) continue; + if (fabs(nSigmaPi) < 3.) + continue; + registry.fill(HIST("hSelectionCounter"), 4); + registry.fill(HIST("hdEdxKaon2"), trk.tpcInnerParam() / trk.sign(), dEdx); + // if((nSigmaPi * nSigmaPi + nSigmaPi * nSigmaPi) < 9.) continue; + if (fabs(nSigmaEl) < 3.) + continue; + registry.fill(HIST("hSelectionCounter"), 5); + registry.fill(HIST("hdEdxKaon3"), trk.tpcInnerParam() / trk.sign(), dEdx); + // if((nSigmaMu * nSigmaMu + nSigmaMu * nSigmaMu) < 9.) continue; + if (fabs(nSigmaMu) < 3.) + continue; + registry.fill(HIST("hSelectionCounter"), 6); + registry.fill(HIST("hdEdxKaon4"), trk.tpcInnerParam() / trk.sign(), dEdx); + + onlyKaonTracks.push_back(kaon); + onlyKaonSigma.push_back(nSigmaKa); + rawKaonTracks.push_back(trk); + + } // trk loop + + if (onlyKaonTracks.size() == 2) { + registry.fill(HIST("hSelectionCounter"), 7); + + for (auto kaon : onlyKaonTracks) { + phi += kaon; + } + + registry.fill(HIST("hdEdxKaon"), rawKaonTracks[0].tpcInnerParam() / rawKaonTracks[0].sign(), rawKaonTracks[1].tpcSignal()); + registry.fill(HIST("hNsigEvsKa1"), rawKaonTracks[0].tpcSignal(), rawKaonTracks[1].tpcSignal()); + registry.fill(HIST("hMassPtPhi"), phi.M(), phi.Pt()); + registry.fill(HIST("hRapidityPhi"), phi.Rapidity()); + + if (rawKaonTracks[0].sign() != rawKaonTracks[1].sign()) { + if ((phi.M() > 0.98) && (phi.M() < 1.05)) { + registry.fill(HIST("hSelectionCounter"), 8); + registry.fill(HIST("hPtPhi"), phi.Pt()); + + if (phi.Pt() < 0.2) { + registry.fill(HIST("hMassPhi"), phi.M()); + registry.fill(HIST("hSelectionCounter"), 9); + } + + if (phi.Pt() > 0.2) { + registry.fill(HIST("hMassPhiIncoherent"), phi.M()); + registry.fill(HIST("hSelectionCounter"), 10); + } + } + } + } + + // =================================== + // Task for phi WITHOUT PID + // =================================== + + // ==================================== + // Selections for events to be stored + // ------------------------------------ + // - PV: only PV contributors + // - only two PV contributors + // - both PV have t.hasITS() ON + // - only ITS tracks + //_____________________________________ + // Create kaons WITHOUT PID + std::vector onlyTwoTracks; + std::vector onlyKaonBandPID; + std::vector onlyITS; + std::vector allTracksAreKaons; + std::vector allTracksArePions; + std::vector allTracksAreKaonsWrongMomentum; + std::vector allTracksAreKaonsBandPID; + std::vector allTracksAreITSonlyAndFourITSclusters; + std::vector booleanAvgClusterSizePerTrackKaonBand; + std::vector booleanAvgClusterSizePerTrackITSonly; + + int counter = 0; + for (auto t : tracks) { + registry.fill(HIST("hSelectionCounter2"), 0); + if (!t.isPVContributor()) { + continue; + } + registry.fill(HIST("hSelectionCounter2"), 1); + registry.fill(HIST("hTracks"), t.size()); + + double momentum = TMath::Sqrt(t.px() * t.px() + t.py() * t.py() + t.pz() * t.pz()); + double dEdx = t.tpcSignal(); + + int clusterSize[7]; + double averageClusterSize = 0.; + for (int i = 0; i < 7; i++) { // info stored in 4 bits + clusterSize[i] = (((1 << 4) - 1) & (t.itsClusterSizes() >> 4 * i)); + averageClusterSize += static_cast(clusterSize[i]); + } + averageClusterSize /= 7.; + registry.fill(HIST("hClusterSizeAllTracks"), averageClusterSize); + + int NFindable = t.tpcNClsFindable(); + int NMinusFound = t.tpcNClsFindableMinusFound(); + int NCluster = NFindable - NMinusFound; + // registry.fill(HIST("hTPCCluster"), NCluster); + + if (NCluster > 50) { + continue; + } + registry.fill(HIST("hSelectionCounter2"), 3); + registry.fill(HIST("hdEdxKaon5"), t.tpcInnerParam() / t.sign(), dEdx); + + if (t.pt() > 0.180) { + continue; + } + if (!(std::abs(t.dcaZ()) < 2.)) { + continue; + } + double dcaLimit = 0.0105 + 0.035 / pow(t.pt(), 1.1); + if (!(std::abs(t.dcaXY()) < dcaLimit)) { + continue; + } + + registry.fill(HIST("hSelectionCounter2"), 4); + registry.fill(HIST("hMomentum"), momentum); + registry.fill(HIST("hdEdxKaon6"), t.tpcInnerParam() / t.sign(), dEdx); + registry.fill(HIST("hClusterSizeMomentumCut"), averageClusterSize); + + onlyTwoTracks.push_back(t); + + TLorentzVector a; + a.SetXYZM(t.px(), t.py(), t.pz(), o2::constants::physics::MassKaonCharged); + TLorentzVector b; + b.SetXYZM(t.px(), t.py(), t.pz(), o2::constants::physics::MassElectron); + TLorentzVector a2; + a2.SetXYZM(-1. * t.px(), -1. * t.py(), -1. * t.pz(), o2::constants::physics::MassKaonCharged); + + allTracksAreKaons.push_back(a); + allTracksArePions.push_back(b); + + if (counter < 1) { + allTracksAreKaonsWrongMomentum.push_back(a); + } else { + allTracksAreKaonsWrongMomentum.push_back(a2); + } + counter += 1; + + bool kaonBand = false; + if ((momentum > 0.180) && (momentum < 0.220) && (dEdx > 300)) { + kaonBand = true; + } else if ((momentum > 0.220) && (momentum < 0.300) && (dEdx > 180)) { + kaonBand = true; + } else if ((momentum > 0.300) && (momentum < 0.500) && (dEdx > 110)) { + kaonBand = true; + } + + if (kaonBand == true) { + registry.fill(HIST("hSelectionCounter2"), 5); + allTracksAreKaonsBandPID.push_back(a); + onlyKaonBandPID.push_back(t); + registry.fill(HIST("hdEdxKaon7"), t.tpcInnerParam() / t.sign(), dEdx); + registry.fill(HIST("hClusterSizeOnlyIdentifiedKaons"), averageClusterSize); + if (averageClusterSize > 5.5) { + booleanAvgClusterSizePerTrackKaonBand.push_back(1); + } else { + booleanAvgClusterSizePerTrackKaonBand.push_back(2); + } + } + + if (NFindable < 1 && t.itsNCls() < 7) { + // if((NCluster==0) && (t.itsNCls() == 4)){ + allTracksAreITSonlyAndFourITSclusters.push_back(a); + onlyITS.push_back(t); + registry.fill(HIST("hdEdxKaon8"), t.tpcInnerParam() / t.sign(), dEdx); + registry.fill(HIST("hSelectionCounter2"), 6); + registry.fill(HIST("hClusterSizeOnlyITS2"), averageClusterSize); + if (averageClusterSize > 5.5) { + booleanAvgClusterSizePerTrackITSonly.push_back(1); + } else { + booleanAvgClusterSizePerTrackITSonly.push_back(2); + } + } + + } // track loop + + //_____________________________________ + // Creating phis and saving all the information + // in the case that there are ONLY 2 PV + + // if ((collision.posZ() < -10) || (collision.posZ() > 10)) { + if (fabs(collision.posZ()) < 10.) { + if (allTracksAreKaons.size() == 2) { + registry.fill(HIST("hSelectionCounter2"), 7); + for (auto kaon : allTracksAreKaons) { + phiWithoutPID += kaon; + } + registry.fill(HIST("hTracksKaons"), allTracksAreKaons.size()); + // kaon mass hypothesis with wrong momentum for one track + for (auto kaon : allTracksAreKaonsWrongMomentum) { + phiWrongMomentaWithoutPID += kaon; + } + // pion mass hypothesis + for (auto pion : allTracksArePions) { + phiWithoutPIDPionHypothesis += pion; + } + + registry.fill(HIST("hNsigEvsKa2"), onlyTwoTracks[0].tpcSignal(), onlyTwoTracks[1].tpcSignal()); + registry.fill(HIST("hEta1"), allTracksAreKaons[0].Eta()); + registry.fill(HIST("hEta2"), allTracksAreKaons[1].Eta()); + + auto costhetaPhi = CosThetaHelicityFrame(allTracksAreKaons[0], allTracksAreKaons[1], phiWithoutPID); + auto phiPhi = 1. * TMath::Pi() + PhiHelicityFrame(allTracksAreKaons[0], allTracksAreKaons[1], phiWithoutPID); + + // All invariant mass region + registry.fill(HIST("hMassPhiWithoutPID"), phiWithoutPID.M()); + registry.fill(HIST("hMassPtPhiWithoutPID"), phiWithoutPID.M(), phiWithoutPID.Pt()); + registry.fill(HIST("hMassPhiWrongMomentumWithoutPID"), phiWrongMomentaWithoutPID.M()); + + // Phi peak region + if ((phiWithoutPID.M() > 0.98) && (phiWithoutPID.M() < 1.05)) { + registry.fill(HIST("PHI/hPtPhiWithoutPID"), phiWithoutPID.Pt()); + registry.fill(HIST("PHI/hMassVsPt"), phiWithoutPID.M(), phiWithoutPID.Pt()); + registry.fill(HIST("PHI/hRapidityPhiWithoutPID"), phiWithoutPID.Rapidity()); + registry.fill(HIST("PHI/hPtKaonVsKaon"), allTracksAreKaons[0].Pt(), allTracksAreKaons[1].Pt()); + + registry.fill(HIST("PHI/hPtPhiWithoutPIDPionHypothesis"), phiWithoutPIDPionHypothesis.Pt()); + registry.fill(HIST("PHI/hMassPhiWithoutPIDPionHypothesis"), phiWithoutPIDPionHypothesis.M()); + + // unlike-sign + if (onlyTwoTracks[0].sign() != onlyTwoTracks[1].sign()) { + registry.fill(HIST("hSelectionCounter2"), 8); + registry.fill(HIST("PHI/hCosThetaPhiWithoutPID"), costhetaPhi); + registry.fill(HIST("PHI/hPhiPhiWithoutPID"), phiPhi); + registry.fill(HIST("PHI/hCostheta_Phi"), phiPhi, costhetaPhi); + registry.fill(HIST("PHI/hUnlikePt"), phiWithoutPID.Pt()); + registry.fill(HIST("PHI/hMassUnlike"), phiWithoutPID.M()); + if (phiWithoutPID.Pt() < 0.1) { + registry.fill(HIST("hSelectionCounter2"), 9); + registry.fill(HIST("PHI/hCoherentPhiWithoutPID"), phiWithoutPID.M()); + } + if (phiWithoutPID.Pt() > 0.1) { + registry.fill(HIST("hSelectionCounter2"), 10); + registry.fill(HIST("PHI/hInCoherentPhiWithoutPID"), phiWithoutPID.M()); + } + } + + // Likesign quantities + if (onlyTwoTracks[0].sign() == onlyTwoTracks[1].sign()) { + registry.fill(HIST("PHI/hMassLike"), phiWithoutPID.M()); + registry.fill(HIST("PHI/hlikePt"), phiWithoutPID.Pt()); + + if (phiWithoutPID.Pt() < 0.2) { + registry.fill(HIST("PHI/hCoherentMassLike"), phiWithoutPID.M()); + } + if (phiWithoutPID.Pt() > 0.2) { + registry.fill(HIST("PHI/hInCoherentMassLike"), phiWithoutPID.M()); + } + } + } // Mass cut + + // Side band above phi mass region + if (phiWithoutPID.M() > 1.05) { + + registry.fill(HIST("PHIHIGH/hPtPhiWithoutPID1"), phiWithoutPID.Pt()); + registry.fill(HIST("PHIHIGH/hMassVsPt1"), phiWithoutPID.M(), phiWithoutPID.Pt()); + registry.fill(HIST("PHIHIGH/hRapidityPhiWithoutPID1"), phiWithoutPID.Rapidity()); + + registry.fill(HIST("PHIHIGH/hPtKaonVsKaon1"), allTracksAreKaons[0].Pt(), allTracksAreKaons[1].Pt()); + registry.fill(HIST("PHIHIGH/hPtPhiWithoutPIDPionHypothesis1"), phiWithoutPIDPionHypothesis.Pt()); + registry.fill(HIST("PHIHIGH/hMassPhiWithoutPIDPionHypothesis1"), phiWithoutPIDPionHypothesis.M()); + + // unlike-sign + if (onlyTwoTracks[0].sign() != onlyTwoTracks[1].sign()) { + registry.fill(HIST("PHIHIGH/hCosThetaPhiWithoutPID1"), costhetaPhi); + registry.fill(HIST("PHIHIGH/hPhiPhiWithoutPID1"), phiPhi); + registry.fill(HIST("PHIHIGH/hCostheta_Phi1"), phiPhi, costhetaPhi); + + registry.fill(HIST("PHIHIGH/hUnlikePt1"), phiWithoutPID.Pt()); + registry.fill(HIST("PHIHIGH/hMassUnlike1"), phiWithoutPID.M()); + if (phiWithoutPID.Pt() < 0.2) { + registry.fill(HIST("PHIHIGH/hCoherentPhiWithoutPID1"), phiWithoutPID.M()); + } + if (phiWithoutPID.Pt() > 0.2) { + registry.fill(HIST("PHIHIGH/hInCoherentPhiWithoutPID1"), phiWithoutPID.M()); + } + } + + // Like sign + if (onlyTwoTracks[0].sign() == onlyTwoTracks[1].sign()) { + // Likesign quantities + registry.fill(HIST("PHIHIGH/hMassLike1"), phiWithoutPID.M()); + registry.fill(HIST("PHIHIGH/hlikePt1"), phiWithoutPID.Pt()); + + if (phiWithoutPID.Pt() < 0.2) { + registry.fill(HIST("PHIHIGH/hCoherentMassLike1"), phiWithoutPID.M()); + } + if (phiWithoutPID.Pt() > 0.2) { + registry.fill(HIST("PHIHIGH/hInCoherentMassLike1"), phiWithoutPID.M()); + } + } + } + + // Side band below phi mass region + if (phiWithoutPID.M() < 0.98) { + registry.fill(HIST("PHILOW/hPtPhiWithoutPID2"), phiWithoutPID.Pt()); + registry.fill(HIST("PHILOW/hMassVsPt2"), phiWithoutPID.M(), phiWithoutPID.Pt()); + registry.fill(HIST("PHILOW/hRapidityPhiWithoutPID2"), phiWithoutPID.Rapidity()); + + registry.fill(HIST("PHILOW/hPtKaonVsKaon2"), allTracksAreKaons[0].Pt(), allTracksAreKaons[1].Pt()); + + registry.fill(HIST("PHILOW/hPtPhiWithoutPIDPionHypothesis2"), phiWithoutPIDPionHypothesis.Pt()); + registry.fill(HIST("PHILOW/hMassPhiWithoutPIDPionHypothesis2"), phiWithoutPIDPionHypothesis.M()); + + // unlike-sign + registry.fill(HIST("PHILOW/hCosThetaPhiWithoutPID2"), costhetaPhi); + registry.fill(HIST("PHILOW/hPhiPhiWithoutPID2"), phiPhi); + registry.fill(HIST("PHILOW/hCostheta_Phi2"), phiPhi, costhetaPhi); + registry.fill(HIST("PHILOW/hUnlikePt2"), phiWithoutPID.Pt()); + registry.fill(HIST("PHILOW/hMassUnlike2"), phiWithoutPID.M()); + if (phiWithoutPID.Pt() < 0.2) { + registry.fill(HIST("PHILOW/hCoherentPhiWithoutPID2"), phiWithoutPID.M()); + } + if (phiWithoutPID.Pt() > 0.2) { + registry.fill(HIST("PHILOW/hInCoherentPhiWithoutPID2"), phiWithoutPID.M()); + } + // like-sign + if (onlyTwoTracks[0].sign() == onlyTwoTracks[1].sign()) { + // Likesign quantities + registry.fill(HIST("PHI/hMassLike2"), phiWithoutPID.M()); + registry.fill(HIST("PHI/hlikePt2"), phiWithoutPID.Pt()); + + if (phiWithoutPID.Pt() < 0.2) { + registry.fill(HIST("PHI/hCoherentMassLike2"), phiWithoutPID.M()); + } + + if (phiWithoutPID.Pt() > 0.2) { + registry.fill(HIST("PHI/hInCoherentMassLike2"), phiWithoutPID.M()); + } + } + } + } // end of two tracks only loop + } // vertex cut + + if (allTracksAreKaonsBandPID.size() == 2) { + + TLorentzVector reallyPhi; + for (auto kaon : allTracksAreKaonsBandPID) { + reallyPhi += kaon; + } + + registry.fill(HIST("KaonBandPHI/hMassPtPhiIdentifiedKaons"), reallyPhi.M(), reallyPhi.Pt()); + if (reallyPhi.Pt() < 0.2) { + registry.fill(HIST("KanonBandPHI/hMassPhiIdentifiedKaons"), reallyPhi.M()); + } + registry.fill(HIST("KaonBandPHI/hPtPhiIdentifiedKaons"), reallyPhi.Pt()); + } + + if (allTracksAreKaonsBandPID.size() == 1) { + + double momentum = TMath::Sqrt(onlyKaonBandPID[0].px() * onlyKaonBandPID[0].px() + onlyKaonBandPID[0].py() * onlyKaonBandPID[0].py() + onlyKaonBandPID[0].pz() * onlyKaonBandPID[0].pz()); + double dEdx = onlyKaonBandPID[0].tpcSignal(); + registry.fill(HIST("hdEdxKaon9"), momentum, dEdx); + + // auto ksize = allTracksAreITSonlyAndFourITSclusters.size(); + registry.fill(HIST("hTracksITSonly"), allTracksAreITSonlyAndFourITSclusters.size()); + + for (std::size_t kaon = 0; kaon < allTracksAreITSonlyAndFourITSclusters.size(); kaon++) { + + int clusterSize[7]; + double averageClusterSize = 0.; + for (int i = 0; i < 7; i++) { // info stored in 4 bits + clusterSize[i] = (((1 << 4) - 1) & (onlyITS[kaon].itsClusterSizes() >> 4 * i)); + averageClusterSize += static_cast(clusterSize[i]); + } + averageClusterSize /= 7.; + registry.fill(HIST("hClusterSizeOnlyITS"), averageClusterSize); + if (booleanAvgClusterSizePerTrackITSonly.size() == 1 && booleanAvgClusterSizePerTrackITSonly[0] == 1) { + registry.fill(HIST("hClusterSizeOnlyITS3"), averageClusterSize); + } + + int clusterSizeKaonBand[7]; + double averageClusterSizeKaonBand = 0.; + for (int i = 0; i < 7; i++) { // info stored in 4 bits + clusterSizeKaonBand[i] = (((1 << 4) - 1) & (onlyKaonBandPID[0].itsClusterSizes() >> 4 * i)); + averageClusterSizeKaonBand += static_cast(clusterSizeKaonBand[i]); + } + averageClusterSizeKaonBand /= 7.; + if (booleanAvgClusterSizePerTrackKaonBand.size() == 1 && booleanAvgClusterSizePerTrackKaonBand[0] == 1) { + registry.fill(HIST("hClusterSizeOnlyIdentifiedKaons2"), averageClusterSizeKaonBand); + } + + TLorentzVector reallyPhi; + reallyPhi += allTracksAreKaonsBandPID[0]; + reallyPhi += allTracksAreITSonlyAndFourITSclusters[kaon]; + registry.fill(HIST("KaonBandPHI/hMassPtPhiIdentifiedKaonAndITSkaon"), reallyPhi.M(), reallyPhi.Pt()); + registry.fill(HIST("KaonBandPHI/hPtPhiIdentifiedKaonAndITSkaon"), reallyPhi.Pt()); + if (reallyPhi.Pt() < 0.2) { + registry.fill(HIST("KaonBandPHI/hMassPhiIdentifiedKaonAndITSkaon"), reallyPhi.M()); + } + + if (booleanAvgClusterSizePerTrackKaonBand.size() == 1 && booleanAvgClusterSizePerTrackKaonBand[0] == 1) { + registry.fill(HIST("KaonBandPHI/hMassPtPhiIdentifiedKaonAndITSkaon2"), reallyPhi.M(), reallyPhi.Pt()); + registry.fill(HIST("KaonBandPHI/hPtPhiIdentifiedKaonAndITSkaon2"), reallyPhi.Pt()); + if (reallyPhi.Pt() < 0.2) { + registry.fill(HIST("KaonBandPHI/hMassPhiIdentifiedKaonAndITSkaon2"), reallyPhi.M()); + } + } + + if (booleanAvgClusterSizePerTrackKaonBand.size() == 1 && booleanAvgClusterSizePerTrackITSonly.size() == 1 && booleanAvgClusterSizePerTrackKaonBand[0] == 1 && booleanAvgClusterSizePerTrackITSonly[0] == 1) { + registry.fill(HIST("KaonBandPHI/hMassPtPhiIdentifiedKaonAndITSkaon3"), reallyPhi.M(), reallyPhi.Pt()); + registry.fill(HIST("KaonBandPHI/hPtPhiIdentifiedKaonAndITSkaon3"), reallyPhi.Pt()); + if (reallyPhi.Pt() < 0.2) { + registry.fill(HIST("KaonBandPHI/hMassPhiIdentifiedKaonAndITSkaon3"), reallyPhi.M()); + } + } + } + } // Kaon Band + } // double gap + } // end of process + +}; // end of struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/sgExclusivePhiITSselections.cxx b/PWGUD/Tasks/sgExclusivePhiITSselections.cxx new file mode 100644 index 00000000000..76c56e609f5 --- /dev/null +++ b/PWGUD/Tasks/sgExclusivePhiITSselections.cxx @@ -0,0 +1,399 @@ +// 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. +// +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "iostream" +#include "PWGUD/DataModel/UDTables.h" +#include +#include "TLorentzVector.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGUD/Core/SGSelector.h" + +using std::array; +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// \brief Exclusive phi without PID +/// \author Simone Ragoni, Creighton +/// \date 8/8/2024 + +struct sgExclusivePhiITSselections { + SGSelector sgSelector; + Configurable FV0_cut{"FV0", 100., "FV0A threshold"}; + Configurable FT0A_cut{"FT0A", 200., "FT0A threshold"}; + Configurable FT0C_cut{"FT0C", 100., "FT0C threshold"}; + Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; + Configurable gap_Side{"gap", 2, "gap selection"}; + Configurable DGactive{"DGactive", false, "DG active"}; + Configurable SGactive{"SGactive", true, "SG active"}; + // Configurable DGorSG{"DGorSG", 1, "SG = 1, DG = 2"}; + Configurable NofITShits{"NofITShits", 7, "ITS layers hit"}; + Configurable pt_threshold{"pt_threshold", 0.180, "pT threshold"}; + // defining histograms using histogram registry + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + //----------------------------------------------------------------------------------------------------------------------- + void init(o2::framework::InitContext&) + { + auto hSelectionCounter = registry.add("hSelectionCounter", "hSelectionCounter;;NEvents", HistType::kTH1I, {{12, 0., 12.}}); + TString SelectionCuts[12] = {"NoSelection", "Trackloop", "PVtracks", "|nsigmaka|<3", "|nsigmapi|>3", "|nsigmael|>3", "|nsigmamu|>3", "two tracks", "Phi-peak", "pt<0.2 GeV/c", "pt>0.2 GeV/c"}; + + for (int i = 0; i < 12; i++) { + hSelectionCounter->GetXaxis()->SetBinLabel(i + 1, SelectionCuts[i].Data()); + } + + registry.add("GapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + registry.add("TrueGapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + + registry.add("posx", "Vertex position in x", kTH1F, {{100, -0.5, 0.5}}); + registry.add("posy", "Vertex position in y", kTH1F, {{100, -0.5, 0.5}}); + registry.add("posz", "Vertex position in z", kTH1F, {{1000, -100., 100.}}); + + registry.add("hTracks", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hTracksITSonly", "N_{tracks ITS only}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hITSCluster", "N_{cluster}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hChi2ITSTrkSegment", "N_{cluster}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hTPCCluster", "N_{cluster}", kTH1F, {{200, -0.5, 199.5}}); + registry.add("hTracksKaons", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hdEdx", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon1", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon2", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon3", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon4", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon5", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon6", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon7", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon8", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + registry.add("hdEdxKaon9", "p_{#ka} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + + registry.add("hNsigEvsKa2", "NSigmaKa(t1) vs NSigmaKa (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, 0., 1000.}, {100, 0., 1000}}); + registry.add("hMomentum", "p_{#ka};#it{p_{trk}}, GeV/c;", kTH1F, {{100, 0., 3.}}); + registry.add("hClusterSizeAllTracks", "ClusterSizeAllTracks;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeMomentumCut", "ClusterSizeMomentumCut;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeOnlyIdentifiedKaons", "ClusterSizeOnlyIdentifiedKaons;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeOnlyITS", "ClusterSizeOnlyITS;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeOnlyITS2", "ClusterSizeOnlyITS;Average cls size in the ITS layers;", kTH1F, {{1000, 0., 100.}}); + registry.add("hClusterSizeAllTracksVsP", "ClusterSizeAllTracks vs p; p; Average cls size in the ITS layers", kTH2F, {{100, 0.0, 10.0}, {1000, 0., 100.}}); + registry.add("hClusterSizeMomentumCutVsP", "hClusterSizeMomentumCut vs p; p; Average cls size in the ITS layers", kTH2F, {{100, 0.0, 10.0}, {1000, 0., 100.}}); + registry.add("hClusterSizeOnlyITSVsP", "hClusterSizeOnlyITS vs p; p; Average cls size in the ITS layers", kTH2F, {{100, 0.0, 10.0}, {1000, 0., 100.}}); + registry.add("hEta1", "#eta_{#ka};#it{#eta_{trk}}, GeV/c;", kTH1F, {{100, -2., 2.}}); + + auto hSelectionCounter2 = registry.add("hSelectionCounter2", "hSelectionCounter;;NEvents", HistType::kTH1I, {{12, 0., 12.}}); + TString SelectionCuts2[12] = {"NoSelection", "Trackloop", "PVtracks", "|nTPCCluster|<50", " track pt<0.180 GeV/c", "Kaon Band", "ITSCluster<6", "two tracks", "Phi-peak", "pt<0.2 GeV/c", "pt>0.2 GeV/c"}; + + for (int i = 0; i < 12; i++) { + hSelectionCounter2->GetXaxis()->SetBinLabel(i + 1, SelectionCuts2[i].Data()); + } + + registry.add("hMassPhiWithoutPID", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + registry.add("hMassPtPhiWithoutPID", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + + // Phi peak region + registry.add("PHI/hPtPhiWithoutPID", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PHI/hMassVsPt", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("PHI/hRapidityPhiWithoutPID", "Rapidity;#it{y_{KK}};", kTH1F, {{100, -2., 2.}}); + registry.add("PHI/hPtKaonVsKaon", "Pt1 vs Pt2;p_{T};p_{T};", kTH2F, {{100, 0., 3.}, {100, 0., 3.}}); + + // DIfferent phi topologies, 2 identified kaons, 1 identified kaon + 1 ITS track with correct selections and N ITS clusters + registry.add("KaonBandPHI/hMassPtPhiIdentifiedKaons", "Raw Inv.M;#it{m_{KK}} (GeV/c^{2});Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("KaonBandPHI/hMassPhiIdentifiedKaons", "Raw Inv.M;#it{M_{KK}} (GeV/c^{2});", kTH1F, {{400, 0., 4.}}); + registry.add("KaonBandPHI/hPtPhiIdentifiedKaons", "Pt;#it{p_{t}} (GeV/c);", kTH1F, {{400, 0., 4.}}); + registry.add("KaonBandPHI/hMassPtPhiIdentifiedKaonAndITSkaon", "Raw Inv.M;#it{m_{KK}} (GeV/c^{2});Pt;#it{p_{t}}, GeV/c;", kTH2F, {{400, 0., 4.}, {400, 0., 4.}}); + registry.add("KaonBandPHI/hMassPhiIdentifiedKaonAndITSkaon", "Raw Inv.M;#it{m_{KK}} (GeV/c^{2});", kTH1F, {{400, 0., 4.}}); + registry.add("KaonBandPHI/hPtPhiIdentifiedKaonAndITSkaon", "Pt;#it{p_{t}} (GeV/c);", kTH1F, {{400, 0., 4.}}); + + registry.add("PHI/hMassLike", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{400, 0., 4.}}); + registry.add("PHI/hMassUnlike", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{400, 0., 4.}}); + registry.add("PHI/hlikePt", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PHI/hUnlikePt", "Pt;#it{p_{t}}, GeV/c;", kTH1F, {{500, 0., 5.}}); + registry.add("PHI/hCoherentPhiWithoutPID", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + registry.add("PHI/hInCoherentPhiWithoutPID", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + registry.add("PHI/hCoherentMassLike", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + registry.add("PHI/hInCoherentMassLike", "Raw Inv.M;#it{m_{KK}}, GeV/c^{2};", kTH1F, {{400, 0., 4.}}); + } + + using udtracks = soa::Join; + using udtracksfull = soa::Join; + using UDCollisionsFull = soa::Join; + //__________________________________________________________________________ + // Main process + void eventprocessing(int gapSide, udtracksfull const& tracks) + { + registry.fill(HIST("hSelectionCounter"), 0); + + if (gapSide == gap_Side) { + TLorentzVector phi, phiWithoutPID, phiWithKaonPID; // lorentz vectors of tracks and the mother + + // =================================== + // Task for phi WITHOUT PID + // =================================== + + // ==================================== + // Selections for events to be stored + // ------------------------------------ + // - PV: only PV contributors + // - only two PV contributors + // - both PV have t.hasITS() ON + // - only ITS tracks + //_____________________________________ + // Create kaons WITHOUT PID + std::vector onlyTwoTracks; + std::vector onlyKaonBandPID; + std::vector onlyITS; + std::vector allTracksAreKaons; + std::vector allTracksAreKaonsBandPID; + std::vector allTracksAreITSonlyAndFourITSclusters; + for (auto t : tracks) { + registry.fill(HIST("hSelectionCounter2"), 0); + if (!t.isPVContributor()) { + continue; + } + registry.fill(HIST("hSelectionCounter2"), 1); + registry.fill(HIST("hTracks"), t.size()); + + double momentum = TMath::Sqrt(t.px() * t.px() + t.py() * t.py() + t.pz() * t.pz()); + double dEdx = t.tpcSignal(); + + int clusterSize[7]; + double averageClusterSize = 0.; + double activeClusters = 0.; + for (int i = 0; i < 7; i++) { // info stored in 4 bits + clusterSize[i] = (((1 << 4) - 1) & (t.itsClusterSizes() >> 4 * i)); + auto clusterSizeValue = static_cast(clusterSize[i]); + if (clusterSizeValue != 0) { + averageClusterSize += clusterSizeValue; + activeClusters += 1; + } + averageClusterSize += static_cast(clusterSize[i]); + } + if (activeClusters != 0) { + averageClusterSize /= activeClusters; + } else { + averageClusterSize = -999.; + } + registry.fill(HIST("hClusterSizeAllTracks"), averageClusterSize); + registry.fill(HIST("hClusterSizeAllTracksVsP"), momentum, averageClusterSize); + + int NFindable = t.tpcNClsFindable(); + int NMinusFound = t.tpcNClsFindableMinusFound(); + int NCluster = NFindable - NMinusFound; + + if (NCluster > 50) { + continue; + } + registry.fill(HIST("hSelectionCounter2"), 3); + registry.fill(HIST("hdEdxKaon5"), t.tpcInnerParam() / t.sign(), dEdx); + + if (t.pt() > pt_threshold) { + continue; + } + if (!(std::abs(t.dcaZ()) < 2.)) { + continue; + } + double dcaLimit = 0.0105 + 0.035 / pow(t.pt(), 1.1); + if (!(std::abs(t.dcaXY()) < dcaLimit)) { + continue; + } + + registry.fill(HIST("hSelectionCounter2"), 4); + registry.fill(HIST("hMomentum"), momentum); + registry.fill(HIST("hdEdxKaon6"), t.tpcInnerParam() / t.sign(), dEdx); + registry.fill(HIST("hdEdxKaon2"), momentum, dEdx); + registry.fill(HIST("hClusterSizeMomentumCut"), averageClusterSize); + registry.fill(HIST("hClusterSizeMomentumCutVsP"), momentum, averageClusterSize); + + onlyTwoTracks.push_back(t); + + TLorentzVector a; + a.SetXYZM(t.px(), t.py(), t.pz(), o2::constants::physics::MassKaonCharged); + allTracksAreKaons.push_back(a); + + bool kaonBand = false; + if ((momentum < 0.150) && (dEdx > 300)) { + kaonBand = true; + } else if ((momentum > 0.150) && (momentum < 0.220) && (dEdx > 250)) { + kaonBand = true; + } else if ((momentum > 0.220) && (momentum < 0.300) && (dEdx > 180)) { + kaonBand = true; + } else if ((momentum > 0.300) && (momentum < 0.500) && (dEdx > 110)) { + kaonBand = true; + } + + if (kaonBand == true) { + registry.fill(HIST("hSelectionCounter2"), 5); + allTracksAreKaonsBandPID.push_back(a); + onlyKaonBandPID.push_back(t); + registry.fill(HIST("hdEdxKaon7"), t.tpcInnerParam() / t.sign(), dEdx); + registry.fill(HIST("hClusterSizeOnlyIdentifiedKaons"), averageClusterSize); + } + + if (NFindable < 1 && t.itsNCls() < NofITShits) { + allTracksAreITSonlyAndFourITSclusters.push_back(a); + onlyITS.push_back(t); + registry.fill(HIST("hdEdxKaon8"), t.tpcInnerParam() / t.sign(), dEdx); + registry.fill(HIST("hSelectionCounter2"), 6); + registry.fill(HIST("hClusterSizeOnlyITS2"), averageClusterSize); + } + + } // track loop + + //_____________________________________ + // Creating phis and saving all the information + // in the case that there are ONLY 2 PV + if (allTracksAreKaons.size() == 2) { + registry.fill(HIST("hSelectionCounter2"), 7); + for (auto kaon : allTracksAreKaons) { + phiWithoutPID += kaon; + } + registry.fill(HIST("hTracksKaons"), allTracksAreKaons.size()); + registry.fill(HIST("hNsigEvsKa2"), onlyTwoTracks[0].tpcSignal(), onlyTwoTracks[1].tpcSignal()); + registry.fill(HIST("hEta1"), allTracksAreKaons[0].Eta()); + registry.fill(HIST("hEta1"), allTracksAreKaons[1].Eta()); + + // All invariant mass region + registry.fill(HIST("hMassPhiWithoutPID"), phiWithoutPID.M()); + registry.fill(HIST("hMassPtPhiWithoutPID"), phiWithoutPID.M(), phiWithoutPID.Pt()); + + // Phi peak region + registry.fill(HIST("PHI/hMassVsPt"), phiWithoutPID.M(), phiWithoutPID.Pt()); + if ((phiWithoutPID.M() > 0.98) && (phiWithoutPID.M() < 1.05)) { + registry.fill(HIST("PHI/hPtPhiWithoutPID"), phiWithoutPID.Pt()); + registry.fill(HIST("PHI/hRapidityPhiWithoutPID"), phiWithoutPID.Rapidity()); + registry.fill(HIST("PHI/hPtKaonVsKaon"), allTracksAreKaons[0].Pt(), allTracksAreKaons[1].Pt()); + + // unlike-sign + if (onlyTwoTracks[0].sign() != onlyTwoTracks[1].sign()) { + registry.fill(HIST("hSelectionCounter2"), 8); + registry.fill(HIST("PHI/hUnlikePt"), phiWithoutPID.Pt()); + registry.fill(HIST("PHI/hMassUnlike"), phiWithoutPID.M()); + if (phiWithoutPID.Pt() < 0.1) { + registry.fill(HIST("hSelectionCounter2"), 9); + registry.fill(HIST("PHI/hCoherentPhiWithoutPID"), phiWithoutPID.M()); + } else { + registry.fill(HIST("hSelectionCounter2"), 10); + registry.fill(HIST("PHI/hInCoherentPhiWithoutPID"), phiWithoutPID.M()); + } + } else { + // Likesign quantities + registry.fill(HIST("PHI/hMassLike"), phiWithoutPID.M()); + registry.fill(HIST("PHI/hlikePt"), phiWithoutPID.Pt()); + if (phiWithoutPID.Pt() < 0.2) { + registry.fill(HIST("PHI/hCoherentMassLike"), phiWithoutPID.M()); + } else { + registry.fill(HIST("PHI/hInCoherentMassLike"), phiWithoutPID.M()); + } + } + } // Mass cut + } // end of two tracks only loop + + if (allTracksAreKaonsBandPID.size() == 2) { + registry.fill(HIST("hTracksKaons"), allTracksAreKaonsBandPID.size() + 10); + TLorentzVector reallyPhi; + for (auto kaon : allTracksAreKaonsBandPID) { + reallyPhi += kaon; + } + registry.fill(HIST("KaonBandPHI/hPtPhiIdentifiedKaons"), reallyPhi.Pt()); + registry.fill(HIST("KaonBandPHI/hMassPtPhiIdentifiedKaons"), reallyPhi.M(), reallyPhi.Pt()); + if (reallyPhi.Pt() < 0.2) { + registry.fill(HIST("KanonBandPHI/hMassPhiIdentifiedKaons"), reallyPhi.M()); + } + } + + if (allTracksAreKaonsBandPID.size() == 1 && allTracksAreITSonlyAndFourITSclusters.size() > 0) { + + registry.fill(HIST("hTracksKaons"), allTracksAreKaonsBandPID.size() + 20); + registry.fill(HIST("hTracksKaons"), allTracksAreITSonlyAndFourITSclusters.size() + 40); + + double momentum = TMath::Sqrt(onlyKaonBandPID[0].px() * onlyKaonBandPID[0].px() + onlyKaonBandPID[0].py() * onlyKaonBandPID[0].py() + onlyKaonBandPID[0].pz() * onlyKaonBandPID[0].pz()); + double dEdx = onlyKaonBandPID[0].tpcSignal(); + registry.fill(HIST("hdEdxKaon9"), momentum, dEdx); + registry.fill(HIST("hTracksITSonly"), allTracksAreITSonlyAndFourITSclusters.size()); + + for (std::size_t kaon = 0; kaon < allTracksAreITSonlyAndFourITSclusters.size(); kaon++) { + + int clusterSize[7]; + double averageClusterSize = 0.; + double activeClusters = 0.; + for (int i = 0; i < 7; i++) { // info stored in 4 bits + clusterSize[i] = (((1 << 4) - 1) & (onlyITS[kaon].itsClusterSizes() >> 4 * i)); + auto clusterSizeValue = static_cast(clusterSize[i]); + if (clusterSizeValue != 0) { + averageClusterSize += clusterSizeValue; + activeClusters += 1; + } + averageClusterSize += static_cast(clusterSize[i]); + } + if (activeClusters != 0) { + averageClusterSize /= activeClusters; + } else { + averageClusterSize = -999.; + } + registry.fill(HIST("hClusterSizeOnlyITS"), averageClusterSize); + registry.fill(HIST("hClusterSizeOnlyITSVsP"), momentum, averageClusterSize); + + TLorentzVector reallyPhi; + reallyPhi += allTracksAreKaonsBandPID[0]; + reallyPhi += allTracksAreITSonlyAndFourITSclusters[kaon]; + registry.fill(HIST("KaonBandPHI/hMassPtPhiIdentifiedKaonAndITSkaon"), reallyPhi.M(), reallyPhi.Pt()); + registry.fill(HIST("KaonBandPHI/hPtPhiIdentifiedKaonAndITSkaon"), reallyPhi.Pt()); + if (reallyPhi.Pt() < 0.2) { + registry.fill(HIST("KaonBandPHI/hMassPhiIdentifiedKaonAndITSkaon"), reallyPhi.M()); + } + } + } // Kaon Band + + } // double gap + } // end of process + + void processSG(UDCollisionsFull::iterator const& collision, udtracksfull const& tracks) + // process function subscribing to SG data + { + int gapSide = collision.gapSide(); + if (gapSide < 0 || gapSide > 2) + return; + + registry.fill(HIST("posx"), collision.posX()); + registry.fill(HIST("posy"), collision.posY()); + registry.fill(HIST("posz"), collision.posZ()); + int truegapSide = sgSelector.trueGap(collision, FV0_cut, FT0A_cut, FT0C_cut, ZDC_cut); + registry.fill(HIST("GapSide"), gapSide); + registry.fill(HIST("TrueGapSide"), truegapSide); + gapSide = truegapSide; + + eventprocessing(gapSide, tracks); + } + PROCESS_SWITCH(sgExclusivePhiITSselections, processSG, "Process SG data", SGactive); + + void processDG(aod::UDCollisions::iterator const& collision, udtracksfull const& tracks) + // process function subscribing to DG data + { + int gapSide = 2; + registry.fill(HIST("posx"), collision.posX()); + registry.fill(HIST("posy"), collision.posY()); + registry.fill(HIST("posz"), collision.posZ()); + registry.fill(HIST("GapSide"), gapSide); + eventprocessing(gapSide, tracks); + } + PROCESS_SWITCH(sgExclusivePhiITSselections, processDG, "Process DG data", DGactive); + +}; // end of struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/sgFITAnalyzer.cxx b/PWGUD/Tasks/sgFITAnalyzer.cxx index f8fce60ac6f..73d42421b87 100644 --- a/PWGUD/Tasks/sgFITAnalyzer.cxx +++ b/PWGUD/Tasks/sgFITAnalyzer.cxx @@ -15,23 +15,42 @@ #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "TVector3.h" +#include "TTree.h" +#include "TFile.h" #include "Common/DataModel/PIDResponse.h" #include "PWGUD/DataModel/UDTables.h" #include "PWGUD/Core/UDHelpers.h" #include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -struct SGFITAnalyzer { // UDTutorial01 +namespace bcNtr +{ +DECLARE_SOA_COLUMN(BC, bc, uint64_t); +DECLARE_SOA_COLUMN(PV, pv, int); +DECLARE_SOA_COLUMN(GS, gs, int); +} // namespace bcNtr +namespace o2::aod +{ +DECLARE_SOA_TABLE(BcPvGs, "AOD", "BCPVGS", + bcNtr::BC, bcNtr::PV, bcNtr::GS); +} +struct SGFITAnalyzer { + Produces bcNtr; SGSelector sgSelector; + Service pdg; // configurables Configurable verbose{"Verbose", {}, "Additional print outs"}; ConfigurableAxis ptAxis{"ptAxis", {250, 0.0, 2.5}, "p_T axis"}; + // ConfigurableAxis BCAxis{"BCAxis", {1000000000000, 0.5, 1000000000000.5}, "BC axis"}; + ConfigurableAxis BCAxis{"BCAxis", {100000000000, 500000000000.5, 600000000000.5}, "BC axis"}; ConfigurableAxis etaAxis{"etaAxis", {300, -1.5, 1.5}, ""}; ConfigurableAxis sigTPCAxis{"sigTPCAxis", {100, -100.0, 100.0}, ""}; ConfigurableAxis sigTOFAxis{"sigTOFAxis", {100, -100.0, 100.0}, ""}; @@ -44,6 +63,16 @@ struct SGFITAnalyzer { // UDTutorial01 Configurable FT0C_cut{"FT0C", 50., "FT0C threshold"}; Configurable FDDA_cut{"FDDA", 10000., "FDDA threshold"}; Configurable FDDC_cut{"FDDC", 10000., "FDDC threshold"}; + // Track Selections + Configurable PV_cut{"PV_cut", 1.0, "Use Only PV tracks"}; + Configurable dcaZ_cut{"dcaZ_cut", 2.0, "dcaZ cut"}; + Configurable dcaXY_cut{"dcaXY_cut", 0.0, "dcaXY cut (0 for Pt-function)"}; + Configurable tpcChi2_cut{"tpcChi2_cut", 4, "Max tpcChi2NCl"}; + Configurable tpcNClsFindable_cut{"tpcNClsFindable_cut", 70, "Min tpcNClsFindable"}; + Configurable itsChi2_cut{"itsChi2_cut", 36, "Max itsChi2NCl"}; + Configurable eta_cut{"eta_cut", 0.9, "Track Pseudorapidity"}; + Configurable pt_cut{"pt_cut", 0.1, "Track Pt"}; + Configurable outputFileName{"outputFileName", "AnalysisResults.root", "Output file name"}; // initialize histogram registry HistogramRegistry registry{ "registry", @@ -52,12 +81,17 @@ struct SGFITAnalyzer { // UDTutorial01 void init(InitContext&) { const AxisSpec axispt{ptAxis, "p_{T}"}; + const AxisSpec axismeanpt{ptAxis, ""}; + const AxisSpec axisBC{BCAxis, "BC"}; const AxisSpec axiseta{etaAxis, "#eta"}; const AxisSpec axismult{multAxis, "N_{tracks}"}; const AxisSpec axisfit{FitAxis, "FIT Amplitude"}; const AxisSpec axiszdc{ZDCAxis, "ZDC Amplitude"}; // Collision histograms registry.add("collisions/BC", "Relative BC number; Relative BC; Collisions", {HistType::kTH1F, {{3564, -0.5, 3563.5}}}); + registry.add("collisions/BC_PVCA", "Global BC; Global BC; Multiplicity", {HistType::kTH2F, {axisBC, axismult}}); + registry.add("collisions/BC_PVCC", "Global BC; Global BC; Multiplicity", {HistType::kTH2F, {axisBC, axismult}}); + registry.add("collisions/BC_PVCAC", "Global BC; Global BC; Multiplicity", {HistType::kTH2F, {axisBC, axismult}}); registry.add("collisions/multiplicityAll", "Multiplicity of all tracks; Tracks; Tracks", {HistType::kTH1F, {{axismult}}}); registry.add("collisions/multiplicityPVC", "Multiplicity of PV contributors; PV contributors; Tracks", {HistType::kTH1F, {{axismult}}}); registry.add("collisions/multiplicityPVCA", "Multiplicity of PV contributors A-side; PV contributors; Tracks", {HistType::kTH1F, {{axismult}}}); @@ -75,6 +109,12 @@ struct SGFITAnalyzer { // UDTutorial01 registry.add("collisions/multiplicityZ1PVCAC", "Multiplicity of PV contributors AC-side; PV contributors; Tracks", {HistType::kTH1F, {{axismult}}}); registry.add("collisions/GapSide", "Gap Side: A, C, A+C", {HistType::kTH1F, {{3, -0.5, 2.5}}}); registry.add("collisions/TrueGapSide", "Gap Side: A, C, A+C", {HistType::kTH1F, {{4, -1.5, 2.5}}}); + registry.add("collisions/2D/multiplicityVsMeanPtPVCA", "Multiplicity of PV contributors A-side; PV contributors; mean #{p}_{T}", {HistType::kTH2F, {{axismult}, {axismeanpt}}}); + registry.add("collisions/2D/multiplicityVsEtaPVCA", "Multiplicity of PV contributors A-side; PV contributors; #eta", {HistType::kTH2F, {{axismult}, {axiseta}}}); + registry.add("collisions/2D/multiplicityVsMeanPtPVCC", "Multiplicity of PV contributors C-side; PV contributors; mean #{p}_{T}", {HistType::kTH2F, {{axismult}, {axismeanpt}}}); + registry.add("collisions/2D/multiplicityVsEtaPVCC", "Multiplicity of PV contributors C-side; PV contributors; #eta", {HistType::kTH2F, {{axismult}, {axiseta}}}); + registry.add("collisions/2D/multiplicityVsMeanPtPVCAC", "Multiplicity of PV contributors AC-side; PV contributors; mean #{p}_{T}", {HistType::kTH2F, {{axismult}, {axismeanpt}}}); + registry.add("collisions/2D/multiplicityVsEtaPVCAC", "Multiplicity of PV contributors AC-side; PV contributors; #eta", {HistType::kTH2F, {{axismult}, {axiseta}}}); // track histograms registry.add("tracks/QCAll", "Track QC of all tracks; Hit in detector; Tracks", {HistType::kTH1F, {{5, -0.5, 4.5}}}); @@ -112,10 +152,20 @@ struct SGFITAnalyzer { // UDTutorial01 registry.add("ZDC/CZNA", "Amplitude ZNA, C Gap", {HistType::kTH1F, {{axiszdc}}}); registry.add("ZDC/ACZNA", "Amplitude ZNA, AC Gap", {HistType::kTH1F, {{axiszdc}}}); registry.add("ZDC/ACZNA_CR", "Amplitude ZNA, AC Gap", {HistType::kTH1F, {{axiszdc}}}); + registry.add("ZDC/AZNA_CR", "Amplitude ZNA, AC Gap", {HistType::kTH1F, {{axiszdc}}}); + registry.add("ZDC/CZNA_CR", "Amplitude ZNA, AC Gap", {HistType::kTH1F, {{axiszdc}}}); + registry.add("ZDC/ACZNA_CM", "Amplitude ZNA, AC Gap", {HistType::kTH1F, {{axiszdc}}}); + registry.add("ZDC/AZNA_CM", "Amplitude ZNA, AC Gap", {HistType::kTH1F, {{axiszdc}}}); + registry.add("ZDC/CZNA_CM", "Amplitude ZNA, AC Gap", {HistType::kTH1F, {{axiszdc}}}); registry.add("ZDC/AZNC", "Amplitude ZNC, A Gap", {HistType::kTH1F, {{axiszdc}}}); registry.add("ZDC/CZNC", "Amplitude ZNC, C Gap", {HistType::kTH1F, {{axiszdc}}}); registry.add("ZDC/ACZNC", "Amplitude ZNC, AC Gap", {HistType::kTH1F, {{axiszdc}}}); registry.add("ZDC/ACZNC_CR", "Amplitude ZNC, AC Gap", {HistType::kTH1F, {{axiszdc}}}); + registry.add("ZDC/AZNC_CR", "Amplitude ZNC, AC Gap", {HistType::kTH1F, {{axiszdc}}}); + registry.add("ZDC/CZNC_CR", "Amplitude ZNC, AC Gap", {HistType::kTH1F, {{axiszdc}}}); + registry.add("ZDC/ACZNC_CM", "Amplitude ZNC, AC Gap", {HistType::kTH1F, {{axiszdc}}}); + registry.add("ZDC/AZNC_CM", "Amplitude ZNC, AC Gap", {HistType::kTH1F, {{axiszdc}}}); + registry.add("ZDC/CZNC_CM", "Amplitude ZNC, AC Gap", {HistType::kTH1F, {{axiszdc}}}); registry.add("ZDC/tAZNA", "Time ZNA", {HistType::kTH1F, {{100, -19.5, 19.5}}}); registry.add("ZDC/tAZNC", "Time ZNC", {HistType::kTH1F, {{100, -19.5, 19.5}}}); registry.add("ZDC/tCZNA", "Time ZNA", {HistType::kTH1F, {{100, -19.5, 19.5}}}); @@ -181,6 +231,31 @@ struct SGFITAnalyzer { // UDTutorial01 registry.add("FIT/ACFT0C_CR", "Amplitude FT0C", {HistType::kTH1F, {{axisfit}}}); registry.add("FIT/ACFDDA_CR", "Amplitude FDDA", {HistType::kTH1F, {{axisfit}}}); registry.add("FIT/ACFDDC_CR", "Amplitude FDDC", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/AFV0A_CR", "Amplitude FV0A", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/AFT0A_CR", "Amplitude FT0A", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/AFT0C_CR", "Amplitude FT0C", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/AFDDA_CR", "Amplitude FDDA", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/AFDDC_CR", "Amplitude FDDC", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/CFV0A_CR", "Amplitude FV0A", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/CFT0A_CR", "Amplitude FT0A", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/CFT0C_CR", "Amplitude FT0C", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/CFDDA_CR", "Amplitude FDDA", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/CFDDC_CR", "Amplitude FDDC", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/ACFV0A_CM", "Amplitude FV0A", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/ACFT0A_CM", "Amplitude FT0A", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/ACFT0C_CM", "Amplitude FT0C", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/ACFDDA_CM", "Amplitude FDDA", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/ACFDDC_CM", "Amplitude FDDC", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/AFV0A_CM", "Amplitude FV0A", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/AFT0A_CM", "Amplitude FT0A", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/AFT0C_CM", "Amplitude FT0C", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/AFDDA_CM", "Amplitude FDDA", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/AFDDC_CM", "Amplitude FDDC", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/CFV0A_CM", "Amplitude FV0A", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/CFT0A_CM", "Amplitude FT0A", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/CFT0C_CM", "Amplitude FT0C", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/CFDDA_CM", "Amplitude FDDA", {HistType::kTH1F, {{axisfit}}}); + registry.add("FIT/CFDDC_CM", "Amplitude FDDC", {HistType::kTH1F, {{axisfit}}}); registry.add("FIT/ACFV0A", "Amplitude FV0A", {HistType::kTH1F, {{axisfit}}}); registry.add("FIT/ACFT0A", "Amplitude FT0A", {HistType::kTH1F, {{axisfit}}}); registry.add("FIT/ACFT0C", "Amplitude FT0C", {HistType::kTH1F, {{axisfit}}}); @@ -278,7 +353,8 @@ struct SGFITAnalyzer { // UDTutorial01 using UDCollisionsFull = soa::Join; // UDCollisions // using UDCollisionsFull = soa::Join; // UDCollisions using UDCollisionFull = UDCollisionsFull::iterator; - using UDTracksFull = soa::Join; + // using UDTracksFull = soa::Join; + using UDTracksFull = soa::Join; // using UDTracksFull = soa::Join; void process(UDCollisionFull const& dgcand, UDTracksFull const& dgtracks) @@ -287,45 +363,76 @@ struct SGFITAnalyzer { // UDTutorial01 LOGF(info, " DG candidate %d", dgcand.globalIndex()); } + const float mpion = pdg->Mass(211); + const float mmuon = pdg->Mass(13); // fill collision histograms registry.get(HIST("collisions/GapSide"))->Fill(dgcand.gapSide(), 1.); // int truegapSide = sgSelector.trueGap(dgcand, FV0_cut, ZDC_cut); float FIT_cut[5] = {FV0_cut, FT0A_cut, FT0C_cut, FDDA_cut, FDDC_cut}; // int truegapSide = sgSelector.trueGap(collision, *FIT_cut, ZDC_cut); - int truegapSide = sgSelector.trueGap(dgcand, FIT_cut[0], FIT_cut[1], FIT_cut[3], ZDC_cut); + int truegapSide = sgSelector.trueGap(dgcand, FIT_cut[0], FIT_cut[1], FIT_cut[2], ZDC_cut); + int gs = truegapSide; registry.get(HIST("collisions/TrueGapSide"))->Fill(truegapSide, 1.); // select PV contributors Partition PVContributors = aod::udtrack::isPVContributor == true; PVContributors.bindTable(dgtracks); - if (PVContributors.size() > 50) - return; + // if (PVContributors.size() > 50) + // return; registry.get(HIST("collisions/multiplicityPVC"))->Fill(PVContributors.size(), 1.); + int pv = PVContributors.size(); bool tof = false; // relative BC number auto bcnum = dgcand.globalBC() % o2::constants::lhc::LHCMaxBunches; + uint64_t bc = dgcand.globalBC(); registry.get(HIST("collisions/BC"))->Fill(bcnum, 1.); - // fill track histograms if (verbose) { LOGF(info, " Number of tracks %d", dgtracks.size()); LOGF(info, " Number of PV contributors %d", PVContributors.size()); } + std::vector parameters = {PV_cut, dcaZ_cut, dcaXY_cut, tpcChi2_cut, tpcNClsFindable_cut, itsChi2_cut, eta_cut, pt_cut}; // check rho0 signals bool coh_rho0 = false; - TLorentzVector p1, p2, rho; - if (PVContributors.size() == 2) { - for (auto& [t0, t1] : combinations(dgtracks, dgtracks)) { - // Apply pion hypothesis and create pairs - p1.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassPionCharged); - p2.SetXYZM(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassPionCharged); - rho = p1 + p2; + bool coh_jpsi = false; + TLorentzVector rho, jpsi; + std::vector goodTracks; + std::vector muonTracks; + float sign = 0; + for (auto t : dgtracks) { + TLorentzVector a; + TLorentzVector b; + a.SetXYZM(t.px(), t.py(), t.pz(), mpion); + b.SetXYZM(t.px(), t.py(), t.pz(), mmuon); + if (trackselector(t, parameters)) { + sign += t.sign(); + goodTracks.push_back(a); + if (std::abs(t.tpcNSigmaMu()) < 3) + muonTracks.push_back(b); } - if (TMath::Abs(rho.Rapidity()) < .9 && rho.M() > .5 && rho.M() < 1.2 && rho.Pt() < 0.15) + } + if (goodTracks.size() == 2) { + for (auto pion : goodTracks) { + rho += pion; + } + if (sign == 0 && TMath::Abs(rho.Rapidity()) < .9 && rho.M() > .5 && rho.M() < 1.2 && rho.Pt() < 0.1) coh_rho0 = true; + if (muonTracks.size() == 2) { + for (auto muon : muonTracks) { + jpsi += muon; + } + if (sign == 0 && TMath::Abs(jpsi.Rapidity()) < .9 && jpsi.M() > 2.8 && jpsi.M() < 3.35 && jpsi.Pt() < 0.1) + coh_jpsi = true; + } } int pva = 0; + double avPtPVa = 0; + std::vector vecEtaPVa; int pvc = 0; + double avPtPVc = 0; + std::vector vecEtaPVc; int pvac = 0; + double avPtPVac = 0; + std::vector vecEtaPVac; int z0pva = 0; int z0pvc = 0; int z0pvac = 0; @@ -417,6 +524,24 @@ struct SGFITAnalyzer { // UDTutorial01 registry.get(HIST("ZDC/tCZNC"))->Fill(dgcand.timeZNC(), 1.); } if (truegapSide == 0) { + if (coh_rho0) { + registry.get(HIST("ZDC/AZNA_CR"))->Fill(zna, 1.); + registry.get(HIST("ZDC/AZNC_CR"))->Fill(znc, 1.); + registry.get(HIST("FIT/AFT0A_CR"))->Fill(dgcand.totalFT0AmplitudeA(), 1.); + registry.get(HIST("FIT/AFT0C_CR"))->Fill(dgcand.totalFT0AmplitudeC(), 1.); + registry.get(HIST("FIT/AFV0A_CR"))->Fill(dgcand.totalFV0AmplitudeA(), 1.); + registry.get(HIST("FIT/AFDDA_CR"))->Fill(dgcand.totalFDDAmplitudeA(), 1.); + registry.get(HIST("FIT/AFDDC_CR"))->Fill(dgcand.totalFDDAmplitudeC(), 1.); + } + if (coh_jpsi) { + registry.get(HIST("ZDC/AZNA_CM"))->Fill(zna, 1.); + registry.get(HIST("ZDC/AZNC_CM"))->Fill(znc, 1.); + registry.get(HIST("FIT/AFT0A_CM"))->Fill(dgcand.totalFT0AmplitudeA(), 1.); + registry.get(HIST("FIT/AFT0C_CM"))->Fill(dgcand.totalFT0AmplitudeC(), 1.); + registry.get(HIST("FIT/AFV0A_CM"))->Fill(dgcand.totalFV0AmplitudeA(), 1.); + registry.get(HIST("FIT/AFDDA_CM"))->Fill(dgcand.totalFDDAmplitudeA(), 1.); + registry.get(HIST("FIT/AFDDC_CM"))->Fill(dgcand.totalFDDAmplitudeC(), 1.); + } registry.get(HIST("ZDC/tAZNA"))->Fill(dgcand.timeZNA(), 1.); registry.get(HIST("ZDC/tAZNC"))->Fill(dgcand.timeZNC(), 1.); registry.get(HIST("ZDC/AZNA"))->Fill(zna, 1.); @@ -479,6 +604,24 @@ struct SGFITAnalyzer { // UDTutorial01 registry.get(HIST("ZDC/MAZNC"))->Fill(PVContributors.size(), znc); } if (truegapSide == 1) { + if (coh_rho0) { + registry.get(HIST("ZDC/CZNA_CR"))->Fill(zna, 1.); + registry.get(HIST("ZDC/CZNC_CR"))->Fill(znc, 1.); + registry.get(HIST("FIT/CFT0A_CR"))->Fill(dgcand.totalFT0AmplitudeA(), 1.); + registry.get(HIST("FIT/CFT0C_CR"))->Fill(dgcand.totalFT0AmplitudeC(), 1.); + registry.get(HIST("FIT/CFV0A_CR"))->Fill(dgcand.totalFV0AmplitudeA(), 1.); + registry.get(HIST("FIT/CFDDA_CR"))->Fill(dgcand.totalFDDAmplitudeA(), 1.); + registry.get(HIST("FIT/CFDDC_CR"))->Fill(dgcand.totalFDDAmplitudeC(), 1.); + } + if (coh_jpsi) { + registry.get(HIST("ZDC/CZNA_CM"))->Fill(zna, 1.); + registry.get(HIST("ZDC/CZNC_CM"))->Fill(znc, 1.); + registry.get(HIST("FIT/CFT0A_CM"))->Fill(dgcand.totalFT0AmplitudeA(), 1.); + registry.get(HIST("FIT/CFT0C_CM"))->Fill(dgcand.totalFT0AmplitudeC(), 1.); + registry.get(HIST("FIT/CFV0A_CM"))->Fill(dgcand.totalFV0AmplitudeA(), 1.); + registry.get(HIST("FIT/CFDDA_CM"))->Fill(dgcand.totalFDDAmplitudeA(), 1.); + registry.get(HIST("FIT/CFDDC_CM"))->Fill(dgcand.totalFDDAmplitudeC(), 1.); + } registry.get(HIST("ZDC/CZNA"))->Fill(zna, 1.); registry.get(HIST("ZDC/CZNC"))->Fill(znc, 1.); registry.get(HIST("ZDC/CZNAC"))->Fill(zna, znc); @@ -564,6 +707,15 @@ struct SGFITAnalyzer { // UDTutorial01 registry.get(HIST("FIT/ACFDDA_CR"))->Fill(dgcand.totalFDDAmplitudeA(), 1.); registry.get(HIST("FIT/ACFDDC_CR"))->Fill(dgcand.totalFDDAmplitudeC(), 1.); } + if (coh_jpsi) { + registry.get(HIST("ZDC/ACZNA_CM"))->Fill(zna, 1.); + registry.get(HIST("ZDC/ACZNC_CM"))->Fill(znc, 1.); + registry.get(HIST("FIT/ACFT0A_CM"))->Fill(dgcand.totalFT0AmplitudeA(), 1.); + registry.get(HIST("FIT/ACFT0C_CM"))->Fill(dgcand.totalFT0AmplitudeC(), 1.); + registry.get(HIST("FIT/ACFV0A_CM"))->Fill(dgcand.totalFV0AmplitudeA(), 1.); + registry.get(HIST("FIT/ACFDDA_CM"))->Fill(dgcand.totalFDDAmplitudeA(), 1.); + registry.get(HIST("FIT/ACFDDC_CM"))->Fill(dgcand.totalFDDAmplitudeC(), 1.); + } registry.get(HIST("FIT/ACFT0A"))->Fill(dgcand.totalFT0AmplitudeA(), 1.); registry.get(HIST("FIT/ACFT0C"))->Fill(dgcand.totalFT0AmplitudeC(), 1.); registry.get(HIST("FIT/ACFV0A"))->Fill(dgcand.totalFV0AmplitudeA(), 1.); @@ -572,7 +724,6 @@ struct SGFITAnalyzer { // UDTutorial01 registry.get(HIST("ZDC/MACZNA"))->Fill(PVContributors.size(), zna); registry.get(HIST("ZDC/MACZNC"))->Fill(PVContributors.size(), znc); } - for (auto track : dgtracks) { registry.get(HIST("tracks/QCAll"))->Fill(0., 1.); registry.get(HIST("tracks/QCAll"))->Fill(1., track.hasITS() * 1.); @@ -609,6 +760,9 @@ struct SGFITAnalyzer { // UDTutorial01 registry.get(HIST("tracks/ptPVC"))->Fill(track.pt(), 1.); // registry.get(HIST("tracks/etavsptPVC"))->Fill(vtrk.Eta(), track.pt(), 1.); if (truegapSide == 0) { + pva++; + avPtPVa += track.pt(); + vecEtaPVa.push_back(vtrk.Eta()); registry.get(HIST("tracks/etaApv"))->Fill(vtrk.Eta(), 1.); if (!an) registry.get(HIST("tracks/eta2Apv"))->Fill(vtrk.Eta(), 1.); @@ -616,9 +770,11 @@ struct SGFITAnalyzer { // UDTutorial01 z0pva++; else if (an == 4) z1pva++; - pva++; } if (truegapSide == 1) { + pvc++; + avPtPVc += track.pt(); + vecEtaPVc.push_back(vtrk.Eta()); registry.get(HIST("tracks/etaCpv"))->Fill(vtrk.Eta(), 1.); if (!cn) registry.get(HIST("tracks/eta2Cpv"))->Fill(vtrk.Eta(), 1.); @@ -626,9 +782,11 @@ struct SGFITAnalyzer { // UDTutorial01 z0pvc++; else if (cn == 4) z1pvc++; - pvc++; } if (truegapSide == 2) { + pvac++; + avPtPVac += track.pt(); + vecEtaPVac.push_back(vtrk.Eta()); registry.get(HIST("tracks/etaACpv"))->Fill(vtrk.Eta(), 1.); if (!an && !cn) registry.get(HIST("tracks/eta2ACpv"))->Fill(vtrk.Eta(), 1.); @@ -636,18 +794,29 @@ struct SGFITAnalyzer { // UDTutorial01 z0pvac++; else if (an >= 3 && cn >= 3) z1pvac++; - pvac++; } registry.get(HIST("tracks/TPCSignalvspPVC"))->Fill(vtrk.Mag(), signalTPC, 1.); registry.get(HIST("tracks/TOFSignalvspPVC"))->Fill(vtrk.Mag(), signalTOF, 1.); } } - if (pva) + if (pva) { registry.get(HIST("collisions/multiplicityPVCA"))->Fill(pva, 1.); - if (pvc) + registry.get(HIST("collisions/2D/multiplicityVsMeanPtPVCA"))->Fill(pva, avPtPVa / pva, 1.); + for (auto& element : vecEtaPVa) + registry.get(HIST("collisions/2D/multiplicityVsEtaPVCA"))->Fill(pva, element, 1.); + } + if (pvc) { registry.get(HIST("collisions/multiplicityPVCC"))->Fill(pvc, 1.); - if (pvac) + registry.get(HIST("collisions/2D/multiplicityVsMeanPtPVCC"))->Fill(pvc, avPtPVc / pvc, 1.); + for (auto& element : vecEtaPVc) + registry.get(HIST("collisions/2D/multiplicityVsEtaPVCC"))->Fill(pvc, element, 1.); + } + if (pvac) { registry.get(HIST("collisions/multiplicityPVCAC"))->Fill(pvac, 1.); + registry.get(HIST("collisions/2D/multiplicityVsMeanPtPVCAC"))->Fill(pvac, avPtPVac / pvac, 1.); + for (auto& element : vecEtaPVac) + registry.get(HIST("collisions/2D/multiplicityVsEtaPVCAC"))->Fill(pvac, element, 1.); + } if (pva) registry.get(HIST("collisions/multiplicityZ0PVCA"))->Fill(z0pva, 1.); if (pvc) @@ -681,6 +850,8 @@ struct SGFITAnalyzer { // UDTutorial01 registry.get(HIST("FIT/BBFDDA"))->Fill(bit - 16, TESTBIT(dgcand.bbFDDApf(), bit)); registry.get(HIST("FIT/BBFDDC"))->Fill(bit - 16, TESTBIT(dgcand.bbFDDCpf(), bit)); } + // Fill Table here + bcNtr(bc, pv, gs); } }; diff --git a/PWGUD/Tasks/sgFourPiAnalyzer.cxx b/PWGUD/Tasks/sgFourPiAnalyzer.cxx index 94cef29adc0..fb437863ed8 100644 --- a/PWGUD/Tasks/sgFourPiAnalyzer.cxx +++ b/PWGUD/Tasks/sgFourPiAnalyzer.cxx @@ -16,35 +16,42 @@ #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "iostream" #include "PWGUD/DataModel/UDTables.h" #include "PWGUD/Core/SGSelector.h" -#include "PWGUD/Tasks/SGTrackSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" #include "Common/DataModel/PIDResponse.h" #include "Framework/ASoA.h" #include "Framework/DataTypes.h" #include "MathUtils/Utils.h" #include "Common/DataModel/TrackSelectionTables.h" - #include #include "TLorentzVector.h" using namespace std; using namespace o2; using namespace o2::aod; -// using namespace o2::aod::track::v001; using namespace o2::framework; using namespace o2::framework::expressions; -#define mpion 0.1396 -#define mkaon 0.4937 -#define mproton 0.9383 struct SGFourPiAnalyzer { SGSelector sgSelector; + Service pdg; + // Adjusted Gap thresholds Configurable FV0_cut{"FV0", 50., "FV0A threshold"}; Configurable FT0A_cut{"FT0A", 150., "FT0A threshold"}; Configurable FT0C_cut{"FT0C", 50., "FT0C threshold"}; Configurable FDDA_cut{"FDDA", 10000., "FDDA threshold"}; Configurable FDDC_cut{"FDDC", 10000., "FDDC threshold"}; Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; + // Track Selections + Configurable PV_cut{"PV_cut", 1.0, "Use Only PV tracks"}; + Configurable dcaZ_cut{"dcaZ_cut", 2.0, "dcaZ cut"}; + Configurable dcaXY_cut{"dcaXY_cut", 0.0, "dcaXY cut (0 for Pt-function)"}; + Configurable tpcChi2_cut{"tpcChi2_cut", 4, "Max tpcChi2NCl"}; + Configurable tpcNClsFindable_cut{"tpcNClsFindable_cut", 70, "Min tpcNClsFindable"}; + Configurable itsChi2_cut{"itsChi2_cut", 36, "Max itsChi2NCl"}; + Configurable eta_cut{"eta_cut", 0.9, "Track Pseudorapidity"}; + Configurable pt_cut{"pt_cut", 0.1, "Track Pt"}; HistogramRegistry registry{ "registry", { @@ -84,6 +91,7 @@ struct SGFourPiAnalyzer { void process(UDCollisionFull const& collision, udtracksfull const& tracks) { + const float mpion = pdg->Mass(211); TLorentzVector a; int gapSide = collision.gapSide(); if (gapSide < 0 || gapSide > 2) @@ -93,13 +101,13 @@ struct SGFourPiAnalyzer { // int truegapSide = sgSelector.trueGap(collision); // int truegapSide = sgSelector.trueGap(collision, FV0_cut, ZDC_cut); float FIT_cut[5] = {FV0_cut, FT0A_cut, FT0C_cut, FDDA_cut, FDDC_cut}; + std::vector parameters = {PV_cut, dcaZ_cut, dcaXY_cut, tpcChi2_cut, tpcNClsFindable_cut, itsChi2_cut, eta_cut, pt_cut}; // int truegapSide = sgSelector.trueGap(collision, *FIT_cut, ZDC_cut); - int truegapSide = sgSelector.trueGap(collision, FIT_cut[0], FIT_cut[1], FIT_cut[3], ZDC_cut); + int truegapSide = sgSelector.trueGap(collision, FIT_cut[0], FIT_cut[1], FIT_cut[2], ZDC_cut); registry.fill(HIST("GapSide"), gapSide); registry.fill(HIST("TrueGapSide"), truegapSide); gapSide = truegapSide; std::vector goodTracks; - // Look for D0 and D0bar float sign = 0; for (auto t : tracks) { int itsNCls = t.itsNCls(); @@ -108,7 +116,7 @@ struct SGFourPiAnalyzer { //} TLorentzVector a; a.SetXYZM(t.px(), t.py(), t.pz(), mpion); - if (trackselector(t)) { + if (trackselector(t, parameters)) { sign += t.sign(); goodTracks.push_back(a); } diff --git a/PWGUD/Tasks/sgInclJpsi.cxx b/PWGUD/Tasks/sgInclJpsi.cxx new file mode 100644 index 00000000000..7e0557ef5f0 --- /dev/null +++ b/PWGUD/Tasks/sgInclJpsi.cxx @@ -0,0 +1,395 @@ +// 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. +// +// \Single Gap Event Analyzer +// \author Sasha Bylinkin, alexander.bylinkin@gmail.com +// \since April 2023 + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "iostream" +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/SGSelector.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGUD/Core/SGTrackSelector.h" +#include +#include "TLorentzVector.h" +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +struct SGInclJpsi { + SGSelector sgSelector; + Service pdg; + Configurable FV0_cut{"FV0", 100., "FV0A threshold"}; + Configurable FT0A_cut{"FT0A", 100., "FT0A threshold"}; + Configurable FT0C_cut{"FT0C", 50., "FT0C threshold"}; + Configurable FDDA_cut{"FDDA", 10000., "FDDA threshold"}; + Configurable FDDC_cut{"FDDC", 10000., "FDDC threshold"}; + Configurable ZDC_cut{"ZDC", 1., "ZDC threshold"}; + // Track Selections + Configurable PV_cut{"PV_cut", 1.0, "Use Only PV tracks"}; + Configurable dcaZ_cut{"dcaZ_cut", 2.0, "dcaZ cut"}; + Configurable dcaXY_cut{"dcaXY_cut", 0, "dcaXY cut (0 for Pt-function)"}; + Configurable tpcChi2_cut{"tpcChi2_cut", 4, "Max tpcChi2NCl"}; + Configurable tpcNClsFindable_cut{"tpcNClsFindable_cut", 70, "Min tpcNClsFindable"}; + Configurable itsChi2_cut{"itsChi2_cut", 36, "Max itsChi2NCl"}; + Configurable eta_cut{"eta_cut", 0.9, "Track Pseudorapidity"}; + Configurable pt_cut{"pt_cut", 0.1, "Track Pt"}; + // JPsi Specific Cuts + Configurable nsigmatpc_cut{"nsigmatpc", 3.0, "nsigma tpc cut"}; + Configurable nsigmatof_cut{"nsigmatof", 9.0, "nsigma tof cut"}; + Configurable use_tof{"Use_TOF", true, "TOF PID"}; + HistogramRegistry registry{ + "registry", + { + + {"GapSide", "Gap Side; Entries", {HistType::kTH1F, {{4, -1.5, 2.5}}}}, + {"TrueGapSide", "Gap Side; Entries", {HistType::kTH1F, {{4, -1.5, 2.5}}}}, + {"Ntr", "Ntracks", {HistType::kTH1F, {{50, -.5, 49.5}}}}, + {"Ntr_0", "Ntracks", {HistType::kTH1F, {{50, -.5, 49.5}}}}, + {"Ntr_1", "Ntracks", {HistType::kTH1F, {{50, -.5, 49.5}}}}, + {"Ntr_2", "Ntracks", {HistType::kTH1F, {{50, -.5, 49.5}}}}, + {"Ntr_3", "Ntracks", {HistType::kTH1F, {{50, -.5, 49.5}}}}, + {"os_mm_pT", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_mm_eTa", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"os_mm_invm", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_mm_pT", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_mm_eTa", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"ss_mm_invm", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_mm_pT_0", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_mm_eTa_0", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"os_mm_invm_0", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_mm_pT_0", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_mm_eTa_0", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"ss_mm_invm_0", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_mm_pT_1", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_mm_eTa_1", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"os_mm_invm_1", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_mm_pT_1", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_mm_eTa_1", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"ss_mm_invm_1", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_mm_pT_2", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_mm_eTa_2", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"os_mm_invm_2", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_mm_pT_2", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_mm_eTa_2", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"ss_mm_invm_2", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_mm_pT_3", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_mm_eTa_3", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"os_mm_invm_3", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_mm_pT_3", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_mm_eTa_3", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"ss_mm_invm_3", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_Ntr_mm_invm_0", "N tracks vs #mu#mu Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"os_Ntr_mm_invm_1", "N tracks vs #mu#mu Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"os_Ntr_mm_invm_2", "N tracks vs #mu#mu Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"os_Ntr_mm_invm_3", "N tracks vs #mu#mu Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"ss_Ntr_mm_invm_0", "N tracks vs #mu#mu Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"ss_Ntr_mm_invm_1", "N tracks vs #mu#mu Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"ss_Ntr_mm_invm_2", "N tracks vs #mu#mu Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"ss_Ntr_mm_invm_3", "N tracks vs #mu#mu Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"sss_Ntr_mm_invm_0", "N tracks vs #mu#mu Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"sss_Ntr_mm_invm_1", "N tracks vs #mu#mu Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"sss_Ntr_mm_invm_2", "N tracks vs #mu#mu Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"sss_Ntr_mm_invm_3", "N tracks vs #mu#mu Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"os_ee_pT", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_ee_eTa", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"os_ee_invm", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_ee_pT", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_ee_eTa", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"ss_ee_invm", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_ee_pT_0", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_ee_eTa_0", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"os_ee_invm_0", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_ee_pT_0", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_ee_eTa_0", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"ss_ee_invm_0", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_ee_pT_1", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_ee_eTa_1", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"os_ee_invm_1", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_ee_pT_1", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_ee_eTa_1", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"ss_ee_invm_1", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_ee_pT_2", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_ee_eTa_2", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"os_ee_invm_2", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_ee_pT_2", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_ee_eTa_2", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"ss_ee_invm_2", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_ee_pT_3", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_ee_eTa_3", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"os_ee_invm_3", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_ee_pT_3", "pT (GeV/c); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"ss_ee_eTa_3", "eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"ss_ee_invm_3", "Mass (GeV/c^2); Entries", {HistType::kTH1F, {{5000, 0, 10}}}}, + {"os_ee_pt_invm_0", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"os_ee_pt_invm_1", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"os_ee_pt_invm_2", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"os_ee_pt_invm_3", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"os_mm_pt_invm_0", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"os_mm_pt_invm_1", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"os_mm_pt_invm_2", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"os_mm_pt_invm_3", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"os_Ntr_ee_invm_0", "N tracks vs ee Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"os_Ntr_ee_invm_1", "N tracks vs ee Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"os_Ntr_ee_invm_2", "N tracks vs ee Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"os_Ntr_ee_invm_3", "N tracks vs ee Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"ss_ee_pt_invm_0", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"ss_ee_pt_invm_1", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"ss_ee_pt_invm_2", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"ss_ee_pt_invm_3", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"ss_mm_pt_invm_0", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"ss_mm_pt_invm_1", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"ss_mm_pt_invm_2", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"ss_mm_pt_invm_3", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"ss_Ntr_ee_invm_0", "N tracks vs ee Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"ss_Ntr_ee_invm_1", "N tracks vs ee Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"ss_Ntr_ee_invm_2", "N tracks vs ee Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"ss_Ntr_ee_invm_3", "N tracks vs ee Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"sss_ee_pt_invm_0", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"sss_ee_pt_invm_1", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"sss_ee_pt_invm_2", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"sss_ee_pt_invm_3", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"sss_mm_pt_invm_0", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"sss_mm_pt_invm_1", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"sss_mm_pt_invm_2", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"sss_mm_pt_invm_3", "N tracks vs ee Mass", {HistType::kTH2F, {{500, 0, 10}, {600, 2., 5.}}}}, + {"sss_Ntr_ee_invm_0", "N tracks vs ee Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"sss_Ntr_ee_invm_1", "N tracks vs ee Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"sss_Ntr_ee_invm_2", "N tracks vs ee Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + {"sss_Ntr_ee_invm_3", "N tracks vs ee Mass", {HistType::kTH2F, {{48, 1.5, 49.5}, {600, 2., 5.}}}}, + }}; + using udtracks = soa::Join; + using udtracksfull = soa::Join; + using UDCollisionsFull = soa::Join; // + using UDCollisionFull = UDCollisionsFull::iterator; + + void process(UDCollisionFull const& collision, udtracksfull const& tracks) + { + TLorentzVector a; + int gapSide = collision.gapSide(); + if (gapSide < 0 || gapSide > 2) + return; + // Single gap either side + TLorentzVector v0; + TLorentzVector v1; + TLorentzVector v01; + // int truegapSide = sgSelector.trueGap(collision); + // int truegapSide = sgSelector.trueGap(collision, FV0_cut, ZDC_cut); + float FIT_cut[5] = {FV0_cut, FT0A_cut, FT0C_cut, FDDA_cut, FDDC_cut}; + std::vector parameters = {PV_cut, dcaZ_cut, dcaXY_cut, tpcChi2_cut, tpcNClsFindable_cut, itsChi2_cut, eta_cut, pt_cut}; + // int truegapSide = sgSelector.trueGap(collision, *FIT_cut, ZDC_cut); + int truegapSide = sgSelector.trueGap(collision, FIT_cut[0], FIT_cut[1], FIT_cut[2], ZDC_cut); + registry.fill(HIST("GapSide"), gapSide); + registry.fill(HIST("TrueGapSide"), truegapSide); + gapSide = truegapSide; + int pvtracks = 0; + for (auto& t0 : tracks) { + if (trackselector(t0, parameters) && t0.isPVContributor()) + pvtracks++; + } + registry.fill(HIST("Ntr"), pvtracks); + if (gapSide == 0) + registry.fill(HIST("Ntr_0"), pvtracks); + if (gapSide == 1) + registry.fill(HIST("Ntr_1"), pvtracks); + if (gapSide == 2) + registry.fill(HIST("Ntr_2"), pvtracks); + if (gapSide == -1) + registry.fill(HIST("Ntr_3"), pvtracks); + // Look for D0 and D0bar + for (auto& [t0, t1] : combinations(tracks, tracks)) { + // PID cut - t0=K, t1=pi + if (!trackselector(t0, parameters) || !trackselector(t1, parameters)) + continue; + if (selectionPIDMuon(t0, use_tof, nsigmatpc_cut, nsigmatof_cut) && selectionPIDMuon(t1, use_tof, nsigmatpc_cut, nsigmatof_cut)) { + // Apply pion hypothesis and create pairs + v0.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassMuon); + v1.SetXYZM(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassMuon); + v01 = v0 + v1; + // Opposite sign pairs + if (t0.sign() != t1.sign()) { + registry.fill(HIST("os_mm_pT"), v01.Pt()); + registry.fill(HIST("os_mm_eTa"), v01.Eta()); + registry.fill(HIST("os_mm_invm"), v01.M()); + if (gapSide == 0) { + registry.fill(HIST("os_mm_pT_0"), v01.Pt()); + registry.fill(HIST("os_mm_eTa_0"), v01.Eta()); + registry.fill(HIST("os_mm_invm_0"), v01.M()); + registry.fill(HIST("os_Ntr_mm_invm_0"), tracks.size(), v01.M()); + registry.fill(HIST("os_mm_pt_invm_0"), v01.Pt(), v01.M()); + registry.fill(HIST("sss_Ntr_mm_invm_0"), tracks.size(), v01.M()); + registry.fill(HIST("sss_mm_pt_invm_0"), v01.Pt(), v01.M()); + } else if (gapSide == 1) { + registry.fill(HIST("os_mm_pT_1"), v01.Pt()); + registry.fill(HIST("os_mm_eTa_1"), v01.Eta()); + registry.fill(HIST("os_mm_invm_1"), v01.M()); + registry.fill(HIST("os_Ntr_mm_invm_1"), tracks.size(), v01.M()); + registry.fill(HIST("os_mm_pt_invm_1"), v01.Pt(), v01.M()); + registry.fill(HIST("sss_Ntr_mm_invm_1"), tracks.size(), v01.M()); + registry.fill(HIST("sss_mm_pt_invm_1"), v01.Pt(), v01.M()); + } else if (gapSide == 2) { + registry.fill(HIST("os_mm_pT_2"), v01.Pt()); + registry.fill(HIST("os_mm_eTa_2"), v01.Eta()); + registry.fill(HIST("os_mm_invm_2"), v01.M()); + registry.fill(HIST("os_Ntr_mm_invm_2"), tracks.size(), v01.M()); + registry.fill(HIST("os_mm_pt_invm_2"), v01.Pt(), v01.M()); + registry.fill(HIST("sss_Ntr_mm_invm_2"), tracks.size(), v01.M()); + registry.fill(HIST("sss_mm_pt_invm_2"), v01.Pt(), v01.M()); + } else { + registry.fill(HIST("os_mm_pT_3"), v01.Pt()); + registry.fill(HIST("os_mm_eTa_3"), v01.Eta()); + registry.fill(HIST("os_mm_invm_3"), v01.M()); + registry.fill(HIST("os_Ntr_mm_invm_3"), tracks.size(), v01.M()); + registry.fill(HIST("os_mm_pt_invm_3"), v01.Pt(), v01.M()); + registry.fill(HIST("sss_Ntr_mm_invm_3"), tracks.size(), v01.M()); + registry.fill(HIST("sss_mm_pt_invm_3"), v01.Pt(), v01.M()); + } + } else if (t0.sign() == t1.sign()) { + registry.fill(HIST("ss_mm_pT"), v01.Pt()); + registry.fill(HIST("ss_mm_eTa"), v01.Eta()); + registry.fill(HIST("ss_mm_invm"), v01.M()); + if (gapSide == 0) { + registry.fill(HIST("ss_mm_pT_0"), v01.Pt()); + registry.fill(HIST("ss_mm_eTa_0"), v01.Eta()); + registry.fill(HIST("ss_mm_invm_0"), v01.M()); + registry.fill(HIST("ss_Ntr_mm_invm_0"), tracks.size(), v01.M()); + registry.fill(HIST("ss_mm_pt_invm_0"), v01.Pt(), v01.M()); + registry.fill(HIST("sss_Ntr_mm_invm_0"), tracks.size(), v01.M(), -1); + registry.fill(HIST("sss_mm_pt_invm_0"), v01.Pt(), v01.M(), -1); + } + if (gapSide == 1) { + registry.fill(HIST("ss_mm_pT_1"), v01.Pt()); + registry.fill(HIST("ss_mm_eTa_1"), v01.Eta()); + registry.fill(HIST("ss_mm_invm_1"), v01.M()); + registry.fill(HIST("ss_Ntr_mm_invm_1"), tracks.size(), v01.M()); + registry.fill(HIST("ss_mm_pt_invm_1"), v01.Pt(), v01.M()); + registry.fill(HIST("sss_Ntr_mm_invm_1"), tracks.size(), v01.M(), -1); + registry.fill(HIST("sss_mm_pt_invm_1"), v01.Pt(), v01.M(), -1); + } + if (gapSide == 2) { + registry.fill(HIST("ss_mm_pT_2"), v01.Pt()); + registry.fill(HIST("ss_mm_eTa_2"), v01.Eta()); + registry.fill(HIST("ss_mm_invm_2"), v01.M()); + registry.fill(HIST("ss_Ntr_mm_invm_2"), tracks.size(), v01.M()); + registry.fill(HIST("ss_mm_pt_invm_2"), v01.Pt(), v01.M()); + registry.fill(HIST("sss_Ntr_mm_invm_2"), tracks.size(), v01.M(), -1); + registry.fill(HIST("sss_mm_pt_invm_2"), v01.Pt(), v01.M(), -1); + } + if (gapSide == -1) { + registry.fill(HIST("ss_mm_pT_3"), v01.Pt()); + registry.fill(HIST("ss_mm_eTa_3"), v01.Eta()); + registry.fill(HIST("ss_mm_invm_3"), v01.M()); + registry.fill(HIST("ss_Ntr_mm_invm_3"), tracks.size(), v01.M()); + registry.fill(HIST("ss_mm_pt_invm_3"), v01.Pt(), v01.M()); + registry.fill(HIST("sss_Ntr_mm_invm_3"), tracks.size(), v01.M(), -1); + registry.fill(HIST("sss_mm_pt_invm_3"), v01.Pt(), v01.M(), -1); + } + } + } + if (selectionPIDElec(t0, use_tof, nsigmatpc_cut, nsigmatof_cut) && selectionPIDElec(t1, use_tof, nsigmatpc_cut, nsigmatof_cut)) { + // Apply pion hypothesis and create pairs + v0.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassElectron); + v1.SetXYZM(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassElectron); + v01 = v0 + v1; + // Opposite sign pairs + if (t0.sign() != t1.sign()) { + registry.fill(HIST("os_ee_pT"), v01.Pt()); + registry.fill(HIST("os_ee_eTa"), v01.Eta()); + registry.fill(HIST("os_ee_invm"), v01.M()); + if (gapSide == 0) { + registry.fill(HIST("os_ee_pT_0"), v01.Pt()); + registry.fill(HIST("os_ee_eTa_0"), v01.Eta()); + registry.fill(HIST("os_ee_invm_0"), v01.M()); + registry.fill(HIST("os_Ntr_ee_invm_0"), tracks.size(), v01.M()); + registry.fill(HIST("os_ee_pt_invm_0"), v01.Pt(), v01.M()); + registry.fill(HIST("sss_ee_pt_invm_0"), v01.Pt(), v01.M()); + registry.fill(HIST("sss_Ntr_ee_invm_0"), tracks.size(), v01.M()); + } else if (gapSide == 1) { + registry.fill(HIST("os_ee_pT_1"), v01.Pt()); + registry.fill(HIST("os_ee_eTa_1"), v01.Eta()); + registry.fill(HIST("os_ee_invm_1"), v01.M()); + registry.fill(HIST("os_Ntr_ee_invm_1"), tracks.size(), v01.M()); + registry.fill(HIST("os_ee_pt_invm_1"), v01.Pt(), v01.M()); + registry.fill(HIST("sss_Ntr_ee_invm_1"), tracks.size(), v01.M()); + registry.fill(HIST("sss_ee_pt_invm_1"), v01.Pt(), v01.M()); + } else if (gapSide == 2) { + registry.fill(HIST("os_ee_pT_2"), v01.Pt()); + registry.fill(HIST("os_ee_eTa_2"), v01.Eta()); + registry.fill(HIST("os_ee_invm_2"), v01.M()); + registry.fill(HIST("os_Ntr_ee_invm_2"), tracks.size(), v01.M()); + registry.fill(HIST("os_ee_pt_invm_2"), v01.Pt(), v01.M()); + registry.fill(HIST("sss_Ntr_ee_invm_2"), tracks.size(), v01.M()); + registry.fill(HIST("sss_ee_pt_invm_2"), v01.Pt(), v01.M()); + } else { + registry.fill(HIST("os_ee_pT_3"), v01.Pt()); + registry.fill(HIST("os_ee_eTa_3"), v01.Eta()); + registry.fill(HIST("os_ee_invm_3"), v01.M()); + registry.fill(HIST("os_Ntr_ee_invm_3"), tracks.size(), v01.M()); + registry.fill(HIST("os_ee_pt_invm_3"), v01.Pt(), v01.M()); + registry.fill(HIST("sss_Ntr_ee_invm_3"), tracks.size(), v01.M()); + registry.fill(HIST("sss_ee_pt_invm_3"), v01.Pt(), v01.M()); + } + } else if (t0.sign() == t1.sign()) { + registry.fill(HIST("ss_ee_pT"), v01.Pt()); + registry.fill(HIST("ss_ee_eTa"), v01.Eta()); + registry.fill(HIST("ss_ee_invm"), v01.M()); + if (gapSide == 0) { + registry.fill(HIST("ss_ee_pT_0"), v01.Pt()); + registry.fill(HIST("ss_ee_eTa_0"), v01.Eta()); + registry.fill(HIST("ss_ee_invm_0"), v01.M()); + registry.fill(HIST("ss_Ntr_ee_invm_0"), tracks.size(), v01.M()); + registry.fill(HIST("ss_ee_pt_invm_0"), v01.Pt(), v01.M()); + registry.fill(HIST("sss_Ntr_ee_invm_0"), tracks.size(), v01.M(), -1); + registry.fill(HIST("sss_ee_pt_invm_0"), v01.Pt(), v01.M(), -1); + } + if (gapSide == 1) { + registry.fill(HIST("ss_ee_pT_1"), v01.Pt()); + registry.fill(HIST("ss_ee_eTa_1"), v01.Eta()); + registry.fill(HIST("ss_ee_invm_1"), v01.M()); + registry.fill(HIST("ss_Ntr_ee_invm_1"), tracks.size(), v01.M()); + registry.fill(HIST("ss_ee_pt_invm_1"), v01.Pt(), v01.M()); + registry.fill(HIST("sss_Ntr_ee_invm_1"), tracks.size(), v01.M(), -1); + registry.fill(HIST("sss_ee_pt_invm_1"), v01.Pt(), v01.M(), -1); + } + if (gapSide == 2) { + registry.fill(HIST("ss_ee_pT_2"), v01.Pt()); + registry.fill(HIST("ss_ee_eTa_2"), v01.Eta()); + registry.fill(HIST("ss_ee_invm_2"), v01.M()); + registry.fill(HIST("ss_Ntr_ee_invm_2"), tracks.size(), v01.M()); + registry.fill(HIST("ss_ee_pt_invm_2"), v01.Pt(), v01.M()); + registry.fill(HIST("sss_Ntr_ee_invm_2"), tracks.size(), v01.M(), -1); + registry.fill(HIST("sss_ee_pt_invm_2"), v01.Pt(), v01.M(), -1); + } + if (gapSide == -1) { + registry.fill(HIST("ss_ee_pT_3"), v01.Pt()); + registry.fill(HIST("ss_ee_eTa_3"), v01.Eta()); + registry.fill(HIST("ss_ee_invm_3"), v01.M()); + registry.fill(HIST("ss_Ntr_ee_invm_3"), tracks.size(), v01.M()); + registry.fill(HIST("ss_ee_pt_invm_3"), v01.Pt(), v01.M()); + registry.fill(HIST("sss_Ntr_ee_invm_3"), tracks.size(), v01.M(), -1); + registry.fill(HIST("sss_ee_pt_invm_3"), v01.Pt(), v01.M(), -1); + } + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/sgPIDAnalyzer.cxx b/PWGUD/Tasks/sgPIDAnalyzer.cxx new file mode 100644 index 00000000000..e4015417971 --- /dev/null +++ b/PWGUD/Tasks/sgPIDAnalyzer.cxx @@ -0,0 +1,334 @@ +// 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. +// +// \Single Gap Event Analyzer +// \author Sasha Bylinkin, alexander.bylinkin@gmail.com +// \since April 2023 + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" + +#include "TVector3.h" +#include "TTree.h" +#include "TFile.h" +#include +#include +#include "Common/DataModel/PIDResponse.h" +#include "PWGUD/DataModel/SGTables.h" +#include "PWGUD/Core/UDHelpers.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct sgPIDAnalyzer { + HistogramRegistry histos{"Histos", {}}; + + ConfigurableAxis ptAxis{ + "ptAxis", + {200, 0.0, 10.0}, + "Pt binning"}; + + ConfigurableAxis sigmaAxis{"sigmaAxis", {1000, -20, 180}, "nSigma TPC binning"}; + ConfigurableAxis tofAxis{"tofAxis", {200, -10, 10}, "nSigma TOF binning"}; + Configurable eta_min{"eta_min", -0.9, "Track Pseudorapidity"}; + Configurable eta_max{"eta_max", 0.9, "Track Pseudorapidity"}; + + void init(InitContext&) + { + + const AxisSpec ptBins{ptAxis, "p_{T} axis"}; + const AxisSpec nSigmaBins{sigmaAxis, "pseudo rapidity axis"}; + const AxisSpec ntofBins{tofAxis, "pseudo rapidity axis"}; + histos.add("Events", "Selected Events", {HistType::kTH1F, {{3, -.5, 2.5}}}); + histos.add("TPC/pTPC_Pi", "Positive TPC Pi Tracks", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_Pi", "Negative TPC Pi Tracks", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_Ka", "Positive TPC Ka Tracks", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_Ka", "Negative TPC Ka Tracks", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_Pr", "Positive TPC Pr Tracks", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_Pr", "Negative TPC Pr Tracks", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_El", "Positive TPC El Tracks", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_El", "Negative TPC El Tracks", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_De", "Positive TPC De Tracks", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_De", "Negative TPC De Tracks", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_Mu", "Positive TPC Mu Tracks", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_Mu", "Negative TPC Mu Tracks", {HistType::kTH2F, {ptBins, nSigmaBins}}); + + histos.add("TPC/pTPC_Pi_Ka", "Positive TPC Pi vs Ka", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_Pi_Pr", "Positive TPC Pi vs Pr", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_Pi_El", "Positive TPC Pi vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_Pi_De", "Positive TPC Pi vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_Ka_Pi", "Positive TPC Ka vs Pi", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_Ka_Pr", "Positive TPC Ka vs Pr", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_Ka_El", "Positive TPC Ka vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_Ka_De", "Positive TPC Ka vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_Pr_Pi", "Positive TPC Pr vs Pi", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_Pr_Ka", "Positive TPC Pr vs Ka", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_Pr_El", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_Pr_De", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_El_Pi", "Positive TPC Pr vs Pi", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_El_Ka", "Positive TPC Pr vs Ka", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_El_Pr", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_El_De", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_De_Pi", "Positive TPC Pr vs Pi", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_De_Ka", "Positive TPC Pr vs Ka", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_De_Pr", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/pTPC_De_El", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + + histos.add("TPC/nTPC_Pi_Ka", "Positive TPC Pi vs Ka", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_Pi_Pr", "Positive TPC Pi vs Pr", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_Pi_El", "Positive TPC Pi vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_Pi_De", "Positive TPC Pi vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_Ka_Pi", "Positive TPC Ka vs Pi", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_Ka_Pr", "Positive TPC Ka vs Pr", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_Ka_El", "Positive TPC Ka vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_Ka_De", "Positive TPC Ka vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_Pr_Pi", "Positive TPC Pr vs Pi", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_Pr_Ka", "Positive TPC Pr vs Ka", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_Pr_El", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_Pr_De", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_El_Pi", "Positive TPC Pr vs Pi", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_El_Ka", "Positive TPC Pr vs Ka", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_El_Pr", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_El_De", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_De_Pi", "Positive TPC Pr vs Pi", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_De_Ka", "Positive TPC Pr vs Ka", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_De_Pr", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TPC/nTPC_De_El", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + + histos.add("TOF/pTOF_Pi_Ka", "Positive TPC Pi vs Ka", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_Pi_Pr", "Positive TPC Pi vs Pr", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_Pi_El", "Positive TPC Pi vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_Pi_De", "Positive TPC Pi vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_Ka_Pi", "Positive TPC Ka vs Pi", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_Ka_Pr", "Positive TPC Ka vs Pr", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_Ka_El", "Positive TPC Ka vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_Ka_De", "Positive TPC Ka vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_Pr_Pi", "Positive TPC Pr vs Pi", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_Pr_Ka", "Positive TPC Pr vs Ka", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_Pr_El", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_Pr_De", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_El_Pi", "Positive TPC Pr vs Pi", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_El_Ka", "Positive TPC Pr vs Ka", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_El_Pr", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_El_De", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_De_Pi", "Positive TPC Pr vs Pi", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_De_Ka", "Positive TPC Pr vs Ka", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_De_Pr", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/pTOF_De_El", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + + histos.add("TOF/nTOF_Pi_Ka", "Positive TPC Pi vs Ka", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_Pi_Pr", "Positive TPC Pi vs Pr", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_Pi_El", "Positive TPC Pi vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_Pi_De", "Positive TPC Pi vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_Ka_Pi", "Positive TPC Ka vs Pi", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_Ka_Pr", "Positive TPC Ka vs Pr", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_Ka_El", "Positive TPC Ka vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_Ka_De", "Positive TPC Ka vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_Pr_Pi", "Positive TPC Pr vs Pi", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_Pr_Ka", "Positive TPC Pr vs Ka", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_Pr_El", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_Pr_De", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_El_Pi", "Positive TPC Pr vs Pi", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_El_Ka", "Positive TPC Pr vs Ka", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_El_Pr", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_El_De", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_De_Pi", "Positive TPC Pr vs Pi", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_De_Ka", "Positive TPC Pr vs Ka", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_De_Pr", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + histos.add("TOF/nTOF_De_El", "Positive TPC Pr vs El", {HistType::kTH2F, {ptBins, nSigmaBins}}); + + histos.add("TOF/pPi", "Positive TPC Pi vs TOF Pi vs pt", {HistType::kTH3F, {ptBins, ntofBins, ntofBins}}); + histos.add("TOF/nPi", "Negative TPC Pi vs TOF Pi vs pt", {HistType::kTH3F, {ptBins, ntofBins, ntofBins}}); + histos.add("TOF/pKa", "Positive TPC Ka vs TOF Ka vs pt", {HistType::kTH3F, {ptBins, ntofBins, ntofBins}}); + histos.add("TOF/nKa", "Negative TPC Ka vs TOF Ka vs pt", {HistType::kTH3F, {ptBins, ntofBins, ntofBins}}); + histos.add("TOF/pPr", "Positive TPC Pr vs TOF Pr vs pt", {HistType::kTH3F, {ptBins, ntofBins, ntofBins}}); + histos.add("TOF/nPr", "Negative TPC Pr vs TOF Pr vs pt", {HistType::kTH3F, {ptBins, ntofBins, ntofBins}}); + histos.add("TOF/pEl", "Positive TPC El vs TOF El vs pt", {HistType::kTH3F, {ptBins, ntofBins, ntofBins}}); + histos.add("TOF/nEl", "Negative TPC El vs TOF El vs pt", {HistType::kTH3F, {ptBins, ntofBins, ntofBins}}); + histos.add("TOF/pDe", "Positive TPC De vs TOF Pi vs pt", {HistType::kTH3F, {ptBins, ntofBins, ntofBins}}); + histos.add("TOF/nDe", "Negative TPC De vs TOF Pi vs pt", {HistType::kTH3F, {ptBins, ntofBins, ntofBins}}); + histos.add("TOF/pMu", "Positive TPC Mu vs TOF El vs pt", {HistType::kTH3F, {ptBins, ntofBins, ntofBins}}); + histos.add("TOF/nMu", "Negative TPC Mu vs TOF El vs pt", {HistType::kTH3F, {ptBins, ntofBins, ntofBins}}); + } + using SGEvent = aod::SGEvents::iterator; + void process(SGEvent const& event, aod::SGTracks const& tracks) + { + histos.fill(HIST("Events"), event.gs()); + for (const auto& track : tracks) { + if (track.eta() < eta_min || track.eta() > eta_max) + continue; + bool isPositive = (track.sign() > 0); + if (track.tofpi() == -999) { + // Directly fill histograms without a local variable for histName + if (isPositive) { + histos.fill(HIST("TPC/pTPC_Pi"), track.pt(), track.tpcpi()); + histos.fill(HIST("TPC/pTPC_Ka"), track.pt(), track.tpcka()); + histos.fill(HIST("TPC/pTPC_Pr"), track.pt(), track.tpcpr()); + histos.fill(HIST("TPC/pTPC_El"), track.pt(), track.tpcel()); + histos.fill(HIST("TPC/pTPC_De"), track.pt(), track.tpcde()); + histos.fill(HIST("TPC/pTPC_Mu"), track.pt(), track.tpcmu()); + if (std::abs(track.tpcpi()) < 1) { + histos.fill(HIST("TPC/pTPC_Ka_Pi"), track.pt(), track.tpcka()); + histos.fill(HIST("TPC/pTPC_Pr_Pi"), track.pt(), track.tpcpr()); + histos.fill(HIST("TPC/pTPC_El_Pi"), track.pt(), track.tpcel()); + histos.fill(HIST("TPC/pTPC_De_Pi"), track.pt(), track.tpcde()); + } + if (std::abs(track.tpcka()) < 1) { + histos.fill(HIST("TPC/pTPC_Pi_Ka"), track.pt(), track.tpcpi()); + histos.fill(HIST("TPC/pTPC_Pr_Ka"), track.pt(), track.tpcpr()); + histos.fill(HIST("TPC/pTPC_El_Ka"), track.pt(), track.tpcel()); + histos.fill(HIST("TPC/pTPC_De_Ka"), track.pt(), track.tpcde()); + } + if (std::abs(track.tpcpr()) < 1) { + histos.fill(HIST("TPC/pTPC_Pi_Pr"), track.pt(), track.tpcpi()); + histos.fill(HIST("TPC/pTPC_Ka_Pr"), track.pt(), track.tpcka()); + histos.fill(HIST("TPC/pTPC_El_Pr"), track.pt(), track.tpcel()); + histos.fill(HIST("TPC/pTPC_De_Pr"), track.pt(), track.tpcde()); + } + if (std::abs(track.tpcel()) < 1) { + histos.fill(HIST("TPC/pTPC_Pi_El"), track.pt(), track.tpcpi()); + histos.fill(HIST("TPC/pTPC_Ka_El"), track.pt(), track.tpcka()); + histos.fill(HIST("TPC/pTPC_Pr_El"), track.pt(), track.tpcpr()); + histos.fill(HIST("TPC/pTPC_De_El"), track.pt(), track.tpcde()); + } + if (std::abs(track.tpcde()) < 1) { + histos.fill(HIST("TPC/pTPC_Pi_De"), track.pt(), track.tpcpi()); + histos.fill(HIST("TPC/pTPC_Ka_De"), track.pt(), track.tpcka()); + histos.fill(HIST("TPC/pTPC_Pr_De"), track.pt(), track.tpcpr()); + histos.fill(HIST("TPC/pTPC_El_De"), track.pt(), track.tpcel()); + } + } else { + histos.fill(HIST("TPC/nTPC_Pi"), track.pt(), track.tpcpi()); + histos.fill(HIST("TPC/nTPC_Ka"), track.pt(), track.tpcka()); + histos.fill(HIST("TPC/nTPC_Pr"), track.pt(), track.tpcpr()); + histos.fill(HIST("TPC/nTPC_El"), track.pt(), track.tpcel()); + histos.fill(HIST("TPC/nTPC_De"), track.pt(), track.tpcde()); + histos.fill(HIST("TPC/nTPC_Mu"), track.pt(), track.tpcmu()); + if (std::abs(track.tpcpi()) < 1) { + histos.fill(HIST("TPC/nTPC_Ka_Pi"), track.pt(), track.tpcka()); + histos.fill(HIST("TPC/nTPC_Pr_Pi"), track.pt(), track.tpcpr()); + histos.fill(HIST("TPC/nTPC_El_Pi"), track.pt(), track.tpcel()); + histos.fill(HIST("TPC/nTPC_De_Pi"), track.pt(), track.tpcde()); + } + if (std::abs(track.tpcka()) < 1) { + histos.fill(HIST("TPC/nTPC_Pi_Ka"), track.pt(), track.tpcpi()); + histos.fill(HIST("TPC/nTPC_Pr_Ka"), track.pt(), track.tpcpr()); + histos.fill(HIST("TPC/nTPC_El_Ka"), track.pt(), track.tpcel()); + histos.fill(HIST("TPC/nTPC_De_Ka"), track.pt(), track.tpcde()); + } + if (std::abs(track.tpcpr()) < 1) { + histos.fill(HIST("TPC/nTPC_Pi_Pr"), track.pt(), track.tpcpi()); + histos.fill(HIST("TPC/nTPC_Ka_Pr"), track.pt(), track.tpcka()); + histos.fill(HIST("TPC/nTPC_El_Pr"), track.pt(), track.tpcel()); + histos.fill(HIST("TPC/nTPC_De_Pr"), track.pt(), track.tpcde()); + } + if (std::abs(track.tpcel()) < 1) { + histos.fill(HIST("TPC/nTPC_Pi_El"), track.pt(), track.tpcpi()); + histos.fill(HIST("TPC/nTPC_Ka_El"), track.pt(), track.tpcka()); + histos.fill(HIST("TPC/nTPC_Pr_El"), track.pt(), track.tpcpr()); + histos.fill(HIST("TPC/nTPC_De_El"), track.pt(), track.tpcde()); + } + if (std::abs(track.tpcde()) < 1) { + histos.fill(HIST("TPC/nTPC_Pi_De"), track.pt(), track.tpcpi()); + histos.fill(HIST("TPC/nTPC_Ka_De"), track.pt(), track.tpcka()); + histos.fill(HIST("TPC/nTPC_Pr_De"), track.pt(), track.tpcpr()); + histos.fill(HIST("TPC/nTPC_El_De"), track.pt(), track.tpcel()); + } + } + } else { + if (isPositive) { + histos.fill(HIST("TOF/pPi"), track.pt(), track.tpcpi(), track.tofpi()); + histos.fill(HIST("TOF/pKa"), track.pt(), track.tpcka(), track.tofka()); + histos.fill(HIST("TOF/pPr"), track.pt(), track.tpcpr(), track.tofpr()); + histos.fill(HIST("TOF/pEl"), track.pt(), track.tpcel(), track.tofel()); + histos.fill(HIST("TOF/pDe"), track.pt(), track.tpcpi(), track.tofde()); + histos.fill(HIST("TOF/pMu"), track.pt(), track.tpcel(), track.tofmu()); + if (std::abs(track.tofpi()) < 1) { + histos.fill(HIST("TOF/pTOF_Ka_Pi"), track.pt(), track.tofka()); + histos.fill(HIST("TOF/pTOF_Pr_Pi"), track.pt(), track.tofpr()); + histos.fill(HIST("TOF/pTOF_El_Pi"), track.pt(), track.tofel()); + histos.fill(HIST("TOF/pTOF_De_Pi"), track.pt(), track.tofde()); + } + if (std::abs(track.tofka()) < 1) { + histos.fill(HIST("TOF/pTOF_Pi_Ka"), track.pt(), track.tofpi()); + histos.fill(HIST("TOF/pTOF_Pr_Ka"), track.pt(), track.tofpr()); + histos.fill(HIST("TOF/pTOF_El_Ka"), track.pt(), track.tofel()); + histos.fill(HIST("TOF/pTOF_De_Ka"), track.pt(), track.tofde()); + } + if (std::abs(track.tofpr()) < 1) { + histos.fill(HIST("TOF/pTOF_Pi_Pr"), track.pt(), track.tofpi()); + histos.fill(HIST("TOF/pTOF_Ka_Pr"), track.pt(), track.tofka()); + histos.fill(HIST("TOF/pTOF_El_Pr"), track.pt(), track.tofel()); + histos.fill(HIST("TOF/pTOF_De_Pr"), track.pt(), track.tofde()); + } + if (std::abs(track.tofel()) < 1) { + histos.fill(HIST("TOF/pTOF_Pi_El"), track.pt(), track.tofpi()); + histos.fill(HIST("TOF/pTOF_Ka_El"), track.pt(), track.tofka()); + histos.fill(HIST("TOF/pTOF_Pr_El"), track.pt(), track.tofpr()); + histos.fill(HIST("TOF/pTOF_De_El"), track.pt(), track.tofde()); + } + if (std::abs(track.tofde()) < 1) { + histos.fill(HIST("TOF/pTOF_Pi_De"), track.pt(), track.tofpi()); + histos.fill(HIST("TOF/pTOF_Ka_De"), track.pt(), track.tofka()); + histos.fill(HIST("TOF/pTOF_Pr_De"), track.pt(), track.tofpr()); + histos.fill(HIST("TOF/pTOF_El_De"), track.pt(), track.tofel()); + } + } else { + histos.fill(HIST("TOF/nPi"), track.pt(), track.tpcpi(), track.tofpi()); + histos.fill(HIST("TOF/nKa"), track.pt(), track.tpcka(), track.tofka()); + histos.fill(HIST("TOF/nPr"), track.pt(), track.tpcpr(), track.tofpr()); + histos.fill(HIST("TOF/nEl"), track.pt(), track.tpcel(), track.tofel()); + histos.fill(HIST("TOF/nDe"), track.pt(), track.tpcpi(), track.tofde()); + histos.fill(HIST("TOF/nMu"), track.pt(), track.tpcel(), track.tofmu()); + if (std::abs(track.tofpi()) < 1) { + histos.fill(HIST("TOF/nTOF_Ka_Pi"), track.pt(), track.tofka()); + histos.fill(HIST("TOF/nTOF_Pr_Pi"), track.pt(), track.tofpr()); + histos.fill(HIST("TOF/nTOF_El_Pi"), track.pt(), track.tofel()); + histos.fill(HIST("TOF/nTOF_De_Pi"), track.pt(), track.tofde()); + } + if (std::abs(track.tofka()) < 1) { + histos.fill(HIST("TOF/nTOF_Pi_Ka"), track.pt(), track.tofpi()); + histos.fill(HIST("TOF/nTOF_Pr_Ka"), track.pt(), track.tofpr()); + histos.fill(HIST("TOF/nTOF_El_Ka"), track.pt(), track.tofel()); + histos.fill(HIST("TOF/nTOF_De_Ka"), track.pt(), track.tofde()); + } + if (std::abs(track.tofpr()) < 1) { + histos.fill(HIST("TOF/nTOF_Pi_Pr"), track.pt(), track.tofpi()); + histos.fill(HIST("TOF/nTOF_Ka_Pr"), track.pt(), track.tofka()); + histos.fill(HIST("TOF/nTOF_El_Pr"), track.pt(), track.tofel()); + histos.fill(HIST("TOF/nTOF_De_Pr"), track.pt(), track.tofde()); + } + if (std::abs(track.tofel()) < 1) { + histos.fill(HIST("TOF/nTOF_Pi_El"), track.pt(), track.tofpi()); + histos.fill(HIST("TOF/nTOF_Ka_El"), track.pt(), track.tofka()); + histos.fill(HIST("TOF/nTOF_Pr_El"), track.pt(), track.tofpr()); + histos.fill(HIST("TOF/nTOF_De_El"), track.pt(), track.tofde()); + } + if (std::abs(track.tofde()) < 1) { + histos.fill(HIST("TOF/nTOF_Pi_De"), track.pt(), track.tofpi()); + histos.fill(HIST("TOF/nTOF_Ka_De"), track.pt(), track.tofka()); + histos.fill(HIST("TOF/nTOF_Pr_De"), track.pt(), track.tofpr()); + histos.fill(HIST("TOF/nTOF_El_De"), track.pt(), track.tofel()); + } + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"sgpidanalyzer"})}; +} diff --git a/PWGUD/Tasks/sgPIDSpectra.cxx b/PWGUD/Tasks/sgPIDSpectra.cxx new file mode 100644 index 00000000000..7ecea94c66d --- /dev/null +++ b/PWGUD/Tasks/sgPIDSpectra.cxx @@ -0,0 +1,359 @@ +// 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. +// +// \Single Gap Event Analyzer +// \author Sasha Bylinkin, alexander.bylinkin@gmail.com +// \since April 2023 + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" + +#include "TVector3.h" +#include "TTree.h" +#include "TFile.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/UDHelpers.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct SGPIDSpectra { + SGSelector sgSelector; + ConfigurableAxis ptAxis{"ptAxis", {1000, 0.0, 20.0}, "p_{T}"}; + ConfigurableAxis sigmaAxis{"sigmaAxis", {2000, -20.0, 180.0}, "#sigma"}; + + // configurables + Configurable FV0_cut{"FV0", 50., "FV0A threshold"}; + Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; + Configurable FT0A_cut{"FT0A", 100., "FT0A threshold"}; + Configurable FT0C_cut{"FT0C", 50., "FT0C threshold"}; + Configurable FDDA_cut{"FDDA", 10000., "FDDA threshold"}; + Configurable FDDC_cut{"FDDC", 10000., "FDDC threshold"}; + // Track Selections + Configurable PV_cut{"PV_cut", 1.0, "Use Only PV tracks"}; + Configurable dcaZ_cut{"dcaZ_cut", 2.0, "dcaZ cut"}; + Configurable dcaXY_cut{"dcaXY_cut", 0.0, "dcaXY cut (0 for Pt-function)"}; + Configurable tpcChi2_cut{"tpcChi2_cut", 4, "Max tpcChi2NCl"}; + Configurable tpcNClsFindable_cut{"tpcNClsFindable_cut", 70, "Min tpcNClsFindable"}; + Configurable itsChi2_cut{"itsChi2_cut", 36, "Max itsChi2NCl"}; + Configurable eta_cut{"eta_cut", 0.9, "Track Pseudorapidity"}; + Configurable pt_cut{"pt_cut", 0.1, "Track Pt"}; + // initialize histogram registry + HistogramRegistry registry{ + "registry", + {}}; + + void init(InitContext&) + { + const AxisSpec axispt{ptAxis, "p_{T}"}; + const AxisSpec axistpc{sigmaAxis, "N_{#sigma}^{TPC}"}; + const AxisSpec axistof{sigmaAxis, "N_{#sigma}^{TOF}"}; + // Collision histograms + registry.add("collisions/GapSide", "Gap Side: A, C, A+C", {HistType::kTH1F, {{3, -0.5, 2.5}}}); + registry.add("collisions/TrueGapSide", "Gap Side: A, C, A+C", {HistType::kTH1F, {{4, -1.5, 2.5}}}); + registry.add("ttracks/pPion_Pt_TPC_El", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pPion_Pt_TPC_Ka", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pPion_Pt_TPC_Pr", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pKaon_Pt_TPC_El", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pKaon_Pt_TPC_Pi", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pKaon_Pt_TPC_Pr", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pProton_Pt_TPC_El", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pProton_Pt_TPC_Ka", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pProton_Pt_TPC_Pi", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nPion_Pt_TPC_El", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nPion_Pt_TPC_Ka", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nPion_Pt_TPC_Pr", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nKaon_Pt_TPC_El", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nKaon_Pt_TPC_Pi", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nKaon_Pt_TPC_Pr", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nProton_Pt_TPC_El", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nProton_Pt_TPC_Ka", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nProton_Pt_TPC_Pi", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pPion_Pt_TPC_p_0", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nPion_Pt_TPC_p_0", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pPion_Pt_TPC_n_0", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nPion_Pt_TPC_n_0", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pPion_Pt_TPC_p_1", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nPion_Pt_TPC_p_1", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pPion_Pt_TPC_n_1", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nPion_Pt_TPC_n_1", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pPion_Pt_TPC_p_2", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nPion_Pt_TPC_p_2", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pPion_Pt_TPC_n_2", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nPion_Pt_TPC_n_2", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pPion_Pt_TPC_p_3", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nPion_Pt_TPC_p_3", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pPion_Pt_TPC_n_3", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nPion_Pt_TPC_n_3", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pKaon_Pt_TPC_p_0", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nKaon_Pt_TPC_p_0", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pKaon_Pt_TPC_n_0", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nKaon_Pt_TPC_n_0", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pKaon_Pt_TPC_p_1", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nKaon_Pt_TPC_p_1", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pKaon_Pt_TPC_n_1", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nKaon_Pt_TPC_n_1", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pKaon_Pt_TPC_p_2", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nKaon_Pt_TPC_p_2", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pKaon_Pt_TPC_n_2", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nKaon_Pt_TPC_n_2", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pKaon_Pt_TPC_p_3", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nKaon_Pt_TPC_p_3", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pKaon_Pt_TPC_n_3", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nKaon_Pt_TPC_n_3", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pProton_Pt_TPC_p_0", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nProton_Pt_TPC_p_0", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pProton_Pt_TPC_n_0", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nProton_Pt_TPC_n_0", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pProton_Pt_TPC_p_1", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nProton_Pt_TPC_p_1", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pProton_Pt_TPC_n_1", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nProton_Pt_TPC_n_1", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pProton_Pt_TPC_p_2", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nProton_Pt_TPC_p_2", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pProton_Pt_TPC_n_2", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nProton_Pt_TPC_n_2", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pProton_Pt_TPC_p_3", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nProton_Pt_TPC_p_3", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/pProton_Pt_TPC_n_3", "", {HistType::kTH2F, {axispt, axistpc}}); + registry.add("ttracks/nProton_Pt_TPC_n_3", "", {HistType::kTH2F, {axispt, axistpc}}); + } + + // define data types + using UDCollisionsFull = soa::Join; // UDCollisions + using UDCollisionFull = UDCollisionsFull::iterator; + using UDTracksFull = soa::Join; + + void process(UDCollisionFull const& coll, UDTracksFull const& tracks) + { + // fill collision histograms + registry.get(HIST("collisions/GapSide"))->Fill(coll.gapSide(), 1.); + // int truegapSide = sgSelector.trueGap(dgcand, FV0_cut, ZDC_cut); + float FIT_cut[5] = {FV0_cut, FT0A_cut, FT0C_cut, FDDA_cut, FDDC_cut}; + int truegapSide = sgSelector.trueGap(coll, FIT_cut[0], FIT_cut[1], FIT_cut[2], ZDC_cut); + registry.get(HIST("collisions/TrueGapSide"))->Fill(truegapSide, 1.); + // select PV contributors + std::vector parameters = {PV_cut, dcaZ_cut, dcaXY_cut, tpcChi2_cut, tpcNClsFindable_cut, itsChi2_cut, eta_cut, pt_cut}; + // check rho0 signals + for (auto t : tracks) { + if (trackselector(t, parameters) && t.hasTPC()) { + if (truegapSide == 0) { + if (t.sign() > 0) { + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/pPion_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaKa()) < 1.) + registry.fill(HIST("ttracks/pPion_Pt_TPC_Ka"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaPr()) < 1.) + registry.fill(HIST("ttracks/pPion_Pt_TPC_Pr"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/pKaon_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaPi()) < 1.) + registry.fill(HIST("ttracks/pKaon_Pt_TPC_Pi"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaPr()) < 1.) + registry.fill(HIST("ttracks/pKaon_Pt_TPC_Pr"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/pProton_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (std::abs(t.tpcNSigmaKa()) < 1.) + registry.fill(HIST("ttracks/pProton_Pt_TPC_Ka"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (std::abs(t.tpcNSigmaPi()) < 1.) + registry.fill(HIST("ttracks/pProton_Pt_TPC_Pi"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (t.pz() > 0) { + registry.fill(HIST("ttracks/pPion_Pt_TPC_p_0"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + registry.fill(HIST("ttracks/pKaon_Pt_TPC_p_0"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + registry.fill(HIST("ttracks/pProton_Pt_TPC_p_0"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + } else { + registry.fill(HIST("ttracks/pPion_Pt_TPC_n_0"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + registry.fill(HIST("ttracks/pKaon_Pt_TPC_n_0"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + registry.fill(HIST("ttracks/pProton_Pt_TPC_n_0"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + } + } else { + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/nPion_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaKa()) < 1.) + registry.fill(HIST("ttracks/nPion_Pt_TPC_Ka"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaPr()) < 1.) + registry.fill(HIST("ttracks/nPion_Pt_TPC_Pr"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/nKaon_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaPi()) < 1.) + registry.fill(HIST("ttracks/nKaon_Pt_TPC_Pi"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaPr()) < 1.) + registry.fill(HIST("ttracks/nKaon_Pt_TPC_Pr"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/nProton_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (std::abs(t.tpcNSigmaKa()) < 1.) + registry.fill(HIST("ttracks/nProton_Pt_TPC_Ka"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (std::abs(t.tpcNSigmaPi()) < 1.) + registry.fill(HIST("ttracks/nProton_Pt_TPC_Pi"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (t.pz() > 0) { + registry.fill(HIST("ttracks/nPion_Pt_TPC_p_0"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + registry.fill(HIST("ttracks/nKaon_Pt_TPC_p_0"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + registry.fill(HIST("ttracks/nProton_Pt_TPC_p_0"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + } else { + registry.fill(HIST("ttracks/nPion_Pt_TPC_n_0"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + registry.fill(HIST("ttracks/nKaon_Pt_TPC_n_0"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + registry.fill(HIST("ttracks/nProton_Pt_TPC_n_0"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + } + } + } else if (truegapSide == 1) { + if (t.sign() > 0) { + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/pPion_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaKa()) < 1.) + registry.fill(HIST("ttracks/pPion_Pt_TPC_Ka"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaPr()) < 1.) + registry.fill(HIST("ttracks/pPion_Pt_TPC_Pr"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/pKaon_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaPi()) < 1.) + registry.fill(HIST("ttracks/pKaon_Pt_TPC_Pi"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaPr()) < 1.) + registry.fill(HIST("ttracks/pKaon_Pt_TPC_Pr"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/pProton_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (std::abs(t.tpcNSigmaKa()) < 1.) + registry.fill(HIST("ttracks/pProton_Pt_TPC_Ka"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (std::abs(t.tpcNSigmaPi()) < 1.) + registry.fill(HIST("ttracks/pProton_Pt_TPC_Pi"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (t.pz() > 0) { + registry.fill(HIST("ttracks/pPion_Pt_TPC_p_1"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + registry.fill(HIST("ttracks/pKaon_Pt_TPC_p_1"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + registry.fill(HIST("ttracks/pProton_Pt_TPC_p_1"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + } else { + registry.fill(HIST("ttracks/pPion_Pt_TPC_n_1"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + registry.fill(HIST("ttracks/pKaon_Pt_TPC_n_1"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + registry.fill(HIST("ttracks/pProton_Pt_TPC_n_1"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + } + } else { + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/nPion_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaKa()) < 1.) + registry.fill(HIST("ttracks/nPion_Pt_TPC_Ka"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaPr()) < 1.) + registry.fill(HIST("ttracks/nPion_Pt_TPC_Pr"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/nKaon_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaPi()) < 1.) + registry.fill(HIST("ttracks/nKaon_Pt_TPC_Pi"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaPr()) < 1.) + registry.fill(HIST("ttracks/nKaon_Pt_TPC_Pr"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/nProton_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (std::abs(t.tpcNSigmaKa()) < 1.) + registry.fill(HIST("ttracks/nProton_Pt_TPC_Ka"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (std::abs(t.tpcNSigmaPi()) < 1.) + registry.fill(HIST("ttracks/nProton_Pt_TPC_Pi"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (t.pz() > 0) { + registry.fill(HIST("ttracks/nPion_Pt_TPC_p_1"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + registry.fill(HIST("ttracks/nKaon_Pt_TPC_p_1"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + registry.fill(HIST("ttracks/nProton_Pt_TPC_p_1"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + } else { + registry.fill(HIST("ttracks/nPion_Pt_TPC_n_1"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + registry.fill(HIST("ttracks/nKaon_Pt_TPC_n_1"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + registry.fill(HIST("ttracks/nProton_Pt_TPC_n_1"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + } + } + } else if (truegapSide == 2) { + if (t.sign() > 0) { + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/pPion_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaKa()) < 1.) + registry.fill(HIST("ttracks/pPion_Pt_TPC_Ka"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaPr()) < 1.) + registry.fill(HIST("ttracks/pPion_Pt_TPC_Pr"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/pKaon_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaPi()) < 1.) + registry.fill(HIST("ttracks/pKaon_Pt_TPC_Pi"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaPr()) < 1.) + registry.fill(HIST("ttracks/pKaon_Pt_TPC_Pr"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/pProton_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (std::abs(t.tpcNSigmaKa()) < 1.) + registry.fill(HIST("ttracks/pProton_Pt_TPC_Ka"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (std::abs(t.tpcNSigmaPi()) < 1.) + registry.fill(HIST("ttracks/pProton_Pt_TPC_Pi"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (t.pz() > 0) { + registry.fill(HIST("ttracks/pPion_Pt_TPC_p_2"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + registry.fill(HIST("ttracks/pKaon_Pt_TPC_p_2"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + registry.fill(HIST("ttracks/pProton_Pt_TPC_p_2"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + } else { + registry.fill(HIST("ttracks/pPion_Pt_TPC_n_2"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + registry.fill(HIST("ttracks/pKaon_Pt_TPC_n_2"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + registry.fill(HIST("ttracks/pProton_Pt_TPC_n_2"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + } + } else { + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/nPion_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaKa()) < 1.) + registry.fill(HIST("ttracks/nPion_Pt_TPC_Ka"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaPr()) < 1.) + registry.fill(HIST("ttracks/nPion_Pt_TPC_Pr"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/nKaon_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaPi()) < 1.) + registry.fill(HIST("ttracks/nKaon_Pt_TPC_Pi"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaPr()) < 1.) + registry.fill(HIST("ttracks/nKaon_Pt_TPC_Pr"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + if (std::abs(t.tpcNSigmaEl()) < 1.) + registry.fill(HIST("ttracks/nProton_Pt_TPC_El"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (std::abs(t.tpcNSigmaKa()) < 1.) + registry.fill(HIST("ttracks/nProton_Pt_TPC_Ka"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (std::abs(t.tpcNSigmaPi()) < 1.) + registry.fill(HIST("ttracks/nProton_Pt_TPC_Pi"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + if (t.pz() > 0) { + registry.fill(HIST("ttracks/nPion_Pt_TPC_p_2"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + registry.fill(HIST("ttracks/nKaon_Pt_TPC_p_2"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + registry.fill(HIST("ttracks/nProton_Pt_TPC_p_2"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + } else { + registry.fill(HIST("ttracks/nPion_Pt_TPC_n_2"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + registry.fill(HIST("ttracks/nKaon_Pt_TPC_n_2"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + registry.fill(HIST("ttracks/nProton_Pt_TPC_n_2"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + } + } + } else { + if (t.sign() > 0) { + if (t.pz() > 0) { + registry.fill(HIST("ttracks/pPion_Pt_TPC_p_3"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + registry.fill(HIST("ttracks/pKaon_Pt_TPC_p_3"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + registry.fill(HIST("ttracks/pProton_Pt_TPC_p_3"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + } else { + registry.fill(HIST("ttracks/pPion_Pt_TPC_n_3"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + registry.fill(HIST("ttracks/pKaon_Pt_TPC_n_3"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + registry.fill(HIST("ttracks/pProton_Pt_TPC_n_3"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + } + } else { + if (t.pz() > 0) { + registry.fill(HIST("ttracks/nPion_Pt_TPC_p_3"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + registry.fill(HIST("ttracks/nKaon_Pt_TPC_p_3"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + registry.fill(HIST("ttracks/nProton_Pt_TPC_p_3"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + } else { + registry.fill(HIST("ttracks/nPion_Pt_TPC_n_3"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPi()); + registry.fill(HIST("ttracks/nKaon_Pt_TPC_n_3"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaKa()); + registry.fill(HIST("ttracks/nProton_Pt_TPC_n_3"), TMath::Abs(t.px() * t.px() + t.py() * t.py()), t.tpcNSigmaPr()); + } + } + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"sgpidspectra"}), + }; +} diff --git a/PWGUD/Tasks/sgPIDSpectraTable.cxx b/PWGUD/Tasks/sgPIDSpectraTable.cxx new file mode 100644 index 00000000000..9a370403a6b --- /dev/null +++ b/PWGUD/Tasks/sgPIDSpectraTable.cxx @@ -0,0 +1,138 @@ +// 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. +// +// \Single Gap Event Analyzer +// \author Sasha Bylinkin, alexander.bylinkin@gmail.com +// \since April 2023 +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" + +#include "TVector3.h" +#include "TTree.h" +#include "TFile.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/DataModel/SGTables.h" +#include "PWGUD/Core/UDHelpers.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct SGPIDSpectraTable { + Produces SGevents; + Produces SGtracks; + SGSelector sgSelector; + + // configurables + Configurable FV0_cut{"FV0", 50., "FV0A threshold"}; + Configurable ZDC_cut{"ZDC", .1, "ZDC threshold"}; + Configurable FT0A_cut{"FT0A", 100., "FT0A threshold"}; + Configurable FT0C_cut{"FT0C", 50., "FT0C threshold"}; + Configurable FDDA_cut{"FDDA", 10000., "FDDA threshold"}; + Configurable FDDC_cut{"FDDC", 10000., "FDDC threshold"}; + Configurable GS_cut{"GS", 0., "Gap-side A=0, C=1, AC = 2, No Gap = -1, All events = 3"}; + // Track Selections + Configurable PV_cut{"PV_cut", 1.0, "Use Only PV tracks"}; + Configurable dcaZ_cut{"dcaZ_cut", 2.0, "dcaZ cut"}; + Configurable dcaXY_cut{"dcaXY_cut", 0.0, "dcaXY cut (0 for Pt-function)"}; + Configurable tpcChi2_cut{"tpcChi2_cut", 4, "Max tpcChi2NCl"}; + Configurable tpcNClsFindable_cut{"tpcNClsFindable_cut", 70, "Min tpcNClsFindable"}; + Configurable itsChi2_cut{"itsChi2_cut", 36, "Max itsChi2NCl"}; + Configurable eta_cut{"eta_cut", 0.9, "Track Pseudorapidity"}; + Configurable pt_cut{"pt_cut", 0.1, "Track Pt"}; + Configurable occ_cut{"occ_cut", 200, "Maximum Occupancy"}; + Configurable occ_bit1_cut{"occ_bit1_cut", 0, "Check NoCollInTimeRangeStandard"}; + Configurable occ_bit2_cut{"occ_bit2_cut", 0, "Check NoCollInRofStandard"}; + Configurable occ_bit3_cut{"occ_bit3_cut", 0, "Check NoHighMultCollInPrevRof"}; + Configurable ir_cut{"ir_cut", 100, "Maximum IR"}; + // initialize histogram registry + HistogramRegistry registry{ + "registry", + {}}; + + void init(InitContext&) + { + // Collision histograms + } + + // define data types + using UDCollisionsFull = soa::Join; // UDCollisions + using UDCollisionFull = UDCollisionsFull::iterator; + using UDTracksFull = soa::Join; + + void process(UDCollisionFull const& coll, UDTracksFull const& tracks) + { + float FIT_cut[5] = {FV0_cut, FT0A_cut, FT0C_cut, FDDA_cut, FDDC_cut}; + int truegapSide = sgSelector.trueGap(coll, FIT_cut[0], FIT_cut[1], FIT_cut[2], ZDC_cut); + if (GS_cut != 3) { + if (truegapSide != GS_cut) + return; + } + // fill collision histograms + // check occupancies: + if (occ_bit1_cut && !coll.trs()) + return; + if (occ_bit2_cut && !coll.trofs()) + return; + if (occ_bit3_cut && !coll.hmpr()) + return; + if (coll.occupancyInTime() > occ_cut) + return; + if (coll.hadronicRate() > ir_cut) + return; + // int truegapSide = sgSelector.trueGap(dgcand, FV0_cut, ZDC_cut); + // select PV contributors + std::vector parameters = {PV_cut, dcaZ_cut, dcaXY_cut, tpcChi2_cut, tpcNClsFindable_cut, itsChi2_cut, eta_cut, pt_cut}; + // check rho0 signals + float tpcpi, tpcka, tpcel, tpcpr, tofpi, tofka, tofpr, tofel; + float tpcde, tofde, tpcmu, tofmu; + TVector3 a; + int goodtracks = 0; + for (auto t : tracks) { + if (trackselector(t, parameters)) { + goodtracks++; + } + } + if (!goodtracks) + return; + SGevents(coll.runNumber(), coll.flags(), truegapSide, coll.energyCommonZNA(), coll.energyCommonZNC(), goodtracks, coll.occupancyInTime(), coll.hadronicRate()); + // SGevents(coll.runNumber(), coll.flags()); + for (auto t : tracks) { + if (trackselector(t, parameters)) { + a.SetXYZ(t.px(), t.py(), t.pz()); + tpcpi = t.hasTPC() ? t.tpcNSigmaPi() : -999; + tpcmu = t.hasTPC() ? t.tpcNSigmaMu() : -999; + tpcka = t.hasTPC() ? t.tpcNSigmaKa() : -999; + tpcpr = t.hasTPC() ? t.tpcNSigmaPr() : -999; + tpcel = t.hasTPC() ? t.tpcNSigmaEl() : -999; + tofpi = t.hasTOF() ? t.tofNSigmaPi() : -999; + tofmu = t.hasTOF() ? t.tofNSigmaMu() : -999; + tofka = t.hasTOF() ? t.tofNSigmaKa() : -999; + tofpr = t.hasTOF() ? t.tofNSigmaPr() : -999; + tofel = t.hasTOF() ? t.tofNSigmaEl() : -999; + tpcde = t.hasTPC() ? t.tpcNSigmaDe() : -999; + tofde = t.hasTOF() ? t.tofNSigmaDe() : -999; + SGtracks(SGevents.lastIndex(), a.Pt(), a.Eta(), a.Phi(), t.sign(), tpcpi, tpcka, tpcpr, tpcel, tofpi, tofka, tofpr, tofel, tpcmu, tofmu, tpcde, tofde); + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"sgpidspectratable"}), + }; +} diff --git a/PWGUD/Tasks/sgSixPiAnalyzer.cxx b/PWGUD/Tasks/sgSixPiAnalyzer.cxx new file mode 100644 index 00000000000..215c5d236a1 --- /dev/null +++ b/PWGUD/Tasks/sgSixPiAnalyzer.cxx @@ -0,0 +1,189 @@ +// 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. +// +// \Single Gap Event Analyzer +// \author Sasha Bylinkin, alexander.bylinkin@gmail.com +// \since April 2023 + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "iostream" +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" +#include "Common/DataModel/PIDResponse.h" +#include "Framework/ASoA.h" +#include "Framework/DataTypes.h" +#include "MathUtils/Utils.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include "TLorentzVector.h" +using namespace std; +using namespace o2; +using namespace o2::aod; +// using namespace o2::aod::track::v001; +using namespace o2::framework; +using namespace o2::framework::expressions; +struct SGSixPiAnalyzer { + SGSelector sgSelector; + Service pdg; + // Adjusted Gap thresholds + Configurable FV0_cut{"FV0", 50., "FV0A threshold"}; + Configurable FT0A_cut{"FT0A", 150., "FT0A threshold"}; + Configurable FT0C_cut{"FT0C", 50., "FT0C threshold"}; + Configurable FDDA_cut{"FDDA", 10000., "FDDA threshold"}; + Configurable FDDC_cut{"FDDC", 10000., "FDDC threshold"}; + Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; + // Track Selections + Configurable PV_cut{"PV_cut", 1.0, "Use Only PV tracks"}; + Configurable dcaZ_cut{"dcaZ_cut", 2.0, "dcaZ cut"}; + Configurable dcaXY_cut{"dcaXY_cut", 0.0, "dcaXY cut (0 for Pt-function)"}; + Configurable tpcChi2_cut{"tpcChi2_cut", 4, "Max tpcChi2NCl"}; + Configurable tpcNClsFindable_cut{"tpcNClsFindable_cut", 70, "Min tpcNClsFindable"}; + Configurable itsChi2_cut{"itsChi2_cut", 36, "Max itsChi2NCl"}; + Configurable eta_cut{"eta_cut", 0.9, "Track Pseudorapidity"}; + Configurable pt_cut{"pt_cut", 0.1, "Track Pt"}; + HistogramRegistry registry{ + "registry", + { + + {"GapSide", "Gap Side; Entries", {HistType::kTH1F, {{4, -1.5, 2.5}}}}, + {"TrueGapSide", "Gap Side; Entries", {HistType::kTH1F, {{4, -1.5, 2.5}}}}, + {"ITSNCls", "ITS Clusters", {HistType::kTH1F, {{10, -.5, 9.5}}}}, + {"os_6Pi_pT", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"os_6Pi_eTa", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + {"os_6Pi_invm", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"ss_6Pi_pT", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"ss_6Pi_eTa", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + {"ss_6Pi_invm", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"os_6Pi_pT_1", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"os_6Pi_eTa_1", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + {"os_6Pi_invm_1", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"ss_6Pi_pT_1", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"ss_6Pi_eTa_1", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + {"ss_6Pi_invm_1", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"os_6Pi_pT_0", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"os_6Pi_eTa_0", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + {"os_6Pi_invm_0", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"ss_6Pi_pT_0", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"ss_6Pi_eTa_0", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + {"ss_6Pi_invm_0", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"os_6Pi_pT_2", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"os_6Pi_eTa_2", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + {"os_6Pi_invm_2", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"ss_6Pi_pT_2", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"ss_6Pi_eTa_2", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + {"ss_6Pi_invm_2", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + }}; + using udtracks = soa::Join; + using udtracksfull = soa::Join; + using UDCollisionsFull = soa::Join; // + using UDCollisionFull = UDCollisionsFull::iterator; + + void process(UDCollisionFull const& collision, udtracksfull const& tracks) + { + const float mpion = pdg->Mass(211); + TLorentzVector a; + int gapSide = collision.gapSide(); + if (gapSide < 0 || gapSide > 2) + return; + // Single gap either side + TLorentzVector v01; + // int truegapSide = sgSelector.trueGap(collision); + // int truegapSide = sgSelector.trueGap(collision, FV0_cut, ZDC_cut); + float FIT_cut[5] = {FV0_cut, FT0A_cut, FT0C_cut, FDDA_cut, FDDC_cut}; + std::vector parameters = {PV_cut, dcaZ_cut, dcaXY_cut, tpcChi2_cut, tpcNClsFindable_cut, itsChi2_cut, eta_cut, pt_cut}; + // int truegapSide = sgSelector.trueGap(collision, *FIT_cut, ZDC_cut); + int truegapSide = sgSelector.trueGap(collision, FIT_cut[0], FIT_cut[1], FIT_cut[2], ZDC_cut); + registry.fill(HIST("GapSide"), gapSide); + registry.fill(HIST("TrueGapSide"), truegapSide); + gapSide = truegapSide; + std::vector goodTracks; + float sign = 0; + for (auto t : tracks) { + int itsNCls = t.itsNCls(); + // if (itsNCls) { + registry.fill(HIST("ITSNCls"), itsNCls); + //} + TLorentzVector a; + a.SetXYZM(t.px(), t.py(), t.pz(), mpion); + if (trackselector(t, parameters)) { + sign += t.sign(); + goodTracks.push_back(a); + } + } + // std::cout << goodTracks.size()<(cfgc)}; +} diff --git a/PWGUD/Tasks/sgSpectraAnalyzer.cxx b/PWGUD/Tasks/sgSpectraAnalyzer.cxx index fbe9847bb0c..cffb6014300 100644 --- a/PWGUD/Tasks/sgSpectraAnalyzer.cxx +++ b/PWGUD/Tasks/sgSpectraAnalyzer.cxx @@ -16,10 +16,11 @@ #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "iostream" #include "PWGUD/DataModel/UDTables.h" #include "PWGUD/Core/SGSelector.h" -#include "PWGUD/Tasks/SGTrackSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" //#include "Common/DataModel/PIDResponse.h" //#include "PWGUD/Core/RLhelper.h" #include @@ -29,19 +30,46 @@ using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; -#define mpion 0.1396 -#define mkaon 0.4937 -#define mproton 0.9383 +namespace excl_fs +{ +DECLARE_SOA_COLUMN(GS, gs, int); +DECLARE_SOA_COLUMN(PV, pv, int); +DECLARE_SOA_COLUMN(ZA, za, int); +DECLARE_SOA_COLUMN(ZC, zc, int); +DECLARE_SOA_COLUMN(SIGN, sign, std::vector); +DECLARE_SOA_COLUMN(PX, px, std::vector); +DECLARE_SOA_COLUMN(PY, py, std::vector); +DECLARE_SOA_COLUMN(PZ, pz, std::vector); +DECLARE_SOA_COLUMN(ISELEC, iselec, std::vector); +DECLARE_SOA_COLUMN(ISMUON, ismuon, std::vector); +DECLARE_SOA_COLUMN(ISPION, ispion, std::vector); +DECLARE_SOA_COLUMN(ISKAON, iskaon, std::vector); +DECLARE_SOA_COLUMN(ISPROTON, isproton, std::vector); +} // namespace excl_fs +namespace o2::aod +{ +DECLARE_SOA_TABLE(Excl_fs, "AOD", "EXCL_FS", + excl_fs::GS, excl_fs::PV, excl_fs::ZA, excl_fs::ZC, excl_fs::SIGN, excl_fs::PX, excl_fs::PY, excl_fs::PZ, excl_fs::ISELEC, excl_fs::ISMUON, excl_fs::ISPION, excl_fs::ISKAON, excl_fs::ISPROTON); +} struct SGSpectraAnalyzer { SGSelector sgSelector; + Service pdg; Configurable FV0_cut{"FV0", 100., "FV0A threshold"}; Configurable FT0A_cut{"FT0A", 100., "FT0A threshold"}; Configurable FT0C_cut{"FT0C", 50., "FT0C threshold"}; Configurable FDDA_cut{"FDDA", 10000., "FDDA threshold"}; Configurable FDDC_cut{"FDDC", 10000., "FDDC threshold"}; Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; - Configurable eta_cut{"Eta", 0.9, "Eta cut"}; Configurable use_tof{"Use_TOF", true, "TOF PID"}; + // Track Selections + Configurable PV_cut{"PV_cut", 1.0, "Use Only PV tracks"}; + Configurable dcaZ_cut{"dcaZ_cut", 2.0, "dcaZ cut"}; + Configurable dcaXY_cut{"dcaXY_cut", 0.0, "dcaXY cut (0 for Pt-function)"}; + Configurable tpcChi2_cut{"tpcChi2_cut", 4, "Max tpcChi2NCl"}; + Configurable tpcNClsFindable_cut{"tpcNClsFindable_cut", 70, "Min tpcNClsFindable"}; + Configurable itsChi2_cut{"itsChi2_cut", 36, "Max itsChi2NCl"}; + Configurable eta_cut{"Eta", 0.9, "Eta cut"}; + Configurable pt_cut{"pt_cut", 0.1, "Track Pt"}; HistogramRegistry registry{ "registry", {// Pion histograms for each eta bin and gapSide @@ -184,6 +212,9 @@ struct SGSpectraAnalyzer { */ void process(UDCollisionFull const& collision, udtracksfull const& tracks) { + const float mpion = pdg->Mass(211); + const float mkaon = pdg->Mass(321); + const float mproton = pdg->Mass(2212); TLorentzVector a; TLorentzVector am; TLorentzVector sum; @@ -192,7 +223,8 @@ struct SGSpectraAnalyzer { sum.SetXYZM(0, 0, 0, 0); int gapSide = collision.gapSide(); float FIT_cut[5] = {FV0_cut, FT0A_cut, FT0C_cut, FDDA_cut, FDDC_cut}; - int truegapSide = sgSelector.trueGap(collision, FIT_cut[0], FIT_cut[1], FIT_cut[3], ZDC_cut); + std::vector parameters = {PV_cut, dcaZ_cut, dcaXY_cut, tpcChi2_cut, tpcNClsFindable_cut, itsChi2_cut, eta_cut, pt_cut}; + int truegapSide = sgSelector.trueGap(collision, FIT_cut[0], FIT_cut[1], FIT_cut[2], ZDC_cut); gapSide = truegapSide; if (gapSide < 0 || gapSide > 2) return; @@ -222,7 +254,7 @@ struct SGSpectraAnalyzer { registry.get(HIST("DcaZ_PV"))->Fill(track.dcaZ()); registry.get(HIST("DcaXY_PV"))->Fill(track.dcaXY()); alltracks++; - if (trackselector(track)) { + if (trackselector(track, parameters)) { int track_pid = trackpid(track, use_tof); // if (ispion(track, use_tof)) { if (track_pid <= 1) { diff --git a/PWGUD/Tasks/sgTwoPiAnalyzer.cxx b/PWGUD/Tasks/sgTwoPiAnalyzer.cxx new file mode 100644 index 00000000000..b7015745448 --- /dev/null +++ b/PWGUD/Tasks/sgTwoPiAnalyzer.cxx @@ -0,0 +1,206 @@ +// 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. +// +// \Single Gap Event Analyzer +// \author Sasha Bylinkin, alexander.bylinkin@gmail.com +// \since April 2023 + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "iostream" +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" +#include "Common/DataModel/PIDResponse.h" +#include "Framework/ASoA.h" +#include "Framework/DataTypes.h" +#include "MathUtils/Utils.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include "TLorentzVector.h" +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +namespace o2::aod +{ +namespace rho +{ +DECLARE_SOA_COLUMN(Run, run, int32_t); +DECLARE_SOA_COLUMN(Flag, flag, int); +DECLARE_SOA_COLUMN(GS, gs, int); +DECLARE_SOA_COLUMN(ZNA, zna, float); +DECLARE_SOA_COLUMN(ZNC, znc, float); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Minv, minv, float); +DECLARE_SOA_COLUMN(Sign, sign, float); +} // namespace rho +DECLARE_SOA_TABLE(Rho, "AOD", "RHO", + rho::Run, rho::Flag, rho::GS, rho::ZNA, rho::ZNC, rho::Pt, rho::Eta, rho::Minv, rho::Sign); +} // namespace o2::aod +struct SGTwoPiAnalyzer { + Produces rhoByRun; + SGSelector sgSelector; + Service pdg; + Configurable FV0_cut{"FV0", 50., "FV0A threshold"}; + Configurable FT0A_cut{"FT0A", 150., "FT0A threshold"}; + Configurable FT0C_cut{"FT0C", 50., "FT0C threshold"}; + Configurable FDDA_cut{"FDDA", 10000., "FDDA threshold"}; + Configurable FDDC_cut{"FDDC", 10000., "FDDC threshold"}; + Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; + // Track Selections + Configurable PV_cut{"PV_cut", 1.0, "Use Only PV tracks"}; + Configurable dcaZ_cut{"dcaZ_cut", 2.0, "dcaZ cut"}; + Configurable dcaXY_cut{"dcaXY_cut", 0.0, "dcaXY cut (0 for Pt-function)"}; + Configurable tpcChi2_cut{"tpcChi2_cut", 4, "Max tpcChi2NCl"}; + Configurable tpcNClsFindable_cut{"tpcNClsFindable_cut", 70, "Min tpcNClsFindable"}; + Configurable itsChi2_cut{"itsChi2_cut", 36, "Max itsChi2NCl"}; + Configurable eta_cut{"eta_cut", 0.9, "Track Pseudorapidity"}; + Configurable pt_cut{"pt_cut", 0.1, "Track Pt"}; + HistogramRegistry registry{ + "registry", + { + + {"GapSide", "Gap Side; Entries", {HistType::kTH1F, {{4, -1.5, 2.5}}}}, + {"TrueGapSide", "Gap Side; Entries", {HistType::kTH1F, {{4, -1.5, 2.5}}}}, + {"ITSNCls", "ITS Clusters", {HistType::kTH1F, {{10, -.5, 9.5}}}}, + {"os_2Pi_pT", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"os_2Pi_eTa", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + {"os_2Pi_invm", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"ss_2Pi_pT", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"ss_2Pi_eTa", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + {"ss_2Pi_invm", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"os_2Pi_pT_1", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"os_2Pi_eTa_1", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + {"os_2Pi_invm_1", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"ss_2Pi_pT_1", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"ss_2Pi_eTa_1", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + {"ss_2Pi_invm_1", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"os_2Pi_pT_0", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"os_2Pi_eTa_0", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + {"os_2Pi_invm_0", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"ss_2Pi_pT_0", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"ss_2Pi_eTa_0", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + {"ss_2Pi_invm_0", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"os_2Pi_pT_2", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"os_2Pi_eTa_2", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + {"os_2Pi_invm_2", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"ss_2Pi_pT_2", "#K#Pi pT (GeV/c); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"ss_2Pi_eTa_2", "#K#Pi eTa (GeV/c); Entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + {"ss_2Pi_invm_2", "#K#Pi Mass (GeV/c^2); Entries", {HistType::kTH1F, {{1000, 0, 10}}}}, + }}; + using udtracks = soa::Join; + using udtracksfull = soa::Join; + using UDCollisionsFull = soa::Join; // + using UDCollisionFull = UDCollisionsFull::iterator; + + void process(UDCollisionFull const& collision, udtracksfull const& tracks) + { + const float mpion = pdg->Mass(211); + TLorentzVector a; + int gapSide = collision.gapSide(); + if (gapSide < 0 || gapSide > 2) + return; + // Single gap either side + TLorentzVector v01; + // int truegapSide = sgSelector.trueGap(collision); + // int truegapSide = sgSelector.trueGap(collision, FV0_cut, ZDC_cut); + float FIT_cut[5] = {FV0_cut, FT0A_cut, FT0C_cut, FDDA_cut, FDDC_cut}; + std::vector parameters = {PV_cut, dcaZ_cut, dcaXY_cut, tpcChi2_cut, tpcNClsFindable_cut, itsChi2_cut, eta_cut, pt_cut}; + // int truegapSide = sgSelector.trueGap(collision, *FIT_cut, ZDC_cut); + int truegapSide = sgSelector.trueGap(collision, FIT_cut[0], FIT_cut[1], FIT_cut[2], ZDC_cut); + registry.fill(HIST("GapSide"), gapSide); + registry.fill(HIST("TrueGapSide"), truegapSide); + gapSide = truegapSide; + std::vector goodTracks; + // Look for D0 and D0bar + float sign = 0; + for (auto t : tracks) { + int itsNCls = t.itsNCls(); + // if (itsNCls) { + registry.fill(HIST("ITSNCls"), itsNCls); + //} + TLorentzVector a; + a.SetXYZM(t.px(), t.py(), t.pz(), mpion); + if (trackselector(t, parameters)) { + sign += t.sign(); + goodTracks.push_back(a); + } + } + // std::cout << goodTracks.size()<(cfgc)}; +} diff --git a/PWGUD/Tasks/sginclusivePhiKstarSD.cxx b/PWGUD/Tasks/sginclusivePhiKstarSD.cxx new file mode 100644 index 00000000000..20d4f08d1d6 --- /dev/null +++ b/PWGUD/Tasks/sginclusivePhiKstarSD.cxx @@ -0,0 +1,1566 @@ +// 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 sginclusivePhiKstarSD.cxx +/// \brief Single Gap Event Analyzer for phi and Kstar +/// \author Sandeep Dudi, sandeep.dudi3@gmail.com +/// \since May 2024 + +#include +#include +#include +#include +#include "Math/Vector4D.h" +#include "Math/Vector3D.h" +#include "Math/GenVector/Boost.h" +#include "TPDGCode.h" + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "ReconstructionDataFormats/Vertex.h" + +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" +#include "PWGUD/Core/UPCHelpers.h" + +#include "Common/DataModel/PIDResponse.h" + +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +struct SginclusivePhiKstarSD { + SGSelector sgSelector; + Service pdg; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + Configurable fv0Cut{"fv0Cut", 50., "FV0A threshold"}; + Configurable ft0aCut{"ft0aCut", 100., "FT0A threshold"}; + Configurable ft0cCut{"ft0cCut", 50., "FT0C threshold"}; + Configurable fddaCut{"fddaCut", 10000., "FDDA threshold"}; + Configurable fddcCut{"fddcCut", 10000., "FDDC threshold"}; + Configurable zdcCut{"zdcCut", 0., "ZDC threshold"}; + Configurable vzCut{"vzCut", 10., "Vz position"}; + Configurable occCut{"occCut", 1000., "Occupancy cut"}; + + // Track Selections + Configurable pvCut{"pvCut", 1.0, "Use Only PV tracks"}; + Configurable dcazCut{"dcazCut", 2.0, "dcaZ cut"}; + Configurable dcaxyCut{"dcaxyCut", 0.0, "dcaXY cut (0 for Pt-function)"}; + Configurable tpcChi2Cut{"tpcChi2Cut", 4, "Max tpcChi2NCl"}; + Configurable tpcNClsFindableCut{"tpcNClsFindableCut", 70, "Min tpcNClsFindable"}; + Configurable itsChi2Cut{"itsChi2Cut", 36, "Max itsChi2NCl"}; + Configurable etaCut{"etaCut", 0.9, "Track Pseudorapidity"}; + Configurable ptCut{"ptCut", 0.15, "Track pt cut"}; + Configurable pt1{"pt1", 0.3, "pid selection pt1"}; + Configurable pt2{"pt2", 0.4, "pid selection pt2"}; + Configurable pt3{"pt3", 0.5, "pid selection pt3"}; + + Configurable etaGapMin{"etaGapMin", 0.0, "Track eta min"}; + Configurable etaGapMax{"etaGapMax", 0.9, "Track eta max"}; + Configurable etaDG{"etaDG", 0.5, "Track eta DG"}; + + Configurable nsigmaTpcCut1{"nsigmaTpcCut1", 3.0, "nsigma tpc cut1"}; + Configurable nsigmaTpcCut2{"nsigmaTpcCut2", 3.0, "nsigma tpc cut2"}; + Configurable nsigmaTpcCut3{"nsigmaTpcCut3", 3.0, "nsigma tpc cut3"}; + Configurable nsigmaTpcCut4{"nsigmaTpcCut4", 3.0, "nsigma tpc cut4"}; + Configurable nsigmaTpcCut{"nsigmaTpcCut", 3.0, "nsigma tpc cut"}; + Configurable nsigmaTofCut{"nsigmaTofCut", 9.0, "nsigma tpc+tof cut"}; + Configurable nsigmaTofCut1{"nsigmaTofCut1", 3.0, "nsigma tof cut"}; + Configurable pionNsigmaCut{"pionNsigmaCut", 3.0, "nsigma tpc cut for kaon"}; + + Configurable mintrack{"mintrack", 1, "min track"}; + Configurable maxtrack{"maxtrack", 50, "max track"}; + Configurable useTof{"useTof", true, "TOF PID"}; + Configurable ccut{"ccut", true, "TPC + TOF PID"}; + Configurable kaoncut{"kaoncut", true, " kaon slection cut for kstar "}; + + Configurable qa{"qa", true, ""}; + Configurable rapidityGap{"rapidityGap", true, ""}; + + Configurable phi{"phi", true, ""}; + Configurable rho{"rho", true, ""}; + Configurable kstar{"kstar", true, ""}; + Configurable fourpion{"fourpion", true, ""}; + Configurable mc{"mc", true, ""}; + Configurable gapsideMC{"gapsideMC", 1, "gapside MC"}; + + Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 1, "Number of mixed events per event"}; + Configurable nBkgRotations{"nBkgRotations", 9, "Number of rotated copies (background) per each original candidate"}; + Configurable fillRotation{"fillRotation", true, "fill rotation"}; + Configurable confMinRot{"confMinRot", 5.0 * o2::constants::math::PI / 6.0, "Minimum of rotation"}; + Configurable confMaxRot{"confMaxRot", 7.0 * o2::constants::math::PI / 6.0, "Maximum of rotation"}; + // + Configurable reconstruction{"reconstruction", true, ""}; + Configurable generatedId{"generatedId", 31, ""}; + + void init(InitContext const& context) + { + registry.add("GapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + registry.add("TrueGapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + registry.add("nPVContributors_data", "Multiplicity_dist_before track cut gap A", kTH1F, {{110, 0, 110}}); + registry.add("nPVContributors_data_1", "Multiplicity_dist_before track cut gap C", kTH1F, {{110, 0, 110}}); + + if (phi) { + registry.add("os_KK_pT_0", "pt kaon pair", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_KK_pT_1", "pt kaon pair", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_KK_pT_2", "pt kaon pair", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_KK_ls_pT_0", "kaon pair like sign", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_KK_ls_pT_1", "kaon pair like sign", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_KK_ls_pT_2", "kaon pair like sign", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + + registry.add("os_KK_mix_pT_0", "kaon pair mix event", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_KK_mix_pT_1", "kaon pair mix event", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_KK_mix_pT_2", "kaon pair mix event", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + + registry.add("os_KK_rot_pT_0", "kaon pair mix event", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_KK_rot_pT_1", "kaon pair mix event", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_KK_rot_pT_2", "kaon pair mix event", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + } + if (rho) { + registry.add("os_pp_pT_0", "pt pion pair", kTH3F, {{120, 1.44, 2.04}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_pp_pT_1", "pt pion pair", kTH3F, {{120, 1.44, 2.04}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_pp_pT_2", "pt pion pair", kTH3F, {{120, 1.44, 2.04}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_pp_ls_pT_0", "pion pair like sign", kTH3F, {{120, 1.44, 2.04}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_pp_ls_pT_1", "pion pair like sign", kTH3F, {{120, 1.44, 2.04}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_pp_ls_pT_2", "pion pair like sign", kTH3F, {{120, 1.44, 2.04}, {80, -2.0, 2.0}, {100, 0, 10}}); + } + if (kstar) { + registry.add("os_pk_pT_0", "pion-kaon pair", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_pk_pT_1", "pion-kaon pair", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_pk_pT_2", "pion-kaon pair", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + + registry.add("os_pk_mix_pT_0", "pion-kaon mix pair", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_pk_mix_pT_1", "pion-kaon mix pair", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_pk_mix_pT_2", "pion-kaon mix pair", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + + registry.add("os_pk_rot_pT_0", "pion-kaon rotional pair", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_pk_rot_pT_1", "pion-kaon rotional pair", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_pk_rot_pT_2", "pion-kaon rotional pair", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + + registry.add("os_pk_ls_pT_0", "pion-kaon pair like sign", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_pk_ls_pT_1", "pion-kaon like sign", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_pk_ls_pT_2", "pion-kaon like sign", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + + registry.add("hRotation", "hRotation", kTH1F, {{360, 0.0, o2::constants::math::TwoPI}}); + } + // qa plots + if (qa) { + registry.add("tpc_dedx", "p vs dE/dx", kTH2F, {{100, 0.0, 10.0}, {10000, 0.0, 2500.0}}); + registry.add("tof_beta", "p vs beta", kTH2F, {{100, 0.0, 10.0}, {100, 0.0, 5.0}}); + + registry.add("tpc_dedx_kaon", "p#k dE/dx", kTH2F, {{100, 0.0, 10.0}, {10000, 0.0, 2500.0}}); + registry.add("tpc_dedx_pion", "p#pi dE/dx", kTH2F, {{100, 0.0, 10.0}, {10000, 0.0, 2500.0}}); + registry.add("tpc_dedx_kaon_1", "tpc+tof pid cut p#k dE/dx", kTH2F, {{100, 0.0, 10.0}, {10000, 0.0, 2500.0}}); + registry.add("tpc_dedx_kaon_2", "tpc+tof pid cut1 p#k dE/dx", kTH2F, {{100, 0.0, 10.0}, {10000, 0.0, 2500.0}}); + registry.add("tpc_dedx_pion_1", "tpc+tof pid cut p#pi dE/dx", kTH2F, {{100, 0.0, 10.0}, {10000, 0.0, 25000.0}}); + registry.add("tpc_nsigma_kaon", "p#k n#sigma", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + registry.add("tpc_nsigma_pion", "p#pi n#sigma", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + registry.add("tpc_tof_nsigma_kaon", "p#k n#sigma TPC vs TOF", kTH2F, {{100, -10.0, 10.0}, {100, -10.0, 10.0}}); + registry.add("tpc_tof_nsigma_pion", "p#pi n#sigma TPC vs TOF", kTH2F, {{100, -10.0, 10.0}, {100, -10.0, 10.0}}); + + registry.add("tof_nsigma_kaon", "p#k n#sigma", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + registry.add("tof_nsigma_pion", "p#pi n#sigma", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + registry.add("tof_nsigma_kaon_f", "p#k n#sigma", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + registry.add("tof_nsigma_pion_f", "p#pi n#sigma", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + registry.add("tpc_nsigma_kaon_f", "p#k n#sigma", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + registry.add("tpc_nsigma_pion_f", "p#pi n#sigma", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + + registry.add("FT0A", "T0A amplitude", kTH1F, {{500, 0.0, 500.0}}); + registry.add("FT0A_0", "T0A amplitude", kTH1F, {{500, 0.0, 500.0}}); + registry.add("FT0A_1", "T0A amplitude", kTH1F, {{20000, 0.0, 20000.0}}); + registry.add("FT0C", "T0C amplitude", kTH1F, {{500, 0.0, 500.0}}); + registry.add("FT0C_0", "T0C amplitude", kTH1F, {{20000, 0.0, 20000.0}}); + registry.add("FT0C_1", "T0C amplitude", kTH1F, {{500, 0.0, 500.0}}); + registry.add("ZDC_A", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + registry.add("ZDC_A_0", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + registry.add("ZDC_A_1", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + registry.add("ZDC_C", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + registry.add("ZDC_C_0", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + registry.add("ZDC_C_1", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + registry.add("V0A", "V0A amplitude", kTH1F, {{1000, 0.0, 1000.0}}); + registry.add("V0A_0", "V0A amplitude", kTH1F, {{1000, 0.0, 1000.0}}); + registry.add("V0A_1", "V0A amplitude", kTH1F, {{1000, 0.0, 1000.0}}); + + if (rapidityGap) { + registry.add("mult_0", "mult0", kTH1F, {{150, 0, 150}}); + registry.add("mult_1", "mult1", kTH1F, {{150, 0, 150}}); + registry.add("mult_2", "mult2", kTH1F, {{150, 0, 150}}); + registry.add("event_rap_gap", "rap_gap", kTH1F, {{15, 0, 15.0}}); + registry.add("rap_mult1", "rap_mult1", kTH1F, {{150, 0, 150}}); + registry.add("rap_mult2", "rap_mult2", kTH1F, {{150, 0, 150}}); + registry.add("rap_mult3", "rap_mult3", kTH1F, {{150, 0, 150}}); + registry.add("rap1_mult1", "rap1_mult1", kTH1F, {{150, 0, 150}}); + registry.add("rap1_mult2", "rap1_mult2", kTH1F, {{150, 0, 150}}); + registry.add("rap1_mult3", "rap1_mult3", kTH1F, {{150, 0, 150}}); + registry.add("rap2_mult1", "rap2_mult1", kTH1F, {{150, 0, 150}}); + registry.add("rap2_mult2", "rap2_mult2", kTH1F, {{150, 0, 150}}); + registry.add("rap2_mult3", "rap2_mult3", kTH1F, {{150, 0, 150}}); + } + } + registry.add("gap_mult0", "Mult 0", kTH1F, {{100, 0.0, 100.0}}); + registry.add("gap_mult1", "Mult 1", kTH1F, {{100, 0.0, 100.0}}); + registry.add("gap_mult2", "Mult 2", kTH1F, {{100, 0.0, 100.0}}); + + // Multiplicity plot + if (rapidityGap && phi) { + registry.add("os_kk_mass_rap", "phi mass1", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kk_mass_rap1", "phi mass2", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kk_mass_rap2", "phi mass3", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kk_mass1_rap", "phi mass1 gap1", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kk_mass1_rap1", "phi mass2 gap1", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kk_mass1_rap2", "phi mass3 gap1", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kk_mass2_rap", "phi mass1 DG", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kk_mass2_rap1", "phi mass2 DG", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kk_mass2_rap2", "phi mass3 DG", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + + // like sign bkg + registry.add("os_kk_ls_mass_rap", "phi ls mass1", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kk_ls_mass_rap1", "phi ls mass2", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kk_ls_mass_rap2", "phi ls mass3", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kk_ls_mass1_rap", "phi ls mass1 gap1", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kk_ls_mass1_rap1", "phi ls mass2 gap1", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kk_ls_mass1_rap2", "phi ls mass3 gap1", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kk_ls_mass2_rap", "phi ls mass1 DG", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kk_ls_mass2_rap1", "phi ls mass2 DG", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kk_ls_mass2_rap2", "phi ls mass3 DG", kTH3F, {{220, 0.98, 1.2}, {80, -2.0, 2.0}, {100, 0, 10}}); + } + + if (rapidityGap && kstar) { + registry.add("os_kp_mass_rap", "kstar mass1", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kp_mass_rap1", "kstar mass2", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kp_mass_rap2", "kstar mass3", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kp_mass1_rap", "kstar mass1 gap1", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kp_mass1_rap1", "kstar mass2 gap1", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kp_mass1_rap2", "kstar mass3 gap1", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kp_mass2_rap", "kstar mass1 DG", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kp_mass2_rap1", "kstar mass2 DG", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kp_mass2_rap2", "kstar mass3 DG", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + + // like sign bkg + + registry.add("os_kp_ls_mass_rap", "kstar ls mass1", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kp_ls_mass_rap1", "kstar ls mass2", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kp_ls_mass_rap2", "kstar ls mass3", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kp_ls_mass1_rap", "kstar ls mass1 gap1", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kp_ls_mass1_rap1", "kstar ls mass2 gap1", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kp_ls_mass1_rap2", "kstar ls mass3 gap1", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kp_ls_mass2_rap", "kstar ls mass1 DG", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kp_ls_mass2_rap1", "kstar ls mass2 DG", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + registry.add("os_kp_ls_mass2_rap2", "kstar ls mass3 DG", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + } + if (fourpion) { + registry.add("os_pppp_pT_2", "4 pion pair", kTH3F, {{800, 0.5, 4.5}, {250, 0.0, 5.0}, {30, -1.5, 1.5}}); + registry.add("os_pppp_pT_2_ls", "4 pion pair", kTH3F, {{800, 0.5, 4.5}, {250, 0.0, 5.0}, {30, -1.5, 1.5}}); + registry.add("os_pp_vs_pp_mass", "pair1 vd pair2 ", kTH2F, {{800, 0.5, 4.5}, {800, 0.5, 4.5}}); + registry.add("os_pp_vs_pp_pt", "pair1 pt vs pair2 pt", kTH2F, {{250, 0.0, 5.0}, {250, 0.0, 5.0}}); + registry.add("os_pp_vs_pp_mass1", "pair3 vd pair4 ", kTH2F, {{800, 0.5, 4.5}, {800, 0.5, 4.5}}); + registry.add("os_pp_vs_pp_pt1", "pair3 pt vs pair4 pt", kTH2F, {{250, 0.0, 5.0}, {250, 0.0, 5.0}}); + registry.add("phi_dis", "phi_dis", kTH1F, {{360, 0, 6.28}}); + registry.add("costheta_dis", "costheta_dis", kTH1F, {{40, -1.0, 1.0}}); + registry.add("costheta_vs_phi", "costheta_vs_phi", kTH2F, {{40, -1.0, 1.0}, {360, 0.0, 6.28}}); + registry.add("phi_dis1", "phi_dis1", kTH1F, {{360, 0, 6.28}}); + registry.add("costheta_dis1", "costheta_dis1", kTH1F, {{40, -1.0, 1.0}}); + registry.add("costheta_vs_phi1", "costheta_vs_phi1", kTH2F, {{40, -1.0, 1.0}, {360, 0.0, 6.28}}); + } + if (mc) { + // add histograms for the different process functions + if (context.mOptions.get("processMCTruth")) { + registry.add("MC/Stat", "Count generated events; ; Entries", {HistType::kTH1F, {{1, -0.5, 0.5}}}); + registry.add("MC/recCols", "Number of reconstructed collisions; Number of reconstructed collisions; Entries", {HistType::kTH1F, {{31, -0.5, 30.5}}}); + registry.add("MC/nParts", "Number of McParticles per collision; Number of McParticles; Entries", {HistType::kTH1F, {{1001, -0.5, 1000.5}}}); + registry.add("MC/nRecTracks", "Number of reconstructed tracks per McParticle; Number of reconstructed tracks per McParticle; Entries", {HistType::kTH1F, {{11, -0.5, 10.5}}}); + registry.add("MC/genEtaPt", "Generated events; eta (1); Pt (GeV/c)", {HistType::kTH2F, {{60, -1.5, 1.5}, {250, 0.0, 5.0}}}); + registry.add("MC/genRap", "Generated events; Rapidity (1)", {HistType::kTH1F, {{60, -1.5, 1.5}}}); + registry.add("MC/genMPt", "Generated events; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH2F, {{220, 0.98, 1.2}, {200, 0.0, 10.0}}}); + registry.add("MC/genM", "Generated events; Mass (GeV/c^2)", {HistType::kTH1F, {{220, 0.98, 1.2}}}); + registry.add("MC/genM_1", "Generated events; Mass (GeV/c^2)", {HistType::kTH1F, {{220, 0.98, 1.2}}}); + + registry.add("MC/accMPtRap_phi_G", "Generated Phi; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH3F, {{220, 0.98, 1.20}, {200, 0.0, 10.0}, {60, -1.5, 1.5}}}); + + registry.add("MC/accEtaPt", "Generated events in acceptance; eta (1); Pt (GeV/c)", {HistType::kTH2F, {{60, -1.5, 1.5}, {250, 0.0, 5.0}}}); + registry.add("MC/accRap", "Generated events in acceptance; Rapidity (1)", {HistType::kTH1F, {{60, -1.5, 1.5}}}); + registry.add("MC/accMPt", "Generated events in acceptance; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH2F, {{220, 0.98, 1.20}, {200, 0.0, 10.0}}}); + registry.add("MC/accMPtRap", "Generated events in acceptance; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH3F, {{220, 0.98, 1.20}, {200, 0.0, 10.0}, {60, -1.5, 1.5}}}); + registry.add("MC/accM", "Generated events in acceptance; Mass (GeV/c^2)", {HistType::kTH1F, {{220, 0.98, 1.20}}}); + registry.add("MC/selRap", "Selected events in acceptance; Rapidity (1)", {HistType::kTH1F, {{60, -1.5, 1.5}}}); + registry.add("MC/selMPt", "Selected events in acceptance; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH2F, {{250, 2.5, 5.0}, {100, 0.0, 1.0}}}); + registry.add("MC/pDiff", "McTruth - reconstructed track momentum; McTruth - reconstructed track momentum; Entries", {HistType::kTH2F, {{240, -6., 6.}, {3, -1.5, 1.5}}}); + // K*0 + registry.add("MC/accMPtRap_kstar_G", "Generated K*0; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH3F, {{400, 0., 2.0}, {200, 0.0, 10.0}, {60, -1.5, 1.5}}}); + registry.add("MC/genEtaPt_k", "Generated events; eta (1); Pt (GeV/c)", {HistType::kTH2F, {{60, -1.5, 1.5}, {250, 0.0, 5.0}}}); + registry.add("MC/genRap_k", "Generated events; Rapidity (1)", {HistType::kTH1F, {{60, -1.5, 1.5}}}); + registry.add("MC/genMPt_k", "Generated events; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH2F, {{400, 0., 2.0}, {200, 0.0, 10.0}}}); + registry.add("MC/genM_k", "Generated events; Mass (GeV/c^2)", {HistType::kTH1F, {{400, 0., 2.0}}}); + registry.add("MC/genM_1_k", "Generated events; Mass (GeV/c^2)", {HistType::kTH1F, {{400, 0., 2.0}}}); + + registry.add("MC/accEtaPt_k", "Generated events in acceptance; eta (1); Pt (GeV/c)", {HistType::kTH2F, {{60, -1.5, 1.5}, {250, 0.0, 5.0}}}); + registry.add("MC/accRap_k", "Generated events in acceptance; Rapidity (1)", {HistType::kTH1F, {{60, -1.5, 1.5}}}); + registry.add("MC/accMPt_k", "Generated events in acceptance; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH2F, {{400, 0., 2.0}, {200, 0.0, 10.0}}}); + registry.add("MC/accMPtRap_k", "Generated events in acceptance; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH3F, {{400, 0., 2.0}, {200, 0.0, 10.0}, {60, -1.5, 1.5}}}); + registry.add("MC/accM_k", "Generated events in acceptance; Mass (GeV/c^2)", {HistType::kTH1F, {{400, 0., 2.0}}}); + } + if (context.mOptions.get("processReco")) { + registry.add("Reco/Stat", "Count reconstruted events; ; Entries", {HistType::kTH1F, {{5, -0.5, 4.5}}}); + registry.add("Reco/nPVContributors", "Number of PV contributors per collision; Number of PV contributors; Entries", {HistType::kTH1F, {{51, -0.5, 50.5}}}); + registry.add("Reco/selRap", "Selected events in acceptance; Rapidity (1)", {HistType::kTH1F, {{60, -1.5, 1.5}}}); + registry.add("Reco/selMPt", "Reconstructed events in acceptance; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH2F, {{220, 0.98, 1.20}, {200, 0.0, 10.0}}}); + registry.add("Reco/selMPtRap", "Reconstructed events in acceptance; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH3F, {{220, 0.98, 1.20}, {200, 0.0, 10.0}, {60, -1.5, 1.5}}}); + registry.add("Reco/selMPtRap_gen", "Reconstructed(gen) events in acceptance; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH3F, {{220, 0.98, 1.20}, {200, 0.0, 10.0}, {60, -1.5, 1.5}}}); + registry.add("MC/accMPtRap_phi_T", "Reconstrcted Phi; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH3F, {{220, 0.98, 1.20}, {200, 0.0, 10.0}, {60, -1.5, 1.5}}}); + registry.add("MC/accMPtRap_kstar_T", "Reconstructed K*0; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH3F, {{400, 0., 2.0}, {200, 0.0, 10.0}, {60, -1.5, 1.5}}}); + + registry.add("Reco/selPt", "Reconstructed events in acceptance;Pt (GeV/c)", {HistType::kTH1F, {{200, 0.0, 10.0}}}); + registry.add("Reco/selM", "Reconstructed events in acceptance; Mass (GeV/c^2); ", {HistType::kTH1F, {{220, 0.98, 1.20}}}); + registry.add("Reco/mcEtaPt", "Generated events in acceptance; eta (1); Pt (GeV/c)", {HistType::kTH2F, {{60, -1.5, 1.5}, {250, 0.0, 5.0}}}); + registry.add("Reco/mcRap", "Generated events in acceptance; Rapidity (1)", {HistType::kTH1F, {{60, -1.5, 1.5}}}); + registry.add("Reco/mcMPt", "Generated events in acceptance; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH2F, {{250, 2.5, 5.0}, {100, 0.0, 1.0}}}); + registry.add("Reco/pDiff", "McTruth - reconstructed track momentum; McTruth - reconstructed track momentum; Entries", {HistType::kTH2F, {{240, -6., 6.}, {3, -1.5, 1.5}}}); + + registry.add("Reco/selRap_k", "Selected events in acceptance; Rapidity (1)", {HistType::kTH1F, {{60, -1.5, 1.5}}}); + registry.add("Reco/selMPt_k", "Reconstructed events in acceptance; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH2F, {{400, 0., 2.0}, {200, 0.0, 10.0}}}); + registry.add("Reco/selMPtRap_k", "Reconstructed events in acceptance; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH3F, {{400, 0., 2.0}, {200, 0.0, 10.0}, {60, -1.5, 1.5}}}); + registry.add("Reco/selMPtRap_k_gen", "Reconstructed(gen) events in acceptance; Mass (GeV/c^2); Pt (GeV/c)", {HistType::kTH3F, {{400, 0., 2.0}, {200, 0.0, 10.0}, {60, -1.5, 1.5}}}); + registry.add("Reco/selPt_k", "Reconstructed events in acceptance;Pt (GeV/c)", {HistType::kTH1F, {{200, 0.0, 10.0}}}); + registry.add("Reco/selM_k", "Reconstructed events in acceptance; Mass (GeV/c^2); ", {HistType::kTH1F, {{400, 0., 2.0}}}); + registry.add("Reco/selM_k_K", "Reconstructed events in acceptance; Mass (GeV/c^2); ", {HistType::kTH1F, {{400, 0., 2.0}}}); + + registry.add("Reco/nTracks", "Number of reconstructed tracks per collision; Number of reconstructed tracks; Entries", {HistType::kTH1F, {{101, -0.5, 100.5}}}); + registry.add("Reco/treta_k", "track kaon eta", {HistType::kTH1F, {{200, -5.0, 5.0}}}); + registry.add("Reco/trpt_k", "rec kaon track pt", {HistType::kTH1F, {{200, 0.0, 10.0}}}); + registry.add("Reco/trpt", "rec track pt", {HistType::kTH1F, {{200, 0.0, 10.0}}}); + + registry.add("Reco/tr_dcaz_1", "dcaz-", {HistType::kTH1F, {{1000, -5.0, 5.0}}}); + registry.add("Reco/tr_dcaxy_1", "dcaxy-", {HistType::kTH1F, {{1000, -5.0, 5.0}}}); + registry.add("Reco/tr_chi2ncl_1", "chi2ncl-", {HistType::kTH1F, {{100, 0.0, 100.0}}}); + registry.add("Reco/tr_tpcnclfind_1", "tpcnclfind-", {HistType::kTH1F, {{300, 0.0, 300.0}}}); + registry.add("Reco/tr_itsChi2NCl_1", "itsChi2NCl-", {HistType::kTH1F, {{200, 0.0, 200.0}}}); + registry.add("Reco/tr_Eta_1", " eta -", {HistType::kTH1F, {{300, 1.5, 1.5}}}); + + registry.add("Reco/tr_dcaz_2", "dcaz", {HistType::kTH1F, {{1000, -5.0, 5.0}}}); + registry.add("Reco/tr_dcaxy_2", "dcaxy", {HistType::kTH1F, {{1000, -5.0, 5.0}}}); + registry.add("Reco/tr_chi2ncl_2", "chi2ncl", {HistType::kTH1F, {{100, 0.0, 100.0}}}); + registry.add("Reco/tr_tpcnclfind_2", "tpcnclfind", {HistType::kTH1F, {{300, 0.0, 300.0}}}); + registry.add("Reco/tr_itsChi2NCl_2", "itsChi2NCl", {HistType::kTH1F, {{200, 0.0, 200.0}}}); + + // qa + registry.add("tpc_dedx_mc", "p vs dE/dx", kTH2F, {{100, 0.0, 10.0}, {5000, 0.0, 5000.0}}); + registry.add("tof_beta_mc", "p vs beta", kTH2F, {{100, 0.0, 10.0}, {5000, 0.0, 5000.0}}); + + registry.add("tpc_dedx_kaon_mc", "p#k dE/dx", kTH2F, {{100, 0.0, 10.0}, {5000, 0.0, 5000.0}}); + registry.add("tpc_dedx_pion_mc", "p#pi dE/dx", kTH2F, {{100, 0.0, 10.0}, {5000, 0.0, 5000.0}}); + registry.add("tpc_nsigma_kaon_mc", "p#k n#sigma", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + registry.add("tpc_nsigma_pion_mc", "p#pi n#sigma", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + + registry.add("tpc_tof_nsigma_kaon_mc", "p#k n#sigma TPC vs TOF", kTH2F, {{100, -10.0, 10.0}, {100, -10.0, 10.0}}); + registry.add("tpc_tof_nsigma_pion_mc", "p#pi n#sigma TPC vs TOF", kTH2F, {{100, -10.0, 10.0}, {100, -10.0, 10.0}}); + + registry.add("tof_nsigma_kaon_mc", "p#k n#sigma", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + registry.add("tof_nsigma_pion_mc", "p#pi n#sigma", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + registry.add("tof_nsigma_kaon_f_mc", "p#k n#sigma", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + registry.add("tof_nsigma_pion_f_mc", "p#pi n#sigma", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + + registry.add("tpc_nsigma_kaon_f_mc", "p#k n#sigma", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + registry.add("tpc_nsigma_pion_f_mc", "p#pi n#sigma", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + + registry.add("FT0A_0_mc", "T0A amplitude", kTH1F, {{500, 0.0, 500.0}}); + registry.add("FT0A_1_mc", "T0A amplitude", kTH1F, {{20000, 0.0, 20000.0}}); + registry.add("FT0C_0_mc", "T0C amplitude", kTH1F, {{20000, 0.0, 20000.0}}); + registry.add("FT0C_1_mc", "T0C amplitude", kTH1F, {{500, 0.0, 500.0}}); + registry.add("ZDC_A_0_mc", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + registry.add("ZDC_A_1_mc", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + registry.add("ZDC_C_0_mc", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + registry.add("ZDC_C_1_mc", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + registry.add("V0A_0_mc", "V0A amplitude", kTH1F, {{1000, 0.0, 1000.0}}); + registry.add("V0A_1_mc", "V0A amplitude", kTH1F, {{1000, 0.0, 1000.0}}); + } + } + } + + //_____________________________________________________________________________ + double cosThetaCollinsSoperFrame(TLorentzVector pair1, + TLorentzVector pair2, + TLorentzVector fourpion) + { + double halfSqrtSnn = 2680.; + double massOfLead208 = 193.6823; + double momentumBeam = std::sqrt(halfSqrtSnn * halfSqrtSnn * 208 * 208 - massOfLead208 * massOfLead208); + + ROOT::Math::PxPyPzEVector pProjCM(0., 0., -momentumBeam, halfSqrtSnn * 208); // projectile + ROOT::Math::PxPyPzEVector pTargCM(0., 0., momentumBeam, halfSqrtSnn * 208); // target + + ROOT::Math::PxPyPzMVector v1 = ROOT::Math::PxPyPzMVector(pair1.Px(), pair1.Py(), pair1.Pz(), pair1.M()); + ROOT::Math::PxPyPzMVector v2 = ROOT::Math::PxPyPzMVector(pair2.Px(), pair2.Py(), pair2.Pz(), pair2.M()); + ROOT::Math::PxPyPzMVector v12 = ROOT::Math::PxPyPzMVector(fourpion.Px(), fourpion.Py(), fourpion.Pz(), fourpion.M()); + + // Boost to center of mass frame + ROOT::Math::Boost boostv12{v12.BoostToCM()}; + ROOT::Math::XYZVectorF v1Cm{(boostv12(v1).Vect()).Unit()}; + ROOT::Math::XYZVectorF v2Cm{(boostv12(v2).Vect()).Unit()}; + ROOT::Math::XYZVectorF beam1Cm{(boostv12(pProjCM).Vect()).Unit()}; + ROOT::Math::XYZVectorF beam2Cm{(boostv12(pTargCM).Vect()).Unit()}; + // Axes + ROOT::Math::XYZVectorF zaxisCs{((beam1Cm.Unit() - beam2Cm.Unit()).Unit())}; + + double cosThetaCs = zaxisCs.Dot((v1Cm)); + return cosThetaCs; + } + + template + bool selectionPIDKaon1(const T& candidate) + { + auto pt = std::sqrt(candidate.px() * candidate.px() + candidate.py() * candidate.py()); + // float pt1, pt2, pt3 , nsigmatpc_cut1, nsigmatpc_cut2, nsigmatpc_cut3; + if (useTof && pt < pt1 && std::abs(candidate.tpcNSigmaKa()) < nsigmaTpcCut1) { + return true; + } + if (useTof && pt >= pt1 && pt < pt2 && std::abs(candidate.tpcNSigmaKa()) < nsigmaTpcCut2) { + return true; + } + if (useTof && pt >= pt2 && pt < pt3 && std::abs(candidate.tpcNSigmaKa()) < nsigmaTpcCut3) { + return true; + } + if (useTof && pt >= pt3 && !candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < nsigmaTpcCut) { + return true; + } + if (useTof && candidate.hasTOF() && ccut && (candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa()) < nsigmaTofCut) { + return true; + } + if (useTof && candidate.hasTOF() && !ccut && std::abs(candidate.tpcNSigmaKa()) < nsigmaTpcCut && std::abs(candidate.tofNSigmaKa()) < nsigmaTofCut1) { + return true; + } + + if (!useTof && std::abs(candidate.tpcNSigmaKa()) < nsigmaTpcCut) { + return true; + } + return false; + } + + template + bool selectionPIDPion1(const T& candidate) + { + auto pt = std::sqrt(candidate.px() * candidate.px() + candidate.py() * candidate.py()); + + if (useTof && pt < pt1 && std::abs(candidate.tpcNSigmaPi()) < nsigmaTpcCut1) { + return true; + } + if (useTof && pt >= pt1 && pt < pt2 && std::abs(candidate.tpcNSigmaPi()) < nsigmaTpcCut2) { + return true; + } + if (useTof && pt >= pt2 && pt < pt3 && std::abs(candidate.tpcNSigmaPi()) < nsigmaTpcCut3) { + return true; + } + if (useTof && pt >= pt3 && !candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < nsigmaTpcCut) { + return true; + } + if (useTof && candidate.hasTOF() && ccut && (candidate.tofNSigmaPi() * candidate.tofNSigmaPi() + candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi()) < nsigmaTofCut) { + return true; + } + if (useTof && candidate.hasTOF() && !ccut && std::abs(candidate.tpcNSigmaPi()) < nsigmaTpcCut && std::abs(candidate.tofNSigmaPi()) < nsigmaTofCut1) { + return true; + } + if (!useTof && std::abs(candidate.tpcNSigmaPi()) < nsigmaTpcCut) { + return true; + } + return false; + } + + //------------------------------------------------------------------------------------------------------ + double phiCollinsSoperFrame(TLorentzVector pair1, TLorentzVector pair2, TLorentzVector fourpion) + { + // Half of the energy per pair of the colliding nucleons. + double halfSqrtSnn = 2680.; + double massOfLead208 = 193.6823; + double momentumBeam = std::sqrt(halfSqrtSnn * halfSqrtSnn * 208 * 208 - massOfLead208 * massOfLead208); + + ROOT::Math::PxPyPzEVector pProjCM(0., 0., -momentumBeam, halfSqrtSnn * 208); // projectile + ROOT::Math::PxPyPzEVector pTargCM(0., 0., momentumBeam, halfSqrtSnn * 208); // target + + ROOT::Math::PxPyPzMVector v1 = ROOT::Math::PxPyPzMVector(pair1.Px(), pair1.Py(), pair1.Pz(), pair1.M()); + ROOT::Math::PxPyPzMVector v2 = ROOT::Math::PxPyPzMVector(pair2.Px(), pair2.Py(), pair2.Pz(), pair2.M()); + ROOT::Math::PxPyPzMVector v12 = ROOT::Math::PxPyPzMVector(fourpion.Px(), fourpion.Py(), fourpion.Pz(), fourpion.M()); + + // Boost to center of mass frame + ROOT::Math::Boost boostv12{v12.BoostToCM()}; + ROOT::Math::XYZVectorF v1Cm{(boostv12(v1).Vect()).Unit()}; + ROOT::Math::XYZVectorF v2Cm{(boostv12(v2).Vect()).Unit()}; + ROOT::Math::XYZVectorF beam1Cm{(boostv12(pProjCM).Vect()).Unit()}; + ROOT::Math::XYZVectorF beam2Cm{(boostv12(pTargCM).Vect()).Unit()}; + // Axes + ROOT::Math::XYZVectorF zaxisCs{((beam1Cm.Unit() - beam2Cm.Unit()).Unit())}; + ROOT::Math::XYZVectorF yaxisCs{(beam1Cm.Cross(beam2Cm)).Unit()}; + ROOT::Math::XYZVectorF xaxisCs{(yaxisCs.Cross(zaxisCs)).Unit()}; + + double phi = std::atan2(yaxisCs.Dot(v1Cm), xaxisCs.Dot(v1Cm)); + return phi; + } + + using UDtracksfull = soa::Join; + using UDCollisionsFull = soa::Join; // + using UDCollisionFull = UDCollisionsFull::iterator; + + void process(UDCollisionFull const& collision, UDtracksfull const& tracks) + { + TLorentzVector v0; + TLorentzVector v1; + TLorentzVector v01; + int gapSide = collision.gapSide(); + float fitCut[5] = {fv0Cut, ft0aCut, ft0cCut, fddaCut, fddcCut}; + std::vector parameters = {pvCut, dcazCut, dcaxyCut, tpcChi2Cut, tpcNClsFindableCut, itsChi2Cut, etaCut, ptCut}; + int truegapSide = sgSelector.trueGap(collision, fitCut[0], fitCut[1], fitCut[2], zdcCut); + + TLorentzVector phiv; + TLorentzVector phiv1; + + std::vector onlyPionTracksp; + std::vector rawPionTracksp; + + std::vector onlyPionTrackspm; + std::vector rawPionTrackspm; + + std::vector onlyPionTracksn; + std::vector rawPionTracksn; + + registry.fill(HIST("GapSide"), gapSide); + registry.fill(HIST("TrueGapSide"), truegapSide); + gapSide = truegapSide; + if (gapSide < 0 || gapSide > 2) + return; + if (std::abs(collision.posZ()) > vzCut) + return; + if (std::abs(collision.occupancyInTime()) > occCut) + return; + + int mult = collision.numContrib(); + if (gapSide == 0) { + registry.fill(HIST("gap_mult0"), mult); + } + if (gapSide == 1) { + registry.fill(HIST("gap_mult1"), mult); + } + if (gapSide == 2) { + registry.fill(HIST("gap_mult2"), mult); + } + if (mult < mintrack || mult > maxtrack) + return; + int mult0 = 0; + int mult1 = 0; + int mult2 = 0; + int trackgapA = 0; + int trackgapC = 0; + int trackDG = 0; + int trackextra = 0; + int trackextraDG = 0; + + Partition pvContributors1 = aod::udtrack::isPVContributor == true; + pvContributors1.bindTable(tracks); + if (gapSide == 0) { + registry.get(HIST("nPVContributors_data"))->Fill(pvContributors1.size(), 1.); + } + if (gapSide == 1) { + registry.get(HIST("nPVContributors_data_1"))->Fill(pvContributors1.size(), 1.); + } + for (const auto& track1 : tracks) { + if (!trackselector(track1, parameters)) + continue; + v0.SetXYZM(track1.px(), track1.py(), track1.pz(), o2::constants::physics::MassPionCharged); + if (selectionPIDPion1(track1)) { + onlyPionTrackspm.push_back(v0); + rawPionTrackspm.push_back(track1); + if (track1.sign() == 1) { + onlyPionTracksp.push_back(v0); + rawPionTracksp.push_back(track1); + } + if (track1.sign() == -1) { + onlyPionTracksn.push_back(v0); + rawPionTracksn.push_back(track1); + } + } + if (gapSide == 0) { + mult0++; + } + if (gapSide == 1) { + mult1++; + } + if (gapSide == 2) { + mult2++; + } + if (std::abs(v0.Eta()) < etaDG) { + trackDG++; + } + if (v0.Eta() > etaGapMin && v0.Eta() < etaGapMax) { + trackgapA++; + } + if (v0.Eta() < etaGapMin && v0.Eta() > -etaGapMax) { + trackgapC++; + } + if (std::abs(v0.Eta()) > etaGapMax || std::abs(v0.Eta()) < etaGapMin) { + trackextra++; + } + if (std::abs(v0.Eta()) > etaDG) { + trackextraDG++; + } + + if (qa) { + registry.fill(HIST("tpc_dedx"), v0.P(), track1.tpcSignal()); + registry.fill(HIST("tof_beta"), v0.P(), track1.beta()); + registry.fill(HIST("tof_nsigma_kaon_f"), v0.Pt(), track1.tofNSigmaKa()); + registry.fill(HIST("tof_nsigma_pion_f"), v0.Pt(), track1.tofNSigmaPi()); + registry.fill(HIST("tpc_nsigma_kaon_f"), v0.Pt(), track1.tpcNSigmaKa()); + registry.fill(HIST("tpc_nsigma_pion_f"), v0.Pt(), track1.tpcNSigmaPi()); + + if (selectionPIDKaon1(track1)) { + registry.fill(HIST("tpc_dedx_kaon_1"), v0.P(), track1.tpcSignal()); + registry.fill(HIST("tpc_nsigma_kaon"), v0.Pt(), track1.tpcNSigmaKa()); + registry.fill(HIST("tof_nsigma_kaon"), v0.Pt(), track1.tofNSigmaKa()); + registry.fill(HIST("tpc_tof_nsigma_kaon"), track1.tpcNSigmaKa(), track1.tofNSigmaKa()); + } + + if (selectionPIDPion1(track1)) { + registry.fill(HIST("tpc_dedx_pion_1"), v0.P(), track1.tpcSignal()); + registry.fill(HIST("tpc_nsigma_pion"), v0.Pt(), track1.tpcNSigmaPi()); + registry.fill(HIST("tof_nsigma_pion"), v0.Pt(), track1.tofNSigmaPi()); + registry.fill(HIST("tpc_tof_nsigma_pion"), track1.tpcNSigmaPi(), track1.tofNSigmaPi()); + } + } + } + if (qa) { + if (gapSide == 0) { + registry.fill(HIST("V0A_0"), collision.totalFV0AmplitudeA()); + registry.fill(HIST("FT0A_0"), collision.totalFT0AmplitudeA()); + registry.fill(HIST("FT0C_0"), collision.totalFT0AmplitudeC()); + registry.fill(HIST("ZDC_A_0"), collision.energyCommonZNA()); + registry.fill(HIST("ZDC_C_0"), collision.energyCommonZNC()); + registry.fill(HIST("mult_0"), mult0); + } + if (gapSide == 1) { + registry.fill(HIST("V0A_1"), collision.totalFV0AmplitudeA()); + registry.fill(HIST("FT0A_1"), collision.totalFT0AmplitudeA()); + registry.fill(HIST("FT0C_1"), collision.totalFT0AmplitudeC()); + registry.fill(HIST("ZDC_A_1"), collision.energyCommonZNA()); + registry.fill(HIST("ZDC_C_1"), collision.energyCommonZNC()); + registry.fill(HIST("mult_1"), mult1); + } + if (gapSide == 2) { + registry.fill(HIST("V0A"), collision.totalFV0AmplitudeA()); + registry.fill(HIST("FT0A"), collision.totalFT0AmplitudeA()); + registry.fill(HIST("FT0C"), collision.totalFT0AmplitudeC()); + registry.fill(HIST("ZDC_A"), collision.energyCommonZNA()); + registry.fill(HIST("ZDC_C"), collision.energyCommonZNC()); + registry.fill(HIST("mult_2"), mult2); + } + if (rapidityGap) { + if (trackgapC > 0 && trackgapA == 0 && trackextra == 0) { + if (gapSide == 0) { + registry.fill(HIST("event_rap_gap"), 1); + registry.fill(HIST("rap_mult1"), trackgapC); + } + if (gapSide == 1) { + registry.fill(HIST("event_rap_gap"), 4); + registry.fill(HIST("rap1_mult1"), trackgapC); + } + if (gapSide == 2) { + registry.fill(HIST("event_rap_gap"), 7); + registry.fill(HIST("rap2_mult1"), trackgapC); + } + } + if (trackgapC == 0 && trackgapA > 0 && trackextra == 0) { + if (gapSide == 0) { + registry.fill(HIST("event_rap_gap"), 2); + registry.fill(HIST("rap_mult2"), trackgapA); + } + if (gapSide == 1) { + registry.fill(HIST("event_rap_gap"), 5); + registry.fill(HIST("rap1_mult2"), trackgapA); + } + if (gapSide == 2) { + registry.fill(HIST("event_rap_gap"), 8); + registry.fill(HIST("rap2_mult2"), trackgapA); + } + } + if (trackDG > 0 && trackextraDG == 0) { + if (gapSide == 0) { + registry.fill(HIST("event_rap_gap"), 3); + registry.fill(HIST("rap_mult3"), trackDG); + } + if (gapSide == 1) { + registry.fill(HIST("event_rap_gap"), 6); + registry.fill(HIST("rap1_mult3"), trackDG); + } + if (gapSide == 2) { + registry.fill(HIST("event_rap_gap"), 9); + registry.fill(HIST("rap2_mult3"), trackDG); + } + } + } + } + + if (rapidityGap) { + if (trackgapC > 0 && trackgapA == 0 && trackextra == 0) { + for (const auto& [t0, t1] : combinations(tracks, tracks)) { + if (!trackselector(t0, parameters) || !trackselector(t1, parameters)) + continue; + if (phi && selectionPIDKaon1(t0) && selectionPIDKaon1(t1)) { + // Apply kaon hypothesis and create pairs + v0.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassKaonCharged); + v1.SetXYZM(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassKaonCharged); + v01 = v0 + v1; + // Opposite sign pairs + if (t0.sign() != t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_kk_mass_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_kk_mass1_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_kk_mass2_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + if (t0.sign() == t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_kk_ls_mass_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_kk_ls_mass1_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_kk_ls_mass2_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + } + } + for (const auto& [t0, t1] : combinations(o2::soa::CombinationsFullIndexPolicy(tracks, tracks))) { + if (!trackselector(t0, parameters) || !trackselector(t1, parameters)) + continue; + if (t0.globalIndex() == t1.globalIndex()) + continue; + if (kstar && selectionPIDKaon1(t0) && selectionPIDPion1(t1)) { + // Apply kaon hypothesis and create pairs + v0.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassKaonCharged); + v1.SetXYZM(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassPionCharged); + v01 = v0 + v1; + // Opposite sign pairs + if (t0.sign() != t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_kp_mass_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_kp_mass1_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_kp_mass2_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + if (t0.sign() == t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_kp_ls_mass_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_kp_ls_mass1_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_kp_ls_mass2_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + } + } + } + + if (trackgapC == 0 && trackgapA > 0 && trackextra == 0) { + for (const auto& [t0, t1] : combinations(tracks, tracks)) { + if (!trackselector(t0, parameters) || !trackselector(t1, parameters)) + continue; + if (phi && selectionPIDKaon1(t0) && selectionPIDKaon1(t1)) { + // Apply kaon hypothesis and create pairs + v0.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassKaonCharged); + v1.SetXYZM(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassKaonCharged); + v01 = v0 + v1; + // Opposite sign pairs + if (t0.sign() != t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_kk_mass_rap1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_kk_mass1_rap1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_kk_mass2_rap1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + if (t0.sign() == t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_kk_ls_mass_rap1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_kk_ls_mass1_rap1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_kk_ls_mass2_rap1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + } + } + for (const auto& [t0, t1] : combinations(o2::soa::CombinationsFullIndexPolicy(tracks, tracks))) { + if (!trackselector(t0, parameters) || !trackselector(t1, parameters)) + continue; + if (t0.globalIndex() == t1.globalIndex()) + continue; + if (kstar && selectionPIDKaon1(t0) && selectionPIDPion1(t1)) { + // Apply kaon hypothesis and create pairs + v0.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassKaonCharged); + v1.SetXYZM(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassPionCharged); + v01 = v0 + v1; + // Opposite sign pairs + if (t0.sign() != t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_kp_mass_rap1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_kp_mass1_rap1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_kp_mass2_rap1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + if (t0.sign() == t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_kp_ls_mass_rap1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_kp_ls_mass1_rap1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_kp_ls_mass2_rap1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + } + } + } + if (trackDG > 0 && trackextraDG == 0) { + for (const auto& [t0, t1] : combinations(tracks, tracks)) { + if (!trackselector(t0, parameters) || !trackselector(t1, parameters)) + continue; + if (phi && selectionPIDKaon1(t0) && selectionPIDKaon1(t1)) { + // Apply kaon hypothesis and create pairs + v0.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassKaonCharged); + v1.SetXYZM(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassKaonCharged); + v01 = v0 + v1; + // Opposite sign pairs + if (t0.sign() != t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_kk_mass_rap2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_kk_mass1_rap2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_kk_mass2_rap2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + if (t0.sign() == t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_kk_ls_mass_rap2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_kk_ls_mass1_rap2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_kk_ls_mass2_rap2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + } + } + for (const auto& [t0, t1] : combinations(o2::soa::CombinationsFullIndexPolicy(tracks, tracks))) { + if (!trackselector(t0, parameters) || !trackselector(t1, parameters)) + continue; + if (t0.globalIndex() == t1.globalIndex()) + continue; + if (kstar && selectionPIDKaon1(t0) && selectionPIDPion1(t1)) { + // Apply kaon hypothesis and create pairs + v0.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassKaonCharged); + v1.SetXYZM(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassPionCharged); + v01 = v0 + v1; + // Opposite sign pairs + if (t0.sign() != t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_kp_mass_rap2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_kp_mass1_rap2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_kp_mass2_rap2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + if (t0.sign() == t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_kp_ls_mass_rap2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_kp_ls_mass1_rap2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_kp_ls_mass2_rap2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + } + } + } + } + + for (const auto& [t0, t1] : combinations(tracks, tracks)) { + if (!trackselector(t0, parameters) || !trackselector(t1, parameters)) + continue; + + if (phi && selectionPIDKaon1(t0) && selectionPIDKaon1(t1)) { + // Apply kaon hypothesis and create pairs + v0.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassKaonCharged); + v1.SetXYZM(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassKaonCharged); + v01 = v0 + v1; + // Opposite sign pairs + if (t0.sign() != t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_KK_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_KK_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_KK_pT_2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + // samesignpair + if (t0.sign() == t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_KK_ls_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_KK_ls_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_KK_ls_pT_2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + + if (fillRotation) { + for (int nrotbkg = 0; nrotbkg < nBkgRotations; nrotbkg++) { + auto anglestart = confMinRot; + auto angleend = confMaxRot; + auto anglestep = (angleend - anglestart) / (1.0 * (nBkgRotations - 1)); + auto rotangle = anglestart + nrotbkg * anglestep; + registry.fill(HIST("hRotation"), rotangle); + + auto rotkaonPx = t0.px() * std::cos(rotangle) - t0.py() * std::sin(rotangle); + auto rotkaonPy = t0.px() * std::sin(rotangle) + t0.py() * std::cos(rotangle); + + v0.SetXYZM(rotkaonPx, rotkaonPy, t0.pz(), o2::constants::physics::MassKaonCharged); + v1.SetXYZM(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassKaonCharged); + v01 = v0 + v1; + if (t0.sign() != t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_KK_rot_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_KK_rot_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_KK_rot_pT_2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + } + } + } + } + for (const auto& [t0, t1] : combinations(o2::soa::CombinationsFullIndexPolicy(tracks, tracks))) { + if (!trackselector(t0, parameters) || !trackselector(t1, parameters)) + continue; + if (t0.globalIndex() == t1.globalIndex()) + continue; + if (rho && selectionPIDProton(t0, useTof, nsigmaTpcCut, nsigmaTofCut) && selectionPIDPion1(t1)) { + v0.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassProton); + v1.SetXYZM(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassPionCharged); + v01 = v0 + v1; + // Opposite sign pairs + if (t0.sign() != t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_pp_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_pp_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_pp_pT_2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } // same sign pair + if (t0.sign() == t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_pp_ls_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_pp_ls_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_pp_ls_pT_2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + } + if (kstar && selectionPIDKaon1(t0) && selectionPIDPion1(t1)) { + if (kaoncut && t0.tpcNSigmaPi() < pionNsigmaCut) + continue; + v0.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassKaonCharged); + v1.SetXYZM(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassPionCharged); + v01 = v0 + v1; + // Opposite sign pairs + if (t0.sign() != t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_pk_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_pk_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_pk_pT_2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } // same sign pair + if (t0.sign() == t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_pk_ls_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_pk_ls_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_pk_ls_pT_2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + if (fillRotation) { + for (int nrotbkg = 0; nrotbkg < nBkgRotations; nrotbkg++) { + auto anglestart = confMinRot; + auto angleend = confMaxRot; + auto anglestep = (angleend - anglestart) / (1.0 * (nBkgRotations - 1)); + auto rotangle = anglestart + nrotbkg * anglestep; + registry.fill(HIST("hRotation"), rotangle); + + auto rotkaonPx = t0.px() * std::cos(rotangle) - t0.py() * std::sin(rotangle); + auto rotkaonPy = t0.px() * std::sin(rotangle) + t0.py() * std::cos(rotangle); + + v0.SetXYZM(rotkaonPx, rotkaonPy, t0.pz(), o2::constants::physics::MassKaonCharged); + v1.SetXYZM(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassPionCharged); + v01 = v0 + v1; + if (t0.sign() != t1.sign()) { + if (gapSide == 0) { + registry.fill(HIST("os_pk_rot_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 1) { + registry.fill(HIST("os_pk_rot_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == 2) { + registry.fill(HIST("os_pk_rot_pT_2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + } + } + } + } + if (fourpion) { + if (gapSide == 2 && mult2 == 4) { + TLorentzVector pair1, pair2, pair3, pair4; + if (onlyPionTracksp.size() == 2 && onlyPionTracksn.size() == 2) { + TLorentzVector k1 = onlyPionTracksp.at(0); + TLorentzVector k2 = onlyPionTracksp.at(1); + TLorentzVector k3 = onlyPionTracksn.at(0); + TLorentzVector k4 = onlyPionTracksn.at(1); + phiv = k1 + k2 + k3 + k4; + pair1 = k1 + k3; + pair2 = k2 + k4; + pair3 = k1 + k4; + pair4 = k2 + k3; + registry.fill(HIST("os_pppp_pT_2"), phiv.M(), phiv.Pt(), phiv.Rapidity()); + registry.fill(HIST("os_pp_vs_pp_mass"), pair1.M(), pair2.M()); + registry.fill(HIST("os_pp_vs_pp_pt"), pair1.Pt(), pair2.Pt()); + auto costhetaPair = cosThetaCollinsSoperFrame(pair1, pair2, phiv); + auto phiPair = 1. * o2::constants::math::PI + phiCollinsSoperFrame(pair1, pair2, phiv); + registry.fill(HIST("phi_dis"), phiPair); + registry.fill(HIST("costheta_dis"), costhetaPair); + registry.fill(HIST("costheta_vs_phi"), costhetaPair, phiPair); + registry.fill(HIST("os_pp_vs_pp_mass1"), pair3.M(), pair4.M()); + registry.fill(HIST("os_pp_vs_pp_pt1"), pair3.Pt(), pair4.Pt()); + auto costhetaPair1 = cosThetaCollinsSoperFrame(pair3, pair4, phiv); + auto phiPair1 = 1. * o2::constants::math::PI + phiCollinsSoperFrame(pair3, pair4, phiv); + registry.fill(HIST("phi_dis1"), phiPair1); + registry.fill(HIST("costheta_dis1"), costhetaPair1); + registry.fill(HIST("costheta_vs_phi1"), costhetaPair1, phiPair1); + } + if (onlyPionTracksp.size() != 2 && onlyPionTracksn.size() != 2) { + if (onlyPionTracksp.size() + onlyPionTracksn.size() != 4) + return; + TLorentzVector l1 = onlyPionTrackspm.at(0); + TLorentzVector l2 = onlyPionTrackspm.at(1); + TLorentzVector l3 = onlyPionTrackspm.at(2); + TLorentzVector l4 = onlyPionTrackspm.at(3); + phiv1 = l1 + l2 + l3 + l4; + registry.fill(HIST("os_pppp_pT_2_ls"), phiv1.M(), phiv1.Pt(), phiv1.Rapidity()); + } + } + } + } + PROCESS_SWITCH(SginclusivePhiKstarSD, process, "Process unlike event", false); + + using UDCollisionsFull1 = soa::Join; // + SliceCache cache; + Partition posTracks = aod::udtrack::sign > 0; + Partition negTracks = aod::udtrack::sign < 0; + + ConfigurableAxis axisVertex{"axisVertex", {10, -10, 10}, "vertex axis for bin"}; + ConfigurableAxis axisMultiplicityClass{"axisMultiplicityClass", {10, 0, 100}, "multiplicity percentile for bin"}; + using BinningTypeVertexContributor = ColumnBinningPolicy; + void mixprocess(UDCollisionsFull1 const& collisions, UDtracksfull const& /*track*/) + { + TLorentzVector v0; + TLorentzVector v1; + TLorentzVector v01; + float fitCut[5] = {fv0Cut, ft0aCut, ft0cCut, fddaCut, fddcCut}; + std::vector parameters = {pvCut, dcazCut, dcaxyCut, tpcChi2Cut, tpcNClsFindableCut, itsChi2Cut, etaCut, ptCut}; + BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicityClass}, true}; + for (auto const& [collision1, collision2] : o2::soa::selfCombinations(binningOnPositions, cfgNoMixedEvents, -1, collisions, collisions)) { + int truegapSide1 = sgSelector.trueGap(collision1, fitCut[0], fitCut[1], fitCut[2], zdcCut); + int truegapSide2 = sgSelector.trueGap(collision2, fitCut[0], fitCut[1], fitCut[2], zdcCut); + if (truegapSide1 != truegapSide2) + continue; + if (truegapSide1 == -1) + continue; + if (std::abs(collision1.posZ()) > vzCut || std::abs(collision2.posZ()) > vzCut) + continue; + if (std::abs(collision1.occupancyInTime()) > occCut || std::abs(collision2.occupancyInTime()) > occCut) + continue; + auto posThisColl = posTracks->sliceByCached(aod::udtrack::udCollisionId, collision1.globalIndex(), cache); + auto negThisColl = negTracks->sliceByCached(aod::udtrack::udCollisionId, collision2.globalIndex(), cache); + // for (auto& [track1, track2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(posThisColl, negThisColl))) { + for (const auto& [track1, track2] : o2::soa::combinations(posThisColl, negThisColl)) { + if (!trackselector(track1, parameters) || !trackselector(track2, parameters)) + continue; + if (phi && selectionPIDKaon1(track1) && selectionPIDKaon1(track2)) { + v0.SetXYZM(track1.px(), track1.py(), track1.pz(), o2::constants::physics::MassKaonCharged); + v1.SetXYZM(track2.px(), track2.py(), track2.pz(), o2::constants::physics::MassKaonCharged); + v01 = v0 + v1; + // Opposite sign pairs + if (track1.sign() != track2.sign()) { + if (truegapSide1 == 0) { + registry.fill(HIST("os_KK_mix_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (truegapSide1 == 1) { + registry.fill(HIST("os_KK_mix_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (truegapSide1 == 2) { + registry.fill(HIST("os_KK_mix_pT_2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + } + } + for (const auto& [track1, track2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(posThisColl, negThisColl))) { + if (!trackselector(track1, parameters) || !trackselector(track2, parameters)) + continue; + if (track1.globalIndex() == track2.globalIndex()) + continue; + if (kstar && selectionPIDKaon1(track1) && selectionPIDPion1(track2)) { + v0.SetXYZM(track1.px(), track1.py(), track1.pz(), o2::constants::physics::MassKaonCharged); + v1.SetXYZM(track2.px(), track2.py(), track2.pz(), o2::constants::physics::MassPionCharged); + v01 = v0 + v1; + // Opposite sign pairs + if (track1.sign() != track2.sign()) { + if (truegapSide1 == 0) { + registry.fill(HIST("os_pk_mix_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (truegapSide1 == 1) { + registry.fill(HIST("os_pk_mix_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (truegapSide1 == 2) { + registry.fill(HIST("os_pk_mix_pT_2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } + } + } + } + } + PROCESS_SWITCH(SginclusivePhiKstarSD, mixprocess, "Process Mixed event", false); + + // define abbreviations , aod::UDCollisions_001, + using CCs = soa::Join; + using CC = CCs::iterator; + // using TCs = soa::Join; + using TCs = soa::Join; + using TC = TCs::iterator; + + PresliceUnsorted partPerMcCollision = aod::udmcparticle::udMcCollisionId; + PresliceUnsorted colPerMcCollision = aod::udcollision::udMcCollisionId; + PresliceUnsorted trackPerMcParticle = aod::udmctracklabel::udMcParticleId; + + void processMCTruth(aod::UDMcCollisions const& mccollisions, CCs const& collisions, aod::UDMcParticles const& McParts, TCs const& tracks) + { + // number of McCollisions in DF + TLorentzVector v0; + TLorentzVector v1; + TLorentzVector v01; + TLorentzVector vkstar; + TLorentzVector vphi; + for (const auto& mccollision : mccollisions) { + if (mccollision.generatorsID() != generatedId) + continue; + registry.get(HIST("MC/Stat"))->Fill(0., 1.); + // get reconstructed collision which belongs to mccollision + auto colSlice = collisions.sliceBy(colPerMcCollision, mccollision.globalIndex()); + registry.get(HIST("MC/recCols"))->Fill(colSlice.size(), 1.); + if (reconstruction && colSlice.size() < 1) + continue; + // get McParticles which belong to mccollision + auto partSlice = McParts.sliceBy(partPerMcCollision, mccollision.globalIndex()); + registry.get(HIST("MC/nParts"))->Fill(partSlice.size(), 1.); + for (const auto& [tr1, tr2] : combinations(partSlice, partSlice)) { + if ((tr1.pdgCode() == kKPlus && tr2.pdgCode() == kPiMinus) || (tr1.pdgCode() == kKMinus && tr2.pdgCode() == kPiPlus) || (tr1.pdgCode() == kPiPlus && tr2.pdgCode() == kKMinus) || (tr1.pdgCode() == kPiMinus && tr2.pdgCode() == kKPlus)) { + if (std::abs(tr1.pdgCode()) == kKPlus) { + v0.SetXYZM(tr1.px(), tr1.py(), tr1.pz(), o2::constants::physics::MassKaonCharged); + v1.SetXYZM(tr2.px(), tr2.py(), tr2.pz(), o2::constants::physics::MassPionCharged); + } else { + v0.SetXYZM(tr1.px(), tr1.py(), tr1.pz(), o2::constants::physics::MassPionCharged); + v1.SetXYZM(tr2.px(), tr2.py(), tr2.pz(), o2::constants::physics::MassKaonCharged); + } + if (!tr1.isPhysicalPrimary() || !tr2.isPhysicalPrimary()) + continue; + v01 = v0 + v1; + if (tr1.globalIndex() + 1 != tr2.globalIndex()) { + registry.get(HIST("MC/genM_1_k"))->Fill(v01.M(), 1.); + } + if (std::abs(tr1.globalIndex() - tr2.globalIndex()) != 1) + continue; + bool flag = false; + bool flag1 = false; + if (tr1.has_mothers() && tr2.has_mothers()) { + for (const auto& mother : tr1.mothers_as()) { + if (std::abs(mother.pdgCode()) == o2::constants::physics::Pdg::kK0Star892) { + vkstar.SetXYZM(mother.px(), mother.py(), mother.pz(), o2::constants::physics::MassK0Star892); + registry.get(HIST("MC/accMPtRap_kstar_G"))->Fill(vkstar.M(), vkstar.Pt(), vkstar.Rapidity(), 1.); + flag = true; + } + } + for (const auto& mother1 : tr2.mothers_as()) { + if (std::abs(mother1.pdgCode()) == o2::constants::physics::Pdg::kK0Star892) { + flag1 = true; + } + } + } + if (flag && flag1) { + registry.get(HIST("MC/genMPt_k"))->Fill(v01.M(), v01.Pt(), 1.); + } + registry.get(HIST("MC/genRap_k"))->Fill(v01.Rapidity(), 1.); + registry.get(HIST("MC/genM_k"))->Fill(v01.M(), 1.); + registry.get(HIST("MC/accRap_k"))->Fill(v01.Rapidity(), 1.); + registry.get(HIST("MC/accMPt_k"))->Fill(v01.M(), v01.Pt(), 1.); + registry.get(HIST("MC/accM_k"))->Fill(v01.M(), 1.); + registry.get(HIST("MC/accMPtRap_k"))->Fill(v01.M(), v01.Pt(), v01.Rapidity(), 1.); + } + + if (std::abs(tr1.pdgCode()) != kKPlus || std::abs(tr2.pdgCode()) != kKPlus) + continue; + v0.SetXYZM(tr1.px(), tr1.py(), tr1.pz(), o2::constants::physics::MassKaonCharged); + v1.SetXYZM(tr2.px(), tr2.py(), tr2.pz(), o2::constants::physics::MassKaonCharged); + if (tr1.pdgCode() == tr2.pdgCode()) + continue; + v01 = v0 + v1; + if (!tr1.isPhysicalPrimary() || !tr2.isPhysicalPrimary()) + continue; + if (tr1.globalIndex() + 1 != tr2.globalIndex()) { + registry.get(HIST("MC/genM_1"))->Fill(v01.M(), 1.); + } + if (std::abs(tr1.globalIndex() - tr2.globalIndex()) != 1) + continue; + bool flag = false; + bool flag1 = false; + if (tr1.has_mothers() && tr2.has_mothers()) { + for (const auto& mother : tr1.mothers_as()) { + if (std::abs(mother.pdgCode()) == o2::constants::physics::Pdg::kPhi) { + vphi.SetXYZM(mother.px(), mother.py(), mother.pz(), o2::constants::physics::MassPhi); + registry.get(HIST("MC/accMPtRap_phi_G"))->Fill(vphi.M(), vphi.Pt(), vphi.Rapidity(), 1.); + flag = true; + } + } + for (const auto& mother1 : tr2.mothers_as()) { + if (std::abs(mother1.pdgCode()) == o2::constants::physics::Pdg::kPhi) { + flag1 = true; + } + } + } + if (flag && flag1) { + registry.get(HIST("MC/genMPt"))->Fill(v01.M(), v01.Pt(), 1.); + } + // registry.get(HIST("MC/genRap"))->Fill(v01.Rapidity(), 1.); + // registry.get(HIST("MC/genM"))->Fill(v01.M(), 1.); + registry.get(HIST("MC/accRap"))->Fill(v01.Rapidity(), 1.); + registry.get(HIST("MC/accMPt"))->Fill(v01.M(), v01.Pt(), 1.); + registry.get(HIST("MC/accM"))->Fill(v01.M(), 1.); + registry.get(HIST("MC/accMPtRap"))->Fill(v01.M(), v01.Pt(), v01.Rapidity(), 1.); + } + // compute the difference between generated and reconstructed particle momentum + for (const auto& McPart : partSlice) { + auto trackSlice = tracks.sliceBy(trackPerMcParticle, McPart.globalIndex()); + registry.get(HIST("MC/nRecTracks"))->Fill(trackSlice.size(), 1.); + // compute momentum difference between MCTruth and Reconstruction + if (trackSlice.size() > 0) { + for (const auto& track : trackSlice) { + // std::cout<(HIST("MC/pDiff"))->Fill(pDiff, track.isPVContributor(), 1.); + } + } else { + registry.get(HIST("MC/pDiff"))->Fill(-5.9, -1, 1.); + } + } + } + } + PROCESS_SWITCH(SginclusivePhiKstarSD, processMCTruth, "Process MC truth", true); + // ............................................................................................................... + void processReco(CC const& collision, TCs const& tracks, aod::UDMcCollisions const& /*mccollisions*/, aod::UDMcParticles const& /*McParts*/) + { + if (!collision.has_udMcCollision()) + return; + auto mccoll = collision.udMcCollision(); + if (mccoll.generatorsID() != generatedId) + return; + float fitCut[5] = {fv0Cut, ft0aCut, ft0cCut, fddaCut, fddcCut}; + std::vector parameters = {pvCut, dcazCut, dcaxyCut, tpcChi2Cut, tpcNClsFindableCut, itsChi2Cut, etaCut, ptCut}; + int truegapSide = sgSelector.trueGap(collision, fitCut[0], fitCut[1], fitCut[2], zdcCut); + registry.get(HIST("Reco/Stat"))->Fill(4.0, 1.); + Partition pvContributors = aod::udtrack::isPVContributor == true; + pvContributors.bindTable(tracks); + if (std::abs(collision.posZ()) > vzCut) + return; + if (std::abs(collision.occupancyInTime()) > occCut) + return; + registry.get(HIST("Reco/Stat"))->Fill(truegapSide, 1.); + if (truegapSide != gapsideMC) + return; + registry.get(HIST("Reco/nPVContributors"))->Fill(pvContributors.size(), 1.); + TLorentzVector vphi; + TLorentzVector vkstar; + TLorentzVector v0; + TLorentzVector vr0; + TLorentzVector vr1; + TLorentzVector vr01; + TLorentzVector vr0g; + TLorentzVector vr1g; + TLorentzVector vr01g; + int t1 = 0; + if (truegapSide == 0) { + registry.fill(HIST("V0A_0_mc"), collision.totalFV0AmplitudeA()); + registry.fill(HIST("FT0A_0_mc"), collision.totalFT0AmplitudeA()); + registry.fill(HIST("FT0C_0_mc"), collision.totalFT0AmplitudeC()); + registry.fill(HIST("ZDC_A_0_mc"), collision.energyCommonZNA()); + registry.fill(HIST("ZDC_C_0_mc"), collision.energyCommonZNC()); + } + if (truegapSide == 1) { + registry.fill(HIST("V0A_1_mc"), collision.totalFV0AmplitudeA()); + registry.fill(HIST("FT0A_1_mc"), collision.totalFT0AmplitudeA()); + registry.fill(HIST("FT0C_1_mc"), collision.totalFT0AmplitudeC()); + registry.fill(HIST("ZDC_A_1_mc"), collision.energyCommonZNA()); + registry.fill(HIST("ZDC_C_1_mc"), collision.energyCommonZNC()); + } + for (const auto& tr1 : tracks) { + if (!tr1.has_udMcParticle()) + continue; + auto mcPart1 = tr1.udMcParticle(); + registry.get(HIST("Reco/tr_dcaz_1"))->Fill(tr1.dcaZ(), 1.); + registry.get(HIST("Reco/tr_dcaxy_1"))->Fill(tr1.dcaXY(), 1.); + registry.get(HIST("Reco/tr_chi2ncl_1"))->Fill(tr1.tpcChi2NCl(), 1.); + registry.get(HIST("Reco/tr_tpcnclfind_1"))->Fill(tr1.tpcNClsFindable(), 1.); + registry.get(HIST("Reco/tr_itsChi2NCl_1"))->Fill(tr1.itsChi2NCl(), 1.); + + if (!trackselector(tr1, parameters)) + continue; + + registry.get(HIST("Reco/tr_dcaz_2"))->Fill(tr1.dcaZ(), 1.); + registry.get(HIST("Reco/tr_dcaxy_2"))->Fill(tr1.dcaXY(), 1.); + registry.get(HIST("Reco/tr_chi2ncl_2"))->Fill(tr1.tpcChi2NCl(), 1.); + registry.get(HIST("Reco/tr_tpcnclfind_2"))->Fill(tr1.tpcNClsFindable(), 1.); + registry.get(HIST("Reco/tr_itsChi2NCl_2"))->Fill(tr1.itsChi2NCl(), 1.); + v0.SetXYZM(tr1.px(), tr1.py(), tr1.pz(), o2::constants::physics::MassPionCharged); + + registry.fill(HIST("tpc_dedx_mc"), v0.P(), tr1.tpcSignal()); + registry.fill(HIST("tof_beta_mc"), v0.P(), tr1.beta()); + registry.fill(HIST("tof_nsigma_kaon_f_mc"), v0.Pt(), tr1.tofNSigmaKa()); + registry.fill(HIST("tof_nsigma_pion_f_mc"), v0.Pt(), tr1.tofNSigmaPi()); + registry.fill(HIST("tpc_nsigma_kaon_f_mc"), v0.Pt(), tr1.tpcNSigmaKa()); + registry.fill(HIST("tpc_nsigma_pion_f_mc"), v0.Pt(), tr1.tpcNSigmaPi()); + if (selectionPIDKaon1(tr1)) { + registry.fill(HIST("tpc_nsigma_kaon_mc"), v0.Pt(), tr1.tpcNSigmaKa()); + registry.fill(HIST("tof_nsigma_kaon_mc"), v0.Pt(), tr1.tofNSigmaKa()); + registry.fill(HIST("tpc_tof_nsigma_kaon_mc"), tr1.tpcNSigmaKa(), tr1.tofNSigmaKa()); + } + if (selectionPIDPion1(tr1)) { + registry.fill(HIST("tpc_nsigma_pion_mc"), v0.Pt(), tr1.tpcNSigmaPi()); + registry.fill(HIST("tof_nsigma_pion_mc"), v0.Pt(), tr1.tofNSigmaPi()); + registry.fill(HIST("tpc_tof_nsigma_pion_mc"), tr1.tpcNSigmaPi(), tr1.tofNSigmaPi()); + } + + t1++; + vr0.SetXYZM(tr1.px(), tr1.py(), tr1.pz(), o2::constants::physics::MassKaonCharged); + registry.get(HIST("Reco/trpt"))->Fill(vr0.Pt(), 1.); + registry.get(HIST("Reco/treta_k"))->Fill(vr0.Eta(), 1.); + if (!selectionPIDKaon1(tr1)) + continue; + registry.get(HIST("Reco/trpt_k"))->Fill(vr0.Pt(), 1.); + int t2 = 0; + for (const auto& tr2 : tracks) { + if (!tr2.has_udMcParticle()) + continue; + if (!trackselector(tr2, parameters)) + continue; + t2++; + if (t2 > t1) { + if (!selectionPIDKaon1(tr2)) + continue; + vr1.SetXYZM(tr2.px(), tr2.py(), tr2.pz(), o2::constants::physics::MassKaonCharged); + auto mcPart2 = tr2.udMcParticle(); + if (std::abs(mcPart2.globalIndex() - mcPart1.globalIndex()) != 1) + continue; + if (std::abs(mcPart1.pdgCode()) != kKPlus || std::abs(mcPart2.pdgCode()) != kKPlus) + continue; + if (mcPart1.pdgCode() == mcPart2.pdgCode()) + continue; + if (!mcPart1.isPhysicalPrimary() || !mcPart2.isPhysicalPrimary()) + continue; + bool flag = false; + bool flag1 = false; + if (mcPart1.has_mothers() && mcPart2.has_mothers()) { + for (const auto& mother : mcPart1.mothers_as()) { + if (std::abs(mother.pdgCode()) == o2::constants::physics::Pdg::kPhi) { + vphi.SetXYZM(mother.px(), mother.py(), mother.pz(), o2::constants::physics::MassPhi); + registry.get(HIST("MC/accMPtRap_phi_T"))->Fill(vphi.M(), vphi.Pt(), vphi.Rapidity(), 1.); + flag = true; + } + } + for (const auto& mother1 : mcPart1.mothers_as()) { + if (std::abs(mother1.pdgCode()) == o2::constants::physics::Pdg::kPhi) { + flag1 = true; + } + } + } + vr0g.SetXYZM(mcPart1.px(), mcPart1.py(), mcPart1.pz(), o2::constants::physics::MassKaonCharged); + vr1g.SetXYZM(mcPart2.px(), mcPart2.py(), mcPart2.pz(), o2::constants::physics::MassKaonCharged); + vr01g = vr0g + vr1g; + vr01 = vr0 + vr1; + + if (flag && flag1) { + registry.get(HIST("Reco/selMPt"))->Fill(vr01.M(), vr01.Pt(), 1.); + } + registry.get(HIST("Reco/selRap"))->Fill(vr01.Rapidity(), 1.); + registry.get(HIST("Reco/selMPtRap"))->Fill(vr01.M(), vr01.Pt(), vr01.Rapidity(), 1.); + registry.get(HIST("Reco/selPt"))->Fill(vr01.Pt(), 1.); + registry.get(HIST("Reco/selM"))->Fill(vr01.M(), 1.); + registry.get(HIST("Reco/selMPtRap_gen"))->Fill(vr01g.M(), vr01g.Pt(), vr01g.Rapidity(), 1.); + } + } + } + // KStar + for (const auto& [tr1, tr2] : combinations(o2::soa::CombinationsFullIndexPolicy(tracks, tracks))) { + if (!tr1.has_udMcParticle() || !tr2.has_udMcParticle()) + continue; + if (!selectionPIDPion1(tr1) || !selectionPIDKaon1(tr2)) + continue; + // if (tr1.index() == tr2.index()) + // continue; // We need to run (0,1), (1,0) pairs as well. but same id pairs are not needed. + auto mcPart1 = tr1.udMcParticle(); + auto mcPart2 = tr2.udMcParticle(); + if (std::abs(mcPart1.pdgCode()) != kPiPlus || std::abs(mcPart2.pdgCode()) != kKPlus) + continue; + if (!mcPart1.isPhysicalPrimary() || !mcPart2.isPhysicalPrimary()) + continue; + if (std::abs(mcPart2.globalIndex() - mcPart1.globalIndex()) != 1) + continue; + + if (tr1.sign() * tr2.sign() > 0) + continue; + + vr0.SetXYZM(tr1.px(), tr1.py(), tr1.pz(), o2::constants::physics::MassPionCharged); + vr1.SetXYZM(tr2.px(), tr2.py(), tr2.pz(), o2::constants::physics::MassKaonCharged); + vr0g.SetXYZM(mcPart1.px(), mcPart1.py(), mcPart1.pz(), o2::constants::physics::MassPionCharged); + vr1g.SetXYZM(mcPart2.px(), mcPart2.py(), mcPart2.pz(), o2::constants::physics::MassKaonCharged); + vr01g = vr0g + vr1g; + vr01 = vr0 + vr1; + if (!trackselector(tr1, parameters) || !trackselector(tr2, parameters)) { + registry.get(HIST("Reco/selM_k"))->Fill(vr01.M(), 1.); + } + if (trackselector(tr1, parameters) && trackselector(tr2, parameters)) { + bool flag = false; + bool flag1 = false; + if (mcPart1.has_mothers() && mcPart2.has_mothers()) { + for (const auto& mother : mcPart1.mothers_as()) { + if (std::abs(mother.pdgCode()) == o2::constants::physics::Pdg::kK0Star892) { + vkstar.SetXYZM(mother.px(), mother.py(), mother.pz(), o2::constants::physics::MassK0Star892); + registry.get(HIST("MC/accMPtRap_kstar_T"))->Fill(vkstar.M(), vkstar.Pt(), vkstar.Rapidity(), 1.); + flag = true; + } + } + for (const auto& mother1 : mcPart2.mothers_as()) { + if (std::abs(mother1.pdgCode()) == o2::constants::physics::Pdg::kK0Star892) { + flag1 = true; + } + } + } + if (flag && flag1) { + registry.get(HIST("Reco/selMPt_k"))->Fill(vr01.M(), vr01.Pt(), 1.); + } + registry.get(HIST("Reco/selM_k_K"))->Fill(vr01.M(), 1.); + registry.get(HIST("Reco/selRap_k"))->Fill(vr01.Rapidity(), 1.); + registry.get(HIST("Reco/selMPtRap_k"))->Fill(vr01.M(), vr01.Pt(), vr01.Rapidity(), 1.); + registry.get(HIST("Reco/selPt_k"))->Fill(vr01.Pt(), 1.); + registry.get(HIST("Reco/selMPtRap_k_gen"))->Fill(vr01g.M(), vr01g.Pt(), vr01g.Rapidity(), 1.); + } + } + registry.get(HIST("Reco/nTracks"))->Fill(t1, 1.); + // now access the McTruth information + // get McCollision belonging to collision + if (collision.has_udMcCollision()) { + // auto mccollision = collision.udMcCollision(); + registry.get(HIST("Reco/Stat"))->Fill(3., 1.); + } + // compute the difference between generated and reconstructed momentum + for (const auto& track : tracks) { + // is there an associated McParticle? + if (track.has_udMcParticle()) { + auto pTrack = std::sqrt(track.px() * track.px() + track.py() * track.py() + track.pz() * track.pz()); + auto mcPart = track.udMcParticle(); + auto pPart = std::sqrt(mcPart.px() * mcPart.px() + mcPart.py() * mcPart.py() + mcPart.pz() * mcPart.pz()); + auto pDiff = pTrack - pPart; + registry.get(HIST("Reco/pDiff"))->Fill(pDiff, track.isPVContributor(), 1.); + } else { + registry.get(HIST("Reco/pDiff"))->Fill(-5.9, -1, 1.); + } + } + } + PROCESS_SWITCH(SginclusivePhiKstarSD, processReco, "Process reconstructed data", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/testMCstdTabsRL.cxx b/PWGUD/Tasks/testMCstdTabsRL.cxx new file mode 100644 index 00000000000..6ac26211e03 --- /dev/null +++ b/PWGUD/Tasks/testMCstdTabsRL.cxx @@ -0,0 +1,107 @@ +// 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 testMCstdTabsRL.cxx +/// \brief task to test the Monte Carlo UD production generatorIDs on hyperloop +/// +/// \author Roman Lavicka , Austrian Academy of Sciences & SMI +/// \since 12.02.2025 +// + +// C++ headers +#include +#include +#include +#include + +// O2 headers +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +// O2Physics headers +#include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" + +// ROOT headers +#include "TLorentzVector.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +struct TestMCstdTabsRL { + + // Global varialbes + Service pdg; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + struct : ConfigurableGroup { + ConfigurableAxis zzAxisNtracks{"zzAxisNtracks", {30, -0.5, 29.5}, "Number of tracks in collision"}; + ConfigurableAxis zzAxisNparticles{"zzAxisNparticles", {60, -0.5, 59.5}, "Number of particles in collision"}; + ConfigurableAxis zzAxisNprocesses{"zzAxisNprocesses", {50, -0.5, 49.5}, "Number of processes"}; + ConfigurableAxis zzAxisInvMassWide{"zzAxisInvMassWide", {1000, 0., 10.}, "Invariant mass (GeV/c^{2}), wider range"}; + ConfigurableAxis zzAxisPt{"zzAxisPt", {400, 0., 2.}, "Transversal momentum (GeV/c)"}; + ConfigurableAxis zzAxisRap{"zzAxisRap", {50, -1.2, 1.2}, "Rapidity (a.u.)"}; + } confAxis; + + // init + void init(InitContext&) + { + histos.add("Events/Truth/hGenIDvsCountCollisions", ";Process ID", HistType::kTH2D, {confAxis.zzAxisNprocesses, {1, 0.5, 1.5}}); + histos.add("Events/Truth/hGenIDvsPDGcodesAll", ";Process ID ;PDG codes of all particles (-)", HistType::kTH2D, {confAxis.zzAxisNprocesses, {2001, -1000, 1000}}); + histos.add("Events/Truth/hGenIDvsPDGcodesNoMother", ";Process ID ;PDG codes of particles without mother (-)", HistType::kTH2D, {confAxis.zzAxisNprocesses, {2001, -1000, 1000}}); + histos.add("Events/Truth/hGenIDvsPDGcodesDaughters", ";Process ID ;PDG codes of daughters of particles without mother (-)", HistType::kTH2D, {confAxis.zzAxisNprocesses, {2001, -1000, 1000}}); + histos.add("Events/Truth/hGenIDvsNparticles", ";Process ID ;Number of particles in a collision (-)", HistType::kTH2D, {confAxis.zzAxisNprocesses, confAxis.zzAxisNparticles}); + histos.add("Events/Truth/hGenIDvsNdaughters", ";Process ID ;Number of daughters of no-mother particle in a collision (-)", HistType::kTH2D, {confAxis.zzAxisNprocesses, confAxis.zzAxisNparticles}); + histos.add("Events/Truth/hGenIDvsMotherMass", ";Process ID ;Mother invariant mass (GeV/c^{2})", HistType::kTH2D, {confAxis.zzAxisNprocesses, confAxis.zzAxisInvMassWide}); + histos.add("Events/Truth/hGenIDvsMotherPt", ";Process ID ;Mother p_{T} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisNprocesses, confAxis.zzAxisPt}); + histos.add("Events/Truth/hGenIDvsMotherRap", ";Process ID ;Mother rapidity (-)", HistType::kTH2D, {confAxis.zzAxisNprocesses, confAxis.zzAxisRap}); + + } // end init + + void processMCgen(aod::McCollision const& collision, aod::McParticles const& particles) + { + + histos.get(HIST("Events/Truth/hGenIDvsCountCollisions"))->Fill(collision.generatorsID(), 1); + histos.get(HIST("Events/Truth/hGenIDvsNparticles"))->Fill(collision.generatorsID(), particles.size()); + + TLorentzVector mother; + for (const auto& particle : particles) { + histos.get(HIST("Events/Truth/hGenIDvsPDGcodesAll"))->Fill(collision.generatorsID(), particle.pdgCode()); + // if (!particle.isPhysicalPrimary()) continue; + if (particle.has_mothers()) + continue; + mother.SetPxPyPzE(particle.px(), particle.py(), particle.pz(), energy(pdg->Mass(particle.pdgCode()), particle.px(), particle.py(), particle.pz())); + histos.get(HIST("Events/Truth/hGenIDvsPDGcodesNoMother"))->Fill(collision.generatorsID(), particle.pdgCode()); + histos.get(HIST("Events/Truth/hGenIDvsMotherMass"))->Fill(collision.generatorsID(), mother.M()); + histos.get(HIST("Events/Truth/hGenIDvsMotherPt"))->Fill(collision.generatorsID(), particle.pt()); + histos.get(HIST("Events/Truth/hGenIDvsMotherRap"))->Fill(collision.generatorsID(), particle.y()); + const auto& daughters = particle.daughters_as(); + histos.get(HIST("Events/Truth/hGenIDvsNdaughters"))->Fill(collision.generatorsID(), daughters.size()); + for (const auto& daughter : daughters) { + histos.get(HIST("Events/Truth/hGenIDvsPDGcodesDaughters"))->Fill(collision.generatorsID(), daughter.pdgCode()); + } + } + + } // end processMCgenDG + + PROCESS_SWITCH(TestMCstdTabsRL, processMCgen, "Iterate Monte Carlo UD tables with truth data.", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/upcEventITSROFcounter.cxx b/PWGUD/Tasks/upcEventITSROFcounter.cxx new file mode 100644 index 00000000000..51241be5d69 --- /dev/null +++ b/PWGUD/Tasks/upcEventITSROFcounter.cxx @@ -0,0 +1,222 @@ +// 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 upcEventITSROFcounter.cxx +/// \brief Personal task to analyze tau events from UPC collisions +/// +/// \author Roman Lavicka , Austrian Academy of Sciences & SMI +/// \since 09.08.2024 + +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "CCDB/BasicCCDBManager.h" +#include "ReconstructionDataFormats/Vertex.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/DataModel/EventSelection.h" + +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/SGSelector.h" + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::dataformats; + +using BCsWithRun3Matchings = soa::Join; +using CCs = soa::Join; +using FullSGUDCollision = soa::Join::iterator; + +struct UpcEventITSROFcounter { + Service ccdb; + SGSelector sgSelector; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable nTracksForUPCevent{"nTracksForUPCevent", 16, {"Maximum of tracks defining a UPC collision"}}; + + Configurable useTrueGap{"useTrueGap", true, {"Calculate gapSide for a given FV0/FT0/ZDC thresholds"}}; + Configurable cutMyGapSideFV0{"cutMyGapSideFV0", -1, "FV0A threshold for SG selector"}; + Configurable cutMyGapSideFT0A{"cutMyGapSideFT0A", 150., "FT0A threshold for SG selector"}; + Configurable cutMyGapSideFT0C{"cutMyGapSideFT0C", 50., "FT0C threshold for SG selector"}; + Configurable cutMyGapSideZDC{"cutMyGapSideZDC", 10., "ZDC threshold for SG selector"}; + ConfigurableAxis axisRunNumbers{"axisRunNumbers", {1400, 544000.5, 545400.5}, "Range of run numbers"}; + + void init(InitContext&) + { + + histos.add("Events/hCountCollisionsExactMatching", ";;Number of collision (-)", HistType::kTH1D, {{11, -0.5, 10.5}}); + histos.add("Events/hCountUPCcollisionsExactMatching", ";;Number of UPC (mult < 17) collision (-)", HistType::kTH1D, {{11, -0.5, 10.5}}); + histos.add("Events/hCountCollisionsInROFborderMatching", ";;Number of collision (-)", HistType::kTH1D, {{11, -0.5, 10.5}}); + histos.add("Events/hCountUPCcollisionsInROFborderMatching", ";;Number of UPC (mult < 17) collision (-)", HistType::kTH1D, {{11, -0.5, 10.5}}); + + histos.add("Events/hPVcontribsVsCollisionsPerITSROFstd", "Collisions reconstructed with standard mode;Number of vertex contributors (-); Number of collisions in one ITSROF (-)", HistType::kTH2D, {{101, -0.5, 100.5}, {11, -0.5, 10.5}}); + histos.add("Events/hPVcontribsVsCollisionsPerITSROFupc", "Collisions reconstructed with upc mode;Number of vertex contributors (-); Number of collisions in one ITSROF (-)", HistType::kTH2D, {{101, -0.5, 100.5}, {11, -0.5, 10.5}}); + + histos.add("Runs/hStdModeCollDG", ";Run number;Number of events (-)", HistType::kTH1D, {axisRunNumbers}); + histos.add("Runs/hUpcModeCollDG", ";Run number;Number of events (-)", HistType::kTH1D, {axisRunNumbers}); + histos.add("Runs/hStdModeCollSG1", ";Run number;Number of events (-)", HistType::kTH1D, {axisRunNumbers}); + histos.add("Runs/hUpcModeCollSG1", ";Run number;Number of events (-)", HistType::kTH1D, {axisRunNumbers}); + histos.add("Runs/hStdModeCollSG0", ";Run number;Number of events (-)", HistType::kTH1D, {axisRunNumbers}); + histos.add("Runs/hUpcModeCollSG0", ";Run number;Number of events (-)", HistType::kTH1D, {axisRunNumbers}); + histos.add("Runs/hStdModeCollNG", ";Run number;Number of events (-)", HistType::kTH1D, {axisRunNumbers}); + histos.add("Runs/hUpcModeCollNG", ";Run number;Number of events (-)", HistType::kTH1D, {axisRunNumbers}); + + } // end init + + void processCounterPerITSROF(BCsWithRun3Matchings const& bcs, CCs const& collisions) + { + int nAllColls = 0; + int nUPCcolls = 0; + uint16_t previousBCinITSROF = 0; + std::vector> vecITSROFborders; + bool isFirst = true; + uint16_t firstBCglobalIndex = 0; + uint16_t previousBCglobalIndex = 0; + + // extract ITS time frame parameters + int64_t ts = bcs.iteratorAt(0).timestamp(); + auto alppar = ccdb->getForTimeStamp>("ITS/Config/AlpideParam", ts); + + for (const auto& bc : bcs) { + uint64_t globalBC = bc.globalBC(); + uint64_t globalIndex = bc.globalIndex(); + if (isFirst) { + firstBCglobalIndex = globalIndex; + isFirst = false; + } + uint16_t bcInITSROF = (globalBC + o2::constants::lhc::LHCMaxBunches - alppar->roFrameBiasInBC) % alppar->roFrameLengthInBC; + + if (bcInITSROF - previousBCinITSROF < 0) { + histos.get(HIST("Events/hCountCollisionsExactMatching"))->Fill(nAllColls); + histos.get(HIST("Events/hCountUPCcollisionsExactMatching"))->Fill(nUPCcolls); + nAllColls = 0; + nUPCcolls = 0; + vecITSROFborders.push_back(std::make_pair(firstBCglobalIndex, previousBCglobalIndex)); + firstBCglobalIndex = globalIndex; + } + previousBCinITSROF = bcInITSROF; + previousBCglobalIndex = globalIndex; + // next is based on exact matching of bc and collision + for (const auto& collision : collisions) { + if (collision.has_foundBC()) { + if (collision.foundBCId() == bc.globalIndex()) { + nAllColls++; + if (collision.numContrib() < nTracksForUPCevent + 1) { + nUPCcolls++; + } + } + } else if (collision.bcId() == bc.globalIndex()) { + nAllColls++; + if (collision.numContrib() < nTracksForUPCevent + 1) { + nUPCcolls++; + } + } + } // end loop over collisions + } // end loop over bcs + + int arrAllColls[1000] = {0}; + int arrUPCcolls[1000] = {0}; + + // next is based on matching of collision bc within ITSROF range in bcs + for (const auto& itsrofBorder : vecITSROFborders) { + int nAllCollsInROF = 0; + int nUpcCollsInROF = 0; + for (const auto& collision : collisions) { + if ((itsrofBorder.first < collision.bcId()) && (collision.bcId() < itsrofBorder.second)) { + nAllCollsInROF++; + if (collision.numContrib() < nTracksForUPCevent + 1) { + nUpcCollsInROF++; + } + } + } // end loop over collisions + arrAllColls[nAllCollsInROF]++; + arrUPCcolls[nUpcCollsInROF]++; + } // end loop over ITSROFs + + for (int ncol = 0; ncol < 12; ncol++) { + histos.get(HIST("Events/hCountCollisionsInROFborderMatching"))->Fill(ncol, arrAllColls[ncol]); + histos.get(HIST("Events/hCountUPCcollisionsInROFborderMatching"))->Fill(ncol, arrUPCcolls[ncol]); + } + + // TEST vertex contributors per reconstruction flag (std vs upc) + // matching of collision bc within ITSROF range in bcs + for (const auto& itsrofBorder : vecITSROFborders) { + std::vector vecNumContribsStd; + std::vector vecNumContribsUpc; + for (const auto& collision : collisions) { + if ((itsrofBorder.first < collision.bcId()) && (collision.bcId() < itsrofBorder.second)) { + if (collision.flags() & dataformats::Vertex>::Flags::UPCMode) { + vecNumContribsUpc.push_back(collision.numContrib()); + } else { + vecNumContribsStd.push_back(collision.numContrib()); + } + } + } // end loop over collisions + + for (const auto& numContribs : vecNumContribsStd) { + histos.get(HIST("Events/hPVcontribsVsCollisionsPerITSROFstd"))->Fill(numContribs, vecNumContribsStd.size()); + } + for (const auto& numContribs : vecNumContribsUpc) { + histos.get(HIST("Events/hPVcontribsVsCollisionsPerITSROFupc"))->Fill(numContribs, vecNumContribsUpc.size()); + } + + } // end loop over ITSROFs + } + + void processCounterPerRun(FullSGUDCollision const& coll) + { + + int gapSide = coll.gapSide(); + int trueGapSide = sgSelector.trueGap(coll, cutMyGapSideFV0, cutMyGapSideFT0A, cutMyGapSideFT0C, cutMyGapSideZDC); + if (useTrueGap) { + gapSide = trueGapSide; + } + + if (coll.flags() == 0) { + if (gapSide == 2) { + histos.get(HIST("Runs/hStdModeCollDG"))->Fill(coll.runNumber()); + } else if (gapSide == 1) { + histos.get(HIST("Runs/hStdModeCollSG1"))->Fill(coll.runNumber()); + } else if (gapSide == 0) { + histos.get(HIST("Runs/hStdModeCollSG0"))->Fill(coll.runNumber()); + } else { + histos.get(HIST("Runs/hStdModeCollNG"))->Fill(coll.runNumber()); + } + } else { + if (gapSide == 2) { + histos.get(HIST("Runs/hUpcModeCollDG"))->Fill(coll.runNumber()); + } else if (gapSide == 1) { + histos.get(HIST("Runs/hUpcModeCollSG1"))->Fill(coll.runNumber()); + } else if (gapSide == 0) { + histos.get(HIST("Runs/hUpcModeCollSG0"))->Fill(coll.runNumber()); + } else { + histos.get(HIST("Runs/hUpcModeCollNG"))->Fill(coll.runNumber()); + } + } + } + + PROCESS_SWITCH(UpcEventITSROFcounter, processCounterPerITSROF, "Counts number of collisions per ITSROF", false); + PROCESS_SWITCH(UpcEventITSROFcounter, processCounterPerRun, "Counts number of whatever per RUN", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/upcJpsiCentralBarrelCorr.cxx b/PWGUD/Tasks/upcJpsiCentralBarrelCorr.cxx deleted file mode 100644 index f2dd073cad7..00000000000 --- a/PWGUD/Tasks/upcJpsiCentralBarrelCorr.cxx +++ /dev/null @@ -1,881 +0,0 @@ -// 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 -/// \author Sara Haidlova, sara.haidlova@cern.ch -/// \since March 2024 - -// O2 headers -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "CommonConstants/MathConstants.h" -#include "CommonConstants/PhysicsConstants.h" - -// O2Physics headers -#include "Common/DataModel/PIDResponse.h" -#include "Common/Core/RecoDecay.h" -#include "PWGUD/DataModel/UDTables.h" -#include "PWGUD/Core/UDHelpers.h" -#include "PWGUD/Core/UPCJpsiCentralBarrelCorrHelper.h" - -// ROOT headers -#include "TLorentzVector.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::constants::math; - -struct UpcJpsiCentralBarrel { - // configurable axes - ConfigurableAxis IVMAxis{"IVMAxis", {350.0f, 0.0f, 4.5f}, "M_#it{inv} (GeV/#it{c}^{2})"}; - ConfigurableAxis ptAxis{"ptAxis", {250.0f, 0.1f, 3.0f}, "#it{p}_T (GeV/#it{c})"}; - ConfigurableAxis pAxis{"pAxis", {250.0f, 0.1f, 3.0f}, "#it{p} (GeV/#it{c})"}; - ConfigurableAxis etaAxis{"etaAxis", {250.0f, -1.5f, 1.5f}, "#eta (-)"}; - ConfigurableAxis countAxis{"countAxis", {10.0f, 0.0f, 10.0f}, "Number of events (-)"}; - ConfigurableAxis phiAxis{"phiAxis", {250.0f, 0, TwoPI}, "#phi (rad)"}; - ConfigurableAxis accoplAxis{"accoplAxis", {250.0f, -0.2f, 0.2f}, "accAngle"}; - ConfigurableAxis thetaAxis{"thetaAxis", {250.0f, -1.5f, 1.5f}, "cos #theta (-)"}; - ConfigurableAxis sigTPCAxis{"sigTPCAxis", {100.0f, 0, 200.0f}, "TPC d#it{E}/d#it{x}"}; - ConfigurableAxis sigTOFAxis{"sigTOFAxis", {100.0f, 0, 200.0f}, "TOF d#it{E}/d#it{x}"}; - - // configurable cuts (modify in json) - Configurable TPCNClsCrossedRows{"TPCNClsCrossedRows", 70, "number of crossed rows in TPC"}; - Configurable TPCNSigmaMu{"TPCNSigmaMu", 5, "PID for TPC Mu track"}; - Configurable EtaCut{"EtaCut", 0.9f, "acceptance cut per track"}; - Configurable RapCut{"RapCut", 0.8f, "choose event in midrapidity"}; - Configurable dcaZCut{"dcaZCut", 2, "cut on the impact parameter in z of the track to the PV"}; - Configurable dcaXYCut{"dcaXYCut", 1e10, "cut on the impact parameter in xy of the track to the PV"}; - Configurable ITSNClsCut{"ITSNClsCut", 1, "minimal number of ITS clusters"}; - Configurable ITSChi2NClsCut{"ITSChi2NClsCut", 36, "minimal Chi2/cluster for the ITS track"}; - Configurable TPCNClsCrossedRowsCut{"TPCNClsCrossedRowsCut", 70, "minimal number of crossed TPC rows"}; - Configurable TPCChi2NCls{"TPCChi2NCls", 4, "minimal Chi2/cluster for the TPC track"}; - - // initialize histogram registry - HistogramRegistry Statistics{ - "Statistics", - {}}; - - HistogramRegistry RawData{ - "RawData", - {}}; - - HistogramRegistry PVContributors{ - "PVContributors", - {}}; - - HistogramRegistry TGmu{ - "TGmu", - {}}; - - HistogramRegistry TGmuCand{ - "TGmuCand", - {}}; - - HistogramRegistry TGel{ - "TGel", - {}}; - - HistogramRegistry TGelCand{ - "TGelCand", - {}}; - - HistogramRegistry TGp{ - "TGp", - {}}; - - HistogramRegistry TGpCand{ - "TGpCand", - {}}; - - HistogramRegistry JPsiToEl{ - "JPsiToEl", - {}}; - - HistogramRegistry JPsiToMu{ - "JPsiToMu", - {}}; - - HistogramRegistry JPsiToP{ - "JPsiToP", - {}}; - - HistogramRegistry Correlation{ - "Correlation", - {}}; - - HistogramRegistry Asymmetry{ - "Asymmetry", - {}}; - - using UDCollisionsFull = soa::Join; - using UDCollisionFull = UDCollisionsFull::iterator; - using UDTracksFull = soa::Join; - using UDTrackFull = UDTracksFull::iterator; - - void init(InitContext&) - { - - const AxisSpec axisIVM{IVMAxis, "IVM axis"}; - const AxisSpec axispt{ptAxis, "pt axis"}; - const AxisSpec axiseta{etaAxis, "eta axis"}; - const AxisSpec axisCounter{countAxis, "counter axis"}; - const AxisSpec axisAccAngle{accoplAxis, "accAngle"}; - const AxisSpec axisAngTheta{thetaAxis, "cosTheta"}; - const AxisSpec axisPhi{phiAxis, "phi"}; - const AxisSpec axisp{pAxis, "p axis"}; - const AxisSpec axisTPC{sigTPCAxis, ""}; - const AxisSpec axisTOF{sigTOFAxis, ""}; - - // statistics histograms for counters - Statistics.add("Statistics/hNumberOfCollisions", "hNumberOfCollisions", {HistType::kTH1F, {axisCounter}}); - Statistics.add("Statistics/hNumberOfTracks", "hNumberOfTracks", {HistType::kTH1F, {axisCounter}}); - Statistics.add("Statistics/hNumberGT", "hNumberGT", {HistType::kTH1F, {axisCounter}}); - Statistics.add("Statistics/hNumberGTselected", "hNumberGTselected", {HistType::kTH1F, {axisCounter}}); - Statistics.add("Statistics/hNumberGTel", "hNumberGTel", {HistType::kTH1F, {axisCounter}}); - Statistics.add("Statistics/hNumberGTmu", "hNumberGTmu", {HistType::kTH1F, {axisCounter}}); - Statistics.add("Statistics/hNumberGTp", "hNumberGTp", {HistType::kTH1F, {axisCounter}}); - - // raw data histograms - RawData.add("RawData/hTrackPt", "hTrackPt", {HistType::kTH1F, {axispt}}); - RawData.add("RawData/hTrackEta", "hTrackEta", {HistType::kTH1F, {axiseta}}); - RawData.add("RawData/hTrackPhi", "hTrackPhi", {HistType::kTH1F, {axisPhi}}); - RawData.add("RawData/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisp, axisTPC}}); - RawData.add("RawData/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axispt, axisTPC}}); - RawData.add("RawData/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); - RawData.add("RawData/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axiseta, axisTPC}}); - RawData.add("RawData/PID/hTOFVsP", "hTOFVsP", {HistType::kTH2F, {axisp, axisTOF}}); - RawData.add("RawData/PID/hTOFVsPt", "hTOFVsPt", {HistType::kTH2F, {axispt, axisTOF}}); - RawData.add("RawData/PID/hTOFVsPhi", "hTOFVsPhi", {HistType::kTH2F, {axisPhi, axisTOF}}); - RawData.add("RawData/PID/hTOFVsEta", "hTOFVsEta", {HistType::kTH2F, {axiseta, axisTOF}}); - - // PVContributors histograms - PVContributors.add("PVContributors/hTrackPt", "hTrackPt", {HistType::kTH1F, {axispt}}); - PVContributors.add("PVContributors/hTrackEta", "hTrackEta", {HistType::kTH1F, {axiseta}}); - PVContributors.add("PVContributors/hTrackPhi", "hTrackPhi", {HistType::kTH1F, {axisPhi}}); - PVContributors.add("PVContributors/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisp, axisTPC}}); - PVContributors.add("PVContributors/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axispt, axisTPC}}); - PVContributors.add("PVContributors/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); - PVContributors.add("PVContributors/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axiseta, axisTPC}}); - PVContributors.add("PVContributors/PID/hTOFVsP", "hTOFVsP", {HistType::kTH2F, {axisp, axisTOF}}); - PVContributors.add("PVContributors/PID/hTOFVsPt", "hTOFVsPt", {HistType::kTH2F, {axispt, axisTOF}}); - PVContributors.add("PVContributors/PID/hTOFVsPhi", "hTOFVsPhi", {HistType::kTH2F, {axisPhi, axisTOF}}); - PVContributors.add("PVContributors/PID/hTOFVsEta", "hTOFVsEta", {HistType::kTH2F, {axiseta, axisTOF}}); - - // TGmu histograms - TGmu.add("TGmu/hTrackPt", "hTrackPt", {HistType::kTH1F, {axispt}}); - TGmu.add("TGmu/hTrackEta", "hTrackEta", {HistType::kTH1F, {axiseta}}); - TGmu.add("TGmu/hTrackPhi", "hTrackPhi", {HistType::kTH1F, {axisPhi}}); - - // TGmuCand histograms - TGmuCand.add("TGmuCand/hTrackPt", "hTrackPt", {HistType::kTH1F, {axispt}}); - TGmuCand.add("TGmuCand/hTrackEta", "hTrackEta", {HistType::kTH1F, {axiseta}}); - TGmuCand.add("TGmuCand/hTrackPhi", "hTrackPhi", {HistType::kTH1F, {axisPhi}}); - TGmuCand.add("TGmuCand/hJpsiPt", "hJpsiPt", {HistType::kTH1F, {axispt}}); - - // TGel histograms - TGel.add("TGel/hTrackPt", "hTrackPt", {HistType::kTH1F, {axispt}}); - TGel.add("TGel/hTrackEta", "hTrackEta", {HistType::kTH1F, {axiseta}}); - TGel.add("TGel/hTrackPhi", "hTrackPhi", {HistType::kTH1F, {axisPhi}}); - - // TGelCand histograms - TGelCand.add("TGelCand/hTrackPt", "hTrackPt", {HistType::kTH1F, {axispt}}); - TGelCand.add("TGelCand/hTrackEta", "hTrackEta", {HistType::kTH1F, {axiseta}}); - TGelCand.add("TGelCand/hTrackPhi", "hTrackPhi", {HistType::kTH1F, {axisPhi}}); - TGelCand.add("TGelCand/hJpsiPt", "hJpsiPt", {HistType::kTH1F, {axispt}}); - - // TGp histograms - TGp.add("TGp/hTrackPt", "hTrackPt", {HistType::kTH1F, {axispt}}); - TGp.add("TGp/hTrackEta", "hTrackEta", {HistType::kTH1F, {axiseta}}); - TGp.add("TGp/hTrackPhi", "hTrackPhi", {HistType::kTH1F, {axisPhi}}); - - // TGpCand histograms - TGpCand.add("TGpCand/hTrackPt", "hTrackPt", {HistType::kTH1F, {axispt}}); - TGpCand.add("TGpCand/hTrackEta", "hTrackEta", {HistType::kTH1F, {axiseta}}); - TGpCand.add("TGpCand/hTrackPhi", "hTrackPhi", {HistType::kTH1F, {axisPhi}}); - TGpCand.add("TGpCand/hJpsiPt", "hJpsiPt", {HistType::kTH1F, {axispt}}); - - // JPsiToEl histograms - JPsiToEl.add("JPsiToEl/Coherent/hPt", "Pt of J/Psi ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToEl.add("JPsiToEl/Coherent/hPt1", "pT of track 1 ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToEl.add("JPsiToEl/Coherent/hPt2", "pT of track 2 ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToEl.add("JPsiToEl/Coherent/hEta1", "eta of track 1 ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToEl.add("JPsiToEl/Coherent/hEta2", "eta of track 2 ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToEl.add("JPsiToEl/Coherent/hPhi1", "phi of track 1 ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToEl.add("JPsiToEl/Coherent/hPhi2", "phi of track 2 ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToEl.add("JPsiToEl/Coherent/hIVM", "J/Psi Invariant Mass ; m {GeV]", {HistType::kTH1F, {axisIVM}}); - JPsiToEl.add("JPsiToEl/Coherent/hRap", "Rap of J/Psi ; y {-]", {HistType::kTH1F, {axiseta}}); - JPsiToEl.add("JPsiToEl/Coherent/hEta", "Eta of J/Psi ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToEl.add("JPsiToEl/Coherent/hPhi", "Phi of J/Psi ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToEl.add("JPsiToEl/Coherent/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisp, axisTPC}}); - JPsiToEl.add("JPsiToEl/Coherent/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axispt, axisTPC}}); - JPsiToEl.add("JPsiToEl/Coherent/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); - JPsiToEl.add("JPsiToEl/Coherent/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axiseta, axisTPC}}); - JPsiToEl.add("JPsiToEl/Coherent/PID/hTOFVsP", "hTOFVsP", {HistType::kTH2F, {axisp, axisTOF}}); - JPsiToEl.add("JPsiToEl/Coherent/PID/hTOFVsPt", "hTOFVsPt", {HistType::kTH2F, {axispt, axisTOF}}); - JPsiToEl.add("JPsiToEl/Coherent/PID/hTOFVsPhi", "hTOFVsPhi", {HistType::kTH2F, {axisPhi, axisTOF}}); - JPsiToEl.add("JPsiToEl/Coherent/PID/hTOFVsEta", "hTOFVsEta", {HistType::kTH2F, {axiseta, axisTOF}}); - - JPsiToEl.add("JPsiToEl/Incoherent/hPt", "Pt of J/Psi ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToEl.add("JPsiToEl/Incoherent/hPt1", "pT of track 1 ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToEl.add("JPsiToEl/Incoherent/hPt2", "pT of track 2 ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToEl.add("JPsiToEl/Incoherent/hEta1", "eta of track 1 ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToEl.add("JPsiToEl/Incoherent/hEta2", "eta of track 2 ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToEl.add("JPsiToEl/Incoherent/hPhi1", "phi of track 1 ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToEl.add("JPsiToEl/Incoherent/hPhi2", "phi of track 2 ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToEl.add("JPsiToEl/Incoherent/hIVM", "J/Psi Invariant Mass ; m {GeV]", {HistType::kTH1F, {axisIVM}}); - JPsiToEl.add("JPsiToEl/Incoherent/hRap", "Rap of J/Psi ; y {-]", {HistType::kTH1F, {axiseta}}); - JPsiToEl.add("JPsiToEl/Incoherent/hEta", "Eta of J/Psi ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToEl.add("JPsiToEl/Incoherent/hPhi", "Phi of J/Psi ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToEl.add("JPsiToEl/Incoherent/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisp, axisTPC}}); - JPsiToEl.add("JPsiToEl/Incoherent/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axispt, axisTPC}}); - JPsiToEl.add("JPsiToEl/Incoherent/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); - JPsiToEl.add("JPsiToEl/Incoherent/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axiseta, axisTPC}}); - JPsiToEl.add("JPsiToEl/Incoherent/PID/hTOFVsP", "hTOFVsP", {HistType::kTH2F, {axisp, axisTOF}}); - JPsiToEl.add("JPsiToEl/Incoherent/PID/hTOFVsPt", "hTOFVsPt", {HistType::kTH2F, {axispt, axisTOF}}); - JPsiToEl.add("JPsiToEl/Incoherent/PID/hTOFVsPhi", "hTOFVsPhi", {HistType::kTH2F, {axisPhi, axisTOF}}); - JPsiToEl.add("JPsiToEl/Incoherent/PID/hTOFVsEta", "hTOFVsEta", {HistType::kTH2F, {axiseta, axisTOF}}); - - // JPsiToMu histograms - JPsiToMu.add("JPsiToMu/Coherent/hPt", "Pt of J/Psi ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToMu.add("JPsiToMu/Coherent/hPt1", "pT of track 1 ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToMu.add("JPsiToMu/Coherent/hPt2", "pT of track 2 ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToMu.add("JPsiToMu/Coherent/hEta1", "eta of track 1 ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToMu.add("JPsiToMu/Coherent/hEta2", "eta of track 2 ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToMu.add("JPsiToMu/Coherent/hPhi1", "phi of track 1 ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToMu.add("JPsiToMu/Coherent/hPhi2", "phi of track 2 ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToMu.add("JPsiToMu/Coherent/hIVM", "J/Psi Invariant Mass ; m {GeV]", {HistType::kTH1F, {axisIVM}}); - JPsiToMu.add("JPsiToMu/Coherent/hRap", "Rap of J/Psi ; y {-]", {HistType::kTH1F, {axiseta}}); - JPsiToMu.add("JPsiToMu/Coherent/hEta", "Eta of J/Psi ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToMu.add("JPsiToMu/Coherent/hPhi", "Phi of J/Psi ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToMu.add("JPsiToMu/Coherent/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisp, axisTPC}}); - JPsiToMu.add("JPsiToMu/Coherent/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axispt, axisTPC}}); - JPsiToMu.add("JPsiToMu/Coherent/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); - JPsiToMu.add("JPsiToMu/Coherent/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axiseta, axisTPC}}); - JPsiToMu.add("JPsiToMu/Coherent/PID/hTOFVsP", "hTOFVsP", {HistType::kTH2F, {axisp, axisTOF}}); - JPsiToMu.add("JPsiToMu/Coherent/PID/hTOFVsPt", "hTOFVsPt", {HistType::kTH2F, {axispt, axisTOF}}); - JPsiToMu.add("JPsiToMu/Coherent/PID/hTOFVsPhi", "hTOFVsPhi", {HistType::kTH2F, {axisPhi, axisTOF}}); - JPsiToMu.add("JPsiToMu/Coherent/PID/hTOFVsEta", "hTOFVsEta", {HistType::kTH2F, {axiseta, axisTOF}}); - - JPsiToMu.add("JPsiToMu/Incoherent/hPt", "Pt of J/Psi ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToMu.add("JPsiToMu/Incoherent/hPt1", "pT of track 1 ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToMu.add("JPsiToMu/Incoherent/hPt2", "pT of track 2 ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToMu.add("JPsiToMu/Incoherent/hEta1", "eta of track 1 ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToMu.add("JPsiToMu/Incoherent/hEta2", "eta of track 2 ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToMu.add("JPsiToMu/Incoherent/hPhi1", "phi of track 1 ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToMu.add("JPsiToMu/Incoherent/hPhi2", "phi of track 2 ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToMu.add("JPsiToMu/Incoherent/hIVM", "J/Psi Invariant Mass ; m {GeV]", {HistType::kTH1F, {axisIVM}}); - JPsiToMu.add("JPsiToMu/Incoherent/hRap", "Rap of J/Psi ; y {-]", {HistType::kTH1F, {axiseta}}); - JPsiToMu.add("JPsiToMu/Incoherent/hEta", "Eta of J/Psi ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToMu.add("JPsiToMu/Incoherent/hPhi", "Phi of J/Psi ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToMu.add("JPsiToMu/Incoherent/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisp, axisTPC}}); - JPsiToMu.add("JPsiToMu/Incoherent/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axispt, axisTPC}}); - JPsiToMu.add("JPsiToMu/Incoherent/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); - JPsiToMu.add("JPsiToMu/Incoherent/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axiseta, axisTPC}}); - JPsiToMu.add("JPsiToMu/Incoherent/PID/hTOFVsP", "hTOFVsP", {HistType::kTH2F, {axisp, axisTOF}}); - JPsiToMu.add("JPsiToMu/Incoherent/PID/hTOFVsPt", "hTOFVsPt", {HistType::kTH2F, {axispt, axisTOF}}); - JPsiToMu.add("JPsiToMu/Incoherent/PID/hTOFVsPhi", "hTOFVsPhi", {HistType::kTH2F, {axisPhi, axisTOF}}); - JPsiToMu.add("JPsiToMu/Incoherent/PID/hTOFVsEta", "hTOFVsEta", {HistType::kTH2F, {axiseta, axisTOF}}); - - // JPsiToP histograms - JPsiToP.add("JPsiToP/Coherent/hPt", "Pt of J/Psi ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToP.add("JPsiToP/Coherent/hPt1", "pT of track 1 ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToP.add("JPsiToP/Coherent/hPt2", "pT of track 2 ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToP.add("JPsiToP/Coherent/hEta1", "eta of track 1 ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToP.add("JPsiToP/Coherent/hEta2", "eta of track 2 ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToP.add("JPsiToP/Coherent/hPhi1", "phi of track 1 ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToP.add("JPsiToP/Coherent/hPhi2", "phi of track 2 ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToP.add("JPsiToP/Coherent/hIVM", "J/Psi Invariant Mass ; m {GeV]", {HistType::kTH1F, {axisIVM}}); - JPsiToP.add("JPsiToP/Coherent/hRap", "Rap of J/Psi ; y {-]", {HistType::kTH1F, {axiseta}}); - JPsiToP.add("JPsiToP/Coherent/hEta", "Eta of J/Psi ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToP.add("JPsiToP/Coherent/hPhi", "Phi of J/Psi ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToP.add("JPsiToP/Coherent/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisp, axisTPC}}); - JPsiToP.add("JPsiToP/Coherent/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axispt, axisTPC}}); - JPsiToP.add("JPsiToP/Coherent/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); - JPsiToP.add("JPsiToP/Coherent/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axiseta, axisTPC}}); - JPsiToP.add("JPsiToP/Coherent/PID/hTOFVsP", "hTOFVsP", {HistType::kTH2F, {axisp, axisTOF}}); - JPsiToP.add("JPsiToP/Coherent/PID/hTOFVsPt", "hTOFVsPt", {HistType::kTH2F, {axispt, axisTOF}}); - JPsiToP.add("JPsiToP/Coherent/PID/hTOFVsPhi", "hTOFVsPhi", {HistType::kTH2F, {axisPhi, axisTOF}}); - JPsiToP.add("JPsiToP/Coherent/PID/hTOFVsEta", "hTOFVsEta", {HistType::kTH2F, {axiseta, axisTOF}}); - - JPsiToP.add("JPsiToP/Incoherent/hPt", "Pt of J/Psi ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToP.add("JPsiToP/Incoherent/hPt1", "pT of track 1 ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToP.add("JPsiToP/Incoherent/hPt2", "pT of track 2 ; p_{T} {GeV/c]", {HistType::kTH1F, {axispt}}); - JPsiToP.add("JPsiToP/Incoherent/hEta1", "eta of track 1 ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToP.add("JPsiToP/Incoherent/hEta2", "eta of track 2 ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToP.add("JPsiToP/Incoherent/hPhi1", "phi of track 1 ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToP.add("JPsiToP/Incoherent/hPhi2", "phi of track 2 ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToP.add("JPsiToP/Incoherent/hIVM", "J/Psi Invariant Mass ; m {GeV]", {HistType::kTH1F, {axisIVM}}); - JPsiToP.add("JPsiToP/Incoherent/hRap", "Rap of J/Psi ; y {-]", {HistType::kTH1F, {axiseta}}); - JPsiToP.add("JPsiToP/Incoherent/hEta", "Eta of J/Psi ; #eta {-]", {HistType::kTH1F, {axiseta}}); - JPsiToP.add("JPsiToP/Incoherent/hPhi", "Phi of J/Psi ; #phi {-]", {HistType::kTH1F, {axisPhi}}); - JPsiToP.add("JPsiToP/Incoherent/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisp, axisTPC}}); - JPsiToP.add("JPsiToP/Incoherent/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axispt, axisTPC}}); - JPsiToP.add("JPsiToP/Incoherent/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); - JPsiToP.add("JPsiToP/Incoherent/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axiseta, axisTPC}}); - JPsiToP.add("JPsiToP/Incoherent/PID/hTOFVsP", "hTOFVsP", {HistType::kTH2F, {axisp, axisTOF}}); - JPsiToP.add("JPsiToP/Incoherent/PID/hTOFVsPt", "hTOFVsPt", {HistType::kTH2F, {axispt, axisTOF}}); - JPsiToP.add("JPsiToP/Incoherent/PID/hTOFVsPhi", "hTOFVsPhi", {HistType::kTH2F, {axisPhi, axisTOF}}); - JPsiToP.add("JPsiToP/Incoherent/PID/hTOFVsEta", "hTOFVsEta", {HistType::kTH2F, {axiseta, axisTOF}}); - - // Correlation histograms - Correlation.add("Correlation/Muon/Coherent/AccoplAngle", "AccoplAngle", {HistType::kTH1F, {axisAccAngle}}); - Correlation.add("Correlation/Muon/Coherent/CosTheta", "CosTheta", {HistType::kTH1F, {axisAngTheta}}); - Correlation.add("Correlation/Muon/Coherent/Phi", "Phi", {HistType::kTH1F, {axisPhi}}); - Correlation.add("Correlation/Muon/Coherent/Phi1", "Phi1", {HistType::kTH1F, {axisPhi}}); - Correlation.add("Correlation/Muon/Coherent/Phi2", "Phi2", {HistType::kTH1F, {axisPhi}}); - Correlation.add("Correlation/Muon/Coherent/CosThetaPhi", "CosThetaPhi", {HistType::kTH2F, {{axisAngTheta}, {axisPhi}}}); - - Correlation.add("Correlation/Muon/Incoherent/AccoplAngle", "AccoplAngle", {HistType::kTH1F, {axisAccAngle}}); - Correlation.add("Correlation/Muon/Incoherent/CosTheta", "CosTheta", {HistType::kTH1F, {axisAngTheta}}); - Correlation.add("Correlation/Muon/Incoherent/Phi", "Phi", {HistType::kTH1F, {axisPhi}}); - Correlation.add("Correlation/Muon/Incoherent/Phi1", "Phi1", {HistType::kTH1F, {axisPhi}}); - Correlation.add("Correlation/Muon/Incoherent/Phi2", "Phi2", {HistType::kTH1F, {axisPhi}}); - Correlation.add("Correlation/Muon/Incoherent/CosThetaPhi", "CosThetaPhi", {HistType::kTH2F, {{axisAngTheta}, {axisPhi}}}); - - Correlation.add("Correlation/Electron/Coherent/AccoplAngle", "AccoplAngle", {HistType::kTH1F, {axisAccAngle}}); - Correlation.add("Correlation/Electron/Coherent/CosTheta", "CosTheta", {HistType::kTH1F, {axisAngTheta}}); - Correlation.add("Correlation/Electron/Coherent/Phi", "Phi", {HistType::kTH1F, {axisPhi}}); - Correlation.add("Correlation/Electron/Coherent/Phi1", "Phi1", {HistType::kTH1F, {axisPhi}}); - Correlation.add("Correlation/Electron/Coherent/Phi2", "Phi2", {HistType::kTH1F, {axisPhi}}); - Correlation.add("Correlation/Electron/Coherent/CosThetaPhi", "CosThetaPhi", {HistType::kTH2F, {{axisAngTheta}, {axisPhi}}}); - - Correlation.add("Correlation/Electron/Incoherent/AccoplAngle", "AccoplAngle", {HistType::kTH1F, {axisAccAngle}}); - Correlation.add("Correlation/Electron/Incoherent/CosTheta", "CosTheta", {HistType::kTH1F, {axisAngTheta}}); - Correlation.add("Correlation/Electron/Incoherent/Phi", "Phi", {HistType::kTH1F, {axisPhi}}); - Correlation.add("Correlation/Electron/Incoherent/Phi1", "Phi1", {HistType::kTH1F, {axisPhi}}); - Correlation.add("Correlation/Electron/Incoherent/Phi2", "Phi2", {HistType::kTH1F, {axisPhi}}); - Correlation.add("Correlation/Electron/Incoherent/CosThetaPhi", "CosThetaPhi", {HistType::kTH2F, {{axisAngTheta}, {axisPhi}}}); - - // Asymmetry histograms - Asymmetry.add("Asymmetry/Muon/Coherent/DeltaPhi", "DeltaPhi", {HistType::kTH1F, {{180, -PI, PI}}}); - Asymmetry.add("Asymmetry/Muon/Incoherent/DeltaPhi", "DeltaPhi", {HistType::kTH1F, {{180, -PI, PI}}}); - Asymmetry.add("Asymmetry/Electron/Coherent/DeltaPhi", "DeltaPhi", {HistType::kTH1F, {{180, -PI, PI}}}); - Asymmetry.add("Asymmetry/Electron/Incoherent/DeltaPhi", "DeltaPhi", {HistType::kTH1F, {{180, -PI, PI}}}); - } - - template - bool GoodTrackCuts(T const& track) - { - // kinematics - if (std::abs(RecoDecay::eta(std::array{track.px(), track.py(), track.pz()})) > EtaCut) { - return false; - } - // DCA - if (track.dcaZ() > dcaZCut) { - return false; - } - if (track.dcaXY() > dcaXYCut) { - return false; - } - // ITS - if (!track.hasITS()) { - return false; - } - if (track.itsNCls() < ITSNClsCut) { - return false; - } - if (track.itsChi2NCl() > ITSChi2NClsCut) { - return false; - } - // TPC - if (!track.hasTPC()) { - return false; - } - if (track.tpcNClsCrossedRows() < TPCNClsCrossedRowsCut) { - return false; - } - if (track.tpcChi2NCl() > TPCChi2NCls) { - return false; // TPC chi2 - } - - return true; - } - - // template - bool CandidateCuts(float massJpsi, float rapJpsi) - { - if (rapJpsi > RapCut) { - return false; - } - - if (massJpsi < 2.5f) { - return false; - } - - return true; - } - - void process(UDCollisionFull const&, UDTracksFull const& tracks) - { - Statistics.get(HIST("Statistics/hNumberOfCollisions"))->Fill(0); // number of collisions without any cuts - - // loop over tracks without selections - for (auto& track : tracks) { - float trkPx = track.px(); - float trkPy = track.py(); - float trkPz = track.pz(); - - Statistics.get(HIST("Statistics/hNumberOfTracks"))->Fill(0); - if (track.isPVContributor() == 1) { - Statistics.get(HIST("Statistics/hNumberOfTracks"))->Fill(1); - PVContributors.get(HIST("PVContributors/hTrackPt"))->Fill(track.pt()); - PVContributors.get(HIST("PVContributors/hTrackEta"))->Fill(RecoDecay::eta(std::array{trkPx, trkPy, trkPz})); - PVContributors.get(HIST("PVContributors/hTrackPhi"))->Fill(RecoDecay::phi(trkPx, trkPy)); - - if (track.hasTPC()) { - PVContributors.get(HIST("PVContributors/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkPx, trkPy, trkPz), track.tpcSignal()); - PVContributors.get(HIST("PVContributors/PID/hTPCVsPt"))->Fill(track.pt(), track.tpcSignal()); - PVContributors.get(HIST("PVContributors/PID/hTPCVsEta"))->Fill(RecoDecay::eta(std::array{trkPx, trkPy, trkPz}), track.tpcSignal()); - PVContributors.get(HIST("PVContributors/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(trkPx, trkPy), track.tpcSignal()); - } - - if (track.hasTOF()) { - PVContributors.get(HIST("PVContributors/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkPx, trkPy, trkPz), track.tofSignal()); - PVContributors.get(HIST("PVContributors/PID/hTOFVsPt"))->Fill(track.pt(), track.tofSignal()); - PVContributors.get(HIST("PVContributors/PID/hTOFVsEta"))->Fill(RecoDecay::eta(std::array{trkPx, trkPy, trkPz}), track.tofSignal()); - PVContributors.get(HIST("PVContributors/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(trkPx, trkPy), track.tofSignal()); - } - } - - RawData.get(HIST("RawData/hTrackPt"))->Fill(track.pt()); - RawData.get(HIST("RawData/hTrackEta"))->Fill(RecoDecay::eta(std::array{trkPx, trkPy, trkPz})); - RawData.get(HIST("RawData/hTrackPhi"))->Fill(RecoDecay::phi(trkPx, trkPy)); - - if (track.hasTPC()) { - RawData.get(HIST("RawData/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkPx, trkPy, trkPz), track.tpcSignal()); - RawData.get(HIST("RawData/PID/hTPCVsPt"))->Fill(track.pt(), track.tpcSignal()); - RawData.get(HIST("RawData/PID/hTPCVsEta"))->Fill(RecoDecay::eta(std::array{trkPx, trkPy, trkPz}), track.tpcSignal()); - RawData.get(HIST("RawData/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(trkPx, trkPy), track.tpcSignal()); - } - - if (track.hasTOF()) { - RawData.get(HIST("RawData/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkPx, trkPy, trkPz), track.tofSignal()); - RawData.get(HIST("RawData/PID/hTOFVsPt"))->Fill(track.pt(), track.tofSignal()); - RawData.get(HIST("RawData/PID/hTOFVsEta"))->Fill(RecoDecay::eta(std::array{trkPx, trkPy, trkPz}), track.tofSignal()); - RawData.get(HIST("RawData/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(trkPx, trkPy), track.tofSignal()); - } - } - - int countGT = 0; - int countGTselected = 0; - int countGTel = 0; - int countGTmu = 0; - int countGTp = 0; - std::vector trkIdx; - // loop over tracks with selections - for (auto& track : tracks) { - // select primary vertex contributors - if (track.isPVContributor() != 1) { - return; - } - // select good tracks - if (GoodTrackCuts(track) != 1) { - return; - } - countGT++; - int hypoID = testPIDhypo(track); - if (hypoID == P_ELECTRON || hypoID == P_MUON) { - countGTselected++; - trkIdx.push_back(track.index()); - if (hypoID == P_ELECTRON) { - countGTel++; - } - if (hypoID == P_MUON) { - countGTmu++; - } - if (hypoID == P_PROTON) { - countGTp++; - } - } - } - - Statistics.get(HIST("Statistics/hNumberOfTracks"))->Fill(2., countGT); - Statistics.get(HIST("Statistics/hNumberOfTracks"))->Fill(3., countGTselected); - Statistics.get(HIST("Statistics/hNumberOfTracks"))->Fill(4., countGTel); - Statistics.get(HIST("Statistics/hNumberOfTracks"))->Fill(5., countGTmu); - Statistics.get(HIST("Statistics/hNumberGT"))->Fill(countGT); - Statistics.get(HIST("Statistics/hNumberGTselected"))->Fill(countGTselected); - Statistics.get(HIST("Statistics/hNumberGTel"))->Fill(countGTel); - Statistics.get(HIST("Statistics/hNumberGTmu"))->Fill(countGTmu); - Statistics.get(HIST("Statistics/hNumberGTp"))->Fill(countGTp); - - float massEl = o2::constants::physics::MassElectron; - float massMu = o2::constants::physics::MassMuonMinus; - float massPr = o2::constants::physics::MassProton; - - if (countGT == 2) { - if (countGTel == 2) { - TLorentzVector mom, daughter[2]; - auto trkDaughter1 = tracks.iteratorAt(trkIdx[0]); - auto trkDaughter2 = tracks.iteratorAt(trkIdx[1]); - if ((trkDaughter1.sign() * trkDaughter2.sign()) > 0) { - return; - } - if (!(RecoDecay::sumOfSquares(trkDaughter1.tpcNSigmaMu(), trkDaughter2.tpcNSigmaMu()) < RecoDecay::sumOfSquares(trkDaughter1.tpcNSigmaEl(), trkDaughter2.tpcNSigmaEl()))) { - return; - } - auto ene1 = RecoDecay::e(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz(), massEl); - auto ene2 = RecoDecay::e(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz(), massEl); - daughter[0].SetPxPyPzE(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz(), ene1); - daughter[1].SetPxPyPzE(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz(), ene2); - mom = daughter[0] + daughter[1]; - - std::array daughter1 = {trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()}; - std::array daughter2 = {trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()}; - - std::array mother = {trkDaughter1.px() + trkDaughter2.px(), trkDaughter1.py() + trkDaughter2.py(), trkDaughter1.pz() + trkDaughter2.pz()}; - - auto arrMom = std::array{daughter1, daughter2}; - float massJpsi = RecoDecay::m(arrMom, std::array{massEl, massEl}); - float rapJpsi = RecoDecay::y(mother, massJpsi); - - TGel.get(HIST("TGel/hTrackPt"))->Fill(trkDaughter1.pt()); - TGel.get(HIST("TGel/hTrackPt"))->Fill(trkDaughter2.pt()); - TGel.get(HIST("TGel/hTrackEta"))->Fill(RecoDecay::eta(daughter1)); - TGel.get(HIST("TGel/hTrackEta"))->Fill(RecoDecay::eta(daughter2)); - TGel.get(HIST("TGel/hTrackPhi"))->Fill(RecoDecay::phi(daughter1)); - TGel.get(HIST("TGel/hTrackPhi"))->Fill(RecoDecay::phi(daughter2)); - - if (CandidateCuts(massJpsi, rapJpsi) != 1) { - return; - } - - TGelCand.get(HIST("TGelCand/hTrackPt"))->Fill(trkDaughter1.pt()); - TGelCand.get(HIST("TGelCand/hTrackPt"))->Fill(trkDaughter2.pt()); - TGelCand.get(HIST("TGelCand/hTrackEta"))->Fill(RecoDecay::eta(daughter1)); - TGelCand.get(HIST("TGelCand/hTrackEta"))->Fill(RecoDecay::eta(daughter2)); - TGelCand.get(HIST("TGelCand/hTrackPhi"))->Fill(RecoDecay::phi(daughter1)); - TGelCand.get(HIST("TGelCand/hTrackPhi"))->Fill(RecoDecay::phi(daughter2)); - TGelCand.get(HIST("TGelCand/hJpsiPt"))->Fill(RecoDecay::pt(mother)); - if (RecoDecay::pt(mother) < 0.2f) { - // fill track histos - JPsiToEl.get(HIST("JPsiToEl/Coherent/hPt1"))->Fill(trkDaughter1.pt()); - JPsiToEl.get(HIST("JPsiToEl/Coherent/hPt2"))->Fill(trkDaughter2.pt()); - JPsiToEl.get(HIST("JPsiToEl/Coherent/hEta1"))->Fill(RecoDecay::eta(daughter1)); - JPsiToEl.get(HIST("JPsiToEl/Coherent/hEta2"))->Fill(RecoDecay::eta(daughter2)); - JPsiToEl.get(HIST("JPsiToEl/Coherent/hPhi1"))->Fill(RecoDecay::phi(daughter1)); - JPsiToEl.get(HIST("JPsiToEl/Coherent/hPhi2"))->Fill(RecoDecay::phi(daughter2)); - if (trkDaughter1.hasTPC()) { - JPsiToEl.get(HIST("JPsiToEl/Coherent/PID/hTPCVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tpcSignal()); - JPsiToEl.get(HIST("JPsiToEl/Coherent/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tpcSignal()); - JPsiToEl.get(HIST("JPsiToEl/Coherent/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tpcSignal()); - } - if (trkDaughter2.hasTPC()) { - JPsiToEl.get(HIST("JPsiToEl/Coherent/PID/hTPCVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); - JPsiToEl.get(HIST("JPsiToEl/Coherent/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); - JPsiToEl.get(HIST("JPsiToEl/Coherent/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tpcSignal()); - } - - if (trkDaughter1.hasTOF()) { - JPsiToEl.get(HIST("JPsiToEl/Coherent/PID/hTOFVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tofSignal()); - JPsiToEl.get(HIST("JPsiToEl/Coherent/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tofSignal()); - JPsiToEl.get(HIST("JPsiToEl/Coherent/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tofSignal()); - } - if (trkDaughter2.hasTOF()) { - JPsiToEl.get(HIST("JPsiToEl/Coherent/PID/hTOFVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tofSignal()); - JPsiToEl.get(HIST("JPsiToEl/Coherent/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tofSignal()); - JPsiToEl.get(HIST("JPsiToEl/Coherent/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tofSignal()); - } - // fill J/psi histos - JPsiToEl.get(HIST("JPsiToEl/Coherent/hPt"))->Fill(RecoDecay::pt(mother)); - JPsiToEl.get(HIST("JPsiToEl/Coherent/hEta"))->Fill(RecoDecay::eta(mother)); - JPsiToEl.get(HIST("JPsiToEl/Coherent/hPhi"))->Fill(RecoDecay::phi(mother)); - JPsiToEl.get(HIST("JPsiToEl/Coherent/hRap"))->Fill(rapJpsi); - JPsiToEl.get(HIST("JPsiToEl/Coherent/hIVM"))->Fill(massJpsi); - - float* q = correlation(&daughter[0], &daughter[1], &mom); - Correlation.get(HIST("Correlation/Electron/Coherent/Phi1"))->Fill(RecoDecay::phi(daughter1), 1.); - Correlation.get(HIST("Correlation/Electron/Coherent/Phi2"))->Fill(RecoDecay::phi(daughter2), 1.); - Correlation.get(HIST("Correlation/Electron/Coherent/Phi"))->Fill(q[1], 1.); - Correlation.get(HIST("Correlation/Electron/Coherent/CosTheta"))->Fill(q[2], 1.); - Correlation.get(HIST("Correlation/Electron/Coherent/AccoplAngle"))->Fill(q[0], 1.); - Correlation.get(HIST("Correlation/Electron/Coherent/CosThetaPhi"))->Fill(q[2], q[1]); - - double dp = DeltaPhi(daughter[0], daughter[1]); - Asymmetry.get(HIST("Asymmetry/Electron/Coherent/DeltaPhi"))->Fill(dp); - - delete[] q; - } - if (RecoDecay::pt(mother) > 0.2f) { - // fill track histos - JPsiToEl.get(HIST("JPsiToEl/Incoherent/hPt1"))->Fill(trkDaughter1.pt()); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/hPt2"))->Fill(trkDaughter2.pt()); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/hEta1"))->Fill(RecoDecay::eta(daughter1)); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/hEta2"))->Fill(RecoDecay::eta(daughter2)); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/hPhi1"))->Fill(RecoDecay::phi(daughter1)); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/hPhi2"))->Fill(RecoDecay::phi(daughter2)); - if (trkDaughter1.hasTPC()) { - JPsiToEl.get(HIST("JPsiToEl/Incoherent/PID/hTPCVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tpcSignal()); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tpcSignal()); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tpcSignal()); - } - if (trkDaughter2.hasTPC()) { - JPsiToEl.get(HIST("JPsiToEl/Incoherent/PID/hTPCVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tpcSignal()); - } - - if (trkDaughter1.hasTOF()) { - JPsiToEl.get(HIST("JPsiToEl/Incoherent/PID/hTOFVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tofSignal()); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tofSignal()); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tofSignal()); - } - if (trkDaughter2.hasTOF()) { - JPsiToEl.get(HIST("JPsiToEl/Incoherent/PID/hTOFVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tofSignal()); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tofSignal()); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tofSignal()); - } - // fill J/psi histos - JPsiToEl.get(HIST("JPsiToEl/Incoherent/hPt"))->Fill(RecoDecay::pt(mother)); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/hEta"))->Fill(RecoDecay::eta(mother)); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/hPhi"))->Fill(RecoDecay::phi(mother)); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/hRap"))->Fill(rapJpsi); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/hIVM"))->Fill(massJpsi); - - float* q = correlation(&daughter[0], &daughter[1], &mom); - Correlation.get(HIST("Correlation/Electron/Incoherent/Phi1"))->Fill(RecoDecay::phi(daughter1), 1.); - Correlation.get(HIST("Correlation/Electron/Incoherent/Phi2"))->Fill(RecoDecay::phi(daughter2), 1.); - Correlation.get(HIST("Correlation/Electron/Incoherent/Phi"))->Fill(q[1], 1.); - Correlation.get(HIST("Correlation/Electron/Incoherent/CosTheta"))->Fill(q[2], 1.); - Correlation.get(HIST("Correlation/Electron/Incoherent/AccoplAngle"))->Fill(q[0], 1.); - Correlation.get(HIST("Correlation/Electron/Incoherent/CosThetaPhi"))->Fill(q[2], q[1]); - - double dp = DeltaPhi(daughter[0], daughter[1]); - Asymmetry.get(HIST("Asymmetry/Electron/Incoherent/DeltaPhi"))->Fill(dp); - - delete[] q; - } - } // end electrons - if (countGTmu == 2) { - TLorentzVector mom, daughter[2]; - auto trkDaughter1 = tracks.iteratorAt(trkIdx[0]); - auto trkDaughter2 = tracks.iteratorAt(trkIdx[1]); - if ((trkDaughter1.sign() * trkDaughter2.sign()) > 0) { - return; - } - if (!(RecoDecay::sumOfSquares(trkDaughter1.tpcNSigmaEl(), trkDaughter2.tpcNSigmaEl() < RecoDecay::sumOfSquares(trkDaughter1.tpcNSigmaMu(), trkDaughter2.tpcNSigmaMu())))) { - return; - } - auto ene1 = RecoDecay::e(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz(), massMu); - auto ene2 = RecoDecay::e(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz(), massMu); - daughter[0].SetPxPyPzE(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz(), ene1); - daughter[1].SetPxPyPzE(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz(), ene2); - mom = daughter[0] + daughter[1]; - - std::array daughter1 = {trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()}; - std::array daughter2 = {trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()}; - - std::array mother = {trkDaughter1.px() + trkDaughter2.px(), trkDaughter1.py() + trkDaughter2.py(), trkDaughter1.pz() + trkDaughter2.pz()}; - - auto arrMom = std::array{daughter1, daughter2}; - float massJpsi = RecoDecay::m(arrMom, std::array{massMu, massMu}); - float rapJpsi = RecoDecay::y(mother, massJpsi); - - TGmu.get(HIST("TGmu/hTrackPt"))->Fill(trkDaughter1.pt()); - TGmu.get(HIST("TGmu/hTrackPt"))->Fill(trkDaughter2.pt()); - TGmu.get(HIST("TGmu/hTrackEta"))->Fill(RecoDecay::eta(daughter1)); - TGmu.get(HIST("TGmu/hTrackEta"))->Fill(RecoDecay::eta(daughter2)); - TGmu.get(HIST("TGmu/hTrackPhi"))->Fill(RecoDecay::phi(daughter1)); - TGmu.get(HIST("TGmu/hTrackPhi"))->Fill(RecoDecay::phi(daughter2)); - - if (CandidateCuts(massJpsi, rapJpsi) != 1) { - return; - } - - TGmuCand.get(HIST("TGmuCand/hTrackPt"))->Fill(trkDaughter1.pt()); - TGmuCand.get(HIST("TGmuCand/hTrackPt"))->Fill(trkDaughter2.pt()); - TGmuCand.get(HIST("TGmuCand/hTrackEta"))->Fill(RecoDecay::eta(daughter1)); - TGmuCand.get(HIST("TGmuCand/hTrackEta"))->Fill(RecoDecay::eta(daughter2)); - TGmuCand.get(HIST("TGmuCand/hTrackPhi"))->Fill(RecoDecay::phi(daughter1)); - TGmuCand.get(HIST("TGmuCand/hTrackPhi"))->Fill(RecoDecay::phi(daughter2)); - TGmuCand.get(HIST("TGmuCand/hJpsiPt"))->Fill(RecoDecay::pt(mother)); - - if (RecoDecay::pt(mother) < 0.2f) { - // fill track histos - JPsiToMu.get(HIST("JPsiToMu/Coherent/hPt1"))->Fill(trkDaughter1.pt()); - JPsiToMu.get(HIST("JPsiToMu/Coherent/hPt2"))->Fill(trkDaughter2.pt()); - JPsiToMu.get(HIST("JPsiToMu/Coherent/hEta1"))->Fill(RecoDecay::eta(daughter1)); - JPsiToMu.get(HIST("JPsiToMu/Coherent/hEta2"))->Fill(RecoDecay::eta(daughter2)); - JPsiToMu.get(HIST("JPsiToMu/Coherent/hPhi1"))->Fill(RecoDecay::phi(daughter1)); - JPsiToMu.get(HIST("JPsiToMu/Coherent/hPhi2"))->Fill(RecoDecay::phi(daughter2)); - if (trkDaughter1.hasTPC()) { - JPsiToMu.get(HIST("JPsiToMu/Coherent/PID/hTPCVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tpcSignal()); - JPsiToMu.get(HIST("JPsiToMu/Coherent/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tpcSignal()); - JPsiToMu.get(HIST("JPsiToMu/Coherent/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tpcSignal()); - } - if (trkDaughter2.hasTPC()) { - JPsiToMu.get(HIST("JPsiToMu/Coherent/PID/hTPCVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); - JPsiToMu.get(HIST("JPsiToMu/Coherent/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); - JPsiToMu.get(HIST("JPsiToMu/Coherent/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tpcSignal()); - } - // fill J/psi histos - JPsiToMu.get(HIST("JPsiToMu/Coherent/hPt"))->Fill(RecoDecay::pt(mother)); - JPsiToMu.get(HIST("JPsiToMu/Coherent/hEta"))->Fill(RecoDecay::eta(mother)); - JPsiToMu.get(HIST("JPsiToMu/Coherent/hPhi"))->Fill(RecoDecay::phi(mother)); - JPsiToMu.get(HIST("JPsiToMu/Coherent/hRap"))->Fill(rapJpsi); - JPsiToMu.get(HIST("JPsiToMu/Coherent/hIVM"))->Fill(massJpsi); - - float* q = correlation(&daughter[0], &daughter[1], &mom); - Correlation.get(HIST("Correlation/Muon/Coherent/Phi1"))->Fill(RecoDecay::phi(daughter1), 1.); - Correlation.get(HIST("Correlation/Muon/Coherent/Phi2"))->Fill(RecoDecay::phi(daughter2), 1.); - Correlation.get(HIST("Correlation/Muon/Coherent/Phi"))->Fill(q[1], 1.); - Correlation.get(HIST("Correlation/Muon/Coherent/CosTheta"))->Fill(q[2], 1.); - Correlation.get(HIST("Correlation/Muon/Coherent/AccoplAngle"))->Fill(q[0], 1.); - Correlation.get(HIST("Correlation/Muon/Coherent/CosThetaPhi"))->Fill(q[2], q[1]); - - double dp = DeltaPhi(daughter[0], daughter[1]); - Asymmetry.get(HIST("Asymmetry/Muon/Coherent/DeltaPhi"))->Fill(dp); - - delete[] q; - } - if (RecoDecay::pt(mother) > 0.2f) { - // fill track histos - JPsiToMu.get(HIST("JPsiToMu/Incoherent/hPt1"))->Fill(trkDaughter1.pt()); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/hPt2"))->Fill(trkDaughter2.pt()); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/hEta1"))->Fill(RecoDecay::eta(daughter1)); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/hEta2"))->Fill(RecoDecay::eta(daughter2)); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/hPhi1"))->Fill(RecoDecay::phi(daughter1)); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/hPhi2"))->Fill(RecoDecay::phi(daughter2)); - if (trkDaughter1.hasTPC()) { - JPsiToMu.get(HIST("JPsiToMu/Incoherent/PID/hTPCVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tpcSignal()); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tpcSignal()); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tpcSignal()); - } - if (trkDaughter2.hasTPC()) { - JPsiToMu.get(HIST("JPsiToMu/Incoherent/PID/hTPCVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tpcSignal()); - } - // fill J/psi histos - JPsiToMu.get(HIST("JPsiToMu/Incoherent/hPt"))->Fill(RecoDecay::pt(mother)); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/hEta"))->Fill(RecoDecay::eta(mother)); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/hPhi"))->Fill(RecoDecay::phi(mother)); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/hRap"))->Fill(rapJpsi); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/hIVM"))->Fill(massJpsi); - - float* q = correlation(&daughter[0], &daughter[1], &mom); - Correlation.get(HIST("Correlation/Muon/Incoherent/Phi1"))->Fill(RecoDecay::phi(daughter1), 1.); - Correlation.get(HIST("Correlation/Muon/Incoherent/Phi2"))->Fill(RecoDecay::phi(daughter2), 1.); - Correlation.get(HIST("Correlation/Muon/Incoherent/Phi"))->Fill(q[1], 1.); - Correlation.get(HIST("Correlation/Muon/Incoherent/CosTheta"))->Fill(q[2], 1.); - Correlation.get(HIST("Correlation/Muon/Incoherent/AccoplAngle"))->Fill(q[0], 1.); - Correlation.get(HIST("Correlation/Muon/Incoherent/CosThetaPhi"))->Fill(q[2], q[1]); - - double dp = DeltaPhi(daughter[0], daughter[1]); - Asymmetry.get(HIST("Asymmetry/Muon/Incoherent/DeltaPhi"))->Fill(dp); - - delete[] q; - } - } // end muons - if (countGTp == 2) { - TLorentzVector mom, daughter[2]; - auto trkDaughter1 = tracks.iteratorAt(trkIdx[0]); - auto trkDaughter2 = tracks.iteratorAt(trkIdx[1]); - if ((trkDaughter1.sign() * trkDaughter2.sign()) > 0) { - return; - } - - auto ene1 = RecoDecay::e(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz(), massPr); - auto ene2 = RecoDecay::e(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz(), massPr); - daughter[0].SetPxPyPzE(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz(), ene1); - daughter[1].SetPxPyPzE(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz(), ene2); - mom = daughter[0] + daughter[1]; - - std::array daughter1 = {trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()}; - std::array daughter2 = {trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()}; - - std::array mother = {trkDaughter1.px() + trkDaughter2.px(), trkDaughter1.py() + trkDaughter2.py(), trkDaughter1.pz() + trkDaughter2.pz()}; - - auto arrMom = std::array{daughter1, daughter2}; - float massJpsi = RecoDecay::m(arrMom, std::array{massPr, massPr}); - float rapJpsi = RecoDecay::y(mother, massJpsi); - - TGp.get(HIST("TGp/hTrackPt"))->Fill(trkDaughter1.pt()); - TGp.get(HIST("TGp/hTrackPt"))->Fill(trkDaughter2.pt()); - TGp.get(HIST("TGp/hTrackEta"))->Fill(RecoDecay::eta(daughter1)); - TGp.get(HIST("TGp/hTrackEta"))->Fill(RecoDecay::eta(daughter2)); - TGp.get(HIST("TGp/hTrackPhi"))->Fill(RecoDecay::phi(daughter1)); - TGp.get(HIST("TGp/hTrackPhi"))->Fill(RecoDecay::phi(daughter2)); - - if (CandidateCuts(massJpsi, rapJpsi) != 1) { - return; - } - - TGpCand.get(HIST("TGpCand/hTrackPt"))->Fill(trkDaughter1.pt()); - TGpCand.get(HIST("TGpCand/hTrackPt"))->Fill(trkDaughter2.pt()); - TGpCand.get(HIST("TGpCand/hTrackEta"))->Fill(RecoDecay::eta(daughter1)); - TGpCand.get(HIST("TGpCand/hTrackEta"))->Fill(RecoDecay::eta(daughter2)); - TGpCand.get(HIST("TGpCand/hTrackPhi"))->Fill(RecoDecay::phi(daughter1)); - TGpCand.get(HIST("TGpCand/hTrackPhi"))->Fill(RecoDecay::phi(daughter2)); - TGpCand.get(HIST("TGpCand/hJpsiPt"))->Fill(RecoDecay::pt(mother)); - - if (RecoDecay::pt(mother) < 0.2f) { - // fill track histos - JPsiToP.get(HIST("JPsiToP/Coherent/hPt1"))->Fill(trkDaughter1.pt()); - JPsiToP.get(HIST("JPsiToP/Coherent/hPt2"))->Fill(trkDaughter2.pt()); - JPsiToP.get(HIST("JPsiToP/Coherent/hEta1"))->Fill(RecoDecay::eta(daughter1)); - JPsiToP.get(HIST("JPsiToP/Coherent/hEta2"))->Fill(RecoDecay::eta(daughter2)); - JPsiToP.get(HIST("JPsiToP/Coherent/hPhi1"))->Fill(RecoDecay::phi(daughter1)); - JPsiToP.get(HIST("JPsiToP/Coherent/hPhi2"))->Fill(RecoDecay::phi(daughter2)); - if (trkDaughter1.hasTPC()) { - JPsiToP.get(HIST("JPsiToP/Coherent/PID/hTPCVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tpcSignal()); - JPsiToP.get(HIST("JPsiToP/Coherent/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tpcSignal()); - JPsiToP.get(HIST("JPsiToP/Coherent/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tpcSignal()); - } - if (trkDaughter2.hasTPC()) { - JPsiToP.get(HIST("JPsiToP/Coherent/PID/hTPCVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); - JPsiToP.get(HIST("JPsiToP/Coherent/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); - JPsiToP.get(HIST("JPsiToP/Coherent/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tpcSignal()); - } - // fill J/psi histos - JPsiToP.get(HIST("JPsiToP/Coherent/hPt"))->Fill(RecoDecay::pt(mother)); - JPsiToP.get(HIST("JPsiToP/Coherent/hEta"))->Fill(RecoDecay::eta(mother)); - JPsiToP.get(HIST("JPsiToP/Coherent/hPhi"))->Fill(RecoDecay::phi(mother)); - JPsiToP.get(HIST("JPsiToP/Coherent/hRap"))->Fill(rapJpsi); - JPsiToP.get(HIST("JPsiToP/Coherent/hIVM"))->Fill(massJpsi); - } - if (RecoDecay::pt(mother) > 0.2f) { - // fill track histos - JPsiToP.get(HIST("JPsiToP/Incoherent/hPt1"))->Fill(trkDaughter1.pt()); - JPsiToP.get(HIST("JPsiToP/Incoherent/hPt2"))->Fill(trkDaughter2.pt()); - JPsiToP.get(HIST("JPsiToP/Incoherent/hEta1"))->Fill(RecoDecay::eta(daughter1)); - JPsiToP.get(HIST("JPsiToP/Incoherent/hEta2"))->Fill(RecoDecay::eta(daughter2)); - JPsiToP.get(HIST("JPsiToP/Incoherent/hPhi1"))->Fill(RecoDecay::phi(daughter1)); - JPsiToP.get(HIST("JPsiToP/Incoherent/hPhi2"))->Fill(RecoDecay::phi(daughter2)); - if (trkDaughter1.hasTPC()) { - JPsiToP.get(HIST("JPsiToP/Incoherent/PID/hTPCVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tpcSignal()); - JPsiToP.get(HIST("JPsiToP/Incoherent/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tpcSignal()); - JPsiToP.get(HIST("JPsiToP/Incoherent/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tpcSignal()); - } - if (trkDaughter2.hasTPC()) { - JPsiToP.get(HIST("JPsiToP/Incoherent/PID/hTPCVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); - JPsiToP.get(HIST("JPsiToP/Incoherent/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); - JPsiToP.get(HIST("JPsiToP/Incoherent/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tpcSignal()); - } - // fill J/psi histos - JPsiToP.get(HIST("JPsiToP/Incoherent/hPt"))->Fill(RecoDecay::pt(mother)); - JPsiToP.get(HIST("JPsiToP/Incoherent/hEta"))->Fill(RecoDecay::eta(mother)); - JPsiToP.get(HIST("JPsiToP/Incoherent/hPhi"))->Fill(RecoDecay::phi(mother)); - JPsiToP.get(HIST("JPsiToP/Incoherent/hRap"))->Fill(rapJpsi); - JPsiToP.get(HIST("JPsiToP/Incoherent/hIVM"))->Fill(massJpsi); - } - } // end protons - } // end two tracks - } // end process -}; // end struct - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"upc-jpsi-corr"}), - }; -} diff --git a/PWGUD/Tasks/upcJpsiCorr.cxx b/PWGUD/Tasks/upcJpsiCorr.cxx new file mode 100644 index 00000000000..8db8746b99d --- /dev/null +++ b/PWGUD/Tasks/upcJpsiCorr.cxx @@ -0,0 +1,1378 @@ +// 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 upcJpsiCorr.cxx +/// \brief Personal task for analysis of azimuthal asymmetry and quantum tomography in J/Psi system. +/// +/// \author Sara Haidlova, sara.haidlova@cern.ch +/// \since March 2024 + +#include +#include + +// O2 headers +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" + +// O2Physics headers +#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/RecoDecay.h" +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/UDHelpers.h" +#include "PWGUD/Core/UPCJpsiCentralBarrelCorrHelper.h" +#include "PWGUD/Core/SGSelector.h" + +// ROOT headers +#include "TLorentzVector.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::math; + +SGSelector sgSelector; + +namespace o2::aod +{ +namespace tree +{ +// misc event info +DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); +DECLARE_SOA_COLUMN(GlobalBC, globalBC, uint64_t); +// event vertex +DECLARE_SOA_COLUMN(PosX, posX, double); +DECLARE_SOA_COLUMN(PosY, posY, double); +DECLARE_SOA_COLUMN(PosZ, posZ, double); +// FIT info +DECLARE_SOA_COLUMN(TotalFT0AmplitudeA, totalFT0AmplitudeA, float); +DECLARE_SOA_COLUMN(TotalFT0AmplitudeC, totalFT0AmplitudeC, float); +DECLARE_SOA_COLUMN(TotalFV0AmplitudeA, totalFV0AmplitudeA, float); +DECLARE_SOA_COLUMN(TotalFDDAmplitudeA, totalFDDAmplitudeA, float); +DECLARE_SOA_COLUMN(TotalFDDAmplitudeC, totalFDDAmplitudeC, float); +DECLARE_SOA_COLUMN(TimeFT0A, timeFT0A, float); +DECLARE_SOA_COLUMN(TimeFT0C, timeFT0C, float); +DECLARE_SOA_COLUMN(TimeFV0A, timeFV0A, float); +DECLARE_SOA_COLUMN(TimeFDDA, timeFDDA, float); +DECLARE_SOA_COLUMN(TimeFDDC, timeFDDC, float); +// ZDC info +DECLARE_SOA_COLUMN(EnergyCommonZNA, energyCommonZNA, float); +DECLARE_SOA_COLUMN(EnergyCommonZNC, energyCommonZNC, float); +DECLARE_SOA_COLUMN(TimeZNA, timeZNA, float); +DECLARE_SOA_COLUMN(TimeZNC, timeZNC, float); +DECLARE_SOA_COLUMN(NeutronClass, neutronClass, int); + +// J/Psi +DECLARE_SOA_COLUMN(JpsiPt, jpsiPt, double); +DECLARE_SOA_COLUMN(JpsiEta, jpsiEta, double); +DECLARE_SOA_COLUMN(JpsiPhi, jpsiPhi, double); +DECLARE_SOA_COLUMN(JpsiM, jpsiM, double); +DECLARE_SOA_COLUMN(JpsiRap, jpsiRap, double); + +// asymmetry and correlation +DECLARE_SOA_COLUMN(JpsiPhiRandom, jpsiPhiRandom, double); +DECLARE_SOA_COLUMN(JpsiPhiCharge, jpsiPhiCharge, double); +DECLARE_SOA_COLUMN(JpsiPhiCS, jpsiPhiCS, double); +DECLARE_SOA_COLUMN(JpsiCosThetaCS, jpsiCosThetaCS, double); + +// muon tracks +DECLARE_SOA_COLUMN(TrackSign1, trackSign1, double); +DECLARE_SOA_COLUMN(TrackPt1, trackPt1, double); +DECLARE_SOA_COLUMN(TrackEta1, trackEta1, double); +DECLARE_SOA_COLUMN(TrackPhi1, trackPhi1, double); +DECLARE_SOA_COLUMN(TrackSign2, trackSign2, double); +DECLARE_SOA_COLUMN(TrackPt2, trackPt2, double); +DECLARE_SOA_COLUMN(TrackEta2, trackEta2, double); +DECLARE_SOA_COLUMN(TrackPhi2, trackPhi2, double); +} // namespace tree +DECLARE_SOA_TABLE(Tree, "AOD", "TREE", + tree::RunNumber, tree::GlobalBC, + tree::PosX, tree::PosY, tree::PosZ, tree::TotalFT0AmplitudeA, tree::TotalFT0AmplitudeC, tree::TotalFV0AmplitudeA, tree::TotalFDDAmplitudeA, tree::TotalFDDAmplitudeC, + tree::TimeFT0A, tree::TimeFT0C, tree::TimeFV0A, tree::TimeFDDA, tree::TimeFDDC, + tree::EnergyCommonZNA, tree::EnergyCommonZNC, tree::TimeZNA, tree::TimeZNC, tree::NeutronClass, + tree::JpsiPt, tree::JpsiEta, tree::JpsiPhi, tree::JpsiRap, tree::JpsiM, tree::JpsiPhiRandom, tree::JpsiPhiCharge, tree::JpsiPhiCS, tree::JpsiCosThetaCS, + tree::TrackSign1, tree::TrackPt1, tree::TrackEta1, tree::TrackPhi1, + tree::TrackSign2, tree::TrackPt2, tree::TrackEta2, tree::TrackPhi2); +namespace tree_mc +{ +// misc event info +DECLARE_SOA_COLUMN(GlobalBC, globalBC, uint64_t); +// event vertex +DECLARE_SOA_COLUMN(PosX, posX, double); +DECLARE_SOA_COLUMN(PosY, posY, double); +DECLARE_SOA_COLUMN(PosZ, posZ, double); + +// J/Psi +DECLARE_SOA_COLUMN(JpsiPt, jpsiPt, double); +DECLARE_SOA_COLUMN(JpsiEta, jpsiEta, double); +DECLARE_SOA_COLUMN(JpsiPhi, jpsiPhi, double); +DECLARE_SOA_COLUMN(JpsiM, jpsiM, double); +DECLARE_SOA_COLUMN(JpsiRap, jpsiRap, double); + +// asymmetry and correlation +DECLARE_SOA_COLUMN(JpsiPhiRandom, jpsiPhiRandom, double); +DECLARE_SOA_COLUMN(JpsiPhiCharge, jpsiPhiCharge, double); +DECLARE_SOA_COLUMN(JpsiPhiCS, jpsiPhiCS, double); +DECLARE_SOA_COLUMN(JpsiCosThetaCS, jpsiCosThetaCS, double); + +// muon tracks +DECLARE_SOA_COLUMN(TrackSign1, trackSign1, double); +DECLARE_SOA_COLUMN(TrackPt1, trackPt1, double); +DECLARE_SOA_COLUMN(TrackEta1, trackEta1, double); +DECLARE_SOA_COLUMN(TrackPhi1, trackPhi1, double); +DECLARE_SOA_COLUMN(TrackSign2, trackSign2, double); +DECLARE_SOA_COLUMN(TrackPt2, trackPt2, double); +DECLARE_SOA_COLUMN(TrackEta2, trackEta2, double); +DECLARE_SOA_COLUMN(TrackPhi2, trackPhi2, double); +} // namespace tree_mc +DECLARE_SOA_TABLE(TreeMC, "AOD", "TREEMC", + tree_mc::GlobalBC, + tree_mc::JpsiPt, tree_mc::JpsiEta, tree_mc::JpsiPhi, tree_mc::JpsiRap, tree_mc::JpsiM, tree_mc::JpsiPhiRandom, tree_mc::JpsiPhiCharge, tree_mc::JpsiPhiCS, tree_mc::JpsiCosThetaCS, + tree_mc::TrackSign1, tree_mc::TrackPt1, tree_mc::TrackEta1, tree_mc::TrackPhi1, + tree_mc::TrackSign2, tree_mc::TrackPt2, tree_mc::TrackEta2, tree_mc::TrackPhi2); +//} // namespace tree_mc +} // namespace o2::aod + +struct UpcJpsiCorr { + Produces tree; + Produces treeMC; + + // configurable axes + ConfigurableAxis axisIVM{"axisIVM", {500.0f, 2.0f, 4.5f}, "M_#it{inv} (GeV/#it{c}^{2})"}; + ConfigurableAxis axisIVMWide{"axisIVMWide", {350.0f, 0.0f, 4.5f}, "M_#it{inv} (GeV/#it{c}^{2})"}; + ConfigurableAxis axisPt{"axisPt", {250.0f, 0.1f, 3.0f}, "#it{p}_T (GeV/#it{c})"}; + ConfigurableAxis axisPt2{"axisPt2", {250.0f, 0.0f, 0.01f}, "#it{p}_T (GeV/#it{c})"}; + ConfigurableAxis axisPt2wide{"axisPt2wide", {250.0f, 0.0f, 0.04f}, "#it{p}_T (GeV/#it{c})"}; + ConfigurableAxis axisP{"axisP", {250.0f, 0.1f, 3.0f}, "#it{p} (GeV/#it{c})"}; + ConfigurableAxis axisEta{"axisEta", {250.0f, -1.5f, 1.5f}, "#eta (-)"}; + ConfigurableAxis axisCounter{"axisCounter", {20.0f, 0.0f, 20.0f}, "Number of events (-)"}; + ConfigurableAxis axisPhi{"axisPhi", {250.0f, 0, TwoPI}, "#phi (rad)"}; + ConfigurableAxis axisAccAngle{"axisAccAngle", {250.0f, -0.2f, 0.2f}, "accAngle"}; + ConfigurableAxis axisAngTheta{"axisAngTheta", {250.0f, -1.5f, 1.5f}, "cos #theta (-)"}; + ConfigurableAxis axisTPC{"axisTPC", {1000.0f, 0, 200.0f}, "TPC d#it{E}/d#it{x}"}; + ConfigurableAxis axisBetaTOF{"axisBetaTOF", {100.0f, 0, 1.5}, "TOF #beta"}; + ConfigurableAxis axisSigma{"axisSigma", {50, -25, 25}, "#sigma"}; + ConfigurableAxis axisZDCEnergy{"axisZDCEnergy", {250, -5.0, 20.0}, "ZDC energy"}; + ConfigurableAxis axisZDCTime{"axisZDCTime", {200, -10.0, 10.0}, "ZDC time"}; + ConfigurableAxis axisDCA{"axisDCA", {1000, -20.0, 20.0}, "DCA"}; + ConfigurableAxis axisChi2{"axisChi2", {200, -10.0, 40}, "Chi2"}; + ConfigurableAxis axisIVMSel{"axisIVMSel", {1000, 0.0, 10.0}, "IVM"}; + ConfigurableAxis axisCounterSel{"axisCounterSel", {1000, 0.0, 200.0}, "Selection"}; + ConfigurableAxis axisITSNCls{"axisITSNCls", {10, 0.0, 10.0}, "ITSNCls"}; + ConfigurableAxis axisTPCNCls{"axisTPCNCls", {170, -1, 160.0}, "TPCNCls"}; + ConfigurableAxis axisTPCCrossed{"axisTPCCrossed", {300, 20, 170.0}, "TPCCrossedRows"}; + + // configurable cuts (modify in json) + // track quality cuts + Configurable tpcNClsCrossedRows{"tpcNClsCrossedRows", 70, "number of crossed rows in TPC"}; + Configurable tofAtLeastOneProton{"tofAtLeastOneProton", false, "at least one candidate track has TOF hits"}; + Configurable tofBothProtons{"tofBothProtons", false, "both candidate protons have TOF hits"}; + Configurable tofOneProton{"tofOneProton", false, "one candidate proton has TOF hits"}; + Configurable dcaCut{"dcaCut", false, "DCA cut from run2."}; + Configurable newCutTPC{"newCutTPC", false, "New cuts for TPC quality tracks."}; + Configurable etaCut{"etaCut", 0.9f, "acceptance cut per track"}; + Configurable cutPtTrack{"cutPtTrack", 0.1f, "pT cut per track"}; + Configurable cutVertexZ{"cutVertexZ", 10.0f, "cut on vertex position in Z"}; + Configurable rapCut{"rapCut", 0.9f, "choose event in midrapidity"}; + Configurable dcaZCut{"dcaZCut", 2, "cut on the impact parameter in z of the track to the PV"}; + Configurable dcaXYCut{"dcaXYCut", 1e10, "cut on the impact parameter in xy of the track to the PV"}; + Configurable itsNClsCut{"itsNClsCut", 4, "minimal number of ITS clusters"}; + Configurable itsChi2NClsCut{"itsChi2NClsCut", 36, "minimal Chi2/cluster for the ITS track"}; + Configurable tpcNClsCrossedRowsCut{"tpcNClsCrossedRowsCut", 70, "minimal number of crossed TPC rows"}; + Configurable tpcChi2NCls{"tpcChi2NCls", 4, "minimal Chi2/cluster for the TPC track"}; + Configurable tpcMinNCls{"tpcMinNCls", 3, "minimum number of TPC clusters"}; + Configurable tpcCrossedOverFindable{"tpcCrossedOverFindable", 3, "number of TPC crossed rows over findable clusters"}; + + // ZDC classes cuts + Configurable znEnergyCut{"znEnergyCut", 0.0, "ZN common energy cut"}; + Configurable znTimeCut{"znTimeCut", 2.0, "ZN time cut"}; + + // Analysis cuts + Configurable maxJpsiMass{"maxJpsiMass", 3.18, "Maximum of the jpsi peak for peak cut"}; + Configurable minJpsiMass{"minJpsiMass", 3.0, "Minimum of the jpsi peak for peak cut"}; + + // SG cuts + Configurable whichGapSide{"whichGapSide", 2, {"0 for side A, 1 for side C, 2 for both sides"}}; + Configurable useTrueGap{"useTrueGap", true, {"Calculate gapSide for a given FV0/FT0/ZDC thresholds"}}; + Configurable cutMyGapSideFV0{"cutMyGapSideFV0", 100, "FV0A threshold for SG selector"}; + Configurable cutMyGapSideFT0A{"cutMyGapSideFT0A", 200., "FT0A threshold for SG selector"}; + Configurable cutMyGapSideFT0C{"cutMyGapSideFT0C", 100., "FT0C threshold for SG selector"}; + Configurable cutMyGapSideZDC{"cutMyGapSideZDC", 1000., "ZDC threshold for SG selector"}; + + // process cuts + Configurable doMuons{"doMuons", true, "Provide muon plots."}; + Configurable doElectrons{"doElectrons", true, "Provide electron plots."}; + Configurable doProtons{"doProtons", true, "Provide proton plots."}; + Configurable chargeOrdered{"chargeOrdered", false, "Order tracks based on charge."}; + Configurable doOnlyUPC{"doOnlyUPC", false, "Analyse only collisions with UPC settings."}; + Configurable doOnlyStandard{"doOnlyStandard", false, "Analyse only collisions with standard settings."}; + + // initialize histogram registry + HistogramRegistry rStatistics{ + "rStatistics", + {}}; + + HistogramRegistry rRawData{ + "rRawData", + {}}; + + HistogramRegistry rSelections{ + "rSelections", + {}}; + + HistogramRegistry rPVContributors{ + "rPVContributors", + {}}; + + HistogramRegistry rTG{ + "rTG", + {}}; + + HistogramRegistry rTGdaug{ + "TrGdaug", + {}}; + + HistogramRegistry rTGdaugCand{ + "rTGdaugCand", + {}}; + + HistogramRegistry rJpsiToDaug{ + "rJpsiToDaug", + {}}; + + HistogramRegistry rCorrelation{ + "rCorrelation", + {}}; + + HistogramRegistry rAsymmetry{ + "rAsymmetry", + {}}; + + HistogramRegistry rMC{ + "rMC", + {}}; + + using UDCollisionsFull = soa::Join; + using UDCollisionFull = UDCollisionsFull::iterator; + using UDTracksFull = soa::Join; + using UDTrackFull = UDTracksFull::iterator; + using SGUDCollisionFull = soa::Join::iterator; + using MCUDTracksFull = soa::Join; + using MCUDCollisionFull = soa::Join::iterator; + using MCSGUDCollisionFull = soa::Join::iterator; + + void init(InitContext&) + { + + // statistics histograms for counters + rStatistics.add("Statistics/hNumberOfCollisions", "hNumberOfCollisions", {HistType::kTH1F, {axisCounter}}); + rStatistics.add("Statistics/hNumberOfTracks", "hNumberOfTracks", {HistType::kTH1F, {axisCounter}}); + rStatistics.add("Statistics/hNumberGT", "hNumberGT", {HistType::kTH1F, {axisCounter}}); + rStatistics.add("Statistics/hCutCounterCollisions", "hCutCounterCollisions", {HistType::kTH1F, {axisCounter}}); + rStatistics.add("Statistics/hCutCounterTracks", "hCutCounterTracks", {HistType::kTH1F, {axisCounter}}); + + // raw data histograms + rRawData.add("RawData/hTrackPt", "hTrackPt", {HistType::kTH1F, {axisPt}}); + rRawData.add("RawData/hTrackEta", "hTrackEta", {HistType::kTH1F, {axisEta}}); + rRawData.add("RawData/hTrackPhi", "hTrackPhi", {HistType::kTH1F, {axisPhi}}); + rRawData.add("RawData/hTrackDCAXYZ", "hTrackDCAXYZ", {HistType::kTH2F, {axisDCA, axisDCA}}); + rRawData.add("RawData/hTPCNClsFindable", "hTPCNClsFindable", {HistType::kTH1F, {axisTPC}}); + rRawData.add("RawData/hTPCNClsFindableMinusFound", "hTPCNClsFindableMinusFound", {HistType::kTH1F, {axisTPC}}); + rRawData.add("RawData/hITSNCls", "hITSNCls", {HistType::kTH1F, {axisCounter}}); + rRawData.add("RawData/hTPCNCls", "hTPCNCls", {HistType::kTH1F, {axisCounter}}); + rRawData.add("RawData/hITSChi2NCls", "hITSChi2NCls", {HistType::kTH1F, {axisChi2}}); + rRawData.add("RawData/hTPCChi2NCls", "hTPCChi2NCls", {HistType::kTH1F, {axisChi2}}); + rRawData.add("RawData/hPositionZ", "hPositionZ", {HistType::kTH1F, {axisSigma}}); + rRawData.add("RawData/hPositionX", "hPositionX", {HistType::kTH1F, {axisSigma}}); + rRawData.add("RawData/hPositionY", "hPositionY", {HistType::kTH1F, {axisSigma}}); + rRawData.add("RawData/hPositionXY", "hPositionXY", {HistType::kTH2F, {axisSigma, axisSigma}}); + rRawData.add("RawData/QA/ZDC/hZNACommonEnergy", "hZNACommonEnergy", {HistType::kTH1F, {axisZDCEnergy}}); + rRawData.add("RawData/QA/ZDC/hZNCCommonEnergy", "hZNCCommonEnergy", {HistType::kTH1F, {axisZDCEnergy}}); + rRawData.add("RawData/QA/ZDC/hZNAvsZNCCommonEnergy", "hZNAvsZNCCommonEnergy", {HistType::kTH2F, {axisZDCEnergy, axisZDCEnergy}}); + rRawData.add("RawData/QA/ZDC/hZNATime", "hZNATime", {HistType::kTH1F, {axisZDCTime}}); + rRawData.add("RawData/QA/ZDC/hZNCTime", "hZNCTime", {HistType::kTH1F, {axisZDCTime}}); + rRawData.add("RawData/QA/ZDC/hZNAvsZNCTime", "hZNAvsZNCTime", {HistType::kTH2F, {axisZDCTime, axisZDCTime}}); + rRawData.add("RawData/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisP, axisTPC}}); + rRawData.add("RawData/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axisPt, axisTPC}}); + rRawData.add("RawData/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); + rRawData.add("RawData/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axisEta, axisTPC}}); + rRawData.add("RawData/PID/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisP, axisBetaTOF}}); + rRawData.add("RawData/QA/FIT/hTotFT0AmplitudeA", "hTotFT0AmplitudeA", {HistType::kTH1D, {{1000, 0.0, 1000}}}); + rRawData.add("RawData/QA/FIT/hTotFT0AmplitudeC", "hTotFT0AmplitudeC", {HistType::kTH1D, {{1000, 0.0, 1000}}}); + rRawData.add("RawData/QA/FIT/hTotFV0AmplitudeA", "hTotFV0AmplitudeA", {HistType::kTH1D, {{1000, 0.0, 1000}}}); + rRawData.add("RawData/QA/FIT/hTotFDDAmplitudeA", "hTotFDDAmplitudeA", {HistType::kTH1D, {{1000, 0.0, 1000}}}); + rRawData.add("RawData/QA/FIT/hTotFDDAmplitudeC", "hTotFDDAmplitudeC", {HistType::kTH1D, {{1000, 0.0, 1000}}}); + rRawData.add("RawData/QA/FIT/hTimeFT0A", "hTimeFT0A", {HistType::kTH1D, {{200, -100, 100}}}); + rRawData.add("RawData/QA/FIT/hTimeFT0C", "hTimeFT0C", {HistType::kTH1D, {{200, -100, 100}}}); + rRawData.add("RawData/QA/FIT/hTimeFV0A", "hTimeFV0A", {HistType::kTH1D, {{200, -100, 100}}}); + rRawData.add("RawData/QA/FIT/hTimeFDDA", "hTimeFDDA", {HistType::kTH1D, {{200, -100, 100}}}); + rRawData.add("RawData/QA/FIT/hTimeFDDC", "hTimeFDDC", {HistType::kTH1D, {{200, -100, 100}}}); + + // Selection checks + rSelections.add("Selections/Electron/Mass/Leading/hITSNCls", "hITSNCls", {HistType::kTH2F, {axisIVMSel, axisITSNCls}}); + rSelections.add("Selections/Electron/Mass/Leading/hITSChi2NCls", "hITSChi2NCls", {HistType::kTH2F, {axisIVMSel, axisChi2}}); + rSelections.add("Selections/Electron/Mass/Leading/hTPCNCls", "hTPCNCls", {HistType::kTH2F, {axisIVMSel, axisTPCNCls}}); + rSelections.add("Selections/Electron/Mass/Leading/hTPCChi2NCls", "hTPCChi2NCls", {HistType::kTH2F, {axisIVMSel, axisChi2}}); + rSelections.add("Selections/Electron/Mass/Leading/hTPCNClsCrossedRows", "hTPCNClsCrossedRows", {HistType::kTH2F, {axisIVMSel, axisTPCCrossed}}); + rSelections.addClone("Selections/Electron/Mass/Leading/", "Selections/Electron/Mass/Subleading/"); + rSelections.addClone("Selections/Electron/Mass/", "Selections/Electron/Rapidity/"); + rSelections.addClone("Selections/Electron/Mass/", "Selections/Electron/Pt/"); + rSelections.addClone("Selections/Electron/", "Selections/Muon/"); + + // PVContributors histograms + rPVContributors.add("PVContributors/hTrackPt", "hTrackPt", {HistType::kTH1F, {axisPt}}); + rPVContributors.add("PVContributors/hTrackEta", "hTrackEta", {HistType::kTH1F, {axisEta}}); + rPVContributors.add("PVContributors/hTrackPhi", "hTrackPhi", {HistType::kTH1F, {axisPhi}}); + rPVContributors.add("PVContributors/hTPCNClsFindable", "hTPCNClsFindable", {HistType::kTH1F, {axisTPC}}); + rPVContributors.add("PVContributors/hTPCNClsFindableMinusFound", "hTPCNClsFindableMinusFound", {HistType::kTH1F, {axisTPC}}); + rPVContributors.add("PVContributors/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisP, axisTPC}}); + rPVContributors.add("PVContributors/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axisPt, axisTPC}}); + rPVContributors.add("PVContributors/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); + rPVContributors.add("PVContributors/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axisEta, axisTPC}}); + rPVContributors.add("PVContributors/PID/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisP, axisBetaTOF}}); + + // TG histograms + rTG.add("TG/hTrackPt1", "hTrackPt1", {HistType::kTH1F, {axisPt}}); + rTG.add("TG/hTrackEta1", "hTrackEta1", {HistType::kTH1F, {axisEta}}); + rTG.add("TG/hTrackPhi1", "hTrackPhi1", {HistType::kTH1F, {axisPhi}}); + rTG.add("TG/hTrackPt2", "hTrackPt2", {HistType::kTH1F, {axisPt}}); + rTG.add("TG/hTrackEta2", "hTrackEta2", {HistType::kTH1F, {axisEta}}); + rTG.add("TG/hTrackPhi2", "hTrackPhi2", {HistType::kTH1F, {axisPhi}}); + rTG.add("TG/hTPCNClsFindable", "hTPCNClsFindable", {HistType::kTH1F, {axisTPC}}); + rTG.add("TG/hTPCNClsFindableMinusFound", "hTPCNClsFindableMinusFound", {HistType::kTH1F, {axisTPC}}); + rTG.add("TG/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisP, axisTPC}}); + rTG.add("TG/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axisPt, axisTPC}}); + rTG.add("TG/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); + rTG.add("TG/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axisEta, axisTPC}}); + rTG.add("TG/PID/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisP, axisBetaTOF}}); + rTG.add("TG/TPC/TPCNegVsPosSignal", "TPCNegVsPosSignal", HistType::kTH2F, {axisTPC, axisTPC}); + + // TGdaug histograms + rTGdaug.add("TGdaug/Muon/hTrackPt1", "hTrackPt1", {HistType::kTH1F, {axisPt}}); + rTGdaug.add("TGdaug/Muon/hTrackEta1", "hTrackEta1", {HistType::kTH1F, {axisEta}}); + rTGdaug.add("TGdaug/Muon/hTrackPhi1", "hTrackPhi1", {HistType::kTH1F, {axisPhi}}); + rTGdaug.add("TGdaug/Muon/hTrackPt2", "hTrackPt2", {HistType::kTH1F, {axisPt}}); + rTGdaug.add("TGdaug/Muon/hTrackEta2", "hTrackEta2", {HistType::kTH1F, {axisEta}}); + rTGdaug.add("TGdaug/Muon/hTrackPhi2", "hTrackPhi2", {HistType::kTH1F, {axisPhi}}); + rTGdaug.add("TGdaug/Muon/TPCNegVsPosSignal", "TPCNegVsPosSignal", HistType::kTH2F, {axisTPC, axisTPC}); + rTGdaug.add("TGdaug/Muon/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisP, axisTPC}}); + rTGdaug.add("TGdaug/Muon/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axisPt, axisTPC}}); + rTGdaug.add("TGdaug/Muon/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); + rTGdaug.add("TGdaug/Muon/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axisEta, axisTPC}}); + rTGdaug.add("TGdaug/Muon/PID/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisP, axisBetaTOF}}); + rTGdaug.addClone("TGdaug/Muon/", "TGdaug/Electron/"); + rTGdaug.addClone("TGdaug/Muon/", "TGdaug/Proton/"); + + // TGmuCand histograms + rTGdaugCand.add("TGdaugCand/Muon/hTrackPt1", "hTrackPt1", {HistType::kTH1F, {axisPt}}); + rTGdaugCand.add("TGdaugCand/Muon/hTrackEta1", "hTrackEta1", {HistType::kTH1F, {axisEta}}); + rTGdaugCand.add("TGdaugCand/Muon/hTrackPhi1", "hTrackPhi1", {HistType::kTH1F, {axisPhi}}); + rTGdaugCand.add("TGdaugCand/Muon/hTrackPt2", "hTrackPt2", {HistType::kTH1F, {axisPt}}); + rTGdaugCand.add("TGdaugCand/Muon/hTrackEta2", "hTrackEta2", {HistType::kTH1F, {axisEta}}); + rTGdaugCand.add("TGdaugCand/Muon/hTrackPhi2", "hTrackPhi2", {HistType::kTH1F, {axisPhi}}); + rTGdaugCand.add("TGdaugCand/Muon/hPairPt", "hPairPt", {HistType::kTH1F, {axisPt}}); + rTGdaugCand.add("TGdaugCand/Muon/hPairIVM", "hPairIVM", {HistType::kTH1F, {axisIVMWide}}); + rTGdaugCand.add("TGdaugCand/Muon/hJpsiPt", "hJpsiPt", {HistType::kTH1F, {axisPt}}); + rTGdaugCand.add("TGdaugCand/Muon/hJpsiRap", "hJpsiRap", {HistType::kTH1F, {axisEta}}); + rTGdaugCand.add("TGdaugCand/Muon/TPCNegVsPosSignal", "TPCNegVsPosSignal", HistType::kTH2F, {axisTPC, axisTPC}); + rTGdaugCand.add("TGdaugCand/Muon/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisP, axisTPC}}); + rTGdaugCand.add("TGdaugCand/Muon/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axisPt, axisTPC}}); + rTGdaugCand.add("TGdaugCand/Muon/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); + rTGdaugCand.add("TGdaugCand/Muon/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axisEta, axisTPC}}); + rTGdaugCand.add("TGdaugCand/Muon/PID/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisP, axisBetaTOF}}); + rTGdaugCand.addClone("TGdaugCand/Muon/", "TGdaugCand/Electron/"); + rTGdaugCand.addClone("TGdaugCand/Muon/", "TGdaugCand/Proton/"); + + // JPsiToEl histograms + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/hPt", "Pt of J/Psi ; p_{T} {GeV/c]", {HistType::kTH1F, {axisPt}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/hPt1", "pT of track 1 ; p_{T} {GeV/c]", {HistType::kTH1F, {axisPt}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/hPt2", "pT of track 2 ; p_{T} {GeV/c]", {HistType::kTH1F, {axisPt}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/hEta1", "eta of track 1 ; #eta {-]", {HistType::kTH1F, {axisEta}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/hEta2", "eta of track 2 ; #eta {-]", {HistType::kTH1F, {axisEta}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/hPhi1", "phi of track 1 ; #phi {-]", {HistType::kTH1F, {axisPhi}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/hPhi2", "phi of track 2 ; #phi {-]", {HistType::kTH1F, {axisPhi}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/hIVM", "J/Psi Invariant Mass ; m {GeV]", {HistType::kTH1F, {axisIVM}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/hRap", "Rap of J/Psi ; y {-]", {HistType::kTH1F, {axisEta}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/hEta", "Eta of J/Psi ; #eta {-]", {HistType::kTH1F, {axisEta}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/hPhi", "Phi of J/Psi ; #phi {-]", {HistType::kTH1F, {axisPhi}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/xnxn/hPt", "Pt of J/Psi ; p_{T} {GeV/c]", {HistType::kTH1F, {axisPt}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/xnxn/hPt1", "pT of track 1 ; p_{T} {GeV/c]", {HistType::kTH1F, {axisPt}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/xnxn/hPt2", "pT of track 2 ; p_{T} {GeV/c]", {HistType::kTH1F, {axisPt}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/xnxn/hEta1", "eta of track 1 ; #eta {-]", {HistType::kTH1F, {axisEta}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/xnxn/hEta2", "eta of track 2 ; #eta {-]", {HistType::kTH1F, {axisEta}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/xnxn/hPhi1", "phi of track 1 ; #phi {-]", {HistType::kTH1F, {axisPhi}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/xnxn/hPhi2", "phi of track 2 ; #phi {-]", {HistType::kTH1F, {axisPhi}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/xnxn/hIVM", "J/Psi Invariant Mass ; m {GeV]", {HistType::kTH1F, {axisIVM}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/xnxn/hRap", "Rap of J/Psi ; y {-]", {HistType::kTH1F, {axisEta}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/xnxn/hEta", "Eta of J/Psi ; #eta {-]", {HistType::kTH1F, {axisEta}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/xnxn/hPhi", "Phi of J/Psi ; #phi {-]", {HistType::kTH1F, {axisPhi}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisP, axisTPC}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axisPt, axisTPC}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axisEta, axisTPC}}); + rJpsiToDaug.add("JPsiToDaug/Electron/Coherent/PID/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisP, axisBetaTOF}}); + rJpsiToDaug.add("JPsiToDaug/Electron/NotCoherent/hIVM", "J/Psi Invariant Mass ; m {GeV]", {HistType::kTH1F, {axisIVM}}); + rJpsiToDaug.add("JPsiToDaug/Electron/NotCoherent/xnxn/hIVM", "J/Psi Invariant Mass ; m {GeV]", {HistType::kTH1F, {axisIVM}}); + rJpsiToDaug.add("JPsiToDaug/Electron/NotCoherent/onon/hIVM", "J/Psi Invariant Mass ; m {GeV]", {HistType::kTH1F, {axisIVM}}); + rJpsiToDaug.add("JPsiToDaug/Electron/NotCoherent/xnon/hIVM", "J/Psi Invariant Mass ; m {GeV]", {HistType::kTH1F, {axisIVM}}); + rJpsiToDaug.add("JPsiToDaug/Electron/NotCoherent/onxn/hIVM", "J/Psi Invariant Mass ; m {GeV]", {HistType::kTH1F, {axisIVM}}); + rJpsiToDaug.addClone("JPsiToDaug/Electron/Coherent/xnxn/", "JPsiToDaug/Electron/Coherent/onxn/"); + rJpsiToDaug.addClone("JPsiToDaug/Electron/Coherent/xnxn/", "JPsiToDaug/Electron/Coherent/onon/"); + rJpsiToDaug.addClone("JPsiToDaug/Electron/Coherent/xnxn/", "JPsiToDaug/Electron/Coherent/xnon/"); + rJpsiToDaug.addClone("JPsiToDaug/Electron/Coherent/", "JPsiToDaug/Electron/Incoherent/"); + rJpsiToDaug.addClone("JPsiToDaug/Electron/", "JPsiToDaug/Muon/"); + rJpsiToDaug.addClone("JPsiToDaug/Electron/", "JPsiToDaug/Proton/"); + + // Correlation histograms + rCorrelation.add("Correlation/Muon/Coherent/AccoplAngle", "AccoplAngle", {HistType::kTH1F, {axisAccAngle}}); + rCorrelation.add("Correlation/Muon/Coherent/CosTheta", "CosTheta", {HistType::kTH1F, {axisAngTheta}}); + rCorrelation.add("Correlation/Muon/Coherent/Phi", "Phi", {HistType::kTH1F, {axisPhi}}); + rCorrelation.add("Correlation/Muon/Coherent/Phi1", "Phi1", {HistType::kTH1F, {axisPhi}}); + rCorrelation.add("Correlation/Muon/Coherent/Phi2", "Phi2", {HistType::kTH1F, {axisPhi}}); + rCorrelation.add("Correlation/Muon/Coherent/CosThetaPhi", "CosThetaPhi", {HistType::kTH2F, {{axisAngTheta}, {axisPhi}}}); + rCorrelation.addClone("Correlation/Muon/Coherent/", "Correlation/Muon/Incoherent/"); + rCorrelation.addClone("Correlation/Muon/", "Correlation/Electron/"); + rCorrelation.addClone("Correlation/Muon/", "Correlation/Proton/"); + + // Asymmetry histograms + rAsymmetry.add("Asymmetry/Muon/Coherent/DeltaPhi", "DeltaPhi", {HistType::kTH1F, {{180, -PI, PI}}}); + rAsymmetry.add("Asymmetry/Muon/Coherent/xnxn/DeltaPhi", "DeltaPhi", {HistType::kTH1F, {{180, -PI, PI}}}); + rAsymmetry.add("Asymmetry/Muon/Coherent/DeltaPhiRandom", "DeltaPhiRandom", {HistType::kTH1F, {{180, -PI, PI}}}); + rAsymmetry.add("Asymmetry/Muon/Coherent/xnxn/DeltaPhiRandom", "DeltaPhiRandom", {HistType::kTH1F, {{180, -PI, PI}}}); + rAsymmetry.addClone("Asymmetry/Muon/Coherent/xnxn/", "Asymmetry/Muon/Coherent/onxn/"); + rAsymmetry.addClone("Asymmetry/Muon/Coherent/xnxn/", "Asymmetry/Muon/Coherent/onon/"); + rAsymmetry.addClone("Asymmetry/Muon/Coherent/xnxn/", "Asymmetry/Muon/Coherent/xnon/"); + rAsymmetry.addClone("Asymmetry/Muon/Coherent/", "Asymmetry/Muon/Incoherent/"); + rAsymmetry.addClone("Asymmetry/Muon/", "Asymmetry/Electron/"); + + // MC histograms + rMC.add("MC/hNumberOfMCCollisions", "hNumberOfCollisions", {HistType::kTH1F, {{10, 0, 10}}}); + rMC.add("MC/hNumberOfRecoCollisions", "hNumberOfRecoCollisions", {HistType::kTH1F, {{10, 0, 10}}}); + rMC.add("MC/hNumberOfTrueCollisions", "hNumberOfTrueCollisions", {HistType::kTH1F, {{10, 0, 10}}}); + rMC.add("MC/Muon/hNumberOfMCTracks", "hNumberOfMCTracks", {HistType::kTH1F, {{10, 0, 10}}}); + rMC.add("MC/hNumberOfMatchedMCTracks", "hNumberOfMatchedMCTracks", {HistType::kTH1F, {{10, 0, 10}}}); + rMC.add("MC/hPosZ", "hPosZ", {HistType::kTH1F, {{60, -15, 15}}}); + rMC.add("MC/hMothersPdg", "hMothersPdg", {HistType::kTH1F, {{1000, -500, 500}}}); + rMC.add("MC/hPdg", "hPdg", {HistType::kTH1F, {{1000, -500, 500}}}); + rMC.add("MC/Muon/hEta1", "hEta1", {HistType::kTH1F, {axisEta}}); + rMC.add("MC/Muon/hEta2", "hEta2", {HistType::kTH1F, {axisEta}}); + rMC.add("MC/Muon/hEta", "hEta", {HistType::kTH1F, {axisEta}}); + rMC.add("MC/Muon/hPhi1", "hPhi1", {HistType::kTH1F, {axisPhi}}); + rMC.add("MC/Muon/hPhi2", "hPhi2", {HistType::kTH1F, {axisPhi}}); + rMC.add("MC/Muon/hPhi", "hPhi", {HistType::kTH1F, {axisPhi}}); + rMC.add("MC/Muon/hIVM", "hIVM", {HistType::kTH1F, {axisIVM}}); + rMC.add("MC/Muon/hRapidity", "hRapidity", {HistType::kTH1F, {axisEta}}); + rMC.add("MC/Muon/hPt1", "hPt1", {HistType::kTH1F, {axisPt}}); + rMC.add("MC/Muon/hPt2", "hPt2", {HistType::kTH1F, {axisPt}}); + rMC.add("MC/Muon/hPt", "hPt", {HistType::kTH1F, {axisPt}}); + rMC.add("MC/hResolution", "hResolution", {HistType::kTH1F, {{100, -10, 10}}}); + rMC.add("MC/hResolutionPhi", "hResolutionPhi", {HistType::kTH1F, {{100, -0.01, 0.01}}}); + } + + bool cutITSLayers(uint8_t itsClusterMap) const + { + std::vector>> requiredITSHits{}; + requiredITSHits.push_back(std::make_pair(1, std::array{0, 1, 2})); // at least one hit in the innermost layer + constexpr uint8_t kBit = 1; + for (const auto& itsRequirement : requiredITSHits) { + auto hits = std::count_if(itsRequirement.second.begin(), itsRequirement.second.end(), [&](auto&& requiredLayer) { return itsClusterMap & (kBit << requiredLayer); }); + + if ((itsRequirement.first == -1) && (hits > 0)) { + return false; // no hits were required in specified layers + } else if (hits < itsRequirement.first) { + return false; // not enough hits found in specified layers + } + } + return true; + } + + template + bool goodTrackCuts(T const& track) + { + // choose only PV contributors + if (!track.isPVContributor()) { + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(1); + return false; + } + // pT cut to choose only tracks contributing to J/psi + if (track.pt() < cutPtTrack) { + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(2); + return false; + } + // acceptance cut (TPC) + if (std::abs(RecoDecay::eta(std::array{track.px(), track.py(), track.pz()})) > etaCut) { + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(3); + return false; + } + // DCA + if (std::abs(track.dcaZ()) > dcaZCut) { + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(4); + return false; + } + if (dcaCut) { + float dcaXYPtCut = 0.0105f + 0.0350f / std::pow(track.pt(), 1.1f); + if (std::abs(track.dcaXY()) > dcaXYPtCut) { + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(5); + return false; + } + } else { + if (std::abs(track.dcaXY()) > dcaXYCut) { + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(5); + return false; + } + } + // ITS + if (!track.hasITS()) { + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(6); + return false; + } + if (track.itsNCls() < itsNClsCut) { + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(7); + return false; + } + if (!cutITSLayers(track.itsClusterMap())) { + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(8); + return false; + } + if (track.itsChi2NCl() > itsChi2NClsCut) { + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(9); + return false; + } + // TPC + if (!track.hasTPC()) { + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(10); + return false; + } + if (track.tpcNClsCrossedRows() < tpcNClsCrossedRowsCut) { + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(11); + return false; + } + if (track.tpcChi2NCl() > tpcChi2NCls) { + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(12); + return false; // TPC chi2 + } + if ((track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) < tpcMinNCls) { + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(13); + return false; + } + if (newCutTPC) { + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < tpcCrossedOverFindable) { + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(14); + return false; + } + } + + return true; + } + + bool candidateCuts(float massJpsi, float rapJpsi) + { + if (std::abs(rapJpsi) > rapCut) { + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(15); + return false; + } + + if (massJpsi < 2.0f) { + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(16); + return false; + } + + return true; + } + + static constexpr std::string_view DaugType[3] = {"Electron/", "Muon/", "Proton/"}; + static constexpr std::string_view ProdType[2] = {"Coherent/", "Incoherent/"}; + static constexpr std::string_view NeutronClass[5] = {"", "xnxn/", "onxn/", "onon/", "xnon/"}; + + template + void fillSelections(const T& leadingP, const T& subleadingP, float massJpsi, float rapJpsi, std::array mother) + { + // selections + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Mass/Leading/hITSNCls"))->Fill(massJpsi, leadingP.itsNCls()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Mass/Leading/hITSChi2NCls"))->Fill(massJpsi, leadingP.itsChi2NCl()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Mass/Leading/hTPCNCls"))->Fill(massJpsi, leadingP.tpcNClsFindable() - leadingP.tpcNClsFindableMinusFound()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Mass/Leading/hTPCChi2NCls"))->Fill(massJpsi, leadingP.tpcChi2NCl()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Mass/Leading/hTPCNClsCrossedRows"))->Fill(massJpsi, subleadingP.tpcNClsCrossedRows()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Mass/Subleading/hITSNCls"))->Fill(massJpsi, subleadingP.itsNCls()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Mass/Subleading/hITSChi2NCls"))->Fill(massJpsi, subleadingP.itsChi2NCl()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Mass/Subleading/hTPCNCls"))->Fill(massJpsi, subleadingP.tpcNClsFindable() - subleadingP.tpcNClsFindableMinusFound()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Mass/Subleading/hTPCChi2NCls"))->Fill(massJpsi, subleadingP.tpcChi2NCl()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Mass/Subleading/hTPCNClsCrossedRows"))->Fill(massJpsi, subleadingP.tpcNClsCrossedRows()); + + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Rapidity/Leading/hITSNCls"))->Fill(rapJpsi, leadingP.itsNCls()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Rapidity/Leading/hITSChi2NCls"))->Fill(rapJpsi, leadingP.itsChi2NCl()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Rapidity/Leading/hTPCNCls"))->Fill(rapJpsi, leadingP.tpcNClsFindable() - leadingP.tpcNClsFindableMinusFound()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Rapidity/Leading/hTPCChi2NCls"))->Fill(rapJpsi, leadingP.tpcChi2NCl()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Rapidity/Leading/hTPCNClsCrossedRows"))->Fill(rapJpsi, subleadingP.tpcNClsCrossedRows()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Rapidity/Subleading/hITSNCls"))->Fill(rapJpsi, subleadingP.itsNCls()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Rapidity/Subleading/hITSChi2NCls"))->Fill(rapJpsi, subleadingP.itsChi2NCl()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Rapidity/Subleading/hTPCNCls"))->Fill(rapJpsi, subleadingP.tpcNClsFindable() - subleadingP.tpcNClsFindableMinusFound()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Rapidity/Subleading/hTPCChi2NCls"))->Fill(rapJpsi, subleadingP.tpcChi2NCl()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Rapidity/Subleading/hTPCNClsCrossedRows"))->Fill(rapJpsi, subleadingP.tpcNClsCrossedRows()); + + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Pt/Leading/hITSNCls"))->Fill(RecoDecay::pt(mother), leadingP.itsNCls()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Pt/Leading/hITSChi2NCls"))->Fill(RecoDecay::pt(mother), leadingP.itsChi2NCl()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Pt/Leading/hTPCNCls"))->Fill(RecoDecay::pt(mother), leadingP.tpcNClsFindable() - leadingP.tpcNClsFindableMinusFound()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Pt/Leading/hTPCChi2NCls"))->Fill(RecoDecay::pt(mother), leadingP.tpcChi2NCl()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Pt/Leading/hTPCNClsCrossedRows"))->Fill(RecoDecay::pt(mother), subleadingP.tpcNClsCrossedRows()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Pt/Subleading/hITSNCls"))->Fill(RecoDecay::pt(mother), subleadingP.itsNCls()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Pt/Subleading/hITSChi2NCls"))->Fill(RecoDecay::pt(mother), subleadingP.itsChi2NCl()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Pt/Subleading/hTPCNCls"))->Fill(RecoDecay::pt(mother), subleadingP.tpcNClsFindable() - subleadingP.tpcNClsFindableMinusFound()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Pt/Subleading/hTPCChi2NCls"))->Fill(RecoDecay::pt(mother), subleadingP.tpcChi2NCl()); + rSelections.get(HIST("Selections/") + HIST(DaugType[daug]) + HIST("Pt/Subleading/hTPCNClsCrossedRows"))->Fill(RecoDecay::pt(mother), subleadingP.tpcNClsCrossedRows()); + } + + template + void fillTGdaug(const T& trkDaughter1, const T& trkDaughter2, std::array daughter1, std::array daughter2) + { + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("hTrackPt1"))->Fill(trkDaughter1.pt()); + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("hTrackPt2"))->Fill(trkDaughter2.pt()); + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("hTrackEta1"))->Fill(RecoDecay::eta(daughter1)); + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("hTrackEta2"))->Fill(RecoDecay::eta(daughter2)); + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("hTrackPhi1"))->Fill(RecoDecay::phi(daughter1)); + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("hTrackPhi2"))->Fill(RecoDecay::phi(daughter2)); + + if (trkDaughter1.hasTPC()) { + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tpcSignal()); + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("PID/hTPCVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tpcSignal()); + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tpcSignal()); + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tpcSignal()); + if (trkDaughter1.sign() < 0) { + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("TPCNegVsPosSignal"))->Fill(trkDaughter1.tpcSignal(), trkDaughter2.tpcSignal()); + } else { + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("TPCNegVsPosSignal"))->Fill(trkDaughter2.tpcSignal(), trkDaughter1.tpcSignal()); + } + } + if (trkDaughter2.hasTPC()) { + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("PID/hTPCVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tpcSignal()); + } + if (trkDaughter1.hasTOF()) { + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.beta()); + } + if (trkDaughter2.hasTOF()) { + + rTGdaug.get(HIST("TGdaug/") + HIST(DaugType[daug]) + HIST("PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.beta()); + } + } + template + void fillCand(const T& trkDaughter1, const T& trkDaughter2, std::array daughter1, std::array daughter2, std::array mother, float massJpsi, bool xnxn, bool onon, bool onxn, bool xnon) + { + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("hTrackPt1"))->Fill(trkDaughter1.pt()); + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("hTrackPt2"))->Fill(trkDaughter2.pt()); + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("hTrackEta1"))->Fill(RecoDecay::eta(daughter1)); + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("hTrackEta2"))->Fill(RecoDecay::eta(daughter2)); + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("hTrackPhi1"))->Fill(RecoDecay::phi(daughter1)); + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("hTrackPhi2"))->Fill(RecoDecay::phi(daughter2)); + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("hPairPt"))->Fill(RecoDecay::pt(mother)); + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("hPairIVM"))->Fill(massJpsi); + + if (trkDaughter1.hasTPC()) { + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tpcSignal()); + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("PID/hTPCVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tpcSignal()); + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tpcSignal()); + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tpcSignal()); + } + if (trkDaughter2.hasTPC()) { + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("PID/hTPCVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tpcSignal()); + } + if (trkDaughter1.hasTOF()) { + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.beta()); + } + if (trkDaughter2.hasTOF()) { + rTGdaugCand.get(HIST("TGdaugCand/") + HIST(DaugType[daug]) + HIST("PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.beta()); + } + + if (RecoDecay::pt(mother) < 0.2f) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST("Coherent/hIVM"))->Fill(massJpsi); + if (xnxn) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST("Coherent/xnxn/hIVM"))->Fill(massJpsi); + } else if (onxn) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST("Coherent/onxn/hIVM"))->Fill(massJpsi); + } else if (xnon) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST("Coherent/xnon/hIVM"))->Fill(massJpsi); + } else if (onon) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST("Coherent/onon/hIVM"))->Fill(massJpsi); + } + } else if (RecoDecay::pt(mother) > 0.4f) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST("NotCoherent/hIVM"))->Fill(massJpsi); + if (xnxn) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST("NotCoherent/xnxn/hIVM"))->Fill(massJpsi); + } else if (onxn) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST("NotCoherent/onxn/hIVM"))->Fill(massJpsi); + } else if (xnon) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST("NotCoherent/xnon/hIVM"))->Fill(massJpsi); + } else if (onon) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST("NotCoherent/onon/hIVM"))->Fill(massJpsi); + } + } + if (RecoDecay::pt(mother) > 0.2f) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST("Incoherent/hIVM"))->Fill(massJpsi); + if (xnxn) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST("Incoherent/xnxn/hIVM"))->Fill(massJpsi); + } else if (onxn) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST("Incoherent/onxn/hIVM"))->Fill(massJpsi); + } else if (xnon) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST("Incoherent/xnon/hIVM"))->Fill(massJpsi); + } else if (onon) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST("Incoherent/onon/hIVM"))->Fill(massJpsi); + } + } + } + + template + void fillPeak(const T& trkDaughter1, const T& trkDaughter2, std::array daughter1, std::array daughter2, std::array mother, float rapJpsi) + { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST(NeutronClass[neutron]) + HIST("hPt1"))->Fill(trkDaughter1.pt()); + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST(NeutronClass[neutron]) + HIST("hPt2"))->Fill(trkDaughter2.pt()); + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST(NeutronClass[neutron]) + HIST("hEta1"))->Fill(RecoDecay::eta(daughter1)); + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST(NeutronClass[neutron]) + HIST("hEta2"))->Fill(RecoDecay::eta(daughter2)); + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST(NeutronClass[neutron]) + HIST("hPhi1"))->Fill(RecoDecay::phi(daughter1)); + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST(NeutronClass[neutron]) + HIST("hPhi2"))->Fill(RecoDecay::phi(daughter2)); + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST(NeutronClass[neutron]) + HIST("hPt"))->Fill(RecoDecay::pt(mother)); + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST(NeutronClass[neutron]) + HIST("hEta"))->Fill(RecoDecay::eta(mother)); + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST(NeutronClass[neutron]) + HIST("hRap"))->Fill(rapJpsi); + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST(NeutronClass[neutron]) + HIST("hPhi"))->Fill(RecoDecay::phi(mother)); + + if (trkDaughter1.hasTPC()) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST("PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tpcSignal()); + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST("PID/hTPCVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tpcSignal()); + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST("PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tpcSignal()); + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST("PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tpcSignal()); + } + if (trkDaughter2.hasTPC()) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST("PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST("PID/hTPCVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST("PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST("PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tpcSignal()); + } + if (trkDaughter1.hasTOF()) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST("PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.beta()); + } + if (trkDaughter2.hasTOF()) { + rJpsiToDaug.get(HIST("JPsiToDaug/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST("PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.beta()); + } + } + + template + void fillCorrAsy(std::array daughter1, std::array daughter2, double dp, double dpRandom, float* q) + { + if (neutron == 0) { + rCorrelation.get(HIST("Correlation/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST("Phi1"))->Fill(RecoDecay::phi(daughter1), 1.); + rCorrelation.get(HIST("Correlation/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST("Phi2"))->Fill(RecoDecay::phi(daughter2), 1.); + rCorrelation.get(HIST("Correlation/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST("Phi"))->Fill(q[1], 1.); + rCorrelation.get(HIST("Correlation/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST("CosTheta"))->Fill(q[2], 1.); + rCorrelation.get(HIST("Correlation/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST("AccoplAngle"))->Fill(q[0], 1.); + rCorrelation.get(HIST("Correlation/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST("CosThetaPhi"))->Fill(q[2], q[1]); + } + + rAsymmetry.get(HIST("Asymmetry/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST(NeutronClass[neutron]) + HIST("DeltaPhi"))->Fill(dp); + rAsymmetry.get(HIST("Asymmetry/") + HIST(DaugType[daug]) + HIST(ProdType[prod]) + HIST(NeutronClass[neutron]) + HIST("DeltaPhiRandom"))->Fill(dpRandom); + } + + template + void fillHistograms(C collision, Ts tracks) + { + rStatistics.get(HIST("Statistics/hCutCounterCollisions"))->Fill(0); // number of collisions without any cuts + + // check UPC vs standard + if (doOnlyUPC) { + if (collision.flags() == 0) { + return; + } + } + if (doOnlyStandard) { + if (collision.flags() == 1) { + return; + } + } + + if (std::abs(collision.posZ()) > cutVertexZ) { + rStatistics.get(HIST("Statistics/hCutCounterCollisions"))->Fill(1); + return; + } + + // distinguish ZDC classes + bool xnxn = false, onon = false, xnon = false, onxn = false; + int neutronClass = -1; + if (collision.energyCommonZNA() < znEnergyCut && collision.energyCommonZNC() < znEnergyCut) { + onon = true; + neutronClass = 0; + } + if (collision.energyCommonZNA() > znEnergyCut && std::abs(collision.timeZNA()) < znTimeCut && collision.energyCommonZNC() > znEnergyCut && std::abs(collision.timeZNC()) < znTimeCut) { + xnxn = true; + neutronClass = 1; + } + if (collision.energyCommonZNA() > znEnergyCut && std::abs(collision.timeZNA()) < znTimeCut && collision.energyCommonZNC() < znEnergyCut) { + xnon = true; + neutronClass = 2; + } + if (collision.energyCommonZNA() < znEnergyCut && collision.energyCommonZNC() > znEnergyCut && std::abs(collision.timeZNC()) < znTimeCut) { + onxn = true; + neutronClass = 3; + } + + // loop over tracks without selections + for (const auto& track : tracks) { + float trkPx = track.px(); + float trkPy = track.py(); + float trkPz = track.pz(); + + rStatistics.get(HIST("Statistics/hNumberOfTracks"))->Fill(0); + rStatistics.get(HIST("Statistics/hCutCounterTracks"))->Fill(0); + if (track.isPVContributor() == 1) { + rStatistics.get(HIST("Statistics/hNumberOfTracks"))->Fill(1); + rPVContributors.get(HIST("PVContributors/hTrackPt"))->Fill(track.pt()); + rPVContributors.get(HIST("PVContributors/hTrackEta"))->Fill(RecoDecay::eta(std::array{trkPx, trkPy, trkPz})); + rPVContributors.get(HIST("PVContributors/hTrackPhi"))->Fill(RecoDecay::phi(trkPx, trkPy)); + + if (track.hasTPC()) { + rPVContributors.get(HIST("PVContributors/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkPx, trkPy, trkPz), track.tpcSignal()); + rPVContributors.get(HIST("PVContributors/PID/hTPCVsPt"))->Fill(track.pt(), track.tpcSignal()); + rPVContributors.get(HIST("PVContributors/PID/hTPCVsEta"))->Fill(RecoDecay::eta(std::array{trkPx, trkPy, trkPz}), track.tpcSignal()); + rPVContributors.get(HIST("PVContributors/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(trkPx, trkPy), track.tpcSignal()); + rPVContributors.get(HIST("PVContributors/hTPCNClsFindable"))->Fill(track.tpcNClsFindable()); + rPVContributors.get(HIST("PVContributors/hTPCNClsFindableMinusFound"))->Fill(track.tpcNClsFindableMinusFound()); + } + + if (track.hasTOF()) { + rPVContributors.get(HIST("PVContributors/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkPx, trkPy, trkPz), track.beta()); + } + } + + rRawData.get(HIST("RawData/hTrackPt"))->Fill(track.pt()); + rRawData.get(HIST("RawData/hTrackEta"))->Fill(RecoDecay::eta(std::array{trkPx, trkPy, trkPz})); + rRawData.get(HIST("RawData/hTrackPhi"))->Fill(RecoDecay::phi(trkPx, trkPy)); + rRawData.get(HIST("RawData/hTrackDCAXYZ"))->Fill(track.dcaXY(), track.dcaZ()); + rRawData.get(HIST("RawData/hTPCNClsFindable"))->Fill(track.tpcNClsFindable()); + rRawData.get(HIST("RawData/hTPCNClsFindableMinusFound"))->Fill(track.tpcNClsFindableMinusFound()); + rRawData.get(HIST("RawData/hITSNCls"))->Fill(track.itsNCls()); + rRawData.get(HIST("RawData/hTPCNCls"))->Fill(track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()); + rRawData.get(HIST("RawData/hITSChi2NCls"))->Fill(track.itsChi2NCl()); + rRawData.get(HIST("RawData/hTPCChi2NCls"))->Fill(track.tpcChi2NCl()); + rRawData.get(HIST("RawData/QA/FIT/hTotFT0AmplitudeA"))->Fill(collision.totalFT0AmplitudeA()); + rRawData.get(HIST("RawData/QA/FIT/hTotFT0AmplitudeC"))->Fill(collision.totalFT0AmplitudeC()); + rRawData.get(HIST("RawData/QA/FIT/hTotFV0AmplitudeA"))->Fill(collision.totalFV0AmplitudeA()); + rRawData.get(HIST("RawData/QA/FIT/hTotFDDAmplitudeA"))->Fill(collision.totalFDDAmplitudeA()); + rRawData.get(HIST("RawData/QA/FIT/hTotFDDAmplitudeC"))->Fill(collision.totalFDDAmplitudeC()); + rRawData.get(HIST("RawData/QA/FIT/hTimeFT0A"))->Fill(collision.timeFT0A()); + rRawData.get(HIST("RawData/QA/FIT/hTimeFT0C"))->Fill(collision.timeFT0C()); + rRawData.get(HIST("RawData/QA/FIT/hTimeFV0A"))->Fill(collision.timeFV0A()); + rRawData.get(HIST("RawData/QA/FIT/hTimeFDDA"))->Fill(collision.timeFDDA()); + rRawData.get(HIST("RawData/QA/FIT/hTimeFDDC"))->Fill(collision.timeFDDC()); + + if (track.hasTPC()) { + rRawData.get(HIST("RawData/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkPx, trkPy, trkPz), track.tpcSignal()); + rRawData.get(HIST("RawData/PID/hTPCVsPt"))->Fill(track.pt(), track.tpcSignal()); + rRawData.get(HIST("RawData/PID/hTPCVsEta"))->Fill(RecoDecay::eta(std::array{trkPx, trkPy, trkPz}), track.tpcSignal()); + rRawData.get(HIST("RawData/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(trkPx, trkPy), track.tpcSignal()); + } + + if (track.hasTOF()) { + rRawData.get(HIST("RawData/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkPx, trkPy, trkPz), track.beta()); + } + } + + int countGT = 0; + std::vector trkIdx; + // loop over tracks with selections + + rRawData.get(HIST("RawData/hPositionX"))->Fill(collision.posX()); + rRawData.get(HIST("RawData/hPositionY"))->Fill(collision.posY()); + rRawData.get(HIST("RawData/hPositionZ"))->Fill(collision.posZ()); + rRawData.get(HIST("RawData/hPositionXY"))->Fill(collision.posX(), collision.posY()); + rRawData.get(HIST("RawData/QA/ZDC/hZNACommonEnergy"))->Fill(collision.energyCommonZNA()); + rRawData.get(HIST("RawData/QA/ZDC/hZNCCommonEnergy"))->Fill(collision.energyCommonZNC()); + rRawData.get(HIST("RawData/QA/ZDC/hZNAvsZNCCommonEnergy"))->Fill(collision.energyCommonZNA(), collision.energyCommonZNC()); + rRawData.get(HIST("RawData/QA/ZDC/hZNCTime"))->Fill(collision.timeZNC()); + rRawData.get(HIST("RawData/QA/ZDC/hZNATime"))->Fill(collision.timeZNA()); + rRawData.get(HIST("RawData/QA/ZDC/hZNAvsZNCTime"))->Fill(collision.timeZNA(), collision.timeZNC()); + + for (const auto& track : tracks) { + + rStatistics.get(HIST("Statistics/hNumberOfTracks"))->Fill(2.); + + // select good tracks + if (goodTrackCuts(track) != 1) { + continue; + } + + countGT++; + trkIdx.push_back(track.index()); + } + + rStatistics.get(HIST("Statistics/hNumberOfTracks"))->Fill(3., countGT); + rStatistics.get(HIST("Statistics/hNumberGT"))->Fill(countGT); + + float massEl = o2::constants::physics::MassElectron; + float massMu = o2::constants::physics::MassMuonMinus; + float massPr = o2::constants::physics::MassProton; + + if (countGT == 2) { + TLorentzVector mom, daughter[2]; + auto trkDaughter1 = tracks.iteratorAt(trkIdx[0]); + auto trkDaughter2 = tracks.iteratorAt(trkIdx[1]); + + if ((trkDaughter1.sign() * trkDaughter2.sign()) != -1) { + return; + } + + if (chargeOrdered) { + if (tracks.iteratorAt(trkIdx[0]).sign() < 0) { + trkDaughter1 = tracks.iteratorAt(trkIdx[0]); + trkDaughter2 = tracks.iteratorAt(trkIdx[1]); + } else { + trkDaughter1 = tracks.iteratorAt(trkIdx[1]); + trkDaughter2 = tracks.iteratorAt(trkIdx[0]); + } + } + + std::array daughter1 = {trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()}; + std::array daughter2 = {trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()}; + + rTG.get(HIST("TG/hTrackPt1"))->Fill(trkDaughter1.pt()); + rTG.get(HIST("TG/hTrackPt2"))->Fill(trkDaughter2.pt()); + rTG.get(HIST("TG/hTrackEta1"))->Fill(RecoDecay::eta(daughter1)); + rTG.get(HIST("TG/hTrackEta2"))->Fill(RecoDecay::eta(daughter2)); + rTG.get(HIST("TG/hTrackPhi1"))->Fill(RecoDecay::phi(daughter1)); + rTG.get(HIST("TG/hTrackPhi2"))->Fill(RecoDecay::phi(daughter2)); + + if (trkDaughter1.hasTPC()) { + rTG.get(HIST("TG/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tpcSignal()); + rTG.get(HIST("TG/PID/hTPCVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tpcSignal()); + rTG.get(HIST("TG/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tpcSignal()); + rTG.get(HIST("TG/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tpcSignal()); + rTG.get(HIST("TG/hTPCNClsFindable"))->Fill(trkDaughter1.tpcNClsFindable()); + rTG.get(HIST("TG/hTPCNClsFindableMinusFound"))->Fill(trkDaughter1.tpcNClsFindableMinusFound()); + if (trkDaughter1.sign() < 0) { + rTG.get(HIST("TG/TPC/TPCNegVsPosSignal"))->Fill(trkDaughter1.tpcSignal(), trkDaughter2.tpcSignal()); + } else { + rTG.get(HIST("TG/TPC/TPCNegVsPosSignal"))->Fill(trkDaughter2.tpcSignal(), trkDaughter1.tpcSignal()); + } + } + if (trkDaughter2.hasTPC()) { + rTG.get(HIST("TG/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); + rTG.get(HIST("TG/PID/hTPCVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); + rTG.get(HIST("TG/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); + rTG.get(HIST("TG/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tpcSignal()); + rTG.get(HIST("TG/hTPCNClsFindable"))->Fill(trkDaughter2.tpcNClsFindable()); + rTG.get(HIST("TG/hTPCNClsFindableMinusFound"))->Fill(trkDaughter2.tpcNClsFindableMinusFound()); + } + if (trkDaughter1.hasTOF()) { + rTG.get(HIST("TG/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.beta()); + } + if (trkDaughter2.hasTOF()) { + rTG.get(HIST("TG/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.beta()); + } + + if (doElectrons) { + if (RecoDecay::sumOfSquares(trkDaughter1.tpcNSigmaMu(), trkDaughter2.tpcNSigmaMu()) > RecoDecay::sumOfSquares(trkDaughter1.tpcNSigmaEl(), trkDaughter2.tpcNSigmaEl())) { + + auto ene1 = RecoDecay::e(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz(), massEl); + auto ene2 = RecoDecay::e(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz(), massEl); + daughter[0].SetPxPyPzE(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz(), ene1); + daughter[1].SetPxPyPzE(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz(), ene2); + mom = daughter[0] + daughter[1]; + + std::array mother = {trkDaughter1.px() + trkDaughter2.px(), trkDaughter1.py() + trkDaughter2.py(), trkDaughter1.pz() + trkDaughter2.pz()}; + + auto arrMom = std::array{daughter1, daughter2}; + float massJpsi = RecoDecay::m(arrMom, std::array{massEl, massEl}); + float rapJpsi = RecoDecay::y(mother, massJpsi); + + auto leadingP = RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()) > RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()) ? trkDaughter1 : trkDaughter2; + auto subleadingP = (leadingP == trkDaughter1) ? trkDaughter1 : trkDaughter2; + + // TGdaug + fillTGdaug<0>(trkDaughter1, trkDaughter2, daughter1, daughter2); + + // selections + fillSelections<0>(leadingP, subleadingP, massJpsi, rapJpsi, mother); + + if (candidateCuts(massJpsi, rapJpsi) != 1) { + return; + } + + // TGdaugCand + fillCand<0>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, massJpsi, xnxn, onon, onxn, xnon); + + double dp = DeltaPhi(daughter[0], daughter[1]); + float* q = correlation(&daughter[0], &daughter[1], &mom); + double dpRandom = DeltaPhiRandom(daughter[0], daughter[1]); + + if ((massJpsi < maxJpsiMass) && (massJpsi > minJpsiMass)) { + rTGdaugCand.get(HIST("TGdaugCand/Electron/hJpsiPt"))->Fill(RecoDecay::pt(mother)); + rTGdaugCand.get(HIST("TGdaugCand/Electron/hJpsiRap"))->Fill(rapJpsi); + + if (trkDaughter1.sign() < 0) { + rTGdaugCand.get(HIST("TGdaugCand/Electron/TPCNegVsPosSignal"))->Fill(trkDaughter1.tpcSignal(), trkDaughter2.tpcSignal()); + } else { + rTGdaugCand.get(HIST("TGdaugCand/Electron/TPCNegVsPosSignal"))->Fill(trkDaughter2.tpcSignal(), trkDaughter1.tpcSignal()); + } + + if (RecoDecay::pt(mother) < 0.2f) { + fillPeak<0, 0, 0>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + + if (xnxn) { + fillPeak<0, 0, 1>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<0, 0, 1>(daughter1, daughter2, dp, dpRandom, q); + } else if (onon) { + fillPeak<0, 0, 3>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<0, 0, 3>(daughter1, daughter2, dp, dpRandom, q); + } else if (xnon) { + fillPeak<0, 0, 4>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<0, 0, 4>(daughter1, daughter2, dp, dpRandom, q); + } else if (onxn) { + fillPeak<0, 0, 2>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<0, 0, 2>(daughter1, daughter2, dp, dpRandom, q); + } + fillCorrAsy<0, 0, 0>(daughter1, daughter2, dp, dpRandom, q); + + } // end coherent electrons + if (RecoDecay::pt(mother) > 0.2f) { + fillPeak<0, 1, 0>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<0, 1, 0>(daughter1, daughter2, dp, dpRandom, q); + + if (xnxn) { + fillPeak<0, 1, 1>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + } else if (onon) { + fillPeak<0, 1, 3>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<0, 1, 3>(daughter1, daughter2, dp, dpRandom, q); + } else if (xnon) { + fillPeak<0, 1, 4>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<0, 1, 4>(daughter1, daughter2, dp, dpRandom, q); + } else if (onxn) { + fillPeak<0, 1, 2>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<0, 1, 2>(daughter1, daughter2, dp, dpRandom, q); + } + + } // end incoherent electrons + } // end mass cut + delete[] q; + } + } // end electrons + if (doMuons) { + if (RecoDecay::sumOfSquares(trkDaughter1.tpcNSigmaEl(), trkDaughter2.tpcNSigmaEl()) > RecoDecay::sumOfSquares(trkDaughter1.tpcNSigmaMu(), trkDaughter2.tpcNSigmaMu())) { + + auto ene1 = RecoDecay::e(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz(), massMu); + auto ene2 = RecoDecay::e(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz(), massMu); + daughter[0].SetPxPyPzE(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz(), ene1); + daughter[1].SetPxPyPzE(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz(), ene2); + mom = daughter[0] + daughter[1]; + + std::array mother = {trkDaughter1.px() + trkDaughter2.px(), trkDaughter1.py() + trkDaughter2.py(), trkDaughter1.pz() + trkDaughter2.pz()}; + + auto arrMom = std::array{daughter1, daughter2}; + float massJpsi = RecoDecay::m(arrMom, std::array{massMu, massMu}); + float rapJpsi = RecoDecay::y(mother, massJpsi); + + auto leadingP = RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()) > RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()) ? trkDaughter1 : trkDaughter2; + auto subleadingP = (leadingP == trkDaughter1) ? trkDaughter1 : trkDaughter2; + + // TGdaug + fillTGdaug<1>(trkDaughter1, trkDaughter2, daughter1, daughter2); + // selections + fillSelections<1>(leadingP, subleadingP, massJpsi, rapJpsi, mother); + + if (candidateCuts(massJpsi, rapJpsi) != 1) { + return; + } + + // TGdaugCand + fillCand<1>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, massJpsi, xnxn, onon, onxn, xnon); + + double dp = DeltaPhi(daughter[0], daughter[1]); + float* q = correlation(&daughter[0], &daughter[1], &mom); + double dpRandom = DeltaPhiRandom(daughter[0], daughter[1]); + // fill tree with muon J/Psi candidates + tree(collision.runNumber(), collision.globalBC(), + collision.posX(), collision.posY(), collision.posZ(), + collision.totalFT0AmplitudeA(), collision.totalFT0AmplitudeC(), collision.totalFV0AmplitudeA(), collision.totalFDDAmplitudeA(), collision.totalFDDAmplitudeC(), + collision.timeFT0A(), collision.timeFT0C(), collision.timeFV0A(), collision.timeFDDA(), collision.timeFDDC(), + collision.energyCommonZNA(), collision.energyCommonZNC(), collision.timeZNA(), collision.timeZNC(), neutronClass, + RecoDecay::pt(mother), RecoDecay::eta(mother), RecoDecay::phi(mother), rapJpsi, massJpsi, dpRandom, dp, q[1], q[2], + trkDaughter1.sign(), trkDaughter1.pt(), RecoDecay::eta(daughter1), RecoDecay::phi(daughter1), + trkDaughter2.sign(), trkDaughter2.pt(), RecoDecay::eta(daughter2), RecoDecay::phi(daughter2)); + + if ((massJpsi < maxJpsiMass) && (massJpsi > minJpsiMass)) { + rTGdaugCand.get(HIST("TGdaugCand/Muon/hJpsiPt"))->Fill(RecoDecay::pt(mother)); + rTGdaugCand.get(HIST("TGdaugCand/Muon/hJpsiRap"))->Fill(rapJpsi); + if (trkDaughter1.sign() < 0) { + rTGdaugCand.get(HIST("TGdaugCand/Muon/TPCNegVsPosSignal"))->Fill(trkDaughter1.tpcSignal(), trkDaughter2.tpcSignal()); + } else { + rTGdaugCand.get(HIST("TGdaugCand/Muon/TPCNegVsPosSignal"))->Fill(trkDaughter2.tpcSignal(), trkDaughter1.tpcSignal()); + } + + if (RecoDecay::pt(mother) < 0.2f) { + fillPeak<1, 0, 0>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<1, 0, 0>(daughter1, daughter2, dp, dpRandom, q); + + if (xnxn) { + fillPeak<1, 0, 1>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<1, 0, 1>(daughter1, daughter2, dp, dpRandom, q); + } else if (onon) { + fillPeak<1, 0, 3>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<1, 0, 3>(daughter1, daughter2, dp, dpRandom, q); + } else if (xnon) { + fillPeak<1, 0, 4>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<1, 0, 4>(daughter1, daughter2, dp, dpRandom, q); + } else if (onxn) { + fillPeak<1, 0, 2>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<1, 0, 2>(daughter1, daughter2, dp, dpRandom, q); + } + } + if (RecoDecay::pt(mother) > 0.2f) { + fillPeak<1, 1, 0>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<1, 1, 0>(daughter1, daughter2, dp, dpRandom, q); + + if (xnxn) { + fillPeak<1, 1, 1>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<1, 1, 1>(daughter1, daughter2, dp, dpRandom, q); + } else if (onon) { + fillPeak<1, 1, 3>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<1, 1, 3>(daughter1, daughter2, dp, dpRandom, q); + } else if (xnon) { + fillPeak<1, 1, 4>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<1, 1, 4>(daughter1, daughter2, dp, dpRandom, q); + } else if (onxn) { + fillPeak<1, 1, 2>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + fillCorrAsy<1, 1, 2>(daughter1, daughter2, dp, dpRandom, q); + } + } // end incoherent + } // end mass cut + delete[] q; + } + } // end muons + if (doProtons) { + if (RecoDecay::sumOfSquares((trkDaughter1.hasTOF() ? trkDaughter1.tofNSigmaPr() : trkDaughter1.tpcNSigmaPr()), (trkDaughter2.hasTOF() ? trkDaughter2.tofNSigmaPr() : trkDaughter2.tpcNSigmaPr()) < 4)) { + + auto ene1 = RecoDecay::e(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz(), massPr); + auto ene2 = RecoDecay::e(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz(), massPr); + daughter[0].SetPxPyPzE(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz(), ene1); + daughter[1].SetPxPyPzE(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz(), ene2); + mom = daughter[0] + daughter[1]; + + std::array mother = {trkDaughter1.px() + trkDaughter2.px(), trkDaughter1.py() + trkDaughter2.py(), trkDaughter1.pz() + trkDaughter2.pz()}; + + if (tofBothProtons) { + if (!trkDaughter1.hasTOF() || !trkDaughter2.hasTOF()) + return; + } + if (tofOneProton) { + if ((trkDaughter1.hasTOF() && trkDaughter2.hasTOF()) || (!trkDaughter1.hasTOF() && !trkDaughter2.hasTOF())) + return; + } + if (tofAtLeastOneProton) { + if (!trkDaughter1.hasTOF() && !trkDaughter2.hasTOF()) + return; + } + + auto arrMom = std::array{daughter1, daughter2}; + float massJpsi = RecoDecay::m(arrMom, std::array{massPr, massPr}); + float rapJpsi = RecoDecay::y(mother, massJpsi); + + // TGdaug + fillTGdaug<2>(trkDaughter1, trkDaughter2, daughter1, daughter2); + + if (candidateCuts(massJpsi, rapJpsi) != 1) { + return; + } + + // TGdaugCand + fillCand<2>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, massJpsi, xnxn, onon, onxn, xnon); + + if (RecoDecay::pt(mother) < 0.2f) { + rJpsiToDaug.get(HIST("JPsiToDaug/Proton/Coherent/hIVM"))->Fill(massJpsi); + } else { + rJpsiToDaug.get(HIST("JPsiToDaug/Proton/Incoherent/hIVM"))->Fill(massJpsi); + } + + if (massJpsi < maxJpsiMass && massJpsi > minJpsiMass) { + rTGdaugCand.get(HIST("TGdaugCand/Proton/hJpsiPt"))->Fill(RecoDecay::pt(mother)); + rTGdaugCand.get(HIST("TGdaugCand/Proton/hJpsiRap"))->Fill(rapJpsi); + if (RecoDecay::pt(mother) < 0.2f) { + + fillPeak<2, 0, 0>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + + } // end coherent + if (RecoDecay::pt(mother) > 0.2f) { + // fill track histos + fillPeak<1, 1, 0>(trkDaughter1, trkDaughter2, daughter1, daughter2, mother, rapJpsi); + } // end incoherent + } // end mass cut + } + } // end protons + } // end two tracks + } // end reco process + + template + void processMC(C const& mcCollision, T const& mcParticles) + { + + rMC.get(HIST("MC/hNumberOfMCCollisions"))->Fill(1.); + rMC.get(HIST("MC/hPosZ"))->Fill(mcCollision.posZ()); + + std::array daughPart1Mu = {-999, -999, -999}; + std::array daughPart2Mu = {-999, -999, -999}; + std::array motherPart = {-999, -999, -999}; + float energyMother = -999; + float daughPart1pdg = -999; + float daughPart2pdg = -999; + + // fill number of particles + for (auto const& mcParticle : mcParticles) { + rMC.get(HIST("MC/Muon/hNumberOfMCTracks"))->Fill(1.); + rMC.get(HIST("MC/hPdg"))->Fill(mcParticle.pdgCode()); + if (mcParticle.has_daughters()) { + rMC.get(HIST("MC/hMothersPdg"))->Fill(mcParticle.pdgCode()); + rMC.get(HIST("MC/Muon/hNumberOfMCTracks"))->Fill(3.); + if (mcParticle.pdgCode() == 443) { + rMC.get(HIST("MC/Muon/hNumberOfMCTracks"))->Fill(4.); + int count = 0; + for (const auto& daughter : mcParticle.template daughters_as()) { + if ((daughter.pdgCode() == -13) && daughter.isPhysicalPrimary()) { + daughPart1Mu = {daughter.px(), daughter.py(), daughter.pz()}; + daughPart1pdg = daughter.pdgCode(); + + rMC.get(HIST("MC/Muon/hNumberOfMCTracks"))->Fill(5.); + count++; + } + if ((daughter.pdgCode() == 13) && daughter.isPhysicalPrimary()) { + daughPart2Mu = {daughter.px(), daughter.py(), daughter.pz()}; + daughPart2pdg = daughter.pdgCode(); + + rMC.get(HIST("MC/Muon/hNumberOfMCTracks"))->Fill(6.); + count++; + } + } + if (count == 2) { + rMC.get(HIST("MC/Muon/hNumberOfMCTracks"))->Fill(7.); + motherPart = {mcParticle.px(), mcParticle.py(), mcParticle.pz()}; + energyMother = mcParticle.e(); + } + } + } + } + + // calculate needed distributions + + rMC.get(HIST("MC/Muon/hEta1"))->Fill(RecoDecay::eta(daughPart1Mu)); + rMC.get(HIST("MC/Muon/hEta2"))->Fill(RecoDecay::eta(daughPart2Mu)); + rMC.get(HIST("MC/Muon/hEta"))->Fill(RecoDecay::eta(motherPart)); + rMC.get(HIST("MC/Muon/hPhi1"))->Fill(RecoDecay::phi(daughPart1Mu)); + rMC.get(HIST("MC/Muon/hPhi2"))->Fill(RecoDecay::phi(daughPart2Mu)); + rMC.get(HIST("MC/Muon/hPhi"))->Fill(RecoDecay::phi(motherPart)); + rMC.get(HIST("MC/Muon/hPt1"))->Fill(RecoDecay::pt(daughPart1Mu)); + rMC.get(HIST("MC/Muon/hPt2"))->Fill(RecoDecay::pt(daughPart2Mu)); + rMC.get(HIST("MC/Muon/hPt"))->Fill(RecoDecay::pt(motherPart)); + rMC.get(HIST("MC/Muon/hIVM"))->Fill(RecoDecay::m(motherPart, energyMother)); + rMC.get(HIST("MC/Muon/hRapidity"))->Fill(RecoDecay::y(motherPart, RecoDecay::m(motherPart, energyMother))); + + float massMu = o2::constants::physics::MassMuonMinus; + auto ene1 = RecoDecay::e(daughPart1Mu, massMu); + auto ene2 = RecoDecay::e(daughPart2Mu, massMu); + + TLorentzVector mom, daughter[2]; + daughter[0].SetPxPyPzE(daughPart1Mu[0], daughPart1Mu[1], daughPart1Mu[2], ene1); + daughter[1].SetPxPyPzE(daughPart2Mu[0], daughPart2Mu[1], daughPart2Mu[2], ene2); + mom = daughter[0] + daughter[1]; + + double dp = DeltaPhi(daughter[0], daughter[1]); + float* q = correlation(&daughter[0], &daughter[1], &mom); + double dpRandom = DeltaPhiRandom(daughter[0], daughter[1]); + + // fill tree with muon J/Psi candidates + treeMC(mcCollision.globalBC(), + RecoDecay::pt(motherPart), RecoDecay::eta(motherPart), RecoDecay::phi(motherPart), RecoDecay::y(motherPart, RecoDecay::m(motherPart, energyMother)), RecoDecay::m(motherPart, energyMother), dpRandom, dp, q[1], q[2], + daughPart1pdg, RecoDecay::pt(daughPart1Mu), RecoDecay::eta(daughPart1Mu), RecoDecay::phi(daughPart1Mu), + daughPart2pdg, RecoDecay::pt(daughPart2Mu), RecoDecay::eta(daughPart2Mu), RecoDecay::phi(daughPart2Mu)); + + } // end MC skimmed process + + void processMCFull(MCUDCollisionFull const& collision, MCUDTracksFull const& tracks, aod::UDMcCollisions const& mcCollision, aod::UDMcParticles const&) + { + rMC.get(HIST("MC/hNumberOfRecoCollisions"))->Fill(collision.size()); + rMC.get(HIST("MC/hNumberOfTrueCollisions"))->Fill(mcCollision.size()); + rMC.get(HIST("MC/hNumberOfMatchedMCTracks"))->Fill(1.); + if (collision.has_udMcCollision()) { + std::array recoTrack; + std::array truePart; + bool mesonFound = false; + for (const auto& track : tracks) { + rMC.get(HIST("MC/hNumberOfMatchedMCTracks"))->Fill(1.); + mesonFound = false; + if (track.has_udMcParticle()) { + rMC.get(HIST("MC/hNumberOfMatchedMCTracks"))->Fill(2.); + auto mcParticle = track.udMcParticle(); + rMC.fill(HIST("MC/hResolution"), mcParticle.px() - track.px()); + if (std::abs(mcParticle.pdgCode()) == 13 && mcParticle.isPhysicalPrimary()) { + rMC.get(HIST("MC/hNumberOfMatchedMCTracks"))->Fill(3.); + if (mcParticle.has_mothers()) { + rMC.get(HIST("MC/hNumberOfMatchedMCTracks"))->Fill(4.); + auto const& mother = mcParticle.mothers_first_as(); + if (mother.pdgCode() == 443) { + rMC.get(HIST("MC/hNumberOfMatchedMCTracks"))->Fill(5.); + recoTrack = {track.px(), track.py(), track.pz()}; + truePart = {mcParticle.px(), mcParticle.py(), mcParticle.pz()}; + mesonFound = true; + } + } + } + if (mesonFound) { + rMC.fill(HIST("MC/hResolutionPhi"), RecoDecay::phi(recoTrack) - RecoDecay::phi(truePart)); + } + } + } + } + } // end MC Full process + + void processDGrecoLevel(UDCollisionFull const& collision, UDTracksFull const& tracks) + { + fillHistograms(collision, tracks); + } // end DG process + + void processSGrecoLevel(SGUDCollisionFull const& collision, UDTracksFull const& tracks) + { + int gapSide = collision.gapSide(); + int trueGapSide = sgSelector.trueGap(collision, cutMyGapSideFV0, cutMyGapSideFT0A, cutMyGapSideFT0C, cutMyGapSideZDC); + if (useTrueGap) { + gapSide = trueGapSide; + } + if (gapSide != whichGapSide) { + return; + } + fillHistograms(collision, tracks); + + } // end SG process + + void processMCtruth(aod::UDMcCollision const& mcCollision, aod::UDMcParticles const& mcParticles) + { + processMC(mcCollision, mcParticles); + } + + PROCESS_SWITCH(UpcJpsiCorr, processDGrecoLevel, "Iterate over DG skimmed data.", false); + PROCESS_SWITCH(UpcJpsiCorr, processSGrecoLevel, "Iterate over SG skimmed data.", true); + PROCESS_SWITCH(UpcJpsiCorr, processMCtruth, "Iterate of MC true data.", true); + PROCESS_SWITCH(UpcJpsiCorr, processMCFull, "Iterate over both true and reco.", true); +}; // end struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGUD/Tasks/upcPhotonuclearAnalysisJMG.cxx b/PWGUD/Tasks/upcPhotonuclearAnalysisJMG.cxx new file mode 100644 index 00000000000..81834492eca --- /dev/null +++ b/PWGUD/Tasks/upcPhotonuclearAnalysisJMG.cxx @@ -0,0 +1,432 @@ +// 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 +/// \author Josué Martínez García, josuem@cern.ch + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct upcPhotonuclearAnalysisJMG { + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Declare configurables on events/collisions + Configurable cutMyPosZMin{"cutMyPosZMin", -10., {"My collision cut"}}; + Configurable cutMyPosZMax{"cutMyPosZMax", 10., {"My collision cut"}}; + Configurable cutMyTimeZNA{"cutMyTimeZNA", 2., {"My collision cut"}}; + Configurable cutMyTimeZNC{"cutMyTimeZNC", 2., {"My collision cut"}}; + // Declare configurables on side A gap + Configurable cutAGapMyEnergyZNAMax{"cutAGapMyEnergyZNAMax", 0., {"My collision cut. A Gap"}}; + Configurable cutAGapMyAmplitudeFT0AMax{"cutAGapMyAmplitudeFT0AMax", 200., {"My collision cut. A Gap"}}; + Configurable cutAGapMyEnergyZNCMin{"cutAGapMyEnergyZNCMin", 1., {"My collision cut. A Gap"}}; + Configurable cutAGapMyAmplitudeFT0CMin{"cutAGapMyAmplitudeFT0CMin", 0., {"My collision cut. A Gap"}}; + // Declare configurables on side C gap + Configurable cutCGapMyEnergyZNAMin{"cutCGapMyEnergyZNAMin", 1., {"My collision cut. C Gap"}}; + Configurable cutCGapMyAmplitudeFT0AMin{"cutCGapMyAmplitudeFT0AMin", 0., {"My collision cut. A Gap"}}; + Configurable cutCGapMyEnergyZNCMax{"cutCGapMyEnergyZNCMax", 0., {"My collision cut. C Gap"}}; + Configurable cutCGapMyAmplitudeFT0CMax{"cutCGapMyAmplitudeFT0CMax", 200., {"My collision cut. A Gap"}}; + // Declare configurables on both side gap + Configurable cutBothGapMyEnergyZNAMax{"cutBothGapMyEnergyZNAMax", 0., {"My collision cut. Both Gap"}}; + Configurable cutBothGapMyAmplitudeFT0AMax{"cutBothGapMyAmplitudeFT0AMax", 200., {"My collision cut. A Gap"}}; + Configurable cutBothGapMyEnergyZNCMax{"cutBothGapMyEnergyZNCMax", 0., {"My collision cut. Both Gap"}}; + Configurable cutBothGapMyAmplitudeFT0CMax{"cutBothGapMyAmplitudeFT0CMax", 200., {"My collision cut. A Gap"}}; + // Declare configurables on tracks + Configurable cutMyptMin{"cutMyptMin", 0.15, {"My Track cut"}}; + Configurable cutMyptMax{"cutMyptMax", 10., {"My Track cut"}}; + Configurable cutMyetaMin{"cutMyetaMin", -0.9, {"My Track cut"}}; + Configurable cutMyetaMax{"cutMyetaMax", 0.9, {"My Track cut"}}; + Configurable cutMydcaZmax{"cutMydcaZmax", 2.f, {"My Track cut"}}; + Configurable cutMydcaXYmax{"cutMydcaXYmax", 1e0f, {"My Track cut"}}; + Configurable cutMydcaXYusePt{"cutMydcaXYusePt", false, {"My Track cut"}}; + Configurable cutMyHasITS{"cutMyHasITS", true, {"My Track cut"}}; + Configurable cutMyITSNClsMin{"cutMyITSNClsMin", 1, {"My Track cut"}}; + Configurable cutMyITSChi2NClMax{"cutMyITSChi2NClMax", 36.f, {"My Track cut"}}; + Configurable cutMyHasTPC{"cutMyHasTPC", true, {"MyGlobalTrack cut"}}; + Configurable cutMyTPCNClsCrossedRowsMin{"cutMyTPCNClsCrossedRowsMin", 70, {"My Track cut"}}; + Configurable cutMyTPCNClsFindableMin{"cutMyTPCNClsFindableMin", 50, {"My Track cut"}}; + Configurable cutMyTPCNClsMin{"cutMyTPCNClsMin", 1, {"My Track cut"}}; + Configurable cutMyTPCNClsCrossedRowsOverNClsFindableMin{"cutMyTPCNClsCrossedRowsOverNClsFindableMin", 0.8f, {"My Track cut"}}; + Configurable cutMyTPCNClsOverFindableNClsMin{"cutMyTPCNClsOverFindableNClsMin", 0.5f, {"My Track cut"}}; + Configurable cutMyTPCChi2NclMax{"cutMyTPCChi2NclMax", 4.f, {"My Track cut"}}; + + using FullSGUDCollision = soa::Join::iterator; + using FullUDTracks = soa::Join; + + void init(InitContext const&) + { + const AxisSpec axisCollision{4, -0.5, 3.5}; + const AxisSpec axisZvtx{40, -20., 20.}; + const AxisSpec axisPt{402, -0.05, 20.05}; + const AxisSpec axisP{402, -10.05, 10.05}; + const AxisSpec axisTPCSignal{802, -0.05, 400.05}; + const AxisSpec axisPhi{64, -2 * o2::constants::math::PI, 2 * o2::constants::math::PI}; + const AxisSpec axisEta{50, -1.2, 1.2}; + const AxisSpec axisNch{101, -0.5, 100.5}; + const AxisSpec axisZNEnergy{1002, -0.5, 500.5}; + const AxisSpec axisZNTime{21, -10.5, 10.5}; + const AxisSpec axisFT0Amplitud{201, -0.5, 200.5}; + const AxisSpec axisNCls{201, -0.5, 200.5}; + const AxisSpec axisChi2NCls{100, 0, 50}; + const AxisSpec axisTPCNClsCrossedRowsMin{100, -0.05, 2.05}; + + histos.add("Events/hCountCollisions", "0 total - 1 side A - 2 side C - 3 both side; Number of analysed collision; counts", kTH1F, {axisCollision}); + + // histos to selection gap in side A + histos.add("Tracks/SGsideA/hTrackPt", "#it{p_{T}} distribution; #it{p_{T}}; counts", kTH1F, {axisPt}); + histos.add("Tracks/SGsideA/hTrackPhi", "#it{#phi} distribution; #it{#phi}; counts", kTH1F, {axisPhi}); + histos.add("Tracks/SGsideA/hTrackEta", "#it{#eta} distribution; #it{#eta}; counts", kTH1F, {axisEta}); + histos.add("Tracks/SGsideA/hTrackTPCSignnalP", "#it{TPC dE/dx vs p}; #it{p*charge}; #it{TPC dE/dx}", kTH2F, {axisP, axisTPCSignal}); + histos.add("Tracks/SGsideA/hTrackITSNCls", "#it{N Clusters ITS} distribution; #it{N Clusters ITS}; counts", kTH1F, {axisNCls}); + histos.add("Tracks/SGsideA/hTrackITSChi2NCls", "#it{N Clusters Chi2 ITS} distribution; #it{N Clusters Chi2 ITS}; counts", kTH1F, {axisChi2NCls}); + histos.add("Tracks/SGsideA/hTrackNClsCrossedRowsOverNClsFindable", "#it{NClsCrossedRows/FindableNCls} distribution in TPC; #it{NClsCrossedRows/FindableNCls}; counts", kTH1F, {axisTPCNClsCrossedRowsMin}); + histos.add("Tracks/SGsideA/hTrackNClsCrossedRowsOverNCls", "#it{NClsCrossedRows/NCls} distribution in TPC; #it{NClsCrossedRows/NCls}; counts", kTH1F, {axisTPCNClsCrossedRowsMin}); + histos.add("Tracks/SGsideA/hTrackTPCNClsCrossedRows", "#it{Number of crossed TPC Rows} distribution; #it{Number of crossed TPC Rows}; counts", kTH1F, {axisNCls}); + histos.add("Tracks/SGsideA/hTrackTPCNClsFindable", "#it{Findable TPC clusters per track} distribution; #it{Findable TPC clusters per track}; counts", kTH1F, {axisNCls}); + histos.add("Tracks/SGsideA/hTrackTPCNClsFound", "#it{Found TPC clusters per track} distribution; #it{Found TPC clusters per track}; counts", kTH1F, {axisNCls}); + histos.add("Tracks/SGsideA/hTrackTPCNClsFindableMinusFound", "#it{TPCNCls: Findable - Found per track} distribution; #it{TPCNCls: Findable - Found per track}; counts", kTH1F, {axisNCls}); + histos.add("Tracks/SGsideA/hTrackTPCNClsFindableMinusCrossedRows", "#it{TPCNCls: Findable - CrossedRows per track} distribution; #it{TPCNCls: Findable - CrossedRows per track}; counts", kTH1F, {axisNCls}); + histos.add("Tracks/SGsideA/hTrackTPCChi2NCls", "#it{N Clusters Chi2 TPC} distribution; #it{N Clusters Chi2 TPC}; counts", kTH1F, {axisChi2NCls}); + histos.add("Tracks/SGsideA/hTrackITSNClsTPCCls", "#it{ITS Clusters vs TPC Clusters}; #it{TPC Clusters}; #it{ITS Clusters}", kTH2F, {axisNCls, axisNCls}); + + histos.add("Events/SGsideA/hTrackZVtx", "vertex in z; z (cm); counts", kTH1F, {axisZvtx}); + histos.add("Events/SGsideA/hNch", "#it{Charged Tracks Multiplicity} distribution; #it{Charged Tracks Multiplicity}; counts", kTH1F, {axisNch}); + histos.add("Events/SGsideA/hPtVSNch", "#it{ #LT p_{T} #GT } vs #it{Charged Tracks Multiplicity}; #it{Charged Tracks Multiplicity}; #it{ #LT p_{T} #GT }", kTH2F, {axisNch, axisPt}); + histos.add("Events/SGsideA/hEnergyZNA", "Energy in side A distribution; Energy in side A; counts", kTH1F, {axisZNEnergy}); + histos.add("Events/SGsideA/hEnergyZNC", "Energy in side C distribution; Energy in side C; counts", kTH1F, {axisZNEnergy}); + histos.add("Events/SGsideA/hEnergyRelationSides", "Energy in side A vs energy in side C; Energy in side A; Energy in side C", kTH2F, {axisZNEnergy, axisZNEnergy}); + histos.add("Events/SGsideA/hTimeZNA", "Time in side A distribution; Time in side A; counts", kTH1F, {axisZNTime}); + histos.add("Events/SGsideA/hTimeZNC", "Time in side C distribution; Time in side C; counts", kTH1F, {axisZNTime}); + histos.add("Events/SGsideA/hTimeRelationSides", "Time in side A vs time in side C; Time in side A; Time in side C", kTH2F, {axisZNTime, axisZNTime}); + histos.add("Events/SGsideA/hAmplitudFT0A", "Amplitud in side A distribution; Amplitud in side A; counts", kTH1F, {axisFT0Amplitud}); + histos.add("Events/SGsideA/hAmplitudFT0C", "Amplitud in side C distribution; Amplitud in side C; counts", kTH1F, {axisFT0Amplitud}); + + // histos to selection gap in side C + histos.add("Tracks/SGsideC/hTrackPt", "#it{p_{T}} distribution; #it{p_{T}}; counts", kTH1F, {axisPt}); + histos.add("Tracks/SGsideC/hTrackPhi", "#it{#phi} distribution; #it{#phi}; counts", kTH1F, {axisPhi}); + histos.add("Tracks/SGsideC/hTrackEta", "#it{#eta} distribution; #it{#eta}; counts", kTH1F, {axisEta}); + histos.add("Tracks/SGsideC/hTrackTPCSignnalP", "#it{TPC dE/dx vs p}; #it{p*charge}; #it{TPC dE/dx}", kTH2F, {axisP, axisTPCSignal}); + histos.add("Tracks/SGsideC/hTrackITSNCls", "#it{N Clusters ITS} distribution; #it{N Clusters ITS}; counts", kTH1F, {axisNCls}); + histos.add("Tracks/SGsideC/hTrackITSChi2NCls", "#it{N Clusters Chi2 ITS} distribution; #it{N Clusters Chi2 ITS}; counts", kTH1F, {axisChi2NCls}); + histos.add("Tracks/SGsideC/hTrackNClsCrossedRowsOverNClsFindable", "#it{NClsCrossedRows/FindableNCls} distribution in TPC; #it{NClsCrossedRows/FindableNCls}; counts", kTH1F, {axisTPCNClsCrossedRowsMin}); + histos.add("Tracks/SGsideC/hTrackNClsCrossedRowsOverNCls", "#it{NClsCrossedRows/NCls} distribution in TPC; #it{NClsCrossedRows/NCls}; counts", kTH1F, {axisTPCNClsCrossedRowsMin}); + histos.add("Tracks/SGsideC/hTrackTPCNClsCrossedRows", "#it{Number of crossed TPC Rows} distribution; #it{Number of crossed TPC Rows}; counts", kTH1F, {axisNCls}); + histos.add("Tracks/SGsideC/hTrackTPCNClsFindable", "#it{Findable TPC clusters per track} distribution; #it{Findable TPC clusters per track}; counts", kTH1F, {axisNCls}); + histos.add("Tracks/SGsideC/hTrackTPCNClsFound", "#it{Found TPC clusters per track} distribution; #it{Found TPC clusters per track}; counts", kTH1F, {axisNCls}); + histos.add("Tracks/SGsideC/hTrackTPCNClsFindableMinusFound", "#it{TPCNCls: Findable - Found per track} distribution; #it{TPCNCls: Findable - Found per track}; counts", kTH1F, {axisNCls}); + histos.add("Tracks/SGsideC/hTrackTPCNClsFindableMinusCrossedRows", "#it{TPCNCls: Findable - CrossedRows per track} distribution; #it{TPCNCls: Findable - CrossedRows per track}; counts", kTH1F, {axisNCls}); + histos.add("Tracks/SGsideC/hTrackTPCChi2NCls", "#it{N Clusters Chi2 TPC} distribution; #it{N Clusters Chi2 TPC}; counts", kTH1F, {axisChi2NCls}); + histos.add("Tracks/SGsideC/hTrackITSNClsTPCCls", "#it{ITS Clusters vs TPC Clusters}; #it{TPC Clusters}; #it{ITS Clusters}", kTH2F, {axisNCls, axisNCls}); + + histos.add("Events/SGsideC/hTrackZVtx", "vertex in z; z (cm); counts", kTH1F, {axisZvtx}); + histos.add("Events/SGsideC/hNch", "#it{Charged Tracks Multiplicity} distribution; #it{Charged Tracks Multiplicity}; counts", kTH1F, {axisNch}); + histos.add("Events/SGsideC/hPtVSNch", "#it{ #LT p_{T} #GT } vs #it{Charged Tracks Multiplicity}; #it{Charged Tracks Multiplicity}; #it{ #LT p_{T} #GT }", kTH2F, {axisNch, axisPt}); + histos.add("Events/SGsideC/hEnergyZNA", "Energy in side A distribution; Energy in side A; counts", kTH1F, {axisZNEnergy}); + histos.add("Events/SGsideC/hEnergyZNC", "Energy in side C distribution; Energy in side C; counts", kTH1F, {axisZNEnergy}); + histos.add("Events/SGsideC/hEnergyRelationSides", "Energy in side A vs energy in side C; Energy in side A; Energy in side C", kTH2F, {axisZNEnergy, axisZNEnergy}); + histos.add("Events/SGsideC/hTimeZNA", "Time in side A distribution; Time in side A; counts", kTH1F, {axisZNTime}); + histos.add("Events/SGsideC/hTimeZNC", "Time in side C distribution; Time in side C; counts", kTH1F, {axisZNTime}); + histos.add("Events/SGsideC/hTimeRelationSides", "Time in side A vs time in side C; Time in side A; Time in side C", kTH2F, {axisZNTime, axisZNTime}); + histos.add("Events/SGsideC/hAmplitudFT0A", "Amplitud in side A distribution; Amplitud in side A; counts", kTH1F, {axisFT0Amplitud}); + histos.add("Events/SGsideC/hAmplitudFT0C", "Amplitud in side C distribution; Amplitud in side C; counts", kTH1F, {axisFT0Amplitud}); + + // histos to selection gap in both sides + histos.add("Tracks/SGsideBoth/hTrackPt", "#it{p_{T}} distribution; #it{p_{T}}; counts", kTH1F, {axisPt}); + histos.add("Tracks/SGsideBoth/hTrackPhi", "#it{#phi} distribution; #it{#phi}; counts", kTH1F, {axisPhi}); + histos.add("Tracks/SGsideBoth/hTrackEta", "#it{#eta} distribution; #it{#eta}; counts", kTH1F, {axisEta}); + histos.add("Tracks/SGsideBoth/hTrackTPCSignnalP", "#it{TPC dE/dx vs p}; #it{p*charge}; #it{TPC dE/dx}", kTH2F, {axisP, axisTPCSignal}); + histos.add("Tracks/SGsideBoth/hTrackITSNCls", "#it{N Clusters ITS} distribution; #it{N Clusters ITS}; counts", kTH1F, {axisNCls}); + histos.add("Tracks/SGsideBoth/hTrackITSChi2NCls", "#it{N Clusters Chi2 ITS} distribution; #it{N Clusters Chi2 ITS}; counts", kTH1F, {axisChi2NCls}); + histos.add("Tracks/SGsideBoth/hTrackNClsCrossedRowsOverNCls", "#it{NClsCrossedRows/FindableNCls} distribution in TPC; #it{NClsCrossedRows/FindableNCls}; counts", kTH1F, {axisTPCNClsCrossedRowsMin}); + histos.add("Tracks/SGsideBoth/hTrackTPCNClsCrossedRows", "#it{Number of crossed TPC Rows} distribution; #it{Number of crossed TPC Rows}; counts", kTH1F, {axisNCls}); + histos.add("Tracks/SGsideBoth/hTrackTPCNClsFindable", "#it{Findable TPC clusters for this track} distribution; #it{Findable TPC clusters for this track}; counts", kTH1F, {axisNCls}); + histos.add("Tracks/SGsideBoth/hTrackTPCChi2NCls", "#it{N Clusters Chi2 TPC} distribution; #it{N Clusters Chi2 TPC}; counts", kTH1F, {axisChi2NCls}); + histos.add("Tracks/SGsideBoth/hTrackITSNClsTPCCls", "#it{ITS Clusters vs TPC Clusters}; #it{TPC Clusters}; #it{ITS Clusters}", kTH2F, {axisNCls, axisNCls}); + + histos.add("Events/SGsideBoth/hTrackZVtx", "vertex in z; z (cm); counts", kTH1F, {axisZvtx}); + histos.add("Events/SGsideBoth/hNch", "#it{Charged Tracks Multiplicity} distribution; #it{Charged Tracks Multiplicity}; counts", kTH1F, {axisNch}); + histos.add("Events/SGsideBoth/hPtVSNch", "#it{ #LT p_{T} #GT } vs #it{Charged Tracks Multiplicity}; #it{Charged Tracks Multiplicity}; #it{ #LT p_{T} #GT }", kTH2F, {axisNch, axisPt}); + histos.add("Events/SGsideBoth/hEnergyZNA", "Energy in side A distribution; Energy in side A; counts", kTH1F, {axisZNEnergy}); + histos.add("Events/SGsideBoth/hEnergyZNC", "Energy in side C distribution; Energy in side C; counts", kTH1F, {axisZNEnergy}); + histos.add("Events/SGsideBoth/hEnergyRelationSides", "Energy in side A vs energy in side C; Energy in side A; Energy in side C", kTH2F, {axisZNEnergy, axisZNEnergy}); + histos.add("Events/SGsideBoth/hTimeZNA", "Time in side A distribution; Time in side A; counts", kTH1F, {axisZNTime}); + histos.add("Events/SGsideBoth/hTimeZNC", "Time in side C distribution; Time in side C; counts", kTH1F, {axisZNTime}); + histos.add("Events/SGsideBoth/hTimeRelationSides", "Time in side A vs time in side C; Time in side A; Time in side C", kTH2F, {axisZNTime, axisZNTime}); + histos.add("Events/SGsideBoth/hAmplitudFT0A", "Amplitud in side A distribution; Amplitud in side A; counts", kTH1F, {axisFT0Amplitud}); + histos.add("Events/SGsideBoth/hAmplitudFT0C", "Amplitud in side C distribution; Amplitud in side C; counts", kTH1F, {axisFT0Amplitud}); + } + + template + bool isGlobalCollisionCut(C const& collision) + { + if (collision.posZ() < cutMyPosZMin || cutMyPosZMax < collision.posZ()) { + return false; + } + if ((std::abs(collision.timeZNA()) < cutMyTimeZNA && std::abs(collision.timeZNC()) < cutMyTimeZNC) == false) { + return false; + } + return true; + } + + template + bool isCollisionCutSG(CSG const& collision, int SideGap) + { + switch (SideGap) { + case 0: // Gap in A side + if ((collision.energyCommonZNA() < cutAGapMyEnergyZNAMax && collision.energyCommonZNC() >= cutAGapMyEnergyZNCMin) == false) { // 0n - A side && Xn - C Side + return false; + } + if ((collision.totalFT0AmplitudeA() < cutAGapMyAmplitudeFT0AMax && collision.totalFT0AmplitudeC() >= cutAGapMyAmplitudeFT0CMin) == false) { + return false; + } + break; + case 1: // Gap in C side + if ((collision.energyCommonZNA() >= cutCGapMyEnergyZNAMin && collision.energyCommonZNC() < cutCGapMyEnergyZNCMax) == false) { // Xn - A side && 0n - C Side + return false; + } + if ((collision.totalFT0AmplitudeA() >= cutCGapMyAmplitudeFT0AMin && collision.totalFT0AmplitudeC() < cutCGapMyAmplitudeFT0CMax) == false) { + return false; + } + break; + case 2: // Gap in Both Sides + if ((collision.energyCommonZNA() < cutBothGapMyEnergyZNAMax && collision.energyCommonZNC() < cutBothGapMyEnergyZNCMax) == false) { // 0n - A side && 0n - C Side + return false; + } + if ((collision.totalFT0AmplitudeA() < cutBothGapMyAmplitudeFT0AMax && collision.totalFT0AmplitudeC() < cutBothGapMyAmplitudeFT0CMax) == false) { + return false; + } + break; + } + return true; + } + + template + bool isTrackCut(T const& track) + { + if (track.pt() < cutMyptMin || track.pt() > cutMyptMax) { + return false; + } + if (eta(track.px(), track.py(), track.pz()) < cutMyetaMin || eta(track.px(), track.py(), track.pz()) > cutMyetaMax) { + return false; + } + if (std::abs(track.dcaZ()) > cutMydcaZmax) { + return false; + } + if (cutMydcaXYusePt) { + float maxDCA = 0.0105f + 0.0350f / std::pow(track.pt(), 1.1f); + if (std::abs(track.dcaXY()) > maxDCA) { + return false; + } + } else { + if (std::abs(track.dcaXY()) > cutMydcaXYmax) { + return false; + } + } + // Quality Track + // ITS + if (cutMyHasITS && !track.hasITS()) { + return false; // ITS refit + } + if (track.itsNCls() < cutMyITSNClsMin) { + return false; + } + if (track.itsChi2NCl() > cutMyITSChi2NClMax) { + return false; + } + // TPC + if (cutMyHasTPC && !track.hasTPC()) { + return false; // TPC refit + } + if (track.tpcNClsCrossedRows() < cutMyTPCNClsCrossedRowsMin) { + return false; + } + if ((track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) < cutMyTPCNClsMin) { + return false; // tpcNClsFound() + } + if (track.tpcNClsFindable() < cutMyTPCNClsFindableMin) { + return false; + } + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < cutMyTPCNClsCrossedRowsOverNClsFindableMin) { + return false; // + } + if ((static_cast(track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) / static_cast(track.tpcNClsFindable())) < cutMyTPCNClsCrossedRowsOverNClsFindableMin) { + return false; // + } + if (track.tpcChi2NCl() > cutMyTPCChi2NclMax) { + return false; // TPC chi2 + } + return true; + } + + void processSG(FullSGUDCollision const& reconstructedCollision, FullUDTracks const& reconstructedTracks) + { + histos.fill(HIST("Events/hCountCollisions"), 0); + int SGside = reconstructedCollision.gapSide(); + int nTracksCharged = 0; + float sumPt = 0; + + if (isGlobalCollisionCut(reconstructedCollision) == false) { + return; + } + + switch (SGside) { + case 0: // for side A + if (isCollisionCutSG(reconstructedCollision, 0) == false) { + return; + } + histos.fill(HIST("Events/hCountCollisions"), 1); + histos.fill(HIST("Events/SGsideA/hEnergyZNA"), reconstructedCollision.energyCommonZNA()); + histos.fill(HIST("Events/SGsideA/hEnergyZNC"), reconstructedCollision.energyCommonZNC()); + histos.fill(HIST("Events/SGsideA/hEnergyRelationSides"), reconstructedCollision.energyCommonZNA(), reconstructedCollision.energyCommonZNC()); + histos.fill(HIST("Events/SGsideA/hTimeZNA"), reconstructedCollision.timeZNA()); + histos.fill(HIST("Events/SGsideA/hTimeZNC"), reconstructedCollision.timeZNC()); + histos.fill(HIST("Events/SGsideA/hTimeRelationSides"), reconstructedCollision.timeZNA(), reconstructedCollision.timeZNC()); + histos.fill(HIST("Events/SGsideA/hTrackZVtx"), reconstructedCollision.posZ()); + histos.fill(HIST("Events/SGsideA/hAmplitudFT0A"), reconstructedCollision.totalFT0AmplitudeA()); + histos.fill(HIST("Events/SGsideA/hAmplitudFT0C"), reconstructedCollision.totalFT0AmplitudeC()); + for (auto& track : reconstructedTracks) { + if (track.sign() == 1 || track.sign() == -1) { + if (isTrackCut(track) == false) { + continue; + } + nTracksCharged++; + sumPt += track.pt(); + histos.fill(HIST("Tracks/SGsideA/hTrackPt"), track.pt()); + histos.fill(HIST("Tracks/SGsideA/hTrackPhi"), phi(track.px(), track.py())); + histos.fill(HIST("Tracks/SGsideA/hTrackEta"), eta(track.px(), track.py(), track.pz())); + histos.fill(HIST("Tracks/SGsideA/hTrackTPCSignnalP"), momentum(track.px(), track.py(), track.pz()) * track.sign(), track.tpcSignal()); + + histos.fill(HIST("Tracks/SGsideA/hTrackITSNCls"), track.itsNCls()); + histos.fill(HIST("Tracks/SGsideA/hTrackITSChi2NCls"), track.itsChi2NCl()); + histos.fill(HIST("Tracks/SGsideA/hTrackNClsCrossedRowsOverNClsFindable"), (static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable()))); + histos.fill(HIST("Tracks/SGsideA/hTrackNClsCrossedRowsOverNCls"), (static_cast(track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) / static_cast(track.tpcNClsFindable()))); + histos.fill(HIST("Tracks/SGsideA/hTrackTPCNClsCrossedRows"), track.tpcNClsCrossedRows()); + histos.fill(HIST("Tracks/SGsideA/hTrackTPCNClsFindable"), track.tpcNClsFindable()); + histos.fill(HIST("Tracks/SGsideA/hTrackTPCNClsFound"), track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()); + histos.fill(HIST("Tracks/SGsideA/hTrackTPCNClsFindableMinusFound"), track.tpcNClsFindableMinusFound()); + histos.fill(HIST("Tracks/SGsideA/hTrackTPCNClsFindableMinusCrossedRows"), track.tpcNClsFindableMinusCrossedRows()); + histos.fill(HIST("Tracks/SGsideA/hTrackTPCChi2NCls"), track.tpcChi2NCl()); + histos.fill(HIST("Tracks/SGsideA/hTrackITSNClsTPCCls"), track.tpcNClsFindable() - track.tpcNClsFindableMinusFound(), track.itsNCls()); + } + } + histos.fill(HIST("Events/SGsideA/hNch"), nTracksCharged); + histos.fill(HIST("Events/SGsideA/hPtVSNch"), nTracksCharged, (sumPt / nTracksCharged)); + nTracksCharged = sumPt = 0; + break; + case 1: // for side C + if (isCollisionCutSG(reconstructedCollision, 1) == false) { + return; + } + histos.fill(HIST("Events/hCountCollisions"), 2); + histos.fill(HIST("Events/SGsideC/hEnergyZNA"), reconstructedCollision.energyCommonZNA()); + histos.fill(HIST("Events/SGsideC/hEnergyZNC"), reconstructedCollision.energyCommonZNC()); + histos.fill(HIST("Events/SGsideC/hEnergyRelationSides"), reconstructedCollision.energyCommonZNA(), reconstructedCollision.energyCommonZNC()); + histos.fill(HIST("Events/SGsideC/hTimeZNA"), reconstructedCollision.timeZNA()); + histos.fill(HIST("Events/SGsideC/hTimeZNC"), reconstructedCollision.timeZNC()); + histos.fill(HIST("Events/SGsideC/hTimeRelationSides"), reconstructedCollision.timeZNA(), reconstructedCollision.timeZNC()); + histos.fill(HIST("Events/SGsideC/hTrackZVtx"), reconstructedCollision.posZ()); + histos.fill(HIST("Events/SGsideC/hAmplitudFT0A"), reconstructedCollision.totalFT0AmplitudeA()); + histos.fill(HIST("Events/SGsideC/hAmplitudFT0C"), reconstructedCollision.totalFT0AmplitudeC()); + for (auto& track : reconstructedTracks) { + if (track.sign() == 1 || track.sign() == -1) { + if (isTrackCut(track) == false) { + continue; + } + nTracksCharged++; + sumPt += track.pt(); + histos.fill(HIST("Tracks/SGsideC/hTrackPt"), track.pt()); + histos.fill(HIST("Tracks/SGsideC/hTrackPhi"), phi(track.px(), track.py())); + histos.fill(HIST("Tracks/SGsideC/hTrackEta"), eta(track.px(), track.py(), track.pz())); + histos.fill(HIST("Tracks/SGsideC/hTrackTPCSignnalP"), momentum(track.px(), track.py(), track.pz()) * track.sign(), track.tpcSignal()); + + histos.fill(HIST("Tracks/SGsideC/hTrackITSNCls"), track.itsNCls()); + histos.fill(HIST("Tracks/SGsideC/hTrackITSChi2NCls"), track.itsChi2NCl()); + histos.fill(HIST("Tracks/SGsideC/hTrackNClsCrossedRowsOverNClsFindable"), (static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable()))); + histos.fill(HIST("Tracks/SGsideC/hTrackNClsCrossedRowsOverNCls"), (static_cast(track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) / static_cast(track.tpcNClsFindable()))); + histos.fill(HIST("Tracks/SGsideC/hTrackTPCNClsCrossedRows"), track.tpcNClsCrossedRows()); + histos.fill(HIST("Tracks/SGsideC/hTrackTPCNClsFindable"), track.tpcNClsFindable()); + histos.fill(HIST("Tracks/SGsideC/hTrackTPCNClsFound"), track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()); + histos.fill(HIST("Tracks/SGsideC/hTrackTPCNClsFindableMinusFound"), track.tpcNClsFindableMinusFound()); + histos.fill(HIST("Tracks/SGsideC/hTrackTPCNClsFindableMinusCrossedRows"), track.tpcNClsFindableMinusCrossedRows()); + histos.fill(HIST("Tracks/SGsideC/hTrackTPCChi2NCls"), track.tpcChi2NCl()); + histos.fill(HIST("Tracks/SGsideC/hTrackITSNClsTPCCls"), track.tpcNClsFindable() - track.tpcNClsFindableMinusFound(), track.itsNCls()); + } + } + histos.fill(HIST("Events/SGsideC/hNch"), nTracksCharged); + histos.fill(HIST("Events/SGsideC/hPtVSNch"), nTracksCharged, (sumPt / nTracksCharged)); + nTracksCharged = sumPt = 0; + break; + case 2: // for both sides + if (isCollisionCutSG(reconstructedCollision, 2) == false) { + return; + } + histos.fill(HIST("Events/hCountCollisions"), 3); + histos.fill(HIST("Events/SGsideBoth/hEnergyZNA"), reconstructedCollision.energyCommonZNA()); + histos.fill(HIST("Events/SGsideBoth/hEnergyZNC"), reconstructedCollision.energyCommonZNC()); + histos.fill(HIST("Events/SGsideBoth/hEnergyRelationSides"), reconstructedCollision.energyCommonZNA(), reconstructedCollision.energyCommonZNC()); + histos.fill(HIST("Events/SGsideBoth/hTimeZNA"), reconstructedCollision.timeZNA()); + histos.fill(HIST("Events/SGsideBoth/hTimeZNC"), reconstructedCollision.timeZNC()); + histos.fill(HIST("Events/SGsideBoth/hTimeRelationSides"), reconstructedCollision.timeZNA(), reconstructedCollision.timeZNC()); + histos.fill(HIST("Events/SGsideBoth/hTrackZVtx"), reconstructedCollision.posZ()); + histos.fill(HIST("Events/SGsideBoth/hAmplitudFT0A"), reconstructedCollision.totalFT0AmplitudeA()); + histos.fill(HIST("Events/SGsideBoth/hAmplitudFT0C"), reconstructedCollision.totalFT0AmplitudeC()); + for (auto& track : reconstructedTracks) { + if (track.sign() == 1 || track.sign() == -1) { + if (isTrackCut(track) == false) { + continue; + } + nTracksCharged++; + sumPt += track.pt(); + histos.fill(HIST("Tracks/SGsideBoth/hTrackPt"), track.pt()); + histos.fill(HIST("Tracks/SGsideBoth/hTrackPhi"), phi(track.px(), track.py())); + histos.fill(HIST("Tracks/SGsideBoth/hTrackEta"), eta(track.px(), track.py(), track.pz())); + histos.fill(HIST("Tracks/SGsideBoth/hTrackTPCSignnalP"), momentum(track.px(), track.py(), track.pz()) * track.sign(), track.tpcSignal()); + + histos.fill(HIST("Tracks/SGsideBoth/hTrackITSNCls"), track.itsNCls()); + histos.fill(HIST("Tracks/SGsideBoth/hTrackITSChi2NCls"), track.itsChi2NCl()); + histos.fill(HIST("Tracks/SGsideBoth/hTrackNClsCrossedRowsOverNCls"), (static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable()))); + histos.fill(HIST("Tracks/SGsideBoth/hTrackTPCNClsCrossedRows"), track.tpcNClsCrossedRows()); + histos.fill(HIST("Tracks/SGsideBoth/hTrackTPCNClsFindable"), track.tpcNClsFindable()); + histos.fill(HIST("Tracks/SGsideBoth/hTrackTPCChi2NCls"), track.tpcChi2NCl()); + histos.fill(HIST("Tracks/SGsideBoth/hTrackITSNClsTPCCls"), track.tpcNClsFindable() - track.tpcNClsFindableMinusFound(), track.itsNCls()); + } + } + histos.fill(HIST("Events/SGsideBoth/hNch"), nTracksCharged); + histos.fill(HIST("Events/SGsideBoth/hPtVSNch"), nTracksCharged, (sumPt / nTracksCharged)); + nTracksCharged = sumPt = 0; + break; + default: + return; + break; + } + } + PROCESS_SWITCH(upcPhotonuclearAnalysisJMG, processSG, "Process in UD tables", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"upcphotonuclear"})}; +} diff --git a/PWGUD/Tasks/upcPionAnalysis.cxx b/PWGUD/Tasks/upcPionAnalysis.cxx new file mode 100644 index 00000000000..2d5d35cd564 --- /dev/null +++ b/PWGUD/Tasks/upcPionAnalysis.cxx @@ -0,0 +1,852 @@ +// 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. +// +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "iostream" +#include "PWGUD/DataModel/UDTables.h" +#include +#include +#include "TLorentzVector.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" +#include "Common/Core/RecoDecay.h" +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// \brief UPC pion study +/// \author Anisa Khatun +/// \date 11.11.2022 + +struct UPCPionAnalysis { + SGSelector sgSelector; + + Configurable FV0_cut{"FV0", 100., "FV0A threshold"}; + Configurable FT0A_cut{"FT0A", 200., "FT0A threshold"}; + Configurable FT0C_cut{"FT0C", 100., "FT0C threshold"}; + Configurable FDDA_cut{"FDDA", 10000., "FDDA threshold"}; + Configurable FDDC_cut{"FDDC", 10000., "FDDC threshold"}; + Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; + Configurable gap_Side{"gap", 2, "gap selection"}; + + // Collision selection + Configurable collcontrib_cut{"collcontrib_cut", 10, "no. of PV contributor per collsion"}; + Configurable Zvtx_cut{"Zvtx_cut", 15, "z-vertex selection"}; + + // Track Selections + Configurable PV_cut{"PV_cut", 1.0, "Use Only PV tracks"}; + Configurable dcaZ_cut{"dcaZ_cut", 2.0, "dcaZ cut"}; + Configurable dcaXY_cut{"dcaXY_cut", 0.0, "dcaXY cut (0 for Pt-function)"}; + Configurable tpcChi2_cut{"tpcChi2_cut", 4, "Max tpcChi2NCl"}; + Configurable tpcNClsFindable_cut{"tpcNClsFindable_cut", 70, "Min tpcNClsFindable"}; + Configurable itsChi2_cut{"itsChi2_cut", 36, "Max itsChi2NCl"}; + Configurable eta_cut{"eta_cut", 0.9, "Track Pseudorapidity"}; + Configurable pt_cut{"pt_cut", 0.1, "Track Pt"}; + Configurable TPC_cluster{"TPC_cluster", 50, "No.of TPC cluster"}; + + // Kinmatic cuts + Configurable PID_cut{"PID_cut", 5, "TPC PID"}; + Configurable Rap_cut{"Rap_cut", 0.9, "Track rapidity"}; + Configurable Mass_Max{"Mass_Max", 10, "Invariant Mass range high"}; + Configurable Mass_Min{"Mass_Min", 0, "Invariant Mass range low"}; + Configurable Pt_coherent{"Pt_coherent", 0.15, "Coherent selection"}; + + // defining histograms using histogram registry + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //_____________________________________________________________________________________________ + Double_t CosThetaHelicityFrame(TLorentzVector pionPositive, + TLorentzVector pionNegative, + TLorentzVector possibleRhoZero) + { + + Double_t HalfSqrtSnn = 2680.; + Double_t MassOfLead208 = 193.6823; + Double_t MomentumBeam = TMath::Sqrt(HalfSqrtSnn * HalfSqrtSnn * 208 * 208 - MassOfLead208 * MassOfLead208); + + TLorentzVector pProjCM(0., 0., -MomentumBeam, HalfSqrtSnn * 208); // projectile + TLorentzVector pTargCM(0., 0., MomentumBeam, HalfSqrtSnn * 208); // target + + TVector3 beta = (-1. / possibleRhoZero.E()) * possibleRhoZero.Vect(); + TLorentzVector pPi1Dipion = pionPositive; + TLorentzVector pPi2Dipion = pionNegative; + TLorentzVector pProjDipion = pProjCM; + TLorentzVector pTargDipion = pTargCM; + + pPi1Dipion.Boost(beta); + pPi2Dipion.Boost(beta); + pProjDipion.Boost(beta); + pTargDipion.Boost(beta); + + TVector3 zaxis = (possibleRhoZero.Vect()).Unit(); + + Double_t CosThetaHE = zaxis.Dot((pPi1Dipion.Vect()).Unit()); + return CosThetaHE; + } + //------------------------------------------------------------------------------------------------------ + Double_t PhiHelicityFrame(TLorentzVector piPositive, TLorentzVector piNegative, TLorentzVector possibleRho) + { + + // Half of the energy per pair of the colliding nucleons. + Double_t HalfSqrtSnn = 2680.; + Double_t MassOfLead208 = 193.6823; + Double_t MomentumBeam = TMath::Sqrt(HalfSqrtSnn * HalfSqrtSnn * 208 * 208 - MassOfLead208 * MassOfLead208); + + TLorentzVector pProjCM(0., 0., -MomentumBeam, HalfSqrtSnn * 208); // projectile + TLorentzVector pTargCM(0., 0., MomentumBeam, HalfSqrtSnn * 208); // target + + // Translate the dipion parameters in the dipion rest frame + TVector3 beta = (-1. / possibleRho.E()) * possibleRho.Vect(); + TLorentzVector pPi1Dipi = piPositive; + TLorentzVector pPi2Dipi = piNegative; + TLorentzVector pProjDipi = pProjCM; + TLorentzVector pTargDipi = pTargCM; + pPi1Dipi.Boost(beta); + pPi2Dipi.Boost(beta); + pProjDipi.Boost(beta); + pTargDipi.Boost(beta); + + // Axes + TVector3 zaxis = (possibleRho.Vect()).Unit(); + TVector3 yaxis = ((pProjDipi.Vect()).Cross(pTargDipi.Vect())).Unit(); + TVector3 xaxis = (yaxis.Cross(zaxis)).Unit(); + // + // --- Calculation of the azimuthal angle (Helicity) + // + Double_t phi = TMath::ATan2((pPi1Dipi.Vect()).Dot(yaxis), (pPi1Dipi.Vect()).Dot(xaxis)); + return phi; + } + //----------------------------------------------------------------------------------------------- + float* AngCorrelation(TLorentzVector* lv1, TLorentzVector* lv2, TLorentzVector* lv) + { + TLorentzVector pa(1., 0., 0, 1); // projectile + TLorentzVector pb(1., 0., 0, -1); // target + + float* q = new float[3]; // to save values + + // Accoplanarity angle + Float_t deltaPhi; + deltaPhi = lv1->Phi() - lv2->Phi(); + float accoplCut = 1. - std::abs(deltaPhi) / o2::constants::math::PI; + // z + TLorentzVector z; + Float_t part1, part2; + + // Dot product: v1*v2 = t1*t2-x1*x2-y1*y2-z1*z2 + + part1 = lv->Dot(pb); + part2 = lv->Dot(pa); + + Float_t part3x = pa.X() * part1; + Float_t part3y = pa.Y() * part1; + Float_t part3z = pa.Z() * part1; + Float_t part3e = pa.T() * part1; + + Float_t part4x = pb.X() * part2; + Float_t part4y = pb.Y() * part2; + Float_t part4z = pb.Z() * part2; + Float_t part4e = pb.T() * part2; + + TLorentzVector part3(TVector3(part3x, part3y, part3z), part3e); + TLorentzVector part4(TVector3(part4x, part4y, part4z), part4e); + + // Un-normalized Z + z = part3 - part4; + + // Normalized z + Float_t normz = std::sqrt(-z * z); + Float_t znx = z.X() / normz; + Float_t zny = z.Y() / normz; + Float_t znz = z.Z() / normz; + Float_t zne = z.E() / normz; + + // Normalized z + TLorentzVector zhat(TVector3(znx, zny, znz), zne); + + // calculate x + TLorentzVector x; + + Float_t constant1 = (lv->Dot(*lv)) / (2 * (lv->Dot(pa))); + Float_t constant2 = (lv->Dot(*lv)) / (2 * (lv->Dot(pb))); + + Float_t comp1x = pa.X() * constant1; + Float_t comp1y = pa.Y() * constant1; + Float_t comp1z = pa.Z() * constant1; + Float_t comp1e = pa.T() * constant1; + + TLorentzVector comp1(TVector3(comp1x, comp1y, comp1z), comp1e); + + Float_t comp2x = pb.X() * constant2; + Float_t comp2y = pb.Y() * constant2; + Float_t comp2z = pb.Z() * constant2; + Float_t comp2e = pb.T() * constant2; + + TLorentzVector comp2(TVector3(comp2x, comp2y, comp2z), comp2e); + + // Un-normalized x + x = *lv - comp1 - comp2; + // normalize x + Float_t normx = std::sqrt(-x * x); + Float_t xnx = x.X() / normx; + Float_t xny = x.Y() / normx; + Float_t xnz = x.Z() / normx; + Float_t xne = x.E() / normx; + + // Normalized x + TLorentzVector xhat(TVector3(xnx, xny, xnz), xne); + + // calculate y + // TLorentzVector y; + Float_t yone = pa.Y() * pb.Z() * lv->E() - pa.Z() * pb.Y() * lv->E() + pa.Z() * pb.E() * lv->Y() + pa.E() * pb.Y() * lv->Z() - pa.Y() * pb.E() * lv->Z() - pa.E() * pb.Z() * lv->Y(); + Float_t ytwo = -pa.Z() * pb.E() * lv->X() + pa.Z() * pb.X() * lv->E() - pa.X() * pb.Z() * lv->E() + pa.X() * pb.E() * lv->Z() - pa.E() * pb.X() * lv->Z() + pa.E() * pb.Z() * lv->X(); + Float_t ythree = pa.X() * pb.Y() * lv->E() - pa.Y() * pb.X() * lv->E() + pa.Y() * pb.E() * lv->X() - pa.X() * pb.E() * lv->Y() + pa.E() * pb.X() * lv->Y() - pa.E() * pb.Y() * lv->X(); + Float_t yfour = -pa.X() * pb.Y() * lv->Z() + pa.X() * pb.Z() * lv->Y() - pa.Z() * pb.X() * lv->Y() + pa.Z() * pb.Y() * lv->X() - pa.Y() * pb.Z() * lv->X() + pa.Y() * pb.X() * lv->Z(); + + // Un-normalized y + TLorentzVector y(TVector3(yone, ytwo, ythree), yfour); + + // normalize y + Float_t normy = std::sqrt(-y * y); + Float_t ynx = y.X() / normy; + Float_t yny = y.Y() / normy; + Float_t ynz = y.Z() / normy; + Float_t yne = y.E() / normy; + + // normalized y + TLorentzVector yhat(TVector3(ynx, yny, ynz), yne); + + // Lepton momentum difference + TLorentzVector diff; + diff = (*lv1 - *lv2); + Float_t diff2x = diff.X() / 2.; + Float_t diff2y = diff.Y() / 2.; + Float_t diff2z = diff.Z() / 2.; + Float_t diff2e = diff.E() / 2.; + TLorentzVector diff2(TVector3(diff2x, diff2y, diff2z), diff2e); + + // Normalize diff2 + Float_t norm2 = std::sqrt(-diff2 * diff2); + Float_t diff3x = diff2.X() / norm2; + Float_t diff3y = diff2.Y() / norm2; + Float_t diff3z = diff2.Z() / norm2; + Float_t diff3e = diff2.E() / norm2; + + TLorentzVector diff3(TVector3(diff3x, diff3y, diff3z), diff3e); + + // computing the angles + float cosThetaCS = zhat * diff3; + Double_t SinThetaCosPhiCS = xhat * diff3; + Double_t SinThetaSinPhiCS = yhat * diff3; + //************************************** + + float phi = atan2(SinThetaSinPhiCS, SinThetaCosPhiCS); + // if (phi>=0) phi = phi; + if (phi < 0) + phi = phi + o2::constants::math::TwoPI; + + q[0] = accoplCut; + q[1] = phi; + q[2] = cosThetaCS; + + return q; + } + + double DeltaPhi(TLorentzVector lv1, TLorentzVector lv2) + { + TLorentzVector lv_sum = lv1 + lv2; + TLorentzVector lv_diff = lv1 - lv2; + + double dp = lv_sum.DeltaPhi(lv_diff); + + return dp; + } + //____________________________________________________________________________________________ + float momentum(float px, float py, float pz) + // Just a simple function to return momentum + { + return std::sqrt(px * px + py * py + pz * pz); + } + + //______________________________________________________________________________________________________ + float eta(float px, float py, float pz) + // Just a simple function to return pseudorapidity + { + float arg = -2.; // outside valid range for std::atanh + float mom = momentum(px, py, pz); + if (mom != 0) + arg = pz / mom; + if (-1. < arg && arg < 1.) + return std::atanh(arg); // definition of eta + return -999.; + } + + //----------------------------------------------------------------------------------------------------------------------- + void init(o2::framework::InitContext&) + { + + registry.add("GapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + registry.add("TrueGapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + + registry.add("posx", "Vertex position in x", kTH1F, {{100, -0.5, 0.5}}); + registry.add("posy", "Vertex position in y", kTH1F, {{100, -0.5, 0.5}}); + registry.add("posz", "Vertex position in z", kTH1F, {{1000, -100., 100.}}); + + auto hSelectionCounter = registry.add("hSelectionCounter", "hSelectionCounter;;NEvents", HistType::kTH1I, {{20, 0., 20.}}); + + TString SelectionCuts[18] = {"NoSelection", "gapside", "goodtracks", "truegap", "ncollcontrib ", "zvtx", "2collcontrib", "2goodtrk", "TPCPID", "Rap_cut", "unlikesign", "mass_cut", "coherent", "incoherent", "likesign", "mass_cut", "coherent", "incoherent"}; + // now we can set BinLabel in histogram Registry + + for (int i = 0; i < 18; i++) { + hSelectionCounter->GetXaxis()->SetBinLabel(i + 1, SelectionCuts[i].Data()); + } + // tracks + registry.add("hTracks", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hTracksPions", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("TwoPion/h2TracksPions", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("h4TracksPions", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("h6TracksPions", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("h8TracksPions", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + + registry.add("hdEdx", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {100, 0.0, 200.0}}); + registry.add("hdEdxPion", "p_{#pi} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {100, 0.0, 200.0}}); + + registry.add("TwoPion/hNsigPi1vsPi2", "NSigmaPi(t1) vs NSigmapi (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); + registry.add("TwoPion/hNsigEl1vsEl2", "NSigmaEl(t1) vs NSigmaEl (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); + registry.add("TwoPion/hNsigPivsPt1", "Pt vs NSigmaPi (t1);#it{p_{t}}, GeV/c;n#sigma_{#pi}", kTH2F, {{100, 0., 2.5}, {100, -15., 15}}); + registry.add("TwoPion/hNsigPivsPt2", "Pt vs NSigmaPi (t2);#it{p_{t}}, GeV/c;n#sigma_{#pi}", kTH2F, {{100, 0., 2.5}, {100, -15., 15}}); + registry.add("TwoPion/hNsigElvsPt1", "Pt vs NSigmaEl (t1);#it{p_{t}}, GeV/c;n#sigma_{#e}", kTH2F, {{100, 0., 2.5}, {100, -15., 15}}); + registry.add("TwoPion/hNsigElvsPt2", "Pt vs NSigmaEl (t2);#it{p_{t}}, GeV/c;n#sigma_{#e}", kTH2F, {{100, 0., 2.5}, {100, -15., 15}}); + registry.add("TwoPion/hNsigMuvsPt1", "Pt vs NSigmaMu (t1);#it{p_{t}}, GeV/c;n#sigma_{#pi}", kTH2F, {{100, 0., 2.5}, {100, -15., 15}}); + registry.add("TwoPion/hNsigMuvsPt2", "Pt vs NSigmaMu (t2);#it{p_{t}}, GeV/c;n#sigma_{#pi}", kTH2F, {{100, 0., 2.5}, {100, -15., 15}}); + registry.add("trackpt", "Track pT per track; Track pT; Track bit; Tracks", {HistType::kTH2F, {{4, 0.5, 4.5}, {100, 0.0, 10.}}}); + registry.add("tracketa", "Track eta per track; Track eta; Track bit; Tracks", {HistType::kTH2F, {{4, 0.5, 4.5}, {100, -5, 5.}}}); + registry.add("trackphi", "Track phi per track; Track phi; Track bit; Tracks", {HistType::kTH2F, {{4, 0.5, 4.5}, {100, 0. * TMath::Pi(), 2. * TMath::Pi()}}}); + registry.add("tracksign", "Track sign per track; Track sign; Track bit; Tracks", {HistType::kTH2F, {{4, 0.5, 4.5}, {200, -10., 10.}}}); + + registry.add("hCharge", "Charge;#it{charge};", kTH1F, {{500, -10., 10.}}); + registry.add("TwoPion/hPtsingle_track1", "Pt t1;#it{p_{t}}, GeV/c;", kTH1F, {{600, 0., 3.}}); + registry.add("TwoPion/hPtsingle_track2", "Pt t2;#it{p_{t}}, GeV/c;", kTH1F, {{600, 0., 3.}}); + registry.add("TwoPion/hEta_t1", "Eta of t1;#it{#eta};", kTH1F, {{100, -5., 5.}}); + registry.add("TwoPion/hEta_t2", "Eta of t2;#it{#eta};", kTH1F, {{100, -5., 5.}}); + registry.add("TwoPion/hP1", "P vs TPC signal;#it{P_{track}}, GeV/c; signal_{TPC} t1", kTH2F, {{100, 0., 2.}, {300, 0, 150}}); + registry.add("TwoPion/hTPCsig", "TPC signal;signal_{TPC} t2; signal_{TPC} t2", kTH2F, {{300, 0., 150.}, {300, 0, 150}}); + registry.add("TwoPion/hP2", "P vs TPC signal;#it{P_{track}}, GeV/c; signal_{TPC} t1", kTH2F, {{100, 0., 2.}, {300, 0, 150}}); + registry.add("TwoPion/hTPCsig1", "TPC signal;signal_{TPC} t2; signal_{TPC} t2", kTH2F, {{300, 0., 150.}, {300, 0, 150}}); + + registry.add("TwoPion/hMassLike", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{20000, 0., 20.}}); + registry.add("TwoPion/hMassUnlike", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{20000, 0., 20.}}); + registry.add("TwoPion/Coherent/hMassUnlikeCoherent", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{20000, 0., 20.}}); + registry.add("TwoPion/Coherent/hMassLikeCoherent", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{20000, 0., 20.}}); + registry.add("TwoPion/Incoherent/hMassUnlikeInCoherent", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{20000, 0., 20.}}); + registry.add("TwoPion/Incoherent/hMassLikeInCoherent", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{20000, 0., 20.}}); + registry.add("hMassFourPionsCoherent", "Raw Inv.M;#it{M_{#pi#pi}} (GeV/c^{2});", kTH1D, {{1000, 0., 10.}}); + registry.add("hMassSixPionsCoherent", "Raw Inv.M;#it{M_{6#pi}} (GeV/c^{2});", kTH1D, {{1000, 0., 10.}}); + registry.add("hMassEightPionsCoherent", "Raw Inv.M;#it{M_{6#pi}} (GeV/c^{2});", kTH1D, {{1000, 0., 10.}}); + registry.add("hMassFourPions", "Raw Inv.M;#it{M_{4#pi}} (GeV/c^{2});", kTH1D, {{1000, 0., 10.}}); + registry.add("hMassSixPions", "Raw Inv.M;#it{M_{6#pi}} (GeV/c^{2});", kTH1D, {{1000, 0., 10.}}); + registry.add("hMassEightPions", "Raw Inv.M;#it{M_{8#pi}} (GeV/c^{2});", kTH1D, {{1000, 0., 10.}}); + registry.add("hMassFourPionsRightSign", "Raw Inv.M;#it{M_{4#pi}} (GeV/c^{2});", kTH1D, {{1000, 0., 10.}}); + registry.add("hMassSixPionsRightSign", "Raw Inv.M;#it{M_{6#pi}} (GeV/c^{2});", kTH1D, {{1000, 0., 10.}}); + registry.add("hMass8PionsRightSign", "Raw Inv.M;#it{M_{8#pi}} (GeV/c^{2});", kTH1D, {{1000, 0., 10.}}); + + registry.add("hPhiEtaFourPionsRightSign", "Phi vs Eta;#it{#phi};#it{#eta};", kTH2F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}, {120, -2, 2}}); + registry.add("hPhiEtaSixPionsRightSign", "Phi vs Eta;#it{#phi};#it{#eta};", kTH2F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}, {120, -2, 2}}); + registry.add("hPhiEta8PionsRightSign", "Phi vs Eta;#it{#phi};#it{#eta};", kTH2F, {{100, 0. * TMath::Pi(), 2. * TMath::Pi()}, {120, -2, 2}}); + + registry.add("TwoPion/hPt", "Pt;#it{p_{t}}, GeV/c;", kTH1D, {{1000, 0., 10.}}); + registry.add("TwoPion/hPtLike", "Pt;#it{p_{t}}, GeV/c;", kTH1D, {{1000, 0., 10.}}); + registry.add("hPt4Pion", "Pt1;#it{p_{t}}, GeV/c;", kTH1D, {{1000, 0., 10.}}); + registry.add("hPt6Pion", "Pt2;#it{p_{t}}, GeV/c;", kTH1D, {{1000, 0., 10.}}); + registry.add("hPt8Pion", "Pt2;#it{p_{t}}, GeV/c;", kTH1D, {{1000, 0., 10.}}); + registry.add("hPt4PionRightSign", "Pt1;#it{p_{t}}, GeV/c;", kTH1D, {{1000, 0., 10.}}); + registry.add("hPt6PionRightSign", "Pt2;#it{p_{t}}, GeV/c;", kTH1D, {{1000, 0., 10.}}); + registry.add("hPt8PionRightSign", "Pt2;#it{p_{t}}, GeV/c;", kTH1D, {{1000, 0., 10.}}); + + registry.add("TwoPion/hEta", "Eta;#it{#eta};", kTH1F, {{500, -10., 10.}}); + registry.add("hEta4Pion", "Eta of four pion;#it{#eta};", kTH1F, {{100, -5., 5.}}); + registry.add("hEta6Pion", "Eta of six pion;#it{#eta};", kTH1F, {{100, -5., 5.}}); + registry.add("hEta8Pion", "Eta of six pion;#it{#eta};", kTH1F, {{100, -5., 5.}}); + + registry.add("TwoPion/hRap", "Rapidity;#it{y};", kTH1F, {{500, -10., 10.}}); + registry.add("hRap4Pion", "Rapidity;#it{y};", kTH1F, {{500, -10., 10.}}); + registry.add("hRap6Pion", "Rapidity;#it{y};", kTH1F, {{500, -10., 10.}}); + registry.add("hRap8pion", "Rapidity;#it{y};", kTH1F, {{500, -10., 10.}}); + + registry.add("TwoPion/hPhiSystem", "Phi;#it{#Phi};", kTH1F, {{250, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + + registry.add("TwoPion/hMPt", "Inv.M vs Pt;M, GeV/c^{2};#it{P_{t}}, GeV/c;", kTH2F, {{100, 0., 10.}, {100, 0., 10.}}); + registry.add("hMPt1", "Inv.M vs Pt;M, GeV/c^{2};#it{P_{t}}, GeV/c;", kTH2F, {{100, 0., 10.}, {100, 0., 10.}}); + registry.add("hMPt2", "Inv.M vs Pt;M, GeV/c^{2};#it{P_{t}}, GeV/c;", kTH2F, {{100, 0., 10.}, {100, 0., 10.}}); + registry.add("hMPt3", "Inv.M vs Pt;M, GeV/c^{2};#it{P_{t}}, GeV/c;", kTH2F, {{100, 0., 20.}, {100, 0., 10.}}); + + // Uisng Polarisaion method + registry.add("TwoPion/Coherent/hPhi", "Phi;#it{#Phi};", kTH1F, {{250, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("TwoPion/Incoherent/hPhiInCoherent", "Phi;#it{#Phi};", kTH1F, {{250, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("hPhi4Pion", "Phi;#it{#Phi};", kTH1F, {{250, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("hPhi6Pion", "Phi;#it{#Phi};", kTH1F, {{250, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("hPhi8Pion", "Phi;#it{#Phi};", kTH1F, {{250, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + + registry.add("TwoPion/Coherent/hCostheta", "Costheta;#it{Cos#Theta};", kTH1F, {{300, -1.5, 1.5}}); + registry.add("TwoPion/Incoherent/hCosthetaInCoherent", "Costheta;#it{Cos#Theta};", kTH1F, {{300, -1.5, 1.5}}); + registry.add("hCostheta4Pion", "Costheta;#it{Cos#Theta};", kTH1F, {{300, -1.5, 1.5}}); + registry.add("hCostheta6Pion", "Costheta;#it{Cos#Theta};", kTH1F, {{300, -1.5, 1.5}}); + registry.add("hCostheta8Pion", "Costheta;#it{Cos#Theta};", kTH1F, {{300, -1.5, 1.5}}); + + // Using Angular Correlation method + + registry.add("TwoPion/Coherent/AccoplAngle", "AccoplAngle", kTH1F, {{250, -0.2, 0.2}}); + registry.add("TwoPion/Coherent/CosTheta", "CosTheta", kTH1F, {{300, -1.5, 1.5}}); + registry.add("TwoPion/Coherent/Phi", "Phi", kTH1F, {{250, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("TwoPion/Coherent/Phi1", "Phi1", kTH1F, {{250, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("TwoPion/Coherent/Phi2", "Phi2", kTH1F, {{250, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("TwoPion/Coherent/CosThetaPhi", "CosThetaPhi", kTH2F, {{300, -1.5, 1.5}, {250, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + + registry.add("TwoPion/Incoherent/AccoplAngle", "AccoplAngle", kTH1F, {{250, -0.2, 0.2}}); + registry.add("TwoPion/Incoherent/CosTheta", "CosTheta", kTH1F, {{300, -1.5, 1.5}}); + registry.add("TwoPion/Incoherent/Phi", "Phi", kTH1F, {{250, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("TwoPion/Incoherent/Phi1", "Phi1", kTH1F, {{250, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("TwoPion/Incoherent/Phi2", "Phi2", kTH1F, {{250, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("TwoPion/Incoherent/CosThetaPhi", "CosThetaPhi", kTH2F, {{300, -1.5, 1.5}, {250, 0., 2. * TMath::Pi()}}); + + // Asymmetry histograms + registry.add("TwoPion/Coherent/DeltaPhi", "DeltaPhi", kTH1F, {{360, -TMath::Pi(), TMath::Pi()}}); + registry.add("TwoPion/Incoherent/DeltaPhi", "DeltaPhi", kTH1F, {{360, -TMath::Pi(), TMath::Pi()}}); + } + + using udtracks = soa::Join; + using udtracksfull = soa::Join; + using UDCollisionsFull = soa::Join; + //__________________________________________________________________________ + // Main process + void process(UDCollisionsFull::iterator const& collision, udtracksfull const& tracks) + { + registry.fill(HIST("hSelectionCounter"), 0); + // LOGF(info, " BC ID %d",collision.gapSide()); + int gapSide = collision.gapSide(); + if (gapSide < 0 || gapSide > 2) + return; + + registry.fill(HIST("hSelectionCounter"), 1); + + float FIT_cut[5] = {FV0_cut, FT0A_cut, FT0C_cut, FDDA_cut, FDDC_cut}; + // int truegapSide = sgSelector.trueGap(collision, FV0_cut, ZDC_cut); + int truegapSide = sgSelector.trueGap(collision, FIT_cut[0], FIT_cut[1], FIT_cut[2], ZDC_cut); + std::vector parameters = {PV_cut, dcaZ_cut, dcaXY_cut, tpcChi2_cut, tpcNClsFindable_cut, itsChi2_cut, eta_cut, pt_cut}; + registry.fill(HIST("hSelectionCounter"), 2); + + registry.fill(HIST("GapSide"), gapSide); + registry.fill(HIST("TrueGapSide"), truegapSide); + gapSide = truegapSide; + + if (gapSide == gap_Side) { + + registry.fill(HIST("hSelectionCounter"), 3); + //_____________________________________ + // Create pions and apply TPC Pion PID + std::vector allTracks; + std::vector onlyPionTracks; + std::vector onlyPionSigma; + std::vector rawPionTracks; + std::vector trackpt; + std::vector tracketa; + std::vector trackphi; + std::vector tracksign; + TLorentzVector p; + registry.fill(HIST("hTracks"), tracks.size()); + + if (collision.numContrib() > collcontrib_cut) + return; + + registry.fill(HIST("hSelectionCounter"), 4); + if ((collision.posZ() < -(Zvtx_cut)) || (collision.posZ() > Zvtx_cut)) + return; + registry.fill(HIST("hSelectionCounter"), 5); + + for (auto t : tracks) { + + /*if (!t.isPVContributor()) { + continue; + }*/ + + if (!trackselector(t, parameters)) + continue; + + // int NFindable = t.tpcNClsFindable(); + // int NMinusFound = t.tpcNClsFindableMinusFound(); + // int NCluster = NFindable - NMinusFound; + + /*if (NCluster < TPC_cluster) { + continue; + }*/ + + double dEdx = t.tpcSignal(); + + registry.fill(HIST("hdEdx"), t.tpcInnerParam() / t.sign(), dEdx); + TLorentzVector a; + a.SetXYZM(t.px(), t.py(), t.pz(), o2::constants::physics::MassPionCharged); + allTracks.push_back(a); + auto nSigmaPi = t.tpcNSigmaPi(); + + if (fabs(nSigmaPi) < PID_cut) { + onlyPionTracks.push_back(a); + onlyPionSigma.push_back(nSigmaPi); + rawPionTracks.push_back(t); + registry.fill(HIST("hdEdxPion"), t.tpcInnerParam() / t.sign(), dEdx); + } + } + registry.fill(HIST("hTracksPions"), onlyPionTracks.size()); + //_____________________________________ + // Creating rhos + for (auto pion : onlyPionTracks) { + p += pion; + } + //_____________________________________ + if (collision.numContrib() == 4) { + // Four pions analysis + + if ((rawPionTracks.size() == 4) && (onlyPionTracks.size() == 4)) { + + registry.get(HIST("trackpt"))->Fill(1., onlyPionTracks[0].Pt()); + registry.get(HIST("trackpt"))->Fill(2., onlyPionTracks[1].Pt()); + registry.get(HIST("trackpt"))->Fill(3., onlyPionTracks[2].Pt()); + registry.get(HIST("trackpt"))->Fill(4., onlyPionTracks[3].Pt()); + + registry.get(HIST("tracketa"))->Fill(1., onlyPionTracks[0].Eta()); + registry.get(HIST("tracketa"))->Fill(2., onlyPionTracks[1].Eta()); + registry.get(HIST("tracketa"))->Fill(3., onlyPionTracks[2].Eta()); + registry.get(HIST("tracketa"))->Fill(4., onlyPionTracks[3].Eta()); + + registry.get(HIST("trackphi"))->Fill(1., onlyPionTracks[0].Phi()); + registry.get(HIST("trackphi"))->Fill(2., onlyPionTracks[1].Phi()); + registry.get(HIST("trackphi"))->Fill(3., onlyPionTracks[2].Phi()); + registry.get(HIST("trackphi"))->Fill(4., onlyPionTracks[3].Phi()); + + registry.get(HIST("tracksign"))->Fill(1., rawPionTracks[0].sign()); + registry.get(HIST("tracksign"))->Fill(2., rawPionTracks[1].sign()); + registry.get(HIST("tracksign"))->Fill(3., rawPionTracks[2].sign()); + registry.get(HIST("tracksign"))->Fill(4., rawPionTracks[3].sign()); + + int sign = 0; + TLorentzVector piplus, piminus; + for (auto rawPion : rawPionTracks) { + sign += rawPion.sign(); + if (rawPion.sign() > 0) { + piplus = onlyPionTracks[0]; + piplus = onlyPionTracks[1]; + piplus = onlyPionTracks[2]; + piplus = onlyPionTracks[3]; + } else if (rawPion.sign() < 0) { + piminus = onlyPionTracks[0]; + piminus = onlyPionTracks[1]; + piminus = onlyPionTracks[2]; + piminus = onlyPionTracks[3]; + } + } + + auto costheta = CosThetaHelicityFrame(piplus, piminus, p); + registry.fill(HIST("hCostheta4Pion"), costheta); + auto phihel = 1. * TMath::Pi() + PhiHelicityFrame(piplus, piminus, p); + registry.fill(HIST("hPhi4Pion"), phihel); + + if ((p.Rapidity() > -Rap_cut) && (p.Rapidity() < Rap_cut)) { + if ((p.M() > 0.8) && (p.M() < 2.5)) { + if (sign != 0) { + registry.fill(HIST("hMassFourPions"), p.M()); + registry.fill(HIST("hPt4Pion"), p.Pt()); + } + + if (sign == 0) { + registry.fill(HIST("hCharge"), sign); + registry.fill(HIST("h4TracksPions"), onlyPionTracks.size()); + + if (p.Pt() < Pt_coherent) { + registry.fill(HIST("hMassFourPionsCoherent"), p.M()); + } + + registry.fill(HIST("hPt4PionRightSign"), p.Pt()); + + registry.fill(HIST("hMassFourPionsRightSign"), p.M()); + registry.fill(HIST("hMPt1"), p.M(), p.Pt()); + registry.fill(HIST("hRap4Pion"), p.Rapidity()); + registry.fill(HIST("hEta4Pion"), p.Eta()); + } + for (auto pion : onlyPionTracks) { + registry.fill(HIST("hPhiEtaFourPionsRightSign"), pion.Phi(), pion.Eta()); + } + } + } + } + } + //_____________________________________________________________________________________________________ + // Six pions analysis + if (collision.numContrib() == 6) { + if ((rawPionTracks.size() == 6) && (onlyPionTracks.size() == 6)) { + + int sign = 0; + TLorentzVector piplus, piminus; + for (auto rawPion : rawPionTracks) { + sign += rawPion.sign(); + if (rawPion.sign() > 0) { + piplus = onlyPionTracks[0]; + piplus = onlyPionTracks[1]; + piplus = onlyPionTracks[2]; + piplus = onlyPionTracks[3]; + piplus = onlyPionTracks[4]; + piplus = onlyPionTracks[5]; + + } else if (rawPion.sign() < 0) { + piminus = onlyPionTracks[0]; + piminus = onlyPionTracks[1]; + piminus = onlyPionTracks[2]; + piminus = onlyPionTracks[3]; + piminus = onlyPionTracks[4]; + piminus = onlyPionTracks[5]; + } + } + + auto costheta = CosThetaHelicityFrame(piplus, piminus, p); + registry.fill(HIST("hCostheta6Pion"), costheta); + auto phihel = 1. * TMath::Pi() + PhiHelicityFrame(piplus, piminus, p); + registry.fill(HIST("hPhi6Pion"), phihel); + + if ((p.Rapidity() > -Rap_cut) && (p.Rapidity() < Rap_cut)) { + if (sign != 0) { + registry.fill(HIST("hMassSixPions"), p.M()); + registry.fill(HIST("hPt6Pion"), p.Pt()); + } + + if (sign == 0) { + registry.fill(HIST("h6TracksPions"), onlyPionTracks.size()); + if (p.Pt() < Pt_coherent) { + registry.fill(HIST("hMassSixPionsCoherent"), p.M()); + } + registry.fill(HIST("hMassSixPionsRightSign"), p.M()); + registry.fill(HIST("hMPt2"), p.M(), p.Pt()); + registry.fill(HIST("hRap6Pion"), p.Rapidity()); + registry.fill(HIST("hEta6Pion"), p.Eta()); + registry.fill(HIST("hPt6PionRightSign"), p.Pt()); + for (auto pion : onlyPionTracks) { + registry.fill(HIST("hPhiEtaSixPionsRightSign"), pion.Phi(), pion.Eta()); + } + } + } + } + } + //_____________________________________ + // Eight pions analysis + if (collision.numContrib() == 8) { + if ((rawPionTracks.size() == 8) && (onlyPionTracks.size() == 8)) { + TLorentzVector piplus, piminus; + int sign = 0; + for (auto rawPion : rawPionTracks) { + sign += rawPion.sign(); + + if (rawPion.sign() > 0) { + piplus = onlyPionTracks[0]; + piplus = onlyPionTracks[1]; + piplus = onlyPionTracks[2]; + piplus = onlyPionTracks[3]; + piplus = onlyPionTracks[4]; + piplus = onlyPionTracks[5]; + piplus = onlyPionTracks[6]; + piplus = onlyPionTracks[7]; + + } else if (rawPion.sign() < 0) { + piminus = onlyPionTracks[0]; + piminus = onlyPionTracks[1]; + piminus = onlyPionTracks[2]; + piminus = onlyPionTracks[3]; + piminus = onlyPionTracks[4]; + piminus = onlyPionTracks[5]; + piminus = onlyPionTracks[6]; + piminus = onlyPionTracks[7]; + } + } + + auto costheta = CosThetaHelicityFrame(piplus, piminus, p); + registry.fill(HIST("hCostheta8Pion"), costheta); + auto phihel = 1. * TMath::Pi() + PhiHelicityFrame(piplus, piminus, p); + registry.fill(HIST("hPhi8Pion"), phihel); + + if ((p.Rapidity() > -Rap_cut) && (p.Rapidity() < Rap_cut)) { + if (sign != 0) { + registry.fill(HIST("hMassEightPions"), p.M()); + registry.fill(HIST("hPt8Pion"), p.Pt()); + } + if (sign == 0) { + registry.fill(HIST("h8TracksPions"), onlyPionTracks.size()); + if (p.Pt() < Pt_coherent) { + registry.fill(HIST("hMassEightPionsCoherent"), p.M()); + } + registry.fill(HIST("hMass8PionsRightSign"), p.M()); + registry.fill(HIST("hPt8PionRightSign"), p.Pt()); + registry.fill(HIST("hMPt3"), p.M(), p.Pt()); + registry.fill(HIST("hRap8pion"), p.Rapidity()); + registry.fill(HIST("hEta8Pion"), p.Eta()); + for (auto pion : onlyPionTracks) { + registry.fill(HIST("hPhiEta8PionsRightSign"), pion.Phi(), pion.Eta()); + } + } + } + } + } + //_____________________________________ + // CUTS + if (collision.numContrib() == 2) { + registry.fill(HIST("hSelectionCounter"), 6); + + if ((rawPionTracks.size() == 2) && (onlyPionTracks.size() == 2)) { + registry.fill(HIST("hSelectionCounter"), 7); + + registry.fill(HIST("TwoPion/h2TracksPions"), onlyPionTracks.size()); + registry.fill(HIST("TwoPion/hNsigPivsPt1"), onlyPionTracks[0].Pt(), rawPionTracks[0].tpcNSigmaPi()); + registry.fill(HIST("TwoPion/hNsigPivsPt2"), onlyPionTracks[1].Pt(), rawPionTracks[1].tpcNSigmaPi()); + registry.fill(HIST("TwoPion/hTPCsig"), rawPionTracks[0].tpcSignal(), rawPionTracks[1].tpcSignal()); + registry.fill(HIST("TwoPion/hNsigPi1vsPi2"), rawPionTracks[0].tpcNSigmaPi(), rawPionTracks[1].tpcNSigmaPi()); + + if ((onlyPionSigma[0] * onlyPionSigma[0] + onlyPionSigma[1] * onlyPionSigma[1]) > (PID_cut * PID_cut)) { + return; + } + registry.fill(HIST("hSelectionCounter"), 8); + if ((p.Rapidity() < -Rap_cut) || (p.Rapidity() > Rap_cut)) { + return; + } + registry.fill(HIST("hSelectionCounter"), 9); + + TLorentzVector tplus, tminus; + if (rawPionTracks[0].sign() > 0) { + tplus = onlyPionTracks[0]; + } else { + tminus = onlyPionTracks[0]; + } + if (rawPionTracks[1].sign() < 0) { + tminus = onlyPionTracks[1]; + } else { + tplus = onlyPionTracks[1]; + } + + auto costheta = CosThetaHelicityFrame(tplus, tminus, p); + auto phihel = 1. * TMath::Pi() + PhiHelicityFrame(tplus, tminus, p); + + // Unlike sign + if (rawPionTracks[0].sign() != rawPionTracks[1].sign()) { + + registry.fill(HIST("hSelectionCounter"), 10); + registry.fill(HIST("TwoPion/hMassUnlike"), p.M()); + + if ((p.M() > Mass_Min) && (p.M() < Mass_Max)) { + + registry.fill(HIST("hSelectionCounter"), 11); + + registry.fill(HIST("TwoPion/hPt"), p.Pt()); + registry.fill(HIST("TwoPion/hEta"), p.Eta()); + registry.fill(HIST("TwoPion/hRap"), p.Rapidity()); + registry.fill(HIST("TwoPion/hPhiSystem"), p.Phi()); + registry.fill(HIST("TwoPion/hMPt"), p.M(), p.Pt()); + + if (p.Pt() < Pt_coherent) { + + registry.fill(HIST("hSelectionCounter"), 12); + + // Quality Control + registry.fill(HIST("TwoPion/hEta_t1"), onlyPionTracks[0].Eta()); + registry.fill(HIST("TwoPion/hEta_t2"), onlyPionTracks[1].Eta()); + registry.fill(HIST("TwoPion/hPtsingle_track1"), onlyPionTracks[0].Pt()); + registry.fill(HIST("TwoPion/hPtsingle_track2"), onlyPionTracks[1].Pt()); + + registry.fill(HIST("TwoPion/hNsigMuvsPt1"), onlyPionTracks[0].Pt(), rawPionTracks[0].tpcNSigmaPi()); + registry.fill(HIST("TwoPion/hNsigMuvsPt2"), onlyPionTracks[1].Pt(), rawPionTracks[1].tpcNSigmaPi()); + registry.fill(HIST("TwoPion/hNsigElvsPt1"), onlyPionTracks[0].Pt(), rawPionTracks[0].tpcNSigmaEl()); + registry.fill(HIST("TwoPion/hNsigElvsPt2"), onlyPionTracks[1].Pt(), rawPionTracks[1].tpcNSigmaEl()); + registry.fill(HIST("TwoPion/hNsigEl1vsEl2"), rawPionTracks[0].tpcNSigmaPi(), rawPionTracks[1].tpcNSigmaPi()); + + registry.fill(HIST("TwoPion/hP1"), onlyPionTracks[0].P(), rawPionTracks[0].tpcSignal()); + registry.fill(HIST("TwoPion/hP2"), onlyPionTracks[1].P(), rawPionTracks[1].tpcSignal()); + registry.fill(HIST("TwoPion/hTPCsig1"), rawPionTracks[0].tpcSignal(), rawPionTracks[1].tpcSignal()); + + registry.fill(HIST("posx"), collision.posX()); + registry.fill(HIST("posy"), collision.posY()); + registry.fill(HIST("posz"), collision.posZ()); + + registry.fill(HIST("TwoPion/Coherent/hCostheta"), costheta); + registry.fill(HIST("TwoPion/Coherent/hPhi"), phihel); + registry.fill(HIST("TwoPion/Coherent/hMassUnlikeCoherent"), p.M()); + + // angular correlations + float* q = AngCorrelation(&onlyPionTracks[0], &onlyPionTracks[1], &p); + registry.fill(HIST("TwoPion/Coherent/Phi"), q[1], 1.); + registry.fill(HIST("TwoPion/Coherent/Phi1"), RecoDecay::phi(onlyPionTracks[0]), 1.); + registry.fill(HIST("TwoPion/Coherent/Phi2"), RecoDecay::phi(onlyPionTracks[1]), 1.); + registry.fill(HIST("TwoPion/Coherent/CosTheta"), q[2], 1.); + registry.fill(HIST("TwoPion/Coherent/CosThetaPhi"), q[2], q[1]); + registry.fill(HIST("TwoPion/Coherent/AccoplAngle"), q[0], 1.); + + double delphi = DeltaPhi(onlyPionTracks[0], onlyPionTracks[1]); + registry.fill(HIST("TwoPion/Coherent/DeltaPhi"), delphi); + } + + if (p.Pt() > Pt_coherent) { + + registry.fill(HIST("hSelectionCounter"), 13); + + registry.fill(HIST("TwoPion/Incoherent/hCosthetaInCoherent"), costheta); + registry.fill(HIST("TwoPion/Incoherent/hPhiInCoherent"), phihel); + registry.fill(HIST("TwoPion/Incoherent/hMassUnlikeInCoherent"), p.M()); + + // angular correlations + float* q = AngCorrelation(&onlyPionTracks[0], &onlyPionTracks[1], &p); + registry.fill(HIST("TwoPion/Incoherent/Phi"), q[1], 1.); + registry.fill(HIST("TwoPion/Incoherent/Phi1"), RecoDecay::phi(onlyPionTracks[0]), 1.); + registry.fill(HIST("TwoPion/Incoherent/Phi2"), RecoDecay::phi(onlyPionTracks[1]), 1.); + registry.fill(HIST("TwoPion/Incoherent/CosTheta"), q[2], 1.); + registry.fill(HIST("TwoPion/Incoherent/CosThetaPhi"), q[2], q[1]); + registry.fill(HIST("TwoPion/Incoherent/AccoplAngle"), q[0], 1.); + + double delphi = DeltaPhi(onlyPionTracks[0], onlyPionTracks[1]); + registry.fill(HIST("TwoPion/Incoherent/DeltaPhi"), delphi); + } + } + } + + // Like sign + if (rawPionTracks[0].sign() == rawPionTracks[1].sign()) { + + registry.fill(HIST("hSelectionCounter"), 14); + registry.fill(HIST("TwoPion/hMassLike"), p.M()); + if ((p.M() > Mass_Min) && (p.M() < Mass_Max)) { + registry.fill(HIST("hSelectionCounter"), 15); + registry.fill(HIST("TwoPion/hPtLike"), p.Pt()); + if (p.Pt() < Pt_coherent) { + registry.fill(HIST("hSelectionCounter"), 16); + registry.fill(HIST("TwoPion/Coherent/hMassLikeCoherent"), p.M()); + } + if (p.Pt() > Pt_coherent) { + registry.fill(HIST("hSelectionCounter"), 17); + registry.fill(HIST("TwoPion/Incoherent/hMassLikeInCoherent"), p.M()); + } + } + } + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/upcQuarkoniaCentralBarrel.cxx b/PWGUD/Tasks/upcQuarkoniaCentralBarrel.cxx new file mode 100644 index 00000000000..f195a750fa4 --- /dev/null +++ b/PWGUD/Tasks/upcQuarkoniaCentralBarrel.cxx @@ -0,0 +1,611 @@ +// 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 upcQuarkoniaCentralBarrel.cxx +/// \brief quarkonia --> ppbar task +/// +/// \author David Dobrigkeit Chinellato , Austrian Academy of Sciences & SMI +/// \author Roman Lavicka , Austrian Academy of Sciences & SMI +/// \author Romain Schotter , Austrian Academy of Sciences & SMI +// +// V0 analysis task +// ================ +// +// This code loops over a V0Cores table and produces some +// standard analysis output. It is meant to be run over +// derived data. +// +// +// Comments, questions, complaints, suggestions? +// Please write to: +// romain.schotter@cern.ch +// david.dobrigkeit.chinellato@cern.ch +// + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "ReconstructionDataFormats/Track.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "PWGUD/Core/SGSelector.h" + +#include "EventFiltering/Zorro.h" +#include "EventFiltering/ZorroSummary.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +using UDCollisions = soa::Join; +using UDCollision = UDCollisions::iterator; +using UDTracks = soa::Join; +using UDTrack = UDTracks::iterator; + +// simple checkers, but ensure 64 bit integers +#define BITSET(var, nbit) ((var) |= (static_cast(1) << static_cast(nbit))) +#define BITCHECK(var, nbit) ((var) & (static_cast(1) << static_cast(nbit))) + +struct upcQuarkoniaCentralBarrel { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable buildSameSignPairs{"buildSameSignPairs", false, "If true: build same-sign pairs, otherwise consider only opposite-sign pairs"}; + + // rapidity cut on the hyperon-antiHyperon pair + Configurable rapidityCut{"rapidityCut", 0.5, "rapidity cut on the ppbar pair"}; + + struct : ConfigurableGroup { + // Selection criteria: acceptance + Configurable etaCut{"trackSelections.etaCut", 0.8, "max eta for daughters"}; + + // Track quality + Configurable dcaxytopv{"trackSelections.dcaxytopv", .05, "max transverse DCA to PV (cm)"}; + Configurable dcaztopv{"trackSelections.dcaztopv", .05, "max longitudinal DCA to PV (cm)"}; + Configurable minTPCrows{"trackSelections.minTPCrows", 70, "minimum TPC crossed rows"}; + Configurable minTPCclusters{"trackSelections.minTPCclusters", 3, "minimum TPC clusters"}; + Configurable minTPCchi2clusters{"trackSelections.minTPCchi2clusters", 4.0, "minimum TPC chi2/clusters"}; + Configurable minTPCrowsoverfindable{"trackSelections.minTPCrowsoverfindable", 0.8, "minimum TPC rows/findable clusters"}; + Configurable minITSclusters{"trackSelections.minITSclusters", -1, "minimum ITS clusters"}; + Configurable minITSchi2clusters{"trackSelections.minITSchi2clusters", -1.0, "minimum ITS chi2/clusters"}; + Configurable requirePVcontributor{"trackSelections.requirePVcontributor", false, "require that track is a PV contributor"}; + Configurable applyDCAptdepsel{"trackSelections.applyDCAptdepsel", false, "apply DCA pt dep. cut à la Run2"}; + Configurable skipTPConly{"trackSelections.skipTPConly", false, "skip V0s comprised of at least one TPC only prong"}; + Configurable requireITSonly{"trackSelections.requirePosITSonly", false, "require that track is ITSonly (overrides TPC quality)"}; + Configurable rejectITSafterburner{"trackSelections.rejectNegITSafterburner", false, "reject track formed out of afterburner ITS tracks"}; + + // PID (TPC/TOF) + Configurable tpcPidNsigmaCut{"trackSelections.tpcPidNsigmaCut", 5, "tpcPidNsigmaCut"}; + Configurable tofPidNsigmaCut{"trackSelections.tofPidNsigmaCut", 1e+6, "tofPidNsigmaCut"}; + } trackSelections; + + // for MC + Configurable doMCAssociation{"doMCAssociation", true, "if MC, do MC association"}; + + // UPC selections + SGSelector sgSelector; + struct : ConfigurableGroup { + Configurable fv0Cut{"upcCuts.fv0Cut", 100., "FV0A threshold"}; + Configurable ft0aCut{"upcCuts.ft0aCut", 200., "FT0A threshold"}; + Configurable ft0cCut{"upcCuts.ft0cCut", 100., "FT0C threshold"}; + Configurable zdcCut{"upcCuts.zdcCut", 10., "ZDC threshold"}; + // Configurable gapSel{"upcCuts.gapSel", 2, "Gap selection"}; + } upcCuts; + + static constexpr float defaultLifetimeCuts[1][2] = {{30., 20.}}; + Configurable> lifetimecut{"lifetimecut", {defaultLifetimeCuts[0], 2, {"lifetimecutLambda", "lifetimecutK0S"}}, "lifetimecut"}; + + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f, 1.2f, 1.4f, 1.6f, 1.8f, 2.0f, 2.4f, 2.8f, 3.2f, 3.6f, 4.0f, 4.8f, 5.6f, 6.5f, 7.5f, 9.0f, 11.0f, 13.0f, 15.0f, 19.0f, 23.0f, 30.0f, 40.0f, 50.0f}, "pt axis for analysis"}; + ConfigurableAxis axisQuarkoniumMass{"axisQuarkoniumMass", {500, 2.600f, 4.000f}, "M (hyp. #bar{hyp.} ) (GeV/#it{c}^{2})"}; + ConfigurableAxis axisOccupancy{"axisOccupancy", {VARIABLE_WIDTH, 0.0f, 250.0f, 500.0f, 750.0f, 1000.0f, 1500.0f, 2000.0f, 3000.0f, 4500.0f, 6000.0f, 8000.0f, 10000.0f, 50000.0f}, "Occupancy"}; + + ConfigurableAxis axisDCAXYtoPV{"axisDCAXYtoPV", {20, 0.0f, 1.0f}, "DCAxy (cm)"}; + ConfigurableAxis axisDCAZtoPV{"axisDCAZtoPV", {20, 0.0f, 1.0f}, "DCAz (cm)"}; + ConfigurableAxis axisTPCrows{"axisTPCrows", {160, 0.0f, 160.0f}, "N TPC rows"}; + ConfigurableAxis axisTPCclus{"axisTPCclus", {160, 0.0f, 160.0f}, "N TPC Clusters"}; + ConfigurableAxis axisTPCChi2clus{"axisTPCChi2clus", {100, 0.0f, 50.0f}, "TPC Chi2/Clusters"}; + ConfigurableAxis axisTPCrowsOverFindable{"axisTPCrowsOverFindable", {100, 0.0f, 1.0f}, "TPC Rows/Findable"}; + ConfigurableAxis axisITSclus{"axisITSclus", {7, 0.0f, 7.0f}, "N ITS Clusters"}; + ConfigurableAxis axisITSChi2clus{"axisITSChi2clus", {100, 0.0f, 50.0f}, "ITS Chi2/Clusters"}; + ConfigurableAxis axisNsigmaTPC{"axisNsigmaTPC", {200, -10.0f, 10.0f}, "N sigma TPC"}; + ConfigurableAxis axisNsigmaTOF{"axisNsigmaTOF", {200, -10.0f, 10.0f}, "N sigma TOF"}; + + // UPC axes + ConfigurableAxis axisSelGap{"axisSelGap", {4, -1.5, 2.5}, "Gap side"}; + + // PDG database + Service pdgDB; + + void init(InitContext const&) + { + // Event Counters + histos.add("hEventPVz", "hEventPVz", kTH1F, {{100, -20.0f, +20.0f}}); + histos.add("hSelGapSideVsPVz", "hSelGapSideVsPVz", kTH2F, {axisSelGap, {100, -20.0f, +20.0f}}); + + histos.add("hEventOccupancy", "hEventOccupancy", kTH1F, {axisOccupancy}); + histos.add("hSelGapSideVsOccupancy", "hSelGapSideVsOccupancy", kTH2F, {axisSelGap, axisOccupancy}); + + histos.add("hGapSide", "Gap side; Entries", kTH1F, {{5, -0.5, 4.5}}); + histos.add("hSelGapSide", "Selected gap side; Entries", kTH1F, {axisSelGap}); + + // histograms versus mass + histos.add("PPbar/h2dMassPPbar", "h2dMassPPbar", kTH2F, {axisPt, axisQuarkoniumMass}); + // Non-UPC info + histos.add("PPbar/h2dMassPPbarHadronic", "h2dMassPPbarHadronic", kTH2F, {axisPt, axisQuarkoniumMass}); + // UPC info + histos.add("PPbar/h2dMassPPbarSGA", "h2dMassPPbarSGA", kTH2F, {axisPt, axisQuarkoniumMass}); + histos.add("PPbar/h2dMassPPbarSGC", "h2dMassPPbarSGC", kTH2F, {axisPt, axisQuarkoniumMass}); + histos.add("PPbar/h2dMassPPbarDG", "h2dMassPPbarDG", kTH2F, {axisPt, axisQuarkoniumMass}); + + histos.add("PPbar/h2dNbrOfProtonsVsSelGapSide", "h2dNbrOfProtonsVsSelGapSide", kTH2F, {axisSelGap, {100, -0.5f, 99.5f}}); + histos.add("PPbar/h2dNbrOfAntiProtonsVsSelGapSide", "h2dNbrOfAntiProtonsVsSelGapSide", kTH2F, {axisSelGap, {100, -0.5f, 99.5f}}); + // QA plot + // Proton Candidates before selections + histos.add("PPbar/Proton/hDCAxyToPV", "hDCAxyToPV", kTH1F, {axisDCAXYtoPV}); + histos.add("PPbar/Proton/hDCAzToPV", "hDCAzToPV", kTH1F, {axisDCAZtoPV}); + histos.add("PPbar/Proton/hTPCCrossedRows", "hTPCCrossedRows", kTH1F, {axisTPCrows}); + histos.add("PPbar/Proton/hTPCNClusters", "hTPCNClusters", kTH1F, {axisTPCclus}); + histos.add("PPbar/Proton/hTPCChi2Clusters", "hTPCChi2Clusters", kTH1F, {axisTPCChi2clus}); + histos.add("PPbar/Proton/hTPCCrossedRowsOverFindable", "hTPCCrossedRowsOverFindable", kTH1F, {axisTPCrowsOverFindable}); + histos.add("PPbar/Proton/hITSNClusters", "hITSNClusters", kTH1F, {axisITSclus}); + histos.add("PPbar/Proton/hITSChi2Clusters", "hITSChi2Clusters", kTH1F, {axisITSChi2clus}); + histos.add("PPbar/Proton/hTPCNsigma", "hTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("PPbar/Proton/hTOFNsigma", "hTOFNsigma", kTH1F, {axisNsigmaTOF}); + histos.add("PPbar/Proton/h2dITSvsTPCpts", "h2dITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + // Anti Proton before selections + histos.add("PPbar/AntiProton/hDCAxyToPV", "hDCAxyToPV", kTH1F, {axisDCAXYtoPV}); + histos.add("PPbar/AntiProton/hDCAzToPV", "hDCAzToPV", kTH1F, {axisDCAZtoPV}); + histos.add("PPbar/AntiProton/hTPCCrossedRows", "hTPCCrossedRows", kTH1F, {axisTPCrows}); + histos.add("PPbar/AntiProton/hTPCNClusters", "hTPCNClusters", kTH1F, {axisTPCclus}); + histos.add("PPbar/AntiProton/hTPCChi2Clusters", "hTPCChi2Clusters", kTH1F, {axisTPCChi2clus}); + histos.add("PPbar/AntiProton/hTPCCrossedRowsOverFindable", "hTPCCrossedRowsOverFindable", kTH1F, {axisTPCrowsOverFindable}); + histos.add("PPbar/AntiProton/hITSNClusters", "hITSNClusters", kTH1F, {axisITSclus}); + histos.add("PPbar/AntiProton/hITSChi2Clusters", "hITSChi2Clusters", kTH1F, {axisITSChi2clus}); + histos.add("PPbar/AntiProton/hTPCNsigma", "hTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("PPbar/AntiProton/hTOFNsigma", "hTOFNsigma", kTH1F, {axisNsigmaTOF}); + histos.add("PPbar/AntiProton/h2dITSvsTPCpts", "h2dITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + // Proton Candidates after selections + histos.add("PPbar/Proton/hDCAxyToPV_aftersel", "hDCAxyToPV", kTH1F, {axisDCAXYtoPV}); + histos.add("PPbar/Proton/hDCAzToPV_aftersel", "hDCAzToPV", kTH1F, {axisDCAZtoPV}); + histos.add("PPbar/Proton/hTPCCrossedRows_aftersel", "hTPCCrossedRows", kTH1F, {axisTPCrows}); + histos.add("PPbar/Proton/hTPCNClusters_aftersel", "hTPCNClusters", kTH1F, {axisTPCclus}); + histos.add("PPbar/Proton/hTPCChi2Clusters_aftersel", "hTPCChi2Clusters", kTH1F, {axisTPCChi2clus}); + histos.add("PPbar/Proton/hTPCCrossedRowsOverFindable_aftersel", "hTPCCrossedRowsOverFindable", kTH1F, {axisTPCrowsOverFindable}); + histos.add("PPbar/Proton/hITSNClusters_aftersel", "hITSNClusters", kTH1F, {axisITSclus}); + histos.add("PPbar/Proton/hITSChi2Clusters_aftersel", "hITSChi2Clusters", kTH1F, {axisITSChi2clus}); + histos.add("PPbar/Proton/hTPCNsigma_aftersel", "hTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("PPbar/Proton/hTOFNsigma_aftersel", "hTOFNsigma", kTH1F, {axisNsigmaTOF}); + histos.add("PPbar/Proton/h2dITSvsTPCpts_aftersel", "h2dITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + // Anti Proton after selections + histos.add("PPbar/AntiProton/hDCAxyToPV_aftersel", "hDCAxyToPV", kTH1F, {axisDCAXYtoPV}); + histos.add("PPbar/AntiProton/hDCAzToPV_aftersel", "hDCAzToPV", kTH1F, {axisDCAZtoPV}); + histos.add("PPbar/AntiProton/hTPCCrossedRows_aftersel", "hTPCCrossedRows", kTH1F, {axisTPCrows}); + histos.add("PPbar/AntiProton/hTPCNClusters_aftersel", "hTPCNClusters", kTH1F, {axisTPCclus}); + histos.add("PPbar/AntiProton/hTPCChi2Clusters_aftersel", "hTPCChi2Clusters", kTH1F, {axisTPCChi2clus}); + histos.add("PPbar/AntiProton/hTPCCrossedRowsOverFindable_aftersel", "hTPCCrossedRowsOverFindable", kTH1F, {axisTPCrowsOverFindable}); + histos.add("PPbar/AntiProton/hITSNClusters_aftersel", "hITSNClusters", kTH1F, {axisITSclus}); + histos.add("PPbar/AntiProton/hITSChi2Clusters_aftersel", "hITSChi2Clusters", kTH1F, {axisITSChi2clus}); + histos.add("PPbar/AntiProton/hTPCNsigma_aftersel", "hTPCNsigma", kTH1F, {axisNsigmaTPC}); + histos.add("PPbar/AntiProton/hTOFNsigma_aftersel", "hTOFNsigma", kTH1F, {axisNsigmaTOF}); + histos.add("PPbar/AntiProton/h2dITSvsTPCpts_aftersel", "h2dITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + if (doMCAssociation) { + histos.add("PPbar/h2dInvMassTrueEtaC1S", "h2dInvMassTrueEtaC1S", kTH2F, {axisPt, axisQuarkoniumMass}); + histos.add("PPbar/h2dInvMassTrueJPsi", "h2dInvMassTrueJPsi", kTH2F, {axisPt, axisQuarkoniumMass}); + histos.add("PPbar/h2dInvMassTrueChiC0", "h2dInvMassTrueChiC0", kTH2F, {axisPt, axisQuarkoniumMass}); + histos.add("PPbar/h2dInvMassTrueChiC1", "h2dInvMassTrueChiC1", kTH2F, {axisPt, axisQuarkoniumMass}); + histos.add("PPbar/h2dInvMassTrueHC", "h2dInvMassTrueHC", kTH2F, {axisPt, axisQuarkoniumMass}); + histos.add("PPbar/h2dInvMassTrueChiC2", "h2dInvMassTrueChiC2", kTH2F, {axisPt, axisQuarkoniumMass}); + histos.add("PPbar/h2dInvMassTrueEtaC2S", "h2dInvMassTrueEtaC2S", kTH2F, {axisPt, axisQuarkoniumMass}); + histos.add("PPbar/h2dInvMassTruePsi2S", "h2dInvMassTruePsi2S", kTH2F, {axisPt, axisQuarkoniumMass}); + } + + // inspect histogram sizes, please + histos.print(); + } + + template + void fillEventHistograms(TCollision collision, int& selGapSide) + { + // in case we want to push the analysis to Pb-Pb UPC + int gapSide = collision.gapSide(); + // -1 --> Hadronic + // 0 --> Single Gap - A side + // 1 --> Single Gap - C side + // 2 --> Double Gap - both A & C sides + selGapSide = sgSelector.trueGap(collision, upcCuts.fv0Cut, upcCuts.ft0aCut, upcCuts.ft0cCut, upcCuts.zdcCut); + histos.fill(HIST("hGapSide"), gapSide); + histos.fill(HIST("hSelGapSide"), selGapSide); + + histos.fill(HIST("hSelGapSideVsPVz"), selGapSide, collision.posZ()); + histos.fill(HIST("hEventPVz"), collision.posZ()); + + histos.fill(HIST("hEventOccupancy"), collision.occupancyInTime()); + histos.fill(HIST("hSelGapSideVsOccupancy"), selGapSide, collision.occupancyInTime()); + + return; + } + + template + bool isTrackSelected(TTrack track) + { + // + // acceptance cut + // + if (std::fabs(RecoDecay::eta(std::array{track.px(), track.py(), track.pz()})) > trackSelections.etaCut) + return false; + + // PV contributor selection + if (trackSelections.requirePVcontributor && !track.isPVContributor()) + return false; + + // dca XY to PV + if (trackSelections.applyDCAptdepsel) { // apply pt dep. selection on DCAxy + float dcaXYPtCut = 0.0105f + 0.0350f / pow(track.pt(), 1.1f); + if (std::fabs(track.dcaXY()) > dcaXYPtCut) + return false; + } else { + if (std::fabs(track.dcaXY()) > trackSelections.dcaxytopv) + return false; + } + // dca Z to PV + if (std::fabs(track.dcaZ()) > trackSelections.dcaztopv) + return false; + + // + // ITS quality flags + // + if (track.itsNCls() < trackSelections.minITSclusters) + return false; + if (track.itsChi2NCl() < trackSelections.minITSchi2clusters) + return false; + if (trackSelections.rejectITSafterburner && track.itsChi2NCl() < 0) + return false; + if (trackSelections.requireITSonly && track.tpcNClsCrossedRows() > 0) + return false; + + // + // TPC quality flags + // + if (track.tpcNClsCrossedRows() < trackSelections.minTPCrows) + return false; + if (track.tpcChi2NCl() < trackSelections.minTPCchi2clusters) + return false; + if (track.tpcNClsFindable() - track.tpcNClsFindableMinusFound() < trackSelections.minTPCclusters) + return false; + if (static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable()) < trackSelections.minTPCrowsoverfindable) + return false; + if (trackSelections.skipTPConly && track.detectorMap() == o2::aod::track::TPC) + return false; + + // + // TPC PID + // + if (std::fabs(track.tpcNSigmaPr()) > trackSelections.tpcPidNsigmaCut) + return false; + + // + // TOF PID in NSigma + // Bachelor track + if (track.hasTOF()) { + if (std::fabs(track.tofNSigmaPr()) > trackSelections.tofPidNsigmaCut) + return false; + } + + return true; + } + + template + bool checkMCAssociation(TTrack track, TTrackMC trackMC) + // MC association (if asked) + { + if (track.sign() * trackMC.pdgCode() != 2212) + return false; + if (!trackMC.isPhysicalPrimary()) + return false; + return true; + } + + template + void fillQAplot(TTrack track, bool afterSel = false) + { // fill QA information about proton/antiproton track + if (afterSel) { + if (track.sign() > 0) { // Proton Candidates after selections + histos.fill(HIST("PPbar/Proton/hDCAxyToPV_aftersel"), track.dcaXY()); + histos.fill(HIST("PPbar/Proton/hDCAzToPV_aftersel"), track.dcaZ()); + histos.fill(HIST("PPbar/Proton/hTPCCrossedRows_aftersel"), track.tpcNClsCrossedRows()); + histos.fill(HIST("PPbar/Proton/hTPCNClusters_aftersel"), track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()); + histos.fill(HIST("PPbar/Proton/hTPCChi2Clusters_aftersel"), track.tpcChi2NCl()); + histos.fill(HIST("PPbar/Proton/hTPCCrossedRowsOverFindable_aftersel"), static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())); + histos.fill(HIST("PPbar/Proton/hITSNClusters_aftersel"), track.itsNCls()); + histos.fill(HIST("PPbar/Proton/hITSChi2Clusters_aftersel"), track.itsChi2NCl()); + histos.fill(HIST("PPbar/Proton/hTPCNsigma_aftersel"), track.tpcNSigmaPr()); + if (track.hasTOF()) + histos.fill(HIST("PPbar/Proton/hTOFNsigma_aftersel"), track.tofNSigmaPr()); + histos.fill(HIST("PPbar/Proton/h2dITSvsTPCpts_aftersel"), track.tpcNClsCrossedRows(), track.itsNCls()); + } else { // Anti Proton after selections + histos.fill(HIST("PPbar/AntiProton/hDCAxyToPV_aftersel"), track.dcaXY()); + histos.fill(HIST("PPbar/AntiProton/hDCAzToPV_aftersel"), track.dcaZ()); + histos.fill(HIST("PPbar/AntiProton/hTPCCrossedRows_aftersel"), track.tpcNClsCrossedRows()); + histos.fill(HIST("PPbar/AntiProton/hTPCNClusters_aftersel"), track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()); + histos.fill(HIST("PPbar/AntiProton/hTPCChi2Clusters_aftersel"), track.tpcChi2NCl()); + histos.fill(HIST("PPbar/AntiProton/hTPCCrossedRowsOverFindable_aftersel"), static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())); + histos.fill(HIST("PPbar/AntiProton/hITSNClusters_aftersel"), track.itsNCls()); + histos.fill(HIST("PPbar/AntiProton/hITSChi2Clusters_aftersel"), track.itsChi2NCl()); + histos.fill(HIST("PPbar/AntiProton/hTPCNsigma_aftersel"), track.tpcNSigmaPr()); + if (track.hasTOF()) + histos.fill(HIST("PPbar/AntiProton/hTOFNsigma_aftersel"), track.tofNSigmaPr()); + histos.fill(HIST("PPbar/AntiProton/h2dITSvsTPCpts_aftersel"), track.tpcNClsCrossedRows(), track.itsNCls()); + } + } else { + if (track.sign() > 0) { // Proton Candidates before selections + histos.fill(HIST("PPbar/Proton/hDCAxyToPV"), track.dcaXY()); + histos.fill(HIST("PPbar/Proton/hDCAzToPV"), track.dcaZ()); + histos.fill(HIST("PPbar/Proton/hTPCCrossedRows"), track.tpcNClsCrossedRows()); + histos.fill(HIST("PPbar/Proton/hTPCNClusters"), track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()); + histos.fill(HIST("PPbar/Proton/hTPCChi2Clusters"), track.tpcChi2NCl()); + histos.fill(HIST("PPbar/Proton/hTPCCrossedRowsOverFindable"), static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())); + histos.fill(HIST("PPbar/Proton/hITSNClusters"), track.itsNCls()); + histos.fill(HIST("PPbar/Proton/hITSChi2Clusters"), track.itsChi2NCl()); + histos.fill(HIST("PPbar/Proton/hTPCNsigma"), track.tpcNSigmaPr()); + if (track.hasTOF()) + histos.fill(HIST("PPbar/Proton/hTOFNsigma"), track.tofNSigmaPr()); + histos.fill(HIST("PPbar/Proton/h2dITSvsTPCpts"), track.tpcNClsCrossedRows(), track.itsNCls()); + } else { + // Anti Proton before selections + histos.fill(HIST("PPbar/AntiProton/hDCAxyToPV"), track.dcaXY()); + histos.fill(HIST("PPbar/AntiProton/hDCAzToPV"), track.dcaZ()); + histos.fill(HIST("PPbar/AntiProton/hTPCCrossedRows"), track.tpcNClsCrossedRows()); + histos.fill(HIST("PPbar/AntiProton/hTPCNClusters"), track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()); + histos.fill(HIST("PPbar/AntiProton/hTPCChi2Clusters"), track.tpcChi2NCl()); + histos.fill(HIST("PPbar/AntiProton/hTPCCrossedRowsOverFindable"), static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())); + histos.fill(HIST("PPbar/AntiProton/hITSNClusters"), track.itsNCls()); + histos.fill(HIST("PPbar/AntiProton/hITSChi2Clusters"), track.itsChi2NCl()); + histos.fill(HIST("PPbar/AntiProton/hTPCNsigma"), track.tpcNSigmaPr()); + if (track.hasTOF()) + histos.fill(HIST("PPbar/AntiProton/hTOFNsigma"), track.tofNSigmaPr()); + histos.fill(HIST("PPbar/AntiProton/h2dITSvsTPCpts"), track.tpcNClsCrossedRows(), track.itsNCls()); + } + } + } + + template + void analyseTrackPairCandidate(TTrack proton, TTrack antiProton, TTrackMCs const& fullTrackMCs, uint8_t gapSide) + // fill information related to the quarkonium mother + { + float pt = RecoDecay::pt(proton.px() + antiProton.px(), proton.py() + antiProton.py()); + float invmass = RecoDecay::m(std::array{std::array{proton.px(), proton.py(), proton.pz()}, std::array{antiProton.px(), antiProton.py(), antiProton.pz()}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassProtonBar}); + float rapidity = RecoDecay::y(std::array{proton.px() + antiProton.px(), proton.py() + antiProton.py(), proton.pz() + antiProton.pz()}, invmass); + + // rapidity cut on the quarkonium mother + if (!doMCAssociation && std::fabs(rapidity) > rapidityCut) + return; + + // __________________________________________ + // main analysis + if (doMCAssociation) { + if constexpr (requires { proton.udMcParticle(); }) { // check if MC information is available + auto protonMC = fullTrackMCs.iteratorAt(proton.udMcParticle().globalIndex()); + auto antiProtonMC = fullTrackMCs.iteratorAt(antiProton.udMcParticle().globalIndex()); + + if (!protonMC.has_mothers()) + return; + if (!antiProtonMC.has_mothers()) + return; + + float ptmc = RecoDecay::pt(protonMC.px() + antiProtonMC.px(), protonMC.py() + antiProtonMC.py()); + + auto protonMothers = protonMC.template mothers_as(); + auto antiProtonMothers = antiProtonMC.template mothers_as(); + for (const auto& protonMother : protonMothers) { + for (const auto& antiProtonMother : antiProtonMothers) { + if (protonMother.globalIndex() != antiProtonMother.globalIndex()) { + continue; + } + + float rapiditymc = RecoDecay::y(std::array{protonMC.px() + antiProtonMC.px(), protonMC.py() + antiProtonMC.py(), protonMC.pz() + antiProtonMC.pz()}, pdgDB->Mass(protonMother.pdgCode())); + + if (std::fabs(rapiditymc) > rapidityCut) + continue; + + if (protonMother.pdgCode() == 441 && protonMother.pdgCode() == antiProtonMother.pdgCode()) { // EtaC(1S) + histos.fill(HIST("PPbar/h2dInvMassTrueEtaC1S"), ptmc, invmass); + } + if (protonMother.pdgCode() == 443 && protonMother.pdgCode() == antiProtonMother.pdgCode()) { // J/psi + histos.fill(HIST("PPbar/h2dInvMassTrueJPsi"), ptmc, invmass); + } + if (protonMother.pdgCode() == 10441 && protonMother.pdgCode() == antiProtonMother.pdgCode()) { // ChiC0 + histos.fill(HIST("PPbar/h2dInvMassTrueChiC0"), ptmc, invmass); + } + if (protonMother.pdgCode() == 20443 && protonMother.pdgCode() == antiProtonMother.pdgCode()) { // ChiC1 + histos.fill(HIST("PPbar/h2dInvMassTrueChiC1"), ptmc, invmass); + } + if (protonMother.pdgCode() == 10443 && protonMother.pdgCode() == antiProtonMother.pdgCode()) { // hC + histos.fill(HIST("PPbar/h2dInvMassTrueHC"), ptmc, invmass); + } + if (protonMother.pdgCode() == 445 && protonMother.pdgCode() == antiProtonMother.pdgCode()) { // ChiC2 + histos.fill(HIST("PPbar/h2dInvMassTrueChiC2"), ptmc, invmass); + } + if (protonMother.pdgCode() == 100441 && protonMother.pdgCode() == antiProtonMother.pdgCode()) { // EtaC(2S) + histos.fill(HIST("PPbar/h2dInvMassTrueEtaC2S"), ptmc, invmass); + } + if (protonMother.pdgCode() == 100443 && protonMother.pdgCode() == antiProtonMother.pdgCode()) { // Psi(2S) + histos.fill(HIST("PPbar/h2dInvMassTruePsi2S"), ptmc, invmass); + } + } + } + } + } + + histos.fill(HIST("PPbar/h2dMassPPbar"), pt, invmass); + if (gapSide == 0) + histos.fill(HIST("PPbar/h2dMassPPbarSGA"), pt, invmass); + else if (gapSide == 1) + histos.fill(HIST("PPbar/h2dMassPPbarSGC"), pt, invmass); + else if (gapSide == 2) + histos.fill(HIST("PPbar/h2dMassPPbarDG"), pt, invmass); + else + histos.fill(HIST("PPbar/h2dMassPPbarHadronic"), pt, invmass); + + fillQAplot(proton, true); + fillQAplot(antiProton, true); + } + + template + void buildProtonAntiProtonPairs(TTracks const& fullTracks, TTrackMCs const& fullMCTracks, std::vector selProtonIndices, std::vector selAntiProtonIndices, uint8_t gapSide) + { + // 1st loop over all protons + for (const auto& proton : fullTracks) { + // select only protons + if (!selProtonIndices[proton.globalIndex() - fullTracks.offset()]) { // local index needed due to collisions grouping + continue; + } + + // 2nd loop over all protons + for (const auto& antiProton : fullTracks) { + // select only anti-protons + if (!selAntiProtonIndices[antiProton.globalIndex() - fullTracks.offset()]) { // local index needed due to collisions grouping + continue; + } + + // check we don't look at the same protons + if (proton.globalIndex() == antiProton.globalIndex()) { + continue; + } + + // form proton-antiproton pairs and fill histograms + analyseTrackPairCandidate(proton, antiProton, fullMCTracks, gapSide); + } // end antiProton loop + } // end proton loop + + return; + } + + // ______________________________________________________ + // Real data processing - no MC subscription + void processRealData(soa::Join::iterator const& collision, soa::Join const& fullTracks) + { + int selGapSide = -1; // only useful in case one wants to use this task in Pb-Pb UPC + fillEventHistograms(collision, selGapSide); + // __________________________________________ + // perform main analysis + // + // Look at tracks and tag those passing the selections + std::vector selProtonIndices(fullTracks.size(), false); + std::vector selAntiProtonIndices(fullTracks.size(), false); + for (const auto& track : fullTracks) { + if (track.sign() > 0) { + selProtonIndices[track.globalIndex() - fullTracks.offset()] = isTrackSelected(track); + } else { + selAntiProtonIndices[track.globalIndex() - fullTracks.offset()] = isTrackSelected(track); + } + fillQAplot(track, false); + } // end track loop + + // count the number of Proton and antiProton passsing the selections + int nProtons = std::count(selProtonIndices.begin(), selProtonIndices.end(), true); + int nAntiProtons = std::count(selAntiProtonIndices.begin(), selAntiProtonIndices.end(), true); + + // fill the histograms with the number of reconstructed protons/antiprotons per collision + histos.fill(HIST("PPbar/h2dNbrOfProtonsVsSelGapSide"), selGapSide, nProtons); + histos.fill(HIST("PPbar/h2dNbrOfAntiProtonsVsSelGapSide"), selGapSide, nAntiProtons); + + // Check the number of Protons and antiProtons + // needs at least 1 of each + if (!buildSameSignPairs && nProtons >= 1 && nAntiProtons >= 1) { + buildProtonAntiProtonPairs(fullTracks, (TObject*)nullptr, selProtonIndices, selAntiProtonIndices, selGapSide); + } + if (buildSameSignPairs && nProtons > 1) { + buildProtonAntiProtonPairs(fullTracks, (TObject*)nullptr, selProtonIndices, selProtonIndices, selGapSide); + } + if (buildSameSignPairs && nAntiProtons > 1) { + buildProtonAntiProtonPairs(fullTracks, (TObject*)nullptr, selAntiProtonIndices, selAntiProtonIndices, selGapSide); + } + } + + // ______________________________________________________ + // Simulated processing (subscribes to MC information too) + void processMonteCarlo(soa::Join::iterator const& collision, soa::Join const& fullTracks, aod::UDMcCollisions const& /*mccollisions*/, aod::UDMcParticles const& fullMCTracks) + { + int selGapSide = -1; // only useful in case one wants to use this task in Pb-Pb UPC + fillEventHistograms(collision, selGapSide); + // __________________________________________ + // perform main analysis + // + // Look at tracks and tag those passing the selections + std::vector selProtonIndices(fullTracks.size(), false); + std::vector selAntiProtonIndices(fullTracks.size(), false); + for (const auto& track : fullTracks) { + if (!track.has_udMcParticle()) + continue; + + auto trackMC = fullMCTracks.iteratorAt(track.udMcParticle().globalIndex()); + + if (track.sign() > 0) { + selProtonIndices[track.globalIndex() - fullTracks.offset()] = isTrackSelected(track) && (!doMCAssociation || checkMCAssociation(track, trackMC)); + } else { + selAntiProtonIndices[track.globalIndex() - fullTracks.offset()] = isTrackSelected(track) && (!doMCAssociation || checkMCAssociation(track, trackMC)); + } + fillQAplot(track, false); + } // end track loop + + // count the number of Proton and antiProton passsing the selections + int nProtons = std::count(selProtonIndices.begin(), selProtonIndices.end(), true); + int nAntiProtons = std::count(selAntiProtonIndices.begin(), selAntiProtonIndices.end(), true); + + // fill the histograms with the number of reconstructed protons/antiprotons per collision + histos.fill(HIST("PPbar/h2dNbrOfProtonsVsSelGapSide"), selGapSide, nProtons); + histos.fill(HIST("PPbar/h2dNbrOfAntiProtonsVsSelGapSide"), selGapSide, nAntiProtons); + + // Check the number of Protons and antiProtons + // needs at least 1 of each + if (!buildSameSignPairs && nProtons >= 1 && nAntiProtons >= 1) { + buildProtonAntiProtonPairs(fullTracks, fullMCTracks, selProtonIndices, selAntiProtonIndices, selGapSide); + } + if (buildSameSignPairs && nProtons > 1) { + buildProtonAntiProtonPairs(fullTracks, fullMCTracks, selProtonIndices, selProtonIndices, selGapSide); + } + if (buildSameSignPairs && nAntiProtons > 1) { + buildProtonAntiProtonPairs(fullTracks, fullMCTracks, selAntiProtonIndices, selAntiProtonIndices, selGapSide); + } + } + + PROCESS_SWITCH(upcQuarkoniaCentralBarrel, processRealData, "process as if real data", true); + PROCESS_SWITCH(upcQuarkoniaCentralBarrel, processMonteCarlo, "process as if MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/upcRhoAnalysis.cxx b/PWGUD/Tasks/upcRhoAnalysis.cxx new file mode 100644 index 00000000000..1395d66c04b --- /dev/null +++ b/PWGUD/Tasks/upcRhoAnalysis.cxx @@ -0,0 +1,794 @@ +// 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 task for analysis of rho in UPCs using UD tables (from SG producer) +/// includes event tagging based on ZN information, track selection, reconstruction, +/// and also some basic stuff for decay phi anisotropy studies +/// \author Jakub Juracka, jakub.juracka@cern.ch +/// \file upcRhoAnalysis.cxx + +#include +#include +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/runDataProcessing.h" + +#include "random" +#include "TLorentzVector.h" + +#include "Common/DataModel/PIDResponse.h" + +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using FullUdSgCollision = soa::Join::iterator; +using FullUdDgCollision = soa::Join::iterator; +using FullUdTracks = soa::Join; + +namespace o2::aod +{ +namespace reco_tree +{ +// event info +DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); +DECLARE_SOA_COLUMN(LocalBC, localBC, int); +DECLARE_SOA_COLUMN(NumContrib, numContrib, int); +DECLARE_SOA_COLUMN(PosX, posX, float); +DECLARE_SOA_COLUMN(PosY, posY, float); +DECLARE_SOA_COLUMN(PosZ, posZ, float); +// FIT info +DECLARE_SOA_COLUMN(TotalFT0AmplitudeA, totalFT0AmplitudeA, float); +DECLARE_SOA_COLUMN(TotalFT0AmplitudeC, totalFT0AmplitudeC, float); +DECLARE_SOA_COLUMN(TotalFV0AmplitudeA, totalFV0AmplitudeA, float); +DECLARE_SOA_COLUMN(TotalFDDAmplitudeA, totalFDDAmplitudeA, float); +DECLARE_SOA_COLUMN(TotalFDDAmplitudeC, totalFDDAmplitudeC, float); +DECLARE_SOA_COLUMN(TimeFT0A, timeFT0A, float); +DECLARE_SOA_COLUMN(TimeFT0C, timeFT0C, float); +DECLARE_SOA_COLUMN(TimeFV0A, timeFV0A, float); +DECLARE_SOA_COLUMN(TimeFDDA, timeFDDA, float); +DECLARE_SOA_COLUMN(TimeFDDC, timeFDDC, float); +// ZDC info +DECLARE_SOA_COLUMN(EnergyCommonZNA, energyCommonZNA, float); +DECLARE_SOA_COLUMN(EnergyCommonZNC, energyCommonZNC, float); +DECLARE_SOA_COLUMN(TimeZNA, timeZNA, float); +DECLARE_SOA_COLUMN(TimeZNC, timeZNC, float); +// pion tracks +DECLARE_SOA_COLUMN(PhiRandom, phiRandom, float); +DECLARE_SOA_COLUMN(PhiCharge, phiCharge, float); +DECLARE_SOA_COLUMN(TrackSign, trackSign, int[2]); +DECLARE_SOA_COLUMN(TrackPt, trackPt, float[2]); +DECLARE_SOA_COLUMN(TrackEta, trackEta, float[2]); +DECLARE_SOA_COLUMN(TrackPhi, trackPhi, float[2]); +DECLARE_SOA_COLUMN(TrackPiPID, trackPiPID, float[2]); +DECLARE_SOA_COLUMN(TrackElPID, trackElPID, float[2]); +DECLARE_SOA_COLUMN(TrackKaPID, trackKaPID, float[2]); +DECLARE_SOA_COLUMN(TrackDcaXY, trackDcaXY, float[2]); +DECLARE_SOA_COLUMN(TrackDcaZ, trackDcaZ, float[2]); +DECLARE_SOA_COLUMN(TrackTpcSignal, trackTpcSignal, float[2]); +} // namespace reco_tree +DECLARE_SOA_TABLE(RecoTree, "AOD", "RECOTREE", + reco_tree::RunNumber, reco_tree::LocalBC, reco_tree::NumContrib, reco_tree::PosX, reco_tree::PosY, reco_tree::PosZ, + reco_tree::TotalFT0AmplitudeA, reco_tree::TotalFT0AmplitudeC, reco_tree::TotalFV0AmplitudeA, reco_tree::TotalFDDAmplitudeA, reco_tree::TotalFDDAmplitudeC, + reco_tree::TimeFT0A, reco_tree::TimeFT0C, reco_tree::TimeFV0A, reco_tree::TimeFDDA, reco_tree::TimeFDDC, + reco_tree::EnergyCommonZNA, reco_tree::EnergyCommonZNC, reco_tree::TimeZNA, reco_tree::TimeZNC, + reco_tree::PhiRandom, reco_tree::PhiCharge, reco_tree::TrackSign, reco_tree::TrackPt, reco_tree::TrackEta, reco_tree::TrackPhi, reco_tree::TrackPiPID, reco_tree::TrackElPID, reco_tree::TrackKaPID, reco_tree::TrackDcaXY, reco_tree::TrackDcaZ, reco_tree::TrackTpcSignal); + +namespace mc_tree +{ +// misc event info +DECLARE_SOA_COLUMN(LocalBc, localBc, int); +// event vertex +DECLARE_SOA_COLUMN(PosX, posX, float); +DECLARE_SOA_COLUMN(PosY, posY, float); +DECLARE_SOA_COLUMN(PosZ, posZ, float); +// pion tracks +DECLARE_SOA_COLUMN(PhiRandom, phiRandom, float); +DECLARE_SOA_COLUMN(PhiCharge, phiCharge, float); +DECLARE_SOA_COLUMN(TrackSign, trackSign, int[2]); +DECLARE_SOA_COLUMN(TrackPt, trackPt, float[2]); +DECLARE_SOA_COLUMN(TrackEta, trackEta, float[2]); +DECLARE_SOA_COLUMN(TrackPhi, trackPhi, float[2]); +} // namespace mc_tree +DECLARE_SOA_TABLE(McTree, "AOD", "MCTREE", + mc_tree::LocalBc, + mc_tree::PosX, mc_tree::PosY, mc_tree::PosZ, + mc_tree::PhiRandom, mc_tree::PhiCharge, mc_tree::TrackSign, mc_tree::TrackPt, mc_tree::TrackEta, mc_tree::TrackPhi); +} // namespace o2::aod + +struct UpcRhoAnalysis { + Produces recoTree; + Produces mcTree; + + Configurable savePions{"savePions", true, "save pion tracks into derived tables"}; + Configurable saveElectrons{"saveElectrons", false, "save electron tracks into derived tables"}; + Configurable saveKaons{"saveKaons", false, "save kaon tracks into derived tables"}; + + float pcEtaCut = 0.9; // physics coordination recommendation + Configurable requireTof{"requireTof", false, "require TOF signal"}; + + Configurable collisionsPosZMaxCut{"collisionsPosZMaxCut", 10.0, "max Z position cut on collisions"}; + Configurable collisionsNumContribsMaxCut{"collisionsNumContribsMaxCut", 4, "max number of contributors cut on collisions"}; + Configurable znCommonEnergyCut{"znCommonEnergyCut", 0.0, "ZN common energy cut"}; + Configurable znTimeCut{"znTimeCut", 2.0, "ZN time cut"}; + + Configurable tracksTpcNSigmaPiCut{"tracksTpcNSigmaPiCut", 3.0, "TPC nSigma pion cut"}; + Configurable tracksTpcNSigmaElCut{"tracksTpcNSigmaElCut", 3.0, "TPC nSigma electron cut"}; + Configurable tracksTpcNSigmaKaCut{"tracksTpcNSigmaKaCut", 3.0, "TPC nSigma kaon cut"}; + Configurable tracksDcaMaxCut{"tracksDcaMaxCut", 1.0, "max DCA cut on tracks"}; + Configurable tracksMinItsNClsCut{"tracksMinItsNClsCut", 6, "min ITS clusters cut"}; + Configurable tracksMaxItsChi2NClCut{"tracksMaxItsChi2NClCut", 3.0, "max ITS chi2/Ncls cut"}; + Configurable tracksMinTpcNClsCut{"tracksMinTpcNClsCut", 120, "min TPC clusters cut"}; + Configurable tracksMinTpcNClsCrossedRowsCut{"tracksMinTpcNClsCrossedRowsCut", 140, "min TPC crossed rows cut"}; + Configurable tracksMinTpcChi2NClCut{"tracksMinTpcChi2NClCut", 1.0, "min TPC chi2/Ncls cut"}; + Configurable tracksMaxTpcChi2NClCut{"tracksMaxTpcChi2NClCut", 1.8, "max TPC chi2/Ncls cut"}; + Configurable tracksMinTpcNClsCrossedOverFindableCut{"tracksMinTpcNClsCrossedOverFindableCut", 1.05, "min TPC crossed rows / findable clusters cut"}; + Configurable tracksMinPtCut{"tracksMinPtCut", 0.2, "min pT cut on tracks"}; + + Configurable systemMassMinCut{"systemMassMinCut", 0.4, "min M cut for reco system"}; + Configurable systemMassMaxCut{"systemMassMaxCut", 1.2, "max M cut for reco system"}; + Configurable systemPtCut{"systemPtCut", 0.1, "max pT cut for reco system"}; + Configurable systemYCut{"systemYCut", 0.9, "rapiditiy cut for reco system"}; + + ConfigurableAxis mAxis{"mAxis", {1000, 0.0, 10.0}, "m (GeV/#it{c}^{2})"}; + ConfigurableAxis mCutAxis{"mCutAxis", {160, 0.4, 1.2}, "m (GeV/#it{c}^{2})"}; + ConfigurableAxis ptAxis{"ptAxis", {1000, 0.0, 10.0}, "p_{T} (GeV/#it{c})"}; + ConfigurableAxis ptCutAxis{"ptCutAxis", {100, 0.0, 0.1}, "p_{T} (GeV/#it{c})"}; + ConfigurableAxis pt2Axis{"pt2Axis", {100, 0.0, 0.01}, "p_{T}^{2} (GeV^{2}/#it{c}^{2})"}; + ConfigurableAxis etaAxis{"etaAxis", {800, -4.0, 4.0}, "#eta"}; + ConfigurableAxis etaCutAxis{"etaCutAxis", {180, -0.9, 0.9}, "#eta"}; + ConfigurableAxis yAxis{"yAxis", {400, -4.0, 4.0}, "y"}; + ConfigurableAxis yCutAxis{"yCutAxis", {180, -0.9, 0.9}, "y"}; + ConfigurableAxis phiAxis{"phiAxis", {180, 0.0, o2::constants::math::TwoPI}, "#phi"}; + ConfigurableAxis phiAsymmAxis{"phiAsymmAxis", {182, -o2::constants::math::PI, o2::constants::math::PI}, "#phi"}; + ConfigurableAxis momentumFromPhiAxis{"momentumFromPhiAxis", {400, -0.1, 0.1}, "p (GeV/#it{c})"}; + ConfigurableAxis znCommonEnergyAxis{"znCommonEnergyAxis", {250, -5.0, 20.0}, "ZN common energy (TeV)"}; + ConfigurableAxis znTimeAxis{"znTimeAxis", {200, -10.0, 10.0}, "ZN time (ns)"}; + + HistogramRegistry rQC{"rQC", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry rTracks{"rTracks", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry rSystem{"rSystem", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry rMC{"rMC", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + // QA // + // collisions + rQC.add("QC/collisions/all/hPosXY", ";x (cm);y (cm);counts", kTH2D, {{2000, -0.1, 0.1}, {2000, -0.1, 0.1}}); + rQC.add("QC/collisions/all/hPosZ", ";z (cm);counts", kTH1D, {{400, -20.0, 20.0}}); + rQC.add("QC/collisions/all/hNumContrib", ";number of contributors;counts", kTH1D, {{36, -0.5, 35.5}}); + rQC.add("QC/collisions/all/hZdcCommonEnergy", ";ZNA common energy (TeV);ZNC common energy (TeV);counts", kTH2D, {znCommonEnergyAxis, znCommonEnergyAxis}); + rQC.add("QC/collisions/all/hZdcTime", ";ZNA time (ns);ZNC time (ns);counts", kTH2D, {znTimeAxis, znTimeAxis}); + rQC.add("QC/collisions/all/hTotalFT0AmplitudeA", ";FT0A amplitude;counts", kTH1D, {{1000, 0.0, 1000.0}}); + rQC.add("QC/collisions/all/hTotalFT0AmplitudeC", ";FT0C amplitude;counts", kTH1D, {{1000, 0.0, 1000.0}}); + rQC.add("QC/collisions/all/hTotalFV0AmplitudeA", ";FV0A amplitude;counts", kTH1D, {{1000, 0.0, 1000.0}}); + rQC.add("QC/collisions/all/hTotalFDDAmplitudeA", ";FDDA amplitude;counts", kTH1D, {{1000, 0.0, 1000.0}}); + rQC.add("QC/collisions/all/hTotalFDDAmplitudeC", ";FDDC amplitude;counts", kTH1D, {{1000, 0.0, 1000.0}}); + rQC.add("QC/collisions/all/hTimeFT0A", ";FT0A time (ns);counts", kTH1D, {{200, -100.0, 100.0}}); + rQC.add("QC/collisions/all/hTimeFT0C", ";FT0C time (ns);counts", kTH1D, {{200, -100.0, 100.0}}); + rQC.add("QC/collisions/all/hTimeFV0A", ";FV0A time (ns);counts", kTH1D, {{200, -100.0, 100.0}}); + rQC.add("QC/collisions/all/hTimeFDDA", ";FDDA time (ns);counts", kTH1D, {{200, -100.0, 100.0}}); + rQC.add("QC/collisions/all/hTimeFDDC", ";FDDC time (ns);counts", kTH1D, {{200, -100.0, 100.0}}); + // events with selected rho candidates + rQC.addClone("QC/collisions/all/", "QC/collisions/selected/"); // clone "all" histograms as "selected" + + // tracks + rQC.add("QC/tracks/all/hTpcNSigmaPi", ";TPC n#sigma(#pi);counts", kTH1D, {{400, -10.0, 30.0}}); + rQC.add("QC/tracks/all/hTpcNSigmaEl", ";TPC n#sigma(e);counts", kTH1D, {{400, -10.0, 30.0}}); + rQC.add("QC/tracks/all/hTpcNSigmaKa", ";TPC n#sigma(K);counts", kTH1D, {{400, -10.0, 30.0}}); + rQC.add("QC/tracks/all/hDcaXYZ", ";DCA_{z} (cm);DCA_{xy} (cm);counts", kTH2D, {{1000, -5.0, 5.0}, {1000, -5.0, 5.0}}); + rQC.add("QC/tracks/all/hItsNCls", ";ITS N_{cls};counts", kTH1D, {{11, -0.5, 10.5}}); + rQC.add("QC/tracks/all/hItsChi2NCl", ";ITS #chi^{2}/N_{cls};counts", kTH1D, {{1000, 0.0, 100.0}}); + rQC.add("QC/tracks/all/hTpcChi2NCl", ";TPC #chi^{2}/N_{cls};counts", kTH1D, {{1000, 0.0, 100.0}}); + rQC.add("QC/tracks/all/hTpcNCls", ";TPC N_{cls} found;counts", kTH1D, {{200, 0.0, 200.0}}); + rQC.add("QC/tracks/all/hTpcNClsCrossedRows", ";TPC crossed rows;counts", kTH1D, {{200, 0.0, 200.0}}); + rQC.add("QC/tracks/all/hTpcNClsCrossedRowsOverNClsFindable", ";TPC crossed rows/findable N_{cls};counts", kTH1D, {{100, 0.0, 10.0}}); + rQC.add("QC/tracks/all/hPt", ";p_{T} (GeV/#it{c});counts", kTH1D, {ptAxis}); + rQC.add("QC/tracks/all/hEta", ";y;counts", kTH1D, {etaAxis}); + rQC.add("QC/tracks/all/hPhi", ";#phi;counts", kTH1D, {phiAxis}); + rQC.add("QC/tracks/all/hTpcSignalVsP", ";p (GeV/#it{c});TPC signal;counts", kTH2D, {ptAxis, {500, 0.0, 500.0}}); + rQC.add("QC/tracks/all/hTpcSignalVsPt", ";p_{T} (GeV/#it{c});TPC signal;counts", kTH2D, {ptAxis, {500, 0.0, 500.0}}); + // tracks passing selections + rQC.addClone("QC/tracks/all/", "QC/tracks/selected/"); // clone "raw" histograms as "cut" + rQC.add("QC/tracks/selected/hRemainingTracks", ";remaining tracks;counts", kTH1D, {{21, -0.5, 20.5}}); + rQC.add("QC/tracks/selected/hTpcNSigmaPi2D", ";TPC n#sigma(#pi_{leading});TPC n#sigma(#pi_{subleading});counts", kTH2D, {{400, -10.0, 30.0}, {400, -10.0, 30.0}}); + rQC.add("QC/tracks/selected/hTpcNSigmaEl2D", ";TPC n#sigma(e_{leading});TPC n#sigma(e_{subleading});counts", kTH2D, {{400, -10.0, 30.0}, {400, -10.0, 30.0}}); + rQC.add("QC/tracks/selected/hTpcNSigmaKa2D", ";TPC n#sigma(K_{leading});TPC n#sigma(K_{subleading});counts", kTH2D, {{400, -10.0, 30.0}, {400, -10.0, 30.0}}); + // selection counter + std::vector selectionCounterLabels = {"all tracks", "PV contributor", "ITS hit", "ITS N_{clusters}", "ITS #chi^{2}/N_{clusters}", "TPC hit", "TPC N_{clusters} found", "TPC #chi^{2}/N_{clusters}", "TPC crossed rows", + "TPC crossed rows/N_{clusters}", + "TOF requirement", + "p_{T}", "DCA", "#eta", "exactly 2 tracks"}; + rQC.add("QC/tracks/hSelectionCounter", ";;tracks passing selections", kTH1D, {{static_cast(selectionCounterLabels.size()), -0.5, static_cast(selectionCounterLabels.size()) - 0.5}}); + for (int i = 0; i < static_cast(selectionCounterLabels.size()); ++i) + rQC.get(HIST("QC/tracks/hSelectionCounter"))->GetXaxis()->SetBinLabel(i + 1, selectionCounterLabels[i].c_str()); + rQC.add("QC/tracks/hTofHitCheck", ";leading track TOF hit;subleading track TOF hit;counts", kTH2D, {{2, -0.5, 1.5}, {2, -0.5, 1.5}}); + + // TRACKS (2D) + rTracks.add("tracks/all/unlike-sign/hPt", ";p_{T}(#pi_{leading}) (GeV/#it{c});p_{T}(#pi_{subleading}) (GeV/#it{c});counts", kTH2D, {ptAxis, ptAxis}); + rTracks.add("tracks/all/unlike-sign/hEta", ";#eta(#pi_{leading});#eta(#pi_{subleading});counts", kTH2D, {etaCutAxis, etaCutAxis}); + rTracks.add("tracks/all/unlike-sign/hPhi", ";#phi(#pi_{leading});#phi(#pi_{subleading});counts", kTH2D, {phiAxis, phiAxis}); + rTracks.addClone("tracks/all/unlike-sign/", "tracks/all/like-sign/positive/"); + rTracks.addClone("tracks/all/unlike-sign/", "tracks/all/like-sign/negative/"); + rTracks.addClone("tracks/all/", "tracks/selected/"); + + // SYSTEM + rSystem.add("system/all/unlike-sign/hM", ";m (GeV/#it{c}^{2});counts", kTH1D, {mAxis}); + rSystem.add("system/all/unlike-sign/hPt", ";p_{T} (GeV/#it{c});counts", kTH1D, {ptAxis}); + rSystem.add("system/all/unlike-sign/hPt2", ";p_{T}^{2} (GeV^{2}/#it{c}^{2});counts", kTH1D, {pt2Axis}); + rSystem.add("system/all/unlike-sign/hPtVsM", ";m (GeV/#it{c}^{2});p_{T} (GeV/#it{c});counts", kTH2D, {mAxis, ptAxis}); + rSystem.add("system/all/unlike-sign/hY", ";y;counts", kTH1D, {yAxis}); + rSystem.add("system/all/unlike-sign/hPhi", ";#phi;counts", kTH1D, {phiAxis}); + rSystem.add("system/all/unlike-sign/hPhiRandom", ";#phi;counts", kTH1D, {phiAsymmAxis}); + rSystem.add("system/all/unlike-sign/hPhiCharge", ";#phi;counts", kTH1D, {phiAsymmAxis}); + // clones for like-sign + rSystem.addClone("system/all/unlike-sign/", "system/all/like-sign/positive/"); + rSystem.addClone("system/all/unlike-sign/", "system/all/like-sign/negative/"); + // selected rhos + rSystem.addClone("system/all/", "system/selected/no-selection/"); + // clones for neutron classes + rSystem.addClone("system/selected/no-selection/", "system/selected/0n0n/"); + rSystem.addClone("system/selected/no-selection/", "system/selected/Xn0n/"); + rSystem.addClone("system/selected/no-selection/", "system/selected/0nXn/"); + rSystem.addClone("system/selected/no-selection/", "system/selected/XnXn/"); + + // MC + // collisions + rMC.add("MC/collisions/hPosXY", ";x (cm);y (cm);counts", kTH2D, {{2000, -0.1, 0.1}, {2000, -0.1, 0.1}}); + rMC.add("MC/collisions/hPosZ", ";z (cm);counts", kTH1D, {{400, -20.0, 20.0}}); + rMC.add("MC/collisions/hNPions", ";number of pions;counts", kTH1D, {{11, -0.5, 10.5}}); + rMC.add("MC/collisions/hNumOfCollisionRecos", ";number of collision reconstructions;counts", kTH1D, {{11, -0.5, 10.5}}); + // tracks + rMC.add("MC/tracks/all/hPdgCode", ";pdg code;counts", kTH1D, {{2001, -1000.5, 1000.5}}); + rMC.add("MC/tracks/all/hProducedByGenerator", ";produced by generator;counts", kTH1D, {{2, -0.5, 1.5}}); + rMC.add("MC/tracks/all/hIsPhysicalPrimary", ";is physical primary;counts", kTH1D, {{2, -0.5, 1.5}}); + rMC.add("MC/tracks/all/hPt", ";p_{T} (GeV/#it{c});counts", kTH1D, {ptAxis}); + rMC.add("MC/tracks/all/hEta", ";#eta;counts", kTH1D, {etaAxis}); + rMC.add("MC/tracks/all/hPhi", ";#phi;counts", kTH1D, {phiAxis}); + rMC.add("MC/tracks/hPt", ";p_{T}(#pi_{leading}) (GeV/#it{c});p_{T}(#pi_{subleading}) (GeV/#it{c});counts", kTH2D, {ptAxis, ptAxis}); + rMC.add("MC/tracks/hEta", ";#eta(#pi_{leading});#eta(#pi_{subleading});counts", kTH2D, {etaAxis, etaAxis}); + rMC.add("MC/tracks/hPhi", ";#phi(#pi_{leading});#phi(#pi_{subleading});counts", kTH2D, {phiAxis, phiAxis}); + // system + rMC.add("MC/system/hM", ";m (GeV/#it{c}^{2});counts", kTH1D, {mAxis}); + rMC.add("MC/system/hPt", ";p_{T} (GeV/#it{c});counts", kTH1D, {ptAxis}); + rMC.add("MC/system/hPt2", ";p_{T}^{2} (GeV^{2}/#it{c}^{2});counts", kTH1D, {pt2Axis}); + rMC.add("MC/system/hPtVsM", ";m (GeV/#it{c}^{2});p_{T} (GeV/#it{c});counts", kTH2D, {mAxis, ptAxis}); + rMC.add("MC/system/hY", ";y;counts", kTH1D, {yAxis}); + rMC.add("MC/system/hPhi", ";#phi;counts", kTH1D, {phiAxis}); + rMC.add("MC/system/hPhiRandom", ";#phi;counts", kTH1D, {phiAsymmAxis}); + rMC.add("MC/system/hPhiCharge", ";#phi;counts", kTH1D, {phiAsymmAxis}); + rMC.addClone("MC/system/", "MC/system/selected/"); + } + + static constexpr std::string_view AppliedSelections[2] = {"all/", "selected/"}; + static constexpr std::string_view ChargeLabel[3] = {"unlike-sign/", "like-sign/positive/", "like-sign/negative/"}; + static constexpr std::string_view NeutronClass[5] = {"no-selection/", "0n0n/", "Xn0n/", "0nXn/", "XnXn/"}; + + template + void fillCollisionQcHistos(const C& collision) // fills collision QC histograms before/after cuts + { + rQC.fill(HIST("QC/collisions/") + HIST(AppliedSelections[cuts]) + HIST("hPosXY"), collision.posX(), collision.posY()); + rQC.fill(HIST("QC/collisions/") + HIST(AppliedSelections[cuts]) + HIST("hPosZ"), collision.posZ()); + rQC.fill(HIST("QC/collisions/") + HIST(AppliedSelections[cuts]) + HIST("hZdcCommonEnergy"), collision.energyCommonZNA(), collision.energyCommonZNC()); + rQC.fill(HIST("QC/collisions/") + HIST(AppliedSelections[cuts]) + HIST("hZdcTime"), collision.timeZNA(), collision.timeZNC()); + rQC.fill(HIST("QC/collisions/") + HIST(AppliedSelections[cuts]) + HIST("hNumContrib"), collision.numContrib()); + rQC.fill(HIST("QC/collisions/") + HIST(AppliedSelections[cuts]) + HIST("hTotalFT0AmplitudeA"), collision.totalFT0AmplitudeA()); + rQC.fill(HIST("QC/collisions/") + HIST(AppliedSelections[cuts]) + HIST("hTotalFT0AmplitudeC"), collision.totalFT0AmplitudeC()); + rQC.fill(HIST("QC/collisions/") + HIST(AppliedSelections[cuts]) + HIST("hTotalFV0AmplitudeA"), collision.totalFV0AmplitudeA()); + rQC.fill(HIST("QC/collisions/") + HIST(AppliedSelections[cuts]) + HIST("hTotalFDDAmplitudeA"), collision.totalFDDAmplitudeA()); + rQC.fill(HIST("QC/collisions/") + HIST(AppliedSelections[cuts]) + HIST("hTotalFDDAmplitudeC"), collision.totalFDDAmplitudeC()); + rQC.fill(HIST("QC/collisions/") + HIST(AppliedSelections[cuts]) + HIST("hTimeFT0A"), collision.timeFT0A()); + rQC.fill(HIST("QC/collisions/") + HIST(AppliedSelections[cuts]) + HIST("hTimeFT0C"), collision.timeFT0C()); + rQC.fill(HIST("QC/collisions/") + HIST(AppliedSelections[cuts]) + HIST("hTimeFV0A"), collision.timeFV0A()); + rQC.fill(HIST("QC/collisions/") + HIST(AppliedSelections[cuts]) + HIST("hTimeFDDA"), collision.timeFDDA()); + rQC.fill(HIST("QC/collisions/") + HIST(AppliedSelections[cuts]) + HIST("hTimeFDDC"), collision.timeFDDC()); + } + + template + void fillTrackQcHistos(const T& track) + { + rQC.fill(HIST("QC/tracks/") + HIST(AppliedSelections[cuts]) + HIST("hPt"), track.pt()); + rQC.fill(HIST("QC/tracks/") + HIST(AppliedSelections[cuts]) + HIST("hEta"), eta(track.px(), track.py(), track.pz())); + rQC.fill(HIST("QC/tracks/") + HIST(AppliedSelections[cuts]) + HIST("hPhi"), phi(track.px(), track.py())); + rQC.fill(HIST("QC/tracks/") + HIST(AppliedSelections[cuts]) + HIST("hTpcNSigmaPi"), track.tpcNSigmaPi()); + rQC.fill(HIST("QC/tracks/") + HIST(AppliedSelections[cuts]) + HIST("hTpcNSigmaEl"), track.tpcNSigmaEl()); + rQC.fill(HIST("QC/tracks/") + HIST(AppliedSelections[cuts]) + HIST("hTpcNSigmaKa"), track.tpcNSigmaKa()); + rQC.fill(HIST("QC/tracks/") + HIST(AppliedSelections[cuts]) + HIST("hDcaXYZ"), track.dcaZ(), track.dcaXY()); + rQC.fill(HIST("QC/tracks/") + HIST(AppliedSelections[cuts]) + HIST("hItsNCls"), track.itsNCls()); + rQC.fill(HIST("QC/tracks/") + HIST(AppliedSelections[cuts]) + HIST("hItsChi2NCl"), track.itsChi2NCl()); + rQC.fill(HIST("QC/tracks/") + HIST(AppliedSelections[cuts]) + HIST("hTpcChi2NCl"), track.tpcChi2NCl()); + rQC.fill(HIST("QC/tracks/") + HIST(AppliedSelections[cuts]) + HIST("hTpcNCls"), (track.tpcNClsFindable() - track.tpcNClsFindableMinusFound())); + rQC.fill(HIST("QC/tracks/") + HIST(AppliedSelections[cuts]) + HIST("hTpcNClsCrossedRows"), track.tpcNClsCrossedRows()); + rQC.fill(HIST("QC/tracks/") + HIST(AppliedSelections[cuts]) + HIST("hTpcNClsCrossedRowsOverNClsFindable"), (static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable()))); + rQC.fill(HIST("QC/tracks/") + HIST(AppliedSelections[cuts]) + HIST("hTpcSignalVsP"), momentum(track.px(), track.py(), track.pz()), track.tpcSignal()); + rQC.fill(HIST("QC/tracks/") + HIST(AppliedSelections[cuts]) + HIST("hTpcSignalVsPt"), track.pt(), track.tpcSignal()); + } + + template + void fillTrack2dHistos(float leadingPt, float subleadingPt, float leadingEta, float subleadingEta, float leadingPhi, float subleadingPhi) + { + rTracks.fill(HIST("tracks/") + HIST(AppliedSelections[cuts]) + HIST(ChargeLabel[charge]) + HIST("hPt"), leadingPt, subleadingPt); + rTracks.fill(HIST("tracks/") + HIST(AppliedSelections[cuts]) + HIST(ChargeLabel[charge]) + HIST("hEta"), leadingEta, subleadingEta); + rTracks.fill(HIST("tracks/") + HIST(AppliedSelections[cuts]) + HIST(ChargeLabel[charge]) + HIST("hPhi"), leadingPhi, subleadingPhi); + } + + template + void fillSystemHistos(float mass, float pt, float rapidity, float phi, float phiRandom, float phiCharge) + { + if (cuts == 0) { + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(ChargeLabel[charge]) + HIST("hM"), mass); + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(ChargeLabel[charge]) + HIST("hPt"), pt); + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(ChargeLabel[charge]) + HIST("hPt2"), pt * pt); + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(ChargeLabel[charge]) + HIST("hPtVsM"), mass, pt); + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(ChargeLabel[charge]) + HIST("hY"), rapidity); + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(ChargeLabel[charge]) + HIST("hPhi"), phi); + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(ChargeLabel[charge]) + HIST("hPhiRandom"), phiRandom); + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(ChargeLabel[charge]) + HIST("hPhiCharge"), phiCharge); + } else { + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hM"), mass); + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hPt"), pt); + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hPt2"), pt * pt); + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hPtVsM"), mass, pt); + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hY"), rapidity); + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hPhi"), phi); + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hPhiRandom"), phiRandom); + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hPhiCharge"), phiCharge); + } + } + + template + bool collisionPassesCuts(const C& collision) // collision cuts + { + if (std::abs(collision.posZ()) > collisionsPosZMaxCut) + return false; + if (collision.numContrib() > collisionsNumContribsMaxCut) + return false; + return true; + } + + template + bool trackPassesCuts(const T& track) // track cuts (PID done separately) + { + if (!track.isPVContributor()) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 1); + + if (!track.hasITS()) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 2); + + if (track.itsNCls() < tracksMinItsNClsCut) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 3); + + if (track.itsChi2NCl() > tracksMaxItsChi2NClCut) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 4); + + if (!track.hasTPC()) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 5); + + if ((track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) < tracksMinTpcNClsCut) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 6); + + if (track.tpcChi2NCl() > tracksMaxTpcChi2NClCut || track.tpcChi2NCl() < tracksMinTpcChi2NClCut) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 7); + + if (track.tpcNClsCrossedRows() < tracksMinTpcNClsCrossedRowsCut) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 8); + + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < tracksMinTpcNClsCrossedOverFindableCut) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 9); + + if (requireTof && !track.hasTOF()) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 10); + + if (track.pt() < tracksMinPtCut) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 11); + + if (std::abs(track.dcaZ()) > tracksDcaMaxCut || std::abs(track.dcaXY()) > (0.0105 + 0.0350 / std::pow(track.pt(), 1.01))) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 12); + + if (std::abs(eta(track.px(), track.py(), track.pz())) > pcEtaCut) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 13); + // if all selections passed + return true; + } + + template + bool tracksPassPiPID(const T& cutTracks) // n-dimensional pion PID cut + { + float radius = 0.0; + for (const auto& track : cutTracks) + radius += std::pow(track.tpcNSigmaPi(), 2); + return radius < std::pow(tracksTpcNSigmaPiCut, 2); + } + + template + bool tracksPassElPID(const T& cutTracks) // n-dimensional electron PID cut + { + float radius = 0.0; + for (const auto& track : cutTracks) + radius += std::pow(track.tpcNSigmaEl(), 2); + return radius < std::pow(tracksTpcNSigmaElCut, 2); + } + + template + bool tracksPassKaPID(const T& cutTracks) // n-dimensional kaon PID cut + { + float radius = 0.0; + for (const auto& track : cutTracks) + radius += std::pow(track.tpcNSigmaKa(), 2); + return radius < std::pow(tracksTpcNSigmaKaCut, 2); + } + + template + int tracksTotalCharge(const T& cutTracks) // total charge of selected tracks + { + int charge = 0; + for (const auto& track : cutTracks) + charge += track.sign(); + return charge; + } + + template + int tracksTotalChargeMC(const T& cutTracks) // total charge of selected MC tracks + { + int charge = 0; + for (const auto& track : cutTracks) + charge += track.pdgCode(); + return charge; + } + + bool systemPassesCuts(const TLorentzVector& system) // system cuts + { + if (system.M() < systemMassMinCut || system.M() > systemMassMaxCut) + return false; + if (system.Pt() > systemPtCut) + return false; + if (std::abs(system.Rapidity()) > systemYCut) + return false; + return true; + } + + TLorentzVector reconstructSystem(const std::vector& cutTracksLVs) // reconstruct system from 4-vectors + { + TLorentzVector system; + for (const auto& trackLV : cutTracksLVs) + system += trackLV; + return system; + } + + float getPhiRandom(const std::vector& cutTracksLVs) // decay phi anisotropy + { // two possible definitions of phi: randomize the tracks + int indices[2] = {0, 1}; + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); // get time-based seed + std::shuffle(std::begin(indices), std::end(indices), std::default_random_engine(seed)); // shuffle indices + // calculate phi + TLorentzVector pOne = cutTracksLVs[indices[0]]; + TLorentzVector pTwo = cutTracksLVs[indices[1]]; + TLorentzVector pPlus = pOne + pTwo; + TLorentzVector pMinus = pOne - pTwo; + return pPlus.DeltaPhi(pMinus); + } + + template + float getPhiCharge(const T& cutTracks, const std::vector& cutTracksLVs) + { // two possible definitions of phi: charge-based assignment + TLorentzVector pOne, pTwo; + pOne = (cutTracks[0].sign() > 0) ? cutTracksLVs[0] : cutTracksLVs[1]; + pTwo = (cutTracks[0].sign() > 0) ? cutTracksLVs[1] : cutTracksLVs[0]; + TLorentzVector pPlus = pOne + pTwo; + TLorentzVector pMinus = pOne - pTwo; + return pPlus.DeltaPhi(pMinus); + } + + template + float getPhiChargeMC(const T& cutTracks, const std::vector& cutTracksLVs) + { // the same as for data but using pdg code instead of charge + TLorentzVector pOne, pTwo; + pOne = (cutTracks[0].pdgCode() > 0) ? cutTracksLVs[0] : cutTracksLVs[1]; + pTwo = (cutTracks[0].pdgCode() > 0) ? cutTracksLVs[1] : cutTracksLVs[0]; + TLorentzVector pPlus = pOne + pTwo; + TLorentzVector pMinus = pOne - pTwo; + return pPlus.DeltaPhi(pMinus); + } + + template + void processReco(C const& collision, T const& tracks) + { + fillCollisionQcHistos<0>(collision); // fill QC histograms before cuts + if (!collisionPassesCuts(collision)) + return; + + bool xnxn = false, onon = false, xnon = false, onxn = false; // note: On == 0n... + if (collision.energyCommonZNA() < znCommonEnergyCut && collision.energyCommonZNC() < znCommonEnergyCut) + onon = true; + if (collision.energyCommonZNA() > znCommonEnergyCut && std::abs(collision.timeZNA()) < znTimeCut && collision.energyCommonZNC() < znCommonEnergyCut) + xnon = true; + if (collision.energyCommonZNA() < znCommonEnergyCut && collision.energyCommonZNC() > znCommonEnergyCut && std::abs(collision.timeZNC()) < znTimeCut) + onxn = true; + if (collision.energyCommonZNA() > znCommonEnergyCut && std::abs(collision.timeZNA()) < znTimeCut && + collision.energyCommonZNC() > znCommonEnergyCut && std::abs(collision.timeZNC()) < znTimeCut) + xnxn = true; + + std::vector cutTracks; // store selected tracks + for (const auto& track : tracks) { + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 0); + fillTrackQcHistos<0>(track); // fill QC histograms before cuts + + if (!trackPassesCuts(track)) // apply track cuts + continue; + + fillTrackQcHistos<1>(track); // fill QC histograms after cuts + cutTracks.push_back(track); + } + rQC.fill(HIST("QC/tracks/selected/hRemainingTracks"), cutTracks.size()); + + if (cutTracks.size() != 2) // further consider only two pion systems + return; + for (int i = 0; i < static_cast(cutTracks.size()); i++) + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 14); + rQC.fill(HIST("QC/tracks/selected/hTpcNSigmaPi2D"), cutTracks[0].tpcNSigmaPi(), cutTracks[1].tpcNSigmaPi()); + rQC.fill(HIST("QC/tracks/selected/hTpcNSigmaEl2D"), cutTracks[0].tpcNSigmaEl(), cutTracks[1].tpcNSigmaEl()); + rQC.fill(HIST("QC/tracks/selected/hTpcNSigmaKa2D"), cutTracks[0].tpcNSigmaKa(), cutTracks[1].tpcNSigmaKa()); + + // create a vector of 4-vectors for selected tracks + std::vector cutTracksLVs; + for (const auto& track : cutTracks) { + TLorentzVector trackLV; + trackLV.SetXYZM(track.px(), track.py(), track.pz(), o2::constants::physics::MassPionCharged); // apriori assume pion mass + cutTracksLVs.push_back(trackLV); + } + + // differentiate leading- and subleading-momentum tracks + auto leadingMomentumTrack = momentum(cutTracks[0].px(), cutTracks[0].py(), cutTracks[0].pz()) > momentum(cutTracks[1].px(), cutTracks[1].py(), cutTracks[1].pz()) ? cutTracks[0] : cutTracks[1]; + auto subleadingMomentumTrack = (leadingMomentumTrack == cutTracks[0]) ? cutTracks[1] : cutTracks[0]; + rQC.fill(HIST("QC/tracks/hTofHitCheck"), leadingMomentumTrack.hasTOF(), subleadingMomentumTrack.hasTOF()); + + float leadingPt = leadingMomentumTrack.pt(); + float subleadingPt = subleadingMomentumTrack.pt(); + float leadingEta = eta(leadingMomentumTrack.px(), leadingMomentumTrack.py(), leadingMomentumTrack.pz()); + float subleadingEta = eta(subleadingMomentumTrack.px(), subleadingMomentumTrack.py(), subleadingMomentumTrack.pz()); + float leadingPhi = phi(leadingMomentumTrack.px(), leadingMomentumTrack.py()); + float subleadingPhi = phi(subleadingMomentumTrack.px(), subleadingMomentumTrack.py()); + float phiRandom = getPhiRandom(cutTracksLVs); + float phiCharge = getPhiCharge(cutTracks, cutTracksLVs); + + // fill recoTree + int localBc = collision.globalBC() % o2::constants::lhc::LHCMaxBunches; + int trackSigns[2] = {leadingMomentumTrack.sign(), subleadingMomentumTrack.sign()}; + float trackPts[2] = {leadingPt, subleadingPt}; + float trackEtas[2] = {leadingEta, subleadingEta}; + float trackPhis[2] = {leadingPhi, subleadingPhi}; + float trackPiPIDs[2] = {leadingMomentumTrack.tpcNSigmaPi(), subleadingMomentumTrack.tpcNSigmaPi()}; + float trackElPIDs[2] = {leadingMomentumTrack.tpcNSigmaEl(), subleadingMomentumTrack.tpcNSigmaEl()}; + float trackKaPIDs[2] = {leadingMomentumTrack.tpcNSigmaKa(), subleadingMomentumTrack.tpcNSigmaKa()}; + float trackDcaXYs[2] = {leadingMomentumTrack.dcaXY(), subleadingMomentumTrack.dcaXY()}; + float trackDcaZs[2] = {leadingMomentumTrack.dcaZ(), subleadingMomentumTrack.dcaZ()}; + float trackTpcSignals[2] = {leadingMomentumTrack.tpcSignal(), subleadingMomentumTrack.tpcSignal()}; + if ((savePions && tracksPassPiPID(cutTracks)) || (saveElectrons && tracksPassElPID(cutTracks)) || (saveKaons && tracksPassKaPID(cutTracks))) + recoTree(collision.runNumber(), localBc, collision.numContrib(), collision.posX(), collision.posY(), collision.posZ(), + collision.totalFT0AmplitudeA(), collision.totalFT0AmplitudeC(), collision.totalFV0AmplitudeA(), collision.totalFDDAmplitudeA(), collision.totalFDDAmplitudeC(), + collision.timeFT0A(), collision.timeFT0C(), collision.timeFV0A(), collision.timeFDDA(), collision.timeFDDC(), + collision.energyCommonZNA(), collision.energyCommonZNC(), collision.timeZNA(), collision.timeZNC(), + phiRandom, phiCharge, trackSigns, trackPts, trackEtas, trackPhis, trackPiPIDs, trackElPIDs, trackKaPIDs, trackDcaXYs, trackDcaZs, trackTpcSignals); + + if (!tracksPassPiPID(cutTracks)) // apply PID cut + return; + TLorentzVector system = reconstructSystem(cutTracksLVs); + int totalCharge = tracksTotalCharge(cutTracks); + float mass = system.M(); + float pT = system.Pt(); + float rapidity = system.Rapidity(); + float systemPhi = system.Phi() + o2::constants::math::PI; + + // fill raw histograms according to total charge + switch (totalCharge) { + case 0: + fillTrack2dHistos<0, 0>(leadingPt, subleadingPt, leadingEta, subleadingEta, leadingPhi, subleadingPhi); + fillSystemHistos<0, 0, 0>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + break; + + case 2: + fillTrack2dHistos<0, 1>(leadingPt, subleadingPt, leadingEta, subleadingEta, leadingPhi, subleadingPhi); + fillSystemHistos<0, 0, 1>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + break; + + case -2: + fillTrack2dHistos<0, 2>(leadingPt, subleadingPt, leadingEta, subleadingEta, leadingPhi, subleadingPhi); + fillSystemHistos<0, 0, 2>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + break; + + default: + break; + } + + // apply cuts to system + if (!systemPassesCuts(system)) + return; + fillCollisionQcHistos<1>(collision); // fill QC histograms for collisions with selected system + + // fill histograms for system passing cuts + switch (totalCharge) { + case 0: + fillTrack2dHistos<1, 0>(leadingPt, subleadingPt, leadingEta, subleadingEta, leadingPhi, subleadingPhi); + fillSystemHistos<1, 0, 0>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + if (onon) + fillSystemHistos<1, 1, 0>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + if (xnon) + fillSystemHistos<1, 2, 0>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + if (onxn) + fillSystemHistos<1, 3, 0>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + if (xnxn) + fillSystemHistos<1, 4, 0>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + break; + + case 2: + fillTrack2dHistos<1, 1>(leadingPt, subleadingPt, leadingEta, subleadingEta, leadingPhi, subleadingPhi); + fillSystemHistos<1, 0, 1>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + if (onon) + fillSystemHistos<1, 1, 1>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + if (xnon) + fillSystemHistos<1, 2, 1>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + if (onxn) + fillSystemHistos<1, 3, 1>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + if (xnxn) + fillSystemHistos<1, 4, 1>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + break; + + case -2: + fillTrack2dHistos<1, 2>(leadingPt, subleadingPt, leadingEta, subleadingEta, leadingPhi, subleadingPhi); + fillSystemHistos<1, 0, 2>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + if (onon) + fillSystemHistos<1, 1, 2>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + if (xnon) + fillSystemHistos<1, 2, 2>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + if (onxn) + fillSystemHistos<1, 3, 2>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + if (xnxn) + fillSystemHistos<1, 4, 2>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + break; + + default: + break; + } + } + + template + void processMC(C const& mcCollision, T const& mcParticles) + { + rMC.fill(HIST("MC/collisions/hPosXY"), mcCollision.posX(), mcCollision.posY()); + rMC.fill(HIST("MC/collisions/hPosZ"), mcCollision.posZ()); + + std::vector cutMcParticles; + std::vector mcParticlesLVs; + + for (auto const& mcParticle : mcParticles) { + rMC.fill(HIST("MC/tracks/all/hPdgCode"), mcParticle.pdgCode()); + rMC.fill(HIST("MC/tracks/all/hProducedByGenerator"), mcParticle.producedByGenerator()); + rMC.fill(HIST("MC/tracks/all/hIsPhysicalPrimary"), mcParticle.isPhysicalPrimary()); + rMC.fill(HIST("MC/tracks/all/hPt"), pt(mcParticle.px(), mcParticle.py())); + rMC.fill(HIST("MC/tracks/all/hEta"), eta(mcParticle.px(), mcParticle.py(), mcParticle.pz())); + rMC.fill(HIST("MC/tracks/all/hPhi"), phi(mcParticle.px(), mcParticle.py())); + if (!mcParticle.isPhysicalPrimary() || std::abs(mcParticle.pdgCode()) != 211) + continue; + cutMcParticles.push_back(mcParticle); + TLorentzVector pionLV; + pionLV.SetPxPyPzE(mcParticle.px(), mcParticle.py(), mcParticle.pz(), mcParticle.e()); + mcParticlesLVs.push_back(pionLV); + } + rMC.fill(HIST("MC/collisions/hNPions"), cutMcParticles.size()); + + if (cutMcParticles.size() != 2) + return; + if (mcParticlesLVs.size() != cutMcParticles.size()) + return; + if (tracksTotalChargeMC(cutMcParticles) != 0) // shouldn't happen in theory + return; + + TLorentzVector system = reconstructSystem(mcParticlesLVs); + float mass = system.M(); + float pT = system.Pt(); + float rapidity = system.Rapidity(); + float systemPhi = system.Phi() + o2::constants::math::PI; + float phiRandom = getPhiRandom(mcParticlesLVs); + float phiCharge = getPhiChargeMC(cutMcParticles, mcParticlesLVs); + + auto leadingMomentumPion = momentum(cutMcParticles[0].px(), cutMcParticles[0].py(), cutMcParticles[0].pz()) > momentum(cutMcParticles[1].px(), cutMcParticles[1].py(), cutMcParticles[1].pz()) ? cutMcParticles[0] : cutMcParticles[1]; + auto subleadingMomentumPion = (leadingMomentumPion == cutMcParticles[0]) ? cutMcParticles[1] : cutMcParticles[0]; + rMC.fill(HIST("MC/tracks/hPt"), pt(leadingMomentumPion.px(), leadingMomentumPion.py()), pt(subleadingMomentumPion.px(), subleadingMomentumPion.py())); + rMC.fill(HIST("MC/tracks/hEta"), eta(leadingMomentumPion.px(), leadingMomentumPion.py(), leadingMomentumPion.pz()), eta(subleadingMomentumPion.px(), subleadingMomentumPion.py(), subleadingMomentumPion.pz())); + rMC.fill(HIST("MC/tracks/hPhi"), phi(leadingMomentumPion.px(), leadingMomentumPion.py()), phi(subleadingMomentumPion.px(), subleadingMomentumPion.py())); + + rMC.fill(HIST("MC/system/hM"), mass); + rMC.fill(HIST("MC/system/hPt"), pT); + rMC.fill(HIST("MC/system/hPtVsM"), mass, pT); + rMC.fill(HIST("MC/system/hPt2"), pT * pT); + rMC.fill(HIST("MC/system/hY"), rapidity); + rMC.fill(HIST("MC/system/hPhi"), systemPhi); + rMC.fill(HIST("MC/system/hPhiRandom"), phiRandom); + rMC.fill(HIST("MC/system/hPhiCharge"), phiCharge); + + if (systemPassesCuts(system)) { + rMC.fill(HIST("MC/system/selected/hM"), mass); + rMC.fill(HIST("MC/system/selected/hPt"), pT); + rMC.fill(HIST("MC/system/selected/hPtVsM"), mass, pT); + rMC.fill(HIST("MC/system/selected/hPt2"), pT * pT); + rMC.fill(HIST("MC/system/selected/hY"), rapidity); + rMC.fill(HIST("MC/system/selected/hPhi"), systemPhi); + rMC.fill(HIST("MC/system/selected/hPhiRandom"), phiRandom); + rMC.fill(HIST("MC/system/selected/hPhiCharge"), phiCharge); + } + + // fill mcTree + int localBc = mcCollision.globalBC() % o2::constants::lhc::LHCMaxBunches; + int trackSigns[2] = {leadingMomentumPion.pdgCode() / std::abs(leadingMomentumPion.pdgCode()), subleadingMomentumPion.pdgCode() / std::abs(subleadingMomentumPion.pdgCode())}; + float trackPts[2] = {pt(leadingMomentumPion.px(), leadingMomentumPion.py()), pt(subleadingMomentumPion.px(), subleadingMomentumPion.py())}; + float trackEtas[2] = {eta(leadingMomentumPion.px(), leadingMomentumPion.py(), leadingMomentumPion.pz()), eta(subleadingMomentumPion.px(), subleadingMomentumPion.py(), subleadingMomentumPion.pz())}; + float trackPhis[2] = {phi(leadingMomentumPion.px(), leadingMomentumPion.py()), phi(subleadingMomentumPion.px(), subleadingMomentumPion.py())}; + mcTree(localBc, + mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), + phiRandom, phiCharge, trackSigns, trackPts, trackEtas, trackPhis); + } + + template + void checkNumberOfCollisionReconstructions(C const& collisions) + { + rMC.fill(HIST("MC/collisions/hNumOfCollisionRecos"), collisions.size()); + } + + void processSGdata(FullUdSgCollision const& collision, FullUdTracks const& tracks) + { + if (collision.gapSide() != 2) + return; + processReco(collision, tracks); + } + PROCESS_SWITCH(UpcRhoAnalysis, processSGdata, "analyse SG data", true); + + void processDGdata(FullUdDgCollision const& collision, FullUdTracks const& tracks) + { + processReco(collision, tracks); + } + PROCESS_SWITCH(UpcRhoAnalysis, processDGdata, "analyse DG data", false); + + void processMCdata(aod::UDMcCollision const& mcCollision, aod::UDMcParticles const& mcParticles) + { + processMC(mcCollision, mcParticles); + } + PROCESS_SWITCH(UpcRhoAnalysis, processMCdata, "analyse MC data", false); + + void processCollisionRecoCheck(aod::McCollision const& /* mcCollision */, soa::SmallGroups> const& collisions) + { + checkNumberOfCollisionReconstructions(collisions); + } + PROCESS_SWITCH(UpcRhoAnalysis, processCollisionRecoCheck, "check number of collision reconstructions", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + o2::framework::adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/upcRhoPrimeAnalysis.cxx b/PWGUD/Tasks/upcRhoPrimeAnalysis.cxx new file mode 100644 index 00000000000..64559cc10dd --- /dev/null +++ b/PWGUD/Tasks/upcRhoPrimeAnalysis.cxx @@ -0,0 +1,333 @@ +// 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 Task for analysis of rho' in UPCs using UD tables (from SG producer). +/// \author Cesar Ramirez, cesar.ramirez@cern.ch + +#include // Para std::string +#include // Para std::vector + +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" // similiar to TLorentzVector (which is now legacy apparently) +#include "random" + +#include "Common/DataModel/PIDResponse.h" + +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using FullUDSgCollision = soa::Join::iterator; +using FullUDTracks = soa::Join; + +namespace o2::aod +{ +namespace fourpi +{ + +// for event +DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); + +// for rho prime +DECLARE_SOA_COLUMN(M, m, double); +DECLARE_SOA_COLUMN(Pt, pt, double); +DECLARE_SOA_COLUMN(Eta, eta, double); +DECLARE_SOA_COLUMN(Phi, phi, double); + +// for vertex +DECLARE_SOA_COLUMN(PosX, posX, double); +DECLARE_SOA_COLUMN(PosY, posY, double); +DECLARE_SOA_COLUMN(PosZ, posZ, double); + +// for other +DECLARE_SOA_COLUMN(TotalCharge, totalCharge, int); + +// info detec +DECLARE_SOA_COLUMN(TotalFT0AmplitudeA, totalFT0AmplitudeA, float); +DECLARE_SOA_COLUMN(TotalFT0AmplitudeC, totalFT0AmplitudeC, float); +DECLARE_SOA_COLUMN(TotalFV0AmplitudeA, totalFV0AmplitudeA, float); +DECLARE_SOA_COLUMN(TotalFDDAmplitudeA, totalFDDAmplitudeA, float); +DECLARE_SOA_COLUMN(TotalFDDAmplitudeC, totalFDDAmplitudeC, float); +DECLARE_SOA_COLUMN(TimeFT0A, timeFT0A, float); +DECLARE_SOA_COLUMN(TimeFT0C, timeFT0C, float); +DECLARE_SOA_COLUMN(TimeFV0A, timeFV0A, float); +DECLARE_SOA_COLUMN(TimeFDDA, timeFDDA, float); +DECLARE_SOA_COLUMN(TimeFDDC, timeFDDC, float); + +// for pion tracks +DECLARE_SOA_COLUMN(NumContrib, numContrib, int32_t); +DECLARE_SOA_COLUMN(Sign, sign, std::vector); +DECLARE_SOA_COLUMN(TrackPt, trackPt, std::vector); +DECLARE_SOA_COLUMN(TrackEta, trackEta, std::vector); +DECLARE_SOA_COLUMN(TrackPhi, trackPhi, std::vector); +DECLARE_SOA_COLUMN(TPCNSigmaEl, tpcNSigmaEl, std::vector); +DECLARE_SOA_COLUMN(TPCNSigmaPi, tpcNSigmaPi, std::vector); +DECLARE_SOA_COLUMN(TPCNSigmaKa, tpcNSigmaKa, std::vector); +DECLARE_SOA_COLUMN(TPCNSigmaPr, tpcNSigmaPr, std::vector); +DECLARE_SOA_COLUMN(TrackID, trackID, std::vector); + +// for others +DECLARE_SOA_COLUMN(IsReconstructedWithUPC, isReconstructedWithUPC, bool); +DECLARE_SOA_COLUMN(TimeZNA, timeZNA, float); +DECLARE_SOA_COLUMN(TimeZNC, timeZNC, float); +DECLARE_SOA_COLUMN(EnergyCommonZNA, energyCommonZNA, float); +DECLARE_SOA_COLUMN(EnergyCommonZNC, energyCommonZNC, float); + +} // namespace fourpi + +DECLARE_SOA_TABLE(SYSTEMTREE, "AOD", "SystemTree", fourpi::RunNumber, fourpi::M, fourpi::Pt, fourpi::Eta, fourpi::Phi, + fourpi::PosX, fourpi::PosY, fourpi::PosZ, fourpi::TotalCharge, fourpi::TotalFT0AmplitudeA, fourpi::TotalFT0AmplitudeC, fourpi::TotalFV0AmplitudeA, + fourpi::TotalFDDAmplitudeA, fourpi::TotalFDDAmplitudeC, fourpi::TimeFT0A, fourpi::TimeFT0C, fourpi::TimeFV0A, fourpi::TimeFDDA, fourpi::TimeFDDC, + fourpi::NumContrib, fourpi::Sign, fourpi::TrackPt, fourpi::TrackEta, fourpi::TrackPhi, + fourpi::TPCNSigmaEl, fourpi::TPCNSigmaPi, fourpi::TPCNSigmaKa, fourpi::TPCNSigmaPr, fourpi::TrackID, fourpi::IsReconstructedWithUPC, + fourpi::TimeZNA, fourpi::TimeZNC, fourpi::EnergyCommonZNA, fourpi::EnergyCommonZNC); +} // namespace o2::aod + +struct upcRhoPrimeAnalysis { + Produces systemTree; + + double PcEtaCut = 0.9; // physics coordination recommendation + + Configurable specifyGapSide{"specifyGapSide", true, "specify gap side for SG/DG produced data"}; + Configurable gapSide{"gapSide", 2, "gap side for SG produced data"}; + Configurable requireTof{"requireTof", false, "require TOF signal"}; + + Configurable collisionsPosZMaxCut{"collisionsPosZMaxCut", 10.0, "max Z position cut on collisions"}; + Configurable ZNcommonEnergyCut{"ZNcommonEnergyCut", 0.0, "ZN common energy cut"}; + Configurable ZNtimeCut{"ZNtimeCut", 2.0, "ZN time cut"}; + + Configurable tracksTpcNSigmaPiCut{"tracksTpcNSigmaPiCut", 3.0, "TPC nSigma pion cut"}; + Configurable tracksDcaMaxCut{"tracksDcaMaxCut", 1.0, "max DCA cut on tracks"}; + + Configurable systemMassMinCut{"systemMassMinCut", 0.5, "min M cut for reco system"}; + Configurable systemMassMaxCut{"systemMassMaxCut", 1.2, "max M cut for reco system"}; + Configurable systemPtCut{"systemPtMaxCut", 0.1, "max pT cut for reco system"}; + Configurable systemYCut{"systemYCut", 0.9, "rapiditiy cut for reco system"}; + + ConfigurableAxis mAxis{"mAxis", {1000, 0.0, 10.0}, "m (GeV/#it{c}^{2})"}; + ConfigurableAxis mCutAxis{"mCutAxis", {70, 0.5, 1.2}, "m (GeV/#it{c}^{2})"}; + ConfigurableAxis ptAxis{"ptAxis", {1000, 0.0, 10.0}, "p_{T} (GeV/#it{c})"}; + ConfigurableAxis ptCutAxis{"ptCutAxis", {300, 0.0, 0.3}, "p_{T} (GeV/#it{c})"}; + ConfigurableAxis pt2Axis{"pt2Axis", {300, 0.0, 0.09}, "p_{T}^{2} (GeV^{2}/#it{c}^{2})"}; + ConfigurableAxis etaAxis{"etaAxis", {180, -0.9, 0.9}, "#eta"}; + ConfigurableAxis yAxis{"yAxis", {180, -0.9, 0.9}, "y"}; + ConfigurableAxis phiAxis{"phiAxis", {180, 0.0, o2::constants::math::TwoPI}, "#phi"}; + ConfigurableAxis phiAsymmAxis{"phiAsymmAxis", {182, -o2::constants::math::PI, o2::constants::math::PI}, "#phi"}; + ConfigurableAxis momentumFromPhiAxis{"momentumFromPhiAxis", {400, -0.1, 0.1}, "p (GeV/#it{c})"}; + ConfigurableAxis ptQuantileAxis{"ptQuantileAxis", {0, 0.0181689, 0.0263408, 0.0330488, 0.0390369, 0.045058, 0.0512604, 0.0582598, 0.066986, 0.0788085, 0.1}, "p_{T} (GeV/#it{c})"}; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + // selection counter + std::vector selectionCounterLabels = {"all tracks", "PV contributor", "ITS + TPC hit", "TOF requirement", "DCA cut", "#eta cut", "2D TPC n#sigma_{#pi} cut"}; + + // 4PI SYSTEM + // registry.add("4pi/hM", ";m (GeV/#it{c}^{2});counts", kTH1D, {mAxis}); + // registry.add("4pi/hPt", ";p_{T} (GeV/#it{c});counts", kTH1D, {ptAxis}); + // registry.add("4pi/hEta", ";Eta (1);counts", kTH1D, {etaAxis}); + // registry.add("4pi/hPhi", ";Phi ();counts", kTH1D, {phiAxis}); + } + + template + bool collisionPassesCuts(const C& collision) // collision cuts + { + if (std::abs(collision.posZ()) > collisionsPosZMaxCut) + return false; + if (specifyGapSide && collision.gapSide() != gapSide) + return false; + return true; + } + + template + bool trackPassesCuts(const T& track) // track cuts (PID done separately) + { + if (!track.isPVContributor()) + return false; + if (!track.hasITS() || !track.hasTPC()) + return false; + if (requireTof && !track.hasTOF()) + return false; + if (std::abs(track.dcaZ()) > tracksDcaMaxCut || std::abs(track.dcaXY()) > (0.0182 + 0.0350 / std::pow(track.pt(), 1.01))) // Run 2 dynamic DCA cut + return false; + if (std::abs(eta(track.px(), track.py(), track.pz())) > PcEtaCut) + return false; + return true; + } + + template + bool tracksPassPiPID(const T& cutTracks) // n-dimensional PID cut + { + double radius = 0.0; + for (const auto& track : cutTracks) + radius += std::pow(track.tpcNSigmaPi(), 2); + return radius < std::pow(tracksTpcNSigmaPiCut, 2); + } + + template + double tracksTotalCharge(const T& cutTracks) // total charge of selected tracks + { + double charge = 0.0; + for (const auto& track : cutTracks) + charge += track.sign(); + return charge; + } + + bool systemPassCuts(const ROOT::Math::PxPyPzMVector& system) // system cuts + { + if (system.M() < systemMassMinCut || system.M() > systemMassMaxCut) + return false; + if (system.Pt() > systemPtCut) + return false; + if (std::abs(system.Rapidity()) > systemYCut) + return false; + return true; + } + + ROOT::Math::PxPyPzMVector reconstructSystem(const std::vector& cutTracks4Vecs) // reconstruct system from 4-vectors + { + ROOT::Math::PxPyPzMVector system; + for (const auto& track4Vec : cutTracks4Vecs) + system += track4Vec; + return system; + } + + double deltaPhi(const ROOT::Math::PxPyPzMVector& p1, const ROOT::Math::PxPyPzMVector& p2) + { + double dPhi = p1.Phi() - p2.Phi(); + if (dPhi > o2::constants::math::PI) + dPhi -= o2::constants::math::TwoPI; + else if (dPhi < -o2::constants::math::PI) + dPhi += o2::constants::math::TwoPI; + return dPhi; // calculate delta phi in (-pi, pi) + } + + double getPhiRandom(const std::vector& cutTracks4Vecs) // decay phi anisotropy + { // two possible definitions of phi: randomize the tracks + std::vector indices = {0, 1}; + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); // get time-based seed + std::shuffle(indices.begin(), indices.end(), std::default_random_engine(seed)); // shuffle indices + // calculate phi + ROOT::Math::PxPyPzMVector pOne = cutTracks4Vecs[indices[0]]; + ROOT::Math::PxPyPzMVector pTwo = cutTracks4Vecs[indices[1]]; + ROOT::Math::PxPyPzMVector pPlus = pOne + pTwo; + ROOT::Math::PxPyPzMVector pMinus = pOne - pTwo; + return deltaPhi(pPlus, pMinus); + } + + template + double getPhiCharge(const T& cutTracks, const std::vector& cutTracks4Vecs) + { // two possible definitions of phi: charge-based assignment + ROOT::Math::PxPyPzMVector pOne, pTwo; + if (cutTracks[0].sign() > 0) { + pOne = cutTracks4Vecs[0]; + pTwo = cutTracks4Vecs[1]; + } else { + pOne = cutTracks4Vecs[1]; + pTwo = cutTracks4Vecs[0]; + } + ROOT::Math::PxPyPzMVector pPlus = pOne + pTwo; + ROOT::Math::PxPyPzMVector pMinus = pOne - pTwo; + return deltaPhi(pPlus, pMinus); + } + + void processReco(FullUDSgCollision const& collision, FullUDTracks const& tracks) + { + + if (!collisionPassesCuts(collision)) + return; + + // vectors for storing selected tracks and their 4-vectors + std::vector cutTracks; + std::vector cutTracks4Vecs; + + // int trackCounter = 0; + for (const auto& track : tracks) { + + if (!trackPassesCuts(track)) + continue; + // trackCounter++; + cutTracks.push_back(track); + cutTracks4Vecs.push_back(ROOT::Math::PxPyPzMVector(track.px(), track.py(), track.pz(), o2::constants::physics::MassPionCharged)); // apriori assume pion mass + } + + if (!tracksPassPiPID(cutTracks)) + return; + // reonstruct system and calculate total charge, save commonly used values into variables + ROOT::Math::PxPyPzMVector system = reconstructSystem(cutTracks4Vecs); + int totalCharge = tracksTotalCharge(cutTracks); + int nTracks = cutTracks.size(); + double mass = system.M(); + double pT = system.Pt(); + // double pTsquare = pT * pT; + double rapidity = system.Rapidity(); + double systemPhi = system.Phi() + o2::constants::math::PI; + + if (nTracks == 4 && tracksTotalCharge(cutTracks) == 0) { // 4pi system + + std::vector vTrackPt, vTrackEta, vTrackPhi; + std::vector vSign, vTrackID; + std::vector vTpcNSigmaEl, vTpcNSigmaPi, vTpcNSigmaKa, vTpcNSigmaPr; + + for (size_t i = 0; i < cutTracks.size(); i++) { + + double tPt = cutTracks[i].pt(); + double tEta = eta(cutTracks[i].px(), cutTracks[i].py(), cutTracks[i].pz()); + double tPhi = phi(cutTracks[i].px(), cutTracks[i].py()); + + vTrackPt.push_back(tPt); + vTrackEta.push_back(tEta); + vTrackPhi.push_back(tPhi); + vSign.push_back(cutTracks[i].sign()); + vTpcNSigmaEl.push_back(cutTracks[i].tpcNSigmaEl()); + vTpcNSigmaPi.push_back(cutTracks[i].tpcNSigmaPi()); + vTpcNSigmaKa.push_back(cutTracks[i].tpcNSigmaKa()); + vTpcNSigmaPr.push_back(cutTracks[i].tpcNSigmaPr()); + + vTrackID.push_back(i); + } + + bool isReconstructedWithUPC = false; + + if (collision.flags() == 1) { + isReconstructedWithUPC = true; + } else { + isReconstructedWithUPC = false; + } + + systemTree(collision.runNumber(), mass, pT, rapidity, systemPhi, collision.posX(), collision.posY(), collision.posZ(), totalCharge, + collision.totalFT0AmplitudeA(), collision.totalFT0AmplitudeC(), collision.timeFV0A(), collision.totalFDDAmplitudeA(), collision.totalFDDAmplitudeC(), + collision.timeFT0A(), collision.timeFT0C(), collision.timeFV0A(), collision.timeFDDA(), collision.timeFDDC(), + collision.numContrib(), vSign, vTrackPt, vTrackEta, vTrackPhi, vTpcNSigmaEl, vTpcNSigmaPi, vTpcNSigmaKa, vTpcNSigmaPr, vTrackID, isReconstructedWithUPC, + collision.timeZNA(), collision.timeZNC(), collision.energyCommonZNA(), collision.energyCommonZNC()); + + // registry.fill(HIST("4pi/hM"), mass); + // registry.fill(HIST("4pi/hPt"), pT); + // registry.fill(HIST("4pi/hEta"), rapiditiy); + // registry.fill(HIST("4pi/hPhi"), system); + } + // std::cout<<"Hello World"<(cfgc)}; +} diff --git a/PWGUD/Tasks/upcTauCentralBarrelRL.cxx b/PWGUD/Tasks/upcTauCentralBarrelRL.cxx deleted file mode 100644 index e3fe3b1a6b8..00000000000 --- a/PWGUD/Tasks/upcTauCentralBarrelRL.cxx +++ /dev/null @@ -1,1900 +0,0 @@ -// 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 -/// \author Roman Lavicka, roman.lavicka@cern.ch -/// \since 12.07.2022 - -// #include -// #include - -// O2 headers -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Framework/runDataProcessing.h" - -// O2Physics headers -#include "Common/CCDB/EventSelectionParams.h" -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "Common/Core/trackUtilities.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" -#include "PWGUD/DataModel/UDTables.h" - -// ROOT headers -#include "TLorentzVector.h" -#include "TEfficiency.h" -#include "TF1.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct UpcTauCentralBarrelRL { - - // Global varialbes - bool isFirstReconstructedCollisions; - int countCollisions; - Service pdg; - - HistogramRegistry histos{ - "histos", - {{"Events/hCountCollisions", ";Number of analysed collision (-)", {HistType::kTH1D, {{10, 0.5, 10.5}}}}, - {"Events/hNreconstructedTracks", ";Number of tracks in a collision (-);Number of events (-)", {HistType::kTH1D, {{30, -0.5, 29.5}}}}, - {"Events/hNreconstructedPVGTelectrons", ";Number of good track electrons from primary vertex in a collision (-);Number of events (-)", {HistType::kTH1D, {{30, -0.5, 29.5}}}}, - {"Events/hNreconstructedPVGTmuons", ";Number of good track muons from primary vertex in a collision (-);Number of events (-)", {HistType::kTH1D, {{30, -0.5, 29.5}}}}, - {"Events/hNreconstructedPVGTpions", ";Number of good track pions from primary vertex in a collision (-);Number of events (-)", {HistType::kTH1D, {{30, -0.5, 29.5}}}}, - {"Events/hNreconstructedPVGTothers", ";Number of good track NOT electron/muon/pion particles from primary vertex in a collision (-);Number of events (-)", {HistType::kTH1D, {{30, -0.5, 29.5}}}}, - {"Events/hNreconstructedPVGT", ";Number of good track particles from primary vertex in a collision (-);Number of events (-)", {HistType::kTH1D, {{30, -0.5, 29.5}}}}, - {"Events/hNreconstructedNotPVGT", ";Number of good track particles from NOT primary vertex in a collision (-);Number of events (-)", {HistType::kTH1D, {{30, -0.5, 29.5}}}}, - {"Events/hChannelsRatio", ";Channels (-);Branching Ratio (-)", {HistType::kTH1D, {{10, -0.5, 9.5}}}}}}; - HistogramRegistry histosPID{ - "histosPID", - {{"Tracks/raw/PID/hTPCsignalVsZ", "All tracks;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, -20., 20.}, {200, 0., 200}}}}, - {"Tracks/raw/PID/hTPCsignalVsP", "All tracks;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/raw/PID/hTPCsignalVsPt", "All tracks;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/raw/PID/hTPCsignalVsEta", "All tracks;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{500, -2., 2.}, {200, 0., 200}}}}, - {"Tracks/raw/PID/hTPCsignalVsPhi", "All tracks;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{64, 0, 2 * o2::constants::math::PI}, {200, 0., 200}}}}, - {"Tracks/raw/PID/PosCharge/hTPCsignalVsZ", "Positively charged track;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, -20., 20.}, {200, 0., 200}}}}, - {"Tracks/raw/PID/PosCharge/hTPCsignalVsP", "Positively charged track;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/raw/PID/PosCharge/hTPCsignalVsPt", "Positively charged track;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/raw/PID/PosCharge/hTPCsignalVsEta", "Positively charged track;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{500, -2., 2.}, {200, 0., 200}}}}, - {"Tracks/raw/PID/PosCharge/hTPCsignalVsPhi", "Positively charged track;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{64, 0, 2 * o2::constants::math::PI}, {200, 0., 200}}}}, - {"Tracks/raw/PID/NegCharge/hTPCsignalVsZ", "Negatively charged track;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, -20., 20.}, {200, 0., 200}}}}, - {"Tracks/raw/PID/NegCharge/hTPCsignalVsP", "Negatively charged track;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/raw/PID/NegCharge/hTPCsignalVsPt", "Negatively charged track;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/raw/PID/NegCharge/hTPCsignalVsEta", "Negatively charged track;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{500, -2., 2.}, {200, 0., 200}}}}, - {"Tracks/raw/PID/NegCharge/hTPCsignalVsPhi", "Negatively charged track;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{64, 0, 2 * o2::constants::math::PI}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/hTPCsignalVsZ", "All good tracks;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, -20., 20.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/hTPCsignalVsP", "All good tracks;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/hTPCsignalVsPt", "All good tracks;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/hTPCsignalVsEta", "All good tracks;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{500, -2., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/hTPCsignalVsPhi", "All good tracks;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{64, 0, 2 * o2::constants::math::PI}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsZ", "Positively charged track;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, -20., 20.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsP", "Positively charged track;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsPt", "Positively charged track;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsEta", "Positively charged track;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{500, -2., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsPhi", "Positively charged track;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{64, 0, 2 * o2::constants::math::PI}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsZ", "Negatively charged track;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, -20., 20.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsP", "Negatively charged track;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsPt", "Negatively charged track;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsEta", "Negatively charged track;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{500, -2., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsPhi", "Negatively charged track;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{64, 0, 2 * o2::constants::math::PI}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Electron/hTPCsignalVsZ", "Identified electron;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, -20., 20.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Electron/hTPCsignalVsP", "Identified electron;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Electron/hTPCsignalVsPt", "Identified electron;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Electron/hTPCsignalVsEta", "Identified electron;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{500, -2., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Electron/hTPCsignalVsPhi", "Identified electron;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{64, 0, 2 * o2::constants::math::PI}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Muon/hTPCsignalVsZ", "Identified Muon;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, -20., 20.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Muon/hTPCsignalVsP", "Identified Muon;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Muon/hTPCsignalVsPt", "Identified Muon;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Muon/hTPCsignalVsEta", "Identified Muon;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{500, -2., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Muon/hTPCsignalVsPhi", "Identified Muon;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{64, 0, 2 * o2::constants::math::PI}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Pion/hTPCsignalVsZ", "Identified Pion;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, -20., 20.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Pion/hTPCsignalVsP", "Identified Pion;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Pion/hTPCsignalVsPt", "Identified Pion;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Pion/hTPCsignalVsEta", "Identified Pion;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{500, -2., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Pion/hTPCsignalVsPhi", "Identified Pion;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{64, 0, 2 * o2::constants::math::PI}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Others/hTPCsignalVsZ", "Identified NOT electron/Muon/Pion;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, -20., 20.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Others/hTPCsignalVsP", "Identified NOT electron/Muon/Pion;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Others/hTPCsignalVsPt", "Identified NOT electron/Muon/Pion;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Others/hTPCsignalVsEta", "Identified NOT electron/Muon/Pion;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{500, -2., 2.}, {200, 0., 200}}}}, - {"Tracks/GoodTrack/PID/Others/hTPCsignalVsPhi", "Identified NOT electron/Muon/Pion;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{64, 0, 2 * o2::constants::math::PI}, {200, 0., 200}}}}, - {"EventTwoTracks/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"EventTwoTracks/TwoElectrons/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"EventTwoTracks/TwoMuons/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"EventTwoTracks/TwoPions/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"EventTwoTracks/ElectronMuon/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"EventTwoTracks/ElectronPion/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"EventTwoTracks/MuonPion/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"EventFourTracks/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"EventFourTracks/WithElectron/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"EventFourTracks/WithMuon/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"EventFourTracks/WithPion/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"EventSixTracks/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}, - {"EventSixTracks/SixPions/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", {HistType::kTH2D, {{200, 0., 2.}, {200, 0., 200}}}}}}; - - // declare configurables - Configurable verboseInfo{"verboseInfo", true, {"Print general info to terminal; default it true."}}; - Configurable verboseDebug{"verboseDebug", false, {"Print debug info to terminal; default it false."}}; - Configurable whichGapSide{"whichGapSide", 2, {"0 for side A, 1 for side C, 2 for both sides"}}; - Configurable cutAvgITSclusterSize{"cutAvgITSclusterSize", 2.05f, {"specific study"}}; - Configurable cutPtAvgITSclusterSize{"cutPtAvgITSclusterSize", 0.7f, {"specific study"}}; - Configurable cutMyGlobalTracksOnly{"cutMyGlobalTracksOnly", false, {"Applies cut on here defined global tracks"}}; - Configurable cutMyGTptMin{"cutMyGTptMin", 0.1f, {"MyGlobalTrack cut"}}; - Configurable cutMyGTptMax{"cutMyGTptMax", 1e10f, {"MyGlobalTrack cut"}}; - Configurable cutMyGTetaMin{"cutMyGTetaMin", -0.8f, {"MyGlobalTrack cut"}}; - Configurable cutMyGTetaMax{"cutMyGTetaMax", 0.8f, {"MyGlobalTrack cut"}}; - Configurable cutMyGTdcaZmax{"cutMyGTdcaZmax", 2.f, {"MyGlobalTrack cut"}}; - Configurable cutMyGTdcaXYmax{"cutMyGTdcaXYmax", 1e10f, {"MyGlobalTrack cut"}}; - Configurable cutMyGTdcaXYusePt{"cutMyGTdcaXYusePt", false, {"MyGlobalTrack cut"}}; - Configurable cutMyHasITS{"cutMyHasITS", true, {"MyGlobalTrack cut"}}; - Configurable cutMyGTitsNClsMin{"cutMyGTitsNClsMin", 1, {"MyGlobalTrack cut"}}; - Configurable cutMyGTitsChi2NclMax{"cutMyGTitsChi2NclMax", 36.f, {"MyGlobalTrack cut"}}; - Configurable cutMyGTitsHitsRule{"cutMyGTitsHitsRule", 0, {"MyGlobalTrack cut"}}; - Configurable cutMyHasTPC{"cutMyHasTPC", true, {"MyGlobalTrack cut"}}; - Configurable cutMyGTtpcNClsMin{"cutMyGTtpcNClsMin", 1, {"MyGlobalTrack cut"}}; - Configurable cutMyGTtpcNClsCrossedRowsMin{"cutMyGTtpcNClsCrossedRowsMin", 70, {"MyGlobalTrack cut"}}; - Configurable cutMyGTtpcNClsCrossedRowsOverNClsMin{"cutMyGTtpcNClsCrossedRowsOverNClsMin", 0.8f, {"MyGlobalTrack cut"}}; - Configurable cutMyGTtpcChi2NclMax{"cutMyGTtpcChi2NclMax", 4.f, {"MyGlobalTrack cut"}}; - - using FullUDTracks = soa::Join; - using FullUDCollision = soa::Join::iterator; - using FullSGUDCollision = soa::Join::iterator; - - TF1* funcPhiCutL = nullptr; - TF1* funcPhiCutH = nullptr; - - // init - void init(InitContext&) - { - mySetITShitsRule(cutMyGTitsHitsRule); - - if (verboseInfo) - printLargeMessage("INIT METHOD"); - countCollisions = 0; - isFirstReconstructedCollisions = true; - - const AxisSpec axisZvtx{40, -20., 20.}; - const AxisSpec axisInvMass{400, 1., 5.}; - const AxisSpec axisInvMassWide{1000, 0., 10.}; - const AxisSpec axisMom{400, 0., 2.}; - const AxisSpec axisMomSigned{800, -2., 2.}; - const AxisSpec axisMomWide{1000, 0., 10.}; - const AxisSpec axisPt{400, 0., 2.}; - const AxisSpec axisPhi{64, -2 * o2::constants::math::PI, 2 * o2::constants::math::PI}; - const AxisSpec axisModPhi{400, 0., .4}; - const AxisSpec axisEta{50, -1.2, 1.2}; - const AxisSpec axisRap{50, -1.2, 1.2}; - const AxisSpec axisAcoplanarity{32, 0.0, o2::constants::math::PI}; - const AxisSpec axisAvgITSclsSizes{500, 0., 10.}; - const AxisSpec axisDCA{100, -0.5, 0.5}; - const AxisSpec axisITSnCls{8, -0.5, 7.5}; - const AxisSpec axisITSchi2{100, 0, 50}; - const AxisSpec axisTPCnCls{165, -0.5, 164.5}; - const AxisSpec axisTPCxRwsFrac{200, 0.0, 2.0}; - const AxisSpec axisTPCchi2{100, 0, 10}; - - histos.add("Tracks/raw/hTrackZ", ";Track z-vertex (cm);Number of events (-)", HistType::kTH1D, {axisZvtx}); - histos.add("Tracks/raw/hTrackP", ";Track #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("Tracks/raw/hTrackPt", ";Track #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("Tracks/raw/hTrackPhi", ";Track #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("Tracks/raw/hTrackPtvsModPhi", ";Track #it{p_{T}} (GeV/c);Track fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("Tracks/raw/hTrackPtvsModPhiTOF", ";Track #it{p_{T}} (GeV/c);Track fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("Tracks/raw/hTrackEta", ";Track #eta (-);Number of events (-)", HistType::kTH1D, {axisEta}); - histos.add("Tracks/raw/hTrackDcaXY", ";Track DCA_{XY} (cm);Number of events (-)", HistType::kTH1D, {axisDCA}); - histos.add("Tracks/raw/hTrackPtvsDcaXY", ";Track #it{p_{T}} (GeV/c);Track DCA_{XY} (cm)", HistType::kTH2D, {axisPt, axisDCA}); - histos.add("Tracks/raw/hTrackDcaZ", ";Track DCA_{Z} (cm);Number of events (-)", HistType::kTH1D, {axisDCA}); - histos.add("Tracks/raw/ITS/itsNCls", "number of found ITS clusters;# clusters ITS", kTH1D, {axisITSnCls}); - histos.add("Tracks/raw/ITS/itsChi2NCl", "chi2 per ITS cluster;chi2 / cluster ITS", kTH1D, {axisITSchi2}); - histos.add("Tracks/raw/TPC/tpcNClsFindable", "number of findable TPC clusters;# findable clusters TPC", kTH1D, {axisTPCnCls}); - histos.add("Tracks/raw/TPC/tpcNClsFound", "number of found TPC clusters;# clusters TPC", kTH1D, {axisTPCnCls}); - histos.add("Tracks/raw/TPC/tpcCrossedRows", "number of crossed TPC rows;# crossed rows TPC", kTH1D, {axisTPCnCls}); - histos.add("Tracks/raw/TPC/tpcCrossedRowsOverFindableCls", "crossed TPC rows over findable clusters;crossed rows / findable clusters TPC", kTH1D, {axisTPCxRwsFrac}); - histos.add("Tracks/raw/TPC/tpcChi2NCl", "chi2 per cluster in TPC;chi2 / cluster TPC", kTH1D, {axisTPCchi2}); - - histos.add("Tracks/GoodTrack/hTrackZ", ";Track z-vertex (cm);Number of events (-)", HistType::kTH1D, {axisZvtx}); - histos.add("Tracks/GoodTrack/hTrackP", ";Track #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("Tracks/GoodTrack/hTrackPt", ";Track #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("Tracks/GoodTrack/hTrackPhi", ";Track #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("Tracks/GoodTrack/hTrackPtvsModPhi", ";Track #it{p_{T}} (GeV/c);Track fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("Tracks/GoodTrack/hTrackPtvsModPhiTOF", ";Track #it{p_{T}} (GeV/c);Track fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("Tracks/GoodTrack/hTrackEta", ";Track #eta (-);Number of events (-)", HistType::kTH1D, {axisEta}); - histos.add("Tracks/GoodTrack/hTrackDcaXY", ";Track DCA_{XY} (cm);Number of events (-)", HistType::kTH1D, {axisDCA}); - histos.add("Tracks/GoodTrack/hTrackPtvsDcaXY", ";Track #it{p_{T}} (GeV/c);Track DCA_{XY} (cm)", HistType::kTH2D, {axisPt, axisDCA}); - histos.add("Tracks/GoodTrack/hTrackDcaZ", ";Track DCA_{Z} (cm);Number of events (-)", HistType::kTH1D, {axisDCA}); - histos.add("Tracks/GoodTrack/ITS/itsNCls", "number of found ITS clusters;# clusters ITS", kTH1D, {axisITSnCls}); - histos.add("Tracks/GoodTrack/ITS/itsChi2NCl", "chi2 per ITS cluster;chi2 / cluster ITS", kTH1D, {axisITSchi2}); - histos.add("Tracks/GoodTrack/TPC/tpcNClsFindable", "number of findable TPC clusters;# findable clusters TPC", kTH1D, {axisTPCnCls}); - histos.add("Tracks/GoodTrack/TPC/tpcNClsFound", "number of found TPC clusters;# clusters TPC", kTH1D, {axisTPCnCls}); - histos.add("Tracks/GoodTrack/TPC/tpcCrossedRows", "number of crossed TPC rows;# crossed rows TPC", kTH1D, {axisTPCnCls}); - histos.add("Tracks/GoodTrack/TPC/tpcCrossedRowsOverFindableCls", "crossed TPC rows over findable clusters;crossed rows / findable clusters TPC", kTH1D, {axisTPCxRwsFrac}); - histos.add("Tracks/GoodTrack/TPC/tpcChi2NCl", "chi2 per cluster in TPC;chi2 / cluster TPC", kTH1D, {axisTPCchi2}); - - histos.add("EventTwoTracks/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventTwoTracks/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/hInvariantMassWideNoMothers", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/hInvariantMassWideAllPionMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/hInvariantMassWideAllPionMassPtCut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/hInvariantMassWideAllPionMassTOF", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/hInvariantMassWideAllPionMassITScut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/hInvariantMassWideAllPionMassPtCutITScut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/hAcoplanarity", ";#Delta#phi (rad);Number of events (-)", HistType::kTH1D, {axisAcoplanarity}); - histos.add("EventTwoTracks/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventTwoTracks/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventTwoTracks/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventTwoTracks/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventTwoTracks/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - histos.add("EventTwoTracks/hDaughtersP", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMom, axisMom}); - histos.add("EventTwoTracks/hDaughtersPwide", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMomWide, axisMomWide}); - histos.add("EventTwoTracks/hDaughtersPt", ";Daughter 1 #it{p_{T}} (GeV/c);Daughter 2 #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisPt, axisPt}); - histos.add("EventTwoTracks/hDaughtersPhi", ";Daughter 1 #phi (rad);Daughter 2 #phi (rad)", HistType::kTH2D, {axisPhi, axisPhi}); - histos.add("EventTwoTracks/hDaughtersRapidity", ";Daughter 1 #it{y} (-);Daughter 2 #it{y} (-)", HistType::kTH2D, {axisRap, axisRap}); - histos.add("EventTwoTracks/hDaughtersPvsITSclusterSize", ";Average ITS cluster size;Daughter #it{p} (GeV/c)", HistType::kTH2D, {axisAvgITSclsSizes, axisMomSigned}); - histos.add("EventTwoTracks/hDaughtersPvsITSclusterSizeXcos", ";Average ITS cluster size x cos(#lambda);Daughter #it{p} (GeV/c)", HistType::kTH2D, {axisAvgITSclsSizes, axisMomSigned}); - - histos.add("EventTwoTracks/TwoElectrons/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventTwoTracks/TwoElectrons/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/TwoElectrons/hInvariantMassWidePtCut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/TwoElectrons/hAcoplanarity", ";#Delta#phi (rad);Number of events (-)", HistType::kTH1D, {axisAcoplanarity}); - histos.add("EventTwoTracks/TwoElectrons/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventTwoTracks/TwoElectrons/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventTwoTracks/TwoElectrons/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventTwoTracks/TwoElectrons/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventTwoTracks/TwoElectrons/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - histos.add("EventTwoTracks/TwoElectrons/hDaughtersP", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMom, axisMom}); - histos.add("EventTwoTracks/TwoElectrons/hDaughtersPwide", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMomWide, axisMomWide}); - histos.add("EventTwoTracks/TwoElectrons/hDaughtersPt", ";Daughter 1 #it{p_{T}} (GeV/c);Daughter 2 #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisPt, axisPt}); - histos.add("EventTwoTracks/TwoElectrons/hDaughtersPhi", ";Daughter 1 #phi (rad);Daughter 2 #phi (rad)", HistType::kTH2D, {axisPhi, axisPhi}); - histos.add("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhi", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiTOF", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiPtCut", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiPtCutTOF", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/TwoElectrons/hDaughtersRapidity", ";Daughter 1 #it{y} (-);Daughter 2 #it{y} (-)", HistType::kTH2D, {axisRap, axisRap}); - histos.add("EventTwoTracks/TwoElectrons/hLeadingP", ";Leading #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventTwoTracks/TwoElectrons/hLeadingPwide", ";Leading #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventTwoTracks/TwoElectrons/hLeadingPt", ";Leading #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventTwoTracks/TwoElectrons/hLeadingPhi", ";Leading #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventTwoTracks/TwoElectrons/hLeadingRapidity", ";Leading #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - - histos.add("EventTwoTracks/TwoMuons/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventTwoTracks/TwoMuons/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/TwoMuons/hInvariantMassWidePtCut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/TwoMuons/hAcoplanarity", ";#Delta#phi (rad);Number of events (-)", HistType::kTH1D, {axisAcoplanarity}); - histos.add("EventTwoTracks/TwoMuons/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventTwoTracks/TwoMuons/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventTwoTracks/TwoMuons/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventTwoTracks/TwoMuons/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventTwoTracks/TwoMuons/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - histos.add("EventTwoTracks/TwoMuons/hDaughtersP", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMom, axisMom}); - histos.add("EventTwoTracks/TwoMuons/hDaughtersPwide", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMomWide, axisMomWide}); - histos.add("EventTwoTracks/TwoMuons/hDaughtersPt", ";Daughter 1 #it{p_{T}} (GeV/c);Daughter 2 #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisPt, axisPt}); - histos.add("EventTwoTracks/TwoMuons/hDaughtersPhi", ";Daughter 1 #phi (rad);Daughter 2 #phi (rad)", HistType::kTH2D, {axisPhi, axisPhi}); - histos.add("EventTwoTracks/TwoMuons/hDaughtersPtvsModPhi", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/TwoMuons/hDaughtersPtvsModPhiTOF", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/TwoMuons/hDaughtersPtvsModPhiPtCut", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/TwoMuons/hDaughtersPtvsModPhiPtCutTOF", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/TwoMuons/hDaughtersRapidity", ";Daughter 1 #it{y} (-);Daughter 2 #it{y} (-)", HistType::kTH2D, {axisRap, axisRap}); - - histos.add("EventTwoTracks/TwoPions/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventTwoTracks/TwoPions/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/TwoPions/hInvariantMassWidePtCut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/TwoPions/hAcoplanarity", ";#Delta#phi (rad);Number of events (-)", HistType::kTH1D, {axisAcoplanarity}); - histos.add("EventTwoTracks/TwoPions/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventTwoTracks/TwoPions/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventTwoTracks/TwoPions/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventTwoTracks/TwoPions/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventTwoTracks/TwoPions/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - histos.add("EventTwoTracks/TwoPions/hDaughtersP", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMom, axisMom}); - histos.add("EventTwoTracks/TwoPions/hDaughtersPwide", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMomWide, axisMomWide}); - histos.add("EventTwoTracks/TwoPions/hDaughtersPt", ";Daughter 1 #it{p_{T}} (GeV/c);Daughter 2 #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisPt, axisPt}); - histos.add("EventTwoTracks/TwoPions/hDaughtersPhi", ";Daughter 1 #phi (rad);Daughter 2 #phi (rad)", HistType::kTH2D, {axisPhi, axisPhi}); - histos.add("EventTwoTracks/TwoPions/hDaughtersPtvsModPhi", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/TwoPions/hDaughtersPtvsModPhiTOF", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/TwoPions/hDaughtersPtvsModPhiPtCut", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/TwoPions/hDaughtersPtvsModPhiPtCutTOF", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/TwoPions/hDaughtersRapidity", ";Daughter 1 #it{y} (-);Daughter 2 #it{y} (-)", HistType::kTH2D, {axisRap, axisRap}); - - histos.add("EventTwoTracks/ElectronMuon/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventTwoTracks/ElectronMuon/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/ElectronMuon/hAcoplanarity", ";#Delta#phi (rad);Number of events (-)", HistType::kTH1D, {axisAcoplanarity}); - histos.add("EventTwoTracks/ElectronMuon/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventTwoTracks/ElectronMuon/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventTwoTracks/ElectronMuon/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventTwoTracks/ElectronMuon/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventTwoTracks/ElectronMuon/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - histos.add("EventTwoTracks/ElectronMuon/hDaughtersP", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMom, axisMom}); - histos.add("EventTwoTracks/ElectronMuon/hDaughtersPwide", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMomWide, axisMomWide}); - histos.add("EventTwoTracks/ElectronMuon/hDaughtersPt", ";Daughter 1 #it{p_{T}} (GeV/c);Daughter 2 #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisPt, axisPt}); - histos.add("EventTwoTracks/ElectronMuon/hDaughtersPhi", ";Daughter 1 #phi (rad);Daughter 2 #phi (rad)", HistType::kTH2D, {axisPhi, axisPhi}); - histos.add("EventTwoTracks/ElectronMuon/hDaughtersRapidity", ";Daughter 1 #it{y} (-);Daughter 2 #it{y} (-)", HistType::kTH2D, {axisRap, axisRap}); - - histos.add("EventTwoTracks/ElectronPion/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventTwoTracks/ElectronPion/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/ElectronPion/hAcoplanarity", ";#Delta#phi (rad);Number of events (-)", HistType::kTH1D, {axisAcoplanarity}); - histos.add("EventTwoTracks/ElectronPion/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventTwoTracks/ElectronPion/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventTwoTracks/ElectronPion/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventTwoTracks/ElectronPion/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventTwoTracks/ElectronPion/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - histos.add("EventTwoTracks/ElectronPion/hDaughtersP", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMom, axisMom}); - histos.add("EventTwoTracks/ElectronPion/hDaughtersPwide", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMomWide, axisMomWide}); - histos.add("EventTwoTracks/ElectronPion/hDaughtersPt", ";Daughter 1 #it{p_{T}} (GeV/c);Daughter 2 #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisPt, axisPt}); - histos.add("EventTwoTracks/ElectronPion/hDaughtersPhi", ";Daughter 1 #phi (rad);Daughter 2 #phi (rad)", HistType::kTH2D, {axisPhi, axisPhi}); - histos.add("EventTwoTracks/ElectronPion/hDaughtersRapidity", ";Daughter 1 #it{y} (-);Daughter 2 #it{y} (-)", HistType::kTH2D, {axisRap, axisRap}); - - histos.add("EventTwoTracks/MuonPion/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventTwoTracks/MuonPion/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonPion/hInvariantMassWidePtCut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonPion/hAcoplanarity", ";#Delta#phi (rad);Number of events (-)", HistType::kTH1D, {axisAcoplanarity}); - histos.add("EventTwoTracks/MuonPion/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventTwoTracks/MuonPion/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventTwoTracks/MuonPion/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventTwoTracks/MuonPion/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventTwoTracks/MuonPion/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - histos.add("EventTwoTracks/MuonPion/hDaughtersP", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMom, axisMom}); - histos.add("EventTwoTracks/MuonPion/hDaughtersPwide", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMomWide, axisMomWide}); - histos.add("EventTwoTracks/MuonPion/hDaughtersPt", ";Daughter 1 #it{p_{T}} (GeV/c);Daughter 2 #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisPt, axisPt}); - histos.add("EventTwoTracks/MuonPion/hDaughtersPhi", ";Daughter 1 #phi (rad);Daughter 2 #phi (rad)", HistType::kTH2D, {axisPhi, axisPhi}); - histos.add("EventTwoTracks/MuonPion/hDaughtersRapidity", ";Daughter 1 #it{y} (-);Daughter 2 #it{y} (-)", HistType::kTH2D, {axisRap, axisRap}); - - histos.add("EventTwoTracks/ElectronMuPi/hNeventsPtCuts", ";Selection (-);Number of events (-)", HistType::kTH1D, {{20, -0.5, 19.5}}); - histos.add("EventTwoTracks/ElectronMuPi/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventTwoTracks/ElectronMuPi/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/ElectronMuPi/hAcoplanarity", ";#Delta#phi (rad);Number of events (-)", HistType::kTH1D, {axisAcoplanarity}); - histos.add("EventTwoTracks/ElectronMuPi/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventTwoTracks/ElectronMuPi/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventTwoTracks/ElectronMuPi/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventTwoTracks/ElectronMuPi/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventTwoTracks/ElectronMuPi/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - histos.add("EventTwoTracks/ElectronMuPi/hElectronPtWide", ";Electron #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventTwoTracks/ElectronMuPi/hDaughtersP", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMom, axisMom}); - histos.add("EventTwoTracks/ElectronMuPi/hDaughtersPwide", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMomWide, axisMomWide}); - histos.add("EventTwoTracks/ElectronMuPi/hDaughtersPt", ";Daughter 1 #it{p_{T}} (GeV/c);Daughter 2 #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisPt, axisPt}); - histos.add("EventTwoTracks/ElectronMuPi/hDaughtersPhi", ";Daughter 1 #phi (rad);Daughter 2 #phi (rad)", HistType::kTH2D, {axisPhi, axisPhi}); - histos.add("EventTwoTracks/ElectronMuPi/hDaughtersRapidity", ";Daughter 1 #it{y} (-);Daughter 2 #it{y} (-)", HistType::kTH2D, {axisRap, axisRap}); - - histos.add("EventTwoTracks/ElectronOther/hNeventsPtCuts", ";Selection (-);Number of events (-)", HistType::kTH1D, {{20, -0.5, 19.5}}); - histos.add("EventTwoTracks/ElectronOther/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventTwoTracks/ElectronOther/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/ElectronOther/hAcoplanarity", ";#Delta#phi (rad);Number of events (-)", HistType::kTH1D, {axisAcoplanarity}); - histos.add("EventTwoTracks/ElectronOther/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventTwoTracks/ElectronOther/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventTwoTracks/ElectronOther/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventTwoTracks/ElectronOther/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventTwoTracks/ElectronOther/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - histos.add("EventTwoTracks/ElectronOther/hElectronPtWide", ";Electron #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventTwoTracks/ElectronOther/hDaughtersP", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMom, axisMom}); - histos.add("EventTwoTracks/ElectronOther/hDaughtersPwide", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMomWide, axisMomWide}); - histos.add("EventTwoTracks/ElectronOther/hDaughtersPt", ";Daughter 1 #it{p_{T}} (GeV/c);Daughter 2 #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisPt, axisPt}); - histos.add("EventTwoTracks/ElectronOther/hDaughtersPhi", ";Daughter 1 #phi (rad);Daughter 2 #phi (rad)", HistType::kTH2D, {axisPhi, axisPhi}); - histos.add("EventTwoTracks/ElectronOther/hDaughtersRapidity", ";Daughter 1 #it{y} (-);Daughter 2 #it{y} (-)", HistType::kTH2D, {axisRap, axisRap}); - - histos.add("EventTwoTracks/PionsSelection/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventTwoTracks/PionsSelection/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/PionsSelection/hInvariantMassWideITS", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/PionsSelection/hInvariantMassPtCut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventTwoTracks/PionsSelection/hInvariantMassWidePtCut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/PionsSelection/hInvariantMassWidePtCutUS", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/PionsSelection/hInvariantMassWidePtCutUSmuMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/PionsSelection/hInvariantMassWidePtCutLS", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/PionsSelection/hInvariantMassWidePtCutUSITScut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/PionsSelection/hInvariantMassWidePtCutLSITScut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/PionsSelection/hasTOF/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/PionsSelection/hasTOF/hInvariantMassWidePtCutUS", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/PionsSelection/hasTOF/hInvariantMassWidePtCutLS", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/PionsSelection/hasTOF/hInvariantMassWidePtCutUSmuMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/PionsSelection/hAcoplanarity", ";#Delta#phi (rad);Number of events (-)", HistType::kTH1D, {axisAcoplanarity}); - histos.add("EventTwoTracks/PionsSelection/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventTwoTracks/PionsSelection/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventTwoTracks/PionsSelection/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventTwoTracks/PionsSelection/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventTwoTracks/PionsSelection/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - histos.add("EventTwoTracks/PionsSelection/hDaughtersP", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMom, axisMom}); - histos.add("EventTwoTracks/PionsSelection/hDaughtersPwide", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMomWide, axisMomWide}); - histos.add("EventTwoTracks/PionsSelection/hDaughtersPt", ";Daughter 1 #it{p_{T}} (GeV/c);Daughter 2 #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisPt, axisPt}); - histos.add("EventTwoTracks/PionsSelection/hDaughtersPhi", ";Daughter 1 #phi (rad);Daughter 2 #phi (rad)", HistType::kTH2D, {axisPhi, axisPhi}); - histos.add("EventTwoTracks/PionsSelection/hDaughtersPtvsModPhi", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/PionsSelection/hasTOF/hDaughtersPtvsModPhi", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/PionsSelection/hDaughtersPtvsModPhiPtCut", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/PionsSelection/hasTOF/hDaughtersPtvsModPhiPtCut", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/PionsSelection/hDaughtersRapidity", ";Daughter 1 #it{y} (-);Daughter 2 #it{y} (-)", HistType::kTH2D, {axisRap, axisRap}); - histos.add("EventTwoTracks/PionsSelection/hDaughtersPtvsDcaXY", ";Daughter #it{p_{T}} (GeV/c);Daughter DCA_{XY} (cm)", HistType::kTH2D, {axisPt, axisDCA}); - histos.add("EventTwoTracks/PionsSelection/hDaughtersPtvsDcaXYPtCut", ";Daughter #it{p_{T}} (GeV/c);Daughter DCA_{XY} (cm)", HistType::kTH2D, {axisPt, axisDCA}); - histos.add("EventTwoTracks/PionsSelection/hDaughtersPvsITSclusterSize", ";Average ITS cluster size;Daughter #it{p} (GeV/c)", HistType::kTH2D, {axisAvgITSclsSizes, axisMomSigned}); - histos.add("EventTwoTracks/PionsSelection/hDaughtersPvsITSclusterSizeXcos", ";Average ITS cluster size x cos(#lambda);Daughter #it{p} (GeV/c)", HistType::kTH2D, {axisAvgITSclsSizes, axisMomSigned}); - - histos.add("EventTwoTracks/MuonsSelection/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWideITS", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassPtCut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUS", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutLS", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSITScut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSnegEta", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSposEta", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSnegRap", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSposRap", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSrap12", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSrap10", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSrap08", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSrap05", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSrap03", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcNcls70", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcNcls100", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcNxRws70", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcNxRws100", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcBordersCut1", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcBordersCut2", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcBordersCut3", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcBordersCut4", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcBordersCut5", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUS", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutLS", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSITScut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSnegEta", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSposEta", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSnegRap", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSposRap", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSrap12", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSrap10", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSrap08", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSrap05", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSrap03", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcNcls70", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcNcls100", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcNxRws70", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcNxRws100", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcBordersCut1", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcBordersCut2", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcBordersCut3", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcBordersCut4", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcBordersCut5", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi1", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi2", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi3", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi4", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi5", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi6", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi7", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi8", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi9", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi10", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi11", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi12", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi13", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi14", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi15", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi16", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi1", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi2", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi3", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi4", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi5", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi6", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi7", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi8", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi9", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi10", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi11", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi12", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi13", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi14", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi15", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi16", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC1", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC2", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC3", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC4", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC5", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC6", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC7", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC8", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC9", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC10", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC11", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC12", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC13", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC14", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC15", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC16", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC1", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC2", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC3", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC4", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC5", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC6", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC7", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC8", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC9", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC10", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC11", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC12", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC13", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC14", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC15", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC16", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutLSITScut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/hAcoplanarity", ";#Delta#phi (rad);Number of events (-)", HistType::kTH1D, {axisAcoplanarity}); - histos.add("EventTwoTracks/MuonsSelection/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventTwoTracks/MuonsSelection/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventTwoTracks/MuonsSelection/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventTwoTracks/MuonsSelection/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventTwoTracks/MuonsSelection/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - histos.add("EventTwoTracks/MuonsSelection/hDaughtersP", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMom, axisMom}); - histos.add("EventTwoTracks/MuonsSelection/hDaughtersPwide", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {axisMomWide, axisMomWide}); - histos.add("EventTwoTracks/MuonsSelection/hDaughtersPt", ";Daughter 1 #it{p_{T}} (GeV/c);Daughter 2 #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisPt, axisPt}); - histos.add("EventTwoTracks/MuonsSelection/hDaughtersPhi", ";Daughter 1 #phi (rad);Daughter 2 #phi (rad)", HistType::kTH2D, {axisPhi, axisPhi}); - histos.add("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhi", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiTPCbordersCut1", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiTPCbordersCut2", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiTPCbordersCut3", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiTPCbordersCut4", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiTPCbordersCut5", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiPtCut", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhi", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiTPCbordersCut1", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiTPCbordersCut2", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiTPCbordersCut3", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiTPCbordersCut4", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiTPCbordersCut5", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiPtCut", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {axisPt, axisModPhi}); - histos.add("EventTwoTracks/MuonsSelection/hDaughtersRapidity", ";Daughter 1 #it{y} (-);Daughter 2 #it{y} (-)", HistType::kTH2D, {axisRap, axisRap}); - histos.add("EventTwoTracks/MuonsSelection/hDaughtersPtvsDcaXY", ";Daughter #it{p_{T}} (GeV/c);Daughter DCA_{XY} (cm)", HistType::kTH2D, {axisPt, axisDCA}); - histos.add("EventTwoTracks/MuonsSelection/hDaughtersPtvsDcaXYPtCut", ";Daughter #it{p_{T}} (GeV/c);Daughter DCA_{XY} (cm)", HistType::kTH2D, {axisPt, axisDCA}); - histos.add("EventTwoTracks/MuonsSelection/hDaughtersPvsITSclusterSize", ";Average ITS cluster size;Daughter #it{p} (GeV/c)", HistType::kTH2D, {axisAvgITSclsSizes, axisMomSigned}); - histos.add("EventTwoTracks/MuonsSelection/hDaughtersPvsITSclusterSizeXcos", ";Average ITS cluster size x cos(#lambda);Daughter #it{p} (GeV/c)", HistType::kTH2D, {axisAvgITSclsSizes, axisMomSigned}); - - histos.add("EventTwoTracks/MuonsSelection/Run2Cuts/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Run2Cuts/hInvariantMassWidePtFitPlot", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventTwoTracks/MuonsSelection/Run2Cuts/hInvariantMassWideCS", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - - histos.add("EventFourTracks/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventFourTracks/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventFourTracks/hInvariantMassWideNoMothers", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventFourTracks/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventFourTracks/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventFourTracks/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventFourTracks/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventFourTracks/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - - histos.add("EventFourTracks/WithElectron/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventFourTracks/WithElectron/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventFourTracks/WithElectron/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventFourTracks/WithElectron/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventFourTracks/WithElectron/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventFourTracks/WithElectron/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventFourTracks/WithElectron/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - - histos.add("EventFourTracks/WithMuon/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventFourTracks/WithMuon/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventFourTracks/WithMuon/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventFourTracks/WithMuon/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventFourTracks/WithMuon/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventFourTracks/WithMuon/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventFourTracks/WithMuon/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - - histos.add("EventFourTracks/WithPion/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventFourTracks/WithPion/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventFourTracks/WithPion/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventFourTracks/WithPion/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventFourTracks/WithPion/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventFourTracks/WithPion/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventFourTracks/WithPion/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - - histos.add("EventSixTracks/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventSixTracks/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventSixTracks/hInvariantMassWideNoMothers", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventSixTracks/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventSixTracks/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventSixTracks/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventSixTracks/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventSixTracks/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - - histos.add("EventSixTracks/SixPions/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventSixTracks/SixPions/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventSixTracks/SixPions/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventSixTracks/SixPions/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventSixTracks/SixPions/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventSixTracks/SixPions/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventSixTracks/SixPions/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - - } // end init - - // run (always called before process :( ) - void run(ProcessingContext& /*context*/) - { - - if (verboseInfo) - printLargeMessage("RUN METHOD"); - if (verboseDebug) - LOGF(info, "countCollisions = %d", countCollisions); - - } // end run - - std::vector>> cutMyRequiredITSHits{}; - - void mySetRequireHitsInITSLayers(int8_t minNRequiredHits, std::set requiredLayers) - { - // layer 0 corresponds to the the innermost ITS layer - cutMyRequiredITSHits.push_back(std::make_pair(minNRequiredHits, requiredLayers)); - } - - void mySetITShitsRule(int matching) - { - switch (matching) { - case 0: // Run3ITSibAny - mySetRequireHitsInITSLayers(1, {0, 1, 2}); - break; - case 1: // Run3ITSibTwo - mySetRequireHitsInITSLayers(2, {0, 1, 2}); - break; - case 2: // Run3ITSallAny - mySetRequireHitsInITSLayers(1, {0, 1, 2, 3, 4, 5, 6}); - break; - case 3: // Run3ITSall7Layers - mySetRequireHitsInITSLayers(7, {0, 1, 2, 3, 4, 5, 6}); - break; - default: - LOG(fatal) << "You chose wrong ITS matching"; - break; - } - } - - bool isFulfillsITSHitRequirementsReinstatement(uint8_t itsClusterMap) const - { - constexpr uint8_t bit = 1; - for (auto& itsRequirement : cutMyRequiredITSHits) { - auto hits = std::count_if(itsRequirement.second.begin(), itsRequirement.second.end(), [&](auto&& requiredLayer) { return itsClusterMap & (bit << requiredLayer); }); - if ((itsRequirement.first == -1) && (hits > 0)) { - return false; // no hits were required in specified layers - } else if (hits < itsRequirement.first) { - return false; // not enough hits found in specified layers - } - } - return true; - } - - template - bool isGlobalTrackReinstatement(T const& track) - { - // kInAcceptance copy - if (track.pt() < cutMyGTptMin || track.pt() > cutMyGTptMax) - return false; - if (eta(track.px(), track.py(), track.pz()) < cutMyGTetaMin || eta(track.px(), track.py(), track.pz()) > cutMyGTetaMax) - return false; - // kPrimaryTracks - // GoldenChi2 cut is only for Run 2 - if (abs(track.dcaZ()) > cutMyGTdcaZmax) - return false; - if (cutMyGTdcaXYusePt) { - float maxDCA = 0.0105f + 0.0350f / pow(track.pt(), 1.1f); // ? not sure yet if will be used - if (abs(track.dcaXY()) > maxDCA) - return false; - } else { - if (abs(track.dcaXY()) > cutMyGTdcaXYmax) - return false; - } - // kQualityTrack - // TrackType is always 1 as per definition of processed Run3 AO2Ds - // ITS - if (cutMyHasITS && !track.hasITS()) - return false; // ITS refit - if (track.itsNCls() < cutMyGTitsNClsMin) - return false; - if (track.itsChi2NCl() > cutMyGTitsChi2NclMax) - return false; - if (!isFulfillsITSHitRequirementsReinstatement(track.itsClusterMap())) - return false; - // TPC - if (cutMyHasTPC && !track.hasTPC()) - return false; // TPC refit - if ((track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) < cutMyGTtpcNClsMin) - return false; // tpcNClsFound() - if (track.tpcNClsCrossedRows() < cutMyGTtpcNClsCrossedRowsMin) - return false; - if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < cutMyGTtpcNClsCrossedRowsOverNClsMin) - return false; - if (track.tpcChi2NCl() > cutMyGTtpcChi2NclMax) - return false; // TPC chi2 - - return true; - } - - template - bool reinstallRun2JpsiTrackSelection(T const& track) - { - // kInAcceptance copy - if (eta(track.px(), track.py(), track.pz()) < -0.8 || eta(track.px(), track.py(), track.pz()) > 0.8) - return false; - // kPrimaryTracks - if (abs(track.dcaZ()) > 2.0) - return false; - float maxDCA = 0.0105f + 0.0350f / pow(track.pt(), 1.1f); - if (abs(track.dcaXY()) > maxDCA) - return false; - // kQualityTrack - // ITS - if (!track.hasITS()) - return false; // ITS refit - if (track.itsChi2NCl() > 36.) - return false; - if (!isFulfillsITSHitRequirementsReinstatement(track.itsClusterMap())) - return false; - // TPC - if (!track.hasTPC()) - return false; // TPC refit - if ((track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) < 70) - return false; // tpcNClsFound() - if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < 0.8) - return false; - if (track.tpcChi2NCl() > 4.) - return false; - // TOF - if (!track.hasTOF()) - return false; - - return true; - } - - template - bool reinstallRun2JpsiEventSelection(C const& collision, T const& trk1, T const& trk2, float rapMother, float aco) - { - // tracks - if (!reinstallRun2JpsiTrackSelection(trk1)) - return false; - if (!reinstallRun2JpsiTrackSelection(trk2)) - return false; - if (trk1.sign() * trk2.sign() > 0) - return false; // opposite sign - if ((trk1.tpcNSigmaMu() * trk1.tpcNSigmaMu() + trk2.tpcNSigmaMu() * trk2.tpcNSigmaMu()) > - (trk1.tpcNSigmaEl() * trk1.tpcNSigmaEl() + trk2.tpcNSigmaEl() * trk2.tpcNSigmaEl())) - return false; // definitely muon than electron - // event - if (collision.posZ() > 15.) - return false; - if (rapMother < -0.8 || rapMother > 0.8) - return false; - if (aco > 4 * o2::constants::math::PI / 5) // max opening angle 144 degrees (I hope, check) - return false; - - return true; - } - - float getPhiModN(float phimodn, int sign, int fieldpolarity) - { - if (fieldpolarity < 0) // for negative polarity field - phimodn = o2::constants::math::TwoPI - phimodn; - if (sign < 0) // for negative charge - phimodn = o2::constants::math::TwoPI - phimodn; - phimodn += o2::constants::math::PI / 18.0; // to center gap in the middle - return std::fmod(phimodn, o2::constants::math::PI / 9.0); - } - - bool isNotCloseToTPCBorder(float phimodn, float trackpt, float cutWidth) - { - - funcPhiCutL = new TF1("funcPhiCutL", Form("0.06/x+pi/18.0-%.f", cutWidth), 0, 100); - funcPhiCutH = new TF1("funcPhiCutH", Form("0.1/x+pi/18.0+%.f", cutWidth), 0, 100); - - if (phimodn < funcPhiCutH->Eval(trackpt) && phimodn > funcPhiCutL->Eval(trackpt)) - return false; // reject track - - return true; - } - - template - void fillHistograms(C reconstructedCollision, Ts reconstructedBarrelTracks) - { - - if (isFirstReconstructedCollisions) { - isFirstReconstructedCollisions = false; - if (verboseInfo) - printLargeMessage("START LOOPING OVER RECONSTRUCTED COLLISIONS"); - } - - histos.get(HIST("Events/hCountCollisions"))->Fill(4); // 1, 2 and 3 are reserved for single-gap - - // Loop over tracks without selections - for (auto& track : reconstructedBarrelTracks) { - float trkPx = track.px(); - float trkPy = track.py(); - float trkPz = track.pz(); - // histos.get(HIST("Tracks/raw/hTrackZ"))->Fill(track.z()); - histos.get(HIST("Tracks/raw/hTrackP"))->Fill(momentum(trkPx, trkPy, trkPz)); - histos.get(HIST("Tracks/raw/hTrackPt"))->Fill(track.pt()); - histos.get(HIST("Tracks/raw/hTrackPhi"))->Fill(phi(trkPx, trkPy)); - histos.get(HIST("Tracks/raw/hTrackEta"))->Fill(eta(trkPx, trkPy, trkPz)); - histos.get(HIST("Tracks/raw/hTrackPtvsModPhi"))->Fill(track.pt(), std::fmod(phi(trkPx, trkPy), o2::constants::math::PI / 9)); - if (track.hasTOF()) - histos.get(HIST("Tracks/raw/hTrackPtvsModPhiTOF"))->Fill(track.pt(), std::fmod(phi(trkPx, trkPy), o2::constants::math::PI / 9)); - // histosPID.get(HIST("Tracks/raw/PID/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); - histos.get(HIST("Tracks/raw/hTrackDcaXY"))->Fill(track.dcaXY()); - histos.get(HIST("Tracks/raw/hTrackPtvsDcaXY"))->Fill(track.pt(), track.dcaXY()); - histos.get(HIST("Tracks/raw/hTrackDcaZ"))->Fill(track.dcaZ()); - histos.get(HIST("Tracks/raw/ITS/itsNCls"))->Fill(track.itsNCls()); - histos.get(HIST("Tracks/raw/ITS/itsChi2NCl"))->Fill(track.itsChi2NCl()); - histos.get(HIST("Tracks/raw/TPC/tpcNClsFindable"))->Fill(track.tpcNClsFindable()); - histos.get(HIST("Tracks/raw/TPC/tpcNClsFound"))->Fill(track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()); - histos.get(HIST("Tracks/raw/TPC/tpcCrossedRows"))->Fill(track.tpcNClsCrossedRows()); - histos.get(HIST("Tracks/raw/TPC/tpcCrossedRowsOverFindableCls"))->Fill((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable()))); - histos.get(HIST("Tracks/raw/TPC/tpcChi2NCl"))->Fill(track.tpcChi2NCl()); - histosPID.get(HIST("Tracks/raw/PID/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/raw/PID/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); - histosPID.get(HIST("Tracks/raw/PID/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/raw/PID/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); - if (track.hasTPC()) { - if (track.sign() == 1) { - // histosPID.get(HIST("Tracks/raw/PID/PosCharge/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); - histosPID.get(HIST("Tracks/raw/PID/PosCharge/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/raw/PID/PosCharge/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); - histosPID.get(HIST("Tracks/raw/PID/PosCharge/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/raw/PID/PosCharge/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); - } else if (track.sign() == -1) { - // histosPID.get(HIST("Tracks/raw/PID/NegCharge/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); - histosPID.get(HIST("Tracks/raw/PID/NegCharge/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/raw/PID/NegCharge/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); - histosPID.get(HIST("Tracks/raw/PID/NegCharge/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/raw/PID/NegCharge/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); - } else { - printMediumMessage("Track has no charge"); - } - } - } // Loop over tracks without selections - - int countPVGT = 0; - int countPVGTselected = 0; - int countPVGTelectrons = 0; - int countPVGTmuons = 0; - int countPVGTpions = 0; - int countPVGTothers = 0; - int countPVGTpionsSelection = 0; - int countPVGTmuonsSelection = 0; - int countTOFtracks = 0; - int countTPCcls70 = 0; - int countTPCcls100 = 0; - int countTPCxRws70 = 0; - int countTPCxRws100 = 0; - std::vector vecPVidx; - // Loop over tracks with selections - for (auto& track : reconstructedBarrelTracks) { - if (track.isPVContributor() != 1) - continue; - if (cutMyGlobalTracksOnly) { - if (isGlobalTrackReinstatement(track) != 1) - continue; - } - countPVGT++; - float trkPx = track.px(); - float trkPy = track.py(); - float trkPz = track.pz(); - // histos.get(HIST("Tracks/GoodTrack/hTrackZ"))->Fill(track.z()); - histos.get(HIST("Tracks/GoodTrack/hTrackP"))->Fill(momentum(trkPx, trkPy, trkPz)); - histos.get(HIST("Tracks/GoodTrack/hTrackPt"))->Fill(track.pt()); - histos.get(HIST("Tracks/GoodTrack/hTrackPhi"))->Fill(phi(trkPx, trkPy)); - histos.get(HIST("Tracks/GoodTrack/hTrackPtvsModPhi"))->Fill(track.pt(), std::fmod(phi(trkPx, trkPy), o2::constants::math::PI / 9)); - if (track.hasTOF()) - histos.get(HIST("Tracks/GoodTrack/hTrackPtvsModPhiTOF"))->Fill(track.pt(), std::fmod(phi(trkPx, trkPy), o2::constants::math::PI / 9)); - histos.get(HIST("Tracks/GoodTrack/hTrackEta"))->Fill(eta(trkPx, trkPy, trkPz)); - // histosPID.get(HIST("Tracks/GoodTrack/PID/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); - histos.get(HIST("Tracks/GoodTrack/hTrackDcaXY"))->Fill(track.dcaXY()); - histos.get(HIST("Tracks/GoodTrack/hTrackPtvsDcaXY"))->Fill(track.pt(), track.dcaXY()); - histos.get(HIST("Tracks/GoodTrack/hTrackDcaZ"))->Fill(track.dcaZ()); - histos.get(HIST("Tracks/GoodTrack/ITS/itsNCls"))->Fill(track.itsNCls()); - histos.get(HIST("Tracks/GoodTrack/ITS/itsChi2NCl"))->Fill(track.itsChi2NCl()); - histos.get(HIST("Tracks/GoodTrack/TPC/tpcNClsFindable"))->Fill(track.tpcNClsFindable()); - histos.get(HIST("Tracks/GoodTrack/TPC/tpcNClsFound"))->Fill(track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()); - histos.get(HIST("Tracks/GoodTrack/TPC/tpcCrossedRows"))->Fill(track.tpcNClsCrossedRows()); - histos.get(HIST("Tracks/GoodTrack/TPC/tpcCrossedRowsOverFindableCls"))->Fill((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable()))); - histos.get(HIST("Tracks/GoodTrack/TPC/tpcChi2NCl"))->Fill(track.tpcChi2NCl()); - histosPID.get(HIST("Tracks/GoodTrack/PID/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); - if (track.hasTPC()) { - if (track.sign() == 1) { - // histosPID.get(HIST("Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); - } else if (track.sign() == -1) { - // histosPID.get(HIST("Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); - } else { - printMediumMessage("Track has no charge"); - } - } - if (track.hasTOF()) - countTOFtracks++; - if ((track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) > 70) - countTPCcls70++; - if ((track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) > 100) - countTPCcls100++; - if (track.tpcNClsCrossedRows() > 70) - countTPCxRws70++; - if (track.tpcNClsCrossedRows() > 100) - countTPCxRws100++; - int hypothesisID = testPIDhypothesis(track); - if (hypothesisID == P_ELECTRON || hypothesisID == P_MUON || hypothesisID == P_PION) { - countPVGTselected++; - vecPVidx.push_back(track.index()); - if (hypothesisID == P_ELECTRON) { - countPVGTelectrons++; - // histosPID.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); - } else if (hypothesisID == P_MUON) { - countPVGTmuons++; - // histosPID.get(HIST("Tracks/GoodTrack/PID/Muon/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/Muon/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/Muon/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/Muon/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/Muon/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); - } else { - countPVGTpions++; - // histosPID.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); - } - } else { - countPVGTothers++; - // histosPID.get(HIST("Tracks/GoodTrack/PID/Others/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/Others/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/Others/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/Others/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); - histosPID.get(HIST("Tracks/GoodTrack/PID/Others/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); - } - if (abs(track.tpcNSigmaPi()) < 3) - countPVGTpionsSelection++; - if (abs(track.tpcNSigmaMu()) < 3) - countPVGTmuonsSelection++; - - } // Loop over tracks with selections - - histos.get(HIST("Events/hNreconstructedPVGT"))->Fill(countPVGT); - histos.get(HIST("Events/hNreconstructedNotPVGT"))->Fill(reconstructedBarrelTracks.size() - countPVGT); - histos.get(HIST("Events/hNreconstructedPVGTelectrons"))->Fill(countPVGTelectrons); - histos.get(HIST("Events/hNreconstructedPVGTmuons"))->Fill(countPVGTmuons); - histos.get(HIST("Events/hNreconstructedPVGTpions"))->Fill(countPVGTpions); - histos.get(HIST("Events/hNreconstructedPVGTothers"))->Fill(countPVGTothers); - - if (countPVGTselected == 2) { - TLorentzVector mother, daug[2], motherOfPions, pion[2], motherOfMuons, muon[2]; - const auto& trkDaug1 = reconstructedBarrelTracks.iteratorAt(vecPVidx[0]); - const auto& trkDaug2 = reconstructedBarrelTracks.iteratorAt(vecPVidx[1]); - daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(pdg->Mass(trackPDG(trkDaug1)), trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); - daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(pdg->Mass(trackPDG(trkDaug2)), trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); - mother = daug[0] + daug[1]; - pion[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(pdg->Mass(211), trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); - pion[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(pdg->Mass(211), trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); - motherOfPions = pion[0] + pion[1]; - muon[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(pdg->Mass(13), trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); - muon[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(pdg->Mass(13), trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); - motherOfMuons = muon[0] + muon[1]; - auto acoplanarity = calculateAcoplanarity(daug[0].Phi(), daug[1].Phi()); - auto sign = trkDaug1.sign() * trkDaug2.sign(); - bool passAvgITSclsSizesCut = passITSAvgClsSizesLowMomCut(trkDaug1, cutAvgITSclusterSize, cutPtAvgITSclusterSize) && passITSAvgClsSizesLowMomCut(trkDaug2, cutAvgITSclusterSize, cutPtAvgITSclusterSize); - - if (trkDaug1.hasTPC()) { - histosPID.get(HIST("EventTwoTracks/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTelectrons == 2) - histosPID.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTmuons == 2) - histosPID.get(HIST("EventTwoTracks/TwoMuons/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTpions == 2) - histosPID.get(HIST("EventTwoTracks/TwoPions/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTelectrons == 1 && countPVGTmuons == 1) - histosPID.get(HIST("EventTwoTracks/ElectronMuon/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTelectrons == 1 && countPVGTpions == 1) - histosPID.get(HIST("EventTwoTracks/ElectronPion/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTpions == 1 && countPVGTmuons == 1) - histosPID.get(HIST("EventTwoTracks/MuonPion/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - } - if (trkDaug2.hasTPC()) { - histosPID.get(HIST("EventTwoTracks/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTelectrons == 2) - histosPID.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTmuons == 2) - histosPID.get(HIST("EventTwoTracks/TwoMuons/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTpions == 2) - histosPID.get(HIST("EventTwoTracks/TwoPions/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTelectrons == 1 && countPVGTmuons == 1) - histosPID.get(HIST("EventTwoTracks/ElectronMuon/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTelectrons == 1 && countPVGTpions == 1) - histosPID.get(HIST("EventTwoTracks/ElectronPion/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTpions == 1 && countPVGTmuons == 1) - histosPID.get(HIST("EventTwoTracks/MuonPion/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - } - - histos.get(HIST("EventTwoTracks/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/hInvariantMassWideAllPionMass"))->Fill(motherOfPions.M()); - histos.get(HIST("EventTwoTracks/hAcoplanarity"))->Fill(acoplanarity); - histos.get(HIST("EventTwoTracks/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventTwoTracks/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventTwoTracks/hMotherRapidity"))->Fill(mother.Rapidity()); - histos.get(HIST("EventTwoTracks/hDaughtersP"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/hDaughtersPwide"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/hDaughtersPt"))->Fill(daug[0].Pt(), daug[1].Pt()); - histos.get(HIST("EventTwoTracks/hDaughtersPhi"))->Fill(daug[0].Phi(), daug[1].Phi()); - histos.get(HIST("EventTwoTracks/hDaughtersRapidity"))->Fill(daug[0].Rapidity(), daug[1].Rapidity()); - if (motherOfPions.Pt() < 0.2) { - histos.get(HIST("EventTwoTracks/hInvariantMassWideAllPionMassPtCut"))->Fill(motherOfPions.M()); - if (passAvgITSclsSizesCut) { - histos.get(HIST("EventTwoTracks/hInvariantMassWideAllPionMassPtCutITScut"))->Fill(motherOfPions.M()); - } - } - if (countTOFtracks == 2) { - histos.get(HIST("EventTwoTracks/hInvariantMassWideAllPionMassTOF"))->Fill(motherOfPions.M()); - } - if (passAvgITSclsSizesCut) { - histos.get(HIST("EventTwoTracks/hInvariantMassWideAllPionMassITScut"))->Fill(motherOfPions.M()); - } - histos.get(HIST("EventTwoTracks/hDaughtersPvsITSclusterSize"))->Fill(getAvgITSClSize(trkDaug1), trkDaug1.sign() * daug[0].P()); - histos.get(HIST("EventTwoTracks/hDaughtersPvsITSclusterSize"))->Fill(getAvgITSClSize(trkDaug2), trkDaug2.sign() * daug[1].P()); - histos.get(HIST("EventTwoTracks/hDaughtersPvsITSclusterSizeXcos"))->Fill(getAvgITSClSize(trkDaug1) * getCosLambda(trkDaug1), trkDaug1.sign() * daug[0].P()); - histos.get(HIST("EventTwoTracks/hDaughtersPvsITSclusterSizeXcos"))->Fill(getAvgITSClSize(trkDaug2) * getCosLambda(trkDaug2), trkDaug2.sign() * daug[1].P()); - - // ee, mm, em, pp, ep, mp, pppp, eppp, mppp, pppppp - if (countPVGTelectrons == 2) { - histos.get(HIST("Events/hChannelsRatio"))->Fill(0); - histos.get(HIST("EventTwoTracks/TwoElectrons/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/TwoElectrons/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/TwoElectrons/hAcoplanarity"))->Fill(acoplanarity); - histos.get(HIST("EventTwoTracks/TwoElectrons/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/TwoElectrons/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/TwoElectrons/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventTwoTracks/TwoElectrons/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventTwoTracks/TwoElectrons/hMotherRapidity"))->Fill(mother.Rapidity()); - histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersP"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPwide"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPt"))->Fill(daug[0].Pt(), daug[1].Pt()); - histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPhi"))->Fill(daug[0].Phi(), daug[1].Phi()); - histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhi"))->Fill(daug[0].P(), getPhiModN(daug[0].Phi(), trkDaug1.sign(), 1)); - histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhi"))->Fill(daug[1].P(), getPhiModN(daug[1].Phi(), trkDaug2.sign(), 1)); - histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersRapidity"))->Fill(daug[0].Rapidity(), daug[1].Rapidity()); - histos.get(HIST("EventTwoTracks/TwoElectrons/hLeadingP"))->Fill(((daug[0].P() > daug[1].P()) ? daug[0].P() : daug[1].P())); - histos.get(HIST("EventTwoTracks/TwoElectrons/hLeadingPwide"))->Fill(((daug[0].P() > daug[1].P()) ? daug[0].P() : daug[1].P())); - histos.get(HIST("EventTwoTracks/TwoElectrons/hLeadingPt"))->Fill(((daug[0].P() > daug[1].P()) ? daug[0].Pt() : daug[1].Pt())); - histos.get(HIST("EventTwoTracks/TwoElectrons/hLeadingPhi"))->Fill(((daug[0].P() > daug[1].P()) ? daug[0].Phi() : daug[1].Phi())); - histos.get(HIST("EventTwoTracks/TwoElectrons/hLeadingRapidity"))->Fill(((daug[0].P() > daug[1].P()) ? daug[0].Rapidity() : daug[1].Rapidity())); - if (mother.Pt() < 0.2) { - histos.get(HIST("EventTwoTracks/TwoElectrons/hInvariantMassWidePtCut"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiPtCut"))->Fill(daug[0].P(), getPhiModN(daug[0].Phi(), trkDaug1.sign(), 1)); - histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiPtCut"))->Fill(daug[1].P(), getPhiModN(daug[1].Phi(), trkDaug2.sign(), 1)); - if (countTOFtracks == 2) { - histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiPtCutTOF"))->Fill(daug[0].P(), getPhiModN(daug[0].Phi(), trkDaug1.sign(), 1)); - histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiPtCutTOF"))->Fill(daug[1].P(), getPhiModN(daug[1].Phi(), trkDaug2.sign(), 1)); - } - } - if (countTOFtracks == 2) { - histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiTOF"))->Fill(daug[0].P(), getPhiModN(daug[0].Phi(), trkDaug1.sign(), 1)); - histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiTOF"))->Fill(daug[1].P(), getPhiModN(daug[1].Phi(), trkDaug2.sign(), 1)); - } - } - if (countPVGTmuons == 2) { - histos.get(HIST("Events/hChannelsRatio"))->Fill(1); - histos.get(HIST("EventTwoTracks/TwoMuons/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/TwoMuons/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/TwoMuons/hAcoplanarity"))->Fill(acoplanarity); - histos.get(HIST("EventTwoTracks/TwoMuons/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/TwoMuons/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/TwoMuons/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventTwoTracks/TwoMuons/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventTwoTracks/TwoMuons/hMotherRapidity"))->Fill(mother.Rapidity()); - histos.get(HIST("EventTwoTracks/TwoMuons/hDaughtersP"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/TwoMuons/hDaughtersPwide"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/TwoMuons/hDaughtersPt"))->Fill(daug[0].Pt(), daug[1].Pt()); - histos.get(HIST("EventTwoTracks/TwoMuons/hDaughtersPhi"))->Fill(daug[0].Phi(), daug[1].Phi()); - histos.get(HIST("EventTwoTracks/TwoMuons/hDaughtersRapidity"))->Fill(daug[0].Rapidity(), daug[1].Rapidity()); - histos.get(HIST("EventTwoTracks/TwoMuons/hDaughtersPtvsModPhi"))->Fill(daug[0].P(), getPhiModN(daug[0].Phi(), trkDaug1.sign(), 1)); - histos.get(HIST("EventTwoTracks/TwoMuons/hDaughtersPtvsModPhi"))->Fill(daug[1].P(), getPhiModN(daug[1].Phi(), trkDaug2.sign(), 1)); - if (mother.Pt() < 0.2) { - histos.get(HIST("EventTwoTracks/TwoMuons/hInvariantMassWidePtCut"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/TwoMuons/hDaughtersPtvsModPhiPtCut"))->Fill(daug[0].P(), getPhiModN(daug[0].Phi(), trkDaug1.sign(), 1)); - histos.get(HIST("EventTwoTracks/TwoMuons/hDaughtersPtvsModPhiPtCut"))->Fill(daug[1].P(), getPhiModN(daug[1].Phi(), trkDaug2.sign(), 1)); - if (countTOFtracks == 2) { - histos.get(HIST("EventTwoTracks/TwoMuons/hDaughtersPtvsModPhiPtCutTOF"))->Fill(daug[0].P(), getPhiModN(daug[0].Phi(), trkDaug1.sign(), 1)); - histos.get(HIST("EventTwoTracks/TwoMuons/hDaughtersPtvsModPhiPtCutTOF"))->Fill(daug[1].P(), getPhiModN(daug[1].Phi(), trkDaug2.sign(), 1)); - } - } - if (countTOFtracks == 2) { - histos.get(HIST("EventTwoTracks/TwoMuons/hDaughtersPtvsModPhiTOF"))->Fill(daug[0].P(), getPhiModN(daug[0].Phi(), trkDaug1.sign(), 1)); - histos.get(HIST("EventTwoTracks/TwoMuons/hDaughtersPtvsModPhiTOF"))->Fill(daug[1].P(), getPhiModN(daug[1].Phi(), trkDaug2.sign(), 1)); - } - } - if (countPVGTelectrons == 1 && countPVGTmuons == 1) { - histos.get(HIST("Events/hChannelsRatio"))->Fill(2); - histos.get(HIST("EventTwoTracks/ElectronMuon/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/ElectronMuon/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/ElectronMuon/hAcoplanarity"))->Fill(acoplanarity); - histos.get(HIST("EventTwoTracks/ElectronMuon/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/ElectronMuon/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/ElectronMuon/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventTwoTracks/ElectronMuon/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventTwoTracks/ElectronMuon/hMotherRapidity"))->Fill(mother.Rapidity()); - histos.get(HIST("EventTwoTracks/ElectronMuon/hDaughtersP"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/ElectronMuon/hDaughtersPwide"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/ElectronMuon/hDaughtersPt"))->Fill(daug[0].Pt(), daug[1].Pt()); - histos.get(HIST("EventTwoTracks/ElectronMuon/hDaughtersPhi"))->Fill(daug[0].Phi(), daug[1].Phi()); - histos.get(HIST("EventTwoTracks/ElectronMuon/hDaughtersRapidity"))->Fill(daug[0].Rapidity(), daug[1].Rapidity()); - } - if (countPVGTpions == 2) { - histos.get(HIST("Events/hChannelsRatio"))->Fill(3); - histos.get(HIST("EventTwoTracks/TwoPions/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/TwoPions/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/TwoPions/hAcoplanarity"))->Fill(acoplanarity); - histos.get(HIST("EventTwoTracks/TwoPions/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/TwoPions/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/TwoPions/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventTwoTracks/TwoPions/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventTwoTracks/TwoPions/hMotherRapidity"))->Fill(mother.Rapidity()); - histos.get(HIST("EventTwoTracks/TwoPions/hDaughtersP"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/TwoPions/hDaughtersPwide"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/TwoPions/hDaughtersPt"))->Fill(daug[0].Pt(), daug[1].Pt()); - histos.get(HIST("EventTwoTracks/TwoPions/hDaughtersPhi"))->Fill(daug[0].Phi(), daug[1].Phi()); - histos.get(HIST("EventTwoTracks/TwoPions/hDaughtersRapidity"))->Fill(daug[0].Rapidity(), daug[1].Rapidity()); - histos.get(HIST("EventTwoTracks/TwoPions/hDaughtersPtvsModPhi"))->Fill(daug[0].P(), getPhiModN(daug[0].Phi(), trkDaug1.sign(), 1)); - histos.get(HIST("EventTwoTracks/TwoPions/hDaughtersPtvsModPhi"))->Fill(daug[1].P(), getPhiModN(daug[1].Phi(), trkDaug2.sign(), 1)); - if (mother.Pt() < 0.2) { - histos.get(HIST("EventTwoTracks/TwoPions/hInvariantMassWidePtCut"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/TwoPions/hDaughtersPtvsModPhiPtCut"))->Fill(daug[0].P(), getPhiModN(daug[0].Phi(), trkDaug1.sign(), 1)); - histos.get(HIST("EventTwoTracks/TwoPions/hDaughtersPtvsModPhiPtCut"))->Fill(daug[1].P(), getPhiModN(daug[1].Phi(), trkDaug2.sign(), 1)); - if (countTOFtracks == 2) { - histos.get(HIST("EventTwoTracks/TwoPions/hDaughtersPtvsModPhiPtCutTOF"))->Fill(daug[0].P(), getPhiModN(daug[0].Phi(), trkDaug1.sign(), 1)); - histos.get(HIST("EventTwoTracks/TwoPions/hDaughtersPtvsModPhiPtCutTOF"))->Fill(daug[1].P(), getPhiModN(daug[1].Phi(), trkDaug2.sign(), 1)); - } - } - if (countTOFtracks == 2) { - histos.get(HIST("EventTwoTracks/TwoPions/hDaughtersPtvsModPhiTOF"))->Fill(daug[0].P(), getPhiModN(daug[0].Phi(), trkDaug1.sign(), 1)); - histos.get(HIST("EventTwoTracks/TwoPions/hDaughtersPtvsModPhiTOF"))->Fill(daug[1].P(), getPhiModN(daug[1].Phi(), trkDaug2.sign(), 1)); - } - } - if (countPVGTelectrons == 1 && countPVGTpions == 1) { - histos.get(HIST("Events/hChannelsRatio"))->Fill(4); - histos.get(HIST("EventTwoTracks/ElectronPion/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/ElectronPion/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/ElectronPion/hAcoplanarity"))->Fill(acoplanarity); - histos.get(HIST("EventTwoTracks/ElectronPion/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/ElectronPion/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/ElectronPion/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventTwoTracks/ElectronPion/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventTwoTracks/ElectronPion/hMotherRapidity"))->Fill(mother.Rapidity()); - histos.get(HIST("EventTwoTracks/ElectronPion/hDaughtersP"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/ElectronPion/hDaughtersPwide"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/ElectronPion/hDaughtersPt"))->Fill(daug[0].Pt(), daug[1].Pt()); - histos.get(HIST("EventTwoTracks/ElectronPion/hDaughtersPhi"))->Fill(daug[0].Phi(), daug[1].Phi()); - histos.get(HIST("EventTwoTracks/ElectronPion/hDaughtersRapidity"))->Fill(daug[0].Rapidity(), daug[1].Rapidity()); - } - if (countPVGTpions == 1 && countPVGTmuons == 1) { - histos.get(HIST("Events/hChannelsRatio"))->Fill(5); - histos.get(HIST("EventTwoTracks/MuonPion/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/MuonPion/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/MuonPion/hAcoplanarity"))->Fill(acoplanarity); - histos.get(HIST("EventTwoTracks/MuonPion/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/MuonPion/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/MuonPion/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventTwoTracks/MuonPion/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventTwoTracks/MuonPion/hMotherRapidity"))->Fill(mother.Rapidity()); - histos.get(HIST("EventTwoTracks/MuonPion/hDaughtersP"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/MuonPion/hDaughtersPwide"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/MuonPion/hDaughtersPt"))->Fill(daug[0].Pt(), daug[1].Pt()); - histos.get(HIST("EventTwoTracks/MuonPion/hDaughtersPhi"))->Fill(daug[0].Phi(), daug[1].Phi()); - histos.get(HIST("EventTwoTracks/MuonPion/hDaughtersRapidity"))->Fill(daug[0].Rapidity(), daug[1].Rapidity()); - if (mother.Pt() < 0.2) { - histos.get(HIST("EventTwoTracks/MuonPion/hInvariantMassWidePtCut"))->Fill(mother.M()); - } - } - if ((countPVGTelectrons == 1 && countPVGTmuons == 1) || (countPVGTelectrons == 1 && countPVGTpions == 1)) { - double electronPt = (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[0].Pt() : daug[1].Pt(); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hAcoplanarity"))->Fill(acoplanarity); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hMotherRapidity"))->Fill(mother.Rapidity()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hElectronPtWide"))->Fill(electronPt); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hDaughtersP"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hDaughtersPwide"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hDaughtersPt"))->Fill(daug[0].Pt(), daug[1].Pt()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hDaughtersPhi"))->Fill(daug[0].Phi(), daug[1].Phi()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hDaughtersRapidity"))->Fill(daug[0].Rapidity(), daug[1].Rapidity()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(0); - if (mother.Pt() < 9.) - histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(1); - if (mother.Pt() < 8.) - histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(2); - if (mother.Pt() < 7.) - histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(3); - if (mother.Pt() < 6.) - histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(4); - if (mother.Pt() < 5.) - histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(5); - if (mother.Pt() < 4.) - histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(6); - if (mother.Pt() < 3.) - histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(7); - if (mother.Pt() < 2.) - histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(8); - if (mother.Pt() < 1.) - histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(9); - if (electronPt > 0.1 && electronPt < 1.) - histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(10); - if (electronPt > 1. && electronPt < 2.) - histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(11); - if (electronPt > 2. && electronPt < 100.) - histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(12); - } - if ((countPVGTelectrons == 2) || (countPVGTelectrons == 1 && countPVGTmuons == 1) || (countPVGTelectrons == 1 && countPVGTpions == 1)) { - double electronPt = (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[0].Pt() : daug[1].Pt(); - if (countPVGTelectrons == 2) - electronPt = (daug[0].Pt() > daug[1].Pt()) ? daug[0].Pt() : daug[1].Pt(); - histos.get(HIST("EventTwoTracks/ElectronOther/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/ElectronOther/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventTwoTracks/ElectronOther/hAcoplanarity"))->Fill(acoplanarity); - histos.get(HIST("EventTwoTracks/ElectronOther/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/ElectronOther/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventTwoTracks/ElectronOther/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventTwoTracks/ElectronOther/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventTwoTracks/ElectronOther/hMotherRapidity"))->Fill(mother.Rapidity()); - histos.get(HIST("EventTwoTracks/ElectronOther/hElectronPtWide"))->Fill(electronPt); - histos.get(HIST("EventTwoTracks/ElectronOther/hDaughtersP"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/ElectronOther/hDaughtersPwide"))->Fill(daug[0].P(), daug[1].P()); - histos.get(HIST("EventTwoTracks/ElectronOther/hDaughtersPt"))->Fill(daug[0].Pt(), daug[1].Pt()); - histos.get(HIST("EventTwoTracks/ElectronOther/hDaughtersPhi"))->Fill(daug[0].Phi(), daug[1].Phi()); - histos.get(HIST("EventTwoTracks/ElectronOther/hDaughtersRapidity"))->Fill(daug[0].Rapidity(), daug[1].Rapidity()); - histos.get(HIST("EventTwoTracks/ElectronOther/hNeventsPtCuts"))->Fill(0); - if (mother.Pt() < 9.) - histos.get(HIST("EventTwoTracks/ElectronOther/hNeventsPtCuts"))->Fill(1); - if (mother.Pt() < 8.) - histos.get(HIST("EventTwoTracks/ElectronOther/hNeventsPtCuts"))->Fill(2); - if (mother.Pt() < 7.) - histos.get(HIST("EventTwoTracks/ElectronOther/hNeventsPtCuts"))->Fill(3); - if (mother.Pt() < 6.) - histos.get(HIST("EventTwoTracks/ElectronOther/hNeventsPtCuts"))->Fill(4); - if (mother.Pt() < 5.) - histos.get(HIST("EventTwoTracks/ElectronOther/hNeventsPtCuts"))->Fill(5); - if (mother.Pt() < 4.) - histos.get(HIST("EventTwoTracks/ElectronOther/hNeventsPtCuts"))->Fill(6); - if (mother.Pt() < 3.) - histos.get(HIST("EventTwoTracks/ElectronOther/hNeventsPtCuts"))->Fill(7); - if (mother.Pt() < 2.) - histos.get(HIST("EventTwoTracks/ElectronOther/hNeventsPtCuts"))->Fill(8); - if (mother.Pt() < 1.) - histos.get(HIST("EventTwoTracks/ElectronOther/hNeventsPtCuts"))->Fill(9); - if (electronPt > 0.1 && electronPt < 1.) - histos.get(HIST("EventTwoTracks/ElectronOther/hNeventsPtCuts"))->Fill(10); - if (electronPt > 1. && electronPt < 2.) - histos.get(HIST("EventTwoTracks/ElectronOther/hNeventsPtCuts"))->Fill(11); - if (electronPt > 2. && electronPt < 100.) - histos.get(HIST("EventTwoTracks/ElectronOther/hNeventsPtCuts"))->Fill(12); - } - if (countPVGTpionsSelection == 2) { - histos.get(HIST("EventTwoTracks/PionsSelection/hInvariantMass"))->Fill(motherOfPions.M()); - histos.get(HIST("EventTwoTracks/PionsSelection/hInvariantMassWide"))->Fill(motherOfPions.M()); - histos.get(HIST("EventTwoTracks/PionsSelection/hAcoplanarity"))->Fill(acoplanarity); - histos.get(HIST("EventTwoTracks/PionsSelection/hMotherP"))->Fill(motherOfPions.P()); - histos.get(HIST("EventTwoTracks/PionsSelection/hMotherPwide"))->Fill(motherOfPions.P()); - histos.get(HIST("EventTwoTracks/PionsSelection/hMotherPt"))->Fill(motherOfPions.Pt()); - histos.get(HIST("EventTwoTracks/PionsSelection/hMotherPhi"))->Fill(motherOfPions.Phi()); - histos.get(HIST("EventTwoTracks/PionsSelection/hMotherRapidity"))->Fill(motherOfPions.Rapidity()); - histos.get(HIST("EventTwoTracks/PionsSelection/hDaughtersP"))->Fill(pion[0].P(), pion[1].P()); - histos.get(HIST("EventTwoTracks/PionsSelection/hDaughtersPwide"))->Fill(pion[0].P(), pion[1].P()); - histos.get(HIST("EventTwoTracks/PionsSelection/hDaughtersPt"))->Fill(pion[0].Pt(), pion[1].Pt()); - histos.get(HIST("EventTwoTracks/PionsSelection/hDaughtersPhi"))->Fill(pion[0].Phi(), pion[1].Phi()); - histos.get(HIST("EventTwoTracks/PionsSelection/hDaughtersRapidity"))->Fill(pion[0].Rapidity(), pion[1].Rapidity()); - histos.get(HIST("EventTwoTracks/PionsSelection/hDaughtersPtvsDcaXY"))->Fill(trkDaug1.pt(), trkDaug1.dcaXY()); - histos.get(HIST("EventTwoTracks/PionsSelection/hDaughtersPtvsDcaXY"))->Fill(trkDaug2.pt(), trkDaug2.dcaXY()); - histos.get(HIST("EventTwoTracks/PionsSelection/hDaughtersPtvsModPhi"))->Fill(pion[0].Pt(), getPhiModN(pion[0].Phi(), trkDaug1.sign(), 1)); - histos.get(HIST("EventTwoTracks/PionsSelection/hDaughtersPtvsModPhi"))->Fill(pion[1].Pt(), getPhiModN(pion[1].Phi(), trkDaug2.sign(), 1)); - if (motherOfPions.Pt() < 0.2) { - histos.get(HIST("EventTwoTracks/PionsSelection/hInvariantMassPtCut"))->Fill(motherOfPions.M()); - histos.get(HIST("EventTwoTracks/PionsSelection/hInvariantMassWidePtCut"))->Fill(motherOfPions.M()); - histos.get(HIST("EventTwoTracks/PionsSelection/hDaughtersPtvsModPhiPtCut"))->Fill(pion[0].Pt(), getPhiModN(pion[0].Phi(), trkDaug1.sign(), 1)); - histos.get(HIST("EventTwoTracks/PionsSelection/hDaughtersPtvsModPhiPtCut"))->Fill(pion[1].Pt(), getPhiModN(pion[1].Phi(), trkDaug2.sign(), 1)); - histos.get(HIST("EventTwoTracks/PionsSelection/hDaughtersPtvsDcaXYPtCut"))->Fill(trkDaug1.pt(), trkDaug1.dcaXY()); - histos.get(HIST("EventTwoTracks/PionsSelection/hDaughtersPtvsDcaXYPtCut"))->Fill(trkDaug2.pt(), trkDaug2.dcaXY()); - if (sign < 0) { - histos.get(HIST("EventTwoTracks/PionsSelection/hInvariantMassWidePtCutUS"))->Fill(motherOfPions.M()); - histos.get(HIST("EventTwoTracks/PionsSelection/hInvariantMassWidePtCutUSmuMass"))->Fill(motherOfMuons.M()); - } - if (sign > 0) - histos.get(HIST("EventTwoTracks/PionsSelection/hInvariantMassWidePtCutLS"))->Fill(motherOfPions.M()); - if (countTOFtracks == 2) { - if (sign < 0) { - histos.get(HIST("EventTwoTracks/PionsSelection/hasTOF/hInvariantMassWidePtCutUS"))->Fill(motherOfPions.M()); - histos.get(HIST("EventTwoTracks/PionsSelection/hasTOF/hInvariantMassWidePtCutUSmuMass"))->Fill(motherOfMuons.M()); - } - if (sign > 0) - histos.get(HIST("EventTwoTracks/PionsSelection/hasTOF/hInvariantMassWidePtCutLS"))->Fill(motherOfPions.M()); - } - if (passAvgITSclsSizesCut) { - if (sign < 0) - histos.get(HIST("EventTwoTracks/PionsSelection/hInvariantMassWidePtCutUSITScut"))->Fill(motherOfPions.M()); - if (sign > 0) - histos.get(HIST("EventTwoTracks/PionsSelection/hInvariantMassWidePtCutLSITScut"))->Fill(motherOfPions.M()); - } - if (countTOFtracks == 2) { - histos.get(HIST("EventTwoTracks/PionsSelection/hasTOF/hDaughtersPtvsModPhiPtCut"))->Fill(pion[0].Pt(), getPhiModN(pion[0].Phi(), trkDaug1.sign(), 1)); - histos.get(HIST("EventTwoTracks/PionsSelection/hasTOF/hDaughtersPtvsModPhiPtCut"))->Fill(pion[1].Pt(), getPhiModN(pion[1].Phi(), trkDaug2.sign(), 1)); - } - } - if (countTOFtracks == 2) { - histos.get(HIST("EventTwoTracks/PionsSelection/hasTOF/hInvariantMassWide"))->Fill(motherOfPions.M()); - histos.get(HIST("EventTwoTracks/PionsSelection/hasTOF/hDaughtersPtvsModPhi"))->Fill(pion[0].Pt(), getPhiModN(pion[0].Phi(), trkDaug1.sign(), 1)); - histos.get(HIST("EventTwoTracks/PionsSelection/hasTOF/hDaughtersPtvsModPhi"))->Fill(pion[1].Pt(), getPhiModN(pion[1].Phi(), trkDaug2.sign(), 1)); - } - if (passAvgITSclsSizesCut) { - histos.get(HIST("EventTwoTracks/PionsSelection/hInvariantMassWideITS"))->Fill(motherOfPions.M()); - } - histos.get(HIST("EventTwoTracks/PionsSelection/hDaughtersPvsITSclusterSize"))->Fill(getAvgITSClSize(trkDaug1), trkDaug1.sign() * daug[0].P()); - histos.get(HIST("EventTwoTracks/PionsSelection/hDaughtersPvsITSclusterSize"))->Fill(getAvgITSClSize(trkDaug2), trkDaug2.sign() * daug[1].P()); - histos.get(HIST("EventTwoTracks/PionsSelection/hDaughtersPvsITSclusterSizeXcos"))->Fill(getAvgITSClSize(trkDaug1) * getCosLambda(trkDaug1), trkDaug1.sign() * daug[0].P()); - histos.get(HIST("EventTwoTracks/PionsSelection/hDaughtersPvsITSclusterSizeXcos"))->Fill(getAvgITSClSize(trkDaug2) * getCosLambda(trkDaug2), trkDaug2.sign() * daug[1].P()); - } - if (countPVGTmuonsSelection == 2) { - float phiModNtrk1 = getPhiModN(muon[0].Phi(), trkDaug1.sign(), 1); - float phiModNtrk2 = getPhiModN(muon[1].Phi(), trkDaug2.sign(), 1); - float cutPhiModN1 = 0.01; - float cutPhiModN2 = 0.03; - float cutPhiModN3 = 0.06; - float cutPhiModN4 = 0.1; - float cutPhiModN5 = 0.2; - float phiPos = 0.; - float phiNeg = 0.; - if (trkDaug1.sign() > 0) { - phiPos = muon[0].Phi(); - phiNeg = muon[1].Phi(); - } else { - phiPos = muon[1].Phi(); - phiNeg = muon[0].Phi(); - } - float phiPosTPC = phiPos - o2::math_utils::angle2Alpha(phiPos); - float phiNegTPC = phiNeg - o2::math_utils::angle2Alpha(phiNeg); - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMass"))->Fill(motherOfMuons.M()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWide"))->Fill(motherOfMuons.M()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hAcoplanarity"))->Fill(acoplanarity); - histos.get(HIST("EventTwoTracks/MuonsSelection/hMotherP"))->Fill(motherOfMuons.P()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hMotherPwide"))->Fill(motherOfMuons.P()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hMotherPt"))->Fill(motherOfMuons.Pt()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hMotherPhi"))->Fill(motherOfMuons.Phi()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hMotherRapidity"))->Fill(motherOfMuons.Rapidity()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersP"))->Fill(muon[0].P(), muon[1].P()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPwide"))->Fill(muon[0].P(), muon[1].P()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPt"))->Fill(muon[0].Pt(), muon[1].Pt()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPhi"))->Fill(muon[0].Phi(), muon[1].Phi()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersRapidity"))->Fill(muon[0].Rapidity(), muon[1].Rapidity()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsDcaXY"))->Fill(trkDaug1.pt(), trkDaug1.dcaXY()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsDcaXY"))->Fill(trkDaug2.pt(), trkDaug2.dcaXY()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhi"))->Fill(muon[0].Pt(), phiModNtrk1); - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhi"))->Fill(muon[1].Pt(), phiModNtrk2); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN1)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiTPCbordersCut1"))->Fill(muon[0].Pt(), phiModNtrk1); - if (isNotCloseToTPCBorder(phiModNtrk2, muon[1].Pt(), cutPhiModN1)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiTPCbordersCut1"))->Fill(muon[1].Pt(), phiModNtrk2); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN2)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiTPCbordersCut2"))->Fill(muon[0].Pt(), phiModNtrk1); - if (isNotCloseToTPCBorder(phiModNtrk2, muon[1].Pt(), cutPhiModN2)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiTPCbordersCut2"))->Fill(muon[1].Pt(), phiModNtrk2); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN3)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiTPCbordersCut3"))->Fill(muon[0].Pt(), phiModNtrk1); - if (isNotCloseToTPCBorder(phiModNtrk2, muon[1].Pt(), cutPhiModN3)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiTPCbordersCut3"))->Fill(muon[1].Pt(), phiModNtrk2); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN4)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiTPCbordersCut4"))->Fill(muon[0].Pt(), phiModNtrk1); - if (isNotCloseToTPCBorder(phiModNtrk2, muon[1].Pt(), cutPhiModN4)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiTPCbordersCut4"))->Fill(muon[1].Pt(), phiModNtrk2); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN5)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiTPCbordersCut5"))->Fill(muon[0].Pt(), phiModNtrk1); - if (isNotCloseToTPCBorder(phiModNtrk2, muon[1].Pt(), cutPhiModN5)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiTPCbordersCut5"))->Fill(muon[1].Pt(), phiModNtrk2); - if (motherOfMuons.Pt() < 0.2) { - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassPtCut"))->Fill(motherOfMuons.M()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCut"))->Fill(motherOfMuons.M()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiPtCut"))->Fill(muon[0].Pt(), phiModNtrk1); - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsModPhiPtCut"))->Fill(muon[1].Pt(), phiModNtrk2); - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsDcaXYPtCut"))->Fill(trkDaug1.pt(), trkDaug1.dcaXY()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPtvsDcaXYPtCut"))->Fill(trkDaug2.pt(), trkDaug2.dcaXY()); - if (sign < 0) { - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUS"))->Fill(motherOfMuons.M()); - if (muon[0].Eta() < 0.0 && muon[1].Eta() < 0.0) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSnegEta"))->Fill(motherOfMuons.M()); - if (muon[0].Eta() > 0.0 && muon[1].Eta() > 0.0) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSposEta"))->Fill(motherOfMuons.M()); - if (motherOfMuons.Rapidity() < 0.0) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSnegRap"))->Fill(motherOfMuons.M()); - if (motherOfMuons.Rapidity() > 0.0) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSposRap"))->Fill(motherOfMuons.M()); - if (std::abs(motherOfMuons.Rapidity()) < 1.2) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSrap12"))->Fill(motherOfMuons.M()); - if (std::abs(motherOfMuons.Rapidity()) < 1.0) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSrap10"))->Fill(motherOfMuons.M()); - if (std::abs(motherOfMuons.Rapidity()) < 0.8) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSrap08"))->Fill(motherOfMuons.M()); - if (std::abs(motherOfMuons.Rapidity()) < 0.5) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSrap05"))->Fill(motherOfMuons.M()); - if (std::abs(motherOfMuons.Rapidity()) < 0.3) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSrap03"))->Fill(motherOfMuons.M()); - if (countTPCcls70 == 2) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcNcls70"))->Fill(motherOfMuons.M()); - if (countTPCcls100 == 2) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcNcls100"))->Fill(motherOfMuons.M()); - if (countTPCxRws70 == 2) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcNxRws70"))->Fill(motherOfMuons.M()); - if (countTPCxRws100 == 2) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcNxRws100"))->Fill(motherOfMuons.M()); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN1) && isNotCloseToTPCBorder(phiModNtrk2, muon[0].Pt(), cutPhiModN1)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcBordersCut1"))->Fill(motherOfMuons.M()); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN2) && isNotCloseToTPCBorder(phiModNtrk2, muon[0].Pt(), cutPhiModN2)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcBordersCut2"))->Fill(motherOfMuons.M()); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN3) && isNotCloseToTPCBorder(phiModNtrk2, muon[0].Pt(), cutPhiModN3)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcBordersCut3"))->Fill(motherOfMuons.M()); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN4) && isNotCloseToTPCBorder(phiModNtrk2, muon[0].Pt(), cutPhiModN4)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcBordersCut4"))->Fill(motherOfMuons.M()); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN5) && isNotCloseToTPCBorder(phiModNtrk2, muon[0].Pt(), cutPhiModN5)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUStpcBordersCut5"))->Fill(motherOfMuons.M()); - if (-8 * o2::constants::math::PI / 8 <= phiPos && phiPos <= -7 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi1"))->Fill(motherOfMuons.M()); - if (-7 * o2::constants::math::PI / 8 < phiPos && phiPos <= -6 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi2"))->Fill(motherOfMuons.M()); - if (-6 * o2::constants::math::PI / 8 < phiPos && phiPos <= -5 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi3"))->Fill(motherOfMuons.M()); - if (-5 * o2::constants::math::PI / 8 < phiPos && phiPos <= -4 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi4"))->Fill(motherOfMuons.M()); - if (-4 * o2::constants::math::PI / 8 < phiPos && phiPos <= -3 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi5"))->Fill(motherOfMuons.M()); - if (-3 * o2::constants::math::PI / 8 < phiPos && phiPos <= -2 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi6"))->Fill(motherOfMuons.M()); - if (-2 * o2::constants::math::PI / 8 < phiPos && phiPos <= -1 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi7"))->Fill(motherOfMuons.M()); - if (-1 * o2::constants::math::PI / 8 < phiPos && phiPos <= -0 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi8"))->Fill(motherOfMuons.M()); - if (0 * o2::constants::math::PI / 8 < phiPos && phiPos <= 1 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi9"))->Fill(motherOfMuons.M()); - if (1 * o2::constants::math::PI / 8 < phiPos && phiPos <= 2 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi10"))->Fill(motherOfMuons.M()); - if (2 * o2::constants::math::PI / 8 < phiPos && phiPos <= 3 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi11"))->Fill(motherOfMuons.M()); - if (3 * o2::constants::math::PI / 8 < phiPos && phiPos <= 4 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi12"))->Fill(motherOfMuons.M()); - if (4 * o2::constants::math::PI / 8 < phiPos && phiPos <= 5 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi13"))->Fill(motherOfMuons.M()); - if (5 * o2::constants::math::PI / 8 < phiPos && phiPos <= 6 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi14"))->Fill(motherOfMuons.M()); - if (6 * o2::constants::math::PI / 8 < phiPos && phiPos <= 7 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi15"))->Fill(motherOfMuons.M()); - if (7 * o2::constants::math::PI / 8 < phiPos && phiPos <= 8 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhi16"))->Fill(motherOfMuons.M()); - if (-8 * o2::constants::math::PI / 8 <= phiNeg && phiNeg <= -7 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi1"))->Fill(motherOfMuons.M()); - if (-7 * o2::constants::math::PI / 8 < phiNeg && phiNeg <= -6 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi2"))->Fill(motherOfMuons.M()); - if (-6 * o2::constants::math::PI / 8 < phiNeg && phiNeg <= -5 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi3"))->Fill(motherOfMuons.M()); - if (-5 * o2::constants::math::PI / 8 < phiNeg && phiNeg <= -4 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi4"))->Fill(motherOfMuons.M()); - if (-4 * o2::constants::math::PI / 8 < phiNeg && phiNeg <= -3 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi5"))->Fill(motherOfMuons.M()); - if (-3 * o2::constants::math::PI / 8 < phiNeg && phiNeg <= -2 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi6"))->Fill(motherOfMuons.M()); - if (-2 * o2::constants::math::PI / 8 < phiNeg && phiNeg <= -1 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi7"))->Fill(motherOfMuons.M()); - if (-1 * o2::constants::math::PI / 8 < phiNeg && phiNeg <= -0 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi8"))->Fill(motherOfMuons.M()); - if (0 * o2::constants::math::PI / 8 < phiNeg && phiNeg <= 1 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi9"))->Fill(motherOfMuons.M()); - if (1 * o2::constants::math::PI / 8 < phiNeg && phiNeg <= 2 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi10"))->Fill(motherOfMuons.M()); - if (2 * o2::constants::math::PI / 8 < phiNeg && phiNeg <= 3 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi11"))->Fill(motherOfMuons.M()); - if (3 * o2::constants::math::PI / 8 < phiNeg && phiNeg <= 4 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi12"))->Fill(motherOfMuons.M()); - if (4 * o2::constants::math::PI / 8 < phiNeg && phiNeg <= 5 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi13"))->Fill(motherOfMuons.M()); - if (5 * o2::constants::math::PI / 8 < phiNeg && phiNeg <= 6 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi14"))->Fill(motherOfMuons.M()); - if (6 * o2::constants::math::PI / 8 < phiNeg && phiNeg <= 7 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi15"))->Fill(motherOfMuons.M()); - if (7 * o2::constants::math::PI / 8 < phiNeg && phiNeg <= 8 * o2::constants::math::PI / 8) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhi16"))->Fill(motherOfMuons.M()); - - if (-8 * o2::constants::math::PI / 256 <= phiPosTPC && phiPosTPC <= -7 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC1"))->Fill(motherOfMuons.M()); - if (-7 * o2::constants::math::PI / 256 < phiPosTPC && phiPosTPC <= -6 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC2"))->Fill(motherOfMuons.M()); - if (-6 * o2::constants::math::PI / 256 < phiPosTPC && phiPosTPC <= -5 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC3"))->Fill(motherOfMuons.M()); - if (-5 * o2::constants::math::PI / 256 < phiPosTPC && phiPosTPC <= -4 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC4"))->Fill(motherOfMuons.M()); - if (-4 * o2::constants::math::PI / 256 < phiPosTPC && phiPosTPC <= -3 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC5"))->Fill(motherOfMuons.M()); - if (-3 * o2::constants::math::PI / 256 < phiPosTPC && phiPosTPC <= -2 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC6"))->Fill(motherOfMuons.M()); - if (-2 * o2::constants::math::PI / 256 < phiPosTPC && phiPosTPC <= -1 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC7"))->Fill(motherOfMuons.M()); - if (-1 * o2::constants::math::PI / 256 < phiPosTPC && phiPosTPC <= -0 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC8"))->Fill(motherOfMuons.M()); - if (0 * o2::constants::math::PI / 256 < phiPosTPC && phiPosTPC <= 1 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC9"))->Fill(motherOfMuons.M()); - if (1 * o2::constants::math::PI / 256 < phiPosTPC && phiPosTPC <= 2 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC10"))->Fill(motherOfMuons.M()); - if (2 * o2::constants::math::PI / 256 < phiPosTPC && phiPosTPC <= 3 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC11"))->Fill(motherOfMuons.M()); - if (3 * o2::constants::math::PI / 256 < phiPosTPC && phiPosTPC <= 4 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC12"))->Fill(motherOfMuons.M()); - if (4 * o2::constants::math::PI / 256 < phiPosTPC && phiPosTPC <= 5 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC13"))->Fill(motherOfMuons.M()); - if (5 * o2::constants::math::PI / 256 < phiPosTPC && phiPosTPC <= 6 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC14"))->Fill(motherOfMuons.M()); - if (6 * o2::constants::math::PI / 256 < phiPosTPC && phiPosTPC <= 7 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC15"))->Fill(motherOfMuons.M()); - if (7 * o2::constants::math::PI / 256 < phiPosTPC && phiPosTPC <= 8 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmupPhiTPC16"))->Fill(motherOfMuons.M()); - if (-8 * o2::constants::math::PI / 256 <= phiNegTPC && phiNegTPC <= -7 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC1"))->Fill(motherOfMuons.M()); - if (-7 * o2::constants::math::PI / 256 < phiNegTPC && phiNegTPC <= -6 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC2"))->Fill(motherOfMuons.M()); - if (-6 * o2::constants::math::PI / 256 < phiNegTPC && phiNegTPC <= -5 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC3"))->Fill(motherOfMuons.M()); - if (-5 * o2::constants::math::PI / 256 < phiNegTPC && phiNegTPC <= -4 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC4"))->Fill(motherOfMuons.M()); - if (-4 * o2::constants::math::PI / 256 < phiNegTPC && phiNegTPC <= -3 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC5"))->Fill(motherOfMuons.M()); - if (-3 * o2::constants::math::PI / 256 < phiNegTPC && phiNegTPC <= -2 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC6"))->Fill(motherOfMuons.M()); - if (-2 * o2::constants::math::PI / 256 < phiNegTPC && phiNegTPC <= -1 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC7"))->Fill(motherOfMuons.M()); - if (-1 * o2::constants::math::PI / 256 < phiNegTPC && phiNegTPC <= -0 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC8"))->Fill(motherOfMuons.M()); - if (0 * o2::constants::math::PI / 256 < phiNegTPC && phiNegTPC <= 1 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC9"))->Fill(motherOfMuons.M()); - if (1 * o2::constants::math::PI / 256 < phiNegTPC && phiNegTPC <= 2 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC10"))->Fill(motherOfMuons.M()); - if (2 * o2::constants::math::PI / 256 < phiNegTPC && phiNegTPC <= 3 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC11"))->Fill(motherOfMuons.M()); - if (3 * o2::constants::math::PI / 256 < phiNegTPC && phiNegTPC <= 4 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC12"))->Fill(motherOfMuons.M()); - if (4 * o2::constants::math::PI / 256 < phiNegTPC && phiNegTPC <= 5 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC13"))->Fill(motherOfMuons.M()); - if (5 * o2::constants::math::PI / 256 < phiNegTPC && phiNegTPC <= 6 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC14"))->Fill(motherOfMuons.M()); - if (6 * o2::constants::math::PI / 256 < phiNegTPC && phiNegTPC <= 7 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC15"))->Fill(motherOfMuons.M()); - if (7 * o2::constants::math::PI / 256 < phiNegTPC && phiNegTPC <= 8 * o2::constants::math::PI / 256) - histos.get(HIST("EventTwoTracks/MuonsSelection/Ruben/hInvariantMassWidePtCutUSmumPhiTPC16"))->Fill(motherOfMuons.M()); - } - if (sign > 0) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutLS"))->Fill(motherOfMuons.M()); - if (countTOFtracks == 2) { - if (sign < 0) { - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUS"))->Fill(motherOfMuons.M()); - if (muon[0].Eta() < 0.0 && muon[1].Eta() < 0.0) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSnegEta"))->Fill(motherOfMuons.M()); - if (muon[0].Eta() > 0.0 && muon[1].Eta() > 0.0) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSposEta"))->Fill(motherOfMuons.M()); - if (motherOfMuons.Rapidity() < 0.0) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSnegRap"))->Fill(motherOfMuons.M()); - if (motherOfMuons.Rapidity() > 0.0) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSposRap"))->Fill(motherOfMuons.M()); - if (std::abs(motherOfMuons.Rapidity()) < 1.2) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSrap12"))->Fill(motherOfMuons.M()); - if (std::abs(motherOfMuons.Rapidity()) < 1.0) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSrap10"))->Fill(motherOfMuons.M()); - if (std::abs(motherOfMuons.Rapidity()) < 0.8) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSrap08"))->Fill(motherOfMuons.M()); - if (std::abs(motherOfMuons.Rapidity()) < 0.5) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSrap05"))->Fill(motherOfMuons.M()); - if (std::abs(motherOfMuons.Rapidity()) < 0.3) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUSrap03"))->Fill(motherOfMuons.M()); - if (countTPCcls70 == 2) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcNcls70"))->Fill(motherOfMuons.M()); - if (countTPCcls100 == 2) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcNcls100"))->Fill(motherOfMuons.M()); - if (countTPCxRws70 == 2) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcNxRws70"))->Fill(motherOfMuons.M()); - if (countTPCxRws100 == 2) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcNxRws100"))->Fill(motherOfMuons.M()); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN1) && isNotCloseToTPCBorder(phiModNtrk2, muon[0].Pt(), cutPhiModN1)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcBordersCut1"))->Fill(motherOfMuons.M()); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN2) && isNotCloseToTPCBorder(phiModNtrk2, muon[0].Pt(), cutPhiModN2)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcBordersCut2"))->Fill(motherOfMuons.M()); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN3) && isNotCloseToTPCBorder(phiModNtrk2, muon[0].Pt(), cutPhiModN3)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcBordersCut3"))->Fill(motherOfMuons.M()); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN4) && isNotCloseToTPCBorder(phiModNtrk2, muon[0].Pt(), cutPhiModN4)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcBordersCut4"))->Fill(motherOfMuons.M()); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN5) && isNotCloseToTPCBorder(phiModNtrk2, muon[0].Pt(), cutPhiModN5)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutUStpcBordersCut5"))->Fill(motherOfMuons.M()); - } - if (sign > 0) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWidePtCutLS"))->Fill(motherOfMuons.M()); - } - if (passAvgITSclsSizesCut) { - if (sign < 0) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutUSITScut"))->Fill(motherOfMuons.M()); - if (sign > 0) - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWidePtCutLSITScut"))->Fill(motherOfMuons.M()); - } - if (countTOFtracks == 2) { - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiPtCut"))->Fill(muon[0].Pt(), phiModNtrk1); - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiPtCut"))->Fill(muon[1].Pt(), phiModNtrk2); - } - } - if (countTOFtracks == 2) { - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hInvariantMassWide"))->Fill(motherOfMuons.M()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhi"))->Fill(muon[0].Pt(), phiModNtrk1); - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhi"))->Fill(muon[1].Pt(), phiModNtrk2); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN1)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiTPCbordersCut1"))->Fill(muon[0].Pt(), phiModNtrk1); - if (isNotCloseToTPCBorder(phiModNtrk2, muon[1].Pt(), cutPhiModN1)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiTPCbordersCut1"))->Fill(muon[1].Pt(), phiModNtrk2); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN2)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiTPCbordersCut2"))->Fill(muon[0].Pt(), phiModNtrk1); - if (isNotCloseToTPCBorder(phiModNtrk2, muon[1].Pt(), cutPhiModN2)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiTPCbordersCut2"))->Fill(muon[1].Pt(), phiModNtrk2); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN3)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiTPCbordersCut3"))->Fill(muon[0].Pt(), phiModNtrk1); - if (isNotCloseToTPCBorder(phiModNtrk2, muon[1].Pt(), cutPhiModN3)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiTPCbordersCut3"))->Fill(muon[1].Pt(), phiModNtrk2); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN4)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiTPCbordersCut4"))->Fill(muon[0].Pt(), phiModNtrk1); - if (isNotCloseToTPCBorder(phiModNtrk2, muon[1].Pt(), cutPhiModN4)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiTPCbordersCut4"))->Fill(muon[1].Pt(), phiModNtrk2); - if (isNotCloseToTPCBorder(phiModNtrk1, muon[0].Pt(), cutPhiModN5)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiTPCbordersCut5"))->Fill(muon[0].Pt(), phiModNtrk1); - if (isNotCloseToTPCBorder(phiModNtrk2, muon[1].Pt(), cutPhiModN5)) - histos.get(HIST("EventTwoTracks/MuonsSelection/hasTOF/hDaughtersPtvsModPhiTPCbordersCut5"))->Fill(muon[1].Pt(), phiModNtrk2); - } - if (reinstallRun2JpsiEventSelection(reconstructedCollision, trkDaug1, trkDaug2, motherOfMuons.Rapidity(), acoplanarity)) { - histos.get(HIST("EventTwoTracks/MuonsSelection/Run2Cuts/hInvariantMassWide"))->Fill(motherOfMuons.M()); - if (motherOfMuons.Pt() < 2.0) { - histos.get(HIST("EventTwoTracks/MuonsSelection/Run2Cuts/hInvariantMassWidePtFitPlot"))->Fill(motherOfMuons.M()); - } - if (motherOfMuons.Pt() < 0.11) { - histos.get(HIST("EventTwoTracks/MuonsSelection/Run2Cuts/hInvariantMassWideCS"))->Fill(motherOfMuons.M()); - } - } - if (passAvgITSclsSizesCut) { - histos.get(HIST("EventTwoTracks/MuonsSelection/hInvariantMassWideITS"))->Fill(motherOfMuons.M()); - } - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPvsITSclusterSize"))->Fill(getAvgITSClSize(trkDaug1), trkDaug1.sign() * daug[0].P()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPvsITSclusterSize"))->Fill(getAvgITSClSize(trkDaug2), trkDaug2.sign() * daug[1].P()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPvsITSclusterSizeXcos"))->Fill(getAvgITSClSize(trkDaug1) * getCosLambda(trkDaug1), trkDaug1.sign() * daug[0].P()); - histos.get(HIST("EventTwoTracks/MuonsSelection/hDaughtersPvsITSclusterSizeXcos"))->Fill(getAvgITSClSize(trkDaug2) * getCosLambda(trkDaug2), trkDaug2.sign() * daug[1].P()); - } - } else if (countPVGTselected == 4) { - - TLorentzVector mother, daug[4]; - const auto& trkDaug1 = reconstructedBarrelTracks.iteratorAt(vecPVidx[0]); - const auto& trkDaug2 = reconstructedBarrelTracks.iteratorAt(vecPVidx[1]); - const auto& trkDaug3 = reconstructedBarrelTracks.iteratorAt(vecPVidx[2]); - const auto& trkDaug4 = reconstructedBarrelTracks.iteratorAt(vecPVidx[3]); - daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(pdg->Mass(trackPDG(trkDaug1)), trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); - daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(pdg->Mass(trackPDG(trkDaug2)), trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); - daug[2].SetPxPyPzE(trkDaug3.px(), trkDaug3.py(), trkDaug3.pz(), energy(pdg->Mass(trackPDG(trkDaug3)), trkDaug3.px(), trkDaug3.py(), trkDaug3.pz())); - daug[3].SetPxPyPzE(trkDaug4.px(), trkDaug4.py(), trkDaug4.pz(), energy(pdg->Mass(trackPDG(trkDaug4)), trkDaug4.px(), trkDaug4.py(), trkDaug4.pz())); - mother = daug[0] + daug[1] + daug[2] + daug[3]; - - if (trkDaug1.hasTPC()) { - histosPID.get(HIST("EventFourTracks/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTpions == 4) - histosPID.get(HIST("EventFourTracks/WithPion/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTelectrons == 1 && countPVGTpions == 3) - histosPID.get(HIST("EventFourTracks/WithElectron/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTpions == 3 && countPVGTmuons == 1) - histosPID.get(HIST("EventFourTracks/WithMuon/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - } - if (trkDaug2.hasTPC()) { - histosPID.get(HIST("EventFourTracks/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTpions == 4) - histosPID.get(HIST("EventFourTracks/WithPion/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTelectrons == 1 && countPVGTpions == 3) - histosPID.get(HIST("EventFourTracks/WithElectron/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTpions == 3 && countPVGTmuons == 1) - histosPID.get(HIST("EventFourTracks/WithMuon/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - } - if (trkDaug3.hasTPC()) { - histosPID.get(HIST("EventFourTracks/PID/hTPCsignalVsP"))->Fill(daug[2].P(), trkDaug3.tpcSignal()); - if (countPVGTpions == 4) - histosPID.get(HIST("EventFourTracks/WithPion/PID/hTPCsignalVsP"))->Fill(daug[2].P(), trkDaug3.tpcSignal()); - if (countPVGTelectrons == 1 && countPVGTpions == 3) - histosPID.get(HIST("EventFourTracks/WithElectron/PID/hTPCsignalVsP"))->Fill(daug[2].P(), trkDaug3.tpcSignal()); - if (countPVGTpions == 3 && countPVGTmuons == 1) - histosPID.get(HIST("EventFourTracks/WithMuon/PID/hTPCsignalVsP"))->Fill(daug[2].P(), trkDaug3.tpcSignal()); - } - if (trkDaug4.hasTPC()) { - histosPID.get(HIST("EventFourTracks/PID/hTPCsignalVsP"))->Fill(daug[3].P(), trkDaug4.tpcSignal()); - if (countPVGTpions == 4) - histosPID.get(HIST("EventFourTracks/WithPion/PID/hTPCsignalVsP"))->Fill(daug[3].P(), trkDaug4.tpcSignal()); - if (countPVGTelectrons == 1 && countPVGTpions == 3) - histosPID.get(HIST("EventFourTracks/WithElectron/PID/hTPCsignalVsP"))->Fill(daug[3].P(), trkDaug4.tpcSignal()); - if (countPVGTpions == 3 && countPVGTmuons == 1) - histosPID.get(HIST("EventFourTracks/WithMuon/PID/hTPCsignalVsP"))->Fill(daug[3].P(), trkDaug4.tpcSignal()); - } - - histos.get(HIST("EventFourTracks/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventFourTracks/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventFourTracks/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventFourTracks/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventFourTracks/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventFourTracks/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventFourTracks/hMotherRapidity"))->Fill(mother.Rapidity()); - - // ee, mm, em, pp, ep, mp, pppp, eppp, mppp, pppppp - if (countPVGTpions == 4) { - histos.get(HIST("Events/hChannelsRatio"))->Fill(6); - histos.get(HIST("EventFourTracks/WithPion/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventFourTracks/WithPion/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventFourTracks/WithPion/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventFourTracks/WithPion/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventFourTracks/WithPion/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventFourTracks/WithPion/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventFourTracks/WithPion/hMotherRapidity"))->Fill(mother.Rapidity()); - } - if (countPVGTelectrons == 1 && countPVGTpions == 3) { - histos.get(HIST("Events/hChannelsRatio"))->Fill(7); - histos.get(HIST("EventFourTracks/WithElectron/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventFourTracks/WithElectron/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventFourTracks/WithElectron/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventFourTracks/WithElectron/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventFourTracks/WithElectron/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventFourTracks/WithElectron/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventFourTracks/WithElectron/hMotherRapidity"))->Fill(mother.Rapidity()); - } - if (countPVGTpions == 3 && countPVGTmuons == 1) { - histos.get(HIST("Events/hChannelsRatio"))->Fill(8); - histos.get(HIST("EventFourTracks/WithMuon/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventFourTracks/WithMuon/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventFourTracks/WithMuon/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventFourTracks/WithMuon/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventFourTracks/WithMuon/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventFourTracks/WithMuon/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventFourTracks/WithMuon/hMotherRapidity"))->Fill(mother.Rapidity()); - } - } else if (countPVGTselected == 6) { - TLorentzVector mother, daug[6]; - const auto& trkDaug1 = reconstructedBarrelTracks.iteratorAt(vecPVidx[0]); - const auto& trkDaug2 = reconstructedBarrelTracks.iteratorAt(vecPVidx[1]); - const auto& trkDaug3 = reconstructedBarrelTracks.iteratorAt(vecPVidx[2]); - const auto& trkDaug4 = reconstructedBarrelTracks.iteratorAt(vecPVidx[3]); - const auto& trkDaug5 = reconstructedBarrelTracks.iteratorAt(vecPVidx[4]); - const auto& trkDaug6 = reconstructedBarrelTracks.iteratorAt(vecPVidx[5]); - daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(pdg->Mass(trackPDG(trkDaug1)), trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); - daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(pdg->Mass(trackPDG(trkDaug2)), trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); - daug[2].SetPxPyPzE(trkDaug3.px(), trkDaug3.py(), trkDaug3.pz(), energy(pdg->Mass(trackPDG(trkDaug3)), trkDaug3.px(), trkDaug3.py(), trkDaug3.pz())); - daug[3].SetPxPyPzE(trkDaug4.px(), trkDaug4.py(), trkDaug4.pz(), energy(pdg->Mass(trackPDG(trkDaug4)), trkDaug4.px(), trkDaug4.py(), trkDaug4.pz())); - daug[4].SetPxPyPzE(trkDaug5.px(), trkDaug5.py(), trkDaug5.pz(), energy(pdg->Mass(trackPDG(trkDaug5)), trkDaug5.px(), trkDaug5.py(), trkDaug5.pz())); - daug[5].SetPxPyPzE(trkDaug6.px(), trkDaug6.py(), trkDaug6.pz(), energy(pdg->Mass(trackPDG(trkDaug6)), trkDaug6.px(), trkDaug6.py(), trkDaug6.pz())); - mother = daug[0] + daug[1] + daug[2] + daug[3] + daug[4] + daug[5]; - - if (trkDaug1.hasTPC()) { - histosPID.get(HIST("EventSixTracks/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTpions == 6) - histosPID.get(HIST("EventSixTracks/SixPions/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - } - if (trkDaug2.hasTPC()) { - histosPID.get(HIST("EventSixTracks/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTpions == 6) - histosPID.get(HIST("EventSixTracks/SixPions/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - } - if (trkDaug3.hasTPC()) { - histosPID.get(HIST("EventSixTracks/PID/hTPCsignalVsP"))->Fill(daug[2].P(), trkDaug3.tpcSignal()); - if (countPVGTpions == 6) - histosPID.get(HIST("EventSixTracks/SixPions/PID/hTPCsignalVsP"))->Fill(daug[2].P(), trkDaug3.tpcSignal()); - } - if (trkDaug4.hasTPC()) { - histosPID.get(HIST("EventSixTracks/PID/hTPCsignalVsP"))->Fill(daug[3].P(), trkDaug4.tpcSignal()); - if (countPVGTpions == 6) - histosPID.get(HIST("EventSixTracks/SixPions/PID/hTPCsignalVsP"))->Fill(daug[3].P(), trkDaug4.tpcSignal()); - } - if (trkDaug5.hasTPC()) { - histosPID.get(HIST("EventSixTracks/PID/hTPCsignalVsP"))->Fill(daug[4].P(), trkDaug5.tpcSignal()); - if (countPVGTpions == 6) - histosPID.get(HIST("EventSixTracks/SixPions/PID/hTPCsignalVsP"))->Fill(daug[4].P(), trkDaug5.tpcSignal()); - } - if (trkDaug6.hasTPC()) { - histosPID.get(HIST("EventSixTracks/PID/hTPCsignalVsP"))->Fill(daug[5].P(), trkDaug6.tpcSignal()); - if (countPVGTpions == 6) - histosPID.get(HIST("EventSixTracks/SixPions/PID/hTPCsignalVsP"))->Fill(daug[5].P(), trkDaug6.tpcSignal()); - } - - histos.get(HIST("EventSixTracks/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventSixTracks/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventSixTracks/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventSixTracks/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventSixTracks/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventSixTracks/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventSixTracks/hMotherRapidity"))->Fill(mother.Rapidity()); - - // ee, mm, em, pp, ep, mp, pppp, eppp, mppp, pppppp - if (countPVGTpions == 6) { - histos.get(HIST("Events/hChannelsRatio"))->Fill(9); - histos.get(HIST("EventSixTracks/SixPions/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventSixTracks/SixPions/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventSixTracks/SixPions/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventSixTracks/SixPions/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventSixTracks/SixPions/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventSixTracks/SixPions/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventSixTracks/SixPions/hMotherRapidity"))->Fill(mother.Rapidity()); - } - } else { - if (verboseDebug) { - printMediumMessage("Other particles"); - } - } - - } // end fillHistograms - - void processDGrecoLevel(FullUDCollision const& reconstructedCollision, - FullUDTracks const& reconstructedBarrelTracks) - { - countCollisions++; - - fillHistograms(reconstructedCollision, reconstructedBarrelTracks); - - } // end processDGrecoLevel - - void processSGrecoLevel(FullSGUDCollision const& reconstructedCollision, - FullUDTracks const& reconstructedBarrelTracks) - { - countCollisions++; - - if (reconstructedCollision.gapSide() == 0) - histos.get(HIST("Events/hCountCollisions"))->Fill(1); - if (reconstructedCollision.gapSide() == 1) - histos.get(HIST("Events/hCountCollisions"))->Fill(2); - if (reconstructedCollision.gapSide() == 2) - histos.get(HIST("Events/hCountCollisions"))->Fill(3); - if (reconstructedCollision.gapSide() != whichGapSide) - return; - - fillHistograms(reconstructedCollision, reconstructedBarrelTracks); - - } // end processDGrecoLevel - - void processAnalysisFinished(FullUDCollision const& /*collisions*/) - { - - if (verboseInfo) - LOGF(info, "####################################### END OF THIS DATAFRAME #######################################"); - if (verboseDebug) - LOGF(info, "countCollisions = %d"); - isFirstReconstructedCollisions = true; - - } // end processAnalysisFinished - - PROCESS_SWITCH(UpcTauCentralBarrelRL, processDGrecoLevel, "Iterate UD tables with reconstructed data created by DG-Candidate-Producer", false); - PROCESS_SWITCH(UpcTauCentralBarrelRL, processSGrecoLevel, "Iterate UD tables with reconstructed data created by SG-Candidate-Producer", false); - PROCESS_SWITCH(UpcTauCentralBarrelRL, processAnalysisFinished, "Simply runs in the end of the dataframe", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"upc-tau-rl"})}; -} diff --git a/PWGUD/Tasks/upcTauRl.cxx b/PWGUD/Tasks/upcTauRl.cxx new file mode 100644 index 00000000000..91b4e87ed29 --- /dev/null +++ b/PWGUD/Tasks/upcTauRl.cxx @@ -0,0 +1,2456 @@ +// 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 upcTauRl.cxx +/// \brief Personal task to analyze tau events from UPC collisions +/// +/// \author Roman Lavicka , Austrian Academy of Sciences & SMI +/// \since 12.07.2022 +// + +// C++ headers +#include +#include +#include +#include +#include + +// O2 headers +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +// O2Physics headers +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/SGSelector.h" + +// ROOT headers +#include "TLorentzVector.h" +#include "TPDGCode.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +namespace o2::aod +{ +namespace tau_tree +{ +// event info +DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); +DECLARE_SOA_COLUMN(Bc, bc, int); +DECLARE_SOA_COLUMN(TotalTracks, totalTracks, int); +DECLARE_SOA_COLUMN(NumContrib, numContrib, int); +DECLARE_SOA_COLUMN(GlobalNonPVtracks, globalNonPVtracks, int); +DECLARE_SOA_COLUMN(PosX, posX, float); +DECLARE_SOA_COLUMN(PosY, posY, float); +DECLARE_SOA_COLUMN(PosZ, posZ, float); +DECLARE_SOA_COLUMN(RecoMode, recoMode, int); +DECLARE_SOA_COLUMN(OccupancyInTime, occupancyInTime, int); +DECLARE_SOA_COLUMN(HadronicRate, hadronicRate, double); +DECLARE_SOA_COLUMN(Trs, trs, int); +DECLARE_SOA_COLUMN(Trofs, trofs, int); +DECLARE_SOA_COLUMN(Hmpr, hmpr, int); +DECLARE_SOA_COLUMN(Tfb, tfb, int); +DECLARE_SOA_COLUMN(ItsRofb, itsRofb, int); +DECLARE_SOA_COLUMN(Sbp, sbp, int); +DECLARE_SOA_COLUMN(ZvtxFT0vsPv, zvtxFT0vsPv, int); +DECLARE_SOA_COLUMN(VtxITSTPC, vtxITSTPC, int); +// FIT info +DECLARE_SOA_COLUMN(TotalFT0AmplitudeA, totalFT0AmplitudeA, float); +DECLARE_SOA_COLUMN(TotalFT0AmplitudeC, totalFT0AmplitudeC, float); +DECLARE_SOA_COLUMN(TotalFV0AmplitudeA, totalFV0AmplitudeA, float); +DECLARE_SOA_COLUMN(EnergyCommonZNA, energyCommonZNA, float); +DECLARE_SOA_COLUMN(EnergyCommonZNC, energyCommonZNC, float); +DECLARE_SOA_COLUMN(TimeFT0A, timeFT0A, float); +DECLARE_SOA_COLUMN(TimeFT0C, timeFT0C, float); +DECLARE_SOA_COLUMN(TimeFV0A, timeFV0A, float); +DECLARE_SOA_COLUMN(TimeZNA, timeZNA, float); +DECLARE_SOA_COLUMN(TimeZNC, timeZNC, float); +// tracks +DECLARE_SOA_COLUMN(TrkPx, trkPx, float[2]); +DECLARE_SOA_COLUMN(TrkPy, trkPy, float[2]); +DECLARE_SOA_COLUMN(TrkPz, trkPz, float[2]); +DECLARE_SOA_COLUMN(TrkSign, trkSign, int[2]); +DECLARE_SOA_COLUMN(TrkDCAxy, trkDCAxy, float[2]); +DECLARE_SOA_COLUMN(TrkDCAz, trkDCAz, float[2]); +DECLARE_SOA_COLUMN(TrkTimeRes, trkTimeRes, float[2]); +DECLARE_SOA_COLUMN(Trk1ITSclusterSizes, trk1ITSclusterSizes, uint32_t); +DECLARE_SOA_COLUMN(Trk2ITSclusterSizes, trk2ITSclusterSizes, uint32_t); +DECLARE_SOA_COLUMN(TrkTPCsignal, trkTPCsignal, float[2]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaEl, trkTPCnSigmaEl, float[2]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaMu, trkTPCnSigmaMu, float[2]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaPi, trkTPCnSigmaPi, float[2]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaKa, trkTPCnSigmaKa, float[2]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaPr, trkTPCnSigmaPr, float[2]); +DECLARE_SOA_COLUMN(TrkTPCinnerParam, trkTPCinnerParam, float[2]); +DECLARE_SOA_COLUMN(TrkTOFsignal, trkTOFsignal, float[2]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaEl, trkTOFnSigmaEl, float[2]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaMu, trkTOFnSigmaMu, float[2]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaPi, trkTOFnSigmaPi, float[2]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaKa, trkTOFnSigmaKa, float[2]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaPr, trkTOFnSigmaPr, float[2]); +DECLARE_SOA_COLUMN(TrkTOFexpMom, trkTOFexpMom, float[2]); + +} // namespace tau_tree +DECLARE_SOA_TABLE(TauTwoTracks, "AOD", "TAUTWOTRACK", + tau_tree::RunNumber, tau_tree::Bc, tau_tree::TotalTracks, tau_tree::NumContrib, tau_tree::GlobalNonPVtracks, tau_tree::PosX, tau_tree::PosY, tau_tree::PosZ, + tau_tree::RecoMode, tau_tree::OccupancyInTime, tau_tree::HadronicRate, + tau_tree::Trs, tau_tree::Trofs, tau_tree::Hmpr, tau_tree::Tfb, tau_tree::ItsRofb, tau_tree::Sbp, tau_tree::ZvtxFT0vsPv, tau_tree::VtxITSTPC, + tau_tree::TotalFT0AmplitudeA, tau_tree::TotalFT0AmplitudeC, tau_tree::TotalFV0AmplitudeA, tau_tree::EnergyCommonZNA, tau_tree::EnergyCommonZNC, + tau_tree::TimeFT0A, tau_tree::TimeFT0C, tau_tree::TimeFV0A, tau_tree::TimeZNA, tau_tree::TimeZNC, + tau_tree::TrkPx, tau_tree::TrkPy, tau_tree::TrkPz, tau_tree::TrkSign, tau_tree::TrkDCAxy, tau_tree::TrkDCAz, tau_tree::TrkTimeRes, + tau_tree::Trk1ITSclusterSizes, tau_tree::Trk2ITSclusterSizes, + tau_tree::TrkTPCsignal, tau_tree::TrkTPCnSigmaEl, tau_tree::TrkTPCnSigmaMu, tau_tree::TrkTPCnSigmaPi, tau_tree::TrkTPCnSigmaKa, tau_tree::TrkTPCnSigmaPr, tau_tree::TrkTPCinnerParam, + tau_tree::TrkTOFsignal, tau_tree::TrkTOFnSigmaEl, tau_tree::TrkTOFnSigmaMu, tau_tree::TrkTOFnSigmaPi, tau_tree::TrkTOFnSigmaKa, tau_tree::TrkTOFnSigmaPr, tau_tree::TrkTOFexpMom); + +} // namespace o2::aod + +struct UpcTauRl { + Produces tauTwoTracks; + + // Global varialbes + Service pdg; + SGSelector sgSelector; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // declare configurables + Configurable verboseInfo{"verboseInfo", false, {"Print general info to terminal; default it false."}}; + Configurable doMainHistos{"doMainHistos", false, {"Fill main histos"}}; + Configurable doPIDhistos{"doPIDhistos", false, {"Fill PID histos"}}; + Configurable doTruthHistos{"doTruthHistos", false, {"Do histograms specific for generated events/particles"}}; + Configurable doMCtrueElectronCheck{"doMCtrueElectronCheck", false, {"Check if track hypothesis corresponds to MC truth. If no, it cuts."}}; + Configurable oppositeMCtrueElectronCheck{"oppositeMCtrueElectronCheck", false, {"While doMCtrueElectronCheck is true, check if track hypothesis corresponds to MC truth. If yes, it cuts."}}; + Configurable doTwoTracks{"doTwoTracks", false, {"Define histos for two tracks and allow to fill them"}}; + Configurable doOutputTauEvents{"doOutputTauEvents", false, {"Select tau two-tracks events under loose criteria and stores them to root tree"}}; + + struct : ConfigurableGroup { + Configurable whichGapSide{"whichGapSide", 2, {"0 for side A, 1 for side C, 2 for both sides"}}; + Configurable useTrueGap{"useTrueGap", true, {"Calculate gapSide for a given FV0/FT0/ZDC thresholds"}}; + Configurable cutNumContribs{"cutNumContribs", 2, {"How many contributors event has"}}; + Configurable useNumContribs{"useNumContribs", true, {"Use coll.numContribs as event cut"}}; + Configurable cutRecoFlag{"cutRecoFlag", 1, {"0 = std mode, 1 = upc mode"}}; + Configurable useRecoFlag{"useRecoFlag", false, {"Use coll.flags as event cut"}}; + Configurable cutTrueGapSideFV0{"cutTrueGapSideFV0", -1, "FV0A threshold for SG selector"}; + Configurable cutTrueGapSideFT0A{"cutTrueGapSideFT0A", 150., "FT0A threshold for SG selector"}; + Configurable cutTrueGapSideFT0C{"cutTrueGapSideFT0C", 50., "FT0C threshold for SG selector"}; + Configurable cutTrueGapSideZDC{"cutTrueGapSideZDC", 0., "ZDC threshold for SG selector. 0 is <1n, 4.2 is <2n, 6.7 is <3n, 9.5 is <4n, 12.5 is <5n"}; + Configurable cutFITtime{"cutFITtime", 40., "Maximum FIT time allowed. Default is 40ns"}; + Configurable cutEvOccupancy{"cutEvOccupancy", 100000., "Maximum allowed occupancy"}; + Configurable cutEvTrs{"cutEvTrs", true, {"Event selection bit kNoCollInTimeRangeStandard"}}; + Configurable cutEvTrofs{"cutEvTrofs", true, {"Event selection bit kNoCollInRofStandard"}}; + Configurable cutEvHmpr{"cutEvHmpr", true, {"Event selection bit kNoHighMultCollInPrevRof"}}; + Configurable applyAcceptanceSelection{"applyAcceptanceSelection", false, {"Select events in ALICE CB acceptance set with cutTrackEta"}}; + Configurable cutTrackEta{"cutTrackEta", 0.9, "Cut on central barrel track eta in absolute values."}; + } cutSample; + + struct : ConfigurableGroup { + Configurable applyGlobalTrackSelection{"applyGlobalTrackSelection", false, {"Applies cut on here defined global tracks"}}; + Configurable cutMinPt{"cutMinPt", 0.1f, {"Global track cut"}}; + Configurable cutMaxPt{"cutMaxPt", 1e10f, {"Global track cut"}}; + Configurable cutMinEta{"cutMinEta", -0.8f, {"Global track cut"}}; + Configurable cutMaxEta{"cutMaxEta", 0.8f, {"Global track cut"}}; + Configurable cutMaxDCAz{"cutMaxDCAz", 2.f, {"Global track cut"}}; + Configurable cutMaxDCAxy{"cutMaxDCAxy", 1e10f, {"Global track cut"}}; + Configurable applyPtDependentDCAxy{"applyPtDependentDCAxy", false, {"Global track cut"}}; + Configurable cutHasITS{"cutHasITS", true, {"Global track cut"}}; + Configurable cutMinITSnCls{"cutMinITSnCls", 1, {"Global track cut"}}; + Configurable cutMaxITSchi2{"cutMaxITSchi2", 36.f, {"Global track cut"}}; + Configurable cutITShitsRule{"cutITShitsRule", 0, {"Global track cut"}}; + Configurable cutHasTPC{"cutHasTPC", true, {"Global track cut"}}; + Configurable cutMinTPCnCls{"cutMinTPCnCls", 1, {"Global track cut"}}; + Configurable cutMinTPCnClsXrows{"cutMinTPCnClsXrows", 70, {"Global track cut"}}; + Configurable cutMinTPCnClsXrowsOverNcls{"cutMinTPCnClsXrowsOverNcls", 0.8f, {"Global track cut"}}; + Configurable cutMaxTPCchi2{"cutMaxTPCchi2", 4.f, {"Global track cut"}}; + Configurable cutGoodITSTPCmatching{"cutGoodITSTPCmatching", true, {"Global track cut"}}; + Configurable cutMaxTOFchi2{"cutMaxTOFchi2", 3.f, {"Global track cut"}}; + } cutGlobalTrack; + + struct : ConfigurableGroup { + Configurable useThresholdsPID{"useThresholdsPID", false, {"Switch off smaller-sigma-wins pidZ."}}; + Configurable applyTauEventSelection{"applyTauEventSelection", true, {"Select tau event."}}; + Configurable cutOppositeCharge{"cutOppositeCharge", true, {"Tracks have opposite charge."}}; + Configurable cutSameCharge{"cutSameCharge", false, {"Tracks have same charge."}}; + Configurable cutMaxAcoplanarity{"cutMaxAcoplanarity", 4 * o2::constants::math::PI / 5, {"Opening angle of the tracks. What is more goes away."}}; + Configurable cutMinAcoplanarity{"cutMinAcoplanarity", 0 * o2::constants::math::PI / 5, {"Opening angle of the tracks. What is less goes away."}}; + Configurable cutElectronHasTOF{"cutElectronHasTOF", true, {"Electron is required to hit TOF."}}; + Configurable cutGoodElectron{"cutGoodElectron", true, {"Select good electron."}}; + Configurable cutOutRho{"cutOutRho", false, {"Cut out rho mass under two tracks are pions hypothesis"}}; + Configurable cutOnRho{"cutOnRho", false, {"Cut on rho mass under two tracks are pions hypothesis"}}; + Configurable cutMinRhoMass{"cutMinRhoMass", 0.6, {"Lower limit on the rho mass region for cut"}}; + Configurable cutMaxRhoMass{"cutMaxRhoMass", 0.95, {"Higher limit on the rho mass region for cut"}}; + Configurable cutMinElectronNsigmaEl{"cutMinElectronNsigmaEl", 2.0, {"Good el hypo in. Upper n sigma cut on el hypo of selected electron. What is more goes away."}}; + Configurable cutMaxElectronNsigmaEl{"cutMaxElectronNsigmaEl", -1.0, {"Good el hypo in. Lower n sigma cut on el hypo of selected electron. What is less goes away."}}; + Configurable cutMinElectronNsigmaPi{"cutMinElectronNsigmaPi", -4.0, {"Good pi hypo out. Lower n sigma cut on pi hypo of selected electron. What is more till upper cut goes away."}}; + Configurable cutMaxElectronNsigmaPi{"cutMaxElectronNsigmaPi", 4.0, {"Good pi hypo out. Upper n sigma cut on pi hypo of selected electron. What is less till lower cut goes away."}}; + Configurable cutMinElectronNsigmaKa{"cutMinElectronNsigmaKa", -4.0, {"Good Ka hypo out. Lower n sigma cut on Ka hypo of selected electron. What is more till upper cut goes away."}}; + Configurable cutMaxElectronNsigmaKa{"cutMaxElectronNsigmaKa", 4.0, {"Good Ka hypo out. Upper n sigma cut on Ka hypo of selected electron. What is less till lower cut goes away."}}; + Configurable cutMinElectronNsigmaPr{"cutMinElectronNsigmaPr", -4.0, {"Good Pr hypo out. Lower n sigma cut on Pr hypo of selected electron. What is more till upper cut goes away."}}; + Configurable cutMaxElectronNsigmaPr{"cutMaxElectronNsigmaPr", 4.0, {"Good Pr hypo out. Upper n sigma cut on Pr hypo of selected electron. What is less till lower cut goes away."}}; + Configurable cutMinElectronTofNsigmaEl{"cutMinElectronTofNsigmaEl", 3.0, {"Good el TOF hypo in. Upper n sigma cut on el hypo of selected electron. What is more goes away."}}; + Configurable cutMaxElectronTofNsigmaEl{"cutMaxElectronTofNsigmaEl", -3.0, {"Good el TOF hypo in. Lower n sigma cut on el hypo of selected electron. What is less goes away."}}; + Configurable cutMinElectronTofNsigmaKa{"cutMinElectronTofNsigmaKa", -4.0, {"Good Ka TOF hypo out. Lower n sigma cut on Ka TOF hypo of selected electron. What is more till upper cut goes away."}}; + Configurable cutMaxElectronTofNsigmaKa{"cutMaxElectronTofNsigmaKa", 4.0, {"Good Ka TOF hypo out. Upper n sigma cut on Ka TOF hypo of selected electron. What is less till lower cut goes away."}}; + Configurable cutPionHasTOF{"cutPionHasTOF", true, {"Pion is required to hit TOF."}}; + Configurable cutGoodMupion{"cutGoodMupion", true, {"Select good muon/pion."}}; + Configurable cutMinPionNsigmaPi{"cutMinPionNsigmaPi", 4.0, {"Good pi hypo in. Upper n sigma cut on pi hypo of selected electron. What is more goes away."}}; + Configurable cutMaxPionNsigmaPi{"cutMaxPionNsigmaPi", -4.0, {"Good pi hypo in. Lower n sigma cut on pi hypo of selected electron. What is less goes away."}}; + Configurable cutMinPionNsigmaKa{"cutMinPionNsigmaKa", -4.0, {"Good Ka hypo out. Lower n sigma cut on Ka hypo of selected electron. What is more till upper cut goes away."}}; + Configurable cutMaxPionNsigmaKa{"cutMaxPionNsigmaKa", 4.0, {"Good Ka hypo out. Upper n sigma cut on Ka hypo of selected electron. What is less till lower cut goes away."}}; + Configurable cutMinPionTofNsigmaPi{"cutMinPionTofNsigmaPi", 4.0, {"Good pi TOF hypo in. Upper n sigma cut on pi hypo of selected electron. What is more goes away."}}; + Configurable cutMaxPionTofNsigmaPi{"cutMaxPionTofNsigmaPi", -4.0, {"Good pi TOF hypo in. Lower n sigma cut on pi hypo of selected electron. What is less goes away."}}; + Configurable cutElectronPt{"cutElectronPt", 0.9, {"Pt, where PiKaon invariant mass histos will split."}}; + } cutTauEvent; + + struct : ConfigurableGroup { + Configurable cutCanUseTrackPID{"cutUseTrackPID", true, {"Apply weak PID check on tracks."}}; + Configurable cutCanNgoodPVtracs{"cutCanNgoodPVtracs", 2, {"How many good PV tracks to select."}}; + Configurable cutCanMinElectronNsigmaEl{"cutCanMinElectronNsigmaEl", 4.0, {"Good el candidate hypo in. Upper n sigma cut on el hypo of selected electron. What is more goes away."}}; + Configurable cutCanMaxElectronNsigmaEl{"cutCanMaxElectronNsigmaEl", -2.0, {"Good el candidate hypo in. Lower n sigma cut on el hypo of selected electron. What is less goes away."}}; + Configurable cutCanElectronHasTOF{"cutCanElectronHasTOF", true, {"Electron candidated is required to hit TOF."}}; + Configurable cutCanMinPionNsigmaEl{"cutCanMinPionNsigmaEl", 5.0, {"Good pi candidate hypo in. Upper n sigma cut on pi hypo of selected electron. What is more goes away."}}; + Configurable cutCanMaxPionNsigmaEl{"cutCanMaxPionNsigmaEl", -5.0, {"Good pi candidate hypo in. Lower n sigma cut on pi hypo of selected electron. What is less goes away."}}; + Configurable cutCanMinMuonNsigmaEl{"cutCanMinMuonNsigmaEl", 5.0, {"Good pi candidate hypo in. Upper n sigma cut on pi hypo of selected electron. What is more goes away."}}; + Configurable cutCanMaxMuonNsigmaEl{"cutCanMaxMuonNsigmaEl", -5.0, {"Good pi candidate hypo in. Lower n sigma cut on pi hypo of selected electron. What is less goes away."}}; + Configurable cutCanMupionHasTOF{"cutCanMupionHasTOF", true, {"Mupion candidate is required to hit TOF."}}; + } cutPreselect; + + struct : ConfigurableGroup { + Configurable usePIDwTOF{"usePIDwTOF", false, {"Determine whether also TOF should be used in testPIDhypothesis"}}; + Configurable useScutTOFinTPC{"useScutTOFinTPC", true, {"Determine whether cut on TOF n sigma should be used after TPC-based decision in testPIDhypothesis"}}; + Configurable cutSiTPC{"cutSiTPC", 35.f, {"n sigma TPC cut on all particles in absolut values for testPIDhypothesis"}}; + Configurable cutSiTOF{"cutSiTOF", 35.f, {"n sigma TOF cut on all particles in absolut values for testPIDhypothesis"}}; + } cutPID; + + struct : ConfigurableGroup { + ConfigurableAxis zzAxisNtracks{"zzAxisNtracks", {30, -0.5, 29.5}, "Number of tracks in collision"}; + ConfigurableAxis zzAxisNparticles{"zzAxisNparticles", {100, -0.5, 99.5}, "Number of particles in collision"}; + ConfigurableAxis zzAxisZvtx{"zzAxisZvtx", {40, -20., 20.}, "Z-vertex position (cm)"}; + ConfigurableAxis zzAxisInvMass{"zzAxisInvMass", {400, 1., 5.}, "Invariant mass (GeV/c^{2})"}; + ConfigurableAxis zzAxisInvMassWide{"zzAxisInvMassWide", {1000, 0., 10.}, "Invariant mass (GeV/c^{2}), wider range"}; + ConfigurableAxis zzAxisMom{"zzAxisMom", {400, 0., 2.}, "Momentum (GeV/c)"}; + ConfigurableAxis zzAxisMomWide{"zzAxisMomWide", {1000, 0., 10.}, "Momentum (GeV/c), wider range"}; + ConfigurableAxis zzAxisMomSigned{"zzAxisMomSigned", {800, -2., 2.}, "Signed momentum (GeV/c)"}; + ConfigurableAxis zzAxisPt{"zzAxisPt", {400, 0., 2.}, "Transversal momentum (GeV/c)"}; + ConfigurableAxis zzAxisPhi{"zzAxisPhi", {64, -o2::constants::math::TwoPI, o2::constants::math::TwoPI}, "Azimuthal angle (a.y.)"}; + ConfigurableAxis zzAxisModPhi{"zzAxisModPhi", {400, 0., .4}, "Track fmod(#phi,#pi/9)"}; + ConfigurableAxis zzAxisEta{"zzAxisEta", {50, -1.2, 1.2}, "Pseudorapidity (a.u.)"}; + ConfigurableAxis zzAxisRap{"zzAxisRap", {50, -1.2, 1.2}, "Rapidity (a.u.)"}; + ConfigurableAxis zzAxisFraction{"zzAxisFraction", {500, 0., 1.}, "Fraction (-)"}; + ConfigurableAxis zzAxisMirrorFraction{"zzAxisMirrorFraction", {500, -1., 1.}, "Fraction (-)"}; + ConfigurableAxis zzAxisAcoplanarity{"zzAxisAcoplanarity", {32, 0.0, o2::constants::math::PI}, "Acoplanarity (rad)"}; + ConfigurableAxis zzAxisCollinearity{"zzAxisCollinearity", {200, 0, 20}, "Collinearity (-)"}; + ConfigurableAxis zzAxisTPCdEdx{"zzAxisTPCdEdx", {2000, 0., 200.}, "TPC dE/dx (a.u.)"}; + ConfigurableAxis zzAxisTOFsignal{"zzAxisTOFsignal", {2500, -10000., 40000.}, "TOF signal (a.u.)"}; + ConfigurableAxis zzAxisNsigma{"zzAxisNsigma", {200, -10., 10.}, "n sigma"}; + ConfigurableAxis zzAxisDCA{"zzAxisDCA", {100, -0.5, 0.5}, "DCA (cm)"}; + ConfigurableAxis zzAxisAvgITSclsSizes{"zzAxisAvgITSclsSizes", {500, 0., 10.}, "ITS average cluster size"}; + ConfigurableAxis zzAxisITSnCls{"zzAxisITSnCls", {8, -0.5, 7.5}, "ITS n clusters"}; + ConfigurableAxis zzAxisITSchi2{"zzAxisITSchi2", {100, 0, 50}, "UTS chi2"}; + ConfigurableAxis zzAxisTPCnCls{"zzAxisTPCnCls", {165, -0.5, 164.5}, "TPC n clusters"}; + ConfigurableAxis zzAxisTPCxRwsFrac{"zzAxisTPCxRwsFrac", {200, 0.0, 2.0}, "TPC fraction of crossed raws"}; + ConfigurableAxis zzAxisTPCchi2{"zzAxisTPCchi2", {100, 0, 10}, "TPC chi2"}; + ConfigurableAxis zzAxisFITtime{"zzAxisFITtime", {201, -40.5, 40.5}, "FIT time in ns"}; + ConfigurableAxis zzAxisFITamplitude{"zzAxisFITamplitude", {1000, 0., 1000.}, "FIT amplitude"}; + + AxisSpec zzAxisChannels{CH_ENUM_COUNTER, -0.5, +CH_ENUM_COUNTER - 0.5, "Channels (-)"}; + AxisSpec zzAxisSelections{40, -0.5, 39.5, "Selections (-)"}; + + } confAxis; + + using FullUDTracks = soa::Join; + using FullUDCollisions = soa::Join; + using FullUDCollision = FullUDCollisions::iterator; + using FullSGUDCollisions = soa::Join; + using FullSGUDCollision = FullSGUDCollisions::iterator; + using FullMCUDTracks = soa::Join; + using FullMCUDCollisions = soa::Join; + using FullMCUDCollision = FullMCUDCollisions::iterator; + using FullMCSGUDCollisions = soa::Join; + using FullMCSGUDCollision = FullMCSGUDCollisions::iterator; + + Preslice perCollision = aod::udtrack::udCollisionId; + Preslice perCollisionMC = aod::udtrack::udCollisionId; + + // init + void init(InitContext&) + { + if (verboseInfo) + printMediumMessage("INIT METHOD"); + + mySetITShitsRule(cutGlobalTrack.cutITShitsRule); + + if (doMainHistos) { + histos.add("Events/hCountCollisions", ";;Number of analysed collision (-)", HistType::kTH1D, {{1, 0.5, 1.5}}); + histos.add("Events/UDtableGapSide", ";GapSide value from UD table (-);Number of events (-)", HistType::kTH1D, {{4, -1.5, 2.5}}); + histos.add("Events/TrueGapSideDiffToTableValue", ";Difference trueGapSide from SGselector and gapSide from UD table (-);Number of events (-)", HistType::kTH1D, {{7, -3.5, 3.5}}); + histos.add("Events/hNreconstructedTracks", ";Number of tracks in a collision (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisNtracks}); + histos.add("Events/hNreconstructedPVGT", ";Number of good track particles from primary vertex in a collision (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisNtracks}); + histos.add("Events/hNreconstructedNotPVGT", ";Number of good track particles from NOT primary vertex in a collision (-);Number of events (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisNtracks}); + histos.add("Events/hNreconstructedPVGTelectrons", ";Number of good track identified electrons from primary vertex in a collision (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisNtracks}); + histos.add("Events/hNreconstructedPVGTmuons", ";Number of good track identified muons from primary vertex in a collision (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisNtracks}); + histos.add("Events/hNreconstructedPVGTpions", ";Number of good track identified pions from primary vertex in a collision (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisNtracks}); + histos.add("Events/hNreconstructedPVGTothers", ";Number of good track NOT identified electron/muon/pion particles from primary vertex in a collision (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisNtracks}); + histos.add("Events/hChannels", ";Channels (-);Number of events (-)", HistType::kTH1D, {{confAxis.zzAxisChannels}}); + histos.add("Events/FIT/hAmplitudeFT0A", ";Amplitude (-);Number of events (-)", HistType::kTH1F, {{confAxis.zzAxisFITamplitude}}); + histos.add("Events/FIT/hAmplitudeFT0C", ";Amplitude (-);Number of events (-)", HistType::kTH1F, {{confAxis.zzAxisFITamplitude}}); + histos.add("Events/FIT/hAmplitudeFDDA", ";Amplitude (-);Number of events (-)", HistType::kTH1F, {{confAxis.zzAxisFITamplitude}}); + histos.add("Events/FIT/hAmplitudeFDDC", ";Amplitude (-);Number of events (-)", HistType::kTH1F, {{confAxis.zzAxisFITamplitude}}); + histos.add("Events/FIT/hAmplitudeFV0A", ";Amplitude (-);Number of events (-)", HistType::kTH1F, {{confAxis.zzAxisFITamplitude}}); + histos.add("Events/FIT/hTimeFT0A", ";Time (ns);Number of events (-)", HistType::kTH1F, {{confAxis.zzAxisFITtime}}); + histos.add("Events/FIT/hTimeFT0C", ";Time (ns);Number of events (-)", HistType::kTH1F, {{confAxis.zzAxisFITtime}}); + histos.add("Events/FIT/hTimeFDDA", ";Time (ns);Number of events (-)", HistType::kTH1F, {{confAxis.zzAxisFITtime}}); + histos.add("Events/FIT/hTimeFDDC", ";Time (ns);Number of events (-)", HistType::kTH1F, {{confAxis.zzAxisFITtime}}); + histos.add("Events/FIT/hTimeFV0A", ";Time (ns);Number of events (-)", HistType::kTH1F, {{confAxis.zzAxisFITtime}}); + histos.add("Events/FIT/hTimeFT0AvsFT0C", ";FT0A time (ns);FT0C time (ns)", HistType::kTH2F, {{confAxis.zzAxisFITtime}, {confAxis.zzAxisFITtime}}); + histos.add("Events/FIT/hTimeFT0CvsFDDA", ";FT0C time (ns);FDDA time (ns)", HistType::kTH2F, {{confAxis.zzAxisFITtime}, {confAxis.zzAxisFITtime}}); + histos.add("Events/FIT/hTimeFDDAvsFDDC", ";FDDA time (ns);FDDC time (ns)", HistType::kTH2F, {{confAxis.zzAxisFITtime}, {confAxis.zzAxisFITtime}}); + histos.add("Events/FIT/hTimeFDDCvsFV0A", ";FDDC time (ns);FV0A time (ns)", HistType::kTH2F, {{confAxis.zzAxisFITtime}, {confAxis.zzAxisFITtime}}); + histos.add("Events/FIT/hTimeFV0AvsFT0A", ";FV0A time (ns);FT0A time (ns)", HistType::kTH2F, {{confAxis.zzAxisFITtime}, {confAxis.zzAxisFITtime}}); + + histos.add("Tracks/raw/hTrackZ", ";Track z-vertex (cm);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisZvtx}); + histos.add("Tracks/raw/hTrackP", ";Track #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMom}); + histos.add("Tracks/raw/hTrackPt", ";Track #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPt}); + histos.add("Tracks/raw/hTrackPhi", ";Track #phi (rad);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPhi}); + histos.add("Tracks/raw/hTrackPtvsModPhi", ";Track #it{p_{T}} (GeV/c);Track fmod(#phi,#pi/9)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisModPhi}); + histos.add("Tracks/raw/hTrackPtvsModPhiTOF", ";Track #it{p_{T}} (GeV/c);Track fmod(#phi,#pi/9)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisModPhi}); + histos.add("Tracks/raw/hTrackEta", ";Track #eta (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisEta}); + histos.add("Tracks/raw/hTrackDcaXY", ";Track DCA_{XY} (cm);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisDCA}); + histos.add("Tracks/raw/hTrackPtvsDcaXY", ";Track #it{p_{T}} (GeV/c);Track DCA_{XY} (cm)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisDCA}); + histos.add("Tracks/raw/hTrackDcaZ", ";Track DCA_{Z} (cm);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisDCA}); + histos.add("Tracks/raw/ITS/itsNCls", "number of found ITS clusters;# clusters ITS", kTH1D, {confAxis.zzAxisITSnCls}); + histos.add("Tracks/raw/ITS/itsChi2NCl", "chi2 per ITS cluster;chi2 / cluster ITS", kTH1D, {confAxis.zzAxisITSchi2}); + histos.add("Tracks/raw/TPC/tpcNClsFindable", "number of findable TPC clusters;# findable clusters TPC", kTH1D, {confAxis.zzAxisTPCnCls}); + histos.add("Tracks/raw/TPC/tpcNClsFound", "number of found TPC clusters;# clusters TPC", kTH1D, {confAxis.zzAxisTPCnCls}); + histos.add("Tracks/raw/TPC/tpcCrossedRows", "number of crossed TPC rows;# crossed rows TPC", kTH1D, {confAxis.zzAxisTPCnCls}); + histos.add("Tracks/raw/TPC/tpcCrossedRowsOverFindableCls", "crossed TPC rows over findable clusters;crossed rows / findable clusters TPC", kTH1D, {confAxis.zzAxisTPCxRwsFrac}); + histos.add("Tracks/raw/TPC/tpcChi2NCl", "chi2 per cluster in TPC;chi2 / cluster TPC", kTH1D, {confAxis.zzAxisTPCchi2}); + histos.add("Tracks/GoodTrack/hTrackZ", ";Track z-vertex (cm);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisZvtx}); + histos.add("Tracks/GoodTrack/hTrackP", ";Track #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMom}); + histos.add("Tracks/GoodTrack/hTrackPt", ";Track #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPt}); + histos.add("Tracks/GoodTrack/hTrackPhi", ";Track #phi (rad);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPhi}); + histos.add("Tracks/GoodTrack/hTrackPtvsModPhi", ";Track #it{p_{T}} (GeV/c);Track fmod(#phi,#pi/9)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisModPhi}); + histos.add("Tracks/GoodTrack/hTrackPtvsModPhiTOF", ";Track #it{p_{T}} (GeV/c);Track fmod(#phi,#pi/9)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisModPhi}); + histos.add("Tracks/GoodTrack/hTrackEta", ";Track #eta (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisEta}); + histos.add("Tracks/GoodTrack/hTrackDcaXY", ";Track DCA_{XY} (cm);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisDCA}); + histos.add("Tracks/GoodTrack/hTrackPtvsDcaXY", ";Track #it{p_{T}} (GeV/c);Track DCA_{XY} (cm)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisDCA}); + histos.add("Tracks/GoodTrack/hTrackDcaZ", ";Track DCA_{Z} (cm);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisDCA}); + histos.add("Tracks/GoodTrack/ITS/itsNCls", "number of found ITS clusters;# clusters ITS", kTH1D, {confAxis.zzAxisITSnCls}); + histos.add("Tracks/GoodTrack/ITS/itsChi2NCl", "chi2 per ITS cluster;chi2 / cluster ITS", kTH1D, {confAxis.zzAxisITSchi2}); + histos.add("Tracks/GoodTrack/TPC/tpcNClsFindable", "number of findable TPC clusters;# findable clusters TPC", kTH1D, {confAxis.zzAxisTPCnCls}); + histos.add("Tracks/GoodTrack/TPC/tpcNClsFound", "number of found TPC clusters;# clusters TPC", kTH1D, {confAxis.zzAxisTPCnCls}); + histos.add("Tracks/GoodTrack/TPC/tpcCrossedRows", "number of crossed TPC rows;# crossed rows TPC", kTH1D, {confAxis.zzAxisTPCnCls}); + histos.add("Tracks/GoodTrack/TPC/tpcCrossedRowsOverFindableCls", "crossed TPC rows over findable clusters;crossed rows / findable clusters TPC", kTH1D, {confAxis.zzAxisTPCxRwsFrac}); + histos.add("Tracks/GoodTrack/TPC/tpcChi2NCl", "chi2 per cluster in TPC;chi2 / cluster TPC", kTH1D, {confAxis.zzAxisTPCchi2}); + } + + if (doPIDhistos) { + histos.add("Tracks/raw/PID/hTPCsignalVsZ", "All tracks;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisZvtx, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/raw/PID/hTPCsignalVsP", "All tracks;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/raw/PID/hTPCsignalVsPt", "All tracks;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/raw/PID/hTPCsignalVsEta", "All tracks;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisEta, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/raw/PID/hTPCsignalVsPhi", "All tracks;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPhi, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/raw/PID/hTOFsignalVsP", "All tracks;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTOFsignal}); + histos.add("Tracks/raw/PID/hTPCnSigmaElVsP", ";Track #it{p} (GeV/c);n#sigma^{e}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("Tracks/raw/PID/hTPCnSigmaMuVsP", ";Track #it{p} (GeV/c);n#sigma^{#mu}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("Tracks/raw/PID/hTPCnSigmaPiVsP", ";Track #it{p} (GeV/c);n#sigma^{#pi}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("Tracks/raw/PID/hTPCnSigmaKaVsP", ";Track #it{p} (GeV/c);n#sigma^{K}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("Tracks/raw/PID/hTPCnSigmaPrVsP", ";Track #it{p} (GeV/c);n#sigma^{p}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("Tracks/raw/PID/PosCharge/hTPCsignalVsZ", "Positively charged tracks;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisZvtx, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/raw/PID/PosCharge/hTPCsignalVsP", "Positively charged tracks;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/raw/PID/PosCharge/hTPCsignalVsPt", "Positively charged tracks;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/raw/PID/PosCharge/hTPCsignalVsEta", "Positively charged tracks;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisEta, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/raw/PID/PosCharge/hTPCsignalVsPhi", "Positively charged tracks;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPhi, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/raw/PID/PosCharge/hTOFsignalVsP", "Positively charged tracks;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTOFsignal}); + histos.add("Tracks/raw/PID/NegCharge/hTPCsignalVsZ", "Negatively charged tracks;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisZvtx, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/raw/PID/NegCharge/hTPCsignalVsP", "Negatively charged tracks;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/raw/PID/NegCharge/hTPCsignalVsPt", "Negatively charged tracks;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/raw/PID/NegCharge/hTPCsignalVsEta", "Negatively charged tracks;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisEta, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/raw/PID/NegCharge/hTPCsignalVsPhi", "Negatively charged tracks;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPhi, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/raw/PID/NegCharge/hTOFsignalVsP", "Negatively charged tracks;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTOFsignal}); + histos.add("Tracks/GoodTrack/PID/hTPCsignalVsZ", "All good tracks;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisZvtx, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/hTPCsignalVsP", "All good tracks;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/hTPCsignalVsPt", "All good tracks;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/hTPCsignalVsEta", "All good tracks;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisEta, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/hTPCsignalVsPhi", "All good tracks;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPhi, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/hTPCnSigmaElVsP", ";Track #it{p} (GeV/c);n#sigma^{e}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/hTPCnSigmaMuVsP", ";Track #it{p} (GeV/c);n#sigma^{#mu}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/hTPCnSigmaPiVsP", ";Track #it{p} (GeV/c);n#sigma^{#pi}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/hTPCnSigmaKaVsP", ";Track #it{p} (GeV/c);n#sigma^{K}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/hTPCnSigmaPrVsP", ";Track #it{p} (GeV/c);n#sigma^{p}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/hTOFsignalVsP", "All good tracks;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTOFsignal}); + histos.add("Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsZ", "Positively charged good tracks;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisZvtx, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsP", "Positively charged good tracks;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsPt", "Positively charged good tracks;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsEta", "Positively charged good tracks;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisEta, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsPhi", "Positively charged good tracks;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPhi, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/PosCharge/hTOFsignalVsP", "Positively charged good tracks;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTOFsignal}); + histos.add("Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsZ", "Negatively charged good tracks;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisZvtx, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsP", "Negatively charged good tracks;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsPt", "Negatively charged good tracks;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsEta", "Negatively charged good tracks;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisEta, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsPhi", "Negatively charged good tracks;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPhi, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/NegCharge/hTOFsignalVsP", "Negatively charged good tracks;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTOFsignal}); + histos.add("Tracks/GoodTrack/PID/Electron/hTPCsignalVsZ", "Identified electrons;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisZvtx, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Electron/hTPCsignalVsP", "Identified electrons;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Electron/hTPCsignalVsPt", "Identified electrons;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Electron/hTPCsignalVsEta", "Identified electrons;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisEta, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Electron/hTPCsignalVsPhi", "Identified electrons;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPhi, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Electron/hTOFsignalVsP", "Identified electrons;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTOFsignal}); + histos.add("Tracks/GoodTrack/PID/Electron/hTPCnSigmaVsP", "Identified electrons;Track #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Electron/hTOFnSigmaVsP", "Identified electrons;Track #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Electron/hTPCnSigmaElVsMu", "Identified electrons;n#sigma^{#it{e}}_{TPC} (arb. units);n#sigma^{#mu}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Electron/hTOFnSigmaElVsMu", "Identified electrons;n#sigma^{#it{e}}_{TOF} (arb. units);n#sigma^{#mu}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Electron/hTPCnSigmaElVsPi", "Identified electrons;n#sigma^{#it{e}}_{TPC} (arb. units);n#sigma^{#pi}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Electron/hTOFnSigmaElVsPi", "Identified electrons;n#sigma^{#it{e}}_{TOF} (arb. units);n#sigma^{#pi}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Electron/hTPCnSigmaElVsKa", "Identified electrons;n#sigma^{#it{e}}_{TPC} (arb. units);n#sigma^{#it{K}}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Electron/hTOFnSigmaElVsKa", "Identified electrons;n#sigma^{#it{e}}_{TOF} (arb. units);n#sigma^{#it{K}}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Electron/hTPCnSigmaElVsPr", "Identified electrons;n#sigma^{#it{e}}_{TPC} (arb. units);n#sigma^{p}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Electron/hTOFnSigmaElVsPr", "Identified electrons;n#sigma^{#it{e}}_{TOF} (arb. units);n#sigma^{p}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Muon/hTPCsignalVsZ", "Identified muons;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisZvtx, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Muon/hTPCsignalVsP", "Identified muons;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Muon/hTPCsignalVsPt", "Identified muons;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Muon/hTPCsignalVsEta", "Identified muons;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisEta, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Muon/hTPCsignalVsPhi", "Identified muons;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPhi, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Muon/hTOFsignalVsP", "Identified muons;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTOFsignal}); + histos.add("Tracks/GoodTrack/PID/Muon/hTPCnSigmaVsP", "Identified muons;Track #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Muon/hTOFnSigmaVsP", "Identified muons;Track #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Muon/hTPCnSigmaMuVsEl", "Identified muons;n#sigma^{#mu}_{TPC} (arb. units);n#sigma^{#it{e}}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Muon/hTOFnSigmaMuVsEl", "Identified muons;n#sigma^{#mu}_{TOF} (arb. units);n#sigma^{#it{e}}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Muon/hTPCnSigmaMuVsPi", "Identified muons;n#sigma^{#mu}_{TPC} (arb. units);n#sigma^{#pi}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Muon/hTOFnSigmaMuVsPi", "Identified muons;n#sigma^{#mu}_{TOF} (arb. units);n#sigma^{#pi}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Muon/hTPCnSigmaMuVsKa", "Identified muons;n#sigma^{#mu}_{TPC} (arb. units);n#sigma^{#it{K}}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Muon/hTOFnSigmaMuVsKa", "Identified muons;n#sigma^{#mu}_{TOF} (arb. units);n#sigma^{#it{K}}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Muon/hTPCnSigmaMuVsPr", "Identified muons;n#sigma^{#mu}_{TPC} (arb. units);n#sigma^{p}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Muon/hTOFnSigmaMuVsPr", "Identified muons;n#sigma^{#mu}_{TOF} (arb. units);n#sigma^{p}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Pion/hTPCsignalVsZ", "Identified pions;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisZvtx, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Pion/hTPCsignalVsP", "Identified pions;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Pion/hTPCsignalVsPt", "Identified pions;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Pion/hTPCsignalVsEta", "Identified pions;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisEta, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Pion/hTPCsignalVsPhi", "Identified pions;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPhi, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Pion/hTOFsignalVsP", "Identified pions;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTOFsignal}); + histos.add("Tracks/GoodTrack/PID/Pion/hTPCnSigmaVsP", "Identified pions;Track #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Pion/hTOFnSigmaVsP", "Identified pions;Track #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Pion/hTPCnSigmaPiVsEl", "Identified pions;n#sigma^{#pi}_{TPC} (arb. units);n#sigma^{#it{e}}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Pion/hTOFnSigmaPiVsEl", "Identified pions;n#sigma^{#pi}_{TOF} (arb. units);n#sigma^{#it{e}}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Pion/hTPCnSigmaPiVsMu", "Identified pions;n#sigma^{#pi}_{TPC} (arb. units);n#sigma^{#mu}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Pion/hTOFnSigmaPiVsMu", "Identified pions;n#sigma^{#pi}_{TOF} (arb. units);n#sigma^{#mu}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Pion/hTPCnSigmaPiVsKa", "Identified pions;n#sigma^{#pi}_{TPC} (arb. units);n#sigma^{#it{K}}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Pion/hTOFnSigmaPiVsKa", "Identified pions;n#sigma^{#pi}_{TOF} (arb. units);n#sigma^{#it{K}}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Pion/hTPCnSigmaPiVsPr", "Identified pions;n#sigma^{#pi}_{TPC} (arb. units);n#sigma^{p}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Pion/hTOFnSigmaPiVsPr", "Identified pions;n#sigma^{#pi}_{TOF} (arb. units);n#sigma^{p}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("Tracks/GoodTrack/PID/Others/hTPCsignalVsZ", "Identified NOT electron/Muon/Pion;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisZvtx, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Others/hTPCsignalVsP", "Identified NOT electron/Muon/Pion;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Others/hTPCsignalVsPt", "Identified NOT electron/Muon/Pion;Track #it{p_{#rm T}} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Others/hTPCsignalVsEta", "Identified NOT electron/Muon/Pion;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisEta, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Others/hTPCsignalVsPhi", "Identified NOT electron/Muon/Pion;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisPhi, confAxis.zzAxisTPCdEdx}); + histos.add("Tracks/GoodTrack/PID/Others/hTOFsignalVsP", "Identified NOT electron/Muon/Pion;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTOFsignal}); + } + + if (doTwoTracks) { + histos.add("EventTwoTracks/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMass}); + histos.add("EventTwoTracks/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMassWide}); + histos.add("EventTwoTracks/hInvariantMassWideNoMothers", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMassWide}); + histos.add("EventTwoTracks/hInvariantMassWideAllPionMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMassWide}); + histos.add("EventTwoTracks/hInvariantMassWideAllPionMassPtCut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMassWide}); + histos.add("EventTwoTracks/hInvariantMassWideAllPionMassTOF", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMassWide}); + histos.add("EventTwoTracks/hAcoplanarity", ";#Delta#phi (rad);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisAcoplanarity}); + histos.add("EventTwoTracks/hCollinearity", ";#DeltaR (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisCollinearity}); + histos.add("EventTwoTracks/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMom}); + histos.add("EventTwoTracks/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMomWide}); + histos.add("EventTwoTracks/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPt}); + histos.add("EventTwoTracks/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPhi}); + histos.add("EventTwoTracks/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisRap}); + histos.add("EventTwoTracks/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisInvMassWide, confAxis.zzAxisPt}); + histos.add("EventTwoTracks/hDaughtersEnergyAsymmetry", ";(E_{electron} - E_{#mu/#pi}) / (E_{electron} + E_{#mu/#pi});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMirrorFraction}); + histos.add("EventTwoTracks/hDaughtersMomentaAsymmetry", ";(#it{p}_{electron} - #it{p}_{#mu/#pi}) / (#it{p}_{electron} + #it{p}_{#mu/#pi});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMirrorFraction}); + histos.add("EventTwoTracks/hDaughtersPtAsymmetry", ";(#it{p_{T}}_{electron} - #it{p_{T}}_{#mu/#pi}) / (#it{p_{T}}_{electron} + #it{p_{T}}_{#mu/#pi});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMirrorFraction}); + histos.add("EventTwoTracks/hDaughtersP", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisMom}); + histos.add("EventTwoTracks/hDaughtersPwide", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisMomWide, confAxis.zzAxisMomWide}); + histos.add("EventTwoTracks/hDaughtersPt", ";Daughter 1 #it{p_{T}} (GeV/c);Daughter 2 #it{p_{T}} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisPt}); + histos.add("EventTwoTracks/hDaughtersPhi", ";Daughter 1 #phi (rad);Daughter 2 #phi (rad)", HistType::kTH2D, {confAxis.zzAxisPhi, confAxis.zzAxisPhi}); + histos.add("EventTwoTracks/hDaughtersRapidity", ";Daughter 1 #it{y} (-);Daughter 2 #it{y} (-)", HistType::kTH2D, {confAxis.zzAxisRap, confAxis.zzAxisRap}); + histos.add("EventTwoTracks/hDaughtersEnergyFractions", ";E_{daughter 1} / E_{tot} (-);E_{daughter 1} / E_{tot} (-)", HistType::kTH2D, {confAxis.zzAxisFraction, confAxis.zzAxisFraction}); + histos.add("EventTwoTracks/hDaughtersPvsITSclusterSize", ";Average ITS cluster size;Daughter #it{p} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisAvgITSclsSizes, confAxis.zzAxisMomSigned}); + histos.add("EventTwoTracks/hDaughtersPvsITSclusterSizeXcos", ";Average ITS cluster size x cos(#lambda);Daughter #it{p} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisAvgITSclsSizes, confAxis.zzAxisMomSigned}); + histos.add("EventTwoTracks/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("EventTwoTracks/PID/hTOFsignalVsP", ";Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTOFsignal}); + histos.add("EventTwoTracks/PID/hTPCnSigmaElVsP", ";Track #it{p} (GeV/c);n#sigma^{e}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/PID/hTPCnSigmaMuVsP", ";Track #it{p} (GeV/c);n#sigma^{#mu}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/PID/hTPCnSigmaPiVsP", ";Track #it{p} (GeV/c);n#sigma^{#pi}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/PID/hTPCnSigmaKaVsP", ";Track #it{p} (GeV/c);n#sigma^{K}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/PID/hTPCnSigmaPrVsP", ";Track #it{p} (GeV/c);n#sigma^{p}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/PID/NoPID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("EventTwoTracks/PID/NoPID/hTPCnSigmaElVsP", ";Track #it{p} (GeV/c);n#sigma^{e}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/PID/NoPID/hTPCnSigmaMuVsP", ";Track #it{p} (GeV/c);n#sigma^{#mu}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/PID/NoPID/hTPCnSigmaPiVsP", ";Track #it{p} (GeV/c);n#sigma^{#pi}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/PID/NoPID/hTPCnSigmaKaVsP", ";Track #it{p} (GeV/c);n#sigma^{K}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/PID/NoPID/hTPCnSigmaPrVsP", ";Track #it{p} (GeV/c);n#sigma^{p}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + + histos.add("EventTwoTracks/TwoElectrons/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMass}); + histos.add("EventTwoTracks/TwoElectrons/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMassWide}); + histos.add("EventTwoTracks/TwoElectrons/hInvariantMassWidePtCut", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMassWide}); + histos.add("EventTwoTracks/TwoElectrons/hAcoplanarity", ";#Delta#phi (rad);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisAcoplanarity}); + histos.add("EventTwoTracks/TwoElectrons/hCollinearity", ";#DeltaR (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisCollinearity}); + histos.add("EventTwoTracks/TwoElectrons/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMom}); + histos.add("EventTwoTracks/TwoElectrons/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMomWide}); + histos.add("EventTwoTracks/TwoElectrons/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPt}); + histos.add("EventTwoTracks/TwoElectrons/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPhi}); + histos.add("EventTwoTracks/TwoElectrons/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisRap}); + histos.add("EventTwoTracks/TwoElectrons/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisInvMassWide, confAxis.zzAxisPt}); + histos.add("EventTwoTracks/TwoElectrons/hDaughtersP", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisMom}); + histos.add("EventTwoTracks/TwoElectrons/hDaughtersPwide", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisMomWide, confAxis.zzAxisMomWide}); + histos.add("EventTwoTracks/TwoElectrons/hDaughtersPt", ";Daughter 1 #it{p_{T}} (GeV/c);Daughter 2 #it{p_{T}} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisPt}); + histos.add("EventTwoTracks/TwoElectrons/hDaughtersPhi", ";Daughter 1 #phi (rad);Daughter 2 #phi (rad)", HistType::kTH2D, {confAxis.zzAxisPhi, confAxis.zzAxisPhi}); + histos.add("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhi", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisModPhi}); + histos.add("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiTOF", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisModPhi}); + histos.add("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiPtCut", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisModPhi}); + histos.add("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiPtCutTOF", ";Daughter #it{p_{T}} (GeV/c);Daughter fmod(#phi,#pi/9)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisModPhi}); + histos.add("EventTwoTracks/TwoElectrons/hDaughtersRapidity", ";Daughter 1 #it{y} (-);Daughter 2 #it{y} (-)", HistType::kTH2D, {confAxis.zzAxisRap, confAxis.zzAxisRap}); + histos.add("EventTwoTracks/TwoElectrons/hLeadingP", ";Leading #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMom}); + histos.add("EventTwoTracks/TwoElectrons/hLeadingPwide", ";Leading #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMomWide}); + histos.add("EventTwoTracks/TwoElectrons/hLeadingPt", ";Leading #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPt}); + histos.add("EventTwoTracks/TwoElectrons/hLeadingPhi", ";Leading #phi (rad);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPhi}); + histos.add("EventTwoTracks/TwoElectrons/hLeadingRapidity", ";Leading #it{y} (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisRap}); + histos.add("EventTwoTracks/TwoElectrons/hLeadingPvsOtherP", ";Leading #it{p} (GeV/c); Other #it{p} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisMom}); + histos.add("EventTwoTracks/TwoElectrons/hLeadingPwideVsOtherPwide", ";Leading #it{p} (GeV/c); Other #it{p} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisMomWide, confAxis.zzAxisMomWide}); + histos.add("EventTwoTracks/TwoElectrons/hLeadingPtVsOtherPt", ";Leading #it{p_{T}} (GeV/c); Other #it{p_{T}} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisPt}); + histos.add("EventTwoTracks/TwoElectrons/hLeadingPhiVsOtherPhi", ";Leading #phi (rad); Other #phi (rad)", HistType::kTH2D, {confAxis.zzAxisPhi, confAxis.zzAxisPhi}); + histos.add("EventTwoTracks/TwoElectrons/hLeadingRapVsOtherRap", ";Leading #it{y} (-); Other #it{y} (-)", HistType::kTH2D, {confAxis.zzAxisRap, confAxis.zzAxisRap}); + histos.add("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsLP", ";Leading #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsOP", ";Other #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("EventTwoTracks/TwoElectrons/PID/hTOFsignalVsP", ";Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTOFsignal}); + histos.add("EventTwoTracks/TwoElectrons/PID/hTOFsignalVsLP", ";Leading #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTOFsignal}); + histos.add("EventTwoTracks/TwoElectrons/PID/hTOFsignalVsOP", ";Other #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTOFsignal}); + histos.add("EventTwoTracks/TwoElectrons/PID/hTPCnSigmaVsP", ";Track #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/TwoElectrons/PID/hTPCnSigmaVsLP", ";Leading #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/TwoElectrons/PID/hTPCnSigmaVsOP", ";Other #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/TwoElectrons/PID/hTOFnSigmaVsP", ";Track #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/TwoElectrons/PID/hTOFnSigmaVsLP", ";Leading #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/TwoElectrons/PID/hTOFnSigmaVsOP", ";Other #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + + histos.add("EventTwoTracks/ElectronMuPi/hNeventsPtCuts", ";Selection (-);Number of events (-)", HistType::kTH1D, {{20, -0.5, 19.5}}); + histos.add("EventTwoTracks/ElectronMuPi/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMass}); + histos.add("EventTwoTracks/ElectronMuPi/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMassWide}); + histos.add("EventTwoTracks/ElectronMuPi/PionsSelection/hInvariantMass", ";Invariant mass (#pi^{+}#pi^{-}) (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMass}); + histos.add("EventTwoTracks/ElectronMuPi/PionsSelection/hInvariantMassWide", ";Invariant mass (#pi^{+}#pi^{-}) (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMassWide}); + histos.add("EventTwoTracks/ElectronMuPi/KstarSelection/hInvariantMass", ";Invariant mass (K#pi) (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMass}); + histos.add("EventTwoTracks/ElectronMuPi/KstarSelection/hInvariantMassWide", ";Invariant mass (K#pi) (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMassWide}); + histos.add("EventTwoTracks/ElectronMuPi/KstarSelection/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisInvMassWide, confAxis.zzAxisPt}); + histos.add("EventTwoTracks/ElectronMuPi/KstarSelection/hMotherMassVsElectronP", ";Invariant mass (K#pi) (GeV/c^{2});Electron #it{p} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisInvMassWide, confAxis.zzAxisMomWide}); + histos.add("EventTwoTracks/ElectronMuPi/KstarSelection/hIMKvsIMe", ";#pi+K invariant mass (GeV/c^{2});#pi+e invariant mass (GeV/c^{2})", HistType::kTH2D, {confAxis.zzAxisInvMassWide, confAxis.zzAxisInvMassWide}); + histos.add("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutLow/hInvariantMass", ";Invariant mass (K#pi) (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMass}); + histos.add("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutLow/hInvariantMassWide", ";Invariant mass (K#pi) (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMassWide}); + histos.add("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutLow/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisInvMassWide, confAxis.zzAxisPt}); + histos.add("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutLow/hIMKvsIMe", ";#pi+K invariant mass (GeV/c^{2});#pi+e invariant mass (GeV/c^{2})", HistType::kTH2D, {confAxis.zzAxisInvMassWide, confAxis.zzAxisInvMassWide}); + histos.add("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutLow/hElectronPwideVsOtherPwide", ";Electron #it{p} (GeV/c); #mu/#pi #it{p} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisMomWide, confAxis.zzAxisMomWide}); + histos.add("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutHigh/hInvariantMass", ";Invariant mass (K#pi) (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMass}); + histos.add("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutHigh/hInvariantMassWide", ";Invariant mass (K#pi) (GeV/c^{2});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisInvMassWide}); + histos.add("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutHigh/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisInvMassWide, confAxis.zzAxisPt}); + histos.add("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutHigh/hIMKvsIMe", ";#pi+K invariant mass (GeV/c^{2});#pi+e invariant mass (GeV/c^{2})", HistType::kTH2D, {confAxis.zzAxisInvMassWide, confAxis.zzAxisInvMassWide}); + histos.add("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutHigh/hElectronPwideVsOtherPwide", ";Electron #it{p} (GeV/c); #mu/#pi #it{p} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisMomWide, confAxis.zzAxisMomWide}); + histos.add("EventTwoTracks/ElectronMuPi/hAcoplanarity", ";#Delta#phi (rad);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisAcoplanarity}); + histos.add("EventTwoTracks/ElectronMuPi/hCollinearity", ";#DeltaR (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisCollinearity}); + histos.add("EventTwoTracks/ElectronMuPi/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMom}); + histos.add("EventTwoTracks/ElectronMuPi/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMomWide}); + histos.add("EventTwoTracks/ElectronMuPi/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPt}); + histos.add("EventTwoTracks/ElectronMuPi/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPhi}); + histos.add("EventTwoTracks/ElectronMuPi/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisRap}); + histos.add("EventTwoTracks/ElectronMuPi/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisInvMassWide, confAxis.zzAxisPt}); + histos.add("EventTwoTracks/ElectronMuPi/hMotherMassVsElectronP", ";Invariant mass (GeV/c^{2});Electron #it{p} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisInvMassWide, confAxis.zzAxisMomWide}); + histos.add("EventTwoTracks/ElectronMuPi/hMotherMassVsAcoplanarity", ";Invariant mass (GeV/c^{2});#Delta#phi (rad)", HistType::kTH2D, {confAxis.zzAxisInvMassWide, confAxis.zzAxisAcoplanarity}); + histos.add("EventTwoTracks/ElectronMuPi/hElectronPt", ";Electron #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPt}); + histos.add("EventTwoTracks/ElectronMuPi/hElectronPtWide", ";Electron #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMomWide}); + histos.add("EventTwoTracks/ElectronMuPi/hDaughtersEnergyAsymmetry", ";(E_{electron} - E_{#mu/#pi}) / (E_{electron} + E_{#mu/#pi});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMirrorFraction}); + histos.add("EventTwoTracks/ElectronMuPi/hDaughtersMomentaAsymmetry", ";(#it{p}_{electron} - #it{p}_{#mu/#pi}) / (#it{p}_{electron} + #it{p}_{#mu/#pi});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMirrorFraction}); + histos.add("EventTwoTracks/ElectronMuPi/hDaughtersPtAsymmetry", ";(#it{p_{T}}_{electron} - #it{p_{T}}_{#mu/#pi}) / (#it{p_{T}}_{electron} + #it{p_{T}}_{#mu/#pi});Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMirrorFraction}); + histos.add("EventTwoTracks/ElectronMuPi/hDaughtersP", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisMom}); + histos.add("EventTwoTracks/ElectronMuPi/hDaughtersPwide", ";Daughter 1 #it{p} (GeV/c);Daughter 2 #it{p} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisMomWide, confAxis.zzAxisMomWide}); + histos.add("EventTwoTracks/ElectronMuPi/hDaughtersPt", ";Daughter 1 #it{p_{T}} (GeV/c);Daughter 2 #it{p_{T}} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisPt}); + histos.add("EventTwoTracks/ElectronMuPi/hDaughtersPhi", ";Daughter 1 #phi (rad);Daughter 2 #phi (rad)", HistType::kTH2D, {confAxis.zzAxisPhi, confAxis.zzAxisPhi}); + histos.add("EventTwoTracks/ElectronMuPi/hDaughtersRapidity", ";Daughter 1 #it{y} (-);Daughter 2 #it{y} (-)", HistType::kTH2D, {confAxis.zzAxisRap, confAxis.zzAxisRap}); + histos.add("EventTwoTracks/ElectronMuPi/hDaughtersEnergyFractions", ";E_{electron} / E_{tot} (-);E_{#mu/#pi} / E_{tot} (-)", HistType::kTH2D, {confAxis.zzAxisFraction, confAxis.zzAxisFraction}); + histos.add("EventTwoTracks/ElectronMuPi/hElectronPvsOtherP", ";Electron #it{p} (GeV/c); #mu/#pi #it{p} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisMom}); + histos.add("EventTwoTracks/ElectronMuPi/hElectronPwideVsOtherPwide", ";Electron #it{p} (GeV/c); #mu/#pi #it{p} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisMomWide, confAxis.zzAxisMomWide}); + histos.add("EventTwoTracks/ElectronMuPi/hElectronPvsAcoplanarity", ";Electron #it{p} (GeV/c); #Delta#phi (rad)", HistType::kTH2D, {confAxis.zzAxisMomWide, confAxis.zzAxisAcoplanarity}); + histos.add("EventTwoTracks/ElectronMuPi/hOtherPvsAcoplanarity", ";#mu/#pi #it{p} (GeV/c); #Delta#phi (rad)", HistType::kTH2D, {confAxis.zzAxisMomWide, confAxis.zzAxisAcoplanarity}); + histos.add("EventTwoTracks/ElectronMuPi/hElectronPtVsOtherPt", ";Electron #it{p_{T}} (GeV/c); #mu/#pi #it{p_{T}} (GeV/c)", HistType::kTH2D, {confAxis.zzAxisPt, confAxis.zzAxisPt}); + histos.add("EventTwoTracks/ElectronMuPi/hElectronPhiVsOtherPhi", ";Electron #phi (rad); #mu/#pi #phi (rad)", HistType::kTH2D, {confAxis.zzAxisPhi, confAxis.zzAxisPhi}); + histos.add("EventTwoTracks/ElectronMuPi/hElectronRapVsOtherRap", ";Electron #it{y} (-); #mu/#pi #it{y} (-)", HistType::kTH2D, {confAxis.zzAxisRap, confAxis.zzAxisRap}); + + histos.add("EventTwoTracks/ElectronMuPi/PID/mcTruth/nSigmaTPC1", "Paul's way;True electron #it{p} (GeV/c);n#sigma^{e}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/ElectronMuPi/PID/mcTruth/nSigmaTPC2", "Paul's way;True not-electron #it{p} (GeV/c);n#sigma^{e}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + + histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCsignalVsEPofE", ";Electron #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCsignalVsOPofO", ";#mu/#pi #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTPCdEdx}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsP", ";Track #it{p} (GeV/c);n#sigma^{e}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsEPofE", ";Electron #it{p} (GeV/c);n#sigma^{e}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsPPofE", ";Electron #it{p} (GeV/c);n#sigma^{#pi}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaEvsnSigmaPofE", ";Electron n#sigma^{e}_{TPC} (arb. units);Electron n#sigma^{#pi}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsEPofO", ";Non-electron #it{p} (GeV/c);n#sigma^{e}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsMPofO", ";Non-electron #it{p} (GeV/c);n#sigma^{#mu}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsPPofO", ";Non-electron #it{p} (GeV/c);n#sigma^{#pi}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaEvsnSigmaPofO", ";Non-electron n#sigma^{e}_{TPC} (arb. units);Non-electron n#sigma^{#pi}_{TPC} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsP", ";Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTOFsignal}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsP", ";Track #it{p} (GeV/c);n#sigma^{e}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsEPofE", ";Electron #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTOFsignal}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsEPofE", ";Electron #it{p} (GeV/c);n#sigma^{e}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsPPofE", ";Electron #it{p} (GeV/c);n#sigma^{#pi}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaEvsnSigmaPofE", ";Electron n#sigma^{e}_{TOF} (arb. units);Electron n#sigma^{#pi}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsOPofO", ";Not-electron #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisTOFsignal}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsEPofO", ";Not-electron #it{p} (GeV/c);n#sigma^{e}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsMPofO", ";Not-electron #it{p} (GeV/c);n#sigma^{#mu}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsPPofO", ";Not-electron #it{p} (GeV/c);n#sigma^{#pi}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisMom, confAxis.zzAxisNsigma}); + histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaEvsnSigmaPofO", ";Not-electron n#sigma^{e}_{TOF} (arb. units);Not-electron n#sigma^{#pi}_{TOF} (arb. units)", HistType::kTH2D, {confAxis.zzAxisNsigma, confAxis.zzAxisNsigma}); + } + + if (doTruthHistos) { + histos.add("Events/Truth/hCountCollisions", ";;Number of generated collision (-)", HistType::kTH1D, {{1, 0.5, 1.5}}); + histos.add("Events/Truth/hChannels", ";Channels (-);Number of events (-)", HistType::kTH1D, {{confAxis.zzAxisChannels}}); + histos.add("Events/Truth/hPDGcodesAll", ";PDG codes of all particles (-);Number of events (-)", HistType::kTH1D, {{2001, -1000, 1000}}); + histos.add("Events/Truth/hPDGcodesNoMother", ";PDG codes of particles without mother (-);Number of events (-)", HistType::kTH1D, {{2001, -1000, 1000}}); + histos.add("Events/Truth/hPDGcodesTauDaughters", ";PDG codes of daughters of particles without mother (-);Number of events (-)", HistType::kTH1D, {{2001, -1000, 1000}}); + histos.add("Events/Truth/hNparticles", ";Number of particles in a collision (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisNparticles}); + histos.add("Events/Truth/hNtauDaughters", ";Number of daughters of no-mother particle in a collision (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisNparticles}); + histos.add("Events/Truth/hNelectrons", ";Number of electrons in a collision (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisNparticles}); + histos.add("Events/Truth/hNmuons", ";Number of muons in a collision (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisNparticles}); + histos.add("Events/Truth/hNpions", ";Number of pions in a collision (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisNparticles}); + histos.add("Events/Truth/hNphysPartVsNwoutMotherParts", ";Number of physical primary particles (-);Number of particles without mother(-)", HistType::kTH2D, {confAxis.zzAxisNparticles, confAxis.zzAxisNparticles}); + histos.add("Tracks/Truth/hTauP", ";Tau #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMom}); + histos.add("Tracks/Truth/hTauPt", ";Tau #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPt}); + histos.add("Tracks/Truth/hTauPhi", ";Tau #phi (rad);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPhi}); + histos.add("Tracks/Truth/hTauEta", ";Tau #eta (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisEta}); + histos.add("Tracks/Truth/hElectronP", ";Electron #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMom}); + histos.add("Tracks/Truth/hElectronPt", ";Electron #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPt}); + histos.add("Tracks/Truth/hElectronPhi", ";Electron #phi (rad);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPhi}); + histos.add("Tracks/Truth/hElectronEta", ";Electron #eta (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisEta}); + histos.add("Tracks/Truth/hMuonP", ";Muon #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMom}); + histos.add("Tracks/Truth/hMuonPt", ";Muon #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPt}); + histos.add("Tracks/Truth/hMuonPhi", ";Muon #phi (rad);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPhi}); + histos.add("Tracks/Truth/hMuonEta", ";Muon #eta (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisEta}); + histos.add("Tracks/Truth/hPionP", ";Pion #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisMom}); + histos.add("Tracks/Truth/hPionPt", ";Pion #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPt}); + histos.add("Tracks/Truth/hPionPhi", ";Pion #phi (rad);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisPhi}); + histos.add("Tracks/Truth/hPionEta", ";Pion #eta (-);Number of events (-)", HistType::kTH1D, {confAxis.zzAxisEta}); + } + + // histos.add("ProcessDataDG/hSelections", ";Selection (-);Number of passed collision (-)", HistType::kTH1D, {confAxis.zzAxisSelections}); + // histos.add("ProcessDataSG/hSelections", ";Selection (-);Number of passed collision (-)", HistType::kTH1D, {confAxis.zzAxisSelections}); + // histos.add("ProcessMCrecDG/hSelections", ";Selection (-);Number of passed collision (-)", HistType::kTH1D, {confAxis.zzAxisSelections}); + // histos.add("ProcessMCrecSG/hSelections", ";Selection (-);Number of passed collision (-)", HistType::kTH1D, {confAxis.zzAxisSelections}); + // histos.add("ProcessMCgen/hSelections", ";Selection (-);Number of passed collision (-)", HistType::kTH1D, {confAxis.zzAxisSelections}); + // histos.add("OutputTable/hSelections", ";Selection (-);Number of passed collision (-)", HistType::kTH1D, {confAxis.zzAxisSelections}); + histos.add("OutputTable/hRejections", ";Rejections (-);Number of passed collision (-)", HistType::kTH1D, {confAxis.zzAxisSelections}); + + } // end init + + // run (always called before process :( ) + void run(ProcessingContext&) + { + + if (verboseInfo) + printLargeMessage("RUN METHOD"); + + } // end run + + std::vector>> cutMyRequiredITSHits{}; + + void mySetRequireHitsInITSLayers(int8_t minNRequiredHits, std::set requiredLayers) + { + // layer 0 corresponds to the the innermost ITS layer + cutMyRequiredITSHits.push_back(std::make_pair(minNRequiredHits, requiredLayers)); + } + + void mySetITShitsRule(int matching) + { + switch (matching) { + case 0: // Run3ITSibAny + mySetRequireHitsInITSLayers(1, {0, 1, 2}); + break; + case 1: // Run3ITSibTwo + mySetRequireHitsInITSLayers(2, {0, 1, 2}); + break; + case 2: // Run3ITSallAny + mySetRequireHitsInITSLayers(1, {0, 1, 2, 3, 4, 5, 6}); + break; + case 3: // Run3ITSall7Layers + mySetRequireHitsInITSLayers(7, {0, 1, 2, 3, 4, 5, 6}); + break; + default: + LOG(fatal) << "You chose wrong ITS matching"; + break; + } + } + + bool isFulfillsITSHitRequirementsReinstatement(uint8_t itsClusterMap) const + { + constexpr uint8_t kBit = 1; + for (const auto& kITSrequirement : cutMyRequiredITSHits) { + auto hits = std::count_if(kITSrequirement.second.begin(), kITSrequirement.second.end(), [&](auto&& requiredLayer) { return itsClusterMap & (kBit << requiredLayer); }); + if ((kITSrequirement.first == -1) && (hits > 0)) { + return false; // no hits were required in specified layers + } else if (hits < kITSrequirement.first) { + return false; // not enough hits found in specified layers + } + } + return true; + } + + template + bool isGlobalTrackReinstatement(T const& track) + { + // kInAcceptance copy + if (track.pt() < cutGlobalTrack.cutMinPt || track.pt() > cutGlobalTrack.cutMaxPt) + return false; + if (eta(track.px(), track.py(), track.pz()) < cutGlobalTrack.cutMinEta || eta(track.px(), track.py(), track.pz()) > cutGlobalTrack.cutMaxEta) + return false; + // kPrimaryTracks + // GoldenChi2 cut is only for Run 2 + if (std::abs(track.dcaZ()) > cutGlobalTrack.cutMaxDCAz) + return false; + if (cutGlobalTrack.applyPtDependentDCAxy) { + float maxDCA = 0.0182f + 0.0350f / std::pow(track.pt(), 1.01f); + if (std::abs(track.dcaXY()) > maxDCA) + return false; + } else { + if (std::abs(track.dcaXY()) > cutGlobalTrack.cutMaxDCAxy) + return false; + } + // kQualityTrack + // TrackType is always 1 as per definition of processed Run3 AO2Ds + // ITS + if (cutGlobalTrack.cutHasITS && !track.hasITS()) + return false; // ITS refit + if (track.itsNCls() < cutGlobalTrack.cutMinITSnCls) + return false; + if (track.itsChi2NCl() > cutGlobalTrack.cutMaxITSchi2) + return false; + if (!isFulfillsITSHitRequirementsReinstatement(track.itsClusterMap())) + return false; + // TPC + if (cutGlobalTrack.cutHasTPC && !track.hasTPC()) + return false; // TPC refit + if ((track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) < cutGlobalTrack.cutMinTPCnCls) + return false; // tpcNClsFound() + if (track.tpcNClsCrossedRows() < cutGlobalTrack.cutMinTPCnClsXrows) + return false; + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < cutGlobalTrack.cutMinTPCnClsXrowsOverNcls) + return false; + if (track.tpcChi2NCl() > cutGlobalTrack.cutMaxTPCchi2) + return false; // TPC chi2 + if (cutGlobalTrack.cutGoodITSTPCmatching) { + if (track.itsChi2NCl() < 0.) + return false; // TPC chi2 + } + // TOF + if (track.hasTOF()) { + if (track.tpcChi2NCl() > cutGlobalTrack.cutMaxTOFchi2) + return false; // TOF chi2 + } + + return true; + } + + template + bool reinstallRun2JpsiTrackSelection(T const& track) + { + // kInAcceptance copy + if (eta(track.px(), track.py(), track.pz()) < -0.8 || eta(track.px(), track.py(), track.pz()) > 0.8) + return false; + // kPrimaryTracks + if (std::abs(track.dcaZ()) > 2.0) + return false; + float maxDCA = 0.0105f + 0.0350f / std::pow(track.pt(), 1.1f); + if (std::abs(track.dcaXY()) > maxDCA) + return false; + // kQualityTrack + // ITS + if (!track.hasITS()) + return false; // ITS refit + if (track.itsChi2NCl() > 36.) + return false; + if (!isFulfillsITSHitRequirementsReinstatement(track.itsClusterMap())) + return false; + // TPC + if (!track.hasTPC()) + return false; // TPC refit + if ((track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) < 70) + return false; // tpcNClsFound() + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < 0.8) + return false; + if (track.tpcChi2NCl() > 4.) + return false; + // TOF + if (!track.hasTOF()) + return false; + + return true; + } + + template + bool reinstallRun2JpsiEventSelection(C const& collision, T const& trk1, T const& trk2, float rapMother, float aco) + { + // tracks + if (!reinstallRun2JpsiTrackSelection(trk1)) + return false; + if (!reinstallRun2JpsiTrackSelection(trk2)) + return false; + if (trk1.sign() * trk2.sign() > 0) + return false; // opposite sign + if ((trk1.tpcNSigmaMu() * trk1.tpcNSigmaMu() + trk2.tpcNSigmaMu() * trk2.tpcNSigmaMu()) > + (trk1.tpcNSigmaEl() * trk1.tpcNSigmaEl() + trk2.tpcNSigmaEl() * trk2.tpcNSigmaEl())) + return false; // definitely muon than electron + // event + if (collision.posZ() > 15.) + return false; + if (rapMother < -0.8 || rapMother > 0.8) + return false; + if (aco > 4 * o2::constants::math::PI / 5) // max opening angle 144 degrees (I hope, check) + return false; + + return true; + } + + float getPhiModN(float phimodn, int sign, int fieldpolarity) + { + if (fieldpolarity < 0) // for negative polarity field + phimodn = o2::constants::math::TwoPI - phimodn; + if (sign < 0) // for negative charge + phimodn = o2::constants::math::TwoPI - phimodn; + phimodn += o2::constants::math::PI / 18.0; // to center gap in the middle + return std::fmod(phimodn, o2::constants::math::PI / 9.0); + } + + template + bool isGoodFITtime(C const& coll, float maxFITtime) + { + + // FTOA + if ((std::abs(coll.timeFT0A()) > maxFITtime) && coll.timeFT0A() > -998.) + return false; + + // FTOC + if ((std::abs(coll.timeFT0C()) > maxFITtime) && coll.timeFT0C() > -998.) + return false; + + return true; + } + + template + bool isGoodROFtime(C const& coll) + { + + // Occupancy + if (coll.occupancyInTime() > cutSample.cutEvOccupancy) + return false; + + // kNoCollInTimeRangeStandard + if (cutSample.cutEvTrs && !coll.trs()) + return false; + + // kNoCollInRofStandard + if (cutSample.cutEvTrofs && !coll.trofs()) + return false; + + // kNoHighMultCollInPrevRof + if (cutSample.cutEvHmpr && !coll.hmpr()) + return false; + + return true; + } + + unsigned int bitsRejection = 0; + unsigned int bitsRejectElCan = 0; + unsigned int bitsRejectMuPiCan = 0; + unsigned int bitsRejectTauEvent = 0; + + void outputGlobalRejectionHistogram() + { + + for (int i{0}; i < 10; i++) { + if (bitsRejection & (1 << i)) + histos.get(HIST("OutputTable/hRejections"))->Fill(i); + } + } + + void outputDetailedRejectionHistogram() + { + + for (int i{0}; i < 10; i++) { + if (bitsRejectTauEvent & (1 << i)) + histos.get(HIST("OutputTable/hRejections"))->Fill(i + 10); + } + + for (int i{0}; i < 10; i++) { + if (bitsRejectElCan & (1 << i)) + histos.get(HIST("OutputTable/hRejections"))->Fill(i + 20); + } + + for (int i{0}; i < 10; i++) { + if (bitsRejectMuPiCan & (1 << i)) + histos.get(HIST("OutputTable/hRejections"))->Fill(i + 30); + } + } + + template + void fillRejectElectronCandidate(T const& electronCandidate) + // Fill reasons of rejecting electron candidate + { + if (electronCandidate.tpcNSigmaEl() < cutPreselect.cutCanMaxElectronNsigmaEl || electronCandidate.tpcNSigmaEl() > cutPreselect.cutCanMinElectronNsigmaEl) + bitsRejectElCan |= (1 << 0); + if (cutPreselect.cutCanElectronHasTOF && !electronCandidate.hasTOF()) + bitsRejectElCan |= (1 << 1); + } + + template + bool isElectronCandidate(T const& electronCandidate) + // Loose criterium to find electron-like particle + // Requiring TOF to avoid double-counting pions/electrons and for better timing + { + fillRejectElectronCandidate(electronCandidate); + if (electronCandidate.tpcNSigmaEl() < cutPreselect.cutCanMaxElectronNsigmaEl || electronCandidate.tpcNSigmaEl() > cutPreselect.cutCanMinElectronNsigmaEl) + return false; + if (cutPreselect.cutCanElectronHasTOF && !electronCandidate.hasTOF()) + return false; + return true; + } + + template + bool fillRejectMuPionCandidate(T const& muPionCandidate) + // Fill reasons of rejecting mupion candidate + { + if (muPionCandidate.tpcNSigmaMu() < cutPreselect.cutCanMaxMuonNsigmaEl || muPionCandidate.tpcNSigmaMu() > cutPreselect.cutCanMinMuonNsigmaEl) + bitsRejectMuPiCan |= (1 << 0); + if (muPionCandidate.tpcNSigmaPi() < cutPreselect.cutCanMaxPionNsigmaEl || muPionCandidate.tpcNSigmaPi() > cutPreselect.cutCanMinPionNsigmaEl) + bitsRejectMuPiCan |= (1 << 1); + if (cutPreselect.cutCanMupionHasTOF && !muPionCandidate.hasTOF()) + bitsRejectMuPiCan |= (1 << 2); + return true; + } + + template + bool isMuPionCandidate(T const& muPionCandidate) + // Loose criterium to find muon/pion-like particle + // Requiring TOF for better timing + { + if (muPionCandidate.tpcNSigmaMu() < cutPreselect.cutCanMaxMuonNsigmaEl || muPionCandidate.tpcNSigmaMu() > cutPreselect.cutCanMinMuonNsigmaEl) + return false; + if (muPionCandidate.tpcNSigmaPi() < cutPreselect.cutCanMaxPionNsigmaEl || muPionCandidate.tpcNSigmaPi() > cutPreselect.cutCanMinPionNsigmaEl) + return false; + if (cutPreselect.cutCanMupionHasTOF && !muPionCandidate.hasTOF()) + return false; + return true; + } + + template + bool selectedGoodElectron(T const& electronCandidate) + { + if (electronCandidate.tpcNSigmaEl() < cutTauEvent.cutMaxElectronNsigmaEl || electronCandidate.tpcNSigmaEl() > cutTauEvent.cutMinElectronNsigmaEl) + return false; + if (electronCandidate.tpcNSigmaPi() > cutTauEvent.cutMinElectronNsigmaPi && electronCandidate.tpcNSigmaPi() < cutTauEvent.cutMaxElectronNsigmaPi) + return false; + if (cutTauEvent.cutElectronHasTOF && !electronCandidate.hasTOF()) + return false; + if (electronCandidate.hasTOF()) { + if (electronCandidate.tofNSigmaEl() < cutTauEvent.cutMaxElectronTofNsigmaEl || electronCandidate.tofNSigmaEl() > cutTauEvent.cutMinElectronTofNsigmaEl) + return false; + if (electronCandidate.tofNSigmaPr() > cutTauEvent.cutMinElectronNsigmaPr && electronCandidate.tofNSigmaPr() < cutTauEvent.cutMaxElectronNsigmaPr) + return false; + if (momentum(electronCandidate.px(), electronCandidate.py(), electronCandidate.pz()) < 1.0) { + if (electronCandidate.tofNSigmaKa() > cutTauEvent.cutMinElectronTofNsigmaKa && electronCandidate.tofNSigmaKa() < cutTauEvent.cutMaxElectronTofNsigmaKa) + return false; + } else { + if (electronCandidate.tpcNSigmaKa() > cutTauEvent.cutMinElectronNsigmaKa && electronCandidate.tpcNSigmaKa() < cutTauEvent.cutMaxElectronNsigmaKa) + return false; + } + } + return true; + } + + template + bool selectedGoodPion(T const& pionCandidate) + { + if (pionCandidate.tpcNSigmaPi() < cutTauEvent.cutMaxPionNsigmaPi || pionCandidate.tpcNSigmaPi() > cutTauEvent.cutMinPionNsigmaPi) + return false; + if (cutTauEvent.cutPionHasTOF && !pionCandidate.hasTOF()) + return false; + if (pionCandidate.hasTOF()) { + if (pionCandidate.tofNSigmaPi() < cutTauEvent.cutMaxPionTofNsigmaPi || pionCandidate.tofNSigmaPi() > cutTauEvent.cutMinPionTofNsigmaPi) + return false; + if (pionCandidate.tofNSigmaPr() > cutTauEvent.cutMinElectronNsigmaPr && pionCandidate.tofNSigmaPr() < cutTauEvent.cutMaxElectronNsigmaPr) + return false; + if (momentum(pionCandidate.px(), pionCandidate.py(), pionCandidate.pz()) < 1.0) { + if (pionCandidate.tofNSigmaKa() > cutTauEvent.cutMinElectronTofNsigmaKa && pionCandidate.tofNSigmaKa() < cutTauEvent.cutMaxElectronTofNsigmaKa) + return false; + } + } + return true; + } + + template + bool selectedTauEvent(T const& trkDaug1, T const& trkDaug2) + { + TLorentzVector mother, daug[2], motherOfPions, pion[2]; + daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(pdg->Mass(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)), trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(pdg->Mass(trackPDG(trkDaug2, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)), trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + if (cutTauEvent.useThresholdsPID) { + if (isElectronCandidate(trkDaug1)) + daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(MassElectron, trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + if (isElectronCandidate(trkDaug2)) + daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(MassElectron, trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + if (isMuPionCandidate(trkDaug1)) + daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(MassPionCharged, trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + if (isMuPionCandidate(trkDaug2)) + daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(MassPionCharged, trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + } + mother = daug[0] + daug[1]; + pion[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(MassPionCharged, trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + pion[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(MassPionCharged, trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + motherOfPions = pion[0] + pion[1]; + + int enumTrk1 = (cutTauEvent.useThresholdsPID ? (isElectronCandidate(trkDaug1) ? P_ELECTRON : P_PION) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC))); + if (cutTauEvent.cutOppositeCharge && (trkDaug1.sign() * trkDaug2.sign() > 0)) + return false; + if (cutTauEvent.cutSameCharge && (trkDaug1.sign() * trkDaug2.sign() < 0)) + return false; + if (calculateAcoplanarity(daug[0].Phi(), daug[1].Phi()) > cutTauEvent.cutMaxAcoplanarity) + return false; + if (calculateAcoplanarity(daug[0].Phi(), daug[1].Phi()) < cutTauEvent.cutMinAcoplanarity) + return false; + bool goodElectron = (enumTrk1 == P_ELECTRON) ? selectedGoodElectron(trkDaug1) : selectedGoodElectron(trkDaug2); + if (cutTauEvent.cutGoodElectron && !goodElectron) + return false; + bool goodMupion = ((enumTrk1 == P_MUON) || (enumTrk1 == P_PION)) ? selectedGoodPion(trkDaug1) : selectedGoodPion(trkDaug2); + if (cutTauEvent.cutGoodMupion && !goodMupion) + return false; + if (cutTauEvent.cutOutRho && (motherOfPions.M() > cutTauEvent.cutMinRhoMass && motherOfPions.M() < cutTauEvent.cutMaxRhoMass)) + return false; + if (cutTauEvent.cutOnRho && (motherOfPions.M() > cutTauEvent.cutMaxRhoMass || motherOfPions.M() < cutTauEvent.cutMinRhoMass)) + return false; + return true; + } + + template + void fillHistograms(Ts const& reconstructedBarrelTracks) + { + + histos.get(HIST("Events/hCountCollisions"))->Fill(1); + histos.get(HIST("Events/hNreconstructedTracks"))->Fill(reconstructedBarrelTracks.size()); + + // Loop over tracks without selections + for (const auto& track : reconstructedBarrelTracks) { + float trkPx = track.px(); + float trkPy = track.py(); + float trkPz = track.pz(); + // histos.get(HIST("Tracks/raw/hTrackZ"))->Fill(track.z()); + histos.get(HIST("Tracks/raw/hTrackP"))->Fill(momentum(trkPx, trkPy, trkPz)); + histos.get(HIST("Tracks/raw/hTrackPt"))->Fill(track.pt()); + histos.get(HIST("Tracks/raw/hTrackPhi"))->Fill(phi(trkPx, trkPy)); + histos.get(HIST("Tracks/raw/hTrackEta"))->Fill(eta(trkPx, trkPy, trkPz)); + histos.get(HIST("Tracks/raw/hTrackPtvsModPhi"))->Fill(track.pt(), std::fmod(phi(trkPx, trkPy), o2::constants::math::PI / 9)); + if (track.hasTOF()) + histos.get(HIST("Tracks/raw/hTrackPtvsModPhiTOF"))->Fill(track.pt(), std::fmod(phi(trkPx, trkPy), o2::constants::math::PI / 9)); + histos.get(HIST("Tracks/raw/hTrackDcaXY"))->Fill(track.dcaXY()); + histos.get(HIST("Tracks/raw/hTrackPtvsDcaXY"))->Fill(track.pt(), track.dcaXY()); + histos.get(HIST("Tracks/raw/hTrackDcaZ"))->Fill(track.dcaZ()); + histos.get(HIST("Tracks/raw/ITS/itsNCls"))->Fill(track.itsNCls()); + histos.get(HIST("Tracks/raw/ITS/itsChi2NCl"))->Fill(track.itsChi2NCl()); + histos.get(HIST("Tracks/raw/TPC/tpcNClsFindable"))->Fill(track.tpcNClsFindable()); + histos.get(HIST("Tracks/raw/TPC/tpcNClsFound"))->Fill(track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()); + histos.get(HIST("Tracks/raw/TPC/tpcCrossedRows"))->Fill(track.tpcNClsCrossedRows()); + histos.get(HIST("Tracks/raw/TPC/tpcCrossedRowsOverFindableCls"))->Fill((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable()))); + histos.get(HIST("Tracks/raw/TPC/tpcChi2NCl"))->Fill(track.tpcChi2NCl()); + } // Loop over tracks without selections + + int countPVGT = 0; + int countPVGTselected = 0; + int countPVGTelectrons = 0; + int countPVGTmuons = 0; + int countPVGTpions = 0; + int countPVGTothers = 0; + int countTOFtracks = 0; + int countPVGTelmupiAlt = 0; + int countPVGTelectronsAlt = 0; + int countPVGTmupionsAlt = 0; + std::vector vecPVidx; + std::vector vecPVnewPIDidx; + // Loop over tracks with selections + for (const auto& track : reconstructedBarrelTracks) { + if (!track.isPVContributor()) + continue; + if (cutGlobalTrack.applyGlobalTrackSelection && !isGlobalTrackReinstatement(track)) + continue; + countPVGT++; + float trkPx = track.px(); + float trkPy = track.py(); + float trkPz = track.pz(); + // histos.get(HIST("Tracks/GoodTrack/hTrackZ"))->Fill(track.z()); + histos.get(HIST("Tracks/GoodTrack/hTrackP"))->Fill(momentum(trkPx, trkPy, trkPz)); + histos.get(HIST("Tracks/GoodTrack/hTrackPt"))->Fill(track.pt()); + histos.get(HIST("Tracks/GoodTrack/hTrackPhi"))->Fill(phi(trkPx, trkPy)); + histos.get(HIST("Tracks/GoodTrack/hTrackPtvsModPhi"))->Fill(track.pt(), std::fmod(phi(trkPx, trkPy), o2::constants::math::PI / 9)); + if (track.hasTOF()) + histos.get(HIST("Tracks/GoodTrack/hTrackPtvsModPhiTOF"))->Fill(track.pt(), std::fmod(phi(trkPx, trkPy), o2::constants::math::PI / 9)); + histos.get(HIST("Tracks/GoodTrack/hTrackEta"))->Fill(eta(trkPx, trkPy, trkPz)); + histos.get(HIST("Tracks/GoodTrack/hTrackDcaXY"))->Fill(track.dcaXY()); + histos.get(HIST("Tracks/GoodTrack/hTrackPtvsDcaXY"))->Fill(track.pt(), track.dcaXY()); + histos.get(HIST("Tracks/GoodTrack/hTrackDcaZ"))->Fill(track.dcaZ()); + histos.get(HIST("Tracks/GoodTrack/ITS/itsNCls"))->Fill(track.itsNCls()); + histos.get(HIST("Tracks/GoodTrack/ITS/itsChi2NCl"))->Fill(track.itsChi2NCl()); + histos.get(HIST("Tracks/GoodTrack/TPC/tpcNClsFindable"))->Fill(track.tpcNClsFindable()); + histos.get(HIST("Tracks/GoodTrack/TPC/tpcNClsFound"))->Fill(track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()); + histos.get(HIST("Tracks/GoodTrack/TPC/tpcCrossedRows"))->Fill(track.tpcNClsCrossedRows()); + histos.get(HIST("Tracks/GoodTrack/TPC/tpcCrossedRowsOverFindableCls"))->Fill((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable()))); + histos.get(HIST("Tracks/GoodTrack/TPC/tpcChi2NCl"))->Fill(track.tpcChi2NCl()); + if (track.hasTOF()) + countTOFtracks++; + int hypothesisID = testPIDhypothesis(track, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC); + if (hypothesisID == P_ELECTRON || hypothesisID == P_MUON || hypothesisID == P_PION) { + countPVGTselected++; + vecPVidx.push_back(track.index()); + if (hypothesisID == P_ELECTRON) { + countPVGTelectrons++; + } else if (hypothesisID == P_MUON) { + countPVGTmuons++; + } else { + countPVGTpions++; + } + } else { + countPVGTothers++; + } + // alternative selection + if (isElectronCandidate(track)) { + countPVGTelmupiAlt++; + countPVGTelectronsAlt++; + vecPVnewPIDidx.push_back(track.index()); + } + if (isMuPionCandidate(track)) { + countPVGTelmupiAlt++; + countPVGTmupionsAlt++; + vecPVnewPIDidx.push_back(track.index()); + } + } // Loop over tracks with selections + + histos.get(HIST("Events/hNreconstructedPVGT"))->Fill(countPVGT); + histos.get(HIST("Events/hNreconstructedNotPVGT"))->Fill(reconstructedBarrelTracks.size() - countPVGT); + histos.get(HIST("Events/hNreconstructedPVGTelectrons"))->Fill(countPVGTelectrons); + histos.get(HIST("Events/hNreconstructedPVGTmuons"))->Fill(countPVGTmuons); + histos.get(HIST("Events/hNreconstructedPVGTpions"))->Fill(countPVGTpions); + histos.get(HIST("Events/hNreconstructedPVGTothers"))->Fill(countPVGTothers); + + bool isTwoSelectedTracks = (cutTauEvent.useThresholdsPID ? countPVGTelmupiAlt == 2 : countPVGTselected == 2); + bool isElEl = (cutTauEvent.useThresholdsPID ? countPVGTelectronsAlt == 2 : countPVGTelectrons == 2); + bool isPiPi = (cutTauEvent.useThresholdsPID ? countPVGTmupionsAlt == 2 : (countPVGTmuons == 2 || (countPVGTmuons == 1 && countPVGTpions == 1) || countPVGTpions == 2)); + bool isFourPion = (cutTauEvent.useThresholdsPID ? countPVGTmupionsAlt == 4 : countPVGTpions == 4); + bool isElThreePion = (cutTauEvent.useThresholdsPID ? (countPVGTelectronsAlt == 1 && countPVGTmupionsAlt == 3) : (countPVGTelectrons == 1 && (countPVGTmuons == 3 || (countPVGTmuons == 2 && countPVGTpions == 1) || (countPVGTmuons == 1 && countPVGTpions == 2) || countPVGTpions == 3))); + bool isSixPion = (cutTauEvent.useThresholdsPID ? countPVGTmupionsAlt == 6 : countPVGTpions == 6); + bool isElMuPion = (cutTauEvent.useThresholdsPID ? (countPVGTelectronsAlt == 1 && countPVGTmupionsAlt == 1) : ((countPVGTelectrons == 1 && countPVGTmuons == 1) || (countPVGTelectrons == 1 && countPVGTpions == 1))); + + if (isElEl) + histos.get(HIST("Events/hChannels"))->Fill(CH_EE); + if (isPiPi) + histos.get(HIST("Events/hChannels"))->Fill(CH_PIPI); + if (isFourPion) + histos.get(HIST("Events/hChannels"))->Fill(CH_FOURPI); + if (isElThreePion) + histos.get(HIST("Events/hChannels"))->Fill(CH_ETHREEPI); + if (isSixPion) + histos.get(HIST("Events/hChannels"))->Fill(CH_SIXPI); + if (isElMuPion) + histos.get(HIST("Events/hChannels"))->Fill(CH_EMUPI); + + if (isTwoSelectedTracks && doTwoTracks) { + TLorentzVector mother, daug[2], motherOfPions, pion[2], motherOfMuons, muon[2]; + const auto& trkDaug1 = reconstructedBarrelTracks.iteratorAt(cutTauEvent.useThresholdsPID ? vecPVnewPIDidx[0] : vecPVidx[0]); + const auto& trkDaug2 = reconstructedBarrelTracks.iteratorAt(cutTauEvent.useThresholdsPID ? vecPVnewPIDidx[1] : vecPVidx[1]); + daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(pdg->Mass(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)), trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(pdg->Mass(trackPDG(trkDaug2, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)), trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + if (cutTauEvent.useThresholdsPID) { + if (isElectronCandidate(trkDaug1)) + daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(MassElectron, trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + if (isElectronCandidate(trkDaug2)) + daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(MassElectron, trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + if (isMuPionCandidate(trkDaug1)) + daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(MassPionCharged, trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + if (isMuPionCandidate(trkDaug2)) + daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(MassPionCharged, trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + } + mother = daug[0] + daug[1]; + pion[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(MassPionCharged, trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + pion[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(MassPionCharged, trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + motherOfPions = pion[0] + pion[1]; + muon[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(MassMuon, trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + muon[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(MassMuon, trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + motherOfMuons = muon[0] + muon[1]; + const auto acoplanarity = calculateAcoplanarity(daug[0].Phi(), daug[1].Phi()); + const auto collinearity = calculateCollinearity(daug[0].Eta(), daug[1].Eta(), daug[0].Phi(), daug[1].Phi()); + if (cutTauEvent.applyTauEventSelection && !selectedTauEvent(trkDaug1, trkDaug2)) { + return; + } + histos.get(HIST("EventTwoTracks/hInvariantMass"))->Fill(mother.M()); + histos.get(HIST("EventTwoTracks/hInvariantMassWide"))->Fill(mother.M()); + histos.get(HIST("EventTwoTracks/hInvariantMassWideAllPionMass"))->Fill(motherOfPions.M()); + histos.get(HIST("EventTwoTracks/hAcoplanarity"))->Fill(acoplanarity); + histos.get(HIST("EventTwoTracks/hCollinearity"))->Fill(collinearity); + histos.get(HIST("EventTwoTracks/hMotherP"))->Fill(mother.P()); + histos.get(HIST("EventTwoTracks/hMotherPwide"))->Fill(mother.P()); + histos.get(HIST("EventTwoTracks/hMotherPt"))->Fill(mother.Pt()); + histos.get(HIST("EventTwoTracks/hMotherPhi"))->Fill(mother.Phi()); + histos.get(HIST("EventTwoTracks/hMotherRapidity"))->Fill(mother.Rapidity()); + histos.get(HIST("EventTwoTracks/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); + histos.get(HIST("EventTwoTracks/hDaughtersEnergyAsymmetry"))->Fill((daug[0].E() - daug[1].E()) / (daug[0].E() + daug[1].E())); + histos.get(HIST("EventTwoTracks/hDaughtersMomentaAsymmetry"))->Fill((daug[0].P() - daug[1].P()) / (daug[0].P() + daug[1].P())); + histos.get(HIST("EventTwoTracks/hDaughtersPtAsymmetry"))->Fill((daug[0].Pt() - daug[1].Pt()) / (daug[0].Pt() + daug[1].Pt())); + histos.get(HIST("EventTwoTracks/hDaughtersP"))->Fill(daug[0].P(), daug[1].P()); + histos.get(HIST("EventTwoTracks/hDaughtersPwide"))->Fill(daug[0].P(), daug[1].P()); + histos.get(HIST("EventTwoTracks/hDaughtersPt"))->Fill(daug[0].Pt(), daug[1].Pt()); + histos.get(HIST("EventTwoTracks/hDaughtersPhi"))->Fill(daug[0].Phi(), daug[1].Phi()); + histos.get(HIST("EventTwoTracks/hDaughtersRapidity"))->Fill(daug[0].Rapidity(), daug[1].Rapidity()); + histos.get(HIST("EventTwoTracks/hDaughtersEnergyFractions"))->Fill(daug[0].E() / (daug[0].E() + daug[1].E()), daug[1].E() / (daug[0].E() + daug[1].E())); + if (motherOfPions.Pt() < 0.2) { + histos.get(HIST("EventTwoTracks/hInvariantMassWideAllPionMassPtCut"))->Fill(motherOfPions.M()); + } + if (countTOFtracks == 2) { + histos.get(HIST("EventTwoTracks/hInvariantMassWideAllPionMassTOF"))->Fill(motherOfPions.M()); + } + histos.get(HIST("EventTwoTracks/hDaughtersPvsITSclusterSize"))->Fill(getAvgITSClSize(trkDaug1), trkDaug1.sign() * daug[0].P()); + histos.get(HIST("EventTwoTracks/hDaughtersPvsITSclusterSize"))->Fill(getAvgITSClSize(trkDaug2), trkDaug2.sign() * daug[1].P()); + histos.get(HIST("EventTwoTracks/hDaughtersPvsITSclusterSizeXcos"))->Fill(getAvgITSClSize(trkDaug1) * getCosLambda(trkDaug1), trkDaug1.sign() * daug[0].P()); + histos.get(HIST("EventTwoTracks/hDaughtersPvsITSclusterSizeXcos"))->Fill(getAvgITSClSize(trkDaug2) * getCosLambda(trkDaug2), trkDaug2.sign() * daug[1].P()); + + if (isElEl) { + histos.get(HIST("EventTwoTracks/TwoElectrons/hInvariantMass"))->Fill(mother.M()); + histos.get(HIST("EventTwoTracks/TwoElectrons/hInvariantMassWide"))->Fill(mother.M()); + histos.get(HIST("EventTwoTracks/TwoElectrons/hAcoplanarity"))->Fill(acoplanarity); + histos.get(HIST("EventTwoTracks/TwoElectrons/hCollinearity"))->Fill(collinearity); + histos.get(HIST("EventTwoTracks/TwoElectrons/hMotherP"))->Fill(mother.P()); + histos.get(HIST("EventTwoTracks/TwoElectrons/hMotherPwide"))->Fill(mother.P()); + histos.get(HIST("EventTwoTracks/TwoElectrons/hMotherPt"))->Fill(mother.Pt()); + histos.get(HIST("EventTwoTracks/TwoElectrons/hMotherPhi"))->Fill(mother.Phi()); + histos.get(HIST("EventTwoTracks/TwoElectrons/hMotherRapidity"))->Fill(mother.Rapidity()); + histos.get(HIST("EventTwoTracks/TwoElectrons/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); + histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersP"))->Fill(daug[0].P(), daug[1].P()); + histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPwide"))->Fill(daug[0].P(), daug[1].P()); + histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPt"))->Fill(daug[0].Pt(), daug[1].Pt()); + histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPhi"))->Fill(daug[0].Phi(), daug[1].Phi()); + histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhi"))->Fill(daug[0].P(), getPhiModN(daug[0].Phi(), trkDaug1.sign(), 1)); + histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhi"))->Fill(daug[1].P(), getPhiModN(daug[1].Phi(), trkDaug2.sign(), 1)); + histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersRapidity"))->Fill(daug[0].Rapidity(), daug[1].Rapidity()); + histos.get(HIST("EventTwoTracks/TwoElectrons/hLeadingP"))->Fill(((daug[0].P() > daug[1].P()) ? daug[0].P() : daug[1].P())); + histos.get(HIST("EventTwoTracks/TwoElectrons/hLeadingPwide"))->Fill(((daug[0].P() > daug[1].P()) ? daug[0].P() : daug[1].P())); + histos.get(HIST("EventTwoTracks/TwoElectrons/hLeadingPt"))->Fill(((daug[0].P() > daug[1].P()) ? daug[0].Pt() : daug[1].Pt())); + histos.get(HIST("EventTwoTracks/TwoElectrons/hLeadingPhi"))->Fill(((daug[0].P() > daug[1].P()) ? daug[0].Phi() : daug[1].Phi())); + histos.get(HIST("EventTwoTracks/TwoElectrons/hLeadingRapidity"))->Fill(((daug[0].P() > daug[1].P()) ? daug[0].Rapidity() : daug[1].Rapidity())); + histos.get(HIST("EventTwoTracks/TwoElectrons/hLeadingPvsOtherP"))->Fill(((daug[0].P() > daug[1].P()) ? daug[0].P() : daug[1].P()), ((daug[0].P() > daug[1].P()) ? daug[1].P() : daug[0].P())); + histos.get(HIST("EventTwoTracks/TwoElectrons/hLeadingPwideVsOtherPwide"))->Fill(((daug[0].P() > daug[1].P()) ? daug[0].P() : daug[1].P()), ((daug[0].P() > daug[1].P()) ? daug[1].P() : daug[0].P())); + histos.get(HIST("EventTwoTracks/TwoElectrons/hLeadingPtVsOtherPt"))->Fill(((daug[0].P() > daug[1].P()) ? daug[0].Pt() : daug[1].Pt()), ((daug[0].P() > daug[1].P()) ? daug[1].Pt() : daug[0].Pt())); + histos.get(HIST("EventTwoTracks/TwoElectrons/hLeadingPhiVsOtherPhi"))->Fill(((daug[0].P() > daug[1].P()) ? daug[0].Phi() : daug[1].Phi()), ((daug[0].P() > daug[1].P()) ? daug[1].Phi() : daug[0].Phi())); + histos.get(HIST("EventTwoTracks/TwoElectrons/hLeadingRapVsOtherRap"))->Fill(((daug[0].P() > daug[1].P()) ? daug[0].Rapidity() : daug[1].Rapidity()), ((daug[0].P() > daug[1].P()) ? daug[1].Rapidity() : daug[0].Rapidity())); + if (mother.Pt() < 0.2) { + histos.get(HIST("EventTwoTracks/TwoElectrons/hInvariantMassWidePtCut"))->Fill(mother.M()); + histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiPtCut"))->Fill(daug[0].P(), getPhiModN(daug[0].Phi(), trkDaug1.sign(), 1)); + histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiPtCut"))->Fill(daug[1].P(), getPhiModN(daug[1].Phi(), trkDaug2.sign(), 1)); + if (countTOFtracks == 2) { + histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiPtCutTOF"))->Fill(daug[0].P(), getPhiModN(daug[0].Phi(), trkDaug1.sign(), 1)); + histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiPtCutTOF"))->Fill(daug[1].P(), getPhiModN(daug[1].Phi(), trkDaug2.sign(), 1)); + } + } + if (countTOFtracks == 2) { + histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiTOF"))->Fill(daug[0].P(), getPhiModN(daug[0].Phi(), trkDaug1.sign(), 1)); + histos.get(HIST("EventTwoTracks/TwoElectrons/hDaughtersPtvsModPhiTOF"))->Fill(daug[1].P(), getPhiModN(daug[1].Phi(), trkDaug2.sign(), 1)); + } + } + if (isElMuPion) { + const auto& electronPt = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug1) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? daug[0].Pt() : daug[1].Pt(); + const auto& electronP = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug1) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? daug[0].P() : daug[1].P(); + const auto& electronE = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug1) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? daug[0].E() : daug[1].E(); + const auto& mupionPt = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug1) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? daug[1].Pt() : daug[0].Pt(); + const auto& mupionP = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug1) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? daug[1].P() : daug[0].P(); + const auto& mupionE = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug1) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? daug[1].E() : daug[0].E(); + + TLorentzVector motherOfPiKaon, kaon; + if (isElectronCandidate(trkDaug1)) { + kaon.SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(MassKaonCharged, trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + motherOfPiKaon = kaon + daug[1]; + } else { + kaon.SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(MassKaonCharged, trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + motherOfPiKaon = daug[0] + kaon; + } + histos.get(HIST("EventTwoTracks/ElectronMuPi/hInvariantMass"))->Fill(mother.M()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hInvariantMassWide"))->Fill(mother.M()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PionsSelection/hInvariantMass"))->Fill(motherOfPions.M()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PionsSelection/hInvariantMassWide"))->Fill(motherOfPions.M()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/KstarSelection/hInvariantMass"))->Fill(motherOfPiKaon.M()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/KstarSelection/hInvariantMassWide"))->Fill(motherOfPiKaon.M()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/KstarSelection/hMotherMassVsPt"))->Fill(motherOfPiKaon.M(), motherOfPiKaon.Pt()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/KstarSelection/hMotherMassVsElectronP"))->Fill(motherOfPiKaon.M(), electronP); + histos.get(HIST("EventTwoTracks/ElectronMuPi/KstarSelection/hIMKvsIMe"))->Fill(motherOfPiKaon.M(), mother.M()); + if (electronPt < cutTauEvent.cutElectronPt) { + histos.get(HIST("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutLow/hInvariantMass"))->Fill(motherOfPiKaon.M()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutLow/hInvariantMassWide"))->Fill(motherOfPiKaon.M()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutLow/hMotherMassVsPt"))->Fill(motherOfPiKaon.M(), motherOfPiKaon.Pt()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutLow/hIMKvsIMe"))->Fill(motherOfPiKaon.M(), mother.M()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutLow/hElectronPwideVsOtherPwide"))->Fill(electronP, mupionP); + } else { + histos.get(HIST("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutHigh/hInvariantMass"))->Fill(motherOfPiKaon.M()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutHigh/hInvariantMassWide"))->Fill(motherOfPiKaon.M()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutHigh/hMotherMassVsPt"))->Fill(motherOfPiKaon.M(), motherOfPiKaon.Pt()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutHigh/hIMKvsIMe"))->Fill(motherOfPiKaon.M(), mother.M()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/KstarSelection/eMomentaCutHigh/hElectronPwideVsOtherPwide"))->Fill(electronP, mupionP); + } + histos.get(HIST("EventTwoTracks/ElectronMuPi/hAcoplanarity"))->Fill(acoplanarity); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hCollinearity"))->Fill(collinearity); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hMotherP"))->Fill(mother.P()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hMotherPwide"))->Fill(mother.P()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hMotherPt"))->Fill(mother.Pt()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hMotherPhi"))->Fill(mother.Phi()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hMotherRapidity"))->Fill(mother.Rapidity()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hMotherMassVsElectronP"))->Fill(mother.M(), electronP); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hMotherMassVsAcoplanarity"))->Fill(mother.M(), acoplanarity); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hElectronPt"))->Fill(electronPt); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hElectronPtWide"))->Fill(electronPt); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hDaughtersEnergyAsymmetry"))->Fill((daug[0].E() - daug[1].E()) / (daug[0].E() + daug[1].E())); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hDaughtersMomentaAsymmetry"))->Fill((daug[0].P() - daug[1].P()) / (daug[0].P() + daug[1].P())); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hDaughtersPtAsymmetry"))->Fill((daug[0].Pt() - daug[1].Pt()) / (daug[0].Pt() + daug[1].Pt())); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hDaughtersP"))->Fill(daug[0].P(), daug[1].P()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hDaughtersPwide"))->Fill(daug[0].P(), daug[1].P()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hDaughtersPt"))->Fill(daug[0].Pt(), daug[1].Pt()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hDaughtersPhi"))->Fill(daug[0].Phi(), daug[1].Phi()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hDaughtersRapidity"))->Fill(daug[0].Rapidity(), daug[1].Rapidity()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hDaughtersEnergyFractions"))->Fill(electronE / (electronE + mupionE), mupionE / (electronE + mupionE)); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hElectronPvsOtherP"))->Fill(electronP, mupionP); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hElectronPwideVsOtherPwide"))->Fill(electronP, mupionP); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hElectronPvsAcoplanarity"))->Fill(electronP, acoplanarity); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hOtherPvsAcoplanarity"))->Fill(mupionP, acoplanarity); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hElectronPtVsOtherPt"))->Fill(electronPt, mupionPt); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hElectronPhiVsOtherPhi"))->Fill(isElectronCandidate(trkDaug1) ? daug[0].Phi() : daug[1].Phi(), isElectronCandidate(trkDaug1) ? daug[1].Phi() : daug[0].Phi()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hElectronRapVsOtherRap"))->Fill(isElectronCandidate(trkDaug1) ? daug[0].Rapidity() : daug[1].Rapidity(), isElectronCandidate(trkDaug1) ? daug[1].Rapidity() : daug[0].Rapidity()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(0); + if (mother.Pt() < 9.) + histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(1); + if (mother.Pt() < 8.) + histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(2); + if (mother.Pt() < 7.) + histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(3); + if (mother.Pt() < 6.) + histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(4); + if (mother.Pt() < 5.) + histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(5); + if (mother.Pt() < 4.) + histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(6); + if (mother.Pt() < 3.) + histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(7); + if (mother.Pt() < 2.) + histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(8); + if (mother.Pt() < 1.) + histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(9); + if (electronPt > 0.1 && electronPt < 1.) + histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(10); + if (electronPt > 1. && electronPt < 2.) + histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(11); + if (electronPt > 2. && electronPt < 100.) + histos.get(HIST("EventTwoTracks/ElectronMuPi/hNeventsPtCuts"))->Fill(12); + } + } else { + printDebugMessage("Other particles"); + } + + } // end fillHistograms + + template + void fillPIDhistograms(C const& /*reconstructedCollision*/, Ts const& reconstructedBarrelTracks) + { + + // Loop over tracks without selections + for (const auto& track : reconstructedBarrelTracks) { + float trkPx = track.px(); + float trkPy = track.py(); + float trkPz = track.pz(); + if (track.hasTPC()) { + // histos.get(HIST("Tracks/raw/PID/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); + histos.get(HIST("Tracks/raw/PID/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/raw/PID/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); + histos.get(HIST("Tracks/raw/PID/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/raw/PID/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); + histos.get(HIST("Tracks/raw/PID/hTPCnSigmaElVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcNSigmaEl()); + histos.get(HIST("Tracks/raw/PID/hTPCnSigmaMuVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcNSigmaMu()); + histos.get(HIST("Tracks/raw/PID/hTPCnSigmaPiVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcNSigmaPi()); + histos.get(HIST("Tracks/raw/PID/hTPCnSigmaKaVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcNSigmaKa()); + histos.get(HIST("Tracks/raw/PID/hTPCnSigmaPrVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcNSigmaPr()); + if (track.hasTOF()) + histos.get(HIST("Tracks/raw/PID/hTOFsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tofSignal()); + if (track.sign() == 1) { + // histos.get(HIST("Tracks/raw/PID/PosCharge/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); + histos.get(HIST("Tracks/raw/PID/PosCharge/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/raw/PID/PosCharge/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); + histos.get(HIST("Tracks/raw/PID/PosCharge/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/raw/PID/PosCharge/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); + if (track.hasTOF()) + histos.get(HIST("Tracks/raw/PID/PosCharge/hTOFsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tofSignal()); + } else if (track.sign() == -1) { + // histos.get(HIST("Tracks/raw/PID/NegCharge/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); + histos.get(HIST("Tracks/raw/PID/NegCharge/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/raw/PID/NegCharge/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); + histos.get(HIST("Tracks/raw/PID/NegCharge/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/raw/PID/NegCharge/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); + if (track.hasTOF()) + histos.get(HIST("Tracks/raw/PID/NegCharge/hTOFsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tofSignal()); + } else { + printMediumMessage("Track has no charge"); + } + } + } // Loop over tracks without selections + + int countPVGT = 0; + int countPVGTselected = 0; + int countPVGTelectrons = 0; + int countPVGTmuons = 0; + int countPVGTpions = 0; + int countPVGTelmupiAlt = 0; + int countPVGTelectronsAlt = 0; + int countPVGTmupionsAlt = 0; + std::vector vecPVidx; + std::vector vecPVnoPIDidx; + std::vector vecPVnewPIDidx; + // Loop over tracks with selections + for (const auto& track : reconstructedBarrelTracks) { + if (!track.isPVContributor()) + continue; + if (cutGlobalTrack.applyGlobalTrackSelection && !isGlobalTrackReinstatement(track)) + continue; + countPVGT++; + vecPVnoPIDidx.push_back(track.index()); + float trkPx = track.px(); + float trkPy = track.py(); + float trkPz = track.pz(); + if (track.hasTPC()) { + histos.get(HIST("Tracks/GoodTrack/PID/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/hTPCnSigmaElVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcNSigmaEl()); + histos.get(HIST("Tracks/GoodTrack/PID/hTPCnSigmaMuVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcNSigmaMu()); + histos.get(HIST("Tracks/GoodTrack/PID/hTPCnSigmaPiVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcNSigmaPi()); + histos.get(HIST("Tracks/GoodTrack/PID/hTPCnSigmaKaVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcNSigmaKa()); + histos.get(HIST("Tracks/GoodTrack/PID/hTPCnSigmaPrVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcNSigmaPr()); + if (track.hasTOF()) + histos.get(HIST("Tracks/GoodTrack/PID/hTOFsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tofSignal()); + if (track.sign() == 1) { + histos.get(HIST("Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); + if (track.hasTOF()) + histos.get(HIST("Tracks/GoodTrack/PID/PosCharge/hTOFsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tofSignal()); + } else if (track.sign() == -1) { + histos.get(HIST("Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); + if (track.hasTOF()) + histos.get(HIST("Tracks/GoodTrack/PID/NegCharge/hTOFsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tofSignal()); + } else { + printMediumMessage("Track has no charge"); + } + } + int hypothesisID = testPIDhypothesis(track, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC); + if (hypothesisID == P_ELECTRON || hypothesisID == P_MUON || hypothesisID == P_PION) { + countPVGTselected++; + vecPVidx.push_back(track.index()); + if (hypothesisID == P_ELECTRON) { + countPVGTelectrons++; + if (!cutTauEvent.useThresholdsPID) { + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCnSigmaVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcNSigmaEl()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCnSigmaElVsMu"))->Fill(track.tpcNSigmaEl(), track.tpcNSigmaMu()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCnSigmaElVsPi"))->Fill(track.tpcNSigmaEl(), track.tpcNSigmaPi()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCnSigmaElVsKa"))->Fill(track.tpcNSigmaEl(), track.tpcNSigmaKa()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCnSigmaElVsPr"))->Fill(track.tpcNSigmaEl(), track.tpcNSigmaPr()); + if (track.hasTOF()) { + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTOFsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tofSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTOFnSigmaVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tofNSigmaEl()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTOFnSigmaElVsMu"))->Fill(track.tofNSigmaEl(), track.tofNSigmaMu()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTOFnSigmaElVsPi"))->Fill(track.tofNSigmaEl(), track.tofNSigmaPi()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTOFnSigmaElVsKa"))->Fill(track.tofNSigmaEl(), track.tofNSigmaKa()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTOFnSigmaElVsPr"))->Fill(track.tofNSigmaEl(), track.tofNSigmaPr()); + } + } + } else if (hypothesisID == P_MUON) { + countPVGTmuons++; + histos.get(HIST("Tracks/GoodTrack/PID/Muon/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Muon/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Muon/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Muon/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Muon/hTPCnSigmaVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcNSigmaMu()); + histos.get(HIST("Tracks/GoodTrack/PID/Muon/hTPCnSigmaMuVsEl"))->Fill(track.tpcNSigmaMu(), track.tpcNSigmaEl()); + histos.get(HIST("Tracks/GoodTrack/PID/Muon/hTPCnSigmaMuVsPi"))->Fill(track.tpcNSigmaMu(), track.tpcNSigmaPi()); + histos.get(HIST("Tracks/GoodTrack/PID/Muon/hTPCnSigmaMuVsKa"))->Fill(track.tpcNSigmaMu(), track.tpcNSigmaKa()); + histos.get(HIST("Tracks/GoodTrack/PID/Muon/hTPCnSigmaMuVsPr"))->Fill(track.tpcNSigmaMu(), track.tpcNSigmaPr()); + if (track.hasTOF()) { + histos.get(HIST("Tracks/GoodTrack/PID/Muon/hTOFsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tofSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Muon/hTOFnSigmaVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tofNSigmaMu()); + histos.get(HIST("Tracks/GoodTrack/PID/Muon/hTOFnSigmaMuVsEl"))->Fill(track.tofNSigmaMu(), track.tofNSigmaEl()); + histos.get(HIST("Tracks/GoodTrack/PID/Muon/hTOFnSigmaMuVsPi"))->Fill(track.tofNSigmaMu(), track.tofNSigmaPi()); + histos.get(HIST("Tracks/GoodTrack/PID/Muon/hTOFnSigmaMuVsKa"))->Fill(track.tofNSigmaMu(), track.tofNSigmaKa()); + histos.get(HIST("Tracks/GoodTrack/PID/Muon/hTOFnSigmaMuVsPr"))->Fill(track.tofNSigmaMu(), track.tofNSigmaPr()); + } + } else { + countPVGTpions++; + if (!cutTauEvent.useThresholdsPID) { + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCnSigmaVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcNSigmaPi()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCnSigmaPiVsEl"))->Fill(track.tpcNSigmaPi(), track.tpcNSigmaEl()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCnSigmaPiVsMu"))->Fill(track.tpcNSigmaPi(), track.tpcNSigmaMu()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCnSigmaPiVsKa"))->Fill(track.tpcNSigmaPi(), track.tpcNSigmaKa()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCnSigmaPiVsPr"))->Fill(track.tpcNSigmaPi(), track.tpcNSigmaPr()); + if (track.hasTOF()) { + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTOFsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tofSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTOFnSigmaVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tofNSigmaPi()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTOFnSigmaPiVsEl"))->Fill(track.tofNSigmaPi(), track.tofNSigmaEl()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTOFnSigmaPiVsMu"))->Fill(track.tofNSigmaPi(), track.tofNSigmaMu()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTOFnSigmaPiVsKa"))->Fill(track.tofNSigmaPi(), track.tofNSigmaKa()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTOFnSigmaPiVsPr"))->Fill(track.tofNSigmaPi(), track.tofNSigmaPr()); + } + } + } + } else { + histos.get(HIST("Tracks/GoodTrack/PID/Others/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Others/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Others/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Others/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); + if (track.hasTOF()) { + histos.get(HIST("Tracks/GoodTrack/PID/Others/hTOFsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tofSignal()); + } + } + // alternative selection + if (isElectronCandidate(track)) { + countPVGTelmupiAlt++; + countPVGTelectronsAlt++; + vecPVnewPIDidx.push_back(track.index()); + if (cutTauEvent.useThresholdsPID) { + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCnSigmaVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcNSigmaEl()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCnSigmaElVsMu"))->Fill(track.tpcNSigmaEl(), track.tpcNSigmaMu()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCnSigmaElVsPi"))->Fill(track.tpcNSigmaEl(), track.tpcNSigmaPi()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCnSigmaElVsKa"))->Fill(track.tpcNSigmaEl(), track.tpcNSigmaKa()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCnSigmaElVsPr"))->Fill(track.tpcNSigmaEl(), track.tpcNSigmaPr()); + if (track.hasTOF()) { + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTOFsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tofSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTOFnSigmaVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tofNSigmaEl()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTOFnSigmaElVsMu"))->Fill(track.tofNSigmaEl(), track.tofNSigmaMu()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTOFnSigmaElVsPi"))->Fill(track.tofNSigmaEl(), track.tofNSigmaPi()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTOFnSigmaElVsKa"))->Fill(track.tofNSigmaEl(), track.tofNSigmaKa()); + histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTOFnSigmaElVsPr"))->Fill(track.tofNSigmaEl(), track.tofNSigmaPr()); + } + } + } + if (isMuPionCandidate(track)) { + countPVGTelmupiAlt++; + countPVGTmupionsAlt++; + vecPVnewPIDidx.push_back(track.index()); + if (cutTauEvent.useThresholdsPID) { + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCsignalVsPt"))->Fill(track.pt(), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCsignalVsEta"))->Fill(eta(trkPx, trkPy, trkPz), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCsignalVsPhi"))->Fill(phi(trkPx, trkPy), track.tpcSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCnSigmaVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tpcNSigmaPi()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCnSigmaPiVsEl"))->Fill(track.tpcNSigmaPi(), track.tpcNSigmaEl()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCnSigmaPiVsMu"))->Fill(track.tpcNSigmaPi(), track.tpcNSigmaMu()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCnSigmaPiVsKa"))->Fill(track.tpcNSigmaPi(), track.tpcNSigmaKa()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCnSigmaPiVsPr"))->Fill(track.tpcNSigmaPi(), track.tpcNSigmaPr()); + if (track.hasTOF()) { + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTOFsignalVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tofSignal()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTOFnSigmaVsP"))->Fill(momentum(trkPx, trkPy, trkPz), track.tofNSigmaPi()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTOFnSigmaPiVsEl"))->Fill(track.tofNSigmaPi(), track.tofNSigmaEl()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTOFnSigmaPiVsMu"))->Fill(track.tofNSigmaPi(), track.tofNSigmaMu()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTOFnSigmaPiVsKa"))->Fill(track.tofNSigmaPi(), track.tofNSigmaKa()); + histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTOFnSigmaPiVsPr"))->Fill(track.tofNSigmaPi(), track.tofNSigmaPr()); + } + } + } + + } // Loop over tracks with selections + + if (countPVGT == 2 && doTwoTracks) { + TLorentzVector daug[2], pion[2], muon[2]; + const auto& trkDaug1 = reconstructedBarrelTracks.iteratorAt(vecPVnoPIDidx[0]); + const auto& trkDaug2 = reconstructedBarrelTracks.iteratorAt(vecPVnoPIDidx[1]); + daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(pdg->Mass(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)), trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(pdg->Mass(trackPDG(trkDaug2, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)), trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + if (cutTauEvent.applyTauEventSelection && !selectedTauEvent(trkDaug1, trkDaug2)) { + return; + } + if (cutTauEvent.useThresholdsPID) { + if (isElectronCandidate(trkDaug1)) + daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(MassElectron, trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + if (isElectronCandidate(trkDaug2)) + daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(MassElectron, trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + if (isMuPionCandidate(trkDaug1)) + daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(MassPionCharged, trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + if (isMuPionCandidate(trkDaug2)) + daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(MassPionCharged, trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + } + + if (trkDaug1.hasTPC()) { + histos.get(HIST("EventTwoTracks/PID/NoPID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); + histos.get(HIST("EventTwoTracks/PID/NoPID/hTPCnSigmaElVsP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaEl()); + histos.get(HIST("EventTwoTracks/PID/NoPID/hTPCnSigmaMuVsP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaMu()); + histos.get(HIST("EventTwoTracks/PID/NoPID/hTPCnSigmaPiVsP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaPi()); + histos.get(HIST("EventTwoTracks/PID/NoPID/hTPCnSigmaKaVsP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaKa()); + histos.get(HIST("EventTwoTracks/PID/NoPID/hTPCnSigmaPrVsP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaPr()); + } + if (trkDaug2.hasTPC()) { + histos.get(HIST("EventTwoTracks/PID/NoPID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); + histos.get(HIST("EventTwoTracks/PID/NoPID/hTPCnSigmaElVsP"))->Fill(daug[1].P(), trkDaug2.tpcNSigmaEl()); + histos.get(HIST("EventTwoTracks/PID/NoPID/hTPCnSigmaMuVsP"))->Fill(daug[1].P(), trkDaug2.tpcNSigmaMu()); + histos.get(HIST("EventTwoTracks/PID/NoPID/hTPCnSigmaPiVsP"))->Fill(daug[1].P(), trkDaug2.tpcNSigmaPi()); + histos.get(HIST("EventTwoTracks/PID/NoPID/hTPCnSigmaKaVsP"))->Fill(daug[1].P(), trkDaug2.tpcNSigmaKa()); + histos.get(HIST("EventTwoTracks/PID/NoPID/hTPCnSigmaPrVsP"))->Fill(daug[1].P(), trkDaug2.tpcNSigmaPr()); + } + } + + bool isTwoSelectedTracks = (cutTauEvent.useThresholdsPID ? countPVGTelmupiAlt == 2 : countPVGTselected == 2); + bool isElEl = (cutTauEvent.useThresholdsPID ? countPVGTelectronsAlt == 2 : countPVGTelectrons == 2); + bool isElMuPion = (cutTauEvent.useThresholdsPID ? (countPVGTelectronsAlt == 1 && countPVGTmupionsAlt == 1) : ((countPVGTelectrons == 1 && countPVGTmuons == 1) || (countPVGTelectrons == 1 && countPVGTpions == 1))); + if (isTwoSelectedTracks && doTwoTracks) { + TLorentzVector daug[2], pion[2], muon[2]; + const auto& trkDaug1 = reconstructedBarrelTracks.iteratorAt(cutTauEvent.useThresholdsPID ? vecPVnewPIDidx[0] : vecPVidx[0]); + const auto& trkDaug2 = reconstructedBarrelTracks.iteratorAt(cutTauEvent.useThresholdsPID ? vecPVnewPIDidx[1] : vecPVidx[1]); + daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(pdg->Mass(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)), trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(pdg->Mass(trackPDG(trkDaug2, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)), trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + pion[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(MassPionCharged, trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + pion[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(MassPionCharged, trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + muon[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(MassMuon, trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + muon[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(MassMuon, trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + if (cutTauEvent.applyTauEventSelection && !selectedTauEvent(trkDaug1, trkDaug2)) { + return; + } + if (cutTauEvent.useThresholdsPID) { + if (isElectronCandidate(trkDaug1)) + daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(MassElectron, trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + if (isElectronCandidate(trkDaug2)) + daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(MassElectron, trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + if (isMuPionCandidate(trkDaug1)) + daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(MassPionCharged, trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + if (isMuPionCandidate(trkDaug2)) + daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(MassPionCharged, trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + } + if (trkDaug1.hasTPC()) { + histos.get(HIST("EventTwoTracks/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); + histos.get(HIST("EventTwoTracks/PID/hTPCnSigmaElVsP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaEl()); + histos.get(HIST("EventTwoTracks/PID/hTPCnSigmaMuVsP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaMu()); + histos.get(HIST("EventTwoTracks/PID/hTPCnSigmaPiVsP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaPi()); + histos.get(HIST("EventTwoTracks/PID/hTPCnSigmaKaVsP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaKa()); + histos.get(HIST("EventTwoTracks/PID/hTPCnSigmaPrVsP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaPr()); + if (trkDaug1.hasTOF()) { + histos.get(HIST("EventTwoTracks/PID/hTOFsignalVsP"))->Fill(daug[0].P(), trkDaug1.tofSignal()); + } + if (isElEl) { + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCnSigmaVsP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaEl()); + if (trkDaug1.hasTOF()) { + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFsignalVsP"))->Fill(daug[0].P(), trkDaug1.tofSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFnSigmaVsP"))->Fill(daug[0].P(), trkDaug1.tofNSigmaEl()); + } + } + if (isElMuPion) { + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaEl()); + if (trkDaug1.hasTOF()) { + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsP"))->Fill(daug[0].P(), trkDaug1.tofSignal()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsP"))->Fill(daug[0].P(), trkDaug1.tofNSigmaEl()); + } + } + } + if (trkDaug2.hasTPC()) { + histos.get(HIST("EventTwoTracks/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); + histos.get(HIST("EventTwoTracks/PID/hTPCnSigmaElVsP"))->Fill(daug[1].P(), trkDaug1.tpcNSigmaEl()); + histos.get(HIST("EventTwoTracks/PID/hTPCnSigmaMuVsP"))->Fill(daug[1].P(), trkDaug1.tpcNSigmaMu()); + histos.get(HIST("EventTwoTracks/PID/hTPCnSigmaPiVsP"))->Fill(daug[1].P(), trkDaug1.tpcNSigmaPi()); + histos.get(HIST("EventTwoTracks/PID/hTPCnSigmaKaVsP"))->Fill(daug[1].P(), trkDaug1.tpcNSigmaKa()); + histos.get(HIST("EventTwoTracks/PID/hTPCnSigmaPrVsP"))->Fill(daug[1].P(), trkDaug1.tpcNSigmaPr()); + if (trkDaug2.hasTOF()) { + histos.get(HIST("EventTwoTracks/PID/hTOFsignalVsP"))->Fill(daug[1].P(), trkDaug2.tofSignal()); + } + if (isElEl) { + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCnSigmaVsP"))->Fill(daug[1].P(), trkDaug2.tpcNSigmaEl()); + if (trkDaug2.hasTOF()) { + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFsignalVsP"))->Fill(daug[1].P(), trkDaug2.tofSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFnSigmaVsP"))->Fill(daug[1].P(), trkDaug2.tofNSigmaEl()); + } + } + if (isElMuPion) { + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsP"))->Fill(daug[1].P(), trkDaug2.tpcNSigmaEl()); + if (trkDaug2.hasTOF()) { + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsP"))->Fill(daug[1].P(), trkDaug2.tofSignal()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsP"))->Fill(daug[1].P(), trkDaug2.tofNSigmaEl()); + } + } + } + if (trkDaug1.hasTPC() && trkDaug2.hasTPC()) { + if ((doprocessDataDG || doprocessDataSG) && isElEl) { + if (daug[0].P() > daug[1].P()) { + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsLP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsOP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCnSigmaVsLP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaEl()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCnSigmaVsOP"))->Fill(daug[1].P(), trkDaug2.tpcNSigmaEl()); + if (trkDaug1.hasTOF()) { + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFsignalVsLP"))->Fill(daug[0].P(), trkDaug1.tofSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFnSigmaVsLP"))->Fill(daug[0].P(), trkDaug1.tofNSigmaEl()); + } + if (trkDaug2.hasTOF()) { + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFsignalVsOP"))->Fill(daug[1].P(), trkDaug2.tofSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFnSigmaVsOP"))->Fill(daug[1].P(), trkDaug2.tofNSigmaEl()); + } + } else { + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsOP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsLP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCnSigmaVsOP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaEl()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCnSigmaVsLP"))->Fill(daug[1].P(), trkDaug2.tpcNSigmaEl()); + if (trkDaug1.hasTOF()) { + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFsignalVsOP"))->Fill(daug[0].P(), trkDaug1.tofSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFnSigmaVsOP"))->Fill(daug[0].P(), trkDaug1.tofNSigmaEl()); + } + if (trkDaug2.hasTOF()) { + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFsignalVsLP"))->Fill(daug[1].P(), trkDaug2.tofSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFnSigmaVsLP"))->Fill(daug[1].P(), trkDaug2.tofNSigmaEl()); + } + } + } + if ((doprocessDataSG || doprocessDataDG) && isElMuPion) { + double electronPt = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug1) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? daug[0].Pt() : daug[1].Pt(); + double electronPID = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug1) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? trkDaug1.tpcSignal() : trkDaug2.tpcSignal(); + double electronNsigmaEl = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug1) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? trkDaug1.tpcNSigmaEl() : trkDaug2.tpcNSigmaEl(); + double electronNsigmaPi = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug1) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? trkDaug1.tpcNSigmaPi() : trkDaug2.tpcNSigmaPi(); + double otherPt = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug2) : enumMyParticle(trackPDG(trkDaug2, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? daug[0].Pt() : daug[1].Pt(); + double otherPID = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug2) : enumMyParticle(trackPDG(trkDaug2, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? trkDaug1.tpcSignal() : trkDaug2.tpcSignal(); + double otherNsigmaMu = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug2) : enumMyParticle(trackPDG(trkDaug2, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? trkDaug1.tpcNSigmaMu() : trkDaug2.tpcNSigmaMu(); + double otherNsigmaPi = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug2) : enumMyParticle(trackPDG(trkDaug2, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? trkDaug1.tpcNSigmaPi() : trkDaug2.tpcNSigmaPi(); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCsignalVsEPofE"))->Fill(electronPt, electronPID); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCsignalVsOPofO"))->Fill(otherPt, otherPID); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsEPofE"))->Fill(electronPt, electronNsigmaEl); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsMPofO"))->Fill(otherPt, otherNsigmaMu); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsPPofO"))->Fill(otherPt, otherNsigmaPi); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaEvsnSigmaPofE"))->Fill(electronNsigmaEl, electronNsigmaPi); + if (trkDaug1.hasTOF()) { + if (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug1) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) { + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsEPofE"))->Fill(electronPt, trkDaug1.tofSignal()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsEPofE"))->Fill(electronPt, trkDaug1.tofNSigmaEl()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaEvsnSigmaPofE"))->Fill(trkDaug1.tofNSigmaEl(), trkDaug1.tofNSigmaPi()); + } else { + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsOPofO"))->Fill(otherPt, trkDaug1.tofSignal()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsMPofO"))->Fill(otherPt, trkDaug1.tofNSigmaMu()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsPPofO"))->Fill(otherPt, trkDaug1.tofNSigmaPi()); + } + } + if (trkDaug2.hasTOF()) { + if (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug2) : enumMyParticle(trackPDG(trkDaug2, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) { + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsEPofE"))->Fill(electronPt, trkDaug2.tofSignal()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsEPofE"))->Fill(electronPt, trkDaug2.tofNSigmaEl()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaEvsnSigmaPofE"))->Fill(trkDaug2.tofNSigmaEl(), trkDaug2.tofNSigmaPi()); + } else { + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsOPofO"))->Fill(otherPt, trkDaug2.tofSignal()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsMPofO"))->Fill(otherPt, trkDaug2.tofNSigmaMu()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsPPofO"))->Fill(otherPt, trkDaug2.tofNSigmaPi()); + } + } + } + } + } else { + printDebugMessage("Other particles"); + } + + } // end fillPIDhistograms + + void fillMCPIDhistograms(FullMCUDTracks const& reconstructedBarrelTracks) + { + + int countPVGTselected = 0; + int countPVGTelectrons = 0; + int countPVGTmuons = 0; + int countPVGTpions = 0; + int countPVGTelmupiAlt = 0; + int countPVGTelectronsAlt = 0; + int countPVGTmupionsAlt = 0; + std::vector vecPVidx; + std::vector vecPVnewPIDidx; + // Loop over tracks with selections + for (const auto& track : reconstructedBarrelTracks) { + if (!track.isPVContributor()) + continue; + if (cutGlobalTrack.applyGlobalTrackSelection && !isGlobalTrackReinstatement(track)) + continue; + int hypothesisID = testPIDhypothesis(track, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC); + if (hypothesisID == P_ELECTRON || hypothesisID == P_MUON || hypothesisID == P_PION) { + countPVGTselected++; + vecPVidx.push_back(track.index()); + if (hypothesisID == P_ELECTRON) { + countPVGTelectrons++; + } else if (hypothesisID == P_MUON) { + countPVGTmuons++; + } else { + countPVGTpions++; + } + } + // alternative selection + if (isElectronCandidate(track)) { + countPVGTelmupiAlt++; + countPVGTelectronsAlt++; + vecPVnewPIDidx.push_back(track.index()); + } + if (isMuPionCandidate(track)) { + countPVGTelmupiAlt++; + countPVGTmupionsAlt++; + vecPVnewPIDidx.push_back(track.index()); + } + + } // Loop over tracks with selections + + bool isTwoSelectedTracks = (cutTauEvent.useThresholdsPID ? countPVGTelmupiAlt == 2 : countPVGTselected == 2); + bool isElEl = (cutTauEvent.useThresholdsPID ? countPVGTelectronsAlt == 2 : countPVGTelectrons == 2); + bool isElMuPion = (cutTauEvent.useThresholdsPID ? (countPVGTelectronsAlt == 1 && countPVGTmupionsAlt == 1) : ((countPVGTelectrons == 1 && countPVGTmuons == 1) || (countPVGTelectrons == 1 && countPVGTpions == 1))); + if (isTwoSelectedTracks && doTwoTracks) { + TLorentzVector daug[2]; + const auto& trkDaug1 = reconstructedBarrelTracks.iteratorAt(cutTauEvent.useThresholdsPID ? vecPVnewPIDidx[0] : vecPVidx[0]); + const auto& trkDaug2 = reconstructedBarrelTracks.iteratorAt(cutTauEvent.useThresholdsPID ? vecPVnewPIDidx[1] : vecPVidx[1]); + daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(pdg->Mass(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)), trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(pdg->Mass(trackPDG(trkDaug2, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)), trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + if (cutTauEvent.applyTauEventSelection && !selectedTauEvent(trkDaug1, trkDaug2)) { + return; + } + if (cutTauEvent.useThresholdsPID) { + if (isElectronCandidate(trkDaug1)) + daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(MassElectron, trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + if (isElectronCandidate(trkDaug2)) + daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(MassElectron, trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + if (isMuPionCandidate(trkDaug1)) + daug[0].SetPxPyPzE(trkDaug1.px(), trkDaug1.py(), trkDaug1.pz(), energy(MassPionCharged, trkDaug1.px(), trkDaug1.py(), trkDaug1.pz())); + if (isMuPionCandidate(trkDaug2)) + daug[1].SetPxPyPzE(trkDaug2.px(), trkDaug2.py(), trkDaug2.pz(), energy(MassPionCharged, trkDaug2.px(), trkDaug2.py(), trkDaug2.pz())); + } + if (trkDaug1.hasTPC() && trkDaug2.hasTPC()) { + if ((doprocessMCgen || doprocessMCrecSG || doprocessMCrecDG) && isElEl) { + if (daug[0].P() > daug[1].P()) { + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsLP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsOP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCnSigmaVsLP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaEl()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCnSigmaVsOP"))->Fill(daug[1].P(), trkDaug2.tpcNSigmaEl()); + if (trkDaug1.hasTOF()) { + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFsignalVsLP"))->Fill(daug[0].P(), trkDaug1.tofSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFnSigmaVsLP"))->Fill(daug[0].P(), trkDaug1.tofNSigmaEl()); + } + if (trkDaug2.hasTOF()) { + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFsignalVsOP"))->Fill(daug[1].P(), trkDaug2.tofSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFnSigmaVsOP"))->Fill(daug[1].P(), trkDaug2.tofNSigmaEl()); + } + } else { + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsOP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsLP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCnSigmaVsOP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaEl()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTPCnSigmaVsLP"))->Fill(daug[1].P(), trkDaug2.tpcNSigmaEl()); + if (trkDaug1.hasTOF()) { + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFsignalVsOP"))->Fill(daug[0].P(), trkDaug1.tofSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFnSigmaVsOP"))->Fill(daug[0].P(), trkDaug1.tofNSigmaEl()); + } + if (trkDaug2.hasTOF()) { + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFsignalVsLP"))->Fill(daug[1].P(), trkDaug2.tofSignal()); + histos.get(HIST("EventTwoTracks/TwoElectrons/PID/hTOFnSigmaVsLP"))->Fill(daug[1].P(), trkDaug2.tofNSigmaEl()); + } + } + } + if ((doprocessMCgen || doprocessMCrecSG || doprocessMCrecDG) && isElMuPion) { + int pid = 0; + if (trkDaug1.has_udMcParticle()) { + const auto& part = trkDaug1.udMcParticle(); + pid = std::abs(part.pdgCode()); + if (pid == 11) { + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/mcTruth/nSigmaTPC1"))->Fill(trkDaug1.pt(), trkDaug1.tpcNSigmaEl(), 1.); + } else { + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/mcTruth/nSigmaTPC2"))->Fill(trkDaug1.pt(), trkDaug1.tpcNSigmaEl(), 1.); + } + } + if (trkDaug2.has_udMcParticle()) { + const auto& part = trkDaug2.udMcParticle(); + pid = std::abs(part.pdgCode()); + if (pid == 11) { + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/mcTruth/nSigmaTPC1"))->Fill(trkDaug2.pt(), trkDaug2.tpcNSigmaEl(), 1.); + } else { + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/mcTruth/nSigmaTPC2"))->Fill(trkDaug2.pt(), trkDaug2.tpcNSigmaEl(), 1.); + } + } + bool isNotTrueElectron = false; + if (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug1) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) { + if (trkDaug1.has_udMcParticle()) { + const auto& particle = trkDaug1.udMcParticle(); + if (enumMyParticle(particle.pdgCode()) != P_ELECTRON) + isNotTrueElectron = true; + } + } else { + if (trkDaug2.has_udMcParticle()) { + const auto& particle = trkDaug2.udMcParticle(); + if (enumMyParticle(particle.pdgCode()) != P_ELECTRON) + isNotTrueElectron = true; + } + } + if (oppositeMCtrueElectronCheck) { + if (doMCtrueElectronCheck && !isNotTrueElectron) + return; + } else { + if (doMCtrueElectronCheck && isNotTrueElectron) + return; + } + + double electronPt = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug1) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? daug[0].Pt() : daug[1].Pt(); + double electronPID = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug1) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? trkDaug1.tpcSignal() : trkDaug2.tpcSignal(); + double electronNsigmaEl = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug1) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? trkDaug1.tpcNSigmaEl() : trkDaug2.tpcNSigmaEl(); + double electronNsigmaPi = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug1) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? trkDaug1.tpcNSigmaPi() : trkDaug2.tpcNSigmaPi(); + double otherPt = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug2) : enumMyParticle(trackPDG(trkDaug2, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? daug[0].Pt() : daug[1].Pt(); + double otherPID = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug2) : enumMyParticle(trackPDG(trkDaug2, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? trkDaug1.tpcSignal() : trkDaug2.tpcSignal(); + double otherNsigmaEl = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug2) : enumMyParticle(trackPDG(trkDaug2, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? trkDaug1.tpcNSigmaEl() : trkDaug2.tpcNSigmaEl(); + double otherNsigmaMu = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug2) : enumMyParticle(trackPDG(trkDaug2, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? trkDaug1.tpcNSigmaMu() : trkDaug2.tpcNSigmaMu(); + double otherNsigmaPi = (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug2) : enumMyParticle(trackPDG(trkDaug2, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) ? trkDaug1.tpcNSigmaPi() : trkDaug2.tpcNSigmaPi(); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCsignalVsEPofE"))->Fill(electronPt, electronPID); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsEPofE"))->Fill(electronPt, electronNsigmaEl); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsPPofE"))->Fill(electronPt, electronNsigmaPi); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaEvsnSigmaPofE"))->Fill(electronNsigmaEl, electronNsigmaPi); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCsignalVsOPofO"))->Fill(otherPt, otherPID); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsEPofO"))->Fill(otherPt, otherNsigmaEl); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsMPofO"))->Fill(otherPt, otherNsigmaMu); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsPPofO"))->Fill(otherPt, otherNsigmaPi); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaEvsnSigmaPofO"))->Fill(otherNsigmaEl, otherNsigmaPi); + if (trkDaug1.hasTOF()) { + if (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug1) : enumMyParticle(trackPDG(trkDaug1, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) { + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsEPofE"))->Fill(electronPt, trkDaug1.tofSignal()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsEPofE"))->Fill(electronPt, trkDaug1.tofNSigmaEl()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsPPofE"))->Fill(electronPt, trkDaug1.tofNSigmaPi()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaEvsnSigmaPofE"))->Fill(trkDaug1.tofNSigmaEl(), trkDaug1.tofNSigmaPi()); + } else { + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsOPofO"))->Fill(otherPt, trkDaug1.tofSignal()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsEPofO"))->Fill(otherPt, trkDaug1.tofNSigmaEl()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsMPofO"))->Fill(otherPt, trkDaug1.tofNSigmaMu()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsPPofO"))->Fill(otherPt, trkDaug1.tofNSigmaPi()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaEvsnSigmaPofO"))->Fill(trkDaug1.tofNSigmaEl(), trkDaug1.tofNSigmaPi()); + } + } + if (trkDaug2.hasTOF()) { + if (cutTauEvent.useThresholdsPID ? isElectronCandidate(trkDaug2) : enumMyParticle(trackPDG(trkDaug2, cutPID.cutSiTPC, cutPID.cutSiTOF, cutPID.usePIDwTOF, cutPID.useScutTOFinTPC)) == P_ELECTRON) { + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsEPofE"))->Fill(electronPt, trkDaug2.tofSignal()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsEPofE"))->Fill(electronPt, trkDaug2.tofNSigmaEl()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsPPofE"))->Fill(electronPt, trkDaug2.tofNSigmaPi()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaEvsnSigmaPofE"))->Fill(trkDaug2.tofNSigmaEl(), trkDaug2.tofNSigmaPi()); + } else { + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsOPofO"))->Fill(otherPt, trkDaug2.tofSignal()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsEPofO"))->Fill(otherPt, trkDaug2.tofNSigmaEl()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsMPofO"))->Fill(otherPt, trkDaug2.tofNSigmaMu()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsPPofO"))->Fill(otherPt, trkDaug2.tofNSigmaPi()); + histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaEvsnSigmaPofO"))->Fill(trkDaug2.tofNSigmaEl(), trkDaug2.tofNSigmaPi()); + } + } + } + } + } + + } // end fillMCPIDhistograms + + template + void fillFIThistograms(C const& reconstructedCollision) + { + + histos.get(HIST("Events/FIT/hAmplitudeFT0A"))->Fill(reconstructedCollision.totalFT0AmplitudeA()); + histos.get(HIST("Events/FIT/hAmplitudeFT0C"))->Fill(reconstructedCollision.totalFT0AmplitudeC()); + histos.get(HIST("Events/FIT/hAmplitudeFDDA"))->Fill(reconstructedCollision.totalFDDAmplitudeA()); + histos.get(HIST("Events/FIT/hAmplitudeFDDC"))->Fill(reconstructedCollision.totalFDDAmplitudeC()); + histos.get(HIST("Events/FIT/hAmplitudeFV0A"))->Fill(reconstructedCollision.totalFV0AmplitudeA()); + + histos.get(HIST("Events/FIT/hTimeFT0A"))->Fill(reconstructedCollision.timeFT0A()); + histos.get(HIST("Events/FIT/hTimeFT0C"))->Fill(reconstructedCollision.timeFT0C()); + histos.get(HIST("Events/FIT/hTimeFDDA"))->Fill(reconstructedCollision.timeFDDA()); + histos.get(HIST("Events/FIT/hTimeFDDC"))->Fill(reconstructedCollision.timeFDDC()); + histos.get(HIST("Events/FIT/hTimeFV0A"))->Fill(reconstructedCollision.timeFV0A()); + + histos.get(HIST("Events/FIT/hTimeFT0AvsFT0C"))->Fill(reconstructedCollision.timeFT0A(), reconstructedCollision.timeFT0C()); + histos.get(HIST("Events/FIT/hTimeFT0CvsFDDA"))->Fill(reconstructedCollision.timeFT0C(), reconstructedCollision.timeFDDA()); + histos.get(HIST("Events/FIT/hTimeFDDAvsFDDC"))->Fill(reconstructedCollision.timeFDDA(), reconstructedCollision.timeFDDC()); + histos.get(HIST("Events/FIT/hTimeFDDCvsFV0A"))->Fill(reconstructedCollision.timeFDDC(), reconstructedCollision.timeFV0A()); + histos.get(HIST("Events/FIT/hTimeFV0AvsFT0A"))->Fill(reconstructedCollision.timeFV0A(), reconstructedCollision.timeFT0A()); + } + + void fillTruthHistograms(aod::UDMcParticles const& particles) + { + histos.get(HIST("Events/Truth/hCountCollisions"))->Fill(1); + histos.get(HIST("Events/Truth/hNparticles"))->Fill(particles.size()); + histos.get(HIST("Events/Truth/hNphysPartVsNwoutMotherParts"))->Fill(countPhysicalPrimary(particles), countParticlesWithoutMother(particles)); + + int countElectrons = 0; + int countMuons = 0; + int countPions = 0; + + for (const auto& particle : particles) { + histos.get(HIST("Events/Truth/hPDGcodesAll"))->Fill(particle.pdgCode()); + // if (!particle.isPhysicalPrimary()) continue; + if (particle.has_mothers()) + continue; + histos.get(HIST("Events/Truth/hPDGcodesNoMother"))->Fill(particle.pdgCode()); + histos.get(HIST("Tracks/Truth/hTauPt"))->Fill(pt(particle.px(), particle.py())); + histos.get(HIST("Tracks/Truth/hTauP"))->Fill(momentum(particle.px(), particle.py(), particle.pz())); + histos.get(HIST("Tracks/Truth/hTauPhi"))->Fill(phi(particle.px(), particle.py())); + histos.get(HIST("Tracks/Truth/hTauEta"))->Fill(eta(particle.px(), particle.py(), particle.pz())); + const auto& daughters = particle.daughters_as(); + histos.get(HIST("Events/Truth/hNtauDaughters"))->Fill(daughters.size()); + for (const auto& daughter : daughters) { + histos.get(HIST("Events/Truth/hPDGcodesTauDaughters"))->Fill(daughter.pdgCode()); + if (enumMyParticle(daughter.pdgCode()) == P_ELECTRON) { + countElectrons++; + histos.get(HIST("Tracks/Truth/hElectronPt"))->Fill(pt(daughter.px(), daughter.py())); + histos.get(HIST("Tracks/Truth/hElectronP"))->Fill(momentum(daughter.px(), daughter.py(), daughter.pz())); + histos.get(HIST("Tracks/Truth/hElectronPhi"))->Fill(phi(daughter.px(), daughter.py())); + histos.get(HIST("Tracks/Truth/hElectronEta"))->Fill(eta(daughter.px(), daughter.py(), daughter.pz())); + } + if (enumMyParticle(daughter.pdgCode()) == P_MUON) { + countMuons++; + histos.get(HIST("Tracks/Truth/hMuonPt"))->Fill(pt(daughter.px(), daughter.py())); + histos.get(HIST("Tracks/Truth/hMuonP"))->Fill(momentum(daughter.px(), daughter.py(), daughter.pz())); + histos.get(HIST("Tracks/Truth/hMuonPhi"))->Fill(phi(daughter.px(), daughter.py())); + histos.get(HIST("Tracks/Truth/hMuonEta"))->Fill(eta(daughter.px(), daughter.py(), daughter.pz())); + } + if (enumMyParticle(daughter.pdgCode()) == P_PION) { + countPions++; + histos.get(HIST("Tracks/Truth/hPionPt"))->Fill(pt(daughter.px(), daughter.py())); + histos.get(HIST("Tracks/Truth/hPionP"))->Fill(momentum(daughter.px(), daughter.py(), daughter.pz())); + histos.get(HIST("Tracks/Truth/hPionPhi"))->Fill(phi(daughter.px(), daughter.py())); + histos.get(HIST("Tracks/Truth/hPionEta"))->Fill(eta(daughter.px(), daughter.py(), daughter.pz())); + } + } + } + + histos.get(HIST("Events/Truth/hNelectrons"))->Fill(countElectrons); + histos.get(HIST("Events/Truth/hNmuons"))->Fill(countMuons); + histos.get(HIST("Events/Truth/hNpions"))->Fill(countPions); + + if (countElectrons == 2 && countMuons == 0 && countPions == 0) + histos.get(HIST("Events/Truth/hChannels"))->Fill(CH_EE); + if (countElectrons == 1 && countMuons == 1 && countPions == 0) + histos.get(HIST("Events/Truth/hChannels"))->Fill(CH_EMU); + if (countElectrons == 1 && countMuons == 0 && countPions == 1) + histos.get(HIST("Events/Truth/hChannels"))->Fill(CH_EPI); + if ((countElectrons == 1 && countMuons == 1 && countPions == 0) || (countElectrons == 1 && countMuons == 0 && countPions == 1)) + histos.get(HIST("Events/Truth/hChannels"))->Fill(CH_EMUPI); + if (countElectrons == 0 && countMuons == 2 && countPions == 0) + histos.get(HIST("Events/Truth/hChannels"))->Fill(CH_MUMU); + if (countElectrons == 0 && countMuons == 1 && countPions == 1) + histos.get(HIST("Events/Truth/hChannels"))->Fill(CH_MUPI); + if (countElectrons == 0 && countMuons == 0 && countPions == 2) + histos.get(HIST("Events/Truth/hChannels"))->Fill(CH_PIPI); + if (countElectrons == 0 && countMuons == 0 && countPions == 4) + histos.get(HIST("Events/Truth/hChannels"))->Fill(CH_FOURPI); + if (countElectrons == 1 && countMuons == 0 && countPions == 3) + histos.get(HIST("Events/Truth/hChannels"))->Fill(CH_ETHREEPI); + if (countElectrons == 0 && countMuons == 1 && countPions == 3) + histos.get(HIST("Events/Truth/hChannels"))->Fill(CH_MUTHREEPI); + if (countElectrons == 0 && countMuons == 0 && countPions == 6) + histos.get(HIST("Events/Truth/hChannels"))->Fill(CH_SIXPI); + } + + template + void outputTauEventCandidates(C const& collision, Ts const& tracks) + { + + int countTracksPerCollision = 0; + int countGoodNonPVtracks = 0; + int countGoodPVtracks = 0; + std::vector vecTrkIdx; + // Loop over tracks with selections + for (const auto& track : tracks) { + countTracksPerCollision++; + if (!isGlobalTrackReinstatement(track)) + continue; + if (!track.isPVContributor()) { + countGoodNonPVtracks++; + continue; + } + countGoodPVtracks++; + vecTrkIdx.push_back(track.index()); + } // Loop over tracks with selections + + // Apply weak condition on track PID + int countPVGTel = 0; + int countPVGTmupi = 0; + if (countGoodPVtracks == 2) { + for (const auto& vecMember : vecTrkIdx) { + const auto& thisTrk = tracks.iteratorAt(vecMember); + if (isElectronCandidate(thisTrk)) { + countPVGTel++; + continue; + } + if (isMuPionCandidate(thisTrk)) { + countPVGTmupi++; + } + } + } + + if (cutPreselect.cutCanUseTrackPID ? ((countPVGTel == 2 && countPVGTmupi == 0) || (countPVGTel == 1 && countPVGTmupi == 1)) : countGoodPVtracks == cutPreselect.cutCanNgoodPVtracs) { + const auto& trk1 = tracks.iteratorAt(vecTrkIdx[0]); + const auto& trk2 = tracks.iteratorAt(vecTrkIdx[1]); + + float px[2] = {trk1.px(), trk2.px()}; + float py[2] = {trk1.py(), trk2.py()}; + float pz[2] = {trk1.pz(), trk2.pz()}; + int sign[2] = {trk1.sign(), trk2.sign()}; + float dcaxy[2] = {trk1.dcaXY(), trk2.dcaXY()}; + float dcaz[2] = {trk1.dcaZ(), trk2.dcaZ()}; + float trkTimeRes[2] = {trk1.trackTimeRes(), trk2.trackTimeRes()}; + uint32_t itsClusterSizesTrk1 = trk1.itsClusterSizes(); + uint32_t itsClusterSizesTrk2 = trk2.itsClusterSizes(); + float tpcSignal[2] = {trk1.tpcSignal(), trk2.tpcSignal()}; + float tpcEl[2] = {trk1.tpcNSigmaEl(), trk2.tpcNSigmaEl()}; + float tpcMu[2] = {trk1.tpcNSigmaMu(), trk2.tpcNSigmaMu()}; + float tpcPi[2] = {trk1.tpcNSigmaPi(), trk2.tpcNSigmaPi()}; + float tpcKa[2] = {trk1.tpcNSigmaKa(), trk2.tpcNSigmaKa()}; + float tpcPr[2] = {trk1.tpcNSigmaPr(), trk2.tpcNSigmaPr()}; + float tpcIP[2] = {trk1.tpcInnerParam(), trk2.tpcInnerParam()}; + float tofSignal[2] = {trk1.tofSignal(), trk2.tofSignal()}; + float tofEl[2] = {trk1.tofNSigmaEl(), trk2.tofNSigmaEl()}; + float tofMu[2] = {trk1.tofNSigmaMu(), trk2.tofNSigmaMu()}; + float tofPi[2] = {trk1.tofNSigmaPi(), trk2.tofNSigmaPi()}; + float tofKa[2] = {trk1.tofNSigmaKa(), trk2.tofNSigmaKa()}; + float tofPr[2] = {trk1.tofNSigmaPr(), trk2.tofNSigmaPr()}; + float tofEP[2] = {trk1.tofExpMom(), trk2.tofExpMom()}; + float ZNinfo[4] = {-999., -999., -999., -999.}; + if constexpr (requires { collision.udZdcsReduced(); }) { + ZNinfo[0] = collision.energyCommonZNA(); + ZNinfo[1] = collision.energyCommonZNC(); + ZNinfo[2] = collision.timeZNA(); + ZNinfo[3] = collision.timeZNC(); + } + + tauTwoTracks(collision.runNumber(), collision.globalBC(), countTracksPerCollision, collision.numContrib(), countGoodNonPVtracks, collision.posX(), collision.posY(), collision.posZ(), + collision.flags(), collision.occupancyInTime(), collision.hadronicRate(), collision.trs(), collision.trofs(), collision.hmpr(), + collision.tfb(), collision.itsROFb(), collision.sbp(), collision.zVtxFT0vPV(), collision.vtxITSTPC(), + collision.totalFT0AmplitudeA(), collision.totalFT0AmplitudeC(), collision.totalFV0AmplitudeA(), ZNinfo[0], ZNinfo[1], + collision.timeFT0A(), collision.timeFT0C(), collision.timeFV0A(), ZNinfo[2], ZNinfo[3], + px, py, pz, sign, dcaxy, dcaz, trkTimeRes, + itsClusterSizesTrk1, itsClusterSizesTrk2, + tpcSignal, tpcEl, tpcMu, tpcPi, tpcKa, tpcPr, tpcIP, + tofSignal, tofEl, tofMu, tofPi, tofKa, tofPr, tofEP); + } else { + // Store info on what would rejected events + bitsRejectTauEvent |= (1 << 0); + + int countTrksPerCol = 0; + int countNonPVtracks = 0; + int countBadTracks = 0; + // Loop over tracks with selections + for (const auto& track : tracks) { + countTrksPerCol++; + if (!isGlobalTrackReinstatement(track)) { + countBadTracks++; + } + if (!track.isPVContributor()) { + countNonPVtracks++; + } + } // Loop over tracks with selections + if (countTrksPerCol - countBadTracks != 2) + bitsRejectTauEvent |= (1 << 1); + if (countTrksPerCol - countNonPVtracks != 2) + bitsRejectTauEvent |= (1 << 2); + } + } + + template + void fillRejectionReasonDG(C const& collision) + { + if (!isGoodROFtime(collision)) + bitsRejection |= (1 << 1); + + if (!isGoodFITtime(collision, cutSample.cutFITtime)) + bitsRejection |= (1 << 2); + + if (cutSample.useNumContribs && (collision.numContrib() != cutSample.cutNumContribs)) + bitsRejection |= (1 << 3); + + if (cutSample.useRecoFlag && (collision.flags() != cutSample.cutRecoFlag)) + bitsRejection |= (1 << 4); + } + + template + void fillRejectionReasonSG(C const& collision) + { + int gapSide = collision.gapSide(); + + if (cutSample.useTrueGap) + gapSide = sgSelector.trueGap(collision, cutSample.cutTrueGapSideFV0, cutSample.cutTrueGapSideFT0A, cutSample.cutTrueGapSideFT0C, cutSample.cutTrueGapSideZDC); + + if (gapSide != cutSample.whichGapSide) + bitsRejection |= (1 << 0); + + if (!isGoodROFtime(collision)) + bitsRejection |= (1 << 1); + + if (!isGoodFITtime(collision, cutSample.cutFITtime)) + bitsRejection |= (1 << 2); + + if (cutSample.useNumContribs && (collision.numContrib() != cutSample.cutNumContribs)) + bitsRejection |= (1 << 3); + + if (cutSample.useRecoFlag && (collision.flags() != cutSample.cutRecoFlag)) + bitsRejection |= (1 << 4); + } + + template + void fillRejectionReasonMCSG(C const& collision) + { + if (collision.gapSide() != cutSample.whichGapSide) + bitsRejection |= (1 << 0); + + if (!isGoodROFtime(collision)) + bitsRejection |= (1 << 1); + + if (!isGoodFITtime(collision, cutSample.cutFITtime)) + bitsRejection |= (1 << 2); + + if (cutSample.useNumContribs && (collision.numContrib() != cutSample.cutNumContribs)) + bitsRejection |= (1 << 3); + + if (cutSample.useRecoFlag && (collision.flags() != cutSample.cutRecoFlag)) + bitsRejection |= (1 << 4); + } + + void processDataDG(FullUDCollision const& reconstructedCollision, + FullUDTracks const& reconstructedBarrelTracks) + { + fillRejectionReasonDG(reconstructedCollision); + outputGlobalRejectionHistogram(); + + if (!isGoodROFtime(reconstructedCollision)) + return; + + if (!isGoodFITtime(reconstructedCollision, cutSample.cutFITtime)) + return; + + if (cutSample.useNumContribs && (reconstructedCollision.numContrib() != cutSample.cutNumContribs)) + return; + + if (cutSample.useRecoFlag && (reconstructedCollision.flags() != cutSample.cutRecoFlag)) + return; + + if (doMainHistos) { + fillHistograms(reconstructedBarrelTracks); + fillFIThistograms(reconstructedCollision); + } + + if (doPIDhistos) + fillPIDhistograms(reconstructedCollision, reconstructedBarrelTracks); + + if (doOutputTauEvents) + outputTauEventCandidates(reconstructedCollision, reconstructedBarrelTracks); + + outputDetailedRejectionHistogram(); + + } // end processDataDG + + void processDataSG(FullSGUDCollision const& reconstructedCollision, + FullUDTracks const& reconstructedBarrelTracks) + { + fillRejectionReasonSG(reconstructedCollision); + outputGlobalRejectionHistogram(); + + int gapSide = reconstructedCollision.gapSide(); + int trueGapSide = sgSelector.trueGap(reconstructedCollision, cutSample.cutTrueGapSideFV0, cutSample.cutTrueGapSideFT0A, cutSample.cutTrueGapSideFT0C, cutSample.cutTrueGapSideZDC); + + if (cutSample.useTrueGap) + gapSide = trueGapSide; + + if (!isGoodROFtime(reconstructedCollision)) + return; + + if (gapSide != cutSample.whichGapSide) + return; + + if (!isGoodFITtime(reconstructedCollision, cutSample.cutFITtime)) + return; + + if (cutSample.useNumContribs && (reconstructedCollision.numContrib() != cutSample.cutNumContribs)) + return; + + if (cutSample.useRecoFlag && (reconstructedCollision.flags() != cutSample.cutRecoFlag)) + return; + + if (doMainHistos) { + histos.fill(HIST("Events/UDtableGapSide"), gapSide); + histos.fill(HIST("Events/TrueGapSideDiffToTableValue"), gapSide - trueGapSide); + fillHistograms(reconstructedBarrelTracks); + fillFIThistograms(reconstructedCollision); + } + + if (doPIDhistos) + fillPIDhistograms(reconstructedCollision, reconstructedBarrelTracks); + + if (doOutputTauEvents) + outputTauEventCandidates(reconstructedCollision, reconstructedBarrelTracks); + + outputDetailedRejectionHistogram(); + + } // end processDataSG + + void processMCrecDG(FullMCUDCollision const& reconstructedCollision, + FullMCUDTracks const& reconstructedBarrelTracks, + aod::UDMcParticles const&) + { + fillRejectionReasonDG(reconstructedCollision); + outputGlobalRejectionHistogram(); + + if (!isGoodROFtime(reconstructedCollision)) + return; + + if (!isGoodFITtime(reconstructedCollision, cutSample.cutFITtime)) + return; + + if (cutSample.useNumContribs && (reconstructedCollision.numContrib() != cutSample.cutNumContribs)) + return; + + if (cutSample.useRecoFlag && (reconstructedCollision.flags() != cutSample.cutRecoFlag)) + return; + + if (cutSample.applyAcceptanceSelection) { + for (const auto& track : reconstructedBarrelTracks) { + if (!track.isPVContributor()) + continue; + if (std::abs(eta(track.px(), track.py(), track.py())) > cutSample.cutTrackEta) + return; + } + } + + if (doMainHistos) { + fillHistograms(reconstructedBarrelTracks); + fillFIThistograms(reconstructedCollision); + } + + if (doPIDhistos) { + fillPIDhistograms(reconstructedCollision, reconstructedBarrelTracks); + fillMCPIDhistograms(reconstructedBarrelTracks); + } + + if (doOutputTauEvents) + outputTauEventCandidates(reconstructedCollision, reconstructedBarrelTracks); + + outputDetailedRejectionHistogram(); + + } // end processMCrecDG + + void processMCrecSG(FullMCSGUDCollision const& reconstructedCollision, + FullMCUDTracks const& reconstructedBarrelTracks, + aod::UDMcParticles const&) + { + fillRejectionReasonMCSG(reconstructedCollision); + outputGlobalRejectionHistogram(); + + int gapSide = reconstructedCollision.gapSide(); + + if (gapSide != cutSample.whichGapSide) + return; + + if (!isGoodROFtime(reconstructedCollision)) + return; + + if (!isGoodFITtime(reconstructedCollision, cutSample.cutFITtime)) + return; + + if (cutSample.useNumContribs && (reconstructedCollision.numContrib() != cutSample.cutNumContribs)) + return; + + if (cutSample.useRecoFlag && (reconstructedCollision.flags() != cutSample.cutRecoFlag)) + return; + + if (cutSample.applyAcceptanceSelection) { + for (const auto& track : reconstructedBarrelTracks) { + if (!track.isPVContributor()) + continue; + if (std::abs(eta(track.px(), track.py(), track.py())) > cutSample.cutTrackEta) + return; + } + } + + if (doMainHistos) { + histos.fill(HIST("Events/UDtableGapSide"), gapSide); + fillHistograms(reconstructedBarrelTracks); + fillFIThistograms(reconstructedCollision); + } + + if (doPIDhistos) { + fillPIDhistograms(reconstructedCollision, reconstructedBarrelTracks); + fillMCPIDhistograms(reconstructedBarrelTracks); + } + + if (doOutputTauEvents) + outputTauEventCandidates(reconstructedCollision, reconstructedBarrelTracks); + + outputDetailedRejectionHistogram(); + + } // end processMCrecDG + + void processMCgen(aod::UDMcCollision const& /*generatedCollision*/, + aod::UDMcParticles const& particles) + { + + if (cutSample.applyAcceptanceSelection) { + for (const auto& particle : particles) { + if (particle.has_mothers()) + continue; + // printLargeMessage(Form("GENE: eta %.3f cut %.2f",std::abs(eta(particle.px(), particle.py(), particle.py())),static_cast(cutTrackEta))); + if (std::abs(eta(particle.px(), particle.py(), particle.py())) > cutSample.cutTrackEta) + return; + } + } + + if (doTruthHistos) { + fillTruthHistograms(particles); + } + + } // end processMCgenDG + + PROCESS_SWITCH(UpcTauRl, processDataDG, "Iterate UD tables with measured data created by DG-Candidate-Producer.", false); + PROCESS_SWITCH(UpcTauRl, processDataSG, "Iterate UD tables with measured data created by SG-Candidate-Producer.", false); + PROCESS_SWITCH(UpcTauRl, processMCrecDG, "Iterate Monte Carlo UD tables with reconstructed data created by DG-Candidate-Producer. Similar to processDataDG but uses association to truth level.", false); + PROCESS_SWITCH(UpcTauRl, processMCrecSG, "Iterate Monte Carlo UD tables with reconstructed data created by SG-Candidate-Producer. Similar to processDataSG but uses association to truth level and trueGap is not available.", false); + PROCESS_SWITCH(UpcTauRl, processMCgen, "Iterate Monte Carlo UD tables with truth data.", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/upcTauTau13topo.cxx b/PWGUD/Tasks/upcTauTau13topo.cxx index 61e7feb9fc1..0d18b316b8b 100644 --- a/PWGUD/Tasks/upcTauTau13topo.cxx +++ b/PWGUD/Tasks/upcTauTau13topo.cxx @@ -9,17 +9,21 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // -// \brief tau tau analysis 1e+3pi topology -// \author Adam Matyja, adam.tomasz.matyja@cern.ch, adam.matryja@ifj.edu.pl -// \since January 2024 +/// \file upcTauTau13topo.cxx +/// \brief tau tau analysis 1e+3pi topology +/// \author Adam Matyja, adam.tomasz.matyja@cern.ch, adam.matryja@ifj.edu.pl +/// \since January 2024 // to run it execute: // copts="--configuration json://tautauConfig.json -b" // o2-analysis-ud-tautau13topo $copts > output.log #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" + +// #include "TDatabasePDG.h" // not recommended in o2 +#include "Framework/O2DatabasePDGPlugin.h" -#include "TDatabasePDG.h" #include "TLorentzVector.h" // #include "Common/DataModel/EventSelection.h" // #include "Common/DataModel/TrackSelectionTables.h" @@ -28,28 +32,123 @@ #include "PWGUD/DataModel/UDTables.h" #include "PWGUD/Core/UDHelpers.h" #include "PWGUD/Core/DGPIDSelector.h" +#include "PWGUD/Core/SGSelector.h" + +#include "Common/Core/RecoDecay.h" +// #include +#include "TPDGCode.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +// derived tables for tautau->4 (=1+3) tracks +namespace o2::aod +{ +namespace tau_tree +{ +// event info +DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); +DECLARE_SOA_COLUMN(Bc, bc, int); +DECLARE_SOA_COLUMN(TotalTracks, totalTracks, int); +DECLARE_SOA_COLUMN(NumContrib, numContrib, int); +// DECLARE_SOA_COLUMN(GlobalNonPVtracks, globalNonPVtracks, int); +// DECLARE_SOA_COLUMN(PosX, posX, float); +// DECLARE_SOA_COLUMN(PosY, posY, float); +DECLARE_SOA_COLUMN(PosZ, posZ, float); +DECLARE_SOA_COLUMN(FlagUPC, flagUPC, bool); +DECLARE_SOA_COLUMN(OccupancyInTime, occupancyInTime, int); +DECLARE_SOA_COLUMN(HadronicRate, hadronicRate, double); +DECLARE_SOA_COLUMN(Trs, trs, bool); +DECLARE_SOA_COLUMN(Trofs, trofs, bool); +DECLARE_SOA_COLUMN(Hmpr, hmpr, bool); +// DECLARE_SOA_COLUMN(Tfb, tfb, int); +// DECLARE_SOA_COLUMN(ItsRofb, itsRofb, int); +// DECLARE_SOA_COLUMN(Sbp, sbp, int); +// DECLARE_SOA_COLUMN(ZvtxFT0vsPv, zvtxFT0vsPv, int); +// DECLARE_SOA_COLUMN(VtxITSTPC, vtxITSTPC, int); +DECLARE_SOA_COLUMN(ZdcAenergy, zdcAenergy, float); +DECLARE_SOA_COLUMN(ZdcCenergy, zdcCenergy, float); +DECLARE_SOA_COLUMN(Qtot, qtot, int16_t); +// FIT info +DECLARE_SOA_COLUMN(TotalFT0AmplitudeA, totalFT0AmplitudeA, float); +DECLARE_SOA_COLUMN(TotalFT0AmplitudeC, totalFT0AmplitudeC, float); +DECLARE_SOA_COLUMN(TotalFV0AmplitudeA, totalFV0AmplitudeA, float); +// DECLARE_SOA_COLUMN(TimeFT0A, timeFT0A, float); +// DECLARE_SOA_COLUMN(TimeFT0C, timeFT0C, float); +// DECLARE_SOA_COLUMN(TimeFV0A, timeFV0A, float); +// tracks +DECLARE_SOA_COLUMN(TrkPx, trkPx, float[4]); +DECLARE_SOA_COLUMN(TrkPy, trkPy, float[4]); +DECLARE_SOA_COLUMN(TrkPz, trkPz, float[4]); +// DECLARE_SOA_COLUMN(TrkSign, trkSign, int[4]); +// DECLARE_SOA_COLUMN(TrkDCAxy, trkDCAxy, float[4]); +// DECLARE_SOA_COLUMN(TrkDCAz, trkDCAz, float[4]); +DECLARE_SOA_COLUMN(TrkTPCcr, trkTPCcr, int[4]); +DECLARE_SOA_COLUMN(TrkTPCsignal, trkTPCsignal, float[4]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaEl, trkTPCnSigmaEl, float[4]); +// DECLARE_SOA_COLUMN(TrkTPCnSigmaMu, trkTPCnSigmaMu, float[4]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaPi, trkTPCnSigmaPi, float[4]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaKa, trkTPCnSigmaKa, float[4]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaPr, trkTPCnSigmaPr, float[4]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaMu, trkTPCnSigmaMu, float[4]); +DECLARE_SOA_COLUMN(TrkTOFbeta, trkTOFbeta, float[4]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaEl, trkTOFnSigmaEl, float[4]); +// DECLARE_SOA_COLUMN(TrkTOFnSigmaMu, trkTOFnSigmaMu, float[4]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaPi, trkTOFnSigmaPi, float[4]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaKa, trkTOFnSigmaKa, float[4]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaPr, trkTOFnSigmaPr, float[4]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaMu, trkTOFnSigmaMu, float[4]); +DECLARE_SOA_COLUMN(TrkTOFchi2, trkTOFchi2, float[4]); + +} // end of namespace tau_tree +DECLARE_SOA_TABLE(TauFourTracks, "AOD", "TAUFOURTRACK", + tau_tree::RunNumber, tau_tree::Bc, tau_tree::TotalTracks, tau_tree::NumContrib, + // tau_tree::GlobalNonPVtracks, + // tau_tree::PosX, tau_tree::PosY, + tau_tree::PosZ, + tau_tree::FlagUPC, tau_tree::OccupancyInTime, tau_tree::HadronicRate, tau_tree::ZdcAenergy, tau_tree::ZdcCenergy, + tau_tree::Qtot, + tau_tree::Trs, tau_tree::Trofs, tau_tree::Hmpr, + // tau_tree::Tfb, tau_tree::ItsRofb, tau_tree::Sbp, tau_tree::ZvtxFT0vsPv, tau_tree::VtxITSTPC, + tau_tree::TotalFT0AmplitudeA, tau_tree::TotalFT0AmplitudeC, tau_tree::TotalFV0AmplitudeA, + // tau_tree::TimeFT0A, tau_tree::TimeFT0C, tau_tree::TimeFV0A, + tau_tree::TrkPx, tau_tree::TrkPy, tau_tree::TrkPz, + // tau_tree::TrkSign, + // tau_tree::TrkDCAxy, tau_tree::TrkDCAz, + tau_tree::TrkTPCcr, + tau_tree::TrkTPCsignal, tau_tree::TrkTPCnSigmaEl, tau_tree::TrkTPCnSigmaPi, tau_tree::TrkTPCnSigmaKa, tau_tree::TrkTPCnSigmaPr, tau_tree::TrkTPCnSigmaMu, + tau_tree::TrkTOFbeta, tau_tree::TrkTOFnSigmaEl, tau_tree::TrkTOFnSigmaPi, tau_tree::TrkTOFnSigmaKa, tau_tree::TrkTOFnSigmaPr, tau_tree::TrkTOFnSigmaMu, + tau_tree::TrkTOFchi2); + +} // end of namespace o2::aod struct TauTau13topo { + Produces tauFourTracks; + SGSelector sgSelector; // configurables - ConfigurableAxis ptAxis{"pAxis", {100, 0., 5.}, "#it{p} (GeV/#it{c})"}; - ConfigurableAxis etaAxis{"etaAxis", {100, -2., 2.}, "#eta"}; + Configurable cutFV0{"cutFV0", 10000., "FV0A threshold"}; + Configurable cutFT0A{"cutFT0A", 150., "FT0A threshold"}; + Configurable cutFT0C{"cutFT0C", 50., "FT0C threshold"}; + Configurable cutZDC{"cutZDC", 10000., "ZDC threshold"}; + Configurable mGapSide{"mGapSide", 2, "gap selection"}; + // ConfigurableAxis ptAxis{"pAxis", {100, 0., 5.}, "#it{p} (GeV/#it{c})"}; + ConfigurableAxis ptAxis{"ptAxis", {120, 0., 4.}, "#it{p} (GeV/#it{c})"}; + // ConfigurableAxis etaAxis{"etaAxis", {100, -2., 2.}, "#eta"}; ConfigurableAxis dedxAxis{"dedxAxis", {100, 20., 160.}, "dE/dx"}; - ConfigurableAxis minvAxis{"MinvAxis", {100, 0., 2.5}, "M_{inv} (GeV/#it{c}^{2})"}; - ConfigurableAxis phiAxis{"phiAxis", {100, 0., 3.2}, "#phi"}; - ConfigurableAxis vectorAxis{"vectorAxis", {100, 0., 2.}, "A_{V}"}; - ConfigurableAxis scalarAxis{"scalarAxis", {100, -1., 1.}, "A_{S}"}; - Configurable verbose{"Verbose", {}, "Additional print outs"}; + ConfigurableAxis minvAxis{"minvAxis", {100, 0.4, 3.5}, "M_{inv} (GeV/#it{c}^{2})"}; + ConfigurableAxis phiAxis{"phiAxis", {120, 0., 3.2}, "#phi"}; + // ConfigurableAxis vectorAxis{"vectorAxis", {100, 0., 2.}, "A_{V}"}; + // ConfigurableAxis scalarAxis{"scalarAxis", {100, -1., 1.}, "A_{S}"}; + Configurable verbose{"verbose", {}, "Additional print outs"}; // cut selection configurables - Configurable zvertexcut{"Zvertexcut", 15., "Z vertex cut"}; - Configurable trkEtacut{"TrkEtacut", 1.5, "max track eta cut"}; - Configurable sameSign{"sameSign", {}, "Switch: same(true) or opposite(false) sign"}; - Configurable ptTotcut{"PtTotcut", 0.15, "min pt of all 4 tracks cut"}; + Configurable zvertexcut{"zvertexcut", 10., "Z vertex cut"}; + Configurable trkEtacut{"trkEtacut", 0.9, "max track eta cut"}; + Configurable sameSign{"sameSign", {}, "Switch: same (true) - BG or opposite (false) - SIGNAL sign"}; + Configurable ptTotcut{"ptTotcut", 0.15, "min pt of all 4 tracks cut"}; Configurable minAnglecut{"minAnglecut", 0.05, "min angle between tracks cut"}; Configurable minNsigmaElcut{"minNsigmaElcut", -2., "min Nsigma for Electrons cut"}; Configurable maxNsigmaElcut{"maxNsigmaElcut", 3., "max Nsigma for Electrons cut"}; @@ -57,227 +156,1545 @@ struct TauTau13topo { Configurable maxNsigmaPrVetocut{"maxNsigmaPrVetocut", 3., "max Nsigma for Proton veto cut"}; Configurable maxNsigmaKaVetocut{"maxNsigmaKaVetocut", 3., "max Nsigma for Kaon veto cut"}; Configurable minPtEtrkcut{"minPtEtrkcut", 0.25, "min Pt for El track cut"}; - Configurable FITvetoFlag{"FITvetoFlag", {}, "To apply FIT veto"}; - Configurable FITvetoWindow{"FITvetoWindow", 1, "FIT veto window"}; + Configurable mFITvetoFlag{"mFITvetoFlag", true, "To apply FIT veto"}; + Configurable mFITvetoWindow{"mFITvetoWindow", 2, "FIT veto window"}; + Configurable useFV0ForVeto{"useFV0ForVeto", 0, "use FV0 for veto"}; + Configurable useFDDAForVeto{"useFDDAForVeto", 0, "use FDDA for veto"}; + Configurable useFDDCForVeto{"useFDDCForVeto", 0, "use FDDC for veto"}; + Configurable nTofTrkMinCut{"nTofTrkMinCut", 1, "min TOF tracks"}; + + Configurable invMass3piSignalRegion{"invMass3piSignalRegion", 1, "1-use inv mass 3pi in signal region, 0-in background region"}; + Configurable invMass3piMaxcut{"invMass3piMaxcut", 1.8, "Z invariant mass of 3 pi cut"}; + Configurable deltaPhiMincut{"deltaPhiMincut", 0., "delta phi electron - 3 pi direction cut"}; + Configurable nTPCcrossedRowsMinCut{"nTPCcrossedRowsMinCut", 50, "min N_crossed TPC rows for electron candidate"}; + Configurable nSigma3piMaxCut{"nSigma3piMaxCut", 5., "n sigma 3 pi max cut"}; + Configurable whichPIDCut{"whichPIDCut", 1., "type of PID selection: 1-TPC,2-sigma(TPC+TOF),3-hardcoded ptCut,default=1"}; + + Configurable generatorIDMC{"generatorIDMC", -1, "MC generator ID"}; + Configurable removeNoTOFrunsInData{"removeNoTOFrunsInData", 1, "1-remove or 0-keep no TOF runs"}; + Configurable occupancyCut{"occupancyCut", 10000., "occupancy cut"}; + + // Configurable DGactive{"DGactive", false, "Switch on DGproducer"}; + // Configurable SGactive{"SGactive", true, "Switch on SGproducer"}; + // a pdg object - TDatabasePDG* pdg = nullptr; + // TDatabasePDG* pdg = nullptr; //not recommended + // Service pdg; // initialize histogram registry HistogramRegistry registry{ "registry", {}}; + HistogramRegistry registryMC{ + "registryMC", + {}}; + HistogramRegistry registry1MC{ + "registry1MC", + {}}; + + HistogramRegistry registrySkim{ + "registrySkim", + {}}; + void init(InitContext&) { - pdg = TDatabasePDG::Instance(); + // pdg = TDatabasePDG::Instance(); // dgcandidates histograms const AxisSpec axisp{100, 0., 5., "#it{p} (GeV/#it{c})"}; const AxisSpec axispt{ptAxis, "p_{T} axis"}; - const AxisSpec axiseta{etaAxis, "#eta - pseudo rapidity axis"}; + // const AxisSpec axiseta{etaAxis, "#eta - pseudo rapidity axis"}; + const AxisSpec axiseta{100, -2., 2., "#eta"}; const AxisSpec axisdedx{dedxAxis, "dEdx axis"}; const AxisSpec axisminv{minvAxis, "invariant mass axis"}; const AxisSpec axisphi{phiAxis, "phi axis"}; - const AxisSpec axisav{vectorAxis, "AV axis"}; - const AxisSpec axisas{scalarAxis, "AS axis"}; - - registry.add("global/hVertexXY", "Vertex position in x and y direction; #it{V}_{x} (cm); #it{V}_{y} (cm); Collisions", {HistType::kTH2F, {{50, -0.05, 0.05}, {50, -0.05, 0.05}}}); - registry.add("global/hVertexZ", "Vertex position in z direction; #it{V}_{z} (cm); Collisions", {HistType::kTH1F, {{100, -25., 25.}}}); - registry.add("global/hVertexZ15", "Vertex position in z direction; #it{V}_{z} (cm); Collisions", {HistType::kTH1F, {{100, -25., 25.}}}); - registry.add("global/hVertexZ10", "Vertex position in z direction; #it{V}_{z} (cm); Collisions", {HistType::kTH1F, {{100, -25., 25.}}}); - registry.add("global/hNTracks", ";N_{tracks};events", {HistType::kTH1D, {{20, 0., 20.}}}); - registry.add("global/hNTracksGlobal", ";N_{tracks,global};events", {HistType::kTH1D, {{20, 0., 20.}}}); - registry.add("global/hNTracksPV", ";N_{tracks,PV};events", {HistType::kTH1D, {{20, 0., 20.}}}); - registry.add("global/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); - registry.add("global/hTrackPtPV", ";p_T^{trk}; Entries", {HistType::kTH1F, {axispt}}); - registry.add("global/hTrackPVTotCharge", "Q_{Tot};Q_{Tot}; Entries", {HistType::kTH1F, {{11, -5, 6}}}); - registry.add("global/hTrackEtaPhiPV", ";Eta;Phi;", {HistType::kTH2D, {axiseta, {140, -3.5, 3.5}}}); - registry.add("global/hSignalTPCvsPtPV", ";Pt;TPC Signal", {HistType::kTH2F, {axispt, {200, 0., 200}}}); - registry.add("global/hITSbitPVtrk", "ITS bit for PV tracks; Layer hit;Entries", {HistType::kTH1F, {{10, 0., 10.}}}); - registry.add("global/hITSnbitsVsEtaPVtrk", "n ITS bits vs #eta for PV tracks; #eta;Layer hit;Entries", {HistType::kTH2F, {axiseta, {8, -1., 7.}}}); - registry.add("global/hITSbitVsEtaPVtrk", "ITS bit vs #eta for PV tracks; #eta;Layer hit;Entries", {HistType::kTH2F, {axiseta, {8, 0., 8.}}}); - registry.add("global/hEventEff", "Event cut efficiency: 0-All,1-PV=4,2-Qtot=0,3-El;Cut;entries", {HistType::kTH1F, {{25, 0., 25.}}}); - registry.add("global/hNCombAfterCut", "Combinations after cut: 0-All,5-M3pi,10-Dphi,15-N_{e},20-N_{v#pi},25-Pt,30-Vcal,35-N_{vp},40-N_{vK},45-Tot;N_{comb};entries", {HistType::kTH1F, {{55, 0., 55.}}}); - // registry.add("global/hInvMassElTrack", ";M_{inv}^{2};entries", {HistType::kTH1F, {{100, -0.01, 0.49}}}); - registry.add("global/hDeltaAngleTrackPV", ";#Delta#alpha;entries", {HistType::kTH1F, {{100, -0.01, 0.49}}}); - registry.add("global/hTrkCheck", ";track type;entries", {HistType::kTH1F, {{16, -1, 15}}}); - - // cut0 - registry.add("control/cut0/h3piMassComb", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); - registry.add("control/cut0/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); - registry.add("control/cut0/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); - registry.add("control/cut0/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); - registry.add("control/cut0/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); - registry.add("control/cut0/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); - registry.add("control/cut0/h13EtaSum", ";#eta^{1-prong}+#eta^{3-prong};entries", {HistType::kTH1F, {{100, -4., 4.}}}); - registry.add("control/cut0/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); - registry.add("control/cut0/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); - registry.add("control/cut0/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); - registry.add("control/cut0/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); - // cut1 - registry.add("control/cut1/h3piMassComb", "3#pi mass, 1 entry per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); - registry.add("control/cut1/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); - registry.add("control/cut1/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); - registry.add("control/cut1/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); - registry.add("control/cut1/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); - registry.add("control/cut1/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); - registry.add("control/cut1/h13EtaSum", ";#eta^{1-prong}+#eta^{3-prong};entries", {HistType::kTH1F, {{100, -4., 4.}}}); - registry.add("control/cut1/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); - registry.add("control/cut1/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); - registry.add("control/cut1/h3piMassVsPt", "3#pi mass vs Pt, 1 entry per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); - registry.add("control/cut1/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); - registry.add("control/cut1/hDcaZ", "All 4 tracks dca ;dca_{Z};entries", {HistType::kTH1F, {{100, -0.05, 0.05}}}); - registry.add("control/cut1/hDcaXY", "All 4 tracks dca ;dca_{XY};entries", {HistType::kTH1F, {{100, -0.05, 0.05}}}); - registry.add("control/cut1/hChi2TPC", "All 4 tracks Chi2 ;Chi2_{TPC};entries", {HistType::kTH1F, {{48, -2, 10.}}}); - registry.add("control/cut1/hChi2ITS", "All 4 tracks Chi2 ;Chi2_{ITS};entries", {HistType::kTH1F, {{44, -2, 20.}}}); - registry.add("control/cut1/hTPCnclsFindable", "All 4 tracks NclFind ;N_{TPC,cl,findable};entries", {HistType::kTH1F, {{160, 0, 160.}}}); - // cut20 - registry.add("control/cut20/h3piMassComb", "3#pi mass, 1 entry per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); - registry.add("control/cut20/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); - registry.add("control/cut20/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); - registry.add("control/cut20/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); - registry.add("control/cut20/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); - registry.add("control/cut20/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); - registry.add("control/cut20/h13EtaSum", ";#eta^{1-prong}+#eta^{3-prong};entries", {HistType::kTH1F, {{100, -4., 4.}}}); - registry.add("control/cut20/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); - registry.add("control/cut20/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); - registry.add("control/cut20/h3piMassVsPt", "3#pi mass vs Pt, 1 entry per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); - registry.add("control/cut20/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); - // cut21 - registry.add("control/cut21/h3piMassComb", "3#pi mass, 1 entry per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); - registry.add("control/cut21/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); - registry.add("control/cut21/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); - registry.add("control/cut21/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); - registry.add("control/cut21/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); - registry.add("control/cut21/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); - registry.add("control/cut21/h13EtaSum", ";#eta^{1-prong}+#eta^{3-prong};entries", {HistType::kTH1F, {{100, -4., 4.}}}); - registry.add("control/cut21/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); - registry.add("control/cut21/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); - registry.add("control/cut21/h3piMassVsPt", "3#pi mass vs Pt, 1 entry per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); - registry.add("control/cut21/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); - // cut22 - registry.add("control/cut22/h3piMassComb", "3#pi mass, 1 entry per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); - registry.add("control/cut22/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); - registry.add("control/cut22/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); - registry.add("control/cut22/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); - registry.add("control/cut22/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); - registry.add("control/cut22/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); - registry.add("control/cut22/h13EtaSum", ";#eta^{1-prong}+#eta^{3-prong};entries", {HistType::kTH1F, {{100, -4., 4.}}}); - registry.add("control/cut22/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); - registry.add("control/cut22/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); - registry.add("control/cut22/h3piMassVsPt", "3#pi mass vs Pt, 1 entry per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); - registry.add("control/cut22/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); - // cut23 - registry.add("control/cut23/h3piMassComb", "3#pi mass, 1 entry per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); - registry.add("control/cut23/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); - registry.add("control/cut23/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); - registry.add("control/cut23/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); - registry.add("control/cut23/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); - registry.add("control/cut23/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); - registry.add("control/cut23/h13EtaSum", ";#eta^{1-prong}+#eta^{3-prong};entries", {HistType::kTH1F, {{100, -4., 4.}}}); - registry.add("control/cut23/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); - registry.add("control/cut23/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); - registry.add("control/cut23/h3piMassVsPt", "3#pi mass vs Pt, 1 entry per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); - registry.add("control/cut23/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); - // cut24 - registry.add("control/cut24/h3piMassComb", "3#pi mass, 1 entry per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); - registry.add("control/cut24/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); - registry.add("control/cut24/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); - registry.add("control/cut24/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); - registry.add("control/cut24/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); - registry.add("control/cut24/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); - registry.add("control/cut24/h13EtaSum", ";#eta^{1-prong}+#eta^{3-prong};entries", {HistType::kTH1F, {{100, -4., 4.}}}); - registry.add("control/cut24/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); - registry.add("control/cut24/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); - registry.add("control/cut24/h3piMassVsPt", "3#pi mass vs Pt, 1 entry per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); - registry.add("control/cut24/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); - // cut25 - registry.add("control/cut25/h3piMassComb", "3#pi mass, 1 entry per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); - registry.add("control/cut25/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); - registry.add("control/cut25/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); - registry.add("control/cut25/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); - registry.add("control/cut25/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); - registry.add("control/cut25/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); - registry.add("control/cut25/h13EtaSum", ";#eta^{1-prong}+#eta^{3-prong};entries", {HistType::kTH1F, {{100, -4., 4.}}}); - registry.add("control/cut25/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); - registry.add("control/cut25/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); - registry.add("control/cut25/h3piMassVsPt", "3#pi mass vs Pt, 1 entry per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); - registry.add("control/cut25/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); - - // pid - registry.add("pidTPC/hpvsdedxElHipCut0", "In hip ;#it{p}_{trk}(GeV/#it{c});dE/dx_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); - registry.add("pidTPC/hpvsdedxElHipCut1", "All hip;#it{p}_{trk}(GeV/#it{c});dE/dx_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); - // pid separately for each cut (what we reject) - registry.add("pidTPC/hpvsdedxElHipCut2", "rejected, IM hip; #it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); - registry.add("pidTPC/hpvsdedxElHipCut3", "rejected, DP hip; #it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); - registry.add("pidTPC/hpvsdedxElHipCut4", "rejected, El hip; #it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); - registry.add("pidTPC/hpvsdedxElHipCut5", "rejected, vPi hip;#it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); - registry.add("pidTPC/hpvsdedxElHipCut6", "rejected, Pt hip; #it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); - registry.add("pidTPC/hpvsdedxElHipCut7", "rejected, vVc hip;#it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); - registry.add("pidTPC/hpvsdedxElHipCut8", "rejected, pTot hip;#it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); - registry.add("pidTPC/hpvsdedxElHipCut9", "rejected, vPr hip;#it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); - registry.add("pidTPC/hpvsdedxElHipCut10", "rejected, vKa hip;#it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); - // pid sequentialy - registry.add("pidTPC/hpvsdedxElHipCut20", "El hip; #it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); - registry.add("pidTPC/hpvsdedxElHipCut21", "vPi+20 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); - registry.add("pidTPC/hpvsdedxElHipCut22", "vVc+21 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); - registry.add("pidTPC/hpvsdedxElHipCut23", "Pt+22 hip; #it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); - registry.add("pidTPC/hpvsdedxElHipCut24", "vPr+23 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); - registry.add("pidTPC/hpvsdedxElHipCut25", "vKa+24 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); - // final electron spectrum - registry.add("global/hFinalPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {{40, 0., 5.}}}); - // fit histos - registry.add("fit/bbFT0Abit", "FT0A bits;bit;entries", {HistType::kTH1F, {{32, 0., 32.}}}); - registry.add("fit/bbFT0Cbit", "FT0C bits;bit;entries", {HistType::kTH1F, {{32, 0., 32.}}}); - registry.add("fit/bbFV0Abit", "FV0A bits;bit;entries", {HistType::kTH1F, {{32, 0., 32.}}}); - registry.add("fit/bbFDDAbit", "FDDA bits;bit;entries", {HistType::kTH1F, {{32, 0., 32.}}}); - registry.add("fit/bbFDDCbit", "FDDC bits;bit;entries", {HistType::kTH1F, {{32, 0., 32.}}}); - registry.add("fit/bbFT0Aamplitude", "FT0A amplitude;Amplitude;entries", {HistType::kTH1F, {{100, -5., 95.}}}); - registry.add("fit/bbFT0Camplitude", "FT0C amplitude;Amplitude;entries", {HistType::kTH1F, {{100, -5., 95.}}}); - registry.add("fit/bbFT0ACamplitude", "FT0A vs FT0C amplitude;Amplitude FT0A;Amplitude FT0C;entries", {HistType::kTH2F, {{100, -5., 95.}, {100, -5., 95.}}}); - registry.add("fit/bbFV0Aamplitude", "FV0A amplitude;Amplitude;entries", {HistType::kTH1F, {{100, -5., 95.}}}); - registry.add("fit/bbFDDAamplitude", "FDDA amplitude;Amplitude;entries", {HistType::kTH1F, {{100, -5., 95.}}}); - registry.add("fit/bbFDDCamplitude", "FDDC amplitude;Amplitude;entries", {HistType::kTH1F, {{100, -5., 95.}}}); - registry.add("fit/bbFDDACamplitude", "FDDA vs FDDC amplitude;Amplitude FDDA;Amplitude FDDC;entries", {HistType::kTH2F, {{100, -5., 95.}, {100, -5., 95.}}}); - registry.add("fit/timeFT0", "FT0 time;time FT0A; time FT0C;entries", {HistType::kTH2F, {{100, -5., 35.}, {100, -5., 35.}}}); - registry.add("fit/timeFDD", "FDD time;time FDDA; time FDDC;entries", {HistType::kTH2F, {{100, -5., 35.}, {100, -5., 35.}}}); + // const AxisSpec axisav{vectorAxis, "AV axis"}; + // const AxisSpec axisas{scalarAxis, "AS axis"}; + const AxisSpec vectorAxis{100, 0., 2., "A_{V}"}; + const AxisSpec scalarAxis{100, -1., 1., "A_{S}"}; + const AxisSpec axisZDC{50, -1., 14., "#it{E} (TeV)"}; + const AxisSpec axisInvMass4trk{160, 0.5, 8.5, "#it{M}^{4trk}_{inv} (GeV/#it{c}^{2})"}; + + if (doprocessDataSG) { + registry.add("global/RunNumber", "Run number; Run; Collisions", {HistType::kTH1F, {{150, 544013, 545367}}}); + registry.add("global/GapSide", "Associated gap side; gap index; Collisions", {HistType::kTH1F, {{5, -1, 4}}}); + registry.add("global/GapSideTrue", "Recalculated gap side; gap index; Collisions", {HistType::kTH1F, {{5, -1, 4}}}); + + registry.add("global/hZNACenergy", "ZNA vs ZNC energy; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + registry.add("global/hZNACtime", "ZNA vs ZNC time; #it{time}_{ZNA} (ns); #it{time}_{ZNC} (ns); Collisions", {HistType::kTH2F, {{100, -10., 10.}, {100, -10., 10.}}}); + // registry.add("global/hZNACenergyTest", "ZNA or ZNC energy; #it{E}_{ZNA,ZNC} (GeV); Collisions", {HistType::kTH1F, {{100,-1000,0}}}); + + registry.add("global/hVertexXY", "Vertex position in x and y direction; #it{V}_{x} (cm); #it{V}_{y} (cm); Collisions", {HistType::kTH2F, {{50, -0.05, 0.05}, {50, -0.02, 0.02}}}); + registry.add("global/hVertexZ", "Vertex position in z direction; #it{V}_{z} (cm); Collisions", {HistType::kTH1F, {{100, -25., 25.}}}); + registry.add("global/hNTracks", ";N_{tracks};events", {HistType::kTH1D, {{20, 0., 20.}}}); + // registry.add("global/hNTracksGlobal", ";N_{tracks,global};events", {HistType::kTH1D, {{20, 0., 20.}}}); + registry.add("global/hNTracksPV", ";N_{tracks,PV};events", {HistType::kTH1D, {{20, 0., 20.}}}); + registry.add("global/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + registry.add("global/hTrackPtPV", ";p_T^{trk}; Entries", {HistType::kTH1F, {axispt}}); + registry.add("global/hTrackEtaPhiPV", ";Eta;Phi;", {HistType::kTH2D, {axiseta, {140, -3.5, 3.5}}}); + registry.add("global/hTrackEfficiencyPVGlobal", "0-All,1-ntpc,2-rat,3-chitpc,4chiits,5-dcaz,6-dcaxy,7pt,8eta;Track efficiency; Entries", {HistType::kTH1F, {{15, 0, 15}}}); + registry.add("global/hTrackPVGood", "0-All,1-ntpc,2-rat,3-chitpc,4chiits,5-dcaz,6-dcaxy,7pt,8eta;Track efficiency; Entries", {HistType::kTH1F, {{15, 0, 15}}}); + registry.add("global/hTrackEtaPhiPVGlobal", ";Eta;Phi;", {HistType::kTH2D, {axiseta, {140, -3.5, 3.5}}}); + + registry.add("global/hSignalTPCvsPtPV", ";Pt;TPC Signal", {HistType::kTH2F, {axispt, {200, 0., 200}}}); + registry.add("global/hITSbitPVtrk", "ITS bit for PV tracks; Layer hit;Entries", {HistType::kTH1F, {{10, 0., 10.}}}); + registry.add("global/hITSnbitsVsEtaPVtrk", "n ITS bits vs #eta for PV tracks; #eta;Layer hit;Entries", {HistType::kTH2F, {axiseta, {8, -1., 7.}}}); + registry.add("global/hITSbitVsEtaPVtrk", "ITS bit vs #eta for PV tracks; #eta;Layer hit;Entries", {HistType::kTH2F, {axiseta, {8, 0., 8.}}}); + registry.add("global/hEventEff", "Event cut efficiency: 0-All,1-PV=4,2-Qtot=0,3-El;Cut;entries", {HistType::kTH1F, {{27, -2., 25.}}}); + registry.add("global/hNCombAfterCut", "Combinations after cut: 0-All,5-M3pi,10-Dphi,15-N_{e},20-N_{v#pi},25-Pt,30-Vcal,35-N_{vp},40-N_{vK},45-Tot;N_{comb};entries", {HistType::kTH1F, {{60, 0., 60.}}}); + // registry.add("global/hInvMassElTrack", ";M_{inv}^{2};entries", {HistType::kTH1F, {{100, -0.01, 0.49}}}); + registry.add("global/hDeltaAngleTrackPV", ";#Delta#alpha;entries", {HistType::kTH1F, {{136, 0., 3.2}}}); // 0.49 + registry.add("global/hTrkCheck", ";track type;entries", {HistType::kTH1F, {{16, -1, 15}}}); + + registry.add("global/hRecFlag", ";Reconstruction Flag;events", {HistType::kTH1F, {{10, 0., 10.}}}); + registry.add("global/hOccupancyInTime", ";Occupancy;events", {HistType::kTH1F, {{100, 0., 10000.}}}); + + registry.add("global1/hVertexZ", "Vertex position in z direction; #it{V}_{z} (cm); Collisions", {HistType::kTH1F, {{100, -25., 25.}}}); + registry.add("global1/hNTracks", ";N_{tracks};events", {HistType::kTH1D, {{20, 0., 20.}}}); + registry.add("global1/hNTracksPV", ";N_{tracks,PV};events", {HistType::kTH1D, {{20, 0., 20.}}}); + registry.add("global1/hTrackPtPV", ";p_T^{trk}; Entries", {HistType::kTH1F, {axispt}}); + registry.add("global1/hTrackEtaPhiPV", ";Eta;Phi;", {HistType::kTH2D, {axiseta, {140, -3.5, 3.5}}}); + registry.add("global1/hTrackPVTotCharge", "Q_{Tot};Q_{Tot}; Entries", {HistType::kTH1F, {{11, -5, 6}}}); + + // cut0 + registry.add("control/cut0/h3piMassComb", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registry.add("control/cut0/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registry.add("control/cut0/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registry.add("control/cut0/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("control/cut0/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registry.add("control/cut0/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + // registry.add("control/cut0/h13EtaSum", ";#eta^{1-prong}+#eta^{3-prong};entries", {HistType::kTH1F, {{100, -4., 4.}}}); + registry.add("control/cut0/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registry.add("control/cut0/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry.add("control/cut0/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry.add("control/cut0/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + registry.add("control/cut0/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + registry.add("control/cut0/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry.add("control/cut0/hsigma3PiNew", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry.add("control/cut0/hsigma2PiNew", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}};#sigma^{2#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry.add("control/cut0/hsigma1PiNew", "#sqrt{#sigma_{1}^{2 }};#sigma^{1#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry.add("control/cut0/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + registry.add("control/cut0/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registry.add("control/cut0/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + registry.add("control/cut0/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {{40, 0., 5.}}}); + registry.add("control/cut0/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + registry.add("control/cut0/hInvMass2ElAll", "Inv Mass of 2 Electrons from coherent peak;M_{inv}^{2e};entries", {HistType::kTH1F, {{150, -0.1, 9.}}}); + registry.add("control/cut0/hInvMass2ElCoh", "Inv Mass of 2 Electrons from coherent peak;M_{inv}^{2e};entries", {HistType::kTH1F, {{150, -0.1, 4.}}}); + registry.add("control/cut0/hGamPtCoh", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registry.add("control/cut0/hGamPtCohIM0", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registry.add("control/cut0/hN2gamma", "Number of gamma pairs among 3 comb;N_{#gamma#gamma};entries", {HistType::kTH1F, {{20, 0., 20.}}}); + registry.add("control/cut0/hGamAS", ";A_{S};entries", {HistType::kTH1F, {{100, 0, 0.2}}}); + registry.add("control/cut0/hGamAV", ";A_{V};entries", {HistType::kTH1F, {{100, 0, 0.2}}}); + registry.add("control/cut0/hInvMass2GamCoh", "Inv Mass of 2 Gamma from coherent peak;M_{inv}^{2#gamma};entries", {HistType::kTH1F, {{160, 0.5, 4.5}}}); + registry.add("control/cut0/hDeltaPhi2GamCoh", "Delta Phi of 2 Gamma from coherent peak;#Delta#phi^{2#gamma};entries", {HistType::kTH1F, {phiAxis}}); + + // // cut1 + // registry.add("control/cut1/h3piMassComb", "3#pi mass, 1 entry per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + // registry.add("control/cut1/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + // registry.add("control/cut1/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + // registry.add("control/cut1/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + // registry.add("control/cut1/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + // registry.add("control/cut1/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + // // registry.add("control/cut1/h13EtaSum", ";#eta^{1-prong}+#eta^{3-prong};entries", {HistType::kTH1F, {{100, -4., 4.}}}); + // registry.add("control/cut1/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + // registry.add("control/cut1/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registry.add("control/cut1/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registry.add("control/cut1/h3piMassVsPt", "3#pi mass vs Pt, 1 entry per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + // registry.add("control/cut1/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + // registry.add("control/cut1/hDcaZ", "All 4 tracks dca ;dca_{Z};entries", {HistType::kTH1F, {{100, -0.05, 0.05}}}); + // registry.add("control/cut1/hDcaXY", "All 4 tracks dca ;dca_{XY};entries", {HistType::kTH1F, {{100, -0.05, 0.05}}}); + // registry.add("control/cut1/hChi2TPC", "All 4 tracks Chi2 ;Chi2_{TPC};entries", {HistType::kTH1F, {{48, -2, 10.}}}); + // registry.add("control/cut1/hChi2ITS", "All 4 tracks Chi2 ;Chi2_{ITS};entries", {HistType::kTH1F, {{44, -2, 20.}}}); + // registry.add("control/cut1/hChi2TOF", "All 4 tracks Chi2 ;Chi2_{TOF};entries", {HistType::kTH1F, {{48, -2, 10.}}}); + // registry.add("control/cut1/hTPCnclsFindable", "All 4 tracks NclFind ;N_{TPC,cl,findable};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + // registry.add("control/cut1/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registry.add("control/cut1/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + // registry.add("control/cut1/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + // registry.add("control/cut1/hZNACenergy", "ZNA vs ZNC energy; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + // registry.add("control/cut1/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {{40, 0., 5.}}}); + // registry.add("control/cut1/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // // cut1a for 20 + registryMC.add("globalMCrec/hPtSpectrumElRec9", "Rec9;#it{p}_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); // effiEl = 23, FIT empty + + // global1 when we require SGProducer + double gap + nPVtracks=4 + registryMC.add("global1MCrec/hVertexZ", "Vertex position in z direction; #it{V}_{z} (cm); Collisions", {HistType::kTH1F, {{100, -25., 25.}}}); + registryMC.add("global1MCrec/hNTracks", ";N_{tracks};events", {HistType::kTH1D, {{20, 0., 20.}}}); + registryMC.add("global1MCrec/hNTracksPV", ";N_{tracks,PV};events", {HistType::kTH1D, {{20, 0., 20.}}}); + registryMC.add("global1MCrec/hTrackPtPV", ";p_T^{trk}; Entries", {HistType::kTH1F, {axispt}}); + registryMC.add("global1MCrec/hTrackEtaPhiPV", ";Eta;Phi;", {HistType::kTH2D, {axiseta, {128, -0.05, 6.35}}}); + registryMC.add("global1MCrec/hTrackPVTotCharge", "Q_{Tot};Q_{Tot}; Entries", {HistType::kTH1F, {{11, -5, 6}}}); + + registryMC.add("global1MCrec/hpTGenRecTracksPV", ";p_{T}^{Rec. tracks,PV} (GeV/c);p_{T}^{Gen} (GeV/c);events", {HistType::kTH2D, {{100, 0., 4.}, {100, 0., 4.}}}); + registryMC.add("global1MCrec/hDeltapTGenRecVsRecpTTracksPV", ";#Delta p_{T}^{Rec.-Gen. tracks,PV} (GeV/c);p_{T}^{Rec. tracks,PV} (GeV/c);events", {HistType::kTH2D, {{100, -4., 4.}, {100, 0., 4.}}}); + registryMC.add("global1MCrec/hEtaGenRecTracksPV", ";#eta^{Rec. tracks,PV} (GeV/c);#eta^{Gen} (GeV/c);events", {HistType::kTH2D, {{100, -2., 2.}, {100, -2., 2.}}}); + registryMC.add("global1MCrec/hDeltaEtaGenRecVsRecpTTracksPV", ";#Delta #eta^{Rec.-Gen. tracks,PV} (GeV/c);p_{T}^{Rec. tracks,PV} (GeV/c);events", {HistType::kTH2D, {{100, -0.25, 0.25}, {100, 0., 4.}}}); + registryMC.add("global1MCrec/hPhiGenRecTracksPV", ";#phi^{Rec. tracks,PV} (GeV/c);#phi^{Gen} (GeV/c);events", {HistType::kTH2D, {{100, 0., 6.4}, {100, 0., 6.4}}}); + registryMC.add("global1MCrec/hDeltaPhiGenRecVsRecpTTracksPV", ";#Delta #phi^{Rec.-Gen. tracks,PV} (GeV/c);p_{T}^{Rec. tracks,PV} (GeV/c);events", {HistType::kTH2D, {{100, -0.5, 0.5}, {100, 0., 4.}}}); + + // pid El in MC true + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut0", "In hip ;#it{p}_{trk}(GeV/#it{c});dE/dx_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut1", "All hip;#it{p}_{trk}(GeV/#it{c});dE/dx_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + // pid separately for each cut (what we reject) + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut2", "rejected, IM hip; #it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut3", "rejected, DP hip; #it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut4", "rejected, El hip; #it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut5", "rejected, vPi hip;#it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut6", "rejected, Pt hip; #it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut7", "rejected, vVc hip;#it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut8", "rejected, pTot hip;#it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut9", "rejected, vPr hip;#it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut10", "rejected, vKa hip;#it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut11", "rejected, nCR hip;#it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut12", "rejected, s3pi hip;#it{p}_{trk} (GeV/#it{c}); d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + // pid sequentialy + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut20", "El hip; #it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut33", "eTOF+20 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut21", "vPi+33 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut24", "vPr+21 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut25", "vKa+24 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut28", "CR+25 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut22", "vVc+28 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut29", "s3pi+22 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut26", "IM+29 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut34", "piTOF+26 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut30", "ptTot+34 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut27", "DP+30 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut35", "ZDC+27 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut23", "Occ+35 hip; #it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + + // registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut31", "FIT+27 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + // registryMC.add("pidTPCMCEltrue/hpvsdedxElHipCut32", "TOF+31 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + + // pid Pi in MC true + registryMC.add("pidTPCMCPitrue/hpvsdedxElHipCut0", "In hip ;#it{p}_{trk}(GeV/#it{c});dE/dx_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCPitrue/hpvsdedxElHipCut20", "El hip; #it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCPitrue/hpvsdedxElHipCut33", "eTOF+20 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCPitrue/hpvsdedxElHipCut21", "vPi+33 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCPitrue/hpvsdedxElHipCut24", "vPr+21 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCPitrue/hpvsdedxElHipCut25", "vKa+24 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCPitrue/hpvsdedxElHipCut28", "CR+25 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCPitrue/hpvsdedxElHipCut22", "vVc+28 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCPitrue/hpvsdedxElHipCut29", "s3pi+22 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCPitrue/hpvsdedxElHipCut26", "IM+29 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCPitrue/hpvsdedxElHipCut34", "piTOF+26 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCPitrue/hpvsdedxElHipCut30", "ptTot+34 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCPitrue/hpvsdedxElHipCut27", "DP+30 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCPitrue/hpvsdedxElHipCut35", "ZDC+27 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + registryMC.add("pidTPCMCPitrue/hpvsdedxElHipCut23", "Occ+35 hip; #it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + + // registryMC.add("pidTPCMCPitrue/hpvsdedxElHipCut31", "FIT+27 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + // registryMC.add("pidTPCMCPitrue/hpvsdedxElHipCut32", "TOF+31 hip;#it{p}_{trk} (GeV/#it{c});d#it{E}/d#it{x}_{trk}", {HistType::kTH2F, {axisp, dedxAxis}}); + + // El PID in TOF MC true + registry1MC.add("pidTOFMCEltrue/hpvsNsigmaElHipCut0", "In hip ;#it{p}_{trk}(GeV/#it{c});N#sigma El^{TOF}_{trk}", {HistType::kTH2F, {axisp, {100, -5., 5.}}}); + registry1MC.add("pidTOFMCEltrue/hpvsNsigmaElHipCut20", "El hip;#it{p}_{trk} (GeV/#it{c});N#sigma El^{TOF}_{trk}", {HistType::kTH2F, {axisp, {100, -5., 5.}}}); + registry1MC.add("pidTOFMCEltrue/hpvsNsigmaElHipCut33", "eTOF+20 hip;#it{p}_{trk} (GeV/#it{c});N#sigma El^{TOF}_{trk}", {HistType::kTH2F, {axisp, {100, -5., 5.}}}); + registry1MC.add("pidTOFMCEltrue/hpvsNsigmaElHipCut21", "vPi+33 hip;#it{p}_{trk} (GeV/#it{c});N#sigma El^{TOF}_{trk}", {HistType::kTH2F, {axisp, {100, -5., 5.}}}); + registry1MC.add("pidTOFMCEltrue/hpvsNsigmaElHipCut24", "vPr+21 hip;#it{p}_{trk} (GeV/#it{c});N#sigma El^{TOF}_{trk}", {HistType::kTH2F, {axisp, {100, -5., 5.}}}); + registry1MC.add("pidTOFMCEltrue/hpvsNsigmaElHipCut25", "vKa+24 hip;#it{p}_{trk} (GeV/#it{c});N#sigma El^{TOF}_{trk}", {HistType::kTH2F, {axisp, {100, -5., 5.}}}); + registry1MC.add("pidTOFMCEltrue/hpvsNsigmaElHipCut28", "CR+25 hip;#it{p}_{trk} (GeV/#it{c});N#sigma El^{TOF}_{trk}", {HistType::kTH2F, {axisp, {100, -5., 5.}}}); + registry1MC.add("pidTOFMCEltrue/hpvsNsigmaElHipCut22", "vVc+28 hip;#it{p}_{trk} (GeV/#it{c});N#sigma El^{TOF}_{trk}", {HistType::kTH2F, {axisp, {100, -5., 5.}}}); + registry1MC.add("pidTOFMCEltrue/hpvsNsigmaElHipCut29", "s3pi+22 hip;#it{p}_{trk} (GeV/#it{c});N#sigma El^{TOF}_{trk}", {HistType::kTH2F, {axisp, {100, -5., 5.}}}); + registry1MC.add("pidTOFMCEltrue/hpvsNsigmaElHipCut26", "IM+29 hip;#it{p}_{trk} (GeV/#it{c});N#sigma El^{TOF}_{trk}", {HistType::kTH2F, {axisp, {100, -5., 5.}}}); + registry1MC.add("pidTOFMCEltrue/hpvsNsigmaElHipCut34", "piTOF+26 hip;#it{p}_{trk} (GeV/#it{c});N#sigma El^{TOF}_{trk}", {HistType::kTH2F, {axisp, {100, -5., 5.}}}); + registry1MC.add("pidTOFMCEltrue/hpvsNsigmaElHipCut30", "ptTot+34 hip;#it{p}_{trk} (GeV/#it{c});N#sigma El^{TOF}_{trk}", {HistType::kTH2F, {axisp, {100, -5., 5.}}}); + registry1MC.add("pidTOFMCEltrue/hpvsNsigmaElHipCut27", "DP+30 hip;#it{p}_{trk} (GeV/#it{c});N#sigma El^{TOF}_{trk}", {HistType::kTH2F, {axisp, {100, -5., 5.}}}); + registry1MC.add("pidTOFMCEltrue/hpvsNsigmaElHipCut35", "ZDC+27 hip;#it{p}_{trk} (GeV/#it{c});N#sigma El^{TOF}_{trk}", {HistType::kTH2F, {axisp, {100, -5., 5.}}}); + registry1MC.add("pidTOFMCEltrue/hpvsNsigmaElHipCut23", "Occ+27 hip;#it{p}_{trk} (GeV/#it{c});N#sigma El^{TOF}_{trk}", {HistType::kTH2F, {axisp, {100, -5., 5.}}}); + + // cut0 + registryMC.add("controlMCtrue/cut0/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCtrue/cut0/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCtrue/cut0/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCtrue/cut0/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCtrue/cut0/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCtrue/cut0/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCtrue/cut0/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut0/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registryMC.add("controlMCtrue/cut0/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registryMC.add("controlMCtrue/cut0/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + registryMC.add("controlMCtrue/cut0/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + registryMC.add("controlMCtrue/cut0/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCtrue/cut0/hsigma3PiNew", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCtrue/cut0/hsigma2PiNew", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}};#sigma^{2#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCtrue/cut0/hsigma1PiNew", "#sqrt{#sigma_{1}^{2 }};#sigma^{1#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + registryMC.add("controlMCtrue/cut0/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + registryMC.add("controlMCtrue/cut0/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCtrue/cut0/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + registry1MC.add("controlMCtrue/cut0/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // + registryMC.add("controlMCcomb/cut0/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCcomb/cut0/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCcomb/cut0/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCcomb/cut0/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCcomb/cut0/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCcomb/cut0/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCcomb/cut0/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registryMC.add("controlMCcomb/cut0/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registry1MC.add("controlMCcomb/cut0/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // cut20 MC + registryMC.add("controlMCtrue/cut20/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registryMC.add("controlMCtrue/cut20/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut20/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + registryMC.add("controlMCtrue/cut20/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + registryMC.add("controlMCtrue/cut20/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCtrue/cut20/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCtrue/cut20/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCtrue/cut20/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCtrue/cut20/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCtrue/cut20/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCtrue/cut20/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCtrue/cut20/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + registryMC.add("controlMCtrue/cut20/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCtrue/cut20/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registryMC.add("controlMCtrue/cut20/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + // registryMC.add("controlMCtrue/cut20/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // + registryMC.add("controlMCcomb/cut20/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCcomb/cut20/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCcomb/cut20/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCcomb/cut20/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCcomb/cut20/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCcomb/cut20/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCcomb/cut20/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCcomb/cut20/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCcomb/cut20/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // cut21 MC + registryMC.add("controlMCtrue/cut21/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registryMC.add("controlMCtrue/cut21/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut21/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + registryMC.add("controlMCtrue/cut21/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + registryMC.add("controlMCtrue/cut21/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCtrue/cut21/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCtrue/cut21/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCtrue/cut21/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCtrue/cut21/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCtrue/cut21/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCtrue/cut21/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCtrue/cut21/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + registryMC.add("controlMCtrue/cut21/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCtrue/cut21/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registryMC.add("controlMCtrue/cut21/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + // registryMC.add("controlMCtrue/cut21/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // + registryMC.add("controlMCcomb/cut21/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCcomb/cut21/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCcomb/cut21/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCcomb/cut21/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCcomb/cut21/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCcomb/cut21/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCcomb/cut21/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCcomb/cut21/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCcomb/cut21/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // cut24 MC + registryMC.add("controlMCtrue/cut24/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registryMC.add("controlMCtrue/cut24/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut24/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + registryMC.add("controlMCtrue/cut24/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + registryMC.add("controlMCtrue/cut24/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCtrue/cut24/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCtrue/cut24/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCtrue/cut24/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCtrue/cut24/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCtrue/cut24/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCtrue/cut24/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCtrue/cut24/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + registryMC.add("controlMCtrue/cut24/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCtrue/cut24/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registryMC.add("controlMCtrue/cut24/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + // registryMC.add("controlMCtrue/cut24/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // + registryMC.add("controlMCcomb/cut24/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCcomb/cut24/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCcomb/cut24/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCcomb/cut24/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCcomb/cut24/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCcomb/cut24/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCcomb/cut24/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCcomb/cut24/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCcomb/cut24/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // cut25 MC + registryMC.add("controlMCtrue/cut25/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registryMC.add("controlMCtrue/cut25/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut25/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + registryMC.add("controlMCtrue/cut25/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + registryMC.add("controlMCtrue/cut25/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCtrue/cut25/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCtrue/cut25/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCtrue/cut25/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCtrue/cut25/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCtrue/cut25/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCtrue/cut25/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCtrue/cut25/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + registryMC.add("controlMCtrue/cut25/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCtrue/cut25/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registryMC.add("controlMCtrue/cut25/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + // registryMC.add("controlMCtrue/cut25/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // + registryMC.add("controlMCcomb/cut25/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCcomb/cut25/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCcomb/cut25/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCcomb/cut25/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCcomb/cut25/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCcomb/cut25/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCcomb/cut25/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCcomb/cut25/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCcomb/cut25/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // cut28 MC + registryMC.add("controlMCtrue/cut28/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registryMC.add("controlMCtrue/cut28/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut28/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + registryMC.add("controlMCtrue/cut28/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + registryMC.add("controlMCtrue/cut28/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCtrue/cut28/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCtrue/cut28/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCtrue/cut28/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCtrue/cut28/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCtrue/cut28/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCtrue/cut28/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCtrue/cut28/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + registryMC.add("controlMCtrue/cut28/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCtrue/cut28/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registryMC.add("controlMCtrue/cut28/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + // registryMC.add("controlMCtrue/cut28/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // + registryMC.add("controlMCcomb/cut28/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCcomb/cut28/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCcomb/cut28/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCcomb/cut28/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCcomb/cut28/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCcomb/cut28/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCcomb/cut28/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCcomb/cut28/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCcomb/cut28/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // cut22 MC + registryMC.add("controlMCtrue/cut22/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registryMC.add("controlMCtrue/cut22/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut22/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + registryMC.add("controlMCtrue/cut22/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + registryMC.add("controlMCtrue/cut22/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCtrue/cut22/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCtrue/cut22/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCtrue/cut22/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCtrue/cut22/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCtrue/cut22/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCtrue/cut22/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCtrue/cut22/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + registryMC.add("controlMCtrue/cut22/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCtrue/cut22/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registryMC.add("controlMCtrue/cut22/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + // registryMC.add("controlMCtrue/cut22/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // + registryMC.add("controlMCcomb/cut22/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCcomb/cut22/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCcomb/cut22/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCcomb/cut22/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCcomb/cut22/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCcomb/cut22/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCcomb/cut22/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCcomb/cut22/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCcomb/cut22/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // cut29 MC + registryMC.add("controlMCtrue/cut29/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registryMC.add("controlMCtrue/cut29/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut29/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + registryMC.add("controlMCtrue/cut29/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + registryMC.add("controlMCtrue/cut29/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCtrue/cut29/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCtrue/cut29/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCtrue/cut29/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCtrue/cut29/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCtrue/cut29/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCtrue/cut29/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCtrue/cut29/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + registryMC.add("controlMCtrue/cut29/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCtrue/cut29/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registryMC.add("controlMCtrue/cut29/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + // registryMC.add("controlMCtrue/cut29/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // + registryMC.add("controlMCcomb/cut29/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCcomb/cut29/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCcomb/cut29/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCcomb/cut29/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCcomb/cut29/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCcomb/cut29/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCcomb/cut29/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCcomb/cut29/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCcomb/cut29/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // cut26 MC + registryMC.add("controlMCtrue/cut26/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registryMC.add("controlMCtrue/cut26/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut26/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + registryMC.add("controlMCtrue/cut26/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + registryMC.add("controlMCtrue/cut26/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCtrue/cut26/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCtrue/cut26/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCtrue/cut26/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCtrue/cut26/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCtrue/cut26/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCtrue/cut26/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCtrue/cut26/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + registryMC.add("controlMCtrue/cut26/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCtrue/cut26/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registryMC.add("controlMCtrue/cut26/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + // registryMC.add("controlMCtrue/cut26/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // + registryMC.add("controlMCcomb/cut26/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCcomb/cut26/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCcomb/cut26/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCcomb/cut26/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCcomb/cut26/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCcomb/cut26/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCcomb/cut26/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCcomb/cut26/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCcomb/cut26/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // cut30 MC + registryMC.add("controlMCtrue/cut30/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registryMC.add("controlMCtrue/cut30/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut30/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + registryMC.add("controlMCtrue/cut30/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + registryMC.add("controlMCtrue/cut30/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCtrue/cut30/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCtrue/cut30/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCtrue/cut30/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCtrue/cut30/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCtrue/cut30/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCtrue/cut30/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCtrue/cut30/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + registryMC.add("controlMCtrue/cut30/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCtrue/cut30/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registryMC.add("controlMCtrue/cut30/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + // registryMC.add("controlMCtrue/cut30/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // + registryMC.add("controlMCcomb/cut30/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCcomb/cut30/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCcomb/cut30/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCcomb/cut30/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCcomb/cut30/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCcomb/cut30/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCcomb/cut30/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCcomb/cut30/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCcomb/cut30/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // cut27 MC + registryMC.add("controlMCtrue/cut27/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registryMC.add("controlMCtrue/cut27/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut27/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + registryMC.add("controlMCtrue/cut27/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + registryMC.add("controlMCtrue/cut27/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCtrue/cut27/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCtrue/cut27/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCtrue/cut27/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCtrue/cut27/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCtrue/cut27/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCtrue/cut27/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCtrue/cut27/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + registryMC.add("controlMCtrue/cut27/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCtrue/cut27/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registryMC.add("controlMCtrue/cut27/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + // registryMC.add("controlMCtrue/cut27/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // + registryMC.add("controlMCcomb/cut27/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCcomb/cut27/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCcomb/cut27/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCcomb/cut27/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCcomb/cut27/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCcomb/cut27/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCcomb/cut27/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCcomb/cut27/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCcomb/cut27/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // //cut31 MC + // registryMC.add("controlMCtrue/cut31/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registryMC.add("controlMCtrue/cut31/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + // registryMC.add("controlMCtrue/cut31/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + // registryMC.add("controlMCtrue/cut31/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + // registryMC.add("controlMCtrue/cut31/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + // registryMC.add("controlMCtrue/cut31/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + // registryMC.add("controlMCtrue/cut31/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + // registryMC.add("controlMCtrue/cut31/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + // registryMC.add("controlMCtrue/cut31/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + // registryMC.add("controlMCtrue/cut31/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + // registryMC.add("controlMCtrue/cut31/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + // registryMC.add("controlMCtrue/cut31/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + // registryMC.add("controlMCtrue/cut31/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registry1MC.add("controlMCtrue/cut31/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // // registryMC.add("controlMCtrue/cut31/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + // // registryMC.add("controlMCtrue/cut31/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // // + // registryMC.add("controlMCcomb/cut31/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + // registryMC.add("controlMCcomb/cut31/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + // registryMC.add("controlMCcomb/cut31/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + // registryMC.add("controlMCcomb/cut31/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + // registryMC.add("controlMCcomb/cut31/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + // registryMC.add("controlMCcomb/cut31/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + // registryMC.add("controlMCcomb/cut31/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + // registryMC.add("controlMCcomb/cut31/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registry1MC.add("controlMCcomb/cut31/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // //cut32 MC + // registryMC.add("controlMCtrue/cut32/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registryMC.add("controlMCtrue/cut32/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + // registryMC.add("controlMCtrue/cut32/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + // registryMC.add("controlMCtrue/cut32/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + // registryMC.add("controlMCtrue/cut32/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + // registryMC.add("controlMCtrue/cut32/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + // registryMC.add("controlMCtrue/cut32/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + // registryMC.add("controlMCtrue/cut32/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + // registryMC.add("controlMCtrue/cut32/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + // registryMC.add("controlMCtrue/cut32/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + // registryMC.add("controlMCtrue/cut32/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + // registryMC.add("controlMCtrue/cut32/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + // registryMC.add("controlMCtrue/cut32/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registry1MC.add("controlMCtrue/cut32/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // // registryMC.add("controlMCtrue/cut32/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + // // registryMC.add("controlMCtrue/cut32/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // // + // registryMC.add("controlMCcomb/cut32/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + // registryMC.add("controlMCcomb/cut32/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + // registryMC.add("controlMCcomb/cut32/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + // registryMC.add("controlMCcomb/cut32/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + // registryMC.add("controlMCcomb/cut32/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + // registryMC.add("controlMCcomb/cut32/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + // registryMC.add("controlMCcomb/cut32/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + // registryMC.add("controlMCcomb/cut32/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registry1MC.add("controlMCcomb/cut32/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // cut33 MC + registryMC.add("controlMCtrue/cut33/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registryMC.add("controlMCtrue/cut33/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut33/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + registryMC.add("controlMCtrue/cut33/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + registryMC.add("controlMCtrue/cut33/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCtrue/cut33/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCtrue/cut33/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCtrue/cut33/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCtrue/cut33/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCtrue/cut33/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCtrue/cut33/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCtrue/cut33/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + registryMC.add("controlMCtrue/cut33/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCtrue/cut33/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registryMC.add("controlMCtrue/cut33/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + // registryMC.add("controlMCtrue/cut33/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // + registryMC.add("controlMCcomb/cut33/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCcomb/cut33/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCcomb/cut33/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCcomb/cut33/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCcomb/cut33/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCcomb/cut33/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCcomb/cut33/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCcomb/cut33/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCcomb/cut33/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // cut34 MC + // registryMC.add("controlMCtrue/cut34/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registryMC.add("controlMCtrue/cut34/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {axisInvMass4trk}}); + registryMC.add("controlMCtrue/cut34/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut34/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + registryMC.add("controlMCtrue/cut34/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + registryMC.add("controlMCtrue/cut34/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCtrue/cut34/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCtrue/cut34/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCtrue/cut34/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCtrue/cut34/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCtrue/cut34/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCtrue/cut34/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCtrue/cut34/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + registryMC.add("controlMCtrue/cut34/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCtrue/cut34/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registryMC.add("controlMCtrue/cut34/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + // registryMC.add("controlMCtrue/cut34/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // + registryMC.add("controlMCcomb/cut34/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCcomb/cut34/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCcomb/cut34/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCcomb/cut34/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCcomb/cut34/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCcomb/cut34/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCcomb/cut34/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCcomb/cut34/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCcomb/cut34/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // cut35 MC + // registryMC.add("controlMCtrue/cut34/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registryMC.add("controlMCtrue/cut35/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {axisInvMass4trk}}); + registryMC.add("controlMCtrue/cut35/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut35/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + registryMC.add("controlMCtrue/cut35/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + registryMC.add("controlMCtrue/cut35/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCtrue/cut35/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCtrue/cut35/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCtrue/cut35/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCtrue/cut35/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCtrue/cut35/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCtrue/cut35/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCtrue/cut35/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + registryMC.add("controlMCtrue/cut35/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCtrue/cut35/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registryMC.add("controlMCtrue/cut35/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + // registryMC.add("controlMCtrue/cut35/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // + registryMC.add("controlMCcomb/cut35/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCcomb/cut35/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCcomb/cut35/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCcomb/cut35/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCcomb/cut35/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCcomb/cut35/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCcomb/cut35/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCcomb/cut35/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCcomb/cut35/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // cut23 MC + registryMC.add("controlMCtrue/cut23/h4piMass", "4#pi mass;M_{inv}^{4#pi} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registryMC.add("controlMCtrue/cut23/h4trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut23/h4trkMassVsPt", "4-track mass vs Pt;M_{inv}^{4track} (GeV/c^{2});p_{T}^{4track} (GeV/c);entries", {HistType::kTH2F, {{100, 1, 5.}, axispt}}); + registryMC.add("controlMCtrue/cut23/hZNACenergy", "ZNA vs ZNC energy, cut0; #it{E}_{ZNA} (GeV); #it{E}_{ZNC} (GeV); Collisions", {HistType::kTH2F, {axisZDC, axisZDC}}); + registryMC.add("controlMCtrue/cut23/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCtrue/cut23/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCtrue/cut23/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCtrue/cut23/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCtrue/cut23/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCtrue/cut23/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCtrue/cut23/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCtrue/cut23/h3piMassVsPt", "3#pi mass vs Pt, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});p_{T}^{3#pi} (GeV/c);entries", {HistType::kTH2F, {minvAxis, axispt}}); + registryMC.add("controlMCtrue/cut23/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCtrue/cut23/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // registryMC.add("controlMCtrue/cut23/hNtofTrk", ";N_{TOF trk}; Entries", {HistType::kTH1F, {{7, 0., 7.}}}); + // registryMC.add("controlMCtrue/cut23/h3pi1eMass", "3#pi+e mass;M_{inv}^{3#pi+e} (GeV/c^{2});entries", {HistType::kTH1F, {{100, 0., 10.}}}); + // + registryMC.add("controlMCcomb/cut23/h3piMass", "3#pi mass, up to 4 entries per event ;M_{inv}^{3#pi} (GeV/c^{2});entries", {HistType::kTH1F, {minvAxis}}); + registryMC.add("controlMCcomb/cut23/h3trkPtTot", ";p_{T} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCcomb/cut23/hDeltaPhi13topo", "#Delta #varphi 1+3 topo, 4 entries/event;#Delta#varphi^{1+3};entries", {HistType::kTH1F, {phiAxis}}); + registryMC.add("controlMCcomb/cut23/h13AssymPt1ProngAver", ";Delta Pt/Sum Pt (1Prong,Aver Pt)", {HistType::kTH1F, {{100, -1., 1.}}}); + registryMC.add("controlMCcomb/cut23/h13Vector", ";A_{V};entries", {HistType::kTH1F, {vectorAxis}}); + registryMC.add("controlMCcomb/cut23/h13Scalar", ";A_{S};entries", {HistType::kTH1F, {scalarAxis}}); + registryMC.add("controlMCcomb/cut23/hTPCnCrossedRows", "N crossed rows ;N_{TPC,crossed rows};entries", {HistType::kTH1F, {{160, 0, 160.}}}); + registryMC.add("controlMCcomb/cut23/hsigma3Pi", "#sqrt{#sigma_{1}^{2 }+#sigma_{2}^{2}+#sigma_{3}^{2}};#sigma^{3#pi};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry1MC.add("controlMCcomb/cut23/hTofChi2El", ";TOF #chi^{2};entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // ptSpectrum of electron for MC true and combinatorics + registryMC.add("controlMCtrue/cut0/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut20/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut21/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut22/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut23/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut24/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut25/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut26/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut27/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut28/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut29/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut30/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut31/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + // registryMC.add("controlMCtrue/cut32/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut33/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut34/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCtrue/cut35/hPtSpectrumEl", ";p_{T}^{e} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + + registryMC.add("controlMCcomb/cut0/hPtSpectrumEl", ";p_{T}^{comb} (GeV/c);entries", {HistType::kTH1F, {ptAxis}}); + registryMC.add("controlMCcomb/cut20/hPtSpectrumEl", ";p_{T}^{comb} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCcomb/cut21/hPtSpectrumEl", ";p_{T}^{comb} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCcomb/cut22/hPtSpectrumEl", ";p_{T}^{comb} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCcomb/cut23/hPtSpectrumEl", ";p_{T}^{comb} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCcomb/cut24/hPtSpectrumEl", ";p_{T}^{comb} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCcomb/cut25/hPtSpectrumEl", ";p_{T}^{comb} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCcomb/cut26/hPtSpectrumEl", ";p_{T}^{comb} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCcomb/cut27/hPtSpectrumEl", ";p_{T}^{comb} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCcomb/cut28/hPtSpectrumEl", ";p_{T}^{comb} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCcomb/cut29/hPtSpectrumEl", ";p_{T}^{comb} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCcomb/cut30/hPtSpectrumEl", ";p_{T}^{comb} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCcomb/cut31/hPtSpectrumEl", ";p_{T}^{comb} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCcomb/cut32/hPtSpectrumEl", ";p_{T}^{comb} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCcomb/cut33/hPtSpectrumEl", ";p_{T}^{comb} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCcomb/cut34/hPtSpectrumEl", ";p_{T}^{comb} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + registryMC.add("controlMCcomb/cut35/hPtSpectrumEl", ";p_{T}^{comb} (GeV/c);entries", {HistType::kTH1F, {axispt}}); + // zrobic hpTspectrumEl dla cut 0,20-35: registry.get(HIST("global/hFinalPtSpectrumEl"))->Fill(tmpPt[i]); + + // tau + registryMC.add("tauMC/hMCeta", ";#eta^{#tau};N^{#tau} ", {HistType::kTH1F, {{100, -5., 5.}}}); + registryMC.add("tauMC/hMCy", ";y^{#tau};N^{#tau}", {HistType::kTH1F, {{100, -5., 5.}}}); + registryMC.add("tauMC/hMCphi", ";#phi^{#tau};N^{#tau}", {HistType::kTH1F, {{100, 0., 6.4}}}); + registryMC.add("tauMC/hMCpt", ";#it{p}_{T}^{#tau};N^{#tau}", {HistType::kTH1F, {{100, 0., 10.}}}); + + registryMC.add("tauMC/hMCdeltaeta", ";#Delta#eta^{#tau};events ", {HistType::kTH1F, {{100, -5., 5.}}}); + registryMC.add("tauMC/hMCdeltaphi", ";#Delta#phi^{#tau}(deg.);events", {HistType::kTH1F, {{100, 131., 181}}}); + + // electron + registryMC.add("electronMC/hMCeta", ";#eta^{e};N^{e}", {HistType::kTH1F, {{100, -5., 5.}}}); + registryMC.add("electronMC/hMCy", ";y^{e};N^{e}", {HistType::kTH1F, {{100, -5., 5.}}}); + registryMC.add("electronMC/hMCphi", ";#phi^{e};N^{e}", {HistType::kTH1F, {{100, 0., 6.4}}}); + registryMC.add("electronMC/hMCpt", ";#it{p}_{T}^{e};N^{e}", {HistType::kTH1F, {{400, 0., 10.}}}); + + // efficiency mu + registryMC.add("efficiencyMCMu/effiMu", ";Efficiency #mu3#pi;events", {HistType::kTH1F, {{20, 0., 20.}}}); + registryMC.add("efficiencyMCMu/hpTmuon", ";p_{T}^{#mu, gen} (GeV/c);events", {HistType::kTH1F, {{200, 0., 5.}}}); + + // efficiency pi + registryMC.add("efficiencyMCPi/effiPi", ";Efficiency #pi3#pi;events", {HistType::kTH1F, {{20, 0., 20.}}}); + registryMC.add("efficiencyMCPi/hpTpi", ";p_{T}^{#pi, gen} (GeV/c);events", {HistType::kTH1F, {{200, 0., 5.}}}); + + // efficiency el + registryMC.add("efficiencyMCEl/effiEl", ";Efficiency e3#pi;events", {HistType::kTH1F, {{70, 0., 70.}}}); + registryMC.add("efficiencyMCEl/hpTelec", ";p_{T}^{e, gen} (GeV/c);events", {HistType::kTH1F, {axispt}}); + + // efficiency el + registryMC.add("efficiencyMCEl/hMCdeltaAlphaEpi", ";#Delta#alpha^{e-#pi(3x), gen} (rad);events", {HistType::kTH1F, {{100, -0.1, 3.2}}}); + registryMC.add("efficiencyMCEl/hMCdeltaAlphaPiPi", ";#Delta#alpha^{#pi-#pi(3x), gen} (rad);events", {HistType::kTH1F, {{100, -0.1, 3.2}}}); + registryMC.add("efficiencyMCEl/hMCdeltaPhiEpi", ";#Delta#phi^{e-#pi(3x), gen} (rad);events", {HistType::kTH1F, {{100, -0.1, 3.2}}}); + registryMC.add("efficiencyMCEl/hMCdeltaPhiPipi", ";#Delta#phi^{#pi-#pi(3x), gen} (rad);events", {HistType::kTH1F, {{100, -0.1, 3.2}}}); + registryMC.add("efficiencyMCEl/hMCvirtCal", ";virt Cal. #Delta #alpha^{#pi-#pi(3x), gen} (rad);events", {HistType::kTH1F, {{100, 0., 2.}}}); + registryMC.add("efficiencyMCEl/hMCScalar", ";A_{S}^{#pi-#pi(3x), gen};events", {HistType::kTH1F, {{100, 0., 1.}}}); + registryMC.add("efficiencyMCEl/hMCVector", ";A_{V}^{#pi-#pi(3x), gen};events", {HistType::kTH1F, {{100, 0., 2.}}}); + + // missing eta vs phi + registryMC.add("efficiencyMCEl/hMCptEl", ";p_{T}^{e, true} (GeV/c) ;events", {HistType::kTH1F, {{200, 0., 5.}}}); + // registryMC.add("efficiencyMCEl/hMCpt4trk",";p_{T}^{4 MC part.} (GeV/c) ;events",{HistType::kTH1F,{{100, 0., 5.}}}); + registryMC.add("efficiencyMCEl/hMCpt4trk", ";p_{T}^{4 MC part.} (GeV/c) ;events", {HistType::kTH1F, {axispt}}); + // registryMC.add("efficiencyMCEl/hMCinvmass4pi",";M_{inv}^{4#pi true} (GeV/c^{2}) ;events",{HistType::kTH1F,{{100, 0.4, 5.4}}}); + registryMC.add("efficiencyMCEl/hMCinvmass4pi", ";M_{inv}^{4#pi true} (GeV/c^{2}) ;events", {HistType::kTH1F, {axisInvMass4trk}}); + registryMC.add("efficiencyMCEl/hMCinvmass3pi", ";M_{inv}^{3#pi true} (GeV/c^{2}) ;events", {HistType::kTH1F, {{100, 0.4, 2.4}}}); + registryMC.add("efficiencyMCEl/hMCdeltaphi13", ";#Delta#phi^{1-3 true} ;events", {HistType::kTH1F, {{100, 0., 3.2}}}); + + } // end of MC histograms processEfficiencyMCSG + + if (doprocessDoSkim) { + registrySkim.add("skim/efficiency", ";efficeincy;events", {HistType::kTH1F, {{10, 0., 10.}}}); + } + + } // end of init method + + float eta(float px, float py, float pz) + // Just a simple function to return pseudorapidity + { + float arg = -2.; // outside valid range for std::atanh + float mom = std::sqrt(px * px + py * py + pz * pz); + if (mom != 0) + arg = pz / mom; + if (-1. < arg && arg < 1.) + return std::atanh(arg); // definition of eta + return -999.; + } + + float phi(float px, float py) + // Just a simple function to return azimuthal angle from 0 to 2pi + { + if (px != 0) + return (std::atan2(py, px) + o2::constants::math::PI); + return -999.; + } + + float pt(float px, float py) + // Just a simple function to return pt + { + return std::sqrt(px * px + py * py); + } + + float rapidity(float energy, float pz) + // Just a simple function to return track rapidity + { + return 0.5 * std::log((energy + pz) / (energy - pz)); + } + + // helper function to calculate delta alpha + float deltaAlpha(auto particle1, auto particle2) + { + + TVector3 vtmp(particle1.px(), particle1.py(), particle1.pz()); + TVector3 v1(particle2.px(), particle2.py(), particle2.pz()); + auto angle = v1.Angle(vtmp); + + return angle; } - float CalculateDeltaPhi(TLorentzVector p, TLorentzVector p1) + float invariantMass(float E, float px, float py, float pz) + // Just a simple function to return invariant mass { - float delta = p.Phi(); - if (delta < 0) - delta += TMath::TwoPi(); - if (p1.Phi() < 0) - delta -= (p1.Phi() + TMath::TwoPi()); - else - delta -= p1.Phi(); - if (delta < 0) - delta += TMath::TwoPi(); - if (delta > TMath::Pi()) - delta = TMath::TwoPi() - delta; + return std::sqrt(E * E - px * px - py * py - pz * pz); + } + + float calculateDeltaPhi(TLorentzVector p, TLorentzVector p1) + { + // float delta = p.Phi(); + float delta = RecoDecay::constrainAngle(p.Phi()); + // if (delta < 0) + // delta += o2::constants::math::TwoPI; + // if (p1.Phi() < 0) + // delta -= (p1.Phi() + o2::constants::math::TwoPI); + // else + delta -= RecoDecay::constrainAngle(p1.Phi()); + delta = RecoDecay::constrainAngle(delta); + // if (delta < 0) + // delta += o2::constants::math::TwoPI; + if (delta > o2::constants::math::PI) + delta = o2::constants::math::TwoPI - delta; + return delta; + } + + float calculateDeltaPhi(float p, float p1) + { + float delta = RecoDecay::constrainAngle(p); + // if (delta < 0) + // delta += o2::constants::math::TwoPI; + // if (p1 < 0) + // delta -= (p1 + o2::constants::math::TwoPI); + // else + delta -= RecoDecay::constrainAngle(p1); + delta = RecoDecay::constrainAngle(delta); + // if (delta < 0) + // delta += o2::constants::math::TwoPI; + if (delta > o2::constants::math::PI) + delta = o2::constants::math::TwoPI - delta; return delta; } + // // helper function to calculate scalar asymmetry + // float scalarAsym(auto particle1, auto particle2){ + // auto delta = particle1.pt() - particle2.pt(); + // return TMath::Abs(delta)/(particle1.pt() + particle2.pt()); + // } + // + // // helper function to calculate vector asymmetry + // float vectorAsym(auto particle1, auto particle2){ + // auto delta = TMath::Sqrt((particle1.px() - particle2.px()) * (particle1.px() - particle2.px()) + + // (particle1.py() - particle2.py()) * (particle1.py() - particle2.py())); + // auto sum = TMath::Sqrt((particle1.px() + particle2.px()) * (particle1.px() + particle2.px()) + + // (particle1.py() + particle2.py()) * (particle1.py() + particle2.py())); + // return sum/delta; + // } + + // helper function to calculate scalar asymmetry + float scalarAsymMC(auto particle1, auto particle2) + { + auto pt1 = pt(particle1.px(), particle1.py()); + auto pt2 = pt(particle2.px(), particle2.py()); + auto delta = pt1 - pt2; + return std::abs(delta) / (pt1 + pt2); + } + + // helper function to calculate vector asymmetry + float vectorAsym(auto particle1, auto particle2) + { + auto delta = std::sqrt((particle1.px() - particle2.px()) * (particle1.px() - particle2.px()) + + (particle1.py() - particle2.py()) * (particle1.py() - particle2.py())); + auto sum = std::sqrt((particle1.px() + particle2.px()) * (particle1.px() + particle2.px()) + + (particle1.py() + particle2.py()) * (particle1.py() + particle2.py())); + return sum / delta; + } + // fill control histograms per track template - void FillControlHistos(T pi3invMass, float pi3pt, float pi3deltaPhi, float pi3assymav, float pi3vector, float pi3scalar, float pi3etasum) + // void fillControlHistos(T pi3invMass, float pi3pt, float pi3deltaPhi, float pi3assymav, float pi3vector, float pi3scalar, float pi3etasum, float nCRtpc) + void fillControlHistos(T pi3invMass, float pi3pt, float pi3deltaPhi, float pi3assymav, float pi3vector, float pi3scalar, float nCRtpc, float ptelec, float tofchi2) + { + static constexpr std::string_view kHistoname[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", + "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", + "30", "31", "32", "33", "34", "35", "36", "37", "38", "39"}; + registry.get(HIST("control/cut") + HIST(kHistoname[mode]) + HIST("/h3piMassComb"))->Fill(pi3invMass); + registry.get(HIST("control/cut") + HIST(kHistoname[mode]) + HIST("/h3trkPtTot"))->Fill(pi3pt); + registry.get(HIST("control/cut") + HIST(kHistoname[mode]) + HIST("/hDeltaPhi13topo"))->Fill(pi3deltaPhi); + registry.get(HIST("control/cut") + HIST(kHistoname[mode]) + HIST("/h13AssymPt1ProngAver"))->Fill(pi3assymav); + registry.get(HIST("control/cut") + HIST(kHistoname[mode]) + HIST("/h13Vector"))->Fill(pi3vector); + registry.get(HIST("control/cut") + HIST(kHistoname[mode]) + HIST("/h13Scalar"))->Fill(pi3scalar); + // registry.get(HIST("control/cut") + HIST(kHistoname[mode]) + HIST("/h13EtaSum"))->Fill(pi3etasum); + registry.get(HIST("control/cut") + HIST(kHistoname[mode]) + HIST("/hTPCnCrossedRows"))->Fill(nCRtpc); + registry.get(HIST("control/cut") + HIST(kHistoname[mode]) + HIST("/hPtSpectrumEl"))->Fill(ptelec); + registry.get(HIST("control/cut") + HIST(kHistoname[mode]) + HIST("/hTofChi2El"))->Fill(tofchi2); + } + + // fill control histograms per track in MC true + template + void fillControlHistosMCtrue(T pi3invMass, float pi3pt, float pi3deltaPhi, float pi3assymav, float pi3vector, float pi3scalar, float nCRtpc, float ptelec, float tofchi2) + { + static constexpr std::string_view kHistoname[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", + "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", + "30", "31", "32", "33", "34", "35", "36", "37", "38", "39"}; + registryMC.get(HIST("controlMCtrue/cut") + HIST(kHistoname[mode]) + HIST("/h3piMass"))->Fill(pi3invMass); + registryMC.get(HIST("controlMCtrue/cut") + HIST(kHistoname[mode]) + HIST("/h3trkPtTot"))->Fill(pi3pt); + registryMC.get(HIST("controlMCtrue/cut") + HIST(kHistoname[mode]) + HIST("/hDeltaPhi13topo"))->Fill(pi3deltaPhi); + registryMC.get(HIST("controlMCtrue/cut") + HIST(kHistoname[mode]) + HIST("/h13AssymPt1ProngAver"))->Fill(pi3assymav); + registryMC.get(HIST("controlMCtrue/cut") + HIST(kHistoname[mode]) + HIST("/h13Vector"))->Fill(pi3vector); + registryMC.get(HIST("controlMCtrue/cut") + HIST(kHistoname[mode]) + HIST("/h13Scalar"))->Fill(pi3scalar); + registryMC.get(HIST("controlMCtrue/cut") + HIST(kHistoname[mode]) + HIST("/hTPCnCrossedRows"))->Fill(nCRtpc); + registryMC.get(HIST("controlMCtrue/cut") + HIST(kHistoname[mode]) + HIST("/hPtSpectrumEl"))->Fill(ptelec); + // registryMC.get(HIST("controlMCtrue/cut") + HIST(kHistoname[mode]) + HIST("/h13EtaSum"))->Fill(pi3etasum); + registry1MC.get(HIST("controlMCtrue/cut") + HIST(kHistoname[mode]) + HIST("/hTofChi2El"))->Fill(tofchi2); + } + + // fill control histograms per track in MC true + template + void fillControlHistosMCcomb(T pi3invMass, float pi3pt, float pi3deltaPhi, float pi3assymav, float pi3vector, float pi3scalar, float nCRtpc, float ptelec, float tofchi2) { - static constexpr std::string_view histoname[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", - "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", - "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", - "30", "31", "32", "33", "34", "35", "36", "37", "38", "39"}; - registry.get(HIST("control/cut") + HIST(histoname[mode]) + HIST("/h3piMassComb"))->Fill(pi3invMass); - registry.get(HIST("control/cut") + HIST(histoname[mode]) + HIST("/h3trkPtTot"))->Fill(pi3pt); - registry.get(HIST("control/cut") + HIST(histoname[mode]) + HIST("/hDeltaPhi13topo"))->Fill(pi3deltaPhi); - registry.get(HIST("control/cut") + HIST(histoname[mode]) + HIST("/h13AssymPt1ProngAver"))->Fill(pi3assymav); - registry.get(HIST("control/cut") + HIST(histoname[mode]) + HIST("/h13Vector"))->Fill(pi3vector); - registry.get(HIST("control/cut") + HIST(histoname[mode]) + HIST("/h13Scalar"))->Fill(pi3scalar); - registry.get(HIST("control/cut") + HIST(histoname[mode]) + HIST("/h13EtaSum"))->Fill(pi3etasum); + static constexpr std::string_view kHistoname[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", + "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", + "30", "31", "32", "33", "34", "35", "36", "37", "38", "39"}; + registryMC.get(HIST("controlMCcomb/cut") + HIST(kHistoname[mode]) + HIST("/h3piMass"))->Fill(pi3invMass); + registryMC.get(HIST("controlMCcomb/cut") + HIST(kHistoname[mode]) + HIST("/h3trkPtTot"))->Fill(pi3pt); + registryMC.get(HIST("controlMCcomb/cut") + HIST(kHistoname[mode]) + HIST("/hDeltaPhi13topo"))->Fill(pi3deltaPhi); + registryMC.get(HIST("controlMCcomb/cut") + HIST(kHistoname[mode]) + HIST("/h13AssymPt1ProngAver"))->Fill(pi3assymav); + registryMC.get(HIST("controlMCcomb/cut") + HIST(kHistoname[mode]) + HIST("/h13Vector"))->Fill(pi3vector); + registryMC.get(HIST("controlMCcomb/cut") + HIST(kHistoname[mode]) + HIST("/h13Scalar"))->Fill(pi3scalar); + registryMC.get(HIST("controlMCcomb/cut") + HIST(kHistoname[mode]) + HIST("/hTPCnCrossedRows"))->Fill(nCRtpc); + registryMC.get(HIST("controlMCcomb/cut") + HIST(kHistoname[mode]) + HIST("/hPtSpectrumEl"))->Fill(ptelec); + // registryMC.get(HIST("controlMCtrue/cut") + HIST(kHistoname[mode]) + HIST("/h13EtaSum"))->Fill(pi3etasum); + registry1MC.get(HIST("controlMCcomb/cut") + HIST(kHistoname[mode]) + HIST("/hTofChi2El"))->Fill(tofchi2); } template - int TrackCheck(T track) + int trackCheck(T track) { // 1 if (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) @@ -316,44 +1733,316 @@ struct TauTau13topo { return -1; } - using UDCollisionsFull = soa::Join; - using UDCollisionFull = UDCollisionsFull::iterator; + // global track check + histogram cuts separatelly + template + bool isGlobalTrackCheck(T track) + { + bool isGlobalTrack = true; + registry.get(HIST("global/hTrackEfficiencyPVGlobal"))->Fill(0., 1.); + if (track.tpcNClsCrossedRows() > 70) { + registry.get(HIST("global/hTrackEfficiencyPVGlobal"))->Fill(1., 1.); + } else { + isGlobalTrack = false; + } + if (track.tpcNClsFindable() == 0) { + isGlobalTrack = false; + } else { + if (track.tpcNClsCrossedRows() / track.tpcNClsFindable() > 0.8) { + registry.get(HIST("global/hTrackEfficiencyPVGlobal"))->Fill(2., 1.); + } else { + isGlobalTrack = false; + } + } + if (track.tpcChi2NCl() < 4.) { + registry.get(HIST("global/hTrackEfficiencyPVGlobal"))->Fill(3., 1.); + } else { + isGlobalTrack = false; + } + if (track.itsChi2NCl() < 36.) { + registry.get(HIST("global/hTrackEfficiencyPVGlobal"))->Fill(4., 1.); + } else { + isGlobalTrack = false; + } + if (track.dcaZ() < 2.) { + registry.get(HIST("global/hTrackEfficiencyPVGlobal"))->Fill(5., 1.); + } else { + isGlobalTrack = false; + } + if (track.dcaXY() < 0.0105 * 0.035 / std::pow(track.pt(), 1.1)) { + registry.get(HIST("global/hTrackEfficiencyPVGlobal"))->Fill(6., 1.); + } else { + isGlobalTrack = false; + } + if (track.pt() > 0.1) { + registry.get(HIST("global/hTrackEfficiencyPVGlobal"))->Fill(7., 1.); + } else { + isGlobalTrack = false; + } + if (std::abs(eta(track.px(), track.py(), track.pz())) < 0.8) { + registry.get(HIST("global/hTrackEfficiencyPVGlobal"))->Fill(8., 1.); + } else { + isGlobalTrack = false; + } + if (track.hasITS()) { + registry.get(HIST("global/hTrackEfficiencyPVGlobal"))->Fill(9., 1.); + // old version + // clustermap1 = trk.itsClusterMap(); + // for (int bitNo = 0; bitNo < 7; bitNo++) { + // if (TESTBIT(clustermap1, bitNo)) { // check ITS bits/layers for each PV track + // registry.get(HIST("global/hITSbitPVtrk"))->Fill(bitNo, 1.); + // registry.get(HIST("global/hITSbitVsEtaPVtrk"))->Fill(p.Eta(), bitNo, 1.); + // nITSbits++; + // } + // } // end of loop over ITS bits + // + // isInnerITS = TESTBIT(clustermap1, 0) || TESTBIT(clustermap1, 1) || TESTBIT(clustermap1, 2); + // if (isInnerITS) { + // registry.get(HIST("global/hTrackEfficiencyPVGlobal"))->Fill(10., 1.); + // } else { + // isGlobalTrack = false; + // } + // + } else { + isGlobalTrack = false; + } + if (track.hasTPC()) { + registry.get(HIST("global/hTrackEfficiencyPVGlobal"))->Fill(11., 1.); + } else { + isGlobalTrack = false; + } + // final global track + if (isGlobalTrack) { + registry.get(HIST("global/hTrackEfficiencyPVGlobal"))->Fill(13., 1.); + } + return isGlobalTrack; + } // end of function + + // analysis track quality check with histogram filling + template + bool isGoodTrackCheckHisto(T track) + { + bool isGoodTrack = true; + registry.get(HIST("global/hTrackPVGood"))->Fill(0., 1.); + if (track.hasTPC()) { + registry.get(HIST("global/hTrackPVGood"))->Fill(1., 1.); + } else { + isGoodTrack = false; + } + if (track.tpcChi2NCl() < 4.) { + registry.get(HIST("global/hTrackPVGood"))->Fill(2., 1.); + } else { + isGoodTrack = false; + } + if (track.itsChi2NCl() < 36.) { + registry.get(HIST("global/hTrackPVGood"))->Fill(3., 1.); + } else { + isGoodTrack = false; + } + if (track.dcaZ() < 2.) { + registry.get(HIST("global/hTrackPVGood"))->Fill(4., 1.); + } else { + isGoodTrack = false; + } + if (track.dcaXY() < 0.0105 * 0.035 / std::pow(track.pt(), 1.1)) { + registry.get(HIST("global/hTrackPVGood"))->Fill(5., 1.); + } else { + isGoodTrack = false; + } + + if (track.tpcNClsCrossedRows() > 50) { + registry.get(HIST("global/hTrackPVGood"))->Fill(6., 1.); + } else { + isGoodTrack = false; + } + if (track.tpcNClsFindable() == 0) { + isGoodTrack = false; + } else { + if (track.tpcNClsCrossedRows() / track.tpcNClsFindable() > 0.8) { + registry.get(HIST("global/hTrackPVGood"))->Fill(7., 1.); + } else { + isGoodTrack = false; + } + } + if (isGoodTrack) { + registry.get(HIST("global/hTrackPVGood"))->Fill(13., 1.); + } + return isGoodTrack; + } + + // analysis track quality check + template + bool isGoodTrackCheck(T track) + { + if (!track.hasTPC()) + return false; + if (track.tpcChi2NCl() >= 4.) + return false; + if (track.itsChi2NCl() >= 36.) + return false; + // if (track.dcaZ() >= 2.) return false; + // if (track.dcaXY() >= 0.0105 * 0.035 / std::pow(track.pt(), 1.1)) return false; + if (track.tpcNClsCrossedRows() <= 50) + return false; + if (track.tpcNClsFindable() == 0) + return false; + if (track.tpcNClsCrossedRows() / track.tpcNClsFindable() <= 0.8) + return false; + return true; + } + + // analysis track quality check + template + bool isGoodTOFTrackCheckHisto(T track) + { + bool isGoodTrack = true; + if (track.hasTOF()) { + registry.get(HIST("global/hTrackPVGood"))->Fill(8., 1.); + } else { + isGoodTrack = false; + } + if (track.hasTOF() && track.tofChi2() < 3) { + registry.get(HIST("global/hTrackPVGood"))->Fill(9., 1.); + } else { + isGoodTrack = false; + } + return isGoodTrack; + } + + // analysis track quality check + template + bool isGoodTOFTrackCheck(T track) + { + if (!track.hasTOF()) + return false; + if (track.tofChi2() >= 3) + return false; + return true; + } + + // using UDCollisionsFull = soa::Join; + // using UDCollisionFull = UDCollisionsFull::iterator; using UDTracksFull = soa::Join; + // using UDCollisionsFull2 = soa::Join; // without occupancy cut + using UDCollisionsFull2 = soa::Join; + using UDCollisionFull2 = UDCollisionsFull2::iterator; + + // PVContributors + Filter pVContributorFilter = aod::udtrack::isPVContributor == true; + using PVTracks = soa::Filtered; - void process(UDCollisionFull const& dgcand, UDTracksFull const& dgtracks) + // using LabeledTracks = soa::Join; + using LabeledTracks = soa::Join; + Preslice perCollision = aod::udtrack::udCollisionId; + // PVContributors in MC handling + // Filter pVContributorFilterMC = aod::udtrack::isPVContributor == true; + // using PVTracksMC = soa::Filtered; + + // void processDG(UDCollisionFull const& dgcand, UDTracksFull const& dgtracks) + // { + // int gapSide = 2; + // mainTask(gapSide,dgtracks); + // } + // PROCESS_SWITCH(TauTau13topo, processDG, "Process DG data", DGactive); + + // void processSG(UDCollisionFull2 const& dgcand, UDTracksFull const& dgtracks) + void processDataSG(UDCollisionFull2 const& dgcand, UDTracksFull const& dgtracks, PVTracks const& PVContributors) { + registry.get(HIST("global/hEventEff"))->Fill(-2., 1.); + registry.get(HIST("global/RunNumber"))->Fill(dgcand.runNumber()); + if (removeNoTOFrunsInData) { + if (dgcand.runNumber() == 544091 || dgcand.runNumber() == 544095 || dgcand.runNumber() == 544121 || dgcand.runNumber() == 544451) + return; + } + registry.get(HIST("global/hEventEff"))->Fill(-1., 1.); + registry.get(HIST("global/hRecFlag"))->Fill(dgcand.flags()); // reconstruction with upc settings flag + registry.get(HIST("global/hOccupancyInTime"))->Fill(dgcand.occupancyInTime()); + + if (dgcand.occupancyInTime() >= occupancyCut) + return; + registry.get(HIST("global/hEventEff"))->Fill(0., 1.); + + int gapSide = dgcand.gapSide(); + int truegapSide = sgSelector.trueGap(dgcand, cutFV0, cutFT0A, cutFT0C, cutZDC); + registry.fill(HIST("global/GapSide"), gapSide); + registry.fill(HIST("global/GapSideTrue"), truegapSide); + if (gapSide < 0 || gapSide > 2) + return; + gapSide = truegapSide; + // mainTask(gapSide,dgtracks); + // } + // PROCESS_SWITCH(TauTau13topo, processSG, "Process SG data", SGactive); + // + // void mainTask(int gapSide, UDTracksFull const& dgtracks) + // { + registry.get(HIST("global/hEventEff"))->Fill(1., 1.); + if (gapSide != mGapSide) + return; // global checks registry.get(HIST("global/hVertexXY"))->Fill(dgcand.posX(), dgcand.posY()); registry.get(HIST("global/hVertexZ"))->Fill(dgcand.posZ()); - if (TMath::Abs(dgcand.posZ()) < 15) - registry.get(HIST("global/hVertexZ15"))->Fill(dgcand.posZ()); - if (TMath::Abs(dgcand.posZ()) < 10) - registry.get(HIST("global/hVertexZ10"))->Fill(dgcand.posZ()); + // if (TMath::Abs(dgcand.posZ()) < 10) + // registry.get(HIST("global/hVertexZ10"))->Fill(dgcand.posZ()); registry.get(HIST("global/hNTracks"))->Fill(dgtracks.size()); // setup PV tracks partition - Partition PVContributors = aod::udtrack::isPVContributor == true; - PVContributors.bindTable(dgtracks); + // Partition PVContributors = aod::udtrack::isPVContributor == true; + // PVContributors.bindTable(dgtracks); registry.get(HIST("global/hNTracksPV"))->Fill(PVContributors.size()); + // zdc information + float energyZNA = dgcand.energyCommonZNA(); + float energyZNC = dgcand.energyCommonZNC(); + // if (energyZNA < 0) registry.get(HIST("global/hZNACenergyTest"))->Fill(energyZNA); + // if (energyZNC < 0) registry.get(HIST("global/hZNACenergyTest"))->Fill(energyZNC); + if (energyZNA < 0) + energyZNA = -1.; + if (energyZNC < 0) + energyZNC = -1.; + registry.get(HIST("global/hZNACenergy"))->Fill(energyZNA, energyZNC); + registry.get(HIST("global/hZNACtime"))->Fill(dgcand.timeZNA(), dgcand.timeZNC()); + uint32_t clusterSizes; + // UChar_t clustermap1; + // bool isInnerITS = false; int nTofTrk = 0; int nEtaIn15 = 0; - int nITSbits = 0; + int nITSbits = -1; + int npT100 = 0; TLorentzVector p; - TParticlePDG* pion = pdg->GetParticle(211); + // auto const pionMass = MassPiPlus; + // auto const electronMass = MassElectron; + bool flagGlobalCheck = true; + // bool isGlobalTrack = true; + int qtot = 0; // loop over PV contributors for (const auto& trk : PVContributors) { - p.SetXYZM(trk.px(), trk.py(), trk.pz(), pion->Mass()); + qtot += trk.sign(); + p.SetXYZM(trk.px(), trk.py(), trk.pz(), MassPiPlus); registry.get(HIST("global/hTrackPtPV"))->Fill(p.Pt()); - if (TMath::Abs(p.Eta()) < trkEtacut) + if (std::abs(p.Eta()) < trkEtacut) nEtaIn15++; // 1.5 is a default registry.get(HIST("global/hTrackEtaPhiPV"))->Fill(p.Eta(), p.Phi()); - nITSbits = -1; + + if (trk.pt() > 0.1) + npT100++; + + if (flagGlobalCheck) { + if (isGlobalTrackCheck(trk)) { + registry.get(HIST("global/hTrackEtaPhiPVGlobal"))->Fill(p.Eta(), p.Phi()); + } + } // end of flag check global + + // check track selection + isGoodTrackCheckHisto(trk); + isGoodTOFTrackCheckHisto(trk); + + // new version if (trk.hasITS()) { // ITS track + nITSbits = -1; clusterSizes = trk.itsClusterSizes(); + // LOGF(info, " clistersize: %d", clusterSizes); for (int layer = 0; layer < 7; layer++) { if ((clusterSizes >> (layer * 4)) & 0xf) { registry.get(HIST("global/hITSbitPVtrk"))->Fill(layer, 1.); @@ -361,65 +2050,100 @@ struct TauTau13topo { nITSbits++; } } // end of loop over ITS bits - } // has ITS + // isInnerITS = TESTBIT(clustermap1, 0) || TESTBIT(clustermap1, 1) || TESTBIT(clustermap1, 2); + // if (isInnerITS) { + // registry.get(HIST("global/hTrackEfficiencyPVGlobal"))->Fill(10., 1.); + // } else { + // isGlobalTrack = false; + // } + } // has ITS registry.get(HIST("global/hITSnbitsVsEtaPVtrk"))->Fill(p.Eta(), nITSbits); if (trk.hasTPC()) registry.get(HIST("global/hSignalTPCvsPtPV"))->Fill(p.Pt(), trk.tpcSignal()); if (trk.hasTOF()) nTofTrk++; - } + } // end of loop over PV tracks registry.get(HIST("global/hNtofTrk"))->Fill(nTofTrk); // // selection // - registry.get(HIST("global/hEventEff"))->Fill(0., 1.); + registry.get(HIST("global/hEventEff"))->Fill(2., 1.); // skip events with too few/many tracks - if (dgcand.numContrib() != 4) { + // if (PVContributors.size() != 4 || dgcand.numContrib() != 4) { + if (PVContributors.size() != 4) { if (verbose) { - LOGF(info, " Candidate rejected: Number of PV contributors is %d", dgcand.numContrib()); + LOGF(info, " Candidate rejected: Number of PV contributors is %d, candContriv %d", PVContributors.size(), dgcand.numContrib()); } return; } - registry.get(HIST("global/hEventEff"))->Fill(1., 1.); - registry.get(HIST("global/hTrackPVTotCharge"))->Fill(dgcand.netCharge()); + // old version in DG producer + // if (dgcand.numContrib() != 4) { + // if (verbose) { + // LOGF(info, " Candidate rejected: Number of PV contributors is %d", dgcand.numContrib()); + // } + // return; + // } + + registry.get(HIST("global/hEventEff"))->Fill(3., 1.); + // registry.get(HIST("global1/hTrackPVTotCharge"))->Fill(dgcand.netCharge()); + registry.get(HIST("global1/hTrackPVTotCharge"))->Fill(qtot); + registry.get(HIST("global1/hVertexZ"))->Fill(dgcand.posZ()); + registry.get(HIST("global1/hNTracks"))->Fill(dgtracks.size()); + registry.get(HIST("global1/hNTracksPV"))->Fill(PVContributors.size()); + for (const auto& trk : PVContributors) { + p.SetXYZM(trk.px(), trk.py(), trk.pz(), MassPiPlus); + registry.get(HIST("global1/hTrackPtPV"))->Fill(p.Pt()); + registry.get(HIST("global1/hTrackEtaPhiPV"))->Fill(p.Eta(), p.Phi()); + } - // if vz < 15 - if (TMath::Abs(dgcand.posZ()) >= zvertexcut) { // default = 15 + // if vz < 10 + if (std::abs(dgcand.posZ()) >= zvertexcut) { // default = 10 if (verbose) { LOGF(info, " Candidate rejected: VertexZ is %f", dgcand.posZ()); } return; } - registry.get(HIST("global/hEventEff"))->Fill(2., 1.); + registry.get(HIST("global/hEventEff"))->Fill(4., 1.); // if eta tracks <1.5 if (nEtaIn15 != 4) { if (verbose) { - LOGF(info, " Candidate rejected: Ntrk inside |eta|<1.5 is %d", nEtaIn15); + LOGF(info, " Candidate rejected: Ntrk inside |eta|<0.9 is %d", nEtaIn15); } return; } - registry.get(HIST("global/hEventEff"))->Fill(3., 1.); + registry.get(HIST("global/hEventEff"))->Fill(5., 1.); + + // if pt tracks >0.100 GeV/c + if (npT100 != 4) { + if (verbose) { + LOGF(info, " Candidate rejected: number of tracks with pT>0.1GeV/c is %d", npT100); + } + return; + } + registry.get(HIST("global/hEventEff"))->Fill(6., 1.); // skip events with net charge != 0 if (!sameSign) { // opposite sign is signal - if (dgcand.netCharge() != 0) { + // if (dgcand.netCharge() != 0) { + if (qtot != 0) { if (verbose) { - LOGF(info, " Candidate rejected: Net charge is %d, while should be 0", dgcand.netCharge()); + LOGF(info, " Candidate rejected: Net charge is %d (dgcand %d), while should be 0", qtot, dgcand.netCharge()); } return; } } else { // same sign is background - if (dgcand.netCharge() == 0) { + // if (dgcand.netCharge() == 0) { + if (qtot == 0) { if (verbose) { - LOGF(info, " Candidate rejected: Net charge is %d, while should be not 0", dgcand.netCharge()); + LOGF(info, " Candidate rejected: Net charge is %d (dgcand %d), while should be not 0", qtot, dgcand.netCharge()); } return; } } - registry.get(HIST("global/hEventEff"))->Fill(4., 1.); + registry.get(HIST("global/hEventEff"))->Fill(7., 1.); // // skip events with out-of-range rgtrwTOF (fraction-of-good-tracks-with-TOF-hit) // auto rtrwTOF = udhelpers::rPVtrwTOF(dgtracks, PVContributors.size()); @@ -429,8 +2153,36 @@ struct TauTau13topo { // } // return; // } + + // n TOF tracks cut + if (nTofTrk < nTofTrkMinCut) { + if (verbose) { + LOGF(info, " Candidate rejected: nTOFtracks is %d", nTofTrk); + } + return; + } + registry.get(HIST("global/hEventEff"))->Fill(8., 1.); + // // FIT informaton + // + auto bitMin = 16 - mFITvetoWindow; // default is +- 1 bc (1 bit) + auto bitMax = 16 + mFITvetoWindow; + bool flagFITveto = false; + // check FIT information + for (auto bit = bitMin; bit <= bitMax; bit++) { + if (TESTBIT(dgcand.bbFT0Apf(), bit)) + flagFITveto = true; + if (TESTBIT(dgcand.bbFT0Cpf(), bit)) + flagFITveto = true; + if (useFV0ForVeto && TESTBIT(dgcand.bbFV0Apf(), bit)) + flagFITveto = true; + if (useFDDAForVeto && TESTBIT(dgcand.bbFDDApf(), bit)) + flagFITveto = true; + if (useFDDCForVeto && TESTBIT(dgcand.bbFDDCpf(), bit)) + flagFITveto = true; + } // end of loop over FIT bits + // FIT histos for (auto bit = 0; bit <= 32; bit++) { registry.get(HIST("fit/bbFT0Abit"))->Fill(bit, TESTBIT(dgcand.bbFT0Apf(), bit)); registry.get(HIST("fit/bbFT0Cbit"))->Fill(bit, TESTBIT(dgcand.bbFT0Cpf(), bit)); @@ -449,19 +2201,14 @@ struct TauTau13topo { registry.get(HIST("fit/timeFT0"))->Fill(dgcand.timeFT0A(), dgcand.timeFT0C()); registry.get(HIST("fit/timeFDD"))->Fill(dgcand.timeFDDA(), dgcand.timeFDDC()); - // check FIT information - // auto bitMin = -1 + 16; - // auto bitMax = 1 + 16; - // for (auto bit = bitMin; bit <= bitMax; bit++) { - // if (TESTBIT(dgcand.bbFT0Apf(), bit) || - // TESTBIT(dgcand.bbFT0Cpf(), bit) || - // TESTBIT(dgcand.bbFV0Apf(), bit) || - // TESTBIT(dgcand.bbFDDApf(), bit) || - // TESTBIT(dgcand.bbFDDCpf(), bit)) { - // return; - // } - // } - // registry.get(HIST("global/hEventEff"))->Fill(5., 1.); + // FIT empty + if (mFITvetoFlag && flagFITveto) { + if (verbose) { + LOGF(info, " Candidate rejected: FIT is not empty"); + } + return; + } + registry.get(HIST("global/hEventEff"))->Fill(9., 1.); // // here PID from TPC starts to be @@ -470,33 +2217,75 @@ struct TauTau13topo { float tmpMomentum[4]; float tmpPt[4]; float tmpDedx[4]; + float tmpTofNsigmaEl[4]; float pi3invMass[4]; float pi3pt[4]; float pi3deltaPhi[4]; float pi3assymav[4]; float pi3vector[4]; float pi3scalar[4]; - float pi3etasum[4]; + // float pi3etasum[4]; float deltaPhiTmp = 0; float scalarPtsum = 0; float nSigmaEl[4]; float nSigmaPi[4]; + float nSigma3Pi[4] = {0., 0., 0., 0.}; + float nSigma3PiNew[4] = {0., 0., 0., 0.}; float nSigmaPr[4]; float nSigmaKa[4]; - float dcaZ[4]; - float dcaXY[4]; - float chi2TPC[4]; - float chi2ITS[4]; - float nclTPCfind[4]; + // float dcaZ[4]; + // float dcaXY[4]; + // float chi2TPC[4]; + // float chi2ITS[4]; + float chi2TOF[4] = {-1., -1., -1., -1.}; + // float nclTPCfind[4]; + float nclTPCcrossedRows[4]; + bool trkHasTof[4]; + bool trkHasTpc[4]; + float mass3pi1e[4]; + double trkTime[4]; + float trkTimeRes[4]; + double trkTimeTot = 0.; + float trkTimeResTot = 10000.; + int nPiHasTPC[4] = {0, 0, 0, 0}; + + // 2 gamma from 4 electrons + // 12 34 | 01 23 |//1 //6 | 0 5 |counter<3?counter:5-counter counter<3?0:1 + // 13 24 | 02 13 |//2 //5 | 1 4 | + // 14 23 | 03 12 |//3 //4 | 2 3 | + TLorentzVector p1, p2; + TLorentzVector gammaPair[3][2]; + float invMass2El[3][2]; + int counterTmp = 0; + bool flagIMGam2ePV[4] = {true, true, true, true}; + + for (const auto& trk : PVContributors) { + p.SetXYZM(trk.px(), trk.py(), trk.pz(), MassElectron); + for (const auto& trk1 : PVContributors) { + if (trk.index() >= trk1.index()) + continue; + if (trk1.hasTPC()) + nPiHasTPC[trk.index()]++; + p1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), MassElectron); + invMass2El[(counterTmp < 3 ? counterTmp : 5 - counterTmp)][(counterTmp < 3 ? 0 : 1)] = (p + p1).Mag2(); + gammaPair[(counterTmp < 3 ? counterTmp : 5 - counterTmp)][(counterTmp < 3 ? 0 : 1)] = (p + p1); + registry.get(HIST("control/cut0/hInvMass2ElAll"))->Fill((p + p1).Mag2()); + counterTmp++; + if ((p + p1).M() < 0.015) { + flagIMGam2ePV[trk.index()] = false; + flagIMGam2ePV[trk1.index()] = false; + } + } // end of loop over PVContributors + } // end of loop over PVContributors // first loop to add all the tracks together - TLorentzVector p1; p = TLorentzVector(0., 0., 0., 0.); for (const auto& trk : PVContributors) { - p1.SetXYZM(trk.px(), trk.py(), trk.pz(), pion->Mass()); + p1.SetXYZM(trk.px(), trk.py(), trk.pz(), MassPiPlus); p += p1; scalarPtsum += trk.pt(); - } + } // end of loop over PVContributors + float pttot = p.Pt(); float mass4pi = p.Mag(); @@ -506,13 +2295,24 @@ struct TauTau13topo { // remove combinatoric bool flagVcalPV[4] = {false, false, false, false}; + // bool trkIsGood[4] = {false, false, false, false}; + bool trkIsTOFGood[4] = {false, false, false, false}; + // second loop to calculate 1 by 1 each combinatorial variable - int counterTmp = 0; + counterTmp = 0; int tmpTrkCheck = -1; for (const auto& trk : PVContributors) { - tmpTrkCheck = TrackCheck(trk); // check detectors associated to track + // trkIsGood[counterTmp] = + isGoodTrackCheck(trk); + trkIsTOFGood[counterTmp] = isGoodTOFTrackCheck(trk); + tmpTrkCheck = trackCheck(trk); // check detectors associated to track registry.get(HIST("global/hTrkCheck"))->Fill(tmpTrkCheck); + // inv mass of 3pi + 1e + p1.SetXYZM(trk.px(), trk.py(), trk.pz(), MassPiPlus); + p2.SetXYZM(trk.px(), trk.py(), trk.pz(), MassElectron); + mass3pi1e[counterTmp] = (p - p1 + p2).Mag(); + v1.SetXYZ(trk.px(), trk.py(), trk.pz()); for (const auto& trk1 : PVContributors) { if (trk.index() == trk1.index()) @@ -523,46 +2323,181 @@ struct TauTau13topo { if (deltaphi < minAnglecut) { // default 0.05 flagVcalPV[counterTmp] = true; } - } + } // end of loop over PVContributors nSigmaEl[counterTmp] = trk.tpcNSigmaEl(); nSigmaPi[counterTmp] = trk.tpcNSigmaPi(); - nSigmaPr[counterTmp] = trk.tpcNSigmaPr(); - nSigmaKa[counterTmp] = trk.tpcNSigmaKa(); - dcaZ[counterTmp] = trk.dcaZ(); - dcaXY[counterTmp] = trk.dcaXY(); - chi2TPC[counterTmp] = trk.tpcChi2NCl(); - chi2ITS[counterTmp] = trk.itsChi2NCl(); - nclTPCfind[counterTmp] = trk.tpcNClsFindable(); + nSigma3Pi[3] += (nSigmaPi[counterTmp] * nSigmaPi[counterTmp]); + if (trk.hasTPC()) + nSigma3PiNew[3] += (nSigmaPi[counterTmp] * nSigmaPi[counterTmp]); + + if (whichPIDCut == 1) { // TPC only + nSigmaPr[counterTmp] = trk.tpcNSigmaPr(); + nSigmaKa[counterTmp] = trk.tpcNSigmaKa(); + } else if (whichPIDCut == 2) { // TPC + TOF sigma + nSigmaPr[counterTmp] = std::sqrt(trk.tofNSigmaPr() * trk.tofNSigmaPr() + trk.tpcNSigmaPr() * trk.tpcNSigmaPr()); + nSigmaKa[counterTmp] = std::sqrt(trk.tofNSigmaKa() * trk.tofNSigmaKa() + trk.tpcNSigmaKa() * trk.tpcNSigmaKa()); + } else if (whichPIDCut == 3) { // TPC + TOF hardcoded pt + nSigmaPr[counterTmp] = (trk.pt() < 1.5 ? trk.tofNSigmaPr() : trk.tpcNSigmaPr()); + nSigmaKa[counterTmp] = (trk.pt() < 1.3 ? trk.tofNSigmaKa() : trk.tpcNSigmaKa()); + } else { + nSigmaPr[counterTmp] = trk.tpcNSigmaPr(); + nSigmaKa[counterTmp] = trk.tpcNSigmaKa(); + } + + // dcaZ[counterTmp] = trk.dcaZ(); + // dcaXY[counterTmp] = trk.dcaXY(); + // chi2TPC[counterTmp] = trk.tpcChi2NCl(); + // chi2ITS[counterTmp] = trk.itsChi2NCl(); + if (trk.hasTOF()) + chi2TOF[counterTmp] = trk.tofChi2(); + // nclTPCfind[counterTmp] = trk.tpcNClsFindable(); + nclTPCcrossedRows[counterTmp] = trk.tpcNClsCrossedRows(); + // trkHasTof[counterTmp] = trk.hasTOF(); + trkHasTof[counterTmp] = isGoodTOFTrackCheck(trk); + trkHasTpc[counterTmp] = trk.hasTPC(); + trkTime[counterTmp] = trk.trackTime(); + trkTimeRes[counterTmp] = trk.trackTimeRes(); - p1.SetXYZM(trk.px(), trk.py(), trk.pz(), pion->Mass()); + p1.SetXYZM(trk.px(), trk.py(), trk.pz(), MassPiPlus); tmpMomentum[counterTmp] = p1.P(); tmpPt[counterTmp] = p1.Pt(); tmpDedx[counterTmp] = trk.tpcSignal(); + tmpTofNsigmaEl[counterTmp] = trk.tofNSigmaEl(); - deltaPhiTmp = CalculateDeltaPhi(p - p1, p1); + deltaPhiTmp = calculateDeltaPhi(p - p1, p1); pi3invMass[counterTmp] = (p - p1).Mag(); pi3pt[counterTmp] = (p - p1).Pt(); pi3deltaPhi[counterTmp] = deltaPhiTmp; pi3assymav[counterTmp] = (p1.Pt() - (scalarPtsum - p1.Pt()) / 3.) / (p1.Pt() + (scalarPtsum - p1.Pt()) / 3.); - pi3vector[counterTmp] = (p + p1).Pt() / (p - p1).Pt(); - pi3scalar[counterTmp] = (p.Pt() - p1.Pt()) / (p.Pt() + p1.Pt()); - pi3etasum[counterTmp] = (p - p1).Eta() + p1.Eta(); + // pi3vector[counterTmp] = (p + p1).Pt() / (p - p1).Pt(); + pi3vector[counterTmp] = p.Pt() / (p - p1 - p1).Pt(); + // pi3scalar[counterTmp] = (p.Pt() - p1.Pt()) / (p.Pt() + p1.Pt()); + pi3scalar[counterTmp] = ((p - p1).Pt() - p1.Pt()) / ((p - p1).Pt() + p1.Pt()); counterTmp++; + } // end of loop over PVContributors + + // calculate trk time and resolution total + // 1. find best resolution + int iTmpBest = -1; + for (int i = 0; i < 4; i++) { + if (trkTimeRes[i] < trkTimeResTot) { + trkTimeResTot = trkTimeRes[i]; + iTmpBest = i; + } + } + // 2. use best resol to calculate total time + for (int i = 0; i < 4; i++) { + if (i == iTmpBest) + continue; + trkTimeTot += std::abs(trkTime[iTmpBest] - trkTime[i]); } + trkTimeResTot = std::sqrt(trkTimeRes[0] * trkTimeRes[0] + + trkTimeRes[1] * trkTimeRes[1] + + trkTimeRes[2] * trkTimeRes[2] + + trkTimeRes[3] * trkTimeRes[3]); // control histos, max 4 per event, cut0 for (int i = 0; i < 4; i++) { - FillControlHistos<0>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], pi3etasum[i]); + fillControlHistos<0>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); registry.get(HIST("control/cut0/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); registry.get(HIST("pidTPC/hpvsdedxElHipCut0"))->Fill(tmpMomentum[i], tmpDedx[i]); - } + registry.get(HIST("pidTOF/hpvsNsigmaElHipCut0"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + // nsigma3Pi calculation + nSigma3Pi[i] = nSigma3Pi[3] - (nSigmaPi[i] * nSigmaPi[i]); + nSigma3Pi[i] = std::sqrt(nSigma3Pi[i]); + registry.get(HIST("control/cut0/hsigma3Pi"))->Fill(nSigma3Pi[i]); + // nsigma3PiNew calculation + if (trkHasTpc[i]) { + nSigma3PiNew[i] = nSigma3PiNew[3] - (nSigmaPi[i] * nSigmaPi[i]); + } + nSigma3PiNew[i] = std::sqrt(nSigma3PiNew[i]); + + if (nPiHasTPC[i] == 3) + registry.get(HIST("control/cut0/hsigma3PiNew"))->Fill(nSigma3PiNew[i]); + if (nPiHasTPC[i] == 2) + registry.get(HIST("control/cut0/hsigma2PiNew"))->Fill(nSigma3PiNew[i]); + if (nPiHasTPC[i] == 1) + registry.get(HIST("control/cut0/hsigma1PiNew"))->Fill(nSigma3PiNew[i]); + // + registry.get(HIST("control/cut0/h3pi1eMass"))->Fill(mass3pi1e[i]); + } // end of loop over 4 tracks + // control, 1 per event registry.get(HIST("control/cut0/h4trkPtTot"))->Fill(pttot); registry.get(HIST("control/cut0/h4piMass"))->Fill(mass4pi); registry.get(HIST("control/cut0/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registry.get(HIST("control/cut0/hNtofTrk"))->Fill(nTofTrk); + registry.get(HIST("control/cut0/hZNACenergy"))->Fill(energyZNA, energyZNC); - // remove combinatoric + if (pttot < 0.150) { + // give all the gg combinations + // 12 34 + // 13 24 + // 14 23 + int nGamPair = 0; + int nGamma = 0; + int whichPair = -1; + float scalarAsym = -1; + float vectorAsym = -1; + bool electronCheck = true; + for (int i = 0; i < 4; i++) { + if (std::abs(nSigmaEl[i]) > 5) + electronCheck = false; + } // end of loop over 4 tracks + + for (int i = 0; i < 3; i++) { + registry.get(HIST("control/cut0/hInvMass2ElCoh"))->Fill(invMass2El[i][0]); + registry.get(HIST("control/cut0/hInvMass2ElCoh"))->Fill(invMass2El[i][1]); + registry.get(HIST("control/cut0/hGamPtCoh"))->Fill(gammaPair[i][0].Pt()); + registry.get(HIST("control/cut0/hGamPtCoh"))->Fill(gammaPair[i][1].Pt()); + if (invMass2El[i][0] < 0.15) { + nGamma++; + registry.get(HIST("control/cut0/hGamPtCohIM0"))->Fill(gammaPair[i][0].Pt()); + } + if (invMass2El[i][1] < 0.15) { + nGamma++; + registry.get(HIST("control/cut0/hGamPtCohIM0"))->Fill(gammaPair[i][1].Pt()); + } + if (invMass2El[i][0] < 0.15 && invMass2El[i][1] < 0.15) { + nGamPair++; + whichPair = i; + } + } // end of loop over 3 tracks + registry.get(HIST("control/cut0/hN2gamma"))->Fill(nGamma); + registry.get(HIST("control/cut0/hN2gamma"))->Fill(10 + nGamPair); + if (nGamPair == 1) { + scalarAsym = std::abs(gammaPair[whichPair][1].Pt() - gammaPair[whichPair][0].Pt()) / (gammaPair[whichPair][1].Pt() + gammaPair[whichPair][0].Pt()); + if ((gammaPair[whichPair][1] - gammaPair[whichPair][0]).Pt() != 0) + vectorAsym = (gammaPair[whichPair][1] + gammaPair[whichPair][0]).Pt() / (gammaPair[whichPair][1] - gammaPair[whichPair][0]).Pt(); + registry.get(HIST("control/cut0/hGamAS"))->Fill(scalarAsym); + registry.get(HIST("control/cut0/hGamAV"))->Fill(vectorAsym); + registry.get(HIST("control/cut0/hInvMass2GamCoh"))->Fill((gammaPair[whichPair][1] + gammaPair[whichPair][0]).M()); + registry.get(HIST("control/cut0/hDeltaPhi2GamCoh"))->Fill(calculateDeltaPhi(gammaPair[whichPair][1], gammaPair[whichPair][0])); + for (int j = 0; j < 4; j++) + registry.get(HIST("pidTPC/hpvsdedxElHipCut40"))->Fill(tmpMomentum[j], tmpDedx[j]); + if ((gammaPair[whichPair][1] + gammaPair[whichPair][0]).M() > 3. && + (gammaPair[whichPair][1] + gammaPair[whichPair][0]).M() < 4.) { + for (int j = 0; j < 4; j++) + registry.get(HIST("pidTPC/hpvsdedxElHipCut0CohPsi2s"))->Fill(tmpMomentum[j], tmpDedx[j]); + } + + if (electronCheck) { + registry.get(HIST("control/cut20/hInvMass2ElCoh"))->Fill(gammaPair[whichPair][0].M()); + registry.get(HIST("control/cut20/hInvMass2ElCoh"))->Fill(gammaPair[whichPair][1].M()); + registry.get(HIST("control/cut20/hGamPtCohIM0"))->Fill(gammaPair[whichPair][0].Pt()); + registry.get(HIST("control/cut20/hGamPtCohIM0"))->Fill(gammaPair[whichPair][1].Pt()); + registry.get(HIST("control/cut20/hGamAS"))->Fill(scalarAsym); + registry.get(HIST("control/cut20/hGamAV"))->Fill(vectorAsym); + registry.get(HIST("control/cut20/hInvMass2GamCoh"))->Fill((gammaPair[whichPair][1] + gammaPair[whichPair][0]).M()); + registry.get(HIST("control/cut20/hDeltaPhi2GamCoh"))->Fill(calculateDeltaPhi(gammaPair[whichPair][1], gammaPair[whichPair][0])); + } + + } // ngam = 1 + + } // end of check ptot<0.15 + + // remove combinatorics bool flagTotal[4] = {false, false, false, false}; bool flagIM[4] = {false, false, false, false}; bool flagDP[4] = {false, false, false, false}; @@ -571,18 +2506,24 @@ struct TauTau13topo { bool flagPt[4] = {false, false, false, false}; bool flagPr[4] = {false, false, false, false}; bool flagKa[4] = {false, false, false, false}; + bool flagCR[4] = {false, false, false, false}; + bool flagS3pi[4] = {false, false, false, false}; // bool flagVcalPV[4]={false,false,false,false}; // float deltaphi=0; for (int i = 0; i < 4; i++) { - if (pi3invMass[i] < 1.8) { - flagIM[i] = true; + if (pi3invMass[i] < invMass3piMaxcut) { // default should be 1.8 + if (invMass3piSignalRegion) { + flagIM[i] = true; + } else { + flagIM[i] = false; + } } else { registry.get(HIST("pidTPC/hpvsdedxElHipCut2"))->Fill(tmpMomentum[i], tmpDedx[i]); } - if (pi3deltaPhi[i] > 1.6) { + if (pi3deltaPhi[i] > deltaPhiMincut) { // default should be 1.6 flagDP[i] = true; } else { registry.get(HIST("pidTPC/hpvsdedxElHipCut3"))->Fill(tmpMomentum[i], tmpDedx[i]); @@ -594,7 +2535,7 @@ struct TauTau13topo { registry.get(HIST("pidTPC/hpvsdedxElHipCut4"))->Fill(tmpMomentum[i], tmpDedx[i]); } - if (TMath::Abs(nSigmaPi[i]) > maxNsigmaPiVetocut) { // default is 4 + if (std::abs(nSigmaPi[i]) > maxNsigmaPiVetocut) { // default is 4 flagPi[i] = true; } else { registry.get(HIST("pidTPC/hpvsdedxElHipCut5"))->Fill(tmpMomentum[i], tmpDedx[i]); @@ -614,20 +2555,36 @@ struct TauTau13topo { registry.get(HIST("pidTPC/hpvsdedxElHipCut8"))->Fill(tmpMomentum[i], tmpDedx[i]); } - if (TMath::Abs(nSigmaPr[i]) > maxNsigmaPrVetocut) { // default is 3 + if (std::abs(nSigmaPr[i]) > maxNsigmaPrVetocut) { // default is 3 flagPr[i] = true; } else { registry.get(HIST("pidTPC/hpvsdedxElHipCut9"))->Fill(tmpMomentum[i], tmpDedx[i]); } - if (TMath::Abs(nSigmaKa[i]) > maxNsigmaKaVetocut) { // default is 3 + if (std::abs(nSigmaKa[i]) > maxNsigmaKaVetocut) { // default is 3 flagKa[i] = true; } else { registry.get(HIST("pidTPC/hpvsdedxElHipCut10"))->Fill(tmpMomentum[i], tmpDedx[i]); } - flagTotal[i] = flagEl[i] && flagPi[i] && flagPt[i] && !flagVcalPV[i] && flagPr[i] && flagKa[i]; - } + if (nclTPCcrossedRows[i] > nTPCcrossedRowsMinCut) { // default is 50 + flagCR[i] = true; + } else { + registry.get(HIST("pidTPC/hpvsdedxElHipCut11"))->Fill(tmpMomentum[i], tmpDedx[i]); + } + + if (nSigma3Pi[i] < nSigma3piMaxCut) { // default is 5 + flagS3pi[i] = true; + } else { + registry.get(HIST("pidTPC/hpvsdedxElHipCut12"))->Fill(tmpMomentum[i], tmpDedx[i]); + } + + if (flagIMGam2ePV[i]) { + registry.get(HIST("pidTPC/hpvsdedxElHipCut13"))->Fill(tmpMomentum[i], tmpDedx[i]); + } + + flagTotal[i] = flagEl[i] && flagPi[i] && flagPt[i] && !flagVcalPV[i] && flagPr[i] && flagKa[i] && flagIM[i] && flagDP[i] && flagCR[i] && flagS3pi[i]; + } // end of loop over 4 tracks int counterM3pi = flagIM[0] + flagIM[1] + flagIM[2] + flagIM[3]; int counterDphi = flagDP[0] + flagDP[1] + flagDP[2] + flagDP[3]; @@ -636,7 +2593,9 @@ struct TauTau13topo { int counterPr = flagPr[0] + flagPr[1] + flagPr[2] + flagPr[3]; int counterKa = flagKa[0] + flagKa[1] + flagKa[2] + flagKa[3]; int counterPt = flagPt[0] + flagPt[1] + flagPt[2] + flagPt[3]; + int counterCR = flagCR[0] + flagCR[1] + flagCR[2] + flagCR[3]; int counterVcal = !flagVcalPV[0] + !flagVcalPV[1] + !flagVcalPV[2] + !flagVcalPV[3]; + int counterS3pi = flagS3pi[0] + flagS3pi[1] + flagS3pi[2] + flagS3pi[3]; int counterTotal = flagTotal[0] + flagTotal[1] + flagTotal[2] + flagTotal[3]; registry.get(HIST("global/hNCombAfterCut"))->Fill(5. + counterM3pi, 1.); @@ -647,191 +2606,2395 @@ struct TauTau13topo { registry.get(HIST("global/hNCombAfterCut"))->Fill(30. + counterVcal, 1.); registry.get(HIST("global/hNCombAfterCut"))->Fill(35. + counterPr, 1.); registry.get(HIST("global/hNCombAfterCut"))->Fill(40. + counterKa, 1.); - registry.get(HIST("global/hNCombAfterCut"))->Fill(45. + counterTotal, 1.); + registry.get(HIST("global/hNCombAfterCut"))->Fill(45. + counterCR, 1.); + registry.get(HIST("global/hNCombAfterCut"))->Fill(50. + counterS3pi, 1.); + registry.get(HIST("global/hNCombAfterCut"))->Fill(55. + counterTotal, 1.); // draw PID histograms + // + // electron + // if (counterEl > 0) { // Nelectrons>0, cut20 - registry.get(HIST("global/hEventEff"))->Fill(6., 1.); + registry.get(HIST("global/hEventEff"))->Fill(10., 1.); registry.get(HIST("control/cut20/h4trkPtTot"))->Fill(pttot); registry.get(HIST("control/cut20/h4piMass"))->Fill(mass4pi); registry.get(HIST("control/cut20/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registry.get(HIST("control/cut20/hNtofTrk"))->Fill(nTofTrk); + registry.get(HIST("control/cut20/hZNACenergy"))->Fill(energyZNA, energyZNC); for (int i = 0; i < 4; i++) { if (flagEl[i]) { registry.get(HIST("pidTPC/hpvsdedxElHipCut20"))->Fill(tmpMomentum[i], tmpDedx[i]); - FillControlHistos<20>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], pi3etasum[i]); + registry.get(HIST("pidTOF/hpvsNsigmaElHipCut20"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + // for (int j = 0; j < 4; j++) { + // if (i == j) continue; + // registry.get(HIST("pidTPC3pi/hpvsdedxElHipCut20"))->Fill(tmpMomentum[j], tmpDedx[j]); + // } + fillControlHistos<20>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); registry.get(HIST("control/cut20/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registry.get(HIST("control/cut20/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry.get(HIST("control/cut20/h3pi1eMass"))->Fill(mass3pi1e[i]); } } + } else { + // no electron + if (verbose) { + LOGF(debug, " Candidate rejected: no electron PID among 4 tracks"); + } + return; + } // end of Nelectrons check - if (flagEl[0] * flagPi[0] + flagEl[1] * flagPi[1] + flagEl[2] * flagPi[2] + flagEl[3] * flagPi[3] > 0) { // pi veto, cut21 - registry.get(HIST("global/hEventEff"))->Fill(7., 1.); - registry.get(HIST("control/cut21/h4trkPtTot"))->Fill(pttot); - registry.get(HIST("control/cut21/h4piMass"))->Fill(mass4pi); - registry.get(HIST("control/cut21/h4trkMassVsPt"))->Fill(mass4pi, pttot); - for (int i = 0; i < 4; i++) { - if (flagEl[i] && flagPi[i]) { - registry.get(HIST("pidTPC/hpvsdedxElHipCut21"))->Fill(tmpMomentum[i], tmpDedx[i]); - FillControlHistos<21>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], pi3etasum[i]); - registry.get(HIST("control/cut21/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); - } - } - - if (flagEl[0] * flagPi[0] * !flagVcalPV[0] + - flagEl[1] * flagPi[1] * !flagVcalPV[1] + - flagEl[2] * flagPi[2] * !flagVcalPV[2] + - flagEl[3] * flagPi[3] * !flagVcalPV[3] > - 0) { // vcal veto, cut22 - registry.get(HIST("global/hEventEff"))->Fill(8., 1.); - registry.get(HIST("control/cut22/h4trkPtTot"))->Fill(pttot); - registry.get(HIST("control/cut22/h4piMass"))->Fill(mass4pi); - registry.get(HIST("control/cut22/h4trkMassVsPt"))->Fill(mass4pi, pttot); - for (int i = 0; i < 4; i++) { - if (flagEl[i] && flagPi[i] && !flagVcalPV[i]) { - registry.get(HIST("pidTPC/hpvsdedxElHipCut22"))->Fill(tmpMomentum[i], tmpDedx[i]); - FillControlHistos<22>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], pi3etasum[i]); - registry.get(HIST("control/cut22/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); - } - } + // + // electron with tof hit (cut33) + // + if (flagEl[0] * trkHasTof[0] + + flagEl[1] * trkHasTof[1] + + flagEl[2] * trkHasTof[2] + + flagEl[3] * trkHasTof[3] > + 0) { // electron has tof hit cut 33 + registry.get(HIST("global/hEventEff"))->Fill(11., 1.); + // registry.get(HIST("control/cut33/hDcaZ"))->Fill(dcaZ[i]); + // registry.get(HIST("control/cut33/hDcaXY"))->Fill(dcaXY[i]); + // registry.get(HIST("control/cut33/hChi2TPC"))->Fill(chi2TPC[i]); + // registry.get(HIST("control/cut33/hChi2ITS"))->Fill(chi2ITS[i]); + registry.get(HIST("control/cut33/h4trkPtTot"))->Fill(pttot); + registry.get(HIST("control/cut33/h4piMass"))->Fill(mass4pi); + registry.get(HIST("control/cut33/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registry.get(HIST("control/cut33/hNtofTrk"))->Fill(nTofTrk); + registry.get(HIST("control/cut33/hZNACenergy"))->Fill(energyZNA, energyZNC); + for (int i = 0; i < 4; i++) { + if (flagEl[i] && trkHasTof[i]) { + fillControlHistos<33>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registry.get(HIST("control/cut33/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registry.get(HIST("pidTPC/hpvsdedxElHipCut33"))->Fill(tmpMomentum[i], tmpDedx[i]); + registry.get(HIST("pidTOF/hpvsNsigmaElHipCut33"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + registry.get(HIST("control/cut33/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry.get(HIST("control/cut33/h3pi1eMass"))->Fill(mass3pi1e[i]); + // registry.get(HIST("control/cut33/hPtSpectrumEl"))->Fill(tmpPt[i]); + } // only for electron + } + } else { + if (verbose) { + LOGF(info, "cut33 trackTime %f, %f, %f, %f Res %f, %f, %f, %f", trkTime[0], trkTime[1], trkTime[2], trkTime[3], trkTimeRes[0], trkTimeRes[1], trkTimeRes[2], trkTimeRes[3]); + LOGF(debug, " Candidate rejected: no TOF hit for electron"); + } + return; + } // end of tof hit for electron - if (flagEl[0] * flagPi[0] * !flagVcalPV[0] * flagPt[0] + - flagEl[1] * flagPi[1] * !flagVcalPV[1] * flagPt[1] + - flagEl[2] * flagPi[2] * !flagVcalPV[2] * flagPt[2] + - flagEl[3] * flagPi[3] * !flagVcalPV[3] * flagPt[3] > - 0) { // pT veto, cut23 - registry.get(HIST("global/hEventEff"))->Fill(9., 1.); - registry.get(HIST("control/cut23/h4trkPtTot"))->Fill(pttot); - registry.get(HIST("control/cut23/h4piMass"))->Fill(mass4pi); - registry.get(HIST("control/cut23/h4trkMassVsPt"))->Fill(mass4pi, pttot); - for (int i = 0; i < 4; i++) { - if (flagEl[i] && flagPi[i] && !flagVcalPV[i] && flagPt[i]) { - registry.get(HIST("pidTPC/hpvsdedxElHipCut23"))->Fill(tmpMomentum[i], tmpDedx[i]); - FillControlHistos<23>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], pi3etasum[i]); - registry.get(HIST("control/cut23/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); - } - } + // + // pi veto cut21 + // + if (flagEl[0] * trkHasTof[0] * flagPi[0] + + flagEl[1] * trkHasTof[1] * flagPi[1] + + flagEl[2] * trkHasTof[2] * flagPi[2] + + flagEl[3] * trkHasTof[3] * flagPi[3] > + 0) { // pi veto, cut21 + registry.get(HIST("global/hEventEff"))->Fill(12., 1.); + registry.get(HIST("control/cut21/h4trkPtTot"))->Fill(pttot); + registry.get(HIST("control/cut21/h4piMass"))->Fill(mass4pi); + registry.get(HIST("control/cut21/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registry.get(HIST("control/cut21/hNtofTrk"))->Fill(nTofTrk); + registry.get(HIST("control/cut21/hZNACenergy"))->Fill(energyZNA, energyZNC); + for (int i = 0; i < 4; i++) { + if (flagEl[i] && trkHasTof[i] && flagPi[i]) { + registry.get(HIST("pidTPC/hpvsdedxElHipCut21"))->Fill(tmpMomentum[i], tmpDedx[i]); + registry.get(HIST("pidTOF/hpvsNsigmaElHipCut21"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + fillControlHistos<21>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registry.get(HIST("control/cut21/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registry.get(HIST("control/cut21/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry.get(HIST("control/cut21/h3pi1eMass"))->Fill(mass3pi1e[i]); + } + } + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: all electrons vetoed by pi PID"); + } + return; + } // end of pi veto - if (flagEl[0] * flagPi[0] * !flagVcalPV[0] * flagPt[0] * flagPr[0] + - flagEl[1] * flagPi[1] * !flagVcalPV[1] * flagPt[1] * flagPr[1] + - flagEl[2] * flagPi[2] * !flagVcalPV[2] * flagPt[2] * flagPr[2] + - flagEl[3] * flagPi[3] * !flagVcalPV[3] * flagPt[3] * flagPr[3] > - 0) { // proton veto, cut24 - registry.get(HIST("global/hEventEff"))->Fill(10., 1.); - registry.get(HIST("control/cut24/h4trkPtTot"))->Fill(pttot); - registry.get(HIST("control/cut24/h4piMass"))->Fill(mass4pi); - registry.get(HIST("control/cut24/h4trkMassVsPt"))->Fill(mass4pi, pttot); - for (int i = 0; i < 4; i++) { - if (flagEl[i] && flagPi[i] && !flagVcalPV[i] && flagPt[i] && flagPr[i]) { - registry.get(HIST("pidTPC/hpvsdedxElHipCut24"))->Fill(tmpMomentum[i], tmpDedx[i]); - FillControlHistos<24>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], pi3etasum[i]); - registry.get(HIST("control/cut24/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); - } - } + // + // proton veto + // + if (flagEl[0] * trkHasTof[0] * flagPi[0] * flagPr[0] + + flagEl[1] * trkHasTof[1] * flagPi[1] * flagPr[1] + + flagEl[2] * trkHasTof[2] * flagPi[2] * flagPr[2] + + flagEl[3] * trkHasTof[3] * flagPi[3] * flagPr[3] > + 0) { // proton veto, cut24 + registry.get(HIST("global/hEventEff"))->Fill(13., 1.); + registry.get(HIST("control/cut24/h4trkPtTot"))->Fill(pttot); + registry.get(HIST("control/cut24/h4piMass"))->Fill(mass4pi); + registry.get(HIST("control/cut24/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registry.get(HIST("control/cut24/hNtofTrk"))->Fill(nTofTrk); + registry.get(HIST("control/cut24/hZNACenergy"))->Fill(energyZNA, energyZNC); + for (int i = 0; i < 4; i++) { + if (flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i]) { + registry.get(HIST("pidTPC/hpvsdedxElHipCut24"))->Fill(tmpMomentum[i], tmpDedx[i]); + registry.get(HIST("pidTOF/hpvsNsigmaElHipCut24"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + // for (int j = 0; j < 4; j++) { + // if (i == j) continue; + // registry.get(HIST("pidTPC3pi/hpvsdedxElHipCut24"))->Fill(tmpMomentum[j], tmpDedx[j]); + // } + fillControlHistos<24>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registry.get(HIST("control/cut24/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registry.get(HIST("control/cut24/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry.get(HIST("control/cut24/h3pi1eMass"))->Fill(mass3pi1e[i]); + } + } + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: all electrons vetoed by piPID+Vcal+pT+prPID"); + } + return; + } // end of proton veto - if (flagEl[0] * flagPi[0] * !flagVcalPV[0] * flagPt[0] * flagPr[0] * flagKa[0] + - flagEl[1] * flagPi[1] * !flagVcalPV[1] * flagPt[1] * flagPr[1] * flagKa[1] + - flagEl[2] * flagPi[2] * !flagVcalPV[2] * flagPt[2] * flagPr[2] * flagKa[2] + - flagEl[3] * flagPi[3] * !flagVcalPV[3] * flagPt[3] * flagPr[3] * flagKa[3] > - 0) { // kaon veto, cut25 - registry.get(HIST("global/hEventEff"))->Fill(11., 1.); - registry.get(HIST("control/cut25/h4trkPtTot"))->Fill(pttot); - registry.get(HIST("control/cut25/h4piMass"))->Fill(mass4pi); - registry.get(HIST("control/cut25/h4trkMassVsPt"))->Fill(mass4pi, pttot); - for (int i = 0; i < 4; i++) { - if (flagEl[i] && flagPi[i] && !flagVcalPV[i] && flagPt[i] && flagPr[i] && flagKa[i]) { - registry.get(HIST("pidTPC/hpvsdedxElHipCut25"))->Fill(tmpMomentum[i], tmpDedx[i]); - FillControlHistos<25>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], pi3etasum[i]); - registry.get(HIST("control/cut25/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); - } - } + // + // kaon veto + // + if (flagEl[0] * trkHasTof[0] * flagPi[0] * flagPr[0] * flagKa[0] + + flagEl[1] * trkHasTof[1] * flagPi[1] * flagPr[1] * flagKa[1] + + flagEl[2] * trkHasTof[2] * flagPi[2] * flagPr[2] * flagKa[2] + + flagEl[3] * trkHasTof[3] * flagPi[3] * flagPr[3] * flagKa[3] > + 0) { // kaon veto, cut25 + registry.get(HIST("global/hEventEff"))->Fill(14., 1.); + registry.get(HIST("control/cut25/h4trkPtTot"))->Fill(pttot); + registry.get(HIST("control/cut25/h4piMass"))->Fill(mass4pi); + registry.get(HIST("control/cut25/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registry.get(HIST("control/cut25/hNtofTrk"))->Fill(nTofTrk); + registry.get(HIST("control/cut25/hZNACenergy"))->Fill(energyZNA, energyZNC); + for (int i = 0; i < 4; i++) { + if (flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i]) { + registry.get(HIST("pidTPC/hpvsdedxElHipCut25"))->Fill(tmpMomentum[i], tmpDedx[i]); + registry.get(HIST("pidTOF/hpvsNsigmaElHipCut25"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + // for (int j = 0; j < 4; j++) { + // if (i == j) continue; + // registry.get(HIST("pidTPC3pi/hpvsdedxElHipCut25"))->Fill(tmpMomentum[j], tmpDedx[j]); + // } + fillControlHistos<25>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registry.get(HIST("control/cut25/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registry.get(HIST("control/cut25/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry.get(HIST("control/cut25/h3pi1eMass"))->Fill(mass3pi1e[i]); + } + } + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: all electrons vetoed by KaPID"); + } + return; + } // end of kaon veto - } else { - if (verbose) { - LOGF(debug, " Candidate rejected: all electrons vetoed by piPID+Vcal+pT+prPID+KaPID"); - } - } // end of kaon veto - } else { - if (verbose) { - LOGF(debug, " Candidate rejected: all electrons vetoed by piPID+Vcal+pT+prPID"); - } - } // end of proton veto - } else { - if (verbose) { - LOGF(debug, " Candidate rejected: all electrons vetoed by piPID+Vcal+pT"); - } - } // end of pT veto - } else { + // + // number of crossed rows in TPC for electron + // + if (flagEl[0] * trkHasTof[0] * flagPi[0] * flagPr[0] * flagKa[0] * flagCR[0] + + flagEl[1] * trkHasTof[1] * flagPi[1] * flagPr[1] * flagKa[1] * flagCR[1] + + flagEl[2] * trkHasTof[2] * flagPi[2] * flagPr[2] * flagKa[2] * flagCR[2] + + flagEl[3] * trkHasTof[3] * flagPi[3] * flagPr[3] * flagKa[3] * flagCR[3] > + 0) { // Nc-rTPC cut, cut28 + registry.get(HIST("global/hEventEff"))->Fill(15., 1.); + registry.get(HIST("control/cut28/h4trkPtTot"))->Fill(pttot); + registry.get(HIST("control/cut28/h4piMass"))->Fill(mass4pi); + registry.get(HIST("control/cut28/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registry.get(HIST("control/cut28/hNtofTrk"))->Fill(nTofTrk); + registry.get(HIST("control/cut28/hZNACenergy"))->Fill(energyZNA, energyZNC); + for (int i = 0; i < 4; i++) { + if (flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i]) { + registry.get(HIST("pidTPC/hpvsdedxElHipCut28"))->Fill(tmpMomentum[i], tmpDedx[i]); + registry.get(HIST("pidTOF/hpvsNsigmaElHipCut28"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + fillControlHistos<28>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registry.get(HIST("control/cut28/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registry.get(HIST("control/cut28/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry.get(HIST("control/cut28/h3pi1eMass"))->Fill(mass3pi1e[i]); + } + } + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: all electrons vetoed by CR"); + } + return; + } // end of TPC crossed rows for electron cut + + // + // virtal calorimeter + // + if (flagEl[0] * trkHasTof[0] * flagPi[0] * flagPr[0] * flagKa[0] * flagCR[0] * !flagVcalPV[0] + + flagEl[1] * trkHasTof[1] * flagPi[1] * flagPr[1] * flagKa[1] * flagCR[1] * !flagVcalPV[1] + + flagEl[2] * trkHasTof[2] * flagPi[2] * flagPr[2] * flagKa[2] * flagCR[2] * !flagVcalPV[2] + + flagEl[3] * trkHasTof[3] * flagPi[3] * flagPr[3] * flagKa[3] * flagCR[3] * !flagVcalPV[3] > + 0) { // vcal veto, cut22 + registry.get(HIST("global/hEventEff"))->Fill(16., 1.); + registry.get(HIST("control/cut22/h4trkPtTot"))->Fill(pttot); + registry.get(HIST("control/cut22/h4piMass"))->Fill(mass4pi); + registry.get(HIST("control/cut22/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registry.get(HIST("control/cut22/hNtofTrk"))->Fill(nTofTrk); + registry.get(HIST("control/cut22/hZNACenergy"))->Fill(energyZNA, energyZNC); + for (int i = 0; i < 4; i++) { + if (flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i] && !flagVcalPV[i]) { + registry.get(HIST("pidTPC/hpvsdedxElHipCut22"))->Fill(tmpMomentum[i], tmpDedx[i]); + registry.get(HIST("pidTOF/hpvsNsigmaElHipCut22"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + // for (int j = 0; j < 4; j++) { + // if (i == j) continue; + // registry.get(HIST("pidTPC3pi/hpvsdedxElHipCut22"))->Fill(tmpMomentum[j], tmpDedx[j]); + // } + fillControlHistos<22>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registry.get(HIST("control/cut22/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registry.get(HIST("control/cut22/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry.get(HIST("control/cut22/h3pi1eMass"))->Fill(mass3pi1e[i]); + } + } + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: all electrons vetoed by Vcal"); + } + return; + } // end of vcal veto + + // + // 3pi nsigma cut29 + // + if (flagEl[0] * trkHasTof[0] * flagPi[0] * flagPr[0] * flagKa[0] * flagCR[0] * !flagVcalPV[0] * flagS3pi[0] + + flagEl[1] * trkHasTof[1] * flagPi[1] * flagPr[1] * flagKa[1] * flagCR[1] * !flagVcalPV[1] * flagS3pi[1] + + flagEl[2] * trkHasTof[2] * flagPi[2] * flagPr[2] * flagKa[2] * flagCR[2] * !flagVcalPV[2] * flagS3pi[2] + + flagEl[3] * trkHasTof[3] * flagPi[3] * flagPr[3] * flagKa[3] * flagCR[3] * !flagVcalPV[3] * flagS3pi[3] > + 0) { // nsigma 3pi cut, cut29 + registry.get(HIST("global/hEventEff"))->Fill(17., 1.); + registry.get(HIST("control/cut29/h4trkPtTot"))->Fill(pttot); + registry.get(HIST("control/cut29/h4piMass"))->Fill(mass4pi); + registry.get(HIST("control/cut29/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registry.get(HIST("control/cut29/hNtofTrk"))->Fill(nTofTrk); + registry.get(HIST("control/cut29/hZNACenergy"))->Fill(energyZNA, energyZNC); + for (int i = 0; i < 4; i++) { + if (flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i] && !flagVcalPV[i] && flagS3pi[i]) { + registry.get(HIST("pidTPC/hpvsdedxElHipCut29"))->Fill(tmpMomentum[i], tmpDedx[i]); + registry.get(HIST("pidTOF/hpvsNsigmaElHipCut29"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + fillControlHistos<29>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registry.get(HIST("control/cut29/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registry.get(HIST("control/cut29/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry.get(HIST("control/cut29/h3pi1eMass"))->Fill(mass3pi1e[i]); if (verbose) { - LOGF(debug, " Candidate rejected: all electrons vetoed by piPID+Vcal"); + LOGF(info, "cut29 timeTot %f, resTot %f, trackTime %f, %f, %f, %f Res %f, %f, %f, %f", trkTimeTot, trkTimeResTot, trkTime[0], trkTime[1], trkTime[2], trkTime[3], trkTimeRes[0], trkTimeRes[1], trkTimeRes[2], trkTimeRes[3]); } - } // end of vcal veto - } else { - if (verbose) { - LOGF(debug, " Candidate rejected: all electrons vetoed by pi PID"); } - } // end of pi veto - } else { // no electron + } + } else { if (verbose) { - LOGF(debug, " Candidate rejected: no electron PID among 4 tracks"); + LOGF(debug, " Candidate rejected: all electrons vetoed by 3piPID"); } - } // end of Nelectrons check + return; + } // end of nsigma 3pi cut + + // + // IM cut + // + if (flagEl[0] * trkHasTof[0] * flagPi[0] * flagPr[0] * flagKa[0] * flagCR[0] * !flagVcalPV[0] * flagS3pi[0] * flagIM[0] + + flagEl[1] * trkHasTof[1] * flagPi[1] * flagPr[1] * flagKa[1] * flagCR[1] * !flagVcalPV[1] * flagS3pi[1] * flagIM[1] + + flagEl[2] * trkHasTof[2] * flagPi[2] * flagPr[2] * flagKa[2] * flagCR[2] * !flagVcalPV[2] * flagS3pi[2] * flagIM[2] + + flagEl[3] * trkHasTof[3] * flagPi[3] * flagPr[3] * flagKa[3] * flagCR[3] * !flagVcalPV[3] * flagS3pi[3] * flagIM[3] > + 0) { // 3pi cut, cut26 + registry.get(HIST("global/hEventEff"))->Fill(18., 1.); + registry.get(HIST("control/cut26/h4trkPtTot"))->Fill(pttot); + registry.get(HIST("control/cut26/h4piMass"))->Fill(mass4pi); + registry.get(HIST("control/cut26/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registry.get(HIST("control/cut26/hNtofTrk"))->Fill(nTofTrk); + registry.get(HIST("control/cut26/hZNACenergy"))->Fill(energyZNA, energyZNC); + for (int i = 0; i < 4; i++) { + if (flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i] && !flagVcalPV[i] && flagS3pi[i] && flagIM[i]) { + registry.get(HIST("pidTPC/hpvsdedxElHipCut26"))->Fill(tmpMomentum[i], tmpDedx[i]); + registry.get(HIST("pidTOF/hpvsNsigmaElHipCut26"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + // for (int j = 0; j < 4; j++) { + // if (i == j) continue; + // registry.get(HIST("pidTPC3pi/hpvsdedxElHipCut26"))->Fill(tmpMomentum[j], tmpDedx[j]); + // } + fillControlHistos<26>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registry.get(HIST("control/cut26/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registry.get(HIST("control/cut26/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry.get(HIST("control/cut26/h3pi1eMass"))->Fill(mass3pi1e[i]); + } + } + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: all electrons vetoed by IM"); + } + return; + } // end of inv mass 3 pi cut + + // + // at least one pion with tof hit (cut34) + // + int otherTOFtracks[4]; + for (int i = 0; i < 4; i++) { + otherTOFtracks[i] = 0; + if (flagEl[i] && trkHasTof[i]) { + for (int j = 0; j < 4; j++) { + if (i == j) + continue; + // if (trkHasTof[j]) { + if (trkIsTOFGood[j]) { + otherTOFtracks[i]++; + registry.get(HIST("pidTOF/h3piTOFchi2"))->Fill(chi2TOF[j]); + } + } // second loop over tracks + } + } // first loop over tracks + // + if (flagEl[0] * trkHasTof[0] * flagPi[0] * flagPr[0] * flagKa[0] * flagCR[0] * !flagVcalPV[0] * flagS3pi[0] * flagIM[0] * (otherTOFtracks[0] >= 1) + + flagEl[1] * trkHasTof[1] * flagPi[1] * flagPr[1] * flagKa[1] * flagCR[1] * !flagVcalPV[1] * flagS3pi[1] * flagIM[1] * (otherTOFtracks[1] >= 1) + + flagEl[2] * trkHasTof[2] * flagPi[2] * flagPr[2] * flagKa[2] * flagCR[2] * !flagVcalPV[2] * flagS3pi[2] * flagIM[2] * (otherTOFtracks[2] >= 1) + + flagEl[3] * trkHasTof[3] * flagPi[3] * flagPr[3] * flagKa[3] * flagCR[3] * !flagVcalPV[3] * flagS3pi[3] * flagIM[3] * (otherTOFtracks[3] >= 1) > + 0) { // at lest 1 pi with tof hit, cut34 + registry.get(HIST("global/hRecFlag"))->Fill(5 + dgcand.flags()); // reconstruction with upc settings flag + registry.get(HIST("global/hEventEff"))->Fill(19., 1.); + // registry.get(HIST("control/cut34/hDcaZ"))->Fill(dcaZ[i]); + // registry.get(HIST("control/cut34/hDcaXY"))->Fill(dcaXY[i]); + // registry.get(HIST("control/cut34/hChi2TPC"))->Fill(chi2TPC[i]); + // registry.get(HIST("control/cut34/hChi2ITS"))->Fill(chi2ITS[i]); + registry.get(HIST("control/cut34/h4trkPtTot"))->Fill(pttot); + registry.get(HIST("control/cut34/h4piMass"))->Fill(mass4pi); + registry.get(HIST("control/cut34/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registry.get(HIST("control/cut34/hNtofTrk"))->Fill(nTofTrk); + registry.get(HIST("control/cut34/hZNACenergy"))->Fill(energyZNA, energyZNC); + for (int i = 0; i < 4; i++) { + if (flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i] && !flagVcalPV[i] && flagS3pi[i] && flagIM[i] && (otherTOFtracks[i] >= 1)) { + fillControlHistos<34>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registry.get(HIST("control/cut34/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registry.get(HIST("pidTPC/hpvsdedxElHipCut34"))->Fill(tmpMomentum[i], tmpDedx[i]); + registry.get(HIST("pidTOF/hpvsNsigmaElHipCut34"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + registry.get(HIST("control/cut34/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry.get(HIST("control/cut34/h3pi1eMass"))->Fill(mass3pi1e[i]); + // registry.get(HIST("control/cut34/hPtSpectrumEl"))->Fill(tmpPt[i]); + } else if (!flagEl[i] && trkHasTof[i]) { + registry.get(HIST("pidTOF/h3piTOFchi2Cut34"))->Fill(chi2TOF[i]); + } + } + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: all electrons vetoed by lack of TOF hit in 3pi"); + } + return; + } // end of at least one pion with tof hit (cut34) + // // skip events with pttot<0.15 + // if (pttot < ptTotcut) { if (verbose) { LOGF(info, " Candidate rejected: pt tot is %f", pttot); } return; - } - if (counterTotal > 0) - registry.get(HIST("global/hEventEff"))->Fill(12., 1.); - - // check FIT information - if (FITvetoFlag) { - auto bitMin = 16 - FITvetoWindow; // default is +- 1 bc (1 bit) - auto bitMax = 16 + FITvetoWindow; - for (auto bit = bitMin; bit <= bitMax; bit++) { - if (TESTBIT(dgcand.bbFT0Apf(), bit) || - TESTBIT(dgcand.bbFT0Cpf(), bit) || - TESTBIT(dgcand.bbFV0Apf(), bit) || - TESTBIT(dgcand.bbFDDApf(), bit) || - TESTBIT(dgcand.bbFDDCpf(), bit)) { - return; + } else { + registry.get(HIST("global/hEventEff"))->Fill(20., 1.); + registry.get(HIST("control/cut30/h4trkPtTot"))->Fill(pttot); + registry.get(HIST("control/cut30/h4piMass"))->Fill(mass4pi); + registry.get(HIST("control/cut30/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registry.get(HIST("control/cut30/hNtofTrk"))->Fill(nTofTrk); + registry.get(HIST("control/cut30/hZNACenergy"))->Fill(energyZNA, energyZNC); + registry.get(HIST("global/hRecFlag"))->Fill(5 + 2 + dgcand.flags()); // reconstruction with upc settings flag + for (int i = 0; i < 4; i++) { + if (flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i] && !flagVcalPV[i] && flagS3pi[i] && flagIM[i] && (otherTOFtracks[i] >= 1)) { + registry.get(HIST("pidTPC/hpvsdedxElHipCut30"))->Fill(tmpMomentum[i], tmpDedx[i]); + registry.get(HIST("pidTOF/hpvsNsigmaElHipCut30"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + fillControlHistos<30>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registry.get(HIST("control/cut30/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registry.get(HIST("control/cut30/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry.get(HIST("control/cut30/h3pi1eMass"))->Fill(mass3pi1e[i]); + } else if (!flagEl[i] && trkHasTof[i]) { + registry.get(HIST("pidTOF/h3piTOFchi2Cut30"))->Fill(chi2TOF[i]); } } - } - if (counterTotal > 0) - registry.get(HIST("global/hEventEff"))->Fill(13., 1.); + } // end of pttot<0.15 cut30 - if (counterTotal == 1) { + // + // delta phi + // + if (flagEl[0] * trkHasTof[0] * flagPi[0] * flagPr[0] * flagKa[0] * flagCR[0] * !flagVcalPV[0] * flagS3pi[0] * flagIM[0] * (otherTOFtracks[0] >= 1) * flagDP[0] + + flagEl[1] * trkHasTof[1] * flagPi[1] * flagPr[1] * flagKa[1] * flagCR[1] * !flagVcalPV[1] * flagS3pi[1] * flagIM[1] * (otherTOFtracks[1] >= 1) * flagDP[1] + + flagEl[2] * trkHasTof[2] * flagPi[2] * flagPr[2] * flagKa[2] * flagCR[2] * !flagVcalPV[2] * flagS3pi[2] * flagIM[2] * (otherTOFtracks[2] >= 1) * flagDP[2] + + flagEl[3] * trkHasTof[3] * flagPi[3] * flagPr[3] * flagKa[3] * flagCR[3] * !flagVcalPV[3] * flagS3pi[3] * flagIM[3] * (otherTOFtracks[3] >= 1) * flagDP[3] > + 0) { // delta phi cut, cut27 + registry.get(HIST("global/hEventEff"))->Fill(21., 1.); + registry.get(HIST("control/cut27/h4trkPtTot"))->Fill(pttot); + registry.get(HIST("control/cut27/h4piMass"))->Fill(mass4pi); + registry.get(HIST("control/cut27/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registry.get(HIST("control/cut27/hNtofTrk"))->Fill(nTofTrk); + registry.get(HIST("control/cut27/hZNACenergy"))->Fill(energyZNA, energyZNC); + registry.get(HIST("global/hRecFlag"))->Fill(5 + 2 + 2 + dgcand.flags()); // reconstruction with upc settings flag for (int i = 0; i < 4; i++) { - registry.get(HIST("control/cut1/hDcaZ"))->Fill(dcaZ[i]); - registry.get(HIST("control/cut1/hDcaXY"))->Fill(dcaXY[i]); - registry.get(HIST("control/cut1/hChi2TPC"))->Fill(chi2TPC[i]); - registry.get(HIST("control/cut1/hChi2ITS"))->Fill(chi2ITS[i]); + if (flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i] && !flagVcalPV[i] && flagS3pi[i] && flagIM[i] && (otherTOFtracks[i] >= 1) && flagDP[i]) { + registry.get(HIST("pidTPC/hpvsdedxElHipCut27"))->Fill(tmpMomentum[i], tmpDedx[i]); + registry.get(HIST("pidTOF/hpvsNsigmaElHipCut27"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + // for (int j = 0; j < 4; j++) { + // if (i == j) continue; + // registry.get(HIST("pidTPC3pi/hpvsdedxElHipCut27"))->Fill(tmpMomentum[j], tmpDedx[j]); + // } + fillControlHistos<27>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registry.get(HIST("control/cut27/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registry.get(HIST("control/cut27/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry.get(HIST("control/cut27/h3pi1eMass"))->Fill(mass3pi1e[i]); + } else if (!flagEl[i] && trkHasTof[i]) { + registry.get(HIST("pidTOF/h3piTOFchi2Cut27"))->Fill(chi2TOF[i]); + // LOGF(info, " chi2TOF %f", chi2TOF[i]); + } + } + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: all electrons vetoed by Dphi"); + } + return; + } // end of Dphi - if (flagTotal[i]) { - FillControlHistos<1>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], pi3etasum[i]); - registry.get(HIST("control/cut1/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); - registry.get(HIST("pidTPC/hpvsdedxElHipCut1"))->Fill(tmpMomentum[i], tmpDedx[i]); - registry.get(HIST("global/hFinalPtSpectrumEl"))->Fill(tmpPt[i]); - registry.get(HIST("control/cut1/hTPCnclsFindable"))->Fill(nclTPCfind[i]); + // + // skip events with znac energy cut 35 + // + if (energyZNA >= 1. || energyZNC >= 1.) { + if (verbose) { + LOGF(info, " Candidate rejected: ZNA, ZNC are %f, %f", energyZNA, energyZNC); + } + return; + } else { + registry.get(HIST("global/hEventEff"))->Fill(22., 1.); + registry.get(HIST("control/cut35/h4trkPtTot"))->Fill(pttot); + registry.get(HIST("control/cut35/h4piMass"))->Fill(mass4pi); + registry.get(HIST("control/cut35/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registry.get(HIST("control/cut35/hNtofTrk"))->Fill(nTofTrk); + registry.get(HIST("control/cut35/hZNACenergy"))->Fill(energyZNA, energyZNC); + for (int i = 0; i < 4; i++) { + if (flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i] && !flagVcalPV[i] && flagS3pi[i] && flagIM[i] && (otherTOFtracks[i] >= 1) && flagDP[i]) { + registry.get(HIST("pidTPC/hpvsdedxElHipCut35"))->Fill(tmpMomentum[i], tmpDedx[i]); + registry.get(HIST("pidTOF/hpvsNsigmaElHipCut35"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + fillControlHistos<35>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registry.get(HIST("control/cut35/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registry.get(HIST("control/cut35/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry.get(HIST("control/cut35/h3pi1eMass"))->Fill(mass3pi1e[i]); + } else if (!flagEl[i] && trkHasTof[i]) { + registry.get(HIST("pidTOF/h3piTOFchi2Cut35"))->Fill(chi2TOF[i]); } } - registry.get(HIST("control/cut1/h4trkPtTot"))->Fill(pttot); - registry.get(HIST("control/cut1/h4piMass"))->Fill(mass4pi); - registry.get(HIST("control/cut1/h4trkMassVsPt"))->Fill(mass4pi, pttot); + } // end of ZNAC energy cut35 - registry.get(HIST("global/hEventEff"))->Fill(14., 1.); - } else { // more than 1 electron candidate + // + // skip events with occupancy >=1000 + // + if (dgcand.occupancyInTime() >= 1000) { if (verbose) { - LOGF(debug, " Candidate rejected: more than one electron candidate"); + LOGF(info, " Candidate rejected: occupancy is %f", dgcand.occupancyInTime()); } - } // end of Nelectrons check - } + return; + } else { + registry.get(HIST("global/hEventEff"))->Fill(23., 1.); + registry.get(HIST("control/cut23/h4trkPtTot"))->Fill(pttot); + registry.get(HIST("control/cut23/h4piMass"))->Fill(mass4pi); + registry.get(HIST("control/cut23/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registry.get(HIST("control/cut23/hNtofTrk"))->Fill(nTofTrk); + registry.get(HIST("control/cut23/hZNACenergy"))->Fill(energyZNA, energyZNC); + for (int i = 0; i < 4; i++) { + if (flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i] && !flagVcalPV[i] && flagS3pi[i] && flagIM[i] && (otherTOFtracks[i] >= 1) && flagDP[i]) { + registry.get(HIST("pidTPC/hpvsdedxElHipCut23"))->Fill(tmpMomentum[i], tmpDedx[i]); + registry.get(HIST("pidTOF/hpvsNsigmaElHipCut23"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + fillControlHistos<23>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registry.get(HIST("control/cut23/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registry.get(HIST("control/cut23/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry.get(HIST("control/cut23/h3pi1eMass"))->Fill(mass3pi1e[i]); + } else if (!flagEl[i] && trkHasTof[i]) { + registry.get(HIST("pidTOF/h3piTOFchi2Cut23"))->Fill(chi2TOF[i]); + } + } + } // end of occupancy < 1000 cut23 + + // // only 1 electron + // if (counterTotal == 1) { + // registry.get(HIST("global/hEventEff"))->Fill(19., 1.); + // for (int i = 0; i < 4; i++) { + // registry.get(HIST("control/cut1/hDcaZ"))->Fill(dcaZ[i]); + // registry.get(HIST("control/cut1/hDcaXY"))->Fill(dcaXY[i]); + // registry.get(HIST("control/cut1/hChi2TPC"))->Fill(chi2TPC[i]); + // registry.get(HIST("control/cut1/hChi2ITS"))->Fill(chi2ITS[i]); + // registry.get(HIST("control/cut1/hChi2TOF"))->Fill(chi2TOF[i]); + // if (flagTotal[i]) { + // fillControlHistos<1>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + // registry.get(HIST("control/cut1/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + // registry.get(HIST("pidTPC/hpvsdedxElHipCut1"))->Fill(tmpMomentum[i], tmpDedx[i]); + // for (int j = 0; j < 4; j++) { + // if (i == j) + // continue; + // registry.get(HIST("pidTPC3pi/hpvsdedxElHipCut1"))->Fill(tmpMomentum[j], tmpDedx[j]); + // } + // registry.get(HIST("global/hFinalPtSpectrumEl"))->Fill(tmpPt[i]); + // registry.get(HIST("control/cut1/hTPCnclsFindable"))->Fill(nclTPCfind[i]); + // registry.get(HIST("control/cut1/hsigma3Pi"))->Fill(nSigma3Pi[i]); + // registry.get(HIST("control/cut1/h3pi1eMass"))->Fill(mass3pi1e[i]); + // if (verbose) { + // LOGF(info, "cut1 trackTime %f, %f, %f, %f Res %f, %f, %f, %f", trkTime[0], trkTime[1], trkTime[2], trkTime[3], trkTimeRes[0], trkTimeRes[1], trkTimeRes[2], trkTimeRes[3]); + // } + // } + // } // end of loop over 4 tracks + // registry.get(HIST("control/cut1/h4trkPtTot"))->Fill(pttot); + // registry.get(HIST("control/cut1/h4piMass"))->Fill(mass4pi); + // registry.get(HIST("control/cut1/h4trkMassVsPt"))->Fill(mass4pi, pttot); + // registry.get(HIST("control/cut1/hNtofTrk"))->Fill(nTofTrk); + // registry.get(HIST("control/cut1/hZNACenergy"))->Fill(energyZNA, energyZNC); + // // special case invmass 4pi (2,2.3) + // // if (mass4pi<2.3 && mass4pi>2) { + // // for (int i = 0; i < 4; i++) { + // // registry.get(HIST("control/cut1/cut1a/hDcaZ"))->Fill(dcaZ[i]); + // // registry.get(HIST("control/cut1/cut1a/hDcaXY"))->Fill(dcaXY[i]); + // // registry.get(HIST("control/cut1/cut1a/hChi2TPC"))->Fill(chi2TPC[i]); + // // registry.get(HIST("control/cut1/cut1a/hChi2ITS"))->Fill(chi2ITS[i]); + // // + // // if (flagTotal[i]) { + // // registry.get(HIST("control/cut1/cut1a/h3piMassComb"))->Fill(pi3invMass[i]); + // // registry.get(HIST("control/cut1/cut1a/h3trkPtTot"))->Fill(pi3pt[i]); + // // registry.get(HIST("control/cut1/cut1a/hDeltaPhi13topo"))->Fill(pi3deltaPhi[i]); + // // registry.get(HIST("control/cut1/cut1a/h13AssymPt1ProngAver"))->Fill(pi3assymav[i]); + // // registry.get(HIST("control/cut1/cut1a/h13Vector"))->Fill(pi3vector[i]); + // // registry.get(HIST("control/cut1/cut1a/h13Scalar"))->Fill(pi3scalar[i]); + // // registry.get(HIST("control/cut1/cut1a/h13EtaSum"))->Fill(pi3etasum[i]); + // // registry.get(HIST("control/cut1/cut1a/hTPCnCrossedRows"))->Fill(nclTPCcrossedRows[i]); + // // + // // registry.get(HIST("control/cut1/cut1a/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + // // registry.get(HIST("control/cut1/cut1a/hTPCnclsFindable"))->Fill(nclTPCfind[i]); + // // registry.get(HIST("control/cut1/cut1a/hsigma3Pi"))->Fill(nSigma3Pi[i]); + // // } + // // } + // // registry.get(HIST("control/cut1/cut1a/h4trkPtTot"))->Fill(pttot); + // // registry.get(HIST("control/cut1/cut1a/h4piMass"))->Fill(mass4pi); + // // registry.get(HIST("control/cut1/cut1a/h4trkMassVsPt"))->Fill(mass4pi, pttot); + // // registry.get(HIST("control/cut1/cut1a/hNtofTrk"))->Fill(nTofTrk); + // // } // end of mass window for 4pi case + // + // } else { // more than 1 electron candidate + // if (verbose) { + // LOGF(debug, " Candidate rejected: more than one electron candidate"); + // } + // } // end of 1electrons check + } // end of processDataSG + // check ntracks-4PVtracks + // check pt of remaining (ntracks-4PVtracks) tracks + + // + // basic distributions from MC related to tau, electron and MC particles + // + void processSimpleMCSG(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) + { + registryMC.get(HIST("globalMC/hMCZvertex"))->Fill(mcCollision.posZ()); + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(0., 1.); + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(0., 1.); + registryMC.get(HIST("efficiencyMCMu/effiMu"))->Fill(0., 1.); + registryMC.get(HIST("efficiencyMCPi/effiPi"))->Fill(0., 1.); + + // check how many physical primaries + // int countPrim = 0; + int countGen = 0; + int countBoth = 0; + int countCharged = 0; + int countChargedFromTau = 0; + int countTau = 0; + + float etaTau[2]; + float phiTau[2]; + + int pionCounter = 0; + int singlePionIndex = -1; + int tmpPionIndex = -1; + // int tmpPionGlobalIndex=-1; + // int singlePionGlobalIndex=-1; + // int singleElectronGlobalIndex=-1; + // int threePionGlobalIndex[3]={-1,-1,-1}; + // int threePionIndex[3]={-1,-1,-1}; + // int motherOfSinglePionIndex=-1; + // int motherOfThreePionIndex=-1; + bool electronFound = false; + bool muonFound = false; + bool threePionsFound = false; + bool singlePionFound = false; + bool tauInRapidity = true; + bool partFromTauInEta = true; + float partPt = 0.; + // bool flagE3pi = false; + // bool flagMu3pi = false; + // bool flagPi3pi = false; + bool flagElPlusElMinus = false; // e+ = 0, e- =1 + bool flagMuPlusMuMinus = false; // mu+ = 0, mu- =1 + bool flagPiPlusPiMinus = false; // pi+ = 0, pi- =1 + + // loop over MC particles + for (const auto& mcParticle : mcParticles) { + // primaries + // if (mcParticle.isPhysicalPrimary()) { + // countPrim++; + // } + // + // MC particles produced by generator only + // + if (mcParticle.producedByGenerator()) { + countGen++; + if (mcParticle.isPhysicalPrimary()) { + countBoth++; + if (mcParticle.pdgCode() != 22 && std::abs(mcParticle.pdgCode()) != 12 && std::abs(mcParticle.pdgCode()) != 14 && std::abs(mcParticle.pdgCode()) != 16 && mcParticle.pdgCode() != 130 && mcParticle.pdgCode() != 111) { + countCharged++; + + registryMC.get(HIST("globalMC/hMCetaGen"))->Fill(mcParticle.eta()); + registryMC.get(HIST("globalMC/hMCphiGen"))->Fill(mcParticle.phi()); + registryMC.get(HIST("globalMC/hMCyGen"))->Fill(mcParticle.y()); + registryMC.get(HIST("globalMC/hMCptGen"))->Fill(mcParticle.pt()); + + if (mcParticle.has_mothers()) { + auto const& mother = mcParticle.mothers_first_as(); + if (std::abs(mother.pdgCode()) == 15) { + countChargedFromTau++; + } // mother is tau + } // mc particle has mother + } // veto neutral particles + } // physicsl primary + } // generator produced by + + // + // tau+/- + // + if (std::abs(mcParticle.pdgCode()) == 15) { // tau+/- + countTau++; + if (countTau <= 2) { + etaTau[countTau - 1] = mcParticle.eta(); + phiTau[countTau - 1] = mcParticle.phi(); + } + + registryMC.get(HIST("tauMC/hMCeta"))->Fill(mcParticle.eta()); + registryMC.get(HIST("tauMC/hMCphi"))->Fill(mcParticle.phi()); + registryMC.get(HIST("tauMC/hMCy"))->Fill(mcParticle.y()); + registryMC.get(HIST("tauMC/hMCpt"))->Fill(mcParticle.pt()); + if (std::abs(mcParticle.y()) > 0.9) + tauInRapidity = false; + pionCounter = 0; + if (mcParticle.has_daughters()) { + for (const auto& daughter : mcParticle.daughters_as()) { + // pions from tau + if (std::abs(daughter.pdgCode()) == 211) { // 211 = pi+ + pionCounter++; + tmpPionIndex = daughter.index(); // returns index of daughter of tau, not in the event, not in the MC particles + if (std::abs(daughter.eta()) > 0.9) + partFromTauInEta = false; + } // end of pion check + // electron from tau + if (std::abs(daughter.pdgCode()) == 11) { // 11 = electron + if (daughter.pdgCode() == 11) + flagElPlusElMinus = true; + registryMC.get(HIST("electronMC/hMCeta"))->Fill(daughter.eta()); + registryMC.get(HIST("electronMC/hMCphi"))->Fill(daughter.phi()); + registryMC.get(HIST("electronMC/hMCy"))->Fill(daughter.y()); + registryMC.get(HIST("electronMC/hMCpt"))->Fill(daughter.pt()); + + electronFound = !electronFound; + partPt = static_cast(daughter.pt()); + // singleElectronGlobalIndex = daughter.globalIndex(); + // LOGF(info,"e pt %f",daughter.pt()); + if (std::abs(daughter.eta()) > 0.9) + partFromTauInEta = false; + } // end of electron check + // muon from tau + if (std::abs(daughter.pdgCode()) == 13) { + if (daughter.pdgCode() == 13) + flagMuPlusMuMinus = true; + muonFound = !muonFound; + partPt = static_cast(daughter.pt()); + // LOGF(info,"mu pt %f",daughter.pt()); + if (std::abs(daughter.eta()) > 0.9) + partFromTauInEta = false; + } // end of muon check + } // end of loop over daughters + if (pionCounter == 3) { + threePionsFound = true; + } // end of 3pi check + if (pionCounter == 1) { + singlePionFound = true; + singlePionIndex = tmpPionIndex; + auto mcPartTmp = mcParticle.daughters_as().begin() + singlePionIndex; + if (mcPartTmp.pdgCode() == -211) + flagPiPlusPiMinus = true; + partPt = static_cast(mcPartTmp.pt()); + // motherOfSinglePionIndex = mcParticle.index(); + if (std::abs(mcPartTmp.eta()) > 0.9) + partFromTauInEta = false; + // LOGF(info,"size %d; tau ID %d GID %d (pdg %d); pi ID %d LID %d GID %d, pt %f", mcParticle.size(), motherOfSinglePionIndex, mcParticle.globalIndex(), mcParticle.pdgCode(),singlePionIndex, mcPartTmp.index(), mcPartTmp.globalIndex(), mcPartTmp.pt()); + } // end of 1 pi check + } // end check tau has daughter + } // end of tau + } // end of loop over MC particles + // LOGF(info,"pt after %f",partPt); + + // tau related things + if (countTau == 2) { + registryMC.get(HIST("tauMC/hMCdeltaeta"))->Fill(etaTau[0] - etaTau[1]); + registryMC.get(HIST("tauMC/hMCdeltaphi"))->Fill(calculateDeltaPhi(phiTau[0], phiTau[1]) * 180. / o2::constants::math::PI); + } + + if (threePionsFound && electronFound) { + // LOGF(info,"3pi + e found"); + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(1., 1.); + if (tauInRapidity) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(2., 1.); + if (partFromTauInEta) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(3., 1.); + registryMC.get(HIST("efficiencyMCEl/hpTelec"))->Fill(partPt, 1.); + // flagE3pi = true; + } // particles from tau in eta + } // tau in y + } // el + 3pi + + if (threePionsFound && muonFound) { + // LOGF(info,"3pi + mu found"); + registryMC.get(HIST("efficiencyMCMu/effiMu"))->Fill(1., 1.); + if (tauInRapidity) { + registryMC.get(HIST("efficiencyMCMu/effiMu"))->Fill(2., 1.); + if (partFromTauInEta) { + registryMC.get(HIST("efficiencyMCMu/effiMu"))->Fill(3., 1.); + registryMC.get(HIST("efficiencyMCMu/hpTmuon"))->Fill(partPt, 1.); + // flagMu3pi = true; + } // particles from tau in eta + } // tau in y + } // el + 3pi + + if (singlePionFound && threePionsFound) { + // LOGF(info,"3pi + pi found in MC"); + // flagPi3pi = true; + registryMC.get(HIST("efficiencyMCPi/effiPi"))->Fill(1., 1.); + if (tauInRapidity) { + registryMC.get(HIST("efficiencyMCPi/effiPi"))->Fill(2., 1.); + if (partFromTauInEta) { + registryMC.get(HIST("efficiencyMCPi/effiPi"))->Fill(3., 1.); + registryMC.get(HIST("efficiencyMCPi/hpTpi"))->Fill(partPt, 1.); + } // particles from tau in eta + } // tau in y + } // el + 3pi + + registryMC.get(HIST("globalMC/hMCnPart"))->Fill(mcParticles.size(), 0); + registryMC.get(HIST("globalMC/hMCnPart"))->Fill(countGen, 1); + registryMC.get(HIST("globalMC/hMCnPart"))->Fill(countBoth, 2); + registryMC.get(HIST("globalMC/hMCnPart"))->Fill(countCharged, 3); + registryMC.get(HIST("globalMC/hMCnPart"))->Fill(countChargedFromTau, 4); + if (countChargedFromTau != 4) + return; + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(1., 1.); + if (electronFound && flagElPlusElMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(2., 1.); // e- + else if (electronFound && !flagElPlusElMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(3., 1.); // e+ + if (muonFound && flagMuPlusMuMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(4., 1.); // mu- + else if (muonFound && !flagMuPlusMuMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(5., 1.); // mu+ + if (singlePionFound && flagPiPlusPiMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(6., 1.); // pi- + else if (singlePionFound && !flagPiPlusPiMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(7., 1.); // pi+ + + if (!tauInRapidity) + return; + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(8., 1.); + if (!partFromTauInEta) + return; + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(9., 1.); + + } // end of processSimpleMCSG + + void processEfficiencyMCSG(aod::UDMcCollision const& mcCollision, + // soa::SmallGroups> const& collisions, + soa::SmallGroups> const& collisions, + LabeledTracks const& tracks, + aod::UDMcParticles const& mcParticles) + { + if (verbose) { + LOGF(info, " GeneratorIDtot %d", mcCollision.generatorsID()); + // below is not implemented in UDMcCollisions + // LOGF(info," GeneratorIDtot %d, GenID %d, subGenID %d, source %d", mcCollision.generatorsID(), mcCollision.getGeneratorId(), mcCollision.getSubGeneratorId(), mcCollision.getSourceId()); + } + registry1MC.get(HIST("globalMC/hGeneratorID"))->Fill(mcCollision.generatorsID()); + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(10., 1.); + if (!(generatorIDMC < 0)) { // do not check generatorsID process if generatorIDMC < 0 + if (mcCollision.generatorsID() != generatorIDMC) + return; + } + + int indexProngMC[4]; + int index1ProngMC = -1; + bool is1ProngElectronMC = false; + // bool is1ProngMuonMC = false; + // bool is1ProngPionMC = false; + bool is3prong3PiMC = false; + int motherIndex[4]; + + int count = 0; + + bool tauInRapidity = true; + bool partFromTauInEta = true; + + TLorentzVector tmp(0., 0., 0., 0.); + + for (const auto& mcParticle : mcParticles) { + if (mcParticle.isPhysicalPrimary()) { + if (mcParticle.pdgCode() != 22 && std::abs(mcParticle.pdgCode()) != 12 && std::abs(mcParticle.pdgCode()) != 14 && std::abs(mcParticle.pdgCode()) != 16 && mcParticle.pdgCode() != 130 && mcParticle.pdgCode() != 111) { + if (mcParticle.has_mothers()) { + auto const& mother = mcParticle.mothers_first_as(); + tmp.SetPxPyPzE(mother.px(), mother.py(), mother.pz(), mother.e()); + if (std::abs(mother.pdgCode()) == 15) { + if (std::abs(rapidity(mother.e(), mother.pz())) > 0.9) + // if (std::abs(tmp.Rapidity()) > 0.9) + tauInRapidity = false; + if (std::abs(eta(mcParticle.px(), mcParticle.py(), mcParticle.pz())) > 0.9) + // if (std::abs(tmp.Eta()) > 0.9) + partFromTauInEta = false; + + if (std::abs(mcParticle.pdgCode()) == 11) { + index1ProngMC = mcParticle.index(); + is1ProngElectronMC = true; + } else if (std::abs(mcParticle.pdgCode()) == 13) { + index1ProngMC = mcParticle.index(); + // is1ProngMuonMC = true; + } + + if (count < 4) { + indexProngMC[count] = mcParticle.index(); + motherIndex[count] = mother.globalIndex(); + } else { + indexProngMC[3] = mcParticle.index(); + motherIndex[3] = mother.globalIndex(); + } + count++; + if (collisions.size() > 0) { + registryMC.get(HIST("globalMCrec/hMCetaGenCol"))->Fill(eta(mcParticle.px(), mcParticle.py(), mcParticle.pz())); + registryMC.get(HIST("globalMCrec/hMCphiGenCol"))->Fill(phi(mcParticle.px(), mcParticle.py())); + registryMC.get(HIST("globalMCrec/hMCyGenCol"))->Fill(rapidity(mcParticle.e(), mcParticle.pz())); + registryMC.get(HIST("globalMCrec/hMCptGenCol"))->Fill(pt(mcParticle.px(), mcParticle.py())); + } + } // mother is tau + } // has mothers + } // charged particles + } // end if isPhysicalPrimary + + } // end loop over mcParticle + + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(11., 1.); + if (count != 4) + return; + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(12., 1.); + if (!tauInRapidity) + return; + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(13., 1.); + if (!partFromTauInEta) + return; + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(14., 1.); // just to confirm there is exactly the same selection + + if (index1ProngMC < 0) { // pion case + 3pi + // bool onlyPi = true; + // // int motherIndex[4]; + // for (int i = 0; i < 4; i++) { + // auto const& tmpMC = mcParticles.begin() + indexProngMC[i]; + // if (std::abs(tmpMC.pdgCode()) != 211) onlyPi = false; + // // // mother's check already done in a loop before + // // // auto const& mother = tmpMC.mothers_first_as(); + // // // motherIndex[i] = mother.globalIndex(); + // // motherIndex[i] = (tmpMC.mothers_first_as()).globalIndex(); + // } + int motherIndex1Pi = motherIndex[0]; + int motherIndexNew = -1; + int nDifferences = 0; + for (int i = 1; i < 4; i++) { + if (motherIndex1Pi != motherIndex[i]) { // the same mother index + nDifferences++; + motherIndexNew = i; + } + } + if (nDifferences == 3) + index1ProngMC = indexProngMC[0]; + else + index1ProngMC = indexProngMC[motherIndexNew]; + // is1ProngPionMC = true; + // if (!onlyPi) LOGF(info, "ERROR: should be 4 pions, but they are not!"); + } // end of special check for pi + 3pi + + int index3ProngMC[3]; + if (index1ProngMC > 0) { // electron or muon case + 3pi + int index3pi = 0; + for (int i = 0; i < 4; i++) { + if (index1ProngMC == indexProngMC[i]) + continue; + index3ProngMC[index3pi] = indexProngMC[i]; + index3pi++; + } + } + + // create 1 prong and 3 prong MC references + auto const& tmp1ProngMC = mcParticles.begin() + index1ProngMC; + // LOGF(info,"tmp1ProngMC ID %d, GID %d", tmp1ProngMC.index(), tmp1ProngMC.globalIndex()); + + auto const& tmpPion1MC = mcParticles.begin() + index3ProngMC[0]; + auto const& tmpPion2MC = mcParticles.begin() + index3ProngMC[1]; + auto const& tmpPion3MC = mcParticles.begin() + index3ProngMC[2]; + + if (std::abs(tmpPion1MC.pdgCode()) == 211 && std::abs(tmpPion2MC.pdgCode()) == 211 && std::abs(tmpPion3MC.pdgCode()) == 211) + is3prong3PiMC = true; + + // + // here it comes e+3pi topology in MC + // + if (!(is1ProngElectronMC && is3prong3PiMC)) + return; + + // LOGF(info,"ID3pi1 %d, GID3pi1 %d",tmpPion1MC.index(),tmpPion1MC.globalIndex()); + // LOGF(info,"ID3pi2 %d, GID3pi2 %d",tmpPion2MC.index(),tmpPion2MC.globalIndex()); + // LOGF(info,"ID3pi3 %d, GID3pi3 %d",tmpPion3MC.index(),tmpPion3MC.globalIndex()); + + auto deltaAlpha1 = deltaAlpha(tmp1ProngMC, tmpPion1MC); + auto deltaAlpha2 = deltaAlpha(tmp1ProngMC, tmpPion2MC); + auto deltaAlpha3 = deltaAlpha(tmp1ProngMC, tmpPion3MC); + registryMC.get(HIST("efficiencyMCEl/hMCdeltaAlphaEpi"))->Fill(deltaAlpha1); + registryMC.get(HIST("efficiencyMCEl/hMCdeltaAlphaEpi"))->Fill(deltaAlpha2); + registryMC.get(HIST("efficiencyMCEl/hMCdeltaAlphaEpi"))->Fill(deltaAlpha3); + // + registryMC.get(HIST("efficiencyMCEl/hMCdeltaPhiEpi"))->Fill(calculateDeltaPhi(phi(tmp1ProngMC.px(), tmp1ProngMC.py()), phi(tmpPion1MC.px(), tmpPion1MC.py()))); + registryMC.get(HIST("efficiencyMCEl/hMCdeltaPhiEpi"))->Fill(calculateDeltaPhi(phi(tmp1ProngMC.px(), tmp1ProngMC.py()), phi(tmpPion2MC.px(), tmpPion2MC.py()))); + registryMC.get(HIST("efficiencyMCEl/hMCdeltaPhiEpi"))->Fill(calculateDeltaPhi(phi(tmp1ProngMC.px(), tmp1ProngMC.py()), phi(tmpPion3MC.px(), tmpPion3MC.py()))); + // + registryMC.get(HIST("efficiencyMCEl/hMCdeltaPhiPipi"))->Fill(calculateDeltaPhi(phi(tmpPion1MC.px(), tmpPion1MC.py()), phi(tmpPion2MC.px(), tmpPion2MC.py()))); + registryMC.get(HIST("efficiencyMCEl/hMCdeltaPhiPipi"))->Fill(calculateDeltaPhi(phi(tmpPion1MC.px(), tmpPion1MC.py()), phi(tmpPion3MC.px(), tmpPion3MC.py()))); + registryMC.get(HIST("efficiencyMCEl/hMCdeltaPhiPipi"))->Fill(calculateDeltaPhi(phi(tmpPion2MC.px(), tmpPion2MC.py()), phi(tmpPion3MC.px(), tmpPion3MC.py()))); + + // + auto deltaAlphaPi1 = deltaAlpha(tmpPion1MC, tmpPion2MC); + auto deltaAlphaPi2 = deltaAlpha(tmpPion1MC, tmpPion3MC); + auto deltaAlphaPi3 = deltaAlpha(tmpPion2MC, tmpPion3MC); + registryMC.get(HIST("efficiencyMCEl/hMCdeltaAlphaPiPi"))->Fill(deltaAlphaPi1); + registryMC.get(HIST("efficiencyMCEl/hMCdeltaAlphaPiPi"))->Fill(deltaAlphaPi2); + registryMC.get(HIST("efficiencyMCEl/hMCdeltaAlphaPiPi"))->Fill(deltaAlphaPi3); + // + float energyInCone = 0; + float angleLimit = 0.5; + if (deltaAlpha1 < angleLimit) { + energyInCone += pt(tmpPion1MC.px(), tmpPion1MC.py()); + } + if (deltaAlpha2 < angleLimit) { + energyInCone += pt(tmpPion2MC.px(), tmpPion2MC.py()); + } + if (deltaAlpha3 < angleLimit) { + energyInCone += pt(tmpPion3MC.px(), tmpPion3MC.py()); + } + registryMC.get(HIST("efficiencyMCEl/hMCvirtCal"))->Fill(energyInCone); + // + registryMC.get(HIST("efficiencyMCEl/hMCScalar"))->Fill(scalarAsymMC(tmp1ProngMC, tmpPion1MC)); + registryMC.get(HIST("efficiencyMCEl/hMCScalar"))->Fill(scalarAsymMC(tmp1ProngMC, tmpPion2MC)); + registryMC.get(HIST("efficiencyMCEl/hMCScalar"))->Fill(scalarAsymMC(tmp1ProngMC, tmpPion3MC)); + // + registryMC.get(HIST("efficiencyMCEl/hMCVector"))->Fill(vectorAsym(tmp1ProngMC, tmpPion1MC)); + registryMC.get(HIST("efficiencyMCEl/hMCVector"))->Fill(vectorAsym(tmp1ProngMC, tmpPion2MC)); + registryMC.get(HIST("efficiencyMCEl/hMCVector"))->Fill(vectorAsym(tmp1ProngMC, tmpPion3MC)); + + // add eta phi + registryMC.get(HIST("efficiencyMCEl/hMCptEl"))->Fill(pt(tmp1ProngMC.px(), tmp1ProngMC.py())); + + float px3pi = tmpPion1MC.px() + tmpPion2MC.px() + tmpPion3MC.px(); + float py3pi = tmpPion1MC.py() + tmpPion2MC.py() + tmpPion3MC.py(); + float pz3pi = tmpPion1MC.pz() + tmpPion2MC.pz() + tmpPion3MC.pz(); + float en3pi = tmpPion1MC.e() + tmpPion2MC.e() + tmpPion3MC.e(); + + registryMC.get(HIST("efficiencyMCEl/hMCpt4trk"))->Fill(pt(tmp1ProngMC.px() + px3pi, tmp1ProngMC.py() + py3pi)); + registryMC.get(HIST("efficiencyMCEl/hMCinvmass4pi"))->Fill(invariantMass(tmp1ProngMC.e() + en3pi, tmp1ProngMC.px() + px3pi, tmp1ProngMC.py() + py3pi, tmp1ProngMC.pz() + pz3pi)); + registryMC.get(HIST("efficiencyMCEl/hMCinvmass3pi"))->Fill(invariantMass(en3pi, px3pi, py3pi, pz3pi)); + registryMC.get(HIST("efficiencyMCEl/hMCdeltaphi13"))->Fill(calculateDeltaPhi(phi(tmp1ProngMC.px(), tmp1ProngMC.py()), phi(px3pi, py3pi))); + + // reconstructed event + if (collisions.size() < 1) + return; + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(15., 1.); // there is at least 1 collision associated to MC collision + if (is1ProngElectronMC && is3prong3PiMC) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(4., 1.); + if (collisions.size() == 1) + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(5., 1.); + + // event selection flags + bool zVertexFlag = false; + bool allInEtaAcceptance = false; + int nTrkInEtaRange = 0; + // bool allAbovePtThreshold = false; + int nTrkAbovePtThreshold = 0; + + int nPVTracks = 0; + int nGhostTracks = 0; + int nGhostPVTracks = 0; + + // int nGenTracks=0; + // int nGenPrimTracks=0; + // int nGenPVTracks=0; + // int nGenPrimPVTracks=0; + + int trackId[4]; // local index in collision + int trackCharge = 0; + bool trackToMCmatch[4]; // match between data track and corresponding MC particle; true = match, false = track not found in this collision + int trackMCId[4]; // when MC found, the global index from MC Particle is stored here + + int matchedElIndexToData = -1; + int gapSide = -2; + int truegapSide = -2; + float reconstructedPtElMatchedToMC = -1; + + bool flagGapSideSGP = false; + bool flagDoubleGap = false; + bool tracksMatchedToMC = false; + + // FIT checks + auto bitMin = 16 - mFITvetoWindow; // default is +- 1 bc (1 bit) + auto bitMax = 16 + mFITvetoWindow; + bool flagFITveto = false; + + for (const auto& collision : collisions) { + // FIT flag set + flagFITveto = false; + for (auto bit = bitMin; bit <= bitMax; bit++) { + if (TESTBIT(collision.bbFT0Apf(), bit)) + flagFITveto = true; + if (TESTBIT(collision.bbFT0Cpf(), bit)) + flagFITveto = true; + if (useFV0ForVeto && TESTBIT(collision.bbFV0Apf(), bit)) + flagFITveto = true; + if (useFDDAForVeto && TESTBIT(collision.bbFDDApf(), bit)) + flagFITveto = true; + if (useFDDCForVeto && TESTBIT(collision.bbFDDCpf(), bit)) + flagFITveto = true; + } // end of loop over FIT bits + + registry1MC.get(HIST("globalMCrec/hRecFlag"))->Fill(collision.flags()); // reconstruction with upc settings flag + registry1MC.get(HIST("globalMCrec/hOccupancyInTime"))->Fill(collision.occupancyInTime()); + + matchedElIndexToData = -1; + reconstructedPtElMatchedToMC = -1; + gapSide = collision.gapSide(); + truegapSide = sgSelector.trueGap(collision, cutFV0, cutFT0A, cutFT0C, cutZDC); + registryMC.fill(HIST("globalMCrec/GapSide"), gapSide); + registryMC.fill(HIST("globalMCrec/GapSideTrue"), truegapSide); + // if (gapSide < 0 || gapSide > 2) continue; //old way + if (gapSide >= 0 && gapSide <= 2) + flagGapSideSGP = true; + + gapSide = truegapSide; + // if (flagGapSideSGP) registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(6., 1./collisions.size()); + // if (flagGapSideSGP && tracksMatchedToMC) registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(7., 1./collisions.size()); // with true information + + // if (gapSide != mGapSide) continue; //old way + if (gapSide == mGapSide) + flagDoubleGap = true; + // if (flagDoubleGap) registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(8., 1./collisions.size()); + // if (flagDoubleGap && tracksMatchedToMC) registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(9., 1./collisions.size()); // with true information + registryMC.get(HIST("globalMCrec/hVertexXY"))->Fill(collision.posX(), collision.posY()); + registryMC.get(HIST("globalMCrec/hVertexZ"))->Fill(collision.posZ()); + + zVertexFlag = true; + if (std::abs(collision.posZ()) >= zvertexcut) + zVertexFlag = false; + + auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex()); + registryMC.get(HIST("globalMCrec/hNTracks"))->Fill(groupedTracks.size()); + nPVTracks = 0; + nGhostTracks = 0; + nGhostPVTracks = 0; + + for (int i = 0; i < 4; i++) { + trackToMCmatch[i] = false; + trackMCId[i] = -1; + } + + // nGenTracks=0; + // nGenPrimTracks=0; + // nGenPVTracks=0; + // nGenPrimPVTracks=0; + + trackCharge = 0; + allInEtaAcceptance = false; + nTrkInEtaRange = 0; + // allAbovePtThreshold = false; + nTrkAbovePtThreshold = 0; + + // + // first loop over grouped Tracks + // + for (auto const& track : groupedTracks) { + // ghost track + if (!track.has_udMcParticle()) { + nGhostTracks++; + } + + if (track.isPVContributor()) { + if (nPVTracks < 4) { + trackId[nPVTracks] = track.index(); + } + nPVTracks++; + trackCharge += track.sign(); + // if (std::abs(eta(track.px(),track.py(),track.pz())) >= trkEtacut) allInEtaAcceptance = false; + if (std::abs(eta(track.px(), track.py(), track.pz())) < trkEtacut) + nTrkInEtaRange++; + if (track.pt() > 0.1) + nTrkAbovePtThreshold++; + // // if (track.tpcNSigmaEl() > -2 && track.tpcNSigmaEl() < 3) atLeast1ElectronPID = true; + // ptmp.SetXYZM(track.px(), track.py(), track.pz(), mpion); + // // hPt->Fill(p.Pt()); + // ptot += ptmp; + + if (track.has_udMcParticle()) { + // LOGF(info, "track ID %d match to MC (1p,3p0,3p1,3p2) (%d, %d, %d, %d)", track.udMcParticle().globalIndex(), tmp1ProngMC.globalIndex(), tmpPion1MC.globalIndex(), tmpPion2MC.globalIndex(), tmpPion3MC.globalIndex()); + if (nPVTracks < 5) { + trackMCId[nPVTracks - 1] = track.udMcParticle().globalIndex(); + if (trackMCId[nPVTracks - 1] == tmp1ProngMC.globalIndex()) { + matchedElIndexToData = nPVTracks - 1; + reconstructedPtElMatchedToMC = track.pt(); + } + + if (trackMCId[nPVTracks - 1] == tmp1ProngMC.globalIndex() || + trackMCId[nPVTracks - 1] == tmpPion1MC.globalIndex() || + trackMCId[nPVTracks - 1] == tmpPion2MC.globalIndex() || + trackMCId[nPVTracks - 1] == tmpPion3MC.globalIndex()) + trackToMCmatch[nPVTracks - 1] = true; // flag, we have a match data <=> MC + } + + } else { // end of case where track has MC Particle associated + // ghost PV track + nGhostPVTracks++; + } + } else { // PV contributor + if (track.has_udMcParticle()) { + // LOGF(info,"non-PV trk: pid %4.0d (%f, %f, %f) gid %d pt %f",track.udMcParticle().pdgCode(), track.udMcParticle().vx(),track.udMcParticle().vy(),track.udMcParticle().vz(),track.udMcParticle().globalIndex(),track.pt()); + if (verbose) { + LOGF(info, "non-PV trk: pid %4.0d gid %d", track.udMcParticle().pdgCode(), track.udMcParticle().globalIndex()); + } + } + } + // if (track.isGlobalTrack()) nGlobalTracks++; + } // end of loop over tracks + registryMC.get(HIST("globalMCrec/hNTracksPV"))->Fill(nPVTracks); + registryMC.get(HIST("globalMCrec/hNGhostTracks"))->Fill(nGhostTracks); + registryMC.get(HIST("globalMCrec/hNGhostTracksPV"))->Fill(nGhostPVTracks); + registryMC.get(HIST("globalMCrec/hQtot"))->Fill(trackCharge); + + // check whether tracks match to MC particles + if (trackToMCmatch[0] && trackToMCmatch[1] && trackToMCmatch[2] && trackToMCmatch[3]) + tracksMatchedToMC = true; + registryMC.get(HIST("globalMCrec/hTrackToMCMatch"))->Fill(tracksMatchedToMC); + + if (nTrkInEtaRange >= 4) + allInEtaAcceptance = true; + if (nTrkAbovePtThreshold >= 4) + nTrkAbovePtThreshold = true; + + // zdc information + float energyZNA = collision.energyCommonZNA(); + float energyZNC = collision.energyCommonZNC(); + // if (energyZNA < 0) registry.get(HIST("global/hZNACenergyTest"))->Fill(energyZNA); + // if (energyZNC < 0) registry.get(HIST("global/hZNACenergyTest"))->Fill(energyZNC); + if (energyZNA < 0) + energyZNA = -1.; + if (energyZNC < 0) + energyZNC = -1.; + registryMC.get(HIST("globalMCrec/hZNACenergy"))->Fill(energyZNA, energyZNC); + registryMC.get(HIST("globalMCrec/hZNACtime"))->Fill(collision.timeZNA(), collision.timeZNC()); + + // + // here analysis event selection comes and track eta phi, pt comparison after that + // + // SG producer: flagGapSideSGP ok + // Double gap: flagDoubleGap ok + // npvtracks: nPVTracks ok + // Zvertex: zVertexFlag + // tracks in eta: allInEtaAcceptance + // tracks charge : trackCharge + // MC to data matching: tracksMatchedToMC + + // it is after reconstruction + if (tracksMatchedToMC) { + registryMC.get(HIST("globalMCrec/hPtSpectrumElRec0"))->Fill(reconstructedPtElMatchedToMC); // pt El confirmed with true information + } + + // skip events wrongly reconstructed by SG producernot + if (!flagGapSideSGP) { + if (verbose) { + LOGF(info, " Candidate rejected: DGproducer flag is %d", gapSide); + } + return; + } + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(6., 1. / collisions.size()); + if (tracksMatchedToMC) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(7., 1. / collisions.size()); // with true information + registryMC.get(HIST("globalMCrec/hPtSpectrumElRec1"))->Fill(reconstructedPtElMatchedToMC); // pt El confirmed with true information + } + + // skip not Double Gap events + if (!flagDoubleGap) { + if (verbose) { + LOGF(info, " Candidate rejected: not double gapevent, gap value is %d", gapSide); + } + return; + } + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(8., 1. / collisions.size()); + if (tracksMatchedToMC) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(9., 1. / collisions.size()); // with true information + registryMC.get(HIST("globalMCrec/hPtSpectrumElRec2"))->Fill(reconstructedPtElMatchedToMC); // pt El confirmed with true information + } + + // // skip events with too few/many tracks + if (nPVTracks != 4) { + if (verbose) { + LOGF(info, " Candidate rejected: Number of PV contributors is %d", nPVTracks); + } + return; + } + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(10., 1.); + if (tracksMatchedToMC) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(11., 1.); // with true information + registryMC.get(HIST("globalMCrec/hPtSpectrumElRec3"))->Fill(reconstructedPtElMatchedToMC); // pt El confirmed with true information + } + + // //four reconstructed track with MC track link + // auto const track1 = groupedTracks.begin()+trackId[0]; + // auto const track2 = groupedTracks.begin()+trackId[1]; + // auto const track3 = groupedTracks.begin()+trackId[2]; + // auto const track4 = groupedTracks.begin()+trackId[3]; + + // here comes histos of global1 but in MC + registryMC.get(HIST("global1MCrec/hTrackPVTotCharge"))->Fill(trackCharge); + registryMC.get(HIST("global1MCrec/hVertexZ"))->Fill(collision.posZ()); + registryMC.get(HIST("global1MCrec/hNTracks"))->Fill(groupedTracks.size()); + registryMC.get(HIST("global1MCrec/hNTracksPV"))->Fill(nPVTracks); + + TLorentzVector p, p1; + p.SetXYZM(0., 0., 0., 0.); + TVector3 v1(0, 0, 0); + TVector3 v2(0, 0, 0); + float scalarPtsum = 0; + bool flagVcalPV[4] = {false, false, false, false}; + float deltaphi = 0; + bool trkHasTof[4] = {false, false, false, false}; + int nPiHasTPC[4] = {0, 0, 0, 0}; + // + // second loop, only over PV tracks + // + for (int i = 0; i < 4; i++) { + auto const tmptrack = groupedTracks.begin() + trackId[i]; + // if (tmptrack.hasTOF()) + // trkHasTof[i] = true; + trkHasTof[i] = isGoodTOFTrackCheck(tmptrack); + v1.SetXYZ(tmptrack.px(), tmptrack.py(), tmptrack.pz()); + // second loop to calculate virtual calorimeter + for (int j = 0; j < 4; j++) { + if (i == j) + continue; + auto const tmptrack2 = groupedTracks.begin() + trackId[j]; + if (tmptrack2.hasTPC()) + nPiHasTPC[i]++; + v2.SetXYZ(tmptrack2.px(), tmptrack2.py(), tmptrack2.pz()); + deltaphi = v1.Angle(v2); + if (deltaphi < minAnglecut) { // default 0.05 + flagVcalPV[i] = true; + } + } // end of second loop + float tmpEtaData = eta(tmptrack.px(), tmptrack.py(), tmptrack.pz()); + float tmpPhiData = phi(tmptrack.px(), tmptrack.py()); + registryMC.get(HIST("global1MCrec/hTrackEtaPhiPV"))->Fill(tmpEtaData, tmpPhiData); + registryMC.get(HIST("global1MCrec/hTrackPtPV"))->Fill(tmptrack.pt()); + p1.SetXYZM(v1.X(), v1.Y(), v1.Z(), MassPiPlus); // in case of ghost + + if (trackMCId[i] >= 0) { + p1.SetXYZM(v1.X(), v1.Y(), v1.Z(), (std::abs(tmptrack.udMcParticle().pdgCode()) == 211 ? MassPiPlus : MassElectron)); + float tmpPt = pt(tmptrack.udMcParticle().px(), tmptrack.udMcParticle().py()); + float tmpEta = eta(tmptrack.udMcParticle().px(), tmptrack.udMcParticle().py(), tmptrack.udMcParticle().pz()); + float tmpPhi = phi(tmptrack.udMcParticle().px(), tmptrack.udMcParticle().py()); + registryMC.get(HIST("global1MCrec/hpTGenRecTracksPV"))->Fill(tmptrack.pt(), tmpPt); + registryMC.get(HIST("global1MCrec/hDeltapTGenRecVsRecpTTracksPV"))->Fill(tmptrack.pt() - tmpPt, tmptrack.pt()); + registryMC.get(HIST("global1MCrec/hEtaGenRecTracksPV"))->Fill(tmpEtaData, tmpEta); + registryMC.get(HIST("global1MCrec/hDeltaEtaGenRecVsRecpTTracksPV"))->Fill(tmpEtaData - tmpEta, tmptrack.pt()); + registryMC.get(HIST("global1MCrec/hPhiGenRecTracksPV"))->Fill(tmpPhiData, tmpPhi); + registryMC.get(HIST("global1MCrec/hDeltaPhiGenRecVsRecpTTracksPV"))->Fill(calculateDeltaPhi(tmpPhiData, tmpPhi), tmptrack.pt()); + } // MC infor exists + p += p1; + scalarPtsum += p1.Pt(); + } // end of short loop over tracks + + int nTofTracks = trkHasTof[0] + trkHasTof[1] + trkHasTof[2] + trkHasTof[3]; + + // if vz < 10 + if (!zVertexFlag) { // default = 10 + if (verbose) { + LOGF(info, " Candidate rejected: VertexZ is %f", collision.posZ()); + } + return; + } + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(12., 1.); + if (tracksMatchedToMC) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(13., 1.); // with true information + registryMC.get(HIST("globalMCrec/hPtSpectrumElRec4"))->Fill(reconstructedPtElMatchedToMC); // pt El confirmed with true information + } + + // if eta tracks <0.9 default + if (!allInEtaAcceptance) { + if (verbose) { + LOGF(info, " Candidate rejected: Ntrk inside |eta|<0.9 is %d", nTrkInEtaRange); + } + return; + } + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(14., 1.); + if (tracksMatchedToMC) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(15., 1.); // with true information + registryMC.get(HIST("globalMCrec/hPtSpectrumElRec5"))->Fill(reconstructedPtElMatchedToMC); // pt El confirmed with true information + } + + // if pt of tracks >100 MeV/c + if (!nTrkAbovePtThreshold) { + if (verbose) { + LOGF(info, " Candidate rejected: Ntrk with pT >100 MeV/c is %d", nTrkAbovePtThreshold); + } + return; + } + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(16., 1.); + if (tracksMatchedToMC) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(17., 1.); // with true information + registryMC.get(HIST("globalMCrec/hPtSpectrumElRec6"))->Fill(reconstructedPtElMatchedToMC); // pt El confirmed with true information + } + + // skip events with net charge != 0 + if (!sameSign) { // opposite sign is signal + if (trackCharge != 0) { + if (verbose) { + LOGF(info, " Candidate rejected: Net charge is %d (dgcand %d), while should be 0", trackCharge, collision.netCharge()); + } + return; + } + } else { // same sign is background + if (trackCharge == 0) { + if (verbose) { + LOGF(info, " Candidate rejected: Net charge is %d (dgcand %d), while should be not 0", trackCharge, collision.netCharge()); + } + return; + } + } + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(18., 1.); + if (tracksMatchedToMC) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(19., 1.); // with true information + registryMC.get(HIST("globalMCrec/hPtSpectrumElRec7"))->Fill(reconstructedPtElMatchedToMC); // pt El confirmed with true information + } + + // + // n TOF tracks cut 32 + // + if (nTofTracks < nTofTrkMinCut) { + if (verbose) { + LOGF(info, " Candidate rejected: nTOFtracks is %d", nTofTracks); + } + return; + } + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(56., 1.); // TOF tracks > Ntoftracks + if (tracksMatchedToMC) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(57., 1.); // electron identified, tracks match to MC Particles + registryMC.get(HIST("globalMCrec/hPtSpectrumElRec8"))->Fill(reconstructedPtElMatchedToMC); // pt El confirmed with true information + } + + // + // check FIT information + // + if (mFITvetoFlag) { + if (flagFITveto) { + if (verbose) { + LOGF(info, " Candidate rejected: FIT not empty"); + } + return; + } + } // end of check emptiness around given BC in FIT detectors + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(53., 1.); // electron identified + if (tracksMatchedToMC) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(54., 1.); // electron identified, tracks match to MC Particles + registryMC.get(HIST("globalMCrec/hPtSpectrumElRec9"))->Fill(reconstructedPtElMatchedToMC); // pt El confirmed with true information + } + + // + // here PID from TPC starts to be + // + // temporary control variables per event with combinatorics + float pttot = p.Pt(); + float mass4pi = p.Mag(); + int counterTmp = 0; + + float nSigmaEl[4]; + float nSigmaPi[4]; + float nSigma3Pi[4] = {0., 0., 0., 0.}; + float nSigma3PiNew[4] = {0., 0., 0., 0.}; + float nSigmaPr[4]; + float nSigmaKa[4]; + // float dcaZ[4]; + // float dcaXY[4]; + // float chi2TPC[4]; + // float chi2ITS[4]; + float chi2TOF[4] = {-1., -1., -1., -1.}; + // float nclTPCfind[4]; + float nclTPCcrossedRows[4]; + // bool tmpHasTOF[4]; + // double trkTime[4]; + // float trkTimeRes[4]; + + float tmpMomentum[4]; + float tmpPt[4]; + float tmpDedx[4]; + float tmpTofNsigmaEl[4]; + + float deltaPhiTmp = 0; + float pi3invMass[4]; + float pi3pt[4]; + float pi3deltaPhi[4]; + float pi3assymav[4]; + float pi3vector[4]; + float pi3scalar[4]; + + // bool trkHasTof[4] = {false, false, false, false}; + bool trkHasTpc[4] = {false, false, false, false}; + + // float mass3pi1e[4]; + // double trkTimeTot = 0.; + // float trkTimeResTot = 10000.; + for (int i = 0; i < 4; i++) { + auto const tmptrack = groupedTracks.begin() + trackId[i]; + // if (tmptrack.hasTOF()) trkHasTof[i] = true; + v1.SetXYZ(tmptrack.px(), tmptrack.py(), tmptrack.pz()); + p1.SetXYZM(v1.X(), v1.Y(), v1.Z(), MassPiPlus); // in case of ghost + if (trackMCId[i] >= 0) { + p1.SetXYZM(v1.X(), v1.Y(), v1.Z(), (i == matchedElIndexToData ? MassElectron : MassPiPlus)); + } + + nSigmaEl[counterTmp] = tmptrack.tpcNSigmaEl(); + nSigmaPi[counterTmp] = tmptrack.tpcNSigmaPi(); + nSigma3Pi[3] += (nSigmaPi[counterTmp] * nSigmaPi[counterTmp]); + if (tmptrack.hasTPC()) + nSigma3PiNew[3] += (nSigmaPi[counterTmp] * nSigmaPi[counterTmp]); + if (whichPIDCut == 1) { // TPC only + nSigmaPr[counterTmp] = tmptrack.tpcNSigmaPr(); + nSigmaKa[counterTmp] = tmptrack.tpcNSigmaKa(); + } else if (whichPIDCut == 2) { // TPC + TOF sigma + nSigmaPr[counterTmp] = std::sqrt(tmptrack.tofNSigmaPr() * tmptrack.tofNSigmaPr() + tmptrack.tpcNSigmaPr() * tmptrack.tpcNSigmaPr()); + nSigmaKa[counterTmp] = std::sqrt(tmptrack.tofNSigmaKa() * tmptrack.tofNSigmaKa() + tmptrack.tpcNSigmaKa() * tmptrack.tpcNSigmaKa()); + } else if (whichPIDCut == 3) { // TPC + TOF hardcoded pt + nSigmaPr[counterTmp] = (tmptrack.pt() < 1.5 ? tmptrack.tofNSigmaPr() : tmptrack.tpcNSigmaPr()); + nSigmaKa[counterTmp] = (tmptrack.pt() < 1.3 ? tmptrack.tofNSigmaKa() : tmptrack.tpcNSigmaKa()); + } else { + nSigmaPr[counterTmp] = tmptrack.tpcNSigmaPr(); + nSigmaKa[counterTmp] = tmptrack.tpcNSigmaKa(); + } + + // dcaZ[counterTmp] = tmptrack.dcaZ(); + // dcaXY[counterTmp] = tmptrack.dcaXY(); + // chi2TPC[counterTmp] = tmptrack.tpcChi2NCl(); + // chi2ITS[counterTmp] = tmptrack.itsChi2NCl(); + if (tmptrack.hasTOF()) + chi2TOF[counterTmp] = tmptrack.tofChi2(); + // nclTPCfind[counterTmp] = tmptrack.tpcNClsFindable(); + nclTPCcrossedRows[counterTmp] = tmptrack.tpcNClsCrossedRows(); + + // tmpHasTOF[counterTmp] = tmptrack.hasTOF(); + trkHasTpc[counterTmp] = tmptrack.hasTPC(); + // trkTime[counterTmp] = tmptrack.trackTime(); + // trkTimeRes[counterTmp] = tmptrack.trackTimeRes(); + + tmpMomentum[counterTmp] = p1.P(); + tmpPt[counterTmp] = p1.Pt(); + tmpDedx[counterTmp] = tmptrack.tpcSignal(); + tmpTofNsigmaEl[counterTmp] = tmptrack.tofNSigmaEl(); + + deltaPhiTmp = calculateDeltaPhi(p - p1, p1); + pi3invMass[counterTmp] = (p - p1).Mag(); + pi3pt[counterTmp] = (p - p1).Pt(); + pi3deltaPhi[counterTmp] = deltaPhiTmp; + pi3assymav[counterTmp] = (p1.Pt() - (scalarPtsum - p1.Pt()) / 3.) / (p1.Pt() + (scalarPtsum - p1.Pt()) / 3.); + pi3vector[counterTmp] = p.Pt() / (p - p1 - p1).Pt(); + pi3scalar[counterTmp] = ((p - p1).Pt() - p1.Pt()) / ((p - p1).Pt() + p1.Pt()); + + counterTmp++; + } // end of second loop over PVtracks + + // fill the histograms with true information + for (int i = 0; i < 4; i++) { + // nsigma3Pi calculation + nSigma3Pi[i] = nSigma3Pi[3] - (nSigmaPi[i] * nSigmaPi[i]); + nSigma3Pi[i] = std::sqrt(nSigma3Pi[i]); + // nsigma3PiNew calculation + if (trkHasTpc[i]) { + nSigma3PiNew[i] = nSigma3PiNew[3] - (nSigmaPi[i] * nSigmaPi[i]); + } + nSigma3PiNew[i] = std::sqrt(nSigma3PiNew[i]); + + if (i == matchedElIndexToData) { + fillControlHistosMCtrue<0>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("controlMCtrue/cut0/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut0"))->Fill(tmpMomentum[i], tmpDedx[i]); + registryMC.get(HIST("controlMCtrue/cut0/hsigma3Pi"))->Fill(nSigma3Pi[i]); + if (nPiHasTPC[i] == 3) + registry1MC.get(HIST("controlMCtrue/cut0/hsigma3PiNew"))->Fill(nSigma3PiNew[i]); + if (nPiHasTPC[i] == 2) + registry1MC.get(HIST("controlMCtrue/cut0/hsigma2PiNew"))->Fill(nSigma3PiNew[i]); + if (nPiHasTPC[i] == 1) + registry1MC.get(HIST("controlMCtrue/cut0/hsigma1PiNew"))->Fill(nSigma3PiNew[i]); + + registry1MC.get(HIST("pidTOFMCEltrue/hpvsNsigmaElHipCut0"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + // registryMC.get(HIST("control/cut0/h3pi1eMass"))->Fill(mass3pi1e[i]); + } else { // only for 1prong = electron true + fillControlHistosMCcomb<0>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("pidTPCMCPitrue/hpvsdedxElHipCut0"))->Fill(tmpMomentum[i], tmpDedx[i]); + registryMC.get(HIST("controlMCcomb/cut0/hsigma3Pi"))->Fill(nSigma3Pi[i]); + } + } // end of loop over PV tracks' informations + // global variables + registryMC.get(HIST("controlMCtrue/cut0/h3pi1eMass"))->Fill(mass4pi); // 3pi + 1e mass + registryMC.get(HIST("controlMCtrue/cut0/h4trkPtTot"))->Fill(pttot); + registryMC.get(HIST("controlMCtrue/cut0/h4piMass"))->Fill(mass4pi); + registryMC.get(HIST("controlMCtrue/cut0/h4trkMassVsPt"))->Fill(mass4pi, pttot); + // registryMC.get(HIST("controlMCtrue/cut0/hNtofTrk"))->Fill(nTofTrk); + registryMC.get(HIST("controlMCtrue/cut0/hZNACenergy"))->Fill(energyZNA, energyZNC); + + // remove combinatorics + // bool flagTotal[4] = {false, false, false, false}; + bool flagIM[4] = {false, false, false, false}; + bool flagDP[4] = {false, false, false, false}; + bool flagEl[4] = {false, false, false, false}; + bool flagPi[4] = {false, false, false, false}; + bool flagPr[4] = {false, false, false, false}; + bool flagKa[4] = {false, false, false, false}; + bool flagCR[4] = {false, false, false, false}; + bool flagS3pi[4] = {false, false, false, false}; + + for (int i = 0; i < 4; i++) { + if (pi3invMass[i] < invMass3piMaxcut) { // default should be 1.8 + if (invMass3piSignalRegion) { + flagIM[i] = true; + } else { + flagIM[i] = false; + } + } else { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut2"))->Fill(tmpMomentum[i], tmpDedx[i]); + } + + if (pi3deltaPhi[i] > deltaPhiMincut) { // default should be 1.5 + flagDP[i] = true; + } else { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut3"))->Fill(tmpMomentum[i], tmpDedx[i]); + } + + if (minNsigmaElcut < nSigmaEl[i] && nSigmaEl[i] < maxNsigmaElcut) { // default (-2,3) + flagEl[i] = true; + } else { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut4"))->Fill(tmpMomentum[i], tmpDedx[i]); + } + + if (std::abs(nSigmaPi[i]) > maxNsigmaPiVetocut) { // default is 4 + flagPi[i] = true; + } else { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut5"))->Fill(tmpMomentum[i], tmpDedx[i]); + } + + // if (tmpPt[i] > minPtEtrkcut) { // 0.25 + // flagPt[i] = true; + // } else { + // registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut6"))->Fill(tmpMomentum[i], tmpDedx[i]); + // } + + if (flagVcalPV[i]) { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut7"))->Fill(tmpMomentum[i], tmpDedx[i]); + } + + if (pttot < 0.15) { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut8"))->Fill(tmpMomentum[i], tmpDedx[i]); + } + + if (std::abs(nSigmaPr[i]) > maxNsigmaPrVetocut) { // default is 3 + flagPr[i] = true; + } else { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut9"))->Fill(tmpMomentum[i], tmpDedx[i]); + } + + if (std::abs(nSigmaKa[i]) > maxNsigmaKaVetocut) { // default is 3 + flagKa[i] = true; + } else { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut10"))->Fill(tmpMomentum[i], tmpDedx[i]); + } + + if (nclTPCcrossedRows[i] > nTPCcrossedRowsMinCut) { // default is 50 + flagCR[i] = true; + } else { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut11"))->Fill(tmpMomentum[i], tmpDedx[i]); + } + + if (nSigma3Pi[i] < nSigma3piMaxCut) { // default is 5 + flagS3pi[i] = true; + } else { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut12"))->Fill(tmpMomentum[i], tmpDedx[i]); + } + + // flagTotal[i] = flagEl[i] && flagPi[i] && flagPt[i] && !flagVcalPV[i] && flagPr[i] && flagKa[i] && flagIM[i] && flagDP[i] && flagCR[i] && flagS3pi[i]; + } // end of loop over 4 tracks + + int counterEl = flagEl[0] + flagEl[1] + flagEl[2] + flagEl[3]; + + // + // draw PID and control histograms + // + + // + // Nelectrons in TPC PID nsigma > 0, cut20 + // + if (counterEl > 0) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(20., 1.); // at least 1 electron identified + if (tracksMatchedToMC) + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(21., 1.); // electron identified, tracks match to MC Particles + if (tracksMatchedToMC && flagEl[matchedElIndexToData]) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(22., 1.); // electron identified, tracks match to MC Particles, El is MC El true + + registryMC.get(HIST("controlMCtrue/cut20/h4piMass"))->Fill(mass4pi); + registryMC.get(HIST("controlMCtrue/cut20/h4trkPtTot"))->Fill(pttot); + registryMC.get(HIST("controlMCtrue/cut20/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registryMC.get(HIST("controlMCtrue/cut20/hZNACenergy"))->Fill(energyZNA, energyZNC); + // registryMC.get(HIST("controlMCtrue/cut20/hNtofTrk"))->Fill(nTofTrk); + } + for (int i = 0; i < 4; i++) { + if (flagEl[i] && tracksMatchedToMC && (i == matchedElIndexToData)) { // only for 1prong = electron true + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut20"))->Fill(tmpMomentum[i], tmpDedx[i]); + fillControlHistosMCtrue<20>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("controlMCtrue/cut20/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registryMC.get(HIST("controlMCtrue/cut20/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry1MC.get(HIST("pidTOFMCEltrue/hpvsNsigmaElHipCut20"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + // registry1MC.get(HIST("controlMCtrue/cut20/hTofChi2El"))->Fill(chi2TOF[i]); + } else if (tracksMatchedToMC && (i != matchedElIndexToData)) { + fillControlHistosMCcomb<20>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("pidTPCMCPitrue/hpvsdedxElHipCut20"))->Fill(tmpMomentum[i], tmpDedx[i]); + registryMC.get(HIST("controlMCcomb/cut20/hsigma3Pi"))->Fill(nSigma3Pi[i]); + // registry1MC.get(HIST("controlMCcomb/cut20/hTofChi2El"))->Fill(chi2TOF[i]); + } + } // end of loop over 4 PV tracks + // end of electron found cut20 + } else { // no electron + if (verbose) { + LOGF(debug, " Candidate rejected: no electron PID among 4 tracks"); + } + return; + } // end of Nelectrons check + + // + // electron has TOF hit + // + if (flagEl[0] * trkHasTof[0] + + flagEl[1] * trkHasTof[1] + + flagEl[2] * trkHasTof[2] + + flagEl[3] * trkHasTof[3] > + 0) { // electron has tof hit cut 33 + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(59., 1.); // electron identified + TOF hit + if (tracksMatchedToMC) + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(60., 1.); // electron identified, tracks match to MC Particles + if (tracksMatchedToMC && flagEl[matchedElIndexToData] && + trkHasTof[matchedElIndexToData]) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(61., 1.); // El PID +TOF, tracks match to MC Particles, El is MC El true + + registryMC.get(HIST("controlMCtrue/cut33/h4piMass"))->Fill(mass4pi); + registryMC.get(HIST("controlMCtrue/cut33/h4trkPtTot"))->Fill(pttot); + registryMC.get(HIST("controlMCtrue/cut33/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registryMC.get(HIST("controlMCtrue/cut33/hZNACenergy"))->Fill(energyZNA, energyZNC); + // registryMC.get(HIST("controlMCtrue/cut33/hNtofTrk"))->Fill(nTofTrk); + } + for (int i = 0; i < 4; i++) { + if (tracksMatchedToMC && flagEl[i] && + trkHasTof[i] && (i == matchedElIndexToData)) { // only for 1prong = electron true + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut33"))->Fill(tmpMomentum[i], tmpDedx[i]); + fillControlHistosMCtrue<33>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("controlMCtrue/cut33/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registryMC.get(HIST("controlMCtrue/cut33/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry1MC.get(HIST("pidTOFMCEltrue/hpvsNsigmaElHipCut33"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + } else if (tracksMatchedToMC && (i != matchedElIndexToData)) { + fillControlHistosMCcomb<33>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("pidTPCMCPitrue/hpvsdedxElHipCut33"))->Fill(tmpMomentum[i], tmpDedx[i]); + registryMC.get(HIST("controlMCcomb/cut33/hsigma3Pi"))->Fill(nSigma3Pi[i]); + } + } // end of loop over 4 PV tracks + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: electron has no tof hit "); + } + return; + } // end of electron has tof hit cut 33 + + // + // electron survived pi veto, cut21 + // + if (flagEl[0] * trkHasTof[0] * flagPi[0] + + flagEl[1] * trkHasTof[1] * flagPi[1] + + flagEl[2] * trkHasTof[2] * flagPi[2] + + flagEl[3] * trkHasTof[3] * flagPi[3] > + 0) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(23., 1.); // electron identified + if (tracksMatchedToMC) + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(24., 1.); // electron identified, tracks match to MC Particles + if (tracksMatchedToMC && flagEl[matchedElIndexToData] && + trkHasTof[matchedElIndexToData] && flagPi[matchedElIndexToData]) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(25., 1.); // pion veto, tracks match to MC Particles, El is MC El true + + registryMC.get(HIST("controlMCtrue/cut21/h4piMass"))->Fill(mass4pi); + registryMC.get(HIST("controlMCtrue/cut21/h4trkPtTot"))->Fill(pttot); + registryMC.get(HIST("controlMCtrue/cut21/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registryMC.get(HIST("controlMCtrue/cut21/hZNACenergy"))->Fill(energyZNA, energyZNC); + // registryMC.get(HIST("controlMCtrue/cut21/hNtofTrk"))->Fill(nTofTrk); + } + for (int i = 0; i < 4; i++) { + if (tracksMatchedToMC && flagEl[i] && trkHasTof[i] && flagPi[i] && (i == matchedElIndexToData)) { // only for 1prong = electron true + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut21"))->Fill(tmpMomentum[i], tmpDedx[i]); + fillControlHistosMCtrue<21>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("controlMCtrue/cut21/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registryMC.get(HIST("controlMCtrue/cut21/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry1MC.get(HIST("pidTOFMCEltrue/hpvsNsigmaElHipCut21"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + } else if (tracksMatchedToMC && (i != matchedElIndexToData)) { + fillControlHistosMCcomb<21>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("pidTPCMCPitrue/hpvsdedxElHipCut21"))->Fill(tmpMomentum[i], tmpDedx[i]); + registryMC.get(HIST("controlMCcomb/cut21/hsigma3Pi"))->Fill(nSigma3Pi[i]); + } + } // end of loop over 4 PV tracks + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: all electrons vetoed by pi PID"); + } + return; + } // end of pi veto, cut21 + + // + // additional proton veto on electron, cut24 + // + if (flagEl[0] * trkHasTof[0] * flagPi[0] * flagPr[0] + + flagEl[1] * trkHasTof[1] * flagPi[1] * flagPr[1] + + flagEl[2] * trkHasTof[2] * flagPi[2] * flagPr[2] + + flagEl[3] * trkHasTof[3] * flagPi[3] * flagPr[3] > + 0) { // proton veto, cut24 + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(26., 1.); // electron identified + if (tracksMatchedToMC) + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(27., 1.); // electron identified, tracks match to MC Particles + if (tracksMatchedToMC && flagEl[matchedElIndexToData] && trkHasTof[matchedElIndexToData] && flagPi[matchedElIndexToData] && flagPr[matchedElIndexToData]) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(28., 1.); // proton veto, tracks match to MC Particles, El is MC El true + + registryMC.get(HIST("controlMCtrue/cut24/h4piMass"))->Fill(mass4pi); + registryMC.get(HIST("controlMCtrue/cut24/h4trkPtTot"))->Fill(pttot); + registryMC.get(HIST("controlMCtrue/cut24/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registryMC.get(HIST("controlMCtrue/cut24/hZNACenergy"))->Fill(energyZNA, energyZNC); + // registryMC.get(HIST("controlMCtrue/cut24/hNtofTrk"))->Fill(nTofTrk); + } + for (int i = 0; i < 4; i++) { + if (tracksMatchedToMC && flagEl[i] && flagEl[i] && flagPi[i] && flagPr[i] && (i == matchedElIndexToData)) { // only for 1prong = electron true + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut24"))->Fill(tmpMomentum[i], tmpDedx[i]); + fillControlHistosMCtrue<24>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("controlMCtrue/cut24/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registryMC.get(HIST("controlMCtrue/cut24/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry1MC.get(HIST("pidTOFMCEltrue/hpvsNsigmaElHipCut24"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + } else if (tracksMatchedToMC && (i != matchedElIndexToData)) { + fillControlHistosMCcomb<24>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("pidTPCMCPitrue/hpvsdedxElHipCut24"))->Fill(tmpMomentum[i], tmpDedx[i]); + registryMC.get(HIST("controlMCcomb/cut24/hsigma3Pi"))->Fill(nSigma3Pi[i]); + } + } // end of loop over 4 PV tracks + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: all electrons vetoed by proton PID"); + } + return; + } // end of proton veto, cut24 + + // + // additional kaon veto on electron, cut25 + // + if (flagEl[0] * trkHasTof[0] * flagPi[0] * flagPr[0] * flagKa[0] + + flagEl[1] * trkHasTof[1] * flagPi[1] * flagPr[1] * flagKa[1] + + flagEl[2] * trkHasTof[2] * flagPi[2] * flagPr[2] * flagKa[2] + + flagEl[3] * trkHasTof[3] * flagPi[3] * flagPr[3] * flagKa[3] > + 0) { // kaon veto, cut25 + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(29., 1.); // electron identified + if (tracksMatchedToMC) + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(30., 1.); // electron identified, tracks match to MC Particles + if (tracksMatchedToMC && flagEl[matchedElIndexToData] && + trkHasTof[matchedElIndexToData] && flagPi[matchedElIndexToData] && flagPr[matchedElIndexToData] && flagKa[matchedElIndexToData]) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(31., 1.); // kaon veto, tracks match to MC Particles, El is MC El true + + registryMC.get(HIST("controlMCtrue/cut25/h4piMass"))->Fill(mass4pi); + registryMC.get(HIST("controlMCtrue/cut25/h4trkPtTot"))->Fill(pttot); + registryMC.get(HIST("controlMCtrue/cut25/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registryMC.get(HIST("controlMCtrue/cut25/hZNACenergy"))->Fill(energyZNA, energyZNC); + // registryMC.get(HIST("controlMCtrue/cut25/hNtofTrk"))->Fill(nTofTrk); + } + for (int i = 0; i < 4; i++) { + if (tracksMatchedToMC && flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i] && (i == matchedElIndexToData)) { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut25"))->Fill(tmpMomentum[i], tmpDedx[i]); + fillControlHistosMCtrue<25>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("controlMCtrue/cut25/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registryMC.get(HIST("controlMCtrue/cut25/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry1MC.get(HIST("pidTOFMCEltrue/hpvsNsigmaElHipCut25"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + } else if (tracksMatchedToMC && (i != matchedElIndexToData)) { + fillControlHistosMCcomb<25>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("pidTPCMCPitrue/hpvsdedxElHipCut25"))->Fill(tmpMomentum[i], tmpDedx[i]); + registryMC.get(HIST("controlMCcomb/cut25/hsigma3Pi"))->Fill(nSigma3Pi[i]); + } + } // end of loop over 4 PV tracks + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: all electrons vetoed by K PID"); + } + return; + } // end of proton veto, cut25 + + // + // crossd rows in TPC + // + if (flagEl[0] * trkHasTof[0] * flagPi[0] * flagPr[0] * flagKa[0] * flagCR[0] + + flagEl[1] * trkHasTof[1] * flagPi[1] * flagPr[1] * flagKa[1] * flagCR[1] + + flagEl[2] * trkHasTof[2] * flagPi[2] * flagPr[2] * flagKa[2] * flagCR[2] + + flagEl[3] * trkHasTof[3] * flagPi[3] * flagPr[3] * flagKa[3] * flagCR[3] > + 0) { // Nc-rTPC cut, cut28 + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(32., 1.); // electron identified + if (tracksMatchedToMC) + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(33., 1.); // electron identified, tracks match to MC Particles + if (tracksMatchedToMC && trkHasTof[matchedElIndexToData] && + flagEl[matchedElIndexToData] && flagPi[matchedElIndexToData] && flagPr[matchedElIndexToData] && flagKa[matchedElIndexToData] && flagCR[matchedElIndexToData]) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(34., 1.); // CR, tracks match to MC Particles, El is MC El true + + registryMC.get(HIST("controlMCtrue/cut28/h4piMass"))->Fill(mass4pi); + registryMC.get(HIST("controlMCtrue/cut28/h4trkPtTot"))->Fill(pttot); + registryMC.get(HIST("controlMCtrue/cut28/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registryMC.get(HIST("controlMCtrue/cut28/hZNACenergy"))->Fill(energyZNA, energyZNC); + // registryMC.get(HIST("controlMCtrue/cut28/hNtofTrk"))->Fill(nTofTrk); + } + for (int i = 0; i < 4; i++) { + if (tracksMatchedToMC && flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i] && (i == matchedElIndexToData)) { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut28"))->Fill(tmpMomentum[i], tmpDedx[i]); + fillControlHistosMCtrue<28>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("controlMCtrue/cut28/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registryMC.get(HIST("controlMCtrue/cut28/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry1MC.get(HIST("pidTOFMCEltrue/hpvsNsigmaElHipCut28"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + } else if (tracksMatchedToMC && (i != matchedElIndexToData)) { + fillControlHistosMCcomb<28>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("pidTPCMCPitrue/hpvsdedxElHipCut28"))->Fill(tmpMomentum[i], tmpDedx[i]); + registryMC.get(HIST("controlMCcomb/cut28/hsigma3Pi"))->Fill(nSigma3Pi[i]); + } + } // end of loop over 4 PV tracks + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: all electrons vetoed by CR in TPC"); + } + return; + } // end of TPC crossed rows for electron cut, cut28 + + // + // virtual calorimeter for electron + // + if (flagEl[0] * trkHasTof[0] * flagPi[0] * flagPr[0] * flagKa[0] * flagCR[0] * !flagVcalPV[0] + + flagEl[1] * trkHasTof[1] * flagPi[1] * flagPr[1] * flagKa[1] * flagCR[1] * !flagVcalPV[1] + + flagEl[2] * trkHasTof[2] * flagPi[2] * flagPr[2] * flagKa[2] * flagCR[2] * !flagVcalPV[2] + + flagEl[3] * trkHasTof[3] * flagPi[3] * flagPr[3] * flagKa[3] * flagCR[3] * !flagVcalPV[3] > + 0) { // vcal veto on electron, cut22 + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(35., 1.); // electron identified + if (tracksMatchedToMC) + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(36., 1.); // electron identified, tracks match to MC Particles + if (tracksMatchedToMC && flagEl[matchedElIndexToData] && trkHasTof[matchedElIndexToData] && flagPi[matchedElIndexToData] && + flagPr[matchedElIndexToData] && flagKa[matchedElIndexToData] && flagCR[matchedElIndexToData] && + !flagVcalPV[matchedElIndexToData]) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(37., 1.); // kaon veto, tracks match to MC Particles, El is MC El true + + registryMC.get(HIST("controlMCtrue/cut22/h4piMass"))->Fill(mass4pi); + registryMC.get(HIST("controlMCtrue/cut22/h4trkPtTot"))->Fill(pttot); + registryMC.get(HIST("controlMCtrue/cut22/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registryMC.get(HIST("controlMCtrue/cut22/hZNACenergy"))->Fill(energyZNA, energyZNC); + // registryMC.get(HIST("controlMCtrue/cut22/hNtofTrk"))->Fill(nTofTrk); + } + for (int i = 0; i < 4; i++) { + if (tracksMatchedToMC && flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i] && !flagVcalPV[i] && (i == matchedElIndexToData)) { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut22"))->Fill(tmpMomentum[i], tmpDedx[i]); + fillControlHistosMCtrue<22>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("controlMCtrue/cut22/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registryMC.get(HIST("controlMCtrue/cut22/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry1MC.get(HIST("pidTOFMCEltrue/hpvsNsigmaElHipCut22"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + } else if (tracksMatchedToMC && (i != matchedElIndexToData)) { + fillControlHistosMCcomb<22>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("pidTPCMCPitrue/hpvsdedxElHipCut22"))->Fill(tmpMomentum[i], tmpDedx[i]); + registryMC.get(HIST("controlMCcomb/cut22/hsigma3Pi"))->Fill(nSigma3Pi[i]); + } + } // end of loop over 4 PV tracks + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: all electrons vetoed by Vcal"); + } + return; + } // end of vcal cut on electron, cut22 + + // + // nsigma 3pi cut, cut29 + // + if (flagEl[0] * trkHasTof[0] * flagPi[0] * flagPr[0] * flagKa[0] * flagCR[0] * !flagVcalPV[0] * flagS3pi[0] + + flagEl[1] * trkHasTof[1] * flagPi[1] * flagPr[1] * flagKa[1] * flagCR[1] * !flagVcalPV[1] * flagS3pi[1] + + flagEl[2] * trkHasTof[2] * flagPi[2] * flagPr[2] * flagKa[2] * flagCR[2] * !flagVcalPV[2] * flagS3pi[2] + + flagEl[3] * trkHasTof[3] * flagPi[3] * flagPr[3] * flagKa[3] * flagCR[3] * !flagVcalPV[3] * flagS3pi[3] > + 0) { // nsigma 3pi cut, cut29 + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(41., 1.); // electron identified + if (tracksMatchedToMC) + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(42., 1.); // electron identified, tracks match to MC Particles + if (tracksMatchedToMC && flagEl[matchedElIndexToData] && trkHasTof[matchedElIndexToData] && flagPi[matchedElIndexToData] && + flagPr[matchedElIndexToData] && flagKa[matchedElIndexToData] && flagCR[matchedElIndexToData] && + !flagVcalPV[matchedElIndexToData] && flagS3pi[matchedElIndexToData]) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(43., 1.); // kaon veto, tracks match to MC Particles, El is MC El true + + registryMC.get(HIST("controlMCtrue/cut29/h4piMass"))->Fill(mass4pi); + registryMC.get(HIST("controlMCtrue/cut29/h4trkPtTot"))->Fill(pttot); + registryMC.get(HIST("controlMCtrue/cut29/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registryMC.get(HIST("controlMCtrue/cut29/hZNACenergy"))->Fill(energyZNA, energyZNC); + // registryMC.get(HIST("controlMCtrue/cut29/hNtofTrk"))->Fill(nTofTrk); + } + for (int i = 0; i < 4; i++) { + if (tracksMatchedToMC && flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i] && !flagVcalPV[i] && flagS3pi[i] && (i == matchedElIndexToData)) { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut29"))->Fill(tmpMomentum[i], tmpDedx[i]); + fillControlHistosMCtrue<29>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("controlMCtrue/cut29/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registryMC.get(HIST("controlMCtrue/cut29/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry1MC.get(HIST("pidTOFMCEltrue/hpvsNsigmaElHipCut29"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + } else if (tracksMatchedToMC && (i != matchedElIndexToData)) { + fillControlHistosMCcomb<29>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("pidTPCMCPitrue/hpvsdedxElHipCut29"))->Fill(tmpMomentum[i], tmpDedx[i]); + registryMC.get(HIST("controlMCcomb/cut29/hsigma3Pi"))->Fill(nSigma3Pi[i]); + } + } // end of loop over 4 PV tracks + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: all electrons vetoed by 3piSigma"); + } + return; + } // end of sigma 3pi cut, cut29 + + // + // invariant mass of 3 pi <1.8 + // + if (flagEl[0] * trkHasTof[0] * flagPi[0] * flagPr[0] * flagKa[0] * flagCR[0] * !flagVcalPV[0] * flagS3pi[0] * flagIM[0] + + flagEl[1] * trkHasTof[1] * flagPi[1] * flagPr[1] * flagKa[1] * flagCR[1] * !flagVcalPV[1] * flagS3pi[1] * flagIM[1] + + flagEl[2] * trkHasTof[2] * flagPi[2] * flagPr[2] * flagKa[2] * flagCR[2] * !flagVcalPV[2] * flagS3pi[2] * flagIM[2] + + flagEl[3] * trkHasTof[3] * flagPi[3] * flagPr[3] * flagKa[3] * flagCR[3] * !flagVcalPV[3] * flagS3pi[3] * flagIM[3] > + 0) { // IM 3pi cut, cut26 + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(44., 1.); // electron identified + if (tracksMatchedToMC) + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(45., 1.); // electron identified, tracks match to MC Particles + if (tracksMatchedToMC && flagEl[matchedElIndexToData] && trkHasTof[matchedElIndexToData] && flagPi[matchedElIndexToData] && + flagPr[matchedElIndexToData] && flagKa[matchedElIndexToData] && flagCR[matchedElIndexToData] && + !flagVcalPV[matchedElIndexToData] && flagS3pi[matchedElIndexToData] && + flagIM[matchedElIndexToData]) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(46., 1.); // IM 3pi, tracks match to MC Particles, El is MC El true + + registryMC.get(HIST("controlMCtrue/cut26/h4piMass"))->Fill(mass4pi); + registryMC.get(HIST("controlMCtrue/cut26/h4trkPtTot"))->Fill(pttot); + registryMC.get(HIST("controlMCtrue/cut26/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registryMC.get(HIST("controlMCtrue/cut26/hZNACenergy"))->Fill(energyZNA, energyZNC); + // registryMC.get(HIST("controlMCtrue/cut26/hNtofTrk"))->Fill(nTofTrk); + } + for (int i = 0; i < 4; i++) { + if (tracksMatchedToMC && flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i] && !flagVcalPV[i] && flagS3pi[i] && flagIM[i] && (i == matchedElIndexToData)) { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut26"))->Fill(tmpMomentum[i], tmpDedx[i]); + fillControlHistosMCtrue<26>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("controlMCtrue/cut26/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registryMC.get(HIST("controlMCtrue/cut26/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry1MC.get(HIST("pidTOFMCEltrue/hpvsNsigmaElHipCut26"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + } else if (tracksMatchedToMC && (i != matchedElIndexToData)) { + fillControlHistosMCcomb<26>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("pidTPCMCPitrue/hpvsdedxElHipCut26"))->Fill(tmpMomentum[i], tmpDedx[i]); + registryMC.get(HIST("controlMCcomb/cut26/hsigma3Pi"))->Fill(nSigma3Pi[i]); + } + } // end of loop over 4 PV tracks + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: all electrons vetoed by IM"); + } + return; + } // end of IM 3pi cut, cut26 + + // + // at least one pion with tof hit (cut34) + // + int otherTOFtracks = 0; + for (int j = 0; j < 4; j++) { + if (j == matchedElIndexToData) + continue; + otherTOFtracks += trkHasTof[j]; + } + + if (otherTOFtracks >= 1) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(62., 1.); // electron identified + if (tracksMatchedToMC) + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(63., 1.); // electron identified, tracks match to MC Particles + if (tracksMatchedToMC && flagEl[matchedElIndexToData] && trkHasTof[matchedElIndexToData] && flagPi[matchedElIndexToData] && + flagPr[matchedElIndexToData] && flagKa[matchedElIndexToData] && flagCR[matchedElIndexToData] && + !flagVcalPV[matchedElIndexToData] && flagS3pi[matchedElIndexToData] && + flagIM[matchedElIndexToData] && trkHasTof[matchedElIndexToData]) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(64., 1.); // 1tof hit in 3pi, tracks match to MC Particles, El is MC El true + + registryMC.get(HIST("controlMCtrue/cut34/h4piMass"))->Fill(mass4pi); + registryMC.get(HIST("controlMCtrue/cut34/h4trkPtTot"))->Fill(pttot); + registryMC.get(HIST("controlMCtrue/cut34/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registryMC.get(HIST("controlMCtrue/cut34/hZNACenergy"))->Fill(energyZNA, energyZNC); + registry1MC.get(HIST("globalMCrec/hRecFlag"))->Fill(5 + collision.flags()); // reconstruction with upc settings flag + // registryMC.get(HIST("controlMCtrue/cut34/hNtofTrk"))->Fill(nTofTrk); + } + for (int i = 0; i < 4; i++) { + if (tracksMatchedToMC && flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i] && !flagVcalPV[i] && flagS3pi[i] && flagIM[i] && (i == matchedElIndexToData)) { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut34"))->Fill(tmpMomentum[i], tmpDedx[i]); + fillControlHistosMCtrue<34>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("controlMCtrue/cut34/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registryMC.get(HIST("controlMCtrue/cut34/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry1MC.get(HIST("pidTOFMCEltrue/hpvsNsigmaElHipCut34"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + } else if (tracksMatchedToMC && (i != matchedElIndexToData)) { + fillControlHistosMCcomb<34>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("pidTPCMCPitrue/hpvsdedxElHipCut34"))->Fill(tmpMomentum[i], tmpDedx[i]); + registryMC.get(HIST("controlMCcomb/cut34/hsigma3Pi"))->Fill(nSigma3Pi[i]); + } + } // end of loop over 4 PV tracks + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: none of 3pi has no tof hit "); + } + return; + } // end of at least one tof hit in 3pi, cut34 + + // + // skip events with pttot<0.15 + // + if (pttot >= ptTotcut) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(47., 1.); // electron identified + if (tracksMatchedToMC) + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(48., 1.); // electron identified, tracks match to MC Particles + if (tracksMatchedToMC && flagEl[matchedElIndexToData] && trkHasTof[matchedElIndexToData] && flagPi[matchedElIndexToData] && + flagPr[matchedElIndexToData] && flagKa[matchedElIndexToData] && flagCR[matchedElIndexToData] && + !flagVcalPV[matchedElIndexToData] && flagS3pi[matchedElIndexToData] && + flagIM[matchedElIndexToData]) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(49., 1.); // IM 3pi, tracks match to MC Particles, El is MC El true + + registryMC.get(HIST("controlMCtrue/cut30/h4piMass"))->Fill(mass4pi); + registryMC.get(HIST("controlMCtrue/cut30/h4trkPtTot"))->Fill(pttot); + registryMC.get(HIST("controlMCtrue/cut30/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registryMC.get(HIST("controlMCtrue/cut30/hZNACenergy"))->Fill(energyZNA, energyZNC); + // registryMC.get(HIST("controlMCtrue/cut30/hNtofTrk"))->Fill(nTofTrk); + registry1MC.get(HIST("globalMCrec/hRecFlag"))->Fill(5 + 2 + collision.flags()); // reconstruction with upc settings flag + } + for (int i = 0; i < 4; i++) { + if (tracksMatchedToMC && flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i] && !flagVcalPV[i] && flagS3pi[i] && flagIM[i] && (i == matchedElIndexToData)) { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut30"))->Fill(tmpMomentum[i], tmpDedx[i]); + fillControlHistosMCtrue<30>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("controlMCtrue/cut30/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registryMC.get(HIST("controlMCtrue/cut30/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry1MC.get(HIST("pidTOFMCEltrue/hpvsNsigmaElHipCut30"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + } else if (tracksMatchedToMC && (i != matchedElIndexToData)) { + fillControlHistosMCcomb<30>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("pidTPCMCPitrue/hpvsdedxElHipCut30"))->Fill(tmpMomentum[i], tmpDedx[i]); + registryMC.get(HIST("controlMCcomb/cut30/hsigma3Pi"))->Fill(nSigma3Pi[i]); + } + } // end of loop over 4 PV tracks + } else { + if (verbose) { + LOGF(info, " Candidate rejected: pt tot is %f", pttot); + } + return; + } // end of pttot cut, cut30 + + // + // delta phi cut, cut27 + // + if (flagEl[0] * trkHasTof[0] * flagPi[0] * flagPr[0] * flagKa[0] * flagCR[0] * !flagVcalPV[0] * flagS3pi[0] * flagIM[0] * flagDP[0] + + flagEl[1] * trkHasTof[1] * flagPi[1] * flagPr[1] * flagKa[1] * flagCR[1] * !flagVcalPV[1] * flagS3pi[1] * flagIM[1] * flagDP[1] + + flagEl[2] * trkHasTof[2] * flagPi[2] * flagPr[2] * flagKa[2] * flagCR[2] * !flagVcalPV[2] * flagS3pi[2] * flagIM[2] * flagDP[2] + + flagEl[3] * trkHasTof[3] * flagPi[3] * flagPr[3] * flagKa[3] * flagCR[3] * !flagVcalPV[3] * flagS3pi[3] * flagIM[3] * flagDP[3] > + 0) { // delta phi cut, cut27 + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(50., 1.); // electron identified + if (tracksMatchedToMC) + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(51., 1.); // electron identified, tracks match to MC Particles + if (tracksMatchedToMC && flagEl[matchedElIndexToData] && trkHasTof[matchedElIndexToData] && flagPi[matchedElIndexToData] && + flagPr[matchedElIndexToData] && flagKa[matchedElIndexToData] && flagCR[matchedElIndexToData] && + !flagVcalPV[matchedElIndexToData] && flagS3pi[matchedElIndexToData] && + flagIM[matchedElIndexToData] && flagDP[matchedElIndexToData]) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(52., 1.); // IM 3pi, tracks match to MC Particles, El is MC El true + + registryMC.get(HIST("controlMCtrue/cut27/h4piMass"))->Fill(mass4pi); + registryMC.get(HIST("controlMCtrue/cut27/h4trkPtTot"))->Fill(pttot); + registryMC.get(HIST("controlMCtrue/cut27/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registryMC.get(HIST("controlMCtrue/cut27/hZNACenergy"))->Fill(energyZNA, energyZNC); + // registryMC.get(HIST("controlMCtrue/cut27/hNtofTrk"))->Fill(nTofTrk); + registry1MC.get(HIST("globalMCrec/hRecFlag"))->Fill(5 + 2 + 2 + collision.flags()); // reconstruction with upc settings flag + } + for (int i = 0; i < 4; i++) { + if (tracksMatchedToMC && flagEl[i] && trkHasTof[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i] && !flagVcalPV[i] && flagS3pi[i] && flagIM[i] && flagDP[i] && (i == matchedElIndexToData)) { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut27"))->Fill(tmpMomentum[i], tmpDedx[i]); + fillControlHistosMCtrue<27>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("controlMCtrue/cut27/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registryMC.get(HIST("controlMCtrue/cut27/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry1MC.get(HIST("pidTOFMCEltrue/hpvsNsigmaElHipCut27"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + } else if (tracksMatchedToMC && (i != matchedElIndexToData)) { + fillControlHistosMCcomb<27>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("pidTPCMCPitrue/hpvsdedxElHipCut27"))->Fill(tmpMomentum[i], tmpDedx[i]); + registryMC.get(HIST("controlMCcomb/cut27/hsigma3Pi"))->Fill(nSigma3Pi[i]); + } + } // end of loop over 4 PV tracks + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: all electrons vetoed by Dphi"); + } + return; + } // end of dphi 3pi-e cut, cut27 + + // + // ZDC cut Energy < 1 TeV on both sides + // + if (energyZNA < 1. && energyZNC < 1.) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(65., 1.); // electron identified + if (tracksMatchedToMC) + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(66., 1.); // electron identified, tracks match to MC Particles + if (tracksMatchedToMC && flagEl[matchedElIndexToData] && flagPi[matchedElIndexToData] && + flagPr[matchedElIndexToData] && flagKa[matchedElIndexToData] && flagCR[matchedElIndexToData] && + !flagVcalPV[matchedElIndexToData] && flagS3pi[matchedElIndexToData] && + flagIM[matchedElIndexToData] && flagDP[matchedElIndexToData] && trkHasTof[matchedElIndexToData]) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(67., 1.); // zdc cut, tracks match to MC Particles, El is MC El true + + registryMC.get(HIST("controlMCtrue/cut35/h4piMass"))->Fill(mass4pi); + registryMC.get(HIST("controlMCtrue/cut35/h4trkPtTot"))->Fill(pttot); + registryMC.get(HIST("controlMCtrue/cut35/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registryMC.get(HIST("controlMCtrue/cut35/hZNACenergy"))->Fill(energyZNA, energyZNC); + // registryMC.get(HIST("controlMCtrue/cut35/hNtofTrk"))->Fill(nTofTrk); + } + for (int i = 0; i < 4; i++) { + if (tracksMatchedToMC && flagEl[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i] && !flagVcalPV[i] && flagS3pi[i] && flagIM[i] && flagDP[i] && trkHasTof[i] && (i == matchedElIndexToData)) { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut35"))->Fill(tmpMomentum[i], tmpDedx[i]); + fillControlHistosMCtrue<35>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("controlMCtrue/cut35/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registryMC.get(HIST("controlMCtrue/cut35/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry1MC.get(HIST("pidTOFMCEltrue/hpvsNsigmaElHipCut35"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + } else if (tracksMatchedToMC && (i != matchedElIndexToData)) { + fillControlHistosMCcomb<35>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("pidTPCMCPitrue/hpvsdedxElHipCut35"))->Fill(tmpMomentum[i], tmpDedx[i]); + registryMC.get(HIST("controlMCcomb/cut35/hsigma3Pi"))->Fill(nSigma3Pi[i]); + } + } // end of loop over 4 PV tracks + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: zdc cut "); + } + return; + } // end of zdc, cut35 + + // + // occupancy cut 23 + // + if (collision.occupancyInTime() < 1000) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(65., 1.); // electron identified + if (tracksMatchedToMC) + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(66., 1.); // electron identified, tracks match to MC Particles + if (tracksMatchedToMC && flagEl[matchedElIndexToData] && flagPi[matchedElIndexToData] && + flagPr[matchedElIndexToData] && flagKa[matchedElIndexToData] && flagCR[matchedElIndexToData] && + !flagVcalPV[matchedElIndexToData] && flagS3pi[matchedElIndexToData] && + flagIM[matchedElIndexToData] && flagDP[matchedElIndexToData] && trkHasTof[matchedElIndexToData]) { + registryMC.get(HIST("efficiencyMCEl/effiEl"))->Fill(67., 1.); // zdc cut, tracks match to MC Particles, El is MC El true + + registryMC.get(HIST("controlMCtrue/cut23/h4piMass"))->Fill(mass4pi); + registryMC.get(HIST("controlMCtrue/cut23/h4trkPtTot"))->Fill(pttot); + registryMC.get(HIST("controlMCtrue/cut23/h4trkMassVsPt"))->Fill(mass4pi, pttot); + registryMC.get(HIST("controlMCtrue/cut23/hZNACenergy"))->Fill(energyZNA, energyZNC); + // registryMC.get(HIST("controlMCtrue/cut23/hNtofTrk"))->Fill(nTofTrk); + } + for (int i = 0; i < 4; i++) { + if (tracksMatchedToMC && flagEl[i] && flagPi[i] && flagPr[i] && flagKa[i] && flagCR[i] && !flagVcalPV[i] && flagS3pi[i] && flagIM[i] && flagDP[i] && trkHasTof[i] && (i == matchedElIndexToData)) { + registryMC.get(HIST("pidTPCMCEltrue/hpvsdedxElHipCut23"))->Fill(tmpMomentum[i], tmpDedx[i]); + fillControlHistosMCtrue<23>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("controlMCtrue/cut23/h3piMassVsPt"))->Fill(pi3invMass[i], pi3pt[i]); + registryMC.get(HIST("controlMCtrue/cut23/hsigma3Pi"))->Fill(nSigma3Pi[i]); + registry1MC.get(HIST("pidTOFMCEltrue/hpvsNsigmaElHipCut23"))->Fill(tmpMomentum[i], tmpTofNsigmaEl[i]); + } else if (tracksMatchedToMC && (i != matchedElIndexToData)) { + fillControlHistosMCcomb<23>(pi3invMass[i], pi3pt[i], pi3deltaPhi[i], pi3assymav[i], pi3vector[i], pi3scalar[i], nclTPCcrossedRows[i], tmpPt[i], chi2TOF[i]); + registryMC.get(HIST("pidTPCMCPitrue/hpvsdedxElHipCut23"))->Fill(tmpMomentum[i], tmpDedx[i]); + registryMC.get(HIST("controlMCcomb/cut23/hsigma3Pi"))->Fill(nSigma3Pi[i]); + } + } // end of loop over 4 PV tracks + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: occupancy cut "); + } + return; + } // end of occupancy cut23 + + } // end of loop over collisions + } // end of electron + 3pi + + } // end of processEfficiencyMCSG + + // skimming: only 4 tracks selection + void processDoSkim(UDCollisionFull2 const& dgcand, UDTracksFull const& dgtracks, PVTracks const& PVContributors) + { + registrySkim.get(HIST("skim/efficiency"))->Fill(0., 1.); + int gapSide = dgcand.gapSide(); + int truegapSide = sgSelector.trueGap(dgcand, cutFV0, cutFT0A, cutFT0C, cutZDC); + if (gapSide < 0 || gapSide > 2) + return; + registrySkim.get(HIST("skim/efficiency"))->Fill(1., 1.); + + gapSide = truegapSide; + if (gapSide != mGapSide) + return; + registrySkim.get(HIST("skim/efficiency"))->Fill(2., 1.); + + // zdc information + float energyZNA = dgcand.energyCommonZNA(); + float energyZNC = dgcand.energyCommonZNC(); + if (energyZNA < 0) + energyZNA = -1.; + if (energyZNC < 0) + energyZNC = -1.; + + int nTofTrk = 0; + int nEtaIn15 = 0; + int npT100 = 0; + // int qtot = 0; + int16_t qtot = 0; + TLorentzVector p; + for (const auto& trk : PVContributors) { + qtot += trk.sign(); + p.SetXYZM(trk.px(), trk.py(), trk.pz(), MassPiPlus); + if (std::abs(p.Eta()) < trkEtacut) + nEtaIn15++; // 0.9 is a default + if (trk.pt() > 0.1) + npT100++; + if (trk.hasTOF()) + nTofTrk++; + } // end of loop over PV tracks + + if (PVContributors.size() != 4) + return; + registrySkim.get(HIST("skim/efficiency"))->Fill(3., 1.); + + if (nEtaIn15 != 4) + return; + registrySkim.get(HIST("skim/efficiency"))->Fill(4., 1.); + + if (npT100 != 4) + return; + registrySkim.get(HIST("skim/efficiency"))->Fill(5., 1.); + + if (nTofTrk < nTofTrkMinCut) + return; + registrySkim.get(HIST("skim/efficiency"))->Fill(6., 1.); + + // + // FIT informaton + // + auto bitMin = 16 - mFITvetoWindow; // default is +- 1 bc (1 bit) + auto bitMax = 16 + mFITvetoWindow; + bool flagFITveto = false; + // check FIT information + for (auto bit = bitMin; bit <= bitMax; bit++) { + if (TESTBIT(dgcand.bbFT0Apf(), bit)) + flagFITveto = true; + if (TESTBIT(dgcand.bbFT0Cpf(), bit)) + flagFITveto = true; + if (useFV0ForVeto && TESTBIT(dgcand.bbFV0Apf(), bit)) + flagFITveto = true; + if (useFDDAForVeto && TESTBIT(dgcand.bbFDDApf(), bit)) + flagFITveto = true; + if (useFDDCForVeto && TESTBIT(dgcand.bbFDDCpf(), bit)) + flagFITveto = true; + } // end of loop over FIT bits + + if (mFITvetoFlag && flagFITveto) + return; + registrySkim.get(HIST("skim/efficiency"))->Fill(7., 1.); + + // + // variables per track + // + int counterTmp = 0; + float px[4], py[4], pz[4]; + // int sign[4]; + // float dcaZ[4]; + // float dcaXY[4]; + + float tmpDedx[4]; + float tmpTofNsigmaEl[4]; + float tmpTofNsigmaPi[4]; + float tmpTofNsigmaKa[4]; + float tmpTofNsigmaPr[4]; + float tmpTofNsigmaMu[4]; + + float nSigmaEl[4]; + float nSigmaPi[4]; + float nSigmaPr[4]; + float nSigmaKa[4]; + float nSigmaMu[4]; + // float chi2TPC[4]; + // float chi2ITS[4]; + float chi2TOF[4] = {-1., -1., -1., -1.}; + // float nclTPCfind[4]; + int nclTPCcrossedRows[4]; + // double trkTime[4]; + // float trkTimeRes[4]; + float trkTofSignal[4]; + + for (const auto& trk : PVContributors) { + + px[counterTmp] = trk.px(); + py[counterTmp] = trk.py(); + pz[counterTmp] = trk.pz(); + // sign[counterTmp] = trk.sign(); + // dcaZ[counterTmp] = trk.dcaZ(); + // dcaXY[counterTmp] = trk.dcaXY(); + + tmpDedx[counterTmp] = trk.tpcSignal(); + nSigmaEl[counterTmp] = trk.tpcNSigmaEl(); + nSigmaPi[counterTmp] = trk.tpcNSigmaPi(); + nSigmaPr[counterTmp] = trk.tpcNSigmaPr(); + nSigmaKa[counterTmp] = trk.tpcNSigmaKa(); + nSigmaMu[counterTmp] = trk.tpcNSigmaMu(); + + trkTofSignal[counterTmp] = trk.beta(); + tmpTofNsigmaEl[counterTmp] = trk.tofNSigmaEl(); + tmpTofNsigmaPi[counterTmp] = trk.tofNSigmaPi(); + tmpTofNsigmaKa[counterTmp] = trk.tofNSigmaKa(); + tmpTofNsigmaPr[counterTmp] = trk.tofNSigmaPr(); + tmpTofNsigmaMu[counterTmp] = trk.tofNSigmaMu(); + + // chi2TPC[counterTmp] = trk.tpcChi2NCl(); + // chi2ITS[counterTmp] = trk.itsChi2NCl(); + if (trk.hasTOF()) + chi2TOF[counterTmp] = trk.tofChi2(); + // nclTPCfind[counterTmp] = trk.tpcNClsFindable(); + nclTPCcrossedRows[counterTmp] = trk.tpcNClsCrossedRows(); + + // trkTime[counterTmp] = trk.trackTime(); + // trkTimeRes[counterTmp] = trk.trackTimeRes(); + counterTmp++; + } + + tauFourTracks(dgcand.runNumber(), + dgcand.globalBC(), // is it necessary + dgtracks.size(), + dgcand.numContrib(), + // dgcand.posX(), dgcand.posY(), + dgcand.posZ(), + dgcand.flags(), + dgcand.occupancyInTime(), + dgcand.hadronicRate(), // is it necessary + energyZNA, energyZNC, + qtot, + dgcand.trs(), dgcand.trofs(), dgcand.hmpr(), // to test it + // dgcand.tfb(), dgcand.itsROFb(), dgcand.sbp(), dgcand.zVtxFT0vPV(), dgcand.vtxITSTPC(), + dgcand.totalFT0AmplitudeA(), dgcand.totalFT0AmplitudeC(), dgcand.totalFV0AmplitudeA(), + // dgcand.timeFT0A(), dgcand.timeFT0C(), dgcand.timeFV0A(), + px, py, pz, // sign, + // dcaXY, dcaZ, + nclTPCcrossedRows, + tmpDedx, nSigmaEl, nSigmaPi, nSigmaKa, nSigmaPr, nSigmaMu, + trkTofSignal, tmpTofNsigmaEl, tmpTofNsigmaPi, tmpTofNsigmaKa, tmpTofNsigmaPr, tmpTofNsigmaMu, + chi2TOF); + } // end of skim process + + PROCESS_SWITCH(TauTau13topo, processDataSG, "Run over SG Producer tables in reco level (reconstructed data or MC)", true); + PROCESS_SWITCH(TauTau13topo, processSimpleMCSG, "Run over SG Producer tables in true level (MC true only)", false); + PROCESS_SWITCH(TauTau13topo, processEfficiencyMCSG, "Run over SG Producer tables in true and reco level (MC true and reconstructed)", false); + PROCESS_SWITCH(TauTau13topo, processDoSkim, "Run over SG Producer tables to produce skimmed data", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ adaptAnalysisTask(cfgc, TaskName{"TauTau13topo"})}; + // adaptAnalysisTask(cfgc)}; } diff --git a/PWGUD/Tasks/upcVetoAnalysis.cxx b/PWGUD/Tasks/upcVetoAnalysis.cxx index f78883e6303..45b3844ed51 100644 --- a/PWGUD/Tasks/upcVetoAnalysis.cxx +++ b/PWGUD/Tasks/upcVetoAnalysis.cxx @@ -8,7 +8,12 @@ // 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. - +#include +#include +#include +#include +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -23,6 +28,8 @@ using namespace o2::framework; using namespace o2::framework::expressions; struct UpcVetoAnalysis { + bool fIsCreated = false; + // amplitude axis int fNbAmp = 101; double fMinAmp = 0.; @@ -105,17 +112,15 @@ struct UpcVetoAnalysis { fRun = bc.runNumber(); o2::ccdb::CcdbApi ccdb_api; ccdb_api.init("http://alice-ccdb.cern.ch"); - std::map metadata; - std::map headers = ccdb_api.retrieveHeaders(Form("RCT/Info/RunInformation/%i", fRun), - metadata, -1); - - fTsSOR = std::atol(headers["SOR"].c_str()); - fTsEOR = std::atol(headers["EOR"].c_str()); + auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdb_api, fRun); + fTsSOR = soreor.first; + fTsEOR = soreor.second; LOGP(info, "fTsSOR={}, fTsEOR={}", fTsSOR, fTsEOR); - auto grplhcif = ccdb_api.retrieveFromTFileAny("GLO/Config/GRPLHCIF", metadata, - fTsSOR); + std::map metadata; + auto grplhcif = ccdb_api.retrieveFromTFileAny("GLO/Config/GRPLHCIF", metadata, fTsSOR); bcPatternB = grplhcif->getBunchFilling().getBCPattern(); + fNBcsB = 0; for (auto i = 0; i < o2::constants::lhc::LHCMaxBunches; ++i) { if (bcPatternB[i]) @@ -154,7 +159,8 @@ struct UpcVetoAnalysis { int nZdcs = zdcs.size(); const o2::aod::BCs::iterator& fbc = bcs.begin(); - if (fbc.runNumber() != fRun) { + if (fbc.runNumber() != fRun && !fIsCreated) { + fIsCreated = true; getBcInfo(fbc); for (auto i = 0; i < o2::constants::lhc::LHCMaxBunches; ++i) { @@ -375,12 +381,12 @@ struct UpcVetoAnalysis { for (auto r = 0; r <= 10; ++r) { auto maxAmpV0A = -999.f; auto maxAmpT0A = -999.f; - auto s = gbc - r; - auto e = gbc + r; + int64_t s = gbc - r; + int64_t e = gbc + r; auto lower = std::lower_bound(gbcs.begin(), gbcs.end(), s); if (lower != gbcs.end()) { auto idx = std::distance(gbcs.begin(), lower); - while (gbcs[idx] >= s && gbcs[idx] <= e && idx < gbcs.size()) { + while (gbcs[idx] >= s && gbcs[idx] <= e && idx < std::ssize(gbcs)) { auto aV0A = vBcIdsWithV0A[idx]; auto aT0A = vBcIdsWithT0A[idx]; if (aV0A > maxAmpV0A) diff --git a/Scripts/find_dependencies.py b/Scripts/find_dependencies.py index 5a4c152ef23..87e07897aff 100755 --- a/Scripts/find_dependencies.py +++ b/Scripts/find_dependencies.py @@ -72,7 +72,7 @@ def load_workflows_from_json(): # Get the workflow name from the JSON file name workflow = os.path.basename(file_json).split(".")[0] try: - with open(file_json, "r") as j: + with open(file_json, "r", encoding="utf8", errors="ignore") as j: specs_wf = json.load(j) db_wf[workflow] = specs_wf["workflow"] except FileNotFoundError: @@ -81,6 +81,13 @@ def load_workflows_from_json(): return db_wf +def format_table_name(description: str, subspec: int): + """Format table description name, including potential versions.""" + if not subspec: + return description + return f"{description}_{subspec:03d}" + + def get_devices(specs_wf: dict): """Get the list of devices of a given workflow loaded from a JSON file.""" return [d["name"] for d in specs_wf] @@ -93,7 +100,9 @@ def get_inputs(specs_wf: dict, device=""): for dev in specs_wf: if device and dev["name"] != device: continue - list_inputs += [i["description"] for i in dev["inputs"] if i["origin"] == "AOD"] + list_inputs += [ + format_table_name(i["description"], i["subspec"]) for i in dev["inputs"] if i["origin"] == "AOD" + ] return list(dict.fromkeys(list_inputs)) # Remove duplicities @@ -105,7 +114,9 @@ def get_outputs(specs_wf: dict, device=""): for dev in specs_wf: if device and dev["name"] != device: continue - list_outputs += [i["description"] for i in dev["outputs"] if i["origin"] == "AOD"] + list_outputs += [ + format_table_name(i["description"], i["subspec"]) for i in dev["outputs"] if i["origin"] == "AOD" + ] return list(dict.fromkeys(list_outputs)) # Remove duplicities @@ -131,7 +142,7 @@ def print_wf(dic_wf: dict, wf: str): print_wf(dic_wf, wf) -def get_table_producers(table: str, dic_wf_all: dict, case_sensitive=False): +def get_table_producers(table: str, dic_wf_all: dict, case_sensitive=False, reverse=False): """Find all workflows that have this table as output.""" list_producers = [] if not case_sensitive: @@ -140,7 +151,7 @@ def get_table_producers(table: str, dic_wf_all: dict, case_sensitive=False): for wf, dic_wf in dic_wf_all.items(): # Loop over devices for dev in dic_wf: - outputs = [o if case_sensitive else o.lower() for o in dic_wf[dev]["outputs"]] + outputs = [o if case_sensitive else o.lower() for o in dic_wf[dev]["inputs" if reverse else "outputs"]] if table in outputs: list_producers.append(wf) return list(dict.fromkeys(list_producers)) # Remove duplicities @@ -168,12 +179,7 @@ def get_workflow_inputs(wf: str, dic_wf_all: dict): def get_tree_for_workflow( - wf: str, - dic_wf_all: dict, - dic_wf_tree=None, - case_sensitive=False, - level=0, - levels_max=0, + wf: str, dic_wf_all: dict, dic_wf_tree=None, case_sensitive=False, level=0, levels_max=0, reverse=False ): """Get the dependency tree of tables and workflows needed to run this workflow.""" # print(level, levels_max) @@ -183,40 +189,47 @@ def get_tree_for_workflow( msg_fatal(f"Workflow {wf} not found") if wf not in dic_wf_tree: dic_wf_tree[wf] = dic_wf_all[wf] - inputs = get_workflow_inputs(wf, dic_wf_all) + if reverse: + inputs = get_workflow_outputs(wf, dic_wf_all) + symbol_direction = "->" + else: + inputs = get_workflow_inputs(wf, dic_wf_all) + symbol_direction = "<-" if inputs: - print(f"{level * ' '}{wf} <- {inputs}") + print(f"{level * ' '}{wf} {symbol_direction} {inputs}") if levels_max < 0 or level < levels_max: for tab in inputs: - producers = get_table_producers(tab, dic_wf_all, case_sensitive) + producers = get_table_producers(tab, dic_wf_all, case_sensitive, reverse) if producers: - print(f"{level * ' ' + ' '}{tab} <- {producers}") + print(f"{level * ' ' + ' '}{tab} {symbol_direction} {producers}") for p in producers: if p not in dic_wf_tree: # avoid infinite recursion get_tree_for_workflow( - p, - dic_wf_all, - dic_wf_tree, - case_sensitive, - level + 1, - levels_max, + p, dic_wf_all, dic_wf_tree, case_sensitive, level + 1, levels_max, reverse ) return dic_wf_tree -def get_tree_for_table(tab: str, dic_wf_all: dict, dic_wf_tree=None, case_sensitive=False, levels_max=0): +def get_tree_for_table(tab: str, dic_wf_all: dict, dic_wf_tree=None, case_sensitive=False, levels_max=0, reverse=False): """Get the dependency tree of tables and workflows needed to produce this table.""" if dic_wf_tree is None: dic_wf_tree = {} - producers = get_table_producers(tab, dic_wf_all, case_sensitive) + producers = get_table_producers(tab, dic_wf_all, case_sensitive, reverse) + symbol_direction = "<-" + if reverse: + symbol_direction = "->" if producers: - print(f"{tab} <- {producers}") - if levels_max != 0: # Search for more dependencies only if needed. + print(f"{tab} {symbol_direction} {producers}") + if levels_max == 0: # Add producers in the dependency dictionary. + for p in producers: + if p not in dic_wf_tree: + dic_wf_tree[p] = dic_wf_all[p] + else: # Search for more dependencies if needed. print("\nWorkflow dependency tree:\n") for p in producers: - get_tree_for_workflow(p, dic_wf_all, dic_wf_tree, case_sensitive, 0, levels_max) + get_tree_for_workflow(p, dic_wf_all, dic_wf_tree, case_sensitive, 0, levels_max, reverse) else: - print("No producers found") + print(f'No {"consumers" if reverse else "producers"} found') return dic_wf_tree @@ -225,8 +238,22 @@ def main(): parser = argparse.ArgumentParser( description="Find dependencies required to produce a given table or to run a given workflow." ) - parser.add_argument("-t", dest="table", type=str, nargs="+", help="table(s)") - parser.add_argument("-w", dest="workflow", type=str, nargs="+", help="workflow(s)") + parser.add_argument( + "-t", dest="table", type=str, nargs="+", help="table(s) for normal (backward) search (i.e. find producers)" + ) + parser.add_argument( + "-w", dest="workflow", type=str, nargs="+", help="workflow(s) for normal (backward) search (i.e. find inputs)" + ) + parser.add_argument( + "-T", dest="table_rev", type=str, nargs="+", help="table(s) for reverse (forward) search (i.e. find consumers)" + ) + parser.add_argument( + "-W", + dest="workflow_rev", + type=str, + nargs="+", + help="workflow(s) for reverse (forward) search (i.e. find outputs)", + ) parser.add_argument( "-c", dest="case", @@ -255,10 +282,12 @@ def main(): help="maximum number of workflow tree levels (default = 0, include all if < 0)", ) args = parser.parse_args() - if not (args.table or args.workflow): + if not (args.table or args.workflow or args.table_rev or args.workflow_rev): parser.error("Provide table(s) and/or workflow(s)") tables = args.table workflows = args.workflow + tables_rev = args.table_rev + workflows_rev = args.workflow_rev case_sensitive = args.case graph_suffix = args.suffix list_exclude = args.exclude @@ -291,27 +320,29 @@ def main(): dic_deps = {} # Find table dependencies - if tables: - for table in tables: - print(f"\nTable: {table}\n") - if not table: - msg_fatal("Bad table") - # producers = get_table_producers(table, dic_wf_all_simple, case_sensitive) - # if not producers: - # print("No producers found") - # return - # print(producers) - # print_workflows(dic_wf_all_simple, producers) - get_tree_for_table(table, dic_wf_all_simple, dic_deps, case_sensitive, n_levels) + for t, reverse in zip((tables, tables_rev), (False, True)): + if t: + for table in t: + print(f"\nTable: {table}\n") + if not table: + msg_fatal("Bad table") + # producers = get_table_producers(table, dic_wf_all_simple, case_sensitive) + # if not producers: + # print("No producers found") + # return + # print(producers) + # print_workflows(dic_wf_all_simple, producers) + get_tree_for_table(table, dic_wf_all_simple, dic_deps, case_sensitive, n_levels, reverse) # Find workflow dependencies - if workflows: - for workflow in workflows: - print(f"\nWorkflow: {workflow}\n") - if not workflow: - msg_fatal("Bad workflow") - # print_workflows(dic_wf_all_simple, [workflow]) - get_tree_for_workflow(workflow, dic_wf_all_simple, dic_deps, case_sensitive, 0, n_levels) + for w, reverse in zip((workflows, workflows_rev), (False, True)): + if w: + for workflow in w: + print(f"\nWorkflow: {workflow}\n") + if not workflow: + msg_fatal("Bad workflow") + # print_workflows(dic_wf_all_simple, [workflow]) + get_tree_for_workflow(workflow, dic_wf_all_simple, dic_deps, case_sensitive, 0, n_levels, reverse) # Print the tree dictionary with dependencies # print("\nTree\n") @@ -319,7 +350,12 @@ def main(): # Produce topology graph. if graph_suffix and dic_deps: - basename = "_".join((tables if tables else []) + (workflows if workflows else [])) + names_all = [] + for names in (tables, tables_rev, workflows, workflows_rev): + if names: + names_all += names + names_all = list(dict.fromkeys(names_all)) # Remove duplicities + basename = "_".join(names_all) # Set a short file name when the full name would be longer than 255 characters. if len(basename) > 251: basename = "o2_dependencies_" + hashlib.sha1(basename.encode(), usedforsecurity=False).hexdigest() @@ -364,7 +400,7 @@ def main(): dot += dot_workflows + dot_tables + dot_deps dot += "}\n" try: - with open(path_file_dot, "w") as file_dot: + with open(path_file_dot, "w", encoding="utf-8") as file_dot: file_dot.write(dot) except IOError: msg_fatal(f"Failed to open file {path_file_dot}") diff --git a/Scripts/o2_linter.py b/Scripts/o2_linter.py new file mode 100644 index 00000000000..fbc4bacc2cd --- /dev/null +++ b/Scripts/o2_linter.py @@ -0,0 +1,1812 @@ +#!/usr/bin/env python3 + +# 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 O2 linter (Find O2-specific issues in O2 code) +@author Vít Kučera , Inha University +@date 2024-07-14 +""" + +import argparse +import os +import re +import sys +from enum import Enum +from pathlib import Path +from typing import Union + +github_mode = False # GitHub mode +prefix_disable = "o2-linter: disable=" # prefix for disabling tests +file_config = "o2linter_config" # name of the configuration file (applied per directory) +# If this file exists in the path of the tested file, +# failures of tests listed in this file will not make the linter fail. + + +# issue severity levels +class Severity(Enum): + WARNING = 1 + ERROR = 2 + DEFAULT = ERROR + + +# strings for error messages +message_levels = { + Severity.WARNING: "warning", + Severity.ERROR: "error", +} + + +class Reference(Enum): + O2 = 1 + ISO_CPP = 2 + LLVM = 3 + GOOGLE = 4 + LINTER = 5 + PWG_HF = 6 + PY_ZEN = 7 + PY_PEP8 = 8 + + +references_list: "list[tuple[Reference, str, str]]" = [ + (Reference.O2, "ALICE O2 Coding Guidelines", "https://github.com/AliceO2Group/CodingGuidelines"), + (Reference.ISO_CPP, "C++ Core Guidelines", "https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines"), + (Reference.LLVM, "LLVM Coding Standards", "https://llvm.org/docs/CodingStandards.html"), + (Reference.GOOGLE, "Google C++ Style Guide", "https://google.github.io/styleguide/cppguide.html"), + ( + Reference.LINTER, + "Proposal of the O2 linter", + "https://indico.cern.ch/event/1482467/#29-development-of-the-o2-linte", + ), + ( + Reference.PWG_HF, + "PWG-HF guidelines", + "https://aliceo2group.github.io/analysis-framework/docs/advanced-specifics/pwghf.html#contribute", + ), + (Reference.PY_ZEN, "The Zen of Python", "https://peps.python.org/pep-0020/"), + (Reference.PY_PEP8, "Style Guide for Python Code", "https://peps.python.org/pep-0008/"), +] + +references: "dict[Reference, dict]" = {name: {"title": title, "url": url} for name, title, url in references_list} + + +def is_camel_case(name: str) -> bool: + """forExample or ForExample""" + return "_" not in name and "-" not in name and " " not in name + + +def is_upper_camel_case(name: str) -> bool: + """ForExample""" + if not name: + return False + return name[0].isupper() and is_camel_case(name) + + +def is_lower_camel_case(name: str) -> bool: + """forExample""" + if not name: + return False + return name[0].islower() and is_camel_case(name) + + +def is_kebab_case(name: str) -> bool: + """for-example""" + if not name: + return False + return name.islower() and "_" not in name and " " not in name + + +def is_snake_case(name: str) -> bool: + """for_example""" + if not name: + return False + return name.islower() and "-" not in name and " " not in name + + +def is_screaming_snake_case(name: str) -> bool: + """FOR_EXAMPLE""" + if not name: + return False + return name.isupper() and "-" not in name and " " not in name + + +def kebab_case_to_camel_case_u(line: str) -> str: + """Convert kebab-case string to UpperCamelCase string.""" + return "".join([w.title() if w[0].isnumeric() else w.capitalize() for w in line.split("-")]) + + +def kebab_case_to_camel_case_l(line: str) -> str: + """Convert kebab-case string to lowerCamelCase string.""" + new_line = kebab_case_to_camel_case_u(line) + return f"{new_line[0].lower()}{new_line[1:]}" # start with lowercase letter + + +def camel_case_to_kebab_case(line: str) -> str: + """Convert CamelCase string to kebab-case string. + As done in O2/Framework/Foundation/include/Framework/TypeIdHelpers.h:type_to_task_name + """ + if not line.strip(): + return line + new_line = [] + for i, c in enumerate(line): + if i > 0 and c.isupper() and line[i - 1] != "-": + new_line.append("-") + new_line.append(c.lower()) + return "".join(new_line) + + +def is_comment_cpp(line: str) -> bool: + """Test whether a line is a C++ comment.""" + return line.strip().startswith(("//", "/*")) + + +def remove_comment_cpp(line: str) -> str: + """Remove C++ comments from the end of a line.""" + for keyword in ("//", "/*"): + if keyword in line: + line = line[: line.index(keyword)] + return line.strip() + + +def block_ranges(line: str, char_open: str, char_close: str) -> "list[list[int]]": + """Get list of index ranges of longest blocks opened with char_open and closed with char_close.""" + # print(f"Looking for {char_open}{char_close} blocks in \"{line}\".") + # print(line) + list_ranges: list[list[int]] = [] + if not all((line, len(char_open) == 1, len(char_close) == 1)): + return list_ranges + + def direction(char: str) -> int: + if char == char_open: + return 1 + if char == char_close: + return -1 + return 0 + + list_levels = [] # list of block levels (net number of opened blocks) + level_sum = 0 # current block level (sum of previous directions) + for char in line: + list_levels.append(level_sum := level_sum + direction(char)) + level_min = min(list_levels) # minimum level (!= 0 if line has opened blocks) + # Look for openings (level_min + 1) and closings (level_min). + index_start = -1 + is_opened = False + # print(list_levels) + for i, level in enumerate(list_levels): + if not is_opened and level > level_min: + is_opened = True + index_start = i + # print(f"Opening at {i}") + elif is_opened and (level == level_min or i == len(list_levels) - 1): + is_opened = False + list_ranges.append([index_start, i]) + # print(f"Closing at {i}") + # print(f"block_ranges: Found {len(list_ranges)} blocks: {list_ranges}.") + if is_opened: + print("block_ranges: Block left opened.") + return list_ranges + + +def get_tolerated_tests(path: str) -> "list[str]": + """Get the list of tolerated tests. + + Looks for the configuration file. + Starts in the test file directory and iterates through parents. + """ + tests: list[str] = [] + for directory in Path(path).resolve().parents: + path_tests = directory / file_config + if path_tests.is_file(): + with path_tests.open() as content: + tests = [line.strip() for line in content.readlines() if line.strip()] + print(f"{path}:0: info: Tolerating tests from {path_tests}. {tests}") + break + return tests + + +class TestSpec: + """Prototype of a test class""" + + name: str = "test-template" # short name of the test + message: str = "Test failed" # error message + rationale: str = "Rationale missing" # brief rationale explanation + references: "list[Reference]" = [] # list of references relevant for this rule + severity_default: Severity = Severity.DEFAULT + severity_current: Severity = Severity.DEFAULT + suffixes: "list[str]" = [] # suffixes of files to test + per_line: bool = True # Test lines separately one by one. + tolerated: bool = False # flag for tolerating issues + n_issues: int = 0 # issue counter + n_disabled: int = 0 # counter of disabled issues + n_tolerated: int = 0 # counter of tolerated issues + + def file_matches(self, path: str) -> bool: + """Test whether the path matches the pattern for files to test.""" + return path.endswith(tuple(self.suffixes)) if self.suffixes else True + + def is_disabled(self, line: str, prefix_comment="//") -> bool: + """Detect whether the test is explicitly disabled.""" + for prefix in [prefix_comment, prefix_disable]: + if prefix not in line: + return False + line = line[(line.index(prefix) + len(prefix)) :] # Strip away part before prefix. + if self.name in line: + self.n_disabled += 1 + # Look for a comment with a reason for disabling. + if re.search(r" \([\w\s]{3,}\)", line): + return True + return False + + def print_error(self, path: str, line: Union[int, None], message: str): + """Format and print error message.""" + # return # Use to suppress error messages. + line = line or 0 + # terminal format + print(f"{path}:{line}: {message_levels[self.severity_current]}: {message} [{self.name}]") + if github_mode and not self.tolerated: # Annotate only not tolerated issues. + # GitHub annotation format + print(f"::{message_levels[self.severity_current]} file={path},line={line},title=[{self.name}]::{message}") + + def test_line(self, line: str) -> bool: + """Test a line.""" + raise NotImplementedError() + + def test_file(self, path: str, content) -> bool: + """Test a file in a way that cannot be done line by line.""" + raise NotImplementedError() + + def run(self, path: str, content: "list[str]") -> bool: + """Run the test.""" + # print(content) + passed = True + self.severity_current = Severity.WARNING if self.tolerated else self.severity_default + if not self.file_matches(path): + return passed + # print(f"Running test {self.name} for {path} with {len(content)} lines") + if self.per_line: + for i, line in enumerate(content): + if not isinstance(self, TestUsingDirective): # Keep the indentation if needed. + line = line.strip() + if not line: + continue + # print(i + 1, line) + if self.is_disabled(line): + continue + if not self.test_line(line): + passed = False + if self.tolerated: + self.n_tolerated += 1 + else: + self.n_issues += 1 + self.print_error(path, i + 1, self.message) + else: + passed = self.test_file(path, content) + if not passed: + if self.tolerated: + self.n_tolerated += 1 + else: + self.n_issues += 1 + self.print_error(path, None, self.message) + return passed or self.tolerated + + +########################## +# Implementations of tests +########################## + +# Bad practice + + +class TestIoStream(TestSpec): + """Detect included iostream.""" + + name = "include-iostream" + message = "Do not include iostream. Use O2 logging instead." + rationale = "Performance. Avoid injection of static constructors. Consistent logging." + references = [Reference.LLVM, Reference.LINTER] + suffixes = [".h", ".cxx"] + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + return not line.startswith("#include ") + + +class TestUsingStd(TestSpec): + """Detect importing names from the std namespace.""" + + name = "import-std-name" + message = "Do not import names from the std namespace in headers." + rationale = "Code safety. Avoid namespace pollution with common names." + references = [Reference.LINTER] + suffixes = [".h"] + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + return not line.startswith("using std::") + + +class TestUsingDirective(TestSpec): + """Detect using directives in headers.""" + + name = "using-directive" + message = "Do not put using directives at global scope in headers." + rationale = "Code safety. Avoid namespace pollution." + references = [Reference.O2, Reference.ISO_CPP, Reference.LLVM, Reference.GOOGLE, Reference.LINTER] + suffixes = [".h"] + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + return not line.startswith("using namespace") + + +class TestStdPrefix(TestSpec): + """Detect missing std:: prefix for common names from the std namespace.""" + + name = "std-prefix" + message = "Use std:: prefix for names from the std namespace." + rationale = "Code clarity, safety and portability. Avoid ambiguity (e.g. abs)." + references = [Reference.LLVM, Reference.LINTER] + suffixes = [".h", ".cxx", ".C"] + prefix_bad = r"[^\w:\.\"]" + patterns = [ + r"vector<", + r"array[<\{\(]", + r"f?abs\(", + r"sqrt\(", + r"pow\(", + r"min\(", + r"max\(", + r"log(2|10)?\(", + r"exp\(", + r"a?(sin|cos|tan)h?\(", + r"atan2\(", + r"erfc?\(", + r"hypot\(", + ] + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + line = remove_comment_cpp(line) + for pattern in self.patterns: + iterators = re.finditer(rf"{self.prefix_bad}{pattern}", line) + matches = [(it.start(), it.group()) for it in iterators] + if not matches: + continue + if '"' not in line: # Found a match which cannot be inside a string. + return False + # Ignore matches inside strings. + for match in matches: + n_quotes_before = line.count('"', 0, match[0]) # Count quotation marks before the match. + if not n_quotes_before % 2: # If even, we are not inside a string and this match is valid. + return False + return True + + +class TestRootEntity(TestSpec): + """Detect unnecessary use of ROOT entities.""" + + name = "root/entity" + message = "Replace ROOT entities with equivalents from standard C++ or from O2." + rationale = "Code simplicity and maintainability. O2 is not a ROOT code." + references = [Reference.ISO_CPP, Reference.LINTER, Reference.PY_ZEN] + suffixes = [".h", ".cxx"] + + def file_matches(self, path: str) -> bool: + return super().file_matches(path) and "Macros/" not in path + + def test_line(self, line: str) -> bool: + pattern = ( + r"TMath::(Abs|Sqrt|Power|Min|Max|Log(2|10)?|Exp|A?(Sin|Cos|Tan)H?|ATan2|Erfc?|Hypot)\(|" + r"(U?(Int|Char|Short)|Double(32)?|Float(16)?|U?Long(64)?|Bool)_t" + ) + if is_comment_cpp(line): + return True + line = remove_comment_cpp(line) + return re.search(pattern, line) is None + + +class TestRootLorentzVector(TestSpec): + """Detect use of TLorentzVector.""" + + name = "root/lorentz-vector" + message = ( + "Do not use the TLorentzVector legacy class. " + "Use std::array with RecoDecay methods or the ROOT::Math::LorentzVector template instead." + ) + rationale = "Performance. Use up-to-date tools." + references = [] + suffixes = [".h", ".cxx"] + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + line = remove_comment_cpp(line) + return "TLorentzVector" not in line + + +class TestPi(TestSpec): + """Detect use of external pi.""" + + name = "external-pi" + message = "Use the PI constant (and its multiples and fractions) defined in o2::constants::math." + rationale = "Code maintainability." + references = [Reference.LINTER, Reference.PY_ZEN] + suffixes = [".h", ".cxx"] + + def file_matches(self, path: str) -> bool: + return super().file_matches(path) and "Macros/" not in path + + def test_line(self, line: str) -> bool: + pattern = r"[^\w]M_PI|TMath::(Two)?Pi" + if is_comment_cpp(line): + return True + line = remove_comment_cpp(line) + return re.search(pattern, line) is None + + +class TestTwoPiAddSubtract(TestSpec): + """Detect adding/subtracting of 2 pi.""" + + name = "two-pi-add-subtract" + message = "Use RecoDecay::constrainAngle to restrict angle to a given range." + rationale = "Code maintainability and safety. Use existing tools." + references = [Reference.ISO_CPP, Reference.LINTER, Reference.PY_ZEN] + suffixes = [".h", ".cxx"] + + def test_line(self, line: str) -> bool: + pattern_two_pi = ( + r"(2(\.0*f?)? \* (M_PI|TMath::Pi\(\)|(((o2::)?constants::)?math::)?PI)|" + r"(((o2::)?constants::)?math::)?TwoPI|TMath::TwoPi\(\))" + ) + pattern = rf"[\+-]=? {pattern_two_pi}" + if is_comment_cpp(line): + return True + line = remove_comment_cpp(line) + return re.search(pattern, line) is None + + +class TestPiMultipleFraction(TestSpec): + """Detect multiples/fractions of pi for existing equivalent constants.""" + + name = "pi-multiple-fraction" + message = "Use multiples/fractions of PI defined in o2::constants::math." + rationale = "Code maintainability." + references = [Reference.LINTER, Reference.PY_ZEN] + suffixes = [".h", ".cxx"] + + def test_line(self, line: str) -> bool: + pattern_pi = r"(M_PI|TMath::(Two)?Pi\(\)|(((o2::)?constants::)?math::)?(Two)?PI)" + pattern_multiple = r"(2(\.0*f?)?|0\.2?5f?) \* " # * 2, 0.25, 0.5 + pattern_fraction = r" / ((2|3|4)([ ,;\)]|\.0*f?))" # / 2, 3, 4 + pattern = rf"{pattern_multiple}{pattern_pi}[^\w]|{pattern_pi}{pattern_fraction}" + if is_comment_cpp(line): + return True + line = remove_comment_cpp(line) + return re.search(pattern, line) is None + + +class TestPdgDatabase(TestSpec): + """Detect use of TDatabasePDG.""" + + name = "pdg/database" + message = ( + "Do not use TDatabasePDG directly. " + "Use o2::constants::physics::Mass... or Service instead." + ) + rationale = "Performance." + references = [Reference.LINTER] + suffixes = [".h", ".cxx"] + + def file_matches(self, path: str) -> bool: + return super().file_matches(path) and "Macros/" not in path + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + line = remove_comment_cpp(line) + return "TDatabasePDG" not in line + + +class TestPdgExplicitCode(TestSpec): + """Detect hard-coded PDG codes.""" + + name = "pdg/explicit-code" + message = "Avoid hard-coded PDG codes. Use named values from PDG_t or o2::constants::physics::Pdg instead." + rationale = "Code comprehensibility, readability, maintainability and safety." + references = [Reference.O2, Reference.ISO_CPP, Reference.LINTER] + suffixes = [".h", ".cxx", ".C"] + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + line = remove_comment_cpp(line) + if re.search(r"->(GetParticle|Mass)\([+-]?[0-9]+\)", line): + return False + match = re.search(r"[Pp][Dd][Gg].* !?={1,2} [+-]?([0-9]+)", line) + if match: + code = match.group(1) + if code not in ("0", "1", "999"): + return False + return True + + +class TestPdgExplicitMass(TestSpec): + """Detect hard-coded particle masses.""" + + name = "pdg/explicit-mass" + message = "Avoid hard-coded particle masses. Use o2::constants::physics::Mass... instead." + rationale = "Code comprehensibility, readability, maintainability and safety." + references = [Reference.O2, Reference.ISO_CPP, Reference.LINTER] + suffixes = [".h", ".cxx"] + masses: "list[str]" = [] # list of mass values to detect + + def __init__(self) -> None: + super().__init__() + + # List of masses of commonly used particles + self.masses.append(r"0\.000511") # e + self.masses.append(r"0\.105") # μ + self.masses.append(r"0\.139") # π+ + self.masses.append(r"0\.493") # K+ + self.masses.append(r"0\.497") # K0 + self.masses.append(r"0\.938") # p + self.masses.append(r"0\.939") # n + self.masses.append(r"1\.115") # Λ + self.masses.append(r"1\.864") # D0 + self.masses.append(r"2\.286") # Λc + self.masses.append(r"3\.096") # J/ψ + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + line = remove_comment_cpp(line) + iterators = re.finditer(rf"(^|\D)({'|'.join(self.masses)})", line) + matches = [(it.start(), it.group(2)) for it in iterators] + if not matches: + return True + if '"' not in line: # Found a match which cannot be inside a string. + return False + # Ignore matches inside strings. + for match in matches: + n_quotes_before = line.count('"', 0, match[0]) # Count quotation marks before the match. + if not n_quotes_before % 2: # If even, we are not inside a string and this match is valid. + return False + return True + + +class TestPdgKnownMass(TestSpec): + """Detect unnecessary call of Mass() for a known PDG code.""" + + name = "pdg/known-mass" + message = "Use o2::constants::physics::Mass... instead of calling a database method for a known PDG code." + rationale = "Performance." + references = [Reference.LINTER] + suffixes = [".h", ".cxx", ".C"] + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + line = remove_comment_cpp(line) + pattern_pdg_code = r"[+-]?(k[A-Z][a-zA-Z0-9]*|[0-9]+)" + if re.search(rf"->GetParticle\({pattern_pdg_code}\)->Mass\(\)", line): + return False + return not re.search(rf"->Mass\({pattern_pdg_code}\)", line) + + +class TestLogging(TestSpec): + """Detect non-O2 logging.""" + + name = "logging" + message = "Use O2 logging (LOG, LOGF, LOGP)." + rationale = "Logs easy to read and process." + references = [Reference.LINTER] + suffixes = [".h", ".cxx"] + + def file_matches(self, path: str) -> bool: + return super().file_matches(path) and "Macros/" not in path + + def test_line(self, line: str) -> bool: + pattern = r"^([Pp]rintf\(|(std::)?cout <)" + if is_comment_cpp(line): + return True + line = remove_comment_cpp(line) + return re.search(pattern, line) is None + + +class TestConstRefInForLoop(TestSpec): + """Test const refs in range-based for loops.""" + + name = "const-ref-in-for-loop" + message = "Use constant references for non-modified iterators in range-based for loops." + rationale = "Performance, code comprehensibility and safety." + references = [Reference.O2, Reference.ISO_CPP, Reference.LLVM] + suffixes = [".h", ".cxx", ".C"] + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + line = remove_comment_cpp(line) + if not re.match(r"for \(.* :", line): + return True + line = line[: line.index(" :")] # keep only the iterator part + return re.search(r"(\w const|const \w+)& ", line) is not None + + +class TestConstRefInSubscription(TestSpec): + """Test const refs in process function subscriptions. + Test only top-level process functions (called process() or has PROCESS_SWITCH). + """ + + name = "const-ref-in-process" + message = "Use constant references for table subscriptions in process functions." + rationale = "Performance, code comprehensibility and safety." + references = [Reference.O2, Reference.ISO_CPP, Reference.LINTER] + suffixes = [".cxx"] + per_line = False + + def test_file(self, path: str, content) -> bool: + passed = True + n_parens_opened = 0 # number of opened parentheses + arguments = "" # process function arguments + line_process = 0 # line number of the process function + # Find names of all top-level process functions. + names_functions = ["process"] # names of allowed process functions to test + for i, line in enumerate(content): + line = line.strip() + if is_comment_cpp(line): + continue + if not line.startswith("PROCESS_SWITCH"): + continue + words = line.split() + if len(words) < 2: + passed = False + self.print_error( + path, + i + 1, + "Failed to get the process function name. Keep it on the same line as the switch.", + ) + continue + names_functions.append(words[1][:-1]) # Remove the trailing comma. + # self.print_error(path, i + 1, f"Got process function name {words[1][:-1]}.") + # Test process functions. + for i, line in enumerate(content): + line = line.strip() + if is_comment_cpp(line): + continue + if self.is_disabled(line): + continue + if "//" in line: # Remove comment. (Ignore /* to avoid truncating at /*parameter*/.) + line = line[: line.index("//")] + if (match := re.match(r"void (process[\w]*)\(", line)) and match.group(1) in names_functions: + line_process = i + 1 + i_closing = line.rfind(")") + i_start = line.index("(") + 1 + i_end = i_closing if i_closing != -1 else len(line) + arguments = line[i_start:i_end] # get arguments between parentheses + n_parens_opened = line.count("(") - line.count(")") + elif n_parens_opened > 0: + i_closing = line.rfind(")") + i_start = 0 + i_end = i_closing if i_closing != -1 else len(line) + arguments += " " + line[i_start:i_end] # get arguments between parentheses + n_parens_opened += line.count("(") - line.count(")") + if line_process > 0 and n_parens_opened == 0: + # Process arguments. + # Sanitise arguments with spaces between <>. + for start, end in block_ranges(arguments, "<", ">"): + arg = arguments[start : (end + 1)] + # print(f"Found argument \"{arg}\" in [{start}, {end}]") + if ", " in arg: + arguments = arguments.replace(arg, arg.replace(", ", "__")) + # Extract arguments. + words = arguments.split(", ") + # Test each argument. + for arg in words: + if not re.search(r"([\w>] const|const [\w<>:]+)&", arg): + passed = False + self.print_error(path, i + 1, f"Argument {arg} is not const&.") + line_process = 0 + return passed + + +class TestWorkflowOptions(TestSpec): + """Detect usage of workflow options in defineDataProcessing. (Not supported on AliHyperloop.)""" + + name = "o2-workflow-options" + message = ( + "Do not use workflow options to customise workflow topology composition in defineDataProcessing. " + "Use process function switches or metadata instead." + ) + rationale = "Not supported on AliHyperloop." + references = [Reference.LINTER] + suffixes = [".cxx"] + per_line = False + + def test_file(self, path: str, content) -> bool: + is_inside_define = False # Are we inside defineDataProcessing? + for _i, line in enumerate(content): # pylint: disable=unused-variable + if not line.strip(): + continue + if self.is_disabled(line): + continue + if is_comment_cpp(line): + continue + line = remove_comment_cpp(line) + # Wait for defineDataProcessing. + if not is_inside_define: + if not re.match(r"((o2::)?framework::)?WorkflowSpec defineDataProcessing\(", line): + continue + # print(f"{i + 1}: Entering define.") + is_inside_define = True + # Return at the end of defineDataProcessing. + if is_inside_define and line[0] == "}": + # print(f"{i + 1}: Exiting define.") + break + # Detect options. + if ".options()" in line: + return False + return True + + +class TestMagicNumber(TestSpec): + """Detect magic numbers.""" + + name = "magic-number" + message = "Avoid magic numbers in expressions. Assign the value to a clearly named variable or constant." + rationale = "Code comprehensibility, maintainability and safety." + references = [Reference.O2, Reference.ISO_CPP] + suffixes = [".h", ".cxx", ".C"] + pattern_compare = r"([<>]=?|[!=]=)" + pattern_number = r"[\+-]?([\d\.]+)f?" + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + line = remove_comment_cpp(line) + iterators = re.finditer( + rf" {self.pattern_compare} {self.pattern_number}|\W{self.pattern_number} {self.pattern_compare} ", line + ) + matches = [(it.start(), it.group(2), it.group(3)) for it in iterators] + if not matches: + return True + # Ignore matches inside strings. + for match in matches: + n_quotes_before = line.count('"', 0, match[0]) # Count quotation marks before the match. + if n_quotes_before % 2: # If odd, we are inside a string and we should ignore this match. + continue + # We are not inside a string and this match is valid. + for match_n in (match[1], match[2]): + # Accept only 0 or 1 (int or float). + if (match_n is not None) and (re.match(r"[01](\.0?)?$", match_n) is None): + return False + return True + + +# Documentation +# Reference: https://rawgit.com/AliceO2Group/CodingGuidelines/master/comments_guidelines.html + + +class TestDocumentationFile(TestSpec): + """Test mandatory documentation of C++ files.""" + + name = "doc/file" + message = "Provide mandatory file documentation." + rationale = "Code comprehensibility. Collaboration." + references = [Reference.O2, Reference.LINTER] + suffixes = [".h", ".cxx", ".C"] + per_line = False + + def test_file(self, path: str, content) -> bool: + passed = False + doc_items = [] + doc_items.append({"keyword": "file", "pattern": rf"{os.path.basename(path)}$", "found": False}) + doc_items.append({"keyword": "brief", "pattern": r"\w.* \w", "found": False}) # at least two words + doc_items.append({"keyword": "author", "pattern": r"[\w]+", "found": False}) + doc_prefix = "///" + n_lines_copyright = 11 + last_doc_line = n_lines_copyright + + for i, line in enumerate(content): + if i < n_lines_copyright: # Skip copyright lines. + continue + if line.strip() and not line.startswith(doc_prefix): # Stop at the first non-empty non-doc line. + break + if line.startswith(doc_prefix): + last_doc_line = i + 1 + for item in doc_items: + if re.search(rf"^{doc_prefix} [\\@]{item['keyword']} +{item['pattern']}", line): + item["found"] = True + # self.print_error(path, i + 1, f"Found \{item['keyword']}.") + break + if all(item["found"] for item in doc_items): # All items have been found. + passed = True + break + if not passed: + for item in doc_items: + if not item["found"]: + self.print_error( + path, + last_doc_line, + f"Documentation for \\{item['keyword']} is missing, incorrect or misplaced.", + ) + return passed + + +# Naming conventions +# Reference: https://rawgit.com/AliceO2Group/CodingGuidelines/master/naming_formatting.html + +rationale_names = "Code readability, comprehensibility and searchability." +references_names = [Reference.O2, Reference.LINTER] + + +class TestNameFunctionVariable(TestSpec): + """Test names of functions and of most variables. + Might report false positives. + Does not detect multiple variable declarations, i.e. "type name1, name2;" + Does not detect function arguments on the same line as the function declaration. + Does not detect multi-line declarations. + Does not check capitalisation for constexpr because of special rules for constants. See TestNameConstant. + """ + + name = "name/function-variable" + message = "Use lowerCamelCase for names of functions and variables." + rationale = rationale_names + references = references_names + suffixes = [".h", ".cxx", ".C"] + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + # Look for declarations of functions and variables. + + # Strip away irrelevant remainders of the line after the object name. + # For functions, stripping after "(" is enough but this way we also identify many declarations of variables. + for keyword in ("(", "{", ";", " = ", "//", "/*"): + if keyword in line: + line = line[: line.index(keyword)] + + # Check the words. + words = line.split() + + # number of words + if len(words) < 2: + return True + + # First word starts with a letter. + if not words[0][0].isalpha(): + return True + + # Reject false positives with same structure. + if words[0] in ( + "return", + "if", + "else", + "new", + "delete", + "delete[]", + "case", + "typename", + "using", + "typedef", + "enum", + "namespace", + "struct", + "class", + "explicit", + "concept", + "throw", + ): + return True + if len(words) > 2 and words[1] in ("typename", "class", "struct"): + return True + + # Identify the position of the name for cases "name[n + m]". + funval_name = words[-1] # expecting the name in the last word + if ( + funval_name.endswith("]") and "[" not in funval_name + ): # it's an array and we do not have the name before "[" here + opens_brackets = ["[" in w for w in words] + if not any(opens_brackets): # The opening "[" is not on this line. We have to give up. + return True + index_name = opens_brackets.index(True) # the name is in the first element with "[" + funval_name = words[index_name] + words = words[: (index_name + 1)] # Strip away words after the name. + if len(words) < 2: # Check the adjusted number of words. + return True + + # All words before the name start with an alphanumeric character (underscores not allowed). + # Rejects expressions, e.g. * = += << }, but accepts numbers in array declarations. + if not all(w[0].isalnum() for w in words[:-1]): + return True + + # Extract function/variable name. + if "[" in funval_name: # Remove brackets for arrays. + funval_name = funval_name[: funval_name.index("[")] + if "::" in funval_name: # Remove the class prefix for methods. + funval_name = funval_name.split("::")[-1] + + # Check the name candidate. + + # Names of variables and functions are identifiers. + if not funval_name.isidentifier(): # should be same as ^[\w]+$ + return True + + # print(f"{line} -> {funval_name}") + # return True + # The actual test comes here. + if "constexpr" in words[:-1]: + return is_camel_case(funval_name) + return is_lower_camel_case(funval_name) + + +class TestNameMacro(TestSpec): + """Test macro names.""" + + name = "name/macro" + message = "Use SCREAMING_SNAKE_CASE for names of macros. Leading and double underscores are not allowed." + rationale = rationale_names + references = references_names + suffixes = [".h", ".cxx", ".C"] + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + if not line.startswith("#define "): + return True + # Extract macro name. + macro_name = line.split()[1] + if "(" in macro_name: + macro_name = macro_name.split("(")[0] + # The actual test comes here. + if macro_name.startswith("_"): + return False + if "__" in macro_name: + return False + return is_screaming_snake_case(macro_name) + + +class TestNameConstant(TestSpec): + """Test constexpr constant names.""" + + name = "name/constexpr-constant" + message = ( + 'Use UpperCamelCase for names of constexpr constants. Names of special constants may be prefixed with "k".' + ) + rationale = rationale_names + references = references_names + suffixes = [".h", ".cxx", ".C"] + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + line = remove_comment_cpp(line) + words = line.split() + if "constexpr" not in words or "=" not in words: + return True + # Extract constant name. + words = words[: words.index("=")] # keep only words before "=" + constant_name = words[-1] # last word before "=" + if ( + constant_name.endswith("]") and "[" not in constant_name + ): # it's an array and we do not have the name before "[" here + opens_brackets = ["[" in w for w in words] + if not any(opens_brackets): # The opening "[" is not on this line. We have to give up. + return True + constant_name = words[opens_brackets.index(True)] # the name is in the first element with "[" + if "[" in constant_name: # Remove brackets for arrays. + constant_name = constant_name[: constant_name.index("[")] + if "::" in constant_name: # Remove the class prefix for methods. + constant_name = constant_name.split("::")[-1] + if "#" in constant_name: # Remove "#" for strings in macros. + constant_name = constant_name[: constant_name.index("#")] + # The actual test comes here. + if constant_name.startswith("k") and len(constant_name) > 1: # exception for special constants + constant_name = constant_name[1:] # test the name without "k" + return is_upper_camel_case(constant_name) + + +class TestNameColumn(TestSpec): + """Test names of O2 columns.""" + + name = "name/o2-column" + message = "Use UpperCamelCase for names of O2 columns and matching lowerCamelCase names for their getters." + rationale = rationale_names + references = references_names + suffixes = [".h", ".cxx"] + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + if not (match := re.match(r"DECLARE(_[A-Z]+)*_COLUMN(_[A-Z]+)*\(", line)): + return True + # Extract names of the column type and getter. + line = remove_comment_cpp(line) + line = line[len(match.group()) :].strip() # Extract part after "(". + if not (match := re.match(r"([^,]+), ([^,\) ]+)", line)): + print(f'Failed to extract column type and getter from "{line}".') + return False + column_type_name = match.group(1) + column_getter_name = match.group(2) + # print(f"Got \"{column_type_name}\" \"{column_getter_name}\"") + # return True + if column_type_name[0] == "_": # probably a macro variable + return True + if "#" in column_type_name: # Remove "#" for strings in macros. + column_type_name = column_type_name[: column_type_name.index("#")] + if "#" in column_getter_name: # Remove "#" for strings in macros. + column_getter_name = column_getter_name[: column_getter_name.index("#")] + # The actual test comes here. + if not is_upper_camel_case(column_type_name): + return False + if not is_lower_camel_case(column_getter_name): + return False + return f"{column_type_name[0].lower()}{column_type_name[1:]}" == column_getter_name + + +class TestNameTable(TestSpec): + """Test names of O2 tables.""" + + name = "name/o2-table" + message = "Use UpperCamelCase for names of O2 tables." + rationale = rationale_names + references = references_names + suffixes = [".h", ".cxx"] + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + if not (match := re.match(r"DECLARE(_[A-Z]+)*_TABLES?(_[A-Z]+)*\(", line)): + return True + # Extract names of the table type. + line = remove_comment_cpp(line) + line = line[len(match.group()) :].strip() # Extract part after "(". + if not (match := re.match(r"([^,\) ]+)", line)): + print(f'Failed to extract table type from "{line}".') + return False + table_type_name = match.group(1) + # print(f"Got \"{table_type_name}\"") + # return True + # Check for a version suffix. + if match := re.match(r"(.*)_([0-9]{3})", line): + table_type_name = match.group(1) + # table_version = match.group(2) + # print(f"Got versioned table \"{table_type_name}\", version {table_version}") + if table_type_name[0] == "_": # probably a macro variable + return True + if "#" in table_type_name: # Remove "#" for strings in macros. + table_type_name = table_type_name[: table_type_name.index("#")] + # The actual test comes here. + return is_upper_camel_case(table_type_name) + + +class TestNameNamespace(TestSpec): + """Test names of namespaces.""" + + name = "name/namespace" + message = "Use snake_case for names of namespaces. Double underscores are not allowed." + rationale = rationale_names + references = references_names + suffixes = [".h", ".cxx", ".C"] + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + if not line.startswith("namespace "): + return True + # Extract namespace name. + namespace_name = line.split()[1] + if namespace_name == "{": # ignore anonymous namespaces + return True + # The actual test comes here. + if "__" in namespace_name: + return False + return is_snake_case(namespace_name) + + +class TestNameType(TestSpec): + """Test names of defined types.""" + + name = "name/type" + message = "Use UpperCamelCase for names of defined types (including concepts)." + rationale = rationale_names + references = references_names + suffixes = [".h", ".cxx", ".C"] + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + if not (match := re.match(r"(using|concept) (\w+) = ", line)): + return True + # Extract type name. + type_name = match.group(2) + # The actual test comes here. + return is_upper_camel_case(type_name) + + +class TestNameUpperCamelCase(TestSpec): + """Base class for a test of UpperCamelCase names.""" + + keyword = "key" + name = f"name/{keyword}" + message = f"Use UpperCamelCase for names of {keyword}." + rationale = rationale_names + references = references_names + suffixes = [".h", ".cxx", ".C"] + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + if not line.startswith(f"{self.keyword} "): + return True + # Extract object name. + words = line.split() + if not words[1].isalnum(): # "struct : ...", "enum { ..." + return True + object_name = words[1] + if object_name in ("class", "struct") and len(words) > 2: # enum class ... or enum struct + object_name = words[2] + # The actual test comes here. + return is_upper_camel_case(object_name) + + +class TestNameEnum(TestNameUpperCamelCase): + """Test names of enumerators.""" + + keyword = "enum" + name = "name/enum" + message = "Use UpperCamelCase for names of enumerators and their values." + + +class TestNameClass(TestNameUpperCamelCase): + """Test names of classes.""" + + keyword = "class" + name = "name/class" + message = "Use UpperCamelCase for names of classes." + + +class TestNameStruct(TestNameUpperCamelCase): + """Test names of structs.""" + + keyword = "struct" + name = "name/struct" + message = "Use UpperCamelCase for names of structs." + + +class TestNameFileCpp(TestSpec): + """Test names of C++ files.""" + + name = "name/file-cpp" + message = "Use lowerCamelCase or UpperCamelCase for names of C++ files. See the O2 naming conventions for details." + rationale = rationale_names + references = references_names + suffixes = [".h", ".cxx", ".C"] + per_line = False + + def test_file(self, path: str, content) -> bool: + file_name = os.path.basename(path) + # workflow file + if re.search(r"(TableProducer|Tasks)/.*\.cxx", path): + return is_lower_camel_case(file_name) + # data model file + if "DataModel/" in path: + return is_upper_camel_case(file_name) + # utility file + if re.search(r"[Uu]til(ity|ities|s)?", file_name): + return is_lower_camel_case(file_name) + return is_camel_case(file_name) + + +class TestNameFilePython(TestSpec): + """Test names of Python files.""" + + name = "name/file-python" + message = "Use snake_case for names of Python files." + rationale = rationale_names + references = [Reference.LINTER, Reference.PY_PEP8] + suffixes = [".py", ".ipynb"] + per_line = False + + def test_file(self, path: str, content) -> bool: + file_name = os.path.basename(path) + return is_snake_case(file_name) + + +class TestNameWorkflow(TestSpec): + """Test names of O2 workflows.""" + + name = "name/o2-workflow" + message = "Use kebab-case for names of workflows and match the name of the workflow file." + rationale = f"{rationale_names} Correspondence workflow ↔ file." + references = references_names + suffixes = ["CMakeLists.txt"] + per_line = False + + def test_file(self, path: str, content) -> bool: + passed = True + workflow_name = "" + for i, line in enumerate(content): + if not line.startswith("o2physics_add_dpl_workflow("): + continue + if self.is_disabled(line, "#"): + continue + # Extract workflow name. + workflow_name = line.strip().split("(")[1].split()[0] + if not is_kebab_case(workflow_name): + passed = False + self.print_error(path, i + 1, f"Invalid workflow name: {workflow_name}.") + continue + # Extract workflow file name. + next_line = content[i + 1].strip() + words = next_line.split() + if words[0] != "SOURCES": + passed = False + self.print_error(path, i + 2, f"Did not find sources for workflow: {workflow_name}.") + continue + workflow_file_name = os.path.basename(words[1]) # the actual file name + # Generate the file name matching the workflow name. + expected_workflow_file_name = kebab_case_to_camel_case_l(workflow_name) + ".cxx" + # Compare the actual and expected file names. + if expected_workflow_file_name != workflow_file_name: + passed = False + self.print_error( + path, + i + 1, + f"Workflow name {workflow_name} does not match its file name {workflow_file_name}. " + f"(Matches {expected_workflow_file_name}.)", + ) + return passed + + +class TestNameTask(TestSpec): + """Test explicit task names. + Detect usage of TaskName, check whether it is needed and whether the task name matches the struct name.""" + + name = "name/o2-task" + message = "Specify task name only when it cannot be derived from the struct name. Only append to the default name." + rationale = f"{rationale_names} Correspondence struct ↔ device." + references = [Reference.LINTER] + suffixes = [".cxx"] + per_line = False + + def test_file(self, path: str, content) -> bool: + is_inside_define = False # Are we inside defineDataProcessing? + is_inside_adapt = False # Are we inside adaptAnalysisTask? + struct_name = "" + struct_templated = False # Is the struct templated? + n_parens_opened = 0 # number of opened parentheses + passed = True + for i, line in enumerate(content): + if not line.strip(): + continue + if self.is_disabled(line): + continue + if is_comment_cpp(line): + continue + line = remove_comment_cpp(line) + # Wait for defineDataProcessing. + if not is_inside_define: + if not re.match(r"((o2::)?framework::)?WorkflowSpec defineDataProcessing\(", line): + continue + # print(f"{i + 1}: Entering define.") + is_inside_define = True + # Return at the end of defineDataProcessing. + if is_inside_define and line[0] == "}": + # print(f"{i + 1}: Exiting define.") + break + # Wait for adaptAnalysisTask. + if not is_inside_adapt: + if (index := line.find("adaptAnalysisTask<")) == -1: + continue + # print(f"{i + 1}: Entering adapt.") + is_inside_adapt = True + line = line[(index + len("adaptAnalysisTask<")) :] + # Extract struct name. + if not (match := re.match(r"([^>]+)", line)): + self.print_error(path, i + 1, f'Failed to extract struct name from "{line}".') + return False + struct_name = match.group(1) + if (index := struct_name.find("<")) > -1: + struct_templated = True + # print(f"{i + 1}: Got templated struct name {struct_name}") + struct_name = struct_name[:index] + # print(f"{i + 1}: Got struct name {struct_name}") + line = line[(line.index(struct_name) + len(struct_name)) :] + if is_inside_adapt: + n_parens_opened += line.count("(") - line.count(")") + # print(f"{i + 1}: {n_parens_opened} opened parens") + if n_parens_opened <= 0: + # print(f"{i + 1}: Exiting adapt.") + is_inside_adapt = False + # Find explicit task name. + if "TaskName{" not in line: + continue + passed = False + # Extract explicit task name. + if not (match := re.search(r"TaskName\{\"([^\}]+)\"\}", line)): + self.print_error(path, i + 1, f'Failed to extract explicit task name from "{line}".') + return False + task_name = match.group(1) + # print(f"{i + 1}: Got struct \"{struct_name}\" with task name \"{task_name}\".") + # Test explicit task name. + device_name_from_struct_name = camel_case_to_kebab_case( + struct_name + ) # default device name, in absence of TaskName + device_name_from_task_name = camel_case_to_kebab_case( + task_name + ) # actual device name, generated from TaskName + struct_name_from_device_name = kebab_case_to_camel_case_u( + device_name_from_task_name + ) # struct name matching the TaskName + if not is_kebab_case(device_name_from_task_name): + self.print_error( + path, + i + 1, + f"Specified task name {task_name} produces an invalid device name " + f"{device_name_from_task_name}.", + ) + passed = False + elif device_name_from_struct_name == device_name_from_task_name: + # If the task name results in the same device name as the struct name would, + # TaskName is redundant and should be removed. + self.print_error( + path, + i + 1, + f"Specified task name {task_name} and the struct name {struct_name} produce " + f"the same device name {device_name_from_struct_name}. TaskName is redundant.", + ) + passed = False + elif device_name_from_struct_name.replace("-", "") == device_name_from_task_name.replace("-", ""): + # If the device names generated from the task name and from the struct name differ in hyphenation, + # capitalisation of the struct name should be fixed and TaskName should be removed. + # (special cases: alice3-, -2prong) + self.print_error( + path, + i + 1, + f"Device names {device_name_from_task_name} and {device_name_from_struct_name} generated " + f"from the specified task name {task_name} and from the struct name {struct_name}, " + f"respectively, differ in hyphenation. Consider fixing capitalisation of the struct name " + f"to {struct_name_from_device_name} and removing TaskName.", + ) + passed = False + elif device_name_from_task_name.startswith(device_name_from_struct_name): + # If the device name generated from the task name is an extension of the device name generated + # from the struct name, accept it if the struct is templated. If the struct is not templated, + # extension is acceptable if adaptAnalysisTask is called multiple times for the same struct. + if not struct_templated: + self.print_error( + path, + i + 1, + f"Device name {device_name_from_task_name} from the specified task name " + f"{task_name} is an extension of the device name {device_name_from_struct_name} " + f"from the struct name {struct_name} but the struct is not templated. " + "Is it adapted multiple times?", + ) + passed = False + # else: + # self.print_error(path, i + 1, f"Device name {device_name_from_task_name} from + # the specified task name {task_name} is an extension of the device name + # {device_name_from_struct_name} from the struct name {struct_name} and the struct is templated. + # All good") + else: + # Other cases should be rejected. + self.print_error( + path, + i + 1, + f"Specified task name {task_name} produces device name {device_name_from_task_name} " + f"which does not match the device name {device_name_from_struct_name} from " + f"the struct name {struct_name}. (Matching struct name {struct_name_from_device_name})", + ) + passed = False + return passed + + +class TestNameFileWorkflow(TestSpec): + """Test names of workflow files.""" + + name = "name/workflow-file" + message = ( + "Name of a workflow file must match the name of the main struct in it (without the PWG prefix). " + '(Class implementation files should be in "Core" directories.)' + ) + rationale = f"{rationale_names} Correspondence file ↔ struct." + references = [Reference.LINTER] + suffixes = [".cxx"] + per_line = False + + def file_matches(self, path: str) -> bool: + return super().file_matches(path) and "/Core/" not in path + + def test_file(self, path: str, content) -> bool: + file_name = os.path.basename(path)[:-4] # file name without suffix + base_struct_name = f"{file_name[0].upper()}{file_name[1:]}" # expected base of struct names + if match := re.search("PWG([A-Z]{2})/", path): + name_pwg = match.group(1) + prefix_pwg = name_pwg.capitalize() + if name_pwg in ("HF"): + base_struct_name = rf"{prefix_pwg}{base_struct_name}" # mandatory PWG prefix + else: + base_struct_name = rf"({prefix_pwg})?{base_struct_name}" # optional PWG prefix + # print(f"For file {file_name} expecting to find {base_struct_name}.") + struct_names = [] # actual struct names in the file + for line in content: + if self.is_disabled(line): + return True + if not line.startswith("struct "): + continue + # Extract struct name. + words = line.split() + if not words[1].isidentifier(): # "struct : ..." + continue + struct_name = words[1] + struct_names.append(struct_name) + # print(f"Found structs: {struct_names}.") + return any(re.match(base_struct_name, struct_name) for struct_name in struct_names) + + +class TestNameConfigurable(TestSpec): + """Test names of configurables.""" + + name = "name/configurable" + message = ( + "Use lowerCamelCase for names of configurables and use the same name " + "for the struct member as for the JSON string. (Declare the type and names on the same line.)" + ) + rationale = f"{rationale_names} Correspondence C++ code ↔ JSON." + references = [Reference.O2, Reference.LINTER] + suffixes = [".h", ".cxx"] + + def file_matches(self, path: str) -> bool: + return super().file_matches(path) and "Macros/" not in path + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + if not line.startswith("Configurable"): + return True + # Extract Configurable name. + words = line.split() + if len(words) < 2: + return False + if len(words) > 2 and words[2] == "=": # expecting Configurable... nameCpp = {"nameJson", + name_cpp = words[1] # nameCpp + name_json = words[3][1:] # expecting "nameJson", + else: + names = words[1].split("{") # expecting Configurable... nameCpp{"nameJson", + if len(names) < 2: + return False + name_cpp = names[0] # nameCpp + name_json = names[1] # expecting "nameJson", + if not name_json: + return False + if name_json[0] != '"': # JSON name is not a literal string. + return True + name_json = name_json.strip('",') # expecting nameJson + # The actual test comes here. + return is_lower_camel_case(name_cpp) and name_cpp == name_json + + +# PWG-HF + +references_hf = [Reference.LINTER, Reference.PWG_HF] + + +class TestHfNameStructClass(TestSpec): + """PWGHF: Test names of structs and classes.""" + + name = "pwghf/name/struct-class" + message = 'Names of PWGHF structs and classes must start with "Hf".' + rationale = f"{rationale_names} Correspondence device ↔ workflow." + references = references_hf + suffixes = [".h", ".cxx"] + + def file_matches(self, path: str) -> bool: + return super().file_matches(path) and "PWGHF/" in path and "Macros/" not in path + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + if not line.startswith(("struct ", "class ")): + return True + line = remove_comment_cpp(line) + # Extract struct/class name. + words = line.split() + if not words[1].isalnum(): # "struct : ..." + return True + struct_name = words[1] + # The actual test comes here. + return struct_name.startswith("Hf") + + +class TestHfNameFileTask(TestSpec): + """PWGHF: Test names of task workflow files.""" + + name = "pwghf/name/task-file" + message = 'Name of a PWGHF task workflow file must start with "task".' + rationale = rationale_names + references = references_hf + suffixes = [".cxx"] + per_line = False + + def file_matches(self, path: str) -> bool: + return super().file_matches(path) and "PWGHF/" in path and "Macros/" not in path + + def test_file(self, path: str, content) -> bool: + file_name = os.path.basename(path) + return not ("/Tasks/" in path and not file_name.startswith("task")) + + +class TestHfStructMembers(TestSpec): + """PWGHF: Test order of struct members. + Caveat: Does not see Configurables in ConfigurableGroup.""" + + name = "pwghf/struct-member-order" + message = "Declare struct members in the conventional order. See the PWGHF coding guidelines." + rationale = rationale_names + references = references_hf + suffixes = [".cxx"] + per_line = False + member_order = [ + "Spawns<", + "Builds<", + "Produces<", + "Configurable<", + "HfHelper ", + "SliceCache ", + "Service<", + "using ", + "Filter ", + "Preslice<", + "PresliceUnsorted<", + "Partition<", + "ConfigurableAxis ", + "AxisSpec ", + "HistogramRegistry ", + "OutputObj<", + "void init(", + "void process", + ] + + def file_matches(self, path: str) -> bool: + return super().file_matches(path) and "PWGHF/" in path + + def test_file(self, path: str, content) -> bool: + passed = True + dic_structs: dict[str, dict] = {} + struct_name = "" + for i, line in enumerate(content): + if is_comment_cpp(line): + continue + if line.startswith("struct "): # expecting no indentation + line = remove_comment_cpp(line) + struct_name = line.strip().split()[1] + dic_structs[struct_name] = {} + continue + if not struct_name: + continue + # Save line numbers of members of the current struct for each category. + for member in self.member_order: + if line.startswith(f" {member}"): # expecting single-level indentation for direct members + if member not in dic_structs[struct_name]: + dic_structs[struct_name][member] = [] + dic_structs[struct_name][member].append(i + 1) # save line number + break + # print(dic_struct) + # Detect members declared in a wrong order. + last_line_last_member = 0 # line number of the last member of the previous member category + index_last_member = 0 # index of the previous member category in the member_order list + for struct_name, dic_struct in dic_structs.items(): + for i_m, member in enumerate(self.member_order): + if member not in dic_struct: + continue + first_line = min(dic_struct[member]) # line number of the first member of this category + last_line = max(dic_struct[member]) # line number of the last member of this category + if ( + first_line < last_line_last_member + ): # The current category starts before the end of the previous category. + passed = False + self.print_error( + path, + first_line, + f"{struct_name}: {member.strip()} appears too early " + f"(before end of {self.member_order[index_last_member].strip()}).", + ) + last_line_last_member = last_line + index_last_member = i_m + return passed + + +# End of test implementations + + +def main(): + """Main function""" + parser = argparse.ArgumentParser(description="O2 linter (Find O2-specific issues in O2 code)") + parser.add_argument("paths", type=str, nargs="+", help="File path(s)") + parser.add_argument( + "-g", + dest="github", + action="store_true", + help="Print messages also as GitHub annotations", + ) + args = parser.parse_args() + if args.github: + global github_mode # pylint: disable=global-statement # noqa: PLW0603 + github_mode = True + + tests: list[TestSpec] = [] # list of activated tests + + # Bad practice + enable_bad_practice = True + if enable_bad_practice: + tests.append(TestIoStream()) + tests.append(TestUsingStd()) + tests.append(TestUsingDirective()) + tests.append(TestStdPrefix()) + tests.append(TestRootEntity()) + tests.append(TestRootLorentzVector()) + tests.append(TestPi()) + tests.append(TestTwoPiAddSubtract()) + tests.append(TestPiMultipleFraction()) + tests.append(TestPdgDatabase()) + tests.append(TestPdgExplicitCode()) + tests.append(TestPdgExplicitMass()) + tests.append(TestPdgKnownMass()) + tests.append(TestLogging()) + tests.append(TestConstRefInForLoop()) + tests.append(TestConstRefInSubscription()) + tests.append(TestWorkflowOptions()) + tests.append(TestMagicNumber()) + + # Documentation + enable_documentation = True + if enable_documentation: + tests.append(TestDocumentationFile()) + + # Naming conventions + enable_naming = True + if enable_naming: + tests.append(TestNameFunctionVariable()) + tests.append(TestNameMacro()) + tests.append(TestNameConstant()) + tests.append(TestNameColumn()) + tests.append(TestNameTable()) + tests.append(TestNameNamespace()) + tests.append(TestNameType()) + tests.append(TestNameEnum()) + tests.append(TestNameClass()) + tests.append(TestNameStruct()) + tests.append(TestNameFileCpp()) + tests.append(TestNameFilePython()) + tests.append(TestNameWorkflow()) + tests.append(TestNameTask()) + tests.append(TestNameFileWorkflow()) + tests.append(TestNameConfigurable()) + + # PWG-HF + enable_pwghf = True + if enable_pwghf: + tests.append(TestHfNameStructClass()) + tests.append(TestHfNameFileTask()) + tests.append(TestHfStructMembers()) + + test_names = [t.name for t in tests] # short names of activated tests + suffixes = tuple({s for test in tests for s in test.suffixes}) # all suffixes from all enabled tests + passed = True # global result of all tests + n_files_bad = dict.fromkeys(test_names, 0) # counter of files with issues + + # Report overview before running. + print(f"Testing {len(args.paths)} files.") + # print(args.paths) + print("Enabled tests:", test_names) + print("Suffixes of tested files:", sorted(suffixes)) + # print(f"Github annotations: {github_mode}.") + + # Test files. + for path in args.paths: + # print(f"Processing path \"{path}\".") + # Skip not tested files. + if not path.endswith(suffixes): + # print(f"Skipping path \"{path}\".") + continue + try: + with open(path, encoding="utf-8") as file: + tolerated_tests = get_tolerated_tests(path) + content = file.readlines() + for test in tests: + test.tolerated = test.name in tolerated_tests + result = test.run(path, content) + if not result: + n_files_bad[test.name] += 1 + passed = False + # print(f"File \"{path}\" {'passed' if result else 'failed'} the test {test.name}.") + except OSError: + print(f'Failed to open file "{path}".') + sys.exit(1) + + # Report results for tests that failed or were disabled or were tolerated. + n_issues, n_disabled, n_tolerated = 0, 0, 0 # global counters + if not passed or any(n > 0 for n in (test.n_disabled + test.n_tolerated for test in tests)): + print("\nResults for failed, tolerated and disabled tests") + len_max = max(len(name) for name in test_names) + print(f"test{' ' * (len_max - len('test'))}\tissues\ttolerated\tdisabled\tbad files\trationale") + print("-" * len_max) + ref_names = [] + for test in tests: + if any(n > 0 for n in (test.n_issues, test.n_disabled, test.n_tolerated, n_files_bad[test.name])): + ref_ids = [ref.value for ref in test.references] + ref_names += test.references + print( + f"{test.name}{' ' * (len_max - len(test.name))}\t{test.n_issues}\t{test.n_tolerated}" + f"\t\t{test.n_disabled}\t\t{n_files_bad[test.name]}\t\t{test.rationale} {ref_ids}" + ) + n_issues += test.n_issues + n_disabled += test.n_disabled + n_tolerated += test.n_tolerated + print("-" * len_max) + # Print the totals. + name_total = "total" + print(f"{name_total}{' ' * (len_max - len(name_total))}\t{n_issues}\t{n_tolerated}\t\t{n_disabled}") + # Print list of references for listed tests. + print("\nReferences") + ref_names = list(dict.fromkeys(ref_names)) + for ref_name, data in references.items(): + if ref_name in ref_names: + print(f"[{ref_name.value}]\t{data['title']}. <{data['url']}>.") + + # Report global result. + title_result = "O2 linter result" + if passed: + msg_result = "All tests passed." + if github_mode: + print(f"\n::notice title={title_result}::{msg_result}") + else: + print(f"\n{title_result}: {msg_result}") + else: + msg_result = "Issues have been found." + msg_disable = ( + f'Exceptionally, you can disable a test for a line by adding a comment with "{prefix_disable}"' + " followed by the name of the test and parentheses with a reason for the exception." + ) + msg_tolerate = f'To tolerate certain issues in a directory, add a line with the test name in "{file_config}".' + if github_mode: + print(f"\n::error title={title_result}::{msg_result}") + print(f"::notice::{msg_disable}") + print(f"::notice::{msg_tolerate}") + else: + print(f"\n{title_result}: {msg_result}") + print(msg_disable) + print(msg_tolerate) + + # Make results available to the GitHub actions. + if github_mode: + try: + with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh: + print(f"n_issues={n_issues}", file=fh) + print(f"n_disabled={n_disabled}", file=fh) + print(f"n_tolerated={n_tolerated}", file=fh) + except KeyError: + print("Skipping writing in GITHUB_OUTPUT.") + + # Print tips. + print("\nTip: You can run the O2 linter locally with: python3 Scripts/o2_linter.py ") + + if not passed: + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/Tools/KFparticle/KFUtilities.h b/Tools/KFparticle/KFUtilities.h index eeb638c2ed8..e27b2340866 100644 --- a/Tools/KFparticle/KFUtilities.h +++ b/Tools/KFparticle/KFUtilities.h @@ -13,6 +13,7 @@ /// \brief Utilities needed for the KFParticle package /// /// \author Annalena Kalteyer , GSI Darmstadt +/// \author Carolina Reetz , Heidelberg University #ifndef TOOLS_KFPARTICLE_KFUTILITIES_H_ #define TOOLS_KFPARTICLE_KFUTILITIES_H_ @@ -21,6 +22,8 @@ #define HomogeneousField #endif +#include + #include // FIXME #include "KFParticle.h" @@ -105,6 +108,75 @@ KFPTrack createKFPTrackFromTrackParCov(const o2::track::TrackParametrizationWith return kfpTrack; } +/// @brief Function to create a KFParticle from a o2::track::TrackParametrizationWithError track +/// @tparam T +/// @param trackparCov TrackParCov +/// @param charge charg of track +/// @param mass mass hypothesis +/// @return KFParticle +template +KFParticle createKFParticleFromTrackParCov(const o2::track::TrackParametrizationWithError& trackparCov, int charge, float mass) +{ + std::array xyz, pxpypz; + float xyzpxpypz[6]; + trackparCov.getPxPyPzGlo(pxpypz); + trackparCov.getXYZGlo(xyz); + for (int i{0}; i < 3; ++i) { + xyzpxpypz[i] = xyz[i]; + xyzpxpypz[i + 3] = pxpypz[i]; + } + + std::array cv; + try { + trackparCov.getCovXYZPxPyPzGlo(cv); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to get cov matrix from TrackParCov" << e.what(); + } + + KFParticle kfPart; + float Mini, SigmaMini, M, SigmaM; + kfPart.GetMass(Mini, SigmaMini); + LOG(debug) << "Daughter KFParticle mass before creation: " << Mini << " +- " << SigmaMini; + + try { + kfPart.Create(xyzpxpypz, cv.data(), charge, mass); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to create KFParticle from daughter TrackParCov" << e.what(); + } + + kfPart.GetMass(M, SigmaM); + LOG(debug) << "Daughter KFParticle mass after creation: " << M << " +- " << SigmaM; + return kfPart; +} + +/// @brief Function to create a o2::track::TrackParametrizationWithError track from a KFParticle +/// @param kfParticle KFParticle to transform +/// @param pid PID hypothesis +/// @param sign sign of the particle +/// @return o2::track::TrackParametrizationWithError track +o2::track::TrackParCov getTrackParCovFromKFP(const KFParticle& kfParticle, const o2::track::PID pid, const int sign) +{ + o2::gpu::gpustd::array xyz, pxpypz; + o2::gpu::gpustd::array cv; + + // get parameters from kfParticle + xyz[0] = kfParticle.GetX(); + xyz[1] = kfParticle.GetY(); + xyz[2] = kfParticle.GetZ(); + pxpypz[0] = kfParticle.GetPx(); + pxpypz[1] = kfParticle.GetPy(); + pxpypz[2] = kfParticle.GetPz(); + + // set covariance matrix elements (lower triangle) + for (int i = 0; i < 21; i++) { + cv[i] = kfParticle.GetCovariance(i); + } + + // create TrackParCov track + o2::track::TrackParCov track = o2::track::TrackParCov(xyz, pxpypz, cv, sign, true, pid); + return track; +} + /// @brief Cosine of pointing angle from KFParticles /// @param kfp KFParticle /// @param PV KFParticle primary vertex @@ -243,4 +315,91 @@ float ldlXYFromKF(KFParticle kfpParticle, KFParticle PV) return l_particle / dl_particle; } +/// @brief squared distance between track and primary vertex normalised by its uncertainty evaluated in matrix form +/// @param track KFParticle track (must be passed as a copy) +/// @param vtx KFParticle primary vertex +/// @return chi2 to primary vertex +float kfCalculateChi2ToPrimaryVertex(KFParticle track, const KFParticle& vtx) +{ + const float PvPoint[3] = {vtx.X(), vtx.Y(), vtx.Z()}; + + track.TransportToPoint(PvPoint); + return track.GetDeviationFromVertex(vtx); +} + +/// @brief prong's momentum in the secondary (decay) vertex +/// @param track KFParticle track (must be passed as a copy) +/// @param vtx KFParticle secondary vertex +/// @return array with components of prong's momentum in the secondary (decay) vertex +std::array kfCalculateProngMomentumInSecondaryVertex(KFParticle track, const KFParticle& vtx) +{ + const float SvPoint[3] = {vtx.X(), vtx.Y(), vtx.Z()}; + + track.TransportToPoint(SvPoint); + return {track.GetPx(), track.GetPy(), track.GetPz()}; +} + +/// @brief distance of closest approach between two tracks, cm +/// @param track1 KFParticle first track (must be passed as a copy) +/// @param track2 KFParticle second track (must be passed as a copy) +/// @return DCA [cm] in the PCA +float kfCalculateDistanceBetweenParticles(KFParticle track1, KFParticle track2) +{ + float dS[2]; + float dsdr[4][6]; + float params1[8], params2[8]; + float covs1[36], covs2[36]; + track1.GetDStoParticle(track2, dS, dsdr); + track1.Transport(dS[0], dsdr[0], params1, covs1); + track2.Transport(dS[1], dsdr[3], params2, covs2); + const float dx = params1[0] - params2[0]; + const float dy = params1[1] - params2[1]; + const float dz = params1[2] - params2[2]; + return std::sqrt(dx * dx + dy * dy + dz * dz); +} + +/// @brief squared distance between two tracks normalised by its uncertainty evaluated in matrix form +/// @param track1 KFParticle first track (must be passed as a copy) +/// @param track2 KFParticle second track (must be passed as a copy) +/// @return chi2 in PCA +float kfCalculateChi2geoBetweenParticles(KFParticle track1, KFParticle track2) +{ + KFParticle kfPair; + const KFParticle* kfDaughters[3] = {&track1, &track2}; + kfPair.SetConstructMethod(2); + kfPair.Construct(kfDaughters, 2); + + return kfPair.Chi2() / kfPair.NDF(); +} + +/// @brief signed distance between primary and secondary vertex and its uncertainty, cm +/// @param candidate KFParticle decay candidate (must be passed as a copy) +/// @param vtx KFParticle primary vertex +/// @return pair of l and delta l +std::pair kfCalculateLdL(KFParticle candidate, const KFParticle& vtx) +{ + float l, dl; + candidate.SetProductionVertex(vtx); + candidate.KFParticleBase::GetDecayLength(l, dl); + + return std::make_pair(l, dl); +} + +/// @brief Z projection of the impact parameter from the track to the primary vertex, cm +/// @param candidate KFParticle prong +/// @param vtx KFParticle primary vertex +/// @return pair of impact parameter and its error +std::pair kfCalculateImpactParameterZ(const KFParticle& candidate, const KFParticle& vtx) +{ + float distanceToVertexXY, errDistanceToVertexXY; + candidate.GetDistanceFromVertexXY(vtx, distanceToVertexXY, errDistanceToVertexXY); + const float distanceToVertex = candidate.GetDistanceFromVertex(vtx); + const float chi2ToVertex = candidate.GetDeviationFromVertex(vtx); + const float distanceToVertexZ2 = distanceToVertex * distanceToVertex - distanceToVertexXY * distanceToVertexXY; + const float distanceToVertexZ = distanceToVertexZ2 > 0 ? std::sqrt(distanceToVertexZ2) : -std::sqrt(-distanceToVertexZ2); + const float errDistanceToVertexZ2 = (distanceToVertex * distanceToVertex * distanceToVertex * distanceToVertex / chi2ToVertex - distanceToVertexXY * distanceToVertexXY * errDistanceToVertexXY * errDistanceToVertexXY) / distanceToVertexZ2; + const float errDistanceToVertexZ = errDistanceToVertexZ2 > 0 ? std::sqrt(errDistanceToVertexZ2) : -std::sqrt(-errDistanceToVertexZ2); + return std::make_pair(distanceToVertexZ, errDistanceToVertexZ); +} + #endif // TOOLS_KFPARTICLE_KFUTILITIES_H_ diff --git a/Tools/ML/MlResponse.h b/Tools/ML/MlResponse.h index 48729270d32..2d16a67bf18 100644 --- a/Tools/ML/MlResponse.h +++ b/Tools/ML/MlResponse.h @@ -17,7 +17,11 @@ #ifndef TOOLS_ML_MLRESPONSE_H_ #define TOOLS_ML_MLRESPONSE_H_ +#if __has_include() #include +#else +#include +#endif #include #include @@ -87,6 +91,15 @@ class MlResponse LOG(fatal) << "Number of expected models (" << mNModels << ") different from the number of CCDB paths (" << pathsCCDB.size() << ")! Please check your configurables."; } + // check that the path is unique for each BDT model (otherwise CCDB download does not work as expected) + for (auto iThisFile{0}; iThisFile < mNModels; ++iThisFile) { + for (auto iOtherFile{iThisFile + 1}; iOtherFile < mNModels; ++iOtherFile) { + if ((pathsCCDB[iThisFile] == pathsCCDB[iOtherFile]) && (onnxFiles[iThisFile] != onnxFiles[iOtherFile])) { + LOGP(fatal, "More than one model ({} and {}) in the same CCDB directory ({})! Each directory in CCDB can contain only one model. Please check your configurables.", onnxFiles[iThisFile], onnxFiles[iOtherFile], pathsCCDB[iThisFile]); + } + } + } + for (auto iFile{0}; iFile < mNModels; ++iFile) { std::map metadata; bool retrieveSuccess = ccdbApi.retrieveBlob(pathsCCDB[iFile], ".", metadata, timestampCCDB, false, onnxFiles[iFile]); @@ -145,7 +158,7 @@ class MlResponse LOG(fatal) << "Model index " << nModel << " is out of range! The number of initialised models is " << mModels.size() << ". Please check your configurables."; } - TypeOutputScore* outputPtr = mModels[nModel].evalModel(input); + TypeOutputScore* outputPtr = mModels[nModel].template evalModel(input); return std::vector{outputPtr, outputPtr + mNClasses}; } diff --git a/Tools/ML/model.cxx b/Tools/ML/model.cxx index 3da0dcd9875..0c29808c73c 100644 --- a/Tools/ML/model.cxx +++ b/Tools/ML/model.cxx @@ -75,13 +75,32 @@ void OnnxModel::initModel(std::string localPath, bool enableOptimizations, int t } mEnv = std::make_shared(ORT_LOGGING_LEVEL_WARNING, "onnx-model"); +#if __has_include() mSession = std::make_shared(*mEnv, modelPath, sessionOptions); +#else + mSession = std::make_shared(*mEnv, modelPath.c_str(), sessionOptions); +#endif +#if __has_include() mInputNames = mSession->GetInputNames(); mInputShapes = mSession->GetInputShapes(); mOutputNames = mSession->GetOutputNames(); mOutputShapes = mSession->GetOutputShapes(); - +#else + Ort::AllocatorWithDefaultOptions tmpAllocator; + for (size_t i = 0; i < mSession->GetInputCount(); ++i) { + mInputNames.push_back(mSession->GetInputNameAllocated(i, tmpAllocator).get()); + } + for (size_t i = 0; i < mSession->GetInputCount(); ++i) { + mInputShapes.emplace_back(mSession->GetInputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape()); + } + for (size_t i = 0; i < mSession->GetOutputCount(); ++i) { + mOutputNames.push_back(mSession->GetOutputNameAllocated(i, tmpAllocator).get()); + } + for (size_t i = 0; i < mSession->GetOutputCount(); ++i) { + mOutputShapes.emplace_back(mSession->GetOutputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape()); + } +#endif LOG(info) << "Input Nodes:"; for (size_t i = 0; i < mInputNames.size(); i++) { LOG(info) << "\t" << mInputNames[i] << " : " << printShape(mInputShapes[i]); diff --git a/Tools/ML/model.h b/Tools/ML/model.h index 1ae1aafca0f..84872224104 100644 --- a/Tools/ML/model.h +++ b/Tools/ML/model.h @@ -21,11 +21,16 @@ #define TOOLS_ML_MODEL_H_ // C++ and system includes +#if __has_include() #include +#else +#include +#endif #include #include #include #include +#include // ROOT includes #include "TSystem.h" @@ -57,7 +62,19 @@ class OnnxModel // assert(input[0].GetTensorTypeAndShapeInfo().GetShape() == getNumInputNodes()); --> Fails build in debug mode, TODO: assertion should be checked somehow try { +#if __has_include() auto outputTensors = mSession->Run(mInputNames, input, mOutputNames); +#else + Ort::RunOptions runOptions; + std::vector inputNamesChar(mInputNames.size(), nullptr); + std::transform(std::begin(mInputNames), std::end(mInputNames), std::begin(inputNamesChar), + [&](const std::string& str) { return str.c_str(); }); + + std::vector outputNamesChar(mOutputNames.size(), nullptr); + std::transform(std::begin(mOutputNames), std::end(mOutputNames), std::begin(outputNamesChar), + [&](const std::string& str) { return str.c_str(); }); + auto outputTensors = mSession->Run(runOptions, inputNamesChar.data(), input.data(), input.size(), outputNamesChar.data(), outputNamesChar.size()); +#endif LOG(debug) << "Number of output tensors: " << outputTensors.size(); if (outputTensors.size() != mOutputNames.size()) { LOG(fatal) << "Number of output tensors: " << outputTensors.size() << " does not agree with the model specified size: " << mOutputNames.size(); @@ -83,18 +100,72 @@ class OnnxModel assert(size % mInputShapes[0][1] == 0); std::vector inputShape{size / mInputShapes[0][1], mInputShapes[0][1]}; std::vector inputTensors; +#if __has_include() inputTensors.emplace_back(Ort::Experimental::Value::CreateTensor(input.data(), size, inputShape)); +#else + Ort::MemoryInfo memInfo = + Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault); + inputTensors.emplace_back(Ort::Value::CreateTensor(memInfo, input.data(), size, inputShape.data(), inputShape.size())); +#endif LOG(debug) << "Input shape calculated from vector: " << printShape(inputShape); return evalModel(inputTensors); } + // For 2D inputs + template + T* evalModel(std::vector>& input) + { + std::vector inputTensors; + +#if !__has_include() + Ort::MemoryInfo memInfo = Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault); +#endif + + for (size_t iinput = 0; iinput < input.size(); iinput++) { + [[maybe_unused]] int totalSize = 1; + int64_t size = input[iinput].size(); + for (size_t idim = 1; idim < mInputShapes[iinput].size(); idim++) { + totalSize *= mInputShapes[iinput][idim]; + } + assert(size % totalSize == 0); + + std::vector inputShape{static_cast(size / totalSize)}; + for (size_t idim = 1; idim < mInputShapes[iinput].size(); idim++) { + inputShape.push_back(mInputShapes[iinput][idim]); + } + +#if __has_include() + inputTensors.emplace_back(Ort::Experimental::Value::CreateTensor(input[iinput].data(), size, inputShape)); +#else + inputTensors.emplace_back(Ort::Value::CreateTensor(memInfo, input[iinput].data(), size, inputShape.data(), inputShape.size())); +#endif + } + + return evalModel(inputTensors); + } + // Reset session +#if __has_include() void resetSession() { mSession.reset(new Ort::Experimental::Session{*mEnv, modelPath, sessionOptions}); } +#else + void resetSession() + { + mSession.reset(new Ort::Session{*mEnv, modelPath.c_str(), sessionOptions}); + } +#endif // Getters & Setters Ort::SessionOptions* getSessionOptions() { return &sessionOptions; } // For optimizations in post +#if __has_include() std::shared_ptr getSession() { return mSession; } +#else + std::shared_ptr getSession() + { + return mSession; + } +#endif int getNumInputNodes() const { return mInputShapes[0][1]; } + std::vector> getInputShapes() const { return mInputShapes; } int getNumOutputNodes() const { return mOutputShapes[0][1]; } uint64_t getValidityFrom() const { return validFrom; } uint64_t getValidityUntil() const { return validUntil; } @@ -103,7 +174,11 @@ class OnnxModel private: // Environment variables for the ONNX runtime std::shared_ptr mEnv = nullptr; +#if __has_include() std::shared_ptr mSession = nullptr; +#else + std::shared_ptr mSession = nullptr; +#endif Ort::SessionOptions sessionOptions; // Input & Output specifications of the loaded network diff --git a/Tools/PIDML/CMakeLists.txt b/Tools/PIDML/CMakeLists.txt index cb2f87f4204..8ac36a5c0df 100644 --- a/Tools/PIDML/CMakeLists.txt +++ b/Tools/PIDML/CMakeLists.txt @@ -9,16 +9,22 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. -o2physics_add_dpl_workflow(pid-ml-producer-mc - SOURCES pidMLProducerMC.cxx +o2physics_add_dpl_workflow(pid-ml-producer + SOURCES pidMLProducer.cxx JOB_POOL analysis PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(pid-ml-producer-data - SOURCES pidMLProducerData.cxx +o2physics_add_dpl_workflow(pid-ml-batch-eff-and-pur-producer + SOURCES pidMLBatchEffAndPurProducer.cxx JOB_POOL analysis - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2::Framework ONNXRuntime::ONNXRuntime O2::CCDB O2Physics::DataModel + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pid-ml-eff-and-pur-producer + SOURCES pidMLEffAndPurProducer.cxx + JOB_POOL analysis + PUBLIC_LINK_LIBRARIES O2::Framework ONNXRuntime::ONNXRuntime O2::CCDB O2Physics::DataModel COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(simple-apply-pid-onnx-model diff --git a/Tools/PIDML/KaonPidTask.cxx b/Tools/PIDML/KaonPidTask.cxx index 19c0972be4a..acc29e47bee 100644 --- a/Tools/PIDML/KaonPidTask.cxx +++ b/Tools/PIDML/KaonPidTask.cxx @@ -60,7 +60,6 @@ struct KaonPidTask { Configurable cfgCCDBURL{"ccdb-url", "http://alice-ccdb.cern.ch", "URL of the CCDB repository"}; Configurable cfgPid{"pid", 321, "PID to predict"}; Configurable cfgCertainty{"certainty", 0.5, "Minimum certainty above which the model accepts a particular type of particle"}; - Configurable cfgDetector{"detector", kTPCTOFTRD, "What detectors to use: 0: TPC only, 1: TPC + TOF, 2: TPC + TOF + TRD"}; Configurable cfgTimestamp{"timestamp", 0, "Fixed timestamp"}; Configurable cfgUseCCDB{"useCCDB", false, "Whether to autofetch ML model from CCDB. If false, local file will be used."}; @@ -85,7 +84,7 @@ struct KaonPidTask { if (cfgUseCCDB) { ccdbApi.init(cfgCCDBURL); // Initializes ccdbApi when cfgUseCCDB is set to 'true' } - pidModel = std::make_shared(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, cfgTimestamp.value, cfgPid.value, static_cast(cfgDetector.value), cfgCertainty.value); + pidModel = std::make_shared(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, cfgTimestamp.value, cfgPid.value, cfgCertainty.value); histos.add("hChargePos", ";z;", kTH1F, {{3, -1.5, 1.5}}); histos.add("hChargeNeg", ";z;", kTH1F, {{3, -1.5, 1.5}}); diff --git a/Tools/PIDML/README.md b/Tools/PIDML/README.md index 57ada2bb48e..1768ac9e900 100644 --- a/Tools/PIDML/README.md +++ b/Tools/PIDML/README.md @@ -1,6 +1,8 @@ # PID ML in O2 -Particle identification is essential in most of the analyzes. The PID ML interface will help you to make use of the machine learning models to improve purity and efficiency of particle kinds for your analysis. A single model is tailored to a specific particle kind, e.g., pions with PID 211. For each track, the model returns a float value in [0, 1] which measures the ''certainty'' of the model that this track is of given kind. +Particle identification is essential in most of the analyzes. +The PID ML interface will help you to make use of the machine learning models to improve purity and efficiency of particle kinds for your analysis. +A single model is tailored to a specific particle kind, e.g., pions with PID 211. For each track, the model returns a float value in [0, 1] which measures the ''certainty'' of the model that this track is of given kind. ## PidONNXModel @@ -11,12 +13,16 @@ This class represents a single ML model from an ONNX file. It requires the follo - CCDB Api instance created in an analysis task - timestamp of the input analysis data -- neded to choose appropriate model - PID to be checked -- detector setup: what detectors should be used for identification. It is described by enum PidMLDetector. Currently available setups: TPC, TPC+TOF, TPC+TOF+TRD - minimum certainty for accepting a track to be of given PID +- *p* limits array - specifiying p limits for each detector configuration (TPC, TPC+TOF, TPC+TOF+TRD) -Let's assume your `PidONNXModel` instance is named `pidModel`. Then, inside your analysis task `process()` function, you can iterate over tracks and call: `pidModel.applyModel(track);` to get the certainty of the model. You can also use `pidModel.applyModelBoolean(track);` to receive a true/false answer, whether the track can be accepted based on the minimum certainty provided to the `PidONNXModel` constructor. +Let's assume your `PidONNXModel` instance is named `pidModel`. +Then, inside your analysis task `process()` function, you can iterate over tracks and call: `pidModel.applyModel(track);` to get the certainty of the model. +You can also use `pidModel.applyModelBoolean(track);` to receive a true/false answer, whether the track can be accepted based on the minimum certainty provided to the `PidONNXModel` constructor. -You can check [a simple analysis task example](https://github.com/AliceO2Group/O2Physics/blob/master/Tools/PIDML/simpleApplyPidOnnxModel.cxx). It uses configurable parameters and shows how to calculate the data timestamp. Note that the calculation of the timestamp requires subscribing to `aod::Collisions` and `aod::BCsWithTimestamps`. For Hyperloop tests, you can set `cfgUseFixedTimestamp` to true with `cfgTimestamp` set to the default value. +You can check [a simple analysis task example](https://github.com/AliceO2Group/O2Physics/blob/master/Tools/PIDML/simpleApplyPidOnnxModel.cxx). +It uses configurable parameters and shows how to calculate the data timestamp. Note that the calculation of the timestamp requires subscribing to `aod::Collisions` and `aod::BCsWithTimestamps`. +For Hyperloop tests, you can set `cfgUseFixedTimestamp` to true with `cfgTimestamp` set to the default value. On the other hand, it is possible to use locally stored models, and then the timestamp is not used, so it can be a dummy value. `processTracksOnly` presents how to analyze on local-only PID ML models. @@ -31,10 +37,10 @@ This is a wrapper around PidONNXModel that contains several models. It has the p Then, obligatory parameters for the interface: - a vector of int output PIDs -- a 2-dimensional LabeledArray of *p*T limits for each PID, for each detector configuration. It describes the minimum *p*T values at which each next detector should be included for predicting given PID +- a 2-dimensional LabeledArray of *p* limits for each PID, for each detector configuration. It describes the minimum *p* values at which each next detector should be included for predicting given PID - a vector of minimum certainties for each PID for accepting a track to be of this PID - boolean flag: whether to switch on auto mode. If true, then *p*T limits and minimum certainties can be passed as an empty array and an empty vector, and the interface will fill them with default configuration: - - *p*T limits: same values for all PIDs: 0.0 (TPC), 0.5 (TPC + TOF), 0.8 (TPC + TOF + TRD) + - *p* limits: same values for all PIDs: 0.0 (TPC), 0.5 (TPC + TOF), 0.8 (TPC + TOF + TRD) - minimum certainties: 0.5 for all PIDs You can use the interface in the same way as the model, by calling `applyModel(track)` or `applyModelBoolean(track)`. The interface will then call the respective method of the model selected with the aforementioned interface parameters. @@ -48,20 +54,49 @@ There is again [a simple analysis task example](https://github.com/AliceO2Group/ Currently, only models for run 285064 (timestamp interval: 1524176895000 - 1524212953000) are uploaded to CCDB, so you can use hardcoded timestamp 1524176895000 for tests. Both model and interface analysis examples can be run with a script: + +### Script for Run2 Converted to Run3 data +```bash +#!/bin/bash + +config_file="my-config.json" + +o2-analysis-tracks-extra-converter --configuration json://$config_file -b | + o2-analysis-timestamp --configuration json://$config_file -b | + o2-analysis-trackextension --configuration json://$config_file -b | + o2-analysis-trackselection --configuration json://$config_file -b | + o2-analysis-multiplicity-table --configuration json://$config_file -b | + o2-analysis-bc-converter --configuration json://$config_file -b | + o2-analysis-collision-converter --configuration json://$config_file -b | + o2-analysis-zdc-converter --configuration json://$config_file -b | + o2-analysis-pid-tof-base --configuration json://$config_file -b | + o2-analysis-pid-tof-beta --configuration json://$config_file -b | + o2-analysis-pid-tof-full --configuration json://$config_file -b | + o2-analysis-pid-tpc-full --configuration json://$config_file -b | + o2-analysis-pid-tpc-base --configuration json://$config_file -b | + o2-analysis-simple-apply-pid-onnx-model --configuration json://$config_file -b +``` +Remember to set every setting, which states that helper task should process Run2 data to `true`. + +### Script for Run3 data ```bash #!/bin/bash config_file="my-config.json" o2-analysis-timestamp --configuration json://$config_file -b | - o2-analysis-trackextension --configuration json://$config_file -b | - o2-analysis-trackselection --configuration json://$config_file -b | - o2-analysis-multiplicity-table --configuration json://$config_file -b | - o2-analysis-fdd-converter --configuration json://$config_file -b | - o2-analysis-pid-tof-base --configuration json://$config_file -b | - o2-analysis-pid-tof-beta --configuration json://$config_file -b | - o2-analysis-pid-tof-full --configuration json://$config_file -b | - o2-analysis-pid-tpc-full --configuration json://$config_file -b | - o2-analysis-simple-apply-pid-onnx-model --configuration json://$config_file -b + o2-analysis-event-selection --configuration json://$config_file -b | + o2-analysis-trackselection --configuration json://$config_file -b | + o2-analysis-multiplicity-table --configuration json://$config_file -b | + o2-analysis-track-propagation --configuration json://$config_file -b | + o2-analysis-pid-tof-base --configuration json://$config_file -b | + o2-analysis-pid-tof-beta --configuration json://$config_file -b | + o2-analysis-pid-tof-full --configuration json://$config_file -b | + o2-analysis-pid-tpc-full --configuration json://$config_file -b | + o2-analysis-pid-tpc-base --configuration json://$config_file -b | + o2-analysis-simple-apply-pid-onnx-model --configuration json://$config_file -b ``` +Remember to set every setting, which states that helper task should process Run3 data to `true`. + + Replace "model" with "interface" in the last line if you want to run the interface workflow. diff --git a/Tools/PIDML/pidMLBatchEffAndPurProducer.cxx b/Tools/PIDML/pidMLBatchEffAndPurProducer.cxx new file mode 100644 index 00000000000..9a611ded269 --- /dev/null +++ b/Tools/PIDML/pidMLBatchEffAndPurProducer.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. + +/// \file pidMLBatchEffAndPurProducer +/// \brief Batch PID execution task. It produces derived data needed for ROOT script, which +/// generates efficiency (recall) and purity (precision) analysis of ML Model PID +/// +/// \author Michał Olędzki +/// \author Marek Mytkowski + +#include +#include +#include + +#include "Framework/AnalysisDataModel.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/StaticFor.h" +#include "CCDB/CcdbApi.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/PIDResponse.h" +#include "Tools/PIDML/pidOnnxModel.h" +#include "Tools/PIDML/pidUtils.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace pidml::pidutils; + +namespace o2::aod +{ +namespace effandpurpidresult +{ +DECLARE_SOA_INDEX_COLUMN(Track, track); //! Track index +DECLARE_SOA_COLUMN(Pid, pid, int32_t); //! PDG particle ID to be tested by the model +DECLARE_SOA_COLUMN(Pt, pt, float); //! particle's pt +DECLARE_SOA_COLUMN(MlCertainty, mlCertainty, float); //! Machine learning model certainty value for track and pid +DECLARE_SOA_COLUMN(NSigma, nSigma, float); //! nSigma value for track and pid +DECLARE_SOA_COLUMN(IsPidMC, isPidMc, bool); //! Is track's mcParticle recognized as "Pid" +DECLARE_SOA_COLUMN(HasTOF, hasTof, bool); //! Does track have TOF detector signal +DECLARE_SOA_COLUMN(HasTRD, hasTrd, bool); //! Does track have TRD detector signal +} // namespace effandpurpidresult + +DECLARE_SOA_TABLE(EffAndPurPidResult, "AOD", "PIDEFFANDPURRES", o2::soa::Index<>, + effandpurpidresult::TrackId, effandpurpidresult::Pid, effandpurpidresult::Pt, effandpurpidresult::MlCertainty, + effandpurpidresult::NSigma, effandpurpidresult::IsPidMC, effandpurpidresult::HasTOF, effandpurpidresult::HasTRD); +} // namespace o2::aod + +struct PidMlBatchEffAndPurProducer { + Produces effAndPurPIDResult; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + static constexpr int32_t currentRunNumber = -1; + static constexpr uint32_t kNPids = 6; + static constexpr int32_t kPids[kNPids] = {2212, 321, 211, -211, -321, -2212}; + static constexpr std::string_view kParticleLabels[kNPids] = {"2212", "321", "211", "0211", "0321", "02212"}; + static constexpr std::string_view kParticleNames[kNPids] = {"proton", "kaon", "pion", "antipion", "antikaon", "antiproton"}; + + std::array, kNPids> hTracked; + std::array, kNPids> hMCPositive; + + o2::ccdb::CcdbApi ccdbApi; + std::vector models; + + Configurable> cfgPids{"pids", std::vector(kPids, kPids + kNPids), "PIDs to predict"}; + Configurable> cfgDetectorsPLimits{"detectors-p-limits", std::array(pidml_pt_cuts::defaultModelPLimits), "\"use {detector} when p >= y_{detector}\": array of 3 doubles [y_TPC, y_TOF, y_TRD]"}; + Configurable cfgPathCCDB{"ccdb-path", "Users/m/mkabus/PIDML", "base path to the CCDB directory with ONNX models"}; + Configurable cfgCCDBURL{"ccdb-url", "http://alice-ccdb.cern.ch", "URL of the CCDB repository"}; + Configurable cfgUseCCDB{"use-ccdb", true, "Whether to autofetch ML model from CCDB. If false, local file will be used."}; + Configurable cfgPathLocal{"local-path", "/home/mkabus/PIDML/", "base path to the local directory with ONNX models"}; + Configurable cfgUseFixedTimestamp{"use-fixed-timestamp", false, "Whether to use fixed timestamp from configurable instead of timestamp calculated from the data"}; + Configurable cfgTimestamp{"timestamp", 1524176895000, "Hardcoded timestamp for tests"}; + + Filter trackFilter = requireGlobalTrackInFilter(); + + using BigTracks = soa::Filtered>; + + void initHistos() + { + static const AxisSpec axisPt{50, 0, 3.1, "pt"}; + + static_for<0, kNPids - 1>([&](auto i) { + if (std::find(cfgPids.value.begin(), cfgPids.value.end(), kPids[i]) != cfgPids.value.end()) { + hTracked[i] = histos.add(Form("%s/hPtMCTracked", kParticleLabels[i].data()), Form("Tracked %ss vs pT", kParticleNames[i].data()), kTH1F, {axisPt}); + hMCPositive[i] = histos.add(Form("%s/hPtMCPositive", kParticleLabels[i].data()), Form("MC Positive %ss vs pT", kParticleNames[i].data()), kTH1F, {axisPt}); + } + }); + } + + void init(InitContext const&) + { + if (cfgUseCCDB) { + ccdbApi.init(cfgCCDBURL); + } + + initHistos(); + } + + std::optional getPartIndex(int32_t pdgCode) + { + std::optional index; + + if (std::find(cfgPids.value.begin(), cfgPids.value.end(), pdgCode) != cfgPids.value.end()) { + switch (pdgCode) { + case 2212: + index = 0; + break; + case 321: + index = 1; + break; + case 211: + index = 2; + break; + case -211: + index = 3; + break; + case -321: + index = 4; + break; + case -2212: + index = 5; + break; + } + } + + return index; + } + + void fillTrackedHist(int32_t pdgCode, float pt) + { + auto ind = getPartIndex(pdgCode); + if (ind) { + hTracked[ind.value()]->Fill(pt); + } + } + + void fillMCPositiveHist(int32_t pdgCode, float pt) + { + auto ind = getPartIndex(pdgCode); + if (ind) { + hMCPositive[ind.value()]->Fill(pt); + } + } + + typedef struct nSigma_t { + double tpc, tof, composed; + } nSigma_t; + + const nSigma_t getNSigma(const BigTracks::iterator& track, const int32_t& cfgPid) + { + nSigma_t nSigma; + + switch (TMath::Abs(cfgPid)) { + case 11: // electron + nSigma.tof = track.tofNSigmaEl(); + nSigma.tpc = track.tpcNSigmaEl(); + break; + case 13: // muon + nSigma.tof = track.tofNSigmaMu(); + nSigma.tpc = track.tpcNSigmaMu(); + break; + case 211: // pion + nSigma.tof = track.tofNSigmaPi(); + nSigma.tpc = track.tpcNSigmaPi(); + break; + case 321: // kaon + nSigma.tof = track.tofNSigmaKa(); + nSigma.tpc = track.tpcNSigmaKa(); + break; + case 2212: // proton + nSigma.tof = track.tofNSigmaPr(); + nSigma.tpc = track.tpcNSigmaPr(); + break; + } + + if (!inPLimit(track, cfgDetectorsPLimits.value[kTPCTOF]) || tofMissing(track)) { + nSigma.composed = TMath::Abs(nSigma.tpc); + } else { + nSigma.composed = TMath::Hypot(nSigma.tof, nSigma.tpc); + } + + int32_t sign = cfgPid > 0 ? 1 : -1; + if (sign != track.sign()) { + nSigma.composed = std::numeric_limits::max(); + } + + return nSigma; + } + + void process(aod::Collisions const& collisions, BigTracks const& tracks, aod::BCsWithTimestamps const&, aod::McParticles const& mcParticles) + { + effAndPurPIDResult.reserve(mcParticles.size()); + + auto bc = collisions.iteratorAt(0).bc_as(); + if (cfgUseCCDB && bc.runNumber() != currentRunNumber) { + uint64_t timestamp = cfgUseFixedTimestamp ? cfgTimestamp.value : bc.timestamp(); + for (const int32_t& pid : cfgPids.value) + models.emplace_back(PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, + ccdbApi, timestamp, pid, 1.1, &cfgDetectorsPLimits.value[0])); + } else { + for (int32_t& pid : cfgPids.value) + models.emplace_back(PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, + ccdbApi, -1, pid, 1.1, &cfgDetectorsPLimits.value[0])); + } + + for (auto& mcPart : mcParticles) { + // eta cut is done in requireGlobalTrackInFilter() so we cut it only here + if (mcPart.isPhysicalPrimary() && TMath::Abs(mcPart.eta()) < kGlobalEtaCut) { + fillMCPositiveHist(mcPart.pdgCode(), mcPart.pt()); + } + } + + for (auto& track : tracks) { + if (track.has_mcParticle()) { + auto mcPart = track.mcParticle(); + if (mcPart.isPhysicalPrimary()) { + fillTrackedHist(mcPart.pdgCode(), track.pt()); + + for (size_t i = 0; i < cfgPids.value.size(); ++i) { + float mlCertainty = models[i].applyModel(track); + nSigma_t nSigma = getNSigma(track, cfgPids.value[i]); + bool isMCPid = mcPart.pdgCode() == cfgPids.value[i]; + + effAndPurPIDResult(track.index(), cfgPids.value[i], track.pt(), mlCertainty, nSigma.composed, isMCPid, track.hasTOF(), track.hasTRD()); + } + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Tools/PIDML/pidMLEffAndPurProducer.cxx b/Tools/PIDML/pidMLEffAndPurProducer.cxx new file mode 100644 index 00000000000..7e626a8d631 --- /dev/null +++ b/Tools/PIDML/pidMLEffAndPurProducer.cxx @@ -0,0 +1,213 @@ +// 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 pidMLEffAndPurProducer.cxx +/// \brief Produce pt histograms for tracks accepted by ML network and for MC mcParticles. +/// +/// \author Michał Olędzki +/// \author Marek Mytkowski + +#include + +#include "Framework/AnalysisDataModel.h" +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "CCDB/CcdbApi.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/PIDResponse.h" +#include "Tools/PIDML/pidOnnxModel.h" +#include "pidOnnxModel.h" +#include "Tools/PIDML/pidUtils.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace pidml::pidutils; + +struct PidMlEffAndPurProducer { + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + PidONNXModel pidModel; + Configurable cfgPid{"pid", 211, "PID to predict"}; + Configurable cfgNSigmaCut{"n-sigma-cut", 3.0f, "TPC and TOF PID nSigma cut"}; + Configurable> cfgDetectorsPLimits{"detectors-p-limits", std::array(pidml_pt_cuts::defaultModelPLimits), "\"use {detector} when p >= y_{detector}\": array of 3 doubles [y_TPC, y_TOF, y_TRD]"}; + Configurable cfgCertainty{"certainty", 0.5, "Min certainty of the model to accept given mcPart to be of given kind"}; + + Configurable cfgPathCCDB{"ccdb-path", "Users/m/mkabus/PIDML", "base path to the CCDB directory with ONNX models"}; + Configurable cfgCCDBURL{"ccdb-url", "http://alice-ccdb.cern.ch", "URL of the CCDB repository"}; + Configurable cfgUseCCDB{"use-ccdb", true, "Whether to autofetch ML model from CCDB. If false, local file will be used."}; + Configurable cfgPathLocal{"local-path", "/home/mkabus/PIDML", "base path to the local directory with ONNX models"}; + + Configurable cfgUseFixedTimestamp{"use-fixed-timestamp", false, "Whether to use fixed timestamp from configurable instead of timestamp calculated from the data"}; + Configurable cfgTimestamp{"timestamp", 1524176895000, "Hardcoded timestamp for tests"}; + + o2::ccdb::CcdbApi ccdbApi; + int currentRunNumber = -1; + + Filter trackFilter = requireGlobalTrackInFilter(); + + using BigTracks = soa::Filtered>; + + typedef struct nSigma_t { + double tpc, tof; + } nSigma_t; + + nSigma_t GetNSigma(const BigTracks::iterator& track) + { + nSigma_t nSigma; + + switch (TMath::Abs(cfgPid)) { + case 11: // electron + nSigma.tof = track.tofNSigmaEl(); + nSigma.tpc = track.tpcNSigmaEl(); + break; + case 13: // muon + nSigma.tof = track.tofNSigmaMu(); + nSigma.tpc = track.tpcNSigmaMu(); + break; + case 211: // pion + nSigma.tof = track.tofNSigmaPi(); + nSigma.tpc = track.tpcNSigmaPi(); + break; + case 321: // kaon + nSigma.tof = track.tofNSigmaKa(); + nSigma.tpc = track.tpcNSigmaKa(); + break; + case 2212: // proton + nSigma.tof = track.tofNSigmaPr(); + nSigma.tpc = track.tpcNSigmaPr(); + break; + } + + return nSigma; + } + + bool IsNSigmaAccept(const BigTracks::iterator& track, nSigma_t& nSigma) + { + // FIXME: for current particles it works, but there are some particles, + // which can have different sign and pdgSign + int sign = cfgPid > 0 ? 1 : -1; + if (track.sign() != sign) + return false; + + if (!inPLimit(track, cfgDetectorsPLimits.value[kTPCTOF]) || tofMissing(track)) { + if (TMath::Abs(nSigma.tpc) >= cfgNSigmaCut) + return false; + } else { + if (TMath::Hypot(nSigma.tof, nSigma.tpc) >= cfgNSigmaCut) + return false; + } + + return true; + } + + void init(InitContext const&) + { + if (cfgUseCCDB) { + ccdbApi.init(cfgCCDBURL); + } else { + pidModel = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, -1, + cfgPid.value, cfgCertainty.value, &cfgDetectorsPLimits.value[0]); + } + + const AxisSpec axisPt{100, 0, 5.0, "pt"}; + const AxisSpec axisP{100, 0, 5.0, "p"}; + const AxisSpec axisBeta{100, 0, 1.0, "beta"}; + const AxisSpec axisTPCSignal{100, 0, 120.0, "dEdx"}; + const AxisSpec axisNSigma{100, -5.0, 5.0, "n-sigma"}; + + // Monte Carlo + histos.add("hPtMCPositive", "hPtMCPositive", kTH1F, {axisPt}); + histos.add("hPtMCTracked", "hPtMCTracked", kTH1F, {axisPt}); + + // Machine learning PID + histos.add("hPtMLPositive", "hPtMLPositive", kTH1F, {axisPt}); + histos.add("hPtMLTruePositive", "hPtMLTruePositive", kTH1F, {axisPt}); + + // NSigma PID + histos.add("hPtNSigmaPositive", "hPtNSigmaPositive", kTH1F, {axisPt}); + histos.add("hPtNSigmaTruePositive", "hPtNSigmaTruePositive", kTH1F, {axisPt}); + + // Context detectors' data + histos.add("full/hPtTOFBeta", "full/hPtTOFBeta", kTH2F, {axisP, axisBeta}); + histos.add("full/hPtTPCSignal", "full/hPtTPCSignal", kTH2F, {axisP, axisTPCSignal}); + histos.add("full/hPtTOFNSigma", "full/hPtTOFNSigma", kTH2F, {axisP, axisNSigma}); + histos.add("full/hPtTPCNSigma", "full/hPtTPCNSigma", kTH2F, {axisP, axisNSigma}); + + histos.add("hPtTOFNSigma", "hPtTOFNSigma", kTH2F, {axisP, axisNSigma}); + histos.add("hPtTPCNSigma", "hPtTPCNSigma", kTH2F, {axisP, axisNSigma}); + } + + void process(aod::Collisions const& collisions, BigTracks const& tracks, aod::BCsWithTimestamps const&, aod::McParticles const& mcParticles) + { + auto bc = collisions.iteratorAt(0).bc_as(); + if (cfgUseCCDB && bc.runNumber() != currentRunNumber) { + uint64_t timestamp = cfgUseFixedTimestamp ? cfgTimestamp.value : bc.timestamp(); + pidModel = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, timestamp, + cfgPid.value, cfgCertainty.value, &cfgDetectorsPLimits.value[0]); + } + + for (auto& mcPart : mcParticles) { + // eta cut is included in requireGlobalTrackInFilter() so we cut it only here + if (mcPart.isPhysicalPrimary() && TMath::Abs(mcPart.eta()) < kGlobalEtaCut && mcPart.pdgCode() == pidModel.mPid) { + histos.fill(HIST("hPtMCPositive"), mcPart.pt()); + } + } + + for (auto& track : tracks) { + if (track.has_mcParticle()) { + auto mcPart = track.mcParticle(); + if (mcPart.isPhysicalPrimary()) { + bool mlAccepted = pidModel.applyModelBoolean(track); + nSigma_t nSigma = GetNSigma(track); + bool nSigmaAccepted = IsNSigmaAccept(track, nSigma); + + LOGF(debug, "collision id: %d track id: %d mlAccepted: %d nSigmaAccepted: %d p: %.3f; x: %.3f, y: %.3f, z: %.3f", + track.collisionId(), track.index(), mlAccepted, nSigmaAccepted, track.p(), track.x(), track.y(), track.z()); + + if (mcPart.pdgCode() == pidModel.mPid) { + histos.fill(HIST("full/hPtTOFNSigma"), track.p(), nSigma.tof); + histos.fill(HIST("full/hPtTPCNSigma"), track.p(), nSigma.tpc); + histos.fill(HIST("hPtMCTracked"), track.pt()); + } + + histos.fill(HIST("full/hPtTOFBeta"), track.pt(), track.beta()); + histos.fill(HIST("full/hPtTPCSignal"), track.pt(), track.tpcSignal()); + + if (mlAccepted) { + if (mcPart.pdgCode() == pidModel.mPid) { + histos.fill(HIST("hPtMLTruePositive"), track.pt()); + } + histos.fill(HIST("hPtMLPositive"), track.pt()); + } + + if (nSigmaAccepted) { + histos.fill(HIST("hPtTOFNSigma"), track.p(), nSigma.tof); + histos.fill(HIST("hPtTPCNSigma"), track.p(), nSigma.tpc); + + if (mcPart.pdgCode() == pidModel.mPid) { + histos.fill(HIST("hPtNSigmaTruePositive"), track.pt()); + } + histos.fill(HIST("hPtNSigmaPositive"), track.pt()); + } + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Tools/PIDML/pidMLProducer.cxx b/Tools/PIDML/pidMLProducer.cxx new file mode 100644 index 00000000000..67cf4308a5e --- /dev/null +++ b/Tools/PIDML/pidMLProducer.cxx @@ -0,0 +1,341 @@ +// 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 pidMLProducer.cxx +/// \brief Produce PID ML skimmed data from MC or data files. +/// +/// \author Maja Kabus +/// \author Marek Mytkowski + +#include +#include "Framework/AnalysisTask.h" +#include "Framework/StaticFor.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Tools/PIDML/pidML.h" +#include "Tools/PIDML/pidUtils.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace pidml::pidutils; + +// Naming convention +// Data: experimental data without simulation +// MC: experimental data with Monte Carlo simulation +// ML: only columns used by Machine Learning network +struct PidMlProducer { + Produces pidTracksTableDataML; + Produces pidTracksTableData; + Produces pidTracksTableMCML; + Produces pidTracksTableMC; + + Filter trackFilter = requireGlobalTrackInFilter(); + + // Data tracks + using BigTracksDataML = soa::Filtered>; + using BigTracksData = soa::Filtered>; + + // MC tracks + using BigTracksMCML = soa::Filtered>; + using BigTracksMC = soa::Filtered>; + + using MyCollisionML = aod::Collisions::iterator; + using MyCollision = soa::Join::iterator; + + static constexpr uint32_t nCharges = 2; + + static constexpr std::string_view histPrefixes[nCharges] = {"minus", "plus"}; + + // 2D + std::array, nCharges> hTPCSigvsP; + std::array, nCharges> hTOFBetavsP; + std::array, nCharges> hTOFSigvsP; + std::array, nCharges> hFilteredTOFSigvsP; + std::array, nCharges> hTRDPattvsP; + std::array, nCharges> hTRDSigvsP; + + // 1D + std::array, nCharges> hP; + std::array, nCharges> hPt; + std::array, nCharges> hPx; + std::array, nCharges> hPy; + std::array, nCharges> hPz; + std::array, nCharges> hX; + std::array, nCharges> hY; + std::array, nCharges> hZ; + std::array, nCharges> hAlpha; + std::array, nCharges> hTrackType; + std::array, nCharges> hTPCNClsShared; + std::array, nCharges> hDcaXY; + std::array, nCharges> hDcaZ; + std::array, nCharges> hPdgCode; + std::array, nCharges> hIsPrimary; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + static const char* genTagvsP(const char* name) + { + return Form("%s vs #it{p};#it{p} (GeV/#it{c});%s", name, name); + } + + template + void initHistSign() + { + hTPCSigvsP[prefixInd] = registry.add(Form("%s/hTPCSigvsP", histPrefixes[prefixInd].data()), genTagvsP("TPC Signal"), HistType::kTH2F, {{500, 0., 10.}, {1000, 0., 600.}}); + hTOFBetavsP[prefixInd] = registry.add(Form("%s/hTOFBetavsP", histPrefixes[prefixInd].data()), genTagvsP("TOF beta"), HistType::kTH2F, {{500, 0., 10.}, {6000, -3., 3.}}); + hTOFSigvsP[prefixInd] = registry.add(Form("%s/hTOFSigvsP", histPrefixes[prefixInd].data()), genTagvsP("TOF signal"), HistType::kTH2F, {{500, 0., 10.}, {10000, -5000., 80000.}}); + hFilteredTOFSigvsP[prefixInd] = registry.add(Form("%s/filtered/hTOFSigvsP", histPrefixes[prefixInd].data()), genTagvsP("TOF signal (filtered)"), HistType::kTH2F, {{500, 0., 10.}, {10000, -5000., 80000.}}); + hTRDPattvsP[prefixInd] = registry.add(Form("%s/hTRDPattvsP", histPrefixes[prefixInd].data()), genTagvsP("TRD pattern"), HistType::kTH2F, {{500, 0., 10.}, {110, -10., 100.}}); + hTRDSigvsP[prefixInd] = registry.add(Form("%s/hTRDSigvsP", histPrefixes[prefixInd].data()), genTagvsP("TRD signal"), HistType::kTH2F, {{500, 0., 10.}, {2500, -2., 100.}}); + hP[prefixInd] = registry.add(Form("%s/hP", histPrefixes[prefixInd].data()), "#it{p};#it{p} (GeV/#it{c})", HistType::kTH1F, {{500, 0., 6.}}); + hPt[prefixInd] = registry.add(Form("%s/hPt", histPrefixes[prefixInd].data()), "#it{p}_{t};#it{p}_{t} (GeV/#it{c})", HistType::kTH1F, {{500, 0., 6.}}); + hPx[prefixInd] = registry.add(Form("%s/hPx", histPrefixes[prefixInd].data()), "#it{p}_{x};#it{p}_{x} (GeV/#it{c})", HistType::kTH1F, {{1000, -6., 6.}}); + hPy[prefixInd] = registry.add(Form("%s/hPy", histPrefixes[prefixInd].data()), "#it{p}_{y};#it{p}_{y} (GeV/#it{c})", HistType::kTH1F, {{1000, -6., 6.}}); + hPz[prefixInd] = registry.add(Form("%s/hPz", histPrefixes[prefixInd].data()), "#it{p}_{z};#it{p}_{z} (GeV/#it{c})", HistType::kTH1F, {{1000, -6., 6.}}); + hX[prefixInd] = registry.add(Form("%s/hX", histPrefixes[prefixInd].data()), "#it{x};#it{x}", HistType::kTH1F, {{1000, -2., 2.}}); + hY[prefixInd] = registry.add(Form("%s/hY", histPrefixes[prefixInd].data()), "#it{y};#it{y}", HistType::kTH1F, {{1000, -2., 2.}}); + hZ[prefixInd] = registry.add(Form("%s/hZ", histPrefixes[prefixInd].data()), "#it{z};#it{z}", HistType::kTH1F, {{1000, -10., 10.}}); + hAlpha[prefixInd] = registry.add(Form("%s/hAlpha", histPrefixes[prefixInd].data()), "alpha;alpha", HistType::kTH1F, {{1000, -5., 5.}}); + hTrackType[prefixInd] = registry.add(Form("%s/hTrackType", histPrefixes[prefixInd].data()), "Track Type;Track Type", HistType::kTH1F, {{300, 0., 300.}}); + hTPCNClsShared[prefixInd] = registry.add(Form("%s/hTPCNClsShared", histPrefixes[prefixInd].data()), "hTPCNClsShared;hTPCNClsShared", HistType::kTH1F, {{100, 0., 100.}}); + hDcaXY[prefixInd] = registry.add(Form("%s/hDcaXY", histPrefixes[prefixInd].data()), "#it{DcaXY};#it{DcaXY}", HistType::kTH1F, {{1000, -1., 1.}}); + hDcaZ[prefixInd] = registry.add(Form("%s/hDcaZ", histPrefixes[prefixInd].data()), "#it{DcaZ};#it{DcaZ}", HistType::kTH1F, {{1000, -1., 1.}}); + } + + template + void initHistSignMC() + { + initHistSign(); + hPdgCode[prefixInd] = registry.add(Form("%s/hPdgCode", histPrefixes[prefixInd].data()), "#it{PdgCode};#it{PdgCode}", HistType::kTH1F, {{2500, 0., 2500.}}); + hIsPrimary[prefixInd] = registry.add(Form("%s/hIsPrimary", histPrefixes[prefixInd].data()), "#it{IsPrimary};#it{IsPrimary}", HistType::kTH1F, {{4, -0.5, 1.5}}); + } + + template + void fillHistSign(const T& track) + { + hTPCSigvsP[prefixInd]->Fill(track.p(), track.tpcSignal()); + hTOFBetavsP[prefixInd]->Fill(track.p(), track.beta()); + hTOFSigvsP[prefixInd]->Fill(track.p(), track.tofSignal()); + if (tofMissing(track)) { + hFilteredTOFSigvsP[prefixInd]->Fill(track.p(), kTOFMissingSignal); + } else { + hFilteredTOFSigvsP[prefixInd]->Fill(track.p(), track.tofSignal()); + } + hTRDPattvsP[prefixInd]->Fill(track.p(), track.trdPattern()); + hTRDSigvsP[prefixInd]->Fill(track.p(), track.trdSignal()); + hP[prefixInd]->Fill(track.p()); + hPt[prefixInd]->Fill(track.pt()); + hPx[prefixInd]->Fill(track.px()); + hPy[prefixInd]->Fill(track.py()); + hPz[prefixInd]->Fill(track.pz()); + hX[prefixInd]->Fill(track.x()); + hY[prefixInd]->Fill(track.y()); + hZ[prefixInd]->Fill(track.z()); + hAlpha[prefixInd]->Fill(track.alpha()); + hTrackType[prefixInd]->Fill(track.trackType()); + hTPCNClsShared[prefixInd]->Fill(track.tpcNClsShared()); + hDcaXY[prefixInd]->Fill(track.dcaXY()); + hDcaZ[prefixInd]->Fill(track.dcaZ()); + } + + template + void fillHistSignMC(const T& track, uint32_t pdgCode, uint8_t isPrimary) + { + fillHistSign(track); + hPdgCode[prefixInd]->Fill(pdgCode); + hIsPrimary[prefixInd]->Fill(isPrimary); + } + + template + void fillHistMC(const T& track, uint32_t pdgCode, uint8_t isPrimary) + { + if (track.sign() < 0) { + fillHistSignMC<0>(track, pdgCode, isPrimary); + } else { + fillHistSignMC<1>(track, pdgCode, isPrimary); + } + } + + template + void fillHist(const T& track) + { + if (track.sign() < 0) { + fillHistSign<0>(track); + } else { + fillHistSign<1>(track); + } + } + + void init(InitContext&) + { + if (doprocessMcMl || doprocessMcAll) { + initHistSignMC<0>(); + initHistSignMC<1>(); + } else { + initHistSign<0>(); + initHistSign<1>(); + } + } + + template + float getTOFSignal(T const& track) + { + return tofMissing(track) ? std::numeric_limits::quiet_NaN() : track.tofSignal(); + } + + template + float getTOFBeta(T const& track) + { + return tofMissing(track) ? std::numeric_limits::quiet_NaN() : track.beta(); + } + + template + float getTRDSignal(T const& track) + { + return trdMissing(track) ? std::numeric_limits::quiet_NaN() : track.trdSignal(); + } + + template + uint8_t getTRDPattern(T const& track) + { + return trdMissing(track) ? static_cast(0U) : track.trdPattern(); + } + + void processDataML(MyCollisionML const& /*collision*/, BigTracksDataML const& tracks) + { + for (const auto& track : tracks) { + pidTracksTableDataML(track.tpcSignal(), getTRDSignal(track), getTRDPattern(track), + getTOFSignal(track), getTOFBeta(track), + track.p(), track.pt(), track.px(), track.py(), track.pz(), + track.sign(), + track.x(), track.y(), track.z(), + track.alpha(), + track.trackType(), + track.tpcNClsShared(), + track.dcaXY(), track.dcaZ()); + + fillHist(track); + } + } + PROCESS_SWITCH(PidMlProducer, processDataML, "Produce only ML real data", true); + + void processDataAll(MyCollision const& collision, BigTracksData const& tracks) + { + for (const auto& track : tracks) { + pidTracksTableData(collision.centRun2V0M(), + collision.multFV0A(), collision.multFV0C(), collision.multFV0M(), + collision.multFT0A(), collision.multFT0C(), collision.multFT0M(), + collision.multZNA(), collision.multZNC(), + collision.multTracklets(), collision.multTPC(), + track.tpcSignal(), getTRDSignal(track), getTRDPattern(track), + track.trackEtaEmcal(), track.trackPhiEmcal(), + getTOFSignal(track), getTOFBeta(track), + track.p(), track.pt(), track.px(), track.py(), track.pz(), + track.sign(), + track.x(), track.y(), track.z(), + track.alpha(), + track.trackType(), + track.tpcNClsShared(), + track.dcaXY(), track.dcaZ(), + track.tpcNSigmaEl(), track.tpcExpSigmaEl(), track.tpcExpSignalDiffEl(), + track.tofNSigmaEl(), track.tofExpSigmaEl(), track.tofExpSignalDiffEl(), + track.tpcNSigmaMu(), track.tpcExpSigmaMu(), track.tpcExpSignalDiffMu(), + track.tofNSigmaMu(), track.tofExpSigmaMu(), track.tofExpSignalDiffMu(), + track.tpcNSigmaPi(), track.tpcExpSigmaPi(), track.tpcExpSignalDiffPi(), + track.tofNSigmaPi(), track.tofExpSigmaPi(), track.tofExpSignalDiffPi(), + track.tpcNSigmaKa(), track.tpcExpSigmaKa(), track.tpcExpSignalDiffKa(), + track.tofNSigmaKa(), track.tofExpSigmaKa(), track.tofExpSignalDiffKa(), + track.tpcNSigmaPr(), track.tpcExpSigmaPr(), track.tpcExpSignalDiffPr(), + track.tofNSigmaPr(), track.tofExpSigmaPr(), track.tofExpSignalDiffPr()); + + fillHist(track); + } + } + PROCESS_SWITCH(PidMlProducer, processDataAll, "Produce all real data", false); + + void processMcMl(MyCollisionML const& /*collision*/, BigTracksMCML const& tracks, aod::McParticles const& /*mctracks*/) + { + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + continue; + } + const auto mcParticle = track.mcParticle_as(); + uint8_t isPrimary = static_cast(mcParticle.isPhysicalPrimary()); + uint32_t pdgCode = mcParticle.pdgCode(); + pidTracksTableMCML(track.tpcSignal(), getTRDSignal(track), getTRDPattern(track), + getTOFSignal(track), getTOFBeta(track), + track.p(), track.pt(), track.px(), track.py(), track.pz(), + track.sign(), + track.x(), track.y(), track.z(), + track.alpha(), + track.trackType(), + track.tpcNClsShared(), + track.dcaXY(), track.dcaZ(), + pdgCode, + isPrimary); + + fillHistMC(track, pdgCode, isPrimary); + } + } + PROCESS_SWITCH(PidMlProducer, processMcMl, "Produce only ML MC essential data", false); + + void processMcAll(MyCollision const& collision, BigTracksMC const& tracks, aod::McParticles const& /*mctracks*/) + { + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + continue; + } + const auto mcParticle = track.mcParticle_as(); + uint8_t isPrimary = static_cast(mcParticle.isPhysicalPrimary()); + uint32_t pdgCode = mcParticle.pdgCode(); + pidTracksTableMC(collision.centRun2V0M(), + collision.multFV0A(), collision.multFV0C(), collision.multFV0M(), + collision.multFT0A(), collision.multFT0C(), collision.multFT0M(), + collision.multZNA(), collision.multZNC(), + collision.multTracklets(), collision.multTPC(), + track.tpcSignal(), getTRDSignal(track), getTRDPattern(track), + track.trackEtaEmcal(), track.trackPhiEmcal(), + getTOFSignal(track), getTOFBeta(track), + track.p(), track.pt(), track.px(), track.py(), track.pz(), + track.sign(), + track.x(), track.y(), track.z(), + track.alpha(), + track.trackType(), + track.tpcNClsShared(), + track.dcaXY(), track.dcaZ(), + track.tpcNSigmaEl(), track.tpcExpSigmaEl(), track.tpcExpSignalDiffEl(), + track.tofNSigmaEl(), track.tofExpSigmaEl(), track.tofExpSignalDiffEl(), + track.tpcNSigmaMu(), track.tpcExpSigmaMu(), track.tpcExpSignalDiffMu(), + track.tofNSigmaMu(), track.tofExpSigmaMu(), track.tofExpSignalDiffMu(), + track.tpcNSigmaPi(), track.tpcExpSigmaPi(), track.tpcExpSignalDiffPi(), + track.tofNSigmaPi(), track.tofExpSigmaPi(), track.tofExpSignalDiffPi(), + track.tpcNSigmaKa(), track.tpcExpSigmaKa(), track.tpcExpSignalDiffKa(), + track.tofNSigmaKa(), track.tofExpSigmaKa(), track.tofExpSignalDiffKa(), + track.tpcNSigmaPr(), track.tpcExpSigmaPr(), track.tpcExpSignalDiffPr(), + track.tofNSigmaPr(), track.tofExpSigmaPr(), track.tofExpSignalDiffPr(), + pdgCode, + isPrimary); + + fillHistMC(track, pdgCode, isPrimary); + } + } + PROCESS_SWITCH(PidMlProducer, processMcAll, "Produce all MC data", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/Tools/PIDML/pidMLProducerData.cxx b/Tools/PIDML/pidMLProducerData.cxx deleted file mode 100644 index 0db70ae821e..00000000000 --- a/Tools/PIDML/pidMLProducerData.cxx +++ /dev/null @@ -1,107 +0,0 @@ -// 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 pidMLProducerData.cxx -/// \brief Produce PID ML skimmed data from data files. -/// -/// \author Maja Kabus -/// -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/HistogramRegistry.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Tools/PIDML/pidML.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -#include "Framework/runDataProcessing.h" - -struct PidMlProducerData { - Produces pidTracksTableML; - Produces pidTracksTable; - - Filter trackFilter = requireGlobalTrackInFilter(); - using BigTracksML = soa::Filtered>; - using MyCollisionML = aod::Collisions::iterator; - using BigTracks = soa::Filtered>; - using MyCollision = soa::Join::iterator; - - HistogramRegistry registry{ - "registry", - {{"hTPCSigvsPt", "TPC signal vs #it{p}_{T};#it{p}_{T} (GeV/#it{c});TPC signal", {HistType::kTH2F, {{500, 0., 10.}, {1000, 0., 600.}}}}, - {"hTOFBetavsPt", "TOF beta vs #it{p}_{T};#it{p}_{T} (GeV/#it{c});TOF beta", {HistType::kTH2F, {{500, 0., 10.}, {500, 0., 2.}}}}, - {"hTRDSigvsPt", "TRD signal vs #it{p}_{T};#it{p}_{T} (GeV/#it{c});TRD signal", {HistType::kTH2F, {{500, 0., 10.}, {2500, 0., 100.}}}}}}; - - void processML(MyCollisionML const& /*collision*/, BigTracksML const& tracks) - { - for (const auto& track : tracks) { - pidTracksTableML(track.tpcSignal(), track.trdSignal(), track.trdPattern(), - track.tofSignal(), track.beta(), - track.p(), track.pt(), track.px(), track.py(), track.pz(), - track.sign(), - track.x(), track.y(), track.z(), - track.alpha(), - track.trackType(), - track.tpcNClsShared(), - track.dcaXY(), track.dcaZ()); - - registry.fill(HIST("hTPCSigvsPt"), track.pt(), track.tpcSignal()); - registry.fill(HIST("hTOFBetavsPt"), track.pt(), track.beta()); - registry.fill(HIST("hTRDSigvsPt"), track.pt(), track.trdSignal()); - } - } - PROCESS_SWITCH(PidMlProducerData, processML, "Produce only ML real data", true); - - void processAll(MyCollision const& collision, BigTracks const& tracks) - { - for (const auto& track : tracks) { - pidTracksTable(collision.centRun2V0M(), - collision.multFV0A(), collision.multFV0C(), collision.multFV0M(), - collision.multFT0A(), collision.multFT0C(), collision.multFT0M(), - collision.multZNA(), collision.multZNC(), - collision.multTracklets(), collision.multTPC(), - track.tpcSignal(), track.trdSignal(), track.trdPattern(), - track.trackEtaEmcal(), track.trackPhiEmcal(), - track.tofSignal(), track.beta(), - track.p(), track.pt(), track.px(), track.py(), track.pz(), - track.sign(), - track.x(), track.y(), track.z(), - track.alpha(), - track.trackType(), - track.tpcNClsShared(), - track.dcaXY(), track.dcaZ(), - track.tpcNSigmaEl(), track.tpcExpSigmaEl(), track.tpcExpSignalDiffEl(), - track.tofNSigmaEl(), track.tofExpSigmaEl(), track.tofExpSignalDiffEl(), - track.tpcNSigmaMu(), track.tpcExpSigmaMu(), track.tpcExpSignalDiffMu(), - track.tofNSigmaMu(), track.tofExpSigmaMu(), track.tofExpSignalDiffMu(), - track.tpcNSigmaPi(), track.tpcExpSigmaPi(), track.tpcExpSignalDiffPi(), - track.tofNSigmaPi(), track.tofExpSigmaPi(), track.tofExpSignalDiffPi(), - track.tpcNSigmaKa(), track.tpcExpSigmaKa(), track.tpcExpSignalDiffKa(), - track.tofNSigmaKa(), track.tofExpSigmaKa(), track.tofExpSignalDiffKa(), - track.tpcNSigmaPr(), track.tpcExpSigmaPr(), track.tpcExpSignalDiffPr(), - track.tofNSigmaPr(), track.tofExpSigmaPr(), track.tofExpSignalDiffPr()); - - registry.fill(HIST("hTPCSigvsPt"), track.pt(), track.tpcSignal()); - registry.fill(HIST("hTOFBetavsPt"), track.pt(), track.beta()); - registry.fill(HIST("hTRDSigvsPt"), track.pt(), track.trdSignal()); - } - } - PROCESS_SWITCH(PidMlProducerData, processAll, "Produce all real data", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} diff --git a/Tools/PIDML/pidMLProducerMC.cxx b/Tools/PIDML/pidMLProducerMC.cxx deleted file mode 100644 index d7362d993a3..00000000000 --- a/Tools/PIDML/pidMLProducerMC.cxx +++ /dev/null @@ -1,122 +0,0 @@ -// 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 pidMLProducerMc.cxx -/// \brief Produce PID ML skimmed data from MC files. -/// -/// \author Maja Kabus - -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/HistogramRegistry.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Tools/PIDML/pidML.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -#include "Framework/runDataProcessing.h" - -struct PidMlProducerMc { - Produces pidTracksTableML; - Produces pidTracksTable; - - Filter trackFilter = requireGlobalTrackInFilter(); - - using BigTracksML = soa::Filtered>; - using MyCollisionML = aod::Collisions::iterator; - using BigTracks = soa::Filtered>; - using MyCollision = soa::Join::iterator; - - HistogramRegistry registry{ - "registry", - {{"hTPCSigvsPt", "TPC signal vs #it{p}_{T};#it{p}_{T} (GeV/#it{c});TPC signal", {HistType::kTH2F, {{500, 0., 10.}, {1000, 0., 600.}}}}, - {"hTOFBetavsPt", "TOF beta vs #it{p}_{T};#it{p}_{T} (GeV/#it{c});TOF beta", {HistType::kTH2F, {{500, 0., 10.}, {500, 0., 2.}}}}, - {"hTRDSigvsPt", "TRD signal vs #it{p}_{T};#it{p}_{T} (GeV/#it{c});TRD signal", {HistType::kTH2F, {{500, 0., 10.}, {2500, 0., 100.}}}}}}; - - void processML(MyCollisionML const& /*collision*/, BigTracksML const& tracks, aod::McParticles const& /*mctracks*/) - { - for (const auto& track : tracks) { - if (!track.has_mcParticle()) { - continue; - } - const auto mcParticle = track.mcParticle_as(); - uint8_t isPrimary = (uint8_t)mcParticle.isPhysicalPrimary(); - pidTracksTableML(track.tpcSignal(), track.trdSignal(), track.trdPattern(), - track.tofSignal(), track.beta(), - track.p(), track.pt(), track.px(), track.py(), track.pz(), - track.sign(), - track.x(), track.y(), track.z(), - track.alpha(), - track.trackType(), - track.tpcNClsShared(), - track.dcaXY(), track.dcaZ(), - mcParticle.pdgCode(), - isPrimary); - - registry.fill(HIST("hTPCSigvsPt"), track.pt(), track.tpcSignal()); - registry.fill(HIST("hTOFBetavsPt"), track.pt(), track.beta()); - registry.fill(HIST("hTRDSigvsPt"), track.pt(), track.trdSignal()); - } - } - PROCESS_SWITCH(PidMlProducerMc, processML, "Produce only ML MC essential data", true); - - void processAll(MyCollision const& collision, BigTracks const& tracks, aod::McParticles const& /*mctracks*/) - { - for (const auto& track : tracks) { - if (!track.has_mcParticle()) { - continue; - } - const auto mcParticle = track.mcParticle_as(); - uint8_t isPrimary = (uint8_t)mcParticle.isPhysicalPrimary(); - pidTracksTable(collision.centRun2V0M(), - collision.multFV0A(), collision.multFV0C(), collision.multFV0M(), - collision.multFT0A(), collision.multFT0C(), collision.multFT0M(), - collision.multZNA(), collision.multZNC(), - collision.multTracklets(), collision.multTPC(), - track.tpcSignal(), track.trdSignal(), track.trdPattern(), - track.trackEtaEmcal(), track.trackPhiEmcal(), - track.tofSignal(), track.beta(), - track.p(), track.pt(), track.px(), track.py(), track.pz(), - track.sign(), - track.x(), track.y(), track.z(), - track.alpha(), - track.trackType(), - track.tpcNClsShared(), - track.dcaXY(), track.dcaZ(), - track.tpcNSigmaEl(), track.tpcExpSigmaEl(), track.tpcExpSignalDiffEl(), - track.tofNSigmaEl(), track.tofExpSigmaEl(), track.tofExpSignalDiffEl(), - track.tpcNSigmaMu(), track.tpcExpSigmaMu(), track.tpcExpSignalDiffMu(), - track.tofNSigmaMu(), track.tofExpSigmaMu(), track.tofExpSignalDiffMu(), - track.tpcNSigmaPi(), track.tpcExpSigmaPi(), track.tpcExpSignalDiffPi(), - track.tofNSigmaPi(), track.tofExpSigmaPi(), track.tofExpSignalDiffPi(), - track.tpcNSigmaKa(), track.tpcExpSigmaKa(), track.tpcExpSignalDiffKa(), - track.tofNSigmaKa(), track.tofExpSigmaKa(), track.tofExpSignalDiffKa(), - track.tpcNSigmaPr(), track.tpcExpSigmaPr(), track.tpcExpSignalDiffPr(), - track.tofNSigmaPr(), track.tofExpSigmaPr(), track.tofExpSignalDiffPr(), - mcParticle.pdgCode(), - isPrimary); - - registry.fill(HIST("hTPCSigvsPt"), track.pt(), track.tpcSignal()); - registry.fill(HIST("hTOFBetavsPt"), track.pt(), track.beta()); - registry.fill(HIST("hTRDSigvsPt"), track.pt(), track.trdSignal()); - } - } - PROCESS_SWITCH(PidMlProducerMc, processAll, "Produce all MC data", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} diff --git a/Tools/PIDML/pidOnnxInterface.h b/Tools/PIDML/pidOnnxInterface.h index 0cf8b473d4a..03e7bc19146 100644 --- a/Tools/PIDML/pidOnnxInterface.h +++ b/Tools/PIDML/pidOnnxInterface.h @@ -36,17 +36,17 @@ auto certainties_v = std::vector{certainties, certainties + nPids}; // default values for the cuts constexpr double cuts[nPids][nCutVars] = {{0.0, 0.5, 0.8}, {0.0, 0.5, 0.8}, {0.0, 0.5, 0.8}, {0.0, 0.5, 0.8}, {0.0, 0.5, 0.8}, {0.0, 0.5, 0.8}}; - // row labels static const std::vector pidLabels = { "211", "321", "2212", "0211", "0321", "02212"}; // column labels static const std::vector cutVarLabels = { "TPC", "TPC + TOF", "TPC + TOF + TRD"}; + } // namespace pidml_pt_cuts struct PidONNXInterface { - PidONNXInterface(std::string& localPath, std::string& ccdbPath, bool useCCDB, o2::ccdb::CcdbApi& ccdbApi, uint64_t timestamp, std::vector const& pids, o2::framework::LabeledArray const& pTLimits, std::vector const& minCertainties, bool autoMode) : mNPids{pids.size()}, mPTLimits{pTLimits} + PidONNXInterface(std::string& localPath, std::string& ccdbPath, bool useCCDB, o2::ccdb::CcdbApi& ccdbApi, uint64_t timestamp, std::vector const& pids, o2::framework::LabeledArray const& pLimits, std::vector const& minCertainties, bool autoMode) : mNPids{pids.size()}, mPLimits{pLimits} { if (pids.size() == 0) { LOG(fatal) << "PID ML Interface needs at least 1 output pid to predict"; @@ -54,7 +54,7 @@ struct PidONNXInterface { std::set tmp; for (auto& pid : pids) { if (!tmp.insert(pid).second) { - LOG(fatal) << "PID M Interface: output pids cannot repeat!"; + LOG(fatal) << "PID ML Interface: output pids cannot repeat!"; } } @@ -68,9 +68,7 @@ struct PidONNXInterface { minCertaintiesFilled = minCertainties; } for (std::size_t i = 0; i < mNPids; i++) { - for (uint32_t j = 0; j < kNDetectors; j++) { - mModels.emplace_back(localPath, ccdbPath, useCCDB, ccdbApi, timestamp, pids[i], (PidMLDetector)(kTPCOnly + j), minCertaintiesFilled[i]); - } + mModels.emplace_back(localPath, ccdbPath, useCCDB, ccdbApi, timestamp, pids[i], minCertaintiesFilled[i], mPLimits[i]); } } PidONNXInterface() = default; @@ -84,12 +82,8 @@ struct PidONNXInterface { float applyModel(const T& track, int pid) { for (std::size_t i = 0; i < mNPids; i++) { - if (mModels[i * kNDetectors].mPid == pid) { - for (uint32_t j = 0; j < kNDetectors; j++) { - if (track.pt() >= mPTLimits[i][j] && (j == kNDetectors - 1 || track.pt() < mPTLimits[i][j + 1])) { - return mModels[i * kNDetectors + j].applyModel(track); - } - } + if (mModels[i].mPid == pid) { + return mModels[i].applyModel(track); } } LOG(error) << "No suitable PID ML model found for track: " << track.globalIndex() << " from collision: " << track.collision().globalIndex() << " and expected pid: " << pid; @@ -100,12 +94,8 @@ struct PidONNXInterface { bool applyModelBoolean(const T& track, int pid) { for (std::size_t i = 0; i < mNPids; i++) { - if (mModels[i * kNDetectors].mPid == pid) { - for (uint32_t j = 0; j < kNDetectors; j++) { - if (track.pt() >= mPTLimits[i][j] && (j == kNDetectors - 1 || track.pt() < mPTLimits[i][j + 1])) { - return mModels[i * kNDetectors + j].applyModelBoolean(track); - } - } + if (mModels[i].mPid == pid) { + return mModels[i].applyModelBoolean(track); } } LOG(error) << "No suitable PID ML model found for track: " << track.globalIndex() << " from collision: " << track.collision().globalIndex() << " and expected pid: " << pid; @@ -116,12 +106,12 @@ struct PidONNXInterface { void fillDefaultConfiguration(std::vector& minCertainties) { // FIXME: A more sophisticated strategy should be based on pid values as well - mPTLimits = o2::framework::LabeledArray{pidml_pt_cuts::cuts[0], pidml_pt_cuts::nPids, pidml_pt_cuts::nCutVars, pidml_pt_cuts::pidLabels, pidml_pt_cuts::cutVarLabels}; + mPLimits = o2::framework::LabeledArray{pidml_pt_cuts::cuts[0], pidml_pt_cuts::nPids, pidml_pt_cuts::nCutVars, pidml_pt_cuts::pidLabels, pidml_pt_cuts::cutVarLabels}; minCertainties = std::vector(mNPids, 0.5); } std::vector mModels; std::size_t mNPids; - o2::framework::LabeledArray mPTLimits; + o2::framework::LabeledArray mPLimits; }; #endif // TOOLS_PIDML_PIDONNXINTERFACE_H_ diff --git a/Tools/PIDML/pidOnnxModel.h b/Tools/PIDML/pidOnnxModel.h index 7cdb43e0e9a..207bc18cd8e 100644 --- a/Tools/PIDML/pidOnnxModel.h +++ b/Tools/PIDML/pidOnnxModel.h @@ -17,18 +17,27 @@ #ifndef TOOLS_PIDML_PIDONNXMODEL_H_ #define TOOLS_PIDML_PIDONNXMODEL_H_ +#include +#include +#include #include #include #include #include #include #include +#if __has_include() +#include +#else +#include +#endif -#include "onnxruntime/core/session/experimental_onnxruntime_cxx_api.h" #include "rapidjson/document.h" #include "rapidjson/filereadstream.h" - #include "CCDB/CcdbApi.h" +#include "Tools/PIDML/pidUtils.h" + +using namespace pidml::pidutils; enum PidMLDetector { kTPCOnly = 0, @@ -37,6 +46,13 @@ enum PidMLDetector { kNDetectors ///< number of available detectors configurations }; +namespace pidml_pt_cuts +{ +// TODO: for now first limit wouldn't be used, +// network needs TPC, so we can either do not cut it by p or return 0.0f as prediction +constexpr std::array defaultModelPLimits({0.0, 0.5, 0.8}); +} // namespace pidml_pt_cuts + // TODO: Copied from cefpTask, shall we put it in some common utils code? namespace { @@ -59,21 +75,45 @@ bool readJsonFile(const std::string& config, rapidjson::Document& d) struct PidONNXModel { public: - PidONNXModel(std::string& localPath, std::string& ccdbPath, bool useCCDB, o2::ccdb::CcdbApi& ccdbApi, uint64_t timestamp, int pid, PidMLDetector detector, double minCertainty) : mDetector(detector), mPid(pid), mMinCertainty(minCertainty) + PidONNXModel(std::string& localPath, std::string& ccdbPath, bool useCCDB, o2::ccdb::CcdbApi& ccdbApi, uint64_t timestamp, + int pid, double minCertainty, const double* pLimits = &pidml_pt_cuts::defaultModelPLimits[0]) + : mPid(pid), mMinCertainty(minCertainty), mPLimits(pLimits, pLimits + kNDetectors) { + assert(mPLimits.size() == kNDetectors); + std::string modelFile; loadInputFiles(localPath, ccdbPath, useCCDB, ccdbApi, timestamp, pid, modelFile); Ort::SessionOptions sessionOptions; mEnv = std::make_shared(ORT_LOGGING_LEVEL_WARNING, "pid-onnx-inferer"); LOG(info) << "Loading ONNX model from file: " << modelFile; +#if __has_include() mSession.reset(new Ort::Experimental::Session{*mEnv, modelFile, sessionOptions}); +#else + mSession.reset(new Ort::Session{*mEnv, modelFile.c_str(), sessionOptions}); +#endif LOG(info) << "ONNX model loaded"; +#if __has_include() mInputNames = mSession->GetInputNames(); mInputShapes = mSession->GetInputShapes(); mOutputNames = mSession->GetOutputNames(); mOutputShapes = mSession->GetOutputShapes(); +#else + Ort::AllocatorWithDefaultOptions tmpAllocator; + for (size_t i = 0; i < mSession->GetInputCount(); ++i) { + mInputNames.push_back(mSession->GetInputNameAllocated(i, tmpAllocator).get()); + } + for (size_t i = 0; i < mSession->GetInputCount(); ++i) { + mInputShapes.emplace_back(mSession->GetInputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape()); + } + for (size_t i = 0; i < mSession->GetOutputCount(); ++i) { + mOutputNames.push_back(mSession->GetOutputNameAllocated(i, tmpAllocator).get()); + } + for (size_t i = 0; i < mSession->GetOutputCount(); ++i) { + mOutputShapes.emplace_back(mSession->GetOutputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape()); + } +#endif LOG(debug) << "Input Node Name/Shape (" << mInputNames.size() << "):"; for (size_t i = 0; i < mInputNames.size(); i++) { @@ -107,27 +147,21 @@ struct PidONNXModel { return getModelOutput(track) >= mMinCertainty; } - PidMLDetector mDetector; int mPid; double mMinCertainty; private: void getModelPaths(std::string const& path, std::string& modelDir, std::string& modelFile, std::string& modelPath, int pid, std::string const& ext) { - modelDir = path + "/TPC"; - if (mDetector >= kTPCTOF) { - modelDir += "_TOF"; - } - if (mDetector >= kTPCTOFTRD) { - modelDir += "_TRD"; - } + modelDir = path; + modelFile = "attention_model_"; - modelFile = "simple_model_"; if (pid < 0) { modelFile += "0" + std::to_string(-pid); } else { modelFile += std::to_string(pid); } + modelFile += ext; modelPath = modelDir + "/" + modelFile; } @@ -184,49 +218,65 @@ struct PidONNXModel { { // TODO: Hardcoded for now. Planning to implement RowView extension to get runtime access to selected columns // sign is short, trackType and tpcNClsShared uint8_t - float scaledX = (track.x() - mScalingParams.at("fX").first) / mScalingParams.at("fX").second; - float scaledY = (track.y() - mScalingParams.at("fY").first) / mScalingParams.at("fY").second; - float scaledZ = (track.z() - mScalingParams.at("fZ").first) / mScalingParams.at("fZ").second; - float scaledAlpha = (track.alpha() - mScalingParams.at("fAlpha").first) / mScalingParams.at("fAlpha").second; - float scaledTPCNClsShared = (static_cast(track.tpcNClsShared()) - mScalingParams.at("fTPCNClsShared").first) / mScalingParams.at("fTPCNClsShared").second; - float scaledDcaXY = (track.dcaXY() - mScalingParams.at("fDcaXY").first) / mScalingParams.at("fDcaXY").second; - float scaledDcaZ = (track.dcaZ() - mScalingParams.at("fDcaZ").first) / mScalingParams.at("fDcaZ").second; float scaledTPCSignal = (track.tpcSignal() - mScalingParams.at("fTPCSignal").first) / mScalingParams.at("fTPCSignal").second; - std::vector inputValues{track.px(), track.py(), track.pz(), static_cast(track.sign()), scaledX, scaledY, scaledZ, scaledAlpha, static_cast(track.trackType()), scaledTPCNClsShared, scaledDcaXY, scaledDcaZ, track.p(), scaledTPCSignal}; + std::vector inputValues{scaledTPCSignal}; - if (mDetector >= kTPCTOF) { + // When TRD Signal shouldn't be used we pass quiet_NaNs to the network + if (!inPLimit(track, mPLimits[kTPCTOFTRD]) || trdMissing(track)) { + inputValues.push_back(std::numeric_limits::quiet_NaN()); + inputValues.push_back(std::numeric_limits::quiet_NaN()); + } else { + float scaledTRDSignal = (track.trdSignal() - mScalingParams.at("fTRDSignal").first) / mScalingParams.at("fTRDSignal").second; + inputValues.push_back(scaledTRDSignal); + inputValues.push_back(track.trdPattern()); + } + + // When TOF Signal shouldn't be used we pass quiet_NaNs to the network + if (!inPLimit(track, mPLimits[kTPCTOF]) || tofMissing(track)) { + inputValues.push_back(std::numeric_limits::quiet_NaN()); + inputValues.push_back(std::numeric_limits::quiet_NaN()); + } else { float scaledTOFSignal = (track.tofSignal() - mScalingParams.at("fTOFSignal").first) / mScalingParams.at("fTOFSignal").second; float scaledBeta = (track.beta() - mScalingParams.at("fBeta").first) / mScalingParams.at("fBeta").second; inputValues.push_back(scaledTOFSignal); inputValues.push_back(scaledBeta); } - if (mDetector >= kTPCTOFTRD) { - float scaledTRDSignal = (track.trdSignal() - mScalingParams.at("fTRDSignal").first) / mScalingParams.at("fTRDSignal").second; - float scaledTRDPattern = (track.trdPattern() - mScalingParams.at("fTRDPattern").first) / mScalingParams.at("fTRDPattern").second; - inputValues.push_back(scaledTRDSignal); - inputValues.push_back(scaledTRDPattern); - } + float scaledX = (track.x() - mScalingParams.at("fX").first) / mScalingParams.at("fX").second; + float scaledY = (track.y() - mScalingParams.at("fY").first) / mScalingParams.at("fY").second; + float scaledZ = (track.z() - mScalingParams.at("fZ").first) / mScalingParams.at("fZ").second; + float scaledAlpha = (track.alpha() - mScalingParams.at("fAlpha").first) / mScalingParams.at("fAlpha").second; + float scaledTPCNClsShared = (static_cast(track.tpcNClsShared()) - mScalingParams.at("fTPCNClsShared").first) / mScalingParams.at("fTPCNClsShared").second; + float scaledDcaXY = (track.dcaXY() - mScalingParams.at("fDcaXY").first) / mScalingParams.at("fDcaXY").second; + float scaledDcaZ = (track.dcaZ() - mScalingParams.at("fDcaZ").first) / mScalingParams.at("fDcaZ").second; - return inputValues; - } + inputValues.insert(inputValues.end(), {track.p(), track.pt(), track.px(), track.py(), track.pz(), static_cast(track.sign()), scaledX, scaledY, scaledZ, scaledAlpha, static_cast(track.trackType()), scaledTPCNClsShared, scaledDcaXY, scaledDcaZ}); - // FIXME: Temporary solution, new networks will have sigmoid layer added - float sigmoid(float x) - { - float value = std::max(-100.0f, std::min(100.0f, x)); - return 1.0f / (1.0f + std::exp(-value)); + return inputValues; } template float getModelOutput(const T& track) { + // First rank of the expected model input is -1 which means that it is dynamic axis. + // Axis is exported as dynamic to make it possible to run model inference with the batch of + // tracks at once in the future (batch would need to have the same amount of quiet_NaNs in each row). + // For now we hardcode 1. + static constexpr int64_t batch_size = 1; auto input_shape = mInputShapes[0]; + input_shape[0] = batch_size; + std::vector inputTensorValues = createInputsSingle(track); std::vector inputTensors; + +#if __has_include() inputTensors.emplace_back(Ort::Experimental::Value::CreateTensor(inputTensorValues.data(), inputTensorValues.size(), input_shape)); +#else + Ort::MemoryInfo mem_info = Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault); + inputTensors.emplace_back(Ort::Value::CreateTensor(mem_info, inputTensorValues.data(), inputTensorValues.size(), input_shape.data(), input_shape.size())); +#endif // Double-check the dimensions of the input tensor assert(inputTensors[0].IsTensor() && @@ -234,7 +284,19 @@ struct PidONNXModel { LOG(debug) << "input tensor shape: " << printShape(inputTensors[0].GetTensorTypeAndShapeInfo().GetShape()); try { +#if __has_include() auto outputTensors = mSession->Run(mInputNames, inputTensors, mOutputNames); +#else + Ort::RunOptions runOptions; + std::vector inputNamesChar(mInputNames.size(), nullptr); + std::transform(std::begin(mInputNames), std::end(mInputNames), std::begin(inputNamesChar), + [&](const std::string& str) { return str.c_str(); }); + + std::vector outputNamesChar(mOutputNames.size(), nullptr); + std::transform(std::begin(mOutputNames), std::end(mOutputNames), std::begin(outputNamesChar), + [&](const std::string& str) { return str.c_str(); }); + auto outputTensors = mSession->Run(runOptions, inputNamesChar.data(), inputTensors.data(), inputTensors.size(), outputNamesChar.data(), outputNamesChar.size()); +#endif // Double-check the dimensions of the output tensors // The number of output tensors is equal to the number of output nodes specified in the Run() call @@ -242,7 +304,7 @@ struct PidONNXModel { LOG(debug) << "output tensor shape: " << printShape(outputTensors[0].GetTensorTypeAndShapeInfo().GetShape()); const float* output_value = outputTensors[0].GetTensorData(); - float certainty = sigmoid(*output_value); // FIXME: Temporary, sigmoid will be added as network layer + float certainty = *output_value; return certainty; } catch (const Ort::Exception& exception) { LOG(error) << "Error running model inference: " << exception.what(); @@ -265,8 +327,13 @@ struct PidONNXModel { std::shared_ptr mEnv = nullptr; // No empty constructors for Session, we need a pointer +#if __has_include() std::shared_ptr mSession = nullptr; +#else + std::shared_ptr mSession = nullptr; +#endif + std::vector mPLimits; std::vector mInputNames; std::vector> mInputShapes; std::vector mOutputNames; diff --git a/Tools/PIDML/pidUtils.h b/Tools/PIDML/pidUtils.h new file mode 100644 index 00000000000..4c101e30b19 --- /dev/null +++ b/Tools/PIDML/pidUtils.h @@ -0,0 +1,46 @@ +// 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 pidUtils.h +/// \brief Common constants and functions for PID. +/// +/// \author Marek Mytkowski + +#ifndef TOOLS_PIDML_PIDUTILS_H_ +#define TOOLS_PIDML_PIDUTILS_H_ + +#include + +namespace pidml::pidutils +{ +constexpr double kTOFMissingSignal = -999.0f; +constexpr double kGlobalEtaCut = 0.8f; + +template +bool trdMissing(const T& track) +{ + return !track.hasTRD(); +} + +template +bool tofMissing(const T& track) +{ + return !track.hasTOF(); +} + +template +bool inPLimit(const T& track, double pLimit) +{ + return track.p() >= pLimit; +} +} // namespace pidml::pidutils + +#endif // TOOLS_PIDML_PIDUTILS_H_ diff --git a/Tools/PIDML/qaPidML.cxx b/Tools/PIDML/qaPidML.cxx index accd055222c..54cafc437ab 100644 --- a/Tools/PIDML/qaPidML.cxx +++ b/Tools/PIDML/qaPidML.cxx @@ -13,6 +13,8 @@ /// \author Łukasz Sawicki /// \since +#include + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" @@ -21,13 +23,12 @@ #include "Common/DataModel/PIDResponse.h" #include #include "Tools/PIDML/pidOnnxModel.h" -#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -struct pidml { +struct QaPidML { static const int maxP = 5; // nb of bins for TH1 hists static const int binsNb = 100; @@ -47,9 +48,9 @@ struct pidml { // available particles: 211, 2212, 321 static constexpr int particlesPdgCode[numParticles] = {211, 2212, 321}; - // values of track momentum when to switch from only TPC signal to combined TPC and TOF signal + // values of track momentum when to switch from only TPC signal to combined TPC and TOF signal and to TPC+TOF+TRD // i-th momentum corresponds to the i-th particle - static constexpr float pSwitchValue[numParticles] = {0.5, 0.8, 0.5}; + static constexpr double pSwitchValue[numParticles][kNDetectors] = {{0.0, 0.5, 0.8}, {0.0, 0.8, 0.8}, {0.0, 0.5, 0.8}}; HistogramRegistry histReg{ "allHistograms", @@ -244,34 +245,35 @@ struct pidml { template void fillMcHistos(const T& track, const int pdgCode) { - // pions if (pdgCode == 211) { + // pions histReg.fill(HIST("MC/211"), track.pt()); } else if (pdgCode == -211) { + // antipions histReg.fill(HIST("MC/0211"), track.pt()); - } - // protons - else if (pdgCode == 2212) { + } else if (pdgCode == 2212) { + // protons histReg.fill(HIST("MC/2212"), track.pt()); } else if (pdgCode == -2212) { + // antiprotons histReg.fill(HIST("MC/02212"), track.pt()); - } - // kaons - else if (pdgCode == 321) { + } else if (pdgCode == 321) { + // kaons histReg.fill(HIST("MC/321"), track.pt()); } else if (pdgCode == -321) { + // antikaons histReg.fill(HIST("MC/0321"), track.pt()); - } - // electrons - else if (pdgCode == 11) { + } else if (pdgCode == 11) { + // electrons histReg.fill(HIST("MC/11"), track.pt()); } else if (pdgCode == -11) { + // positrons histReg.fill(HIST("MC/011"), track.pt()); - } - // muons - else if (pdgCode == 13) { + } else if (pdgCode == 13) { + // muons histReg.fill(HIST("MC/13"), track.pt()); } else if (pdgCode == -13) { + // antimuons histReg.fill(HIST("MC/013"), track.pt()); } else { histReg.fill(HIST("MC/else"), track.pt()); @@ -326,15 +328,9 @@ struct pidml { void pidML(const T& track, const int pdgCodeMC) { float pidCertainties[3]; - if (track.p() < pSwitchValue[i]) { - pidCertainties[0] = model211TPC.applyModel(track); - pidCertainties[1] = model2212TPC.applyModel(track); - pidCertainties[2] = model321TPC.applyModel(track); - } else { - pidCertainties[0] = model211All.applyModel(track); - pidCertainties[1] = model2212All.applyModel(track); - pidCertainties[2] = model321All.applyModel(track); - } + pidCertainties[0] = model211.applyModel(track); + pidCertainties[1] = model2212.applyModel(track); + pidCertainties[2] = model321.applyModel(track); int pid = getParticlePdg(pidCertainties); // condition for sign: we want to work only with pi, p and K, without antiparticles if (pid == particlesPdgCode[i] && track.sign() == 1) { @@ -346,14 +342,10 @@ struct pidml { } } - // one model for one particle; Model with all TPC and TOF signal - PidONNXModel model211All; - PidONNXModel model2212All; - PidONNXModel model321All; - // Model with only TPC signal model - PidONNXModel model211TPC; - PidONNXModel model2212TPC; - PidONNXModel model321TPC; + // one model for one particle + PidONNXModel model211; + PidONNXModel model2212; + PidONNXModel model321; Configurable cfgPathCCDB{"ccdb-path", "Users/m/mkabus/PIDML", "base path to the CCDB directory with ONNX models"}; Configurable cfgCCDBURL{"ccdb-url", "http://alice-ccdb.cern.ch", "URL of the CCDB repository"}; @@ -368,13 +360,9 @@ struct pidml { if (cfgUseCCDB) { ccdbApi.init(cfgCCDBURL); } else { - model211All = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, -1, 211, kTPCTOF, 0.5f); - model2212All = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, -1, 2211, kTPCTOF, 0.5f); - model321All = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, -1, 321, kTPCTOF, 0.5f); - - model211TPC = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, -1, 211, kTPCOnly, 0.5f); - model2212TPC = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, -1, 2211, kTPCOnly, 0.5f); - model321TPC = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, -1, 321, kTPCOnly, 0.5f); + model211 = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, -1, 211, 0.5f, pSwitchValue[0]); + model2212 = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, -1, 2211, 0.5f, pSwitchValue[1]); + model321 = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, -1, 321, 0.5f, pSwitchValue[2]); } } @@ -384,13 +372,9 @@ struct pidml { { auto bc = collisions.iteratorAt(0).bc_as(); if (cfgUseCCDB && bc.runNumber() != currentRunNumber) { - model211All = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, bc.timestamp(), 211, kTPCTOF, 0.5f); - model2212All = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, bc.timestamp(), 2211, kTPCTOF, 0.5f); - model321All = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, bc.timestamp(), 321, kTPCTOF, 0.5f); - - model211TPC = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, bc.timestamp(), 211, kTPCOnly, 0.5f); - model2212TPC = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, bc.timestamp(), 2211, kTPCOnly, 0.5f); - model321TPC = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, bc.timestamp(), 321, kTPCOnly, 0.5f); + model211 = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, bc.timestamp(), 211, 0.5f, pSwitchValue[0]); + model2212 = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, bc.timestamp(), 2211, 0.5f, pSwitchValue[1]); + model321 = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, bc.timestamp(), 321, 0.5f, pSwitchValue[2]); } for (auto& track : tracks) { @@ -410,6 +394,6 @@ struct pidml { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), }; } diff --git a/Tools/PIDML/simpleApplyPidOnnxInterface.cxx b/Tools/PIDML/simpleApplyPidOnnxInterface.cxx index 85847320787..82f644103ed 100644 --- a/Tools/PIDML/simpleApplyPidOnnxInterface.cxx +++ b/Tools/PIDML/simpleApplyPidOnnxInterface.cxx @@ -14,6 +14,8 @@ /// /// \author Maja Kabus +#include + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "CCDB/CcdbApi.h" @@ -21,8 +23,6 @@ #include "Common/DataModel/PIDResponse.h" #include "Tools/PIDML/pidOnnxInterface.h" -#include - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; diff --git a/Tools/PIDML/simpleApplyPidOnnxModel.cxx b/Tools/PIDML/simpleApplyPidOnnxModel.cxx index 00dc843ca47..e261c1e10bc 100644 --- a/Tools/PIDML/simpleApplyPidOnnxModel.cxx +++ b/Tools/PIDML/simpleApplyPidOnnxModel.cxx @@ -14,6 +14,8 @@ /// /// \author Maja Kabus +#include + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "CCDB/CcdbApi.h" @@ -21,8 +23,6 @@ #include "Common/DataModel/PIDResponse.h" #include "Tools/PIDML/pidOnnxModel.h" -#include - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -40,7 +40,6 @@ DECLARE_SOA_TABLE(MlPidResults, "AOD", "MLPIDRESULTS", o2::soa::Index<>, mlpidre struct SimpleApplyOnnxModel { PidONNXModel pidModel; // One instance per model, e.g., one per each pid to predict - Configurable cfgDetector{"detector", kTPCTOFTRD, "What detectors to use: 0: TPC only, 1: TPC + TOF, 2: TPC + TOF + TRD"}; Configurable cfgPid{"pid", 211, "PID to predict"}; Configurable cfgCertainty{"certainty", 0.5, "Min certainty of the model to accept given particle to be of given kind"}; @@ -68,7 +67,7 @@ struct SimpleApplyOnnxModel { if (cfgUseCCDB) { ccdbApi.init(cfgCCDBURL); } else { - pidModel = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, -1, cfgPid.value, static_cast(cfgDetector.value), cfgCertainty.value); + pidModel = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, -1, cfgPid.value, cfgCertainty.value); } } @@ -77,7 +76,7 @@ struct SimpleApplyOnnxModel { auto bc = collisions.iteratorAt(0).bc_as(); if (cfgUseCCDB && bc.runNumber() != currentRunNumber) { uint64_t timestamp = cfgUseFixedTimestamp ? cfgTimestamp.value : bc.timestamp(); - pidModel = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, timestamp, cfgPid.value, static_cast(cfgDetector.value), cfgCertainty.value); + pidModel = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, timestamp, cfgPid.value, cfgCertainty.value); } for (auto& track : tracks) { diff --git a/Tutorials/CMakeLists.txt b/Tutorials/CMakeLists.txt index 8a77f3dead9..d99c71adc88 100644 --- a/Tutorials/CMakeLists.txt +++ b/Tutorials/CMakeLists.txt @@ -29,7 +29,7 @@ o2physics_add_dpl_workflow(track-iteration COMPONENT_NAME AnalysisTutorial) o2physics_add_dpl_workflow(pid - SOURCES src/pid.cxx + SOURCES src/pidTpcTof.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME AnalysisTutorial) diff --git a/Tutorials/ML/applyMlSelection.cxx b/Tutorials/ML/applyMlSelection.cxx index d33427e3c2a..dcbfb0f80e9 100644 --- a/Tutorials/ML/applyMlSelection.cxx +++ b/Tutorials/ML/applyMlSelection.cxx @@ -11,7 +11,7 @@ /// \file applyMlSelection.cxx /// \brief Showcase usage of trained ML model exported to ONNX format for candidate selection in analysis -/// \brief This is only the starting point for the tutorial. The complete task is available at https://github.com/AliceO2Group/analysis-tutorials/tree/master/o2at-3/machineLearning/MlInference +/// \brief This is only the starting point for the tutorial. The complete task is available at https://github.com/AliceO2Group/analysis-tutorials/tree/master/o2at-4/machineLearning/MlInference /// /// \author Fabio Catalano , CERN @@ -39,13 +39,13 @@ struct applyMlSelection { Configurable> binsPtMl{"binsPtMl", std::vector{1., 36.}, "pT bin limits for ML application"}; Configurable> cutDirMl{"cutDirMl", std::vector{cuts_ml::CutSmaller, cuts_ml::CutNot, cuts_ml::CutNot}, "Whether to reject score values greater or smaller than the threshold"}; Configurable> cutsMl{"cutsMl", {defaultCutsMl[0], 1, 3, {"pT bin 0"}, {"score prompt", "score non-prompt", "score bkg"}}, "ML selections per pT bin"}; - Configurable nClassesMl{"nClassesMl", (int8_t)3, "Number of classes in ML model"}; + Configurable nClassesMl{"nClassesMl", 3, "Number of classes in ML model"}; // Model file names Configurable> onnxFileNames{"onnxFileNames", std::vector{"model_onnx.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; // Bonus: CCDB configuration (needed for ML application on the GRID) Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable modelPathsCCDB{"modelPathsCCDB", "Users/f/fcatalan/O2AT3/MlInference", "Path on CCDB"}; + Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"Users/c/ciacco/O2AT4/MlInference"}, "Path on CCDB"}; Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; Filter filterDsFlag = (o2::aod::hf_track_index::hfflag & static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi))) != static_cast(0); diff --git a/Tutorials/ML/dpl-config_applyMlSelection.json b/Tutorials/ML/dpl-config_applyMlSelection.json index ddb5a42d329..592d2973bf0 100644 --- a/Tutorials/ML/dpl-config_applyMlSelection.json +++ b/Tutorials/ML/dpl-config_applyMlSelection.json @@ -41,124 +41,37 @@ }, "loadModelsFromCCDB": "false", "ccdbUrl": "http://alice-ccdb.cern.ch", - "modelPathsCCDB": "Users/f/fcatalan/O2AT3/MlInference", + "modelPathsCCDB": { + "values": [ + "Users\/c\/ciacco\/O2AT4\/MlInference" + ] + }, "timestampCCDB": "-1" }, - "internal-dpl-aod-reader": { + "aod-file-private": "AO2D_MC_Ds.root", "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": "AO2D.root" - }, - "hf-track-index-skim-creator-cascades": { - "maxDZIni": "4", - "tpcRefitV0Daugh": "1", - "ccdbPathGrpMag": "GLO/Config/GRPMagField", - "processCascades": "0", - "propagateToPCA": "1", - "cutInvMassCascLc": "1", - "ccdbPathGrp": "GLO/GRP/GRP", - "processNoCascades": "1", - "ccdbUrl": "http://alice-ccdb.cern.ch", - "doCutQuality": "1", - "nCrossedRowsMinBach": "50", - "etaMaxV0Daugh": "1.1", - "dcaXYNegToPvMin": "0.1", - "maxR": "200", - "nCrossedRowsMinV0Daugh": "50", - "useAbsDCA": "1", - "minRelChi2Change": "0.9", - "cpaV0Min": "0.995", - "useWeightedFinalPCA": "1", - "cutInvMassV0": "0.05", - "dcaXYPosToPvMin": "0.1", - "minParamChange": "0.001", - "etaMinV0Daugh": "-99999", - "fillHistograms": "1", - "isRun2": "0", - "ptCascCandMin": "-1", - "ccdbPathLut": "GLO/Param/MatLUT", - "tpcRefitBach": "1", - "ptMinV0Daugh": "0.05" - }, - "track-to-collision-association": { - "timeMargin": "500", - "bcWindowForOneSigma": "60", - "usePVAssociation": "1", - "processStandardAssoc": "0", - "processAssocWithTime": "1", - "nSigmaForTimeCompat": "4", - "includeUnassigned": "1", - "fillTableOfCollIdsPerTrack": "0", - "setTrackSelections": "1" - }, - "hf-track-index-skim-creator-lf-cascades": { - "maxDZIni": "4", - "dcaBachToPv": "0.05", - "dcaV0ToPv": "0.05", - "ccdbPathGrpMag": "GLO/Config/GRPMagField", - "v0Radius": "0.9", - "tpcNsigmaBachelor": "4", - "dcaV0Dau": "2", - "processNoLfCascades": "1", - "propagateToPCA": "1", - "ccdbPathGrp": "GLO/GRP/GRP", - "do3Prong": "0", - "v0MassWindow": "0.008", - "ccdbUrl": "http://alice-ccdb.cern.ch", - "rejDiffCollTrack": "1", - "doCutQuality": "1", - "tpcNsigmaPion": "4", - "cascRadius": "0.5", - "tpcNsigmaProton": "4", - "maxR": "200", - "useAbsDCA": "1", - "minRelChi2Change": "0.9", - "dcaPosToPv": "0.05", - "cascCosPA": "0.95", - "dcaNegToPv": "0.05", - "useWeightedFinalPCA": "1", - "dcaCascDau": "1", - "processLfCascades": "0", - "minParamChange": "0.001", - "v0CosPA": "0.95", - "fillHistograms": "1", - "isRun2": "0", - "ccdbPathLut": "GLO/Param/MatLUT" + "aod-parent-access-level": "1" }, "hf-track-index-skim-creator": { - "maxDZIni": "4", - "cutsDplusToPiKPi": { + "thresholdMlScoreDsToPiKK": { "values": [ [ - 1.75, - 2.05, - 0.7, - 0.02 - ], - [ - 1.75, - 2.05, + 0.1, 0.5, - 0.02 + 0.5 ] ] }, - "ccdbPathGrpMag": "GLO/Config/GRPMagField", - "axisNumTracks": { - "values": [ - 250, - -0.5, - 249.5 - ] - }, + "applyProtonPidForXicToPKPi": "1", "binsPtDsToKKPi": { "values": [ - 1, + 0, 5, 1000 ] @@ -167,23 +80,23 @@ "binsPtJpsiToEE": { "values": [ 0, - 0, - 0 + 5, + 1000 ] }, "cutsLcToPKPi": { "values": [ [ - 1.75, - 2.05, + 2.1, + 2.55, 0.7, - 0.02 + 0 ], [ - 1.75, - 2.05, - 0.5, - 0.02 + 2, + 2.6, + 0.85, + 0.01 ] ] }, @@ -191,11 +104,11 @@ "binsPtLcToPKPi": { "values": [ 0, - 0, - 0 + 5, + 1000 ] }, - "process2And3ProngsWithPvRefit": "0", + "minTwoTrackDecayLengthFor3Prongs": "0", "axisPvRefitDeltaY": { "values": [ 1000, @@ -207,16 +120,16 @@ "cutsJpsiToEE": { "values": [ [ - 1.65, - 2.15, - 0.5, - 100 + 0, + 0, + 2, + 0 ], [ - 1.65, - 2.15, - 0.5, - 100 + 0, + 0, + 2, + 0 ] ] }, @@ -227,25 +140,27 @@ 0.5 ] }, - "cutsD0ToPiK": { + "ccdbUrl": "http://alice-ccdb.cern.ch", + "onnxFileNames": { "values": [ [ - 1.65, - 2.15, - 0.5, - 100 + "ModelHandler_onnx_D0ToKPi.onnx" ], [ - 1.65, - 2.15, - 0.5, - 100 + "ModelHandler_onnx_DplusToPiKPi.onnx" + ], + [ + "ModelHandler_onnx_LcToPKPi.onnx" + ], + [ + "ModelHandler_onnx_DsToKKPi.onnx" + ], + [ + "" ] ] }, - "ccdbUrl": "http://alice-ccdb.cern.ch", - "debugPvRefit": "0", - "maxR": "200", + "maxTwoTrackChi2PcaFor3Prongs": "1e+10", "axisPvRefitDeltaX": { "values": [ 1000, @@ -259,372 +174,254 @@ "cutsJpsiToMuMu": { "values": [ [ - 1.65, - 2.15, - 0.5, - 100 + 0, + 0, + 2, + 0 ], [ - 1.65, - 2.15, - 0.5, - 100 + 0, + 0, + 2, + 0 ] ] }, - "debug": "0", "binsPtXicToPKPi": { "values": [ 0, - 0, - 0 - ] - }, - "cutsDsToKKPi": { - "values": [ - [ - 1.78, - 2.18, - 0.95, - 0.01 - ], - [ - 1.78, - 2.18, - 0.98, - 0.02 - ] + 5, + 1000 ] }, - "doDstar": "0", + "doDstar": "1", "binsPtDstarToD0Pi": { "values": [ 0, - 0, - 0 + 5, + 1000 ] }, "binsPtDplusToPiKPi": { "values": [ 0, - 0, - 0 + 5, + 1000 ] }, "useWeightedFinalPCA": "0", - "axisNumCands": { - "values": [ - 200, - -0.5, - 199.5 - ] - }, "cutsDstarToD0Pi": { "values": [ [ 0.17, - 0.05 + 0.12 ], [ 0.17, - 0.08 + 0.4 ] ] }, "binsPtJpsiToMuMu": { "values": [ 0, - 0, - 0 - ] - }, - "binsPtD0ToPiK": { - "values": [ - 0, - 0, - 0 + 5, + 1000 ] }, - "cutsXicToPKPi": { + "loadMlModelsFromCCDB": "1", + "minParamChange": "0.001", + "ptTolerance": "0.1", + "ccdbPathLut": "GLO/Param/MatLUT", + "applyMlForHfFilters": "0", + "maxDZIni": "4", + "cutsDplusToPiKPi": { "values": [ [ - 1.75, + 1.7, 2.05, - 0.7, - 0.02 + 0.85, + 0.01 ], [ - 1.75, - 2.05, - 0.5, + 1.6, + 2.5, + 0.9, 0.02 ] ] }, - "minParamChange": "0.001", - "processNo2And3Prongs": "0", - "ptTolerance": "0.1", - "fillHistograms": "1", - "isRun2": "0", - "ccdbPathLut": "GLO/Param/MatLUT" - }, - "ft0-corrected-table": {}, - "hf-candidate-creator-3prong-expressions": { - "processMc": "1" - }, - "hf-track-index-skim-creator-tag-sel-collisions": { - "zVertexMin": "-10", - "xVertexMax": "1", - "useSel8Trigger": "1", - "axisNumContributors": { + "ccdbPathGrpMag": "GLO/Config/GRPMagField", + "thresholdMlScoreLcToPiKP": { "values": [ - 200, - -0.5, - 199.5 + [ + 0.1, + 0.5, + 0.5 + ] ] }, - "triggerClassName": "kINT7", - "processTrigSel": "1", - "yVertexMax": "1", - "fillHistograms": "1", - "zVertexMax": "10", - "xVertexMin": "-1", - "chi2Max": "0", - "processNoTrigSel": "0", - "nContribMin": "0", - "yVertexMin": "-1" - }, - "hf-track-index-skim-creator-tag-sel-tracks": { - "etaMaxTrack2Prong": "0.8", - "useIsGlobalTrackForSoftPion": "0", - "ccdbPathGrpMag": "GLO/Config/GRPMagField", - "useIsGlobalTrackWoDCAForSoftPion": "0", - "ptMaxSoftPionForDstar": "2", - "ptMinSoftPionForDstar": "0.05", - "cutsTrack3Prong": { + "process2And3ProngsWithPvRefit": "0", + "cutsD0ToPiK": { "values": [ [ - 0, - 10 - ], - [ - 0, - 10 - ], - [ - 0, - 10 + 1.65, + 2.1, + 0.8, + 0.01 ], [ - 0, - 10 - ], + 1.6, + 5, + 0.85, + 0.01 + ] + ] + }, + "debugPvRefit": "0", + "maxR": "200", + "debug": "0", + "cutsDsToKKPi": { + "values": [ [ - 0, - 10 + 1.7, + 2.15, + 0.8, + 0.01, + 0.02 ], [ - 0, - 10 + 1.7, + 2.25, + 0.85, + 0.01, + 0.02 ] ] }, - "binsPtTrack": { + "applyProtonPidForLcToPKPi": "1", + "applyKaonPidIn3Prongs": "0", + "binsPtD0ToPiK": { "values": [ 0, - 0.5, - 1, - 1.5, - 2, - 3, + 5, 1000 ] }, - "ccdbPathGrp": "GLO/GRP/GRP", - "doPvRefit": "0", - "useIsGlobalTrackWoDCA": "1", - "axisPvRefitDeltaY": { - "values": [ - 1000, - -0.5, - 0.5 - ] - }, - "axisPvRefitDeltaZ": { - "values": [ - 1000, - -0.5, - 0.5 - ] - }, - "ptMinTrack3Prong": "0.3", - "etaMinTrack3Prong": "-99999", - "useIsQualityTrackITSForSoftPion": "1", - "ccdbUrl": "http://alice-ccdb.cern.ch", - "doCutQuality": "1", - "debugPvRefit": "0", - "ptMinTrackBach": "0.3", - "useIsGlobalTrack": "0", - "axisPvRefitDeltaX": { - "values": [ - 1000, - -0.5, - 0.5 - ] - }, - "etaMaxTrackBach": "0.8", - "cutsTrack2Prong": { + "mlModelPathCCDB": "EventFiltering/PWGHF/BDTSmeared", + "cutsXicToPKPi": { "values": [ [ - 0, - 10 - ], - [ - 0, - 10 - ], - [ - 0, - 10 - ], - [ - 0, - 10 - ], - [ - 0, - 10 + 2.1, + 2.65, + 0.8, + 0.01 ], [ - 0, - 10 + 2, + 2.7, + 0.85, + 0.01 ] ] }, - "ptMinTrack2Prong": "0.3", - "etaMinTrackBach": "-99999", - "cutsTrackDstar": { + "processNo2And3Prongs": "0", + "fillHistograms": "1", + "isRun2": "0", + "thresholdMlScoreXicToPiKP": { "values": [ [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0, - 0 + 0.1, + 0.5, + 0.5 ] ] }, - "etaMaxSoftPionForDstar": "0.8", - "etaMinTrack2Prong": "-99999", - "tpcNClsFoundMin": "70", - "etaMaxTrack3Prong": "0.8", - "fillHistograms": "1", - "isRun2": "0", - "cutsTrackBach": { + "timestampCcdbForHfFilters": "1657032422771", + "thresholdMlScoreDplusToPiKPi": { "values": [ [ - 10, - 10 - ], - [ - 10, - 10 - ], - [ - 10, - 10 - ], - [ - 10, - 10 - ], - [ - 10, - 10 - ], - [ - 10, - 10 + 0.1, + 0.5, + 0.5 ] ] }, - "etaMinSoftPionForDstar": "-99999", - "ccdbPathLut": "GLO/Param/MatLUT" + "thresholdMlScoreD0ToKPi": { + "values": [ + [ + 0.1, + 0.5, + 0.5 + ] + ] + } }, - "track-selection": { - "ptMax": "1e+10", - "produceTable": "1", - "etaMin": "-0.8", - "isRun3": "1", - "itsMatching": "1", - "etaMax": "0.8", - "compatibilityIU": "0", - "dcaSetup": "0", - "ptMin": "0.1", - "produceFBextendedTable": "-1" + "timestamp-task": { + "fatalOnInvalidTimestamp": "false", + "verbose": "false", + "rct-path": "RCT\/Info\/RunInformation", + "orbit-reset-path": "CTP\/Calib\/OrbitReset", + "ccdb-url": "http:\/\/alice-ccdb.cern.ch", + "isRun2MC": "-1" + }, + "track-propagation": { + "ccdb-url": "http:\/\/alice-ccdb.cern.ch", + "lutPath": "GLO\/Param\/MatLUT", + "geoPath": "GLO\/Config\/GeometryAligned", + "grpmagPath": "GLO\/Config\/GRPMagField", + "mVtxPath": "GLO\/Calib\/MeanVertex", + "minPropagationDistance": "5", + "trackTunerParams": "debugInfo=0|updateTrackDCAs=1|updateTrackCovMat=1|updateCurvature=0|updateCurvatureIU=1|updatePulls=1|isInputFileFromCCDB=1|pathInputFile=Users\/m\/mfaggin\/test\/inputsTrackTuner\/pp2023\/smoothHighPtMC|nameInputFile=trackTuner_DataLHC23fPass1_McLHC23k4b_run535085.root|pathFileQoverPt=Users\/h\/hsharma\/qOverPtGraphs|nameFileQoverPt=D0sigma_Data_removal_itstps_MC_LHC22b1b.root|usePvRefitCorrections=0|qOverPtMC=1|qOverPtData=1.5", + "processStandard": "false", + "processStandardWithPID": "false", + "processCovarianceMc": "false", + "processCovariance": "true", + "processCovarianceWithPID": "false" }, "bc-selection-task": { "triggerBcShift": "999", - "processRun3": "1", - "processRun2": "0" + "processRun2": "false", + "processRun3": "true" }, "event-selection-task": { "syst": "pp", - "isMC": "1", - "processRun3": "1", - "processRun2": "0", "muonSelection": "0", - "customDeltaBC": "-1" + "maxDiffZvtxFT0vsPV": "1", + "isMC": "1", + "processRun2": "false", + "processRun3": "true" }, "hf-candidate-creator-3prong": { + "propagateToPCA": "true", + "useAbsDCA": "false", + "useWeightedFinalPCA": "false", + "maxR": "200", "maxDZIni": "4", - "minRelChi2Change": "0.9", - "processNoPvRefit": "1", - "ccdbPathGrpMag": "GLO/Config/GRPMagField", - "useWeightedFinalPCA": "0", - "propagateToPCA": "1", "minParamChange": "0.001", - "ccdbPathGrp": "GLO/GRP/GRP", - "processPvRefit": "0", - "fillHistograms": "1", - "ccdbUrl": "http://alice-ccdb.cern.ch", - "isRun2": "0", - "ccdbPathLut": "GLO/Param/MatLUT", - "maxR": "200", - "useAbsDCA": "0" - }, - "track-propagation": { - "lutPath": "GLO/Param/MatLUT", - "mVtxPath": "GLO/Calib/MeanVertex", - "geoPath": "GLO/Config/GeometryAligned", - "grpmagPath": "GLO/Config/GRPMagField", - "ccdb-url": "http://alice-ccdb.cern.ch", - "minPropagationDistance": "5", - "processStandard": "0", - "processCovariance": "1" + "minRelChi2Change": "0.9", + "fillHistograms": "true", + "isRun2": "false", + "ccdbUrl": "http:\/\/alice-ccdb.cern.ch", + "ccdbPathLut": "GLO\/Param\/MatLUT", + "ccdbPathGrp": "GLO\/GRP\/GRP", + "ccdbPathGrpMag": "GLO\/Config\/GRPMagField", + "createDplus": "true", + "createDs": "true", + "createLc": "false", + "createXic": "false", + "processNoPvRefit": "true" }, - "timestamp-task": { - "rct-path": "RCT/Info/RunInformation", - "orbit-reset-path": "CTP/Calib/OrbitReset", - "ccdb-url": "http://alice-ccdb.cern.ch", - "verbose": "0", - "isRun2MC": "0" + "track-selection": { + "ptMax": "1e+10", + "produceTable": "1", + "etaMin": "-0.8", + "isRun3": "1", + "itsMatching": "1", + "etaMax": "0.8", + "compatibilityIU": "0", + "dcaSetup": "0", + "ptMin": "0.1", + "produceFBextendedTable": "-1" } -} \ No newline at end of file +} diff --git a/Tutorials/PWGCF/CMakeLists.txt b/Tutorials/PWGCF/CMakeLists.txt index 9bf7685cfeb..ad718c5289f 100644 --- a/Tutorials/PWGCF/CMakeLists.txt +++ b/Tutorials/PWGCF/CMakeLists.txt @@ -9,6 +9,7 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +add_subdirectory(EventPlane) add_subdirectory(FemtoFramework) add_subdirectory(FlowGenericFramework) add_subdirectory(TwoParticleCorrelations) diff --git a/Tutorials/PWGCF/EventPlane/CMakeLists.txt b/Tutorials/PWGCF/EventPlane/CMakeLists.txt new file mode 100644 index 00000000000..4e0a34d9971 --- /dev/null +++ b/Tutorials/PWGCF/EventPlane/CMakeLists.txt @@ -0,0 +1,12 @@ +# 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. + +add_subdirectory(src) diff --git a/Tutorials/PWGCF/EventPlane/README.md b/Tutorials/PWGCF/EventPlane/README.md new file mode 100644 index 00000000000..c9610b0b45c --- /dev/null +++ b/Tutorials/PWGCF/EventPlane/README.md @@ -0,0 +1,3 @@ +# O2AT - Second edition - PWG-CF + +## Event Plane hands-on session diff --git a/Tutorials/PWGCF/EventPlane/doc/README.md b/Tutorials/PWGCF/EventPlane/doc/README.md new file mode 100644 index 00000000000..c9610b0b45c --- /dev/null +++ b/Tutorials/PWGCF/EventPlane/doc/README.md @@ -0,0 +1,3 @@ +# O2AT - Second edition - PWG-CF + +## Event Plane hands-on session diff --git a/Tutorials/PWGCF/EventPlane/src/CMakeLists.txt b/Tutorials/PWGCF/EventPlane/src/CMakeLists.txt new file mode 100644 index 00000000000..86e39d138cf --- /dev/null +++ b/Tutorials/PWGCF/EventPlane/src/CMakeLists.txt @@ -0,0 +1,15 @@ +# 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(qvectors-tutorial + SOURCES qVectorstutorial.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/Tutorials/PWGCF/EventPlane/src/qVectorstutorial.cxx b/Tutorials/PWGCF/EventPlane/src/qVectorstutorial.cxx new file mode 100644 index 00000000000..b5b01185a49 --- /dev/null +++ b/Tutorials/PWGCF/EventPlane/src/qVectorstutorial.cxx @@ -0,0 +1,175 @@ +// 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. + +// C++/ROOT includes. +#include +#include +#include +#include +#include +#include +#include +#include + +// o2Physics includes. +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StaticFor.h" + +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/Core/EventPlaneHelper.h" +#include "Common/Core/TrackSelection.h" + +#include "CommonConstants/PhysicsConstants.h" + +// o2 includes. + +using namespace o2; +using namespace o2::framework; + +using MyCollisions = soa::Join; +using MyTracks = soa::Join; + +struct qVectorstutorial { + HistogramRegistry histosQA{"histosQA", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + Configurable> cfgnMods{"cfgnMods", {2}, "Modulation of interest"}; + Configurable cfgDetName{"cfgDetName", "FT0C", "The name of detector to be analyzed"}; + Configurable cfgRefAName{"cfgRefAName", "TPCpos", "The name of detector for reference A"}; + Configurable cfgRefBName{"cfgRefBName", "TPCneg", "The name of detector for reference B"}; + + Configurable cfgMinPt{"cfgMinPt", 0.15, "Minimum transverse momentum for charged track"}; + Configurable cfgMaxEta{"cfgMaxEta", 0.8, "Maximum pseudorapidiy for charged track"}; + Configurable cfgMaxDCArToPVcut{"cfgMaxDCArToPVcut", 0.1, "Maximum transverse DCA"}; + Configurable cfgMaxDCAzToPVcut{"cfgMaxDCAzToPVcut", 1.0, "Maximum longitudinal DCA"}; + + ConfigurableAxis cfgaxisQvecF{"cfgaxisQvecF", {300, -1, 1}, ""}; + ConfigurableAxis cfgaxisQvec{"cfgaxisQvec", {100, -3, 3}, ""}; + ConfigurableAxis cfgaxisCent{"cfgaxisCent", {100, 0, 100}, ""}; + + ConfigurableAxis cfgaxiscos{"cfgaxiscos", {102, -1.02, 1.02}, ""}; + ConfigurableAxis cfgaxispt{"cfgaxispt", {100, 0, 10}, ""}; + ConfigurableAxis cfgaxisCentMerged{"cfgaxisCentMerged", {20, 0, 100}, ""}; + + EventPlaneHelper helperEP; + + void init(InitContext const&) + { + AxisSpec axisCent{cfgaxisCent, "centrality"}; + AxisSpec axisQvec{cfgaxisQvec, "Q"}; + AxisSpec axisQvecF{cfgaxisQvecF, "Q"}; + AxisSpec axisEvtPl = {100, -1.0 * constants::math::PI, constants::math::PI}; + + AxisSpec axisCos{cfgaxiscos, "angle function"}; + AxisSpec axisPt{cfgaxispt, "trasverse momentum"}; + AxisSpec axisCentMerged{cfgaxisCentMerged, "merged centrality"}; + + histosQA.add(Form("histQvecV2"), "", {HistType::kTH3F, {axisQvecF, axisQvecF, axisCent}}); + histosQA.add(Form("histEvtPlV2"), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); + histosQA.add(Form("histQvecRes_SigRefAV2"), "", {HistType::kTH2F, {axisQvecF, axisCent}}); + histosQA.add(Form("histCosDetV2"), "", {HistType::kTH3F, {axisCentMerged, axisPt, axisCos}}); + } + + template + bool SelEvent(const CollType& collision) + { + if (!collision.sel8()) { + return 0; + } + if (!collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return 0; + } + if (!collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return 0; + } + if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return 0; + } + + return 1; + } + + template + bool SelTrack(const TrackType track) + { + if (track.pt() < cfgMinPt) + return false; + if (std::abs(track.eta()) > cfgMaxEta) + return false; + if (!track.passedITSNCls()) + return false; + if (!track.passedITSChi2NDF()) + return false; + if (!track.passedITSHits()) + return false; + if (!track.passedTPCCrossedRowsOverNCls()) + return false; + if (!track.passedTPCChi2NDF()) + return false; + if (!track.passedDCAxy()) + return false; + if (!track.passedDCAz()) + return false; + + return true; + } + + template + void fillHistosQvec(const CollType& collision, int nmode) + { + if (nmode == 2) { + histosQA.fill(HIST("histQvecV2"), collision.qvecFT0CReVec()[0], collision.qvecFT0CImVec()[0], collision.centFT0C()); + histosQA.fill(HIST("histEvtPlV2"), helperEP.GetEventPlane(collision.qvecFT0CReVec()[0], collision.qvecFT0CImVec()[0], nmode), collision.centFT0C()); + histosQA.fill(HIST("histQvecRes_SigRefAV2"), helperEP.GetResolution(helperEP.GetEventPlane(collision.qvecFT0CReVec()[0], collision.qvecFT0CImVec()[0], nmode), helperEP.GetEventPlane(collision.qvecTPCposReVec()[0], collision.qvecTPCposImVec()[0], nmode), nmode), collision.centFT0C()); + } + } + + template + void fillHistosFlow(const CollType& collision, const TrackType& track, int nmode) + { + if (collision.sumAmplFT0C() < 1e-4) { + return; + } + for (auto& trk : track) { + if (!SelTrack(trk)) { + continue; + } + if (nmode == 2) { + histosQA.fill(HIST("histCosDetV2"), collision.centFT0C(), trk.pt(), + std::cos(static_cast(nmode) * (trk.phi() - helperEP.GetEventPlane(collision.qvecFT0CReVec()[0], collision.qvecFT0CImVec()[0], nmode)))); + } + } + } + + void process(MyCollisions::iterator const& collision, MyTracks const& tracks) + { + if (!SelEvent(collision)) { + return; + } + for (std::size_t i = 0; i < cfgnMods->size(); i++) { + fillHistosQvec(collision, cfgnMods->at(i)); + fillHistosFlow(collision, tracks, cfgnMods->at(i)); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask1.cxx b/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask1.cxx index acb7f799a7c..369e63cbdf6 100644 --- a/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask1.cxx +++ b/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask1.cxx @@ -37,7 +37,7 @@ struct CFTutorialTask1 { // TODO : // Defining filters for analysis level selections on events and tracks - // on Femto tables defined FemtoDerived.h + // on Femto tables defined in FemtoDerived.h // Filter collisionFilter = ... // Filter trackFilter = ... @@ -50,7 +50,6 @@ struct CFTutorialTask1 { // create analysis objects like histograms void init(o2::framework::InitContext&) { - // Add histograms to histogram registry HistRegistry.add("Event/hZvtx", ";Z (cm)", kTH1F, {{240, -12, 12}}); diff --git a/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask2.cxx b/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask2.cxx index 8c3adcfd542..ff5fa93aa5b 100644 --- a/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask2.cxx +++ b/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask2.cxx @@ -92,7 +92,7 @@ struct CFTutorialTask2 { HistRegistry.fill(HIST("Event/hZvtx"), col.posZ()); // TODO - // generate partition of particles 1&2 with sliceByCached method + // generate partition of particles 1 & 2 with sliceByCached method /// TODO: /// loop over particle group 1 diff --git a/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask3.cxx b/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask3.cxx index 02e7b9d9e14..ca200fd3937 100644 --- a/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask3.cxx +++ b/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask3.cxx @@ -57,13 +57,11 @@ struct CFTutorialTask3 { // ... Configurable ConfCutPartTwo{"ConfCutPartTwo", 3191978, "Particle 2 - Selection bit"}; - // additional configurables for particle 1 - // ... - - // more configurables for PID selection + // additional configurables for particle 2 // ... - /// Partitions for particle 1 and particle 2 + // Partitions for particle 1 and particle 2 + // add PID selection to partition definition Partition PartsOne = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && ((aod::femtodreamparticle::cut & ConfCutPartOne) == ConfCutPartOne); Partition PartsTwo = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && ((aod::femtodreamparticle::cut & ConfCutPartTwo) == ConfCutPartTwo); @@ -96,40 +94,27 @@ struct CFTutorialTask3 { void process(FilteredFDCollision const& col, FilteredFDParts const& /*parts*/) { - /// event QA + // event QA HistRegistry.fill(HIST("Event/hZvtx"), col.posZ()); // generate partition of particels auto GroupPartsOne = PartsOne->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); auto GroupPartsTwo = PartsTwo->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); - /// QA for particle 1 + // QA for particle 1 for (auto& part : GroupPartsOne) { - - // TODO: - // add function for PID selection from FemtoUtils - // if (PID cut) { - HistRegistry.fill(HIST("Particle1/hPt"), part.pt()); HistRegistry.fill(HIST("Particle1/hEta"), part.eta()); HistRegistry.fill(HIST("Particle1/hPhi"), part.phi()); - - // } } - /// QA for particle 2 - /// skip QA if particle 1 & 2 are the same + // QA for particle 2 + // skip QA if particle 1 & 2 are the same if (ConfIsSame.value == false) { for (auto& part : GroupPartsTwo) { - // TODO: - // add function for PID selection from FemtoUtils - // if (PID cut) { - HistRegistry.fill(HIST("Particle2/hPt"), part.pt()); HistRegistry.fill(HIST("Particle2/hEta"), part.eta()); HistRegistry.fill(HIST("Particle2/hPhi"), part.phi()); - - // } } } } diff --git a/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask4.cxx b/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask4.cxx index 943f1e5bc12..90ae5168a78 100644 --- a/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask4.cxx +++ b/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask4.cxx @@ -50,18 +50,16 @@ struct CFTutorialTask4 { Configurable ConfIsSame{"ConfIsSame", false, "Pairs of the same particle"}; Configurable ConfPDGCodePartOne{"ConfPDGCodePartOne", 2212, "Particle 1 - PDG code"}; - Configurable ConfCutPartOne{"ConfCutPartOne", 3191978, "Particle 1 - Selection bit from cutCulator"}; - Configurable ConfPIDPartOne{"ConfPIDPartOne", 0, "Particle 1 - Index in ConfTrkPIDspecies of producer task"}; - Configurable ConfPIDValuePartOne{"ConfPIDValuePartOne", 3, "Particle 1 - Read from cutCulator"}; + Configurable ConfCutPartOne{"ConfCutPartOne", 3191978, "Particle 1 - Selection bit"}; + Configurable ConfPIDTPCPartOne{"ConfPIDTPCPartOne", 2, "Particle 1 - TPC PID Selection bit"}; + Configurable ConfPIDTPCTOFPartOne{"ConfPIDTPCTOFPartOne", 4, "Particle 1 - TPCTOF PID Selection bit"}; + Configurable ConfPIDThresholdPartOne{"ConfPIDThresholdPartOne", 0.75, "Particle 1 - Momentum threshold for TPC to TPCTOF PID"}; Configurable ConfPDGCodePartTwo{"ConfPDGCodePartTwo", 2212, "Particle 2 - PDG code"}; Configurable ConfCutPartTwo{"ConfCutPartTwo", 3191978, "Particle 2 - Selection bit"}; - Configurable ConfPIDPartTwo{"ConfPIDPartTwo", 0, "Particle 2 - Index in ConfTrkPIDspecies of producer task"}; - Configurable ConfPIDValuePartTwo{"ConfPIDValuePartTwo", 3, "Particle 1 - Read from cutCulator"}; - - Configurable ConfPIDThreshold{"ConfPIDThreshold", 0.75, "Momentum threshold for TPC to TPCTOF PID"}; - Configurable ConfNspecies{"ConfNspecies", 2, "Number of particle spieces with PID info"}; - Configurable> ConfTrkPIDnSigmaMax{"ConfTrkPIDnSigmaMax", std::vector{3.f, 3.5f, 2.5f}, "This configurable needs to be the same as the one used in the producer task"}; + Configurable ConfPIDTPCPartTwo{"ConfPIDTPCPartTwo", 0, "Particle 2 - TPC PID Selection bit"}; + Configurable ConfPIDTPCTOFPartTwo{"ConfPIDTPCTOFPartTwo", 0, "Particle 2 - TPCTOF PID Selection bit"}; + Configurable ConfPIDThresholdPartTwo{"ConfPIDThresholdPartTwo", 0.75, "Particle 2 - Momentum threshold for TPC to TPCTOF PID"}; /// Partitions for particle 1 and particle 2 Partition PartsOne = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && ((aod::femtodreamparticle::cut & ConfCutPartOne) == ConfCutPartOne); @@ -105,38 +103,18 @@ struct CFTutorialTask4 { /// QA for particle 1 for (auto& part : GroupPartsOne) { - /// check PID of particle 1 using function from FemtoUtils using PID bit - if (isFullPIDSelected(part.pidcut(), - part.p(), - ConfPIDThreshold.value, - ConfPIDPartOne.value, - ConfNspecies.value, - ConfTrkPIDnSigmaMax.value, - ConfPIDValuePartOne.value, - ConfPIDValuePartOne.value)) { - HistRegistry.fill(HIST("Particle1/hPt"), part.pt()); - HistRegistry.fill(HIST("Particle1/hEta"), part.eta()); - HistRegistry.fill(HIST("Particle1/hPhi"), part.phi()); - } + HistRegistry.fill(HIST("Particle1/hPt"), part.pt()); + HistRegistry.fill(HIST("Particle1/hEta"), part.eta()); + HistRegistry.fill(HIST("Particle1/hPhi"), part.phi()); } /// QA for particle 2 /// skip QA if particle 1 & 2 are the same if (ConfIsSame.value == false) { for (auto& part : GroupPartsTwo) { - /// check PID of particle 1 using function from FemtoUtils using PID bit - if (isFullPIDSelected(part.pidcut(), - part.p(), - ConfPIDThreshold.value, - ConfPIDPartTwo.value, - ConfNspecies.value, - ConfTrkPIDnSigmaMax.value, - ConfPIDValuePartTwo.value, - ConfPIDValuePartTwo.value)) { - HistRegistry.fill(HIST("Particle2/hPt"), part.pt()); - HistRegistry.fill(HIST("Particle2/hEta"), part.eta()); - HistRegistry.fill(HIST("Particle2/hPhi"), part.phi()); - } + HistRegistry.fill(HIST("Particle2/hPt"), part.pt()); + HistRegistry.fill(HIST("Particle2/hEta"), part.eta()); + HistRegistry.fill(HIST("Particle2/hPhi"), part.phi()); } } diff --git a/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask5.cxx b/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask5.cxx index f7c0c4a815a..d9159c2e3cc 100644 --- a/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask5.cxx +++ b/Tutorials/PWGCF/FemtoFramework/src/CFTutorialTask5.cxx @@ -51,22 +51,21 @@ struct CFTutorialTask5 { Configurable ConfIsSame{"ConfIsSame", false, "Pairs of the same particle"}; Configurable ConfPDGCodePartOne{"ConfPDGCodePartOne", 2212, "Particle 1 - PDG code"}; - Configurable ConfCutPartOne{"ConfCutPartOne", 3191978, "Particle 1 - Selection bit from cutCulator"}; - Configurable ConfPIDPartOne{"ConfPIDPartOne", 0, "Particle 1 - Index in ConfTrkPIDspecies of producer task"}; - Configurable ConfPIDValuePartOne{"ConfPIDValuePartOne", 3, "Particle 1 - Read from cutCulator"}; + Configurable ConfCutPartOne{"ConfCutPartOne", 3191978, "Particle 1 - Selection bit"}; + Configurable ConfPIDTPCPartOne{"ConfPIDTPCPartOne", 2, "Particle 1 - TPC PID Selection bit"}; + Configurable ConfPIDTPCTOFPartOne{"ConfPIDTPCTOFPartOne", 4, "Particle 1 - TPCTOF PID Selection bit"}; + Configurable ConfPIDThresholdPartOne{"ConfPIDThresholdPartOne", 0.75, "Particle 1 - Momentum threshold for TPC to TPCTOF PID"}; Configurable ConfPDGCodePartTwo{"ConfPDGCodePartTwo", 2212, "Particle 2 - PDG code"}; Configurable ConfCutPartTwo{"ConfCutPartTwo", 3191978, "Particle 2 - Selection bit"}; - Configurable ConfPIDPartTwo{"ConfPIDPartTwo", 0, "Particle 2 - Index in ConfTrkPIDspecies of producer task"}; - Configurable ConfPIDValuePartTwo{"ConfPIDValuePartTwo", 3, "Particle 1 - Read from cutCulator"}; - - Configurable ConfPIDThreshold{"ConfPIDThreshold", 0.75, "Momentum threshold for TPC to TPCTOF PID"}; - Configurable ConfNspecies{"ConfNspecies", 2, "Number of particle spieces with PID info"}; - Configurable> ConfTrkPIDnSigmaMax{"ConfTrkPIDnSigmaMax", std::vector{3.f, 3.5f, 2.5f}, "This configurable needs to be the same as the one used in the producer task"}; + Configurable ConfPIDTPCPartTwo{"ConfPIDTPCPartTwo", 0, "Particle 2 - TPC PID Selection bit"}; + Configurable ConfPIDTPCTOFPartTwo{"ConfPIDTPCTOFPartTwo", 0, "Particle 2 - TPCTOF PID Selection bit"}; + Configurable ConfPIDThresholdPartTwo{"ConfPIDThresholdPartTwo", 0.75, "Particle 2 - Momentum threshold for TPC to TPCTOF PID"}; /// Partitions for particle 1 and particle 2 - Partition PartsOne = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && ((aod::femtodreamparticle::cut & ConfCutPartOne) == ConfCutPartOne); - Partition PartsTwo = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && ((aod::femtodreamparticle::cut & ConfCutPartTwo) == ConfCutPartTwo); + Partition PartsOne = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && ((aod::femtodreamparticle::cut & ConfCutPartOne) == ConfCutPartOne) && ifnode(aod::femtodreamparticle::pt < ConfPIDThresholdPartOne, ncheckbit(aod::femtodreamparticle::pidcut, ConfPIDTPCPartOne), ncheckbit(aod::femtodreamparticle::pidcut, ConfPIDTPCTOFPartOne)); + + Partition PartsTwo = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && ((aod::femtodreamparticle::cut & ConfCutPartTwo) == ConfCutPartTwo) && ifnode(aod::femtodreamparticle::pt < ConfPIDThresholdPartTwo, ncheckbit(aod::femtodreamparticle::pidcut, ConfPIDTPCPartTwo), ncheckbit(aod::femtodreamparticle::pidcut, ConfPIDTPCTOFPartTwo)); HistogramRegistry HistRegistry{"FemtoTutorial", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -104,7 +103,6 @@ struct CFTutorialTask5 { // process same event void process(FilteredFDCollision const& col, FilteredFDParts const& /*parts*/) { - /// event QA HistRegistry.fill(HIST("Event/hZvtx"), col.posZ()); @@ -114,94 +112,36 @@ struct CFTutorialTask5 { /// QA for particle 1 for (auto& part : GroupPartsOne) { - /// check PID of particle 1 using function from FemtoUtils using PID bit - if (isFullPIDSelected(part.pidcut(), - part.p(), - ConfPIDThreshold.value, - ConfPIDPartOne.value, - ConfNspecies.value, - ConfTrkPIDnSigmaMax.value, - ConfPIDValuePartOne.value, - ConfPIDValuePartOne.value)) { - HistRegistry.fill(HIST("Particle1/hPt"), part.pt()); - HistRegistry.fill(HIST("Particle1/hEta"), part.eta()); - HistRegistry.fill(HIST("Particle1/hPhi"), part.phi()); - } + HistRegistry.fill(HIST("Particle1/hPt"), part.pt()); + HistRegistry.fill(HIST("Particle1/hEta"), part.eta()); + HistRegistry.fill(HIST("Particle1/hPhi"), part.phi()); } /// QA for particle 2 /// skip QA if particle 1 & 2 are the same if (ConfIsSame.value == false) { for (auto& part : GroupPartsTwo) { - /// check PID of particle 1 using function from FemtoUtils using PID bit - if (isFullPIDSelected(part.pidcut(), - part.p(), - ConfPIDThreshold.value, - ConfPIDPartTwo.value, - ConfNspecies.value, - ConfTrkPIDnSigmaMax.value, - ConfPIDValuePartTwo.value, - ConfPIDValuePartTwo.value)) { - HistRegistry.fill(HIST("Particle2/hPt"), part.pt()); - HistRegistry.fill(HIST("Particle2/hEta"), part.eta()); - HistRegistry.fill(HIST("Particle2/hPhi"), part.phi()); - } + HistRegistry.fill(HIST("Particle2/hPt"), part.pt()); + HistRegistry.fill(HIST("Particle2/hEta"), part.eta()); + HistRegistry.fill(HIST("Particle2/hPhi"), part.phi()); } } float kstar = 0.; - float m0 = TDatabasePDG::Instance()->GetParticle(ConfPDGCodePartOne.value)->Mass(); - float m1 = TDatabasePDG::Instance()->GetParticle(ConfPDGCodePartTwo.value)->Mass(); + float m0 = o2::analysis::femtoDream::getMass(ConfPDGCodePartOne); + float m1 = o2::analysis::femtoDream::getMass(ConfPDGCodePartTwo); /// particle combinations /// if particles are the same or not determines the combination stratety if (ConfIsSame) { for (auto& [p0, p1] : combinations(soa::CombinationsStrictlyUpperIndexPolicy(GroupPartsOne, GroupPartsTwo))) { - if (isFullPIDSelected(p0.pidcut(), - p0.p(), - ConfPIDThreshold.value, - ConfPIDPartOne.value, - ConfNspecies.value, - ConfTrkPIDnSigmaMax.value, - ConfPIDValuePartOne.value, - ConfPIDValuePartOne.value) && - isFullPIDSelected(p1.pidcut(), - p1.p(), - ConfPIDThreshold.value, - ConfPIDPartOne.value, - ConfNspecies.value, - ConfTrkPIDnSigmaMax.value, - ConfPIDValuePartOne.value, - ConfPIDValuePartOne.value) - - ) { - kstar = FemtoDreamMath::getkstar(p0, m0, p1, m1); - HistRegistry.fill(HIST("Pair/hSE"), kstar); - } + kstar = FemtoDreamMath::getkstar(p0, m0, p1, m1); + HistRegistry.fill(HIST("Pair/hSE"), kstar); } } else { for (auto& [p0, p1] : combinations(soa::CombinationsFullIndexPolicy(GroupPartsOne, GroupPartsTwo))) { - if (isFullPIDSelected(p0.pidcut(), - p0.p(), - ConfPIDThreshold.value, - ConfPIDPartOne.value, - ConfNspecies.value, - ConfTrkPIDnSigmaMax.value, - ConfPIDValuePartOne.value, - ConfPIDValuePartOne.value) && - isFullPIDSelected(p1.pidcut(), - p1.p(), - ConfPIDThreshold.value, - ConfPIDPartOne.value, - ConfNspecies.value, - ConfTrkPIDnSigmaMax.value, - ConfPIDValuePartOne.value, - ConfPIDValuePartOne.value) - - ) { - kstar = FemtoDreamMath::getkstar(p0, m0, p1, m1); - HistRegistry.fill(HIST("Pair/hSE"), kstar); - } + kstar = FemtoDreamMath::getkstar(p0, m0, p1, m1); + HistRegistry.fill(HIST("Pair/hSE"), kstar); } } } diff --git a/Tutorials/PWGCF/TwoParticleCorrelations/src/firstcfcorrelations.cxx b/Tutorials/PWGCF/TwoParticleCorrelations/src/firstcfcorrelations.cxx index bd4d9dfd4f5..cdec4f3ca95 100644 --- a/Tutorials/PWGCF/TwoParticleCorrelations/src/firstcfcorrelations.cxx +++ b/Tutorials/PWGCF/TwoParticleCorrelations/src/firstcfcorrelations.cxx @@ -39,7 +39,7 @@ struct firstcorrelations { } template - void fillQA(TCollision collision, float centrality, TTracks tracks) + void fillQA(TCollision /*collision*/, float /*centrality*/, TTracks /*tracks*/) { } @@ -50,7 +50,7 @@ struct firstcorrelations { } template - void fillCorrelations(TTarget target, TTracks tracks1, TTracks tracks2, float centrality, float posZ) + void fillCorrelations(TTarget /*target*/, TTracks /*tracks1*/, TTracks /*tracks2*/, float /*centrality*/, float /*posZ*/) { } diff --git a/Tutorials/PWGHF/DataModelMini.h b/Tutorials/PWGHF/DataModelMini.h index 40a430a4813..7a03f1462b7 100644 --- a/Tutorials/PWGHF/DataModelMini.h +++ b/Tutorials/PWGHF/DataModelMini.h @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file task-mini.cxx +/// \file DataModelMini.h /// \brief Mini version of the HF analysis chain /// /// \author Vít Kučera , Inha University @@ -28,7 +28,7 @@ DECLARE_SOA_COLUMN(IsSelProng, isSelProng, bool); //! prong selection flag } // namespace hf_seltrack // Track selection table -DECLARE_SOA_TABLE(HfSelTrack, "AOD", "HFSELTRACK", //! track selection table +DECLARE_SOA_TABLE(HfTSelTrack, "AOD", "HFTSELTRACK", //! track selection table hf_seltrack::IsSelProng); namespace hf_track_index @@ -39,7 +39,7 @@ DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, Tracks, "_1"); //! prong 1 } // namespace hf_track_index // Track index skim table -DECLARE_SOA_TABLE(HfTrackIndexProng2, "AOD", "HFTRACKIDXP2", //! table with prongs indices +DECLARE_SOA_TABLE(HfT2Prongs, "AOD", "HFT2PRONG", //! table with prongs indices hf_track_index::Prong0Id, hf_track_index::Prong1Id); @@ -79,12 +79,12 @@ DECLARE_SOA_EXPRESSION_COLUMN(Pz, pz, //! pz of candidate float, 1.f * pzProng0 + 1.f * pzProng1); DECLARE_SOA_DYNAMIC_COLUMN(M, m, //! invariant mass of candidate [](float px0, float py0, float pz0, float px1, float py1, float pz1, const std::array& m) -> float { return RecoDecay::m(std::array{std::array{px0, py0, pz0}, std::array{px1, py1, pz1}}, m); }); -DECLARE_SOA_DYNAMIC_COLUMN(CPA, cpa, //! cosine of pointing angle of candidate +DECLARE_SOA_DYNAMIC_COLUMN(Cpa, cpa, //! cosine of pointing angle of candidate [](float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS, float px, float py, float pz) -> float { return RecoDecay::cpa(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}, std::array{px, py, pz}); }); } // namespace hf_cand_prong2 // Candidate table -DECLARE_SOA_TABLE(HfCandProng2Base, "AOD", "HFCANDP2BASE", //! 2-prong candidate table +DECLARE_SOA_TABLE(HfTCand2ProngBase, "AOD", "HFTCAND2PBASE", //! 2-prong candidate table hf_cand_prong2::CollisionId, collision::PosX, collision::PosY, collision::PosZ, hf_cand_prong2::XSecondaryVertex, hf_cand_prong2::YSecondaryVertex, hf_cand_prong2::ZSecondaryVertex, @@ -98,14 +98,14 @@ DECLARE_SOA_TABLE(HfCandProng2Base, "AOD", "HFCANDP2BASE", //! 2-prong candidate /* dynamic columns */ hf_cand_prong2::M, /* dynamic columns that use candidate momentum components */ - hf_cand_prong2::CPA, + hf_cand_prong2::Cpa, hf_cand_prong2::Pt); // Extended table with expression columns that can be used as arguments of dynamic columns -DECLARE_SOA_EXTENDED_TABLE_USER(HfCandProng2Ext, HfCandProng2Base, "HFCANDP2EXT", //! extension table for the 2-prong candidate table +DECLARE_SOA_EXTENDED_TABLE_USER(HfTCand2ProngExt, HfTCand2ProngBase, "HFTCAND2PEXT", //! extension table for the 2-prong candidate table hf_cand_prong2::Px, hf_cand_prong2::Py, hf_cand_prong2::Pz); -using HfCandProng2 = HfCandProng2Ext; +using HfTCand2Prong = HfTCand2ProngExt; namespace hf_selcandidate_d0 { @@ -115,7 +115,7 @@ DECLARE_SOA_COLUMN(IsSelD0bar, isSelD0bar, int); //! selection flag for D0 bar } // namespace hf_selcandidate_d0 // Candidate selection table -DECLARE_SOA_TABLE(HfSelCandidateD0, "AOD", "HFSELCANDD0", //! table with D0 selection flags +DECLARE_SOA_TABLE(HfTSelD0, "AOD", "HFTSELD0", //! table with D0 selection flags hf_selcandidate_d0::IsSelD0, hf_selcandidate_d0::IsSelD0bar); } // namespace o2::aod diff --git a/Tutorials/PWGHF/dpl-config_skim.json b/Tutorials/PWGHF/dpl-config_skim.json index 07d172b2c9d..3d78778042e 100644 --- a/Tutorials/PWGHF/dpl-config_skim.json +++ b/Tutorials/PWGHF/dpl-config_skim.json @@ -1,25 +1,27 @@ { "internal-dpl-clock": "", "internal-dpl-aod-reader": { + "aod-file-private": "AO2D.root", + "aod-max-io-rate": "0", "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": "AO2D.root" + "step-value-enumeration": "1" }, "internal-dpl-aod-spawner": "", "bc-converter": "", "timestamp-task": { + "fatalOnInvalidTimestamp": "false", "verbose": "false", "rct-path": "RCT/Info/RunInformation", "orbit-reset-path": "CTP/Calib/OrbitReset", "ccdb-url": "http://alice-ccdb.cern.ch", - "isRun2MC": "false" + "isRun2MC": "-1" }, "tracks-extra-converter": "", - "zdc-converter": "", + "tracks-extra-spawner": "", "track-propagation": { "ccdb-url": "http://alice-ccdb.cern.ch", "lutPath": "GLO/Param/MatLUT", @@ -27,8 +29,75 @@ "grpmagPath": "GLO/Config/GRPMagField", "mVtxPath": "GLO/Calib/MeanVertex", "minPropagationDistance": "83.0999985", + "useTrackTuner": "false", + "fillTrackTunerTable": "false", + "trackTunerParams": "debugInfo=0|updateTrackDCAs=1|updateTrackCovMat=1|updateCurvature=0|updateCurvatureIU=0|updatePulls=0|isInputFileFromCCDB=1|pathInputFile=Users/m/mfaggin/test/inputsTrackTuner/PbPb2022|nameInputFile=trackTuner_DataLHC22sPass5_McLHC22l1b2_run529397.root|pathFileQoverPt=Users/h/hsharma/qOverPtGraphs|nameFileQoverPt=D0sigma_Data_removal_itstps_MC_LHC22b1b.root|usePvRefitCorrections=0|qOverPtMC=-1.|qOverPtData=-1.", + "axisPtQA": { + "values": [ + "0", + "0", + "0.1", + "0.2", + "0.3", + "0.4", + "0.5", + "0.6", + "0.7", + "0.8", + "0.9", + "1", + "1.1", + "1.2", + "1.3", + "1.4", + "1.5", + "1.6", + "1.7", + "1.8", + "1.9", + "2", + "2.2", + "2.4", + "2.6", + "2.8", + "3", + "3.2", + "3.4", + "3.6", + "3.8", + "4", + "4.4", + "4.8", + "5.2", + "5.6", + "6", + "6.5", + "7", + "7.5", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "15", + "17", + "19", + "21", + "23", + "25", + "30", + "35", + "40", + "50" + ] + }, "processStandard": "false", - "processCovariance": "true" + "processStandardWithPID": "false", + "processCovarianceMc": "false", + "processCovariance": "true", + "processCovarianceWithPID": "false" }, "track-selection": { "isRun3": "true", @@ -42,12 +111,12 @@ "etaMin": "-0.8", "etaMax": "0.8" }, - "hf-track-index-skim-creator-tag-sel-tracks": { + "hf-skim-creator-mini-tag-sel-tracks": { "ptTrackMin": "0.3", "etaTrackMax": "0.8", "dcaTrackMin": "0.0025" }, - "hf-track-index-skim-creator": { + "hf-skim-creator-mini": { "magneticField": "5", "propagateToPCA": "true", "useAbsDCA": "false", diff --git a/Tutorials/PWGHF/dpl-config_task.json b/Tutorials/PWGHF/dpl-config_task.json index 719c8acd000..4e07d936675 100644 --- a/Tutorials/PWGHF/dpl-config_task.json +++ b/Tutorials/PWGHF/dpl-config_task.json @@ -1,52 +1,160 @@ { "internal-dpl-clock": "", "internal-dpl-aod-reader": { + "aod-file-private": "AnalysisResults_trees.root", + "aod-max-io-rate": "0", "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": "AnalysisResults_trees.root", - "aod-parent-access-level": "1", - "aod-parent-base-path-replacement": "old-path-to-parent;new-path-to-parent" + "step-value-enumeration": "1" }, "internal-dpl-aod-spawner": "", "bc-converter": "", "internal-dpl-aod-index-builder": "", "timestamp-task": { + "fatalOnInvalidTimestamp": "false", "verbose": "false", "rct-path": "RCT/Info/RunInformation", "orbit-reset-path": "CTP/Calib/OrbitReset", "ccdb-url": "http://alice-ccdb.cern.ch", - "isRun2MC": "false" + "isRun2MC": "-1" }, "tracks-extra-converter": "", - "zdc-converter": "", + "bc-selection-task": { + "triggerBcShift": "0", + "ITSROFrameStartBorderMargin": "-1", + "ITSROFrameEndBorderMargin": "-1", + "TimeFrameStartBorderMargin": "-1", + "TimeFrameEndBorderMargin": "-1", + "checkRunDurationLimits": "false", + "processRun2": "false", + "processRun3": "true" + }, + "tracks-extra-spawner": "", "track-propagation": { "ccdb-url": "http://alice-ccdb.cern.ch", "lutPath": "GLO/Param/MatLUT", "geoPath": "GLO/Config/GeometryAligned", "grpmagPath": "GLO/Config/GRPMagField", "mVtxPath": "GLO/Calib/MeanVertex", - "minPropagationDistance": "83.0999985", + "minPropagationDistance": "5", + "useTrackTuner": "true", + "fillTrackTunerTable": "false", + "trackTunerParams": "debugInfo=0|updateTrackDCAs=1|updateTrackCovMat=1|updateCurvature=0|updateCurvatureIU=1|updatePulls=1|isInputFileFromCCDB=1|pathInputFile=Users/m/mfaggin/test/inputsTrackTuner/pp2023/smoothHighPtMC|nameInputFile=trackTuner_DataLHC23fPass1_McLHC23k4b_run535085.root|pathFileQoverPt=Users/h/hsharma/qOverPtGraphs|nameFileQoverPt=D0sigma_Data_removal_itstps_MC_LHC22b1b.root|usePvRefitCorrections=0|qOverPtMC=1|qOverPtData=2", + "axisPtQA": { + "values": [ + "0", + "0", + "0.1", + "0.2", + "0.3", + "0.4", + "0.5", + "0.6", + "0.7", + "0.8", + "0.9", + "1", + "1.1", + "1.2", + "1.3", + "1.4", + "1.5", + "1.6", + "1.7", + "1.8", + "1.9", + "2", + "2.2", + "2.4", + "2.6", + "2.8", + "3", + "3.2", + "3.4", + "3.6", + "3.8", + "4", + "4.4", + "4.8", + "5.2", + "5.6", + "6", + "6.5", + "7", + "7.5", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "15", + "17", + "19", + "21", + "23", + "25", + "30", + "35", + "40", + "50" + ] + }, "processStandard": "false", - "processCovariance": "true" + "processStandardWithPID": "false", + "processCovarianceMc": "false", + "processCovariance": "true", + "processCovarianceWithPID": "false" }, - "bc-selection-task": { - "triggerBcShift": "999", - "processRun2": "false", - "processRun3": "true" + "tof-signal": { + "ccdb-url": "http://alice-ccdb.cern.ch", + "ccdb-timestamp": "-1", + "timeShiftCCDBPath": "", + "distanceForGoodMatch": "999", + "distanceForGoodMatchLowMult": "999", + "multThreshold": "0", + "enableQaHistograms": "false", + "processRun3": "true", + "processRun2": "false" }, "event-selection-task": { - "syst": "pp", "muonSelection": "0", - "customDeltaBC": "300", - "isMC": "false", + "maxDiffZvtxFT0vsPV": "1", + "isMC": "0", + "TimeIntervalForOccupancyCalculationMin": "-40", + "TimeIntervalForOccupancyCalculationMax": "100", + "TimeBinsForOccupancyCalculation": { + "values": [ + "-40", + "-20", + "0", + "25", + "50", + "75", + "100" + ] + }, + "ReferenceOccupanciesInTimeBins": { + "values": [ + "3000", + "1400", + "750", + "1000", + "1750", + "4000" + ] + }, + "TimeRangeVetoOnCollStandard": "10", + "TimeRangeVetoOnCollNarrow": "4", + "UseWeightsForOccupancyEstimator": "true", "processRun2": "false", "processRun3": "true" }, - "hf-candidate-creator2-prong": { + "hf-task-mini-candidate-creator-2prong": { "magneticField": "5", "propagateToPCA": "true", "useAbsDCA": "false", @@ -56,14 +164,10 @@ "minRelChi2Change": "0.9" }, "pid-multiplicity": { - "processIU": "false", - "processStandard": "true" + "processIU": "true", + "processStandard": "false" }, - "tof-signal": { - "processRun3": "true", - "processRun2": "false" - }, - "tpc-pid-full": { + "tpc-pid": { "param-file": "", "ccdb-url": "http://alice-ccdb.cern.ch", "ccdbPath": "Analysis/PID/TPC/Response", @@ -71,47 +175,155 @@ "ccdb-timestamp": "0", "useNetworkCorrection": "false", "autofetchNetworks": "true", - "skipTPCOnly": "false", + "skipTPCOnly": "true", "networkPathLocally": "network.onnx", "networkPathCCDB": "Analysis/PID/TPC/ML", "enableNetworkOptimizations": "true", "networkSetNumThreads": "0", - "pid-el": "-1", - "pid-mu": "-1", - "pid-pi": "-1", - "pid-ka": "-1", - "pid-pr": "-1", - "pid-de": "-1", - "pid-tr": "-1", - "pid-he": "-1", - "pid-al": "-1" + "pid-full-el": "-1", + "pid-full-mu": "-1", + "pid-full-pi": "-1", + "pid-full-ka": "-1", + "pid-full-pr": "-1", + "pid-full-de": "-1", + "pid-full-tr": "-1", + "pid-full-he": "-1", + "pid-full-al": "-1", + "pid-tiny-el": "-1", + "pid-tiny-mu": "-1", + "pid-tiny-pi": "-1", + "pid-tiny-ka": "-1", + "pid-tiny-pr": "-1", + "pid-tiny-de": "-1", + "pid-tiny-tr": "-1", + "pid-tiny-he": "-1", + "pid-tiny-al": "-1", + "enableTuneOnDataTable": "-1", + "useNetworkEl": "1", + "useNetworkMu": "1", + "useNetworkPi": "1", + "useNetworkKa": "1", + "useNetworkPr": "1", + "useNetworkDe": "1", + "useNetworkTr": "1", + "useNetworkHe": "1", + "useNetworkAl": "1", + "networkBetaGammaCutoff": "0.45", + "processStandard": "true", + "processMcTuneOnData": "false" }, + "multiplicity-table": { + "doVertexZeq": "1", + "fractionOfEvents": "2", + "enabledTables": { + "labels_rows": [ + "FV0Mults", + "FT0Mults", + "FDDMults", + "ZDCMults", + "TrackletMults", + "TPCMults", + "PVMults", + "MultsExtra", + "MultSelections", + "FV0MultZeqs", + "FT0MultZeqs", + "FDDMultZeqs", + "PVMultZeqs", + "MultMCExtras" + ], + "labels_cols": [ + "Enable" + ], + "values": [ + [ + "-1" + ], + [ + "-1" + ], + [ + "-1" + ], + [ + "-1" + ], + [ + "-1" + ], + [ + "-1" + ], + [ + "-1" + ], + [ + "-1" + ], + [ + "-1" + ], + [ + "-1" + ], + [ + "-1" + ], + [ + "-1" + ], + [ + "-1" + ], + [ + "-1" + ] + ] + }, + "ccdburl": "http://alice-ccdb.cern.ch", + "ccdbpath": "Centrality/Calibration", + "reconstructionPass": "", + "produceHistograms": "false", + "min_pt_globaltrack": "0.15", + "max_pt_globaltrack": "1e+10", + "min_ncluster_its_globaltrack": "5", + "min_ncluster_itsib_globaltrack": "1", + "processRun2": "false", + "processRun3": "true", + "processGlobalTrackingCounters": "false", + "processMC": "false", + "processMC2Mults": "false" + }, + "ft0-corrected-table": "", + "hf-task-mini-candidate-creator-2prong-expressions": "", "tof-event-time": { + "inheritFromBaseTask": "true", + "ccdb-url": "", + "ccdb-timestamp": "-1", "minMomentum": "0.5", "maxMomentum": "2", "maxEvTimeTOF": "100000", + "sel8TOFEvTime": "false", + "maxNtracksInSet": "10", "paramFileName": "", - "ccdb-url": "http://alice-ccdb.cern.ch", "parametrizationPath": "TOF/Calib/Params", "passName": "", - "ccdb-timestamp": "-1", "loadResponseFromCCDB": "false", + "enableTimeDependentResponse": "false", "fatalOnPassNotAvailable": "true", - "sel8TOFEvTime": "false", - "maxNtracksInSet": "10", "processRun2": "false", - "processNoFT0": "true", - "processFT0": "false", + "processNoFT0": "false", + "processFT0": "true", "processOnlyFT0": "false" }, - "hf-candidate-creator2-prong-expressions": "", "tof-pid-full": { + "inheritFromBaseTask": "true", + "ccdb-url": "", + "ccdb-timestamp": "-1", "paramFileName": "", - "ccdb-url": "http://alice-ccdb.cern.ch", - "parametrizationPath": "TOF/Calib/Params", - "timeShiftCCDBPath": "", + "parametrizationPath": "", "passName": "", - "ccdb-timestamp": "-1", + "timeShiftCCDBPath": "", "loadResponseFromCCDB": "false", "enableTimeDependentResponse": "false", "fatalOnPassNotAvailable": "true", @@ -163,7 +375,7 @@ "processWSlice": "true", "processWoSlice": "false" }, - "hf-candidate-selector-d0": { + "hf-task-mini-candidate-selector-d0": { "ptCandMin": "0", "ptCandMax": "50", "ptPidTpcMin": "0.15", @@ -172,7 +384,7 @@ "cpaMin": "0.98", "massWindow": "0.4" }, - "hf-task-d0": { + "hf-task-mini-d0": { "selectionFlagD0": "1", "selectionFlagD0bar": "1" }, diff --git a/Tutorials/PWGHF/run_skim.sh b/Tutorials/PWGHF/run_skim.sh index 788a2ffd460..6adefe69b01 100644 --- a/Tutorials/PWGHF/run_skim.sh +++ b/Tutorials/PWGHF/run_skim.sh @@ -28,17 +28,23 @@ DIR_THIS="$(dirname "$(realpath "$0")")" JSON="$DIR_THIS/dpl-config_skim.json" # command line options of O2 workflows -OPTIONS="-b --configuration json://$JSON --aod-memory-rate-limit 2000000000 --shm-segment-size 16000000000 --resources-monitoring 2 --min-failure-level error --aod-writer-keep AOD/HFTRACKIDXP2/0" +OPTIONS=( + -b + --configuration json://"$JSON" + --aod-memory-rate-limit 2000000000 + --shm-segment-size 16000000000 + --resources-monitoring 2 + --aod-writer-keep "AOD/HFT2PRONG/0" +) # execute the mini task workflow and its dependencies # shellcheck disable=SC2086 # Ignore unquoted options. -o2-analysistutorial-hf-skim-creator-mini $OPTIONS | \ -o2-analysis-timestamp $OPTIONS | \ -o2-analysis-trackselection $OPTIONS | \ -o2-analysis-track-propagation $OPTIONS | \ -o2-analysis-bc-converter $OPTIONS | \ -o2-analysis-tracks-extra-converter $OPTIONS | \ -o2-analysis-zdc-converter $OPTIONS \ +o2-analysistutorial-hf-skim-creator-mini "${OPTIONS[@]}" | \ +o2-analysis-timestamp "${OPTIONS[@]}" | \ +o2-analysis-trackselection "${OPTIONS[@]}" | \ +o2-analysis-track-propagation "${OPTIONS[@]}" | \ +o2-analysis-bc-converter "${OPTIONS[@]}" | \ +o2-analysis-tracks-extra-converter "${OPTIONS[@]}" \ > "$LOGFILE" 2>&1 # report status diff --git a/Tutorials/PWGHF/run_task.sh b/Tutorials/PWGHF/run_task.sh index 096ee292150..de4096c2b85 100644 --- a/Tutorials/PWGHF/run_task.sh +++ b/Tutorials/PWGHF/run_task.sh @@ -28,21 +28,30 @@ DIR_THIS="$(dirname "$(realpath "$0")")" JSON="$DIR_THIS/dpl-config_task.json" # command line options of O2 workflows -OPTIONS="-b --configuration json://$JSON --aod-memory-rate-limit 2000000000 --shm-segment-size 16000000000 --resources-monitoring 2 --min-failure-level error" +OPTIONS=( + -b + --configuration json://"$JSON" + --aod-memory-rate-limit 2000000000 + --shm-segment-size 16000000000 + --resources-monitoring 2 + --aod-parent-base-path-replacement "old-path-to-parent;new-path-to-parent" + --aod-parent-access-level 1 +) # execute the mini task workflow and its dependencies # shellcheck disable=SC2086 # Ignore unquoted options. -o2-analysistutorial-hf-task-mini $OPTIONS | \ -o2-analysis-timestamp $OPTIONS | \ -o2-analysis-track-propagation $OPTIONS | \ -o2-analysis-event-selection $OPTIONS | \ -o2-analysis-pid-tpc-base $OPTIONS | \ -o2-analysis-pid-tpc-full $OPTIONS | \ -o2-analysis-pid-tof-base $OPTIONS | \ -o2-analysis-pid-tof-full $OPTIONS | \ -o2-analysis-bc-converter $OPTIONS | \ -o2-analysis-tracks-extra-converter $OPTIONS | \ -o2-analysis-zdc-converter $OPTIONS \ +o2-analysistutorial-hf-task-mini "${OPTIONS[@]}" | \ +o2-analysis-timestamp "${OPTIONS[@]}" | \ +o2-analysis-track-propagation "${OPTIONS[@]}" | \ +o2-analysis-event-selection "${OPTIONS[@]}" | \ +o2-analysis-pid-tpc-base "${OPTIONS[@]}" | \ +o2-analysis-pid-tpc "${OPTIONS[@]}" | \ +o2-analysis-pid-tof-base "${OPTIONS[@]}" | \ +o2-analysis-pid-tof-full "${OPTIONS[@]}" | \ +o2-analysis-ft0-corrected-table "${OPTIONS[@]}" | \ +o2-analysis-bc-converter "${OPTIONS[@]}" | \ +o2-analysis-tracks-extra-converter "${OPTIONS[@]}" | \ +o2-analysis-zdc-converter "${OPTIONS[@]}" \ > "$LOGFILE" 2>&1 # report status diff --git a/Tutorials/PWGHF/skimCreatorMini.cxx b/Tutorials/PWGHF/skimCreatorMini.cxx index 6f20d6ac6fb..ac6b12e2004 100644 --- a/Tutorials/PWGHF/skimCreatorMini.cxx +++ b/Tutorials/PWGHF/skimCreatorMini.cxx @@ -38,13 +38,13 @@ using namespace o2::framework::expressions; // Track selection ===================================================================== /// Track selection -struct HfTrackIndexSkimCreatorTagSelTracks { - Produces rowSelectedTrack; +struct HfSkimCreatorMiniTagSelTracks { + Produces rowSelectedTrack; // 2-prong cuts - Configurable ptTrackMin{"ptTrackMin", 0.3, "min. track pT for 2 prong candidate"}; - Configurable etaTrackMax{"etaTrackMax", 0.8, "max. pseudorapidity for 2 prong candidate"}; - Configurable dcaTrackMin{"dcaTrackMin", 0.0025, "min. DCA for 2 prong candidate"}; + Configurable ptTrackMin{"ptTrackMin", 0.3, "min. track pT for 2 prong candidate"}; + Configurable etaTrackMax{"etaTrackMax", 0.8, "max. pseudorapidity for 2 prong candidate"}; + Configurable dcaTrackMin{"dcaTrackMin", 0.0025, "min. DCA for 2 prong candidate"}; using TracksWDcaSel = soa::Join; @@ -110,21 +110,21 @@ struct HfTrackIndexSkimCreatorTagSelTracks { /// Track index skim creator /// Pre-selection of 2-prong secondary vertices -struct HfTrackIndexSkimCreator { - Produces rowTrackIndexProng2; +struct HfSkimCreatorMini { + Produces rowTrackIndexProng2; // vertexing parameters - Configurable magneticField{"magneticField", 5., "magnetic field [kG]"}; + Configurable magneticField{"magneticField", 5., "magnetic field [kG]"}; Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; Configurable useAbsDCA{"useAbsDCA", false, "Minimise abs. distance rather than chi2"}; - Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; - Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; - Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; - Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations if chi2/chi2old > this"}; + Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; + Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; + Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations if chi2/chi2old > this"}; o2::vertexing::DCAFitterN<2> fitter; // 2-prong vertex fitter - using SelectedTracks = soa::Filtered>; + using SelectedTracks = soa::Filtered>; Filter filterSelectTracks = aod::hf_seltrack::isSelProng == true; @@ -166,7 +166,12 @@ struct HfTrackIndexSkimCreator { auto trackParVarNeg1 = getTrackParCov(trackNeg1); // secondary vertex reconstruction and further 2-prong selections - if (fitter.process(trackParVarPos1, trackParVarNeg1) == 0) { + int nVtxFromFitter = 0; + try { + nVtxFromFitter = fitter.process(trackParVarPos1, trackParVarNeg1); + } catch (...) { + } + if (nVtxFromFitter == 0) { continue; } // get secondary vertex @@ -197,6 +202,6 @@ struct HfTrackIndexSkimCreator { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; } diff --git a/Tutorials/PWGHF/taskMini.cxx b/Tutorials/PWGHF/taskMini.cxx index 800153a4fb9..871fe710581 100644 --- a/Tutorials/PWGHF/taskMini.cxx +++ b/Tutorials/PWGHF/taskMini.cxx @@ -41,17 +41,17 @@ using namespace o2::framework::expressions; /// Candidate creator /// Reconstruction of heavy-flavour 2-prong decay candidates -struct HfCandidateCreator2Prong { - Produces rowCandidateBase; +struct HfTaskMiniCandidateCreator2Prong { + Produces rowCandidateBase; // vertexing parameters - Configurable magneticField{"magneticField", 5., "magnetic field [kG]"}; + Configurable magneticField{"magneticField", 5., "magnetic field [kG]"}; Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; Configurable useAbsDCA{"useAbsDCA", false, "Minimise abs. distance rather than chi2"}; - Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; - Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; - Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; - Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations if chi2/chi2old > this"}; + Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; + Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; + Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations if chi2/chi2old > this"}; o2::vertexing::DCAFitterN<2> fitter; // 2-prong vertex fitter double massPiK{0.}; @@ -74,7 +74,7 @@ struct HfCandidateCreator2Prong { } void process(aod::Collisions const&, - aod::HfTrackIndexProng2 const& rowsTrackIndexProng2, + aod::HfT2Prongs const& rowsTrackIndexProng2, TracksWithCov const&) { // loop over pairs of track indices @@ -119,27 +119,27 @@ struct HfCandidateCreator2Prong { }; /// Helper extension task -/// Extends the base table with expression columns (see the HfCandProng2Ext table). -struct HfCandidateCreator2ProngExpressions { - Spawns rowCandidateProng2; +/// Extends the base table with expression columns (see the HfTCand2ProngExt table). +struct HfTaskMiniCandidateCreator2ProngExpressions { + Spawns rowCandidateProng2; void init(InitContext const&) {} }; // Candidate selection ===================================================================== /// D0 candidate selector -struct HfCandidateSelectorD0 { - Produces hfSelD0Candidate; +struct HfTaskMiniCandidateSelectorD0 { + Produces hfSelD0Candidate; - Configurable ptCandMin{"ptCandMin", 0., "Lower bound of candidate pT"}; - Configurable ptCandMax{"ptCandMax", 50., "Upper bound of candidate pT"}; + Configurable ptCandMin{"ptCandMin", 0., "Lower bound of candidate pT"}; + Configurable ptCandMax{"ptCandMax", 50., "Upper bound of candidate pT"}; // TPC - Configurable ptPidTpcMin{"ptPidTpcMin", 0.15, "Lower bound of track pT for TPC PID"}; - Configurable ptPidTpcMax{"ptPidTpcMax", 5., "Upper bound of track pT for TPC PID"}; - Configurable nSigmaTpc{"nSigmaTpc", 3., "Nsigma cut on TPC only"}; + Configurable ptPidTpcMin{"ptPidTpcMin", 0.15, "Lower bound of track pT for TPC PID"}; + Configurable ptPidTpcMax{"ptPidTpcMax", 5., "Upper bound of track pT for TPC PID"}; + Configurable nSigmaTpc{"nSigmaTpc", 3., "Nsigma cut on TPC only"}; // topological cuts - Configurable cpaMin{"cpaMin", 0.98, "Min. cosine of pointing angle"}; - Configurable massWindow{"massWindow", 0.4, "Half-width of the invariant-mass window"}; + Configurable cpaMin{"cpaMin", 0.98, "Min. cosine of pointing angle"}; + Configurable massWindow{"massWindow", 0.4, "Half-width of the invariant-mass window"}; HfHelper hfHelper; TrackSelectorPi selectorPion; @@ -195,7 +195,7 @@ struct HfCandidateSelectorD0 { return true; } - void process(aod::HfCandProng2 const& candidates, + void process(aod::HfTCand2Prong const& candidates, TracksWithPid const&) { // looping over 2-prong candidates @@ -273,13 +273,13 @@ struct HfCandidateSelectorD0 { // Analysis task ===================================================================== /// D0 analysis task -struct HfTaskD0 { +struct HfTaskMiniD0 { Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection flag for D0"}; Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection flag for D0 bar"}; HfHelper hfHelper; - Partition> selectedD0Candidates = aod::hf_selcandidate_d0::isSelD0 >= selectionFlagD0 || aod::hf_selcandidate_d0::isSelD0bar >= selectionFlagD0bar; + Partition> selectedD0Candidates = aod::hf_selcandidate_d0::isSelD0 >= selectionFlagD0 || aod::hf_selcandidate_d0::isSelD0bar >= selectionFlagD0bar; HistogramRegistry registry{ "registry", @@ -295,7 +295,7 @@ struct HfTaskD0 { registry.add("hCpaVsPtCand", strTitle + ";" + "cosine of pointing angle" + ";" + strPt + ";" + strEntries, {HistType::kTH2F, {{110, -1.1, 1.1}, {100, 0., 10.}}}); } - void process(soa::Join const& /*candidates*/) + void process(soa::Join const& /*candidates*/) { for (const auto& candidate : selectedD0Candidates) { if (candidate.isSelD0() >= selectionFlagD0) { @@ -314,8 +314,8 @@ struct HfTaskD0 { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc, TaskName{"hf-task-mini-candidate-creator-2prong"}), // o2-linter: disable=name/o2-task + adaptAnalysisTask(cfgc, TaskName{"hf-task-mini-candidate-creator-2prong-expressions"}), // o2-linter: disable=name/o2-task + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; } diff --git a/Tutorials/PWGLF/Resonance/CMakeLists.txt b/Tutorials/PWGLF/Resonance/CMakeLists.txt index 36c4b84bf28..35ac519aa65 100644 --- a/Tutorials/PWGLF/Resonance/CMakeLists.txt +++ b/Tutorials/PWGLF/Resonance/CMakeLists.txt @@ -24,3 +24,33 @@ o2physics_add_dpl_workflow(resonances-step2 SOURCES resonances_step2.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(resonances-step3 + SOURCES resonances_step3.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(resonances-step4 + SOURCES resonances_step4.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(resonances-step5 + SOURCES resonances_step5.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(resonances-step6 + SOURCES resonances_step6.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(resonances-combine + SOURCES resonancesCombine.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(resonances-microtrack + SOURCES resonancesMicrotrack.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) diff --git a/Tutorials/PWGLF/Resonance/README.md b/Tutorials/PWGLF/Resonance/README.md index 7e1433bb8bb..19d51c0eced 100644 --- a/Tutorials/PWGLF/Resonance/README.md +++ b/Tutorials/PWGLF/Resonance/README.md @@ -1,6 +1,6 @@ # This is the base for the PWGLF tutorials for the O2AT -The tutorial (6-10 Nov 2023) can be still used and is a reference for the LF analyses. +The tutorial can be still used and is a reference for the LF Resonance analyses. It is built as a set of steps. Each step adds a level of complexity and is built in a separate executable. The executables are defined in the `CMakeLists.txt`. @@ -8,3 +8,9 @@ The executables are defined in the `CMakeLists.txt`. * `README.md` this readme * `CMakeLists.txt` here are defined the source files to compile * `resonance_step0.cxx` Read the resonance table and run basic track loop +* `resonance_step1.cxx` Producing same event invariant mass distribution +* `resonance_step2.cxx` Producing Mixed event invariant mass distribution +* `resonance_step3.cxx` Starting point for MC: loop over all Generated MC particles +* `resonance_step4.cxx` Producing histograms (pt distributions etc.) for Generated MCs +* `resonance_step5.cxx` Loop over all MC Tracks and produce basic QA histograms +* `resonance_step6.cxx` Resonance reconstruction diff --git a/Tutorials/PWGLF/Resonance/resonancesCombine.cxx b/Tutorials/PWGLF/Resonance/resonancesCombine.cxx new file mode 100644 index 00000000000..26a28661c6c --- /dev/null +++ b/Tutorials/PWGLF/Resonance/resonancesCombine.cxx @@ -0,0 +1,193 @@ +// 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 resonancesCombine.cxx +/// \brief Resonance combination tutorial +/// \author Bong-Hwi Lim +/// \since 13/12/2024 + +#include +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/Core/EventPlaneHelper.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFResonanceTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// Extract STEP +// Combine Resonance tables into other O2 tables +struct ResonanceCombine { + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Configurable for number of bins + Configurable nBins{"nBins", 100, "N bins in all histos"}; + // Configurable for min pT cut + Configurable cMinPtcut{"cMinPtcut", 0.15, "Track minium pt cut"}; + // Configurable for event plane + Configurable cfgEvtPl{"cfgEvtPl", 40500, "Configuration of three subsystems for the event plane and its resolution, 10000*RefA + 100*RefB + S, where FT0C:0, FT0A:1, FT0M:2, FV0A:3, BPos:5, BNeg:6"}; + + // Track selection + // primary track condition + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; + Configurable cfgPVContributor{"cfgPVContributor", true, "PV contributor track selection"}; + // DCA Selections + // DCAr to PV + Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 0.5, "Track DCAr cut to PV Maximum"}; + // DCAz to PV + Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; + Configurable cMinDCAzToPVcut{"cMinDCAzToPVcut", 0.0, "Track DCAz cut to PV Minimum"}; + + // PID selection + Configurable nSigmaCutTPC{"nSigmaCutTPC", 3.0, "Value of the TPC Nsigma cut"}; + Configurable nSigmaCutTOF{"nSigmaCutTOF", 3.0, "Value of the TOF Nsigma cut"}; + + double massKa = o2::constants::physics::MassKPlus; + + EventPlaneHelper helperEP; + int evtPlRefAId = static_cast(cfgEvtPl / 10000); + int evtPlRefBId = static_cast((cfgEvtPl - evtPlRefAId * 10000) / 100); + int evtPlDetId = cfgEvtPl - evtPlRefAId * 10000 - evtPlRefBId * 100; + + void init(o2::framework::InitContext&) + { + histos.add("hVertexZ", "hVertexZ", HistType::kTH1F, {{nBins, -15., 15.}}); + histos.add("hMultiplicityPercent", "Multiplicity Percentile", kTH1F, {{120, 0.0f, 120.0f}}); + histos.add("hEvtPl", "Event Plane", kTH1F, {{100, -1.0f, 1.0f}}); + histos.add("hEta", "Eta distribution", kTH1F, {{200, -1.0f, 1.0f}}); + histos.add("hDcaxy", "Dcaxy distribution", kTH1F, {{200, -1.0f, 1.0f}}); + histos.add("hDcaz", "Dcaz distribution", kTH1F, {{200, -1.0f, 1.0f}}); + histos.add("hNsigmaKaonTPC", "NsigmaKaon TPC distribution", kTH1F, {{100, -10.0f, 10.0f}}); + histos.add("hNsigmaKaonTOF", "NsigmaKaon TOF distribution", kTH1F, {{100, -10.0f, 10.0f}}); + histos.add("hTiemResolutionTOF", "TOF time resolution", kTH1F, {{100, -10.0f, 10.0f}}); + histos.add("h1PhiInvMassUnlikeSign", "Invariant mass of Phi meson Unlike Sign", kTH1F, {{300, 0.9, 1.2}}); + histos.add("h1PhiInvMassLikeSignPP", "Invariant mass of Phi meson Like Sign positive", kTH1F, {{300, 0.9, 1.2}}); + histos.add("h1PhiInvMassLikeSignMM", "Invariant mass of Phi meson Like Sign negative", kTH1F, {{300, 0.9, 1.2}}); + histos.add("h3PhiInvMassUnlikeSign", "Invariant mass of Phi meson Unlike Sign", kTH3F, {{120, 0.0f, 120.0f}, {100, 0.0f, 10.0f}, {300, 0.9, 1.2}}); + histos.add("h3PhiInvMassLikeSignPP", "Invariant mass of Phi meson Like Sign positive", kTH3F, {{120, 0.0f, 120.0f}, {100, 0.0f, 10.0f}, {300, 0.9, 1.2}}); + histos.add("h3PhiInvMassLikeSignMM", "Invariant mass of Phi meson Like Sign negative", kTH3F, {{120, 0.0f, 120.0f}, {100, 0.0f, 10.0f}, {300, 0.9, 1.2}}); + + LOG(info) << "Size of the histograms in resonance tutorial with table combination:"; + histos.print(); + } + + template + bool trackCut(const TrackType track) + { + if (std::abs(track.pt()) < cMinPtcut) + return false; + if (std::abs(track.dcaXY()) > cMaxDCArToPVcut) + return false; + if (std::abs(track.dcaZ()) > cMaxDCAzToPVcut) + return false; + if (cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (cfgPVContributor && !track.isPVContributor()) + return false; + return true; + } + + template + bool selectionPID(const T& candidate) + { + bool tpcPass = std::abs(candidate.tpcNSigmaKa()) < nSigmaCutTPC; + bool tofPass = (candidate.hasTOF()) ? std::abs(candidate.tofNSigmaKa()) < nSigmaCutTOF : true; + if (tpcPass && tofPass) { + return true; + } + return false; + } + + double rapidity, mass, pT, paircharge; + TLorentzVector daughter1, daughter2, mother; + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksType& dTracks2) + { + auto multiplicity = collision.template collision_as().cent(); + for (auto const& track1 : dTracks1) { + auto track1Reso = track1.template track_as(); + auto track1FullPidExt = track1.template track_as(); + if (!trackCut(track1Reso) || !selectionPID(track1Reso)) { + continue; + } + histos.fill(HIST("hEta"), track1Reso.eta()); + histos.fill(HIST("hDcaxy"), track1Reso.dcaXY()); + histos.fill(HIST("hDcaz"), track1Reso.dcaZ()); + histos.fill(HIST("hNsigmaKaonTPC"), track1Reso.tpcNSigmaKa()); + if (track1Reso.hasTOF()) { + histos.fill(HIST("hNsigmaKaonTOF"), track1Reso.tofNSigmaKa()); + histos.fill(HIST("hTiemResolutionTOF"), track1FullPidExt.trackTimeRes()); // TOF time resolution is not in the ResoTracks table (Important) + } + for (auto const& track2 : dTracks2) { + auto track2Reso = track2.template track_as(); + // auto track2FullPidExt = track2.template track_as(); + + if (!trackCut(track2Reso) || !selectionPID(track2Reso)) { + continue; + } + if (track2Reso.index() <= track1Reso.index()) { + continue; + } + daughter1.SetXYZM(track1Reso.px(), track1Reso.py(), track1Reso.pz(), massKa); + daughter2.SetXYZM(track2Reso.px(), track2Reso.py(), track2Reso.pz(), massKa); + mother = daughter1 + daughter2; + mass = mother.M(); + pT = mother.Pt(); + rapidity = mother.Rapidity(); + paircharge = track1Reso.sign() * track2Reso.sign(); + + if (std::abs(rapidity) > 0.5) + continue; + + if (paircharge < 0) { + histos.fill(HIST("h3PhiInvMassUnlikeSign"), multiplicity, pT, mass); + histos.fill(HIST("h1PhiInvMassUnlikeSign"), mass); + } else { + if (track1Reso.sign() > 0 && track2Reso.sign() > 0) { + histos.fill(HIST("h3PhiInvMassLikeSignPP"), multiplicity, pT, mass); + histos.fill(HIST("h1PhiInvMassLikeSignPP"), mass); + } else { + histos.fill(HIST("h3PhiInvMassLikeSignMM"), multiplicity, pT, mass); + histos.fill(HIST("h1PhiInvMassLikeSignMM"), mass); + } + } + } + } + } + + void process(soa::Join::iterator const& collision, soa::Join const& resotracks) + { + histos.fill(HIST("hVertexZ"), collision.posZ()); + // Both resoCollisions and Qvectors have the same cent column, so we have to use "_as" to access it + // Similarly, we can use "_as" to access the Qvectors table or other tables + histos.fill(HIST("hMultiplicityPercent"), collision.collision_as().cent()); + // Event plane + auto collisionQvec = collision.template collision_as(); // Qvectors table is not in the ResoCollisions table (Important) + auto evtPl = -999.0; + if (collisionQvec.qvecAmp()[evtPlDetId] > 1e-8) + evtPl = helperEP.GetEventPlane(collisionQvec.qvecRe()[evtPlDetId * 4 + 3], collisionQvec.qvecIm()[evtPlDetId * 4 + 3], 2); + if (evtPl > -999.0) + histos.fill(HIST("hEvtPl"), evtPl); + + fillHistograms(collision, resotracks, resotracks); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/Tutorials/PWGLF/Resonance/resonancesMicrotrack.cxx b/Tutorials/PWGLF/Resonance/resonancesMicrotrack.cxx new file mode 100644 index 00000000000..07736a3e841 --- /dev/null +++ b/Tutorials/PWGLF/Resonance/resonancesMicrotrack.cxx @@ -0,0 +1,203 @@ +// 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 resonancesMicrotrack.cxx +/// \brief Resonance microtrack tutorial +/// \author Bong-Hwi Lim +/// \since 07/03/2025 + +#include +#include + +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFResonanceTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::math; +// Extract STEP +// Handle resomicrotracks +struct ResonancesMicrotrack { + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Configurable for number of bins + Configurable nBins{"nBins", 100, "N bins in all histos"}; + // Configurable for min pT cut + Configurable cMinPtcut{"cMinPtcut", 0.15, "Track minium pt cut"}; + // Configurable for event plane + Configurable cfgEvtPl{"cfgEvtPl", 40500, "Configuration of three subsystems for the event plane and its resolution, 10000*RefA + 100*RefB + S, where FT0C:0, FT0A:1, FT0M:2, FV0A:3, BPos:5, BNeg:6"}; + + // Track selection + // primary track condition + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", false, "Primary track selection"}; + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; + Configurable cfgPVContributor{"cfgPVContributor", false, "PV contributor track selection"}; + // DCA Selections + // DCAr to PV + Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 0.5, "Track DCAr cut to PV Maximum"}; + // DCAz to PV + Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 1.0, "Track DCAz cut to PV Maximum"}; + Configurable cMinDCAzToPVcut{"cMinDCAzToPVcut", 0.0, "Track DCAz cut to PV Minimum"}; + + // PID selection + Configurable nSigmaCutTPC{"nSigmaCutTPC", 3.0, "Value of the TPC Nsigma cut"}; + Configurable nSigmaCutTOF{"nSigmaCutTOF", 3.0, "Value of the TOF Nsigma cut"}; + + void init(o2::framework::InitContext&) + { + histos.add("hVertexZ", "hVertexZ", HistType::kTH1F, {{nBins, -15., 15.}}); + histos.add("hMultiplicityPercent", "Multiplicity Percentile", kTH1F, {{120, 0.0f, 120.0f}}); + histos.add("hEta_ResoTracks", "Eta distribution", kTH1F, {{200, -1.0f, 1.0f}}); + histos.add("hEta_ResoMicroTracks", "Eta distribution", kTH1F, {{200, -1.0f, 1.0f}}); + histos.add("hPhi_ResoTracks", "Phi distribution", kTH1F, {{200, 0, TwoPI}}); + histos.add("hPhi_ResoMicroTracks", "Phi distribution", kTH1F, {{200, 0, TwoPI}}); + histos.add("hPt_ResoTracks", "Pt distribution", kTH1F, {{150, 0.0f, 15.0f}}); + histos.add("hPt_ResoMicroTracks", "Pt distribution", kTH1F, {{150, 0.0f, 15.0f}}); + histos.add("hPx_ResoTracks", "Px distribution", kTH1F, {{200, -10.0f, 10.0f}}); + histos.add("hPx_ResoMicroTracks", "Px distribution", kTH1F, {{200, -10.0f, 10.0f}}); + histos.add("hPy_ResoTracks", "Py distribution", kTH1F, {{200, -10.0f, 10.0f}}); + histos.add("hPy_ResoMicroTracks", "Py distribution", kTH1F, {{200, -10.0f, 10.0f}}); + histos.add("hPz_ResoTracks", "Pz distribution", kTH1F, {{200, -10.0f, 10.0f}}); + histos.add("hPz_ResoMicroTracks", "Pz distribution", kTH1F, {{200, -10.0f, 10.0f}}); + + histos.add("hDcaxy_ResoTracks", "Dcaxy distribution", kTH1F, {{200, 0, 2.0f}}); + histos.add("hDcaz_ResoTracks", "Dcaz distribution", kTH1F, {{200, 0, 2.0f}}); + histos.add("hDcaxy_ResoMicroTracks", "Dcaxy distribution", kTH1F, {{200, 0, 2.0f}}); + histos.add("hDcaz_ResoMicroTracks", "Dcaz distribution", kTH1F, {{200, 0, 2.0f}}); + + // PID + histos.add("hNsigmaKaonTPC_ResoMicroTracks", "NsigmaKaonTPC distribution", kTH1F, {{240, -6.0f, 6.0f}}); + histos.add("hNsigmaKaonTOF_ResoMicroTracks", "NsigmaKaonTOF distribution", kTH1F, {{240, -6.0f, 6.0f}}); + histos.add("hNsigmaKaonTPC_ResoTracks", "NsigmaKaonTPC distribution", kTH1F, {{240, -6.0f, 6.0f}}); + histos.add("hNsigmaKaonTOF_ResoTracks", "NsigmaKaonTOF distribution", kTH1F, {{240, -6.0f, 6.0f}}); + + LOG(info) << "Size of the histograms in resonance tutorial with table combination:"; + histos.print(); + } + + template + bool trackCut(const TrackType track) + { + if constexpr (!IsResoMicrotrack) { + if (std::abs(track.pt()) < cMinPtcut) + return false; + if (std::abs(track.dcaXY()) > cMaxDCArToPVcut) + return false; + if (std::abs(track.dcaZ()) > cMaxDCAzToPVcut) + return false; + if (cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (cfgPVContributor && !track.isPVContributor()) + return false; + } else { + if (std::abs(track.pt()) < cMinPtcut) + return false; + if (o2::aod::resodmciroaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags()) > cMaxDCArToPVcut - Epsilon) + return false; + if (o2::aod::resodmciroaughter::ResoMicroTrackSelFlag::decodeDCAz(track.trackSelectionFlags()) > cMaxDCAzToPVcut - Epsilon) + return false; + if (cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (cfgPVContributor && !track.isPVContributor()) + return false; + } + return true; + } + + template + bool selectionPID(const T& candidate) + { + if constexpr (!IsResoMicrotrack) { + bool tpcPass = std::abs(candidate.tpcNSigmaPr()) < nSigmaCutTPC; + bool tofPass = (candidate.hasTOF()) ? std::abs(candidate.tofNSigmaPr()) < nSigmaCutTOF : true; + if (tpcPass && tofPass) { + return true; + } + // return true; + } else { + bool tpcPass = std::abs(o2::aod::resodmciroaughter::PidNSigma::getTPCnSigma(candidate.pidNSigmaPrFlag())) < nSigmaCutTPC + Epsilon; + bool tofPass = candidate.hasTOF() ? std::abs(o2::aod::resodmciroaughter::PidNSigma::getTOFnSigma(candidate.pidNSigmaPrFlag())) < nSigmaCutTOF + Epsilon : true; + if (tpcPass && tofPass) { + return true; + } + // return true; + } + return false; + } + + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks) + { + auto multiplicity = collision.cent(); + histos.fill(HIST("hVertexZ"), collision.posZ()); + histos.fill(HIST("hMultiplicityPercent"), multiplicity); + for (auto const& track : dTracks) { + if (!trackCut(track) || !selectionPID(track)) { + continue; + } + + if constexpr (!IsResoMicrotrack) { // ResoTracks + histos.fill(HIST("hEta_ResoTracks"), track.eta()); + histos.fill(HIST("hPhi_ResoTracks"), track.phi()); + histos.fill(HIST("hPt_ResoTracks"), track.pt()); + histos.fill(HIST("hPx_ResoTracks"), track.px()); + histos.fill(HIST("hPy_ResoTracks"), track.py()); + histos.fill(HIST("hPz_ResoTracks"), track.pz()); + histos.fill(HIST("hDcaxy_ResoTracks"), track.dcaXY()); + histos.fill(HIST("hDcaz_ResoTracks"), track.dcaZ()); + histos.fill(HIST("hNsigmaKaonTPC_ResoTracks"), track.tpcNSigmaPr()); + if (track.hasTOF()) { + histos.fill(HIST("hNsigmaKaonTOF_ResoTracks"), track.tofNSigmaPr()); + } + } else { // ResoMicroTracks + histos.fill(HIST("hEta_ResoMicroTracks"), track.eta()); + histos.fill(HIST("hPhi_ResoMicroTracks"), track.phi()); + histos.fill(HIST("hPt_ResoMicroTracks"), track.pt()); + histos.fill(HIST("hPx_ResoMicroTracks"), track.px()); + histos.fill(HIST("hPy_ResoMicroTracks"), track.py()); + histos.fill(HIST("hPz_ResoMicroTracks"), track.pz()); + histos.fill(HIST("hDcaxy_ResoMicroTracks"), o2::aod::resodmciroaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags())); + histos.fill(HIST("hDcaz_ResoMicroTracks"), o2::aod::resodmciroaughter::ResoMicroTrackSelFlag::decodeDCAz(track.trackSelectionFlags())); + histos.fill(HIST("hNsigmaKaonTPC_ResoMicroTracks"), o2::aod::resodmciroaughter::PidNSigma::getTPCnSigma(track.pidNSigmaPrFlag())); + if (track.hasTOF()) { + histos.fill(HIST("hNsigmaKaonTOF_ResoMicroTracks"), o2::aod::resodmciroaughter::PidNSigma::getTOFnSigma(track.pidNSigmaPrFlag())); + } + } + } + } + void processDummy(aod::ResoCollision const& /*collisions*/) + { + } + PROCESS_SWITCH(ResonancesMicrotrack, processDummy, "Process Dummy", true); + + void processResoTracks(aod::ResoCollision const& collision, aod::ResoTracks const& resotracks) + { + fillHistograms(collision, resotracks); + } + PROCESS_SWITCH(ResonancesMicrotrack, processResoTracks, "Process ResoTracks", false); + + void processResoMicroTracks(aod::ResoCollision const& collision, aod::ResoMicroTracks const& resomicrotracks) + { + fillHistograms(collision, resomicrotracks); + } + PROCESS_SWITCH(ResonancesMicrotrack, processResoMicroTracks, "Process ResoMicroTracks", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/Tutorials/PWGLF/Resonance/resonances_step3.cxx b/Tutorials/PWGLF/Resonance/resonances_step3.cxx new file mode 100644 index 00000000000..f2ef8dbbe67 --- /dev/null +++ b/Tutorials/PWGLF/Resonance/resonances_step3.cxx @@ -0,0 +1,77 @@ +// 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 this is a starting point for the Resonances tutorial for MC part +/// \author Hirak Kumar Koley +/// \since 11/10/2024 + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFResonanceTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 3 +// Starting point for MC: loop over all Generated MC particles +struct resonances_tutorial { + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Configurable for number of bins + Configurable nBins{"nBins", 100, "N bins in all histos"}; + // Configurable for min pT cut + Configurable cMinPtcut{"cMinPtcut", 0.15, "Track minimum pt cut"}; + + // Initialize the ananlysis task + void init(o2::framework::InitContext&) + { + // register histograms + histos.add("hVertexZ", "hVertexZ", HistType::kTH1F, {{nBins, -15., 15.}}); + histos.add("hEta", "Eta distribution", kTH1F, {{200, -1.0f, 1.0f}}); + } + + // MC particle selection + template + bool ptCut(const ParticleType resoParents) + { + // basic pt cuts + if (std::abs(resoParents.pt()) < cMinPtcut) + return false; + + return true; + } + + // Fill histograms (main function) + template + void fillHistograms(const CollisionType& /*collision*/, const ParticleType& resoParents) + { + for (auto part : resoParents) { // loop over all resoParents + if (!ptCut(part)) + continue; // pt selection + + // QA plots + histos.fill(HIST("hEta"), part.eta()); + } + } + + // Process the MC + void process(aod::ResoCollision& collision, aod::ResoMCParents& resoParents) + { + // Fill the event counter + histos.fill(HIST("hVertexZ"), collision.posZ()); + fillHistograms(collision, resoParents); // Fill histograms, MC + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/Tutorials/PWGLF/Resonance/resonances_step4.cxx b/Tutorials/PWGLF/Resonance/resonances_step4.cxx new file mode 100644 index 00000000000..05f7b35f7cf --- /dev/null +++ b/Tutorials/PWGLF/Resonance/resonances_step4.cxx @@ -0,0 +1,109 @@ +// 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 this is a starting point for the Resonances tutorial for MC +/// \author Hirak Kumar Koley +/// \since 11/10/2024 + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFResonanceTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 4 +// Producing histograms for Generated MCs +struct resonances_tutorial { + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Configurable for number of bins + Configurable nBins{"nBins", 100, "N bins in all histos"}; + // Configurable for min pT cut + Configurable cMinPtcut{"cMinPtcut", 0.15, "Track minium pt cut"}; + + /// Histograms + ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12.0, 12.1, 12.2, 12.3, 12.4, 12.5, 12.6, 12.7, 12.8, 12.9, 13.0, 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7, 13.8, 13.9, 14.0, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15.0}, "Binning of the pT axis"}; + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 1., 5., 10., 30., 50., 70., 100., 110.}, "Binning of the centrality axis"}; + + // Initialize the ananlysis task + void init(o2::framework::InitContext&) + { + AxisSpec centAxis = {binsCent, "V0M (%)"}; + AxisSpec ptAxis = {binsPt, "#it{p}_{T} (GeV/#it{c})"}; + + // register histograms + histos.add("hVertexZ", "hVertexZ", HistType::kTH1F, {{nBins, -15., 15.}}); + histos.add("hEta", "Eta distribution", kTH1F, {{200, -1.0f, 1.0f}}); + histos.add("hMultiplicityPercent", "Multiplicity Percentile", kTH1F, {{120, 0.0f, 120.0f}}); + + // MC QA + histos.add("hphipt", "pT distribution of True MC phi", kTH1F, {ptAxis}); + histos.add("phiGen", "pT distribution of True MC phi", kTH2F, {ptAxis, centAxis}); + + // Print output histograms statistics + LOG(info) << "Size of the histograms in resonance tutorial step1:"; + histos.print(); + } + + // MC particle selection + template + bool ptCut(const ParticleType resoParents) + { + // basic pt cuts + if (std::abs(resoParents.pt()) < cMinPtcut) + return false; + + return true; + } + + // Fill histograms (main function) + template + void fillHistograms(const CollisionType& collision, const ParticleType& resoParents) + { + auto multiplicity = collision.cent(); + for (auto& part : resoParents) { // loop over all pre-filtered MC particles + if (!ptCut(part)) + continue; // pt selection + + // QA plots + histos.fill(HIST("hEta"), part.eta()); + + if (abs(part.pdgCode()) != 333) // phi(0) + continue; + if (abs(part.y()) > 0.5) { // rapidity cut + continue; + } + if (abs(part.daughterPDG1()) != 321 || abs(part.daughterPDG2()) != 321) { // At least one decay to Kaon + continue; + } + histos.fill(HIST("phiGen"), part.pt(), multiplicity); + histos.fill(HIST("hphipt"), part.pt()); + } + } + + // Process the MC + void process(aod::ResoCollision& collision, aod::ResoMCParents& resoParents) + { + auto multiplicity = collision.cent(); + + // Fill the event counter + histos.fill(HIST("hVertexZ"), collision.posZ()); + histos.fill(HIST("hMultiplicityPercent"), multiplicity); + + fillHistograms(collision, resoParents); // Fill histograms, MC + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/Tutorials/PWGLF/Resonance/resonances_step5.cxx b/Tutorials/PWGLF/Resonance/resonances_step5.cxx new file mode 100644 index 00000000000..7d8463b9236 --- /dev/null +++ b/Tutorials/PWGLF/Resonance/resonances_step5.cxx @@ -0,0 +1,136 @@ +// 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 this is a starting point for the Resonances tutorial +/// \author Hirak Kumar Koley +/// \since 11/10/2024 + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFResonanceTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 5 +// loop over all MC Tracks and produce basic QA histograms +struct resonances_tutorial { + // Define slice per Resocollision + SliceCache cache; + Preslice perResoCollision = aod::resodaughter::resoCollisionId; + Preslice perCollision = aod::track::collisionId; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Configurable for number of bins + Configurable nBins{"nBins", 100, "N bins in all histos"}; + // Configurable for min pT cut + Configurable cMinPtcut{"cMinPtcut", 0.15, "Track minium pt cut"}; + + // Track selection + // primary track condition + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) + Configurable cfgPVContributor{"cfgPVContributor", true, "PV contributor track selection"}; // PV Contriuibutor + + // DCA Selections + // DCAr to PV + Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 0.5, "Track DCAr cut to PV Maximum"}; + // DCAz to PV + Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; + + // PID selection + Configurable nsigmaCutTPC{"nsigmacutTPC", 3.0, "Value of the TPC Nsigma cut"}; + Configurable nsigmacutTOF{"nsigmacutTOF", 3.0, "Value /home/hirak/Desktop/LstarTaskTest/run/dpl-config.jsonof the TOF Nsigma cut"}; + + // Initialize the ananlysis task + void init(o2::framework::InitContext&) + { + // register histograms + histos.add("hVertexZ", "hVertexZ", HistType::kTH1F, {{nBins, -15., 15.}}); + histos.add("hEta", "Eta distribution", kTH1F, {{200, -1.0f, 1.0f}}); + histos.add("hMultiplicityPercent", "Multiplicity Percentile", kTH1F, {{120, 0.0f, 120.0f}}); + histos.add("hDcaxy", "Dcaxy distribution", kTH1F, {{100, -0.5f, 0.5f}}); + histos.add("hDcaz", "Dcaz distribution", kTH1F, {{100, -0.5f, 0.5f}}); + histos.add("hNsigmaKaonTPC", "NsigmaKaon TPC distribution", kTH1F, {{100, -10.0f, 10.0f}}); + histos.add("hNsigmaKaonTOF", "NsigmaKaon TOF distribution", kTH1F, {{100, -10.0f, 10.0f}}); + + // Print output histograms statistics + LOG(info) << "Size of the histograms in resonance tutorial step2:"; + histos.print(); + } + + // Track selection + template + bool trackCut(const TrackType track) + { + // basic track cuts + if (std::abs(track.pt()) < cMinPtcut) + return false; + if (std::abs(track.dcaXY()) > cMaxDCArToPVcut) + return false; + if (std::abs(track.dcaZ()) > cMaxDCAzToPVcut) + return false; + if (cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (cfgPVContributor && !track.isPVContributor()) + return false; + return true; + } + + // PID selection TPC +TOF Veto + template + bool selectionPID(const T& candidate) + { + bool tpcPass = std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC; + bool tofPass = (candidate.hasTOF()) ? std::abs(candidate.tofNSigmaKa()) < nsigmacutTOF : true; + if (tpcPass && tofPass) { + return true; + } + return false; + } + + template + void fillHistograms(const CollisionType& /* collision */, const TracksType& dTracks) + { + for (auto track : dTracks) { // loop over all dTracks + if (!trackCut(track) || !selectionPID(track)) { + continue; // track selection and PID selection + } + // QA plots + histos.fill(HIST("hEta"), track.eta()); + histos.fill(HIST("hDcaxy"), track.dcaXY()); + histos.fill(HIST("hDcaz"), track.dcaZ()); + histos.fill(HIST("hNsigmaKaonTPC"), track.tpcNSigmaKa()); + if (track.hasTOF()) { + histos.fill(HIST("hNsigmaKaonTOF"), track.tofNSigmaKa()); + } + } + } + + // Process the data + void process(aod::ResoCollision& collision, + soa::Join const& resotracks) + { + // Fill the event counter + histos.fill(HIST("hVertexZ"), collision.posZ()); + histos.fill(HIST("hMultiplicityPercent"), collision.cent()); + + fillHistograms(collision, resotracks); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/Tutorials/PWGLF/Resonance/resonances_step6.cxx b/Tutorials/PWGLF/Resonance/resonances_step6.cxx new file mode 100644 index 00000000000..23ccac6dfd2 --- /dev/null +++ b/Tutorials/PWGLF/Resonance/resonances_step6.cxx @@ -0,0 +1,188 @@ +// 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 this is a starting point for the Resonances tutorial +/// \author Hirak Kumar Koley +/// \since 11/10/2024 + +#include + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFResonanceTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 6 +// Resonance reconstruction +struct resonances_tutorial { + // Define slice per Resocollision + SliceCache cache; + Preslice perResoCollision = aod::resodaughter::resoCollisionId; + Preslice perCollision = aod::track::collisionId; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + ///// Configurables + /// Histograms + ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12.0, 12.1, 12.2, 12.3, 12.4, 12.5, 12.6, 12.7, 12.8, 12.9, 13.0, 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7, 13.8, 13.9, 14.0, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15.0}, "Binning of the pT axis"}; + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 1., 5., 10., 30., 50., 70., 100., 110.}, "Binning of the centrality axis"}; + Configurable cInvMassStart{"cInvMassStart", 0.6, "Invariant mass start"}; + Configurable cInvMassEnd{"cInvMassEnd", 1.5, "Invariant mass end"}; + Configurable cInvMassBins{"cInvMassBins", 900, "Invariant mass binning"}; + + // Configurable for number of bins + Configurable nBins{"nBins", 100, "N bins in all histos"}; + // Configurable for min pT cut + Configurable cMinPtcut{"cMinPtcut", 0.15, "Track minium pt cut"}; + + // Track selection + // primary track condition + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) + Configurable cfgPVContributor{"cfgPVContributor", true, "PV contributor track selection"}; // PV Contriuibutor + + // DCA Selections + // DCAr to PV + Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 0.5, "Track DCAr cut to PV Maximum"}; + // DCAz to PV + Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; + + // PID selection + Configurable nsigmaCutTPC{"nsigmacutTPC", 3.0, "Value of the TPC Nsigma cut"}; + Configurable nsigmacutTOF{"nsigmacutTOF", 3.0, "Value of the TOF Nsigma cut"}; + + // variables + double massKa = o2::constants::physics::MassKPlus; + + // Initialize the ananlysis task + void init(o2::framework::InitContext&) + { + AxisSpec centAxis = {binsCent, "V0M (%)"}; + AxisSpec ptAxis = {binsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec invMassAxis = {cInvMassBins, cInvMassStart, cInvMassEnd, "Invariant Mass (GeV/#it{c}^2)"}; + + // register histograms + histos.add("hVertexZ", "hVertexZ", HistType::kTH1F, {{nBins, -15., 15.}}); + histos.add("hEta", "Eta distribution", kTH1F, {{200, -1.0f, 1.0f}}); + histos.add("hMultiplicityPercent", "Multiplicity Percentile", kTH1F, {{120, 0.0f, 120.0f}}); + histos.add("hDcaxy", "Dcaxy distribution", kTH1F, {{100, -0.5f, 0.5f}}); + histos.add("hDcaz", "Dcaz distribution", kTH1F, {{100, -0.5f, 0.5f}}); + histos.add("hNsigmaKaonTPC", "NsigmaKaon TPC distribution", kTH1F, {{100, -10.0f, 10.0f}}); + histos.add("hNsigmaKaonTOF", "NsigmaKaon TOF distribution", kTH1F, {{100, -10.0f, 10.0f}}); + + // MC QA + histos.add("h3Recphiinvmass", "Invariant mass of Reconstructed MC phi", kTH3F, {centAxis, ptAxis, invMassAxis}); + histos.add("phiRec", "pT distribution of Reconstructed MC phi", kTH2F, {ptAxis, centAxis}); + histos.add("phiRecinvmass", "Inv mass distribution of Reconstructed MC Phi", kTH1F, {invMassAxis}); + + // Print output histograms statistics + LOG(info) << "Size of the histograms in resonance tutorial step2:"; + histos.print(); + } + + // Track selection + template + bool trackCut(const TrackType track) + { + // basic track cuts + if (std::abs(track.pt()) < cMinPtcut) + return false; + if (std::abs(track.dcaXY()) > cMaxDCArToPVcut) + return false; + if (std::abs(track.dcaZ()) > cMaxDCAzToPVcut) + return false; + if (cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (cfgPVContributor && !track.isPVContributor()) + return false; + return true; + } + + // PID selection TPC +TOF Veto + template + bool selectionPID(const T& candidate) + { + bool tpcPass = std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC; + bool tofPass = (candidate.hasTOF()) ? std::abs(candidate.tofNSigmaKa()) < nsigmacutTOF : true; + if (tpcPass && tofPass) { + return true; + } + return false; + } + + // Fill histograms (main function) + double rapidity, mass, pT, paircharge; + TLorentzVector daughter1, daughter2, lResonance; + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksType& dTracks2) + { + auto multiplicity = collision.cent(); + for (auto track1 : dTracks1) { // loop over all dTracks1 + if (!trackCut(track1) || !selectionPID(track1)) { + continue; // track selection and PID selection + } + // QA plots + histos.fill(HIST("hEta"), track1.eta()); + histos.fill(HIST("hDcaxy"), track1.dcaXY()); + histos.fill(HIST("hDcaz"), track1.dcaZ()); + histos.fill(HIST("hNsigmaKaonTPC"), track1.tpcNSigmaKa()); + if (track1.hasTOF()) { + histos.fill(HIST("hNsigmaKaonTOF"), track1.tofNSigmaKa()); + } + for (auto track2 : dTracks2) { // loop over all dTracks2 + if (!trackCut(track2) || !selectionPID(track2)) { + continue; // track selection and PID selection + } + if (track2.index() <= track1.index()) { + continue; // condition to avoid double counting of pair + } + daughter1.SetXYZM(track1.px(), track1.py(), track1.pz(), massKa); // set the daughter1 4-momentum + daughter2.SetXYZM(track2.px(), track2.py(), track2.pz(), massKa); // set the daughter2 4-momentum + lResonance = daughter1 + daughter2; // calculate the lResonance 4-momentum + mass = lResonance.M(); + pT = lResonance.Pt(); + rapidity = lResonance.Rapidity(); + + if (abs(track1.pdgCode()) != 321 || abs(track2.pdgCode()) != 321) + continue; + if (track1.motherId() != track2.motherId()) // Same mother + continue; + if (abs(track1.motherPDG()) != 333) + continue; + + // MC histograms + histos.fill(HIST("phiRec"), lResonance.Pt(), multiplicity); + histos.fill(HIST("phiRecinvmass"), lResonance.M()); + histos.fill(HIST("h3Recphiinvmass"), multiplicity, lResonance.Pt(), lResonance.M()); + } + } + } + + // Process the data + void process(aod::ResoCollision& collision, + soa::Join const& resotracks) + { + // Fill the event counter + histos.fill(HIST("hVertexZ"), collision.posZ()); + histos.fill(HIST("hMultiplicityPercent"), collision.cent()); + + fillHistograms(collision, resotracks, resotracks); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/Tutorials/PWGLF/Strangeness/CMakeLists.txt b/Tutorials/PWGLF/Strangeness/CMakeLists.txt index ede23b4c734..39734cb836a 100644 --- a/Tutorials/PWGLF/Strangeness/CMakeLists.txt +++ b/Tutorials/PWGLF/Strangeness/CMakeLists.txt @@ -9,28 +9,6 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. -# Strangeness analysis tutorial -o2physics_add_dpl_workflow(strangeness-step0 - SOURCES strangeness_step0.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME AnalysisTutorial) +add_subdirectory(pp) +add_subdirectory(PbPb) -o2physics_add_dpl_workflow(strangeness-step1 - SOURCES strangeness_step1.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME AnalysisTutorial) - -o2physics_add_dpl_workflow(strangeness-step2 - SOURCES strangeness_step2.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME AnalysisTutorial) - -o2physics_add_dpl_workflow(strangeness-step3 - SOURCES strangeness_step3.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME AnalysisTutorial) - -o2physics_add_dpl_workflow(strangeness-step4 - SOURCES strangeness_step4.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME AnalysisTutorial) diff --git a/Tutorials/PWGLF/Strangeness/PbPb/Analysis/CMakeLists.txt b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/CMakeLists.txt new file mode 100644 index 00000000000..d050dc59b47 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/CMakeLists.txt @@ -0,0 +1,41 @@ +# 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-pbpb-skeleton + SOURCES strangeness_pbpb_skeleton.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-pbpb-step0 + SOURCES strangeness_pbpb_step0.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-pbpb-step1 + SOURCES strangeness_pbpb_step1.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-pbpb-step2 + SOURCES strangeness_pbpb_step2.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-pbpb-step3 + SOURCES strangeness_pbpb_step3.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-pbpb-step4 + SOURCES strangeness_pbpb_step4.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + diff --git a/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_skeleton.sh b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_skeleton.sh new file mode 100644 index 00000000000..9327402771f --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_skeleton.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="skeleton" +LOGFILE="log-${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration_skeleton.json" + +o2-analysistutorial-lf-strangeness-pbpb-skeleton "${OPTION}" --aod-file @input_data.txt > "$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}/${STEP}.json" +else + echo "Error: Exit code ${rc}" + echo "Check the log file ${LOGFILE}" + exit ${rc} +fi \ No newline at end of file diff --git a/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_step0.sh b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_step0.sh new file mode 100644 index 00000000000..bcfeb9ab890 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_step0.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="0" +LOGFILE="log-${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration_step0.json" + +o2-analysis-lf-cascadespawner "${OPTION}" | o2-analysistutorial-lf-strangeness-pbpb-step0 "${OPTION}" --aod-file @input_data.txt > "$LOGFILE" 2>&1 + +# report status +rc=$? +if [ $rc -eq 0 ]; then + echo "No problems!" + mkdir -p "${DIR_THIS}/results/step${STEP}" + mv AnalysisResults.root "${DIR_THIS}/results/step${STEP}/AnalysisResults.root" + mv dpl-config.json "${DIR_THIS}/results/step${STEP}/step${STEP}.json" +else + echo "Error: Exit code ${rc}" + echo "Check the log file ${LOGFILE}" + exit ${rc} +fi \ No newline at end of file diff --git a/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_step1.sh b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_step1.sh new file mode 100644 index 00000000000..826f0ea1421 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_step1.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="1" +LOGFILE="log-${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration_step1.json" + +o2-analysis-lf-cascadespawner "${OPTION}" | o2-analysistutorial-lf-strangeness-pbpb-step1 "${OPTION}" --aod-file @input_data.txt > "$LOGFILE" 2>&1 + +# report status +rc=$? +if [ $rc -eq 0 ]; then + echo "No problems!" + mkdir -p "${DIR_THIS}/results/step${STEP}" + mv AnalysisResults.root "${DIR_THIS}/results/step${STEP}/AnalysisResults.root" + mv dpl-config.json "${DIR_THIS}/results/step${STEP}/step${STEP}.json" +else + echo "Error: Exit code ${rc}" + echo "Check the log file ${LOGFILE}" + exit ${rc} +fi \ No newline at end of file diff --git a/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_step2.sh b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_step2.sh new file mode 100644 index 00000000000..aca62bad45e --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_step2.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="2" +LOGFILE="log-${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration_step2.json" + +o2-analysis-lf-cascadespawner "${OPTION}" | o2-analysistutorial-lf-strangeness-pbpb-step2 "${OPTION}" --aod-file @input_data.txt > "$LOGFILE" 2>&1 + +# report status +rc=$? +if [ $rc -eq 0 ]; then + echo "No problems!" + mkdir -p "${DIR_THIS}/results/step${STEP}" + mv AnalysisResults.root "${DIR_THIS}/results/step${STEP}/AnalysisResults.root" + mv dpl-config.json "${DIR_THIS}/results/step${STEP}/step${STEP}.json" +else + echo "Error: Exit code ${rc}" + echo "Check the log file ${LOGFILE}" + exit ${rc} +fi \ No newline at end of file diff --git a/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_step3.sh b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_step3.sh new file mode 100644 index 00000000000..580b3c0c17f --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_step3.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="3" +LOGFILE="log-${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration_step3.json" + +o2-analysis-lf-cascadepid "${OPTION}" | o2-analysis-lf-cascadespawner "${OPTION}" | o2-analysistutorial-lf-strangeness-pbpb-step3 "${OPTION}" --aod-file @input_data.txt > "$LOGFILE" 2>&1 + +# report status +rc=$? +if [ $rc -eq 0 ]; then + echo "No problems!" + mkdir -p "${DIR_THIS}/results/step${STEP}" + mv AnalysisResults.root "${DIR_THIS}/results/step${STEP}/AnalysisResults.root" + mv dpl-config.json "${DIR_THIS}/results/step${STEP}/step${STEP}.json" +else + echo "Error: Exit code ${rc}" + echo "Check the log file ${LOGFILE}" + exit ${rc} +fi diff --git a/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_step4.sh b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_step4.sh new file mode 100644 index 00000000000..08f929b3fa8 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/run_step4.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="4" +LOGFILE="log-${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration_step4.json" + +o2-analysis-lf-cascadepid "${OPTION}" | o2-analysis-lf-cascadespawner "${OPTION}" | o2-analysistutorial-lf-strangeness-pbpb-step4 "${OPTION}" --aod-file @input_data.txt > "$LOGFILE" 2>&1 + +# report status +rc=$? +if [ $rc -eq 0 ]; then + echo "No problems!" + mkdir -p "${DIR_THIS}/results/step${STEP}" + mv AnalysisResults.root "${DIR_THIS}/results/step${STEP}/AnalysisResults.root" + mv dpl-config.json "${DIR_THIS}/results/step${STEP}/step${STEP}.json" +else + echo "Error: Exit code ${rc}" + echo "Check the log file ${LOGFILE}" + exit ${rc} +fi \ No newline at end of file diff --git a/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_skeleton.cxx b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_skeleton.cxx new file mode 100644 index 00000000000..788aaead7ae --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_skeleton.cxx @@ -0,0 +1,67 @@ +// 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 Strangeness tutorial +/// \author Romain Schotter +/// based on the original codes from: +/// \author Nepeivoda Roman (roman.nepeivoda@cern.ch) +/// \author Chiara De Martin (chiara.de.martin@cern.ch) + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Common/DataModel/EventSelection.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Framework/O2DatabasePDGPlugin.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct strangeness_pbpb_tutorial { + // 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)"}; + + // PDG data base + Service pdgDB; + + 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)}; +} diff --git a/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_step0.cxx b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_step0.cxx new file mode 100644 index 00000000000..b0e595246d7 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_step0.cxx @@ -0,0 +1,86 @@ +// 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 Strangeness tutorial +/// \author Romain Schotter +/// based on the original codes from: +/// \author Nepeivoda Roman (roman.nepeivoda@cern.ch) +/// \author Chiara De Martin (chiara.de.martin@cern.ch) + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Common/DataModel/EventSelection.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Framework/O2DatabasePDGPlugin.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 0 +// Starting point: loop over all cascades and fill invariant mass histogram + +struct strangeness_pbpb_tutorial { + // Histograms are defined with HistogramRegistry + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rXi{"xi", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rOmega{"omega", {}, 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)"}; + + // PDG data base + Service pdgDB; + + void init(InitContext const&) + { + // Axes + AxisSpec XiMassAxis = {100, 1.28f, 1.36f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec OmegaMassAxis = {100, 1.63f, 1.7f, "#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}}); + + // Xi/Omega reconstruction + rXi.add("hMassXi", "hMassXi", {HistType::kTH1F, {XiMassAxis}}); + + rOmega.add("hMassOmega", "hMassOmega", {HistType::kTH1F, {OmegaMassAxis}}); + } + + // 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::CascCores const& Cascades) + { + // Fill the event counter + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + + // Cascades + for (const auto& casc : Cascades) { + rXi.fill(HIST("hMassXi"), casc.mXi()); + rOmega.fill(HIST("hMassOmega"), casc.mOmega()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_step1.cxx b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_step1.cxx new file mode 100644 index 00000000000..836be98b240 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_step1.cxx @@ -0,0 +1,146 @@ +// 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 Strangeness tutorial +/// \author Romain Schotter +/// based on the original codes from: +/// \author Nepeivoda Roman (roman.nepeivoda@cern.ch) +/// \author Chiara De Martin (chiara.de.martin@cern.ch) + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Common/DataModel/EventSelection.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Framework/O2DatabasePDGPlugin.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 0 +// Starting point: loop over all cascades and fill invariant mass histogram +// STEP 1 +// Apply selections on topological variables of Cascades + +struct strangeness_pbpb_tutorial { + // Histograms are defined with HistogramRegistry + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rXi{"xi", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rOmega{"omega", {}, 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 cascade selection + Configurable cascadesetting_cospa{"cascadesetting_cospa", 0.98, "Casc CosPA"}; + Configurable cascadesetting_v0cospa{"cascadesetting_v0cospa", 0.97, "V0 CosPA"}; + Configurable cascadesetting_dcacascdau{"cascadesetting_dcacascdau", 1.0, "DCA cascade daughters"}; + Configurable cascadesetting_dcav0dau{"cascadesetting_dcav0dau", 1.0, "DCA v0 daughters"}; + Configurable cascadesetting_dcabachtopv{"cascadesetting_dcabachtopv", 0.06, "DCA bachelor to PV"}; + Configurable cascadesetting_dcapostopv{"cascadesetting_dcapostopv", 0.06, "DCA positive to PV"}; + Configurable cascadesetting_dcanegtopv{"cascadesetting_dcanegtopv", 0.06, "DCA negative to PV"}; + Configurable cascadesetting_mindcav0topv{"cascadesetting_mindcav0topv", 0.01, "minimum V0 DCA to PV"}; + Configurable cascadesetting_cascradius{"cascadesetting_cascradius", 0.5, "cascradius"}; + Configurable cascadesetting_v0radius{"cascadesetting_v0radius", 1.2, "v0radius"}; + Configurable cascadesetting_v0masswindow{"cascadesetting_v0masswindow", 0.01, "v0 mass window"}; + Configurable cascadesetting_competingmassrej{"cascadesetting_competingmassrej", 0.008, "Competing mass rejection"}; + + // PDG data base + Service pdgDB; + + void init(InitContext const&) + { + // Axes + AxisSpec XiMassAxis = {100, 1.28f, 1.36f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec OmegaMassAxis = {100, 1.63f, 1.7f, "#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}}); + + // Xi/Omega reconstruction + rXi.add("hMassXi", "hMassXi", {HistType::kTH1F, {XiMassAxis}}); + rXi.add("hMassXiSelected", "hMassXiSelected", {HistType::kTH1F, {XiMassAxis}}); + + rOmega.add("hMassOmega", "hMassOmega", {HistType::kTH1F, {OmegaMassAxis}}); + rOmega.add("hMassOmegaSelected", "hMassOmegaSelected", {HistType::kTH1F, {OmegaMassAxis}}); + + // Xi/Omega topological cuts + rXi.add("hCascDCAV0Daughters", "hCascDCAV0Daughters", {HistType::kTH1F, {{55, 0.0f, 2.2f}}}); + rXi.add("hCascCosPA", "hCascCosPA", {HistType::kTH1F, {{100, 0.95f, 1.f}}}); + + rOmega.add("hCascDCAV0Daughters", "hCascDCAV0Daughters", {HistType::kTH1F, {{55, 0.0f, 2.2f}}}); + rOmega.add("hCascCosPA", "hCascCosPA", {HistType::kTH1F, {{100, 0.95f, 1.f}}}); + } + + // 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 Cascades + // Cannot filter on dynamic columns + Filter preFilterCascades = (aod::cascdata::dcaV0daughters < cascadesetting_dcav0dau && + nabs(aod::cascdata::dcapostopv) > cascadesetting_dcapostopv && + nabs(aod::cascdata::dcanegtopv) > cascadesetting_dcanegtopv && + nabs(aod::cascdata::dcabachtopv) > cascadesetting_dcabachtopv && + aod::cascdata::dcacascdaughters < cascadesetting_dcacascdau); + + void process(soa::Filtered>::iterator const& collision, + soa::Filtered> const& Cascades) + { + // Fill the event counter + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + + // Cascades + for (const auto& casc : Cascades) { + rXi.fill(HIST("hMassXi"), casc.mXi()); + rOmega.fill(HIST("hMassOmega"), casc.mOmega()); + + // Cut on dynamic columns + if (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadesetting_cospa) + continue; + if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadesetting_v0cospa) + continue; + if (TMath::Abs(casc.mLambda() - pdgDB->Mass(3122)) > cascadesetting_v0masswindow) + continue; + if (casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()) < cascadesetting_mindcav0topv) + continue; + if (casc.cascradius() < cascadesetting_cascradius) + continue; + if (casc.v0radius() < cascadesetting_v0radius) + continue; + + // Fill histograms! (if possible) + rXi.fill(HIST("hMassXiSelected"), casc.mXi()); + + rXi.fill(HIST("hCascDCAV0Daughters"), casc.dcaV0daughters()); + rXi.fill(HIST("hCascCosPA"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + + if (TMath::Abs(casc.mXi() - pdgDB->Mass(3312)) > cascadesetting_competingmassrej) { // competing mass rejection, only in case of Omega + rOmega.fill(HIST("hMassOmegaSelected"), casc.mOmega()); + + rOmega.fill(HIST("hCascDCAV0Daughters"), casc.dcaV0daughters()); + rOmega.fill(HIST("hCascCosPA"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_step2.cxx b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_step2.cxx new file mode 100644 index 00000000000..1558bb78052 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_step2.cxx @@ -0,0 +1,182 @@ +// 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 Strangeness tutorial +/// \author Romain Schotter +/// based on the original codes from: +/// \author Nepeivoda Roman (roman.nepeivoda@cern.ch) +/// \author Chiara De Martin (chiara.de.martin@cern.ch) + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Common/DataModel/EventSelection.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Framework/O2DatabasePDGPlugin.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 0 +// Starting point: loop over all cascades and fill invariant mass histogram +// STEP 1 +// Apply selections on topological variables of Cascades +// STEP 2 +// Apply TPC PID selections on cascade daughter tracks + +struct strangeness_pbpb_tutorial { + // Histograms are defined with HistogramRegistry + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rXi{"xi", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rOmega{"omega", {}, 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 cascade selection + Configurable cascadesetting_cospa{"cascadesetting_cospa", 0.98, "Casc CosPA"}; + Configurable cascadesetting_v0cospa{"cascadesetting_v0cospa", 0.97, "V0 CosPA"}; + Configurable cascadesetting_dcacascdau{"cascadesetting_dcacascdau", 1.0, "DCA cascade daughters"}; + Configurable cascadesetting_dcav0dau{"cascadesetting_dcav0dau", 1.0, "DCA v0 daughters"}; + Configurable cascadesetting_dcabachtopv{"cascadesetting_dcabachtopv", 0.06, "DCA bachelor to PV"}; + Configurable cascadesetting_dcapostopv{"cascadesetting_dcapostopv", 0.06, "DCA positive to PV"}; + Configurable cascadesetting_dcanegtopv{"cascadesetting_dcanegtopv", 0.06, "DCA negative to PV"}; + Configurable cascadesetting_mindcav0topv{"cascadesetting_mindcav0topv", 0.01, "minimum V0 DCA to PV"}; + Configurable cascadesetting_cascradius{"cascadesetting_cascradius", 0.5, "cascradius"}; + Configurable cascadesetting_v0radius{"cascadesetting_v0radius", 1.2, "v0radius"}; + Configurable cascadesetting_v0masswindow{"cascadesetting_v0masswindow", 0.01, "v0 mass window"}; + Configurable cascadesetting_competingmassrej{"cascadesetting_competingmassrej", 0.008, "Competing mass rejection"}; + + // Configurable parameters for PID selection + Configurable NSigmaTPCPion{"NSigmaTPCPion", 4, "NSigmaTPCPion"}; + Configurable NSigmaTPCKaon{"NSigmaTPCKaon", 4, "NSigmaTPCKaon"}; + Configurable NSigmaTPCProton{"NSigmaTPCProton", 4, "NSigmaTPCProton"}; + + // PDG data base + Service pdgDB; + + void init(InitContext const&) + { + // Axes + AxisSpec XiMassAxis = {100, 1.28f, 1.36f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec OmegaMassAxis = {100, 1.63f, 1.7f, "#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}}); + + // Xi/Omega reconstruction + rXi.add("hMassXi", "hMassXi", {HistType::kTH1F, {XiMassAxis}}); + rXi.add("hMassXiSelected", "hMassXiSelected", {HistType::kTH1F, {XiMassAxis}}); + + rOmega.add("hMassOmega", "hMassOmega", {HistType::kTH1F, {OmegaMassAxis}}); + rOmega.add("hMassOmegaSelected", "hMassOmegaSelected", {HistType::kTH1F, {OmegaMassAxis}}); + + // Xi/Omega topological cuts + rXi.add("hCascDCAV0Daughters", "hCascDCAV0Daughters", {HistType::kTH1F, {{55, 0.0f, 2.2f}}}); + rXi.add("hCascCosPA", "hCascCosPA", {HistType::kTH1F, {{100, 0.95f, 1.f}}}); + + rOmega.add("hCascDCAV0Daughters", "hCascDCAV0Daughters", {HistType::kTH1F, {{55, 0.0f, 2.2f}}}); + rOmega.add("hCascCosPA", "hCascCosPA", {HistType::kTH1F, {{100, 0.95f, 1.f}}}); + } + + // 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 Cascades + // Cannot filter on dynamic columns + Filter preFilterCascades = (aod::cascdata::dcaV0daughters < cascadesetting_dcav0dau && + nabs(aod::cascdata::dcapostopv) > cascadesetting_dcapostopv && + nabs(aod::cascdata::dcanegtopv) > cascadesetting_dcanegtopv && + nabs(aod::cascdata::dcabachtopv) > cascadesetting_dcabachtopv && + aod::cascdata::dcacascdaughters < cascadesetting_dcacascdau); + + // Defining the type of the daughter tracks + using dauTracks = soa::Join; + + void process(soa::Filtered>::iterator const& collision, + soa::Filtered> const& Cascades, + dauTracks const&) + { + // Fill the event counter + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + + // Cascades + for (const auto& casc : Cascades) { + const auto& bachDaughterTrackCasc = casc.bachTrackExtra_as(); + const auto& posDaughterTrackCasc = casc.posTrackExtra_as(); + const auto& negDaughterTrackCasc = casc.negTrackExtra_as(); + + rXi.fill(HIST("hMassXi"), casc.mXi()); + rOmega.fill(HIST("hMassOmega"), casc.mOmega()); + + // Cut on dynamic columns + if (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadesetting_cospa) + continue; + if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadesetting_v0cospa) + continue; + if (TMath::Abs(casc.mLambda() - pdgDB->Mass(3122)) > cascadesetting_v0masswindow) + continue; + if (casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()) < cascadesetting_mindcav0topv) + continue; + if (casc.cascradius() < cascadesetting_cascradius) + continue; + if (casc.v0radius() < cascadesetting_v0radius) + continue; + + // PID selection + if (casc.sign() < 0) { + if (TMath::Abs(posDaughterTrackCasc.tpcNSigmaPr()) > NSigmaTPCProton) { + continue; + } + if (TMath::Abs(negDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { + continue; + } + } else { + if (TMath::Abs(negDaughterTrackCasc.tpcNSigmaPr()) > NSigmaTPCProton) { + continue; + } + if (TMath::Abs(posDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { + continue; + } + } + + // Fill histograms! (if possible) + if (TMath::Abs(bachDaughterTrackCasc.tpcNSigmaPi()) < NSigmaTPCPion) { // Xi case + rXi.fill(HIST("hMassXiSelected"), casc.mXi()); + + rXi.fill(HIST("hCascDCAV0Daughters"), casc.dcaV0daughters()); + rXi.fill(HIST("hCascCosPA"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + } + if (TMath::Abs(bachDaughterTrackCasc.tpcNSigmaKa()) < NSigmaTPCKaon) { // Omega case + if (TMath::Abs(casc.mXi() - pdgDB->Mass(3312)) > cascadesetting_competingmassrej) { // competing mass rejection, only in case of Omega + rOmega.fill(HIST("hMassOmegaSelected"), casc.mOmega()); + + rOmega.fill(HIST("hCascDCAV0Daughters"), casc.dcaV0daughters()); + rOmega.fill(HIST("hCascCosPA"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_step3.cxx b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_step3.cxx new file mode 100644 index 00000000000..f12a4f02560 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_step3.cxx @@ -0,0 +1,243 @@ +// 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 Strangeness tutorial +/// \author Romain Schotter +/// based on the original codes from: +/// \author Nepeivoda Roman (roman.nepeivoda@cern.ch) +/// \author Chiara De Martin (chiara.de.martin@cern.ch) + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Common/DataModel/EventSelection.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Framework/O2DatabasePDGPlugin.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 0 +// Starting point: loop over all cascades and fill invariant mass histogram +// STEP 1 +// Apply selections on topological variables of Cascades +// STEP 2 +// Apply TPC PID selections on cascade daughter tracks +// STEP 3 +// Apply TOF PID selections on cascade daugther tracks (if info is available) + +struct strangeness_pbpb_tutorial { + // Histograms are defined with HistogramRegistry + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rXi{"xi", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rOmega{"omega", {}, 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 cascade selection + Configurable cascadesetting_cospa{"cascadesetting_cospa", 0.98, "Casc CosPA"}; + Configurable cascadesetting_v0cospa{"cascadesetting_v0cospa", 0.97, "V0 CosPA"}; + Configurable cascadesetting_dcacascdau{"cascadesetting_dcacascdau", 1.0, "DCA cascade daughters"}; + Configurable cascadesetting_dcav0dau{"cascadesetting_dcav0dau", 1.0, "DCA v0 daughters"}; + Configurable cascadesetting_dcabachtopv{"cascadesetting_dcabachtopv", 0.06, "DCA bachelor to PV"}; + Configurable cascadesetting_dcapostopv{"cascadesetting_dcapostopv", 0.06, "DCA positive to PV"}; + Configurable cascadesetting_dcanegtopv{"cascadesetting_dcanegtopv", 0.06, "DCA negative to PV"}; + Configurable cascadesetting_mindcav0topv{"cascadesetting_mindcav0topv", 0.01, "minimum V0 DCA to PV"}; + Configurable cascadesetting_cascradius{"cascadesetting_cascradius", 0.5, "cascradius"}; + Configurable cascadesetting_v0radius{"cascadesetting_v0radius", 1.2, "v0radius"}; + Configurable cascadesetting_v0masswindow{"cascadesetting_v0masswindow", 0.01, "v0 mass window"}; + Configurable cascadesetting_competingmassrej{"cascadesetting_competingmassrej", 0.008, "Competing mass rejection"}; + + // Configurable parameters for PID selection + Configurable NSigmaTPCPion{"NSigmaTPCPion", 4, "NSigmaTPCPion"}; + Configurable NSigmaTPCKaon{"NSigmaTPCKaon", 4, "NSigmaTPCKaon"}; + Configurable NSigmaTPCProton{"NSigmaTPCProton", 4, "NSigmaTPCProton"}; + + // Configurable parameters for TOF PID selection + Configurable NSigmaTOFPion{"NSigmaTOFPion", 3, "NSigmaTOFPion"}; + Configurable NSigmaTOFKaon{"NSigmaTOFKaon", 3, "NSigmaTOFKaon"}; + Configurable NSigmaTOFProton{"NSigmaTOFProton", 3, "NSigmaTOFProton"}; + + // PDG data base + Service pdgDB; + + void init(InitContext const&) + { + // Axes + AxisSpec XiMassAxis = {100, 1.28f, 1.36f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec OmegaMassAxis = {100, 1.63f, 1.7f, "#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}}); + + // Xi/Omega reconstruction + rXi.add("hMassXi", "hMassXi", {HistType::kTH1F, {XiMassAxis}}); + rXi.add("hMassXiSelected", "hMassXiSelected", {HistType::kTH1F, {XiMassAxis}}); + rXi.add("hMassXiSelectedWithTOF", "hMassXiSelectedWithTOF", {HistType::kTH1F, {XiMassAxis}}); + + rOmega.add("hMassOmega", "hMassOmega", {HistType::kTH1F, {OmegaMassAxis}}); + rOmega.add("hMassOmegaSelected", "hMassOmegaSelected", {HistType::kTH1F, {OmegaMassAxis}}); + rOmega.add("hMassOmegaSelectedWithTOF", "hMassOmegaSelectedWithTOF", {HistType::kTH1F, {OmegaMassAxis}}); + + // Xi/Omega topological cuts + rXi.add("hCascDCAV0Daughters", "hCascDCAV0Daughters", {HistType::kTH1F, {{55, 0.0f, 2.2f}}}); + rXi.add("hCascCosPA", "hCascCosPA", {HistType::kTH1F, {{100, 0.95f, 1.f}}}); + + rOmega.add("hCascDCAV0Daughters", "hCascDCAV0Daughters", {HistType::kTH1F, {{55, 0.0f, 2.2f}}}); + rOmega.add("hCascCosPA", "hCascCosPA", {HistType::kTH1F, {{100, 0.95f, 1.f}}}); + } + + // 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 Cascades + // Cannot filter on dynamic columns + Filter preFilterCascades = (aod::cascdata::dcaV0daughters < cascadesetting_dcav0dau && + nabs(aod::cascdata::dcapostopv) > cascadesetting_dcapostopv && + nabs(aod::cascdata::dcanegtopv) > cascadesetting_dcanegtopv && + nabs(aod::cascdata::dcabachtopv) > cascadesetting_dcabachtopv && + aod::cascdata::dcacascdaughters < cascadesetting_dcacascdau); + + // Defining the type of the daughter tracks + using dauTracks = soa::Join; + + void process(soa::Filtered>::iterator const& collision, + soa::Filtered> const& Cascades, + dauTracks const&) + { + // Fill the event counter + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + + // Cascades + for (const auto& casc : Cascades) { + const auto& bachDaughterTrackCasc = casc.bachTrackExtra_as(); + const auto& posDaughterTrackCasc = casc.posTrackExtra_as(); + const auto& negDaughterTrackCasc = casc.negTrackExtra_as(); + + rXi.fill(HIST("hMassXi"), casc.mXi()); + rOmega.fill(HIST("hMassOmega"), casc.mOmega()); + + // Cut on dynamic columns + if (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadesetting_cospa) + continue; + if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadesetting_v0cospa) + continue; + if (TMath::Abs(casc.mLambda() - pdgDB->Mass(3122)) > cascadesetting_v0masswindow) + continue; + if (casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()) < cascadesetting_mindcav0topv) + continue; + if (casc.cascradius() < cascadesetting_cascradius) + continue; + if (casc.v0radius() < cascadesetting_v0radius) + continue; + + // PID selection + if (casc.sign() < 0) { + if (TMath::Abs(posDaughterTrackCasc.tpcNSigmaPr()) > NSigmaTPCProton) { + continue; + } + if (TMath::Abs(negDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { + continue; + } + } else { + if (TMath::Abs(negDaughterTrackCasc.tpcNSigmaPr()) > NSigmaTPCProton) { + continue; + } + if (TMath::Abs(posDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { + continue; + } + } + + // TOF PID check + bool xiPassTOFSelection = true; + bool omegaPassTOFSelection = true; + if (casc.sign() < 0) { + if (posDaughterTrackCasc.hasTOF()) { + if (TMath::Abs(casc.tofNSigmaXiLaPr()) > NSigmaTOFProton) { + xiPassTOFSelection &= false; + } + if (TMath::Abs(casc.tofNSigmaOmLaPr()) > NSigmaTOFProton) { + omegaPassTOFSelection &= false; + } + } + if (negDaughterTrackCasc.hasTOF()) { + if (TMath::Abs(casc.tofNSigmaXiLaPi()) > NSigmaTOFPion) { + xiPassTOFSelection &= false; + } + if (TMath::Abs(casc.tofNSigmaOmLaPi()) > NSigmaTOFPion) { + omegaPassTOFSelection &= false; + } + } + } else { + if (posDaughterTrackCasc.hasTOF()) { + if (TMath::Abs(casc.tofNSigmaXiLaPi()) > NSigmaTOFPion) { + xiPassTOFSelection &= false; + } + if (TMath::Abs(casc.tofNSigmaOmLaPi()) > NSigmaTOFPion) { + omegaPassTOFSelection &= false; + } + } + if (negDaughterTrackCasc.hasTOF()) { + if (TMath::Abs(casc.tofNSigmaXiLaPr()) > NSigmaTOFProton) { + xiPassTOFSelection &= false; + } + if (TMath::Abs(casc.tofNSigmaOmLaPr()) > NSigmaTOFProton) { + omegaPassTOFSelection &= false; + } + } + } + + if (bachDaughterTrackCasc.hasTOF()) { + if (TMath::Abs(casc.tofNSigmaXiPi()) > NSigmaTOFPion) { + xiPassTOFSelection &= false; + } + if (TMath::Abs(casc.tofNSigmaOmKa()) > NSigmaTOFKaon) { + omegaPassTOFSelection &= false; + } + } + + // Fill histograms! (if possible) + if (TMath::Abs(bachDaughterTrackCasc.tpcNSigmaPi()) < NSigmaTPCPion) { // Xi case + rXi.fill(HIST("hMassXiSelected"), casc.mXi()); + if (xiPassTOFSelection) + rXi.fill(HIST("hMassXiSelectedWithTOF"), casc.mXi()); + + rXi.fill(HIST("hCascDCAV0Daughters"), casc.dcaV0daughters()); + rXi.fill(HIST("hCascCosPA"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + } + if (TMath::Abs(bachDaughterTrackCasc.tpcNSigmaKa()) < NSigmaTPCKaon) { // Omega case + if (TMath::Abs(casc.mXi() - pdgDB->Mass(3312)) > cascadesetting_competingmassrej) { // competing mass rejection, only in case of Omega + rOmega.fill(HIST("hMassOmegaSelected"), casc.mOmega()); + if (omegaPassTOFSelection) + rOmega.fill(HIST("hMassOmegaSelectedWithTOF"), casc.mOmega()); + + rOmega.fill(HIST("hCascDCAV0Daughters"), casc.dcaV0daughters()); + rOmega.fill(HIST("hCascCosPA"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_step4.cxx b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_step4.cxx new file mode 100644 index 00000000000..d45ef3c26a1 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/PbPb/Analysis/strangeness_pbpb_step4.cxx @@ -0,0 +1,324 @@ +// 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 Strangeness tutorial +/// \author Romain Schotter +/// based on the original codes from: +/// \author Nepeivoda Roman (roman.nepeivoda@cern.ch) +/// \author Chiara De Martin (chiara.de.martin@cern.ch) + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Common/DataModel/EventSelection.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Framework/O2DatabasePDGPlugin.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 0 +// Starting point: loop over all cascades and fill invariant mass histogram +// STEP 1 +// Apply selections on topological variables of Cascades +// STEP 2 +// Apply TPC PID selections on cascade daughter tracks +// STEP 3 +// Apply TOF PID selections on cascade daugther tracks (if info is available) +// STEP 4 +// Check the MC information of the cascades + +struct strangeness_pbpb_tutorial { + // Histograms are defined with HistogramRegistry + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rXi{"xi", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rOmega{"omega", {}, 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 cascade selection + Configurable cascadesetting_cospa{"cascadesetting_cospa", 0.98, "Casc CosPA"}; + Configurable cascadesetting_v0cospa{"cascadesetting_v0cospa", 0.97, "V0 CosPA"}; + Configurable cascadesetting_dcacascdau{"cascadesetting_dcacascdau", 1.0, "DCA cascade daughters"}; + Configurable cascadesetting_dcav0dau{"cascadesetting_dcav0dau", 1.0, "DCA v0 daughters"}; + Configurable cascadesetting_dcabachtopv{"cascadesetting_dcabachtopv", 0.06, "DCA bachelor to PV"}; + Configurable cascadesetting_dcapostopv{"cascadesetting_dcapostopv", 0.06, "DCA positive to PV"}; + Configurable cascadesetting_dcanegtopv{"cascadesetting_dcanegtopv", 0.06, "DCA negative to PV"}; + Configurable cascadesetting_mindcav0topv{"cascadesetting_mindcav0topv", 0.01, "minimum V0 DCA to PV"}; + Configurable cascadesetting_cascradius{"cascadesetting_cascradius", 0.5, "cascradius"}; + Configurable cascadesetting_v0radius{"cascadesetting_v0radius", 1.2, "v0radius"}; + Configurable cascadesetting_v0masswindow{"cascadesetting_v0masswindow", 0.01, "v0 mass window"}; + Configurable cascadesetting_competingmassrej{"cascadesetting_competingmassrej", 0.008, "Competing mass rejection"}; + + // Configurable parameters for PID selection + Configurable NSigmaTPCPion{"NSigmaTPCPion", 4, "NSigmaTPCPion"}; + Configurable NSigmaTPCKaon{"NSigmaTPCKaon", 4, "NSigmaTPCKaon"}; + Configurable NSigmaTPCProton{"NSigmaTPCProton", 4, "NSigmaTPCProton"}; + + // Configurable parameters for TOF PID selection + Configurable NSigmaTOFPion{"NSigmaTOFPion", 3, "NSigmaTOFPion"}; + Configurable NSigmaTOFKaon{"NSigmaTOFKaon", 3, "NSigmaTOFKaon"}; + Configurable NSigmaTOFProton{"NSigmaTOFProton", 3, "NSigmaTOFProton"}; + + // PDG data base + Service pdgDB; + + void init(InitContext const&) + { + // Axes + AxisSpec XiMassAxis = {100, 1.28f, 1.36f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec OmegaMassAxis = {100, 1.63f, 1.7f, "#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})"}; + + // Histograms + // Event selection + rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); + + // Xi/Omega reconstruction + rXi.add("hMassXi", "hMassXi", {HistType::kTH1F, {XiMassAxis}}); + rXi.add("hMassXiSelected", "hMassXiSelected", {HistType::kTH1F, {XiMassAxis}}); + rXi.add("hMassXiSelectedWithTOF", "hMassXiSelectedWithTOF", {HistType::kTH1F, {XiMassAxis}}); + rXi.add("hMassXiTrueRec", "hMassXiTrueRec", {HistType::kTH1F, {XiMassAxis}}); + rXi.add("hPtXiTrueRec", "hPtXiTrueRec", {HistType::kTH1F, {ptAxis}}); + rXi.add("hMassXiTrueRecWithTOF", "hMassXiTrueRecWithTOF", {HistType::kTH1F, {XiMassAxis}}); + rXi.add("hPtXiTrueRecWithTOF", "hPtXiTrueRecWithTOF", {HistType::kTH1F, {ptAxis}}); + + rOmega.add("hMassOmega", "hMassOmega", {HistType::kTH1F, {OmegaMassAxis}}); + rOmega.add("hMassOmegaSelected", "hMassOmegaSelected", {HistType::kTH1F, {OmegaMassAxis}}); + rOmega.add("hMassOmegaSelectedWithTOF", "hMassOmegaSelectedWithTOF", {HistType::kTH1F, {OmegaMassAxis}}); + rOmega.add("hMassOmegaTrueRec", "hMassOmegaTrueRec", {HistType::kTH1F, {OmegaMassAxis}}); + rOmega.add("hPtOmegaTrueRec", "hPtOmegaTrueRec", {HistType::kTH1F, {ptAxis}}); + rOmega.add("hMassOmegaTrueRecWithTOF", "hMassOmegaTrueRecWithTOF", {HistType::kTH1F, {OmegaMassAxis}}); + rOmega.add("hPtOmegaTrueRecWithTOF", "hPtOmegaTrueRecWithTOF", {HistType::kTH1F, {ptAxis}}); + + // Xi/Omega topological cuts + rXi.add("hCascDCAV0Daughters", "hCascDCAV0Daughters", {HistType::kTH1F, {{55, 0.0f, 2.2f}}}); + rXi.add("hCascCosPA", "hCascCosPA", {HistType::kTH1F, {{100, 0.95f, 1.f}}}); + + rOmega.add("hCascDCAV0Daughters", "hCascDCAV0Daughters", {HistType::kTH1F, {{55, 0.0f, 2.2f}}}); + rOmega.add("hCascCosPA", "hCascCosPA", {HistType::kTH1F, {{100, 0.95f, 1.f}}}); + + // Generated level histograms + rEventSelection.add("hVertexZGen", "hVertexZGen", {HistType::kTH1F, {vertexZAxis}}); + rGenParticles.add("hPtXiGen", "hPtXiGen", {HistType::kTH1F, {{ptAxis}}}); + rGenParticles.add("hPtOmegaGen", "hPtOmegaGen", {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 Cascades + // Cannot filter on dynamic columns + Filter preFilterCascades = (aod::cascdata::dcaV0daughters < cascadesetting_dcav0dau && + nabs(aod::cascdata::dcapostopv) > cascadesetting_dcapostopv && + nabs(aod::cascdata::dcanegtopv) > cascadesetting_dcanegtopv && + nabs(aod::cascdata::dcabachtopv) > cascadesetting_dcabachtopv && + aod::cascdata::dcacascdaughters < cascadesetting_dcacascdau); + + // Defining the type of the daughter tracks + using dauTracks = soa::Join; + + void processRecMC(soa::Filtered>::iterator const& collision, + soa::Filtered> const& Cascades, + dauTracks const&, + aod::CascMCCores const& /*cascmccores*/) + { + // Fill the event counter + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + + // Cascades + for (const auto& casc : Cascades) { + const auto& bachDaughterTrackCasc = casc.bachTrackExtra_as(); + const auto& posDaughterTrackCasc = casc.posTrackExtra_as(); + const auto& negDaughterTrackCasc = casc.negTrackExtra_as(); + + rXi.fill(HIST("hMassXi"), casc.mXi()); + rOmega.fill(HIST("hMassOmega"), casc.mOmega()); + + // Cut on dynamic columns + if (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadesetting_cospa) + continue; + if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadesetting_v0cospa) + continue; + if (TMath::Abs(casc.mLambda() - pdgDB->Mass(3122)) > cascadesetting_v0masswindow) + continue; + if (casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()) < cascadesetting_mindcav0topv) + continue; + if (casc.cascradius() < cascadesetting_cascradius) + continue; + if (casc.v0radius() < cascadesetting_v0radius) + continue; + + // PID selection + if (casc.sign() < 0) { + if (TMath::Abs(posDaughterTrackCasc.tpcNSigmaPr()) > NSigmaTPCProton) { + continue; + } + if (TMath::Abs(negDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { + continue; + } + } else { + if (TMath::Abs(negDaughterTrackCasc.tpcNSigmaPr()) > NSigmaTPCProton) { + continue; + } + if (TMath::Abs(posDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { + continue; + } + } + + // TOF PID check + bool xiPassTOFSelection = true; + bool omegaPassTOFSelection = true; + if (casc.sign() < 0) { + if (posDaughterTrackCasc.hasTOF()) { + if (TMath::Abs(casc.tofNSigmaXiLaPr()) > NSigmaTOFProton) { + xiPassTOFSelection &= false; + } + if (TMath::Abs(casc.tofNSigmaOmLaPr()) > NSigmaTOFProton) { + omegaPassTOFSelection &= false; + } + } + if (negDaughterTrackCasc.hasTOF()) { + if (TMath::Abs(casc.tofNSigmaXiLaPi()) > NSigmaTOFPion) { + xiPassTOFSelection &= false; + } + if (TMath::Abs(casc.tofNSigmaOmLaPi()) > NSigmaTOFPion) { + omegaPassTOFSelection &= false; + } + } + } else { + if (posDaughterTrackCasc.hasTOF()) { + if (TMath::Abs(casc.tofNSigmaXiLaPi()) > NSigmaTOFPion) { + xiPassTOFSelection &= false; + } + if (TMath::Abs(casc.tofNSigmaOmLaPi()) > NSigmaTOFPion) { + omegaPassTOFSelection &= false; + } + } + if (negDaughterTrackCasc.hasTOF()) { + if (TMath::Abs(casc.tofNSigmaXiLaPr()) > NSigmaTOFProton) { + xiPassTOFSelection &= false; + } + if (TMath::Abs(casc.tofNSigmaOmLaPr()) > NSigmaTOFProton) { + omegaPassTOFSelection &= false; + } + } + } + + if (bachDaughterTrackCasc.hasTOF()) { + if (TMath::Abs(casc.tofNSigmaXiPi()) > NSigmaTOFPion) { + xiPassTOFSelection &= false; + } + if (TMath::Abs(casc.tofNSigmaOmKa()) > NSigmaTOFKaon) { + omegaPassTOFSelection &= false; + } + } + + if (bachDaughterTrackCasc.hasTOF()) { + if (TMath::Abs(casc.tofNSigmaXiPi()) > NSigmaTOFPion) { + xiPassTOFSelection &= false; + } + if (TMath::Abs(casc.tofNSigmaOmKa()) > NSigmaTOFKaon) { + omegaPassTOFSelection &= false; + } + } + + // Fill histograms! (if possible) + if (TMath::Abs(bachDaughterTrackCasc.tpcNSigmaPi()) < NSigmaTPCPion) { // Xi case + rXi.fill(HIST("hMassXiSelected"), casc.mXi()); + if (xiPassTOFSelection) { + rXi.fill(HIST("hMassXiSelectedWithTOF"), casc.mXi()); + } + + rXi.fill(HIST("hCascDCAV0Daughters"), casc.dcaV0daughters()); + rXi.fill(HIST("hCascCosPA"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + } + if (TMath::Abs(bachDaughterTrackCasc.tpcNSigmaKa()) < NSigmaTPCKaon) { // Omega case + if (TMath::Abs(casc.mXi() - pdgDB->Mass(3312)) > cascadesetting_competingmassrej) { // competing mass rejection, only in case of Omega + rOmega.fill(HIST("hMassOmegaSelected"), casc.mOmega()); + if (omegaPassTOFSelection) { + rOmega.fill(HIST("hMassOmegaSelectedWithTOF"), casc.mOmega()); + } + + rOmega.fill(HIST("hCascDCAV0Daughters"), casc.dcaV0daughters()); + rOmega.fill(HIST("hCascCosPA"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + } + } + + // MC truth info + if (!casc.has_cascMCCore()) { + continue; + } + auto cascmccore = casc.cascMCCore_as(); + + // Checking that the cascade is a true Xi + if (TMath::Abs(cascmccore.pdgCode()) == 3312) { + if (TMath::Abs(bachDaughterTrackCasc.tpcNSigmaPi()) < NSigmaTPCPion) { // Xi case + rXi.fill(HIST("hMassXiTrueRec"), casc.mXi()); + rXi.fill(HIST("hPtXiTrueRec"), casc.pt()); + if (xiPassTOFSelection) { + rXi.fill(HIST("hMassXiTrueRecWithTOF"), casc.mXi()); + rXi.fill(HIST("hPtXiTrueRecWithTOF"), casc.pt()); + } + } + } + if (TMath::Abs(cascmccore.pdgCode()) == 3334) { + if (TMath::Abs(bachDaughterTrackCasc.tpcNSigmaKa()) < NSigmaTPCKaon) { // Omega case + if (TMath::Abs(casc.mXi() - pdgDB->Mass(3312)) > cascadesetting_competingmassrej) { // competing mass rejection, only in case of Omega + rOmega.fill(HIST("hMassOmegaTrueRec"), casc.mOmega()); + rOmega.fill(HIST("hPtOmegaTrueRec"), casc.pt()); + if (omegaPassTOFSelection) { + rOmega.fill(HIST("hMassOmegaTrueRecWithTOF"), casc.mOmega()); + rOmega.fill(HIST("hPtOmegaTrueRecWithTOF"), casc.pt()); + } + } + } + } + } + } + + void processGenMC(soa::Filtered::iterator const& mcCollision, + const soa::SmallGroups>& collisions, + const soa::SmallGroups>& cascMC) + { + 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& cascmc : cascMC) { + if (TMath::Abs(cascmc.pdgCode()) == 3312) { + rGenParticles.fill(HIST("hPtXiGen"), cascmc.ptMC()); + } + if (TMath::Abs(cascmc.pdgCode()) == 3334) { + rGenParticles.fill(HIST("hPtOmegaGen"), cascmc.ptMC()); + } + } + } + + PROCESS_SWITCH(strangeness_pbpb_tutorial, processRecMC, "Process Run 3 mc, reconstructed", true); + PROCESS_SWITCH(strangeness_pbpb_tutorial, processGenMC, "Process Run 3 mc, generated", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Tutorials/PWGLF/Strangeness/PbPb/CMakeLists.txt b/Tutorials/PWGLF/Strangeness/PbPb/CMakeLists.txt new file mode 100644 index 00000000000..f593f821726 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/PbPb/CMakeLists.txt @@ -0,0 +1,13 @@ +# 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. + +add_subdirectory(Analysis) +# add_subdirectory(DerivedDataProduction) \ No newline at end of file diff --git a/Tutorials/PWGLF/Strangeness/PbPb/DerivedDataProduction/Data/run.sh b/Tutorials/PWGLF/Strangeness/PbPb/DerivedDataProduction/Data/run.sh new file mode 100644 index 00000000000..632f8375470 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/PbPb/DerivedDataProduction/Data/run.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="deriveddata" +LOGFILE="log-${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration.json" + +o2-analysis-pid-tof-base "${OPTION}" | + o2-analysis-event-selection "${OPTION}" | + o2-analysis-lf-lambdakzerobuilder "${OPTION}" | + o2-analysis-lf-cascadebuilder "${OPTION}" | + o2-analysis-multiplicity-table "${OPTION}" | + o2-analysis-centrality-table "${OPTION}" | + o2-analysis-lf-epvector "${OPTION}" | + o2-analysis-centrality-qa "${OPTION}" | + o2-analysis-ud-sgcand-producer "${OPTION}" | + o2-analysis-timestamp "${OPTION}" | + o2-analysis-ft0-corrected-table "${OPTION}" | + o2-analysis-track-propagation "${OPTION}" | + o2-analysis-pid-tpc-base "${OPTION}" | + o2-analysis-pid-tpc "${OPTION}" | + o2-analysis-trackselection "${OPTION}" | + o2-analysis-pid-tof-full "${OPTION}" | + o2-analysis-pid-tof-beta "${OPTION}" | + o2-analysis-lf-strangederivedbuilder "${OPTION}" --aod-file @input_data.txt --aod-writer-json OutputDirector.json >"$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 AO2D.root "${DIR_THIS}/results/${STEP}/AO2D.root" + mv dpl-config.json "${DIR_THIS}/results/${STEP}/${STEP}.json" +else + echo "Error: Exit code ${rc}" + echo "Check the log file ${LOGFILE}" + exit ${rc} +fi diff --git a/Tutorials/PWGLF/Strangeness/PbPb/DerivedDataProduction/MC/runMC.sh b/Tutorials/PWGLF/Strangeness/PbPb/DerivedDataProduction/MC/runMC.sh new file mode 100644 index 00000000000..e9e086e4f4e --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/PbPb/DerivedDataProduction/MC/runMC.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="deriveddata" +LOGFILE="log-${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configurationMC.json" + +o2-analysis-pid-tof-base "${OPTION}" | + o2-analysis-mccollisionextra "${OPTION}" | + o2-analysis-lf-lambdakzerobuilder "${OPTION}" | + o2-analysis-lf-cascadebuilder "${OPTION}" | + o2-analysis-lf-cascademcbuilder "${OPTION}" | + o2-analysis-centrality-table "${OPTION}" | + o2-analysis-lf-lambdakzeromcbuilder "${OPTION}" | + o2-analysis-mccollision-converter "${OPTION}" | + o2-analysis-ud-sgcand-producer "${OPTION}" | + o2-analysis-timestamp "${OPTION}" | + o2-analysis-ft0-corrected-table "${OPTION}" | + o2-analysis-track-propagation "${OPTION}" | + o2-analysis-pid-tpc-base "${OPTION}" | + o2-analysis-pid-tpc "${OPTION}" | + o2-analysis-multiplicity-table "${OPTION}" | + o2-analysis-trackselection "${OPTION}" | + o2-analysis-pid-tof-full "${OPTION}" | + o2-analysis-pid-tof-beta "${OPTION}" | + o2-analysis-event-selection "${OPTION}" | + o2-analysis-lf-strangederivedbuilder "${OPTION}" --aod-file @input_dataMC.txt --aod-writer-json OutputDirectorMC.json >"$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 AO2D.root "${DIR_THIS}/results/${STEP}/AO2D.root" + mv dpl-config.json "${DIR_THIS}/results/${STEP}/${STEP}.json" +else + echo "Error: Exit code ${rc}" + echo "Check the log file ${LOGFILE}" + exit ${rc} +fi diff --git a/Tutorials/PWGLF/Strangeness/README.md b/Tutorials/PWGLF/Strangeness/README.md index ee28059d0f8..1976051fe3b 100644 --- a/Tutorials/PWGLF/Strangeness/README.md +++ b/Tutorials/PWGLF/Strangeness/README.md @@ -1,13 +1,29 @@ # This is the base for the PWGLF tutorials for the O2AT -The tutorial (17-28 Apr 2023) can be still used and is a reference for the LF analyses. +The tutorial (14-18 Oct 2024) can be used as a reference for the LF analysis. It is built as a set of steps. Each step adds a level of complexity and is built in a separate executable. -The executables are defined in the `CMakeLists.txt`. -## Files -* `README.md` this readme +The tutorial is divided into two directories depending on the collision system: +## pp +This repository contains the codes to analyse V0 and cascade particles in proton-proton collisions: * `CMakeLists.txt` here are defined the source files to compile * `strangeness_step0.cxx` Starting point: loop over all V0s and fill invariant mass histogram * `strangeness_step1.cxx` Apply selections on topological variables of V0s * `strangeness_step2.cxx` Apply PID selections on V0 daughter tracks * `strangeness_step3.cxx` Check the MC information of the V0s and verify with the PID information of daughter tracks + +The introduction and hands-on sessions can be found here: https://indico.cern.ch/event/1326201/ + +## PbPb +This repository contains the code to analyse cascade particles in Pb-Pb collisions. +The tutorial revolves around two aspects: +i) the derived data production in the directory DerivedDataProduction, +ii) the analysis of the derived data in the directory Analysis, containing: +* `CMakeLists.txt` here are defined the source files to compile +* `strangeness_pbpb_step0.cxx` Starting point: loop over all cascades and fill invariant mass histogram +* `strangeness_pbpb_step1.cxx` Apply selections on topological variables of cascades +* `strangeness_pbpb_step2.cxx` Apply TPC PID selections on cascade daughter tracks +* `strangeness_pbpb_step3.cxx` Apply TOF PID selections on cascade daughter tracks (if available) +* `strangeness_pbpb_step4.cxx` Check the MC information of the cascade + +The introduction and hands-on sessions can be found here: https://indico.cern.ch/event/1425820/ \ No newline at end of file diff --git a/Tutorials/PWGLF/Strangeness/pp/CMakeLists.txt b/Tutorials/PWGLF/Strangeness/pp/CMakeLists.txt new file mode 100644 index 00000000000..f46ac1f9e0b --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/pp/CMakeLists.txt @@ -0,0 +1,36 @@ +# 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. + +# Strangeness analysis tutorial +o2physics_add_dpl_workflow(strangeness-step0 + SOURCES strangeness_step0.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-step1 + SOURCES strangeness_step1.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-step2 + SOURCES strangeness_step2.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-step3 + SOURCES strangeness_step3.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-step4 + SOURCES strangeness_step4.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) \ No newline at end of file diff --git a/Tutorials/PWGLF/Strangeness/strangeness_step0.cxx b/Tutorials/PWGLF/Strangeness/pp/strangeness_step0.cxx similarity index 100% rename from Tutorials/PWGLF/Strangeness/strangeness_step0.cxx rename to Tutorials/PWGLF/Strangeness/pp/strangeness_step0.cxx diff --git a/Tutorials/PWGLF/Strangeness/strangeness_step1.cxx b/Tutorials/PWGLF/Strangeness/pp/strangeness_step1.cxx similarity index 100% rename from Tutorials/PWGLF/Strangeness/strangeness_step1.cxx rename to Tutorials/PWGLF/Strangeness/pp/strangeness_step1.cxx diff --git a/Tutorials/PWGLF/Strangeness/strangeness_step2.cxx b/Tutorials/PWGLF/Strangeness/pp/strangeness_step2.cxx similarity index 100% rename from Tutorials/PWGLF/Strangeness/strangeness_step2.cxx rename to Tutorials/PWGLF/Strangeness/pp/strangeness_step2.cxx diff --git a/Tutorials/PWGLF/Strangeness/strangeness_step3.cxx b/Tutorials/PWGLF/Strangeness/pp/strangeness_step3.cxx similarity index 100% rename from Tutorials/PWGLF/Strangeness/strangeness_step3.cxx rename to Tutorials/PWGLF/Strangeness/pp/strangeness_step3.cxx diff --git a/Tutorials/PWGLF/Strangeness/strangeness_step4.cxx b/Tutorials/PWGLF/Strangeness/pp/strangeness_step4.cxx similarity index 100% rename from Tutorials/PWGLF/Strangeness/strangeness_step4.cxx rename to Tutorials/PWGLF/Strangeness/pp/strangeness_step4.cxx diff --git a/Tutorials/PWGUD/CMakeLists.txt b/Tutorials/PWGUD/CMakeLists.txt index da52aa07b26..1be9c2f6815 100644 --- a/Tutorials/PWGUD/CMakeLists.txt +++ b/Tutorials/PWGUD/CMakeLists.txt @@ -39,3 +39,17 @@ o2physics_add_dpl_workflow(udtutorial-04 PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(udtutorial-05 + SOURCES UDTutorial_05.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(udtutorial-06 + SOURCES UDTutorial_06.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(udtutorial-07 + SOURCES UDTutorial_07.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/Tutorials/PWGUD/UDTutorial_05.cxx b/Tutorials/PWGUD/UDTutorial_05.cxx new file mode 100644 index 00000000000..3a9bfb79605 --- /dev/null +++ b/Tutorials/PWGUD/UDTutorial_05.cxx @@ -0,0 +1,318 @@ +// 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. +// + +#include "iostream" +#include "TLorentzVector.h" +#include "TDatabasePDG.h" + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" + +// using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// \brief Example task to study two pions candidates using SG derive data +/// \author Anisa Khatun +/// \date 10.10.2024 + +// Struct to define the analysis task +struct UDTutorial05 { + // SGSelector object to manage track and collision selections + SGSelector sgSelector; + + Configurable FV0_cut{"FV0", 100., "FV0A threshold"}; + Configurable FT0A_cut{"FT0A", 100., "FT0A threshold"}; + Configurable FT0C_cut{"FT0C", 50., "FT0C threshold"}; + Configurable FDDA_cut{"FDDA", 10000., "FDDA threshold"}; + Configurable FDDC_cut{"FDDC", 10000., "FDDC threshold"}; + Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; + Configurable gap_Side{"gap", 2, "gap selection"}; + + // Track Selections + Configurable PV_cut{"PV_cut", 1.0, "Use Only PV tracks"}; + Configurable dcaZ_cut{"dcaZ_cut", 2.0, "dcaZ cut"}; + Configurable dcaXY_cut{"dcaXY_cut", 0.0, "dcaXY cut (0 for Pt-function)"}; + Configurable tpcChi2_cut{"tpcChi2_cut", 4, "Max tpcChi2NCl"}; + Configurable tpcNClsFindable_cut{"tpcNClsFindable_cut", 70, "Min tpcNClsFindable"}; + Configurable itsChi2_cut{"itsChi2_cut", 36, "Max itsChi2NCl"}; + Configurable eta_cut{"eta_cut", 0.9, "Track Pseudorapidity"}; + Configurable pt_cut{"pt_cut", 0.01, "Track Pt"}; + Configurable TPC_cluster{"TPC_cluster", 50, "No.of TPC cluster"}; + + // Kinmatic cuts + Configurable PID_cut{"PID_cut", 5, "TPC PID"}; + Configurable Rap_cut{"Rap_cut", 0.9, "Track rapidity"}; + Configurable Mass_Max{"Mass_Max", 10, "Invariant Mass range high"}; + Configurable Mass_Min{"Mass_Min", 0, "Invariant Mass range low"}; + Configurable Pt_coherent{"Pt_coherent", 0.15, "Coherent selection"}; + + // defining histograms using histogram registry + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //----------------------------------------------------------------------------------------------------------------------- + void init(o2::framework::InitContext&) + { + + registry.add("GapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + registry.add("TrueGapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + + // Fill counter to see effect of each selection criteria + auto hSelectionCounter = registry.add("hSelectionCounter", "hSelectionCounter;;NEvents", HistType::kTH1I, {{20, 0., 20.}}); + + TString SelectionCuts[16] = {"NoSelection", "gapside", "goodtracks", "truegap", "2collcontrib", "2goodtrk", "TPCPID", "Rap_cut", "unlikesign", "mass_cut", "coherent", "incoherent", "likesign", "mass_cut", "coherent", "incoherent"}; + + for (int i = 0; i < 16; i++) { + hSelectionCounter->GetXaxis()->SetBinLabel(i + 1, SelectionCuts[i].Data()); + } + // tracks + registry.add("hTracks", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hTracksPions", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("TwoPion/h2TracksPions", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + + registry.add("hdEdx", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {100, 0.0, 200.0}}); + registry.add("hdEdxPion", "p_{#pi} vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {100, 0.0, 200.0}}); + + registry.add("TwoPion/hNsigPi1vsPi2", "NSigmaPi(t1) vs NSigmapi (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); + registry.add("TwoPion/hNsigEl1vsEl2", "NSigmaEl(t1) vs NSigmaEl (t2);n#sigma_{1};n#sigma_{2}", kTH2F, {{100, -15., 15.}, {100, -15., 15}}); + registry.add("TwoPion/hNsigPivsPt1", "Pt vs NSigmaPi (t1);#it{p_{t}}, GeV/c;n#sigma_{#pi}", kTH2F, {{100, 0., 2.5}, {100, -15., 15}}); + registry.add("TwoPion/hNsigPivsPt2", "Pt vs NSigmaPi (t2);#it{p_{t}}, GeV/c;n#sigma_{#pi}", kTH2F, {{100, 0., 2.5}, {100, -15., 15}}); + registry.add("TwoPion/hNsigElvsPt1", "Pt vs NSigmaEl (t1);#it{p_{t}}, GeV/c;n#sigma_{#e}", kTH2F, {{100, 0., 2.5}, {100, -15., 15}}); + registry.add("TwoPion/hNsigElvsPt2", "Pt vs NSigmaEl (t2);#it{p_{t}}, GeV/c;n#sigma_{#e}", kTH2F, {{100, 0., 2.5}, {100, -15., 15}}); + registry.add("TwoPion/hNsigMuvsPt1", "Pt vs NSigmaMu (t1);#it{p_{t}}, GeV/c;n#sigma_{#pi}", kTH2F, {{100, 0., 2.5}, {100, -15., 15}}); + registry.add("TwoPion/hNsigMuvsPt2", "Pt vs NSigmaMu (t2);#it{p_{t}}, GeV/c;n#sigma_{#pi}", kTH2F, {{100, 0., 2.5}, {100, -15., 15}}); + + registry.add("TwoPion/hPtsingle_track1", "Pt t1;#it{p_{t}}, GeV/c;", kTH1F, {{600, 0., 3.}}); + registry.add("TwoPion/hPtsingle_track2", "Pt t2;#it{p_{t}}, GeV/c;", kTH1F, {{600, 0., 3.}}); + registry.add("TwoPion/hEta_t1", "Eta of t1;#it{#eta};", kTH1F, {{100, -5., 5.}}); + registry.add("TwoPion/hEta_t2", "Eta of t2;#it{#eta};", kTH1F, {{100, -5., 5.}}); + registry.add("TwoPion/hP1", "P vs TPC signal;#it{P_{track}}, GeV/c; signal_{TPC} t1", kTH2F, {{100, 0., 2.}, {300, 0, 150}}); + registry.add("TwoPion/hTPCsig", "TPC signal;signal_{TPC} t2; signal_{TPC} t2", kTH2F, {{300, 0., 150.}, {300, 0, 150}}); + registry.add("TwoPion/hP2", "P vs TPC signal;#it{P_{track}}, GeV/c; signal_{TPC} t1", kTH2F, {{100, 0., 2.}, {300, 0, 150}}); + registry.add("TwoPion/hTPCsig1", "TPC signal;signal_{TPC} t2; signal_{TPC} t2", kTH2F, {{300, 0., 150.}, {300, 0, 150}}); + + registry.add("TwoPion/hMassLike", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{20000, 0., 20.}}); + registry.add("TwoPion/hMassUnlike", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{20000, 0., 20.}}); + registry.add("TwoPion/Coherent/hMassUnlikeCoherent", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{20000, 0., 20.}}); + registry.add("TwoPion/Coherent/hMassLikeCoherent", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{20000, 0., 20.}}); + registry.add("TwoPion/Incoherent/hMassUnlikeInCoherent", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{20000, 0., 20.}}); + registry.add("TwoPion/Incoherent/hMassLikeInCoherent", "m_{#pi#pi} [GeV/#it{c}^{2}]", kTH1F, {{20000, 0., 20.}}); + + registry.add("TwoPion/hPt", "Pt;#it{p_{t}}, GeV/c;", kTH1D, {{1000, 0., 10.}}); + registry.add("TwoPion/hPtLike", "Pt;#it{p_{t}}, GeV/c;", kTH1D, {{1000, 0., 10.}}); + registry.add("TwoPion/hEta", "Eta;#it{#eta};", kTH1F, {{500, -10., 10.}}); + registry.add("TwoPion/hRap", "Rapidity;#it{y};", kTH1F, {{500, -10., 10.}}); + registry.add("TwoPion/hPhiSystem", "Phi;#it{#Phi};", kTH1F, {{250, 0. * TMath::Pi(), 2. * TMath::Pi()}}); + registry.add("TwoPion/hMPt", "Inv.M vs Pt;M, GeV/c^{2};#it{P_{t}}, GeV/c;", kTH2F, {{100, 0., 10.}, {100, 0., 10.}}); + } + + using udtracks = soa::Join; + using udtracksfull = soa::Join; + + using UDCollisionsFull = soa::Join; + + //__________________________________________________________________________ + // Main process + void process(UDCollisionsFull::iterator const& collision, udtracksfull const& tracks) + { + // No selection criteria + registry.fill(HIST("hSelectionCounter"), 0); + + // Accessing gap sides + int gapSide = collision.gapSide(); + if (gapSide < 0 || gapSide > 2) + return; + + registry.fill(HIST("hSelectionCounter"), 1); + + // Accessing FIT information for further exclusivity and/or inclusivity + float FIT_cut[5] = {FV0_cut, FT0A_cut, FT0C_cut, FDDA_cut, FDDC_cut}; + int truegapSide = sgSelector.trueGap(collision, FIT_cut[0], FIT_cut[1], FIT_cut[2], ZDC_cut); + + // Intiating track parameters to select good tracks, values to be optimized in the configurables, parameters will be taken from SGtrackselector.h task included in the header + std::vector parameters = {PV_cut, dcaZ_cut, dcaXY_cut, tpcChi2_cut, tpcNClsFindable_cut, itsChi2_cut, eta_cut, pt_cut}; + + registry.fill(HIST("GapSide"), gapSide); + registry.fill(HIST("TrueGapSide"), truegapSide); + + // Gap side to be selected in the configuables + gapSide = truegapSide; + + if (gapSide == gap_Side) { + + registry.fill(HIST("hSelectionCounter"), 2); + + //____________________________________________________________________________________ + + // Create LorentzVector to store all tracks, Pion tracks and TPC Pion PID + std::vector allTracks; + std::vector onlyPionTracks; + std::vector onlyPionSigma; + std::vector rawPionTracks; + TLorentzVector p; + + registry.fill(HIST("hTracks"), tracks.size()); + + for (auto t : tracks) { + // Apply good track selection criteria + if (!trackselector(t, parameters)) + continue; + + double dEdx = t.tpcSignal(); + + registry.fill(HIST("hdEdx"), t.tpcInnerParam() / t.sign(), dEdx); + + // Creating Lorenz vector to store raw tracks and piontracks + TLorentzVector a; + a.SetXYZM(t.px(), t.py(), t.pz(), o2::constants::physics::MassPionCharged); + allTracks.push_back(a); + + // Apply TPC pion sigma + auto nSigmaPi = t.tpcNSigmaPi(); + if (fabs(nSigmaPi) < PID_cut) { + onlyPionTracks.push_back(a); + onlyPionSigma.push_back(nSigmaPi); + rawPionTracks.push_back(t); + registry.fill(HIST("hdEdxPion"), t.tpcInnerParam() / t.sign(), dEdx); + } + } + + registry.fill(HIST("hTracksPions"), onlyPionTracks.size()); + //_____________________________________ + // Adding all onlypiontracks + for (auto pion : onlyPionTracks) { + p += pion; + } + + //_____________________________________ + // Selecting collisions with Two PV contributors + if (collision.numContrib() == 2) { + + registry.fill(HIST("hSelectionCounter"), 3); + + // Selecting only Two good tracks + if ((rawPionTracks.size() == 2) && (onlyPionTracks.size() == 2)) { + + registry.fill(HIST("hSelectionCounter"), 4); + + registry.fill(HIST("TwoPion/h2TracksPions"), onlyPionTracks.size()); + + registry.fill(HIST("TwoPion/hNsigPivsPt1"), onlyPionTracks[0].Pt(), rawPionTracks[0].tpcNSigmaPi()); + registry.fill(HIST("TwoPion/hNsigPivsPt2"), onlyPionTracks[1].Pt(), rawPionTracks[1].tpcNSigmaPi()); + registry.fill(HIST("TwoPion/hTPCsig"), rawPionTracks[0].tpcSignal(), rawPionTracks[1].tpcSignal()); + registry.fill(HIST("TwoPion/hNsigPi1vsPi2"), rawPionTracks[0].tpcNSigmaPi(), rawPionTracks[1].tpcNSigmaPi()); + + // Make sure two good tracks are with TPC pion sigma limit + if ((onlyPionSigma[0] * onlyPionSigma[0] + onlyPionSigma[1] * onlyPionSigma[1]) > (PID_cut * PID_cut)) { + return; + } + + registry.fill(HIST("hSelectionCounter"), 5); + + // Rapidity of midrapidity acceptance + if ((p.Rapidity() < -Rap_cut) || (p.Rapidity() > Rap_cut)) { + return; + } + + registry.fill(HIST("hSelectionCounter"), 6); + + // Two oppsotite sign tracks + if (rawPionTracks[0].sign() != rawPionTracks[1].sign()) { + + registry.fill(HIST("hSelectionCounter"), 7); + registry.fill(HIST("TwoPion/hMassUnlike"), p.M()); + + // Flexible mass limits, can be selected in the configurable + if ((p.M() > Mass_Min) && (p.M() < Mass_Max)) { + + registry.fill(HIST("hSelectionCounter"), 8); + + registry.fill(HIST("TwoPion/hPt"), p.Pt()); + registry.fill(HIST("TwoPion/hEta"), p.Eta()); + registry.fill(HIST("TwoPion/hRap"), p.Rapidity()); + registry.fill(HIST("TwoPion/hPhiSystem"), p.Phi()); + registry.fill(HIST("TwoPion/hMPt"), p.M(), p.Pt()); + + // flexible pt limit for selecting coherent Rho(0) + if (p.Pt() < Pt_coherent) { + + registry.fill(HIST("hSelectionCounter"), 9); + + // Quality Control plots after coherent Rho(0) selection + registry.fill(HIST("TwoPion/hEta_t1"), onlyPionTracks[0].Eta()); + registry.fill(HIST("TwoPion/hEta_t2"), onlyPionTracks[1].Eta()); + registry.fill(HIST("TwoPion/hPtsingle_track1"), onlyPionTracks[0].Pt()); + registry.fill(HIST("TwoPion/hPtsingle_track2"), onlyPionTracks[1].Pt()); + + registry.fill(HIST("TwoPion/hNsigMuvsPt1"), onlyPionTracks[0].Pt(), rawPionTracks[0].tpcNSigmaPi()); + registry.fill(HIST("TwoPion/hNsigMuvsPt2"), onlyPionTracks[1].Pt(), rawPionTracks[1].tpcNSigmaPi()); + registry.fill(HIST("TwoPion/hNsigElvsPt1"), onlyPionTracks[0].Pt(), rawPionTracks[0].tpcNSigmaEl()); + registry.fill(HIST("TwoPion/hNsigElvsPt2"), onlyPionTracks[1].Pt(), rawPionTracks[1].tpcNSigmaEl()); + registry.fill(HIST("TwoPion/hNsigEl1vsEl2"), rawPionTracks[0].tpcNSigmaPi(), rawPionTracks[1].tpcNSigmaPi()); + + registry.fill(HIST("TwoPion/hP1"), onlyPionTracks[0].P(), rawPionTracks[0].tpcSignal()); + registry.fill(HIST("TwoPion/hP2"), onlyPionTracks[1].P(), rawPionTracks[1].tpcSignal()); + registry.fill(HIST("TwoPion/hTPCsig1"), rawPionTracks[0].tpcSignal(), rawPionTracks[1].tpcSignal()); + + registry.fill(HIST("TwoPion/Coherent/hMassUnlikeCoherent"), p.M()); + } + // Incoherent Rho(0) selection + if (p.Pt() > Pt_coherent) { + registry.fill(HIST("hSelectionCounter"), 10); + registry.fill(HIST("TwoPion/Incoherent/hMassUnlikeInCoherent"), p.M()); + } + } + } + + // Same charge particles + if (rawPionTracks[0].sign() == rawPionTracks[1].sign()) { + + registry.fill(HIST("hSelectionCounter"), 11); + registry.fill(HIST("TwoPion/hMassLike"), p.M()); + + // Mass limit + if ((p.M() > Mass_Min) && (p.M() < Mass_Max)) { + + registry.fill(HIST("hSelectionCounter"), 12); + registry.fill(HIST("TwoPion/hPtLike"), p.Pt()); + + // Coherent Rho(0) selection + if (p.Pt() < Pt_coherent) { + + registry.fill(HIST("hSelectionCounter"), 13); + registry.fill(HIST("TwoPion/Coherent/hMassLikeCoherent"), p.M()); + } + // Incoherent Rho(0) selection + if (p.Pt() > Pt_coherent) { + + registry.fill(HIST("hSelectionCounter"), 14); + registry.fill(HIST("TwoPion/Incoherent/hMassLikeInCoherent"), p.M()); + } + } + } + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"udtutorial05"})}; +} diff --git a/Tutorials/PWGUD/UDTutorial_06.cxx b/Tutorials/PWGUD/UDTutorial_06.cxx new file mode 100644 index 00000000000..9b1d1f55895 --- /dev/null +++ b/Tutorials/PWGUD/UDTutorial_06.cxx @@ -0,0 +1,232 @@ +// 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 This task is to compute invariant mass of dimuon at forward rapidity for UPC events. +/// \author Anisa Khatun +/// \date 10.10.2024 + +// O2 headers +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" + +// O2Physics headers +#include "PWGUD/DataModel/UDTables.h" +#include "PWGUD/Core/UDHelpers.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsParameters/GRPECSObject.h" + +// ROOT headers +#include "TSystem.h" +#include "TDatabasePDG.h" +#include "TLorentzVector.h" +#include "TLorentzVector.h" +#include "TMath.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace std; + +struct UDTutorial06 { + + // Histogram registry: an object to hold your histograms + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + Configurable nBinsPt{"nBinsPt", 500, "N bins in pT histo"}; + Configurable nBinsMass{"nBinsMass", 500, "N bins in InvMass histo"}; + + using UDCollisionsFwd = soa::Join; + using fwdtraks = soa::Join; + + void init(InitContext const&) + { + // define axes you want to use + const AxisSpec axisCounter{1, 0, +1, ""}; + const AxisSpec axisEta{80, -5.0, -2.0, "#eta"}; + const AxisSpec axisPt{nBinsPt, 0.0, 10.0, "p_{T}"}; + const AxisSpec axisM{nBinsMass, 0.0, 10.0, "M_{#pi#pi}"}; + const AxisSpec axisPhi{120, -TMath::Pi(), -TMath::Pi(), "#phi"}; + const AxisSpec axisRapidity{80, -5.0, -2.0, "#it{y}"}; + + // create histograms + // Fill counter to see effect of each selection criteria + auto hSelectionCounter = registry.add("hSelectionCounter", "hSelectionCounter;;NEvents", HistType::kTH1I, {{15, 0., 15.}}); + TString SelectionCuts[13] = {"NoSelection", "V0A", "rAbs1", "rAbs2", "trackmatch", "eta1", "eta2", "trackpt", "pair rapidity", "mass_cut", "unlikesign", "likesign"}; + + for (int i = 0; i < 12; i++) { + hSelectionCounter->GetXaxis()->SetBinLabel(i + 1, SelectionCuts[i].Data()); + } + + registry.add("eventCounter", "eventCounter", kTH1F, {axisCounter}); + registry.add("hnumContrib", "hnumContrib;;#counts", kTH1D, {{100, -0.5, 99.5}}); + registry.add("hTracks1", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hTracks2", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hTracksMuons", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + + registry.add("etaMuon1", "etaMuon1", kTH1F, {axisEta}); + registry.add("ptMuon1", "ptMuon1", kTH1F, {axisPt}); + registry.add("phiMuon1", "phiMuon1", kTH1F, {axisPhi}); + + registry.add("etaMuon2", "etaMuon2", kTH1F, {axisEta}); + registry.add("ptMuon2", "ptMuon2", kTH1F, {axisPt}); + registry.add("phiMuon2", "phiMuon2", kTH1F, {axisPhi}); + + registry.add("YJpsi", "YJpsi", kTH1F, {axisRapidity}); + registry.add("PhiJpsi", "PhiJpsi", kTH1F, {axisPhi}); + + registry.add("MJpsiUnlike", "MJpsi", kTH1F, {axisM}); + registry.add("PtJpsiUnlike", "PtJpsi", kTH1F, {axisPt}); + registry.add("MJpsiLike", "MJpsi", kTH1F, {axisM}); + registry.add("PtJpsiLike", "PtJpsi", kTH1F, {axisPt}); + } + + //____________________________________________________________________________________________ + + template + void processCandidate(UDCollisionsFwd::iterator const& collision, TTrack1& tr1, TTrack2& tr2) + { + registry.fill(HIST("eventCounter"), 0.5); + registry.fill(HIST("hnumContrib"), collision.numContrib()); + registry.fill(HIST("hTracks1"), tr1.size()); + registry.fill(HIST("hTracks2"), tr2.size()); + registry.fill(HIST("hSelectionCounter"), 0); + + // V0A selection + const auto& ampsV0A = collision.amplitudesV0A(); + const auto& ampsRelBCsV0A = collision.ampRelBCsV0A(); + for (unsigned int i = 0; i < ampsV0A.size(); ++i) { + if (std::abs(ampsRelBCsV0A[i]) <= 1) { + if (ampsV0A[i] > 100.) + return; + } + } + + // T0A selection + const auto& ampsT0A = collision.amplitudesT0A(); + const auto& ampsRelBCsT0A = collision.ampRelBCsT0A(); + for (unsigned int i = 0; i < ampsT0A.size(); ++i) { + if (std::abs(ampsRelBCsT0A[i]) <= 1) { + if (ampsT0A[i] > 100.) + return; + } + } + + registry.fill(HIST("hSelectionCounter"), 1); + + // absorber end selection + if (tr1.rAtAbsorberEnd() < 17.6 || tr1.rAtAbsorberEnd() > 89.5) + return; + registry.fill(HIST("hSelectionCounter"), 2); + if (tr2.rAtAbsorberEnd() < 17.6 || tr2.rAtAbsorberEnd() > 89.5) + return; + registry.fill(HIST("hSelectionCounter"), 3); + + // MCH-MID match selection + if ((tr1.chi2MatchMCHMID() < 0) || (tr2.chi2MatchMCHMID() < 0)) + return; + registry.fill(HIST("hSelectionCounter"), 4); + + bool isUnlikeSign = (tr1.sign() + tr2.sign()) == 0; + bool isLikeSign = ((tr1.sign() + tr2.sign()) != 0); + + // track selection + TLorentzVector p1, p2; + p1.SetXYZM(tr1.px(), tr1.py(), tr1.pz(), o2::constants::physics::MassMuon); + p2.SetXYZM(tr2.px(), tr2.py(), tr2.pz(), o2::constants::physics::MassMuon); + TLorentzVector p = p1 + p2; + + // eta cut on each track + if (p1.Eta() < -4.0 || p1.Eta() > -2.5) + return; + registry.fill(HIST("hSelectionCounter"), 5); + if (p2.Eta() < -4.0 || p2.Eta() > -2.5) + return; + registry.fill(HIST("hSelectionCounter"), 6); + + // pt cut on track + if ((p1.Pt() < 0.0) || (p2.Pt() < 0.0)) + return; + registry.fill(HIST("hSelectionCounter"), 7); + + if ((p.Rapidity() < -4.0) || (p.Rapidity() > -2.5)) + return; + registry.fill(HIST("hSelectionCounter"), 8); + + // cuts on pair kinematics + if (!(p.M() > 2.5 && p.M() < 5.0)) + return; + registry.fill(HIST("hSelectionCounter"), 9); + + registry.fill(HIST("hTracksMuons"), collision.numContrib()); + registry.fill(HIST("ptMuon1"), p1.Pt()); + registry.fill(HIST("ptMuon2"), p2.Pt()); + registry.fill(HIST("etaMuon1"), p1.Eta()); + registry.fill(HIST("etaMuon2"), p2.Eta()); + registry.fill(HIST("phiMuon1"), p1.Phi()); + registry.fill(HIST("phiMuon2"), p2.Phi()); + registry.fill(HIST("YJpsi"), p.Rapidity()); + registry.fill(HIST("PhiJpsi"), p.Phi()); + + if (isUnlikeSign) { + registry.fill(HIST("hSelectionCounter"), 10); + registry.fill(HIST("MJpsiUnlike"), p.M()); + registry.fill(HIST("PtJpsiUnlike"), p.Pt()); + } + + if (isLikeSign) { + registry.fill(HIST("hSelectionCounter"), 11); + registry.fill(HIST("MJpsiLike"), p.M()); + registry.fill(HIST("PtJpsiLike"), p.Pt()); + } + } + + //____________________________________________________________________________________________ + + // Template that collects all collision IDs and track per collision + template + void collectCandIDs(std::unordered_map>& tracksPerCand, TTracks& tracks) + { + for (const auto& tr : tracks) { + int32_t candId = tr.udCollisionId(); + if (candId < 0) { + continue; + } + tracksPerCand[candId].push_back(tr.globalIndex()); + } + } + + //____________________________________________________________________________________________ + + // process candidates with 2 forward tracks + void process(UDCollisionsFwd const& eventCandidates, + fwdtraks const& fwdTracks) + { + std::unordered_map> tracksPerCand; + collectCandIDs(tracksPerCand, fwdTracks); + + // assuming that candidates have exatly 2 forward tracks + for (const auto& item : tracksPerCand) { + int32_t trId1 = item.second[0]; + int32_t trId2 = item.second[1]; + int32_t candID = item.first; + const auto& collision = eventCandidates.iteratorAt(candID); + const auto& tr1 = fwdTracks.iteratorAt(trId1); + const auto& tr2 = fwdTracks.iteratorAt(trId2); + processCandidate(collision, tr1, tr2); + } + } +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"udtutorial06"})}; +} diff --git a/Tutorials/PWGUD/UDTutorial_07.cxx b/Tutorials/PWGUD/UDTutorial_07.cxx new file mode 100644 index 00000000000..f2a5616f00d --- /dev/null +++ b/Tutorials/PWGUD/UDTutorial_07.cxx @@ -0,0 +1,230 @@ +// 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. +// +#include "iostream" +#include +#include +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "PWGUD/DataModel/UDTables.h" +#include "TLorentzVector.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" + +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// \brief This is an example to fill outputs in a tree, useful for post processing analysis +/// \author Amrit Gautam +/// \author Anisa Khatun +/// \date 10.10.2024 + +namespace o2::aod +{ +namespace tree +{ +// track tables +DECLARE_SOA_COLUMN(SIGMAPI, sigmapi, std::vector); +DECLARE_SOA_COLUMN(PT, Pt, float); +DECLARE_SOA_COLUMN(RAP, rap, float); +DECLARE_SOA_COLUMN(PHI, Phi, float); +DECLARE_SOA_COLUMN(TOTSIGN, totsign, int); +DECLARE_SOA_COLUMN(MASS, mass, float); +DECLARE_SOA_COLUMN(NPVTRACK, npvtrack, int); +DECLARE_SOA_COLUMN(PTS, Pts, std::vector); +DECLARE_SOA_COLUMN(ETAS, etas, std::vector); +DECLARE_SOA_COLUMN(PHIS, Phis, std::vector); +DECLARE_SOA_COLUMN(SIGNS, Signs, std::vector); +} // namespace tree + +DECLARE_SOA_TABLE(TREE, "AOD", "Tree", + tree::PT, + tree::RAP, + tree::PHI, + tree::MASS, + tree::TOTSIGN, + tree::NPVTRACK, + tree::SIGMAPI, + tree::PTS, + tree::ETAS, + tree::PHIS, + tree::SIGNS); + +} // namespace o2::aod + +struct UDTutorial07 { + SGSelector sgSelector; + Produces tree; + + Configurable FV0_cut{"FV0", 100., "FV0A threshold"}; + Configurable FT0A_cut{"FT0A", 200., "FT0A threshold"}; + Configurable FT0C_cut{"FT0C", 100., "FT0C threshold"}; + Configurable FDDA_cut{"FDDA", 10000., "FDDA threshold"}; + Configurable FDDC_cut{"FDDC", 10000., "FDDC threshold"}; + Configurable ZDC_cut{"ZDC", 10., "ZDC threshold"}; + Configurable gap_Side{"gap", 2, "gap selection"}; + + // Track Selections + Configurable PV_cut{"PV_cut", 1.0, "Use Only PV tracks"}; + Configurable dcaZ_cut{"dcaZ_cut", 2.0, "dcaZ cut"}; + Configurable dcaXY_cut{"dcaXY_cut", 0.0, "dcaXY cut (0 for Pt-function)"}; + Configurable tpcChi2_cut{"tpcChi2_cut", 4, "Max tpcChi2NCl"}; + Configurable tpcNClsFindable_cut{"tpcNClsFindable_cut", 70, "Min tpcNClsFindable"}; + Configurable itsChi2_cut{"itsChi2_cut", 36, "Max itsChi2NCl"}; + Configurable eta_cut{"eta_cut", 0.9, "Track Pseudorapidity"}; + Configurable pt_cut{"pt_cut", 0.1, "Track Pt"}; + Configurable TPC_cluster{"TPC_cluster", 50, "No.of TPC cluster"}; + + // Kinmatic cuts + Configurable PID_cut{"PID_cut", 5, "TPC PID"}; + Configurable Rap_cut{"Rap_cut", 0.9, "Track rapidity"}; + Configurable Mass_Max{"Mass_Max", 10, "Invariant Mass range high"}; + Configurable Mass_Min{"Mass_Min", 0, "Invariant Mass range low"}; + Configurable Pt_coherent{"Pt_coherent", 0.15, "Coherent selection"}; + + // defining histograms using histogram registry + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //----------------------------------------------------------------------------------------------------------------------- + void init(o2::framework::InitContext&) + { + + registry.add("GapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + registry.add("TrueGapSide", "Gap Side; Entries", kTH1F, {{4, -1.5, 2.5}}); + + // Fill counter to see effect of each selection criteria + auto hSelectionCounter = registry.add("hSelectionCounter", "hSelectionCounter;;NEvents", HistType::kTH1I, {{10, 0., 10.}}); + TString SelectionCuts[7] = {"NoSelection", "gapside", "goodtracks", "truegap", "2collcontrib", "2goodtrk"}; + for (int i = 0; i < 7; i++) { + hSelectionCounter->GetXaxis()->SetBinLabel(i + 1, SelectionCuts[i].Data()); + } + + // Fill histograms to cross-check the selected numbers + registry.add("hTracks", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + registry.add("hTracksPions", "N_{tracks}", kTH1F, {{100, -0.5, 99.5}}); + } + + using udtracks = soa::Join; + using udtracksfull = soa::Join; + using UDCollisionsFull = soa::Join; + //__________________________________________________________________________ + // Main process + void process(UDCollisionsFull::iterator const& collision, udtracksfull const& tracks) + { + registry.fill(HIST("hSelectionCounter"), 0); + + // Accessing gap sides + int gapSide = collision.gapSide(); + if (gapSide < 0 || gapSide > 2) + return; + + registry.fill(HIST("hSelectionCounter"), 1); + + // Accessing FIT information for further exclusivity and/or inclusivity + float FIT_cut[5] = {FV0_cut, FT0A_cut, FT0C_cut, FDDA_cut, FDDC_cut}; + int truegapSide = sgSelector.trueGap(collision, FIT_cut[0], FIT_cut[1], FIT_cut[2], ZDC_cut); + + // Intiating track parameters to select good tracks, values to be optimized in the configurables, parameters will be taken from SGtrackselector.h task included in the header + std::vector parameters = {PV_cut, dcaZ_cut, dcaXY_cut, tpcChi2_cut, tpcNClsFindable_cut, itsChi2_cut, eta_cut, pt_cut}; + + registry.fill(HIST("GapSide"), gapSide); + registry.fill(HIST("TrueGapSide"), truegapSide); + + // Gap side to be selected in the configuables + gapSide = truegapSide; + + registry.fill(HIST("hSelectionCounter"), 2); + //_____________________________________ + // Create LorentzVector to store track information + std::vector allTracks; + std::vector onlyPionTracks; + std::vector onlyPionSigma; + std::vector rawPionTracks; + std::vector trackpt; + std::vector tracketa; + std::vector trackphi; + std::vector tracksign; + std::vector pitpcpid; + + TLorentzVector p; + + if (gapSide == gap_Side) { + + registry.fill(HIST("hSelectionCounter"), 3); + + for (auto t : tracks) { + + // Apply good track selection criteria + if (!trackselector(t, parameters)) + continue; + + // Creating Lorenz vector to store raw tracks and piontracks + TLorentzVector a; + a.SetXYZM(t.px(), t.py(), t.pz(), o2::constants::physics::MassPionCharged); + allTracks.push_back(a); + + // Apply TPC pion sigma + auto nSigmaPi = t.tpcNSigmaPi(); + if (fabs(nSigmaPi) < PID_cut) { + onlyPionTracks.push_back(a); + onlyPionSigma.push_back(nSigmaPi); + rawPionTracks.push_back(t); + } + } + registry.fill(HIST("hTracksPions"), onlyPionTracks.size()); + + //_____________________________________ + // Selecting collisions with Two PV contributors + if (collision.numContrib() == 2) { + + registry.fill(HIST("hSelectionCounter"), 4); + + // Selecting only Two good tracks + if ((rawPionTracks.size() == 2) && (allTracks.size() == 2)) { + + registry.fill(HIST("hSelectionCounter"), 4); + + // Creating rhos + for (auto pion : onlyPionTracks) { + p += pion; + } + + for (auto rtrk : rawPionTracks) { + TLorentzVector itrk; + itrk.SetXYZM(rtrk.px(), rtrk.py(), rtrk.pz(), o2::constants::physics::MassPionCharged); + trackpt.push_back(itrk.Pt()); + tracketa.push_back(itrk.Eta()); + trackphi.push_back(itrk.Phi()); + tracksign.push_back(rtrk.sign()); + pitpcpid.push_back(rtrk.tpcNSigmaPi()); + } + + int sign = 0; + for (auto rawPion : rawPionTracks) { + sign += rawPion.sign(); + } + // Filling tree, make to be consistent with the declared tables + tree(p.Pt(), p.Y(), p.Phi(), p.M(), sign, collision.numContrib(), pitpcpid, trackpt, tracketa, trackphi, tracksign); + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"udtutorial07"})}; +} diff --git a/Tutorials/src/TrainingTree.h b/Tutorials/src/TrainingTree.h index 93b4741a951..229b8393193 100644 --- a/Tutorials/src/TrainingTree.h +++ b/Tutorials/src/TrainingTree.h @@ -45,7 +45,7 @@ auto meanPt(Tracks const& tracks) auto apt = 0.f; auto npt = 0; for (auto& track : tracks) { - if (isfinite(track.pt()) && (std::abs(track.pt()) > 1e-3)) { + if (std::isfinite(track.pt()) && (std::abs(track.pt()) > 1e-3)) { ++npt; apt += track.pt(); } diff --git a/Tutorials/src/eventMixing.cxx b/Tutorials/src/eventMixing.cxx index 79abe008e85..676d6ba96e3 100644 --- a/Tutorials/src/eventMixing.cxx +++ b/Tutorials/src/eventMixing.cxx @@ -31,7 +31,7 @@ namespace hash { DECLARE_SOA_COLUMN(Bin, bin, int); } // namespace hash -DECLARE_SOA_TABLE(Hashes, "AOD", "HASH", hash::Bin); +DECLARE_SOA_TABLE(MixingHashes, "AOD", "HASH", hash::Bin); } // namespace o2::aod @@ -49,7 +49,11 @@ struct MixedEvents { int count = 0; for (auto& [c1, tracks1, c2, tracks2] : pair) { - LOGF(info, "Mixed event collisions: (%d, %d)", c1.globalIndex(), c2.globalIndex()); + // Example of using getBin() to check collisions bin + // NOTE that it is a bit different for FlexibleBinning -- check in respective example + int bin = binningOnPositions.getBin({c1.posX(), c1.posY()}); + + LOGF(info, "Mixed event collisions: (%d, %d) from bin %d", c1.globalIndex(), c2.globalIndex(), bin); count++; if (count == 100) break; @@ -300,7 +304,7 @@ struct MixedEventsTripleVariousKinds { struct HashTask { std::vector xBins{-0.064f, -0.062f, -0.060f, 0.066f, 0.068f, 0.070f, 0.072}; std::vector yBins{-0.320f, -0.301f, -0.300f, 0.330f, 0.340f, 0.350f, 0.360}; - Produces hashes; + Produces hashes; // Calculate hash for an element based on 2 properties and their bins. int getHash(const std::vector& xBins, const std::vector& yBins, float colX, float colY) @@ -337,7 +341,7 @@ struct HashTask { struct MixedEventsWithHashTask { SliceCache cache; - using myCollisions = soa::Join; + using myCollisions = soa::Join; NoBinningPolicy hashBin; SameKindPair> pair{hashBin, 5, -1, &cache}; // indicates that 5 events should be mixed and under/overflow (-1) to be ignored @@ -434,7 +438,10 @@ struct MixedEventsLambdaBinning { int count = 0; for (auto& [c1, tracks1, c2, tracks2] : pair) { - LOGF(info, "Mixed event collisions: (%d, %d) z: (%.3f, %.3f), tracks size (%d, %d)", c1.globalIndex(), c2.globalIndex(), c1.posZ(), c2.posZ(), tracks1.size(), tracks2.size()); + // NOTE that getBin() with FlexibleBinningPolicy needs explicit tuple construction + int bin = binningWithLambda.getBin(std::tuple(getTracksSize(c1), c1.posZ())); + + LOGF(info, "Mixed event collisions: (%d, %d) from bin %d z: (%.3f, %.3f), tracks size (%d, %d)", c1.globalIndex(), c2.globalIndex(), bin, c1.posZ(), c2.posZ(), tracks1.size(), tracks2.size()); count++; if (count == 100) break; @@ -451,6 +458,30 @@ struct MixedEventsLambdaBinning { } }; +struct MixedEventsCounters { + // Please read carefully the tutorial description in O2 documentation to understand the behaviour of currentWindowNeighbours(). + // https://aliceo2group.github.io/analysis-framework/docs/tutorials/eventMixing.html#mixedeventscounters + + SliceCache cache; + + std::vector xBins{VARIABLE_WIDTH, -0.064, -0.062, -0.060, 0.066, 0.068, 0.070, 0.072}; + std::vector yBins{VARIABLE_WIDTH, -0.320, -0.301, -0.300, 0.330, 0.340, 0.350, 0.360}; + using BinningType = ColumnBinningPolicy; + BinningType binningOnPositions{{xBins, yBins}, true}; + // true is for 'ignore overflows' (true by default) + SameKindPair pair{binningOnPositions, 5, -1, &cache}; // indicates that 5 events should be mixed and under / overflow(-1) to be ignored + + void process(aod::Collisions const& collisions, aod::Tracks const& tracks) + { + LOGF(info, "Input data Collisions %d, Tracks %d ", collisions.size(), tracks.size()); + + for (auto it = pair.begin(); it != pair.end(); it++) { + auto& [c1, tracks1, c2, tracks2] = *it; + LOGF(info, "Mixed event collisions: (%d, %d), is it first pair with %d: %d, number of collisions mixed with the first: %d", c1.globalIndex(), c2.globalIndex(), c1.globalIndex(), it.isNewWindow(), it.currentWindowNeighbours()); + } + } +}; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ @@ -466,5 +497,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), }; } diff --git a/Tutorials/src/eventMixingValidation.cxx b/Tutorials/src/eventMixingValidation.cxx index eb5b27f798b..2db94b1d082 100644 --- a/Tutorials/src/eventMixingValidation.cxx +++ b/Tutorials/src/eventMixingValidation.cxx @@ -121,39 +121,11 @@ struct MixedEventsJoinedTracks { // } //}; -struct MixedEventsCounters { - SliceCache cache; - // This task shows how to extract variables needed for weighted correlations. - // NOTE: The same number of currentWindowNeighbours is returned for all kinds of block combinations. - // Strictly upper: the first collision will is paired with exactly currentWindowNeighbours other collisions. - // Upper: the first collision is paired with (currentWindowNeighbours + 1) collisions, including itself. - // Full: (currentWindowNeighbours + 1) pairs with the first collision in the first position (c1) - // + there are other combinations with the first collision at other positions. - - std::vector xBins{VARIABLE_WIDTH, -0.064, -0.062, -0.060, 0.066, 0.068, 0.070, 0.072}; - std::vector yBins{VARIABLE_WIDTH, -0.320, -0.301, -0.300, 0.330, 0.340, 0.350, 0.360}; - using BinningType = ColumnBinningPolicy; - BinningType binningOnPositions{{xBins, yBins}, true}; - // true is for 'ignore overflows' (true by default) - SameKindPair pair{binningOnPositions, 5, -1, &cache}; // indicates that 5 events should be mixed and under / overflow(-1) to be ignored - - void process(aod::Collisions const& collisions, aod::Tracks const& tracks) - { - LOGF(info, "Input data Collisions %d, Tracks %d ", collisions.size(), tracks.size()); - - for (auto it = pair.begin(); it != pair.end(); it++) { - auto& [c1, tracks1, c2, tracks2] = *it; - LOGF(info, "Mixed event collisions: (%d, %d), is it first pair with %d: %d, number of collisions mixed with the first: %d", c1.globalIndex(), c2.globalIndex(), c1.globalIndex(), it.isNewWindow(), it.currentWindowNeighbours()); - } - } -}; - WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), // adaptAnalysisTask(cfgc), // Should not compile - adaptAnalysisTask(cfgc), }; } diff --git a/Tutorials/src/extendedTables.cxx b/Tutorials/src/extendedTables.cxx index ce511fbb887..643a81e1504 100644 --- a/Tutorials/src/extendedTables.cxx +++ b/Tutorials/src/extendedTables.cxx @@ -21,6 +21,7 @@ namespace o2::aod namespace extension { DECLARE_SOA_EXPRESSION_COLUMN(P2exp, p2exp, float, track::p* track::p); +DECLARE_SOA_CONFIGURABLE_EXPRESSION_COLUMN(Cfg, cfg, float, "cfg"); DECLARE_SOA_COLUMN(mX, mx, float); DECLARE_SOA_COLUMN(mY, my, float); @@ -36,6 +37,8 @@ DECLARE_SOA_TABLE(DynTable, "AOD", "DYNTABLE", DECLARE_SOA_EXTENDED_TABLE_USER(ExTable, Tracks, "EXTABLE", extension::P2exp); +DECLARE_SOA_CONFIGURABLE_EXTENDED_TABLE(CExTable, Tracks, "CTRK", + extension::Cfg); } // namespace o2::aod using namespace o2; @@ -107,6 +110,14 @@ struct ExtendAndAttach { struct SpawnDynamicColumns { Produces dyntable; Spawns extable; + Defines cextable; + + Configurable factor{"factor", 1.0f, "scale factor"}; + + void init(InitContext&) + { + cextable.projectors[0] = (float)factor * aod::track::p * aod::track::p; + } void process(aod::Tracks const& tracks) { @@ -119,7 +130,7 @@ struct SpawnDynamicColumns { // loop over the joined table struct ProcessExtendedTables { // join the table ExTable and DynTable - using allinfo = soa::Join; + using allinfo = soa::Join; void process(aod::Collision const&, allinfo const& tracks) { @@ -128,6 +139,7 @@ struct ProcessExtendedTables { if (row.trackType() != 3) { if (row.index() % 10000 == 0) { LOGF(info, "E: EXPRESSION P^2 = %.3f, DYNAMIC P^2 = %.3f R^2 = %.3f", row.p2exp(), row.p2dyn(), row.r2dyn()); + LOGF(info, "C: CONF EXPRESSION f * P^2 = %.3f", row.cfg()); } } } diff --git a/Tutorials/src/pid.cxx b/Tutorials/src/pidTpcTof.cxx similarity index 96% rename from Tutorials/src/pid.cxx rename to Tutorials/src/pidTpcTof.cxx index bc51f07ab4c..777c09c1920 100644 --- a/Tutorials/src/pid.cxx +++ b/Tutorials/src/pidTpcTof.cxx @@ -10,7 +10,7 @@ // or submit itself to any jurisdiction. /// -/// \file pid.cxx +/// \file pidTpcTof.cxx /// \author Nicolò Jacazio nicolo.jacazio@cern.ch /// \brief Task to test the PID features and utilities /// @@ -30,7 +30,7 @@ using namespace o2::framework::expressions; using namespace o2::track; /// Task to produce the response table -struct pid { +struct pidTpcTof { void init(o2::framework::InitContext&) { } @@ -75,5 +75,5 @@ struct pid { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/Tutorials/src/reweighting.cxx b/Tutorials/src/reweighting.cxx index 4ea6e83dbc0..72c17a1cb29 100644 --- a/Tutorials/src/reweighting.cxx +++ b/Tutorials/src/reweighting.cxx @@ -28,11 +28,16 @@ // This workflow is used to create a flat tree for model training // Use o2-aod-merger to combine dataframes in output AnalysisResults_trees.root +#if __has_include() #include +#else +#include +#endif #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Common/DataModel/Multiplicity.h" #include "TrainingTree.h" +#include using namespace o2; using namespace o2::framework; @@ -77,7 +82,11 @@ struct CreateWeights { Filter centralTracks = nabs(aod::track::eta) < centralEtaCut; /// onnx runtime session handle +#if __has_include() std::shared_ptr onnxSession = nullptr; +#else + std::shared_ptr onnxSession = nullptr; +#endif /// onnx runtime session options Ort::SessionOptions sessionOptions; /// input vectore @@ -89,9 +98,17 @@ struct CreateWeights { { auto path = (std::string)onnxModel; /// create session +#if __has_include() onnxSession = std::make_shared(env, path, sessionOptions); /// adjust input shape to use row-by-row model application inputShapes = onnxSession->GetInputShapes(); +#else + onnxSession = std::make_shared(env, path.c_str(), sessionOptions); + /// adjust input shape to use row-by-row model application + for (size_t i = 0; i < onnxSession->GetInputCount(); ++i) { + inputShapes.emplace_back(onnxSession->GetInputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape()); + } +#endif if (inputShapes[0][0] < 0) { LOG(warning) << "Model with negative input shape, setting it to 1."; inputShapes[0][0] = 1; @@ -103,9 +120,29 @@ struct CreateWeights { /// get the input variables auto features = collect(collision, tracks); /// add an entry in input vector +#if __has_include() inputML.push_back(Ort::Experimental::Value::CreateTensor(features.data(), features.size(), inputShapes[0])); /// run inference auto result = onnxSession->Run(onnxSession->GetInputNames(), inputML, onnxSession->GetOutputNames()); +#else + Ort::MemoryInfo mem_info = + Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault); + inputML.push_back(Ort::Value::CreateTensor(mem_info, features.data(), features.size(), inputShapes[0].data(), inputShapes[0].size())); + /// run inference + + Ort::RunOptions runOptions; + Ort::AllocatorWithDefaultOptions tmpAllocator; + std::vector inputNamesChar(onnxSession->GetInputCount(), nullptr); + for (size_t i = 0; i < onnxSession->GetInputCount(); ++i) { + inputNamesChar.push_back(onnxSession->GetInputNameAllocated(i, tmpAllocator).get()); + } + + std::vector outputNamesChar(onnxSession->GetOutputCount(), nullptr); + for (size_t i = 0; i < onnxSession->GetOutputCount(); ++i) { + outputNamesChar.push_back(onnxSession->GetOutputNameAllocated(i, tmpAllocator).get()); + } + auto result = onnxSession->Run(runOptions, inputNamesChar.data(), inputML.data(), inputML.size(), outputNamesChar.data(), outputNamesChar.size()); +#endif /// extract scores auto scores = result[1].GetTensorMutableData(); LOGP(info, "Col {}: scores ({}, {})", collision.globalIndex(), scores[0], scores[1]); @@ -145,7 +182,7 @@ struct ConsumeWeights { /// fill histograms with using BDT scores produced by previous task as weights for (auto& track : tracks) { - if (isfinite(track.pt())) { + if (std::isfinite(track.pt())) { registry.fill(HIST("Weighted/Tracks/Pt"), track.pt(), collision.weight()); } } @@ -165,7 +202,7 @@ struct ConsumeWeights { /// fill histograms without weights for (auto& track : tracks) { - if (isfinite(track.pt())) { + if (std::isfinite(track.pt())) { registry.fill(HIST("Tracks/Pt"), track.pt()); } } diff --git a/Tutorials/src/tracksCombinations.cxx b/Tutorials/src/tracksCombinations.cxx index a61d8daf5aa..413e8399e9b 100644 --- a/Tutorials/src/tracksCombinations.cxx +++ b/Tutorials/src/tracksCombinations.cxx @@ -30,7 +30,7 @@ namespace hash { DECLARE_SOA_COLUMN(Bin, bin, int); } // namespace hash -DECLARE_SOA_TABLE(Hashes, "AOD", "HASH", hash::Bin); +DECLARE_SOA_TABLE(MixingHashes, "AOD", "HASH", hash::Bin); } // namespace o2::aod @@ -116,7 +116,7 @@ struct BinnedTrackPartitionsCombinations { struct HashTask { std::vector xBins{-0.064f, -0.062f, -0.060f, 0.066f, 0.068f, 0.070f, 0.072}; std::vector yBins{-0.320f, -0.301f, -0.300f, 0.330f, 0.340f, 0.350f, 0.360}; - Produces hashes; + Produces hashes; // Calculate hash for an element based on 2 properties and their bins. int getHash(const std::vector& xBins, const std::vector& yBins, float colX, float colY) @@ -154,7 +154,7 @@ struct HashTask { struct BinnedTrackCombinationsWithHashTable { NoBinningPolicy hashBin; - void process(soa::Join const& hashedTracks) + void process(soa::Join const& hashedTracks) { int count = 0; // Strictly upper categorised tracks diff --git a/cmake/O2PhysicsDefineOptions.cmake b/cmake/O2PhysicsDefineOptions.cmake index d647fa2fde0..95868fe8904 100644 --- a/cmake/O2PhysicsDefineOptions.cmake +++ b/cmake/O2PhysicsDefineOptions.cmake @@ -18,4 +18,6 @@ function(o2physics_define_options) option(ENABLE_CASSERT "Enable asserts" OFF) option(ENABLE_UPGRADES "Enable detectors for upgrades" OFF) + + option(O2PHYSICS_WARNINGS_AS_ERRORS "Treat selected warnings as errors" OFF) endfunction() diff --git a/dependencies/FindONNXRuntime.cmake b/dependencies/FindONNXRuntime.cmake new file mode 100644 index 00000000000..c10d1af36f6 --- /dev/null +++ b/dependencies/FindONNXRuntime.cmake @@ -0,0 +1,24 @@ +# 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. + +find_package(ONNXRuntime::ONNXRuntime CONFIG) +if (ONNXRuntime::ONNXRuntime_FOUND) + set(onnxruntime_FOUND 1) + add_library(onnxruntime::onnxruntime ALIAS ONNXRuntime::ONNXRuntime) +endif() + +if (NOT ONNXRuntime::ONNXRuntime_FOUND) + find_package(onnxruntime CONFIG) + if (onnxruntime_FOUND) + add_library(ONNXRuntime::ONNXRuntime ALIAS onnxruntime::onnxruntime) + endif() +endif() + diff --git a/dependencies/FindONNXRuntime::ONNXRuntime.cmake b/dependencies/FindONNXRuntime::ONNXRuntime.cmake deleted file mode 100644 index ead747618a2..00000000000 --- a/dependencies/FindONNXRuntime::ONNXRuntime.cmake +++ /dev/null @@ -1,18 +0,0 @@ -include_guard() - -find_package(ONNXRuntime::ONNXRuntime CONFIG) - -if (NOT ONNXRuntime::ONNXRuntime_FOUND) - message(WARNING "No config found for ONNXRuntime::ONNXRuntime. Trying pkgconfig version") - find_package(PkgConfig) - pkg_check_modules(ONNXRuntime REQUIRED IMPORTED_TARGET GLOBAL libonnxruntime) - - if (TARGET PkgConfig::ONNXRuntime) - message(WARNING "Creating alias ONNXRuntime::ONNXRuntime") - add_library(ONNXRuntime::ONNXRuntime ALIAS PkgConfig::ONNXRuntime) - endif() - - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(ONNXRuntime::ONNXRuntime - REQUIRED_VARS ONNXRuntime_LINK_LIBRARIES) -endif() diff --git a/dependencies/O2PhysicsCompileFlags.cmake b/dependencies/O2PhysicsCompileFlags.cmake index c29d8c4a996..20078b607f7 100644 --- a/dependencies/O2PhysicsCompileFlags.cmake +++ b/dependencies/O2PhysicsCompileFlags.cmake @@ -11,13 +11,53 @@ include_guard() -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-error \ --Werror=deprecated-enum-float-conversion \ --Werror=narrowing \ --Werror=parentheses \ --Werror=return-type \ --Werror=uninitialized \ --Werror=unused") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") + +# Enabled warnings supported by Clang and GCC, not treated as errors +set(O2PHYSICS_WARNINGS_COMMON_NO_ERROR "") + +# Enabled warnings supported by Clang only, not treated as errors +set(O2PHYSICS_WARNINGS_CLANG_NO_ERROR "") + +# Enabled warnings supported by GCC only, not treated as errors +set(O2PHYSICS_WARNINGS_GCC_NO_ERROR "") + +# Function to build a list of warning flags from their names +function(o2_build_warning_flags) + cmake_parse_arguments(PARSE_ARGV 0 A "" "PREFIX;OUTPUTVARNAME" "WARNINGS") + if(A_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unexpected unparsed arguments: ${A_UNPARSED_ARGUMENTS}") + endif() + list(TRANSFORM A_WARNINGS STRIP) + list(TRANSFORM A_WARNINGS PREPEND ${A_PREFIX}) + string(JOIN " " OUTPUT ${A_WARNINGS}) + set(${A_OUTPUTVARNAME} ${OUTPUT} PARENT_SCOPE) +endfunction() + +message(STATUS "O2PHYSICS_WARNINGS_AS_ERRORS: ${O2PHYSICS_WARNINGS_AS_ERRORS}") + +# Treat warnings as errors. +if(O2PHYSICS_WARNINGS_AS_ERRORS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") + # Set warning flags for all platforms. + o2_build_warning_flags(PREFIX "-Wno-error=" + OUTPUTVARNAME O2PHYSICS_CXX_WARNINGS_COMMON_NO_ERROR + WARNINGS ${O2PHYSICS_WARNINGS_COMMON_NO_ERROR}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${O2PHYSICS_CXX_WARNINGS_COMMON_NO_ERROR}") + if(APPLE) + # Set warning flags for macOS only. + o2_build_warning_flags(PREFIX "-Wno-error=" + OUTPUTVARNAME O2PHYSICS_CXX_WARNINGS_APPLE_NO_ERROR + WARNINGS ${O2PHYSICS_WARNINGS_CLANG_NO_ERROR}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${O2PHYSICS_CXX_WARNINGS_APPLE_NO_ERROR}") + elseif(UNIX) + # Set warning flags for Linux only. + o2_build_warning_flags(PREFIX "-Wno-error=" + OUTPUTVARNAME O2PHYSICS_CXX_WARNINGS_UNIX_NO_ERROR + WARNINGS ${O2PHYSICS_WARNINGS_GCC_NO_ERROR}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${O2PHYSICS_CXX_WARNINGS_UNIX_NO_ERROR}") + endif() +endif() IF (ENABLE_TIMETRACE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftime-trace") @@ -41,11 +81,11 @@ IF (NOT CMAKE_BUILD_TYPE) ENDIF (NOT CMAKE_BUILD_TYPE) IF(ENABLE_CASSERT) #For the CI, we want to have assertions enabled - set(CMAKE_CXX_FLAGS_RELEASE "-O2") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") + set(CMAKE_CXX_FLAGS_RELEASE "-O2 -pipe") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -pipe") ELSE() - set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG") + set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG -pipe") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG -pipe") if (CMAKE_BUILD_TYPE STREQUAL "RELEASE" OR CMAKE_BUILD_TYPE STREQUAL "RELWITHDEBINFO") set(FAIR_MIN_SEVERITY "info") endif() diff --git a/dependencies/O2PhysicsDependencies.cmake b/dependencies/O2PhysicsDependencies.cmake index 515ad0056a2..d1a2a6280ac 100644 --- a/dependencies/O2PhysicsDependencies.cmake +++ b/dependencies/O2PhysicsDependencies.cmake @@ -24,6 +24,6 @@ set_package_properties(KFParticle PROPERTIES TYPE REQUIRED) find_package(fjcontrib) set_package_properties(fjcontrib PROPERTIES TYPE REQUIRED) -find_package(ONNXRuntime::ONNXRuntime) +find_package(ONNXRuntime) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)